diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 3a08426..0000000 --- a/.appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ -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 new file mode 100644 index 0000000..c6074b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# IDE folders +.idea +.vsc +.vs diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f6ef0d8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -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 libasound2-dev libxi-dev libxinerama-dev libxcursor-dev libxxf86vm-dev libxrandr-dev -y; - fi - -install: - - go get -t ./... diff --git a/Makefile b/Makefile deleted file mode 100644 index 964f4d9..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -PACKAGES= raylib raygui raymath 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 d56ca55..034576d 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,134 @@ -![logo](https://goo.gl/XlIcXz) +![logo](https://git.terah.dev/UnrealXR/raylib-go/raw/branch/master/assets/raylib-go_256x256.png) ## raylib-go -[![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) +[![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) -Golang bindings for [raylib](http://www.raylib.com/), a simple and easy-to-use library to learn videogames programming. +Golang bindings for [raylib](http://www.raylib.com/), a simple and easy-to-use library to enjoy videogames programming. -![screenshot](https://goo.gl/q6DAoy) +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 -* [GLFW](http://www.glfw.org/) is included as part of the Go package, but you need to make sure you have dependencies installed, see below. - ##### Ubuntu - apt-get install libgl1-mesa-dev libxi-dev libxinerama-dev libxcursor-dev libxxf86vm-dev libxrandr-dev + apt-get install libgl1-mesa-dev libxi-dev libxcursor-dev libxrandr-dev libxinerama-dev libwayland-dev libxkbcommon-dev ##### Fedora - dnf install mesa-libGL-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel + dnf install mesa-libGL-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel wayland-devel libxkbcommon-devel ##### macOS -On macOS you need Xcode or Command Line Tools for Xcode. +On macOS, you need Xcode or Command Line Tools for Xcode (if you have `brew` installed, you already have this). ##### 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://github.com/gen2brain/raylib-go/tree/master/examples/others/android/example). +[Android example](https://git.terah.dev/UnrealXR/raylib-go/tree/master/examples/others/android/example). -##### Raspberry Pi +##### Wasm + +For web bindings, refer to [Raylib-Go-Wasm](https://github.com/BrownNPC/Raylib-Go-Wasm); it should be largely compatible with this repository. -[RPi example](https://github.com/gen2brain/raylib-go/tree/master/examples/others/rpi/basic_window). ### Installation - go get -v -u github.com/gen2brain/raylib-go/raylib + go get -v -u git.terah.dev/UnrealXR/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) * `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) -* `wayland` - builds against Wayland libraries +* `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/github.com/gen2brain/raylib-go/raylib). Also check raylib [cheatsheet](http://www.raylib.com/cheatsheet/cheatsheet.html). +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. ### Example ```go package main -import "github.com/gen2brain/raylib-go/raylib" +import rl "git.terah.dev/UnrealXR/raylib-go/raylib" func main() { - raylib.InitWindow(800, 450, "raylib [core] example - basic window") + rl.InitWindow(800, 450, "raylib [core] example - basic window") + defer rl.CloseWindow() - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray) - raylib.DrawText("Congrats! You created your first window!", 190, 200, 20, raylib.LightGray) - - raylib.EndDrawing() + rl.EndDrawing() } - - raylib.CloseWindow() } ``` -Check more [examples](https://github.com/gen2brain/raylib-go/tree/master/examples) organized by raylib modules. +Check more [examples](https://git.terah.dev/UnrealXR/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://github.com/gen2brain/raylib-go/blob/master/LICENSE). +raylib-go is licensed under an unmodified zlib/libpng license. View [LICENSE](https://git.terah.dev/UnrealXR/raylib-go/blob/master/LICENSE). diff --git a/assets/raylib-go_256x256.png b/assets/raylib-go_256x256.png new file mode 100644 index 0000000..380e8c8 Binary files /dev/null and b/assets/raylib-go_256x256.png differ diff --git a/easings/README.md b/easings/README.md index fbc1273..54c3761 100644 --- a/easings/README.md +++ b/easings/README.md @@ -1,7 +1,7 @@ -## easings [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/easings?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/easings) +## easings [![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/easings?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/easings) Useful easing functions for values animation. A port of Robert Penner's [easing equations](http://robertpenner.com/easing/). -![screenshot](https://goo.gl/crzRrH) +![Demo](../examples/easings/easings/easings.gif) diff --git a/easings/easings.go b/easings/easings.go index 6959c23..5004e88 100644 --- a/easings/easings.go +++ b/easings/easings.go @@ -10,21 +10,25 @@ import ( // Linear Easing functions // LinearNone easing +// t: current time, b: begInnIng value, c: change In value, d: duration func LinearNone(t, b, c, d float32) float32 { return c*t/d + b } // LinearIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func LinearIn(t, b, c, d float32) float32 { return c*t/d + b } // LinearOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func LinearOut(t, b, c, d float32) float32 { return c*t/d + b } // LinearInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func LinearInOut(t, b, c, d float32) float32 { return c*t/d + b } @@ -32,16 +36,19 @@ func LinearInOut(t, b, c, d float32) float32 { // Sine Easing functions // SineIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func SineIn(t, b, c, d float32) float32 { return -c*float32(math.Cos(float64(t/d)*(math.Pi/2))) + c + b } // SineOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func SineOut(t, b, c, d float32) float32 { return c*float32(math.Sin(float64(t/d)*(math.Pi/2))) + b } // SineInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func SineInOut(t, b, c, d float32) float32 { return -c/2*(float32(math.Cos(math.Pi*float64(t/d)))-1) + b } @@ -49,17 +56,20 @@ func SineInOut(t, b, c, d float32) float32 { // Circular Easing functions // CircIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CircIn(t, b, c, d float32) float32 { t = t / d return -c*(float32(math.Sqrt(float64(1-t*t)))-1) + b } // CircOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CircOut(t, b, c, d float32) float32 { return c*float32(math.Sqrt(1-float64((t/d-1)*t))) + b } // CircInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CircInOut(t, b, c, d float32) float32 { t = t / d * 2 @@ -74,18 +84,21 @@ func CircInOut(t, b, c, d float32) float32 { // Cubic Easing functions // CubicIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CubicIn(t, b, c, d float32) float32 { t = t / d return c*t*t*t + b } // CubicOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CubicOut(t, b, c, d float32) float32 { t = t/d - 1 return c*(t*t*t+1) + b } // CubicInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func CubicInOut(t, b, c, d float32) float32 { t = t / d * 2 if t < 1 { @@ -99,18 +112,21 @@ func CubicInOut(t, b, c, d float32) float32 { // Quadratic Easing functions // QuadIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func QuadIn(t, b, c, d float32) float32 { t = t / d return c*t*t + b } // QuadOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func QuadOut(t, b, c, d float32) float32 { t = t / d return (-c*t*(t-2) + b) } // QuadInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func QuadInOut(t, b, c, d float32) float32 { t = t / d * 2 if t < 1 { @@ -123,6 +139,7 @@ func QuadInOut(t, b, c, d float32) float32 { // Exponential Easing functions // ExpoIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ExpoIn(t, b, c, d float32) float32 { if t == 0 { return b @@ -132,6 +149,7 @@ func ExpoIn(t, b, c, d float32) float32 { } // ExpoOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ExpoOut(t, b, c, d float32) float32 { if t == d { return (b + c) @@ -141,6 +159,7 @@ func ExpoOut(t, b, c, d float32) float32 { } // ExpoInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ExpoInOut(t, b, c, d float32) float32 { if t == 0 { return b @@ -162,6 +181,7 @@ func ExpoInOut(t, b, c, d float32) float32 { // Back Easing functions // BackIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BackIn(t, b, c, d float32) float32 { s := float32(1.70158) t = t / d @@ -169,6 +189,7 @@ func BackIn(t, b, c, d float32) float32 { } // BackOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BackOut(t, b, c, d float32) float32 { s := float32(1.70158) t = t/d - 1 @@ -176,6 +197,7 @@ func BackOut(t, b, c, d float32) float32 { } // BackInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BackInOut(t, b, c, d float32) float32 { s := float32(1.70158) s = s * 1.525 @@ -192,11 +214,13 @@ func BackInOut(t, b, c, d float32) float32 { // Bounce Easing functions // BounceIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BounceIn(t, b, c, d float32) float32 { return (c - BounceOut(d-t, 0, c, d) + b) } // BounceOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BounceOut(t, b, c, d float32) float32 { t = t / d if t < (1 / 2.75) { @@ -214,6 +238,7 @@ func BounceOut(t, b, c, d float32) float32 { } // BounceInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func BounceInOut(t, b, c, d float32) float32 { if t < d/2 { return BounceIn(t*2, 0, c, d)*0.5 + b @@ -225,6 +250,7 @@ func BounceInOut(t, b, c, d float32) float32 { // Elastic Easing functions // ElasticIn easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ElasticIn(t, b, c, d float32) float32 { if t == 0 { return b @@ -245,6 +271,7 @@ func ElasticIn(t, b, c, d float32) float32 { } // ElasticOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ElasticOut(t, b, c, d float32) float32 { if t == 0 { return b @@ -264,6 +291,7 @@ func ElasticOut(t, b, c, d float32) float32 { } // ElasticInOut easing +// t: current time, b: begInnIng value, c: change In value, d: duration func ElasticInOut(t, b, c, d float32) float32 { if t == 0 { return b diff --git a/easings/go.mod b/easings/go.mod new file mode 100644 index 0000000..54815db --- /dev/null +++ b/easings/go.mod @@ -0,0 +1,3 @@ +module git.terah.dev/UnrealXR/raylib-go/easings + +go 1.21 diff --git a/examples/audio/mixed_processor/coin.wav b/examples/audio/mixed_processor/coin.wav new file mode 100644 index 0000000..ad95bfb Binary files /dev/null and b/examples/audio/mixed_processor/coin.wav differ diff --git a/examples/audio/mixed_processor/country.mp3 b/examples/audio/mixed_processor/country.mp3 new file mode 100644 index 0000000..91066cc Binary files /dev/null and b/examples/audio/mixed_processor/country.mp3 differ diff --git a/examples/audio/mixed_processor/main.go b/examples/audio/mixed_processor/main.go new file mode 100644 index 0000000..de3789d --- /dev/null +++ b/examples/audio/mixed_processor/main.go @@ -0,0 +1,155 @@ +/******************************************************************************************* +* +* 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 18d18c3..18b81e5 100644 --- a/examples/audio/module_playing/main.go +++ b/examples/audio/module_playing/main.go @@ -1,33 +1,33 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) const maxCircles = 64 type circleWave struct { - Position raylib.Vector2 + Position rl.Vector2 Radius float32 Alpha float32 Speed float32 - Color raylib.Color + Color rl.Color } func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) // NOTE: Try to enable MSAA 4X + rl.SetConfigFlags(rl.FlagMsaa4xHint) // NOTE: Try to enable MSAA 4X - raylib.InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing (streaming)") + rl.InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing (streaming)") - raylib.InitAudioDevice() + rl.InitAudioDevice() - colors := []raylib.Color{ - raylib.Orange, raylib.Red, raylib.Gold, raylib.Lime, raylib.Blue, - raylib.Violet, raylib.Brown, raylib.LightGray, raylib.Pink, - raylib.Yellow, raylib.Green, raylib.SkyBlue, raylib.Purple, raylib.Beige, + colors := []rl.Color{ + rl.Orange, rl.Red, rl.Gold, rl.Lime, rl.Blue, + rl.Violet, rl.Brown, rl.LightGray, rl.Pink, + rl.Yellow, rl.Green, rl.SkyBlue, rl.Purple, rl.Beige, } circles := make([]circleWave, maxCircles) @@ -36,47 +36,47 @@ func main() { c := circleWave{} c.Alpha = 0 - c.Radius = float32(raylib.GetRandomValue(10, 40)) + c.Radius = float32(rl.GetRandomValue(10, 40)) - x := raylib.GetRandomValue(int32(c.Radius), screenWidth-int32(c.Radius)) - y := raylib.GetRandomValue(int32(c.Radius), screenHeight-int32(c.Radius)) - c.Position = raylib.NewVector2(float32(x), float32(y)) + x := rl.GetRandomValue(int32(c.Radius), screenWidth-int32(c.Radius)) + y := rl.GetRandomValue(int32(c.Radius), screenHeight-int32(c.Radius)) + c.Position = rl.NewVector2(float32(x), float32(y)) - c.Speed = float32(raylib.GetRandomValue(1, 100)) / 20000.0 - c.Color = colors[raylib.GetRandomValue(0, int32(len(colors)-1))] + c.Speed = float32(rl.GetRandomValue(1, 100)) / 20000.0 + c.Color = colors[rl.GetRandomValue(0, int32(len(colors)-1))] circles[i] = c } - xm := raylib.LoadMusicStream("mini1111.xm") - raylib.PlayMusicStream(xm) + xm := rl.LoadMusicStream("mini1111.xm") + rl.PlayMusicStream(xm) pause := false - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.UpdateMusicStream(xm) // Update music buffer with new stream data + for !rl.WindowShouldClose() { + rl.UpdateMusicStream(xm) // Update music buffer with new stream data // Restart music playing (stop and play) - if raylib.IsKeyPressed(raylib.KeySpace) { - raylib.StopMusicStream(xm) - raylib.PlayMusicStream(xm) + if rl.IsKeyPressed(rl.KeySpace) { + rl.StopMusicStream(xm) + rl.PlayMusicStream(xm) } // Pause/Resume music playing - if raylib.IsKeyPressed(raylib.KeyP) { + if rl.IsKeyPressed(rl.KeyP) { pause = !pause if pause { - raylib.PauseMusicStream(xm) + rl.PauseMusicStream(xm) } else { - raylib.ResumeMusicStream(xm) + rl.ResumeMusicStream(xm) } } // Get timePlayed scaled to bar dimensions - timePlayed := int32(raylib.GetMusicTimePlayed(xm)/raylib.GetMusicTimeLength(xm)*float32(screenWidth-40)) * 2 + timePlayed := int32(rl.GetMusicTimePlayed(xm)/rl.GetMusicTimeLength(xm)*float32(screenWidth-40)) * 2 // Color circles animation for i := maxCircles - 1; (i >= 0) && !pause; i-- { @@ -89,33 +89,33 @@ func main() { if circles[i].Alpha <= 0.0 { circles[i].Alpha = 0.0 - circles[i].Radius = float32(raylib.GetRandomValue(10, 40)) - circles[i].Position.X = float32(raylib.GetRandomValue(int32(circles[i].Radius), screenWidth-int32(circles[i].Radius))) - circles[i].Position.Y = float32(raylib.GetRandomValue(int32(circles[i].Radius), screenHeight-int32(circles[i].Radius))) - circles[i].Color = colors[raylib.GetRandomValue(0, 13)] - circles[i].Speed = float32(raylib.GetRandomValue(1, 100)) / 20000.0 + circles[i].Radius = float32(rl.GetRandomValue(10, 40)) + circles[i].Position.X = float32(rl.GetRandomValue(int32(circles[i].Radius), screenWidth-int32(circles[i].Radius))) + circles[i].Position.Y = float32(rl.GetRandomValue(int32(circles[i].Radius), screenHeight-int32(circles[i].Radius))) + circles[i].Color = colors[rl.GetRandomValue(0, 13)] + circles[i].Speed = float32(rl.GetRandomValue(1, 100)) / 20000.0 } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) for i := maxCircles - 1; i >= 0; i-- { - raylib.DrawCircleV(circles[i].Position, float32(circles[i].Radius), raylib.Fade(circles[i].Color, circles[i].Alpha)) + rl.DrawCircleV(circles[i].Position, float32(circles[i].Radius), rl.Fade(circles[i].Color, circles[i].Alpha)) } // Draw time bar - raylib.DrawRectangle(20, screenHeight-20-12, screenWidth-40, 12, raylib.LightGray) - raylib.DrawRectangle(20, screenHeight-20-12, timePlayed, 12, raylib.Maroon) - raylib.DrawRectangleLines(20, screenHeight-20-12, screenWidth-40, 12, raylib.Gray) + rl.DrawRectangle(20, screenHeight-20-12, screenWidth-40, 12, rl.LightGray) + rl.DrawRectangle(20, screenHeight-20-12, timePlayed, 12, rl.Maroon) + rl.DrawRectangleLines(20, screenHeight-20-12, screenWidth-40, 12, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadMusicStream(xm) + rl.UnloadMusicStream(xm) - raylib.CloseAudioDevice() + rl.CloseAudioDevice() - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/audio/music_stream/main.go b/examples/audio/music_stream/main.go index a4af68f..0a9f7a5 100644 --- a/examples/audio/music_stream/main.go +++ b/examples/audio/music_stream/main.go @@ -1,60 +1,56 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { - raylib.InitWindow(800, 450, "raylib [audio] example - music playing (streaming)") - raylib.InitAudioDevice() + rl.InitWindow(800, 450, "raylib [audio] example - music playing (streaming)") + rl.InitAudioDevice() - music := raylib.LoadMusicStream("guitar_noodling.ogg") + music := rl.LoadMusicStream("guitar_noodling.ogg") pause := false - raylib.PlayMusicStream(music) + rl.PlayMusicStream(music) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.UpdateMusicStream(music) // Update music buffer with new stream data + for !rl.WindowShouldClose() { + rl.UpdateMusicStream(music) // Update music buffer with new stream data // Restart music playing (stop and play) - if raylib.IsKeyPressed(raylib.KeySpace) { - raylib.StopMusicStream(music) - raylib.PlayMusicStream(music) + if rl.IsKeyPressed(rl.KeySpace) { + rl.StopMusicStream(music) + rl.PlayMusicStream(music) } // Pause/Resume music playing - if raylib.IsKeyPressed(raylib.KeyP) { + if rl.IsKeyPressed(rl.KeyP) { pause = !pause if pause { - raylib.PauseMusicStream(music) + rl.PauseMusicStream(music) } else { - raylib.ResumeMusicStream(music) + rl.ResumeMusicStream(music) } } // Get timePlayed scaled to bar dimensions (400 pixels) - timePlayed := raylib.GetMusicTimePlayed(music) / raylib.GetMusicTimeLength(music) * 100 * 4 + timePlayed := rl.GetMusicTimePlayed(music) / rl.GetMusicTimeLength(music) * 100 * 4 - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) - raylib.DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, raylib.LightGray) + rl.ClearBackground(rl.RayWhite) + rl.DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, rl.LightGray) - raylib.DrawRectangle(200, 200, 400, 12, raylib.LightGray) - raylib.DrawRectangle(200, 200, int32(timePlayed), 12, raylib.Maroon) - raylib.DrawRectangleLines(200, 200, 400, 12, raylib.Gray) + rl.DrawRectangle(200, 200, 400, 12, rl.LightGray) + rl.DrawRectangle(200, 200, int32(timePlayed), 12, rl.Maroon) + rl.DrawRectangleLines(200, 200, 400, 12, rl.Gray) - raylib.DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, raylib.LightGray) - raylib.DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, raylib.LightGray) + rl.DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, rl.LightGray) + rl.DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadMusicStream(music) // Unload music stream buffers from RAM - raylib.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) + rl.UnloadMusicStream(music) // Unload music stream buffers from RAM + rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/audio/raw_stream/main.go b/examples/audio/raw_stream/main.go index 39870f9..9a1f335 100644 --- a/examples/audio/raw_stream/main.go +++ b/examples/audio/raw_stream/main.go @@ -1,81 +1,79 @@ package main import ( + "fmt" "math" + "time" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( - maxSamples = 22050 - maxSamplesPerUpdate = 4096 + nSamples = 44000 * 10 + sampleRate = 6000 + bufferSize = nSamples + frequency = 440 + targetFPS = 240 ) func main() { - raylib.InitWindow(800, 450, "raylib [audio] example - raw audio streaming") + rl.InitWindow(800, 450, "raylib [audio] example - raw audio streaming") + position := rl.NewVector2(0, 0) - raylib.InitAudioDevice() + rl.SetAudioStreamBufferSizeDefault(bufferSize) - // Init raw audio stream (sample rate: 22050, sample size: 32bit-float, channels: 1-mono) - stream := raylib.InitAudioStream(22050, 32, 1) + rl.InitAudioDevice() - //// Fill audio stream with some samples (sine wave) - data := make([]float32, maxSamples) + // Init raw audio stream (sample rate: , sample size: 32bit-float, channels: 1-mono) + stream := rl.LoadAudioStream(nSamples, 32, 1) - for i := 0; i < maxSamples; i++ { - data[i] = float32(math.Sin(float64((2*raylib.Pi*float32(i))/2) * raylib.Deg2rad)) + //// Create sine wave to play + data := make([]float32, nSamples) + + for i := 0; i < nSamples; i++ { + t := float32(i) / float32(nSamples) + data[i] = float32(math.Sin(float64((2 * rl.Pi * frequency * t)))) } - // 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 - raylib.PlayAudioStream(stream) + // NOTE: The buffer can only be updated when it has been processed. Time between buffer processing and next load and causes clipping + rl.PlayAudioStream(stream) - totalSamples := int32(maxSamples) - samplesLeft := int32(totalSamples) + startTime := time.Now() + rl.SetTargetFPS(targetFPS) - position := raylib.NewVector2(0, 0) + for !rl.WindowShouldClose() { + // Refill audio stream if buffer is processed + if rl.IsAudioStreamProcessed(stream) { + elapsedTime := time.Since(startTime).Seconds() + currentSampleIndex := int(math.Mod(elapsedTime*float64(sampleRate), float64(nSamples))) + nextSampleIndex := currentSampleIndex + bufferSize - raylib.SetTargetFPS(30) - - for !raylib.WindowShouldClose() { - // Refill audio stream if required - if raylib.IsAudioBufferProcessed(stream) { - numSamples := int32(0) - if samplesLeft >= maxSamplesPerUpdate { - numSamples = maxSamplesPerUpdate + if nextSampleIndex > nSamples { + nextSampleIndex = bufferSize - (nSamples - currentSampleIndex) + rl.UpdateAudioStream(stream, append(data[currentSampleIndex:], data[:nextSampleIndex]...)) } else { - numSamples = samplesLeft - } - - raylib.UpdateAudioStream(stream, data[totalSamples-samplesLeft:], numSamples) - - samplesLeft -= numSamples - - // Reset samples feeding (loop audio) - if samplesLeft <= 0 { - samplesLeft = totalSamples + rl.UpdateAudioStream(stream, data[currentSampleIndex:nextSampleIndex]) } } - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - raylib.DrawText("SINE WAVE SHOULD BE PLAYING!", 240, 140, 20, raylib.LightGray) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) + rl.DrawText(fmt.Sprintf("%d Hz SINE WAVE SHOULD BE PLAYING!", frequency), 200, 140, 20, rl.LightGray) // NOTE: Draw a part of the sine wave (only screen width) - for i := 0; i < int(raylib.GetScreenWidth()); i++ { + for i := 0; i < int(rl.GetScreenWidth()); i++ { position.X = float32(i) - position.Y = 250 + 50*data[i] + position.Y = 250 + 10*data[i*nSamples/int(20*rl.GetScreenWidth())] - raylib.DrawPixelV(position, raylib.Red) + rl.DrawPixelV(position, rl.Red) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseAudioStream(stream) // Close raw audio stream and delete buffers from RAM + rl.UnloadAudioStream(stream) // Close raw audio stream and delete buffers from RAM - raylib.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) + rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/audio/sound_loading/main.go b/examples/audio/sound_loading/main.go index 64a54a5..8239c03 100644 --- a/examples/audio/sound_loading/main.go +++ b/examples/audio/sound_loading/main.go @@ -1,41 +1,41 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [audio] example - sound loading and playing") + rl.InitWindow(800, 450, "raylib [audio] example - sound loading and playing") - raylib.InitAudioDevice() + rl.InitAudioDevice() - fxWav := raylib.LoadSound("weird.wav") - fxOgg := raylib.LoadSound("tanatana.ogg") + fxWav := rl.LoadSound("weird.wav") + fxOgg := rl.LoadSound("tanatana.ogg") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyPressed(raylib.KeySpace) { - raylib.PlaySound(fxWav) + for !rl.WindowShouldClose() { + if rl.IsKeyPressed(rl.KeySpace) { + rl.PlaySound(fxWav) } - if raylib.IsKeyPressed(raylib.KeyEnter) { - raylib.PlaySound(fxOgg) + if rl.IsKeyPressed(rl.KeyEnter) { + rl.PlaySound(fxOgg) } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, raylib.LightGray) - raylib.DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, raylib.LightGray) + rl.DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, rl.LightGray) + rl.DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadSound(fxWav) - raylib.UnloadSound(fxOgg) + rl.UnloadSound(fxWav) + rl.UnloadSound(fxOgg) - raylib.CloseAudioDevice() + rl.CloseAudioDevice() - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/audio/sound_multi/main.go b/examples/audio/sound_multi/main.go new file mode 100644 index 0000000..067440b --- /dev/null +++ b/examples/audio/sound_multi/main.go @@ -0,0 +1,65 @@ +/******************************************************************************************* +* +* 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/audio/sound_multi/sound.wav b/examples/audio/sound_multi/sound.wav new file mode 100644 index 0000000..b5d01c9 Binary files /dev/null and b/examples/audio/sound_multi/sound.wav differ diff --git a/examples/core/2d_camera/main.go b/examples/core/2d_camera/main.go index 82471e7..6c77b20 100644 --- a/examples/core/2d_camera/main.go +++ b/examples/core/2d_camera/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) var ( @@ -12,54 +12,52 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera") - player := raylib.NewRectangle(400, 280, 40, 40) + player := rl.NewRectangle(400, 280, 40, 40) - buildings := make([]raylib.Rectangle, maxBuildings) - buildColors := make([]raylib.Color, maxBuildings) + buildings := make([]rl.Rectangle, maxBuildings) + buildColors := make([]rl.Color, maxBuildings) spacing := float32(0) for i := 0; i < maxBuildings; i++ { - r := raylib.Rectangle{} - r.Width = float32(raylib.GetRandomValue(50, 200)) - r.Height = float32(raylib.GetRandomValue(100, 800)) + r := rl.Rectangle{} + r.Width = float32(rl.GetRandomValue(50, 200)) + r.Height = float32(rl.GetRandomValue(100, 800)) r.Y = float32(screenHeight) - 130 - r.Height r.X = -6000 + spacing spacing += r.Width - c := raylib.NewColor(byte(raylib.GetRandomValue(200, 240)), byte(raylib.GetRandomValue(200, 240)), byte(raylib.GetRandomValue(200, 250)), byte(255)) + c := rl.NewColor(byte(rl.GetRandomValue(200, 240)), byte(rl.GetRandomValue(200, 240)), byte(rl.GetRandomValue(200, 250)), byte(255)) buildings[i] = r buildColors[i] = c } - camera := raylib.Camera2D{} - camera.Target = raylib.NewVector2(float32(player.X+20), float32(player.Y+20)) - camera.Offset = raylib.NewVector2(0, 0) + camera := rl.Camera2D{} + camera.Target = rl.NewVector2(float32(player.X+20), float32(player.Y+20)) + camera.Offset = rl.NewVector2(float32(screenWidth/2), float32(screenHeight/2)) camera.Rotation = 0.0 camera.Zoom = 1.0 - raylib.SetTargetFPS(30) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyDown(raylib.KeyRight) { - player.X += 2 // Player movement - camera.Offset.X -= 2 // Camera displacement with player movement - } else if raylib.IsKeyDown(raylib.KeyLeft) { - player.X -= 2 // Player movement - camera.Offset.X += 2 // Camera displacement with player movement + for !rl.WindowShouldClose() { + if rl.IsKeyDown(rl.KeyRight) { + player.X += 2 // Player movement + } else if rl.IsKeyDown(rl.KeyLeft) { + player.X -= 2 // Player movement } // Camera target follows player - camera.Target = raylib.NewVector2(float32(player.X+20), float32(player.Y+20)) + camera.Target = rl.NewVector2(float32(player.X+20), float32(player.Y+20)) // Camera rotation controls - if raylib.IsKeyDown(raylib.KeyA) { + if rl.IsKeyDown(rl.KeyA) { camera.Rotation-- - } else if raylib.IsKeyDown(raylib.KeyS) { + } else if rl.IsKeyDown(rl.KeyS) { camera.Rotation++ } @@ -71,7 +69,7 @@ func main() { } // Camera zoom controls - camera.Zoom += float32(raylib.GetMouseWheelMove()) * 0.05 + camera.Zoom += float32(rl.GetMouseWheelMove()) * 0.05 if camera.Zoom > 3.0 { camera.Zoom = 3.0 @@ -80,48 +78,48 @@ func main() { } // Camera reset (zoom and rotation) - if raylib.IsKeyPressed(raylib.KeyR) { + if rl.IsKeyPressed(rl.KeyR) { camera.Zoom = 1.0 camera.Rotation = 0.0 } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode2D(camera) + rl.BeginMode2D(camera) - raylib.DrawRectangle(-6000, 320, 13000, 8000, raylib.DarkGray) + rl.DrawRectangle(-6000, 320, 13000, 8000, rl.DarkGray) for i := 0; i < maxBuildings; i++ { - raylib.DrawRectangleRec(buildings[i], buildColors[i]) + rl.DrawRectangleRec(buildings[i], buildColors[i]) } - raylib.DrawRectangleRec(player, raylib.Red) + rl.DrawRectangleRec(player, rl.Red) - raylib.DrawRectangle(int32(camera.Target.X), -500, 1, screenHeight*4, raylib.Green) - raylib.DrawRectangle(-500, int32(camera.Target.Y), screenWidth*4, 1, raylib.Green) + rl.DrawRectangle(int32(camera.Target.X), -500, 1, screenHeight*4, rl.Green) + rl.DrawRectangle(-500, int32(camera.Target.Y), screenWidth*4, 1, rl.Green) - raylib.EndMode2D() + rl.EndMode2D() - raylib.DrawText("SCREEN AREA", 640, 10, 20, raylib.Red) + rl.DrawText("SCREEN AREA", 640, 10, 20, rl.Red) - raylib.DrawRectangle(0, 0, screenWidth, 5, raylib.Red) - raylib.DrawRectangle(0, 5, 5, screenHeight-10, raylib.Red) - raylib.DrawRectangle(screenWidth-5, 5, 5, screenHeight-10, raylib.Red) - raylib.DrawRectangle(0, screenHeight-5, screenWidth, 5, raylib.Red) + rl.DrawRectangle(0, 0, screenWidth, 5, rl.Red) + rl.DrawRectangle(0, 5, 5, screenHeight-10, rl.Red) + rl.DrawRectangle(screenWidth-5, 5, 5, screenHeight-10, rl.Red) + rl.DrawRectangle(0, screenHeight-5, screenWidth, 5, rl.Red) - raylib.DrawRectangle(10, 10, 250, 113, raylib.Fade(raylib.SkyBlue, 0.5)) - raylib.DrawRectangleLines(10, 10, 250, 113, raylib.Blue) + rl.DrawRectangle(10, 10, 250, 113, rl.Fade(rl.SkyBlue, 0.5)) + rl.DrawRectangleLines(10, 10, 250, 113, rl.Blue) - raylib.DrawText("Free 2d camera controls:", 20, 20, 10, raylib.Black) - raylib.DrawText("- Right/Left to move Offset", 40, 40, 10, raylib.DarkGray) - raylib.DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, raylib.DarkGray) - raylib.DrawText("- A / S to Rotate", 40, 80, 10, raylib.DarkGray) - raylib.DrawText("- R to reset Zoom and Rotation", 40, 100, 10, raylib.DarkGray) + rl.DrawText("Free 2d camera controls:", 20, 20, 10, rl.Black) + rl.DrawText("- Right/Left to move Offset", 40, 40, 10, rl.DarkGray) + rl.DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, rl.DarkGray) + rl.DrawText("- A / S to Rotate", 40, 80, 10, rl.DarkGray) + rl.DrawText("- R to reset Zoom and Rotation", 40, 100, 10, rl.DarkGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/2d_camera_mouse_zoom/main.go b/examples/core/2d_camera_mouse_zoom/main.go new file mode 100644 index 0000000..a99522e --- /dev/null +++ b/examples/core/2d_camera_mouse_zoom/main.go @@ -0,0 +1,101 @@ +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 new file mode 100644 index 0000000..7ce4f17 --- /dev/null +++ b/examples/core/2d_camera_platformer/main.go @@ -0,0 +1,261 @@ +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 new file mode 100644 index 0000000..141b376 --- /dev/null +++ b/examples/core/2d_camera_splitscreen/main.go @@ -0,0 +1,128 @@ +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 new file mode 100644 index 0000000..5c83e85 --- /dev/null +++ b/examples/core/2d_paint/main.go @@ -0,0 +1,216 @@ +package main + +import ( + "os" + + rl "git.terah.dev/UnrealXR/raylib-go/raylib" +) + +const colorCount = 23 + +func main() { + const screenWidth, screenHeight int32 = 800, 450 + + rl.InitWindow(screenWidth, screenHeight, "raypaint") + + // Colors to choose from + var colors = [colorCount]rl.Color{ + rl.RayWhite, rl.Yellow, rl.Gold, rl.Orange, 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, + } + + // Define colorsRecs data (for every rectangle) + var colorRecs = [colorCount]rl.Rectangle{} + + for i := 0; i < colorCount; i++ { + colorRecs[i].X = float32(10 + 30*i + 2*i) + colorRecs[i].Y = 10 + colorRecs[i].Width = 30 + colorRecs[i].Height = 30 + } + + colorSelected := 0 + colorSelectedPrev := colorSelected + colorMouseHover := 0 + brushSize := 20 + + var btnSaveRec = rl.Rectangle{750, 10, 40, 30} + btnSaveMouseHover := false + showSaveMessage := false + saveMessageCounter := 0 + + checkSaveHover := func() rl.Color { + if btnSaveMouseHover { + return rl.Red + } + return rl.Black + } + + // Create a RenderTexture2D to use as a canvas + var target rl.RenderTexture2D = rl.LoadRenderTexture(screenWidth, screenHeight) + + // Clear render texture before entering the game loop + rl.BeginTextureMode(target) + rl.ClearBackground(colors[0]) + rl.EndTextureMode() + + rl.SetTargetFPS(120) + + // Main game loop + for !rl.WindowShouldClose() { + mousePos := rl.GetMousePosition() + + // Move between colors with keys + if rl.IsKeyPressed(rl.KeyRight) { + colorSelected++ + } else if rl.IsKeyPressed(rl.KeyLeft) { + colorSelected-- + } + + if colorSelected >= colorCount { + colorSelected = colorCount - 1 + } else if colorSelected < 0 { + colorSelected = 0 + } + + // Choose color with mouse + for i := 0; i < colorCount; i++ { + if rl.CheckCollisionPointRec(mousePos, colorRecs[i]) { + colorMouseHover = i + break + } else { + colorMouseHover = -1 + } + } + + if colorMouseHover >= 0 && rl.IsMouseButtonPressed(rl.MouseLeftButton) { + colorSelected = colorMouseHover + colorSelectedPrev = colorSelected + } + + // Change brush size + brushSize += int(rl.GetMouseWheelMove() * 5) + if brushSize < 2 { + brushSize = 2 + } + + if brushSize > 50 { + brushSize = 50 + } + + if rl.IsKeyPressed(rl.KeyC) { + // Clear render texture to clear color + rl.BeginTextureMode(target) + rl.ClearBackground(colors[0]) + rl.EndTextureMode() + } + + if rl.IsMouseButtonDown(rl.MouseLeftButton) || rl.GetGestureDetected() == rl.GestureDrag { + // Clear render texture to clear color + rl.BeginTextureMode(target) + + if mousePos.Y > 50 { + rl.DrawCircle(int32(mousePos.X), int32(mousePos.Y), float32(brushSize), colors[colorSelected]) + } + + rl.EndTextureMode() + } + + if rl.IsMouseButtonDown(rl.MouseRightButton) { + colorSelected = 0 + + // Erase circle from render texture + rl.BeginTextureMode(target) + + if mousePos.Y > 50 { + rl.DrawCircle(int32(mousePos.X), int32(mousePos.Y), float32(brushSize), colors[0]) + } + + rl.EndTextureMode() + } else { + colorSelected = colorSelectedPrev + } + + if rl.CheckCollisionPointRec(mousePos, btnSaveRec) { + btnSaveMouseHover = true + } else { + btnSaveMouseHover = false + } + + if btnSaveMouseHover && rl.IsMouseButtonReleased(rl.MouseLeftButton) || rl.IsKeyPressed(rl.KeyS) { + image := rl.LoadImageFromTexture(target.Texture) + rl.ImageFlipVertical(*&image) + rl.ExportImage(*image, "export.png") + rl.UnloadImage(image) + showSaveMessage = true + } + + if showSaveMessage { + // On saving, show a full screen message for 2 seconds + saveMessageCounter++ + if saveMessageCounter > 240 { + showSaveMessage = false + saveMessageCounter = 0 + } + } + + // Draw + //---------------------------------------------------------------------------------- + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + rl.DrawTextureRec(target.Texture, rl.Rectangle{0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)}, rl.Vector2{0, 0}, rl.White) + + if mousePos.Y > 50 { + if rl.IsMouseButtonDown(rl.MouseRightButton) { + rl.DrawCircleLines(int32(mousePos.X), int32(mousePos.Y), float32(brushSize), rl.Gray) + } else { + rl.DrawCircle(rl.GetMouseX(), rl.GetMouseY(), float32(brushSize), colors[colorSelected]) + } + } + + // Draw top panel + rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), 50, rl.RayWhite) + rl.DrawLine(0, 50, int32(rl.GetScreenWidth()), 50, rl.LightGray) + + // Draw color selection rectangles + for i := 0; i < colorCount; 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.0)) + } + + rl.DrawRectangleLinesEx(rl.Rectangle{ + colorRecs[colorSelected].X - 2, colorRecs[colorSelected].Y - 2, colorRecs[colorSelected].Width + 4, colorRecs[colorSelected].Height + 4, + }, 2, rl.Black) + + // Draw save image button + rl.DrawRectangleLinesEx(btnSaveRec, 2, checkSaveHover()) + rl.DrawText("SAVE!", 755, 20, 10, checkSaveHover()) + + if showSaveMessage { + rl.DrawRectangle(0, 0, int32(rl.GetScreenWidth()), int32(rl.GetScreenHeight()), rl.Fade(rl.RayWhite, 0.8)) + rl.DrawRectangle(0, 150, int32(rl.GetScreenWidth()), 80, rl.Black) + rl.DrawText("IMAGE SAVED: export.png", 150, 180, 20, rl.RayWhite) + } + + rl.EndDrawing() + + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + rl.UnloadRenderTexture(target) + + rl.CloseWindow() + + os.Exit(0) + +} diff --git a/examples/core/3d_camera_first_person/main.go b/examples/core/3d_camera_first_person/main.go index 24a8170..95ecee5 100644 --- a/examples/core/3d_camera_first_person/main.go +++ b/examples/core/3d_camera_first_person/main.go @@ -1,69 +1,194 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "fmt" + + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( - maxColumns = 20 + maxColumns = 20 + screenWidth = 800 + screenHeight = 450 + False = 0 + True = 1 ) -func main() { - raylib.InitWindow(800, 450, "raylib [core] example - 3d camera first person") +var camModes = map[rl.CameraMode]string{ + rl.CameraFree: "FREE", + rl.CameraOrbital: "ORBITAL", + rl.CameraFirstPerson: "FIRST PERSON", + rl.CameraThirdPerson: "THIRD PERSON", +} - camera := raylib.Camera3D{} - camera.Position = raylib.NewVector3(4.0, 2.0, 4.0) - camera.Target = raylib.NewVector3(0.0, 1.8, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) - camera.Fovy = 60.0 - camera.Type = raylib.CameraPerspective +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") + + // 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 // Generates some random columns heights := make([]float32, maxColumns) - positions := make([]raylib.Vector3, maxColumns) - colors := make([]raylib.Color, maxColumns) + positions := make([]rl.Vector3, maxColumns) + colors := make([]rl.Color, maxColumns) for i := 0; i < maxColumns; i++ { - heights[i] = float32(raylib.GetRandomValue(1, 12)) - positions[i] = raylib.NewVector3(float32(raylib.GetRandomValue(-15, 15)), heights[i]/2, float32(raylib.GetRandomValue(-15, 15))) - colors[i] = raylib.NewColor(uint8(raylib.GetRandomValue(20, 255)), uint8(raylib.GetRandomValue(10, 55)), 30, 255) + 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) } - raylib.SetCameraMode(camera, raylib.CameraFirstPerson) // Set a first person camera mode + rl.DisableCursor() // Limit cursor to relative movement inside the window + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - raylib.SetTargetFPS(60) + // 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 + } - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera + // 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 + } + } - raylib.BeginDrawing() + // 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 - raylib.ClearBackground(raylib.RayWhite) + /* + // 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) + */ - raylib.BeginMode3D(camera) + rl.BeginDrawing() - raylib.DrawPlane(raylib.NewVector3(0.0, 0.0, 0.0), raylib.NewVector2(32.0, 32.0), raylib.LightGray) // Draw ground - raylib.DrawCube(raylib.NewVector3(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, raylib.Blue) // Draw a blue wall - raylib.DrawCube(raylib.NewVector3(16.0, 2.5, 0.0), 1.0, 5.0, 32.0, raylib.Lime) // Draw a green wall - raylib.DrawCube(raylib.NewVector3(0.0, 2.5, 16.0), 32.0, 5.0, 1.0, raylib.Gold) // Draw a yellow wall + rl.ClearBackground(rl.RayWhite) + + rl.BeginMode3D(camera) + + rl.DrawPlane(rl.NewVector3(0.0, 0.0, 0.0), rl.NewVector2(32.0, 32.0), rl.LightGray) // Draw ground + rl.DrawCube(rl.NewVector3(-16.0, 2.5, 0.0), 1.0, 5.0, 32.0, rl.Blue) // Draw a blue wall + rl.DrawCube(rl.NewVector3(16.0, 2.5, 0.0), 1.0, 5.0, 32.0, rl.Lime) // Draw a green wall + rl.DrawCube(rl.NewVector3(0.0, 2.5, 16.0), 32.0, 5.0, 1.0, rl.Gold) // Draw a yellow wall // Draw some cubes around for i := 0; i < maxColumns; i++ { - raylib.DrawCube(positions[i], 2.0, heights[i], 2.0, colors[i]) - raylib.DrawCubeWires(positions[i], 2.0, heights[i], 2.0, raylib.Maroon) + rl.DrawCube(positions[i], 2.0, heights[i], 2.0, colors[i]) + rl.DrawCubeWires(positions[i], 2.0, heights[i], 2.0, rl.Maroon) } - raylib.EndMode3D() + // 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) + } - raylib.DrawRectangle(10, 10, 220, 70, raylib.Fade(raylib.SkyBlue, 0.5)) - raylib.DrawRectangleLines(10, 10, 220, 70, raylib.Blue) + rl.EndMode3D() - raylib.DrawText("First person camera default controls:", 20, 20, 10, raylib.Black) - raylib.DrawText("- Move with keys: W, A, S, D", 40, 40, 10, raylib.DarkGray) - raylib.DrawText("- Mouse move to look around", 40, 60, 10, raylib.DarkGray) + // Draw info boxes + rl.DrawRectangle(5, 5, 330, 100, rl.Fade(rl.SkyBlue, 0.5)) + rl.DrawRectangleLines(5, 5, 330, 100, rl.Blue) - raylib.EndDrawing() + 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.EndDrawing() } - raylib.CloseWindow() + 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 dd82774..c4b4751 100644 --- a/examples/core/3d_camera_free/main.go +++ b/examples/core/3d_camera_free/main.go @@ -1,57 +1,53 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [core] example - 3d camera free") + rl.InitWindow(800, 450, "raylib [core] example - 3d camera free") - camera := raylib.Camera3D{} - camera.Position = raylib.NewVector3(10.0, 10.0, 10.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera3D{} + 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.Type = raylib.CameraPerspective + camera.Projection = rl.CameraPerspective - cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) + cubePosition := rl.NewVector3(0.0, 0.0, 0.0) - raylib.SetCameraMode(camera, raylib.CameraFree) // Set a free camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera - - if raylib.IsKeyDown(raylib.KeyZ) { - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) + if rl.IsKeyDown(rl.KeyZ) { + camera.Target = rl.NewVector3(0.0, 0.0, 0.0) } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) - raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) + rl.DrawCube(cubePosition, 2.0, 2.0, 2.0, rl.Red) + rl.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, rl.Maroon) - raylib.DrawGrid(10, 1.0) + rl.DrawGrid(10, 1.0) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawRectangle(10, 10, 320, 133, raylib.Fade(raylib.SkyBlue, 0.5)) - raylib.DrawRectangleLines(10, 10, 320, 133, raylib.Blue) + rl.DrawRectangle(10, 10, 320, 133, rl.Fade(rl.SkyBlue, 0.5)) + rl.DrawRectangleLines(10, 10, 320, 133, rl.Blue) - raylib.DrawText("Free camera default controls:", 20, 20, 10, raylib.Black) - raylib.DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, raylib.DarkGray) - raylib.DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, raylib.DarkGray) - raylib.DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, raylib.DarkGray) - raylib.DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, raylib.DarkGray) - raylib.DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, raylib.DarkGray) + 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("- Z to zoom to (0, 0, 0)", 40, 120, 10, rl.DarkGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/3d_camera_splitscreen/main.go b/examples/core/3d_camera_splitscreen/main.go new file mode 100644 index 0000000..8a8dc5a --- /dev/null +++ b/examples/core/3d_camera_splitscreen/main.go @@ -0,0 +1,127 @@ +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 034c858..6cf6a63 100644 --- a/examples/core/3d_mode/main.go +++ b/examples/core/3d_mode/main.go @@ -1,43 +1,43 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [core] example - 3d mode") + rl.InitWindow(800, 450, "raylib [core] example - 3d mode") - camera := raylib.Camera3D{} - camera.Position = raylib.NewVector3(0.0, 10.0, 10.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera3D{} + 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 = 45.0 - camera.Type = raylib.CameraPerspective + camera.Projection = rl.CameraPerspective - cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) + cubePosition := rl.NewVector3(0.0, 0.0, 0.0) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) - raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) + rl.DrawCube(cubePosition, 2.0, 2.0, 2.0, rl.Red) + rl.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, rl.Maroon) - raylib.DrawGrid(10, 1.0) + rl.DrawGrid(10, 1.0) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawText("Welcome to the third dimension!", 10, 40, 20, raylib.DarkGray) + rl.DrawText("Welcome to the third dimension!", 10, 40, 20, rl.DarkGray) - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/3d_picking/main.go b/examples/core/3d_picking/main.go index ec61fe5..1bba7ae 100644 --- a/examples/core/3d_picking/main.go +++ b/examples/core/3d_picking/main.go @@ -1,78 +1,78 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking") - camera := raylib.Camera3D{} - camera.Position = raylib.NewVector3(10.0, 10.0, 10.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera3D{} + 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.Type = raylib.CameraPerspective + camera.Projection = rl.CameraPerspective - cubePosition := raylib.NewVector3(0.0, 1.0, 0.0) - cubeSize := raylib.NewVector3(2.0, 2.0, 2.0) + cubePosition := rl.NewVector3(0.0, 1.0, 0.0) + cubeSize := rl.NewVector3(2.0, 2.0, 2.0) - var ray raylib.Ray + var ray rl.Ray + var collision rl.RayCollision - collision := false + rl.SetTargetFPS(60) - raylib.SetCameraMode(camera, raylib.CameraFree) // Set a free camera mode + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode - raylib.SetTargetFPS(60) + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + if !collision.Hit { + ray = rl.GetMouseRay(rl.GetMousePosition(), camera) - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera - - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - // NOTE: This function is NOT WORKING properly! - ray = raylib.GetMouseRay(raylib.GetMousePosition(), camera) - - // Check collision between ray and box - min := raylib.NewVector3(cubePosition.X-cubeSize.X/2, cubePosition.Y-cubeSize.Y/2, cubePosition.Z-cubeSize.Z/2) - max := raylib.NewVector3(cubePosition.X+cubeSize.X/2, cubePosition.Y+cubeSize.Y/2, cubePosition.Z+cubeSize.Z/2) - collision = raylib.CheckCollisionRayBox(ray, raylib.NewBoundingBox(min, max)) + // 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 + } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - if collision { - raylib.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.Red) - raylib.DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.Maroon) + if collision.Hit { + rl.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.Red) + rl.DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.Maroon) - raylib.DrawCubeWires(cubePosition, cubeSize.X+0.2, cubeSize.Y+0.2, cubeSize.Z+0.2, raylib.Green) + rl.DrawCubeWires(cubePosition, cubeSize.X+0.2, cubeSize.Y+0.2, cubeSize.Z+0.2, rl.Green) } else { - raylib.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.Gray) - raylib.DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, raylib.DarkGray) + rl.DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.Gray) + rl.DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, rl.DarkGray) } - raylib.DrawRay(ray, raylib.Maroon) + rl.DrawRay(ray, rl.Maroon) - raylib.DrawGrid(10, 1.0) + rl.DrawGrid(10, 1.0) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawText("Try selecting the box with mouse!", 240, 10, 20, raylib.DarkGray) + rl.DrawText("Try selecting the box with mouse!", 240, 10, 20, rl.DarkGray) - if collision { - raylib.DrawText("BOX SELECTED", (screenWidth-raylib.MeasureText("BOX SELECTED", 30))/2, int32(float32(screenHeight)*0.1), 30, raylib.Green) + if collision.Hit { + rl.DrawText("BOX SELECTED", (screenWidth-rl.MeasureText("BOX SELECTED", 30))/2, int32(float32(screenHeight)*0.1), 30, rl.Green) } - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/basic_window/main.go b/examples/core/basic_window/main.go index 9931223..ced965d 100644 --- a/examples/core/basic_window/main.go +++ b/examples/core/basic_window/main.go @@ -1,22 +1,22 @@ package main -import "github.com/gen2brain/raylib-go/raylib" +import "git.terah.dev/UnrealXR/raylib-go/raylib" func main() { - raylib.SetConfigFlags(raylib.FlagVsyncHint) - raylib.InitWindow(800, 450, "raylib [core] example - basic window") + rl.SetConfigFlags(rl.FlagVsyncHint) + rl.InitWindow(800, 450, "raylib [core] example - basic window") - //raylib.SetTargetFPS(60) + //rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("Congrats! You created your first window!", 190, 200, 20, raylib.LightGray) + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/basic_window_manager/main.go b/examples/core/basic_window_manager/main.go new file mode 100644 index 0000000..98ac1a6 --- /dev/null +++ b/examples/core/basic_window_manager/main.go @@ -0,0 +1,106 @@ +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 aa813ab..2bb9bd3 100644 --- a/examples/core/color_select/main.go +++ b/examples/core/color_select/main.go @@ -1,23 +1,19 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { - raylib.InitWindow(800, 450, "raylib [core] example - color selection (collision detection)") + rl.InitWindow(800, 450, "raylib [core] example - color selection (collision detection)") - colors := [21]raylib.Color{ - raylib.DarkGray, raylib.Maroon, raylib.Orange, raylib.DarkGreen, raylib.DarkBlue, raylib.DarkPurple, - raylib.DarkBrown, raylib.Gray, raylib.Red, raylib.Gold, raylib.Lime, raylib.Blue, raylib.Violet, raylib.Brown, - raylib.LightGray, raylib.Pink, raylib.Yellow, raylib.Green, raylib.SkyBlue, raylib.Purple, raylib.Beige, + colors := [21]rl.Color{ + rl.DarkGray, rl.Maroon, rl.Orange, rl.DarkGreen, rl.DarkBlue, rl.DarkPurple, + rl.DarkBrown, rl.Gray, rl.Red, rl.Gold, rl.Lime, rl.Blue, rl.Violet, rl.Brown, + rl.LightGray, rl.Pink, rl.Yellow, rl.Green, rl.SkyBlue, rl.Purple, rl.Beige, } - colorsRecs := make([]raylib.Rectangle, 21) // Rectangles array + colorsRecs := make([]rl.Rectangle, 21) // Rectangles array // Fills colorsRecs data (for every rectangle) for i := 0; i < 21; i++ { - r := raylib.Rectangle{} + r := rl.Rectangle{} r.X = float32(20 + 100*(i%7) + 10*(i%7)) r.Y = float32(60 + 100*(i/7) + 10*(i/7)) r.Width = 100 @@ -28,18 +24,18 @@ func main() { selected := make([]bool, 21) // Selected rectangles indicator - mousePoint := raylib.Vector2{} + mousePoint := rl.Vector2{} - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - mousePoint = raylib.GetMousePosition() + for !rl.WindowShouldClose() { + mousePoint = rl.GetMousePosition() for i := 0; i < 21; i++ { // Iterate along all the rectangles - if raylib.CheckCollisionPointRec(mousePoint, colorsRecs[i]) { + if rl.CheckCollisionPointRec(mousePoint, colorsRecs[i]) { colors[i].A = 120 - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { selected[i] = !selected[i] } } else { @@ -47,24 +43,24 @@ func main() { } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) for i := 0; i < 21; i++ { // Draw all rectangles - raylib.DrawRectangleRec(colorsRecs[i], colors[i]) + rl.DrawRectangleRec(colorsRecs[i], colors[i]) // Draw four rectangles around selected rectangle if selected[i] { - raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 100, 10, raylib.RayWhite) // Square top rectangle - raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 10, 100, raylib.RayWhite) // Square left rectangle - raylib.DrawRectangle(int32(colorsRecs[i].X+90), int32(colorsRecs[i].Y), 10, 100, raylib.RayWhite) // Square right rectangle - raylib.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y)+90, 100, 10, raylib.RayWhite) // Square bottom rectangle + rl.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 100, 10, rl.RayWhite) // Square top rectangle + rl.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y), 10, 100, rl.RayWhite) // Square left rectangle + rl.DrawRectangle(int32(colorsRecs[i].X+90), int32(colorsRecs[i].Y), 10, 100, rl.RayWhite) // Square right rectangle + rl.DrawRectangle(int32(colorsRecs[i].X), int32(colorsRecs[i].Y)+90, 100, 10, rl.RayWhite) // Square bottom rectangle } } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/core_split_screen/main.go b/examples/core/core_split_screen/main.go new file mode 100644 index 0000000..dd70554 --- /dev/null +++ b/examples/core/core_split_screen/main.go @@ -0,0 +1,144 @@ +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 new file mode 100644 index 0000000..4498b48 --- /dev/null +++ b/examples/core/custom_frame_control/main.go @@ -0,0 +1,131 @@ +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 new file mode 100644 index 0000000..76934b7 --- /dev/null +++ b/examples/core/custom_logging/main.go @@ -0,0 +1,49 @@ +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 2a587bb..cd05821 100644 --- a/examples/core/drop_files/main.go +++ b/examples/core/drop_files/main.go @@ -1,50 +1,47 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - drop files") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - drop files") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - count := int32(0) + var count int var droppedFiles []string - for !raylib.WindowShouldClose() { - if raylib.IsFileDropped() { - droppedFiles = raylib.GetDroppedFiles(&count) + for !rl.WindowShouldClose() { + if rl.IsFileDropped() { + droppedFiles = rl.LoadDroppedFiles() + count = len(droppedFiles) } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) if count == 0 { - raylib.DrawText("Drop your files to this window!", 100, 40, 20, raylib.DarkGray) + rl.DrawText("Drop your files to this window!", 100, 40, 20, rl.DarkGray) } else { - raylib.DrawText("Dropped files:", 100, 40, 20, raylib.DarkGray) + rl.DrawText("Dropped files:", 100, 40, 20, rl.DarkGray) - for i := int32(0); i < count; i++ { + for i := 0; i < count; i++ { if i%2 == 0 { - raylib.DrawRectangle(0, int32(85+40*i), screenWidth, 40, raylib.Fade(raylib.LightGray, 0.5)) + rl.DrawRectangle(0, int32(85+40*i), screenWidth, 40, rl.Fade(rl.LightGray, 0.5)) } else { - raylib.DrawRectangle(0, int32(85+40*i), screenWidth, 40, raylib.Fade(raylib.LightGray, 0.3)) + rl.DrawRectangle(0, int32(85+40*i), screenWidth, 40, rl.Fade(rl.LightGray, 0.3)) } - raylib.DrawText(droppedFiles[i], 120, int32(100), 10, raylib.Gray) + rl.DrawText(droppedFiles[i], 120, int32(100+i*40), 10, rl.Gray) } - raylib.DrawText("Drop new files...", 100, int32(150), 20, raylib.DarkGray) + rl.DrawText("Drop new files...", 100, int32(150+count*40), 20, rl.DarkGray) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.ClearDroppedFiles() + rl.UnloadDroppedFiles() - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/gestures_detection/main.go b/examples/core/gestures_detection/main.go index bcab437..78fd200 100644 --- a/examples/core/gestures_detection/main.go +++ b/examples/core/gestures_detection/main.go @@ -1,9 +1,5 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - var ( maxGestureStrings int = 20 ) @@ -12,47 +8,47 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection") - touchPosition := raylib.NewVector2(0, 0) - touchArea := raylib.NewRectangle(220, 10, float32(screenWidth)-230, float32(screenHeight)-20) + touchPosition := rl.NewVector2(0, 0) + touchArea := rl.NewRectangle(220, 10, float32(screenWidth)-230, float32(screenHeight)-20) gestureStrings := make([]string, 0) - currentGesture := raylib.GestureNone - lastGesture := raylib.GestureNone + currentGesture := rl.GestureNone + lastGesture := rl.GestureNone - //raylib.SetGesturesEnabled(uint32(raylib.GestureHold | raylib.GestureDrag)) // Enable only some gestures to be detected + //rl.SetGesturesEnabled(uint32(rl.GestureHold | rl.GestureDrag)) // Enable only some gestures to be detected - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { lastGesture = currentGesture - currentGesture = raylib.GetGestureDetected() - touchPosition = raylib.GetTouchPosition(0) + currentGesture = rl.GetGestureDetected() + touchPosition = rl.GetTouchPosition(0) - if raylib.CheckCollisionPointRec(touchPosition, touchArea) && currentGesture != raylib.GestureNone { + if rl.CheckCollisionPointRec(touchPosition, touchArea) && currentGesture != rl.GestureNone { if currentGesture != lastGesture { switch currentGesture { - case raylib.GestureTap: + case rl.GestureTap: gestureStrings = append(gestureStrings, "GESTURE TAP") - case raylib.GestureDoubletap: + case rl.GestureDoubletap: gestureStrings = append(gestureStrings, "GESTURE DOUBLETAP") - case raylib.GestureHold: + case rl.GestureHold: gestureStrings = append(gestureStrings, "GESTURE HOLD") - case raylib.GestureDrag: + case rl.GestureDrag: gestureStrings = append(gestureStrings, "GESTURE DRAG") - case raylib.GestureSwipeRight: + case rl.GestureSwipeRight: gestureStrings = append(gestureStrings, "GESTURE SWIPE RIGHT") - case raylib.GestureSwipeLeft: + case rl.GestureSwipeLeft: gestureStrings = append(gestureStrings, "GESTURE SWIPE LEFT") - case raylib.GestureSwipeUp: + case rl.GestureSwipeUp: gestureStrings = append(gestureStrings, "GESTURE SWIPE UP") - case raylib.GestureSwipeDown: + case rl.GestureSwipeDown: gestureStrings = append(gestureStrings, "GESTURE SWIPE DOWN") - case raylib.GesturePinchIn: + case rl.GesturePinchIn: gestureStrings = append(gestureStrings, "GESTURE PINCH IN") - case raylib.GesturePinchOut: + case rl.GesturePinchOut: gestureStrings = append(gestureStrings, "GESTURE PINCH OUT") } @@ -62,38 +58,38 @@ func main() { } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawRectangleRec(touchArea, raylib.Gray) - raylib.DrawRectangle(225, 15, screenWidth-240, screenHeight-30, raylib.RayWhite) + rl.DrawRectangleRec(touchArea, rl.Gray) + rl.DrawRectangle(225, 15, screenWidth-240, screenHeight-30, rl.RayWhite) - raylib.DrawText("GESTURES TEST AREA", screenWidth-270, screenHeight-40, 20, raylib.Fade(raylib.Gray, 0.5)) + rl.DrawText("GESTURES TEST AREA", screenWidth-270, screenHeight-40, 20, rl.Fade(rl.Gray, 0.5)) for i := 0; i < len(gestureStrings); i++ { if i%2 == 0 { - raylib.DrawRectangle(10, int32(30+20*i), 200, 20, raylib.Fade(raylib.LightGray, 0.5)) + rl.DrawRectangle(10, int32(30+20*i), 200, 20, rl.Fade(rl.LightGray, 0.5)) } else { - raylib.DrawRectangle(10, int32(30+20*i), 200, 20, raylib.Fade(raylib.LightGray, 0.3)) + rl.DrawRectangle(10, int32(30+20*i), 200, 20, rl.Fade(rl.LightGray, 0.3)) } if i < len(gestureStrings)-1 { - raylib.DrawText(gestureStrings[i], 35, int32(36+20*i), 10, raylib.DarkGray) + rl.DrawText(gestureStrings[i], 35, int32(36+20*i), 10, rl.DarkGray) } else { - raylib.DrawText(gestureStrings[i], 35, int32(36+20*i), 10, raylib.Maroon) + rl.DrawText(gestureStrings[i], 35, int32(36+20*i), 10, rl.Maroon) } } - raylib.DrawRectangleLines(10, 29, 200, screenHeight-50, raylib.Gray) - raylib.DrawText("DETECTED GESTURES", 50, 15, 10, raylib.Gray) + rl.DrawRectangleLines(10, 29, 200, screenHeight-50, rl.Gray) + rl.DrawText("DETECTED GESTURES", 50, 15, 10, rl.Gray) - if currentGesture != raylib.GestureNone { - raylib.DrawCircleV(touchPosition, 30, raylib.Maroon) + if currentGesture != rl.GestureNone { + rl.DrawCircleV(touchPosition, 30, rl.Maroon) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/input_gamepad/main.go b/examples/core/input_gamepad/main.go index 8c2bcce..3a42f93 100644 --- a/examples/core/input_gamepad/main.go +++ b/examples/core/input_gamepad/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( @@ -12,190 +12,192 @@ const ( ) func main() { - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) // Set MSAA 4X hint before windows creation + rl.SetConfigFlags(rl.FlagMsaa4xHint) // Set MSAA 4X hint before windows creation - raylib.InitWindow(800, 450, "raylib [core] example - gamepad input") + rl.InitWindow(800, 450, "raylib [core] example - gamepad input") - texPs3Pad := raylib.LoadTexture("ps3.png") - texXboxPad := raylib.LoadTexture("xbox.png") + texPs3Pad := rl.LoadTexture("ps3.png") + texXboxPad := rl.LoadTexture("xbox.png") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + var gamepad int32 = 0 // which gamepad to display - raylib.ClearBackground(raylib.RayWhite) + for !rl.WindowShouldClose() { + rl.BeginDrawing() - if raylib.IsGamepadAvailable(raylib.GamepadPlayer1) { - raylib.DrawText(fmt.Sprintf("GP1: %s", raylib.GetGamepadName(raylib.GamepadPlayer1)), 10, 10, 10, raylib.Black) + rl.ClearBackground(rl.RayWhite) - if raylib.IsGamepadName(raylib.GamepadPlayer1, xbox360NameID) { - raylib.DrawTexture(texXboxPad, 0, 0, raylib.DarkGray) + if rl.IsGamepadAvailable(gamepad) { + rl.DrawText(fmt.Sprintf("GP1: %s", rl.GetGamepadName(gamepad)), 10, 10, 10, rl.Black) + + if rl.GetGamepadName(gamepad) == xbox360NameID { + rl.DrawTexture(texXboxPad, 0, 0, rl.DarkGray) // Draw buttons: xbox home - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonHome) { - raylib.DrawCircle(394, 89, 19, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddle) { + rl.DrawCircle(394, 89, 19, rl.Red) } // Draw buttons: basic - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonStart) { - raylib.DrawCircle(436, 150, 9, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleRight) { + rl.DrawCircle(436, 150, 9, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonSelect) { - raylib.DrawCircle(352, 150, 9, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleLeft) { + rl.DrawCircle(352, 150, 9, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonX) { - raylib.DrawCircle(501, 151, 15, raylib.Blue) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceLeft) { + rl.DrawCircle(501, 151, 15, rl.Blue) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonA) { - raylib.DrawCircle(536, 187, 15, raylib.Lime) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceDown) { + rl.DrawCircle(536, 187, 15, rl.Lime) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonB) { - raylib.DrawCircle(572, 151, 15, raylib.Maroon) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceRight) { + rl.DrawCircle(572, 151, 15, rl.Maroon) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonY) { - raylib.DrawCircle(536, 115, 15, raylib.Gold) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceUp) { + rl.DrawCircle(536, 115, 15, rl.Gold) } // Draw buttons: d-pad - raylib.DrawRectangle(317, 202, 19, 71, raylib.Black) - raylib.DrawRectangle(293, 228, 69, 19, raylib.Black) - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonUp) { - raylib.DrawRectangle(317, 202, 19, 26, raylib.Red) + rl.DrawRectangle(317, 202, 19, 71, rl.Black) + rl.DrawRectangle(293, 228, 69, 19, rl.Black) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceUp) { + rl.DrawRectangle(317, 202, 19, 26, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonDown) { - raylib.DrawRectangle(317, 202+45, 19, 26, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceDown) { + rl.DrawRectangle(317, 202+45, 19, 26, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonLeft) { - raylib.DrawRectangle(292, 228, 25, 19, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceLeft) { + rl.DrawRectangle(292, 228, 25, 19, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonRight) { - raylib.DrawRectangle(292+44, 228, 26, 19, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceRight) { + rl.DrawRectangle(292+44, 228, 26, 19, rl.Red) } // Draw buttons: left-right back - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonLb) { - raylib.DrawCircle(259, 61, 20, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftTrigger1) { + rl.DrawCircle(259, 61, 20, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadXboxButtonRb) { - raylib.DrawCircle(536, 61, 20, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightTrigger1) { + rl.DrawCircle(536, 61, 20, rl.Red) } // Draw axis: left joystick - raylib.DrawCircle(259, 152, 39, raylib.Black) - raylib.DrawCircle(259, 152, 34, raylib.LightGray) - raylib.DrawCircle(int32(259+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisLeftX)*20)), - int32(152-(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisLeftY)*20)), 25, raylib.Black) + 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) // Draw axis: right joystick - raylib.DrawCircle(461, 237, 38, raylib.Black) - raylib.DrawCircle(461, 237, 33, raylib.LightGray) - raylib.DrawCircle(int32(461+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisRightX)*20)), - int32(237-(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisRightY)*20)), 25, raylib.Black) + 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) // Draw axis: left-right triggers - raylib.DrawRectangle(170, 30, 15, 70, raylib.Gray) - raylib.DrawRectangle(604, 30, 15, 70, raylib.Gray) - raylib.DrawRectangle(170, 30, 15, int32(((1.0+raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisLt))/2.0)*70), raylib.Red) - raylib.DrawRectangle(604, 30, 15, int32(((1.0+raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadXboxAxisRt))/2.0)*70), raylib.Red) + 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) - } else if raylib.IsGamepadName(raylib.GamepadPlayer1, ps3NameID) { - raylib.DrawTexture(texPs3Pad, 0, 0, raylib.DarkGray) + } else if rl.GetGamepadName(gamepad) == ps3NameID { + rl.DrawTexture(texPs3Pad, 0, 0, rl.DarkGray) // Draw buttons: ps - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonPs) { - raylib.DrawCircle(396, 222, 13, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddle) { + rl.DrawCircle(396, 222, 13, rl.Red) } // Draw buttons: basic - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonSelect) { - raylib.DrawRectangle(328, 170, 32, 13, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleLeft) { + rl.DrawRectangle(328, 170, 32, 13, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonStart) { - raylib.DrawTriangle(raylib.NewVector2(436, 168), raylib.NewVector2(436, 185), raylib.NewVector2(464, 177), raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonMiddleRight) { + rl.DrawTriangle(rl.NewVector2(436, 168), rl.NewVector2(436, 185), rl.NewVector2(464, 177), rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonTriangle) { - raylib.DrawCircle(557, 144, 13, raylib.Lime) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceUp) { + rl.DrawCircle(557, 144, 13, rl.Lime) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonCircle) { - raylib.DrawCircle(586, 173, 13, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceRight) { + rl.DrawCircle(586, 173, 13, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonCross) { - raylib.DrawCircle(557, 203, 13, raylib.Violet) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceDown) { + rl.DrawCircle(557, 203, 13, rl.Violet) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonSquare) { - raylib.DrawCircle(527, 173, 13, raylib.Pink) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightFaceLeft) { + rl.DrawCircle(527, 173, 13, rl.Pink) } // Draw buttons: d-pad - raylib.DrawRectangle(225, 132, 24, 84, raylib.Black) - raylib.DrawRectangle(195, 161, 84, 25, raylib.Black) - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonUp) { - raylib.DrawRectangle(225, 132, 24, 29, raylib.Red) + rl.DrawRectangle(225, 132, 24, 84, rl.Black) + rl.DrawRectangle(195, 161, 84, 25, rl.Black) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceUp) { + rl.DrawRectangle(225, 132, 24, 29, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonDown) { - raylib.DrawRectangle(225, 132+54, 24, 30, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceDown) { + rl.DrawRectangle(225, 132+54, 24, 30, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonLeft) { - raylib.DrawRectangle(195, 161, 30, 25, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceLeft) { + rl.DrawRectangle(195, 161, 30, 25, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonRight) { - raylib.DrawRectangle(195+54, 161, 30, 25, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftFaceRight) { + rl.DrawRectangle(195+54, 161, 30, 25, rl.Red) } // Draw buttons: left-right back buttons - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonL1) { - raylib.DrawCircle(239, 82, 20, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonLeftTrigger1) { + rl.DrawCircle(239, 82, 20, rl.Red) } - if raylib.IsGamepadButtonDown(raylib.GamepadPlayer1, raylib.GamepadPs3ButtonR1) { - raylib.DrawCircle(557, 82, 20, raylib.Red) + if rl.IsGamepadButtonDown(gamepad, rl.GamepadButtonRightTrigger1) { + rl.DrawCircle(557, 82, 20, rl.Red) } // Draw axis: left joystick - raylib.DrawCircle(319, 255, 35, raylib.Black) - raylib.DrawCircle(319, 255, 31, raylib.LightGray) - raylib.DrawCircle(int32(319+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisLeftX)*20)), - int32(255+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisLeftY)*20)), 25, raylib.Black) + 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) // Draw axis: right joystick - raylib.DrawCircle(475, 255, 35, raylib.Black) - raylib.DrawCircle(475, 255, 31, raylib.LightGray) - raylib.DrawCircle(int32(475+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisRightX)*20)), - int32(255+(raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisRightY)*20)), 25, raylib.Black) + 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) // Draw axis: left-right triggers - raylib.DrawRectangle(169, 48, 15, 70, raylib.Gray) - raylib.DrawRectangle(611, 48, 15, 70, raylib.Gray) - raylib.DrawRectangle(169, 48, 15, int32(((1.0-raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisL2))/2.0)*70), raylib.Red) - raylib.DrawRectangle(611, 48, 15, int32(((1.0-raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, raylib.GamepadPs3AxisR2))/2.0)*70), raylib.Red) + 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) } else { - raylib.DrawText("- GENERIC GAMEPAD -", 280, 180, 20, raylib.Gray) + rl.DrawText("- GENERIC GAMEPAD -", 280, 180, 20, rl.Gray) // TODO: Draw generic gamepad } - raylib.DrawText(fmt.Sprintf("DETECTED AXIS [%d]:", raylib.GetGamepadAxisCount(raylib.GamepadPlayer1)), 10, 50, 10, raylib.Maroon) + rl.DrawText(fmt.Sprintf("DETECTED AXIS [%d]:", rl.GetGamepadAxisCount(gamepad)), 10, 50, 10, rl.Maroon) - for i := int32(0); i < raylib.GetGamepadAxisCount(raylib.GamepadPlayer1); i++ { - raylib.DrawText(fmt.Sprintf("AXIS %d: %.02f", i, raylib.GetGamepadAxisMovement(raylib.GamepadPlayer1, i)), 20, 70+20*i, 10, raylib.DarkGray) + 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) } - if raylib.GetGamepadButtonPressed() != -1 { - raylib.DrawText(fmt.Sprintf("DETECTED BUTTON: %d", raylib.GetGamepadButtonPressed()), 10, 430, 10, raylib.Red) + if rl.GetGamepadButtonPressed() != -1 { + rl.DrawText(fmt.Sprintf("DETECTED BUTTON: %d", rl.GetGamepadButtonPressed()), 10, 430, 10, rl.Red) } else { - raylib.DrawText("DETECTED BUTTON: NONE", 10, 430, 10, raylib.Gray) + rl.DrawText("DETECTED BUTTON: NONE", 10, 430, 10, rl.Gray) } } else { - raylib.DrawText("GP1: NOT DETECTED", 10, 10, 10, raylib.Gray) + rl.DrawText("GP1: NOT DETECTED", 10, 10, 10, rl.Gray) - raylib.DrawTexture(texXboxPad, 0, 0, raylib.LightGray) + rl.DrawTexture(texXboxPad, 0, 0, rl.LightGray) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texPs3Pad) - raylib.UnloadTexture(texXboxPad) + rl.UnloadTexture(texPs3Pad) + rl.UnloadTexture(texXboxPad) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/input_keys/main.go b/examples/core/input_keys/main.go index f92a14f..90d2be8 100644 --- a/examples/core/input_keys/main.go +++ b/examples/core/input_keys/main.go @@ -1,41 +1,37 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input") - ballPosition := raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2) + ballPosition := rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyDown(raylib.KeyRight) { + for !rl.WindowShouldClose() { + if rl.IsKeyDown(rl.KeyRight) { ballPosition.X += 0.8 } - if raylib.IsKeyDown(raylib.KeyLeft) { + if rl.IsKeyDown(rl.KeyLeft) { ballPosition.X -= 0.8 } - if raylib.IsKeyDown(raylib.KeyUp) { + if rl.IsKeyDown(rl.KeyUp) { ballPosition.Y -= 0.8 } - if raylib.IsKeyDown(raylib.KeyDown) { + if rl.IsKeyDown(rl.KeyDown) { ballPosition.Y += 0.8 } - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("move the ball with arrow keys", 10, 10, 20, raylib.DarkGray) - raylib.DrawCircleV(ballPosition, 50, raylib.Maroon) + rl.DrawText("move the ball with arrow keys", 10, 10, 20, rl.DarkGray) + rl.DrawCircleV(ballPosition, 50, rl.Maroon) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/input_mouse/main.go b/examples/core/input_mouse/main.go index c71a88e..72d2af6 100644 --- a/examples/core/input_mouse/main.go +++ b/examples/core/input_mouse/main.go @@ -1,35 +1,35 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [core] example - mouse input") - raylib.SetTargetFPS(60) + rl.InitWindow(800, 450, "raylib [core] example - mouse input") + rl.SetTargetFPS(60) - ballColor := raylib.DarkBlue + ballColor := rl.DarkBlue - for !raylib.WindowShouldClose() { - ballPosition := raylib.GetMousePosition() + for !rl.WindowShouldClose() { + ballPosition := rl.GetMousePosition() - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - ballColor = raylib.Maroon - } else if raylib.IsMouseButtonPressed(raylib.MouseMiddleButton) { - ballColor = raylib.Lime - } else if raylib.IsMouseButtonPressed(raylib.MouseRightButton) { - ballColor = raylib.DarkBlue + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + ballColor = rl.Maroon + } else if rl.IsMouseButtonPressed(rl.MouseMiddleButton) { + ballColor = rl.Lime + } else if rl.IsMouseButtonPressed(rl.MouseRightButton) { + ballColor = rl.DarkBlue } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) - raylib.DrawCircleV(ballPosition, 40, ballColor) + rl.ClearBackground(rl.RayWhite) + rl.DrawCircleV(ballPosition, 40, ballColor) - raylib.DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, raylib.DarkGray) + rl.DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, rl.DarkGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/mouse_wheel/main.go b/examples/core/mouse_wheel/main.go index d8e66fa..bfa2819 100644 --- a/examples/core/mouse_wheel/main.go +++ b/examples/core/mouse_wheel/main.go @@ -3,34 +3,34 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse wheel") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse wheel") boxPositionY := screenHeight/2 - 40 scrollSpeed := int32(4) // Scrolling speed in pixels - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - boxPositionY -= raylib.GetMouseWheelMove() * scrollSpeed + for !rl.WindowShouldClose() { + boxPositionY -= int32(rl.GetMouseWheelMove()) * scrollSpeed - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawRectangle(screenWidth/2-40, boxPositionY, 80, 80, raylib.Maroon) + rl.DrawRectangle(screenWidth/2-40, boxPositionY, 80, 80, rl.Maroon) - raylib.DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, raylib.Gray) - raylib.DrawText(fmt.Sprintf("Box position Y: %d", boxPositionY), 10, 40, 20, raylib.LightGray) + rl.DrawText("Use mouse wheel to move the square up and down!", 10, 10, 20, rl.Gray) + rl.DrawText(fmt.Sprintf("Box position Y: %d", boxPositionY), 10, 40, 20, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/random_values/main.go b/examples/core/random_values/main.go index 94da27f..c0a88a8 100644 --- a/examples/core/random_values/main.go +++ b/examples/core/random_values/main.go @@ -3,36 +3,36 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [core] example - generate random values") + rl.InitWindow(800, 450, "raylib [core] example - generate random values") - framesCounter := 0 // Variable used to count frames - randValue := raylib.GetRandomValue(-8, 5) // Get a random integer number between -8 and 5 (both included) + framesCounter := 0 // Variable used to count frames + randValue := rl.GetRandomValue(-8, 5) // Get a random integer number between -8 and 5 (both included) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { framesCounter++ // Every two seconds (120 frames) a new random value is generated if ((framesCounter / 120) % 2) == 1 { - randValue = raylib.GetRandomValue(-8, 5) + randValue = rl.GetRandomValue(-8, 5) framesCounter = 0 } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, raylib.Maroon) + rl.DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, rl.Maroon) - raylib.DrawText(fmt.Sprintf("%d", randValue), 360, 180, 80, raylib.LightGray) + rl.DrawText(fmt.Sprintf("%d", randValue), 360, 180, 80, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/core/scissor_test/main.go b/examples/core/scissor_test/main.go new file mode 100644 index 0000000..2be5593 --- /dev/null +++ b/examples/core/scissor_test/main.go @@ -0,0 +1,52 @@ +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 new file mode 100644 index 0000000..b137f67 --- /dev/null +++ b/examples/core/smooth_pixelperfect/main.go @@ -0,0 +1,85 @@ +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 0898700..c2f136e 100644 --- a/examples/core/storage_values/main.go +++ b/examples/core/storage_values/main.go @@ -1,58 +1,127 @@ +/******************************************************************************************* +* +* 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" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( - storageScore = 0 - storageHiscore = 1 + screenWidth = 800 + screenHeight = 450 + storageDataFile = "storage.data" + // NOTE: Storage positions must start with 0, directly related to file memory layout + storagePositionScore = 0 + storagePositionHiscore = 1 ) func main() { - raylib.InitWindow(800, 450, "raylib [core] example - storage save/load values") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - storage save/load values") - score := int32(0) - hiscore := int32(0) + var score int32 + var hiscore int32 + var framesCounter int32 - framesCounter := 0 + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - if raylib.IsKeyPressed(raylib.KeyR) { - score = raylib.GetRandomValue(1000, 2000) - hiscore = raylib.GetRandomValue(2000, 4000) + // Main game loop + for !rl.WindowShouldClose() { // Detect window close button or ESC key + // Update + if rl.IsKeyPressed(rl.KeyR) { + score = rl.GetRandomValue(1000, 2000) + hiscore = rl.GetRandomValue(2000, 4000) } - if raylib.IsKeyPressed(raylib.KeyEnter) { - raylib.StorageSaveValue(storageScore, score) - raylib.StorageSaveValue(storageHiscore, hiscore) - } else if raylib.IsKeyPressed(raylib.KeySpace) { + if rl.IsKeyPressed(rl.KeyEnter) { + _ = SaveStorageValue(storagePositionScore, score) + _ = SaveStorageValue(storagePositionHiscore, hiscore) + } else if rl.IsKeyPressed(rl.KeySpace) { // NOTE: If requested position could not be found, value 0 is returned - score = raylib.StorageLoadValue(storageScore) - hiscore = raylib.StorageLoadValue(storageHiscore) + score, _ = LoadStorageValue(storagePositionScore) + hiscore, _ = LoadStorageValue(storagePositionHiscore) } framesCounter++ - raylib.BeginDrawing() + // Draw + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.ClearBackground(raylib.RayWhite) + rl.DrawText(fmt.Sprintf("SCORE: %d", score), 280, 130, 40, rl.Maroon) + rl.DrawText(fmt.Sprintf("HI-SCORE: %d", hiscore), 210, 200, 50, rl.Black) - raylib.DrawText(fmt.Sprintf("SCORE: %d", score), 280, 130, 40, raylib.Maroon) - raylib.DrawText(fmt.Sprintf("HI-SCORE: %d", hiscore), 210, 200, 50, raylib.Black) + rl.DrawText(fmt.Sprintf("frames: %d", framesCounter), 10, 10, 20, rl.Lime) - raylib.DrawText(fmt.Sprintf("frames: %d", framesCounter), 10, 10, 20, raylib.Lime) + rl.DrawText("Press R to generate random numbers", 220, 40, 20, rl.LightGray) + rl.DrawText("Press ENTER to SAVE values", 250, 310, 20, rl.LightGray) + rl.DrawText("Press SPACE to LOAD values", 252, 350, 20, rl.LightGray) - raylib.DrawText("Press R to generate random numbers", 220, 40, 20, raylib.LightGray) - raylib.DrawText("Press ENTER to SAVE values", 250, 310, 20, raylib.LightGray) - raylib.DrawText("Press SPACE to LOAD values", 252, 350, 20, raylib.LightGray) - - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + // 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 } diff --git a/examples/core/vr_simulator/distortion100.fs b/examples/core/vr_simulator/distortion100.fs new file mode 100644 index 0000000..f72c689 --- /dev/null +++ b/examples/core/vr_simulator/distortion100.fs @@ -0,0 +1,52 @@ +#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 new file mode 100644 index 0000000..97044c4 --- /dev/null +++ b/examples/core/vr_simulator/distortion330.fs @@ -0,0 +1,53 @@ +#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 index b8cc807..3e1e7e1 100644 --- a/examples/core/vr_simulator/main.go +++ b/examples/core/vr_simulator/main.go @@ -1,58 +1,137 @@ +/******************************************************************************************* +* +* 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 ( - "github.com/gen2brain/raylib-go/raylib" + "fmt" + + rl "git.terah.dev/UnrealXR/raylib-go/raylib" +) + +const ( + screenWidth = 800 + screenHeight = 450 + glslVersion = 330 // Desktop + // glslVersion = 100 // Android, web ) func main() { - screenWidth := int32(1080) - screenHeight := int32(600) - // NOTE: screenWidth/screenHeight should match VR device aspect ratio + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator") - raylib.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: default device (simulator) - raylib.InitVrSimulator(raylib.GetVrDeviceInfo(raylib.HmdOculusRiftCv1)) // Init VR device (Oculus Rift CV1) + // NOTE: CV1 uses fresnel-hybrid-asymmetric lenses with specific compute shaders + // Following parameters are just an approximation to CV1 distortion stereo rendering - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(5.0, 2.0, 5.0) // Camera position - camera.Target = raylib.NewVector3(0.0, 2.0, 0.0) // Camera looking at point - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) // Camera up vector (rotation towards target) - camera.Fovy = 60.0 // Camera field-of-view Y - - cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) - - raylib.SetCameraMode(camera, raylib.CameraFirstPerson) // Set first person camera mode - - raylib.SetTargetFPS(90) - - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera (simulator mode) - - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.BeginVrDrawing() - - raylib.BeginMode3D(camera) - - raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) - raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) - - raylib.DrawGrid(40, 1.0) - - raylib.EndMode3D() - - raylib.EndVrDrawing() - - raylib.DrawFPS(10, 10) - - raylib.EndDrawing() + // 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}, } - raylib.CloseVrSimulator() // Close VR simulator + // Load VR stereo config for VR device parameters (Oculus Rift CV1 parameters) + config := rl.LoadVrStereoConfig(device) - raylib.CloseWindow() + // 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 new file mode 100644 index 0000000..5fa82fa --- /dev/null +++ b/examples/core/window_flags/main.go @@ -0,0 +1,260 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..b004d34 --- /dev/null +++ b/examples/core/window_letterbox/main.go @@ -0,0 +1,115 @@ +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 new file mode 100644 index 0000000..4858ed5 --- /dev/null +++ b/examples/core/window_should_close/main.go @@ -0,0 +1,47 @@ +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 c61e81a..53b4ba7 100644 --- a/examples/core/world_screen/main.go +++ b/examples/core/world_screen/main.go @@ -1,52 +1,50 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free") + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(10.0, 10.0, 10.0) // Camera position - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) // Camera looking at point - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) // Camera up vector (rotation towards target) - camera.Fovy = 45.0 // Camera field-of-view Y + camera := rl.Camera{} + 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 - cubePosition := raylib.NewVector3(0.0, 0.0, 0.0) - cubeScreenPosition := raylib.Vector2{} + cubePosition := rl.NewVector3(0.0, 0.0, 0.0) + cubeScreenPosition := rl.Vector2{} - raylib.SetCameraMode(camera, raylib.CameraFree) // Set a free camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode // Calculate cube screen space position (with a little offset to be in top) - cubeScreenPosition = raylib.GetWorldToScreen(raylib.NewVector3(cubePosition.X, cubePosition.Y+2.5, cubePosition.Z), camera) + cubeScreenPosition = rl.GetWorldToScreen(rl.NewVector3(cubePosition.X, cubePosition.Y+2.5, cubePosition.Z), camera) - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawCube(cubePosition, 2.0, 2.0, 2.0, raylib.Red) - raylib.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, raylib.Maroon) + rl.DrawCube(cubePosition, 2.0, 2.0, 2.0, rl.Red) + rl.DrawCubeWires(cubePosition, 2.0, 2.0, 2.0, rl.Maroon) - raylib.DrawGrid(10, 1.0) + rl.DrawGrid(10, 1.0) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawText("Enemy: 100 / 100", int32(cubeScreenPosition.X)-raylib.MeasureText("Enemy: 100 / 100", 20)/2, int32(cubeScreenPosition.Y), 20, raylib.Black) - raylib.DrawText("Text is always on top of the cube", (screenWidth-raylib.MeasureText("Text is always on top of the cube", 20))/2, 25, 20, raylib.Gray) + rl.DrawText("Enemy: 100 / 100", int32(cubeScreenPosition.X)-rl.MeasureText("Enemy: 100 / 100", 20)/2, int32(cubeScreenPosition.Y), 20, rl.Black) + rl.DrawText("Text is always on top of the cube", (screenWidth-rl.MeasureText("Text is always on top of the cube", 20))/2, 25, 20, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/easings/easings/easings.gif b/examples/easings/easings/easings.gif new file mode 100644 index 0000000..633bcf1 Binary files /dev/null and b/examples/easings/easings/easings.gif differ diff --git a/examples/easings/easings/main.go b/examples/easings/easings/main.go index 92de6b3..c2371fb 100644 --- a/examples/easings/easings/main.go +++ b/examples/easings/easings/main.go @@ -1,17 +1,19 @@ package main import ( - "github.com/gen2brain/raylib-go/easings" - "github.com/gen2brain/raylib-go/raygui" - "github.com/gen2brain/raylib-go/raylib" + "strings" + + "git.terah.dev/UnrealXR/raylib-go/easings" + "git.terah.dev/UnrealXR/raylib-go/raygui" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagVsyncHint) - raylib.InitWindow(screenWidth, screenHeight, "raylib [easings] example - easings") + rl.SetConfigFlags(rl.FlagVsyncHint) + rl.InitWindow(screenWidth, screenHeight, "raylib [easings] example - easings") currentTime := 0 duration := float32(60) @@ -19,18 +21,18 @@ func main() { finalPositionX := startPositionX * 3 currentPositionX := startPositionX - ballPosition := raylib.NewVector2(startPositionX, float32(screenHeight)/2) + ballPosition := rl.NewVector2(startPositionX, float32(screenHeight)/2) - comboActive := 0 - comboLastActive := 0 + comboActive := int32(0) + comboLastActive := int32(0) easingTypes := []string{"SineIn", "SineOut", "SineInOut", "BounceIn", "BounceOut", "BounceInOut", "BackIn", "BackOut", "BackInOut"} ease := easingTypes[comboActive] - //raylib.SetTargetFPS(60) + //rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyDown(raylib.KeyR) { + for !rl.WindowShouldClose() { + if rl.IsKeyDown(rl.KeyR) { currentTime = 0 currentPositionX = startPositionX ballPosition.X = currentPositionX @@ -71,18 +73,18 @@ func main() { currentTime++ } - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raygui.Label(raylib.NewRectangle(20, 20, 200, 20), "Easing Type:") - comboActive = raygui.ComboBox(raylib.NewRectangle(20, 40, 200, 20), easingTypes, comboActive) + raygui.Label(rl.NewRectangle(20, 20, 200, 20), "Easing Type:") + comboActive = raygui.ComboBox(rl.NewRectangle(20, 40, 200, 20), strings.Join(easingTypes, ";"), comboActive) - raygui.Label(raylib.NewRectangle(20, 80, 200, 20), "Press R to reset") + raygui.Label(rl.NewRectangle(20, 80, 200, 20), "Press R to reset") - raylib.DrawCircleV(ballPosition, 50, raylib.Maroon) + rl.DrawCircleV(ballPosition, 50, rl.Maroon) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/games/arkanoid/main.go b/examples/games/arkanoid/main.go new file mode 100644 index 0000000..0339aaa --- /dev/null +++ b/examples/games/arkanoid/main.go @@ -0,0 +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() +} diff --git a/examples/games/floppy/main.go b/examples/games/floppy/main.go index 3992e48..35c61b1 100644 --- a/examples/games/floppy/main.go +++ b/examples/games/floppy/main.go @@ -4,8 +4,6 @@ import ( "fmt" "os" "runtime" - - "github.com/gen2brain/raylib-go/raylib" ) const ( @@ -35,20 +33,20 @@ const ( // Floppy type type Floppy struct { - Position raylib.Vector2 + Position rl.Vector2 } // Pipe type type Pipe struct { - Rec raylib.Rectangle - Color raylib.Color + Rec rl.Rectangle + Color rl.Color Active bool } // Particle type type Particle struct { - Position raylib.Vector2 - Color raylib.Color + Position rl.Vector2 + Color rl.Color Alpha float32 Size float32 Rotation float32 @@ -57,17 +55,17 @@ type Particle struct { // Game type type Game struct { - FxFlap raylib.Sound - FxSlap raylib.Sound - FxPoint raylib.Sound - FxClick raylib.Sound + FxFlap rl.Sound + FxSlap rl.Sound + FxPoint rl.Sound + FxClick rl.Sound - TxSprites raylib.Texture2D - TxSmoke raylib.Texture2D - TxClouds raylib.Texture2D + TxSprites rl.Texture2D + TxSmoke rl.Texture2D + TxClouds rl.Texture2D - CloudRec raylib.Rectangle - FrameRec raylib.Rectangle + CloudRec rl.Rectangle + FrameRec rl.Rectangle GameOver bool Dead bool @@ -84,7 +82,7 @@ type Game struct { Particles []Particle Pipes []Pipe - PipesPos []raylib.Vector2 + PipesPos []rl.Vector2 } // NewGame - Start new game @@ -95,7 +93,7 @@ func NewGame() (g Game) { // On Android this sets callback function to be used for android_main func init() { - raylib.SetCallbackFunc(main) + rl.SetCallbackFunc(main) } func main() { @@ -104,16 +102,16 @@ func main() { game.GameOver = true // Initialize window - raylib.InitWindow(screenWidth, screenHeight, "Floppy Gopher") + rl.InitWindow(screenWidth, screenHeight, "Floppy Gopher") // Initialize audio - raylib.InitAudioDevice() + rl.InitAudioDevice() // NOTE: Textures and Sounds MUST be loaded after Window/Audio initialization game.Load() // Limit FPS - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) // Main loop for !game.WindowShouldClose { @@ -128,10 +126,10 @@ func main() { game.Unload() // Close audio - raylib.CloseAudioDevice() + rl.CloseAudioDevice() // Close window - raylib.CloseWindow() + rl.CloseWindow() // Exit os.Exit(0) @@ -141,37 +139,37 @@ func main() { func (g *Game) Init() { // Gopher - g.Floppy = Floppy{raylib.NewVector2(80, float32(screenHeight)/2-spriteSize/2)} + g.Floppy = Floppy{rl.NewVector2(80, float32(screenHeight)/2-spriteSize/2)} // Sprite rectangle - g.FrameRec = raylib.NewRectangle(0, 0, spriteSize, spriteSize) + g.FrameRec = rl.NewRectangle(0, 0, spriteSize, spriteSize) // Cloud rectangle - g.CloudRec = raylib.NewRectangle(0, 0, float32(screenWidth), float32(g.TxClouds.Height)) + g.CloudRec = rl.NewRectangle(0, 0, float32(screenWidth), float32(g.TxClouds.Height)) // Initialize particles g.Particles = make([]Particle, maxParticles) for i := 0; i < maxParticles; i++ { - g.Particles[i].Position = raylib.NewVector2(0, 0) - g.Particles[i].Color = raylib.RayWhite + g.Particles[i].Position = rl.NewVector2(0, 0) + g.Particles[i].Color = rl.RayWhite g.Particles[i].Alpha = 1.0 - g.Particles[i].Size = float32(raylib.GetRandomValue(1, 30)) / 20.0 - g.Particles[i].Rotation = float32(raylib.GetRandomValue(0, 360)) + g.Particles[i].Size = float32(rl.GetRandomValue(1, 30)) / 20.0 + g.Particles[i].Rotation = float32(rl.GetRandomValue(0, 360)) g.Particles[i].Active = false } // Pipes positions - g.PipesPos = make([]raylib.Vector2, maxPipes) + g.PipesPos = make([]rl.Vector2, maxPipes) for i := 0; i < maxPipes; i++ { g.PipesPos[i].X = float32(480 + 360*i) - g.PipesPos[i].Y = -float32(raylib.GetRandomValue(0, 240)) + g.PipesPos[i].Y = -float32(rl.GetRandomValue(0, 240)) } // Pipes colors - colors := []raylib.Color{ - raylib.Orange, raylib.Red, raylib.Gold, raylib.Lime, - raylib.Violet, raylib.Brown, raylib.LightGray, raylib.Blue, - raylib.Yellow, raylib.Green, raylib.Purple, raylib.Beige, + colors := []rl.Color{ + rl.Orange, rl.Red, rl.Gold, rl.Lime, + rl.Violet, rl.Brown, rl.LightGray, rl.Blue, + rl.Yellow, rl.Green, rl.Purple, rl.Beige, } // Pipes @@ -181,7 +179,7 @@ func (g *Game) Init() { g.Pipes[i].Rec.Y = g.PipesPos[i/2].Y g.Pipes[i].Rec.Width = pipesWidth g.Pipes[i].Rec.Height = 550 - g.Pipes[i].Color = colors[raylib.GetRandomValue(0, int32(len(colors)-1))] + g.Pipes[i].Color = colors[rl.GetRandomValue(0, int32(len(colors)-1))] g.Pipes[i+1].Rec.X = g.PipesPos[i/2].X g.Pipes[i+1].Rec.Y = 1200 + g.PipesPos[i/2].Y - 550 @@ -203,35 +201,35 @@ func (g *Game) Init() { // Load - Load resources func (g *Game) Load() { - g.FxFlap = raylib.LoadSound("sounds/flap.wav") - g.FxSlap = raylib.LoadSound("sounds/slap.wav") - g.FxPoint = raylib.LoadSound("sounds/point.wav") - g.FxClick = raylib.LoadSound("sounds/click.wav") - g.TxSprites = raylib.LoadTexture("images/sprite.png") - g.TxSmoke = raylib.LoadTexture("images/smoke.png") - g.TxClouds = raylib.LoadTexture("images/clouds.png") + g.FxFlap = rl.LoadSound("sounds/flap.wav") + g.FxSlap = rl.LoadSound("sounds/slap.wav") + g.FxPoint = rl.LoadSound("sounds/point.wav") + g.FxClick = rl.LoadSound("sounds/click.wav") + g.TxSprites = rl.LoadTexture("images/sprite.png") + g.TxSmoke = rl.LoadTexture("images/smoke.png") + g.TxClouds = rl.LoadTexture("images/clouds.png") } // Unload - Unload resources func (g *Game) Unload() { - raylib.UnloadSound(g.FxFlap) - raylib.UnloadSound(g.FxSlap) - raylib.UnloadSound(g.FxPoint) - raylib.UnloadSound(g.FxClick) - raylib.UnloadTexture(g.TxSprites) - raylib.UnloadTexture(g.TxSmoke) - raylib.UnloadTexture(g.TxClouds) + rl.UnloadSound(g.FxFlap) + rl.UnloadSound(g.FxSlap) + rl.UnloadSound(g.FxPoint) + rl.UnloadSound(g.FxClick) + rl.UnloadTexture(g.TxSprites) + rl.UnloadTexture(g.TxSmoke) + rl.UnloadTexture(g.TxClouds) } // Update - Update game func (g *Game) Update() { - if raylib.WindowShouldClose() { + if rl.WindowShouldClose() { g.WindowShouldClose = true } if !g.GameOver { - if raylib.IsKeyPressed(raylib.KeyP) || raylib.IsKeyPressed(raylib.KeyBack) { - raylib.PlaySound(g.FxClick) + if rl.IsKeyPressed(rl.KeyP) || rl.IsKeyPressed(rl.KeyBack) { + rl.PlaySound(g.FxClick) if runtime.GOOS == "android" && g.Pause { g.WindowShouldClose = true @@ -259,8 +257,8 @@ func (g *Game) Update() { } // Movement/Controls - if raylib.IsKeyDown(raylib.KeySpace) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - raylib.PlaySound(g.FxFlap) + if rl.IsKeyDown(rl.KeySpace) || rl.IsMouseButtonDown(rl.MouseLeftButton) { + rl.PlaySound(g.FxFlap) // Activate one particle every frame for i := 0; i < maxParticles; i++ { @@ -315,11 +313,11 @@ func (g *Game) Update() { // Check Collisions for i := 0; i < maxPipes*2; i++ { - if raylib.CheckCollisionRecs(raylib.NewRectangle(g.Floppy.Position.X, g.Floppy.Position.Y, spriteSize, spriteSize), g.Pipes[i].Rec) { + if rl.CheckCollisionRecs(rl.NewRectangle(g.Floppy.Position.X, g.Floppy.Position.Y, spriteSize, spriteSize), g.Pipes[i].Rec) { // OMG You killed Gopher you bastard! g.Dead = true - raylib.PlaySound(g.FxSlap) + rl.PlaySound(g.FxSlap) } else if (g.PipesPos[i/2].X < g.Floppy.Position.X-spriteSize) && g.Pipes[i/2].Active && !g.GameOver { // Score point g.Score += 1 @@ -333,7 +331,7 @@ func (g *Game) Update() { g.HiScore = g.Score } - raylib.PlaySound(g.FxPoint) + rl.PlaySound(g.FxPoint) } } } else { @@ -351,17 +349,17 @@ func (g *Game) Update() { } } } else { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { g.Pause = !g.Pause } } } else { - if raylib.IsKeyPressed(raylib.KeyEnter) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - raylib.PlaySound(g.FxClick) + if rl.IsKeyPressed(rl.KeyEnter) || rl.IsMouseButtonDown(rl.MouseLeftButton) { + rl.PlaySound(g.FxClick) // Return of the Gopher! g.Init() - } else if runtime.GOOS == "android" && raylib.IsKeyDown(raylib.KeyBack) { + } else if runtime.GOOS == "android" && rl.IsKeyDown(rl.KeyBack) { g.WindowShouldClose = true } @@ -379,32 +377,32 @@ func (g *Game) Update() { // Draw - Draw game func (g *Game) Draw() { - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.SkyBlue) + rl.ClearBackground(rl.SkyBlue) if !g.GameOver { // Draw clouds - raylib.DrawTextureRec(g.TxClouds, g.CloudRec, raylib.NewVector2(0, float32(screenHeight-g.TxClouds.Height)), raylib.RayWhite) + rl.DrawTextureRec(g.TxClouds, g.CloudRec, rl.NewVector2(0, float32(screenHeight-g.TxClouds.Height)), rl.RayWhite) // Draw rotated clouds - raylib.DrawTexturePro(g.TxClouds, raylib.NewRectangle(-g.CloudRec.X, 0, float32(g.TxClouds.Width), float32(g.TxClouds.Height)), - raylib.NewRectangle(0, 0, float32(g.TxClouds.Width), float32(g.TxClouds.Height)), raylib.NewVector2(float32(g.TxClouds.Width), float32(g.TxClouds.Height)), 180, raylib.White) + rl.DrawTexturePro(g.TxClouds, rl.NewRectangle(-g.CloudRec.X, 0, float32(g.TxClouds.Width), float32(g.TxClouds.Height)), + rl.NewRectangle(0, 0, float32(g.TxClouds.Width), float32(g.TxClouds.Height)), rl.NewVector2(float32(g.TxClouds.Width), float32(g.TxClouds.Height)), 180, rl.White) // Draw Gopher - raylib.DrawTextureRec(g.TxSprites, g.FrameRec, g.Floppy.Position, raylib.RayWhite) + rl.DrawTextureRec(g.TxSprites, g.FrameRec, g.Floppy.Position, rl.RayWhite) // Draw active particles if !g.Dead { for i := 0; i < maxParticles; i++ { if g.Particles[i].Active { - raylib.DrawTexturePro( + rl.DrawTexturePro( g.TxSmoke, - raylib.NewRectangle(0, 0, float32(g.TxSmoke.Width), float32(g.TxSmoke.Height)), - raylib.NewRectangle(g.Particles[i].Position.X, g.Particles[i].Position.Y, float32(g.TxSmoke.Width)*g.Particles[i].Size, float32(g.TxSmoke.Height)*g.Particles[i].Size), - raylib.NewVector2(float32(g.TxSmoke.Width)*g.Particles[i].Size/2, float32(g.TxSmoke.Height)*g.Particles[i].Size/2), + rl.NewRectangle(0, 0, float32(g.TxSmoke.Width), float32(g.TxSmoke.Height)), + rl.NewRectangle(g.Particles[i].Position.X, g.Particles[i].Position.Y, float32(g.TxSmoke.Width)*g.Particles[i].Size, float32(g.TxSmoke.Height)*g.Particles[i].Size), + rl.NewVector2(float32(g.TxSmoke.Width)*g.Particles[i].Size/2, float32(g.TxSmoke.Height)*g.Particles[i].Size/2), g.Particles[i].Rotation, - raylib.Fade(g.Particles[i].Color, g.Particles[i].Alpha), + rl.Fade(g.Particles[i].Color, g.Particles[i].Alpha), ) } } @@ -412,41 +410,41 @@ func (g *Game) Draw() { // Draw pipes for i := 0; i < maxPipes; i++ { - raylib.DrawRectangle(int32(g.Pipes[i*2].Rec.X), int32(g.Pipes[i*2].Rec.Y), int32(g.Pipes[i*2].Rec.Width), int32(g.Pipes[i*2].Rec.Height), g.Pipes[i*2].Color) - raylib.DrawRectangle(int32(g.Pipes[i*2+1].Rec.X), int32(g.Pipes[i*2+1].Rec.Y), int32(g.Pipes[i*2+1].Rec.Width), int32(g.Pipes[i*2+1].Rec.Height), g.Pipes[i*2].Color) + rl.DrawRectangle(int32(g.Pipes[i*2].Rec.X), int32(g.Pipes[i*2].Rec.Y), int32(g.Pipes[i*2].Rec.Width), int32(g.Pipes[i*2].Rec.Height), g.Pipes[i*2].Color) + rl.DrawRectangle(int32(g.Pipes[i*2+1].Rec.X), int32(g.Pipes[i*2+1].Rec.Y), int32(g.Pipes[i*2+1].Rec.Width), int32(g.Pipes[i*2+1].Rec.Height), g.Pipes[i*2].Color) // Draw borders - raylib.DrawRectangleLines(int32(g.Pipes[i*2].Rec.X), int32(g.Pipes[i*2].Rec.Y), int32(g.Pipes[i*2].Rec.Width), int32(g.Pipes[i*2].Rec.Height), raylib.Black) - raylib.DrawRectangleLines(int32(g.Pipes[i*2+1].Rec.X), int32(g.Pipes[i*2+1].Rec.Y), int32(g.Pipes[i*2+1].Rec.Width), int32(g.Pipes[i*2+1].Rec.Height), raylib.Black) + rl.DrawRectangleLines(int32(g.Pipes[i*2].Rec.X), int32(g.Pipes[i*2].Rec.Y), int32(g.Pipes[i*2].Rec.Width), int32(g.Pipes[i*2].Rec.Height), rl.Black) + rl.DrawRectangleLines(int32(g.Pipes[i*2+1].Rec.X), int32(g.Pipes[i*2+1].Rec.Y), int32(g.Pipes[i*2+1].Rec.Width), int32(g.Pipes[i*2+1].Rec.Height), rl.Black) } // Draw Super Flashing FX (one frame only) if g.SuperFX { - raylib.DrawRectangle(0, 0, screenWidth, screenHeight, raylib.White) + rl.DrawRectangle(0, 0, screenWidth, screenHeight, rl.White) g.SuperFX = false } // Draw HI-SCORE - raylib.DrawText(fmt.Sprintf("%02d", g.Score), 20, 20, 32, raylib.Black) - raylib.DrawText(fmt.Sprintf("HI-SCORE: %02d", g.HiScore), 20, 64, 20, raylib.Black) + rl.DrawText(fmt.Sprintf("%02d", g.Score), 20, 20, 32, rl.Black) + rl.DrawText(fmt.Sprintf("HI-SCORE: %02d", g.HiScore), 20, 64, 20, rl.Black) if g.Pause { // Draw PAUSED text - raylib.DrawText("PAUSED", screenWidth/2-raylib.MeasureText("PAUSED", 24)/2, screenHeight/2-50, 20, raylib.Black) + rl.DrawText("PAUSED", screenWidth/2-rl.MeasureText("PAUSED", 24)/2, screenHeight/2-50, 20, rl.Black) } } else { // Draw text - raylib.DrawText("Floppy Gopher", raylib.GetScreenWidth()/2-raylib.MeasureText("Floppy Gopher", 40)/2, raylib.GetScreenHeight()/2-150, 40, raylib.RayWhite) + rl.DrawText("Floppy Gopher", int32(rl.GetScreenWidth())/2-rl.MeasureText("Floppy Gopher", 40)/2, int32(rl.GetScreenHeight())/2-150, 40, rl.RayWhite) if runtime.GOOS == "android" { - raylib.DrawText("[TAP] TO PLAY", raylib.GetScreenWidth()/2-raylib.MeasureText("[TAP] TO PLAY", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Black) + rl.DrawText("[TAP] TO PLAY", int32(rl.GetScreenWidth())/2-rl.MeasureText("[TAP] TO PLAY", 20)/2, int32(rl.GetScreenHeight())/2-50, 20, rl.Black) } else { - raylib.DrawText("[ENTER] TO PLAY", raylib.GetScreenWidth()/2-raylib.MeasureText("[ENTER] TO PLAY", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Black) + rl.DrawText("[ENTER] TO PLAY", int32(rl.GetScreenWidth())/2-rl.MeasureText("[ENTER] TO PLAY", 20)/2, int32(rl.GetScreenHeight())/2-50, 20, rl.Black) } // Draw Gopher - raylib.DrawTextureRec(g.TxSprites, g.FrameRec, raylib.NewVector2(float32(raylib.GetScreenWidth()/2-spriteSize/2), float32(raylib.GetScreenHeight()/2)), raylib.RayWhite) + rl.DrawTextureRec(g.TxSprites, g.FrameRec, rl.NewVector2(float32(rl.GetScreenWidth()/2-spriteSize/2), float32(rl.GetScreenHeight()/2)), rl.RayWhite) } - raylib.EndDrawing() + rl.EndDrawing() } diff --git a/examples/games/life/main.go b/examples/games/life/main.go index 1b385fe..e4ed546 100644 --- a/examples/games/life/main.go +++ b/examples/games/life/main.go @@ -4,7 +4,7 @@ import ( "math/rand" "time" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( @@ -13,8 +13,8 @@ const ( // Cell type type Cell struct { - Position raylib.Vector2 - Size raylib.Vector2 + Position rl.Vector2 + Size rl.Vector2 Alive bool Next bool Visited bool @@ -32,15 +32,15 @@ type Game struct { } func main() { - rand.Seed(time.Now().UnixNano()) + rand.New(rand.NewSource(time.Now().UnixNano())) game := Game{} game.Init(false) - raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, "Conway's Game of Life") - raylib.SetTargetFPS(20) + rl.InitWindow(game.ScreenWidth, game.ScreenHeight, "Conway's Game of Life") + rl.SetTargetFPS(20) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { if game.Playing { game.Update() } @@ -50,7 +50,7 @@ func main() { game.Draw() } - raylib.CloseWindow() + rl.CloseWindow() } // Init - Initialize game @@ -70,8 +70,8 @@ func (g *Game) Init(clear bool) { for x := int32(0); x <= g.Cols; x++ { for y := int32(0); y <= g.Rows; y++ { g.Cells[x][y] = &Cell{} - g.Cells[x][y].Position = raylib.NewVector2((float32(x) * squareSize), (float32(y)*squareSize)+1) - g.Cells[x][y].Size = raylib.NewVector2(squareSize-1, squareSize-1) + g.Cells[x][y].Position = rl.NewVector2((float32(x) * squareSize), (float32(y)*squareSize)+1) + g.Cells[x][y].Size = rl.NewVector2(squareSize-1, squareSize-1) if rand.Float64() < 0.1 && clear == false { g.Cells[x][y].Alive = true } @@ -82,19 +82,19 @@ func (g *Game) Init(clear bool) { // Input - Game input func (g *Game) Input() { // control - if raylib.IsKeyPressed(raylib.KeyR) { + if rl.IsKeyPressed(rl.KeyR) { g.Init(false) } - if raylib.IsKeyPressed(raylib.KeyC) { + if rl.IsKeyPressed(rl.KeyC) { g.Init(true) } - if raylib.IsKeyDown(raylib.KeyRight) && !g.Playing { + if rl.IsKeyDown(rl.KeyRight) && !g.Playing { g.Update() } - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - g.Click(raylib.GetMouseX(), raylib.GetMouseY()) + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + g.Click(rl.GetMouseX(), rl.GetMouseY()) } - if raylib.IsKeyPressed(raylib.KeySpace) { + if rl.IsKeyPressed(rl.KeySpace) { g.Playing = !g.Playing } @@ -165,36 +165,36 @@ func (g *Game) CountNeighbors(x, y int32) int { // Draw - Draw game func (g *Game) Draw() { - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) // Draw cells for x := int32(0); x <= g.Cols; x++ { for y := int32(0); y <= g.Rows; y++ { if g.Cells[x][y].Alive { - raylib.DrawRectangleV(g.Cells[x][y].Position, g.Cells[x][y].Size, raylib.Blue) + rl.DrawRectangleV(g.Cells[x][y].Position, g.Cells[x][y].Size, rl.Blue) } else if g.Cells[x][y].Visited { - raylib.DrawRectangleV(g.Cells[x][y].Position, g.Cells[x][y].Size, raylib.Color{R: 128, G: 177, B: 136, A: 255}) + rl.DrawRectangleV(g.Cells[x][y].Position, g.Cells[x][y].Size, rl.Color{R: 128, G: 177, B: 136, A: 255}) } } } // Draw grid lines for i := int32(0); i < g.Cols+1; i++ { - raylib.DrawLineV( - raylib.NewVector2(float32(squareSize*i), 0), - raylib.NewVector2(float32(squareSize*i), float32(g.ScreenHeight)), - raylib.LightGray, + rl.DrawLineV( + rl.NewVector2(float32(squareSize*i), 0), + rl.NewVector2(float32(squareSize*i), float32(g.ScreenHeight)), + rl.LightGray, ) } for i := int32(0); i < g.Rows+1; i++ { - raylib.DrawLineV( - raylib.NewVector2(0, float32(squareSize*i)), - raylib.NewVector2(float32(g.ScreenWidth), float32(squareSize*i)), - raylib.LightGray, + rl.DrawLineV( + rl.NewVector2(0, float32(squareSize*i)), + rl.NewVector2(float32(g.ScreenWidth), float32(squareSize*i)), + rl.LightGray, ) } - raylib.EndDrawing() + rl.EndDrawing() } diff --git a/examples/games/pong/main.go b/examples/games/pong/main.go new file mode 100644 index 0000000..0f1dd4f --- /dev/null +++ b/examples/games/pong/main.go @@ -0,0 +1,174 @@ +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 6de6511..86eaaae 100644 --- a/examples/games/snake/main.go +++ b/examples/games/snake/main.go @@ -1,9 +1,5 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - const ( snakeLength = 256 squareSize = 31 @@ -11,18 +7,18 @@ const ( // Snake type type Snake struct { - Position raylib.Vector2 - Size raylib.Vector2 - Speed raylib.Vector2 - Color raylib.Color + Position rl.Vector2 + Size rl.Vector2 + Speed rl.Vector2 + Color rl.Color } // Food type type Food struct { - Position raylib.Vector2 - Size raylib.Vector2 + Position rl.Vector2 + Size rl.Vector2 Active bool - Color raylib.Color + Color rl.Color } // Game type @@ -36,9 +32,9 @@ type Game struct { Fruit Food Snake []Snake - SnakePosition []raylib.Vector2 + SnakePosition []rl.Vector2 AllowMove bool - Offset raylib.Vector2 + Offset rl.Vector2 CounterTail int } @@ -46,17 +42,17 @@ func main() { game := Game{} game.Init() - raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, "sample game: snake") + rl.InitWindow(game.ScreenWidth, game.ScreenHeight, "sample game: snake") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { game.Update() game.Draw() } - raylib.CloseWindow() + rl.CloseWindow() } // Init - Initialize game @@ -71,58 +67,58 @@ func (g *Game) Init() { g.CounterTail = 1 g.AllowMove = false - g.Offset = raylib.Vector2{} + g.Offset = rl.Vector2{} g.Offset.X = float32(g.ScreenWidth % squareSize) g.Offset.Y = float32(g.ScreenHeight % squareSize) g.Snake = make([]Snake, snakeLength) for i := 0; i < snakeLength; i++ { - g.Snake[i].Position = raylib.NewVector2(g.Offset.X/2, g.Offset.Y/2) - g.Snake[i].Size = raylib.NewVector2(squareSize, squareSize) - g.Snake[i].Speed = raylib.NewVector2(squareSize, 0) + g.Snake[i].Position = rl.NewVector2(g.Offset.X/2, g.Offset.Y/2) + g.Snake[i].Size = rl.NewVector2(squareSize, squareSize) + g.Snake[i].Speed = rl.NewVector2(squareSize, 0) if i == 0 { - g.Snake[i].Color = raylib.DarkBlue + g.Snake[i].Color = rl.DarkBlue } else { - g.Snake[i].Color = raylib.Blue + g.Snake[i].Color = rl.Blue } } - g.SnakePosition = make([]raylib.Vector2, snakeLength) + g.SnakePosition = make([]rl.Vector2, snakeLength) for i := 0; i < snakeLength; i++ { - g.SnakePosition[i] = raylib.NewVector2(0.0, 0.0) + g.SnakePosition[i] = rl.NewVector2(0.0, 0.0) } - g.Fruit.Size = raylib.NewVector2(squareSize, squareSize) - g.Fruit.Color = raylib.SkyBlue + g.Fruit.Size = rl.NewVector2(squareSize, squareSize) + g.Fruit.Color = rl.SkyBlue g.Fruit.Active = false } // Update - Update game func (g *Game) Update() { if !g.GameOver { - if raylib.IsKeyPressed('P') { + if rl.IsKeyPressed(rl.KeyP) { g.Pause = !g.Pause } if !g.Pause { // control - if raylib.IsKeyPressed(raylib.KeyRight) && g.Snake[0].Speed.X == 0 && g.AllowMove { - g.Snake[0].Speed = raylib.NewVector2(squareSize, 0) + if rl.IsKeyPressed(rl.KeyRight) && g.Snake[0].Speed.X == 0 && g.AllowMove { + g.Snake[0].Speed = rl.NewVector2(squareSize, 0) g.AllowMove = false } - if raylib.IsKeyPressed(raylib.KeyLeft) && g.Snake[0].Speed.X == 0 && g.AllowMove { - g.Snake[0].Speed = raylib.NewVector2(-squareSize, 0) + if rl.IsKeyPressed(rl.KeyLeft) && g.Snake[0].Speed.X == 0 && g.AllowMove { + g.Snake[0].Speed = rl.NewVector2(-squareSize, 0) g.AllowMove = false } - if raylib.IsKeyPressed(raylib.KeyUp) && g.Snake[0].Speed.Y == 0 && g.AllowMove { - g.Snake[0].Speed = raylib.NewVector2(0, -squareSize) + if rl.IsKeyPressed(rl.KeyUp) && g.Snake[0].Speed.Y == 0 && g.AllowMove { + g.Snake[0].Speed = rl.NewVector2(0, -squareSize) g.AllowMove = false } - if raylib.IsKeyPressed(raylib.KeyDown) && g.Snake[0].Speed.Y == 0 && g.AllowMove { - g.Snake[0].Speed = raylib.NewVector2(0, squareSize) + if rl.IsKeyPressed(rl.KeyDown) && g.Snake[0].Speed.Y == 0 && g.AllowMove { + g.Snake[0].Speed = rl.NewVector2(0, squareSize) g.AllowMove = false } @@ -159,16 +155,16 @@ func (g *Game) Update() { if !g.Fruit.Active { g.Fruit.Active = true - g.Fruit.Position = raylib.NewVector2( - float32(raylib.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize+int32(g.Offset.X)/2), - float32(raylib.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize+int32(g.Offset.Y)/2), + 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, ) 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 = raylib.NewVector2( - float32(raylib.GetRandomValue(0, (g.ScreenWidth/squareSize)-1)*squareSize), - float32(raylib.GetRandomValue(0, (g.ScreenHeight/squareSize)-1)*squareSize), + 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, ) i = 0 } @@ -176,9 +172,9 @@ func (g *Game) Update() { } // collision - if raylib.CheckCollisionRecs( - raylib.NewRectangle(g.Snake[0].Position.X, g.Snake[0].Position.Y, g.Snake[0].Size.X, g.Snake[0].Size.Y), - raylib.NewRectangle(g.Fruit.Position.X, g.Fruit.Position.Y, g.Fruit.Size.X, g.Fruit.Size.Y), + if rl.CheckCollisionRecs( + rl.NewRectangle(g.Snake[0].Position.X, g.Snake[0].Position.Y, g.Snake[0].Size.X, g.Snake[0].Size.Y), + rl.NewRectangle(g.Fruit.Position.X, g.Fruit.Position.Y, g.Fruit.Size.X, g.Fruit.Size.Y), ) { g.Snake[g.CounterTail].Position = g.SnakePosition[g.CounterTail-1] g.CounterTail += 1 @@ -188,7 +184,7 @@ func (g *Game) Update() { g.FramesCounter++ } } else { - if raylib.IsKeyPressed(raylib.KeyEnter) { + if rl.IsKeyPressed(rl.KeyEnter) { g.Init() g.GameOver = false } @@ -197,42 +193,42 @@ func (g *Game) Update() { // Draw - Draw game func (g *Game) Draw() { - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) if !g.GameOver { // Draw grid lines for i := int32(0); i < g.ScreenWidth/squareSize+1; i++ { - raylib.DrawLineV( - raylib.NewVector2(float32(squareSize*i)+g.Offset.X/2, g.Offset.Y/2), - raylib.NewVector2(float32(squareSize*i)+g.Offset.X/2, float32(g.ScreenHeight)-g.Offset.Y/2), - raylib.LightGray, + rl.DrawLineV( + rl.NewVector2(float32(squareSize*i)+g.Offset.X/2, g.Offset.Y/2), + rl.NewVector2(float32(squareSize*i)+g.Offset.X/2, float32(g.ScreenHeight)-g.Offset.Y/2), + rl.LightGray, ) } for i := int32(0); i < g.ScreenHeight/squareSize+1; i++ { - raylib.DrawLineV( - raylib.NewVector2(g.Offset.X/2, float32(squareSize*i)+g.Offset.Y/2), - raylib.NewVector2(float32(g.ScreenWidth)-g.Offset.X/2, float32(squareSize*i)+g.Offset.Y/2), - raylib.LightGray, + rl.DrawLineV( + rl.NewVector2(g.Offset.X/2, float32(squareSize*i)+g.Offset.Y/2), + rl.NewVector2(float32(g.ScreenWidth)-g.Offset.X/2, float32(squareSize*i)+g.Offset.Y/2), + rl.LightGray, ) } // Draw snake for i := 0; i < g.CounterTail; i++ { - raylib.DrawRectangleV(g.Snake[i].Position, g.Snake[i].Size, g.Snake[i].Color) + rl.DrawRectangleV(g.Snake[i].Position, g.Snake[i].Size, g.Snake[i].Color) } // Draw fruit to pick - raylib.DrawRectangleV(g.Fruit.Position, g.Fruit.Size, g.Fruit.Color) + rl.DrawRectangleV(g.Fruit.Position, g.Fruit.Size, g.Fruit.Color) if g.Pause { - raylib.DrawText("GAME PAUSED", g.ScreenWidth/2-raylib.MeasureText("GAME PAUSED", 40)/2, g.ScreenHeight/2-40, 40, raylib.Gray) + rl.DrawText("GAME PAUSED", g.ScreenWidth/2-rl.MeasureText("GAME PAUSED", 40)/2, g.ScreenHeight/2-40, 40, rl.Gray) } } else { - raylib.DrawText("PRESS [ENTER] TO PLAY AGAIN", raylib.GetScreenWidth()/2-raylib.MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Gray) + rl.DrawText("PRESS [ENTER] TO PLAY AGAIN", int32(rl.GetScreenWidth())/2-rl.MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, int32(rl.GetScreenHeight())/2-50, 20, rl.Gray) } - raylib.EndDrawing() + rl.EndDrawing() } diff --git a/examples/go.mod b/examples/go.mod new file mode 100644 index 0000000..70eaebf --- /dev/null +++ b/examples/go.mod @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..928bf43 --- /dev/null +++ b/examples/go.sum @@ -0,0 +1,10 @@ +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 deleted file mode 100644 index 7d392a5..0000000 --- a/examples/gui/basic_controls/main.go +++ /dev/null @@ -1,92 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/gen2brain/raylib-go/raygui" - "github.com/gen2brain/raylib-go/raylib" -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - raylib.SetConfigFlags(raylib.FlagVsyncHint) - - raylib.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 - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - if buttonClicked { - progressValue += 0.1 - if progressValue >= 1.1 { - progressValue = 0.0 - } - } - - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.Beige) - - raygui.Label(raylib.NewRectangle(50, 50, 80, 20), "Label") - - buttonClicked = raygui.Button(raylib.NewRectangle(50, 70, 80, 40), "Button") - - raygui.Label(raylib.NewRectangle(70, 140, 20, 20), "Checkbox") - checkboxChecked = raygui.CheckBox(raylib.NewRectangle(50, 140, 20, 20), checkboxChecked) - - raygui.Label(raylib.NewRectangle(50, 190, 200, 20), "ProgressBar") - raygui.ProgressBar(raylib.NewRectangle(50, 210, 200, 20), progressValue) - raygui.Label(raylib.NewRectangle(200+50+5, 210, 20, 20), fmt.Sprintf("%.1f", progressValue)) - - raygui.Label(raylib.NewRectangle(50, 260, 200, 20), "Slider") - sliderValue = raygui.Slider(raylib.NewRectangle(50, 280, 200, 20), sliderValue, 0, 100) - raygui.Label(raylib.NewRectangle(200+50+5, 280, 20, 20), fmt.Sprintf("%.0f", sliderValue)) - - buttonToggle = raygui.ToggleButton(raylib.NewRectangle(50, 350, 100, 40), "ToggleButton", buttonToggle) - - raygui.Label(raylib.NewRectangle(500, 50, 200, 20), "ToggleGroup") - toggleActive = raygui.ToggleGroup(raylib.NewRectangle(500, 70, 60, 30), toggleText, toggleActive) - - raygui.Label(raylib.NewRectangle(500, 120, 200, 20), "SliderBar") - sliderBarValue = raygui.SliderBar(raylib.NewRectangle(500, 140, 200, 20), sliderBarValue, 0, 100) - raygui.Label(raylib.NewRectangle(500+200+5, 140, 20, 20), fmt.Sprintf("%.0f", sliderBarValue)) - - raygui.Label(raylib.NewRectangle(500, 190, 200, 20), "Spinner") - spinnerValue = raygui.Spinner(raylib.NewRectangle(500, 210, 200, 20), spinnerValue, 0, 100) - - raygui.Label(raylib.NewRectangle(500, 260, 200, 20), "ComboBox") - comboActive = raygui.ComboBox(raylib.NewRectangle(500, 280, 200, 20), comboText, comboActive) - - if comboLastActive != comboActive { - raygui.LoadGuiStyle(fmt.Sprintf("styles/%s.style", comboText[comboActive])) - comboLastActive = comboActive - } - - raygui.Label(raylib.NewRectangle(500, 330, 200, 20), "TextBox") - inputText = raygui.TextBox(raylib.NewRectangle(500, 350, 200, 20), inputText) - - raylib.EndDrawing() - } - - raylib.CloseWindow() -} diff --git a/examples/gui/basic_controls/styles/default_dark.style b/examples/gui/basic_controls/styles/default_dark.style deleted file mode 100644 index 4b903c8..0000000 --- a/examples/gui/basic_controls/styles/default_dark.style +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 3a4786c..0000000 --- a/examples/gui/basic_controls/styles/default_light.style +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index bba8e32..0000000 --- a/examples/gui/basic_controls/styles/hello_kitty.style +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 0248d6e..0000000 --- a/examples/gui/basic_controls/styles/monokai.style +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 79d4053..0000000 --- a/examples/gui/basic_controls/styles/obsidian.style +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 24605c1..0000000 --- a/examples/gui/basic_controls/styles/solarized.style +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 8d413c9..0000000 --- a/examples/gui/basic_controls/styles/solarized_light.style +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 54ca5f6..0000000 --- a/examples/gui/basic_controls/styles/zahnrad.style +++ /dev/null @@ -1,98 +0,0 @@ -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 new file mode 100644 index 0000000..ef2d6fa --- /dev/null +++ b/examples/gui/button/main.go @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..a635890 --- /dev/null +++ b/examples/gui/controls_test_suite/controls_test_suite.go @@ -0,0 +1,281 @@ +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 new file mode 100644 index 0000000..8db0e25 Binary files /dev/null and b/examples/gui/controls_test_suite/controls_test_suite.png differ diff --git a/examples/gui/icons/README.md b/examples/gui/icons/README.md new file mode 100644 index 0000000..8c114f4 --- /dev/null +++ b/examples/gui/icons/README.md @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000..8271617 Binary files /dev/null and b/examples/gui/icons/default_icons_with_255.rgi differ diff --git a/examples/gui/icons/main.go b/examples/gui/icons/main.go new file mode 100644 index 0000000..a86e84f --- /dev/null +++ b/examples/gui/icons/main.go @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..3e05961 Binary files /dev/null and b/examples/gui/icons/screenshot.png differ diff --git a/examples/gui/portable_window/portable_window.go b/examples/gui/portable_window/portable_window.go new file mode 100644 index 0000000..9f8463c --- /dev/null +++ b/examples/gui/portable_window/portable_window.go @@ -0,0 +1,99 @@ +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 new file mode 100644 index 0000000..eed0a62 --- /dev/null +++ b/examples/gui/scroll_panel/scroll_panel.go @@ -0,0 +1,193 @@ +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 new file mode 100644 index 0000000..fe2e095 Binary files /dev/null and b/examples/gui/scroll_panel/scroll_panel.png differ diff --git a/examples/models/animation/guy.iqm b/examples/models/animation/guy.iqm new file mode 100644 index 0000000..36bed5e Binary files /dev/null and b/examples/models/animation/guy.iqm differ diff --git a/examples/models/animation/guyanim.iqm b/examples/models/animation/guyanim.iqm new file mode 100644 index 0000000..824a68a Binary files /dev/null and b/examples/models/animation/guyanim.iqm differ diff --git a/examples/models/animation/guytex.png b/examples/models/animation/guytex.png new file mode 100644 index 0000000..05a58ee Binary files /dev/null and b/examples/models/animation/guytex.png differ diff --git a/examples/models/animation/main.go b/examples/models/animation/main.go new file mode 100644 index 0000000..c5e06b7 --- /dev/null +++ b/examples/models/animation/main.go @@ -0,0 +1,95 @@ +/******************************************************************************************* +* +* 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/billboard.png b/examples/models/billboard/billboard.png index e2fe398..8c99118 100644 Binary files a/examples/models/billboard/billboard.png and b/examples/models/billboard/billboard.png differ diff --git a/examples/models/billboard/main.go b/examples/models/billboard/main.go index 6975b2a..7f0320f 100644 --- a/examples/models/billboard/main.go +++ b/examples/models/billboard/main.go @@ -1,48 +1,94 @@ -package main +/******************************************************************************************* +* +* 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 import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" +) + +const ( + screenWidth = 800 + screenHeight = 450 ) func main() { - screenWidth := int32(800) - screenHeight := int32(450) + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards") - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards") - - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(5.0, 4.0, 5.0) - camera.Target = raylib.NewVector3(0.0, 2.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(5.0, 4.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.Type = raylib.CameraPerspective + camera.Projection = rl.CameraPerspective - bill := raylib.LoadTexture("billboard.png") // Our texture billboard - billPosition := raylib.NewVector3(0.0, 2.0, 0.0) // Position where draw billboard + 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 - raylib.SetCameraMode(camera, raylib.CameraOrbital) // Set an orbital camera mode - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera - - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.BeginMode3D(camera) - - raylib.DrawBillboard(camera, bill, billPosition, 2.0, raylib.White) - - raylib.DrawGrid(10, 1.0) // Draw a grid - - raylib.EndMode3D() - - raylib.EndDrawing() + // 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), } - raylib.UnloadTexture(bill) // Unload texture + // NOTE: Billboard locked on axis-Y + billUp := rl.Vector3{Y: 1.0} - raylib.CloseWindow() + // 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.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + // Update + rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode + + 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.EndMode3D() + rl.DrawFPS(10, 10) + rl.EndDrawing() + } + + rl.UnloadTexture(bill) // Unload texture + + rl.CloseWindow() } diff --git a/examples/models/box_collisions/main.go b/examples/models/box_collisions/main.go index d2867e4..82c2c4c 100644 --- a/examples/models/box_collisions/main.go +++ b/examples/models/box_collisions/main.go @@ -1,69 +1,69 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions") + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(0.0, 10.0, 10.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + 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 = 45.0 - camera.Type = raylib.CameraPerspective + camera.Projection = rl.CameraPerspective - playerPosition := raylib.NewVector3(0.0, 1.0, 2.0) - playerSize := raylib.NewVector3(1.0, 2.0, 1.0) - playerColor := raylib.Green + playerPosition := rl.NewVector3(0.0, 1.0, 2.0) + playerSize := rl.NewVector3(1.0, 2.0, 1.0) + playerColor := rl.Green - enemyBoxPos := raylib.NewVector3(-4.0, 1.0, 0.0) - enemyBoxSize := raylib.NewVector3(2.0, 2.0, 2.0) + enemyBoxPos := rl.NewVector3(-4.0, 1.0, 0.0) + enemyBoxSize := rl.NewVector3(2.0, 2.0, 2.0) - enemySpherePos := raylib.NewVector3(4.0, 0.0, 0.0) + enemySpherePos := rl.NewVector3(4.0, 0.0, 0.0) enemySphereSize := float32(1.5) collision := false - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update // Move player - if raylib.IsKeyDown(raylib.KeyRight) { + if rl.IsKeyDown(rl.KeyRight) { playerPosition.X += 0.2 - } else if raylib.IsKeyDown(raylib.KeyLeft) { + } else if rl.IsKeyDown(rl.KeyLeft) { playerPosition.X -= 0.2 - } else if raylib.IsKeyDown(raylib.KeyDown) { + } else if rl.IsKeyDown(rl.KeyDown) { playerPosition.Z += 0.2 - } else if raylib.IsKeyDown(raylib.KeyUp) { + } else if rl.IsKeyDown(rl.KeyUp) { playerPosition.Z -= 0.2 } collision = false // Check collisions player vs enemy-box - if raylib.CheckCollisionBoxes( - raylib.NewBoundingBox( - raylib.NewVector3(playerPosition.X-playerSize.X/2, playerPosition.Y-playerSize.Y/2, playerPosition.Z-playerSize.Z/2), - raylib.NewVector3(playerPosition.X+playerSize.X/2, playerPosition.Y+playerSize.Y/2, playerPosition.Z+playerSize.Z/2)), - raylib.NewBoundingBox( - raylib.NewVector3(enemyBoxPos.X-enemyBoxSize.X/2, enemyBoxPos.Y-enemyBoxSize.Y/2, enemyBoxPos.Z-enemyBoxSize.Z/2), - raylib.NewVector3(enemyBoxPos.X+enemyBoxSize.X/2, enemyBoxPos.Y+enemyBoxSize.Y/2, enemyBoxPos.Z+enemyBoxSize.Z/2)), + if rl.CheckCollisionBoxes( + rl.NewBoundingBox( + rl.NewVector3(playerPosition.X-playerSize.X/2, playerPosition.Y-playerSize.Y/2, playerPosition.Z-playerSize.Z/2), + rl.NewVector3(playerPosition.X+playerSize.X/2, playerPosition.Y+playerSize.Y/2, playerPosition.Z+playerSize.Z/2)), + rl.NewBoundingBox( + rl.NewVector3(enemyBoxPos.X-enemyBoxSize.X/2, enemyBoxPos.Y-enemyBoxSize.Y/2, enemyBoxPos.Z-enemyBoxSize.Z/2), + rl.NewVector3(enemyBoxPos.X+enemyBoxSize.X/2, enemyBoxPos.Y+enemyBoxSize.Y/2, enemyBoxPos.Z+enemyBoxSize.Z/2)), ) { collision = true } // Check collisions player vs enemy-sphere - if raylib.CheckCollisionBoxSphere( - raylib.NewBoundingBox( - raylib.NewVector3(playerPosition.X-playerSize.X/2, playerPosition.Y-playerSize.Y/2, playerPosition.Z-playerSize.Z/2), - raylib.NewVector3(playerPosition.X+playerSize.X/2, playerPosition.Y+playerSize.Y/2, playerPosition.Z+playerSize.Z/2)), + if rl.CheckCollisionBoxSphere( + rl.NewBoundingBox( + rl.NewVector3(playerPosition.X-playerSize.X/2, playerPosition.Y-playerSize.Y/2, playerPosition.Z-playerSize.Z/2), + rl.NewVector3(playerPosition.X+playerSize.X/2, playerPosition.Y+playerSize.Y/2, playerPosition.Z+playerSize.Z/2)), enemySpherePos, enemySphereSize, ) { @@ -71,40 +71,40 @@ func main() { } if collision { - playerColor = raylib.Red + playerColor = rl.Red } else { - playerColor = raylib.Green + playerColor = rl.Green } // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) // Draw enemy-box - raylib.DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, raylib.Gray) - raylib.DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, raylib.DarkGray) + rl.DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, rl.Gray) + rl.DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, rl.DarkGray) // Draw enemy-sphere - raylib.DrawSphere(enemySpherePos, enemySphereSize, raylib.Gray) - raylib.DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, raylib.DarkGray) + rl.DrawSphere(enemySpherePos, enemySphereSize, rl.Gray) + rl.DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, rl.DarkGray) // Draw player - raylib.DrawCubeV(playerPosition, playerSize, playerColor) + rl.DrawCubeV(playerPosition, playerSize, playerColor) - raylib.DrawGrid(10, 1.0) // Draw a grid + rl.DrawGrid(10, 1.0) // Draw a grid - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawText("Move player with cursors to collide", 220, 40, 20, raylib.Gray) + rl.DrawText("Move player with cursors to collide", 220, 40, 20, rl.Gray) - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/models/cubicmap/main.go b/examples/models/cubicmap/main.go index f105825..f5790fe 100644 --- a/examples/models/cubicmap/main.go +++ b/examples/models/cubicmap/main.go @@ -1,71 +1,68 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(16.0, 14.0, 16.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(16.0, 14.0, 16.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.Type = raylib.CameraPerspective - image := raylib.LoadImage("cubicmap.png") // Load cubicmap image (RAM) - cubicmap := raylib.LoadTextureFromImage(image) // Convert image to texture to display (VRAM) + image := rl.LoadImage("cubicmap.png") // Load cubicmap image (RAM) + cubicmap := rl.LoadTextureFromImage(image) // Convert image to texture to display (VRAM) - mesh := raylib.GenMeshCubicmap(*image, raylib.NewVector3(1.0, 1.0, 1.0)) - model := raylib.LoadModelFromMesh(mesh) + mesh := rl.GenMeshCubicmap(*image, 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 := raylib.LoadTexture("cubicmap_atlas.png") // Load map texture - model.Material.Maps[raylib.MapDiffuse].Texture = texture // Set map diffuse texture + texture := rl.LoadTexture("cubicmap_atlas.png") // Load map texture + rl.SetMaterialTexture(model.Materials, rl.MapDiffuse, texture) // Set map diffuse texture - mapPosition := raylib.NewVector3(-16.0, 0.0, -8.0) // Set model position + mapPosition := rl.NewVector3(-16.0, 0.0, -8.0) // Set model position - raylib.UnloadImage(image) // Unload cubicmap image from RAM, already uploaded to VRAM + rl.UnloadImage(image) // Unload cubicmap image from RAM, already uploaded to VRAM - raylib.SetCameraMode(camera, raylib.CameraOrbital) // Set an orbital camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update - raylib.UpdateCamera(&camera) // Update camera + rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawModel(model, mapPosition, 1.0, raylib.White) + rl.DrawModel(model, mapPosition, 1.0, rl.White) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawTextureEx(cubicmap, raylib.NewVector2(float32(screenWidth-cubicmap.Width*4-20), 20), 0.0, 4.0, raylib.White) - raylib.DrawRectangleLines(screenWidth-cubicmap.Width*4-20, 20, cubicmap.Width*4, cubicmap.Height*4, raylib.Green) + rl.DrawTextureEx(cubicmap, rl.NewVector2(float32(screenWidth-cubicmap.Width*4-20), 20), 0.0, 4.0, rl.White) + rl.DrawRectangleLines(screenWidth-cubicmap.Width*4-20, 20, cubicmap.Width*4, cubicmap.Height*4, rl.Green) - raylib.DrawText("cubicmap image used to", 658, 90, 10, raylib.Gray) - raylib.DrawText("generate map 3d model", 658, 104, 10, raylib.Gray) + rl.DrawText("cubicmap image used to", 658, 90, 10, rl.Gray) + rl.DrawText("generate map 3d model", 658, 104, 10, rl.Gray) - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(cubicmap) // Unload cubicmap texture - raylib.UnloadTexture(texture) // Unload map texture - raylib.UnloadModel(model) // Unload map model + rl.UnloadTexture(cubicmap) // Unload cubicmap texture + rl.UnloadTexture(texture) // Unload map texture + rl.UnloadModel(model) // Unload map model - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/models/draw_cube_texture/cubicmap_atlas.png b/examples/models/draw_cube_texture/cubicmap_atlas.png new file mode 100644 index 0000000..9fc404a Binary files /dev/null and b/examples/models/draw_cube_texture/cubicmap_atlas.png differ diff --git a/examples/models/draw_cube_texture/main.go b/examples/models/draw_cube_texture/main.go new file mode 100644 index 0000000..9ae0ef5 --- /dev/null +++ b/examples/models/draw_cube_texture/main.go @@ -0,0 +1,256 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..392dbf2 Binary files /dev/null and b/examples/models/first_person_maze/cubicmap.png differ diff --git a/examples/models/first_person_maze/cubicmap_atlas.png b/examples/models/first_person_maze/cubicmap_atlas.png new file mode 100644 index 0000000..9fc404a Binary files /dev/null and b/examples/models/first_person_maze/cubicmap_atlas.png differ diff --git a/examples/models/first_person_maze/main.go b/examples/models/first_person_maze/main.go new file mode 100644 index 0000000..310e31d --- /dev/null +++ b/examples/models/first_person_maze/main.go @@ -0,0 +1,117 @@ +/******************************************************************************************* +* +* 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 04e734d..bf78869 100644 --- a/examples/models/geometric_shapes/main.go +++ b/examples/models/geometric_shapes/main.go @@ -1,52 +1,48 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes") + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(0.0, 10.0, 10.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + 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 = 45.0 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawCube(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Red) - raylib.DrawCubeWires(raylib.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, raylib.Gold) - raylib.DrawCubeWires(raylib.NewVector3(-4.0, 0.0, -2.0), 3.0, 6.0, 2.0, raylib.Maroon) + rl.DrawCube(rl.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, rl.Red) + rl.DrawCubeWires(rl.NewVector3(-4.0, 0.0, 2.0), 2.0, 5.0, 2.0, rl.Gold) + rl.DrawCubeWires(rl.NewVector3(-4.0, 0.0, -2.0), 3.0, 6.0, 2.0, rl.Maroon) - raylib.DrawSphere(raylib.NewVector3(-1.0, 0.0, -2.0), 1.0, raylib.Green) - raylib.DrawSphereWires(raylib.NewVector3(1.0, 0.0, 2.0), 2.0, 16, 16, raylib.Lime) + rl.DrawSphere(rl.NewVector3(-1.0, 0.0, -2.0), 1.0, rl.Green) + rl.DrawSphereWires(rl.NewVector3(1.0, 0.0, 2.0), 2.0, 16, 16, rl.Lime) - raylib.DrawCylinder(raylib.NewVector3(4.0, 0.0, -2.0), 1.0, 2.0, 3.0, 4, raylib.SkyBlue) - raylib.DrawCylinderWires(raylib.NewVector3(4.0, 0.0, -2.0), 1.0, 2.0, 3.0, 4, raylib.DarkBlue) - raylib.DrawCylinderWires(raylib.NewVector3(4.5, -1.0, 2.0), 1.0, 1.0, 2.0, 6, raylib.Brown) + rl.DrawCylinder(rl.NewVector3(4.0, 0.0, -2.0), 1.0, 2.0, 3.0, 4, rl.SkyBlue) + rl.DrawCylinderWires(rl.NewVector3(4.0, 0.0, -2.0), 1.0, 2.0, 3.0, 4, rl.DarkBlue) + rl.DrawCylinderWires(rl.NewVector3(4.5, -1.0, 2.0), 1.0, 1.0, 2.0, 6, rl.Brown) - raylib.DrawCylinder(raylib.NewVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, raylib.Gold) - raylib.DrawCylinderWires(raylib.NewVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, raylib.Pink) + rl.DrawCylinder(rl.NewVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, rl.Gold) + rl.DrawCylinderWires(rl.NewVector3(1.0, 0.0, -4.0), 0.0, 1.5, 3.0, 8, rl.Pink) - raylib.DrawGrid(10, 1.0) // Draw a grid + rl.DrawGrid(10, 1.0) // Draw a grid - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/models/gltf_loading/main.go b/examples/models/gltf_loading/main.go new file mode 100644 index 0000000..79505ab --- /dev/null +++ b/examples/models/gltf_loading/main.go @@ -0,0 +1,74 @@ +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 new file mode 100644 index 0000000..549011e Binary files /dev/null and b/examples/models/gltf_loading/robot.glb differ diff --git a/examples/models/heightmap/main.go b/examples/models/heightmap/main.go index 9e59043..896ffd8 100644 --- a/examples/models/heightmap/main.go +++ b/examples/models/heightmap/main.go @@ -1,65 +1,66 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + //"fmt" + + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(18.0, 16.0, 18.0) - camera.Target = raylib.NewVector3(0.0, 0.0, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(18.0, 16.0, 18.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 - image := raylib.LoadImage("heightmap.png") // Load heightmap image (RAM) - texture := raylib.LoadTextureFromImage(image) // Convert image to texture (VRAM) + image := rl.LoadImage("heightmap.png") // Load heightmap image (RAM) + texture := rl.LoadTextureFromImage(image) // Convert image to texture (VRAM) - mesh := raylib.GenMeshHeightmap(*image, raylib.NewVector3(16, 8, 16)) // Generate heightmap mesh (RAM and VRAM) - model := raylib.LoadModelFromMesh(mesh) // Load model from generated mesh + mesh := rl.GenMeshHeightmap(*image, rl.NewVector3(16, 8, 16)) // Generate heightmap mesh (RAM and VRAM) + model := rl.LoadModelFromMesh(mesh) // Load model from generated mesh - model.Material.Maps[raylib.MapDiffuse].Texture = texture // Set map diffuse texture - mapPosition := raylib.NewVector3(-8.0, 0.0, -8.0) // Set model position + rl.SetMaterialTexture(model.Materials, rl.MapDiffuse, texture) // Set map diffuse texture - raylib.UnloadImage(image) // Unload heightmap image from RAM, already uploaded to VRAM + mapPosition := rl.NewVector3(-8.0, 0.0, -8.0) // Set model position - raylib.SetCameraMode(camera, raylib.CameraOrbital) // Set an orbital camera mode + rl.UnloadImage(image) // Unload heightmap image from RAM, already uploaded to VRAM - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update - raylib.UpdateCamera(&camera) // Update camera + rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginMode3D(camera) + rl.BeginMode3D(camera) - raylib.DrawModel(model, mapPosition, 1.0, raylib.Red) + rl.DrawModel(model, mapPosition, 1.0, rl.Red) - raylib.DrawGrid(20, 1.0) + rl.DrawGrid(20, 1.0) - raylib.EndMode3D() + rl.EndMode3D() - raylib.DrawTexture(texture, screenWidth-texture.Width-20, 20, raylib.White) - raylib.DrawRectangleLines(screenWidth-texture.Width-20, 20, texture.Width, texture.Height, raylib.Green) + rl.DrawTexture(texture, screenWidth-texture.Width-20, 20, rl.White) + rl.DrawRectangleLines(screenWidth-texture.Width-20, 20, texture.Width, texture.Height, rl.Green) - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) // Unload map texture - raylib.UnloadModel(model) // Unload map model + rl.UnloadTexture(texture) // Unload map texture + rl.UnloadModel(model) // Unload map model - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/models/m3d_loading/cesium_man.m3d b/examples/models/m3d_loading/cesium_man.m3d new file mode 100644 index 0000000..ddf9f50 Binary files /dev/null and b/examples/models/m3d_loading/cesium_man.m3d differ diff --git a/examples/models/m3d_loading/main.go b/examples/models/m3d_loading/main.go new file mode 100644 index 0000000..d979a2c --- /dev/null +++ b/examples/models/m3d_loading/main.go @@ -0,0 +1,155 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..9f1d0ec --- /dev/null +++ b/examples/models/mesh_generation/main.go @@ -0,0 +1,167 @@ +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 new file mode 100644 index 0000000..fba3e4e --- /dev/null +++ b/examples/models/mesh_picking/main.go @@ -0,0 +1,261 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..bf7caac --- /dev/null +++ b/examples/models/mesh_picking/turret.obj @@ -0,0 +1,1888 @@ +# (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 new file mode 100644 index 0000000..33628e3 Binary files /dev/null and b/examples/models/mesh_picking/turret_diffuse.png differ diff --git a/examples/models/obj_loading/castle.obj b/examples/models/obj_loading/castle.obj new file mode 100644 index 0000000..a4ec921 --- /dev/null +++ b/examples/models/obj_loading/castle.obj @@ -0,0 +1,12919 @@ +# (c) 2018 Medieval Assets Pack by Alberto Cano +# Licensed as Creative Commons Attribution-NonCommercial 4.0 + +# +# object castle +# + +v -17.17 7.76 -10.68 +v -16.55 7.76 -12.98 +v -16.55 0.00 -12.98 +v -17.17 0.00 -10.68 +v -14.87 7.76 -14.66 +v -14.87 0.00 -14.66 +v -12.57 7.76 -15.28 +v -12.57 0.00 -15.28 +v -10.27 7.76 -14.66 +v -10.27 0.00 -14.66 +v -8.58 7.76 -12.98 +v -8.58 0.00 -12.98 +v -7.97 7.76 -10.68 +v -7.97 0.00 -10.68 +v -8.58 7.76 -8.38 +v -8.58 0.00 -8.38 +v -10.27 7.76 -6.69 +v -10.27 0.00 -6.69 +v -12.57 7.76 -6.08 +v -12.57 0.00 -6.08 +v -14.87 7.76 -6.69 +v -14.87 0.00 -6.69 +v -16.55 7.76 -8.38 +v -16.55 0.00 -8.38 +v -16.78 7.76 -13.11 +v -17.43 7.76 -10.68 +v -17.43 8.57 -10.68 +v -16.78 8.57 -13.11 +v -15.00 7.76 -14.89 +v -15.00 8.57 -14.89 +v -12.57 7.76 -15.54 +v -12.57 8.57 -15.54 +v -10.13 7.76 -14.89 +v -10.13 8.57 -14.89 +v -8.35 7.76 -13.11 +v -8.35 8.57 -13.11 +v -7.70 7.76 -10.68 +v -7.70 8.57 -10.68 +v -8.35 7.76 -8.24 +v -8.35 8.57 -8.24 +v -10.13 7.76 -6.46 +v -10.13 8.57 -6.46 +v -12.57 7.76 -5.81 +v -12.57 8.57 -5.81 +v -15.00 7.76 -6.46 +v -15.00 8.57 -6.46 +v -16.78 7.76 -8.24 +v -16.78 8.57 -8.24 +v -17.17 8.57 -10.68 +v -16.55 8.57 -12.98 +v -14.87 8.57 -14.66 +v -12.57 8.57 -15.28 +v -10.27 8.57 -14.66 +v -8.58 8.57 -12.98 +v -7.97 8.57 -10.68 +v -8.58 8.57 -8.38 +v -10.27 8.57 -6.69 +v -12.57 8.57 -6.08 +v -14.87 8.57 -6.69 +v -16.55 8.57 -8.38 +v -17.17 16.89 -10.68 +v -16.55 16.89 -12.98 +v -14.87 16.89 -14.66 +v -12.57 16.89 -15.28 +v -10.27 16.89 -14.66 +v -8.58 16.89 -12.98 +v -7.97 16.89 -10.68 +v -8.58 16.89 -8.38 +v -10.27 16.89 -6.69 +v -12.57 16.89 -6.08 +v -14.87 16.89 -6.69 +v -16.55 16.89 -8.38 +v -17.13 21.30 -13.31 +v -17.83 21.30 -10.68 +v -18.23 21.30 -10.68 +v -17.47 21.30 -13.51 +v -15.20 21.30 -15.24 +v -15.40 21.30 -15.58 +v -12.57 21.30 -15.94 +v -12.57 21.30 -16.34 +v -9.93 21.30 -15.24 +v -9.73 21.30 -15.58 +v -8.01 21.30 -13.31 +v -7.66 21.30 -13.51 +v -7.30 21.30 -10.68 +v -6.90 21.30 -10.68 +v -8.01 21.30 -8.04 +v -7.66 21.30 -7.84 +v -9.93 21.30 -6.12 +v -9.73 21.30 -5.77 +v -12.57 21.30 -5.41 +v -12.57 21.30 -5.01 +v -15.20 21.30 -6.12 +v -15.40 21.30 -5.77 +v -17.13 21.30 -8.04 +v -17.47 21.30 -7.84 +v -16.72 24.76 -10.68 +v -16.17 24.76 -12.76 +v -14.64 24.76 -14.28 +v -12.57 24.76 -14.83 +v -10.49 24.76 -14.28 +v -8.97 24.76 -12.76 +v -8.41 24.76 -10.68 +v -8.97 24.76 -8.60 +v -10.49 24.76 -7.08 +v -12.57 24.76 -6.52 +v -14.64 24.76 -7.08 +v -16.17 24.76 -8.60 +v -16.69 28.50 -10.68 +v -16.13 28.50 -12.74 +v -14.63 28.50 -14.24 +v -12.57 28.50 -14.80 +v -10.51 28.50 -14.24 +v -9.00 28.50 -12.74 +v -8.45 28.50 -10.68 +v -9.00 28.50 -8.62 +v -10.51 28.50 -7.11 +v -12.57 28.50 -6.56 +v -14.63 28.50 -7.11 +v -16.13 28.50 -8.62 +v -17.83 17.36 -10.68 +v -17.13 17.36 -13.31 +v -15.20 17.36 -15.24 +v -12.57 17.36 -15.94 +v -9.93 17.36 -15.24 +v -8.01 17.36 -13.31 +v -7.30 17.36 -10.68 +v -8.01 17.36 -8.04 +v -9.93 17.36 -6.12 +v -12.57 17.36 -5.41 +v -15.20 17.36 -6.12 +v -17.13 17.36 -8.04 +v -17.91 20.21 -10.37 +v -17.91 20.52 -10.80 +v -17.91 19.21 -10.80 +v -17.91 19.23 -10.37 +v -17.81 19.26 -10.03 +v -17.91 19.26 -10.04 +v -17.91 19.12 -10.04 +v -17.81 19.12 -10.03 +v -17.89 20.75 -10.80 +v -17.98 20.75 -10.81 +v -17.94 20.29 -10.15 +v -17.84 20.29 -10.15 +v -17.68 19.12 -11.55 +v -17.78 19.12 -11.56 +v -17.78 19.26 -11.56 +v -17.68 19.26 -11.55 +v -17.89 19.07 -10.80 +v -17.98 19.07 -10.81 +v -17.82 19.12 -11.45 +v -17.73 19.12 -11.45 +v -18.05 19.12 -10.16 +v -18.05 19.26 -10.16 +v -18.08 19.23 -10.39 +v -17.98 20.52 -10.81 +v -17.98 20.21 -10.38 +v -17.93 19.26 -11.46 +v -17.93 19.12 -11.46 +v -18.01 19.24 -11.24 +v -18.09 19.07 -10.82 +v -18.09 19.21 -10.82 +v -17.83 20.21 -11.23 +v -17.83 19.24 -11.23 +v -17.73 20.29 -11.45 +v -17.82 20.29 -11.45 +v -17.84 19.12 -10.15 +v -17.94 19.12 -10.15 +v -17.90 20.21 -11.23 +v -17.98 19.23 -10.38 +v -17.90 19.24 -11.23 +v -17.98 19.21 -10.81 +v -17.82 19.26 -11.45 +v -17.73 19.26 -11.45 +v -17.94 19.26 -10.15 +v -17.84 19.26 -10.15 +v -18.02 19.26 -10.05 +v -18.02 19.12 -10.05 +v -17.88 19.12 -11.57 +v -17.88 19.26 -11.57 +v -12.87 20.21 -16.02 +v -12.44 20.52 -16.02 +v -12.44 19.21 -16.02 +v -12.87 19.23 -16.02 +v -13.21 19.26 -15.92 +v -13.20 19.26 -16.02 +v -13.20 19.12 -16.02 +v -13.21 19.12 -15.92 +v -12.44 20.75 -16.00 +v -12.43 20.75 -16.10 +v -13.09 20.29 -16.05 +v -13.10 20.29 -15.95 +v -11.69 19.12 -15.79 +v -11.68 19.12 -15.89 +v -11.68 19.26 -15.89 +v -11.69 19.26 -15.79 +v -12.44 19.07 -16.00 +v -12.43 19.07 -16.10 +v -11.79 19.12 -15.94 +v -11.80 19.12 -15.84 +v -13.08 19.12 -16.16 +v -13.08 19.26 -16.16 +v -12.85 19.23 -16.20 +v -12.43 20.52 -16.10 +v -12.86 20.21 -16.09 +v -11.78 19.26 -16.04 +v -11.78 19.12 -16.04 +v -12.00 19.24 -16.12 +v -12.42 19.07 -16.20 +v -12.42 19.21 -16.20 +v -12.01 20.21 -15.94 +v -12.01 19.24 -15.94 +v -11.80 20.29 -15.84 +v -11.79 20.29 -15.94 +v -13.10 19.12 -15.95 +v -13.09 19.12 -16.05 +v -12.01 20.21 -16.01 +v -12.86 19.23 -16.09 +v -12.01 19.24 -16.01 +v -12.43 19.21 -16.10 +v -11.79 19.26 -15.94 +v -11.80 19.26 -15.84 +v -13.09 19.26 -16.05 +v -13.10 19.26 -15.95 +v -13.19 19.26 -16.13 +v -13.19 19.12 -16.13 +v -11.67 19.12 -16.00 +v -11.67 19.26 -16.00 +v -9.24 23.34 -12.52 +v -9.78 23.34 -13.29 +v -9.10 24.92 -13.76 +v -8.56 24.92 -12.99 +v -8.63 28.41 -12.92 +v -9.53 28.41 -12.29 +v -9.18 28.41 -13.70 +v -10.08 28.41 -13.07 +v -12.87 27.21 -14.81 +v -12.44 27.52 -14.82 +v -12.44 26.21 -14.82 +v -12.87 26.24 -14.81 +v -13.21 26.26 -14.72 +v -13.20 26.26 -14.82 +v -13.20 26.12 -14.82 +v -13.21 26.12 -14.72 +v -12.44 27.75 -14.80 +v -12.43 27.75 -14.89 +v -13.09 27.30 -14.85 +v -13.10 27.30 -14.75 +v -11.69 26.12 -14.59 +v -11.68 26.12 -14.69 +v -11.68 26.26 -14.69 +v -11.69 26.26 -14.59 +v -12.44 26.07 -14.80 +v -12.43 26.07 -14.89 +v -11.79 26.12 -14.73 +v -11.80 26.12 -14.64 +v -13.08 26.12 -14.96 +v -13.08 26.26 -14.96 +v -12.85 26.24 -14.99 +v -12.43 27.52 -14.89 +v -12.86 27.21 -14.89 +v -11.78 26.26 -14.84 +v -11.78 26.12 -14.84 +v -12.00 26.25 -14.92 +v -12.42 26.07 -15.00 +v -12.42 26.21 -15.00 +v -12.01 27.21 -14.74 +v -12.01 26.25 -14.74 +v -11.80 27.30 -14.64 +v -11.79 27.30 -14.73 +v -13.10 26.12 -14.75 +v -13.09 26.12 -14.85 +v -12.01 27.21 -14.81 +v -12.86 26.24 -14.89 +v -12.01 26.25 -14.81 +v -12.43 26.21 -14.89 +v -11.79 26.26 -14.73 +v -11.80 26.26 -14.64 +v -13.09 26.26 -14.85 +v -13.10 26.26 -14.75 +v -13.19 26.26 -14.93 +v -13.19 26.12 -14.93 +v -11.67 26.12 -14.79 +v -11.67 26.26 -14.79 +v -14.41 23.34 -14.01 +v -15.18 23.34 -13.46 +v -15.65 24.92 -14.14 +v -14.88 24.92 -14.68 +v -14.81 28.41 -14.61 +v -14.18 28.41 -13.71 +v -15.59 28.41 -14.07 +v -14.96 28.41 -13.17 +v -8.43 27.21 -10.98 +v -8.42 27.52 -10.55 +v -8.42 26.21 -10.55 +v -8.43 26.24 -10.98 +v -8.52 26.26 -11.32 +v -8.42 26.26 -11.31 +v -8.42 26.12 -11.31 +v -8.52 26.12 -11.32 +v -8.45 27.75 -10.55 +v -8.35 27.75 -10.54 +v -8.39 27.30 -11.20 +v -8.49 27.30 -11.21 +v -8.65 26.12 -9.80 +v -8.56 26.12 -9.79 +v -8.56 26.26 -9.79 +v -8.65 26.26 -9.80 +v -8.45 26.07 -10.55 +v -8.35 26.07 -10.54 +v -8.51 26.12 -9.90 +v -8.61 26.12 -9.91 +v -8.29 26.12 -11.19 +v -8.29 26.26 -11.19 +v -8.25 26.24 -10.96 +v -8.35 27.52 -10.54 +v -8.35 27.21 -10.97 +v -8.40 26.26 -9.89 +v -8.40 26.12 -9.89 +v -8.32 26.25 -10.11 +v -8.24 26.07 -10.53 +v -8.24 26.21 -10.53 +v -8.50 27.21 -10.13 +v -8.50 26.25 -10.13 +v -8.61 27.30 -9.91 +v -8.51 27.30 -9.90 +v -8.49 26.12 -11.21 +v -8.39 26.12 -11.20 +v -8.43 27.21 -10.12 +v -8.35 26.24 -10.97 +v -8.43 26.25 -10.12 +v -8.35 26.21 -10.54 +v -8.51 26.26 -9.90 +v -8.61 26.26 -9.91 +v -8.39 26.26 -11.20 +v -8.49 26.26 -11.21 +v -8.32 26.26 -11.30 +v -8.32 26.12 -11.30 +v -8.45 26.12 -9.78 +v -8.45 26.26 -9.78 +v -13.04 12.70 -6.81 +v -12.09 12.70 -6.81 +v -12.09 14.28 -5.99 +v -13.04 14.28 -5.99 +v -13.04 17.34 -5.64 +v -13.04 17.34 -6.74 +v -12.09 17.34 -5.64 +v -12.09 17.34 -6.74 +v -8.98 12.70 -12.20 +v -9.46 12.70 -13.02 +v -8.74 14.28 -13.43 +v -8.27 14.28 -12.61 +v -7.97 17.34 -12.79 +v -8.92 17.34 -12.24 +v -8.44 17.34 -13.61 +v -9.39 17.34 -13.06 +v -12.09 12.70 -14.54 +v -13.04 12.70 -14.54 +v -13.04 14.28 -15.36 +v -12.09 14.28 -15.36 +v -12.09 17.34 -15.71 +v -12.09 17.34 -14.62 +v -13.04 17.34 -15.71 +v -13.04 17.34 -14.62 +v -10.73 23.34 -7.35 +v -9.95 23.34 -7.89 +v -9.48 24.92 -7.22 +v -10.25 24.92 -6.67 +v -10.32 28.41 -6.74 +v -10.95 28.41 -7.65 +v -9.55 28.41 -7.29 +v -10.18 28.41 -8.19 +v -9.46 12.70 -8.34 +v -8.98 12.70 -9.15 +v -8.27 14.28 -8.74 +v -8.74 14.28 -7.92 +v -8.44 17.34 -7.75 +v -9.39 17.34 -8.30 +v -7.97 17.34 -8.57 +v -8.92 17.34 -9.12 +v -7.23 20.21 -10.98 +v -7.22 20.52 -10.55 +v -7.22 19.21 -10.55 +v -7.23 19.23 -10.98 +v -7.32 19.26 -11.32 +v -7.22 19.26 -11.31 +v -7.22 19.12 -11.31 +v -7.32 19.12 -11.32 +v -7.24 20.75 -10.55 +v -7.15 20.75 -10.54 +v -7.19 20.29 -11.20 +v -7.29 20.29 -11.21 +v -7.45 19.12 -9.80 +v -7.35 19.12 -9.79 +v -7.35 19.26 -9.79 +v -7.45 19.26 -9.80 +v -7.24 19.07 -10.55 +v -7.15 19.07 -10.54 +v -7.31 19.12 -9.90 +v -7.41 19.12 -9.91 +v -7.09 19.12 -11.19 +v -7.09 19.26 -11.19 +v -7.05 19.23 -10.96 +v -7.15 20.52 -10.54 +v -7.15 20.21 -10.97 +v -7.20 19.26 -9.89 +v -7.20 19.12 -9.89 +v -7.12 19.24 -10.11 +v -7.04 19.07 -10.53 +v -7.04 19.21 -10.53 +v -7.30 20.21 -10.13 +v -7.30 19.24 -10.13 +v -7.41 20.29 -9.91 +v -7.31 20.29 -9.90 +v -7.29 19.12 -11.21 +v -7.19 19.12 -11.20 +v -7.23 20.21 -10.12 +v -7.15 19.23 -10.97 +v -7.23 19.24 -10.12 +v -7.15 19.21 -10.54 +v -7.31 19.26 -9.90 +v -7.41 19.26 -9.91 +v -7.19 19.26 -11.20 +v -7.29 19.26 -11.21 +v -7.11 19.26 -11.30 +v -7.11 19.12 -11.30 +v -7.25 19.12 -9.78 +v -7.25 19.26 -9.78 +v -12.26 27.21 -6.54 +v -12.69 27.52 -6.53 +v -12.69 26.21 -6.53 +v -12.26 26.24 -6.54 +v -11.92 26.26 -6.63 +v -11.93 26.26 -6.53 +v -11.93 26.12 -6.53 +v -11.92 26.12 -6.63 +v -12.69 27.75 -6.56 +v -12.70 27.75 -6.46 +v -12.04 27.30 -6.51 +v -12.03 27.30 -6.60 +v -13.44 26.12 -6.76 +v -13.45 26.12 -6.67 +v -13.45 26.26 -6.67 +v -13.44 26.26 -6.76 +v -12.69 26.07 -6.56 +v -12.70 26.07 -6.46 +v -13.34 26.12 -6.62 +v -13.34 26.12 -6.72 +v -12.05 26.12 -6.40 +v -12.05 26.26 -6.40 +v -12.28 26.24 -6.36 +v -12.70 27.52 -6.46 +v -12.27 27.21 -6.47 +v -13.35 26.26 -6.51 +v -13.35 26.12 -6.51 +v -13.13 26.25 -6.43 +v -12.71 26.07 -6.35 +v -12.71 26.21 -6.35 +v -13.12 27.21 -6.61 +v -13.12 26.25 -6.61 +v -13.34 27.30 -6.72 +v -13.34 27.30 -6.62 +v -12.03 26.12 -6.60 +v -12.04 26.12 -6.51 +v -13.12 27.21 -6.54 +v -12.27 26.24 -6.47 +v -13.12 26.25 -6.54 +v -12.70 26.21 -6.46 +v -13.34 26.26 -6.62 +v -13.34 26.26 -6.72 +v -12.04 26.26 -6.51 +v -12.03 26.26 -6.60 +v -11.94 26.26 -6.43 +v -11.94 26.12 -6.43 +v -13.46 26.12 -6.56 +v -13.46 26.26 -6.56 +v -16.15 12.70 -9.15 +v -15.67 12.70 -8.34 +v -16.39 14.28 -7.92 +v -16.86 14.28 -8.74 +v -17.17 17.34 -8.57 +v -16.21 17.34 -9.12 +v -16.69 17.34 -7.75 +v -15.74 17.34 -8.30 +v -12.26 20.21 -5.34 +v -12.69 20.52 -5.33 +v -12.69 19.21 -5.33 +v -12.26 19.23 -5.34 +v -11.92 19.26 -5.43 +v -11.93 19.26 -5.33 +v -11.93 19.12 -5.33 +v -11.92 19.12 -5.43 +v -12.69 20.75 -5.36 +v -12.70 20.75 -5.26 +v -12.04 20.29 -5.30 +v -12.03 20.29 -5.40 +v -13.44 19.12 -5.56 +v -13.45 19.12 -5.47 +v -13.45 19.26 -5.47 +v -13.44 19.26 -5.56 +v -12.69 19.07 -5.36 +v -12.70 19.07 -5.26 +v -13.34 19.12 -5.42 +v -13.34 19.12 -5.52 +v -12.05 19.12 -5.20 +v -12.05 19.26 -5.20 +v -12.28 19.23 -5.16 +v -12.70 20.52 -5.26 +v -12.27 20.21 -5.26 +v -13.35 19.26 -5.31 +v -13.35 19.12 -5.31 +v -13.13 19.24 -5.23 +v -12.71 19.07 -5.15 +v -12.71 19.21 -5.15 +v -13.12 20.21 -5.41 +v -13.12 19.24 -5.41 +v -13.34 20.29 -5.52 +v -13.34 20.29 -5.42 +v -12.03 19.12 -5.40 +v -12.04 19.12 -5.30 +v -13.12 20.21 -5.34 +v -12.27 19.23 -5.26 +v -13.12 19.24 -5.34 +v -12.70 19.21 -5.26 +v -13.34 19.26 -5.42 +v -13.34 19.26 -5.52 +v -12.04 19.26 -5.30 +v -12.03 19.26 -5.40 +v -11.94 19.26 -5.23 +v -11.94 19.12 -5.23 +v -13.46 19.12 -5.36 +v -13.46 19.26 -5.36 +v -15.89 23.34 -8.84 +v -15.35 23.34 -8.06 +v -16.03 24.92 -7.59 +v -16.57 24.92 -8.36 +v -16.50 28.41 -8.43 +v -15.60 28.41 -9.06 +v -15.96 28.41 -7.66 +v -15.06 28.41 -8.29 +v -16.70 27.21 -10.37 +v -16.71 27.52 -10.80 +v -16.71 26.21 -10.80 +v -16.70 26.24 -10.37 +v -16.61 26.26 -10.03 +v -16.71 26.26 -10.04 +v -16.71 26.12 -10.04 +v -16.61 26.12 -10.03 +v -16.69 27.75 -10.80 +v -16.78 27.75 -10.81 +v -16.74 27.30 -10.15 +v -16.64 27.30 -10.15 +v -16.48 26.12 -11.55 +v -16.58 26.12 -11.56 +v -16.58 26.26 -11.56 +v -16.48 26.26 -11.55 +v -16.69 26.07 -10.80 +v -16.78 26.07 -10.81 +v -16.62 26.12 -11.45 +v -16.53 26.12 -11.45 +v -16.84 26.12 -10.16 +v -16.84 26.26 -10.16 +v -16.88 26.24 -10.39 +v -16.78 27.52 -10.81 +v -16.78 27.21 -10.38 +v -16.73 26.26 -11.46 +v -16.73 26.12 -11.46 +v -16.81 26.25 -11.24 +v -16.89 26.07 -10.82 +v -16.89 26.21 -10.82 +v -16.63 27.21 -11.23 +v -16.63 26.25 -11.23 +v -16.53 27.30 -11.45 +v -16.62 27.30 -11.45 +v -16.64 26.12 -10.15 +v -16.74 26.12 -10.15 +v -16.70 27.21 -11.23 +v -16.78 26.24 -10.38 +v -16.70 26.25 -11.23 +v -16.78 26.21 -10.81 +v -16.62 26.26 -11.45 +v -16.53 26.26 -11.45 +v -16.74 26.26 -10.15 +v -16.64 26.26 -10.15 +v -16.82 26.26 -10.05 +v -16.82 26.12 -10.05 +v -16.68 26.12 -11.57 +v -16.68 26.26 -11.57 +v -15.67 12.70 -13.02 +v -16.15 12.70 -12.20 +v -16.86 14.28 -12.61 +v -16.39 14.28 -13.43 +v -16.69 17.34 -13.61 +v -15.74 17.34 -13.06 +v -17.17 17.34 -12.79 +v -16.21 17.34 -12.24 +v -16.83 28.50 -13.14 +v -17.49 28.50 -10.68 +v -17.49 30.29 -10.68 +v -16.83 30.29 -13.14 +v -15.03 28.50 -14.94 +v -15.03 30.29 -14.94 +v -12.57 28.50 -15.60 +v -12.57 30.29 -15.60 +v -10.10 28.50 -14.94 +v -10.10 30.29 -14.94 +v -8.30 28.50 -13.14 +v -8.30 30.29 -13.14 +v -7.64 28.50 -10.68 +v -7.64 30.29 -10.68 +v -8.30 28.50 -8.21 +v -8.30 30.29 -8.21 +v -10.10 28.50 -6.41 +v -10.10 30.29 -6.41 +v -12.57 28.50 -5.75 +v -12.57 30.29 -5.75 +v -15.03 28.50 -6.41 +v -15.03 30.29 -6.41 +v -16.83 28.50 -8.21 +v -16.83 30.29 -8.21 +v -16.78 30.29 -10.68 +v -16.21 30.29 -12.78 +v -15.03 30.90 -14.94 +v -16.83 30.90 -13.14 +v -16.21 30.90 -12.78 +v -14.67 30.90 -14.32 +v -14.67 30.29 -14.32 +v -12.57 30.29 -14.89 +v -10.10 30.90 -14.94 +v -12.57 30.90 -15.60 +v -12.57 30.90 -14.89 +v -10.46 30.90 -14.32 +v -10.46 30.29 -14.32 +v -8.92 30.29 -12.78 +v -7.64 30.90 -10.68 +v -8.30 30.90 -13.14 +v -8.92 30.90 -12.78 +v -8.36 30.90 -10.68 +v -8.36 30.29 -10.68 +v -8.92 30.29 -8.57 +v -10.10 30.90 -6.41 +v -8.30 30.90 -8.21 +v -8.92 30.90 -8.57 +v -10.46 30.90 -7.03 +v -10.46 30.29 -7.03 +v -12.57 30.29 -6.47 +v -15.03 30.90 -6.41 +v -12.57 30.90 -5.75 +v -12.57 30.90 -6.47 +v -14.67 30.90 -7.03 +v -14.67 30.29 -7.03 +v -16.21 30.29 -8.57 +v -17.49 30.90 -10.68 +v -16.83 30.90 -8.21 +v -16.21 30.90 -8.57 +v -16.78 30.90 -10.68 +v -16.78 29.42 -10.68 +v -16.21 29.42 -12.78 +v -14.67 29.42 -14.32 +v -12.57 29.42 -14.89 +v -10.46 29.42 -14.32 +v -8.92 29.42 -12.78 +v -8.36 29.42 -10.68 +v -8.92 29.42 -8.57 +v -10.46 29.42 -7.03 +v -12.57 29.42 -6.47 +v -14.67 29.42 -7.03 +v -16.21 29.42 -8.57 +v -12.57 29.42 -10.68 +v 15.69 11.78 11.98 +v 15.69 11.78 -12.46 +v 10.74 17.79 -7.40 +v 10.74 17.79 7.40 +v -15.69 11.78 -12.46 +v -10.74 17.79 -7.40 +v -15.69 11.78 11.98 +v -10.74 17.79 7.40 +v 12.89 0.00 11.03 +v 12.89 0.00 -11.03 +v 12.89 11.78 -11.03 +v 12.89 11.78 11.03 +v -12.89 0.00 -11.03 +v -12.89 11.78 -11.03 +v -23.42 0.00 -6.76 +v -23.42 0.00 6.76 +v -23.42 6.95 6.76 +v -23.42 6.95 -6.76 +v -12.89 0.00 11.03 +v -12.89 11.78 11.03 +v 8.74 17.79 -3.62 +v 8.74 17.79 3.62 +v -8.74 17.79 -3.62 +v -8.74 17.79 3.62 +v -12.89 6.95 6.76 +v -12.89 0.00 6.76 +v -12.89 6.95 -6.76 +v -12.89 0.00 -6.76 +v -9.46 12.70 7.57 +v -8.74 14.28 7.16 +v -8.27 14.28 7.98 +v -8.98 12.70 8.39 +v -9.39 17.34 7.53 +v -8.44 17.34 6.98 +v -7.97 17.34 7.80 +v -8.92 17.34 8.35 +v -9.31 28.15 -0.00 +v -9.31 23.30 4.54 +v 0.00 22.65 4.30 +v -0.11 25.84 -0.00 +v -9.31 27.72 -0.00 +v -9.31 22.87 4.55 +v 0.00 22.23 4.31 +v 0.00 22.65 -4.30 +v -9.31 23.30 -4.54 +v -9.31 22.87 -4.55 +v 0.00 22.23 -4.31 +v 9.31 28.15 -0.00 +v 9.31 23.30 4.54 +v 9.31 27.72 -0.00 +v 9.31 22.87 4.55 +v 9.31 23.30 -4.54 +v 9.31 22.87 -4.55 +v 4.76 26.71 -0.63 +v 5.87 26.95 -0.63 +v 5.91 26.75 -0.63 +v 4.80 26.52 -0.63 +v 4.68 27.10 -0.11 +v 5.79 27.34 -0.11 +v 4.72 26.91 -0.11 +v 5.79 27.35 -0.00 +v 4.68 27.12 -0.00 +v 4.72 26.93 -0.00 +v 5.91 26.75 0.63 +v 5.87 26.95 0.63 +v 4.76 26.71 0.63 +v 4.80 26.52 0.63 +v 5.79 27.34 0.11 +v 4.68 27.10 0.11 +v 4.72 26.91 0.11 +v 3.88 26.49 -0.63 +v 5.00 26.69 -0.63 +v 5.03 26.49 -0.63 +v 3.91 26.30 -0.63 +v 3.81 26.89 -0.11 +v 4.93 27.08 -0.11 +v 3.84 26.69 -0.11 +v 4.92 27.09 -0.00 +v 3.81 26.90 -0.00 +v 3.84 26.71 -0.00 +v 5.03 26.49 0.63 +v 5.00 26.69 0.63 +v 3.88 26.49 0.63 +v 3.91 26.30 0.63 +v 4.93 27.08 0.11 +v 3.81 26.89 0.11 +v 3.84 26.69 0.11 +v 2.89 26.32 -0.63 +v 4.01 26.46 -0.63 +v 4.04 26.27 -0.63 +v 2.91 26.13 -0.63 +v 2.84 26.72 -0.11 +v 3.96 26.86 -0.11 +v 2.86 26.53 -0.11 +v 3.96 26.87 -0.00 +v 2.84 26.74 -0.00 +v 2.86 26.54 -0.00 +v 4.04 26.27 0.63 +v 4.01 26.46 0.63 +v 2.89 26.32 0.63 +v 2.91 26.13 0.63 +v 3.96 26.86 0.11 +v 2.84 26.72 0.11 +v 2.86 26.53 0.11 +v 1.88 26.15 -0.63 +v 3.00 26.29 -0.63 +v 3.02 26.09 -0.63 +v 1.90 25.96 -0.63 +v 1.83 26.55 -0.11 +v 2.95 26.69 -0.11 +v 1.85 26.36 -0.11 +v 2.95 26.70 -0.00 +v 1.83 26.56 -0.00 +v 1.85 26.37 -0.00 +v 3.02 26.09 0.63 +v 3.00 26.29 0.63 +v 1.88 26.15 0.63 +v 1.90 25.96 0.63 +v 2.95 26.69 0.11 +v 1.83 26.55 0.11 +v 1.85 26.36 0.11 +v 0.78 26.08 -0.63 +v 1.91 26.12 -0.63 +v 1.92 25.93 -0.63 +v 0.79 25.89 -0.63 +v 0.77 26.49 -0.11 +v 1.90 26.52 -0.11 +v 0.77 26.29 -0.11 +v 1.90 26.54 -0.00 +v 0.77 26.50 -0.00 +v 0.77 26.30 -0.00 +v 1.92 25.93 0.63 +v 1.91 26.12 0.63 +v 0.78 26.08 0.63 +v 0.79 25.89 0.63 +v 1.90 26.52 0.11 +v 0.77 26.49 0.11 +v 0.77 26.29 0.11 +v -0.35 26.05 -0.63 +v 0.78 26.11 -0.63 +v 0.79 25.91 -0.63 +v -0.34 25.85 -0.63 +v -0.37 26.45 -0.11 +v 0.76 26.51 -0.11 +v -0.36 26.25 -0.11 +v 0.76 26.52 -0.00 +v -0.38 26.46 -0.00 +v -0.37 26.27 -0.00 +v 0.79 25.91 0.63 +v 0.78 26.11 0.63 +v -0.35 26.05 0.63 +v -0.34 25.85 0.63 +v 0.76 26.51 0.11 +v -0.37 26.45 0.11 +v -0.36 26.25 0.11 +v 6.98 27.27 -0.63 +v 8.09 27.50 -0.63 +v 8.13 27.31 -0.63 +v 7.02 27.08 -0.63 +v 6.90 27.66 -0.11 +v 8.01 27.90 -0.11 +v 6.94 27.47 -0.11 +v 8.00 27.91 -0.00 +v 6.89 27.68 -0.00 +v 6.93 27.48 -0.00 +v 8.13 27.31 0.63 +v 8.09 27.50 0.63 +v 6.98 27.27 0.63 +v 7.02 27.08 0.63 +v 8.01 27.90 0.11 +v 6.90 27.66 0.11 +v 6.94 27.47 0.11 +v 5.87 26.96 -0.63 +v 6.98 27.20 -0.63 +v 7.02 27.01 -0.63 +v 5.91 26.77 -0.63 +v 5.79 27.36 -0.11 +v 6.90 27.59 -0.11 +v 5.83 27.17 -0.11 +v 6.89 27.60 -0.00 +v 5.79 27.37 -0.00 +v 5.83 27.18 -0.00 +v 7.02 27.01 0.63 +v 6.98 27.20 0.63 +v 5.87 26.96 0.63 +v 5.91 26.77 0.63 +v 6.90 27.59 0.11 +v 5.79 27.36 0.11 +v 5.83 27.17 0.11 +v -6.20 26.77 -0.63 +v -6.16 26.96 -0.63 +v -5.05 26.72 -0.63 +v -5.09 26.53 -0.63 +v -4.97 27.12 -0.11 +v -6.08 27.35 -0.11 +v -5.01 26.92 -0.11 +v -6.07 27.36 -0.00 +v -4.96 27.13 -0.00 +v -5.01 26.94 -0.00 +v -5.05 26.72 0.63 +v -6.16 26.96 0.63 +v -6.20 26.77 0.63 +v -5.09 26.53 0.63 +v -4.97 27.12 0.11 +v -6.08 27.35 0.11 +v -5.01 26.92 0.11 +v -5.32 26.52 -0.63 +v -5.28 26.71 -0.63 +v -4.17 26.51 -0.63 +v -4.20 26.32 -0.63 +v -4.10 26.91 -0.11 +v -5.21 27.11 -0.11 +v -4.13 26.72 -0.11 +v -5.21 27.12 -0.00 +v -4.10 26.92 -0.00 +v -4.13 26.73 -0.00 +v -4.17 26.51 0.63 +v -5.28 26.71 0.63 +v -5.32 26.52 0.63 +v -4.20 26.32 0.63 +v -4.10 26.91 0.11 +v -5.21 27.11 0.11 +v -4.13 26.72 0.11 +v -4.32 26.27 -0.63 +v -4.30 26.46 -0.63 +v -3.18 26.32 -0.63 +v -3.20 26.13 -0.63 +v -3.13 26.72 -0.11 +v -4.25 26.86 -0.11 +v -3.15 26.53 -0.11 +v -4.25 26.87 -0.00 +v -3.13 26.73 -0.00 +v -3.15 26.54 -0.00 +v -3.18 26.32 0.63 +v -4.30 26.46 0.63 +v -4.32 26.27 0.63 +v -3.20 26.13 0.63 +v -3.13 26.72 0.11 +v -4.25 26.86 0.11 +v -3.15 26.53 0.11 +v -3.31 26.05 -0.63 +v -3.29 26.24 -0.63 +v -2.16 26.11 -0.63 +v -2.19 25.91 -0.63 +v -2.12 26.50 -0.11 +v -3.24 26.64 -0.11 +v -2.14 26.31 -0.11 +v -3.24 26.65 -0.00 +v -2.11 26.52 -0.00 +v -2.14 26.32 -0.00 +v -2.16 26.11 0.63 +v -3.29 26.24 0.63 +v -3.31 26.05 0.63 +v -2.19 25.91 0.63 +v -2.12 26.50 0.11 +v -3.24 26.64 0.11 +v -2.14 26.31 0.11 +v -2.21 25.88 -0.63 +v -2.20 26.08 -0.63 +v -1.07 26.04 -0.63 +v -1.07 25.84 -0.63 +v -1.05 26.44 -0.11 +v -2.19 26.48 -0.11 +v -1.06 26.25 -0.11 +v -2.19 26.49 -0.00 +v -1.05 26.45 -0.00 +v -1.06 26.26 -0.00 +v -1.07 26.04 0.63 +v -2.20 26.08 0.63 +v -2.21 25.88 0.63 +v -1.07 25.84 0.63 +v -1.05 26.44 0.11 +v -2.19 26.48 0.11 +v -1.06 26.25 0.11 +v -1.08 25.87 -0.63 +v -1.07 26.06 -0.63 +v 0.07 26.00 -0.63 +v 0.06 25.80 -0.63 +v 0.09 26.40 -0.11 +v -1.04 26.46 -0.11 +v 0.08 26.21 -0.11 +v -1.04 26.47 -0.00 +v 0.09 26.41 -0.00 +v 0.08 26.22 -0.00 +v 0.07 26.00 0.63 +v -1.07 26.06 0.63 +v -1.08 25.87 0.63 +v 0.06 25.80 0.63 +v 0.09 26.40 0.11 +v -1.04 26.46 0.11 +v 0.08 26.21 0.11 +v -8.19 27.32 -0.63 +v -8.15 27.51 -0.63 +v -7.04 27.28 -0.63 +v -7.08 27.09 -0.63 +v -6.96 27.67 -0.11 +v -8.07 27.90 -0.11 +v -7.00 27.48 -0.11 +v -8.06 27.92 -0.00 +v -6.95 27.68 -0.00 +v -6.99 27.49 -0.00 +v -7.04 27.28 0.63 +v -8.15 27.51 0.63 +v -8.19 27.32 0.63 +v -7.08 27.09 0.63 +v -6.96 27.67 0.11 +v -8.07 27.90 0.11 +v -7.00 27.48 0.11 +v -7.06 27.02 -0.63 +v -7.02 27.21 -0.63 +v -5.92 26.97 -0.63 +v -5.96 26.78 -0.63 +v -5.83 27.37 -0.11 +v -6.94 27.60 -0.11 +v -5.87 27.18 -0.11 +v -6.94 27.61 -0.00 +v -5.83 27.38 -0.00 +v -5.87 27.19 -0.00 +v -5.92 26.97 0.63 +v -7.02 27.21 0.63 +v -7.06 27.02 0.63 +v -5.96 26.78 0.63 +v -5.83 27.37 0.11 +v -6.94 27.60 0.11 +v -5.87 27.18 0.11 +v -9.18 27.83 -0.63 +v -8.10 27.48 -0.63 +v -8.16 27.29 -0.63 +v -9.24 27.64 -0.63 +v -9.05 28.21 -0.11 +v -7.98 27.86 -0.11 +v -9.11 28.02 -0.11 +v -7.97 27.87 -0.00 +v -9.05 28.22 -0.00 +v -9.11 28.04 -0.00 +v -8.16 27.29 0.63 +v -8.10 27.48 0.63 +v -9.18 27.83 0.63 +v -9.24 27.64 0.63 +v -7.98 27.86 0.11 +v -9.05 28.21 0.11 +v -9.11 28.02 0.11 +v 8.19 27.28 -0.63 +v 8.13 27.46 -0.63 +v 9.21 27.81 -0.63 +v 9.27 27.63 -0.63 +v 9.08 28.20 -0.11 +v 8.01 27.84 -0.11 +v 9.15 28.01 -0.11 +v 8.00 27.86 -0.00 +v 9.08 28.21 -0.00 +v 9.14 28.02 -0.00 +v 9.21 27.81 0.63 +v 8.13 27.46 0.63 +v 8.19 27.28 0.63 +v 9.27 27.63 0.63 +v 9.08 28.20 0.11 +v 8.01 27.84 0.11 +v 9.15 28.01 0.11 +v 9.46 12.70 7.57 +v 8.98 12.70 8.39 +v 8.27 14.28 7.98 +v 8.74 14.28 7.16 +v 8.44 17.34 6.98 +v 9.39 17.34 7.53 +v 7.97 17.34 7.80 +v 8.92 17.34 8.35 +v -15.48 7.80 6.90 +v -15.48 7.80 6.03 +v -17.46 7.80 6.03 +v -17.46 7.80 6.90 +v -15.48 6.95 6.90 +v -15.48 6.95 6.03 +v -17.46 6.95 6.03 +v -17.46 6.95 6.90 +v -18.47 7.80 6.90 +v -18.47 7.80 6.03 +v -20.45 7.80 6.03 +v -20.45 7.80 6.90 +v -18.47 6.95 6.90 +v -18.47 6.95 6.03 +v -20.45 6.95 6.03 +v -20.45 6.95 6.90 +v -21.45 7.80 6.90 +v -21.45 7.80 6.03 +v -23.44 7.80 6.03 +v -23.44 7.80 6.90 +v -21.45 6.95 6.90 +v -21.45 6.95 6.03 +v -23.44 6.95 6.03 +v -23.44 6.95 6.90 +v -23.40 7.80 5.50 +v -22.53 7.80 5.50 +v -22.53 7.80 3.51 +v -23.40 7.80 3.51 +v -23.40 6.95 5.50 +v -22.53 6.95 5.50 +v -22.53 6.95 3.51 +v -23.40 6.95 3.51 +v -23.40 7.80 2.51 +v -22.53 7.80 2.51 +v -22.53 7.80 0.53 +v -23.40 7.80 0.53 +v -23.40 6.95 2.51 +v -22.53 6.95 2.51 +v -22.53 6.95 0.53 +v -23.40 6.95 0.53 +v -23.40 7.80 -0.48 +v -22.53 7.80 -0.48 +v -22.53 7.80 -2.46 +v -23.40 7.80 -2.46 +v -23.40 6.95 -0.48 +v -22.53 6.95 -0.48 +v -22.53 6.95 -2.46 +v -23.40 6.95 -2.46 +v -23.40 7.80 -3.47 +v -22.53 7.80 -3.47 +v -22.53 7.80 -5.45 +v -23.40 7.80 -5.45 +v -23.40 6.95 -3.47 +v -22.53 6.95 -3.47 +v -22.53 6.95 -5.45 +v -23.40 6.95 -5.45 +v -21.45 7.80 -6.02 +v -21.45 7.80 -6.88 +v -23.44 7.80 -6.88 +v -23.44 7.80 -6.02 +v -21.45 6.95 -6.02 +v -21.45 6.95 -6.88 +v -23.44 6.95 -6.88 +v -23.44 6.95 -6.02 +v -18.47 7.80 -6.02 +v -18.47 7.80 -6.88 +v -20.45 7.80 -6.88 +v -20.45 7.80 -6.02 +v -18.47 6.95 -6.02 +v -18.47 6.95 -6.88 +v -20.45 6.95 -6.88 +v -20.45 6.95 -6.02 +v -15.48 7.80 -6.02 +v -15.48 7.80 -6.88 +v -17.46 7.80 -6.88 +v -17.46 7.80 -6.02 +v -15.48 6.95 -6.02 +v -15.48 6.95 -6.88 +v -17.46 6.95 -6.88 +v -17.46 6.95 -6.02 +v -7.10 7.80 -12.06 +v -7.10 7.80 -12.93 +v -9.08 7.80 -12.93 +v -9.08 7.80 -12.06 +v -7.10 6.95 -12.06 +v -7.10 6.95 -12.93 +v -9.08 6.95 -12.93 +v -9.08 6.95 -12.06 +v -4.46 7.80 -12.06 +v -4.46 7.80 -12.93 +v -6.45 7.80 -12.93 +v -6.45 7.80 -12.06 +v -4.46 6.95 -12.06 +v -4.46 6.95 -12.93 +v -6.45 6.95 -12.93 +v -6.45 6.95 -12.06 +v -1.83 7.80 -12.06 +v -1.83 7.80 -12.93 +v -3.81 7.80 -12.93 +v -3.81 7.80 -12.06 +v -1.83 6.95 -12.06 +v -1.83 6.95 -12.93 +v -3.81 6.95 -12.93 +v -3.81 6.95 -12.06 +v 0.81 7.80 -12.06 +v 0.81 7.80 -12.93 +v -1.17 7.80 -12.93 +v -1.17 7.80 -12.06 +v 0.81 6.95 -12.06 +v 0.81 6.95 -12.93 +v -1.17 6.95 -12.93 +v -1.17 6.95 -12.06 +v 3.44 7.80 -12.06 +v 3.44 7.80 -12.93 +v 1.46 7.80 -12.93 +v 1.46 7.80 -12.06 +v 3.44 6.95 -12.06 +v 3.44 6.95 -12.93 +v 1.46 6.95 -12.93 +v 1.46 6.95 -12.06 +v 6.08 7.80 -12.06 +v 6.08 7.80 -12.93 +v 4.10 7.80 -12.93 +v 4.10 7.80 -12.06 +v 6.08 6.95 -12.06 +v 6.08 6.95 -12.93 +v 4.10 6.95 -12.93 +v 4.10 6.95 -12.06 +v 8.72 7.80 -12.06 +v 8.72 7.80 -12.93 +v 6.74 7.80 -12.93 +v 6.74 7.80 -12.06 +v 8.72 6.95 -12.06 +v 8.72 6.95 -12.93 +v 6.74 6.95 -12.93 +v 6.74 6.95 -12.06 +v -4.39 18.64 -6.78 +v -4.39 18.64 -7.64 +v -6.37 18.64 -7.64 +v -6.37 18.64 -6.78 +v -4.39 17.79 -6.78 +v -4.39 17.79 -7.64 +v -6.37 17.79 -7.64 +v -6.37 17.79 -6.78 +v -1.66 18.64 -6.78 +v -1.66 18.64 -7.64 +v -3.64 18.64 -7.64 +v -3.64 18.64 -6.78 +v -1.66 17.79 -6.78 +v -1.66 17.79 -7.64 +v -3.64 17.79 -7.64 +v -3.64 17.79 -6.78 +v 1.06 18.64 -6.78 +v 1.06 18.64 -7.64 +v -0.92 18.64 -7.64 +v -0.92 18.64 -6.78 +v 1.06 17.79 -6.78 +v 1.06 17.79 -7.64 +v -0.92 17.79 -7.64 +v -0.92 17.79 -6.78 +v 3.79 18.64 -6.78 +v 3.79 18.64 -7.64 +v 1.80 18.64 -7.64 +v 1.80 18.64 -6.78 +v 3.79 17.79 -6.78 +v 3.79 17.79 -7.64 +v 1.80 17.79 -7.64 +v 1.80 17.79 -6.78 +v 6.51 18.64 -6.78 +v 6.51 18.64 -7.64 +v 4.53 18.64 -7.64 +v 4.53 18.64 -6.78 +v 6.51 17.79 -6.78 +v 6.51 17.79 -7.64 +v 4.53 17.79 -7.64 +v 4.53 17.79 -6.78 +v 9.24 18.64 -6.78 +v 9.24 18.64 -7.64 +v 7.25 18.64 -7.64 +v 7.25 18.64 -6.78 +v 9.24 17.79 -6.78 +v 9.24 17.79 -7.64 +v 7.25 17.79 -7.64 +v 7.25 17.79 -6.78 +v -7.11 18.64 -6.78 +v -7.11 18.64 -7.64 +v -9.09 18.64 -7.64 +v -9.09 18.64 -6.78 +v -7.11 17.79 -6.78 +v -7.11 17.79 -7.64 +v -9.09 17.79 -7.64 +v -9.09 17.79 -6.78 +v -9.92 18.64 -6.55 +v -10.78 18.64 -6.55 +v -10.78 18.64 -4.56 +v -9.92 18.64 -4.56 +v -9.92 17.79 -6.55 +v -10.78 17.79 -6.55 +v -10.78 17.79 -4.56 +v -9.92 17.79 -4.56 +v -9.92 18.64 -3.82 +v -10.78 18.64 -3.82 +v -10.78 18.64 -1.84 +v -9.92 18.64 -1.84 +v -9.92 17.79 -3.82 +v -10.78 17.79 -3.82 +v -10.78 17.79 -1.84 +v -9.92 17.79 -1.84 +v -9.92 18.64 -1.10 +v -10.78 18.64 -1.10 +v -10.78 18.64 0.88 +v -9.92 18.64 0.88 +v -9.92 17.79 -1.10 +v -10.78 17.79 -1.10 +v -10.78 17.79 0.88 +v -9.92 17.79 0.88 +v -9.92 18.64 1.63 +v -10.78 18.64 1.63 +v -10.78 18.64 3.61 +v -9.92 18.64 3.61 +v -9.92 17.79 1.63 +v -10.78 17.79 1.63 +v -10.78 17.79 3.61 +v -9.92 17.79 3.61 +v -7.11 18.64 7.48 +v -7.11 18.64 6.62 +v -9.09 18.64 6.62 +v -9.09 18.64 7.48 +v -7.11 17.79 7.48 +v -7.11 17.79 6.62 +v -9.09 17.79 6.62 +v -9.09 17.79 7.48 +v -4.39 18.64 7.48 +v -4.39 18.64 6.62 +v -6.37 18.64 6.62 +v -6.37 18.64 7.48 +v -4.39 17.79 7.48 +v -4.39 17.79 6.62 +v -6.37 17.79 6.62 +v -6.37 17.79 7.48 +v -1.66 18.64 7.48 +v -1.66 18.64 6.62 +v -3.64 18.64 6.62 +v -3.64 18.64 7.48 +v -1.66 17.79 7.48 +v -1.66 17.79 6.62 +v -3.64 17.79 6.62 +v -3.64 17.79 7.48 +v 1.06 18.64 7.48 +v 1.06 18.64 6.62 +v -0.92 18.64 6.62 +v -0.92 18.64 7.48 +v 1.06 17.79 7.48 +v 1.06 17.79 6.62 +v -0.92 17.79 6.62 +v -0.92 17.79 7.48 +v 3.79 18.64 7.48 +v 3.79 18.64 6.62 +v 1.80 18.64 6.62 +v 1.80 18.64 7.48 +v 3.79 17.79 7.48 +v 3.79 17.79 6.62 +v 1.80 17.79 6.62 +v 1.80 17.79 7.48 +v 9.24 18.64 7.48 +v 9.24 18.64 6.62 +v 7.25 18.64 6.62 +v 7.25 18.64 7.48 +v 9.24 17.79 7.48 +v 9.24 17.79 6.62 +v 7.25 17.79 6.62 +v 7.25 17.79 7.48 +v 6.51 18.64 7.48 +v 6.51 18.64 6.62 +v 4.53 18.64 6.62 +v 4.53 18.64 7.48 +v 6.51 17.79 7.48 +v 6.51 17.79 6.62 +v 4.53 17.79 6.62 +v 4.53 17.79 7.48 +v 10.85 18.64 -6.55 +v 9.99 18.64 -6.55 +v 9.99 18.64 -4.56 +v 10.85 18.64 -4.56 +v 10.85 17.79 -6.55 +v 9.99 17.79 -6.55 +v 9.99 17.79 -4.56 +v 10.85 17.79 -4.56 +v 10.85 18.64 -3.82 +v 9.99 18.64 -3.82 +v 9.99 18.64 -1.84 +v 10.85 18.64 -1.84 +v 10.85 17.79 -3.82 +v 9.99 17.79 -3.82 +v 9.99 17.79 -1.84 +v 10.85 17.79 -1.84 +v 10.85 18.64 -1.10 +v 9.99 18.64 -1.10 +v 9.99 18.64 0.88 +v 10.85 18.64 0.88 +v 10.85 17.79 -1.10 +v 9.99 17.79 -1.10 +v 9.99 17.79 0.88 +v 10.85 17.79 0.88 +v 10.85 18.64 1.63 +v 9.99 18.64 1.63 +v 9.99 18.64 3.61 +v 10.85 18.64 3.61 +v 10.85 17.79 1.63 +v 9.99 17.79 1.63 +v 9.99 17.79 3.61 +v 10.85 17.79 3.61 +v 10.85 18.64 4.35 +v 9.99 18.64 4.35 +v 9.99 18.64 6.33 +v 10.85 18.64 6.33 +v 10.85 17.79 4.35 +v 9.99 17.79 4.35 +v 9.99 17.79 6.33 +v 10.85 17.79 6.33 +v 11.17 6.95 -11.03 +v 11.17 6.95 -12.83 +v -11.17 6.95 -12.83 +v -11.17 6.95 -11.03 +v 11.17 -0.02 -12.83 +v -11.17 -0.02 -12.83 +v -19.96 4.66 -6.77 +v -19.60 5.22 -6.77 +v -19.60 2.88 -6.77 +v -19.96 2.92 -6.77 +v -20.24 2.96 -6.83 +v -20.24 2.71 -6.83 +v -20.24 2.71 -6.75 +v -20.24 2.96 -6.75 +v -19.60 5.63 -6.83 +v -20.15 4.82 -6.83 +v -20.15 4.82 -6.75 +v -19.60 5.63 -6.75 +v -18.96 2.71 -6.83 +v -18.96 2.96 -6.83 +v -18.96 2.96 -6.75 +v -18.96 2.71 -6.75 +v -19.60 2.63 -6.83 +v -19.05 2.71 -6.83 +v -19.05 2.71 -6.75 +v -19.60 2.63 -6.75 +v -20.15 2.71 -6.92 +v -20.15 2.96 -6.92 +v -19.96 2.92 -6.92 +v -19.60 5.22 -6.83 +v -19.96 4.66 -6.83 +v -19.05 2.96 -6.92 +v -19.05 2.71 -6.92 +v -19.24 2.94 -6.92 +v -19.60 2.63 -6.92 +v -19.60 2.88 -6.92 +v -19.24 4.66 -6.77 +v -19.24 2.94 -6.77 +v -19.05 4.82 -6.83 +v -19.05 4.82 -6.75 +v -20.15 2.71 -6.83 +v -20.15 2.71 -6.75 +v -19.24 4.66 -6.83 +v -19.96 2.92 -6.83 +v -19.24 2.94 -6.83 +v -19.60 2.88 -6.83 +v -19.05 2.96 -6.83 +v -19.05 2.96 -6.75 +v -20.15 2.96 -6.83 +v -20.15 2.96 -6.75 +v -20.24 2.96 -6.92 +v -20.24 2.71 -6.92 +v -18.96 2.71 -6.92 +v -18.96 2.96 -6.92 +v -6.81 4.66 -12.83 +v -6.45 5.22 -12.83 +v -6.45 2.88 -12.83 +v -6.81 2.92 -12.83 +v -7.09 2.96 -12.89 +v -7.09 2.71 -12.89 +v -7.09 2.71 -12.81 +v -7.09 2.96 -12.81 +v -6.45 5.63 -12.89 +v -6.99 4.82 -12.89 +v -6.99 4.82 -12.81 +v -6.45 5.63 -12.81 +v -5.81 2.71 -12.89 +v -5.81 2.96 -12.89 +v -5.81 2.96 -12.81 +v -5.81 2.71 -12.81 +v -6.45 2.63 -12.89 +v -5.90 2.71 -12.89 +v -5.90 2.71 -12.81 +v -6.45 2.63 -12.81 +v -6.99 2.71 -12.98 +v -6.99 2.96 -12.98 +v -6.81 2.92 -12.98 +v -6.45 5.22 -12.89 +v -6.81 4.66 -12.89 +v -5.90 2.96 -12.98 +v -5.90 2.71 -12.98 +v -6.09 2.94 -12.98 +v -6.45 2.63 -12.98 +v -6.45 2.88 -12.98 +v -6.09 4.66 -12.83 +v -6.09 2.94 -12.83 +v -5.90 4.82 -12.89 +v -5.90 4.82 -12.81 +v -6.99 2.71 -12.89 +v -6.99 2.71 -12.81 +v -6.09 4.66 -12.89 +v -6.81 2.92 -12.89 +v -6.09 2.94 -12.89 +v -6.45 2.88 -12.89 +v -5.90 2.96 -12.89 +v -5.90 2.96 -12.81 +v -6.99 2.96 -12.89 +v -6.99 2.96 -12.81 +v -7.09 2.96 -12.98 +v -7.09 2.71 -12.98 +v -5.81 2.71 -12.98 +v -5.81 2.96 -12.98 +v -4.17 10.56 -11.04 +v -3.81 11.12 -11.04 +v -3.81 8.77 -11.04 +v -4.17 8.82 -11.04 +v -4.45 8.86 -11.10 +v -4.45 8.61 -11.10 +v -4.45 8.61 -11.02 +v -4.45 8.86 -11.02 +v -3.81 11.53 -11.10 +v -4.36 10.72 -11.10 +v -4.36 10.72 -11.02 +v -3.81 11.53 -11.02 +v -3.17 8.61 -11.10 +v -3.17 8.86 -11.10 +v -3.17 8.86 -11.02 +v -3.17 8.61 -11.02 +v -3.81 8.52 -11.10 +v -3.27 8.61 -11.10 +v -3.27 8.61 -11.02 +v -3.81 8.52 -11.02 +v -4.36 8.61 -11.19 +v -4.36 8.86 -11.19 +v -4.17 8.82 -11.19 +v -3.81 11.12 -11.10 +v -4.17 10.56 -11.10 +v -3.27 8.86 -11.19 +v -3.27 8.61 -11.19 +v -3.45 8.83 -11.19 +v -3.81 8.52 -11.19 +v -3.81 8.77 -11.19 +v -3.45 10.56 -11.04 +v -3.45 8.83 -11.04 +v -3.27 10.72 -11.10 +v -3.27 10.72 -11.02 +v -4.36 8.61 -11.10 +v -4.36 8.61 -11.02 +v -3.45 10.56 -11.10 +v -4.17 8.82 -11.10 +v -3.45 8.83 -11.10 +v -3.81 8.77 -11.10 +v -3.27 8.86 -11.10 +v -3.27 8.86 -11.02 +v -4.36 8.86 -11.10 +v -4.36 8.86 -11.02 +v -4.45 8.86 -11.19 +v -4.45 8.61 -11.19 +v -3.17 8.61 -11.19 +v -3.17 8.86 -11.19 +v 3.09 10.56 -11.04 +v 3.44 11.12 -11.04 +v 3.44 8.77 -11.04 +v 3.09 8.82 -11.04 +v 2.81 8.86 -11.10 +v 2.81 8.61 -11.10 +v 2.81 8.61 -11.02 +v 2.81 8.86 -11.02 +v 3.44 11.53 -11.10 +v 2.90 10.72 -11.10 +v 2.90 10.72 -11.02 +v 3.44 11.53 -11.02 +v 4.08 8.61 -11.10 +v 4.08 8.86 -11.10 +v 4.08 8.86 -11.02 +v 4.08 8.61 -11.02 +v 3.44 8.52 -11.10 +v 3.99 8.61 -11.10 +v 3.99 8.61 -11.02 +v 3.44 8.52 -11.02 +v 2.90 8.61 -11.19 +v 2.90 8.86 -11.19 +v 3.09 8.82 -11.19 +v 3.44 11.12 -11.10 +v 3.09 10.56 -11.10 +v 3.99 8.86 -11.19 +v 3.99 8.61 -11.19 +v 3.80 8.83 -11.19 +v 3.44 8.52 -11.19 +v 3.44 8.77 -11.19 +v 3.80 10.56 -11.04 +v 3.80 8.83 -11.04 +v 3.99 10.72 -11.10 +v 3.99 10.72 -11.02 +v 2.90 8.61 -11.10 +v 2.90 8.61 -11.02 +v 3.80 10.56 -11.10 +v 3.09 8.82 -11.10 +v 3.80 8.83 -11.10 +v 3.44 8.77 -11.10 +v 3.99 8.86 -11.10 +v 3.99 8.86 -11.02 +v 2.90 8.86 -11.10 +v 2.90 8.86 -11.02 +v 2.81 8.86 -11.19 +v 2.81 8.61 -11.19 +v 4.08 8.61 -11.19 +v 4.08 8.86 -11.19 +v 5.72 4.66 -12.83 +v 6.08 5.22 -12.83 +v 6.08 2.88 -12.83 +v 5.72 2.92 -12.83 +v 5.44 2.96 -12.89 +v 5.44 2.71 -12.89 +v 5.44 2.71 -12.81 +v 5.44 2.96 -12.81 +v 6.08 5.63 -12.89 +v 5.54 4.82 -12.89 +v 5.54 4.82 -12.81 +v 6.08 5.63 -12.81 +v 6.72 2.71 -12.89 +v 6.72 2.96 -12.89 +v 6.72 2.96 -12.81 +v 6.72 2.71 -12.81 +v 6.08 2.63 -12.89 +v 6.63 2.71 -12.89 +v 6.63 2.71 -12.81 +v 6.08 2.63 -12.81 +v 5.54 2.71 -12.98 +v 5.54 2.96 -12.98 +v 5.72 2.92 -12.98 +v 6.08 5.22 -12.89 +v 5.72 4.66 -12.89 +v 6.63 2.96 -12.98 +v 6.63 2.71 -12.98 +v 6.44 2.94 -12.98 +v 6.08 2.63 -12.98 +v 6.08 2.88 -12.98 +v 6.44 4.66 -12.83 +v 6.44 2.94 -12.83 +v 6.63 4.82 -12.89 +v 6.63 4.82 -12.81 +v 5.54 2.71 -12.89 +v 5.54 2.71 -12.81 +v 6.44 4.66 -12.89 +v 5.72 2.92 -12.89 +v 6.44 2.94 -12.89 +v 6.08 2.88 -12.89 +v 6.63 2.96 -12.89 +v 6.63 2.96 -12.81 +v 5.54 2.96 -12.89 +v 5.54 2.96 -12.81 +v 5.44 2.96 -12.98 +v 5.44 2.71 -12.98 +v 6.72 2.71 -12.98 +v 6.72 2.96 -12.98 +v -6.30 20.76 -3.63 +v -5.94 21.32 -3.63 +v -5.94 18.98 -3.63 +v -6.30 19.02 -3.63 +v -6.58 19.06 -3.69 +v -6.58 18.81 -3.69 +v -6.58 18.81 -3.60 +v -6.58 19.06 -3.60 +v -5.94 21.73 -3.69 +v -6.49 20.92 -3.69 +v -6.49 20.92 -3.60 +v -5.94 21.73 -3.60 +v -5.30 18.81 -3.69 +v -5.30 19.06 -3.69 +v -5.30 19.06 -3.60 +v -5.30 18.81 -3.60 +v -5.94 18.73 -3.69 +v -5.40 18.81 -3.69 +v -5.40 18.81 -3.60 +v -5.94 18.73 -3.60 +v -6.49 18.81 -3.78 +v -6.49 19.06 -3.78 +v -6.30 19.02 -3.78 +v -5.94 21.32 -3.69 +v -6.30 20.76 -3.69 +v -5.40 19.06 -3.78 +v -5.40 18.81 -3.78 +v -5.58 19.04 -3.78 +v -5.94 18.73 -3.78 +v -5.94 18.98 -3.78 +v -5.58 20.76 -3.63 +v -5.58 19.04 -3.63 +v -5.40 20.92 -3.69 +v -5.40 20.92 -3.60 +v -6.49 18.81 -3.69 +v -6.49 18.81 -3.60 +v -5.58 20.76 -3.69 +v -6.30 19.02 -3.69 +v -5.58 19.04 -3.69 +v -5.94 18.98 -3.69 +v -5.40 19.06 -3.69 +v -5.40 19.06 -3.60 +v -6.49 19.06 -3.69 +v -6.49 19.06 -3.60 +v -6.58 19.06 -3.78 +v -6.58 18.81 -3.78 +v -5.30 18.81 -3.78 +v -5.30 19.06 -3.78 +v 5.89 20.76 -3.63 +v 6.25 21.32 -3.63 +v 6.25 18.98 -3.63 +v 5.89 19.02 -3.63 +v 5.61 19.06 -3.69 +v 5.61 18.81 -3.69 +v 5.61 18.81 -3.60 +v 5.61 19.06 -3.60 +v 6.25 21.73 -3.69 +v 5.70 20.92 -3.69 +v 5.70 20.92 -3.60 +v 6.25 21.73 -3.60 +v 6.89 18.81 -3.69 +v 6.89 19.06 -3.69 +v 6.89 19.06 -3.60 +v 6.89 18.81 -3.60 +v 6.25 18.73 -3.69 +v 6.79 18.81 -3.69 +v 6.79 18.81 -3.60 +v 6.25 18.73 -3.60 +v 5.70 18.81 -3.78 +v 5.70 19.06 -3.78 +v 5.89 19.02 -3.78 +v 6.25 21.32 -3.69 +v 5.89 20.76 -3.69 +v 6.79 19.06 -3.78 +v 6.79 18.81 -3.78 +v 6.61 19.04 -3.78 +v 6.25 18.73 -3.78 +v 6.25 18.98 -3.78 +v 6.61 20.76 -3.63 +v 6.61 19.04 -3.63 +v 6.79 20.92 -3.69 +v 6.79 20.92 -3.60 +v 5.70 18.81 -3.69 +v 5.70 18.81 -3.60 +v 6.61 20.76 -3.69 +v 5.89 19.02 -3.69 +v 6.61 19.04 -3.69 +v 6.25 18.98 -3.69 +v 6.79 19.06 -3.69 +v 6.79 19.06 -3.60 +v 5.70 19.06 -3.69 +v 5.70 19.06 -3.60 +v 5.61 19.06 -3.78 +v 5.61 18.81 -3.78 +v 6.89 18.81 -3.78 +v 6.89 19.06 -3.78 +v -8.76 20.76 0.36 +v -8.76 21.32 -0.00 +v -8.76 18.98 -0.00 +v -8.76 19.02 0.36 +v -8.82 19.06 0.64 +v -8.82 18.81 0.64 +v -8.74 18.81 0.64 +v -8.74 19.06 0.64 +v -8.82 21.73 -0.00 +v -8.82 20.92 0.55 +v -8.74 20.92 0.55 +v -8.74 21.73 -0.00 +v -8.82 18.81 -0.64 +v -8.82 19.06 -0.64 +v -8.74 19.06 -0.64 +v -8.74 18.81 -0.64 +v -8.82 18.73 -0.00 +v -8.82 18.81 -0.55 +v -8.74 18.81 -0.55 +v -8.74 18.73 -0.00 +v -8.91 18.81 0.55 +v -8.91 19.06 0.55 +v -8.91 19.02 0.36 +v -8.82 21.32 -0.00 +v -8.82 20.76 0.36 +v -8.91 19.06 -0.55 +v -8.91 18.81 -0.55 +v -8.91 19.04 -0.36 +v -8.91 18.73 -0.00 +v -8.91 18.98 -0.00 +v -8.76 20.76 -0.36 +v -8.76 19.04 -0.36 +v -8.82 20.92 -0.55 +v -8.74 20.92 -0.55 +v -8.82 18.81 0.55 +v -8.74 18.81 0.55 +v -8.82 20.76 -0.36 +v -8.82 19.02 0.36 +v -8.82 19.04 -0.36 +v -8.82 18.98 -0.00 +v -8.82 19.06 -0.55 +v -8.74 19.06 -0.55 +v -8.82 19.06 0.55 +v -8.74 19.06 0.55 +v -8.91 19.06 0.64 +v -8.91 18.81 0.64 +v -8.91 18.81 -0.64 +v -8.91 19.06 -0.64 +v -23.42 4.66 -0.35 +v -23.42 2.92 -0.35 +v -23.42 2.88 0.01 +v -23.42 5.22 0.01 +v -23.48 2.96 -0.63 +v -23.40 2.96 -0.63 +v -23.40 2.71 -0.63 +v -23.48 2.71 -0.63 +v -23.48 5.63 0.01 +v -23.40 5.63 0.01 +v -23.40 4.82 -0.54 +v -23.48 4.82 -0.54 +v -23.48 2.71 0.65 +v -23.40 2.71 0.65 +v -23.40 2.96 0.65 +v -23.48 2.96 0.65 +v -23.48 2.63 0.01 +v -23.40 2.63 0.01 +v -23.40 2.71 0.55 +v -23.48 2.71 0.55 +v -23.57 2.71 -0.54 +v -23.57 2.92 -0.35 +v -23.57 2.96 -0.54 +v -23.48 5.22 0.01 +v -23.48 4.66 -0.35 +v -23.57 2.96 0.55 +v -23.57 2.94 0.37 +v -23.57 2.71 0.55 +v -23.57 2.63 0.01 +v -23.57 2.88 0.01 +v -23.42 4.66 0.37 +v -23.42 2.94 0.37 +v -23.48 4.82 0.55 +v -23.40 4.82 0.55 +v -23.48 2.71 -0.54 +v -23.40 2.71 -0.54 +v -23.48 4.66 0.37 +v -23.48 2.92 -0.35 +v -23.48 2.94 0.37 +v -23.48 2.88 0.01 +v -23.48 2.96 0.55 +v -23.40 2.96 0.55 +v -23.40 2.96 -0.54 +v -23.48 2.96 -0.54 +v -23.57 2.71 -0.63 +v -23.57 2.96 -0.63 +v -23.57 2.96 0.65 +v -23.57 2.71 0.65 +v -19.96 4.66 6.78 +v -19.96 2.92 6.78 +v -19.60 2.88 6.78 +v -19.60 5.22 6.78 +v -20.24 2.96 6.85 +v -20.24 2.96 6.76 +v -20.24 2.71 6.76 +v -20.24 2.71 6.85 +v -19.60 5.63 6.85 +v -19.60 5.63 6.76 +v -20.15 4.82 6.76 +v -20.15 4.82 6.85 +v -18.96 2.71 6.85 +v -18.96 2.71 6.76 +v -18.96 2.96 6.76 +v -18.96 2.96 6.85 +v -19.60 2.63 6.85 +v -19.60 2.63 6.76 +v -19.05 2.71 6.76 +v -19.05 2.71 6.85 +v -20.15 2.71 6.94 +v -19.96 2.92 6.94 +v -20.15 2.96 6.94 +v -19.60 5.22 6.85 +v -19.96 4.66 6.85 +v -19.05 2.96 6.94 +v -19.24 2.94 6.94 +v -19.05 2.71 6.94 +v -19.60 2.63 6.94 +v -19.60 2.88 6.94 +v -19.24 4.66 6.78 +v -19.24 2.94 6.78 +v -19.05 4.82 6.85 +v -19.05 4.82 6.76 +v -20.15 2.71 6.85 +v -20.15 2.71 6.76 +v -19.24 4.66 6.85 +v -19.96 2.92 6.85 +v -19.24 2.94 6.85 +v -19.60 2.88 6.85 +v -19.05 2.96 6.85 +v -19.05 2.96 6.76 +v -20.15 2.96 6.76 +v -20.15 2.96 6.85 +v -20.24 2.71 6.94 +v -20.24 2.96 6.94 +v -18.96 2.96 6.94 +v -18.96 2.71 6.94 +v -5.42 9.62 11.04 +v -5.42 7.88 11.04 +v -5.06 7.83 11.04 +v -5.06 10.18 11.04 +v -5.70 7.92 11.10 +v -5.70 7.92 11.01 +v -5.70 7.67 11.01 +v -5.70 7.67 11.10 +v -5.06 10.59 11.10 +v -5.06 10.59 11.01 +v -5.61 9.78 11.01 +v -5.61 9.78 11.10 +v -4.43 7.67 11.10 +v -4.43 7.67 11.01 +v -4.43 7.92 11.01 +v -4.43 7.92 11.10 +v -5.06 7.58 11.10 +v -5.06 7.58 11.01 +v -4.52 7.67 11.01 +v -4.52 7.67 11.10 +v -5.61 7.67 11.19 +v -5.42 7.88 11.19 +v -5.61 7.92 11.19 +v -5.06 10.18 11.10 +v -5.42 9.62 11.10 +v -4.52 7.92 11.19 +v -4.71 7.89 11.19 +v -4.52 7.67 11.19 +v -5.06 7.58 11.19 +v -5.06 7.83 11.19 +v -4.71 9.62 11.04 +v -4.71 7.89 11.04 +v -4.52 9.78 11.10 +v -4.52 9.78 11.01 +v -5.61 7.67 11.10 +v -5.61 7.67 11.01 +v -4.71 9.62 11.10 +v -5.42 7.88 11.10 +v -4.71 7.89 11.10 +v -5.06 7.83 11.10 +v -4.52 7.92 11.10 +v -4.52 7.92 11.01 +v -5.61 7.92 11.01 +v -5.61 7.92 11.10 +v -5.70 7.67 11.19 +v -5.70 7.92 11.19 +v -4.43 7.92 11.19 +v -4.43 7.67 11.19 +v 3.43 9.62 11.04 +v 3.43 7.88 11.04 +v 3.79 7.83 11.04 +v 3.79 10.18 11.04 +v 3.15 7.92 11.10 +v 3.15 7.92 11.01 +v 3.15 7.67 11.01 +v 3.15 7.67 11.10 +v 3.79 10.59 11.10 +v 3.79 10.59 11.01 +v 3.24 9.78 11.01 +v 3.24 9.78 11.10 +v 4.43 7.67 11.10 +v 4.43 7.67 11.01 +v 4.43 7.92 11.01 +v 4.43 7.92 11.10 +v 3.79 7.58 11.10 +v 3.79 7.58 11.01 +v 4.33 7.67 11.01 +v 4.33 7.67 11.10 +v 3.24 7.67 11.19 +v 3.43 7.88 11.19 +v 3.24 7.92 11.19 +v 3.79 10.18 11.10 +v 3.43 9.62 11.10 +v 4.33 7.92 11.19 +v 4.15 7.89 11.19 +v 4.33 7.67 11.19 +v 3.79 7.58 11.19 +v 3.79 7.83 11.19 +v 4.15 9.62 11.04 +v 4.15 7.89 11.04 +v 4.33 9.78 11.10 +v 4.33 9.78 11.01 +v 3.24 7.67 11.10 +v 3.24 7.67 11.01 +v 4.15 9.62 11.10 +v 3.43 7.88 11.10 +v 4.15 7.89 11.10 +v 3.79 7.83 11.10 +v 4.33 7.92 11.10 +v 4.33 7.92 11.01 +v 3.24 7.92 11.01 +v 3.24 7.92 11.10 +v 3.15 7.67 11.19 +v 3.15 7.92 11.19 +v 4.43 7.92 11.19 +v 4.43 7.67 11.19 +v -0.84 4.66 11.04 +v -0.84 2.92 11.04 +v -0.48 2.88 11.04 +v -0.48 5.22 11.04 +v -1.12 2.96 11.10 +v -1.12 2.96 11.01 +v -1.12 2.71 11.01 +v -1.12 2.71 11.10 +v -0.48 5.63 11.10 +v -0.48 5.63 11.01 +v -1.03 4.82 11.01 +v -1.03 4.82 11.10 +v 0.15 2.71 11.10 +v 0.15 2.71 11.01 +v 0.15 2.96 11.01 +v 0.15 2.96 11.10 +v -0.48 2.63 11.10 +v -0.48 2.63 11.01 +v 0.06 2.71 11.01 +v 0.06 2.71 11.10 +v -1.03 2.71 11.19 +v -0.84 2.92 11.19 +v -1.03 2.96 11.19 +v -0.48 5.22 11.10 +v -0.84 4.66 11.10 +v 0.06 2.96 11.19 +v -0.13 2.94 11.19 +v 0.06 2.71 11.19 +v -0.48 2.63 11.19 +v -0.48 2.88 11.19 +v -0.13 4.66 11.04 +v -0.13 2.94 11.04 +v 0.06 4.82 11.10 +v 0.06 4.82 11.01 +v -1.03 2.71 11.10 +v -1.03 2.71 11.01 +v -0.13 4.66 11.10 +v -0.84 2.92 11.10 +v -0.13 2.94 11.10 +v -0.48 2.88 11.10 +v 0.06 2.96 11.10 +v 0.06 2.96 11.01 +v -1.03 2.96 11.01 +v -1.03 2.96 11.10 +v -1.12 2.71 11.19 +v -1.12 2.96 11.19 +v 0.15 2.96 11.19 +v 0.15 2.71 11.19 +v 0.43 20.76 3.64 +v 0.07 21.32 3.64 +v 0.07 18.98 3.64 +v 0.43 19.02 3.64 +v 0.71 19.06 3.70 +v 0.71 18.81 3.70 +v 0.71 18.81 3.61 +v 0.71 19.06 3.61 +v 0.07 21.73 3.70 +v 0.62 20.92 3.70 +v 0.62 20.92 3.61 +v 0.07 21.73 3.61 +v -0.57 18.81 3.70 +v -0.57 19.06 3.70 +v -0.57 19.06 3.61 +v -0.57 18.81 3.61 +v 0.07 18.73 3.70 +v -0.47 18.81 3.70 +v -0.47 18.81 3.61 +v 0.07 18.73 3.61 +v 0.62 18.81 3.79 +v 0.62 19.06 3.79 +v 0.43 19.02 3.79 +v 0.07 21.32 3.70 +v 0.43 20.76 3.70 +v -0.47 19.06 3.79 +v -0.47 18.81 3.79 +v -0.29 19.04 3.79 +v 0.07 18.73 3.79 +v 0.07 18.98 3.79 +v -0.29 20.76 3.64 +v -0.29 19.04 3.64 +v -0.47 20.92 3.70 +v -0.47 20.92 3.61 +v 0.62 18.81 3.70 +v 0.62 18.81 3.61 +v -0.29 20.76 3.70 +v 0.43 19.02 3.70 +v -0.29 19.04 3.70 +v 0.07 18.98 3.70 +v -0.47 19.06 3.70 +v -0.47 19.06 3.61 +v 0.62 19.06 3.70 +v 0.62 19.06 3.61 +v 0.71 19.06 3.79 +v 0.71 18.81 3.79 +v -0.57 18.81 3.79 +v -0.57 19.06 3.79 +v 6.58 20.76 3.64 +v 6.22 21.32 3.64 +v 6.22 18.98 3.64 +v 6.58 19.02 3.64 +v 6.86 19.06 3.70 +v 6.86 18.81 3.70 +v 6.86 18.81 3.61 +v 6.86 19.06 3.61 +v 6.22 21.73 3.70 +v 6.76 20.92 3.70 +v 6.76 20.92 3.61 +v 6.22 21.73 3.61 +v 5.58 18.81 3.70 +v 5.58 19.06 3.70 +v 5.58 19.06 3.61 +v 5.58 18.81 3.61 +v 6.22 18.73 3.70 +v 5.67 18.81 3.70 +v 5.67 18.81 3.61 +v 6.22 18.73 3.61 +v 6.76 18.81 3.79 +v 6.76 19.06 3.79 +v 6.58 19.02 3.79 +v 6.22 21.32 3.70 +v 6.58 20.76 3.70 +v 5.67 19.06 3.79 +v 5.67 18.81 3.79 +v 5.86 19.04 3.79 +v 6.22 18.73 3.79 +v 6.22 18.98 3.79 +v 5.86 20.76 3.64 +v 5.86 19.04 3.64 +v 5.67 20.92 3.70 +v 5.67 20.92 3.61 +v 6.76 18.81 3.70 +v 6.76 18.81 3.61 +v 5.86 20.76 3.70 +v 6.58 19.02 3.70 +v 5.86 19.04 3.70 +v 6.22 18.98 3.70 +v 5.67 19.06 3.70 +v 5.67 19.06 3.61 +v 6.76 19.06 3.70 +v 6.76 19.06 3.61 +v 6.86 19.06 3.79 +v 6.86 18.81 3.79 +v 5.58 18.81 3.79 +v 5.58 19.06 3.79 +v 12.89 4.66 -3.98 +v 12.89 5.22 -3.62 +v 12.89 2.88 -3.62 +v 12.89 2.92 -3.98 +v 12.96 2.96 -4.26 +v 12.96 2.71 -4.26 +v 12.87 2.71 -4.26 +v 12.87 2.96 -4.26 +v 12.96 5.63 -3.62 +v 12.96 4.82 -4.17 +v 12.87 4.82 -4.17 +v 12.87 5.63 -3.62 +v 12.96 2.71 -2.98 +v 12.96 2.96 -2.98 +v 12.87 2.96 -2.98 +v 12.87 2.71 -2.98 +v 12.96 2.63 -3.62 +v 12.96 2.71 -3.08 +v 12.87 2.71 -3.08 +v 12.87 2.63 -3.62 +v 13.05 2.71 -4.17 +v 13.05 2.96 -4.17 +v 13.05 2.92 -3.98 +v 12.96 5.22 -3.62 +v 12.96 4.66 -3.98 +v 13.05 2.96 -3.08 +v 13.05 2.71 -3.08 +v 13.05 2.94 -3.26 +v 13.05 2.63 -3.62 +v 13.05 2.88 -3.62 +v 12.89 4.66 -3.26 +v 12.89 2.94 -3.26 +v 12.96 4.82 -3.08 +v 12.87 4.82 -3.08 +v 12.96 2.71 -4.17 +v 12.87 2.71 -4.17 +v 12.96 4.66 -3.26 +v 12.96 2.92 -3.98 +v 12.96 2.94 -3.26 +v 12.96 2.88 -3.62 +v 12.96 2.96 -3.08 +v 12.87 2.96 -3.08 +v 12.96 2.96 -4.17 +v 12.87 2.96 -4.17 +v 13.05 2.96 -4.26 +v 13.05 2.71 -4.26 +v 13.05 2.71 -2.98 +v 13.05 2.96 -2.98 +v 12.89 4.66 3.26 +v 12.89 5.22 3.62 +v 12.89 2.88 3.62 +v 12.89 2.92 3.26 +v 12.96 2.96 2.98 +v 12.96 2.71 2.98 +v 12.87 2.71 2.98 +v 12.87 2.96 2.98 +v 12.96 5.63 3.62 +v 12.96 4.82 3.08 +v 12.87 4.82 3.08 +v 12.87 5.63 3.62 +v 12.96 2.71 4.26 +v 12.96 2.96 4.26 +v 12.87 2.96 4.26 +v 12.87 2.71 4.26 +v 12.96 2.63 3.62 +v 12.96 2.71 4.17 +v 12.87 2.71 4.17 +v 12.87 2.63 3.62 +v 13.05 2.71 3.08 +v 13.05 2.96 3.08 +v 13.05 2.92 3.26 +v 12.96 5.22 3.62 +v 12.96 4.66 3.26 +v 13.05 2.96 4.17 +v 13.05 2.71 4.17 +v 13.05 2.94 3.98 +v 13.05 2.63 3.62 +v 13.05 2.88 3.62 +v 12.89 4.66 3.98 +v 12.89 2.94 3.98 +v 12.96 4.82 4.17 +v 12.87 4.82 4.17 +v 12.96 2.71 3.08 +v 12.87 2.71 3.08 +v 12.96 4.66 3.98 +v 12.96 2.92 3.26 +v 12.96 2.94 3.98 +v 12.96 2.88 3.62 +v 12.96 2.96 4.17 +v 12.87 2.96 4.17 +v 12.96 2.96 3.08 +v 12.87 2.96 3.08 +v 13.05 2.96 2.98 +v 13.05 2.71 2.98 +v 13.05 2.71 4.26 +v 13.05 2.96 4.26 +v 8.75 20.76 0.36 +v 8.75 19.02 0.36 +v 8.75 18.98 -0.00 +v 8.75 21.32 -0.00 +v 8.81 19.06 0.64 +v 8.73 19.06 0.64 +v 8.73 18.81 0.64 +v 8.81 18.81 0.64 +v 8.81 21.73 -0.00 +v 8.73 21.73 -0.00 +v 8.73 20.92 0.55 +v 8.81 20.92 0.55 +v 8.81 18.81 -0.64 +v 8.73 18.81 -0.64 +v 8.73 19.06 -0.64 +v 8.81 19.06 -0.64 +v 8.81 18.73 -0.00 +v 8.73 18.73 -0.00 +v 8.73 18.81 -0.55 +v 8.81 18.81 -0.55 +v 8.90 18.81 0.55 +v 8.90 19.02 0.36 +v 8.90 19.06 0.55 +v 8.81 21.32 -0.00 +v 8.81 20.76 0.36 +v 8.90 19.06 -0.55 +v 8.90 19.04 -0.36 +v 8.90 18.81 -0.55 +v 8.90 18.73 -0.00 +v 8.90 18.98 -0.00 +v 8.75 20.76 -0.36 +v 8.75 19.04 -0.36 +v 8.81 20.92 -0.55 +v 8.73 20.92 -0.55 +v 8.81 18.81 0.55 +v 8.73 18.81 0.55 +v 8.81 20.76 -0.36 +v 8.81 19.02 0.36 +v 8.81 19.04 -0.36 +v 8.81 18.98 -0.00 +v 8.81 19.06 -0.55 +v 8.73 19.06 -0.55 +v 8.73 19.06 0.55 +v 8.81 19.06 0.55 +v 8.90 18.81 0.64 +v 8.90 19.06 0.64 +v 8.90 19.06 -0.64 +v 8.90 18.81 -0.64 +v -5.91 20.76 3.64 +v -6.27 21.32 3.64 +v -6.27 18.98 3.64 +v -5.91 19.02 3.64 +v -5.63 19.06 3.70 +v -5.63 18.81 3.70 +v -5.63 18.81 3.61 +v -5.63 19.06 3.61 +v -6.27 21.73 3.70 +v -5.73 20.92 3.70 +v -5.73 20.92 3.61 +v -6.27 21.73 3.61 +v -6.91 18.81 3.70 +v -6.91 19.06 3.70 +v -6.91 19.06 3.61 +v -6.91 18.81 3.61 +v -6.27 18.73 3.70 +v -6.82 18.81 3.70 +v -6.82 18.81 3.61 +v -6.27 18.73 3.61 +v -5.73 18.81 3.79 +v -5.73 19.06 3.79 +v -5.91 19.02 3.79 +v -6.27 21.32 3.70 +v -5.91 20.76 3.70 +v -6.82 19.06 3.79 +v -6.82 18.81 3.79 +v -6.63 19.04 3.79 +v -6.27 18.73 3.79 +v -6.27 18.98 3.79 +v -6.63 20.76 3.64 +v -6.63 19.04 3.64 +v -6.82 20.92 3.70 +v -6.82 20.92 3.61 +v -5.73 18.81 3.70 +v -5.73 18.81 3.61 +v -6.63 20.76 3.70 +v -5.91 19.02 3.70 +v -6.63 19.04 3.70 +v -6.27 18.98 3.70 +v -6.82 19.06 3.70 +v -6.82 19.06 3.61 +v -5.73 19.06 3.70 +v -5.73 19.06 3.61 +v -5.63 19.06 3.79 +v -5.63 18.81 3.79 +v -6.91 18.81 3.79 +v -6.91 19.06 3.79 +v 1.22 3.89 -13.04 +v 1.22 0.00 -13.04 +v 0.00 0.00 -13.04 +v 0.00 4.45 -13.04 +v -2.44 3.02 -13.04 +v -1.22 3.89 -13.04 +v -1.22 0.00 -13.04 +v -2.44 0.00 -13.04 +v 2.44 3.02 -13.04 +v 2.44 0.00 -13.04 +v 2.76 0.00 -12.61 +v 2.76 0.00 -13.28 +v 2.72 2.63 -13.28 +v 2.72 2.63 -12.61 +v 2.32 0.00 -13.28 +v 2.28 2.21 -13.28 +v 2.32 0.00 -12.61 +v 2.28 2.21 -12.61 +v 1.57 4.51 -13.28 +v 1.57 4.51 -12.61 +v 1.32 3.79 -13.28 +v 1.32 3.79 -12.61 +v 0.00 5.20 -13.28 +v 0.00 5.20 -12.61 +v 0.00 4.45 -13.28 +v 0.00 4.45 -12.61 +v -1.57 4.51 -13.28 +v -1.57 4.51 -12.61 +v -1.32 3.79 -13.28 +v -1.32 3.79 -12.61 +v -2.72 2.63 -13.28 +v -2.72 2.63 -12.61 +v -2.28 2.21 -13.28 +v -2.28 2.21 -12.61 +v -2.76 0.00 -13.28 +v -2.76 0.00 -12.61 +v -2.32 0.00 -13.28 +v -2.32 0.00 -12.61 +v -23.02 0.02 -7.19 +v -23.81 0.02 -7.26 +v -23.50 3.76 -6.94 +v -22.95 3.76 -6.89 +v -23.10 0.02 -6.35 +v -23.01 3.76 -6.25 +v -23.88 0.02 -6.42 +v -23.56 3.76 -6.30 +v -23.00 6.77 -7.20 +v -23.83 6.77 -7.27 +v -23.08 7.23 -6.33 +v -23.90 7.23 -6.41 +v -23.14 6.61 -6.66 +v -23.14 6.39 0.01 +v -23.82 6.39 0.01 +v -23.82 6.61 -6.66 +v -23.82 7.03 0.01 +v -23.82 7.24 -6.66 +v -23.14 7.03 0.01 +v -23.14 7.24 -6.66 +v -23.14 6.61 6.68 +v -23.82 6.61 6.68 +v -23.82 7.24 6.68 +v -23.14 7.24 6.68 +v -10.64 6.61 -6.65 +v -17.31 6.39 -6.65 +v -17.31 6.39 -7.33 +v -10.64 6.61 -7.33 +v -17.31 7.03 -7.33 +v -10.64 7.24 -7.33 +v -17.31 7.03 -6.65 +v -10.64 7.24 -6.65 +v -23.99 6.61 -6.65 +v -23.99 6.61 -7.33 +v -23.99 7.24 -7.33 +v -23.99 7.24 -6.65 +v -23.02 0.02 7.20 +v -22.95 3.76 6.91 +v -23.50 3.76 6.95 +v -23.81 0.02 7.27 +v -23.10 0.02 6.37 +v -23.01 3.76 6.27 +v -23.88 0.02 6.44 +v -23.56 3.76 6.32 +v -23.00 6.77 7.22 +v -23.83 6.77 7.29 +v -23.08 7.23 6.35 +v -23.90 7.23 6.42 +v -10.64 6.61 6.68 +v -10.64 6.61 7.36 +v -17.31 6.39 7.36 +v -17.31 6.39 6.68 +v -10.64 7.24 7.36 +v -17.31 7.03 7.36 +v -10.64 7.24 6.68 +v -17.31 7.03 6.68 +v -23.99 6.61 7.36 +v -23.99 6.61 6.68 +v -23.99 7.24 7.36 +v -23.99 7.24 6.68 +v 8.74 6.44 10.70 +v 8.74 6.44 11.59 +v 0.00 6.16 11.59 +v 0.00 6.16 10.70 +v 8.74 7.27 11.59 +v 0.00 6.98 11.59 +v 8.74 7.27 10.70 +v 0.00 6.98 10.70 +v -8.74 6.44 11.59 +v -8.74 6.44 10.70 +v -8.74 7.27 11.59 +v -8.74 7.27 10.70 +v 8.74 17.79 -0.00 +v 8.74 27.72 -0.00 +v 8.74 23.62 3.62 +v 0.00 17.79 -3.62 +v 0.00 23.02 -3.62 +v 8.74 23.62 -3.62 +v -8.74 17.79 -0.00 +v -8.74 27.60 -0.00 +v -8.74 23.62 -3.62 +v 0.00 17.79 3.62 +v 0.00 23.02 3.62 +v -8.74 23.62 3.62 +v 8.34 17.58 -3.11 +v 8.50 20.48 -3.15 +v 8.50 20.48 -3.73 +v 8.34 17.58 -3.92 +v 8.34 24.35 -3.11 +v 8.34 23.76 -3.83 +v 9.14 17.58 -3.11 +v 9.09 20.48 -3.15 +v 9.14 24.35 -3.11 +v 9.14 17.58 -3.92 +v 9.09 20.48 -3.73 +v 9.14 23.76 -3.83 +v -0.81 20.18 -3.56 +v -0.81 17.74 -3.56 +v -0.81 17.74 -3.74 +v -0.81 20.18 -3.74 +v -0.95 20.13 -3.74 +v -0.95 17.74 -3.74 +v -0.95 17.74 -3.56 +v -0.95 20.13 -3.56 +v -1.04 20.10 -3.76 +v -1.04 20.10 -3.58 +v -1.04 20.32 -3.58 +v -1.04 20.32 -3.76 +v 1.04 20.32 -3.58 +v 1.04 20.10 -3.58 +v 1.04 20.10 -3.76 +v 1.04 20.32 -3.76 +v -0.39 20.29 -3.76 +v -0.39 20.29 -3.58 +v -0.39 20.51 -3.76 +v -0.39 20.51 -3.58 +v 0.94 20.15 -3.56 +v 0.94 17.74 -3.56 +v 0.94 17.74 -3.74 +v 0.94 20.15 -3.74 +v 0.80 17.74 -3.74 +v 0.80 20.19 -3.74 +v 0.80 17.74 -3.56 +v 0.80 20.19 -3.56 +v 0.39 20.29 -3.76 +v 0.39 20.29 -3.58 +v 0.39 20.51 -3.76 +v 0.39 20.51 -3.58 +v 0.00 20.34 -3.76 +v 0.00 20.34 -3.58 +v 0.00 20.56 -3.76 +v 0.00 20.56 -3.58 +v -0.01 17.69 -4.00 +v 0.78 17.69 -4.00 +v 0.78 17.66 -3.95 +v -0.01 17.66 -3.95 +v -0.01 17.76 -4.01 +v 0.78 17.76 -4.01 +v 0.78 17.75 -3.95 +v 0.78 17.85 -3.95 +v 0.78 17.85 -3.64 +v 0.78 17.75 -3.64 +v 0.78 17.82 -4.00 +v 0.78 17.66 -3.64 +v -0.01 17.85 -3.95 +v -0.01 17.85 -3.64 +v -0.01 17.82 -4.00 +v -0.80 17.66 -3.95 +v -0.80 17.69 -4.00 +v -0.80 17.76 -4.01 +v -0.80 17.85 -3.64 +v -0.80 17.85 -3.95 +v -0.80 17.75 -3.95 +v -0.80 17.75 -3.64 +v -0.80 17.82 -4.00 +v -0.80 17.66 -3.64 +v 0.86 20.19 -3.66 +v 0.86 17.72 -3.66 +v 0.02 17.72 -3.66 +v 0.02 20.45 -3.66 +v -0.82 20.19 -3.66 +v -0.82 17.72 -3.66 +v -9.14 17.58 -3.11 +v -8.97 20.48 -3.15 +v -8.97 20.48 -3.73 +v -9.14 17.58 -3.92 +v -9.14 24.35 -3.11 +v -9.14 23.76 -3.83 +v -8.34 17.58 -3.11 +v -8.39 20.48 -3.15 +v -8.34 24.35 -3.11 +v -8.34 17.58 -3.92 +v -8.39 20.48 -3.73 +v -8.34 23.76 -3.83 +v -9.14 17.58 3.11 +v -9.14 17.58 3.92 +v -8.97 20.48 3.73 +v -8.97 20.48 3.15 +v -9.14 23.76 3.83 +v -9.14 24.35 3.11 +v -8.34 17.58 3.11 +v -8.39 20.48 3.15 +v -8.34 24.35 3.11 +v -8.39 20.48 3.73 +v -8.34 17.58 3.92 +v -8.34 23.76 3.83 +v 8.34 17.58 3.11 +v 8.34 17.58 3.92 +v 8.50 20.48 3.73 +v 8.50 20.48 3.15 +v 8.34 23.76 3.83 +v 8.34 24.35 3.11 +v 9.14 17.58 3.11 +v 9.09 20.48 3.15 +v 9.14 24.35 3.11 +v 9.09 20.48 3.73 +v 9.14 17.58 3.92 +v 9.14 23.76 3.83 +v 12.59 6.44 -8.74 +v 13.48 6.44 -8.74 +v 13.48 6.16 -0.00 +v 12.59 6.16 -0.00 +v 13.48 7.27 -8.74 +v 13.48 6.98 -0.00 +v 12.59 7.27 -8.74 +v 12.59 6.98 -0.00 +v 13.48 6.44 8.74 +v 12.59 6.44 8.74 +v 13.48 7.27 8.74 +v 12.59 7.27 8.74 +v -9.92 18.64 4.67 +v -10.78 18.64 4.67 +v -10.78 18.64 6.66 +v -9.92 18.64 6.66 +v -9.92 17.79 4.67 +v -10.78 17.79 4.67 +v -10.78 17.79 6.66 +v -9.92 17.79 6.66 +v -12.40 7.80 6.90 +v -12.40 7.80 6.03 +v -14.38 7.80 6.03 +v -14.38 7.80 6.90 +v -12.40 6.95 6.90 +v -12.40 6.95 6.03 +v -14.38 6.95 6.03 +v -14.38 6.95 6.90 +v -12.40 7.80 -5.99 +v -12.40 7.80 -6.86 +v -14.38 7.80 -6.86 +v -14.38 7.80 -5.99 +v -12.40 6.95 -5.99 +v -12.40 6.95 -6.86 +v -14.38 6.95 -6.86 +v -14.38 6.95 -5.99 +v -16.55 0.00 12.98 +v -16.55 7.76 12.98 +v -17.17 7.76 10.68 +v -17.17 0.00 10.68 +v -14.87 0.00 14.66 +v -14.87 7.76 14.66 +v -12.57 0.00 15.28 +v -12.57 7.76 15.28 +v -10.27 0.00 14.66 +v -10.27 7.76 14.66 +v -8.58 0.00 12.98 +v -8.58 7.76 12.98 +v -7.97 0.00 10.68 +v -7.97 7.76 10.68 +v -8.58 0.00 8.38 +v -8.58 7.76 8.38 +v -10.27 0.00 6.69 +v -10.27 7.76 6.69 +v -12.57 0.00 6.08 +v -12.57 7.76 6.08 +v -14.87 0.00 6.69 +v -14.87 7.76 6.69 +v -16.55 0.00 8.38 +v -16.55 7.76 8.38 +v -16.78 7.76 13.11 +v -16.78 8.57 13.11 +v -17.43 8.57 10.68 +v -17.43 7.76 10.68 +v -15.00 7.76 14.89 +v -15.00 8.57 14.89 +v -12.57 7.76 15.54 +v -12.57 8.57 15.54 +v -10.13 7.76 14.89 +v -10.13 8.57 14.89 +v -8.35 7.76 13.11 +v -8.35 8.57 13.11 +v -7.70 7.76 10.68 +v -7.70 8.57 10.68 +v -8.35 7.76 8.24 +v -8.35 8.57 8.24 +v -10.13 7.76 6.46 +v -10.13 8.57 6.46 +v -12.57 7.76 5.81 +v -12.57 8.57 5.81 +v -15.00 7.76 6.46 +v -15.00 8.57 6.46 +v -16.78 7.76 8.24 +v -16.78 8.57 8.24 +v -17.17 8.57 10.68 +v -16.55 8.57 12.98 +v -14.87 8.57 14.66 +v -12.57 8.57 15.28 +v -10.27 8.57 14.66 +v -8.58 8.57 12.98 +v -7.97 8.57 10.68 +v -8.58 8.57 8.38 +v -10.27 8.57 6.69 +v -12.57 8.57 6.08 +v -14.87 8.57 6.69 +v -16.55 8.57 8.38 +v -16.55 16.89 12.98 +v -17.17 16.89 10.68 +v -14.87 16.89 14.66 +v -12.57 16.89 15.28 +v -10.27 16.89 14.66 +v -8.58 16.89 12.98 +v -7.97 16.89 10.68 +v -8.58 16.89 8.38 +v -10.27 16.89 6.69 +v -12.57 16.89 6.08 +v -14.87 16.89 6.69 +v -16.55 16.89 8.38 +v -17.13 21.30 13.31 +v -17.47 21.30 13.51 +v -18.23 21.30 10.68 +v -17.83 21.30 10.68 +v -15.20 21.30 15.24 +v -15.40 21.30 15.58 +v -12.57 21.30 15.94 +v -12.57 21.30 16.34 +v -9.93 21.30 15.24 +v -9.73 21.30 15.58 +v -8.01 21.30 13.31 +v -7.66 21.30 13.51 +v -7.30 21.30 10.68 +v -6.90 21.30 10.68 +v -8.01 21.30 8.04 +v -7.66 21.30 7.84 +v -9.93 21.30 6.12 +v -9.73 21.30 5.77 +v -12.57 21.30 5.41 +v -12.57 21.30 5.01 +v -15.20 21.30 6.12 +v -15.40 21.30 5.77 +v -17.13 21.30 8.04 +v -17.47 21.30 7.84 +v -16.17 24.76 12.76 +v -16.72 24.76 10.68 +v -14.64 24.76 14.28 +v -12.57 24.76 14.83 +v -10.49 24.76 14.28 +v -8.97 24.76 12.76 +v -8.41 24.76 10.68 +v -8.97 24.76 8.60 +v -10.49 24.76 7.08 +v -12.57 24.76 6.52 +v -14.64 24.76 7.08 +v -16.17 24.76 8.60 +v -16.13 28.50 12.74 +v -16.69 28.50 10.68 +v -14.63 28.50 14.24 +v -12.57 28.50 14.80 +v -10.51 28.50 14.24 +v -9.00 28.50 12.74 +v -8.45 28.50 10.68 +v -9.00 28.50 8.62 +v -10.51 28.50 7.11 +v -12.57 28.50 6.56 +v -14.63 28.50 7.11 +v -16.13 28.50 8.62 +v -17.13 17.36 13.31 +v -17.83 17.36 10.68 +v -15.20 17.36 15.24 +v -12.57 17.36 15.94 +v -9.93 17.36 15.24 +v -8.01 17.36 13.31 +v -7.30 17.36 10.68 +v -8.01 17.36 8.04 +v -9.93 17.36 6.12 +v -12.57 17.36 5.41 +v -15.20 17.36 6.12 +v -17.13 17.36 8.04 +v -17.91 20.21 10.37 +v -17.91 19.23 10.37 +v -17.91 19.21 10.80 +v -17.91 20.52 10.80 +v -17.81 19.26 10.03 +v -17.81 19.12 10.03 +v -17.91 19.12 10.04 +v -17.91 19.26 10.04 +v -17.89 20.75 10.80 +v -17.84 20.29 10.15 +v -17.94 20.29 10.15 +v -17.98 20.75 10.81 +v -17.68 19.12 11.55 +v -17.68 19.26 11.55 +v -17.78 19.26 11.56 +v -17.78 19.12 11.56 +v -17.89 19.07 10.80 +v -17.73 19.12 11.45 +v -17.82 19.12 11.45 +v -17.98 19.07 10.81 +v -18.05 19.12 10.16 +v -18.08 19.23 10.39 +v -18.05 19.26 10.16 +v -17.98 20.21 10.38 +v -17.98 20.52 10.81 +v -17.93 19.26 11.46 +v -18.01 19.24 11.24 +v -17.93 19.12 11.46 +v -18.09 19.07 10.82 +v -18.09 19.21 10.82 +v -17.83 20.21 11.23 +v -17.83 19.24 11.23 +v -17.73 20.29 11.45 +v -17.82 20.29 11.45 +v -17.84 19.12 10.15 +v -17.94 19.12 10.15 +v -17.90 20.21 11.23 +v -17.98 19.23 10.38 +v -17.90 19.24 11.23 +v -17.98 19.21 10.81 +v -17.82 19.26 11.45 +v -17.73 19.26 11.45 +v -17.84 19.26 10.15 +v -17.94 19.26 10.15 +v -18.02 19.12 10.05 +v -18.02 19.26 10.05 +v -17.88 19.26 11.57 +v -17.88 19.12 11.57 +v -12.87 20.21 16.02 +v -12.87 19.23 16.02 +v -12.44 19.21 16.02 +v -12.44 20.52 16.02 +v -13.21 19.26 15.92 +v -13.21 19.12 15.92 +v -13.20 19.12 16.02 +v -13.20 19.26 16.02 +v -12.44 20.75 16.00 +v -13.10 20.29 15.95 +v -13.09 20.29 16.05 +v -12.43 20.75 16.10 +v -11.69 19.12 15.79 +v -11.69 19.26 15.79 +v -11.68 19.26 15.89 +v -11.68 19.12 15.89 +v -12.44 19.07 16.00 +v -11.80 19.12 15.84 +v -11.79 19.12 15.94 +v -12.43 19.07 16.10 +v -13.08 19.12 16.16 +v -12.85 19.23 16.20 +v -13.08 19.26 16.16 +v -12.86 20.21 16.09 +v -12.43 20.52 16.10 +v -11.78 19.26 16.04 +v -12.00 19.24 16.12 +v -11.78 19.12 16.04 +v -12.42 19.07 16.20 +v -12.42 19.21 16.20 +v -12.01 20.21 15.94 +v -12.01 19.24 15.94 +v -11.80 20.29 15.84 +v -11.79 20.29 15.94 +v -13.10 19.12 15.95 +v -13.09 19.12 16.05 +v -12.01 20.21 16.01 +v -12.86 19.23 16.09 +v -12.01 19.24 16.01 +v -12.43 19.21 16.10 +v -11.79 19.26 15.94 +v -11.80 19.26 15.84 +v -13.10 19.26 15.95 +v -13.09 19.26 16.05 +v -13.19 19.12 16.13 +v -13.19 19.26 16.13 +v -11.67 19.26 16.00 +v -11.67 19.12 16.00 +v -9.24 23.34 12.52 +v -8.56 24.92 12.99 +v -9.10 24.92 13.76 +v -9.78 23.34 13.29 +v -9.53 28.41 12.29 +v -8.63 28.41 12.92 +v -9.18 28.41 13.70 +v -10.08 28.41 13.07 +v -12.87 27.21 14.81 +v -12.87 26.24 14.81 +v -12.44 26.21 14.82 +v -12.44 27.52 14.82 +v -13.21 26.26 14.72 +v -13.21 26.12 14.72 +v -13.20 26.12 14.82 +v -13.20 26.26 14.82 +v -12.44 27.75 14.80 +v -13.10 27.30 14.75 +v -13.09 27.30 14.85 +v -12.43 27.75 14.89 +v -11.69 26.12 14.59 +v -11.69 26.26 14.59 +v -11.68 26.26 14.69 +v -11.68 26.12 14.69 +v -12.44 26.07 14.80 +v -11.80 26.12 14.64 +v -11.79 26.12 14.73 +v -12.43 26.07 14.89 +v -13.08 26.12 14.96 +v -12.85 26.24 14.99 +v -13.08 26.26 14.96 +v -12.86 27.21 14.89 +v -12.43 27.52 14.89 +v -11.78 26.26 14.84 +v -12.00 26.25 14.92 +v -11.78 26.12 14.84 +v -12.42 26.07 15.00 +v -12.42 26.21 15.00 +v -12.01 27.21 14.74 +v -12.01 26.25 14.74 +v -11.80 27.30 14.64 +v -11.79 27.30 14.73 +v -13.10 26.12 14.75 +v -13.09 26.12 14.85 +v -12.01 27.21 14.81 +v -12.86 26.24 14.89 +v -12.01 26.25 14.81 +v -12.43 26.21 14.89 +v -11.79 26.26 14.73 +v -11.80 26.26 14.64 +v -13.10 26.26 14.75 +v -13.09 26.26 14.85 +v -13.19 26.12 14.93 +v -13.19 26.26 14.93 +v -11.67 26.26 14.79 +v -11.67 26.12 14.79 +v -14.41 23.34 14.01 +v -14.88 24.92 14.68 +v -15.65 24.92 14.14 +v -15.18 23.34 13.46 +v -14.18 28.41 13.71 +v -14.81 28.41 14.61 +v -15.59 28.41 14.07 +v -14.96 28.41 13.17 +v -8.43 27.21 10.98 +v -8.43 26.24 10.98 +v -8.42 26.21 10.55 +v -8.42 27.52 10.55 +v -8.52 26.26 11.32 +v -8.52 26.12 11.32 +v -8.42 26.12 11.31 +v -8.42 26.26 11.31 +v -8.45 27.75 10.55 +v -8.49 27.30 11.21 +v -8.39 27.30 11.20 +v -8.35 27.75 10.54 +v -8.65 26.12 9.80 +v -8.65 26.26 9.80 +v -8.56 26.26 9.79 +v -8.56 26.12 9.79 +v -8.45 26.07 10.55 +v -8.61 26.12 9.91 +v -8.51 26.12 9.90 +v -8.35 26.07 10.54 +v -8.29 26.12 11.19 +v -8.25 26.24 10.96 +v -8.29 26.26 11.19 +v -8.35 27.21 10.97 +v -8.35 27.52 10.54 +v -8.40 26.26 9.89 +v -8.32 26.25 10.11 +v -8.40 26.12 9.89 +v -8.24 26.07 10.53 +v -8.24 26.21 10.53 +v -8.50 27.21 10.13 +v -8.50 26.25 10.13 +v -8.61 27.30 9.91 +v -8.51 27.30 9.90 +v -8.49 26.12 11.21 +v -8.39 26.12 11.20 +v -8.43 27.21 10.12 +v -8.35 26.24 10.97 +v -8.43 26.25 10.12 +v -8.35 26.21 10.54 +v -8.51 26.26 9.90 +v -8.61 26.26 9.91 +v -8.49 26.26 11.21 +v -8.39 26.26 11.20 +v -8.32 26.12 11.30 +v -8.32 26.26 11.30 +v -8.45 26.26 9.78 +v -8.45 26.12 9.78 +v -13.04 12.70 6.81 +v -13.04 14.28 5.99 +v -12.09 14.28 5.99 +v -12.09 12.70 6.81 +v -13.04 17.34 6.74 +v -13.04 17.34 5.64 +v -12.09 17.34 5.64 +v -12.09 17.34 6.74 +v -8.98 12.70 12.20 +v -8.27 14.28 12.61 +v -8.74 14.28 13.43 +v -9.46 12.70 13.02 +v -8.92 17.34 12.24 +v -7.97 17.34 12.79 +v -8.44 17.34 13.61 +v -9.39 17.34 13.06 +v -12.09 12.70 14.54 +v -12.09 14.28 15.36 +v -13.04 14.28 15.36 +v -13.04 12.70 14.54 +v -12.09 17.34 14.62 +v -12.09 17.34 15.71 +v -13.04 17.34 15.71 +v -13.04 17.34 14.62 +v -10.73 23.34 7.35 +v -10.25 24.92 6.67 +v -9.48 24.92 7.22 +v -9.95 23.34 7.89 +v -10.95 28.41 7.65 +v -10.32 28.41 6.74 +v -9.55 28.41 7.29 +v -10.18 28.41 8.19 +v -9.46 12.70 8.34 +v -8.74 14.28 7.92 +v -8.27 14.28 8.74 +v -8.98 12.70 9.15 +v -9.39 17.34 8.30 +v -8.44 17.34 7.75 +v -7.97 17.34 8.57 +v -8.92 17.34 9.12 +v -7.23 20.21 10.98 +v -7.23 19.23 10.98 +v -7.22 19.21 10.55 +v -7.22 20.52 10.55 +v -7.32 19.26 11.32 +v -7.32 19.12 11.32 +v -7.22 19.12 11.31 +v -7.22 19.26 11.31 +v -7.24 20.75 10.55 +v -7.29 20.29 11.21 +v -7.19 20.29 11.20 +v -7.15 20.75 10.54 +v -7.45 19.12 9.80 +v -7.45 19.26 9.80 +v -7.35 19.26 9.79 +v -7.35 19.12 9.79 +v -7.24 19.07 10.55 +v -7.41 19.12 9.91 +v -7.31 19.12 9.90 +v -7.15 19.07 10.54 +v -7.09 19.12 11.19 +v -7.05 19.23 10.96 +v -7.09 19.26 11.19 +v -7.15 20.21 10.97 +v -7.15 20.52 10.54 +v -7.20 19.26 9.89 +v -7.12 19.24 10.11 +v -7.20 19.12 9.89 +v -7.04 19.07 10.53 +v -7.04 19.21 10.53 +v -7.30 20.21 10.13 +v -7.30 19.24 10.13 +v -7.41 20.29 9.91 +v -7.31 20.29 9.90 +v -7.29 19.12 11.21 +v -7.19 19.12 11.20 +v -7.23 20.21 10.12 +v -7.15 19.23 10.97 +v -7.23 19.24 10.12 +v -7.15 19.21 10.54 +v -7.31 19.26 9.90 +v -7.41 19.26 9.91 +v -7.29 19.26 11.21 +v -7.19 19.26 11.20 +v -7.11 19.12 11.30 +v -7.11 19.26 11.30 +v -7.25 19.26 9.78 +v -7.25 19.12 9.78 +v -12.26 27.21 6.54 +v -12.26 26.24 6.54 +v -12.69 26.21 6.53 +v -12.69 27.52 6.53 +v -11.92 26.26 6.63 +v -11.92 26.12 6.63 +v -11.93 26.12 6.53 +v -11.93 26.26 6.53 +v -12.69 27.75 6.56 +v -12.03 27.30 6.60 +v -12.04 27.30 6.51 +v -12.70 27.75 6.46 +v -13.44 26.12 6.76 +v -13.44 26.26 6.76 +v -13.45 26.26 6.67 +v -13.45 26.12 6.67 +v -12.69 26.07 6.56 +v -13.34 26.12 6.72 +v -13.34 26.12 6.62 +v -12.70 26.07 6.46 +v -12.05 26.12 6.40 +v -12.28 26.24 6.36 +v -12.05 26.26 6.40 +v -12.27 27.21 6.47 +v -12.70 27.52 6.46 +v -13.35 26.26 6.51 +v -13.13 26.25 6.43 +v -13.35 26.12 6.51 +v -12.71 26.07 6.35 +v -12.71 26.21 6.35 +v -13.12 27.21 6.61 +v -13.12 26.25 6.61 +v -13.34 27.30 6.72 +v -13.34 27.30 6.62 +v -12.03 26.12 6.60 +v -12.04 26.12 6.51 +v -13.12 27.21 6.54 +v -12.27 26.24 6.47 +v -13.12 26.25 6.54 +v -12.70 26.21 6.46 +v -13.34 26.26 6.62 +v -13.34 26.26 6.72 +v -12.03 26.26 6.60 +v -12.04 26.26 6.51 +v -11.94 26.12 6.43 +v -11.94 26.26 6.43 +v -13.46 26.26 6.56 +v -13.46 26.12 6.56 +v -16.15 12.70 9.15 +v -16.86 14.28 8.74 +v -16.39 14.28 7.92 +v -15.67 12.70 8.34 +v -16.21 17.34 9.12 +v -17.17 17.34 8.57 +v -16.69 17.34 7.75 +v -15.74 17.34 8.30 +v -12.26 20.21 5.34 +v -12.26 19.23 5.34 +v -12.69 19.21 5.33 +v -12.69 20.52 5.33 +v -11.92 19.26 5.43 +v -11.92 19.12 5.43 +v -11.93 19.12 5.33 +v -11.93 19.26 5.33 +v -12.69 20.75 5.36 +v -12.03 20.29 5.40 +v -12.04 20.29 5.30 +v -12.70 20.75 5.26 +v -13.44 19.12 5.56 +v -13.44 19.26 5.56 +v -13.45 19.26 5.47 +v -13.45 19.12 5.47 +v -12.69 19.07 5.36 +v -13.34 19.12 5.52 +v -13.34 19.12 5.42 +v -12.70 19.07 5.26 +v -12.05 19.12 5.20 +v -12.28 19.23 5.16 +v -12.05 19.26 5.20 +v -12.27 20.21 5.26 +v -12.70 20.52 5.26 +v -13.35 19.26 5.31 +v -13.13 19.24 5.23 +v -13.35 19.12 5.31 +v -12.71 19.07 5.15 +v -12.71 19.21 5.15 +v -13.12 20.21 5.41 +v -13.12 19.24 5.41 +v -13.34 20.29 5.52 +v -13.34 20.29 5.42 +v -12.03 19.12 5.40 +v -12.04 19.12 5.30 +v -13.12 20.21 5.34 +v -12.27 19.23 5.26 +v -13.12 19.24 5.34 +v -12.70 19.21 5.26 +v -13.34 19.26 5.42 +v -13.34 19.26 5.52 +v -12.03 19.26 5.40 +v -12.04 19.26 5.30 +v -11.94 19.12 5.23 +v -11.94 19.26 5.23 +v -13.46 19.26 5.36 +v -13.46 19.12 5.36 +v -15.89 23.34 8.84 +v -16.57 24.92 8.36 +v -16.03 24.92 7.59 +v -15.35 23.34 8.06 +v -15.60 28.41 9.06 +v -16.50 28.41 8.43 +v -15.96 28.41 7.66 +v -15.06 28.41 8.29 +v -16.70 27.21 10.37 +v -16.70 26.24 10.37 +v -16.71 26.21 10.80 +v -16.71 27.52 10.80 +v -16.61 26.26 10.03 +v -16.61 26.12 10.03 +v -16.71 26.12 10.04 +v -16.71 26.26 10.04 +v -16.69 27.75 10.80 +v -16.64 27.30 10.15 +v -16.74 27.30 10.15 +v -16.78 27.75 10.81 +v -16.48 26.12 11.55 +v -16.48 26.26 11.55 +v -16.58 26.26 11.56 +v -16.58 26.12 11.56 +v -16.69 26.07 10.80 +v -16.53 26.12 11.45 +v -16.62 26.12 11.45 +v -16.78 26.07 10.81 +v -16.84 26.12 10.16 +v -16.88 26.24 10.39 +v -16.84 26.26 10.16 +v -16.78 27.21 10.38 +v -16.78 27.52 10.81 +v -16.73 26.26 11.46 +v -16.81 26.25 11.24 +v -16.73 26.12 11.46 +v -16.89 26.07 10.82 +v -16.89 26.21 10.82 +v -16.63 27.21 11.23 +v -16.63 26.25 11.23 +v -16.53 27.30 11.45 +v -16.62 27.30 11.45 +v -16.64 26.12 10.15 +v -16.74 26.12 10.15 +v -16.70 27.21 11.23 +v -16.78 26.24 10.38 +v -16.70 26.25 11.23 +v -16.78 26.21 10.81 +v -16.62 26.26 11.45 +v -16.53 26.26 11.45 +v -16.64 26.26 10.15 +v -16.74 26.26 10.15 +v -16.82 26.12 10.05 +v -16.82 26.26 10.05 +v -16.68 26.26 11.57 +v -16.68 26.12 11.57 +v -15.67 12.70 13.02 +v -16.39 14.28 13.43 +v -16.86 14.28 12.61 +v -16.15 12.70 12.20 +v -15.74 17.34 13.06 +v -16.69 17.34 13.61 +v -17.17 17.34 12.79 +v -16.21 17.34 12.24 +v -16.83 28.50 13.14 +v -16.83 30.29 13.14 +v -17.49 30.29 10.68 +v -17.49 28.50 10.68 +v -15.03 28.50 14.94 +v -15.03 30.29 14.94 +v -12.57 28.50 15.60 +v -12.57 30.29 15.60 +v -10.10 28.50 14.94 +v -10.10 30.29 14.94 +v -8.30 28.50 13.14 +v -8.30 30.29 13.14 +v -7.64 28.50 10.68 +v -7.64 30.29 10.68 +v -8.30 28.50 8.21 +v -8.30 30.29 8.21 +v -10.10 28.50 6.41 +v -10.10 30.29 6.41 +v -12.57 28.50 5.75 +v -12.57 30.29 5.75 +v -15.03 28.50 6.41 +v -15.03 30.29 6.41 +v -16.83 28.50 8.21 +v -16.83 30.29 8.21 +v -16.21 30.29 12.78 +v -16.78 30.29 10.68 +v -15.03 30.90 14.94 +v -14.67 30.90 14.32 +v -16.21 30.90 12.78 +v -16.83 30.90 13.14 +v -12.57 30.29 14.89 +v -14.67 30.29 14.32 +v -10.10 30.90 14.94 +v -10.46 30.90 14.32 +v -12.57 30.90 14.89 +v -12.57 30.90 15.60 +v -8.92 30.29 12.78 +v -10.46 30.29 14.32 +v -7.64 30.90 10.68 +v -8.36 30.90 10.68 +v -8.92 30.90 12.78 +v -8.30 30.90 13.14 +v -8.92 30.29 8.57 +v -8.36 30.29 10.68 +v -10.10 30.90 6.41 +v -10.46 30.90 7.03 +v -8.92 30.90 8.57 +v -8.30 30.90 8.21 +v -12.57 30.29 6.47 +v -10.46 30.29 7.03 +v -15.03 30.90 6.41 +v -14.67 30.90 7.03 +v -12.57 30.90 6.47 +v -12.57 30.90 5.75 +v -16.21 30.29 8.57 +v -14.67 30.29 7.03 +v -17.49 30.90 10.68 +v -16.78 30.90 10.68 +v -16.21 30.90 8.57 +v -16.83 30.90 8.21 +v -16.21 29.42 12.78 +v -16.78 29.42 10.68 +v -14.67 29.42 14.32 +v -12.57 29.42 14.89 +v -10.46 29.42 14.32 +v -8.92 29.42 12.78 +v -8.36 29.42 10.68 +v -8.92 29.42 8.57 +v -10.46 29.42 7.03 +v -12.57 29.42 6.47 +v -14.67 29.42 7.03 +v -16.21 29.42 8.57 +v -12.57 29.42 10.68 +v 17.17 7.76 10.68 +v 16.55 7.76 12.98 +v 16.55 0.00 12.98 +v 17.17 0.00 10.68 +v 14.87 7.76 14.66 +v 14.87 0.00 14.66 +v 12.57 7.76 15.28 +v 12.57 0.00 15.28 +v 10.27 7.76 14.66 +v 10.27 0.00 14.66 +v 8.58 7.76 12.98 +v 8.58 0.00 12.98 +v 7.97 7.76 10.68 +v 7.97 0.00 10.68 +v 8.58 7.76 8.38 +v 8.58 0.00 8.38 +v 10.27 7.76 6.69 +v 10.27 0.00 6.69 +v 12.57 7.76 6.08 +v 12.57 0.00 6.08 +v 14.87 7.76 6.69 +v 14.87 0.00 6.69 +v 16.55 7.76 8.38 +v 16.55 0.00 8.38 +v 16.78 7.76 13.11 +v 17.43 7.76 10.68 +v 17.43 8.57 10.68 +v 16.78 8.57 13.11 +v 15.00 7.76 14.89 +v 15.00 8.57 14.89 +v 12.57 7.76 15.54 +v 12.57 8.57 15.54 +v 10.13 7.76 14.89 +v 10.13 8.57 14.89 +v 8.35 7.76 13.11 +v 8.35 8.57 13.11 +v 7.70 7.76 10.68 +v 7.70 8.57 10.68 +v 8.35 7.76 8.24 +v 8.35 8.57 8.24 +v 10.13 7.76 6.46 +v 10.13 8.57 6.46 +v 12.57 7.76 5.81 +v 12.57 8.57 5.81 +v 15.00 7.76 6.46 +v 15.00 8.57 6.46 +v 16.78 7.76 8.24 +v 16.78 8.57 8.24 +v 17.17 8.57 10.68 +v 16.55 8.57 12.98 +v 14.87 8.57 14.66 +v 12.57 8.57 15.28 +v 10.27 8.57 14.66 +v 8.58 8.57 12.98 +v 7.97 8.57 10.68 +v 8.58 8.57 8.38 +v 10.27 8.57 6.69 +v 12.57 8.57 6.08 +v 14.87 8.57 6.69 +v 16.55 8.57 8.38 +v 17.17 16.89 10.68 +v 16.55 16.89 12.98 +v 14.87 16.89 14.66 +v 12.57 16.89 15.28 +v 10.27 16.89 14.66 +v 8.58 16.89 12.98 +v 7.97 16.89 10.68 +v 8.58 16.89 8.38 +v 10.27 16.89 6.69 +v 12.57 16.89 6.08 +v 14.87 16.89 6.69 +v 16.55 16.89 8.38 +v 17.13 21.30 13.31 +v 17.83 21.30 10.68 +v 18.23 21.30 10.68 +v 17.47 21.30 13.51 +v 15.20 21.30 15.24 +v 15.40 21.30 15.58 +v 12.57 21.30 15.94 +v 12.57 21.30 16.34 +v 9.93 21.30 15.24 +v 9.73 21.30 15.58 +v 8.01 21.30 13.31 +v 7.66 21.30 13.51 +v 7.30 21.30 10.68 +v 6.90 21.30 10.68 +v 8.01 21.30 8.04 +v 7.66 21.30 7.84 +v 9.93 21.30 6.12 +v 9.73 21.30 5.77 +v 12.57 21.30 5.41 +v 12.57 21.30 5.01 +v 15.20 21.30 6.12 +v 15.40 21.30 5.77 +v 17.13 21.30 8.04 +v 17.47 21.30 7.84 +v 16.72 24.76 10.68 +v 16.17 24.76 12.76 +v 14.64 24.76 14.28 +v 12.57 24.76 14.83 +v 10.49 24.76 14.28 +v 8.97 24.76 12.76 +v 8.41 24.76 10.68 +v 8.97 24.76 8.60 +v 10.49 24.76 7.08 +v 12.57 24.76 6.52 +v 14.64 24.76 7.08 +v 16.17 24.76 8.60 +v 16.69 28.50 10.68 +v 16.13 28.50 12.74 +v 14.63 28.50 14.24 +v 12.57 28.50 14.80 +v 10.51 28.50 14.24 +v 9.00 28.50 12.74 +v 8.45 28.50 10.68 +v 9.00 28.50 8.62 +v 10.51 28.50 7.11 +v 12.57 28.50 6.56 +v 14.63 28.50 7.11 +v 16.13 28.50 8.62 +v 17.83 17.36 10.68 +v 17.13 17.36 13.31 +v 15.20 17.36 15.24 +v 12.57 17.36 15.94 +v 9.93 17.36 15.24 +v 8.01 17.36 13.31 +v 7.30 17.36 10.68 +v 8.01 17.36 8.04 +v 9.93 17.36 6.12 +v 12.57 17.36 5.41 +v 15.20 17.36 6.12 +v 17.13 17.36 8.04 +v 17.91 20.21 10.37 +v 17.91 20.52 10.80 +v 17.91 19.21 10.80 +v 17.91 19.23 10.37 +v 17.81 19.26 10.03 +v 17.91 19.26 10.04 +v 17.91 19.12 10.04 +v 17.81 19.12 10.03 +v 17.89 20.75 10.80 +v 17.98 20.75 10.81 +v 17.94 20.29 10.15 +v 17.84 20.29 10.15 +v 17.68 19.12 11.55 +v 17.78 19.12 11.56 +v 17.78 19.26 11.56 +v 17.68 19.26 11.55 +v 17.89 19.07 10.80 +v 17.98 19.07 10.81 +v 17.82 19.12 11.45 +v 17.73 19.12 11.45 +v 18.05 19.12 10.16 +v 18.05 19.26 10.16 +v 18.08 19.23 10.39 +v 17.98 20.52 10.81 +v 17.98 20.21 10.38 +v 17.93 19.26 11.46 +v 17.93 19.12 11.46 +v 18.01 19.24 11.24 +v 18.09 19.07 10.82 +v 18.09 19.21 10.82 +v 17.83 20.21 11.23 +v 17.83 19.24 11.23 +v 17.73 20.29 11.45 +v 17.82 20.29 11.45 +v 17.84 19.12 10.15 +v 17.94 19.12 10.15 +v 17.90 20.21 11.23 +v 17.98 19.23 10.38 +v 17.90 19.24 11.23 +v 17.98 19.21 10.81 +v 17.82 19.26 11.45 +v 17.73 19.26 11.45 +v 17.94 19.26 10.15 +v 17.84 19.26 10.15 +v 18.02 19.26 10.05 +v 18.02 19.12 10.05 +v 17.88 19.12 11.57 +v 17.88 19.26 11.57 +v 12.87 20.21 16.02 +v 12.44 20.52 16.02 +v 12.44 19.21 16.02 +v 12.87 19.23 16.02 +v 13.21 19.26 15.92 +v 13.20 19.26 16.02 +v 13.20 19.12 16.02 +v 13.21 19.12 15.92 +v 12.44 20.75 16.00 +v 12.43 20.75 16.10 +v 13.09 20.29 16.05 +v 13.10 20.29 15.95 +v 11.69 19.12 15.79 +v 11.68 19.12 15.89 +v 11.68 19.26 15.89 +v 11.69 19.26 15.79 +v 12.44 19.07 16.00 +v 12.43 19.07 16.10 +v 11.79 19.12 15.94 +v 11.80 19.12 15.84 +v 13.08 19.12 16.16 +v 13.08 19.26 16.16 +v 12.85 19.23 16.20 +v 12.43 20.52 16.10 +v 12.86 20.21 16.09 +v 11.78 19.26 16.04 +v 11.78 19.12 16.04 +v 12.00 19.24 16.12 +v 12.42 19.07 16.20 +v 12.42 19.21 16.20 +v 12.01 20.21 15.94 +v 12.01 19.24 15.94 +v 11.80 20.29 15.84 +v 11.79 20.29 15.94 +v 13.10 19.12 15.95 +v 13.09 19.12 16.05 +v 12.01 20.21 16.01 +v 12.86 19.23 16.09 +v 12.01 19.24 16.01 +v 12.43 19.21 16.10 +v 11.79 19.26 15.94 +v 11.80 19.26 15.84 +v 13.09 19.26 16.05 +v 13.10 19.26 15.95 +v 13.19 19.26 16.13 +v 13.19 19.12 16.13 +v 11.67 19.12 16.00 +v 11.67 19.26 16.00 +v 9.24 23.34 12.52 +v 9.78 23.34 13.29 +v 9.10 24.92 13.76 +v 8.56 24.92 12.99 +v 8.63 28.41 12.92 +v 9.53 28.41 12.29 +v 9.18 28.41 13.70 +v 10.08 28.41 13.07 +v 12.87 27.21 14.81 +v 12.44 27.52 14.82 +v 12.44 26.21 14.82 +v 12.87 26.24 14.81 +v 13.21 26.26 14.72 +v 13.20 26.26 14.82 +v 13.20 26.12 14.82 +v 13.21 26.12 14.72 +v 12.44 27.75 14.80 +v 12.43 27.75 14.89 +v 13.09 27.30 14.85 +v 13.10 27.30 14.75 +v 11.69 26.12 14.59 +v 11.68 26.12 14.69 +v 11.68 26.26 14.69 +v 11.69 26.26 14.59 +v 12.44 26.07 14.80 +v 12.43 26.07 14.89 +v 11.79 26.12 14.73 +v 11.80 26.12 14.64 +v 13.08 26.12 14.96 +v 13.08 26.26 14.96 +v 12.85 26.24 14.99 +v 12.43 27.52 14.89 +v 12.86 27.21 14.89 +v 11.78 26.26 14.84 +v 11.78 26.12 14.84 +v 12.00 26.25 14.92 +v 12.42 26.07 15.00 +v 12.42 26.21 15.00 +v 12.01 27.21 14.74 +v 12.01 26.25 14.74 +v 11.80 27.30 14.64 +v 11.79 27.30 14.73 +v 13.10 26.12 14.75 +v 13.09 26.12 14.85 +v 12.01 27.21 14.81 +v 12.86 26.24 14.89 +v 12.01 26.25 14.81 +v 12.43 26.21 14.89 +v 11.79 26.26 14.73 +v 11.80 26.26 14.64 +v 13.09 26.26 14.85 +v 13.10 26.26 14.75 +v 13.19 26.26 14.93 +v 13.19 26.12 14.93 +v 11.67 26.12 14.79 +v 11.67 26.26 14.79 +v 14.41 23.34 14.01 +v 15.18 23.34 13.46 +v 15.65 24.92 14.14 +v 14.88 24.92 14.68 +v 14.81 28.41 14.61 +v 14.18 28.41 13.71 +v 15.59 28.41 14.07 +v 14.96 28.41 13.17 +v 8.43 27.21 10.98 +v 8.42 27.52 10.55 +v 8.42 26.21 10.55 +v 8.43 26.24 10.98 +v 8.52 26.26 11.32 +v 8.42 26.26 11.31 +v 8.42 26.12 11.31 +v 8.52 26.12 11.32 +v 8.45 27.75 10.55 +v 8.35 27.75 10.54 +v 8.39 27.30 11.20 +v 8.49 27.30 11.21 +v 8.65 26.12 9.80 +v 8.56 26.12 9.79 +v 8.56 26.26 9.79 +v 8.65 26.26 9.80 +v 8.45 26.07 10.55 +v 8.35 26.07 10.54 +v 8.51 26.12 9.90 +v 8.61 26.12 9.91 +v 8.29 26.12 11.19 +v 8.29 26.26 11.19 +v 8.25 26.24 10.96 +v 8.35 27.52 10.54 +v 8.35 27.21 10.97 +v 8.40 26.26 9.89 +v 8.40 26.12 9.89 +v 8.32 26.25 10.11 +v 8.24 26.07 10.53 +v 8.24 26.21 10.53 +v 8.50 27.21 10.13 +v 8.50 26.25 10.13 +v 8.61 27.30 9.91 +v 8.51 27.30 9.90 +v 8.49 26.12 11.21 +v 8.39 26.12 11.20 +v 8.43 27.21 10.12 +v 8.35 26.24 10.97 +v 8.43 26.25 10.12 +v 8.35 26.21 10.54 +v 8.51 26.26 9.90 +v 8.61 26.26 9.91 +v 8.39 26.26 11.20 +v 8.49 26.26 11.21 +v 8.32 26.26 11.30 +v 8.32 26.12 11.30 +v 8.45 26.12 9.78 +v 8.45 26.26 9.78 +v 13.04 12.70 6.81 +v 12.09 12.70 6.81 +v 12.09 14.28 5.99 +v 13.04 14.28 5.99 +v 13.04 17.34 5.64 +v 13.04 17.34 6.74 +v 12.09 17.34 5.64 +v 12.09 17.34 6.74 +v 8.98 12.70 12.20 +v 9.46 12.70 13.02 +v 8.74 14.28 13.43 +v 8.27 14.28 12.61 +v 7.97 17.34 12.79 +v 8.92 17.34 12.24 +v 8.44 17.34 13.61 +v 9.39 17.34 13.06 +v 12.09 12.70 14.54 +v 13.04 12.70 14.54 +v 13.04 14.28 15.36 +v 12.09 14.28 15.36 +v 12.09 17.34 15.71 +v 12.09 17.34 14.62 +v 13.04 17.34 15.71 +v 13.04 17.34 14.62 +v 10.73 23.34 7.35 +v 9.95 23.34 7.89 +v 9.48 24.92 7.22 +v 10.25 24.92 6.67 +v 10.32 28.41 6.74 +v 10.95 28.41 7.65 +v 9.55 28.41 7.29 +v 10.18 28.41 8.19 +v 9.46 12.70 8.34 +v 8.98 12.70 9.15 +v 8.27 14.28 8.74 +v 8.74 14.28 7.92 +v 8.44 17.34 7.75 +v 9.39 17.34 8.30 +v 7.97 17.34 8.57 +v 8.92 17.34 9.12 +v 7.23 20.21 10.98 +v 7.22 20.52 10.55 +v 7.22 19.21 10.55 +v 7.23 19.23 10.98 +v 7.32 19.26 11.32 +v 7.22 19.26 11.31 +v 7.22 19.12 11.31 +v 7.32 19.12 11.32 +v 7.24 20.75 10.55 +v 7.15 20.75 10.54 +v 7.19 20.29 11.20 +v 7.29 20.29 11.21 +v 7.45 19.12 9.80 +v 7.35 19.12 9.79 +v 7.35 19.26 9.79 +v 7.45 19.26 9.80 +v 7.24 19.07 10.55 +v 7.15 19.07 10.54 +v 7.31 19.12 9.90 +v 7.41 19.12 9.91 +v 7.09 19.12 11.19 +v 7.09 19.26 11.19 +v 7.05 19.23 10.96 +v 7.15 20.52 10.54 +v 7.15 20.21 10.97 +v 7.20 19.26 9.89 +v 7.20 19.12 9.89 +v 7.12 19.24 10.11 +v 7.04 19.07 10.53 +v 7.04 19.21 10.53 +v 7.30 20.21 10.13 +v 7.30 19.24 10.13 +v 7.41 20.29 9.91 +v 7.31 20.29 9.90 +v 7.29 19.12 11.21 +v 7.19 19.12 11.20 +v 7.23 20.21 10.12 +v 7.15 19.23 10.97 +v 7.23 19.24 10.12 +v 7.15 19.21 10.54 +v 7.31 19.26 9.90 +v 7.41 19.26 9.91 +v 7.19 19.26 11.20 +v 7.29 19.26 11.21 +v 7.11 19.26 11.30 +v 7.11 19.12 11.30 +v 7.25 19.12 9.78 +v 7.25 19.26 9.78 +v 12.26 27.21 6.54 +v 12.69 27.52 6.53 +v 12.69 26.21 6.53 +v 12.26 26.24 6.54 +v 11.92 26.26 6.63 +v 11.93 26.26 6.53 +v 11.93 26.12 6.53 +v 11.92 26.12 6.63 +v 12.69 27.75 6.56 +v 12.70 27.75 6.46 +v 12.04 27.30 6.51 +v 12.03 27.30 6.60 +v 13.44 26.12 6.76 +v 13.45 26.12 6.67 +v 13.45 26.26 6.67 +v 13.44 26.26 6.76 +v 12.69 26.07 6.56 +v 12.70 26.07 6.46 +v 13.34 26.12 6.62 +v 13.34 26.12 6.72 +v 12.05 26.12 6.40 +v 12.05 26.26 6.40 +v 12.28 26.24 6.36 +v 12.70 27.52 6.46 +v 12.27 27.21 6.47 +v 13.35 26.26 6.51 +v 13.35 26.12 6.51 +v 13.13 26.25 6.43 +v 12.71 26.07 6.35 +v 12.71 26.21 6.35 +v 13.12 27.21 6.61 +v 13.12 26.25 6.61 +v 13.34 27.30 6.72 +v 13.34 27.30 6.62 +v 12.03 26.12 6.60 +v 12.04 26.12 6.51 +v 13.12 27.21 6.54 +v 12.27 26.24 6.47 +v 13.12 26.25 6.54 +v 12.70 26.21 6.46 +v 13.34 26.26 6.62 +v 13.34 26.26 6.72 +v 12.04 26.26 6.51 +v 12.03 26.26 6.60 +v 11.94 26.26 6.43 +v 11.94 26.12 6.43 +v 13.46 26.12 6.56 +v 13.46 26.26 6.56 +v 16.15 12.70 9.15 +v 15.67 12.70 8.34 +v 16.39 14.28 7.92 +v 16.86 14.28 8.74 +v 17.17 17.34 8.57 +v 16.21 17.34 9.12 +v 16.69 17.34 7.75 +v 15.74 17.34 8.30 +v 12.26 20.21 5.34 +v 12.69 20.52 5.33 +v 12.69 19.21 5.33 +v 12.26 19.23 5.34 +v 11.92 19.26 5.43 +v 11.93 19.26 5.33 +v 11.93 19.12 5.33 +v 11.92 19.12 5.43 +v 12.69 20.75 5.36 +v 12.70 20.75 5.26 +v 12.04 20.29 5.30 +v 12.03 20.29 5.40 +v 13.44 19.12 5.56 +v 13.45 19.12 5.47 +v 13.45 19.26 5.47 +v 13.44 19.26 5.56 +v 12.69 19.07 5.36 +v 12.70 19.07 5.26 +v 13.34 19.12 5.42 +v 13.34 19.12 5.52 +v 12.05 19.12 5.20 +v 12.05 19.26 5.20 +v 12.28 19.23 5.16 +v 12.70 20.52 5.26 +v 12.27 20.21 5.26 +v 13.35 19.26 5.31 +v 13.35 19.12 5.31 +v 13.13 19.24 5.23 +v 12.71 19.07 5.15 +v 12.71 19.21 5.15 +v 13.12 20.21 5.41 +v 13.12 19.24 5.41 +v 13.34 20.29 5.52 +v 13.34 20.29 5.42 +v 12.03 19.12 5.40 +v 12.04 19.12 5.30 +v 13.12 20.21 5.34 +v 12.27 19.23 5.26 +v 13.12 19.24 5.34 +v 12.70 19.21 5.26 +v 13.34 19.26 5.42 +v 13.34 19.26 5.52 +v 12.04 19.26 5.30 +v 12.03 19.26 5.40 +v 11.94 19.26 5.23 +v 11.94 19.12 5.23 +v 13.46 19.12 5.36 +v 13.46 19.26 5.36 +v 15.89 23.34 8.84 +v 15.35 23.34 8.06 +v 16.03 24.92 7.59 +v 16.57 24.92 8.36 +v 16.50 28.41 8.43 +v 15.60 28.41 9.06 +v 15.96 28.41 7.66 +v 15.06 28.41 8.29 +v 16.70 27.21 10.37 +v 16.71 27.52 10.80 +v 16.71 26.21 10.80 +v 16.70 26.24 10.37 +v 16.61 26.26 10.03 +v 16.71 26.26 10.04 +v 16.71 26.12 10.04 +v 16.61 26.12 10.03 +v 16.69 27.75 10.80 +v 16.78 27.75 10.81 +v 16.74 27.30 10.15 +v 16.64 27.30 10.15 +v 16.48 26.12 11.55 +v 16.58 26.12 11.56 +v 16.58 26.26 11.56 +v 16.48 26.26 11.55 +v 16.69 26.07 10.80 +v 16.78 26.07 10.81 +v 16.62 26.12 11.45 +v 16.53 26.12 11.45 +v 16.84 26.12 10.16 +v 16.84 26.26 10.16 +v 16.88 26.24 10.39 +v 16.78 27.52 10.81 +v 16.78 27.21 10.38 +v 16.73 26.26 11.46 +v 16.73 26.12 11.46 +v 16.81 26.25 11.24 +v 16.89 26.07 10.82 +v 16.89 26.21 10.82 +v 16.63 27.21 11.23 +v 16.63 26.25 11.23 +v 16.53 27.30 11.45 +v 16.62 27.30 11.45 +v 16.64 26.12 10.15 +v 16.74 26.12 10.15 +v 16.70 27.21 11.23 +v 16.78 26.24 10.38 +v 16.70 26.25 11.23 +v 16.78 26.21 10.81 +v 16.62 26.26 11.45 +v 16.53 26.26 11.45 +v 16.74 26.26 10.15 +v 16.64 26.26 10.15 +v 16.82 26.26 10.05 +v 16.82 26.12 10.05 +v 16.68 26.12 11.57 +v 16.68 26.26 11.57 +v 15.67 12.70 13.02 +v 16.15 12.70 12.20 +v 16.86 14.28 12.61 +v 16.39 14.28 13.43 +v 16.69 17.34 13.61 +v 15.74 17.34 13.06 +v 17.17 17.34 12.79 +v 16.21 17.34 12.24 +v 16.83 28.50 13.14 +v 17.49 28.50 10.68 +v 17.49 30.29 10.68 +v 16.83 30.29 13.14 +v 15.03 28.50 14.94 +v 15.03 30.29 14.94 +v 12.57 28.50 15.60 +v 12.57 30.29 15.60 +v 10.10 28.50 14.94 +v 10.10 30.29 14.94 +v 8.30 28.50 13.14 +v 8.30 30.29 13.14 +v 7.64 28.50 10.68 +v 7.64 30.29 10.68 +v 8.30 28.50 8.21 +v 8.30 30.29 8.21 +v 10.10 28.50 6.41 +v 10.10 30.29 6.41 +v 12.57 28.50 5.75 +v 12.57 30.29 5.75 +v 15.03 28.50 6.41 +v 15.03 30.29 6.41 +v 16.83 28.50 8.21 +v 16.83 30.29 8.21 +v 16.78 30.29 10.68 +v 16.21 30.29 12.78 +v 15.03 30.90 14.94 +v 16.83 30.90 13.14 +v 16.21 30.90 12.78 +v 14.67 30.90 14.32 +v 14.67 30.29 14.32 +v 12.57 30.29 14.89 +v 10.10 30.90 14.94 +v 12.57 30.90 15.60 +v 12.57 30.90 14.89 +v 10.46 30.90 14.32 +v 10.46 30.29 14.32 +v 8.92 30.29 12.78 +v 7.64 30.90 10.68 +v 8.30 30.90 13.14 +v 8.92 30.90 12.78 +v 8.36 30.90 10.68 +v 8.36 30.29 10.68 +v 8.92 30.29 8.57 +v 10.10 30.90 6.41 +v 8.30 30.90 8.21 +v 8.92 30.90 8.57 +v 10.46 30.90 7.03 +v 10.46 30.29 7.03 +v 12.57 30.29 6.47 +v 15.03 30.90 6.41 +v 12.57 30.90 5.75 +v 12.57 30.90 6.47 +v 14.67 30.90 7.03 +v 14.67 30.29 7.03 +v 16.21 30.29 8.57 +v 17.49 30.90 10.68 +v 16.83 30.90 8.21 +v 16.21 30.90 8.57 +v 16.78 30.90 10.68 +v 16.78 29.42 10.68 +v 16.21 29.42 12.78 +v 14.67 29.42 14.32 +v 12.57 29.42 14.89 +v 10.46 29.42 14.32 +v 8.92 29.42 12.78 +v 8.36 29.42 10.68 +v 8.92 29.42 8.57 +v 10.46 29.42 7.03 +v 12.57 29.42 6.47 +v 14.67 29.42 7.03 +v 16.21 29.42 8.57 +v 12.57 29.42 10.68 +v 16.55 0.00 -12.98 +v 16.55 7.76 -12.98 +v 17.17 7.76 -10.68 +v 17.17 0.00 -10.68 +v 14.87 0.00 -14.66 +v 14.87 7.76 -14.66 +v 12.57 0.00 -15.28 +v 12.57 7.76 -15.28 +v 10.27 0.00 -14.66 +v 10.27 7.76 -14.66 +v 8.58 0.00 -12.98 +v 8.58 7.76 -12.98 +v 7.97 0.00 -10.68 +v 7.97 7.76 -10.68 +v 8.58 0.00 -8.38 +v 8.58 7.76 -8.38 +v 10.27 0.00 -6.69 +v 10.27 7.76 -6.69 +v 12.57 0.00 -6.08 +v 12.57 7.76 -6.08 +v 14.87 0.00 -6.69 +v 14.87 7.76 -6.69 +v 16.55 0.00 -8.38 +v 16.55 7.76 -8.38 +v 16.78 7.76 -13.11 +v 16.78 8.57 -13.11 +v 17.43 8.57 -10.68 +v 17.43 7.76 -10.68 +v 15.00 7.76 -14.89 +v 15.00 8.57 -14.89 +v 12.57 7.76 -15.54 +v 12.57 8.57 -15.54 +v 10.13 7.76 -14.89 +v 10.13 8.57 -14.89 +v 8.35 7.76 -13.11 +v 8.35 8.57 -13.11 +v 7.70 7.76 -10.68 +v 7.70 8.57 -10.68 +v 8.35 7.76 -8.24 +v 8.35 8.57 -8.24 +v 10.13 7.76 -6.46 +v 10.13 8.57 -6.46 +v 12.57 7.76 -5.81 +v 12.57 8.57 -5.81 +v 15.00 7.76 -6.46 +v 15.00 8.57 -6.46 +v 16.78 7.76 -8.24 +v 16.78 8.57 -8.24 +v 17.17 8.57 -10.68 +v 16.55 8.57 -12.98 +v 14.87 8.57 -14.66 +v 12.57 8.57 -15.28 +v 10.27 8.57 -14.66 +v 8.58 8.57 -12.98 +v 7.97 8.57 -10.68 +v 8.58 8.57 -8.38 +v 10.27 8.57 -6.69 +v 12.57 8.57 -6.08 +v 14.87 8.57 -6.69 +v 16.55 8.57 -8.38 +v 16.55 16.89 -12.98 +v 17.17 16.89 -10.68 +v 14.87 16.89 -14.66 +v 12.57 16.89 -15.28 +v 10.27 16.89 -14.66 +v 8.58 16.89 -12.98 +v 7.97 16.89 -10.68 +v 8.58 16.89 -8.38 +v 10.27 16.89 -6.69 +v 12.57 16.89 -6.08 +v 14.87 16.89 -6.69 +v 16.55 16.89 -8.38 +v 17.13 21.30 -13.31 +v 17.47 21.30 -13.51 +v 18.23 21.30 -10.68 +v 17.83 21.30 -10.68 +v 15.20 21.30 -15.24 +v 15.40 21.30 -15.58 +v 12.57 21.30 -15.94 +v 12.57 21.30 -16.34 +v 9.93 21.30 -15.24 +v 9.73 21.30 -15.58 +v 8.01 21.30 -13.31 +v 7.66 21.30 -13.51 +v 7.30 21.30 -10.68 +v 6.90 21.30 -10.68 +v 8.01 21.30 -8.04 +v 7.66 21.30 -7.84 +v 9.93 21.30 -6.12 +v 9.73 21.30 -5.77 +v 12.57 21.30 -5.41 +v 12.57 21.30 -5.01 +v 15.20 21.30 -6.12 +v 15.40 21.30 -5.77 +v 17.13 21.30 -8.04 +v 17.47 21.30 -7.84 +v 16.17 24.76 -12.76 +v 16.72 24.76 -10.68 +v 14.64 24.76 -14.28 +v 12.57 24.76 -14.83 +v 10.49 24.76 -14.28 +v 8.97 24.76 -12.76 +v 8.41 24.76 -10.68 +v 8.97 24.76 -8.60 +v 10.49 24.76 -7.08 +v 12.57 24.76 -6.52 +v 14.64 24.76 -7.08 +v 16.17 24.76 -8.60 +v 16.13 28.50 -12.74 +v 16.69 28.50 -10.68 +v 14.63 28.50 -14.24 +v 12.57 28.50 -14.80 +v 10.51 28.50 -14.24 +v 9.00 28.50 -12.74 +v 8.45 28.50 -10.68 +v 9.00 28.50 -8.62 +v 10.51 28.50 -7.11 +v 12.57 28.50 -6.56 +v 14.63 28.50 -7.11 +v 16.13 28.50 -8.62 +v 17.13 17.36 -13.31 +v 17.83 17.36 -10.68 +v 15.20 17.36 -15.24 +v 12.57 17.36 -15.94 +v 9.93 17.36 -15.24 +v 8.01 17.36 -13.31 +v 7.30 17.36 -10.68 +v 8.01 17.36 -8.04 +v 9.93 17.36 -6.12 +v 12.57 17.36 -5.41 +v 15.20 17.36 -6.12 +v 17.13 17.36 -8.04 +v 17.91 20.21 -10.37 +v 17.91 19.23 -10.37 +v 17.91 19.21 -10.80 +v 17.91 20.52 -10.80 +v 17.81 19.26 -10.03 +v 17.81 19.12 -10.03 +v 17.91 19.12 -10.04 +v 17.91 19.26 -10.04 +v 17.89 20.75 -10.80 +v 17.84 20.29 -10.15 +v 17.94 20.29 -10.15 +v 17.98 20.75 -10.81 +v 17.68 19.12 -11.55 +v 17.68 19.26 -11.55 +v 17.78 19.26 -11.56 +v 17.78 19.12 -11.56 +v 17.89 19.07 -10.80 +v 17.73 19.12 -11.45 +v 17.82 19.12 -11.45 +v 17.98 19.07 -10.81 +v 18.05 19.12 -10.16 +v 18.08 19.23 -10.39 +v 18.05 19.26 -10.16 +v 17.98 20.21 -10.38 +v 17.98 20.52 -10.81 +v 17.93 19.26 -11.46 +v 18.01 19.24 -11.24 +v 17.93 19.12 -11.46 +v 18.09 19.07 -10.82 +v 18.09 19.21 -10.82 +v 17.83 20.21 -11.23 +v 17.83 19.24 -11.23 +v 17.73 20.29 -11.45 +v 17.82 20.29 -11.45 +v 17.84 19.12 -10.15 +v 17.94 19.12 -10.15 +v 17.90 20.21 -11.23 +v 17.98 19.23 -10.38 +v 17.90 19.24 -11.23 +v 17.98 19.21 -10.81 +v 17.82 19.26 -11.45 +v 17.73 19.26 -11.45 +v 17.84 19.26 -10.15 +v 17.94 19.26 -10.15 +v 18.02 19.12 -10.05 +v 18.02 19.26 -10.05 +v 17.88 19.26 -11.57 +v 17.88 19.12 -11.57 +v 12.87 20.21 -16.02 +v 12.87 19.23 -16.02 +v 12.44 19.21 -16.02 +v 12.44 20.52 -16.02 +v 13.21 19.26 -15.92 +v 13.21 19.12 -15.92 +v 13.20 19.12 -16.02 +v 13.20 19.26 -16.02 +v 12.44 20.75 -16.00 +v 13.10 20.29 -15.95 +v 13.09 20.29 -16.05 +v 12.43 20.75 -16.10 +v 11.69 19.12 -15.79 +v 11.69 19.26 -15.79 +v 11.68 19.26 -15.89 +v 11.68 19.12 -15.89 +v 12.44 19.07 -16.00 +v 11.80 19.12 -15.84 +v 11.79 19.12 -15.94 +v 12.43 19.07 -16.10 +v 13.08 19.12 -16.16 +v 12.85 19.23 -16.20 +v 13.08 19.26 -16.16 +v 12.86 20.21 -16.09 +v 12.43 20.52 -16.10 +v 11.78 19.26 -16.04 +v 12.00 19.24 -16.12 +v 11.78 19.12 -16.04 +v 12.42 19.07 -16.20 +v 12.42 19.21 -16.20 +v 12.01 20.21 -15.94 +v 12.01 19.24 -15.94 +v 11.80 20.29 -15.84 +v 11.79 20.29 -15.94 +v 13.10 19.12 -15.95 +v 13.09 19.12 -16.05 +v 12.01 20.21 -16.01 +v 12.86 19.23 -16.09 +v 12.01 19.24 -16.01 +v 12.43 19.21 -16.10 +v 11.79 19.26 -15.94 +v 11.80 19.26 -15.84 +v 13.10 19.26 -15.95 +v 13.09 19.26 -16.05 +v 13.19 19.12 -16.13 +v 13.19 19.26 -16.13 +v 11.67 19.26 -16.00 +v 11.67 19.12 -16.00 +v 9.24 23.34 -12.52 +v 8.56 24.92 -12.99 +v 9.10 24.92 -13.76 +v 9.78 23.34 -13.29 +v 9.53 28.41 -12.29 +v 8.63 28.41 -12.92 +v 9.18 28.41 -13.70 +v 10.08 28.41 -13.07 +v 12.87 27.21 -14.81 +v 12.87 26.24 -14.81 +v 12.44 26.21 -14.82 +v 12.44 27.52 -14.82 +v 13.21 26.26 -14.72 +v 13.21 26.12 -14.72 +v 13.20 26.12 -14.82 +v 13.20 26.26 -14.82 +v 12.44 27.75 -14.80 +v 13.10 27.30 -14.75 +v 13.09 27.30 -14.85 +v 12.43 27.75 -14.89 +v 11.69 26.12 -14.59 +v 11.69 26.26 -14.59 +v 11.68 26.26 -14.69 +v 11.68 26.12 -14.69 +v 12.44 26.07 -14.80 +v 11.80 26.12 -14.64 +v 11.79 26.12 -14.73 +v 12.43 26.07 -14.89 +v 13.08 26.12 -14.96 +v 12.85 26.24 -14.99 +v 13.08 26.26 -14.96 +v 12.86 27.21 -14.89 +v 12.43 27.52 -14.89 +v 11.78 26.26 -14.84 +v 12.00 26.25 -14.92 +v 11.78 26.12 -14.84 +v 12.42 26.07 -15.00 +v 12.42 26.21 -15.00 +v 12.01 27.21 -14.74 +v 12.01 26.25 -14.74 +v 11.80 27.30 -14.64 +v 11.79 27.30 -14.73 +v 13.10 26.12 -14.75 +v 13.09 26.12 -14.85 +v 12.01 27.21 -14.81 +v 12.86 26.24 -14.89 +v 12.01 26.25 -14.81 +v 12.43 26.21 -14.89 +v 11.79 26.26 -14.73 +v 11.80 26.26 -14.64 +v 13.10 26.26 -14.75 +v 13.09 26.26 -14.85 +v 13.19 26.12 -14.93 +v 13.19 26.26 -14.93 +v 11.67 26.26 -14.79 +v 11.67 26.12 -14.79 +v 14.41 23.34 -14.01 +v 14.88 24.92 -14.68 +v 15.65 24.92 -14.14 +v 15.18 23.34 -13.46 +v 14.18 28.41 -13.71 +v 14.81 28.41 -14.61 +v 15.59 28.41 -14.07 +v 14.96 28.41 -13.17 +v 8.43 27.21 -10.98 +v 8.43 26.24 -10.98 +v 8.42 26.21 -10.55 +v 8.42 27.52 -10.55 +v 8.52 26.26 -11.32 +v 8.52 26.12 -11.32 +v 8.42 26.12 -11.31 +v 8.42 26.26 -11.31 +v 8.45 27.75 -10.55 +v 8.49 27.30 -11.21 +v 8.39 27.30 -11.20 +v 8.35 27.75 -10.54 +v 8.65 26.12 -9.80 +v 8.65 26.26 -9.80 +v 8.56 26.26 -9.79 +v 8.56 26.12 -9.79 +v 8.45 26.07 -10.55 +v 8.61 26.12 -9.91 +v 8.51 26.12 -9.90 +v 8.35 26.07 -10.54 +v 8.29 26.12 -11.19 +v 8.25 26.24 -10.96 +v 8.29 26.26 -11.19 +v 8.35 27.21 -10.97 +v 8.35 27.52 -10.54 +v 8.40 26.26 -9.89 +v 8.32 26.25 -10.11 +v 8.40 26.12 -9.89 +v 8.24 26.07 -10.53 +v 8.24 26.21 -10.53 +v 8.50 27.21 -10.13 +v 8.50 26.25 -10.13 +v 8.61 27.30 -9.91 +v 8.51 27.30 -9.90 +v 8.49 26.12 -11.21 +v 8.39 26.12 -11.20 +v 8.43 27.21 -10.12 +v 8.35 26.24 -10.97 +v 8.43 26.25 -10.12 +v 8.35 26.21 -10.54 +v 8.51 26.26 -9.90 +v 8.61 26.26 -9.91 +v 8.49 26.26 -11.21 +v 8.39 26.26 -11.20 +v 8.32 26.12 -11.30 +v 8.32 26.26 -11.30 +v 8.45 26.26 -9.78 +v 8.45 26.12 -9.78 +v 13.04 12.70 -6.81 +v 13.04 14.28 -5.99 +v 12.09 14.28 -5.99 +v 12.09 12.70 -6.81 +v 13.04 17.34 -6.74 +v 13.04 17.34 -5.64 +v 12.09 17.34 -5.64 +v 12.09 17.34 -6.74 +v 8.98 12.70 -12.20 +v 8.27 14.28 -12.61 +v 8.74 14.28 -13.43 +v 9.46 12.70 -13.02 +v 8.92 17.34 -12.24 +v 7.97 17.34 -12.79 +v 8.44 17.34 -13.61 +v 9.39 17.34 -13.06 +v 12.09 12.70 -14.54 +v 12.09 14.28 -15.36 +v 13.04 14.28 -15.36 +v 13.04 12.70 -14.54 +v 12.09 17.34 -14.62 +v 12.09 17.34 -15.71 +v 13.04 17.34 -15.71 +v 13.04 17.34 -14.62 +v 10.73 23.34 -7.35 +v 10.25 24.92 -6.67 +v 9.48 24.92 -7.22 +v 9.95 23.34 -7.89 +v 10.95 28.41 -7.65 +v 10.32 28.41 -6.74 +v 9.55 28.41 -7.29 +v 10.18 28.41 -8.19 +v 9.46 12.70 -8.34 +v 8.74 14.28 -7.92 +v 8.27 14.28 -8.74 +v 8.98 12.70 -9.15 +v 9.39 17.34 -8.30 +v 8.44 17.34 -7.75 +v 7.97 17.34 -8.57 +v 8.92 17.34 -9.12 +v 7.23 20.21 -10.98 +v 7.23 19.23 -10.98 +v 7.22 19.21 -10.55 +v 7.22 20.52 -10.55 +v 7.32 19.26 -11.32 +v 7.32 19.12 -11.32 +v 7.22 19.12 -11.31 +v 7.22 19.26 -11.31 +v 7.24 20.75 -10.55 +v 7.29 20.29 -11.21 +v 7.19 20.29 -11.20 +v 7.15 20.75 -10.54 +v 7.45 19.12 -9.80 +v 7.45 19.26 -9.80 +v 7.35 19.26 -9.79 +v 7.35 19.12 -9.79 +v 7.24 19.07 -10.55 +v 7.41 19.12 -9.91 +v 7.31 19.12 -9.90 +v 7.15 19.07 -10.54 +v 7.09 19.12 -11.19 +v 7.05 19.23 -10.96 +v 7.09 19.26 -11.19 +v 7.15 20.21 -10.97 +v 7.15 20.52 -10.54 +v 7.20 19.26 -9.89 +v 7.12 19.24 -10.11 +v 7.20 19.12 -9.89 +v 7.04 19.07 -10.53 +v 7.04 19.21 -10.53 +v 7.30 20.21 -10.13 +v 7.30 19.24 -10.13 +v 7.41 20.29 -9.91 +v 7.31 20.29 -9.90 +v 7.29 19.12 -11.21 +v 7.19 19.12 -11.20 +v 7.23 20.21 -10.12 +v 7.15 19.23 -10.97 +v 7.23 19.24 -10.12 +v 7.15 19.21 -10.54 +v 7.31 19.26 -9.90 +v 7.41 19.26 -9.91 +v 7.29 19.26 -11.21 +v 7.19 19.26 -11.20 +v 7.11 19.12 -11.30 +v 7.11 19.26 -11.30 +v 7.25 19.26 -9.78 +v 7.25 19.12 -9.78 +v 12.26 27.21 -6.54 +v 12.26 26.24 -6.54 +v 12.69 26.21 -6.53 +v 12.69 27.52 -6.53 +v 11.92 26.26 -6.63 +v 11.92 26.12 -6.63 +v 11.93 26.12 -6.53 +v 11.93 26.26 -6.53 +v 12.69 27.75 -6.56 +v 12.03 27.30 -6.60 +v 12.04 27.30 -6.51 +v 12.70 27.75 -6.46 +v 13.44 26.12 -6.76 +v 13.44 26.26 -6.76 +v 13.45 26.26 -6.67 +v 13.45 26.12 -6.67 +v 12.69 26.07 -6.56 +v 13.34 26.12 -6.72 +v 13.34 26.12 -6.62 +v 12.70 26.07 -6.46 +v 12.05 26.12 -6.40 +v 12.28 26.24 -6.36 +v 12.05 26.26 -6.40 +v 12.27 27.21 -6.47 +v 12.70 27.52 -6.46 +v 13.35 26.26 -6.51 +v 13.13 26.25 -6.43 +v 13.35 26.12 -6.51 +v 12.71 26.07 -6.35 +v 12.71 26.21 -6.35 +v 13.12 27.21 -6.61 +v 13.12 26.25 -6.61 +v 13.34 27.30 -6.72 +v 13.34 27.30 -6.62 +v 12.03 26.12 -6.60 +v 12.04 26.12 -6.51 +v 13.12 27.21 -6.54 +v 12.27 26.24 -6.47 +v 13.12 26.25 -6.54 +v 12.70 26.21 -6.46 +v 13.34 26.26 -6.62 +v 13.34 26.26 -6.72 +v 12.03 26.26 -6.60 +v 12.04 26.26 -6.51 +v 11.94 26.12 -6.43 +v 11.94 26.26 -6.43 +v 13.46 26.26 -6.56 +v 13.46 26.12 -6.56 +v 16.15 12.70 -9.15 +v 16.86 14.28 -8.74 +v 16.39 14.28 -7.92 +v 15.67 12.70 -8.34 +v 16.21 17.34 -9.12 +v 17.17 17.34 -8.57 +v 16.69 17.34 -7.75 +v 15.74 17.34 -8.30 +v 12.26 20.21 -5.34 +v 12.26 19.23 -5.34 +v 12.69 19.21 -5.33 +v 12.69 20.52 -5.33 +v 11.92 19.26 -5.43 +v 11.92 19.12 -5.43 +v 11.93 19.12 -5.33 +v 11.93 19.26 -5.33 +v 12.69 20.75 -5.36 +v 12.03 20.29 -5.40 +v 12.04 20.29 -5.30 +v 12.70 20.75 -5.26 +v 13.44 19.12 -5.56 +v 13.44 19.26 -5.56 +v 13.45 19.26 -5.47 +v 13.45 19.12 -5.47 +v 12.69 19.07 -5.36 +v 13.34 19.12 -5.52 +v 13.34 19.12 -5.42 +v 12.70 19.07 -5.26 +v 12.05 19.12 -5.20 +v 12.28 19.23 -5.16 +v 12.05 19.26 -5.20 +v 12.27 20.21 -5.26 +v 12.70 20.52 -5.26 +v 13.35 19.26 -5.31 +v 13.13 19.24 -5.23 +v 13.35 19.12 -5.31 +v 12.71 19.07 -5.15 +v 12.71 19.21 -5.15 +v 13.12 20.21 -5.41 +v 13.12 19.24 -5.41 +v 13.34 20.29 -5.52 +v 13.34 20.29 -5.42 +v 12.03 19.12 -5.40 +v 12.04 19.12 -5.30 +v 13.12 20.21 -5.34 +v 12.27 19.23 -5.26 +v 13.12 19.24 -5.34 +v 12.70 19.21 -5.26 +v 13.34 19.26 -5.42 +v 13.34 19.26 -5.52 +v 12.03 19.26 -5.40 +v 12.04 19.26 -5.30 +v 11.94 19.12 -5.23 +v 11.94 19.26 -5.23 +v 13.46 19.26 -5.36 +v 13.46 19.12 -5.36 +v 15.89 23.34 -8.84 +v 16.57 24.92 -8.36 +v 16.03 24.92 -7.59 +v 15.35 23.34 -8.06 +v 15.60 28.41 -9.06 +v 16.50 28.41 -8.43 +v 15.96 28.41 -7.66 +v 15.06 28.41 -8.29 +v 16.70 27.21 -10.37 +v 16.70 26.24 -10.37 +v 16.71 26.21 -10.80 +v 16.71 27.52 -10.80 +v 16.61 26.26 -10.03 +v 16.61 26.12 -10.03 +v 16.71 26.12 -10.04 +v 16.71 26.26 -10.04 +v 16.69 27.75 -10.80 +v 16.64 27.30 -10.15 +v 16.74 27.30 -10.15 +v 16.78 27.75 -10.81 +v 16.48 26.12 -11.55 +v 16.48 26.26 -11.55 +v 16.58 26.26 -11.56 +v 16.58 26.12 -11.56 +v 16.69 26.07 -10.80 +v 16.53 26.12 -11.45 +v 16.62 26.12 -11.45 +v 16.78 26.07 -10.81 +v 16.84 26.12 -10.16 +v 16.88 26.24 -10.39 +v 16.84 26.26 -10.16 +v 16.78 27.21 -10.38 +v 16.78 27.52 -10.81 +v 16.73 26.26 -11.46 +v 16.81 26.25 -11.24 +v 16.73 26.12 -11.46 +v 16.89 26.07 -10.82 +v 16.89 26.21 -10.82 +v 16.63 27.21 -11.23 +v 16.63 26.25 -11.23 +v 16.53 27.30 -11.45 +v 16.62 27.30 -11.45 +v 16.64 26.12 -10.15 +v 16.74 26.12 -10.15 +v 16.70 27.21 -11.23 +v 16.78 26.24 -10.38 +v 16.70 26.25 -11.23 +v 16.78 26.21 -10.81 +v 16.62 26.26 -11.45 +v 16.53 26.26 -11.45 +v 16.64 26.26 -10.15 +v 16.74 26.26 -10.15 +v 16.82 26.12 -10.05 +v 16.82 26.26 -10.05 +v 16.68 26.26 -11.57 +v 16.68 26.12 -11.57 +v 15.67 12.70 -13.02 +v 16.39 14.28 -13.43 +v 16.86 14.28 -12.61 +v 16.15 12.70 -12.20 +v 15.74 17.34 -13.06 +v 16.69 17.34 -13.61 +v 17.17 17.34 -12.79 +v 16.21 17.34 -12.24 +v 16.83 28.50 -13.14 +v 16.83 30.29 -13.14 +v 17.49 30.29 -10.68 +v 17.49 28.50 -10.68 +v 15.03 28.50 -14.94 +v 15.03 30.29 -14.94 +v 12.57 28.50 -15.60 +v 12.57 30.29 -15.60 +v 10.10 28.50 -14.94 +v 10.10 30.29 -14.94 +v 8.30 28.50 -13.14 +v 8.30 30.29 -13.14 +v 7.64 28.50 -10.68 +v 7.64 30.29 -10.68 +v 8.30 28.50 -8.21 +v 8.30 30.29 -8.21 +v 10.10 28.50 -6.41 +v 10.10 30.29 -6.41 +v 12.57 28.50 -5.75 +v 12.57 30.29 -5.75 +v 15.03 28.50 -6.41 +v 15.03 30.29 -6.41 +v 16.83 28.50 -8.21 +v 16.83 30.29 -8.21 +v 16.21 30.29 -12.78 +v 16.78 30.29 -10.68 +v 15.03 30.90 -14.94 +v 14.67 30.90 -14.32 +v 16.21 30.90 -12.78 +v 16.83 30.90 -13.14 +v 12.57 30.29 -14.89 +v 14.67 30.29 -14.32 +v 10.10 30.90 -14.94 +v 10.46 30.90 -14.32 +v 12.57 30.90 -14.89 +v 12.57 30.90 -15.60 +v 8.92 30.29 -12.78 +v 10.46 30.29 -14.32 +v 7.64 30.90 -10.68 +v 8.36 30.90 -10.68 +v 8.92 30.90 -12.78 +v 8.30 30.90 -13.14 +v 8.92 30.29 -8.57 +v 8.36 30.29 -10.68 +v 10.10 30.90 -6.41 +v 10.46 30.90 -7.03 +v 8.92 30.90 -8.57 +v 8.30 30.90 -8.21 +v 12.57 30.29 -6.47 +v 10.46 30.29 -7.03 +v 15.03 30.90 -6.41 +v 14.67 30.90 -7.03 +v 12.57 30.90 -6.47 +v 12.57 30.90 -5.75 +v 16.21 30.29 -8.57 +v 14.67 30.29 -7.03 +v 17.49 30.90 -10.68 +v 16.78 30.90 -10.68 +v 16.21 30.90 -8.57 +v 16.83 30.90 -8.21 +v 16.21 29.42 -12.78 +v 16.78 29.42 -10.68 +v 14.67 29.42 -14.32 +v 12.57 29.42 -14.89 +v 10.46 29.42 -14.32 +v 8.92 29.42 -12.78 +v 8.36 29.42 -10.68 +v 8.92 29.42 -8.57 +v 10.46 29.42 -7.03 +v 12.57 29.42 -6.47 +v 14.67 29.42 -7.03 +v 16.21 29.42 -8.57 +v 12.57 29.42 -10.68 +# 4553 vertices + +vn -1.00 0.00 -0.00 +vn -0.48 0.00 -0.88 +vn -0.17 0.00 -0.99 +vn 0.00 0.00 -1.00 +vn 0.17 0.00 -0.99 +vn 0.48 0.00 -0.88 +vn 1.00 0.00 -0.00 +vn 0.48 0.00 0.88 +vn 0.17 0.00 0.99 +vn 0.00 0.00 1.00 +vn -0.17 0.00 0.99 +vn -0.48 0.00 0.88 +vn -0.73 0.00 -0.69 +vn -0.27 0.00 -0.96 +vn -0.08 0.00 -1.00 +vn 0.08 0.00 -1.00 +vn 0.27 0.00 -0.96 +vn 0.73 0.00 -0.69 +vn 0.73 0.00 0.69 +vn 0.27 0.00 0.96 +vn 0.08 0.00 1.00 +vn -0.08 0.00 1.00 +vn -0.27 0.00 0.96 +vn -0.73 0.00 0.69 +vn -0.72 0.00 0.69 +vn 0.00 -1.00 -0.00 +vn 0.00 1.00 -0.00 +vn -0.60 0.56 -0.57 +vn -0.26 0.33 -0.91 +vn -0.07 0.25 -0.96 +vn 0.07 0.25 -0.96 +vn 0.26 0.33 -0.91 +vn 0.60 0.56 -0.57 +vn 0.60 0.56 0.57 +vn 0.26 0.33 0.91 +vn 0.07 0.25 0.96 +vn -0.07 0.25 0.96 +vn -0.26 0.33 0.91 +vn -0.60 0.56 0.57 +vn -0.73 0.01 -0.69 +vn -0.27 0.01 -0.96 +vn -0.08 0.01 -1.00 +vn -0.07 0.01 -1.00 +vn 0.08 0.01 -1.00 +vn 0.27 0.01 -0.96 +vn 0.73 0.01 -0.69 +vn 0.72 0.01 0.69 +vn 0.73 0.01 0.69 +vn 0.27 0.01 0.96 +vn 0.08 0.01 1.00 +vn -0.08 0.01 1.00 +vn -0.07 0.01 1.00 +vn -0.27 0.01 0.96 +vn -0.73 0.01 0.69 +vn -0.72 0.01 0.69 +vn -0.30 -0.91 -0.29 +vn -0.18 -0.75 -0.64 +vn -0.18 -0.74 -0.64 +vn -0.06 -0.65 -0.76 +vn 0.06 -0.65 -0.76 +vn 0.18 -0.75 -0.64 +vn 0.18 -0.74 -0.64 +vn 0.30 -0.91 -0.29 +vn 0.30 -0.91 0.29 +vn 0.18 -0.74 0.64 +vn 0.18 -0.75 0.64 +vn 0.06 -0.65 0.76 +vn -0.06 -0.65 0.76 +vn -0.18 -0.74 0.64 +vn -0.18 -0.75 0.64 +vn -0.30 -0.91 0.29 +vn -1.00 0.00 0.06 +vn -0.02 0.00 1.00 +vn -0.02 0.65 0.76 +vn 0.02 0.00 -1.00 +vn 0.00 -0.99 -0.12 +vn -0.85 0.00 0.52 +vn -0.95 0.12 0.30 +vn -0.62 0.00 -0.78 +vn -0.76 -0.16 -0.63 +vn -0.83 0.00 -0.56 +vn 0.02 0.66 -0.75 +vn -0.00 -0.99 0.12 +vn -0.72 0.09 -0.69 +vn -0.96 -0.21 0.19 +vn 0.02 -0.64 -0.77 +vn -0.02 -0.64 0.77 +vn -0.00 0.99 0.13 +vn 0.00 1.00 -0.10 +vn 0.00 0.99 -0.17 +vn 0.01 0.99 -0.17 +vn -0.00 0.99 0.10 +vn -0.74 0.00 0.67 +vn -0.75 0.00 0.67 +vn -0.54 0.00 -0.84 +vn -0.00 0.00 -1.00 +vn -0.96 0.00 -0.29 +vn -0.95 0.00 -0.30 +vn -0.31 0.95 -0.10 +vn 0.95 0.00 0.30 +vn 0.96 0.00 0.29 +vn 0.03 -1.00 0.01 +vn -0.05 0.00 -1.00 +vn -0.03 0.04 -1.00 +vn 0.10 0.00 -1.00 +vn 0.07 -0.06 -1.00 +vn 0.05 0.00 -1.00 +vn 0.31 0.95 0.10 +vn -0.04 -1.00 -0.01 +vn 0.08 0.04 -1.00 +vn -0.02 -0.06 -1.00 +vn 0.32 -0.94 0.10 +vn -0.32 -0.94 -0.10 +vn -0.04 1.00 -0.01 +vn 0.03 1.00 0.01 +vn 0.05 1.00 0.01 +vn -0.03 1.00 -0.01 +vn -0.07 0.00 -1.00 +vn 0.12 0.00 -0.99 +vn 0.33 -0.45 -0.83 +vn 0.19 -0.00 0.98 +vn 0.37 0.03 -0.93 +vn -0.19 0.00 -0.98 +vn -0.01 0.00 -1.00 +vn -0.96 0.00 -0.30 +vn 0.31 0.95 0.09 +vn -0.18 -0.35 -0.92 +vn 0.37 -0.00 -0.93 +vn -0.19 0.02 -0.98 +vn -0.37 0.00 0.93 +vn 1.00 0.00 -0.06 +vn 0.02 0.65 -0.76 +vn 0.85 0.00 -0.52 +vn 0.95 0.12 -0.30 +vn 0.62 0.00 0.78 +vn 0.76 -0.16 0.63 +vn 0.83 0.00 0.56 +vn 0.82 0.00 0.57 +vn -0.02 0.66 0.75 +vn 0.72 0.09 0.69 +vn 0.96 -0.21 -0.19 +vn 0.00 0.99 -0.13 +vn -0.00 1.00 0.10 +vn -0.00 0.99 0.17 +vn 0.00 0.99 -0.10 +vn 0.75 0.00 -0.67 +vn 0.54 0.00 0.84 +vn 0.00 -0.30 0.95 +vn 0.00 -0.07 1.00 +vn 0.38 -0.49 -0.78 +vn 0.16 0.00 0.99 +vn 0.44 -0.12 -0.89 +vn -0.16 0.00 -0.99 +vn 0.00 -0.30 -0.95 +vn 0.00 -0.07 -1.00 +vn 0.18 -0.35 0.92 +vn -0.37 -0.00 0.93 +vn 0.19 0.02 0.98 +vn 0.37 0.00 -0.93 +vn 0.38 -0.49 0.78 +vn -0.16 0.00 0.99 +vn 0.44 -0.12 0.89 +vn 0.16 0.00 -0.99 +vn 0.01 0.00 1.00 +vn 0.96 0.00 0.30 +vn -0.03 -1.00 -0.01 +vn 0.05 0.00 1.00 +vn 0.03 0.04 1.00 +vn -0.10 0.00 1.00 +vn -0.07 -0.06 1.00 +vn -0.05 0.00 1.00 +vn -0.31 0.95 -0.09 +vn 0.04 -1.00 0.01 +vn -0.08 0.04 1.00 +vn 0.02 -0.06 1.00 +vn 0.04 1.00 0.01 +vn -0.05 1.00 -0.02 +vn 0.07 0.00 1.00 +vn -0.12 0.00 0.99 +vn -0.38 -0.49 0.78 +vn -0.44 -0.12 0.89 +vn -0.43 -0.12 0.89 +vn -0.33 -0.45 0.83 +vn -0.19 -0.00 -0.98 +vn -0.37 0.03 0.93 +vn 0.19 0.00 0.98 +vn -0.38 -0.49 -0.78 +vn -0.44 -0.12 -0.89 +vn -0.43 -0.12 -0.89 +vn 0.72 0.00 0.69 +vn -0.07 0.00 1.00 +vn -0.72 0.00 -0.69 +vn 0.07 0.00 -1.00 +vn 0.72 0.00 -0.69 +vn 0.44 0.00 -0.90 +vn 0.44 0.00 0.90 +vn -0.44 0.00 0.90 +vn -0.44 0.00 -0.90 +vn 0.50 0.87 -0.00 +vn 0.00 0.45 -0.89 +vn -0.50 0.87 -0.00 +vn 0.00 0.42 0.91 +vn 0.08 1.00 -0.00 +vn 0.04 0.55 0.83 +vn -0.00 0.55 0.83 +vn 0.01 0.01 1.00 +vn -0.00 0.55 -0.83 +vn 0.04 0.55 -0.83 +vn 0.01 0.01 -1.00 +vn -0.08 1.00 -0.00 +vn -0.04 0.55 0.83 +vn -0.01 0.01 1.00 +vn -0.04 0.55 -0.83 +vn -0.01 0.01 -1.00 +vn -0.06 0.60 -0.79 +vn -0.91 -0.41 0.00 +vn -0.10 0.98 -0.19 +vn -0.06 0.60 0.79 +vn -0.91 -0.41 -0.00 +vn -0.10 0.98 0.19 +vn -0.05 0.61 -0.79 +vn -0.94 -0.35 -0.00 +vn -0.08 0.98 -0.19 +vn -0.05 0.61 0.79 +vn -0.08 0.98 0.19 +vn -0.04 0.61 -0.79 +vn -0.03 0.61 -0.79 +vn -0.97 -0.25 0.00 +vn -0.97 -0.25 -0.00 +vn -0.06 0.98 -0.19 +vn -0.04 0.61 0.79 +vn -0.03 0.61 0.79 +vn -0.06 0.98 0.19 +vn -0.01 0.61 -0.79 +vn -1.00 -0.07 -0.00 +vn -0.02 0.98 -0.19 +vn -0.01 0.61 0.79 +vn -0.02 0.98 0.19 +vn -1.00 -0.07 0.00 +vn -0.02 0.61 -0.79 +vn -0.99 -0.11 -0.00 +vn -0.02 0.61 0.79 +vn -0.99 -0.11 0.00 +vn 0.06 0.60 -0.79 +vn 0.91 -0.41 0.00 +vn 0.10 0.98 -0.19 +vn 0.06 0.60 0.79 +vn 0.91 -0.41 -0.00 +vn 0.10 0.98 0.19 +vn 0.05 0.61 -0.79 +vn 0.94 -0.35 -0.00 +vn 0.08 0.98 -0.19 +vn 0.05 0.61 0.79 +vn 0.94 -0.35 0.00 +vn 0.08 0.98 0.19 +vn 0.03 0.61 -0.79 +vn 0.04 0.61 -0.79 +vn 0.97 -0.25 0.00 +vn 0.06 0.98 -0.19 +vn 0.03 0.61 0.79 +vn 0.97 -0.25 -0.00 +vn 0.06 0.98 0.19 +vn 0.04 0.61 0.79 +vn 0.01 0.61 -0.79 +vn 1.00 -0.07 -0.00 +vn 0.02 0.98 -0.19 +vn 0.01 0.61 0.79 +vn 0.02 0.98 0.19 +vn 1.00 -0.07 0.00 +vn 0.02 0.61 -0.79 +vn 0.99 -0.11 -0.00 +vn 0.02 0.61 0.79 +vn 0.99 -0.11 0.00 +vn 0.10 0.98 -0.20 +vn 0.10 0.98 0.20 +vn 0.09 0.59 -0.80 +vn -0.82 0.57 0.00 +vn -0.82 0.57 -0.00 +vn 0.15 0.97 -0.20 +vn 0.09 0.59 0.80 +vn 0.15 0.97 0.20 +vn -0.09 0.59 -0.80 +vn 0.82 0.57 0.00 +vn -0.15 0.97 -0.20 +vn -0.09 0.59 0.80 +vn 0.82 0.57 -0.00 +vn -0.15 0.97 0.20 +vn -0.57 0.82 -0.00 +vn 0.08 -1.00 -0.00 +vn 0.57 0.82 -0.00 +vn -0.08 -1.00 -0.00 +vn 0.59 -0.81 -0.00 +vn -0.59 -0.81 -0.00 +vn 0.06 1.00 -0.00 +vn 0.10 0.99 -0.00 +vn -0.06 1.00 -0.00 +vn -0.07 -1.00 -0.00 +vn 0.07 -1.00 -0.00 +vn 0.00 0.37 0.93 +vn 0.00 -0.97 -0.26 +vn 0.00 0.37 -0.93 +vn 0.00 -0.97 0.26 +vn 0.00 -0.36 -0.93 +vn 0.00 -0.36 0.93 +vn 0.00 0.96 0.28 +vn 0.00 0.98 -0.21 +vn 0.00 0.94 -0.35 +vn 0.00 0.98 0.22 +vn 0.00 0.96 -0.28 +vn 0.00 0.98 0.21 +vn 0.00 0.94 0.35 +vn 0.00 0.98 -0.22 +vn 0.11 0.99 -0.00 +vn -0.10 0.99 -0.00 +vn 1.00 0.04 -0.00 +vn 0.87 0.50 -0.00 +vn -1.00 -0.04 -0.00 +vn -0.87 -0.50 -0.00 +vn 0.40 0.92 -0.00 +vn -0.42 -0.91 -0.00 +vn -0.40 0.92 -0.00 +vn 0.42 -0.91 -0.00 +vn -0.87 0.50 -0.00 +vn 0.87 -0.50 -0.00 +vn -1.00 0.04 -0.00 +vn 1.00 -0.04 -0.00 +vn 0.02 0.05 -1.00 +vn 0.95 -0.05 0.30 +vn -0.02 -0.01 1.00 +vn -0.94 0.18 -0.29 +vn 0.03 -0.06 -1.00 +vn 0.02 -0.06 -1.00 +vn 0.96 0.05 0.27 +vn -0.02 0.01 1.00 +vn -0.96 -0.22 -0.19 +vn 0.00 -1.00 -0.05 +vn 0.00 1.00 0.05 +vn 0.00 -1.00 0.05 +vn 0.00 1.00 -0.05 +vn 0.02 -1.00 -0.00 +vn -0.02 1.00 -0.00 +vn -0.01 1.00 -0.00 +vn -0.01 -1.00 -0.00 +vn 0.01 1.00 -0.00 +vn 0.02 0.05 1.00 +vn 0.95 -0.05 -0.30 +vn -0.02 -0.01 -1.00 +vn -0.94 0.18 0.29 +vn 0.03 -0.06 1.00 +vn 0.96 0.05 -0.27 +vn -0.02 0.01 -1.00 +vn -0.96 -0.22 0.19 +vn -0.96 -0.22 0.18 +vn 0.01 -1.00 -0.00 +vn -0.02 -1.00 -0.00 +vn 0.02 1.00 -0.00 +vn -0.99 0.12 -0.00 +vn -1.00 0.01 0.04 +vn -0.99 -0.10 0.07 +vn 0.00 0.01 1.00 +vn 0.00 -0.00 1.00 +vn 1.00 0.01 0.01 +vn 1.00 -0.03 0.02 +vn 0.00 0.04 -1.00 +vn 0.00 0.01 -1.00 +vn 0.00 -0.02 -1.00 +vn 0.13 -0.99 -0.00 +vn -0.13 0.99 -0.00 +vn -0.13 -0.99 -0.00 +vn 0.13 0.99 -0.00 +vn -0.07 1.00 -0.00 +vn 0.07 1.00 -0.00 +vn 0.00 -0.67 -0.74 +vn 0.00 -0.13 -0.99 +vn 0.00 0.67 -0.74 +vn 0.00 0.13 -0.99 +vn 0.00 0.12 -0.99 +vn -1.00 0.01 -0.04 +vn -0.99 -0.10 -0.07 +vn 0.00 -0.00 -1.00 +vn 1.00 0.01 -0.01 +vn 1.00 -0.03 -0.02 +vn 0.00 0.04 1.00 +vn 0.00 -0.02 1.00 +vn 0.72 0.01 -0.69 +vn -0.72 0.01 -0.69 +vn -1.00 0.00 -0.06 +vn -0.02 0.00 -1.00 +vn -0.02 0.65 -0.76 +vn 0.02 0.00 1.00 +vn 0.00 -0.99 0.12 +vn -0.85 0.00 -0.52 +vn -0.95 0.12 -0.30 +vn -0.62 0.00 0.78 +vn -0.76 -0.16 0.63 +vn -0.83 0.00 0.56 +vn 0.02 0.66 0.75 +vn -0.00 -0.99 -0.12 +vn -0.72 0.09 0.69 +vn -0.96 -0.21 -0.19 +vn 0.02 -0.64 0.77 +vn -0.02 -0.64 -0.77 +vn -0.00 0.99 -0.13 +vn 0.00 1.00 0.10 +vn 0.00 0.99 0.17 +vn 0.01 0.99 0.17 +vn -0.00 0.99 -0.10 +vn -0.74 0.00 -0.67 +vn -0.75 0.00 -0.67 +vn -0.54 0.00 0.84 +vn -0.00 0.00 1.00 +vn -0.96 0.00 0.29 +vn -0.95 0.00 0.30 +vn -0.31 0.95 0.10 +vn 0.95 0.00 -0.30 +vn 0.96 0.00 -0.29 +vn 0.03 -1.00 -0.01 +vn -0.03 0.04 1.00 +vn 0.10 0.00 1.00 +vn 0.07 -0.06 1.00 +vn 0.31 0.95 -0.10 +vn -0.04 -1.00 0.01 +vn 0.08 0.04 1.00 +vn -0.02 -0.06 1.00 +vn 0.32 -0.94 -0.10 +vn -0.32 -0.94 0.10 +vn -0.04 1.00 0.01 +vn 0.03 1.00 -0.01 +vn 0.05 1.00 -0.01 +vn -0.03 1.00 0.01 +vn 0.12 0.00 0.99 +vn 0.33 -0.45 0.83 +vn 0.19 -0.00 -0.98 +vn 0.37 0.03 0.93 +vn -0.19 0.00 0.98 +vn -0.01 0.00 1.00 +vn -0.96 0.00 0.30 +vn 0.31 0.95 -0.09 +vn -0.18 -0.35 0.92 +vn 0.37 -0.00 0.93 +vn -0.19 0.02 0.98 +vn -0.37 0.00 -0.93 +vn 1.00 0.00 0.06 +vn 0.02 0.65 0.76 +vn 0.85 0.00 0.52 +vn 0.95 0.12 0.30 +vn 0.62 0.00 -0.78 +vn 0.76 -0.16 -0.63 +vn 0.83 0.00 -0.56 +vn 0.82 0.00 -0.57 +vn -0.02 0.66 -0.75 +vn 0.72 0.09 -0.69 +vn 0.96 -0.21 0.19 +vn 0.00 0.99 0.13 +vn -0.00 1.00 -0.10 +vn -0.00 0.99 -0.17 +vn 0.00 0.99 0.10 +vn 0.75 0.00 0.67 +vn 0.54 0.00 -0.84 +vn 0.18 -0.35 -0.92 +vn -0.37 -0.00 -0.93 +vn 0.19 0.02 -0.98 +vn 0.37 0.00 0.93 +vn 0.01 0.00 -1.00 +vn 0.96 0.00 -0.30 +vn -0.03 -1.00 0.01 +vn 0.03 0.04 -1.00 +vn -0.10 0.00 -1.00 +vn -0.07 -0.06 -1.00 +vn -0.31 0.95 0.09 +vn 0.04 -1.00 -0.01 +vn -0.08 0.04 -1.00 +vn 0.04 1.00 -0.01 +vn -0.05 1.00 0.02 +vn -0.12 0.00 -0.99 +vn -0.33 -0.45 -0.83 +vn -0.19 -0.00 0.98 +vn -0.37 0.03 -0.93 +vn 0.19 0.00 -0.98 +vn 0.74 0.00 -0.67 +vn -0.05 1.00 -0.01 +vn -0.82 0.00 -0.57 +vn 0.05 1.00 0.02 +vn 0.74 0.00 0.67 +vn -0.05 1.00 0.01 +vn -0.82 0.00 0.57 +vn 0.05 1.00 -0.02 +# 487 vertex normals + +vt 0.10 0.10 0.00 +vt 0.07 0.10 0.00 +vt 0.07 0.01 0.00 +vt 0.10 0.01 0.00 +vt 0.05 0.10 0.00 +vt 0.05 0.01 0.00 +vt 0.02 0.10 0.00 +vt 0.02 0.01 0.00 +vt 0.38 0.10 0.00 +vt 0.35 0.10 0.00 +vt 0.35 0.01 0.00 +vt 0.38 0.01 0.00 +vt 0.32 0.10 0.00 +vt 0.32 0.01 0.00 +vt 0.29 0.10 0.00 +vt 0.29 0.01 0.00 +vt 0.27 0.10 0.00 +vt 0.27 0.01 0.00 +vt 0.24 0.10 0.00 +vt 0.24 0.01 0.00 +vt 0.21 0.10 0.00 +vt 0.21 0.01 0.00 +vt 0.17 0.10 0.00 +vt 0.17 0.01 0.00 +vt 0.13 0.10 0.00 +vt 0.13 0.01 0.00 +vt 0.34 0.56 0.00 +vt 0.37 0.56 0.00 +vt 0.37 0.57 0.00 +vt 0.34 0.57 0.00 +vt 0.30 0.56 0.00 +vt 0.30 0.57 0.00 +vt 0.27 0.56 0.00 +vt 0.27 0.57 0.00 +vt 0.61 0.56 0.00 +vt 0.64 0.56 0.00 +vt 0.64 0.57 0.00 +vt 0.61 0.57 0.00 +vt 0.58 0.56 0.00 +vt 0.58 0.57 0.00 +vt 0.55 0.56 0.00 +vt 0.55 0.57 0.00 +vt 0.52 0.56 0.00 +vt 0.52 0.57 0.00 +vt 0.49 0.56 0.00 +vt 0.49 0.57 0.00 +vt 0.46 0.56 0.00 +vt 0.46 0.57 0.00 +vt 0.43 0.56 0.00 +vt 0.43 0.57 0.00 +vt 0.40 0.56 0.00 +vt 0.40 0.57 0.00 +vt 0.97 0.27 0.00 +vt 0.96 0.28 0.00 +vt 0.94 0.27 0.00 +vt 0.93 0.26 0.00 +vt 0.93 0.25 0.00 +vt 0.93 0.24 0.00 +vt 0.93 0.23 0.00 +vt 0.94 0.23 0.00 +vt 0.94 0.22 0.00 +vt 0.96 0.22 0.00 +vt 0.97 0.23 0.00 +vt 0.97 0.22 0.00 +vt 0.98 0.24 0.00 +vt 0.98 0.23 0.00 +vt 0.99 0.25 0.00 +vt 0.98 0.26 0.00 +vt 0.81 0.06 0.00 +vt 0.81 0.16 0.00 +vt 0.78 0.16 0.00 +vt 0.78 0.06 0.00 +vt 0.76 0.16 0.00 +vt 0.76 0.06 0.00 +vt 0.73 0.16 0.00 +vt 0.73 0.06 0.00 +vt 0.71 0.16 0.00 +vt 0.71 0.06 0.00 +vt 0.69 0.16 0.00 +vt 0.69 0.06 0.00 +vt 0.98 0.06 0.00 +vt 0.98 0.16 0.00 +vt 0.95 0.16 0.00 +vt 0.95 0.06 0.00 +vt 0.93 0.16 0.00 +vt 0.93 0.06 0.00 +vt 0.91 0.16 0.00 +vt 0.91 0.06 0.00 +vt 0.88 0.16 0.00 +vt 0.88 0.06 0.00 +vt 0.86 0.16 0.00 +vt 0.86 0.07 0.00 +vt 0.83 0.16 0.00 +vt 0.83 0.07 0.00 +vt 0.98 0.28 0.00 +vt 0.96 0.29 0.00 +vt 0.99 0.27 0.00 +vt 1.00 0.25 0.00 +vt 0.99 0.23 0.00 +vt 0.98 0.22 0.00 +vt 0.96 0.21 0.00 +vt 0.92 0.23 0.00 +vt 0.92 0.25 0.00 +vt 0.93 0.27 0.00 +vt 0.92 0.27 0.00 +vt 0.94 0.28 0.00 +vt 0.11 0.23 0.00 +vt 0.09 0.22 0.00 +vt 0.10 0.18 0.00 +vt 0.13 0.19 0.00 +vt 0.14 0.24 0.00 +vt 0.15 0.19 0.00 +vt 0.17 0.24 0.00 +vt 0.18 0.20 0.00 +vt 0.21 0.24 0.00 +vt 0.20 0.20 0.00 +vt 0.24 0.24 0.00 +vt 0.23 0.19 0.00 +vt 0.27 0.23 0.00 +vt 0.25 0.19 0.00 +vt 0.30 0.22 0.00 +vt 0.28 0.18 0.00 +vt 0.32 0.21 0.00 +vt 0.30 0.17 0.00 +vt 0.35 0.19 0.00 +vt 0.32 0.16 0.00 +vt 0.03 0.19 0.00 +vt 0.01 0.17 0.00 +vt 0.04 0.14 0.00 +vt 0.06 0.16 0.00 +vt 0.06 0.21 0.00 +vt 0.08 0.17 0.00 +vt 0.12 0.14 0.00 +vt 0.14 0.15 0.00 +vt 0.16 0.15 0.00 +vt 0.18 0.16 0.00 +vt 0.20 0.16 0.00 +vt 0.22 0.15 0.00 +vt 0.24 0.15 0.00 +vt 0.26 0.14 0.00 +vt 0.28 0.13 0.00 +vt 0.31 0.12 0.00 +vt 0.06 0.11 0.00 +vt 0.08 0.12 0.00 +vt 0.10 0.13 0.00 +vt 0.14 0.12 0.00 +vt 0.12 0.12 0.00 +vt 0.12 0.11 0.00 +vt 0.14 0.11 0.00 +vt 0.10 0.12 0.00 +vt 0.10 0.11 0.00 +vt 0.35 0.12 0.00 +vt 0.33 0.12 0.00 +vt 0.33 0.11 0.00 +vt 0.35 0.11 0.00 +vt 0.31 0.11 0.00 +vt 0.29 0.12 0.00 +vt 0.29 0.11 0.00 +vt 0.27 0.12 0.00 +vt 0.27 0.11 0.00 +vt 0.24 0.12 0.00 +vt 0.24 0.11 0.00 +vt 0.22 0.12 0.00 +vt 0.22 0.11 0.00 +vt 0.20 0.12 0.00 +vt 0.20 0.11 0.00 +vt 0.18 0.12 0.00 +vt 0.18 0.11 0.00 +vt 0.16 0.12 0.00 +vt 0.16 0.11 0.00 +vt 0.67 0.06 0.00 +vt 0.64 0.06 0.00 +vt 0.64 0.01 0.00 +vt 0.67 0.01 0.00 +vt 0.60 0.06 0.00 +vt 0.60 0.01 0.00 +vt 0.99 0.06 0.00 +vt 0.96 0.06 0.00 +vt 0.96 0.01 0.00 +vt 0.99 0.01 0.00 +vt 0.93 0.01 0.00 +vt 0.89 0.06 0.00 +vt 0.89 0.01 0.00 +vt 0.86 0.06 0.00 +vt 0.86 0.01 0.00 +vt 0.83 0.06 0.00 +vt 0.83 0.01 0.00 +vt 0.80 0.06 0.00 +vt 0.80 0.01 0.00 +vt 0.77 0.06 0.00 +vt 0.77 0.01 0.00 +vt 0.73 0.01 0.00 +vt 0.70 0.06 0.00 +vt 0.70 0.01 0.00 +vt 0.95 0.87 0.00 +vt 0.93 0.89 0.00 +vt 0.92 0.82 0.00 +vt 0.95 0.82 0.00 +vt 0.92 0.79 0.00 +vt 0.90 0.79 0.00 +vt 0.90 0.77 0.00 +vt 0.92 0.77 0.00 +vt 0.99 0.56 0.00 +vt 0.98 0.56 0.00 +vt 0.98 0.52 0.00 +vt 0.99 0.52 0.00 +vt 0.93 0.78 0.00 +vt 0.96 0.78 0.00 +vt 0.96 0.79 0.00 +vt 0.96 0.81 0.00 +vt 0.94 0.81 0.00 +vt 0.93 0.90 0.00 +vt 0.95 0.88 0.00 +vt 0.96 0.88 0.00 +vt 0.89 0.79 0.00 +vt 0.89 0.81 0.00 +vt 0.90 0.87 0.00 +vt 0.90 0.82 0.00 +vt 0.99 0.60 0.00 +vt 0.98 0.60 0.00 +vt 0.99 0.66 0.00 +vt 0.99 0.59 0.00 +vt 0.99 0.46 0.00 +vt 0.92 0.76 0.00 +vt 0.86 0.76 0.00 +vt 0.86 0.77 0.00 +vt 0.96 0.83 0.00 +vt 0.95 0.83 0.00 +vt 0.98 0.66 0.00 +vt 0.98 0.46 0.00 +vt 0.96 0.76 0.00 +vt 0.92 0.75 0.00 +vt 0.96 0.75 0.00 +vt 0.86 0.75 0.00 +vt 0.93 0.77 0.00 +vt 0.96 0.77 0.00 +vt 0.97 0.76 0.00 +vt 0.97 0.77 0.00 +vt 0.97 0.75 0.00 +vt 0.97 0.79 0.00 +vt 0.98 0.80 0.00 +vt 0.97 0.78 0.00 +vt 0.62 0.90 0.00 +vt 0.63 0.90 0.00 +vt 0.63 0.93 0.00 +vt 0.62 0.93 0.00 +vt 0.66 0.90 0.00 +vt 0.64 0.93 0.00 +vt 0.64 0.98 0.00 +vt 0.66 0.98 0.00 +vt 0.63 0.99 0.00 +vt 0.62 0.99 0.00 +vt 0.60 0.18 0.00 +vt 0.63 0.18 0.00 +vt 0.63 0.20 0.00 +vt 0.60 0.20 0.00 +vt 0.56 0.18 0.00 +vt 0.56 0.20 0.00 +vt 0.53 0.18 0.00 +vt 0.53 0.20 0.00 +vt 0.89 0.18 0.00 +vt 0.92 0.18 0.00 +vt 0.92 0.20 0.00 +vt 0.89 0.20 0.00 +vt 0.86 0.18 0.00 +vt 0.86 0.20 0.00 +vt 0.82 0.18 0.00 +vt 0.82 0.20 0.00 +vt 0.79 0.18 0.00 +vt 0.79 0.20 0.00 +vt 0.76 0.18 0.00 +vt 0.76 0.20 0.00 +vt 0.73 0.18 0.00 +vt 0.73 0.20 0.00 +vt 0.69 0.18 0.00 +vt 0.69 0.20 0.00 +vt 0.66 0.18 0.00 +vt 0.66 0.20 0.00 +vt 0.86 0.88 0.00 +vt 0.83 0.89 0.00 +vt 0.83 0.88 0.00 +vt 0.85 0.88 0.00 +vt 0.88 0.87 0.00 +vt 0.87 0.86 0.00 +vt 0.88 0.84 0.00 +vt 0.88 0.81 0.00 +vt 0.87 0.82 0.00 +vt 0.86 0.79 0.00 +vt 0.85 0.80 0.00 +vt 0.83 0.79 0.00 +vt 0.83 0.80 0.00 +vt 0.81 0.79 0.00 +vt 0.81 0.80 0.00 +vt 0.79 0.81 0.00 +vt 0.79 0.82 0.00 +vt 0.78 0.84 0.00 +vt 0.79 0.84 0.00 +vt 0.79 0.87 0.00 +vt 0.79 0.86 0.00 +vt 0.81 0.88 0.00 +vt 0.60 0.67 0.00 +vt 0.58 0.67 0.00 +vt 0.58 0.66 0.00 +vt 0.61 0.66 0.00 +vt 0.64 0.67 0.00 +vt 0.64 0.66 0.00 +vt 0.68 0.67 0.00 +vt 0.68 0.66 0.00 +vt 0.72 0.67 0.00 +vt 0.72 0.66 0.00 +vt 0.76 0.67 0.00 +vt 0.76 0.66 0.00 +vt 0.79 0.67 0.00 +vt 0.79 0.66 0.00 +vt 0.81 0.67 0.00 +vt 0.81 0.66 0.00 +vt 0.84 0.67 0.00 +vt 0.84 0.66 0.00 +vt 0.88 0.67 0.00 +vt 0.88 0.66 0.00 +vt 0.53 0.67 0.00 +vt 0.49 0.67 0.00 +vt 0.50 0.66 0.00 +vt 0.53 0.66 0.00 +vt 0.56 0.67 0.00 +vt 0.56 0.66 0.00 +vt 0.66 0.16 0.00 +vt 0.63 0.17 0.00 +vt 0.63 0.12 0.00 +vt 0.68 0.14 0.00 +vt 0.68 0.12 0.00 +vt 0.68 0.09 0.00 +vt 0.66 0.07 0.00 +vt 0.63 0.07 0.00 +vt 0.61 0.07 0.00 +vt 0.59 0.09 0.00 +vt 0.59 0.12 0.00 +vt 0.59 0.14 0.00 +vt 0.61 0.16 0.00 +vt 0.60 0.21 0.00 +vt 0.56 0.21 0.00 +vt 0.64 0.68 0.00 +vt 0.60 0.68 0.00 +vt 0.92 0.21 0.00 +vt 0.89 0.21 0.00 +vt 0.72 0.68 0.00 +vt 0.68 0.68 0.00 +vt 0.86 0.21 0.00 +vt 0.82 0.21 0.00 +vt 0.79 0.68 0.00 +vt 0.76 0.68 0.00 +vt 0.79 0.21 0.00 +vt 0.76 0.21 0.00 +vt 0.84 0.68 0.00 +vt 0.81 0.68 0.00 +vt 0.73 0.21 0.00 +vt 0.69 0.21 0.00 +vt 0.53 0.68 0.00 +vt 0.49 0.68 0.00 +vt 0.66 0.21 0.00 +vt 0.63 0.21 0.00 +vt 0.58 0.68 0.00 +vt 0.56 0.68 0.00 +vt 0.24 0.62 0.00 +vt 0.00 0.62 0.00 +vt 0.05 0.71 0.00 +vt 0.19 0.71 0.00 +vt 0.00 0.41 0.00 +vt 0.28 0.41 0.00 +vt 0.24 0.49 0.00 +vt 0.05 0.49 0.00 +vt 0.01 0.52 0.00 +vt 0.29 0.52 0.00 +vt 0.24 0.59 0.00 +vt 0.05 0.59 0.00 +vt 0.38 0.32 0.00 +vt 0.53 0.32 0.00 +vt 0.53 0.42 0.00 +vt 0.38 0.42 0.00 +vt 0.67 0.21 0.00 +vt 0.49 0.21 0.00 +vt 0.49 0.30 0.00 +vt 0.67 0.30 0.00 +vt 0.46 0.89 0.00 +vt 0.27 0.89 0.00 +vt 0.27 0.99 0.00 +vt 0.46 0.99 0.00 +vt 0.62 0.80 0.00 +vt 0.77 0.80 0.00 +vt 0.77 0.88 0.00 +vt 0.62 0.88 0.00 +vt 0.24 0.73 0.00 +vt 0.32 0.73 0.00 +vt 0.31 0.72 0.00 +vt 0.24 0.72 0.00 +vt 0.32 0.63 0.00 +vt 0.31 0.64 0.00 +vt 0.24 0.63 0.00 +vt 0.24 0.64 0.00 +vt 0.19 0.33 0.00 +vt 0.19 0.25 0.00 +vt 0.20 0.27 0.00 +vt 0.20 0.31 0.00 +vt 0.31 0.25 0.00 +vt 0.30 0.27 0.00 +vt 0.31 0.33 0.00 +vt 0.30 0.31 0.00 +vt 0.14 0.26 0.00 +vt 0.14 0.40 0.00 +vt 0.18 0.34 0.00 +vt 0.18 0.26 0.00 +vt 0.36 0.40 0.00 +vt 0.32 0.34 0.00 +vt 0.36 0.26 0.00 +vt 0.32 0.26 0.00 +vt 0.49 0.15 0.00 +vt 0.49 0.25 0.00 +vt 0.36 0.25 0.00 +vt 0.36 0.15 0.00 +vt 0.41 0.01 0.00 +vt 0.58 0.01 0.00 +vt 0.58 0.14 0.00 +vt 0.41 0.14 0.00 +vt 0.58 0.42 0.00 +vt 0.58 0.54 0.00 +vt 0.45 0.53 0.00 +vt 0.45 0.45 0.00 +vt 0.71 0.95 0.00 +vt 0.66 0.89 0.00 +vt 0.14 0.94 0.00 +vt 0.01 0.95 0.00 +vt 0.76 0.89 0.00 +vt 0.32 0.41 0.00 +vt 0.32 0.53 0.00 +vt 0.27 0.95 0.00 +vt 0.80 0.98 0.00 +vt 0.80 0.93 0.00 +vt 0.81 0.93 0.00 +vt 0.81 0.98 0.00 +vt 0.78 0.98 0.00 +vt 0.78 0.93 0.00 +vt 0.77 0.93 0.00 +vt 0.77 0.98 0.00 +vt 0.77 0.99 0.00 +vt 0.78 0.99 0.00 +vt 0.73 0.93 0.00 +vt 0.74 0.93 0.00 +vt 0.74 0.98 0.00 +vt 0.73 0.98 0.00 +vt 0.76 0.98 0.00 +vt 0.86 0.48 0.00 +vt 0.86 0.45 0.00 +vt 0.94 0.45 0.00 +vt 0.94 0.48 0.00 +vt 0.95 0.40 0.00 +vt 0.99 0.40 0.00 +vt 0.99 0.45 0.00 +vt 0.95 0.45 0.00 +vt 0.99 0.35 0.00 +vt 0.90 0.35 0.00 +vt 0.90 0.39 0.00 +vt 0.99 0.39 0.00 +vt 0.68 0.24 0.00 +vt 0.71 0.24 0.00 +vt 0.71 0.62 0.00 +vt 0.68 0.62 0.00 +vt 0.61 0.69 0.00 +vt 0.80 0.69 0.00 +vt 0.80 0.76 0.00 +vt 0.61 0.76 0.00 +vt 0.87 0.95 0.00 +vt 0.86 0.97 0.00 +vt 0.86 0.91 0.00 +vt 0.87 0.91 0.00 +vt 0.90 0.94 0.00 +vt 0.90 0.91 0.00 +vt 0.91 0.91 0.00 +vt 0.91 0.94 0.00 +vt 0.98 0.83 0.00 +vt 0.98 0.76 0.00 +vt 0.89 0.94 0.00 +vt 0.89 0.91 0.00 +vt 0.95 0.93 0.00 +vt 0.97 0.93 0.00 +vt 0.97 0.94 0.00 +vt 0.97 0.97 0.00 +vt 0.97 0.99 0.00 +vt 0.96 0.99 0.00 +vt 0.86 0.98 0.00 +vt 0.87 0.97 0.00 +vt 0.88 0.97 0.00 +vt 0.86 0.99 0.00 +vt 0.90 0.99 0.00 +vt 0.90 0.97 0.00 +vt 0.91 0.99 0.00 +vt 0.93 0.97 0.00 +vt 0.93 0.98 0.00 +vt 0.85 0.95 0.00 +vt 0.85 0.91 0.00 +vt 0.98 0.90 0.00 +vt 0.93 0.93 0.00 +vt 0.84 0.97 0.00 +vt 0.85 0.97 0.00 +vt 0.99 0.78 0.00 +vt 0.99 0.67 0.00 +vt 0.99 0.83 0.00 +vt 0.99 0.89 0.00 +vt 0.99 0.99 0.00 +vt 0.93 0.95 0.00 +vt 0.93 0.96 0.00 +vt 0.90 0.96 0.00 +vt 0.90 0.95 0.00 +vt 0.96 0.95 0.00 +vt 0.96 0.96 0.00 +vt 0.84 0.92 0.00 +vt 0.85 0.92 0.00 +vt 0.98 0.99 0.00 +vt 0.98 0.67 0.00 +vt 0.88 0.92 0.00 +vt 0.97 0.95 0.00 +vt 0.89 0.95 0.00 +vt 0.95 0.92 0.00 +vt 0.97 0.92 0.00 +vt 0.93 0.92 0.00 +vt 0.98 0.95 0.00 +vt 0.98 0.96 0.00 +vt 0.97 0.96 0.00 +vt 0.98 0.94 0.00 +vt 0.89 0.99 0.00 +vt 0.89 0.97 0.00 +vt 0.88 0.96 0.00 +vt 0.88 0.95 0.00 +vt 0.89 0.96 0.00 +vt 0.04 0.35 0.00 +vt 0.04 0.25 0.00 +vt 0.07 0.25 0.00 +vt 0.07 0.36 0.00 +vt 0.13 0.33 0.00 +vt 0.10 0.35 0.00 +vt 0.10 0.25 0.00 +vt 0.13 0.25 0.00 +vt 0.01 0.33 0.00 +vt 0.01 0.25 0.00 +vt 0.93 0.52 0.00 +vt 0.94 0.52 0.00 +vt 0.94 0.58 0.00 +vt 0.93 0.58 0.00 +vt 0.92 0.49 0.00 +vt 0.91 0.49 0.00 +vt 0.91 0.54 0.00 +vt 0.92 0.55 0.00 +vt 0.97 0.52 0.00 +vt 0.95 0.52 0.00 +vt 0.95 0.58 0.00 +vt 0.97 0.58 0.00 +vt 0.94 0.64 0.00 +vt 0.93 0.64 0.00 +vt 0.89 0.58 0.00 +vt 0.89 0.59 0.00 +vt 0.95 0.64 0.00 +vt 0.97 0.64 0.00 +vt 0.94 0.69 0.00 +vt 0.93 0.69 0.00 +vt 0.86 0.59 0.00 +vt 0.86 0.61 0.00 +vt 0.95 0.69 0.00 +vt 0.97 0.69 0.00 +vt 0.83 0.58 0.00 +vt 0.83 0.59 0.00 +vt 0.81 0.54 0.00 +vt 0.80 0.55 0.00 +vt 0.81 0.49 0.00 +vt 0.80 0.49 0.00 +vt 0.82 0.22 0.00 +vt 0.85 0.22 0.00 +vt 0.84 0.39 0.00 +vt 0.81 0.39 0.00 +vt 0.76 0.22 0.00 +vt 0.80 0.22 0.00 +vt 0.79 0.38 0.00 +vt 0.76 0.38 0.00 +vt 0.82 0.52 0.00 +vt 0.85 0.52 0.00 +vt 0.80 0.51 0.00 +vt 0.76 0.53 0.00 +vt 0.18 0.92 0.00 +vt 0.09 0.92 0.00 +vt 0.09 0.93 0.00 +vt 0.18 0.93 0.00 +vt 0.00 0.90 0.00 +vt 0.10 0.89 0.00 +vt 0.10 0.90 0.00 +vt 0.00 0.91 0.00 +vt 0.00 0.92 0.00 +vt 0.00 0.93 0.00 +vt 0.20 0.90 0.00 +vt 0.20 0.91 0.00 +vt 0.20 0.93 0.00 +vt 0.23 0.90 0.00 +vt 0.23 0.93 0.00 +vt 0.26 0.76 0.00 +vt 0.26 0.90 0.00 +vt 0.22 0.84 0.00 +vt 0.22 0.76 0.00 +vt 0.11 0.81 0.00 +vt 0.11 0.87 0.00 +vt 0.02 0.88 0.00 +vt 0.02 0.81 0.00 +vt 0.31 0.84 0.00 +vt 0.31 0.76 0.00 +vt 0.11 0.74 0.00 +vt 0.11 0.80 0.00 +vt 0.01 0.80 0.00 +vt 0.01 0.74 0.00 +vt 0.20 0.81 0.00 +vt 0.20 0.88 0.00 +vt 0.20 0.74 0.00 +vt 0.20 0.80 0.00 +vt 0.36 0.65 0.00 +vt 0.36 0.75 0.00 +vt 0.34 0.75 0.00 +vt 0.33 0.65 0.00 +vt 0.36 0.89 0.00 +vt 0.33 0.87 0.00 +vt 0.45 0.67 0.00 +vt 0.45 0.76 0.00 +vt 0.43 0.76 0.00 +vt 0.42 0.67 0.00 +vt 0.45 0.89 0.00 +vt 0.42 0.89 0.00 +vt 0.41 0.66 0.00 +vt 0.38 0.66 0.00 +vt 0.39 0.77 0.00 +vt 0.41 0.77 0.00 +vt 0.38 0.88 0.00 +vt 0.41 0.88 0.00 +vt 0.72 0.62 0.00 +vt 0.72 0.52 0.00 +vt 0.73 0.52 0.00 +vt 0.73 0.62 0.00 +vt 0.74 0.62 0.00 +vt 0.74 0.43 0.00 +vt 0.73 0.43 0.00 +vt 0.59 0.58 0.00 +vt 0.64 0.58 0.00 +vt 0.64 0.63 0.00 +vt 0.59 0.63 0.00 +vt 0.75 0.42 0.00 +vt 0.73 0.42 0.00 +vt 0.73 0.36 0.00 +vt 0.75 0.36 0.00 +vt 0.92 0.71 0.00 +vt 0.97 0.71 0.00 +vt 0.92 0.73 0.00 +vt 0.73 0.29 0.00 +vt 0.73 0.24 0.00 +vt 0.75 0.24 0.00 +vt 0.75 0.29 0.00 +vt 0.86 0.72 0.00 +vt 0.86 0.73 0.00 +vt 0.81 0.72 0.00 +vt 0.81 0.70 0.00 +vt 0.73 0.33 0.00 +vt 0.75 0.33 0.00 +vt 0.89 0.74 0.00 +vt 0.89 0.72 0.00 +vt 0.83 0.62 0.00 +vt 0.92 0.62 0.00 +vt 0.92 0.61 0.00 +vt 0.83 0.61 0.00 +vt 0.83 0.63 0.00 +vt 0.92 0.63 0.00 +vt 0.71 0.65 0.00 +vt 0.71 0.66 0.00 +vt 0.75 0.66 0.00 +vt 0.75 0.65 0.00 +vt 0.71 0.64 0.00 +vt 0.75 0.64 0.00 +vt 0.58 0.64 0.00 +vt 0.62 0.66 0.00 +vt 0.62 0.64 0.00 +vt 0.92 0.64 0.00 +vt 0.83 0.64 0.00 +vt 0.75 0.61 0.00 +vt 0.75 0.62 0.00 +vt 0.75 0.63 0.00 +vt 0.67 0.66 0.00 +vt 0.67 0.64 0.00 +vt 0.41 0.65 0.00 +vt 0.41 0.57 0.00 +vt 0.44 0.57 0.00 +vt 0.44 0.66 0.00 +vt 0.48 0.65 0.00 +vt 0.48 0.57 0.00 +# 694 texture coords + +o castle +g castle +f 1/1/1 2/2/2 3/3/2 +f 3/3/2 4/4/1 1/1/1 +f 2/2/2 5/5/3 6/6/3 +f 6/6/3 3/3/2 2/2/2 +f 5/5/3 7/7/4 8/8/4 +f 8/8/4 6/6/3 5/5/3 +f 7/9/4 9/10/5 10/11/5 +f 10/11/5 8/12/4 7/9/4 +f 9/10/5 11/13/6 12/14/6 +f 12/14/6 10/11/5 9/10/5 +f 11/13/6 13/15/7 14/16/7 +f 14/16/7 12/14/6 11/13/6 +f 13/15/7 15/17/8 16/18/8 +f 16/18/8 14/16/7 13/15/7 +f 15/17/8 17/19/9 18/20/9 +f 18/20/9 16/18/8 15/17/8 +f 17/19/9 19/21/10 20/22/10 +f 20/22/10 18/20/9 17/19/9 +f 19/21/10 21/23/11 22/24/11 +f 22/24/11 20/22/10 19/21/10 +f 21/23/11 23/25/12 24/26/12 +f 24/26/12 22/24/11 21/23/11 +f 23/25/12 1/1/1 4/4/1 +f 4/4/1 24/26/12 23/25/12 +f 25/27/13 26/28/13 27/29/13 +f 27/29/13 28/30/13 25/27/13 +f 29/31/14 25/27/14 28/30/14 +f 28/30/14 30/32/14 29/31/14 +f 31/33/15 29/31/15 30/32/15 +f 30/32/15 32/34/15 31/33/15 +f 33/35/16 31/36/16 32/37/16 +f 32/37/16 34/38/16 33/35/16 +f 35/39/17 33/35/17 34/38/17 +f 34/38/17 36/40/17 35/39/17 +f 37/41/18 35/39/18 36/40/18 +f 36/40/18 38/42/18 37/41/18 +f 39/43/19 37/41/19 38/42/19 +f 38/42/19 40/44/19 39/43/19 +f 41/45/20 39/43/20 40/44/20 +f 40/44/20 42/46/20 41/45/20 +f 43/47/21 41/45/21 42/46/21 +f 42/46/21 44/48/21 43/47/21 +f 45/49/22 43/47/22 44/48/22 +f 44/48/22 46/50/22 45/49/22 +f 47/51/23 45/49/23 46/50/23 +f 46/50/23 48/52/23 47/51/23 +f 26/28/24 47/51/25 48/52/25 +f 48/52/25 27/29/24 26/28/24 +f 2/53/26 1/54/26 26/54/26 +f 26/54/26 25/53/26 2/53/26 +f 1/54/26 23/55/26 47/55/26 +f 47/55/26 26/54/26 1/54/26 +f 23/55/26 21/56/26 45/56/26 +f 45/56/26 47/55/26 23/55/26 +f 21/56/26 19/57/26 43/57/26 +f 43/57/26 45/56/26 21/56/26 +f 19/57/26 17/58/26 41/59/26 +f 41/59/26 43/57/26 19/57/26 +f 17/58/26 15/60/26 39/61/26 +f 39/61/26 41/59/26 17/58/26 +f 15/60/26 13/62/26 37/62/26 +f 37/62/26 39/61/26 15/60/26 +f 13/62/26 11/63/26 35/64/26 +f 35/64/26 37/62/26 13/62/26 +f 11/63/26 9/65/26 33/66/26 +f 33/66/26 35/64/26 11/63/26 +f 9/65/26 7/67/26 31/67/26 +f 31/67/26 33/66/26 9/65/26 +f 7/67/26 5/68/26 29/68/26 +f 29/68/26 31/67/26 7/67/26 +f 5/68/26 2/53/26 25/53/26 +f 25/53/26 29/68/26 5/68/26 +f 49/54/27 50/53/27 28/53/27 +f 28/53/27 27/54/27 49/54/27 +f 50/53/27 51/68/27 30/68/27 +f 30/68/27 28/53/27 50/53/27 +f 51/68/27 52/67/27 32/67/27 +f 32/67/27 30/68/27 51/68/27 +f 52/67/27 53/65/27 34/66/27 +f 34/66/27 32/67/27 52/67/27 +f 53/65/27 54/63/27 36/64/27 +f 36/64/27 34/66/27 53/65/27 +f 54/63/27 55/62/27 38/62/27 +f 38/62/27 36/64/27 54/63/27 +f 55/62/27 56/60/27 40/61/27 +f 40/61/27 38/62/27 55/62/27 +f 56/60/27 57/58/27 42/59/27 +f 42/59/27 40/61/27 56/60/27 +f 57/58/27 58/57/27 44/57/27 +f 44/57/27 42/59/27 57/58/27 +f 58/57/27 59/56/27 46/56/27 +f 46/56/27 44/57/27 58/57/27 +f 59/56/27 60/55/27 48/55/27 +f 48/55/27 46/56/27 59/56/27 +f 60/55/27 49/54/27 27/54/27 +f 27/54/27 48/55/27 60/55/27 +f 49/69/1 61/70/1 62/71/2 +f 62/71/2 50/72/2 49/69/1 +f 50/72/2 62/71/2 63/73/14 +f 63/73/14 51/74/14 50/72/2 +f 51/74/15 63/73/15 64/75/15 +f 64/75/15 52/76/15 51/74/15 +f 52/76/16 64/75/16 65/77/5 +f 65/77/5 53/78/5 52/76/16 +f 53/78/5 65/77/5 66/79/6 +f 66/79/6 54/80/6 53/78/5 +f 54/81/6 66/82/6 67/83/7 +f 67/83/7 55/84/7 54/81/6 +f 55/84/7 67/83/7 68/85/8 +f 68/85/8 56/86/8 55/84/7 +f 56/86/8 68/85/8 69/87/9 +f 69/87/9 57/88/9 56/86/8 +f 57/88/9 69/87/9 70/89/10 +f 70/89/10 58/90/10 57/88/9 +f 58/90/10 70/89/10 71/91/11 +f 71/91/11 59/92/11 58/90/10 +f 59/92/11 71/91/11 72/93/12 +f 72/93/12 60/94/12 59/92/11 +f 60/94/12 72/93/12 61/70/1 +f 61/70/1 49/69/1 60/94/12 +f 73/95/26 74/96/26 75/96/26 +f 75/96/26 76/95/26 73/95/26 +f 77/97/26 73/95/26 76/95/26 +f 76/95/26 78/97/26 77/97/26 +f 79/67/26 77/97/26 78/97/26 +f 78/97/26 80/98/26 79/67/26 +f 81/99/26 79/67/26 80/98/26 +f 80/98/26 82/99/26 81/99/26 +f 83/100/26 81/99/26 82/99/26 +f 82/99/26 84/100/26 83/100/26 +f 85/101/26 83/100/26 84/100/26 +f 84/100/26 86/101/26 85/101/26 +f 87/61/26 85/101/26 86/101/26 +f 86/101/26 88/61/26 87/61/26 +f 89/59/26 87/61/26 88/61/26 +f 88/61/26 90/102/26 89/59/26 +f 91/103/26 89/59/26 90/102/26 +f 90/102/26 92/103/26 91/103/26 +f 93/104/26 91/103/26 92/103/26 +f 92/103/26 94/105/26 93/104/26 +f 95/106/26 93/104/26 94/105/26 +f 94/105/26 96/106/26 95/106/26 +f 74/96/26 95/106/26 96/106/26 +f 96/106/26 75/96/26 74/96/26 +f 76/107/28 75/108/28 97/109/28 +f 97/109/28 98/110/28 76/107/28 +f 78/111/29 76/107/29 98/110/29 +f 98/110/29 99/112/29 78/111/29 +f 80/113/30 78/111/30 99/112/30 +f 99/112/30 100/114/30 80/113/30 +f 82/115/31 80/113/31 100/114/31 +f 100/114/31 101/116/31 82/115/31 +f 84/117/32 82/115/32 101/116/32 +f 101/116/32 102/118/32 84/117/32 +f 86/119/33 84/117/33 102/118/33 +f 102/118/33 103/120/33 86/119/33 +f 88/121/34 86/119/34 103/120/34 +f 103/120/34 104/122/34 88/121/34 +f 90/123/35 88/121/35 104/122/35 +f 104/122/35 105/124/35 90/123/35 +f 92/125/36 90/123/36 105/124/36 +f 105/124/36 106/126/36 92/125/36 +f 94/127/37 92/128/37 106/129/37 +f 106/129/37 107/130/37 94/127/37 +f 96/131/38 94/127/38 107/130/38 +f 107/130/38 108/132/38 96/131/38 +f 75/108/39 96/131/39 108/132/39 +f 108/132/39 97/109/39 75/108/39 +f 98/110/40 97/109/40 109/133/40 +f 109/133/40 110/134/40 98/110/40 +f 99/112/41 98/110/41 110/134/41 +f 110/134/41 111/135/41 99/112/41 +f 100/114/42 99/112/42 111/135/42 +f 111/135/42 112/136/43 100/114/42 +f 101/116/44 100/114/44 112/136/44 +f 112/136/44 113/137/44 101/116/44 +f 102/118/45 101/116/45 113/137/45 +f 113/137/45 114/138/45 102/118/45 +f 103/120/46 102/118/46 114/138/46 +f 114/138/46 115/139/46 103/120/46 +f 104/122/47 103/120/48 115/139/48 +f 115/139/48 116/140/48 104/122/47 +f 105/124/49 104/122/49 116/140/49 +f 116/140/49 117/141/49 105/124/49 +f 106/126/50 105/124/50 117/141/50 +f 117/141/50 118/142/50 106/126/50 +f 107/130/51 106/129/51 118/143/52 +f 118/143/52 119/144/51 107/130/51 +f 108/132/53 107/130/53 119/144/53 +f 119/144/53 120/145/53 108/132/53 +f 97/109/54 108/132/55 120/145/54 +f 120/145/54 109/133/54 97/109/54 +f 121/146/56 122/147/56 62/148/56 +f 62/148/56 61/149/56 121/146/56 +f 122/147/57 123/150/58 63/151/58 +f 63/151/58 62/148/57 122/147/57 +f 123/152/59 124/153/59 64/154/59 +f 64/154/59 63/155/59 123/152/59 +f 124/153/60 125/142/60 65/156/60 +f 65/156/60 64/154/60 124/153/60 +f 125/142/61 126/157/62 66/158/61 +f 66/158/61 65/156/62 125/142/61 +f 126/157/63 127/159/63 67/160/63 +f 67/160/63 66/158/63 126/157/63 +f 127/159/64 128/161/64 68/162/64 +f 68/162/64 67/160/64 127/159/64 +f 128/161/65 129/163/66 69/164/66 +f 69/164/66 68/162/66 128/161/65 +f 129/163/67 130/165/67 70/166/67 +f 70/166/67 69/164/67 129/163/67 +f 130/165/68 131/167/68 71/168/68 +f 71/168/68 70/166/68 130/165/68 +f 131/167/69 132/169/70 72/170/70 +f 72/170/70 71/168/70 131/167/69 +f 132/169/71 121/146/71 61/149/71 +f 61/149/71 72/170/71 132/169/71 +f 74/171/1 73/172/2 122/173/2 +f 122/173/2 121/174/1 74/171/1 +f 73/172/2 77/175/3 123/176/3 +f 123/176/3 122/173/2 73/172/2 +f 77/177/3 79/178/4 124/179/4 +f 124/179/4 123/180/3 77/177/3 +f 79/178/4 81/86/5 125/181/5 +f 125/181/5 124/179/4 79/178/4 +f 81/86/5 83/182/6 126/183/6 +f 126/183/6 125/181/5 81/86/5 +f 83/182/6 85/184/7 127/185/7 +f 127/185/7 126/183/6 83/182/6 +f 85/184/7 87/186/8 128/187/8 +f 128/187/8 127/185/7 85/184/7 +f 87/186/8 89/188/9 129/189/9 +f 129/189/9 128/187/8 87/186/8 +f 89/188/9 91/190/10 130/191/10 +f 130/191/10 129/189/9 89/188/9 +f 91/190/10 93/76/11 131/192/11 +f 131/192/11 130/191/10 91/190/10 +f 93/76/11 95/193/12 132/194/12 +f 132/194/12 131/192/11 93/76/11 +f 95/193/12 74/171/1 121/174/1 +f 121/174/1 132/194/12 95/193/12 +f 133/195/72 134/196/72 135/197/72 +f 135/197/72 136/198/72 133/195/72 +f 137/199/73 138/200/73 139/201/73 +f 139/201/73 140/202/73 137/199/73 +f 141/203/74 142/204/74 143/205/74 +f 143/205/74 144/206/74 141/203/74 +f 145/202/75 146/201/75 147/200/75 +f 147/200/75 148/199/75 145/202/75 +f 149/207/76 150/207/76 151/208/76 +f 151/208/76 152/209/76 149/207/76 +f 153/209/77 154/210/77 155/211/77 +f 142/212/78 156/196/78 157/213/78 +f 157/213/78 143/214/78 142/212/78 +f 158/210/79 159/209/79 160/211/79 +f 161/215/80 162/216/80 160/211/80 +f 160/211/80 159/209/80 161/215/80 +f 163/217/81 164/218/81 135/197/81 +f 135/197/81 134/196/81 163/217/81 +f 165/219/82 166/220/82 142/204/82 +f 142/204/82 141/203/82 165/219/82 +f 167/209/83 168/208/83 150/207/83 +f 150/207/83 149/207/83 167/209/83 +f 142/212/84 166/214/84 169/213/84 +f 169/213/84 156/196/84 142/212/84 +f 161/215/85 153/209/85 155/211/85 +f 155/211/85 162/216/85 161/215/85 +f 170/221/75 157/222/75 133/222/75 +f 133/222/75 136/221/75 170/221/75 +f 157/222/86 156/203/86 134/203/86 +f 134/203/86 133/222/86 157/222/86 +f 156/203/87 169/206/87 163/206/87 +f 163/206/87 134/203/87 156/203/87 +f 169/206/73 171/223/73 164/223/73 +f 164/223/73 163/206/73 169/206/73 +f 171/224/88 172/225/88 135/226/88 +f 135/226/88 164/224/88 171/224/88 +f 172/225/89 170/224/89 136/224/89 +f 136/224/89 135/226/89 172/225/89 +f 166/214/79 173/227/79 171/228/79 +f 171/228/79 169/213/79 166/214/79 +f 173/229/75 166/220/75 165/219/75 +f 165/219/75 174/221/75 173/229/75 +f 144/206/73 143/205/73 175/230/73 +f 175/230/73 176/223/73 144/206/73 +f 175/227/77 143/214/77 157/213/77 +f 157/213/77 170/228/77 175/227/77 +f 139/201/73 138/200/73 177/199/73 +f 177/199/73 178/202/73 139/201/73 +f 175/231/90 170/224/90 155/232/90 +f 155/232/90 154/233/91 175/231/90 +f 170/224/89 172/225/89 162/234/89 +f 162/234/89 155/232/89 170/224/89 +f 172/225/88 171/224/88 160/232/88 +f 160/232/88 162/234/88 172/225/88 +f 171/224/92 173/231/92 158/233/92 +f 158/233/92 160/232/92 171/224/92 +f 147/200/75 146/201/75 179/202/75 +f 179/202/75 180/199/75 147/200/75 +f 151/208/76 150/207/76 161/235/76 +f 161/235/76 159/236/76 151/208/76 +f 150/207/83 168/208/83 153/236/83 +f 153/236/83 161/235/83 150/207/83 +f 176/236/27 175/231/27 138/237/27 +f 138/237/27 137/238/27 176/236/27 +f 175/231/27 154/233/27 177/239/27 +f 177/239/27 138/237/27 175/231/27 +f 154/210/93 153/209/93 178/240/94 +f 178/240/94 177/241/94 154/210/93 +f 153/236/26 168/208/26 139/242/26 +f 139/242/26 178/238/26 153/236/26 +f 168/208/26 167/209/26 140/240/26 +f 140/240/26 139/242/26 168/208/26 +f 152/209/26 151/208/26 146/242/26 +f 146/242/26 145/240/26 152/209/26 +f 151/208/26 159/236/26 179/238/26 +f 179/238/26 146/242/26 151/208/26 +f 159/209/95 158/210/95 180/241/95 +f 180/241/95 179/240/95 159/209/95 +f 158/233/27 173/231/27 147/237/27 +f 147/237/27 180/239/27 158/233/27 +f 173/231/27 174/236/27 148/238/27 +f 148/238/27 147/237/27 173/231/27 +f 181/195/96 182/196/96 183/197/96 +f 183/197/96 184/198/96 181/195/96 +f 185/199/97 186/200/98 187/201/98 +f 187/201/98 188/202/97 185/199/97 +f 189/203/99 190/204/99 191/205/99 +f 191/205/99 192/206/99 189/203/99 +f 193/202/100 194/201/101 195/200/101 +f 195/200/101 196/199/100 193/202/100 +f 197/207/102 198/207/102 199/208/102 +f 199/208/102 200/209/102 197/207/102 +f 201/209/103 202/210/103 203/211/103 +f 190/212/104 204/196/104 205/213/104 +f 205/213/104 191/214/104 190/212/104 +f 206/210/105 207/209/105 208/211/105 +f 209/215/106 210/216/106 208/211/106 +f 208/211/106 207/209/106 209/215/106 +f 211/217/107 212/218/107 183/197/107 +f 183/197/107 182/196/107 211/217/107 +f 213/219/108 214/220/108 190/204/108 +f 190/204/108 189/203/108 213/219/108 +f 215/209/109 216/208/109 198/207/109 +f 198/207/109 197/207/109 215/209/109 +f 190/212/110 214/214/110 217/213/110 +f 217/213/110 204/196/110 190/212/110 +f 209/215/111 201/209/111 203/211/111 +f 203/211/111 210/216/111 209/215/111 +f 218/221/100 205/222/100 181/222/101 +f 181/222/101 184/221/101 218/221/100 +f 205/222/112 204/203/112 182/203/112 +f 182/203/112 181/222/112 205/222/112 +f 204/203/113 217/206/113 211/206/113 +f 211/206/113 182/203/113 204/203/113 +f 217/206/98 219/223/98 212/223/98 +f 212/223/98 211/206/98 217/206/98 +f 219/224/114 220/225/114 183/226/114 +f 183/226/114 212/224/114 219/224/114 +f 220/225/115 218/224/115 184/224/115 +f 184/224/115 183/226/115 220/225/115 +f 214/214/105 221/227/105 219/228/105 +f 219/228/105 217/213/105 214/214/105 +f 221/229/100 214/220/100 213/219/100 +f 213/219/100 222/221/100 221/229/100 +f 192/206/98 191/205/98 223/230/98 +f 223/230/98 224/223/98 192/206/98 +f 223/227/103 191/214/103 205/213/103 +f 205/213/103 218/228/103 223/227/103 +f 187/201/98 186/200/98 225/199/97 +f 225/199/97 226/202/97 187/201/98 +f 223/231/116 218/224/116 203/232/116 +f 203/232/116 202/233/116 223/231/116 +f 218/224/115 220/225/115 210/234/115 +f 210/234/115 203/232/115 218/224/115 +f 220/225/114 219/224/114 208/232/114 +f 208/232/114 210/234/114 220/225/114 +f 219/224/117 221/231/117 206/233/117 +f 206/233/117 208/232/117 219/224/117 +f 195/200/101 194/201/101 227/202/100 +f 227/202/100 228/199/100 195/200/101 +f 199/208/102 198/207/102 209/235/102 +f 209/235/102 207/236/102 199/208/102 +f 198/207/109 216/208/109 201/236/109 +f 201/236/109 209/235/109 198/207/109 +f 224/236/27 223/231/27 186/237/27 +f 186/237/27 185/238/27 224/236/27 +f 223/231/27 202/233/27 225/239/27 +f 225/239/27 186/237/27 223/231/27 +f 202/210/118 201/209/118 226/240/118 +f 226/240/118 225/241/118 202/210/118 +f 201/236/26 216/208/26 187/242/26 +f 187/242/26 226/238/26 201/236/26 +f 216/208/26 215/209/26 188/240/26 +f 188/240/26 187/242/26 216/208/26 +f 200/209/26 199/208/26 194/242/26 +f 194/242/26 193/240/26 200/209/26 +f 199/208/26 207/236/26 227/238/26 +f 227/238/26 194/242/26 199/208/26 +f 207/209/119 206/210/119 228/241/119 +f 228/241/119 227/240/119 207/209/119 +f 206/233/27 221/231/27 195/237/27 +f 195/237/27 228/239/27 206/233/27 +f 221/231/27 222/236/27 196/238/27 +f 196/238/27 195/237/27 221/231/27 +f 229/243/120 230/244/120 231/245/120 +f 231/245/120 232/246/120 229/243/120 +f 229/247/121 232/248/121 233/249/121 +f 233/249/121 234/250/121 229/247/121 +f 232/246/122 231/245/122 235/251/122 +f 235/251/122 233/252/122 232/246/122 +f 231/248/123 230/247/123 236/250/123 +f 236/250/123 235/249/123 231/248/123 +f 237/195/124 238/196/124 239/197/124 +f 239/197/124 240/198/124 237/195/124 +f 241/199/125 242/200/98 243/201/98 +f 243/201/98 244/202/125 241/199/125 +f 245/203/99 246/204/99 247/205/99 +f 247/205/99 248/206/99 245/203/99 +f 249/202/100 250/201/101 251/200/101 +f 251/200/101 252/199/100 249/202/100 +f 253/207/102 254/207/102 255/208/102 +f 255/208/102 256/209/102 253/207/102 +f 257/209/103 258/210/103 259/211/103 +f 246/212/104 260/196/104 261/213/104 +f 261/213/104 247/214/104 246/212/104 +f 262/210/105 263/209/105 264/211/105 +f 265/215/106 266/216/106 264/211/106 +f 264/211/106 263/209/106 265/215/106 +f 267/217/107 268/218/107 239/197/107 +f 239/197/107 238/196/107 267/217/107 +f 269/219/126 270/220/126 246/204/108 +f 246/204/108 245/203/108 269/219/126 +f 271/209/109 272/208/109 254/207/109 +f 254/207/109 253/207/109 271/209/109 +f 246/212/110 270/214/110 273/213/110 +f 273/213/110 260/196/110 246/212/110 +f 265/215/111 257/209/111 259/211/111 +f 259/211/111 266/216/111 265/215/111 +f 274/221/100 261/222/100 237/222/100 +f 237/222/100 240/221/100 274/221/100 +f 261/222/112 260/203/112 238/203/112 +f 238/203/112 237/222/112 261/222/112 +f 260/203/113 273/206/113 267/206/113 +f 267/206/113 238/203/113 260/203/113 +f 273/206/98 275/223/98 268/223/98 +f 268/223/98 267/206/98 273/206/98 +f 275/224/114 276/225/114 239/226/114 +f 239/226/114 268/224/114 275/224/114 +f 276/225/115 274/224/115 240/224/115 +f 240/224/115 239/226/115 276/225/115 +f 270/214/105 277/227/105 275/228/105 +f 275/228/105 273/213/105 270/214/105 +f 277/229/101 270/220/101 269/219/101 +f 269/219/101 278/221/101 277/229/101 +f 248/206/98 247/205/97 279/230/97 +f 279/230/97 280/223/98 248/206/98 +f 279/227/103 247/214/103 261/213/103 +f 261/213/103 274/228/103 279/227/103 +f 243/201/98 242/200/98 281/199/97 +f 281/199/97 282/202/97 243/201/98 +f 279/231/116 274/224/116 259/232/116 +f 259/232/116 258/233/116 279/231/116 +f 274/224/115 276/225/115 266/234/115 +f 266/234/115 259/232/115 274/224/115 +f 276/225/114 275/224/114 264/232/114 +f 264/232/114 266/234/114 276/225/114 +f 275/224/117 277/231/117 262/233/117 +f 262/233/117 264/232/117 275/224/117 +f 251/200/101 250/201/101 283/202/100 +f 283/202/100 284/199/100 251/200/101 +f 255/208/102 254/207/102 265/235/102 +f 265/235/102 263/236/102 255/208/102 +f 254/207/109 272/208/109 257/236/109 +f 257/236/109 265/235/109 254/207/109 +f 280/236/27 279/231/27 242/237/27 +f 242/237/27 241/238/27 280/236/27 +f 279/231/27 258/233/27 281/239/27 +f 281/239/27 242/237/27 279/231/27 +f 258/210/118 257/209/118 282/240/118 +f 282/240/118 281/241/118 258/210/118 +f 257/236/26 272/208/26 243/242/26 +f 243/242/26 282/238/26 257/236/26 +f 272/208/26 271/209/26 244/240/26 +f 244/240/26 243/242/26 272/208/26 +f 256/209/26 255/208/26 250/242/26 +f 250/242/26 249/240/26 256/209/26 +f 255/208/26 263/236/26 283/238/26 +f 283/238/26 250/242/26 255/208/26 +f 263/209/119 262/210/119 284/241/119 +f 284/241/119 283/240/119 263/209/119 +f 262/233/27 277/231/27 251/237/27 +f 251/237/27 284/239/27 262/233/27 +f 277/231/27 278/236/27 252/238/27 +f 252/238/27 251/237/27 277/231/27 +f 285/243/127 286/244/127 287/245/127 +f 287/245/127 288/246/127 285/243/127 +f 285/247/128 288/248/128 289/249/128 +f 289/249/128 290/250/128 285/247/128 +f 288/246/129 287/245/129 291/251/129 +f 291/251/129 289/252/129 288/246/129 +f 287/248/130 286/247/130 292/250/130 +f 292/250/130 291/249/130 287/248/130 +f 293/195/131 294/196/131 295/197/131 +f 295/197/131 296/198/131 293/195/131 +f 297/199/75 298/200/75 299/201/75 +f 299/201/75 300/202/75 297/199/75 +f 301/203/132 302/204/132 303/205/132 +f 303/205/132 304/206/132 301/203/132 +f 305/202/73 306/201/73 307/200/73 +f 307/200/73 308/199/73 305/202/73 +f 309/207/83 310/207/83 311/208/83 +f 311/208/83 312/209/83 309/207/83 +f 313/209/133 314/210/133 315/211/133 +f 302/212/134 316/196/134 317/213/134 +f 317/213/134 303/214/134 302/212/134 +f 318/210/135 319/209/135 320/211/135 +f 321/215/136 322/216/136 320/211/136 +f 320/211/136 319/209/136 321/215/136 +f 323/217/137 324/218/137 295/197/138 +f 295/197/138 294/196/138 323/217/137 +f 325/219/139 326/220/139 302/204/139 +f 302/204/139 301/203/139 325/219/139 +f 327/209/76 328/208/76 310/207/76 +f 310/207/76 309/207/76 327/209/76 +f 302/212/140 326/214/140 329/213/140 +f 329/213/140 316/196/140 302/212/140 +f 321/215/141 313/209/141 315/211/141 +f 315/211/141 322/216/141 321/215/141 +f 330/221/73 317/222/73 293/222/73 +f 293/222/73 296/221/73 330/221/73 +f 317/222/87 316/203/87 294/203/87 +f 294/203/87 293/222/87 317/222/87 +f 316/203/86 329/206/86 323/206/86 +f 323/206/86 294/203/86 316/203/86 +f 329/206/75 331/223/75 324/223/75 +f 324/223/75 323/206/75 329/206/75 +f 331/224/142 332/225/142 295/226/142 +f 295/226/142 324/224/142 331/224/142 +f 332/225/143 330/224/143 296/224/143 +f 296/224/143 295/226/143 332/225/143 +f 326/214/135 333/227/135 331/228/135 +f 331/228/135 329/213/135 326/214/135 +f 333/229/73 326/220/73 325/219/73 +f 325/219/73 334/221/73 333/229/73 +f 304/206/75 303/205/75 335/230/75 +f 335/230/75 336/223/75 304/206/75 +f 335/227/133 303/214/133 317/213/133 +f 317/213/133 330/228/133 335/227/133 +f 299/201/75 298/200/75 337/199/75 +f 337/199/75 338/202/75 299/201/75 +f 335/231/144 330/224/144 315/232/144 +f 315/232/144 314/233/144 335/231/144 +f 330/224/143 332/225/143 322/234/143 +f 322/234/143 315/232/143 330/224/143 +f 332/225/142 331/224/142 320/232/142 +f 320/232/142 322/234/142 332/225/142 +f 331/224/145 333/231/145 318/233/145 +f 318/233/145 320/232/145 331/224/145 +f 307/200/73 306/201/73 339/202/73 +f 339/202/73 340/199/73 307/200/73 +f 311/208/83 310/207/83 321/235/83 +f 321/235/83 319/236/83 311/208/83 +f 310/207/76 328/208/76 313/236/76 +f 313/236/76 321/235/76 310/207/76 +f 336/236/27 335/231/27 298/237/27 +f 298/237/27 297/238/27 336/236/27 +f 335/231/27 314/233/27 337/239/27 +f 337/239/27 298/237/27 335/231/27 +f 314/210/146 313/209/146 338/240/146 +f 338/240/146 337/241/146 314/210/146 +f 313/236/26 328/208/26 299/242/26 +f 299/242/26 338/238/26 313/236/26 +f 328/208/26 327/209/26 300/240/26 +f 300/240/26 299/242/26 328/208/26 +f 312/209/26 311/208/26 306/242/26 +f 306/242/26 305/240/26 312/209/26 +f 311/208/26 319/236/26 339/238/26 +f 339/238/26 306/242/26 311/208/26 +f 319/209/147 318/210/147 340/241/147 +f 340/241/147 339/240/147 319/209/147 +f 318/233/27 333/231/27 307/237/27 +f 307/237/27 340/239/27 318/233/27 +f 333/231/27 334/236/27 308/238/27 +f 308/238/27 307/237/27 333/231/27 +f 341/243/148 342/244/148 343/245/148 +f 343/245/148 344/246/148 341/243/148 +f 341/247/1 344/248/1 345/249/1 +f 345/249/1 346/250/1 341/247/1 +f 344/246/149 343/245/149 347/251/149 +f 347/251/149 345/252/149 344/246/149 +f 343/248/7 342/247/7 348/250/7 +f 348/250/7 347/249/7 343/248/7 +f 349/243/150 350/244/150 351/245/150 +f 351/245/150 352/246/150 349/243/150 +f 349/247/151 352/248/151 353/249/151 +f 353/249/151 354/250/151 349/247/151 +f 352/246/152 351/245/152 355/251/152 +f 355/251/152 353/252/152 352/246/152 +f 351/248/153 350/247/153 356/250/153 +f 356/250/153 355/249/153 351/248/153 +f 357/243/154 358/244/154 359/245/154 +f 359/245/154 360/246/154 357/243/154 +f 357/247/7 360/248/7 361/249/7 +f 361/249/7 362/250/7 357/247/7 +f 360/246/155 359/245/155 363/251/155 +f 363/251/155 361/252/155 360/246/155 +f 359/248/1 358/247/1 364/250/1 +f 364/250/1 363/249/1 359/248/1 +f 365/243/156 366/244/156 367/245/156 +f 367/245/156 368/246/156 365/243/156 +f 365/247/157 368/248/157 369/249/157 +f 369/249/157 370/250/157 365/247/157 +f 368/246/158 367/245/158 371/251/158 +f 371/251/158 369/252/158 368/246/158 +f 367/248/159 366/247/159 372/250/159 +f 372/250/159 371/249/159 367/248/159 +f 373/243/160 374/244/160 375/245/160 +f 375/245/160 376/246/160 373/243/160 +f 373/247/161 376/248/161 377/249/161 +f 377/249/161 378/250/161 373/247/161 +f 376/246/162 375/245/162 379/251/162 +f 379/251/162 377/252/162 376/246/162 +f 375/248/163 374/247/163 380/250/163 +f 380/250/163 379/249/163 375/248/163 +f 381/195/131 382/196/131 383/197/131 +f 383/197/131 384/198/131 381/195/131 +f 385/199/75 386/200/75 387/201/75 +f 387/201/75 388/202/75 385/199/75 +f 389/203/132 390/204/132 391/205/132 +f 391/205/132 392/206/132 389/203/132 +f 393/202/73 394/201/73 395/200/73 +f 395/200/73 396/199/73 393/202/73 +f 397/207/83 398/207/83 399/208/83 +f 399/208/83 400/209/83 397/207/83 +f 401/209/133 402/210/133 403/211/133 +f 390/212/134 404/196/134 405/213/134 +f 405/213/134 391/214/134 390/212/134 +f 406/210/135 407/209/135 408/211/135 +f 409/215/136 410/216/136 408/211/136 +f 408/211/136 407/209/136 409/215/136 +f 411/217/137 412/218/137 383/197/138 +f 383/197/138 382/196/138 411/217/137 +f 413/219/139 414/220/139 390/204/139 +f 390/204/139 389/203/139 413/219/139 +f 415/209/76 416/208/76 398/207/76 +f 398/207/76 397/207/76 415/209/76 +f 390/212/140 414/214/140 417/213/140 +f 417/213/140 404/196/140 390/212/140 +f 409/215/141 401/209/141 403/211/141 +f 403/211/141 410/216/141 409/215/141 +f 418/221/73 405/222/73 381/222/73 +f 381/222/73 384/221/73 418/221/73 +f 405/222/87 404/203/87 382/203/87 +f 382/203/87 381/222/87 405/222/87 +f 404/203/86 417/206/86 411/206/86 +f 411/206/86 382/203/86 404/203/86 +f 417/206/75 419/223/75 412/223/75 +f 412/223/75 411/206/75 417/206/75 +f 419/224/142 420/225/142 383/226/142 +f 383/226/142 412/224/142 419/224/142 +f 420/225/143 418/224/143 384/224/143 +f 384/224/143 383/226/143 420/225/143 +f 414/214/135 421/227/135 419/228/135 +f 419/228/135 417/213/135 414/214/135 +f 421/229/73 414/220/73 413/219/73 +f 413/219/73 422/221/73 421/229/73 +f 392/206/75 391/205/75 423/230/75 +f 423/230/75 424/223/75 392/206/75 +f 423/227/133 391/214/133 405/213/133 +f 405/213/133 418/228/133 423/227/133 +f 387/201/75 386/200/75 425/199/75 +f 425/199/75 426/202/75 387/201/75 +f 423/231/144 418/224/144 403/232/144 +f 403/232/144 402/233/144 423/231/144 +f 418/224/143 420/225/143 410/234/143 +f 410/234/143 403/232/143 418/224/143 +f 420/225/142 419/224/142 408/232/142 +f 408/232/142 410/234/142 420/225/142 +f 419/224/145 421/231/145 406/233/145 +f 406/233/145 408/232/145 419/224/145 +f 395/200/73 394/201/73 427/202/73 +f 427/202/73 428/199/73 395/200/73 +f 399/208/83 398/207/83 409/235/83 +f 409/235/83 407/236/83 399/208/83 +f 398/207/76 416/208/76 401/236/76 +f 401/236/76 409/235/76 398/207/76 +f 424/236/27 423/231/27 386/237/27 +f 386/237/27 385/238/27 424/236/27 +f 423/231/27 402/233/27 425/239/27 +f 425/239/27 386/237/27 423/231/27 +f 402/210/146 401/209/146 426/240/146 +f 426/240/146 425/241/146 402/210/146 +f 401/236/26 416/208/26 387/242/26 +f 387/242/26 426/238/26 401/236/26 +f 416/208/26 415/209/26 388/240/26 +f 388/240/26 387/242/26 416/208/26 +f 400/209/26 399/208/26 394/242/26 +f 394/242/26 393/240/26 400/209/26 +f 399/208/26 407/236/26 427/238/26 +f 427/238/26 394/242/26 399/208/26 +f 407/209/147 406/210/147 428/241/147 +f 428/241/147 427/240/147 407/209/147 +f 406/233/27 421/231/27 395/237/27 +f 395/237/27 428/239/27 406/233/27 +f 421/231/27 422/236/27 396/238/27 +f 396/238/27 395/237/27 421/231/27 +f 429/195/164 430/196/10 431/197/10 +f 431/197/10 432/198/164 429/195/164 +f 433/199/165 434/200/165 435/201/165 +f 435/201/165 436/202/165 433/199/165 +f 437/203/108 438/204/108 439/205/108 +f 439/205/108 440/206/108 437/203/108 +f 441/202/125 442/201/125 443/200/125 +f 443/200/125 444/199/125 441/202/125 +f 445/207/166 446/207/166 447/208/166 +f 447/208/166 448/209/166 445/207/166 +f 449/209/167 450/210/167 451/211/167 +f 438/212/168 452/196/168 453/213/168 +f 453/213/168 439/214/168 438/212/168 +f 454/210/169 455/209/169 456/211/169 +f 457/215/170 458/216/170 456/211/170 +f 456/211/170 455/209/170 457/215/170 +f 459/217/171 460/218/171 431/197/171 +f 431/197/171 430/196/171 459/217/171 +f 461/219/172 462/220/99 438/204/99 +f 438/204/99 437/203/99 461/219/172 +f 463/209/173 464/208/173 446/207/173 +f 446/207/173 445/207/173 463/209/173 +f 438/212/174 462/214/174 465/213/174 +f 465/213/174 452/196/174 438/212/174 +f 457/215/175 449/209/175 451/211/175 +f 451/211/175 458/216/175 457/215/175 +f 466/221/125 453/222/125 429/222/125 +f 429/222/125 432/221/125 466/221/125 +f 453/222/113 452/203/113 430/203/113 +f 430/203/113 429/222/113 453/222/113 +f 452/203/112 465/206/112 459/206/112 +f 459/206/112 430/203/112 452/203/112 +f 465/206/165 467/223/165 460/223/165 +f 460/223/165 459/206/165 465/206/165 +f 467/224/176 468/225/176 431/226/176 +f 431/226/176 460/224/176 467/224/176 +f 468/225/117 466/224/117 432/224/117 +f 432/224/117 431/226/117 468/225/117 +f 462/214/169 469/227/169 467/228/169 +f 467/228/169 465/213/169 462/214/169 +f 469/229/125 462/220/125 461/219/125 +f 461/219/125 470/221/125 469/229/125 +f 440/206/165 439/205/165 471/230/165 +f 471/230/165 472/223/165 440/206/165 +f 471/227/167 439/214/167 453/213/167 +f 453/213/167 466/228/167 471/227/167 +f 435/201/165 434/200/165 473/199/165 +f 473/199/165 474/202/165 435/201/165 +f 471/231/177 466/224/177 451/232/177 +f 451/232/177 450/233/177 471/231/177 +f 466/224/117 468/225/117 458/234/117 +f 458/234/117 451/232/117 466/224/117 +f 468/225/176 467/224/176 456/232/176 +f 456/232/176 458/234/176 468/225/176 +f 467/224/115 469/231/115 454/233/115 +f 454/233/115 456/232/115 467/224/115 +f 443/200/125 442/201/125 475/202/125 +f 475/202/125 476/199/125 443/200/125 +f 447/208/166 446/207/166 457/235/166 +f 457/235/166 455/236/166 447/208/166 +f 446/207/173 464/208/173 449/236/173 +f 449/236/173 457/235/173 446/207/173 +f 472/236/27 471/231/27 434/237/27 +f 434/237/27 433/238/27 472/236/27 +f 471/231/27 450/233/27 473/239/27 +f 473/239/27 434/237/27 471/231/27 +f 450/210/178 449/209/178 474/240/178 +f 474/240/178 473/241/178 450/210/178 +f 449/236/26 464/208/26 435/242/26 +f 435/242/26 474/238/26 449/236/26 +f 464/208/26 463/209/26 436/240/26 +f 436/240/26 435/242/26 464/208/26 +f 448/209/26 447/208/26 442/242/26 +f 442/242/26 441/240/26 448/209/26 +f 447/208/26 455/236/26 475/238/26 +f 475/238/26 442/242/26 447/208/26 +f 455/209/179 454/210/179 476/241/179 +f 476/241/179 475/240/179 455/209/179 +f 454/233/27 469/231/27 443/237/27 +f 443/237/27 476/239/27 454/233/27 +f 469/231/27 470/236/27 444/238/27 +f 444/238/27 443/237/27 469/231/27 +f 477/243/180 478/244/180 479/245/180 +f 479/245/180 480/246/180 477/243/180 +f 477/247/153 480/248/153 481/249/153 +f 481/249/153 482/250/153 477/247/153 +f 480/246/181 479/245/181 483/251/181 +f 483/251/181 481/252/182 480/246/181 +f 479/248/151 478/247/151 484/250/151 +f 484/250/151 483/249/151 479/248/151 +f 485/195/10 486/196/10 487/197/10 +f 487/197/10 488/198/10 485/195/10 +f 489/199/165 490/200/165 491/201/165 +f 491/201/165 492/202/165 489/199/165 +f 493/203/108 494/204/108 495/205/108 +f 495/205/108 496/206/108 493/203/108 +f 497/202/125 498/201/125 499/200/125 +f 499/200/125 500/199/125 497/202/125 +f 501/207/166 502/207/166 503/208/166 +f 503/208/166 504/209/166 501/207/166 +f 505/209/167 506/210/167 507/211/167 +f 494/212/168 508/196/168 509/213/168 +f 509/213/168 495/214/168 494/212/168 +f 510/210/169 511/209/169 512/211/169 +f 513/215/170 514/216/170 512/211/170 +f 512/211/170 511/209/170 513/215/170 +f 515/217/171 516/218/171 487/197/171 +f 487/197/171 486/196/171 515/217/171 +f 517/219/99 518/220/99 494/204/172 +f 494/204/172 493/203/99 517/219/99 +f 519/209/173 520/208/173 502/207/173 +f 502/207/173 501/207/173 519/209/173 +f 494/212/174 518/214/174 521/213/174 +f 521/213/174 508/196/174 494/212/174 +f 513/215/175 505/209/175 507/211/175 +f 507/211/175 514/216/175 513/215/175 +f 522/221/125 509/222/125 485/222/125 +f 485/222/125 488/221/125 522/221/125 +f 509/222/113 508/203/113 486/203/113 +f 486/203/113 485/222/113 509/222/113 +f 508/203/112 521/206/112 515/206/112 +f 515/206/112 486/203/112 508/203/112 +f 521/206/165 523/223/165 516/223/165 +f 516/223/165 515/206/165 521/206/165 +f 523/224/176 524/225/176 487/226/176 +f 487/226/176 516/224/176 523/224/176 +f 524/225/117 522/224/117 488/224/117 +f 488/224/117 487/226/117 524/225/117 +f 518/214/169 525/227/169 523/228/169 +f 523/228/169 521/213/169 518/214/169 +f 525/229/125 518/220/125 517/219/125 +f 517/219/125 526/221/125 525/229/125 +f 496/206/165 495/205/165 527/230/165 +f 527/230/165 528/223/165 496/206/165 +f 527/227/167 495/214/167 509/213/167 +f 509/213/167 522/228/167 527/227/167 +f 491/201/165 490/200/165 529/199/165 +f 529/199/165 530/202/165 491/201/165 +f 527/231/177 522/224/177 507/232/177 +f 507/232/177 506/233/177 527/231/177 +f 522/224/117 524/225/117 514/234/117 +f 514/234/117 507/232/117 522/224/117 +f 524/225/176 523/224/176 512/232/176 +f 512/232/176 514/234/176 524/225/176 +f 523/224/115 525/231/115 510/233/115 +f 510/233/115 512/232/115 523/224/115 +f 499/200/125 498/201/125 531/202/125 +f 531/202/125 532/199/125 499/200/125 +f 503/208/166 502/207/166 513/235/166 +f 513/235/166 511/236/166 503/208/166 +f 502/207/173 520/208/173 505/236/173 +f 505/236/173 513/235/173 502/207/173 +f 528/236/27 527/231/27 490/237/27 +f 490/237/27 489/238/27 528/236/27 +f 527/231/27 506/233/27 529/239/27 +f 529/239/27 490/237/27 527/231/27 +f 506/210/178 505/209/178 530/240/178 +f 530/240/178 529/241/178 506/210/178 +f 505/236/26 520/208/26 491/242/26 +f 491/242/26 530/238/26 505/236/26 +f 520/208/26 519/209/26 492/240/26 +f 492/240/26 491/242/26 520/208/26 +f 504/209/26 503/208/26 498/242/26 +f 498/242/26 497/240/26 504/209/26 +f 503/208/26 511/236/26 531/238/26 +f 531/238/26 498/242/26 503/208/26 +f 511/209/179 510/210/179 532/241/179 +f 532/241/179 531/240/179 511/209/179 +f 510/233/27 525/231/27 499/237/27 +f 499/237/27 532/239/27 510/233/27 +f 525/231/27 526/236/27 500/238/27 +f 500/238/27 499/237/27 525/231/27 +f 533/243/183 534/244/183 535/245/183 +f 535/245/183 536/246/183 533/243/183 +f 533/247/184 536/248/184 537/249/184 +f 537/249/184 538/250/184 533/247/184 +f 536/246/185 535/245/185 539/251/185 +f 539/251/185 537/252/185 536/246/185 +f 535/248/186 534/247/186 540/250/186 +f 540/250/186 539/249/186 535/248/186 +f 541/195/72 542/196/72 543/197/72 +f 543/197/72 544/198/72 541/195/72 +f 545/199/73 546/200/73 547/201/73 +f 547/201/73 548/202/73 545/199/73 +f 549/203/74 550/204/74 551/205/74 +f 551/205/74 552/206/74 549/203/74 +f 553/202/75 554/201/75 555/200/75 +f 555/200/75 556/199/75 553/202/75 +f 557/207/76 558/207/76 559/208/76 +f 559/208/76 560/209/76 557/207/76 +f 561/209/77 562/210/77 563/211/77 +f 550/212/78 564/196/78 565/213/78 +f 565/213/78 551/214/78 550/212/78 +f 566/210/79 567/209/79 568/211/79 +f 569/215/80 570/216/80 568/211/80 +f 568/211/80 567/209/80 569/215/80 +f 571/217/81 572/218/81 543/197/81 +f 543/197/81 542/196/81 571/217/81 +f 573/219/82 574/220/82 550/204/82 +f 550/204/82 549/203/82 573/219/82 +f 575/209/83 576/208/83 558/207/83 +f 558/207/83 557/207/83 575/209/83 +f 550/212/84 574/214/84 577/213/84 +f 577/213/84 564/196/84 550/212/84 +f 569/215/85 561/209/85 563/211/85 +f 563/211/85 570/216/85 569/215/85 +f 578/221/75 565/222/75 541/222/75 +f 541/222/75 544/221/75 578/221/75 +f 565/222/86 564/203/86 542/203/86 +f 542/203/86 541/222/86 565/222/86 +f 564/203/87 577/206/87 571/206/87 +f 571/206/87 542/203/87 564/203/87 +f 577/206/73 579/223/73 572/223/73 +f 572/223/73 571/206/73 577/206/73 +f 579/224/88 580/225/88 543/226/88 +f 543/226/88 572/224/88 579/224/88 +f 580/225/89 578/224/89 544/224/89 +f 544/224/89 543/226/89 580/225/89 +f 574/214/79 581/227/79 579/228/79 +f 579/228/79 577/213/79 574/214/79 +f 581/229/75 574/220/75 573/219/75 +f 573/219/75 582/221/75 581/229/75 +f 552/206/73 551/205/73 583/230/73 +f 583/230/73 584/223/73 552/206/73 +f 583/227/77 551/214/77 565/213/77 +f 565/213/77 578/228/77 583/227/77 +f 547/201/73 546/200/73 585/199/73 +f 585/199/73 586/202/73 547/201/73 +f 583/231/90 578/224/90 563/232/90 +f 563/232/90 562/233/90 583/231/90 +f 578/224/89 580/225/89 570/234/89 +f 570/234/89 563/232/89 578/224/89 +f 580/225/88 579/224/88 568/232/88 +f 568/232/88 570/234/88 580/225/88 +f 579/224/92 581/231/92 566/233/92 +f 566/233/92 568/232/92 579/224/92 +f 555/200/75 554/201/75 587/202/75 +f 587/202/75 588/199/75 555/200/75 +f 559/208/76 558/207/76 569/235/76 +f 569/235/76 567/236/76 559/208/76 +f 558/207/83 576/208/83 561/236/83 +f 561/236/83 569/235/83 558/207/83 +f 584/236/27 583/231/27 546/237/27 +f 546/237/27 545/238/27 584/236/27 +f 583/231/27 562/233/27 585/239/27 +f 585/239/27 546/237/27 583/231/27 +f 562/210/94 561/209/94 586/240/94 +f 586/240/94 585/241/94 562/210/94 +f 561/236/26 576/208/26 547/242/26 +f 547/242/26 586/238/26 561/236/26 +f 576/208/26 575/209/26 548/240/26 +f 548/240/26 547/242/26 576/208/26 +f 560/209/26 559/208/26 554/242/26 +f 554/242/26 553/240/26 560/209/26 +f 559/208/26 567/236/26 587/238/26 +f 587/238/26 554/242/26 559/208/26 +f 567/209/95 566/210/95 588/241/95 +f 588/241/95 587/240/95 567/209/95 +f 566/233/27 581/231/27 555/237/27 +f 555/237/27 588/239/27 566/233/27 +f 581/231/27 582/236/27 556/238/27 +f 556/238/27 555/237/27 581/231/27 +f 589/243/187 590/244/187 591/245/187 +f 591/245/187 592/246/187 589/243/187 +f 589/247/163 592/248/163 593/249/163 +f 593/249/163 594/250/163 589/247/163 +f 592/246/188 591/245/188 595/251/189 +f 595/251/189 593/252/188 592/246/188 +f 591/248/161 590/247/161 596/250/161 +f 596/250/161 595/249/161 591/248/161 +f 597/253/13 598/254/13 599/255/13 +f 599/255/13 600/256/13 597/253/13 +f 601/257/14 597/253/14 600/256/14 +f 600/256/14 602/258/14 601/257/14 +f 603/259/118 601/257/118 602/258/118 +f 602/258/118 604/260/15 603/259/118 +f 605/261/16 603/262/16 604/263/16 +f 604/263/16 606/264/16 605/261/16 +f 607/265/17 605/261/17 606/264/17 +f 606/264/17 608/266/17 607/265/17 +f 609/267/18 607/265/18 608/266/18 +f 608/266/18 610/268/18 609/267/18 +f 611/269/190 609/267/19 610/268/19 +f 610/268/19 612/270/190 611/269/190 +f 613/271/20 611/269/20 612/270/20 +f 612/270/20 614/272/20 613/271/20 +f 615/273/21 613/271/21 614/272/21 +f 614/272/21 616/274/21 615/273/21 +f 617/275/191 615/273/191 616/274/22 +f 616/274/22 618/276/191 617/275/191 +f 619/277/23 617/275/23 618/276/23 +f 618/276/23 620/278/23 619/277/23 +f 598/254/24 619/277/25 620/278/25 +f 620/278/25 599/255/24 598/254/24 +f 600/279/27 599/280/27 621/281/27 +f 621/281/27 622/282/27 600/279/27 +f 623/283/27 624/279/27 625/282/27 +f 625/282/27 626/284/27 623/283/27 +f 604/285/27 602/283/27 627/284/27 +f 627/284/27 628/285/27 604/285/27 +f 629/286/27 630/285/27 631/285/27 +f 631/285/27 632/287/27 629/286/27 +f 608/288/27 606/286/27 633/287/27 +f 633/287/27 634/289/27 608/288/27 +f 635/290/27 636/288/27 637/289/27 +f 637/289/27 638/291/27 635/290/27 +f 612/292/27 610/290/27 639/291/27 +f 639/291/27 640/293/27 612/292/27 +f 641/294/27 642/292/27 643/293/27 +f 643/293/27 644/295/27 641/294/27 +f 616/296/27 614/294/27 645/295/27 +f 645/295/27 646/297/27 616/296/27 +f 647/298/27 648/296/27 649/297/27 +f 649/297/27 650/299/27 647/298/27 +f 620/300/27 618/298/27 651/299/27 +f 651/299/27 652/300/27 620/300/27 +f 653/280/27 654/300/27 655/300/27 +f 655/300/27 656/281/27 653/280/27 +f 622/301/19 621/302/19 657/303/19 +f 657/303/19 658/304/19 622/301/19 +f 627/305/20 622/301/20 658/304/20 +f 658/304/20 659/306/20 627/305/20 +f 628/307/21 627/305/21 659/306/21 +f 659/306/21 660/308/21 628/307/21 +f 633/309/22 628/307/22 660/308/22 +f 660/308/22 661/310/22 633/309/22 +f 634/311/23 633/309/23 661/310/23 +f 661/310/23 662/312/23 634/311/23 +f 639/313/24 634/311/24 662/312/24 +f 662/312/24 663/314/24 639/313/24 +f 640/315/192 639/313/13 663/314/13 +f 663/314/13 664/316/192 640/315/192 +f 645/317/14 640/315/14 664/316/14 +f 664/316/14 665/318/14 645/317/14 +f 646/319/15 645/317/15 665/318/15 +f 665/318/15 666/320/15 646/319/15 +f 651/321/16 646/322/16 666/323/193 +f 666/323/193 667/324/16 651/321/16 +f 652/325/17 651/321/17 667/324/17 +f 667/324/17 668/326/17 652/325/17 +f 621/302/18 652/325/194 668/326/194 +f 668/326/194 657/303/18 621/302/18 +f 658/327/27 657/328/27 669/329/27 +f 659/330/27 658/327/27 669/329/27 +f 660/331/27 659/330/27 669/329/27 +f 661/332/27 660/331/27 669/329/27 +f 662/333/27 661/332/27 669/329/27 +f 663/334/27 662/333/27 669/329/27 +f 664/335/27 663/334/27 669/329/27 +f 665/336/27 664/335/27 669/329/27 +f 666/337/27 665/336/27 669/329/27 +f 667/338/27 666/337/27 669/329/27 +f 668/339/27 667/338/27 669/329/27 +f 657/328/27 668/339/27 669/329/27 +f 602/258/14 600/256/14 624/340/14 +f 624/340/14 623/341/14 602/258/14 +f 600/279/161 622/282/161 625/282/161 +f 625/282/161 624/279/161 600/279/161 +f 622/301/20 627/305/20 626/342/20 +f 626/342/20 625/343/20 622/301/20 +f 627/284/195 602/283/195 623/283/195 +f 623/283/195 626/284/195 627/284/195 +f 606/264/16 604/263/16 630/344/193 +f 630/344/193 629/345/16 606/264/16 +f 604/285/1 628/285/1 631/285/1 +f 631/285/1 630/285/1 604/285/1 +f 628/307/22 633/309/22 632/346/22 +f 632/346/22 631/347/22 628/307/22 +f 633/287/196 606/286/196 629/286/196 +f 629/286/196 632/287/196 633/287/196 +f 610/268/18 608/266/18 636/348/18 +f 636/348/18 635/349/18 610/268/18 +f 608/288/153 634/289/153 637/289/153 +f 637/289/153 636/288/153 608/288/153 +f 634/311/24 639/313/24 638/350/24 +f 638/350/24 637/351/24 634/311/24 +f 639/291/10 610/290/10 635/290/10 +f 635/290/10 638/291/10 639/291/10 +f 614/272/20 612/270/20 642/352/20 +f 642/352/20 641/353/20 614/272/20 +f 612/292/163 640/293/163 643/293/163 +f 643/293/163 642/292/163 612/292/163 +f 640/315/14 645/317/14 644/354/14 +f 644/354/14 643/355/14 640/315/14 +f 645/295/197 614/294/197 641/294/197 +f 641/294/197 644/295/197 645/295/197 +f 618/276/191 616/274/22 648/356/22 +f 648/356/22 647/357/22 618/276/191 +f 616/296/7 646/297/7 649/297/7 +f 649/297/7 648/296/7 616/296/7 +f 646/322/16 651/321/16 650/358/16 +f 650/358/16 649/359/16 646/322/16 +f 651/299/198 618/298/198 647/298/198 +f 647/298/198 650/299/198 651/299/198 +f 599/255/24 620/278/25 654/360/24 +f 654/360/24 653/361/24 599/255/24 +f 620/300/151 652/300/151 655/300/151 +f 655/300/151 654/300/151 620/300/151 +f 652/325/194 621/302/18 656/362/18 +f 656/362/18 655/363/194 652/325/194 +f 621/281/4 599/280/4 653/280/4 +f 653/280/4 656/281/4 621/281/4 +f 670/364/199 671/365/199 672/366/199 +f 672/366/199 673/367/199 670/364/199 +f 671/368/200 674/369/200 675/370/200 +f 675/370/200 672/371/200 671/368/200 +f 674/365/201 676/364/201 677/367/201 +f 677/367/201 675/366/201 674/365/201 +f 676/372/202 670/373/202 673/374/202 +f 673/374/202 677/375/202 676/372/202 +f 678/376/7 679/377/7 680/378/7 +f 680/378/7 681/379/7 678/376/7 +f 679/380/4 682/381/4 683/382/4 +f 683/382/4 680/383/4 679/380/4 +f 684/384/1 685/385/1 686/386/1 +f 686/386/1 687/387/1 684/384/1 +f 688/388/10 678/389/10 681/390/10 +f 681/390/10 689/391/10 688/388/10 +f 676/392/26 674/393/26 683/394/26 +f 683/394/26 689/395/26 676/392/26 +f 683/394/26 674/393/26 671/396/26 +f 671/396/26 680/397/26 683/394/26 +f 680/397/26 671/396/26 670/398/26 +f 670/398/26 681/399/26 680/397/26 +f 681/399/26 670/398/26 676/392/26 +f 676/392/26 689/395/26 681/399/26 +f 673/400/27 672/401/27 690/402/27 +f 690/402/27 691/403/27 673/400/27 +f 672/401/27 675/404/27 692/405/27 +f 692/405/27 690/402/27 672/401/27 +f 675/404/27 677/406/27 693/407/27 +f 693/407/27 692/405/27 675/404/27 +f 677/406/27 673/400/27 691/403/27 +f 691/403/27 693/407/27 677/406/27 +f 688/408/1 689/409/1 694/410/1 +f 694/410/1 695/411/1 688/408/1 +f 689/409/1 683/412/1 696/413/1 +f 696/413/1 694/410/1 689/409/1 +f 683/412/1 682/414/1 697/415/1 +f 697/415/1 696/413/1 683/412/1 +f 695/416/10 694/417/10 686/418/10 +f 686/418/10 685/419/10 695/416/10 +f 694/420/27 696/421/27 687/422/27 +f 687/422/27 686/423/27 694/420/27 +f 696/417/4 697/416/4 684/419/4 +f 684/419/4 687/418/4 696/417/4 +f 698/243/150 699/246/150 700/245/150 +f 700/245/150 701/244/150 698/243/150 +f 698/247/153 702/250/153 703/249/153 +f 703/249/153 699/248/153 698/247/153 +f 699/246/152 703/252/152 704/251/152 +f 704/251/152 700/245/152 699/246/152 +f 700/248/151 704/249/151 705/250/151 +f 705/250/151 701/247/151 700/248/151 +f 706/424/203 707/425/204 708/426/205 +f 708/426/205 709/427/27 706/424/203 +f 710/428/1 711/429/1 707/429/1 +f 707/429/1 706/428/1 710/428/1 +f 712/430/206 708/430/206 707/431/206 +f 707/431/206 711/431/206 712/430/206 +f 706/424/203 709/427/27 713/426/207 +f 713/426/207 714/425/208 706/424/203 +f 710/428/1 706/428/1 714/432/1 +f 714/432/1 715/432/1 710/428/1 +f 714/431/209 713/430/209 716/430/209 +f 716/430/209 715/431/209 714/431/209 +f 717/433/210 709/427/27 708/426/205 +f 708/426/205 718/434/211 717/433/210 +f 719/428/7 717/428/7 718/429/7 +f 718/429/7 720/429/7 719/428/7 +f 718/435/212 708/430/212 712/430/212 +f 712/430/212 720/435/212 718/435/212 +f 717/433/210 721/434/213 713/426/207 +f 713/426/207 709/427/27 717/433/210 +f 719/428/7 722/432/7 721/432/7 +f 721/432/7 717/428/7 719/428/7 +f 716/430/214 713/430/214 721/435/214 +f 721/435/214 722/435/214 716/430/214 +f 723/436/4 724/437/4 725/438/4 +f 725/438/4 726/439/4 723/436/4 +f 724/437/215 723/436/215 727/440/215 +f 727/440/215 728/441/215 724/437/215 +f 723/436/216 726/439/216 729/440/216 +f 729/440/216 727/440/216 723/436/216 +f 730/442/217 728/441/217 727/440/217 +f 727/440/217 731/443/217 730/442/217 +f 732/444/216 731/443/216 727/440/216 +f 727/440/216 729/445/216 732/444/216 +f 733/446/10 734/447/10 735/448/10 +f 735/448/10 736/449/10 733/446/10 +f 734/447/218 737/442/218 738/443/218 +f 738/443/218 735/448/218 734/447/218 +f 735/448/219 738/443/219 739/450/219 +f 739/450/219 736/449/219 735/448/219 +f 738/443/220 737/442/220 730/442/220 +f 730/442/220 731/443/220 738/443/220 +f 732/444/219 739/444/219 738/443/219 +f 738/443/219 731/443/219 732/444/219 +f 740/436/4 741/437/4 742/438/4 +f 742/438/4 743/439/4 740/436/4 +f 741/437/221 740/436/221 744/440/221 +f 744/440/221 745/441/221 741/437/221 +f 740/436/222 743/439/222 746/440/222 +f 746/440/222 744/440/222 740/436/222 +f 747/442/223 745/441/223 744/440/223 +f 744/440/223 748/443/223 747/442/223 +f 749/444/222 748/443/222 744/440/222 +f 744/440/222 746/445/222 749/444/222 +f 750/446/10 751/447/10 752/448/10 +f 752/448/10 753/449/10 750/446/10 +f 751/447/224 754/442/224 755/443/224 +f 755/443/224 752/448/224 751/447/224 +f 752/448/222 755/443/222 756/450/222 +f 756/450/222 753/449/222 752/448/222 +f 755/443/225 754/442/225 747/442/225 +f 747/442/225 748/443/225 755/443/225 +f 749/444/222 756/444/222 755/443/222 +f 755/443/222 748/443/222 749/444/222 +f 757/436/4 758/437/4 759/438/4 +f 759/438/4 760/439/4 757/436/4 +f 758/437/226 757/436/226 761/440/226 +f 761/440/226 762/441/227 758/437/226 +f 757/436/228 760/439/228 763/440/229 +f 763/440/229 761/440/229 757/436/228 +f 764/442/230 762/441/230 761/440/230 +f 761/440/230 765/443/230 764/442/230 +f 766/444/228 765/443/228 761/440/228 +f 761/440/228 763/445/228 766/444/228 +f 767/446/10 768/447/10 769/448/10 +f 769/448/10 770/449/10 767/446/10 +f 768/447/231 771/442/232 772/443/231 +f 772/443/231 769/448/232 768/447/231 +f 769/448/229 772/443/229 773/450/229 +f 773/450/229 770/449/229 769/448/229 +f 772/443/233 771/442/233 764/442/233 +f 764/442/233 765/443/233 772/443/233 +f 766/444/229 773/444/229 772/443/229 +f 772/443/229 765/443/229 766/444/229 +f 774/436/4 775/437/4 776/438/4 +f 776/438/4 777/439/4 774/436/4 +f 775/437/226 774/436/227 778/440/227 +f 778/440/227 779/441/227 775/437/226 +f 774/436/229 777/439/229 780/440/229 +f 780/440/229 778/440/229 774/436/229 +f 781/442/230 779/441/230 778/440/230 +f 778/440/230 782/443/230 781/442/230 +f 783/444/229 782/443/229 778/440/229 +f 778/440/229 780/445/229 783/444/229 +f 784/446/10 785/447/10 786/448/10 +f 786/448/10 787/449/10 784/446/10 +f 785/447/231 788/442/232 789/443/232 +f 789/443/232 786/448/231 785/447/231 +f 786/448/228 789/443/229 790/450/229 +f 790/450/229 787/449/228 786/448/228 +f 789/443/233 788/442/233 781/442/233 +f 781/442/233 782/443/233 789/443/233 +f 783/444/229 790/444/229 789/443/229 +f 789/443/229 782/443/229 783/444/229 +f 791/436/4 792/437/4 793/438/4 +f 793/438/4 794/439/4 791/436/4 +f 792/437/234 791/436/234 795/440/234 +f 795/440/234 796/441/234 792/437/234 +f 791/436/235 794/439/235 797/440/235 +f 797/440/235 795/440/235 791/436/235 +f 798/442/236 796/441/236 795/440/236 +f 795/440/236 799/443/236 798/442/236 +f 800/444/235 799/443/235 795/440/235 +f 795/440/235 797/445/235 800/444/235 +f 801/446/10 802/447/10 803/448/10 +f 803/448/10 804/449/10 801/446/10 +f 802/447/237 805/442/237 806/443/237 +f 806/443/237 803/448/237 802/447/237 +f 803/448/235 806/443/235 807/450/235 +f 807/450/235 804/449/235 803/448/235 +f 806/443/238 805/442/238 798/442/238 +f 798/442/238 799/443/238 806/443/238 +f 800/444/239 807/444/239 806/443/239 +f 806/443/239 799/443/239 800/444/239 +f 808/436/4 809/437/4 810/438/4 +f 810/438/4 811/439/4 808/436/4 +f 809/437/240 808/436/240 812/440/240 +f 812/440/240 813/441/240 809/437/240 +f 808/436/241 811/439/241 814/440/241 +f 814/440/241 812/440/241 808/436/241 +f 815/442/236 813/441/236 812/440/236 +f 812/440/236 816/443/236 815/442/236 +f 817/444/241 816/443/241 812/440/241 +f 812/440/241 814/445/241 817/444/241 +f 818/446/10 819/447/10 820/448/10 +f 820/448/10 821/449/10 818/446/10 +f 819/447/242 822/442/242 823/443/242 +f 823/443/242 820/448/242 819/447/242 +f 820/448/243 823/443/241 824/450/241 +f 824/450/241 821/449/243 820/448/243 +f 823/443/238 822/442/238 815/442/238 +f 815/442/238 816/443/238 823/443/238 +f 817/444/241 824/444/241 823/443/241 +f 823/443/241 816/443/241 817/444/241 +f 825/436/4 826/437/4 827/438/4 +f 827/438/4 828/439/4 825/436/4 +f 826/437/215 825/436/215 829/440/215 +f 829/440/215 830/441/215 826/437/215 +f 825/436/216 828/439/216 831/440/216 +f 831/440/216 829/440/216 825/436/216 +f 832/442/217 830/441/217 829/440/217 +f 829/440/217 833/443/217 832/442/217 +f 834/444/216 833/443/216 829/440/216 +f 829/440/216 831/445/216 834/444/216 +f 835/446/10 836/447/10 837/448/10 +f 837/448/10 838/449/10 835/446/10 +f 836/447/218 839/442/218 840/443/218 +f 840/443/218 837/448/218 836/447/218 +f 837/448/219 840/443/219 841/450/219 +f 841/450/219 838/449/219 837/448/219 +f 840/443/220 839/442/220 832/442/220 +f 832/442/220 833/443/220 840/443/220 +f 834/444/219 841/444/219 840/443/219 +f 840/443/219 833/443/219 834/444/219 +f 842/436/4 843/437/4 844/438/4 +f 844/438/4 845/439/4 842/436/4 +f 843/437/215 842/436/215 846/440/215 +f 846/440/215 847/441/215 843/437/215 +f 842/436/216 845/439/216 848/440/216 +f 848/440/216 846/440/216 842/436/216 +f 849/442/217 847/441/217 846/440/217 +f 846/440/217 850/443/217 849/442/217 +f 851/444/216 850/443/216 846/440/216 +f 846/440/216 848/445/216 851/444/216 +f 852/446/10 853/447/10 854/448/10 +f 854/448/10 855/449/10 852/446/10 +f 853/447/218 856/442/218 857/443/218 +f 857/443/218 854/448/218 853/447/218 +f 854/448/219 857/443/219 858/450/219 +f 858/450/219 855/449/219 854/448/219 +f 857/443/220 856/442/220 849/442/220 +f 849/442/220 850/443/220 857/443/220 +f 851/444/219 858/444/219 857/443/219 +f 857/443/219 850/443/219 851/444/219 +f 859/438/4 860/437/4 861/436/4 +f 861/436/4 862/439/4 859/438/4 +f 863/440/244 861/436/244 860/437/244 +f 860/437/244 864/441/244 863/440/244 +f 865/440/245 862/439/245 861/436/245 +f 861/436/245 863/440/245 865/440/245 +f 863/440/246 864/441/246 866/442/246 +f 866/442/246 867/443/246 863/440/246 +f 868/444/245 865/445/245 863/440/245 +f 863/440/245 867/443/245 868/444/245 +f 869/448/10 870/447/10 871/446/10 +f 871/446/10 872/449/10 869/448/10 +f 873/443/247 874/442/247 870/447/247 +f 870/447/247 869/448/247 873/443/247 +f 875/450/248 873/443/248 869/448/248 +f 869/448/248 872/449/248 875/450/248 +f 866/442/249 874/442/249 873/443/249 +f 873/443/249 867/443/249 866/442/249 +f 868/444/248 867/443/248 873/443/248 +f 873/443/248 875/444/248 868/444/248 +f 876/438/4 877/437/4 878/436/4 +f 878/436/4 879/439/4 876/438/4 +f 880/440/250 878/436/250 877/437/250 +f 877/437/250 881/441/250 880/440/250 +f 882/440/251 879/439/251 878/436/251 +f 878/436/251 880/440/251 882/440/251 +f 880/440/252 881/441/252 883/442/252 +f 883/442/252 884/443/252 880/440/252 +f 885/444/251 882/445/251 880/440/251 +f 880/440/251 884/443/251 885/444/251 +f 886/448/10 887/447/10 888/446/10 +f 888/446/10 889/449/10 886/448/10 +f 890/443/253 891/442/253 887/447/253 +f 887/447/253 886/448/253 890/443/253 +f 892/450/251 890/443/251 886/448/254 +f 886/448/254 889/449/254 892/450/251 +f 883/442/255 891/442/255 890/443/255 +f 890/443/255 884/443/255 883/442/255 +f 885/444/251 884/443/251 890/443/251 +f 890/443/251 892/444/251 885/444/251 +f 893/438/4 894/437/4 895/436/4 +f 895/436/4 896/439/4 893/438/4 +f 897/440/256 895/436/257 894/437/256 +f 894/437/256 898/441/256 897/440/256 +f 899/440/258 896/439/258 895/436/258 +f 895/436/258 897/440/258 899/440/258 +f 897/440/259 898/441/259 900/442/259 +f 900/442/259 901/443/259 897/440/259 +f 902/444/258 899/445/258 897/440/258 +f 897/440/258 901/443/258 902/444/258 +f 903/448/10 904/447/10 905/446/10 +f 905/446/10 906/449/10 903/448/10 +f 907/443/260 908/442/260 904/447/260 +f 904/447/260 903/448/260 907/443/260 +f 909/450/261 907/443/261 903/448/261 +f 903/448/261 906/449/261 909/450/261 +f 900/442/262 908/442/262 907/443/262 +f 907/443/262 901/443/262 900/442/262 +f 902/444/261 901/443/261 907/443/261 +f 907/443/261 909/444/261 902/444/261 +f 910/438/4 911/437/4 912/436/4 +f 912/436/4 913/439/4 910/438/4 +f 914/440/257 912/436/257 911/437/257 +f 911/437/257 915/441/256 914/440/257 +f 916/440/261 913/439/261 912/436/261 +f 912/436/261 914/440/261 916/440/261 +f 914/440/259 915/441/259 917/442/259 +f 917/442/259 918/443/259 914/440/259 +f 919/444/261 916/445/261 914/440/261 +f 914/440/261 918/443/261 919/444/261 +f 920/448/10 921/447/10 922/446/10 +f 922/446/10 923/449/10 920/448/10 +f 924/443/263 925/442/260 921/447/263 +f 921/447/263 920/448/263 924/443/263 +f 926/450/258 924/443/258 920/448/261 +f 920/448/261 923/449/261 926/450/258 +f 917/442/262 925/442/262 924/443/262 +f 924/443/262 918/443/262 917/442/262 +f 919/444/261 918/443/261 924/443/261 +f 924/443/261 926/444/261 919/444/261 +f 927/438/4 928/437/4 929/436/4 +f 929/436/4 930/439/4 927/438/4 +f 931/440/264 929/436/264 928/437/264 +f 928/437/264 932/441/264 931/440/264 +f 933/440/265 930/439/265 929/436/265 +f 929/436/265 931/440/265 933/440/265 +f 931/440/266 932/441/266 934/442/266 +f 934/442/266 935/443/266 931/440/266 +f 936/444/265 933/445/265 931/440/265 +f 931/440/265 935/443/265 936/444/265 +f 937/448/10 938/447/10 939/446/10 +f 939/446/10 940/449/10 937/448/10 +f 941/443/267 942/442/267 938/447/267 +f 938/447/267 937/448/267 941/443/267 +f 943/450/265 941/443/265 937/448/265 +f 937/448/265 940/449/265 943/450/265 +f 934/442/268 942/442/268 941/443/268 +f 941/443/268 935/443/268 934/442/268 +f 936/444/269 935/443/269 941/443/269 +f 941/443/269 943/444/269 936/444/269 +f 944/438/4 945/437/4 946/436/4 +f 946/436/4 947/439/4 944/438/4 +f 948/440/270 946/436/270 945/437/270 +f 945/437/270 949/441/270 948/440/270 +f 950/440/271 947/439/271 946/436/271 +f 946/436/271 948/440/271 950/440/271 +f 948/440/266 949/441/266 951/442/266 +f 951/442/266 952/443/266 948/440/266 +f 953/444/271 950/445/271 948/440/271 +f 948/440/271 952/443/271 953/444/271 +f 954/448/10 955/447/10 956/446/10 +f 956/446/10 957/449/10 954/448/10 +f 958/443/272 959/442/272 955/447/272 +f 955/447/272 954/448/272 958/443/272 +f 960/450/271 958/443/271 954/448/273 +f 954/448/273 957/449/273 960/450/271 +f 951/442/268 959/442/268 958/443/268 +f 958/443/268 952/443/268 951/442/268 +f 953/444/271 952/443/271 958/443/271 +f 958/443/271 960/444/271 953/444/271 +f 961/438/4 962/437/4 963/436/4 +f 963/436/4 964/439/4 961/438/4 +f 965/440/244 963/436/244 962/437/244 +f 962/437/244 966/441/244 965/440/244 +f 967/440/245 964/439/245 963/436/245 +f 963/436/245 965/440/245 967/440/245 +f 965/440/246 966/441/246 968/442/274 +f 968/442/274 969/443/246 965/440/246 +f 970/444/245 967/445/245 965/440/245 +f 965/440/245 969/443/245 970/444/245 +f 971/448/10 972/447/10 973/446/10 +f 973/446/10 974/449/10 971/448/10 +f 975/443/247 976/442/247 972/447/247 +f 972/447/247 971/448/247 975/443/247 +f 977/450/248 975/443/248 971/448/248 +f 971/448/248 974/449/248 977/450/248 +f 968/442/275 976/442/249 975/443/249 +f 975/443/249 969/443/249 968/442/275 +f 970/444/248 969/443/248 975/443/248 +f 975/443/248 977/444/248 970/444/248 +f 978/438/4 979/437/4 980/436/4 +f 980/436/4 981/439/4 978/438/4 +f 982/440/244 980/436/244 979/437/244 +f 979/437/244 983/441/244 982/440/244 +f 984/440/245 981/439/245 980/436/245 +f 980/436/245 982/440/245 984/440/245 +f 982/440/246 983/441/246 985/442/246 +f 985/442/246 986/443/246 982/440/246 +f 987/444/245 984/445/245 982/440/245 +f 982/440/245 986/443/245 987/444/245 +f 988/448/10 989/447/10 990/446/10 +f 990/446/10 991/449/10 988/448/10 +f 992/443/247 993/442/247 989/447/247 +f 989/447/247 988/448/247 992/443/247 +f 994/450/248 992/443/248 988/448/248 +f 988/448/248 991/449/248 994/450/248 +f 985/442/249 993/442/249 992/443/249 +f 992/443/249 986/443/249 985/442/249 +f 987/444/248 986/443/248 992/443/248 +f 992/443/248 994/444/248 987/444/248 +f 995/436/4 996/437/4 997/438/4 +f 997/438/4 998/439/4 995/436/4 +f 996/437/276 995/436/276 999/440/276 +f 999/440/276 1000/441/276 996/437/276 +f 995/436/277 998/439/277 1001/440/278 +f 1001/440/278 999/440/278 995/436/277 +f 1002/442/279 1000/441/279 999/440/279 +f 999/440/279 1003/443/279 1002/442/279 +f 1004/444/277 1003/443/277 999/440/277 +f 999/440/277 1001/445/277 1004/444/277 +f 1005/446/10 1006/447/10 1007/448/10 +f 1007/448/10 1008/449/10 1005/446/10 +f 1006/447/280 1009/442/280 1010/443/280 +f 1010/443/280 1007/448/280 1006/447/280 +f 1007/448/278 1010/443/278 1011/450/278 +f 1011/450/278 1008/449/278 1007/448/278 +f 1010/443/281 1009/442/281 1002/442/281 +f 1002/442/281 1003/443/281 1010/443/281 +f 1004/444/278 1011/444/278 1010/443/278 +f 1010/443/278 1003/443/278 1004/444/278 +f 1012/438/4 1013/437/4 1014/436/4 +f 1014/436/4 1015/439/4 1012/438/4 +f 1016/440/282 1014/436/282 1013/437/282 +f 1013/437/282 1017/441/282 1016/440/282 +f 1018/440/283 1015/439/283 1014/436/283 +f 1014/436/283 1016/440/283 1018/440/283 +f 1016/440/284 1017/441/284 1019/442/284 +f 1019/442/284 1020/443/284 1016/440/284 +f 1021/444/283 1018/445/283 1016/440/283 +f 1016/440/283 1020/443/283 1021/444/283 +f 1022/448/10 1023/447/10 1024/446/10 +f 1024/446/10 1025/449/10 1022/448/10 +f 1026/443/285 1027/442/285 1023/447/285 +f 1023/447/285 1022/448/285 1026/443/285 +f 1028/450/286 1026/443/286 1022/448/286 +f 1022/448/286 1025/449/286 1028/450/286 +f 1019/442/287 1027/442/287 1026/443/287 +f 1026/443/287 1020/443/287 1019/442/287 +f 1021/444/286 1020/443/286 1026/443/286 +f 1026/443/286 1028/444/286 1021/444/286 +f 1029/243/187 1030/244/187 1031/245/187 +f 1031/245/187 1032/246/187 1029/243/187 +f 1029/247/163 1032/248/163 1033/249/163 +f 1033/249/163 1034/250/163 1029/247/163 +f 1032/246/188 1031/245/188 1035/251/188 +f 1035/251/188 1033/252/188 1032/246/188 +f 1031/248/161 1030/247/161 1036/250/161 +f 1036/250/161 1035/249/161 1031/248/161 +f 1037/451/27 1038/452/27 1039/453/27 +f 1039/453/27 1040/454/27 1037/451/27 +f 1041/455/7 1042/456/7 1038/457/7 +f 1038/457/7 1037/458/7 1041/455/7 +f 1042/459/4 1043/460/4 1039/461/4 +f 1039/461/4 1038/462/4 1042/459/4 +f 1043/456/1 1044/455/1 1040/458/1 +f 1040/458/1 1039/457/1 1043/456/1 +f 1044/460/10 1041/459/10 1037/462/10 +f 1037/462/10 1040/461/10 1044/460/10 +f 1045/451/27 1046/452/27 1047/453/27 +f 1047/453/27 1048/454/27 1045/451/27 +f 1049/455/7 1050/456/7 1046/457/7 +f 1046/457/7 1045/458/7 1049/455/7 +f 1050/459/4 1051/460/4 1047/461/4 +f 1047/461/4 1046/462/4 1050/459/4 +f 1051/456/1 1052/455/1 1048/458/1 +f 1048/458/1 1047/457/1 1051/456/1 +f 1052/460/10 1049/459/10 1045/462/10 +f 1045/462/10 1048/461/10 1052/460/10 +f 1053/451/27 1054/452/27 1055/453/27 +f 1055/453/27 1056/454/27 1053/451/27 +f 1057/455/7 1058/456/7 1054/457/7 +f 1054/457/7 1053/458/7 1057/455/7 +f 1058/459/4 1059/460/4 1055/461/4 +f 1055/461/4 1054/462/4 1058/459/4 +f 1059/456/1 1060/455/1 1056/458/1 +f 1056/458/1 1055/457/1 1059/456/1 +f 1060/460/10 1057/459/10 1053/462/10 +f 1053/462/10 1056/461/10 1060/460/10 +f 1061/451/27 1062/452/27 1063/453/27 +f 1063/453/27 1064/454/27 1061/451/27 +f 1065/455/10 1066/456/10 1062/457/10 +f 1062/457/10 1061/458/10 1065/455/10 +f 1066/459/7 1067/460/7 1063/461/7 +f 1063/461/7 1062/462/7 1066/459/7 +f 1067/456/4 1068/455/4 1064/458/4 +f 1064/458/4 1063/457/4 1067/456/4 +f 1068/460/1 1065/459/1 1061/462/1 +f 1061/462/1 1064/461/1 1068/460/1 +f 1069/451/27 1070/452/27 1071/453/27 +f 1071/453/27 1072/454/27 1069/451/27 +f 1073/455/10 1074/456/10 1070/457/10 +f 1070/457/10 1069/458/10 1073/455/10 +f 1074/459/7 1075/460/7 1071/461/7 +f 1071/461/7 1070/462/7 1074/459/7 +f 1075/456/4 1076/455/4 1072/458/4 +f 1072/458/4 1071/457/4 1075/456/4 +f 1076/460/1 1073/459/1 1069/462/1 +f 1069/462/1 1072/461/1 1076/460/1 +f 1077/451/27 1078/452/27 1079/453/27 +f 1079/453/27 1080/454/27 1077/451/27 +f 1081/455/10 1082/456/10 1078/457/10 +f 1078/457/10 1077/458/10 1081/455/10 +f 1082/459/7 1083/460/7 1079/461/7 +f 1079/461/7 1078/462/7 1082/459/7 +f 1083/456/4 1084/455/4 1080/458/4 +f 1080/458/4 1079/457/4 1083/456/4 +f 1084/460/1 1081/459/1 1077/462/1 +f 1077/462/1 1080/461/1 1084/460/1 +f 1085/451/27 1086/452/27 1087/453/27 +f 1087/453/27 1088/454/27 1085/451/27 +f 1089/455/10 1090/456/10 1086/457/10 +f 1086/457/10 1085/458/10 1089/455/10 +f 1090/459/7 1091/460/7 1087/461/7 +f 1087/461/7 1086/462/7 1090/459/7 +f 1091/456/4 1092/455/4 1088/458/4 +f 1088/458/4 1087/457/4 1091/456/4 +f 1092/460/1 1089/459/1 1085/462/1 +f 1085/462/1 1088/461/1 1092/460/1 +f 1093/451/27 1094/452/27 1095/453/27 +f 1095/453/27 1096/454/27 1093/451/27 +f 1097/455/7 1098/456/7 1094/457/7 +f 1094/457/7 1093/458/7 1097/455/7 +f 1098/459/4 1099/460/4 1095/461/4 +f 1095/461/4 1094/462/4 1098/459/4 +f 1099/456/1 1100/455/1 1096/458/1 +f 1096/458/1 1095/457/1 1099/456/1 +f 1100/460/10 1097/459/10 1093/462/10 +f 1093/462/10 1096/461/10 1100/460/10 +f 1101/451/27 1102/452/27 1103/453/27 +f 1103/453/27 1104/454/27 1101/451/27 +f 1105/455/7 1106/456/7 1102/457/7 +f 1102/457/7 1101/458/7 1105/455/7 +f 1106/459/4 1107/460/4 1103/461/4 +f 1103/461/4 1102/462/4 1106/459/4 +f 1107/456/1 1108/455/1 1104/458/1 +f 1104/458/1 1103/457/1 1107/456/1 +f 1108/460/10 1105/459/10 1101/462/10 +f 1101/462/10 1104/461/10 1108/460/10 +f 1109/451/27 1110/452/27 1111/453/27 +f 1111/453/27 1112/454/27 1109/451/27 +f 1113/455/7 1114/456/7 1110/457/7 +f 1110/457/7 1109/458/7 1113/455/7 +f 1114/459/4 1115/460/4 1111/461/4 +f 1111/461/4 1110/462/4 1114/459/4 +f 1115/456/1 1116/455/1 1112/458/1 +f 1112/458/1 1111/457/1 1115/456/1 +f 1116/460/10 1113/459/10 1109/462/10 +f 1109/462/10 1112/461/10 1116/460/10 +f 1117/451/27 1118/452/27 1119/453/27 +f 1119/453/27 1120/454/27 1117/451/27 +f 1121/455/7 1122/456/7 1118/457/7 +f 1118/457/7 1117/458/7 1121/455/7 +f 1122/459/4 1123/460/4 1119/461/4 +f 1119/461/4 1118/462/4 1122/459/4 +f 1123/456/1 1124/455/1 1120/458/1 +f 1120/458/1 1119/457/1 1123/456/1 +f 1124/460/10 1121/459/10 1117/462/10 +f 1117/462/10 1120/461/10 1124/460/10 +f 1125/451/27 1126/452/27 1127/453/27 +f 1127/453/27 1128/454/27 1125/451/27 +f 1129/455/7 1130/456/7 1126/457/7 +f 1126/457/7 1125/458/7 1129/455/7 +f 1130/459/4 1131/460/4 1127/461/4 +f 1127/461/4 1126/462/4 1130/459/4 +f 1131/456/1 1132/455/1 1128/458/1 +f 1128/458/1 1127/457/1 1131/456/1 +f 1132/460/10 1129/459/10 1125/462/10 +f 1125/462/10 1128/461/10 1132/460/10 +f 1133/451/27 1134/452/27 1135/453/27 +f 1135/453/27 1136/454/27 1133/451/27 +f 1137/455/7 1138/456/7 1134/457/7 +f 1134/457/7 1133/458/7 1137/455/7 +f 1138/459/4 1139/460/4 1135/461/4 +f 1135/461/4 1134/462/4 1138/459/4 +f 1139/456/1 1140/455/1 1136/458/1 +f 1136/458/1 1135/457/1 1139/456/1 +f 1140/460/10 1137/459/10 1133/462/10 +f 1133/462/10 1136/461/10 1140/460/10 +f 1141/451/27 1142/452/27 1143/453/27 +f 1143/453/27 1144/454/27 1141/451/27 +f 1145/455/7 1146/456/7 1142/457/7 +f 1142/457/7 1141/458/7 1145/455/7 +f 1146/459/4 1147/460/4 1143/461/4 +f 1143/461/4 1142/462/4 1146/459/4 +f 1147/456/1 1148/455/1 1144/458/1 +f 1144/458/1 1143/457/1 1147/456/1 +f 1148/460/10 1145/459/10 1141/462/10 +f 1141/462/10 1144/461/10 1148/460/10 +f 1149/451/27 1150/452/27 1151/453/27 +f 1151/453/27 1152/454/27 1149/451/27 +f 1153/455/7 1154/456/7 1150/457/7 +f 1150/457/7 1149/458/7 1153/455/7 +f 1154/459/4 1155/460/4 1151/461/4 +f 1151/461/4 1150/462/4 1154/459/4 +f 1155/456/1 1156/455/1 1152/458/1 +f 1152/458/1 1151/457/1 1155/456/1 +f 1156/460/10 1153/459/10 1149/462/10 +f 1149/462/10 1152/461/10 1156/460/10 +f 1157/451/27 1158/452/27 1159/453/27 +f 1159/453/27 1160/454/27 1157/451/27 +f 1161/455/7 1162/456/7 1158/457/7 +f 1158/457/7 1157/458/7 1161/455/7 +f 1162/459/4 1163/460/4 1159/461/4 +f 1159/461/4 1158/462/4 1162/459/4 +f 1163/456/1 1164/455/1 1160/458/1 +f 1160/458/1 1159/457/1 1163/456/1 +f 1164/460/10 1161/459/10 1157/462/10 +f 1157/462/10 1160/461/10 1164/460/10 +f 1165/451/27 1166/452/27 1167/453/27 +f 1167/453/27 1168/454/27 1165/451/27 +f 1169/455/7 1170/456/7 1166/457/7 +f 1166/457/7 1165/458/7 1169/455/7 +f 1170/459/4 1171/460/4 1167/461/4 +f 1167/461/4 1166/462/4 1170/459/4 +f 1171/456/1 1172/455/1 1168/458/1 +f 1168/458/1 1167/457/1 1171/456/1 +f 1172/460/10 1169/459/10 1165/462/10 +f 1165/462/10 1168/461/10 1172/460/10 +f 1173/451/27 1174/452/27 1175/453/27 +f 1175/453/27 1176/454/27 1173/451/27 +f 1177/455/7 1178/456/7 1174/457/7 +f 1174/457/7 1173/458/7 1177/455/7 +f 1178/459/4 1179/460/4 1175/461/4 +f 1175/461/4 1174/462/4 1178/459/4 +f 1179/456/1 1180/455/1 1176/458/1 +f 1176/458/1 1175/457/1 1179/456/1 +f 1180/460/10 1177/459/10 1173/462/10 +f 1173/462/10 1176/461/10 1180/460/10 +f 1181/451/27 1182/452/27 1183/453/27 +f 1183/453/27 1184/454/27 1181/451/27 +f 1185/455/7 1186/456/7 1182/457/7 +f 1182/457/7 1181/458/7 1185/455/7 +f 1186/459/4 1187/460/4 1183/461/4 +f 1183/461/4 1182/462/4 1186/459/4 +f 1187/456/1 1188/455/1 1184/458/1 +f 1184/458/1 1183/457/1 1187/456/1 +f 1188/460/10 1185/459/10 1181/462/10 +f 1181/462/10 1184/461/10 1188/460/10 +f 1189/451/27 1190/452/27 1191/453/27 +f 1191/453/27 1192/454/27 1189/451/27 +f 1193/455/7 1194/456/7 1190/457/7 +f 1190/457/7 1189/458/7 1193/455/7 +f 1194/459/4 1195/460/4 1191/461/4 +f 1191/461/4 1190/462/4 1194/459/4 +f 1195/456/1 1196/455/1 1192/458/1 +f 1192/458/1 1191/457/1 1195/456/1 +f 1196/460/10 1193/459/10 1189/462/10 +f 1189/462/10 1192/461/10 1196/460/10 +f 1197/451/27 1198/452/27 1199/453/27 +f 1199/453/27 1200/454/27 1197/451/27 +f 1201/455/7 1202/456/7 1198/457/7 +f 1198/457/7 1197/458/7 1201/455/7 +f 1202/459/4 1203/460/4 1199/461/4 +f 1199/461/4 1198/462/4 1202/459/4 +f 1203/456/1 1204/455/1 1200/458/1 +f 1200/458/1 1199/457/1 1203/456/1 +f 1204/460/10 1201/459/10 1197/462/10 +f 1197/462/10 1200/461/10 1204/460/10 +f 1205/451/27 1206/452/27 1207/453/27 +f 1207/453/27 1208/454/27 1205/451/27 +f 1209/455/7 1210/456/7 1206/457/7 +f 1206/457/7 1205/458/7 1209/455/7 +f 1210/459/4 1211/460/4 1207/461/4 +f 1207/461/4 1206/462/4 1210/459/4 +f 1211/456/1 1212/455/1 1208/458/1 +f 1208/458/1 1207/457/1 1211/456/1 +f 1212/460/10 1209/459/10 1205/462/10 +f 1205/462/10 1208/461/10 1212/460/10 +f 1213/451/27 1214/452/27 1215/453/27 +f 1215/453/27 1216/454/27 1213/451/27 +f 1217/455/7 1218/456/7 1214/457/7 +f 1214/457/7 1213/458/7 1217/455/7 +f 1218/459/4 1219/460/4 1215/461/4 +f 1215/461/4 1214/462/4 1218/459/4 +f 1219/456/1 1220/455/1 1216/458/1 +f 1216/458/1 1215/457/1 1219/456/1 +f 1220/460/10 1217/459/10 1213/462/10 +f 1213/462/10 1216/461/10 1220/460/10 +f 1221/451/27 1222/452/27 1223/453/27 +f 1223/453/27 1224/454/27 1221/451/27 +f 1225/455/7 1226/456/7 1222/457/7 +f 1222/457/7 1221/458/7 1225/455/7 +f 1226/459/4 1227/460/4 1223/461/4 +f 1223/461/4 1222/462/4 1226/459/4 +f 1227/456/1 1228/455/1 1224/458/1 +f 1224/458/1 1223/457/1 1227/456/1 +f 1228/460/10 1225/459/10 1221/462/10 +f 1221/462/10 1224/461/10 1228/460/10 +f 1229/451/27 1230/452/27 1231/453/27 +f 1231/453/27 1232/454/27 1229/451/27 +f 1233/455/4 1234/456/4 1230/457/4 +f 1230/457/4 1229/458/4 1233/455/4 +f 1234/459/1 1235/460/1 1231/461/1 +f 1231/461/1 1230/462/1 1234/459/1 +f 1235/456/10 1236/455/10 1232/458/10 +f 1232/458/10 1231/457/10 1235/456/10 +f 1236/460/7 1233/459/7 1229/462/7 +f 1229/462/7 1232/461/7 1236/460/7 +f 1237/451/27 1238/452/27 1239/453/27 +f 1239/453/27 1240/454/27 1237/451/27 +f 1241/455/4 1242/456/4 1238/457/4 +f 1238/457/4 1237/458/4 1241/455/4 +f 1242/459/1 1243/460/1 1239/461/1 +f 1239/461/1 1238/462/1 1242/459/1 +f 1243/456/10 1244/455/10 1240/458/10 +f 1240/458/10 1239/457/10 1243/456/10 +f 1244/460/7 1241/459/7 1237/462/7 +f 1237/462/7 1240/461/7 1244/460/7 +f 1245/451/27 1246/452/27 1247/453/27 +f 1247/453/27 1248/454/27 1245/451/27 +f 1249/455/4 1250/456/4 1246/457/4 +f 1246/457/4 1245/458/4 1249/455/4 +f 1250/459/1 1251/460/1 1247/461/1 +f 1247/461/1 1246/462/1 1250/459/1 +f 1251/456/10 1252/455/10 1248/458/10 +f 1248/458/10 1247/457/10 1251/456/10 +f 1252/460/7 1249/459/7 1245/462/7 +f 1245/462/7 1248/461/7 1252/460/7 +f 1253/451/27 1254/452/27 1255/453/27 +f 1255/453/27 1256/454/27 1253/451/27 +f 1257/455/4 1258/456/4 1254/457/4 +f 1254/457/4 1253/458/4 1257/455/4 +f 1258/459/1 1259/460/1 1255/461/1 +f 1255/461/1 1254/462/1 1258/459/1 +f 1259/456/10 1260/455/10 1256/458/10 +f 1256/458/10 1255/457/10 1259/456/10 +f 1260/460/7 1257/459/7 1253/462/7 +f 1253/462/7 1256/461/7 1260/460/7 +f 1261/451/27 1262/452/27 1263/453/27 +f 1263/453/27 1264/454/27 1261/451/27 +f 1265/455/7 1266/456/7 1262/457/7 +f 1262/457/7 1261/458/7 1265/455/7 +f 1266/459/4 1267/460/4 1263/461/4 +f 1263/461/4 1262/462/4 1266/459/4 +f 1267/456/1 1268/455/1 1264/458/1 +f 1264/458/1 1263/457/1 1267/456/1 +f 1268/460/10 1265/459/10 1261/462/10 +f 1261/462/10 1264/461/10 1268/460/10 +f 1269/451/27 1270/452/27 1271/453/27 +f 1271/453/27 1272/454/27 1269/451/27 +f 1273/455/7 1274/456/7 1270/457/7 +f 1270/457/7 1269/458/7 1273/455/7 +f 1274/459/4 1275/460/4 1271/461/4 +f 1271/461/4 1270/462/4 1274/459/4 +f 1275/456/1 1276/455/1 1272/458/1 +f 1272/458/1 1271/457/1 1275/456/1 +f 1276/460/10 1273/459/10 1269/462/10 +f 1269/462/10 1272/461/10 1276/460/10 +f 1277/451/27 1278/452/27 1279/453/27 +f 1279/453/27 1280/454/27 1277/451/27 +f 1281/455/7 1282/456/7 1278/457/7 +f 1278/457/7 1277/458/7 1281/455/7 +f 1282/459/4 1283/460/4 1279/461/4 +f 1279/461/4 1278/462/4 1282/459/4 +f 1283/456/1 1284/455/1 1280/458/1 +f 1280/458/1 1279/457/1 1283/456/1 +f 1284/460/10 1281/459/10 1277/462/10 +f 1277/462/10 1280/461/10 1284/460/10 +f 1285/451/27 1286/452/27 1287/453/27 +f 1287/453/27 1288/454/27 1285/451/27 +f 1289/455/7 1290/456/7 1286/457/7 +f 1286/457/7 1285/458/7 1289/455/7 +f 1290/459/4 1291/460/4 1287/461/4 +f 1287/461/4 1286/462/4 1290/459/4 +f 1291/456/1 1292/455/1 1288/458/1 +f 1288/458/1 1287/457/1 1291/456/1 +f 1292/460/10 1289/459/10 1285/462/10 +f 1285/462/10 1288/461/10 1292/460/10 +f 1293/451/27 1294/452/27 1295/453/27 +f 1295/453/27 1296/454/27 1293/451/27 +f 1297/455/7 1298/456/7 1294/457/7 +f 1294/457/7 1293/458/7 1297/455/7 +f 1298/459/4 1299/460/4 1295/461/4 +f 1295/461/4 1294/462/4 1298/459/4 +f 1299/456/1 1300/455/1 1296/458/1 +f 1296/458/1 1295/457/1 1299/456/1 +f 1300/460/10 1297/459/10 1293/462/10 +f 1293/462/10 1296/461/10 1300/460/10 +f 1301/451/27 1302/452/27 1303/453/27 +f 1303/453/27 1304/454/27 1301/451/27 +f 1305/455/7 1306/456/7 1302/457/7 +f 1302/457/7 1301/458/7 1305/455/7 +f 1306/459/4 1307/460/4 1303/461/4 +f 1303/461/4 1302/462/4 1306/459/4 +f 1307/456/1 1308/455/1 1304/458/1 +f 1304/458/1 1303/457/1 1307/456/1 +f 1308/460/10 1305/459/10 1301/462/10 +f 1301/462/10 1304/461/10 1308/460/10 +f 1309/451/27 1310/452/27 1311/453/27 +f 1311/453/27 1312/454/27 1309/451/27 +f 1313/455/7 1314/456/7 1310/457/7 +f 1310/457/7 1309/458/7 1313/455/7 +f 1314/459/4 1315/460/4 1311/461/4 +f 1311/461/4 1310/462/4 1314/459/4 +f 1315/456/1 1316/455/1 1312/458/1 +f 1312/458/1 1311/457/1 1315/456/1 +f 1316/460/10 1313/459/10 1309/462/10 +f 1309/462/10 1312/461/10 1316/460/10 +f 1317/451/27 1318/452/27 1319/453/27 +f 1319/453/27 1320/454/27 1317/451/27 +f 1321/455/4 1322/456/4 1318/457/4 +f 1318/457/4 1317/458/4 1321/455/4 +f 1322/459/1 1323/460/1 1319/461/1 +f 1319/461/1 1318/462/1 1322/459/1 +f 1323/456/10 1324/455/10 1320/458/10 +f 1320/458/10 1319/457/10 1323/456/10 +f 1324/460/7 1321/459/7 1317/462/7 +f 1317/462/7 1320/461/7 1324/460/7 +f 1325/451/27 1326/452/27 1327/453/27 +f 1327/453/27 1328/454/27 1325/451/27 +f 1329/455/4 1330/456/4 1326/457/4 +f 1326/457/4 1325/458/4 1329/455/4 +f 1330/459/1 1331/460/1 1327/461/1 +f 1327/461/1 1326/462/1 1330/459/1 +f 1331/456/10 1332/455/10 1328/458/10 +f 1328/458/10 1327/457/10 1331/456/10 +f 1332/460/7 1329/459/7 1325/462/7 +f 1325/462/7 1328/461/7 1332/460/7 +f 1333/451/27 1334/452/27 1335/453/27 +f 1335/453/27 1336/454/27 1333/451/27 +f 1337/455/4 1338/456/4 1334/457/4 +f 1334/457/4 1333/458/4 1337/455/4 +f 1338/459/1 1339/460/1 1335/461/1 +f 1335/461/1 1334/462/1 1338/459/1 +f 1339/456/10 1340/455/10 1336/458/10 +f 1336/458/10 1335/457/10 1339/456/10 +f 1340/460/7 1337/459/7 1333/462/7 +f 1333/462/7 1336/461/7 1340/460/7 +f 1341/451/27 1342/452/27 1343/453/27 +f 1343/453/27 1344/454/27 1341/451/27 +f 1345/455/4 1346/456/4 1342/457/4 +f 1342/457/4 1341/458/4 1345/455/4 +f 1346/459/1 1347/460/1 1343/461/1 +f 1343/461/1 1342/462/1 1346/459/1 +f 1347/456/10 1348/455/10 1344/458/10 +f 1344/458/10 1343/457/10 1347/456/10 +f 1348/460/7 1345/459/7 1341/462/7 +f 1341/462/7 1344/461/7 1348/460/7 +f 1349/451/27 1350/452/27 1351/453/27 +f 1351/453/27 1352/454/27 1349/451/27 +f 1353/455/4 1354/456/4 1350/457/4 +f 1350/457/4 1349/458/4 1353/455/4 +f 1354/459/1 1355/460/1 1351/461/1 +f 1351/461/1 1350/462/1 1354/459/1 +f 1355/456/10 1356/455/10 1352/458/10 +f 1352/458/10 1351/457/10 1355/456/10 +f 1356/460/7 1353/459/7 1349/462/7 +f 1349/462/7 1352/461/7 1356/460/7 +f 1357/463/27 1358/464/27 1359/465/27 +f 1359/465/27 1360/466/27 1357/463/27 +f 1361/467/4 1362/468/4 1359/469/4 +f 1359/469/4 1358/470/4 1361/467/4 +f 1363/471/4 1364/472/4 1365/473/4 +f 1365/473/4 1366/474/4 1363/471/4 +f 1367/475/1 1368/476/1 1369/477/1 +f 1369/477/1 1370/478/1 1367/475/1 +f 1371/479/27 1372/480/288 1373/480/288 +f 1373/480/288 1374/479/27 1371/479/27 +f 1375/476/7 1376/475/7 1377/481/7 +f 1377/481/7 1378/482/7 1375/476/7 +f 1379/483/26 1380/484/289 1381/485/289 +f 1381/485/289 1382/483/26 1379/483/26 +f 1383/486/4 1384/487/4 1385/488/4 +f 1386/489/4 1387/490/4 1372/491/4 +f 1372/491/4 1371/492/4 1386/489/4 +f 1388/493/4 1389/494/4 1390/495/4 +f 1391/496/4 1392/497/4 1390/495/4 +f 1390/495/4 1389/494/4 1391/496/4 +f 1393/498/4 1394/499/4 1365/473/4 +f 1365/473/4 1364/472/4 1393/498/4 +f 1395/500/290 1371/479/27 1374/479/27 +f 1374/479/27 1396/500/290 1395/500/290 +f 1397/501/291 1379/483/26 1382/483/26 +f 1382/483/26 1398/501/291 1397/501/291 +f 1395/502/4 1399/503/4 1386/489/4 +f 1386/489/4 1371/492/4 1395/502/4 +f 1391/496/4 1383/486/4 1385/488/4 +f 1385/488/4 1392/497/4 1391/496/4 +f 1387/504/7 1363/504/7 1366/505/7 +f 1366/505/7 1400/505/7 1387/504/7 +f 1386/506/292 1364/506/292 1363/504/292 +f 1363/504/292 1387/504/292 1386/506/292 +f 1399/507/293 1393/507/293 1364/506/293 +f 1364/506/293 1386/506/293 1399/507/293 +f 1401/508/1 1394/508/1 1393/507/1 +f 1393/507/1 1399/507/1 1401/508/1 +f 1402/509/210 1365/510/210 1394/511/210 +f 1394/511/210 1401/512/210 1402/509/210 +f 1400/513/294 1366/514/294 1365/510/294 +f 1365/510/294 1402/509/294 1400/513/294 +f 1403/515/4 1401/516/4 1399/503/4 +f 1399/503/4 1395/502/4 1403/515/4 +f 1395/500/7 1396/500/7 1404/517/7 +f 1404/517/7 1403/517/7 1395/500/7 +f 1372/480/1 1405/518/1 1406/518/1 +f 1406/518/1 1373/480/1 1372/480/1 +f 1405/519/4 1372/491/4 1387/490/4 +f 1387/490/4 1400/474/4 1405/519/4 +f 1367/475/1 1407/481/1 1408/482/1 +f 1408/482/1 1368/476/1 1367/475/1 +f 1400/513/295 1385/513/295 1384/485/295 +f 1384/485/295 1405/520/295 1400/513/295 +f 1402/509/294 1392/509/294 1385/513/294 +f 1385/513/294 1400/513/294 1402/509/294 +f 1401/512/210 1390/512/210 1392/509/210 +f 1392/509/210 1402/509/210 1401/512/210 +f 1403/521/296 1388/521/296 1390/512/296 +f 1390/512/296 1401/512/296 1403/521/296 +f 1375/476/7 1409/477/7 1410/478/7 +f 1410/478/7 1376/475/7 1375/476/7 +f 1379/483/289 1391/522/289 1389/523/289 +f 1389/523/289 1380/484/289 1379/483/289 +f 1397/501/291 1383/524/291 1391/522/291 +f 1391/522/291 1379/483/291 1397/501/291 +f 1405/520/27 1367/525/27 1370/526/27 +f 1370/526/27 1406/527/27 1405/520/27 +f 1384/485/27 1407/528/27 1367/525/27 +f 1367/525/27 1405/520/27 1384/485/27 +f 1383/486/4 1408/486/4 1407/487/4 +f 1407/487/4 1384/487/4 1383/486/4 +f 1397/501/26 1368/501/26 1408/524/26 +f 1408/524/26 1383/524/26 1397/501/26 +f 1398/501/26 1369/501/26 1368/501/26 +f 1368/501/26 1397/501/26 1398/501/26 +f 1380/484/26 1375/484/26 1378/485/26 +f 1378/485/26 1381/485/26 1380/484/26 +f 1389/523/26 1409/523/26 1375/484/26 +f 1375/484/26 1380/484/26 1389/523/26 +f 1388/493/4 1410/529/4 1409/530/4 +f 1409/530/4 1389/494/4 1388/493/4 +f 1403/521/27 1376/531/27 1410/532/27 +f 1410/532/27 1388/521/27 1403/521/27 +f 1404/533/27 1377/531/27 1376/531/27 +f 1376/531/27 1403/521/27 1404/533/27 +f 1411/471/4 1412/472/4 1413/473/4 +f 1413/473/4 1414/474/4 1411/471/4 +f 1415/475/1 1416/476/1 1417/477/1 +f 1417/477/1 1418/478/1 1415/475/1 +f 1419/479/27 1420/480/288 1421/480/288 +f 1421/480/288 1422/479/27 1419/479/27 +f 1423/476/7 1424/475/7 1425/481/7 +f 1425/481/7 1426/482/7 1423/476/7 +f 1427/483/26 1428/484/289 1429/485/289 +f 1429/485/289 1430/483/26 1427/483/26 +f 1431/486/4 1432/487/4 1433/488/4 +f 1434/489/4 1435/490/4 1420/491/4 +f 1420/491/4 1419/492/4 1434/489/4 +f 1436/493/4 1437/494/4 1438/495/4 +f 1439/496/4 1440/497/4 1438/495/4 +f 1438/495/4 1437/494/4 1439/496/4 +f 1441/498/4 1442/499/4 1413/473/4 +f 1413/473/4 1412/472/4 1441/498/4 +f 1443/500/290 1419/479/27 1422/479/27 +f 1422/479/27 1444/500/290 1443/500/290 +f 1445/501/291 1427/483/26 1430/483/26 +f 1430/483/26 1446/501/291 1445/501/291 +f 1443/502/4 1447/503/4 1434/489/4 +f 1434/489/4 1419/492/4 1443/502/4 +f 1439/496/4 1431/486/4 1433/488/4 +f 1433/488/4 1440/497/4 1439/496/4 +f 1435/504/7 1411/504/7 1414/505/7 +f 1414/505/7 1448/505/7 1435/504/7 +f 1434/506/292 1412/506/292 1411/504/292 +f 1411/504/292 1435/504/292 1434/506/292 +f 1447/507/293 1441/507/293 1412/506/293 +f 1412/506/293 1434/506/293 1447/507/293 +f 1449/508/1 1442/508/1 1441/507/1 +f 1441/507/1 1447/507/1 1449/508/1 +f 1450/509/210 1413/510/210 1442/511/210 +f 1442/511/210 1449/512/210 1450/509/210 +f 1448/513/294 1414/514/294 1413/510/294 +f 1413/510/294 1450/509/294 1448/513/294 +f 1451/515/4 1449/516/4 1447/503/4 +f 1447/503/4 1443/502/4 1451/515/4 +f 1443/500/7 1444/500/7 1452/517/7 +f 1452/517/7 1451/517/7 1443/500/7 +f 1420/480/1 1453/518/1 1454/518/1 +f 1454/518/1 1421/480/1 1420/480/1 +f 1453/519/4 1420/491/4 1435/490/4 +f 1435/490/4 1448/474/4 1453/519/4 +f 1415/475/1 1455/481/1 1456/482/1 +f 1456/482/1 1416/476/1 1415/475/1 +f 1448/513/295 1433/513/295 1432/485/295 +f 1432/485/295 1453/520/295 1448/513/295 +f 1450/509/294 1440/509/294 1433/513/294 +f 1433/513/294 1448/513/294 1450/509/294 +f 1449/512/210 1438/512/210 1440/509/210 +f 1440/509/210 1450/509/210 1449/512/210 +f 1451/521/296 1436/521/296 1438/512/296 +f 1438/512/296 1449/512/296 1451/521/296 +f 1423/476/7 1457/477/7 1458/478/7 +f 1458/478/7 1424/475/7 1423/476/7 +f 1427/483/289 1439/522/289 1437/523/289 +f 1437/523/289 1428/484/289 1427/483/289 +f 1445/501/291 1431/524/291 1439/522/291 +f 1439/522/291 1427/483/291 1445/501/291 +f 1453/520/27 1415/525/27 1418/526/27 +f 1418/526/27 1454/527/27 1453/520/27 +f 1432/485/27 1455/528/27 1415/525/27 +f 1415/525/27 1453/520/27 1432/485/27 +f 1431/486/4 1456/486/4 1455/487/4 +f 1455/487/4 1432/487/4 1431/486/4 +f 1445/501/26 1416/501/26 1456/524/26 +f 1456/524/26 1431/524/26 1445/501/26 +f 1446/501/26 1417/501/26 1416/501/26 +f 1416/501/26 1445/501/26 1446/501/26 +f 1428/484/26 1423/484/26 1426/485/26 +f 1426/485/26 1429/485/26 1428/484/26 +f 1437/523/26 1457/523/26 1423/484/26 +f 1423/484/26 1428/484/26 1437/523/26 +f 1436/493/4 1458/529/4 1457/530/4 +f 1457/530/4 1437/494/4 1436/493/4 +f 1451/521/27 1424/531/27 1458/532/27 +f 1458/532/27 1436/521/27 1451/521/27 +f 1452/533/27 1425/531/27 1424/531/27 +f 1424/531/27 1451/521/27 1452/533/27 +f 1459/471/4 1460/472/4 1461/473/4 +f 1461/473/4 1462/474/4 1459/471/4 +f 1463/475/1 1464/476/1 1465/477/1 +f 1465/477/1 1466/478/1 1463/475/1 +f 1467/479/27 1468/480/288 1469/480/288 +f 1469/480/288 1470/479/27 1467/479/27 +f 1471/476/7 1472/475/7 1473/481/7 +f 1473/481/7 1474/482/7 1471/476/7 +f 1475/483/26 1476/484/289 1477/485/289 +f 1477/485/289 1478/483/26 1475/483/26 +f 1479/486/4 1480/487/4 1481/488/4 +f 1482/489/4 1483/490/4 1468/491/4 +f 1468/491/4 1467/492/4 1482/489/4 +f 1484/493/4 1485/494/4 1486/495/4 +f 1487/496/4 1488/497/4 1486/495/4 +f 1486/495/4 1485/494/4 1487/496/4 +f 1489/498/4 1490/499/4 1461/473/4 +f 1461/473/4 1460/472/4 1489/498/4 +f 1491/500/290 1467/479/27 1470/479/27 +f 1470/479/27 1492/500/290 1491/500/290 +f 1493/501/291 1475/483/26 1478/483/26 +f 1478/483/26 1494/501/291 1493/501/291 +f 1491/502/4 1495/503/4 1482/489/4 +f 1482/489/4 1467/492/4 1491/502/4 +f 1487/496/4 1479/486/4 1481/488/4 +f 1481/488/4 1488/497/4 1487/496/4 +f 1483/504/7 1459/504/7 1462/505/7 +f 1462/505/7 1496/505/7 1483/504/7 +f 1482/506/292 1460/506/292 1459/504/292 +f 1459/504/292 1483/504/292 1482/506/292 +f 1495/507/293 1489/507/293 1460/506/293 +f 1460/506/293 1482/506/293 1495/507/293 +f 1497/508/1 1490/508/1 1489/507/1 +f 1489/507/1 1495/507/1 1497/508/1 +f 1498/509/210 1461/510/210 1490/511/210 +f 1490/511/210 1497/512/210 1498/509/210 +f 1496/513/294 1462/514/294 1461/510/294 +f 1461/510/294 1498/509/294 1496/513/294 +f 1499/515/4 1497/516/4 1495/503/4 +f 1495/503/4 1491/502/4 1499/515/4 +f 1491/500/7 1492/500/7 1500/517/7 +f 1500/517/7 1499/517/7 1491/500/7 +f 1468/480/1 1501/518/1 1502/518/1 +f 1502/518/1 1469/480/1 1468/480/1 +f 1501/519/4 1468/491/4 1483/490/4 +f 1483/490/4 1496/474/4 1501/519/4 +f 1463/475/1 1503/481/1 1504/482/1 +f 1504/482/1 1464/476/1 1463/475/1 +f 1496/513/295 1481/513/295 1480/485/295 +f 1480/485/295 1501/520/295 1496/513/295 +f 1498/509/294 1488/509/294 1481/513/294 +f 1481/513/294 1496/513/294 1498/509/294 +f 1497/512/210 1486/512/210 1488/509/210 +f 1488/509/210 1498/509/210 1497/512/210 +f 1499/521/296 1484/521/296 1486/512/296 +f 1486/512/296 1497/512/296 1499/521/296 +f 1471/476/7 1505/477/7 1506/478/7 +f 1506/478/7 1472/475/7 1471/476/7 +f 1475/483/289 1487/522/289 1485/523/289 +f 1485/523/289 1476/484/289 1475/483/289 +f 1493/501/291 1479/524/291 1487/522/291 +f 1487/522/291 1475/483/291 1493/501/291 +f 1501/520/27 1463/525/27 1466/526/27 +f 1466/526/27 1502/527/27 1501/520/27 +f 1480/485/27 1503/528/27 1463/525/27 +f 1463/525/27 1501/520/27 1480/485/27 +f 1479/486/4 1504/486/4 1503/487/4 +f 1503/487/4 1480/487/4 1479/486/4 +f 1493/501/26 1464/501/26 1504/524/26 +f 1504/524/26 1479/524/26 1493/501/26 +f 1494/501/26 1465/501/26 1464/501/26 +f 1464/501/26 1493/501/26 1494/501/26 +f 1476/484/26 1471/484/26 1474/485/26 +f 1474/485/26 1477/485/26 1476/484/26 +f 1485/523/26 1505/523/26 1471/484/26 +f 1471/484/26 1476/484/26 1485/523/26 +f 1484/493/4 1506/529/4 1505/530/4 +f 1505/530/4 1485/494/4 1484/493/4 +f 1499/521/27 1472/531/27 1506/532/27 +f 1506/532/27 1484/521/27 1499/521/27 +f 1500/533/27 1473/531/27 1472/531/27 +f 1472/531/27 1499/521/27 1500/533/27 +f 1507/471/4 1508/472/4 1509/473/4 +f 1509/473/4 1510/474/4 1507/471/4 +f 1511/475/1 1512/476/1 1513/477/1 +f 1513/477/1 1514/478/1 1511/475/1 +f 1515/479/27 1516/480/288 1517/480/288 +f 1517/480/288 1518/479/27 1515/479/27 +f 1519/476/7 1520/475/7 1521/481/7 +f 1521/481/7 1522/482/7 1519/476/7 +f 1523/483/26 1524/484/289 1525/485/289 +f 1525/485/289 1526/483/26 1523/483/26 +f 1527/486/4 1528/487/4 1529/488/4 +f 1530/489/4 1531/490/4 1516/491/4 +f 1516/491/4 1515/492/4 1530/489/4 +f 1532/493/4 1533/494/4 1534/495/4 +f 1535/496/4 1536/497/4 1534/495/4 +f 1534/495/4 1533/494/4 1535/496/4 +f 1537/498/4 1538/499/4 1509/473/4 +f 1509/473/4 1508/472/4 1537/498/4 +f 1539/500/290 1515/479/27 1518/479/27 +f 1518/479/27 1540/500/290 1539/500/290 +f 1541/501/291 1523/483/26 1526/483/26 +f 1526/483/26 1542/501/291 1541/501/291 +f 1539/502/4 1543/503/4 1530/489/4 +f 1530/489/4 1515/492/4 1539/502/4 +f 1535/496/4 1527/486/4 1529/488/4 +f 1529/488/4 1536/497/4 1535/496/4 +f 1531/504/7 1507/504/7 1510/505/7 +f 1510/505/7 1544/505/7 1531/504/7 +f 1530/506/292 1508/506/292 1507/504/292 +f 1507/504/292 1531/504/292 1530/506/292 +f 1543/507/293 1537/507/293 1508/506/293 +f 1508/506/293 1530/506/293 1543/507/293 +f 1545/508/1 1538/508/1 1537/507/1 +f 1537/507/1 1543/507/1 1545/508/1 +f 1546/509/210 1509/510/210 1538/511/210 +f 1538/511/210 1545/512/210 1546/509/210 +f 1544/513/294 1510/514/294 1509/510/294 +f 1509/510/294 1546/509/294 1544/513/294 +f 1547/515/4 1545/516/4 1543/503/4 +f 1543/503/4 1539/502/4 1547/515/4 +f 1539/500/7 1540/500/7 1548/517/7 +f 1548/517/7 1547/517/7 1539/500/7 +f 1516/480/1 1549/518/1 1550/518/1 +f 1550/518/1 1517/480/1 1516/480/1 +f 1549/519/4 1516/491/4 1531/490/4 +f 1531/490/4 1544/474/4 1549/519/4 +f 1511/475/1 1551/481/1 1552/482/1 +f 1552/482/1 1512/476/1 1511/475/1 +f 1544/513/295 1529/513/295 1528/485/295 +f 1528/485/295 1549/520/295 1544/513/295 +f 1546/509/294 1536/509/294 1529/513/294 +f 1529/513/294 1544/513/294 1546/509/294 +f 1545/512/210 1534/512/210 1536/509/210 +f 1536/509/210 1546/509/210 1545/512/210 +f 1547/521/296 1532/521/296 1534/512/296 +f 1534/512/296 1545/512/296 1547/521/296 +f 1519/476/7 1553/477/7 1554/478/7 +f 1554/478/7 1520/475/7 1519/476/7 +f 1523/483/289 1535/522/289 1533/523/289 +f 1533/523/289 1524/484/289 1523/483/289 +f 1541/501/291 1527/524/291 1535/522/291 +f 1535/522/291 1523/483/291 1541/501/291 +f 1549/520/27 1511/525/27 1514/526/27 +f 1514/526/27 1550/527/27 1549/520/27 +f 1528/485/27 1551/528/27 1511/525/27 +f 1511/525/27 1549/520/27 1528/485/27 +f 1527/486/4 1552/486/4 1551/487/4 +f 1551/487/4 1528/487/4 1527/486/4 +f 1541/501/26 1512/501/26 1552/524/26 +f 1552/524/26 1527/524/26 1541/501/26 +f 1542/501/26 1513/501/26 1512/501/26 +f 1512/501/26 1541/501/26 1542/501/26 +f 1524/484/26 1519/484/26 1522/485/26 +f 1522/485/26 1525/485/26 1524/484/26 +f 1533/523/26 1553/523/26 1519/484/26 +f 1519/484/26 1524/484/26 1533/523/26 +f 1532/493/4 1554/529/4 1553/530/4 +f 1553/530/4 1533/494/4 1532/493/4 +f 1547/521/27 1520/531/27 1554/532/27 +f 1554/532/27 1532/521/27 1547/521/27 +f 1548/533/27 1521/531/27 1520/531/27 +f 1520/531/27 1547/521/27 1548/533/27 +f 1555/471/4 1556/472/4 1557/473/4 +f 1557/473/4 1558/474/4 1555/471/4 +f 1559/475/1 1560/476/1 1561/477/1 +f 1561/477/1 1562/478/1 1559/475/1 +f 1563/479/27 1564/480/288 1565/480/288 +f 1565/480/288 1566/479/27 1563/479/27 +f 1567/476/7 1568/475/7 1569/481/7 +f 1569/481/7 1570/482/7 1567/476/7 +f 1571/483/26 1572/484/289 1573/485/289 +f 1573/485/289 1574/483/26 1571/483/26 +f 1575/486/4 1576/487/4 1577/488/4 +f 1578/489/4 1579/490/4 1564/491/4 +f 1564/491/4 1563/492/4 1578/489/4 +f 1580/493/4 1581/494/4 1582/495/4 +f 1583/496/4 1584/497/4 1582/495/4 +f 1582/495/4 1581/494/4 1583/496/4 +f 1585/498/4 1586/499/4 1557/473/4 +f 1557/473/4 1556/472/4 1585/498/4 +f 1587/500/290 1563/479/27 1566/479/27 +f 1566/479/27 1588/500/290 1587/500/290 +f 1589/501/291 1571/483/26 1574/483/26 +f 1574/483/26 1590/501/291 1589/501/291 +f 1587/502/4 1591/503/4 1578/489/4 +f 1578/489/4 1563/492/4 1587/502/4 +f 1583/496/4 1575/486/4 1577/488/4 +f 1577/488/4 1584/497/4 1583/496/4 +f 1579/504/7 1555/504/7 1558/505/7 +f 1558/505/7 1592/505/7 1579/504/7 +f 1578/506/292 1556/506/292 1555/504/292 +f 1555/504/292 1579/504/292 1578/506/292 +f 1591/507/293 1585/507/293 1556/506/293 +f 1556/506/293 1578/506/293 1591/507/293 +f 1593/508/1 1586/508/1 1585/507/1 +f 1585/507/1 1591/507/1 1593/508/1 +f 1594/509/210 1557/510/210 1586/511/210 +f 1586/511/210 1593/512/210 1594/509/210 +f 1592/513/294 1558/514/294 1557/510/294 +f 1557/510/294 1594/509/294 1592/513/294 +f 1595/515/4 1593/516/4 1591/503/4 +f 1591/503/4 1587/502/4 1595/515/4 +f 1587/500/7 1588/500/7 1596/517/7 +f 1596/517/7 1595/517/7 1587/500/7 +f 1564/480/1 1597/518/1 1598/518/1 +f 1598/518/1 1565/480/1 1564/480/1 +f 1597/519/4 1564/491/4 1579/490/4 +f 1579/490/4 1592/474/4 1597/519/4 +f 1559/475/1 1599/481/1 1600/482/1 +f 1600/482/1 1560/476/1 1559/475/1 +f 1592/513/295 1577/513/295 1576/485/295 +f 1576/485/295 1597/520/295 1592/513/295 +f 1594/509/294 1584/509/294 1577/513/294 +f 1577/513/294 1592/513/294 1594/509/294 +f 1593/512/210 1582/512/210 1584/509/210 +f 1584/509/210 1594/509/210 1593/512/210 +f 1595/521/296 1580/521/296 1582/512/296 +f 1582/512/296 1593/512/296 1595/521/296 +f 1567/476/7 1601/477/7 1602/478/7 +f 1602/478/7 1568/475/7 1567/476/7 +f 1571/483/289 1583/522/289 1581/523/289 +f 1581/523/289 1572/484/289 1571/483/289 +f 1589/501/291 1575/524/291 1583/522/291 +f 1583/522/291 1571/483/291 1589/501/291 +f 1597/520/27 1559/525/27 1562/526/27 +f 1562/526/27 1598/527/27 1597/520/27 +f 1576/485/27 1599/528/27 1559/525/27 +f 1559/525/27 1597/520/27 1576/485/27 +f 1575/486/4 1600/486/4 1599/487/4 +f 1599/487/4 1576/487/4 1575/486/4 +f 1589/501/26 1560/501/26 1600/524/26 +f 1600/524/26 1575/524/26 1589/501/26 +f 1590/501/26 1561/501/26 1560/501/26 +f 1560/501/26 1589/501/26 1590/501/26 +f 1572/484/26 1567/484/26 1570/485/26 +f 1570/485/26 1573/485/26 1572/484/26 +f 1581/523/26 1601/523/26 1567/484/26 +f 1567/484/26 1572/484/26 1581/523/26 +f 1580/493/4 1602/529/4 1601/530/4 +f 1601/530/4 1581/494/4 1580/493/4 +f 1595/521/27 1568/531/27 1602/532/27 +f 1602/532/27 1580/521/27 1595/521/27 +f 1596/533/27 1569/531/27 1568/531/27 +f 1568/531/27 1595/521/27 1596/533/27 +f 1603/471/4 1604/472/4 1605/473/4 +f 1605/473/4 1606/474/4 1603/471/4 +f 1607/475/1 1608/476/1 1609/477/1 +f 1609/477/1 1610/478/1 1607/475/1 +f 1611/479/27 1612/480/288 1613/480/288 +f 1613/480/288 1614/479/27 1611/479/27 +f 1615/476/7 1616/475/7 1617/481/7 +f 1617/481/7 1618/482/7 1615/476/7 +f 1619/483/26 1620/484/289 1621/485/289 +f 1621/485/289 1622/483/26 1619/483/26 +f 1623/486/4 1624/487/4 1625/488/4 +f 1626/489/4 1627/490/4 1612/491/4 +f 1612/491/4 1611/492/4 1626/489/4 +f 1628/493/4 1629/494/4 1630/495/4 +f 1631/496/4 1632/497/4 1630/495/4 +f 1630/495/4 1629/494/4 1631/496/4 +f 1633/498/4 1634/499/4 1605/473/4 +f 1605/473/4 1604/472/4 1633/498/4 +f 1635/500/290 1611/479/27 1614/479/27 +f 1614/479/27 1636/500/290 1635/500/290 +f 1637/501/291 1619/483/26 1622/483/26 +f 1622/483/26 1638/501/291 1637/501/291 +f 1635/502/4 1639/503/4 1626/489/4 +f 1626/489/4 1611/492/4 1635/502/4 +f 1631/496/4 1623/486/4 1625/488/4 +f 1625/488/4 1632/497/4 1631/496/4 +f 1627/504/7 1603/504/7 1606/505/7 +f 1606/505/7 1640/505/7 1627/504/7 +f 1626/506/292 1604/506/292 1603/504/292 +f 1603/504/292 1627/504/292 1626/506/292 +f 1639/507/293 1633/507/293 1604/506/293 +f 1604/506/293 1626/506/293 1639/507/293 +f 1641/508/1 1634/508/1 1633/507/1 +f 1633/507/1 1639/507/1 1641/508/1 +f 1642/509/210 1605/510/210 1634/511/210 +f 1634/511/210 1641/512/210 1642/509/210 +f 1640/513/294 1606/514/294 1605/510/294 +f 1605/510/294 1642/509/294 1640/513/294 +f 1643/515/4 1641/516/4 1639/503/4 +f 1639/503/4 1635/502/4 1643/515/4 +f 1635/500/7 1636/500/7 1644/517/7 +f 1644/517/7 1643/517/7 1635/500/7 +f 1612/480/1 1645/518/1 1646/518/1 +f 1646/518/1 1613/480/1 1612/480/1 +f 1645/519/4 1612/491/4 1627/490/4 +f 1627/490/4 1640/474/4 1645/519/4 +f 1607/475/1 1647/481/1 1648/482/1 +f 1648/482/1 1608/476/1 1607/475/1 +f 1640/513/295 1625/513/295 1624/485/295 +f 1624/485/295 1645/520/295 1640/513/295 +f 1642/509/294 1632/509/294 1625/513/294 +f 1625/513/294 1640/513/294 1642/509/294 +f 1641/512/210 1630/512/210 1632/509/210 +f 1632/509/210 1642/509/210 1641/512/210 +f 1643/521/296 1628/521/296 1630/512/296 +f 1630/512/296 1641/512/296 1643/521/296 +f 1615/476/7 1649/477/7 1650/478/7 +f 1650/478/7 1616/475/7 1615/476/7 +f 1619/483/289 1631/522/289 1629/523/289 +f 1629/523/289 1620/484/289 1619/483/289 +f 1637/501/291 1623/524/291 1631/522/297 +f 1631/522/297 1619/483/297 1637/501/291 +f 1645/520/27 1607/525/27 1610/526/27 +f 1610/526/27 1646/527/27 1645/520/27 +f 1624/485/27 1647/528/27 1607/525/27 +f 1607/525/27 1645/520/27 1624/485/27 +f 1623/486/4 1648/486/4 1647/487/4 +f 1647/487/4 1624/487/4 1623/486/4 +f 1637/501/26 1608/501/26 1648/524/26 +f 1648/524/26 1623/524/26 1637/501/26 +f 1638/501/26 1609/501/26 1608/501/26 +f 1608/501/26 1637/501/26 1638/501/26 +f 1620/484/26 1615/484/26 1618/485/26 +f 1618/485/26 1621/485/26 1620/484/26 +f 1629/523/26 1649/523/26 1615/484/26 +f 1615/484/26 1620/484/26 1629/523/26 +f 1628/493/4 1650/529/4 1649/530/4 +f 1649/530/4 1629/494/4 1628/493/4 +f 1643/521/27 1616/531/27 1650/532/27 +f 1650/532/27 1628/521/27 1643/521/27 +f 1644/533/27 1617/531/27 1616/531/27 +f 1616/531/27 1643/521/27 1644/533/27 +f 1651/471/4 1652/472/4 1653/473/4 +f 1653/473/4 1654/474/4 1651/471/4 +f 1655/475/1 1656/476/1 1657/477/1 +f 1657/477/1 1658/478/1 1655/475/1 +f 1659/479/27 1660/480/288 1661/480/288 +f 1661/480/288 1662/479/27 1659/479/27 +f 1663/476/7 1664/475/7 1665/481/7 +f 1665/481/7 1666/482/7 1663/476/7 +f 1667/483/26 1668/484/289 1669/485/289 +f 1669/485/289 1670/483/26 1667/483/26 +f 1671/486/4 1672/487/4 1673/488/4 +f 1674/489/4 1675/490/4 1660/491/4 +f 1660/491/4 1659/492/4 1674/489/4 +f 1676/493/4 1677/494/4 1678/495/4 +f 1679/496/4 1680/497/4 1678/495/4 +f 1678/495/4 1677/494/4 1679/496/4 +f 1681/498/4 1682/499/4 1653/473/4 +f 1653/473/4 1652/472/4 1681/498/4 +f 1683/500/290 1659/479/27 1662/479/27 +f 1662/479/27 1684/500/290 1683/500/290 +f 1685/501/291 1667/483/26 1670/483/26 +f 1670/483/26 1686/501/291 1685/501/291 +f 1683/502/4 1687/503/4 1674/489/4 +f 1674/489/4 1659/492/4 1683/502/4 +f 1679/496/4 1671/486/4 1673/488/4 +f 1673/488/4 1680/497/4 1679/496/4 +f 1675/504/7 1651/504/7 1654/505/7 +f 1654/505/7 1688/505/7 1675/504/7 +f 1674/506/292 1652/506/292 1651/504/292 +f 1651/504/292 1675/504/292 1674/506/292 +f 1687/507/293 1681/507/293 1652/506/293 +f 1652/506/293 1674/506/293 1687/507/293 +f 1689/508/1 1682/508/1 1681/507/1 +f 1681/507/1 1687/507/1 1689/508/1 +f 1690/509/210 1653/510/210 1682/511/210 +f 1682/511/210 1689/512/210 1690/509/210 +f 1688/513/294 1654/514/294 1653/510/294 +f 1653/510/294 1690/509/294 1688/513/294 +f 1691/515/4 1689/516/4 1687/503/4 +f 1687/503/4 1683/502/4 1691/515/4 +f 1683/500/7 1684/500/7 1692/517/7 +f 1692/517/7 1691/517/7 1683/500/7 +f 1660/480/1 1693/518/1 1694/518/1 +f 1694/518/1 1661/480/1 1660/480/1 +f 1693/519/4 1660/491/4 1675/490/4 +f 1675/490/4 1688/474/4 1693/519/4 +f 1655/475/1 1695/481/1 1696/482/1 +f 1696/482/1 1656/476/1 1655/475/1 +f 1688/513/295 1673/513/295 1672/485/295 +f 1672/485/295 1693/520/295 1688/513/295 +f 1690/509/294 1680/509/294 1673/513/294 +f 1673/513/294 1688/513/294 1690/509/294 +f 1689/512/210 1678/512/210 1680/509/210 +f 1680/509/210 1690/509/210 1689/512/210 +f 1691/521/296 1676/521/296 1678/512/296 +f 1678/512/296 1689/512/296 1691/521/296 +f 1663/476/7 1697/477/7 1698/478/7 +f 1698/478/7 1664/475/7 1663/476/7 +f 1667/483/298 1679/522/298 1677/523/289 +f 1677/523/289 1668/484/289 1667/483/298 +f 1685/501/291 1671/524/291 1679/522/297 +f 1679/522/297 1667/483/297 1685/501/291 +f 1693/520/27 1655/525/27 1658/526/27 +f 1658/526/27 1694/527/27 1693/520/27 +f 1672/485/27 1695/528/27 1655/525/27 +f 1655/525/27 1693/520/27 1672/485/27 +f 1671/486/4 1696/486/4 1695/487/4 +f 1695/487/4 1672/487/4 1671/486/4 +f 1685/501/26 1656/501/26 1696/524/26 +f 1696/524/26 1671/524/26 1685/501/26 +f 1686/501/26 1657/501/26 1656/501/26 +f 1656/501/26 1685/501/26 1686/501/26 +f 1668/484/26 1663/484/26 1666/485/26 +f 1666/485/26 1669/485/26 1668/484/26 +f 1677/523/26 1697/523/26 1663/484/26 +f 1663/484/26 1668/484/26 1677/523/26 +f 1676/493/4 1698/529/4 1697/530/4 +f 1697/530/4 1677/494/4 1676/493/4 +f 1691/521/27 1664/531/27 1698/532/27 +f 1698/532/27 1676/521/27 1691/521/27 +f 1692/533/27 1665/531/27 1664/531/27 +f 1664/531/27 1691/521/27 1692/533/27 +f 1699/471/1 1700/472/1 1701/473/1 +f 1701/473/1 1702/474/1 1699/471/1 +f 1703/475/10 1704/476/10 1705/477/10 +f 1705/477/10 1706/478/10 1703/475/10 +f 1707/479/27 1708/480/299 1709/480/299 +f 1709/480/299 1710/479/27 1707/479/27 +f 1711/476/4 1712/475/4 1713/481/4 +f 1713/481/4 1714/482/4 1711/476/4 +f 1715/483/26 1716/484/300 1717/485/300 +f 1717/485/300 1718/483/26 1715/483/26 +f 1719/486/1 1720/487/1 1721/488/1 +f 1722/489/1 1723/490/1 1708/491/1 +f 1708/491/1 1707/492/1 1722/489/1 +f 1724/493/1 1725/494/1 1726/495/1 +f 1727/496/1 1728/497/1 1726/495/1 +f 1726/495/1 1725/494/1 1727/496/1 +f 1729/498/1 1730/499/1 1701/473/1 +f 1701/473/1 1700/472/1 1729/498/1 +f 1731/500/301 1707/479/27 1710/479/27 +f 1710/479/27 1732/500/301 1731/500/301 +f 1733/501/302 1715/483/26 1718/483/26 +f 1718/483/26 1734/501/302 1733/501/302 +f 1731/502/1 1735/503/1 1722/489/1 +f 1722/489/1 1707/492/1 1731/502/1 +f 1727/496/1 1719/486/1 1721/488/1 +f 1721/488/1 1728/497/1 1727/496/1 +f 1723/504/4 1699/504/4 1702/505/4 +f 1702/505/4 1736/505/4 1723/504/4 +f 1722/506/303 1700/506/303 1699/504/303 +f 1699/504/303 1723/504/303 1722/506/303 +f 1735/507/304 1729/507/304 1700/506/304 +f 1700/506/304 1722/506/304 1735/507/304 +f 1737/508/10 1730/508/10 1729/507/10 +f 1729/507/10 1735/507/10 1737/508/10 +f 1738/509/305 1701/510/305 1730/511/305 +f 1730/511/305 1737/512/305 1738/509/305 +f 1736/513/306 1702/514/306 1701/510/306 +f 1701/510/306 1738/509/306 1736/513/306 +f 1739/515/1 1737/516/1 1735/503/1 +f 1735/503/1 1731/502/1 1739/515/1 +f 1731/500/4 1732/500/4 1740/517/4 +f 1740/517/4 1739/517/4 1731/500/4 +f 1708/480/10 1741/518/10 1742/518/10 +f 1742/518/10 1709/480/10 1708/480/10 +f 1741/519/1 1708/491/1 1723/490/1 +f 1723/490/1 1736/474/1 1741/519/1 +f 1703/475/10 1743/481/10 1744/482/10 +f 1744/482/10 1704/476/10 1703/475/10 +f 1736/513/307 1721/513/307 1720/485/307 +f 1720/485/307 1741/520/307 1736/513/307 +f 1738/509/306 1728/509/306 1721/513/306 +f 1721/513/306 1736/513/306 1738/509/306 +f 1737/512/305 1726/512/305 1728/509/305 +f 1728/509/305 1738/509/305 1737/512/305 +f 1739/521/308 1724/521/308 1726/512/308 +f 1726/512/308 1737/512/308 1739/521/308 +f 1711/476/4 1745/477/4 1746/478/4 +f 1746/478/4 1712/475/4 1711/476/4 +f 1715/483/300 1727/522/300 1725/523/300 +f 1725/523/300 1716/484/300 1715/483/300 +f 1733/501/302 1719/524/302 1727/522/302 +f 1727/522/302 1715/483/302 1733/501/302 +f 1741/520/27 1703/525/27 1706/526/27 +f 1706/526/27 1742/527/27 1741/520/27 +f 1720/485/27 1743/528/27 1703/525/27 +f 1703/525/27 1741/520/27 1720/485/27 +f 1719/486/1 1744/486/1 1743/487/1 +f 1743/487/1 1720/487/1 1719/486/1 +f 1733/501/26 1704/501/26 1744/524/26 +f 1744/524/26 1719/524/26 1733/501/26 +f 1734/501/26 1705/501/26 1704/501/26 +f 1704/501/26 1733/501/26 1734/501/26 +f 1716/484/26 1711/484/26 1714/485/26 +f 1714/485/26 1717/485/26 1716/484/26 +f 1725/523/26 1745/523/26 1711/484/26 +f 1711/484/26 1716/484/26 1725/523/26 +f 1724/493/1 1746/529/1 1745/530/1 +f 1745/530/1 1725/494/1 1724/493/1 +f 1739/521/27 1712/531/27 1746/532/27 +f 1746/532/27 1724/521/27 1739/521/27 +f 1740/533/27 1713/531/27 1712/531/27 +f 1712/531/27 1739/521/27 1740/533/27 +f 1747/471/1 1748/474/1 1749/473/1 +f 1749/473/1 1750/472/1 1747/471/1 +f 1751/475/4 1752/478/4 1753/477/4 +f 1753/477/4 1754/476/4 1751/475/4 +f 1755/479/27 1756/479/27 1757/480/301 +f 1757/480/301 1758/480/301 1755/479/27 +f 1759/476/10 1760/482/10 1761/481/10 +f 1761/481/10 1762/475/10 1759/476/10 +f 1763/483/26 1764/483/26 1765/485/302 +f 1765/485/302 1766/484/302 1763/483/26 +f 1767/486/1 1768/488/1 1769/487/1 +f 1770/489/1 1755/492/1 1758/491/1 +f 1758/491/1 1771/490/1 1770/489/1 +f 1772/493/1 1773/495/1 1774/494/1 +f 1775/496/1 1774/494/1 1773/495/1 +f 1773/495/1 1776/497/1 1775/496/1 +f 1777/498/1 1750/472/1 1749/473/1 +f 1749/473/1 1778/499/1 1777/498/1 +f 1779/500/299 1780/500/299 1756/479/27 +f 1756/479/27 1755/479/27 1779/500/299 +f 1781/501/300 1782/501/300 1764/483/26 +f 1764/483/26 1763/483/26 1781/501/300 +f 1779/502/1 1755/492/1 1770/489/1 +f 1770/489/1 1783/503/1 1779/502/1 +f 1775/496/1 1776/497/1 1768/488/1 +f 1768/488/1 1767/486/1 1775/496/1 +f 1771/504/10 1784/505/10 1748/505/10 +f 1748/505/10 1747/504/10 1771/504/10 +f 1770/506/304 1771/504/304 1747/504/304 +f 1747/504/304 1750/506/304 1770/506/304 +f 1783/507/303 1770/506/303 1750/506/303 +f 1750/506/303 1777/507/303 1783/507/303 +f 1785/508/4 1783/507/4 1777/507/4 +f 1777/507/4 1778/508/4 1785/508/4 +f 1786/509/309 1785/512/309 1778/511/309 +f 1778/511/309 1749/510/309 1786/509/309 +f 1784/513/310 1786/509/310 1749/510/310 +f 1749/510/310 1748/514/310 1784/513/310 +f 1787/515/1 1779/502/1 1783/503/1 +f 1783/503/1 1785/516/1 1787/515/1 +f 1779/500/10 1787/517/10 1788/517/10 +f 1788/517/10 1780/500/10 1779/500/10 +f 1758/480/4 1757/480/4 1789/518/4 +f 1789/518/4 1790/518/4 1758/480/4 +f 1790/519/1 1784/474/1 1771/490/1 +f 1771/490/1 1758/491/1 1790/519/1 +f 1751/475/4 1754/476/4 1791/482/4 +f 1791/482/4 1792/481/4 1751/475/4 +f 1784/513/311 1790/520/311 1769/485/311 +f 1769/485/311 1768/513/311 1784/513/311 +f 1786/509/310 1784/513/310 1768/513/310 +f 1768/513/310 1776/509/310 1786/509/310 +f 1785/512/309 1786/509/309 1776/509/309 +f 1776/509/309 1773/512/309 1785/512/309 +f 1787/521/312 1785/512/312 1773/512/312 +f 1773/512/312 1772/521/312 1787/521/312 +f 1759/476/10 1762/475/10 1793/478/10 +f 1793/478/10 1794/477/10 1759/476/10 +f 1763/483/302 1766/484/302 1774/523/302 +f 1774/523/302 1775/522/302 1763/483/302 +f 1781/501/300 1763/483/300 1775/522/300 +f 1775/522/300 1767/524/300 1781/501/300 +f 1790/520/27 1789/527/27 1752/526/27 +f 1752/526/27 1751/525/27 1790/520/27 +f 1769/485/27 1790/520/27 1751/525/27 +f 1751/525/27 1792/528/27 1769/485/27 +f 1767/486/1 1769/487/1 1792/487/1 +f 1792/487/1 1791/486/1 1767/486/1 +f 1781/501/26 1767/524/26 1791/524/26 +f 1791/524/26 1754/501/26 1781/501/26 +f 1782/501/26 1781/501/26 1754/501/26 +f 1754/501/26 1753/501/26 1782/501/26 +f 1766/484/26 1765/485/26 1760/485/26 +f 1760/485/26 1759/484/26 1766/484/26 +f 1774/523/26 1766/484/26 1759/484/26 +f 1759/484/26 1794/523/26 1774/523/26 +f 1772/493/1 1774/494/1 1794/530/1 +f 1794/530/1 1793/529/1 1772/493/1 +f 1787/521/27 1772/521/27 1793/532/27 +f 1793/532/27 1762/531/27 1787/521/27 +f 1788/533/27 1787/521/27 1762/531/27 +f 1762/531/27 1761/531/27 1788/533/27 +f 1795/471/10 1796/474/10 1797/473/10 +f 1797/473/10 1798/472/10 1795/471/10 +f 1799/475/1 1800/478/1 1801/477/1 +f 1801/477/1 1802/476/1 1799/475/1 +f 1803/479/27 1804/479/27 1805/480/288 +f 1805/480/288 1806/480/288 1803/479/27 +f 1807/476/7 1808/482/7 1809/481/7 +f 1809/481/7 1810/475/7 1807/476/7 +f 1811/483/26 1812/483/26 1813/485/289 +f 1813/485/289 1814/484/289 1811/483/26 +f 1815/486/10 1816/488/10 1817/487/10 +f 1818/489/10 1803/492/10 1806/491/10 +f 1806/491/10 1819/490/10 1818/489/10 +f 1820/493/10 1821/495/10 1822/494/10 +f 1823/496/10 1822/494/10 1821/495/10 +f 1821/495/10 1824/497/10 1823/496/10 +f 1825/498/10 1798/472/10 1797/473/10 +f 1797/473/10 1826/499/10 1825/498/10 +f 1827/500/290 1828/500/290 1804/479/27 +f 1804/479/27 1803/479/27 1827/500/290 +f 1829/501/291 1830/501/291 1812/483/26 +f 1812/483/26 1811/483/26 1829/501/291 +f 1827/502/10 1803/492/10 1818/489/10 +f 1818/489/10 1831/503/10 1827/502/10 +f 1823/496/10 1824/497/10 1816/488/10 +f 1816/488/10 1815/486/10 1823/496/10 +f 1819/504/7 1832/505/7 1796/505/7 +f 1796/505/7 1795/504/7 1819/504/7 +f 1818/506/292 1819/504/292 1795/504/292 +f 1795/504/292 1798/506/292 1818/506/292 +f 1831/507/293 1818/506/293 1798/506/293 +f 1798/506/293 1825/507/293 1831/507/293 +f 1833/508/1 1831/507/1 1825/507/1 +f 1825/507/1 1826/508/1 1833/508/1 +f 1834/509/210 1833/512/210 1826/511/210 +f 1826/511/210 1797/510/210 1834/509/210 +f 1832/513/294 1834/509/294 1797/510/294 +f 1797/510/294 1796/514/294 1832/513/294 +f 1835/515/10 1827/502/10 1831/503/10 +f 1831/503/10 1833/516/10 1835/515/10 +f 1827/500/7 1835/517/7 1836/517/7 +f 1836/517/7 1828/500/7 1827/500/7 +f 1806/480/1 1805/480/1 1837/518/1 +f 1837/518/1 1838/518/1 1806/480/1 +f 1838/519/10 1832/474/10 1819/490/10 +f 1819/490/10 1806/491/10 1838/519/10 +f 1799/475/1 1802/476/1 1839/482/1 +f 1839/482/1 1840/481/1 1799/475/1 +f 1832/513/313 1838/520/295 1817/485/295 +f 1817/485/295 1816/513/313 1832/513/313 +f 1834/509/294 1832/513/294 1816/513/294 +f 1816/513/294 1824/509/294 1834/509/294 +f 1833/512/210 1834/509/210 1824/509/210 +f 1824/509/210 1821/512/210 1833/512/210 +f 1835/521/296 1833/512/296 1821/512/296 +f 1821/512/296 1820/521/296 1835/521/296 +f 1807/476/7 1810/475/7 1841/478/7 +f 1841/478/7 1842/477/7 1807/476/7 +f 1811/483/289 1814/484/289 1822/523/289 +f 1822/523/289 1823/522/289 1811/483/289 +f 1829/501/291 1811/483/291 1823/522/291 +f 1823/522/291 1815/524/291 1829/501/291 +f 1838/520/27 1837/527/27 1800/526/27 +f 1800/526/27 1799/525/27 1838/520/27 +f 1817/485/27 1838/520/27 1799/525/27 +f 1799/525/27 1840/528/27 1817/485/27 +f 1815/486/10 1817/487/10 1840/487/10 +f 1840/487/10 1839/486/10 1815/486/10 +f 1829/501/26 1815/524/26 1839/524/26 +f 1839/524/26 1802/501/26 1829/501/26 +f 1830/501/26 1829/501/26 1802/501/26 +f 1802/501/26 1801/501/26 1830/501/26 +f 1814/484/26 1813/485/26 1808/485/26 +f 1808/485/26 1807/484/26 1814/484/26 +f 1822/523/26 1814/484/26 1807/484/26 +f 1807/484/26 1842/523/26 1822/523/26 +f 1820/493/10 1822/494/10 1842/530/10 +f 1842/530/10 1841/529/10 1820/493/10 +f 1835/521/27 1820/521/27 1841/532/27 +f 1841/532/27 1810/531/27 1835/521/27 +f 1836/533/27 1835/521/27 1810/531/27 +f 1810/531/27 1809/531/27 1836/533/27 +f 1843/471/10 1844/474/10 1845/473/10 +f 1845/473/10 1846/472/10 1843/471/10 +f 1847/475/1 1848/478/1 1849/477/1 +f 1849/477/1 1850/476/1 1847/475/1 +f 1851/479/27 1852/479/27 1853/480/288 +f 1853/480/288 1854/480/288 1851/479/27 +f 1855/476/7 1856/482/7 1857/481/7 +f 1857/481/7 1858/475/7 1855/476/7 +f 1859/483/26 1860/483/26 1861/485/289 +f 1861/485/289 1862/484/289 1859/483/26 +f 1863/486/10 1864/488/10 1865/487/10 +f 1866/489/10 1851/492/10 1854/491/10 +f 1854/491/10 1867/490/10 1866/489/10 +f 1868/493/10 1869/495/10 1870/494/10 +f 1871/496/10 1870/494/10 1869/495/10 +f 1869/495/10 1872/497/10 1871/496/10 +f 1873/498/10 1846/472/10 1845/473/10 +f 1845/473/10 1874/499/10 1873/498/10 +f 1875/500/290 1876/500/290 1852/479/27 +f 1852/479/27 1851/479/27 1875/500/290 +f 1877/501/291 1878/501/291 1860/483/26 +f 1860/483/26 1859/483/26 1877/501/291 +f 1875/502/10 1851/492/10 1866/489/10 +f 1866/489/10 1879/503/10 1875/502/10 +f 1871/496/10 1872/497/10 1864/488/10 +f 1864/488/10 1863/486/10 1871/496/10 +f 1867/504/7 1880/505/7 1844/505/7 +f 1844/505/7 1843/504/7 1867/504/7 +f 1866/506/292 1867/504/292 1843/504/292 +f 1843/504/292 1846/506/292 1866/506/292 +f 1879/507/293 1866/506/293 1846/506/293 +f 1846/506/293 1873/507/293 1879/507/293 +f 1881/508/1 1879/507/1 1873/507/1 +f 1873/507/1 1874/508/1 1881/508/1 +f 1882/509/210 1881/512/210 1874/511/210 +f 1874/511/210 1845/510/210 1882/509/210 +f 1880/513/294 1882/509/294 1845/510/294 +f 1845/510/294 1844/514/294 1880/513/294 +f 1883/515/10 1875/502/10 1879/503/10 +f 1879/503/10 1881/516/10 1883/515/10 +f 1875/500/7 1883/517/7 1884/517/7 +f 1884/517/7 1876/500/7 1875/500/7 +f 1854/480/1 1853/480/1 1885/518/1 +f 1885/518/1 1886/518/1 1854/480/1 +f 1886/519/10 1880/474/10 1867/490/10 +f 1867/490/10 1854/491/10 1886/519/10 +f 1847/475/1 1850/476/1 1887/482/1 +f 1887/482/1 1888/481/1 1847/475/1 +f 1880/513/295 1886/520/295 1865/485/295 +f 1865/485/295 1864/513/295 1880/513/295 +f 1882/509/294 1880/513/294 1864/513/294 +f 1864/513/294 1872/509/294 1882/509/294 +f 1881/512/210 1882/509/210 1872/509/210 +f 1872/509/210 1869/512/210 1881/512/210 +f 1883/521/296 1881/512/296 1869/512/296 +f 1869/512/296 1868/521/296 1883/521/296 +f 1855/476/7 1858/475/7 1889/478/7 +f 1889/478/7 1890/477/7 1855/476/7 +f 1859/483/289 1862/484/289 1870/523/289 +f 1870/523/289 1871/522/289 1859/483/289 +f 1877/501/291 1859/483/291 1871/522/291 +f 1871/522/291 1863/524/291 1877/501/291 +f 1886/520/27 1885/527/27 1848/526/27 +f 1848/526/27 1847/525/27 1886/520/27 +f 1865/485/27 1886/520/27 1847/525/27 +f 1847/525/27 1888/528/27 1865/485/27 +f 1863/486/10 1865/487/10 1888/487/10 +f 1888/487/10 1887/486/10 1863/486/10 +f 1877/501/26 1863/524/26 1887/524/26 +f 1887/524/26 1850/501/26 1877/501/26 +f 1878/501/26 1877/501/26 1850/501/26 +f 1850/501/26 1849/501/26 1878/501/26 +f 1862/484/26 1861/485/26 1856/485/26 +f 1856/485/26 1855/484/26 1862/484/26 +f 1870/523/26 1862/484/26 1855/484/26 +f 1855/484/26 1890/523/26 1870/523/26 +f 1868/493/10 1870/494/10 1890/530/10 +f 1890/530/10 1889/529/10 1868/493/10 +f 1883/521/27 1868/521/27 1889/532/27 +f 1889/532/27 1858/531/27 1883/521/27 +f 1884/533/27 1883/521/27 1858/531/27 +f 1858/531/27 1857/531/27 1884/533/27 +f 1891/471/10 1892/474/10 1893/473/10 +f 1893/473/10 1894/472/10 1891/471/10 +f 1895/475/1 1896/478/1 1897/477/1 +f 1897/477/1 1898/476/1 1895/475/1 +f 1899/479/27 1900/479/27 1901/480/288 +f 1901/480/288 1902/480/288 1899/479/27 +f 1903/476/7 1904/482/7 1905/481/7 +f 1905/481/7 1906/475/7 1903/476/7 +f 1907/483/26 1908/483/26 1909/485/289 +f 1909/485/289 1910/484/289 1907/483/26 +f 1911/486/10 1912/488/10 1913/487/10 +f 1914/489/10 1899/492/10 1902/491/10 +f 1902/491/10 1915/490/10 1914/489/10 +f 1916/493/10 1917/495/10 1918/494/10 +f 1919/496/10 1918/494/10 1917/495/10 +f 1917/495/10 1920/497/10 1919/496/10 +f 1921/498/10 1894/472/10 1893/473/10 +f 1893/473/10 1922/499/10 1921/498/10 +f 1923/500/290 1924/500/290 1900/479/27 +f 1900/479/27 1899/479/27 1923/500/290 +f 1925/501/291 1926/501/291 1908/483/26 +f 1908/483/26 1907/483/26 1925/501/291 +f 1923/502/10 1899/492/10 1914/489/10 +f 1914/489/10 1927/503/10 1923/502/10 +f 1919/496/10 1920/497/10 1912/488/10 +f 1912/488/10 1911/486/10 1919/496/10 +f 1915/504/7 1928/505/7 1892/505/7 +f 1892/505/7 1891/504/7 1915/504/7 +f 1914/506/292 1915/504/292 1891/504/292 +f 1891/504/292 1894/506/292 1914/506/292 +f 1927/507/293 1914/506/293 1894/506/293 +f 1894/506/293 1921/507/293 1927/507/293 +f 1929/508/1 1927/507/1 1921/507/1 +f 1921/507/1 1922/508/1 1929/508/1 +f 1930/509/210 1929/512/210 1922/511/210 +f 1922/511/210 1893/510/210 1930/509/210 +f 1928/513/294 1930/509/294 1893/510/294 +f 1893/510/294 1892/514/294 1928/513/294 +f 1931/515/10 1923/502/10 1927/503/10 +f 1927/503/10 1929/516/10 1931/515/10 +f 1923/500/7 1931/517/7 1932/517/7 +f 1932/517/7 1924/500/7 1923/500/7 +f 1902/480/1 1901/480/1 1933/518/1 +f 1933/518/1 1934/518/1 1902/480/1 +f 1934/519/10 1928/474/10 1915/490/10 +f 1915/490/10 1902/491/10 1934/519/10 +f 1895/475/1 1898/476/1 1935/482/1 +f 1935/482/1 1936/481/1 1895/475/1 +f 1928/513/295 1934/520/295 1913/485/295 +f 1913/485/295 1912/513/295 1928/513/295 +f 1930/509/294 1928/513/294 1912/513/294 +f 1912/513/294 1920/509/294 1930/509/294 +f 1929/512/210 1930/509/210 1920/509/210 +f 1920/509/210 1917/512/210 1929/512/210 +f 1931/521/296 1929/512/296 1917/512/296 +f 1917/512/296 1916/521/296 1931/521/296 +f 1903/476/7 1906/475/7 1937/478/7 +f 1937/478/7 1938/477/7 1903/476/7 +f 1907/483/289 1910/484/289 1918/523/289 +f 1918/523/289 1919/522/289 1907/483/289 +f 1925/501/291 1907/483/291 1919/522/291 +f 1919/522/291 1911/524/291 1925/501/291 +f 1934/520/27 1933/527/27 1896/526/27 +f 1896/526/27 1895/525/27 1934/520/27 +f 1913/485/27 1934/520/27 1895/525/27 +f 1895/525/27 1936/528/27 1913/485/27 +f 1911/486/10 1913/487/10 1936/487/10 +f 1936/487/10 1935/486/10 1911/486/10 +f 1925/501/26 1911/524/26 1935/524/26 +f 1935/524/26 1898/501/26 1925/501/26 +f 1926/501/26 1925/501/26 1898/501/26 +f 1898/501/26 1897/501/26 1926/501/26 +f 1910/484/26 1909/485/26 1904/485/26 +f 1904/485/26 1903/484/26 1910/484/26 +f 1918/523/26 1910/484/26 1903/484/26 +f 1903/484/26 1938/523/26 1918/523/26 +f 1916/493/10 1918/494/10 1938/530/10 +f 1938/530/10 1937/529/10 1916/493/10 +f 1931/521/27 1916/521/27 1937/532/27 +f 1937/532/27 1906/531/27 1931/521/27 +f 1932/533/27 1931/521/27 1906/531/27 +f 1906/531/27 1905/531/27 1932/533/27 +f 1939/471/10 1940/474/10 1941/473/10 +f 1941/473/10 1942/472/10 1939/471/10 +f 1943/475/1 1944/478/1 1945/477/1 +f 1945/477/1 1946/476/1 1943/475/1 +f 1947/479/27 1948/479/27 1949/480/288 +f 1949/480/288 1950/480/288 1947/479/27 +f 1951/476/7 1952/482/7 1953/481/7 +f 1953/481/7 1954/475/7 1951/476/7 +f 1955/483/26 1956/483/26 1957/485/289 +f 1957/485/289 1958/484/289 1955/483/26 +f 1959/486/10 1960/488/10 1961/487/10 +f 1962/489/10 1947/492/10 1950/491/10 +f 1950/491/10 1963/490/10 1962/489/10 +f 1964/493/10 1965/495/10 1966/494/10 +f 1967/496/10 1966/494/10 1965/495/10 +f 1965/495/10 1968/497/10 1967/496/10 +f 1969/498/10 1942/472/10 1941/473/10 +f 1941/473/10 1970/499/10 1969/498/10 +f 1971/500/290 1972/500/290 1948/479/27 +f 1948/479/27 1947/479/27 1971/500/290 +f 1973/501/291 1974/501/291 1956/483/26 +f 1956/483/26 1955/483/26 1973/501/291 +f 1971/502/10 1947/492/10 1962/489/10 +f 1962/489/10 1975/503/10 1971/502/10 +f 1967/496/10 1968/497/10 1960/488/10 +f 1960/488/10 1959/486/10 1967/496/10 +f 1963/504/7 1976/505/7 1940/505/7 +f 1940/505/7 1939/504/7 1963/504/7 +f 1962/506/292 1963/504/292 1939/504/292 +f 1939/504/292 1942/506/292 1962/506/292 +f 1975/507/293 1962/506/293 1942/506/293 +f 1942/506/293 1969/507/293 1975/507/293 +f 1977/508/1 1975/507/1 1969/507/1 +f 1969/507/1 1970/508/1 1977/508/1 +f 1978/509/210 1977/512/210 1970/511/210 +f 1970/511/210 1941/510/210 1978/509/210 +f 1976/513/294 1978/509/294 1941/510/294 +f 1941/510/294 1940/514/294 1976/513/294 +f 1979/515/10 1971/502/10 1975/503/10 +f 1975/503/10 1977/516/10 1979/515/10 +f 1971/500/7 1979/517/7 1980/517/7 +f 1980/517/7 1972/500/7 1971/500/7 +f 1950/480/1 1949/480/1 1981/518/1 +f 1981/518/1 1982/518/1 1950/480/1 +f 1982/519/10 1976/474/10 1963/490/10 +f 1963/490/10 1950/491/10 1982/519/10 +f 1943/475/1 1946/476/1 1983/482/1 +f 1983/482/1 1984/481/1 1943/475/1 +f 1976/513/295 1982/520/295 1961/485/295 +f 1961/485/295 1960/513/295 1976/513/295 +f 1978/509/294 1976/513/294 1960/513/294 +f 1960/513/294 1968/509/294 1978/509/294 +f 1977/512/210 1978/509/210 1968/509/210 +f 1968/509/210 1965/512/210 1977/512/210 +f 1979/521/296 1977/512/296 1965/512/296 +f 1965/512/296 1964/521/296 1979/521/296 +f 1951/476/7 1954/475/7 1985/478/7 +f 1985/478/7 1986/477/7 1951/476/7 +f 1955/483/289 1958/484/289 1966/523/289 +f 1966/523/289 1967/522/289 1955/483/289 +f 1973/501/291 1955/483/291 1967/522/291 +f 1967/522/291 1959/524/291 1973/501/291 +f 1982/520/27 1981/527/27 1944/526/27 +f 1944/526/27 1943/525/27 1982/520/27 +f 1961/485/27 1982/520/27 1943/525/27 +f 1943/525/27 1984/528/27 1961/485/27 +f 1959/486/10 1961/487/10 1984/487/10 +f 1984/487/10 1983/486/10 1959/486/10 +f 1973/501/26 1959/524/26 1983/524/26 +f 1983/524/26 1946/501/26 1973/501/26 +f 1974/501/26 1973/501/26 1946/501/26 +f 1946/501/26 1945/501/26 1974/501/26 +f 1958/484/26 1957/485/26 1952/485/26 +f 1952/485/26 1951/484/26 1958/484/26 +f 1966/523/26 1958/484/26 1951/484/26 +f 1951/484/26 1986/523/26 1966/523/26 +f 1964/493/10 1966/494/10 1986/530/10 +f 1986/530/10 1985/529/10 1964/493/10 +f 1979/521/27 1964/521/27 1985/532/27 +f 1985/532/27 1954/531/27 1979/521/27 +f 1980/533/27 1979/521/27 1954/531/27 +f 1954/531/27 1953/531/27 1980/533/27 +f 1987/471/10 1988/472/10 1989/473/10 +f 1989/473/10 1990/474/10 1987/471/10 +f 1991/475/7 1992/476/7 1993/477/7 +f 1993/477/7 1994/478/7 1991/475/7 +f 1995/479/27 1996/480/290 1997/480/290 +f 1997/480/290 1998/479/27 1995/479/27 +f 1999/476/1 2000/475/1 2001/481/1 +f 2001/481/1 2002/482/1 1999/476/1 +f 2003/483/26 2004/484/291 2005/485/291 +f 2005/485/291 2006/483/26 2003/483/26 +f 2007/486/10 2008/487/10 2009/488/10 +f 2010/489/10 2011/490/10 1996/491/10 +f 1996/491/10 1995/492/10 2010/489/10 +f 2012/493/10 2013/494/10 2014/495/10 +f 2015/496/10 2016/497/10 2014/495/10 +f 2014/495/10 2013/494/10 2015/496/10 +f 2017/498/10 2018/499/10 1989/473/10 +f 1989/473/10 1988/472/10 2017/498/10 +f 2019/500/288 1995/479/27 1998/479/27 +f 1998/479/27 2020/500/288 2019/500/288 +f 2021/501/289 2003/483/26 2006/483/26 +f 2006/483/26 2022/501/289 2021/501/289 +f 2019/502/10 2023/503/10 2010/489/10 +f 2010/489/10 1995/492/10 2019/502/10 +f 2015/496/10 2007/486/10 2009/488/10 +f 2009/488/10 2016/497/10 2015/496/10 +f 2011/504/1 1987/504/1 1990/505/1 +f 1990/505/1 2024/505/1 2011/504/1 +f 2010/506/293 1988/506/293 1987/504/293 +f 1987/504/293 2011/504/293 2010/506/293 +f 2023/507/292 2017/507/292 1988/506/292 +f 1988/506/292 2010/506/292 2023/507/292 +f 2025/508/7 2018/508/7 2017/507/7 +f 2017/507/7 2023/507/7 2025/508/7 +f 2026/509/203 1989/510/203 2018/511/203 +f 2018/511/203 2025/512/203 2026/509/203 +f 2024/513/296 1990/514/296 1989/510/296 +f 1989/510/296 2026/509/296 2024/513/296 +f 2027/515/10 2025/516/10 2023/503/10 +f 2023/503/10 2019/502/10 2027/515/10 +f 2019/500/1 2020/500/1 2028/517/1 +f 2028/517/1 2027/517/1 2019/500/1 +f 1996/480/7 2029/518/7 2030/518/7 +f 2030/518/7 1997/480/7 1996/480/7 +f 2029/519/10 1996/491/10 2011/490/10 +f 2011/490/10 2024/474/10 2029/519/10 +f 1991/475/7 2031/481/7 2032/482/7 +f 2032/482/7 1992/476/7 1991/475/7 +f 2024/513/314 2009/513/314 2008/485/314 +f 2008/485/314 2029/520/314 2024/513/314 +f 2026/509/296 2016/509/296 2009/513/296 +f 2009/513/296 2024/513/296 2026/509/296 +f 2025/512/203 2014/512/203 2016/509/203 +f 2016/509/203 2026/509/203 2025/512/203 +f 2027/521/294 2012/521/294 2014/512/294 +f 2014/512/294 2025/512/294 2027/521/294 +f 1999/476/1 2033/477/1 2034/478/1 +f 2034/478/1 2000/475/1 1999/476/1 +f 2003/483/291 2015/522/291 2013/523/291 +f 2013/523/291 2004/484/291 2003/483/291 +f 2021/501/289 2007/524/289 2015/522/289 +f 2015/522/289 2003/483/289 2021/501/289 +f 2029/520/27 1991/525/27 1994/526/27 +f 1994/526/27 2030/527/27 2029/520/27 +f 2008/485/27 2031/528/27 1991/525/27 +f 1991/525/27 2029/520/27 2008/485/27 +f 2007/486/10 2032/486/10 2031/487/10 +f 2031/487/10 2008/487/10 2007/486/10 +f 2021/501/26 1992/501/26 2032/524/26 +f 2032/524/26 2007/524/26 2021/501/26 +f 2022/501/26 1993/501/26 1992/501/26 +f 1992/501/26 2021/501/26 2022/501/26 +f 2004/484/26 1999/484/26 2002/485/26 +f 2002/485/26 2005/485/26 2004/484/26 +f 2013/523/26 2033/523/26 1999/484/26 +f 1999/484/26 2004/484/26 2013/523/26 +f 2012/493/10 2034/529/10 2033/530/10 +f 2033/530/10 2013/494/10 2012/493/10 +f 2027/521/27 2000/531/27 2034/532/27 +f 2034/532/27 2012/521/27 2027/521/27 +f 2028/533/27 2001/531/27 2000/531/27 +f 2000/531/27 2027/521/27 2028/533/27 +f 2035/471/10 2036/472/10 2037/473/10 +f 2037/473/10 2038/474/10 2035/471/10 +f 2039/475/7 2040/476/7 2041/477/7 +f 2041/477/7 2042/478/7 2039/475/7 +f 2043/479/27 2044/480/290 2045/480/290 +f 2045/480/290 2046/479/27 2043/479/27 +f 2047/476/1 2048/475/1 2049/481/1 +f 2049/481/1 2050/482/1 2047/476/1 +f 2051/483/26 2052/484/291 2053/485/291 +f 2053/485/291 2054/483/26 2051/483/26 +f 2055/486/10 2056/487/10 2057/488/10 +f 2058/489/10 2059/490/10 2044/491/10 +f 2044/491/10 2043/492/10 2058/489/10 +f 2060/493/10 2061/494/10 2062/495/10 +f 2063/496/10 2064/497/10 2062/495/10 +f 2062/495/10 2061/494/10 2063/496/10 +f 2065/498/10 2066/499/10 2037/473/10 +f 2037/473/10 2036/472/10 2065/498/10 +f 2067/500/288 2043/479/27 2046/479/27 +f 2046/479/27 2068/500/288 2067/500/288 +f 2069/501/289 2051/483/26 2054/483/26 +f 2054/483/26 2070/501/289 2069/501/289 +f 2067/502/10 2071/503/10 2058/489/10 +f 2058/489/10 2043/492/10 2067/502/10 +f 2063/496/10 2055/486/10 2057/488/10 +f 2057/488/10 2064/497/10 2063/496/10 +f 2059/504/1 2035/504/1 2038/505/1 +f 2038/505/1 2072/505/1 2059/504/1 +f 2058/506/293 2036/506/293 2035/504/293 +f 2035/504/293 2059/504/293 2058/506/293 +f 2071/507/292 2065/507/292 2036/506/292 +f 2036/506/292 2058/506/292 2071/507/292 +f 2073/508/7 2066/508/7 2065/507/7 +f 2065/507/7 2071/507/7 2073/508/7 +f 2074/509/203 2037/510/203 2066/511/203 +f 2066/511/203 2073/512/203 2074/509/203 +f 2072/513/296 2038/514/296 2037/510/296 +f 2037/510/296 2074/509/296 2072/513/296 +f 2075/515/10 2073/516/10 2071/503/10 +f 2071/503/10 2067/502/10 2075/515/10 +f 2067/500/1 2068/500/1 2076/517/1 +f 2076/517/1 2075/517/1 2067/500/1 +f 2044/480/7 2077/518/7 2078/518/7 +f 2078/518/7 2045/480/7 2044/480/7 +f 2077/519/10 2044/491/10 2059/490/10 +f 2059/490/10 2072/474/10 2077/519/10 +f 2039/475/7 2079/481/7 2080/482/7 +f 2080/482/7 2040/476/7 2039/475/7 +f 2072/513/314 2057/513/314 2056/485/314 +f 2056/485/314 2077/520/314 2072/513/314 +f 2074/509/296 2064/509/296 2057/513/296 +f 2057/513/296 2072/513/296 2074/509/296 +f 2073/512/203 2062/512/203 2064/509/203 +f 2064/509/203 2074/509/203 2073/512/203 +f 2075/521/294 2060/521/294 2062/512/294 +f 2062/512/294 2073/512/294 2075/521/294 +f 2047/476/1 2081/477/1 2082/478/1 +f 2082/478/1 2048/475/1 2047/476/1 +f 2051/483/291 2063/522/291 2061/523/291 +f 2061/523/291 2052/484/291 2051/483/291 +f 2069/501/289 2055/524/289 2063/522/298 +f 2063/522/298 2051/483/298 2069/501/289 +f 2077/520/27 2039/525/27 2042/526/27 +f 2042/526/27 2078/527/27 2077/520/27 +f 2056/485/27 2079/528/27 2039/525/27 +f 2039/525/27 2077/520/27 2056/485/27 +f 2055/486/10 2080/486/10 2079/487/10 +f 2079/487/10 2056/487/10 2055/486/10 +f 2069/501/26 2040/501/26 2080/524/26 +f 2080/524/26 2055/524/26 2069/501/26 +f 2070/501/26 2041/501/26 2040/501/26 +f 2040/501/26 2069/501/26 2070/501/26 +f 2052/484/26 2047/484/26 2050/485/26 +f 2050/485/26 2053/485/26 2052/484/26 +f 2061/523/26 2081/523/26 2047/484/26 +f 2047/484/26 2052/484/26 2061/523/26 +f 2060/493/10 2082/529/10 2081/530/10 +f 2081/530/10 2061/494/10 2060/493/10 +f 2075/521/27 2048/531/27 2082/532/27 +f 2082/532/27 2060/521/27 2075/521/27 +f 2076/533/27 2049/531/27 2048/531/27 +f 2048/531/27 2075/521/27 2076/533/27 +f 2083/471/7 2084/472/7 2085/473/7 +f 2085/473/7 2086/474/7 2083/471/7 +f 2087/475/4 2088/476/4 2089/477/4 +f 2089/477/4 2090/478/4 2087/475/4 +f 2091/479/27 2092/480/301 2093/480/301 +f 2093/480/301 2094/479/27 2091/479/27 +f 2095/476/10 2096/475/10 2097/481/10 +f 2097/481/10 2098/482/10 2095/476/10 +f 2099/483/26 2100/484/302 2101/485/302 +f 2101/485/302 2102/483/26 2099/483/26 +f 2103/486/7 2104/487/7 2105/488/7 +f 2106/489/7 2107/490/7 2092/491/7 +f 2092/491/7 2091/492/7 2106/489/7 +f 2108/493/7 2109/494/7 2110/495/7 +f 2111/496/7 2112/497/7 2110/495/7 +f 2110/495/7 2109/494/7 2111/496/7 +f 2113/498/7 2114/499/7 2085/473/7 +f 2085/473/7 2084/472/7 2113/498/7 +f 2115/500/299 2091/479/27 2094/479/27 +f 2094/479/27 2116/500/299 2115/500/299 +f 2117/501/300 2099/483/26 2102/483/26 +f 2102/483/26 2118/501/300 2117/501/300 +f 2115/502/7 2119/503/7 2106/489/7 +f 2106/489/7 2091/492/7 2115/502/7 +f 2111/496/7 2103/486/7 2105/488/7 +f 2105/488/7 2112/497/7 2111/496/7 +f 2107/504/10 2083/504/10 2086/505/10 +f 2086/505/10 2120/505/10 2107/504/10 +f 2106/506/304 2084/506/304 2083/504/304 +f 2083/504/304 2107/504/304 2106/506/304 +f 2119/507/303 2113/507/303 2084/506/303 +f 2084/506/303 2106/506/303 2119/507/303 +f 2121/508/4 2114/508/4 2113/507/4 +f 2113/507/4 2119/507/4 2121/508/4 +f 2122/509/309 2085/510/309 2114/511/309 +f 2114/511/309 2121/512/309 2122/509/309 +f 2120/513/310 2086/514/310 2085/510/310 +f 2085/510/310 2122/509/310 2120/513/310 +f 2123/515/7 2121/516/7 2119/503/7 +f 2119/503/7 2115/502/7 2123/515/7 +f 2115/500/10 2116/500/10 2124/517/10 +f 2124/517/10 2123/517/10 2115/500/10 +f 2092/480/4 2125/518/4 2126/518/4 +f 2126/518/4 2093/480/4 2092/480/4 +f 2125/519/7 2092/491/7 2107/490/7 +f 2107/490/7 2120/474/7 2125/519/7 +f 2087/475/4 2127/481/4 2128/482/4 +f 2128/482/4 2088/476/4 2087/475/4 +f 2120/513/311 2105/513/311 2104/485/311 +f 2104/485/311 2125/520/311 2120/513/311 +f 2122/509/310 2112/509/310 2105/513/310 +f 2105/513/310 2120/513/310 2122/509/310 +f 2121/512/309 2110/512/309 2112/509/309 +f 2112/509/309 2122/509/309 2121/512/309 +f 2123/521/312 2108/521/312 2110/512/312 +f 2110/512/312 2121/512/312 2123/521/312 +f 2095/476/10 2129/477/10 2130/478/10 +f 2130/478/10 2096/475/10 2095/476/10 +f 2099/483/302 2111/522/302 2109/523/302 +f 2109/523/302 2100/484/302 2099/483/302 +f 2117/501/300 2103/524/300 2111/522/300 +f 2111/522/300 2099/483/300 2117/501/300 +f 2125/520/27 2087/525/27 2090/526/27 +f 2090/526/27 2126/527/27 2125/520/27 +f 2104/485/27 2127/528/27 2087/525/27 +f 2087/525/27 2125/520/27 2104/485/27 +f 2103/486/7 2128/486/7 2127/487/7 +f 2127/487/7 2104/487/7 2103/486/7 +f 2117/501/26 2088/501/26 2128/524/26 +f 2128/524/26 2103/524/26 2117/501/26 +f 2118/501/26 2089/501/26 2088/501/26 +f 2088/501/26 2117/501/26 2118/501/26 +f 2100/484/26 2095/484/26 2098/485/26 +f 2098/485/26 2101/485/26 2100/484/26 +f 2109/523/26 2129/523/26 2095/484/26 +f 2095/484/26 2100/484/26 2109/523/26 +f 2108/493/7 2130/529/7 2129/530/7 +f 2129/530/7 2109/494/7 2108/493/7 +f 2123/521/27 2096/531/27 2130/532/27 +f 2130/532/27 2108/521/27 2123/521/27 +f 2124/533/27 2097/531/27 2096/531/27 +f 2096/531/27 2123/521/27 2124/533/27 +f 2131/471/7 2132/472/7 2133/473/7 +f 2133/473/7 2134/474/7 2131/471/7 +f 2135/475/4 2136/476/4 2137/477/4 +f 2137/477/4 2138/478/4 2135/475/4 +f 2139/479/27 2140/480/301 2141/480/301 +f 2141/480/301 2142/479/27 2139/479/27 +f 2143/476/10 2144/475/10 2145/481/10 +f 2145/481/10 2146/482/10 2143/476/10 +f 2147/483/26 2148/484/302 2149/485/302 +f 2149/485/302 2150/483/26 2147/483/26 +f 2151/486/7 2152/487/7 2153/488/7 +f 2154/489/7 2155/490/7 2140/491/7 +f 2140/491/7 2139/492/7 2154/489/7 +f 2156/493/7 2157/494/7 2158/495/7 +f 2159/496/7 2160/497/7 2158/495/7 +f 2158/495/7 2157/494/7 2159/496/7 +f 2161/498/7 2162/499/7 2133/473/7 +f 2133/473/7 2132/472/7 2161/498/7 +f 2163/500/299 2139/479/27 2142/479/27 +f 2142/479/27 2164/500/299 2163/500/299 +f 2165/501/300 2147/483/26 2150/483/26 +f 2150/483/26 2166/501/300 2165/501/300 +f 2163/502/7 2167/503/7 2154/489/7 +f 2154/489/7 2139/492/7 2163/502/7 +f 2159/496/7 2151/486/7 2153/488/7 +f 2153/488/7 2160/497/7 2159/496/7 +f 2155/504/10 2131/504/10 2134/505/10 +f 2134/505/10 2168/505/10 2155/504/10 +f 2154/506/304 2132/506/304 2131/504/304 +f 2131/504/304 2155/504/304 2154/506/304 +f 2167/507/303 2161/507/303 2132/506/303 +f 2132/506/303 2154/506/303 2167/507/303 +f 2169/508/4 2162/508/4 2161/507/4 +f 2161/507/4 2167/507/4 2169/508/4 +f 2170/509/309 2133/510/309 2162/511/309 +f 2162/511/309 2169/512/309 2170/509/309 +f 2168/513/310 2134/514/310 2133/510/310 +f 2133/510/310 2170/509/310 2168/513/310 +f 2171/515/7 2169/516/7 2167/503/7 +f 2167/503/7 2163/502/7 2171/515/7 +f 2163/500/10 2164/500/10 2172/517/10 +f 2172/517/10 2171/517/10 2163/500/10 +f 2140/480/4 2173/518/4 2174/518/4 +f 2174/518/4 2141/480/4 2140/480/4 +f 2173/519/7 2140/491/7 2155/490/7 +f 2155/490/7 2168/474/7 2173/519/7 +f 2135/475/4 2175/481/4 2176/482/4 +f 2176/482/4 2136/476/4 2135/475/4 +f 2168/513/311 2153/513/311 2152/485/311 +f 2152/485/311 2173/520/311 2168/513/311 +f 2170/509/310 2160/509/310 2153/513/310 +f 2153/513/310 2168/513/310 2170/509/310 +f 2169/512/309 2158/512/309 2160/509/309 +f 2160/509/309 2170/509/309 2169/512/309 +f 2171/521/312 2156/521/312 2158/512/312 +f 2158/512/312 2169/512/312 2171/521/312 +f 2143/476/10 2177/477/10 2178/478/10 +f 2178/478/10 2144/475/10 2143/476/10 +f 2147/483/302 2159/522/302 2157/523/302 +f 2157/523/302 2148/484/302 2147/483/302 +f 2165/501/300 2151/524/300 2159/522/300 +f 2159/522/300 2147/483/300 2165/501/300 +f 2173/520/27 2135/525/27 2138/526/27 +f 2138/526/27 2174/527/27 2173/520/27 +f 2152/485/27 2175/528/27 2135/525/27 +f 2135/525/27 2173/520/27 2152/485/27 +f 2151/486/7 2176/486/7 2175/487/7 +f 2175/487/7 2152/487/7 2151/486/7 +f 2165/501/26 2136/501/26 2176/524/26 +f 2176/524/26 2151/524/26 2165/501/26 +f 2166/501/26 2137/501/26 2136/501/26 +f 2136/501/26 2165/501/26 2166/501/26 +f 2148/484/26 2143/484/26 2146/485/26 +f 2146/485/26 2149/485/26 2148/484/26 +f 2157/523/26 2177/523/26 2143/484/26 +f 2143/484/26 2148/484/26 2157/523/26 +f 2156/493/7 2178/529/7 2177/530/7 +f 2177/530/7 2157/494/7 2156/493/7 +f 2171/521/27 2144/531/27 2178/532/27 +f 2178/532/27 2156/521/27 2171/521/27 +f 2172/533/27 2145/531/27 2144/531/27 +f 2144/531/27 2171/521/27 2172/533/27 +f 2179/471/7 2180/474/7 2181/473/7 +f 2181/473/7 2182/472/7 2179/471/7 +f 2183/475/10 2184/478/10 2185/477/10 +f 2185/477/10 2186/476/10 2183/475/10 +f 2187/479/27 2188/479/27 2189/480/299 +f 2189/480/299 2190/480/299 2187/479/27 +f 2191/476/4 2192/482/4 2193/481/4 +f 2193/481/4 2194/475/4 2191/476/4 +f 2195/483/26 2196/483/26 2197/485/300 +f 2197/485/300 2198/484/300 2195/483/26 +f 2199/486/7 2200/488/7 2201/487/7 +f 2202/489/7 2187/492/7 2190/491/7 +f 2190/491/7 2203/490/7 2202/489/7 +f 2204/493/7 2205/495/7 2206/494/7 +f 2207/496/7 2206/494/7 2205/495/7 +f 2205/495/7 2208/497/7 2207/496/7 +f 2209/498/7 2182/472/7 2181/473/7 +f 2181/473/7 2210/499/7 2209/498/7 +f 2211/500/301 2212/500/301 2188/479/27 +f 2188/479/27 2187/479/27 2211/500/301 +f 2213/501/302 2214/501/302 2196/483/26 +f 2196/483/26 2195/483/26 2213/501/302 +f 2211/502/7 2187/492/7 2202/489/7 +f 2202/489/7 2215/503/7 2211/502/7 +f 2207/496/7 2208/497/7 2200/488/7 +f 2200/488/7 2199/486/7 2207/496/7 +f 2203/504/4 2216/505/4 2180/505/4 +f 2180/505/4 2179/504/4 2203/504/4 +f 2202/506/303 2203/504/303 2179/504/303 +f 2179/504/303 2182/506/303 2202/506/303 +f 2215/507/304 2202/506/304 2182/506/304 +f 2182/506/304 2209/507/304 2215/507/304 +f 2217/508/10 2215/507/10 2209/507/10 +f 2209/507/10 2210/508/10 2217/508/10 +f 2218/509/305 2217/512/305 2210/511/305 +f 2210/511/305 2181/510/305 2218/509/305 +f 2216/513/306 2218/509/306 2181/510/306 +f 2181/510/306 2180/514/306 2216/513/306 +f 2219/515/7 2211/502/7 2215/503/7 +f 2215/503/7 2217/516/7 2219/515/7 +f 2211/500/4 2219/517/4 2220/517/4 +f 2220/517/4 2212/500/4 2211/500/4 +f 2190/480/10 2189/480/10 2221/518/10 +f 2221/518/10 2222/518/10 2190/480/10 +f 2222/519/7 2216/474/7 2203/490/7 +f 2203/490/7 2190/491/7 2222/519/7 +f 2183/475/10 2186/476/10 2223/482/10 +f 2223/482/10 2224/481/10 2183/475/10 +f 2216/513/307 2222/520/307 2201/485/307 +f 2201/485/307 2200/513/307 2216/513/307 +f 2218/509/306 2216/513/306 2200/513/306 +f 2200/513/306 2208/509/306 2218/509/306 +f 2217/512/305 2218/509/305 2208/509/305 +f 2208/509/305 2205/512/305 2217/512/305 +f 2219/521/308 2217/512/308 2205/512/308 +f 2205/512/308 2204/521/308 2219/521/308 +f 2191/476/4 2194/475/4 2225/478/4 +f 2225/478/4 2226/477/4 2191/476/4 +f 2195/483/300 2198/484/300 2206/523/300 +f 2206/523/300 2207/522/300 2195/483/300 +f 2213/501/302 2195/483/302 2207/522/302 +f 2207/522/302 2199/524/302 2213/501/302 +f 2222/520/27 2221/527/27 2184/526/27 +f 2184/526/27 2183/525/27 2222/520/27 +f 2201/485/27 2222/520/27 2183/525/27 +f 2183/525/27 2224/528/27 2201/485/27 +f 2199/486/7 2201/487/7 2224/487/7 +f 2224/487/7 2223/486/7 2199/486/7 +f 2213/501/26 2199/524/26 2223/524/26 +f 2223/524/26 2186/501/26 2213/501/26 +f 2214/501/26 2213/501/26 2186/501/26 +f 2186/501/26 2185/501/26 2214/501/26 +f 2198/484/26 2197/485/26 2192/485/26 +f 2192/485/26 2191/484/26 2198/484/26 +f 2206/523/26 2198/484/26 2191/484/26 +f 2191/484/26 2226/523/26 2206/523/26 +f 2204/493/7 2206/494/7 2226/530/7 +f 2226/530/7 2225/529/7 2204/493/7 +f 2219/521/27 2204/521/27 2225/532/27 +f 2225/532/27 2194/531/27 2219/521/27 +f 2220/533/27 2219/521/27 2194/531/27 +f 2194/531/27 2193/531/27 2220/533/27 +f 2227/471/10 2228/472/10 2229/473/10 +f 2229/473/10 2230/474/10 2227/471/10 +f 2231/475/7 2232/476/7 2233/477/7 +f 2233/477/7 2234/478/7 2231/475/7 +f 2235/479/27 2236/480/290 2237/480/290 +f 2237/480/290 2238/479/27 2235/479/27 +f 2239/476/1 2240/475/1 2241/481/1 +f 2241/481/1 2242/482/1 2239/476/1 +f 2243/483/26 2244/484/291 2245/485/291 +f 2245/485/291 2246/483/26 2243/483/26 +f 2247/486/10 2248/487/10 2249/488/10 +f 2250/489/10 2251/490/10 2236/491/10 +f 2236/491/10 2235/492/10 2250/489/10 +f 2252/493/10 2253/494/10 2254/495/10 +f 2255/496/10 2256/497/10 2254/495/10 +f 2254/495/10 2253/494/10 2255/496/10 +f 2257/498/10 2258/499/10 2229/473/10 +f 2229/473/10 2228/472/10 2257/498/10 +f 2259/500/288 2235/479/27 2238/479/27 +f 2238/479/27 2260/500/288 2259/500/288 +f 2261/501/289 2243/483/26 2246/483/26 +f 2246/483/26 2262/501/289 2261/501/289 +f 2259/502/10 2263/503/10 2250/489/10 +f 2250/489/10 2235/492/10 2259/502/10 +f 2255/496/10 2247/486/10 2249/488/10 +f 2249/488/10 2256/497/10 2255/496/10 +f 2251/504/1 2227/504/1 2230/505/1 +f 2230/505/1 2264/505/1 2251/504/1 +f 2250/506/293 2228/506/293 2227/504/293 +f 2227/504/293 2251/504/293 2250/506/293 +f 2263/507/292 2257/507/292 2228/506/292 +f 2228/506/292 2250/506/292 2263/507/292 +f 2265/508/7 2258/508/7 2257/507/7 +f 2257/507/7 2263/507/7 2265/508/7 +f 2266/509/203 2229/510/203 2258/511/203 +f 2258/511/203 2265/512/203 2266/509/203 +f 2264/513/296 2230/514/296 2229/510/296 +f 2229/510/296 2266/509/296 2264/513/296 +f 2267/515/10 2265/516/10 2263/503/10 +f 2263/503/10 2259/502/10 2267/515/10 +f 2259/500/1 2260/500/1 2268/517/1 +f 2268/517/1 2267/517/1 2259/500/1 +f 2236/480/7 2269/518/7 2270/518/7 +f 2270/518/7 2237/480/7 2236/480/7 +f 2269/519/10 2236/491/10 2251/490/10 +f 2251/490/10 2264/474/10 2269/519/10 +f 2231/475/7 2271/481/7 2272/482/7 +f 2272/482/7 2232/476/7 2231/475/7 +f 2264/513/314 2249/513/314 2248/485/314 +f 2248/485/314 2269/520/314 2264/513/314 +f 2266/509/296 2256/509/296 2249/513/296 +f 2249/513/296 2264/513/296 2266/509/296 +f 2265/512/203 2254/512/203 2256/509/203 +f 2256/509/203 2266/509/203 2265/512/203 +f 2267/521/294 2252/521/294 2254/512/294 +f 2254/512/294 2265/512/294 2267/521/294 +f 2239/476/1 2273/477/1 2274/478/1 +f 2274/478/1 2240/475/1 2239/476/1 +f 2243/483/297 2255/522/297 2253/523/291 +f 2253/523/291 2244/484/291 2243/483/297 +f 2261/501/289 2247/524/289 2255/522/289 +f 2255/522/289 2243/483/289 2261/501/289 +f 2269/520/27 2231/525/27 2234/526/27 +f 2234/526/27 2270/527/27 2269/520/27 +f 2248/485/27 2271/528/27 2231/525/27 +f 2231/525/27 2269/520/27 2248/485/27 +f 2247/486/10 2272/486/10 2271/487/10 +f 2271/487/10 2248/487/10 2247/486/10 +f 2261/501/26 2232/501/26 2272/524/26 +f 2272/524/26 2247/524/26 2261/501/26 +f 2262/501/26 2233/501/26 2232/501/26 +f 2232/501/26 2261/501/26 2262/501/26 +f 2244/484/26 2239/484/26 2242/485/26 +f 2242/485/26 2245/485/26 2244/484/26 +f 2253/523/26 2273/523/26 2239/484/26 +f 2239/484/26 2244/484/26 2253/523/26 +f 2252/493/10 2274/529/10 2273/530/10 +f 2273/530/10 2253/494/10 2252/493/10 +f 2267/521/27 2240/531/27 2274/532/27 +f 2274/532/27 2252/521/27 2267/521/27 +f 2268/533/27 2241/531/27 2240/531/27 +f 2240/531/27 2267/521/27 2268/533/27 +f 2275/534/4 2276/535/4 2277/536/4 +f 2277/536/4 2278/537/4 2275/534/4 +f 2279/538/4 2280/539/4 2281/540/4 +f 2281/540/4 2282/541/4 2279/538/4 +f 2283/542/4 2284/543/4 2276/535/4 +f 2276/535/4 2275/534/4 2283/542/4 +f 2280/539/4 2278/537/4 2277/536/4 +f 2277/536/4 2281/540/4 2280/539/4 +f 2285/544/315 2286/545/315 2287/546/316 +f 2287/546/316 2288/547/316 2285/544/315 +f 2286/548/4 2289/549/4 2290/550/4 +f 2290/550/4 2287/551/4 2286/548/4 +f 2289/552/317 2291/553/317 2292/554/318 +f 2292/554/318 2290/555/318 2289/552/317 +f 2288/547/316 2287/546/316 2293/556/319 +f 2293/556/319 2294/557/319 2288/547/316 +f 2287/551/4 2290/550/4 2295/558/4 +f 2295/558/4 2293/559/4 2287/551/4 +f 2290/555/318 2292/554/318 2296/560/320 +f 2296/560/320 2295/561/320 2290/555/318 +f 2294/557/319 2293/556/319 2297/562/27 +f 2297/562/27 2298/563/27 2294/557/319 +f 2293/559/4 2295/558/4 2299/564/4 +f 2299/564/4 2297/565/4 2293/559/4 +f 2295/561/320 2296/560/320 2300/566/26 +f 2300/566/26 2299/567/26 2295/561/320 +f 2298/563/27 2297/562/27 2301/556/321 +f 2301/556/321 2302/557/321 2298/563/27 +f 2297/565/4 2299/564/4 2303/568/4 +f 2303/568/4 2301/569/4 2297/565/4 +f 2299/567/26 2300/566/26 2304/560/322 +f 2304/560/322 2303/561/322 2299/567/26 +f 2302/557/321 2301/556/321 2305/546/323 +f 2305/546/323 2306/547/323 2302/557/321 +f 2301/569/4 2303/568/4 2307/570/4 +f 2307/570/4 2305/571/4 2301/569/4 +f 2303/561/322 2304/560/322 2308/554/324 +f 2308/554/324 2307/555/324 2303/561/322 +f 2306/547/323 2305/546/323 2309/545/325 +f 2309/545/325 2310/544/325 2306/547/323 +f 2305/571/4 2307/570/4 2311/572/4 +f 2311/572/4 2309/573/4 2305/571/4 +f 2307/555/324 2308/554/324 2312/553/326 +f 2312/553/326 2311/552/326 2307/555/324 +f 2313/574/327 2314/575/327 2315/576/327 +f 2315/576/327 2316/577/327 2313/574/327 +f 2317/578/328 2313/579/328 2316/580/328 +f 2316/580/328 2318/581/328 2317/578/328 +f 2319/579/329 2317/578/329 2318/581/329 +f 2318/581/329 2320/580/329 2319/579/329 +f 2319/578/330 2320/581/330 2315/580/330 +f 2315/580/330 2314/579/330 2319/578/330 +f 2321/582/331 2316/577/331 2315/576/331 +f 2315/576/331 2322/583/332 2321/582/331 +f 2318/581/333 2316/580/333 2321/584/333 +f 2321/584/333 2323/585/333 2318/581/333 +f 2324/584/334 2320/580/334 2318/581/334 +f 2318/581/334 2323/585/334 2324/584/334 +f 2322/584/335 2315/580/335 2320/581/335 +f 2320/581/335 2324/585/335 2322/584/335 +f 2325/586/336 2326/587/26 2327/588/26 +f 2327/588/26 2328/589/336 2325/586/336 +f 2328/590/1 2327/591/1 2329/592/1 +f 2329/592/1 2330/593/1 2328/590/1 +f 2330/589/337 2329/588/27 2331/587/27 +f 2331/587/27 2332/586/337 2330/589/337 +f 2327/588/26 2326/587/26 2333/594/338 +f 2333/594/338 2334/595/338 2327/588/26 +f 2329/592/1 2327/591/1 2334/596/1 +f 2334/596/1 2335/597/1 2329/592/1 +f 2331/587/27 2329/588/27 2335/595/339 +f 2335/595/339 2336/594/339 2331/587/27 +f 2337/586/340 2338/587/26 2339/588/26 +f 2339/588/26 2340/589/340 2337/586/340 +f 2340/590/4 2339/591/4 2341/592/4 +f 2341/592/4 2342/593/4 2340/590/4 +f 2342/589/341 2341/588/27 2343/587/27 +f 2343/587/27 2344/586/342 2342/589/341 +f 2339/588/26 2338/587/26 2345/594/343 +f 2345/594/343 2346/595/343 2339/588/26 +f 2341/592/4 2339/591/4 2346/596/4 +f 2346/596/4 2347/597/4 2341/592/4 +f 2343/587/27 2341/588/27 2347/595/344 +f 2347/595/344 2348/594/344 2343/587/27 +f 2347/598/1 2346/596/1 2345/599/1 +f 2345/599/1 2348/600/1 2347/598/1 +f 2349/574/345 2350/577/345 2351/576/345 +f 2351/576/345 2352/575/345 2349/574/345 +f 2353/578/346 2354/581/346 2350/580/346 +f 2350/580/346 2349/579/346 2353/578/346 +f 2355/579/347 2356/580/347 2354/581/347 +f 2354/581/347 2353/578/347 2355/579/347 +f 2355/578/348 2352/579/348 2351/580/348 +f 2351/580/348 2356/581/348 2355/578/348 +f 2357/582/175 2358/583/349 2351/576/349 +f 2351/576/349 2350/577/349 2357/582/175 +f 2354/581/350 2359/585/350 2357/584/350 +f 2357/584/350 2350/580/350 2354/581/350 +f 2360/584/351 2359/585/351 2354/581/351 +f 2354/581/351 2356/580/351 2360/584/351 +f 2358/584/352 2360/585/352 2356/581/353 +f 2356/581/353 2351/580/352 2358/584/352 +f 2361/586/340 2362/589/340 2363/588/26 +f 2363/588/26 2364/587/26 2361/586/340 +f 2362/590/10 2365/593/10 2366/592/10 +f 2366/592/10 2363/591/10 2362/590/10 +f 2365/589/341 2367/586/342 2368/587/27 +f 2368/587/27 2366/588/27 2365/589/341 +f 2363/588/26 2369/595/343 2370/594/343 +f 2370/594/343 2364/587/26 2363/588/26 +f 2366/592/10 2371/597/10 2369/596/10 +f 2369/596/10 2363/591/10 2366/592/10 +f 2368/587/27 2372/594/344 2371/595/344 +f 2371/595/344 2366/588/27 2368/587/27 +f 2370/599/1 2369/596/1 2371/598/1 +f 2371/598/1 2372/600/1 2370/599/1 +f 2373/586/354 2374/589/340 2375/588/26 +f 2375/588/26 2376/587/26 2373/586/354 +f 2374/590/10 2377/593/10 2378/592/10 +f 2378/592/10 2375/591/10 2374/590/10 +f 2377/589/342 2379/586/341 2380/587/27 +f 2380/587/27 2378/588/27 2377/589/342 +f 2375/588/26 2381/595/355 2382/594/355 +f 2382/594/355 2376/587/26 2375/588/26 +f 2378/592/10 2383/597/10 2381/596/10 +f 2381/596/10 2375/591/10 2378/592/10 +f 2380/587/27 2384/594/356 2383/595/344 +f 2383/595/344 2378/588/27 2380/587/27 +f 2385/601/7 2386/602/7 2387/603/7 +f 2387/603/7 691/604/7 2385/601/7 +f 2388/605/4 2389/606/4 2390/607/4 +f 2390/607/4 690/608/4 2388/605/4 +f 2391/601/1 2392/602/1 2393/609/1 +f 2393/609/1 692/610/1 2391/601/1 +f 2394/611/10 2395/612/10 2396/613/10 +f 2396/613/10 693/614/10 2394/611/10 +f 690/610/7 2390/609/7 2386/602/7 +f 2386/602/7 2385/601/7 690/610/7 +f 693/604/1 2396/603/1 2392/602/1 +f 2392/602/1 2391/601/1 693/604/1 +f 692/615/4 2393/616/4 2389/606/4 +f 2389/606/4 2388/605/4 692/615/4 +f 691/617/10 2387/618/10 2395/612/10 +f 2395/612/10 2394/611/10 691/617/10 +f 2397/619/357 2398/620/358 2399/621/358 +f 2399/621/358 2400/622/357 2397/619/357 +f 2398/620/358 2401/623/359 2402/624/359 +f 2402/624/359 2399/621/358 2398/620/358 +f 2403/625/360 2404/626/10 2398/627/10 +f 2398/627/10 2397/628/360 2403/625/360 +f 2398/627/10 2404/626/10 2405/629/361 +f 2405/629/361 2401/630/361 2398/627/10 +f 2403/619/315 2406/622/315 2407/621/362 +f 2407/621/362 2404/620/362 2403/619/315 +f 2404/620/362 2407/621/362 2408/624/363 +f 2408/624/363 2405/623/363 2404/620/362 +f 2406/631/364 2400/632/364 2399/633/365 +f 2399/633/365 2407/634/365 2406/631/364 +f 2399/633/365 2402/635/366 2408/636/366 +f 2408/636/366 2407/634/365 2399/633/365 +f 2409/637/7 2410/638/7 2411/639/7 +f 2411/639/7 2412/640/7 2409/637/7 +f 2413/640/4 2412/641/4 2411/642/4 +f 2411/642/4 2414/643/4 2413/640/4 +f 2413/637/1 2414/638/1 2415/639/1 +f 2415/639/1 2416/640/1 2413/637/1 +f 2417/644/1 2418/645/1 2419/646/1 +f 2419/646/1 2420/647/1 2417/644/1 +f 2421/647/7 2422/644/7 2423/645/7 +f 2423/645/7 2424/646/7 2421/647/7 +f 2418/648/367 2417/649/367 2425/650/367 +f 2425/650/367 2426/651/367 2418/648/367 +f 2425/652/4 2417/567/4 2420/653/4 +f 2420/653/4 2427/654/4 2425/652/4 +f 2420/648/368 2419/649/368 2428/650/368 +f 2428/650/368 2427/651/368 2420/648/368 +f 2429/637/7 2430/638/7 2431/639/7 +f 2431/639/7 2432/640/7 2429/637/7 +f 2432/640/4 2431/643/4 2433/642/4 +f 2433/642/4 2434/641/4 2432/640/4 +f 2434/637/1 2433/638/1 2435/639/1 +f 2435/639/1 2436/640/1 2434/637/1 +f 2437/655/369 2423/656/369 2422/657/369 +f 2422/657/369 2438/658/369 2437/655/369 +f 2437/659/4 2439/660/4 2424/661/4 +f 2424/661/4 2423/662/4 2437/659/4 +f 2440/655/370 2421/656/370 2424/657/370 +f 2424/657/370 2439/658/370 2440/655/370 +f 2441/663/298 2442/664/298 2426/651/298 +f 2426/651/298 2425/650/298 2441/663/298 +f 2427/654/4 2443/665/4 2441/666/4 +f 2441/666/4 2425/652/4 2427/654/4 +f 2444/663/371 2443/664/371 2427/651/371 +f 2427/651/371 2428/650/371 2444/663/371 +f 2437/655/297 2438/658/297 2442/664/297 +f 2442/664/297 2441/663/297 2437/655/297 +f 2439/660/4 2437/659/4 2441/666/4 +f 2441/666/4 2443/665/4 2439/660/4 +f 2440/655/372 2439/658/372 2443/664/372 +f 2443/664/372 2444/663/372 2440/655/372 +f 2445/667/373 2446/668/373 2447/669/373 +f 2447/669/373 2448/670/373 2445/667/373 +f 2449/671/374 2450/672/374 2446/668/374 +f 2446/668/374 2445/667/374 2449/671/374 +f 2451/673/7 2452/674/7 2453/675/7 +f 2453/675/7 2454/676/7 2451/673/7 +f 2451/673/7 2450/673/7 2455/673/7 +f 2455/673/7 2452/674/7 2451/673/7 +f 2451/673/7 2447/677/7 2446/677/7 +f 2446/677/7 2450/673/7 2451/673/7 +f 2456/678/7 2447/677/7 2451/673/7 +f 2451/673/7 2454/676/7 2456/678/7 +f 2453/679/27 2452/303/27 2457/680/27 +f 2457/680/27 2458/681/27 2453/679/27 +f 2452/682/375 2455/672/375 2459/671/375 +f 2459/671/375 2457/683/375 2452/682/375 +f 2455/672/376 2450/672/377 2449/671/377 +f 2449/671/377 2459/671/376 2455/672/376 +f 2460/684/373 2461/685/373 2445/667/373 +f 2445/667/373 2448/670/373 2460/684/373 +f 2461/685/374 2462/686/374 2449/671/374 +f 2449/671/374 2445/667/374 2461/685/374 +f 2463/678/1 2464/677/1 2465/673/1 +f 2465/673/1 2466/676/1 2463/678/1 +f 2465/673/1 2464/677/1 2467/677/1 +f 2467/677/1 2462/673/1 2465/673/1 +f 2465/673/1 2462/673/1 2461/673/1 +f 2461/673/1 2460/674/1 2465/673/1 +f 2465/673/1 2460/674/1 2468/675/1 +f 2468/675/1 2466/676/1 2465/673/1 +f 2457/680/27 2464/687/27 2463/688/27 +f 2463/688/27 2458/681/27 2457/680/27 +f 2459/671/375 2467/686/375 2464/678/375 +f 2464/678/375 2457/683/375 2459/671/375 +f 2449/671/377 2462/686/377 2467/686/376 +f 2467/686/376 2459/671/376 2449/671/377 +f 2469/689/4 2470/690/4 2471/691/4 +f 2471/691/4 2472/692/4 2469/689/4 +f 2473/693/4 2472/692/4 2471/691/4 +f 2471/691/4 2474/694/4 2473/693/4 +f 2475/619/357 2476/620/358 2477/621/358 +f 2477/621/358 2478/622/357 2475/619/357 +f 2476/620/358 2479/623/359 2480/624/359 +f 2480/624/359 2477/621/358 2476/620/358 +f 2481/625/360 2482/626/10 2476/627/10 +f 2476/627/10 2475/628/360 2481/625/360 +f 2476/627/10 2482/626/10 2483/629/361 +f 2483/629/361 2479/630/361 2476/627/10 +f 2481/619/315 2484/622/315 2485/621/362 +f 2485/621/362 2482/620/362 2481/619/315 +f 2482/620/362 2485/621/362 2486/624/363 +f 2486/624/363 2483/623/363 2482/620/362 +f 2484/631/364 2478/632/364 2477/633/365 +f 2477/633/365 2485/634/365 2484/631/364 +f 2477/633/365 2480/635/366 2486/636/366 +f 2486/636/366 2485/634/365 2477/633/365 +f 2487/619/357 2488/622/357 2489/621/378 +f 2489/621/378 2490/620/378 2487/619/357 +f 2490/620/378 2489/621/378 2491/624/379 +f 2491/624/379 2492/623/379 2490/620/378 +f 2493/625/365 2487/628/365 2490/627/4 +f 2490/627/4 2494/626/4 2493/625/365 +f 2490/627/4 2492/630/380 2495/629/380 +f 2495/629/380 2494/626/4 2490/627/4 +f 2493/619/315 2494/620/381 2496/621/381 +f 2496/621/381 2497/622/315 2493/619/315 +f 2494/620/381 2495/623/382 2498/624/382 +f 2498/624/382 2496/621/381 2494/620/381 +f 2497/631/383 2496/634/360 2489/633/360 +f 2489/633/360 2488/632/383 2497/631/383 +f 2489/633/360 2496/634/360 2498/636/384 +f 2498/636/384 2491/635/384 2489/633/360 +f 2499/619/357 2500/622/357 2501/621/378 +f 2501/621/378 2502/620/378 2499/619/357 +f 2502/620/378 2501/621/378 2503/624/379 +f 2503/624/379 2504/623/379 2502/620/378 +f 2505/625/365 2499/628/365 2502/627/4 +f 2502/627/4 2506/626/4 2505/625/365 +f 2502/627/4 2504/630/380 2507/629/380 +f 2507/629/380 2506/626/4 2502/627/4 +f 2505/619/315 2506/620/381 2508/621/381 +f 2508/621/381 2509/622/315 2505/619/315 +f 2506/620/381 2507/623/382 2510/624/382 +f 2510/624/382 2508/621/381 2506/620/381 +f 2509/631/383 2508/634/360 2501/633/360 +f 2501/633/360 2500/632/383 2509/631/383 +f 2501/633/360 2508/634/360 2510/636/384 +f 2510/636/384 2503/635/384 2501/633/360 +f 2511/586/336 2512/589/336 2513/588/26 +f 2513/588/26 2514/587/26 2511/586/336 +f 2512/590/7 2515/593/7 2516/592/7 +f 2516/592/7 2513/591/7 2512/590/7 +f 2515/589/337 2517/586/337 2518/587/27 +f 2518/587/27 2516/588/27 2515/589/337 +f 2513/588/26 2519/595/338 2520/594/338 +f 2520/594/338 2514/587/26 2513/588/26 +f 2516/592/7 2521/597/7 2519/596/7 +f 2519/596/7 2513/591/7 2516/592/7 +f 2518/587/27 2522/594/339 2521/595/339 +f 2521/595/339 2516/588/27 2518/587/27 +f 2523/451/27 2524/452/27 2525/453/27 +f 2525/453/27 2526/454/27 2523/451/27 +f 2527/455/4 2528/456/4 2524/457/4 +f 2524/457/4 2523/458/4 2527/455/4 +f 2528/459/1 2529/460/1 2525/461/1 +f 2525/461/1 2524/462/1 2528/459/1 +f 2529/456/10 2530/455/10 2526/458/10 +f 2526/458/10 2525/457/10 2529/456/10 +f 2530/460/7 2527/459/7 2523/462/7 +f 2523/462/7 2526/461/7 2530/460/7 +f 2531/451/27 2532/452/27 2533/453/27 +f 2533/453/27 2534/454/27 2531/451/27 +f 2535/455/7 2536/456/7 2532/457/7 +f 2532/457/7 2531/458/7 2535/455/7 +f 2536/459/4 2537/460/4 2533/461/4 +f 2533/461/4 2532/462/4 2536/459/4 +f 2537/456/1 2538/455/1 2534/458/1 +f 2534/458/1 2533/457/1 2537/456/1 +f 2538/460/10 2535/459/10 2531/462/10 +f 2531/462/10 2534/461/10 2538/460/10 +f 2539/451/27 2540/452/27 2541/453/27 +f 2541/453/27 2542/454/27 2539/451/27 +f 2543/455/7 2544/456/7 2540/457/7 +f 2540/457/7 2539/458/7 2543/455/7 +f 2544/459/4 2545/460/4 2541/461/4 +f 2541/461/4 2540/462/4 2544/459/4 +f 2545/456/1 2546/455/1 2542/458/1 +f 2542/458/1 2541/457/1 2545/456/1 +f 2546/460/10 2543/459/10 2539/462/10 +f 2539/462/10 2542/461/10 2546/460/10 +f 2547/3/12 2548/2/12 2549/1/1 +f 2549/1/1 2550/4/1 2547/3/12 +f 2551/6/11 2552/5/11 2548/2/12 +f 2548/2/12 2547/3/12 2551/6/11 +f 2553/8/10 2554/7/10 2552/5/11 +f 2552/5/11 2551/6/11 2553/8/10 +f 2555/11/9 2556/10/9 2554/9/10 +f 2554/9/10 2553/12/10 2555/11/9 +f 2557/14/8 2558/13/8 2556/10/9 +f 2556/10/9 2555/11/9 2557/14/8 +f 2559/16/7 2560/15/7 2558/13/8 +f 2558/13/8 2557/14/8 2559/16/7 +f 2561/18/6 2562/17/6 2560/15/7 +f 2560/15/7 2559/16/7 2561/18/6 +f 2563/20/5 2564/19/5 2562/17/6 +f 2562/17/6 2561/18/6 2563/20/5 +f 2565/22/4 2566/21/4 2564/19/5 +f 2564/19/5 2563/20/5 2565/22/4 +f 2567/24/3 2568/23/3 2566/21/4 +f 2566/21/4 2565/22/4 2567/24/3 +f 2569/26/2 2570/25/2 2568/23/3 +f 2568/23/3 2567/24/3 2569/26/2 +f 2550/4/1 2549/1/1 2570/25/2 +f 2570/25/2 2569/26/2 2550/4/1 +f 2571/27/24 2572/30/24 2573/29/24 +f 2573/29/24 2574/28/24 2571/27/24 +f 2575/31/23 2576/32/23 2572/30/23 +f 2572/30/23 2571/27/23 2575/31/23 +f 2577/33/22 2578/34/22 2576/32/22 +f 2576/32/22 2575/31/22 2577/33/22 +f 2579/35/21 2580/38/21 2578/37/21 +f 2578/37/21 2577/36/21 2579/35/21 +f 2581/39/20 2582/40/20 2580/38/20 +f 2580/38/20 2579/35/20 2581/39/20 +f 2583/41/19 2584/42/19 2582/40/19 +f 2582/40/19 2581/39/19 2583/41/19 +f 2585/43/18 2586/44/18 2584/42/18 +f 2584/42/18 2583/41/18 2585/43/18 +f 2587/45/17 2588/46/17 2586/44/17 +f 2586/44/17 2585/43/17 2587/45/17 +f 2589/47/16 2590/48/16 2588/46/16 +f 2588/46/16 2587/45/16 2589/47/16 +f 2591/49/15 2592/50/15 2590/48/15 +f 2590/48/15 2589/47/15 2591/49/15 +f 2593/51/14 2594/52/14 2592/50/14 +f 2592/50/14 2591/49/14 2593/51/14 +f 2574/28/13 2573/29/13 2594/52/192 +f 2594/52/192 2593/51/192 2574/28/13 +f 2548/53/26 2571/53/26 2574/54/26 +f 2574/54/26 2549/54/26 2548/53/26 +f 2549/54/26 2574/54/26 2593/55/26 +f 2593/55/26 2570/55/26 2549/54/26 +f 2570/55/26 2593/55/26 2591/56/26 +f 2591/56/26 2568/56/26 2570/55/26 +f 2568/56/26 2591/56/26 2589/57/26 +f 2589/57/26 2566/57/26 2568/56/26 +f 2566/57/26 2589/57/26 2587/59/26 +f 2587/59/26 2564/58/26 2566/57/26 +f 2564/58/26 2587/59/26 2585/61/26 +f 2585/61/26 2562/60/26 2564/58/26 +f 2562/60/26 2585/61/26 2583/62/26 +f 2583/62/26 2560/62/26 2562/60/26 +f 2560/62/26 2583/62/26 2581/64/26 +f 2581/64/26 2558/63/26 2560/62/26 +f 2558/63/26 2581/64/26 2579/66/26 +f 2579/66/26 2556/65/26 2558/63/26 +f 2556/65/26 2579/66/26 2577/67/26 +f 2577/67/26 2554/67/26 2556/65/26 +f 2554/67/26 2577/67/26 2575/68/26 +f 2575/68/26 2552/68/26 2554/67/26 +f 2552/68/26 2575/68/26 2571/53/26 +f 2571/53/26 2548/53/26 2552/68/26 +f 2595/54/27 2573/54/27 2572/53/27 +f 2572/53/27 2596/53/27 2595/54/27 +f 2596/53/27 2572/53/27 2576/68/27 +f 2576/68/27 2597/68/27 2596/53/27 +f 2597/68/27 2576/68/27 2578/67/27 +f 2578/67/27 2598/67/27 2597/68/27 +f 2598/67/27 2578/67/27 2580/66/27 +f 2580/66/27 2599/65/27 2598/67/27 +f 2599/65/27 2580/66/27 2582/64/27 +f 2582/64/27 2600/63/27 2599/65/27 +f 2600/63/27 2582/64/27 2584/62/27 +f 2584/62/27 2601/62/27 2600/63/27 +f 2601/62/27 2584/62/27 2586/61/27 +f 2586/61/27 2602/60/27 2601/62/27 +f 2602/60/27 2586/61/27 2588/59/27 +f 2588/59/27 2603/58/27 2602/60/27 +f 2603/58/27 2588/59/27 2590/57/27 +f 2590/57/27 2604/57/27 2603/58/27 +f 2604/57/27 2590/57/27 2592/56/27 +f 2592/56/27 2605/56/27 2604/57/27 +f 2605/56/27 2592/56/27 2594/55/27 +f 2594/55/27 2606/55/27 2605/56/27 +f 2606/55/27 2594/55/27 2573/54/27 +f 2573/54/27 2595/54/27 2606/55/27 +f 2607/71/12 2608/70/1 2595/69/1 +f 2595/69/1 2596/72/12 2607/71/12 +f 2609/73/23 2607/71/12 2596/72/12 +f 2596/72/12 2597/74/23 2609/73/23 +f 2610/75/22 2609/73/22 2597/74/22 +f 2597/74/22 2598/76/22 2610/75/22 +f 2611/77/9 2610/75/21 2598/76/21 +f 2598/76/21 2599/78/9 2611/77/9 +f 2612/79/8 2611/77/9 2599/78/9 +f 2599/78/9 2600/80/8 2612/79/8 +f 2613/83/7 2612/82/8 2600/81/8 +f 2600/81/8 2601/84/7 2613/83/7 +f 2614/85/6 2613/83/7 2601/84/7 +f 2601/84/7 2602/86/6 2614/85/6 +f 2615/87/5 2614/85/6 2602/86/6 +f 2602/86/6 2603/88/5 2615/87/5 +f 2616/89/4 2615/87/5 2603/88/5 +f 2603/88/5 2604/90/4 2616/89/4 +f 2617/91/3 2616/89/4 2604/90/4 +f 2604/90/4 2605/92/3 2617/91/3 +f 2618/93/2 2617/91/3 2605/92/3 +f 2605/92/3 2606/94/2 2618/93/2 +f 2608/70/1 2618/93/2 2606/94/2 +f 2606/94/2 2595/69/1 2608/70/1 +f 2619/95/26 2620/95/26 2621/96/26 +f 2621/96/26 2622/96/26 2619/95/26 +f 2623/97/26 2624/97/26 2620/95/26 +f 2620/95/26 2619/95/26 2623/97/26 +f 2625/67/26 2626/98/26 2624/97/26 +f 2624/97/26 2623/97/26 2625/67/26 +f 2627/99/26 2628/99/26 2626/98/26 +f 2626/98/26 2625/67/26 2627/99/26 +f 2629/100/26 2630/100/26 2628/99/26 +f 2628/99/26 2627/99/26 2629/100/26 +f 2631/101/26 2632/101/26 2630/100/26 +f 2630/100/26 2629/100/26 2631/101/26 +f 2633/61/26 2634/61/26 2632/101/26 +f 2632/101/26 2631/101/26 2633/61/26 +f 2635/59/26 2636/102/26 2634/61/26 +f 2634/61/26 2633/61/26 2635/59/26 +f 2637/103/26 2638/103/26 2636/102/26 +f 2636/102/26 2635/59/26 2637/103/26 +f 2639/104/26 2640/105/26 2638/103/26 +f 2638/103/26 2637/103/26 2639/104/26 +f 2641/106/26 2642/106/26 2640/105/26 +f 2640/105/26 2639/104/26 2641/106/26 +f 2622/96/26 2621/96/26 2642/106/26 +f 2642/106/26 2641/106/26 2622/96/26 +f 2620/107/39 2643/110/39 2644/109/39 +f 2644/109/39 2621/108/39 2620/107/39 +f 2624/111/38 2645/112/38 2643/110/38 +f 2643/110/38 2620/107/38 2624/111/38 +f 2626/113/37 2646/114/37 2645/112/37 +f 2645/112/37 2624/111/37 2626/113/37 +f 2628/115/36 2647/116/36 2646/114/36 +f 2646/114/36 2626/113/36 2628/115/36 +f 2630/117/35 2648/118/35 2647/116/35 +f 2647/116/35 2628/115/35 2630/117/35 +f 2632/119/34 2649/120/34 2648/118/34 +f 2648/118/34 2630/117/34 2632/119/34 +f 2634/121/33 2650/122/33 2649/120/33 +f 2649/120/33 2632/119/33 2634/121/33 +f 2636/123/32 2651/124/32 2650/122/32 +f 2650/122/32 2634/121/32 2636/123/32 +f 2638/125/31 2652/126/31 2651/124/31 +f 2651/124/31 2636/123/31 2638/125/31 +f 2640/127/30 2653/130/30 2652/129/30 +f 2652/129/30 2638/128/30 2640/127/30 +f 2642/131/29 2654/132/29 2653/130/29 +f 2653/130/29 2640/127/29 2642/131/29 +f 2621/108/28 2644/109/28 2654/132/28 +f 2654/132/28 2642/131/28 2621/108/28 +f 2643/110/54 2655/134/54 2656/133/54 +f 2656/133/54 2644/109/54 2643/110/54 +f 2645/112/53 2657/135/53 2655/134/53 +f 2655/134/53 2643/110/53 2645/112/53 +f 2646/114/51 2658/136/52 2657/135/51 +f 2657/135/51 2645/112/51 2646/114/51 +f 2647/116/50 2659/137/50 2658/136/50 +f 2658/136/50 2646/114/50 2647/116/50 +f 2648/118/49 2660/138/49 2659/137/49 +f 2659/137/49 2647/116/49 2648/118/49 +f 2649/120/48 2661/139/48 2660/138/48 +f 2660/138/48 2648/118/48 2649/120/48 +f 2650/122/385 2662/140/46 2661/139/46 +f 2661/139/46 2649/120/46 2650/122/385 +f 2651/124/45 2663/141/45 2662/140/45 +f 2662/140/45 2650/122/45 2651/124/45 +f 2652/126/44 2664/142/44 2663/141/44 +f 2663/141/44 2651/124/44 2652/126/44 +f 2653/130/42 2665/144/42 2664/143/43 +f 2664/143/43 2652/129/42 2653/130/42 +f 2654/132/41 2666/145/41 2665/144/41 +f 2665/144/41 2653/130/41 2654/132/41 +f 2644/109/40 2656/133/40 2666/145/40 +f 2666/145/40 2654/132/386 2644/109/40 +f 2607/148/71 2667/147/71 2668/146/71 +f 2668/146/71 2608/149/71 2607/148/71 +f 2609/151/69 2669/150/70 2667/147/70 +f 2667/147/70 2607/148/69 2609/151/69 +f 2610/154/68 2670/153/68 2669/152/68 +f 2669/152/68 2609/155/68 2610/154/68 +f 2611/156/67 2671/142/67 2670/153/67 +f 2670/153/67 2610/154/67 2611/156/67 +f 2612/158/65 2672/157/66 2671/142/66 +f 2671/142/66 2611/156/65 2612/158/65 +f 2613/160/64 2673/159/64 2672/157/64 +f 2672/157/64 2612/158/64 2613/160/64 +f 2614/162/63 2674/161/63 2673/159/63 +f 2673/159/63 2613/160/63 2614/162/63 +f 2615/164/62 2675/163/61 2674/161/61 +f 2674/161/61 2614/162/62 2615/164/62 +f 2616/166/60 2676/165/60 2675/163/60 +f 2675/163/60 2615/164/60 2616/166/60 +f 2617/168/59 2677/167/59 2676/165/59 +f 2676/165/59 2616/166/59 2617/168/59 +f 2618/170/58 2678/169/57 2677/167/57 +f 2677/167/57 2617/168/57 2618/170/58 +f 2608/149/56 2668/146/56 2678/169/56 +f 2678/169/56 2618/170/56 2608/149/56 +f 2667/173/12 2619/172/12 2622/171/1 +f 2622/171/1 2668/174/1 2667/173/12 +f 2669/176/11 2623/175/11 2619/172/12 +f 2619/172/12 2667/173/12 2669/176/11 +f 2670/179/10 2625/178/10 2623/177/11 +f 2623/177/11 2669/180/11 2670/179/10 +f 2671/181/9 2627/86/9 2625/178/10 +f 2625/178/10 2670/179/10 2671/181/9 +f 2672/183/8 2629/182/8 2627/86/9 +f 2627/86/9 2671/181/9 2672/183/8 +f 2673/185/7 2631/184/7 2629/182/8 +f 2629/182/8 2672/183/8 2673/185/7 +f 2674/187/6 2633/186/6 2631/184/7 +f 2631/184/7 2673/185/7 2674/187/6 +f 2675/189/5 2635/188/5 2633/186/6 +f 2633/186/6 2674/187/6 2675/189/5 +f 2676/191/4 2637/190/4 2635/188/5 +f 2635/188/5 2675/189/5 2676/191/4 +f 2677/192/3 2639/76/3 2637/190/4 +f 2637/190/4 2676/191/4 2677/192/3 +f 2678/194/2 2641/193/2 2639/76/3 +f 2639/76/3 2677/192/3 2678/194/2 +f 2668/174/1 2622/171/1 2641/193/2 +f 2641/193/2 2678/194/2 2668/174/1 +f 2679/195/387 2680/198/387 2681/197/387 +f 2681/197/387 2682/196/387 2679/195/387 +f 2683/199/388 2684/202/388 2685/201/388 +f 2685/201/388 2686/200/388 2683/199/388 +f 2687/203/389 2688/206/389 2689/205/389 +f 2689/205/389 2690/204/389 2687/203/389 +f 2691/202/390 2692/199/390 2693/200/390 +f 2693/200/390 2694/201/390 2691/202/390 +f 2695/207/391 2696/209/391 2697/208/391 +f 2697/208/391 2698/207/391 2695/207/391 +f 2699/209/392 2700/211/392 2701/210/392 +f 2690/212/393 2689/214/393 2702/213/393 +f 2702/213/393 2703/196/393 2690/212/393 +f 2704/210/394 2705/211/394 2706/209/394 +f 2707/215/395 2706/209/395 2705/211/395 +f 2705/211/395 2708/216/395 2707/215/395 +f 2709/217/396 2682/196/396 2681/197/396 +f 2681/197/396 2710/218/396 2709/217/396 +f 2711/219/397 2687/203/397 2690/204/397 +f 2690/204/397 2712/220/397 2711/219/397 +f 2713/209/398 2695/207/398 2698/207/398 +f 2698/207/398 2714/208/398 2713/209/398 +f 2690/212/399 2703/196/399 2715/213/399 +f 2715/213/399 2712/214/399 2690/212/399 +f 2707/215/400 2708/216/400 2700/211/400 +f 2700/211/400 2699/209/400 2707/215/400 +f 2716/221/390 2680/221/390 2679/222/390 +f 2679/222/390 2702/222/390 2716/221/390 +f 2702/222/401 2679/222/401 2682/203/401 +f 2682/203/401 2703/203/401 2702/222/401 +f 2703/203/402 2682/203/402 2709/206/402 +f 2709/206/402 2715/206/402 2703/203/402 +f 2715/206/388 2709/206/388 2710/223/388 +f 2710/223/388 2717/223/388 2715/206/388 +f 2717/224/403 2710/224/403 2681/226/403 +f 2681/226/403 2718/225/403 2717/224/403 +f 2718/225/404 2681/226/404 2680/224/404 +f 2680/224/404 2716/224/404 2718/225/404 +f 2712/214/394 2715/213/394 2717/228/394 +f 2717/228/394 2719/227/394 2712/214/394 +f 2719/229/390 2720/221/390 2711/219/390 +f 2711/219/390 2712/220/390 2719/229/390 +f 2688/206/388 2721/223/388 2722/230/388 +f 2722/230/388 2689/205/388 2688/206/388 +f 2722/227/392 2716/228/392 2702/213/392 +f 2702/213/392 2689/214/392 2722/227/392 +f 2685/201/388 2723/202/388 2724/199/388 +f 2724/199/388 2686/200/388 2685/201/388 +f 2722/231/405 2701/233/406 2700/232/405 +f 2700/232/405 2716/224/405 2722/231/405 +f 2716/224/404 2700/232/404 2708/234/404 +f 2708/234/404 2718/225/404 2716/224/404 +f 2718/225/403 2708/234/403 2705/232/403 +f 2705/232/403 2717/224/403 2718/225/403 +f 2717/224/407 2705/232/407 2704/233/407 +f 2704/233/407 2719/231/407 2717/224/407 +f 2693/200/390 2725/199/390 2726/202/390 +f 2726/202/390 2694/201/390 2693/200/390 +f 2697/208/391 2706/236/391 2707/235/391 +f 2707/235/391 2698/207/391 2697/208/391 +f 2698/207/398 2707/235/398 2699/236/398 +f 2699/236/398 2714/208/398 2698/207/398 +f 2721/236/27 2683/238/27 2686/237/27 +f 2686/237/27 2722/231/27 2721/236/27 +f 2722/231/27 2686/237/27 2724/239/27 +f 2724/239/27 2701/233/27 2722/231/27 +f 2701/210/408 2724/241/409 2723/240/409 +f 2723/240/409 2699/209/408 2701/210/408 +f 2699/236/26 2723/238/26 2685/242/26 +f 2685/242/26 2714/208/26 2699/236/26 +f 2714/208/26 2685/242/26 2684/240/26 +f 2684/240/26 2713/209/26 2714/208/26 +f 2696/209/26 2691/240/26 2694/242/26 +f 2694/242/26 2697/208/26 2696/209/26 +f 2697/208/26 2694/242/26 2726/238/26 +f 2726/238/26 2706/236/26 2697/208/26 +f 2706/209/410 2726/240/410 2725/241/410 +f 2725/241/410 2704/210/410 2706/209/410 +f 2704/233/27 2725/239/27 2693/237/27 +f 2693/237/27 2719/231/27 2704/233/27 +f 2719/231/27 2693/237/27 2692/238/27 +f 2692/238/27 2720/236/27 2719/231/27 +f 2727/195/411 2728/198/411 2729/197/411 +f 2729/197/411 2730/196/411 2727/195/411 +f 2731/199/412 2732/202/412 2733/201/413 +f 2733/201/413 2734/200/413 2731/199/412 +f 2735/203/414 2736/206/414 2737/205/414 +f 2737/205/414 2738/204/414 2735/203/414 +f 2739/202/415 2740/199/415 2741/200/416 +f 2741/200/416 2742/201/416 2739/202/415 +f 2743/207/417 2744/209/417 2745/208/417 +f 2745/208/417 2746/207/417 2743/207/417 +f 2747/209/171 2748/211/171 2749/210/171 +f 2738/212/418 2737/214/418 2750/213/418 +f 2750/213/418 2751/196/418 2738/212/418 +f 2752/210/419 2753/211/419 2754/209/419 +f 2755/215/420 2754/209/420 2753/211/420 +f 2753/211/420 2756/216/420 2755/215/420 +f 2757/217/167 2730/196/167 2729/197/167 +f 2729/197/167 2758/218/167 2757/217/167 +f 2759/219/421 2735/203/421 2738/204/421 +f 2738/204/421 2760/220/421 2759/219/421 +f 2761/209/422 2743/207/422 2746/207/422 +f 2746/207/422 2762/208/422 2761/209/422 +f 2738/212/423 2751/196/423 2763/213/423 +f 2763/213/423 2760/214/423 2738/212/423 +f 2755/215/424 2756/216/424 2748/211/424 +f 2748/211/424 2747/209/424 2755/215/424 +f 2764/221/415 2728/221/416 2727/222/416 +f 2727/222/416 2750/222/415 2764/221/415 +f 2750/222/425 2727/222/425 2730/203/425 +f 2730/203/425 2751/203/425 2750/222/425 +f 2751/203/426 2730/203/426 2757/206/426 +f 2757/206/426 2763/206/426 2751/203/426 +f 2763/206/413 2757/206/413 2758/223/413 +f 2758/223/413 2765/223/413 2763/206/413 +f 2765/224/427 2758/224/427 2729/226/427 +f 2729/226/427 2766/225/427 2765/224/427 +f 2766/225/428 2729/226/428 2728/224/428 +f 2728/224/428 2764/224/428 2766/225/428 +f 2760/214/419 2763/213/419 2765/228/419 +f 2765/228/419 2767/227/419 2760/214/419 +f 2767/229/415 2768/221/415 2759/219/415 +f 2759/219/415 2760/220/415 2767/229/415 +f 2736/206/413 2769/223/413 2770/230/413 +f 2770/230/413 2737/205/413 2736/206/413 +f 2770/227/171 2764/228/171 2750/213/171 +f 2750/213/171 2737/214/171 2770/227/171 +f 2733/201/413 2771/202/412 2772/199/412 +f 2772/199/412 2734/200/413 2733/201/413 +f 2770/231/429 2749/233/429 2748/232/429 +f 2748/232/429 2764/224/429 2770/231/429 +f 2764/224/428 2748/232/428 2756/234/428 +f 2756/234/428 2766/225/428 2764/224/428 +f 2766/225/427 2756/234/427 2753/232/427 +f 2753/232/427 2765/224/427 2766/225/427 +f 2765/224/430 2753/232/430 2752/233/430 +f 2752/233/430 2767/231/430 2765/224/430 +f 2741/200/416 2773/199/415 2774/202/415 +f 2774/202/415 2742/201/416 2741/200/416 +f 2745/208/417 2754/236/417 2755/235/417 +f 2755/235/417 2746/207/417 2745/208/417 +f 2746/207/422 2755/235/422 2747/236/422 +f 2747/236/422 2762/208/422 2746/207/422 +f 2769/236/27 2731/238/27 2734/237/27 +f 2734/237/27 2770/231/27 2769/236/27 +f 2770/231/27 2734/237/27 2772/239/27 +f 2772/239/27 2749/233/27 2770/231/27 +f 2749/210/191 2772/241/191 2771/240/191 +f 2771/240/191 2747/209/191 2749/210/191 +f 2747/236/26 2771/238/26 2733/242/26 +f 2733/242/26 2762/208/26 2747/236/26 +f 2762/208/26 2733/242/26 2732/240/26 +f 2732/240/26 2761/209/26 2762/208/26 +f 2744/209/26 2739/240/26 2742/242/26 +f 2742/242/26 2745/208/26 2744/209/26 +f 2745/208/26 2742/242/26 2774/238/26 +f 2774/238/26 2754/236/26 2745/208/26 +f 2754/209/431 2774/240/431 2773/241/431 +f 2773/241/431 2752/210/431 2754/209/431 +f 2752/233/27 2773/239/27 2741/237/27 +f 2741/237/27 2767/231/27 2752/233/27 +f 2767/231/27 2741/237/27 2740/238/27 +f 2740/238/27 2768/236/27 2767/231/27 +f 2775/243/432 2776/246/432 2777/245/432 +f 2777/245/432 2778/244/432 2775/243/432 +f 2775/247/433 2779/250/433 2780/249/433 +f 2780/249/433 2776/248/433 2775/247/433 +f 2776/246/434 2780/252/434 2781/251/434 +f 2781/251/434 2777/245/434 2776/246/434 +f 2777/248/435 2781/249/435 2782/250/435 +f 2782/250/435 2778/247/435 2777/248/435 +f 2783/195/436 2784/198/436 2785/197/436 +f 2785/197/436 2786/196/436 2783/195/436 +f 2787/199/437 2788/202/437 2789/201/413 +f 2789/201/413 2790/200/413 2787/199/437 +f 2791/203/414 2792/206/414 2793/205/414 +f 2793/205/414 2794/204/414 2791/203/414 +f 2795/202/415 2796/199/415 2797/200/416 +f 2797/200/416 2798/201/416 2795/202/415 +f 2799/207/417 2800/209/417 2801/208/417 +f 2801/208/417 2802/207/417 2799/207/417 +f 2803/209/171 2804/211/171 2805/210/171 +f 2794/212/418 2793/214/418 2806/213/418 +f 2806/213/418 2807/196/418 2794/212/418 +f 2808/210/419 2809/211/419 2810/209/419 +f 2811/215/420 2810/209/420 2809/211/420 +f 2809/211/420 2812/216/420 2811/215/420 +f 2813/217/167 2786/196/167 2785/197/167 +f 2785/197/167 2814/218/167 2813/217/167 +f 2815/219/438 2791/203/421 2794/204/421 +f 2794/204/421 2816/220/438 2815/219/438 +f 2817/209/422 2799/207/422 2802/207/422 +f 2802/207/422 2818/208/422 2817/209/422 +f 2794/212/423 2807/196/423 2819/213/423 +f 2819/213/423 2816/214/423 2794/212/423 +f 2811/215/424 2812/216/424 2804/211/424 +f 2804/211/424 2803/209/424 2811/215/424 +f 2820/221/415 2784/221/415 2783/222/415 +f 2783/222/415 2806/222/415 2820/221/415 +f 2806/222/425 2783/222/425 2786/203/425 +f 2786/203/425 2807/203/425 2806/222/425 +f 2807/203/426 2786/203/426 2813/206/426 +f 2813/206/426 2819/206/426 2807/203/426 +f 2819/206/413 2813/206/413 2814/223/413 +f 2814/223/413 2821/223/413 2819/206/413 +f 2821/224/427 2814/224/427 2785/226/427 +f 2785/226/427 2822/225/427 2821/224/427 +f 2822/225/428 2785/226/428 2784/224/428 +f 2784/224/428 2820/224/428 2822/225/428 +f 2816/214/419 2819/213/419 2821/228/419 +f 2821/228/419 2823/227/419 2816/214/419 +f 2823/229/416 2824/221/416 2815/219/416 +f 2815/219/416 2816/220/416 2823/229/416 +f 2792/206/413 2825/223/413 2826/230/412 +f 2826/230/412 2793/205/412 2792/206/413 +f 2826/227/171 2820/228/171 2806/213/171 +f 2806/213/171 2793/214/171 2826/227/171 +f 2789/201/413 2827/202/412 2828/199/412 +f 2828/199/412 2790/200/413 2789/201/413 +f 2826/231/429 2805/233/429 2804/232/429 +f 2804/232/429 2820/224/429 2826/231/429 +f 2820/224/428 2804/232/428 2812/234/428 +f 2812/234/428 2822/225/428 2820/224/428 +f 2822/225/427 2812/234/427 2809/232/427 +f 2809/232/427 2821/224/427 2822/225/427 +f 2821/224/430 2809/232/430 2808/233/430 +f 2808/233/430 2823/231/430 2821/224/430 +f 2797/200/416 2829/199/415 2830/202/415 +f 2830/202/415 2798/201/416 2797/200/416 +f 2801/208/417 2810/236/417 2811/235/417 +f 2811/235/417 2802/207/417 2801/208/417 +f 2802/207/422 2811/235/422 2803/236/422 +f 2803/236/422 2818/208/422 2802/207/422 +f 2825/236/27 2787/238/27 2790/237/27 +f 2790/237/27 2826/231/27 2825/236/27 +f 2826/231/27 2790/237/27 2828/239/27 +f 2828/239/27 2805/233/27 2826/231/27 +f 2805/210/191 2828/241/191 2827/240/191 +f 2827/240/191 2803/209/191 2805/210/191 +f 2803/236/26 2827/238/26 2789/242/26 +f 2789/242/26 2818/208/26 2803/236/26 +f 2818/208/26 2789/242/26 2788/240/26 +f 2788/240/26 2817/209/26 2818/208/26 +f 2800/209/26 2795/240/26 2798/242/26 +f 2798/242/26 2801/208/26 2800/209/26 +f 2801/208/26 2798/242/26 2830/238/26 +f 2830/238/26 2810/236/26 2801/208/26 +f 2810/209/431 2830/240/431 2829/241/431 +f 2829/241/431 2808/210/431 2810/209/431 +f 2808/233/27 2829/239/27 2797/237/27 +f 2797/237/27 2823/231/27 2808/233/27 +f 2823/231/27 2797/237/27 2796/238/27 +f 2796/238/27 2824/236/27 2823/231/27 +f 2831/243/439 2832/246/439 2833/245/439 +f 2833/245/439 2834/244/439 2831/243/439 +f 2831/247/440 2835/250/440 2836/249/440 +f 2836/249/440 2832/248/440 2831/247/440 +f 2832/246/441 2836/252/441 2837/251/441 +f 2837/251/441 2833/245/441 2832/246/441 +f 2833/248/442 2837/249/442 2838/250/442 +f 2838/250/442 2834/247/442 2833/248/442 +f 2839/195/443 2840/198/443 2841/197/443 +f 2841/197/443 2842/196/443 2839/195/443 +f 2843/199/390 2844/202/390 2845/201/390 +f 2845/201/390 2846/200/390 2843/199/390 +f 2847/203/444 2848/206/444 2849/205/444 +f 2849/205/444 2850/204/444 2847/203/444 +f 2851/202/388 2852/199/388 2853/200/388 +f 2853/200/388 2854/201/388 2851/202/388 +f 2855/207/398 2856/209/398 2857/208/398 +f 2857/208/398 2858/207/398 2855/207/398 +f 2859/209/445 2860/211/445 2861/210/445 +f 2850/212/446 2849/214/446 2862/213/446 +f 2862/213/446 2863/196/446 2850/212/446 +f 2864/210/447 2865/211/447 2866/209/447 +f 2867/215/448 2866/209/448 2865/211/448 +f 2865/211/448 2868/216/448 2867/215/448 +f 2869/217/449 2842/196/450 2841/197/450 +f 2841/197/450 2870/218/449 2869/217/449 +f 2871/219/451 2847/203/451 2850/204/451 +f 2850/204/451 2872/220/451 2871/219/451 +f 2873/209/391 2855/207/391 2858/207/391 +f 2858/207/391 2874/208/391 2873/209/391 +f 2850/212/452 2863/196/452 2875/213/452 +f 2875/213/452 2872/214/452 2850/212/452 +f 2867/215/453 2868/216/453 2860/211/453 +f 2860/211/453 2859/209/453 2867/215/453 +f 2876/221/388 2840/221/388 2839/222/388 +f 2839/222/388 2862/222/388 2876/221/388 +f 2862/222/402 2839/222/402 2842/203/402 +f 2842/203/402 2863/203/402 2862/222/402 +f 2863/203/401 2842/203/401 2869/206/401 +f 2869/206/401 2875/206/401 2863/203/401 +f 2875/206/390 2869/206/390 2870/223/390 +f 2870/223/390 2877/223/390 2875/206/390 +f 2877/224/454 2870/224/454 2841/226/454 +f 2841/226/454 2878/225/454 2877/224/454 +f 2878/225/455 2841/226/455 2840/224/455 +f 2840/224/455 2876/224/455 2878/225/455 +f 2872/214/447 2875/213/447 2877/228/447 +f 2877/228/447 2879/227/447 2872/214/447 +f 2879/229/388 2880/221/388 2871/219/388 +f 2871/219/388 2872/220/388 2879/229/388 +f 2848/206/390 2881/223/390 2882/230/390 +f 2882/230/390 2849/205/390 2848/206/390 +f 2882/227/445 2876/228/445 2862/213/445 +f 2862/213/445 2849/214/445 2882/227/445 +f 2845/201/390 2883/202/390 2884/199/390 +f 2884/199/390 2846/200/390 2845/201/390 +f 2882/231/456 2861/233/456 2860/232/456 +f 2860/232/456 2876/224/456 2882/231/456 +f 2876/224/455 2860/232/455 2868/234/455 +f 2868/234/455 2878/225/455 2876/224/455 +f 2878/225/454 2868/234/454 2865/232/454 +f 2865/232/454 2877/224/454 2878/225/454 +f 2877/224/457 2865/232/457 2864/233/457 +f 2864/233/457 2879/231/457 2877/224/457 +f 2853/200/388 2885/199/388 2886/202/388 +f 2886/202/388 2854/201/388 2853/200/388 +f 2857/208/398 2866/236/398 2867/235/398 +f 2867/235/398 2858/207/398 2857/208/398 +f 2858/207/391 2867/235/391 2859/236/391 +f 2859/236/391 2874/208/391 2858/207/391 +f 2881/236/27 2843/238/27 2846/237/27 +f 2846/237/27 2882/231/27 2881/236/27 +f 2882/231/27 2846/237/27 2884/239/27 +f 2884/239/27 2861/233/27 2882/231/27 +f 2861/210/458 2884/241/458 2883/240/458 +f 2883/240/458 2859/209/458 2861/210/458 +f 2859/236/26 2883/238/26 2845/242/26 +f 2845/242/26 2874/208/26 2859/236/26 +f 2874/208/26 2845/242/26 2844/240/26 +f 2844/240/26 2873/209/26 2874/208/26 +f 2856/209/26 2851/240/26 2854/242/26 +f 2854/242/26 2857/208/26 2856/209/26 +f 2857/208/26 2854/242/26 2886/238/26 +f 2886/238/26 2866/236/26 2857/208/26 +f 2866/209/459 2886/240/459 2885/241/459 +f 2885/241/459 2864/210/459 2866/209/459 +f 2864/233/27 2885/239/27 2853/237/27 +f 2853/237/27 2879/231/27 2864/233/27 +f 2879/231/27 2853/237/27 2852/238/27 +f 2852/238/27 2880/236/27 2879/231/27 +f 2887/243/154 2888/246/154 2889/245/154 +f 2889/245/154 2890/244/154 2887/243/154 +f 2887/247/1 2891/250/1 2892/249/1 +f 2892/249/1 2888/248/1 2887/247/1 +f 2888/246/155 2892/252/155 2893/251/155 +f 2893/251/155 2889/245/155 2888/246/155 +f 2889/248/7 2893/249/7 2894/250/7 +f 2894/250/7 2890/247/7 2889/248/7 +f 2895/243/160 2896/246/160 2897/245/160 +f 2897/245/160 2898/244/160 2895/243/160 +f 2895/247/163 2899/250/163 2900/249/163 +f 2900/249/163 2896/248/163 2895/247/163 +f 2896/246/162 2900/252/162 2901/251/162 +f 2901/251/162 2897/245/162 2896/246/162 +f 2897/248/161 2901/249/161 2902/250/161 +f 2902/250/161 2898/247/161 2897/248/161 +f 2903/243/148 2904/246/148 2905/245/148 +f 2905/245/148 2906/244/148 2903/243/148 +f 2903/247/7 2907/250/7 2908/249/7 +f 2908/249/7 2904/248/7 2903/247/7 +f 2904/246/149 2908/252/149 2909/251/149 +f 2909/251/149 2905/245/149 2904/246/149 +f 2905/248/1 2909/249/1 2910/250/1 +f 2910/250/1 2906/247/1 2905/248/1 +f 2911/243/460 2912/246/460 2913/245/460 +f 2913/245/460 2914/244/460 2911/243/460 +f 2911/247/461 2915/250/461 2916/249/461 +f 2916/249/461 2912/248/461 2911/247/461 +f 2912/246/462 2916/252/462 2917/251/462 +f 2917/251/462 2913/245/462 2912/246/462 +f 2913/248/463 2917/249/463 2918/250/463 +f 2918/250/463 2914/247/463 2913/248/463 +f 2919/243/150 2920/246/150 2921/245/150 +f 2921/245/150 2922/244/150 2919/243/150 +f 2919/247/153 2923/250/153 2924/249/153 +f 2924/249/153 2920/248/153 2919/247/153 +f 2920/246/152 2924/252/152 2925/251/152 +f 2925/251/152 2921/245/152 2920/246/152 +f 2921/248/151 2925/249/151 2926/250/151 +f 2926/250/151 2922/247/151 2921/248/151 +f 2927/195/443 2928/198/443 2929/197/443 +f 2929/197/443 2930/196/443 2927/195/443 +f 2931/199/390 2932/202/390 2933/201/390 +f 2933/201/390 2934/200/390 2931/199/390 +f 2935/203/444 2936/206/444 2937/205/444 +f 2937/205/444 2938/204/444 2935/203/444 +f 2939/202/388 2940/199/388 2941/200/388 +f 2941/200/388 2942/201/388 2939/202/388 +f 2943/207/398 2944/209/398 2945/208/398 +f 2945/208/398 2946/207/398 2943/207/398 +f 2947/209/445 2948/211/445 2949/210/445 +f 2938/212/446 2937/214/446 2950/213/446 +f 2950/213/446 2951/196/446 2938/212/446 +f 2952/210/447 2953/211/447 2954/209/447 +f 2955/215/448 2954/209/448 2953/211/448 +f 2953/211/448 2956/216/448 2955/215/448 +f 2957/217/449 2930/196/450 2929/197/450 +f 2929/197/450 2958/218/449 2957/217/449 +f 2959/219/451 2935/203/451 2938/204/451 +f 2938/204/451 2960/220/451 2959/219/451 +f 2961/209/391 2943/207/391 2946/207/391 +f 2946/207/391 2962/208/391 2961/209/391 +f 2938/212/452 2951/196/452 2963/213/452 +f 2963/213/452 2960/214/452 2938/212/452 +f 2955/215/453 2956/216/453 2948/211/453 +f 2948/211/453 2947/209/453 2955/215/453 +f 2964/221/388 2928/221/388 2927/222/388 +f 2927/222/388 2950/222/388 2964/221/388 +f 2950/222/402 2927/222/402 2930/203/402 +f 2930/203/402 2951/203/402 2950/222/402 +f 2951/203/401 2930/203/401 2957/206/401 +f 2957/206/401 2963/206/401 2951/203/401 +f 2963/206/390 2957/206/390 2958/223/390 +f 2958/223/390 2965/223/390 2963/206/390 +f 2965/224/454 2958/224/454 2929/226/454 +f 2929/226/454 2966/225/454 2965/224/454 +f 2966/225/455 2929/226/455 2928/224/455 +f 2928/224/455 2964/224/455 2966/225/455 +f 2960/214/447 2963/213/447 2965/228/447 +f 2965/228/447 2967/227/447 2960/214/447 +f 2967/229/388 2968/221/388 2959/219/388 +f 2959/219/388 2960/220/388 2967/229/388 +f 2936/206/390 2969/223/390 2970/230/390 +f 2970/230/390 2937/205/390 2936/206/390 +f 2970/227/445 2964/228/445 2950/213/445 +f 2950/213/445 2937/214/445 2970/227/445 +f 2933/201/390 2971/202/390 2972/199/390 +f 2972/199/390 2934/200/390 2933/201/390 +f 2970/231/456 2949/233/456 2948/232/456 +f 2948/232/456 2964/224/456 2970/231/456 +f 2964/224/455 2948/232/455 2956/234/455 +f 2956/234/455 2966/225/455 2964/224/455 +f 2966/225/454 2956/234/454 2953/232/454 +f 2953/232/454 2965/224/454 2966/225/454 +f 2965/224/457 2953/232/457 2952/233/457 +f 2952/233/457 2967/231/457 2965/224/457 +f 2941/200/388 2973/199/388 2974/202/388 +f 2974/202/388 2942/201/388 2941/200/388 +f 2945/208/398 2954/236/398 2955/235/398 +f 2955/235/398 2946/207/398 2945/208/398 +f 2946/207/391 2955/235/391 2947/236/391 +f 2947/236/391 2962/208/391 2946/207/391 +f 2969/236/27 2931/238/27 2934/237/27 +f 2934/237/27 2970/231/27 2969/236/27 +f 2970/231/27 2934/237/27 2972/239/27 +f 2972/239/27 2949/233/27 2970/231/27 +f 2949/210/458 2972/241/458 2971/240/458 +f 2971/240/458 2947/209/458 2949/210/458 +f 2947/236/26 2971/238/26 2933/242/26 +f 2933/242/26 2962/208/26 2947/236/26 +f 2962/208/26 2933/242/26 2932/240/26 +f 2932/240/26 2961/209/26 2962/208/26 +f 2944/209/26 2939/240/26 2942/242/26 +f 2942/242/26 2945/208/26 2944/209/26 +f 2945/208/26 2942/242/26 2974/238/26 +f 2974/238/26 2954/236/26 2945/208/26 +f 2954/209/459 2974/240/459 2973/241/459 +f 2973/241/459 2952/210/459 2954/209/459 +f 2952/233/27 2973/239/27 2941/237/27 +f 2941/237/27 2967/231/27 2952/233/27 +f 2967/231/27 2941/237/27 2940/238/27 +f 2940/238/27 2968/236/27 2967/231/27 +f 2975/195/464 2976/198/464 2977/197/4 +f 2977/197/4 2978/196/4 2975/195/464 +f 2979/199/465 2980/202/465 2981/201/465 +f 2981/201/465 2982/200/465 2979/199/465 +f 2983/203/421 2984/206/421 2985/205/421 +f 2985/205/421 2986/204/421 2983/203/421 +f 2987/202/437 2988/199/437 2989/200/437 +f 2989/200/437 2990/201/437 2987/202/437 +f 2991/207/466 2992/209/466 2993/208/466 +f 2993/208/466 2994/207/466 2991/207/466 +f 2995/209/107 2996/211/107 2997/210/107 +f 2986/212/467 2985/214/467 2998/213/467 +f 2998/213/467 2999/196/467 2986/212/467 +f 3000/210/468 3001/211/468 3002/209/468 +f 3003/215/469 3002/209/469 3001/211/469 +f 3001/211/469 3004/216/469 3003/215/469 +f 3005/217/103 2978/196/103 2977/197/103 +f 2977/197/103 3006/218/103 3005/217/103 +f 3007/219/470 2983/203/414 2986/204/414 +f 2986/204/414 3008/220/414 3007/219/470 +f 3009/209/471 2991/207/471 2994/207/471 +f 2994/207/471 3010/208/471 3009/209/471 +f 2986/212/472 2999/196/472 3011/213/472 +f 3011/213/472 3008/214/472 2986/212/472 +f 3003/215/332 3004/216/332 2996/211/332 +f 2996/211/332 2995/209/332 3003/215/332 +f 3012/221/437 2976/221/437 2975/222/437 +f 2975/222/437 2998/222/437 3012/221/437 +f 2998/222/426 2975/222/426 2978/203/426 +f 2978/203/426 2999/203/426 2998/222/426 +f 2999/203/425 2978/203/425 3005/206/425 +f 3005/206/425 3011/206/425 2999/203/425 +f 3011/206/465 3005/206/465 3006/223/465 +f 3006/223/465 3013/223/465 3011/206/465 +f 3013/224/473 3006/224/473 2977/226/473 +f 2977/226/473 3014/225/473 3013/224/473 +f 3014/225/430 2977/226/430 2976/224/430 +f 2976/224/430 3012/224/430 3014/225/430 +f 3008/214/468 3011/213/468 3013/228/468 +f 3013/228/468 3015/227/468 3008/214/468 +f 3015/229/437 3016/221/437 3007/219/437 +f 3007/219/437 3008/220/437 3015/229/437 +f 2984/206/465 3017/223/465 3018/230/465 +f 3018/230/465 2985/205/465 2984/206/465 +f 3018/227/107 3012/228/107 2998/213/107 +f 2998/213/107 2985/214/107 3018/227/107 +f 2981/201/465 3019/202/465 3020/199/465 +f 3020/199/465 2982/200/465 2981/201/465 +f 3018/231/474 2997/233/474 2996/232/474 +f 2996/232/474 3012/224/474 3018/231/474 +f 3012/224/430 2996/232/430 3004/234/430 +f 3004/234/430 3014/225/430 3012/224/430 +f 3014/225/473 3004/234/473 3001/232/473 +f 3001/232/473 3013/224/473 3014/225/473 +f 3013/224/428 3001/232/428 3000/233/428 +f 3000/233/428 3015/231/428 3013/224/428 +f 2989/200/437 3021/199/437 3022/202/437 +f 3022/202/437 2990/201/437 2989/200/437 +f 2993/208/466 3002/236/466 3003/235/466 +f 3003/235/466 2994/207/466 2993/208/466 +f 2994/207/471 3003/235/471 2995/236/471 +f 2995/236/471 3010/208/471 2994/207/471 +f 3017/236/27 2979/238/27 2982/237/27 +f 2982/237/27 3018/231/27 3017/236/27 +f 3018/231/27 2982/237/27 3020/239/27 +f 3020/239/27 2997/233/27 3018/231/27 +f 2997/210/193 3020/241/193 3019/240/193 +f 3019/240/193 2995/209/193 2997/210/193 +f 2995/236/26 3019/238/26 2981/242/26 +f 2981/242/26 3010/208/26 2995/236/26 +f 3010/208/26 2981/242/26 2980/240/26 +f 2980/240/26 3009/209/26 3010/208/26 +f 2992/209/26 2987/240/26 2990/242/26 +f 2990/242/26 2993/208/26 2992/209/26 +f 2993/208/26 2990/242/26 3022/238/26 +f 3022/238/26 3002/236/26 2993/208/26 +f 3002/209/475 3022/240/475 3021/241/475 +f 3021/241/475 3000/210/475 3002/209/475 +f 3000/233/27 3021/239/27 2989/237/27 +f 2989/237/27 3015/231/27 3000/233/27 +f 3015/231/27 2989/237/27 2988/238/27 +f 2988/238/27 3016/236/27 3015/231/27 +f 3023/243/187 3024/246/187 3025/245/187 +f 3025/245/187 3026/244/187 3023/243/187 +f 3023/247/161 3027/250/161 3028/249/161 +f 3028/249/161 3024/248/161 3023/247/161 +f 3024/246/188 3028/252/189 3029/251/188 +f 3029/251/188 3025/245/188 3024/246/188 +f 3025/248/163 3029/249/163 3030/250/163 +f 3030/250/163 3026/247/163 3025/248/163 +f 3031/195/4 3032/198/4 3033/197/4 +f 3033/197/4 3034/196/4 3031/195/4 +f 3035/199/465 3036/202/465 3037/201/465 +f 3037/201/465 3038/200/465 3035/199/465 +f 3039/203/421 3040/206/421 3041/205/421 +f 3041/205/421 3042/204/421 3039/203/421 +f 3043/202/437 3044/199/437 3045/200/437 +f 3045/200/437 3046/201/437 3043/202/437 +f 3047/207/466 3048/209/466 3049/208/466 +f 3049/208/466 3050/207/466 3047/207/466 +f 3051/209/107 3052/211/107 3053/210/107 +f 3042/212/467 3041/214/467 3054/213/467 +f 3054/213/467 3055/196/467 3042/212/467 +f 3056/210/468 3057/211/468 3058/209/468 +f 3059/215/469 3058/209/469 3057/211/469 +f 3057/211/469 3060/216/469 3059/215/469 +f 3061/217/103 3034/196/103 3033/197/103 +f 3033/197/103 3062/218/103 3061/217/103 +f 3063/219/414 3039/203/414 3042/204/470 +f 3042/204/470 3064/220/414 3063/219/414 +f 3065/209/471 3047/207/471 3050/207/471 +f 3050/207/471 3066/208/471 3065/209/471 +f 3042/212/472 3055/196/472 3067/213/472 +f 3067/213/472 3064/214/472 3042/212/472 +f 3059/215/332 3060/216/332 3052/211/332 +f 3052/211/332 3051/209/332 3059/215/332 +f 3068/221/437 3032/221/437 3031/222/437 +f 3031/222/437 3054/222/437 3068/221/437 +f 3054/222/426 3031/222/426 3034/203/426 +f 3034/203/426 3055/203/426 3054/222/426 +f 3055/203/425 3034/203/425 3061/206/425 +f 3061/206/425 3067/206/425 3055/203/425 +f 3067/206/465 3061/206/465 3062/223/465 +f 3062/223/465 3069/223/465 3067/206/465 +f 3069/224/473 3062/224/473 3033/226/473 +f 3033/226/473 3070/225/473 3069/224/473 +f 3070/225/430 3033/226/430 3032/224/430 +f 3032/224/430 3068/224/430 3070/225/430 +f 3064/214/468 3067/213/468 3069/228/468 +f 3069/228/468 3071/227/468 3064/214/468 +f 3071/229/437 3072/221/437 3063/219/437 +f 3063/219/437 3064/220/437 3071/229/437 +f 3040/206/465 3073/223/465 3074/230/465 +f 3074/230/465 3041/205/465 3040/206/465 +f 3074/227/107 3068/228/107 3054/213/107 +f 3054/213/107 3041/214/107 3074/227/107 +f 3037/201/465 3075/202/465 3076/199/465 +f 3076/199/465 3038/200/465 3037/201/465 +f 3074/231/474 3053/233/474 3052/232/474 +f 3052/232/474 3068/224/474 3074/231/474 +f 3068/224/430 3052/232/430 3060/234/430 +f 3060/234/430 3070/225/430 3068/224/430 +f 3070/225/473 3060/234/473 3057/232/473 +f 3057/232/473 3069/224/473 3070/225/473 +f 3069/224/428 3057/232/428 3056/233/428 +f 3056/233/428 3071/231/428 3069/224/428 +f 3045/200/437 3077/199/437 3078/202/437 +f 3078/202/437 3046/201/437 3045/200/437 +f 3049/208/466 3058/236/466 3059/235/466 +f 3059/235/466 3050/207/466 3049/208/466 +f 3050/207/471 3059/235/471 3051/236/471 +f 3051/236/471 3066/208/471 3050/207/471 +f 3073/236/27 3035/238/27 3038/237/27 +f 3038/237/27 3074/231/27 3073/236/27 +f 3074/231/27 3038/237/27 3076/239/27 +f 3076/239/27 3053/233/27 3074/231/27 +f 3053/210/193 3076/241/193 3075/240/193 +f 3075/240/193 3051/209/193 3053/210/193 +f 3051/236/26 3075/238/26 3037/242/26 +f 3037/242/26 3066/208/26 3051/236/26 +f 3066/208/26 3037/242/26 3036/240/26 +f 3036/240/26 3065/209/26 3066/208/26 +f 3048/209/26 3043/240/26 3046/242/26 +f 3046/242/26 3049/208/26 3048/209/26 +f 3049/208/26 3046/242/26 3078/238/26 +f 3078/238/26 3058/236/26 3049/208/26 +f 3058/209/475 3078/240/475 3077/241/475 +f 3077/241/475 3056/210/475 3058/209/475 +f 3056/233/27 3077/239/27 3045/237/27 +f 3045/237/27 3071/231/27 3056/233/27 +f 3071/231/27 3045/237/27 3044/238/27 +f 3044/238/27 3072/236/27 3071/231/27 +f 3079/243/476 3080/246/476 3081/245/476 +f 3081/245/476 3082/244/476 3079/243/476 +f 3079/247/477 3083/250/477 3084/249/477 +f 3084/249/477 3080/248/477 3079/247/477 +f 3080/246/478 3084/252/478 3085/251/478 +f 3085/251/478 3081/245/478 3080/246/478 +f 3081/248/479 3085/249/479 3086/250/479 +f 3086/250/479 3082/247/479 3081/248/479 +f 3087/195/387 3088/198/387 3089/197/387 +f 3089/197/387 3090/196/387 3087/195/387 +f 3091/199/388 3092/202/388 3093/201/388 +f 3093/201/388 3094/200/388 3091/199/388 +f 3095/203/389 3096/206/389 3097/205/389 +f 3097/205/389 3098/204/389 3095/203/389 +f 3099/202/390 3100/199/390 3101/200/390 +f 3101/200/390 3102/201/390 3099/202/390 +f 3103/207/391 3104/209/391 3105/208/391 +f 3105/208/391 3106/207/391 3103/207/391 +f 3107/209/392 3108/211/392 3109/210/392 +f 3098/212/393 3097/214/393 3110/213/393 +f 3110/213/393 3111/196/393 3098/212/393 +f 3112/210/394 3113/211/394 3114/209/394 +f 3115/215/395 3114/209/395 3113/211/395 +f 3113/211/395 3116/216/395 3115/215/395 +f 3117/217/396 3090/196/396 3089/197/396 +f 3089/197/396 3118/218/396 3117/217/396 +f 3119/219/397 3095/203/397 3098/204/397 +f 3098/204/397 3120/220/397 3119/219/397 +f 3121/209/398 3103/207/398 3106/207/398 +f 3106/207/398 3122/208/398 3121/209/398 +f 3098/212/399 3111/196/399 3123/213/399 +f 3123/213/399 3120/214/399 3098/212/399 +f 3115/215/400 3116/216/400 3108/211/400 +f 3108/211/400 3107/209/400 3115/215/400 +f 3124/221/390 3088/221/390 3087/222/390 +f 3087/222/390 3110/222/390 3124/221/390 +f 3110/222/401 3087/222/401 3090/203/401 +f 3090/203/401 3111/203/401 3110/222/401 +f 3111/203/402 3090/203/402 3117/206/402 +f 3117/206/402 3123/206/402 3111/203/402 +f 3123/206/388 3117/206/388 3118/223/388 +f 3118/223/388 3125/223/388 3123/206/388 +f 3125/224/403 3118/224/403 3089/226/403 +f 3089/226/403 3126/225/403 3125/224/403 +f 3126/225/404 3089/226/404 3088/224/404 +f 3088/224/404 3124/224/404 3126/225/404 +f 3120/214/394 3123/213/394 3125/228/394 +f 3125/228/394 3127/227/394 3120/214/394 +f 3127/229/390 3128/221/390 3119/219/390 +f 3119/219/390 3120/220/390 3127/229/390 +f 3096/206/388 3129/223/388 3130/230/388 +f 3130/230/388 3097/205/388 3096/206/388 +f 3130/227/392 3124/228/392 3110/213/392 +f 3110/213/392 3097/214/392 3130/227/392 +f 3093/201/388 3131/202/388 3132/199/388 +f 3132/199/388 3094/200/388 3093/201/388 +f 3130/231/405 3109/233/405 3108/232/405 +f 3108/232/405 3124/224/405 3130/231/405 +f 3124/224/404 3108/232/404 3116/234/404 +f 3116/234/404 3126/225/404 3124/224/404 +f 3126/225/403 3116/234/403 3113/232/403 +f 3113/232/403 3125/224/403 3126/225/403 +f 3125/224/407 3113/232/407 3112/233/407 +f 3112/233/407 3127/231/407 3125/224/407 +f 3101/200/390 3133/199/390 3134/202/390 +f 3134/202/390 3102/201/390 3101/200/390 +f 3105/208/391 3114/236/391 3115/235/391 +f 3115/235/391 3106/207/391 3105/208/391 +f 3106/207/398 3115/235/398 3107/236/398 +f 3107/236/398 3122/208/398 3106/207/398 +f 3129/236/27 3091/238/27 3094/237/27 +f 3094/237/27 3130/231/27 3129/236/27 +f 3130/231/27 3094/237/27 3132/239/27 +f 3132/239/27 3109/233/27 3130/231/27 +f 3109/210/409 3132/241/409 3131/240/409 +f 3131/240/409 3107/209/409 3109/210/409 +f 3107/236/26 3131/238/26 3093/242/26 +f 3093/242/26 3122/208/26 3107/236/26 +f 3122/208/26 3093/242/26 3092/240/26 +f 3092/240/26 3121/209/26 3122/208/26 +f 3104/209/26 3099/240/26 3102/242/26 +f 3102/242/26 3105/208/26 3104/209/26 +f 3105/208/26 3102/242/26 3134/238/26 +f 3134/238/26 3114/236/26 3105/208/26 +f 3114/209/410 3134/240/410 3133/241/410 +f 3133/241/410 3112/210/410 3114/209/410 +f 3112/233/27 3133/239/27 3101/237/27 +f 3101/237/27 3127/231/27 3112/233/27 +f 3127/231/27 3101/237/27 3100/238/27 +f 3100/238/27 3128/236/27 3127/231/27 +f 3135/243/180 3136/246/180 3137/245/180 +f 3137/245/180 3138/244/180 3135/243/180 +f 3135/247/151 3139/250/151 3140/249/151 +f 3140/249/151 3136/248/151 3135/247/151 +f 3136/246/181 3140/252/181 3141/251/182 +f 3141/251/182 3137/245/181 3136/246/181 +f 3137/248/153 3141/249/153 3142/250/153 +f 3142/250/153 3138/247/153 3137/248/153 +f 3143/253/24 3144/256/24 3145/255/24 +f 3145/255/24 3146/254/24 3143/253/24 +f 3147/257/23 3148/258/23 3144/256/23 +f 3144/256/23 3143/253/23 3147/257/23 +f 3149/259/191 3150/260/22 3148/258/191 +f 3148/258/191 3147/257/191 3149/259/191 +f 3151/261/21 3152/264/21 3150/263/21 +f 3150/263/21 3149/262/21 3151/261/21 +f 3153/265/20 3154/266/20 3152/264/20 +f 3152/264/20 3151/261/20 3153/265/20 +f 3155/267/19 3156/268/19 3154/266/19 +f 3154/266/19 3153/265/19 3155/267/19 +f 3157/269/194 3158/270/194 3156/268/18 +f 3156/268/18 3155/267/18 3157/269/194 +f 3159/271/17 3160/272/17 3158/270/17 +f 3158/270/17 3157/269/17 3159/271/17 +f 3161/273/16 3162/274/16 3160/272/16 +f 3160/272/16 3159/271/16 3161/273/16 +f 3163/275/118 3164/276/118 3162/274/15 +f 3162/274/15 3161/273/118 3163/275/118 +f 3165/277/14 3166/278/14 3164/276/14 +f 3164/276/14 3163/275/14 3165/277/14 +f 3146/254/13 3145/255/13 3166/278/192 +f 3166/278/192 3165/277/192 3146/254/13 +f 3144/279/27 3167/282/27 3168/281/27 +f 3168/281/27 3145/280/27 3144/279/27 +f 3169/283/27 3170/284/27 3171/282/27 +f 3171/282/27 3172/279/27 3169/283/27 +f 3150/285/27 3173/285/27 3174/284/27 +f 3174/284/27 3148/283/27 3150/285/27 +f 3175/286/27 3176/287/27 3177/285/27 +f 3177/285/27 3178/285/27 3175/286/27 +f 3154/288/27 3179/289/27 3180/287/27 +f 3180/287/27 3152/286/27 3154/288/27 +f 3181/290/27 3182/291/27 3183/289/27 +f 3183/289/27 3184/288/27 3181/290/27 +f 3158/292/27 3185/293/27 3186/291/27 +f 3186/291/27 3156/290/27 3158/292/27 +f 3187/294/27 3188/295/27 3189/293/27 +f 3189/293/27 3190/292/27 3187/294/27 +f 3162/296/27 3191/297/27 3192/295/27 +f 3192/295/27 3160/294/27 3162/296/27 +f 3193/298/27 3194/299/27 3195/297/27 +f 3195/297/27 3196/296/27 3193/298/27 +f 3166/300/27 3197/300/27 3198/299/27 +f 3198/299/27 3164/298/27 3166/300/27 +f 3199/280/27 3200/281/27 3201/300/27 +f 3201/300/27 3202/300/27 3199/280/27 +f 3167/301/18 3203/304/18 3204/303/18 +f 3204/303/18 3168/302/18 3167/301/18 +f 3174/305/17 3205/306/17 3203/304/17 +f 3203/304/17 3167/301/17 3174/305/17 +f 3173/307/16 3206/308/16 3205/306/16 +f 3205/306/16 3174/305/16 3173/307/16 +f 3180/309/15 3207/310/15 3206/308/15 +f 3206/308/15 3173/307/15 3180/309/15 +f 3179/311/14 3208/312/14 3207/310/14 +f 3207/310/14 3180/309/14 3179/311/14 +f 3186/313/13 3209/314/13 3208/312/13 +f 3208/312/13 3179/311/13 3186/313/13 +f 3185/315/25 3210/316/25 3209/314/24 +f 3209/314/24 3186/313/24 3185/315/25 +f 3192/317/23 3211/318/23 3210/316/23 +f 3210/316/23 3185/315/23 3192/317/23 +f 3191/319/22 3212/320/22 3211/318/22 +f 3211/318/22 3192/317/22 3191/319/22 +f 3198/321/21 3213/324/21 3212/323/178 +f 3212/323/178 3191/322/21 3198/321/21 +f 3197/325/20 3214/326/20 3213/324/20 +f 3213/324/20 3198/321/20 3197/325/20 +f 3168/302/19 3204/303/19 3214/326/190 +f 3214/326/190 3197/325/190 3168/302/19 +f 3203/327/27 3215/329/27 3204/328/27 +f 3205/330/27 3215/329/27 3203/327/27 +f 3206/331/27 3215/329/27 3205/330/27 +f 3207/332/27 3215/329/27 3206/331/27 +f 3208/333/27 3215/329/27 3207/332/27 +f 3209/334/27 3215/329/27 3208/333/27 +f 3210/335/27 3215/329/27 3209/334/27 +f 3211/336/27 3215/329/27 3210/335/27 +f 3212/337/27 3215/329/27 3211/336/27 +f 3213/338/27 3215/329/27 3212/337/27 +f 3214/339/27 3215/329/27 3213/338/27 +f 3204/328/27 3215/329/27 3214/339/27 +f 3148/258/23 3169/341/23 3172/340/23 +f 3172/340/23 3144/256/23 3148/258/23 +f 3144/279/153 3172/279/153 3171/282/153 +f 3171/282/153 3167/282/153 3144/279/153 +f 3167/301/17 3171/343/17 3170/342/17 +f 3170/342/17 3174/305/17 3167/301/17 +f 3174/284/196 3170/284/196 3169/283/196 +f 3169/283/196 3148/283/196 3174/284/196 +f 3152/264/21 3175/345/21 3178/344/178 +f 3178/344/178 3150/263/21 3152/264/21 +f 3150/285/1 3178/285/1 3177/285/1 +f 3177/285/1 3173/285/1 3150/285/1 +f 3173/307/15 3177/347/15 3176/346/15 +f 3176/346/15 3180/309/15 3173/307/15 +f 3180/287/195 3176/287/195 3175/286/195 +f 3175/286/195 3152/286/195 3180/287/195 +f 3156/268/19 3181/349/19 3184/348/19 +f 3184/348/19 3154/266/19 3156/268/19 +f 3154/288/161 3184/288/161 3183/289/161 +f 3183/289/161 3179/289/161 3154/288/161 +f 3179/311/13 3183/351/13 3182/350/13 +f 3182/350/13 3186/313/13 3179/311/13 +f 3186/291/4 3182/291/4 3181/290/4 +f 3181/290/4 3156/290/4 3186/291/4 +f 3160/272/17 3187/353/17 3190/352/17 +f 3190/352/17 3158/270/17 3160/272/17 +f 3158/292/151 3190/292/151 3189/293/151 +f 3189/293/151 3185/293/151 3158/292/151 +f 3185/315/23 3189/355/23 3188/354/23 +f 3188/354/23 3192/317/23 3185/315/23 +f 3192/295/198 3188/295/198 3187/294/198 +f 3187/294/198 3160/294/198 3192/295/198 +f 3164/276/118 3193/357/15 3196/356/15 +f 3196/356/15 3162/274/15 3164/276/118 +f 3162/296/7 3196/296/7 3195/297/7 +f 3195/297/7 3191/297/7 3162/296/7 +f 3191/322/21 3195/359/21 3194/358/21 +f 3194/358/21 3198/321/21 3191/322/21 +f 3198/299/197 3194/299/197 3193/298/197 +f 3193/298/197 3164/298/197 3198/299/197 +f 3145/255/13 3199/361/13 3202/360/13 +f 3202/360/13 3166/278/192 3145/255/13 +f 3166/300/163 3202/300/163 3201/300/163 +f 3201/300/163 3197/300/163 3166/300/163 +f 3197/325/190 3201/363/190 3200/362/19 +f 3200/362/19 3168/302/19 3197/325/190 +f 3168/281/10 3200/281/10 3199/280/10 +f 3199/280/10 3145/280/10 3168/281/10 +f 3216/1/7 3217/2/8 3218/3/8 +f 3218/3/8 3219/4/7 3216/1/7 +f 3217/2/8 3220/5/9 3221/6/9 +f 3221/6/9 3218/3/8 3217/2/8 +f 3220/5/9 3222/7/10 3223/8/10 +f 3223/8/10 3221/6/9 3220/5/9 +f 3222/9/10 3224/10/11 3225/11/11 +f 3225/11/11 3223/12/10 3222/9/10 +f 3224/10/11 3226/13/12 3227/14/12 +f 3227/14/12 3225/11/11 3224/10/11 +f 3226/13/12 3228/15/1 3229/16/1 +f 3229/16/1 3227/14/12 3226/13/12 +f 3228/15/1 3230/17/2 3231/18/2 +f 3231/18/2 3229/16/1 3228/15/1 +f 3230/17/2 3232/19/3 3233/20/3 +f 3233/20/3 3231/18/2 3230/17/2 +f 3232/19/3 3234/21/4 3235/22/4 +f 3235/22/4 3233/20/3 3232/19/3 +f 3234/21/4 3236/23/5 3237/24/5 +f 3237/24/5 3235/22/4 3234/21/4 +f 3236/23/5 3238/25/6 3239/26/6 +f 3239/26/6 3237/24/5 3236/23/5 +f 3238/25/6 3216/1/7 3219/4/7 +f 3219/4/7 3239/26/6 3238/25/6 +f 3240/27/19 3241/28/19 3242/29/19 +f 3242/29/19 3243/30/19 3240/27/19 +f 3244/31/20 3240/27/20 3243/30/20 +f 3243/30/20 3245/32/20 3244/31/20 +f 3246/33/21 3244/31/21 3245/32/21 +f 3245/32/21 3247/34/21 3246/33/21 +f 3248/35/22 3246/36/22 3247/37/22 +f 3247/37/22 3249/38/22 3248/35/22 +f 3250/39/23 3248/35/23 3249/38/23 +f 3249/38/23 3251/40/23 3250/39/23 +f 3252/41/24 3250/39/24 3251/40/24 +f 3251/40/24 3253/42/24 3252/41/24 +f 3254/43/13 3252/41/13 3253/42/13 +f 3253/42/13 3255/44/13 3254/43/13 +f 3256/45/14 3254/43/14 3255/44/14 +f 3255/44/14 3257/46/14 3256/45/14 +f 3258/47/15 3256/45/15 3257/46/15 +f 3257/46/15 3259/48/15 3258/47/15 +f 3260/49/16 3258/47/16 3259/48/16 +f 3259/48/16 3261/50/16 3260/49/16 +f 3262/51/17 3260/49/17 3261/50/17 +f 3261/50/17 3263/52/17 3262/51/17 +f 3241/28/18 3262/51/194 3263/52/18 +f 3263/52/18 3242/29/18 3241/28/18 +f 3217/53/26 3216/54/26 3241/54/26 +f 3241/54/26 3240/53/26 3217/53/26 +f 3216/54/26 3238/55/26 3262/55/26 +f 3262/55/26 3241/54/26 3216/54/26 +f 3238/55/26 3236/56/26 3260/56/26 +f 3260/56/26 3262/55/26 3238/55/26 +f 3236/56/26 3234/57/26 3258/57/26 +f 3258/57/26 3260/56/26 3236/56/26 +f 3234/57/26 3232/58/26 3256/59/26 +f 3256/59/26 3258/57/26 3234/57/26 +f 3232/58/26 3230/60/26 3254/61/26 +f 3254/61/26 3256/59/26 3232/58/26 +f 3230/60/26 3228/62/26 3252/62/26 +f 3252/62/26 3254/61/26 3230/60/26 +f 3228/62/26 3226/63/26 3250/64/26 +f 3250/64/26 3252/62/26 3228/62/26 +f 3226/63/26 3224/65/26 3248/66/26 +f 3248/66/26 3250/64/26 3226/63/26 +f 3224/65/26 3222/67/26 3246/67/26 +f 3246/67/26 3248/66/26 3224/65/26 +f 3222/67/26 3220/68/26 3244/68/26 +f 3244/68/26 3246/67/26 3222/67/26 +f 3220/68/26 3217/53/26 3240/53/26 +f 3240/53/26 3244/68/26 3220/68/26 +f 3264/54/27 3265/53/27 3243/53/27 +f 3243/53/27 3242/54/27 3264/54/27 +f 3265/53/27 3266/68/27 3245/68/27 +f 3245/68/27 3243/53/27 3265/53/27 +f 3266/68/27 3267/67/27 3247/67/27 +f 3247/67/27 3245/68/27 3266/68/27 +f 3267/67/27 3268/65/27 3249/66/27 +f 3249/66/27 3247/67/27 3267/67/27 +f 3268/65/27 3269/63/27 3251/64/27 +f 3251/64/27 3249/66/27 3268/65/27 +f 3269/63/27 3270/62/27 3253/62/27 +f 3253/62/27 3251/64/27 3269/63/27 +f 3270/62/27 3271/60/27 3255/61/27 +f 3255/61/27 3253/62/27 3270/62/27 +f 3271/60/27 3272/58/27 3257/59/27 +f 3257/59/27 3255/61/27 3271/60/27 +f 3272/58/27 3273/57/27 3259/57/27 +f 3259/57/27 3257/59/27 3272/58/27 +f 3273/57/27 3274/56/27 3261/56/27 +f 3261/56/27 3259/57/27 3273/57/27 +f 3274/56/27 3275/55/27 3263/55/27 +f 3263/55/27 3261/56/27 3274/56/27 +f 3275/55/27 3264/54/27 3242/54/27 +f 3242/54/27 3263/55/27 3275/55/27 +f 3264/69/7 3276/70/7 3277/71/8 +f 3277/71/8 3265/72/8 3264/69/7 +f 3265/72/8 3277/71/8 3278/73/20 +f 3278/73/20 3266/74/20 3265/72/8 +f 3266/74/21 3278/73/21 3279/75/21 +f 3279/75/21 3267/76/21 3266/74/21 +f 3267/76/22 3279/75/22 3280/77/11 +f 3280/77/11 3268/78/11 3267/76/22 +f 3268/78/11 3280/77/11 3281/79/12 +f 3281/79/12 3269/80/12 3268/78/11 +f 3269/81/12 3281/82/12 3282/83/1 +f 3282/83/1 3270/84/1 3269/81/12 +f 3270/84/1 3282/83/1 3283/85/2 +f 3283/85/2 3271/86/2 3270/84/1 +f 3271/86/2 3283/85/2 3284/87/3 +f 3284/87/3 3272/88/3 3271/86/2 +f 3272/88/3 3284/87/3 3285/89/4 +f 3285/89/4 3273/90/4 3272/88/3 +f 3273/90/4 3285/89/4 3286/91/5 +f 3286/91/5 3274/92/5 3273/90/4 +f 3274/92/5 3286/91/5 3287/93/6 +f 3287/93/6 3275/94/6 3274/92/5 +f 3275/94/6 3287/93/6 3276/70/7 +f 3276/70/7 3264/69/7 3275/94/6 +f 3288/95/26 3289/96/26 3290/96/26 +f 3290/96/26 3291/95/26 3288/95/26 +f 3292/97/26 3288/95/26 3291/95/26 +f 3291/95/26 3293/97/26 3292/97/26 +f 3294/67/26 3292/97/26 3293/97/26 +f 3293/97/26 3295/98/26 3294/67/26 +f 3296/99/26 3294/67/26 3295/98/26 +f 3295/98/26 3297/99/26 3296/99/26 +f 3298/100/26 3296/99/26 3297/99/26 +f 3297/99/26 3299/100/26 3298/100/26 +f 3300/101/26 3298/100/26 3299/100/26 +f 3299/100/26 3301/101/26 3300/101/26 +f 3302/61/26 3300/101/26 3301/101/26 +f 3301/101/26 3303/61/26 3302/61/26 +f 3304/59/26 3302/61/26 3303/61/26 +f 3303/61/26 3305/102/26 3304/59/26 +f 3306/103/26 3304/59/26 3305/102/26 +f 3305/102/26 3307/103/26 3306/103/26 +f 3308/104/26 3306/103/26 3307/103/26 +f 3307/103/26 3309/105/26 3308/104/26 +f 3310/106/26 3308/104/26 3309/105/26 +f 3309/105/26 3311/106/26 3310/106/26 +f 3289/96/26 3310/106/26 3311/106/26 +f 3311/106/26 3290/96/26 3289/96/26 +f 3291/107/34 3290/108/34 3312/109/34 +f 3312/109/34 3313/110/34 3291/107/34 +f 3293/111/35 3291/107/35 3313/110/35 +f 3313/110/35 3314/112/35 3293/111/35 +f 3295/113/36 3293/111/36 3314/112/36 +f 3314/112/36 3315/114/36 3295/113/36 +f 3297/115/37 3295/113/37 3315/114/37 +f 3315/114/37 3316/116/37 3297/115/37 +f 3299/117/38 3297/115/38 3316/116/38 +f 3316/116/38 3317/118/38 3299/117/38 +f 3301/119/39 3299/117/39 3317/118/39 +f 3317/118/39 3318/120/39 3301/119/39 +f 3303/121/28 3301/119/28 3318/120/28 +f 3318/120/28 3319/122/28 3303/121/28 +f 3305/123/29 3303/121/29 3319/122/29 +f 3319/122/29 3320/124/29 3305/123/29 +f 3307/125/30 3305/123/30 3320/124/30 +f 3320/124/30 3321/126/30 3307/125/30 +f 3309/127/31 3307/128/31 3321/129/31 +f 3321/129/31 3322/130/31 3309/127/31 +f 3311/131/32 3309/127/32 3322/130/32 +f 3322/130/32 3323/132/32 3311/131/32 +f 3290/108/33 3311/131/33 3323/132/33 +f 3323/132/33 3312/109/33 3290/108/33 +f 3313/110/48 3312/109/48 3324/133/48 +f 3324/133/48 3325/134/48 3313/110/48 +f 3314/112/49 3313/110/49 3325/134/49 +f 3325/134/49 3326/135/49 3314/112/49 +f 3315/114/50 3314/112/50 3326/135/50 +f 3326/135/50 3327/136/50 3315/114/50 +f 3316/116/51 3315/114/51 3327/136/52 +f 3327/136/52 3328/137/51 3316/116/51 +f 3317/118/53 3316/116/53 3328/137/53 +f 3328/137/53 3329/138/53 3317/118/53 +f 3318/120/54 3317/118/54 3329/138/54 +f 3329/138/54 3330/139/54 3318/120/54 +f 3319/122/386 3318/120/40 3330/139/40 +f 3330/139/40 3331/140/40 3319/122/386 +f 3320/124/41 3319/122/41 3331/140/41 +f 3331/140/41 3332/141/41 3320/124/41 +f 3321/126/42 3320/124/42 3332/141/42 +f 3332/141/42 3333/142/43 3321/126/42 +f 3322/130/44 3321/129/44 3333/143/44 +f 3333/143/44 3334/144/44 3322/130/44 +f 3323/132/45 3322/130/45 3334/144/45 +f 3334/144/45 3335/145/45 3323/132/45 +f 3312/109/46 3323/132/385 3335/145/46 +f 3335/145/46 3324/133/46 3312/109/46 +f 3336/146/64 3337/147/64 3277/148/64 +f 3277/148/64 3276/149/64 3336/146/64 +f 3337/147/66 3338/150/66 3278/151/65 +f 3278/151/65 3277/148/65 3337/147/66 +f 3338/152/67 3339/153/67 3279/154/67 +f 3279/154/67 3278/155/67 3338/152/67 +f 3339/153/68 3340/142/68 3280/156/68 +f 3280/156/68 3279/154/68 3339/153/68 +f 3340/142/70 3341/157/70 3281/158/69 +f 3281/158/69 3280/156/69 3340/142/70 +f 3341/157/71 3342/159/71 3282/160/71 +f 3282/160/71 3281/158/71 3341/157/71 +f 3342/159/56 3343/161/56 3283/162/56 +f 3283/162/56 3282/160/56 3342/159/56 +f 3343/161/57 3344/163/57 3284/164/58 +f 3284/164/58 3283/162/58 3343/161/57 +f 3344/163/59 3345/165/59 3285/166/59 +f 3285/166/59 3284/164/59 3344/163/59 +f 3345/165/60 3346/167/60 3286/168/60 +f 3286/168/60 3285/166/60 3345/165/60 +f 3346/167/61 3347/169/61 3287/170/61 +f 3287/170/61 3286/168/62 3346/167/61 +f 3347/169/63 3336/146/63 3276/149/63 +f 3276/149/63 3287/170/63 3347/169/63 +f 3289/171/7 3288/172/8 3337/173/8 +f 3337/173/8 3336/174/7 3289/171/7 +f 3288/172/8 3292/175/9 3338/176/9 +f 3338/176/9 3337/173/8 3288/172/8 +f 3292/177/9 3294/178/10 3339/179/10 +f 3339/179/10 3338/180/9 3292/177/9 +f 3294/178/10 3296/86/11 3340/181/11 +f 3340/181/11 3339/179/10 3294/178/10 +f 3296/86/11 3298/182/12 3341/183/12 +f 3341/183/12 3340/181/11 3296/86/11 +f 3298/182/12 3300/184/1 3342/185/1 +f 3342/185/1 3341/183/12 3298/182/12 +f 3300/184/1 3302/186/2 3343/187/2 +f 3343/187/2 3342/185/1 3300/184/1 +f 3302/186/2 3304/188/3 3344/189/3 +f 3344/189/3 3343/187/2 3302/186/2 +f 3304/188/3 3306/190/4 3345/191/4 +f 3345/191/4 3344/189/3 3304/188/3 +f 3306/190/4 3308/76/5 3346/192/5 +f 3346/192/5 3345/191/4 3306/190/4 +f 3308/76/5 3310/193/6 3347/194/6 +f 3347/194/6 3346/192/5 3308/76/5 +f 3310/193/6 3289/171/7 3336/174/7 +f 3336/174/7 3347/194/6 3310/193/6 +f 3348/195/131 3349/196/131 3350/197/131 +f 3350/197/131 3351/198/131 3348/195/131 +f 3352/199/75 3353/200/75 3354/201/75 +f 3354/201/75 3355/202/75 3352/199/75 +f 3356/203/132 3357/204/132 3358/205/132 +f 3358/205/132 3359/206/132 3356/203/132 +f 3360/202/73 3361/201/73 3362/200/73 +f 3362/200/73 3363/199/73 3360/202/73 +f 3364/207/83 3365/207/83 3366/208/83 +f 3366/208/83 3367/209/83 3364/207/83 +f 3368/209/133 3369/210/133 3370/211/133 +f 3357/212/134 3371/196/134 3372/213/134 +f 3372/213/134 3358/214/134 3357/212/134 +f 3373/210/135 3374/209/135 3375/211/135 +f 3376/215/136 3377/216/136 3375/211/136 +f 3375/211/136 3374/209/136 3376/215/136 +f 3378/217/137 3379/218/137 3350/197/137 +f 3350/197/137 3349/196/137 3378/217/137 +f 3380/219/139 3381/220/139 3357/204/139 +f 3357/204/139 3356/203/139 3380/219/139 +f 3382/209/76 3383/208/76 3365/207/76 +f 3365/207/76 3364/207/76 3382/209/76 +f 3357/212/140 3381/214/140 3384/213/140 +f 3384/213/140 3371/196/140 3357/212/140 +f 3376/215/141 3368/209/141 3370/211/141 +f 3370/211/141 3377/216/141 3376/215/141 +f 3385/221/73 3372/222/73 3348/222/73 +f 3348/222/73 3351/221/73 3385/221/73 +f 3372/222/87 3371/203/87 3349/203/87 +f 3349/203/87 3348/222/87 3372/222/87 +f 3371/203/86 3384/206/86 3378/206/86 +f 3378/206/86 3349/203/86 3371/203/86 +f 3384/206/75 3386/223/75 3379/223/75 +f 3379/223/75 3378/206/75 3384/206/75 +f 3386/224/142 3387/225/142 3350/226/142 +f 3350/226/142 3379/224/142 3386/224/142 +f 3387/225/143 3385/224/143 3351/224/143 +f 3351/224/143 3350/226/143 3387/225/143 +f 3381/214/135 3388/227/135 3386/228/135 +f 3386/228/135 3384/213/135 3381/214/135 +f 3388/229/73 3381/220/73 3380/219/73 +f 3380/219/73 3389/221/73 3388/229/73 +f 3359/206/75 3358/205/75 3390/230/75 +f 3390/230/75 3391/223/75 3359/206/75 +f 3390/227/133 3358/214/133 3372/213/133 +f 3372/213/133 3385/228/133 3390/227/133 +f 3354/201/75 3353/200/75 3392/199/75 +f 3392/199/75 3393/202/75 3354/201/75 +f 3390/231/144 3385/224/144 3370/232/144 +f 3370/232/144 3369/233/144 3390/231/144 +f 3385/224/143 3387/225/143 3377/234/143 +f 3377/234/143 3370/232/143 3385/224/143 +f 3387/225/142 3386/224/142 3375/232/142 +f 3375/232/142 3377/234/142 3387/225/142 +f 3386/224/145 3388/231/145 3373/233/145 +f 3373/233/145 3375/232/145 3386/224/145 +f 3362/200/73 3361/201/73 3394/202/73 +f 3394/202/73 3395/199/73 3362/200/73 +f 3366/208/83 3365/207/83 3376/235/83 +f 3376/235/83 3374/236/83 3366/208/83 +f 3365/207/76 3383/208/76 3368/236/76 +f 3368/236/76 3376/235/76 3365/207/76 +f 3391/236/27 3390/231/27 3353/237/27 +f 3353/237/27 3352/238/27 3391/236/27 +f 3390/231/27 3369/233/27 3392/239/27 +f 3392/239/27 3353/237/27 3390/231/27 +f 3369/210/480 3368/209/480 3393/240/480 +f 3393/240/480 3392/241/480 3369/210/480 +f 3368/236/26 3383/208/26 3354/242/26 +f 3354/242/26 3393/238/26 3368/236/26 +f 3383/208/26 3382/209/26 3355/240/26 +f 3355/240/26 3354/242/26 3383/208/26 +f 3367/209/26 3366/208/26 3361/242/26 +f 3361/242/26 3360/240/26 3367/209/26 +f 3366/208/26 3374/236/26 3394/238/26 +f 3394/238/26 3361/242/26 3366/208/26 +f 3374/209/147 3373/210/147 3395/241/147 +f 3395/241/147 3394/240/147 3374/209/147 +f 3373/233/27 3388/231/27 3362/237/27 +f 3362/237/27 3395/239/27 3373/233/27 +f 3388/231/27 3389/236/27 3363/238/27 +f 3363/238/27 3362/237/27 3388/231/27 +f 3396/195/10 3397/196/10 3398/197/10 +f 3398/197/10 3399/198/10 3396/195/10 +f 3400/199/101 3401/200/100 3402/201/100 +f 3402/201/100 3403/202/101 3400/199/101 +f 3404/203/108 3405/204/108 3406/205/108 +f 3406/205/108 3407/206/108 3404/203/108 +f 3408/202/98 3409/201/97 3410/200/97 +f 3410/200/97 3411/199/98 3408/202/98 +f 3412/207/166 3413/207/166 3414/208/166 +f 3414/208/166 3415/209/166 3412/207/166 +f 3416/209/167 3417/210/167 3418/211/167 +f 3405/212/168 3419/196/168 3420/213/168 +f 3420/213/168 3406/214/168 3405/212/168 +f 3421/210/169 3422/209/169 3423/211/169 +f 3424/215/170 3425/216/170 3423/211/170 +f 3423/211/170 3422/209/170 3424/215/170 +f 3426/217/171 3427/218/171 3398/197/171 +f 3398/197/171 3397/196/171 3426/217/171 +f 3428/219/99 3429/220/99 3405/204/99 +f 3405/204/99 3404/203/99 3428/219/99 +f 3430/209/173 3431/208/173 3413/207/173 +f 3413/207/173 3412/207/173 3430/209/173 +f 3405/212/174 3429/214/174 3432/213/174 +f 3432/213/174 3419/196/174 3405/212/174 +f 3424/215/175 3416/209/175 3418/211/175 +f 3418/211/175 3425/216/175 3424/215/175 +f 3433/221/98 3420/222/98 3396/222/97 +f 3396/222/97 3399/221/97 3433/221/98 +f 3420/222/113 3419/203/113 3397/203/113 +f 3397/203/113 3396/222/113 3420/222/113 +f 3419/203/112 3432/206/112 3426/206/112 +f 3426/206/112 3397/203/112 3419/203/112 +f 3432/206/100 3434/223/100 3427/223/100 +f 3427/223/100 3426/206/100 3432/206/100 +f 3434/224/176 3435/225/176 3398/226/176 +f 3398/226/176 3427/224/176 3434/224/176 +f 3435/225/117 3433/224/117 3399/224/117 +f 3399/224/117 3398/226/117 3435/225/117 +f 3429/214/169 3436/227/169 3434/228/169 +f 3434/228/169 3432/213/169 3429/214/169 +f 3436/229/98 3429/220/98 3428/219/98 +f 3428/219/98 3437/221/98 3436/229/98 +f 3407/206/100 3406/205/100 3438/230/100 +f 3438/230/100 3439/223/100 3407/206/100 +f 3438/227/167 3406/214/167 3420/213/167 +f 3420/213/167 3433/228/167 3438/227/167 +f 3402/201/100 3401/200/100 3440/199/101 +f 3440/199/101 3441/202/101 3402/201/100 +f 3438/231/481 3433/224/481 3418/232/481 +f 3418/232/481 3417/233/481 3438/231/481 +f 3433/224/117 3435/225/117 3425/234/117 +f 3425/234/117 3418/232/117 3433/224/117 +f 3435/225/176 3434/224/176 3423/232/176 +f 3423/232/176 3425/234/176 3435/225/176 +f 3434/224/115 3436/231/115 3421/233/115 +f 3421/233/115 3423/232/115 3434/224/115 +f 3410/200/97 3409/201/97 3442/202/98 +f 3442/202/98 3443/199/98 3410/200/97 +f 3414/208/166 3413/207/166 3424/235/166 +f 3424/235/166 3422/236/166 3414/208/166 +f 3413/207/173 3431/208/173 3416/236/173 +f 3416/236/173 3424/235/173 3413/207/173 +f 3439/236/27 3438/231/27 3401/237/27 +f 3401/237/27 3400/238/27 3439/236/27 +f 3438/231/27 3417/233/27 3440/239/27 +f 3440/239/27 3401/237/27 3438/231/27 +f 3417/210/178 3416/209/178 3441/240/178 +f 3441/240/178 3440/241/178 3417/210/178 +f 3416/236/26 3431/208/26 3402/242/26 +f 3402/242/26 3441/238/26 3416/236/26 +f 3431/208/26 3430/209/26 3403/240/26 +f 3403/240/26 3402/242/26 3431/208/26 +f 3415/209/26 3414/208/26 3409/242/26 +f 3409/242/26 3408/240/26 3415/209/26 +f 3414/208/26 3422/236/26 3442/238/26 +f 3442/238/26 3409/242/26 3414/208/26 +f 3422/209/179 3421/210/179 3443/241/179 +f 3443/241/179 3442/240/179 3422/209/179 +f 3421/233/27 3436/231/27 3410/237/27 +f 3410/237/27 3443/239/27 3421/233/27 +f 3436/231/27 3437/236/27 3411/238/27 +f 3411/238/27 3410/237/27 3436/231/27 +f 3444/243/183 3445/244/183 3446/245/183 +f 3446/245/183 3447/246/183 3444/243/183 +f 3444/247/184 3447/248/184 3448/249/184 +f 3448/249/184 3449/250/184 3444/247/184 +f 3447/246/185 3446/245/185 3450/251/185 +f 3450/251/185 3448/252/185 3447/246/185 +f 3446/248/186 3445/247/186 3451/250/186 +f 3451/250/186 3450/249/186 3446/248/186 +f 3452/195/164 3453/196/164 3454/197/164 +f 3454/197/164 3455/198/164 3452/195/164 +f 3456/199/101 3457/200/100 3458/201/100 +f 3458/201/100 3459/202/101 3456/199/101 +f 3460/203/108 3461/204/108 3462/205/108 +f 3462/205/108 3463/206/108 3460/203/108 +f 3464/202/98 3465/201/97 3466/200/97 +f 3466/200/97 3467/199/98 3464/202/98 +f 3468/207/166 3469/207/166 3470/208/166 +f 3470/208/166 3471/209/166 3468/207/166 +f 3472/209/167 3473/210/167 3474/211/167 +f 3461/212/168 3475/196/168 3476/213/168 +f 3476/213/168 3462/214/168 3461/212/168 +f 3477/210/169 3478/209/169 3479/211/169 +f 3480/215/170 3481/216/170 3479/211/170 +f 3479/211/170 3478/209/170 3480/215/170 +f 3482/217/171 3483/218/171 3454/197/171 +f 3454/197/171 3453/196/171 3482/217/171 +f 3484/219/172 3485/220/172 3461/204/99 +f 3461/204/99 3460/203/99 3484/219/172 +f 3486/209/173 3487/208/173 3469/207/173 +f 3469/207/173 3468/207/173 3486/209/173 +f 3461/212/174 3485/214/174 3488/213/174 +f 3488/213/174 3475/196/174 3461/212/174 +f 3480/215/175 3472/209/175 3474/211/175 +f 3474/211/175 3481/216/175 3480/215/175 +f 3489/221/98 3476/222/98 3452/222/98 +f 3452/222/98 3455/221/98 3489/221/98 +f 3476/222/113 3475/203/113 3453/203/113 +f 3453/203/113 3452/222/113 3476/222/113 +f 3475/203/112 3488/206/112 3482/206/112 +f 3482/206/112 3453/203/112 3475/203/112 +f 3488/206/100 3490/223/100 3483/223/100 +f 3483/223/100 3482/206/100 3488/206/100 +f 3490/224/176 3491/225/176 3454/226/176 +f 3454/226/176 3483/224/176 3490/224/176 +f 3491/225/117 3489/224/117 3455/224/117 +f 3455/224/117 3454/226/117 3491/225/117 +f 3485/214/169 3492/227/169 3490/228/169 +f 3490/228/169 3488/213/169 3485/214/169 +f 3492/229/125 3485/220/125 3484/219/97 +f 3484/219/97 3493/221/97 3492/229/125 +f 3463/206/100 3462/205/101 3494/230/101 +f 3494/230/101 3495/223/100 3463/206/100 +f 3494/227/167 3462/214/167 3476/213/167 +f 3476/213/167 3489/228/167 3494/227/167 +f 3458/201/100 3457/200/100 3496/199/101 +f 3496/199/101 3497/202/101 3458/201/100 +f 3494/231/481 3489/224/481 3474/232/481 +f 3474/232/481 3473/233/481 3494/231/481 +f 3489/224/117 3491/225/117 3481/234/117 +f 3481/234/117 3474/232/117 3489/224/117 +f 3491/225/176 3490/224/176 3479/232/176 +f 3479/232/176 3481/234/176 3491/225/176 +f 3490/224/115 3492/231/115 3477/233/115 +f 3477/233/115 3479/232/115 3490/224/115 +f 3466/200/97 3465/201/97 3498/202/98 +f 3498/202/98 3499/199/98 3466/200/97 +f 3470/208/166 3469/207/166 3480/235/166 +f 3480/235/166 3478/236/166 3470/208/166 +f 3469/207/173 3487/208/173 3472/236/173 +f 3472/236/173 3480/235/173 3469/207/173 +f 3495/236/27 3494/231/27 3457/237/27 +f 3457/237/27 3456/238/27 3495/236/27 +f 3494/231/27 3473/233/27 3496/239/27 +f 3496/239/27 3457/237/27 3494/231/27 +f 3473/210/178 3472/209/178 3497/240/178 +f 3497/240/178 3496/241/178 3473/210/178 +f 3472/236/26 3487/208/26 3458/242/26 +f 3458/242/26 3497/238/26 3472/236/26 +f 3487/208/26 3486/209/26 3459/240/26 +f 3459/240/26 3458/242/26 3487/208/26 +f 3471/209/26 3470/208/26 3465/242/26 +f 3465/242/26 3464/240/26 3471/209/26 +f 3470/208/26 3478/236/26 3498/238/26 +f 3498/238/26 3465/242/26 3470/208/26 +f 3478/209/179 3477/210/179 3499/241/179 +f 3499/241/179 3498/240/179 3478/209/179 +f 3477/233/27 3492/231/27 3466/237/27 +f 3466/237/27 3499/239/27 3477/233/27 +f 3492/231/27 3493/236/27 3467/238/27 +f 3467/238/27 3466/237/27 3492/231/27 +f 3500/243/156 3501/244/156 3502/245/156 +f 3502/245/156 3503/246/156 3500/243/156 +f 3500/247/157 3503/248/157 3504/249/157 +f 3504/249/157 3505/250/157 3500/247/157 +f 3503/246/158 3502/245/158 3506/251/158 +f 3506/251/158 3504/252/158 3503/246/158 +f 3502/248/159 3501/247/159 3507/250/159 +f 3507/250/159 3506/249/159 3502/248/159 +f 3508/195/72 3509/196/72 3510/197/72 +f 3510/197/72 3511/198/72 3508/195/72 +f 3512/199/73 3513/200/73 3514/201/73 +f 3514/201/73 3515/202/73 3512/199/73 +f 3516/203/74 3517/204/74 3518/205/74 +f 3518/205/74 3519/206/74 3516/203/74 +f 3520/202/75 3521/201/75 3522/200/75 +f 3522/200/75 3523/199/75 3520/202/75 +f 3524/207/76 3525/207/76 3526/208/76 +f 3526/208/76 3527/209/76 3524/207/76 +f 3528/209/77 3529/210/77 3530/211/77 +f 3517/212/78 3531/196/78 3532/213/78 +f 3532/213/78 3518/214/78 3517/212/78 +f 3533/210/79 3534/209/79 3535/211/79 +f 3536/215/80 3537/216/80 3535/211/80 +f 3535/211/80 3534/209/80 3536/215/80 +f 3538/217/81 3539/218/81 3510/197/482 +f 3510/197/482 3509/196/482 3538/217/81 +f 3540/219/82 3541/220/82 3517/204/82 +f 3517/204/82 3516/203/82 3540/219/82 +f 3542/209/83 3543/208/83 3525/207/83 +f 3525/207/83 3524/207/83 3542/209/83 +f 3517/212/84 3541/214/84 3544/213/84 +f 3544/213/84 3531/196/84 3517/212/84 +f 3536/215/85 3528/209/85 3530/211/85 +f 3530/211/85 3537/216/85 3536/215/85 +f 3545/221/75 3532/222/75 3508/222/75 +f 3508/222/75 3511/221/75 3545/221/75 +f 3532/222/86 3531/203/86 3509/203/86 +f 3509/203/86 3508/222/86 3532/222/86 +f 3531/203/87 3544/206/87 3538/206/87 +f 3538/206/87 3509/203/87 3531/203/87 +f 3544/206/73 3546/223/73 3539/223/73 +f 3539/223/73 3538/206/73 3544/206/73 +f 3546/224/88 3547/225/88 3510/226/88 +f 3510/226/88 3539/224/88 3546/224/88 +f 3547/225/89 3545/224/89 3511/224/89 +f 3511/224/89 3510/226/89 3547/225/89 +f 3541/214/79 3548/227/79 3546/228/79 +f 3546/228/79 3544/213/79 3541/214/79 +f 3548/229/75 3541/220/75 3540/219/75 +f 3540/219/75 3549/221/75 3548/229/75 +f 3519/206/73 3518/205/73 3550/230/73 +f 3550/230/73 3551/223/73 3519/206/73 +f 3550/227/77 3518/214/77 3532/213/77 +f 3532/213/77 3545/228/77 3550/227/77 +f 3514/201/73 3513/200/73 3552/199/73 +f 3552/199/73 3553/202/73 3514/201/73 +f 3550/231/90 3545/224/90 3530/232/90 +f 3530/232/90 3529/233/90 3550/231/90 +f 3545/224/89 3547/225/89 3537/234/89 +f 3537/234/89 3530/232/89 3545/224/89 +f 3547/225/88 3546/224/88 3535/232/88 +f 3535/232/88 3537/234/88 3547/225/88 +f 3546/224/92 3548/231/92 3533/233/92 +f 3533/233/92 3535/232/92 3546/224/92 +f 3522/200/75 3521/201/75 3554/202/75 +f 3554/202/75 3555/199/75 3522/200/75 +f 3526/208/76 3525/207/76 3536/235/76 +f 3536/235/76 3534/236/76 3526/208/76 +f 3525/207/83 3543/208/83 3528/236/83 +f 3528/236/83 3536/235/83 3525/207/83 +f 3551/236/27 3550/231/27 3513/237/27 +f 3513/237/27 3512/238/27 3551/236/27 +f 3550/231/27 3529/233/27 3552/239/27 +f 3552/239/27 3513/237/27 3550/231/27 +f 3529/210/94 3528/209/94 3553/240/94 +f 3553/240/94 3552/241/94 3529/210/94 +f 3528/236/26 3543/208/26 3514/242/26 +f 3514/242/26 3553/238/26 3528/236/26 +f 3543/208/26 3542/209/26 3515/240/26 +f 3515/240/26 3514/242/26 3543/208/26 +f 3527/209/26 3526/208/26 3521/242/26 +f 3521/242/26 3520/240/26 3527/209/26 +f 3526/208/26 3534/236/26 3554/238/26 +f 3554/238/26 3521/242/26 3526/208/26 +f 3534/209/95 3533/210/95 3555/241/95 +f 3555/241/95 3554/240/95 3534/209/95 +f 3533/233/27 3548/231/27 3522/237/27 +f 3522/237/27 3555/239/27 3533/233/27 +f 3548/231/27 3549/236/27 3523/238/27 +f 3523/238/27 3522/237/27 3548/231/27 +f 3556/243/154 3557/244/154 3558/245/154 +f 3558/245/154 3559/246/154 3556/243/154 +f 3556/247/7 3559/248/7 3560/249/7 +f 3560/249/7 3561/250/7 3556/247/7 +f 3559/246/155 3558/245/155 3562/251/155 +f 3562/251/155 3560/252/155 3559/246/155 +f 3558/248/1 3557/247/1 3563/250/1 +f 3563/250/1 3562/249/1 3558/248/1 +f 3564/243/180 3565/244/180 3566/245/180 +f 3566/245/180 3567/246/180 3564/243/180 +f 3564/247/153 3567/248/153 3568/249/153 +f 3568/249/153 3569/250/153 3564/247/153 +f 3567/246/181 3566/245/181 3570/251/181 +f 3570/251/181 3568/252/181 3567/246/181 +f 3566/248/151 3565/247/151 3571/250/151 +f 3571/250/151 3570/249/151 3566/248/151 +f 3572/243/148 3573/244/148 3574/245/148 +f 3574/245/148 3575/246/148 3572/243/148 +f 3572/247/1 3575/248/1 3576/249/1 +f 3576/249/1 3577/250/1 3572/247/1 +f 3575/246/149 3574/245/149 3578/251/149 +f 3578/251/149 3576/252/149 3575/246/149 +f 3574/248/7 3573/247/7 3579/250/7 +f 3579/250/7 3578/249/7 3574/248/7 +f 3580/243/127 3581/244/127 3582/245/127 +f 3582/245/127 3583/246/127 3580/243/127 +f 3580/247/128 3583/248/128 3584/249/128 +f 3584/249/128 3585/250/128 3580/247/128 +f 3583/246/129 3582/245/129 3586/251/129 +f 3586/251/129 3584/252/129 3583/246/129 +f 3582/248/130 3581/247/130 3587/250/130 +f 3587/250/130 3586/249/130 3582/248/130 +f 3588/243/187 3589/244/187 3590/245/187 +f 3590/245/187 3591/246/187 3588/243/187 +f 3588/247/163 3591/248/163 3592/249/163 +f 3592/249/163 3593/250/163 3588/247/163 +f 3591/246/188 3590/245/188 3594/251/188 +f 3594/251/188 3592/252/188 3591/246/188 +f 3590/248/161 3589/247/161 3595/250/161 +f 3595/250/161 3594/249/161 3590/248/161 +f 3596/195/72 3597/196/72 3598/197/72 +f 3598/197/72 3599/198/72 3596/195/72 +f 3600/199/73 3601/200/73 3602/201/73 +f 3602/201/73 3603/202/73 3600/199/73 +f 3604/203/74 3605/204/74 3606/205/74 +f 3606/205/74 3607/206/74 3604/203/74 +f 3608/202/75 3609/201/75 3610/200/75 +f 3610/200/75 3611/199/75 3608/202/75 +f 3612/207/76 3613/207/76 3614/208/76 +f 3614/208/76 3615/209/76 3612/207/76 +f 3616/209/77 3617/210/77 3618/211/77 +f 3605/212/78 3619/196/78 3620/213/78 +f 3620/213/78 3606/214/78 3605/212/78 +f 3621/210/79 3622/209/79 3623/211/79 +f 3624/215/80 3625/216/80 3623/211/80 +f 3623/211/80 3622/209/80 3624/215/80 +f 3626/217/81 3627/218/81 3598/197/482 +f 3598/197/482 3597/196/482 3626/217/81 +f 3628/219/82 3629/220/82 3605/204/82 +f 3605/204/82 3604/203/82 3628/219/82 +f 3630/209/83 3631/208/83 3613/207/83 +f 3613/207/83 3612/207/83 3630/209/83 +f 3605/212/84 3629/214/84 3632/213/84 +f 3632/213/84 3619/196/84 3605/212/84 +f 3624/215/85 3616/209/85 3618/211/85 +f 3618/211/85 3625/216/85 3624/215/85 +f 3633/221/75 3620/222/75 3596/222/75 +f 3596/222/75 3599/221/75 3633/221/75 +f 3620/222/86 3619/203/86 3597/203/86 +f 3597/203/86 3596/222/86 3620/222/86 +f 3619/203/87 3632/206/87 3626/206/87 +f 3626/206/87 3597/203/87 3619/203/87 +f 3632/206/73 3634/223/73 3627/223/73 +f 3627/223/73 3626/206/73 3632/206/73 +f 3634/224/88 3635/225/88 3598/226/88 +f 3598/226/88 3627/224/88 3634/224/88 +f 3635/225/89 3633/224/89 3599/224/89 +f 3599/224/89 3598/226/89 3635/225/89 +f 3629/214/79 3636/227/79 3634/228/79 +f 3634/228/79 3632/213/79 3629/214/79 +f 3636/229/75 3629/220/75 3628/219/75 +f 3628/219/75 3637/221/75 3636/229/75 +f 3607/206/73 3606/205/73 3638/230/73 +f 3638/230/73 3639/223/73 3607/206/73 +f 3638/227/77 3606/214/77 3620/213/77 +f 3620/213/77 3633/228/77 3638/227/77 +f 3602/201/73 3601/200/73 3640/199/73 +f 3640/199/73 3641/202/73 3602/201/73 +f 3638/231/90 3633/224/90 3618/232/90 +f 3618/232/90 3617/233/90 3638/231/90 +f 3633/224/89 3635/225/89 3625/234/89 +f 3625/234/89 3618/232/89 3633/224/89 +f 3635/225/88 3634/224/88 3623/232/88 +f 3623/232/88 3625/234/88 3635/225/88 +f 3634/224/92 3636/231/92 3621/233/92 +f 3621/233/92 3623/232/92 3634/224/92 +f 3610/200/75 3609/201/75 3642/202/75 +f 3642/202/75 3643/199/75 3610/200/75 +f 3614/208/76 3613/207/76 3624/235/76 +f 3624/235/76 3622/236/76 3614/208/76 +f 3613/207/83 3631/208/83 3616/236/83 +f 3616/236/83 3624/235/83 3613/207/83 +f 3639/236/27 3638/231/27 3601/237/27 +f 3601/237/27 3600/238/27 3639/236/27 +f 3638/231/27 3617/233/27 3640/239/27 +f 3640/239/27 3601/237/27 3638/231/27 +f 3617/210/94 3616/209/94 3641/240/94 +f 3641/240/94 3640/241/94 3617/210/94 +f 3616/236/26 3631/208/26 3602/242/26 +f 3602/242/26 3641/238/26 3616/236/26 +f 3631/208/26 3630/209/26 3603/240/26 +f 3603/240/26 3602/242/26 3631/208/26 +f 3615/209/26 3614/208/26 3609/242/26 +f 3609/242/26 3608/240/26 3615/209/26 +f 3614/208/26 3622/236/26 3642/238/26 +f 3642/238/26 3609/242/26 3614/208/26 +f 3622/209/95 3621/210/95 3643/241/95 +f 3643/241/95 3642/240/95 3622/209/95 +f 3621/233/27 3636/231/27 3610/237/27 +f 3610/237/27 3643/239/27 3621/233/27 +f 3636/231/27 3637/236/27 3611/238/27 +f 3611/238/27 3610/237/27 3636/231/27 +f 3644/195/124 3645/196/96 3646/197/96 +f 3646/197/96 3647/198/124 3644/195/124 +f 3648/199/125 3649/200/125 3650/201/125 +f 3650/201/125 3651/202/125 3648/199/125 +f 3652/203/99 3653/204/99 3654/205/99 +f 3654/205/99 3655/206/99 3652/203/99 +f 3656/202/165 3657/201/165 3658/200/165 +f 3658/200/165 3659/199/165 3656/202/165 +f 3660/207/102 3661/207/102 3662/208/102 +f 3662/208/102 3663/209/102 3660/207/102 +f 3664/209/103 3665/210/103 3666/211/103 +f 3653/212/104 3667/196/104 3668/213/104 +f 3668/213/104 3654/214/104 3653/212/104 +f 3669/210/105 3670/209/105 3671/211/105 +f 3672/215/106 3673/216/106 3671/211/106 +f 3671/211/106 3670/209/106 3672/215/106 +f 3674/217/107 3675/218/107 3646/197/107 +f 3646/197/107 3645/196/107 3674/217/107 +f 3676/219/126 3677/220/108 3653/204/108 +f 3653/204/108 3652/203/108 3676/219/126 +f 3678/209/109 3679/208/109 3661/207/109 +f 3661/207/109 3660/207/109 3678/209/109 +f 3653/212/110 3677/214/110 3680/213/110 +f 3680/213/110 3667/196/110 3653/212/110 +f 3672/215/111 3664/209/111 3666/211/111 +f 3666/211/111 3673/216/111 3672/215/111 +f 3681/221/165 3668/222/165 3644/222/165 +f 3644/222/165 3647/221/165 3681/221/165 +f 3668/222/112 3667/203/112 3645/203/112 +f 3645/203/112 3644/222/112 3668/222/112 +f 3667/203/113 3680/206/113 3674/206/113 +f 3674/206/113 3645/203/113 3667/203/113 +f 3680/206/125 3682/223/125 3675/223/125 +f 3675/223/125 3674/206/125 3680/206/125 +f 3682/224/114 3683/225/114 3646/226/114 +f 3646/226/114 3675/224/114 3682/224/114 +f 3683/225/115 3681/224/115 3647/224/115 +f 3647/224/115 3646/226/115 3683/225/115 +f 3677/214/105 3684/227/105 3682/228/105 +f 3682/228/105 3680/213/105 3677/214/105 +f 3684/229/165 3677/220/165 3676/219/165 +f 3676/219/165 3685/221/165 3684/229/165 +f 3655/206/125 3654/205/125 3686/230/125 +f 3686/230/125 3687/223/125 3655/206/125 +f 3686/227/103 3654/214/103 3668/213/103 +f 3668/213/103 3681/228/103 3686/227/103 +f 3650/201/125 3649/200/125 3688/199/125 +f 3688/199/125 3689/202/125 3650/201/125 +f 3686/231/483 3681/224/483 3666/232/483 +f 3666/232/483 3665/233/483 3686/231/483 +f 3681/224/115 3683/225/115 3673/234/115 +f 3673/234/115 3666/232/115 3681/224/115 +f 3683/225/114 3682/224/114 3671/232/114 +f 3671/232/114 3673/234/114 3683/225/114 +f 3682/224/117 3684/231/117 3669/233/117 +f 3669/233/117 3671/232/117 3682/224/117 +f 3658/200/165 3657/201/165 3690/202/165 +f 3690/202/165 3691/199/165 3658/200/165 +f 3662/208/102 3661/207/102 3672/235/102 +f 3672/235/102 3670/236/102 3662/208/102 +f 3661/207/109 3679/208/109 3664/236/109 +f 3664/236/109 3672/235/109 3661/207/109 +f 3687/236/27 3686/231/27 3649/237/27 +f 3649/237/27 3648/238/27 3687/236/27 +f 3686/231/27 3665/233/27 3688/239/27 +f 3688/239/27 3649/237/27 3686/231/27 +f 3665/210/118 3664/209/118 3689/240/118 +f 3689/240/118 3688/241/118 3665/210/118 +f 3664/236/26 3679/208/26 3650/242/26 +f 3650/242/26 3689/238/26 3664/236/26 +f 3679/208/26 3678/209/26 3651/240/26 +f 3651/240/26 3650/242/26 3679/208/26 +f 3663/209/26 3662/208/26 3657/242/26 +f 3657/242/26 3656/240/26 3663/209/26 +f 3662/208/26 3670/236/26 3690/238/26 +f 3690/238/26 3657/242/26 3662/208/26 +f 3670/209/119 3669/210/119 3691/241/119 +f 3691/241/119 3690/240/119 3670/209/119 +f 3669/233/27 3684/231/27 3658/237/27 +f 3658/237/27 3691/239/27 3669/233/27 +f 3684/231/27 3685/236/27 3659/238/27 +f 3659/238/27 3658/237/27 3684/231/27 +f 3692/243/150 3693/244/150 3694/245/150 +f 3694/245/150 3695/246/150 3692/243/150 +f 3692/247/151 3695/248/151 3696/249/151 +f 3696/249/151 3697/250/151 3692/247/151 +f 3695/246/152 3694/245/152 3698/251/152 +f 3698/251/152 3696/252/152 3695/246/152 +f 3694/248/153 3693/247/153 3699/250/153 +f 3699/250/153 3698/249/153 3694/248/153 +f 3700/195/96 3701/196/124 3702/197/124 +f 3702/197/124 3703/198/96 3700/195/96 +f 3704/199/125 3705/200/125 3706/201/125 +f 3706/201/125 3707/202/125 3704/199/125 +f 3708/203/99 3709/204/99 3710/205/99 +f 3710/205/99 3711/206/99 3708/203/99 +f 3712/202/165 3713/201/165 3714/200/165 +f 3714/200/165 3715/199/165 3712/202/165 +f 3716/207/102 3717/207/102 3718/208/102 +f 3718/208/102 3719/209/102 3716/207/102 +f 3720/209/103 3721/210/103 3722/211/103 +f 3709/212/104 3723/196/104 3724/213/104 +f 3724/213/104 3710/214/104 3709/212/104 +f 3725/210/105 3726/209/105 3727/211/105 +f 3728/215/106 3729/216/106 3727/211/106 +f 3727/211/106 3726/209/106 3728/215/106 +f 3730/217/107 3731/218/107 3702/197/107 +f 3702/197/107 3701/196/107 3730/217/107 +f 3732/219/108 3733/220/108 3709/204/126 +f 3709/204/126 3708/203/108 3732/219/108 +f 3734/209/109 3735/208/109 3717/207/109 +f 3717/207/109 3716/207/109 3734/209/109 +f 3709/212/110 3733/214/110 3736/213/110 +f 3736/213/110 3723/196/110 3709/212/110 +f 3728/215/111 3720/209/111 3722/211/111 +f 3722/211/111 3729/216/111 3728/215/111 +f 3737/221/165 3724/222/165 3700/222/165 +f 3700/222/165 3703/221/165 3737/221/165 +f 3724/222/112 3723/203/112 3701/203/112 +f 3701/203/112 3700/222/112 3724/222/112 +f 3723/203/113 3736/206/113 3730/206/113 +f 3730/206/113 3701/203/113 3723/203/113 +f 3736/206/125 3738/223/125 3731/223/125 +f 3731/223/125 3730/206/125 3736/206/125 +f 3738/224/114 3739/225/114 3702/226/114 +f 3702/226/114 3731/224/114 3738/224/114 +f 3739/225/115 3737/224/115 3703/224/115 +f 3703/224/115 3702/226/115 3739/225/115 +f 3733/214/105 3740/227/105 3738/228/105 +f 3738/228/105 3736/213/105 3733/214/105 +f 3740/229/165 3733/220/165 3732/219/165 +f 3732/219/165 3741/221/165 3740/229/165 +f 3711/206/125 3710/205/125 3742/230/125 +f 3742/230/125 3743/223/125 3711/206/125 +f 3742/227/103 3710/214/103 3724/213/103 +f 3724/213/103 3737/228/103 3742/227/103 +f 3706/201/125 3705/200/125 3744/199/125 +f 3744/199/125 3745/202/125 3706/201/125 +f 3742/231/483 3737/224/483 3722/232/483 +f 3722/232/483 3721/233/483 3742/231/483 +f 3737/224/115 3739/225/115 3729/234/115 +f 3729/234/115 3722/232/115 3737/224/115 +f 3739/225/114 3738/224/114 3727/232/114 +f 3727/232/114 3729/234/114 3739/225/114 +f 3738/224/117 3740/231/117 3725/233/117 +f 3725/233/117 3727/232/117 3738/224/117 +f 3714/200/165 3713/201/165 3746/202/165 +f 3746/202/165 3747/199/165 3714/200/165 +f 3718/208/102 3717/207/102 3728/235/102 +f 3728/235/102 3726/236/102 3718/208/102 +f 3717/207/109 3735/208/109 3720/236/109 +f 3720/236/109 3728/235/109 3717/207/109 +f 3743/236/27 3742/231/27 3705/237/27 +f 3705/237/27 3704/238/27 3743/236/27 +f 3742/231/27 3721/233/27 3744/239/27 +f 3744/239/27 3705/237/27 3742/231/27 +f 3721/210/118 3720/209/118 3745/240/118 +f 3745/240/118 3744/241/118 3721/210/118 +f 3720/236/26 3735/208/26 3706/242/26 +f 3706/242/26 3745/238/26 3720/236/26 +f 3735/208/26 3734/209/26 3707/240/26 +f 3707/240/26 3706/242/26 3735/208/26 +f 3719/209/26 3718/208/26 3713/242/26 +f 3713/242/26 3712/240/26 3719/209/26 +f 3718/208/26 3726/236/26 3746/238/26 +f 3746/238/26 3713/242/26 3718/208/26 +f 3726/209/119 3725/210/119 3747/241/119 +f 3747/241/119 3746/240/119 3726/209/119 +f 3725/233/27 3740/231/27 3714/237/27 +f 3714/237/27 3747/239/27 3725/233/27 +f 3740/231/27 3741/236/27 3715/238/27 +f 3715/238/27 3714/237/27 3740/231/27 +f 3748/243/120 3749/244/120 3750/245/120 +f 3750/245/120 3751/246/120 3748/243/120 +f 3748/247/121 3751/248/121 3752/249/121 +f 3752/249/121 3753/250/121 3748/247/121 +f 3751/246/122 3750/245/122 3754/251/122 +f 3754/251/122 3752/252/122 3751/246/122 +f 3750/248/123 3749/247/123 3755/250/123 +f 3755/250/123 3754/249/123 3750/248/123 +f 3756/195/131 3757/196/131 3758/197/131 +f 3758/197/131 3759/198/131 3756/195/131 +f 3760/199/75 3761/200/75 3762/201/75 +f 3762/201/75 3763/202/75 3760/199/75 +f 3764/203/132 3765/204/132 3766/205/132 +f 3766/205/132 3767/206/132 3764/203/132 +f 3768/202/73 3769/201/73 3770/200/73 +f 3770/200/73 3771/199/73 3768/202/73 +f 3772/207/83 3773/207/83 3774/208/83 +f 3774/208/83 3775/209/83 3772/207/83 +f 3776/209/133 3777/210/133 3778/211/133 +f 3765/212/134 3779/196/134 3780/213/134 +f 3780/213/134 3766/214/134 3765/212/134 +f 3781/210/135 3782/209/135 3783/211/135 +f 3784/215/136 3785/216/136 3783/211/136 +f 3783/211/136 3782/209/136 3784/215/136 +f 3786/217/137 3787/218/137 3758/197/137 +f 3758/197/137 3757/196/137 3786/217/137 +f 3788/219/139 3789/220/139 3765/204/139 +f 3765/204/139 3764/203/139 3788/219/139 +f 3790/209/76 3791/208/76 3773/207/76 +f 3773/207/76 3772/207/76 3790/209/76 +f 3765/212/140 3789/214/140 3792/213/140 +f 3792/213/140 3779/196/140 3765/212/140 +f 3784/215/141 3776/209/141 3778/211/141 +f 3778/211/141 3785/216/141 3784/215/141 +f 3793/221/73 3780/222/73 3756/222/73 +f 3756/222/73 3759/221/73 3793/221/73 +f 3780/222/87 3779/203/87 3757/203/87 +f 3757/203/87 3756/222/87 3780/222/87 +f 3779/203/86 3792/206/86 3786/206/86 +f 3786/206/86 3757/203/86 3779/203/86 +f 3792/206/75 3794/223/75 3787/223/75 +f 3787/223/75 3786/206/75 3792/206/75 +f 3794/224/142 3795/225/142 3758/226/142 +f 3758/226/142 3787/224/142 3794/224/142 +f 3795/225/143 3793/224/143 3759/224/143 +f 3759/224/143 3758/226/143 3795/225/143 +f 3789/214/135 3796/227/135 3794/228/135 +f 3794/228/135 3792/213/135 3789/214/135 +f 3796/229/73 3789/220/73 3788/219/73 +f 3788/219/73 3797/221/73 3796/229/73 +f 3767/206/75 3766/205/75 3798/230/75 +f 3798/230/75 3799/223/75 3767/206/75 +f 3798/227/133 3766/214/133 3780/213/133 +f 3780/213/133 3793/228/133 3798/227/133 +f 3762/201/75 3761/200/75 3800/199/75 +f 3800/199/75 3801/202/75 3762/201/75 +f 3798/231/144 3793/224/144 3778/232/144 +f 3778/232/144 3777/233/144 3798/231/144 +f 3793/224/143 3795/225/143 3785/234/143 +f 3785/234/143 3778/232/143 3793/224/143 +f 3795/225/142 3794/224/142 3783/232/142 +f 3783/232/142 3785/234/142 3795/225/142 +f 3794/224/145 3796/231/145 3781/233/145 +f 3781/233/145 3783/232/145 3794/224/145 +f 3770/200/73 3769/201/73 3802/202/73 +f 3802/202/73 3803/199/73 3770/200/73 +f 3774/208/83 3773/207/83 3784/235/83 +f 3784/235/83 3782/236/83 3774/208/83 +f 3773/207/76 3791/208/76 3776/236/76 +f 3776/236/76 3784/235/76 3773/207/76 +f 3799/236/27 3798/231/27 3761/237/27 +f 3761/237/27 3760/238/27 3799/236/27 +f 3798/231/27 3777/233/27 3800/239/27 +f 3800/239/27 3761/237/27 3798/231/27 +f 3777/210/480 3776/209/480 3801/240/480 +f 3801/240/480 3800/241/480 3777/210/480 +f 3776/236/26 3791/208/26 3762/242/26 +f 3762/242/26 3801/238/26 3776/236/26 +f 3791/208/26 3790/209/26 3763/240/26 +f 3763/240/26 3762/242/26 3791/208/26 +f 3775/209/26 3774/208/26 3769/242/26 +f 3769/242/26 3768/240/26 3775/209/26 +f 3774/208/26 3782/236/26 3802/238/26 +f 3802/238/26 3769/242/26 3774/208/26 +f 3782/209/147 3781/210/147 3803/241/147 +f 3803/241/147 3802/240/147 3782/209/147 +f 3781/233/27 3796/231/27 3770/237/27 +f 3770/237/27 3803/239/27 3781/233/27 +f 3796/231/27 3797/236/27 3771/238/27 +f 3771/238/27 3770/237/27 3796/231/27 +f 3804/243/160 3805/244/160 3806/245/160 +f 3806/245/160 3807/246/160 3804/243/160 +f 3804/247/161 3807/248/161 3808/249/161 +f 3808/249/161 3809/250/161 3804/247/161 +f 3807/246/162 3806/245/162 3810/251/162 +f 3810/251/162 3808/252/162 3807/246/162 +f 3806/248/163 3805/247/163 3811/250/163 +f 3811/250/163 3810/249/163 3806/248/163 +f 3812/253/19 3813/254/19 3814/255/19 +f 3814/255/19 3815/256/19 3812/253/19 +f 3816/257/20 3812/253/20 3815/256/20 +f 3815/256/20 3817/258/20 3816/257/20 +f 3818/259/21 3816/257/21 3817/258/21 +f 3817/258/21 3819/260/21 3818/259/21 +f 3820/261/22 3818/262/191 3819/263/22 +f 3819/263/22 3821/264/22 3820/261/22 +f 3822/265/23 3820/261/23 3821/264/23 +f 3821/264/23 3823/266/23 3822/265/23 +f 3824/267/24 3822/265/24 3823/266/24 +f 3823/266/24 3825/268/24 3824/267/24 +f 3826/269/192 3824/267/13 3825/268/13 +f 3825/268/13 3827/270/192 3826/269/192 +f 3828/271/14 3826/269/14 3827/270/14 +f 3827/270/14 3829/272/14 3828/271/14 +f 3830/273/118 3828/271/15 3829/272/15 +f 3829/272/15 3831/274/15 3830/273/118 +f 3832/275/16 3830/273/16 3831/274/16 +f 3831/274/16 3833/276/16 3832/275/16 +f 3834/277/17 3832/275/17 3833/276/17 +f 3833/276/17 3835/278/17 3834/277/17 +f 3813/254/18 3834/277/194 3835/278/194 +f 3835/278/194 3814/255/18 3813/254/18 +f 3815/279/27 3814/280/27 3836/281/27 +f 3836/281/27 3837/282/27 3815/279/27 +f 3838/283/27 3839/279/27 3840/282/27 +f 3840/282/27 3841/284/27 3838/283/27 +f 3819/285/27 3817/283/27 3842/284/27 +f 3842/284/27 3843/285/27 3819/285/27 +f 3844/286/27 3845/285/27 3846/285/27 +f 3846/285/27 3847/287/27 3844/286/27 +f 3823/288/27 3821/286/27 3848/287/27 +f 3848/287/27 3849/289/27 3823/288/27 +f 3850/290/27 3851/288/27 3852/289/27 +f 3852/289/27 3853/291/27 3850/290/27 +f 3827/292/27 3825/290/27 3854/291/27 +f 3854/291/27 3855/293/27 3827/292/27 +f 3856/294/27 3857/292/27 3858/293/27 +f 3858/293/27 3859/295/27 3856/294/27 +f 3831/296/27 3829/294/27 3860/295/27 +f 3860/295/27 3861/297/27 3831/296/27 +f 3862/298/27 3863/296/27 3864/297/27 +f 3864/297/27 3865/299/27 3862/298/27 +f 3835/300/27 3833/298/27 3866/299/27 +f 3866/299/27 3867/300/27 3835/300/27 +f 3868/280/27 3869/300/27 3870/300/27 +f 3870/300/27 3871/281/27 3868/280/27 +f 3837/301/13 3836/302/13 3872/303/13 +f 3872/303/13 3873/304/13 3837/301/13 +f 3842/305/14 3837/301/14 3873/304/14 +f 3873/304/14 3874/306/14 3842/305/14 +f 3843/307/15 3842/305/118 3874/306/15 +f 3874/306/15 3875/308/15 3843/307/15 +f 3848/309/16 3843/307/16 3875/308/16 +f 3875/308/16 3876/310/16 3848/309/16 +f 3849/311/17 3848/309/17 3876/310/17 +f 3876/310/17 3877/312/17 3849/311/17 +f 3854/313/18 3849/311/18 3877/312/18 +f 3877/312/18 3878/314/18 3854/313/18 +f 3855/315/190 3854/313/19 3878/314/19 +f 3878/314/19 3879/316/190 3855/315/190 +f 3860/317/20 3855/315/20 3879/316/20 +f 3879/316/20 3880/318/20 3860/317/20 +f 3861/319/21 3860/317/21 3880/318/21 +f 3880/318/21 3881/320/21 3861/319/21 +f 3866/321/191 3861/322/22 3881/323/22 +f 3881/323/22 3882/324/22 3866/321/191 +f 3867/325/23 3866/321/23 3882/324/23 +f 3882/324/23 3883/326/23 3867/325/23 +f 3836/302/24 3867/325/25 3883/326/25 +f 3883/326/25 3872/303/24 3836/302/24 +f 3873/327/27 3872/328/27 3884/329/27 +f 3874/330/27 3873/327/27 3884/329/27 +f 3875/331/27 3874/330/27 3884/329/27 +f 3876/332/27 3875/331/27 3884/329/27 +f 3877/333/27 3876/332/27 3884/329/27 +f 3878/334/27 3877/333/27 3884/329/27 +f 3879/335/27 3878/334/27 3884/329/27 +f 3880/336/27 3879/335/27 3884/329/27 +f 3881/337/27 3880/336/27 3884/329/27 +f 3882/338/27 3881/337/27 3884/329/27 +f 3883/339/27 3882/338/27 3884/329/27 +f 3872/328/27 3883/339/27 3884/329/27 +f 3817/258/20 3815/256/20 3839/340/20 +f 3839/340/20 3838/341/20 3817/258/20 +f 3815/279/163 3837/282/163 3840/282/163 +f 3840/282/163 3839/279/163 3815/279/163 +f 3837/301/14 3842/305/14 3841/342/14 +f 3841/342/14 3840/343/14 3837/301/14 +f 3842/284/197 3817/283/197 3838/283/197 +f 3838/283/197 3841/284/197 3842/284/197 +f 3821/264/22 3819/263/22 3845/344/22 +f 3845/344/22 3844/345/22 3821/264/22 +f 3819/285/7 3843/285/7 3846/285/7 +f 3846/285/7 3845/285/7 3819/285/7 +f 3843/307/16 3848/309/16 3847/346/16 +f 3847/346/16 3846/347/16 3843/307/16 +f 3848/287/198 3821/286/198 3844/286/198 +f 3844/286/198 3847/287/198 3848/287/198 +f 3825/268/24 3823/266/24 3851/348/24 +f 3851/348/24 3850/349/24 3825/268/24 +f 3823/288/151 3849/289/151 3852/289/151 +f 3852/289/151 3851/288/151 3823/288/151 +f 3849/311/18 3854/313/18 3853/350/18 +f 3853/350/18 3852/351/18 3849/311/18 +f 3854/291/4 3825/290/4 3850/290/4 +f 3850/290/4 3853/291/4 3854/291/4 +f 3829/272/14 3827/270/14 3857/352/14 +f 3857/352/14 3856/353/14 3829/272/14 +f 3827/292/161 3855/293/161 3858/293/161 +f 3858/293/161 3857/292/161 3827/292/161 +f 3855/315/20 3860/317/20 3859/354/20 +f 3859/354/20 3858/355/20 3855/315/20 +f 3860/295/195 3829/294/195 3856/294/195 +f 3856/294/195 3859/295/195 3860/295/195 +f 3833/276/16 3831/274/16 3863/356/193 +f 3863/356/193 3862/357/16 3833/276/16 +f 3831/296/1 3861/297/1 3864/297/1 +f 3864/297/1 3863/296/1 3831/296/1 +f 3861/322/22 3866/321/191 3865/358/22 +f 3865/358/22 3864/359/22 3861/322/22 +f 3866/299/196 3833/298/196 3862/298/196 +f 3862/298/196 3865/299/196 3866/299/196 +f 3814/255/18 3835/278/194 3869/360/18 +f 3869/360/18 3868/361/18 3814/255/18 +f 3835/300/153 3867/300/153 3870/300/153 +f 3870/300/153 3869/300/153 3835/300/153 +f 3867/325/25 3836/302/24 3871/362/24 +f 3871/362/24 3870/363/25 3867/325/25 +f 3836/281/10 3814/280/10 3868/280/10 +f 3868/280/10 3871/281/10 3836/281/10 +f 3885/3/6 3886/2/6 3887/1/7 +f 3887/1/7 3888/4/7 3885/3/6 +f 3889/6/5 3890/5/5 3886/2/6 +f 3886/2/6 3885/3/6 3889/6/5 +f 3891/8/4 3892/7/4 3890/5/5 +f 3890/5/5 3889/6/5 3891/8/4 +f 3893/11/3 3894/10/3 3892/9/4 +f 3892/9/4 3891/12/4 3893/11/3 +f 3895/14/2 3896/13/2 3894/10/3 +f 3894/10/3 3893/11/3 3895/14/2 +f 3897/16/1 3898/15/1 3896/13/2 +f 3896/13/2 3895/14/2 3897/16/1 +f 3899/18/12 3900/17/12 3898/15/1 +f 3898/15/1 3897/16/1 3899/18/12 +f 3901/20/11 3902/19/11 3900/17/12 +f 3900/17/12 3899/18/12 3901/20/11 +f 3903/22/10 3904/21/10 3902/19/11 +f 3902/19/11 3901/20/11 3903/22/10 +f 3905/24/9 3906/23/9 3904/21/10 +f 3904/21/10 3903/22/10 3905/24/9 +f 3907/26/8 3908/25/8 3906/23/9 +f 3906/23/9 3905/24/9 3907/26/8 +f 3888/4/7 3887/1/7 3908/25/8 +f 3908/25/8 3907/26/8 3888/4/7 +f 3909/27/18 3910/30/18 3911/29/18 +f 3911/29/18 3912/28/18 3909/27/18 +f 3913/31/17 3914/32/17 3910/30/17 +f 3910/30/17 3909/27/17 3913/31/17 +f 3915/33/16 3916/34/16 3914/32/16 +f 3914/32/16 3913/31/16 3915/33/16 +f 3917/35/15 3918/38/15 3916/37/15 +f 3916/37/15 3915/36/15 3917/35/15 +f 3919/39/14 3920/40/14 3918/38/14 +f 3918/38/14 3917/35/14 3919/39/14 +f 3921/41/13 3922/42/13 3920/40/13 +f 3920/40/13 3919/39/13 3921/41/13 +f 3923/43/24 3924/44/24 3922/42/24 +f 3922/42/24 3921/41/24 3923/43/24 +f 3925/45/23 3926/46/23 3924/44/23 +f 3924/44/23 3923/43/23 3925/45/23 +f 3927/47/22 3928/48/22 3926/46/22 +f 3926/46/22 3925/45/22 3927/47/22 +f 3929/49/21 3930/50/21 3928/48/21 +f 3928/48/21 3927/47/21 3929/49/21 +f 3931/51/20 3932/52/20 3930/50/20 +f 3930/50/20 3929/49/20 3931/51/20 +f 3912/28/19 3911/29/19 3932/52/19 +f 3932/52/19 3931/51/190 3912/28/19 +f 3886/53/26 3909/53/26 3912/54/26 +f 3912/54/26 3887/54/26 3886/53/26 +f 3887/54/26 3912/54/26 3931/55/26 +f 3931/55/26 3908/55/26 3887/54/26 +f 3908/55/26 3931/55/26 3929/56/26 +f 3929/56/26 3906/56/26 3908/55/26 +f 3906/56/26 3929/56/26 3927/57/26 +f 3927/57/26 3904/57/26 3906/56/26 +f 3904/57/26 3927/57/26 3925/59/26 +f 3925/59/26 3902/58/26 3904/57/26 +f 3902/58/26 3925/59/26 3923/61/26 +f 3923/61/26 3900/60/26 3902/58/26 +f 3900/60/26 3923/61/26 3921/62/26 +f 3921/62/26 3898/62/26 3900/60/26 +f 3898/62/26 3921/62/26 3919/64/26 +f 3919/64/26 3896/63/26 3898/62/26 +f 3896/63/26 3919/64/26 3917/66/26 +f 3917/66/26 3894/65/26 3896/63/26 +f 3894/65/26 3917/66/26 3915/67/26 +f 3915/67/26 3892/67/26 3894/65/26 +f 3892/67/26 3915/67/26 3913/68/26 +f 3913/68/26 3890/68/26 3892/67/26 +f 3890/68/26 3913/68/26 3909/53/26 +f 3909/53/26 3886/53/26 3890/68/26 +f 3933/54/27 3911/54/27 3910/53/27 +f 3910/53/27 3934/53/27 3933/54/27 +f 3934/53/27 3910/53/27 3914/68/27 +f 3914/68/27 3935/68/27 3934/53/27 +f 3935/68/27 3914/68/27 3916/67/27 +f 3916/67/27 3936/67/27 3935/68/27 +f 3936/67/27 3916/67/27 3918/66/27 +f 3918/66/27 3937/65/27 3936/67/27 +f 3937/65/27 3918/66/27 3920/64/27 +f 3920/64/27 3938/63/27 3937/65/27 +f 3938/63/27 3920/64/27 3922/62/27 +f 3922/62/27 3939/62/27 3938/63/27 +f 3939/62/27 3922/62/27 3924/61/27 +f 3924/61/27 3940/60/27 3939/62/27 +f 3940/60/27 3924/61/27 3926/59/27 +f 3926/59/27 3941/58/27 3940/60/27 +f 3941/58/27 3926/59/27 3928/57/27 +f 3928/57/27 3942/57/27 3941/58/27 +f 3942/57/27 3928/57/27 3930/56/27 +f 3930/56/27 3943/56/27 3942/57/27 +f 3943/56/27 3930/56/27 3932/55/27 +f 3932/55/27 3944/55/27 3943/56/27 +f 3944/55/27 3932/55/27 3911/54/27 +f 3911/54/27 3933/54/27 3944/55/27 +f 3945/71/6 3946/70/7 3933/69/7 +f 3933/69/7 3934/72/6 3945/71/6 +f 3947/73/17 3945/71/6 3934/72/6 +f 3934/72/6 3935/74/17 3947/73/17 +f 3948/75/16 3947/73/16 3935/74/16 +f 3935/74/16 3936/76/16 3948/75/16 +f 3949/77/3 3948/75/15 3936/76/15 +f 3936/76/15 3937/78/3 3949/77/3 +f 3950/79/2 3949/77/3 3937/78/3 +f 3937/78/3 3938/80/2 3950/79/2 +f 3951/83/1 3950/82/2 3938/81/2 +f 3938/81/2 3939/84/1 3951/83/1 +f 3952/85/12 3951/83/1 3939/84/1 +f 3939/84/1 3940/86/12 3952/85/12 +f 3953/87/11 3952/85/12 3940/86/12 +f 3940/86/12 3941/88/11 3953/87/11 +f 3954/89/10 3953/87/11 3941/88/11 +f 3941/88/11 3942/90/10 3954/89/10 +f 3955/91/9 3954/89/10 3942/90/10 +f 3942/90/10 3943/92/9 3955/91/9 +f 3956/93/8 3955/91/9 3943/92/9 +f 3943/92/9 3944/94/8 3956/93/8 +f 3946/70/7 3956/93/8 3944/94/8 +f 3944/94/8 3933/69/7 3946/70/7 +f 3957/95/26 3958/95/26 3959/96/26 +f 3959/96/26 3960/96/26 3957/95/26 +f 3961/97/26 3962/97/26 3958/95/26 +f 3958/95/26 3957/95/26 3961/97/26 +f 3963/67/26 3964/98/26 3962/97/26 +f 3962/97/26 3961/97/26 3963/67/26 +f 3965/99/26 3966/99/26 3964/98/26 +f 3964/98/26 3963/67/26 3965/99/26 +f 3967/100/26 3968/100/26 3966/99/26 +f 3966/99/26 3965/99/26 3967/100/26 +f 3969/101/26 3970/101/26 3968/100/26 +f 3968/100/26 3967/100/26 3969/101/26 +f 3971/61/26 3972/61/26 3970/101/26 +f 3970/101/26 3969/101/26 3971/61/26 +f 3973/59/26 3974/102/26 3972/61/26 +f 3972/61/26 3971/61/26 3973/59/26 +f 3975/103/26 3976/103/26 3974/102/26 +f 3974/102/26 3973/59/26 3975/103/26 +f 3977/104/26 3978/105/26 3976/103/26 +f 3976/103/26 3975/103/26 3977/104/26 +f 3979/106/26 3980/106/26 3978/105/26 +f 3978/105/26 3977/104/26 3979/106/26 +f 3960/96/26 3959/96/26 3980/106/26 +f 3980/106/26 3979/106/26 3960/96/26 +f 3958/107/33 3981/110/33 3982/109/33 +f 3982/109/33 3959/108/33 3958/107/33 +f 3962/111/32 3983/112/32 3981/110/32 +f 3981/110/32 3958/107/32 3962/111/32 +f 3964/113/31 3984/114/31 3983/112/31 +f 3983/112/31 3962/111/31 3964/113/31 +f 3966/115/30 3985/116/30 3984/114/30 +f 3984/114/30 3964/113/30 3966/115/30 +f 3968/117/29 3986/118/29 3985/116/29 +f 3985/116/29 3966/115/29 3968/117/29 +f 3970/119/28 3987/120/28 3986/118/28 +f 3986/118/28 3968/117/28 3970/119/28 +f 3972/121/39 3988/122/39 3987/120/39 +f 3987/120/39 3970/119/39 3972/121/39 +f 3974/123/38 3989/124/38 3988/122/38 +f 3988/122/38 3972/121/38 3974/123/38 +f 3976/125/37 3990/126/37 3989/124/37 +f 3989/124/37 3974/123/37 3976/125/37 +f 3978/127/36 3991/130/36 3990/129/36 +f 3990/129/36 3976/128/36 3978/127/36 +f 3980/131/35 3992/132/35 3991/130/35 +f 3991/130/35 3978/127/35 3980/131/35 +f 3959/108/34 3982/109/34 3992/132/34 +f 3992/132/34 3980/131/34 3959/108/34 +f 3981/110/46 3993/134/46 3994/133/46 +f 3994/133/46 3982/109/46 3981/110/46 +f 3983/112/45 3995/135/45 3993/134/45 +f 3993/134/45 3981/110/45 3983/112/45 +f 3984/114/44 3996/136/44 3995/135/44 +f 3995/135/44 3983/112/44 3984/114/44 +f 3985/116/42 3997/137/42 3996/136/43 +f 3996/136/43 3984/114/42 3985/116/42 +f 3986/118/41 3998/138/41 3997/137/41 +f 3997/137/41 3985/116/41 3986/118/41 +f 3987/120/40 3999/139/40 3998/138/40 +f 3998/138/40 3986/118/40 3987/120/40 +f 3988/122/55 4000/140/54 3999/139/54 +f 3999/139/54 3987/120/54 3988/122/55 +f 3989/124/53 4001/141/53 4000/140/53 +f 4000/140/53 3988/122/53 3989/124/53 +f 3990/126/51 4002/142/52 4001/141/51 +f 4001/141/51 3989/124/51 3990/126/51 +f 3991/130/50 4003/144/50 4002/143/50 +f 4002/143/50 3990/129/50 3991/130/50 +f 3992/132/49 4004/145/49 4003/144/49 +f 4003/144/49 3991/130/49 3992/132/49 +f 3982/109/48 3994/133/48 4004/145/48 +f 4004/145/48 3992/132/47 3982/109/48 +f 3945/148/63 4005/147/63 4006/146/63 +f 4006/146/63 3946/149/63 3945/148/63 +f 3947/151/62 4007/150/61 4005/147/61 +f 4005/147/61 3945/148/62 3947/151/62 +f 3948/154/60 4008/153/60 4007/152/60 +f 4007/152/60 3947/155/60 3948/154/60 +f 3949/156/59 4009/142/59 4008/153/59 +f 4008/153/59 3948/154/59 3949/156/59 +f 3950/158/58 4010/157/57 4009/142/57 +f 4009/142/57 3949/156/58 3950/158/58 +f 3951/160/56 4011/159/56 4010/157/56 +f 4010/157/56 3950/158/56 3951/160/56 +f 3952/162/71 4012/161/71 4011/159/71 +f 4011/159/71 3951/160/71 3952/162/71 +f 3953/164/69 4013/163/70 4012/161/70 +f 4012/161/70 3952/162/69 3953/164/69 +f 3954/166/68 4014/165/68 4013/163/68 +f 4013/163/68 3953/164/68 3954/166/68 +f 3955/168/67 4015/167/67 4014/165/67 +f 4014/165/67 3954/166/67 3955/168/67 +f 3956/170/66 4016/169/66 4015/167/66 +f 4015/167/66 3955/168/65 3956/170/66 +f 3946/149/64 4006/146/64 4016/169/64 +f 4016/169/64 3956/170/64 3946/149/64 +f 4005/173/6 3957/172/6 3960/171/7 +f 3960/171/7 4006/174/7 4005/173/6 +f 4007/176/5 3961/175/5 3957/172/6 +f 3957/172/6 4005/173/6 4007/176/5 +f 4008/179/4 3963/178/4 3961/177/5 +f 3961/177/5 4007/180/5 4008/179/4 +f 4009/181/3 3965/86/3 3963/178/4 +f 3963/178/4 4008/179/4 4009/181/3 +f 4010/183/2 3967/182/2 3965/86/3 +f 3965/86/3 4009/181/3 4010/183/2 +f 4011/185/1 3969/184/1 3967/182/2 +f 3967/182/2 4010/183/2 4011/185/1 +f 4012/187/12 3971/186/12 3969/184/1 +f 3969/184/1 4011/185/1 4012/187/12 +f 4013/189/11 3973/188/11 3971/186/12 +f 3971/186/12 4012/187/12 4013/189/11 +f 4014/191/10 3975/190/10 3973/188/11 +f 3973/188/11 4013/189/11 4014/191/10 +f 4015/192/9 3977/76/9 3975/190/10 +f 3975/190/10 4014/191/10 4015/192/9 +f 4016/194/8 3979/193/8 3977/76/9 +f 3977/76/9 4015/192/9 4016/194/8 +f 4006/174/7 3960/171/7 3979/193/8 +f 3979/193/8 4016/194/8 4006/174/7 +f 4017/195/443 4018/198/443 4019/197/443 +f 4019/197/443 4020/196/443 4017/195/443 +f 4021/199/390 4022/202/390 4023/201/390 +f 4023/201/390 4024/200/390 4021/199/390 +f 4025/203/444 4026/206/444 4027/205/444 +f 4027/205/444 4028/204/444 4025/203/444 +f 4029/202/388 4030/199/388 4031/200/388 +f 4031/200/388 4032/201/388 4029/202/388 +f 4033/207/398 4034/209/398 4035/208/398 +f 4035/208/398 4036/207/398 4033/207/398 +f 4037/209/445 4038/211/445 4039/210/445 +f 4028/212/446 4027/214/446 4040/213/446 +f 4040/213/446 4041/196/446 4028/212/446 +f 4042/210/447 4043/211/447 4044/209/447 +f 4045/215/448 4044/209/448 4043/211/448 +f 4043/211/448 4046/216/448 4045/215/448 +f 4047/217/449 4020/196/449 4019/197/449 +f 4019/197/449 4048/218/449 4047/217/449 +f 4049/219/451 4025/203/451 4028/204/451 +f 4028/204/451 4050/220/451 4049/219/451 +f 4051/209/391 4033/207/391 4036/207/391 +f 4036/207/391 4052/208/391 4051/209/391 +f 4028/212/452 4041/196/452 4053/213/452 +f 4053/213/452 4050/214/452 4028/212/452 +f 4045/215/453 4046/216/453 4038/211/453 +f 4038/211/453 4037/209/453 4045/215/453 +f 4054/221/388 4018/221/388 4017/222/388 +f 4017/222/388 4040/222/388 4054/221/388 +f 4040/222/402 4017/222/402 4020/203/402 +f 4020/203/402 4041/203/402 4040/222/402 +f 4041/203/401 4020/203/401 4047/206/401 +f 4047/206/401 4053/206/401 4041/203/401 +f 4053/206/390 4047/206/390 4048/223/390 +f 4048/223/390 4055/223/390 4053/206/390 +f 4055/224/454 4048/224/454 4019/226/454 +f 4019/226/454 4056/225/454 4055/224/454 +f 4056/225/455 4019/226/455 4018/224/455 +f 4018/224/455 4054/224/455 4056/225/455 +f 4050/214/447 4053/213/447 4055/228/447 +f 4055/228/447 4057/227/447 4050/214/447 +f 4057/229/388 4058/221/388 4049/219/388 +f 4049/219/388 4050/220/388 4057/229/388 +f 4026/206/390 4059/223/390 4060/230/390 +f 4060/230/390 4027/205/390 4026/206/390 +f 4060/227/445 4054/228/445 4040/213/445 +f 4040/213/445 4027/214/445 4060/227/445 +f 4023/201/390 4061/202/390 4062/199/390 +f 4062/199/390 4024/200/390 4023/201/390 +f 4060/231/456 4039/233/456 4038/232/456 +f 4038/232/456 4054/224/456 4060/231/456 +f 4054/224/455 4038/232/455 4046/234/455 +f 4046/234/455 4056/225/455 4054/224/455 +f 4056/225/454 4046/234/454 4043/232/454 +f 4043/232/454 4055/224/454 4056/225/454 +f 4055/224/457 4043/232/457 4042/233/457 +f 4042/233/457 4057/231/457 4055/224/457 +f 4031/200/388 4063/199/388 4064/202/388 +f 4064/202/388 4032/201/388 4031/200/388 +f 4035/208/398 4044/236/398 4045/235/398 +f 4045/235/398 4036/207/398 4035/208/398 +f 4036/207/391 4045/235/391 4037/236/391 +f 4037/236/391 4052/208/391 4036/207/391 +f 4059/236/27 4021/238/27 4024/237/27 +f 4024/237/27 4060/231/27 4059/236/27 +f 4060/231/27 4024/237/27 4062/239/27 +f 4062/239/27 4039/233/27 4060/231/27 +f 4039/210/484 4062/241/484 4061/240/484 +f 4061/240/484 4037/209/484 4039/210/484 +f 4037/236/26 4061/238/26 4023/242/26 +f 4023/242/26 4052/208/26 4037/236/26 +f 4052/208/26 4023/242/26 4022/240/26 +f 4022/240/26 4051/209/26 4052/208/26 +f 4034/209/26 4029/240/26 4032/242/26 +f 4032/242/26 4035/208/26 4034/209/26 +f 4035/208/26 4032/242/26 4064/238/26 +f 4064/238/26 4044/236/26 4035/208/26 +f 4044/209/459 4064/240/459 4063/241/459 +f 4063/241/459 4042/210/459 4044/209/459 +f 4042/233/27 4063/239/27 4031/237/27 +f 4031/237/27 4057/231/27 4042/233/27 +f 4057/231/27 4031/237/27 4030/238/27 +f 4030/238/27 4058/236/27 4057/231/27 +f 4065/195/4 4066/198/4 4067/197/4 +f 4067/197/4 4068/196/4 4065/195/4 +f 4069/199/416 4070/202/416 4071/201/415 +f 4071/201/415 4072/200/415 4069/199/416 +f 4073/203/421 4074/206/421 4075/205/421 +f 4075/205/421 4076/204/421 4073/203/421 +f 4077/202/413 4078/199/413 4079/200/412 +f 4079/200/412 4080/201/412 4077/202/413 +f 4081/207/466 4082/209/466 4083/208/466 +f 4083/208/466 4084/207/466 4081/207/466 +f 4085/209/107 4086/211/107 4087/210/107 +f 4076/212/467 4075/214/467 4088/213/467 +f 4088/213/467 4089/196/467 4076/212/467 +f 4090/210/468 4091/211/468 4092/209/468 +f 4093/215/469 4092/209/469 4091/211/469 +f 4091/211/469 4094/216/469 4093/215/469 +f 4095/217/103 4068/196/103 4067/197/103 +f 4067/197/103 4096/218/103 4095/217/103 +f 4097/219/414 4073/203/414 4076/204/414 +f 4076/204/414 4098/220/414 4097/219/414 +f 4099/209/471 4081/207/471 4084/207/471 +f 4084/207/471 4100/208/471 4099/209/471 +f 4076/212/472 4089/196/472 4101/213/472 +f 4101/213/472 4098/214/472 4076/212/472 +f 4093/215/332 4094/216/332 4086/211/332 +f 4086/211/332 4085/209/332 4093/215/332 +f 4102/221/413 4066/221/412 4065/222/412 +f 4065/222/412 4088/222/413 4102/221/413 +f 4088/222/426 4065/222/426 4068/203/426 +f 4068/203/426 4089/203/426 4088/222/426 +f 4089/203/425 4068/203/425 4095/206/425 +f 4095/206/425 4101/206/425 4089/203/425 +f 4101/206/415 4095/206/415 4096/223/415 +f 4096/223/415 4103/223/415 4101/206/415 +f 4103/224/473 4096/224/473 4067/226/473 +f 4067/226/473 4104/225/473 4103/224/473 +f 4104/225/430 4067/226/430 4066/224/430 +f 4066/224/430 4102/224/430 4104/225/430 +f 4098/214/468 4101/213/468 4103/228/468 +f 4103/228/468 4105/227/468 4098/214/468 +f 4105/229/413 4106/221/413 4097/219/413 +f 4097/219/413 4098/220/413 4105/229/413 +f 4074/206/415 4107/223/415 4108/230/415 +f 4108/230/415 4075/205/415 4074/206/415 +f 4108/227/107 4102/228/107 4088/213/107 +f 4088/213/107 4075/214/107 4108/227/107 +f 4071/201/415 4109/202/416 4110/199/416 +f 4110/199/416 4072/200/415 4071/201/415 +f 4108/231/485 4087/233/485 4086/232/485 +f 4086/232/485 4102/224/485 4108/231/485 +f 4102/224/430 4086/232/430 4094/234/430 +f 4094/234/430 4104/225/430 4102/224/430 +f 4104/225/473 4094/234/473 4091/232/473 +f 4091/232/473 4103/224/473 4104/225/473 +f 4103/224/428 4091/232/428 4090/233/428 +f 4090/233/428 4105/231/428 4103/224/428 +f 4079/200/412 4111/199/413 4112/202/413 +f 4112/202/413 4080/201/412 4079/200/412 +f 4083/208/466 4092/236/466 4093/235/466 +f 4093/235/466 4084/207/466 4083/208/466 +f 4084/207/471 4093/235/471 4085/236/471 +f 4085/236/471 4100/208/471 4084/207/471 +f 4107/236/27 4069/238/27 4072/237/27 +f 4072/237/27 4108/231/27 4107/236/27 +f 4108/231/27 4072/237/27 4110/239/27 +f 4110/239/27 4087/233/27 4108/231/27 +f 4087/210/193 4110/241/193 4109/240/193 +f 4109/240/193 4085/209/193 4087/210/193 +f 4085/236/26 4109/238/26 4071/242/26 +f 4071/242/26 4100/208/26 4085/236/26 +f 4100/208/26 4071/242/26 4070/240/26 +f 4070/240/26 4099/209/26 4100/208/26 +f 4082/209/26 4077/240/26 4080/242/26 +f 4080/242/26 4083/208/26 4082/209/26 +f 4083/208/26 4080/242/26 4112/238/26 +f 4112/238/26 4092/236/26 4083/208/26 +f 4092/209/475 4112/240/475 4111/241/475 +f 4111/241/475 4090/210/475 4092/209/475 +f 4090/233/27 4111/239/27 4079/237/27 +f 4079/237/27 4105/231/27 4090/233/27 +f 4105/231/27 4079/237/27 4078/238/27 +f 4078/238/27 4106/236/27 4105/231/27 +f 4113/243/476 4114/246/476 4115/245/476 +f 4115/245/476 4116/244/476 4113/243/476 +f 4113/247/477 4117/250/477 4118/249/477 +f 4118/249/477 4114/248/477 4113/247/477 +f 4114/246/478 4118/252/478 4119/251/478 +f 4119/251/478 4115/245/478 4114/246/478 +f 4115/248/479 4119/249/479 4120/250/479 +f 4120/250/479 4116/247/479 4115/248/479 +f 4121/195/464 4122/198/464 4123/197/464 +f 4123/197/464 4124/196/464 4121/195/464 +f 4125/199/416 4126/202/416 4127/201/415 +f 4127/201/415 4128/200/415 4125/199/416 +f 4129/203/421 4130/206/421 4131/205/421 +f 4131/205/421 4132/204/421 4129/203/421 +f 4133/202/413 4134/199/413 4135/200/412 +f 4135/200/412 4136/201/412 4133/202/413 +f 4137/207/466 4138/209/466 4139/208/466 +f 4139/208/466 4140/207/466 4137/207/466 +f 4141/209/107 4142/211/107 4143/210/107 +f 4132/212/467 4131/214/467 4144/213/467 +f 4144/213/467 4145/196/467 4132/212/467 +f 4146/210/468 4147/211/468 4148/209/468 +f 4149/215/469 4148/209/469 4147/211/469 +f 4147/211/469 4150/216/469 4149/215/469 +f 4151/217/103 4124/196/103 4123/197/103 +f 4123/197/103 4152/218/103 4151/217/103 +f 4153/219/470 4129/203/414 4132/204/414 +f 4132/204/414 4154/220/470 4153/219/470 +f 4155/209/471 4137/207/471 4140/207/471 +f 4140/207/471 4156/208/471 4155/209/471 +f 4132/212/472 4145/196/472 4157/213/472 +f 4157/213/472 4154/214/472 4132/212/472 +f 4149/215/332 4150/216/332 4142/211/332 +f 4142/211/332 4141/209/332 4149/215/332 +f 4158/221/413 4122/221/413 4121/222/413 +f 4121/222/413 4144/222/413 4158/221/413 +f 4144/222/426 4121/222/426 4124/203/426 +f 4124/203/426 4145/203/426 4144/222/426 +f 4145/203/425 4124/203/425 4151/206/425 +f 4151/206/425 4157/206/425 4145/203/425 +f 4157/206/415 4151/206/415 4152/223/415 +f 4152/223/415 4159/223/415 4157/206/415 +f 4159/224/473 4152/224/473 4123/226/473 +f 4123/226/473 4160/225/473 4159/224/473 +f 4160/225/430 4123/226/430 4122/224/430 +f 4122/224/430 4158/224/430 4160/225/430 +f 4154/214/468 4157/213/468 4159/228/468 +f 4159/228/468 4161/227/468 4154/214/468 +f 4161/229/437 4162/221/412 4153/219/412 +f 4153/219/412 4154/220/437 4161/229/437 +f 4130/206/415 4163/223/415 4164/230/416 +f 4164/230/416 4131/205/416 4130/206/415 +f 4164/227/107 4158/228/107 4144/213/107 +f 4144/213/107 4131/214/107 4164/227/107 +f 4127/201/415 4165/202/416 4166/199/416 +f 4166/199/416 4128/200/415 4127/201/415 +f 4164/231/485 4143/233/485 4142/232/485 +f 4142/232/485 4158/224/485 4164/231/485 +f 4158/224/430 4142/232/430 4150/234/430 +f 4150/234/430 4160/225/430 4158/224/430 +f 4160/225/473 4150/234/473 4147/232/473 +f 4147/232/473 4159/224/473 4160/225/473 +f 4159/224/428 4147/232/428 4146/233/428 +f 4146/233/428 4161/231/428 4159/224/428 +f 4135/200/412 4167/199/413 4168/202/413 +f 4168/202/413 4136/201/412 4135/200/412 +f 4139/208/466 4148/236/466 4149/235/466 +f 4149/235/466 4140/207/466 4139/208/466 +f 4140/207/471 4149/235/471 4141/236/471 +f 4141/236/471 4156/208/471 4140/207/471 +f 4163/236/27 4125/238/27 4128/237/27 +f 4128/237/27 4164/231/27 4163/236/27 +f 4164/231/27 4128/237/27 4166/239/27 +f 4166/239/27 4143/233/27 4164/231/27 +f 4143/210/193 4166/241/193 4165/240/193 +f 4165/240/193 4141/209/193 4143/210/193 +f 4141/236/26 4165/238/26 4127/242/26 +f 4127/242/26 4156/208/26 4141/236/26 +f 4156/208/26 4127/242/26 4126/240/26 +f 4126/240/26 4155/209/26 4156/208/26 +f 4138/209/26 4133/240/26 4136/242/26 +f 4136/242/26 4139/208/26 4138/209/26 +f 4139/208/26 4136/242/26 4168/238/26 +f 4168/238/26 4148/236/26 4139/208/26 +f 4148/209/475 4168/240/475 4167/241/475 +f 4167/241/475 4146/210/475 4148/209/475 +f 4146/233/27 4167/239/27 4135/237/27 +f 4135/237/27 4161/231/27 4146/233/27 +f 4161/231/27 4135/237/27 4134/238/27 +f 4134/238/27 4162/236/27 4161/231/27 +f 4169/243/460 4170/246/460 4171/245/460 +f 4171/245/460 4172/244/460 4169/243/460 +f 4169/247/461 4173/250/461 4174/249/461 +f 4174/249/461 4170/248/461 4169/247/461 +f 4170/246/462 4174/252/462 4175/251/462 +f 4175/251/462 4171/245/462 4170/246/462 +f 4171/248/463 4175/249/463 4176/250/463 +f 4176/250/463 4172/247/463 4171/248/463 +f 4177/195/387 4178/198/387 4179/197/387 +f 4179/197/387 4180/196/387 4177/195/387 +f 4181/199/388 4182/202/388 4183/201/388 +f 4183/201/388 4184/200/388 4181/199/388 +f 4185/203/389 4186/206/389 4187/205/389 +f 4187/205/389 4188/204/389 4185/203/389 +f 4189/202/390 4190/199/390 4191/200/390 +f 4191/200/390 4192/201/390 4189/202/390 +f 4193/207/391 4194/209/391 4195/208/391 +f 4195/208/391 4196/207/391 4193/207/391 +f 4197/209/392 4198/211/392 4199/210/392 +f 4188/212/393 4187/214/393 4200/213/393 +f 4200/213/393 4201/196/393 4188/212/393 +f 4202/210/394 4203/211/394 4204/209/394 +f 4205/215/395 4204/209/395 4203/211/395 +f 4203/211/395 4206/216/395 4205/215/395 +f 4207/217/396 4180/196/486 4179/197/486 +f 4179/197/486 4208/218/396 4207/217/396 +f 4209/219/397 4185/203/397 4188/204/397 +f 4188/204/397 4210/220/397 4209/219/397 +f 4211/209/398 4193/207/398 4196/207/398 +f 4196/207/398 4212/208/398 4211/209/398 +f 4188/212/399 4201/196/399 4213/213/399 +f 4213/213/399 4210/214/399 4188/212/399 +f 4205/215/400 4206/216/400 4198/211/400 +f 4198/211/400 4197/209/400 4205/215/400 +f 4214/221/390 4178/221/390 4177/222/390 +f 4177/222/390 4200/222/390 4214/221/390 +f 4200/222/401 4177/222/401 4180/203/401 +f 4180/203/401 4201/203/401 4200/222/401 +f 4201/203/402 4180/203/402 4207/206/402 +f 4207/206/402 4213/206/402 4201/203/402 +f 4213/206/388 4207/206/388 4208/223/388 +f 4208/223/388 4215/223/388 4213/206/388 +f 4215/224/403 4208/224/403 4179/226/403 +f 4179/226/403 4216/225/403 4215/224/403 +f 4216/225/404 4179/226/404 4178/224/404 +f 4178/224/404 4214/224/404 4216/225/404 +f 4210/214/394 4213/213/394 4215/228/394 +f 4215/228/394 4217/227/394 4210/214/394 +f 4217/229/390 4218/221/390 4209/219/390 +f 4209/219/390 4210/220/390 4217/229/390 +f 4186/206/388 4219/223/388 4220/230/388 +f 4220/230/388 4187/205/388 4186/206/388 +f 4220/227/392 4214/228/392 4200/213/392 +f 4200/213/392 4187/214/392 4220/227/392 +f 4183/201/388 4221/202/388 4222/199/388 +f 4222/199/388 4184/200/388 4183/201/388 +f 4220/231/405 4199/233/405 4198/232/405 +f 4198/232/405 4214/224/405 4220/231/405 +f 4214/224/404 4198/232/404 4206/234/404 +f 4206/234/404 4216/225/404 4214/224/404 +f 4216/225/403 4206/234/403 4203/232/403 +f 4203/232/403 4215/224/403 4216/225/403 +f 4215/224/407 4203/232/407 4202/233/407 +f 4202/233/407 4217/231/407 4215/224/407 +f 4191/200/390 4223/199/390 4224/202/390 +f 4224/202/390 4192/201/390 4191/200/390 +f 4195/208/391 4204/236/391 4205/235/391 +f 4205/235/391 4196/207/391 4195/208/391 +f 4196/207/398 4205/235/398 4197/236/398 +f 4197/236/398 4212/208/398 4196/207/398 +f 4219/236/27 4181/238/27 4184/237/27 +f 4184/237/27 4220/231/27 4219/236/27 +f 4220/231/27 4184/237/27 4222/239/27 +f 4222/239/27 4199/233/27 4220/231/27 +f 4199/210/409 4222/241/409 4221/240/409 +f 4221/240/409 4197/209/409 4199/210/409 +f 4197/236/26 4221/238/26 4183/242/26 +f 4183/242/26 4212/208/26 4197/236/26 +f 4212/208/26 4183/242/26 4182/240/26 +f 4182/240/26 4211/209/26 4212/208/26 +f 4194/209/26 4189/240/26 4192/242/26 +f 4192/242/26 4195/208/26 4194/209/26 +f 4195/208/26 4192/242/26 4224/238/26 +f 4224/238/26 4204/236/26 4195/208/26 +f 4204/209/410 4224/240/410 4223/241/410 +f 4223/241/410 4202/210/410 4204/209/410 +f 4202/233/27 4223/239/27 4191/237/27 +f 4191/237/27 4217/231/27 4202/233/27 +f 4217/231/27 4191/237/27 4190/238/27 +f 4190/238/27 4218/236/27 4217/231/27 +f 4225/243/148 4226/246/148 4227/245/148 +f 4227/245/148 4228/244/148 4225/243/148 +f 4225/247/7 4229/250/7 4230/249/7 +f 4230/249/7 4226/248/7 4225/247/7 +f 4226/246/149 4230/252/149 4231/251/149 +f 4231/251/149 4227/245/149 4226/246/149 +f 4227/248/1 4231/249/1 4232/250/1 +f 4232/250/1 4228/247/1 4227/248/1 +f 4233/243/187 4234/246/187 4235/245/187 +f 4235/245/187 4236/244/187 4233/243/187 +f 4233/247/161 4237/250/161 4238/249/161 +f 4238/249/161 4234/248/161 4233/247/161 +f 4234/246/188 4238/252/188 4239/251/188 +f 4239/251/188 4235/245/188 4234/246/188 +f 4235/248/163 4239/249/163 4240/250/163 +f 4240/250/163 4236/247/163 4235/248/163 +f 4241/243/154 4242/246/154 4243/245/154 +f 4243/245/154 4244/244/154 4241/243/154 +f 4241/247/1 4245/250/1 4246/249/1 +f 4246/249/1 4242/248/1 4241/247/1 +f 4242/246/155 4246/252/155 4247/251/155 +f 4247/251/155 4243/245/155 4242/246/155 +f 4243/248/7 4247/249/7 4248/250/7 +f 4248/250/7 4244/247/7 4243/248/7 +f 4249/243/439 4250/246/439 4251/245/439 +f 4251/245/439 4252/244/439 4249/243/439 +f 4249/247/440 4253/250/440 4254/249/440 +f 4254/249/440 4250/248/440 4249/247/440 +f 4250/246/441 4254/252/441 4255/251/441 +f 4255/251/441 4251/245/441 4250/246/441 +f 4251/248/442 4255/249/442 4256/250/442 +f 4256/250/442 4252/247/442 4251/248/442 +f 4257/243/180 4258/246/180 4259/245/180 +f 4259/245/180 4260/244/180 4257/243/180 +f 4257/247/151 4261/250/151 4262/249/151 +f 4262/249/151 4258/248/151 4257/247/151 +f 4258/246/181 4262/252/181 4263/251/181 +f 4263/251/181 4259/245/181 4258/246/181 +f 4259/248/153 4263/249/153 4264/250/153 +f 4264/250/153 4260/247/153 4259/248/153 +f 4265/195/387 4266/198/387 4267/197/387 +f 4267/197/387 4268/196/387 4265/195/387 +f 4269/199/388 4270/202/388 4271/201/388 +f 4271/201/388 4272/200/388 4269/199/388 +f 4273/203/389 4274/206/389 4275/205/389 +f 4275/205/389 4276/204/389 4273/203/389 +f 4277/202/390 4278/199/390 4279/200/390 +f 4279/200/390 4280/201/390 4277/202/390 +f 4281/207/391 4282/209/391 4283/208/391 +f 4283/208/391 4284/207/391 4281/207/391 +f 4285/209/392 4286/211/392 4287/210/392 +f 4276/212/393 4275/214/393 4288/213/393 +f 4288/213/393 4289/196/393 4276/212/393 +f 4290/210/394 4291/211/394 4292/209/394 +f 4293/215/395 4292/209/395 4291/211/395 +f 4291/211/395 4294/216/395 4293/215/395 +f 4295/217/396 4268/196/486 4267/197/486 +f 4267/197/486 4296/218/396 4295/217/396 +f 4297/219/397 4273/203/397 4276/204/397 +f 4276/204/397 4298/220/397 4297/219/397 +f 4299/209/398 4281/207/398 4284/207/398 +f 4284/207/398 4300/208/398 4299/209/398 +f 4276/212/399 4289/196/399 4301/213/399 +f 4301/213/399 4298/214/399 4276/212/399 +f 4293/215/400 4294/216/400 4286/211/400 +f 4286/211/400 4285/209/400 4293/215/400 +f 4302/221/390 4266/221/390 4265/222/390 +f 4265/222/390 4288/222/390 4302/221/390 +f 4288/222/401 4265/222/401 4268/203/401 +f 4268/203/401 4289/203/401 4288/222/401 +f 4289/203/402 4268/203/402 4295/206/402 +f 4295/206/402 4301/206/402 4289/203/402 +f 4301/206/388 4295/206/388 4296/223/388 +f 4296/223/388 4303/223/388 4301/206/388 +f 4303/224/403 4296/224/403 4267/226/403 +f 4267/226/403 4304/225/403 4303/224/403 +f 4304/225/404 4267/226/404 4266/224/404 +f 4266/224/404 4302/224/404 4304/225/404 +f 4298/214/394 4301/213/394 4303/228/394 +f 4303/228/394 4305/227/394 4298/214/394 +f 4305/229/390 4306/221/390 4297/219/390 +f 4297/219/390 4298/220/390 4305/229/390 +f 4274/206/388 4307/223/388 4308/230/388 +f 4308/230/388 4275/205/388 4274/206/388 +f 4308/227/392 4302/228/392 4288/213/392 +f 4288/213/392 4275/214/392 4308/227/392 +f 4271/201/388 4309/202/388 4310/199/388 +f 4310/199/388 4272/200/388 4271/201/388 +f 4308/231/405 4287/233/405 4286/232/405 +f 4286/232/405 4302/224/405 4308/231/405 +f 4302/224/404 4286/232/404 4294/234/404 +f 4294/234/404 4304/225/404 4302/224/404 +f 4304/225/403 4294/234/403 4291/232/403 +f 4291/232/403 4303/224/403 4304/225/403 +f 4303/224/407 4291/232/407 4290/233/407 +f 4290/233/407 4305/231/407 4303/224/407 +f 4279/200/390 4311/199/390 4312/202/390 +f 4312/202/390 4280/201/390 4279/200/390 +f 4283/208/391 4292/236/391 4293/235/391 +f 4293/235/391 4284/207/391 4283/208/391 +f 4284/207/398 4293/235/398 4285/236/398 +f 4285/236/398 4300/208/398 4284/207/398 +f 4307/236/27 4269/238/27 4272/237/27 +f 4272/237/27 4308/231/27 4307/236/27 +f 4308/231/27 4272/237/27 4310/239/27 +f 4310/239/27 4287/233/27 4308/231/27 +f 4287/210/409 4310/241/409 4309/240/409 +f 4309/240/409 4285/209/409 4287/210/409 +f 4285/236/26 4309/238/26 4271/242/26 +f 4271/242/26 4300/208/26 4285/236/26 +f 4300/208/26 4271/242/26 4270/240/26 +f 4270/240/26 4299/209/26 4300/208/26 +f 4282/209/26 4277/240/26 4280/242/26 +f 4280/242/26 4283/208/26 4282/209/26 +f 4283/208/26 4280/242/26 4312/238/26 +f 4312/238/26 4292/236/26 4283/208/26 +f 4292/209/410 4312/240/410 4311/241/410 +f 4311/241/410 4290/210/410 4292/209/410 +f 4290/233/27 4311/239/27 4279/237/27 +f 4279/237/27 4305/231/27 4290/233/27 +f 4305/231/27 4279/237/27 4278/238/27 +f 4278/238/27 4306/236/27 4305/231/27 +f 4313/195/436 4314/198/436 4315/197/411 +f 4315/197/411 4316/196/411 4313/195/436 +f 4317/199/437 4318/202/437 4319/201/437 +f 4319/201/437 4320/200/437 4317/199/437 +f 4321/203/414 4322/206/414 4323/205/414 +f 4323/205/414 4324/204/414 4321/203/414 +f 4325/202/465 4326/199/465 4327/200/465 +f 4327/200/465 4328/201/465 4325/202/465 +f 4329/207/417 4330/209/417 4331/208/417 +f 4331/208/417 4332/207/417 4329/207/417 +f 4333/209/171 4334/211/171 4335/210/171 +f 4324/212/418 4323/214/418 4336/213/418 +f 4336/213/418 4337/196/418 4324/212/418 +f 4338/210/419 4339/211/419 4340/209/419 +f 4341/215/420 4340/209/420 4339/211/420 +f 4339/211/420 4342/216/420 4341/215/420 +f 4343/217/167 4316/196/167 4315/197/167 +f 4315/197/167 4344/218/167 4343/217/167 +f 4345/219/438 4321/203/421 4324/204/421 +f 4324/204/421 4346/220/421 4345/219/438 +f 4347/209/422 4329/207/422 4332/207/422 +f 4332/207/422 4348/208/422 4347/209/422 +f 4324/212/423 4337/196/423 4349/213/423 +f 4349/213/423 4346/214/423 4324/212/423 +f 4341/215/424 4342/216/424 4334/211/424 +f 4334/211/424 4333/209/424 4341/215/424 +f 4350/221/465 4314/221/465 4313/222/465 +f 4313/222/465 4336/222/465 4350/221/465 +f 4336/222/425 4313/222/425 4316/203/425 +f 4316/203/425 4337/203/425 4336/222/425 +f 4337/203/426 4316/203/426 4343/206/426 +f 4343/206/426 4349/206/426 4337/203/426 +f 4349/206/437 4343/206/437 4344/223/437 +f 4344/223/437 4351/223/437 4349/206/437 +f 4351/224/427 4344/224/427 4315/226/427 +f 4315/226/427 4352/225/427 4351/224/427 +f 4352/225/428 4315/226/428 4314/224/428 +f 4314/224/428 4350/224/428 4352/225/428 +f 4346/214/419 4349/213/419 4351/228/419 +f 4351/228/419 4353/227/419 4346/214/419 +f 4353/229/465 4354/221/465 4345/219/465 +f 4345/219/465 4346/220/465 4353/229/465 +f 4322/206/437 4355/223/437 4356/230/437 +f 4356/230/437 4323/205/437 4322/206/437 +f 4356/227/171 4350/228/171 4336/213/171 +f 4336/213/171 4323/214/171 4356/227/171 +f 4319/201/437 4357/202/437 4358/199/437 +f 4358/199/437 4320/200/437 4319/201/437 +f 4356/231/487 4335/233/487 4334/232/487 +f 4334/232/487 4350/224/487 4356/231/487 +f 4350/224/428 4334/232/428 4342/234/428 +f 4342/234/428 4352/225/428 4350/224/428 +f 4352/225/427 4342/234/427 4339/232/427 +f 4339/232/427 4351/224/427 4352/225/427 +f 4351/224/430 4339/232/430 4338/233/430 +f 4338/233/430 4353/231/430 4351/224/430 +f 4327/200/465 4359/199/465 4360/202/465 +f 4360/202/465 4328/201/465 4327/200/465 +f 4331/208/417 4340/236/417 4341/235/417 +f 4341/235/417 4332/207/417 4331/208/417 +f 4332/207/422 4341/235/422 4333/236/422 +f 4333/236/422 4348/208/422 4332/207/422 +f 4355/236/27 4317/238/27 4320/237/27 +f 4320/237/27 4356/231/27 4355/236/27 +f 4356/231/27 4320/237/27 4358/239/27 +f 4358/239/27 4335/233/27 4356/231/27 +f 4335/210/191 4358/241/191 4357/240/191 +f 4357/240/191 4333/209/191 4335/210/191 +f 4333/236/26 4357/238/26 4319/242/26 +f 4319/242/26 4348/208/26 4333/236/26 +f 4348/208/26 4319/242/26 4318/240/26 +f 4318/240/26 4347/209/26 4348/208/26 +f 4330/209/26 4325/240/26 4328/242/26 +f 4328/242/26 4331/208/26 4330/209/26 +f 4331/208/26 4328/242/26 4360/238/26 +f 4360/238/26 4340/236/26 4331/208/26 +f 4340/209/431 4360/240/431 4359/241/431 +f 4359/241/431 4338/210/431 4340/209/431 +f 4338/233/27 4359/239/27 4327/237/27 +f 4327/237/27 4353/231/27 4338/233/27 +f 4353/231/27 4327/237/27 4326/238/27 +f 4326/238/27 4354/236/27 4353/231/27 +f 4361/243/160 4362/246/160 4363/245/160 +f 4363/245/160 4364/244/160 4361/243/160 +f 4361/247/163 4365/250/163 4366/249/163 +f 4366/249/163 4362/248/163 4361/247/163 +f 4362/246/162 4366/252/162 4367/251/162 +f 4367/251/162 4363/245/162 4362/246/162 +f 4363/248/161 4367/249/161 4368/250/161 +f 4368/250/161 4364/247/161 4363/248/161 +f 4369/195/411 4370/198/411 4371/197/436 +f 4371/197/436 4372/196/436 4369/195/411 +f 4373/199/437 4374/202/437 4375/201/437 +f 4375/201/437 4376/200/437 4373/199/437 +f 4377/203/414 4378/206/414 4379/205/414 +f 4379/205/414 4380/204/414 4377/203/414 +f 4381/202/465 4382/199/465 4383/200/465 +f 4383/200/465 4384/201/465 4381/202/465 +f 4385/207/417 4386/209/417 4387/208/417 +f 4387/208/417 4388/207/417 4385/207/417 +f 4389/209/171 4390/211/171 4391/210/171 +f 4380/212/418 4379/214/418 4392/213/418 +f 4392/213/418 4393/196/418 4380/212/418 +f 4394/210/419 4395/211/419 4396/209/419 +f 4397/215/420 4396/209/420 4395/211/420 +f 4395/211/420 4398/216/420 4397/215/420 +f 4399/217/167 4372/196/167 4371/197/167 +f 4371/197/167 4400/218/167 4399/217/167 +f 4401/219/421 4377/203/421 4380/204/438 +f 4380/204/438 4402/220/421 4401/219/421 +f 4403/209/422 4385/207/422 4388/207/422 +f 4388/207/422 4404/208/422 4403/209/422 +f 4380/212/423 4393/196/423 4405/213/423 +f 4405/213/423 4402/214/423 4380/212/423 +f 4397/215/424 4398/216/424 4390/211/424 +f 4390/211/424 4389/209/424 4397/215/424 +f 4406/221/465 4370/221/465 4369/222/465 +f 4369/222/465 4392/222/465 4406/221/465 +f 4392/222/425 4369/222/425 4372/203/425 +f 4372/203/425 4393/203/425 4392/222/425 +f 4393/203/426 4372/203/426 4399/206/426 +f 4399/206/426 4405/206/426 4393/203/426 +f 4405/206/437 4399/206/437 4400/223/437 +f 4400/223/437 4407/223/437 4405/206/437 +f 4407/224/427 4400/224/427 4371/226/427 +f 4371/226/427 4408/225/427 4407/224/427 +f 4408/225/428 4371/226/428 4370/224/428 +f 4370/224/428 4406/224/428 4408/225/428 +f 4402/214/419 4405/213/419 4407/228/419 +f 4407/228/419 4409/227/419 4402/214/419 +f 4409/229/465 4410/221/465 4401/219/465 +f 4401/219/465 4402/220/465 4409/229/465 +f 4378/206/437 4411/223/437 4412/230/437 +f 4412/230/437 4379/205/437 4378/206/437 +f 4412/227/171 4406/228/171 4392/213/171 +f 4392/213/171 4379/214/171 4412/227/171 +f 4375/201/437 4413/202/437 4414/199/437 +f 4414/199/437 4376/200/437 4375/201/437 +f 4412/231/487 4391/233/487 4390/232/487 +f 4390/232/487 4406/224/487 4412/231/487 +f 4406/224/428 4390/232/428 4398/234/428 +f 4398/234/428 4408/225/428 4406/224/428 +f 4408/225/427 4398/234/427 4395/232/427 +f 4395/232/427 4407/224/427 4408/225/427 +f 4407/224/430 4395/232/430 4394/233/430 +f 4394/233/430 4409/231/430 4407/224/430 +f 4383/200/465 4415/199/465 4416/202/465 +f 4416/202/465 4384/201/465 4383/200/465 +f 4387/208/417 4396/236/417 4397/235/417 +f 4397/235/417 4388/207/417 4387/208/417 +f 4388/207/422 4397/235/422 4389/236/422 +f 4389/236/422 4404/208/422 4388/207/422 +f 4411/236/27 4373/238/27 4376/237/27 +f 4376/237/27 4412/231/27 4411/236/27 +f 4412/231/27 4376/237/27 4414/239/27 +f 4414/239/27 4391/233/27 4412/231/27 +f 4391/210/191 4414/241/191 4413/240/191 +f 4413/240/191 4389/209/191 4391/210/191 +f 4389/236/26 4413/238/26 4375/242/26 +f 4375/242/26 4404/208/26 4389/236/26 +f 4404/208/26 4375/242/26 4374/240/26 +f 4374/240/26 4403/209/26 4404/208/26 +f 4386/209/26 4381/240/26 4384/242/26 +f 4384/242/26 4387/208/26 4386/209/26 +f 4387/208/26 4384/242/26 4416/238/26 +f 4416/238/26 4396/236/26 4387/208/26 +f 4396/209/431 4416/240/431 4415/241/431 +f 4415/241/431 4394/210/431 4396/209/431 +f 4394/233/27 4415/239/27 4383/237/27 +f 4383/237/27 4409/231/27 4394/233/27 +f 4409/231/27 4383/237/27 4382/238/27 +f 4382/238/27 4410/236/27 4409/231/27 +f 4417/243/432 4418/246/432 4419/245/432 +f 4419/245/432 4420/244/432 4417/243/432 +f 4417/247/433 4421/250/433 4422/249/433 +f 4422/249/433 4418/248/433 4417/247/433 +f 4418/246/434 4422/252/434 4423/251/434 +f 4423/251/434 4419/245/434 4418/246/434 +f 4419/248/435 4423/249/435 4424/250/435 +f 4424/250/435 4420/247/435 4419/248/435 +f 4425/195/443 4426/198/443 4427/197/443 +f 4427/197/443 4428/196/443 4425/195/443 +f 4429/199/390 4430/202/390 4431/201/390 +f 4431/201/390 4432/200/390 4429/199/390 +f 4433/203/444 4434/206/444 4435/205/444 +f 4435/205/444 4436/204/444 4433/203/444 +f 4437/202/388 4438/199/388 4439/200/388 +f 4439/200/388 4440/201/388 4437/202/388 +f 4441/207/398 4442/209/398 4443/208/398 +f 4443/208/398 4444/207/398 4441/207/398 +f 4445/209/445 4446/211/445 4447/210/445 +f 4436/212/446 4435/214/446 4448/213/446 +f 4448/213/446 4449/196/446 4436/212/446 +f 4450/210/447 4451/211/447 4452/209/447 +f 4453/215/448 4452/209/448 4451/211/448 +f 4451/211/448 4454/216/448 4453/215/448 +f 4455/217/449 4428/196/449 4427/197/449 +f 4427/197/449 4456/218/449 4455/217/449 +f 4457/219/451 4433/203/451 4436/204/451 +f 4436/204/451 4458/220/451 4457/219/451 +f 4459/209/391 4441/207/391 4444/207/391 +f 4444/207/391 4460/208/391 4459/209/391 +f 4436/212/452 4449/196/452 4461/213/452 +f 4461/213/452 4458/214/452 4436/212/452 +f 4453/215/453 4454/216/453 4446/211/453 +f 4446/211/453 4445/209/453 4453/215/453 +f 4462/221/388 4426/221/388 4425/222/388 +f 4425/222/388 4448/222/388 4462/221/388 +f 4448/222/402 4425/222/402 4428/203/402 +f 4428/203/402 4449/203/402 4448/222/402 +f 4449/203/401 4428/203/401 4455/206/401 +f 4455/206/401 4461/206/401 4449/203/401 +f 4461/206/390 4455/206/390 4456/223/390 +f 4456/223/390 4463/223/390 4461/206/390 +f 4463/224/454 4456/224/454 4427/226/454 +f 4427/226/454 4464/225/454 4463/224/454 +f 4464/225/455 4427/226/455 4426/224/455 +f 4426/224/455 4462/224/455 4464/225/455 +f 4458/214/447 4461/213/447 4463/228/447 +f 4463/228/447 4465/227/447 4458/214/447 +f 4465/229/388 4466/221/388 4457/219/388 +f 4457/219/388 4458/220/388 4465/229/388 +f 4434/206/390 4467/223/390 4468/230/390 +f 4468/230/390 4435/205/390 4434/206/390 +f 4468/227/445 4462/228/445 4448/213/445 +f 4448/213/445 4435/214/445 4468/227/445 +f 4431/201/390 4469/202/390 4470/199/390 +f 4470/199/390 4432/200/390 4431/201/390 +f 4468/231/456 4447/233/456 4446/232/456 +f 4446/232/456 4462/224/456 4468/231/456 +f 4462/224/455 4446/232/455 4454/234/455 +f 4454/234/455 4464/225/455 4462/224/455 +f 4464/225/454 4454/234/454 4451/232/454 +f 4451/232/454 4463/224/454 4464/225/454 +f 4463/224/457 4451/232/457 4450/233/457 +f 4450/233/457 4465/231/457 4463/224/457 +f 4439/200/388 4471/199/388 4472/202/388 +f 4472/202/388 4440/201/388 4439/200/388 +f 4443/208/398 4452/236/398 4453/235/398 +f 4453/235/398 4444/207/398 4443/208/398 +f 4444/207/391 4453/235/391 4445/236/391 +f 4445/236/391 4460/208/391 4444/207/391 +f 4467/236/27 4429/238/27 4432/237/27 +f 4432/237/27 4468/231/27 4467/236/27 +f 4468/231/27 4432/237/27 4470/239/27 +f 4470/239/27 4447/233/27 4468/231/27 +f 4447/210/484 4470/241/484 4469/240/484 +f 4469/240/484 4445/209/484 4447/210/484 +f 4445/236/26 4469/238/26 4431/242/26 +f 4431/242/26 4460/208/26 4445/236/26 +f 4460/208/26 4431/242/26 4430/240/26 +f 4430/240/26 4459/209/26 4460/208/26 +f 4442/209/26 4437/240/26 4440/242/26 +f 4440/242/26 4443/208/26 4442/209/26 +f 4443/208/26 4440/242/26 4472/238/26 +f 4472/238/26 4452/236/26 4443/208/26 +f 4452/209/459 4472/240/459 4471/241/459 +f 4471/241/459 4450/210/459 4452/209/459 +f 4450/233/27 4471/239/27 4439/237/27 +f 4439/237/27 4465/231/27 4450/233/27 +f 4465/231/27 4439/237/27 4438/238/27 +f 4438/238/27 4466/236/27 4465/231/27 +f 4473/243/150 4474/246/150 4475/245/150 +f 4475/245/150 4476/244/150 4473/243/150 +f 4473/247/153 4477/250/153 4478/249/153 +f 4478/249/153 4474/248/153 4473/247/153 +f 4474/246/152 4478/252/152 4479/251/152 +f 4479/251/152 4475/245/152 4474/246/152 +f 4475/248/151 4479/249/151 4480/250/151 +f 4480/250/151 4476/247/151 4475/248/151 +f 4481/253/18 4482/256/18 4483/255/18 +f 4483/255/18 4484/254/18 4481/253/18 +f 4485/257/17 4486/258/17 4482/256/17 +f 4482/256/17 4481/253/17 4485/257/17 +f 4487/259/16 4488/260/16 4486/258/16 +f 4486/258/16 4485/257/16 4487/259/16 +f 4489/261/15 4490/264/15 4488/263/15 +f 4488/263/15 4487/262/118 4489/261/15 +f 4491/265/14 4492/266/14 4490/264/14 +f 4490/264/14 4489/261/14 4491/265/14 +f 4493/267/13 4494/268/13 4492/266/13 +f 4492/266/13 4491/265/13 4493/267/13 +f 4495/269/25 4496/270/25 4494/268/24 +f 4494/268/24 4493/267/24 4495/269/25 +f 4497/271/23 4498/272/23 4496/270/23 +f 4496/270/23 4495/269/23 4497/271/23 +f 4499/273/191 4500/274/22 4498/272/22 +f 4498/272/22 4497/271/22 4499/273/191 +f 4501/275/21 4502/276/21 4500/274/21 +f 4500/274/21 4499/273/21 4501/275/21 +f 4503/277/20 4504/278/20 4502/276/20 +f 4502/276/20 4501/275/20 4503/277/20 +f 4484/254/19 4483/255/19 4504/278/190 +f 4504/278/190 4503/277/190 4484/254/19 +f 4482/279/27 4505/282/27 4506/281/27 +f 4506/281/27 4483/280/27 4482/279/27 +f 4507/283/27 4508/284/27 4509/282/27 +f 4509/282/27 4510/279/27 4507/283/27 +f 4488/285/27 4511/285/27 4512/284/27 +f 4512/284/27 4486/283/27 4488/285/27 +f 4513/286/27 4514/287/27 4515/285/27 +f 4515/285/27 4516/285/27 4513/286/27 +f 4492/288/27 4517/289/27 4518/287/27 +f 4518/287/27 4490/286/27 4492/288/27 +f 4519/290/27 4520/291/27 4521/289/27 +f 4521/289/27 4522/288/27 4519/290/27 +f 4496/292/27 4523/293/27 4524/291/27 +f 4524/291/27 4494/290/27 4496/292/27 +f 4525/294/27 4526/295/27 4527/293/27 +f 4527/293/27 4528/292/27 4525/294/27 +f 4500/296/27 4529/297/27 4530/295/27 +f 4530/295/27 4498/294/27 4500/296/27 +f 4531/298/27 4532/299/27 4533/297/27 +f 4533/297/27 4534/296/27 4531/298/27 +f 4504/300/27 4535/300/27 4536/299/27 +f 4536/299/27 4502/298/27 4504/300/27 +f 4537/280/27 4538/281/27 4539/300/27 +f 4539/300/27 4540/300/27 4537/280/27 +f 4505/301/24 4541/304/24 4542/303/24 +f 4542/303/24 4506/302/24 4505/301/24 +f 4512/305/23 4543/306/23 4541/304/23 +f 4541/304/23 4505/301/23 4512/305/23 +f 4511/307/22 4544/308/22 4543/306/22 +f 4543/306/22 4512/305/191 4511/307/22 +f 4518/309/21 4545/310/21 4544/308/21 +f 4544/308/21 4511/307/21 4518/309/21 +f 4517/311/20 4546/312/20 4545/310/20 +f 4545/310/20 4518/309/20 4517/311/20 +f 4524/313/19 4547/314/19 4546/312/19 +f 4546/312/19 4517/311/19 4524/313/19 +f 4523/315/194 4548/316/194 4547/314/18 +f 4547/314/18 4524/313/18 4523/315/194 +f 4530/317/17 4549/318/17 4548/316/17 +f 4548/316/17 4523/315/17 4530/317/17 +f 4529/319/16 4550/320/16 4549/318/16 +f 4549/318/16 4530/317/16 4529/319/16 +f 4536/321/118 4551/324/15 4550/323/15 +f 4550/323/15 4529/322/15 4536/321/118 +f 4535/325/14 4552/326/14 4551/324/14 +f 4551/324/14 4536/321/14 4535/325/14 +f 4506/302/13 4542/303/13 4552/326/192 +f 4552/326/192 4535/325/192 4506/302/13 +f 4541/327/27 4553/329/27 4542/328/27 +f 4543/330/27 4553/329/27 4541/327/27 +f 4544/331/27 4553/329/27 4543/330/27 +f 4545/332/27 4553/329/27 4544/331/27 +f 4546/333/27 4553/329/27 4545/332/27 +f 4547/334/27 4553/329/27 4546/333/27 +f 4548/335/27 4553/329/27 4547/334/27 +f 4549/336/27 4553/329/27 4548/335/27 +f 4550/337/27 4553/329/27 4549/336/27 +f 4551/338/27 4553/329/27 4550/337/27 +f 4552/339/27 4553/329/27 4551/338/27 +f 4542/328/27 4553/329/27 4552/339/27 +f 4486/258/17 4507/341/17 4510/340/17 +f 4510/340/17 4482/256/17 4486/258/17 +f 4482/279/151 4510/279/151 4509/282/151 +f 4509/282/151 4505/282/151 4482/279/151 +f 4505/301/23 4509/343/23 4508/342/23 +f 4508/342/23 4512/305/23 4505/301/23 +f 4512/284/198 4508/284/198 4507/283/198 +f 4507/283/198 4486/283/198 4512/284/198 +f 4490/264/15 4513/345/15 4516/344/15 +f 4516/344/15 4488/263/15 4490/264/15 +f 4488/285/7 4516/285/7 4515/285/7 +f 4515/285/7 4511/285/7 4488/285/7 +f 4511/307/21 4515/347/21 4514/346/21 +f 4514/346/21 4518/309/21 4511/307/21 +f 4518/287/197 4514/287/197 4513/286/197 +f 4513/286/197 4490/286/197 4518/287/197 +f 4494/268/13 4519/349/13 4522/348/13 +f 4522/348/13 4492/266/13 4494/268/13 +f 4492/288/163 4522/288/163 4521/289/163 +f 4521/289/163 4517/289/163 4492/288/163 +f 4517/311/19 4521/351/19 4520/350/19 +f 4520/350/19 4524/313/19 4517/311/19 +f 4524/291/10 4520/291/10 4519/290/10 +f 4519/290/10 4494/290/10 4524/291/10 +f 4498/272/23 4525/353/23 4528/352/23 +f 4528/352/23 4496/270/23 4498/272/23 +f 4496/292/153 4528/292/153 4527/293/153 +f 4527/293/153 4523/293/153 4496/292/153 +f 4523/315/17 4527/355/17 4526/354/17 +f 4526/354/17 4530/317/17 4523/315/17 +f 4530/295/196 4526/295/196 4525/294/196 +f 4525/294/196 4498/294/196 4530/295/196 +f 4502/276/21 4531/357/21 4534/356/178 +f 4534/356/178 4500/274/21 4502/276/21 +f 4500/296/1 4534/296/1 4533/297/1 +f 4533/297/1 4529/297/1 4500/296/1 +f 4529/322/15 4533/359/15 4532/358/15 +f 4532/358/15 4536/321/118 4529/322/15 +f 4536/299/195 4532/299/195 4531/298/195 +f 4531/298/195 4502/298/195 4536/299/195 +f 4483/255/19 4537/361/19 4540/360/19 +f 4540/360/19 4504/278/190 4483/255/19 +f 4504/300/161 4540/300/161 4539/300/161 +f 4539/300/161 4535/300/161 4504/300/161 +f 4535/325/192 4539/363/192 4538/362/13 +f 4538/362/13 4506/302/13 4535/325/192 +f 4506/281/4 4538/281/4 4537/280/4 +f 4537/280/4 4483/280/4 4506/281/4 +# 7168 faces + diff --git a/examples/models/obj_loading/castle_diffuse.png b/examples/models/obj_loading/castle_diffuse.png new file mode 100644 index 0000000..c7085a3 Binary files /dev/null and b/examples/models/obj_loading/castle_diffuse.png differ diff --git a/examples/models/obj_loading/dwarf.obj b/examples/models/obj_loading/dwarf.obj deleted file mode 100644 index a24f0c1..0000000 --- a/examples/models/obj_loading/dwarf.obj +++ /dev/null @@ -1,54966 +0,0 @@ -# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware -# File Created: 28.05.2015 21:59:00 - -mtllib Enano_Final_001.mtl - -# -# object Box001 -# - -v 0.387459278107 0.001037180424 -0.000000000000 -v 0.357966661453 0.000561296940 -0.148274183273 -v 0.273977041245 0.000000000000 -0.273975044489 -v 0.148276805878 -0.000561356544 -0.357965648174 -v 0.000002622604 -0.001037240028 -0.387459248304 -v -0.148271799088 -0.001355171204 -0.357965648174 -v -0.273973226547 -0.001466870308 -0.273975044489 -v -0.357964754105 -0.001355171204 -0.148274242878 -v -0.387459278107 -0.001037240028 -0.000000059605 -v -0.357966899872 -0.000561356544 0.148274183273 -v -0.273977279663 -0.000000059605 0.273975014687 -v -0.148276805878 0.000561296940 0.357965707779 -v -0.000002861023 0.001037180424 0.387459278107 -v 0.148271799088 0.001355111599 0.357965588570 -v 0.273973226547 0.001466810703 0.273974895477 -v 0.357964634895 0.001355111599 0.148274123669 -v 0.387031078339 0.161010622978 -0.000428199768 -v 0.357538461685 0.160534739494 -0.148702442646 -v 0.273548841476 0.159973442554 -0.274403274059 -v 0.147848606110 0.159412086010 -0.358393877745 -v -0.000425577164 0.158936202526 -0.387887477875 -v -0.148699998856 0.158618271351 -0.358393877745 -v -0.274401426315 0.158506572247 -0.274403274059 -v -0.358391761780 0.158147990704 -0.148701190948 -v -0.387881040573 0.156506061554 -0.000421762466 -v -0.358393907547 0.158941805363 0.147847235203 -v -0.274405479431 0.159973382950 0.273546814919 -v -0.148705244064 0.160534739494 0.357537508011 -v -0.000431060791 0.161010622978 0.387031078339 -v 0.147843360901 0.161328554153 0.357537388802 -v 0.273545026779 0.161440253258 0.273546695709 -v 0.357536435127 0.161328554153 0.147845864296 -v 0.353100299835 0.160919785500 -0.000428199768 -v 0.326190590858 0.160485565662 -0.135717749596 -v 0.249556064606 0.159973442554 -0.250410705805 -v 0.134863615036 0.159461259842 -0.327046126127 -v -0.000425815582 0.159027040005 -0.353956878185 -v -0.135715484619 0.158736944199 -0.327046126127 -v -0.250409126282 0.158635079861 -0.250410705805 -v -0.327044963837 0.158685207367 -0.135717630386 -v -0.353955745697 0.158622086048 -0.000427186489 -v -0.327047109604 0.159409523010 0.134861409664 -v -0.250412702560 0.159973382950 0.249554216862 -v -0.135720252991 0.160485565662 0.326189637184 -v -0.000430822372 0.160919785500 0.353100419044 -v 0.134859085083 0.161209881306 0.326189637184 -v 0.249552488327 0.161311805248 0.249554157257 -v 0.326188802719 0.161209881306 0.134861171246 -v 0.353296518326 0.087664961815 -0.000232100487 -v 0.326386690140 0.087230741978 -0.135521650314 -v 0.249752044678 0.086718618870 -0.250214606524 -v 0.135059833527 0.086206436157 -0.326850026846 -v -0.000229597092 0.085772216320 -0.353760749102 -v -0.135519504547 0.085482120514 -0.326850026846 -v -0.250212907791 0.085380256176 -0.250214606524 -v -0.326848983765 0.085482120514 -0.135521650314 -v -0.353760719299 0.085772216320 -0.000232160091 -v -0.326851129532 0.086206436157 0.135057389736 -v -0.250216484070 0.086718559265 0.249750316143 -v -0.135524034500 0.087230741978 0.326385736465 -v -0.000234603882 0.087664961815 0.353296518326 -v 0.135055065155 0.087955057621 0.326385736465 -v 0.249748706818 0.088056981564 0.249750256538 -v 0.326384902000 0.087955057621 0.135057270527 -v 0.375676870346 0.177378296852 -0.000472128391 -v 0.364366769791 0.177348017693 -0.000472128391 -v 0.347045183182 0.176916301250 -0.144418120384 -v 0.336596012115 0.176899909973 -0.140089869499 -v 0.265507221222 0.176371395588 -0.266449689865 -v 0.257509708405 0.176371395588 -0.258452177048 -v 0.143476247787 0.175826430321 -0.347988516092 -v 0.139147996902 0.175842821598 -0.337539315224 -v -0.000469446182 0.175364434719 -0.376621156931 -v -0.000469684601 0.175394713879 -0.365310996771 -v -0.144415855408 0.175055742264 -0.347988516092 -v -0.140087604523 0.175095319748 -0.337539315224 -v -0.266447782516 0.174947381020 -0.266449689865 -v -0.258450269699 0.174990177155 -0.258452177048 -v -0.347987651825 0.175055742264 -0.144418120384 -v -0.337538242340 0.175095319748 -0.140089929104 -v -0.376621246338 0.175364434719 -0.000472187996 -v -0.365311145782 0.175394713879 -0.000472187996 -v -0.347989559174 0.175826430321 0.143473863602 -v -0.337540388107 0.175842821598 0.139145612717 -v -0.266451835632 0.176371335983 0.265505313873 -v -0.258454084396 0.176371335983 0.257507801056 -v -0.144420623779 0.176916301250 0.347044229507 -v -0.140092372894 0.176899909973 0.336595058441 -v -0.000474929810 0.177378296852 0.375676870346 -v -0.000474691391 0.177348017693 0.364366769791 -v 0.143471479416 0.177686989307 0.347044229507 -v 0.139143228531 0.177647411823 0.336595058441 -v 0.265503644943 0.177795350552 0.265505313873 -v 0.257506132126 0.177752554417 0.257507801056 -v 0.347043275833 0.177686989307 0.143473744392 -v 0.336594104767 0.177647411823 0.139145493507 -v -0.260723114014 0.157754421234 -0.259547352791 -v 0.188534498215 0.162128329277 0.220312714577 -v 0.150835990906 0.255903840065 -0.122018277645 -v -0.367745399475 0.145474791527 -0.000509381294 -v 0.326006412506 0.188046872616 0.061991870403 -v -0.140351295471 0.145963966846 0.338536977768 -v -0.092543125153 0.133517801762 0.209983170033 -v -0.045091629028 0.219104647636 0.071014165878 -v 0.117162466049 0.138920009136 0.148487687111 -v 0.094516038895 0.211338222027 0.006093084812 -v 0.141849040985 0.167456209660 -0.338641077280 -v -0.132145881653 0.224308967590 -0.168267190456 -v -0.290617465973 0.153861880302 0.041577756405 -v 0.232747793198 0.220157623291 -0.020193576813 -v -0.104435920715 0.156720459461 0.107542216778 -v 0.261220932007 0.215893089771 0.140530586243 -v 0.339339137077 0.144055008888 0.139837384224 -v 0.232198715210 0.238567829132 -0.074207901955 -v 0.139328241348 0.221993207932 -0.251845806837 -v 0.001096725464 0.115566849709 0.232506930828 -v 0.235008478165 0.183093011379 -0.224647879601 -v 0.025869607925 0.220658242702 0.010586977005 -v -0.260028839111 0.142340183258 0.258761763573 -v 0.149353027344 0.195868253708 0.071023166180 -v -0.312650203705 0.150955259800 0.143607854843 -v -0.012047052383 0.257859528065 -0.223151683807 -v -0.092512130737 0.135187923908 0.292060732841 -v -0.015312671661 0.255189657211 -0.138771057129 -v 0.137337684631 0.183658897877 -0.296297132969 -v -0.172811269760 0.177352190018 -0.007483303547 -v 0.223266124725 0.217488348484 0.090728402138 -v 0.064405202866 0.252335906029 -0.226450979710 -v -0.188626766205 0.189203381538 -0.061699330807 -v 0.016028881073 0.124756276608 0.299646496773 -v 0.089669704437 0.233257532120 -0.075778305531 -v 0.139914751053 0.137555956841 0.338332772255 -v 0.284914731979 0.198863744736 -0.022770822048 -v 0.304054975510 0.196833968163 0.028051853180 -v -0.097067356110 0.222885787487 -0.054254412651 -v -0.237313508987 0.144842386246 0.232705712318 -v 0.269050121307 0.216346383095 0.051027357578 -v -0.120793342590 0.202318608761 0.021182298660 -v -0.339625835419 0.138534486294 0.138899505138 -v 0.037177801132 0.231764197350 -0.090419173241 -v 0.143469810486 0.149774491787 0.195432603359 -v 0.293514966965 0.187747895718 -0.097219467163 -v -0.168785572052 0.151870310307 0.060518741608 -v 0.020806550980 0.266882598400 -0.172512531281 -v 0.259666919708 0.145984232426 0.258646607399 -v 0.034334182739 0.252145409584 -0.135116934776 -v -0.140362977982 0.156036436558 -0.339551180601 -v 0.032037258148 0.132924497128 0.150658845901 -v 0.366469740868 0.153844237328 -0.000785291195 -v -0.013993501663 0.172754645348 0.088831484318 -v 0.075382471085 0.258517682552 -0.122498214245 -v -0.144392013550 0.200841248035 -0.234057486057 -v 0.200603008270 0.174400389194 0.172962725163 -v -0.017191648483 0.226316809654 0.000772595406 -v 0.077378988266 0.224100291729 -0.039400041103 -v -0.000497341156 0.134032607079 0.366490840912 -v 0.338284015656 0.156314671040 -0.141668856144 -v -0.153885364532 0.204451203346 -0.099687397480 -v 0.195820569992 0.205458104610 0.131933152676 -v 0.216483592987 0.239142835140 -0.141529560089 -v -0.048132896423 0.252258181572 -0.187425732613 -v 0.048329114914 0.181412041187 0.058874249458 -v 0.297631740570 0.188538789749 0.118461728096 -v 0.094685554504 0.275856882334 -0.177895724773 -v 0.291773080826 0.176003396511 0.168679654598 -v 0.258277654648 0.169047772884 -0.258827954531 -v -0.025267601013 0.222986042500 -0.080369651318 -v -0.082452535629 0.196722209454 -0.287426501513 -v -0.052076101303 0.149037420750 0.130536139011 -v 0.078437328339 0.166446685791 -0.351232022047 -v -0.079320430756 0.196040034294 0.077153921127 -v 0.147503852844 0.252151966095 -0.186089634895 -v -0.237520694733 0.165661454201 -0.003286302090 -v -0.029679536819 0.118149220943 0.186804175377 -v 0.181889533997 0.212109684944 -0.008958518505 -v -0.094622135162 0.229876041412 -0.137650251389 -v 0.069519281387 0.135161101818 0.174413204193 -v 0.278537750244 0.214016139507 0.012907266617 -v -0.000745296478 0.139973580837 0.130587935448 -v 0.161170482635 0.208140671253 0.035515487194 -v -0.166126012802 0.139393448830 0.192975401878 -v 0.290117979050 0.177705764771 -0.146035611629 -v 0.020158529282 0.206230044365 0.052492976189 -v -0.134399890900 0.143064141273 0.142413377762 -v -0.266332864761 0.169014453888 -0.063792705536 -v 0.132324457169 0.250333786011 -0.097359597683 -v 0.001193761826 0.159170746803 -0.367280960083 -v -0.188598394394 0.189268946648 -0.191226005554 -v 0.097879648209 0.156538784504 0.109527528286 -v 0.203623294830 0.224369049072 -0.037161529064 -v -0.129595041275 0.211527705193 -0.041961491108 -v -0.339376449585 0.143820405006 -0.140513777733 -v 0.205133199692 0.213180243969 -0.004063129425 -v 0.233246803284 0.214453101158 -0.008401036263 -v 0.206484079361 0.212388336658 0.016018033028 -v 0.242507219315 0.213977515697 0.010456264019 -v 0.209819316864 0.211635589600 0.041306018829 -v 0.251682043076 0.213515639305 0.034897506237 -v 0.219023942947 0.211915493011 0.102876901627 -v 0.255498886108 0.213328659534 0.102843940258 -v 0.209807872772 0.211321473122 0.073793649673 -v 0.260978460312 0.213306427002 0.070012688637 -v 0.218056917191 0.213957488537 -0.009956002235 -v 0.237318038940 0.212719857693 0.106576442719 -v 0.201871395111 0.223009884357 -0.005214691162 -v 0.234170436859 0.224603056908 -0.010290384293 -v 0.201443910599 0.221436142921 0.017751872540 -v 0.247167825699 0.223902463913 0.009773075581 -v 0.204860687256 0.220546007156 0.042006075382 -v 0.256182670593 0.223231375217 0.033681809902 -v 0.217150449753 0.220006823540 0.104498565197 -v 0.257226705551 0.222062766552 0.105154514313 -v 0.202792167664 0.219771981239 0.074708163738 -v 0.266690969467 0.222605288029 0.069311499596 -v 0.216041564941 0.224303185940 -0.016883432865 -v 0.236886978149 0.220857679844 0.113419055939 -v 0.201165676117 0.241792380810 -0.002464711666 -v 0.235595226288 0.243774831295 -0.008793592453 -v 0.200091838837 0.239008307457 0.019165515900 -v 0.248582601547 0.241591095924 0.009618818760 -v 0.203350067139 0.236650824547 0.041424393654 -v 0.256637573242 0.239299356937 0.032281756401 -v 0.218260288239 0.230036914349 0.104059219360 -v 0.253784656525 0.232075154781 0.103391885757 -v 0.206028461456 0.232413649559 0.076064765453 -v 0.216443300247 0.243729174137 -0.014796018600 -v 0.236021757126 0.231211543083 0.111301779747 -v 0.247812032700 0.238879442215 0.099651157856 -v 0.235158205032 0.239502251148 0.103205502033 -v 0.262071609497 0.235375046730 0.069712936878 -v 0.252540349960 0.260097324848 0.055052101612 -v 0.222467422485 0.237549602985 0.101014792919 -v 0.212550878525 0.258014202118 0.062277555466 -v 0.201892614365 0.345312535763 0.008776485920 -v 0.242216825485 0.349303513765 0.009433805943 -v 0.191249847412 0.342574447393 0.028094410896 -v 0.255865812302 0.346988528967 0.028772234917 -v 0.196735858917 0.339674323797 0.052435636520 -v 0.258110046387 0.343376874924 0.052006244659 -v 0.221249341965 0.348548620939 0.002917945385 -v 0.222075462341 0.356713175774 0.034231722355 -v 0.229865312576 0.337269216776 0.076513707638 -v 0.232888221741 0.263725697994 0.063763737679 -v 0.204312324524 0.270660489798 0.003390491009 -v 0.236067295074 0.272651731968 -0.001152694225 -v 0.200947046280 0.266749739647 0.023094773293 -v 0.249783754349 0.268808007240 0.012558996677 -v 0.202597379684 0.262279391289 0.042629957199 -v 0.255157470703 0.263839781284 0.032649099827 -v 0.218951225281 0.272833973169 -0.005811095238 -v 0.248102664948 0.339510381222 0.071823954582 -v 0.211038351059 0.337233841419 0.072277426720 -v 0.212896347046 0.211532533169 0.087992787361 -v 0.260196208954 0.213362693787 0.086466848850 -v 0.206652641296 0.219657599926 0.088583350182 -v 0.265573501587 0.222268044949 0.086174011230 -v 0.208487510681 0.231236219406 0.089933633804 -v 0.261114358902 0.233485519886 0.086178541183 -v 0.249599456787 0.241804718971 0.087328910828 -v 0.218761682510 0.240887939930 0.090320706367 -v 0.234282970428 0.244165539742 0.089901387691 -v 0.249197959900 0.245250940323 0.071763932705 -v 0.233741044998 0.248610019684 0.075530111790 -v 0.218100309372 0.243478000164 0.076156377792 -v 0.259891033173 0.237450182438 0.052915513515 -v 0.262217521667 0.222825467587 0.053764879704 -v 0.257991552353 0.213336646557 0.054791927338 -v 0.209878206253 0.211354732513 0.060339868069 -v 0.203500509262 0.219918906689 0.060940921307 -v 0.205494880676 0.234648823738 0.060976922512 -v 0.232362031937 0.296486437321 0.068670928478 -v 0.247957706451 0.297481447458 0.058879435062 -v 0.214935302734 0.296461522579 0.063020169735 -v 0.256248474121 0.300734728575 0.041230976582 -v 0.205139160156 0.308436393738 0.010030686855 -v 0.238288879395 0.311282992363 0.009258210659 -v 0.199443340302 0.304088622332 0.028930902481 -v 0.251448392868 0.306685805321 0.022934615612 -v 0.202795028687 0.299219369888 0.047689616680 -v 0.221186876297 0.311318457127 0.002745151520 -v 0.225008487701 0.352216601372 0.053049981594 -v 0.202267408371 0.358467698097 0.014773547649 -v 0.193837165833 0.356905907393 0.031560063362 -v 0.200456142426 0.354091018438 0.051699697971 -v 0.214915990829 0.351570516825 0.066617071629 -v 0.227507829666 0.352972269058 0.069517612457 -v 0.240033149719 0.354288905859 0.067502856255 -v 0.247437715530 0.356183379889 0.048327982426 -v 0.255626201630 0.361346334219 0.031195163727 -v 0.243300676346 0.363204896450 0.016159296036 -v 0.220804214478 0.361127465963 0.011520028114 -v -0.006412744522 0.219254732132 -0.070368289948 -v -0.034497737885 0.219416260719 -0.075179994106 -v -0.007551431656 0.219255983829 -0.050698041916 -v -0.043589591980 0.219416618347 -0.056793034077 -v -0.010588407516 0.219317317009 -0.025610864162 -v -0.052551269531 0.219525873661 -0.032343029976 -v -0.019434452057 0.219501733780 0.036931097507 -v -0.056055307388 0.219407021999 0.036677896976 -v -0.010255813599 0.219376742840 0.007310867310 -v -0.061593055725 0.219416677952 0.003298044205 -v -0.019374847412 0.219313621521 -0.076339542866 -v -0.037804126740 0.219456374645 0.040600121021 -v -0.003419399261 0.229272305965 -0.072110950947 -v -0.035720348358 0.229651033878 -0.077736675739 -v -0.002564668655 0.228819966316 -0.049440383911 -v -0.048538923264 0.229538142681 -0.058115601540 -v -0.005802154541 0.228773951530 -0.025171041489 -v -0.057313680649 0.229480981827 -0.033867120743 -v -0.017800569534 0.228000402451 0.038410604000 -v -0.058048009872 0.228443384171 0.038873791695 -v -0.003192663193 0.228343427181 0.008078634739 -v -0.067610979080 0.228918552399 0.002470076084 -v -0.017654657364 0.229513227940 -0.083801627159 -v -0.037597417831 0.228035628796 0.047402024269 -v -0.003135919571 0.248828172684 -0.071072876453 -v -0.037687301636 0.249413430691 -0.078146457672 -v -0.001599311829 0.247187077999 -0.049244463444 -v -0.050426006317 0.247864484787 -0.059458792210 -v -0.004717350006 0.245696306229 -0.026384413242 -v -0.058178663254 0.246295332909 -0.035779118538 -v -0.019185543060 0.238504111767 0.037673413754 -v -0.054839372635 0.239117026329 0.036907553673 -v -0.006999969482 0.241730749607 0.009231150150 -v -0.018567800522 0.249538004398 -0.083647012711 -v -0.037009954453 0.238889813423 0.044985234737 -v -0.049028873444 0.246678113937 0.033095300198 -v -0.036361932755 0.247815668583 0.036695182323 -v -0.063289403915 0.242662429810 0.002855598927 -v -0.054507970810 0.268849194050 -0.014230966568 -v -0.023601055145 0.246319174767 0.034479141235 -v -0.014294147491 0.268415987492 -0.006592750549 -v -0.007125854492 0.352546513081 -0.070307731628 -v -0.047215461731 0.354491233826 -0.074513196945 -v 0.003531694412 0.351069599390 -0.050791621208 -v -0.060627460480 0.352100074291 -0.057532072067 -v -0.001306772232 0.349359750748 -0.028730213642 -v -0.062292337418 0.349174886942 -0.036085724831 -v -0.026328802109 0.354579001665 -0.078574538231 -v -0.027374744415 0.363825768232 -0.050758659840 -v -0.033916950226 0.346315592527 -0.004494011402 -v -0.034796714783 0.273458153009 -0.005827486515 -v -0.007123708725 0.278406739235 -0.068862497807 -v -0.038926839828 0.278996378183 -0.074869096279 -v -0.003371477127 0.275840729475 -0.048226654530 -v -0.052319049835 0.275491327047 -0.060075223446 -v -0.004662275314 0.272252291441 -0.027530074120 -v -0.057320117950 0.271499335766 -0.038320362568 -v -0.021856307983 0.279480308294 -0.079001605511 -v -0.051886796951 0.346334606409 -0.018019616604 -v -0.015472888947 0.347499132156 -0.012708246708 -v -0.013341426849 0.219453394413 0.021781980991 -v -0.060760498047 0.219377577305 0.020002603531 -v -0.007234573364 0.228128254414 0.022226035595 -v -0.066421747208 0.228480756283 0.019553661346 -v -0.009428262711 0.240280926228 0.023335456848 -v -0.062236309052 0.240545749664 0.019495189190 -v -0.050906419754 0.249981880188 0.020713865757 -v -0.019988298416 0.250182330608 0.023671388626 -v -0.035615205765 0.253143727779 0.023297965527 -v -0.050571680069 0.253851354122 0.004940390587 -v -0.035207986832 0.258085966110 0.008688688278 -v -0.019476890564 0.253200232983 0.009263873100 -v -0.061208486557 0.244841516018 -0.014327108860 -v -0.063190460205 0.229270637035 -0.013317525387 -v -0.058711767197 0.219515621662 -0.012146055698 -v -0.010442733765 0.219379901886 -0.006376981735 -v -0.004127025604 0.228489577770 -0.005963206291 -v -0.006670236588 0.244056880474 -0.006213486195 -v -0.035041809082 0.306504577398 -0.012205660343 -v -0.050817012787 0.305917531252 -0.022203505039 -v -0.017575979233 0.306866586208 -0.015941679478 -v -0.059380531311 0.307994395494 -0.039807379246 -v -0.009127378464 0.316277623177 -0.068142294884 -v -0.042343616486 0.317533701658 -0.072862088680 -v -0.003009557724 0.313361108303 -0.048151373863 -v -0.055118322372 0.313115835190 -0.059049367905 -v -0.005843162537 0.309433162212 -0.029619455338 -v -0.025185585022 0.317963033915 -0.077642977238 -v -0.029360532761 0.360437393188 -0.033840239048 -v -0.013695001602 0.365091145039 -0.063374280930 -v -0.005713224411 0.364561080933 -0.049769103527 -v -0.006861448288 0.363386452198 -0.031659960747 -v -0.019543409348 0.360915482044 -0.018560290337 -v -0.032689571381 0.360493153334 -0.010817825794 -v -0.045087814331 0.359358161688 -0.021629929543 -v -0.058130502701 0.362013280392 -0.034903645515 -v -0.055710792542 0.363338232040 -0.056892096996 -v -0.040955543518 0.367505073547 -0.065858364105 -v -0.026666879654 0.366931766272 -0.066344976425 -v 0.019335746765 0.891146719456 0.147463440895 -v 0.077193498611 0.876855552197 -0.156872689724 -v 0.077016353607 0.674709022045 -0.110481500626 -v 0.026651859283 0.777218222618 0.134643375874 -v 0.027640104294 0.662163913250 0.117864131927 -v 0.092115879059 0.819933474064 0.165385544300 -v 0.022340536118 0.851363182068 0.150859296322 -v 0.081831455231 0.861464142799 0.176887631416 -v 0.145524740219 0.883852779865 0.172923028469 -v 0.158493518829 0.841617703438 0.157872855663 -v 0.277504920959 1.007843017578 0.047269701958 -v 0.272853851318 1.025377511978 0.051120281219 -v 0.286534786224 1.034585952759 0.047402620316 -v 0.302318572998 0.995641767979 0.049039125443 -v 0.262354612350 0.997510433197 0.039628624916 -v 0.254748582840 1.029515981674 0.052300691605 -v 0.286922931671 0.964170455933 0.051867485046 -v 0.263444900513 0.934777021408 -0.010773301125 -v 0.278232336044 0.898669064045 -0.017279744148 -v 0.282225131989 0.895403862000 -0.048148393631 -v 0.268206119537 0.922013401985 -0.048899114132 -v 0.263873815536 0.932216346264 -0.047488868237 -v 0.249542474747 0.950950801373 -0.014343142509 -v 0.242866039276 0.973144650459 0.013231754303 -v 0.257011651993 0.958706617355 0.025045931339 -v 0.272060394287 0.937663674355 0.036257743835 -v 0.267414808273 0.922991752625 0.012871444225 -v 0.282770156860 0.902756571770 0.011130094528 -v 0.123666524887 0.582465767860 -0.075673460960 -v 0.149766921997 0.525964796543 -0.038310170174 -v 0.177918195724 0.547954797745 -0.041567981243 -v 0.164103984833 0.607049584389 -0.064459025860 -v 0.103845834732 0.528503477573 -0.026832699776 -v 0.132575511932 0.506744384766 -0.010294854641 -v 0.262545824051 0.962624549866 -0.120018243790 -v 0.277079582214 0.942464232445 -0.121075093746 -v 0.283565044403 0.978037595749 -0.130021154881 -v 0.242907762527 1.002508759499 -0.135505557060 -v 0.261280298233 0.944051027298 -0.092559337616 -v 0.272555112839 0.925887763500 -0.087273895741 -v 0.231066703796 0.961506426334 -0.136641144753 -v 0.218405961990 0.840843498707 0.091216206551 -v 0.210432529449 0.794565856457 0.084894001484 -v 0.186074256897 0.768438935280 0.106157541275 -v 0.168217658997 0.802124977112 0.130858242512 -v 0.239678859711 0.831269502640 0.040043413639 -v 0.225566387177 0.781253993511 0.055830478668 -v 0.209580659866 0.882061362267 0.132225513458 -v 0.155940294266 0.740337014198 0.119884729385 -v 0.106715440750 0.770864248276 0.151021718979 -v 0.178981781006 0.699676811695 0.084566056728 -v 0.182432651520 0.725065171719 0.095114350319 -v 0.204370975494 0.743299126625 0.076818108559 -v 0.213043212891 0.707077801228 0.041539013386 -v 0.136242151260 0.711864829063 0.109547138214 -v 0.155378341675 0.589013695717 0.109423935413 -v 0.137723207474 0.638659536839 0.112122654915 -v 0.171539545059 0.636296868324 0.090351223946 -v 0.201073408127 0.608585000038 0.070430636406 -v 0.217098474503 0.565734565258 0.062991678715 -v 0.191636562347 0.555289149284 0.088190674782 -v 0.150764703751 1.090515971184 0.031594216824 -v 0.133168458939 1.064684152603 0.068517208099 -v 0.107606649399 1.083139657974 0.037304639816 -v 0.119329452515 1.104554176331 0.014675736427 -v 0.187176704407 1.110415458679 0.029244542122 -v 0.202834844589 1.080092191696 0.052686989307 -v 0.179083585739 1.058245539665 0.064180791378 -v 0.160923242569 1.034242868423 0.096240758896 -v 0.254607439041 1.061115264893 0.052536368370 -v 0.220592498779 1.047652482986 0.058174490929 -v 0.231979370117 1.086294531822 0.047397136688 -v 0.231719017029 1.019516706467 0.049612939358 -v 0.293545246124 0.912459313869 0.040535092354 -v 0.235724687576 1.107659101486 0.028177142143 -v 0.274882793427 1.085638523102 0.028672218323 -v 0.096796751022 0.524665117264 0.020752966404 -v 0.121049642563 1.164031744003 -0.039851784706 -v 0.109050750732 1.171761870384 -0.060386240482 -v 0.151132822037 1.143172383308 -0.073541879654 -v 0.162862539291 1.139242529869 -0.047275900841 -v 0.166463375092 1.129762411118 -0.013145327568 -v 0.125269412994 1.148490905762 -0.022257208824 -v 0.222014427185 1.136164307594 -0.085919082165 -v 0.229552507401 1.134870767593 -0.049831032753 -v 0.233881950378 1.128509044647 -0.008981227875 -v 0.281436681747 1.108168125153 -0.051254689693 -v 0.281991004944 1.102712631226 -0.009698688984 -v 0.317685604095 1.067490458488 -0.049807429314 -v 0.317203044891 1.065495610237 -0.009583413601 -v 0.306344747543 1.052000999451 0.026935875416 -v 0.343569040298 1.024486541748 -0.007518947124 -v 0.329200625420 1.013627648354 0.025783419609 -v 0.366793274879 0.985834360123 -0.007350325584 -v 0.354122877121 0.976988136768 0.026278495789 -v 0.334745645523 0.958747029305 0.052049517632 -v 0.379283428192 0.947536230087 0.020861685276 -v 0.362321138382 0.928932666779 0.043664336205 -v 0.342812895775 0.907195210457 0.044864654541 -v 0.314275741577 0.935671687126 0.057043790817 -v 0.319790363312 0.888074278831 0.029314041138 -v 0.379310607910 0.902640283108 0.024499237537 -v 0.358928322792 0.880074322224 0.019105792046 -v 0.338169336319 0.861247479916 0.001740396023 -v 0.400299787521 0.877586364746 0.025739133358 -v 0.380050063133 0.852149724960 0.022235631943 -v 0.363364696503 0.827350735664 0.010587811470 -v 0.362974047661 0.811894834042 -0.017841279507 -v 0.332549810410 0.850514173508 -0.031367659569 -v 0.376002192497 0.802355408669 -0.049095809460 -v 0.339113950729 0.838486850262 -0.071368515491 -v 0.312850952148 0.871554672718 -0.076692581177 -v 0.306100845337 0.872793436050 -0.043697237968 -v 0.402581334114 0.810562849045 -0.068494379520 -v 0.367998600006 0.846436321735 -0.105324327946 -v 0.326204538345 0.882910430431 -0.107103466988 -v 0.432064533234 0.831387817860 -0.069692969322 -v 0.409785628319 0.862663328648 -0.103722870350 -v 0.452204942703 0.860042333603 -0.057465374470 -v 0.432444095612 0.890474557877 -0.088653087616 -v 0.403483510017 0.924710273743 -0.103032827377 -v 0.390702843666 0.900007128716 -0.125450611115 -v 0.458554625511 0.884764671326 -0.038810074329 -v 0.440712213516 0.916401028633 -0.064721584320 -v 0.409626007080 0.946123480797 -0.076701641083 -v 0.377049446106 0.978414773941 -0.079899370670 -v 0.369030594826 0.959930837154 -0.107197761536 -v 0.434939265251 0.931571722031 -0.036256074905 -v 0.403420209885 0.955381631851 -0.043758153915 -v 0.375007867813 0.986278414726 -0.043334543705 -v 0.346902847290 1.024103283882 -0.045506417751 -v 0.346037387848 1.015392422676 -0.082815170288 -v 0.391106963158 0.955277502537 -0.011757612228 -v 0.418347239494 0.931938529015 -0.009633421898 -v 0.398629426956 0.921277165413 0.011540293694 -v 0.441792011261 0.907627224922 0.005505323410 -v 0.420485854149 0.897287666798 0.019965410233 -v 0.454711556435 0.901762425900 -0.017239570618 -v 0.312911748886 1.057415366173 -0.085565030575 -v 0.301878452301 1.036462783813 -0.110103130341 -v 0.341517090797 0.998458266258 -0.115687966347 -v 0.291906356812 1.012423157692 -0.127237200737 -v 0.328496098518 0.970709323883 -0.136209249496 -v 0.354727029800 0.934686720371 -0.121113419533 -v 0.311561107635 0.939342975616 -0.134227514267 -v 0.340052127838 0.908680558205 -0.124131619930 -v 0.367459774017 0.884051918983 -0.123385787010 -v 0.297220230103 0.911664009094 -0.117913901806 -v 0.289204835892 0.899315834045 -0.083201110363 -v 0.250025033951 1.053760290146 -0.137834787369 -v 0.264823913574 1.083865046501 -0.119606435299 -v 0.201839447021 1.117434144020 -0.118024945259 -v 0.189693689346 1.079212427139 -0.142952740192 -v 0.277281999588 1.102975010872 -0.089239239693 -v 0.120431184769 1.085181832314 -0.138198077679 -v 0.121253252029 1.037931799889 -0.155860960484 -v 0.184354066849 1.029958724976 -0.157751560211 -v 0.119925260544 1.132153749466 -0.108325600624 -v 0.123482465744 0.987731099129 -0.170279264450 -v 0.180538892746 0.979573845863 -0.163978517056 -v 0.125545501709 0.932765841484 -0.173250615597 -v 0.179258108139 0.925383329391 -0.162734568119 -v 0.227316141129 0.914090216160 -0.128659784794 -v 0.178707361221 0.866539001465 -0.151616394520 -v 0.224370002747 0.859528779984 -0.116147398949 -v 0.256502151489 0.857412219048 -0.071282267570 -v 0.259006500244 0.905853331089 -0.084065675735 -v 0.258020401001 0.867200314999 -0.023059964180 -v 0.263725519180 0.906981647015 -0.038188934326 -v 0.246686458588 0.885027527809 0.019917786121 -v 0.248519420624 0.927023947239 0.000404238701 -v 0.239131689072 0.904338777065 0.060729622841 -v 0.241918325424 0.948883771896 0.032647311687 -v 0.229748249054 0.932023048401 0.094542920589 -v 0.231833934784 0.972128450871 0.056386351585 -v 0.237094879150 0.996514856815 0.032092094421 -v 0.225894212723 0.997993648052 0.079689145088 -v 0.216531753540 0.964301168919 0.116260170937 -v 0.190495014191 0.998777031898 0.114465355873 -v 0.204521656036 1.026806235313 0.079624712467 -v 0.192690134048 0.921263933182 0.150567412376 -v 0.164333105087 0.961874485016 0.145105898380 -v 0.135314941406 1.002291202545 0.123882234097 -v 0.122396469116 0.928251743317 0.165373027325 -v 0.099461555481 0.973314642906 0.142395615578 -v 0.080953598022 1.017653703690 0.112643778324 -v 0.110545635223 1.040468931198 0.096353948116 -v 0.067555904388 1.051582455635 0.072920858860 -v 0.089736461639 1.065327763557 0.058615803719 -v 0.057373523712 0.952757716179 0.147553682327 -v 0.047913312912 1.000822305679 0.117389440536 -v 0.042551279068 1.041895747185 0.078767657280 -v 0.069515228271 0.905283331871 0.168992578983 -v 0.244445800781 0.817365288734 -0.006311953068 -v 0.244346380234 0.804270505905 -0.054641485214 -v 0.217851400375 0.751652359962 -0.033641099930 -v 0.227277755737 0.763818323612 0.012114584446 -v 0.197771310806 0.745314657688 -0.074247181416 -v 0.188985824585 0.683782935143 -0.054120063782 -v 0.209798336029 0.693763196468 -0.014226317406 -v 0.216273546219 0.801639676094 -0.098835766315 -v 0.174543857574 0.806066751480 -0.130712211132 -v 0.165594577789 0.745285034180 -0.103144109249 -v 0.123121976852 0.748481452465 -0.116453528404 -v 0.120306491852 0.673266887665 -0.099647700787 -v 0.158249378204 0.678283751011 -0.080645978451 -v 0.126316308975 0.812821507454 -0.142758727074 -v 0.126960277557 0.873750686646 -0.163805663586 -v 0.068856477737 0.984705030918 -0.177298188210 -v 0.055420398712 1.084348678589 -0.154314756393 -v 0.046322107315 1.128087520599 -0.128710865974 -v 0.075109720230 0.593776226044 -0.089249253273 -v 0.192573547363 0.621916353703 -0.036496400833 -v 0.203611850739 0.571760535240 -0.021339297295 -v 0.217868804932 0.595229387283 0.017003238201 -v 0.213207960129 0.638992846012 0.003613412380 -v 0.204703092575 0.652575969696 0.048748970032 -v 0.170325040817 0.665199697018 0.078543841839 -v 0.130563020706 0.677610635757 0.104269742966 -v 0.083450555801 0.650120198727 0.126545190811 -v 0.081408262253 0.691678225994 0.131133735180 -v 0.086372137070 0.729118704796 0.137566983700 -v 0.026894569397 0.740492343903 0.127000212669 -v 0.088793277740 0.606545627117 0.116948366165 -v 0.091482639313 0.568313062191 0.093596041203 -v 0.093423366547 0.540040552616 0.060054659843 -v 0.137021780014 0.550631523132 0.090929865837 -v 0.129982471466 0.524636745453 0.061635315418 -v 0.129219055176 0.512163639069 0.027145802975 -v 0.155890464783 0.512163281441 0.061540365219 -v 0.151852607727 0.501129508018 0.032996356487 -v 0.151466369629 0.490233093500 0.004889369011 -v 0.164501428604 0.473722547293 0.017774462700 -v 0.166211366653 0.483703285456 0.041170895100 -v 0.176519632339 0.462068229914 0.050208270550 -v 0.178006410599 0.457004278898 0.029782295227 -v 0.190201759338 0.459076434374 0.014697730541 -v 0.178750276566 0.478803396225 0.000907838345 -v 0.166320323944 0.497839301825 -0.015286624432 -v 0.207526922226 0.465957105160 0.009304404259 -v 0.199348926544 0.490522235632 -0.004005312920 -v 0.189775466919 0.514920592308 -0.020356297493 -v 0.225358963013 0.475811570883 0.017339110374 -v 0.221742391586 0.505469441414 0.004819691181 -v 0.213993549347 0.536153674126 -0.007584154606 -v 0.236834526062 0.485237836838 0.038113415241 -v 0.233140468597 0.520117580891 0.029869019985 -v 0.226602554321 0.556548476219 0.023947119713 -v 0.239451885223 0.491162627935 0.065631270409 -v 0.229833841324 0.528143048286 0.060667395592 -v 0.239911079407 0.454511433840 0.042522192001 -v 0.245521306992 0.457225382328 0.067053318024 -v 0.237636566162 0.455539733171 0.084717154503 -v 0.226967334747 0.489047199488 0.082951843739 -v 0.211964607239 0.523329734802 0.080300390720 -v 0.217800378799 0.450385510921 0.087392747402 -v 0.206350564957 0.480243116617 0.084223449230 -v 0.190374135971 0.509804129601 0.078286647797 -v 0.183592557907 0.468741506338 0.072134256363 -v 0.173839807510 0.494874238968 0.062670707703 -v 0.168895244598 0.532966911793 0.083921194077 -v 0.194311380386 0.443297296762 0.078714847565 -v 0.186420440674 0.440069437027 0.057327508926 -v 0.193065404892 0.417387604713 0.057190775871 -v 0.203305721283 0.417975842953 0.076225996017 -v 0.205404996872 0.391247153282 0.066273987293 -v 0.194074869156 0.392329305410 0.049775362015 -v 0.190062761307 0.393557667732 0.030566751957 -v 0.192551136017 0.417236864567 0.037556171417 -v 0.188753843307 0.438155025244 0.037616431713 -v 0.199758052826 0.395951777697 0.012652158737 -v 0.201189756393 0.418664783239 0.020802915096 -v 0.198827505112 0.439186781645 0.022741913795 -v 0.220117330551 0.398994356394 0.008019566536 -v 0.217715263367 0.422239899635 0.015295565128 -v 0.213492631912 0.443650007248 0.018471002579 -v 0.236896991730 0.400686651468 0.011681675911 -v 0.232114553452 0.425558745861 0.022678315639 -v 0.227942943573 0.449451982975 0.025451838970 -v 0.247877597809 0.399994522333 0.024417579174 -v 0.242132186890 0.427206337452 0.038007915020 -v 0.250198125839 0.367911368608 0.023290991783 -v 0.239138841629 0.370674878359 0.011764705181 -v 0.234215259552 0.326959192753 0.024860799313 -v 0.239667415619 0.325394153595 0.032651007175 -v 0.239298582077 0.323285490274 0.041500747204 -v 0.250197172165 0.363285213709 0.041953921318 -v 0.248555660248 0.397186785936 0.044638574123 -v 0.236860036850 0.320421725512 0.050307810307 -v 0.239134788513 0.358723700047 0.058663964272 -v 0.239214897156 0.393967717886 0.063256323338 -v 0.230540990829 0.316507697105 0.058507502079 -v 0.225771665573 0.354905188084 0.069335877895 -v 0.224077701569 0.390892267227 0.075807273388 -v 0.220066547394 0.317402213812 0.054555177689 -v 0.211529970169 0.357036679983 0.059551179409 -v 0.212295293808 0.320155978203 0.044720351696 -v 0.198891878128 0.359852999449 0.045892953873 -v 0.208841085434 0.323172211647 0.033653140068 -v 0.194800376892 0.364280372858 0.028407096863 -v 0.212930202484 0.325841575861 0.024493038654 -v 0.203210353851 0.368161261082 0.013654232025 -v 0.223614931107 0.327202796936 0.020913243294 -v 0.221999883652 0.371129333973 0.011114120483 -v 0.299593925476 0.875928103924 -0.016731262207 -v 0.305377960205 0.881739974022 0.006167829037 -v 0.124761581421 1.127089619637 -0.005370020866 -v 0.144920587540 1.114051818848 -0.000504493713 -v 0.320274353027 0.867451727390 -0.003048002720 -v 0.317344665527 0.863656222820 -0.015280425549 -v 0.081691741943 1.171155452728 -0.082533001900 -v 0.489620566368 0.754746913910 0.055047810078 -v 0.492703795433 0.744488835335 0.057417750359 -v 0.500872254372 0.748085975647 0.052790284157 -v 0.503330826759 0.759612381458 0.050021946430 -v 0.455907583237 0.767686963081 0.180662214756 -v 0.448605775833 0.763490140438 0.179388940334 -v 0.454131126404 0.774452686310 0.183209419250 -v 0.512239336967 0.719803869724 0.108971118927 -v 0.513665318489 0.712346911430 0.098931610584 -v 0.501137852669 0.723156571388 0.088684141636 -v 0.498448848724 0.729723930359 0.098093867302 -v 0.506369471550 0.735136747360 0.129543185234 -v 0.510510444641 0.727772593498 0.119067549706 -v 0.495698451996 0.736607313156 0.107330560684 -v 0.491642713547 0.742265939713 0.117717981339 -v 0.492995619774 0.730934858322 0.070337891579 -v 0.488109588623 0.732578217983 0.080537736416 -v 0.505285978317 0.719612061977 0.078231096268 -v 0.525172829628 0.681995272636 0.167945027351 -v 0.521392345428 0.683978497982 0.175799846649 -v 0.521812319756 0.691806197166 0.180061340332 -v 0.519139647484 0.787753224373 0.090079247952 -v 0.529436826706 0.773348331451 0.102756619453 -v 0.523522257805 0.779470205307 0.115589499474 -v 0.511284351349 0.795331001282 0.102586388588 -v 0.539867997169 0.729618787766 0.089468300343 -v 0.531417727470 0.747590124607 0.073452115059 -v 0.527307748795 0.738277912140 0.066966652870 -v 0.535834193230 0.725835144520 0.077996909618 -v 0.523569345474 0.720503687859 0.128831326962 -v 0.526804924011 0.719818413258 0.135298848152 -v 0.537645578384 0.725556254387 0.133212625980 -v 0.540601491928 0.730802595615 0.123283326626 -v 0.534850597382 0.748413085938 0.143720269203 -v 0.533050775528 0.738149583340 0.147188425064 -v 0.521691203117 0.732560038567 0.148685574532 -v 0.515544414520 0.738024771214 0.147808253765 -v 0.521300554276 0.711467444897 0.118006944656 -v 0.506483316422 0.747644484043 0.153991520405 -v 0.502677559853 0.742156207561 0.140237092972 -v 0.501390576363 0.751134574413 0.149526238441 -v 0.541826605797 0.742310583591 0.123451471329 -v 0.541710376740 0.746488988400 0.128475904465 -v 0.540703296661 0.751621305943 0.123491525650 -v 0.541983366013 0.746656119823 0.119618058205 -v 0.532743930817 0.764434099197 0.148749291897 -v 0.529609441757 0.768829822540 0.144122123718 -v 0.533065080643 0.763605058193 0.139945745468 -v 0.534711122513 0.759675085545 0.143647730350 -v 0.519114732742 0.724147796631 0.142600655556 -v 0.515840530396 0.728727519512 0.137992262840 -v 0.540112376213 0.734770715237 0.138869524002 -v 0.540696740150 0.740617036819 0.133606433868 -v 0.522036075592 0.709590852261 0.079642355442 -v 0.515752315521 0.708322763443 0.088428199291 -v 0.523067712784 0.698891818523 0.096575498581 -v 0.528108596802 0.700006604195 0.087751507759 -v 0.538988947868 0.715688526630 0.081110537052 -v 0.540867447853 0.712676644325 0.084093391895 -v 0.543041229248 0.715164959431 0.088397443295 -v 0.540838479996 0.719581723213 0.084006726742 -v 0.506251692772 0.761048257351 0.153887510300 -v 0.509725928307 0.757334053516 0.158531010151 -v 0.525017738342 0.770337998867 0.149724423885 -v 0.527247309685 0.767623901367 0.152778089046 -v 0.526124477386 0.703662514687 0.107429325581 -v 0.541818618774 0.721548616886 0.089130938053 -v 0.543096542358 0.717609286308 0.092653989792 -v 0.514024734497 0.685954689980 0.172047317028 -v 0.515303611755 0.692099928856 0.177232980728 -v 0.518338084221 0.682923436165 0.165953993797 -v 0.535277485847 0.708344936371 0.147681176662 -v 0.524157166481 0.704845070839 0.148237943649 -v 0.523532152176 0.699540019035 0.152397453785 -v 0.534913420677 0.702481508255 0.152555465698 -v 0.519562959671 0.716747760773 0.161118566990 -v 0.530426263809 0.720963180065 0.161624073982 -v 0.530594706535 0.714648783207 0.166401624680 -v 0.519082903862 0.711292505264 0.165497899055 -v 0.516831398010 0.709372937679 0.154453039169 -v 0.516183376312 0.703925609589 0.158576548100 -v 0.538677573204 0.715157747269 0.155361831188 -v 0.538471341133 0.711140751839 0.158608913422 -v 0.533556699753 0.693566560745 0.159267961979 -v 0.521171927452 0.692192018032 0.156506180763 -v 0.519478797913 0.686819851398 0.160811662674 -v 0.531105518341 0.687699437141 0.163550257683 -v 0.516932487488 0.704223155975 0.170683681965 -v 0.529407978058 0.705302298069 0.173214852810 -v 0.527298688889 0.699028372765 0.177262067795 -v 0.515662312508 0.698305785656 0.174661695957 -v 0.512620925903 0.697871327400 0.162089228630 -v 0.511643767357 0.691746532917 0.166646361351 -v 0.537143468857 0.698810040951 0.168046832085 -v 0.535217404366 0.695275962353 0.170467853546 -v 0.537539839745 0.719420015812 0.138411521912 -v 0.526125192642 0.715106844902 0.139984965324 -v 0.524770259857 0.710178494453 0.144071102142 -v 0.534347414970 0.711749315262 0.141898036003 -v 0.521291613579 0.727184534073 0.152451038361 -v 0.531763315201 0.732593894005 0.152449965477 -v 0.526586532593 0.727051615715 0.158230066299 -v 0.519834280014 0.721794843674 0.156188130379 -v 0.519172072411 0.719282746315 0.146682977676 -v 0.518319606781 0.714717566967 0.150376081467 -v 0.542425036430 0.726674139500 0.146438956261 -v 0.541626691818 0.720945656300 0.142000854015 -v 0.540896654129 0.716939508915 0.144021809101 -v 0.542814254761 0.723198592663 0.149447917938 -v 0.538549065590 0.730741381645 0.152049660683 -v 0.537324070930 0.727843642235 0.155685722828 -v 0.540292024612 0.714531242847 0.147353291512 -v 0.541417002678 0.719230473042 0.152375280857 -v 0.537661671638 0.723493218422 0.157489120960 -v 0.522315740585 0.696558475494 0.153652429581 -v 0.532957553864 0.696634590626 0.154145359993 -v 0.526823282242 0.710777997971 0.170685768127 -v 0.517996311188 0.707997262478 0.167178988457 -v 0.514600038528 0.702156662941 0.159258484840 -v 0.540738582611 0.708825647831 0.160881042480 -v 0.539718866348 0.703809440136 0.156380772591 -v 0.539808750153 0.700395345688 0.157848179340 -v 0.541602373123 0.705698668957 0.163604915142 -v 0.537238717079 0.712285995483 0.166008591652 -v 0.536659955978 0.709942877293 0.169121146202 -v 0.539298772812 0.698089897633 0.160789132118 -v 0.540274739265 0.702055811882 0.166186392307 -v 0.536662101746 0.706197261810 0.170638501644 -v 0.540821313858 0.729771852493 0.143572688103 -v 0.534619212151 0.690335750580 0.174641072750 -v 0.534919500351 0.687159657478 0.171165943146 -v 0.534467816353 0.684770822525 0.172516167164 -v 0.533648490906 0.687150001526 0.176869094372 -v 0.533669948578 0.692957580090 0.178517937660 -v 0.532203197479 0.690804123878 0.179874420166 -v 0.528633236885 0.684847950935 0.177231550217 -v 0.531227588654 0.682927608490 0.170618474483 -v 0.534844160080 0.687096238136 0.168217778206 -v 0.534787893295 0.692861855030 0.172489643097 -v 0.532088637352 0.695515155792 0.178507089615 -v 0.528244614601 0.691161870956 0.180853903294 -v 0.542320370674 0.728663325310 0.099375784397 -v 0.542763829231 0.724370181561 0.102947711945 -v 0.543692111969 0.728317677975 0.108140170574 -v 0.543245792389 0.733878433704 0.103289365768 -v 0.539205074310 0.750491321087 0.133062005043 -v 0.538523197174 0.754346132278 0.129205644131 -v 0.543280839920 0.732618570328 0.112749457359 -v 0.543036103249 0.737028181553 0.108903169632 -v 0.531576871872 0.715822875500 0.076436996460 -v 0.537781238556 0.706454157829 0.084965169430 -v 0.516264319420 0.770024180412 0.150568723679 -v 0.521349906921 0.763900756836 0.157923758030 -v 0.548167467117 0.667905509472 0.148447632790 -v 0.546362757683 0.670237898827 0.157298624516 -v 0.545064449310 0.678077816963 0.161700785160 -v 0.530092954636 0.702552258968 0.114723563194 -v 0.540755271912 0.707639873028 0.112147867680 -v 0.542485356331 0.714294910431 0.102276742458 -v 0.538369178772 0.719116032124 0.127693057060 -v 0.527642726898 0.713942587376 0.130929112434 -v 0.524290800095 0.705752372742 0.123955726624 -v 0.543419122696 0.722295403481 0.112965941429 -v 0.543574094772 0.715997815132 0.118450582027 -v 0.538602828979 0.668676257133 0.156609654427 -v 0.538909435272 0.675573229790 0.161329925060 -v 0.541661739349 0.665838003159 0.149098932743 -v 0.544516205788 0.691595375538 0.125912368298 -v 0.534333825111 0.686268508434 0.128116250038 -v 0.535755872726 0.680908918381 0.132590770721 -v 0.546100020409 0.686485588551 0.130807101727 -v 0.530930757523 0.697768330574 0.144220829010 -v 0.540539383888 0.703372836113 0.142738342285 -v 0.542316913605 0.698138594627 0.147101879120 -v 0.532684803009 0.692637383938 0.148399233818 -v 0.528201103210 0.689944863319 0.137334823608 -v 0.529621005058 0.684429168701 0.141547918320 -v 0.547267079353 0.699201166630 0.134586215019 -v 0.548285603523 0.695777177811 0.137413918972 -v 0.549032688141 0.678514897823 0.138707518578 -v 0.538316488266 0.672254383564 0.139705061913 -v 0.539997816086 0.668147265911 0.143931210041 -v 0.549917817116 0.673808932304 0.142802059650 -v 0.535045385361 0.684714317322 0.155533432961 -v 0.545179843903 0.690104901791 0.154163777828 -v 0.546261072159 0.685271203518 0.157988131046 -v 0.536641716957 0.680283010006 0.159242749214 -v 0.531511306763 0.676025629044 0.148519396782 -v 0.533580183983 0.671684741974 0.152756392956 -v 0.551849842072 0.686028897762 0.146424531937 -v 0.552071809769 0.683168113232 0.148839414120 -v 0.542264461517 0.702010095119 0.117023289204 -v 0.531574487686 0.696618914604 0.119827747345 -v 0.533209562302 0.691803276539 0.124981045723 -v 0.542015671730 0.694402575493 0.120017051697 -v 0.527886033058 0.708098948002 0.135989665985 -v 0.538574695587 0.713628768921 0.133871257305 -v 0.536827564240 0.708746492863 0.140737891197 -v 0.529211044312 0.702663362026 0.140047073364 -v 0.525272846222 0.700050890446 0.129155695438 -v 0.527511239052 0.695425748825 0.133208036423 -v 0.547236084938 0.709693551064 0.126150548458 -v 0.546826839447 0.704466640949 0.120804965496 -v 0.547609567642 0.700840175152 0.122550547123 -v 0.548392534256 0.706934809685 0.128966629505 -v 0.544142603874 0.712298274040 0.132492303848 -v 0.544166088104 0.709887802601 0.136017978191 -v 0.548007726669 0.698595046997 0.125999212265 -v 0.548170447350 0.703358292580 0.131739497185 -v 0.545077085495 0.706430852413 0.137581646442 -v 0.536803126335 0.676721870899 0.136981487274 -v 0.546262025833 0.680178046227 0.133575916290 -v 0.541578054428 0.694177865982 0.152556836605 -v 0.533885598183 0.688042283058 0.151733100414 -v 0.530973911285 0.680204808712 0.144950151443 -v 0.550747156143 0.694574475288 0.139328360558 -v 0.550565600395 0.689205110073 0.134101927280 -v 0.551587820053 0.686272799969 0.135594725609 -v 0.551995396614 0.692323207855 0.141612648964 -v 0.547929286957 0.697340607643 0.145395517349 -v 0.548542022705 0.695518493652 0.148347735405 -v 0.552347660065 0.684621572495 0.138660132885 -v 0.552754878998 0.689439475536 0.144070029259 -v 0.549746870995 0.692574083805 0.149577498436 -v 0.544905066490 0.711640059948 0.123353600502 -v 0.554090023041 0.679983973503 0.152069270611 -v 0.554366350174 0.676740288734 0.148733615875 -v 0.555369496346 0.674915611744 0.149775743484 -v 0.555078744888 0.677470684052 0.154006123543 -v 0.553590416908 0.682599842548 0.155873715878 -v 0.553566455841 0.680583536625 0.157422304153 -v 0.552198171616 0.673865497112 0.155969619751 -v 0.553200006485 0.671683013439 0.148962199688 -v 0.553523778915 0.675942182541 0.146138072014 -v 0.552976369858 0.681672930717 0.150468468666 -v 0.551427602768 0.684173226357 0.156823754311 -v 0.550627708435 0.679804623127 0.159817218781 -v 0.561773300171 0.667005836964 0.108489274979 -v 0.562437891960 0.667055547237 0.116291821003 -v 0.561485767365 0.672465205193 0.121660053730 -v 0.532580971718 0.693629801273 0.092338800430 -v 0.540351271629 0.699979722500 0.089606344700 -v 0.542522072792 0.705165266991 0.104129672050 -v 0.533750057220 0.698765039444 0.106722295284 -v 0.530255436897 0.693876147270 0.100649118423 -v 0.544795274734 0.705484151840 0.095455408096 -v 0.543451189995 0.710095763206 0.092419564724 -v 0.556688308716 0.663857758045 0.117876172066 -v 0.557191729546 0.668581724167 0.123596191406 -v 0.557321429253 0.663886785507 0.110297203064 -v 0.550040364265 0.687514245510 0.096655666828 -v 0.542815566063 0.681384682655 0.099399805069 -v 0.546362757683 0.677153646946 0.101630270481 -v 0.552957534790 0.683309435844 0.099402546883 -v 0.543991684914 0.686676859856 0.113965272903 -v 0.550568699837 0.692732572556 0.109966218472 -v 0.552548170090 0.688747942448 0.112151980400 -v 0.546415090561 0.682839512825 0.116651713848 -v 0.540330171585 0.681044578552 0.107999801636 -v 0.543417692184 0.676724195480 0.110768854618 -v 0.553754329681 0.691745519638 0.102674782276 -v 0.555277824402 0.688932120800 0.104441046715 -v 0.558210253716 0.676781058311 0.102892100811 -v 0.551411271095 0.670395851135 0.105135142803 -v 0.554313540459 0.666436553001 0.107223451138 -v 0.560604929924 0.672852039337 0.104644954205 -v 0.551035642624 0.676183104515 0.121510207653 -v 0.557325959206 0.682806491852 0.115938246250 -v 0.559729456902 0.679148495197 0.118263065815 -v 0.554118156433 0.672260820866 0.123688340187 -v 0.547722101212 0.669512152672 0.114816784859 -v 0.551224112511 0.665718138218 0.116806447506 -v 0.561138749123 0.681422650814 0.108677029610 -v 0.562478303909 0.679623842239 0.109518647194 -v 0.544580936432 0.695759892464 0.091603696346 -v 0.536828517914 0.688898324966 0.094865858555 -v 0.539610147476 0.684746026993 0.097163736820 -v 0.545929908752 0.689909696579 0.093230366707 -v 0.538297772408 0.693749725819 0.109103918076 -v 0.546232938766 0.700979232788 0.105687260628 -v 0.547426342964 0.696206927299 0.109800815582 -v 0.541006326675 0.689810454845 0.111045122147 -v 0.534368872643 0.688101053238 0.103304982185 -v 0.538012027740 0.685010075569 0.105363309383 -v 0.550858020782 0.700949549675 0.097763538361 -v 0.549491643906 0.697909832001 0.093589007854 -v 0.550813794136 0.695187926292 0.094435930252 -v 0.552393674850 0.698510527611 0.099156975746 -v 0.550143718719 0.701255559921 0.102890193462 -v 0.551577091217 0.699175059795 0.104868292809 -v 0.552265882492 0.693053603172 0.096573829651 -v 0.553521633148 0.695399820805 0.100726366043 -v 0.552729487419 0.696392178535 0.105458736420 -v 0.549271106720 0.673505485058 0.104050397873 -v 0.554521441460 0.678445816040 0.100325822830 -v 0.553958654404 0.685331046581 0.116456747055 -v 0.548520803452 0.679022014141 0.118942022324 -v 0.546076059341 0.673519492149 0.112744927406 -v 0.557391166687 0.687807381153 0.105319499969 -v 0.556760072708 0.685200691223 0.101653337479 -v 0.558141469955 0.683105111122 0.102121174335 -v 0.559174299240 0.686151802540 0.106331229210 -v 0.556374430656 0.688750267029 0.109533429146 -v 0.557712197304 0.687251687050 0.111271739006 -v 0.559688806534 0.681563556194 0.103728890419 -v 0.560254931450 0.683878600597 0.107563853264 -v 0.559006214142 0.685161352158 0.111566960812 -v 0.547902107239 0.702368199825 0.096936225891 -v 0.564785003662 0.677279114723 0.110871613026 -v 0.565037727356 0.675400853157 0.107921242714 -v 0.566116333008 0.673743724823 0.108678221703 -v 0.566264390945 0.674956560135 0.112121045589 -v 0.564288020134 0.678330838680 0.113956749439 -v 0.565272808075 0.676626622677 0.115107536316 -v 0.565854787827 0.671615004539 0.113909065723 -v 0.565153121948 0.671011805534 0.108082771301 -v 0.564292907715 0.675019502640 0.105877757072 -v 0.563846707344 0.678827285767 0.109954953194 -v 0.563235521317 0.679445624352 0.115319430828 -v 0.564523458481 0.675631463528 0.117880046368 -v 0.508027791977 0.705808162689 0.185932517052 -v 0.503305912018 0.708674609661 0.193543970585 -v 0.504237651825 0.716933488846 0.197534382343 -v 0.514192581177 0.739058196545 0.152600765228 -v 0.527436256409 0.742018103600 0.152551293373 -v 0.521233081818 0.757511794567 0.163559794426 -v 0.510088562965 0.753134310246 0.162780582905 -v 0.506630778313 0.744708418846 0.157582461834 -v 0.531264781952 0.752472937107 0.158268332481 -v 0.532356500626 0.758174300194 0.153628230095 -v 0.496481537819 0.711037337780 0.188681483269 -v 0.497926712036 0.717670679092 0.193979084492 -v 0.501640081406 0.707217693329 0.182956755161 -v 0.524531006813 0.727519810200 0.166848421097 -v 0.513245224953 0.726689815521 0.165383756161 -v 0.511902570724 0.722795486450 0.168308913708 -v 0.523548841476 0.723003327847 0.171342372894 -v 0.509620904922 0.739431321621 0.176361441612 -v 0.520829081535 0.741701781750 0.179257631302 -v 0.519819498062 0.736979722977 0.183732628822 -v 0.508016705513 0.736198961735 0.179792046547 -v 0.506378054619 0.732324659824 0.169591844082 -v 0.504464268684 0.729115188122 0.172098159790 -v 0.528473019600 0.734543383121 0.174971342087 -v 0.527720928192 0.731290459633 0.178188145161 -v 0.518843531609 0.715346276760 0.178183495998 -v 0.507250308990 0.715426683426 0.173481583595 -v 0.504154086113 0.710596859455 0.177767276764 -v 0.515055418015 0.710507869720 0.182130753994 -v 0.502767324448 0.729494333267 0.186172127724 -v 0.514684081078 0.728843152523 0.190630316734 -v 0.510843634605 0.723370432854 0.194603562355 -v 0.499645948410 0.723829448223 0.190759420395 -v 0.498818874359 0.722565889359 0.177140593529 -v 0.495809078217 0.716866850853 0.182247757912 -v 0.521199822426 0.721097052097 0.187072217464 -v 0.518935918808 0.718163132668 0.189251482487 -v 0.525767803192 0.736793160439 0.157169640064 -v 0.513168215752 0.734809756279 0.157476186752 -v 0.513290882111 0.730967700481 0.161826848984 -v 0.522656917572 0.730214118958 0.160739362240 -v 0.510023117065 0.747913599014 0.168063998222 -v 0.522023916245 0.752246916294 0.169538915157 -v 0.518543243408 0.747491836548 0.175433754921 -v 0.509775161743 0.743234395981 0.172257661819 -v 0.506842017174 0.740149796009 0.162537455559 -v 0.507179975510 0.736026167870 0.166410088539 -v 0.533026695251 0.745195150375 0.165490031242 -v 0.531216979027 0.738591969013 0.161130785942 -v 0.530287504196 0.734632968903 0.163438796997 -v 0.532566308975 0.741663217545 0.168802976608 -v 0.529102921486 0.749674737453 0.170213341713 -v 0.527972817421 0.746949017048 0.173987030983 -v 0.529739618301 0.732569515705 0.167208254337 -v 0.531125068665 0.737987637520 0.172155261040 -v 0.527689337730 0.742842078209 0.176281332970 -v 0.509422302246 0.719553887844 0.170410692692 -v 0.519722938538 0.717905282974 0.172781825066 -v 0.514890789986 0.734458565712 0.187463164330 -v 0.505210161209 0.733366072178 0.182220578194 -v 0.502490282059 0.726530313492 0.174150884151 -v 0.528773427010 0.728935301304 0.181077003479 -v 0.527782201767 0.723789393902 0.176339983940 -v 0.526475429535 0.720672547817 0.177816569805 -v 0.527674317360 0.726253092289 0.183694541454 -v 0.525176644325 0.733416676521 0.184952259064 -v 0.523093461990 0.731555163860 0.187405228615 -v 0.524735569954 0.719069778919 0.180645465851 -v 0.525143027306 0.723502397537 0.185845911503 -v 0.521940231323 0.728395640850 0.189189791679 -v 0.531512737274 0.747916936874 0.162386298180 -v 0.516651630402 0.713900744915 0.192825019360 -v 0.516959309578 0.710621714592 0.189882099628 -v 0.516236543655 0.708358943462 0.191311597824 -v 0.515579700470 0.710943758488 0.195346117020 -v 0.515369772911 0.716586649418 0.195921123028 -v 0.514391779900 0.714817166328 0.197931408882 -v 0.510539889336 0.709055662155 0.195576369762 -v 0.513627529144 0.706451058388 0.189301311970 -v 0.517277002335 0.710314393044 0.187095999718 -v 0.517525792122 0.716093361378 0.190888464451 -v 0.514751195908 0.719347119331 0.196116745472 -v 0.510549068451 0.715662777424 0.198681712151 -v 0.533120870590 0.762782216072 0.130480825901 -v 0.524248719215 0.772845745087 0.138786017895 -v 0.540866613388 0.746797680855 0.109364151955 -v 0.537410974503 0.759103238583 0.116162776947 -v 0.540438890457 0.742126762867 0.095553338528 -v 0.520689725876 0.728452146053 0.065447509289 -v 0.512445688248 0.721606135368 0.069535374641 -v 0.484276175499 0.737580657005 0.089107573032 -v 0.532676100731 0.765493094921 0.091823399067 -v 0.533045768738 0.757094204426 0.081643581390 -v 0.514222741127 0.784138381481 0.129911184311 -v 0.490095019341 0.767989397049 0.145252108574 -v 0.479055404663 0.768541455269 0.143870294094 -v 0.488378524780 0.780031323433 0.144005358219 -v 0.498183012009 0.777795016766 0.142598867416 -v 0.481902122498 0.759345829487 0.139733493328 -v 0.467978596687 0.763386905193 0.133951485157 -v 0.455418944359 0.777963399887 0.119988799095 -v 0.451926827431 0.777264595032 0.134350359440 -v 0.458689928055 0.767885684967 0.141088008881 -v 0.468816995621 0.769495069981 0.148243069649 -v 0.476413726807 0.779487848282 0.150034487247 -v 0.438565135002 0.771156847477 0.177375793457 -v 0.441770315170 0.764434158802 0.175460696220 -v 0.444827079773 0.770441770554 0.183847427368 -v 0.469913721085 0.779009222984 0.155741333961 -v 0.463364720345 0.769138574600 0.153375625610 -v 0.460401535034 0.767174780369 0.158601582050 -v 0.467330098152 0.775935709476 0.162042737007 -v 0.453510165215 0.769425153732 0.147249221802 -v 0.450202226639 0.768634498119 0.153188824654 -v 0.467652678490 0.791541039944 0.152924060822 -v 0.464564323425 0.787662565708 0.161086738110 -v 0.456722617149 0.792148888111 0.148283004761 -v 0.454262137413 0.790213525295 0.153603911400 -v 0.449564695358 0.782195746899 0.142867326736 -v 0.445333719254 0.781309008598 0.150482535362 -v 0.462369918823 0.796061277390 0.131073176861 -v 0.470566511154 0.799281775951 0.136529088020 -v 0.469121217728 0.797714054585 0.143102586269 -v 0.460547566414 0.795852959156 0.138329267502 -v 0.455207109451 0.789058446884 0.126723527908 -v 0.453316926956 0.788498997688 0.133789181709 -v 0.477501153946 0.792452573776 0.146006584167 -v 0.465461015701 0.796401441097 0.147136926651 -v 0.458685755730 0.794838547707 0.143734753132 -v 0.453046441078 0.789503097534 0.139946758747 -v 0.477824330330 0.801583707333 0.131692588329 -v 0.462747812271 0.795654177666 0.121492981911 -v 0.461746931076 0.769132852554 0.174213290215 -v 0.453706622124 0.761957705021 0.170404195786 -v 0.443747997284 0.765161931515 0.166959524155 -v 0.460104227066 0.781512916088 0.175598621368 -v 0.445243358612 0.784041821957 0.176206707954 -v 0.449878454208 0.784194827080 0.178927242756 -v 0.448585391045 0.782106339931 0.182242095470 -v 0.443793654442 0.781242489815 0.181344807148 -v 0.440421819687 0.782552838326 0.174964666367 -v 0.439622640610 0.780634343624 0.178736805916 -v 0.438029885292 0.777883410454 0.165846407413 -v 0.457392096519 0.764703154564 0.162105917931 -v 0.465457439423 0.772188305855 0.166752159595 -v 0.447040438652 0.767057418823 0.158573865891 -v 0.465133786201 0.783054172993 0.168668568134 -v 0.452129364014 0.790718674660 0.158209085464 -v 0.459192514420 0.790737628937 0.162641108036 -v 0.459162950516 0.789255976677 0.167319536209 -v 0.450338006020 0.789745509624 0.162790656090 -v 0.445508122444 0.787147641182 0.154866278172 -v 0.442550182343 0.785621106625 0.158436417580 -v 0.440964460373 0.777064740658 0.156837046146 -v 0.456962108612 0.787429749966 0.170820236206 -v 0.448460698128 0.787783861160 0.167056441307 -v 0.441197395325 0.784746885300 0.163089811802 -v 0.447333574295 0.785258412361 0.169726729393 -v 0.443022251129 0.777300119400 0.184506356716 -v 0.450631856918 0.780292212963 0.183982253075 -v 0.453623771667 0.784703671932 0.178378582001 -v 0.445952057838 0.786179065704 0.172527611256 -v 0.438473701477 0.781861722469 0.171767473221 -v 0.437908291817 0.777420401573 0.178881585598 -v 0.492766499519 0.755644321442 0.143515646458 -v 0.486923098564 0.747458815575 0.130217909813 -v 0.466797590256 0.757182359695 0.099651396275 -v 0.472083091736 0.750997185707 0.089635670185 -v 0.469869136810 0.760206878185 0.083161294460 -v 0.463792681694 0.773227989674 0.097641050816 -v 0.480604887009 0.743164718151 0.097418367863 -v 0.509183526039 0.740819334984 0.056642234325 -v 0.515854835510 0.750867664814 0.056534111500 -v 0.500680327415 0.800476849079 0.113281011581 -v 0.480252742767 0.809417188168 0.104322493076 -v 0.496218204498 0.805853843689 0.093608915806 -v 0.494943737984 0.789026916027 0.136653363705 -v 0.501828312874 0.788901865482 0.133081078529 -v 0.507851958275 0.797888576984 0.081428110600 -v 0.522942423820 0.779709160328 0.077857553959 -v 0.499507188797 0.765030682087 0.148840188980 -v 0.507470130920 0.774820327759 0.144708752632 -v 0.476036071777 0.746732592583 0.106510400772 -v 0.493361711502 0.803006708622 0.122841835022 -v 0.478899002075 0.807841002941 0.117558896542 -v 0.463644027710 0.796741485596 0.111424744129 -v 0.465716123581 0.794997811317 0.103478550911 -v 0.458229780197 0.777908682823 0.107420504093 -v 0.462887525558 0.761031866074 0.109043002129 -v 0.471899509430 0.750320196152 0.116126954556 -v 0.478152394295 0.753174483776 0.131771326065 -v 0.468824982643 0.755779623985 0.124225437641 -v 0.461404800415 0.763227701187 0.116893410683 -v 0.489722132683 0.797489106655 0.133335888386 -v 0.486714601517 0.789863348007 0.141924619675 -v 0.484797358513 0.741189062595 0.067133903503 -v 0.478503465652 0.751935124397 0.068854808807 -v 0.500882506371 0.734169185162 0.061571240425 -v 0.477385044098 0.744656562805 0.080763101578 -v 0.481624126434 0.739364206791 0.075847864151 -v 0.500677943230 0.775840044022 0.048178792000 -v 0.488707780838 0.765670180321 0.051871418953 -v 0.477584242821 0.762718737125 0.063034832478 -v 0.467450737953 0.766845524311 0.076912343502 -v 0.461498498917 0.778625905514 0.089994966984 -v 0.461806297302 0.795562386513 0.096759736538 -v 0.470135807991 0.809676170349 0.096153378487 -v 0.483797073364 0.812756240368 0.088045477867 -v 0.497678637505 0.805696189404 0.075719475746 -v 0.504785418510 0.791619062424 0.059249997139 -v 0.513334751129 0.788233518600 0.068128407001 -v 0.511568665504 0.770020723343 0.053026437759 -v 0.520908117294 0.761221706867 0.061087131500 -v 0.497784495354 0.788155913353 0.046932697296 -v 0.488117575645 0.775684356689 0.047841131687 -v 0.475840330124 0.770089447498 0.057217180729 -v 0.463661313057 0.771884500980 0.069685220718 -v 0.455235481262 0.782279491425 0.081061065197 -v 0.454746246338 0.798582255840 0.087480664253 -v 0.461082696915 0.812864422798 0.088064253330 -v 0.473519444466 0.820378422737 0.082788586617 -v 0.488731861115 0.816120684147 0.070775330067 -v 0.498112678528 0.803522765636 0.056562244892 -v 0.494563221931 0.799096226692 0.042310714722 -v 0.486902475357 0.808524429798 0.030907094479 -v 0.478900671005 0.793341755867 0.029809832573 -v 0.486203432083 0.785064756870 0.041563153267 -v 0.464779496193 0.783073127270 0.035595595837 -v 0.472564697266 0.777089834213 0.049066007137 -v 0.450284838676 0.780604720116 0.044155120850 -v 0.458022236824 0.776483118534 0.058857560158 -v 0.440367698669 0.784753084183 0.049066960812 -v 0.443802475929 0.787280976772 0.064302384853 -v 0.444123268127 0.804896831512 0.073245406151 -v 0.451916456223 0.821180701256 0.076650619507 -v 0.464986562729 0.832542598248 0.073360800743 -v 0.480245232582 0.831362009048 0.059292852879 -v 0.481340765953 0.834166049957 0.044129669666 -v 0.492998480797 0.814772903919 0.050042569637 -v 0.486271023750 0.822800278664 0.037332177162 -v 0.523271918297 0.770754814148 0.068353176117 -v 0.514518499374 0.778774738312 0.058889150620 -v 0.507184267044 0.776329338551 0.050279438496 -v 0.508969664574 0.781902492046 0.054183304310 -v 0.244488239288 0.426662117243 0.058280527592 -v 0.238626718521 0.424758225679 0.073367774487 -v 0.224532604218 0.421156793833 0.082624495029 -v 0.024168014526 0.813921332359 0.149686336517 -v -0.045492410660 0.811454951763 0.138143301010 -v -0.043429851532 0.849619209766 0.152232885361 -v -0.103686809540 0.858773767948 0.124039173126 -v -0.105726003647 0.821566998959 0.105698108673 -v -0.216044902802 1.015913844109 -0.065555334091 -v -0.209439516068 0.999427437782 -0.058619439602 -v -0.211006164551 0.987861990929 -0.064142704010 -v -0.230187892914 0.988817870617 -0.073895573616 -v -0.197565555573 0.993671536446 -0.052417397499 -v -0.196903944016 0.968688607216 -0.066415429115 -v -0.226006031036 0.954002797604 -0.069144666195 -v -0.186616420746 0.850906968117 -0.171889841557 -v -0.197167158127 0.860019028187 -0.140617847443 -v -0.179961204529 0.897772192955 -0.115278422832 -v -0.166189670563 0.875091910362 -0.153516530991 -v -0.148694753647 0.880870044231 -0.136985838413 -v -0.150884389877 0.907215118408 -0.104235470295 -v -0.157392501831 0.931122899055 -0.078570246696 -v -0.191499710083 0.929601490498 -0.075881302357 -v -0.215350627899 0.919599175453 -0.078258514404 -v -0.203397989273 0.897285580635 -0.100253224373 -v -0.217379808426 0.875960350037 -0.118124604225 -v -0.029005050659 0.571525335312 -0.088107168674 -v 0.002735614777 0.548631310463 -0.070256829262 -v 0.027010679245 0.590999245644 -0.090317308903 -v -0.018280744553 0.620064198971 -0.103850007057 -v 0.018197059631 0.528473854065 -0.041200280190 -v 0.039121389389 0.542406558990 -0.043555021286 -v -0.148338317871 0.925767302513 -0.247407793999 -v -0.147905111313 0.887462854385 -0.231083989143 -v -0.130671024323 0.907526671886 -0.214898705482 -v -0.110074996948 0.950674951077 -0.223033547401 -v -0.158329963684 0.874756038189 -0.191096603870 -v -0.134732007980 0.893178164959 -0.177285671234 -v -0.090615749359 0.914829909801 -0.207994282246 -v -0.112192392349 0.762768864632 0.047738432884 -v -0.126791477203 0.781367957592 0.019289433956 -v -0.137742519379 0.815532445908 0.021429121494 -v -0.104435205460 0.789754331112 0.077099800110 -v -0.129538536072 0.770201504230 -0.012699365616 -v -0.138639211655 0.806268036366 -0.033546984196 -v -0.147496223450 0.848499417305 0.061839640141 -v -0.089931488037 0.741834282875 0.071407139301 -v -0.054453372955 0.767961084843 0.118939399719 -v -0.098224401474 0.709381341934 0.028533697128 -v -0.111907958984 0.714046895504 -0.023087024689 -v -0.118014335632 0.742692947388 0.013800978661 -v -0.105286121368 0.729441761971 0.038245499134 -v -0.068748474121 0.719616711140 0.068620622158 -v -0.085082054138 0.653443753719 0.027877748013 -v -0.058162212372 0.656390905380 0.056895077229 -v -0.050686836243 0.607604086399 0.047678053379 -v -0.099447727203 0.621420621872 0.005962431431 -v -0.068820476532 0.563984632492 0.037404358387 -v -0.093855857849 0.573501050472 0.006214916706 -v -0.061287641525 1.064289569855 0.001488387585 -v -0.092086315155 1.040367364883 0.017865002155 -v -0.100042343140 1.063028454781 -0.025874853134 -v -0.068414211273 1.083276271820 -0.024904131889 -v -0.152829885483 1.043263196945 -0.030532896519 -v -0.132411718369 1.076464056969 -0.043527424335 -v -0.132525444031 1.024463057518 -0.009899616241 -v -0.121130466461 1.003944158554 0.032351315022 -v -0.171019792557 1.007393002510 -0.034520506859 -v -0.196717739105 1.027601242065 -0.048720419407 -v -0.173523902893 1.051656365395 -0.044109880924 -v -0.172769784927 0.976805567741 -0.047324657440 -v -0.238524913788 0.893932402134 -0.094456076622 -v -0.167498588562 1.074029922485 -0.061905801296 -v -0.199609756470 1.058331489563 -0.076546132565 -v 0.035741090775 0.537817895412 0.004574596882 -v 0.063968896866 0.537479221821 0.012407362461 -v 0.069581508636 0.543589949608 -0.037130057812 -v -0.067850828171 1.115831255913 -0.122188806534 -v -0.044815301895 1.153640151024 -0.091253459454 -v -0.061902284622 1.142533540726 -0.076420962811 -v -0.087494134903 1.110044360161 -0.101176381111 -v -0.102974891663 1.099434852600 -0.071468591690 -v -0.069273948669 1.125692009926 -0.061185836792 -v -0.110057592392 1.099711656570 -0.165807723999 -v -0.129351377487 1.099599599838 -0.132730364799 -v -0.150191068649 1.093798398972 -0.095395982265 -v -0.167793750763 1.074134111404 -0.162128686905 -v -0.187201261520 1.073685646057 -0.118393898010 -v -0.200552225113 1.044490218163 -0.186491847038 -v -0.215443849564 1.052723646164 -0.141018509865 -v -0.222080469131 1.039790749550 -0.094145119190 -v -0.239657878876 1.022207856178 -0.158943414688 -v -0.241830825806 1.013184070587 -0.110611021519 -v -0.260427713394 0.986940979958 -0.176530241966 -v -0.263617753983 0.981970906258 -0.132411062717 -v -0.260305166245 0.958638668060 -0.098890125751 -v -0.278702974319 0.955592036247 -0.163595557213 -v -0.278200626373 0.932817518711 -0.130598545074 -v -0.271001577377 0.901743829250 -0.119967401028 -v -0.252998113632 0.927197396755 -0.088302910328 -v -0.255738973618 0.872728466988 -0.122977674007 -v -0.288134813309 0.917696714401 -0.166244506836 -v -0.280348777771 0.886196553707 -0.155893802643 -v -0.267940998077 0.855949759483 -0.158157467842 -v -0.322344541550 0.899317681789 -0.184273540974 -v -0.314202308655 0.871414363384 -0.169530987740 -v -0.304754018784 0.841402471066 -0.163097262383 -v -0.351705789566 0.865829944611 -0.176985263824 -v -0.346288204193 0.842895746231 -0.165701746941 -v -0.342967510223 0.821778357029 -0.172056436539 -v -0.297340869904 0.818372488022 -0.180801868439 -v -0.255311727524 0.834150016308 -0.184277534485 -v -0.344840049744 0.807662725449 -0.190519332886 -v -0.298639774323 0.802460789680 -0.209736287594 -v -0.253891229630 0.813284337521 -0.222991466522 -v -0.215986251831 0.835866868496 -0.183695673943 -v -0.214768171310 0.830051660538 -0.219524562359 -v -0.309920310974 0.802444458008 -0.240571200848 -v -0.261218309402 0.820708096027 -0.265693724155 -v -0.202613115311 0.844021797180 -0.252863943577 -v -0.351272106171 0.804853558540 -0.214755058289 -v -0.361089944839 0.814315497875 -0.239227890968 -v -0.324601888657 0.821000874043 -0.263598829508 -v -0.283481359482 0.848797678947 -0.284017473459 -v -0.368223667145 0.837127387524 -0.253749161959 -v -0.336348056793 0.853153288364 -0.277962535620 -v -0.297395467758 0.883530080318 -0.294476032257 -v -0.240055322647 0.874735951424 -0.304646462202 -v -0.264170885086 0.907689154148 -0.292484790087 -v -0.343079566956 0.886833965778 -0.280547678471 -v -0.304080247879 0.919566035271 -0.288546800613 -v -0.274107933044 0.937634170055 -0.272911608219 -v -0.237725257874 0.939036250114 -0.275381207466 -v -0.246447801590 0.963879764080 -0.250892400742 -v -0.299230575562 0.941379368305 -0.261109113693 -v -0.274475336075 0.952009916306 -0.239782989025 -v -0.254629850388 0.977320313454 -0.217426180840 -v -0.217944860458 0.993275702000 -0.236558616161 -v -0.229768037796 1.010393023491 -0.203123748302 -v -0.274976491928 0.958194017410 -0.204134941101 -v -0.294450044632 0.945626258850 -0.227268993855 -v -0.291128396988 0.938337326050 -0.193792879581 -v -0.336385011673 0.927444577217 -0.237453699112 -v -0.328366279602 0.918976187706 -0.207168340683 -v -0.373788356781 0.900349020958 -0.237839400768 -v -0.367165803909 0.902696073055 -0.212942600250 -v -0.358767509460 0.887838721275 -0.192018508911 -v -0.399082183838 0.886386156082 -0.210687160492 -v -0.391416311264 0.878774166107 -0.190892636776 -v -0.385291337967 0.862347722054 -0.175807774067 -v -0.380799770355 0.844238936901 -0.168828010559 -v -0.377043247223 0.828504204750 -0.168903589249 -v -0.378103971481 0.815952479839 -0.178110599518 -v -0.382728338242 0.809657692909 -0.196520686150 -v -0.389034032822 0.812136590481 -0.218078017235 -v -0.393783569336 0.826233685017 -0.232942044735 -v -0.374763011932 0.861356377602 -0.261329650879 -v -0.397455453873 0.845723807812 -0.239633858204 -v -0.401363134384 0.864607393742 -0.240126490593 -v -0.377741813660 0.885030388832 -0.257234215736 -v -0.342441082001 0.914424657822 -0.266438513994 -v -0.402511835098 0.878381252289 -0.229500651360 -v -0.170168876648 1.000604867935 -0.237006545067 -v -0.184483528137 1.026935815811 -0.219662249088 -v -0.204886913300 0.972634196281 -0.262749642134 -v -0.159294366837 0.967827081680 -0.247309863567 -v -0.191198587418 0.937436878681 -0.281654030085 -v -0.222276926041 0.905950903893 -0.284064441919 -v -0.177347660065 0.896951436996 -0.278299987316 -v -0.199582099915 0.874506413937 -0.276412338018 -v -0.219844818115 0.853652238846 -0.284712314606 -v -0.174687385559 0.863596737385 -0.250282466412 -v -0.181549310684 0.849696934223 -0.207981944084 -v -0.116446971893 1.003559350967 -0.234433829784 -v -0.131599664688 1.042656898499 -0.224299788475 -v -0.063884496689 1.038912057877 -0.210333466530 -v -0.085042953491 1.078667521477 -0.191534459591 -v -0.149874925613 1.067245244980 -0.198640346527 -v 0.006145715714 1.018314838409 -0.186279118061 -v -0.007123947144 1.064264893532 -0.171564280987 -v -0.048004388809 0.991492629051 -0.217727243900 -v -0.026478528976 1.111588954926 -0.142706692219 -v 0.017360448837 0.970607042313 -0.195879101753 -v -0.035747051239 0.945858657360 -0.214797735214 -v 0.026816844940 0.918899655342 -0.194363832474 -v -0.025933980942 0.897993922234 -0.206000804901 -v -0.080864667892 0.874895334244 -0.192031383514 -v -0.018188714981 0.847238957882 -0.190483808517 -v -0.072869777679 0.831310868263 -0.174542069435 -v -0.116947174072 0.821985781193 -0.144294202328 -v -0.121940612793 0.859033942223 -0.160447001457 -v -0.136636972427 0.828852474689 -0.101162433624 -v -0.142194747925 0.857307851315 -0.121078729630 -v -0.143414735794 0.845660209656 -0.058004975319 -v -0.144388198853 0.880819320679 -0.082161068916 -v -0.153039455414 0.862532734871 -0.018098533154 -v -0.153266906738 0.903006434441 -0.052416980267 -v -0.161772251129 0.888247668743 0.014432668686 -v -0.160099267960 0.926342248917 -0.032119214535 -v -0.164556503296 0.953284680843 -0.062894344330 -v -0.171996355057 0.952526032925 -0.012361943722 -v -0.164795875549 0.921657145023 0.036377131939 -v -0.147756576538 0.961669743061 0.040470600128 -v -0.158525466919 0.986356794834 -0.006434679031 -v -0.145291805267 0.885101556778 0.083670973778 -v -0.126105070114 0.929664313793 0.086600899696 -v -0.100680828094 0.976286113262 0.074836552143 -v -0.088333368301 0.904943823814 0.124103307724 -v -0.068841934204 0.954400718212 0.109162628651 -v -0.050687789917 1.002869248390 0.086499452591 -v -0.076419353485 1.019973993301 0.056980848312 -v -0.031089067459 1.040452837944 0.053422629833 -v -0.048895835876 1.049849748611 0.030142068863 -v -0.028286457062 0.943060517311 0.130822718143 -v -0.018934726715 0.993253171444 0.104324102402 -v -0.008577823639 1.036106586456 0.068773925304 -v 0.016984224319 0.938255190849 0.132273197174 -v 0.016255617142 0.988211154938 0.106916069984 -v 0.017256975174 1.034857988358 0.074777126312 -v -0.037022590637 0.893554985523 0.148184359074 -v -0.125862836838 0.795052647591 -0.077642142773 -v -0.088509559631 0.748381972313 -0.091158628464 -v -0.106392145157 0.784361839294 -0.120982527733 -v -0.114890336990 0.757017672062 -0.053101658821 -v -0.051238536835 0.693981826305 -0.101675391197 -v -0.053010225296 0.743843674660 -0.121231853962 -v -0.086938619614 0.703561365604 -0.072716116905 -v -0.064249753952 0.786670446396 -0.151442766190 -v -0.010465383530 0.743931651115 -0.136873304844 -v -0.013234376907 0.796020328999 -0.166346788406 -v 0.032855987549 0.676068127155 -0.117384016514 -v 0.034677505493 0.748068869114 -0.133399724960 -v -0.010420322418 0.684079170227 -0.115326344967 -v 0.036463499069 0.808236598969 -0.159694790840 -v 0.077756881714 0.752460122108 -0.118776857853 -v 0.079266071320 0.817305207253 -0.140415549278 -v 0.034280061722 0.864266276360 -0.182166934013 -v 0.072944402695 0.932042717934 -0.169168591499 -v 0.063047170639 1.036345005035 -0.171650230885 -v -0.058959484100 0.640669405460 -0.090303719044 -v -0.066095590591 0.592738807201 -0.077589452267 -v -0.097780227661 0.609835147858 -0.045422494411 -v -0.095155477524 0.656358480453 -0.060826182365 -v -0.105790376663 0.668013811111 -0.016322851181 -v -0.087153911591 0.680714309216 0.023537695408 -v -0.060539484024 0.690345466137 0.063132166862 -v -0.022153139114 0.659986138344 0.099782228470 -v -0.026333808899 0.697329998016 0.108290851116 -v -0.032596349716 0.731493532658 0.113822937012 -v 0.026883125305 0.702849328518 0.121817588806 -v -0.007471561432 0.622038125992 0.083720922470 -v 0.033208370209 0.620859384537 0.106691539288 -v 0.010722160339 0.584229052067 0.067391037941 -v 0.046667098999 0.584562242031 0.083252370358 -v 0.025924444199 0.553159415722 0.041892528534 -v 0.057153224945 0.554712772369 0.051456034184 -v -0.020308732986 0.569664835930 0.051660239697 -v 0.001250267029 0.543498456478 0.031863629818 -v 0.013638973236 0.532003760338 -0.001672267914 -v -0.000382900238 0.520153343678 -0.005273222923 -v -0.012644290924 0.528460025787 0.023336231709 -v 0.006472110748 0.512750744820 -0.036196351051 -v -0.007425308228 0.474734485149 -0.000116705894 -v -0.005846261978 0.500033557415 -0.004471659660 -v 0.000211715698 0.494048833847 -0.030069172382 -v -0.006864786148 0.472749769688 -0.022261261940 -v -0.018941164017 0.475434243679 -0.039400577545 -v -0.014056682587 0.499557584524 -0.049792110920 -v -0.007712841034 0.522083699703 -0.061311900616 -v -0.037567615509 0.480722934008 -0.046939432621 -v -0.037078142166 0.509507179260 -0.057908356190 -v -0.034726858139 0.538039565086 -0.071861624718 -v -0.058244705200 0.486637681723 -0.040571570396 -v -0.064287900925 0.519816040993 -0.052058398724 -v -0.066971778870 0.554416954517 -0.064069986343 -v -0.073494434357 0.490894377232 -0.019915223122 -v -0.083090543747 0.529140114784 -0.027455270290 -v -0.092357873917 0.568181574345 -0.034658551216 -v -0.079753637314 0.491208374500 0.009451150894 -v -0.086676597595 0.532695353031 0.006102561951 -v -0.073581457138 0.454350113869 0.007979691029 -v -0.066380023956 0.457608014345 -0.017444491386 -v -0.067813158035 0.488057374954 0.029619216919 -v -0.066108465195 0.450441658497 0.027257204056 -v -0.069606781006 0.527580559254 0.030218899250 -v -0.044326543808 0.482478886843 0.033305048943 -v -0.044793844223 0.448259085417 0.031902611256 -v -0.042425155640 0.517599105835 0.031794846058 -v -0.017328262329 0.477021217346 0.022542297840 -v -0.018852710724 0.507313489914 0.017633438110 -v -0.037883758545 0.545025348663 0.042228996754 -v -0.019141912460 0.447015106678 0.024648547173 -v -0.009853363037 0.448897719383 0.002969503403 -v -0.010138511658 0.424218118191 -0.001672625542 -v -0.006133556366 0.399529516697 -0.015495121479 -v -0.017596960068 0.394342869520 -0.000591039658 -v -0.020816802979 0.419395595789 0.016798019409 -v -0.009426116943 0.427912145853 -0.021588802338 -v -0.001868963242 0.404415190220 -0.034041702747 -v -0.011332273483 0.450134307146 -0.017913401127 -v -0.018124103546 0.431156426668 -0.039218008518 -v -0.011564016342 0.408847093582 -0.052631855011 -v -0.021310806274 0.452264279127 -0.034315645695 -v -0.035163879395 0.433271795511 -0.046046972275 -v -0.032569646835 0.410334706306 -0.058933556080 -v -0.036829233170 0.455296754837 -0.040022969246 -v -0.050311565399 0.433117091656 -0.039737045765 -v -0.049625396729 0.409451037645 -0.056582272053 -v -0.052719354630 0.457712709904 -0.034135818481 -v -0.060839176178 0.430344671011 -0.025123417377 -v -0.060647249222 0.405378311872 -0.044947326183 -v -0.039075374603 0.333637267351 -0.059441745281 -v -0.046819448471 0.377576559782 -0.066945731640 -v -0.057845830917 0.373610943556 -0.056396543980 -v -0.044396162033 0.332225650549 -0.051878690720 -v -0.043912887573 0.330512613058 -0.042705893517 -v -0.057412862778 0.368281006813 -0.038785338402 -v -0.061007261276 0.399160534143 -0.025505304337 -v -0.041280269623 0.328136712313 -0.033087968826 -v -0.046390056610 0.364219039679 -0.022349596024 -v -0.051404714584 0.393975228071 -0.006930351257 -v -0.035102367401 0.325139790773 -0.023742496967 -v -0.033584117889 0.360739827156 -0.011030375957 -v -0.036393165588 0.389957576990 0.006403863430 -v -0.024703979492 0.326273173094 -0.026353597641 -v -0.019546747208 0.364557057619 -0.018281936646 -v -0.016890287399 0.328833460808 -0.035211801529 -v -0.006627321243 0.368008077145 -0.028945624828 -v -0.013489007950 0.331431388855 -0.046256422997 -v -0.002036094666 0.373024463654 -0.045083582401 -v -0.017686605453 0.333469033241 -0.056734740734 -v -0.010092020035 0.377158254385 -0.060950160027 -v -0.028373241425 0.334166795015 -0.062248706818 -v -0.029481172562 0.378683656454 -0.066067218781 -v -0.219955444336 0.842094063759 -0.154961943626 -v -0.235270023346 0.857862532139 -0.137915790081 -v -0.087909221649 1.087654352188 -0.050910711288 -v -0.070798635483 1.104470491409 -0.045316457748 -v -0.247585058212 0.849854946136 -0.153714001179 -v -0.240604400635 0.840870857239 -0.163044929504 -v -0.011443376541 1.160188794136 -0.101308941841 -v 0.036525011063 1.165561199188 -0.098447144032 -v -0.447368383408 0.797736108303 -0.173693537712 -v -0.447412490845 0.796239554882 -0.162157893181 -v -0.443197250366 0.802235960960 -0.155865490437 -v -0.438388586044 0.805791616440 -0.164553344250 -v -0.494693517685 0.893587052822 -0.106214702129 -v -0.495902061462 0.900918126106 -0.105787515640 -v -0.493417978287 0.900910675526 -0.096440255642 -v -0.491146326065 0.891790270805 -0.099022448063 -v -0.489644289017 0.821257293224 -0.123335301876 -v -0.471888542175 0.823015093803 -0.132293999195 -v -0.468766212463 0.813135862350 -0.129689037800 -v -0.484895229340 0.811676740646 -0.120194315910 -v -0.476134061813 0.841621756554 -0.135791420937 -v -0.474495887756 0.832299590111 -0.135184764862 -v -0.494080066681 0.831160485744 -0.126861453056 -v -0.496844291687 0.842333674431 -0.129078328609 -v -0.451151609421 0.806489586830 -0.139960348606 -v -0.466060161591 0.802223086357 -0.129936814308 -v -0.452974319458 0.816859483719 -0.137552082539 -v -0.485681533813 0.851063311100 -0.187404632568 -v -0.502808094025 0.846567988396 -0.173310935497 -v -0.499794721603 0.830486893654 -0.174043655396 -v -0.483735561371 0.833467781544 -0.188756585121 -v -0.491135358810 0.786839187145 -0.137906074524 -v -0.477485179901 0.788113296032 -0.152600586414 -v -0.484442234039 0.794747292995 -0.160152792931 -v -0.501042604446 0.794560611248 -0.139316618443 -v -0.508388519287 0.830364823341 -0.119966745377 -v -0.521482229233 0.819912433624 -0.130728006363 -v -0.523111343384 0.828098714352 -0.121222257614 -v -0.512018680573 0.834384858608 -0.118249833584 -v -0.514605045319 0.853373050690 -0.127098441124 -v -0.517944812775 0.850607991219 -0.124822854996 -v -0.530208826065 0.845044076443 -0.127292752266 -v -0.531853437424 0.844683170319 -0.137332379818 -v -0.500032663345 0.821590065956 -0.116037189960 -v -0.509562015533 0.864964723587 -0.132301747799 -v -0.504422664642 0.864491283894 -0.132351279259 -v -0.500204324722 0.853452622890 -0.129730045795 -v -0.520584106445 0.822443604469 -0.147195518017 -v -0.522242069244 0.828122496605 -0.150109887123 -v -0.526848316193 0.828633189201 -0.143665313721 -v -0.523217201233 0.823370218277 -0.141705751419 -v -0.528179168701 0.850113034248 -0.151596605778 -v -0.527724266052 0.857582092285 -0.153711855412 -v -0.533334732056 0.857348978519 -0.147594749928 -v -0.531985759735 0.850167274475 -0.146348357201 -v -0.507945299149 0.843233942986 -0.123751223087 -v -0.509826183319 0.844902992249 -0.121303021908 -v -0.529620647430 0.830736279488 -0.135385751724 -v -0.531349182129 0.833562910557 -0.126550495625 -v -0.487643718719 0.804054796696 -0.111395001411 -v -0.480391025543 0.801913261414 -0.119697570801 -v -0.480456352234 0.792149066925 -0.122189939022 -v -0.488045692444 0.794178664684 -0.112424015999 -v -0.495940208435 0.784620106220 -0.126145541668 -v -0.499251127243 0.786586403847 -0.129543840885 -v -0.504209518433 0.787554085255 -0.123033821583 -v -0.499408006668 0.785145521164 -0.121613442898 -v -0.510551452637 0.871032297611 -0.138833642006 -v -0.515317440033 0.871675372124 -0.137129485607 -v -0.526596546173 0.864687561989 -0.151889979839 -v -0.530538082123 0.864613473415 -0.148025453091 -v -0.497328281403 0.811198830605 -0.112283110619 -v -0.503155469894 0.790419399738 -0.130545675755 -v -0.506678104401 0.791445076466 -0.125318050385 -v -0.493824243546 0.871466159821 -0.085897326469 -v -0.490470170975 0.869438707829 -0.092285215855 -v -0.485040903091 0.863280296326 -0.091263115406 -v -0.487308979034 0.865945041180 -0.082743287086 -v -0.485924720764 0.855860471725 -0.088013470173 -v -0.489061117172 0.856862902641 -0.081349372864 -v -0.520172119141 0.836955487728 -0.100135803223 -v -0.515067815781 0.840695142746 -0.093722283840 -v -0.506313800812 0.841244280338 -0.101609706879 -v -0.510276794434 0.838908553123 -0.105833172798 -v -0.512242078781 0.857203602791 -0.107409000397 -v -0.522161960602 0.857336878777 -0.099027633667 -v -0.526552677155 0.854199707508 -0.105519115925 -v -0.515424251556 0.854900300503 -0.111687183380 -v -0.508421897888 0.847175776958 -0.111868441105 -v -0.505060672760 0.849078774452 -0.108070075512 -v -0.524366140366 0.847588360310 -0.093832015991 -v -0.527771949768 0.845007956028 -0.098792850971 -v -0.504534959793 0.847885608673 -0.086177408695 -v -0.498050689697 0.852172255516 -0.082087755203 -v -0.490575790405 0.850792109966 -0.091464221478 -v -0.496593952179 0.846407592297 -0.095529913902 -v -0.496419668198 0.867350459099 -0.096872746944 -v -0.503741264343 0.868512868881 -0.087242722511 -v -0.511126995087 0.864330530167 -0.091117858887 -v -0.503080606461 0.863209724426 -0.101341784000 -v -0.495740175247 0.854071259499 -0.103795528412 -v -0.489275217056 0.858667314053 -0.098730802536 -v -0.510396480560 0.857069015503 -0.083190023899 -v -0.506175994873 0.859634041786 -0.081316232681 -v -0.511812210083 0.838328003883 -0.109384715557 -v -0.512324810028 0.836986780167 -0.113109648228 -v -0.523508548737 0.831316888332 -0.112718701363 -v -0.519570350647 0.833538651466 -0.105941951275 -v -0.527900457382 0.853996634483 -0.113405644894 -v -0.530893802643 0.848428845406 -0.119828045368 -v -0.517930030823 0.852390527725 -0.120005369186 -v -0.516858100891 0.853576421738 -0.115721166134 -v -0.510461807251 0.846561253071 -0.116781532764 -v -0.510272741318 0.846948623657 -0.114067971706 -v -0.528704881668 0.833988189697 -0.105706632137 -v -0.529921531677 0.832707405090 -0.110456645489 -v -0.535176277161 0.837255477905 -0.113185763359 -v -0.535221815109 0.839498996735 -0.107395589352 -v -0.535897016525 0.844757020473 -0.115204930305 -v -0.535224437714 0.848018705845 -0.110409140587 -v -0.527960300446 0.836800575256 -0.101769506931 -v -0.532390594482 0.842326819897 -0.102183938026 -v -0.532948493958 0.849078893661 -0.105126917362 -v -0.501554489136 0.843218922615 -0.099216759205 -v -0.507042169571 0.842735946178 -0.091056108475 -v -0.515851497650 0.862206101418 -0.097064733505 -v -0.508196115494 0.859079062939 -0.104793012142 -v -0.501304626465 0.850616335869 -0.106691837311 -v -0.514235734940 0.845977485180 -0.086078166962 -v -0.518186092377 0.844501137733 -0.088461101055 -v -0.522804021835 0.849747896194 -0.088824689388 -v -0.519546508789 0.852388918400 -0.085314571857 -v -0.523418426514 0.855972528458 -0.091820836067 -v -0.520101308823 0.859155178070 -0.089708983898 -v -0.511596202850 0.849000573158 -0.083929896355 -v -0.515213012695 0.854938268661 -0.083392798901 -v -0.516395092010 0.860537409782 -0.087069749832 -v -0.532750368118 0.836167395115 -0.118552982807 -v -0.497567176819 0.865602970123 -0.074603199959 -v -0.496635437012 0.860588312149 -0.074069917202 -v -0.499092817307 0.859558403492 -0.075726687908 -v -0.501167774200 0.863645672798 -0.076683282852 -v -0.499398469925 0.869491815567 -0.076963126659 -v -0.502336740494 0.868161380291 -0.077675879002 -v -0.493256807327 0.858881592751 -0.076175630093 -v -0.492352008820 0.866495013237 -0.076975762844 -v -0.499328136444 0.856431543827 -0.076817274094 -v -0.503676176071 0.861703813076 -0.079042315483 -v -0.503543376923 0.868796229362 -0.080610632896 -v -0.497124195099 0.871228098869 -0.080048918724 -v -0.508443832397 0.800419390202 -0.136265814304 -v -0.511143684387 0.804700791836 -0.140411615372 -v -0.514699935913 0.806024491787 -0.133704960346 -v -0.511139869690 0.801549851894 -0.131215751171 -v -0.524834394455 0.834584176540 -0.149969577789 -v -0.528397083282 0.835094690323 -0.144962668419 -v -0.514429330826 0.810142576694 -0.141759753227 -v -0.517162799835 0.811100900173 -0.136384963989 -v -0.496298074722 0.786881387234 -0.115870833397 -v -0.486750125885 0.785451531410 -0.128098964691 -v -0.527594327927 0.869485437870 -0.141907572746 -v -0.518058300018 0.869149982929 -0.149671852589 -v -0.510817766190 0.799105167389 -0.121699333191 -v -0.512484073639 0.806650936604 -0.113031685352 -v -0.502429008484 0.813118338585 -0.111305117607 -v -0.508829832077 0.828153192997 -0.116886317730 -v -0.518706083298 0.822669982910 -0.117713034153 -v -0.501774787903 0.822176635265 -0.114453732967 -v -0.519619703293 0.812057256699 -0.116438627243 -v -0.517436027527 0.808292090893 -0.126053214073 -v -0.483708858490 0.853024780750 -0.088355422020 -v -0.481112241745 0.850262880325 -0.093426942825 -v -0.475982189178 0.844028592110 -0.091422438622 -v -0.477612257004 0.847269892693 -0.084727108479 -v -0.475871086121 0.837056696415 -0.086321115494 -v -0.478466987610 0.838783323765 -0.080502748489 -v -0.504234790802 0.817612648010 -0.093765556812 -v -0.500945329666 0.822281956673 -0.087224364281 -v -0.490716695786 0.824029862881 -0.093403875828 -v -0.494282245636 0.819924414158 -0.099487662315 -v -0.496157646179 0.841752350330 -0.100961446762 -v -0.505415439606 0.841348707676 -0.095487833023 -v -0.508846998215 0.836988449097 -0.101620197296 -v -0.499357938766 0.838020980358 -0.106621682644 -v -0.492764949799 0.830117106438 -0.105411946774 -v -0.489102363586 0.833834648132 -0.099696338177 -v -0.508481979370 0.830541670322 -0.089690744877 -v -0.510588169098 0.827774941921 -0.093720853329 -v -0.492753744125 0.831151664257 -0.079553246498 -v -0.486364841461 0.835210800171 -0.078461050987 -v -0.479637861252 0.832388997078 -0.086949884892 -v -0.484333038330 0.829082310200 -0.088134169579 -v -0.485946178436 0.848959863186 -0.095764815807 -v -0.492048025131 0.851611673832 -0.087720692158 -v -0.497788429260 0.848133265972 -0.089569866657 -v -0.490402221680 0.846298635006 -0.097313344479 -v -0.483847379684 0.837090373039 -0.096990287304 -v -0.479485511780 0.840040266514 -0.095492541790 -v -0.497706413269 0.841334342957 -0.080382227898 -v -0.493602514267 0.843913137913 -0.079816043377 -v -0.498492002487 0.817435145378 -0.105219185352 -v -0.501165628433 0.814163446426 -0.109083890915 -v -0.511910438538 0.809615671635 -0.104608774185 -v -0.505473136902 0.811411023140 -0.099508881569 -v -0.510790824890 0.835031032562 -0.109548807144 -v -0.516519069672 0.828535556793 -0.111123204231 -v -0.506266832352 0.830387651920 -0.115914404392 -v -0.502544403076 0.833584547043 -0.112453937531 -v -0.499927043915 0.823450028896 -0.114233195782 -v -0.497344493866 0.826164782047 -0.110643565655 -v -0.513412475586 0.815074205399 -0.096650004387 -v -0.516290664673 0.813745021820 -0.099655687809 -v -0.519789934158 0.819998562336 -0.101308584213 -v -0.517743349075 0.822623610497 -0.098065078259 -v -0.519121646881 0.827042996883 -0.104812145233 -v -0.516560077667 0.830451726913 -0.103179037571 -v -0.511471986771 0.818441748619 -0.094288408756 -v -0.514646053314 0.825179815292 -0.095527946949 -v -0.514303207397 0.831783711910 -0.099781036377 -v -0.487943172455 0.827379703522 -0.090247273445 -v -0.495469808578 0.824954450130 -0.082411110401 -v -0.500364780426 0.846157968044 -0.094868063927 -v -0.493069171906 0.843513786793 -0.098693013191 -v -0.487038612366 0.835436344147 -0.097534894943 -v -0.502112865448 0.828593492508 -0.079975128174 -v -0.504857540131 0.826588690281 -0.083056867123 -v -0.508306980133 0.833120644093 -0.085304498672 -v -0.506083965302 0.836166918278 -0.082021951675 -v -0.507864236832 0.840063154697 -0.089241921902 -v -0.505406856537 0.843329131603 -0.087880432606 -v -0.499519109726 0.832336187363 -0.078415036201 -v -0.502271652222 0.839114248753 -0.080325365067 -v -0.502671241760 0.844747602940 -0.085275530815 -v -0.520011425018 0.816879510880 -0.107176601887 -v -0.485849618912 0.848793625832 -0.077213406563 -v -0.484879255295 0.844172120094 -0.075477480888 -v -0.486962318420 0.843352615833 -0.076518177986 -v -0.488926410675 0.847343027592 -0.078180730343 -v -0.487652778625 0.852373063564 -0.079998552799 -v -0.490156412125 0.851481437683 -0.079959809780 -v -0.482032775879 0.841814160347 -0.076701343060 -v -0.481650590897 0.848758876324 -0.079696655273 -v -0.487200260162 0.840355038643 -0.076348960400 -v -0.491241216660 0.845820188522 -0.079050183296 -v -0.491406917572 0.852079093456 -0.082417190075 -v -0.486078977585 0.853447556496 -0.083156108856 -v -0.498555898666 0.789247334003 -0.110209047794 -v -0.490535259247 0.795914649963 -0.107083380222 -v -0.499561071396 0.808594465256 -0.109262883663 -v -0.509321451187 0.801345944405 -0.113677084446 -v -0.491660594940 0.804835021496 -0.106762707233 -v -0.506342411041 0.790087342262 -0.117207169533 -v -0.507618427277 0.792013823986 -0.113375782967 -v -0.489049196243 0.826286792755 -0.079535543919 -v -0.485815525055 0.826620817184 -0.084511041641 -v -0.480561256409 0.821815013885 -0.084118247032 -v -0.483257293701 0.822232902050 -0.077751755714 -v -0.479671239853 0.815304994583 -0.082047581673 -v -0.482170104980 0.815054416656 -0.077047288418 -v -0.498437404633 0.795974731445 -0.094222247601 -v -0.495993852615 0.799155712128 -0.089099407196 -v -0.488581657410 0.803750157356 -0.092741906643 -v -0.489798069000 0.801814615726 -0.097452342510 -v -0.499174118042 0.816335558891 -0.095021665096 -v -0.505331993103 0.810285627842 -0.091094553471 -v -0.508020877838 0.806802392006 -0.096497237682 -v -0.500244140625 0.813882708549 -0.098373711109 -v -0.491198301315 0.810434281826 -0.099174976349 -v -0.490566730499 0.812255382538 -0.095983982086 -v -0.504388093948 0.801935672760 -0.089532196522 -v -0.506303787231 0.799559772015 -0.093178451061 -v -0.490227460861 0.806715846062 -0.080041587353 -v -0.486819744110 0.810494184494 -0.077443838120 -v -0.481586694717 0.811227262020 -0.084623336792 -v -0.484838962555 0.807765960693 -0.087508916855 -v -0.489450216293 0.825551927090 -0.087533473969 -v -0.494817018509 0.822417318821 -0.080430269241 -v -0.498338937759 0.818705558777 -0.082634210587 -v -0.493239879608 0.822486460209 -0.090337991714 -v -0.485663890839 0.816083729267 -0.092872619629 -v -0.482256412506 0.819070279598 -0.089587986469 -v -0.495429277420 0.813326537609 -0.077522575855 -v -0.493692398071 0.815349698067 -0.076042175293 -v -0.490639209747 0.799663007259 -0.100690245628 -v -0.491382598877 0.797495901585 -0.103254914284 -v -0.500654220581 0.789737641811 -0.104475378990 -v -0.497671604156 0.792602598667 -0.098903775215 -v -0.509530782700 0.806396782398 -0.102260172367 -v -0.511167049408 0.801594376564 -0.108417809010 -v -0.500758171082 0.809814274311 -0.105136036873 -v -0.500140190125 0.811406195164 -0.101884782314 -v -0.491745948792 0.806727945805 -0.103401362896 -v -0.492305278778 0.808004617691 -0.101605892181 -v -0.505864143372 0.790762722492 -0.098364591599 -v -0.506949424744 0.789222061634 -0.102397680283 -v -0.511898517609 0.792011439800 -0.104481697083 -v -0.511413574219 0.793921768665 -0.099860727787 -v -0.513942241669 0.797082841396 -0.105452656746 -v -0.513425111771 0.799474656582 -0.101383924484 -v -0.505221366882 0.793554723263 -0.095338940620 -v -0.509412050247 0.796497941017 -0.095882833004 -v -0.511485099792 0.800802588463 -0.097495257854 -v -0.487203598022 0.805865585804 -0.089809119701 -v -0.491508483887 0.801817178726 -0.084747970104 -v -0.501916170120 0.816967248917 -0.087054252625 -v -0.496026515961 0.819197714329 -0.092714369297 -v -0.489030599594 0.813616871834 -0.094238102436 -v -0.496573925018 0.803260147572 -0.081626772881 -v -0.499391555786 0.800740122795 -0.084920167923 -v -0.503435134888 0.803725183010 -0.085128188133 -v -0.500617980957 0.807261526585 -0.080836713314 -v -0.505204677582 0.808161199093 -0.085975766182 -v -0.502797126770 0.812113285065 -0.082701086998 -v -0.494894981384 0.806727290154 -0.079006910324 -v -0.497905254364 0.810785889626 -0.078416407108 -v -0.500154018402 0.814402937889 -0.080199837685 -v -0.509780406952 0.792054593563 -0.109013736248 -v -0.489554882050 0.819736123085 -0.072930335999 -v -0.487940311432 0.816487431526 -0.072609961033 -v -0.489381313324 0.815415918827 -0.073478043079 -v -0.491574764252 0.818117618561 -0.074059128761 -v -0.491600751877 0.822124600410 -0.074348628521 -v -0.493067026138 0.820745110512 -0.075044274330 -v -0.485497951508 0.815698802471 -0.073549985886 -v -0.486885070801 0.821202099323 -0.073756098747 -v -0.488751888275 0.812952458858 -0.073907077312 -v -0.492937803268 0.816626131535 -0.074767291546 -v -0.494431257248 0.821339190006 -0.076288044453 -v -0.491227149963 0.824168622494 -0.075623750687 -v -0.527001857758 0.853478670120 -0.125246942043 -v -0.513896465302 0.857641816139 -0.126969873905 -v -0.517309665680 0.873407602310 -0.133468151093 -v -0.529544591904 0.871562659740 -0.133002638817 -v -0.510344266891 0.866749882698 -0.130797505379 -v -0.535715341568 0.858517348766 -0.139212429523 -v -0.535772323608 0.861216902733 -0.129334509373 -v -0.490445613861 0.890650033951 -0.100051939487 -v -0.488363265991 0.888513207436 -0.107455074787 -v -0.485354423523 0.880579829216 -0.108673691750 -v -0.485455274582 0.882985472679 -0.099698960781 -v -0.487403631210 0.872754931450 -0.105823457241 -v -0.488933801651 0.873876035213 -0.098851382732 -v -0.518436908722 0.863012790680 -0.108661413193 -v -0.512920618057 0.866162419319 -0.104191660881 -v -0.507155895233 0.865417718887 -0.113856613636 -v -0.510566711426 0.863865315914 -0.116527736187 -v -0.512574672699 0.881888926029 -0.117601990700 -v -0.519688844681 0.883390605450 -0.107507109642 -v -0.524630069733 0.880152225494 -0.113091707230 -v -0.515925884247 0.879324555397 -0.120808780193 -v -0.509762763977 0.871237039566 -0.122120618820 -v -0.506671428680 0.872891902924 -0.120059609413 -v -0.521101236343 0.874487102032 -0.101826131344 -v -0.524887323380 0.872092723846 -0.105790376663 -v -0.502747774124 0.870004713535 -0.100400567055 -v -0.497266054153 0.871715247631 -0.097897529602 -v -0.492583751678 0.869514763355 -0.108082056046 -v -0.498463630676 0.867662549019 -0.110751748085 -v -0.494890928268 0.888140499592 -0.110826432705 -v -0.499839544296 0.889504313469 -0.100029766560 -v -0.507523536682 0.887580394745 -0.102457940578 -v -0.502919435501 0.885920166969 -0.114045023918 -v -0.498455524445 0.875417351723 -0.118292808533 -v -0.491332054138 0.877597153187 -0.115070879459 -v -0.506424903870 0.879839777946 -0.096214175224 -v -0.503129482269 0.880639374256 -0.095109224319 -v -0.512672424316 0.862300992012 -0.120484471321 -v -0.513113737106 0.860535264015 -0.123115837574 -v -0.525039196014 0.856878221035 -0.118569016457 -v -0.519091129303 0.858681201935 -0.114477872849 -v -0.526840448380 0.879119575024 -0.120443284512 -v -0.530992031097 0.874435842037 -0.125046432018 -v -0.518256187439 0.875537931919 -0.128518223763 -v -0.517742633820 0.876998245716 -0.124922633171 -v -0.511662721634 0.868683815002 -0.127072453499 -v -0.511864900589 0.869614481926 -0.124864697456 -v -0.530849933624 0.860190629959 -0.111503541470 -v -0.533360242844 0.859168589115 -0.115616202354 -v -0.536691904068 0.865351617336 -0.116629421711 -v -0.534475564957 0.867561042309 -0.111754179001 -v -0.535916090012 0.871988415718 -0.118930697441 -v -0.533593416214 0.874997556210 -0.115182757378 -v -0.527114391327 0.863506555557 -0.108078002930 -v -0.529962301254 0.869924604893 -0.107841134071 -v -0.530357837677 0.875990808010 -0.111109972000 -v -0.503102540970 0.866510391235 -0.113218367100 -v -0.505452632904 0.866206705570 -0.104708135128 -v -0.513443470001 0.887060940266 -0.106990933418 -v -0.508520841599 0.883631944656 -0.116348564625 -v -0.503959178925 0.873957514763 -0.119046747684 -v -0.510499000549 0.870763242245 -0.097471833229 -v -0.514724016190 0.870366811752 -0.098390698433 -v -0.518878698349 0.876383900642 -0.097725093365 -v -0.514991760254 0.878054201603 -0.095596671104 -v -0.519540309906 0.882226943970 -0.100633978844 -v -0.515974521637 0.884334146976 -0.099541544914 -v -0.507736682892 0.872971475124 -0.096328496933 -v -0.510526895523 0.879325091839 -0.095016777515 -v -0.511901855469 0.884887933731 -0.097839653492 -v -0.535580873489 0.863515138626 -0.121753752232 -v -0.494115114212 0.883353888988 -0.090229034424 -v -0.494159221649 0.878465473652 -0.090765476227 -v -0.496655464172 0.878225266933 -0.091974556446 -v -0.497776508331 0.882385611534 -0.092055082321 -v -0.494970798492 0.887757301331 -0.091351509094 -v -0.497639894485 0.886616647243 -0.092495083809 -v -0.491739749908 0.876264393330 -0.093018054962 -v -0.489335536957 0.883648872375 -0.093107581139 -v -0.497393131256 0.875543773174 -0.093272686005 -v -0.500410795212 0.881527364254 -0.093731045723 -v -0.499048471451 0.888204634190 -0.094248950481 -v -0.492660522461 0.889721930027 -0.094091176987 -v -0.521483898163 0.842776119709 -0.155532121658 -v -0.518549919128 0.858851313591 -0.158480763435 -v -0.513115406036 0.815885305405 -0.150368809700 -v -0.514750003815 0.828490138054 -0.158624708652 -v -0.504255294800 0.803942263126 -0.149980843067 -v -0.471243858337 0.786971271038 -0.142925024033 -v -0.466823101044 0.792440652847 -0.134708881378 -v -0.454370021820 0.826037108898 -0.138828337193 -v -0.495823860168 0.816522121429 -0.171279489994 -v -0.490122318268 0.804616093636 -0.166800975800 -v -0.501922845840 0.864825129509 -0.167882800102 -v -0.488729238510 0.869901716709 -0.140693187714 -v -0.494021654129 0.873752593994 -0.152330935001 -v -0.487847566605 0.878740549088 -0.152684986591 -v -0.480398416519 0.872110724449 -0.138898909092 -v -0.463868141174 0.866027951241 -0.132292509079 -v -0.478146791458 0.862194061279 -0.133633494377 -v -0.463702440262 0.875368595123 -0.127856612206 -v -0.453201293945 0.882918894291 -0.131946742535 -v -0.446355819702 0.873552322388 -0.141134619713 -v -0.483682394028 0.883540391922 -0.145150899887 -v -0.476632833481 0.876343607903 -0.133325040340 -v -0.484167098999 0.901457369328 -0.093008697033 -v -0.485260963440 0.893595635891 -0.095105886459 -v -0.483138322830 0.889306485653 -0.131258606911 -v -0.477747440338 0.882396876812 -0.121179759502 -v -0.476070404053 0.880022823811 -0.127019524574 -v -0.481888771057 0.887317419052 -0.138192296028 -v -0.468255043030 0.884616315365 -0.116226017475 -v -0.464697837830 0.881538629532 -0.122920870781 -v -0.479435443878 0.900566041470 -0.136166751385 -v -0.477606296539 0.898043036461 -0.145556926727 -v -0.468045234680 0.902096092701 -0.133089959621 -v -0.465980529785 0.900569677353 -0.139554977417 -v -0.462095737457 0.895440816879 -0.121656596661 -v -0.457749605179 0.892096400261 -0.130192101002 -v -0.470758438110 0.897547125816 -0.155327796936 -v -0.466237306595 0.894115865231 -0.159044146538 -v -0.457171916962 0.892076790333 -0.153369426727 -v -0.461186885834 0.897225439548 -0.149793088436 -v -0.450381755829 0.887220442295 -0.144794583321 -v -0.453635215759 0.891810834408 -0.140942871571 -v -0.480525970459 0.891566216946 -0.156198561192 -v -0.471389532089 0.900366127491 -0.149930894375 -v -0.463864564896 0.900258302689 -0.145290255547 -v -0.457410335541 0.896189451218 -0.139161109924 -v -0.469795703888 0.888008773327 -0.165396869183 -v -0.452988624573 0.883881807327 -0.157703280449 -v -0.491194486618 0.891927838326 -0.114754319191 -v -0.486534357071 0.885707378387 -0.106756806374 -v -0.479014396667 0.889679074287 -0.100693225861 -v -0.489616870880 0.903515696526 -0.117441117764 -v -0.487568616867 0.908877730370 -0.099188625813 -v -0.490461826324 0.908248662949 -0.103589415550 -v -0.486899375916 0.906276345253 -0.106632411480 -v -0.481706142426 0.906772732735 -0.103209018707 -v -0.484368562698 0.908297657967 -0.096467256546 -v -0.480246782303 0.906286239624 -0.099046111107 -v -0.472922801971 0.901211500168 -0.101609766483 -v -0.481368541718 0.883780658245 -0.114653468132 -v -0.486560106277 0.890575349331 -0.123603880405 -v -0.473132371902 0.886498153210 -0.109143614769 -v -0.485536098480 0.901406943798 -0.128164887428 -v -0.480238437653 0.907655954361 -0.126654922962 -v -0.476631164551 0.906661093235 -0.131565809250 -v -0.469987869263 0.906214416027 -0.128223299980 -v -0.473164319992 0.908138692379 -0.122179150581 -v -0.465127468109 0.902755975723 -0.122632205486 -v -0.467630147934 0.903878688812 -0.116376280785 -v -0.467125654221 0.895816802979 -0.111212134361 -v -0.482595682144 0.906823217869 -0.120295464993 -v -0.477108955383 0.906865596771 -0.115525126457 -v -0.472041606903 0.904061913490 -0.110747873783 -v -0.477966785431 0.905460000038 -0.110133111477 -v -0.493883132935 0.907011985779 -0.104439914227 -v -0.491958379745 0.907425343990 -0.096913754940 -v -0.489140272141 0.905874848366 -0.111298918724 -v -0.479014158249 0.906400084496 -0.107349276543 -v -0.476996898651 0.905042469501 -0.099129199982 -v -0.484606742859 0.906890451908 -0.093938052654 -v -0.491485834122 0.862887859344 -0.133998870850 -v -0.478189468384 0.851019322872 -0.133088052273 -v -0.436126470566 0.836560726166 -0.156523883343 -v -0.442461729050 0.835687577724 -0.147658109665 -v -0.441426515579 0.845188915730 -0.148403167725 -v -0.437577724457 0.854609191418 -0.159161508083 -v -0.454926490784 0.834215760231 -0.140588104725 -v -0.462005615234 0.792235910892 -0.166105270386 -v -0.456657409668 0.791631460190 -0.155758082867 -v -0.483422994614 0.867121934891 -0.181242167950 -v -0.468945980072 0.855017066002 -0.193509101868 -v -0.462913751602 0.870561540127 -0.183496356010 -v -0.491529464722 0.874752402306 -0.165132880211 -v -0.487841367722 0.878770470619 -0.162872314453 -v -0.468900203705 0.836523592472 -0.196922063828 -v -0.479998111725 0.818049311638 -0.186679184437 -v -0.499879121780 0.870677828789 -0.139983534813 -v -0.504315376282 0.871536970139 -0.151580274105 -v -0.454349756241 0.840840578079 -0.139953255653 -v -0.480731725693 0.877718329430 -0.174314856529 -v -0.464861869812 0.879262804985 -0.174113869667 -v -0.446362018585 0.868979811668 -0.170653223991 -v -0.449486732483 0.874917387962 -0.165948867798 -v -0.440111875534 0.863788783550 -0.154974460602 -v -0.441115617752 0.851662218571 -0.146024465561 -v -0.454034090042 0.845933496952 -0.138140499592 -v -0.456007719040 0.854448795319 -0.133829414845 -v -0.469702482224 0.854526937008 -0.132327675819 -v -0.444778442383 0.858243584633 -0.139310777187 -v -0.481812000275 0.882776081562 -0.167174339294 -v -0.484746932983 0.884817302227 -0.160003304482 -v -0.442131519318 0.811856746674 -0.148359179497 -v -0.436752319336 0.819676995277 -0.155522286892 -v -0.452622652054 0.797102570534 -0.146845281124 -v -0.443253278732 0.825838088989 -0.145939826965 -v -0.444576740265 0.818954288960 -0.143559813499 -v -0.433326005936 0.807289421558 -0.173588871956 -v -0.441542625427 0.803750753403 -0.187457442284 -v -0.430660247803 0.819438576698 -0.164661586285 -v -0.430188417435 0.836086511612 -0.162424981594 -v -0.432472229004 0.853630959988 -0.163688778877 -v -0.439163208008 0.866289258003 -0.172386646271 -v -0.448523044586 0.868499755859 -0.185838401318 -v -0.454426765442 0.857727229595 -0.197017431259 -v -0.454931259155 0.839325785637 -0.202164053917 -v -0.465736627579 0.819396853447 -0.194947898388 -v -0.450971364975 0.817552566528 -0.198323130608 -v -0.456123352051 0.800768375397 -0.183851480484 -v -0.468741416931 0.797707617283 -0.175054907799 -v -0.425196409225 0.807017326355 -0.182153224945 -v -0.429808616638 0.808018207550 -0.197672486305 -v -0.423538684845 0.817356407642 -0.170044660568 -v -0.423536777496 0.833735704422 -0.165797650814 -v -0.425173997879 0.851301014423 -0.165531635284 -v -0.430070877075 0.863844513893 -0.173078656197 -v -0.436095714569 0.867850482464 -0.187229573727 -v -0.440057992935 0.861827850342 -0.201652050018 -v -0.439754009247 0.844789445400 -0.210174918175 -v -0.435653448105 0.823165953159 -0.207971274853 -v -0.419240474701 0.811311781406 -0.205702304840 -v -0.414561510086 0.807009160519 -0.189636647701 -v -0.403192281723 0.809433162212 -0.199932932854 -v -0.409330129623 0.817718327045 -0.216658353806 -v -0.413339853287 0.815283596516 -0.174596428871 -v -0.399246454239 0.813498079777 -0.181282222271 -v -0.413203001022 0.829875349998 -0.168070018291 -v -0.397543668747 0.824719786644 -0.171226143837 -v -0.395318984985 0.834834337234 -0.168890595436 -v -0.408400058746 0.846953988075 -0.167888164520 -v -0.413450241089 0.863622665405 -0.173395872116 -v -0.419510841370 0.872239351273 -0.188069701195 -v -0.424756288528 0.871203422546 -0.206108510494 -v -0.424194335938 0.854732930660 -0.219132661819 -v -0.414286136627 0.851325511932 -0.227738976479 -v -0.424114227295 0.828399658203 -0.215525388718 -v -0.413206815720 0.834980130196 -0.225028336048 -v -0.474735736847 0.806489527225 -0.181779563427 -v -0.461838483810 0.807741761208 -0.190207779408 -v -0.450213432312 0.803499877453 -0.189132690430 -v -0.453882694244 0.808152139187 -0.192983090878 -v -0.063398599625 0.425415545702 -0.004801809788 -v -0.057441711426 0.421231210232 0.011059165001 -v -0.042950868607 0.417842894793 0.021519958973 -v 0.144121408463 0.511780261993 0.077085554600 -v 0.108297348022 0.528908789158 0.076607823372 -v 0.103316783905 0.511069953442 0.013130068779 -v 0.120876550674 0.499709635973 0.015783727169 -v 0.143322706223 0.510246276855 0.023608624935 -v 0.161252737045 0.523530781269 0.064749538898 -v 0.152065515518 0.501725971699 -0.009824156761 -v 0.140231609344 0.498346298933 -0.030532300472 -v 0.192918300629 0.507425546646 -0.030843675137 -v 0.185611486435 0.508959054947 -0.011636078358 -v 0.187336921692 0.531630814075 -0.041304111481 -v 0.124450206757 0.523272991180 -0.047710359097 -v 0.227248430252 0.552403509617 -0.004147112370 -v 0.228659629822 0.532396197319 -0.002932310104 -v 0.227637529373 0.592922449112 0.034270524979 -v 0.233801364899 0.565752506256 0.035560011864 -v 0.223552703857 0.587897717953 -0.008055388927 -v 0.221391916275 0.630149424076 0.032777488232 -v 0.188503026962 0.624325811863 0.092208683491 -v 0.197622060776 0.591138243675 0.090726375580 -v 0.214549303055 0.686934411526 0.045682489872 -v 0.187195301056 0.673267960548 0.099526941776 -v 0.216737031937 0.692575335503 -0.008495330811 -v 0.199777126312 0.701083362103 -0.008754312992 -v 0.194094419479 0.686676740646 0.034240126610 -v 0.220711708069 0.636359512806 -0.020351350307 -v 0.182755708694 0.725424706936 -0.089372277260 -v 0.179335832596 0.729352295399 -0.071519851685 -v 0.187209367752 0.650559663773 -0.072877883911 -v 0.166259288788 0.675132751465 0.078442573547 -v 0.195732593536 0.668351173401 0.035658538342 -v 0.165970325470 0.662057161331 0.079006195068 -v 0.184274196625 0.697052001953 -0.025637030602 -v 0.136685848236 0.621061325073 0.124828457832 -v 0.146819353104 0.581296682358 0.115078270435 -v 0.209793090820 0.565983176231 0.086855173111 -v 0.165661096573 0.548517227173 0.104174733162 -v 0.134027719498 0.671311855316 0.129685342312 -v 0.078870058060 0.624179244041 0.127473473549 -v 0.088960170746 0.573084473610 0.105961620808 -v 0.077410221100 0.682400047779 0.141914546490 -v 0.184307813644 0.588923692703 -0.058013796806 -v 0.129453897476 0.595893144608 -0.086390793324 -v 0.133975744247 0.663929998875 -0.106234252453 -v 0.236451148987 0.552949547768 0.037623882294 -v 0.224511861801 0.541902184486 0.036363959312 -v 0.211948394775 0.525437772274 0.006383121014 -v 0.214318037033 0.545253038406 0.069983601570 -v 0.212549924850 0.552964806557 0.068517923355 -v 0.224463939667 0.549749970436 0.033728003502 -v 0.218957901001 0.557131946087 0.083203673363 -v 0.187869310379 0.532874941826 0.092133939266 -v 0.187714338303 0.534057557583 0.080063939095 -v 0.181240797043 0.545281291008 0.081068098545 -v 0.146420955658 0.531102359295 0.067861676216 -v 0.212937355042 0.534900724888 0.000919044018 -v 0.184135675430 0.516894340515 -0.018340229988 -v 0.071259021759 0.544855475426 -0.057795166969 -v 0.062549352646 0.523616433144 0.002657234669 -v 0.072495937347 0.605195105076 -0.099032998085 -v 0.012754201889 0.670661449432 -0.129763662815 -v 0.074255228043 0.671743631363 -0.122924923897 -v 0.016004562378 0.604284882545 -0.108093738556 -v -0.047175407410 0.665716767311 -0.120963096619 -v -0.047187089920 0.735366821289 -0.127462327480 -v 0.014084577560 0.746303260326 -0.145008087158 -v -0.093496322632 0.661609470844 -0.084233760834 -v -0.096379756927 0.725130677223 -0.084452211857 -v -0.035370826721 0.739451408386 -0.115991532803 -v 0.016326665878 0.748082160950 -0.129412829876 -v -0.076249361038 0.729390442371 -0.078382790089 -v -0.043362140656 0.605586290359 -0.104780077934 -v -0.089107990265 0.608498692513 -0.073513865471 -v -0.114396095276 0.659402668476 -0.028737843037 -v -0.114691495895 0.720096588135 -0.025828123093 -v -0.112749338150 0.613461971283 -0.024391472340 -v 0.026057243347 0.539770305157 -0.068712770939 -v -0.036364793777 0.558640837669 -0.091128528118 -v 0.081735372543 0.748860776424 -0.142071723938 -v 0.138632535934 0.742601990700 -0.123913228512 -v 0.074531555176 0.752696514130 -0.124717712402 -v 0.130490541458 0.744501113892 -0.108744025230 -v 0.031629323959 0.521139383316 -0.005045592785 -v 0.039030313492 0.551695644855 0.056075632572 -v -0.001458644867 0.553142666817 0.050433158875 -v 0.022727251053 0.514308512211 -0.007078170776 -v 0.018694400787 0.521275639534 -0.064219474792 -v -0.013375759125 0.545891344547 0.025897085667 -v 0.010625362396 0.528762698174 -0.008753895760 -v -0.013785123825 0.537784159184 0.044802665710 -v -0.003431797028 0.556365251541 0.031631588936 -v 0.021438360214 0.537024855614 -0.007674217224 -v -0.044837236404 0.555213034153 0.041083216667 -v -0.037632226944 0.567453145981 0.046529829502 -v -0.051511764526 0.550408124924 0.056568264961 -v -0.049501657486 0.569334208965 0.059367895126 -v -0.012590885162 0.593995332718 0.081816494465 -v -0.056488513947 0.606606721878 0.067150175571 -v 0.028929233551 0.585341632366 0.093791067600 -v 0.008466243744 0.527554392815 -0.046013593674 -v 0.015324592590 0.539409756660 -0.046251296997 -v -0.025128364563 0.548998892307 -0.059863686562 -v -0.028495788574 0.536334693432 -0.059524655342 -v -0.034542560577 0.529292702675 -0.083323836327 -v 0.145991802216 0.508340239525 -0.014416158199 -v 0.131390333176 0.516479372978 0.021855235100 -v 0.026699304581 0.634563446045 0.117274522781 -v -0.020232677460 0.642315804958 0.100721597672 -v -0.026278018951 0.702590823174 0.111697435379 -v -0.068937778473 0.706630170345 0.078983545303 -v -0.064911603928 0.651495337486 0.071269571781 -v -0.015012741089 0.704616785049 0.095527708530 -v -0.054348468781 0.709064245224 0.065617680550 -v 0.026480436325 0.697825789452 0.111364364624 -v 0.025828838348 0.691604137421 0.109849214554 -v -0.014955997467 0.698180437088 0.094332814217 -v 0.071362495422 0.688030838966 0.115027904510 -v 0.069956779480 0.677348077297 0.113705933094 -v 0.121142864227 0.674957156181 0.104752779007 -v 0.119457006454 0.664903819561 0.103474259377 -v 0.021538257599 0.694689214230 0.131033778191 -v -0.053185701370 0.703009426594 0.064263105392 -v -0.084846496582 0.713242530823 0.025584518909 -v -0.102933645248 0.712332844734 0.035015225410 -v -0.095738649368 0.717043399811 -0.024513781071 -v -0.100670337677 0.658007621765 0.027561366558 -v -0.096192121506 0.614809751511 0.028727471828 -v -0.093750953674 0.575753808022 0.032837092876 -v -0.107775926590 0.575954735279 -0.015404582024 -v -0.076748132706 0.721031785011 -0.079203486443 -v -0.095304489136 0.708831727505 -0.024215877056 -v -0.035797357559 0.727729797363 -0.117839038372 -v 0.016345024109 0.738378584385 -0.135166823864 -v -0.084352016449 0.707949042320 0.025263905525 -v -0.074731111526 0.537435054779 -0.053000748158 -v -0.060385465622 0.543911695480 -0.041588306427 -v -0.085829257965 0.563987195492 -0.064947962761 -v -0.100173950195 0.556139528751 -0.010330975056 -v -0.076323747635 0.554702341557 -0.007672071457 -v -0.072488784790 0.558982849121 0.027619063854 -v -0.093396186829 0.559440493584 0.031786739826 -v -0.076028823853 0.564334809780 -0.006530702114 -v -0.068377733231 0.567896723747 0.030334770679 -v -0.061259269714 0.555227398872 -0.041971862316 -v 0.073889255524 0.745370209217 -0.123060703278 -v 0.128804206848 0.738630473614 -0.107519149780 -v 0.170720815659 0.713177621365 -0.074004113674 -v 0.014654159546 0.516860008240 -0.008520841599 -v 0.013562679291 0.518869280815 -0.057164371014 -v -0.016606330872 0.536776065826 0.037213981152 -v -0.049576044083 0.547559082508 0.050266206264 -v -0.032561779022 0.526100814342 -0.075417101383 -v -0.081507205963 0.541957616806 -0.059140264988 -v -0.090506315231 0.551226019859 -0.008307635784 -v -0.086373806000 0.554394304752 0.030092954636 -v 0.154227733612 0.513570308685 0.073047876358 -v 0.132213592529 0.500396609306 0.018915951252 -v 0.146581411362 0.496055126190 -0.020876288414 -v 0.191246986389 0.503775417805 -0.022085011005 -v 0.222658157349 0.525225639343 0.000867187977 -v 0.230988979340 0.543813467026 0.037524938583 -v 0.219683170319 0.549111723900 0.076172590256 -v 0.182136535645 0.536433517933 0.100669324398 -v 0.046369791031 0.719563126564 0.135822176933 -v 0.042241811752 0.721289813519 0.120435237885 -v -0.003053903580 0.735716164112 0.113252401352 -v -0.001557350159 0.734151005745 0.128390729427 -v 0.048724651337 0.693842947483 0.145092248917 -v 0.088016271591 0.680101275444 0.143559694290 -v 0.088751792908 0.712511181831 0.134645402431 -v -0.005078792572 0.687308907509 0.133116126060 -v 0.005204916000 0.678244352341 0.114929139614 -v 0.045290470123 0.679847002029 0.130735397339 -v -0.046638011932 0.679906129837 0.107797205448 -v -0.036025047302 0.673013865948 0.093445062637 -v -0.047019481659 0.748887658119 0.117437124252 -v -0.043670654297 0.749698400497 0.105795860291 -v -0.083326578140 0.758892953396 0.081229805946 -v -0.092339754105 0.758642017841 0.089627742767 -v -0.084635972977 0.674705922604 0.074784040451 -v -0.118670225143 0.769500553608 0.044728934765 -v -0.110567569733 0.675210475922 0.032601892948 -v -0.073696851730 0.668749451637 0.062748491764 -v -0.096913099289 0.669786691666 0.024165332317 -v -0.136384248734 0.778806865215 -0.006764948368 -v -0.125165224075 0.685560584068 -0.010455846786 -v -0.128728628159 0.779637575150 -0.004121005535 -v -0.123834848404 0.788750588894 -0.051987946033 -v -0.134121894836 0.787187457085 -0.055941343307 -v -0.112501621246 0.770408868790 0.043770790100 -v -0.125114917755 0.696647584438 -0.048348546028 -v 0.088402271271 0.679888308048 0.132619023323 -v 0.127837419510 0.673484921455 0.119722843170 -v 0.132176876068 0.673645257950 0.122276902199 -v 0.162997484207 0.673051953316 0.104590058327 -v 0.168073177338 0.673548042774 0.111319541931 -v 0.194190502167 0.675714135170 0.075663864613 -v 0.201750755310 0.681370317936 0.081253111362 -v 0.160883426666 0.700167834759 0.107342004776 -v 0.126739978790 0.702453672886 0.123044371605 -v 0.196573019028 0.701241195202 0.081610202789 -v 0.218851804733 0.692234337330 0.023782670498 -v 0.218031644821 0.722697138786 0.022761344910 -v 0.211975812912 0.697270512581 -0.019005358219 -v 0.210978746414 0.684415698051 0.022575974464 -v 0.206652164459 0.696023881435 -0.015635728836 -v 0.217346906662 0.742312967777 -0.024935722351 -v 0.212719678879 0.723642468452 0.022974371910 -v 0.189186811447 0.703710496426 0.071625590324 -v 0.151532173157 0.701240718365 0.096213757992 -v 0.119452953339 0.703918457031 0.109877347946 -v 0.084906578064 0.714441061020 0.121117770672 -v -0.109468936920 0.675620913506 -0.013445198536 -v -0.102214574814 0.688136637211 -0.049785196781 -v -0.112360954285 0.709139764309 -0.096938610077 -v -0.090363025665 0.703007459641 -0.084746301174 -v -0.079424858093 0.723271906376 -0.131462454796 -v -0.063344240189 0.716237366199 -0.108357429504 -v -0.031183481216 0.732107281685 -0.152232766151 -v -0.028877019882 0.723726272583 -0.136132776737 -v 0.020634174347 0.744759976864 -0.156958043575 -v 0.014694929123 0.733487784863 -0.142659604549 -v 0.069174766541 0.743137419224 -0.152602612972 -v 0.061331748962 0.735695242882 -0.140975654125 -v 0.110146522522 0.735085666180 -0.144149661064 -v 0.103978872299 0.731820046902 -0.132717370987 -v 0.077984094620 0.798910439014 -0.141461968422 -v 0.119859457016 0.790866315365 -0.137311816216 -v 0.074426889420 0.802294850349 -0.135301411152 -v 0.116223812103 0.793579339981 -0.130329132080 -v 0.161331653595 0.781449317932 -0.127611219883 -v 0.152729034424 0.728924751282 -0.130435585976 -v 0.157443046570 0.783650875092 -0.121536970139 -v 0.016957759857 0.807849287987 -0.168082594872 -v 0.013961553574 0.810384929180 -0.162219345570 -v 0.142093658447 0.720312654972 -0.115514278412 -v 0.183982133865 0.712360918522 -0.110098004341 -v 0.172728776932 0.703007578850 -0.095244884491 -v 0.204134464264 0.694908976555 -0.070124804974 -v 0.194279670715 0.698028326035 -0.065750300884 -v 0.193339109421 0.770651638508 -0.104809045792 -v 0.212558984756 0.760952532291 -0.071953296661 -v -0.037868022919 0.804407358170 -0.172462224960 -v -0.085999965668 0.798096537590 -0.150223016739 -v -0.079912900925 0.801035761833 -0.145433545113 -v -0.039311408997 0.806997716427 -0.165538191795 -v -0.114581584930 0.791720926762 -0.122836530209 -v -0.107570171356 0.793677270412 -0.103108108044 -v 0.188315153122 0.773532092571 -0.101306200027 -v 0.206870555878 0.763117253780 -0.069325089455 -v 0.211477041245 0.744883477688 -0.024265110493 -v 0.042490959167 0.714094579220 0.143952012062 -v 0.087229490280 0.708064198494 0.141458809376 -v -0.003680706024 0.725511908531 0.134795546532 -v -0.046833276749 0.736211478710 0.117370963097 -v -0.090959787369 0.743731617928 0.091760039330 -v -0.118830442429 0.753062367439 0.045624971390 -v -0.137614011765 0.761805653572 -0.004316985607 -v -0.138007164001 0.771108925343 -0.055927753448 -v 0.164827346802 0.696167469025 0.115181803703 -v 0.129087686539 0.698045313358 0.129442453384 -v 0.202077627182 0.697257161140 0.083701729774 -v 0.223474979401 0.716901838779 0.021489858627 -v 0.219713687897 0.734807431698 -0.024288654327 -v 0.116148948669 0.780359745026 -0.140539228916 -v 0.075758695602 0.788216233253 -0.143896400928 -v 0.158277511597 0.770472466946 -0.130922555923 -v 0.016254663467 0.794478595257 -0.169810354710 -v 0.214664697647 0.750561535358 -0.070789575577 -v 0.193098306656 0.760572731495 -0.107543230057 -v -0.038340330124 0.789423942566 -0.169972777367 -v -0.089158058167 0.786127924919 -0.148080706596 -v -0.117129564285 0.774500608444 -0.117468833923 -v 0.042947053909 0.680678486824 0.141971707344 -v 0.088331699371 0.690217196941 0.148079514503 -v 0.003902912140 0.677657604218 0.129070520401 -v -0.041256189346 0.671179771423 0.103981673717 -v -0.082117557526 0.666609048843 0.067920327187 -v -0.102604150772 0.668240845203 0.030974626541 -v -0.117699861526 0.673860788345 -0.010850131512 -v -0.117666482925 0.687893807888 -0.057794094086 -v 0.130661725998 0.680747628212 0.129106581211 -v 0.167012929916 0.680982887745 0.119741201401 -v 0.203903198242 0.687600016594 0.084002554417 -v 0.223474740982 0.696553647518 0.024260759354 -v 0.218124628067 0.702928543091 -0.021467387676 -v -0.105328559875 0.700765669346 -0.090611577034 -v -0.074398279190 0.714329957962 -0.125499725342 -v -0.027653694153 0.722540020943 -0.144668102264 -v 0.022192239761 0.732428669930 -0.150135040283 -v 0.065891504288 0.733176171780 -0.148831009865 -v 0.109828948975 0.726947844028 -0.140057563782 -v 0.145726919174 0.717888236046 -0.127151072025 -v 0.178150177002 0.702635169029 -0.105906605721 -v 0.208762645721 0.699994683266 -0.072454273701 -v 0.474818944931 0.829751849174 0.080761909485 -v 0.447371721268 0.827144682407 0.082335829735 -v 0.436402082443 0.801355779171 0.076726853848 -v 0.437137126923 0.782028198242 0.062518715858 -v 0.449114084244 0.774479269981 0.043720185757 -v 0.466235399246 0.780543923378 0.026742458344 -v 0.482433199883 0.796503424644 0.020002663136 -v 0.497534036636 0.817176282406 0.030400276184 -v 0.490592956543 0.825681328773 0.062343478203 -v 0.416083812714 0.856479287148 0.063238620758 -v 0.397818565369 0.822540879250 0.058679580688 -v 0.394402980804 0.790257930756 0.037392973900 -v 0.409307241440 0.778394103050 -0.000016272068 -v 0.435056686401 0.793707430363 -0.030144393444 -v 0.461454987526 0.821685552597 -0.037738919258 -v 0.478555798531 0.853732824326 -0.014944911003 -v 0.468921065331 0.879577338696 0.027264356613 -v 0.445375442505 0.880728542805 0.053184807301 -v 0.466699838638 0.886996567249 -0.046786844730 -v 0.444378852844 0.847988784313 -0.076629161835 -v 0.406841993332 0.809575557709 -0.076438903809 -v 0.371905088425 0.787828385830 -0.042897462845 -v 0.357719540596 0.804510772228 0.005992591381 -v 0.362805366516 0.843034982681 0.036714971066 -v 0.391008257866 0.879716992378 0.041662096977 -v 0.425895571709 0.907973527908 0.033029556274 -v 0.459516048431 0.908767938614 0.004759609699 -v 0.474973201752 0.818710982800 0.074997305870 -v 0.461808919907 0.809670209885 0.079118371010 -v 0.456480264664 0.798067808151 0.076258957386 -v 0.455782771111 0.786437451839 0.067734181881 -v 0.461717367172 0.781551599503 0.053859353065 -v 0.471699953079 0.783859133720 0.044202029705 -v 0.482946038246 0.793918967247 0.038748741150 -v 0.489899158478 0.805950462818 0.046118319035 -v 0.486937761307 0.816467463970 0.063097000122 -v 0.441228270531 0.887848794460 -0.051129221916 -v 0.419926643372 0.855345606804 -0.080606341362 -v 0.393717527390 0.828494906425 -0.076067388058 -v 0.370517253876 0.811828851700 -0.047418713570 -v 0.361316323280 0.823268711567 -0.005200862885 -v 0.369323611259 0.850542843342 0.018845379353 -v 0.388053059578 0.882371962070 0.021297752857 -v 0.414115905762 0.906186938286 0.015702068806 -v 0.435689449310 0.907421112061 -0.006201267242 -v 0.457625389099 0.893979549408 -0.053317129612 -v 0.432103991508 0.851549267769 -0.084864497185 -v 0.397927403450 0.816684424877 -0.084416866302 -v 0.365631699562 0.796897709370 -0.048830389977 -v 0.351232051849 0.811093628407 -0.000877141953 -v 0.357836484909 0.846324503422 0.031680703163 -v 0.384871840477 0.884247660637 0.031613469124 -v 0.419532299042 0.913497269154 0.023943066597 -v 0.448849439621 0.918320059776 -0.001152694225 -v 0.468704581261 0.841255605221 0.076112985611 -v 0.455493927002 0.817524373531 0.086187958717 -v 0.447009682655 0.798206448555 0.080420792103 -v 0.444962501526 0.781422913074 0.068031430244 -v 0.455179333687 0.774285674095 0.049756467342 -v 0.471616744995 0.778853714466 0.036065757275 -v 0.486483812332 0.790827751160 0.029048442841 -v 0.496397018433 0.808861613274 0.039405584335 -v 0.487864613533 0.835947692394 0.054146111012 -v 0.153582811356 1.146741271019 -0.023735761642 -v 0.146487712860 1.131359100342 -0.001364409924 -v 0.166741371155 1.124185800552 0.018122673035 -v 0.193145751953 1.149736404419 -0.011541187763 -v 0.155054807663 1.159122467041 -0.049359142780 -v 0.204403400421 1.165102362633 -0.054153501987 -v 0.122463703156 1.154211997986 -0.012223064899 -v 0.122359752655 1.165279030800 -0.031655430794 -v 0.111874103546 1.145521163940 -0.014831602573 -v 0.108873367310 1.130098581314 0.001646161079 -v 0.118844747543 1.140482068062 0.008030056953 -v 0.112039089203 1.157532334328 -0.030208945274 -v 0.117567777634 1.174703359604 -0.051419258118 -v 0.107257843018 1.165954709053 -0.045900940895 -v 0.104554653168 1.179394125938 -0.069682717323 -v 0.096223115921 1.169898509979 -0.061130762100 -v 0.078921318054 1.169709205627 -0.074586033821 -v 0.084147691727 1.179101228714 -0.084845960140 -v 0.060791492462 1.176911592484 -0.095880866051 -v 0.057977199554 1.167713642120 -0.084590315819 -v 0.036164999008 1.174309372902 -0.102829873562 -v 0.034911155701 1.165031433105 -0.090920388699 -v 0.010727643967 1.171227931976 -0.105658352375 -v 0.011106491089 1.162466049194 -0.093655586243 -v 0.043484210968 1.148231267929 -0.125569045544 -v 0.015298843384 1.144926548004 -0.130406677723 -v 0.071163892746 1.151486396790 -0.119160473347 -v 0.099195003510 1.154577970505 -0.109847664833 -v 0.129453897476 1.156361937523 -0.098611533642 -v 0.148039340973 1.161061882973 -0.075409770012 -v 0.194738388062 1.157809615135 -0.093097984791 -v 0.166496038437 1.133596062660 -0.120083212852 -v 0.241148471832 1.147128343582 -0.110760331154 -v 0.205090999603 1.108767747879 -0.138120114803 -v 0.296813964844 1.119970321655 -0.113083600998 -v 0.248097181320 1.079767704010 -0.139568984509 -v 0.314052343369 1.139110684395 -0.062264442444 -v 0.255768775940 1.160152196884 -0.056023120880 -v 0.125734090805 1.143847703934 -0.100883603096 -v 0.157966852188 1.121018052101 -0.115687131882 -v 0.195927619934 1.096690416336 -0.130942702293 -v 0.102578163147 1.110636472702 0.020105242729 -v 0.110338211060 1.120410561562 0.029318034649 -v 0.135500192642 1.112133264542 0.027387619019 -v 0.121419668198 1.085264921188 0.053761780262 -v 0.096231937408 1.096061944962 0.048072874546 -v 0.121106386185 1.072343826294 0.043408513069 -v 0.135016918182 1.098165869713 0.015953302383 -v 0.146015644073 1.118869185448 -0.003721117973 -v 0.161901235580 1.110084056854 0.008137762547 -v 0.196237564087 1.113056898117 0.041670143604 -v 0.231638908386 1.147067785263 0.005591809750 -v 0.187341213226 1.099266767502 0.029134333134 -v 0.101557731628 1.063514590263 0.082820892334 -v 0.102081298828 1.052370190620 0.074180006981 -v 0.079520702362 1.077967882156 0.068052530289 -v 0.091128826141 1.087718725204 0.037324488163 -v 0.076925516129 1.069971561432 0.055388748646 -v 0.073636531830 1.045414447784 0.104310035706 -v 0.060042619705 1.063298940659 0.085158526897 -v 0.060029506683 1.056650996208 0.070179820061 -v 0.076045036316 1.035140991211 0.095563471317 -v 0.043664932251 1.024097084999 0.109484314919 -v 0.049406528473 1.016946673393 0.102544367313 -v -0.092731475830 1.104547619820 -0.051223099232 -v -0.113844156265 1.093252182007 -0.044122219086 -v -0.106844902039 1.081219434738 -0.051757276058 -v -0.089383363724 1.092386722565 -0.054474711418 -v -0.142742395401 1.079518079758 -0.034633517265 -v -0.133426666260 1.067001342773 -0.045482337475 -v -0.184802770615 1.058834671974 -0.039483308792 -v -0.173303604126 1.048474073410 -0.050417959690 -v -0.212892293930 1.028311491013 -0.072805166245 -v -0.225590705872 1.036243677139 -0.063136100769 -v -0.252138376236 1.016947031021 -0.094444274902 -v -0.238336086273 1.010701894760 -0.105198681355 -v -0.261181116104 1.009418725967 -0.139634251595 -v -0.249701499939 1.001395821571 -0.147045373917 -v -0.236275196075 1.050160169601 -0.116216957569 -v -0.220269918442 1.051454544067 -0.180383503437 -v -0.255511283875 1.006905913353 -0.191586971283 -v -0.200874567032 1.088705539703 -0.091722786427 -v -0.183070182800 1.090037822723 -0.163334965706 -v -0.194282293320 1.042732954025 -0.226393222809 -v -0.229079723358 1.004474639893 -0.227474808693 -v -0.159255266190 1.014430284500 -0.241221547127 -v -0.196877479553 1.004197716713 -0.243847310543 -v -0.161328792572 1.084260106087 -0.219420254230 -v -0.119579792023 1.036281943321 -0.230625808239 -v -0.244533061981 0.997296631336 -0.191611886024 -v -0.223453521729 0.995631098747 -0.221788883209 -v -0.153653621674 1.110693693161 -0.078140616417 -v -0.146693229675 1.116624593735 -0.140892207623 -v -0.119409322739 1.117959380150 -0.075315594673 -v -0.110646963120 1.127498865128 -0.118036568165 -v -0.091603517532 1.119367361069 -0.072633266449 -v -0.084799051285 1.131223559380 -0.097159922123 -v -0.115998268127 1.108692765236 -0.190854609013 -v -0.089858293533 1.122802376747 -0.153536438942 -v -0.082515239716 1.073935151100 -0.031460642815 -v -0.089494943619 1.087044239044 -0.020607233047 -v -0.073734283447 1.050684690475 0.000546932220 -v -0.080284357071 1.062893509865 0.010187029839 -v -0.068449974060 1.044618606567 0.047623455524 -v -0.062891244888 1.033905506134 0.039388358593 -v -0.047109127045 1.031812429428 0.080443978310 -v -0.031396150589 1.052964568138 0.067215263844 -v -0.045845985413 1.064046025276 0.042960286140 -v -0.017226934433 1.017256498337 0.097646474838 -v -0.012994289398 1.040772914886 0.082050144672 -v -0.024281263351 1.047124743462 0.053621292114 -v -0.036925554276 1.057082414627 0.032743573189 -v -0.047004699707 1.072139143944 0.009349822998 -v -0.057619094849 1.078983664513 0.016488373280 -v -0.069085836411 1.100236415863 -0.007317364216 -v -0.056204557419 1.092651844025 -0.012012958527 -v -0.059460639954 1.110859036446 -0.031832396984 -v -0.073314666748 1.118509888649 -0.030457615852 -v -0.059396266937 1.125840187073 -0.048513889313 -v -0.072108268738 1.131877303123 -0.050584912300 -v -0.009020328522 1.040055990219 0.067265510559 -v -0.008279085159 1.048065781593 0.086258769035 -v -0.001708984375 1.044293761253 0.063691854477 -v -0.011102437973 1.013419628143 0.107842206955 -v 0.012402534485 1.014568805695 0.111340701580 -v -0.007885932922 1.000435948372 0.096706688404 -v 0.016772985458 0.998014330864 0.098615229130 -v -0.018301010132 1.009325742722 0.089410901070 -v 0.012949943542 1.049798607826 0.088101744652 -v 0.018573284149 1.045927882195 0.061640202999 -v 0.036473512650 1.048622608185 0.071156620979 -v 0.042591094971 1.045850872993 0.077319562435 -v 0.032891273499 1.053035736084 0.094713449478 -v -0.043589353561 1.021625638008 0.071766734123 -v -0.062194108963 1.102410316467 -0.172938823700 -v -0.045767784119 1.134480834007 -0.135547220707 -v -0.039524316788 1.122236609459 -0.136410057545 -v -0.056471109390 1.089962005615 -0.166750788689 -v -0.069718599319 1.135420084000 -0.119947195053 -v -0.057276010513 1.154541730881 -0.085973024368 -v -0.039468765259 1.162768602371 -0.098182201385 -v -0.047900676727 1.148107647896 -0.076298177242 -v -0.032938718796 1.155064463615 -0.086415827274 -v -0.067025423050 1.143415451050 -0.068977236748 -v -0.056419372559 1.138137459755 -0.063298463821 -v -0.015136957169 1.167805433273 -0.104464530945 -v -0.012070894241 1.159346342087 -0.092343151569 -v -0.014311790466 1.140978336334 -0.133057236671 -v -0.011669158936 1.129227042198 -0.125870227814 -v 0.016017198563 1.133123755455 -0.120839774609 -v 0.042919397354 1.136187195778 -0.116020321846 -v 0.069320917130 1.139438748360 -0.110212624073 -v 0.096272230148 1.142657041550 -0.103571355343 -v -0.084033012390 1.068661570549 -0.209112644196 -v -0.079619884491 1.055715084076 -0.200545787811 -v -0.114229202271 1.024448990822 -0.220436096191 -v -0.152589321136 1.005478620529 -0.229532003403 -v -0.190863609314 0.997435450554 -0.232511520386 -v 0.283624172211 1.127811551094 0.019655466080 -v 0.238133430481 1.093801021576 0.054984629154 -v 0.281615972519 1.070061683655 0.051802158356 -v 0.324586987495 1.083217859268 0.015623211861 -v 0.317109346390 1.049089670181 0.037077486515 -v 0.344853520393 1.035368323326 0.004752695560 -v 0.272841930389 1.062416911125 0.039141774178 -v 0.309236288071 1.042762875557 0.023036181927 -v 0.228971004486 1.083329319954 0.041944861412 -v 0.336932301521 1.026821017265 -0.005697131157 -v 0.352009296417 1.016058206558 -0.045218408108 -v 0.363454222679 1.025239586830 -0.041483044624 -v 0.350228548050 1.082829117775 -0.050576865673 -v 0.331254720688 1.069567441940 -0.102947354317 -v 0.354001879692 1.020647644997 -0.085915803909 -v 0.344488024712 1.012196183205 -0.082506895065 -v 0.291500329971 1.049303770065 -0.131860733032 -v 0.316508769989 1.020089149475 -0.108288466930 -v 0.278244972229 1.045682430267 -0.121770381927 -v 0.329316139221 1.025645136833 -0.117285430431 -v 0.237555980682 1.070979237556 -0.131267666817 -v 0.035062551498 1.018665790558 0.116485953331 -v 0.040465593338 1.046646237373 0.092548847198 -v 0.039201974869 1.005905747414 0.105759739876 -v 0.407534599304 1.049324989319 -0.053019642830 -v 0.407415151596 1.048302650452 -0.055281043053 -v 0.409241080284 1.045540690422 -0.054215550423 -v 0.409348964691 1.045631766319 -0.052197813988 -v 0.407567024231 1.045038938522 -0.053497850895 -v 0.408619165421 1.045577406883 -0.051431357861 -v 0.405469179153 1.048570752144 -0.051153659821 -v 0.405564785004 1.047778606415 -0.056019663811 -v 0.403634786606 1.047237396240 -0.053114891052 -v 0.403636693954 1.047934293747 -0.055059254169 -v 0.400758862495 1.061518907547 -0.057837843895 -v 0.404543042183 1.054217815399 -0.054585695267 -v 0.403454065323 1.053356051445 -0.050477862358 -v 0.400370597839 1.052134513855 -0.054630398750 -v 0.400712847710 1.052084445953 -0.049256503582 -v 0.390304088593 1.109333515167 -0.057016730309 -v 0.388536572456 1.106098771095 -0.056595444679 -v 0.390356302261 1.105766057968 -0.046931087971 -v 0.392881512642 1.108199954033 -0.046167612076 -v 0.386311173439 1.096173763275 -0.029934227467 -v 0.384410738945 1.113091945648 -0.026496827602 -v 0.389004111290 1.130117177963 -0.037221312523 -v 0.392682909966 1.108635425568 -0.037295579910 -v 0.393145322800 1.127447843552 -0.052910566330 -v 0.390158653259 1.094229102135 -0.034627795219 -v 0.365346193314 1.095366001129 -0.075250387192 -v 0.361508131027 1.084615111351 -0.066927909851 -v 0.372699022293 1.087730288506 -0.066918432713 -v 0.371014833450 1.094595193863 -0.072323203087 -v 0.361182332039 1.096700906754 -0.029368877411 -v 0.354959249496 1.107748985291 -0.019379496574 -v 0.363673329353 1.110366463661 -0.021963655949 -v 0.367691278458 1.100643992424 -0.026672244072 -v 0.374418973923 1.110103130341 -0.023161590099 -v 0.377149462700 1.091655015945 -0.026055395603 -v 0.373545646667 1.081293344498 -0.038487195969 -v 0.338927745819 1.093048810959 -0.023161709309 -v 0.335716485977 1.096756339073 -0.022189855576 -v 0.333831310272 1.101293921471 -0.015252113342 -v 0.339010357857 1.099372625351 -0.015726268291 -v 0.336115360260 1.103556871414 -0.011844396591 -v 0.344871759415 1.091088294983 -0.023372709751 -v 0.330793619156 1.106926560402 -0.018525958061 -v 0.326990127563 1.115554690361 -0.016181170940 -v 0.328750967979 1.092396497726 -0.021561920643 -v 0.325265884399 1.098267674446 -0.019644141197 -v 0.346914052963 1.103241682053 -0.017480194569 -v 0.338825702667 1.108204364777 -0.011111140251 -v 0.344290256500 1.120107769966 -0.013092637062 -v 0.340465307236 1.136773347855 -0.015785038471 -v 0.324753522873 1.125427603722 -0.015070736408 -v 0.325292944908 1.136361837387 -0.017429172993 -v 0.329348087311 1.116966009140 -0.013588488102 -v 0.332792520523 1.118334770203 -0.096988618374 -v 0.332243442535 1.122267842293 -0.094619393349 -v 0.323136806488 1.125333309174 -0.083494544029 -v 0.327710032463 1.113504409790 -0.092576861382 -v 0.341573119164 1.120945453644 -0.094311773777 -v 0.335590600967 1.131715416908 -0.092355489731 -v 0.328661322594 1.133670330048 -0.089798271656 -v 0.324473619461 1.135583043098 -0.085328757763 -v 0.353020310402 1.126932740211 -0.091999888420 -v 0.346932053566 1.140344977379 -0.090539395809 -v 0.324019074440 1.120222568512 -0.017995357513 -v 0.289908170700 1.127960801125 -0.085108101368 -v 0.304053783417 1.121056914330 -0.078729987144 -v 0.358429908752 1.193968534470 -0.088134527206 -v 0.357683658600 1.184876799583 -0.100257873535 -v 0.363889813423 1.171106338501 -0.087482929230 -v 0.366210937500 1.176288127899 -0.080222189426 -v 0.368631839752 1.159053325653 -0.078640401363 -v 0.373743414879 1.167661428452 -0.066681802273 -v 0.375433444977 1.182421684265 -0.018816709518 -v 0.371500611305 1.164965748787 -0.026864171028 -v 0.360645771027 1.163048863411 -0.020475804806 -v 0.365925073624 1.182272315025 -0.013802051544 -v 0.355728268623 1.168922543526 -0.016866326332 -v 0.365192413330 1.144321084023 -0.023384571075 -v 0.351355433464 1.141466021538 -0.019072234631 -v 0.347202420235 1.153388857841 -0.018843293190 -v 0.341611385345 1.160166978836 -0.015560805798 -v 0.308113574982 1.139430522919 -0.086172342300 -v 0.313164234161 1.145732045174 -0.091821610928 -v 0.344058752060 1.152563452721 -0.093004882336 -v 0.359626531601 1.152780056000 -0.086724877357 -v 0.353022336960 1.166682362556 -0.092923939228 -v 0.347189664841 1.169834375381 -0.094244897366 -v 0.342811346054 1.158735275269 -0.094510555267 -v 0.353778600693 1.178154706955 -0.104299247265 -v 0.348872900009 1.177428722382 -0.102648377419 -v 0.331777811050 1.146316647530 -0.093712210655 -v 0.320755481720 1.145852565765 -0.098560571671 -v 0.323286175728 1.148737668991 -0.101337194443 -v 0.333321571350 1.152906417847 -0.097986042500 -v 0.326210260391 1.151933670044 -0.103993952274 -v 0.320780992508 1.131242513657 -0.019613742828 -v 0.316488265991 1.137263059616 -0.026703536510 -v 0.320133447647 1.137962102890 -0.020618379116 -v 0.337424993515 1.147775053978 -0.018649101257 -v 0.334059238434 1.153875350952 -0.016800880432 -v 0.332339167595 1.160215377808 -0.011005222797 -v 0.333034753799 1.162801146507 -0.010488092899 -v 0.342080116272 1.164801001549 -0.014642059803 -v 0.329650044441 1.156030654907 -0.012940168381 -v 0.320695400238 1.147234559059 -0.025550961494 -v 0.324349880219 1.148427605629 -0.021465837955 -v 0.324996113777 1.144489049911 -0.022029399872 -v 0.319767236710 1.142206072807 -0.025610327721 -v 0.316439867020 1.145988821983 -0.028391957283 -v 0.314030408859 1.140980482101 -0.030016005039 -v 0.306605100632 1.136893630028 -0.031398415565 -v 0.311094760895 1.138293743134 -0.030661761761 -v 0.314454317093 1.133188128471 -0.029211819172 -v 0.307747125626 1.131512522697 -0.031591475010 -v 0.291517019272 1.138318657875 -0.033916234970 -v 0.304842948914 1.122800350189 -0.030405402184 -v 0.289185523987 1.130287408829 -0.033323228359 -v 0.286009788513 1.137142181396 -0.090150713921 -v 0.292701721191 1.141978979111 -0.107457876205 -v 0.304615020752 1.142538189888 -0.102706909180 -v 0.309559822083 1.150496006012 -0.024630010128 -v 0.318125486374 1.150960326195 -0.022390007973 -v 0.317887067795 1.153405547142 -0.009570956230 -v 0.321745395660 1.151527643204 -0.017602443695 -v 0.312289476395 1.154029130936 -0.016137778759 -v 0.300724506378 1.151372194290 -0.025900006294 -v 0.302543878555 1.155046701431 -0.016855716705 -v 0.311131477356 1.148434042931 -0.121525228024 -v 0.314778566360 1.145795822144 -0.111356735229 -v 0.318232536316 1.148830175400 -0.113018929958 -v 0.316641569138 1.155373811722 -0.125974237919 -v 0.310946226120 1.160884141922 -0.130396544933 -v 0.305948495865 1.152399063110 -0.128264009953 -v 0.322793602943 1.153211474419 -0.114452242851 -v 0.319596290588 1.160681724548 -0.123025000095 -v 0.319034099579 1.171830296516 0.017393767834 -v 0.317905664444 1.160627365112 0.008475244045 -v 0.311162710190 1.163662672043 0.014921247959 -v 0.310447931290 1.172396779060 0.019649803638 -v 0.309610843658 1.159015893936 0.012034296989 -v 0.310906410217 1.144272089005 -0.107071161270 -v 0.306469917297 1.144841670990 -0.117874324322 -v 0.302479743958 1.143570303917 -0.114495694637 -v 0.301431417465 1.147624731064 -0.126265466213 -v 0.295472621918 1.145630240440 -0.120796620846 -v 0.288472175598 1.148880720139 -0.025115370750 -v 0.301652908325 1.141206622124 -0.031471252441 -v 0.309620141983 1.142498731613 -0.029031515121 -v 0.273790359497 1.148244857788 -0.025866985321 -v 0.272537946701 1.142426609993 -0.030830979347 -v 0.272406339645 1.134789586067 -0.032956182957 -v 0.291519165039 1.153991341591 -0.016412615776 -v 0.305040836334 1.167021632195 0.019629895687 -v 0.307030200958 1.163709878922 0.017679572105 -v 0.305133104324 1.161130547523 0.017725169659 -v 0.303712606430 1.163359761238 0.020457804203 -v 0.294210910797 1.150454163551 -0.129565417767 -v 0.297544717789 1.151566028595 -0.131443619728 -v 0.299007177353 1.157061815262 -0.131160855293 -v 0.289251804352 1.162134289742 -0.127951741219 -v 0.300848484039 1.162901401520 0.020725965500 -v 0.299931526184 1.168733119965 0.019787251949 -v 0.302267789841 1.160912990570 0.017476558685 -v 0.284586906433 1.155997037888 -0.118712186813 -v 0.320478677750 1.183388590813 0.019893288612 -v 0.315504550934 1.185158967972 0.021765649319 -v 0.304894447327 1.174435973167 0.020509123802 -v 0.311547279358 1.187007069588 0.021684288979 -v 0.294510126114 1.164358973503 0.015730142593 -v 0.295584678650 1.166682958603 0.018493294716 -v 0.298225879669 1.162472367287 0.019704580307 -v 0.296677112579 1.161968946457 0.018077135086 -v 0.299949407578 1.160799622536 0.016491711140 -v 0.297479152679 1.160787940025 0.014298200607 -v 0.295337200165 1.162495613098 0.013063669205 -v 0.297493457794 1.159226298332 0.006240844727 -v 0.292984724045 1.162090659142 0.007228136063 -v 0.289747714996 1.165970087051 0.009980738163 -v 0.293587207794 1.173587322235 0.017361879349 -v 0.295882701874 1.184546113014 0.019877433777 -v 0.289324522018 1.170376300812 0.013289868832 -v 0.304202318192 1.163235664368 -0.131868004799 -v 0.295037984848 1.173500776291 -0.132903218269 -v 0.339935421944 1.204928994179 0.011042654514 -v 0.323164343834 1.198740124702 0.019174516201 -v 0.319356679916 1.202640295029 0.017888188362 -v 0.333619713783 1.216896772385 0.006251335144 -v 0.316392660141 1.223941683769 0.004564166069 -v 0.318291187286 1.236307144165 -0.009308457375 -v 0.339412450790 1.232521295547 -0.013116896152 -v 0.309664726257 1.210659503937 0.013969600201 -v 0.320227146149 1.235717296600 -0.089737355709 -v 0.315104484558 1.228830337524 -0.112790822983 -v 0.326388478279 1.222050905228 -0.113814830780 -v 0.333210706711 1.227595806122 -0.095670104027 -v 0.337775707245 1.211602926254 -0.112435698509 -v 0.344557762146 1.216145873070 -0.082126915455 -v 0.326203584671 1.226114869118 -0.064788460732 -v 0.278375148773 1.164562225342 0.002692937851 -v 0.286962032318 1.159514427185 -0.002162218094 -v 0.278234004974 1.155510902405 -0.013907790184 -v 0.260844707489 1.160049319267 -0.009037494659 -v 0.253694772720 1.171441078186 0.002056777477 -v 0.274199008942 1.172616839409 0.009002089500 -v 0.241376399994 1.164381980896 -0.022117018700 -v 0.236744165421 1.171596884727 -0.017185091972 -v 0.257408142090 1.154074668884 -0.020835101604 -v 0.240831613541 1.161932706833 -0.027496337891 -v 0.272498369217 1.184606671333 0.015063345432 -v 0.283818006516 1.195466637611 0.018259227276 -v 0.251496076584 1.179788351059 0.004774987698 -v 0.280345439911 1.187177538872 -0.130770325661 -v 0.278849363327 1.200135588646 -0.128845155239 -v 0.264022827148 1.197203159332 -0.124487996101 -v 0.263042688370 1.188585639000 -0.125758051872 -v 0.247735500336 1.194719552994 -0.112018883228 -v 0.248827695847 1.181841850281 -0.113283038139 -v 0.269680976868 1.173762202263 -0.124203026295 -v 0.254821300507 1.213196992874 -0.005989432335 -v 0.259692907333 1.217268109322 -0.002873539925 -v 0.264866352081 1.212918281555 0.006526708603 -v 0.262398242950 1.203422427177 0.007279813290 -v 0.274141788483 1.213083267212 0.013194501400 -v 0.276415348053 1.206676006317 0.013642489910 -v 0.247564315796 1.194469571114 -0.000649333000 -v 0.245563030243 1.205689191818 -0.011326313019 -v 0.232998371124 1.204849720001 -0.033008277416 -v 0.242313385010 1.215915679932 -0.027005612850 -v 0.237220525742 1.198678970337 -0.018567323685 -v 0.235009908676 1.188932180405 -0.016125142574 -v 0.229682207108 1.194204092026 -0.034655272961 -v 0.280081987381 1.256208896637 -0.019527673721 -v 0.266340732574 1.257276535034 -0.021893620491 -v 0.272911071777 1.248642563820 -0.034798681736 -v 0.289152145386 1.246002078056 -0.035115897655 -v 0.308747768402 1.234785199165 -0.048455655575 -v 0.315008163452 1.240252733231 -0.028551578522 -v 0.295452594757 1.246342897415 -0.017771065235 -v 0.291768074036 1.252464294434 -0.011624932289 -v 0.272852182388 1.246320486069 0.026719093323 -v 0.274995565414 1.244897484779 0.026039719582 -v 0.270889520645 1.239411234856 0.026342213154 -v 0.269581317902 1.240408897400 0.026497364044 -v 0.264169454575 1.234132766724 0.025929450989 -v 0.263763427734 1.235451221466 0.026660978794 -v 0.263376712799 1.240142583847 0.021522641182 -v 0.268235921860 1.245139122009 0.023626983166 -v 0.227350234985 1.201413989067 -0.060404598713 -v 0.226505756378 1.187961101532 -0.062663376331 -v 0.232470035553 1.193228960037 -0.089262902737 -v 0.238893508911 1.210202097893 -0.088255286217 -v 0.253223896027 1.206307768822 -0.110778868198 -v 0.239593505859 1.224539875984 -0.073748230934 -v 0.232012033463 1.216619491577 -0.053089022636 -v 0.252145767212 1.219983339310 -0.097832560539 -v 0.250634193420 1.229226589203 -0.085364758968 -v 0.252376794815 1.238263368607 -0.057780742645 -v 0.267105579376 1.240937113762 -0.056898772717 -v 0.258289337158 1.241248607635 -0.051965177059 -v 0.252767086029 1.235920786858 -0.034247636795 -v 0.247609376907 1.233851552010 -0.039491355419 -v 0.265551090240 1.267001390457 0.009194791317 -v 0.272844314575 1.261870384216 0.012323737144 -v 0.270809888840 1.260163426399 0.015809416771 -v 0.262974262238 1.263656973839 0.012956202030 -v 0.268976211548 1.265585422516 0.000393331051 -v 0.258705377579 1.266561031342 -0.002085030079 -v 0.261866092682 1.261532545090 -0.010348796844 -v 0.274395465851 1.261371612549 -0.009189963341 -v 0.238660573959 1.248261332512 0.003617167473 -v 0.232067346573 1.245571255684 0.001219451427 -v 0.233589172363 1.253527522087 -0.000213980675 -v 0.238280773163 1.252982854843 0.002291560173 -v 0.241975069046 1.261794805527 0.000397861004 -v 0.244624614716 1.256234288216 0.001851916313 -v 0.222787380219 1.257822632790 -0.151930749416 -v 0.228422880173 1.254693269730 -0.147209823132 -v 0.230664730072 1.257706403732 -0.153383851051 -v 0.225557327271 1.260083436966 -0.156076908112 -v 0.224181652069 1.269489765167 -0.164974153042 -v 0.218438386917 1.260652661324 -0.156715095043 -v 0.235471725464 1.260826349258 -0.157907843590 -v 0.216721296310 1.261644721031 -0.151875853539 -v 0.215643405914 1.258587121964 -0.150196969509 -v 0.234998703003 1.261462807655 -0.124403178692 -v 0.224088907242 1.267516016960 -0.134056270123 -v 0.228742599487 1.274905562401 -0.138475537300 -v 0.243557214737 1.273823022842 -0.127884268761 -v 0.218826293945 1.271217346191 -0.139695227146 -v 0.223790407181 1.282513380051 -0.156298041344 -v 0.229401111603 1.281741142273 -0.159395992756 -v 0.243339538574 1.285583496094 -0.155722141266 -v 0.240149497986 1.285640001297 -0.147173225880 -v 0.263746500015 1.284044027328 -0.144365310669 -v 0.256647109985 1.283450603485 -0.135616004467 -v 0.249143123627 1.278396368027 -0.130899667740 -v 0.231034517288 1.281445980072 -0.142535567284 -v 0.228749275208 1.279866695404 -0.162645876408 -v 0.225111246109 1.280306816101 -0.161672592163 -v 0.326325416565 1.095832467079 -0.026897907257 -v 0.328660488129 1.092162013054 -0.027155876160 -v 0.334224581718 1.083390593529 -0.031802475452 -v 0.331976652145 1.086985468864 -0.036189317703 -v 0.244880199432 1.142374873161 -0.073979854584 -v 0.242966175079 1.142764568329 -0.078356206417 -v 0.235785722733 1.146784543991 -0.078433096409 -v 0.238635778427 1.145627975464 -0.074249148369 -v 0.232438325882 1.149214863777 -0.073069214821 -v 0.236898422241 1.147114753723 -0.069623470306 -v 0.255175828934 1.136546134949 -0.077648699284 -v 0.255682229996 1.136946439743 -0.070239722729 -v 0.269840002060 1.141850829124 -0.088529407978 -v 0.257449388504 1.150468826294 -0.085283041000 -v 0.282135963440 1.148957133293 -0.107223212719 -v 0.262875080109 1.157893180847 -0.106579840183 -v 0.264955282211 1.164611697197 -0.115844190121 -v 0.244687318802 1.169971346855 -0.105285048485 -v 0.246577739716 1.164339303970 -0.095911860466 -v 0.234338521957 1.172934412956 -0.084621906281 -v 0.237678050995 1.167568325996 -0.080495774746 -v 0.230271100998 1.181651115417 -0.088845074177 -v 0.227655649185 1.178839325905 -0.062708079815 -v 0.231756448746 1.172751188278 -0.062062919140 -v 0.229456424713 1.177902221680 -0.036529541016 -v 0.232846736908 1.170946717262 -0.038640320301 -v 0.227507114410 1.182419776917 -0.036165595055 -v 0.234830379486 1.176739931107 -0.015439331532 -v 0.235546827316 1.166122555733 -0.040820002556 -v 0.235387325287 1.167956709862 -0.061342179775 -v 0.236512184143 1.160708308220 -0.043142557144 -v 0.237915754318 1.161495804787 -0.059940874577 -v 0.241000175476 1.156659126282 -0.029682040215 -v 0.256223201752 1.147885084152 -0.025309741497 -v 0.252270221710 1.141531467438 -0.026705861092 -v 0.236812353134 1.148920893669 -0.030205547810 -v 0.290362834930 1.128957509995 -0.035883367062 -v 0.271513700485 1.134885430336 -0.035297334194 -v 0.306781768799 1.119673848152 -0.033734023571 -v 0.317042827606 1.112375974655 -0.022598922253 -v 0.317406177521 1.108932733536 -0.028873980045 -v 0.332089543343 1.094723105431 -0.085125267506 -v 0.322933316231 1.108649253845 -0.085476875305 -v 0.319103002548 1.109926819801 -0.080069780350 -v 0.329759955406 1.096952438354 -0.079336047173 -v 0.334635496140 1.087565541267 -0.070015192032 -v 0.337785124779 1.084333658218 -0.074962139130 -v 0.336755514145 1.081413388252 -0.053044438362 -v 0.338276147842 1.079147696495 -0.053146123886 -v 0.346428036690 1.085549473763 -0.069611251354 -v 0.343625307083 1.093718051910 -0.081809461117 -v 0.333607673645 1.104474425316 -0.090680718422 -v 0.343541741371 1.081957101822 -0.052684903145 -v 0.353684067726 1.082917213440 -0.067507863045 -v 0.358879923820 1.093483090401 -0.077935218811 -v 0.351037502289 1.092784404755 -0.080610275269 -v 0.360334396362 1.102306008339 -0.085941970348 -v 0.347621440887 1.101400613785 -0.092805027962 -v 0.345952153206 1.079882979393 -0.052633166313 -v 0.355161905289 1.077038049698 -0.051688134670 -v 0.343386173248 1.084547519684 -0.034452319145 -v 0.352032899857 1.082792043686 -0.035345792770 -v 0.340294599533 1.086036086082 -0.034663975239 -v 0.321768999100 1.104483842850 -0.020316779613 -v 0.326095461845 1.115695357323 -0.020195245743 -v 0.319353103638 1.123223304749 -0.025029301643 -v 0.322834372520 1.101128458977 -0.027329206467 -v 0.321851253510 1.127054452896 -0.022767901421 -v 0.353766679764 1.095177173615 -0.026385903358 -v 0.359876632690 1.086948037148 -0.037192046642 -v 0.368791699409 1.081473231316 -0.054299533367 -v 0.366416454315 1.085834145546 -0.039678335190 -v 0.375720381737 1.077826261520 -0.054867923260 -v 0.385641813278 1.069572925568 -0.047519683838 -v 0.386780261993 1.068247556686 -0.054583191872 -v 0.379089593887 1.078935027122 -0.064835965633 -v 0.387892365456 1.068310856819 -0.060149490833 -v 0.394519090652 1.059546113014 -0.055611908436 -v 0.389144182205 1.068464994431 -0.063209295273 -v 0.381745100021 1.079965829849 -0.068755567074 -v 0.395897269249 1.059724450111 -0.058292984962 -v 0.397762775421 1.058734893799 -0.060246050358 -v 0.390513181686 1.068549633026 -0.065918266773 -v 0.401293635368 1.052220582962 -0.057137370110 -v 0.402930855751 1.052381992340 -0.058841645718 -v 0.399328708649 1.059069991112 -0.062133789063 -v 0.404549121857 1.052707433701 -0.057922661304 -v 0.400724768639 1.060495495796 -0.061055362225 -v 0.394371271133 1.071512341499 -0.065981507301 -v 0.392708420753 1.069672346115 -0.067366063595 -v 0.394284963608 1.071869850159 -0.062373280525 -v 0.388498425484 1.083336234093 -0.066320896149 -v 0.388929486275 1.082942962646 -0.069176137447 -v 0.389878511429 1.092170119286 -0.038135766983 -v 0.392562985420 1.073132753372 -0.038371622562 -v 0.393902897835 1.072458386421 -0.036485314369 -v 0.400479316711 1.060284376144 -0.040919661522 -v 0.400619268417 1.059895157814 -0.042878329754 -v 0.392677068710 1.071635484695 -0.034626603127 -v 0.399963617325 1.058247804642 -0.039560496807 -v 0.389219284058 1.072089076042 -0.033550858498 -v 0.398481249809 1.057546377182 -0.040394842625 -v 0.385063409805 1.070487856865 -0.035343050957 -v 0.395586490631 1.058170080185 -0.044803380966 -v 0.402001142502 1.052767753601 -0.042411684990 -v 0.388577699661 1.095486879349 -0.066482841969 -v 0.387288451195 1.094378232956 -0.064481914043 -v 0.389545917511 1.108287096024 -0.069271624088 -v 0.387219429016 1.094375610352 -0.071040332317 -v 0.390260934830 1.124660015106 -0.067944049835 -v 0.383810281754 1.146947145462 -0.036770582199 -v 0.387935638428 1.145303487778 -0.049735426903 -v 0.385385751724 1.144845247269 -0.066654205322 -v 0.379234194756 1.167300224304 -0.047699809074 -v 0.378260374069 1.142871618271 -0.078380703926 -v 0.384638786316 1.121478676796 -0.079748928547 -v 0.371328830719 1.114236831665 -0.083621263504 -v 0.366134643555 1.134753823280 -0.086642682552 -v 0.358268737793 1.111678957939 -0.091841936111 -v 0.384584784508 1.105457901955 -0.077077627182 -v 0.377453684807 1.103823542595 -0.078171491623 -v 0.383101344109 1.092535972595 -0.074570477009 -v 0.376216292381 1.093980312347 -0.073397576809 -v 0.384114503860 1.080561161041 -0.071538448334 -v 0.387168884277 1.081826567650 -0.071408987045 -v 0.378217101097 1.166335225105 -0.036741614342 -v 0.376491785049 1.185984611511 -0.027371287346 -v 0.375539779663 1.191256642342 -0.040807008743 -v 0.376024484634 1.146698236465 -0.028571903706 -v 0.380968809128 1.128817915916 -0.027356445789 -v 0.372819066048 1.124244213104 -0.021395444870 -v 0.357726931572 1.123675107956 -0.019232869148 -v 0.363764047623 1.199695229530 -0.003253161907 -v 0.359092354774 1.192318797112 -0.001357376575 -v 0.363418817520 1.207986116409 -0.009030759335 -v 0.363287687302 1.216881036758 -0.024423658848 -v 0.353446960449 1.214913725853 -0.051911473274 -v 0.367811679840 1.192584276199 -0.062469363213 -v 0.335019469261 1.232254981995 -0.039931237698 -v 0.341472268105 1.196155428886 0.010244071484 -v 0.354283452034 1.192304849625 -0.001765370369 -v 0.339673757553 1.196221947670 0.007006824017 -v 0.363298535347 1.182292938232 -0.012944102287 -v 0.354795575142 1.171777725220 -0.016488790512 -v 0.327435612679 1.161281824112 -0.002656698227 -v 0.324092507362 1.165798902512 0.006462395191 -v 0.322525382042 1.168064355850 0.004236161709 -v 0.326949238777 1.164337635040 -0.003446638584 -v 0.325284123421 1.158543467522 -0.003361463547 -v 0.322180032730 1.162310838699 0.007995128632 -v 0.320963859558 1.172976732254 0.015366852283 -v 0.319886207581 1.174322366714 0.011200785637 -v 0.321480035782 1.183079004288 0.017309784889 -v 0.326878428459 1.193821310997 0.018233954906 -v 0.327511191368 1.192236304283 0.015911042690 -v 0.303445339203 1.120934963226 -0.074148416519 -v 0.251810550690 1.141942739487 -0.031309187412 -v 0.241466999054 1.146666526794 -0.036401212215 -v 0.236400604248 1.148872971535 -0.047140300274 -v 0.230206489563 1.152073264122 -0.044595956802 -v 0.229574203491 1.151367187500 -0.061807334423 -v 0.239748239517 1.160202145576 -0.073878407478 -v 0.247816801071 1.157876133919 -0.081561207771 -v 0.234130144119 1.149081230164 -0.061738610268 -v 0.224230289459 1.281635522842 -0.153767704964 -v 0.223762512207 1.278146028519 -0.159069538116 -v 0.219611406326 1.279417753220 -0.152326762676 -v 0.213749408722 1.273561835289 -0.144396305084 -v 0.217382907867 1.273008942604 -0.147697806358 -v 0.221839427948 1.275884628296 -0.154915273190 -v 0.210401773453 1.265159130096 -0.141010046005 -v 0.213674545288 1.265947461128 -0.146045088768 -v 0.217527627945 1.274109721184 -0.141741633415 -v 0.215512275696 1.264181613922 -0.138061285019 -v 0.220313549042 1.262314796448 -0.135805130005 -v 0.220573663712 1.257741451263 -0.138237059116 -v 0.216372489929 1.257721900940 -0.141187667847 -v 0.212907791138 1.258577108383 -0.145352184772 -v 0.233858585358 1.256473422050 -0.125267803669 -v 0.234248638153 1.251918315887 -0.127823233604 -v 0.246033430099 1.251870393753 -0.112772464752 -v 0.246748685837 1.247483968735 -0.115507006645 -v 0.247130870819 1.256455659866 -0.111137330532 -v 0.258541584015 1.245236992836 -0.084437072277 -v 0.256093978882 1.239906072617 -0.086883187294 -v 0.257097005844 1.266151666641 -0.110764563084 -v 0.266882419586 1.251339793205 -0.085104942322 -v 0.267502307892 1.270240545273 -0.112958729267 -v 0.275364637375 1.256015896797 -0.091180860996 -v 0.275161266327 1.274131059647 -0.118503391743 -v 0.285532474518 1.258744239807 -0.098316013813 -v 0.281810045242 1.273761987686 -0.128352165222 -v 0.294841051102 1.259177684784 -0.109563946724 -v 0.285378694534 1.267878890038 -0.136893749237 -v 0.299645662308 1.256075739861 -0.122435271740 -v 0.267150640488 1.279207229614 -0.152110457420 -v 0.266644477844 1.272503018379 -0.155482232571 -v 0.285328865051 1.260385632515 -0.145259499550 -v 0.245440483093 1.281306147575 -0.162130832672 -v 0.247352838516 1.277317881584 -0.164401888847 -v 0.226536273956 1.277150392532 -0.165146172047 -v 0.244216680527 1.272458314896 -0.165734708309 -v 0.265185594559 1.264242410660 -0.158591628075 -v 0.225196361542 1.271236658096 -0.164832949638 -v 0.240829467773 1.264716506004 -0.164158344269 -v 0.256122827530 1.256213188171 -0.158023118973 -v 0.249283313751 1.251091122627 -0.154383540154 -v 0.264867782593 1.238259196281 -0.149782478809 -v 0.271236419678 1.243698835373 -0.152746677399 -v 0.242131233215 1.248456358910 -0.149258136749 -v 0.259697437286 1.235559821129 -0.143175721169 -v 0.238021850586 1.246404170990 -0.140355885029 -v 0.255519628525 1.235976219177 -0.134220600128 -v 0.235714912415 1.248224496841 -0.132601261139 -v 0.249901533127 1.242415428162 -0.121484637260 -v 0.225628137589 1.255354166031 -0.141528964043 -v 0.219279289246 1.256212234497 -0.146652877331 -v 0.261144638062 1.227618336678 -0.105385541916 -v 0.265067815781 1.218194127083 -0.118982553482 -v 0.255488157272 1.234093666077 -0.095165371895 -v 0.257819652557 1.237515091896 -0.082652032375 -v 0.256304979324 1.231330990791 -0.090660393238 -v 0.261433124542 1.242497920990 -0.080974459648 -v 0.269018650055 1.247485637665 -0.080007076263 -v 0.276544094086 1.249154090881 -0.084097981453 -v 0.286174535751 1.250129461288 -0.091734588146 -v 0.297051906586 1.250920057297 -0.101950109005 -v 0.304772377014 1.248518705368 -0.115050077438 -v 0.297762155533 1.245796918869 -0.131601870060 -v 0.303509950638 1.239294528961 -0.125708818436 -v 0.278063774109 1.251515507698 -0.150501132011 -v 0.292453289032 1.234364628792 -0.138768732548 -v 0.285548925400 1.222070693970 -0.138958930969 -v 0.275888442993 1.216582298279 -0.135062336922 -v 0.269642829895 1.214331030846 -0.127090573311 -v 0.265042543411 1.214603662491 -0.116683065891 -v 0.270244359970 1.211904883385 -0.125036418438 -v 0.259296417236 1.223366022110 -0.101866900921 -v 0.260845899582 1.212415218353 -0.112328946590 -v 0.266552209854 1.205083847046 -0.122853875160 -v 0.268821239471 1.210025906563 -0.123203098774 -v 0.277948856354 1.207428336143 -0.128034055233 -v 0.277915716171 1.211367130280 -0.128684759140 -v 0.288717508316 1.213802814484 -0.129420161247 -v 0.287309169769 1.217238068581 -0.130407452583 -v 0.277626991272 1.213335871696 -0.130287289619 -v 0.286727428436 1.219543695450 -0.133292317390 -v 0.297491550446 1.224069118500 -0.127825796604 -v 0.295832872391 1.229104042053 -0.133770406246 -v 0.299275398254 1.222613096237 -0.126457333565 -v 0.306288719177 1.231516838074 -0.115943133831 -v 0.303650856018 1.233008384705 -0.119831323624 -v 0.304522037506 1.218244671822 -0.125307500362 -v 0.291501283646 1.207969903946 -0.129891932011 -v 0.295377254486 1.198327302933 -0.132311940193 -v 0.312335252762 1.210624575615 -0.126865327358 -v 0.307499647141 1.182762622833 -0.133446455002 -v 0.321811676025 1.199660181999 -0.127626895905 -v 0.313686370850 1.178631782532 -0.132702827454 -v 0.327832698822 1.190094709396 -0.127820491791 -v 0.318174362183 1.174999833107 -0.130550682545 -v 0.329443216324 1.184651136398 -0.126586496830 -v 0.320348262787 1.172263383865 -0.127011775970 -v 0.329268336296 1.182359218597 -0.124253869057 -v 0.319159746170 1.172549962997 -0.124517083168 -v 0.327510595322 1.181082725525 -0.121122121811 -v 0.341977953911 1.186866998672 -0.119443237782 -v 0.340240001678 1.181673407555 -0.114829957485 -v 0.342066526413 1.190820455551 -0.118938207626 -v 0.343557119370 1.197325468063 -0.114280879498 -v 0.308367967606 1.238885641098 -0.100797057152 -v 0.302496671677 1.241308212280 -0.108589589596 -v 0.297030925751 1.244460582733 -0.094559252262 -v 0.288425922394 1.242414832115 -0.070966482162 -v 0.300933361053 1.241560339928 -0.084082663059 -v 0.287242650986 1.245997667313 -0.082513213158 -v 0.276428461075 1.242347240448 -0.063216865063 -v 0.276814937592 1.246329665184 -0.074558973312 -v 0.262533426285 1.248234033585 -0.033080637455 -v 0.268426895142 1.245181202888 -0.070157289505 -v 0.255537271500 1.244341135025 -0.030193269253 -v 0.255340337753 1.255470871925 -0.021258711815 -v 0.248293161392 1.248656272888 -0.019238531590 -v 0.246406555176 1.241610646248 -0.014172136784 -v 0.252004623413 1.238135337830 -0.023450851440 -v 0.240248918533 1.252865195274 -0.008260846138 -v 0.236009836197 1.244751214981 -0.002041816711 -v 0.250643014908 1.260913610458 -0.006915748119 -v 0.241449356079 1.238094210625 0.000856995583 -v 0.248243808746 1.235244989395 -0.007029771805 -v 0.236295223236 1.238589763641 0.006947577000 -v 0.244088888168 1.237448453903 0.010651528835 -v 0.245872020721 1.235504984856 0.007974743843 -v 0.240644693375 1.243501543999 0.007078409195 -v 0.245250463486 1.240480542183 0.010777413845 -v 0.252675771713 1.233302831650 0.020247042179 -v 0.254426479340 1.231533646584 0.017972588539 -v 0.254062652588 1.237539768219 0.019096493721 -v 0.276159763336 1.255128741264 0.018554508686 -v 0.275947093964 1.249229311943 0.022302091122 -v 0.272867918015 1.249667882919 0.024674117565 -v 0.271744251251 1.251732468605 0.021295309067 -v 0.283636093140 1.255234718323 0.014072477818 -v 0.280255317688 1.247575402260 0.019362986088 -v 0.276215314865 1.261920690536 0.008904576302 -v 0.278604030609 1.259399175644 0.004241228104 -v 0.285460472107 1.252817630768 0.010138630867 -v 0.266534566879 1.266445875168 0.005049049854 -v 0.258428096771 1.268704891205 0.002973020077 -v 0.254645347595 1.267239928246 0.003869831562 -v 0.287663459778 1.258239984512 -0.004414916039 -v 0.298110485077 1.250542998314 0.003384351730 -v 0.298449993134 1.244361400604 -0.001860737801 -v 0.299829959869 1.234122157097 0.006569683552 -v 0.298758268356 1.238474845886 0.010709106922 -v 0.303976297379 1.239164352417 -0.006211340427 -v 0.305155038834 1.229295969009 0.004372239113 -v 0.300870895386 1.218429088593 0.011674880981 -v 0.295304775238 1.223464488983 0.011802554131 -v 0.293110609055 1.205903887749 0.015846788883 -v 0.286343812943 1.213704109192 0.013587355614 -v 0.302354812622 1.196681976318 0.018828034401 -v 0.283874988556 1.219200730324 0.015126287937 -v 0.293270826340 1.227752089500 0.015739440918 -v 0.283052444458 1.240837812424 0.023119628429 -v 0.276622056961 1.233630180359 0.024268507957 -v 0.286540031433 1.246751070023 0.017804086208 -v 0.272910356522 1.237592816353 0.025359690189 -v 0.278305053711 1.243288516998 0.024740695953 -v 0.267666101456 1.227963447571 0.022224366665 -v 0.264769792557 1.232656955719 0.024754941463 -v 0.260413408279 1.224851250648 0.011581957340 -v 0.257379055023 1.225758671761 -0.000789821148 -v 0.253545045853 1.232021093369 -0.012868225574 -v 0.254851341248 1.226656675339 -0.018729388714 -v 0.251304626465 1.230217099190 0.003005683422 -v 0.256979942322 1.228909850121 0.014670252800 -v 0.250156402588 1.223106861115 -0.021990776062 -v 0.239892244339 1.227292776108 -0.045880913734 -v 0.245432853699 1.234084725380 -0.064319491386 -v 0.254643917084 1.237128496170 -0.077797412872 -v 0.259204149246 1.241605043411 -0.074413061142 -v 0.253374576569 1.265572071075 0.004234373569 -v 0.252619743347 1.259510278702 0.004528701305 -v 0.295717954636 1.157437562943 -0.004984855652 -v 0.302157163620 1.158133268356 0.007280886173 -v 0.303221464157 1.155419707298 -0.004480600357 -v 0.306118011475 1.158186078072 0.009157180786 -v 0.309594392776 1.154529452324 -0.002081036568 -v 0.317309141159 1.145281672478 -0.095512390137 -v 0.342793583870 1.111549854279 -0.096035361290 -v 0.370063781738 1.103682756424 -0.078702569008 -v 0.223846435547 1.280663371086 -0.149150192738 -v 0.262922763824 1.260004043579 0.011266469955 -v 0.278262376785 1.128904223442 -0.071313738823 -v 0.278782129288 1.129065513611 -0.078170895576 -v 0.214526414871 1.261890172958 -0.147512257099 -v 0.403749704361 1.053897500038 -0.044087231159 -v -0.173335313797 1.189228773117 -0.074161946774 -v -0.172501087189 1.194711208344 -0.077600002289 -v -0.156718730927 1.200044989586 -0.067752003670 -v -0.159983634949 1.195769190788 -0.064942240715 -v -0.157345533371 1.192241907120 -0.064338445663 -v -0.176035165787 1.182665348053 -0.074862539768 -v -0.153723001480 1.198203325272 -0.067141354084 -v -0.154419660568 1.185277462006 -0.061343967915 -v -0.174031734467 1.176616787910 -0.076530218124 -v -0.153948068619 1.192448616028 -0.066138029099 -v -0.152566671371 1.196974277496 -0.068748712540 -v -0.149900436401 1.188096642494 -0.064178586006 -v -0.167804479599 1.171906828880 -0.078679144382 -v -0.151026010513 1.177392482758 -0.069037199020 -v -0.159547805786 1.170724391937 -0.081492185593 -v -0.137443780899 1.179318189621 -0.071261107922 -v -0.151052713394 1.171566128731 -0.090630888939 -v -0.145410776138 1.202758073807 -0.074415385723 -v -0.146416664124 1.204916477203 -0.073959469795 -v -0.142997503281 1.206828117371 -0.075007200241 -v -0.139394283295 1.203434348106 -0.075942695141 -v -0.143990516663 1.207095742226 -0.077334642410 -v -0.152405261993 1.204598784447 -0.072375178337 -v -0.150315523148 1.201716780663 -0.070241928101 -v -0.169452428818 1.199298620224 -0.083030939102 -v -0.163226604462 1.203215003014 -0.090547025204 -v -0.193114757538 1.175109863281 -0.086916208267 -v -0.185326576233 1.171366214752 -0.082843124866 -v -0.186292409897 1.165282964706 -0.088589191437 -v -0.200573444366 1.166569828987 -0.092627763748 -v -0.138775825500 1.205187916756 -0.076617836952 -v -0.135615825653 1.203529238701 -0.077090024948 -v -0.155732393265 1.203607797623 -0.096656978130 -v -0.149366855621 1.200804471970 -0.100724101067 -v -0.137942790985 1.205677509308 -0.079242825508 -v -0.131234407425 1.203546047211 -0.080529451370 -v -0.130687952042 1.197476148605 -0.079052925110 -v -0.130004167557 1.197584390640 -0.081454098225 -v -0.129281997681 1.189852356911 -0.077395677567 -v -0.131329774857 1.190665483475 -0.076595366001 -v -0.141457080841 1.192768573761 -0.102260649204 -v -0.127812385559 1.196197390556 -0.082319319248 -v -0.144458770752 1.197188854218 -0.101949512959 -v -0.177466392517 1.161493182182 -0.094907760620 -v -0.163338899612 1.165530800819 -0.106261909008 -v -0.128491640091 1.187958240509 -0.082086682320 -v -0.140712261200 1.182583570480 -0.100011527538 -v -0.210927009583 1.107810139656 -0.110981822014 -v -0.211072683334 1.103303790092 -0.109917879105 -v -0.213212490082 1.101778507233 -0.109918236732 -v -0.214309692383 1.109030246735 -0.111766934395 -v -0.204130172729 1.105494737625 -0.113910675049 -v -0.205763339996 1.099799871445 -0.112921178341 -v -0.223363876343 1.117204904556 -0.114630222321 -v -0.214059114456 1.124341964722 -0.111509382725 -v -0.219065189362 1.105570316315 -0.114096760750 -v -0.238481521606 1.129768848419 -0.130072593689 -v -0.234876394272 1.134552240372 -0.130008339882 -v -0.223749637604 1.136018037796 -0.118461847305 -v -0.207642078400 1.120860934258 -0.111469984055 -v -0.208950042725 1.096844553947 -0.112857937813 -v -0.215140581131 1.098256349564 -0.112100958824 -v -0.209567785263 1.147545337677 -0.113711655140 -v -0.197745561600 1.140209794044 -0.107432365417 -v -0.193334102631 1.132169842720 -0.107758402824 -v -0.193572998047 1.150783538818 -0.107727050781 -v -0.203800201416 1.156490325928 -0.111603617668 -v -0.175592660904 1.145561695099 -0.106927514076 -v -0.172769784927 1.138006210327 -0.105781555176 -v -0.177102327347 1.152362346649 -0.109004378319 -v -0.203049182892 1.103446960449 -0.115947484970 -v -0.205771446228 1.097857356071 -0.116888880730 -v -0.200581550598 1.109675526619 -0.119850099087 -v -0.202297449112 1.114114880562 -0.116474270821 -v -0.205280303955 1.096752166748 -0.122693479061 -v -0.225318193436 1.093360424042 -0.128429234028 -v -0.225040435791 1.096657991409 -0.123039066792 -v -0.220809221268 1.096151828766 -0.119270980358 -v -0.221869707108 1.091606855392 -0.126757025719 -v -0.228603363037 1.095641136169 -0.129044175148 -v -0.228597879410 1.101918220520 -0.122385978699 -v -0.224291801453 1.103944659233 -0.118215620518 -v -0.247853517532 1.125877380371 -0.145480275154 -v -0.241319656372 1.134932279587 -0.146954476833 -v -0.224902391434 1.146563768387 -0.131057977676 -v -0.189874410629 1.125573754311 -0.113757431507 -v -0.188519477844 1.120980858803 -0.117558717728 -v -0.197483062744 1.107985734940 -0.124557018280 -v -0.203064918518 1.094104051590 -0.134538710117 -v -0.212108135223 1.091883540154 -0.125092267990 -v -0.146539926529 1.190650701523 -0.114794254303 -v -0.146754264832 1.180134177208 -0.115530133247 -v -0.152557849884 1.174678444862 -0.113840103149 -v -0.143783569336 1.177394032478 -0.097335398197 -v -0.152518033981 1.177743196487 -0.127124845982 -v -0.154675722122 1.168212413788 -0.123611927032 -v -0.152200698853 1.192405939102 -0.124226093292 -v -0.149080038071 1.190506696701 -0.121930062771 -v -0.149870634079 1.194133043289 -0.115894854069 -v -0.152212619781 1.190471172333 -0.127474963665 -v -0.152487754822 1.182887434959 -0.127529799938 -v -0.154866933823 1.185299873352 -0.129990160465 -v -0.154926300049 1.181805968285 -0.133388638496 -v -0.233518838882 1.051918983459 -0.153825461864 -v -0.234681367874 1.048460602760 -0.154123127460 -v -0.235526800156 1.045760154724 -0.156687140465 -v -0.238681077957 1.048464179039 -0.156781077385 -v -0.229362010956 1.049855709076 -0.154987037182 -v -0.227258443832 1.057394742966 -0.153537988663 -v -0.231667280197 1.046329975128 -0.156813800335 -v -0.223042964935 1.088201880455 -0.145084559917 -v -0.215483188629 1.087337613106 -0.146565556526 -v -0.215860605240 1.081712245941 -0.155044794083 -v -0.226407766342 1.085251331329 -0.153320491314 -v -0.235337972641 1.090702056885 -0.156869351864 -v -0.226635932922 1.075340270996 -0.153673052788 -v -0.235593795776 1.084217786789 -0.159696042538 -v -0.230427265167 1.064726591110 -0.154860198498 -v -0.235838890076 1.056318044662 -0.154584050179 -v -0.244804859161 1.037203311920 -0.166494607925 -v -0.242951393127 1.043129205704 -0.159860074520 -v -0.236907005310 1.041309475899 -0.161783397198 -v -0.243432760239 1.035140395164 -0.168893754482 -v -0.224668979645 1.052752375603 -0.157276332378 -v -0.230270862579 1.046147704124 -0.159191727638 -v -0.159595966339 1.184921741486 -0.135831117630 -v -0.160187005997 1.181343317032 -0.141996622086 -v -0.153135061264 1.179491877556 -0.142091393471 -v -0.169377088547 1.185044288635 -0.136880159378 -v -0.170533895493 1.181570768356 -0.151052296162 -v -0.160138130188 1.174441456795 -0.159372687340 -v -0.222903490067 1.065987110138 -0.152610003948 -v -0.210915327072 1.058199882507 -0.158076643944 -v -0.219084739685 1.052546024323 -0.157240092754 -v -0.209656953812 1.069716095924 -0.156206488609 -v -0.242612361908 1.097414970398 -0.161309957504 -v -0.247563600540 1.103350877762 -0.164090692997 -v -0.248119831085 1.110607266426 -0.158350706100 -v -0.241690874100 1.101655244827 -0.159433066845 -v -0.244697809219 1.092168807983 -0.164222717285 -v -0.251339673996 1.101027250290 -0.169793009758 -v -0.253261089325 1.111646056175 -0.160615861416 -v -0.246266365051 1.039236307144 -0.166336178780 -v -0.249294042587 1.037806272507 -0.168891787529 -v -0.250867843628 1.039080262184 -0.168178379536 -v -0.247174024582 1.041245818138 -0.164608359337 -v -0.252528667450 1.034430623055 -0.174002289772 -v -0.255876541138 1.036398887634 -0.174964785576 -v -0.248456478119 1.035744786263 -0.171986579895 -v -0.207899332047 1.087407350540 -0.147547543049 -v -0.209868431091 1.082488656044 -0.153715491295 -v -0.206011295319 1.082607984543 -0.148635447025 -v -0.207342624664 1.075194835663 -0.155124664307 -v -0.252168178558 1.045034170151 -0.165443241596 -v -0.258034706116 1.046116113663 -0.173089325428 -v -0.262003183365 1.051245570183 -0.178000867367 -v -0.252234935760 1.049173116684 -0.164762079716 -v -0.252549409866 1.041483521461 -0.167263507843 -v -0.259843349457 1.041425228119 -0.177599608898 -v -0.270201206207 1.045489907265 -0.187091112137 -v -0.276372432709 1.040201425552 -0.192463517189 -v -0.278449535370 1.034975290298 -0.196169674397 -v -0.284775257111 1.029717683792 -0.197532415390 -v -0.284212112427 1.040760636330 -0.193028330803 -v -0.271418571472 1.038434147835 -0.194264531136 -v -0.273589372635 1.034032583237 -0.199454545975 -v -0.281298398972 1.027353167534 -0.202217400074 -v -0.285241842270 1.052183389664 -0.197862207890 -v -0.287758827209 1.044720053673 -0.200536787510 -v -0.285270452499 1.052050352097 -0.209925532341 -v -0.284770965576 1.056814908981 -0.208144426346 -v -0.286429882050 1.041720151901 -0.204202711582 -v -0.282965183258 1.049952030182 -0.209141969681 -v -0.281043052673 1.048063278198 -0.188708662987 -v -0.144400358200 1.176907896996 -0.151417970657 -v -0.135134458542 1.175758123398 -0.166907787323 -v -0.129020690918 1.170335769653 -0.138893842697 -v -0.141971826553 1.174503087997 -0.135131359100 -v -0.119428634644 1.164143443108 -0.165285944939 -v -0.116199493408 1.159146547318 -0.141210973263 -v -0.142082691193 1.176310896873 -0.178735315800 -v -0.151244163513 1.175081014633 -0.169050514698 -v -0.125181674957 1.176591157913 -0.177203238010 -v -0.130443096161 1.183761119843 -0.186303555965 -v -0.245208501816 1.111506700516 -0.205009043217 -v -0.232599973679 1.125318527222 -0.206095397472 -v -0.240747690201 1.128869056702 -0.186226844788 -v -0.252095937729 1.110360264778 -0.190840721130 -v -0.230934619904 1.112748980522 -0.219200611115 -v -0.201740980148 1.135213136673 -0.227704524994 -v -0.210019588470 1.145615220070 -0.203961193562 -v -0.256554365158 1.026075959206 -0.197485446930 -v -0.252297163010 1.025413274765 -0.206123828888 -v -0.262440681458 1.028629183769 -0.203707456589 -v -0.262872934341 1.028875350952 -0.197542905807 -v -0.253294944763 1.027410507202 -0.211396694183 -v -0.259093761444 1.029339194298 -0.211079478264 -v -0.246476411819 1.024986743927 -0.206110835075 -v -0.252317905426 1.024993419647 -0.197774946690 -v -0.311765909195 0.993130266666 -0.226933717728 -v -0.310108184814 0.996098339558 -0.225180983543 -v -0.310272455215 0.995082259178 -0.224124073982 -v -0.309615135193 0.992788553238 -0.226431727409 -v -0.307722568512 0.995178222656 -0.223333239555 -v -0.308899879456 0.997443914413 -0.225597083569 -v -0.306552886963 0.996318519115 -0.226082086563 -v -0.301561355591 0.999858021736 -0.221365690231 -v -0.301273822784 0.999540150166 -0.223513543606 -v -0.300451040268 0.999494612217 -0.225161433220 -v -0.291275262833 1.008644461632 -0.219689548016 -v -0.289765357971 1.008863568306 -0.223312497139 -v -0.303882122040 1.002618789673 -0.222436308861 -v -0.245472908020 1.029212474823 -0.216191470623 -v -0.251756668091 1.032742142677 -0.216125905514 -v -0.240088224411 1.029202461243 -0.212740898132 -v -0.305489063263 0.996842980385 -0.228073120117 -v -0.301641464233 1.000535249710 -0.226922750473 -v -0.297816038132 1.000618338585 -0.226435422897 -v -0.304344177246 0.995790660381 -0.228550374508 -v -0.307172536850 0.993706703186 -0.230047941208 -v -0.308262586594 0.994648814201 -0.229670286179 -v -0.308869600296 0.993044137955 -0.230499446392 -v -0.308663368225 0.993162393570 -0.231502115726 -v -0.309333801270 0.993721485138 -0.231109619141 -v -0.308087825775 0.994998931885 -0.231224834919 -v -0.103364944458 1.130733013153 -0.165089964867 -v -0.107626914978 1.133225798607 -0.140607297421 -v -0.110349178314 1.147431254387 -0.169585108757 -v -0.118245124817 1.140465259552 -0.188436806202 -v -0.112480401993 1.127350330353 -0.185356020927 -v -0.119234800339 1.154477119446 -0.179611444473 -v -0.122121334076 1.162646651268 -0.173162460327 -v -0.123259067535 1.147673130035 -0.192043066025 -v -0.307780742645 0.994723260403 -0.231847167015 -v -0.307749986649 0.993669688702 -0.231788516045 -v -0.306983709335 0.993704020977 -0.230996787548 -v -0.193033456802 1.081855773926 -0.203872740269 -v -0.194959878922 1.074067234993 -0.206613779068 -v -0.192106723785 1.074653506279 -0.197215080261 -v -0.189585685730 1.081505656242 -0.199741780758 -v -0.181468963623 1.087621688843 -0.203916847706 -v -0.182246923447 1.086801290512 -0.208190560341 -v -0.180797338486 1.080666303635 -0.200190067291 -v -0.238004446030 1.038412332535 -0.221756696701 -v -0.255303144455 1.040868282318 -0.221722602844 -v -0.259346246719 1.034848093987 -0.217119097710 -v -0.226242780685 1.046014308929 -0.223912119865 -v -0.243605136871 1.045503258705 -0.225179314613 -v -0.229806661606 1.033677101135 -0.221885204315 -v -0.128174781799 1.188377022743 -0.200627446175 -v -0.148290157318 1.179109573364 -0.194076895714 -v -0.271722316742 1.054550886154 -0.227642059326 -v -0.274076938629 1.049859046936 -0.228212535381 -v -0.270540475845 1.041400551796 -0.231285452843 -v -0.265389442444 1.048523783684 -0.231947541237 -v -0.279670238495 1.057693004608 -0.219425976276 -v -0.279539346695 1.051576972008 -0.220776438713 -v -0.275705814362 1.041727423668 -0.228427529335 -v -0.199706077576 1.055555105209 -0.210151553154 -v -0.194469451904 1.055464029312 -0.201491832733 -v -0.188562631607 1.062397480011 -0.194959938526 -v -0.193209409714 1.067214727402 -0.202750325203 -v -0.197559595108 1.061594724655 -0.212190330029 -v -0.199322462082 1.054384827614 -0.212732195854 -v -0.264539003372 1.034891843796 -0.224602222443 -v -0.264505386353 1.033686161041 -0.220391511917 -v -0.259446859360 1.043034553528 -0.228882968426 -v -0.253154993057 1.049899816513 -0.229087173939 -v -0.192896127701 1.083252668381 -0.207294523716 -v -0.205631494522 1.076366066933 -0.214735269547 -v -0.194759368896 1.084827780724 -0.212751626968 -v -0.223470926285 1.074144601822 -0.221447348595 -v -0.204793214798 1.086842775345 -0.216361939907 -v -0.216625213623 1.087888479233 -0.219625651836 -v -0.195574283600 1.087720632553 -0.216327428818 -v -0.220762968063 1.036061048508 -0.216470956802 -v -0.213054895401 1.035783767700 -0.213620066643 -v -0.201663494110 1.045588612556 -0.206914484501 -v -0.209848642349 1.043720960617 -0.214580178261 -v -0.216307878494 1.038053512573 -0.218539953232 -v -0.226351261139 1.035285830498 -0.218240320683 -v -0.205461740494 1.046299815178 -0.217294871807 -v -0.213101387024 1.042110800743 -0.219072997570 -v -0.220921278000 1.039087295532 -0.221290767193 -v -0.220387458801 1.042260169983 -0.223516404629 -v -0.213362932205 1.046354770660 -0.223494648933 -v -0.166803121567 1.090283155441 -0.212349832058 -v -0.172270536423 1.087766289711 -0.218560039997 -v -0.183573484421 1.086018800735 -0.212494730949 -v -0.167399406433 1.091666579247 -0.207822561264 -v -0.158848285675 1.093401670456 -0.218638300896 -v -0.162909030914 1.089765548706 -0.223327994347 -v -0.030130147934 1.186614990234 -0.177592396736 -v -0.028016805649 1.185017704964 -0.176330447197 -v -0.027128219604 1.182949185371 -0.177097141743 -v -0.030794620514 1.185065984726 -0.177214145660 -v -0.027263402939 1.185469865799 -0.176604092121 -v -0.029033184052 1.187615036964 -0.178278744221 -v -0.025565147400 1.183858990669 -0.176834225655 -v -0.026248216629 1.187106251717 -0.178503096104 -v -0.155820369720 1.101422905922 -0.208842039108 -v -0.143939018250 1.110964536667 -0.203809499741 -v -0.147772073746 1.116233944893 -0.210553169250 -v -0.153800964355 1.103918313980 -0.216478586197 -v -0.151521444321 1.110116600990 -0.224545180798 -v -0.153570175171 1.098989486694 -0.229076087475 -v -0.153712034225 1.098475694656 -0.221522092819 -v -0.143598556519 1.121090412140 -0.215590834618 -v -0.025197982788 1.179040908813 -0.178160905838 -v -0.028691530228 1.180666327477 -0.177641034126 -v -0.024049282074 1.180395364761 -0.178064346313 -v -0.023061275482 1.183145642281 -0.176922082901 -v -0.024633884430 1.187012076378 -0.180191814899 -v -0.022006034851 1.183752536774 -0.176543354988 -v -0.023281335831 1.181692600250 -0.177503108978 -v -0.041700124741 1.194597840309 -0.188832759857 -v -0.040053844452 1.195041775703 -0.191445589066 -v -0.038641691208 1.194105863571 -0.194117784500 -v -0.021546125412 1.184016108513 -0.178950071335 -v -0.023211956024 1.185567021370 -0.181426763535 -v -0.020884990692 1.182555675507 -0.179597258568 -v -0.155306577682 1.094101190567 -0.223596096039 -v -0.153067588806 1.095505952835 -0.230197072029 -v -0.024875402451 1.176557660103 -0.180157959461 -v -0.029001712799 1.177595734596 -0.180325567722 -v -0.022265434265 1.178601741791 -0.180594265461 -v -0.022731781006 1.183528065681 -0.182420313358 -v -0.129092454910 1.126704692841 -0.201514482498 -v -0.129842519760 1.138575315475 -0.203304290771 -v -0.140452623367 1.137107372284 -0.216508805752 -v -0.143960952759 1.126296997070 -0.219137907028 -v -0.154357194901 1.127161264420 -0.228255271912 -v -0.149726629257 1.136419534683 -0.223747491837 -v -0.174418687820 1.142764806747 -0.223434805870 -v -0.169390678406 1.132646441460 -0.235435843468 -v -0.159634113312 1.138588905334 -0.227177619934 -v -0.183374881744 1.151468753815 -0.210604786873 -v -0.202531337738 1.122591972351 -0.235654771328 -v -0.174713850021 1.123547434807 -0.239896833897 -v -0.026677846909 1.177809119225 -0.182901620865 -v -0.028857231140 1.177586197853 -0.182363390923 -v -0.180840730667 1.098434567451 -0.228965997696 -v -0.177192926407 1.093732595444 -0.232580184937 -v -0.174651861191 1.104560375214 -0.238290369511 -v -0.178368806839 1.106090188026 -0.233393609524 -v -0.168076038361 1.097283363342 -0.234453976154 -v -0.169014692307 1.107891798019 -0.237803101540 -v -0.176104545593 1.089681625366 -0.227148771286 -v -0.167286634445 1.091750741005 -0.230993151665 -v -0.157043457031 1.091841936111 -0.227160215378 -v -0.159157276154 1.091518163681 -0.229555249214 -v -0.155268907547 1.095846176147 -0.231792688370 -v -0.160398960114 1.094118118286 -0.232700586319 -v -0.161424636841 1.113683462143 -0.233527243137 -v -0.153696537018 1.112774372101 -0.227253794670 -v -0.160377740860 1.100663542747 -0.232878029346 -v -0.155321598053 1.101318359375 -0.229982614517 -v -0.129415988922 1.121230006218 -0.195909500122 -v -0.115429162979 1.119397759438 -0.179361224174 -v -0.130902051926 1.117012500763 -0.191515922546 -v -0.115962266922 1.118604898453 -0.176315546036 -v -0.110272169113 1.120705842972 -0.160776674747 -v -0.113960504532 1.119729280472 -0.159553110600 -v -0.120643854141 1.123042941093 -0.142679691315 -v -0.116504192352 1.124894142151 -0.141778171062 -v -0.116237640381 1.119012355804 -0.159137606621 -v -0.121575117111 1.122238159180 -0.143324553967 -v -0.133432149887 1.123821258545 -0.128500640392 -v -0.129076957703 1.126407384872 -0.125177204609 -v -0.133791923523 1.122404217720 -0.126223802567 -v -0.151261806488 1.118286848068 -0.116750955582 -v -0.150382995605 1.123445391655 -0.118158876896 -v -0.165156841278 1.112223029137 -0.114312648773 -v -0.168798208237 1.119785189629 -0.114506125450 -v -0.146946668625 1.111286401749 -0.115677714348 -v -0.159301757813 1.103829860687 -0.112823069096 -v -0.169470071793 1.095391631126 -0.113259613514 -v -0.176546573639 1.104174375534 -0.116012811661 -v -0.181593179703 1.086678743362 -0.119435906410 -v -0.187299728394 1.095249652863 -0.122014880180 -v -0.192334890366 1.079224348068 -0.132685303688 -v -0.196459770203 1.086544990540 -0.133203148842 -v -0.167187929153 1.093284368515 -0.118592262268 -v -0.158042192459 1.100373268127 -0.117775142193 -v -0.177332639694 1.085744619370 -0.124823093414 -v -0.188689470291 1.078408122063 -0.135257482529 -v -0.133802890778 1.114060878754 -0.127829909325 -v -0.147693157196 1.107499122620 -0.121569573879 -v -0.130974292755 1.116622328758 -0.124757289886 -v -0.118712902069 1.116385936737 -0.142161726952 -v -0.114444732666 1.114831447601 -0.156344830990 -v -0.116871118546 1.115381836891 -0.173745512962 -v -0.127918481827 1.112462520599 -0.189754128456 -v -0.140444517136 1.105615377426 -0.201572239399 -v -0.153226137161 1.096442341805 -0.206420838833 -v -0.166574478149 1.087847948074 -0.204887628555 -v -0.148325681686 1.084455490112 -0.202776551247 -v -0.132059097290 1.095326542854 -0.197568535805 -v -0.118970394135 1.104256153107 -0.183249711990 -v -0.113605022430 1.110781550407 -0.171092212200 -v -0.119467735291 1.110980629921 -0.156059205532 -v -0.118595600128 1.107293367386 -0.167004108429 -v -0.122451543808 1.113593697548 -0.145232379436 -v -0.123160123825 1.101921558380 -0.179320454597 -v -0.134120464325 1.093572258949 -0.190831780434 -v -0.149135828018 1.083696126938 -0.196358323097 -v -0.164771795273 1.075974822044 -0.199542462826 -v -0.178263664246 1.069347739220 -0.194986939430 -v -0.178308486938 1.067918300629 -0.193336069584 -v -0.187574863434 1.061674833298 -0.193846702576 -v -0.165014982224 1.074935913086 -0.195628762245 -v -0.203114748001 1.047059774399 -0.203367710114 -v -0.194963455200 1.055162310600 -0.198111474514 -v -0.211767911911 1.036029338837 -0.208810448647 -v -0.212155818939 1.037373661995 -0.206103205681 -v -0.226508617401 1.025479078293 -0.212446689606 -v -0.223773002625 1.027394175529 -0.209277987480 -v -0.234503984451 1.028979897499 -0.212858796120 -v -0.240490436554 1.019392728806 -0.204267203808 -v -0.244890213013 1.018656373024 -0.196853935719 -v -0.253900766373 1.026709318161 -0.190710783005 -v -0.246401309967 1.020783185959 -0.188246011734 -v -0.252592563629 1.030183553696 -0.180509030819 -v -0.245979547501 1.024557352066 -0.179143786430 -v -0.256746768951 1.027064442635 -0.190641164780 -v -0.255533695221 1.030755162239 -0.181877255440 -v -0.261640310287 1.031444549561 -0.191453814507 -v -0.259487628937 1.033203363419 -0.183249652386 -v -0.265381097794 1.035956144333 -0.193069219589 -v -0.262969732285 1.038062810898 -0.186465203762 -v -0.266802787781 1.033626079559 -0.198642969131 -v -0.266010284424 1.031839489937 -0.204385280609 -v -0.270675420761 1.031339287758 -0.205536782742 -v -0.263313770294 1.031893968582 -0.211139619350 -v -0.266834974289 1.031145095825 -0.212556302547 -v -0.272355556488 1.027421116829 -0.214405179024 -v -0.271020889282 1.027558326721 -0.222151696682 -v -0.277619600296 1.026623606682 -0.207558810711 -v -0.287308216095 1.017905473709 -0.209584236145 -v -0.281747341156 1.017393589020 -0.217522501945 -v -0.290399074554 1.018112540245 -0.206793189049 -v -0.296507358551 1.008396148682 -0.213786959648 -v -0.293893098831 1.008637905121 -0.215864181519 -v -0.293311119080 1.018383622169 -0.204794526100 -v -0.298957824707 1.008759021759 -0.211997389793 -v -0.304624319077 1.000485181808 -0.218563914299 -v -0.302252292633 1.000493049622 -0.219046711922 -v -0.300442457199 1.010485529900 -0.212966322899 -v -0.295816421509 1.020895838737 -0.206146836281 -v -0.304791212082 1.002254843712 -0.220315814018 -v -0.298930644989 1.011639118195 -0.215272247791 -v -0.294509649277 1.021376132965 -0.208923101425 -v -0.305289983749 0.996663510799 -0.231430888176 -v -0.299525260925 1.002564072609 -0.230026721954 -v -0.304598808289 0.995765805244 -0.231520950794 -v -0.298396825790 1.001657962799 -0.230945348740 -v -0.303261518478 0.995977520943 -0.230365991592 -v -0.297660827637 1.000682115555 -0.229683041573 -v -0.297706365585 1.000391125679 -0.228264808655 -v -0.289501190186 1.008563995361 -0.227962017059 -v -0.289624452591 1.008912801743 -0.230370998383 -v -0.289333820343 1.008850455284 -0.225851535797 -v -0.279825210571 1.017765641212 -0.226271927357 -v -0.280007839203 1.018149375916 -0.228962600231 -v -0.279944658279 1.017497062683 -0.223519802094 -v -0.270844221115 1.027772903442 -0.226072430611 -v -0.271415948868 1.028410196304 -0.229272961617 -v -0.265730381012 1.036768198013 -0.229641437531 -v -0.273293256760 1.029914379120 -0.231202602386 -v -0.281020164490 1.019194722176 -0.231097579002 -v -0.275867462158 1.031501293182 -0.230385065079 -v -0.282980203629 1.020815610886 -0.230529665947 -v -0.276958703995 1.032087326050 -0.227720260620 -v -0.283688306808 1.021362662315 -0.227996766567 -v -0.275023937225 1.041705608368 -0.224775314331 -v -0.277465105057 1.049158096313 -0.218947708607 -v -0.292066335678 1.011417031288 -0.228806972504 -v -0.291158199310 1.010475993156 -0.230765581131 -v -0.289323091507 1.031211256981 -0.203581392765 -v -0.290323972702 1.031991720200 -0.200689315796 -v -0.239644289017 1.023190736771 -0.194890260696 -v -0.243260860443 1.023399710655 -0.188031911850 -v -0.234212636948 1.023423552513 -0.201564133167 -v -0.236090183258 1.021491050720 -0.202814877033 -v -0.199890851974 1.066753745079 -0.155146598816 -v -0.198434829712 1.067134857178 -0.156990110874 -v -0.202668666840 1.063336849213 -0.159977316856 -v -0.203597068787 1.063326001167 -0.157728374004 -v -0.194704532623 1.071926832199 -0.149038195610 -v -0.198426008224 1.071671962738 -0.146451592445 -v -0.204805612564 1.071662425995 -0.154704451561 -v -0.202652454376 1.077832579613 -0.147649407387 -v -0.199759483337 1.090992927551 -0.134201765060 -v -0.193034887314 1.103491783142 -0.123884439468 -v -0.185172319412 1.115739107132 -0.117173492908 -v -0.169998168945 1.124291777611 -0.114598035812 -v -0.171854734421 1.130073547363 -0.107446432114 -v -0.148004770279 1.133014440536 -0.109064579010 -v -0.149436950684 1.126783370972 -0.117963194847 -v -0.150363683701 1.141389131546 -0.109232008457 -v -0.129365682602 1.151356697083 -0.121360957623 -v -0.122787952423 1.133342862129 -0.118729412556 -v -0.155005455017 1.151965379715 -0.112209022045 -v -0.138591766357 1.161190986633 -0.122988164425 -v -0.160556554794 1.158395051956 -0.114823222160 -v -0.147845268250 1.166557192802 -0.123666226864 -v -0.164972066879 1.160841345787 -0.116209328175 -v -0.178743362427 1.155038595200 -0.107457756996 -v -0.193982124329 1.154866933823 -0.105260729790 -v -0.203804731369 1.162194013596 -0.107664465904 -v -0.203792333603 1.170711994171 -0.114600837231 -v -0.206958532333 1.165179967880 -0.118471503258 -v -0.199360370636 1.174407482147 -0.126586496830 -v -0.196566343307 1.177967667580 -0.121480822563 -v -0.211217403412 1.155824661255 -0.123464763165 -v -0.203953742981 1.165765166283 -0.134148895741 -v -0.217429161072 1.159095644951 -0.144569456577 -v -0.199710369110 1.170780539513 -0.160428583622 -v -0.189121007919 1.175161838531 -0.143832862377 -v -0.234441280365 1.145398378372 -0.158812522888 -v -0.208461523056 1.159196853638 -0.180670976639 -v -0.252185583115 1.116116285324 -0.170371294022 -v -0.254233121872 1.105154395103 -0.180382847786 -v -0.260434627533 1.096214771271 -0.185628652573 -v -0.256431102753 1.092083334923 -0.177367925644 -v -0.260645627975 1.097700595856 -0.194319903851 -v -0.270902156830 1.083015918732 -0.199528574944 -v -0.269893407822 1.081749439240 -0.189446091652 -v -0.256181478500 1.098464727402 -0.206231713295 -v -0.266798496246 1.083191156387 -0.212066352367 -v -0.273687601089 1.068179607391 -0.216568171978 -v -0.278900146484 1.067694902420 -0.202702641487 -v -0.258903264999 1.083254337311 -0.220462024212 -v -0.247154474258 1.097606897354 -0.216386973858 -v -0.265223979950 1.066669940948 -0.225265324116 -v -0.269017219543 1.059843063354 -0.226757824421 -v -0.277544975281 1.061369776726 -0.218553006649 -v -0.256574153900 1.063487887383 -0.228868722916 -v -0.250155687332 1.081251740456 -0.223481357098 -v -0.261117696762 1.055521845818 -0.231173992157 -v -0.248385906219 1.057556748390 -0.228811144829 -v -0.238748550415 1.076548695564 -0.223608195782 -v -0.234692811966 1.056388735771 -0.223354101181 -v -0.211627244949 1.056368947029 -0.221282124519 -v -0.228275060654 1.091947317123 -0.220990777016 -v -0.238418102264 1.094660639763 -0.219326555729 -v -0.216057777405 1.107417821884 -0.225473523140 -v -0.224503517151 1.109220266342 -0.227116346359 -v -0.211361885071 1.098301529884 -0.220512151718 -v -0.212726354599 1.104912161827 -0.221194267273 -v -0.207950830460 1.100727200508 -0.218157291412 -v -0.203674316406 1.092759370804 -0.219182014465 -v -0.202742576599 1.096199750900 -0.218188643456 -v -0.196501970291 1.090510606766 -0.218953371048 -v -0.196993589401 1.093491673470 -0.220363080502 -v -0.187599182129 1.091245770454 -0.224233686924 -v -0.188641786575 1.095030307770 -0.223733663559 -v -0.186239719391 1.088770151138 -0.220787882805 -v -0.185178756714 1.086016893387 -0.216318964958 -v -0.174246788025 1.087175607681 -0.223291456699 -v -0.165641307831 1.089258909225 -0.227088153362 -v -0.211334466934 1.109454154968 -0.224141299725 -v -0.196863412857 1.116337895393 -0.232053399086 -v -0.198950290680 1.117026805878 -0.234745264053 -v -0.180886983871 1.115268468857 -0.233694016933 -v -0.180615663528 1.115485668182 -0.236742198467 -v -0.177260398865 1.118756055832 -0.240124464035 -v -0.201287984848 1.117602467537 -0.238141715527 -v -0.282895326614 1.060189247131 -0.204914152622 -v -0.282418012619 1.057005047798 -0.194644689560 -v -0.277503967285 1.065804839134 -0.192061483860 -v -0.270702600479 1.064300417900 -0.181479215622 -v -0.276010751724 1.054841160774 -0.184064984322 -v -0.264964342117 1.078153371811 -0.180190920830 -v -0.254631042480 1.068855047226 -0.170619845390 -v -0.259245395660 1.057962894440 -0.174149036407 -v -0.248440742493 1.082378029823 -0.167859196663 -v -0.239177227020 1.074390888214 -0.160453259945 -v -0.243740320206 1.063062429428 -0.160507678986 -v -0.249438762665 1.055111646652 -0.162672996521 -v -0.241800546646 1.051291108131 -0.157198011875 -v -0.245920419693 1.046977758408 -0.160051584244 -v -0.247624635696 1.043250799179 -0.161501169205 -v -0.185623407364 1.163547277451 -0.191922187805 -v -0.178851366043 1.168696165085 -0.170140326023 -v -0.171039104462 1.162240505219 -0.197747766972 -v -0.167164564133 1.171891689301 -0.179815948009 -v -0.169514179230 1.153752446175 -0.212879836559 -v -0.163647174835 1.155890226364 -0.217210114002 -v -0.164894342422 1.163555622101 -0.203335464001 -v -0.162951707840 1.147874236107 -0.221974015236 -v -0.158002376556 1.151909351349 -0.223278760910 -v -0.154706716537 1.144289135933 -0.224242210388 -v -0.152066946030 1.148701906204 -0.224407970905 -v -0.146767616272 1.142306327820 -0.221583485603 -v -0.143728017807 1.146293640137 -0.221992492676 -v -0.138458013535 1.141785860062 -0.215267539024 -v -0.135710000992 1.144933223724 -0.215805530548 -v -0.130891323090 1.143802881241 -0.204370617867 -v -0.129570007324 1.146505594254 -0.206188857555 -v -0.125153064728 1.151684284210 -0.194277405739 -v -0.120690345764 1.156343221664 -0.196658849716 -v -0.123557567596 1.151302337646 -0.207581400871 -v -0.123983860016 1.158541202545 -0.182885527611 -v -0.120908975601 1.161676406860 -0.185635268688 -v -0.127824783325 1.167345404625 -0.175681769848 -v -0.122528076172 1.169641494751 -0.178976297379 -v -0.113455295563 1.165868759155 -0.187700688839 -v -0.108748197556 1.163328170776 -0.198548078537 -v -0.110469579697 1.173360347748 -0.185494899750 -v -0.091323852539 1.179773807526 -0.191483795643 -v -0.090184450150 1.176342606544 -0.194954812527 -v -0.111765384674 1.178711295128 -0.185415387154 -v -0.092939138412 1.184199452400 -0.190637469292 -v -0.113289833069 1.182440042496 -0.187966227531 -v -0.095153093338 1.187181711197 -0.191652655602 -v -0.073956251144 1.192005038261 -0.192678928375 -v -0.073637962341 1.188065290451 -0.191455483437 -v -0.099256277084 1.190625190735 -0.194961786270 -v -0.073813676834 1.195713639259 -0.195692181587 -v -0.096777915955 1.196445703506 -0.206112921238 -v -0.072917699814 1.198483467102 -0.200721621513 -v -0.095563650131 1.196424365044 -0.214924454689 -v -0.071158885956 1.198626756668 -0.206956505775 -v -0.129826784134 1.190738201141 -0.212317109108 -v -0.157343387604 1.172712326050 -0.208674550056 -v -0.128477811813 1.186428785324 -0.221658170223 -v -0.093955516815 1.193287849426 -0.221389353275 -v -0.154647350311 1.168583154678 -0.219737291336 -v -0.149827718735 1.162814021111 -0.225700199604 -v -0.124877214432 1.179793953896 -0.226911485195 -v -0.144460201263 1.156676888466 -0.227152824402 -v -0.120687484741 1.171841144562 -0.228286266327 -v -0.139381647110 1.150594115257 -0.223807334900 -v -0.117116689682 1.165078282356 -0.225237190723 -v -0.128769636154 1.149663209915 -0.217538893223 -v -0.111747980118 1.161472201347 -0.217855334282 -v -0.109767198563 1.161700129509 -0.209116935730 -v -0.088203907013 1.172519445419 -0.211088180542 -v -0.088263034821 1.173820972443 -0.218165874481 -v -0.089234113693 1.173993110657 -0.201246440411 -v -0.071101665497 1.179669737816 -0.199828505516 -v -0.069531917572 1.179702758789 -0.205872833729 -v -0.072219848633 1.181545853615 -0.195242881775 -v -0.056831598282 1.183016300201 -0.193188905716 -v -0.055566310883 1.181527018547 -0.196716129780 -v -0.073021411896 1.184370517731 -0.192374467850 -v -0.057552337646 1.185418963432 -0.190718352795 -v -0.057724237442 1.188611626625 -0.189705491066 -v -0.045343875885 1.186881065369 -0.185175061226 -v -0.045280933380 1.183866500854 -0.186353206635 -v -0.057383060455 1.192056655884 -0.190340936184 -v -0.044640541077 1.190080165863 -0.185317754745 -v -0.056554079056 1.195130228996 -0.192540347576 -v -0.043342113495 1.192810654640 -0.186669468880 -v -0.055220603943 1.197255134583 -0.196023941040 -v -0.053610086441 1.197649002075 -0.200031757355 -v -0.052100419998 1.196197032928 -0.203523576260 -v -0.069370269775 1.196292161942 -0.211897075176 -v -0.068021297455 1.192861676216 -0.214833736420 -v -0.050945520401 1.193327188492 -0.205915927887 -v -0.092361450195 1.188226699829 -0.224879384041 -v -0.090728044510 1.182599067688 -0.225352346897 -v -0.067334413528 1.188707113266 -0.215543806553 -v -0.089248895645 1.177467584610 -0.223018467426 -v -0.067439317703 1.184669256210 -0.214068412781 -v -0.068172216415 1.181514143944 -0.210815250874 -v -0.052105903625 1.183036804199 -0.204133033752 -v -0.050871849060 1.185964107513 -0.206329762936 -v -0.053818464279 1.181404590607 -0.200728774071 -v -0.041506052017 1.180616259575 -0.193893551826 -v -0.039731979370 1.182307600975 -0.196195423603 -v -0.043209075928 1.180416822433 -0.191138744354 -v -0.044537305832 1.181544065475 -0.188471496105 -v -0.031432151794 1.183127760887 -0.177642107010 -v -0.023880004883 1.179421424866 -0.182783424854 -v -0.023120403290 1.181398153305 -0.182788312435 -v -0.038379907608 1.185227513313 -0.197383880615 -v -0.021365642548 1.180629491806 -0.180217981339 -v -0.037654399872 1.188567876816 -0.197493553162 -v -0.037757396698 1.191774725914 -0.196288704872 -v -0.050418376923 1.189674615860 -0.206975281239 -v -0.158075809479 1.171878576279 -0.187048196793 -v -0.184828758240 1.181181192398 -0.133212804794 -v -0.183850765228 1.183899402618 -0.127866744995 -v -0.169936895370 1.187874436378 -0.131015658379 -v -0.160047531128 1.187471389771 -0.131462752819 -v -0.157574653625 1.192477464676 -0.129109740257 -v -0.170529127121 1.193306446075 -0.127960264683 -v -0.157630920410 1.193547725677 -0.127042472363 -v -0.168020248413 1.194449782372 -0.126551985741 -v -0.155678272247 1.197181582451 -0.117395758629 -v -0.168904304504 1.200421571732 -0.116072595119 -v -0.177747726440 1.199375391006 -0.109128236771 -v -0.186355590820 1.196253895760 -0.100548923016 -v -0.188017368317 1.190521001816 -0.119188547134 -v -0.194039821625 1.188312888145 -0.112169504166 -v -0.203054904938 1.179349541664 -0.106702864170 -v -0.192745685577 1.189022660255 -0.093927919865 -v -0.195131540298 1.185600280762 -0.119000375271 -v -0.185272932053 1.190236568451 -0.123825550079 -v -0.202980279922 1.177518606186 -0.111484885216 -v -0.206887245178 1.169745087624 -0.105333983898 -v -0.206416130066 1.174813270569 -0.101252019405 -v -0.199194669724 1.162851572037 -0.099504411221 -v -0.197700738907 1.180861234665 -0.091671824455 -v -0.150561571121 1.174575209618 -0.132039248943 -v -0.209591627121 1.058356404305 -0.160460770130 -v -0.217305183411 1.052603721619 -0.160649895668 -v -0.238281965256 1.033112168312 -0.170957684517 -v -0.244051933289 1.025660991669 -0.180232465267 -v -0.239808082581 1.032481074333 -0.169264376163 -v -0.232315063477 1.036808967590 -0.161297738552 -v -0.230905294418 1.037472367287 -0.163685441017 -v -0.225137472153 1.044082164764 -0.158028185368 -v -0.223443984985 1.044231295586 -0.160395681858 -v -0.223054885864 1.028931379318 -0.207141757011 -v -0.210240125656 1.094408273697 -0.117802858353 -v -0.226145267487 1.091406583786 -0.144528210163 -v -0.228773593903 1.093539595604 -0.144238770008 -v -0.229978561401 1.091392636299 -0.150956988335 -v -0.231330394745 1.094696521759 -0.150297284126 -v -0.228517770767 1.097494721413 -0.144955992699 -v -0.229495048523 1.099721908569 -0.131893873215 -v -0.229601860046 1.105694532394 -0.127975225449 -v -0.230824470520 1.112782955170 -0.126599431038 -v -0.231130123138 1.112404465675 -0.120916366577 -v -0.238191127777 1.121705651283 -0.135489940643 -v -0.240043640137 1.121748328209 -0.132544755936 -v -0.242587566376 1.117125391960 -0.144999742508 -v -0.246487855911 1.119711399078 -0.144290924072 -v -0.241481542587 1.113143205643 -0.153935611248 -v -0.245183229446 1.112014532089 -0.156490027905 -v -0.238260984421 1.105642080307 -0.157133936882 -v -0.240424156189 1.103380203247 -0.159065842628 -v -0.233463764191 1.100573539734 -0.154703736305 -v -0.235453605652 1.097964048386 -0.155216693878 -v -0.235904932022 1.095326662064 -0.155326545238 -v -0.230455398560 1.097877264023 -0.150153517723 -v -0.249421119690 1.121675491333 -0.144378840923 -v -0.240281105042 1.124884128571 -0.131052792072 -v -0.227780818939 1.113982677460 -0.117298245430 -v -0.130397796631 1.182343721390 -0.076600074768 -v -0.129862308502 1.183777570724 -0.072378516197 -v -0.136162042618 1.179548740387 -0.069244503975 -v -0.137062549591 1.183297991753 -0.068274199963 -v -0.133409261703 1.184647083282 -0.072437226772 -v -0.144817352295 1.180659770966 -0.065627694130 -v -0.142683744431 1.184700131416 -0.066475808620 -v -0.271175146103 1.039876699448 -0.190005302429 -v -0.301822423935 1.001146674156 -0.225157797337 -v 0.040446281433 1.266857385635 0.129650652409 -v 0.045840978622 1.267236709595 0.128639698029 -v 0.042178869247 1.272785186768 0.116086125374 -v 0.035976171494 1.262238383293 0.125946938992 -v -0.000801801682 1.292400956154 0.102130472660 -v -0.000761747360 1.303220987320 0.093628942966 -v 0.015448331833 1.314785122871 0.084255039692 -v 0.030528545380 1.315371155739 0.082960784435 -v 0.019721984863 1.301102638245 0.098109424114 -v 0.034617424011 1.303159475327 0.095117151737 -v -0.001373052597 1.277826786041 0.111266195774 -v -0.001722097397 1.284371614456 0.109198451042 -v 0.011536121368 1.282118082047 0.111050844193 -v 0.009827852249 1.276010155678 0.111163258553 -v 0.008899927139 1.272522568703 0.108775258064 -v 0.007982730865 1.269812107086 0.108590006828 -v -0.013120889664 1.280258178711 0.103836178780 -v -0.013952493668 1.287459611893 0.096029043198 -v -0.010375499725 1.274148821831 0.106453537941 -v -0.007061481476 1.270083665848 0.105696380138 -v 0.000071287155 1.273618578911 0.108782231808 -v -0.005353450775 1.267195701599 0.105669260025 -v -0.003715276718 1.265943884850 0.104040384293 -v -0.004131793976 1.253381729126 0.104748189449 -v -0.003669261932 1.256071329117 0.105417490005 -v -0.002878904343 1.257432699203 0.105259358883 -v -0.013543844223 1.267071247101 0.099097788334 -v -0.009968519211 1.265434265137 0.100078165531 -v -0.008393764496 1.263895630836 0.101276814938 -v -0.006794929504 1.262893676758 0.101056635380 -v -0.010854721069 1.252157211304 0.098580598831 -v -0.008997440338 1.255574226379 0.100211143494 -v -0.010912179947 1.258270978928 0.096816718578 -v -0.011093616486 1.261292099953 0.096696496010 -v -0.007898807526 1.257424354553 0.101626813412 -v -0.009550809860 1.259004950523 0.098516225815 -v -0.009840488434 1.260907649994 0.098658919334 -v -0.006556272507 1.258249044418 0.101993978024 -v -0.008103132248 1.259290218353 0.099143624306 -v -0.008106708527 1.260651588440 0.098746120930 -v 0.000634908676 1.269962787628 0.108458042145 -v 0.001318454742 1.268399953842 0.106259763241 -v 0.007476329803 1.268658280373 0.106844902039 -v 0.003443002701 1.252889513969 0.108284533024 -v 0.002853155136 1.255975246429 0.108673334122 -v 0.002923965454 1.257455945015 0.107795357704 -v 0.011467933655 1.255045294762 0.108669996262 -v 0.009955406189 1.257626056671 0.108927190304 -v 0.009441614151 1.258421897888 0.107399821281 -v 0.014464855194 1.289756536484 0.104732036591 -v 0.025943517685 1.283508300781 0.107297778130 -v 0.039303779602 1.279110550880 0.106710374355 -v 0.036115169525 1.278290748596 0.107457518578 -v 0.042536735535 1.278733968735 0.105807304382 -v 0.030768871307 1.288198709488 0.104064941406 -v 0.037350654602 1.289890766144 0.102047562599 -v 0.032482862473 1.275633811951 0.108351588249 -v 0.028729915619 1.263514757156 0.113653242588 -v 0.018857955933 1.271643638611 0.108702600002 -v 0.016063928604 1.269024133682 0.106653332710 -v 0.028270483017 1.270699024200 0.108028233051 -v 0.022220373154 1.277044057846 0.110479056835 -v 0.019372463226 1.258092880249 0.110031247139 -v 0.023556232452 1.262869477272 0.107618689537 -v 0.035057067871 1.268901348114 0.115687489510 -v 0.039037466049 1.272062182426 0.116605579853 -v 0.014039754868 1.267450094223 0.106931269169 -v 0.012716054916 1.266707539558 0.106147646904 -v 0.017132282257 1.259011745453 0.106750369072 -v 0.020047903061 1.262408375740 0.104903697968 -v 0.019694805145 1.265416860580 0.105079472065 -v 0.017275571823 1.264821529388 0.105033516884 -v 0.017734289169 1.262517094612 0.104454278946 -v 0.015003919601 1.260491371155 0.107061386108 -v 0.015677213669 1.264597892761 0.104555845261 -v 0.016396999359 1.262519359589 0.103408336639 -v 0.014380216599 1.260196924210 0.104527294636 -v 0.023535966873 1.267078399658 0.106167256832 -v -0.012151002884 1.235135316849 0.109545886517 -v -0.016305923462 1.224170684814 0.110445380211 -v -0.010377168655 1.200674295425 0.124419331551 -v -0.006423950195 1.185832023621 0.138172209263 -v -0.010899543762 1.192893743515 0.129531621933 -v -0.017629623413 1.210340738297 0.107257723808 -v -0.026541233063 1.185374736786 0.118990361691 -v -0.022340297699 1.197549104691 0.109548330307 -v 0.035350084305 1.248472332954 0.142883300781 -v 0.051932334900 1.253603696823 0.148347139359 -v 0.041118383408 1.258031487465 0.142182707787 -v 0.049641847610 1.260149955750 0.141103088856 -v 0.044825792313 1.252733945847 0.148908674717 -v 0.042319774628 1.246564269066 0.148949384689 -v 0.041991710663 1.241669535637 0.144866228104 -v 0.052286386490 1.246867418289 0.148005247116 -v 0.051711082458 1.241842269897 0.144327402115 -v 0.035593986511 1.255735874176 0.134251892567 -v 0.029677391052 1.244845509529 0.136716425419 -v 0.033319473267 1.250971555710 0.137745916843 -v 0.031243801117 1.242845058441 0.136967241764 -v 0.030688762665 1.256210803986 0.122289538383 -v 0.030338525772 1.250825643539 0.129136621952 -v 0.028740406036 1.247478961945 0.134274959564 -v 0.033815860748 1.242522120476 0.134662628174 -v 0.036343336105 1.243577361107 0.131516873837 -v 0.035639047623 1.243583917618 0.141259193420 -v 0.038025856018 1.243572592735 0.136724710464 -v 0.038744688034 1.229243755341 0.136170148849 -v 0.024222373962 1.241967678070 0.129807054996 -v 0.026626348495 1.240379929543 0.132212758064 -v 0.025287628174 1.233862161636 0.128705739975 -v 0.029455423355 1.240218400955 0.133426547050 -v 0.032053232193 1.237096786499 0.129116058350 -v 0.032113552094 1.241108894348 0.132747650146 -v 0.035292625427 1.241956233978 0.129371285439 -v 0.030912876129 1.229870319366 0.131015717983 -v 0.030648946762 1.224499464035 0.134449362755 -v 0.044306993484 1.238245844841 0.135809302330 -v 0.043252468109 1.240461349487 0.139098584652 -v 0.042135715485 1.240919113159 0.133995532990 -v 0.041716814041 1.241783857346 0.135482788086 -v 0.039429187775 1.243738889694 0.133056044579 -v 0.050420999527 1.240142822266 0.139068543911 -v 0.044756889343 1.234812498093 0.136098802090 -v 0.045078516006 1.231711387634 0.137417495251 -v 0.049524068832 1.238426923752 0.135339796543 -v 0.049675464630 1.235311508179 0.135039925575 -v 0.049990892410 1.232141256332 0.135455429554 -v 0.050583839417 1.228020906448 0.136361002922 -v 0.039813756943 1.238145470619 0.129698514938 -v 0.039825677872 1.242085576057 0.130345582962 -v 0.038737535477 1.233376264572 0.133297681808 -v 0.021462440491 1.217258930206 0.132264912128 -v 0.022056579590 1.212752580643 0.133517026901 -v 0.018235683441 1.205214858055 0.139099240303 -v 0.020352602005 1.209083795547 0.136137485504 -v 0.026568651199 1.202765941620 0.148095548153 -v 0.023966073990 1.192803263664 0.152344107628 -v 0.016592502594 1.199261784554 0.141214609146 -v 0.012834787369 1.191551685333 0.144409120083 -v 0.037743806839 1.215576529503 0.149055123329 -v 0.045881509781 1.225828409195 0.145537972450 -v 0.052435159683 1.227740526199 0.144624948502 -v 0.046445846558 1.218936204910 0.150274634361 -v 0.053923368454 1.220834851265 0.149113297462 -v 0.037250757217 1.206232309341 0.152749001980 -v 0.035874843597 1.194463729858 0.157640993595 -v 0.046791553497 1.196104288101 0.159853577614 -v 0.056510210037 1.197567701340 0.158931136131 -v 0.046874284744 1.208952426910 0.154512763023 -v 0.055248498917 1.210875630379 0.153577446938 -v 0.029203891754 1.216282963753 0.141427814960 -v 0.038281440735 1.222136378288 0.144550740719 -v 0.039469957352 1.224807739258 0.138187825680 -v 0.027691841125 1.210708260536 0.145226716995 -v 0.031136751175 1.219664812088 0.136600375175 -v 0.045809268951 1.227646589279 0.138405919075 -v 0.014129638672 1.249409794807 0.115332782269 -v 0.012882471085 1.252357363701 0.110826134682 -v 0.003088235855 1.244774341583 0.113203525543 -v 0.015806198120 1.243852615356 0.119367957115 -v 0.002343654633 1.237422823906 0.117558121681 -v 0.001748561859 1.226236939430 0.122058868408 -v 0.018728971481 1.236750602722 0.120574116707 -v 0.013330936432 1.222983598709 0.124980926514 -v 0.020515918732 1.223115921021 0.129145741463 -v -0.008113384247 1.243763685226 0.107061862946 -v -0.005330562592 1.249330997467 0.104984104633 -v 0.003616333008 1.249160528183 0.109515726566 -v 0.024304866791 1.250104308128 0.120198249817 -v 0.023406744003 1.245513081551 0.126008749008 -v 0.022205352783 1.255663037300 0.115017294884 -v 0.022286176682 1.233654975891 0.123781740665 -v 0.005661487579 1.202055335045 0.129107356071 -v -0.006587982178 1.211276650429 0.122517585754 -v 0.004577875137 1.210666298866 0.126435041428 -v 0.000176429749 1.201238393784 0.127685189247 -v 0.010596990585 1.210288167000 0.128963351250 -v 0.011595726013 1.201239705086 0.133424997330 -v 0.008545637131 1.200110793114 0.130007266998 -v 0.008605241776 1.202653884888 0.129701614380 -v 0.013861179352 1.203346967697 0.131477773190 -v 0.010287761688 1.201593160629 0.130020737648 -v 0.010378360748 1.202918767929 0.129963099957 -v 0.013339757919 1.208619117737 0.130371451378 -v 0.014328479767 1.206321358681 0.130973219872 -v 0.004492282867 1.192520976067 0.136268198490 -v 0.005780458450 1.198042392731 0.130144894123 -v 0.000226497650 1.195833086967 0.130556583405 -v 0.009120702744 1.197683811188 0.134836256504 -v -0.030488014221 1.283267021179 0.061819374561 -v -0.020040273666 1.274581432343 0.086394488811 -v -0.024308919907 1.279701232910 0.074724912643 -v -0.023217916489 1.261051177979 0.081465482712 -v -0.028754949570 1.261417388916 0.070602059364 -v -0.036482095718 1.283128738403 0.047661483288 -v -0.035109758377 1.260555624962 0.058661758900 -v -0.041009902954 1.257912158966 0.046594083309 -v -0.021064043045 1.302900314331 0.072026371956 -v -0.003322601318 1.312586545944 0.080484449863 -v -0.016522645950 1.296046495438 0.085470199585 -v -0.025208473206 1.303212285042 0.054149925709 -v -0.007358551025 1.313477158546 0.060375809669 -v 0.010043859482 1.317523241043 0.063381493092 -v 0.024682044983 1.319341421127 0.062246799469 -v -0.017404079437 1.270059585571 0.095172524452 -v -0.018391847610 1.253546833992 0.091046571732 -v -0.013947963715 1.256553530693 0.094790697098 -v -0.014717340469 1.261037349701 0.094909310341 -v -0.018908500671 1.260896086693 0.090010643005 -v -0.020776271820 1.238931417465 0.095742464066 -v -0.023503780365 1.249016761780 0.084496319294 -v -0.025747776031 1.229195833206 0.091487228870 -v -0.028454780579 1.243663668633 0.075471043587 -v -0.028841972351 1.217222690582 0.085641384125 -v -0.036760330200 1.200345516205 0.081055641174 -v -0.043103218079 1.175856351852 0.098108768463 -v -0.034443616867 1.237311244011 0.066220164299 -v -0.040151596069 1.230180382729 0.055966675282 -v -0.047009706497 1.225324869156 0.042491793633 -v -0.047743082047 1.194535493851 0.058303952217 -v -0.054014205933 1.190686464310 0.040780961514 -v -0.015044689178 1.246884107590 0.097714483738 -v 0.051012039185 1.267523407936 0.126842677593 -v 0.053725004196 1.263754844666 0.121200740337 -v 0.044191360474 1.316711425781 0.076770126820 -v 0.049160242081 1.303004741669 0.090367913246 -v 0.070050954819 1.296021223068 0.083691716194 -v 0.064377546310 1.307411193848 0.076644003391 -v 0.044227600098 1.289105176926 0.100519239902 -v 0.046434164047 1.276561975479 0.104707181454 -v 0.050604581833 1.285138130188 0.100853264332 -v 0.058474540710 1.292474508286 0.093251526356 -v 0.065127134323 1.284862875938 0.097177326679 -v 0.048618316650 1.269841313362 0.112119197845 -v 0.045237541199 1.272487878799 0.114981353283 -v 0.053706645966 1.265324115753 0.107027411461 -v 0.050548315048 1.272162795067 0.102230787277 -v 0.056096792221 1.279160976410 0.101499915123 -v 0.055377244949 1.264985799789 0.099373936653 -v 0.058884382248 1.273606300354 0.098348557949 -v 0.060819864273 1.270249724388 0.095299720764 -v 0.067456960678 1.278015136719 0.096721053123 -v 0.067724943161 1.273309826851 0.094431757927 -v 0.068783521652 1.270277500153 0.094106316566 -v 0.060762882233 1.261790990829 0.099568009377 -v 0.054175376892 1.268918275833 0.098160982132 -v 0.062816143036 1.268297910690 0.094869017601 -v 0.063694953918 1.267551422119 0.093782484531 -v 0.068581581116 1.269197702408 0.092460989952 -v 0.061268568039 1.263207793236 0.095967531204 -v 0.057333707809 1.264688968658 0.095514893532 -v 0.057271957397 1.267230391502 0.095370531082 -v 0.059454441071 1.266519188881 0.094323635101 -v 0.059153795242 1.264902830124 0.094141185284 -v 0.062749862671 1.265080451965 0.095315635204 -v 0.060599803925 1.266317009926 0.093307375908 -v 0.059796094894 1.264950871468 0.092611730099 -v 0.062308549881 1.264286756516 0.092826724052 -v 0.067521333694 1.262562036514 0.095242917538 -v 0.068541765213 1.265034556389 0.094969451427 -v 0.068204641342 1.265207529068 0.093506395817 -v 0.077112913132 1.279425144196 0.091373026371 -v 0.075383424759 1.286835432053 0.089299082756 -v 0.082441329956 1.283947467804 0.079257071018 -v 0.078902959824 1.292372465134 0.071949005127 -v 0.075701475143 1.271097064018 0.090313911438 -v 0.074272155762 1.269963860512 0.088880062103 -v 0.080384016037 1.272943258286 0.083734631538 -v 0.075593948364 1.274363636971 0.090127468109 -v 0.079707145691 1.270199537277 0.084501504898 -v 0.077773094177 1.269171714783 0.084009110928 -v 0.074470520020 1.262153863907 0.091184914112 -v 0.074804306030 1.264805197716 0.091423273087 -v 0.074141263962 1.265561819077 0.090759217739 -v 0.079296112061 1.262190818787 0.084158301353 -v 0.078951358795 1.264721870422 0.085185348988 -v 0.078058242798 1.265552878380 0.085563898087 -v 0.080155134201 1.268244743347 0.078729867935 -v 0.078858852386 1.267360806465 0.079410076141 -v 0.080429077148 1.264863848686 0.079188346863 -v 0.080001354218 1.264985084534 0.075401127338 -v 0.080117464066 1.266297817230 0.075324594975 -v 0.079468488693 1.265514373779 0.080408871174 -v 0.079141855240 1.265153050423 0.076866209507 -v 0.078771829605 1.266029000282 0.076456785202 -v 0.082354784012 1.277361154556 0.082759082317 -v 0.082641601563 1.272576570511 0.074128508568 -v 0.080540895462 1.270089030266 0.076882600784 -v 0.081943511963 1.258766055107 0.074625015259 -v 0.080802440643 1.262812852859 0.077187001705 -v 0.080394029617 1.264332532883 0.073039591312 -v 0.080169439316 1.266933917999 0.072909772396 -v 0.057654857635 1.259309649467 0.137847244740 -v 0.058503150940 1.253966927528 0.145442008972 -v 0.064238071442 1.251279354095 0.135221183300 -v 0.061223030090 1.248335599899 0.143793106079 -v 0.060226678848 1.243742227554 0.139886677265 -v 0.058931112289 1.258131980896 0.127938270569 -v 0.063202142715 1.254297494888 0.129694104195 -v 0.065549135208 1.247506380081 0.127456486225 -v 0.057339906693 1.259414553642 0.114988744259 -v 0.062293052673 1.246687650681 0.126744151115 -v 0.058286666870 1.246920347214 0.125443816185 -v 0.066583871841 1.249766945839 0.126530528069 -v 0.061671018600 1.255462884903 0.120306611061 -v 0.065866470337 1.252713918686 0.123935759068 -v 0.054228067398 1.239598989487 0.133096814156 -v 0.056482315063 1.242153167725 0.135511994362 -v 0.054856777191 1.242565155029 0.130528688431 -v 0.055840969086 1.243560433388 0.131651639938 -v 0.056303262711 1.246041178703 0.128419876099 -v 0.063732147217 1.246660113335 0.133645892143 -v 0.059375524521 1.246311187744 0.130905628204 -v 0.054415225983 1.236288070679 0.133475065231 -v 0.055111885071 1.233415126801 0.134682297707 -v 0.059905767441 1.232897996902 0.130329132080 -v 0.055068492889 1.240468859673 0.125481486320 -v 0.054852485657 1.244311332703 0.126182913780 -v 0.061526775360 1.241811394691 0.120923161507 -v 0.062999248505 1.245989322662 0.124036252499 -v 0.058302879333 1.245635032654 0.122877240181 -v 0.058226346970 1.236359000206 0.127980589867 -v 0.068130016327 1.248301506042 0.117564380169 -v 0.067496299744 1.246428251266 0.120817005634 -v 0.067075014114 1.240431427956 0.117183685303 -v 0.065690279007 1.245734214783 0.123227000237 -v 0.063593864441 1.235562324524 0.122017323971 -v 0.065532922745 1.231557369232 0.124712467194 -v 0.058642148972 1.228264093399 0.141964733601 -v 0.060995340347 1.221785545349 0.146217465401 -v 0.067803859711 1.221554160118 0.140724539757 -v 0.065596818924 1.198537349701 0.155037641525 -v 0.063088893890 1.211889743805 0.150147914886 -v 0.070540428162 1.212059378624 0.143783211708 -v 0.074363708496 1.199054241180 0.147871077061 -v 0.055469512939 1.229463577271 0.135724365711 -v 0.064706325531 1.227428913116 0.137217521667 -v 0.060773849487 1.229086875916 0.132322847843 -v 0.070334196091 1.226015686989 0.129881024361 -v 0.073707818985 1.221224188805 0.132331371307 -v 0.066503286362 1.228003025055 0.126726925373 -v 0.071586132050 1.228841543198 0.118208587170 -v 0.071873664856 1.225707650185 0.119430422783 -v 0.077915668488 1.220404744148 0.122084975243 -v 0.074536085129 1.223444819450 0.120662927628 -v 0.076755285263 1.212785243988 0.134442687035 -v 0.081811666489 1.200371980667 0.137430131435 -v 0.080988883972 1.214165449142 0.123166322708 -v 0.086687803268 1.203819513321 0.124526441097 -v 0.062492609024 1.254801988602 0.109791696072 -v 0.066610813141 1.251634597778 0.113950848579 -v 0.061021566391 1.259107947350 0.104773223400 -v 0.068827152252 1.254087090492 0.101265370846 -v 0.067484378815 1.258732795715 0.097137033939 -v 0.069918870926 1.248601675034 0.105034232140 -v 0.067322969437 1.240279912949 0.111719012260 -v 0.068537473679 1.242500543594 0.107286572456 -v 0.075018405914 1.232970237732 0.108255088329 -v 0.070877790451 1.232767581940 0.115252256393 -v 0.077867746353 1.249896764755 0.094340682030 -v 0.081087350845 1.242408514023 0.097182273865 -v 0.083758115768 1.234669685364 0.100204110146 -v 0.075211763382 1.256941318512 0.091831862926 -v 0.080814123154 1.256867170334 0.083383440971 -v 0.084712028503 1.249413847923 0.083412945271 -v 0.090125322342 1.240862131119 0.083279728889 -v 0.094750881195 1.231421947479 0.081762373447 -v 0.077249050140 1.224474191666 0.112283647060 -v 0.076828718185 1.222699880600 0.113141000271 -v 0.078745365143 1.225707769394 0.109818100929 -v 0.080643415451 1.218926310539 0.113611519337 -v 0.081604242325 1.218360304832 0.109059333801 -v 0.081132650375 1.220607519150 0.109011828899 -v 0.077664852142 1.220381379128 0.113147377968 -v 0.080033540726 1.219517707825 0.110023081303 -v 0.079794406891 1.220654487610 0.110094487667 -v 0.083391666412 1.220073938370 0.107060670853 -v 0.082854270935 1.225638270378 0.104710161686 -v 0.087911605835 1.218507766724 0.103260695934 -v 0.091594696045 1.224019408226 0.096191704273 -v 0.096889257431 1.214898347855 0.095897138119 -v 0.083808422089 1.215420007706 0.113558650017 -v 0.089332103729 1.208635091782 0.112731575966 -v 0.084277868271 1.216469287872 0.107762217522 -v 0.089827299118 1.213289976120 0.105555117130 -v 0.101368904114 1.198026537895 0.110524892807 -v 0.100582122803 1.206828474998 0.100248575211 -v 0.095614671707 1.219149708748 0.078378736973 -v 0.110302448273 1.196131229401 0.085673749447 -v 0.101401090622 1.207566261292 0.078618407249 -v 0.038086652756 1.319437146187 0.056139290333 -v 0.058758258820 1.316738009453 0.064338445663 -v 0.052024126053 1.317465305328 0.045089304447 -v 0.071031332016 1.309057235718 0.048146665096 -v 0.074790716171 1.301920175552 0.061692059040 -v 0.065555095673 1.309342384338 0.030936956406 -v 0.076519966125 1.290452003479 0.034301042557 -v 0.081107854843 1.281051397324 0.059998869896 -v 0.083610057831 1.276207208633 0.068830192089 -v 0.084535121918 1.260300159454 0.064144432545 -v 0.082194328308 1.262906312943 0.069637179375 -v 0.082393407822 1.267321228981 0.069480359554 -v 0.083597660065 1.267654538155 0.063186764717 -v 0.078208923340 1.286485910416 0.048090279102 -v 0.083045482635 1.268104314804 0.053750872612 -v 0.082231521606 1.268839240074 0.041879594326 -v 0.074455499649 1.290663003922 0.019667565823 -v 0.081685543060 1.268450379372 0.028919160366 -v 0.080770254135 1.266295671463 0.016477346420 -v 0.085688114166 1.253255128860 0.071567714214 -v 0.090450763702 1.245868682861 0.066874861717 -v 0.086171150208 1.256250977516 0.055930197239 -v 0.086350440979 1.251328825951 0.045859992504 -v 0.093620538712 1.236952662468 0.060706198215 -v 0.094166755676 1.225640654564 0.054646670818 -v 0.099492788315 1.210208415985 0.048777282238 -v 0.114588975906 1.187431573868 0.062622427940 -v 0.087287187576 1.245572805405 0.035482227802 -v 0.087604761124 1.239173889160 0.025138556957 -v 0.087361097336 1.235268592834 0.012534439564 -v 0.098117351532 1.205789446831 0.027765154839 -v 0.095893383026 1.203208208084 0.014717459679 -v -0.011510133743 1.163360238075 0.149067997932 -v -0.004560947418 1.134804606438 0.155196785927 -v -0.023927450180 1.173175573349 0.133506655693 -v -0.025471687317 1.141367435455 0.137405753136 -v 0.017634153366 1.178678154945 0.157647490501 -v 0.025628328323 1.157846570015 0.168135166168 -v 0.003703117371 1.180795431137 0.148849606514 -v 0.006724596024 1.158563613892 0.161044716835 -v 0.032204389572 1.178767085075 0.163424730301 -v 0.045523643494 1.179651737213 0.165940761566 -v 0.057294130325 1.180637598038 0.164849698544 -v 0.042539596558 1.158673048019 0.171049177647 -v 0.056924104691 1.159794092178 0.170381605625 -v 0.017149686813 1.133303642273 0.166976332664 -v 0.037201642990 1.133634090424 0.172211468220 -v 0.054214477539 1.134839653969 0.171566545963 -v -0.010805606842 1.115299701691 0.134994447231 -v -0.012533187866 1.105522513390 0.110044121742 -v 0.010537385941 1.112756729126 0.149111986160 -v 0.047211885452 1.112629652023 0.157582700253 -v 0.030074119568 1.112287878990 0.156457722187 -v 0.006142139435 1.103373646736 0.121430158615 -v 0.022053003311 1.103733062744 0.127525568008 -v 0.036193370819 1.104734897614 0.128820121288 -v -0.040673494339 1.155994772911 0.117093861103 -v -0.049955368042 1.141332268715 0.095714688301 -v -0.032525300980 1.123396158218 0.116316258907 -v -0.032552003860 1.114442110062 0.094371557236 -v -0.031067371368 1.110062003136 0.075444519520 -v -0.052037954330 1.167015790939 0.075356423855 -v -0.056231737137 1.161347627640 0.056636929512 -v -0.059476852417 1.156821727753 0.039392709732 -v -0.059850692749 1.140776157379 0.039435088634 -v -0.061575651169 1.141006946564 0.028368413448 -v -0.050864934921 1.133266210556 0.076295912266 -v -0.056070089340 1.117838740349 0.039700746536 -v -0.049790382385 1.128654956818 0.061231255531 -v -0.052109718323 1.122534751892 0.050932705402 -v -0.034054994583 1.104509353638 0.060616970062 -v -0.043396234512 1.096928238869 0.048614859581 -v -0.048959255219 1.091627120972 0.033554553986 -v -0.056957721710 1.112890362740 0.023788034916 -v -0.035567522049 1.043387889862 0.047449171543 -v -0.039433956146 1.039121747017 0.052413821220 -v -0.064744234085 1.050780534744 0.014951646328 -v -0.038980245590 1.074284434319 0.043637633324 -v -0.041082859039 1.069077014923 0.029278635979 -v -0.034406661987 1.055065155029 0.043360531330 -v -0.047071218491 1.085974812508 0.015686988831 -v -0.049998521805 1.061222076416 0.019102632999 -v -0.053887367249 1.043840646744 0.036689996719 -v -0.042478322983 1.050164461136 0.036054790020 -v -0.014271974564 1.099223375320 0.086969316006 -v 0.000830411911 1.094314455986 0.095309138298 -v -0.019607543945 1.090406298637 0.068407773972 -v -0.029613494873 1.080608129501 0.054361045361 -v -0.005763530731 1.081238627434 0.073860049248 -v -0.027546405792 1.059183478355 0.053171813488 -v -0.013939142227 1.067626953125 0.057299792767 -v 0.014307975769 1.093263268471 0.099898755550 -v 0.027014970779 1.094081640244 0.101382076740 -v 0.021053075790 1.074604153633 0.082123875618 -v 0.007202863693 1.075435996056 0.078675389290 -v -0.027371644974 1.043602824211 0.054658472538 -v -0.017439126968 1.044979572296 0.062561631203 -v -0.024429798126 1.035316348076 0.064470529556 -v -0.010132312775 1.032010316849 0.071531534195 -v 0.004372358322 1.030398845673 0.073763489723 -v 0.017338514328 1.031093001366 0.076553463936 -v 0.000297546387 1.051457285881 0.063539087772 -v 0.017464637756 1.050814867020 0.071853816509 -v 0.068420410156 1.181527853012 0.160425603390 -v 0.079635143280 1.182518243790 0.152125537395 -v 0.070542097092 1.160900115967 0.164953768253 -v 0.085201978683 1.162357091904 0.154878497124 -v 0.090045928955 1.184562206268 0.140001475811 -v 0.098061561584 1.189689755440 0.125387966633 -v 0.099827289581 1.165438413620 0.139908611774 -v 0.070614814758 1.136290311813 0.165854871273 -v 0.088030338287 1.138740301132 0.153091609478 -v 0.104446411133 1.143034815788 0.133147954941 -v 0.097229003906 1.124236106873 0.117044687271 -v 0.083167791367 1.114722371101 0.099347352982 -v 0.111231565475 1.172423601151 0.120619416237 -v 0.114904880524 1.183718919754 0.100513756275 -v 0.116925716400 1.151993751526 0.107569992542 -v 0.063422679901 1.115132212639 0.151529729366 -v 0.080619335175 1.118611931801 0.138225674629 -v 0.050387620926 1.106717824936 0.125205457211 -v 0.066112041473 1.109486579895 0.115795731544 -v 0.086173295975 1.122708439827 0.068399488926 -v 0.080250263214 1.118033289909 0.063007235527 -v 0.082655668259 1.112149238586 0.061163365841 -v 0.121577978134 1.167878985405 0.081856548786 -v 0.119044303894 1.154315471649 0.063807129860 -v 0.111441612244 1.134985923767 0.090731918812 -v 0.098887205124 1.126488447189 0.077325224876 -v 0.111427545547 1.179712891579 0.043127000332 -v 0.106110334396 1.175122380257 0.031305313110 -v 0.102075576782 1.172155618668 0.024685502052 -v 0.102116584778 1.157317161560 0.033418297768 -v 0.101032018661 1.158340215683 0.029302597046 -v 0.100531339645 1.143308043480 0.048263728619 -v 0.097441434860 1.138330459595 0.048066020012 -v 0.109502553940 1.146957397461 0.052747786045 -v 0.096754789352 1.134839057922 0.047012090683 -v 0.085198402405 1.107511401176 0.055232167244 -v 0.094857692719 1.130478262901 0.041637301445 -v 0.040197134018 1.096347808838 0.099944472313 -v 0.054687500000 1.100618243217 0.094639301300 -v 0.048788309097 1.088074207306 0.078770637512 -v 0.035143613815 1.078818082809 0.081493318081 -v 0.048858642578 1.075313687325 0.068564772606 -v 0.070461988449 1.108810186386 0.084021329880 -v 0.064486742020 1.100866556168 0.073438167572 -v 0.065836668015 1.092562913895 0.068579912186 -v 0.060715675354 1.069221019745 0.070371031761 -v 0.030231714249 1.033327579498 0.078828334808 -v 0.035176753998 1.055608034134 0.070235610008 -v 0.043811559677 1.038117885590 0.082073748112 -v 0.050953388214 1.052722811699 0.075931191444 -v 0.063144207001 1.053842663765 0.072386682034 -v 0.073226213455 1.055658340454 0.068940043449 -v 0.075714349747 1.052077531815 0.075281441212 -v 0.058623790741 1.044714212418 0.080729842186 -v 0.072857141495 1.087235689163 0.064580619335 -v 0.071193933487 1.066993713379 0.064158737659 -v 0.079437494278 1.082699298859 0.053134381771 -v 0.086660146713 1.101273775101 0.041690945625 -v 0.092396974564 1.077137112617 0.048476576805 -v 0.108497619629 1.069890260696 0.052235901356 -v 0.082067012787 1.064140319824 0.061126887798 -v 0.093047380447 1.060159802437 0.067036211491 -v -0.040343284607 1.237436652184 -0.032936990261 -v -0.052459239960 1.221552133560 0.028179645538 -v -0.056158065796 1.218947887421 0.012705385685 -v -0.055384397507 1.217468619347 -0.008952379227 -v -0.058702945709 1.188291907310 0.024425923824 -v -0.061626672745 1.162003040314 0.018809258938 -v -0.061149597168 1.186267733574 0.006660997868 -v -0.059507608414 1.179691553116 -0.010669171810 -v -0.055477380753 1.198352456093 -0.021095275879 -v -0.052834749222 1.169609308243 -0.030598759651 -v -0.042055368423 1.195482850075 -0.042439877987 -v -0.019744396210 1.243911266327 -0.053574860096 -v 0.005693435669 1.249059438705 -0.062779784203 -v -0.040396451950 1.167162179947 -0.069658398628 -v -0.015247583389 1.206512212753 -0.057519495487 -v 0.014311552048 1.212281465530 -0.062326133251 -v -0.013623714447 1.176701664925 -0.078638434410 -v 0.025074958801 1.182491421700 -0.078897595406 -v 0.055553436279 1.246190905571 -0.042324364185 -v 0.072591066360 1.207378625870 -0.039697229862 -v 0.085914134979 1.232458949089 0.001026153564 -v 0.083698034286 1.230814695358 -0.009619951248 -v 0.077988386154 1.229747176170 -0.023236691952 -v 0.094089031219 1.202184319496 0.005038857460 -v 0.098302841187 1.178545475006 0.013474762440 -v 0.091052532196 1.195588827133 -0.011169850826 -v 0.092413902283 1.201389551163 -0.004166901112 -v 0.082178831100 1.212141036987 -0.025714099407 -v 0.089784622192 1.185250520706 -0.019735872746 -v 0.032395839691 1.248675107956 -0.057501971722 -v 0.044507265091 1.212738394737 -0.056064784527 -v 0.063519954681 1.185031294823 -0.068458735943 -v 0.090191364288 1.181271433830 -0.050654113293 -v -0.059590101242 1.158144712448 0.001819372177 -v -0.060241460800 1.136449337006 0.012746274471 -v -0.055771827698 1.128415822983 -0.007795572281 -v -0.056196689606 1.149477005005 -0.018423438072 -v -0.059613704681 1.094871759415 -0.017021775246 -v -0.052507877350 1.106217026711 0.003190934658 -v -0.061356782913 1.135336041451 -0.044591844082 -v -0.055210590363 1.152688622475 -0.057234942913 -v -0.061703920364 1.115628957748 -0.031736850739 -v -0.076354265213 1.118670940399 -0.068626523018 -v -0.078945398331 1.100923299789 -0.053504228592 -v -0.072272777557 1.063135385513 -0.010518550873 -v -0.077728748322 1.081091284752 -0.034207820892 -v -0.055848836899 1.076079010963 0.000701248646 -v -0.070124626160 1.134061932564 -0.082705259323 -v -0.052391529083 1.145668983459 -0.097816407681 -v -0.014596939087 1.152688741684 -0.108650863171 -v 0.038563251495 1.158075928688 -0.105544686317 -v 0.095056056976 1.175324201584 0.007279813290 -v 0.097741365433 1.154363512993 0.024574756622 -v 0.096329450607 1.145889043808 0.014402627945 -v 0.095551252365 1.166598796844 -0.001544177532 -v 0.092842340469 1.122950792313 0.029080450535 -v 0.106817960739 1.113699555397 0.016706228256 -v 0.110495090485 1.154946565628 -0.013335943222 -v 0.104727029800 1.170523405075 -0.031004786491 -v 0.110179185867 1.135258436203 0.001379370689 -v 0.134946107864 1.143305301666 -0.026512145996 -v 0.134920597076 1.125534772873 -0.009499669075 -v 0.100990295410 1.093693971634 0.033296287060 -v 0.121155023575 1.084573626518 0.031806349754 -v 0.130618572235 1.104586720467 0.010483145714 -v 0.088234901428 1.164701461792 -0.088147342205 -v 0.131562232971 1.157645463943 -0.042793512344 -v 0.118981122971 1.165749549866 -0.063742041588 -v 0.061493158340 1.307609081268 0.082881748676 -v 0.060327529907 1.318495154381 0.079182028770 -v 0.072385311127 1.317370176315 0.066087126732 -v 0.075205326080 1.306590318680 0.068933367729 -v 0.076874732971 1.311258077621 0.048126757145 -v 0.079223632813 1.301067113876 0.051980793476 -v 0.079833984375 1.300073146820 0.031079173088 -v 0.080294847488 1.289757966995 0.038935780525 -v 0.084419488907 1.282017230988 0.020341932774 -v 0.084472656250 1.274614810944 0.031600832939 -v 0.089787960052 1.257214426994 0.028529644012 -v 0.093410491943 1.257125258446 0.016011953354 -v 0.093643188477 1.237569332123 0.028812587261 -v 0.099745988846 1.236010193825 0.015180408955 -v 0.101211547852 1.209712862968 0.029784440994 -v 0.105703353882 1.216141939163 0.016078948975 -v 0.107604503632 1.206364512444 0.004519283772 -v 0.106831312180 1.196551799774 0.008540511131 -v 0.103477239609 1.200936555862 -0.016821682453 -v 0.102436780930 1.189777612686 -0.016660988331 -v 0.094894409180 1.201877832413 -0.033474504948 -v 0.091467142105 1.192241907120 -0.033644795418 -v 0.081027984619 1.205593347549 -0.044518053532 -v 0.078697204590 1.196267604828 -0.045972108841 -v 0.030203104019 1.317878961563 0.092599034309 -v 0.031599044800 1.306848764420 0.096550464630 -v 0.000533103943 1.315608501434 0.092406988144 -v 0.001453638077 1.304747343063 0.097599565983 -v -0.019915580750 1.309429168701 0.081647753716 -v -0.018998622894 1.298553228378 0.086916089058 -v -0.033011198044 1.297790884972 0.064219474792 -v -0.029258489609 1.289492845535 0.072676897049 -v -0.041879415512 1.274564981461 0.053379595280 -v -0.035678148270 1.269248962402 0.063527703285 -v -0.049278259277 1.251981019974 0.053342640400 -v -0.040801525116 1.249933481216 0.062599599361 -v -0.052246570587 1.230650424957 0.054706454277 -v -0.042381286621 1.229251742363 0.063888192177 -v -0.056648731232 1.206089735031 0.058673679829 -v -0.047176122665 1.203041553497 0.068685829639 -v -0.063978195190 1.193070888519 0.045640826225 -v -0.059770822525 1.182946562767 0.046971440315 -v -0.068000316620 1.188966512680 0.023967921734 -v -0.064295291901 1.178698301315 0.022614359856 -v -0.068785667419 1.192012310028 0.001784324646 -v -0.065010547638 1.183354616165 -0.002156734467 -v -0.066419363022 1.198132634163 -0.014372169971 -v -0.061841726303 1.189954519272 -0.018084764481 -v -0.056248426437 1.205180168152 -0.032190322876 -v -0.050663232803 1.196324706078 -0.035794079304 -v -0.035155773163 1.208442568779 -0.053844273090 -v -0.033224582672 1.197817921638 -0.051412761211 -v -0.008906602859 1.210032224655 -0.066920220852 -v -0.007337331772 1.200033903122 -0.065757989883 -v 0.025993824005 1.211974382401 -0.073480010033 -v 0.026358604431 1.201002120972 -0.069385886192 -v 0.049157142639 1.212844133377 -0.068056046963 -v 0.048957347870 1.202935099602 -0.064820349216 -v 0.065938234329 1.210010766983 -0.056550920010 -v 0.063969373703 1.200293183327 -0.057101726532 -v 0.026063919067 1.253668546677 -0.073655724525 -v -0.009798765182 1.251827239990 -0.066984713078 -v -0.036081075668 1.251029968262 -0.053802967072 -v -0.053255796432 1.248492121696 -0.030867159367 -v -0.061401128769 1.237682819366 -0.006527304649 -v -0.065071582794 1.235451579094 0.005308210850 -v -0.066051959991 1.232313632965 0.024793028831 -v -0.063958168030 1.215806245804 0.036684691906 -v -0.058470249176 1.244234442711 0.038768827915 -v -0.056696653366 1.254055619240 0.036476075649 -v 0.047235488892 1.252357602119 -0.067458629608 -v 0.065943956375 1.248579740524 -0.052758038044 -v 0.082094430923 1.242822408676 -0.039423704147 -v 0.101416587830 1.234602212906 0.000243604183 -v 0.095574378967 1.254433631897 -0.000831246376 -v 0.081856250763 1.282060623169 0.002210915089 -v 0.070363283157 1.305048108101 0.002756774426 -v 0.064732551575 1.325939893723 0.037348568439 -v 0.059475421906 1.330581545830 0.056172847748 -v 0.051770687103 1.331991195679 0.066862940788 -v 0.026969909668 1.331480026245 0.080155074596 -v 0.000534296036 1.328585267067 0.078154027462 -v -0.016364336014 1.321949958801 0.068262755871 -v -0.032131671906 1.307672977448 0.049133062363 -v -0.046026468277 1.281006813049 0.033047616482 -v -0.057170391083 1.264941453934 0.018052995205 -v -0.059194087982 1.260551929474 0.005703926086 -v -0.056351184845 1.267251372337 -0.005363285542 -v -0.049419403076 1.281430959702 0.018636167049 -v -0.050104856491 1.281523466110 -0.026480972767 -v -0.032762527466 1.285117030144 -0.046894788742 -v -0.006237030029 1.288429498672 -0.060750246048 -v 0.045986413956 1.285272717476 -0.059156835079 -v 0.060814857483 1.282638311386 -0.047715902328 -v 0.081722974777 1.278753519058 -0.015161991119 -v 0.093460798264 1.257528543472 -0.016839504242 -v 0.099166631699 1.234176397324 -0.016934752464 -v 0.080812215805 1.267979621887 -0.031077861786 -v 0.066226243973 1.297156810760 -0.022842288017 -v 0.025224208832 1.286554098129 -0.066509544849 -v 0.046222925186 1.308892011642 -0.040655016899 -v 0.025389671326 1.311321735382 -0.048380911350 -v -0.002219676971 1.312392711639 -0.044137835503 -v -0.024477481842 1.309771776199 -0.033741474152 -v -0.040723323822 1.304569959641 -0.014032125473 -v -0.038681983948 1.307122945786 0.022028684616 -v -0.033923625946 1.316653251648 0.007554233074 -v -0.022377967834 1.325628161430 0.032776713371 -v -0.011242151260 1.334012389183 0.047734975815 -v 0.005346775055 1.339532971382 0.057651221752 -v 0.023217439651 1.341475963593 0.059436559677 -v 0.043385505676 1.340054035187 0.050687074661 -v 0.050596475601 1.337354063988 0.041210770607 -v 0.055289745331 1.331090807915 0.023640811443 -v 0.054258584976 1.323943614960 -0.003970444202 -v 0.035431385040 1.330586671829 -0.015784919262 -v 0.002865314484 1.329736113548 -0.018387377262 -v -0.017127513885 1.325981378555 -0.009942293167 -v -0.009388685226 1.335545063019 0.010651230812 -v 0.008429527283 1.339061737061 0.003008246422 -v 0.036308050156 1.338485956192 0.004922389984 -v 0.036141872406 1.342529535294 0.023647129536 -v 0.034445047379 1.343819022179 0.035101830959 -v 0.020200014114 1.344961047173 0.038254320621 -v 0.006144762039 1.343188524246 0.040450692177 -v -0.003520011902 1.340352535248 0.030388653278 -v 0.015350580215 1.343349337578 0.023720622063 -v 0.002131700516 1.294373512268 0.084310173988 -v 0.032253980637 1.296369910240 0.083501935005 -v 0.053240537643 1.297918319702 0.073384404182 -v 0.063632249832 1.297773361206 0.063727974892 -v 0.066441297531 1.292367458344 0.051250755787 -v 0.069464921951 1.284128427505 0.042113184929 -v 0.072947740555 1.268516302109 0.036393523216 -v 0.077996730804 1.254851579666 0.034342646599 -v 0.082294940948 1.238687992096 0.033778369427 -v 0.096078634262 1.210922002792 0.033141076565 -v 0.093547344208 1.197418689728 0.010111808777 -v 0.088402271271 1.190471649170 -0.012344717979 -v 0.079278945923 1.192068338394 -0.027221798897 -v 0.067305803299 1.196002244949 -0.037115812302 -v 0.056254863739 1.199710249901 -0.045009076595 -v 0.043886661530 1.202761530876 -0.050360381603 -v 0.028577089310 1.203777551651 -0.055042266846 -v 0.000556945801 1.202123761177 -0.054026365280 -v -0.022556543350 1.199745535851 -0.042454838753 -v -0.037118673325 1.196506142616 -0.027604460716 -v -0.044364452362 1.191485524178 -0.013580024242 -v -0.048760175705 1.185310840607 0.001701295376 -v -0.049472093582 1.181732654572 0.018289864063 -v -0.043260574341 1.188125729561 0.041829228401 -v -0.042436599731 1.200907945633 0.067196130753 -v -0.029914379120 1.229040384293 0.062778651714 -v -0.028822183609 1.249405384064 0.061480879784 -v -0.026416063309 1.267934322357 0.062469124794 -v -0.020500183105 1.284778714180 0.069266617298 -v -0.011813879013 1.290825963020 0.077379345894 -v -0.036173343658 1.205227851868 0.065852403641 -v 0.089926242828 1.212391614914 0.033588826656 -v 0.086484670639 1.264750957489 -0.025318682194 -v 0.090276241302 1.249650478363 -0.029009580612 -v 0.093374252319 1.235239744186 -0.028121829033 -v -0.680430412292 1.393068790436 -0.320257246494 -v -0.698494911194 1.408102989197 -0.328137785196 -v -0.705596685410 1.403319478035 -0.332353264093 -v -0.702425003052 1.401414155960 -0.341219663620 -v -0.693487405777 1.401706576347 -0.345480948687 -v -0.677313804626 1.388596534729 -0.332979142666 -v -0.696997642517 1.407511115074 -0.337174981833 -v -0.689204931259 1.409341335297 -0.330315768719 -v -0.693303585052 1.391095876694 -0.314780384302 -v -0.703037500381 1.384432554245 -0.323003411293 -v -0.699735164642 1.379808068275 -0.336086094379 -v -0.686516761780 1.382108569145 -0.341215163469 -v -0.688117027283 1.406664133072 -0.339293509722 -v -0.671191692352 1.325040817261 -0.285161167383 -v -0.653577566147 1.274054050446 -0.263464331627 -v -0.622252702713 1.186689734459 -0.227236688137 -v -0.589787960052 1.099176168442 -0.192291796207 -v -0.552791118622 1.003217101097 -0.157474160194 -v -0.510915994644 0.897739231586 -0.121878385544 -v -0.492876291275 0.902821123600 -0.129963815212 -v -0.535413742065 1.007634758949 -0.164884626865 -v -0.573541641235 1.102779388428 -0.199071943760 -v -0.606878757477 1.189758062363 -0.233704805374 -v -0.639323711395 1.276522159576 -0.269631683826 -v -0.656749725342 1.327616810799 -0.290879905224 -v -0.681891918182 1.317631244659 -0.293967366219 -v -0.664569854736 1.266501188278 -0.272399932146 -v -0.634156942368 1.178615331650 -0.236648023129 -v -0.601839542389 1.090810775757 -0.202318966389 -v -0.566227912903 0.994425058365 -0.168143510818 -v -0.525188207626 0.888482391834 -0.133112192154 -v -0.678204059601 1.312798857689 -0.308455199003 -v -0.660619258881 1.261751770973 -0.287267655134 -v -0.630073070526 1.173742771149 -0.252752542496 -v -0.597980260849 1.085862278938 -0.219300508499 -v -0.562275886536 0.989962458611 -0.186343669891 -v -0.521363496780 0.884423673153 -0.152287662029 -v -0.663713693619 1.315396070480 -0.314257442951 -v -0.645992040634 1.264471530914 -0.293223381042 -v -0.614400863647 1.176954030991 -0.259143769741 -v -0.581530570984 1.089387059212 -0.226521193981 -v -0.544843912125 0.994354009628 -0.193900704384 -v -0.503242254257 0.889585494995 -0.160271108150 -v -0.653139591217 1.322819709778 -0.305283248425 -v -0.635165929794 1.272057771683 -0.284064382315 -v -0.603127479553 1.184988617897 -0.249243974686 -v -0.569592237473 1.097936868668 -0.215854406357 -v -0.531643867493 1.003189921379 -0.182969391346 -v -0.488971471786 0.898870944977 -0.149086236954 -v -0.484921455383 0.834170520306 -0.089892804623 -v -0.460219383240 0.840958893299 -0.100384473801 -v -0.511497497559 0.901323735714 -0.132468283176 -v -0.501404762268 0.904189109802 -0.136912345886 -v -0.472644090652 0.759641647339 -0.086778938770 -v -0.504419326782 0.821840167046 -0.105421543121 -v -0.519470214844 0.896225512028 -0.138695955276 -v -0.467942714691 0.754820764065 -0.108005642891 -v -0.499197244644 0.815808892250 -0.131774783134 -v -0.517336845398 0.893964409828 -0.149376213551 -v -0.448551177979 0.760925114155 -0.116835474968 -v -0.474140167236 0.822419762611 -0.142395973206 -v -0.507234096527 0.896824002266 -0.153811216354 -v -0.433065176010 0.771692276001 -0.104480087757 -v -0.455140352249 0.835817098618 -0.126966357231 -v -0.499275684357 0.901945590973 -0.147596955299 -v -0.459559202194 0.773626148701 -0.068398654461 -v -0.433999776840 0.781386613846 -0.079760193825 -v -0.427901983261 0.774820268154 -0.107565879822 -v -0.447791576385 0.760745763779 -0.123485684395 -v -0.472889900208 0.752940356731 -0.112041771412 -v -0.479088068008 0.758860111237 -0.084373116493 -v -0.491303682327 0.910904347897 -0.129152178764 -v -0.514250516891 0.904531538486 -0.118242800236 -v -0.533769607544 0.893227875233 -0.132516324520 -v -0.528328418732 0.887990593910 -0.157591700554 -v -0.504444837570 0.894635677338 -0.168278694153 -v -0.485826730728 0.906584739685 -0.153679370880 -v -0.461875915527 0.779266953468 -0.070306479931 -v -0.436331748962 0.787207782269 -0.081280946732 -v -0.430136680603 0.780604958534 -0.109252929688 -v -0.449860572815 0.765928268433 -0.125815510750 -v -0.475796222687 0.757836759090 -0.114095747471 -v -0.482009410858 0.764635562897 -0.085911035538 -v -0.487102031708 0.905195295811 -0.125341534615 -v -0.511810302734 0.898107171059 -0.114347636700 -v -0.531330347061 0.885510385036 -0.129618883133 -v -0.526210784912 0.880015254021 -0.155877709389 -v -0.501423597336 0.887129247189 -0.166869044304 -v -0.482195377350 0.899640679359 -0.151460170746 -v -0.462564945221 0.780975162983 -0.071647465229 -v -0.437812328339 0.788343131542 -0.082418143749 -v -0.431942939758 0.781991302967 -0.109270632267 -v -0.450904846191 0.768045961857 -0.124982774258 -v -0.475512504578 0.760414898396 -0.113783419132 -v -0.481489181519 0.767017781734 -0.087105572224 -v -0.487062454224 0.902436256409 -0.125205695629 -v -0.510672807693 0.895664632320 -0.114782571793 -v -0.529201984406 0.883543848991 -0.129371404648 -v -0.524323225021 0.878087401390 -0.154505074024 -v -0.500638008118 0.884852886200 -0.164988815784 -v -0.482070446014 0.897029280663 -0.150350451469 -v -0.424216270447 0.726895034313 -0.088332355022 -v -0.433250427246 0.720961630344 -0.097859382629 -v -0.445126295090 0.718145370483 -0.091281771660 -v -0.435346364975 0.722274005413 -0.082853138447 -v -0.449822902679 0.721979498863 -0.078244268894 -v -0.438974618912 0.728516280651 -0.071362376213 -v -0.426059484482 0.732701241970 -0.075176239014 -v -0.425045013428 0.742575645447 -0.074277520180 -v -0.443370342255 0.737635374069 -0.066380739212 -v -0.452912092209 0.722330808640 -0.097539663315 -v -0.434735298157 0.726553499699 -0.105409443378 -v -0.457568168640 0.770726919174 -0.074224233627 -v -0.438102483749 0.776775538921 -0.083273649216 -v -0.457084417343 0.727426528931 -0.078251421452 -v -0.421734809875 0.737034559250 -0.093638539314 -v -0.440868854523 0.726467907429 -0.079293847084 -v -0.441762924194 0.723804175854 -0.084031581879 -v -0.437235593796 0.723723113537 -0.086625933647 -v -0.433544158936 0.726360797882 -0.083503544331 -v -0.435790300369 0.728097319603 -0.078992664814 -v -0.435076475143 0.716530799866 -0.078679621220 -v -0.436748027802 0.715161144733 -0.083459377289 -v -0.433470964432 0.717130362988 -0.086149096489 -v -0.429803609848 0.719704866409 -0.082996487617 -v -0.430795431137 0.719356417656 -0.078405201435 -v -0.426370620728 0.708177804947 -0.082949578762 -v -0.429102659225 0.708031177521 -0.087148606777 -v -0.427751302719 0.711654126644 -0.088896811008 -v -0.424102544785 0.714181125164 -0.085791230202 -v -0.423462867737 0.712011873722 -0.082427322865 -v -0.417178869247 0.705715954304 -0.092401742935 -v -0.421164512634 0.705772161484 -0.095329344273 -v -0.421780347824 0.710141003132 -0.095210850239 -v -0.418033361435 0.712694764137 -0.092156529427 -v -0.415308475494 0.709888398647 -0.090527355671 -v -0.411131381989 0.710895836353 -0.103977918625 -v -0.416023015976 0.710323870182 -0.105279445648 -v -0.418101072311 0.713830649853 -0.102593660355 -v -0.414386272430 0.716481685638 -0.099799752235 -v -0.409998416901 0.714512467384 -0.100628316402 -v -0.412442445755 0.723457217216 -0.112111985683 -v -0.417440891266 0.721303761005 -0.112163603306 -v -0.419823646545 0.722338557243 -0.107104063034 -v -0.416396379471 0.725583493710 -0.104684352875 -v -0.411242246628 0.725655853748 -0.107722580433 -v -0.419799089432 0.736344456673 -0.113022804260 -v -0.424517631531 0.732703447342 -0.112453818321 -v -0.425635576248 0.730973005295 -0.106811225414 -v -0.422138690948 0.734303593636 -0.103965282440 -v -0.418025732040 0.737095832825 -0.108072340488 -v -0.427905082703 0.742825925350 -0.108273148537 -v -0.431505441666 0.737993359566 -0.108103752136 -v -0.431043863297 0.735172092915 -0.103496670723 -v -0.427010297775 0.737998902798 -0.100774705410 -v -0.425103187561 0.742438733578 -0.103610634804 -v -0.434395790100 0.745493888855 -0.102516651154 -v -0.437351465225 0.740055739880 -0.103321194649 -v -0.434785366058 0.735876679420 -0.100580215454 -v -0.429973125458 0.739280521870 -0.096914887428 -v -0.430575609207 0.744815766811 -0.098116934299 -v -0.638014793396 1.230491757393 -0.244978487492 -v -0.622946262360 1.233280658722 -0.251465588808 -v -0.649592638016 1.222546815872 -0.254358708858 -v -0.645442724228 1.217762947083 -0.269892901182 -v -0.630394697189 1.220943450928 -0.275375068188 -v -0.619070529938 1.228546142578 -0.266649246216 -v -0.606110572815 1.143009781837 -0.209524273872 -v -0.590292215347 1.146337389946 -0.216171145439 -v -0.617876529694 1.134744167328 -0.219516158104 -v -0.614089488983 1.129821658134 -0.235923349857 -v -0.598005294800 1.133176445961 -0.242772758007 -v -0.586416721344 1.141480803490 -0.232462942600 -v -0.572516918182 1.054052591324 -0.175565481186 -v -0.555697917938 1.058142900467 -0.182277798653 -v -0.585446357727 1.045498132706 -0.185521006584 -v -0.581245422363 1.040752649307 -0.203099846840 -v -0.564207553864 1.044691920280 -0.210411846638 -v -0.551835060120 1.053359389305 -0.199682593346 -v -0.530359745026 0.946404516697 -0.139006793499 -v -0.512903213501 0.951150536537 -0.146695137024 -v -0.544089317322 0.937598705292 -0.149761617184 -v -0.540381193161 0.933445930481 -0.168263316154 -v -0.522706985474 0.938259720802 -0.175991654396 -v -0.508960247040 0.947188973427 -0.165071189404 -v -0.473415136337 0.870537042618 -0.112968623638 -v -0.496746063232 0.863225281239 -0.101937651634 -v -0.516067743301 0.851110696793 -0.117046415806 -v -0.510797500610 0.845018565655 -0.142522931099 -v -0.486820697784 0.852223873138 -0.153340578079 -v -0.467840671539 0.864946663380 -0.138649642467 -v -0.447163105011 0.810840010643 -0.089115977287 -v -0.472838640213 0.805846035480 -0.079120457172 -v -0.492668628693 0.793564498425 -0.095415353775 -v -0.486189365387 0.784938633442 -0.121517777443 -v -0.460333108902 0.791131556034 -0.131569087505 -v -0.440885305405 0.803529441357 -0.115472018719 -v -0.450312852859 0.753731548786 -0.070098817348 -v -0.431421279907 0.759420990944 -0.078914582729 -v -0.465086460114 0.742805838585 -0.082118272781 -v -0.460514783859 0.737773180008 -0.103004276752 -v -0.441336154938 0.743454098701 -0.111343443394 -v -0.426443099976 0.754368603230 -0.099310636520 -v -0.731904268265 1.409023046494 -0.283832073212 -v -0.731420993805 1.409527540207 -0.277567297220 -v -0.769669771194 1.473773002625 -0.284856706858 -v -0.769919872284 1.473968267441 -0.288533568382 -v -0.807954311371 1.532006978989 -0.292883962393 -v -0.809309005737 1.532471895218 -0.288937449455 -v -0.723148822784 1.397814750671 -0.277460843325 -v -0.725734949112 1.400135159492 -0.284406632185 -v -0.701467037201 1.393261909485 -0.299498915672 -v -0.702801704407 1.394067406654 -0.304610729218 -v -0.697797775269 1.322681307793 -0.245903372765 -v -0.678847789764 1.325425028801 -0.269638597965 -v -0.699045181274 1.318197965622 -0.247449636459 -v -0.679080247879 1.320086479187 -0.270336747169 -v -0.698448657990 1.258418440819 -0.191542923450 -v -0.699070453644 1.255869746208 -0.195368707180 -v -0.698896884918 1.187084913254 -0.134619593620 -v -0.700427770615 1.184316277504 -0.138689637184 -v -0.701871871948 1.162669658661 -0.121972262859 -v -0.711782455444 1.180882930756 -0.144968867302 -v -0.710798740387 1.249737977982 -0.202855288982 -v -0.711197614670 1.311830759048 -0.256590962410 -v -0.690308570862 1.311554193497 -0.279663801193 -v -0.713588476181 1.315556406975 -0.259247243404 -v -0.693629026413 1.312055587769 -0.281306147575 -v -0.714844465256 1.249986529350 -0.202514290810 -v -0.714670181274 1.182743430138 -0.144470751286 -v -0.703557968140 1.160912275314 -0.124656915665 -v -0.734780550003 1.184387803078 -0.107548713684 -v -0.803620576859 1.413166880608 -0.193729162216 -v -0.844019651413 1.455053806305 -0.184393405914 -v -0.807727098465 1.321138620377 -0.116503834724 -v -0.837025165558 1.372961163521 -0.126379728317 -v -0.771314382553 1.244080543518 -0.100617885590 -v -0.793653011322 1.271091222763 -0.097309827805 -v -0.731769084930 1.187012553215 -0.105778515339 -v -0.778274536133 1.234176158905 -0.089952230453 -v -0.774795055389 1.242721438408 -0.096917808056 -v -0.802556514740 1.267426371574 -0.087716221809 -v -0.781018733978 1.239013910294 -0.089828252792 -v -0.831202745438 1.315947771072 -0.093698978424 -v -0.857189416885 1.373258233070 -0.109514474869 -v -0.872247457504 1.439273834229 -0.146919488907 -v -0.862528800964 1.441547393799 -0.156704366207 -v -0.872767448425 1.465386867523 -0.168636918068 -v -0.871892452240 1.446012973785 -0.152757167816 -v -0.870913505554 1.465698003769 -0.171075582504 -v -0.872616052628 1.496040582657 -0.196074187756 -v -0.873492717743 1.469481587410 -0.172275424004 -v -0.844311237335 1.563365578651 -0.288278520107 -v -0.867714643478 1.493918657303 -0.196815609932 -v -0.870485305786 1.498056888580 -0.198610186577 -v -0.873506069183 1.498218655586 -0.200232744217 -v -0.873781919479 1.495349645615 -0.197271823883 -v -0.868160724640 1.436191439629 -0.160237908363 -v -0.874623298645 1.443897843361 -0.155241250992 -v -0.875429630280 1.468093872070 -0.173968076706 -v -0.875430583954 1.464208483696 -0.170832037926 -v -0.861469507217 1.539059877396 -0.244808673859 -v -0.864252090454 1.538134932518 -0.246580541134 -v -0.846224308014 1.561979532242 -0.289737492800 -v -0.836484193802 1.567539691925 -0.300393223763 -v -0.837390184402 1.566413164139 -0.303441166878 -v -0.780709743500 1.232831001282 -0.092110395432 -v -0.770603179932 1.241312861443 -0.120023488998 -v -0.805193901062 1.265119791031 -0.089168965816 -v -0.783527612686 1.236857414246 -0.091316342354 -v -0.834095478058 1.314088821411 -0.095762848854 -v -0.860008001328 1.371434450150 -0.112266540527 -v -0.874962329865 1.439385414124 -0.149586439133 -v -0.845883846283 1.368828058243 -0.133463740349 -v -0.873351573944 1.462928771973 -0.173678338528 -v -0.871895790100 1.493336915970 -0.199328541756 -v -0.840737104416 1.510570049286 -0.263315886259 -v -0.833376646042 1.531134724617 -0.288762927055 -v -0.817931175232 1.526331186295 -0.300622344017 -v -0.746751785278 1.402173876762 -0.290421187878 -v -0.796869993210 1.488108158112 -0.299173355103 -v -0.803301095963 1.423126697540 -0.242137193680 -v -0.853743076324 1.448746681213 -0.194176614285 -v -0.821331739426 1.314145565033 -0.119208931923 -v -0.793041229248 1.273641824722 -0.120415627956 -v -0.779705524445 1.238341212273 -0.096930265427 -v -0.758402109146 1.325504183769 -0.214042127132 -v -0.734133243561 1.393293976784 -0.292042940855 -v -0.736127614975 1.383604526520 -0.289822369814 -v -0.747549772263 1.393516778946 -0.284139096737 -v -0.713304281235 1.387033820152 -0.312869518995 -v -0.716605424881 1.378824830055 -0.315402686596 -v -0.667083024979 1.332947969437 -0.272325456142 -v -0.686036825180 1.396254181862 -0.300350457430 -v -0.652807712555 1.335969448090 -0.279133826494 -v -0.671698808670 1.397094845772 -0.306801915169 -v -0.641156673431 1.331952333450 -0.292787551880 -v -0.662131309509 1.392925381660 -0.323805451393 -v -0.665781974792 1.324501156807 -0.274403363466 -v -0.653313159943 1.326481461525 -0.280657827854 -v -0.643545627594 1.325591325760 -0.292931616306 -v -0.687883615494 1.396928071976 -0.306693255901 -v -0.677305936813 1.397392749786 -0.311640799046 -v -0.668898105621 1.393209457397 -0.326097100973 -v -0.639791965485 1.324838161469 -0.306407392025 -v -0.661513090134 1.386579990387 -0.338125854731 -v -0.642078876495 1.321270823479 -0.304058849812 -v -0.667977333069 1.387650251389 -0.338719785213 -v -0.640511274338 1.320248246193 -0.313241720200 -v -0.661991596222 1.385642766953 -0.342326313257 -v -0.643562793732 1.316686630249 -0.313483148813 -v -0.666442394257 1.385178923607 -0.344291776419 -v -0.716503143311 1.372074604034 -0.326735794544 -v -0.694771766663 1.309220075607 -0.296694934368 -v -0.710252761841 1.365118026733 -0.340708762407 -v -0.689024686813 1.304324030876 -0.313677370548 -v -0.695271492004 1.365952491760 -0.350932478905 -v -0.673334360123 1.305315852165 -0.323754280806 -v -0.676507711411 1.373834609985 -0.354276686907 -v -0.657118558884 1.312539339066 -0.327110052109 -v -0.713317871094 1.378292798996 -0.329542458057 -v -0.708588600159 1.374512910843 -0.340065002441 -v -0.695788145065 1.374732732773 -0.347389072180 -v -0.678169250488 1.378413438797 -0.351348221302 -v -0.690240859985 1.306376218796 -0.295807123184 -v -0.685710668564 1.302699327469 -0.310207158327 -v -0.671741962433 1.304181456566 -0.319831520319 -v -0.655930995941 1.309202790260 -0.323127806187 -v -0.634047985077 1.305329561234 -0.344313293695 -v -0.623847723007 1.313705205917 -0.334188282490 -v -0.622318029404 1.319812774658 -0.335038781166 -v -0.636306285858 1.308283686638 -0.347529143095 -v -0.657687187195 1.368595123291 -0.372926771641 -v -0.657169342041 1.375516891479 -0.371039777994 -v -0.642990112305 1.381778359413 -0.362855851650 -v -0.649636030197 1.380834460258 -0.366766542196 -v -0.621777534485 1.454902648926 -0.452792227268 -v -0.627440929413 1.456566333771 -0.455327212811 -v -0.631230592728 1.454094767570 -0.456920742989 -v -0.635877132416 1.447454333305 -0.459561079741 -v -0.624344110489 1.466953277588 -0.470377117395 -v -0.627939224243 1.463238477707 -0.473223686218 -v -0.611341238022 1.455082416534 -0.477429419756 -v -0.615406513214 1.452845573425 -0.479317456484 -v -0.596461057663 1.429937839508 -0.461888015270 -v -0.585901737213 1.430440187454 -0.486534267664 -v -0.568025112152 1.390513300896 -0.463041514158 -v -0.556784152985 1.394706368446 -0.490542352200 -v -0.620961666107 1.366299271584 -0.374592006207 -v -0.602149963379 1.328221082687 -0.365407556295 -v -0.554142475128 1.359774947166 -0.457094848156 -v -0.544462203979 1.367879867554 -0.489594697952 -v -0.554653167725 1.386860847473 -0.492153495550 -v -0.540938138962 1.330043315887 -0.446610987186 -v -0.526558876038 1.326992034912 -0.474644184113 -v -0.532519340515 1.298381805420 -0.428922235966 -v -0.517386436462 1.295669794083 -0.456924021244 -v -0.517901897430 1.258272409439 -0.422607213259 -v -0.512837409973 1.254708290100 -0.429519742727 -v -0.540863037109 1.262001872063 -0.384749233723 -v -0.516560077667 1.256026744843 -0.420525699854 -v -0.516956090927 1.229684472084 -0.400133073330 -v -0.512316942215 1.247911930084 -0.421232968569 -v -0.543984174728 1.231948614120 -0.360431998968 -v -0.536952972412 1.211765289307 -0.364224553108 -v -0.613957405090 1.310405731201 -0.337616801262 -v -0.617177486420 1.305488467216 -0.336197882891 -v -0.547671794891 1.226849794388 -0.359812885523 -v -0.623764514923 1.295241832733 -0.345131874084 -v -0.550174236298 1.224074363708 -0.363058030605 -v -0.611073017120 1.422493457794 -0.469076097012 -v -0.633231639862 1.343430519104 -0.382424205542 -v -0.617163181305 1.313082218170 -0.376247048378 -v -0.627777338028 1.298094511032 -0.349091798067 -v -0.587876319885 1.425273895264 -0.487512648106 -v -0.559880733490 1.391711711884 -0.492971718311 -v -0.546575784683 1.364702701569 -0.491101324558 -v -0.556817054749 1.384633302689 -0.494335830212 -v -0.581263065338 1.378509998322 -0.469431370497 -v -0.528251409531 1.325081706047 -0.475629925728 -v -0.562163352966 1.334616303444 -0.456040829420 -v -0.519301652908 1.293952107430 -0.458499312401 -v -0.546352624893 1.291024565697 -0.436513841152 -v -0.514696121216 1.253158092499 -0.430215626955 -v -0.520211696625 1.255135059357 -0.424808651209 -v -0.520582675934 1.251160979271 -0.424345523119 -v -0.549528598785 1.249001860619 -0.397651523352 -v -0.514673948288 1.245489358902 -0.423131406307 -v -0.518534421921 1.226596713066 -0.399023622274 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.538474559784 1.209404468536 -0.364824950695 -v -0.528185606003 1.214612126350 -0.376569181681 -v -0.529793500900 1.213744163513 -0.379284560680 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.752520561218 1.404311418533 -0.285495400429 -v -0.799973726273 1.489697456360 -0.296636253595 -v 0.070177555084 1.274966716766 0.089686870575 -v 0.067983150482 1.274402737617 0.090926527977 -v 0.066224336624 1.272931575775 0.092114746571 -v 0.065168857574 1.270776987076 0.093070566654 -v 0.064977169037 1.268267154694 0.093648433685 -v 0.065678596497 1.265784263611 0.093760550022 -v 0.067166328430 1.263706088066 0.093389570713 -v 0.069213867188 1.262349128723 0.092592179775 -v 0.071509599686 1.261919736862 0.091489672661 -v 0.073703765869 1.262483835220 0.090249955654 -v 0.075462818146 1.263954997063 0.089061796665 -v 0.076518297195 1.266109466553 0.088105916977 -v 0.076709985733 1.268619298935 0.087528049946 -v 0.076008558273 1.271102190018 0.087416052818 -v 0.074520826340 1.273180484772 0.087786972523 -v 0.072473287582 1.274537563324 0.088584363461 -v 0.068333148956 1.278423786163 0.086334288120 -v 0.064796447754 1.277514934540 0.088332414627 -v 0.061961412430 1.275143623352 0.090247511864 -v 0.060260057449 1.271671056747 0.091788053513 -v 0.059951066971 1.267625689507 0.092719554901 -v 0.061081647873 1.263623714447 0.092900037766 -v 0.063479423523 1.260274052620 0.092302203178 -v 0.066779851913 1.258086919785 0.091017007828 -v 0.070479869843 1.257395267487 0.089240074158 -v 0.074016571045 1.258304119110 0.087241888046 -v 0.076851606369 1.260675430298 0.085326790810 -v 0.078552961349 1.264147996902 0.083786249161 -v 0.078861951828 1.268193244934 0.082854807377 -v 0.077731370926 1.272195339203 0.082674264908 -v 0.075333595276 1.275544881821 0.083272099495 -v 0.072033166885 1.277732014656 0.084557354450 -v 0.065737485886 1.280808687210 0.081495702267 -v 0.061116695404 1.279621124268 0.084106385708 -v 0.057412624359 1.276522874832 0.086608529091 -v 0.055189609528 1.271985650063 0.088621377945 -v 0.054785966873 1.266700267792 0.089838445187 -v 0.056262969971 1.261471390724 0.090074300766 -v 0.059396028519 1.257094979286 0.089293181896 -v 0.063708066940 1.254237174988 0.087613999844 -v 0.068542480469 1.253333449364 0.085292279720 -v 0.073163509369 1.254521012306 0.082681596279 -v 0.076867341995 1.257619142532 0.080179393291 -v 0.079090595245 1.262156486511 0.078166604042 -v 0.079494237900 1.267441749573 0.076949536800 -v 0.078016996384 1.272670745850 0.076713681221 -v 0.074883937836 1.277047157288 0.077494800091 -v 0.070571899414 1.279904842377 0.079174041748 -v 0.062948465347 1.280951499939 0.076157152653 -v 0.057946681976 1.279666066170 0.078983008862 -v 0.053937673569 1.276312589645 0.081691384315 -v 0.051531553268 1.271401524544 0.083870053291 -v 0.051094532013 1.265680670738 0.085187315941 -v 0.052693367004 1.260020971298 0.085442662239 -v 0.056084394455 1.255283951759 0.084597170353 -v 0.060751676559 1.252190828323 0.082779586315 -v 0.065984487534 1.251212596893 0.080266594887 -v 0.070986270905 1.252498149872 0.077440857887 -v 0.074995517731 1.255851507187 0.074732422829 -v 0.077401638031 1.260762453079 0.072553753853 -v 0.077838659286 1.266483306885 0.071236491203 -v 0.076239824295 1.272143006325 0.070981144905 -v 0.072848558426 1.276880025864 0.071826636791 -v 0.068181276321 1.279973268509 0.073644220829 -v 0.060390472412 1.278830766678 0.071131527424 -v 0.055769443512 1.277642965317 0.073742210865 -v 0.052065610886 1.274544715881 0.076244413853 -v 0.049842596054 1.270007610321 0.078257262707 -v 0.049438953400 1.264722228050 0.079474270344 -v 0.050915956497 1.259493350983 0.079710185528 -v 0.054049015045 1.255116820335 0.078929066658 -v 0.058361053467 1.252259254456 0.077249825001 -v 0.063195466995 1.251355409622 0.074928104877 -v 0.067816495895 1.252542972565 0.072317481041 -v 0.071520328522 1.255641222000 0.069815278053 -v 0.073743581772 1.260178327560 0.067802429199 -v 0.074147224426 1.265463709831 0.066585421562 -v 0.072669982910 1.270692825317 0.066349506378 -v 0.069536924362 1.275068998337 0.067130684853 -v 0.065225124359 1.277926802635 0.068809866905 -v 0.067524909973 1.268451929092 0.093102991581 -v 0.069175004959 1.268501400948 0.092242240906 -v 0.071127653122 1.268560051918 0.091223716736 -v 0.073080301285 1.268618583679 0.090205192566 -v 0.074730157852 1.268668174744 0.089344441891 -v 0.070652723312 1.273131608963 0.090560674667 -v 0.068799734116 1.272726535797 0.091593861580 -v 0.067301273346 1.271686553955 0.092565476894 -v 0.066444635391 1.270407199860 0.093231320381 -v 0.066426753998 1.268414258957 0.093641161919 -v 0.066850900650 1.266429066658 0.093780994415 -v 0.067962169647 1.265214204788 0.093459844589 -v 0.069663047791 1.264270186424 0.092762410641 -v 0.071587085724 1.263978362083 0.091825425625 -v 0.073440074921 1.264383435249 0.090792238712 -v 0.074938535690 1.265423536301 0.089820683002 -v 0.075786352158 1.266697168350 0.089119791985 -v 0.075813055038 1.268695831299 0.088744938374 -v 0.075380325317 1.270675182343 0.088570117950 -v 0.074277639389 1.271895647049 0.088926315308 -v 0.072576761246 1.272839784622 0.089623689651 -v 0.004819393158 1.270663738251 0.106835365295 -v 0.004348754883 1.274211406708 0.103122293949 -v 0.008491754532 1.273808002472 0.103105425835 -v 0.007389783859 1.270413398743 0.106824874878 -v 0.012167453766 1.271865367889 0.103312313557 -v 0.009670257568 1.269208192825 0.106953203678 -v 0.014816045761 1.268679141998 0.103711485863 -v 0.011313676834 1.267231464386 0.107200860977 -v 0.016034841537 1.264734506607 0.104242146015 -v 0.012069702148 1.264783978462 0.107530117035 -v 0.015637636185 1.260631918907 0.104823470116 -v 0.011823415756 1.262238621712 0.107890844345 -v 0.013685464859 1.256995797157 0.105367064476 -v 0.010612010956 1.259982705116 0.108228087425 -v 0.010475158691 1.254379987717 0.105790019035 -v 0.008620262146 1.258359789848 0.108490467072 -v 0.006495475769 1.253182649612 0.106028079987 -v 0.006151199341 1.257616877556 0.108638167381 -v 0.002352476120 1.253586053848 0.106044888496 -v 0.003580808640 1.257867097855 0.108648657799 -v -0.001322984695 1.255528688431 0.105838000774 -v 0.001300334930 1.259072422981 0.108520269394 -v -0.003971815109 1.258714914322 0.105438828468 -v -0.000343084335 1.261049270630 0.108272612095 -v -0.005190372467 1.262659549713 0.104908168316 -v -0.001099109650 1.263496637344 0.107943356037 -v -0.004793405533 1.266762256622 0.104326844215 -v -0.000852823257 1.266042113304 0.107582688332 -v -0.002841234207 1.270398139954 0.103783249855 -v 0.000358581543 1.268298029900 0.107245445251 -v 0.000369071960 1.273014068604 0.103360295296 -v 0.002350330353 1.269920825958 0.106983006001 -v 0.003931760788 1.276739597321 0.097712039948 -v 0.009344816208 1.276212692261 0.097690045834 -v 0.014147281647 1.273674488068 0.097960352898 -v 0.017608165741 1.269511461258 0.098481893539 -v 0.019200325012 1.264357566833 0.099175214767 -v 0.018681526184 1.258997201920 0.099934816360 -v 0.016130685806 1.254246473312 0.100645005703 -v 0.011936426163 1.250828742981 0.101197659969 -v 0.006736755371 1.249264478683 0.101508677006 -v 0.001323699951 1.249791383743 0.101530730724 -v -0.003478765488 1.252329587936 0.101260423660 -v -0.006939411163 1.256492614746 0.100738883018 -v -0.008531808853 1.261646509171 0.100045561790 -v -0.008013010025 1.267006874084 0.099285960197 -v -0.005462169647 1.271757602692 0.098575711250 -v -0.001267671585 1.275175333023 0.098023056984 -v 0.003712654114 1.277051687241 0.091699361801 -v 0.009571552277 1.276481389999 0.091675460339 -v 0.014769792557 1.273733854294 0.091968059540 -v 0.018515825272 1.269227981567 0.092532575130 -v 0.020239114761 1.263649225235 0.093283057213 -v 0.019677639008 1.257847428322 0.094105184078 -v 0.016916751862 1.252705335617 0.094873905182 -v 0.012376546860 1.249006032944 0.095472097397 -v 0.006748676300 1.247312784195 0.095808684826 -v 0.000889539719 1.247883200645 0.095832526684 -v -0.004308462143 1.250630378723 0.095539927483 -v -0.008054494858 1.255136489868 0.094975411892 -v -0.009777784348 1.260715007782 0.094224989414 -v -0.009216308594 1.266516923904 0.093402862549 -v -0.006455421448 1.271659016609 0.092634141445 -v -0.001915454865 1.275358438492 0.092035949230 -v 0.003724575043 1.275099992752 0.085999369621 -v 0.009137630463 1.274572968483 0.085977315903 -v 0.013940095901 1.272034764290 0.086247682571 -v 0.017400741577 1.267871737480 0.086769223213 -v 0.018993139267 1.262717843056 0.087462544441 -v 0.018474340439 1.257357597351 0.088222086430 -v 0.015923500061 1.252606868744 0.088932335377 -v 0.011729001999 1.249189138412 0.089484930038 -v 0.006529569626 1.247624635696 0.089795947075 -v 0.001116514206 1.248151659966 0.089817941189 -v -0.003685951233 1.250689744949 0.089547634125 -v -0.007146835327 1.254852890968 0.089026153088 -v -0.008738994598 1.260006904602 0.088332772255 -v -0.008220195770 1.265367150307 0.087573230267 -v -0.005669355392 1.270117759705 0.086863040924 -v -0.001475095749 1.273535490036 0.086310386658 -v 0.000261068344 1.263721823692 0.108568012714 -v 0.000306606293 1.265732765198 0.108267664909 -v 0.001283168793 1.267090082169 0.108078360558 -v 0.001492738724 1.263846516609 0.108560204506 -v 0.005061388016 1.268813371658 0.107770264149 -v 0.007216453552 1.268672227859 0.107751905918 -v 0.007727861404 1.264456152916 0.108364582062 -v 0.005536317825 1.264241814613 0.108433365822 -v 0.002977371216 1.268257856369 0.107884883881 -v 0.003344774246 1.264027595520 0.108502089977 -v 0.009113311768 1.267855644226 0.107832670212 -v 0.009579896927 1.264637112617 0.108306467533 -v 0.010335683823 1.266713142395 0.107952952385 -v 0.010796070099 1.264751791954 0.108237385750 -v 0.010741710663 1.262735128403 0.108502686024 -v 0.009773969650 1.261383295059 0.108727037907 -v 0.008079767227 1.260215759277 0.108920395374 -v 0.005995750427 1.259660124779 0.109035074711 -v 0.003840684891 1.259801387787 0.109053432941 -v 0.001943826675 1.260617733002 0.108972728252 -v 0.000712633133 1.261754751205 0.108817398548 -v -0.090843439102 0.711956977844 -0.100321829319 -v -0.097157239914 0.660702586174 -0.115609467030 -v -0.006523370743 0.676110148430 -0.150974154472 -v -0.006254673004 0.734257340431 -0.141055881977 -v -0.106460332870 0.595456779003 -0.120525121689 -v -0.013854026794 0.609138488770 -0.144045293331 -v 0.159080028534 0.595945835114 -0.117241799831 -v 0.082373142242 0.601140439510 -0.140979409218 -v 0.217724084854 0.633673191071 -0.043690085411 -v 0.161948204041 0.658787310123 -0.116667926311 -v 0.161992549896 0.716392397881 -0.109141111374 -v 0.200988769531 0.700885295868 -0.057521402836 -v 0.082037210464 0.736163735390 -0.142028212547 -v 0.083940982819 0.671887874603 -0.145761489868 -v -0.052839994431 0.668570876122 -0.136453270912 -v -0.051985740662 0.724966228008 -0.126949429512 -v -0.060494899750 0.603041768074 -0.130789637566 -v 0.039752244949 0.676460027695 -0.152075648308 -v 0.039582014084 0.736532151699 -0.145459830761 -v 0.035222053528 0.606680989265 -0.146267235279 -v 0.123104095459 0.599229633808 -0.133650958538 -v 0.124687910080 0.666198194027 -0.136043965816 -v 0.123418569565 0.728347480297 -0.130160868168 -v 0.192488431931 0.646883368492 -0.081060171127 -v 0.192901372910 0.580796957016 -0.078956365585 -v 0.191608905792 0.708395838737 -0.080889344215 -v -0.110157966614 0.521872341633 -0.123427271843 -v -0.020442485809 0.542563259602 -0.144708812237 -v -0.109526634216 0.464789211750 -0.130063176155 -v -0.029718160629 0.474508851767 -0.155036568642 -v 0.068801403046 0.477472692728 -0.140547931194 -v 0.076097488403 0.537705183029 -0.135993599892 -v 0.162404775620 0.526327550411 -0.118127703667 -v 0.165109157562 0.450441986322 -0.139342069626 -v 0.228643178940 0.555671572685 -0.027355194092 -v 0.238083362579 0.474860131741 -0.044692456722 -v -0.066143035889 0.532799482346 -0.133282661438 -v -0.084163904190 0.454995065928 -0.141852140427 -v 0.016598701477 0.487684130669 -0.148972153664 -v 0.027564287186 0.544286847115 -0.143417119980 -v 0.122592210770 0.530475378036 -0.130063533783 -v 0.122491121292 0.461961984634 -0.139939665794 -v 0.199285984039 0.507649183273 -0.092158377171 -v 0.206475257874 0.438298881054 -0.125071763992 -v 0.236012935638 0.432352960110 -0.098448753357 -v -0.090003728867 0.713547110558 -0.098060905933 -v -0.096627950668 0.660236895084 -0.111967146397 -v -0.006083011627 0.675602138042 -0.146969020367 -v -0.005826711655 0.733766078949 -0.137710273266 -v -0.104192733765 0.594722390175 -0.114763200283 -v -0.013294696808 0.609091877937 -0.139524400234 -v 0.157139778137 0.595473289490 -0.113379478455 -v 0.081852197647 0.601088523865 -0.137477576733 -v 0.215976238251 0.632654249668 -0.042290151119 -v 0.160015106201 0.658218741417 -0.113578557968 -v 0.160174369812 0.716303348541 -0.106486916542 -v 0.199095010757 0.698588788509 -0.055205583572 -v 0.081353425980 0.736018717289 -0.138786435127 -v 0.083306312561 0.671617090702 -0.142443776131 -v -0.051246881485 0.668073892593 -0.131973326206 -v -0.051016092300 0.724832594395 -0.123342573643 -v -0.058906555176 0.602810740471 -0.125979125500 -v 0.039349555969 0.676087617874 -0.148158311844 -v 0.039282560349 0.736191391945 -0.142057716846 -v 0.034797668457 0.606659471989 -0.142599940300 -v 0.122372865677 0.599070608616 -0.130384206772 -v 0.123716592789 0.665827274323 -0.132826924324 -v 0.122337818146 0.727991521358 -0.127091944218 -v 0.189619779587 0.645916223526 -0.078319907188 -v 0.190189838409 0.580016136169 -0.076071262360 -v 0.189076185226 0.708024799824 -0.078644990921 -v -0.109309196472 0.521241247654 -0.119572401047 -v -0.019951820374 0.542360663414 -0.139999091625 -v -0.107759237289 0.462610036135 -0.125670790672 -v -0.029715299606 0.473200440407 -0.152146577835 -v 0.068043947220 0.475595116615 -0.137133598328 -v 0.075683832169 0.537864387035 -0.132634162903 -v 0.160769462585 0.526261806488 -0.115079045296 -v 0.163467884064 0.450367748737 -0.135400056839 -v 0.221496105194 0.555388748646 -0.030082941055 -v 0.230763673782 0.473996579647 -0.045731902122 -v -0.064914464951 0.532697319984 -0.129568278790 -v -0.083212852478 0.454447656870 -0.137265324593 -v 0.015990495682 0.486549288034 -0.145901143551 -v 0.027146339417 0.544277787209 -0.140076875687 -v 0.121834754944 0.530655384064 -0.126233458519 -v 0.121745109558 0.460826694965 -0.136413335800 -v 0.196135759354 0.507262945175 -0.088767468929 -v 0.203240156174 0.436599731445 -0.122523009777 -v 0.234281539917 0.431487858295 -0.096786618233 -v -0.090369224548 0.714081227779 -0.101824402809 -v -0.097647190094 0.660447895527 -0.114232182503 -v -0.108165264130 0.595181941986 -0.117026686668 -v 0.217889308929 0.634391546249 -0.045080006123 -v 0.200847625732 0.698190927505 -0.056285917759 -v -0.110817670822 0.521583199501 -0.122230708599 -v -0.109757661819 0.463707029819 -0.127314388752 -v -0.029812097549 0.473399698734 -0.154148936272 -v 0.068494558334 0.476215690374 -0.139647960663 -v 0.164371013641 0.449653983116 -0.137532711029 -v 0.229068279266 0.556188762188 -0.032200336456 -v 0.238276958466 0.475655049086 -0.049598276615 -v -0.083764553070 0.453088641167 -0.140538215637 -v 0.016265869141 0.486640363932 -0.148057878017 -v 0.122293949127 0.461069822311 -0.137957692146 -v 0.204746484756 0.437017977238 -0.123723983765 -v 0.236302852631 0.434788256884 -0.099483311176 -# 5612 vertices - -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000006930147 0.002676741453 0.999996423721 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.161999627948 0.909521639347 0.382787853479 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000007515317 0.002677260898 0.999996423721 -vn 0.382675856352 0.003497111378 0.923876047134 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.047306902707 0.969304382801 0.241269692779 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.248550355434 0.968081712723 0.032257635146 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.665100693703 0.708603322506 0.235631942749 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.208323746920 0.938979506493 0.273712754250 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.704381942749 0.650786757469 0.283412605524 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.375906050205 0.924689590931 0.060363583267 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.433224350214 0.852531194687 0.292416185141 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.232279226184 0.908129572868 0.348349064589 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.410649836063 0.890585064888 0.195512071252 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.109717316926 0.925979495049 0.361281156540 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.089727103710 0.922582089901 0.375221759081 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129825502634 0.989126026630 0.069101937115 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.140165805817 0.920780718327 0.364028096199 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.647070944309 0.737142920494 0.194729119539 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.289651811123 0.940054774284 0.179996877909 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.132732138038 0.979921698570 0.148780390620 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.026919174939 0.987045407295 0.158166885376 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.207886472344 0.974640905857 0.082815110683 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.788730025291 0.571293294430 0.226999789476 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.841550469398 0.399582356215 0.363492399454 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.546461105347 0.726369321346 0.416854739189 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.618004083633 0.135420069098 0.774423897266 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.543861091137 0.085662640631 0.834791600704 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.819668352604 0.424242556095 0.384918212891 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.813350260258 0.528666734695 0.242843255401 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.407970279455 0.717792689800 0.564210891724 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.605787634850 0.494257092476 0.623483181000 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.969513058662 0.062274549156 0.236994311213 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.059391405433 0.995314598083 0.076298937201 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.030940596014 0.946716606617 0.320578128099 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.972541630268 0.205112487078 0.109961979091 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.572210907936 0.744452595711 0.344042211771 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.036019083112 0.815896332264 0.577075183392 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.811857640743 0.316165834665 0.490842521191 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.505996525288 0.084093302488 0.858426392078 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.372912973166 0.711369335651 0.595726132393 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.075495623052 0.638999342918 0.765493452549 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.237984761596 0.763823807240 0.599947035313 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.171342536807 0.505555272102 0.845609605312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.209175691009 0.608960092068 0.765122950077 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.209175691009 0.608960092068 0.765122950077 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.908309876919 0.015843641013 0.417997717857 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.448863714933 0.183967590332 0.874458312988 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.819909214973 0.467708528042 0.330147922039 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.972455918789 0.091722354293 0.214281424880 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.707751631737 0.511009931564 0.487807840109 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.648009002209 0.425326675177 0.631808161736 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.716207981110 0.499084711075 0.487812042236 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.629050672054 0.575037002563 0.523094296455 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.496823996305 0.472443997860 0.727985262871 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.521306455135 0.467230886221 0.714097201824 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.787957370281 0.477610796690 0.388601541519 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.518603384495 0.300804406404 0.800354421139 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.997338175774 0.072519011796 0.007588622160 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.700886607170 0.338039726019 0.628082096577 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.571633458138 0.247708499432 0.782224833965 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.674985289574 0.334197402000 0.657804667950 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.655655622482 0.397478044033 0.641971111298 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.605633556843 0.573746502399 0.551382780075 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.578698873520 0.646696209908 0.496881872416 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.734525084496 0.400696694851 0.547644972801 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.519214332104 0.253620952368 0.816145122051 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.508684575558 0.100909605622 0.855018854141 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.482553303242 0.293915122747 0.825079500675 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.143501415849 0.469171375036 0.871369957924 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.532382369041 0.165311589837 0.830205440521 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.265235602856 0.751007497311 0.604679942131 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.438396394253 0.250405520201 0.863195061684 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.184828087687 0.570850193501 0.799980401993 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.339759290218 0.652270197868 0.677574515343 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.975914239883 0.216983765364 0.022570852190 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.437682479620 0.131488755345 0.889463186264 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.693001866341 0.498886138201 0.520443081856 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.890769839287 0.184809222817 0.415180265903 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.616071522236 0.741670787334 0.265292972326 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.983508825302 0.178707674146 0.027819553390 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.657146453857 0.579351842403 0.482192873955 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.677771806717 0.617188751698 0.399629086256 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.610949575901 0.705598056316 0.358987480402 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.518502652645 0.501994550228 0.692211270332 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.461553364992 0.375474810600 0.803733229637 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.731816112995 0.506709039211 0.455731421709 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.310053557158 0.172868609428 0.934870719910 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.531211972237 0.828068792820 0.179209098220 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.296533823013 0.937092840672 0.184186592698 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.879008293152 0.327037870884 0.346973568201 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.418872237206 0.170925334096 0.891813099384 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.073301777244 0.768137931824 0.636074662209 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.106712952256 0.917102098465 0.384104311466 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.482846260071 0.869433462620 0.104618154466 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.087274819613 0.444357991219 0.891587972641 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.383311569691 0.245430797338 0.890413403511 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.368794947863 0.655544221401 0.658978044987 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.432463288307 0.539263606071 0.722613453865 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.196437984705 0.667735934258 0.718011736870 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.606201291084 0.206537902355 0.768024802208 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.513534486294 0.648863255978 0.561479091644 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.426534503698 0.658479154110 0.620059251785 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.449752897024 0.215031251311 0.866881728172 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.220938414335 0.246594354510 0.943598151207 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.525134205818 0.469024330378 0.710105836391 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.518878757954 0.427382588387 0.740343809128 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.418460667133 0.901152551174 0.113202057779 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.898592233658 0.382915318012 0.214261218905 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.582837760448 0.017110457644 0.812408387661 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.125691637397 0.965929806232 0.226232767105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.716074943542 0.144961029291 0.682805240154 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.429535895586 0.902928054333 0.014827483334 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.925961256027 0.377290695906 0.015729881823 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.934488713741 0.355977147818 0.003339467803 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn -0.364090979099 0.029598439112 0.930892944336 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.030472742394 0.502272367477 0.864172399044 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.048600327224 0.791139721870 0.609701573849 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.441782504320 0.297333627939 0.846416532993 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.184340089560 0.964558541775 0.188800379634 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.964621126652 0.160373017192 0.209252431989 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.945016801357 0.013837653212 0.326728969812 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.757342994213 0.639263868332 0.133316561580 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.689539670944 0.551088571548 0.469932347536 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.934458494186 0.322290331125 0.151381283998 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.547749757767 0.077166840434 0.833075940609 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.777829766273 0.488033413887 0.395985156298 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.326971471310 0.053588666022 0.943513572216 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.067655861378 0.094781979918 0.993196368217 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.004601359833 0.522861719131 0.852405130863 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.423879355192 0.904768526554 0.041475951672 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.313855469227 0.815999209881 0.485427707434 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.952248871326 0.304680645466 0.019794657826 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.343221575022 0.333233237267 0.878154039383 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.765450656414 0.598935127258 0.235291317105 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.720277249813 0.069460451603 0.690199911594 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.301544338465 0.953448176384 0.002751463326 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.793979823589 0.261099308729 0.549020230770 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn 0.229095175862 0.971845209599 0.055066000670 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.298334419727 0.949311316013 0.099018156528 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.195449680090 0.978367269039 0.067800879478 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.580564439297 0.618157505989 0.529930353165 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.148294940591 0.763890028000 0.628076970577 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.260491907597 0.307280063629 0.915272057056 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.162017181516 0.796604990959 0.582383811474 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.094890594482 0.167634546757 0.981271862984 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.965605020523 0.107465490699 0.236765861511 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.068652406335 0.974390566349 0.214125752449 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.716325759888 0.585582971573 0.379433780909 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.930489718914 -0.261996328831 -0.256021112204 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.967172682285 0.241761222482 0.078284777701 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn -0.344990402460 -0.115646079183 -0.931454539299 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.255546450615 -0.236742943525 -0.937362670898 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn 0.385443925858 0.300371497869 -0.872473478317 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.817613303661 0.347829401493 0.458828032017 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn 0.624225676060 -0.733383476734 -0.269241482019 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.913559436798 -0.390938848257 -0.112142503262 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.434841871262 0.650471568108 -0.622735321522 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.206277325749 0.496593266726 -0.843116104603 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.275574177504 0.178359404206 0.944588184357 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.318132579327 0.109800979495 0.941666305065 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.864802479744 0.500968754292 0.033867362887 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.609832704067 0.779186606407 0.144818082452 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.676929712296 0.735970973969 0.010624704883 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.730528593063 0.682668983936 0.017058826983 -vn 0.676929712296 0.735970973969 0.010624704883 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.067695811391 0.526292204857 0.847604751587 -vn -0.394177705050 0.541026473045 0.742909312248 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.052583612502 0.985693454742 0.160135433078 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.026022652164 0.988108336926 0.151541069150 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn 0.116307489574 0.990462958813 0.073862694204 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.040402501822 0.989431560040 0.139258161187 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.052583612502 0.985693454742 0.160135433078 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.134896829724 0.973662376404 0.183805242181 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.011763782240 0.995036125183 0.098816752434 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.026022652164 0.988108336926 0.151541069150 -vn -0.018820434809 0.989357590675 0.144282087684 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.914270520210 -0.374885022640 -0.153527349234 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.469311714172 -0.101307049394 0.877202033997 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn 0.465971797705 0.054153501987 -0.883140802383 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.448319792747 0.129651442170 -0.884420633316 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.167976438999 0.232479542494 0.957985997200 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.301698088646 0.951182126999 0.065044857562 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.171455085278 0.914633154869 0.366127461195 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.215676337481 0.968818902969 0.121957629919 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.473818302155 0.648060023785 0.596250295639 -vn 0.116785392165 0.979833245277 0.162135779858 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.248102903366 0.886689305305 0.390162765980 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.745227813721 0.633083999157 0.209380432963 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.812033295631 0.514916896820 0.274704486132 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.237624734640 0.624630987644 0.743888854980 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.454803496599 0.485992193222 0.746301114559 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.382084578276 0.771323442459 0.508990705013 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.392548322678 0.780418395996 0.486675381660 -vn -0.382084578276 0.771323442459 0.508990705013 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.218308880925 0.796049535275 0.564487636089 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.147346720099 0.889737486839 0.432037174702 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.598508119583 0.249849140644 0.761159241199 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.181642502546 0.885934293270 0.426762789488 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.424639850855 0.811399281025 0.401636928320 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.077389903367 0.914463222027 0.397199958563 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.669492661953 0.064479798079 0.740014791489 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.545027732849 0.737514972687 0.398768693209 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.743179678917 0.068944804370 0.665530264378 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.553945541382 0.699680268764 0.451211482286 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.436596006155 0.685988366604 0.582068622112 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.436596006155 0.685988366604 0.582068622112 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.298728913069 0.741523385048 0.600752949715 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.936779797077 0.026538468897 0.348911702633 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887424767017 0.078465610743 0.454225122929 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.030449874699 -0.613143086433 -0.789384782314 -vn -0.030449874699 -0.613143146038 -0.789384782314 -vn -0.030449876562 -0.613143146038 -0.789384782314 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295757294 -0.699427545071 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.373588293791 0.906539082527 0.196516364813 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.388561308384 0.831142783165 0.397771000862 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.008125438355 0.822232007980 0.569094419479 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.114516958594 0.788044095039 0.604873836040 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.415789157152 0.681671321392 0.602032840252 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.143064171076 0.886963069439 0.439123153687 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.829526424408 0.541623890400 0.136123031378 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.564102113247 0.009641343728 0.825648725033 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.236986622214 0.101993352175 0.966144263744 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.203997373581 0.026348058134 0.978616833687 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.132363051176 0.588919281960 0.797279179096 -vn 0.370204120874 0.758121490479 0.536843240261 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.227597177029 0.752148985863 0.618442714214 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.671189248562 0.679710924625 0.295800745487 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.132539749146 0.945317745209 0.298005938530 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.263727605343 0.610503315926 0.746815502644 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.020327450708 0.685757458210 0.727546215057 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.047376774251 0.985158741474 0.164977937937 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.050312381238 0.219402447343 0.974336326122 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.075094878674 0.432029217482 0.898727715015 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.263161271811 0.103435955942 0.959190905094 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.453169703484 0.481266558170 0.750346422195 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.660578846931 0.637442171574 0.396614521742 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.204309478402 0.943660676479 0.260311752558 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.179308205843 0.861584722996 0.474889785051 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.196217641234 0.079919569194 0.977298080921 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.087292499840 0.331456899643 0.939423382282 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.534430682659 0.838877797127 0.103285685182 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.560695827007 0.078877851367 0.824256300926 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.881415486336 0.472221165895 0.010672469623 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.283379137516 0.492464959621 0.822906136513 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.131599500775 0.737507283688 0.662393093109 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.119672834873 0.101008400321 0.987661719322 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.354700446129 0.034820698202 0.934331357479 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.314111679792 0.058616135269 0.947574794292 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.027125038207 0.236739024520 0.971194565296 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.334633797407 0.108778014779 0.936048924923 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.987220883369 0.152396500111 0.046585436910 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.506033003330 0.457370489836 0.731261134148 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.290093451738 0.940565109253 0.176587253809 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.645085215569 0.203440889716 0.736530244350 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.254643589258 0.460702836514 0.850240886211 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.317261904478 0.790387809277 0.524053394794 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.487584769726 0.575793743134 0.656294643879 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.288535594940 0.014455531724 0.957360029221 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.936993002892 0.101482637227 0.334283322096 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.234883025289 0.208845853806 0.949322581291 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.094372428954 0.461883842945 0.881905436516 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.125300318003 0.134481579065 0.982962131500 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.092569380999 0.481423765421 0.871585965157 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.090679392219 0.816002249718 0.570891857147 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.065149024129 0.968082070351 0.242018088698 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.214608341455 0.516929745674 0.828689873219 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.363941878080 0.109785512090 0.924928903580 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.327142566442 0.847049534321 0.418909132481 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.373320966959 0.424053817987 0.825111985207 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.378446906805 0.448631554842 0.809634268284 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.182598531246 0.715381562710 0.674453139305 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.421047270298 0.334669202566 0.843039572239 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.883379578590 0.453356623650 0.118778400123 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.334695070982 0.126260608435 0.933829486370 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.748294830322 0.242019072175 0.617641985416 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.291076213121 0.481702655554 0.826581597328 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.190369337797 0.409592747688 0.892184555531 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.270152628422 0.623499035835 0.733666479588 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.193748310208 0.389752209187 0.900308191776 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.080102473497 0.828760683537 0.553840458393 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.469709098339 0.664078414440 0.581698536873 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn 0.057261314243 0.891568779945 0.449250817299 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.489686667919 0.504504680634 0.711113214493 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.465997457504 0.474939972162 0.746510803699 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.104101993144 0.368369311094 0.923832714558 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.256318479776 0.039006829262 0.965804994106 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.148606613278 0.474946022034 0.867376685143 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.012771333568 0.858014822006 0.513466119766 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.067125074565 0.157456219196 0.985242009163 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.202230855823 0.135011807084 0.969986855984 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.027015432715 0.338717550039 0.940500199795 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.069257460535 0.874967575073 0.479202568531 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.266394942999 0.146734341979 0.952629387379 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.069257460535 0.874967575073 0.479202568531 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.125801399350 0.381812900305 0.915637969971 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.246009349823 0.853070199490 0.460163712502 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.084336921573 0.993597984314 0.075168356299 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.211031064391 0.334258556366 0.918551623821 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.005775345955 0.566921889782 0.823751330376 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.022682305425 0.700176298618 0.713609576225 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.158913969994 0.649801671505 0.743306219578 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.425227582455 0.791610717773 0.438786923885 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.905587971210 0.151429876685 0.396206259727 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.506390750408 0.538258075714 0.673681437969 -vn -0.299555271864 0.546643376350 0.781951189041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.203431159258 0.979057490826 0.007884264924 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.288760930300 0.908043682575 0.303436666727 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.707089662552 0.699392676353 0.104278922081 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.105939380825 0.093255937099 0.989989995956 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.924340128899 0.360457271338 0.125163570046 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.395210921764 0.116690479219 0.911148548126 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.215249896049 0.259879410267 0.941344857216 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.347879409790 0.817592084408 0.458827942610 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.254123061895 0.426116853952 0.868242979050 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.201308771968 0.240931555629 0.949434995651 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.240289658308 0.320749431849 0.916177213192 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.680037975311 0.480506420135 0.553770661354 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.219177588820 0.295268416405 0.929934263229 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.225854665041 0.275281429291 0.934456944466 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.680287778378 0.480499923229 0.553469419479 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.658345997334 0.509523391724 0.554045557976 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.211771011353 0.234253704548 0.948829948902 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.213284403086 0.286679387093 0.933983266354 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn 0.570412695408 0.657898664474 0.491730272770 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.227320805192 0.221673280001 0.948254287243 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.153622061014 0.138630852103 0.978356659412 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.551810741425 0.698545396328 0.455564767122 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.543161213398 0.695157170296 0.470884680748 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.263800501823 0.365938633680 0.892467498779 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.117148451507 0.034600071609 0.992511510849 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.706371426582 0.398818373680 0.584793448448 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.168904587626 0.153192564845 0.973654627800 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.696267127991 0.416324853897 0.584709942341 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.804239809513 -0.440206110477 0.399270415306 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473841011524 -0.329637020826 -0.816586852074 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.838858008385 0.494629532099 0.227285787463 -vn 0.804961979389 0.551999032497 0.217562019825 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.675563931465 0.163798823953 0.718876481056 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn -0.600282192230 -0.662484288216 -0.448080182076 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.223079264164 -0.842810750008 0.489801704884 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.769818246365 0.161918729544 0.617383360863 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.769818246365 0.161918729544 0.617383360863 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn 0.298304438591 0.947766005993 -0.112933620811 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.218723073602 0.307124495506 0.926193714142 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.676530897617 0.479380965233 0.559016883373 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.231893524528 0.286410689354 0.929620504379 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.681994259357 0.479156374931 0.552533268929 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.206624403596 0.240915045142 0.948296546936 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.206473186612 0.250022917986 0.945968985558 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.226969450712 0.276726186275 0.933759868145 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.272610336542 0.367797374725 0.889049291611 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.582295238972 0.388309806585 0.714246273041 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.660991668701 0.493317723274 0.565444648266 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.370886951685 0.612930238247 0.697681427002 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn 0.229398831725 0.792460381985 -0.565139591694 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.221627816558 0.735603809357 -0.640131354332 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn 0.199336946011 0.966365575790 -0.162488013506 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.526178479195 0.778710901737 -0.341680556536 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.005032873247 -0.546992003918 0.837122738361 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.058633551002 -0.727339625359 0.683768332005 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.601092875004 -0.198408842087 0.774158477783 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.286670923233 0.777926385403 -0.559151470661 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.316740483046 0.940792977810 -0.120764441788 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.766251981258 0.386263102293 0.513477087021 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.679944336414 0.429292380810 0.594460844994 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755384206772 0.451619952917 0.474799036980 -vn -0.714168488979 0.133881628513 0.687050998211 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.696129977703 0.598392426968 0.396647810936 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.218742683530 -0.747778773308 0.626880049706 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.336433708668 -0.580547392368 0.741469502449 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.292118996382 -0.289201915264 0.911607801914 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.676289498806 0.234662115574 0.698259413242 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.822031438351 -0.366936504841 -0.435455977917 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.833994865417 -0.328578948975 -0.443270176649 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.667977154255 -0.468124926090 -0.578502893448 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn 0.605304896832 -0.786918938160 0.119852282107 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.644578337669 -0.723311424255 0.247667729855 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.576117694378 0.644429028034 0.502791821957 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.706421017647 0.534547507763 0.463927060366 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.041993357241 0.797598063946 0.601725757122 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.378463476896 0.783811092377 0.492346972227 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.740822911263 0.609460711479 0.282381057739 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.817769885063 0.481556564569 0.315207391977 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn 0.581513226032 0.206123635173 -0.786991357803 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.595149517059 -0.417273491621 -0.686789572239 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn -0.537571310997 0.772639870644 -0.337705105543 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.495952785015 0.803755402565 -0.328645855188 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.629080116749 -0.764525115490 0.140568733215 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627170860767 -0.766199529171 0.139982149005 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.599086761475 -0.409433424473 -0.688083827496 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.700512945652 -0.458336979151 -0.546999812126 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.572836101055 0.156684830785 0.804554939270 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn 0.354127824306 -0.701984345913 0.617908954620 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.356339871883 -0.698108613491 0.621020376682 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.830982983112 0.368793278933 0.416483879089 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.830982983112 0.368793278933 0.416483879089 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.221020415425 0.617830932140 0.754609107971 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.235830068588 0.898830175400 0.369443446398 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.395072251558 0.917763888836 0.040340516716 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.169255286455 0.259556770325 0.950780153275 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.194399654865 0.158964470029 0.967956125736 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.197535604239 0.024697216228 0.979984581470 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.427116841078 0.346271544695 0.835264742374 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.226580724120 0.800231337547 0.555239558220 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.274038642645 0.932397603989 0.235664024949 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.067393772304 0.322359681129 0.944215178490 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.074658878148 0.311024487019 0.947464942932 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155109524727 0.599816203117 0.784959554672 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.990912795067 0.127940833569 0.041508488357 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.171049833298 0.970419943333 0.170373469591 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.086038894951 0.984414279461 0.153381422162 -vn 0.083577327430 0.994467854500 0.063627921045 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.023173412308 0.995078146458 0.096345901489 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.063926614821 0.963856279850 0.258639603853 -vn -0.375237524509 0.793154478073 0.479690253735 -vn -0.350450277328 0.809412717819 0.471206605434 -vn -0.350450277328 0.809412717819 0.471206605434 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.577268898487 0.306803852320 0.756724536419 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.185570269823 0.171825677156 0.967491388321 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.487122595310 0.042172510177 0.872314751148 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn -0.268814533949 0.206545710564 0.940785646439 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.180396959186 0.971246838570 0.155359238386 -vn -0.194942057133 0.976504385471 0.091851882637 -# 32013 vertex normals - -vt 0.377155363560 0.858360707760 0.000000000000 -vt 0.377155363560 0.848666846752 0.000000000000 -vt 0.387879788876 0.848666846752 0.000000000000 -vt 0.387879788876 0.858360707760 0.000000000000 -vt 0.377155363560 0.838978648186 0.000000000000 -vt 0.387879788876 0.838978648186 0.000000000000 -vt 0.377155363560 0.829283058643 0.000000000000 -vt 0.387879788876 0.829283058643 0.000000000000 -vt 0.377155363560 0.984480679035 0.000000000000 -vt 0.377155363560 0.974780797958 0.000000000000 -vt 0.387879788876 0.974780797958 0.000000000000 -vt 0.387879788876 0.984480679035 0.000000000000 -vt 0.377155363560 0.965079963207 0.000000000000 -vt 0.387879788876 0.965079963207 0.000000000000 -vt 0.377155363560 0.955380022526 0.000000000000 -vt 0.387879788876 0.955380022526 0.000000000000 -vt 0.377155363560 0.945681273937 0.000000000000 -vt 0.387879788876 0.945681273937 0.000000000000 -vt 0.377155363560 0.935981333256 0.000000000000 -vt 0.387879788876 0.935981333256 0.000000000000 -vt 0.377155363560 0.926279187202 0.000000000000 -vt 0.387879788876 0.926279187202 0.000000000000 -vt 0.377155363560 0.916576147079 0.000000000000 -vt 0.387879788876 0.916576147079 0.000000000000 -vt 0.377155363560 0.906873524189 0.000000000000 -vt 0.387879788876 0.906873524189 0.000000000000 -vt 0.377155363560 0.897172033787 0.000000000000 -vt 0.387879788876 0.897172033787 0.000000000000 -vt 0.377155363560 0.887470304966 0.000000000000 -vt 0.387879788876 0.887470304966 0.000000000000 -vt 0.377155363560 0.877766370773 0.000000000000 -vt 0.387879788876 0.877766370773 0.000000000000 -vt 0.377155363560 0.868061482906 0.000000000000 -vt 0.387879788876 0.868061482906 0.000000000000 -vt 0.389967858791 0.848666846752 0.000000000000 -vt 0.389967858791 0.858360707760 0.000000000000 -vt 0.389223754406 0.858360707760 0.000000000000 -vt 0.389223754406 0.848666846752 0.000000000000 -vt 0.389967858791 0.838978648186 0.000000000000 -vt 0.389223754406 0.838978648186 0.000000000000 -vt 0.389967858791 0.829283058643 0.000000000000 -vt 0.389223754406 0.829283058643 0.000000000000 -vt 0.389967858791 0.974780797958 0.000000000000 -vt 0.389967858791 0.984480679035 0.000000000000 -vt 0.389223754406 0.984480679035 0.000000000000 -vt 0.389223754406 0.974780797958 0.000000000000 -vt 0.389967858791 0.965079963207 0.000000000000 -vt 0.389223754406 0.965079963207 0.000000000000 -vt 0.389967858791 0.955380022526 0.000000000000 -vt 0.389223754406 0.955380022526 0.000000000000 -vt 0.389967858791 0.945681273937 0.000000000000 -vt 0.389223754406 0.945681273937 0.000000000000 -vt 0.389967858791 0.935981333256 0.000000000000 -vt 0.389223754406 0.935981333256 0.000000000000 -vt 0.389967858791 0.926279187202 0.000000000000 -vt 0.389223754406 0.926279187202 0.000000000000 -vt 0.389967858791 0.916576147079 0.000000000000 -vt 0.389223754406 0.916576147079 0.000000000000 -vt 0.389967858791 0.906873524189 0.000000000000 -vt 0.389223754406 0.906873524189 0.000000000000 -vt 0.389967858791 0.897172033787 0.000000000000 -vt 0.389223754406 0.897172033787 0.000000000000 -vt 0.389967858791 0.887470304966 0.000000000000 -vt 0.389223754406 0.887470304966 0.000000000000 -vt 0.389967858791 0.877766370773 0.000000000000 -vt 0.389223754406 0.877766370773 0.000000000000 -vt 0.389967858791 0.868061482906 0.000000000000 -vt 0.389223754406 0.868061482906 0.000000000000 -vt 0.391293346882 0.858360707760 0.000000000000 -vt 0.391293346882 0.848666846752 0.000000000000 -vt 0.396203100681 0.848666846752 0.000000000000 -vt 0.396203100681 0.858360707760 0.000000000000 -vt 0.391293346882 0.838978648186 0.000000000000 -vt 0.396203100681 0.838978648186 0.000000000000 -vt 0.391293346882 0.829283058643 0.000000000000 -vt 0.396203100681 0.829283058643 0.000000000000 -vt 0.391293346882 0.984480679035 0.000000000000 -vt 0.391293346882 0.974780797958 0.000000000000 -vt 0.396203100681 0.974780797958 0.000000000000 -vt 0.396203100681 0.984480679035 0.000000000000 -vt 0.391293346882 0.965079963207 0.000000000000 -vt 0.396203100681 0.965079963207 0.000000000000 -vt 0.391293346882 0.955380022526 0.000000000000 -vt 0.396203100681 0.955380022526 0.000000000000 -vt 0.391293346882 0.945681273937 0.000000000000 -vt 0.396203100681 0.945681273937 0.000000000000 -vt 0.391293346882 0.935981333256 0.000000000000 -vt 0.396203100681 0.935981333256 0.000000000000 -vt 0.391293346882 0.926279187202 0.000000000000 -vt 0.396203100681 0.926279187202 0.000000000000 -vt 0.391293346882 0.916576147079 0.000000000000 -vt 0.396203100681 0.916576147079 0.000000000000 -vt 0.391293346882 0.906873524189 0.000000000000 -vt 0.396203100681 0.906873524189 0.000000000000 -vt 0.391293346882 0.897172033787 0.000000000000 -vt 0.396203100681 0.897172033787 0.000000000000 -vt 0.391293346882 0.887470304966 0.000000000000 -vt 0.396203100681 0.887470304966 0.000000000000 -vt 0.391293346882 0.877766370773 0.000000000000 -vt 0.396203100681 0.877766370773 0.000000000000 -vt 0.391293346882 0.868061482906 0.000000000000 -vt 0.396203100681 0.868061482906 0.000000000000 -vt 0.409175425768 0.672242879868 0.000000000000 -vt 0.452760726213 0.666515350342 0.000000000000 -vt 0.431881427765 0.692003369331 0.000000000000 -vt 0.481934756041 0.680083930492 0.000000000000 -vt 0.508225858212 0.789766192436 0.000000000000 -vt 0.553140699863 0.792127192020 0.000000000000 -vt 0.543430626392 0.810674130917 0.000000000000 -vt 0.493056267500 0.761313557625 0.000000000000 -vt 0.498380273581 0.738467097282 0.000000000000 -vt 0.515042841434 0.755405724049 0.000000000000 -vt 0.550852000713 0.845992863178 0.000000000000 -vt 0.577347338200 0.824143350124 0.000000000000 -vt 0.609382450581 0.854941427708 0.000000000000 -vt 0.665927231312 0.810042083263 0.000000000000 -vt 0.669713199139 0.747112154961 0.000000000000 -vt 0.691940128803 0.688431560993 0.000000000000 -vt 0.480293363333 0.580234348774 0.000000000000 -vt 0.515759050846 0.550068080425 0.000000000000 -vt 0.567890584469 0.594532608986 0.000000000000 -vt 0.623778641224 0.602010011673 0.000000000000 -vt 0.572804629803 0.544676065445 0.000000000000 -vt 0.631756961346 0.573595166206 0.000000000000 -vt 0.610680639744 0.688212931156 0.000000000000 -vt 0.650606334209 0.643516659737 0.000000000000 -vt 0.631374895573 0.713805377483 0.000000000000 -vt 0.451538383961 0.699487090111 0.000000000000 -vt 0.488095849752 0.712747395039 0.000000000000 -vt 0.505906522274 0.654317796230 0.000000000000 -vt 0.514503896236 0.621594429016 0.000000000000 -vt 0.546522319317 0.636798501015 0.000000000000 -vt 0.620644509792 0.650109648705 0.000000000000 -vt 0.536644995213 0.674807369709 0.000000000000 -vt 0.559180438519 0.677152156830 0.000000000000 -vt 0.546803295612 0.700395822525 0.000000000000 -vt 0.580495297909 0.670894205570 0.000000000000 -vt 0.560229241848 0.708388805389 0.000000000000 -vt 0.583466589451 0.746397972107 0.000000000000 -vt 0.590534269810 0.714147150517 0.000000000000 -vt 0.632254183292 0.742581784725 0.000000000000 -vt 0.392473429441 0.735891520977 0.000000000000 -vt 0.401782691479 0.699883401394 0.000000000000 -vt 0.437636852264 0.750069797039 0.000000000000 -vt 0.443033576012 0.728961050510 0.000000000000 -vt 0.467387497425 0.731456875801 0.000000000000 -vt 0.397550672293 0.599925756454 0.000000000000 -vt 0.443568110466 0.613210141659 0.000000000000 -vt 0.366362631321 0.656876027584 0.000000000000 -vt 0.447481751442 0.559440612793 0.000000000000 -vt 0.601355612278 0.819214940071 0.000000000000 -vt 0.636718928814 0.797729492188 0.000000000000 -vt 0.619128763676 0.819936096668 0.000000000000 -vt 0.559825360775 0.776961624622 0.000000000000 -vt 0.572190821171 0.759399116039 0.000000000000 -vt 0.604671776295 0.773796379566 0.000000000000 -vt 0.554654181004 0.617363810539 0.000000000000 -vt 0.567634403706 0.651618182659 0.000000000000 -vt 0.590938866138 0.618936240673 0.000000000000 -vt 0.596868813038 0.647921144962 0.000000000000 -vt 0.651719510555 0.782778739929 0.000000000000 -vt 0.614525854588 0.755118906498 0.000000000000 -vt 0.455462366343 0.816022455692 0.000000000000 -vt 0.450997769833 0.780333817005 0.000000000000 -vt 0.483516186476 0.802494883537 0.000000000000 -vt 0.485845893621 0.853235423565 0.000000000000 -vt 0.417244762182 0.840927124023 0.000000000000 -vt 0.433641225100 0.829533994198 0.000000000000 -vt 0.477579563856 0.870459556580 0.000000000000 -vt 0.530758202076 0.857129693031 0.000000000000 -vt 0.544338524342 0.876446247101 0.000000000000 -vt 0.532405674458 0.712911307812 0.000000000000 -vt 0.526134669781 0.742851078510 0.000000000000 -vt 0.547361195087 0.739448964596 0.000000000000 -vt 0.567548215389 0.558903396130 0.000000000000 -vt 0.397433131933 0.817093312740 0.000000000000 -vt 0.514106690884 0.777620911598 0.000000000000 -vt 0.462766647339 0.752251565456 0.000000000000 -vt 0.460485816002 0.643762111664 0.000000000000 -vt 0.485318392515 0.636485338211 0.000000000000 -vt 0.480034440756 0.664412677288 0.000000000000 -vt 0.630446612835 0.777688920498 0.000000000000 -vt 0.600008070469 0.799526214600 0.000000000000 -vt 0.476415723562 0.779506325722 0.000000000000 -vt 0.473682790995 0.610604822636 0.000000000000 -vt 0.675627768040 0.625576317310 0.000000000000 -vt 0.565741121769 0.800483822823 0.000000000000 -vt 0.356244146824 0.722902357578 0.000000000000 -vt 0.588402211666 0.811188578606 0.000000000000 -vt 0.518669903278 0.699171006680 0.000000000000 -vt 0.535777628422 0.658217966557 0.000000000000 -vt 0.508222043514 0.539263308048 0.000000000000 -vt 0.648145139217 0.728081822395 0.000000000000 -vt 0.514887988567 0.819228231907 0.000000000000 -vt 0.480209141970 0.748140454292 0.000000000000 -vt 0.594826638699 0.678737699986 0.000000000000 -vt 0.609615743160 0.711115896702 0.000000000000 -vt 0.374209046364 0.788166940212 0.000000000000 -vt 0.696136057377 0.841438889503 0.000000000000 -vt 0.697102844715 0.847001552582 0.000000000000 -vt 0.687970817089 0.838945984840 0.000000000000 -vt 0.676894485950 0.837039768696 0.000000000000 -vt 0.668740808964 0.834839344025 0.000000000000 -vt 0.658680617809 0.855564236641 0.000000000000 -vt 0.651980459690 0.853254318237 0.000000000000 -vt 0.694596707821 0.852629542351 0.000000000000 -vt 0.685916483402 0.854809284210 0.000000000000 -vt 0.674534022808 0.855843186378 0.000000000000 -vt 0.665389955044 0.856125533581 0.000000000000 -vt 0.650012195110 0.834412455559 0.000000000000 -vt 0.656730353832 0.833129286766 0.000000000000 -vt 0.646296203136 0.841373562813 0.000000000000 -vt 0.688886702061 0.834426641464 0.000000000000 -vt 0.699207842350 0.838674664497 0.000000000000 -vt 0.697359144688 0.855724990368 0.000000000000 -vt 0.686487972736 0.859591126442 0.000000000000 -vt 0.702463567257 0.847452104092 0.000000000000 -vt 0.677858173847 0.832566380501 0.000000000000 -vt 0.674788177013 0.860633373260 0.000000000000 -vt 0.656709134579 0.828647792339 0.000000000000 -vt 0.663522779942 0.828503489494 0.000000000000 -vt 0.663026511669 0.833329021931 0.000000000000 -vt 0.665229976177 0.860744595528 0.000000000000 -vt 0.646054327488 0.849184870720 0.000000000000 -vt 0.944440543652 0.577088952065 0.000000000000 -vt 0.934413731098 0.578397750854 0.000000000000 -vt 0.933311760426 0.570732593536 0.000000000000 -vt 0.942559897900 0.569070458412 0.000000000000 -vt 0.878645479679 0.586926877499 0.000000000000 -vt 0.868258655071 0.588900566101 0.000000000000 -vt 0.867458641529 0.580585360527 0.000000000000 -vt 0.877176105976 0.579317748547 0.000000000000 -vt 0.952389657497 0.575497746468 0.000000000000 -vt 0.950832903385 0.567034423351 0.000000000000 -vt 0.923831403255 0.579496085644 0.000000000000 -vt 0.923619329929 0.572405040264 0.000000000000 -vt 0.628452599049 0.873331427574 0.000000000000 -vt 0.632204830647 0.876753568649 0.000000000000 -vt 0.628753483295 0.881655633450 0.000000000000 -vt 0.623970210552 0.878167748451 0.000000000000 -vt 0.646685302258 0.866765677929 0.000000000000 -vt 0.656351864338 0.871634185314 0.000000000000 -vt 0.653122007847 0.874798536301 0.000000000000 -vt 0.645847260952 0.871063649654 0.000000000000 -vt 0.726799309254 0.837845385075 0.000000000000 -vt 0.661485850811 0.880055904388 0.000000000000 -vt 0.656600654125 0.882020831108 0.000000000000 -vt 0.636110603809 0.868256449699 0.000000000000 -vt 0.637845695019 0.872147083282 0.000000000000 -vt 0.649987399578 0.877419590950 0.000000000000 -vt 0.644934833050 0.875803411007 0.000000000000 -vt 0.639724314213 0.875453293324 0.000000000000 -vt 0.650543510914 0.882872819901 0.000000000000 -vt 0.637335002422 0.879814982414 0.000000000000 -vt 0.635132730007 0.885670363903 0.000000000000 -vt 0.643860280514 0.881775856018 0.000000000000 -vt 0.642733037472 0.850792288780 0.000000000000 -vt 0.641889035702 0.840179145336 0.000000000000 -vt 0.669664084911 0.830182671547 0.000000000000 -vt 0.650239527225 0.857445180416 0.000000000000 -vt 0.648015201092 0.831698417664 0.000000000000 -vt 0.642690360546 0.888261675835 0.000000000000 -vt 0.663629949093 0.887337207794 0.000000000000 -vt 0.657781779766 0.889087080956 0.000000000000 -vt 0.889635980129 0.584733188152 0.000000000000 -vt 0.887632310390 0.577965676785 0.000000000000 -vt 0.898609101772 0.583011865616 0.000000000000 -vt 0.896672070026 0.576863348484 0.000000000000 -vt 0.915674507618 0.580389678478 0.000000000000 -vt 0.915229618549 0.574002265930 0.000000000000 -vt 0.657724201679 0.860278069973 0.000000000000 -vt 0.930922925472 0.558675527573 0.000000000000 -vt 0.650379359722 0.889898777008 0.000000000000 -vt 0.939678132534 0.556469440460 0.000000000000 -vt 0.867106497288 0.567602217197 0.000000000000 -vt 0.875806748867 0.567502915859 0.000000000000 -vt 0.947033226490 0.554314255714 0.000000000000 -vt 0.922403037548 0.561220228672 0.000000000000 -vt 0.885274112225 0.567466676235 0.000000000000 -vt 0.658997356892 0.896231293678 0.000000000000 -vt 0.649604141712 0.899704515934 0.000000000000 -vt 0.895252883434 0.566620349884 0.000000000000 -vt 0.719376146793 0.837280273438 0.000000000000 -vt 0.918815433979 0.545299708843 0.000000000000 -vt 0.910051763058 0.547324061394 0.000000000000 -vt 0.907046377659 0.529140114784 0.000000000000 -vt 0.916585505009 0.527373969555 0.000000000000 -vt 0.899707138538 0.530310690403 0.000000000000 -vt 0.641025960445 0.896537065506 0.000000000000 -vt 0.901793301105 0.548481404781 0.000000000000 -vt 0.927321612835 0.542573332787 0.000000000000 -vt 0.632426559925 0.894321084023 0.000000000000 -vt 0.625132262707 0.886998593807 0.000000000000 -vt 0.717746436596 0.831090271473 0.000000000000 -vt 0.725946605206 0.830549895763 0.000000000000 -vt 0.735287845135 0.838093996048 0.000000000000 -vt 0.734414517879 0.830852091312 0.000000000000 -vt 0.717679798603 0.825329720974 0.000000000000 -vt 0.723944962025 0.823542177677 0.000000000000 -vt 0.732950508595 0.823792576790 0.000000000000 -vt 0.739792287350 0.825830638409 0.000000000000 -vt 0.741621911526 0.831147015095 0.000000000000 -vt 0.741378247738 0.836689889431 0.000000000000 -vt 0.665112435818 0.894209623337 0.000000000000 -vt 0.620138943195 0.882827579975 0.000000000000 -vt 0.936108648777 0.539952039719 0.000000000000 -vt 0.867212593555 0.550016939640 0.000000000000 -vt 0.875978291035 0.550476253033 0.000000000000 -vt 0.943726122379 0.537669897079 0.000000000000 -vt 0.884841740131 0.551008760929 0.000000000000 -vt 0.913087069988 0.563861310482 0.000000000000 -vt 0.893644869328 0.550148010254 0.000000000000 -vt 0.892628490925 0.531013190746 0.000000000000 -vt 0.904061496258 0.562744498253 0.000000000000 -vt 0.926213800907 0.525771796703 0.000000000000 -vt 0.934501111507 0.523906171322 0.000000000000 -vt 0.865935027599 0.533409059048 0.000000000000 -vt 0.875216186047 0.532836914063 0.000000000000 -vt 0.942422688007 0.521042168140 0.000000000000 -vt 0.884195983410 0.531999826431 0.000000000000 -vt 0.924653232098 0.517368316650 0.000000000000 -vt 0.932635247707 0.517127633095 0.000000000000 -vt 0.914257109165 0.519580006599 0.000000000000 -vt 0.906176626682 0.522352159023 0.000000000000 -vt 0.899168789387 0.522687613964 0.000000000000 -vt 0.892163813114 0.523706674576 0.000000000000 -vt 0.884188354015 0.523065209389 0.000000000000 -vt 0.873883426189 0.524219810963 0.000000000000 -vt 0.865347802639 0.526163995266 0.000000000000 -vt 0.858433783054 0.526082932949 0.000000000000 -vt 0.859899699688 0.590485215187 0.000000000000 -vt 0.858855664730 0.581898033619 0.000000000000 -vt 0.859369337559 0.568410336971 0.000000000000 -vt 0.859169065952 0.551045894623 0.000000000000 -vt 0.856827557087 0.534337580204 0.000000000000 -vt 0.937964379787 0.513839006424 0.000000000000 -vt 0.693465530872 0.814677596092 0.000000000000 -vt 0.700085699558 0.824197411537 0.000000000000 -vt 0.694888770580 0.822570204735 0.000000000000 -vt 0.692891776562 0.803992629051 0.000000000000 -vt 0.691710650921 0.795865237713 0.000000000000 -vt 0.711294472218 0.782084345818 0.000000000000 -vt 0.712714016438 0.788840830326 0.000000000000 -vt 0.708831012249 0.814877569675 0.000000000000 -vt 0.705738484859 0.822653293610 0.000000000000 -vt 0.711153686047 0.804187417030 0.000000000000 -vt 0.712479650974 0.795391499996 0.000000000000 -vt 0.700650393963 0.775034308434 0.000000000000 -vt 0.691504657269 0.783996403217 0.000000000000 -vt 0.693565666676 0.777675151825 0.000000000000 -vt 0.691854059696 0.825260579586 0.000000000000 -vt 0.688908874989 0.815112352371 0.000000000000 -vt 0.713424861431 0.816177845001 0.000000000000 -vt 0.708342850208 0.825807273388 0.000000000000 -vt 0.699830830097 0.829423010349 0.000000000000 -vt 0.688347995281 0.804415702820 0.000000000000 -vt 0.715837776661 0.805065751076 0.000000000000 -vt 0.690926015377 0.790131390095 0.000000000000 -vt 0.686091244221 0.790077388287 0.000000000000 -vt 0.687085330486 0.783463239670 0.000000000000 -vt 0.717056095600 0.795820415020 0.000000000000 -vt 0.700017035007 0.770576894283 0.000000000000 -vt 0.914225161076 0.695051312447 0.000000000000 -vt 0.916345059872 0.684997260571 0.000000000000 -vt 0.924999296665 0.686340272427 0.000000000000 -vt 0.923253715038 0.697034716606 0.000000000000 -vt 0.917016923428 0.620534837246 0.000000000000 -vt 0.915503799915 0.609951913357 0.000000000000 -vt 0.924802958965 0.608696460724 0.000000000000 -vt 0.925778567791 0.619882166386 0.000000000000 -vt 0.912027418613 0.704157292843 0.000000000000 -vt 0.921499311924 0.705678403378 0.000000000000 -vt 0.918580591679 0.674305975437 0.000000000000 -vt 0.926661670208 0.674895882607 0.000000000000 -vt 0.718583166599 0.876050651073 0.000000000000 -vt 0.713863432407 0.879810035229 0.000000000000 -vt 0.710420310497 0.875060856342 0.000000000000 -vt 0.714020431042 0.871412634850 0.000000000000 -vt 0.697144329548 0.869657814503 0.000000000000 -vt 0.690142214298 0.873365402222 0.000000000000 -vt 0.686877906322 0.870136678219 0.000000000000 -vt 0.696207225323 0.865324914455 0.000000000000 -vt 0.723377764225 0.855088472366 0.000000000000 -vt 0.686818659306 0.880428075790 0.000000000000 -vt 0.681876957417 0.878385961056 0.000000000000 -vt 0.704877674580 0.870628654957 0.000000000000 -vt 0.706442534924 0.866614162922 0.000000000000 -vt 0.698146879673 0.874422729015 0.000000000000 -vt 0.693293511868 0.876017093658 0.000000000000 -vt 0.703139483929 0.874020636082 0.000000000000 -vt 0.692841827869 0.881317675114 0.000000000000 -vt 0.707678377628 0.883993208408 0.000000000000 -vt 0.705496728420 0.878273785114 0.000000000000 -vt 0.700505435467 0.886600732803 0.000000000000 -vt 0.710137546062 0.772817432880 0.000000000000 -vt 0.708110511303 0.775850474834 0.000000000000 -vt 0.686994135380 0.796237647533 0.000000000000 -vt 0.715639293194 0.780954062939 0.000000000000 -vt 0.691104710102 0.775407373905 0.000000000000 -vt 0.699277937412 0.880255401134 0.000000000000 -vt 0.685730040073 0.887317180634 0.000000000000 -vt 0.679790914059 0.885531485081 0.000000000000 -vt 0.918968498707 0.632217705250 0.000000000000 -vt 0.927030384541 0.632067978382 0.000000000000 -vt 0.920924723148 0.642282843590 0.000000000000 -vt 0.928346455097 0.642091691494 0.000000000000 -vt 0.920858919621 0.665029823780 0.000000000000 -vt 0.928194463253 0.665964901447 0.000000000000 -vt 0.717470824718 0.788531899452 0.000000000000 -vt 0.900251805782 0.692512214184 0.000000000000 -vt 0.693121254444 0.888164877892 0.000000000000 -vt 0.902859151363 0.682655394077 0.000000000000 -vt 0.903970539570 0.621789634228 0.000000000000 -vt 0.901585161686 0.612310171127 0.000000000000 -vt 0.898017823696 0.700807869434 0.000000000000 -vt 0.905948698521 0.673050761223 0.000000000000 -vt 0.906874597073 0.632321536541 0.000000000000 -vt 0.693904578686 0.898468434811 0.000000000000 -vt 0.684614479542 0.894367456436 0.000000000000 -vt 0.909317672253 0.643546879292 0.000000000000 -vt 0.731463849545 0.855961382389 0.000000000000 -vt 0.869329869747 0.669516265392 0.000000000000 -vt 0.870946586132 0.660611331463 0.000000000000 -vt 0.890423119068 0.661864340305 0.000000000000 -vt 0.888348281384 0.670855045319 0.000000000000 -vt 0.890978634357 0.652710914612 0.000000000000 -vt 0.702305495739 0.895358145237 0.000000000000 -vt 0.871763646603 0.652749598026 0.000000000000 -vt 0.882360517979 0.689871191978 0.000000000000 -vt 0.710604488850 0.892980515957 0.000000000000 -vt 0.717464387417 0.885056376457 0.000000000000 -vt 0.730221688747 0.863188624382 0.000000000000 -vt 0.722860634327 0.863828301430 0.000000000000 -vt 0.714506924152 0.854860365391 0.000000000000 -vt 0.713789999485 0.863633096218 0.000000000000 -vt 0.724120557308 0.846761763096 0.000000000000 -vt 0.730854570866 0.849116206169 0.000000000000 -vt 0.714706599712 0.846446990967 0.000000000000 -vt 0.706338703632 0.855344653130 0.000000000000 -vt 0.707510411739 0.848723769188 0.000000000000 -vt 0.707069814205 0.861884772778 0.000000000000 -vt 0.678365886211 0.892260015011 0.000000000000 -vt 0.722407639027 0.880594253540 0.000000000000 -vt 0.885312139988 0.679928541183 0.000000000000 -vt 0.886436760426 0.624270200729 0.000000000000 -vt 0.883410274982 0.615363061428 0.000000000000 -vt 0.879997313023 0.698587834835 0.000000000000 -vt 0.889629900455 0.633672416210 0.000000000000 -vt 0.909305155277 0.662700593472 0.000000000000 -vt 0.891184151173 0.643255293369 0.000000000000 -vt 0.871766149998 0.644696950912 0.000000000000 -vt 0.907031238079 0.653394460678 0.000000000000 -vt 0.865283668041 0.687783956528 0.000000000000 -vt 0.867546260357 0.678728938103 0.000000000000 -vt 0.868419826031 0.627362251282 0.000000000000 -vt 0.866138994694 0.618586599827 0.000000000000 -vt 0.862232387066 0.696758449078 0.000000000000 -vt 0.870358645916 0.636041104794 0.000000000000 -vt 0.858235895634 0.685826241970 0.000000000000 -vt 0.858604013920 0.677683055401 0.000000000000 -vt 0.860833942890 0.667493700981 0.000000000000 -vt 0.863862931728 0.659794270992 0.000000000000 -vt 0.864249050617 0.652788579464 0.000000000000 -vt 0.864739954472 0.645918428898 0.000000000000 -vt 0.861379206181 0.638689100742 0.000000000000 -vt 0.859226524830 0.628483951092 0.000000000000 -vt 0.858618676662 0.620088815689 0.000000000000 -vt 0.856225430965 0.613054513931 0.000000000000 -vt 0.914761722088 0.600589513779 0.000000000000 -vt 0.924306929111 0.599584639072 0.000000000000 -vt 0.900618851185 0.603945910931 0.000000000000 -vt 0.882335126400 0.606884181499 0.000000000000 -vt 0.864254891872 0.609210252762 0.000000000000 -vt 0.854927241802 0.691868305206 0.000000000000 -vt 0.837422072887 0.841993212700 0.000000000000 -vt 0.887628972530 0.127281382680 0.000000000000 -vt 0.891492426395 0.109981805086 0.000000000000 -vt 0.853538930416 0.841780006886 0.000000000000 -vt 0.446142524481 0.173150673509 0.000000000000 -vt 0.852221906185 0.869813799858 0.000000000000 -vt 0.834832131863 0.866848766804 0.000000000000 -vt 0.827377617359 0.891240715981 0.000000000000 -vt 0.844508349895 0.896685421467 0.000000000000 -vt 0.876590073109 0.913664817810 0.000000000000 -vt 0.631155192852 0.291285961866 0.000000000000 -vt 0.626378953457 0.296571254730 0.000000000000 -vt 0.619356811047 0.293236494064 0.000000000000 -vt 0.617115795612 0.281405717134 0.000000000000 -vt 0.627076447010 0.304564028978 0.000000000000 -vt 0.612752139568 0.299342244864 0.000000000000 -vt 0.603455007076 0.284176468849 0.000000000000 -vt 0.551565110683 0.292362421751 0.000000000000 -vt 0.563377797604 0.287606924772 0.000000000000 -vt 0.575475394726 0.299903571606 0.000000000000 -vt 0.558976709843 0.303807973862 0.000000000000 -vt 0.562288582325 0.307399660349 0.000000000000 -vt 0.579733312130 0.307971090078 0.000000000000 -vt 0.596043288708 0.307672083378 0.000000000000 -vt 0.594420373440 0.298339635134 0.000000000000 -vt 0.590357482433 0.287719279528 0.000000000000 -vt 0.579626619816 0.290383100510 0.000000000000 -vt 0.573159515858 0.282042890787 0.000000000000 -vt 0.578718960285 0.044730942696 0.000000000000 -vt 0.566518962383 0.050097059458 0.000000000000 -vt 0.561770737171 0.022569365799 0.000000000000 -vt 0.579452574253 0.019849490374 0.000000000000 -vt 0.557008445263 0.060779999942 0.000000000000 -vt 0.548213899136 0.048078324646 0.000000000000 -vt 0.693731248379 0.210530251265 0.000000000000 -vt 0.693874895573 0.194242313504 0.000000000000 -vt 0.701992332935 0.200576603413 0.000000000000 -vt 0.711977064610 0.218270197511 0.000000000000 -vt 0.698697388172 0.178742393851 0.000000000000 -vt 0.704717457294 0.185912460089 0.000000000000 -vt 0.903121650219 0.125584170222 0.000000000000 -vt 0.867082893848 0.928871572018 0.000000000000 -vt 0.847567975521 0.932113111019 0.000000000000 -vt 0.861807763577 0.903646290302 0.000000000000 -vt 0.874533474445 0.941229879856 0.000000000000 -vt 0.854254424572 0.953694105148 0.000000000000 -vt 0.828710377216 0.919355154037 0.000000000000 -vt 0.886985480785 0.898062467575 0.000000000000 -vt 0.872782289982 0.875068247318 0.000000000000 -vt 0.906435072422 0.912213265896 0.000000000000 -vt 0.907167255878 0.936152637005 0.000000000000 -vt 0.888857185841 0.925772547722 0.000000000000 -vt 0.894924700260 0.912269532681 0.000000000000 -vt 0.909523308277 0.137212976813 0.000000000000 -vt 0.900375425816 0.890851438046 0.000000000000 -vt 0.647988855839 0.030116569251 0.000000000000 -vt 0.663214385509 0.030034158379 0.000000000000 -vt 0.655444204807 0.048680160195 0.000000000000 -vt 0.633447468281 0.039773471653 0.000000000000 -vt 0.639170706272 0.061737354845 0.000000000000 -vt 0.625266969204 0.055919121951 0.000000000000 -vt 0.724736869335 0.892238378525 0.000000000000 -vt 0.741851985455 0.899839401245 0.000000000000 -vt 0.725909292698 0.912707686424 0.000000000000 -vt 0.713663756847 0.901688575745 0.000000000000 -vt 0.650711238384 0.327391177416 0.000000000000 -vt 0.634856283665 0.320250153542 0.000000000000 -vt 0.740120351315 0.933756113052 0.000000000000 -vt 0.722898066044 0.930224955082 0.000000000000 -vt 0.640473186970 0.306113332510 0.000000000000 -vt 0.652059733868 0.314922749996 0.000000000000 -vt 0.621949970722 0.313803285360 0.000000000000 -vt 0.583925902843 0.276038467884 0.000000000000 -vt 0.669873058796 0.330044180155 0.000000000000 -vt 0.663455307484 0.311076432467 0.000000000000 -vt 0.653194963932 0.296154946089 0.000000000000 -vt 0.537551581860 0.063254460692 0.000000000000 -vt 0.855031669140 0.035574551672 0.000000000000 -vt 0.837493717670 0.022007379681 0.000000000000 -vt 0.709798753262 0.290995299816 0.000000000000 -vt 0.720909416676 0.320390880108 0.000000000000 -vt 0.708561480045 0.322530746460 0.000000000000 -vt 0.747772991657 0.921521842480 0.000000000000 -vt 0.695623576641 0.297934114933 0.000000000000 -vt 0.680082261562 0.305459260941 0.000000000000 -vt 0.693427860737 0.329764753580 0.000000000000 -vt 0.681907594204 0.278335958719 0.000000000000 -vt 0.667823493481 0.287369400263 0.000000000000 -vt 0.667146265507 0.261673122644 0.000000000000 -vt 0.654371798038 0.271894037724 0.000000000000 -vt 0.641373217106 0.281966120005 0.000000000000 -vt 0.639975368977 0.258212238550 0.000000000000 -vt 0.628611147404 0.269090384245 0.000000000000 -vt 0.626621663570 0.244766697288 0.000000000000 -vt 0.616053998470 0.255464911461 0.000000000000 -vt 0.605184614658 0.264766514301 0.000000000000 -vt 0.605853140354 0.242097690701 0.000000000000 -vt 0.595517814159 0.250885695219 0.000000000000 -vt 0.585814058781 0.256739497185 0.000000000000 -vt 0.595492184162 0.270403504372 0.000000000000 -vt 0.574711024761 0.264054805040 0.000000000000 -vt 0.585790932178 0.239443764091 0.000000000000 -vt 0.572891771793 0.246539995074 0.000000000000 -vt 0.559696972370 0.254923403263 0.000000000000 -vt 0.577001988888 0.228986665606 0.000000000000 -vt 0.564495980740 0.234662607312 0.000000000000 -vt 0.551713407040 0.238481923938 0.000000000000 -vt 0.545511305332 0.261512130499 0.000000000000 -vt 0.538646757603 0.241494938731 0.000000000000 -vt 0.661286294460 0.149169623852 0.000000000000 -vt 0.643085420132 0.133995741606 0.000000000000 -vt 0.684797942638 0.147779509425 0.000000000000 -vt 0.676565825939 0.159141749144 0.000000000000 -vt 0.630804598331 0.144728660583 0.000000000000 -vt 0.649197280407 0.162055477500 0.000000000000 -vt 0.669700562954 0.172124639153 0.000000000000 -vt 0.633624017239 0.171124503016 0.000000000000 -vt 0.617616355419 0.157551243901 0.000000000000 -vt 0.624203979969 0.183554634452 0.000000000000 -vt 0.607319533825 0.173306703568 0.000000000000 -vt 0.645736873150 0.185071289539 0.000000000000 -vt 0.638931095600 0.196221649647 0.000000000000 -vt 0.601086556911 0.187993124127 0.000000000000 -vt 0.617492735386 0.196533486247 0.000000000000 -vt 0.632214725018 0.207936018705 0.000000000000 -vt 0.654465734959 0.209547683597 0.000000000000 -vt 0.646386682987 0.221093416214 0.000000000000 -vt 0.611703574657 0.208597302437 0.000000000000 -vt 0.624510347843 0.219911128283 0.000000000000 -vt 0.636621057987 0.233212843537 0.000000000000 -vt 0.661210715771 0.235190823674 0.000000000000 -vt 0.651021778584 0.247041419148 0.000000000000 -vt 0.615979254246 0.231477782130 0.000000000000 -vt 0.605249464512 0.220229938626 0.000000000000 -vt 0.596773326397 0.230893954635 0.000000000000 -vt 0.592077195644 0.211689129472 0.000000000000 -vt 0.586139500141 0.221562415361 0.000000000000 -vt 0.596748054028 0.200712144375 0.000000000000 -vt 0.686020314693 0.238807246089 0.000000000000 -vt 0.677805483341 0.250549525023 0.000000000000 -vt 0.669185936451 0.222903206944 0.000000000000 -vt 0.691701591015 0.226273551583 0.000000000000 -vt 0.675190150738 0.210060581565 0.000000000000 -vt 0.660946547985 0.197643056512 0.000000000000 -vt 0.679371058941 0.196919396520 0.000000000000 -vt 0.665786325932 0.185841768980 0.000000000000 -vt 0.653169095516 0.177967861295 0.000000000000 -vt 0.682948529720 0.183452650905 0.000000000000 -vt 0.688856303692 0.169335424900 0.000000000000 -vt 0.712051331997 0.240907743573 0.000000000000 -vt 0.705046594143 0.257047295570 0.000000000000 -vt 0.693947613239 0.268588751554 0.000000000000 -vt 0.846441566944 0.016312304884 0.000000000000 -vt 0.725233733654 0.280963063240 0.000000000000 -vt 0.864230215549 0.027330722660 0.000000000000 -vt 0.867542684078 0.077758729458 0.000000000000 -vt 0.873992264271 0.059032347053 0.000000000000 -vt 0.900698363781 0.073607310653 0.000000000000 -vt 0.893409788609 0.088153243065 0.000000000000 -vt 0.837527215481 0.094833135605 0.000000000000 -vt 0.838087618351 0.073169842362 0.000000000000 -vt 0.864491522312 0.098964735866 0.000000000000 -vt 0.839568436146 0.049210395664 0.000000000000 -vt 0.838048279285 0.117027804255 0.000000000000 -vt 0.862743914127 0.119909122586 0.000000000000 -vt 0.839784204960 0.140174224973 0.000000000000 -vt 0.862825214863 0.142299681902 0.000000000000 -vt 0.887471616268 0.147722780704 0.000000000000 -vt 0.864518344402 0.167147815228 0.000000000000 -vt 0.760909855366 0.908550620079 0.000000000000 -vt 0.702537238598 0.924268066883 0.000000000000 -vt 0.688291251659 0.928146779537 0.000000000000 -vt 0.681064426899 0.908967435360 0.000000000000 -vt 0.690809547901 0.908960223198 0.000000000000 -vt 0.831720411777 0.965238690376 0.000000000000 -vt 0.609436690807 0.309842139482 0.000000000000 -vt 0.841262519360 0.982780098915 0.000000000000 -vt 0.824164688587 0.990950345993 0.000000000000 -vt 0.813748776913 0.974472284317 0.000000000000 -vt 0.803931534290 0.981341362000 0.000000000000 -vt 0.813704669476 0.995644569397 0.000000000000 -vt 0.821433365345 0.949445426464 0.000000000000 -vt 0.802491247654 0.961359918118 0.000000000000 -vt 0.792442619801 0.969731867313 0.000000000000 -vt 0.808618605137 0.936246752739 0.000000000000 -vt 0.791009962559 0.950495541096 0.000000000000 -vt 0.780412495136 0.960320413113 0.000000000000 -vt 0.779733002186 0.938618302345 0.000000000000 -vt 0.769098222256 0.949621915817 0.000000000000 -vt 0.795302093029 0.925809264183 0.000000000000 -vt 0.779587566853 0.917365670204 0.000000000000 -vt 0.765330970287 0.930258750916 0.000000000000 -vt 0.755919754505 0.940638661385 0.000000000000 -vt 0.888226568699 0.171349883080 0.000000000000 -vt 0.910776436329 0.175429016352 0.000000000000 -vt 0.910029232502 0.154122352600 0.000000000000 -vt 0.931366503239 0.177302077413 0.000000000000 -vt 0.929215371609 0.158224686980 0.000000000000 -vt 0.927563607693 0.146612986922 0.000000000000 -vt 0.907406389713 0.225816711783 0.000000000000 -vt 0.909843504429 0.199414119124 0.000000000000 -vt 0.930679738522 0.201603308320 0.000000000000 -vt 0.928200304508 0.226828783751 0.000000000000 -vt 0.887493193150 0.252168864012 0.000000000000 -vt 0.887319624424 0.224217891693 0.000000000000 -vt 0.907594621181 0.252231895924 0.000000000000 -vt 0.932080924511 0.253668844700 0.000000000000 -vt 0.888279378414 0.197011262178 0.000000000000 -vt 0.868254363537 0.222412139177 0.000000000000 -vt 0.866531431675 0.193962886930 0.000000000000 -vt 0.850991070271 0.254400819540 0.000000000000 -vt 0.425416767597 0.169557422400 0.000000000000 -vt 0.527126252651 0.054304089397 0.000000000000 -vt 0.537031948566 0.037999924272 0.000000000000 -vt 0.594819605350 0.021248605102 0.000000000000 -vt 0.593616664410 0.041817199439 0.000000000000 -vt 0.611463606358 0.039550118148 0.000000000000 -vt 0.612102329731 0.021802034229 0.000000000000 -vt 0.629308164120 0.021318852901 0.000000000000 -vt 0.684654057026 0.026047337800 0.000000000000 -vt 0.686814010143 0.010275442153 0.000000000000 -vt 0.813150346279 0.910948097706 0.000000000000 -vt 0.795561254025 0.902303934097 0.000000000000 -vt 0.708547055721 0.008438628167 0.000000000000 -vt 0.706763446331 0.024136669934 0.000000000000 -vt 0.681121885777 0.042657937855 0.000000000000 -vt 0.703326165676 0.040577050298 0.000000000000 -vt 0.679071128368 0.059330899268 0.000000000000 -vt 0.697736203671 0.057211738080 0.000000000000 -vt 0.679068386555 0.075802132487 0.000000000000 -vt 0.694422185421 0.074145883322 0.000000000000 -vt 0.660856544971 0.065091490746 0.000000000000 -vt 0.664182245731 0.079712390900 0.000000000000 -vt 0.667562067509 0.093277320266 0.000000000000 -vt 0.658718883991 0.094275429845 0.000000000000 -vt 0.653593957424 0.083498373628 0.000000000000 -vt 0.562429010868 0.070872798562 0.000000000000 -vt 0.561431109905 0.091275691986 0.000000000000 -vt 0.651631176472 0.096843779087 0.000000000000 -vt 0.566199004650 0.079591929913 0.000000000000 -vt 0.568919837475 0.088470026851 0.000000000000 -vt 0.576352179050 0.086408510804 0.000000000000 -vt 0.573891699314 0.075738176703 0.000000000000 -vt 0.570575177670 0.065078660846 0.000000000000 -vt 0.584147036076 0.084593981504 0.000000000000 -vt 0.582864105701 0.072689130902 0.000000000000 -vt 0.580894887447 0.060486171395 0.000000000000 -vt 0.593160688877 0.083160415292 0.000000000000 -vt 0.593804895878 0.070337161422 0.000000000000 -vt 0.593818604946 0.057107713073 0.000000000000 -vt 0.603601753712 0.082686245441 0.000000000000 -vt 0.606147468090 0.069071784616 0.000000000000 -vt 0.609074890614 0.054980006069 0.000000000000 -vt 0.614769279957 0.083682104945 0.000000000000 -vt 0.619084775448 0.069891348481 0.000000000000 -vt 0.610922992229 0.095825180411 0.000000000000 -vt 0.601321876049 0.094617664814 0.000000000000 -vt 0.622694909573 0.086109951138 0.000000000000 -vt 0.617340266705 0.097710400820 0.000000000000 -vt 0.629761517048 0.073689267039 0.000000000000 -vt 0.629895031452 0.090603604913 0.000000000000 -vt 0.623498737812 0.100945651531 0.000000000000 -vt 0.638310372829 0.080408573151 0.000000000000 -vt 0.638113796711 0.097320660949 0.000000000000 -vt 0.645590126514 0.088923722506 0.000000000000 -vt 0.647677242756 0.071726813912 0.000000000000 -vt 0.631511867046 0.105762854218 0.000000000000 -vt 0.638789474964 0.110335975885 0.000000000000 -vt 0.562276422977 0.105178341269 0.000000000000 -vt 0.630611360073 0.128678917885 0.000000000000 -vt 0.623610913754 0.125340327621 0.000000000000 -vt 0.626384556293 0.114658728242 0.000000000000 -vt 0.569847881794 0.105211660266 0.000000000000 -vt 0.570068538189 0.114621803164 0.000000000000 -vt 0.570002615452 0.097111940384 0.000000000000 -vt 0.577380478382 0.104798287153 0.000000000000 -vt 0.576979458332 0.114249393344 0.000000000000 -vt 0.577486932278 0.096096485853 0.000000000000 -vt 0.584565103054 0.104308113456 0.000000000000 -vt 0.583777844906 0.114008486271 0.000000000000 -vt 0.584677040577 0.095082387328 0.000000000000 -vt 0.591241061687 0.104193970561 0.000000000000 -vt 0.589022576809 0.114581719041 0.000000000000 -vt 0.592356622219 0.094391390681 0.000000000000 -vt 0.598587095737 0.105026379228 0.000000000000 -vt 0.594260156155 0.115820080042 0.000000000000 -vt 0.586750924587 0.143253445625 0.000000000000 -vt 0.588111102581 0.125869661570 0.000000000000 -vt 0.593005359173 0.127749264240 0.000000000000 -vt 0.591630995274 0.144661337137 0.000000000000 -vt 0.596110045910 0.146092429757 0.000000000000 -vt 0.598921716213 0.130493223667 0.000000000000 -vt 0.601200044155 0.117737725377 0.000000000000 -vt 0.600308954716 0.147598937154 0.000000000000 -vt 0.605599582195 0.133385121822 0.000000000000 -vt 0.608710825443 0.120034545660 0.000000000000 -vt 0.604579865932 0.149645149708 0.000000000000 -vt 0.611486494541 0.135846063495 0.000000000000 -vt 0.615960538387 0.122533097863 0.000000000000 -vt 0.608992874622 0.150967940688 0.000000000000 -vt 0.617690265179 0.137778565288 0.000000000000 -vt 0.624459326267 0.140183672309 0.000000000000 -vt 0.613782465458 0.152489989996 0.000000000000 -vt 0.570089280605 0.125959947705 0.000000000000 -vt 0.557442963123 0.275540649891 0.000000000000 -vt 0.566006243229 0.270970880985 0.000000000000 -vt 0.775371730328 0.893757700920 0.000000000000 -vt 0.808763206005 0.883916676044 0.000000000000 -vt 0.559562146664 0.264112442732 0.000000000000 -vt 0.554663598537 0.266600191593 0.000000000000 -vt 0.848581612110 0.221785306931 0.000000000000 -vt 0.393582761288 0.484183341265 0.000000000000 -vt 0.396767795086 0.480453461409 0.000000000000 -vt 0.400794714689 0.480809420347 0.000000000000 -vt 0.399765521288 0.485055834055 0.000000000000 -vt 0.439470499754 0.511713802814 0.000000000000 -vt 0.440386444330 0.513542473316 0.000000000000 -vt 0.437012046576 0.514041662216 0.000000000000 -vt 0.437573134899 0.511677742004 0.000000000000 -vt 0.422013103962 0.460037946701 0.000000000000 -vt 0.418047666550 0.470334529877 0.000000000000 -vt 0.412509530783 0.468371391296 0.000000000000 -vt 0.414865106344 0.458373844624 0.000000000000 -vt 0.429023534060 0.476388931274 0.000000000000 -vt 0.423462659121 0.473014324903 0.000000000000 -vt 0.429314196110 0.462833255529 0.000000000000 -vt 0.436214298010 0.467371255159 0.000000000000 -vt 0.406041711569 0.475491911173 0.000000000000 -vt 0.406945496798 0.467524141073 0.000000000000 -vt 0.410694092512 0.476356506348 0.000000000000 -vt 0.435092151165 0.452288359404 0.000000000000 -vt 0.438309162855 0.447881609201 0.000000000000 -vt 0.359971135855 0.090370342135 0.000000000000 -vt 0.368420302868 0.099629849195 0.000000000000 -vt 0.362833082676 0.104876860976 0.000000000000 -vt 0.354921132326 0.096900969744 0.000000000000 -vt 0.352515369654 0.130700588226 0.000000000000 -vt 0.345492541790 0.124132826924 0.000000000000 -vt 0.349532276392 0.119571164250 0.000000000000 -vt 0.358871489763 0.128728002310 0.000000000000 -vt 0.438525289297 0.449985921383 0.000000000000 -vt 0.439274400473 0.451704740524 0.000000000000 -vt 0.449622303247 0.464140743017 0.000000000000 -vt 0.448981046677 0.460056871176 0.000000000000 -vt 0.450336039066 0.460677176714 0.000000000000 -vt 0.452015697956 0.460444808006 0.000000000000 -vt 0.425263881683 0.450979530811 0.000000000000 -vt 0.453179091215 0.473780065775 0.000000000000 -vt 0.449453443289 0.477478682995 0.000000000000 -vt 0.442929327488 0.472293376923 0.000000000000 -vt 0.441622525454 0.459930330515 0.000000000000 -vt 0.444129645824 0.456388652325 0.000000000000 -vt 0.373616009951 0.118581384420 0.000000000000 -vt 0.375112146139 0.115701422095 0.000000000000 -vt 0.377992779016 0.117945536971 0.000000000000 -vt 0.375868886709 0.120479449630 0.000000000000 -vt 0.382243275642 0.107223436236 0.000000000000 -vt 0.383732229471 0.103787556291 0.000000000000 -vt 0.386310935020 0.106139764190 0.000000000000 -vt 0.384451150894 0.109020173550 0.000000000000 -vt 0.409286201000 0.450759083033 0.000000000000 -vt 0.408566385508 0.458585023880 0.000000000000 -vt 0.376690715551 0.126454398036 0.000000000000 -vt 0.381214976311 0.120371833444 0.000000000000 -vt 0.403114914894 0.459155589342 0.000000000000 -vt 0.403876841068 0.452309519053 0.000000000000 -vt 0.454835981131 0.482029527426 0.000000000000 -vt 0.457485169172 0.479463666677 0.000000000000 -vt 0.384555608034 0.122786611319 0.000000000000 -vt 0.382433533669 0.128221631050 0.000000000000 -vt 0.385892122984 0.114606484771 0.000000000000 -vt 0.389199435711 0.119001969695 0.000000000000 -vt 0.416368693113 0.447328180075 0.000000000000 -vt 0.461556434631 0.440214395523 0.000000000000 -vt 0.354810804129 0.135790005326 0.000000000000 -vt 0.356487303972 0.133928865194 0.000000000000 -vt 0.459117084742 0.440935134888 0.000000000000 -vt 0.359035402536 0.136161059141 0.000000000000 -vt 0.356604158878 0.137259811163 0.000000000000 -vt 0.456829965115 0.439723789692 0.000000000000 -vt 0.458451539278 0.437272518873 0.000000000000 -vt 0.454769343138 0.438526421785 0.000000000000 -vt 0.454550951719 0.435967743397 0.000000000000 -vt 0.441826075315 0.444921255112 0.000000000000 -vt 0.443551659584 0.442011803389 0.000000000000 -vt 0.448256731033 0.443818241358 0.000000000000 -vt 0.446299463511 0.446265220642 0.000000000000 -vt 0.455544114113 0.449857115746 0.000000000000 -vt 0.458855003119 0.454671829939 0.000000000000 -vt 0.455724000931 0.457280248404 0.000000000000 -vt 0.453310787678 0.452473431826 0.000000000000 -vt 0.450308114290 0.448847740889 0.000000000000 -vt 0.386408418417 0.101448193192 0.000000000000 -vt 0.387978881598 0.103007167578 0.000000000000 -vt 0.452250301838 0.446324646473 0.000000000000 -vt 0.447152793407 0.437671035528 0.000000000000 -vt 0.450194656849 0.436007380486 0.000000000000 -vt 0.452898085117 0.439646780491 0.000000000000 -vt 0.450881361961 0.441238403320 0.000000000000 -vt 0.458574026823 0.443444490433 0.000000000000 -vt 0.463303625584 0.444895386696 0.000000000000 -vt 0.462563782930 0.448778629303 0.000000000000 -vt 0.457480877638 0.446133941412 0.000000000000 -vt 0.454026341438 0.443802684546 0.000000000000 -vt 0.359097301960 0.132905989885 0.000000000000 -vt 0.361074864864 0.134876102209 0.000000000000 -vt 0.455461025238 0.441745221615 0.000000000000 -vt 0.444298267365 0.448686748743 0.000000000000 -vt 0.442074418068 0.450537770987 0.000000000000 -vt 0.439655810595 0.449115246534 0.000000000000 -vt 0.441199243069 0.447540730238 0.000000000000 -vt 0.451972931623 0.458101630211 0.000000000000 -vt 0.450596332550 0.459385693073 0.000000000000 -vt 0.449565351009 0.457458138466 0.000000000000 -vt 0.450939685106 0.454803764820 0.000000000000 -vt 0.446267724037 0.453737437725 0.000000000000 -vt 0.397592544556 0.132566675544 0.000000000000 -vt 0.395102560520 0.138213351369 0.000000000000 -vt 0.392103701830 0.135889068246 0.000000000000 -vt 0.395304739475 0.130839735270 0.000000000000 -vt 0.399295836687 0.125662967563 0.000000000000 -vt 0.402231425047 0.128127291799 0.000000000000 -vt 0.404049992561 0.137433633208 0.000000000000 -vt 0.405965834856 0.138806402683 0.000000000000 -vt 0.404163688421 0.144568577409 0.000000000000 -vt 0.448208779097 0.451402574778 0.000000000000 -vt 0.449387699366 0.442756623030 0.000000000000 -vt 0.445775300264 0.440066248178 0.000000000000 -vt 0.459970653057 0.451159417629 0.000000000000 -vt 0.456270694733 0.448136717081 0.000000000000 -vt 0.400764316320 0.142388850451 0.000000000000 -vt 0.410871744156 0.135244905949 0.000000000000 -vt 0.407858490944 0.132529079914 0.000000000000 -vt 0.389080792665 0.131361424923 0.000000000000 -vt 0.387762486935 0.129610389471 0.000000000000 -vt 0.389104187489 0.126333042979 0.000000000000 -vt 0.390812218189 0.127695217729 0.000000000000 -vt 0.391797959805 0.123638600111 0.000000000000 -vt 0.393867135048 0.124303475022 0.000000000000 -vt 0.390969157219 0.132123574615 0.000000000000 -vt 0.392821729183 0.129185527563 0.000000000000 -vt 0.395075976849 0.126136258245 0.000000000000 -vt 0.398736566305 0.138166293502 0.000000000000 -vt 0.397700846195 0.136793285608 0.000000000000 -vt 0.399035334587 0.133746489882 0.000000000000 -vt 0.400510340929 0.134889379144 0.000000000000 -vt 0.401520818472 0.131361871958 0.000000000000 -vt 0.403166472912 0.131912827492 0.000000000000 -vt 0.400330662727 0.138775110245 0.000000000000 -vt 0.402200579643 0.136118054390 0.000000000000 -vt 0.404188245535 0.133363723755 0.000000000000 -vt 0.385480999947 0.131040126085 0.000000000000 -vt 0.387488692999 0.124964997172 0.000000000000 -vt 0.392740219831 0.120471790433 0.000000000000 -vt 0.397779881954 0.121211871505 0.000000000000 -vt 0.388019412756 0.135536253452 0.000000000000 -vt 0.406621724367 0.128388255835 0.000000000000 -vt 0.396779060364 0.141935378313 0.000000000000 -vt 0.409657478333 0.141405150294 0.000000000000 -vt 0.408238559961 0.143032342196 0.000000000000 -vt 0.452826261520 0.445473134518 0.000000000000 -vt 0.398223191500 0.453096210957 0.000000000000 -vt 0.397748589516 0.459203541279 0.000000000000 -vt 0.461537957191 0.483292669058 0.000000000000 -vt 0.458966463804 0.486215561628 0.000000000000 -vt 0.417104929686 0.441364258528 0.000000000000 -vt 0.418126702309 0.442871898413 0.000000000000 -vt 0.420422822237 0.444641411304 0.000000000000 -vt 0.433500528336 0.448079735041 0.000000000000 -vt 0.436020672321 0.448221594095 0.000000000000 -vt 0.427099138498 0.446181684732 0.000000000000 -vt 0.438960522413 0.423234313726 0.000000000000 -vt 0.436720907688 0.424649864435 0.000000000000 -vt 0.407253503799 0.142381638288 0.000000000000 -vt 0.408249586821 0.140351876616 0.000000000000 -vt 0.434051692486 0.423569798470 0.000000000000 -vt 0.434879601002 0.420804440975 0.000000000000 -vt 0.431214749813 0.423123985529 0.000000000000 -vt 0.430086702108 0.420641422272 0.000000000000 -vt 0.419274091721 0.434574037790 0.000000000000 -vt 0.420379161835 0.430852890015 0.000000000000 -vt 0.426141530275 0.431651085615 0.000000000000 -vt 0.424853444099 0.434927970171 0.000000000000 -vt 0.436181217432 0.434532612562 0.000000000000 -vt 0.441298097372 0.437351107597 0.000000000000 -vt 0.439914047718 0.441069751978 0.000000000000 -vt 0.435192108154 0.437948435545 0.000000000000 -vt 0.430372446775 0.435908526182 0.000000000000 -vt 0.410810738802 0.139599621296 0.000000000000 -vt 0.409828603268 0.138812705874 0.000000000000 -vt 0.431275308132 0.432643771172 0.000000000000 -vt 0.423234343529 0.424417972565 0.000000000000 -vt 0.425667136908 0.422001600266 0.000000000000 -vt 0.429718136787 0.424738824368 0.000000000000 -vt 0.428410202265 0.426783442497 0.000000000000 -vt 0.437025994062 0.426789969206 0.000000000000 -vt 0.441838681698 0.426870137453 0.000000000000 -vt 0.442383557558 0.430333465338 0.000000000000 -vt 0.436957329512 0.429274797440 0.000000000000 -vt 0.432621270418 0.428078770638 0.000000000000 -vt 0.414452850819 0.144986689091 0.000000000000 -vt 0.409147053957 0.147766679525 0.000000000000 -vt 0.433331876993 0.425908029079 0.000000000000 -vt 0.423957765102 0.438147932291 0.000000000000 -vt 0.422544687986 0.441486746073 0.000000000000 -vt 0.418296456337 0.441183239222 0.000000000000 -vt 0.419304251671 0.438087821007 0.000000000000 -vt 0.437636613846 0.443893879652 0.000000000000 -vt 0.436708301306 0.446964770555 0.000000000000 -vt 0.433489710093 0.444419175386 0.000000000000 -vt 0.434133440256 0.441165685654 0.000000000000 -vt 0.428444206715 0.442456930876 0.000000000000 -vt 0.408575177193 0.144754558802 0.000000000000 -vt 0.411639750004 0.142881035805 0.000000000000 -vt 0.406258314848 0.142990231514 0.000000000000 -vt 0.407059431076 0.139547616243 0.000000000000 -vt 0.410056680441 0.137724533677 0.000000000000 -vt 0.415505886078 0.139094606042 0.000000000000 -vt 0.412565827370 0.139450341463 0.000000000000 -vt 0.364202499390 0.128939658403 0.000000000000 -vt 0.366093575954 0.126167103648 0.000000000000 -vt 0.429390072823 0.439258158207 0.000000000000 -vt 0.427526712418 0.428991526365 0.000000000000 -vt 0.422490209341 0.427620559931 0.000000000000 -vt 0.441317677498 0.433453887701 0.000000000000 -vt 0.436557680368 0.431637555361 0.000000000000 -vt 0.368825376034 0.128782272339 0.000000000000 -vt 0.366221219301 0.131002977490 0.000000000000 -vt 0.377708643675 0.113558173180 0.000000000000 -vt 0.379947811365 0.115249529481 0.000000000000 -vt 0.368792057037 0.124293580651 0.000000000000 -vt 0.370973348618 0.126337096095 0.000000000000 -vt 0.379835903645 0.132157340646 0.000000000000 -vt 0.374702155590 0.134804278612 0.000000000000 -vt 0.371608525515 0.131661787629 0.000000000000 -vt 0.385006606579 0.145867496729 0.000000000000 -vt 0.380806565285 0.150551855564 0.000000000000 -vt 0.378436356783 0.147939816117 0.000000000000 -vt 0.383413165808 0.143897384405 0.000000000000 -vt 0.388382792473 0.140254378319 0.000000000000 -vt 0.390580326319 0.142940923572 0.000000000000 -vt 0.389787077904 0.151387169957 0.000000000000 -vt 0.391084223986 0.152869373560 0.000000000000 -vt 0.387653529644 0.157836511731 0.000000000000 -vt 0.385402202606 0.155462026596 0.000000000000 -vt 0.396483421326 0.150470122695 0.000000000000 -vt 0.394613981247 0.147955358028 0.000000000000 -vt 0.377133131027 0.143021076918 0.000000000000 -vt 0.431962937117 0.430194556713 0.000000000000 -vt 0.398509591818 0.449473470449 0.000000000000 -vt 0.403451532125 0.447545230389 0.000000000000 -vt 0.412772059441 0.443381220102 0.000000000000 -vt 0.415262728930 0.442666351795 0.000000000000 -vt 0.408193081617 0.445362567902 0.000000000000 -vt 0.402572304010 0.417491078377 0.000000000000 -vt 0.401636779308 0.420146107674 0.000000000000 -vt 0.376334518194 0.141268029809 0.000000000000 -vt 0.378864586353 0.138637766242 0.000000000000 -vt 0.398579388857 0.420967459679 0.000000000000 -vt 0.397203922272 0.418318748474 0.000000000000 -vt 0.395930439234 0.422812163830 0.000000000000 -vt 0.393101811409 0.421740859747 0.000000000000 -vt 0.393963277340 0.440714478493 0.000000000000 -vt 0.392591178417 0.436948060989 0.000000000000 -vt 0.397990405560 0.434073746204 0.000000000000 -vt 0.399504780769 0.437697380781 0.000000000000 -vt 0.408009588718 0.428790479898 0.000000000000 -vt 0.414924532175 0.428841352463 0.000000000000 -vt 0.416294604540 0.432789921761 0.000000000000 -vt 0.409434139729 0.432349741459 0.000000000000 -vt 0.404077023268 0.434443891048 0.000000000000 -vt 0.380261212587 0.140083029866 0.000000000000 -vt 0.382164925337 0.137022957206 0.000000000000 -vt 0.402819514275 0.430790752172 0.000000000000 -vt 0.390489786863 0.430026113987 0.000000000000 -vt 0.390550136566 0.426381319761 0.000000000000 -vt 0.395857959986 0.425411134958 0.000000000000 -vt 0.396276742220 0.428331613541 0.000000000000 -vt 0.403288513422 0.421578973532 0.000000000000 -vt 0.408246427774 0.418946474791 0.000000000000 -vt 0.411142379045 0.421542286873 0.000000000000 -vt 0.405009150505 0.423732370138 0.000000000000 -vt 0.400750786066 0.425774753094 0.000000000000 -vt 0.383944779634 0.138014540076 0.000000000000 -vt 0.378778368235 0.144098669291 0.000000000000 -vt 0.399727702141 0.423417359591 0.000000000000 -vt 0.400881379843 0.440771222115 0.000000000000 -vt 0.401966422796 0.443919539452 0.000000000000 -vt 0.396847724915 0.446899026632 0.000000000000 -vt 0.396342486143 0.443651407957 0.000000000000 -vt 0.415956437588 0.436509907246 0.000000000000 -vt 0.416573584080 0.440072774887 0.000000000000 -vt 0.411374956369 0.439379304647 0.000000000000 -vt 0.410169273615 0.436066806316 0.000000000000 -vt 0.406326770782 0.441095888615 0.000000000000 -vt 0.381734192371 0.141807720065 0.000000000000 -vt 0.384717941284 0.139707922935 0.000000000000 -vt 0.384294420481 0.151226192713 0.000000000000 -vt 0.383655220270 0.149787440896 0.000000000000 -vt 0.386135309935 0.147063747048 0.000000000000 -vt 0.387247562408 0.148301199079 0.000000000000 -vt 0.389312237501 0.145468518138 0.000000000000 -vt 0.390688598156 0.146293267608 0.000000000000 -vt 0.385713368654 0.152030900121 0.000000000000 -vt 0.405239045620 0.437882453203 0.000000000000 -vt 0.396997690201 0.430689215660 0.000000000000 -vt 0.392160445452 0.433128327131 0.000000000000 -vt 0.412164151669 0.424938082695 0.000000000000 -vt 0.406307399273 0.426028043032 0.000000000000 -vt 0.388458669186 0.149755924940 0.000000000000 -vt 0.391224920750 0.147718727589 0.000000000000 -vt 0.373405694962 0.142156943679 0.000000000000 -vt 0.377377659082 0.137248560786 0.000000000000 -vt 0.383390426636 0.134469017386 0.000000000000 -vt 0.387974828482 0.136217564344 0.000000000000 -vt 0.374564796686 0.146659821272 0.000000000000 -vt 0.394345581532 0.144419968128 0.000000000000 -vt 0.381775170565 0.154543623328 0.000000000000 -vt 0.393369078636 0.155557274818 0.000000000000 -vt 0.391563802958 0.156876459718 0.000000000000 -vt 0.390937179327 0.156117007136 0.000000000000 -vt 0.392488509417 0.154420018196 0.000000000000 -vt 0.395006179810 0.154078006744 0.000000000000 -vt 0.394348293543 0.153221741319 0.000000000000 -vt 0.396971106529 0.159922137856 0.000000000000 -vt 0.391263425350 0.161551579833 0.000000000000 -vt 0.391377806664 0.158593714237 0.000000000000 -vt 0.394818872213 0.157320469618 0.000000000000 -vt 0.389807134867 0.156631037593 0.000000000000 -vt 0.391787588596 0.153602257371 0.000000000000 -vt 0.395006865263 0.152312338352 0.000000000000 -vt 0.401779532433 0.428116351366 0.000000000000 -vt 0.452458798885 0.462447345257 0.000000000000 -vt 0.452626556158 0.465537369251 0.000000000000 -vt 0.459379166365 0.476943254471 0.000000000000 -vt 0.462601810694 0.480663985014 0.000000000000 -vt 0.455803722143 0.471922338009 0.000000000000 -vt 0.479603260756 0.461800038815 0.000000000000 -vt 0.477074772120 0.461461395025 0.000000000000 -vt 0.399524837732 0.154673993587 0.000000000000 -vt 0.396705895662 0.154279291630 0.000000000000 -vt 0.475300759077 0.459207594395 0.000000000000 -vt 0.477906495333 0.457540988922 0.000000000000 -vt 0.473629444838 0.457062989473 0.000000000000 -vt 0.474505990744 0.454424381256 0.000000000000 -vt 0.457420319319 0.456922262907 0.000000000000 -vt 0.460104405880 0.454761892557 0.000000000000 -vt 0.463730514050 0.459742784500 0.000000000000 -vt 0.461280167103 0.461182653904 0.000000000000 -vt 0.469485044479 0.469264149666 0.000000000000 -vt 0.472566455603 0.474419951439 0.000000000000 -vt 0.469833135605 0.475842684507 0.000000000000 -vt 0.467271775007 0.470811873674 0.000000000000 -vt 0.464453041553 0.465783476830 0.000000000000 -vt 0.371207743883 0.139285087585 0.000000000000 -vt 0.356069415808 0.140628591180 0.000000000000 -vt 0.466606199741 0.464368134737 0.000000000000 -vt 0.466347038746 0.452607154846 0.000000000000 -vt 0.470105797052 0.452469378710 0.000000000000 -vt 0.471197992563 0.457316517830 0.000000000000 -vt 0.468378633261 0.458023726940 0.000000000000 -vt 0.475411504507 0.463598579168 0.000000000000 -vt 0.478970795870 0.466784060001 0.000000000000 -vt 0.476854532957 0.469994544983 0.000000000000 -vt 0.473139971495 0.465840876102 0.000000000000 -vt 0.470534920692 0.462002217770 0.000000000000 -vt 0.361092180014 0.138868093491 0.000000000000 -vt 0.362757891417 0.141520425677 0.000000000000 -vt 0.473011165857 0.460577666759 0.000000000000 -vt 0.458834081888 0.463209271431 0.000000000000 -vt 0.456127494574 0.464871376753 0.000000000000 -vt 0.453364372253 0.461712449789 0.000000000000 -vt 0.455975264311 0.460149645805 0.000000000000 -vt 0.466653943062 0.476451963186 0.000000000000 -vt 0.464873641729 0.479033142328 0.000000000000 -vt 0.462096124887 0.474372893572 0.000000000000 -vt 0.464624851942 0.472282111645 0.000000000000 -vt 0.459239572287 0.469601660967 0.000000000000 -vt 0.358396410942 0.143731668591 0.000000000000 -vt 0.366143107414 0.136179968715 0.000000000000 -vt 0.367462068796 0.140748366714 0.000000000000 -vt 0.367624849081 0.152154952288 0.000000000000 -vt 0.363851904869 0.154144421220 0.000000000000 -vt 0.362488389015 0.151757776737 0.000000000000 -vt 0.366743355989 0.150309801102 0.000000000000 -vt 0.370945870876 0.149034306407 0.000000000000 -vt 0.371946483850 0.151283830404 0.000000000000 -vt 0.461986482143 0.467537879944 0.000000000000 -vt 0.466021031141 0.459026336670 0.000000000000 -vt 0.463648796082 0.454296290874 0.000000000000 -vt 0.474090546370 0.471629172564 0.000000000000 -vt 0.471038132906 0.467538326979 0.000000000000 -vt 0.369695812464 0.157271832228 0.000000000000 -vt 0.370106279850 0.158484742045 0.000000000000 -vt 0.366340100765 0.161045432091 0.000000000000 -vt 0.365696161985 0.158691659570 0.000000000000 -vt 0.374921888113 0.158001109958 0.000000000000 -vt 0.373830109835 0.155684486032 0.000000000000 -vt 0.362566053867 0.147848188877 0.000000000000 -vt 0.362277865410 0.146466180682 0.000000000000 -vt 0.364509135485 0.145325541496 0.000000000000 -vt 0.365181237459 0.146691560745 0.000000000000 -vt 0.366957485676 0.145109176636 0.000000000000 -vt 0.367903143167 0.146292820573 0.000000000000 -vt 0.363559901714 0.149057939649 0.000000000000 -vt 0.365885078907 0.148352980614 0.000000000000 -vt 0.368204176426 0.147704318166 0.000000000000 -vt 0.366324573755 0.155576184392 0.000000000000 -vt 0.366173952818 0.154380381107 0.000000000000 -vt 0.368186831474 0.153372362256 0.000000000000 -vt 0.368705600500 0.154601037502 0.000000000000 -vt 0.370330303907 0.152888730168 0.000000000000 -vt 0.371147632599 0.153870403767 0.000000000000 -vt 0.367092341185 0.156595915556 0.000000000000 -vt 0.369238078594 0.155905812979 0.000000000000 -vt 0.371273934841 0.155043467879 0.000000000000 -vt 0.359594911337 0.146293044090 0.000000000000 -vt 0.363820612431 0.143866091967 0.000000000000 -vt 0.368623167276 0.143500894308 0.000000000000 -vt 0.468312889338 0.463350683451 0.000000000000 -vt 0.396901309490 0.467744559050 0.000000000000 -vt 0.401809483767 0.467451632023 0.000000000000 -vt 0.371416240931 0.146074414253 0.000000000000 -vt 0.359569907188 0.149919614196 0.000000000000 -vt 0.374465495348 0.153269469738 0.000000000000 -vt 0.414790123701 0.478396862745 0.000000000000 -vt 0.447205245495 0.489582329988 0.000000000000 -vt 0.452684849501 0.491852372885 0.000000000000 -vt 0.449784398079 0.494581252337 0.000000000000 -vt 0.442751228809 0.493985742331 0.000000000000 -vt 0.434156626463 0.494034796953 0.000000000000 -vt 0.440118283033 0.488046973944 0.000000000000 -vt 0.434461027384 0.500024855137 0.000000000000 -vt 0.430395841599 0.501698195934 0.000000000000 -vt 0.425874501467 0.499181836843 0.000000000000 -vt 0.446397393942 0.499464601278 0.000000000000 -vt 0.440220713615 0.499364227057 0.000000000000 -vt 0.434654891491 0.512679457664 0.000000000000 -vt 0.435968428850 0.511407136917 0.000000000000 -vt 0.443066686392 0.505874812603 0.000000000000 -vt 0.438906043768 0.505390286446 0.000000000000 -vt 0.439353436232 0.502900302410 0.000000000000 -vt 0.444775164127 0.503243684769 0.000000000000 -vt 0.435113310814 0.505446374416 0.000000000000 -vt 0.434737980366 0.503206968307 0.000000000000 -vt 0.447127133608 0.507210433483 0.000000000000 -vt 0.449805349112 0.505035459995 0.000000000000 -vt 0.363566637039 0.157027080655 0.000000000000 -vt 0.371184110641 0.161255732179 0.000000000000 -vt 0.431567996740 0.505946636200 0.000000000000 -vt 0.430854707956 0.504090666771 0.000000000000 -vt 0.369521766901 0.161624297500 0.000000000000 -vt 0.369182020426 0.160728856921 0.000000000000 -vt 0.370721399784 0.159941717982 0.000000000000 -vt 0.372713804245 0.160549417138 0.000000000000 -vt 0.372284442186 0.159536883235 0.000000000000 -vt 0.372968226671 0.165679350495 0.000000000000 -vt 0.452052175999 0.500936031342 0.000000000000 -vt 0.368058949709 0.165135830641 0.000000000000 -vt 0.368970602751 0.162820771337 0.000000000000 -vt 0.371845602989 0.162883594632 0.000000000000 -vt 0.368251889944 0.160784929991 0.000000000000 -vt 0.370353937149 0.159135669470 0.000000000000 -vt 0.440568357706 0.509817063808 0.000000000000 -vt 0.437990337610 0.509382963181 0.000000000000 -vt 0.435604155064 0.509494423866 0.000000000000 -vt 0.443635433912 0.511720776558 0.000000000000 -vt 0.373006284237 0.158982783556 0.000000000000 -vt 0.376509696245 0.162375643849 0.000000000000 -vt 0.374031394720 0.161057814956 0.000000000000 -vt 0.389625668526 0.108183041215 0.000000000000 -vt 0.393046200275 0.109792903066 0.000000000000 -vt 0.392523407936 0.116342663765 0.000000000000 -vt 0.432401984930 0.510016977787 0.000000000000 -vt 0.438322216272 0.506984829903 0.000000000000 -vt 0.441790044308 0.507623851299 0.000000000000 -vt 0.435307621956 0.507277548313 0.000000000000 -vt 0.444958448410 0.509229838848 0.000000000000 -vt 0.392005532980 0.101636424661 0.000000000000 -vt 0.395671516657 0.103756263852 0.000000000000 -vt 0.407296061516 0.115123912692 0.000000000000 -vt 0.406397461891 0.121328055859 0.000000000000 -vt 0.403196871281 0.120348632336 0.000000000000 -vt 0.404978096485 0.114345774055 0.000000000000 -vt 0.432492733002 0.507707357407 0.000000000000 -vt 0.406864881516 0.108425304294 0.000000000000 -vt 0.409913033247 0.109619542956 0.000000000000 -vt 0.414692848921 0.117440745234 0.000000000000 -vt 0.416797161102 0.118163943291 0.000000000000 -vt 0.416874825954 0.124142721295 0.000000000000 -vt 0.413157969713 0.123205170035 0.000000000000 -vt 0.420296519995 0.113394036889 0.000000000000 -vt 0.416648089886 0.111873343587 0.000000000000 -vt 0.399549156427 0.117066100240 0.000000000000 -vt 0.397761642933 0.115746006370 0.000000000000 -vt 0.444640964270 0.482646912336 0.000000000000 -vt 0.435251086950 0.480776757002 0.000000000000 -vt 0.412997663021 0.489607781172 0.000000000000 -vt 0.415611475706 0.485968559980 0.000000000000 -vt 0.419600337744 0.489331930876 0.000000000000 -vt 0.418021112680 0.495383232832 0.000000000000 -vt 0.418760269880 0.480955928564 0.000000000000 -vt 0.451327174902 0.485552281141 0.000000000000 -vt 0.397986561060 0.111830547452 0.000000000000 -vt 0.400141090155 0.112691327929 0.000000000000 -vt 0.399654954672 0.108637854457 0.000000000000 -vt 0.401813089848 0.108847483993 0.000000000000 -vt 0.401618987322 0.117125526071 0.000000000000 -vt 0.402521193027 0.113518998027 0.000000000000 -vt 0.403585493565 0.110106542706 0.000000000000 -vt 0.409883081913 0.119960919023 0.000000000000 -vt 0.455791562796 0.489336222410 0.000000000000 -vt 0.422770082951 0.483635991812 0.000000000000 -vt 0.423145622015 0.491761177778 0.000000000000 -vt 0.408528327942 0.119000181556 0.000000000000 -vt 0.408956587315 0.115644469857 0.000000000000 -vt 0.410606950521 0.116135522723 0.000000000000 -vt 0.410386979580 0.112677589059 0.000000000000 -vt 0.421489149332 0.498041182756 0.000000000000 -vt 0.426815658808 0.486486226320 0.000000000000 -vt 0.430106759071 0.489818543196 0.000000000000 -vt 0.434814959764 0.486344844103 0.000000000000 -vt 0.426011174917 0.493239969015 0.000000000000 -vt 0.405869930983 0.480812519789 0.000000000000 -vt 0.412047952414 0.112628281116 0.000000000000 -vt 0.406924337149 0.485618025064 0.000000000000 -vt 0.401090562344 0.475320100784 0.000000000000 -vt 0.396311402321 0.475648850203 0.000000000000 -vt 0.411765158176 0.482897728682 0.000000000000 -vt 0.409521043301 0.480445533991 0.000000000000 -vt 0.453219145536 0.496879428625 0.000000000000 -vt 0.411550819874 0.119953945279 0.000000000000 -vt 0.412490606308 0.116729035974 0.000000000000 -vt 0.413484215736 0.113597795367 0.000000000000 -vt 0.395627617836 0.118285313249 0.000000000000 -vt 0.396080166101 0.111090466380 0.000000000000 -vt 0.399283915758 0.105090305209 0.000000000000 -vt 0.404269516468 0.104768797755 0.000000000000 -vt 0.398505777121 0.120832040906 0.000000000000 -vt 0.413978666067 0.108735352755 0.000000000000 -vt 0.409310519695 0.124303475022 0.000000000000 -vt 0.420999675989 0.119554504752 0.000000000000 -vt 0.420234143734 0.121525302529 0.000000000000 -vt 0.419045567513 0.121159419417 0.000000000000 -vt 0.419289410114 0.118994310498 0.000000000000 -vt 0.421489626169 0.117538690567 0.000000000000 -vt 0.420303285122 0.117139488459 0.000000000000 -vt 0.426694989204 0.121457740664 0.000000000000 -vt 0.422340482473 0.125688865781 0.000000000000 -vt 0.420924037695 0.122998699546 0.000000000000 -vt 0.423304349184 0.120309680700 0.000000000000 -vt 0.418264955282 0.122074902058 0.000000000000 -vt 0.417998820543 0.118570342660 0.000000000000 -vt 0.420178323984 0.115989848971 0.000000000000 -vt 0.425800204277 0.115537062287 0.000000000000 -vt 0.423050165176 0.116810753942 0.000000000000 -vt 0.377677112818 0.108308449388 0.000000000000 -vt 0.380777746439 0.100671857595 0.000000000000 -vt 0.387641370296 0.097277656198 0.000000000000 -vt 0.368460386992 0.119178041816 0.000000000000 -vt 0.370848834515 0.112134292722 0.000000000000 -vt 0.361701697111 0.122205942869 0.000000000000 -vt 0.350305467844 0.135973051190 0.000000000000 -vt 0.358212679625 0.109973028302 0.000000000000 -vt 0.353615224361 0.114691153169 0.000000000000 -vt 0.374976605177 0.093655571342 0.000000000000 -vt 0.389860272408 0.064062759280 0.000000000000 -vt 0.392403393984 0.070562094450 0.000000000000 -vt 0.387591153383 0.070836335421 0.000000000000 -vt 0.386600703001 0.064674735069 0.000000000000 -vt 0.390128880739 0.057090383023 0.000000000000 -vt 0.385809719563 0.057704154402 0.000000000000 -vt 0.381569832563 0.070360124111 0.000000000000 -vt 0.378056943417 0.070291683078 0.000000000000 -vt 0.376780331135 0.065116941929 0.000000000000 -vt 0.571491539478 0.142689660192 0.000000000000 -vt 0.576072752476 0.124807611108 0.000000000000 -vt 0.575986921787 0.141870543361 0.000000000000 -vt 0.787393748760 0.876816630363 0.000000000000 -vt 0.764766037464 0.871043145657 0.000000000000 -vt 0.754721701145 0.886201500893 0.000000000000 -vt 0.742770016193 0.866340160370 0.000000000000 -vt 0.734950125217 0.879857540131 0.000000000000 -vt 0.639134943485 0.405957043171 0.000000000000 -vt 0.626996815205 0.399863898754 0.000000000000 -vt 0.634920418262 0.394428640604 0.000000000000 -vt 0.639219582081 0.397930711508 0.000000000000 -vt 0.634795248508 0.383935958147 0.000000000000 -vt 0.643223226070 0.392979323864 0.000000000000 -vt 0.621101796627 0.387013614178 0.000000000000 -vt 0.588396847248 0.330318629742 0.000000000000 -vt 0.604378163815 0.331369876862 0.000000000000 -vt 0.613536059856 0.349697083235 0.000000000000 -vt 0.593470990658 0.343456894159 0.000000000000 -vt 0.615174353123 0.332106143236 0.000000000000 -vt 0.627085506916 0.345775991678 0.000000000000 -vt 0.635642707348 0.359163492918 0.000000000000 -vt 0.624931395054 0.369269371033 0.000000000000 -vt 0.614598810673 0.373340398073 0.000000000000 -vt 0.608756959438 0.360698610544 0.000000000000 -vt 0.595678865910 0.357187539339 0.000000000000 -vt 0.436208903790 0.152205392718 0.000000000000 -vt 0.456390678883 0.160455301404 0.000000000000 -vt 0.470007836819 0.150451436639 0.000000000000 -vt 0.463308125734 0.141743332148 0.000000000000 -vt 0.426335632801 0.240489169955 0.000000000000 -vt 0.436077862978 0.227415770292 0.000000000000 -vt 0.568314850330 0.508301794529 0.000000000000 -vt 0.585736811161 0.522079706192 0.000000000000 -vt 0.563862621784 0.526518404484 0.000000000000 -vt 0.552698671818 0.519208967686 0.000000000000 -vt 0.611942946911 0.313467800617 0.000000000000 -vt 0.543040931225 0.535523951054 0.000000000000 -vt 0.869499862194 0.252641230822 0.000000000000 -vt 0.794922888279 0.858771979809 0.000000000000 -vt 0.771254837513 0.855260670185 0.000000000000 -vt 0.747811377048 0.852186858654 0.000000000000 -vt 0.797975599766 0.840329766273 0.000000000000 -vt 0.773927867413 0.839067518711 0.000000000000 -vt 0.750024020672 0.837795853615 0.000000000000 -vt 0.816554009914 0.862926125526 0.000000000000 -vt 0.819631397724 0.841430306435 0.000000000000 -vt 0.863419592381 0.971586704254 0.000000000000 -vt 0.886208474636 0.956715881824 0.000000000000 -vt 0.845495879650 0.192380949855 0.000000000000 -vt 0.921158373356 0.909126162529 0.000000000000 -vt 0.928987085819 0.927418887615 0.000000000000 -vt 0.914810121059 0.888543367386 0.000000000000 -vt 0.449255734682 0.250441461802 0.000000000000 -vt 0.429135203362 0.255882352591 0.000000000000 -vt 0.454719811678 0.222426101565 0.000000000000 -vt 0.463549941778 0.236386403441 0.000000000000 -vt 0.480748862028 0.132810741663 0.000000000000 -vt 0.460707813501 0.129074752331 0.000000000000 -vt 0.890980184078 0.866303682327 0.000000000000 -vt 0.906893670559 0.863792300224 0.000000000000 -vt 0.901800453663 0.838266909122 0.000000000000 -vt 0.885961711407 0.839472353458 0.000000000000 -vt 0.672634780407 0.403682291508 0.000000000000 -vt 0.870305716991 0.840758919716 0.000000000000 -vt 0.709015905857 0.913828730583 0.000000000000 -vt 0.702005445957 0.906553089619 0.000000000000 -vt 0.664313495159 0.411870300770 0.000000000000 -vt 0.651246488094 0.405295312405 0.000000000000 -vt 0.658828794956 0.392099201679 0.000000000000 -vt 0.648704469204 0.380986869335 0.000000000000 -vt 0.598465621471 0.371364206076 0.000000000000 -vt 0.649795591831 0.422901540995 0.000000000000 -vt 0.666176021099 0.425574362278 0.000000000000 -vt 0.478667050600 0.121633604169 0.000000000000 -vt 0.439155727625 0.188678041101 0.000000000000 -vt 0.419110178947 0.186491340399 0.000000000000 -vt 0.828646361828 0.222074419260 0.000000000000 -vt 0.825475156307 0.193224608898 0.000000000000 -vt 0.842488110065 0.165252909064 0.000000000000 -vt 0.821768820286 0.166762799025 0.000000000000 -vt 0.836636006832 0.816951870918 0.000000000000 -vt 0.852425515652 0.813404560089 0.000000000000 -vt 0.638719737530 0.461908787489 0.000000000000 -vt 0.645538747311 0.442247092724 0.000000000000 -vt 0.666097700596 0.445383280516 0.000000000000 -vt 0.662395417690 0.464661508799 0.000000000000 -vt 0.617127835751 0.458045125008 0.000000000000 -vt 0.627697288990 0.440409153700 0.000000000000 -vt 0.635399162769 0.421377927065 0.000000000000 -vt 0.609715163708 0.435786485672 0.000000000000 -vt 0.619829595089 0.417641699314 0.000000000000 -vt 0.590706527233 0.430238008499 0.000000000000 -vt 0.600633800030 0.414015561342 0.000000000000 -vt 0.605100929737 0.397916287184 0.000000000000 -vt 0.580789983273 0.413832962513 0.000000000000 -vt 0.585207521915 0.396601408720 0.000000000000 -vt 0.583855688572 0.381996691227 0.000000000000 -vt 0.602939188480 0.384962439537 0.000000000000 -vt 0.583396375179 0.371497720480 0.000000000000 -vt 0.567030251026 0.398448109627 0.000000000000 -vt 0.565822064877 0.380739450455 0.000000000000 -vt 0.565940558910 0.366790413857 0.000000000000 -vt 0.546947419643 0.397279322147 0.000000000000 -vt 0.547453343868 0.381623625755 0.000000000000 -vt 0.546291291714 0.366621524096 0.000000000000 -vt 0.529646694660 0.384682595730 0.000000000000 -vt 0.528711616993 0.373113870621 0.000000000000 -vt 0.526230156422 0.363655120134 0.000000000000 -vt 0.543110311031 0.353565901518 0.000000000000 -vt 0.560514271259 0.346006095409 0.000000000000 -vt 0.521848142147 0.354256451130 0.000000000000 -vt 0.537153065205 0.340497672558 0.000000000000 -vt 0.550614297390 0.329262435436 0.000000000000 -vt 0.573693096638 0.334259301424 0.000000000000 -vt 0.565188109875 0.321530610323 0.000000000000 -vt 0.481604665518 0.473584860563 0.000000000000 -vt 0.503952205181 0.484111279249 0.000000000000 -vt 0.523758590221 0.503893256187 0.000000000000 -vt 0.516087591648 0.344791620970 0.000000000000 -vt 0.508227407932 0.335609555244 0.000000000000 -vt 0.518797814846 0.319672405720 0.000000000000 -vt 0.510983765125 0.468507856131 0.000000000000 -vt 0.490077227354 0.435670107603 0.000000000000 -vt 0.502925693989 0.448421299458 0.000000000000 -vt 0.522674977779 0.457363337278 0.000000000000 -vt 0.530655562878 0.477804929018 0.000000000000 -vt 0.538420259953 0.463601946831 0.000000000000 -vt 0.515796720982 0.440703213215 0.000000000000 -vt 0.534934461117 0.448625057936 0.000000000000 -vt 0.549823939800 0.452839523554 0.000000000000 -vt 0.557107031345 0.466927945614 0.000000000000 -vt 0.568541586399 0.456593096256 0.000000000000 -vt 0.547232806683 0.441114574671 0.000000000000 -vt 0.561775863171 0.442336261272 0.000000000000 -vt 0.578855931759 0.444288581610 0.000000000000 -vt 0.586479246616 0.463815152645 0.000000000000 -vt 0.597201764584 0.451105147600 0.000000000000 -vt 0.571721136570 0.429578959942 0.000000000000 -vt 0.557132422924 0.430043905973 0.000000000000 -vt 0.564029395580 0.415538519621 0.000000000000 -vt 0.537347137928 0.424302697182 0.000000000000 -vt 0.544077932835 0.411527603865 0.000000000000 -vt 0.518473088741 0.418114066124 0.000000000000 -vt 0.524959385395 0.408595174551 0.000000000000 -vt 0.528635084629 0.397043138742 0.000000000000 -vt 0.509449779987 0.404620736837 0.000000000000 -vt 0.513173401356 0.395612955093 0.000000000000 -vt 0.514248788357 0.385702759027 0.000000000000 -vt 0.513777077198 0.377086073160 0.000000000000 -vt 0.512884557247 0.370190680027 0.000000000000 -vt 0.510034501553 0.363916963339 0.000000000000 -vt 0.505580484867 0.356326758862 0.000000000000 -vt 0.500341594219 0.348006844521 0.000000000000 -vt 0.481183856726 0.423593431711 0.000000000000 -vt 0.500625789165 0.430742353201 0.000000000000 -vt 0.490146607161 0.420840919018 0.000000000000 -vt 0.498169153929 0.417084664106 0.000000000000 -vt 0.510002553463 0.425448060036 0.000000000000 -vt 0.527178347111 0.433869749308 0.000000000000 -vt 0.503946959972 0.411769419909 0.000000000000 -vt 0.596737325191 0.484501451254 0.000000000000 -vt 0.576489269733 0.474731117487 0.000000000000 -vt 0.606985628605 0.472689867020 0.000000000000 -vt 0.584141671658 0.495642870665 0.000000000000 -vt 0.563076555729 0.485377997160 0.000000000000 -vt 0.546334922314 0.479332834482 0.000000000000 -vt 0.550337493420 0.497008413076 0.000000000000 -vt 0.537908732891 0.494894415140 0.000000000000 -vt 0.526974737644 0.490041226149 0.000000000000 -vt 0.537790954113 0.509640336037 0.000000000000 -vt 0.527427136898 0.525675892830 0.000000000000 -vt 0.605959832668 0.507260859013 0.000000000000 -vt 0.620633423328 0.493587821722 0.000000000000 -vt 0.631438195705 0.478594750166 0.000000000000 -vt 0.817847788334 0.142355754972 0.000000000000 -vt 0.814487040043 0.119411304593 0.000000000000 -vt 0.658278763294 0.481082051992 0.000000000000 -vt 0.811750113964 0.097056999803 0.000000000000 -vt 0.809368431568 0.075157731771 0.000000000000 -vt 0.807133018970 0.053564000875 0.000000000000 -vt 0.831686437130 0.254841685295 0.000000000000 -vt 0.856208741665 0.293983995914 0.000000000000 -vt 0.835455358028 0.290136784315 0.000000000000 -vt 0.873124063015 0.283648252487 0.000000000000 -vt 0.889739573002 0.279546380043 0.000000000000 -vt 0.909207642078 0.276814579964 0.000000000000 -vt 0.929072201252 0.276617109776 0.000000000000 -vt 0.884098351002 0.044427882880 0.000000000000 -vt 0.824312150478 0.028333339840 0.000000000000 -vt 0.804996788502 0.032941136509 0.000000000000 -vt 0.745384037495 0.153986141086 0.000000000000 -vt 0.727315604687 0.170344561338 0.000000000000 -vt 0.831523954868 0.792076110840 0.000000000000 -vt 0.846453726292 0.786361873150 0.000000000000 -vt 0.871971428394 0.766853511333 0.000000000000 -vt 0.860507428646 0.778107702732 0.000000000000 -vt 0.849813520908 0.750272214413 0.000000000000 -vt 0.864782273769 0.752571046352 0.000000000000 -vt 0.641757309437 0.369858145714 0.000000000000 -vt 0.871010005474 0.740061163902 0.000000000000 -vt 0.856036365032 0.728532135487 0.000000000000 -vt 0.833810746670 0.763259589672 0.000000000000 -vt 0.880542218685 0.781249523163 0.000000000000 -vt 0.870216548443 0.805862307549 0.000000000000 -vt 0.895947515965 0.765040814877 0.000000000000 -vt 0.886363804340 0.766362249851 0.000000000000 -vt 0.881665766239 0.753908455372 0.000000000000 -vt 0.896844565868 0.741948008537 0.000000000000 -vt 0.892329037189 0.786806523800 0.000000000000 -vt 0.730150520802 0.779693901539 0.000000000000 -vt 0.720385253429 0.768897235394 0.000000000000 -vt 0.732248246670 0.757981956005 0.000000000000 -vt 0.746850073338 0.773370444775 0.000000000000 -vt 0.746807038784 0.737674295902 0.000000000000 -vt 0.754076421261 0.750202596188 0.000000000000 -vt 0.729847013950 0.741506457329 0.000000000000 -vt 0.766269385815 0.766434729099 0.000000000000 -vt 0.732167899609 0.725132286549 0.000000000000 -vt 0.744101583958 0.727173089981 0.000000000000 -vt 0.726897180080 0.154936745763 0.000000000000 -vt 0.736608207226 0.138647675514 0.000000000000 -vt 0.757733404636 0.048427533358 0.000000000000 -vt 0.748305857182 0.039854753762 0.000000000000 -vt 0.762275159359 0.025697443634 0.000000000000 -vt 0.771673381329 0.029945448041 0.000000000000 -vt 0.737863123417 0.066377580166 0.000000000000 -vt 0.730143487453 0.052494283766 0.000000000000 -vt 0.754568159580 0.099855229259 0.000000000000 -vt 0.731352865696 0.116734221578 0.000000000000 -vt 0.725217759609 0.099748730659 0.000000000000 -vt 0.746904551983 0.081010863185 0.000000000000 -vt 0.718968212605 0.084019616246 0.000000000000 -vt 0.786774814129 0.105366572738 0.000000000000 -vt 0.761492788792 0.119630172849 0.000000000000 -vt 0.781676113605 0.084223598242 0.000000000000 -vt 0.775007426739 0.059413980693 0.000000000000 -vt 0.791212141514 0.126294299960 0.000000000000 -vt 0.767748415470 0.138232484460 0.000000000000 -vt 0.435300618410 0.206924617290 0.000000000000 -vt 0.415769994259 0.205245867372 0.000000000000 -vt 0.415477305651 0.223549634218 0.000000000000 -vt 0.415708750486 0.260153979063 0.000000000000 -vt 0.415216326714 0.241337999701 0.000000000000 -vt 0.431532442570 0.277840822935 0.000000000000 -vt 0.416861325502 0.282650142908 0.000000000000 -vt 0.437933146954 0.297910034657 0.000000000000 -vt 0.422700941563 0.304020076990 0.000000000000 -vt 0.710437953472 0.745294928551 0.000000000000 -vt 0.448528498411 0.274154812098 0.000000000000 -vt 0.453730016947 0.292313814163 0.000000000000 -vt 0.466458499432 0.272584140301 0.000000000000 -vt 0.470066845417 0.288187146187 0.000000000000 -vt 0.483627885580 0.271198511124 0.000000000000 -vt 0.486174434423 0.284226238728 0.000000000000 -vt 0.468398451805 0.256950020790 0.000000000000 -vt 0.484410136938 0.259565204382 0.000000000000 -vt 0.499547928572 0.260835975409 0.000000000000 -vt 0.488594621420 0.251296162605 0.000000000000 -vt 0.500861465931 0.255602240562 0.000000000000 -vt 0.476949125528 0.155961647630 0.000000000000 -vt 0.496368080378 0.154256105423 0.000000000000 -vt 0.493585199118 0.162589550018 0.000000000000 -vt 0.484565943480 0.159969419241 0.000000000000 -vt 0.504522025585 0.250607877970 0.000000000000 -vt 0.490841835737 0.170824587345 0.000000000000 -vt 0.479497641325 0.168406203389 0.000000000000 -vt 0.468820154667 0.165049582720 0.000000000000 -vt 0.487937420607 0.179314747453 0.000000000000 -vt 0.474618524313 0.178034290671 0.000000000000 -vt 0.461312592030 0.176021173596 0.000000000000 -vt 0.485546678305 0.188977956772 0.000000000000 -vt 0.470588952303 0.189741462469 0.000000000000 -vt 0.455546349287 0.189690113068 0.000000000000 -vt 0.484867841005 0.200385212898 0.000000000000 -vt 0.468716144562 0.203217670321 0.000000000000 -vt 0.452557861805 0.205941826105 0.000000000000 -vt 0.486695379019 0.212983325124 0.000000000000 -vt 0.470563501120 0.217475160956 0.000000000000 -vt 0.498891204596 0.197758778930 0.000000000000 -vt 0.500793755054 0.208588525653 0.000000000000 -vt 0.503768861294 0.215860128403 0.000000000000 -vt 0.490694373846 0.221827194095 0.000000000000 -vt 0.476610749960 0.228770300746 0.000000000000 -vt 0.508271515369 0.222307890654 0.000000000000 -vt 0.496900588274 0.229248985648 0.000000000000 -vt 0.485334604979 0.237566873431 0.000000000000 -vt 0.505223691463 0.237320348620 0.000000000000 -vt 0.495418399572 0.244713291526 0.000000000000 -vt 0.475383609533 0.245258644223 0.000000000000 -vt 0.514443337917 0.230237171054 0.000000000000 -vt 0.519902884960 0.237665936351 0.000000000000 -vt 0.511179625988 0.154767423868 0.000000000000 -vt 0.523703515530 0.224226221442 0.000000000000 -vt 0.534955561161 0.219976648688 0.000000000000 -vt 0.539630472660 0.226309135556 0.000000000000 -vt 0.522125780582 0.163012161851 0.000000000000 -vt 0.511400759220 0.162948891521 0.000000000000 -vt 0.502651274204 0.163395151496 0.000000000000 -vt 0.521724998951 0.170782491565 0.000000000000 -vt 0.510841667652 0.171353936195 0.000000000000 -vt 0.501311361790 0.171751782298 0.000000000000 -vt 0.521135985851 0.178479418159 0.000000000000 -vt 0.510029613972 0.179412469268 0.000000000000 -vt 0.499761670828 0.179692775011 0.000000000000 -vt 0.521464765072 0.184219524264 0.000000000000 -vt 0.509710252285 0.186720550060 0.000000000000 -vt 0.498645514250 0.187971740961 0.000000000000 -vt 0.522567331791 0.189815983176 0.000000000000 -vt 0.510646045208 0.194714680314 0.000000000000 -vt 0.552625119686 0.181308269501 0.000000000000 -vt 0.553095877171 0.186058148742 0.000000000000 -vt 0.535693705082 0.186998158693 0.000000000000 -vt 0.534666717052 0.182170838118 0.000000000000 -vt 0.553785145283 0.190441906452 0.000000000000 -vt 0.537737786770 0.193066775799 0.000000000000 -vt 0.524687230587 0.197172924876 0.000000000000 -vt 0.554820120335 0.194571927190 0.000000000000 -vt 0.540497124195 0.200262054801 0.000000000000 -vt 0.527609050274 0.205128788948 0.000000000000 -vt 0.556690990925 0.198639363050 0.000000000000 -vt 0.543533384800 0.206711396575 0.000000000000 -vt 0.531002581120 0.212646707892 0.000000000000 -vt 0.558761537075 0.202166423202 0.000000000000 -vt 0.546805322170 0.212670803070 0.000000000000 -vt 0.550771892071 0.218399211764 0.000000000000 -vt 0.561493337154 0.206085249782 0.000000000000 -vt 0.535221517086 0.163484767079 0.000000000000 -vt 0.552473127842 0.164653763175 0.000000000000 -vt 0.534547865391 0.169898986816 0.000000000000 -vt 0.552217543125 0.170028448105 0.000000000000 -vt 0.534365713596 0.176693260670 0.000000000000 -vt 0.552374064922 0.175845101476 0.000000000000 -vt 0.432602375746 0.133366212249 0.000000000000 -vt 0.579707443714 0.344648867846 0.000000000000 -vt 0.582962691784 0.359227657318 0.000000000000 -vt 0.699510276318 0.760418593884 0.000000000000 -vt 0.690002620220 0.760535240173 0.000000000000 -vt 0.573572456837 0.358697652817 0.000000000000 -vt 0.571034729481 0.348925471306 0.000000000000 -vt 0.795890152454 0.148126482964 0.000000000000 -vt 0.773672997952 0.158082619309 0.000000000000 -vt 0.761886537075 0.368884116411 0.000000000000 -vt 0.756864488125 0.374716073275 0.000000000000 -vt 0.752732694149 0.371530354023 0.000000000000 -vt 0.756020605564 0.368056684732 0.000000000000 -vt 0.745198905468 0.426691144705 0.000000000000 -vt 0.748513877392 0.424927502871 0.000000000000 -vt 0.751336514950 0.428736001253 0.000000000000 -vt 0.745641887188 0.430311173201 0.000000000000 -vt 0.718655884266 0.367600291967 0.000000000000 -vt 0.723707854748 0.362223118544 0.000000000000 -vt 0.731543242931 0.368654459715 0.000000000000 -vt 0.727982223034 0.373404115438 0.000000000000 -vt 0.723776161671 0.384299814701 0.000000000000 -vt 0.712015807629 0.382623314857 0.000000000000 -vt 0.714580357075 0.374560505152 0.000000000000 -vt 0.725447237492 0.378716200590 0.000000000000 -vt 0.743162930012 0.370530217886 0.000000000000 -vt 0.739214956760 0.374083191156 0.000000000000 -vt 0.736095726490 0.364764451981 0.000000000000 -vt 0.470379114151 0.072487622499 0.000000000000 -vt 0.476932018995 0.067091092467 0.000000000000 -vt 0.483967453241 0.075338751078 0.000000000000 -vt 0.477926939726 0.080794483423 0.000000000000 -vt 0.511079013348 0.066174268723 0.000000000000 -vt 0.508617579937 0.072203919291 0.000000000000 -vt 0.499857753515 0.062445472926 0.000000000000 -vt 0.504508316517 0.058762382716 0.000000000000 -vt 0.705864846706 0.371028959751 0.000000000000 -vt 0.701381266117 0.375573486090 0.000000000000 -vt 0.698225557804 0.370354384184 0.000000000000 -vt 0.697068870068 0.367405295372 0.000000000000 -vt 0.701902329922 0.391683101654 0.000000000000 -vt 0.691578447819 0.393901556730 0.000000000000 -vt 0.693959891796 0.392793804407 0.000000000000 -vt 0.699081957340 0.388415664434 0.000000000000 -vt 0.712482511997 0.363048106432 0.000000000000 -vt 0.706260859966 0.399656295776 0.000000000000 -vt 0.710350573063 0.390655279160 0.000000000000 -vt 0.709410727024 0.398413658142 0.000000000000 -vt 0.497506469488 0.086208790541 0.000000000000 -vt 0.499487847090 0.088523834944 0.000000000000 -vt 0.496975511312 0.090857118368 0.000000000000 -vt 0.494485110044 0.087826982141 0.000000000000 -vt 0.485454589128 0.095807611942 0.000000000000 -vt 0.487140089273 0.098796099424 0.000000000000 -vt 0.483731955290 0.100186884403 0.000000000000 -vt 0.481757134199 0.096767678857 0.000000000000 -vt 0.701098263264 0.382279485464 0.000000000000 -vt 0.704454600811 0.381990849972 0.000000000000 -vt 0.505547583103 0.089302882552 0.000000000000 -vt 0.507946908474 0.095191136003 0.000000000000 -vt 0.725627362728 0.354063272476 0.000000000000 -vt 0.730535089970 0.352071553469 0.000000000000 -vt 0.733845055103 0.356517255306 0.000000000000 -vt 0.729133427143 0.358981132507 0.000000000000 -vt 0.502358973026 0.098305702209 0.000000000000 -vt 0.499749034643 0.094421327114 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.499274820089 0.102383270860 0.000000000000 -vt 0.709335625172 0.404707193375 0.000000000000 -vt 0.707483947277 0.405635058880 0.000000000000 -vt 0.516392290592 0.069226473570 0.000000000000 -vt 0.518077909946 0.071355760098 0.000000000000 -vt 0.718284785748 0.355620443821 0.000000000000 -vt 0.516956746578 0.073715612292 0.000000000000 -vt 0.514483392239 0.070643588901 0.000000000000 -vt 0.668390452862 0.386624544859 0.000000000000 -vt 0.667060911655 0.380806088448 0.000000000000 -vt 0.671376407146 0.380861908197 0.000000000000 -vt 0.671312749386 0.384570688009 0.000000000000 -vt 0.669187486172 0.375094115734 0.000000000000 -vt 0.671998560429 0.377249538898 0.000000000000 -vt 0.691448748112 0.370133042336 0.000000000000 -vt 0.690848052502 0.375890284777 0.000000000000 -vt 0.686910808086 0.375525057316 0.000000000000 -vt 0.687306106091 0.369519740343 0.000000000000 -vt 0.686368644238 0.386486738920 0.000000000000 -vt 0.689943373203 0.386325776577 0.000000000000 -vt 0.688951313496 0.392648577690 0.000000000000 -vt 0.685665905476 0.393045514822 0.000000000000 -vt 0.690709650517 0.381118148565 0.000000000000 -vt 0.686853349209 0.380862385035 0.000000000000 -vt 0.480086654425 0.100869327784 0.000000000000 -vt 0.478839308023 0.098695233464 0.000000000000 -vt 0.678826630116 0.369220048189 0.000000000000 -vt 0.679812729359 0.375340670347 0.000000000000 -vt 0.675520837307 0.375914126635 0.000000000000 -vt 0.673433959484 0.370380729437 0.000000000000 -vt 0.674808919430 0.385995447636 0.000000000000 -vt 0.679343521595 0.386584460735 0.000000000000 -vt 0.678030192852 0.392984062433 0.000000000000 -vt 0.672598540783 0.391514003277 0.000000000000 -vt 0.680286943913 0.380828380585 0.000000000000 -vt 0.675836026669 0.380848854780 0.000000000000 -vt 0.515295088291 0.075423642993 0.000000000000 -vt 0.513281047344 0.073069870472 0.000000000000 -vt 0.693681657314 0.376642733812 0.000000000000 -vt 0.693711340427 0.371875762939 0.000000000000 -vt 0.696114480495 0.370918631554 0.000000000000 -vt 0.696933090687 0.376871287823 0.000000000000 -vt 0.691533505917 0.391513794661 0.000000000000 -vt 0.692914068699 0.386218369007 0.000000000000 -vt 0.695932805538 0.386784404516 0.000000000000 -vt 0.693213999271 0.392598807812 0.000000000000 -vt 0.693558990955 0.381606072187 0.000000000000 -vt 0.696726262569 0.381991982460 0.000000000000 -vt 0.512632310390 0.113346979022 0.000000000000 -vt 0.510703504086 0.110827267170 0.000000000000 -vt 0.515379965305 0.107007056475 0.000000000000 -vt 0.518175065517 0.110701844096 0.000000000000 -vt 0.505509078503 0.114236339927 0.000000000000 -vt 0.508307397366 0.117514595389 0.000000000000 -vt 0.518149077892 0.121353730559 0.000000000000 -vt 0.522928655148 0.117672875524 0.000000000000 -vt 0.525190651417 0.121514260769 0.000000000000 -vt 0.683571517467 0.375538796186 0.000000000000 -vt 0.683092653751 0.370623677969 0.000000000000 -vt 0.682278931141 0.392029613256 0.000000000000 -vt 0.683356225491 0.386358857155 0.000000000000 -vt 0.684057652950 0.380769610405 0.000000000000 -vt 0.519570291042 0.123483464122 0.000000000000 -vt 0.516307771206 0.128428325057 0.000000000000 -vt 0.513406455517 0.124672070146 0.000000000000 -vt 0.511565864086 0.103494629264 0.000000000000 -vt 0.507416427135 0.106189742684 0.000000000000 -vt 0.506013691425 0.103982776403 0.000000000000 -vt 0.509203732014 0.102665841579 0.000000000000 -vt 0.504296243191 0.108756288886 0.000000000000 -vt 0.503382742405 0.106384947896 0.000000000000 -vt 0.511651098728 0.106469616294 0.000000000000 -vt 0.509026229382 0.108525276184 0.000000000000 -vt 0.506196796894 0.110484585166 0.000000000000 -vt 0.518708407879 0.115314379334 0.000000000000 -vt 0.515459358692 0.117382884026 0.000000000000 -vt 0.514127433300 0.115409389138 0.000000000000 -vt 0.518203437328 0.112691774964 0.000000000000 -vt 0.512567102909 0.119688019156 0.000000000000 -vt 0.511780798435 0.117559626698 0.000000000000 -vt 0.519389688969 0.117316469550 0.000000000000 -vt 0.516777694225 0.119350507855 0.000000000000 -vt 0.514133274555 0.121143206954 0.000000000000 -vt 0.510631144047 0.099778667092 0.000000000000 -vt 0.504632174969 0.101817682385 0.000000000000 -vt 0.499871104956 0.106421664357 0.000000000000 -vt 0.500889837742 0.111934348941 0.000000000000 -vt 0.514839589596 0.101724907756 0.000000000000 -vt 0.509192049503 0.122385606170 0.000000000000 -vt 0.522657573223 0.113145455718 0.000000000000 -vt 0.522569835186 0.127797886729 0.000000000000 -vt 0.521396934986 0.126231938601 0.000000000000 -vt 0.735525667667 0.349380731583 0.000000000000 -vt 0.738029062748 0.353152751923 0.000000000000 -vt 0.709487140179 0.411515235901 0.000000000000 -vt 0.706850707531 0.412472575903 0.000000000000 -vt 0.713795721531 0.355628103018 0.000000000000 -vt 0.714886367321 0.349705845118 0.000000000000 -vt 0.715047299862 0.346170902252 0.000000000000 -vt 0.700704872608 0.366192162037 0.000000000000 -vt 0.705918371677 0.365258455276 0.000000000000 -vt 0.710480749607 0.361039042473 0.000000000000 -vt 0.523268878460 0.125216260552 0.000000000000 -vt 0.523997724056 0.126300171018 0.000000000000 -vt 0.687866628170 0.342219889164 0.000000000000 -vt 0.691187441349 0.337702393532 0.000000000000 -vt 0.693574011326 0.340425401926 0.000000000000 -vt 0.690801203251 0.342919677496 0.000000000000 -vt 0.696296155453 0.334926456213 0.000000000000 -vt 0.696642935276 0.338050007820 0.000000000000 -vt 0.711912453175 0.345587313175 0.000000000000 -vt 0.707153379917 0.348584800959 0.000000000000 -vt 0.704814493656 0.344684004784 0.000000000000 -vt 0.710185706615 0.341764390469 0.000000000000 -vt 0.695865690708 0.351892799139 0.000000000000 -vt 0.699073016644 0.355076700449 0.000000000000 -vt 0.695596873760 0.359068036079 0.000000000000 -vt 0.692301213741 0.356082707644 0.000000000000 -vt 0.702675044537 0.351823449135 0.000000000000 -vt 0.699874341488 0.348093301058 0.000000000000 -vt 0.520938813686 0.128895744681 0.000000000000 -vt 0.520082056522 0.127839773893 0.000000000000 -vt 0.705446422100 0.335541337729 0.000000000000 -vt 0.701623976231 0.340389162302 0.000000000000 -vt 0.699281990528 0.338887810707 0.000000000000 -vt 0.701398193836 0.333822280169 0.000000000000 -vt 0.691363513470 0.345513224602 0.000000000000 -vt 0.692718684673 0.347970575094 0.000000000000 -vt 0.688071906567 0.350903898478 0.000000000000 -vt 0.686495840549 0.347062766552 0.000000000000 -vt 0.697414934635 0.344720244408 0.000000000000 -vt 0.695644319057 0.342764317989 0.000000000000 -vt 0.526300132275 0.132303252816 0.000000000000 -vt 0.524093449116 0.129697531462 0.000000000000 -vt 0.709353864193 0.352346479893 0.000000000000 -vt 0.712929904461 0.348732739687 0.000000000000 -vt 0.714268267155 0.349192053080 0.000000000000 -vt 0.711979806423 0.354660391808 0.000000000000 -vt 0.699490010738 0.361016511917 0.000000000000 -vt 0.702696144581 0.358416646719 0.000000000000 -vt 0.704991638660 0.361978620291 0.000000000000 -vt 0.700050175190 0.364112406969 0.000000000000 -vt 0.705978453159 0.355808466673 0.000000000000 -vt 0.708694994450 0.358966708183 0.000000000000 -vt 0.525715887547 0.126499876380 0.000000000000 -vt 0.528771936893 0.126690357924 0.000000000000 -vt 0.523779094219 0.124067738652 0.000000000000 -vt 0.520451605320 0.124855801463 0.000000000000 -vt 0.518978536129 0.127953931689 0.000000000000 -vt 0.520814955235 0.130581036210 0.000000000000 -vt 0.520374357700 0.133407860994 0.000000000000 -vt 0.508442223072 0.077186152339 0.000000000000 -vt 0.510329902172 0.079375565052 0.000000000000 -vt 0.703039348125 0.342263132334 0.000000000000 -vt 0.707691013813 0.338801592588 0.000000000000 -vt 0.691107928753 0.352693885565 0.000000000000 -vt 0.694404184818 0.349684000015 0.000000000000 -vt 0.698663651943 0.346254229546 0.000000000000 -vt 0.508014619350 0.081564977765 0.000000000000 -vt 0.505533874035 0.078727111220 0.000000000000 -vt 0.494260638952 0.093220800161 0.000000000000 -vt 0.492302030325 0.090663939714 0.000000000000 -vt 0.505529224873 0.083532154560 0.000000000000 -vt 0.503514945507 0.081306725740 0.000000000000 -vt 0.510711610317 0.084656804800 0.000000000000 -vt 0.514165699482 0.088350698352 0.000000000000 -vt 0.511911690235 0.093188375235 0.000000000000 -vt 0.527652680874 0.098926231265 0.000000000000 -vt 0.525356113911 0.097472637892 0.000000000000 -vt 0.528094470501 0.091692224145 0.000000000000 -vt 0.531258046627 0.093997821212 0.000000000000 -vt 0.521796643734 0.102959886193 0.000000000000 -vt 0.525596559048 0.105276063085 0.000000000000 -vt 0.534857928753 0.104219183326 0.000000000000 -vt 0.537856757641 0.099045574665 0.000000000000 -vt 0.540888249874 0.101543441415 0.000000000000 -vt 0.536647617817 0.105644643307 0.000000000000 -vt 0.534925162792 0.111184135079 0.000000000000 -vt 0.531729161739 0.109336286783 0.000000000000 -vt 0.523591578007 0.091089487076 0.000000000000 -vt 0.730021059513 0.349459081888 0.000000000000 -vt 0.735328376293 0.349237293005 0.000000000000 -vt 0.715811312199 0.346691012383 0.000000000000 -vt 0.720742166042 0.350149869919 0.000000000000 -vt 0.725372970104 0.349892735481 0.000000000000 -vt 0.521666467190 0.094739928842 0.000000000000 -vt 0.520136296749 0.093459248543 0.000000000000 -vt 0.731795966625 0.325470387936 0.000000000000 -vt 0.736351430416 0.326853275299 0.000000000000 -vt 0.734878718853 0.329794704914 0.000000000000 -vt 0.732054173946 0.328241348267 0.000000000000 -vt 0.739810764790 0.330046653748 0.000000000000 -vt 0.737516939640 0.331477284431 0.000000000000 -vt 0.737019240856 0.345520436764 0.000000000000 -vt 0.732173502445 0.343047350645 0.000000000000 -vt 0.734046399593 0.340439140797 0.000000000000 -vt 0.738021910191 0.343094855547 0.000000000000 -vt 0.725114047527 0.336557924747 0.000000000000 -vt 0.723978340626 0.339484244585 0.000000000000 -vt 0.718742549419 0.338676393032 0.000000000000 -vt 0.720449268818 0.335456222296 0.000000000000 -vt 0.728333771229 0.341184616089 0.000000000000 -vt 0.729620277882 0.338552564383 0.000000000000 -vt 0.521848857403 0.090589866042 0.000000000000 -vt 0.519341766834 0.098529517651 0.000000000000 -vt 0.741242706776 0.337124168873 0.000000000000 -vt 0.736575305462 0.336675226688 0.000000000000 -vt 0.737431108952 0.333985060453 0.000000000000 -vt 0.741768896580 0.333650708199 0.000000000000 -vt 0.730156362057 0.329479277134 0.000000000000 -vt 0.728279173374 0.331620484591 0.000000000000 -vt 0.724462211132 0.328425318003 0.000000000000 -vt 0.727317392826 0.325960755348 0.000000000000 -vt 0.732129871845 0.334760516882 0.000000000000 -vt 0.733519494534 0.332428127527 0.000000000000 -vt 0.518350422382 0.096643164754 0.000000000000 -vt 0.524855554104 0.092653632164 0.000000000000 -vt 0.731151521206 0.345263779163 0.000000000000 -vt 0.735784590244 0.347043156624 0.000000000000 -vt 0.736424624920 0.348627597094 0.000000000000 -vt 0.730661809444 0.347184121609 0.000000000000 -vt 0.718040287495 0.341615349054 0.000000000000 -vt 0.723183095455 0.342720180750 0.000000000000 -vt 0.721934854984 0.345855712891 0.000000000000 -vt 0.715493619442 0.344276010990 0.000000000000 -vt 0.727172791958 0.344054907560 0.000000000000 -vt 0.726349413395 0.346510440111 0.000000000000 -vt 0.523354947567 0.096010923386 0.000000000000 -vt 0.521311223507 0.099254280329 0.000000000000 -vt 0.533330857754 0.097978785634 0.000000000000 -vt 0.531335532665 0.101454958320 0.000000000000 -vt 0.529585421085 0.100170671940 0.000000000000 -vt 0.531549036503 0.097181737423 0.000000000000 -vt 0.529571712017 0.105359822512 0.000000000000 -vt 0.528426826000 0.103743880987 0.000000000000 -vt 0.534639537334 0.099621966481 0.000000000000 -vt 0.735392153263 0.338480740786 0.000000000000 -vt 0.739044845104 0.340150952339 0.000000000000 -vt 0.723158061504 0.331868380308 0.000000000000 -vt 0.726885974407 0.334070175886 0.000000000000 -vt 0.730814039707 0.336822479963 0.000000000000 -vt 0.533084571362 0.102829977870 0.000000000000 -vt 0.531313717365 0.105897054076 0.000000000000 -vt 0.521283328533 0.087026789784 0.000000000000 -vt 0.517856895924 0.091663181782 0.000000000000 -vt 0.514960706234 0.097525775433 0.000000000000 -vt 0.517828285694 0.100980103016 0.000000000000 -vt 0.526034533978 0.087389066815 0.000000000000 -vt 0.527589142323 0.109247803688 0.000000000000 -vt 0.535756528378 0.095117062330 0.000000000000 -vt 0.539837419987 0.107863321900 0.000000000000 -vt 0.538558781147 0.107128873467 0.000000000000 -vt 0.539949953556 0.105316147208 0.000000000000 -vt 0.540825903416 0.105864629149 0.000000000000 -vt 0.538582384586 0.109620437026 0.000000000000 -vt 0.537616670132 0.109082773328 0.000000000000 -vt 0.544267117977 0.110548302531 0.000000000000 -vt 0.541652381420 0.108950823545 0.000000000000 -vt 0.542387545109 0.105380535126 0.000000000000 -vt 0.545064866543 0.104814276099 0.000000000000 -vt 0.540196716785 0.104028716683 0.000000000000 -vt 0.537597596645 0.106465324759 0.000000000000 -vt 0.536735951900 0.109748318791 0.000000000000 -vt 0.701508939266 0.396991372108 0.000000000000 -vt 0.695306599140 0.396085560322 0.000000000000 -vt 0.705828607082 0.412745684385 0.000000000000 -vt 0.705876052380 0.406576901674 0.000000000000 -vt 0.704530298710 0.401503235102 0.000000000000 -vt 0.538923561573 0.111143380404 0.000000000000 -vt 0.539531409740 0.113621219993 0.000000000000 -vt 0.688302695751 0.427976310253 0.000000000000 -vt 0.683832943439 0.424098700285 0.000000000000 -vt 0.687000572681 0.421046495438 0.000000000000 -vt 0.689052641392 0.424283087254 0.000000000000 -vt 0.681496918201 0.418339222670 0.000000000000 -vt 0.684903800488 0.417768895626 0.000000000000 -vt 0.690302073956 0.401867091656 0.000000000000 -vt 0.694480240345 0.405638903379 0.000000000000 -vt 0.692191779613 0.407944500446 0.000000000000 -vt 0.687600672245 0.404441058636 0.000000000000 -vt 0.699370443821 0.415826499462 0.000000000000 -vt 0.700973808765 0.413097828627 0.000000000000 -vt 0.704431712627 0.417759448290 0.000000000000 -vt 0.703326642513 0.420762330294 0.000000000000 -vt 0.697867929935 0.408945530653 0.000000000000 -vt 0.695929110050 0.411309421062 0.000000000000 -vt 0.517626106739 0.084983274341 0.000000000000 -vt 0.521136224270 0.070760220289 0.000000000000 -vt 0.683233559132 0.409444689751 0.000000000000 -vt 0.688319623470 0.412122905254 0.000000000000 -vt 0.686133563519 0.414829730988 0.000000000000 -vt 0.680900275707 0.412907809019 0.000000000000 -vt 0.692204892635 0.422975838184 0.000000000000 -vt 0.695665299892 0.420329362154 0.000000000000 -vt 0.698658287525 0.425916135311 0.000000000000 -vt 0.694272696972 0.428446441889 0.000000000000 -vt 0.692554771900 0.415226012468 0.000000000000 -vt 0.689908921719 0.417935758829 0.000000000000 -vt 0.523216187954 0.072577908635 0.000000000000 -vt 0.520890176296 0.077228039503 0.000000000000 -vt 0.697199761868 0.403361231089 0.000000000000 -vt 0.693439781666 0.400654852390 0.000000000000 -vt 0.693814694881 0.397902786732 0.000000000000 -vt 0.699269115925 0.401036739349 0.000000000000 -vt 0.704553306103 0.414974272251 0.000000000000 -vt 0.702452123165 0.410426139832 0.000000000000 -vt 0.703826010227 0.408506244421 0.000000000000 -vt 0.705401599407 0.414679765701 0.000000000000 -vt 0.700053751469 0.406474679708 0.000000000000 -vt 0.701919615269 0.404333680868 0.000000000000 -vt 0.519232571125 0.075901642442 0.000000000000 -vt 0.515266001225 0.080151677132 0.000000000000 -vt 0.519640505314 0.081991866231 0.000000000000 -vt 0.533958613873 0.080200076103 0.000000000000 -vt 0.531604349613 0.079964339733 0.000000000000 -vt 0.532588779926 0.075347989798 0.000000000000 -vt 0.535456359386 0.075775325298 0.000000000000 -vt 0.531062185764 0.084430292249 0.000000000000 -vt 0.534919083118 0.084616497159 0.000000000000 -vt 0.690639078617 0.410164058208 0.000000000000 -vt 0.686743676662 0.408009111881 0.000000000000 -vt 0.700886189938 0.422482520342 0.000000000000 -vt 0.697773873806 0.417764842510 0.000000000000 -vt 0.694584786892 0.413028031588 0.000000000000 -vt 0.543268382549 0.081021666527 0.000000000000 -vt 0.542410075665 0.076548516750 0.000000000000 -vt 0.545253694057 0.076710179448 0.000000000000 -vt 0.544744908810 0.081107899547 0.000000000000 -vt 0.545586764812 0.085359513760 0.000000000000 -vt 0.542715609074 0.085166096687 0.000000000000 -vt 0.528137505054 0.076546490192 0.000000000000 -vt 0.526995480061 0.079263880849 0.000000000000 -vt 0.524926722050 0.078719690442 0.000000000000 -vt 0.526245653629 0.076403737068 0.000000000000 -vt 0.526619493961 0.081934899092 0.000000000000 -vt 0.524678170681 0.081073686481 0.000000000000 -vt 0.529789626598 0.077268108726 0.000000000000 -vt 0.529239356518 0.079652726650 0.000000000000 -vt 0.528736531734 0.081992313266 0.000000000000 -vt 0.539014041424 0.077833026648 0.000000000000 -vt 0.539221823215 0.080529257655 0.000000000000 -vt 0.536268293858 0.080332249403 0.000000000000 -vt 0.536676228046 0.078035444021 0.000000000000 -vt 0.539300858974 0.083174824715 0.000000000000 -vt 0.536652386189 0.082537859678 0.000000000000 -vt 0.541114032269 0.078451976180 0.000000000000 -vt 0.541567981243 0.080870822072 0.000000000000 -vt 0.541349947453 0.083064511418 0.000000000000 -vt 0.525810420513 0.073440477252 0.000000000000 -vt 0.522990167141 0.078078895807 0.000000000000 -vt 0.522753298283 0.083092421293 0.000000000000 -vt 0.744985520840 0.358051896095 0.000000000000 -vt 0.740702569485 0.361511409283 0.000000000000 -vt 0.737015068531 0.377986699343 0.000000000000 -vt 0.527110517025 0.085661664605 0.000000000000 -vt 0.529920637608 0.072953239083 0.000000000000 -vt 0.539422690868 0.086372941732 0.000000000000 -vt 0.720288455486 0.404917716980 0.000000000000 -vt 0.725336492062 0.406646698713 0.000000000000 -vt 0.719956338406 0.413258612156 0.000000000000 -vt 0.717335283756 0.410958647728 0.000000000000 -vt 0.723915517330 0.398037433624 0.000000000000 -vt 0.731581389904 0.399601578712 0.000000000000 -vt 0.741063773632 0.398945480585 0.000000000000 -vt 0.741147696972 0.402583092451 0.000000000000 -vt 0.735348403454 0.405078500509 0.000000000000 -vt 0.724570930004 0.415234774351 0.000000000000 -vt 0.730074822903 0.409371733665 0.000000000000 -vt 0.755069792271 0.423953682184 0.000000000000 -vt 0.751188337803 0.423076480627 0.000000000000 -vt 0.732347548008 0.419561594725 0.000000000000 -vt 0.728611052036 0.417487025261 0.000000000000 -vt 0.734247624874 0.412292242050 0.000000000000 -vt 0.737663686275 0.415086418390 0.000000000000 -vt 0.739005625248 0.408245295286 0.000000000000 -vt 0.742154181004 0.411730021238 0.000000000000 -vt 0.728346526623 0.424829334021 0.000000000000 -vt 0.724365770817 0.423212945461 0.000000000000 -vt 0.539046466351 0.074854224920 0.000000000000 -vt 0.547604382038 0.081218689680 0.000000000000 -vt 0.744521200657 0.403573781252 0.000000000000 -vt 0.746637046337 0.406587243080 0.000000000000 -vt 0.546402513981 0.081313252449 0.000000000000 -vt 0.546436250210 0.079620987177 0.000000000000 -vt 0.547303736210 0.079606115818 0.000000000000 -vt 0.547511637211 0.082779005170 0.000000000000 -vt 0.546545684338 0.082813456655 0.000000000000 -vt 0.551446378231 0.080884099007 0.000000000000 -vt 0.719365775585 0.420285463333 0.000000000000 -vt 0.548926889896 0.081119611859 0.000000000000 -vt 0.547964394093 0.078651010990 0.000000000000 -vt 0.549326121807 0.076903134584 0.000000000000 -vt 0.546006023884 0.078606888652 0.000000000000 -vt 0.545527517796 0.081211924553 0.000000000000 -vt 0.740861833096 0.424791932106 0.000000000000 -vt 0.744636476040 0.421375900507 0.000000000000 -vt 0.748865187168 0.419236689806 0.000000000000 -vt 0.738058149815 0.430005639791 0.000000000000 -vt 0.546189963818 0.083545655012 0.000000000000 -vt 0.548156440258 0.083578765392 0.000000000000 -vt 0.549798786640 0.085083246231 0.000000000000 -vt 0.493128985167 0.107532128692 0.000000000000 -vt 0.487130194902 0.108177408576 0.000000000000 -vt 0.484787672758 0.104095578194 0.000000000000 -vt 0.754294574261 0.415865898132 0.000000000000 -vt 0.741011559963 0.418052166700 0.000000000000 -vt 0.736329138279 0.422021627426 0.000000000000 -vt 0.745218575001 0.415226459503 0.000000000000 -vt 0.732700407505 0.426749676466 0.000000000000 -vt 0.477795451880 0.104249805212 0.000000000000 -vt 0.480690747499 0.109506055713 0.000000000000 -vt 0.493065744638 0.123880639672 0.000000000000 -vt 0.492350906134 0.121099308133 0.000000000000 -vt 0.498245447874 0.118749126792 0.000000000000 -vt 0.499274820089 0.122994199395 0.000000000000 -vt 0.749212324619 0.411244809628 0.000000000000 -vt 0.486499279737 0.122255474329 0.000000000000 -vt 0.487754553556 0.125899389386 0.000000000000 -vt 0.495414823294 0.131725952029 0.000000000000 -vt 0.501138865948 0.129815727472 0.000000000000 -vt 0.501795589924 0.132985696197 0.000000000000 -vt 0.496015042067 0.133395478129 0.000000000000 -vt 0.491779893637 0.137110754848 0.000000000000 -vt 0.490246385336 0.133341893554 0.000000000000 -vt 0.493753403425 0.114416465163 0.000000000000 -vt 0.490512460470 0.116016864777 0.000000000000 -vt 0.716776549816 0.397952318192 0.000000000000 -vt 0.722395479679 0.390428304672 0.000000000000 -vt 0.748906552792 0.386245161295 0.000000000000 -vt 0.748211801052 0.394017070532 0.000000000000 -vt 0.743617475033 0.387832283974 0.000000000000 -vt 0.743471086025 0.384143799543 0.000000000000 -vt 0.735934555531 0.381866127253 0.000000000000 -vt 0.489763349295 0.113667383790 0.000000000000 -vt 0.714425027370 0.404076099396 0.000000000000 -vt 0.492669016123 0.112787023187 0.000000000000 -vt 0.487121194601 0.117388963699 0.000000000000 -vt 0.486971467733 0.115077972412 0.000000000000 -vt 0.494484215975 0.116980090737 0.000000000000 -vt 0.491517156363 0.118607267737 0.000000000000 -vt 0.488306194544 0.119425490499 0.000000000000 -vt 0.498060315847 0.127201452851 0.000000000000 -vt 0.713693201542 0.410189747810 0.000000000000 -vt 0.735486447811 0.385052949190 0.000000000000 -vt 0.746610701084 0.396617144346 0.000000000000 -vt 0.494058936834 0.127958431840 0.000000000000 -vt 0.493515819311 0.126024797559 0.000000000000 -vt 0.496876925230 0.125608488917 0.000000000000 -vt 0.490766674280 0.128856346011 0.000000000000 -vt 0.743014752865 0.389892905951 0.000000000000 -vt 0.735056340694 0.387602627277 0.000000000000 -vt 0.727178633213 0.392949610949 0.000000000000 -vt 0.733748018742 0.392339646816 0.000000000000 -vt 0.739848792553 0.392785251141 0.000000000000 -vt 0.747750461102 0.374964654446 0.000000000000 -vt 0.490720719099 0.127026960254 0.000000000000 -vt 0.750498473644 0.379568845034 0.000000000000 -vt 0.752317011356 0.363459676504 0.000000000000 -vt 0.747864067554 0.366984248161 0.000000000000 -vt 0.743768513203 0.380047321320 0.000000000000 -vt 0.743770778179 0.376911133528 0.000000000000 -vt 0.716933429241 0.416927278042 0.000000000000 -vt 0.497924119234 0.128914669156 0.000000000000 -vt 0.494692295790 0.129884406924 0.000000000000 -vt 0.491763919592 0.130519121885 0.000000000000 -vt 0.495831340551 0.110157430172 0.000000000000 -vt 0.489241451025 0.111455008388 0.000000000000 -vt 0.483312696218 0.114056900144 0.000000000000 -vt 0.482924073935 0.118979677558 0.000000000000 -vt 0.499466627836 0.113667383790 0.000000000000 -vt 0.487026840448 0.130218312144 0.000000000000 -vt 0.502736389637 0.126097753644 0.000000000000 -vt 0.497383981943 0.137650460005 0.000000000000 -vt 0.496828526258 0.135942205787 0.000000000000 -vt 0.498790949583 0.135475009680 0.000000000000 -vt 0.489594787359 0.354463160038 0.000000000000 -vt 0.493529766798 0.348664730787 0.000000000000 -vt 0.466066062450 0.416784971952 0.000000000000 -vt 0.492370694876 0.361383527517 0.000000000000 -vt 0.500243246555 0.364317297935 0.000000000000 -vt 0.494832962751 0.368273258209 0.000000000000 -vt 0.503132641315 0.370268374681 0.000000000000 -vt 0.497408539057 0.374473363161 0.000000000000 -vt 0.505711734295 0.374342322350 0.000000000000 -vt 0.501966536045 0.380494236946 0.000000000000 -vt 0.502037703991 0.387555330992 0.000000000000 -vt 0.500600278378 0.394303470850 0.000000000000 -vt 0.497024863958 0.400832056999 0.000000000000 -vt 0.490292042494 0.406675279140 0.000000000000 -vt 0.490373104811 0.412000209093 0.000000000000 -vt 0.478659600019 0.408653289080 0.000000000000 -vt 0.483080357313 0.413705527782 0.000000000000 -vt 0.483867734671 0.400707095861 0.000000000000 -vt 0.475096553564 0.403399050236 0.000000000000 -vt 0.490063995123 0.397259533405 0.000000000000 -vt 0.493380278349 0.393484354019 0.000000000000 -vt 0.495144337416 0.389038652182 0.000000000000 -vt 0.495407789946 0.384074211121 0.000000000000 -vt 0.493809431791 0.377649396658 0.000000000000 -vt 0.491057127714 0.371400237083 0.000000000000 -vt 0.488305300474 0.365160942078 0.000000000000 -vt 0.485417455435 0.358706206083 0.000000000000 -vt 0.499160021544 0.136612713337 0.000000000000 -vt 0.495681852102 0.138441428542 0.000000000000 -vt 0.495292752981 0.137186184525 0.000000000000 -vt 0.499904841185 0.142935067415 0.000000000000 -vt 0.512892186642 0.203441917896 0.000000000000 -vt 0.515536010265 0.210260972381 0.000000000000 -vt 0.519058048725 0.216575443745 0.000000000000 -vt 0.498339504004 0.139838293195 0.000000000000 -vt 0.500721871853 0.137117296457 0.000000000000 -vt 0.503684222698 0.138030976057 0.000000000000 -vt 0.499697417021 0.134602531791 0.000000000000 -vt 0.496406823397 0.134647563100 0.000000000000 -vt 0.494290322065 0.137108504772 0.000000000000 -vt 0.495159000158 0.139991164207 0.000000000000 -vt 0.493990033865 0.142434999347 0.000000000000 -vt 0.486728996038 0.090575456619 0.000000000000 -vt 0.478315383196 0.092991143465 0.000000000000 -vt 0.474077731371 0.098476827145 0.000000000000 -vt 0.498264402151 0.081063106656 0.000000000000 -vt 0.490895956755 0.083478346467 0.000000000000 -vt 0.501754701138 0.074368119240 0.000000000000 -vt 0.516297876835 0.064490333200 0.000000000000 -vt 0.489585071802 0.070763155818 0.000000000000 -vt 0.494673103094 0.066240236163 0.000000000000 -vt 0.470336109400 0.086715623736 0.000000000000 -vt 0.436086863279 0.092820927501 0.000000000000 -vt 0.438066899776 0.090013250709 0.000000000000 -vt 0.444520950317 0.092675030231 0.000000000000 -vt 0.441438585520 0.096161559224 0.000000000000 -vt 0.428543061018 0.092088505626 0.000000000000 -vt 0.430847972631 0.087048172951 0.000000000000 -vt 0.445708662271 0.087137565017 0.000000000000 -vt 0.440775513649 0.085114762187 0.000000000000 -vt 0.441083967686 0.081669896841 0.000000000000 -vt 0.445867836475 0.084105402231 0.000000000000 -vt 0.434993296862 0.082800179720 0.000000000000 -vt 0.435679793358 0.079566493630 0.000000000000 -vt 0.443775683641 0.089068949223 0.000000000000 -vt 0.439778298140 0.087716892362 0.000000000000 -vt 0.435482561588 0.085728764534 0.000000000000 -vt 0.449968576431 0.082234129310 0.000000000000 -vt 0.441662847996 0.076967298985 0.000000000000 -vt 0.431835711002 0.073218241334 0.000000000000 -vt 0.428974449635 0.081223636866 0.000000000000 -vt 0.450840383768 0.089633405209 0.000000000000 -vt 0.429250478745 0.110776379704 0.000000000000 -vt 0.428867727518 0.107335552573 0.000000000000 -vt 0.431848555803 0.108271300793 0.000000000000 -vt 0.431623846292 0.110644668341 0.000000000000 -vt 0.427443832159 0.110487952828 0.000000000000 -vt 0.426816552877 0.108107388020 0.000000000000 -vt 0.437157928944 0.099945515394 0.000000000000 -vt 0.433482289314 0.098722696304 0.000000000000 -vt 0.434810459614 0.095693901181 0.000000000000 -vt 0.437838792801 0.097269997001 0.000000000000 -vt 0.429327040911 0.097964599729 0.000000000000 -vt 0.431027412415 0.095057398081 0.000000000000 -vt 0.435632973909 0.102705463767 0.000000000000 -vt 0.431967437267 0.102064222097 0.000000000000 -vt 0.428185939789 0.101327285171 0.000000000000 -vt 0.424739956856 0.097438409925 0.000000000000 -vt 0.424326807261 0.104374542832 0.000000000000 -vt 0.430121839046 0.103951931000 0.000000000000 -vt 0.436985909939 0.106490775943 0.000000000000 -vt 0.440761536360 0.101641386747 0.000000000000 -vt 0.429635047913 0.115833595395 0.000000000000 -vt 0.429685264826 0.112943276763 0.000000000000 -vt 0.432830691338 0.111719325185 0.000000000000 -vt 0.435101598501 0.113605901599 0.000000000000 -vt 0.434298694134 0.107984006405 0.000000000000 -vt 0.429523140192 0.105171591043 0.000000000000 -vt 0.425729721785 0.106971934438 0.000000000000 -vt 0.426668196917 0.111298739910 0.000000000000 -vt 0.424650788307 0.112406730652 0.000000000000 -vt 0.509388387203 0.055841218680 0.000000000000 -vt 0.498403996229 0.043372806162 0.000000000000 -vt 0.502433478832 0.048159595579 0.000000000000 -vt 0.497449725866 0.051044743508 0.000000000000 -vt 0.492421835661 0.043788667768 0.000000000000 -vt 0.463615030050 0.077348947525 0.000000000000 -vt 0.455456525087 0.070783421397 0.000000000000 -vt 0.464122295380 0.066180795431 0.000000000000 -vt 0.462868630886 0.093436956406 0.000000000000 -vt 0.458721280098 0.092571005225 0.000000000000 -vt 0.459522604942 0.087591469288 0.000000000000 -vt 0.462670952082 0.086979731917 0.000000000000 -vt 0.471514105797 0.060662243515 0.000000000000 -vt 0.482812136412 0.062291014940 0.000000000000 -vt 0.467946112156 0.095136195421 0.000000000000 -vt 0.458524495363 0.080985873938 0.000000000000 -vt 0.452050387859 0.076159223914 0.000000000000 -vt 0.443986207247 0.071658372879 0.000000000000 -vt 0.445354491472 0.066013723612 0.000000000000 -vt 0.436717092991 0.065082713962 0.000000000000 -vt 0.437832713127 0.058958042413 0.000000000000 -vt 0.456312119961 0.084696203470 0.000000000000 -vt 0.455533295870 0.088533744216 0.000000000000 -vt 0.442759126425 0.026406910270 0.000000000000 -vt 0.439107567072 0.033566392958 0.000000000000 -vt 0.433614879847 0.033746067435 0.000000000000 -vt 0.436550229788 0.040571421385 0.000000000000 -vt 0.431009620428 0.041979093105 0.000000000000 -vt 0.436738461256 0.048520524055 0.000000000000 -vt 0.433239340782 0.050523724407 0.000000000000 -vt 0.439432889223 0.056393977255 0.000000000000 -vt 0.444673389196 0.062197577208 0.000000000000 -vt 0.452080547810 0.064230725169 0.000000000000 -vt 0.459633141756 0.061068650335 0.000000000000 -vt 0.466834276915 0.054884534329 0.000000000000 -vt 0.476173490286 0.048398043960 0.000000000000 -vt 0.478311985731 0.055618535727 0.000000000000 -vt 0.487611383200 0.048637155443 0.000000000000 -vt 0.492559403181 0.054551754147 0.000000000000 -vt 0.450314640999 0.028678275645 0.000000000000 -vt 0.445344805717 0.034261446446 0.000000000000 -vt 0.441385686398 0.039831560105 0.000000000000 -vt 0.440092831850 0.046508762985 0.000000000000 -vt 0.441298097372 0.053300123662 0.000000000000 -vt 0.444251447916 0.058152657002 0.000000000000 -vt 0.449525713921 0.059440102428 0.000000000000 -vt 0.455304324627 0.055676858872 0.000000000000 -vt 0.461506903172 0.049404706806 0.000000000000 -vt 0.469306051731 0.042024347931 0.000000000000 -vt 0.487811952829 0.058225836605 0.000000000000 -vt 0.483524292707 0.052073474973 0.000000000000 -vt 0.484311491251 0.046199399978 0.000000000000 -vt 0.481747001410 0.048475492746 0.000000000000 -vt 0.380680233240 0.065514564514 0.000000000000 -vt 0.376588284969 0.059708710760 0.000000000000 -vt 0.380253583193 0.059918548912 0.000000000000 -vt 0.384085476398 0.069081693888 0.000000000000 -vt 0.495234221220 0.099533021450 0.000000000000 -vt 0.383714437485 0.065352901816 0.000000000000 -vt 0.383114397526 0.061096791178 0.000000000000 -vt 0.374451309443 0.073164209723 0.000000000000 -vt 0.372015357018 0.063677519560 0.000000000000 -vt 0.374059766531 0.053939338773 0.000000000000 -vt 0.381692320108 0.054332684726 0.000000000000 -vt 0.383103370667 0.075196906924 0.000000000000 -vt 0.405146718025 0.062567278743 0.000000000000 -vt 0.405029207468 0.064906865358 0.000000000000 -vt 0.403085887432 0.065327689052 0.000000000000 -vt 0.402291089296 0.062788158655 0.000000000000 -vt 0.404567837715 0.060321133584 0.000000000000 -vt 0.402513980865 0.060236703604 0.000000000000 -vt 0.396065324545 0.068468824029 0.000000000000 -vt 0.393785178661 0.067805290222 0.000000000000 -vt 0.392409473658 0.063877239823 0.000000000000 -vt 0.394892245531 0.063695982099 0.000000000000 -vt 0.392374575138 0.059808004647 0.000000000000 -vt 0.394494861364 0.058848392218 0.000000000000 -vt 0.398127049208 0.067958623171 0.000000000000 -vt 0.397333174944 0.063290476799 0.000000000000 -vt 0.396797299385 0.058876764029 0.000000000000 -vt 0.394452542067 0.054397072643 0.000000000000 -vt 0.399751543999 0.055975642055 0.000000000000 -vt 0.399062365294 0.062898263335 0.000000000000 -vt 0.401548743248 0.070496574044 0.000000000000 -vt 0.397002875805 0.072747439146 0.000000000000 -vt 0.410708278418 0.061957109720 0.000000000000 -vt 0.408443450928 0.068036526442 0.000000000000 -vt 0.406104087830 0.065834060311 0.000000000000 -vt 0.407416969538 0.062223013490 0.000000000000 -vt 0.402603596449 0.067001029849 0.000000000000 -vt 0.400384694338 0.062776446342 0.000000000000 -vt 0.401618093252 0.058767784387 0.000000000000 -vt 0.407653838396 0.056897196919 0.000000000000 -vt 0.405660539865 0.059153925627 0.000000000000 -vt 0.342144489288 0.129252389073 0.000000000000 -vt 0.330034285784 0.118232384324 0.000000000000 -vt 0.331073820591 0.111910715699 0.000000000000 -vt 0.337948709726 0.117126211524 0.000000000000 -vt 0.334675848484 0.122342392802 0.000000000000 -vt 0.364498108625 0.084034025669 0.000000000000 -vt 0.353841513395 0.081475362182 0.000000000000 -vt 0.359023243189 0.072227567434 0.000000000000 -vt 0.383939355612 0.087411120534 0.000000000000 -vt 0.376194030046 0.086917132139 0.000000000000 -vt 0.378380954266 0.083674445748 0.000000000000 -vt 0.385140568018 0.082588523626 0.000000000000 -vt 0.348989427090 0.090118840337 0.000000000000 -vt 0.349848628044 0.102441802621 0.000000000000 -vt 0.384516656399 0.092244535685 0.000000000000 -vt 0.368901699781 0.080153703690 0.000000000000 -vt 0.366300255060 0.072573855519 0.000000000000 -vt 0.362025469542 0.061230536550 0.000000000000 -vt 0.366504251957 0.062840163708 0.000000000000 -vt 0.364860385656 0.049893748015 0.000000000000 -vt 0.368391275406 0.052941676229 0.000000000000 -vt 0.375058352947 0.079524159431 0.000000000000 -vt 0.381066381931 0.079621434212 0.000000000000 -vt 0.369406282902 0.023787003011 0.000000000000 -vt 0.363827377558 0.021882418543 0.000000000000 -vt 0.362167745829 0.013727746904 0.000000000000 -vt 0.369875043631 0.032330740243 0.000000000000 -vt 0.363867014647 0.030249182135 0.000000000000 -vt 0.367265045643 0.040660582483 0.000000000000 -vt 0.362684249878 0.039418853819 0.000000000000 -vt 0.360803991556 0.049217607826 0.000000000000 -vt 0.358212471008 0.058879461139 0.000000000000 -vt 0.354023665190 0.067041784525 0.000000000000 -vt 0.349367916584 0.074845895171 0.000000000000 -vt 0.344372838736 0.084569439292 0.000000000000 -vt 0.343579858541 0.097275629640 0.000000000000 -vt 0.337548166513 0.094781354070 0.000000000000 -vt 0.336168199778 0.107096001506 0.000000000000 -vt 0.341732889414 0.112160399556 0.000000000000 -vt 0.358703076839 0.019574124366 0.000000000000 -vt 0.356585264206 0.011583819985 0.000000000000 -vt 0.359179943800 0.028422724456 0.000000000000 -vt 0.358128011227 0.037861227989 0.000000000000 -vt 0.355775833130 0.047059264034 0.000000000000 -vt 0.352667778730 0.055755432695 0.000000000000 -vt 0.348802536726 0.062798514962 0.000000000000 -vt 0.344516932964 0.069515347481 0.000000000000 -vt 0.339693903923 0.078744009137 0.000000000000 -vt 0.334405004978 0.088547706604 0.000000000000 -vt 0.351488649845 0.008813511580 0.000000000000 -vt 0.353146910667 0.017157759517 0.000000000000 -vt 0.344804912806 0.016256015748 0.000000000000 -vt 0.343273401260 0.007860429585 0.000000000000 -vt 0.353605329990 0.026377867907 0.000000000000 -vt 0.345076918602 0.024861443788 0.000000000000 -vt 0.351858347654 0.035421445966 0.000000000000 -vt 0.343469291925 0.032606557012 0.000000000000 -vt 0.329398661852 0.083495229483 0.000000000000 -vt 0.321584880352 0.080222144723 0.000000000000 -vt 0.345637321472 0.107405588031 0.000000000000 -vt 0.339709669352 0.102807238698 0.000000000000 -vt 0.334294229746 0.103572994471 0.000000000000 -vt 0.336519658566 0.100833073258 0.000000000000 -vt 0.331020236015 0.072261109948 0.000000000000 -vt 0.336660385132 0.064951002598 0.000000000000 -vt 0.434932053089 0.026294331998 0.000000000000 -vt 0.340934514999 0.059087056667 0.000000000000 -vt 0.343839913607 0.051737319678 0.000000000000 -vt 0.346170932055 0.042951311916 0.000000000000 -vt 0.340638875961 0.037561997771 0.000000000000 -vt 0.323255330324 0.073237612844 0.000000000000 -vt 0.695959985256 0.741854548454 0.000000000000 -vt 0.714866340160 0.723106801510 0.000000000000 -vt 0.697431623936 0.719995796680 0.000000000000 -vt 0.483988851309 0.041881825775 0.000000000000 -vt 0.839606106281 0.716192245483 0.000000000000 -vt 0.824899375439 0.704895555973 0.000000000000 -vt 0.836511552334 0.689590156078 0.000000000000 -vt 0.848930418491 0.699052095413 0.000000000000 -vt 0.814055740833 0.694797575474 0.000000000000 -vt 0.477539271116 0.036895312369 0.000000000000 -vt 0.826638519764 0.681990265846 0.000000000000 -vt 0.829895794392 0.731659770012 0.000000000000 -vt 0.813143789768 0.716623902321 0.000000000000 -vt 0.801700055599 0.705101132393 0.000000000000 -vt 0.817305624485 0.743863582611 0.000000000000 -vt 0.801387965679 0.725039482117 0.000000000000 -vt 0.789851725101 0.712394773960 0.000000000000 -vt 0.788582026958 0.734670758247 0.000000000000 -vt 0.777517497540 0.721166849136 0.000000000000 -vt 0.803215801716 0.752814412117 0.000000000000 -vt 0.786242902279 0.759428799152 0.000000000000 -vt 0.773034870625 0.741466820240 0.000000000000 -vt 0.763387620449 0.729409098625 0.000000000000 -vt 0.819508969784 0.771108031273 0.000000000000 -vt 0.801594197750 0.778130888939 0.000000000000 -vt 0.780358016491 0.784393787384 0.000000000000 -vt 0.813161194324 0.798096477985 0.000000000000 -vt 0.791216671467 0.802965700626 0.000000000000 -vt 0.768060982227 0.806276857853 0.000000000000 -vt 0.758998692036 0.789613127708 0.000000000000 -vt 0.745742022991 0.808515787125 0.000000000000 -vt 0.739104449749 0.793780505657 0.000000000000 -vt 0.796912372112 0.821695029736 0.000000000000 -vt 0.772977530956 0.822699189186 0.000000000000 -vt 0.749330580235 0.823236882687 0.000000000000 -vt 0.818778097630 0.819741129875 0.000000000000 -vt 0.864375889301 0.710809707642 0.000000000000 -vt 0.880953133106 0.724374651909 0.000000000000 -vt 0.915635168552 0.748171925545 0.000000000000 -vt 0.908841907978 0.766230940819 0.000000000000 -vt 0.905186593533 0.787342846394 0.000000000000 -vt 0.887137472630 0.812209010124 0.000000000000 -vt 0.901950418949 0.812799155712 0.000000000000 -vt 0.716777384281 0.755539953709 0.000000000000 -vt 0.709918677807 0.762999296188 0.000000000000 -vt 0.751775801182 0.171791642904 0.000000000000 -vt 0.779532253742 0.179935947061 0.000000000000 -vt 0.757754266262 0.191265076399 0.000000000000 -vt 0.738353550434 0.202746644616 0.000000000000 -vt 0.733651459217 0.186159908772 0.000000000000 -vt 0.720768034458 0.212536171079 0.000000000000 -vt 0.718448698521 0.197526648641 0.000000000000 -vt 0.715862095356 0.185371875763 0.000000000000 -vt 0.749988734722 0.241413876414 0.000000000000 -vt 0.731017768383 0.248716101050 0.000000000000 -vt 0.725487768650 0.230310603976 0.000000000000 -vt 0.743789970875 0.221092060208 0.000000000000 -vt 0.774173557758 0.257214367390 0.000000000000 -vt 0.754297435284 0.261839717627 0.000000000000 -vt 0.769551694393 0.234550252557 0.000000000000 -vt 0.731539070606 0.269993722439 0.000000000000 -vt 0.763681709766 0.212278813124 0.000000000000 -vt 0.789024770260 0.228903159499 0.000000000000 -vt 0.784669578075 0.203588500619 0.000000000000 -vt 0.812417447567 0.255994260311 0.000000000000 -vt 0.793350636959 0.255872875452 0.000000000000 -vt 0.808808386326 0.224819734693 0.000000000000 -vt 0.805518686771 0.196942374110 0.000000000000 -vt 0.801068723202 0.171566486359 0.000000000000 -vt 0.816036999226 0.293190568686 0.000000000000 -vt 0.796044886112 0.283715814352 0.000000000000 -vt 0.777438461781 0.280535697937 0.000000000000 -vt 0.757886707783 0.282600164413 0.000000000000 -vt 0.739174664021 0.287719726563 0.000000000000 -vt 0.785341441631 0.033302962780 0.000000000000 -vt 0.582609474659 0.124908477068 0.000000000000 -vt 0.581306993961 0.142187565565 0.000000000000 -vt 0.545368969440 0.011624570936 0.000000000000 -vt 0.646641552448 0.018267553300 0.000000000000 -vt 0.606483757496 0.106701299548 0.000000000000 -vt 0.612616598606 0.108521446586 0.000000000000 -vt 0.618627488613 0.111129656434 0.000000000000 -vt 0.665071904659 0.014743648469 0.000000000000 -vt 0.370113700628 0.016160547733 0.000000000000 -vt 0.331191360950 0.103096559644 0.000000000000 -vt 0.330383718014 0.097089871764 0.000000000000 -vt 0.327046245337 0.092111021280 0.000000000000 -vt 0.319549947977 0.088000133634 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.696907937527 0.156802833080 0.000000000000 -vt 0.707364618778 0.164915174246 0.000000000000 -vt 0.711468279362 0.167301818728 0.000000000000 -vt 0.672648847103 0.136169388890 0.000000000000 -vt 0.654392778873 0.123681157827 0.000000000000 -vt 0.546281397343 0.277987629175 0.000000000000 -vt 0.555889427662 0.542913317680 0.000000000000 -vt 0.598048627377 0.315594613552 0.000000000000 -vt 0.474871605635 0.487518340349 0.000000000000 -vt 0.493717104197 0.499704867601 0.000000000000 -vt 0.510663211346 0.513657331467 0.000000000000 -vt 0.529695570469 0.328777670860 0.000000000000 -vt 0.478573888540 0.439885228872 0.000000000000 -vt 0.489638179541 0.458603054285 0.000000000000 -vt 0.472153753042 0.424974769354 0.000000000000 -vt 0.581608593464 0.316328614950 0.000000000000 -vt 0.469933092594 0.410422533751 0.000000000000 -vt 0.474573940039 0.415574103594 0.000000000000 -vt 0.496727436781 0.356613397598 0.000000000000 -vt 0.467020928860 0.405297100544 0.000000000000 -vt 0.680720627308 0.091846004128 0.000000000000 -vt 0.694580972195 0.090741172433 0.000000000000 -vt 0.547491371632 0.071579337120 0.000000000000 -vt 0.553497970104 0.078128427267 0.000000000000 -vt 0.645280063152 0.102942556143 0.000000000000 -vt 0.557917654514 0.084493562579 0.000000000000 -vt 0.562383949757 0.098196953535 0.000000000000 -vt 0.633653700352 0.118626862764 0.000000000000 -vt 0.562888324261 0.114720419049 0.000000000000 -vt 0.563672840595 0.128326103091 0.000000000000 -vt 0.567211091518 0.144699171185 0.000000000000 -vt 0.500136196613 0.268927842379 0.000000000000 -vt 0.502436935902 0.280043512583 0.000000000000 -vt 0.482790559530 0.140759631991 0.000000000000 -vt 0.485283464193 0.145932793617 0.000000000000 -vt 0.511669576168 0.244729980826 0.000000000000 -vt 0.489596575499 0.150636732578 0.000000000000 -vt 0.503686726093 0.155002936721 0.000000000000 -vt 0.528804123402 0.231279209256 0.000000000000 -vt 0.521844804287 0.155472621322 0.000000000000 -vt 0.536552846432 0.156950756907 0.000000000000 -vt 0.553597509861 0.159783437848 0.000000000000 -vt 0.307654768229 0.609554529190 0.000000000000 -vt 0.290467321873 0.613707244396 0.000000000000 -vt 0.204575508833 0.719810605049 0.000000000000 -vt 0.210707157850 0.703682720661 0.000000000000 -vt 0.284538298845 0.585472345352 0.000000000000 -vt 0.223060980439 0.709351420403 0.000000000000 -vt 0.213785484433 0.729282855988 0.000000000000 -vt 0.294191390276 0.583933651447 0.000000000000 -vt 0.193332836032 0.738901257515 0.000000000000 -vt 0.188829287887 0.728674709797 0.000000000000 -vt 0.197825804353 0.749223530293 0.000000000000 -vt 0.225497603416 0.740132212639 0.000000000000 -vt 0.172644689679 0.756999909878 0.000000000000 -vt 0.173354595900 0.748063921928 0.000000000000 -vt 0.153877779841 0.774228334427 0.000000000000 -vt 0.153797164559 0.760271430016 0.000000000000 -vt 0.173445329070 0.773155450821 0.000000000000 -vt 0.149432986975 0.820051431656 0.000000000000 -vt 0.173765048385 0.821435034275 0.000000000000 -vt 0.175114631653 0.829998791218 0.000000000000 -vt 0.154235765338 0.830059587955 0.000000000000 -vt 0.154094830155 0.792689681053 0.000000000000 -vt 0.177844420075 0.795601427555 0.000000000000 -vt 0.212241590023 0.836606919765 0.000000000000 -vt 0.307616710663 0.586260378361 0.000000000000 -vt 0.319666564465 0.604332268238 0.000000000000 -vt 0.206351310015 0.841337859631 0.000000000000 -vt 0.357945650816 0.653928995132 0.000000000000 -vt 0.205141782761 0.802912175655 0.000000000000 -vt 0.181257992983 0.838490307331 0.000000000000 -vt 0.150479733944 0.836383342743 0.000000000000 -vt 0.202541679144 0.774786055088 0.000000000000 -vt 0.230581372976 0.776787877083 0.000000000000 -vt 0.232835412025 0.808410942554 0.000000000000 -vt 0.153742238879 0.753254890442 0.000000000000 -vt 0.354879945517 0.670894861221 0.000000000000 -vt 0.156122118235 0.742229044437 0.000000000000 -vt 0.325383484364 0.664160490036 0.000000000000 -vt 0.172345682979 0.736270546913 0.000000000000 -vt 0.329998701811 0.649386703968 0.000000000000 -vt 0.344495564699 0.695504546165 0.000000000000 -vt 0.319999575615 0.685368955135 0.000000000000 -vt 0.340014070272 0.705360293388 0.000000000000 -vt 0.316662311554 0.697957396507 0.000000000000 -vt 0.335703253746 0.712217569351 0.000000000000 -vt 0.314472913742 0.703338801861 0.000000000000 -vt 0.298693358898 0.660711348057 0.000000000000 -vt 0.305291980505 0.643745899200 0.000000000000 -vt 0.335656195879 0.638233840466 0.000000000000 -vt 0.170275822282 0.731788814068 0.000000000000 -vt 0.154652982950 0.738835036755 0.000000000000 -vt 0.186667352915 0.724648237228 0.000000000000 -vt 0.232443422079 0.711409807205 0.000000000000 -vt 0.252836883068 0.745151817799 0.000000000000 -vt 0.251037418842 0.715631723404 0.000000000000 -vt 0.257062584162 0.778479039669 0.000000000000 -vt 0.286519646645 0.808762609959 0.000000000000 -vt 0.259915977716 0.810499906540 0.000000000000 -vt 0.282630771399 0.777449607849 0.000000000000 -vt 0.312265455723 0.804308831692 0.000000000000 -vt 0.315088212490 0.835467398167 0.000000000000 -vt 0.288638800383 0.843417167664 0.000000000000 -vt 0.337379038334 0.797992110252 0.000000000000 -vt 0.342023313046 0.826052308083 0.000000000000 -vt 0.314613372087 0.842931270599 0.000000000000 -vt 0.360430896282 0.641259968281 0.000000000000 -vt 0.314939886332 0.630025804043 0.000000000000 -vt 0.289557874203 0.850114881992 0.000000000000 -vt 0.294469684362 0.682716429234 0.000000000000 -vt 0.273877441883 0.659004628658 0.000000000000 -vt 0.280411213636 0.635718882084 0.000000000000 -vt 0.270008593798 0.684478938580 0.000000000000 -vt 0.359717398882 0.625162005424 0.000000000000 -vt 0.343318879604 0.624738991261 0.000000000000 -vt 0.344458639622 0.621523499489 0.000000000000 -vt 0.360369205475 0.621685206890 0.000000000000 -vt 0.360682636499 0.635098338127 0.000000000000 -vt 0.339501827955 0.634016931057 0.000000000000 -vt 0.340652346611 0.835465610027 0.000000000000 -vt 0.309305101633 0.776968240738 0.000000000000 -vt 0.334473401308 0.773887217045 0.000000000000 -vt 0.363107293844 0.791482627392 0.000000000000 -vt 0.368501096964 0.820234537125 0.000000000000 -vt 0.358934253454 0.769033312798 0.000000000000 -vt 0.275969982147 0.743224263191 0.000000000000 -vt 0.305437386036 0.756031274796 0.000000000000 -vt 0.260169744492 0.846379280090 0.000000000000 -vt 0.235436409712 0.844436645508 0.000000000000 -vt 0.262015789747 0.854236066341 0.000000000000 -vt 0.234238356352 0.851540505886 0.000000000000 -vt 0.263981163502 0.715166091919 0.000000000000 -vt 0.267965942621 0.713351130486 0.000000000000 -vt 0.281729459763 0.734891474247 0.000000000000 -vt 0.288172066212 0.722100436687 0.000000000000 -vt 0.277648299932 0.707795619965 0.000000000000 -vt 0.291222691536 0.716961920261 0.000000000000 -vt 0.308623343706 0.723172843456 0.000000000000 -vt 0.307381391525 0.728834807873 0.000000000000 -vt 0.281491696835 0.703531861305 0.000000000000 -vt 0.305040448904 0.743083953857 0.000000000000 -vt 0.201677769423 0.717027664185 0.000000000000 -vt 0.205799683928 0.700485944748 0.000000000000 -vt 0.367262303829 0.829703629017 0.000000000000 -vt 0.341758757830 0.839105904102 0.000000000000 -vt 0.368334710598 0.833229362965 0.000000000000 -vt 0.316586196423 0.847852051258 0.000000000000 -vt 0.290764272213 0.854788422585 0.000000000000 -vt 0.327047795057 0.738471865654 0.000000000000 -vt 0.326124876738 0.730000674725 0.000000000000 -vt 0.330911010504 0.754280507565 0.000000000000 -vt 0.355491876602 0.749867677689 0.000000000000 -vt 0.351486146450 0.739300012589 0.000000000000 -vt 0.326873511076 0.724973142147 0.000000000000 -vt 0.344539195299 0.722123146057 0.000000000000 -vt 0.344190418720 0.726383745670 0.000000000000 -vt 0.261989206076 0.857144653797 0.000000000000 -vt 0.233581811190 0.854094266891 0.000000000000 -vt 0.204417899251 0.849156141281 0.000000000000 -vt 0.326887309551 0.621081113815 0.000000000000 -vt 0.252677500248 0.583962917328 0.000000000000 -vt 0.265231251717 0.586087048054 0.000000000000 -vt 0.256276845932 0.613264143467 0.000000000000 -vt 0.236884176731 0.612185239792 0.000000000000 -vt 0.225397676229 0.592031359673 0.000000000000 -vt 0.240359246731 0.578182041645 0.000000000000 -vt 0.249482765794 0.581659138203 0.000000000000 -vt 0.230406701565 0.604802131653 0.000000000000 -vt 0.221547290683 0.586520910263 0.000000000000 -vt 0.237664133310 0.573132932186 0.000000000000 -vt 0.211196690798 0.601164758205 0.000000000000 -vt 0.209809958935 0.594907939434 0.000000000000 -vt 0.213919267058 0.613228797913 0.000000000000 -vt 0.215259835124 0.621791481972 0.000000000000 -vt 0.233155399561 0.635776519775 0.000000000000 -vt 0.212040349841 0.638687551022 0.000000000000 -vt 0.329966962337 0.616993844509 0.000000000000 -vt 0.252798855305 0.635614156723 0.000000000000 -vt 0.333201110363 0.612495720387 0.000000000000 -vt 0.324382007122 0.598686695099 0.000000000000 -vt 0.311093568802 0.581733644009 0.000000000000 -vt 0.250871539116 0.659518659115 0.000000000000 -vt 0.246007040143 0.695468783379 0.000000000000 -vt 0.267591327429 0.695985734463 0.000000000000 -vt 0.229620695114 0.658928096294 0.000000000000 -vt 0.224895358086 0.685685992241 0.000000000000 -vt 0.202963665128 0.683032333851 0.000000000000 -vt 0.206480368972 0.658463180065 0.000000000000 -vt 0.225187152624 0.694258570671 0.000000000000 -vt 0.267994135618 0.700619399548 0.000000000000 -vt 0.246059074998 0.698300302029 0.000000000000 -vt 0.202539697289 0.691807746887 0.000000000000 -vt 0.292167007923 0.695293128490 0.000000000000 -vt 0.291803628206 0.699824810028 0.000000000000 -vt 0.246173635125 0.686428308487 0.000000000000 -vt 0.225166440010 0.697112381458 0.000000000000 -vt 0.202534750104 0.694576680660 0.000000000000 -vt 0.179447337985 0.689694881439 0.000000000000 -vt 0.179994687438 0.681011319160 0.000000000000 -vt 0.156249374151 0.689290702343 0.000000000000 -vt 0.153237923980 0.680606484413 0.000000000000 -vt 0.181782424450 0.657110214233 0.000000000000 -vt 0.156527668238 0.653305292130 0.000000000000 -vt 0.186954230070 0.638771533966 0.000000000000 -vt 0.162625998259 0.633767902851 0.000000000000 -vt 0.191838979721 0.622671365738 0.000000000000 -vt 0.169981136918 0.618435740471 0.000000000000 -vt 0.179694786668 0.692102015018 0.000000000000 -vt 0.157019853592 0.692945420742 0.000000000000 -vt 0.174810484052 0.610164642334 0.000000000000 -vt 0.181283250451 0.599177777767 0.000000000000 -vt 0.196757718921 0.604870617390 0.000000000000 -vt 0.192525476217 0.616066217422 0.000000000000 -vt 0.183410972357 0.595816195011 0.000000000000 -vt 0.198278859258 0.601250529289 0.000000000000 -vt 0.244824290276 0.579442679882 0.000000000000 -vt 0.273151040077 0.710567533970 0.000000000000 -vt 0.285232663155 0.728684842587 0.000000000000 -vt 0.227200508118 0.598817527294 0.000000000000 -vt 0.212605252862 0.606770217419 0.000000000000 -vt 0.305614590645 0.736904382706 0.000000000000 -vt 0.328240215778 0.744696319103 0.000000000000 -vt 0.178053170443 0.604644119740 0.000000000000 -vt 0.348152697086 0.732621014118 0.000000000000 -vt 0.194131508470 0.610380828381 0.000000000000 -vt 0.313762992620 0.607308149338 0.000000000000 -vt 0.300771087408 0.584314823151 0.000000000000 -vt 0.216887891293 0.707050144672 0.000000000000 -vt 0.208923026919 0.724448800087 0.000000000000 -vt 0.190924808383 0.733412683010 0.000000000000 -vt 0.173134177923 0.741575896740 0.000000000000 -vt 0.154957845807 0.745678186417 0.000000000000 -vt 0.360251009464 0.628313779831 0.000000000000 -vt 0.342385172844 0.628576755524 0.000000000000 -vt 0.322390943766 0.625243067741 0.000000000000 -vt 0.255816608667 0.538961172104 0.000000000000 -vt 0.255609929562 0.531903445721 0.000000000000 -vt 0.276532471180 0.523902297020 0.000000000000 -vt 0.276766628027 0.530665338039 0.000000000000 -vt 0.258155763149 0.542869150639 0.000000000000 -vt 0.239253938198 0.549565970898 0.000000000000 -vt 0.237569808960 0.546314954758 0.000000000000 -vt 0.259632319212 0.557646989822 0.000000000000 -vt 0.278000265360 0.557606041431 0.000000000000 -vt 0.280406028032 0.561680853367 0.000000000000 -vt 0.259857028723 0.562739551067 0.000000000000 -vt 0.301217794418 0.558059513569 0.000000000000 -vt 0.301868736744 0.561496496201 0.000000000000 -vt 0.280528068542 0.552090644836 0.000000000000 -vt 0.277729153633 0.535347640514 0.000000000000 -vt 0.297178983688 0.528205513954 0.000000000000 -vt 0.301819860935 0.553178787231 0.000000000000 -vt 0.296229928732 0.518692255020 0.000000000000 -vt 0.297345817089 0.522403001785 0.000000000000 -vt 0.317796647549 0.513919591904 0.000000000000 -vt 0.319642692804 0.516018092632 0.000000000000 -vt 0.318866372108 0.522611498833 0.000000000000 -vt 0.323723644018 0.553826808929 0.000000000000 -vt 0.342375040054 0.518720626831 0.000000000000 -vt 0.345081865788 0.553842306137 0.000000000000 -vt 0.325454175472 0.558225631714 0.000000000000 -vt 0.324885904789 0.562544107437 0.000000000000 -vt 0.344201058149 0.558419764042 0.000000000000 -vt 0.346064895391 0.561874091625 0.000000000000 -vt 0.367183536291 0.508728206158 0.000000000000 -vt 0.365877866745 0.516082882881 0.000000000000 -vt 0.342823565006 0.511460900307 0.000000000000 -vt 0.365199923515 0.505763173103 0.000000000000 -vt 0.387129127979 0.502111792564 0.000000000000 -vt 0.389222174883 0.506725013256 0.000000000000 -vt 0.341677963734 0.508929491043 0.000000000000 -vt 0.382050991058 0.547588169575 0.000000000000 -vt 0.364945054054 0.550378084183 0.000000000000 -vt 0.388924062252 0.514224946499 0.000000000000 -vt 0.256348222494 0.552059113979 0.000000000000 -vt 0.239861428738 0.565382003784 0.000000000000 -vt 0.239956676960 0.562402725220 0.000000000000 -vt 0.220832422376 0.568670809269 0.000000000000 -vt 0.219239458442 0.567124247551 0.000000000000 -vt 0.203210204840 0.570883214474 0.000000000000 -vt 0.201898008585 0.568920969963 0.000000000000 -vt 0.182944670320 0.570823550224 0.000000000000 -vt 0.183698490262 0.567600429058 0.000000000000 -vt 0.203983396292 0.564405024052 0.000000000000 -vt 0.204041033983 0.557649910450 0.000000000000 -vt 0.220529600978 0.554902791977 0.000000000000 -vt 0.220537245274 0.562811851501 0.000000000000 -vt 0.183808818460 0.564445316792 0.000000000000 -vt 0.182822406292 0.557343244553 0.000000000000 -vt 0.156297102571 0.564277827740 0.000000000000 -vt 0.153392598033 0.552050530910 0.000000000000 -vt 0.137154191732 0.566353738308 0.000000000000 -vt 0.156789526343 0.566984176636 0.000000000000 -vt 0.156581923366 0.569497346878 0.000000000000 -vt 0.138306304812 0.569090723991 0.000000000000 -vt 0.154402419925 0.548665106297 0.000000000000 -vt 0.132301419973 0.547170519829 0.000000000000 -vt 0.131927892566 0.543763041496 0.000000000000 -vt 0.183378085494 0.554381549358 0.000000000000 -vt 0.155377343297 0.546469151974 0.000000000000 -vt 0.182058230042 0.549026727676 0.000000000000 -vt 0.203520476818 0.547020137310 0.000000000000 -vt 0.203194230795 0.553471744061 0.000000000000 -vt 0.219951391220 0.551127851009 0.000000000000 -vt 0.219577863812 0.544329047203 0.000000000000 -vt 0.236548244953 0.540101110935 0.000000000000 -vt 0.239640295506 0.557557404041 0.000000000000 -vt 0.364015817642 0.556429386139 0.000000000000 -vt 0.364667207003 0.559019565582 0.000000000000 -vt 0.385533690453 0.553289771080 0.000000000000 -vt 0.382902741432 0.557026267052 0.000000000000 -vt 0.154217123985 0.713813722134 0.000000000000 -vt 0.157158553600 0.710084676743 0.000000000000 -vt 0.139992043376 0.697338879108 0.000000000000 -vt 0.145032361150 0.694776415825 0.000000000000 -vt 0.129598200321 0.676885545254 0.000000000000 -vt 0.133522659540 0.676785171032 0.000000000000 -vt 0.121781267226 0.655710399151 0.000000000000 -vt 0.125936508179 0.658108294010 0.000000000000 -vt 0.117115393281 0.636653959751 0.000000000000 -vt 0.121172465384 0.637733101845 0.000000000000 -vt 0.116183921695 0.616349458694 0.000000000000 -vt 0.120485514402 0.618173420429 0.000000000000 -vt 0.084196135402 0.636717438698 0.000000000000 -vt 0.084505945444 0.617743194103 0.000000000000 -vt 0.089589498937 0.618903636932 0.000000000000 -vt 0.089312784374 0.636993050575 0.000000000000 -vt 0.080862037838 0.637916862965 0.000000000000 -vt 0.081022799015 0.618841469288 0.000000000000 -vt 0.085008040071 0.598570287228 0.000000000000 -vt 0.090116359293 0.599607348442 0.000000000000 -vt 0.081807009876 0.598996996880 0.000000000000 -vt 0.086025521159 0.666380286217 0.000000000000 -vt 0.083288080990 0.667724907398 0.000000000000 -vt 0.115721911192 0.657637059689 0.000000000000 -vt 0.091839924455 0.665398180485 0.000000000000 -vt 0.112071022391 0.636431932449 0.000000000000 -vt 0.116621181369 0.598775207996 0.000000000000 -vt 0.122074656188 0.598256886005 0.000000000000 -vt 0.117822155356 0.580991744995 0.000000000000 -vt 0.122807092965 0.579663336277 0.000000000000 -vt 0.118204921484 0.561226546764 0.000000000000 -vt 0.122930236161 0.561480045319 0.000000000000 -vt 0.086409181356 0.580696821213 0.000000000000 -vt 0.088303416967 0.563481450081 0.000000000000 -vt 0.092769816518 0.562017738819 0.000000000000 -vt 0.090972624719 0.580980956554 0.000000000000 -vt 0.112636163831 0.581119179726 0.000000000000 -vt 0.110782906413 0.597800493240 0.000000000000 -vt 0.092613331974 0.689584314823 0.000000000000 -vt 0.099071905017 0.688045859337 0.000000000000 -vt 0.108099728823 0.710213482380 0.000000000000 -vt 0.102641746402 0.710727512836 0.000000000000 -vt 0.099205419421 0.711480677128 0.000000000000 -vt 0.090210475028 0.691667914391 0.000000000000 -vt 0.112440273166 0.725039958954 0.000000000000 -vt 0.109685271978 0.733518600464 0.000000000000 -vt 0.120316430926 0.724148333073 0.000000000000 -vt 0.149469718337 0.716144502163 0.000000000000 -vt 0.083509407938 0.581079363823 0.000000000000 -vt 0.085539408028 0.563082933426 0.000000000000 -vt 0.091403126717 0.541651070118 0.000000000000 -vt 0.135661408305 0.562481999397 0.000000000000 -vt 0.112166255713 0.617554724216 0.000000000000 -vt 0.115233764052 0.561244547367 0.000000000000 -vt 0.124406136572 0.679192543030 0.000000000000 -vt 0.135345742106 0.699786543846 0.000000000000 -vt 0.124257989228 0.753876924515 0.000000000000 -vt 0.128552585840 0.751157760620 0.000000000000 -vt 0.165847733617 0.731854498386 0.000000000000 -vt 0.135802805424 0.748261570930 0.000000000000 -vt 0.166685536504 0.724866151810 0.000000000000 -vt 0.170482099056 0.722631275654 0.000000000000 -vt 0.118092343211 0.538387894630 0.000000000000 -vt 0.120958782732 0.537692189217 0.000000000000 -vt 0.098085269332 0.540873169899 0.000000000000 -vt 0.094365492463 0.541822671890 0.000000000000 -vt 0.132603570819 0.540962100029 0.000000000000 -vt 0.113834425807 0.538623392582 0.000000000000 -vt 0.319482028484 0.899047315121 0.000000000000 -vt 0.309817373753 0.903006970882 0.000000000000 -vt 0.303308844566 0.883904874325 0.000000000000 -vt 0.314649820328 0.880987823009 0.000000000000 -vt 0.328109025955 0.880558192730 0.000000000000 -vt 0.328658103943 0.897744834423 0.000000000000 -vt 0.341684728861 0.882348120213 0.000000000000 -vt 0.338721781969 0.899649322033 0.000000000000 -vt 0.355538994074 0.885123133659 0.000000000000 -vt 0.346919715405 0.902684092522 0.000000000000 -vt 0.264496624470 0.923883795738 0.000000000000 -vt 0.285223543644 0.930731534958 0.000000000000 -vt 0.267435461283 0.909074544907 0.000000000000 -vt 0.288075894117 0.921931266785 0.000000000000 -vt 0.274401426315 0.897557139397 0.000000000000 -vt 0.292297661304 0.914312303066 0.000000000000 -vt 0.287088751793 0.890229046345 0.000000000000 -vt 0.300147175789 0.908530831337 0.000000000000 -vt 0.310877472162 0.867308914661 0.000000000000 -vt 0.326778471470 0.865757822990 0.000000000000 -vt 0.343281567097 0.865718007088 0.000000000000 -vt 0.361255347729 0.866305887699 0.000000000000 -vt 0.245798677206 0.914549648762 0.000000000000 -vt 0.250797957182 0.897025287151 0.000000000000 -vt 0.263053983450 0.883340418339 0.000000000000 -vt 0.278658270836 0.875975549221 0.000000000000 -vt 0.297883272171 0.872081577778 0.000000000000 -vt 0.321375846863 0.908167660236 0.000000000000 -vt 0.313384771347 0.911024928093 0.000000000000 -vt 0.312286227942 0.907532513142 0.000000000000 -vt 0.320597171783 0.903883635998 0.000000000000 -vt 0.329484283924 0.906974732876 0.000000000000 -vt 0.329025387764 0.902560055256 0.000000000000 -vt 0.335602283478 0.907388985157 0.000000000000 -vt 0.336900919676 0.903732657433 0.000000000000 -vt 0.340975165367 0.909342050552 0.000000000000 -vt 0.344243913889 0.905984163284 0.000000000000 -vt 0.292275160551 0.931756854057 0.000000000000 -vt 0.288374781609 0.931339025497 0.000000000000 -vt 0.294533699751 0.926007986069 0.000000000000 -vt 0.291681826115 0.923927128315 0.000000000000 -vt 0.298611998558 0.919755756855 0.000000000000 -vt 0.295432448387 0.917401850224 0.000000000000 -vt 0.304809689522 0.915081322193 0.000000000000 -vt 0.302478045225 0.912388324738 0.000000000000 -vt 0.309649169445 0.859347939491 0.000000000000 -vt 0.325541138649 0.857225894928 0.000000000000 -vt 0.326330006123 0.861102938652 0.000000000000 -vt 0.309487581253 0.863262355328 0.000000000000 -vt 0.341508537531 0.857451260090 0.000000000000 -vt 0.343136012554 0.863369047642 0.000000000000 -vt 0.356366693974 0.855853736401 0.000000000000 -vt 0.360483229160 0.861095964909 0.000000000000 -vt 0.237906411290 0.910131931305 0.000000000000 -vt 0.242411300540 0.912403225899 0.000000000000 -vt 0.243345454335 0.892147541046 0.000000000000 -vt 0.247076600790 0.894490242004 0.000000000000 -vt 0.255101680756 0.878566741943 0.000000000000 -vt 0.258435934782 0.881105363369 0.000000000000 -vt 0.274271398783 0.868584036827 0.000000000000 -vt 0.276469051838 0.872065901756 0.000000000000 -vt 0.295189887285 0.862639725208 0.000000000000 -vt 0.297131747007 0.866627097130 0.000000000000 -vt 0.264509558678 0.939163446426 0.000000000000 -vt 0.284231007099 0.939391553402 0.000000000000 -vt 0.245086982846 0.933630704880 0.000000000000 -vt 0.292607039213 0.937922894955 0.000000000000 -vt 0.288247227669 0.939458549023 0.000000000000 -vt 0.234031543136 0.927958786488 0.000000000000 -vt 0.239948898554 0.931120336056 0.000000000000 -vt 0.303108215332 0.259901374578 0.000000000000 -vt 0.299691259861 0.272608458996 0.000000000000 -vt 0.227741092443 0.179622754455 0.000000000000 -vt 0.241408705711 0.177819043398 0.000000000000 -vt 0.288645803928 0.272444993258 0.000000000000 -vt 0.249047771096 0.186873659492 0.000000000000 -vt 0.294585645199 0.259171187878 0.000000000000 -vt 0.304501682520 0.254701167345 0.000000000000 -vt 0.313444852829 0.253634393215 0.000000000000 -vt 0.312482535839 0.259582310915 0.000000000000 -vt 0.296862632036 0.254683613777 0.000000000000 -vt 0.286406427622 0.256932258606 0.000000000000 -vt 0.289906680584 0.252584934235 0.000000000000 -vt 0.279214531183 0.252052009106 0.000000000000 -vt 0.283777058125 0.248220309615 0.000000000000 -vt 0.278458207846 0.270513832569 0.000000000000 -vt 0.212318181992 0.149050965905 0.000000000000 -vt 0.220562011003 0.146735697985 0.000000000000 -vt 0.222703933716 0.152291625738 0.000000000000 -vt 0.213263839483 0.154687494040 0.000000000000 -vt 0.203408792615 0.155836462975 0.000000000000 -vt 0.203189268708 0.150103569031 0.000000000000 -vt 0.193548575044 0.156050369143 0.000000000000 -vt 0.193696498871 0.150199025869 0.000000000000 -vt 0.183689251542 0.155369937420 0.000000000000 -vt 0.184210494161 0.149640426040 0.000000000000 -vt 0.193191483617 0.169719755650 0.000000000000 -vt 0.182228907943 0.169336318970 0.000000000000 -vt 0.268187999725 0.265260279179 0.000000000000 -vt 0.324253201485 0.252125859261 0.000000000000 -vt 0.231818437576 0.195312470198 0.000000000000 -vt 0.212309181690 0.181552782655 0.000000000000 -vt 0.213149681687 0.200687378645 0.000000000000 -vt 0.197734892368 0.182133242488 0.000000000000 -vt 0.196059510112 0.201420485973 0.000000000000 -vt 0.178108111024 0.197619631886 0.000000000000 -vt 0.184773385525 0.179257780313 0.000000000000 -vt 0.193671286106 0.220274075866 0.000000000000 -vt 0.204073458910 0.169701069593 0.000000000000 -vt 0.171984791756 0.217511638999 0.000000000000 -vt 0.196902945638 0.242536947131 0.000000000000 -vt 0.323984831572 0.258038192987 0.000000000000 -vt 0.310539454222 0.271224856377 0.000000000000 -vt 0.324096947908 0.268115252256 0.000000000000 -vt 0.339193135500 0.265587210655 0.000000000000 -vt 0.336792320013 0.254855424166 0.000000000000 -vt 0.340972989798 0.271843373775 0.000000000000 -vt 0.325516790152 0.274833887815 0.000000000000 -vt 0.313507229090 0.275261014700 0.000000000000 -vt 0.171768411994 0.240901872516 0.000000000000 -vt 0.215576186776 0.241010859609 0.000000000000 -vt 0.215113937855 0.219385609031 0.000000000000 -vt 0.179179176688 0.179597318172 0.000000000000 -vt 0.354237109423 0.261272788048 0.000000000000 -vt 0.356365293264 0.266201436520 0.000000000000 -vt 0.348684787750 0.251001656055 0.000000000000 -vt 0.335720360279 0.249260529876 0.000000000000 -vt 0.346057444811 0.245707139373 0.000000000000 -vt 0.367124110460 0.254228800535 0.000000000000 -vt 0.359250634909 0.246444091201 0.000000000000 -vt 0.355434030294 0.241601213813 0.000000000000 -vt 0.369936972857 0.258326172829 0.000000000000 -vt 0.169737070799 0.113030180335 0.000000000000 -vt 0.170575097203 0.120991900563 0.000000000000 -vt 0.297219276428 0.135332033038 0.000000000000 -vt 0.283211469650 0.234442397952 0.000000000000 -vt 0.292599529028 0.237945362926 0.000000000000 -vt 0.298478573561 0.140298739076 0.000000000000 -vt 0.290076673031 0.243708446622 0.000000000000 -vt 0.282434672117 0.239781066775 0.000000000000 -vt 0.305352568626 0.241858348250 0.000000000000 -vt 0.303028285503 0.248206838965 0.000000000000 -vt 0.324729174376 0.241821423173 0.000000000000 -vt 0.321562141180 0.249174103141 0.000000000000 -vt 0.347120851278 0.237402305007 0.000000000000 -vt 0.343635231256 0.232021078467 0.000000000000 -vt 0.357544183731 0.220489770174 0.000000000000 -vt 0.362244993448 0.226528212428 0.000000000000 -vt 0.363515973091 0.202669411898 0.000000000000 -vt 0.368934571743 0.200474381447 0.000000000000 -vt 0.344842731953 0.210690349340 0.000000000000 -vt 0.342417836189 0.185361966491 0.000000000000 -vt 0.364349514246 0.181216180325 0.000000000000 -vt 0.324543416500 0.218253985047 0.000000000000 -vt 0.321842014790 0.191119849682 0.000000000000 -vt 0.337232500315 0.165248394012 0.000000000000 -vt 0.356791496277 0.164284512401 0.000000000000 -vt 0.332506477833 0.147537469864 0.000000000000 -vt 0.347481101751 0.153085976839 0.000000000000 -vt 0.318637371063 0.169776722789 0.000000000000 -vt 0.312718063593 0.146633028984 0.000000000000 -vt 0.370308697224 0.181861028075 0.000000000000 -vt 0.360243141651 0.161985456944 0.000000000000 -vt 0.304652988911 0.221441268921 0.000000000000 -vt 0.303939700127 0.197721183300 0.000000000000 -vt 0.289470791817 0.148055776954 0.000000000000 -vt 0.285560518503 0.142270863056 0.000000000000 -vt 0.291176348925 0.221764370799 0.000000000000 -vt 0.288291871548 0.203909799457 0.000000000000 -vt 0.276085317135 0.156505629420 0.000000000000 -vt 0.272780030966 0.150750204921 0.000000000000 -vt 0.258125126362 0.158074513078 0.000000000000 -vt 0.260224252939 0.163233041763 0.000000000000 -vt 0.243465483189 0.162214890122 0.000000000000 -vt 0.243714034557 0.151190385222 0.000000000000 -vt 0.254636585712 0.146920993924 0.000000000000 -vt 0.229478836060 0.163604542613 0.000000000000 -vt 0.233701616526 0.153107583523 0.000000000000 -vt 0.167218700051 0.121271774173 0.000000000000 -vt 0.166369423270 0.112692907453 0.000000000000 -vt 0.243073940277 0.145069316030 0.000000000000 -vt 0.252761274576 0.141263067722 0.000000000000 -vt 0.263089358807 0.136896863580 0.000000000000 -vt 0.266313344240 0.141587063670 0.000000000000 -vt 0.277861565351 0.135119035840 0.000000000000 -vt 0.273413181305 0.131129965186 0.000000000000 -vt 0.282169669867 0.124930545688 0.000000000000 -vt 0.287077844143 0.128512978554 0.000000000000 -vt 0.289280533791 0.119594141841 0.000000000000 -vt 0.293950706720 0.122467115521 0.000000000000 -vt 0.168387711048 0.136361449957 0.000000000000 -vt 0.172123029828 0.133879333735 0.000000000000 -vt 0.159614548087 0.137594163418 0.000000000000 -vt 0.170139640570 0.142349898815 0.000000000000 -vt 0.159916698933 0.145990878344 0.000000000000 -vt 0.175263956189 0.137986391783 0.000000000000 -vt 0.158946737647 0.121140733361 0.000000000000 -vt 0.158538520336 0.111063912511 0.000000000000 -vt 0.150848120451 0.113286182284 0.000000000000 -vt 0.147537663579 0.113875642419 0.000000000000 -vt 0.150810301304 0.122010722756 0.000000000000 -vt 0.150818631053 0.137049511075 0.000000000000 -vt 0.146893724799 0.134909197688 0.000000000000 -vt 0.234794318676 0.147171825171 0.000000000000 -vt 0.280413031578 0.223018944263 0.000000000000 -vt 0.244322419167 0.167136326432 0.000000000000 -vt 0.215430051088 0.169227793813 0.000000000000 -vt 0.276956439018 0.210102006793 0.000000000000 -vt 0.230842590332 0.168110579252 0.000000000000 -vt 0.304748684168 0.128483712673 0.000000000000 -vt 0.319317579269 0.112706646323 0.000000000000 -vt 0.304126799107 0.108920201659 0.000000000000 -vt 0.306201845407 0.100410684943 0.000000000000 -vt 0.324304103851 0.102940306067 0.000000000000 -vt 0.298506706953 0.108017548919 0.000000000000 -vt 0.227834999561 0.168783783913 0.000000000000 -vt 0.173827692866 0.153802856803 0.000000000000 -vt 0.164431959391 0.150985270739 0.000000000000 -vt 0.166879624128 0.145447134972 0.000000000000 -vt 0.175091713667 0.148140892386 0.000000000000 -vt 0.170737877488 0.168616726995 0.000000000000 -vt 0.158358171582 0.168257147074 0.000000000000 -vt 0.171079888940 0.173917546868 0.000000000000 -vt 0.298551976681 0.176225617528 0.000000000000 -vt 0.284409761429 0.187349408865 0.000000000000 -vt 0.278388887644 0.172707334161 0.000000000000 -vt 0.265587240458 0.188653051853 0.000000000000 -vt 0.263487190008 0.183533251286 0.000000000000 -vt 0.172304287553 0.195576354861 0.000000000000 -vt 0.166341051459 0.215843468904 0.000000000000 -vt 0.246410295367 0.175310358405 0.000000000000 -vt 0.253420293331 0.181435257196 0.000000000000 -vt 0.258993119001 0.199986010790 0.000000000000 -vt 0.238587737083 0.209960162640 0.000000000000 -vt 0.263290882111 0.194039210677 0.000000000000 -vt 0.244794785976 0.230162426829 0.000000000000 -vt 0.267062664032 0.219509899616 0.000000000000 -vt 0.265724569559 0.241132006049 0.000000000000 -vt 0.247063919902 0.252580881119 0.000000000000 -vt 0.260249704123 0.258537381887 0.000000000000 -vt 0.247949019074 0.272692441940 0.000000000000 -vt 0.271840006113 0.241458699107 0.000000000000 -vt 0.267441391945 0.259758830070 0.000000000000 -vt 0.274886131287 0.221160054207 0.000000000000 -vt 0.248786136508 0.278353273869 0.000000000000 -vt 0.233543574810 0.288995474577 0.000000000000 -vt 0.228813290596 0.284420073032 0.000000000000 -vt 0.222581654787 0.263455659151 0.000000000000 -vt 0.201069429517 0.264848470688 0.000000000000 -vt 0.147332772613 0.121980324388 0.000000000000 -vt 0.149485930800 0.143096730113 0.000000000000 -vt 0.144085362554 0.139203354716 0.000000000000 -vt 0.274613022804 0.168164387345 0.000000000000 -vt 0.272586405277 0.198066562414 0.000000000000 -vt 0.292887955904 0.156603798270 0.000000000000 -vt 0.289811223745 0.151691362262 0.000000000000 -vt 0.308121502399 0.141383305192 0.000000000000 -vt 0.331666439772 0.141558468342 0.000000000000 -vt 0.346801817417 0.147019162774 0.000000000000 -vt 0.208444163203 0.284849673510 0.000000000000 -vt 0.207779288292 0.289209812880 0.000000000000 -vt 0.329524755478 0.248061582446 0.000000000000 -vt 0.180802538991 0.263033509254 0.000000000000 -vt 0.364997059107 0.218376457691 0.000000000000 -vt 0.185599476099 0.280001878738 0.000000000000 -vt 0.174449339509 0.263261795044 0.000000000000 -vt 0.192701548338 0.278811007738 0.000000000000 -vt 0.367429643869 0.175568386912 0.000000000000 -vt 0.166094049811 0.244550302625 0.000000000000 -vt 0.159377232194 0.173221364617 0.000000000000 -vt 0.182153701782 0.175170764327 0.000000000000 -vt 0.193075969815 0.175665423274 0.000000000000 -vt 0.313833713531 0.139958515763 0.000000000000 -vt 0.352484732866 0.149898454547 0.000000000000 -vt 0.203923046589 0.175497695804 0.000000000000 -vt 0.214893281460 0.174428433180 0.000000000000 -vt 0.226242244244 0.173432335258 0.000000000000 -vt 0.378087341785 0.245563969016 0.000000000000 -vt 0.380262136459 0.249743267894 0.000000000000 -vt 0.367841005325 0.240881398320 0.000000000000 -vt 0.362897038460 0.237351402640 0.000000000000 -vt 0.300132334232 0.100594177842 0.000000000000 -vt 0.299615830183 0.116130575538 0.000000000000 -vt 0.294845253229 0.114346668124 0.000000000000 -vt 0.312476694584 0.120818093419 0.000000000000 -vt 0.262099564075 0.265859633684 0.000000000000 -vt 0.271560132504 0.212059065700 0.000000000000 -vt 0.224148511887 0.289957106113 0.000000000000 -vt 0.191555723548 0.285657763481 0.000000000000 -vt 0.165448531508 0.236725702882 0.000000000000 -vt 0.048055123538 0.175203412771 0.000000000000 -vt 0.048704918474 0.175287619233 0.000000000000 -vt 0.049519758672 0.175945073366 0.000000000000 -vt 0.048962052912 0.176530927420 0.000000000000 -vt 0.048142258078 0.174550458789 0.000000000000 -vt 0.048840459436 0.174907326698 0.000000000000 -vt 0.048184361309 0.177168339491 0.000000000000 -vt 0.047785613686 0.175479233265 0.000000000000 -vt 0.050077687949 0.175508722663 0.000000000000 -vt 0.049611847848 0.173526674509 0.000000000000 -vt 0.050155591220 0.174321472645 0.000000000000 -vt 0.050484325737 0.174935474992 0.000000000000 -vt 0.049262631685 0.178634554148 0.000000000000 -vt 0.050630893558 0.177782341838 0.000000000000 -vt 0.053486991674 0.179326459765 0.000000000000 -vt 0.051250975579 0.172665014863 0.000000000000 -vt 0.052335549146 0.174432024360 0.000000000000 -vt 0.052290286869 0.172393932939 0.000000000000 -vt 0.060022119433 0.196368679404 0.000000000000 -vt 0.059825789183 0.195150136948 0.000000000000 -vt 0.062848724425 0.193425223231 0.000000000000 -vt 0.063640370965 0.194470614195 0.000000000000 -vt 0.057444769889 0.198157310486 0.000000000000 -vt 0.061123806983 0.204831123352 0.000000000000 -vt 0.054434444755 0.202152684331 0.000000000000 -vt 0.052125032991 0.196384206414 0.000000000000 -vt 0.065405808389 0.200892046094 0.000000000000 -vt 0.053650680929 0.194501906633 0.000000000000 -vt 0.071322210133 0.182865217328 0.000000000000 -vt 0.069051973522 0.180266022682 0.000000000000 -vt 0.072467572987 0.177512601018 0.000000000000 -vt 0.073771677911 0.182455211878 0.000000000000 -vt 0.046373885125 0.201640009880 0.000000000000 -vt 0.047620352358 0.205844104290 0.000000000000 -vt 0.044672172517 0.207344532013 0.000000000000 -vt 0.043322812766 0.201532378793 0.000000000000 -vt 0.048094075173 0.197172701359 0.000000000000 -vt 0.050799090415 0.203515991569 0.000000000000 -vt 0.043212261051 0.193465515971 0.000000000000 -vt 0.038478370756 0.209311038256 0.000000000000 -vt 0.037481162697 0.210909873247 0.000000000000 -vt 0.035782586783 0.208673626184 0.000000000000 -vt 0.036327917129 0.206941053271 0.000000000000 -vt 0.038885008544 0.211182534695 0.000000000000 -vt 0.037817772478 0.205236405134 0.000000000000 -vt 0.037915710360 0.216193586588 0.000000000000 -vt 0.036525826901 0.213128775358 0.000000000000 -vt 0.033292595297 0.211684182286 0.000000000000 -vt 0.032988864928 0.209396824241 0.000000000000 -vt 0.044357400388 0.213697507977 0.000000000000 -vt 0.040415156633 0.211841553450 0.000000000000 -vt 0.041487347335 0.208158016205 0.000000000000 -vt 0.042062167078 0.222331538796 0.000000000000 -vt 0.039700064808 0.219182297587 0.000000000000 -vt 0.046859998256 0.219299152493 0.000000000000 -vt 0.039277669042 0.216008275747 0.000000000000 -vt 0.090955741704 0.182833924890 0.000000000000 -vt 0.095942027867 0.185236781836 0.000000000000 -vt 0.091125510633 0.186936691403 0.000000000000 -vt 0.090062774718 0.185735270381 0.000000000000 -vt 0.091737933457 0.190855517983 0.000000000000 -vt 0.087909393013 0.188273668289 0.000000000000 -vt 0.096602633595 0.188918739557 0.000000000000 -vt 0.094589523971 0.190106213093 0.000000000000 -vt 0.088805288076 0.195824697614 0.000000000000 -vt 0.085034608841 0.192018002272 0.000000000000 -vt 0.037808310241 0.218160092831 0.000000000000 -vt 0.101674705744 0.180272325873 0.000000000000 -vt 0.108147457242 0.181930154562 0.000000000000 -vt 0.084888033569 0.212164208293 0.000000000000 -vt 0.086827971041 0.209401324391 0.000000000000 -vt 0.092867530882 0.213331192732 0.000000000000 -vt 0.090507008135 0.217772141099 0.000000000000 -vt 0.078402668238 0.211174651980 0.000000000000 -vt 0.081946156919 0.206284955144 0.000000000000 -vt 0.064126476645 0.226784884930 0.000000000000 -vt 0.059163603932 0.221614643931 0.000000000000 -vt 0.063531167805 0.218933045864 0.000000000000 -vt 0.066850177944 0.224536255002 0.000000000000 -vt 0.058718021959 0.224759161472 0.000000000000 -vt 0.052740599960 0.222449973226 0.000000000000 -vt 0.051313344389 0.218079030514 0.000000000000 -vt 0.056304361671 0.215266615152 0.000000000000 -vt 0.052650313824 0.225943475962 0.000000000000 -vt 0.101671561599 0.191067621112 0.000000000000 -vt 0.102857217193 0.187916800380 0.000000000000 -vt 0.090246729553 0.206087037921 0.000000000000 -vt 0.085568904877 0.202257156372 0.000000000000 -vt 0.091549478471 0.199667423964 0.000000000000 -vt 0.092842765152 0.201647892594 0.000000000000 -vt 0.092551417649 0.205803573132 0.000000000000 -vt 0.094774819911 0.209103897214 0.000000000000 -vt 0.094059728086 0.210680663586 0.000000000000 -vt 0.095144078135 0.195538073778 0.000000000000 -vt 0.099691078067 0.194344520569 0.000000000000 -vt 0.099405810237 0.196164458990 0.000000000000 -vt 0.099158152938 0.198102816939 0.000000000000 -vt 0.095910727978 0.198648139834 0.000000000000 -vt 0.040310692042 0.223760381341 0.000000000000 -vt 0.038051482290 0.225095763803 0.000000000000 -vt 0.039297934622 0.221828088164 0.000000000000 -vt 0.048715729266 0.226211413741 0.000000000000 -vt 0.048271726817 0.223471954465 0.000000000000 -vt 0.054012056440 0.227152556181 0.000000000000 -vt 0.051328878850 0.229439899325 0.000000000000 -vt 0.050317708403 0.229129895568 0.000000000000 -vt 0.048270147294 0.228640601039 0.000000000000 -vt 0.040398042649 0.225845307112 0.000000000000 -vt 0.043110940605 0.225429221988 0.000000000000 -vt 0.043746557087 0.226806730032 0.000000000000 -vt 0.041524719447 0.227182060480 0.000000000000 -vt 0.039583209902 0.227637097239 0.000000000000 -vt 0.037672769278 0.226903319359 0.000000000000 -vt 0.033523153514 0.225719004869 0.000000000000 -vt 0.036088127643 0.224684417248 0.000000000000 -vt 0.036136310548 0.226817533374 0.000000000000 -vt 0.034433234483 0.227448642254 0.000000000000 -vt 0.027782825753 0.229924663901 0.000000000000 -vt 0.030765233561 0.223758801818 0.000000000000 -vt 0.030333613977 0.231470361352 0.000000000000 -vt 0.110832214355 0.191612944007 0.000000000000 -vt 0.111078530550 0.184968620539 0.000000000000 -vt 0.106155976653 0.192477762699 0.000000000000 -vt 0.041945312172 0.228952214122 0.000000000000 -vt 0.038930263370 0.230628952384 0.000000000000 -vt 0.041834760457 0.232057794929 0.000000000000 -vt 0.044282648712 0.228836938739 0.000000000000 -vt 0.044818740338 0.232165411115 0.000000000000 -vt 0.039072107524 0.234580442309 0.000000000000 -vt 0.036424513906 0.232783898711 0.000000000000 -vt 0.106855750084 0.201680526137 0.000000000000 -vt 0.103606760502 0.198020190001 0.000000000000 -vt 0.104195758700 0.196577385068 0.000000000000 -vt 0.107200011611 0.198694974184 0.000000000000 -vt 0.109750792384 0.200388818979 0.000000000000 -vt 0.109513923526 0.203364923596 0.000000000000 -vt 0.105775907636 0.203093826771 0.000000000000 -vt 0.102690592408 0.199908792973 0.000000000000 -vt 0.050538811833 0.243682101369 0.000000000000 -vt 0.048396233469 0.240920796990 0.000000000000 -vt 0.048424374312 0.237581744790 0.000000000000 -vt 0.051719974726 0.241248175502 0.000000000000 -vt 0.046845819801 0.239993855357 0.000000000000 -vt 0.108550950885 0.195103302598 0.000000000000 -vt 0.107877954841 0.196638181806 0.000000000000 -vt 0.104663178325 0.194704324007 0.000000000000 -vt 0.111446216702 0.196098938584 0.000000000000 -vt 0.110371097922 0.198414430022 0.000000000000 -vt 0.033939246088 0.229781255126 0.000000000000 -vt 0.032943610102 0.235806867480 0.000000000000 -vt 0.036778222769 0.228347703815 0.000000000000 -vt 0.026748239994 0.237935468554 0.000000000000 -vt 0.029005868360 0.239583835006 0.000000000000 -vt 0.024600934237 0.235979780555 0.000000000000 -vt 0.036203410476 0.237542793155 0.000000000000 -vt 0.047933544964 0.242292001843 0.000000000000 -vt 0.048371467739 0.243713185191 0.000000000000 -vt 0.047026615590 0.242233023047 0.000000000000 -vt 0.047408472747 0.243272319436 0.000000000000 -vt 0.112042874098 0.199774816632 0.000000000000 -vt 0.112708196044 0.198945805430 0.000000000000 -vt 0.112421587110 0.201317355037 0.000000000000 -vt 0.115999296308 0.201012045145 0.000000000000 -vt 0.047676410526 0.245324388146 0.000000000000 -vt 0.046835009009 0.243697628379 0.000000000000 -vt 0.046366009861 0.242653593421 0.000000000000 -vt 0.116282775998 0.196683213115 0.000000000000 -vt 0.054629202932 0.245314940810 0.000000000000 -vt 0.055006336421 0.243421837687 0.000000000000 -vt 0.054401572794 0.246826633811 0.000000000000 -vt 0.049971643835 0.245547279716 0.000000000000 -vt 0.045614894480 0.244002953172 0.000000000000 -vt 0.046210203320 0.243990585208 0.000000000000 -vt 0.046083893627 0.245279118419 0.000000000000 -vt 0.044977705926 0.244760379195 0.000000000000 -vt 0.044843737036 0.243163123727 0.000000000000 -vt 0.045724090189 0.242940440774 0.000000000000 -vt 0.044279497117 0.243847146630 0.000000000000 -vt 0.042543780059 0.243463918567 0.000000000000 -vt 0.042998816818 0.241575345397 0.000000000000 -vt 0.043060954660 0.245589390397 0.000000000000 -vt 0.050320636481 0.250064343214 0.000000000000 -vt 0.046863149852 0.247579082847 0.000000000000 -vt 0.044486861676 0.247248783708 0.000000000000 -vt 0.115950897336 0.205869093537 0.000000000000 -vt 0.111902818084 0.203687563539 0.000000000000 -vt 0.067590266466 0.245651528239 0.000000000000 -vt 0.060156088322 0.247964099050 0.000000000000 -vt 0.059522051364 0.246006831527 0.000000000000 -vt 0.064255714417 0.241894826293 0.000000000000 -vt 0.075842648745 0.243643149734 0.000000000000 -vt 0.076406665146 0.251217573881 0.000000000000 -vt 0.068737201393 0.251990318298 0.000000000000 -vt 0.061447802931 0.252729058266 0.000000000000 -vt 0.101252302527 0.229214087129 0.000000000000 -vt 0.107055231929 0.225204750896 0.000000000000 -vt 0.110550090671 0.228503510356 0.000000000000 -vt 0.103125378489 0.234605416656 0.000000000000 -vt 0.093981824815 0.227124422789 0.000000000000 -vt 0.102826148272 0.221592798829 0.000000000000 -vt 0.093353867531 0.237001970410 0.000000000000 -vt 0.031605061144 0.248132273555 0.000000000000 -vt 0.033780287951 0.241846427321 0.000000000000 -vt 0.038934987038 0.242647275329 0.000000000000 -vt 0.038883429021 0.246692433953 0.000000000000 -vt 0.040764149278 0.250432223082 0.000000000000 -vt 0.034480068833 0.253740221262 0.000000000000 -vt 0.026098441333 0.256615221500 0.000000000000 -vt 0.024784889072 0.253078043461 0.000000000000 -vt 0.027103310451 0.246195510030 0.000000000000 -vt 0.022952351719 0.252045035362 0.000000000000 -vt 0.043932076544 0.254584789276 0.000000000000 -vt 0.049854788929 0.255521208048 0.000000000000 -vt 0.035871531814 0.256568402052 0.000000000000 -vt 0.127526775002 0.205384328961 0.000000000000 -vt 0.129298523068 0.208109617233 0.000000000000 -vt 0.124919943511 0.212541341782 0.000000000000 -vt 0.122282020748 0.208313822746 0.000000000000 -vt 0.130605995655 0.199026852846 0.000000000000 -vt 0.134021386504 0.202176094055 0.000000000000 -vt 0.123184211552 0.201524719596 0.000000000000 -vt 0.043590750545 0.262480288744 0.000000000000 -vt 0.045658569783 0.265317708254 0.000000000000 -vt 0.042624827474 0.268781721592 0.000000000000 -vt 0.040003802627 0.268262714148 0.000000000000 -vt 0.049783188850 0.260548025370 0.000000000000 -vt 0.050202202052 0.262952446938 0.000000000000 -vt 0.035101722926 0.267388671637 0.000000000000 -vt 0.036307651550 0.262090772390 0.000000000000 -vt 0.158384069800 0.177545472980 0.000000000000 -vt 0.163128763437 0.177713662386 0.000000000000 -vt 0.161081433296 0.184286177158 0.000000000000 -vt 0.155855119228 0.182891562581 0.000000000000 -vt 0.030163845047 0.266456753016 0.000000000000 -vt 0.028748972341 0.262917995453 0.000000000000 -vt 0.152635857463 0.180741325021 0.000000000000 -vt 0.156146481633 0.174547314644 0.000000000000 -vt 0.108293592930 0.175105020404 0.000000000000 -vt 0.103180319071 0.172587782145 0.000000000000 -vt 0.102925881743 0.166502520442 0.000000000000 -vt 0.107659325004 0.167699888349 0.000000000000 -vt 0.091472923756 0.255974650383 0.000000000000 -vt 0.083825305104 0.257546931505 0.000000000000 -vt 0.084012404084 0.249293193221 0.000000000000 -vt 0.091871894896 0.246349737048 0.000000000000 -vt 0.112725540996 0.167742446065 0.000000000000 -vt 0.113225832582 0.171109184623 0.000000000000 -vt 0.035772006959 0.183283552527 0.000000000000 -vt 0.035782817751 0.183923900127 0.000000000000 -vt 0.033255446702 0.184070467949 0.000000000000 -vt 0.033405173570 0.183254063129 0.000000000000 -vt 0.038481753320 0.182127386332 0.000000000000 -vt 0.038974162191 0.182417154312 0.000000000000 -vt 0.034431885928 0.181669190526 0.000000000000 -vt 0.036685016006 0.180374324322 0.000000000000 -vt 0.144137382507 0.199537962675 0.000000000000 -vt 0.139657467604 0.194585889578 0.000000000000 -vt 0.144188717008 0.186229258776 0.000000000000 -vt 0.148093581200 0.188943728805 0.000000000000 -vt 0.136400818825 0.206110462546 0.000000000000 -vt 0.153703317046 0.190900772810 0.000000000000 -vt 0.151239663363 0.198920801282 0.000000000000 -vt 0.150279834867 0.205067992210 0.000000000000 -vt 0.143856838346 0.206392586231 0.000000000000 -vt 0.163417190313 0.198642060161 0.000000000000 -vt 0.164253860712 0.202018722892 0.000000000000 -vt 0.160158962011 0.199008166790 0.000000000000 -vt 0.162906080484 0.192356184125 0.000000000000 -vt 0.165629789233 0.191846653819 0.000000000000 -vt 0.028680523857 0.176149964333 0.000000000000 -vt 0.028775541112 0.179067075253 0.000000000000 -vt 0.027133254334 0.179045230150 0.000000000000 -vt 0.026841904968 0.175766751170 0.000000000000 -vt 0.107328131795 0.163071155548 0.000000000000 -vt 0.102894365788 0.161774039268 0.000000000000 -vt 0.103162080050 0.158067077398 0.000000000000 -vt 0.107190564275 0.158765062690 0.000000000000 -vt 0.034622143954 0.168636307120 0.000000000000 -vt 0.034757684916 0.167032986879 0.000000000000 -vt 0.037417437881 0.167039290071 0.000000000000 -vt 0.036150719970 0.169255033135 0.000000000000 -vt 0.032856475562 0.170001432300 0.000000000000 -vt 0.031410526484 0.168317034841 0.000000000000 -vt 0.071371294558 0.162234246731 0.000000000000 -vt 0.072683498263 0.160097971559 0.000000000000 -vt 0.074752002954 0.160783797503 0.000000000000 -vt 0.072475455701 0.163342237473 0.000000000000 -vt 0.070219628513 0.164971008897 0.000000000000 -vt 0.067989014089 0.162172779441 0.000000000000 -vt 0.070951156318 0.158560618758 0.000000000000 -vt 0.071128129959 0.166468963027 0.000000000000 -vt 0.069623641670 0.166651114821 0.000000000000 -vt 0.052506666631 0.160904929042 0.000000000000 -vt 0.057779353112 0.165149331093 0.000000000000 -vt 0.056724499911 0.167911082506 0.000000000000 -vt 0.050493102521 0.165551453829 0.000000000000 -vt 0.060259658843 0.168007910252 0.000000000000 -vt 0.059231828898 0.159990578890 0.000000000000 -vt 0.061392862350 0.158380940557 0.000000000000 -vt 0.063771635294 0.161536499858 0.000000000000 -vt 0.063607268035 0.163274914026 0.000000000000 -vt 0.055211450905 0.155678853393 0.000000000000 -vt 0.057744000107 0.153191789985 0.000000000000 -vt 0.058993611485 0.163293376565 0.000000000000 -vt 0.053434979171 0.158556342125 0.000000000000 -vt 0.064857780933 0.162417531013 0.000000000000 -vt 0.064824908972 0.161404550076 0.000000000000 -vt 0.031159481034 0.208711221814 0.000000000000 -vt 0.030880516395 0.210443794727 0.000000000000 -vt 0.029724342749 0.204800054431 0.000000000000 -vt 0.031837198883 0.204756379128 0.000000000000 -vt 0.128212377429 0.176210075617 0.000000000000 -vt 0.128955841064 0.177864745259 0.000000000000 -vt 0.126242950559 0.177906855941 0.000000000000 -vt 0.125418648124 0.176409572363 0.000000000000 -vt 0.129953056574 0.174939975142 0.000000000000 -vt 0.130758658051 0.176998347044 0.000000000000 -vt 0.121036924422 0.175653725863 0.000000000000 -vt 0.121420361102 0.178308978677 0.000000000000 -vt 0.123617418110 0.183743998408 0.000000000000 -vt 0.117588669062 0.183899804950 0.000000000000 -vt 0.115403994918 0.191726654768 0.000000000000 -vt 0.122710488737 0.192234605551 0.000000000000 -vt 0.123056329787 0.196519747376 0.000000000000 -vt 0.128924548626 0.189431414008 0.000000000000 -vt 0.129672512412 0.193513929844 0.000000000000 -vt 0.133775278926 0.185372322798 0.000000000000 -vt 0.134995400906 0.187966778874 0.000000000000 -vt 0.136989831924 0.191276341677 0.000000000000 -vt 0.139916166663 0.181990936399 0.000000000000 -vt 0.141775041819 0.183941915631 0.000000000000 -vt 0.145468041301 0.175736352801 0.000000000000 -vt 0.147888004780 0.177232280374 0.000000000000 -vt 0.149156302214 0.178392961621 0.000000000000 -vt 0.151406511664 0.170416608453 0.000000000000 -vt 0.153140649199 0.171435669065 0.000000000000 -vt 0.026889864355 0.258701503277 0.000000000000 -vt 0.148213580251 0.169269666076 0.000000000000 -vt 0.138399973512 0.180339202285 0.000000000000 -vt 0.143568634987 0.174784168601 0.000000000000 -vt 0.146306514740 0.170045778155 0.000000000000 -vt 0.137052193284 0.178213953972 0.000000000000 -vt 0.141616314650 0.173843026161 0.000000000000 -vt 0.144707694650 0.169350728393 0.000000000000 -vt 0.021730657667 0.250446200371 0.000000000000 -vt 0.024742785841 0.244501665235 0.000000000000 -vt 0.018961701542 0.249092146754 0.000000000000 -vt 0.022073570639 0.243767663836 0.000000000000 -vt 0.023706618696 0.235825523734 0.000000000000 -vt 0.027095658705 0.229019328952 0.000000000000 -vt 0.029609059915 0.222379729152 0.000000000000 -vt 0.030542327091 0.216693878174 0.000000000000 -vt 0.033057313412 0.217472910881 0.000000000000 -vt 0.087314084172 0.175335809588 0.000000000000 -vt 0.094248183072 0.178092375398 0.000000000000 -vt 0.092181935906 0.179499372840 0.000000000000 -vt 0.085963152349 0.177274391055 0.000000000000 -vt 0.081338465214 0.174150139093 0.000000000000 -vt 0.082193829119 0.172002837062 0.000000000000 -vt 0.076521947980 0.167970299721 0.000000000000 -vt 0.077380686998 0.167476311326 0.000000000000 -vt 0.081656381488 0.178617432714 0.000000000000 -vt 0.077681265771 0.174922868609 0.000000000000 -vt 0.087579086423 0.180975034833 0.000000000000 -vt 0.074853092432 0.169260442257 0.000000000000 -vt 0.079015091062 0.179725423455 0.000000000000 -vt 0.076188489795 0.181088745594 0.000000000000 -vt 0.074826754630 0.175708204508 0.000000000000 -vt 0.082938641310 0.183109730482 0.000000000000 -vt 0.078197099268 0.184789612889 0.000000000000 -vt 0.070867173374 0.171145886183 0.000000000000 -vt 0.073829539120 0.169667065144 0.000000000000 -vt 0.031271602958 0.196384206414 0.000000000000 -vt 0.033982921392 0.194425582886 0.000000000000 -vt 0.037058766931 0.199865102768 0.000000000000 -vt 0.034688781947 0.202102705836 0.000000000000 -vt 0.033738177270 0.202948838472 0.000000000000 -vt 0.030448889360 0.197130590677 0.000000000000 -vt 0.028569748625 0.198085710406 0.000000000000 -vt 0.036571081728 0.216693878174 0.000000000000 -vt 0.033219423145 0.214136794209 0.000000000000 -vt 0.035667311400 0.220581635833 0.000000000000 -vt 0.030702864751 0.212936937809 0.000000000000 -vt 0.037512231618 0.221022486687 0.000000000000 -vt 0.039851140231 0.198102816939 0.000000000000 -vt 0.041124176234 0.203433588147 0.000000000000 -vt 0.037788044661 0.191379234195 0.000000000000 -vt 0.041217606515 0.195904180408 0.000000000000 -vt 0.067828707397 0.174960240722 0.000000000000 -vt 0.038927104324 0.189132183790 0.000000000000 -vt 0.041049417108 0.184728831053 0.000000000000 -vt 0.043036188930 0.186458468437 0.000000000000 -vt 0.065335564315 0.175491616130 0.000000000000 -vt 0.064928933978 0.179175376892 0.000000000000 -vt 0.059944216162 0.177007809281 0.000000000000 -vt 0.060216885060 0.175005495548 0.000000000000 -vt 0.055878814310 0.175014957786 0.000000000000 -vt 0.064486503601 0.180831611156 0.000000000000 -vt 0.059665244073 0.178134486079 0.000000000000 -vt 0.055603001267 0.176066651940 0.000000000000 -vt 0.059327062219 0.179134845734 0.000000000000 -vt 0.054891061038 0.176806747913 0.000000000000 -vt 0.052252914757 0.175443425775 0.000000000000 -vt 0.054579224437 0.177642062306 0.000000000000 -vt 0.051933418959 0.176275372505 0.000000000000 -vt 0.054217841476 0.178369775414 0.000000000000 -vt 0.051375713199 0.176691457629 0.000000000000 -vt 0.058970417827 0.180060461164 0.000000000000 -vt 0.058582257479 0.180961072445 0.000000000000 -vt 0.057680051774 0.181828826666 0.000000000000 -vt 0.062502883375 0.183891922235 0.000000000000 -vt 0.061697278172 0.184658572078 0.000000000000 -vt 0.050166402012 0.187552273273 0.000000000000 -vt 0.051037531346 0.187452524900 0.000000000000 -vt 0.054431293160 0.193168088794 0.000000000000 -vt 0.049586858600 0.182190433145 0.000000000000 -vt 0.049161311239 0.182690724730 0.000000000000 -vt 0.048391725868 0.182542562485 0.000000000000 -vt 0.049334455281 0.187815472484 0.000000000000 -vt 0.048377547413 0.188716322184 0.000000000000 -vt 0.047788541764 0.182509928942 0.000000000000 -vt 0.046637099236 0.188832953572 0.000000000000 -vt 0.046065207571 0.182266756892 0.000000000000 -vt 0.047180842608 0.178921401501 0.000000000000 -vt 0.047978799790 0.180811345577 0.000000000000 -vt 0.042535897344 0.180803701282 0.000000000000 -vt 0.063310064375 0.188303396106 0.000000000000 -vt 0.064299397171 0.188258126378 0.000000000000 -vt 0.065667442977 0.187005370855 0.000000000000 -vt 0.067313097417 0.191977471113 0.000000000000 -vt 0.069538079202 0.197437480092 0.000000000000 -vt 0.067683927715 0.207009509206 0.000000000000 -vt 0.063888035715 0.210395619273 0.000000000000 -vt 0.073146872222 0.203862056136 0.000000000000 -vt 0.071523271501 0.214295744896 0.000000000000 -vt 0.073026858270 0.194442689419 0.000000000000 -vt 0.077325977385 0.201174154878 0.000000000000 -vt 0.081237144768 0.196533709764 0.000000000000 -vt 0.076219789684 0.190154388547 0.000000000000 -vt 0.081086061895 0.187698617578 0.000000000000 -vt 0.069806240499 0.189532741904 0.000000000000 -vt 0.071710377932 0.187683090568 0.000000000000 -vt 0.067168101668 0.185359716415 0.000000000000 -vt 0.069611258805 0.183986946940 0.000000000000 -vt 0.063944101334 0.182054877281 0.000000000000 -vt 0.063255354762 0.183039709926 0.000000000000 -vt 0.074488565326 0.222574487329 0.000000000000 -vt 0.069771796465 0.223591953516 0.000000000000 -vt 0.067730538547 0.216421216726 0.000000000000 -vt 0.060474004596 0.213022723794 0.000000000000 -vt 0.053378012031 0.208070665598 0.000000000000 -vt 0.057214211673 0.207134246826 0.000000000000 -vt 0.049100745469 0.211366251111 0.000000000000 -vt 0.064397566020 0.232721552253 0.000000000000 -vt 0.067054398358 0.233078405261 0.000000000000 -vt 0.070033647120 0.233986899257 0.000000000000 -vt 0.075478121638 0.233488187194 0.000000000000 -vt 0.081782467663 0.220023691654 0.000000000000 -vt 0.083951614797 0.230261281133 0.000000000000 -vt 0.084691703320 0.240565523505 0.000000000000 -vt 0.062245752662 0.239568278193 0.000000000000 -vt 0.061321716756 0.238784536719 0.000000000000 -vt 0.063168220222 0.233371362090 0.000000000000 -vt 0.063390895724 0.227339446545 0.000000000000 -vt 0.058965694159 0.225806355476 0.000000000000 -vt 0.050889376551 0.232737079263 0.000000000000 -vt 0.051590736955 0.236221358180 0.000000000000 -vt 0.050666701049 0.236511155963 0.000000000000 -vt 0.049805026501 0.232663914561 0.000000000000 -vt 0.049557130784 0.236889854074 0.000000000000 -vt 0.048572305590 0.232626542449 0.000000000000 -vt 0.052862185985 0.239495113492 0.000000000000 -vt 0.052227925509 0.240581259131 0.000000000000 -vt 0.055151116103 0.242463573813 0.000000000000 -vt 0.058518532664 0.242689415812 0.000000000000 -vt 0.058837804943 0.243750557303 0.000000000000 -vt 0.027835739776 0.198754191399 0.000000000000 -vt 0.102103173733 0.178665846586 0.000000000000 -vt 0.020530804992 0.243255212903 0.000000000000 -vt 0.017403624952 0.246614530683 0.000000000000 -vt 0.142661705613 0.167488694191 0.000000000000 -vt 0.138711810112 0.171222224832 0.000000000000 -vt 0.136936917901 0.169240176678 0.000000000000 -vt 0.140343055129 0.166225120425 0.000000000000 -vt 0.133923217654 0.174637824297 0.000000000000 -vt 0.132665947080 0.181584313512 0.000000000000 -vt 0.128641068935 0.183620840311 0.000000000000 -vt 0.132804647088 0.173296123743 0.000000000000 -vt 0.065053895116 0.163422614336 0.000000000000 -vt 0.063069596887 0.163681775331 0.000000000000 -vt 0.064668200910 0.167430609465 0.000000000000 -vt 0.063209198415 0.168160781264 0.000000000000 -vt 0.063756324351 0.165098443627 0.000000000000 -vt 0.065168723464 0.164823085070 0.000000000000 -vt 0.065913312137 0.169554486871 0.000000000000 -vt 0.062940359116 0.170286476612 0.000000000000 -vt 0.061481129378 0.167505130172 0.000000000000 -vt 0.060151811689 0.170392528176 0.000000000000 -vt 0.060107905418 0.172657802701 0.000000000000 -vt 0.057210605592 0.172009363770 0.000000000000 -vt 0.057532805949 0.170253381133 0.000000000000 -vt 0.063048884273 0.172646328807 0.000000000000 -vt 0.048934575170 0.168896585703 0.000000000000 -vt 0.049731176347 0.167191714048 0.000000000000 -vt 0.042593311518 0.164057999849 0.000000000000 -vt 0.043497528881 0.162384659052 0.000000000000 -vt 0.044287156314 0.160732463002 0.000000000000 -vt 0.033884081990 0.156096965075 0.000000000000 -vt 0.034770067781 0.153932109475 0.000000000000 -vt 0.036515694112 0.150483399630 0.000000000000 -vt 0.046103026718 0.155740767717 0.000000000000 -vt 0.039584781975 0.147428721189 0.000000000000 -vt 0.047613140196 0.151688650250 0.000000000000 -vt 0.043061178178 0.143725812435 0.000000000000 -vt 0.050141181797 0.149046242237 0.000000000000 -vt 0.047894362360 0.140243798494 0.000000000000 -vt 0.053615551442 0.146738171577 0.000000000000 -vt 0.053296964616 0.138070821762 0.000000000000 -vt 0.056939747185 0.144772797823 0.000000000000 -vt 0.060318645090 0.151515960693 0.000000000000 -vt 0.060732934624 0.143554925919 0.000000000000 -vt 0.062500409782 0.150664418936 0.000000000000 -vt 0.064538739622 0.156376838684 0.000000000000 -vt 0.063412509859 0.157254040241 0.000000000000 -vt 0.065951131284 0.161686450243 0.000000000000 -vt 0.064260445535 0.149016290903 0.000000000000 -vt 0.065228387713 0.155802473426 0.000000000000 -vt 0.067762054503 0.156014785171 0.000000000000 -vt 0.067490294576 0.161968335509 0.000000000000 -vt 0.068041928113 0.150318130851 0.000000000000 -vt 0.072004206479 0.152485474944 0.000000000000 -vt 0.068994782865 0.144661113620 0.000000000000 -vt 0.072091117501 0.145224899054 0.000000000000 -vt 0.075190380216 0.145809859037 0.000000000000 -vt 0.074453443289 0.154495447874 0.000000000000 -vt 0.078592248261 0.146916940808 0.000000000000 -vt 0.077539868653 0.155462488532 0.000000000000 -vt 0.083513915539 0.149794429541 0.000000000000 -vt 0.080134786665 0.156474098563 0.000000000000 -vt 0.076403960586 0.162150710821 0.000000000000 -vt 0.082034416497 0.157592907548 0.000000000000 -vt 0.077113650739 0.164572715759 0.000000000000 -vt 0.075192175806 0.166414484382 0.000000000000 -vt 0.073551476002 0.164994657040 0.000000000000 -vt 0.072395749390 0.167818546295 0.000000000000 -vt 0.086013361812 0.151608720422 0.000000000000 -vt 0.082925580442 0.138807758689 0.000000000000 -vt 0.088270992041 0.142190933228 0.000000000000 -vt 0.092381425202 0.144706368446 0.000000000000 -vt 0.033781412989 0.159828022122 0.000000000000 -vt 0.032040510327 0.158961847425 0.000000000000 -vt 0.032221313566 0.155238896608 0.000000000000 -vt 0.033128913492 0.152995914221 0.000000000000 -vt 0.034247931093 0.149646267295 0.000000000000 -vt 0.036089029163 0.146674454212 0.000000000000 -vt 0.039337117225 0.142542183399 0.000000000000 -vt 0.044477183372 0.138003721833 0.000000000000 -vt 0.051182758063 0.134617850184 0.000000000000 -vt 0.057887878269 0.132730364799 0.000000000000 -vt 0.058954205364 0.136307403445 0.000000000000 -vt 0.065197318792 0.135614156723 0.000000000000 -vt 0.065236717463 0.143920347095 0.000000000000 -vt 0.070889234543 0.135065451264 0.000000000000 -vt 0.075503565371 0.136102512479 0.000000000000 -vt 0.079501420259 0.136758163571 0.000000000000 -vt 0.080287218094 0.135892897844 0.000000000000 -vt 0.083798281848 0.137524142861 0.000000000000 -vt 0.089716039598 0.140691623092 0.000000000000 -vt 0.143560752273 0.209685027599 0.000000000000 -vt 0.135448858142 0.212041050196 0.000000000000 -vt 0.136980593204 0.209762930870 0.000000000000 -vt 0.149614498019 0.207925885916 0.000000000000 -vt 0.093936122954 0.143564611673 0.000000000000 -vt 0.131235316396 0.212935358286 0.000000000000 -vt 0.130912885070 0.210914373398 0.000000000000 -vt 0.130802333355 0.214139938354 0.000000000000 -vt 0.126496925950 0.214841082692 0.000000000000 -vt 0.127033010125 0.216304361820 0.000000000000 -vt 0.123436622322 0.220508232713 0.000000000000 -vt 0.122662074864 0.219344407320 0.000000000000 -vt 0.127302527428 0.217270508409 0.000000000000 -vt 0.124103523791 0.221681743860 0.000000000000 -vt 0.121738053858 0.226466968656 0.000000000000 -vt 0.119399368763 0.224682837725 0.000000000000 -vt 0.071574836969 0.132907792926 0.000000000000 -vt 0.076760835946 0.134390205145 0.000000000000 -vt 0.065341189504 0.132802188396 0.000000000000 -vt 0.115896403790 0.229595944285 0.000000000000 -vt 0.113967284560 0.229628607631 0.000000000000 -vt 0.118455067277 0.224354103208 0.000000000000 -vt 0.118444040418 0.231105849147 0.000000000000 -vt 0.116246968508 0.222922116518 0.000000000000 -vt 0.121256656945 0.217508718371 0.000000000000 -vt 0.113348767161 0.220198199153 0.000000000000 -vt 0.118779063225 0.214370504022 0.000000000000 -vt 0.109506264329 0.216642320156 0.000000000000 -vt 0.113111913204 0.210065305233 0.000000000000 -vt 0.106790229678 0.213530674577 0.000000000000 -vt 0.110659286380 0.209100753069 0.000000000000 -vt 0.105615362525 0.211812064052 0.000000000000 -vt 0.108720943332 0.208151713014 0.000000000000 -vt 0.104931339622 0.210859879851 0.000000000000 -vt 0.107262387872 0.207199767232 0.000000000000 -vt 0.104268938303 0.209731861949 0.000000000000 -vt 0.106411516666 0.206867888570 0.000000000000 -vt 0.099854543805 0.210535883904 0.000000000000 -vt 0.101010948420 0.212820082903 0.000000000000 -vt 0.101252302527 0.214150756598 0.000000000000 -vt 0.100541725755 0.216653347015 0.000000000000 -vt 0.109188362956 0.234976246953 0.000000000000 -vt 0.112999781966 0.234926506877 0.000000000000 -vt 0.116525933146 0.235893979669 0.000000000000 -vt 0.113097950816 0.239953324199 0.000000000000 -vt 0.109616830945 0.240531280637 0.000000000000 -vt 0.105305328965 0.241614267230 0.000000000000 -vt 0.103323295712 0.248255476356 0.000000000000 -vt 0.107525810599 0.246296599507 0.000000000000 -vt 0.106832340360 0.251131802797 0.000000000000 -vt 0.103008523583 0.253494113684 0.000000000000 -vt 0.111104875803 0.245297834277 0.000000000000 -vt 0.110048457980 0.249654576182 0.000000000000 -vt 0.096914246678 0.264147579670 0.000000000000 -vt 0.095100626349 0.260864347219 0.000000000000 -vt 0.103348061442 0.257600039244 0.000000000000 -vt 0.106801033020 0.254496067762 0.000000000000 -vt 0.169106185436 0.192728593946 0.000000000000 -vt 0.170338675380 0.195399373770 0.000000000000 -vt 0.099874362350 0.170928612351 0.000000000000 -vt 0.097011074424 0.169942215085 0.000000000000 -vt 0.095663733780 0.165094852448 0.000000000000 -vt 0.099198222160 0.165355354548 0.000000000000 -vt 0.093683719635 0.168949723244 0.000000000000 -vt 0.092458203435 0.165013566613 0.000000000000 -vt 0.090356379747 0.159508973360 0.000000000000 -vt 0.094260796905 0.160128593445 0.000000000000 -vt 0.099197551608 0.159526988864 0.000000000000 -vt 0.033023308963 0.163863465190 0.000000000000 -vt 0.037694837898 0.165538623929 0.000000000000 -vt 0.027775174007 0.166775852442 0.000000000000 -vt 0.088919214904 0.165129065514 0.000000000000 -vt 0.087757416070 0.161358624697 0.000000000000 -vt 0.041305195540 0.168003618717 0.000000000000 -vt 0.039413448423 0.169479295611 0.000000000000 -vt 0.041364412755 0.172144010663 0.000000000000 -vt 0.039971377701 0.172480389476 0.000000000000 -vt 0.038754414767 0.172880932689 0.000000000000 -vt 0.037746172398 0.170685455203 0.000000000000 -vt 0.041679184884 0.177758023143 0.000000000000 -vt 0.040490355343 0.177621126175 0.000000000000 -vt 0.038885232061 0.177430868149 0.000000000000 -vt 0.031558681279 0.181349694729 0.000000000000 -vt 0.032375093549 0.182451382279 0.000000000000 -vt 0.031321812421 0.183208808303 0.000000000000 -vt 0.029306901619 0.181765779853 0.000000000000 -vt 0.030110931024 0.184735804796 0.000000000000 -vt 0.026748467237 0.183448821306 0.000000000000 -vt 0.025492548943 0.179579749703 0.000000000000 -vt 0.025225963444 0.184383660555 0.000000000000 -vt 0.023586835712 0.180322989821 0.000000000000 -vt 0.023586835712 0.175274342299 0.000000000000 -vt 0.025453597307 0.175285145640 0.000000000000 -vt 0.025660742074 0.170873910189 0.000000000000 -vt 0.026788990945 0.172416672111 0.000000000000 -vt 0.028133621439 0.171821355820 0.000000000000 -vt 0.117384001613 0.164725363255 0.000000000000 -vt 0.112397044897 0.164127796888 0.000000000000 -vt 0.111941114068 0.159629434347 0.000000000000 -vt 0.116640761495 0.160034939647 0.000000000000 -vt 0.117678731680 0.167584165931 0.000000000000 -vt 0.121842063963 0.165160596371 0.000000000000 -vt 0.122367806733 0.167285159230 0.000000000000 -vt 0.123244337738 0.169767260551 0.000000000000 -vt 0.118570342660 0.170628488064 0.000000000000 -vt 0.076927222311 0.256597876549 0.000000000000 -vt 0.069735996425 0.256459414959 0.000000000000 -vt 0.126834645867 0.166902616620 0.000000000000 -vt 0.127785488963 0.169480189681 0.000000000000 -vt 0.062401559204 0.256990790367 0.000000000000 -vt 0.061513323337 0.259970039129 0.000000000000 -vt 0.055246125907 0.260234832764 0.000000000000 -vt 0.055534552783 0.256361246109 0.000000000000 -vt 0.055091898888 0.251717656851 0.000000000000 -vt 0.055174525827 0.262654781342 0.000000000000 -vt 0.131237342954 0.166645258665 0.000000000000 -vt 0.126206025481 0.164752155542 0.000000000000 -vt 0.130478784442 0.164564833045 0.000000000000 -vt 0.128323823214 0.157905861735 0.000000000000 -vt 0.124372817576 0.158351898193 0.000000000000 -vt 0.120934464037 0.159285396338 0.000000000000 -vt 0.031951349229 0.187119752169 0.000000000000 -vt 0.032728809863 0.185262441635 0.000000000000 -vt 0.035856213421 0.185055300593 0.000000000000 -vt 0.035672266036 0.187161847949 0.000000000000 -vt 0.028532592580 0.186527818441 0.000000000000 -vt 0.128893464804 0.155811250210 0.000000000000 -vt 0.132322803140 0.155696868896 0.000000000000 -vt 0.132445976138 0.157863765955 0.000000000000 -vt 0.134399861097 0.164290815592 0.000000000000 -vt 0.137302115560 0.158585160971 0.000000000000 -vt 0.138255640864 0.163551405072 0.000000000000 -vt 0.141750499606 0.159247785807 0.000000000000 -vt 0.142176494002 0.162172332406 0.000000000000 -vt 0.167481020093 0.185227319598 0.000000000000 -vt 0.170263931155 0.178922742605 0.000000000000 -vt 0.172615230083 0.181126117706 0.000000000000 -vt 0.170385509729 0.185613691807 0.000000000000 -vt 0.137086644769 0.156343296170 0.000000000000 -vt 0.141829982400 0.156543448567 0.000000000000 -vt 0.084312535822 0.167729392648 0.000000000000 -vt 0.084777034819 0.164774447680 0.000000000000 -vt 0.089359387755 0.168153122067 0.000000000000 -vt 0.136736750603 0.154593154788 0.000000000000 -vt 0.141693994403 0.153399839997 0.000000000000 -vt 0.084533862770 0.161654248834 0.000000000000 -vt 0.132128268480 0.155035361648 0.000000000000 -vt 0.168764844537 0.189312979579 0.000000000000 -vt 0.165124982595 0.185052827001 0.000000000000 -vt 0.167759761214 0.178524002433 0.000000000000 -vt 0.158733054996 0.192014843225 0.000000000000 -vt 0.156409904361 0.199086070061 0.000000000000 -vt 0.155019804835 0.205063492060 0.000000000000 -vt 0.157773226500 0.205484077334 0.000000000000 -vt 0.157165527344 0.207992762327 0.000000000000 -vt 0.154318660498 0.207045525312 0.000000000000 -vt 0.039390247315 0.183007746935 0.000000000000 -vt 0.109839722514 0.252810090780 0.000000000000 -vt 0.161794945598 0.206194669008 0.000000000000 -vt 0.160380065441 0.209382638335 0.000000000000 -vt 0.030997594818 0.172260865569 0.000000000000 -vt 0.028872353956 0.171737149358 0.000000000000 -vt 0.040024068207 0.239364311099 0.000000000000 -vt 0.041931357235 0.237304374576 0.000000000000 -vt 0.044145528227 0.240434691310 0.000000000000 -vt 0.045424859971 0.239937767386 0.000000000000 -vt 0.044002104551 0.236135587096 0.000000000000 -vt 0.100529327989 0.192775428295 0.000000000000 -vt 0.086145527661 0.185369163752 0.000000000000 -vt 0.074024297297 0.186244800687 0.000000000000 -vt 0.062078233808 0.164369389415 0.000000000000 -vt 0.030012762174 0.176220208406 0.000000000000 -vt 0.112108394504 0.179039835930 0.000000000000 -vt 0.112108394504 0.176560640335 0.000000000000 -vt 0.069380022585 0.168249264359 0.000000000000 -vt 0.065014265478 0.171704053879 0.000000000000 -vt 0.048454102129 0.180325239897 0.000000000000 -vt 0.146105453372 0.080951645970 0.000000000000 -vt 0.144684508443 0.079957589507 0.000000000000 -vt 0.149933993816 0.076390907168 0.000000000000 -vt 0.151316225529 0.078695371747 0.000000000000 -vt 0.153613030910 0.080021530390 0.000000000000 -vt 0.145809382200 0.082432046533 0.000000000000 -vt 0.143933385611 0.080989018083 0.000000000000 -vt 0.154818966985 0.082354143262 0.000000000000 -vt 0.145563289523 0.085070192814 0.000000000000 -vt 0.143352255225 0.081543803215 0.000000000000 -vt 0.144436612725 0.082785755396 0.000000000000 -vt 0.143652841449 0.084858089685 0.000000000000 -vt 0.146591797471 0.088287875056 0.000000000000 -vt 0.154597863555 0.085654467344 0.000000000000 -vt 0.153173521161 0.089168235660 0.000000000000 -vt 0.152664005756 0.094450607896 0.000000000000 -vt 0.140441447496 0.090233892202 0.000000000000 -vt 0.138348862529 0.080004423857 0.000000000000 -vt 0.139517411590 0.078812226653 0.000000000000 -vt 0.140799894929 0.078904315829 0.000000000000 -vt 0.140338554978 0.079870223999 0.000000000000 -vt 0.139646649361 0.078048720956 0.000000000000 -vt 0.142411112785 0.080079168081 0.000000000000 -vt 0.142763257027 0.078845098615 0.000000000000 -vt 0.144676625729 0.071552544832 0.000000000000 -vt 0.147951960564 0.073969364166 0.000000000000 -vt 0.165310516953 0.075303182006 0.000000000000 -vt 0.162680253386 0.081052973866 0.000000000000 -vt 0.159637063742 0.079843878746 0.000000000000 -vt 0.160642147064 0.076046422124 0.000000000000 -vt 0.138225704432 0.079229891300 0.000000000000 -vt 0.137284547091 0.079804927111 0.000000000000 -vt 0.137759849429 0.078385323286 0.000000000000 -vt 0.137967005372 0.069246500731 0.000000000000 -vt 0.141144156456 0.069925799966 0.000000000000 -vt 0.135236993432 0.081436410546 0.000000000000 -vt 0.135894671082 0.079535424709 0.000000000000 -vt 0.134577959776 0.080499768257 0.000000000000 -vt 0.135107755661 0.084568321705 0.000000000000 -vt 0.134055823088 0.084435924888 0.000000000000 -vt 0.133896872401 0.080932959914 0.000000000000 -vt 0.133128866553 0.069963172078 0.000000000000 -vt 0.135289907455 0.069450497627 0.000000000000 -vt 0.163844078779 0.085923969746 0.000000000000 -vt 0.162402868271 0.094224542379 0.000000000000 -vt 0.132371440530 0.082354143262 0.000000000000 -vt 0.128753200173 0.071022763848 0.000000000000 -vt 0.105484560132 0.044374290854 0.000000000000 -vt 0.104406282306 0.042068254203 0.000000000000 -vt 0.105255573988 0.042082216591 0.000000000000 -vt 0.106301188469 0.043263372034 0.000000000000 -vt 0.105341121554 0.039797786623 0.000000000000 -vt 0.107362121344 0.040538098663 0.000000000000 -vt 0.102971151471 0.044095326215 0.000000000000 -vt 0.109018579125 0.049298208207 0.000000000000 -vt 0.103879645467 0.048260468990 0.000000000000 -vt 0.106288582087 0.055648040026 0.000000000000 -vt 0.099673971534 0.057078447193 0.000000000000 -vt 0.097955361009 0.055400144309 0.000000000000 -vt 0.110525324941 0.046463962644 0.000000000000 -vt 0.102905854583 0.041538458318 0.000000000000 -vt 0.103917017579 0.039889875799 0.000000000000 -vt 0.118358477950 0.052561160177 0.000000000000 -vt 0.113901987672 0.058519665152 0.000000000000 -vt 0.118132635951 0.047917779535 0.000000000000 -vt 0.118020296097 0.061421241611 0.000000000000 -vt 0.122165165842 0.055722784251 0.000000000000 -vt 0.126941144466 0.044675100595 0.000000000000 -vt 0.128192335367 0.048273082823 0.000000000000 -vt 0.129756718874 0.051271017641 0.000000000000 -vt 0.104457631707 0.038520034403 0.000000000000 -vt 0.106935217977 0.039335094392 0.000000000000 -vt 0.110430315137 0.041719038039 0.000000000000 -vt 0.109509423375 0.038915853947 0.000000000000 -vt 0.103522777557 0.036517728120 0.000000000000 -vt 0.097110807896 0.038964264095 0.000000000000 -vt 0.099772140384 0.040999215096 0.000000000000 -vt 0.097977206111 0.041525851935 0.000000000000 -vt 0.096010699868 0.040015961975 0.000000000000 -vt 0.098011419177 0.043816577643 0.000000000000 -vt 0.095403008163 0.041276607662 0.000000000000 -vt 0.100398525596 0.044103201479 0.000000000000 -vt 0.092719830573 0.059615265578 0.000000000000 -vt 0.090432256460 0.055584091693 0.000000000000 -vt 0.103748843074 0.062081839889 0.000000000000 -vt 0.109088838100 0.036444552243 0.000000000000 -vt 0.116189554334 0.040374409407 0.000000000000 -vt 0.117214694619 0.043208893389 0.000000000000 -vt 0.100217953324 0.036773279309 0.000000000000 -vt 0.101216748357 0.031871203333 0.000000000000 -vt 0.129965662956 0.062457408756 0.000000000000 -vt 0.134202405810 0.063657253981 0.000000000000 -vt 0.126032650471 0.071523055434 0.000000000000 -vt 0.126584276557 0.061618920416 0.000000000000 -vt 0.126425325871 0.056240197271 0.000000000000 -vt 0.131047084928 0.056420769542 0.000000000000 -vt 0.136421307921 0.063021421432 0.000000000000 -vt 0.135489389300 0.060313250870 0.000000000000 -vt 0.137195616961 0.059194456786 0.000000000000 -vt 0.136729776859 0.057686138898 0.000000000000 -vt 0.156631231308 0.049092646688 0.000000000000 -vt 0.157220244408 0.050672557205 0.000000000000 -vt 0.155348747969 0.051238145679 0.000000000000 -vt 0.152967959642 0.049707990140 0.000000000000 -vt 0.072539396584 0.024206470698 0.000000000000 -vt 0.073009975255 0.022490788251 0.000000000000 -vt 0.074167720973 0.023411672562 0.000000000000 -vt 0.075313083827 0.024346742779 0.000000000000 -vt 0.078608684242 0.024770483375 0.000000000000 -vt 0.076113961637 0.022561032325 0.000000000000 -vt 0.074407733977 0.021668069065 0.000000000000 -vt 0.085832558572 0.034895710647 0.000000000000 -vt 0.088694959879 0.030288133770 0.000000000000 -vt 0.092079266906 0.032754708081 0.000000000000 -vt 0.090345121920 0.035805787891 0.000000000000 -vt 0.080766797066 0.037424653769 0.000000000000 -vt 0.083163343370 0.031321149319 0.000000000000 -vt 0.082765944302 0.039579611272 0.000000000000 -vt 0.075439170003 0.026426948607 0.000000000000 -vt 0.079141400754 0.028394807130 0.000000000000 -vt 0.065825045109 0.019637845457 0.000000000000 -vt 0.070792645216 0.020507168025 0.000000000000 -vt 0.069720685482 0.023076642305 0.000000000000 -vt 0.066453002393 0.021015118808 0.000000000000 -vt 0.074630416930 0.020555578172 0.000000000000 -vt 0.078393660486 0.021780196577 0.000000000000 -vt 0.118059247732 0.097139850259 0.000000000000 -vt 0.114740446210 0.098579719663 0.000000000000 -vt 0.114250972867 0.095418095589 0.000000000000 -vt 0.117238104343 0.094657748938 0.000000000000 -vt 0.109638676047 0.091790616512 0.000000000000 -vt 0.115868493915 0.090512856841 0.000000000000 -vt 0.106643870473 0.097877010703 0.000000000000 -vt 0.080275960267 0.020345281810 0.000000000000 -vt 0.084542199969 0.020472947508 0.000000000000 -vt 0.082198783755 0.026802506298 0.000000000000 -vt 0.087908044457 0.024324897677 0.000000000000 -vt 0.082033514977 0.045575719327 0.000000000000 -vt 0.083040185273 0.050441998988 0.000000000000 -vt 0.079672768712 0.048204403371 0.000000000000 -vt 0.080490976572 0.044366639107 0.000000000000 -vt 0.076486371458 0.049105029553 0.000000000000 -vt 0.078130230308 0.043149676174 0.000000000000 -vt 0.081851139665 0.052377205342 0.000000000000 -vt 0.066788040102 0.023179534823 0.000000000000 -vt 0.064600206912 0.023336920887 0.000000000000 -vt 0.064584665000 0.022389467806 0.000000000000 -vt 0.066289320588 0.022115226835 0.000000000000 -vt 0.060966644436 0.023584589362 0.000000000000 -vt 0.061784636229 0.022029668093 0.000000000000 -vt 0.063617177308 0.021110359579 0.000000000000 -vt 0.091050982475 0.028800085187 0.000000000000 -vt 0.094201579690 0.030098102987 0.000000000000 -vt 0.090151712298 0.025628998876 0.000000000000 -vt 0.093743383884 0.027991328388 0.000000000000 -vt 0.066948570311 0.027383632958 0.000000000000 -vt 0.060868475586 0.030944012105 0.000000000000 -vt 0.062462348491 0.027807373554 0.000000000000 -vt 0.066029265523 0.025897156447 0.000000000000 -vt 0.059814978391 0.026431452483 0.000000000000 -vt 0.064851254225 0.024653624743 0.000000000000 -vt 0.054694723338 0.030345775187 0.000000000000 -vt 0.047921154648 0.032958924770 0.000000000000 -vt 0.043463084847 0.030261565000 0.000000000000 -vt 0.047107893974 0.029183298349 0.000000000000 -vt 0.050095032901 0.030151013285 0.000000000000 -vt 0.047431897372 0.026514083147 0.000000000000 -vt 0.050590369850 0.027707632631 0.000000000000 -vt 0.042810361832 0.027617346495 0.000000000000 -vt 0.047869820148 0.042448315769 0.000000000000 -vt 0.045954655856 0.041697423905 0.000000000000 -vt 0.046084117144 0.036520879716 0.000000000000 -vt 0.049386020750 0.038101017475 0.000000000000 -vt 0.044854771346 0.041064735502 0.000000000000 -vt 0.043885473162 0.036986950785 0.000000000000 -vt 0.051757570356 0.034210111946 0.000000000000 -vt 0.154328122735 0.043087299913 0.000000000000 -vt 0.154911056161 0.037254884839 0.000000000000 -vt 0.167563647032 0.034898862243 0.000000000000 -vt 0.161921262741 0.041362386197 0.000000000000 -vt 0.153502255678 0.030707374215 0.000000000000 -vt 0.163250565529 0.027692098171 0.000000000000 -vt 0.103868618608 0.102910131216 0.000000000000 -vt 0.111994698644 0.103447571397 0.000000000000 -vt 0.106992870569 0.109234735370 0.000000000000 -vt 0.101400464773 0.108030393720 0.000000000000 -vt 0.096481271088 0.122771069407 0.000000000000 -vt 0.089952446520 0.124826297164 0.000000000000 -vt 0.088087268174 0.119303897023 0.000000000000 -vt 0.094165779650 0.117781624198 0.000000000000 -vt 0.070482604206 0.058522816747 0.000000000000 -vt 0.077887058258 0.065487995744 0.000000000000 -vt 0.071217961609 0.071155369282 0.000000000000 -vt 0.066381409764 0.064373925328 0.000000000000 -vt 0.070337608457 0.087279632688 0.000000000000 -vt 0.063515856862 0.072370767593 0.000000000000 -vt 0.079217955470 0.082213863730 0.000000000000 -vt 0.050732221454 0.021630693227 0.000000000000 -vt 0.048374619335 0.020630329847 0.000000000000 -vt 0.048564653844 0.016099080443 0.000000000000 -vt 0.051573622972 0.018779102713 0.000000000000 -vt 0.045837800950 0.018292993307 0.000000000000 -vt 0.046268071979 0.015899594873 0.000000000000 -vt 0.051961567253 0.016921799630 0.000000000000 -vt 0.048754904419 0.013884905726 0.000000000000 -vt 0.026494264603 0.028064500540 0.000000000000 -vt 0.026460040361 0.028243724257 0.000000000000 -vt 0.026340033859 0.028218735009 0.000000000000 -vt 0.026315040886 0.028072383255 0.000000000000 -vt 0.026271361858 0.028111334890 0.000000000000 -vt 0.026316616684 0.028287407011 0.000000000000 -vt 0.026220027357 0.028083190322 0.000000000000 -vt 0.025830507278 0.027961608022 0.000000000000 -vt 0.026793498546 0.027743656188 0.000000000000 -vt 0.022305700928 0.037761259824 0.000000000000 -vt 0.020612087101 0.038116555661 0.000000000000 -vt 0.018779549748 0.032605204731 0.000000000000 -vt 0.019568044692 0.032413598150 0.000000000000 -vt 0.026293199509 0.029374904931 0.000000000000 -vt 0.026729550213 0.056939747185 0.000000000000 -vt 0.025282029063 0.059646341950 0.000000000000 -vt 0.023371588439 0.056319449097 0.000000000000 -vt 0.024051103741 0.054049205035 0.000000000000 -vt 0.023613180965 0.061910506338 0.000000000000 -vt 0.020778700709 0.056646820158 0.000000000000 -vt 0.024753816426 0.028824850917 0.000000000000 -vt 0.024046380073 0.029639910907 0.000000000000 -vt 0.021925639361 0.027996055782 0.000000000000 -vt 0.019233010709 0.029932837933 0.000000000000 -vt 0.020827110857 0.032996300608 0.000000000000 -vt 0.018511611968 0.030085492879 0.000000000000 -vt 0.018042616546 0.028514813632 0.000000000000 -vt 0.018695343286 0.028449516743 0.000000000000 -vt 0.018340270966 0.027692098171 0.000000000000 -vt 0.019049059600 0.027235481888 0.000000000000 -vt 0.018784277141 0.027503643185 0.000000000000 -vt 0.018855873495 0.026894371957 0.000000000000 -vt 0.019962288439 0.026958312839 0.000000000000 -vt 0.019748840481 0.027567584068 0.000000000000 -vt 0.160484761000 0.020033445209 0.000000000000 -vt 0.147482961416 0.021641500294 0.000000000000 -vt 0.154410749674 0.015146899968 0.000000000000 -vt 0.161012977362 0.008924962953 0.000000000000 -vt 0.166393518448 0.013308282942 0.000000000000 -vt 0.166352987289 0.025851901621 0.000000000000 -vt 0.166651993990 0.020915377885 0.000000000000 -vt 0.170089438558 0.015492964536 0.000000000000 -vt 0.019588306546 0.027807373554 0.000000000000 -vt 0.019134845585 0.027851056308 0.000000000000 -vt 0.019064817578 0.028270293027 0.000000000000 -vt 0.038729425520 0.090958446264 0.000000000000 -vt 0.036177065223 0.089736983180 0.000000000000 -vt 0.038676287979 0.085981622338 0.000000000000 -vt 0.040239315480 0.089066922665 0.000000000000 -vt 0.042406659573 0.093741580844 0.000000000000 -vt 0.040854658931 0.094687461853 0.000000000000 -vt 0.037749316543 0.094786986709 0.000000000000 -vt 0.027898332104 0.053784426302 0.000000000000 -vt 0.031369995326 0.055613588542 0.000000000000 -vt 0.030157541856 0.062759563327 0.000000000000 -vt 0.033898938447 0.060758832842 0.000000000000 -vt 0.032940682024 0.067951634526 0.000000000000 -vt 0.027729919180 0.065882235765 0.000000000000 -vt 0.093380436301 0.131579592824 0.000000000000 -vt 0.101789981127 0.126331463456 0.000000000000 -vt 0.037756975740 0.051755558699 0.000000000000 -vt 0.035693880171 0.048643913120 0.000000000000 -vt 0.039868485183 0.048481795937 0.000000000000 -vt 0.041482623667 0.049996417016 0.000000000000 -vt 0.042654555291 0.045740988106 0.000000000000 -vt 0.045040067285 0.046664800495 0.000000000000 -vt 0.036985594779 0.046448197216 0.000000000000 -vt 0.034682709724 0.086651682854 0.000000000000 -vt 0.030933646485 0.089648038149 0.000000000000 -vt 0.029764866456 0.085144937038 0.000000000000 -vt 0.031592678279 0.081364586949 0.000000000000 -vt 0.034569006413 0.082026988268 0.000000000000 -vt 0.032102201134 0.080329999328 0.000000000000 -vt 0.028744241223 0.051196273416 0.000000000000 -vt 0.030639147386 0.050709929317 0.000000000000 -vt 0.036769222468 0.056941326708 0.000000000000 -vt 0.034461375326 0.053469661623 0.000000000000 -vt 0.041688408703 0.088625833392 0.000000000000 -vt 0.044041287154 0.087036460638 0.000000000000 -vt 0.042447183281 0.080775573850 0.000000000000 -vt 0.049191255122 0.076541990042 0.000000000000 -vt 0.046822618693 0.081983312964 0.000000000000 -vt 0.044226806611 0.072259977460 0.000000000000 -vt 0.046158861369 0.086456924677 0.000000000000 -vt 0.027991769835 0.075538471341 0.000000000000 -vt 0.027059858665 0.080196022987 0.000000000000 -vt 0.025024902076 0.073586151004 0.000000000000 -vt 0.026086058468 0.070214003325 0.000000000000 -vt 0.026441354305 0.067705318332 0.000000000000 -vt 0.028167841956 0.071457535028 0.000000000000 -vt 0.028880013153 0.073195055127 0.000000000000 -vt 0.030567547306 0.076351955533 0.000000000000 -vt 0.030551789328 0.069745004177 0.000000000000 -vt 0.029026357457 0.069470763206 0.000000000000 -vt 0.030614150688 0.072523415089 0.000000000000 -vt 0.043936815113 0.092527776957 0.000000000000 -vt 0.046364661306 0.097238019109 0.000000000000 -vt 0.044538419694 0.100720718503 0.000000000000 -vt 0.042931716889 0.101345524192 0.000000000000 -vt 0.048817273229 0.100172251463 0.000000000000 -vt 0.048457246274 0.102738559246 0.000000000000 -vt 0.137558788061 0.098332047462 0.000000000000 -vt 0.139102905989 0.097345650196 0.000000000000 -vt 0.138733655214 0.098258882761 0.000000000000 -vt 0.137797236443 0.098970815539 0.000000000000 -vt 0.138197556138 0.099481925368 0.000000000000 -vt 0.139004737139 0.098487854004 0.000000000000 -vt 0.139805614948 0.097956493497 0.000000000000 -vt 0.139377146959 0.099524021149 0.000000000000 -vt 0.050679307431 0.107523784041 0.000000000000 -vt 0.054135438055 0.112569287419 0.000000000000 -vt 0.050330314785 0.114288136363 0.000000000000 -vt 0.047148425132 0.107650101185 0.000000000000 -vt 0.050964351743 0.104889020324 0.000000000000 -vt 0.053239319474 0.103625223041 0.000000000000 -vt 0.055646907538 0.107062682509 0.000000000000 -vt 0.058104019612 0.112983807921 0.000000000000 -vt 0.140801474452 0.096658468246 0.000000000000 -vt 0.138233363628 0.096205011010 0.000000000000 -vt 0.140344858170 0.095949456096 0.000000000000 -vt 0.142007410526 0.098663926125 0.000000000000 -vt 0.140017718077 0.100223585963 0.000000000000 -vt 0.141385748982 0.098199442029 0.000000000000 -vt 0.141155198216 0.097431436181 0.000000000000 -vt 0.133312597871 0.105359598994 0.000000000000 -vt 0.132514864206 0.104310825467 0.000000000000 -vt 0.134183719754 0.106383368373 0.000000000000 -vt 0.140815436840 0.100723877549 0.000000000000 -vt 0.141863986850 0.099782720208 0.000000000000 -vt 0.142421916127 0.100219070911 0.000000000000 -vt 0.142892494798 0.098935022950 0.000000000000 -vt 0.050447177142 0.103112548590 0.000000000000 -vt 0.052483703941 0.102864876390 0.000000000000 -vt 0.144728183746 0.104067876935 0.000000000000 -vt 0.144224733114 0.102514311671 0.000000000000 -vt 0.145186141133 0.101699247956 0.000000000000 -vt 0.146470203996 0.103851273656 0.000000000000 -vt 0.143584400415 0.101527899504 0.000000000000 -vt 0.144430533051 0.100561767817 0.000000000000 -vt 0.141550794244 0.101287886500 0.000000000000 -vt 0.061257999390 0.112659797072 0.000000000000 -vt 0.065134719014 0.115944370627 0.000000000000 -vt 0.061873342842 0.123118489981 0.000000000000 -vt 0.056573864073 0.121722295880 0.000000000000 -vt 0.067445486784 0.110573291779 0.000000000000 -vt 0.063640370965 0.107372716069 0.000000000000 -vt 0.069648854434 0.106004670262 0.000000000000 -vt 0.066685140133 0.100748866796 0.000000000000 -vt 0.072863399982 0.099591121078 0.000000000000 -vt 0.079629309475 0.095017760992 0.000000000000 -vt 0.063420616090 0.097499877214 0.000000000000 -vt 0.064508341253 0.086475610733 0.000000000000 -vt 0.143850758672 0.104326352477 0.000000000000 -vt 0.143411472440 0.103562861681 0.000000000000 -vt 0.056262250990 0.094160601497 0.000000000000 -vt 0.056469622999 0.096354737878 0.000000000000 -vt 0.051992859691 0.094852507114 0.000000000000 -vt 0.052877943963 0.092719376087 0.000000000000 -vt 0.057681854814 0.098607867956 0.000000000000 -vt 0.053764607757 0.098246261477 0.000000000000 -vt 0.051455195993 0.098188623786 0.000000000000 -vt 0.049526061863 0.095104902983 0.000000000000 -vt 0.050771173090 0.101749226451 0.000000000000 -vt 0.052848231047 0.102208778262 0.000000000000 -vt 0.051238592714 0.100907593966 0.000000000000 -vt 0.052483703941 0.100563332438 0.000000000000 -vt 0.057426307350 0.106243103743 0.000000000000 -vt 0.059230696410 0.102589055896 0.000000000000 -vt 0.054297324270 0.103461548686 0.000000000000 -vt 0.054697874933 0.101320534945 0.000000000000 -vt 0.052963506430 0.122161805630 0.000000000000 -vt 0.052379231900 0.131099566817 0.000000000000 -vt 0.048094075173 0.130477920175 0.000000000000 -vt 0.046760257334 0.130856394768 0.000000000000 -vt 0.050066884607 0.122128933668 0.000000000000 -vt 0.156333580613 0.006823139265 0.000000000000 -vt 0.149899765849 0.012613456696 0.000000000000 -vt 0.148388311267 0.011923130602 0.000000000000 -vt 0.154814451933 0.007212657481 0.000000000000 -vt 0.143572017550 0.018695119768 0.000000000000 -vt 0.142008990049 0.017630811781 0.000000000000 -vt 0.141720786691 0.017121285200 0.000000000000 -vt 0.147525057197 0.011396490037 0.000000000000 -vt 0.137385874987 0.025342378765 0.000000000000 -vt 0.135559633374 0.023885395378 0.000000000000 -vt 0.134478226304 0.023776423186 0.000000000000 -vt 0.129616662860 0.030687112361 0.000000000000 -vt 0.127787277102 0.029326722026 0.000000000000 -vt 0.122677840292 0.035132572055 0.000000000000 -vt 0.121847249568 0.031333755702 0.000000000000 -vt 0.121459312737 0.026788320392 0.000000000000 -vt 0.126799300313 0.025711629540 0.000000000000 -vt 0.116022720933 0.031031373888 0.000000000000 -vt 0.116498008370 0.026107456535 0.000000000000 -vt 0.109646543860 0.029707010835 0.000000000000 -vt 0.110188722610 0.025318961591 0.000000000000 -vt 0.102204486728 0.027808953077 0.000000000000 -vt 0.102347925305 0.024181474000 0.000000000000 -vt 0.120979495347 0.024089615792 0.000000000000 -vt 0.116271957755 0.023522447795 0.000000000000 -vt 0.110184207559 0.022347588092 0.000000000000 -vt 0.102416366339 0.022239964455 0.000000000000 -vt 0.133086755872 0.021283280104 0.000000000000 -vt 0.125700771809 0.022800825536 0.000000000000 -vt 0.131805852056 0.019698411226 0.000000000000 -vt 0.140229582787 0.014688935131 0.000000000000 -vt 0.145475924015 0.010294806212 0.000000000000 -vt 0.152886912227 0.006676563993 0.000000000000 -vt 0.047576893121 0.122769504786 0.000000000000 -vt 0.044946629554 0.130904808640 0.000000000000 -vt 0.047352414578 0.114989265800 0.000000000000 -vt 0.044636588544 0.108223572373 0.000000000000 -vt 0.040943596512 0.101545020938 0.000000000000 -vt 0.041778694838 0.117057085037 0.000000000000 -vt 0.038933407515 0.109159991145 0.000000000000 -vt 0.042194779962 0.125491634011 0.000000000000 -vt 0.042258728296 0.131637245417 0.000000000000 -vt 0.150459289551 0.005439335480 0.000000000000 -vt 0.147406622767 0.004468692467 0.000000000000 -vt 0.143596783280 0.008389092982 0.000000000000 -vt 0.139240026474 0.012483991683 0.000000000000 -vt 0.039006810635 0.131603017449 0.000000000000 -vt 0.039525572211 0.125474527478 0.000000000000 -vt 0.038843121380 0.117890611291 0.000000000000 -vt 0.036237854511 0.109794244170 0.000000000000 -vt 0.035265412182 0.101655572653 0.000000000000 -vt 0.032339062542 0.095125168562 0.000000000000 -vt 0.030368058011 0.090082809329 0.000000000000 -vt 0.031399492174 0.094974085689 0.000000000000 -vt 0.033498387784 0.101733475924 0.000000000000 -vt 0.028639992699 0.086095318198 0.000000000000 -vt 0.025852348655 0.081437990069 0.000000000000 -vt 0.022753085941 0.076138511300 0.000000000000 -vt 0.023653708398 0.075184747577 0.000000000000 -vt 0.020847376436 0.069434955716 0.000000000000 -vt 0.021620105952 0.067643180490 0.000000000000 -vt 0.023307643831 0.064264953136 0.000000000000 -vt 0.017721544951 0.061841826886 0.000000000000 -vt 0.020375225693 0.059083905071 0.000000000000 -vt 0.053222205490 0.012929573655 0.000000000000 -vt 0.050235074013 0.010815139860 0.000000000000 -vt 0.056510146707 0.014634449035 0.000000000000 -vt 0.054663654417 0.018612489104 0.000000000000 -vt 0.060259204358 0.016382552683 0.000000000000 -vt 0.059049900621 0.020086579025 0.000000000000 -vt 0.058030847460 0.021122742444 0.000000000000 -vt 0.054247569293 0.019831027836 0.000000000000 -vt 0.056996259838 0.023039262742 0.000000000000 -vt 0.053340639919 0.022660780698 0.000000000000 -vt 0.055484797806 0.025647688657 0.000000000000 -vt 0.052176591009 0.025117896497 0.000000000000 -vt 0.049496565014 0.024186205119 0.000000000000 -vt 0.045745935291 0.023629847914 0.000000000000 -vt 0.047365020961 0.022347588092 0.000000000000 -vt 0.044394996017 0.020589802414 0.000000000000 -vt 0.045242708176 0.019883941859 0.000000000000 -vt 0.024909622967 0.052349288017 0.000000000000 -vt 0.025043588132 0.050973366946 0.000000000000 -vt 0.027739373967 0.047426950186 0.000000000000 -vt 0.024479579180 0.048439692706 0.000000000000 -vt 0.042350593954 0.024865496904 0.000000000000 -vt 0.042051356286 0.021227214485 0.000000000000 -vt 0.036529209465 0.022210467607 0.000000000000 -vt 0.037055846304 0.026330355555 0.000000000000 -vt 0.036963980645 0.028058420867 0.000000000000 -vt 0.031510043889 0.025784809142 0.000000000000 -vt 0.031432140619 0.027294699103 0.000000000000 -vt 0.036716084927 0.029509097338 0.000000000000 -vt 0.031419757754 0.028624013066 0.000000000000 -vt 0.027148788795 0.027899462730 0.000000000000 -vt 0.027295140550 0.028648782521 0.000000000000 -vt 0.036427881569 0.031031373888 0.000000000000 -vt 0.031274754554 0.029678862542 0.000000000000 -vt 0.027111416683 0.029242511839 0.000000000000 -vt 0.030949188396 0.030895829201 0.000000000000 -vt 0.035843607038 0.032156471163 0.000000000000 -vt 0.020707104355 0.028784547001 0.000000000000 -vt 0.022812303156 0.031886737794 0.000000000000 -vt 0.020281784236 0.029052484781 0.000000000000 -vt 0.023458946496 0.031434852630 0.000000000000 -vt 0.022109370679 0.032270174474 0.000000000000 -vt 0.020171005279 0.029769152403 0.000000000000 -vt 0.021504826844 0.032532032579 0.000000000000 -vt 0.025012519211 0.036299776286 0.000000000000 -vt 0.024063490331 0.036756169051 0.000000000000 -vt 0.023340519518 0.037314102054 0.000000000000 -vt 0.027483826503 0.041390310973 0.000000000000 -vt 0.026430319995 0.041890602559 0.000000000000 -vt 0.025338094682 0.042350146919 0.000000000000 -vt 0.029316132888 0.046764533967 0.000000000000 -vt 0.022701527923 0.043102841824 0.000000000000 -vt 0.030600195751 0.046093124896 0.000000000000 -vt 0.032929647714 0.049832727760 0.000000000000 -vt 0.031767170876 0.045388620347 0.000000000000 -vt 0.029398767278 0.040288627148 0.000000000000 -vt 0.032870430499 0.044547211379 0.000000000000 -vt 0.028457617387 0.040873128921 0.000000000000 -vt 0.030336765572 0.039641980082 0.000000000000 -vt 0.033799197525 0.043578144163 0.000000000000 -vt 0.037752252072 0.045114379376 0.000000000000 -vt 0.041783425957 0.044548790902 0.000000000000 -vt 0.025857076049 0.035843163729 0.000000000000 -vt 0.026734281331 0.035361554474 0.000000000000 -vt 0.041914243251 0.032859180123 0.000000000000 -vt 0.040793869644 0.033786371350 0.000000000000 -vt 0.030941305682 0.023799840361 0.000000000000 -vt 0.057466831058 0.013119827956 0.000000000000 -vt 0.054774206132 0.010378789157 0.000000000000 -vt 0.051085937768 0.008826795965 0.000000000000 -vt 0.051754426211 0.007754832506 0.000000000000 -vt 0.088373884559 0.020429264754 0.000000000000 -vt 0.088517308235 0.019399408251 0.000000000000 -vt 0.090854644775 0.019729707390 0.000000000000 -vt 0.090842038393 0.020712960511 0.000000000000 -vt 0.094946391881 0.022414457053 0.000000000000 -vt 0.095091395080 0.020460564643 0.000000000000 -vt 0.094299748540 0.025574509054 0.000000000000 -vt 0.090377770364 0.023751430213 0.000000000000 -vt 0.109390988946 0.033906377852 0.000000000000 -vt 0.101716801524 0.030102606863 0.000000000000 -vt 0.116005614400 0.037482291460 0.000000000000 -vt 0.123491324484 0.037183284760 0.000000000000 -vt 0.125074386597 0.041345056146 0.000000000000 -vt 0.130738392472 0.031681168824 0.000000000000 -vt 0.133287593722 0.035913188010 0.000000000000 -vt 0.135103031993 0.039498783648 0.000000000000 -vt 0.140455409884 0.028768789023 0.000000000000 -vt 0.144802927971 0.035279151052 0.000000000000 -vt 0.146699190140 0.040768656880 0.000000000000 -vt 0.137726977468 0.044129770249 0.000000000000 -vt 0.147504791617 0.045349668711 0.000000000000 -vt 0.138828665018 0.047825690359 0.000000000000 -vt 0.146984457970 0.048285465688 0.000000000000 -vt 0.138644710183 0.050088282675 0.000000000000 -vt 0.129806697369 0.052833821625 0.000000000000 -vt 0.169347777963 0.087803125381 0.000000000000 -vt 0.166878044605 0.096072614193 0.000000000000 -vt 0.123137615621 0.057648766786 0.000000000000 -vt 0.120253384113 0.063675940037 0.000000000000 -vt 0.115961924195 0.067340791225 0.000000000000 -vt 0.118732467294 0.069205984473 0.000000000000 -vt 0.118006333709 0.075494781137 0.000000000000 -vt 0.115131542087 0.074644148350 0.000000000000 -vt 0.109959736466 0.072775810957 0.000000000000 -vt 0.111552253366 0.064712107182 0.000000000000 -vt 0.102553710341 0.070056840777 0.000000000000 -vt 0.109609171748 0.082248091698 0.000000000000 -vt 0.100861445069 0.081328779459 0.000000000000 -vt 0.090299867094 0.080892428756 0.000000000000 -vt 0.091694474220 0.066030398011 0.000000000000 -vt 0.079119786620 0.055774118751 0.000000000000 -vt 0.072969444096 0.053520996124 0.000000000000 -vt 0.071013972163 0.047288250178 0.000000000000 -vt 0.068132661283 0.051054421812 0.000000000000 -vt 0.065332636237 0.054049205035 0.000000000000 -vt 0.061893608421 0.046331342310 0.000000000000 -vt 0.058749314398 0.049416642636 0.000000000000 -vt 0.061658326536 0.058715995401 0.000000000000 -vt 0.055071856827 0.053793657571 0.000000000000 -vt 0.052937161177 0.044756155461 0.000000000000 -vt 0.049072828144 0.049751672894 0.000000000000 -vt 0.058147702366 0.064059153199 0.000000000000 -vt 0.052524227649 0.058092769235 0.000000000000 -vt 0.045923579484 0.053873132914 0.000000000000 -vt 0.046409692615 0.047785166651 0.000000000000 -vt 0.043375950307 0.051665265113 0.000000000000 -vt 0.050428483635 0.061640765518 0.000000000000 -vt 0.043210681528 0.056986581534 0.000000000000 -vt 0.040099035949 0.054348435253 0.000000000000 -vt 0.039909008890 0.059638466686 0.000000000000 -vt 0.047191876918 0.065960139036 0.000000000000 -vt 0.038101460785 0.065509825945 0.000000000000 -vt 0.035400953144 0.074902862310 0.000000000000 -vt 0.055581387132 0.067733466625 0.000000000000 -vt 0.052806120366 0.071872040629 0.000000000000 -vt 0.060378994793 0.075755074620 0.000000000000 -vt 0.058071371168 0.078776419163 0.000000000000 -vt 0.055618759245 0.080065205693 0.000000000000 -vt 0.052734520286 0.079525962472 0.000000000000 -vt 0.053052444011 0.081367731094 0.000000000000 -vt 0.050789859146 0.083292141557 0.000000000000 -vt 0.049432624131 0.082779452205 0.000000000000 -vt 0.049594733864 0.085844501853 0.000000000000 -vt 0.048008512706 0.086075052619 0.000000000000 -vt 0.050535883754 0.089364573359 0.000000000000 -vt 0.049192603678 0.090299412608 0.000000000000 -vt 0.047464769334 0.090754449368 0.000000000000 -vt 0.045393791050 0.091461896896 0.000000000000 -vt 0.047896388918 0.095926046371 0.000000000000 -vt 0.049828443676 0.098826035857 0.000000000000 -vt 0.057419996709 0.081000059843 0.000000000000 -vt 0.060966644436 0.087109863758 0.000000000000 -vt 0.059794712812 0.087519645691 0.000000000000 -vt 0.060287129134 0.094168484211 0.000000000000 -vt 0.059352282435 0.093295782804 0.000000000000 -vt 0.062393907458 0.086673513055 0.000000000000 -vt 0.061801750213 0.096052348614 0.000000000000 -vt 0.049892392009 0.042724128813 0.000000000000 -vt 0.052075494081 0.038878478110 0.000000000000 -vt 0.055960100144 0.041236083955 0.000000000000 -vt 0.055889848620 0.035288382322 0.000000000000 -vt 0.060157891363 0.037993393838 0.000000000000 -vt 0.065116032958 0.042724128813 0.000000000000 -vt 0.064106442034 0.032941814512 0.000000000000 -vt 0.068679787219 0.036249794066 0.000000000000 -vt 0.074156686664 0.040447585285 0.000000000000 -vt 0.073277905583 0.031112428755 0.000000000000 -vt 0.077270135283 0.034540414810 0.000000000000 -vt 0.072071976960 0.025901664048 0.000000000000 -vt 0.069379344583 0.029083553702 0.000000000000 -vt 0.069463558495 0.025113392621 0.000000000000 -vt 0.067841313779 0.024271763861 0.000000000000 -vt 0.099162861705 0.091220304370 0.000000000000 -vt 0.089000269771 0.092127218843 0.000000000000 -vt 0.097078159451 0.097934648395 0.000000000000 -vt 0.087571434677 0.099022373557 0.000000000000 -vt 0.079772509634 0.101554468274 0.000000000000 -vt 0.086257882416 0.102638825774 0.000000000000 -vt 0.079043231905 0.105086937547 0.000000000000 -vt 0.075504690409 0.108024075627 0.000000000000 -vt 0.074613302946 0.105156958103 0.000000000000 -vt 0.073125250638 0.110627785325 0.000000000000 -vt 0.071593523026 0.108968392015 0.000000000000 -vt 0.070599466562 0.114607393742 0.000000000000 -vt 0.069200120866 0.112909048796 0.000000000000 -vt 0.067964471877 0.119090452790 0.000000000000 -vt 0.066672757268 0.117705300450 0.000000000000 -vt 0.065623983741 0.124006733298 0.000000000000 -vt 0.064179614186 0.123651430011 0.000000000000 -vt 0.064288586378 0.130211338401 0.000000000000 -vt 0.062253635377 0.130234748125 0.000000000000 -vt 0.058482732624 0.130786374211 0.000000000000 -vt 0.122141756117 0.148486047983 0.000000000000 -vt 0.127875998616 0.147998362780 0.000000000000 -vt 0.127665698528 0.150818660855 0.000000000000 -vt 0.122073300183 0.151981130242 0.000000000000 -vt 0.133205190301 0.149006605148 0.000000000000 -vt 0.133069649339 0.151248708367 0.000000000000 -vt 0.172021716833 0.016547817737 0.000000000000 -vt 0.169503584504 0.022040475160 0.000000000000 -vt 0.137767508626 0.149533241987 0.000000000000 -vt 0.137985691428 0.152411177754 0.000000000000 -vt 0.168945640326 0.028130020946 0.000000000000 -vt 0.129772469401 0.142226740718 0.000000000000 -vt 0.133960813284 0.145277813077 0.000000000000 -vt 0.137136399746 0.143440544605 0.000000000000 -vt 0.135624930263 0.133524268866 0.000000000000 -vt 0.137717753649 0.134089857340 0.000000000000 -vt 0.109607592225 0.111450493336 0.000000000000 -vt 0.100973561406 0.115215316415 0.000000000000 -vt 0.100111901760 0.112997993827 0.000000000000 -vt 0.109063848853 0.109449759126 0.000000000000 -vt 0.094076842070 0.114406555891 0.000000000000 -vt 0.109662085772 0.113127216697 0.000000000000 -vt 0.101924166083 0.117096036673 0.000000000000 -vt 0.118073418736 0.107520863414 0.000000000000 -vt 0.118896141648 0.109094470739 0.000000000000 -vt 0.119979143143 0.110803857446 0.000000000000 -vt 0.109627857804 0.115891456604 0.000000000000 -vt 0.121512211859 0.112745359540 0.000000000000 -vt 0.113743022084 0.119411528111 0.000000000000 -vt 0.123366601765 0.114860013127 0.000000000000 -vt 0.116215899587 0.122188150883 0.000000000000 -vt 0.104867622256 0.130242630839 0.000000000000 -vt 0.095320373774 0.140049934387 0.000000000000 -vt 0.118313208222 0.124379143119 0.000000000000 -vt 0.107863992453 0.133408755064 0.000000000000 -vt 0.099661588669 0.143760040402 0.000000000000 -vt 0.087192721665 0.108221992850 0.000000000000 -vt 0.082525931299 0.110838308930 0.000000000000 -vt 0.110880628228 0.135783463717 0.000000000000 -vt 0.103619366884 0.146102100611 0.000000000000 -vt 0.078900031745 0.113002493978 0.000000000000 -vt 0.114026710391 0.137971296906 0.000000000000 -vt 0.107220500708 0.147809907794 0.000000000000 -vt 0.075743131340 0.114870831370 0.000000000000 -vt 0.117038622499 0.139775693417 0.000000000000 -vt 0.110938265920 0.149550363421 0.000000000000 -vt 0.072325952351 0.116807609797 0.000000000000 -vt 0.121297188103 0.140570491552 0.000000000000 -vt 0.116660133004 0.148486047983 0.000000000000 -vt 0.070322073996 0.122125789523 0.000000000000 -vt 0.125169411302 0.141371369362 0.000000000000 -vt 0.067821048200 0.126478031278 0.000000000000 -vt 0.126182377338 0.130125775933 0.000000000000 -vt 0.128910809755 0.131200894713 0.000000000000 -vt 0.132871732116 0.132607877254 0.000000000000 -vt 0.133273646235 0.122961118817 0.000000000000 -vt 0.135723099113 0.124199911952 0.000000000000 -vt 0.137808039784 0.124982103705 0.000000000000 -vt 0.138423606753 0.117220535874 0.000000000000 -vt 0.140033245087 0.117920324206 0.000000000000 -vt 0.141472890973 0.118429854512 0.000000000000 -vt 0.139520570636 0.125482171774 0.000000000000 -vt 0.124876491725 0.103963419795 0.000000000000 -vt 0.117411032319 0.105984404683 0.000000000000 -vt 0.124236144125 0.102663815022 0.000000000000 -vt 0.129794090986 0.099442973733 0.000000000000 -vt 0.130341216922 0.100725457072 0.000000000000 -vt 0.131000250578 0.101975068450 0.000000000000 -vt 0.125632330775 0.105312764645 0.000000000000 -vt 0.131731107831 0.103181213140 0.000000000000 -vt 0.126520335674 0.106766596437 0.000000000000 -vt 0.127601757646 0.108326464891 0.000000000000 -vt 0.128798455000 0.109823748469 0.000000000000 -vt 0.130024880171 0.111135736108 0.000000000000 -vt 0.125136762857 0.116662845016 0.000000000000 -vt 0.131293177605 0.112291902304 0.000000000000 -vt 0.126648217440 0.118099555373 0.000000000000 -vt 0.120172336698 0.126228556037 0.000000000000 -vt 0.128081783652 0.119333624840 0.000000000000 -vt 0.122010938823 0.127758711576 0.000000000000 -vt 0.129577711225 0.120530337095 0.000000000000 -vt 0.123975865543 0.129045933485 0.000000000000 -vt 0.131254225969 0.121706768870 0.000000000000 -vt 0.133884489536 0.114366039634 0.000000000000 -vt 0.135243296623 0.115338250995 0.000000000000 -vt 0.136775031686 0.116316780448 0.000000000000 -vt 0.138644710183 0.110085606575 0.000000000000 -vt 0.139880597591 0.110813304782 0.000000000000 -vt 0.141141012311 0.111453637481 0.000000000000 -vt 0.142396926880 0.111997395754 0.000000000000 -vt 0.143704399467 0.112458750606 0.000000000000 -vt 0.137226909399 0.097607508302 0.000000000000 -vt 0.142870649695 0.102392718196 0.000000000000 -vt 0.137440353632 0.109256580472 0.000000000000 -vt 0.142222434282 0.101855054498 0.000000000000 -vt 0.143068566918 0.100842311978 0.000000000000 -vt 0.143592044711 0.099678248167 0.000000000000 -vt 0.136274725199 0.108363851905 0.000000000000 -vt 0.135182499886 0.107386663556 0.000000000000 -vt 0.132592767477 0.113364085555 0.000000000000 -vt 0.095187984407 0.102827504277 0.000000000000 -vt 0.094770319760 0.109039977193 0.000000000000 -vt 0.115190759301 0.083002358675 0.000000000000 -vt 0.117822378874 0.083010017872 0.000000000000 -vt 0.118609294295 0.089811727405 0.000000000000 -vt 0.145974636078 0.053520996124 0.000000000000 -vt 0.146114915609 0.056235466152 0.000000000000 -vt 0.139495581388 0.056631293148 0.000000000000 -vt 0.139889821410 0.054191056639 0.000000000000 -vt 0.119352757931 0.094131112099 0.000000000000 -vt 0.136199980974 0.055359613150 0.000000000000 -vt 0.119957312942 0.096627399325 0.000000000000 -vt 0.133549451828 0.056533124298 0.000000000000 -vt 0.144910335541 0.057005267590 0.000000000000 -vt 0.139738738537 0.057558249682 0.000000000000 -vt 0.145398020744 0.061774957925 0.000000000000 -vt 0.139342918992 0.061978947371 0.000000000000 -vt 0.149662911892 0.063947036862 0.000000000000 -vt 0.153687775135 0.067230239511 0.000000000000 -vt 0.155149489641 0.059760045260 0.000000000000 -vt 0.158387213945 0.062926396728 0.000000000000 -vt 0.157279461622 0.070296630263 0.000000000000 -vt 0.163594841957 0.066641241312 0.000000000000 -vt 0.153912261128 0.057711135596 0.000000000000 -vt 0.159546762705 0.060358505696 0.000000000000 -vt 0.164818108082 0.064783707261 0.000000000000 -vt 0.165087610483 0.069813668728 0.000000000000 -vt 0.167392298579 0.069913417101 0.000000000000 -vt 0.162909239531 0.058806512505 0.000000000000 -vt 0.168085560203 0.065015837550 0.000000000000 -vt 0.170962139964 0.071387514472 0.000000000000 -vt 0.171663269401 0.079518079758 0.000000000000 -vt 0.168453454971 0.075633481145 0.000000000000 -vt 0.154616549611 0.054712962359 0.000000000000 -vt 0.160480037332 0.072431325912 0.000000000000 -vt 0.165078386664 0.102370887995 0.000000000000 -vt 0.160031303763 0.101119697094 0.000000000000 -vt 0.153291955590 0.047032695264 0.000000000000 -vt 0.081070527434 0.018897537142 0.000000000000 -vt 0.085028529167 0.019402559847 0.000000000000 -vt 0.066250368953 0.017697680742 0.000000000000 -vt 0.060628462583 0.015371378511 0.000000000000 -vt 0.066359564662 0.016670975834 0.000000000000 -vt 0.071543760598 0.016661521047 0.000000000000 -vt 0.071405068040 0.017848987132 0.000000000000 -vt 0.075989224017 0.018615640700 0.000000000000 -vt 0.076596923172 0.017573174089 0.000000000000 -vt 0.017198059708 0.064038887620 0.000000000000 -vt 0.020149167627 0.070380836725 0.000000000000 -vt 0.016810115427 0.065315067768 0.000000000000 -vt 0.158577471972 0.046223942190 0.000000000000 -vt 0.102452382445 0.038576319814 0.000000000000 -vt 0.089843250811 0.037739418447 0.000000000000 -vt 0.086650550365 0.040033075958 0.000000000000 -vt 0.086444757879 0.038370531052 0.000000000000 -vt 0.089615844190 0.039254039526 0.000000000000 -vt 0.094363689423 0.042627539486 0.000000000000 -vt 0.089279234409 0.040964987129 0.000000000000 -vt 0.096154123545 0.044999096543 0.000000000000 -vt 0.099321827292 0.047730680555 0.000000000000 -vt 0.097085818648 0.047713566571 0.000000000000 -vt 0.095434077084 0.052601691335 0.000000000000 -vt 0.094276331365 0.051693182439 0.000000000000 -vt 0.089904040098 0.052642215043 0.000000000000 -vt 0.089681141078 0.050836246461 0.000000000000 -vt 0.084422186017 0.049848269671 0.000000000000 -vt 0.086022593081 0.049033429474 0.000000000000 -vt 0.082889109850 0.045797046274 0.000000000000 -vt 0.084425337613 0.045902874321 0.000000000000 -vt 0.084310062230 0.042319070548 0.000000000000 -vt 0.085408590734 0.043013904244 0.000000000000 -vt 0.083744473755 0.041396614164 0.000000000000 -vt 0.087161652744 0.041465062648 0.000000000000 -vt 0.089801147580 0.053888674825 0.000000000000 -vt 0.096400216222 0.053726788610 0.000000000000 -vt 0.101375699043 0.047830428928 0.000000000000 -vt 0.150993570685 0.099017649889 0.000000000000 -vt 0.131135791540 0.085984766483 0.000000000000 -vt 0.137482464314 0.092382773757 0.000000000000 -vt 0.135268285871 0.088904798031 0.000000000000 -vt 0.139503464103 0.089568555355 0.000000000000 -vt 0.136636331677 0.087804690003 0.000000000000 -vt 0.139095246792 0.088097617030 0.000000000000 -vt 0.141262590885 0.086944609880 0.000000000000 -vt 0.143028035760 0.087709680200 0.000000000000 -vt 0.052647162229 0.028242152184 0.000000000000 -vt 0.091367103159 0.114521846175 0.000000000000 -vt 0.024943847209 0.029597807676 0.000000000000 -vt 0.082706280053 0.355134129524 0.000000000000 -vt 0.085947386920 0.363250732422 0.000000000000 -vt 0.082174688578 0.364220470190 0.000000000000 -vt 0.079061470926 0.357818633318 0.000000000000 -vt 0.076576210558 0.349433183670 0.000000000000 -vt 0.074389949441 0.353636831045 0.000000000000 -vt 0.070025764406 0.352275311947 0.000000000000 -vt 0.069683760405 0.347608089447 0.000000000000 -vt 0.084169343114 0.377381920815 0.000000000000 -vt 0.080777153373 0.375979661942 0.000000000000 -vt 0.082553848624 0.370932579041 0.000000000000 -vt 0.086099147797 0.371338099241 0.000000000000 -vt 0.079547807574 0.364964604378 0.000000000000 -vt 0.080153018236 0.370642364025 0.000000000000 -vt 0.076729759574 0.359675943851 0.000000000000 -vt 0.073228374124 0.356270015240 0.000000000000 -vt 0.070341885090 0.355011194944 0.000000000000 -vt 0.078728012741 0.374791979790 0.000000000000 -vt 0.078406266868 0.379009783268 0.000000000000 -vt 0.081292532384 0.382708638906 0.000000000000 -vt 0.077228710055 0.376913607121 0.000000000000 -vt 0.076079964638 0.380043476820 0.000000000000 -vt 0.075517080724 0.383981227875 0.000000000000 -vt 0.075921684504 0.377626001835 0.000000000000 -vt 0.067173950374 0.353658229113 0.000000000000 -vt 0.068672135472 0.355914741755 0.000000000000 -vt 0.064776502550 0.349804252386 0.000000000000 -vt 0.072278216481 0.378946751356 0.000000000000 -vt 0.069932326674 0.382139891386 0.000000000000 -vt 0.073346585035 0.376760721207 0.000000000000 -vt 0.065008409321 0.358051896095 0.000000000000 -vt 0.067364208400 0.359130382538 0.000000000000 -vt 0.061515796930 0.356177270412 0.000000000000 -vt 0.067828252912 0.375058323145 0.000000000000 -vt 0.064983420074 0.377222746611 0.000000000000 -vt 0.069865681231 0.373641878366 0.000000000000 -vt 0.063662886620 0.364159464836 0.000000000000 -vt 0.066595532000 0.364011079073 0.000000000000 -vt 0.059879150242 0.364149570465 0.000000000000 -vt 0.064561255276 0.369833588600 0.000000000000 -vt 0.067180253565 0.369111299515 0.000000000000 -vt 0.061178293079 0.370929658413 0.000000000000 -vt 0.087921552360 0.351186037064 0.000000000000 -vt 0.091303609312 0.361563861370 0.000000000000 -vt 0.079885534942 0.343255817890 0.000000000000 -vt 0.069204851985 0.340724855661 0.000000000000 -vt 0.060809489340 0.344233006239 0.000000000000 -vt 0.055593322963 0.353128671646 0.000000000000 -vt 0.053862329572 0.363875776529 0.000000000000 -vt 0.055507313460 0.372740805149 0.000000000000 -vt 0.060099344701 0.380897492170 0.000000000000 -vt 0.066655874252 0.386289954185 0.000000000000 -vt 0.073765367270 0.388392239809 0.000000000000 -vt 0.081145055592 0.388035595417 0.000000000000 -vt 0.088785246015 0.377678692341 0.000000000000 -vt 0.087788932025 0.382556229830 0.000000000000 -vt 0.090708971024 0.371422529221 0.000000000000 -vt 0.098516449332 0.359101116657 0.000000000000 -vt 0.095570974052 0.371151894331 0.000000000000 -vt 0.081494718790 0.391452759504 0.000000000000 -vt 0.072904601693 0.391978055239 0.000000000000 -vt 0.087930560112 0.387041747570 0.000000000000 -vt 0.089069843292 0.390307635069 0.000000000000 -vt 0.093086160719 0.377379685640 0.000000000000 -vt 0.092234395444 0.382332623005 0.000000000000 -vt 0.096012048423 0.378206431866 0.000000000000 -vt 0.095273993909 0.382441610098 0.000000000000 -vt 0.098627001047 0.372742831707 0.000000000000 -vt 0.100691899657 0.375768691301 0.000000000000 -vt 0.097777709365 0.379422277212 0.000000000000 -vt 0.096909299493 0.382944613695 0.000000000000 -vt 0.064227119088 0.390731811523 0.000000000000 -vt 0.047463636845 0.374592483044 0.000000000000 -vt 0.045266803354 0.362910062075 0.000000000000 -vt 0.053129222244 0.386380702257 0.000000000000 -vt 0.055269774050 0.337182939053 0.000000000000 -vt 0.068264156580 0.332182705402 0.000000000000 -vt 0.047308508307 0.348847329617 0.000000000000 -vt 0.083508059382 0.335973203182 0.000000000000 -vt 0.092679306865 0.386310219765 0.000000000000 -vt 0.094604156911 0.389197170734 0.000000000000 -vt 0.096809998155 0.386411547661 0.000000000000 -vt 0.095029927790 0.385251104832 0.000000000000 -vt 0.098225995898 0.388757675886 0.000000000000 -vt 0.097066685557 0.389816790819 0.000000000000 -vt 0.098929613829 0.391160309315 0.000000000000 -vt 0.097326502204 0.391429573298 0.000000000000 -vt 0.094737671316 0.391862779856 0.000000000000 -vt 0.089453734457 0.392666131258 0.000000000000 -vt 0.081771887839 0.393726825714 0.000000000000 -vt 0.072946928442 0.394806444645 0.000000000000 -vt 0.063999712467 0.395681649446 0.000000000000 -vt 0.053615327924 0.396396279335 0.000000000000 -vt 0.041419353336 0.396926730871 0.000000000000 -vt 0.039976555854 0.386726528406 0.000000000000 -vt 0.037052463740 0.374329954386 0.000000000000 -vt 0.035149227828 0.359872728586 0.000000000000 -vt 0.038212914020 0.342804163694 0.000000000000 -vt 0.049577396363 0.328440159559 0.000000000000 -vt 0.067996665835 0.322506874800 0.000000000000 -vt 0.093688450754 0.346306473017 0.000000000000 -vt 0.088374562562 0.327701002359 0.000000000000 -vt 0.100369259715 0.339963853359 0.000000000000 -vt 0.105655893683 0.350941717625 0.000000000000 -vt 0.103044107556 0.365339487791 0.000000000000 -vt 0.108533605933 0.357757389545 0.000000000000 -vt 0.105408892035 0.369979262352 0.000000000000 -vt 0.098068401217 0.383108973503 0.000000000000 -vt 0.098497763276 0.385625302792 0.000000000000 -vt 0.101734369993 0.380148172379 0.000000000000 -vt 0.098705813289 0.380785822868 0.000000000000 -vt 0.099697157741 0.387924820185 0.000000000000 -vt 0.100644618273 0.390900254250 0.000000000000 -vt 0.105129703879 0.377691507339 0.000000000000 -vt 0.105785802007 0.382571756840 0.000000000000 -vt 0.103088900447 0.383172452450 0.000000000000 -vt 0.106459483504 0.386435866356 0.000000000000 -vt 0.104129120708 0.386695683002 0.000000000000 -vt 0.104879111052 0.390249550343 0.000000000000 -vt 0.102643325925 0.390611141920 0.000000000000 -vt 0.101812496781 0.387293249369 0.000000000000 -vt 0.099612280726 0.383124738932 0.000000000000 -vt 0.100343361497 0.384889960289 0.000000000000 -vt 0.101334720850 0.382499039173 0.000000000000 -vt 0.099765837193 0.381787300110 0.000000000000 -vt 0.101950511336 0.385482788086 0.000000000000 -vt 0.102647826076 0.385179489851 0.000000000000 -vt 0.102046653628 0.383690536022 0.000000000000 -vt 0.101413294673 0.384207725525 0.000000000000 -vt 0.101018831134 0.383238196373 0.000000000000 -vt 0.111804887652 0.347057133913 0.000000000000 -vt 0.113323777914 0.353700101376 0.000000000000 -vt 0.116853311658 0.353322982788 0.000000000000 -vt 0.117552861571 0.346509546041 0.000000000000 -vt 0.123864643276 0.349401652813 0.000000000000 -vt 0.120530322194 0.355773121119 0.000000000000 -vt 0.129755362868 0.355360180140 0.000000000000 -vt 0.124298743904 0.360911160707 0.000000000000 -vt 0.134041413665 0.362597793341 0.000000000000 -vt 0.127354532480 0.367429167032 0.000000000000 -vt 0.129645943642 0.373671829700 0.000000000000 -vt 0.136888504028 0.369591563940 0.000000000000 -vt 0.138823032379 0.375629991293 0.000000000000 -vt 0.131178572774 0.379008889198 0.000000000000 -vt 0.110230609775 0.361257672310 0.000000000000 -vt 0.113775447011 0.356992095709 0.000000000000 -vt 0.115981966257 0.356578052044 0.000000000000 -vt 0.118140742183 0.358845561743 0.000000000000 -vt 0.120337590575 0.363843351603 0.000000000000 -vt 0.122301377356 0.370323300362 0.000000000000 -vt 0.123794607818 0.376463502645 0.000000000000 -vt 0.125330835581 0.385786980391 0.000000000000 -vt 0.124756477773 0.381512612104 0.000000000000 -vt 0.132145613432 0.383721172810 0.000000000000 -vt 0.117319837213 0.365754455328 0.000000000000 -vt 0.116345807910 0.360568702221 0.000000000000 -vt 0.118315473199 0.372491776943 0.000000000000 -vt 0.119095861912 0.378632873297 0.000000000000 -vt 0.115259900689 0.358279764652 0.000000000000 -vt 0.113950163126 0.358692705631 0.000000000000 -vt 0.111850589514 0.362477779388 0.000000000000 -vt 0.109477445483 0.369221389294 0.000000000000 -vt 0.108606114984 0.376295775175 0.000000000000 -vt 0.108548924327 0.381853967905 0.000000000000 -vt 0.108668252826 0.385990947485 0.000000000000 -vt 0.109056636691 0.389389663935 0.000000000000 -vt 0.106977775693 0.389831870794 0.000000000000 -vt 0.115236923099 0.380258053541 0.000000000000 -vt 0.119639605284 0.383368134499 0.000000000000 -vt 0.115580737591 0.384713888168 0.000000000000 -vt 0.114937916398 0.374172329903 0.000000000000 -vt 0.114662095904 0.367107868195 0.000000000000 -vt 0.114699468017 0.361614972353 0.000000000000 -vt 0.114764764905 0.359385490417 0.000000000000 -vt 0.114121511579 0.359670996666 0.000000000000 -vt 0.113303065300 0.362503677607 0.000000000000 -vt 0.112174823880 0.368418276310 0.000000000000 -vt 0.111594587564 0.375343382359 0.000000000000 -vt 0.111402764916 0.381200790405 0.000000000000 -vt 0.111436754465 0.385559558868 0.000000000000 -vt 0.111605182290 0.388848632574 0.000000000000 -vt 0.140208870173 0.380911469460 0.000000000000 -vt 0.120046690106 0.387208133936 0.000000000000 -vt 0.116041406989 0.388132423162 0.000000000000 -vt 0.108075186610 0.335427641869 0.000000000000 -vt 0.097032681108 0.317022114992 0.000000000000 -vt 0.068101368845 0.311556011438 0.000000000000 -vt 0.117994397879 0.334477722645 0.000000000000 -vt 0.128177925944 0.338179260492 0.000000000000 -vt 0.136790558696 0.345966488123 0.000000000000 -vt 0.142394453287 0.355307698250 0.000000000000 -vt 0.145550668240 0.364030212164 0.000000000000 -vt 0.147579327226 0.371295541525 0.000000000000 -vt 0.149121865630 0.377288043499 0.000000000000 -vt 0.117433980107 0.316912233829 0.000000000000 -vt 0.132998272777 0.322530061007 0.000000000000 -vt 0.144912809134 0.333580464125 0.000000000000 -vt 0.151742890477 0.346387058496 0.000000000000 -vt 0.155101761222 0.357449173927 0.000000000000 -vt 0.157138064504 0.366050541401 0.000000000000 -vt 0.158694103360 0.372791916132 0.000000000000 -vt 0.093021988869 0.298639088869 0.000000000000 -vt 0.116434976459 0.299687176943 0.000000000000 -vt 0.137037336826 0.306387364864 0.000000000000 -vt 0.152599602938 0.319078207016 0.000000000000 -vt 0.161577224731 0.334434717894 0.000000000000 -vt 0.165657475591 0.348677575588 0.000000000000 -vt 0.167427644134 0.359111487865 0.000000000000 -vt 0.169053271413 0.366990566254 0.000000000000 -vt 0.066684693098 0.299283713102 0.000000000000 -vt 0.044727105647 0.318464457989 0.000000000000 -vt 0.029994530603 0.333837360144 0.000000000000 -vt 0.023920066655 0.352325320244 0.000000000000 -vt 0.023143958300 0.369406253099 0.000000000000 -vt 0.024057183415 0.384051918983 0.000000000000 -vt 0.024341106415 0.396830379963 0.000000000000 -vt 0.177712291479 0.335085839033 0.000000000000 -vt 0.181121811271 0.347459256649 0.000000000000 -vt 0.170949757099 0.319616109133 0.000000000000 -vt 0.158325985074 0.304390668869 0.000000000000 -vt 0.139046162367 0.292386740446 0.000000000000 -vt 0.114894911647 0.285406500101 0.000000000000 -vt 0.089810602367 0.284732818604 0.000000000000 -vt 0.064246259630 0.287257254124 0.000000000000 -vt 0.060561817139 0.275299966335 0.000000000000 -vt 0.085912264884 0.272128403187 0.000000000000 -vt 0.112814709544 0.271828740835 0.000000000000 -vt 0.139997899532 0.280653685331 0.000000000000 -vt 0.162012219429 0.289723157883 0.000000000000 -vt 0.177664101124 0.300114750862 0.000000000000 -vt 0.190142661333 0.313898980618 0.000000000000 -vt 0.198672652245 0.327432364225 0.000000000000 -vt 0.205239757895 0.340885162354 0.000000000000 -vt 0.183992534876 0.357445776463 0.000000000000 -vt 0.069244705141 0.368339478970 0.000000000000 -vt 0.071158297360 0.372511804104 0.000000000000 -vt 0.073666974902 0.375427126884 0.000000000000 -vt 0.075608938932 0.376399338245 0.000000000000 -vt 0.076639704406 0.375857174397 0.000000000000 -vt 0.077665731311 0.373797893524 0.000000000000 -vt 0.078264869750 0.370282560587 0.000000000000 -vt 0.077448233962 0.365520745516 0.000000000000 -vt 0.075266703963 0.360965639353 0.000000000000 -vt 0.072741590440 0.357893168926 0.000000000000 -vt 0.070687949657 0.356488436460 0.000000000000 -vt 0.069615535438 0.357108056545 0.000000000000 -vt 0.068887837231 0.359731346369 0.000000000000 -vt 0.068630032241 0.363813161850 0.000000000000 -vt 0.070949353278 0.367750674486 0.000000000000 -vt 0.072260208428 0.371762514114 0.000000000000 -vt 0.074021823704 0.374623537064 0.000000000000 -vt 0.075438044965 0.375722974539 0.000000000000 -vt 0.076083339751 0.375304430723 0.000000000000 -vt 0.076256714761 0.373671144247 0.000000000000 -vt 0.077135719359 0.370294928551 0.000000000000 -vt 0.076337769628 0.365889549255 0.000000000000 -vt 0.074512436986 0.361760437489 0.000000000000 -vt 0.072514630854 0.358907490969 0.000000000000 -vt 0.070951603353 0.357409089804 0.000000000000 -vt 0.070442758501 0.357752889395 0.000000000000 -vt 0.070120111108 0.359841883183 0.000000000000 -vt 0.070317119360 0.363489836454 0.000000000000 -vt 0.095527067780 0.433499604464 0.000000000000 -vt 0.089006572962 0.431389659643 0.000000000000 -vt 0.089679561555 0.423253923655 0.000000000000 -vt 0.095813460648 0.423289269209 0.000000000000 -vt 0.090270593762 0.442476540804 0.000000000000 -vt 0.085782580078 0.438130587339 0.000000000000 -vt 0.082391515374 0.447095155716 0.000000000000 -vt 0.081284202635 0.441373258829 0.000000000000 -vt 0.088421173394 0.409246772528 0.000000000000 -vt 0.092461802065 0.414794385433 0.000000000000 -vt 0.088074430823 0.416153192520 0.000000000000 -vt 0.085401162505 0.411531209946 0.000000000000 -vt 0.085601098835 0.423056453466 0.000000000000 -vt 0.085188619792 0.417149722576 0.000000000000 -vt 0.084852233529 0.429683655500 0.000000000000 -vt 0.083113588393 0.435138046741 0.000000000000 -vt 0.080847173929 0.437920957804 0.000000000000 -vt 0.083637073636 0.413283139467 0.000000000000 -vt 0.082392193377 0.409229904413 0.000000000000 -vt 0.084188699722 0.404711484909 0.000000000000 -vt 0.081871181726 0.411629140377 0.000000000000 -vt 0.079863473773 0.408857047558 0.000000000000 -vt 0.078159049153 0.404978066683 0.000000000000 -vt 0.080601528287 0.411386430264 0.000000000000 -vt 0.077497541904 0.440609782934 0.000000000000 -vt 0.078839689493 0.437481015921 0.000000000000 -vt 0.075624249876 0.445949316025 0.000000000000 -vt 0.076512485743 0.410979568958 0.000000000000 -vt 0.072959765792 0.408222317696 0.000000000000 -vt 0.078687265515 0.412980526686 0.000000000000 -vt 0.074185512960 0.435919106007 0.000000000000 -vt 0.076881967485 0.434023529291 0.000000000000 -vt 0.070257902145 0.439116775990 0.000000000000 -vt 0.073384404182 0.416101634502 0.000000000000 -vt 0.069238848984 0.414494931698 0.000000000000 -vt 0.076494477689 0.417049527168 0.000000000000 -vt 0.072321221232 0.429132491350 0.000000000000 -vt 0.075570665300 0.428600221872 0.000000000000 -vt 0.067612551153 0.430139392614 0.000000000000 -vt 0.072135694325 0.422728389502 0.000000000000 -vt 0.075469121337 0.422917068005 0.000000000000 -vt 0.067447289824 0.422248363495 0.000000000000 -vt 0.102335080504 0.423187494278 0.000000000000 -vt 0.103228494525 0.435963690281 0.000000000000 -vt 0.096575386822 0.448499649763 0.000000000000 -vt 0.084121152759 0.455617934465 0.000000000000 -vt 0.072271011770 0.453928828239 0.000000000000 -vt 0.063513830304 0.444215625525 0.000000000000 -vt 0.059691589326 0.431783914566 0.000000000000 -vt 0.059796515852 0.421276837587 0.000000000000 -vt 0.062896229327 0.411542922258 0.000000000000 -vt 0.068578697741 0.404683113098 0.000000000000 -vt 0.075288772583 0.400957018137 0.000000000000 -vt 0.082664631307 0.399442404509 0.000000000000 -vt 0.090280279517 0.402916997671 0.000000000000 -vt 0.092445820570 0.407546848059 0.000000000000 -vt 0.097145929933 0.413269847631 0.000000000000 -vt 0.101524755359 0.411767631769 0.000000000000 -vt 0.108704730868 0.422636747360 0.000000000000 -vt 0.073573760688 0.397591859102 0.000000000000 -vt 0.082102417946 0.395999342203 0.000000000000 -vt 0.089554600418 0.398501247168 0.000000000000 -vt 0.089799568057 0.395039051771 0.000000000000 -vt 0.096459656954 0.406454414129 0.000000000000 -vt 0.094413220882 0.401787608862 0.000000000000 -vt 0.097341135144 0.400798738003 0.000000000000 -vt 0.099026650190 0.404693007469 0.000000000000 -vt 0.103435859084 0.409006088972 0.000000000000 -vt 0.100435674191 0.402943789959 0.000000000000 -vt 0.104281768203 0.405376374722 0.000000000000 -vt 0.098907768726 0.399778544903 0.000000000000 -vt 0.065163768828 0.400598347187 0.000000000000 -vt 0.049860190600 0.420209825039 0.000000000000 -vt 0.048853974789 0.434106171131 0.000000000000 -vt 0.054477673024 0.406693518162 0.000000000000 -vt 0.086032271385 0.466448366642 0.000000000000 -vt 0.067181386054 0.464296758175 0.000000000000 -vt 0.053818415850 0.451216369867 0.000000000000 -vt 0.103748381138 0.455393463373 0.000000000000 -vt 0.094275876880 0.397762984037 0.000000000000 -vt 0.095426648855 0.394399613142 0.000000000000 -vt 0.096762046218 0.398063540459 0.000000000000 -vt 0.098227351904 0.396364301443 0.000000000000 -vt 0.097545132041 0.393038094044 0.000000000000 -vt 0.098932549357 0.393664687872 0.000000000000 -vt 0.040455233306 0.407481104136 0.000000000000 -vt 0.037843432277 0.421338081360 0.000000000000 -vt 0.036472912878 0.438838243484 0.000000000000 -vt 0.042982604355 0.460524737835 0.000000000000 -vt 0.062214907259 0.477089822292 0.000000000000 -vt 0.089566305280 0.478372305632 0.000000000000 -vt 0.111008062959 0.438808530569 0.000000000000 -vt 0.113180801272 0.462344437838 0.000000000000 -vt 0.120472237468 0.442430824041 0.000000000000 -vt 0.117490500212 0.428076952696 0.000000000000 -vt 0.109111800790 0.414127260447 0.000000000000 -vt 0.115140110254 0.419330358505 0.000000000000 -vt 0.109508290887 0.408478111029 0.000000000000 -vt 0.099965557456 0.396614462137 0.000000000000 -vt 0.100016877055 0.399250566959 0.000000000000 -vt 0.101089760661 0.401380300522 0.000000000000 -vt 0.104426547885 0.401133537292 0.000000000000 -vt 0.100525066257 0.394041150808 0.000000000000 -vt 0.108131244779 0.401879489422 0.000000000000 -vt 0.105194106698 0.397765219212 0.000000000000 -vt 0.107807472348 0.397282481194 0.000000000000 -vt 0.105133533478 0.393932640553 0.000000000000 -vt 0.107335999608 0.393302202225 0.000000000000 -vt 0.102719649673 0.394079893827 0.000000000000 -vt 0.101905718446 0.396900862455 0.000000000000 -vt 0.101522728801 0.398900896311 0.000000000000 -vt 0.101974606514 0.400191038847 0.000000000000 -vt 0.103468522429 0.399126052856 0.000000000000 -vt 0.104171678424 0.395909041166 0.000000000000 -vt 0.103377550840 0.395803213120 0.000000000000 -vt 0.103972420096 0.397658735514 0.000000000000 -vt 0.103157803416 0.397318959236 0.000000000000 -vt 0.102937594056 0.398482114077 0.000000000000 -vt 0.120900921524 0.421827554703 0.000000000000 -vt 0.125391185284 0.429458737373 0.000000000000 -vt 0.124984331429 0.420799940825 0.000000000000 -vt 0.132154166698 0.427056103945 0.000000000000 -vt 0.128460273147 0.416311025620 0.000000000000 -vt 0.138081595302 0.420313149691 0.000000000000 -vt 0.142197445035 0.410675615072 0.000000000000 -vt 0.131676614285 0.408927738667 0.000000000000 -vt 0.133587732911 0.401068240404 0.000000000000 -vt 0.143351808190 0.401146143675 0.000000000000 -vt 0.133652120829 0.394226670265 0.000000000000 -vt 0.142618030310 0.392982929945 0.000000000000 -vt 0.132911369205 0.388540625572 0.000000000000 -vt 0.141394317150 0.386369884014 0.000000000000 -vt 0.114809587598 0.414815992117 0.000000000000 -vt 0.119088873267 0.418000578880 0.000000000000 -vt 0.121582247317 0.417691677809 0.000000000000 -vt 0.123152919114 0.414221823215 0.000000000000 -vt 0.124552257359 0.408110886812 0.000000000000 -vt 0.125927954912 0.401200413704 0.000000000000 -vt 0.126286625862 0.395116031170 0.000000000000 -vt 0.125815823674 0.390080004930 0.000000000000 -vt 0.120327234268 0.413139492273 0.000000000000 -vt 0.120299309492 0.407533794641 0.000000000000 -vt 0.120726875961 0.401063978672 0.000000000000 -vt 0.120826847851 0.395488440990 0.000000000000 -vt 0.119930967689 0.416081815958 0.000000000000 -vt 0.118429407477 0.416086316109 0.000000000000 -vt 0.115609556437 0.412894517183 0.000000000000 -vt 0.112695828080 0.407353222370 0.000000000000 -vt 0.111295580864 0.401569455862 0.000000000000 -vt 0.110395416617 0.396767795086 0.000000000000 -vt 0.109471604228 0.392846018076 0.000000000000 -vt 0.116785764694 0.395642906427 0.000000000000 -vt 0.116270169616 0.391529113054 0.000000000000 -vt 0.120401531458 0.391011029482 0.000000000000 -vt 0.117080941796 0.400902092457 0.000000000000 -vt 0.117325022817 0.407227128744 0.000000000000 -vt 0.118285760283 0.412657201290 0.000000000000 -vt 0.118986204267 0.415048807859 0.000000000000 -vt 0.118248149753 0.414979010820 0.000000000000 -vt 0.116768434644 0.412282764912 0.000000000000 -vt 0.114910230041 0.406959205866 0.000000000000 -vt 0.113860324025 0.401094585657 0.000000000000 -vt 0.113027706742 0.396125406027 0.000000000000 -vt 0.112157255411 0.392097175121 0.000000000000 -vt 0.130801886320 0.442939460278 0.000000000000 -vt 0.128610894084 0.468570888042 0.000000000000 -vt 0.094356708229 0.491361290216 0.000000000000 -vt 0.141893029213 0.437752097845 0.000000000000 -vt 0.150102630258 0.427333265543 0.000000000000 -vt 0.154337808490 0.414093464613 0.000000000000 -vt 0.154476270080 0.401521474123 0.000000000000 -vt 0.152643069625 0.391335010529 0.000000000000 -vt 0.150666207075 0.383463352919 0.000000000000 -vt 0.151377916336 0.454670488834 0.000000000000 -vt 0.163681745529 0.437636584044 0.000000000000 -vt 0.168372631073 0.418352723122 0.000000000000 -vt 0.166913852096 0.401432096958 0.000000000000 -vt 0.163569614291 0.388818919659 0.000000000000 -vt 0.160684034228 0.379647225142 0.000000000000 -vt 0.159950926900 0.471008867025 0.000000000000 -vt 0.132880300283 0.489435285330 0.000000000000 -vt 0.177281573415 0.447766780853 0.000000000000 -vt 0.184215664864 0.422988891602 0.000000000000 -vt 0.181977853179 0.401209205389 0.000000000000 -vt 0.176495552063 0.385539740324 0.000000000000 -vt 0.171912297606 0.374865829945 0.000000000000 -vt 0.098764792085 0.505384683609 0.000000000000 -vt 0.058615576476 0.491276592016 0.000000000000 -vt 0.294122487307 0.343028873205 0.000000000000 -vt 0.033512126654 0.473827123642 0.000000000000 -vt 0.022036869079 0.449060529470 0.000000000000 -vt 0.304196149111 0.365502059460 0.000000000000 -vt 0.294669389725 0.374178409576 0.000000000000 -vt 0.283370435238 0.353863328695 0.000000000000 -vt 0.021253105253 0.427221357822 0.000000000000 -vt 0.316540300846 0.419560700655 0.000000000000 -vt 0.308288812637 0.422085821629 0.000000000000 -vt 0.304480075836 0.396445810795 0.000000000000 -vt 0.312906295061 0.403799384832 0.000000000000 -vt 0.320418357849 0.438478231430 0.000000000000 -vt 0.309799134731 0.442829579115 0.000000000000 -vt 0.322631418705 0.453612715006 0.000000000000 -vt 0.308162033558 0.458434849977 0.000000000000 -vt 0.322842836380 0.466000735760 0.000000000000 -vt 0.304739683867 0.470083713531 0.000000000000 -vt 0.321488976479 0.476586610079 0.000000000000 -vt 0.301276564598 0.479211658239 0.000000000000 -vt 0.318110078573 0.486222833395 0.000000000000 -vt 0.298631459475 0.487806051970 0.000000000000 -vt 0.342029422522 0.477887094021 0.000000000000 -vt 0.335520654917 0.489814013243 0.000000000000 -vt 0.338924765587 0.462258905172 0.000000000000 -vt 0.335986942053 0.447854578495 0.000000000000 -vt 0.331019103527 0.432695329189 0.000000000000 -vt 0.324403166771 0.415379106998 0.000000000000 -vt 0.317968666553 0.397860914469 0.000000000000 -vt 0.311544537544 0.382980197668 0.000000000000 -vt 0.292794078588 0.320117980242 0.000000000000 -vt 0.322062432766 0.330567449331 0.000000000000 -vt 0.310178071260 0.344646602869 0.000000000000 -vt 0.321752399206 0.375562220812 0.000000000000 -vt 0.315860539675 0.358816295862 0.000000000000 -vt 0.327765852213 0.391973108053 0.000000000000 -vt 0.334508121014 0.409605920315 0.000000000000 -vt 0.341052263975 0.426227092743 0.000000000000 -vt 0.345613449812 0.441917032003 0.000000000000 -vt 0.349559307098 0.456911921501 0.000000000000 -vt 0.353330194950 0.470938861370 0.000000000000 -vt 0.352067083120 0.491384476423 0.000000000000 -vt 0.346471965313 0.498636275530 0.000000000000 -vt 0.357014626265 0.482859700918 0.000000000000 -vt 0.023049619049 0.410277992487 0.000000000000 -vt 0.188200235367 0.367613345385 0.000000000000 -vt 0.193979293108 0.380675494671 0.000000000000 -vt 0.199914619327 0.400077104568 0.000000000000 -vt 0.200497537851 0.426822185516 0.000000000000 -vt 0.188813567162 0.456079959869 0.000000000000 -vt 0.165967300534 0.483203917742 0.000000000000 -vt 0.135587558150 0.503403544426 0.000000000000 -vt 0.101455852389 0.518397510052 0.000000000000 -vt 0.136549651623 0.514204204082 0.000000000000 -vt 0.102526023984 0.530645966530 0.000000000000 -vt 0.170128390193 0.491040199995 0.000000000000 -vt 0.198282465339 0.460966050625 0.000000000000 -vt 0.217465236783 0.429308772087 0.000000000000 -vt 0.220426246524 0.397770404816 0.000000000000 -vt 0.216484680772 0.373772233725 0.000000000000 -vt 0.211094245315 0.355721533298 0.000000000000 -vt 0.078403115273 0.417854249477 0.000000000000 -vt 0.077661454678 0.423130065203 0.000000000000 -vt 0.361433088779 0.473092228174 0.000000000000 -vt 0.358897387981 0.464050680399 0.000000000000 -vt 0.356920510530 0.451468318701 0.000000000000 -vt 0.079683125019 0.414227455854 0.000000000000 -vt 0.080865636468 0.412698864937 0.000000000000 -vt 0.081717401743 0.412858963013 0.000000000000 -vt 0.082934811711 0.414582073689 0.000000000000 -vt 0.083612754941 0.417999476194 0.000000000000 -vt 0.083627842367 0.422989368439 0.000000000000 -vt 0.355338811874 0.436321228743 0.000000000000 -vt 0.352934360504 0.420035988092 0.000000000000 -vt 0.348425179720 0.402650177479 0.000000000000 -vt 0.342104852200 0.385241180658 0.000000000000 -vt 0.336092978716 0.368649065495 0.000000000000 -vt 0.083053693175 0.428555428982 0.000000000000 -vt 0.331038475037 0.351473778486 0.000000000000 -vt 0.295939028263 0.301119387150 0.000000000000 -vt 0.322564095259 0.306299775839 0.000000000000 -vt 0.297336816788 0.282364428043 0.000000000000 -vt 0.323178768158 0.284241318703 0.000000000000 -vt 0.367684066296 0.461390703917 0.000000000000 -vt 0.363470733166 0.458035647869 0.000000000000 -vt 0.364652335644 0.447590470314 0.000000000000 -vt 0.365994274616 0.432411193848 0.000000000000 -vt 0.366280674934 0.415150791407 0.000000000000 -vt 0.364420890808 0.396647334099 0.000000000000 -vt 0.360572069883 0.378713041544 0.000000000000 -vt 0.356490701437 0.362032413483 0.000000000000 -vt 0.353067219257 0.345778703690 0.000000000000 -vt 0.350522726774 0.327914893627 0.000000000000 -vt 0.348939448595 0.305953025818 0.000000000000 -vt 0.346083581448 0.277952730656 0.000000000000 -vt 0.373975127935 0.447995543480 0.000000000000 -vt 0.379207283258 0.431906849146 0.000000000000 -vt 0.382956564426 0.412491261959 0.000000000000 -vt 0.384116321802 0.392035484314 0.000000000000 -vt 0.382254749537 0.373682171106 0.000000000000 -vt 0.379626274109 0.358964234591 0.000000000000 -vt 0.377992331982 0.345823734999 0.000000000000 -vt 0.377301573753 0.329902321100 0.000000000000 -vt 0.376336544752 0.303653508425 0.000000000000 -vt 0.370527774096 0.266846507788 0.000000000000 -vt 0.216167435050 0.467717558146 0.000000000000 -vt 0.210370138288 0.459447145462 0.000000000000 -vt 0.081996142864 0.433199465275 0.000000000000 -vt 0.222096204758 0.439130961895 0.000000000000 -vt 0.226445078850 0.444121509790 0.000000000000 -vt 0.233966410160 0.386992007494 0.000000000000 -vt 0.231436342001 0.403846651316 0.000000000000 -vt 0.228788286448 0.415274649858 0.000000000000 -vt 0.231669127941 0.390098005533 0.000000000000 -vt 0.233401954174 0.365559697151 0.000000000000 -vt 0.227946877480 0.368952572346 0.000000000000 -vt 0.222369551659 0.352989733219 0.000000000000 -vt 0.231268167496 0.347663909197 0.000000000000 -vt 0.228197038174 0.333069592714 0.000000000000 -vt 0.215772062540 0.341411590576 0.000000000000 -vt 0.225630939007 0.321423888206 0.000000000000 -vt 0.210557922721 0.332115828991 0.000000000000 -vt 0.240293502808 0.310512185097 0.000000000000 -vt 0.238473564386 0.327548325062 0.000000000000 -vt 0.237924396992 0.344880312681 0.000000000000 -vt 0.237548619509 0.364148646593 0.000000000000 -vt 0.080796964467 0.435884207487 0.000000000000 -vt 0.235683202744 0.385488867760 0.000000000000 -vt 0.233118027449 0.406267970800 0.000000000000 -vt 0.231307089329 0.424209684134 0.000000000000 -vt 0.210896104574 0.489333540201 0.000000000000 -vt 0.228112816811 0.462109386921 0.000000000000 -vt 0.236405730247 0.472126305103 0.000000000000 -vt 0.236261844635 0.426290810108 0.000000000000 -vt 0.232935667038 0.445951789618 0.000000000000 -vt 0.237997591496 0.406573981047 0.000000000000 -vt 0.240250259638 0.385305374861 0.000000000000 -vt 0.242734611034 0.364867120981 0.000000000000 -vt 0.244929671288 0.346436828375 0.000000000000 -vt 0.247872665524 0.330308973789 0.000000000000 -vt 0.250990182161 0.316065877676 0.000000000000 -vt 0.249255821109 0.295715004206 0.000000000000 -vt 0.254375159740 0.304102927446 0.000000000000 -vt 0.259052336216 0.313747882843 0.000000000000 -vt 0.256746292114 0.322819858789 0.000000000000 -vt 0.255218595266 0.335408508778 0.000000000000 -vt 0.254195064306 0.350621551275 0.000000000000 -vt 0.252835571766 0.367554813623 0.000000000000 -vt 0.250323951244 0.386674314737 0.000000000000 -vt 0.247343555093 0.407099246979 0.000000000000 -vt 0.244989335537 0.426806420088 0.000000000000 -vt 0.242804884911 0.447076678276 0.000000000000 -vt 0.235569059849 0.496732383966 0.000000000000 -vt 0.210636273026 0.507261335850 0.000000000000 -vt 0.265602082014 0.325080633163 0.000000000000 -vt 0.261477023363 0.328609049320 0.000000000000 -vt 0.262952446938 0.338707923889 0.000000000000 -vt 0.264598786831 0.353362590075 0.000000000000 -vt 0.265408009291 0.370452553034 0.000000000000 -vt 0.264614790678 0.389507651329 0.000000000000 -vt 0.262594908476 0.408623784781 0.000000000000 -vt 0.260723888874 0.426476329565 0.000000000000 -vt 0.259777098894 0.444406121969 0.000000000000 -vt 0.259517729282 0.464280545712 0.000000000000 -vt 0.259723722935 0.488092929125 0.000000000000 -vt 0.272190570831 0.337464153767 0.000000000000 -vt 0.277376800776 0.352163642645 0.000000000000 -vt 0.281132608652 0.370615124702 0.000000000000 -vt 0.283069849014 0.391205787659 0.000000000000 -vt 0.282786369324 0.410528808832 0.000000000000 -vt 0.281975150108 0.425936192274 0.000000000000 -vt 0.281850397587 0.438871800900 0.000000000000 -vt 0.282650381327 0.454188883305 0.000000000000 -vt 0.285106837749 0.479603022337 0.000000000000 -vt 0.079694159329 0.435663342476 0.000000000000 -vt 0.078524023294 0.432797789574 0.000000000000 -vt 0.077620923519 0.428230971098 0.000000000000 -vt 0.079657681286 0.418213814497 0.000000000000 -vt 0.079307116568 0.423214733601 0.000000000000 -vt 0.080295994878 0.414836943150 0.000000000000 -vt 0.080963805318 0.413298457861 0.000000000000 -vt 0.081294111907 0.413456052542 0.000000000000 -vt 0.081488415599 0.414713323116 0.000000000000 -vt 0.082648865879 0.418150305748 0.000000000000 -vt 0.082757845521 0.422904253006 0.000000000000 -vt 0.082332074642 0.427900880575 0.000000000000 -vt 0.081549659371 0.432032704353 0.000000000000 -vt 0.080782778561 0.434659361839 0.000000000000 -vt 0.080355659127 0.434551537037 0.000000000000 -vt 0.079714648426 0.432231515646 0.000000000000 -vt 0.079296082258 0.428110510111 0.000000000000 -vt 0.221947401762 0.311564117670 0.000000000000 -vt 0.206676691771 0.323618710041 0.000000000000 -vt 0.234236359596 0.298808634281 0.000000000000 -vt 0.243671953678 0.288532763720 0.000000000000 -vt 0.210074737668 0.525931179523 0.000000000000 -vt 0.234980046749 0.519074082375 0.000000000000 -vt 0.258448451757 0.516759932041 0.000000000000 -vt 0.285151630640 0.516420423985 0.000000000000 -vt 0.195827364922 0.027920853347 0.000000000000 -vt 0.193216472864 0.025534208864 0.000000000000 -vt 0.208045646548 0.014590993524 0.000000000000 -vt 0.209939867258 0.017815891653 0.000000000000 -vt 0.219733223319 0.012098524719 0.000000000000 -vt 0.219577640295 0.015777334571 0.000000000000 -vt 0.231459319592 0.012075107545 0.000000000000 -vt 0.230521082878 0.016644857824 0.000000000000 -vt 0.243238985538 0.012886568904 0.000000000000 -vt 0.242090910673 0.019283901900 0.000000000000 -vt 0.254986017942 0.014112763107 0.000000000000 -vt 0.254209905863 0.020853456110 0.000000000000 -vt 0.268618255854 0.021859001368 0.000000000000 -vt 0.266599744558 0.015186753124 0.000000000000 -vt 0.278297692537 0.015581674874 0.000000000000 -vt 0.280311465263 0.022918354720 0.000000000000 -vt 0.294243395329 0.017284523696 0.000000000000 -vt 0.290962666273 0.024005178362 0.000000000000 -vt 0.296158790588 0.030226442963 0.000000000000 -vt 0.300414890051 0.029313210398 0.000000000000 -vt 0.303686618805 0.042154934257 0.000000000000 -vt 0.299199730158 0.041589122266 0.000000000000 -vt 0.303400695324 0.052850034088 0.000000000000 -vt 0.299067586660 0.051488291472 0.000000000000 -vt 0.301245510578 0.063028395176 0.000000000000 -vt 0.297050625086 0.061028119177 0.000000000000 -vt 0.188072130084 0.041658472270 0.000000000000 -vt 0.184647515416 0.040359999985 0.000000000000 -vt 0.185590237379 0.054300930351 0.000000000000 -vt 0.180999323726 0.054078709334 0.000000000000 -vt 0.186842098832 0.067733690143 0.000000000000 -vt 0.180815145373 0.066969290376 0.000000000000 -vt 0.187923297286 0.082707628608 0.000000000000 -vt 0.181074976921 0.081876814365 0.000000000000 -vt 0.187377303839 0.107746466994 0.000000000000 -vt 0.187539190054 0.120622426271 0.000000000000 -vt 0.181078135967 0.122370526195 0.000000000000 -vt 0.180750086904 0.106961801648 0.000000000000 -vt 0.181374669075 0.094601452351 0.000000000000 -vt 0.187665045261 0.095849484205 0.000000000000 -vt 0.227798283100 0.129312291741 0.000000000000 -vt 0.238564521074 0.124569609761 0.000000000000 -vt 0.243330389261 0.127270132303 0.000000000000 -vt 0.231010556221 0.133791074157 0.000000000000 -vt 0.220073655248 0.135354548693 0.000000000000 -vt 0.218523919582 0.131200432777 0.000000000000 -vt 0.206768333912 0.135661438107 0.000000000000 -vt 0.206591814756 0.131151124835 0.000000000000 -vt 0.194878339767 0.131718292832 0.000000000000 -vt 0.195264026523 0.127670004964 0.000000000000 -vt 0.297571629286 0.073909014463 0.000000000000 -vt 0.293510973454 0.071692824364 0.000000000000 -vt 0.293531447649 0.085388556123 0.000000000000 -vt 0.288804322481 0.082740962505 0.000000000000 -vt 0.284273296595 0.097582057118 0.000000000000 -vt 0.281252384186 0.094275429845 0.000000000000 -vt 0.270511358976 0.111514881253 0.000000000000 -vt 0.267813563347 0.108745023608 0.000000000000 -vt 0.253925532103 0.117747187614 0.000000000000 -vt 0.256331086159 0.121454820037 0.000000000000 -vt 0.267415255308 0.081492692232 0.000000000000 -vt 0.255906671286 0.094144165516 0.000000000000 -vt 0.244139820337 0.101001486182 0.000000000000 -vt 0.231230318546 0.105198845267 0.000000000000 -vt 0.219598352909 0.110711082816 0.000000000000 -vt 0.213647723198 0.110525771976 0.000000000000 -vt 0.198271200061 0.116921544075 0.000000000000 -vt 0.203886121511 0.110362097621 0.000000000000 -vt 0.196813777089 0.098104864359 0.000000000000 -vt 0.196252465248 0.102853164077 0.000000000000 -vt 0.272518634796 0.073012456298 0.000000000000 -vt 0.276711463928 0.062691569328 0.000000000000 -vt 0.280104994774 0.053172681481 0.000000000000 -vt 0.283575773239 0.045879449695 0.000000000000 -vt 0.283506870270 0.039421103895 0.000000000000 -vt 0.282259076834 0.030528377742 0.000000000000 -vt 0.272425651550 0.030439440161 0.000000000000 -vt 0.257659971714 0.030192218721 0.000000000000 -vt 0.247058525681 0.033215377480 0.000000000000 -vt 0.228341341019 0.025837715715 0.000000000000 -vt 0.218866378069 0.024133518338 0.000000000000 -vt 0.212634310126 0.025178913027 0.000000000000 -vt 0.200903266668 0.032452777028 0.000000000000 -vt 0.194876089692 0.044088792056 0.000000000000 -vt 0.193243041635 0.053994949907 0.000000000000 -vt 0.194931253791 0.067793801427 0.000000000000 -vt 0.198766767979 0.084062173963 0.000000000000 -vt 0.206359907985 0.094736546278 0.000000000000 -vt 0.212366148829 0.098234102130 0.000000000000 -vt 0.217166453600 0.096218973398 0.000000000000 -vt 0.205443292856 0.087112799287 0.000000000000 -vt 0.226509511471 0.090840920806 0.000000000000 -vt 0.237037748098 0.087899029255 0.000000000000 -vt 0.246875688434 0.081057921052 0.000000000000 -vt 0.256278872490 0.072482436895 0.000000000000 -vt 0.260736495256 0.057795342058 0.000000000000 -vt 0.259254723787 0.064904838800 0.000000000000 -vt 0.272691100836 0.038979575038 0.000000000000 -vt 0.262009739876 0.038989257067 0.000000000000 -vt 0.276944041252 0.045822035521 0.000000000000 -vt 0.268426418304 0.047114204615 0.000000000000 -vt 0.269619315863 0.043809827417 0.000000000000 -vt 0.253669768572 0.045147921890 0.000000000000 -vt 0.248847588897 0.056667540222 0.000000000000 -vt 0.246177032590 0.064497530460 0.000000000000 -vt 0.239239543676 0.071869567037 0.000000000000 -vt 0.232059359550 0.077080324292 0.000000000000 -vt 0.222070574760 0.079870447516 0.000000000000 -vt 0.206698760390 0.074161648750 0.000000000000 -vt 0.213897421956 0.072432681918 0.000000000000 -vt 0.205729246140 0.062620416284 0.000000000000 -vt 0.203790888190 0.054370727390 0.000000000000 -vt 0.204770088196 0.045650247484 0.000000000000 -vt 0.208388775587 0.038391694427 0.000000000000 -vt 0.216515302658 0.032267022878 0.000000000000 -vt 0.221525013447 0.031139671803 0.000000000000 -vt 0.229856431484 0.032532032579 0.000000000000 -vt 0.240117192268 0.040356174111 0.000000000000 -vt 0.238003432751 0.049525838345 0.000000000000 -vt 0.230851382017 0.062317129225 0.000000000000 -vt 0.223892956972 0.068100020289 0.000000000000 -vt 0.218158707023 0.060949768871 0.000000000000 -vt 0.224889278412 0.055608633906 0.000000000000 -vt 0.231338173151 0.044668566436 0.000000000000 -vt 0.224949836731 0.040866594762 0.000000000000 -vt 0.220517441630 0.039209909737 0.000000000000 -vt 0.215718701482 0.043925788254 0.000000000000 -vt 0.211569100618 0.049045812339 0.000000000000 -vt 0.212551221251 0.054835002869 0.000000000000 -vt 0.219418004155 0.048615094274 0.000000000000 -vt 0.177896246314 0.039324510843 0.000000000000 -vt 0.189204439521 0.020011376590 0.000000000000 -vt 0.204814672470 0.008875429630 0.000000000000 -vt 0.218808963895 0.005773015320 0.000000000000 -vt 0.232130467892 0.004795841873 0.000000000000 -vt 0.243434399366 0.006405927241 0.000000000000 -vt 0.255707651377 0.007152091712 0.000000000000 -vt 0.266037523746 0.008445382118 0.000000000000 -vt 0.276542603970 0.009638480842 0.000000000000 -vt 0.291882872581 0.013886258006 0.000000000000 -vt 0.305758953094 0.026801381260 0.000000000000 -vt 0.310110300779 0.042010162026 0.000000000000 -vt 0.309658646584 0.054701257497 0.000000000000 -vt 0.307640582323 0.066039174795 0.000000000000 -vt 0.304315268993 0.075605571270 0.000000000000 -vt 0.302689433098 0.083687961102 0.000000000000 -vt 0.289600938559 0.101637110114 0.000000000000 -vt 0.275979250669 0.114943787456 0.000000000000 -vt 0.261293739080 0.125751689076 0.000000000000 -vt 0.248583957553 0.132909372449 0.000000000000 -vt 0.218775406480 0.143254563212 0.000000000000 -vt 0.228658616543 0.143950298429 0.000000000000 -vt 0.206840604544 0.142785564065 0.000000000000 -vt 0.190907508135 0.138325244188 0.000000000000 -vt 0.181003153324 0.126772314310 0.000000000000 -vt 0.174718171358 0.105727061629 0.000000000000 -vt 0.175457358360 0.093386068940 0.000000000000 -vt 0.176170423627 0.080959752202 0.000000000000 -vt 0.175519734621 0.067012742162 0.000000000000 -vt 0.174860477448 0.054189030081 0.000000000000 -vt 0.175442948937 0.118314579129 0.000000000000 -vt 0.299658834934 0.013686995953 0.000000000000 -vt 0.297007620335 0.015501294285 0.000000000000 -vt 0.296986013651 0.094732716680 0.000000000000 -vt 0.178140535951 0.121313422918 0.000000000000 -vt 0.178094834089 0.129377126694 0.000000000000 -vt 0.290370285511 0.010927941650 0.000000000000 -vt 0.240662753582 0.138773083687 0.000000000000 -vt 0.059489179403 0.582100212574 0.000000000000 -vt 0.068415686488 0.582416296005 0.000000000000 -vt 0.067261539400 0.606926023960 0.000000000000 -vt 0.058599364012 0.606609225273 0.000000000000 -vt 0.050634499639 0.581815600395 0.000000000000 -vt 0.050033342093 0.606300354004 0.000000000000 -vt 0.041638877243 0.581597447395 0.000000000000 -vt 0.041299115866 0.606083035469 0.000000000000 -vt 0.032489020377 0.581519067287 0.000000000000 -vt 0.032466728240 0.605973839760 0.000000000000 -vt 0.023544281721 0.581574916840 0.000000000000 -vt 0.023710895330 0.605970263481 0.000000000000 -vt 0.077301658690 0.582797050476 0.000000000000 -vt 0.075893089175 0.607333362103 0.000000000000 -vt 0.035480882972 0.775563001633 0.000000000000 -vt 0.040293347090 0.776472151279 0.000000000000 -vt 0.036699648947 0.779854416847 0.000000000000 -vt 0.032038930804 0.777974605560 0.000000000000 -vt 0.044753897935 0.775144159794 0.000000000000 -vt 0.049120556563 0.776610195637 0.000000000000 -vt 0.044636141509 0.779394447803 0.000000000000 -vt 0.050690788776 0.780745148659 0.000000000000 -vt 0.054302733392 0.776831269264 0.000000000000 -vt 0.056948300451 0.779902398586 0.000000000000 -vt 0.057442288846 0.767054140568 0.000000000000 -vt 0.051350947469 0.766096353531 0.000000000000 -vt 0.045185070485 0.765643537045 0.000000000000 -vt 0.039071660489 0.765589058399 0.000000000000 -vt 0.032788928598 0.766110718250 0.000000000000 -vt 0.026467472315 0.767407417297 0.000000000000 -vt 0.063698008657 0.768436372280 0.000000000000 -vt 0.410184800625 0.205661505461 0.000000000000 -vt 0.061233457178 0.523812234402 0.000000000000 -vt 0.070765629411 0.524310529232 0.000000000000 -vt 0.069685108960 0.554912924767 0.000000000000 -vt 0.060390468687 0.554528176785 0.000000000000 -vt 0.053767081350 0.729990005493 0.000000000000 -vt 0.061261150986 0.730732798576 0.000000000000 -vt 0.054995980114 0.702194809914 0.000000000000 -vt 0.062634825706 0.702704548836 0.000000000000 -vt 0.064006246626 0.678737044334 0.000000000000 -vt 0.055990491062 0.678335130215 0.000000000000 -vt 0.056928943843 0.654432654381 0.000000000000 -vt 0.065110854805 0.654795587063 0.000000000000 -vt 0.066195428371 0.630862057209 0.000000000000 -vt 0.057763587683 0.630513489246 0.000000000000 -vt 0.051746767014 0.523659586906 0.000000000000 -vt 0.051160465926 0.554318308830 0.000000000000 -vt 0.046276170760 0.729541480541 0.000000000000 -vt 0.047176342458 0.701836824417 0.000000000000 -vt 0.047830644995 0.678016304970 0.000000000000 -vt 0.048644352704 0.654150307178 0.000000000000 -vt 0.049303833395 0.630233883858 0.000000000000 -vt 0.042389769107 0.523753523827 0.000000000000 -vt 0.041977059096 0.554233670235 0.000000000000 -vt 0.038769047707 0.729471445084 0.000000000000 -vt 0.039331037551 0.701696574688 0.000000000000 -vt 0.039704795927 0.677826702595 0.000000000000 -vt 0.040310915560 0.653930783272 0.000000000000 -vt 0.040829222649 0.630019962788 0.000000000000 -vt 0.032788697630 0.523885667324 0.000000000000 -vt 0.032603625208 0.554248988628 0.000000000000 -vt 0.031183568761 0.729752242565 0.000000000000 -vt 0.031547192484 0.701745390892 0.000000000000 -vt 0.031793061644 0.677753329277 0.000000000000 -vt 0.032022494823 0.653800427914 0.000000000000 -vt 0.032241348177 0.629892110825 0.000000000000 -vt 0.023286256939 0.523862004280 0.000000000000 -vt 0.023312594742 0.554275989532 0.000000000000 -vt 0.023615654558 0.730087935925 0.000000000000 -vt 0.023773714900 0.701748549938 0.000000000000 -vt 0.023966450244 0.677748382092 0.000000000000 -vt 0.023824151605 0.653813481331 0.000000000000 -vt 0.023755025119 0.629873633385 0.000000000000 -vt 0.080035939813 0.524939179420 0.000000000000 -vt 0.078819200397 0.555354475975 0.000000000000 -vt 0.068714916706 0.731523096561 0.000000000000 -vt 0.070204541087 0.703219473362 0.000000000000 -vt 0.071883074939 0.679210066795 0.000000000000 -vt 0.073152050376 0.655230820179 0.000000000000 -vt 0.074596188962 0.631297707558 0.000000000000 -vt 0.427655726671 0.333007007837 0.000000000000 -vt 0.440372914076 0.328327596188 0.000000000000 -vt 0.444987475872 0.344597071409 0.000000000000 -vt 0.432079792023 0.348230421543 0.000000000000 -vt 0.436833947897 0.363906830549 0.000000000000 -vt 0.449768215418 0.360880523920 0.000000000000 -vt 0.454692780972 0.378165900707 0.000000000000 -vt 0.441895663738 0.381562143564 0.000000000000 -vt 0.414691954851 0.337748318911 0.000000000000 -vt 0.419402211905 0.352767288685 0.000000000000 -vt 0.424107730389 0.368486940861 0.000000000000 -vt 0.429422736168 0.385863065720 0.000000000000 -vt 0.401303559542 0.341026574373 0.000000000000 -vt 0.406823009253 0.357325315475 0.000000000000 -vt 0.411697834730 0.372874319553 0.000000000000 -vt 0.417245209217 0.390449941158 0.000000000000 -vt 0.387970775366 0.344980746508 0.000000000000 -vt 0.393820285797 0.361572891474 0.000000000000 -vt 0.399133056402 0.377458244562 0.000000000000 -vt 0.404806077480 0.394824922085 0.000000000000 -vt 0.453473359346 0.324476778507 0.000000000000 -vt 0.466956764460 0.321778506041 0.000000000000 -vt 0.471398383379 0.338798433542 0.000000000000 -vt 0.458161979914 0.342115193605 0.000000000000 -vt 0.462697505951 0.358080714941 0.000000000000 -vt 0.475638061762 0.355021774769 0.000000000000 -vt 0.480182796717 0.372735410929 0.000000000000 -vt 0.467404156923 0.375559061766 0.000000000000 -vt 0.423334538937 0.312670528889 0.000000000000 -vt 0.433873385191 0.309838533401 0.000000000000 -vt 0.436265200377 0.312351495028 0.000000000000 -vt 0.422530740499 0.315895646811 0.000000000000 -vt 0.447797864676 0.306353360415 0.000000000000 -vt 0.450094014406 0.308744937181 0.000000000000 -vt 0.461704343557 0.302910506725 0.000000000000 -vt 0.463915377855 0.305326640606 0.000000000000 -vt 0.382604420185 0.326017051935 0.000000000000 -vt 0.392749220133 0.322181522846 0.000000000000 -vt 0.395257681608 0.324275016785 0.000000000000 -vt 0.382101863623 0.329265147448 0.000000000000 -vt 0.406064450741 0.317371100187 0.000000000000 -vt 0.408690214157 0.319537758827 0.000000000000 -vt 0.454164594412 0.389897853136 0.000000000000 -vt 0.448823004961 0.391495555639 0.000000000000 -vt 0.443516105413 0.386446684599 0.000000000000 -vt 0.456138074398 0.383067548275 0.000000000000 -vt 0.437463909388 0.395830690861 0.000000000000 -vt 0.431178033352 0.391206234694 0.000000000000 -vt 0.424428552389 0.400618851185 0.000000000000 -vt 0.419008165598 0.395644724369 0.000000000000 -vt 0.412200152874 0.404757648706 0.000000000000 -vt 0.406511843204 0.400167405605 0.000000000000 -vt 0.479276150465 0.385172754526 0.000000000000 -vt 0.473846048117 0.386270821095 0.000000000000 -vt 0.468606919050 0.380785584450 0.000000000000 -vt 0.481370300055 0.378176510334 0.000000000000 -vt 0.436999201775 0.315413832664 0.000000000000 -vt 0.423440814018 0.318899452686 0.000000000000 -vt 0.450722873211 0.311825752258 0.000000000000 -vt 0.464657485485 0.308184534311 0.000000000000 -vt 0.396297454834 0.327027112246 0.000000000000 -vt 0.382932245731 0.332121223211 0.000000000000 -vt 0.409763991833 0.322595357895 0.000000000000 -vt 0.442299365997 0.382790595293 0.000000000000 -vt 0.455049455166 0.379350900650 0.000000000000 -vt 0.429864943027 0.387207239866 0.000000000000 -vt 0.417697101831 0.391777902842 0.000000000000 -vt 0.404973804951 0.396399646997 0.000000000000 -vt 0.467713981867 0.376910001040 0.000000000000 -vt 0.480817049742 0.374158143997 0.000000000000 -vt 0.437278181314 0.316399097443 0.000000000000 -vt 0.423721343279 0.319981753826 0.000000000000 -vt 0.450930684805 0.312892526388 0.000000000000 -vt 0.464460253716 0.309410959482 0.000000000000 -vt 0.396746635437 0.328152865171 0.000000000000 -vt 0.383763283491 0.333080857992 0.000000000000 -vt 0.410141348839 0.323806256056 0.000000000000 -vt 0.371242642403 0.206788405776 0.000000000000 -vt 0.375714451075 0.200254172087 0.000000000000 -vt 0.379231601954 0.206475213170 0.000000000000 -vt 0.375783115625 0.212909027934 0.000000000000 -vt 0.383946120739 0.214252978563 0.000000000000 -vt 0.385994136333 0.206152796745 0.000000000000 -vt 0.383823841810 0.198206618428 0.000000000000 -vt 0.389040261507 0.196492955089 0.000000000000 -vt 0.391231000423 0.205955997109 0.000000000000 -vt 0.388896137476 0.215648040175 0.000000000000 -vt 0.386244505644 0.225284442306 0.000000000000 -vt 0.381366074085 0.234502539039 0.000000000000 -vt 0.377654612064 0.230434879661 0.000000000000 -vt 0.380352199078 0.177962914109 0.000000000000 -vt 0.385863542557 0.187034189701 0.000000000000 -vt 0.376735985279 0.182071089745 0.000000000000 -vt 0.400243073702 0.205795019865 0.000000000000 -vt 0.398853629827 0.194475561380 0.000000000000 -vt 0.398457139730 0.217155665159 0.000000000000 -vt 0.395268946886 0.228200212121 0.000000000000 -vt 0.391248136759 0.239007428288 0.000000000000 -vt 0.395271182060 0.183712929487 0.000000000000 -vt 0.390099167824 0.173236235976 0.000000000000 -vt 0.404895007610 0.295395046473 0.000000000000 -vt 0.401947498322 0.296175211668 0.000000000000 -vt 0.399637848139 0.292153716087 0.000000000000 -vt 0.401830643415 0.291295886040 0.000000000000 -vt 0.399310708046 0.296199768782 0.000000000000 -vt 0.397574305534 0.292755782604 0.000000000000 -vt 0.408904105425 0.288272053003 0.000000000000 -vt 0.407307982445 0.290285140276 0.000000000000 -vt 0.404559284449 0.287732571363 0.000000000000 -vt 0.406326085329 0.285840153694 0.000000000000 -vt 0.406662702560 0.292970359325 0.000000000000 -vt 0.403447926044 0.289671152830 0.000000000000 -vt 0.396660417318 0.287977755070 0.000000000000 -vt 0.398700773716 0.286984145641 0.000000000000 -vt 0.394956201315 0.288790345192 0.000000000000 -vt 0.401856094599 0.284300088882 0.000000000000 -vt 0.403861761093 0.282722651958 0.000000000000 -vt 0.400499969721 0.285655498505 0.000000000000 -vt 0.393806338310 0.283442467451 0.000000000000 -vt 0.395833194256 0.282441198826 0.000000000000 -vt 0.392093360424 0.284306377172 0.000000000000 -vt 0.399467855692 0.280218929052 0.000000000000 -vt 0.401700288057 0.278968840837 0.000000000000 -vt 0.397831201553 0.281272202730 0.000000000000 -vt 0.391297876835 0.278489261866 0.000000000000 -vt 0.393293648958 0.277554869652 0.000000000000 -vt 0.389414459467 0.279250085354 0.000000000000 -vt 0.397396445274 0.275657951832 0.000000000000 -vt 0.399793207645 0.274844229221 0.000000000000 -vt 0.395377457142 0.276584476233 0.000000000000 -vt 0.389087766409 0.272915095091 0.000000000000 -vt 0.391173362732 0.272055685520 0.000000000000 -vt 0.386810988188 0.273582458496 0.000000000000 -vt 0.395762920380 0.270275622606 0.000000000000 -vt 0.398250907660 0.270135104656 0.000000000000 -vt 0.393281280994 0.271341711283 0.000000000000 -vt 0.387520015240 0.266913384199 0.000000000000 -vt 0.389951229095 0.266276419163 0.000000000000 -vt 0.384966522455 0.267515212297 0.000000000000 -vt 0.394670933485 0.264871448278 0.000000000000 -vt 0.397267192602 0.265005409718 0.000000000000 -vt 0.392056882381 0.265746623278 0.000000000000 -vt 0.386280536652 0.262535691261 0.000000000000 -vt 0.389030128717 0.261800318956 0.000000000000 -vt 0.383825421333 0.263225555420 0.000000000000 -vt 0.394305050373 0.261209517717 0.000000000000 -vt 0.396993845701 0.261318951845 0.000000000000 -vt 0.391601622105 0.261423856020 0.000000000000 -vt 0.384926229715 0.259148895741 0.000000000000 -vt 0.388205587864 0.257940262556 0.000000000000 -vt 0.382767438889 0.261004865170 0.000000000000 -vt 0.394367873669 0.258704215288 0.000000000000 -vt 0.397562384605 0.259168028831 0.000000000000 -vt 0.391579329967 0.257740765810 0.000000000000 -vt 0.062066528946 0.497222512960 0.000000000000 -vt 0.071865737438 0.497819632292 0.000000000000 -vt 0.052253138274 0.497047573328 0.000000000000 -vt 0.042627077550 0.497259229422 0.000000000000 -vt 0.032757628709 0.497487276793 0.000000000000 -vt 0.022930733860 0.497487515211 0.000000000000 -vt 0.081421323121 0.498642355204 0.000000000000 -vt 0.408895790577 0.192783519626 0.000000000000 -vt 0.405064105988 0.180669501424 0.000000000000 -vt 0.400167405605 0.169291511178 0.000000000000 -vt 0.401480078697 0.242461070418 0.000000000000 -vt 0.405161798000 0.230870768428 0.000000000000 -vt 0.408491641283 0.218653172255 0.000000000000 -vt 0.380247503519 0.189571470022 0.000000000000 -vt 0.381086647511 0.223131284118 0.000000000000 -vt 0.420218378305 0.313499540091 0.000000000000 -vt 0.442574709654 0.393686324358 0.000000000000 -vt 0.437170535326 0.308998465538 0.000000000000 -vt 0.450992375612 0.305552929640 0.000000000000 -vt 0.395807057619 0.321048557758 0.000000000000 -vt 0.409543335438 0.316259503365 0.000000000000 -vt 0.460468471050 0.388684481382 0.000000000000 -vt 0.429571330547 0.398836284876 0.000000000000 -vt 0.417428702116 0.402817249298 0.000000000000 -vt 0.465852618217 0.387890368700 0.000000000000 -vt 0.165486067533 0.985748410225 0.000000000000 -vt 0.153918713331 0.884558439255 0.000000000000 -vt 0.153763413429 0.881860136986 0.000000000000 -vt 0.204113468528 0.982658386230 0.000000000000 -vt 0.204646229744 0.989186286926 0.000000000000 -vt 0.186044186354 0.877731442451 0.000000000000 -vt 0.185995131731 0.879323482513 0.000000000000 -vt 0.165391892195 0.991528987885 0.000000000000 -vt 0.215989306569 0.874527692795 0.000000000000 -vt 0.239299163222 0.979033589363 0.000000000000 -vt 0.216438904405 0.876245737076 0.000000000000 -vt 0.147602885962 0.884569108486 0.000000000000 -vt 0.252690643072 0.979669451714 0.000000000000 -vt 0.252580404282 0.986951112747 0.000000000000 -vt 0.149314463139 0.881703615189 0.000000000000 -vt 0.239499345422 0.986131906509 0.000000000000 -vt 0.139916136861 0.872989058495 0.000000000000 -vt 0.153603509068 0.992006182671 0.000000000000 -vt 0.153609484434 0.990444540977 0.000000000000 -vt 0.010600453243 0.824086070061 0.000000000000 -vt 0.012143557891 0.805372476578 0.000000000000 -vt 0.018072610721 0.805904865265 0.000000000000 -vt 0.018011515960 0.835803985596 0.000000000000 -vt 0.854685604572 0.394145637751 0.000000000000 -vt 0.856347262859 0.406974732876 0.000000000000 -vt 0.854803860188 0.407253265381 0.000000000000 -vt 0.852515399456 0.394508123398 0.000000000000 -vt 0.014217739925 0.786286652088 0.000000000000 -vt 0.141516894102 0.871268332005 0.000000000000 -vt 0.236085057259 0.870658397675 0.000000000000 -vt 0.235590070486 0.871755778790 0.000000000000 -vt 0.115637660027 0.902860224247 0.000000000000 -vt 0.110983915627 0.890343248844 0.000000000000 -vt 0.113721966743 0.903127968311 0.000000000000 -vt 0.108955033123 0.891542613506 0.000000000000 -vt 0.094152219594 0.932179987431 0.000000000000 -vt 0.092673666775 0.930834054947 0.000000000000 -vt 0.070010572672 0.963107407093 0.000000000000 -vt 0.068242847919 0.961778044701 0.000000000000 -vt 0.061999842525 0.971761763096 0.000000000000 -vt 0.174994021654 0.927675366402 0.000000000000 -vt 0.144831538200 0.970289051533 0.000000000000 -vt 0.200194299221 0.932316362858 0.000000000000 -vt 0.170293733478 0.964262902737 0.000000000000 -vt 0.108677349985 0.981302440166 0.000000000000 -vt 0.124079853296 0.982393920422 0.000000000000 -vt 0.078137099743 0.979704558849 0.000000000000 -vt 0.109282203019 0.983950555325 0.000000000000 -vt 0.105039052665 0.987083256245 0.000000000000 -vt 0.125474229455 0.988127648830 0.000000000000 -vt 0.111332640052 0.988403081894 0.000000000000 -vt 0.149527281523 0.983822643757 0.000000000000 -vt 0.175797849894 0.974198222160 0.000000000000 -vt 0.200493484735 0.947993755341 0.000000000000 -vt 0.202181890607 0.953875601292 0.000000000000 -vt 0.210946768522 0.941928744316 0.000000000000 -vt 0.204716980457 0.950321793556 0.000000000000 -vt 0.211182147264 0.940664827824 0.000000000000 -vt 0.221946761012 0.927524268627 0.000000000000 -vt 0.212981313467 0.939730703831 0.000000000000 -vt 0.219961285591 0.926237881184 0.000000000000 -vt 0.236418157816 0.878085970879 0.000000000000 -vt 0.009088402614 0.867007911205 0.000000000000 -vt 0.233274430037 0.900619506836 0.000000000000 -vt 0.223317831755 0.925070583820 0.000000000000 -vt 0.222155556083 0.926465988159 0.000000000000 -vt 0.221913784742 0.924954414368 0.000000000000 -vt 0.222598418593 0.927596032619 0.000000000000 -vt 0.201231330633 0.949153244495 0.000000000000 -vt 0.203538969159 0.953897118568 0.000000000000 -vt 0.818132102489 0.385249525309 0.000000000000 -vt 0.205010369420 0.951609432697 0.000000000000 -vt 0.213920146227 0.940414905548 0.000000000000 -vt 0.818589150906 0.383544415236 0.000000000000 -vt 0.780589759350 0.374358534813 0.000000000000 -vt 0.016577487811 0.868200361729 0.000000000000 -vt 0.016604727134 0.872863054276 0.000000000000 -vt 0.010927146301 0.873423874378 0.000000000000 -vt 0.781472146511 0.373139113188 0.000000000000 -vt 0.775797307491 0.355791121721 0.000000000000 -vt 0.767820060253 0.372488409281 0.000000000000 -vt 0.802661955357 0.343176126480 0.000000000000 -vt 0.212836444378 0.942034363747 0.000000000000 -vt 0.794418156147 0.332618147135 0.000000000000 -vt 0.017825072631 0.886228740215 0.000000000000 -vt 0.859027683735 0.311750322580 0.000000000000 -vt 0.856714665890 0.300876915455 0.000000000000 -vt 0.011322205886 0.886385619640 0.000000000000 -vt 0.890980184078 0.300591170788 0.000000000000 -vt 0.212094113231 0.942788124084 0.000000000000 -vt 0.234720200300 0.900862038136 0.000000000000 -vt 0.237578302622 0.878117561340 0.000000000000 -vt 0.077356182039 0.981415390968 0.000000000000 -vt 0.060611370951 0.973357379436 0.000000000000 -vt 0.105943888426 0.988982677460 0.000000000000 -vt 0.258138507605 0.974806785583 0.000000000000 -vt 0.257529258728 0.990823626518 0.000000000000 -vt 0.264203071594 0.971977353096 0.000000000000 -vt 0.263009667397 0.993429660797 0.000000000000 -vt 0.271215617657 0.974126696587 0.000000000000 -vt 0.269773542881 0.993223547935 0.000000000000 -vt 0.125471040606 0.989767909050 0.000000000000 -vt 0.110437445343 0.990312933922 0.000000000000 -vt 0.276588261127 0.979046463966 0.000000000000 -vt 0.273934006691 0.990138053894 0.000000000000 -vt 0.150033578277 0.985471129417 0.000000000000 -vt 0.176784589887 0.975747346878 0.000000000000 -vt 0.276720821857 0.986530065536 0.000000000000 -vt 0.022495752200 0.890904963017 0.000000000000 -vt 0.891464889050 0.306228846312 0.000000000000 -vt 0.904646217823 0.305932313204 0.000000000000 -vt 0.893834292889 0.301968216896 0.000000000000 -vt 0.904706299305 0.304305553436 0.000000000000 -vt 0.921183407307 0.310902148485 0.000000000000 -vt 0.906808555126 0.304849773645 0.000000000000 -vt 0.921672403812 0.309491783381 0.000000000000 -vt 0.938244044781 0.337644517422 0.000000000000 -vt 0.005772059783 0.892303645611 0.000000000000 -vt 0.024704044685 0.895432829857 0.000000000000 -vt 0.004067962989 0.897250592709 0.000000000000 -vt 0.023151105270 0.902699828148 0.000000000000 -vt 0.006364827976 0.903177917004 0.000000000000 -vt 0.019447928295 0.907367289066 0.000000000000 -vt 0.011597758159 0.909153997898 0.000000000000 -vt 0.018155282363 0.909749448299 0.000000000000 -vt 0.289794445038 0.979737758636 0.000000000000 -vt 0.289097309113 0.986868619919 0.000000000000 -vt 0.108699530363 0.986913800240 0.000000000000 -vt 0.923338353634 0.310172647238 0.000000000000 -vt 0.947028934956 0.322753190994 0.000000000000 -vt 0.017324453220 0.921973764896 0.000000000000 -vt 0.107475332916 0.990945875645 0.000000000000 -vt 0.012956982478 0.921561121941 0.000000000000 -vt 0.109573453665 0.884426295757 0.000000000000 -vt 0.020662194118 0.973094761372 0.000000000000 -vt 0.018618410453 0.972752928734 0.000000000000 -vt 0.963379323483 0.338597148657 0.000000000000 -vt 0.020546024665 0.981108963490 0.000000000000 -vt 0.018002038822 0.980931103230 0.000000000000 -vt 0.135590508580 0.867567420006 0.000000000000 -vt 0.106516152620 0.878543734550 0.000000000000 -vt 0.131759136915 0.862308800220 0.000000000000 -vt 0.101919859648 0.872579514980 0.000000000000 -vt 0.127446323633 0.855293273926 0.000000000000 -vt 0.106182672083 0.886078596115 0.000000000000 -vt 0.102917589247 0.880396783352 0.000000000000 -vt 0.099388279021 0.873800635338 0.000000000000 -vt 0.137774154544 0.865794837475 0.000000000000 -vt 0.134449630976 0.860945940018 0.000000000000 -vt 0.129994958639 0.853814363480 0.000000000000 -vt 0.098041392863 0.867455244064 0.000000000000 -vt 0.123956769705 0.849580526352 0.000000000000 -vt 0.096607387066 0.868979096413 0.000000000000 -vt 0.126601263881 0.848501205444 0.000000000000 -vt 0.095606558025 0.864713788033 0.000000000000 -vt 0.123283371329 0.847612500191 0.000000000000 -vt 0.093895524740 0.865760445595 0.000000000000 -vt 0.125174984336 0.846612274647 0.000000000000 -vt 0.090208120644 0.853443682194 0.000000000000 -vt 0.088275067508 0.855292141438 0.000000000000 -vt 0.116189479828 0.837091147900 0.000000000000 -vt 0.119325831532 0.836723268032 0.000000000000 -vt 0.133553490043 0.788949906826 0.000000000000 -vt 0.293736696243 0.986775279045 0.000000000000 -vt 0.295940577984 0.980653762817 0.000000000000 -vt 0.340545475483 0.984447240829 0.000000000000 -vt 0.340072214603 0.986525893211 0.000000000000 -vt 0.950552880764 0.345313966274 0.000000000000 -vt 0.967208921909 0.344859838486 0.000000000000 -vt 0.950094163418 0.353987187147 0.000000000000 -vt 0.933797061443 0.363659620285 0.000000000000 -vt 0.136295691133 0.788761913776 0.000000000000 -vt 0.138059511781 0.780847370625 0.000000000000 -vt 0.130408823490 0.777872502804 0.000000000000 -vt 0.131355047226 0.775953590870 0.000000000000 -vt 0.138569056988 0.778319716454 0.000000000000 -vt 0.118060231209 0.785308957100 0.000000000000 -vt 0.896019995213 0.384664356709 0.000000000000 -vt 0.115173012018 0.774169325829 0.000000000000 -vt 0.898356497288 0.351344764233 0.000000000000 -vt 0.096679173410 0.785911738873 0.000000000000 -vt 0.095730684698 0.772729396820 0.000000000000 -vt 0.104705169797 0.831313431263 0.000000000000 -vt 0.902008712292 0.319425404072 0.000000000000 -vt 0.086956694722 0.837567865849 0.000000000000 -vt 0.082478508353 0.790962874889 0.000000000000 -vt 0.833729565144 0.320394694805 0.000000000000 -vt 0.348657131195 0.984760761261 0.000000000000 -vt 0.081306569278 0.775940597057 0.000000000000 -vt 0.089978247881 0.773647964001 0.000000000000 -vt 0.829791605473 0.309479862452 0.000000000000 -vt 0.816609799862 0.333315908909 0.000000000000 -vt 0.807817518711 0.321131646633 0.000000000000 -vt 0.797316968441 0.333731085062 0.000000000000 -vt 0.795922100544 0.331054210663 0.000000000000 -vt 0.852600395679 0.366287618876 0.000000000000 -vt 0.888158023357 0.389725148678 0.000000000000 -vt 0.891561090946 0.383528649807 0.000000000000 -vt 0.892443001270 0.390044867992 0.000000000000 -vt 0.890115559101 0.403733402491 0.000000000000 -vt 0.893740594387 0.402232736349 0.000000000000 -vt 0.889661490917 0.409355312586 0.000000000000 -vt 0.859144628048 0.413082540035 0.000000000000 -vt 0.889299809933 0.416188776493 0.000000000000 -vt 0.860674321651 0.420680373907 0.000000000000 -vt 0.890587747097 0.423362225294 0.000000000000 -vt 0.861845076084 0.428339481354 0.000000000000 -vt 0.893469750881 0.431529492140 0.000000000000 -vt 0.863975346088 0.435634076595 0.000000000000 -vt 0.892712771893 0.409693717957 0.000000000000 -vt 0.893171131611 0.415372341871 0.000000000000 -vt 0.894341528416 0.422278076410 0.000000000000 -vt 0.895548760891 0.430168658495 0.000000000000 -vt 0.856991708279 0.413939237595 0.000000000000 -vt 0.858568608761 0.420849025249 0.000000000000 -vt 0.860028803349 0.428554058075 0.000000000000 -vt 0.861705243587 0.435540854931 0.000000000000 -vt 0.862937510014 0.448144823313 0.000000000000 -vt 0.865016877651 0.448156058788 0.000000000000 -vt 0.894014537334 0.443118661642 0.000000000000 -vt 0.896675527096 0.441695034504 0.000000000000 -vt 0.942015469074 0.465249389410 0.000000000000 -vt 0.938968360424 0.467184603214 0.000000000000 -vt 0.947230279446 0.471932232380 0.000000000000 -vt 0.929851353168 0.479779750109 0.000000000000 -vt 0.884821474552 0.455685496330 0.000000000000 -vt 0.911414802074 0.493092268705 0.000000000000 -vt 0.871183216572 0.461694657803 0.000000000000 -vt 0.860978066921 0.452166974545 0.000000000000 -vt 0.943686783314 0.478628307581 0.000000000000 -vt 0.933102667332 0.492131799459 0.000000000000 -vt 0.919620096684 0.505386710167 0.000000000000 -vt 0.891063272953 0.499169915915 0.000000000000 -vt 0.916852533817 0.507224857807 0.000000000000 -vt 0.908044636250 0.511230826378 0.000000000000 -vt 0.888901054859 0.516245007515 0.000000000000 -vt 0.869810879230 0.502536654472 0.000000000000 -vt 0.873295843601 0.517087996006 0.000000000000 -vt 0.852177441120 0.511175870895 0.000000000000 -vt 0.852176964283 0.514577090740 0.000000000000 -vt 0.850538194180 0.510758638382 0.000000000000 -vt 0.846698939800 0.494376987219 0.000000000000 -vt 0.847678959370 0.512833237648 0.000000000000 -vt 0.836011469364 0.506721198559 0.000000000000 -vt 0.830273568630 0.488239735365 0.000000000000 -vt 0.829936563969 0.486338347197 0.000000000000 -vt 0.858301818371 0.452152788639 0.000000000000 -vt 0.827840387821 0.498115986586 0.000000000000 -vt 0.829935252666 0.487876564264 0.000000000000 -vt 0.823986113071 0.491719275713 0.000000000000 -vt 0.069046996534 0.797405838966 0.000000000000 -vt 0.063239946961 0.785030543804 0.000000000000 -vt 0.056414369494 0.807498395443 0.000000000000 -vt 0.050693791360 0.794903695583 0.000000000000 -vt 0.038561563939 0.813347876072 0.000000000000 -vt 0.035990972072 0.810181796551 0.000000000000 -vt 0.047508850694 0.830956161022 0.000000000000 -vt 0.037681039423 0.814844489098 0.000000000000 -vt 0.029368514195 0.826868057251 0.000000000000 -vt 0.033771704882 0.815734088421 0.000000000000 -vt 0.038801524788 0.845296800137 0.000000000000 -vt 0.029519105330 0.846085309982 0.000000000000 -vt 0.027892099693 0.839723408222 0.000000000000 -vt 0.084708891809 0.852553844452 0.000000000000 -vt 0.083767443895 0.854980945587 0.000000000000 -vt 0.037650745362 0.847761273384 0.000000000000 -vt 0.114381492138 0.771946310997 0.000000000000 -vt 0.094816014171 0.771821796894 0.000000000000 -vt 0.080136142671 0.774619162083 0.000000000000 -vt 0.090211994946 0.772520661354 0.000000000000 -vt 0.095953144133 0.783221781254 0.000000000000 -vt 0.062365397811 0.784237205982 0.000000000000 -vt 0.049735300243 0.794033586979 0.000000000000 -vt 0.035117056221 0.810181081295 0.000000000000 -vt 0.028672711924 0.846871018410 0.000000000000 -vt 0.036163691431 0.812595427036 0.000000000000 -vt 0.032508853823 0.815019369125 0.000000000000 -vt 0.035413723439 0.813524901867 0.000000000000 -vt 0.028211543337 0.827950716019 0.000000000000 -vt 0.026609050110 0.839356005192 0.000000000000 -vt 0.896258294582 0.381265163422 0.000000000000 -vt 0.934112012386 0.361818969250 0.000000000000 -vt 0.059123776853 0.925175607204 0.000000000000 -vt 0.055362485349 0.926216900349 0.000000000000 -vt 0.054541967809 0.924610912800 0.000000000000 -vt 0.057503841817 0.922102153301 0.000000000000 -vt 0.059521101415 0.928506195545 0.000000000000 -vt 0.055455230176 0.928037106991 0.000000000000 -vt 0.058347843587 0.931667983532 0.000000000000 -vt 0.054807446897 0.929809391499 0.000000000000 -vt 0.056133113801 0.934393584728 0.000000000000 -vt 0.053610645235 0.931369364262 0.000000000000 -vt 0.053249321878 0.936173141003 0.000000000000 -vt 0.051895163953 0.932276666164 0.000000000000 -vt 0.049887977540 0.936500608921 0.000000000000 -vt 0.050015471876 0.932548344135 0.000000000000 -vt 0.046488307416 0.935653746128 0.000000000000 -vt 0.048176728189 0.932161509991 0.000000000000 -vt 0.043682835996 0.933717668056 0.000000000000 -vt 0.046699486673 0.931114256382 0.000000000000 -vt 0.042096994817 0.930674016476 0.000000000000 -vt 0.045871280134 0.929518997669 0.000000000000 -vt 0.041774652898 0.927204310894 0.000000000000 -vt 0.045793555677 0.927666127682 0.000000000000 -vt 0.042907558382 0.923894703388 0.000000000000 -vt 0.046437762678 0.925861775875 0.000000000000 -vt 0.045091055334 0.921195805073 0.000000000000 -vt 0.047651670873 0.924327433109 0.000000000000 -vt 0.048192583025 0.919690430164 0.000000000000 -vt 0.049426577985 0.923481881618 0.000000000000 -vt 0.051677010953 0.919228494167 0.000000000000 -vt 0.051336131990 0.923179805279 0.000000000000 -vt 0.054966412485 0.919925153255 0.000000000000 -vt 0.053134106100 0.923531472683 0.000000000000 -vt 0.063366554677 0.923810899258 0.000000000000 -vt 0.060973726213 0.919329464436 0.000000000000 -vt 0.064595483243 0.929011166096 0.000000000000 -vt 0.062306247652 0.933849632740 0.000000000000 -vt 0.059110067785 0.937792122364 0.000000000000 -vt 0.054868541658 0.941029012203 0.000000000000 -vt 0.049543462694 0.940982162952 0.000000000000 -vt 0.044648133218 0.939702689648 0.000000000000 -vt 0.040030620992 0.937077343464 0.000000000000 -vt 0.037820480764 0.932063996792 0.000000000000 -vt 0.036892317235 0.926711142063 0.000000000000 -vt 0.038925252855 0.921679198742 0.000000000000 -vt 0.042036972940 0.917214572430 0.000000000000 -vt 0.046976409853 0.915347874165 0.000000000000 -vt 0.051998518407 0.914744794369 0.000000000000 -vt 0.057310722768 0.915426671505 0.000000000000 -vt 0.067497454584 0.921644866467 0.000000000000 -vt 0.065058015287 0.917089760303 0.000000000000 -vt 0.069694779813 0.926195323467 0.000000000000 -vt 0.065975569189 0.936767637730 0.000000000000 -vt 0.062733851373 0.940771758556 0.000000000000 -vt 0.059423707426 0.944580018520 0.000000000000 -vt 0.048389576375 0.945518910885 0.000000000000 -vt 0.043406806886 0.944201171398 0.000000000000 -vt 0.038586281240 0.942701995373 0.000000000000 -vt 0.033321164548 0.933438599110 0.000000000000 -vt 0.031816206872 0.928624808788 0.000000000000 -vt 0.034770034254 0.919423639774 0.000000000000 -vt 0.037123106420 0.914970576763 0.000000000000 -vt 0.046392939985 0.910692512989 0.000000000000 -vt 0.051504157484 0.910091817379 0.000000000000 -vt 0.056533597410 0.909688174725 0.000000000000 -vt 0.071821056306 0.919187366962 0.000000000000 -vt 0.069497846067 0.914850890636 0.000000000000 -vt 0.074104093015 0.923345625401 0.000000000000 -vt 0.069763801992 0.939998447895 0.000000000000 -vt 0.066682241857 0.943804800510 0.000000000000 -vt 0.063756071031 0.947524607182 0.000000000000 -vt 0.046995721757 0.950295627117 0.000000000000 -vt 0.042247436941 0.949036777020 0.000000000000 -vt 0.037652872503 0.947865664959 0.000000000000 -vt 0.028527699411 0.934890091419 0.000000000000 -vt 0.027052603662 0.930507719517 0.000000000000 -vt 0.030363760889 0.917036354542 0.000000000000 -vt 0.032438538969 0.912907421589 0.000000000000 -vt 0.045932315290 0.905737102032 0.000000000000 -vt 0.050800107419 0.905163943768 0.000000000000 -vt 0.055495165288 0.904551923275 0.000000000000 -vt 0.050987325609 0.924352467060 0.000000000000 -vt 0.048744998872 0.925625741482 0.000000000000 -vt 0.048258863389 0.925050437450 0.000000000000 -vt 0.049704097211 0.924391329288 0.000000000000 -vt 0.054107807577 0.926788032055 0.000000000000 -vt 0.051701687276 0.929121911526 0.000000000000 -vt 0.050647579134 0.927882850170 0.000000000000 -vt 0.053451858461 0.925569355488 0.000000000000 -vt 0.052362285554 0.924720108509 0.000000000000 -vt 0.049598239362 0.926641643047 0.000000000000 -vt 0.054247222841 0.928189814091 0.000000000000 -vt 0.052564702928 0.930132806301 0.000000000000 -vt 0.053045056760 0.930693566799 0.000000000000 -vt 0.053973041475 0.929413259029 0.000000000000 -vt 0.050350688398 0.931418359280 0.000000000000 -vt 0.051625333726 0.931378662586 0.000000000000 -vt 0.048955641687 0.931039512157 0.000000000000 -vt 0.047835491598 0.930190026760 0.000000000000 -vt 0.047166489065 0.928965747356 0.000000000000 -vt 0.047026477754 0.927548825741 0.000000000000 -vt 0.047300122678 0.926310837269 0.000000000000 -vt 0.076263017952 0.889852464199 0.000000000000 -vt 0.072937078774 0.890983402729 0.000000000000 -vt 0.072223909199 0.886963069439 0.000000000000 -vt 0.073955483735 0.886285126209 0.000000000000 -vt 0.078647918999 0.887252748013 0.000000000000 -vt 0.075236566365 0.884860932827 0.000000000000 -vt 0.080082006752 0.883868515491 0.000000000000 -vt 0.075974173844 0.882985889912 0.000000000000 -vt 0.080343849957 0.880316436291 0.000000000000 -vt 0.076127000153 0.880949914455 0.000000000000 -vt 0.078979976475 0.877020061016 0.000000000000 -vt 0.075315542519 0.879069387913 0.000000000000 -vt 0.076549418271 0.874237835407 0.000000000000 -vt 0.074006743729 0.877511203289 0.000000000000 -vt 0.073425479233 0.872460305691 0.000000000000 -vt 0.072319932282 0.876525342464 0.000000000000 -vt 0.069821424782 0.872302711010 0.000000000000 -vt 0.070436544716 0.876380264759 0.000000000000 -vt 0.066397853196 0.873569548130 0.000000000000 -vt 0.068679399788 0.877089798450 0.000000000000 -vt 0.063854344189 0.876202642918 0.000000000000 -vt 0.067366369069 0.878527104855 0.000000000000 -vt 0.062428124249 0.879545271397 0.000000000000 -vt 0.066652543843 0.880400240421 0.000000000000 -vt 0.062527008355 0.883167207241 0.000000000000 -vt 0.066598244011 0.882463753223 0.000000000000 -vt 0.063823170960 0.886639058590 0.000000000000 -vt 0.067381329834 0.884392201900 0.000000000000 -vt 0.066064722836 0.889388978481 0.000000000000 -vt 0.068642385304 0.885931313038 0.000000000000 -vt 0.069291241467 0.890806376934 0.000000000000 -vt 0.070335276425 0.886830031872 0.000000000000 -vt 0.079105265439 0.894360721111 0.000000000000 -vt 0.073614127934 0.895603239536 0.000000000000 -vt 0.082558877766 0.889905154705 0.000000000000 -vt 0.084692724049 0.885016143322 0.000000000000 -vt 0.085654027760 0.879498064518 0.000000000000 -vt 0.083038873971 0.874549567699 0.000000000000 -vt 0.079515941441 0.870571315289 0.000000000000 -vt 0.074898667634 0.867442429066 0.000000000000 -vt 0.069151528180 0.867639601231 0.000000000000 -vt 0.063656993210 0.869233548641 0.000000000000 -vt 0.059899874032 0.873542368412 0.000000000000 -vt 0.057234056294 0.878605186939 0.000000000000 -vt 0.057885952294 0.884120523930 0.000000000000 -vt 0.059755094349 0.889095604420 0.000000000000 -vt 0.062920100987 0.893733680248 0.000000000000 -vt 0.068280227482 0.895384490490 0.000000000000 -vt 0.078785724938 0.900479376316 0.000000000000 -vt 0.073472566903 0.900497257710 0.000000000000 -vt 0.087039537728 0.891929209232 0.000000000000 -vt 0.089219875634 0.886968076229 0.000000000000 -vt 0.091177947819 0.882038056850 0.000000000000 -vt 0.086754925549 0.871306598186 0.000000000000 -vt 0.083158977330 0.867264211178 0.000000000000 -vt 0.079480238259 0.863445341587 0.000000000000 -vt 0.068381793797 0.862759649754 0.000000000000 -vt 0.063137896359 0.863549411297 0.000000000000 -vt 0.055807478726 0.870739161968 0.000000000000 -vt 0.052770502865 0.875079214573 0.000000000000 -vt 0.053255327046 0.885821878910 0.000000000000 -vt 0.055160112679 0.890882432461 0.000000000000 -vt 0.057204969227 0.895774066448 0.000000000000 -vt 0.068046040833 0.900283634663 0.000000000000 -vt 0.078120060265 0.905958473682 0.000000000000 -vt 0.073138959706 0.905713617802 0.000000000000 -vt 0.091880030930 0.893913924694 0.000000000000 -vt 0.093954570591 0.889196693897 0.000000000000 -vt 0.096018739045 0.884667575359 0.000000000000 -vt 0.090575344861 0.867730081081 0.000000000000 -vt 0.087147958577 0.863881051540 0.000000000000 -vt 0.083878643811 0.860125720501 0.000000000000 -vt 0.067553706467 0.857561290264 0.000000000000 -vt 0.062731571496 0.858179271221 0.000000000000 -vt 0.051463313401 0.867761790752 0.000000000000 -vt 0.048594601452 0.871683299541 0.000000000000 -vt 0.048404522240 0.887782871723 0.000000000000 -vt 0.050217278302 0.892602741718 0.000000000000 -vt 0.051908619702 0.897282183170 0.000000000000 -vt 0.067971713841 0.905510962009 0.000000000000 -vt 0.069196112454 0.884744703770 0.000000000000 -vt 0.068222053349 0.883839309216 0.000000000000 -vt 0.067552991211 0.882304251194 0.000000000000 -vt 0.068320401013 0.882175028324 0.000000000000 -vt 0.073343880475 0.884937107563 0.000000000000 -vt 0.071995504200 0.885450780392 0.000000000000 -vt 0.071372933686 0.881675302982 0.000000000000 -vt 0.073059923947 0.881411254406 0.000000000000 -vt 0.070542402565 0.885377347469 0.000000000000 -vt 0.069689460099 0.881946742535 0.000000000000 -vt 0.074404723942 0.883906543255 0.000000000000 -vt 0.074438758194 0.881199419498 0.000000000000 -vt 0.075204439461 0.881086766720 0.000000000000 -vt 0.075038559735 0.882739722729 0.000000000000 -vt 0.073512084782 0.878659069538 0.000000000000 -vt 0.074500329792 0.879579484463 0.000000000000 -vt 0.072161979973 0.877989232540 0.000000000000 -vt 0.070704765618 0.877902209759 0.000000000000 -vt 0.069342859089 0.878422200680 0.000000000000 -vt 0.068271823227 0.879460871220 0.000000000000 -vt 0.067647464573 0.880636036396 0.000000000000 -vt 0.069012485445 0.932736814022 0.000000000000 -vt 0.053315483034 0.946615636349 0.000000000000 -vt 0.034739337862 0.938278734684 0.000000000000 -vt 0.032324932516 0.923826873302 0.000000000000 -vt 0.041412316263 0.911473333836 0.000000000000 -vt 0.062483809888 0.912739932537 0.000000000000 -vt 0.072793565691 0.936362326145 0.000000000000 -vt 0.051563642919 0.951559722424 0.000000000000 -vt 0.029731415212 0.939354598522 0.000000000000 -vt 0.028038166463 0.921029269695 0.000000000000 -vt 0.041223250329 0.906235873699 0.000000000000 -vt 0.067299149930 0.910646736622 0.000000000000 -vt 0.084724672139 0.896705806255 0.000000000000 -vt 0.090130694211 0.875394165516 0.000000000000 -vt 0.073611505330 0.861880958080 0.000000000000 -vt 0.058759339154 0.866340816021 0.000000000000 -vt 0.051577635109 0.880795300007 0.000000000000 -vt 0.062752433121 0.899852573872 0.000000000000 -vt 0.089935369790 0.898496687412 0.000000000000 -vt 0.093930847943 0.871406018734 0.000000000000 -vt 0.072329230607 0.856650412083 0.000000000000 -vt 0.054085560143 0.863671362400 0.000000000000 -vt 0.046596772969 0.883146226406 0.000000000000 -vt 0.062987215817 0.905366241932 0.000000000000 -vt 0.724434196949 0.690520286560 0.000000000000 -vt 0.714673578739 0.670199394226 0.000000000000 -vt 0.738192379475 0.658733546734 0.000000000000 -vt 0.749425828457 0.679554581642 0.000000000000 -vt 0.766880452633 0.648001551628 0.000000000000 -vt 0.778476417065 0.667455196381 0.000000000000 -vt 0.658123552799 0.561918437481 0.000000000000 -vt 0.681013524532 0.545336842537 0.000000000000 -vt 0.691574394703 0.565115392208 0.000000000000 -vt 0.668605864048 0.578333139420 0.000000000000 -vt 0.678273379803 0.596119463444 0.000000000000 -vt 0.700517117977 0.582515180111 0.000000000000 -vt 0.708820402622 0.600191891193 0.000000000000 -vt 0.686416089535 0.614063024521 0.000000000000 -vt 0.693850934505 0.631938755512 0.000000000000 -vt 0.717175424099 0.619349181652 0.000000000000 -vt 0.726578891277 0.638749718666 0.000000000000 -vt 0.702835142612 0.650949716568 0.000000000000 -vt 0.727393448353 0.566789627075 0.000000000000 -vt 0.737516939640 0.584310531616 0.000000000000 -vt 0.746533215046 0.605367720127 0.000000000000 -vt 0.755558550358 0.627303957939 0.000000000000 -vt 0.717193305492 0.550311207771 0.000000000000 -vt 0.707122027874 0.527874290943 0.000000000000 -vt 0.648476541042 0.550091445446 0.000000000000 -vt 0.670800983906 0.526029586792 0.000000000000 -vt 0.796826541424 0.635315418243 0.000000000000 -vt 0.810074508190 0.653544664383 0.000000000000 -vt 0.828041613102 0.628299355507 0.000000000000 -vt 0.837326347828 0.640173137188 0.000000000000 -vt 0.784561932087 0.614920377731 0.000000000000 -vt 0.774542272091 0.593422353268 0.000000000000 -vt 0.802680790424 0.583606719971 0.000000000000 -vt 0.815609514713 0.603868663311 0.000000000000 -vt 0.744441092014 0.531438291073 0.000000000000 -vt 0.776179373264 0.512288391590 0.000000000000 -vt 0.783609092236 0.532737612724 0.000000000000 -vt 0.755129158497 0.549743592739 0.000000000000 -vt 0.697984158993 0.500902295113 0.000000000000 -vt 0.737360656261 0.508947730064 0.000000000000 -vt 0.730104506016 0.483820885420 0.000000000000 -vt 0.765154659748 0.571034491062 0.000000000000 -vt 0.792746603489 0.558559775352 0.000000000000 -vt 0.768725693226 0.492010682821 0.000000000000 -vt 0.757663547993 0.472875863314 0.000000000000 -vt 0.725043118000 0.693508327007 0.000000000000 -vt 0.750067889690 0.685739338398 0.000000000000 -vt 0.791203796864 0.399861633778 0.000000000000 -vt 0.779777586460 0.399193614721 0.000000000000 -vt 0.752974689007 0.710415661335 0.000000000000 -vt 0.804506599903 0.398513197899 0.000000000000 -vt 0.782004177570 0.452414214611 0.000000000000 -vt 0.780603945255 0.444166988134 0.000000000000 -vt 0.791876137257 0.443759024143 0.000000000000 -vt 0.793968260288 0.453128397465 0.000000000000 -vt 0.779418051243 0.435353308916 0.000000000000 -vt 0.778252422810 0.426639556885 0.000000000000 -vt 0.789694845676 0.427197962999 0.000000000000 -vt 0.790620148182 0.435532063246 0.000000000000 -vt 0.777533710003 0.418020188808 0.000000000000 -vt 0.777940571308 0.408807516098 0.000000000000 -vt 0.789442360401 0.409360051155 0.000000000000 -vt 0.789057195187 0.418372094631 0.000000000000 -vt 0.803890883923 0.427518129349 0.000000000000 -vt 0.804031312466 0.435820281506 0.000000000000 -vt 0.803060233593 0.417909622192 0.000000000000 -vt 0.802897393703 0.408120334148 0.000000000000 -vt 0.804555714130 0.443755626678 0.000000000000 -vt 0.807329356670 0.454006284475 0.000000000000 -vt 0.725099384785 0.716310918331 0.000000000000 -vt 0.779836833477 0.674231469631 0.000000000000 -vt 0.783605754375 0.697045505047 0.000000000000 -vt 0.818779408932 0.398010879755 0.000000000000 -vt 0.643724501133 0.545761525631 0.000000000000 -vt 0.628008902073 0.541231870651 0.000000000000 -vt 0.816486179829 0.407289743423 0.000000000000 -vt 0.643818080425 0.512760996819 0.000000000000 -vt 0.665438830853 0.521224975586 0.000000000000 -vt 0.815758764744 0.416817396879 0.000000000000 -vt 0.818642079830 0.444537609816 0.000000000000 -vt 0.817937195301 0.436300307512 0.000000000000 -vt 0.811494052410 0.658484101295 0.000000000000 -vt 0.816042482853 0.680989921093 0.000000000000 -vt 0.840249359608 0.645133495331 0.000000000000 -vt 0.822369277477 0.453545153141 0.000000000000 -vt 0.847676336765 0.654553532600 0.000000000000 -vt 0.848686635494 0.579840302467 0.000000000000 -vt 0.816775619984 0.426806628704 0.000000000000 -vt 0.821314275265 0.600943446159 0.000000000000 -vt 0.813257277012 0.578419387341 0.000000000000 -vt 0.838545382023 0.561789393425 0.000000000000 -vt 0.819137394428 0.502666831017 0.000000000000 -vt 0.823779404163 0.522105157375 0.000000000000 -vt 0.790229976177 0.529961049557 0.000000000000 -vt 0.781899273396 0.510464847088 0.000000000000 -vt 0.668055117130 0.483010739088 0.000000000000 -vt 0.692842900753 0.497021466494 0.000000000000 -vt 0.808572947979 0.481489390135 0.000000000000 -vt 0.704506456852 0.458266437054 0.000000000000 -vt 0.801172792912 0.554602205753 0.000000000000 -vt 0.830090582371 0.542637288570 0.000000000000 -vt 0.773884236813 0.490298360586 0.000000000000 -vt 0.726107180119 0.478320568800 0.000000000000 -vt 0.745716154575 0.441092967987 0.000000000000 -vt 0.753030359745 0.462626129389 0.000000000000 -vt 0.722523391247 0.691917836666 0.000000000000 -vt 0.749568045139 0.682414948940 0.000000000000 -vt 0.779008090496 0.670675337315 0.000000000000 -vt 0.667049825191 0.578830957413 0.000000000000 -vt 0.684892475605 0.614746153355 0.000000000000 -vt 0.676726400852 0.596634447575 0.000000000000 -vt 0.701373159885 0.652009308338 0.000000000000 -vt 0.692301928997 0.632841825485 0.000000000000 -vt 0.646996915340 0.549704909325 0.000000000000 -vt 0.667850673199 0.524221837521 0.000000000000 -vt 0.810716688633 0.655620336533 0.000000000000 -vt 0.839727461338 0.639870941639 0.000000000000 -vt 0.830280363560 0.627509713173 0.000000000000 -vt 0.818201720715 0.602329492569 0.000000000000 -vt 0.807740032673 0.580971300602 0.000000000000 -vt 0.786967098713 0.531335592270 0.000000000000 -vt 0.778827011585 0.511309623718 0.000000000000 -vt 0.695696294308 0.499585956335 0.000000000000 -vt 0.728171169758 0.480036228895 0.000000000000 -vt 0.796798646450 0.556795895100 0.000000000000 -vt 0.771090447903 0.491387873888 0.000000000000 -vt 0.755518972874 0.467876076698 0.000000000000 -vt 0.857891857624 0.600561559200 0.000000000000 -vt 0.832526981831 0.625968098640 0.000000000000 -vt 0.721892893314 0.690372586250 0.000000000000 -vt 0.713340461254 0.671590626240 0.000000000000 -vt 0.646686851978 0.550678908825 0.000000000000 -vt 0.656452476978 0.562453389168 0.000000000000 -vt 0.842236578465 0.638690054417 0.000000000000 -vt 0.764252245426 0.471054345369 0.000000000000 -vt 0.725051343441 0.691869199276 0.000000000000 -vt 0.646329224110 0.548061668873 0.000000000000 -vt 0.838410317898 0.642666935921 0.000000000000 -vt 0.759749114513 0.472487002611 0.000000000000 -# 6542 texture coords - -g Box001 -usemtl Material__283 -s 1 -f 18/3/1 17/4/2 1/1/3 -f 1/1/4 2/2/5 18/3/6 -f 19/6/7 18/3/8 2/2/9 -f 2/2/10 3/5/11 19/6/12 -f 20/8/13 19/6/14 3/5/15 -f 3/5/16 4/7/17 20/8/18 -f 21/11/19 20/12/20 4/9/21 -f 4/9/22 5/10/23 21/11/24 -f 22/14/25 21/11/26 5/10/27 -f 5/10/28 6/13/29 22/14/30 -f 23/16/31 22/14/32 6/13/33 -f 6/13/34 7/15/35 23/16/36 -f 24/18/37 23/16/38 7/15/39 -f 7/15/40 8/17/41 24/18/42 -f 25/20/43 24/18/44 8/17/45 -f 8/17/46 9/19/47 25/20/48 -f 26/22/49 25/20/50 9/19/51 -f 9/19/52 10/21/53 26/22/54 -f 27/24/55 26/22/56 10/21/57 -f 10/21/58 11/23/59 27/24/60 -f 28/26/61 27/24/62 11/23/63 -f 11/23/64 12/25/65 28/26/66 -f 29/28/67 28/26/68 12/25/69 -f 12/25/70 13/27/71 29/28/72 -f 30/30/73 29/28/74 13/27/75 -f 13/27/76 14/29/77 30/30/78 -f 31/32/79 30/30/80 14/29/81 -f 14/29/82 15/31/83 31/32/84 -f 32/34/85 31/32/86 15/31/87 -f 15/31/88 16/33/89 32/34/90 -f 17/4/91 32/34/92 16/33/93 -f 16/33/94 1/1/95 17/4/96 -f 65/37/97 67/38/98 68/35/99 -f 68/35/100 66/36/101 65/37/102 -f 67/38/103 69/40/104 70/39/105 -f 70/39/106 68/35/107 67/38/108 -f 69/40/109 71/42/110 72/41/111 -f 72/41/112 70/39/113 69/40/114 -f 71/45/115 73/46/116 74/43/117 -f 74/43/118 72/44/119 71/45/120 -f 73/46/121 75/48/122 76/47/123 -f 76/47/124 74/43/125 73/46/126 -f 75/48/127 77/50/128 78/49/129 -f 78/49/130 76/47/131 75/48/132 -f 77/50/133 79/52/134 80/51/135 -f 80/51/136 78/49/137 77/50/138 -f 79/52/139 81/54/140 82/53/141 -f 82/53/142 80/51/143 79/52/144 -f 81/54/145 83/56/146 84/55/147 -f 84/55/148 82/53/149 81/54/150 -f 83/56/151 85/58/152 86/57/153 -f 86/57/154 84/55/155 83/56/156 -f 85/58/157 87/60/158 88/59/159 -f 88/59/160 86/57/161 85/58/162 -f 87/60/163 89/62/164 90/61/165 -f 90/61/166 88/59/167 87/60/168 -f 89/62/169 91/64/170 92/63/171 -f 92/63/172 90/61/173 89/62/174 -f 91/64/175 93/66/176 94/65/177 -f 94/65/178 92/63/179 91/64/180 -f 93/66/181 95/68/182 96/67/183 -f 96/67/184 94/65/185 93/66/186 -f 95/68/187 65/37/188 66/36/189 -f 66/36/190 96/67/191 95/68/192 -f 50/71/193 49/72/194 33/69/195 -f 33/69/196 34/70/197 50/71/198 -f 51/74/199 50/71/200 34/70/201 -f 34/70/202 35/73/203 51/74/204 -f 52/76/205 51/74/206 35/73/207 -f 35/73/208 36/75/209 52/76/210 -f 53/79/211 52/80/212 36/77/213 -f 36/77/214 37/78/215 53/79/216 -f 54/82/217 53/79/218 37/78/219 -f 37/78/220 38/81/221 54/82/222 -f 55/84/223 54/82/224 38/81/225 -f 38/81/226 39/83/227 55/84/228 -f 56/86/229 55/84/230 39/83/231 -f 39/83/232 40/85/233 56/86/234 -f 57/88/235 56/86/236 40/85/237 -f 40/85/238 41/87/239 57/88/240 -f 58/90/241 57/88/242 41/87/243 -f 41/87/244 42/89/245 58/90/246 -f 59/92/247 58/90/248 42/89/249 -f 42/89/250 43/91/251 59/92/252 -f 60/94/253 59/92/254 43/91/255 -f 43/91/256 44/93/257 60/94/258 -f 61/96/259 60/94/260 44/93/261 -f 44/93/262 45/95/263 61/96/264 -f 62/98/265 61/96/266 45/95/267 -f 45/95/268 46/97/269 62/98/270 -f 63/100/271 62/98/272 46/97/273 -f 46/97/274 47/99/275 63/100/276 -f 64/102/277 63/100/278 47/99/279 -f 47/99/280 48/101/281 64/102/282 -f 49/72/283 64/102/284 48/101/285 -f 48/101/286 33/69/287 49/72/288 -f 66/36/289 68/35/290 34/70/291 -f 34/70/292 33/69/293 66/36/294 -f 67/38/295 65/37/296 17/4/297 -f 17/4/298 18/3/299 67/38/300 -f 68/35/301 70/39/302 35/73/303 -f 35/73/304 34/70/305 68/35/306 -f 69/40/307 67/38/308 18/3/309 -f 18/3/310 19/6/311 69/40/312 -f 70/39/313 72/41/314 36/75/315 -f 36/75/316 35/73/317 70/39/318 -f 71/42/319 69/40/320 19/6/321 -f 19/6/322 20/8/323 71/42/324 -f 72/44/325 74/43/326 37/78/327 -f 37/78/328 36/77/329 72/44/330 -f 73/46/331 71/45/332 20/12/333 -f 20/12/334 21/11/335 73/46/336 -f 74/43/337 76/47/338 38/81/339 -f 38/81/340 37/78/341 74/43/342 -f 75/48/343 73/46/344 21/11/345 -f 21/11/346 22/14/347 75/48/348 -f 76/47/349 78/49/350 39/83/351 -f 39/83/352 38/81/353 76/47/354 -f 77/50/355 75/48/356 22/14/357 -f 22/14/358 23/16/359 77/50/360 -f 78/49/361 80/51/362 40/85/363 -f 40/85/364 39/83/365 78/49/366 -f 79/52/367 77/50/368 23/16/369 -f 23/16/370 24/18/371 79/52/372 -f 80/51/373 82/53/374 41/87/375 -f 41/87/376 40/85/377 80/51/378 -f 81/54/379 79/52/380 24/18/381 -f 24/18/382 25/20/383 81/54/384 -f 82/53/385 84/55/386 42/89/387 -f 42/89/388 41/87/389 82/53/390 -f 83/56/391 81/54/392 25/20/393 -f 25/20/394 26/22/395 83/56/396 -f 84/55/397 86/57/398 43/91/399 -f 43/91/400 42/89/401 84/55/402 -f 85/58/403 83/56/404 26/22/405 -f 26/22/406 27/24/407 85/58/408 -f 86/57/409 88/59/410 44/93/411 -f 44/93/412 43/91/413 86/57/414 -f 87/60/415 85/58/416 27/24/417 -f 27/24/418 28/26/419 87/60/420 -f 88/59/421 90/61/422 45/95/423 -f 45/95/424 44/93/425 88/59/426 -f 89/62/427 87/60/428 28/26/429 -f 28/26/430 29/28/431 89/62/432 -f 90/61/433 92/63/434 46/97/435 -f 46/97/436 45/95/437 90/61/438 -f 91/64/439 89/62/440 29/28/441 -f 29/28/442 30/30/443 91/64/444 -f 92/63/445 94/65/446 47/99/447 -f 47/99/448 46/97/449 92/63/450 -f 93/66/451 91/64/452 30/30/453 -f 30/30/454 31/32/455 93/66/456 -f 94/65/457 96/67/458 48/101/459 -f 48/101/460 47/99/461 94/65/462 -f 95/68/463 93/66/464 31/32/465 -f 31/32/466 32/34/467 95/68/468 -f 96/67/469 66/36/470 33/69/471 -f 33/69/472 48/101/473 96/67/474 -f 65/37/475 95/68/476 32/34/477 -f 32/34/478 17/4/479 65/37/480 -f 188/103/481 158/104/482 108/105/483 -f 108/105/484 158/104/485 135/106/486 -f 99/107/487 190/108/488 114/109/489 -f 151/110/490 140/111/491 131/112/492 -f 142/113/493 133/114/494 149/115/495 -f 113/116/496 145/117/497 132/118/498 -f 109/119/499 121/120/500 181/121/501 -f 123/122/502 119/123/503 102/124/504 -f 177/125/505 130/126/506 141/127/507 -f 176/128/508 135/106/509 167/129/510 -f 138/130/511 143/131/512 111/132/513 -f 116/133/514 123/122/515 130/126/516 -f 104/134/517 150/135/518 183/136/519 -f 150/135/520 179/137/521 162/138/522 -f 120/139/523 189/140/524 153/141/525 -f 168/142/526 152/143/527 122/144/528 -f 152/143/529 161/145/530 122/144/531 -f 176/128/532 167/129/533 124/146/534 -f 192/147/535 185/148/536 97/149/537 -f 192/147/538 100/150/539 185/148/540 -f 134/151/541 163/152/542 101/153/543 -f 175/154/544 180/155/545 127/156/546 -f 143/131/547 181/121/548 184/157/549 -f 169/158/550 103/159/551 174/160/552 -f 165/161/553 145/117/554 113/116/555 -f 120/139/556 153/141/557 159/162/558 -f 142/113/559 114/109/560 133/114/561 -f 115/163/562 128/164/563 172/165/564 -f 115/163/565 172/165/566 117/166/567 -f 107/167/568 125/168/569 166/169/570 -f 177/125/571 116/133/572 130/126/573 -f 125/168/574 117/166/575 166/169/576 -f 166/169/577 182/170/578 157/171/579 -f 104/134/580 183/136/581 118/172/582 -f 131/112/583 155/173/584 106/174/585 -f 100/150/586 121/120/587 109/119/588 -f 162/138/589 189/140/590 120/139/591 -f 175/154/592 106/174/593 180/155/594 -f 121/120/595 136/175/596 181/121/597 -f 122/144/598 128/164/599 170/176/600 -f 103/159/601 123/122/602 116/133/603 -f 181/121/604 136/175/605 123/122/606 -f 99/107/607 186/177/608 190/108/609 -f 122/144/610 144/178/611 128/164/612 -f 115/163/613 117/166/614 125/168/615 -f 129/179/616 126/180/617 191/181/618 -f 109/119/619 181/121/620 143/131/621 -f 127/156/622 112/182/623 137/183/624 -f 159/162/625 153/141/626 112/182/627 -f 128/164/628 144/178/629 164/184/630 -f 128/164/631 164/184/632 172/165/633 -f 129/179/634 173/185/635 126/180/636 -f 188/103/637 185/148/638 158/104/639 -f 123/122/640 102/124/641 130/126/642 -f 141/127/643 130/126/644 156/186/645 -f 186/177/646 175/154/647 190/108/648 -f 175/154/649 127/156/650 137/183/651 -f 130/126/652 102/124/653 156/186/654 -f 110/187/655 133/114/656 114/109/657 -f 133/114/658 134/151/659 149/115/660 -f 97/149/661 185/148/662 188/103/663 -f 147/188/664 152/143/665 168/142/666 -f 190/108/667 175/154/668 137/183/669 -f 133/114/670 110/187/671 178/189/672 -f 135/106/673 154/190/674 167/129/675 -f 138/130/676 171/191/677 104/134/678 -f 136/175/679 119/123/680 123/122/681 -f 139/192/682 119/123/683 136/175/684 -f 137/183/685 112/182/686 134/151/687 -f 133/114/688 178/189/689 134/151/690 -f 138/130/691 104/134/692 135/106/693 -f 191/181/694 126/180/695 138/130/696 -f 112/182/697 163/152/698 134/151/699 -f 112/182/700 98/193/701 165/161/702 -f 139/192/703 136/175/704 121/120/705 -f 100/150/706 139/192/707 121/120/708 -f 131/112/709 140/111/710 155/173/711 -f 154/190/712 118/172/713 167/129/714 -f 141/127/715 156/186/716 98/193/717 -f 153/141/718 98/193/719 112/182/720 -f 166/169/721 117/166/722 182/170/723 -f 117/166/724 160/194/725 182/170/726 -f 126/180/727 143/131/728 138/130/729 -f 173/185/730 143/131/731 126/180/732 -f 144/178/733 146/195/734 164/184/735 -f 161/145/736 176/128/737 124/146/738 -f 98/193/739 145/117/740 165/161/741 -f 98/193/742 132/118/743 145/117/744 -f 161/145/745 124/146/746 144/178/747 -f 124/146/748 140/111/749 146/195/750 -f 97/149/751 152/143/752 147/188/753 -f 177/125/754 148/196/755 116/133/756 -f 103/159/757 116/133/758 174/160/759 -f 134/151/760 101/153/761 149/115/762 -f 169/158/763 179/137/764 150/135/765 -f 138/130/766 111/132/767 171/191/768 -f 140/111/769 151/110/770 146/195/771 -f 146/195/772 151/110/773 164/184/774 -f 152/143/775 97/149/776 188/103/777 -f 188/103/778 108/105/779 152/143/780 -f 105/197/781 141/127/782 153/141/783 -f 141/127/784 98/193/785 153/141/786 -f 135/106/787 104/134/788 154/190/789 -f 154/190/790 104/134/791 118/172/792 -f 122/144/793 161/145/794 144/178/795 -f 155/173/796 118/172/797 106/174/798 -f 167/129/799 118/172/800 155/173/801 -f 98/193/802 156/186/803 132/118/804 -f 142/113/805 149/115/806 157/171/807 -f 129/179/808 191/181/809 158/104/810 -f 158/104/811 185/148/812 129/179/813 -f 120/139/814 159/162/815 127/156/816 -f 127/156/817 159/162/818 112/182/819 -f 160/194/820 114/109/821 142/113/822 -f 99/107/823 114/109/824 160/194/825 -f 108/105/826 161/145/827 152/143/828 -f 176/128/829 108/105/830 135/106/831 -f 118/172/832 162/138/833 106/174/834 -f 106/174/835 162/138/836 120/139/837 -f 165/161/838 113/116/839 163/152/840 -f 164/184/841 186/177/842 99/107/843 -f 164/184/844 99/107/845 172/165/846 -f 112/182/847 165/161/848 163/152/849 -f 167/129/850 155/173/851 140/111/852 -f 124/146/853 167/129/854 140/111/855 -f 100/150/856 109/119/857 185/148/858 -f 109/119/859 143/131/860 173/185/861 -f 189/140/862 105/197/863 153/141/864 -f 170/176/865 125/168/866 107/167/867 -f 172/165/868 99/107/869 160/194/870 -f 172/165/871 160/194/872 117/166/873 -f 171/191/874 111/132/875 169/158/876 -f 184/157/877 103/159/878 169/158/879 -f 187/198/880 168/142/881 122/144/882 -f 147/188/883 168/142/884 187/198/885 -f 171/191/886 150/135/887 104/134/888 -f 171/191/889 169/158/890 150/135/891 -f 109/119/892 173/185/893 185/148/894 -f 185/148/895 173/185/896 129/179/897 -f 169/158/898 174/160/899 179/137/900 -f 148/196/901 174/160/902 116/133/903 -f 131/112/904 175/154/905 186/177/906 -f 131/112/907 106/174/908 175/154/909 -f 161/145/910 108/105/911 176/128/912 -f 105/197/913 177/125/914 141/127/915 -f 177/125/916 105/197/917 189/140/918 -f 178/189/919 137/183/920 134/151/921 -f 110/187/922 137/183/923 178/189/924 -f 179/137/925 174/160/926 148/196/927 -f 179/137/928 148/196/929 162/138/930 -f 180/155/931 120/139/932 127/156/933 -f 106/174/934 120/139/935 180/155/936 -f 103/159/937 181/121/938 123/122/939 -f 184/157/940 181/121/941 103/159/942 -f 182/170/943 142/113/944 157/171/945 -f 160/194/946 142/113/947 182/170/948 -f 183/136/949 150/135/950 162/138/951 -f 118/172/952 183/136/953 162/138/954 -f 111/132/955 184/157/956 169/158/957 -f 143/131/958 184/157/959 111/132/960 -f 164/184/961 151/110/962 186/177/963 -f 151/110/964 131/112/965 186/177/966 -f 149/115/967 101/153/968 163/152/969 -f 163/152/970 113/116/971 149/115/972 -f 187/198/973 122/144/974 170/176/975 -f 189/140/976 162/138/977 148/196/978 -f 189/140/979 148/196/980 177/125/981 -f 190/108/982 137/183/983 110/187/984 -f 190/108/985 110/187/986 114/109/987 -f 191/181/988 138/130/989 135/106/990 -f 158/104/991 191/181/992 135/106/993 -f 125/168/994 170/176/995 128/164/996 -f 128/164/997 115/163/998 125/168/999 -f 124/146/1000 146/195/1001 144/178/1002 -s 2 -f 207/213/1003 205/214/1004 193/199/1005 -f 193/199/1006 195/201/1007 207/213/1008 -f 206/215/1009 208/216/1010 196/207/1011 -f 196/207/1012 194/206/1013 206/215/1014 -f 205/214/1015 215/217/1016 203/200/1017 -f 203/200/1018 193/199/1019 205/214/1020 -f 209/218/1021 207/213/1022 195/201/1023 -f 195/201/1024 197/202/1025 209/218/1026 -f 208/216/1027 210/219/1028 198/208/1029 -f 198/208/1030 196/207/1031 208/216/1032 -f 213/221/1033 201/222/1034 253/211/1035 -f 253/211/1036 255/220/1037 213/221/1038 -f 266/223/1039 267/209/1040 198/208/1041 -f 198/208/1042 210/219/1043 266/223/1044 -f 212/257/1045 216/258/1046 204/212/1047 -f 204/212/1048 200/224/1049 212/257/1050 -f 209/218/1051 197/202/1052 268/203/1053 -f 268/203/1054 269/259/1055 209/218/1056 -f 212/257/1057 200/224/1058 254/205/1059 -f 254/205/1060 256/260/1061 212/257/1062 -f 215/217/1063 206/215/1064 194/206/1065 -f 194/206/1066 203/200/1067 215/217/1068 -f 216/258/1069 211/261/1070 199/210/1071 -f 199/210/1072 204/212/1073 216/258/1074 -f 219/227/1075 217/228/1076 205/225/1077 -f 205/225/1078 207/226/1079 219/227/1080 -f 218/231/1081 220/232/1082 208/229/1083 -f 208/229/1084 206/230/1085 218/231/1086 -f 217/228/1087 226/234/1088 215/233/1089 -f 215/233/1090 205/225/1091 217/228/1092 -f 221/236/1093 219/227/1094 207/226/1095 -f 207/226/1096 209/235/1097 221/236/1098 -f 220/232/1099 222/266/1100 210/265/1101 -f 210/265/1102 208/229/1103 220/232/1104 -f 225/239/1105 213/240/1106 255/237/1107 -f 255/237/1108 257/238/1109 225/239/1110 -f 222/266/1111 265/268/1112 266/267/1113 -f 266/267/1114 210/265/1115 222/266/1116 -f 224/243/1117 227/244/1118 216/241/1119 -f 216/241/1120 212/242/1121 224/243/1122 -f 270/270/1123 221/236/1124 209/235/1125 -f 209/235/1126 269/269/1127 270/270/1128 -f 224/243/1129 212/242/1130 256/246/1131 -f 256/246/1132 258/247/1133 224/243/1134 -f 226/332/1135 218/231/1136 206/230/1137 -f 206/230/1138 215/331/1139 226/332/1140 -f 227/244/1141 223/249/1142 211/248/1143 -f 211/248/1144 216/241/1145 227/244/1146 -f 228/250/1147 229/251/1148 227/244/1149 -f 227/244/1150 224/243/1151 228/250/1152 -f 229/251/1153 232/252/1154 223/249/1155 -f 223/249/1156 227/244/1157 229/251/1158 -f 258/247/1159 259/253/1160 228/250/1161 -f 228/250/1162 224/243/1163 258/247/1164 -f 260/254/1165 264/255/1166 225/239/1167 -f 225/239/1168 257/238/1169 260/254/1170 -f 244/274/1171 217/228/1172 219/227/1173 -f 219/227/1174 246/272/1175 244/274/1176 -f 247/276/1177 220/232/1178 218/231/1179 -f 218/231/1180 245/275/1181 247/276/1182 -f 250/277/1183 226/234/1184 217/228/1185 -f 217/228/1186 244/274/1187 250/277/1188 -f 246/272/1189 219/227/1190 221/236/1191 -f 221/236/1192 248/278/1193 246/272/1194 -f 249/279/1195 222/266/1196 220/232/1197 -f 220/232/1198 247/276/1199 249/279/1200 -f 245/275/1201 218/231/1202 226/332/1203 -f 226/332/1204 250/333/1205 245/275/1206 -f 231/282/1207 265/268/1208 222/266/1209 -f 222/266/1210 249/279/1211 231/282/1212 -f 252/286/1213 238/287/1214 279/284/1215 -f 279/284/1216 273/285/1217 252/286/1218 -f 273/285/1219 271/290/1220 242/288/1221 -f 242/288/1222 252/286/1223 273/285/1224 -f 291/294/1225 241/295/1226 289/245/1227 -f 289/245/1228 290/283/1229 291/294/1230 -f 241/295/1231 281/297/1232 288/296/1233 -f 288/296/1234 289/245/1235 241/295/1236 -f 283/299/1237 241/295/1238 291/294/1239 -f 291/294/1240 282/298/1241 283/299/1242 -f 281/297/1243 241/295/1244 283/299/1245 -f 283/299/1246 284/300/1247 281/297/1248 -f 263/262/1249 264/255/1250 260/254/1251 -f 260/254/1252 261/256/1253 263/262/1254 -f 261/256/1255 229/251/1256 228/250/1257 -f 228/250/1258 259/253/1259 261/256/1260 -f 275/306/1261 244/274/1262 246/272/1263 -f 246/272/1264 277/291/1265 275/306/1266 -f 247/276/1267 245/275/1268 276/307/1269 -f 276/307/1270 278/308/1271 247/276/1272 -f 280/309/1273 250/277/1274 244/274/1275 -f 244/274/1276 275/306/1277 280/309/1278 -f 246/272/1279 248/278/1280 279/284/1281 -f 279/284/1282 277/291/1283 246/272/1284 -f 274/310/1285 249/279/1286 247/276/1287 -f 247/276/1288 278/308/1289 274/310/1290 -f 245/275/1291 250/333/1292 280/334/1293 -f 280/334/1294 276/307/1295 245/275/1296 -f 233/311/1297 248/278/1298 221/236/1299 -f 221/236/1300 270/270/1301 233/311/1302 -f 272/312/1303 231/282/1304 249/279/1305 -f 249/279/1306 274/310/1307 272/312/1308 -f 272/312/1309 251/313/1310 242/288/1311 -f 242/288/1312 271/290/1313 272/312/1314 -f 255/220/1315 253/211/1316 199/210/1317 -f 199/210/1318 211/261/1319 255/220/1320 -f 256/260/1321 254/205/1322 202/204/1323 -f 202/204/1324 214/271/1325 256/260/1326 -f 257/238/1327 255/237/1328 211/248/1329 -f 211/248/1330 223/249/1331 257/238/1332 -f 258/247/1333 256/246/1334 214/263/1335 -f 214/263/1336 230/264/1337 258/247/1338 -f 259/253/1339 258/247/1340 230/264/1341 -f 230/264/1342 262/273/1343 259/253/1344 -f 232/252/1345 260/254/1346 257/238/1347 -f 257/238/1348 223/249/1349 232/252/1350 -f 261/256/1351 260/254/1352 232/252/1353 -f 232/252/1354 229/251/1355 261/256/1356 -f 263/262/1357 261/256/1358 259/253/1359 -f 259/253/1360 262/273/1361 263/262/1362 -f 231/281/1363 262/273/1364 230/264/1365 -f 230/264/1366 265/280/1367 231/281/1368 -f 243/289/1369 263/262/1370 262/273/1371 -f 262/273/1372 231/281/1373 243/289/1374 -f 264/255/1375 263/262/1376 243/289/1377 -f 243/289/1378 233/292/1379 264/255/1380 -f 270/293/1381 225/239/1382 264/255/1383 -f 264/255/1384 233/292/1385 270/293/1386 -f 266/304/1387 265/280/1388 230/264/1389 -f 230/264/1390 214/263/1391 266/304/1392 -f 267/209/1393 266/223/1394 214/271/1395 -f 214/271/1396 202/204/1397 267/209/1398 -f 269/259/1399 268/203/1400 201/222/1401 -f 201/222/1402 213/221/1403 269/259/1404 -f 225/239/1405 270/293/1406 269/305/1407 -f 269/305/1408 213/240/1409 225/239/1410 -f 243/314/1411 271/290/1412 273/285/1413 -f 273/285/1414 233/311/1415 243/314/1416 -f 231/282/1417 272/312/1418 271/290/1419 -f 271/290/1420 243/314/1421 231/282/1422 -f 234/316/1423 275/306/1424 277/291/1425 -f 277/291/1426 236/315/1427 234/316/1428 -f 278/308/1429 276/307/1430 235/317/1431 -f 235/317/1432 237/318/1433 278/308/1434 -f 240/319/1435 280/309/1436 275/306/1437 -f 275/306/1438 234/316/1439 240/319/1440 -f 277/291/1441 279/284/1442 238/287/1443 -f 238/287/1444 236/315/1445 277/291/1446 -f 239/320/1447 274/310/1448 278/308/1449 -f 278/308/1450 237/318/1451 239/320/1452 -f 276/307/1453 280/334/1454 240/335/1455 -f 240/335/1456 235/317/1457 276/307/1458 -f 251/313/1459 272/312/1460 274/310/1461 -f 274/310/1462 239/320/1463 251/313/1464 -f 273/285/1465 279/284/1466 248/278/1467 -f 248/278/1468 233/311/1469 273/285/1470 -f 281/297/1471 284/300/1472 285/301/1473 -f 285/301/1474 286/302/1475 281/297/1476 -f 287/303/1477 288/296/1478 281/297/1479 -f 281/297/1480 286/302/1481 287/303/1482 -f 283/321/1483 282/322/1484 234/316/1485 -f 234/316/1486 236/315/1487 283/321/1488 -f 284/323/1489 283/321/1490 236/315/1491 -f 236/315/1492 238/287/1493 284/323/1494 -f 285/324/1495 284/323/1496 238/287/1497 -f 238/287/1498 252/286/1499 285/324/1500 -f 286/325/1501 285/324/1502 252/286/1503 -f 252/286/1504 242/288/1505 286/325/1506 -f 287/326/1507 286/325/1508 242/288/1509 -f 242/288/1510 251/313/1511 287/326/1512 -f 288/327/1513 287/326/1514 251/313/1515 -f 251/313/1516 239/320/1517 288/327/1518 -f 289/328/1519 288/327/1520 239/320/1521 -f 239/320/1522 237/318/1523 289/328/1524 -f 290/329/1525 289/328/1526 237/318/1527 -f 237/318/1528 235/317/1529 290/329/1530 -f 291/330/1531 290/329/1532 235/317/1533 -f 235/317/1534 240/335/1535 291/330/1536 -f 282/322/1537 291/336/1538 240/319/1539 -f 240/319/1540 234/316/1541 282/322/1542 -s 1 -f 294/337/1543 292/339/1544 304/351/1545 -f 304/351/1546 306/352/1547 294/337/1548 -f 293/345/1549 295/344/1550 307/353/1551 -f 307/353/1552 305/354/1553 293/345/1554 -f 292/339/1555 302/338/1556 314/355/1557 -f 314/355/1558 304/351/1559 292/339/1560 -f 296/340/1561 294/337/1562 306/352/1563 -f 306/352/1564 308/356/1565 296/340/1566 -f 295/344/1567 297/346/1568 309/357/1569 -f 309/357/1570 307/353/1571 295/344/1572 -f 354/360/1573 352/349/1574 300/358/1575 -f 300/358/1576 312/359/1577 354/360/1578 -f 309/357/1579 297/346/1580 366/347/1581 -f 366/347/1582 365/361/1583 309/357/1584 -f 299/396/1585 303/348/1586 315/362/1587 -f 315/362/1588 311/395/1589 299/396/1590 -f 368/397/1591 367/341/1592 296/340/1593 -f 296/340/1594 308/356/1595 368/397/1596 -f 355/398/1597 353/342/1598 299/396/1599 -f 299/396/1600 311/395/1601 355/398/1602 -f 302/338/1603 293/345/1604 305/354/1605 -f 305/354/1606 314/355/1607 302/338/1608 -f 303/348/1609 298/350/1610 310/399/1611 -f 310/399/1612 315/362/1613 303/348/1614 -f 306/365/1615 304/366/1616 316/363/1617 -f 316/363/1618 318/364/1619 306/365/1620 -f 305/369/1621 307/370/1622 319/367/1623 -f 319/367/1624 317/368/1625 305/369/1626 -f 304/366/1627 314/372/1628 325/371/1629 -f 325/371/1630 316/363/1631 304/366/1632 -f 308/374/1633 306/365/1634 318/364/1635 -f 318/364/1636 320/373/1637 308/374/1638 -f 307/370/1639 309/404/1640 321/403/1641 -f 321/403/1642 319/367/1643 307/370/1644 -f 356/377/1645 354/378/1646 312/375/1647 -f 312/375/1648 324/376/1649 356/377/1650 -f 309/404/1651 365/406/1652 364/405/1653 -f 364/405/1654 321/403/1655 309/404/1656 -f 311/381/1657 315/382/1658 326/379/1659 -f 326/379/1660 323/380/1661 311/381/1662 -f 368/408/1663 308/374/1664 320/373/1665 -f 320/373/1666 369/407/1667 368/408/1668 -f 357/384/1669 355/385/1670 311/381/1671 -f 311/381/1672 323/380/1673 357/384/1674 -f 314/470/1675 305/369/1676 317/368/1677 -f 317/368/1678 325/469/1679 314/470/1680 -f 315/382/1681 310/387/1682 322/386/1683 -f 322/386/1684 326/379/1685 315/382/1686 -f 323/380/1687 326/379/1688 328/388/1689 -f 328/388/1690 327/389/1691 323/380/1692 -f 326/379/1693 322/386/1694 331/390/1695 -f 331/390/1696 328/388/1697 326/379/1698 -f 323/380/1699 327/389/1700 358/391/1701 -f 358/391/1702 357/384/1703 323/380/1704 -f 356/377/1705 324/376/1706 363/392/1707 -f 363/392/1708 359/393/1709 356/377/1710 -f 345/412/1711 318/364/1712 316/363/1713 -f 316/363/1714 343/410/1715 345/412/1716 -f 344/414/1717 317/368/1718 319/367/1719 -f 319/367/1720 346/413/1721 344/414/1722 -f 343/410/1723 316/363/1724 325/371/1725 -f 325/371/1726 349/415/1727 343/410/1728 -f 347/416/1729 320/373/1730 318/364/1731 -f 318/364/1732 345/412/1733 347/416/1734 -f 346/413/1735 319/367/1736 321/403/1737 -f 321/403/1738 348/417/1739 346/413/1740 -f 349/471/1741 325/469/1742 317/368/1743 -f 317/368/1744 344/414/1745 349/471/1746 -f 348/417/1747 321/403/1748 364/405/1749 -f 364/405/1750 330/420/1751 348/417/1752 -f 372/424/1753 378/425/1754 337/422/1755 -f 337/422/1756 351/423/1757 372/424/1758 -f 351/423/1759 341/428/1760 370/426/1761 -f 370/426/1762 372/424/1763 351/423/1764 -f 389/432/1765 388/433/1766 340/383/1767 -f 340/383/1768 390/421/1769 389/432/1770 -f 388/433/1771 387/435/1772 380/434/1773 -f 380/434/1774 340/383/1775 388/433/1776 -f 381/437/1777 390/421/1778 340/383/1779 -f 340/383/1780 382/436/1781 381/437/1782 -f 383/438/1783 382/436/1784 340/383/1785 -f 340/383/1786 380/434/1787 383/438/1788 -f 360/400/1789 359/393/1790 363/392/1791 -f 363/392/1792 362/394/1793 360/400/1794 -f 358/391/1795 327/389/1796 328/388/1797 -f 328/388/1798 360/400/1799 358/391/1800 -f 376/444/1801 345/412/1802 343/410/1803 -f 343/410/1804 374/429/1805 376/444/1806 -f 377/445/1807 375/446/1808 344/414/1809 -f 344/414/1810 346/413/1811 377/445/1812 -f 374/429/1813 343/410/1814 349/415/1815 -f 349/415/1816 379/447/1817 374/429/1818 -f 376/444/1819 378/425/1820 347/416/1821 -f 347/416/1822 345/412/1823 376/444/1824 -f 377/445/1825 346/413/1826 348/417/1827 -f 348/417/1828 373/448/1829 377/445/1830 -f 375/446/1831 379/472/1832 349/471/1833 -f 349/471/1834 344/414/1835 375/446/1836 -f 369/407/1837 320/373/1838 347/416/1839 -f 347/416/1840 332/449/1841 369/407/1842 -f 373/448/1843 348/417/1844 330/420/1845 -f 330/420/1846 371/450/1847 373/448/1848 -f 370/426/1849 341/428/1850 350/451/1851 -f 350/451/1852 371/450/1853 370/426/1854 -f 310/399/1855 298/350/1856 352/349/1857 -f 352/349/1858 354/360/1859 310/399/1860 -f 313/409/1861 301/343/1862 353/342/1863 -f 353/342/1864 355/398/1865 313/409/1866 -f 322/386/1867 310/387/1868 354/378/1869 -f 354/378/1870 356/377/1871 322/386/1872 -f 329/401/1873 313/402/1874 355/385/1875 -f 355/385/1876 357/384/1877 329/401/1878 -f 361/411/1879 329/401/1880 357/384/1881 -f 357/384/1882 358/391/1883 361/411/1884 -f 322/386/1885 356/377/1886 359/393/1887 -f 359/393/1888 331/390/1889 322/386/1890 -f 328/388/1891 331/390/1892 359/393/1893 -f 359/393/1894 360/400/1895 328/388/1896 -f 361/411/1897 358/391/1898 360/400/1899 -f 360/400/1900 362/394/1901 361/411/1902 -f 364/419/1903 329/401/1904 361/411/1905 -f 361/411/1906 330/418/1907 364/419/1908 -f 330/418/1909 361/411/1910 362/394/1911 -f 362/394/1912 342/427/1913 330/418/1914 -f 332/430/1915 342/427/1916 362/394/1917 -f 362/394/1918 363/392/1919 332/430/1920 -f 332/430/1921 363/392/1922 324/376/1923 -f 324/376/1924 369/431/1925 332/430/1926 -f 313/402/1927 329/401/1928 364/419/1929 -f 364/419/1930 365/442/1931 313/402/1932 -f 301/343/1933 313/409/1934 365/361/1935 -f 365/361/1936 366/347/1937 301/343/1938 -f 312/359/1939 300/358/1940 367/341/1941 -f 367/341/1942 368/397/1943 312/359/1944 -f 312/375/1945 368/443/1946 369/431/1947 -f 369/431/1948 324/376/1949 312/375/1950 -f 332/449/1951 372/424/1952 370/426/1953 -f 370/426/1954 342/452/1955 332/449/1956 -f 342/452/1957 370/426/1958 371/450/1959 -f 371/450/1960 330/420/1961 342/452/1962 -f 335/454/1963 376/444/1964 374/429/1965 -f 374/429/1966 333/453/1967 335/454/1968 -f 336/455/1969 334/456/1970 375/446/1971 -f 375/446/1972 377/445/1973 336/455/1974 -f 333/453/1975 374/429/1976 379/447/1977 -f 379/447/1978 339/457/1979 333/453/1980 -f 335/454/1981 337/422/1982 378/425/1983 -f 378/425/1984 376/444/1985 335/454/1986 -f 336/455/1987 377/445/1988 373/448/1989 -f 373/448/1990 338/458/1991 336/455/1992 -f 334/456/1993 339/473/1994 379/472/1995 -f 379/472/1996 375/446/1997 334/456/1998 -f 338/458/1999 373/448/2000 371/450/2001 -f 371/450/2002 350/451/2003 338/458/2004 -f 332/449/2005 347/416/2006 378/425/2007 -f 378/425/2008 372/424/2009 332/449/2010 -f 385/439/2011 384/440/2012 383/438/2013 -f 383/438/2014 380/434/2015 385/439/2016 -f 385/439/2017 380/434/2018 387/435/2019 -f 387/435/2020 386/441/2021 385/439/2022 -f 335/454/2023 333/453/2024 381/459/2025 -f 381/459/2026 382/460/2027 335/454/2028 -f 337/422/2029 335/454/2030 382/460/2031 -f 382/460/2032 383/461/2033 337/422/2034 -f 351/423/2035 337/422/2036 383/461/2037 -f 383/461/2038 384/462/2039 351/423/2040 -f 341/428/2041 351/423/2042 384/462/2043 -f 384/462/2044 385/463/2045 341/428/2046 -f 350/451/2047 341/428/2048 385/463/2049 -f 385/463/2050 386/464/2051 350/451/2052 -f 338/458/2053 350/451/2054 386/464/2055 -f 386/464/2056 387/465/2057 338/458/2058 -f 336/455/2059 338/458/2060 387/465/2061 -f 387/465/2062 388/466/2063 336/455/2064 -f 334/456/2065 336/455/2066 388/466/2067 -f 388/466/2068 389/467/2069 334/456/2070 -f 339/473/2071 334/456/2072 389/467/2073 -f 389/467/2074 390/468/2075 339/473/2076 -f 333/453/2077 339/457/2078 390/474/2079 -f 390/474/2080 381/459/2081 333/453/2082 -f 396/480/2083 398/481/2084 397/475/2085 -f 397/475/2086 1269/478/2087 396/480/2088 -f 396/480/2089 400/483/2090 399/482/2091 -f 399/482/2092 398/481/2093 396/480/2094 -f 401/487/2095 404/488/2096 403/485/2097 -f 403/485/2098 402/486/2099 401/487/2100 -f 405/490/2101 401/487/2102 402/486/2103 -f 402/486/2104 406/489/2105 405/490/2106 -f 401/487/2107 405/490/2108 407/491/2109 -f 407/491/2110 404/488/2111 401/487/2112 -f 408/494/2113 411/495/2114 410/492/2115 -f 410/492/2116 409/493/2117 408/494/2118 -f 408/494/2119 413/497/2120 412/496/2121 -f 412/496/2122 411/495/2123 408/494/2124 -f 408/494/2125 415/499/2126 414/498/2127 -f 414/498/2128 413/497/2129 408/494/2130 -f 408/494/2131 417/501/2132 416/500/2133 -f 416/500/2134 415/499/2135 408/494/2136 -f 408/494/2137 409/493/2138 418/502/2139 -f 418/502/2140 417/501/2141 408/494/2142 -f 419/505/2143 422/506/2144 421/503/2145 -f 421/503/2146 420/504/2147 419/505/2148 -f 419/505/2149 420/504/2150 424/507/2151 -f 424/507/2152 423/508/2153 419/505/2154 -f 425/511/2155 428/512/2156 427/509/2157 -f 427/509/2158 426/510/2159 425/511/2160 -f 429/514/2161 425/511/2162 426/510/2163 -f 426/510/2164 430/513/2165 429/514/2166 -f 425/515/2167 429/528/2168 431/476/2169 -f 431/476/2170 428/477/2171 425/515/2172 -f 432/517/2173 435/518/2174 434/484/2175 -f 434/484/2176 433/516/2177 432/517/2178 -f 432/517/2179 433/516/2180 437/519/2181 -f 437/519/2182 436/520/2183 432/517/2184 -f 432/517/2185 438/521/2186 400/483/2187 -f 400/483/2188 435/518/2189 432/517/2190 -f 435/518/2191 440/523/2192 439/522/2193 -f 439/522/2194 434/484/2195 435/518/2196 -f 443/526/2197 442/527/2198 441/524/2199 -f 441/524/2200 444/525/2201 443/526/2202 -f 442/527/2203 443/526/2204 434/484/2205 -f 434/484/2206 439/522/2207 442/527/2208 -f 442/527/2209 439/522/2210 445/529/2211 -f 445/529/2212 441/524/2213 442/527/2214 -f 446/532/2215 449/533/2216 448/530/2217 -f 448/530/2218 447/531/2219 446/532/2220 -f 451/534/2221 450/535/2222 449/533/2223 -f 449/533/2224 446/532/2225 451/534/2226 -f 433/516/2227 434/484/2228 443/526/2229 -f 443/526/2230 437/519/2231 433/516/2232 -f 452/538/2233 455/539/2234 454/536/2235 -f 454/536/2236 453/537/2237 452/538/2238 -f 452/538/2239 458/557/2240 457/542/2241 -f 457/542/2242 456/543/2243 452/538/2244 -f 452/538/2245 453/537/2246 459/644/2247 -f 459/644/2248 458/557/2249 452/538/2250 -f 460/544/2251 462/545/2252 457/540/2253 -f 457/540/2254 461/541/2255 460/544/2256 -f 460/544/2257 406/489/2258 402/486/2259 -f 402/486/2260 403/485/2261 460/544/2262 -f 460/544/2263 461/541/2264 463/546/2265 -f 463/546/2266 406/489/2267 460/544/2268 -f 417/501/2269 418/502/2270 464/547/2271 -f 464/547/2272 416/500/2273 417/501/2274 -f 462/545/2275 465/549/2276 456/548/2277 -f 456/548/2278 457/540/2279 462/545/2280 -f 462/545/2281 460/544/2282 466/550/2283 -f 466/550/2284 465/549/2285 462/545/2286 -f 1342/688/2287 423/508/2288 467/551/2289 -f 467/551/2290 1341/687/2291 1342/688/2292 -f 468/627/2293 471/629/2294 470/552/2295 -f 470/552/2296 469/553/2297 468/627/2298 -f 468/647/2299 473/648/2300 472/645/2301 -f 472/645/2302 471/646/2303 468/647/2304 -f 471/556/2305 475/558/2306 474/554/2307 -f 474/554/2308 470/555/2309 471/556/2310 -f 471/556/2311 472/560/2312 476/559/2313 -f 476/559/2314 475/558/2315 471/556/2316 -f 476/559/2317 478/562/2318 477/561/2319 -f 477/561/2320 475/558/2321 476/559/2322 -f 476/559/2323 465/549/2324 466/550/2325 -f 466/550/2326 478/562/2327 476/559/2328 -f 476/559/2329 472/560/2330 456/548/2331 -f 456/548/2332 465/549/2333 476/559/2334 -f 478/562/2335 480/564/2336 479/563/2337 -f 479/563/2338 477/561/2339 478/562/2340 -f 478/562/2341 466/550/2342 481/565/2343 -f 481/565/2344 480/564/2345 478/562/2346 -f 481/565/2347 483/567/2348 482/566/2349 -f 482/566/2350 480/564/2351 481/565/2352 -f 481/565/2353 403/485/2354 404/488/2355 -f 404/488/2356 483/567/2357 481/565/2358 -f 481/565/2359 466/550/2360 460/544/2361 -f 460/544/2362 403/485/2363 481/565/2364 -f 483/567/2365 485/569/2366 484/568/2367 -f 484/568/2368 482/566/2369 483/567/2370 -f 483/567/2371 404/488/2372 486/570/2373 -f 486/570/2374 485/569/2375 483/567/2376 -f 486/570/2377 488/572/2378 487/571/2379 -f 487/571/2380 485/569/2381 486/570/2382 -f 486/570/2383 490/574/2384 489/573/2385 -f 489/573/2386 488/572/2387 486/570/2388 -f 486/570/2389 404/488/2390 407/491/2391 -f 407/491/2392 490/574/2393 486/570/2394 -f 490/574/2395 464/547/2396 491/575/2397 -f 491/575/2398 489/573/2399 490/574/2400 -f 490/574/2401 407/491/2402 416/500/2403 -f 416/500/2404 464/547/2405 490/574/2406 -f 489/573/2407 493/577/2408 492/576/2409 -f 492/576/2410 488/572/2411 489/573/2412 -f 489/573/2413 491/575/2414 494/578/2415 -f 494/578/2416 493/577/2417 489/573/2418 -f 493/577/2419 496/580/2420 495/579/2421 -f 495/579/2422 492/576/2423 493/577/2424 -f 493/577/2425 494/578/2426 497/581/2427 -f 497/581/2428 496/580/2429 493/577/2430 -f 497/581/2431 494/578/2432 499/582/2433 -f 499/582/2434 498/583/2435 497/581/2436 -f 498/2584/2437 499/2583/2438 501/584/2439 -f 501/584/2440 500/585/2441 498/2584/2442 -f 501/584/2443 499/2583/2444 503/586/2445 -f 503/586/2446 502/587/2447 501/584/2448 -f 501/584/2449 505/589/2450 504/588/2451 -f 504/588/2452 500/585/2453 501/584/2454 -f 501/584/2455 502/587/2456 506/590/2457 -f 506/590/2458 505/589/2459 501/584/2460 -f 504/588/2461 505/589/2462 508/591/2463 -f 508/591/2464 507/592/2465 504/588/2466 -f 507/592/2467 508/591/2468 510/593/2469 -f 510/593/2470 509/594/2471 507/592/2472 -f 510/593/2473 508/591/2474 512/595/2475 -f 512/595/2476 511/596/2477 510/593/2478 -f 510/593/2479 514/598/2480 513/597/2481 -f 513/597/2482 509/594/2483 510/593/2484 -f 510/593/2485 511/596/2486 515/599/2487 -f 515/599/2488 514/598/2489 510/593/2490 -f 515/599/2491 511/596/2492 517/600/2493 -f 517/600/2494 516/601/2495 515/599/2496 -f 515/599/2497 519/603/2498 518/602/2499 -f 518/602/2500 514/598/2501 515/599/2502 -f 515/599/2503 516/601/2504 520/604/2505 -f 520/604/2506 519/603/2507 515/599/2508 -f 520/604/2509 516/601/2510 522/605/2511 -f 522/605/2512 521/606/2513 520/604/2514 -f 520/604/2515 484/568/2516 523/607/2517 -f 523/607/2518 519/603/2519 520/604/2520 -f 520/604/2521 521/606/2522 482/566/2523 -f 482/566/2524 484/568/2525 520/604/2526 -f 523/607/2527 524/608/2528 518/602/2529 -f 518/602/2530 519/603/2531 523/607/2532 -f 523/607/2533 487/571/2534 525/609/2535 -f 525/609/2536 524/608/2537 523/607/2538 -f 523/607/2539 484/568/2540 485/569/2541 -f 485/569/2542 487/571/2543 523/607/2544 -f 525/609/2545 527/611/2546 526/610/2547 -f 526/610/2548 524/608/2549 525/609/2550 -f 525/609/2551 492/576/2552 495/579/2553 -f 495/579/2554 527/611/2555 525/609/2556 -f 525/609/2557 487/571/2558 488/572/2559 -f 488/572/2560 492/576/2561 525/609/2562 -f 528/612/2563 513/597/2564 514/598/2565 -f 514/598/2566 518/602/2567 528/612/2568 -f 528/612/2569 518/602/2570 524/608/2571 -f 524/608/2572 526/610/2573 528/612/2574 -f 522/605/2575 531/615/2576 530/613/2577 -f 530/613/2578 529/614/2579 522/605/2580 -f 522/605/2581 516/601/2582 517/600/2583 -f 517/600/2584 531/615/2585 522/605/2586 -f 522/605/2587 529/614/2588 479/563/2589 -f 479/563/2590 521/606/2591 522/605/2592 -f 531/615/2593 533/617/2594 532/616/2595 -f 532/616/2596 530/613/2597 531/615/2598 -f 531/615/2599 517/600/2600 534/618/2601 -f 534/618/2602 533/617/2603 531/615/2604 -f 534/618/2605 536/620/2606 535/619/2607 -f 535/619/2608 533/617/2609 534/618/2610 -f 534/618/2611 512/595/2612 537/621/2613 -f 537/621/2614 536/620/2615 534/618/2616 -f 534/618/2617 517/600/2618 511/596/2619 -f 511/596/2620 512/595/2621 534/618/2622 -f 535/619/2623 538/622/2624 426/510/2625 -f 426/510/2626 427/509/2627 535/619/2628 -f 535/619/2629 536/620/2630 506/590/2631 -f 506/590/2632 538/622/2633 535/619/2634 -f 535/619/2635 427/509/2636 532/616/2637 -f 532/616/2638 533/617/2639 535/619/2640 -f 538/622/2641 539/623/2642 430/513/2643 -f 430/513/2644 426/510/2645 538/622/2646 -f 538/622/2647 506/590/2648 502/587/2649 -f 502/587/2650 539/623/2651 538/622/2652 -f 539/623/2653 410/2580/2654 411/2581/2655 -f 411/2581/2656 430/513/2657 539/623/2658 -f 539/623/2659 502/587/2660 503/586/2661 -f 503/586/2662 410/2580/2663 539/623/2664 -f 532/616/2665 427/509/2666 428/512/2667 -f 428/512/2668 540/624/2669 532/616/2670 -f 532/616/2671 540/624/2672 541/625/2673 -f 541/625/2674 530/613/2675 532/616/2676 -f 541/632/2677 540/633/2678 543/630/2679 -f 543/630/2680 542/631/2681 541/632/2682 -f 541/625/2683 544/626/2684 529/614/2685 -f 529/614/2686 530/613/2687 541/625/2688 -f 541/625/2689 542/628/2690 474/554/2691 -f 474/554/2692 544/626/2693 541/625/2694 -f 544/626/2695 477/561/2696 479/563/2697 -f 479/563/2698 529/614/2699 544/626/2700 -f 544/626/2701 474/554/2702 475/558/2703 -f 475/558/2704 477/561/2705 544/626/2706 -f 543/630/2707 547/636/2708 546/634/2709 -f 546/634/2710 545/635/2711 543/630/2712 -f 543/630/2713 540/633/2714 428/477/2715 -f 428/477/2716 547/636/2717 543/630/2718 -f 543/630/2719 545/635/2720 548/637/2721 -f 548/637/2722 542/631/2723 543/630/2724 -f 547/636/2725 550/639/2726 549/638/2727 -f 549/638/2728 546/634/2729 547/636/2730 -f 547/636/2731 428/477/2732 431/476/2733 -f 431/476/2734 550/639/2735 547/636/2736 -f 550/639/2737 552/641/2738 551/640/2739 -f 551/640/2740 549/638/2741 550/639/2742 -f 550/639/2743 431/476/2744 553/642/2745 -f 553/642/2746 552/641/2747 550/639/2748 -f 553/642/2749 555/668/2750 554/643/2751 -f 554/643/2752 552/641/2753 553/642/2754 -f 553/642/2755 557/670/2756 556/669/2757 -f 556/669/2758 555/668/2759 553/642/2760 -f 553/642/2761 431/476/2762 429/528/2763 -f 429/528/2764 557/670/2765 553/642/2766 -f 557/670/2767 559/672/2768 558/671/2769 -f 558/671/2770 556/669/2771 557/670/2772 -f 557/670/2773 429/528/2774 412/673/2775 -f 412/673/2776 559/672/2777 557/670/2778 -f 559/652/2779 561/653/2780 560/649/2781 -f 560/649/2782 558/651/2783 559/652/2784 -f 559/652/2785 412/655/2786 413/654/2787 -f 413/654/2788 561/653/2789 559/652/2790 -f 561/653/2791 563/657/2792 562/656/2793 -f 562/656/2794 560/649/2795 561/653/2796 -f 561/653/2797 413/654/2798 414/658/2799 -f 414/658/2800 563/657/2801 561/653/2802 -f 563/657/2803 565/660/2804 564/659/2805 -f 564/659/2806 562/656/2807 563/657/2808 -f 563/657/2809 414/658/2810 566/661/2811 -f 566/661/2812 565/660/2813 563/657/2814 -f 566/661/2815 463/663/2816 567/662/2817 -f 567/662/2818 565/660/2819 566/661/2820 -f 566/650/2821 405/490/2822 406/489/2823 -f 406/489/2824 463/546/2825 566/650/2826 -f 566/650/2827 414/498/2828 415/499/2829 -f 415/499/2830 405/490/2831 566/650/2832 -f 567/662/2833 568/664/2834 564/659/2835 -f 564/659/2836 565/660/2837 567/662/2838 -f 567/662/2839 570/666/2840 569/665/2841 -f 569/665/2842 568/664/2843 567/662/2844 -f 567/662/2845 463/663/2846 461/667/2847 -f 461/667/2848 570/666/2849 567/662/2850 -f 570/666/2851 458/557/2852 459/644/2853 -f 459/644/2854 569/665/2855 570/666/2856 -f 570/666/2857 461/667/2858 457/542/2859 -f 457/542/2860 458/557/2861 570/666/2862 -f 569/665/2863 572/697/2864 571/696/2865 -f 571/696/2866 568/664/2867 569/665/2868 -f 569/665/2869 459/644/2870 573/781/2871 -f 573/781/2872 572/697/2873 569/665/2874 -f 573/781/2875 575/1353/2876 574/782/2877 -f 574/782/2878 572/697/2879 573/781/2880 -f 573/781/2881 577/1355/2882 576/1354/2883 -f 576/1354/2884 575/1353/2885 573/781/2886 -f 573/781/2887 459/644/2888 453/537/2889 -f 453/537/2890 577/1355/2891 573/781/2892 -f 577/1355/2893 579/1357/2894 578/1356/2895 -f 578/1356/2896 576/1354/2897 577/1355/2898 -f 577/1355/2899 453/537/2900 454/536/2901 -f 454/536/2902 579/1357/2903 577/1355/2904 -f 576/1354/2905 581/1390/2906 580/1389/2907 -f 580/1389/2908 575/1353/2909 576/1354/2910 -f 576/1354/2911 578/1356/2912 582/1391/2913 -f 582/1391/2914 581/1390/2915 576/1354/2916 -f 581/1390/2917 1483/1393/2918 1482/1392/2919 -f 1482/1392/2920 580/1389/2921 581/1390/2922 -f 581/1390/2923 582/1391/2924 1484/1394/2925 -f 1484/1394/2926 1483/1393/2927 581/1390/2928 -f 1482/1392/2929 391/1396/2930 583/1395/2931 -f 583/1395/2932 580/1389/2933 1482/1392/2934 -f 391/1396/2935 397/475/2936 398/481/2937 -f 398/481/2938 583/1395/2939 391/1396/2940 -f 583/1395/2941 574/782/2942 575/1353/2943 -f 575/1353/2944 580/1389/2945 583/1395/2946 -f 583/1395/2947 398/481/2948 399/482/2949 -f 399/482/2950 574/782/2951 583/1395/2952 -f 574/782/2953 399/482/2954 571/696/2955 -f 571/696/2956 572/697/2957 574/782/2958 -f 571/696/2959 399/482/2960 400/483/2961 -f 400/483/2962 438/521/2963 571/696/2964 -f 571/696/2965 438/521/2966 564/659/2967 -f 564/659/2968 568/664/2969 571/696/2970 -f 564/659/2971 438/521/2972 432/517/2973 -f 432/517/2974 562/656/2975 564/659/2976 -f 562/656/2977 432/517/2978 436/520/2979 -f 436/520/2980 560/649/2981 562/656/2982 -f 560/649/2983 436/520/2984 584/1397/2985 -f 584/1397/2986 558/651/2987 560/649/2988 -f 584/676/2989 587/677/2990 586/674/2991 -f 586/674/2992 585/675/2993 584/676/2994 -f 584/1397/2995 436/520/2996 437/519/2997 -f 437/519/2998 587/1398/2999 584/1397/3000 -f 584/676/3001 585/675/3002 556/669/3003 -f 556/669/3004 558/671/3005 584/676/3006 -f 586/674/3007 590/680/3008 589/678/3009 -f 589/678/3010 588/679/3011 586/674/3012 -f 586/674/3013 587/677/3014 444/681/3015 -f 444/681/3016 590/680/3017 586/674/3018 -f 586/674/3019 588/679/3020 591/682/3021 -f 591/682/3022 585/675/3023 586/674/3024 -f 591/682/3025 588/679/3026 593/683/3027 -f 593/683/3028 592/684/3029 591/682/3030 -f 591/682/3031 555/668/3032 556/669/3033 -f 556/669/3034 585/675/3035 591/682/3036 -f 591/682/3037 592/684/3038 554/643/3039 -f 554/643/3040 555/668/3041 591/682/3042 -f 593/683/3043 596/1388/3044 595/685/3045 -f 595/685/3046 594/785/3047 593/683/3048 -f 593/683/3049 588/679/3050 589/678/3051 -f 589/678/3052 596/1388/3053 593/683/3054 -f 593/683/3055 594/785/3056 597/1399/3057 -f 597/1399/3058 592/684/3059 593/683/3060 -f 597/1399/3061 594/785/3062 1500/1427/3063 -f 1500/1427/3064 1501/1428/3065 597/1399/3066 -f 597/1399/3067 598/1429/3068 554/643/3069 -f 554/643/3070 592/684/3071 597/1399/3072 -f 597/1399/3073 1501/1428/3074 392/1430/3075 -f 392/1430/3076 598/1429/3077 597/1399/3078 -f 392/1430/3079 1503/1525/3080 551/640/3081 -f 551/640/3082 598/1429/3083 392/1430/3084 -f 1503/1525/3085 599/1526/3086 549/638/3087 -f 549/638/3088 551/640/3089 1503/1525/3090 -f 599/1526/3091 1504/1528/3092 546/634/3093 -f 546/634/3094 549/638/3095 599/1526/3096 -f 1504/1528/3097 600/1529/3098 545/635/3099 -f 545/635/3100 546/634/3101 1504/1528/3102 -f 600/1529/3103 601/1530/3104 548/637/3105 -f 548/637/3106 545/635/3107 600/1529/3108 -f 598/1429/3109 551/640/3110 552/641/3111 -f 552/641/3112 554/643/3113 598/1429/3114 -f 1500/1427/3115 594/785/3116 595/685/3117 -f 595/685/3118 393/1531/3119 1500/1427/3120 -f 393/1531/3121 595/685/3122 419/1532/3123 -f 419/1532/3124 602/1533/3125 393/1531/3126 -f 596/1388/3127 422/1534/3128 419/1532/3129 -f 419/1532/3130 595/685/3131 596/1388/3132 -f 596/1388/3133 589/678/3134 603/1535/3135 -f 603/1535/3136 422/1534/3137 596/1388/3138 -f 603/689/3139 604/690/3140 421/503/3141 -f 421/503/3142 422/506/3143 603/689/3144 -f 603/689/3145 606/692/3146 605/691/3147 -f 605/691/3148 604/690/3149 603/689/3150 -f 603/1535/3151 589/678/3152 590/680/3153 -f 590/680/3154 606/1536/3155 603/1535/3156 -f 607/693/3157 449/533/3158 605/691/3159 -f 605/691/3160 606/692/3161 607/693/3162 -f 606/1536/3163 590/680/3164 444/681/3165 -f 444/681/3166 607/1537/3167 606/1536/3168 -f 607/1401/3169 444/525/3170 441/524/3171 -f 441/524/3172 608/1400/3173 607/1401/3174 -f 608/1400/3175 441/524/3176 445/529/3177 -f 445/529/3178 609/1402/3179 608/1400/3180 -f 609/1402/3181 445/529/3182 612/1409/3183 -f 612/1409/3184 611/1410/3185 609/1402/3186 -f 612/1409/3187 445/529/3188 439/522/3189 -f 439/522/3190 440/523/3191 612/1409/3192 -f 612/1409/3193 613/1412/3194 1515/1411/3195 -f 1515/1411/3196 611/1410/3197 612/1409/3198 -f 612/1409/3199 440/523/3200 394/1414/3201 -f 394/1414/3202 613/1412/3203 612/1409/3204 -f 1515/698/3205 395/699/3206 610/694/3207 -f 610/694/3208 611/695/3209 1515/698/3210 -f 395/699/3211 1517/701/3212 614/700/3213 -f 614/700/3214 610/694/3215 395/699/3216 -f 1517/701/3217 1519/703/3218 615/702/3219 -f 615/702/3220 614/700/3221 1517/701/3222 -f 1519/703/3223 1521/705/3224 616/704/3225 -f 616/704/3226 615/702/3227 1519/703/3228 -f 1521/705/3229 1341/2601/3230 467/2600/3231 -f 467/2600/3232 616/704/3233 1521/705/3234 -f 616/704/3235 618/707/3236 617/706/3237 -f 617/706/3238 615/702/3239 616/704/3240 -f 616/704/3241 467/2600/3242 619/708/3243 -f 619/708/3244 618/707/3245 616/704/3246 -f 620/710/3247 618/707/3248 619/708/3249 -f 619/708/3250 621/709/3251 620/710/3252 -f 424/507/3253 622/711/3254 621/2603/3255 -f 621/2603/3256 619/2602/3257 424/507/3258 -f 619/2602/3259 467/551/3260 423/508/3261 -f 423/508/3262 424/507/3263 619/2602/3264 -f 623/714/3265 626/715/3266 625/712/3267 -f 625/712/3268 624/2605/3269 623/714/3270 -f 623/714/3271 628/717/3272 627/716/3273 -f 627/716/3274 626/715/3275 623/714/3276 -f 622/711/3277 629/718/3278 628/717/3279 -f 628/717/3280 623/714/3281 622/711/3282 -f 628/717/3283 631/720/3284 630/719/3285 -f 630/719/3286 627/716/3287 628/717/3288 -f 629/718/3289 632/721/3290 631/720/3291 -f 631/720/3292 628/717/3293 629/718/3294 -f 631/720/3295 634/723/3296 633/722/3297 -f 633/722/3298 630/719/3299 631/720/3300 -f 632/721/3301 635/724/3302 634/723/3303 -f 634/723/3304 631/720/3305 632/721/3306 -f 634/723/3307 637/726/3308 636/725/3309 -f 636/725/3310 633/722/3311 634/723/3312 -f 635/724/3313 638/727/3314 637/726/3315 -f 637/726/3316 634/723/3317 635/724/3318 -f 637/726/3319 640/729/3320 639/728/3321 -f 639/728/3322 636/725/3323 637/726/3324 -f 638/727/3325 450/535/3326 640/729/3327 -f 640/729/3328 637/726/3329 638/727/3330 -f 642/730/3331 641/731/3332 636/725/3333 -f 636/725/3334 639/728/3335 642/730/3336 -f 644/732/3337 643/733/3338 642/730/3339 -f 642/730/3340 639/728/3341 644/732/3342 -f 639/728/3343 640/729/3344 645/734/3345 -f 645/734/3346 644/732/3347 639/728/3348 -f 647/735/3349 646/736/3350 643/733/3351 -f 643/733/3352 644/732/3353 647/735/3354 -f 644/732/3355 645/734/3356 648/737/3357 -f 648/737/3358 647/735/3359 644/732/3360 -f 648/737/3361 650/739/3362 649/738/3363 -f 649/738/3364 647/735/3365 648/737/3366 -f 620/710/3367 650/739/3368 648/737/3369 -f 648/737/3370 651/740/3371 620/710/3372 -f 645/734/3373 451/534/3374 651/740/3375 -f 651/740/3376 648/737/3377 645/734/3378 -f 646/736/3379 647/735/3380 649/738/3381 -f 649/738/3382 652/741/3383 646/736/3384 -f 653/742/3385 652/741/3386 649/738/3387 -f 649/738/3388 625/2604/3389 653/742/3390 -f 649/738/3391 650/739/3392 624/713/3393 -f 624/713/3394 625/2604/3395 649/738/3396 -f 656/745/3397 655/746/3398 654/2607/3399 -f 654/2607/3400 657/744/3401 656/745/3402 -f 659/747/3403 658/748/3404 657/2608/3405 -f 657/2608/3406 654/743/3407 659/747/3408 -f 653/2606/3409 660/749/3410 659/747/3411 -f 659/747/3412 654/743/3413 653/2606/3414 -f 662/750/3415 661/751/3416 658/748/3417 -f 658/748/3418 659/747/3419 662/750/3420 -f 660/749/3421 663/752/3422 662/750/3423 -f 662/750/3424 659/747/3425 660/749/3426 -f 665/753/3427 664/754/3428 661/751/3429 -f 661/751/3430 662/750/3431 665/753/3432 -f 663/752/3433 666/755/3434 665/753/3435 -f 665/753/3436 662/750/3437 663/752/3438 -f 667/757/3439 664/754/3440 665/753/3441 -f 665/753/3442 668/756/3443 667/757/3444 -f 666/755/3445 669/758/3446 668/756/3447 -f 668/756/3448 665/753/3449 666/755/3450 -f 670/760/3451 667/757/3452 668/756/3453 -f 668/756/3454 671/759/3455 670/760/3456 -f 641/731/3457 671/759/3458 668/756/3459 -f 668/756/3460 669/758/3461 641/731/3462 -f 672/763/3463 675/764/3464 674/761/3465 -f 674/761/3466 673/762/3467 672/763/3468 -f 672/763/3469 677/766/3470 676/765/3471 -f 676/765/3472 675/764/3473 672/763/3474 -f 670/760/3475 678/767/3476 677/766/3477 -f 677/766/3478 672/763/3479 670/760/3480 -f 677/766/3481 680/769/3482 679/768/3483 -f 679/768/3484 676/765/3485 677/766/3486 -f 678/767/3487 681/770/3488 680/769/3489 -f 680/769/3490 677/766/3491 678/767/3492 -f 680/769/3493 683/772/3494 682/771/3495 -f 682/771/3496 679/768/3497 680/769/3498 -f 681/770/3499 684/773/3500 683/772/3501 -f 683/772/3502 680/769/3503 681/770/3504 -f 683/772/3505 686/775/3506 685/774/3507 -f 685/774/3508 682/771/3509 683/772/3510 -f 656/745/3511 686/775/3512 683/772/3513 -f 683/772/3514 684/773/3515 656/745/3516 -f 685/774/3517 686/775/3518 688/776/3519 -f 688/776/3520 687/777/3521 685/774/3522 -f 687/2610/3523 688/2609/3524 690/778/3525 -f 690/778/3526 689/1350/3527 687/2610/3528 -f 689/1350/3529 690/778/3530 692/1351/3531 -f 692/1351/3532 691/1352/3533 689/1350/3534 -f 691/1352/3535 692/1351/3536 694/2566/3537 -f 694/2566/3538 693/2567/3539 691/1352/3540 -f 693/2567/3541 694/2566/3542 673/762/3543 -f 673/762/3544 674/761/3545 693/2567/3546 -f 617/706/3547 446/532/3548 614/700/3549 -f 614/700/3550 615/702/3551 617/706/3552 -f 542/631/3553 548/637/3554 470/552/3555 -f 470/552/3556 474/1538/3557 542/631/3558 -f 521/606/3559 479/563/3560 480/564/3561 -f 480/564/3562 482/566/3563 521/606/3564 -f 503/2585/3565 695/779/3566 409/493/3567 -f 409/493/3568 410/492/3569 503/2585/3570 -f 491/575/3571 464/547/3572 418/502/3573 -f 418/502/3574 696/780/3575 491/575/3576 -f 455/539/3577 452/538/3578 698/1415/3579 -f 698/1415/3580 697/1416/3581 455/539/3582 -f 430/513/3583 411/2581/3584 412/2582/3585 -f 412/2582/3586 429/514/3587 430/513/3588 -f 1342/688/3589 602/2568/3590 419/505/3591 -f 419/505/3592 423/508/3593 1342/688/3594 -f 698/1415/3595 472/645/3596 473/648/3597 -f 473/648/3598 697/1416/3599 698/1415/3600 -f 698/1415/3601 452/538/3602 456/543/3603 -f 456/543/3604 472/645/3605 698/1415/3606 -f 418/502/3607 409/493/3608 695/779/3609 -f 695/779/3610 696/780/3611 418/502/3612 -f 416/500/3613 407/491/3614 405/490/3615 -f 405/490/3616 415/499/3617 416/500/3618 -f 1269/478/3619 394/1414/3620 440/523/3621 -f 440/523/3622 396/480/3623 1269/478/3624 -f 537/621/3625 505/589/3626 506/590/3627 -f 506/590/3628 536/620/3629 537/621/3630 -f 537/621/3631 512/595/3632 508/591/3633 -f 508/591/3634 505/589/3635 537/621/3636 -f 435/518/3637 400/483/3638 396/480/3639 -f 396/480/3640 440/523/3641 435/518/3642 -f 695/779/3643 700/784/3644 699/783/3645 -f 699/783/3646 696/780/3647 695/779/3648 -f 491/575/3649 696/780/3650 699/783/3651 -f 699/783/3652 494/578/3653 491/575/3654 -f 700/784/3655 499/582/3656 494/578/3657 -f 494/578/3658 699/783/3659 700/784/3660 -f 503/2585/3661 499/582/3662 700/784/3663 -f 700/784/3664 695/779/3665 503/2585/3666 -f 601/1530/3667 1607/1540/3668 701/1539/3669 -f 701/1539/3670 548/637/3671 601/1530/3672 -f 548/637/3673 701/1539/3674 469/553/3675 -f 469/553/3676 470/552/3677 548/637/3678 -f 703/788/3679 702/789/3680 705/786/3681 -f 705/786/3682 704/787/3683 703/788/3684 -f 1129/792/3685 707/793/3686 706/790/3687 -f 706/790/3688 708/791/3689 1129/792/3690 -f 711/796/3691 710/797/3692 709/794/3693 -f 709/794/3694 712/795/3695 711/796/3696 -f 714/800/3697 713/801/3698 716/798/3699 -f 716/798/3700 715/799/3701 714/800/3702 -f 711/796/3703 718/804/3704 717/802/3705 -f 717/802/3706 719/803/3707 711/796/3708 -f 724/809/3709 723/810/3710 726/807/3711 -f 726/807/3712 725/808/3713 724/809/3714 -f 728/813/3715 727/814/3716 730/811/3717 -f 730/811/3718 729/812/3719 728/813/3720 -f 733/815/3721 732/816/3722 731/805/3723 -f 731/805/3724 734/806/3725 733/815/3726 -f 736/819/3727 735/820/3728 738/817/3729 -f 738/817/3730 737/818/3731 736/819/3732 -f 739/821/3733 731/805/3734 714/800/3735 -f 714/800/3736 709/794/3737 739/821/3738 -f 741/824/3739 738/817/3740 740/822/3741 -f 740/822/3742 742/823/3743 741/824/3744 -f 744/829/3745 743/830/3746 746/827/3747 -f 746/827/3748 745/828/3749 744/829/3750 -f 747/833/3751 750/834/3752 749/831/3753 -f 749/831/3754 748/832/3755 747/833/3756 -f 751/826/3757 737/818/3758 738/817/3759 -f 738/817/3760 752/825/3761 751/826/3762 -f 751/826/3763 752/825/3764 731/805/3765 -f 731/805/3766 732/816/3767 751/826/3768 -f 753/843/3769 733/844/3770 734/837/3771 -f 734/837/3772 754/838/3773 753/843/3774 -f 753/843/3775 754/838/3776 735/845/3777 -f 735/845/3778 736/846/3779 753/843/3780 -f 755/839/3781 758/840/3782 757/835/3783 -f 757/835/3784 756/836/3785 755/839/3786 -f 761/852/3787 760/853/3788 759/849/3789 -f 759/849/3790 762/850/3791 761/852/3792 -f 740/822/3793 764/842/3794 763/841/3795 -f 763/841/3796 742/823/3797 740/822/3798 -f 765/867/3799 766/868/3800 747/833/3801 -f 747/833/3802 748/832/3803 765/867/3804 -f 710/797/3805 767/847/3806 739/821/3807 -f 739/821/3808 709/794/3809 710/797/3810 -f 768/879/3811 769/880/3812 761/852/3813 -f 761/852/3814 762/850/3815 768/879/3816 -f 770/854/3817 721/855/3818 722/848/3819 -f 722/848/3820 771/851/3821 770/854/3822 -f 772/856/3823 720/857/3824 721/855/3825 -f 721/855/3826 770/854/3827 772/856/3828 -f 775/860/3829 774/861/3830 773/858/3831 -f 773/858/3832 776/859/3833 775/860/3834 -f 778/864/3835 777/865/3836 780/862/3837 -f 780/862/3838 779/863/3839 778/864/3840 -f 780/862/3841 777/865/3842 781/866/3843 -f 781/866/3844 782/869/3845 780/862/3846 -f 781/866/3847 774/861/3848 775/860/3849 -f 775/860/3850 782/869/3851 781/866/3852 -f 773/893/3853 783/894/3854 784/891/3855 -f 784/891/3856 776/892/3857 773/893/3858 -f 784/891/3859 783/894/3860 778/895/3861 -f 778/895/3862 779/896/3863 784/891/3864 -f 787/872/3865 786/873/3866 785/870/3867 -f 785/870/3868 788/871/3869 787/872/3870 -f 790/876/3871 789/877/3872 792/874/3873 -f 792/874/3874 791/875/3875 790/876/3876 -f 792/874/3877 789/877/3878 793/878/3879 -f 793/878/3880 794/881/3881 792/874/3882 -f 793/878/3883 786/873/3884 787/872/3885 -f 787/872/3886 794/881/3887 793/878/3888 -f 788/899/3889 785/905/3890 795/897/3891 -f 795/897/3892 796/898/3893 788/899/3894 -f 795/897/3895 790/907/3896 791/906/3897 -f 791/906/3898 796/898/3899 795/897/3900 -f 797/884/3901 800/885/3902 799/882/3903 -f 799/882/3904 798/883/3905 797/884/3906 -f 801/888/3907 804/889/3908 803/886/3909 -f 803/886/3910 802/887/3911 801/888/3912 -f 805/890/3913 806/900/3914 804/889/3915 -f 804/889/3916 801/888/3917 805/890/3918 -f 798/883/3919 799/882/3920 806/900/3921 -f 806/900/3922 805/890/3923 798/883/3924 -f 807/910/3925 810/911/3926 809/908/3927 -f 809/908/3928 808/909/3929 807/910/3930 -f 811/912/3931 812/913/3932 810/911/3933 -f 810/911/3934 807/910/3935 811/912/3936 -f 800/885/3937 773/858/3938 774/861/3939 -f 774/861/3940 799/882/3941 800/885/3942 -f 804/889/3943 777/865/3944 778/864/3945 -f 778/864/3946 803/886/3947 804/889/3948 -f 806/900/3949 781/866/3950 777/865/3951 -f 777/865/3952 804/889/3953 806/900/3954 -f 799/882/3955 774/861/3956 781/866/3957 -f 781/866/3958 806/900/3959 799/882/3960 -f 810/911/3961 814/915/3962 813/914/3963 -f 813/914/3964 809/908/3965 810/911/3966 -f 812/913/3967 815/916/3968 814/915/3969 -f 814/915/3970 810/911/3971 812/913/3972 -f 776/859/3973 817/902/3974 816/901/3975 -f 816/901/3976 775/860/3977 776/859/3978 -f 780/862/3979 819/904/3980 818/903/3981 -f 818/903/3982 779/863/3983 780/862/3984 -f 782/869/3985 820/935/3986 819/904/3987 -f 819/904/3988 780/862/3989 782/869/3990 -f 775/860/3991 816/901/3992 820/935/3993 -f 820/935/3994 782/869/3995 775/860/3996 -f 821/919/3997 824/920/3998 823/917/3999 -f 823/917/4000 822/918/4001 821/919/4002 -f 825/921/4003 826/922/4004 824/920/4005 -f 824/920/4006 821/919/4007 825/921/4008 -f 817/902/4009 785/870/4010 786/873/4011 -f 786/873/4012 816/901/4013 817/902/4014 -f 819/904/4015 789/877/4016 790/876/4017 -f 790/876/4018 818/903/4019 819/904/4020 -f 820/935/4021 793/878/4022 789/877/4023 -f 789/877/4024 819/904/4025 820/935/4026 -f 816/901/4027 786/873/4028 793/878/4029 -f 793/878/4030 820/935/4031 816/901/4032 -f 824/920/4033 828/924/4034 827/923/4035 -f 827/923/4036 823/917/4037 824/920/4038 -f 826/922/4039 829/925/4040 828/924/4041 -f 828/924/4042 824/920/4043 826/922/4044 -f 807/910/4045 808/909/4046 797/926/4047 -f 797/926/4048 830/927/4049 807/910/4050 -f 811/912/4051 807/910/4052 830/927/4053 -f 830/927/4054 802/928/4055 811/912/4056 -f 812/913/4057 811/912/4058 802/928/4059 -f 802/928/4060 803/929/4061 812/913/4062 -f 815/916/4063 812/913/4064 803/929/4065 -f 803/929/4066 778/895/4067 815/916/4068 -f 814/915/4069 815/916/4070 778/895/4071 -f 778/895/4072 783/894/4073 814/915/4074 -f 813/914/4075 814/915/4076 783/894/4077 -f 783/894/4078 773/893/4079 813/914/4080 -f 809/908/4081 813/914/4082 773/893/4083 -f 773/893/4084 800/930/4085 809/908/4086 -f 808/909/4087 809/908/4088 800/930/4089 -f 800/930/4090 797/926/4091 808/909/4092 -f 821/919/4093 822/918/4094 776/892/4095 -f 776/892/4096 784/891/4097 821/919/4098 -f 825/921/4099 821/919/4100 784/891/4101 -f 784/891/4102 779/896/4103 825/921/4104 -f 826/922/4105 825/921/4106 779/896/4107 -f 779/896/4108 818/931/4109 826/922/4110 -f 829/925/4111 826/922/4112 818/931/4113 -f 818/931/4114 790/907/4115 829/925/4116 -f 828/924/4117 829/925/4118 790/907/4119 -f 790/907/4120 795/897/4121 828/924/4122 -f 827/923/4123 828/924/4124 795/897/4125 -f 795/897/4126 785/905/4127 827/923/4128 -f 823/917/4129 827/923/4130 785/905/4131 -f 785/905/4132 817/932/4133 823/917/4134 -f 822/918/4135 823/917/4136 817/932/4137 -f 817/932/4138 776/892/4139 822/918/4140 -f 772/856/4141 787/872/4142 788/871/4143 -f 788/871/4144 720/857/4145 772/856/4146 -f 791/875/4147 792/874/4148 771/851/4149 -f 771/851/4150 722/848/4151 791/875/4152 -f 771/851/4153 792/874/4154 794/881/4155 -f 794/881/4156 770/854/4157 771/851/4158 -f 794/881/4159 787/872/4160 772/856/4161 -f 772/856/4162 770/854/4163 794/881/4164 -f 832/948/4165 831/949/4166 834/933/4167 -f 834/933/4168 833/934/4169 832/948/4170 -f 831/949/4171 835/964/4172 836/963/4173 -f 836/963/4174 834/933/4175 831/949/4176 -f 838/987/4177 837/988/4178 721/975/4179 -f 721/975/4180 720/976/4181 838/987/4182 -f 839/989/4183 838/987/4184 720/976/4185 -f 720/976/4186 788/899/4187 839/989/4188 -f 840/990/4189 839/989/4190 788/899/4191 -f 788/899/4192 796/898/4193 840/990/4194 -f 841/991/4195 840/990/4196 796/898/4197 -f 796/898/4198 791/906/4199 841/991/4200 -f 842/993/4201 841/991/4202 791/906/4203 -f 791/906/4204 722/992/4205 842/993/4206 -f 837/988/4207 842/993/4208 722/992/4209 -f 722/992/4210 721/975/4211 837/988/4212 -f 833/934/4213 834/933/4214 837/988/4215 -f 837/988/4216 838/987/4217 833/934/4218 -f 832/948/4219 833/934/4220 838/987/4221 -f 838/987/4222 839/989/4223 832/948/4224 -f 831/949/4225 832/948/4226 839/989/4227 -f 839/989/4228 840/990/4229 831/949/4230 -f 835/964/4231 831/949/4232 840/990/4233 -f 840/990/4234 841/991/4235 835/964/4236 -f 836/963/4237 835/964/4238 841/991/4239 -f 841/991/4240 842/993/4241 836/963/4242 -f 834/933/4243 836/963/4244 842/993/4245 -f 842/993/4246 837/988/4247 834/933/4248 -f 845/1001/4249 844/1002/4250 843/994/4251 -f 843/994/4252 846/995/4253 845/1001/4254 -f 848/1003/4255 847/1004/4256 744/829/4257 -f 744/829/4258 745/828/4259 848/1003/4260 -f 850/1005/4261 849/1006/4262 845/1001/4263 -f 845/1001/4264 846/995/4265 850/1005/4266 -f 714/800/4267 731/805/4268 752/825/4269 -f 752/825/4270 713/801/4271 714/800/4272 -f 752/825/4273 738/817/4274 741/824/4275 -f 741/824/4276 713/801/4277 752/825/4278 -f 757/835/4279 767/847/4280 710/797/4281 -f 710/797/4282 756/836/4283 757/835/4284 -f 755/839/4285 851/937/4286 852/936/4287 -f 852/936/4288 758/840/4289 755/839/4290 -f 853/939/4291 763/841/4292 764/842/4293 -f 764/842/4294 854/938/4295 853/939/4296 -f 732/816/4297 733/815/4298 797/884/4299 -f 797/884/4300 798/883/4301 732/816/4302 -f 802/887/4303 736/819/4304 737/818/4305 -f 737/818/4306 801/888/4307 802/887/4308 -f 737/818/4309 751/826/4310 805/890/4311 -f 805/890/4312 801/888/4313 737/818/4314 -f 805/890/4315 751/826/4316 732/816/4317 -f 732/816/4318 798/883/4319 805/890/4320 -f 733/844/4321 753/843/4322 830/927/4323 -f 830/927/4324 797/926/4325 733/844/4326 -f 830/927/4327 753/843/4328 736/846/4329 -f 736/846/4330 802/928/4331 830/927/4332 -f 859/941/4333 858/942/4334 767/847/4335 -f 767/847/4336 860/940/4337 859/941/4338 -f 861/944/4339 734/806/4340 731/805/4341 -f 731/805/4342 862/943/4343 861/944/4344 -f 863/945/4345 862/943/4346 731/805/4347 -f 731/805/4348 739/821/4349 863/945/4350 -f 863/945/4351 739/821/4352 767/847/4353 -f 767/847/4354 858/942/4355 863/945/4356 -f 865/1008/4357 864/1009/4358 734/837/4359 -f 734/837/4360 861/1007/4361 865/1008/4362 -f 866/950/4363 856/951/4364 857/946/4365 -f 857/946/4366 867/947/4367 866/950/4368 -f 868/952/4369 855/953/4370 856/951/4371 -f 856/951/4372 866/950/4373 868/952/4374 -f 871/956/4375 870/957/4376 869/954/4377 -f 869/954/4378 872/955/4379 871/956/4380 -f 874/960/4381 873/961/4382 876/958/4383 -f 876/958/4384 875/959/4385 874/960/4386 -f 876/958/4387 873/961/4388 877/962/4389 -f 877/962/4390 878/965/4391 876/958/4392 -f 877/962/4393 870/957/4394 871/956/4395 -f 871/956/4396 878/965/4397 877/962/4398 -f 869/1012/4399 879/1013/4400 880/1010/4401 -f 880/1010/4402 872/1011/4403 869/1012/4404 -f 880/1010/4405 879/1013/4406 874/1014/4407 -f 874/1014/4408 875/1015/4409 880/1010/4410 -f 883/968/4411 882/969/4412 881/966/4413 -f 881/966/4414 884/967/4415 883/968/4416 -f 886/972/4417 885/973/4418 888/970/4419 -f 888/970/4420 887/971/4421 886/972/4422 -f 888/970/4423 885/973/4424 889/974/4425 -f 889/974/4426 890/977/4427 888/970/4428 -f 889/974/4429 882/969/4430 883/968/4431 -f 883/968/4432 890/977/4433 889/974/4434 -f 884/1018/4435 881/1019/4436 891/1016/4437 -f 891/1016/4438 892/1017/4439 884/1018/4440 -f 891/1016/4441 886/1021/4442 887/1020/4443 -f 887/1020/4444 892/1017/4445 891/1016/4446 -f 893/980/4447 896/981/4448 895/978/4449 -f 895/978/4450 894/979/4451 893/980/4452 -f 897/984/4453 900/985/4454 899/982/4455 -f 899/982/4456 898/983/4457 897/984/4458 -f 901/986/4459 902/996/4460 900/985/4461 -f 900/985/4462 897/984/4463 901/986/4464 -f 894/979/4465 895/978/4466 902/996/4467 -f 902/996/4468 901/986/4469 894/979/4470 -f 903/1032/4471 906/1046/4472 905/1022/4473 -f 905/1022/4474 904/1031/4475 903/1032/4476 -f 907/1047/4477 908/1058/4478 906/1046/4479 -f 906/1046/4480 903/1032/4481 907/1047/4482 -f 896/981/4483 869/954/4484 870/957/4485 -f 870/957/4486 895/978/4487 896/981/4488 -f 900/985/4489 873/961/4490 874/960/4491 -f 874/960/4492 899/982/4493 900/985/4494 -f 902/996/4495 877/962/4496 873/961/4497 -f 873/961/4498 900/985/4499 902/996/4500 -f 895/978/4501 870/957/4502 877/962/4503 -f 877/962/4504 902/996/4505 895/978/4506 -f 906/1046/4507 910/1070/4508 909/1059/4509 -f 909/1059/4510 905/1022/4511 906/1046/4512 -f 908/1058/4513 911/1071/4514 910/1070/4515 -f 910/1070/4516 906/1046/4517 908/1058/4518 -f 872/955/4519 913/998/4520 912/997/4521 -f 912/997/4522 871/956/4523 872/955/4524 -f 876/958/4525 915/1000/4526 914/999/4527 -f 914/999/4528 875/959/4529 876/958/4530 -f 878/965/4531 916/1023/4532 915/1000/4533 -f 915/1000/4534 876/958/4535 878/965/4536 -f 871/956/4537 912/997/4538 916/1023/4539 -f 916/1023/4540 878/965/4541 871/956/4542 -f 917/1074/4543 920/1075/4544 919/1072/4545 -f 919/1072/4546 918/1073/4547 917/1074/4548 -f 921/1076/4549 922/1077/4550 920/1075/4551 -f 920/1075/4552 917/1074/4553 921/1076/4554 -f 913/998/4555 881/966/4556 882/969/4557 -f 882/969/4558 912/997/4559 913/998/4560 -f 915/1000/4561 885/973/4562 886/972/4563 -f 886/972/4564 914/999/4565 915/1000/4566 -f 916/1023/4567 889/974/4568 885/973/4569 -f 885/973/4570 915/1000/4571 916/1023/4572 -f 912/997/4573 882/969/4574 889/974/4575 -f 889/974/4576 916/1023/4577 912/997/4578 -f 920/1075/4579 924/1084/4580 923/1078/4581 -f 923/1078/4582 919/1072/4583 920/1075/4584 -f 922/1077/4585 925/1085/4586 924/1084/4587 -f 924/1084/4588 920/1075/4589 922/1077/4590 -f 903/1032/4591 904/1031/4592 893/1086/4593 -f 893/1086/4594 926/1087/4595 903/1032/4596 -f 907/1047/4597 903/1032/4598 926/1087/4599 -f 926/1087/4600 898/1088/4601 907/1047/4602 -f 908/1058/4603 907/1047/4604 898/1088/4605 -f 898/1088/4606 899/1089/4607 908/1058/4608 -f 911/1071/4609 908/1058/4610 899/1089/4611 -f 899/1089/4612 874/1014/4613 911/1071/4614 -f 910/1070/4615 911/1071/4616 874/1014/4617 -f 874/1014/4618 879/1013/4619 910/1070/4620 -f 909/1059/4621 910/1070/4622 879/1013/4623 -f 879/1013/4624 869/1012/4625 909/1059/4626 -f 905/1022/4627 909/1059/4628 869/1012/4629 -f 869/1012/4630 896/1090/4631 905/1022/4632 -f 904/1031/4633 905/1022/4634 896/1090/4635 -f 896/1090/4636 893/1086/4637 904/1031/4638 -f 917/1074/4639 918/1073/4640 872/1011/4641 -f 872/1011/4642 880/1010/4643 917/1074/4644 -f 921/1076/4645 917/1074/4646 880/1010/4647 -f 880/1010/4648 875/1015/4649 921/1076/4650 -f 922/1077/4651 921/1076/4652 875/1015/4653 -f 875/1015/4654 914/1091/4655 922/1077/4656 -f 925/1085/4657 922/1077/4658 914/1091/4659 -f 914/1091/4660 886/1021/4661 925/1085/4662 -f 924/1084/4663 925/1085/4664 886/1021/4665 -f 886/1021/4666 891/1016/4667 924/1084/4668 -f 923/1078/4669 924/1084/4670 891/1016/4671 -f 891/1016/4672 881/1019/4673 923/1078/4674 -f 919/1072/4675 923/1078/4676 881/1019/4677 -f 881/1019/4678 913/1092/4679 919/1072/4680 -f 918/1073/4681 919/1072/4682 913/1092/4683 -f 913/1092/4684 872/1011/4685 918/1073/4686 -f 868/952/4687 883/968/4688 884/967/4689 -f 884/967/4690 855/953/4691 868/952/4692 -f 887/971/4693 888/970/4694 867/947/4695 -f 867/947/4696 857/946/4697 887/971/4698 -f 867/947/4699 888/970/4700 890/977/4701 -f 890/977/4702 866/950/4703 867/947/4704 -f 890/977/4705 883/968/4706 868/952/4707 -f 868/952/4708 866/950/4709 890/977/4710 -f 928/1095/4711 927/1096/4712 930/1093/4713 -f 930/1093/4714 929/1094/4715 928/1095/4716 -f 927/1096/4717 931/1098/4718 932/1097/4719 -f 932/1097/4720 930/1093/4721 927/1096/4722 -f 934/1101/4723 933/1102/4724 856/1099/4725 -f 856/1099/4726 855/1100/4727 934/1101/4728 -f 935/1103/4729 934/1101/4730 855/1100/4731 -f 855/1100/4732 884/1018/4733 935/1103/4734 -f 936/1104/4735 935/1103/4736 884/1018/4737 -f 884/1018/4738 892/1017/4739 936/1104/4740 -f 937/1105/4741 936/1104/4742 892/1017/4743 -f 892/1017/4744 887/1020/4745 937/1105/4746 -f 938/1115/4747 937/1105/4748 887/1020/4749 -f 887/1020/4750 857/1114/4751 938/1115/4752 -f 933/1102/4753 938/1115/4754 857/1114/4755 -f 857/1114/4756 856/1099/4757 933/1102/4758 -f 929/1094/4759 930/1093/4760 933/1102/4761 -f 933/1102/4762 934/1101/4763 929/1094/4764 -f 928/1095/4765 929/1094/4766 934/1101/4767 -f 934/1101/4768 935/1103/4769 928/1095/4770 -f 927/1096/4771 928/1095/4772 935/1103/4773 -f 935/1103/4774 936/1104/4775 927/1096/4776 -f 931/1098/4777 927/1096/4778 936/1104/4779 -f 936/1104/4780 937/1105/4781 931/1098/4782 -f 932/1097/4783 931/1098/4784 937/1105/4785 -f 937/1105/4786 938/1115/4787 932/1097/4788 -f 930/1093/4789 932/1097/4790 938/1115/4791 -f 938/1115/4792 933/1102/4793 930/1093/4794 -f 858/942/4795 859/941/4796 893/980/4797 -f 893/980/4798 894/979/4799 858/942/4800 -f 898/983/4801 861/944/4802 862/943/4803 -f 862/943/4804 897/984/4805 898/983/4806 -f 862/943/4807 863/945/4808 901/986/4809 -f 901/986/4810 897/984/4811 862/943/4812 -f 901/986/4813 863/945/4814 858/942/4815 -f 858/942/4816 894/979/4817 901/986/4818 -f 859/1129/4819 865/1008/4820 926/1087/4821 -f 926/1087/4822 893/1086/4823 859/1129/4824 -f 926/1087/4825 865/1008/4826 861/1007/4827 -f 861/1007/4828 898/1088/4829 926/1087/4830 -f 943/1024/4831 942/1025/4832 758/840/4833 -f 758/840/4834 852/936/4835 943/1024/4836 -f 944/1027/4837 860/940/4838 767/847/4839 -f 767/847/4840 945/1026/4841 944/1027/4842 -f 946/1028/4843 945/1026/4844 767/847/4845 -f 767/847/4846 757/835/4847 946/1028/4848 -f 946/1028/4849 757/835/4850 758/840/4851 -f 758/840/4852 942/1025/4853 946/1028/4854 -f 947/1142/4855 943/1153/4856 852/1130/4857 -f 852/1130/4858 948/1141/4859 947/1142/4860 -f 947/1142/4861 948/1141/4862 860/1154/4863 -f 860/1154/4864 944/1155/4865 947/1142/4866 -f 949/1033/4867 940/1034/4868 941/1029/4869 -f 941/1029/4870 950/1030/4871 949/1033/4872 -f 951/1035/4873 939/1036/4874 940/1034/4875 -f 940/1034/4876 949/1033/4877 951/1035/4878 -f 954/1039/4879 953/1040/4880 952/1037/4881 -f 952/1037/4882 955/1038/4883 954/1039/4884 -f 957/1043/4885 956/1044/4886 959/1041/4887 -f 959/1041/4888 958/1042/4889 957/1043/4890 -f 959/1041/4891 956/1044/4892 960/1045/4893 -f 960/1045/4894 961/1048/4895 959/1041/4896 -f 960/1045/4897 953/1040/4898 954/1039/4899 -f 954/1039/4900 961/1048/4901 960/1045/4902 -f 952/1158/4903 962/1159/4904 963/1156/4905 -f 963/1156/4906 955/1157/4907 952/1158/4908 -f 963/1156/4909 962/1159/4910 957/1160/4911 -f 957/1160/4912 958/1161/4913 963/1156/4914 -f 966/1051/4915 965/1052/4916 964/1049/4917 -f 964/1049/4918 967/1050/4919 966/1051/4920 -f 969/1055/4921 968/1056/4922 971/1053/4923 -f 971/1053/4924 970/1054/4925 969/1055/4926 -f 971/1053/4927 968/1056/4928 972/1057/4929 -f 972/1057/4930 973/1060/4931 971/1053/4932 -f 972/1057/4933 965/1052/4934 966/1051/4935 -f 966/1051/4936 973/1060/4937 972/1057/4938 -f 967/1169/4939 964/1170/4940 974/1167/4941 -f 974/1167/4942 975/1168/4943 967/1169/4944 -f 974/1167/4945 969/1172/4946 970/1171/4947 -f 970/1171/4948 975/1168/4949 974/1167/4950 -f 976/1063/4951 979/1064/4952 978/1061/4953 -f 978/1061/4954 977/1062/4955 976/1063/4956 -f 980/1067/4957 983/1068/4958 982/1065/4959 -f 982/1065/4960 981/1066/4961 980/1067/4962 -f 984/1069/4963 985/1079/4964 983/1068/4965 -f 983/1068/4966 980/1067/4967 984/1069/4968 -f 977/1062/4969 978/1061/4970 985/1079/4971 -f 985/1079/4972 984/1069/4973 977/1062/4974 -f 986/1175/4975 989/1176/4976 988/1173/4977 -f 988/1173/4978 987/1174/4979 986/1175/4980 -f 990/1177/4981 991/1178/4982 989/1176/4983 -f 989/1176/4984 986/1175/4985 990/1177/4986 -f 979/1064/4987 952/1037/4988 953/1040/4989 -f 953/1040/4990 978/1061/4991 979/1064/4992 -f 983/1068/4993 956/1044/4994 957/1043/4995 -f 957/1043/4996 982/1065/4997 983/1068/4998 -f 985/1079/4999 960/1045/5000 956/1044/5001 -f 956/1044/5002 983/1068/5003 985/1079/5004 -f 978/1061/5005 953/1040/5006 960/1045/5007 -f 960/1045/5008 985/1079/5009 978/1061/5010 -f 989/1176/5011 993/1180/5012 992/1179/5013 -f 992/1179/5014 988/1173/5015 989/1176/5016 -f 991/1178/5017 994/1181/5018 993/1180/5019 -f 993/1180/5020 989/1176/5021 991/1178/5022 -f 955/1038/5023 996/1081/5024 995/1080/5025 -f 995/1080/5026 954/1039/5027 955/1038/5028 -f 959/1041/5029 998/1083/5030 997/1082/5031 -f 997/1082/5032 958/1042/5033 959/1041/5034 -f 961/1048/5035 999/1106/5036 998/1083/5037 -f 998/1083/5038 959/1041/5039 961/1048/5040 -f 954/1039/5041 995/1080/5042 999/1106/5043 -f 999/1106/5044 961/1048/5045 954/1039/5046 -f 1000/1184/5047 1003/1185/5048 1002/1182/5049 -f 1002/1182/5050 1001/1183/5051 1000/1184/5052 -f 1004/1186/5053 1005/1187/5054 1003/1185/5055 -f 1003/1185/5056 1000/1184/5057 1004/1186/5058 -f 996/1081/5059 964/1049/5060 965/1052/5061 -f 965/1052/5062 995/1080/5063 996/1081/5064 -f 998/1083/5065 968/1056/5066 969/1055/5067 -f 969/1055/5068 997/1082/5069 998/1083/5070 -f 999/1106/5071 972/1057/5072 968/1056/5073 -f 968/1056/5074 998/1083/5075 999/1106/5076 -f 995/1080/5077 965/1052/5078 972/1057/5079 -f 972/1057/5080 999/1106/5081 995/1080/5082 -f 1003/1185/5083 1007/1189/5084 1006/1188/5085 -f 1006/1188/5086 1002/1182/5087 1003/1185/5088 -f 1005/1187/5089 1008/1190/5090 1007/1189/5091 -f 1007/1189/5092 1003/1185/5093 1005/1187/5094 -f 986/1175/5095 987/1174/5096 976/1191/5097 -f 976/1191/5098 1009/1192/5099 986/1175/5100 -f 990/1177/5101 986/1175/5102 1009/1192/5103 -f 1009/1192/5104 981/1193/5105 990/1177/5106 -f 991/1178/5107 990/1177/5108 981/1193/5109 -f 981/1193/5110 982/1197/5111 991/1178/5112 -f 994/1181/5113 991/1178/5114 982/1197/5115 -f 982/1197/5116 957/1160/5117 994/1181/5118 -f 993/1180/5119 994/1181/5120 957/1160/5121 -f 957/1160/5122 962/1159/5123 993/1180/5124 -f 992/1179/5125 993/1180/5126 962/1159/5127 -f 962/1159/5128 952/1158/5129 992/1179/5130 -f 988/1173/5131 992/1179/5132 952/1158/5133 -f 952/1158/5134 979/1198/5135 988/1173/5136 -f 987/1174/5137 988/1173/5138 979/1198/5139 -f 979/1198/5140 976/1191/5141 987/1174/5142 -f 1000/1184/5143 1001/1183/5144 955/1157/5145 -f 955/1157/5146 963/1156/5147 1000/1184/5148 -f 1004/1186/5149 1000/1184/5150 963/1156/5151 -f 963/1156/5152 958/1161/5153 1004/1186/5154 -f 1005/1187/5155 1004/1186/5156 958/1161/5157 -f 958/1161/5158 997/1199/5159 1005/1187/5160 -f 1008/1190/5161 1005/1187/5162 997/1199/5163 -f 997/1199/5164 969/1172/5165 1008/1190/5166 -f 1007/1189/5167 1008/1190/5168 969/1172/5169 -f 969/1172/5170 974/1167/5171 1007/1189/5172 -f 1006/1188/5173 1007/1189/5174 974/1167/5175 -f 974/1167/5176 964/1170/5177 1006/1188/5178 -f 1002/1182/5179 1006/1188/5180 964/1170/5181 -f 964/1170/5182 996/1222/5183 1002/1182/5184 -f 1001/1183/5185 1002/1182/5186 996/1222/5187 -f 996/1222/5188 955/1157/5189 1001/1183/5190 -f 951/1035/5191 966/1051/5192 967/1050/5193 -f 967/1050/5194 939/1036/5195 951/1035/5196 -f 970/1054/5197 971/1053/5198 950/1030/5199 -f 950/1030/5200 941/1029/5201 970/1054/5202 -f 950/1030/5203 971/1053/5204 973/1060/5205 -f 973/1060/5206 949/1033/5207 950/1030/5208 -f 973/1060/5209 966/1051/5210 951/1035/5211 -f 951/1035/5212 949/1033/5213 973/1060/5214 -f 1011/1227/5215 1010/1228/5216 1013/1223/5217 -f 1013/1223/5218 1012/1226/5219 1011/1227/5220 -f 1010/1228/5221 1014/1230/5222 1015/1229/5223 -f 1015/1229/5224 1013/1223/5225 1010/1228/5226 -f 1017/1234/5227 1016/1235/5228 940/1231/5229 -f 940/1231/5230 939/1233/5231 1017/1234/5232 -f 1018/1236/5233 1017/1234/5234 939/1233/5235 -f 939/1233/5236 967/1169/5237 1018/1236/5238 -f 1019/1237/5239 1018/1236/5240 967/1169/5241 -f 967/1169/5242 975/1168/5243 1019/1237/5244 -f 1020/1242/5245 1019/1237/5246 975/1168/5247 -f 975/1168/5248 970/1171/5249 1020/1242/5250 -f 1021/1244/5251 1020/1242/5252 970/1171/5253 -f 970/1171/5254 941/1243/5255 1021/1244/5256 -f 1016/1235/5257 1021/1244/5258 941/1243/5259 -f 941/1243/5260 940/1231/5261 1016/1235/5262 -f 1012/1226/5263 1013/1223/5264 1016/1235/5265 -f 1016/1235/5266 1017/1234/5267 1012/1226/5268 -f 1011/1227/5269 1012/1226/5270 1017/1234/5271 -f 1017/1234/5272 1018/1236/5273 1011/1227/5274 -f 1010/1228/5275 1011/1227/5276 1018/1236/5277 -f 1018/1236/5278 1019/1237/5279 1010/1228/5280 -f 1014/1230/5281 1010/1228/5282 1019/1237/5283 -f 1019/1237/5284 1020/1242/5285 1014/1230/5286 -f 1015/1229/5287 1014/1230/5288 1020/1242/5289 -f 1020/1242/5290 1021/1244/5291 1015/1229/5292 -f 1013/1223/5293 1015/1229/5294 1021/1244/5295 -f 1021/1244/5296 1016/1235/5297 1013/1223/5298 -f 942/1025/5299 943/1024/5300 976/1063/5301 -f 976/1063/5302 977/1062/5303 942/1025/5304 -f 981/1066/5305 944/1027/5306 945/1026/5307 -f 945/1026/5308 980/1067/5309 981/1066/5310 -f 945/1026/5311 946/1028/5312 984/1069/5313 -f 984/1069/5314 980/1067/5315 945/1026/5316 -f 984/1069/5317 946/1028/5318 942/1025/5319 -f 942/1025/5320 977/1062/5321 984/1069/5322 -f 943/1153/5323 947/1142/5324 1009/1192/5325 -f 1009/1192/5326 976/1191/5327 943/1153/5328 -f 1009/1192/5329 947/1142/5330 944/1155/5331 -f 944/1155/5332 981/1193/5333 1009/1192/5334 -f 1026/1107/5335 1025/1108/5336 738/817/5337 -f 738/817/5338 735/820/5339 1026/1107/5340 -f 1027/1110/5341 854/938/5342 764/842/5343 -f 764/842/5344 1028/1109/5345 1027/1110/5346 -f 1029/1111/5347 1028/1109/5348 764/842/5349 -f 764/842/5350 740/822/5351 1029/1111/5352 -f 1029/1111/5353 740/822/5354 738/817/5355 -f 738/817/5356 1025/1108/5357 1029/1111/5358 -f 1030/1246/5359 1026/1247/5360 735/845/5361 -f 735/845/5362 1031/1245/5363 1030/1246/5364 -f 1030/1246/5365 1031/1245/5366 854/1253/5367 -f 854/1253/5368 1027/1254/5369 1030/1246/5370 -f 1032/1116/5371 1023/1117/5372 1024/1112/5373 -f 1024/1112/5374 1033/1113/5375 1032/1116/5376 -f 1034/1118/5377 1022/1119/5378 1023/1117/5379 -f 1023/1117/5380 1032/1116/5381 1034/1118/5382 -f 1037/1122/5383 1036/1123/5384 1035/1120/5385 -f 1035/1120/5386 1038/1121/5387 1037/1122/5388 -f 1040/1126/5389 1039/1127/5390 1042/1124/5391 -f 1042/1124/5392 1041/1125/5393 1040/1126/5394 -f 1042/1124/5395 1039/1127/5396 1043/1128/5397 -f 1043/1128/5398 1044/1131/5399 1042/1124/5400 -f 1043/1128/5401 1036/1123/5402 1037/1122/5403 -f 1037/1122/5404 1044/1131/5405 1043/1128/5406 -f 1035/1257/5407 1045/1258/5408 1046/1255/5409 -f 1046/1255/5410 1038/1256/5411 1035/1257/5412 -f 1046/1255/5413 1045/1258/5414 1040/1260/5415 -f 1040/1260/5416 1041/1261/5417 1046/1255/5418 -f 1049/1134/5419 1048/1135/5420 1047/1132/5421 -f 1047/1132/5422 1050/1133/5423 1049/1134/5424 -f 1052/1138/5425 1051/1139/5426 1054/1136/5427 -f 1054/1136/5428 1053/1137/5429 1052/1138/5430 -f 1054/1136/5431 1051/1139/5432 1055/1140/5433 -f 1055/1140/5434 1056/1143/5435 1054/1136/5436 -f 1055/1140/5437 1048/1135/5438 1049/1134/5439 -f 1049/1134/5440 1056/1143/5441 1055/1140/5442 -f 1050/1264/5443 1047/1265/5444 1057/1262/5445 -f 1057/1262/5446 1058/1263/5447 1050/1264/5448 -f 1057/1262/5449 1052/1267/5450 1053/1266/5451 -f 1053/1266/5452 1058/1263/5453 1057/1262/5454 -f 1059/1146/5455 1062/1147/5456 1061/1144/5457 -f 1061/1144/5458 1060/1145/5459 1059/1146/5460 -f 1063/1150/5461 1066/1151/5462 1065/1148/5463 -f 1065/1148/5464 1064/1149/5465 1063/1150/5466 -f 1067/1152/5467 1068/1162/5468 1066/1151/5469 -f 1066/1151/5470 1063/1150/5471 1067/1152/5472 -f 1060/1145/5473 1061/1144/5474 1068/1162/5475 -f 1068/1162/5476 1067/1152/5477 1060/1145/5478 -f 1069/1278/5479 1072/1279/5480 1071/1268/5481 -f 1071/1268/5482 1070/1269/5483 1069/1278/5484 -f 1073/1280/5485 1074/1281/5486 1072/1279/5487 -f 1072/1279/5488 1069/1278/5489 1073/1280/5490 -f 1062/1147/5491 1035/1120/5492 1036/1123/5493 -f 1036/1123/5494 1061/1144/5495 1062/1147/5496 -f 1066/1151/5497 1039/1127/5498 1040/1126/5499 -f 1040/1126/5500 1065/1148/5501 1066/1151/5502 -f 1068/1162/5503 1043/1128/5504 1039/1127/5505 -f 1039/1127/5506 1066/1151/5507 1068/1162/5508 -f 1061/1144/5509 1036/1123/5510 1043/1128/5511 -f 1043/1128/5512 1068/1162/5513 1061/1144/5514 -f 1072/1279/5515 1076/1283/5516 1075/1282/5517 -f 1075/1282/5518 1071/1268/5519 1072/1279/5520 -f 1074/1281/5521 1077/1284/5522 1076/1283/5523 -f 1076/1283/5524 1072/1279/5525 1074/1281/5526 -f 1038/1121/5527 1079/1164/5528 1078/1163/5529 -f 1078/1163/5530 1037/1122/5531 1038/1121/5532 -f 1042/1124/5533 1081/1166/5534 1080/1165/5535 -f 1080/1165/5536 1041/1125/5537 1042/1124/5538 -f 1044/1131/5539 1082/1194/5540 1081/1166/5541 -f 1081/1166/5542 1042/1124/5543 1044/1131/5544 -f 1037/1122/5545 1078/1163/5546 1082/1194/5547 -f 1082/1194/5548 1044/1131/5549 1037/1122/5550 -f 1083/1290/5551 1086/1291/5552 1085/1285/5553 -f 1085/1285/5554 1084/1289/5555 1083/1290/5556 -f 1087/1292/5557 1088/1299/5558 1086/1291/5559 -f 1086/1291/5560 1083/1290/5561 1087/1292/5562 -f 1079/1164/5563 1047/1132/5564 1048/1135/5565 -f 1048/1135/5566 1078/1163/5567 1079/1164/5568 -f 1081/1166/5569 1051/1139/5570 1052/1138/5571 -f 1052/1138/5572 1080/1165/5573 1081/1166/5574 -f 1082/1194/5575 1055/1140/5576 1051/1139/5577 -f 1051/1139/5578 1081/1166/5579 1082/1194/5580 -f 1078/1163/5581 1048/1135/5582 1055/1140/5583 -f 1055/1140/5584 1082/1194/5585 1078/1163/5586 -f 1086/1291/5587 1090/1307/5588 1089/1306/5589 -f 1089/1306/5590 1085/1285/5591 1086/1291/5592 -f 1088/1299/5593 1091/1308/5594 1090/1307/5595 -f 1090/1307/5596 1086/1291/5597 1088/1299/5598 -f 1069/1278/5599 1070/1269/5600 1059/1309/5601 -f 1059/1309/5602 1092/1310/5603 1069/1278/5604 -f 1073/1280/5605 1069/1278/5606 1092/1310/5607 -f 1092/1310/5608 1064/1311/5609 1073/1280/5610 -f 1074/1281/5611 1073/1280/5612 1064/1311/5613 -f 1064/1311/5614 1065/1312/5615 1074/1281/5616 -f 1077/1284/5617 1074/1281/5618 1065/1312/5619 -f 1065/1312/5620 1040/1260/5621 1077/1284/5622 -f 1076/1283/5623 1077/1284/5624 1040/1260/5625 -f 1040/1260/5626 1045/1258/5627 1076/1283/5628 -f 1075/1282/5629 1076/1283/5630 1045/1258/5631 -f 1045/1258/5632 1035/1257/5633 1075/1282/5634 -f 1071/1268/5635 1075/1282/5636 1035/1257/5637 -f 1035/1257/5638 1062/1313/5639 1071/1268/5640 -f 1070/1269/5641 1071/1268/5642 1062/1313/5643 -f 1062/1313/5644 1059/1309/5645 1070/1269/5646 -f 1083/1290/5647 1084/1289/5648 1038/1256/5649 -f 1038/1256/5650 1046/1255/5651 1083/1290/5652 -f 1087/1292/5653 1083/1290/5654 1046/1255/5655 -f 1046/1255/5656 1041/1261/5657 1087/1292/5658 -f 1088/1299/5659 1087/1292/5660 1041/1261/5661 -f 1041/1261/5662 1080/1314/5663 1088/1299/5664 -f 1091/1308/5665 1088/1299/5666 1080/1314/5667 -f 1080/1314/5668 1052/1267/5669 1091/1308/5670 -f 1090/1307/5671 1091/1308/5672 1052/1267/5673 -f 1052/1267/5674 1057/1262/5675 1090/1307/5676 -f 1089/1306/5677 1090/1307/5678 1057/1262/5679 -f 1057/1262/5680 1047/1265/5681 1089/1306/5682 -f 1085/1285/5683 1089/1306/5684 1047/1265/5685 -f 1047/1265/5686 1079/1315/5687 1085/1285/5688 -f 1084/1289/5689 1085/1285/5690 1079/1315/5691 -f 1079/1315/5692 1038/1256/5693 1084/1289/5694 -f 1034/1118/5695 1049/1134/5696 1050/1133/5697 -f 1050/1133/5698 1022/1119/5699 1034/1118/5700 -f 1053/1137/5701 1054/1136/5702 1033/1113/5703 -f 1033/1113/5704 1024/1112/5705 1053/1137/5706 -f 1033/1113/5707 1054/1136/5708 1056/1143/5709 -f 1056/1143/5710 1032/1116/5711 1033/1113/5712 -f 1056/1143/5713 1049/1134/5714 1034/1118/5715 -f 1034/1118/5716 1032/1116/5717 1056/1143/5718 -f 1094/1318/5719 1093/1319/5720 1096/1316/5721 -f 1096/1316/5722 1095/1317/5723 1094/1318/5724 -f 1093/1319/5725 1097/1321/5726 1098/1320/5727 -f 1098/1320/5728 1096/1316/5729 1093/1319/5730 -f 1100/1324/5731 1099/1325/5732 1023/1322/5733 -f 1023/1322/5734 1022/1323/5735 1100/1324/5736 -f 1101/1326/5737 1100/1324/5738 1022/1323/5739 -f 1022/1323/5740 1050/1264/5741 1101/1326/5742 -f 1102/1327/5743 1101/1326/5744 1050/1264/5745 -f 1050/1264/5746 1058/1263/5747 1102/1327/5748 -f 1103/1328/5749 1102/1327/5750 1058/1263/5751 -f 1058/1263/5752 1053/1266/5753 1103/1328/5754 -f 1104/1330/5755 1103/1328/5756 1053/1266/5757 -f 1053/1266/5758 1024/1329/5759 1104/1330/5760 -f 1099/1325/5761 1104/1330/5762 1024/1329/5763 -f 1024/1329/5764 1023/1322/5765 1099/1325/5766 -f 1095/1317/5767 1096/1316/5768 1099/1325/5769 -f 1099/1325/5770 1100/1324/5771 1095/1317/5772 -f 1094/1318/5773 1095/1317/5774 1100/1324/5775 -f 1100/1324/5776 1101/1326/5777 1094/1318/5778 -f 1093/1319/5779 1094/1318/5780 1101/1326/5781 -f 1101/1326/5782 1102/1327/5783 1093/1319/5784 -f 1097/1321/5785 1093/1319/5786 1102/1327/5787 -f 1102/1327/5788 1103/1328/5789 1097/1321/5790 -f 1098/1320/5791 1097/1321/5792 1103/1328/5793 -f 1103/1328/5794 1104/1330/5795 1098/1320/5796 -f 1096/1316/5797 1098/1320/5798 1104/1330/5799 -f 1104/1330/5800 1099/1325/5801 1096/1316/5802 -f 1025/1108/5803 1026/1107/5804 1059/1146/5805 -f 1059/1146/5806 1060/1145/5807 1025/1108/5808 -f 1064/1149/5809 1027/1110/5810 1028/1109/5811 -f 1028/1109/5812 1063/1150/5813 1064/1149/5814 -f 1028/1109/5815 1029/1111/5816 1067/1152/5817 -f 1067/1152/5818 1063/1150/5819 1028/1109/5820 -f 1067/1152/5821 1029/1111/5822 1025/1108/5823 -f 1025/1108/5824 1060/1145/5825 1067/1152/5826 -f 1026/1247/5827 1030/1246/5828 1092/1310/5829 -f 1092/1310/5830 1059/1309/5831 1026/1247/5832 -f 1092/1310/5833 1030/1246/5834 1027/1254/5835 -f 1027/1254/5836 1064/1311/5837 1092/1310/5838 -f 750/834/5839 747/833/5840 1031/1245/5841 -f 1031/1245/5842 735/845/5843 750/834/5844 -f 749/831/5845 750/834/5846 735/845/5847 -f 735/845/5848 1105/1331/5849 749/831/5850 -f 748/832/5851 749/831/5852 1105/1331/5853 -f 1105/1331/5854 1106/1332/5855 748/832/5856 -f 765/867/5857 748/832/5858 1106/1332/5859 -f 1106/1332/5860 853/1333/5861 765/867/5862 -f 766/868/5863 765/867/5864 853/1333/5865 -f 853/1333/5866 854/1253/5867 766/868/5868 -f 747/833/5869 766/868/5870 854/1253/5871 -f 854/1253/5872 1031/1245/5873 747/833/5874 -f 743/830/5875 744/829/5876 754/838/5877 -f 754/838/5878 734/837/5879 743/830/5880 -f 746/827/5881 743/830/5882 734/837/5883 -f 734/837/5884 1107/1334/5885 746/827/5886 -f 745/828/5887 746/827/5888 1107/1334/5889 -f 1107/1334/5890 1108/1335/5891 745/828/5892 -f 848/1003/5893 745/828/5894 1108/1335/5895 -f 1108/1335/5896 1105/1331/5897 848/1003/5898 -f 847/1004/5899 848/1003/5900 1105/1331/5901 -f 1105/1331/5902 735/845/5903 847/1004/5904 -f 744/829/5905 847/1004/5906 735/845/5907 -f 735/845/5908 754/838/5909 744/829/5910 -f 845/1001/5911 849/1006/5912 734/837/5913 -f 734/837/5914 864/1009/5915 845/1001/5916 -f 844/1002/5917 845/1001/5918 864/1009/5919 -f 864/1009/5920 860/1154/5921 844/1002/5922 -f 843/994/5923 844/1002/5924 860/1154/5925 -f 860/1154/5926 727/814/5927 843/994/5928 -f 846/995/5929 843/994/5930 727/814/5931 -f 727/814/5932 1109/1336/5933 846/995/5934 -f 850/1005/5935 846/995/5936 1109/1336/5937 -f 1109/1336/5938 1107/1334/5939 850/1005/5940 -f 849/1006/5941 850/1005/5942 1107/1334/5943 -f 1107/1334/5944 734/837/5945 849/1006/5946 -f 760/853/5947 761/852/5948 948/1141/5949 -f 948/1141/5950 852/1130/5951 760/853/5952 -f 759/849/5953 760/853/5954 852/1130/5955 -f 852/1130/5956 851/1337/5957 759/849/5958 -f 762/850/5959 759/849/5960 851/1337/5961 -f 851/1337/5962 730/811/5963 762/850/5964 -f 768/879/5965 762/850/5966 730/811/5967 -f 730/811/5968 727/814/5969 768/879/5970 -f 769/880/5971 768/879/5972 727/814/5973 -f 727/814/5974 860/1154/5975 769/880/5976 -f 761/852/5977 769/880/5978 860/1154/5979 -f 860/1154/5980 948/1141/5981 761/852/5982 -f 859/1129/5983 860/1154/5984 864/1009/5985 -f 864/1009/5986 865/1008/5987 859/1129/5988 -f 755/839/5989 1111/1196/5990 1110/1195/5991 -f 1110/1195/5992 851/937/5993 755/839/5994 -f 712/795/5995 1112/1200/5996 718/804/5997 -f 718/804/5998 711/796/5999 712/795/6000 -f 1109/1336/6001 1114/1339/6002 1113/1338/6003 -f 1113/1338/6004 1107/1334/6005 1109/1336/6006 -f 719/803/6007 756/836/6008 710/797/6009 -f 710/797/6010 711/796/6011 719/803/6012 -f 725/808/6013 1115/1340/6014 1106/1332/6015 -f 1106/1332/6016 1105/1331/6017 725/808/6018 -f 1108/1335/6019 724/809/6020 725/808/6021 -f 725/808/6022 1105/1331/6023 1108/1335/6024 -f 1118/1203/6025 1117/1204/6026 1116/1201/6027 -f 1116/1201/6028 1119/1202/6029 1118/1203/6030 -f 1121/1205/6031 1120/1206/6032 1116/1201/6033 -f 1116/1201/6034 1117/1204/6035 1121/1205/6036 -f 1123/1208/6037 1122/1209/6038 1121/1205/6039 -f 1121/1205/6040 1124/1207/6041 1123/1208/6042 -f 1117/1204/6043 1118/1203/6044 1126/1210/6045 -f 1126/1210/6046 1125/1211/6047 1117/1204/6048 -f 1124/1207/6049 1121/1205/6050 1117/1204/6051 -f 1117/1204/6052 1125/1211/6053 1124/1207/6054 -f 707/793/6055 1129/792/6056 1127/1212/6057 -f 1127/1212/6058 1128/1213/6059 707/793/6060 -f 1131/1216/6061 1130/1217/6062 1133/1214/6063 -f 1133/1214/6064 1132/1215/6065 1131/1216/6066 -f 1135/1218/6067 1134/1219/6068 1131/1216/6069 -f 1131/1216/6070 1132/1215/6071 1135/1218/6072 -f 1130/1217/6073 1136/1221/6074 1137/1220/6075 -f 1137/1220/6076 1133/1214/6077 1130/1217/6078 -f 1136/1343/6079 1138/1344/6080 1139/1341/6081 -f 1139/1341/6082 1137/1342/6083 1136/1343/6084 -f 1138/1344/6085 1140/1346/6086 1141/1345/6087 -f 1141/1345/6088 1139/1341/6089 1138/1344/6090 -f 1141/1224/6091 1140/1225/6092 1134/1219/6093 -f 1134/1219/6094 1135/1218/6095 1141/1224/6096 -f 1142/1349/6097 1145/2379/6098 1144/1347/6099 -f 1144/1347/6100 1143/1348/6101 1142/1349/6102 -f 1146/2380/6103 1147/2381/6104 1145/2379/6105 -f 1145/2379/6106 1142/1349/6107 1146/2380/6108 -f 1126/1210/6109 1130/1217/6110 1131/1216/6111 -f 1131/1216/6112 1125/1211/6113 1126/1210/6114 -f 1125/1211/6115 1131/1216/6116 1134/1219/6117 -f 1134/1219/6118 1124/1207/6119 1125/1211/6120 -f 1148/1232/6121 1136/1221/6122 1130/1217/6123 -f 1130/1217/6124 1126/1210/6125 1148/1232/6126 -f 1145/2379/6127 1150/2384/6128 1149/2382/6129 -f 1149/2382/6130 1144/1347/6131 1145/2379/6132 -f 1147/2381/6133 1151/2385/6134 1150/2384/6135 -f 1150/2384/6136 1145/2379/6137 1147/2381/6138 -f 1124/1207/6139 1134/1219/6140 1140/1225/6141 -f 1140/1225/6142 1123/1208/6143 1124/1207/6144 -f 1142/1349/6145 1143/1348/6146 1152/2386/6147 -f 1152/2386/6148 1153/2387/6149 1142/1349/6150 -f 1146/2380/6151 1142/1349/6152 1153/2387/6153 -f 1153/2387/6154 1122/2388/6155 1146/2380/6156 -f 1147/2381/6157 1146/2380/6158 1122/2388/6159 -f 1122/2388/6160 1123/2389/6161 1147/2381/6162 -f 1151/2385/6163 1147/2381/6164 1123/2389/6165 -f 1123/2389/6166 1140/1346/6167 1151/2385/6168 -f 1150/2384/6169 1151/2385/6170 1140/1346/6171 -f 1140/1346/6172 1138/1344/6173 1150/2384/6174 -f 1149/2382/6175 1150/2384/6176 1138/1344/6177 -f 1138/1344/6178 1136/1343/6179 1149/2382/6180 -f 1144/1347/6181 1149/2382/6182 1136/1343/6183 -f 1136/1343/6184 1148/2390/6185 1144/1347/6186 -f 1143/1348/6187 1144/1347/6188 1148/2390/6189 -f 1148/2390/6190 1152/2386/6191 1143/1348/6192 -f 707/793/6193 1155/1239/6194 1154/1238/6195 -f 1154/1238/6196 706/790/6197 707/793/6198 -f 1128/1213/6199 1156/1240/6200 1155/1239/6201 -f 1155/1239/6202 707/793/6203 1128/1213/6204 -f 1154/1238/6205 1157/1241/6206 708/791/6207 -f 708/791/6208 706/790/6209 1154/1238/6210 -f 1159/2393/6211 1158/2394/6212 1161/2391/6213 -f 1161/2391/6214 1160/2392/6215 1159/2393/6216 -f 1158/2394/6217 1162/2396/6218 1163/2395/6219 -f 1163/2395/6220 1161/2391/6221 1158/2394/6222 -f 1164/1248/6223 1156/1240/6224 1128/1213/6225 -f 1128/1213/6226 1127/1212/6227 1164/1248/6228 -f 1133/1214/6229 1166/1250/6230 1165/1249/6231 -f 1165/1249/6232 1132/1215/6233 1133/1214/6234 -f 1132/1215/6235 1165/1249/6236 1167/1251/6237 -f 1167/1251/6238 1135/1218/6239 1132/1215/6240 -f 1137/1220/6241 1168/1252/6242 1166/1250/6243 -f 1166/1250/6244 1133/1214/6245 1137/1220/6246 -f 1169/2399/6247 1172/2400/6248 1171/2397/6249 -f 1171/2397/6250 1170/2398/6251 1169/2399/6252 -f 1173/2401/6253 1174/2402/6254 1172/2400/6255 -f 1172/2400/6256 1169/2399/6257 1173/2401/6258 -f 1135/1218/6259 1167/1251/6260 1175/1259/6261 -f 1175/1259/6262 1141/1224/6263 1135/1218/6264 -f 1166/1250/6265 1154/1238/6266 1155/1239/6267 -f 1155/1239/6268 1165/1249/6269 1166/1250/6270 -f 1165/1249/6271 1155/1239/6272 1156/1240/6273 -f 1156/1240/6274 1167/1251/6275 1165/1249/6276 -f 1168/1252/6277 1157/1241/6278 1154/1238/6279 -f 1154/1238/6280 1166/1250/6281 1168/1252/6282 -f 1172/2400/6283 1177/2404/6284 1176/2403/6285 -f 1176/2403/6286 1171/2397/6287 1172/2400/6288 -f 1174/2402/6289 1178/2405/6290 1177/2404/6291 -f 1177/2404/6292 1172/2400/6293 1174/2402/6294 -f 1167/1251/6295 1156/1240/6296 1164/1248/6297 -f 1164/1248/6298 1175/1259/6299 1167/1251/6300 -f 1169/2399/6301 1170/2398/6302 1137/1342/6303 -f 1137/1342/6304 1139/1341/6305 1169/2399/6306 -f 1173/2401/6307 1169/2399/6308 1139/1341/6309 -f 1139/1341/6310 1141/1345/6311 1173/2401/6312 -f 1174/2402/6313 1173/2401/6314 1141/1345/6315 -f 1141/1345/6316 1175/2406/6317 1174/2402/6318 -f 1178/2405/6319 1174/2402/6320 1175/2406/6321 -f 1175/2406/6322 1164/2407/6323 1178/2405/6324 -f 1177/2404/6325 1178/2405/6326 1164/2407/6327 -f 1164/2407/6328 1179/2408/6329 1177/2404/6330 -f 1176/2403/6331 1177/2404/6332 1179/2408/6333 -f 1179/2408/6334 1157/2409/6335 1176/2403/6336 -f 1171/2397/6337 1176/2403/6338 1157/2409/6339 -f 1157/2409/6340 1168/2410/6341 1171/2397/6342 -f 1170/2398/6343 1171/2397/6344 1168/2410/6345 -f 1168/2410/6346 1137/1342/6347 1170/2398/6348 -f 1181/2413/6349 1180/2414/6350 1129/2411/6351 -f 1129/2411/6352 708/2412/6353 1181/2413/6354 -f 1182/2415/6355 1181/2413/6356 708/2412/6357 -f 708/2412/6358 1157/2409/6359 1182/2415/6360 -f 1183/2416/6361 1182/2415/6362 1157/2409/6363 -f 1157/2409/6364 1179/2408/6365 1183/2416/6366 -f 1184/2417/6367 1183/2416/6368 1179/2408/6369 -f 1179/2408/6370 1164/2407/6371 1184/2417/6372 -f 1185/2419/6373 1184/2417/6374 1164/2407/6375 -f 1164/2407/6376 1127/2418/6377 1185/2419/6378 -f 1180/2414/6379 1185/2419/6380 1127/2418/6381 -f 1127/2418/6382 1129/2411/6383 1180/2414/6384 -f 1160/2392/6385 1161/2391/6386 1180/2414/6387 -f 1180/2414/6388 1181/2413/6389 1160/2392/6390 -f 1159/2393/6391 1160/2392/6392 1181/2413/6393 -f 1181/2413/6394 1182/2415/6395 1159/2393/6396 -f 1158/2394/6397 1159/2393/6398 1182/2415/6399 -f 1182/2415/6400 1183/2416/6401 1158/2394/6402 -f 1162/2396/6403 1158/2394/6404 1183/2416/6405 -f 1183/2416/6406 1184/2417/6407 1162/2396/6408 -f 1163/2395/6409 1162/2396/6410 1184/2417/6411 -f 1184/2417/6412 1185/2419/6413 1163/2395/6414 -f 1161/2391/6415 1163/2395/6416 1185/2419/6417 -f 1185/2419/6418 1180/2414/6419 1161/2391/6420 -f 741/824/6421 742/823/6422 1186/1270/6423 -f 1186/1270/6424 1187/1271/6425 741/824/6426 -f 1188/1274/6427 1191/1275/6428 1190/1272/6429 -f 1190/1272/6430 1189/1273/6431 1188/1274/6432 -f 1192/1276/6433 1112/1200/6434 712/795/6435 -f 712/795/6436 715/799/6437 1192/1276/6438 -f 1110/2420/6439 729/812/6440 730/811/6441 -f 730/811/6442 851/1337/6443 1110/2420/6444 -f 1194/2423/6445 1193/2424/6446 704/2421/6447 -f 704/2421/6448 705/2422/6449 1194/2423/6450 -f 728/813/6451 1114/1339/6452 1109/1336/6453 -f 1109/1336/6454 727/814/6455 728/813/6456 -f 1197/2426/6457 1196/2427/6458 1195/2425/6459 -f 1195/2425/6460 726/807/6461 1197/2426/6462 -f 725/808/6463 726/807/6464 1195/2425/6465 -f 1195/2425/6466 1115/1340/6467 725/808/6468 -f 1198/2430/6469 1118/2431/6470 1119/2428/6471 -f 1119/2428/6472 1199/2429/6473 1198/2430/6474 -f 1113/1338/6475 724/809/6476 1108/1335/6477 -f 1108/1335/6478 1107/1334/6479 1113/1338/6480 -f 1197/2426/6481 726/807/6482 723/810/6483 -f 723/810/6484 1200/2432/6485 1197/2426/6486 -f 1113/1338/6487 1201/2433/6488 723/810/6489 -f 723/810/6490 724/809/6491 1113/1338/6492 -f 1202/1277/6493 1186/1270/6494 742/823/6495 -f 742/823/6496 763/841/6497 1202/1277/6498 -f 853/939/6499 1203/1286/6500 1202/1277/6501 -f 1202/1277/6502 763/841/6503 853/939/6504 -f 1106/1332/6505 1115/1340/6506 1203/2434/6507 -f 1203/2434/6508 853/1333/6509 1106/1332/6510 -f 1204/1287/6511 1192/1276/6512 715/799/6513 -f 715/799/6514 716/798/6515 1204/1287/6516 -f 1205/2435/6517 1199/2429/6518 1115/1340/6519 -f 1115/1340/6520 1195/2425/6521 1205/2435/6522 -f 1206/2436/6523 1205/2435/6524 1195/2425/6525 -f 1195/2425/6526 1196/2427/6527 1206/2436/6528 -f 1207/2438/6529 1206/2436/6530 1196/2427/6531 -f 1196/2427/6532 1208/2437/6533 1207/2438/6534 -f 1209/2440/6535 1207/2438/6536 1208/2437/6537 -f 1208/2437/6538 1191/2439/6539 1209/2440/6540 -f 1210/1288/6541 1209/1293/6542 1191/1275/6543 -f 1191/1275/6544 1188/1274/6545 1210/1288/6546 -f 1187/1271/6547 1211/1294/6548 1204/1287/6549 -f 1204/1287/6550 716/798/6551 1187/1271/6552 -f 1211/1294/6553 1210/1288/6554 1188/1274/6555 -f 1188/1274/6556 1204/1287/6557 1211/1294/6558 -f 1213/1295/6559 1212/1296/6560 1120/1206/6561 -f 1120/1206/6562 1121/1205/6563 1213/1295/6564 -f 1153/2387/6565 1152/2386/6566 1206/2436/6567 -f 1206/2436/6568 1207/2438/6569 1153/2387/6570 -f 1209/2440/6571 1122/2388/6572 1153/2387/6573 -f 1153/2387/6574 1207/2438/6575 1209/2440/6576 -f 1214/1297/6577 1122/1209/6578 1209/1293/6579 -f 1209/1293/6580 1210/1288/6581 1214/1297/6582 -f 1211/1294/6583 1213/1295/6584 1214/1297/6585 -f 1214/1297/6586 1210/1288/6587 1211/1294/6588 -f 1187/1271/6589 1212/1296/6590 1213/1295/6591 -f 1213/1295/6592 1211/1294/6593 1187/1271/6594 -f 1186/1270/6595 1120/1206/6596 1212/1296/6597 -f 1212/1296/6598 1187/1271/6599 1186/1270/6600 -f 1203/1286/6601 1119/1202/6602 1116/1201/6603 -f 1116/1201/6604 1202/1277/6605 1203/1286/6606 -f 1199/2429/6607 1119/2428/6608 1203/2434/6609 -f 1203/2434/6610 1115/1340/6611 1199/2429/6612 -f 1206/2436/6613 1152/2386/6614 1215/2441/6615 -f 1215/2441/6616 1205/2435/6617 1206/2436/6618 -f 1116/1201/6619 1120/1206/6620 1186/1270/6621 -f 1186/1270/6622 1202/1277/6623 1116/1201/6624 -f 1198/2430/6625 1199/2429/6626 1205/2435/6627 -f 1205/2435/6628 1215/2441/6629 1198/2430/6630 -f 1198/2430/6631 1215/2441/6632 1216/2442/6633 -f 1216/2442/6634 1118/2431/6635 1198/2430/6636 -f 702/789/6637 703/788/6638 1217/1298/6639 -f 1217/1298/6640 1218/1300/6641 702/789/6642 -f 755/839/6643 756/836/6644 719/803/6645 -f 719/803/6646 1111/1196/6647 755/839/6648 -f 1194/2423/6649 729/812/6650 1110/2420/6651 -f 1110/2420/6652 1193/2424/6653 1194/2423/6654 -f 1219/1301/6655 1193/1302/6656 1110/1195/6657 -f 1110/1195/6658 1111/1196/6659 1219/1301/6660 -f 717/802/6661 1219/1301/6662 1111/1196/6663 -f 1111/1196/6664 719/803/6665 717/802/6666 -f 716/798/6667 713/801/6668 741/824/6669 -f 741/824/6670 1187/1271/6671 716/798/6672 -f 715/799/6673 712/795/6674 709/794/6675 -f 709/794/6676 714/800/6677 715/799/6678 -f 1112/1200/6679 1192/1276/6680 1189/1273/6681 -f 1189/1273/6682 1220/1303/6683 1112/1200/6684 -f 1204/1287/6685 1188/1274/6686 1189/1273/6687 -f 1189/1273/6688 1192/1276/6689 1204/1287/6690 -f 1217/1298/6691 1221/1304/6692 1220/1303/6693 -f 1220/1303/6694 1218/1300/6695 1217/1298/6696 -f 703/788/6697 704/787/6698 1193/1302/6699 -f 1193/1302/6700 1219/1301/6701 703/788/6702 -f 717/802/6703 1217/1298/6704 703/788/6705 -f 703/788/6706 1219/1301/6707 717/802/6708 -f 1221/1304/6709 1217/1298/6710 717/802/6711 -f 717/802/6712 718/804/6713 1221/1304/6714 -f 1112/1200/6715 1220/1303/6716 1221/1304/6717 -f 1221/1304/6718 718/804/6719 1112/1200/6720 -f 1190/1272/6721 1218/1300/6722 1220/1303/6723 -f 1220/1303/6724 1189/1273/6725 1190/1272/6726 -f 1223/2444/6727 1222/2445/6728 705/2574/6729 -f 705/2574/6730 702/2443/6731 1223/2444/6732 -f 1224/2447/6733 1223/2444/6734 702/2443/6735 -f 702/2443/6736 1218/2446/6737 1224/2447/6738 -f 1225/2449/6739 1224/2447/6740 1218/2446/6741 -f 1218/2446/6742 1190/2448/6743 1225/2449/6744 -f 1226/2450/6745 1225/2449/6746 1190/2448/6747 -f 1190/2448/6748 1191/2439/6749 1226/2450/6750 -f 1227/2451/6751 1226/2450/6752 1191/2439/6753 -f 1191/2439/6754 1208/2437/6755 1227/2451/6756 -f 1228/2452/6757 1227/2451/6758 1208/2437/6759 -f 1208/2437/6760 1196/2427/6761 1228/2452/6762 -f 1229/2453/6763 1228/2452/6764 1196/2427/6765 -f 1196/2427/6766 1197/2426/6767 1229/2453/6768 -f 1230/2454/6769 1229/2453/6770 1197/2426/6771 -f 1197/2426/6772 1200/2432/6773 1230/2454/6774 -f 1231/2456/6775 1230/2454/6776 1200/2432/6777 -f 1200/2432/6778 1232/2455/6779 1231/2456/6780 -f 1194/2423/6781 705/2422/6782 1233/2457/6783 -f 1233/2457/6784 1234/2458/6785 1194/2423/6786 -f 1201/2433/6787 1232/2455/6788 1200/2432/6789 -f 1200/2432/6790 723/810/6791 1201/2433/6792 -f 1235/2460/6793 1222/2445/6794 1223/2444/6795 -f 1223/2444/6796 1236/2459/6797 1235/2460/6798 -f 1237/2461/6799 1236/2459/6800 1223/2444/6801 -f 1223/2444/6802 1224/2447/6803 1237/2461/6804 -f 1237/2461/6805 1224/2447/6806 1225/2449/6807 -f 1225/2449/6808 1238/2462/6809 1237/2461/6810 -f 1238/2462/6811 1225/2449/6812 1226/2450/6813 -f 1226/2450/6814 1239/2463/6815 1238/2462/6816 -f 1239/2463/6817 1226/2450/6818 1227/2451/6819 -f 1227/2451/6820 1240/2464/6821 1239/2463/6822 -f 1241/2465/6823 1240/2464/6824 1227/2451/6825 -f 1227/2451/6826 1228/2452/6827 1241/2465/6828 -f 1242/2466/6829 1241/2465/6830 1228/2452/6831 -f 1228/2452/6832 1229/2453/6833 1242/2466/6834 -f 1243/2467/6835 1242/2466/6836 1229/2453/6837 -f 1229/2453/6838 1230/2454/6839 1243/2467/6840 -f 1243/2467/6841 1230/2454/6842 1231/2456/6843 -f 1231/2456/6844 1244/2468/6845 1243/2467/6846 -f 1244/2468/6847 1231/2456/6848 1222/2575/6849 -f 1222/2575/6850 1235/2576/6851 1244/2468/6852 -f 1213/1295/6853 1121/1205/6854 1122/1209/6855 -f 1122/1209/6856 1214/1297/6857 1213/1295/6858 -f 1118/1203/6859 1216/1305/6860 1148/1232/6861 -f 1148/1232/6862 1126/1210/6863 1118/1203/6864 -f 1148/2390/6865 1216/2442/6866 1215/2441/6867 -f 1215/2441/6868 1152/2386/6869 1148/2390/6870 -f 1247/2471/6871 1246/2472/6872 1245/2469/6873 -f 1245/2469/6874 1248/2470/6875 1247/2471/6876 -f 1250/2473/6877 1249/2474/6878 1247/2471/6879 -f 1247/2471/6880 1248/2470/6881 1250/2473/6882 -f 1251/2476/6883 1249/2474/6884 1250/2473/6885 -f 1250/2473/6886 1252/2475/6887 1251/2476/6888 -f 1246/2578/6889 1261/2478/6890 1260/2477/6891 -f 1260/2477/6892 1245/2577/6893 1246/2578/6894 -f 1194/2423/6895 1234/2458/6896 728/813/6897 -f 728/813/6898 729/812/6899 1194/2423/6900 -f 1262/2479/6901 1114/1339/6902 728/813/6903 -f 728/813/6904 1234/2458/6905 1262/2479/6906 -f 1114/1339/6907 1262/2479/6908 1201/2433/6909 -f 1201/2433/6910 1113/1338/6911 1114/1339/6912 -f 1263/2480/6913 1262/2479/6914 1234/2458/6915 -f 1234/2458/6916 1233/2457/6917 1263/2480/6918 -f 1264/2481/6919 1233/2457/6920 705/2422/6921 -f 705/2422/6922 1222/2575/6923 1264/2481/6924 -f 1231/2456/6925 1265/2482/6926 1264/2481/6927 -f 1264/2481/6928 1222/2575/6929 1231/2456/6930 -f 1263/2480/6931 1233/2457/6932 1264/2481/6933 -f 1264/2481/6934 1265/2482/6935 1263/2480/6936 -f 1232/2455/6937 1263/2480/6938 1265/2482/6939 -f 1265/2482/6940 1231/2456/6941 1232/2455/6942 -f 1262/2479/6943 1263/2480/6944 1232/2455/6945 -f 1232/2455/6946 1201/2433/6947 1262/2479/6948 -f 1260/2477/6949 1258/2483/6950 1243/2467/6951 -f 1243/2467/6952 1244/2468/6953 1260/2477/6954 -f 1257/2484/6955 1242/2466/6956 1243/2467/6957 -f 1243/2467/6958 1258/2483/6959 1257/2484/6960 -f 1256/2486/6961 1241/2465/6962 1242/2466/6963 -f 1242/2466/6964 1257/2484/6965 1256/2486/6966 -f 1255/2487/6967 1240/2464/6968 1241/2465/6969 -f 1241/2465/6970 1256/2486/6971 1255/2487/6972 -f 1254/2488/6973 1239/2463/6974 1240/2464/6975 -f 1240/2464/6976 1255/2487/6977 1254/2488/6978 -f 1252/2475/6979 1254/2488/6980 1253/2489/6981 -f 1253/2489/6982 1251/2476/6983 1252/2475/6984 -f 1237/2461/6985 1238/2462/6986 1252/2475/6987 -f 1252/2475/6988 1250/2473/6989 1237/2461/6990 -f 1236/2459/6991 1237/2461/6992 1250/2473/6993 -f 1250/2473/6994 1248/2470/6995 1236/2459/6996 -f 1245/2469/6997 1235/2460/6998 1236/2459/6999 -f 1236/2459/7000 1248/2470/7001 1245/2469/7002 -f 1244/2468/7003 1235/2576/7004 1245/2577/7005 -f 1245/2577/7006 1260/2477/7007 1244/2468/7008 -f 1260/2477/7009 1261/2478/7010 1259/2490/7011 -f 1259/2490/7012 1258/2483/7013 1260/2477/7014 -f 1252/2475/7015 1238/2462/7016 1239/2463/7017 -f 1239/2463/7018 1254/2488/7019 1252/2475/7020 -f 587/1398/7021 437/519/7022 443/526/7023 -f 443/526/7024 444/525/7025 587/1398/7026 -f 645/734/7027 640/729/7028 450/535/7029 -f 450/535/7030 451/534/7031 645/734/7032 -f 621/709/7033 624/713/7034 650/739/7035 -f 650/739/7036 620/710/7037 621/709/7038 -f 622/711/7039 623/714/7040 624/2605/7041 -f 624/2605/7042 621/2603/7043 622/711/7044 -f 424/507/7045 420/504/7046 629/718/7047 -f 629/718/7048 622/711/7049 424/507/7050 -f 420/504/7051 421/503/7052 632/721/7053 -f 632/721/7054 629/718/7055 420/504/7056 -f 421/503/7057 604/690/7058 635/724/7059 -f 635/724/7060 632/721/7061 421/503/7062 -f 604/690/7063 605/691/7064 638/727/7065 -f 638/727/7066 635/724/7067 604/690/7068 -f 605/691/7069 449/533/7070 450/535/7071 -f 450/535/7072 638/727/7073 605/691/7074 -f 651/740/7075 617/706/7076 618/707/7077 -f 618/707/7078 620/710/7079 651/740/7080 -f 451/534/7081 446/532/7082 617/706/7083 -f 617/706/7084 651/740/7085 451/534/7086 -f 607/693/7087 608/2569/7088 448/530/7089 -f 448/530/7090 449/533/7091 607/693/7092 -f 642/730/7093 1266/2570/7094 671/759/7095 -f 671/759/7096 641/731/7097 642/730/7098 -f 643/733/7099 1267/2571/7100 1266/2570/7101 -f 1266/2570/7102 642/730/7103 643/733/7104 -f 1268/2572/7105 1267/2571/7106 643/733/7107 -f 643/733/7108 646/736/7109 1268/2572/7110 -f 655/746/7111 1268/2572/7112 646/736/7113 -f 646/736/7114 652/741/7115 655/746/7116 -f 654/2607/7117 655/746/7118 652/741/7119 -f 652/741/7120 653/742/7121 654/2607/7122 -f 653/2606/7123 625/712/7124 626/715/7125 -f 626/715/7126 660/749/7127 653/2606/7128 -f 626/715/7129 627/716/7130 663/752/7131 -f 663/752/7132 660/749/7133 626/715/7134 -f 627/716/7135 630/719/7136 666/755/7137 -f 666/755/7138 663/752/7139 627/716/7140 -f 630/719/7141 633/722/7142 669/758/7143 -f 669/758/7144 666/755/7145 630/719/7146 -f 633/722/7147 636/725/7148 641/731/7149 -f 641/731/7150 669/758/7151 633/722/7152 -f 657/744/7153 688/776/7154 686/775/7155 -f 686/775/7156 656/745/7157 657/744/7158 -f 658/748/7159 690/778/7160 688/2609/7161 -f 688/2609/7162 657/2608/7163 658/748/7164 -f 661/751/7165 692/1351/7166 690/778/7167 -f 690/778/7168 658/748/7169 661/751/7170 -f 664/754/7171 694/2566/7172 692/1351/7173 -f 692/1351/7174 661/751/7175 664/754/7176 -f 673/762/7177 694/2566/7178 664/754/7179 -f 664/754/7180 667/757/7181 673/762/7182 -f 672/763/7183 673/762/7184 667/757/7185 -f 667/757/7186 670/760/7187 672/763/7188 -f 671/759/7189 1266/2570/7190 678/767/7191 -f 678/767/7192 670/760/7193 671/759/7194 -f 1266/2570/7195 1267/2571/7196 681/770/7197 -f 681/770/7198 678/767/7199 1266/2570/7200 -f 1267/2571/7201 1268/2572/7202 684/773/7203 -f 684/773/7204 681/770/7205 1267/2571/7206 -f 684/773/7207 1268/2572/7208 655/746/7209 -f 655/746/7210 656/745/7211 684/773/7212 -f 1270/1432/7213 1269/478/7214 397/475/7215 -f 397/475/7216 1271/1431/7217 1270/1432/7218 -f 1270/1432/7219 1271/1431/7220 1272/1543/7221 -f 1272/1543/7222 1273/1544/7223 1270/1432/7224 -f 1276/1360/7225 1275/1361/7226 1274/1358/7227 -f 1274/1358/7228 1277/1359/7229 1276/1360/7230 -f 1279/1362/7231 1278/1363/7232 1275/1361/7233 -f 1275/1361/7234 1276/1360/7235 1279/1362/7236 -f 1276/1360/7237 1277/1359/7238 1280/1364/7239 -f 1280/1364/7240 1279/1362/7241 1276/1360/7242 -f 1283/1367/7243 1282/1368/7244 1281/1365/7245 -f 1281/1365/7246 1284/1366/7247 1283/1367/7248 -f 1283/1367/7249 1284/1366/7250 1285/1369/7251 -f 1285/1369/7252 1286/1370/7253 1283/1367/7254 -f 1283/1367/7255 1286/1370/7256 1287/1371/7257 -f 1287/1371/7258 1288/1372/7259 1283/1367/7260 -f 1283/1367/7261 1288/1372/7262 1289/1373/7263 -f 1289/1373/7264 1290/1374/7265 1283/1367/7266 -f 1283/1367/7267 1290/1374/7268 1291/1375/7269 -f 1291/1375/7270 1282/1368/7271 1283/1367/7272 -f 1294/1376/7273 1293/1377/7274 1292/479/7275 -f 1292/479/7276 1295/686/7277 1294/1376/7278 -f 1294/1376/7279 1297/1379/7280 1296/1378/7281 -f 1296/1378/7282 1293/1377/7283 1294/1376/7284 -f 1300/1384/7285 1299/1385/7286 1298/1382/7287 -f 1298/1382/7288 1301/1383/7289 1300/1384/7290 -f 1303/2586/7291 1302/1387/7292 1299/1385/7293 -f 1299/1385/7294 1300/1384/7295 1303/2586/7296 -f 1300/1570/7297 1301/1571/7298 1304/1541/7299 -f 1304/1541/7300 1303/1542/7301 1300/1570/7302 -f 1307/1547/7303 1306/1548/7304 1305/1545/7305 -f 1305/1545/7306 1308/1546/7307 1307/1547/7308 -f 1307/1547/7309 1310/1551/7310 1309/1550/7311 -f 1309/1550/7312 1306/1548/7313 1307/1547/7314 -f 1307/1547/7315 1308/1546/7316 1273/1544/7317 -f 1273/1544/7318 1311/1552/7319 1307/1547/7320 -f 1308/1546/7321 1305/1545/7322 1312/1553/7323 -f 1312/1553/7324 1313/1554/7325 1308/1546/7326 -f 1316/1557/7327 1315/1558/7328 1314/1555/7329 -f 1314/1555/7330 1317/1556/7331 1316/1557/7332 -f 1317/1556/7333 1312/1553/7334 1305/1545/7335 -f 1305/1545/7336 1316/1557/7337 1317/1556/7338 -f 1317/1556/7339 1314/1555/7340 1318/1559/7341 -f 1318/1559/7342 1312/1553/7343 1317/1556/7344 -f 1321/1403/7345 1320/1404/7346 1319/1380/7347 -f 1319/1380/7348 1322/1381/7349 1321/1403/7350 -f 1323/1406/7351 1321/1403/7352 1322/1381/7353 -f 1322/1381/7354 1324/1405/7355 1323/1406/7356 -f 1306/1548/7357 1309/1550/7358 1316/1557/7359 -f 1316/1557/7360 1305/1545/7361 1306/1548/7362 -f 1327/1562/7363 1326/1563/7364 1325/1560/7365 -f 1325/1560/7366 1328/1561/7367 1327/1562/7368 -f 1327/1562/7369 1330/1566/7370 1329/1564/7371 -f 1329/1564/7372 1331/1565/7373 1327/1562/7374 -f 1327/1562/7375 1331/1565/7376 1332/1567/7377 -f 1332/1567/7378 1326/1563/7379 1327/1562/7380 -f 1334/1418/7381 1333/1419/7382 1329/1413/7383 -f 1329/1413/7384 1335/1417/7385 1334/1418/7386 -f 1334/1418/7387 1274/1358/7388 1275/1361/7389 -f 1275/1361/7390 1278/1363/7391 1334/1418/7392 -f 1334/1418/7393 1278/1363/7394 1336/1420/7395 -f 1336/1420/7396 1333/1419/7397 1334/1418/7398 -f 1290/1374/7399 1289/1373/7400 1337/1421/7401 -f 1337/1421/7402 1291/1375/7403 1290/1374/7404 -f 1335/1569/7405 1329/1564/7406 1330/1566/7407 -f 1330/1566/7408 1338/1568/7409 1335/1569/7410 -f 1335/1417/7411 1338/1423/7412 1339/1422/7413 -f 1339/1422/7414 1334/1418/7415 1335/1417/7416 -f 1342/1408/7417 1341/1424/7418 1340/1407/7419 -f 1340/1407/7420 1297/1379/7421 1342/1408/7422 -f 1345/1574/7423 1344/1575/7424 1343/1572/7425 -f 1343/1572/7426 1346/1573/7427 1345/1574/7428 -f 1345/1687/7429 1346/2491/7430 1347/1598/7431 -f 1347/1598/7432 1348/1686/7433 1345/1687/7434 -f 1346/1573/7435 1343/1572/7436 1349/1576/7437 -f 1349/1576/7438 1350/1577/7439 1346/1573/7440 -f 1346/2491/7441 1350/2493/7442 1351/2492/7443 -f 1351/2492/7444 1347/1598/7445 1346/2491/7446 -f 1351/1435/7447 1350/1436/7448 1352/1433/7449 -f 1352/1433/7450 1353/1434/7451 1351/1435/7452 -f 1351/1435/7453 1353/1434/7454 1339/1422/7455 -f 1339/1422/7456 1338/1423/7457 1351/1435/7458 -f 1351/2492/7459 1338/1568/7460 1330/1566/7461 -f 1330/1566/7462 1347/1598/7463 1351/2492/7464 -f 1353/1434/7465 1352/1433/7466 1354/1437/7467 -f 1354/1437/7468 1355/1438/7469 1353/1434/7470 -f 1353/1434/7471 1355/1438/7472 1356/1439/7473 -f 1356/1439/7474 1339/1422/7475 1353/1434/7476 -f 1356/1439/7477 1355/1438/7478 1357/1440/7479 -f 1357/1440/7480 1358/1441/7481 1356/1439/7482 -f 1356/1439/7483 1358/1441/7484 1277/1359/7485 -f 1277/1359/7486 1274/1358/7487 1356/1439/7488 -f 1356/1439/7489 1274/1358/7490 1334/1418/7491 -f 1334/1418/7492 1339/1422/7493 1356/1439/7494 -f 1358/1441/7495 1357/1440/7496 1359/1442/7497 -f 1359/1442/7498 1360/1443/7499 1358/1441/7500 -f 1358/1441/7501 1360/1443/7502 1361/1444/7503 -f 1361/1444/7504 1277/1359/7505 1358/1441/7506 -f 1361/1444/7507 1360/1443/7508 1362/1445/7509 -f 1362/1445/7510 1363/1446/7511 1361/1444/7512 -f 1361/1444/7513 1363/1446/7514 1364/1447/7515 -f 1364/1447/7516 1365/1448/7517 1361/1444/7518 -f 1361/1444/7519 1365/1448/7520 1280/1364/7521 -f 1280/1364/7522 1277/1359/7523 1361/1444/7524 -f 1365/1448/7525 1364/1447/7526 1366/1449/7527 -f 1366/1449/7528 1337/1421/7529 1365/1448/7530 -f 1365/1448/7531 1337/1421/7532 1289/1373/7533 -f 1289/1373/7534 1280/1364/7535 1365/1448/7536 -f 1364/1447/7537 1363/1446/7538 1367/1450/7539 -f 1367/1450/7540 1368/1451/7541 1364/1447/7542 -f 1364/1447/7543 1368/1451/7544 1369/1452/7545 -f 1369/1452/7546 1366/1449/7547 1364/1447/7548 -f 1368/1451/7549 1367/1450/7550 1370/1453/7551 -f 1370/1453/7552 1371/1454/7553 1368/1451/7554 -f 1368/1451/7555 1371/1454/7556 1372/1455/7557 -f 1372/1455/7558 1369/1452/7559 1368/1451/7560 -f 1372/1455/7561 1371/1454/7562 1373/1456/7563 -f 1373/1456/7564 1374/1457/7565 1372/1455/7566 -f 1372/1455/7567 1374/1457/7568 1375/1458/7569 -f 1375/1458/7570 1376/1459/7571 1372/1455/7572 -f 1372/1455/7573 1376/1459/7574 1377/1460/7575 -f 1377/1460/7576 1369/1452/7577 1372/1455/7578 -f 1376/1459/7579 1375/1458/7580 1378/1461/7581 -f 1378/1461/7582 1379/1462/7583 1376/1459/7584 -f 1376/1459/7585 1379/1462/7586 1380/1463/7587 -f 1380/1463/7588 1377/1460/7589 1376/1459/7590 -f 1380/1463/7591 1382/1465/7592 1381/1464/7593 -f 1381/1464/7594 1377/1460/7595 1380/1463/7596 -f 1380/2589/7597 1379/2588/7598 1383/1466/7599 -f 1383/1466/7600 1384/1467/7601 1380/2589/7602 -f 1380/2589/7603 1384/1467/7604 1385/1468/7605 -f 1385/1468/7606 1382/2590/7607 1380/2589/7608 -f 1383/2591/7609 1379/1462/7610 1378/1461/7611 -f 1378/1461/7612 1386/1469/7613 1383/2591/7614 -f 1383/2591/7615 1386/1469/7616 1387/1470/7617 -f 1387/1470/7618 1388/1471/7619 1383/2591/7620 -f 1383/1466/7621 1388/2593/7622 1389/1472/7623 -f 1389/1472/7624 1384/1467/7625 1383/1466/7626 -f 1388/2593/7627 1387/2592/7628 1390/1473/7629 -f 1390/1473/7630 1391/1474/7631 1388/2593/7632 -f 1388/2593/7633 1391/1474/7634 1392/1475/7635 -f 1392/1475/7636 1389/1472/7637 1388/2593/7638 -f 1392/1475/7639 1394/1477/7640 1393/1476/7641 -f 1393/1476/7642 1389/1472/7643 1392/1475/7644 -f 1392/1475/7645 1391/1474/7646 1395/1478/7647 -f 1395/1478/7648 1396/1479/7649 1392/1475/7650 -f 1392/1475/7651 1396/1479/7652 1397/1480/7653 -f 1397/1480/7654 1394/1477/7655 1392/1475/7656 -f 1397/1480/7657 1399/1482/7658 1398/1481/7659 -f 1398/1481/7660 1394/1477/7661 1397/1480/7662 -f 1397/1480/7663 1396/1479/7664 1400/1483/7665 -f 1400/1483/7666 1401/1484/7667 1397/1480/7668 -f 1397/1480/7669 1401/1484/7670 1402/1485/7671 -f 1402/1485/7672 1399/1482/7673 1397/1480/7674 -f 1402/1485/7675 1404/1487/7676 1403/1486/7677 -f 1403/1486/7678 1399/1482/7679 1402/1485/7680 -f 1402/1485/7681 1401/1484/7682 1405/1488/7683 -f 1405/1488/7684 1359/1442/7685 1402/1485/7686 -f 1402/1485/7687 1359/1442/7688 1357/1440/7689 -f 1357/1440/7690 1404/1487/7691 1402/1485/7692 -f 1405/1488/7693 1401/1484/7694 1400/1483/7695 -f 1400/1483/7696 1406/1489/7697 1405/1488/7698 -f 1405/1488/7699 1406/1489/7700 1407/1490/7701 -f 1407/1490/7702 1362/1445/7703 1405/1488/7704 -f 1405/1488/7705 1362/1445/7706 1360/1443/7707 -f 1360/1443/7708 1359/1442/7709 1405/1488/7710 -f 1407/1490/7711 1406/1489/7712 1408/1491/7713 -f 1408/1491/7714 1409/1492/7715 1407/1490/7716 -f 1407/1490/7717 1409/1492/7718 1370/1453/7719 -f 1370/1453/7720 1367/1450/7721 1407/1490/7722 -f 1407/1490/7723 1367/1450/7724 1363/1446/7725 -f 1363/1446/7726 1362/1445/7727 1407/1490/7728 -f 1409/1492/7729 1408/1491/7730 1410/1493/7731 -f 1410/1493/7732 1411/1494/7733 1409/1492/7734 -f 1409/1492/7735 1411/1494/7736 1412/1495/7737 -f 1412/1495/7738 1370/1453/7739 1409/1492/7740 -f 1412/1495/7741 1411/1494/7742 1413/1496/7743 -f 1413/1496/7744 1414/1497/7745 1412/1495/7746 -f 1412/1495/7747 1414/1497/7748 1415/1498/7749 -f 1415/1498/7750 1373/1456/7751 1412/1495/7752 -f 1412/1495/7753 1373/1456/7754 1371/1454/7755 -f 1371/1454/7756 1370/1453/7757 1412/1495/7758 -f 1415/1498/7759 1416/1499/7760 1374/1457/7761 -f 1374/1457/7762 1373/1456/7763 1415/1498/7764 -f 1416/1499/7765 1417/1500/7766 1375/1458/7767 -f 1375/1458/7768 1374/1457/7769 1416/1499/7770 -f 1417/1500/7771 1418/1501/7772 1378/1461/7773 -f 1378/1461/7774 1375/1458/7775 1417/1500/7776 -f 1418/1501/7777 1419/1502/7778 1386/1469/7779 -f 1386/1469/7780 1378/1461/7781 1418/1501/7782 -f 1419/1502/7783 1420/1503/7784 1387/1470/7785 -f 1387/1470/7786 1386/1469/7787 1419/1502/7788 -f 1420/2594/7789 1421/1504/7790 1390/1473/7791 -f 1390/1473/7792 1387/2592/7793 1420/2594/7794 -f 1421/1504/7795 1423/1506/7796 1422/1505/7797 -f 1422/1505/7798 1390/1473/7799 1421/1504/7800 -f 1422/1505/7801 1395/1478/7802 1391/1474/7803 -f 1391/1474/7804 1390/1473/7805 1422/1505/7806 -f 1422/1505/7807 1423/1506/7808 1424/1507/7809 -f 1424/1507/7810 1425/1508/7811 1422/1505/7812 -f 1422/1505/7813 1425/1508/7814 1426/1509/7815 -f 1426/1509/7816 1395/1478/7817 1422/1505/7818 -f 1426/1509/7819 1400/1483/7820 1396/1479/7821 -f 1396/1479/7822 1395/1478/7823 1426/1509/7824 -f 1426/1509/7825 1425/1508/7826 1410/1493/7827 -f 1410/1493/7828 1408/1491/7829 1426/1509/7830 -f 1426/1509/7831 1408/1491/7832 1406/1489/7833 -f 1406/1489/7834 1400/1483/7835 1426/1509/7836 -f 1425/1508/7837 1424/1507/7838 1427/1510/7839 -f 1427/1510/7840 1410/1493/7841 1425/1508/7842 -f 1427/1510/7843 1413/1496/7844 1411/1494/7845 -f 1411/1494/7846 1410/1493/7847 1427/1510/7848 -f 1403/1486/7849 1429/1513/7850 1428/1511/7851 -f 1428/1511/7852 1430/1512/7853 1403/1486/7854 -f 1403/1486/7855 1430/1512/7856 1398/1481/7857 -f 1398/1481/7858 1399/1482/7859 1403/1486/7860 -f 1403/1486/7861 1404/1487/7862 1354/1437/7863 -f 1354/1437/7864 1429/1513/7865 1403/1486/7866 -f 1430/1512/7867 1428/1511/7868 1431/1514/7869 -f 1431/1514/7870 1432/1515/7871 1430/1512/7872 -f 1430/1512/7873 1432/1515/7874 1433/1516/7875 -f 1433/1516/7876 1398/1481/7877 1430/1512/7878 -f 1433/1516/7879 1432/1515/7880 1434/1517/7881 -f 1434/1517/7882 1435/1518/7883 1433/1516/7884 -f 1433/1516/7885 1435/1518/7886 1436/1519/7887 -f 1436/1519/7888 1393/1476/7889 1433/1516/7890 -f 1433/1516/7891 1393/1476/7892 1394/1477/7893 -f 1394/1477/7894 1398/1481/7895 1433/1516/7896 -f 1434/1517/7897 1298/1382/7898 1299/1385/7899 -f 1299/1385/7900 1437/1520/7901 1434/1517/7902 -f 1434/1517/7903 1437/1520/7904 1385/1468/7905 -f 1385/1468/7906 1435/1518/7907 1434/1517/7908 -f 1434/1517/7909 1432/1515/7910 1431/1514/7911 -f 1431/1514/7912 1298/1382/7913 1434/1517/7914 -f 1437/1520/7915 1299/1385/7916 1302/1387/7917 -f 1302/1387/7918 1438/1521/7919 1437/1520/7920 -f 1437/1520/7921 1438/1521/7922 1382/2590/7923 -f 1382/2590/7924 1385/1468/7925 1437/1520/7926 -f 1438/2595/7927 1302/2587/7928 1284/1366/7929 -f 1284/1366/7930 1281/1365/7931 1438/2595/7932 -f 1438/2595/7933 1281/1365/7934 1381/1464/7935 -f 1381/1464/7936 1382/1465/7937 1438/2595/7938 -f 1431/1514/7939 1439/1522/7940 1301/1383/7941 -f 1301/1383/7942 1298/1382/7943 1431/1514/7944 -f 1431/1514/7945 1428/1511/7946 1440/1523/7947 -f 1440/1523/7948 1439/1522/7949 1431/1514/7950 -f 1440/1580/7951 1442/1581/7952 1441/1578/7953 -f 1441/1578/7954 1439/1579/7955 1440/1580/7956 -f 1440/1523/7957 1428/1511/7958 1429/1513/7959 -f 1429/1513/7960 1443/1524/7961 1440/1523/7962 -f 1440/1580/7963 1443/1582/7964 1349/1576/7965 -f 1349/1576/7966 1442/1581/7967 1440/1580/7968 -f 1443/1524/7969 1429/1513/7970 1354/1437/7971 -f 1354/1437/7972 1352/1433/7973 1443/1524/7974 -f 1443/1524/7975 1352/1433/7976 1350/1436/7977 -f 1350/1436/7978 1349/1527/7979 1443/1524/7980 -f 1441/1578/7981 1445/1585/7982 1444/1583/7983 -f 1444/1583/7984 1446/1584/7985 1441/1578/7986 -f 1441/1578/7987 1446/1584/7988 1301/1571/7989 -f 1301/1571/7990 1439/1579/7991 1441/1578/7992 -f 1441/1578/7993 1442/1581/7994 1447/1586/7995 -f 1447/1586/7996 1445/1585/7997 1441/1578/7998 -f 1446/1584/7999 1444/1583/8000 1448/1587/8001 -f 1448/1587/8002 1449/1588/8003 1446/1584/8004 -f 1446/1584/8005 1449/1588/8006 1304/1541/8007 -f 1304/1541/8008 1301/1571/8009 1446/1584/8010 -f 1449/1588/8011 1448/1587/8012 1450/1690/8013 -f 1450/1690/8014 1451/1691/8015 1449/1588/8016 -f 1449/1588/8017 1451/1691/8018 1452/2536/8019 -f 1452/2536/8020 1304/1541/8021 1449/1588/8022 -f 1452/2536/8023 1451/1691/8024 1453/2537/8025 -f 1453/2537/8026 1454/2538/8027 1452/2536/8028 -f 1452/2536/8029 1454/2538/8030 1455/2539/8031 -f 1455/2539/8032 1456/2540/8033 1452/2536/8034 -f 1452/2536/8035 1456/2540/8036 1303/1542/8037 -f 1303/1542/8038 1304/1541/8039 1452/2536/8040 -f 1456/2540/8041 1455/2539/8042 1457/2541/8043 -f 1457/2541/8044 1458/2542/8045 1456/2540/8046 -f 1456/2540/8047 1458/2542/8048 1285/2543/8049 -f 1285/2543/8050 1303/1542/8051 1456/2540/8052 -f 1458/2497/8053 1457/2498/8054 1459/2495/8055 -f 1459/2495/8056 1460/2496/8057 1458/2497/8058 -f 1458/2497/8059 1460/2496/8060 1286/2499/8061 -f 1286/2499/8062 1285/2501/8063 1458/2497/8064 -f 1460/2496/8065 1459/2495/8066 1461/2502/8067 -f 1461/2502/8068 1462/2503/8069 1460/2496/8070 -f 1460/2496/8071 1462/2503/8072 1287/2504/8073 -f 1287/2504/8074 1286/2499/8075 1460/2496/8076 -f 1462/2503/8077 1461/2502/8078 1463/2505/8079 -f 1463/2505/8080 1464/2506/8081 1462/2503/8082 -f 1462/2503/8083 1464/2506/8084 1465/2507/8085 -f 1465/2507/8086 1287/2504/8087 1462/2503/8088 -f 1465/2507/8089 1464/2506/8090 1466/2508/8091 -f 1466/2508/8092 1336/2509/8093 1465/2507/8094 -f 1465/1549/8095 1336/1420/8096 1278/1363/8097 -f 1278/1363/8098 1279/1362/8099 1465/1549/8100 -f 1465/1549/8101 1279/1362/8102 1288/1372/8103 -f 1288/1372/8104 1287/1371/8105 1465/1549/8106 -f 1466/2508/8107 1464/2506/8108 1463/2505/8109 -f 1463/2505/8110 1467/2510/8111 1466/2508/8112 -f 1466/2508/8113 1467/2510/8114 1468/2511/8115 -f 1468/2511/8116 1469/2512/8117 1466/2508/8118 -f 1466/2508/8119 1469/2512/8120 1333/2513/8121 -f 1333/2513/8122 1336/2509/8123 1466/2508/8124 -f 1469/2512/8125 1468/2511/8126 1332/1567/8127 -f 1332/1567/8128 1331/1565/8129 1469/2512/8130 -f 1469/2512/8131 1331/1565/8132 1329/1564/8133 -f 1329/1564/8134 1333/2513/8135 1469/2512/8136 -f 1468/2511/8137 1467/2510/8138 1470/2514/8139 -f 1470/2514/8140 1471/2515/8141 1468/2511/8142 -f 1468/2511/8143 1471/2515/8144 1472/2516/8145 -f 1472/2516/8146 1332/1567/8147 1468/2511/8148 -f 1472/2516/8149 1471/2515/8150 1473/2517/8151 -f 1473/2517/8152 1474/2518/8153 1472/2516/8154 -f 1472/2516/8155 1474/2518/8156 1475/2519/8157 -f 1475/2519/8158 1476/2520/8159 1472/2516/8160 -f 1472/2516/8161 1476/2520/8162 1326/1563/8163 -f 1326/1563/8164 1332/1567/8165 1472/2516/8166 -f 1476/2520/8167 1475/2519/8168 1477/2521/8169 -f 1477/2521/8170 1478/2522/8171 1476/2520/8172 -f 1476/2520/8173 1478/2522/8174 1325/1560/8175 -f 1325/1560/8176 1326/1563/8177 1476/2520/8178 -f 1475/2519/8179 1474/2518/8180 1479/2523/8181 -f 1479/2523/8182 1480/2524/8183 1475/2519/8184 -f 1475/2519/8185 1480/2524/8186 1481/2525/8187 -f 1481/2525/8188 1477/2521/8189 1475/2519/8190 -f 1480/2524/8191 1479/2523/8192 1482/1392/8193 -f 1482/1392/8194 1483/1393/8195 1480/2524/8196 -f 1480/2524/8197 1483/1393/8198 1484/1394/8199 -f 1484/1394/8200 1481/2525/8201 1480/2524/8202 -f 1482/1392/8203 1479/2523/8204 1485/2526/8205 -f 1485/2526/8206 391/1396/8207 1482/1392/8208 -f 391/1396/8209 1485/2526/8210 1271/1431/8211 -f 1271/1431/8212 397/475/8213 391/1396/8214 -f 1485/2526/8215 1479/2523/8216 1474/2518/8217 -f 1474/2518/8218 1473/2517/8219 1485/2526/8220 -f 1485/2526/8221 1473/2517/8222 1272/1543/8223 -f 1272/1543/8224 1271/1431/8225 1485/2526/8226 -f 1473/2517/8227 1471/2515/8228 1470/2514/8229 -f 1470/2514/8230 1272/1543/8231 1473/2517/8232 -f 1470/2514/8233 1311/1552/8234 1273/1544/8235 -f 1273/1544/8236 1272/1543/8237 1470/2514/8238 -f 1470/2514/8239 1467/2510/8240 1463/2505/8241 -f 1463/2505/8242 1311/1552/8243 1470/2514/8244 -f 1463/2505/8245 1461/2502/8246 1307/1547/8247 -f 1307/1547/8248 1311/1552/8249 1463/2505/8250 -f 1461/2502/8251 1459/2495/8252 1310/1551/8253 -f 1310/1551/8254 1307/1547/8255 1461/2502/8256 -f 1459/2495/8257 1457/2498/8258 1486/2527/8259 -f 1486/2527/8260 1310/1551/8261 1459/2495/8262 -f 1486/2546/8263 1488/2547/8264 1487/2544/8265 -f 1487/2544/8266 1489/2545/8267 1486/2546/8268 -f 1486/2527/8269 1489/2528/8270 1309/1550/8271 -f 1309/1550/8272 1310/1551/8273 1486/2527/8274 -f 1486/2546/8275 1457/2541/8276 1455/2539/8277 -f 1455/2539/8278 1488/2547/8279 1486/2546/8280 -f 1487/2544/8281 1491/2550/8282 1490/2548/8283 -f 1490/2548/8284 1492/2549/8285 1487/2544/8286 -f 1487/2544/8287 1492/2549/8288 1315/2551/8289 -f 1315/2551/8290 1489/2545/8291 1487/2544/8292 -f 1487/2544/8293 1488/2547/8294 1493/2552/8295 -f 1493/2552/8296 1491/2550/8297 1487/2544/8298 -f 1493/2552/8299 1495/2554/8300 1494/2553/8301 -f 1494/2553/8302 1491/2550/8303 1493/2552/8304 -f 1493/2552/8305 1488/2547/8306 1455/2539/8307 -f 1455/2539/8308 1454/2538/8309 1493/2552/8310 -f 1493/2552/8311 1454/2538/8312 1453/2537/8313 -f 1453/2537/8314 1495/2554/8315 1493/2552/8316 -f 1494/2553/8317 1497/2557/8318 1496/2555/8319 -f 1496/2555/8320 1498/2556/8321 1494/2553/8322 -f 1494/2553/8323 1498/2556/8324 1490/2548/8325 -f 1490/2548/8326 1491/2550/8327 1494/2553/8328 -f 1494/2553/8329 1495/2554/8330 1499/2558/8331 -f 1499/2558/8332 1497/2557/8333 1494/2553/8334 -f 1499/2558/8335 1501/1428/8336 1500/1427/8337 -f 1500/1427/8338 1497/2557/8339 1499/2558/8340 -f 1499/2558/8341 1495/2554/8342 1453/2537/8343 -f 1453/2537/8344 1502/2559/8345 1499/2558/8346 -f 1499/2558/8347 1502/2559/8348 392/1430/8349 -f 392/1430/8350 1501/1428/8351 1499/2558/8352 -f 392/1430/8353 1502/2559/8354 1450/1690/8355 -f 1450/1690/8356 1503/1525/8357 392/1430/8358 -f 1503/1525/8359 1450/1690/8360 1448/1587/8361 -f 1448/1587/8362 599/1526/8363 1503/1525/8364 -f 599/1526/8365 1448/1587/8366 1444/1583/8367 -f 1444/1583/8368 1504/1528/8369 599/1526/8370 -f 1504/1528/8371 1444/1583/8372 1445/1585/8373 -f 1445/1585/8374 600/1529/8375 1504/1528/8376 -f 600/1529/8377 1445/1585/8378 1447/1586/8379 -f 1447/1586/8380 601/1530/8381 600/1529/8382 -f 1502/2559/8383 1453/2537/8384 1451/1691/8385 -f 1451/1691/8386 1450/1690/8387 1502/2559/8388 -f 1500/1427/8389 393/1531/8390 1496/2555/8391 -f 1496/2555/8392 1497/2557/8393 1500/1427/8394 -f 393/1531/8395 602/1533/8396 1294/2560/8397 -f 1294/2560/8398 1496/2555/8399 393/1531/8400 -f 1498/2556/8401 1496/2555/8402 1294/2560/8403 -f 1294/2560/8404 1295/2561/8405 1498/2556/8406 -f 1498/2556/8407 1295/2561/8408 1505/2562/8409 -f 1505/2562/8410 1490/2548/8411 1498/2556/8412 -f 1505/1426/8413 1295/686/8414 1292/479/8415 -f 1292/479/8416 1506/1425/8417 1505/1426/8418 -f 1505/1426/8419 1506/1425/8420 1507/1589/8421 -f 1507/1589/8422 1508/1590/8423 1505/1426/8424 -f 1505/2562/8425 1508/2563/8426 1492/2549/8427 -f 1492/2549/8428 1490/2548/8429 1505/2562/8430 -f 1509/1591/8431 1508/1590/8432 1507/1589/8433 -f 1507/1589/8434 1322/1381/8435 1509/1591/8436 -f 1508/2563/8437 1509/2564/8438 1315/2551/8439 -f 1315/2551/8440 1492/2549/8441 1508/2563/8442 -f 1509/2529/8443 1510/2530/8444 1314/1555/8445 -f 1314/1555/8446 1315/1558/8447 1509/2529/8448 -f 1510/1593/8449 1319/1380/8450 1320/1404/8451 -f 1320/1404/8452 1511/1592/8453 1510/1593/8454 -f 1510/2530/8455 1511/2531/8456 1318/1559/8457 -f 1318/1559/8458 1314/1555/8459 1510/2530/8460 -f 1511/1592/8461 1320/1404/8462 1512/1594/8463 -f 1512/1594/8464 1513/1595/8465 1511/1592/8466 -f 1511/2531/8467 1513/2533/8468 1514/2532/8469 -f 1514/2532/8470 1318/1559/8471 1511/2531/8472 -f 1514/2532/8473 1313/1554/8474 1312/1553/8475 -f 1312/1553/8476 1318/1559/8477 1514/2532/8478 -f 1514/2532/8479 1513/2533/8480 1515/1411/8481 -f 1515/1411/8482 613/1412/8483 1514/2532/8484 -f 1514/2532/8485 613/1412/8486 394/1414/8487 -f 394/1414/8488 1313/1554/8489 1514/2532/8490 -f 1515/1597/8491 1513/1595/8492 1512/1594/8493 -f 1512/1594/8494 395/1596/8495 1515/1597/8496 -f 395/1596/8497 1512/1594/8498 1516/1599/8499 -f 1516/1599/8500 1517/1600/8501 395/1596/8502 -f 1517/1600/8503 1516/1599/8504 1518/1601/8505 -f 1518/1601/8506 1519/1602/8507 1517/1600/8508 -f 1519/1602/8509 1518/1601/8510 1520/1603/8511 -f 1520/1603/8512 1521/1604/8513 1519/1602/8514 -f 1521/1604/8515 1520/1603/8516 1340/2611/8517 -f 1340/2611/8518 1341/2612/8519 1521/1604/8520 -f 1520/1603/8521 1518/1601/8522 1522/1605/8523 -f 1522/1605/8524 1523/1606/8525 1520/1603/8526 -f 1520/1603/8527 1523/1606/8528 1524/1607/8529 -f 1524/1607/8530 1340/2611/8531 1520/1603/8532 -f 1526/1608/8533 1525/1609/8534 1524/1607/8535 -f 1524/1607/8536 1523/1606/8537 1526/1608/8538 -f 1296/1378/8539 1524/2613/8540 1525/2614/8541 -f 1525/2614/8542 1527/1610/8543 1296/1378/8544 -f 1524/2613/8545 1296/1378/8546 1297/1379/8547 -f 1297/1379/8548 1340/1407/8549 1524/2613/8550 -f 1530/1613/8551 1529/2616/8552 1528/1611/8553 -f 1528/1611/8554 1531/1612/8555 1530/1613/8556 -f 1530/1613/8557 1531/1612/8558 1532/1615/8559 -f 1532/1615/8560 1533/1616/8561 1530/1613/8562 -f 1527/1610/8563 1530/1613/8564 1533/1616/8565 -f 1533/1616/8566 1534/1617/8567 1527/1610/8568 -f 1533/1616/8569 1532/1615/8570 1535/1618/8571 -f 1535/1618/8572 1536/1619/8573 1533/1616/8574 -f 1534/1617/8575 1533/1616/8576 1536/1619/8577 -f 1536/1619/8578 1537/1620/8579 1534/1617/8580 -f 1536/1619/8581 1535/1618/8582 1538/1621/8583 -f 1538/1621/8584 1539/1622/8585 1536/1619/8586 -f 1537/1620/8587 1536/1619/8588 1539/1622/8589 -f 1539/1622/8590 1540/1623/8591 1537/1620/8592 -f 1539/1622/8593 1538/1621/8594 1541/1624/8595 -f 1541/1624/8596 1542/1625/8597 1539/1622/8598 -f 1540/1623/8599 1539/1622/8600 1542/1625/8601 -f 1542/1625/8602 1543/1626/8603 1540/1623/8604 -f 1542/1625/8605 1541/1624/8606 1544/1627/8607 -f 1544/1627/8608 1545/1628/8609 1542/1625/8610 -f 1543/1626/8611 1542/1625/8612 1545/1628/8613 -f 1545/1628/8614 1324/1405/8615 1543/1626/8616 -f 1546/1630/8617 1544/1627/8618 1541/1624/8619 -f 1541/1624/8620 1547/1629/8621 1546/1630/8622 -f 1548/1632/8623 1544/1627/8624 1546/1630/8625 -f 1546/1630/8626 1549/1631/8627 1548/1632/8628 -f 1544/1627/8629 1548/1632/8630 1550/1633/8631 -f 1550/1633/8632 1545/1628/8633 1544/1627/8634 -f 1551/1635/8635 1548/1632/8636 1549/1631/8637 -f 1549/1631/8638 1552/1634/8639 1551/1635/8640 -f 1548/1632/8641 1551/1635/8642 1553/1636/8643 -f 1553/1636/8644 1550/1633/8645 1548/1632/8646 -f 1553/1636/8647 1551/1635/8648 1554/1637/8649 -f 1554/1637/8650 1555/1638/8651 1553/1636/8652 -f 1526/1608/8653 1556/1639/8654 1553/1636/8655 -f 1553/1636/8656 1555/1638/8657 1526/1608/8658 -f 1550/1633/8659 1553/1636/8660 1556/1639/8661 -f 1556/1639/8662 1323/1406/8663 1550/1633/8664 -f 1552/1634/8665 1557/1640/8666 1554/1637/8667 -f 1554/1637/8668 1551/1635/8669 1552/1634/8670 -f 1558/1641/8671 1528/2615/8672 1554/1637/8673 -f 1554/1637/8674 1557/1640/8675 1558/1641/8676 -f 1554/1637/8677 1528/2615/8678 1529/1614/8679 -f 1529/1614/8680 1555/1638/8681 1554/1637/8682 -f 1561/1644/8683 1560/1645/8684 1559/2618/8685 -f 1559/2618/8686 1562/1643/8687 1561/1644/8688 -f 1563/1647/8689 1559/1642/8690 1560/2619/8691 -f 1560/2619/8692 1564/1646/8693 1563/1647/8694 -f 1558/2617/8695 1559/1642/8696 1563/1647/8697 -f 1563/1647/8698 1565/1648/8699 1558/2617/8700 -f 1566/1650/8701 1563/1647/8702 1564/1646/8703 -f 1564/1646/8704 1567/1649/8705 1566/1650/8706 -f 1565/1648/8707 1563/1647/8708 1566/1650/8709 -f 1566/1650/8710 1568/1651/8711 1565/1648/8712 -f 1569/1653/8713 1566/1650/8714 1567/1649/8715 -f 1567/1649/8716 1570/1652/8717 1569/1653/8718 -f 1568/1651/8719 1566/1650/8720 1569/1653/8721 -f 1569/1653/8722 1571/1654/8723 1568/1651/8724 -f 1573/1655/8725 1572/1656/8726 1569/1653/8727 -f 1569/1653/8728 1570/1652/8729 1573/1655/8730 -f 1571/1654/8731 1569/1653/8732 1572/1656/8733 -f 1572/1656/8734 1574/1657/8735 1571/1654/8736 -f 1576/1658/8737 1575/1659/8738 1572/1656/8739 -f 1572/1656/8740 1573/1655/8741 1576/1658/8742 -f 1547/1629/8743 1574/1657/8744 1572/1656/8745 -f 1572/1656/8746 1575/1659/8747 1547/1629/8748 -f 1579/1662/8749 1578/1663/8750 1577/1660/8751 -f 1577/1660/8752 1580/1661/8753 1579/1662/8754 -f 1579/1662/8755 1580/1661/8756 1581/1664/8757 -f 1581/1664/8758 1582/1665/8759 1579/1662/8760 -f 1576/1658/8761 1579/1662/8762 1582/1665/8763 -f 1582/1665/8764 1583/1666/8765 1576/1658/8766 -f 1582/1665/8767 1581/1664/8768 1584/1667/8769 -f 1584/1667/8770 1585/1668/8771 1582/1665/8772 -f 1583/1666/8773 1582/1665/8774 1585/1668/8775 -f 1585/1668/8776 1586/1669/8777 1583/1666/8778 -f 1585/1668/8779 1584/1667/8780 1587/1670/8781 -f 1587/1670/8782 1588/1671/8783 1585/1668/8784 -f 1586/1669/8785 1585/1668/8786 1588/1671/8787 -f 1588/1671/8788 1589/1672/8789 1586/1669/8790 -f 1588/1671/8791 1587/1670/8792 1590/1673/8793 -f 1590/1673/8794 1591/1674/8795 1588/1671/8796 -f 1561/1644/8797 1589/1672/8798 1588/1671/8799 -f 1588/1671/8800 1591/1674/8801 1561/1644/8802 -f 1590/1673/8803 1592/1676/8804 1593/1675/8805 -f 1593/1675/8806 1591/1674/8807 1590/1673/8808 -f 1592/2621/8809 1594/1678/8810 1595/1677/8811 -f 1595/1677/8812 1593/2620/8813 1592/2621/8814 -f 1594/1678/8815 1596/1680/8816 1597/1679/8817 -f 1597/1679/8818 1595/1677/8819 1594/1678/8820 -f 1596/1680/8821 1598/1682/8822 1599/1681/8823 -f 1599/1681/8824 1597/1679/8825 1596/1680/8826 -f 1598/1682/8827 1577/1660/8828 1578/1663/8829 -f 1578/1663/8830 1599/1681/8831 1598/1682/8832 -f 1522/1605/8833 1518/1601/8834 1516/1599/8835 -f 1516/1599/8836 1321/1403/8837 1522/1605/8838 -f 1516/1599/8839 1512/1594/8840 1320/1404/8841 -f 1320/1404/8842 1321/1403/8843 1516/1599/8844 -f 1442/1581/8845 1349/1576/8846 1343/1572/8847 -f 1343/1572/8848 1447/1586/8849 1442/1581/8850 -f 1404/1487/8851 1357/1440/8852 1355/1438/8853 -f 1355/1438/8854 1354/1437/8855 1404/1487/8856 -f 1381/1464/8857 1281/1365/8858 1282/1368/8859 -f 1282/1368/8860 1600/1684/8861 1381/1464/8862 -f 1366/1449/8863 1601/1685/8864 1291/1375/8865 -f 1291/1375/8866 1337/1421/8867 1366/1449/8868 -f 1328/1561/8869 1603/2535/8870 1602/2534/8871 -f 1602/2534/8872 1327/1562/8873 1328/1561/8874 -f 1302/2587/8875 1303/1386/8876 1285/1369/8877 -f 1285/1369/8878 1284/1366/8879 1302/2587/8880 -f 1342/1408/8881 1297/1379/8882 1294/1376/8883 -f 1294/1376/8884 602/1683/8885 1342/1408/8886 -f 1602/2534/8887 1603/2535/8888 1348/1686/8889 -f 1348/1686/8890 1347/1598/8891 1602/2534/8892 -f 1602/2534/8893 1347/1598/8894 1330/1566/8895 -f 1330/1566/8896 1327/1562/8897 1602/2534/8898 -f 1291/1375/8899 1601/1685/8900 1600/1684/8901 -f 1600/1684/8902 1282/1368/8903 1291/1375/8904 -f 1289/1373/8905 1288/1372/8906 1279/1362/8907 -f 1279/1362/8908 1280/1364/8909 1289/1373/8910 -f 1269/478/8911 1270/1432/8912 1313/1554/8913 -f 1313/1554/8914 394/1414/8915 1269/478/8916 -f 1436/1519/8917 1435/1518/8918 1385/1468/8919 -f 1385/1468/8920 1384/1467/8921 1436/1519/8922 -f 1436/1519/8923 1384/1467/8924 1389/1472/8925 -f 1389/1472/8926 1393/1476/8927 1436/1519/8928 -f 1308/1546/8929 1313/1554/8930 1270/1432/8931 -f 1270/1432/8932 1273/1544/8933 1308/1546/8934 -f 1600/1684/8935 1601/1685/8936 1604/1688/8937 -f 1604/1688/8938 1605/1689/8939 1600/1684/8940 -f 1366/1449/8941 1369/1452/8942 1604/1688/8943 -f 1604/1688/8944 1601/1685/8945 1366/1449/8946 -f 1605/1689/8947 1604/1688/8948 1369/1452/8949 -f 1369/1452/8950 1377/1460/8951 1605/1689/8952 -f 1381/1464/8953 1600/1684/8954 1605/1689/8955 -f 1605/1689/8956 1377/1460/8957 1381/1464/8958 -f 601/1530/8959 1447/1586/8960 1606/2565/8961 -f 1606/2565/8962 1607/1540/8963 601/1530/8964 -f 1447/1586/8965 1343/1572/8966 1344/1575/8967 -f 1344/1575/8968 1606/2565/8969 1447/1586/8970 -f 1610/1694/8971 1609/1695/8972 1608/1692/8973 -f 1608/1692/8974 1611/1693/8975 1610/1694/8976 -f 1614/1698/8977 1613/1699/8978 1612/1696/8979 -f 1612/1696/8980 1615/1697/8981 1614/1698/8982 -f 1618/1702/8983 1617/1703/8984 1616/1700/8985 -f 1616/1700/8986 1619/1701/8987 1618/1702/8988 -f 1622/1706/8989 1621/1707/8990 1620/1704/8991 -f 1620/1704/8992 1623/1705/8993 1622/1706/8994 -f 1618/1702/8995 1625/1710/8996 1624/1708/8997 -f 1624/1708/8998 1626/1709/8999 1618/1702/9000 -f 1629/1713/9001 1628/1714/9002 1627/1711/9003 -f 1627/1711/9004 1630/1712/9005 1629/1713/9006 -f 1633/1717/9007 1632/1718/9008 1631/1715/9009 -f 1631/1715/9010 1634/1716/9011 1633/1717/9012 -f 1637/1721/9013 1636/1722/9014 1635/1719/9015 -f 1635/1719/9016 1638/1720/9017 1637/1721/9018 -f 1641/1725/9019 1640/1726/9020 1639/1723/9021 -f 1639/1723/9022 1642/1724/9023 1641/1725/9024 -f 1643/1727/9025 1616/1700/9026 1622/1706/9027 -f 1622/1706/9028 1635/1719/9029 1643/1727/9030 -f 1646/1729/9031 1645/1730/9032 1644/1728/9033 -f 1644/1728/9034 1639/1723/9035 1646/1729/9036 -f 1649/1733/9037 1648/1734/9038 1647/1731/9039 -f 1647/1731/9040 1650/1732/9041 1649/1733/9042 -f 1653/1737/9043 1652/1738/9044 1651/1735/9045 -f 1651/1735/9046 1654/1736/9047 1653/1737/9048 -f 1656/1739/9049 1655/1740/9050 1639/1723/9051 -f 1639/1723/9052 1640/1726/9053 1656/1739/9054 -f 1656/1739/9055 1638/1720/9056 1635/1719/9057 -f 1635/1719/9058 1655/1740/9059 1656/1739/9060 -f 1658/1747/9061 1657/1748/9062 1636/1741/9063 -f 1636/1741/9064 1637/1742/9065 1658/1747/9066 -f 1658/1747/9067 1641/1750/9068 1642/2383/9069 -f 1642/2383/9070 1657/1748/9071 1658/1747/9072 -f 1661/1745/9073 1660/1746/9074 1659/1743/9075 -f 1659/1743/9076 1662/1744/9077 1661/1745/9078 -f 1665/1756/9079 1664/1757/9080 1663/1753/9081 -f 1663/1753/9082 1666/1754/9083 1665/1756/9084 -f 1644/1728/9085 1645/1730/9086 1667/1751/9087 -f 1667/1751/9088 1668/1752/9089 1644/1728/9090 -f 1669/1775/9091 1652/1738/9092 1653/1737/9093 -f 1653/1737/9094 1670/1774/9095 1669/1775/9096 -f 1619/1701/9097 1616/1700/9098 1643/1727/9099 -f 1643/1727/9100 1671/1755/9101 1619/1701/9102 -f 1672/1787/9103 1664/1757/9104 1665/1756/9105 -f 1665/1756/9106 1673/1786/9107 1672/1787/9108 -f 1676/1760/9109 1675/1761/9110 1674/1758/9111 -f 1674/1758/9112 1677/1759/9113 1676/1760/9114 -f 1678/1763/9115 1676/1760/9116 1677/1759/9117 -f 1677/1759/9118 1679/1762/9119 1678/1763/9120 -f 1682/1766/9121 1681/1767/9122 1680/1764/9123 -f 1680/1764/9124 1683/1765/9125 1682/1766/9126 -f 1686/1770/9127 1685/1771/9128 1684/1768/9129 -f 1684/1768/9130 1687/1769/9131 1686/1770/9132 -f 1684/1768/9133 1689/1773/9134 1688/1772/9135 -f 1688/1772/9136 1687/1769/9137 1684/1768/9138 -f 1688/1772/9139 1689/1773/9140 1682/1766/9141 -f 1682/1766/9142 1683/1765/9143 1688/1772/9144 -f 1680/1800/9145 1681/1801/9146 1690/1798/9147 -f 1690/1798/9148 1691/1799/9149 1680/1800/9150 -f 1690/1798/9151 1685/1803/9152 1686/1802/9153 -f 1686/1802/9154 1691/1799/9155 1690/1798/9156 -f 1694/1778/9157 1693/1779/9158 1692/1776/9159 -f 1692/1776/9160 1695/1777/9161 1694/1778/9162 -f 1698/1782/9163 1697/1783/9164 1696/1780/9165 -f 1696/1780/9166 1699/1781/9167 1698/1782/9168 -f 1696/1780/9169 1701/1785/9170 1700/1784/9171 -f 1700/1784/9172 1699/1781/9173 1696/1780/9174 -f 1700/1784/9175 1701/1785/9176 1694/1778/9177 -f 1694/1778/9178 1695/1777/9179 1700/1784/9180 -f 1693/1806/9181 1703/1812/9182 1702/1804/9183 -f 1702/1804/9184 1692/1805/9185 1693/1806/9186 -f 1702/1804/9187 1703/1812/9188 1697/1813/9189 -f 1697/1813/9190 1698/1814/9191 1702/1804/9192 -f 1706/1790/9193 1705/1791/9194 1704/1788/9195 -f 1704/1788/9196 1707/1789/9197 1706/1790/9198 -f 1710/1794/9199 1709/1795/9200 1708/1792/9201 -f 1708/1792/9202 1711/1793/9203 1710/1794/9204 -f 1712/1797/9205 1710/1794/9206 1711/1793/9207 -f 1711/1793/9208 1713/1796/9209 1712/1797/9210 -f 1705/1791/9211 1712/1797/9212 1713/1796/9213 -f 1713/1796/9214 1704/1788/9215 1705/1791/9216 -f 1716/1817/9217 1715/1818/9218 1714/1815/9219 -f 1714/1815/9220 1717/1816/9221 1716/1817/9222 -f 1718/1820/9223 1716/1817/9224 1717/1816/9225 -f 1717/1816/9226 1719/1819/9227 1718/1820/9228 -f 1707/1789/9229 1704/1788/9230 1683/1765/9231 -f 1683/1765/9232 1680/1764/9233 1707/1789/9234 -f 1711/1793/9235 1708/1792/9236 1686/1770/9237 -f 1686/1770/9238 1687/1769/9239 1711/1793/9240 -f 1713/1796/9241 1711/1793/9242 1687/1769/9243 -f 1687/1769/9244 1688/1772/9245 1713/1796/9246 -f 1704/1788/9247 1713/1796/9248 1688/1772/9249 -f 1688/1772/9250 1683/1765/9251 1704/1788/9252 -f 1717/1816/9253 1714/1815/9254 1720/1821/9255 -f 1720/1821/9256 1721/1822/9257 1717/1816/9258 -f 1719/1819/9259 1717/1816/9260 1721/1822/9261 -f 1721/1822/9262 1722/1823/9263 1719/1819/9264 -f 1681/1767/9265 1682/1766/9266 1723/1807/9267 -f 1723/1807/9268 1724/1808/9269 1681/1767/9270 -f 1684/1768/9271 1685/1771/9272 1725/1809/9273 -f 1725/1809/9274 1726/1810/9275 1684/1768/9276 -f 1689/1773/9277 1684/1768/9278 1726/1810/9279 -f 1726/1810/9280 1727/1811/9281 1689/1773/9282 -f 1682/1766/9283 1689/1773/9284 1727/1811/9285 -f 1727/1811/9286 1723/1807/9287 1682/1766/9288 -f 1730/1826/9289 1729/1827/9290 1728/1824/9291 -f 1728/1824/9292 1731/1825/9293 1730/1826/9294 -f 1732/1829/9295 1730/1826/9296 1731/1825/9297 -f 1731/1825/9298 1733/1828/9299 1732/1829/9300 -f 1724/1808/9301 1723/1807/9302 1695/1777/9303 -f 1695/1777/9304 1692/1776/9305 1724/1808/9306 -f 1726/1810/9307 1725/1809/9308 1698/1782/9309 -f 1698/1782/9310 1699/1781/9311 1726/1810/9312 -f 1727/1811/9313 1726/1810/9314 1699/1781/9315 -f 1699/1781/9316 1700/1784/9317 1727/1811/9318 -f 1723/1807/9319 1727/1811/9320 1700/1784/9321 -f 1700/1784/9322 1695/1777/9323 1723/1807/9324 -f 1731/1825/9325 1728/1824/9326 1734/1830/9327 -f 1734/1830/9328 1735/1831/9329 1731/1825/9330 -f 1733/1828/9331 1731/1825/9332 1735/1831/9333 -f 1735/1831/9334 1736/1832/9335 1733/1828/9336 -f 1716/1817/9337 1737/1834/9338 1706/1833/9339 -f 1706/1833/9340 1715/1818/9341 1716/1817/9342 -f 1718/1820/9343 1709/1835/9344 1737/1834/9345 -f 1737/1834/9346 1716/1817/9347 1718/1820/9348 -f 1719/1819/9349 1708/1836/9350 1709/1835/9351 -f 1709/1835/9352 1718/1820/9353 1719/1819/9354 -f 1722/1823/9355 1686/1802/9356 1708/1836/9357 -f 1708/1836/9358 1719/1819/9359 1722/1823/9360 -f 1721/1822/9361 1691/1799/9362 1686/1802/9363 -f 1686/1802/9364 1722/1823/9365 1721/1822/9366 -f 1720/1821/9367 1680/1800/9368 1691/1799/9369 -f 1691/1799/9370 1721/1822/9371 1720/1821/9372 -f 1714/1815/9373 1707/1837/9374 1680/1800/9375 -f 1680/1800/9376 1720/1821/9377 1714/1815/9378 -f 1715/1818/9379 1706/1833/9380 1707/1837/9381 -f 1707/1837/9382 1714/1815/9383 1715/1818/9384 -f 1730/1826/9385 1690/1798/9386 1681/1801/9387 -f 1681/1801/9388 1729/1827/9389 1730/1826/9390 -f 1732/1829/9391 1685/1803/9392 1690/1798/9393 -f 1690/1798/9394 1730/1826/9395 1732/1829/9396 -f 1733/1828/9397 1725/1838/9398 1685/1803/9399 -f 1685/1803/9400 1732/1829/9401 1733/1828/9402 -f 1736/1832/9403 1698/1814/9404 1725/1838/9405 -f 1725/1838/9406 1733/1828/9407 1736/1832/9408 -f 1735/1831/9409 1702/1804/9410 1698/1814/9411 -f 1698/1814/9412 1736/1832/9413 1735/1831/9414 -f 1734/1830/9415 1692/1805/9416 1702/1804/9417 -f 1702/1804/9418 1735/1831/9419 1734/1830/9420 -f 1728/1824/9421 1724/1839/9422 1692/1805/9423 -f 1692/1805/9424 1734/1830/9425 1728/1824/9426 -f 1729/1827/9427 1681/1801/9428 1724/1839/9429 -f 1724/1839/9430 1728/1824/9431 1729/1827/9432 -f 1678/1763/9433 1679/1762/9434 1693/1779/9435 -f 1693/1779/9436 1694/1778/9437 1678/1763/9438 -f 1697/1783/9439 1674/1758/9440 1675/1761/9441 -f 1675/1761/9442 1696/1780/9443 1697/1783/9444 -f 1675/1761/9445 1676/1760/9446 1701/1785/9447 -f 1701/1785/9448 1696/1780/9449 1675/1761/9450 -f 1701/1785/9451 1676/1760/9452 1678/1763/9453 -f 1678/1763/9454 1694/1778/9455 1701/1785/9456 -f 1740/1852/9457 1739/1853/9458 1738/1840/9459 -f 1738/1840/9460 1741/1841/9461 1740/1852/9462 -f 1741/1841/9463 1738/1840/9464 1742/1870/9465 -f 1742/1870/9466 1743/1871/9467 1741/1841/9468 -f 1744/1894/9469 1679/1895/9470 1677/1882/9471 -f 1677/1882/9472 1745/1883/9473 1744/1894/9474 -f 1746/1896/9475 1693/1806/9476 1679/1895/9477 -f 1679/1895/9478 1744/1894/9479 1746/1896/9480 -f 1747/1897/9481 1703/1812/9482 1693/1806/9483 -f 1693/1806/9484 1746/1896/9485 1747/1897/9486 -f 1748/1898/9487 1697/1813/9488 1703/1812/9489 -f 1703/1812/9490 1747/1897/9491 1748/1898/9492 -f 1749/1899/9493 1674/1900/9494 1697/1813/9495 -f 1697/1813/9496 1748/1898/9497 1749/1899/9498 -f 1745/1883/9499 1677/1882/9500 1674/1900/9501 -f 1674/1900/9502 1749/1899/9503 1745/1883/9504 -f 1739/1853/9505 1744/1894/9506 1745/1883/9507 -f 1745/1883/9508 1738/1840/9509 1739/1853/9510 -f 1740/1852/9511 1746/1896/9512 1744/1894/9513 -f 1744/1894/9514 1739/1853/9515 1740/1852/9516 -f 1741/1841/9517 1747/1897/9518 1746/1896/9519 -f 1746/1896/9520 1740/1852/9521 1741/1841/9522 -f 1743/1871/9523 1748/1898/9524 1747/1897/9525 -f 1747/1897/9526 1741/1841/9527 1743/1871/9528 -f 1742/1870/9529 1749/1899/9530 1748/1898/9531 -f 1748/1898/9532 1743/1871/9533 1742/1870/9534 -f 1738/1840/9535 1745/1883/9536 1749/1899/9537 -f 1749/1899/9538 1742/1870/9539 1738/1840/9540 -f 1752/1908/9541 1751/1909/9542 1750/1901/9543 -f 1750/1901/9544 1753/1902/9545 1752/1908/9546 -f 1754/1911/9547 1648/1734/9548 1649/1733/9549 -f 1649/1733/9550 1755/1910/9551 1754/1911/9552 -f 1756/1913/9553 1751/1909/9554 1752/1908/9555 -f 1752/1908/9556 1757/1912/9557 1756/1913/9558 -f 1622/1706/9559 1623/1705/9560 1655/1740/9561 -f 1655/1740/9562 1635/1719/9563 1622/1706/9564 -f 1655/1740/9565 1623/1705/9566 1646/1729/9567 -f 1646/1729/9568 1639/1723/9569 1655/1740/9570 -f 1659/1743/9571 1660/1746/9572 1619/1701/9573 -f 1619/1701/9574 1671/1755/9575 1659/1743/9576 -f 1661/1745/9577 1662/1744/9578 1758/1842/9579 -f 1758/1842/9580 1759/1843/9581 1661/1745/9582 -f 1761/1844/9583 1760/1845/9584 1668/1752/9585 -f 1668/1752/9586 1667/1751/9587 1761/1844/9588 -f 1638/1720/9589 1705/1791/9590 1706/1790/9591 -f 1706/1790/9592 1637/1721/9593 1638/1720/9594 -f 1709/1795/9595 1710/1794/9596 1640/1726/9597 -f 1640/1726/9598 1641/1725/9599 1709/1795/9600 -f 1640/1726/9601 1710/1794/9602 1712/1797/9603 -f 1712/1797/9604 1656/1739/9605 1640/1726/9606 -f 1712/1797/9607 1705/1791/9608 1638/1720/9609 -f 1638/1720/9610 1656/1739/9611 1712/1797/9612 -f 1637/1742/9613 1706/1833/9614 1737/1834/9615 -f 1737/1834/9616 1658/1747/9617 1637/1742/9618 -f 1737/1834/9619 1709/1835/9620 1641/1750/9621 -f 1641/1750/9622 1658/1747/9623 1737/1834/9624 -f 1763/1847/9625 1762/1848/9626 1671/1755/9627 -f 1671/1755/9628 1764/1846/9629 1763/1847/9630 -f 1766/1849/9631 1765/1850/9632 1635/1719/9633 -f 1635/1719/9634 1636/1722/9635 1766/1849/9636 -f 1767/1851/9637 1643/1727/9638 1635/1719/9639 -f 1635/1719/9640 1765/1850/9641 1767/1851/9642 -f 1767/1851/9643 1764/1846/9644 1671/1755/9645 -f 1671/1755/9646 1643/1727/9647 1767/1851/9648 -f 1768/1915/9649 1766/1916/9650 1636/1741/9651 -f 1636/1741/9652 1769/1914/9653 1768/1915/9654 -f 1772/1856/9655 1771/1857/9656 1770/1854/9657 -f 1770/1854/9658 1773/1855/9659 1772/1856/9660 -f 1774/1859/9661 1772/1856/9662 1773/1855/9663 -f 1773/1855/9664 1775/1858/9665 1774/1859/9666 -f 1778/1862/9667 1777/1863/9668 1776/1860/9669 -f 1776/1860/9670 1779/1861/9671 1778/1862/9672 -f 1782/1866/9673 1781/1867/9674 1780/1864/9675 -f 1780/1864/9676 1783/1865/9677 1782/1866/9678 -f 1780/1864/9679 1785/1869/9680 1784/1868/9681 -f 1784/1868/9682 1783/1865/9683 1780/1864/9684 -f 1784/1868/9685 1785/1869/9686 1778/1862/9687 -f 1778/1862/9688 1779/1861/9689 1784/1868/9690 -f 1776/1919/9691 1777/1920/9692 1786/1917/9693 -f 1786/1917/9694 1787/1918/9695 1776/1919/9696 -f 1786/1917/9697 1781/1922/9698 1782/1921/9699 -f 1782/1921/9700 1787/1918/9701 1786/1917/9702 -f 1790/1874/9703 1789/1875/9704 1788/1872/9705 -f 1788/1872/9706 1791/1873/9707 1790/1874/9708 -f 1794/1878/9709 1793/1879/9710 1792/1876/9711 -f 1792/1876/9712 1795/1877/9713 1794/1878/9714 -f 1792/1876/9715 1797/1881/9716 1796/1880/9717 -f 1796/1880/9718 1795/1877/9719 1792/1876/9720 -f 1796/1880/9721 1797/1881/9722 1790/1874/9723 -f 1790/1874/9724 1791/1873/9725 1796/1880/9726 -f 1789/1925/9727 1799/1926/9728 1798/1923/9729 -f 1798/1923/9730 1788/1924/9731 1789/1925/9732 -f 1798/1923/9733 1799/1926/9734 1793/1927/9735 -f 1793/1927/9736 1794/1928/9737 1798/1923/9738 -f 1802/1886/9739 1801/1887/9740 1800/1884/9741 -f 1800/1884/9742 1803/1885/9743 1802/1886/9744 -f 1806/1890/9745 1805/1891/9746 1804/1888/9747 -f 1804/1888/9748 1807/1889/9749 1806/1890/9750 -f 1808/1893/9751 1806/1890/9752 1807/1889/9753 -f 1807/1889/9754 1809/1892/9755 1808/1893/9756 -f 1801/1887/9757 1808/1893/9758 1809/1892/9759 -f 1809/1892/9760 1800/1884/9761 1801/1887/9762 -f 1812/1936/9763 1811/1953/9764 1810/1929/9765 -f 1810/1929/9766 1813/1935/9767 1812/1936/9768 -f 1814/1965/9769 1812/1936/9770 1813/1935/9771 -f 1813/1935/9772 1815/1954/9773 1814/1965/9774 -f 1803/1885/9775 1800/1884/9776 1779/1861/9777 -f 1779/1861/9778 1776/1860/9779 1803/1885/9780 -f 1807/1889/9781 1804/1888/9782 1782/1866/9783 -f 1782/1866/9784 1783/1865/9785 1807/1889/9786 -f 1809/1892/9787 1807/1889/9788 1783/1865/9789 -f 1783/1865/9790 1784/1868/9791 1809/1892/9792 -f 1800/1884/9793 1809/1892/9794 1784/1868/9795 -f 1784/1868/9796 1779/1861/9797 1800/1884/9798 -f 1813/1935/9799 1810/1929/9800 1816/1966/9801 -f 1816/1966/9802 1817/1977/9803 1813/1935/9804 -f 1815/1954/9805 1813/1935/9806 1817/1977/9807 -f 1817/1977/9808 1818/1978/9809 1815/1954/9810 -f 1777/1863/9811 1778/1862/9812 1819/1903/9813 -f 1819/1903/9814 1820/1904/9815 1777/1863/9816 -f 1780/1864/9817 1781/1867/9818 1821/1905/9819 -f 1821/1905/9820 1822/1906/9821 1780/1864/9822 -f 1785/1869/9823 1780/1864/9824 1822/1906/9825 -f 1822/1906/9826 1823/1907/9827 1785/1869/9828 -f 1778/1862/9829 1785/1869/9830 1823/1907/9831 -f 1823/1907/9832 1819/1903/9833 1778/1862/9834 -f 1826/1981/9835 1825/1982/9836 1824/1979/9837 -f 1824/1979/9838 1827/1980/9839 1826/1981/9840 -f 1828/1984/9841 1826/1981/9842 1827/1980/9843 -f 1827/1980/9844 1829/1983/9845 1828/1984/9846 -f 1820/1904/9847 1819/1903/9848 1791/1873/9849 -f 1791/1873/9850 1788/1872/9851 1820/1904/9852 -f 1822/1906/9853 1821/1905/9854 1794/1878/9855 -f 1794/1878/9856 1795/1877/9857 1822/1906/9858 -f 1823/1907/9859 1822/1906/9860 1795/1877/9861 -f 1795/1877/9862 1796/1880/9863 1823/1907/9864 -f 1819/1903/9865 1823/1907/9866 1796/1880/9867 -f 1796/1880/9868 1791/1873/9869 1819/1903/9870 -f 1827/1980/9871 1824/1979/9872 1830/1985/9873 -f 1830/1985/9874 1831/1991/9875 1827/1980/9876 -f 1829/1983/9877 1827/1980/9878 1831/1991/9879 -f 1831/1991/9880 1832/1992/9881 1829/1983/9882 -f 1812/1936/9883 1833/1994/9884 1802/1993/9885 -f 1802/1993/9886 1811/1953/9887 1812/1936/9888 -f 1814/1965/9889 1805/1995/9890 1833/1994/9891 -f 1833/1994/9892 1812/1936/9893 1814/1965/9894 -f 1815/1954/9895 1804/1996/9896 1805/1995/9897 -f 1805/1995/9898 1814/1965/9899 1815/1954/9900 -f 1818/1978/9901 1782/1921/9902 1804/1996/9903 -f 1804/1996/9904 1815/1954/9905 1818/1978/9906 -f 1817/1977/9907 1787/1918/9908 1782/1921/9909 -f 1782/1921/9910 1818/1978/9911 1817/1977/9912 -f 1816/1966/9913 1776/1919/9914 1787/1918/9915 -f 1787/1918/9916 1817/1977/9917 1816/1966/9918 -f 1810/1929/9919 1803/1997/9920 1776/1919/9921 -f 1776/1919/9922 1816/1966/9923 1810/1929/9924 -f 1811/1953/9925 1802/1993/9926 1803/1997/9927 -f 1803/1997/9928 1810/1929/9929 1811/1953/9930 -f 1826/1981/9931 1786/1917/9932 1777/1920/9933 -f 1777/1920/9934 1825/1982/9935 1826/1981/9936 -f 1828/1984/9937 1781/1922/9938 1786/1917/9939 -f 1786/1917/9940 1826/1981/9941 1828/1984/9942 -f 1829/1983/9943 1821/1998/9944 1781/1922/9945 -f 1781/1922/9946 1828/1984/9947 1829/1983/9948 -f 1832/1992/9949 1794/1928/9950 1821/1998/9951 -f 1821/1998/9952 1829/1983/9953 1832/1992/9954 -f 1831/1991/9955 1798/1923/9956 1794/1928/9957 -f 1794/1928/9958 1832/1992/9959 1831/1991/9960 -f 1830/1985/9961 1788/1924/9962 1798/1923/9963 -f 1798/1923/9964 1831/1991/9965 1830/1985/9966 -f 1824/1979/9967 1820/1999/9968 1788/1924/9969 -f 1788/1924/9970 1830/1985/9971 1824/1979/9972 -f 1825/1982/9973 1777/1920/9974 1820/1999/9975 -f 1820/1999/9976 1824/1979/9977 1825/1982/9978 -f 1774/1859/9979 1775/1858/9980 1789/1875/9981 -f 1789/1875/9982 1790/1874/9983 1774/1859/9984 -f 1793/1879/9985 1770/1854/9986 1771/1857/9987 -f 1771/1857/9988 1792/1876/9989 1793/1879/9990 -f 1771/1857/9991 1772/1856/9992 1797/1881/9993 -f 1797/1881/9994 1792/1876/9995 1771/1857/9996 -f 1797/1881/9997 1772/1856/9998 1774/1859/9999 -f 1774/1859/10000 1790/1874/10001 1797/1881/10002 -f 1836/2002/10003 1835/2003/10004 1834/2000/10005 -f 1834/2000/10006 1837/2001/10007 1836/2002/10008 -f 1837/2001/10009 1834/2000/10010 1838/2004/10011 -f 1838/2004/10012 1839/2005/10013 1837/2001/10014 -f 1840/2008/10015 1775/2009/10016 1773/2006/10017 -f 1773/2006/10018 1841/2007/10019 1840/2008/10020 -f 1842/2010/10021 1789/1925/10022 1775/2009/10023 -f 1775/2009/10024 1840/2008/10025 1842/2010/10026 -f 1843/2011/10027 1799/1926/10028 1789/1925/10029 -f 1789/1925/10030 1842/2010/10031 1843/2011/10032 -f 1844/2012/10033 1793/1927/10034 1799/1926/10035 -f 1799/1926/10036 1843/2011/10037 1844/2012/10038 -f 1845/2018/10039 1770/2019/10040 1793/1927/10041 -f 1793/1927/10042 1844/2012/10043 1845/2018/10044 -f 1841/2007/10045 1773/2006/10046 1770/2019/10047 -f 1770/2019/10048 1845/2018/10049 1841/2007/10050 -f 1835/2003/10051 1840/2008/10052 1841/2007/10053 -f 1841/2007/10054 1834/2000/10055 1835/2003/10056 -f 1836/2002/10057 1842/2010/10058 1840/2008/10059 -f 1840/2008/10060 1835/2003/10061 1836/2002/10062 -f 1837/2001/10063 1843/2011/10064 1842/2010/10065 -f 1842/2010/10066 1836/2002/10067 1837/2001/10068 -f 1839/2005/10069 1844/2012/10070 1843/2011/10071 -f 1843/2011/10072 1837/2001/10073 1839/2005/10074 -f 1838/2004/10075 1845/2018/10076 1844/2012/10077 -f 1844/2012/10078 1839/2005/10079 1838/2004/10080 -f 1834/2000/10081 1841/2007/10082 1845/2018/10083 -f 1845/2018/10084 1838/2004/10085 1834/2000/10086 -f 1764/1846/10087 1801/1887/10088 1802/1886/10089 -f 1802/1886/10090 1763/1847/10091 1764/1846/10092 -f 1805/1891/10093 1806/1890/10094 1765/1850/10095 -f 1765/1850/10096 1766/1849/10097 1805/1891/10098 -f 1765/1850/10099 1806/1890/10100 1808/1893/10101 -f 1808/1893/10102 1767/1851/10103 1765/1850/10104 -f 1808/1893/10105 1801/1887/10106 1764/1846/10107 -f 1764/1846/10108 1767/1851/10109 1808/1893/10110 -f 1763/2036/10111 1802/1993/10112 1833/1994/10113 -f 1833/1994/10114 1768/1915/10115 1763/2036/10116 -f 1833/1994/10117 1805/1995/10118 1766/1916/10119 -f 1766/1916/10120 1768/1915/10121 1833/1994/10122 -f 1846/1931/10123 1758/1842/10124 1662/1744/10125 -f 1662/1744/10126 1847/1930/10127 1846/1931/10128 -f 1849/1932/10129 1848/1933/10130 1671/1755/10131 -f 1671/1755/10132 1762/1848/10133 1849/1932/10134 -f 1850/1934/10135 1659/1743/10136 1671/1755/10137 -f 1671/1755/10138 1848/1933/10139 1850/1934/10140 -f 1850/1934/10141 1847/1930/10142 1662/1744/10143 -f 1662/1744/10144 1659/1743/10145 1850/1934/10146 -f 1852/2049/10147 1851/2060/10148 1758/2037/10149 -f 1758/2037/10150 1846/2048/10151 1852/2049/10152 -f 1852/2049/10153 1849/2062/10154 1762/2061/10155 -f 1762/2061/10156 1851/2060/10157 1852/2049/10158 -f 1855/1939/10159 1854/1940/10160 1853/1937/10161 -f 1853/1937/10162 1856/1938/10163 1855/1939/10164 -f 1857/1942/10165 1855/1939/10166 1856/1938/10167 -f 1856/1938/10168 1858/1941/10169 1857/1942/10170 -f 1861/1945/10171 1860/1946/10172 1859/1943/10173 -f 1859/1943/10174 1862/1944/10175 1861/1945/10176 -f 1865/1949/10177 1864/1950/10178 1863/1947/10179 -f 1863/1947/10180 1866/1948/10181 1865/1949/10182 -f 1863/1947/10183 1868/1952/10184 1867/1951/10185 -f 1867/1951/10186 1866/1948/10187 1863/1947/10188 -f 1867/1951/10189 1868/1952/10190 1861/1945/10191 -f 1861/1945/10192 1862/1944/10193 1867/1951/10194 -f 1859/2065/10195 1860/2066/10196 1869/2063/10197 -f 1869/2063/10198 1870/2064/10199 1859/2065/10200 -f 1869/2063/10201 1864/2068/10202 1865/2067/10203 -f 1865/2067/10204 1870/2064/10205 1869/2063/10206 -f 1873/1957/10207 1872/1958/10208 1871/1955/10209 -f 1871/1955/10210 1874/1956/10211 1873/1957/10212 -f 1877/1961/10213 1876/1962/10214 1875/1959/10215 -f 1875/1959/10216 1878/1960/10217 1877/1961/10218 -f 1875/1959/10219 1880/1964/10220 1879/1963/10221 -f 1879/1963/10222 1878/1960/10223 1875/1959/10224 -f 1879/1963/10225 1880/1964/10226 1873/1957/10227 -f 1873/1957/10228 1874/1956/10229 1879/1963/10230 -f 1872/2076/10231 1882/2077/10232 1881/2074/10233 -f 1881/2074/10234 1871/2075/10235 1872/2076/10236 -f 1881/2074/10237 1882/2077/10238 1876/2078/10239 -f 1876/2078/10240 1877/2079/10241 1881/2074/10242 -f 1885/1969/10243 1884/1970/10244 1883/1967/10245 -f 1883/1967/10246 1886/1968/10247 1885/1969/10248 -f 1889/1973/10249 1888/1974/10250 1887/1971/10251 -f 1887/1971/10252 1890/1972/10253 1889/1973/10254 -f 1891/1976/10255 1889/1973/10256 1890/1972/10257 -f 1890/1972/10258 1892/1975/10259 1891/1976/10260 -f 1884/1970/10261 1891/1976/10262 1892/1975/10263 -f 1892/1975/10264 1883/1967/10265 1884/1970/10266 -f 1895/2082/10267 1894/2083/10268 1893/2080/10269 -f 1893/2080/10270 1896/2081/10271 1895/2082/10272 -f 1897/2085/10273 1895/2082/10274 1896/2081/10275 -f 1896/2081/10276 1898/2084/10277 1897/2085/10278 -f 1886/1968/10279 1883/1967/10280 1862/1944/10281 -f 1862/1944/10282 1859/1943/10283 1886/1968/10284 -f 1890/1972/10285 1887/1971/10286 1865/1949/10287 -f 1865/1949/10288 1866/1948/10289 1890/1972/10290 -f 1892/1975/10291 1890/1972/10292 1866/1948/10293 -f 1866/1948/10294 1867/1951/10295 1892/1975/10296 -f 1883/1967/10297 1892/1975/10298 1867/1951/10299 -f 1867/1951/10300 1862/1944/10301 1883/1967/10302 -f 1896/2081/10303 1893/2080/10304 1899/2086/10305 -f 1899/2086/10306 1900/2087/10307 1896/2081/10308 -f 1898/2084/10309 1896/2081/10310 1900/2087/10311 -f 1900/2087/10312 1901/2088/10313 1898/2084/10314 -f 1860/1946/10315 1861/1945/10316 1902/1986/10317 -f 1902/1986/10318 1903/1987/10319 1860/1946/10320 -f 1863/1947/10321 1864/1950/10322 1904/1988/10323 -f 1904/1988/10324 1905/1989/10325 1863/1947/10326 -f 1868/1952/10327 1863/1947/10328 1905/1989/10329 -f 1905/1989/10330 1906/1990/10331 1868/1952/10332 -f 1861/1945/10333 1868/1952/10334 1906/1990/10335 -f 1906/1990/10336 1902/1986/10337 1861/1945/10338 -f 1909/2091/10339 1908/2092/10340 1907/2089/10341 -f 1907/2089/10342 1910/2090/10343 1909/2091/10344 -f 1911/2094/10345 1909/2091/10346 1910/2090/10347 -f 1910/2090/10348 1912/2093/10349 1911/2094/10350 -f 1903/1987/10351 1902/1986/10352 1874/1956/10353 -f 1874/1956/10354 1871/1955/10355 1903/1987/10356 -f 1905/1989/10357 1904/1988/10358 1877/1961/10359 -f 1877/1961/10360 1878/1960/10361 1905/1989/10362 -f 1906/1990/10363 1905/1989/10364 1878/1960/10365 -f 1878/1960/10366 1879/1963/10367 1906/1990/10368 -f 1902/1986/10369 1906/1990/10370 1879/1963/10371 -f 1879/1963/10372 1874/1956/10373 1902/1986/10374 -f 1910/2090/10375 1907/2089/10376 1913/2095/10377 -f 1913/2095/10378 1914/2096/10379 1910/2090/10380 -f 1912/2093/10381 1910/2090/10382 1914/2096/10383 -f 1914/2096/10384 1915/2097/10385 1912/2093/10386 -f 1895/2082/10387 1916/2099/10388 1885/2098/10389 -f 1885/2098/10390 1894/2083/10391 1895/2082/10392 -f 1897/2085/10393 1888/2100/10394 1916/2099/10395 -f 1916/2099/10396 1895/2082/10397 1897/2085/10398 -f 1898/2084/10399 1887/2104/10400 1888/2100/10401 -f 1888/2100/10402 1897/2085/10403 1898/2084/10404 -f 1901/2088/10405 1865/2067/10406 1887/2104/10407 -f 1887/2104/10408 1898/2084/10409 1901/2088/10410 -f 1900/2087/10411 1870/2064/10412 1865/2067/10413 -f 1865/2067/10414 1901/2088/10415 1900/2087/10416 -f 1899/2086/10417 1859/2065/10418 1870/2064/10419 -f 1870/2064/10420 1900/2087/10421 1899/2086/10422 -f 1893/2080/10423 1886/2105/10424 1859/2065/10425 -f 1859/2065/10426 1899/2086/10427 1893/2080/10428 -f 1894/2083/10429 1885/2098/10430 1886/2105/10431 -f 1886/2105/10432 1893/2080/10433 1894/2083/10434 -f 1909/2091/10435 1869/2063/10436 1860/2066/10437 -f 1860/2066/10438 1908/2092/10439 1909/2091/10440 -f 1911/2094/10441 1864/2068/10442 1869/2063/10443 -f 1869/2063/10444 1909/2091/10445 1911/2094/10446 -f 1912/2093/10447 1904/2106/10448 1864/2068/10449 -f 1864/2068/10450 1911/2094/10451 1912/2093/10452 -f 1915/2097/10453 1877/2079/10454 1904/2106/10455 -f 1904/2106/10456 1912/2093/10457 1915/2097/10458 -f 1914/2096/10459 1881/2074/10460 1877/2079/10461 -f 1877/2079/10462 1915/2097/10463 1914/2096/10464 -f 1913/2095/10465 1871/2075/10466 1881/2074/10467 -f 1881/2074/10468 1914/2096/10469 1913/2095/10470 -f 1907/2089/10471 1903/2128/10472 1871/2075/10473 -f 1871/2075/10474 1913/2095/10475 1907/2089/10476 -f 1908/2092/10477 1860/2066/10478 1903/2128/10479 -f 1903/2128/10480 1907/2089/10481 1908/2092/10482 -f 1857/1942/10483 1858/1941/10484 1872/1958/10485 -f 1872/1958/10486 1873/1957/10487 1857/1942/10488 -f 1876/1962/10489 1853/1937/10490 1854/1940/10491 -f 1854/1940/10492 1875/1959/10493 1876/1962/10494 -f 1854/1940/10495 1855/1939/10496 1880/1964/10497 -f 1880/1964/10498 1875/1959/10499 1854/1940/10500 -f 1880/1964/10501 1855/1939/10502 1857/1942/10503 -f 1857/1942/10504 1873/1957/10505 1880/1964/10506 -f 1919/2133/10507 1918/2134/10508 1917/2129/10509 -f 1917/2129/10510 1920/2132/10511 1919/2133/10512 -f 1920/2132/10513 1917/2129/10514 1921/2135/10515 -f 1921/2135/10516 1922/2136/10517 1920/2132/10518 -f 1923/2140/10519 1858/2141/10520 1856/2137/10521 -f 1856/2137/10522 1924/2139/10523 1923/2140/10524 -f 1925/2142/10525 1872/2076/10526 1858/2141/10527 -f 1858/2141/10528 1923/2140/10529 1925/2142/10530 -f 1926/2143/10531 1882/2077/10532 1872/2076/10533 -f 1872/2076/10534 1925/2142/10535 1926/2143/10536 -f 1927/2148/10537 1876/2078/10538 1882/2077/10539 -f 1882/2077/10540 1926/2143/10541 1927/2148/10542 -f 1928/2149/10543 1853/2150/10544 1876/2078/10545 -f 1876/2078/10546 1927/2148/10547 1928/2149/10548 -f 1924/2139/10549 1856/2137/10550 1853/2150/10551 -f 1853/2150/10552 1928/2149/10553 1924/2139/10554 -f 1918/2134/10555 1923/2140/10556 1924/2139/10557 -f 1924/2139/10558 1917/2129/10559 1918/2134/10560 -f 1919/2133/10561 1925/2142/10562 1923/2140/10563 -f 1923/2140/10564 1918/2134/10565 1919/2133/10566 -f 1920/2132/10567 1926/2143/10568 1925/2142/10569 -f 1925/2142/10570 1919/2133/10571 1920/2132/10572 -f 1922/2136/10573 1927/2148/10574 1926/2143/10575 -f 1926/2143/10576 1920/2132/10577 1922/2136/10578 -f 1921/2135/10579 1928/2149/10580 1927/2148/10581 -f 1927/2148/10582 1922/2136/10583 1921/2135/10584 -f 1917/2129/10585 1924/2139/10586 1928/2149/10587 -f 1928/2149/10588 1921/2135/10589 1917/2129/10590 -f 1847/1930/10591 1884/1970/10592 1885/1969/10593 -f 1885/1969/10594 1846/1931/10595 1847/1930/10596 -f 1888/1974/10597 1889/1973/10598 1848/1933/10599 -f 1848/1933/10600 1849/1932/10601 1888/1974/10602 -f 1848/1933/10603 1889/1973/10604 1891/1976/10605 -f 1891/1976/10606 1850/1934/10607 1848/1933/10608 -f 1891/1976/10609 1884/1970/10610 1847/1930/10611 -f 1847/1930/10612 1850/1934/10613 1891/1976/10614 -f 1846/2048/10615 1885/2098/10616 1916/2099/10617 -f 1916/2099/10618 1852/2049/10619 1846/2048/10620 -f 1916/2099/10621 1888/2100/10622 1849/2062/10623 -f 1849/2062/10624 1852/2049/10625 1916/2099/10626 -f 1929/2014/10627 1642/1724/10628 1639/1723/10629 -f 1639/1723/10630 1930/2013/10631 1929/2014/10632 -f 1932/2015/10633 1931/2016/10634 1668/1752/10635 -f 1668/1752/10636 1760/1845/10637 1932/2015/10638 -f 1933/2017/10639 1644/1728/10640 1668/1752/10641 -f 1668/1752/10642 1931/2016/10643 1933/2017/10644 -f 1933/2017/10645 1930/2013/10646 1639/1723/10647 -f 1639/1723/10648 1644/1728/10649 1933/2017/10650 -f 1935/2152/10651 1934/2153/10652 1642/1749/10653 -f 1642/1749/10654 1929/2151/10655 1935/2152/10656 -f 1935/2152/10657 1932/2160/10658 1760/2159/10659 -f 1760/2159/10660 1934/2153/10661 1935/2152/10662 -f 1938/2022/10663 1937/2023/10664 1936/2020/10665 -f 1936/2020/10666 1939/2021/10667 1938/2022/10668 -f 1940/2025/10669 1938/2022/10670 1939/2021/10671 -f 1939/2021/10672 1941/2024/10673 1940/2025/10674 -f 1944/2028/10675 1943/2029/10676 1942/2026/10677 -f 1942/2026/10678 1945/2027/10679 1944/2028/10680 -f 1948/2032/10681 1947/2033/10682 1946/2030/10683 -f 1946/2030/10684 1949/2031/10685 1948/2032/10686 -f 1946/2030/10687 1951/2035/10688 1950/2034/10689 -f 1950/2034/10690 1949/2031/10691 1946/2030/10692 -f 1950/2034/10693 1951/2035/10694 1944/2028/10695 -f 1944/2028/10696 1945/2027/10697 1950/2034/10698 -f 1942/2163/10699 1943/2164/10700 1952/2161/10701 -f 1952/2161/10702 1953/2162/10703 1942/2163/10704 -f 1952/2161/10705 1947/2167/10706 1948/2166/10707 -f 1948/2166/10708 1953/2162/10709 1952/2161/10710 -f 1956/2040/10711 1955/2041/10712 1954/2038/10713 -f 1954/2038/10714 1957/2039/10715 1956/2040/10716 -f 1960/2044/10717 1959/2045/10718 1958/2042/10719 -f 1958/2042/10720 1961/2043/10721 1960/2044/10722 -f 1958/2042/10723 1963/2047/10724 1962/2046/10725 -f 1962/2046/10726 1961/2043/10727 1958/2042/10728 -f 1962/2046/10729 1963/2047/10730 1956/2040/10731 -f 1956/2040/10732 1957/2039/10733 1962/2046/10734 -f 1955/2170/10735 1965/2171/10736 1964/2168/10737 -f 1964/2168/10738 1954/2169/10739 1955/2170/10740 -f 1964/2168/10741 1965/2171/10742 1959/2172/10743 -f 1959/2172/10744 1960/2173/10745 1964/2168/10746 -f 1968/2052/10747 1967/2053/10748 1966/2050/10749 -f 1966/2050/10750 1969/2051/10751 1968/2052/10752 -f 1972/2056/10753 1971/2057/10754 1970/2054/10755 -f 1970/2054/10756 1973/2055/10757 1972/2056/10758 -f 1974/2059/10759 1972/2056/10760 1973/2055/10761 -f 1973/2055/10762 1975/2058/10763 1974/2059/10764 -f 1967/2053/10765 1974/2059/10766 1975/2058/10767 -f 1975/2058/10768 1966/2050/10769 1967/2053/10770 -f 1978/2183/10771 1977/2185/10772 1976/2174/10773 -f 1976/2174/10774 1979/2175/10775 1978/2183/10776 -f 1980/2187/10777 1978/2183/10778 1979/2175/10779 -f 1979/2175/10780 1981/2186/10781 1980/2187/10782 -f 1969/2051/10783 1966/2050/10784 1945/2027/10785 -f 1945/2027/10786 1942/2026/10787 1969/2051/10788 -f 1973/2055/10789 1970/2054/10790 1948/2032/10791 -f 1948/2032/10792 1949/2031/10793 1973/2055/10794 -f 1975/2058/10795 1973/2055/10796 1949/2031/10797 -f 1949/2031/10798 1950/2034/10799 1975/2058/10800 -f 1966/2050/10801 1975/2058/10802 1950/2034/10803 -f 1950/2034/10804 1945/2027/10805 1966/2050/10806 -f 1979/2175/10807 1976/2174/10808 1982/2188/10809 -f 1982/2188/10810 1983/2189/10811 1979/2175/10812 -f 1981/2186/10813 1979/2175/10814 1983/2189/10815 -f 1983/2189/10816 1984/2190/10817 1981/2186/10818 -f 1943/2029/10819 1944/2028/10820 1985/2069/10821 -f 1985/2069/10822 1986/2070/10823 1943/2029/10824 -f 1946/2030/10825 1947/2033/10826 1987/2071/10827 -f 1987/2071/10828 1988/2072/10829 1946/2030/10830 -f 1951/2035/10831 1946/2030/10832 1988/2072/10833 -f 1988/2072/10834 1989/2073/10835 1951/2035/10836 -f 1944/2028/10837 1951/2035/10838 1989/2073/10839 -f 1989/2073/10840 1985/2069/10841 1944/2028/10842 -f 1992/2196/10843 1991/2197/10844 1990/2191/10845 -f 1990/2191/10846 1993/2195/10847 1992/2196/10848 -f 1994/2205/10849 1992/2196/10850 1993/2195/10851 -f 1993/2195/10852 1995/2198/10853 1994/2205/10854 -f 1986/2070/10855 1985/2069/10856 1957/2039/10857 -f 1957/2039/10858 1954/2038/10859 1986/2070/10860 -f 1988/2072/10861 1987/2071/10862 1960/2044/10863 -f 1960/2044/10864 1961/2043/10865 1988/2072/10866 -f 1989/2073/10867 1988/2072/10868 1961/2043/10869 -f 1961/2043/10870 1962/2046/10871 1989/2073/10872 -f 1985/2069/10873 1989/2073/10874 1962/2046/10875 -f 1962/2046/10876 1957/2039/10877 1985/2069/10878 -f 1993/2195/10879 1990/2191/10880 1996/2212/10881 -f 1996/2212/10882 1997/2213/10883 1993/2195/10884 -f 1995/2198/10885 1993/2195/10886 1997/2213/10887 -f 1997/2213/10888 1998/2214/10889 1995/2198/10890 -f 1978/2183/10891 1999/2216/10892 1968/2215/10893 -f 1968/2215/10894 1977/2185/10895 1978/2183/10896 -f 1980/2187/10897 1971/2217/10898 1999/2216/10899 -f 1999/2216/10900 1978/2183/10901 1980/2187/10902 -f 1981/2186/10903 1970/2218/10904 1971/2217/10905 -f 1971/2217/10906 1980/2187/10907 1981/2186/10908 -f 1984/2190/10909 1948/2166/10910 1970/2218/10911 -f 1970/2218/10912 1981/2186/10913 1984/2190/10914 -f 1983/2189/10915 1953/2162/10916 1948/2166/10917 -f 1948/2166/10918 1984/2190/10919 1983/2189/10920 -f 1982/2188/10921 1942/2163/10922 1953/2162/10923 -f 1953/2162/10924 1983/2189/10925 1982/2188/10926 -f 1976/2174/10927 1969/2219/10928 1942/2163/10929 -f 1942/2163/10930 1982/2188/10931 1976/2174/10932 -f 1977/2185/10933 1968/2215/10934 1969/2219/10935 -f 1969/2219/10936 1976/2174/10937 1977/2185/10938 -f 1992/2196/10939 1952/2161/10940 1943/2164/10941 -f 1943/2164/10942 1991/2197/10943 1992/2196/10944 -f 1994/2205/10945 1947/2167/10946 1952/2161/10947 -f 1952/2161/10948 1992/2196/10949 1994/2205/10950 -f 1995/2198/10951 1987/2220/10952 1947/2167/10953 -f 1947/2167/10954 1994/2205/10955 1995/2198/10956 -f 1998/2214/10957 1960/2173/10958 1987/2220/10959 -f 1987/2220/10960 1995/2198/10961 1998/2214/10962 -f 1997/2213/10963 1964/2168/10964 1960/2173/10965 -f 1960/2173/10966 1998/2214/10967 1997/2213/10968 -f 1996/2212/10969 1954/2169/10970 1964/2168/10971 -f 1964/2168/10972 1997/2213/10973 1996/2212/10974 -f 1990/2191/10975 1986/2221/10976 1954/2169/10977 -f 1954/2169/10978 1996/2212/10979 1990/2191/10980 -f 1991/2197/10981 1943/2164/10982 1986/2221/10983 -f 1986/2221/10984 1990/2191/10985 1991/2197/10986 -f 1940/2025/10987 1941/2024/10988 1955/2041/10989 -f 1955/2041/10990 1956/2040/10991 1940/2025/10992 -f 1959/2045/10993 1936/2020/10994 1937/2023/10995 -f 1937/2023/10996 1958/2042/10997 1959/2045/10998 -f 1937/2023/10999 1938/2022/11000 1963/2047/11001 -f 1963/2047/11002 1958/2042/11003 1937/2023/11004 -f 1963/2047/11005 1938/2022/11006 1940/2025/11007 -f 1940/2025/11008 1956/2040/11009 1963/2047/11010 -f 2002/2224/11011 2001/2252/11012 2000/2222/11013 -f 2000/2222/11014 2003/2223/11015 2002/2224/11016 -f 2003/2223/11017 2000/2222/11018 2004/2253/11019 -f 2004/2253/11020 2005/2254/11021 2003/2223/11022 -f 2006/2260/11023 1941/2261/11024 1939/2255/11025 -f 1939/2255/11026 2007/2259/11027 2006/2260/11028 -f 2008/2262/11029 1955/2170/11030 1941/2261/11031 -f 1941/2261/11032 2006/2260/11033 2008/2262/11034 -f 2009/2263/11035 1965/2171/11036 1955/2170/11037 -f 1955/2170/11038 2008/2262/11039 2009/2263/11040 -f 2010/2264/11041 1959/2172/11042 1965/2171/11043 -f 1965/2171/11044 2009/2263/11045 2010/2264/11046 -f 2011/2265/11047 1936/2266/11048 1959/2172/11049 -f 1959/2172/11050 2010/2264/11051 2011/2265/11052 -f 2007/2259/11053 1939/2255/11054 1936/2266/11055 -f 1936/2266/11056 2011/2265/11057 2007/2259/11058 -f 2001/2252/11059 2006/2260/11060 2007/2259/11061 -f 2007/2259/11062 2000/2222/11063 2001/2252/11064 -f 2002/2224/11065 2008/2262/11066 2006/2260/11067 -f 2006/2260/11068 2001/2252/11069 2002/2224/11070 -f 2003/2223/11071 2009/2263/11072 2008/2262/11073 -f 2008/2262/11074 2002/2224/11075 2003/2223/11076 -f 2005/2254/11077 2010/2264/11078 2009/2263/11079 -f 2009/2263/11080 2003/2223/11081 2005/2254/11082 -f 2004/2253/11083 2011/2265/11084 2010/2264/11085 -f 2010/2264/11086 2005/2254/11087 2004/2253/11088 -f 2000/2222/11089 2007/2259/11090 2011/2265/11091 -f 2011/2265/11092 2004/2253/11093 2000/2222/11094 -f 1930/2013/11095 1967/2053/11096 1968/2052/11097 -f 1968/2052/11098 1929/2014/11099 1930/2013/11100 -f 1971/2057/11101 1972/2056/11102 1931/2016/11103 -f 1931/2016/11104 1932/2015/11105 1971/2057/11106 -f 1931/2016/11107 1972/2056/11108 1974/2059/11109 -f 1974/2059/11110 1933/2017/11111 1931/2016/11112 -f 1974/2059/11113 1967/2053/11114 1930/2013/11115 -f 1930/2013/11116 1933/2017/11117 1974/2059/11118 -f 1929/2151/11119 1968/2215/11120 1999/2216/11121 -f 1999/2216/11122 1935/2152/11123 1929/2151/11124 -f 1999/2216/11125 1971/2217/11126 1932/2160/11127 -f 1932/2160/11128 1935/2152/11129 1999/2216/11130 -f 1654/1736/11131 1642/1749/11132 1934/2153/11133 -f 1934/2153/11134 1653/1737/11135 1654/1736/11136 -f 1651/1735/11137 2012/2267/11138 1642/2579/11139 -f 1642/2579/11140 1654/1736/11141 1651/1735/11142 -f 1652/1738/11143 2013/2268/11144 2012/2267/11145 -f 2012/2267/11146 1651/1735/11147 1652/1738/11148 -f 1669/1775/11149 1761/2269/11150 2013/2268/11151 -f 2013/2268/11152 1652/1738/11153 1669/1775/11154 -f 1670/1774/11155 1760/2159/11156 1761/2269/11157 -f 1761/2269/11158 1669/1775/11159 1670/1774/11160 -f 1653/1737/11161 1934/2153/11162 1760/2159/11163 -f 1760/2159/11164 1670/1774/11165 1653/1737/11166 -f 1650/1732/11167 1636/1741/11168 1657/1748/11169 -f 1657/1748/11170 1649/1733/11171 1650/1732/11172 -f 1647/1731/11173 2014/2270/11174 1636/1741/11175 -f 1636/1741/11176 1650/1732/11177 1647/1731/11178 -f 1648/1734/11179 2015/2271/11180 2014/2270/11181 -f 2014/2270/11182 1647/1731/11183 1648/1734/11184 -f 1754/1911/11185 2012/2267/11186 2015/2271/11187 -f 2015/2271/11188 1648/1734/11189 1754/1911/11190 -f 1755/1910/11191 1642/2579/11192 2012/2267/11193 -f 2012/2267/11194 1754/1911/11195 1755/1910/11196 -f 1649/1733/11197 1657/1748/11198 1642/2383/11199 -f 1642/2383/11200 1755/1910/11201 1649/1733/11202 -f 1752/1908/11203 1769/1914/11204 1636/1741/11205 -f 1636/1741/11206 1757/1912/11207 1752/1908/11208 -f 1753/1902/11209 1762/2061/11210 1769/1914/11211 -f 1769/1914/11212 1752/1908/11213 1753/1902/11214 -f 1750/1901/11215 1634/1716/11216 1762/2061/11217 -f 1762/2061/11218 1753/1902/11219 1750/1901/11220 -f 1751/1909/11221 2016/2272/11222 1634/1716/11223 -f 1634/1716/11224 1750/1901/11225 1751/1909/11226 -f 1756/1913/11227 2014/2270/11228 2016/2272/11229 -f 2016/2272/11230 1751/1909/11231 1756/1913/11232 -f 1757/1912/11233 1636/1741/11234 2014/2270/11235 -f 2014/2270/11236 1756/1913/11237 1757/1912/11238 -f 1666/1754/11239 1758/2037/11240 1851/2060/11241 -f 1851/2060/11242 1665/1756/11243 1666/1754/11244 -f 1663/1753/11245 1759/2273/11246 1758/2037/11247 -f 1758/2037/11248 1666/1754/11249 1663/1753/11250 -f 1664/1757/11251 1631/1715/11252 1759/2273/11253 -f 1759/2273/11254 1663/1753/11255 1664/1757/11256 -f 1672/1787/11257 1634/1716/11258 1631/1715/11259 -f 1631/1715/11260 1664/1757/11261 1672/1787/11262 -f 1673/1786/11263 1762/2061/11264 1634/1716/11265 -f 1634/1716/11266 1672/1787/11267 1673/1786/11268 -f 1665/1756/11269 1851/2060/11270 1762/2061/11271 -f 1762/2061/11272 1673/1786/11273 1665/1756/11274 -f 1763/2036/11275 1768/1915/11276 1769/1914/11277 -f 1769/1914/11278 1762/2061/11279 1763/2036/11280 -f 1661/1745/11281 1759/1843/11282 2017/2101/11283 -f 2017/2101/11284 2018/2102/11285 1661/1745/11286 -f 1617/1703/11287 1618/1702/11288 1626/1709/11289 -f 1626/1709/11290 2019/2103/11291 1617/1703/11292 -f 2016/2272/11293 2014/2270/11294 2020/2274/11295 -f 2020/2274/11296 2021/2275/11297 2016/2272/11298 -f 1625/1710/11299 1618/1702/11300 1619/1701/11301 -f 1619/1701/11302 1660/1746/11303 1625/1710/11304 -f 1628/1714/11305 2012/2267/11306 2013/2268/11307 -f 2013/2268/11308 2022/2276/11309 1628/1714/11310 -f 2015/2271/11311 2012/2267/11312 1628/1714/11313 -f 1628/1714/11314 1629/1713/11315 2015/2271/11316 -f 2025/2109/11317 2024/2110/11318 2023/2107/11319 -f 2023/2107/11320 2026/2108/11321 2025/2109/11322 -f 2027/2112/11323 2026/2108/11324 2023/2107/11325 -f 2023/2107/11326 2028/2111/11327 2027/2112/11328 -f 2030/2114/11329 2029/2115/11330 2027/2112/11331 -f 2027/2112/11332 2031/2113/11333 2030/2114/11334 -f 2026/2108/11335 2033/2117/11336 2032/2116/11337 -f 2032/2116/11338 2025/2109/11339 2026/2108/11340 -f 2029/2115/11341 2033/2117/11342 2026/2108/11343 -f 2026/2108/11344 2027/2112/11345 2029/2115/11346 -f 1615/1697/11347 2035/2119/11348 2034/2118/11349 -f 2034/2118/11350 1614/1698/11351 1615/1697/11352 -f 2038/2122/11353 2037/2123/11354 2036/2120/11355 -f 2036/2120/11356 2039/2121/11357 2038/2122/11358 -f 2040/2125/11359 2037/2123/11360 2038/2122/11361 -f 2038/2122/11362 2041/2124/11363 2040/2125/11364 -f 2039/2121/11365 2036/2120/11366 2042/2126/11367 -f 2042/2126/11368 2043/2127/11369 2039/2121/11370 -f 2043/2279/11371 2042/2280/11372 2044/2277/11373 -f 2044/2277/11374 2045/2278/11375 2043/2279/11376 -f 2045/2278/11377 2044/2277/11378 2046/2281/11379 -f 2046/2281/11380 2047/2282/11381 2045/2278/11382 -f 2046/2131/11383 2040/2125/11384 2041/2124/11385 -f 2041/2124/11386 2047/2130/11387 2046/2131/11388 -f 2050/2285/11389 2049/2286/11390 2048/2283/11391 -f 2048/2283/11392 2051/2284/11393 2050/2285/11394 -f 2052/2288/11395 2050/2285/11396 2051/2284/11397 -f 2051/2284/11398 2053/2287/11399 2052/2288/11400 -f 2032/2116/11401 2033/2117/11402 2038/2122/11403 -f 2038/2122/11404 2039/2121/11405 2032/2116/11406 -f 2033/2117/11407 2029/2115/11408 2041/2124/11409 -f 2041/2124/11410 2038/2122/11411 2033/2117/11412 -f 2054/2138/11413 2032/2116/11414 2039/2121/11415 -f 2039/2121/11416 2043/2127/11417 2054/2138/11418 -f 2051/2284/11419 2048/2283/11420 2055/2289/11421 -f 2055/2289/11422 2056/2290/11423 2051/2284/11424 -f 2053/2287/11425 2051/2284/11426 2056/2290/11427 -f 2056/2290/11428 2057/2291/11429 2053/2287/11430 -f 2029/2115/11431 2030/2114/11432 2047/2130/11433 -f 2047/2130/11434 2041/2124/11435 2029/2115/11436 -f 2050/2285/11437 2059/2293/11438 2058/2292/11439 -f 2058/2292/11440 2049/2286/11441 2050/2285/11442 -f 2052/2288/11443 2031/2294/11444 2059/2293/11445 -f 2059/2293/11446 2050/2285/11447 2052/2288/11448 -f 2053/2287/11449 2030/2295/11450 2031/2294/11451 -f 2031/2294/11452 2052/2288/11453 2053/2287/11454 -f 2057/2291/11455 2047/2282/11456 2030/2295/11457 -f 2030/2295/11458 2053/2287/11459 2057/2291/11460 -f 2056/2290/11461 2045/2278/11462 2047/2282/11463 -f 2047/2282/11464 2057/2291/11465 2056/2290/11466 -f 2055/2289/11467 2043/2279/11468 2045/2278/11469 -f 2045/2278/11470 2056/2290/11471 2055/2289/11472 -f 2048/2283/11473 2054/2296/11474 2043/2279/11475 -f 2043/2279/11476 2055/2289/11477 2048/2283/11478 -f 2049/2286/11479 2058/2292/11480 2054/2296/11481 -f 2054/2296/11482 2048/2283/11483 2049/2286/11484 -f 1615/1697/11485 1612/1696/11486 2060/2144/11487 -f 2060/2144/11488 2061/2145/11489 1615/1697/11490 -f 2035/2119/11491 1615/1697/11492 2061/2145/11493 -f 2061/2145/11494 2062/2146/11495 2035/2119/11496 -f 2060/2144/11497 1612/1696/11498 1613/1699/11499 -f 1613/1699/11500 2063/2147/11501 2060/2144/11502 -f 2066/2299/11503 2065/2300/11504 2064/2297/11505 -f 2064/2297/11506 2067/2298/11507 2066/2299/11508 -f 2067/2298/11509 2064/2297/11510 2068/2301/11511 -f 2068/2301/11512 2069/2302/11513 2067/2298/11514 -f 2070/2154/11515 2034/2118/11516 2035/2119/11517 -f 2035/2119/11518 2062/2146/11519 2070/2154/11520 -f 2036/2120/11521 2037/2123/11522 2071/2155/11523 -f 2071/2155/11524 2072/2156/11525 2036/2120/11526 -f 2037/2123/11527 2040/2125/11528 2073/2157/11529 -f 2073/2157/11530 2071/2155/11531 2037/2123/11532 -f 2042/2126/11533 2036/2120/11534 2072/2156/11535 -f 2072/2156/11536 2074/2158/11537 2042/2126/11538 -f 2077/2305/11539 2076/2306/11540 2075/2303/11541 -f 2075/2303/11542 2078/2304/11543 2077/2305/11544 -f 2079/2308/11545 2077/2305/11546 2078/2304/11547 -f 2078/2304/11548 2080/2307/11549 2079/2308/11550 -f 2040/2125/11551 2046/2131/11552 2081/2165/11553 -f 2081/2165/11554 2073/2157/11555 2040/2125/11556 -f 2072/2156/11557 2071/2155/11558 2061/2145/11559 -f 2061/2145/11560 2060/2144/11561 2072/2156/11562 -f 2071/2155/11563 2073/2157/11564 2062/2146/11565 -f 2062/2146/11566 2061/2145/11567 2071/2155/11568 -f 2074/2158/11569 2072/2156/11570 2060/2144/11571 -f 2060/2144/11572 2063/2147/11573 2074/2158/11574 -f 2078/2304/11575 2075/2303/11576 2082/2309/11577 -f 2082/2309/11578 2083/2310/11579 2078/2304/11580 -f 2080/2307/11581 2078/2304/11582 2083/2310/11583 -f 2083/2310/11584 2084/2311/11585 2080/2307/11586 -f 2073/2157/11587 2081/2165/11588 2070/2154/11589 -f 2070/2154/11590 2062/2146/11591 2073/2157/11592 -f 2077/2305/11593 2044/2277/11594 2042/2280/11595 -f 2042/2280/11596 2076/2306/11597 2077/2305/11598 -f 2079/2308/11599 2046/2281/11600 2044/2277/11601 -f 2044/2277/11602 2077/2305/11603 2079/2308/11604 -f 2080/2307/11605 2081/2312/11606 2046/2281/11607 -f 2046/2281/11608 2079/2308/11609 2080/2307/11610 -f 2084/2311/11611 2070/2313/11612 2081/2312/11613 -f 2081/2312/11614 2080/2307/11615 2084/2311/11616 -f 2083/2310/11617 2085/2314/11618 2070/2313/11619 -f 2070/2313/11620 2084/2311/11621 2083/2310/11622 -f 2082/2309/11623 2063/2315/11624 2085/2314/11625 -f 2085/2314/11626 2083/2310/11627 2082/2309/11628 -f 2075/2303/11629 2074/2316/11630 2063/2315/11631 -f 2063/2315/11632 2082/2309/11633 2075/2303/11634 -f 2076/2306/11635 2042/2280/11636 2074/2316/11637 -f 2074/2316/11638 2075/2303/11639 2076/2306/11640 -f 2086/2319/11641 1613/2320/11642 1614/2317/11643 -f 1614/2317/11644 2087/2318/11645 2086/2319/11646 -f 2088/2321/11647 2063/2315/11648 1613/2320/11649 -f 1613/2320/11650 2086/2319/11651 2088/2321/11652 -f 2089/2322/11653 2085/2314/11654 2063/2315/11655 -f 2063/2315/11656 2088/2321/11657 2089/2322/11658 -f 2090/2323/11659 2070/2313/11660 2085/2314/11661 -f 2085/2314/11662 2089/2322/11663 2090/2323/11664 -f 2091/2324/11665 2034/2325/11666 2070/2313/11667 -f 2070/2313/11668 2090/2323/11669 2091/2324/11670 -f 2087/2318/11671 1614/2317/11672 2034/2325/11673 -f 2034/2325/11674 2091/2324/11675 2087/2318/11676 -f 2065/2300/11677 2086/2319/11678 2087/2318/11679 -f 2087/2318/11680 2064/2297/11681 2065/2300/11682 -f 2066/2299/11683 2088/2321/11684 2086/2319/11685 -f 2086/2319/11686 2065/2300/11687 2066/2299/11688 -f 2067/2298/11689 2089/2322/11690 2088/2321/11691 -f 2088/2321/11692 2066/2299/11693 2067/2298/11694 -f 2069/2302/11695 2090/2323/11696 2089/2322/11697 -f 2089/2322/11698 2067/2298/11699 2069/2302/11700 -f 2068/2301/11701 2091/2324/11702 2090/2323/11703 -f 2090/2323/11704 2069/2302/11705 2068/2301/11706 -f 2064/2297/11707 2087/2318/11708 2091/2324/11709 -f 2091/2324/11710 2068/2301/11711 2064/2297/11712 -f 1646/1729/11713 2093/2177/11714 2092/2176/11715 -f 2092/2176/11716 1645/1730/11717 1646/1729/11718 -f 2096/2180/11719 2095/2181/11720 2094/2178/11721 -f 2094/2178/11722 2097/2179/11723 2096/2180/11724 -f 2098/2182/11725 1621/1707/11726 1617/1703/11727 -f 1617/1703/11728 2019/2103/11729 2098/2182/11730 -f 2017/2326/11731 1759/2273/11732 1631/1715/11733 -f 1631/1715/11734 1632/1718/11735 2017/2326/11736 -f 2099/2329/11737 1608/2330/11738 1609/2327/11739 -f 1609/2327/11740 2100/2328/11741 2099/2329/11742 -f 1633/1717/11743 1634/1716/11744 2016/2272/11745 -f 2016/2272/11746 2021/2275/11747 1633/1717/11748 -f 2102/2333/11749 1627/1711/11750 2101/2331/11751 -f 2101/2331/11752 2103/2332/11753 2102/2333/11754 -f 1628/1714/11755 2022/2276/11756 2101/2331/11757 -f 2101/2331/11758 1627/1711/11759 1628/1714/11760 -f 2105/2336/11761 2104/2337/11762 2024/2334/11763 -f 2024/2334/11764 2025/2335/11765 2105/2336/11766 -f 2020/2274/11767 2014/2270/11768 2015/2271/11769 -f 2015/2271/11770 1629/1713/11771 2020/2274/11772 -f 2102/2333/11773 2106/2338/11774 1630/1712/11775 -f 1630/1712/11776 1627/1711/11777 2102/2333/11778 -f 2020/2274/11779 1629/1713/11780 1630/1712/11781 -f 1630/1712/11782 2107/2339/11783 2020/2274/11784 -f 2108/2184/11785 1667/1751/11786 1645/1730/11787 -f 1645/1730/11788 2092/2176/11789 2108/2184/11790 -f 1761/1844/11791 1667/1751/11792 2108/2184/11793 -f 2108/2184/11794 2109/2192/11795 1761/1844/11796 -f 2013/2268/11797 1761/2269/11798 2109/2340/11799 -f 2109/2340/11800 2022/2276/11801 2013/2268/11802 -f 2110/2193/11803 1620/1704/11804 1621/1707/11805 -f 1621/1707/11806 2098/2182/11807 2110/2193/11808 -f 2111/2341/11809 2101/2331/11810 2022/2276/11811 -f 2022/2276/11812 2104/2337/11813 2111/2341/11814 -f 2112/2342/11815 2103/2332/11816 2101/2331/11817 -f 2101/2331/11818 2111/2341/11819 2112/2342/11820 -f 2114/2343/11821 2113/2344/11822 2103/2332/11823 -f 2103/2332/11824 2112/2342/11825 2114/2343/11826 -f 2115/2345/11827 2097/2346/11828 2113/2344/11829 -f 2113/2344/11830 2114/2343/11831 2115/2345/11832 -f 2116/2199/11833 2096/2180/11834 2097/2179/11835 -f 2097/2179/11836 2115/2194/11837 2116/2199/11838 -f 2093/2177/11839 1620/1704/11840 2110/2193/11841 -f 2110/2193/11842 2117/2200/11843 2093/2177/11844 -f 2117/2200/11845 2110/2193/11846 2096/2180/11847 -f 2096/2180/11848 2116/2199/11849 2117/2200/11850 -f 2118/2202/11851 2027/2112/11852 2028/2111/11853 -f 2028/2111/11854 2119/2201/11855 2118/2202/11856 -f 2059/2293/11857 2114/2343/11858 2112/2342/11859 -f 2112/2342/11860 2058/2292/11861 2059/2293/11862 -f 2115/2345/11863 2114/2343/11864 2059/2293/11865 -f 2059/2293/11866 2031/2294/11867 2115/2345/11868 -f 2120/2203/11869 2116/2199/11870 2115/2194/11871 -f 2115/2194/11872 2031/2113/11873 2120/2203/11874 -f 2117/2200/11875 2116/2199/11876 2120/2203/11877 -f 2120/2203/11878 2118/2202/11879 2117/2200/11880 -f 2093/2177/11881 2117/2200/11882 2118/2202/11883 -f 2118/2202/11884 2119/2201/11885 2093/2177/11886 -f 2092/2176/11887 2093/2177/11888 2119/2201/11889 -f 2119/2201/11890 2028/2111/11891 2092/2176/11892 -f 2109/2192/11893 2108/2184/11894 2023/2107/11895 -f 2023/2107/11896 2024/2110/11897 2109/2192/11898 -f 2104/2337/11899 2022/2276/11900 2109/2340/11901 -f 2109/2340/11902 2024/2334/11903 2104/2337/11904 -f 2112/2342/11905 2111/2341/11906 2121/2347/11907 -f 2121/2347/11908 2058/2292/11909 2112/2342/11910 -f 2023/2107/11911 2108/2184/11912 2092/2176/11913 -f 2092/2176/11914 2028/2111/11915 2023/2107/11916 -f 2105/2336/11917 2121/2347/11918 2111/2341/11919 -f 2111/2341/11920 2104/2337/11921 2105/2336/11922 -f 2105/2336/11923 2025/2335/11924 2122/2348/11925 -f 2122/2348/11926 2121/2347/11927 2105/2336/11928 -f 1611/1693/11929 2124/2206/11930 2123/2204/11931 -f 2123/2204/11932 1610/1694/11933 1611/1693/11934 -f 1661/1745/11935 2018/2102/11936 1625/1710/11937 -f 1625/1710/11938 1660/1746/11939 1661/1745/11940 -f 2099/2329/11941 2100/2328/11942 2017/2326/11943 -f 2017/2326/11944 1632/1718/11945 2099/2329/11946 -f 2125/2208/11947 2018/2102/11948 2017/2101/11949 -f 2017/2101/11950 2100/2207/11951 2125/2208/11952 -f 1624/1708/11953 1625/1710/11954 2018/2102/11955 -f 2018/2102/11956 2125/2208/11957 1624/1708/11958 -f 1620/1704/11959 2093/2177/11960 1646/1729/11961 -f 1646/1729/11962 1623/1705/11963 1620/1704/11964 -f 1621/1707/11965 1622/1706/11966 1616/1700/11967 -f 1616/1700/11968 1617/1703/11969 1621/1707/11970 -f 2019/2103/11971 2126/2209/11972 2095/2181/11973 -f 2095/2181/11974 2098/2182/11975 2019/2103/11976 -f 2110/2193/11977 2098/2182/11978 2095/2181/11979 -f 2095/2181/11980 2096/2180/11981 2110/2193/11982 -f 2123/2204/11983 2124/2206/11984 2126/2209/11985 -f 2126/2209/11986 2127/2210/11987 2123/2204/11988 -f 1610/1694/11989 2125/2208/11990 2100/2207/11991 -f 2100/2207/11992 1609/1695/11993 1610/1694/11994 -f 1624/1708/11995 2125/2208/11996 1610/1694/11997 -f 1610/1694/11998 2123/2204/11999 1624/1708/12000 -f 2127/2210/12001 1626/1709/12002 1624/1708/12003 -f 1624/1708/12004 2123/2204/12005 2127/2210/12006 -f 2019/2103/12007 1626/1709/12008 2127/2210/12009 -f 2127/2210/12010 2126/2209/12011 2019/2103/12012 -f 2094/2178/12013 2095/2181/12014 2126/2209/12015 -f 2126/2209/12016 2124/2206/12017 2094/2178/12018 -f 2128/2350/12019 1611/2351/12020 1608/2485/12021 -f 1608/2485/12022 2129/2349/12023 2128/2350/12024 -f 2130/2352/12025 2124/2353/12026 1611/2351/12027 -f 1611/2351/12028 2128/2350/12029 2130/2352/12030 -f 2131/2354/12031 2094/2355/12032 2124/2353/12033 -f 2124/2353/12034 2130/2352/12035 2131/2354/12036 -f 2132/2356/12037 2097/2346/12038 2094/2355/12039 -f 2094/2355/12040 2131/2354/12041 2132/2356/12042 -f 2133/2357/12043 2113/2344/12044 2097/2346/12045 -f 2097/2346/12046 2132/2356/12047 2133/2357/12048 -f 2134/2358/12049 2103/2332/12050 2113/2344/12051 -f 2113/2344/12052 2133/2357/12053 2134/2358/12054 -f 2135/2359/12055 2102/2333/12056 2103/2332/12057 -f 2103/2332/12058 2134/2358/12059 2135/2359/12060 -f 2136/2360/12061 2106/2338/12062 2102/2333/12063 -f 2102/2333/12064 2135/2359/12065 2136/2360/12066 -f 2138/2361/12067 2137/2362/12068 2106/2338/12069 -f 2106/2338/12070 2136/2360/12071 2138/2361/12072 -f 2099/2329/12073 2140/2364/12074 2139/2363/12075 -f 2139/2363/12076 1608/2330/12077 2099/2329/12078 -f 2107/2339/12079 1630/1712/12080 2106/2338/12081 -f 2106/2338/12082 2137/2362/12083 2107/2339/12084 -f 2142/2365/12085 2141/2366/12086 2128/2350/12087 -f 2128/2350/12088 2129/2349/12089 2142/2365/12090 -f 2143/2367/12091 2130/2352/12092 2128/2350/12093 -f 2128/2350/12094 2141/2366/12095 2143/2367/12096 -f 2143/2367/12097 2144/2368/12098 2131/2354/12099 -f 2131/2354/12100 2130/2352/12101 2143/2367/12102 -f 2144/2368/12103 2145/2369/12104 2132/2356/12105 -f 2132/2356/12106 2131/2354/12107 2144/2368/12108 -f 2145/2369/12109 2146/2370/12110 2133/2357/12111 -f 2133/2357/12112 2132/2356/12113 2145/2369/12114 -f 2147/2371/12115 2134/2358/12116 2133/2357/12117 -f 2133/2357/12118 2146/2370/12119 2147/2371/12120 -f 2148/2372/12121 2135/2359/12122 2134/2358/12123 -f 2134/2358/12124 2147/2371/12125 2148/2372/12126 -f 2149/2373/12127 2136/2360/12128 2135/2359/12129 -f 2135/2359/12130 2148/2372/12131 2149/2373/12132 -f 2149/2373/12133 2150/2374/12134 2138/2361/12135 -f 2138/2361/12136 2136/2360/12137 2149/2373/12138 -f 2150/2374/12139 2142/2500/12140 2129/2494/12141 -f 2129/2494/12142 2138/2361/12143 2150/2374/12144 -f 2118/2202/12145 2120/2203/12146 2031/2113/12147 -f 2031/2113/12148 2027/2112/12149 2118/2202/12150 -f 2025/2109/12151 2032/2116/12152 2054/2138/12153 -f 2054/2138/12154 2122/2211/12155 2025/2109/12156 -f 2054/2296/12157 2058/2292/12158 2121/2347/12159 -f 2121/2347/12160 2122/2348/12161 2054/2296/12162 -f 2153/2598/12163 2152/2228/12164 2151/2225/12165 -f 2151/2225/12166 2154/2226/12167 2153/2598/12168 -f 2155/2230/12169 2152/2228/12170 2153/2598/12171 -f 2153/2598/12172 2156/2229/12173 2155/2230/12174 -f 2158/2231/12175 2157/2232/12176 2155/2230/12177 -f 2155/2230/12178 2156/2229/12179 2158/2231/12180 -f 1416/1499/12181 2160/2234/12182 2159/2233/12183 -f 2159/2233/12184 1417/1500/12185 1416/1499/12186 -f 1415/1498/12187 2161/2235/12188 2160/2234/12189 -f 2160/2234/12190 1416/1499/12191 1415/1498/12192 -f 2162/2236/12193 2161/2235/12194 1415/1498/12195 -f 1415/1498/12196 1414/1497/12197 2162/2236/12198 -f 2163/2237/12199 2162/2236/12200 1414/1497/12201 -f 1414/1497/12202 1413/1496/12203 2163/2237/12204 -f 2164/2238/12205 2163/2237/12206 1413/1496/12207 -f 1413/1496/12208 1427/1510/12209 2164/2238/12210 -f 1427/1510/12211 1424/1507/12212 2165/2239/12213 -f 2165/2239/12214 2164/2238/12215 1427/1510/12216 -f 2154/2597/12217 2151/2596/12218 2166/2240/12219 -f 2166/2240/12220 2167/2241/12221 2154/2597/12222 -f 2099/2329/12223 1632/1718/12224 1633/1717/12225 -f 1633/1717/12226 2140/2364/12227 2099/2329/12228 -f 2168/2375/12229 2140/2364/12230 1633/1717/12231 -f 1633/1717/12232 2021/2275/12233 2168/2375/12234 -f 2021/2275/12235 2020/2274/12236 2107/2339/12237 -f 2107/2339/12238 2168/2375/12239 2021/2275/12240 -f 2169/2376/12241 2139/2363/12242 2140/2364/12243 -f 2140/2364/12244 2168/2375/12245 2169/2376/12246 -f 2170/2377/12247 2129/2494/12248 1608/2330/12249 -f 1608/2330/12250 2139/2363/12251 2170/2377/12252 -f 2138/2361/12253 2129/2494/12254 2170/2377/12255 -f 2170/2377/12256 2171/2378/12257 2138/2361/12258 -f 2169/2376/12259 2171/2378/12260 2170/2377/12261 -f 2170/2377/12262 2139/2363/12263 2169/2376/12264 -f 2137/2362/12265 2138/2361/12266 2171/2378/12267 -f 2171/2378/12268 2169/2376/12269 2137/2362/12270 -f 2168/2375/12271 2107/2339/12272 2137/2362/12273 -f 2137/2362/12274 2169/2376/12275 2168/2375/12276 -f 2166/2240/12277 2150/2243/12278 2149/2242/12279 -f 2149/2242/12280 2164/2238/12281 2166/2240/12282 -f 2163/2237/12283 2164/2238/12284 2149/2242/12285 -f 2149/2242/12286 2148/2244/12287 2163/2237/12288 -f 2162/2236/12289 2163/2237/12290 2148/2244/12291 -f 2148/2244/12292 2147/2245/12293 2162/2236/12294 -f 2161/2235/12295 2162/2236/12296 2147/2245/12297 -f 2147/2245/12298 2146/2246/12299 2161/2235/12300 -f 2160/2234/12301 2161/2235/12302 2146/2246/12303 -f 2146/2246/12304 2145/2247/12305 2160/2234/12306 -f 2157/2232/12307 2158/2231/12308 2159/2233/12309 -f 2159/2233/12310 2160/2234/12311 2157/2232/12312 -f 2143/2249/12313 2155/2230/12314 2157/2232/12315 -f 2157/2232/12316 2144/2248/12317 2143/2249/12318 -f 2141/2250/12319 2152/2228/12320 2155/2230/12321 -f 2155/2230/12322 2143/2249/12323 2141/2250/12324 -f 2151/2225/12325 2152/2228/12326 2141/2250/12327 -f 2141/2250/12328 2142/2251/12329 2151/2225/12330 -f 2150/2243/12331 2166/2240/12332 2151/2596/12333 -f 2151/2596/12334 2142/2599/12335 2150/2243/12336 -f 1423/1506/12337 2167/2241/12338 2165/2239/12339 -f 2165/2239/12340 1424/1507/12341 1423/1506/12342 -f 1421/1504/12343 2154/2597/12344 2167/2241/12345 -f 2167/2241/12346 1423/1506/12347 1421/1504/12348 -f 1420/2594/12349 2153/2227/12350 2154/2597/12351 -f 2154/2597/12352 1421/1504/12353 1420/2594/12354 -f 2156/2229/12355 2153/2598/12356 1420/1503/12357 -f 1420/1503/12358 1419/1502/12359 2156/2229/12360 -f 2158/2231/12361 2156/2229/12362 1419/1502/12363 -f 1419/1502/12364 1418/1501/12365 2158/2231/12366 -f 1417/1500/12367 2159/2233/12368 2158/2231/12369 -f 2158/2231/12370 1418/1501/12371 1417/1500/12372 -f 2166/2240/12373 2164/2238/12374 2165/2239/12375 -f 2165/2239/12376 2167/2241/12377 2166/2240/12378 -f 2157/2232/12379 2160/2234/12380 2145/2247/12381 -f 2145/2247/12382 2144/2248/12383 2157/2232/12384 -f 1489/2528/12385 1315/1558/12386 1316/1557/12387 -f 1316/1557/12388 1309/1550/12389 1489/2528/12390 -f 1550/1633/12391 1323/1406/12392 1324/1405/12393 -f 1324/1405/12394 1545/1628/12395 1550/1633/12396 -f 1525/1609/12397 1526/1608/12398 1555/1638/12399 -f 1555/1638/12400 1529/1614/12401 1525/1609/12402 -f 1527/1610/12403 1525/2614/12404 1529/2616/12405 -f 1529/2616/12406 1530/1613/12407 1527/1610/12408 -f 1296/1378/12409 1527/1610/12410 1534/1617/12411 -f 1534/1617/12412 1293/1377/12413 1296/1378/12414 -f 1293/1377/12415 1534/1617/12416 1537/1620/12417 -f 1537/1620/12418 1292/479/12419 1293/1377/12420 -f 1292/479/12421 1537/1620/12422 1540/1623/12423 -f 1540/1623/12424 1506/1425/12425 1292/479/12426 -f 1506/1425/12427 1540/1623/12428 1543/1626/12429 -f 1543/1626/12430 1507/1589/12431 1506/1425/12432 -f 1507/1589/12433 1543/1626/12434 1324/1405/12435 -f 1324/1405/12436 1322/1381/12437 1507/1589/12438 -f 1556/1639/12439 1526/1608/12440 1523/1606/12441 -f 1523/1606/12442 1522/1605/12443 1556/1639/12444 -f 1323/1406/12445 1556/1639/12446 1522/1605/12447 -f 1522/1605/12448 1321/1403/12449 1323/1406/12450 -f 1509/1591/12451 1322/1381/12452 1319/1380/12453 -f 1319/1380/12454 1510/1593/12455 1509/1591/12456 -f 1546/1630/12457 1547/1629/12458 1575/1659/12459 -f 1575/1659/12460 2172/2256/12461 1546/1630/12462 -f 1549/1631/12463 1546/1630/12464 2172/2256/12465 -f 2172/2256/12466 2173/2257/12467 1549/1631/12468 -f 2174/2258/12469 1552/1634/12470 1549/1631/12471 -f 1549/1631/12472 2173/2257/12473 2174/2258/12474 -f 1562/1643/12475 1557/1640/12476 1552/1634/12477 -f 1552/1634/12478 2174/2258/12479 1562/1643/12480 -f 1559/2618/12481 1558/1641/12482 1557/1640/12483 -f 1557/1640/12484 1562/1643/12485 1559/2618/12486 -f 1558/2617/12487 1565/1648/12488 1531/1612/12489 -f 1531/1612/12490 1528/1611/12491 1558/2617/12492 -f 1531/1612/12493 1565/1648/12494 1568/1651/12495 -f 1568/1651/12496 1532/1615/12497 1531/1612/12498 -f 1532/1615/12499 1568/1651/12500 1571/1654/12501 -f 1571/1654/12502 1535/1618/12503 1532/1615/12504 -f 1535/1618/12505 1571/1654/12506 1574/1657/12507 -f 1574/1657/12508 1538/1621/12509 1535/1618/12510 -f 1538/1621/12511 1574/1657/12512 1547/1629/12513 -f 1547/1629/12514 1541/1624/12515 1538/1621/12516 -f 1560/1645/12517 1561/1644/12518 1591/1674/12519 -f 1591/1674/12520 1593/1675/12521 1560/1645/12522 -f 1564/1646/12523 1560/2619/12524 1593/2620/12525 -f 1593/2620/12526 1595/1677/12527 1564/1646/12528 -f 1567/1649/12529 1564/1646/12530 1595/1677/12531 -f 1595/1677/12532 1597/1679/12533 1567/1649/12534 -f 1570/1652/12535 1567/1649/12536 1597/1679/12537 -f 1597/1679/12538 1599/1681/12539 1570/1652/12540 -f 1578/1663/12541 1573/1655/12542 1570/1652/12543 -f 1570/1652/12544 1599/1681/12545 1578/1663/12546 -f 1579/1662/12547 1576/1658/12548 1573/1655/12549 -f 1573/1655/12550 1578/1663/12551 1579/1662/12552 -f 1575/1659/12553 1576/1658/12554 1583/1666/12555 -f 1583/1666/12556 2172/2256/12557 1575/1659/12558 -f 2172/2256/12559 1583/1666/12560 1586/1669/12561 -f 1586/1669/12562 2173/2257/12563 2172/2256/12564 -f 2173/2257/12565 1586/1669/12566 1589/1672/12567 -f 1589/1672/12568 2174/2258/12569 2173/2257/12570 -f 1589/1672/12571 1561/1644/12572 1562/1643/12573 -f 1562/1643/12574 2174/2258/12575 1589/1672/12576 -f 608/2569/12577 609/2573/12578 447/531/12579 -f 447/531/12580 448/530/12581 608/2569/12582 -f 609/2573/12583 611/695/12584 610/694/12585 -f 610/694/12586 447/531/12587 609/2573/12588 -f 614/700/12589 446/532/12590 447/531/12591 -f 447/531/12592 610/694/12593 614/700/12594 -f 2175/2622/12595 2176/2623/12596 2177/2626/12597 -f 2177/2626/12598 2178/2629/12599 2175/2622/12600 -f 2330/2806/12601 2331/2807/12602 2179/2646/12603 -f 2179/2646/12604 2180/2647/12605 2330/2806/12606 -f 2181/2624/12607 2179/2625/12608 2331/2808/12609 -f 2331/2808/12610 2332/2809/12611 2181/2624/12612 -f 2181/2624/12613 2332/2809/12614 2333/2810/12615 -f 2333/2810/12616 2184/2631/12617 2181/2624/12618 -f 2185/2632/12619 2183/2630/12620 2182/2628/12621 -f 2182/2628/12622 2186/2633/12623 2185/2632/12624 -f 2187/2634/12625 2188/2635/12626 2183/2630/12627 -f 2183/2630/12628 2185/2632/12629 2187/2634/12630 -f 2189/2636/12631 2190/2637/12632 2187/2634/12633 -f 2187/2634/12634 2191/2638/12635 2189/2636/12636 -f 2189/2649/12637 2192/2657/12638 2193/2659/12639 -f 2193/2659/12640 2194/2661/12641 2189/2649/12642 -f 2192/2657/12643 2195/2662/12644 2196/2663/12645 -f 2196/2663/12646 2193/2659/12647 2192/2657/12648 -s 2 -f 2195/2639/12649 2197/2640/12650 2198/2641/12651 -f 2198/2641/12652 2199/2642/12653 2195/2639/12654 -s 1 -f 2192/2643/12655 2200/2644/12656 2197/2640/12657 -f 2197/2640/12658 2195/2639/12659 2192/2643/12660 -s 2 -f 2201/2645/12661 2202/2648/12662 2198/2641/12663 -f 2198/2641/12664 2197/2640/12665 2201/2645/12666 -s 1 -f 2200/2644/12667 2203/2650/12668 2201/2645/12669 -f 2201/2645/12670 2197/2640/12671 2200/2644/12672 -s 2 -f 2196/2663/12673 2195/2662/12674 2199/2664/12675 -f 2199/2664/12676 2204/2665/12677 2196/2663/12678 -s 1 -f 2205/2666/12679 2206/2667/12680 2204/2665/12681 -f 2204/2665/12682 2199/2664/12683 2205/2666/12684 -f 2198/2641/12685 2207/2651/12686 2205/2652/12687 -f 2205/2652/12688 2199/2642/12689 2198/2641/12690 -f 2194/2661/12691 2193/2659/12692 2208/2668/12693 -f 2208/2668/12694 2209/2669/12695 2194/2661/12696 -f 2194/2661/12697 2210/2670/12698 2190/2687/12699 -f 2190/2687/12700 2189/2649/12701 2194/2661/12702 -f 2209/2669/12703 2211/2688/12704 2210/2670/12705 -f 2210/2670/12706 2194/2661/12707 2209/2669/12708 -f 2212/2690/12709 2208/2668/12710 2193/2659/12711 -f 2193/2659/12712 2196/2663/12713 2212/2690/12714 -f 2213/2691/12715 2214/2692/12716 2209/2669/12717 -f 2209/2669/12718 2208/2668/12719 2213/2691/12720 -f 2213/2691/12721 2208/2668/12722 2212/2690/12723 -f 2212/2690/12724 2215/2693/12725 2213/2691/12726 -f 2189/2636/12727 2191/2638/12728 2200/2644/12729 -f 2200/2644/12730 2192/2643/12731 2189/2636/12732 -f 2191/2638/12733 2216/2653/12734 2203/2650/12735 -f 2203/2650/12736 2200/2644/12737 2191/2638/12738 -f 2216/2653/12739 2217/2654/12740 2218/2655/12741 -f 2218/2655/12742 2203/2650/12743 2216/2653/12744 -f 2217/2654/12745 2216/2653/12746 2185/2632/12747 -f 2185/2632/12748 2186/2633/12749 2217/2654/12750 -f 2185/2632/12751 2216/2653/12752 2191/2638/12753 -f 2191/2638/12754 2187/2634/12755 2185/2632/12756 -f 2219/2656/12757 2188/2635/12758 2187/2634/12759 -f 2187/2634/12760 2190/2637/12761 2219/2656/12762 -f 2335/2812/12763 2220/2658/12764 2221/2660/12765 -f 2221/2660/12766 2334/2811/12767 2335/2812/12768 -s 2 -f 2220/2694/12769 2222/2695/12770 2223/2696/12771 -f 2223/2696/12772 2224/2697/12773 2220/2694/12774 -s 1 -f 2335/2813/12775 2336/2814/12776 2222/2695/12777 -f 2222/2695/12778 2220/2694/12779 2335/2813/12780 -f 2226/2740/12781 2227/2757/12782 2222/2695/12783 -f 2222/2695/12784 2336/2814/12785 2226/2740/12786 -f 2210/2670/12787 2211/2688/12788 2337/2815/12789 -f 2337/2815/12790 2225/2699/12791 2210/2670/12792 -f 2190/2687/12793 2210/2670/12794 2225/2699/12795 -f 2225/2699/12796 2219/2698/12797 2190/2687/12798 -s 4 -f 2227/2757/12799 2228/2759/12800 2223/2696/12801 -f 2223/2696/12802 2222/2695/12803 2227/2757/12804 -s 8 -f 2228/2759/12805 2227/2757/12806 2180/2647/12807 -f 2180/2647/12808 2229/2760/12809 2228/2759/12810 -s 2 -f 2230/2671/12811 2221/2660/12812 2220/2658/12813 -f 2220/2658/12814 2224/2672/12815 2230/2671/12816 -f 2221/2660/12817 2230/2671/12818 2231/2673/12819 -f 2231/2673/12820 2184/2631/12821 2221/2660/12822 -s 1 -f 2334/2811/12823 2221/2660/12824 2184/2631/12825 -f 2184/2631/12826 2333/2810/12827 2334/2811/12828 -f 2177/2674/12829 2186/2633/12830 2182/2628/12831 -f 2182/2628/12832 2178/2627/12833 2177/2674/12834 -f 2232/2675/12835 2186/2633/12836 2177/2674/12837 -f 2177/2674/12838 2233/2676/12839 2232/2675/12840 -f 2232/2675/12841 2234/2677/12842 2217/2654/12843 -f 2217/2654/12844 2186/2633/12845 2232/2675/12846 -f 2235/2678/12847 2236/2679/12848 2234/2677/12849 -f 2234/2677/12850 2237/2680/12851 2235/2678/12852 -f 2235/2678/12853 2238/2681/12854 2239/2682/12855 -f 2239/2682/12856 2240/2683/12857 2235/2678/12858 -f 2239/2682/12859 2238/2681/12860 2241/2684/12861 -f 2241/2684/12862 2242/2685/12863 2239/2682/12864 -s 2 -f 2239/2682/12865 2243/2686/12866 2244/2689/12867 -f 2244/2689/12868 2240/2683/12869 2239/2682/12870 -f 2243/2686/12871 2239/2682/12872 2242/2685/12873 -f 2242/2685/12874 2245/2700/12875 2243/2686/12876 -s 1 -f 2238/2681/12877 2246/2701/12878 2247/2702/12879 -f 2247/2702/12880 2241/2684/12881 2238/2681/12882 -f 2241/2684/12883 2248/2703/12884 2249/2704/12885 -f 2249/2704/12886 2242/2685/12887 2241/2684/12888 -f 2247/2702/12889 2250/2705/12890 2248/2703/12891 -f 2248/2703/12892 2241/2684/12893 2247/2702/12894 -f 2237/2680/12895 2246/2701/12896 2238/2681/12897 -f 2238/2681/12898 2235/2678/12899 2237/2680/12900 -f 2251/2706/12901 2252/2707/12902 2246/2701/12903 -f 2246/2701/12904 2237/2680/12905 2251/2706/12906 -f 2234/2677/12907 2232/2675/12908 2251/2706/12909 -f 2251/2706/12910 2237/2680/12911 2234/2677/12912 -f 2236/2679/12913 2235/2678/12914 2240/2683/12915 -f 2240/2683/12916 2253/2708/12917 2236/2679/12918 -f 2217/2654/12919 2234/2677/12920 2236/2679/12921 -f 2236/2679/12922 2218/2655/12923 2217/2654/12924 -f 2236/2679/12925 2253/2708/12926 2254/2709/12927 -f 2254/2709/12928 2218/2655/12929 2236/2679/12930 -s 2 -f 2254/2709/12931 2253/2708/12932 2255/2710/12933 -f 2255/2710/12934 2256/2711/12935 2254/2709/12936 -f 2240/2683/12937 2244/2689/12938 2255/2710/12939 -f 2255/2710/12940 2253/2708/12941 2240/2683/12942 -s 1 -f 2233/2676/12943 2257/2712/12944 2251/2706/12945 -f 2251/2706/12946 2232/2675/12947 2233/2676/12948 -f 2257/2741/12949 2233/2742/12950 2258/2743/12951 -f 2258/2743/12952 2259/2744/12953 2257/2741/12954 -s 2 -f 2251/2706/12955 2257/2712/12956 2260/2713/12957 -f 2260/2713/12958 2261/2714/12959 2251/2706/12960 -s 1 -f 2262/2745/12961 2263/2746/12962 2322/2796/12963 -f 2322/2796/12964 2324/2799/12965 2262/2745/12966 -s 2 -f 2262/2745/12967 2265/2749/12968 2266/2750/12969 -f 2266/2750/12970 2263/2746/12971 2262/2745/12972 -f 2265/2749/12973 2262/2745/12974 2267/2751/12975 -f 2267/2751/12976 2268/2752/12977 2265/2749/12978 -s 1 -f 2324/2799/12979 2325/2800/12980 2267/2751/12981 -f 2267/2751/12982 2262/2745/12983 2324/2799/12984 -f 2259/2744/12985 2264/2748/12986 2260/2747/12987 -f 2260/2747/12988 2257/2741/12989 2259/2744/12990 -f 2259/2744/12991 2270/2754/12992 2269/2753/12993 -f 2269/2753/12994 2264/2748/12995 2259/2744/12996 -f 2259/2744/12997 2271/2755/12998 2272/2756/12999 -f 2272/2756/13000 2270/2754/13001 2259/2744/13002 -f 2273/2758/13003 2271/2755/13004 2259/2744/13005 -f 2259/2744/13006 2258/2743/13007 2273/2758/13008 -f 2274/2715/13009 2323/2798/13010 2322/2797/13011 -f 2322/2797/13012 2263/2716/13013 2274/2715/13014 -s 2 -f 2274/2715/13015 2275/2717/13016 2276/2718/13017 -f 2276/2718/13018 2277/2719/13019 2274/2715/13020 -s 4 -f 2275/2717/13021 2274/2715/13022 2263/2716/13023 -f 2263/2716/13024 2266/2720/13025 2275/2717/13026 -s 1 -f 2323/2798/13027 2274/2715/13028 2277/2719/13029 -f 2277/2719/13030 2326/2801/13031 2323/2798/13032 -f 2177/2626/13033 2176/2623/13034 2258/2743/13035 -f 2258/2743/13036 2233/2742/13037 2177/2626/13038 -s 8 -f 2279/2722/13039 2280/2723/13040 2179/2625/13041 -f 2179/2625/13042 2181/2624/13043 2279/2722/13044 -s 2 -f 2184/2631/13045 2231/2673/13046 2279/2722/13047 -f 2279/2722/13048 2181/2624/13049 2184/2631/13050 -s 8 -f 2280/2761/13051 2229/2760/13052 2180/2647/13053 -f 2180/2647/13054 2179/2646/13055 2280/2761/13056 -s 1 -f 2176/2623/13057 2175/2622/13058 2337/2815/13059 -f 2337/2815/13060 2211/2688/13061 2176/2623/13062 -f 2227/2757/13063 2226/2740/13064 2330/2806/13065 -f 2330/2806/13066 2180/2647/13067 2227/2757/13068 -f 2214/2692/13069 2273/2758/13070 2258/2743/13071 -f 2258/2743/13072 2176/2623/13073 2214/2692/13074 -f 2176/2623/13075 2211/2688/13076 2209/2669/13077 -f 2209/2669/13078 2214/2692/13079 2176/2623/13080 -f 2214/2692/13081 2213/2691/13082 2281/2762/13083 -f 2281/2762/13084 2273/2758/13085 2214/2692/13086 -f 2281/2762/13087 2282/2765/13088 2271/2755/13089 -f 2271/2755/13090 2273/2758/13091 2281/2762/13092 -f 2282/2765/13093 2283/2766/13094 2284/2767/13095 -f 2284/2767/13096 2285/2768/13097 2282/2765/13098 -s 2 -f 2283/2766/13099 2286/2769/13100 2287/2772/13101 -f 2287/2772/13102 2284/2767/13103 2283/2766/13104 -s 1 -f 2286/2769/13105 2288/2763/13106 2289/2771/13107 -f 2289/2771/13108 2290/2776/13109 2286/2769/13110 -f 2288/2763/13111 2291/2764/13112 2292/2770/13113 -f 2292/2770/13114 2289/2771/13115 2288/2763/13116 -f 2293/2773/13117 2294/2774/13118 2292/2770/13119 -f 2292/2770/13120 2291/2764/13121 2293/2773/13122 -f 2294/2774/13123 2293/2773/13124 2204/2665/13125 -f 2204/2665/13126 2206/2667/13127 2294/2774/13128 -s 2 -f 2212/2690/13129 2196/2663/13130 2204/2665/13131 -f 2204/2665/13132 2293/2773/13133 2212/2690/13134 -f 2215/2693/13135 2212/2690/13136 2293/2773/13137 -f 2293/2773/13138 2291/2764/13139 2215/2693/13140 -f 2215/2693/13141 2291/2764/13142 2288/2763/13143 -f 2288/2763/13144 2295/2775/13145 2215/2693/13146 -f 2288/2763/13147 2286/2769/13148 2283/2766/13149 -f 2283/2766/13150 2295/2775/13151 2288/2763/13152 -s 1 -f 2213/2691/13153 2215/2693/13154 2295/2775/13155 -f 2295/2775/13156 2281/2762/13157 2213/2691/13158 -f 2281/2762/13159 2295/2775/13160 2283/2766/13161 -f 2283/2766/13162 2282/2765/13163 2281/2762/13164 -f 2287/2772/13165 2286/2769/13166 2290/2776/13167 -f 2290/2776/13168 2296/2777/13169 2287/2772/13170 -s 2 -f 2287/2772/13171 2297/2778/13172 2298/2779/13173 -f 2298/2779/13174 2284/2767/13175 2287/2772/13176 -f 2298/2779/13177 2297/2778/13178 2299/2780/13179 -f 2299/2780/13180 2249/2781/13181 2298/2779/13182 -s 1 -f 2298/2779/13183 2300/2782/13184 2285/2768/13185 -f 2285/2768/13186 2284/2767/13187 2298/2779/13188 -f 2298/2779/13189 2249/2781/13190 2248/2783/13191 -f 2248/2783/13192 2300/2782/13193 2298/2779/13194 -f 2300/2782/13195 2301/2784/13196 2272/2756/13197 -f 2272/2756/13198 2285/2768/13199 2300/2782/13200 -f 2301/2784/13201 2300/2782/13202 2248/2783/13203 -f 2248/2783/13204 2250/2785/13205 2301/2784/13206 -f 2270/2754/13207 2272/2756/13208 2301/2784/13209 -f 2301/2784/13210 2302/2786/13211 2270/2754/13212 -f 2250/2785/13213 2303/2787/13214 2302/2786/13215 -f 2302/2786/13216 2301/2784/13217 2250/2785/13218 -f 2271/2755/13219 2282/2765/13220 2285/2768/13221 -f 2285/2768/13222 2272/2756/13223 2271/2755/13224 -s 2 -f 2242/2685/13225 2249/2704/13226 2299/2724/13227 -f 2299/2724/13228 2245/2700/13229 2242/2685/13230 -s 1 -f 2304/2725/13231 2245/2700/13232 2299/2724/13233 -f 2299/2724/13234 2305/2726/13235 2304/2725/13236 -f 2306/2727/13237 2243/2686/13238 2245/2700/13239 -f 2245/2700/13240 2304/2725/13241 2306/2727/13242 -f 2244/2689/13243 2243/2686/13244 2306/2727/13245 -f 2306/2727/13246 2307/2728/13247 2244/2689/13248 -f 2299/2780/13249 2297/2778/13250 2308/2788/13251 -f 2308/2788/13252 2305/2789/13253 2299/2780/13254 -f 2287/2772/13255 2296/2777/13256 2308/2788/13257 -f 2308/2788/13258 2297/2778/13259 2287/2772/13260 -f 2254/2709/13261 2201/2645/13262 2203/2650/13263 -f 2203/2650/13264 2218/2655/13265 2254/2709/13266 -s 2 -f 2254/2709/13267 2256/2711/13268 2202/2648/13269 -f 2202/2648/13270 2201/2645/13271 2254/2709/13272 -s 1 -f 2261/2714/13273 2278/2721/13274 2252/2707/13275 -f 2252/2707/13276 2251/2706/13277 2261/2714/13278 -f 2309/2729/13279 2326/2801/13280 2277/2719/13281 -f 2277/2719/13282 2310/2730/13283 2309/2729/13284 -f 2278/2721/13285 2327/2802/13286 2311/2731/13287 -f 2311/2731/13288 2252/2707/13289 2278/2721/13290 -f 2247/2702/13291 2246/2701/13292 2252/2707/13293 -f 2252/2707/13294 2311/2731/13295 2247/2702/13296 -f 2303/2732/13297 2250/2705/13298 2247/2702/13299 -f 2247/2702/13300 2311/2731/13301 2303/2732/13302 -f 2312/2733/13303 2303/2732/13304 2311/2731/13305 -f 2311/2731/13306 2327/2802/13307 2312/2733/13308 -f 2328/2803/13309 2313/2791/13310 2314/2792/13311 -f 2314/2792/13312 2329/2805/13313 2328/2803/13314 -s 4 -f 2316/2794/13315 2317/2795/13316 2314/2792/13317 -f 2314/2792/13318 2313/2791/13319 2316/2794/13320 -f 2318/2734/13321 2316/2735/13322 2313/2736/13323 -f 2313/2736/13324 2310/2730/13325 2318/2734/13326 -f 2276/2718/13327 2318/2734/13328 2310/2730/13329 -f 2310/2730/13330 2277/2719/13331 2276/2718/13332 -s 1 -f 2328/2804/13333 2309/2729/13334 2310/2730/13335 -f 2310/2730/13336 2313/2736/13337 2328/2804/13338 -s 8 -f 2314/2792/13339 2317/2795/13340 2268/2752/13341 -f 2268/2752/13342 2267/2751/13343 2314/2792/13344 -s 1 -f 2325/2800/13345 2329/2805/13346 2314/2792/13347 -f 2314/2792/13348 2267/2751/13349 2325/2800/13350 -f 2302/2786/13351 2303/2787/13352 2312/2790/13353 -f 2312/2790/13354 2315/2793/13355 2302/2786/13356 -f 2315/2793/13357 2269/2753/13358 2270/2754/13359 -f 2270/2754/13360 2302/2786/13361 2315/2793/13362 -f 2319/2737/13363 2255/2710/13364 2244/2689/13365 -f 2244/2689/13366 2307/2728/13367 2319/2737/13368 -f 2320/2738/13369 2256/2711/13370 2255/2710/13371 -f 2255/2710/13372 2319/2737/13373 2320/2738/13374 -f 2256/2711/13375 2320/2738/13376 2321/2739/13377 -f 2321/2739/13378 2202/2648/13379 2256/2711/13380 -f 2321/2739/13381 2207/2651/13382 2198/2641/13383 -f 2198/2641/13384 2202/2648/13385 2321/2739/13386 -f 2260/2713/13387 2322/2797/13388 2323/2798/13389 -f 2323/2798/13390 2261/2714/13391 2260/2713/13392 -f 2322/2796/13393 2260/2747/13394 2264/2748/13395 -f 2264/2748/13396 2324/2799/13397 2322/2796/13398 -f 2324/2799/13399 2264/2748/13400 2269/2753/13401 -f 2269/2753/13402 2325/2800/13403 2324/2799/13404 -f 2326/2801/13405 2278/2721/13406 2261/2714/13407 -f 2261/2714/13408 2323/2798/13409 2326/2801/13410 -f 2309/2729/13411 2327/2802/13412 2278/2721/13413 -f 2278/2721/13414 2326/2801/13415 2309/2729/13416 -f 2327/2802/13417 2309/2729/13418 2328/2804/13419 -f 2328/2804/13420 2312/2733/13421 2327/2802/13422 -f 2329/2805/13423 2315/2793/13424 2312/2790/13425 -f 2312/2790/13426 2328/2803/13427 2329/2805/13428 -f 2325/2800/13429 2269/2753/13430 2315/2793/13431 -f 2315/2793/13432 2329/2805/13433 2325/2800/13434 -f 2178/2629/13435 2331/2807/13436 2330/2806/13437 -f 2330/2806/13438 2175/2622/13439 2178/2629/13440 -f 2331/2808/13441 2178/2627/13442 2182/2628/13443 -f 2182/2628/13444 2332/2809/13445 2331/2808/13446 -f 2332/2809/13447 2182/2628/13448 2183/2630/13449 -f 2183/2630/13450 2333/2810/13451 2332/2809/13452 -f 2188/2635/13453 2334/2811/13454 2333/2810/13455 -f 2333/2810/13456 2183/2630/13457 2188/2635/13458 -f 2219/2656/13459 2335/2812/13460 2334/2811/13461 -f 2334/2811/13462 2188/2635/13463 2219/2656/13464 -f 2335/2813/13465 2219/2698/13466 2225/2699/13467 -f 2225/2699/13468 2336/2814/13469 2335/2813/13470 -f 2336/2814/13471 2225/2699/13472 2337/2815/13473 -f 2337/2815/13474 2226/2740/13475 2336/2814/13476 -f 2175/2622/13477 2330/2806/13478 2226/2740/13479 -f 2226/2740/13480 2337/2815/13481 2175/2622/13482 -f 2340/2818/13483 2341/2819/13484 2338/2816/13485 -f 2338/2816/13486 2339/2817/13487 2340/2818/13488 -f 2426/2820/13489 2427/2821/13490 2344/2822/13491 -f 2344/2822/13492 2338/2816/13493 2426/2820/13494 -f 2346/2825/13495 2347/2826/13496 2448/2823/13497 -f 2448/2823/13498 2450/2824/13499 2346/2825/13500 -f 2451/2827/13501 2349/2828/13502 2346/2825/13503 -f 2346/2825/13504 2450/2824/13505 2451/2827/13506 -f 2428/2830/13507 2429/2831/13508 2348/2832/13509 -f 2348/2832/13510 2345/2829/13511 2428/2830/13512 -f 2351/2833/13513 2350/2834/13514 2341/2819/13515 -f 2341/2819/13516 2340/2818/13517 2351/2833/13518 -f 2352/2835/13519 2353/2836/13520 2350/2834/13521 -f 2350/2834/13522 2351/2833/13523 2352/2835/13524 -f 2350/2834/13525 2353/2836/13526 2430/2837/13527 -f 2430/2837/13528 2429/2831/13529 2350/2834/13530 -f 2354/2838/13531 2430/2837/13532 2431/2839/13533 -f 2431/2839/13534 2356/2840/13535 2354/2838/13536 -f 2357/2842/13537 2349/2828/13538 2451/2827/13539 -f 2451/2827/13540 2452/2841/13541 2357/2842/13542 -f 2358/2844/13543 2357/2842/13544 2452/2841/13545 -f 2452/2841/13546 2453/2843/13547 2358/2844/13548 -f 2432/2846/13549 2431/2839/13550 2355/2847/13551 -f 2355/2847/13552 2359/2845/13553 2432/2846/13554 -f 2362/2849/13555 2363/2850/13556 2359/2845/13557 -f 2359/2845/13558 2361/2848/13559 2362/2849/13560 -f 2361/2848/13561 2359/2845/13562 2355/2847/13563 -f 2355/2847/13564 2364/2851/13565 2361/2848/13566 -f 2365/2852/13567 2360/2853/13568 2432/2846/13569 -f 2432/2846/13570 2433/2854/13571 2365/2852/13572 -f 2355/2847/13573 2353/2836/13574 2352/2835/13575 -f 2352/2835/13576 2364/2851/13577 2355/2847/13578 -f 2345/2829/13579 2342/2855/13580 2426/2820/13581 -f 2426/2820/13582 2428/2830/13583 2345/2829/13584 -f 2366/2856/13585 2343/2857/13586 2448/2823/13587 -f 2448/2823/13588 2347/2826/13589 2366/2856/13590 -f 2368/2859/13591 2343/2857/13592 2366/2856/13593 -f 2366/2856/13594 2367/2858/13595 2368/2859/13596 -f 2370/2861/13597 2368/2859/13598 2367/2858/13599 -f 2367/2858/13600 2369/2860/13601 2370/2861/13602 -f 2371/2862/13603 2372/2863/13604 2370/2861/13605 -f 2370/2861/13606 2369/2860/13607 2371/2862/13608 -f 2434/2865/13609 2435/2866/13610 2456/2867/13611 -f 2456/2867/13612 2457/2864/13613 2434/2865/13614 -f 2458/2868/13615 2436/2869/13616 2434/2865/13617 -f 2434/2865/13618 2457/2864/13619 2458/2868/13620 -f 2459/2870/13621 2437/2871/13622 2436/2869/13623 -f 2436/2869/13624 2458/2868/13625 2459/2870/13626 -f 2379/2874/13627 2380/2875/13628 2378/2872/13629 -f 2378/2872/13630 2376/2873/13631 2379/2874/13632 -f 2371/2862/13633 2379/2874/13634 2376/2873/13635 -f 2376/2873/13636 2372/2863/13637 2371/2862/13638 -f 2377/2876/13639 2437/2871/13640 2438/2877/13641 -f 2438/2877/13642 2381/2878/13643 2377/2876/13644 -f 2382/2880/13645 2383/2881/13646 2375/2879/13647 -f 2375/2879/13648 2377/2876/13649 2382/2880/13650 -f 2375/2879/13651 2383/2881/13652 2384/2882/13653 -f 2384/2882/13654 2373/2883/13655 2375/2879/13656 -f 2384/2882/13657 2385/2885/13658 2374/2884/13659 -f 2374/2884/13660 2373/2883/13661 2384/2882/13662 -f 2386/2886/13663 2344/2822/13664 2374/2884/13665 -f 2374/2884/13666 2385/2885/13667 2386/2886/13668 -f 2344/2822/13669 2386/2886/13670 2339/2817/13671 -f 2339/2817/13672 2338/2816/13673 2344/2822/13674 -f 2449/2887/13675 2456/2867/13676 2435/2866/13677 -f 2435/2866/13678 2427/2821/13679 2449/2887/13680 -f 2454/2888/13681 2387/2889/13682 2358/2844/13683 -f 2358/2844/13684 2453/2843/13685 2454/2888/13686 -f 2388/2891/13687 2387/2889/13688 2454/2888/13689 -f 2454/2888/13690 2455/2890/13691 2388/2891/13692 -f 2390/2893/13693 2388/2953/13694 2455/2952/13695 -f 2455/2952/13696 2461/2892/13697 2390/2893/13698 -f 2392/2895/13699 2390/2893/13700 2461/2892/13701 -f 2461/2892/13702 2462/2894/13703 2392/2895/13704 -f 2392/2895/13705 2462/2894/13706 2463/2896/13707 -f 2463/2896/13708 2394/2897/13709 2392/2895/13710 -f 2394/2897/13711 2463/2896/13712 2464/2898/13713 -f 2464/2898/13714 2396/2899/13715 2394/2897/13716 -f 2396/2899/13717 2464/2898/13718 2465/2900/13719 -f 2465/2900/13720 2398/2901/13721 2396/2899/13722 -f 2400/2903/13723 2398/2901/13724 2465/2900/13725 -f 2465/2900/13726 2466/2902/13727 2400/2903/13728 -f 2402/2905/13729 2439/2906/13730 2440/2907/13731 -f 2440/2907/13732 2401/2904/13733 2402/2905/13734 -f 2403/2908/13735 2404/2909/13736 2402/2905/13737 -f 2402/2905/13738 2401/2904/13739 2403/2908/13740 -f 2405/2910/13741 2441/2911/13742 2439/2906/13743 -f 2439/2906/13744 2402/2905/13745 2405/2910/13746 -f 2405/2910/13747 2402/2905/13748 2404/2909/13749 -f 2404/2909/13750 2407/2912/13751 2405/2910/13752 -f 2409/2914/13753 2403/2908/13754 2401/2904/13755 -f 2401/2904/13756 2408/2913/13757 2409/2914/13758 -f 2442/2916/13759 2440/2907/13760 2397/2917/13761 -f 2397/2917/13762 2395/2915/13763 2442/2916/13764 -f 2467/2918/13765 2410/2919/13766 2400/2903/13767 -f 2400/2903/13768 2466/2902/13769 2467/2918/13770 -f 2412/2921/13771 2410/2919/13772 2467/2918/13773 -f 2467/2918/13774 2468/2920/13775 2412/2921/13776 -f 2413/2922/13777 2414/2923/13778 2412/2921/13779 -f 2412/2921/13780 2468/2920/13781 2413/2922/13782 -f 2416/2925/13783 2443/2926/13784 2444/2927/13785 -f 2444/2927/13786 2415/2924/13787 2416/2925/13788 -f 2406/2929/13789 2441/2911/13790 2444/2927/13791 -f 2444/2927/13792 2411/2928/13793 2406/2929/13794 -f 2417/2930/13795 2408/2913/13796 2442/2916/13797 -f 2442/2916/13798 2445/2931/13799 2417/2930/13800 -f 2445/2931/13801 2446/2932/13802 2418/2933/13803 -f 2418/2933/13804 2417/2930/13805 2445/2931/13806 -f 2420/2935/13807 2417/2930/13808 2418/2933/13809 -f 2418/2933/13810 2419/2934/13811 2420/2935/13812 -f 2422/2937/13813 2419/2934/13814 2418/2933/13815 -f 2418/2933/13816 2421/2936/13817 2422/2937/13818 -f 2421/2936/13819 2418/2933/13820 2446/2932/13821 -f 2446/2932/13822 2447/2938/13823 2421/2936/13824 -f 2363/2949/13825 2362/2948/13826 2422/2937/13827 -f 2422/2937/13828 2421/2936/13829 2363/2949/13830 -f 2433/2951/13831 2447/2938/13832 2389/2939/13833 -f 2389/2939/13834 2365/2950/13835 2433/2951/13836 -f 2409/2914/13837 2408/2913/13838 2417/2930/13839 -f 2417/2930/13840 2420/2935/13841 2409/2914/13842 -f 2405/2910/13843 2407/2912/13844 2423/2940/13845 -f 2423/2940/13846 2415/2924/13847 2405/2910/13848 -f 2423/2940/13849 2424/2941/13850 2416/2925/13851 -f 2416/2925/13852 2415/2924/13853 2423/2940/13854 -f 2425/2942/13855 2381/2957/13856 2416/2925/13857 -f 2416/2925/13858 2424/2941/13859 2425/2942/13860 -f 2377/2876/13861 2381/2878/13862 2425/2958/13863 -f 2425/2958/13864 2382/2880/13865 2377/2876/13866 -f 2381/2957/13867 2438/2956/13868 2443/2926/13869 -f 2443/2926/13870 2416/2925/13871 2381/2957/13872 -f 2378/2954/13873 2380/2955/13874 2414/2923/13875 -f 2414/2923/13876 2413/2922/13877 2378/2954/13878 -f 2342/2855/13879 2449/2887/13880 2427/2821/13881 -f 2427/2821/13882 2426/2820/13883 2342/2855/13884 -f 2341/2819/13885 2350/2834/13886 2429/2831/13887 -f 2429/2831/13888 2428/2830/13889 2341/2819/13890 -f 2430/2837/13891 2354/2838/13892 2348/2832/13893 -f 2348/2832/13894 2429/2831/13895 2430/2837/13896 -f 2353/2836/13897 2355/2847/13898 2431/2839/13899 -f 2431/2839/13900 2430/2837/13901 2353/2836/13902 -f 2360/2853/13903 2356/2840/13904 2431/2839/13905 -f 2431/2839/13906 2432/2846/13907 2360/2853/13908 -f 2359/2845/13909 2363/2850/13910 2433/2854/13911 -f 2433/2854/13912 2432/2846/13913 2359/2845/13914 -f 2338/2816/13915 2341/2819/13916 2428/2830/13917 -f 2428/2830/13918 2426/2820/13919 2338/2816/13920 -f 2373/2883/13921 2374/2884/13922 2435/2866/13923 -f 2435/2866/13924 2434/2865/13925 2373/2883/13926 -f 2436/2869/13927 2375/2879/13928 2373/2883/13929 -f 2373/2883/13930 2434/2865/13931 2436/2869/13932 -f 2437/2871/13933 2377/2876/13934 2375/2879/13935 -f 2375/2879/13936 2436/2869/13937 2437/2871/13938 -f 2437/2871/13939 2459/2870/13940 2460/2943/13941 -f 2460/2943/13942 2438/2877/13943 2437/2871/13944 -f 2374/2884/13945 2344/2822/13946 2427/2821/13947 -f 2427/2821/13948 2435/2866/13949 2374/2884/13950 -f 2399/2944/13951 2397/2917/13952 2440/2907/13953 -f 2440/2907/13954 2439/2906/13955 2399/2944/13956 -f 2441/2911/13957 2406/2929/13958 2399/2944/13959 -f 2399/2944/13960 2439/2906/13961 2441/2911/13962 -f 2442/2916/13963 2408/2913/13964 2401/2904/13965 -f 2401/2904/13966 2440/2907/13967 2442/2916/13968 -f 2443/2926/13969 2469/2945/13970 2411/2928/13971 -f 2411/2928/13972 2444/2927/13973 2443/2926/13974 -f 2441/2911/13975 2405/2910/13976 2415/2924/13977 -f 2415/2924/13978 2444/2927/13979 2441/2911/13980 -f 2395/2915/13981 2393/2946/13982 2445/2931/13983 -f 2445/2931/13984 2442/2916/13985 2395/2915/13986 -f 2393/2946/13987 2391/2947/13988 2446/2932/13989 -f 2446/2932/13990 2445/2931/13991 2393/2946/13992 -f 2391/2947/13993 2389/2939/13994 2447/2938/13995 -f 2447/2938/13996 2446/2932/13997 2391/2947/13998 -f 2363/2949/13999 2421/2936/14000 2447/2938/14001 -f 2447/2938/14002 2433/2951/14003 2363/2949/14004 -f 2438/2956/14005 2460/2959/14006 2469/2945/14007 -f 2469/2945/14008 2443/2926/14009 2438/2956/14010 -f 2342/2855/14011 2448/2823/14012 2343/2857/14013 -f 2343/2857/14014 2449/2887/14015 2342/2855/14016 -f 2448/2823/14017 2342/2855/14018 2345/2829/14019 -f 2345/2829/14020 2450/2824/14021 2448/2823/14022 -f 2450/2824/14023 2345/2829/14024 2348/2832/14025 -f 2348/2832/14026 2451/2827/14027 2450/2824/14028 -f 2354/2838/14029 2452/2841/14030 2451/2827/14031 -f 2451/2827/14032 2348/2832/14033 2354/2838/14034 -f 2356/2840/14035 2453/2843/14036 2452/2841/14037 -f 2452/2841/14038 2354/2838/14039 2356/2840/14040 -f 2360/2853/14041 2454/2888/14042 2453/2843/14043 -f 2453/2843/14044 2356/2840/14045 2360/2853/14046 -f 2365/2852/14047 2455/2890/14048 2454/2888/14049 -f 2454/2888/14050 2360/2853/14051 2365/2852/14052 -f 2368/2859/14053 2456/2867/14054 2449/2887/14055 -f 2449/2887/14056 2343/2857/14057 2368/2859/14058 -f 2370/2861/14059 2457/2864/14060 2456/2867/14061 -f 2456/2867/14062 2368/2859/14063 2370/2861/14064 -f 2372/2863/14065 2458/2868/14066 2457/2864/14067 -f 2457/2864/14068 2370/2861/14069 2372/2863/14070 -f 2458/2868/14071 2372/2863/14072 2376/2873/14073 -f 2376/2873/14074 2459/2870/14075 2458/2868/14076 -f 2378/2872/14077 2460/2943/14078 2459/2870/14079 -f 2459/2870/14080 2376/2873/14081 2378/2872/14082 -f 2455/2952/14083 2365/2950/14084 2389/2939/14085 -f 2389/2939/14086 2461/2892/14087 2455/2952/14088 -f 2461/2892/14089 2389/2939/14090 2391/2947/14091 -f 2391/2947/14092 2462/2894/14093 2461/2892/14094 -f 2462/2894/14095 2391/2947/14096 2393/2946/14097 -f 2393/2946/14098 2463/2896/14099 2462/2894/14100 -f 2463/2896/14101 2393/2946/14102 2395/2915/14103 -f 2395/2915/14104 2464/2898/14105 2463/2896/14106 -f 2464/2898/14107 2395/2915/14108 2397/2917/14109 -f 2397/2917/14110 2465/2900/14111 2464/2898/14112 -f 2465/2900/14113 2397/2917/14114 2399/2944/14115 -f 2399/2944/14116 2466/2902/14117 2465/2900/14118 -f 2406/2929/14119 2467/2918/14120 2466/2902/14121 -f 2466/2902/14122 2399/2944/14123 2406/2929/14124 -f 2467/2918/14125 2406/2929/14126 2411/2928/14127 -f 2411/2928/14128 2468/2920/14129 2467/2918/14130 -f 2468/2920/14131 2411/2928/14132 2469/2945/14133 -f 2469/2945/14134 2413/2922/14135 2468/2920/14136 -f 2460/2959/14137 2378/2954/14138 2413/2922/14139 -f 2413/2922/14140 2469/2945/14141 2460/2959/14142 -f 2486/2962/14143 2487/2963/14144 2524/2960/14145 -f 2524/2960/14146 2532/2961/14147 2486/2962/14148 -f 2471/2965/14149 2524/2960/14150 2487/2963/14151 -f 2487/2963/14152 2479/2964/14153 2471/2965/14154 -f 2472/2967/14155 2471/2965/14156 2479/2964/14157 -f 2479/2964/14158 2480/2966/14159 2472/2967/14160 -f 2473/2969/14161 2472/2967/14162 2480/2966/14163 -f 2480/2966/14164 2481/2968/14165 2473/2969/14166 -f 2474/2971/14167 2473/3024/14168 2481/3023/14169 -f 2481/3023/14170 2482/2970/14171 2474/2971/14172 -f 2475/2973/14173 2474/2971/14174 2482/2970/14175 -f 2482/2970/14176 2483/2972/14177 2475/2973/14178 -f 2476/2975/14179 2475/2973/14180 2483/2972/14181 -f 2483/2972/14182 2484/2974/14183 2476/2975/14184 -f 2477/2977/14185 2476/2975/14186 2484/2974/14187 -f 2484/2974/14188 2485/2976/14189 2477/2977/14190 -f 2532/2961/14191 2477/2977/14192 2485/2976/14193 -f 2485/2976/14194 2486/2962/14195 2532/2961/14196 -f 2495/2978/14197 2494/2979/14198 2479/2964/14199 -f 2479/2964/14200 2487/2963/14201 2495/2978/14202 -f 2480/2966/14203 2479/2964/14204 2494/2979/14205 -f 2494/2979/14206 2493/2980/14207 2480/2966/14208 -f 2481/2968/14209 2480/2966/14210 2493/2980/14211 -f 2493/2980/14212 2492/2981/14213 2481/2968/14214 -f 2482/2970/14215 2481/3023/14216 2492/3025/14217 -f 2492/3025/14218 2491/2982/14219 2482/2970/14220 -f 2483/2972/14221 2482/2970/14222 2491/2982/14223 -f 2491/2982/14224 2490/2983/14225 2483/2972/14226 -f 2484/2974/14227 2483/2972/14228 2490/2983/14229 -f 2490/2983/14230 2489/2984/14231 2484/2974/14232 -f 2485/2976/14233 2484/2974/14234 2489/2984/14235 -f 2489/2984/14236 2488/2985/14237 2485/2976/14238 -f 2486/2962/14239 2485/2976/14240 2488/2985/14241 -f 2488/2985/14242 2496/2986/14243 2486/2962/14244 -f 2487/2963/14245 2486/2962/14246 2496/2986/14247 -f 2496/2986/14248 2495/2978/14249 2487/2963/14250 -f 2478/2989/14251 2470/2990/14252 2497/2987/14253 -f 2497/2987/14254 2505/2988/14255 2478/2989/14256 -f 2470/2990/14257 2525/2992/14258 2498/2991/14259 -f 2498/2991/14260 2497/2987/14261 2470/2990/14262 -f 2525/2992/14263 2526/2994/14264 2499/2993/14265 -f 2499/2993/14266 2498/2991/14267 2525/2992/14268 -f 2526/2994/14269 2527/2996/14270 2500/2995/14271 -f 2500/2995/14272 2499/2993/14273 2526/2994/14274 -f 2527/3027/14275 2528/2998/14276 2501/2997/14277 -f 2501/2997/14278 2500/3026/14279 2527/3027/14280 -f 2528/2998/14281 2529/3000/14282 2502/2999/14283 -f 2502/2999/14284 2501/2997/14285 2528/2998/14286 -f 2529/3000/14287 2530/3002/14288 2503/3001/14289 -f 2503/3001/14290 2502/2999/14291 2529/3000/14292 -f 2530/3002/14293 2531/3004/14294 2504/3003/14295 -f 2504/3003/14296 2503/3001/14297 2530/3002/14298 -f 2531/3004/14299 2478/2989/14300 2505/2988/14301 -f 2505/2988/14302 2504/3003/14303 2531/3004/14304 -f 2521/3007/14305 2522/3008/14306 2513/3005/14307 -f 2513/3005/14308 2512/3006/14309 2521/3007/14310 -f 2520/3010/14311 2521/3007/14312 2512/3006/14313 -f 2512/3006/14314 2511/3009/14315 2520/3010/14316 -f 2519/3012/14317 2520/3010/14318 2511/3009/14319 -f 2511/3009/14320 2510/3011/14321 2519/3012/14322 -f 2518/3014/14323 2519/3029/14324 2510/3028/14325 -f 2510/3028/14326 2509/3013/14327 2518/3014/14328 -f 2517/3016/14329 2518/3014/14330 2509/3013/14331 -f 2509/3013/14332 2508/3015/14333 2517/3016/14334 -f 2516/3018/14335 2517/3016/14336 2508/3015/14337 -f 2508/3015/14338 2507/3017/14339 2516/3018/14340 -f 2515/3020/14341 2516/3018/14342 2507/3017/14343 -f 2507/3017/14344 2506/3019/14345 2515/3020/14346 -f 2523/3022/14347 2515/3020/14348 2506/3019/14349 -f 2506/3019/14350 2514/3021/14351 2523/3022/14352 -f 2522/3008/14353 2523/3022/14354 2514/3021/14355 -f 2514/3021/14356 2513/3005/14357 2522/3008/14358 -f 2495/2978/14359 2522/3008/14360 2521/3007/14361 -f 2521/3007/14362 2494/2979/14363 2495/2978/14364 -f 2494/2979/14365 2521/3007/14366 2520/3010/14367 -f 2520/3010/14368 2493/2980/14369 2494/2979/14370 -f 2493/2980/14371 2520/3010/14372 2519/3012/14373 -f 2519/3012/14374 2492/2981/14375 2493/2980/14376 -f 2492/3025/14377 2519/3029/14378 2518/3014/14379 -f 2518/3014/14380 2491/2982/14381 2492/3025/14382 -f 2491/2982/14383 2518/3014/14384 2517/3016/14385 -f 2517/3016/14386 2490/2983/14387 2491/2982/14388 -f 2490/2983/14389 2517/3016/14390 2516/3018/14391 -f 2516/3018/14392 2489/2984/14393 2490/2983/14394 -f 2489/2984/14395 2516/3018/14396 2515/3020/14397 -f 2515/3020/14398 2488/2985/14399 2489/2984/14400 -f 2488/2985/14401 2515/3020/14402 2523/3022/14403 -f 2523/3022/14404 2496/2986/14405 2488/2985/14406 -f 2496/2986/14407 2523/3022/14408 2522/3008/14409 -f 2522/3008/14410 2495/2978/14411 2496/2986/14412 -f 2524/2960/14413 2470/2990/14414 2478/2989/14415 -f 2478/2989/14416 2532/2961/14417 2524/2960/14418 -f 2471/2965/14419 2525/2992/14420 2470/2990/14421 -f 2470/2990/14422 2524/2960/14423 2471/2965/14424 -f 2472/2967/14425 2526/2994/14426 2525/2992/14427 -f 2525/2992/14428 2471/2965/14429 2472/2967/14430 -f 2473/2969/14431 2527/2996/14432 2526/2994/14433 -f 2526/2994/14434 2472/2967/14435 2473/2969/14436 -f 2474/2971/14437 2528/2998/14438 2527/3027/14439 -f 2527/3027/14440 2473/3024/14441 2474/2971/14442 -f 2475/2973/14443 2529/3000/14444 2528/2998/14445 -f 2528/2998/14446 2474/2971/14447 2475/2973/14448 -f 2476/2975/14449 2530/3002/14450 2529/3000/14451 -f 2529/3000/14452 2475/2973/14453 2476/2975/14454 -f 2477/2977/14455 2531/3004/14456 2530/3002/14457 -f 2530/3002/14458 2476/2975/14459 2477/2977/14460 -f 2532/2961/14461 2478/2989/14462 2531/3004/14463 -f 2531/3004/14464 2477/2977/14465 2532/2961/14466 -f 2535/3035/14467 2536/3060/14468 2533/3032/14469 -f 2533/3032/14470 2534/3033/14471 2535/3035/14472 -f 2536/3060/14473 2538/3062/14474 2537/3061/14475 -f 2537/3061/14476 2533/3032/14477 2536/3060/14478 -f 2537/3034/14479 2540/3036/14480 2539/3030/14481 -f 2539/3030/14482 2533/3031/14483 2537/3034/14484 -f 2542/3038/14485 2543/3039/14486 2539/3030/14487 -f 2539/3030/14488 2541/3037/14489 2542/3038/14490 -f 2539/3030/14491 2540/3036/14492 2544/3040/14493 -f 2544/3040/14494 2541/3037/14495 2539/3030/14496 -f 2544/3040/14497 2540/3036/14498 2545/3041/14499 -f 2545/3041/14500 2546/3042/14501 2544/3040/14502 -f 2548/3044/14503 2546/3042/14504 2545/3041/14505 -f 2545/3041/14506 2547/3043/14507 2548/3044/14508 -f 2547/3048/14509 2550/3049/14510 2549/3046/14511 -f 2549/3046/14512 2548/3047/14513 2547/3048/14514 -f 2549/3046/14515 2550/3049/14516 2551/3050/14517 -f 2551/3050/14518 2552/3051/14519 2549/3046/14520 -f 2554/3053/14521 2552/3051/14522 2551/3050/14523 -f 2551/3050/14524 2553/3052/14525 2554/3053/14526 -f 2555/3054/14527 2556/3055/14528 2554/3053/14529 -f 2554/3053/14530 2553/3052/14531 2555/3054/14532 -f 2557/3056/14533 2558/3057/14534 2555/3054/14535 -f 2555/3054/14536 2553/3052/14537 2557/3056/14538 -f 2559/3068/14539 2557/3056/14540 2553/3052/14541 -f 2553/3052/14542 2551/3050/14543 2559/3068/14544 -f 2559/3068/14545 2551/3050/14546 2550/3049/14547 -f 2550/3049/14548 2560/3166/14549 2559/3068/14550 -f 2550/3049/14551 2547/3048/14552 2561/3175/14553 -f 2561/3175/14554 2560/3166/14555 2550/3049/14556 -f 2562/3045/14557 2561/3058/14558 2547/3043/14559 -f 2547/3043/14560 2545/3041/14561 2562/3045/14562 -f 2564/3065/14563 2561/3066/14564 2562/3063/14565 -f 2562/3063/14566 2563/3064/14567 2564/3065/14568 -f 2566/3069/14569 2564/3065/14570 2563/3064/14571 -f 2563/3064/14572 2565/3067/14573 2566/3069/14574 -f 2567/3070/14575 2568/3079/14576 2566/3069/14577 -f 2566/3069/14578 2565/3067/14579 2567/3070/14580 -f 2565/3067/14581 2570/3081/14582 2569/3080/14583 -f 2569/3080/14584 2567/3070/14585 2565/3067/14586 -f 2538/3062/14587 2570/3081/14588 2565/3067/14589 -f 2565/3067/14590 2563/3064/14591 2538/3062/14592 -f 2564/3065/14593 2572/3188/14594 2571/3082/14595 -f 2571/3082/14596 2561/3066/14597 2564/3065/14598 -f 2566/3069/14599 2573/3189/14600 2572/3188/14601 -f 2572/3188/14602 2564/3065/14603 2566/3069/14604 -f 2538/3062/14605 2563/3064/14606 2562/3063/14607 -f 2562/3063/14608 2537/3061/14609 2538/3062/14610 -f 2562/3045/14611 2545/3041/14612 2540/3036/14613 -f 2540/3036/14614 2537/3034/14615 2562/3045/14616 -f 2574/3059/14617 2575/3071/14618 2543/3039/14619 -f 2543/3039/14620 2542/3038/14621 2574/3059/14622 -f 2539/3030/14623 2543/3039/14624 2534/3072/14625 -f 2534/3072/14626 2533/3031/14627 2539/3030/14628 -f 2576/3073/14629 2534/3072/14630 2543/3039/14631 -f 2543/3039/14632 2575/3071/14633 2576/3073/14634 -f 2575/3071/14635 2578/3075/14636 2577/3074/14637 -f 2577/3074/14638 2576/3073/14639 2575/3071/14640 -f 2579/3076/14641 2580/3077/14642 2576/3073/14643 -f 2576/3073/14644 2577/3074/14645 2579/3076/14646 -f 2576/3073/14647 2580/3077/14648 2581/3078/14649 -f 2581/3078/14650 2534/3072/14651 2576/3073/14652 -f 2581/3190/14653 2582/3191/14654 2535/3035/14655 -f 2535/3035/14656 2534/3033/14657 2581/3190/14658 -f 2584/3193/14659 2536/3060/14660 2535/3035/14661 -f 2535/3035/14662 2583/3192/14663 2584/3193/14664 -f 2585/3194/14665 2583/3192/14666 2535/3035/14667 -f 2535/3035/14668 2582/3191/14669 2585/3194/14670 -f 2586/3083/14671 2587/3084/14672 2579/3076/14673 -f 2579/3076/14674 2577/3074/14675 2586/3083/14676 -f 2577/3074/14677 2578/3075/14678 2588/3085/14679 -f 2588/3085/14680 2586/3083/14681 2577/3074/14682 -f 2589/3086/14683 2590/3087/14684 2588/3085/14685 -f 2588/3085/14686 2578/3075/14687 2589/3086/14688 -f 2588/3085/14689 2592/3089/14690 2591/3088/14691 -f 2591/3088/14692 2586/3083/14693 2588/3085/14694 -f 2588/3085/14695 2590/3087/14696 2593/3090/14697 -f 2593/3090/14698 2592/3089/14699 2588/3085/14700 -f 2587/3084/14701 2586/3083/14702 2591/3088/14703 -f 2591/3088/14704 2594/3091/14705 2587/3084/14706 -f 2594/3091/14707 2591/3088/14708 2595/3237/14709 -f 2595/3237/14710 2596/3238/14711 2594/3091/14712 -f 2578/3075/14713 2575/3071/14714 2574/3059/14715 -f 2574/3059/14716 2589/3086/14717 2578/3075/14718 -f 2599/3098/14719 2600/3099/14720 2597/3095/14721 -f 2597/3095/14722 2598/3096/14723 2599/3098/14724 -f 2602/3101/14725 2599/3098/14726 2598/3096/14727 -f 2598/3096/14728 2601/3100/14729 2602/3101/14730 -f 2604/3103/14731 2602/3101/14732 2601/3100/14733 -f 2601/3100/14734 2603/3102/14735 2604/3103/14736 -f 2603/3102/14737 2606/3105/14738 2605/3104/14739 -f 2605/3104/14740 2604/3221/14741 2603/3102/14742 -f 2605/3104/14743 2606/3105/14744 2607/3106/14745 -f 2607/3106/14746 2608/3107/14747 2605/3104/14748 -f 2608/3223/14749 2607/3106/14750 2609/3108/14751 -f 2609/3108/14752 2610/3109/14753 2608/3223/14754 -f 2612/3111/14755 2613/3112/14756 2609/3108/14757 -f 2609/3108/14758 2611/3110/14759 2612/3111/14760 -f 2606/3105/14761 2603/3102/14762 2614/3113/14763 -f 2614/3113/14764 2611/3110/14765 2606/3105/14766 -f 2614/3113/14767 2615/3114/14768 2612/3111/14769 -f 2612/3111/14770 2611/3110/14771 2614/3113/14772 -f 2617/3116/14773 2613/3112/14774 2612/3111/14775 -f 2612/3111/14776 2616/3115/14777 2617/3116/14778 -f 2618/3117/14779 2619/3118/14780 2617/3116/14781 -f 2617/3116/14782 2616/3115/14783 2618/3117/14784 -f 2621/3120/14785 2618/3117/14786 2616/3115/14787 -f 2616/3115/14788 2620/3119/14789 2621/3120/14790 -f 2612/3111/14791 2615/3114/14792 2620/3119/14793 -f 2620/3119/14794 2616/3115/14795 2612/3111/14796 -f 2610/3109/14797 2609/3108/14798 2613/3112/14799 -f 2613/3112/14800 2622/3121/14801 2610/3109/14802 -f 2623/3122/14803 2622/3227/14804 2613/3112/14805 -f 2613/3112/14806 2617/3116/14807 2623/3122/14808 -f 2615/3114/14809 2614/3113/14810 2624/3123/14811 -f 2624/3123/14812 2625/3124/14813 2615/3114/14814 -f 2627/3128/14815 2625/3124/14816 2624/3123/14817 -f 2624/3123/14818 2626/3127/14819 2627/3128/14820 -f 2601/3100/14821 2598/3096/14822 2626/3127/14823 -f 2626/3127/14824 2624/3123/14825 2601/3100/14826 -f 2629/3167/14827 2627/3128/14828 2626/3127/14829 -f 2626/3127/14830 2628/3164/14831 2629/3167/14832 -f 2628/3164/14833 2626/3127/14834 2598/3096/14835 -f 2598/3096/14836 2597/3095/14837 2628/3164/14838 -f 2630/3183/14839 2620/3119/14840 2615/3114/14841 -f 2615/3114/14842 2625/3124/14843 2630/3183/14844 -f 2631/3184/14845 2630/3183/14846 2625/3124/14847 -f 2625/3124/14848 2627/3128/14849 2631/3184/14850 -f 2614/3113/14851 2603/3102/14852 2601/3100/14853 -f 2601/3100/14854 2624/3123/14855 2614/3113/14856 -f 2606/3105/14857 2611/3110/14858 2609/3108/14859 -f 2609/3108/14860 2607/3106/14861 2606/3105/14862 -f 2632/3125/14863 2633/3126/14864 2597/3094/14865 -f 2597/3094/14866 2600/3097/14867 2632/3125/14868 -f 2633/3126/14869 2632/3125/14870 2634/3129/14871 -f 2634/3129/14872 2635/3130/14873 2633/3126/14874 -f 2634/3129/14875 2637/3132/14876 2636/3131/14877 -f 2636/3131/14878 2635/3130/14879 2634/3129/14880 -f 2639/3134/14881 2640/3135/14882 2636/3131/14883 -f 2636/3131/14884 2638/3133/14885 2639/3134/14886 -f 2641/3136/14887 2642/3137/14888 2639/3134/14889 -f 2639/3134/14890 2638/3133/14891 2641/3136/14892 -f 2643/3140/14893 2644/3141/14894 2640/3135/14895 -f 2640/3135/14896 2639/3134/14897 2643/3140/14898 -f 2646/3143/14899 2640/3135/14900 2644/3141/14901 -f 2644/3141/14902 2645/3142/14903 2646/3143/14904 -f 2645/3142/14905 2648/3145/14906 2647/3144/14907 -f 2647/3144/14908 2646/3143/14909 2645/3142/14910 -f 2650/3147/14911 2647/3144/14912 2648/3145/14913 -f 2648/3145/14914 2649/3146/14915 2650/3147/14916 -f 2650/3147/14917 2649/3146/14918 2651/3148/14919 -f 2651/3148/14920 2652/3149/14921 2650/3147/14922 -f 2635/3130/14923 2646/3143/14924 2647/3144/14925 -f 2647/3144/14926 2633/3126/14927 2635/3130/14928 -f 2647/3144/14929 2650/3147/14930 2597/3094/14931 -f 2597/3094/14932 2633/3126/14933 2647/3144/14934 -f 2640/3135/14935 2646/3143/14936 2635/3130/14937 -f 2635/3130/14938 2636/3131/14939 2640/3135/14940 -f 2639/3134/14941 2642/3137/14942 2653/3163/14943 -f 2653/3163/14944 2643/3140/14945 2639/3134/14946 -f 2654/3138/14947 2655/3139/14948 2653/3092/14949 -f 2653/3092/14950 2642/3093/14951 2654/3138/14952 -f 2642/3093/14953 2641/3151/14954 2656/3150/14955 -f 2656/3150/14956 2654/3138/14957 2642/3093/14958 -f 2658/3153/14959 2659/3154/14960 2657/3152/14961 -f 2657/3152/14962 2656/3150/14963 2658/3153/14964 -f 2656/3150/14965 2641/3151/14966 2660/3155/14967 -f 2660/3155/14968 2658/3153/14969 2656/3150/14970 -f 2657/3152/14971 2661/3156/14972 2654/3138/14973 -f 2654/3138/14974 2656/3150/14975 2657/3152/14976 -s 2 -f 2662/3157/14977 2653/3092/14978 2655/3139/14979 -s 4 -f 2662/3157/14980 2663/3158/14981 2664/3159/14982 -s 1 -f 2662/3157/14983 2661/3156/14984 2665/3160/14985 -f 2665/3160/14986 2663/3158/14987 2662/3157/14988 -f 2661/3156/14989 2662/3157/14990 2655/3139/14991 -f 2655/3139/14992 2654/3138/14993 2661/3156/14994 -f 2660/3168/14995 2641/3136/14996 2638/3133/14997 -f 2638/3133/14998 2666/3165/14999 2660/3168/15000 -f 2666/3165/15001 2638/3133/15002 2636/3131/15003 -f 2636/3131/15004 2637/3132/15005 2666/3165/15006 -f 2650/3147/15007 2652/3149/15008 2628/3169/15009 -f 2628/3169/15010 2597/3094/15011 2650/3147/15012 -f 2669/3187/15013 2670/3212/15014 2667/3185/15015 -f 2667/3185/15016 2668/3186/15017 2669/3187/15018 -f 2631/3184/15019 2671/3213/15020 2668/3186/15021 -f 2668/3186/15022 2667/3185/15023 2631/3184/15024 -f 2673/3172/15025 2668/3173/15026 2671/3170/15027 -f 2671/3170/15028 2672/3171/15029 2673/3172/15030 -f 2675/3241/15031 2673/3172/15032 2672/3171/15033 -f 2672/3171/15034 2674/3174/15035 2675/3241/15036 -f 2676/3242/15037 2677/3243/15038 2674/3174/15039 -f 2674/3174/15040 2672/3171/15041 2676/3242/15042 -f 2652/3149/15043 2651/3148/15044 2677/3243/15045 -f 2677/3243/15046 2676/3242/15047 2652/3149/15048 -f 2652/3149/15049 2676/3242/15050 2629/3244/15051 -f 2629/3244/15052 2628/3169/15053 2652/3149/15054 -f 2672/3171/15055 2671/3170/15056 2629/3244/15057 -f 2629/3244/15058 2676/3242/15059 2672/3171/15060 -f 2675/3178/15061 2679/3179/15062 2678/3176/15063 -f 2678/3176/15064 2673/3177/15065 2675/3178/15066 -f 2558/3057/15067 2680/3180/15068 2678/3176/15069 -f 2678/3176/15070 2555/3054/15071 2558/3057/15072 -f 2680/3180/15073 2668/3181/15074 2673/3177/15075 -f 2673/3177/15076 2678/3176/15077 2680/3180/15078 -f 2669/3229/15079 2668/3181/15080 2680/3180/15081 -f 2680/3180/15082 2681/3182/15083 2669/3229/15084 -f 2682/3230/15085 2681/3182/15086 2680/3180/15087 -f 2680/3180/15088 2558/3057/15089 2682/3230/15090 -f 2682/3230/15091 2558/3057/15092 2557/3056/15093 -f 2557/3056/15094 2683/3231/15095 2682/3230/15096 -f 2557/3056/15097 2559/3068/15098 2684/3234/15099 -f 2684/3234/15100 2683/3231/15101 2557/3056/15102 -f 2684/3234/15103 2559/3068/15104 2560/3166/15105 -f 2560/3166/15106 2685/3235/15107 2684/3234/15108 -f 2556/3055/15109 2555/3054/15110 2678/3176/15111 -f 2678/3176/15112 2679/3179/15113 2556/3055/15114 -f 2631/3184/15115 2627/3128/15116 2629/3167/15117 -f 2629/3167/15118 2671/3213/15119 2631/3184/15120 -f 2686/3214/15121 2630/3183/15122 2631/3184/15123 -f 2631/3184/15124 2667/3185/15125 2686/3214/15126 -f 2620/3119/15127 2630/3183/15128 2686/3214/15129 -f 2686/3214/15130 2621/3120/15131 2620/3119/15132 -f 2621/3120/15133 2686/3214/15134 2687/3215/15135 -f 2687/3215/15136 2688/3216/15137 2621/3120/15138 -f 2670/3212/15139 2687/3215/15140 2686/3214/15141 -f 2686/3214/15142 2667/3185/15143 2670/3212/15144 -f 2689/3217/15145 2618/3117/15146 2621/3120/15147 -f 2621/3120/15148 2688/3232/15149 2689/3217/15150 -f 2690/3218/15151 2619/3118/15152 2618/3117/15153 -f 2618/3117/15154 2689/3217/15155 2690/3218/15156 -f 2690/3233/15157 2623/3122/15158 2617/3116/15159 -f 2617/3116/15160 2619/3118/15161 2690/3233/15162 -f 2561/3175/15163 2571/3236/15164 2685/3235/15165 -f 2685/3235/15166 2560/3166/15167 2561/3175/15168 -f 2584/3193/15169 2570/3081/15170 2538/3062/15171 -f 2538/3062/15172 2536/3060/15173 2584/3193/15174 -f 2691/3195/15175 2569/3080/15176 2570/3081/15177 -f 2570/3081/15178 2584/3193/15179 2691/3195/15180 -f 2691/3195/15181 2584/3193/15182 2583/3192/15183 -f 2583/3192/15184 2692/3196/15185 2691/3195/15186 -f 2694/3198/15187 2691/3195/15188 2692/3196/15189 -f 2692/3196/15190 2693/3197/15191 2694/3198/15192 -f 2696/3200/15193 2694/3198/15194 2693/3197/15195 -f 2693/3197/15196 2695/3199/15197 2696/3200/15198 -f 2698/3202/15199 2695/3199/15200 2693/3197/15201 -f 2693/3197/15202 2697/3201/15203 2698/3202/15204 -f 2692/3196/15205 2699/3203/15206 2697/3201/15207 -f 2697/3201/15208 2693/3197/15209 2692/3196/15210 -f 2583/3192/15211 2585/3194/15212 2699/3246/15213 -f 2699/3246/15214 2692/3196/15215 2583/3192/15216 -f 2696/3200/15217 2695/3199/15218 2698/3245/15219 -f 2698/3245/15220 2700/3204/15221 2696/3200/15222 -f 2701/3205/15223 2702/3206/15224 2696/3200/15225 -f 2696/3200/15226 2700/3204/15227 2701/3205/15228 -f 2696/3200/15229 2702/3206/15230 2703/3207/15231 -f 2703/3207/15232 2694/3198/15233 2696/3200/15234 -f 2567/3070/15235 2569/3080/15236 2703/3207/15237 -f 2703/3207/15238 2704/3208/15239 2567/3070/15240 -f 2705/3219/15241 2704/3208/15242 2703/3207/15243 -f 2703/3207/15244 2702/3206/15245 2705/3219/15246 -f 2701/3247/15247 2706/3220/15248 2705/3219/15249 -f 2705/3219/15250 2702/3206/15251 2701/3247/15252 -f 2704/3208/15253 2707/3222/15254 2568/3079/15255 -f 2568/3079/15256 2567/3070/15257 2704/3208/15258 -f 2707/3222/15259 2710/3226/15260 2708/3224/15261 -f 2708/3224/15262 2709/3225/15263 2707/3222/15264 -f 2710/3226/15265 2707/3222/15266 2704/3208/15267 -f 2704/3208/15268 2705/3219/15269 2710/3226/15270 -f 2707/3222/15271 2709/3225/15272 2711/3228/15273 -f 2711/3228/15274 2568/3079/15275 2707/3222/15276 -f 2694/3198/15277 2703/3207/15278 2569/3080/15279 -f 2569/3080/15280 2691/3195/15281 2694/3198/15282 -f 2712/3161/15283 2665/3160/15284 2661/3156/15285 -f 2661/3156/15286 2657/3152/15287 2712/3161/15288 -f 2595/3162/15289 2713/3209/15290 2665/3160/15291 -f 2665/3160/15292 2712/3161/15293 2595/3162/15294 -f 2591/3088/15295 2592/3089/15296 2713/3239/15297 -f 2713/3239/15298 2595/3237/15299 2591/3088/15300 -f 2664/3159/15301 2663/3158/15302 2665/3160/15303 -f 2665/3160/15304 2713/3209/15305 2664/3159/15306 -f 2592/3089/15307 2593/3090/15308 2664/3240/15309 -f 2664/3240/15310 2713/3239/15311 2592/3089/15312 -f 2714/3210/15313 2596/3211/15314 2595/3162/15315 -f 2595/3162/15316 2712/3161/15317 2714/3210/15318 -f 2659/3154/15319 2714/3210/15320 2712/3161/15321 -f 2712/3161/15322 2657/3152/15323 2659/3154/15324 -f 2573/3189/15325 2566/3069/15326 2568/3079/15327 -f 2568/3079/15328 2711/3249/15329 2573/3189/15330 -f 2708/3248/15331 2710/3226/15332 2705/3219/15333 -f 2705/3219/15334 2706/3220/15335 2708/3248/15336 -f 2716/3252/15337 2715/3253/15338 2718/3250/15339 -f 2718/3250/15340 2717/3251/15341 2716/3252/15342 -f 2719/3255/15343 2717/3251/15344 2718/3250/15345 -f 2718/3250/15346 2720/3254/15347 2719/3255/15348 -f 2721/3256/15349 2720/3257/15350 2718/3250/15351 -f 2718/3250/15352 2715/3253/15353 2721/3256/15354 -f 2722/3258/15355 2716/3252/15356 2717/3251/15357 -f 2717/3251/15358 2719/3255/15359 2722/3258/15360 -f 2723/3260/15361 2719/3255/15362 2720/3254/15363 -f 2720/3254/15364 2721/3259/15365 2723/3260/15366 -f 2719/3255/15367 2723/3260/15368 2724/3261/15369 -f 2724/3261/15370 2722/3258/15371 2719/3255/15372 -f 2727/3262/15373 2726/3263/15374 2725/3264/15375 -f 2723/3260/15376 2721/3259/15377 2727/3265/15378 -f 2727/3265/15379 2728/3266/15380 2723/3260/15381 -f 2727/3265/15382 2729/3267/15383 2728/3266/15384 -f 2731/3270/15385 2730/3271/15386 2733/3268/15387 -f 2733/3268/15388 2732/3269/15389 2731/3270/15390 -f 2735/3274/15391 2734/3275/15392 2737/3272/15393 -f 2737/3272/15394 2736/3273/15395 2735/3274/15396 -f 2738/3276/15397 2736/3273/15398 2737/3272/15399 -f 2737/3272/15400 2733/3268/15401 2738/3276/15402 -f 2739/3277/15403 2733/3268/15404 2737/3272/15405 -f 2737/3272/15406 2734/3275/15407 2739/3277/15408 -f 2741/3280/15409 2740/3281/15410 2743/3278/15411 -f 2743/3278/15412 2742/3279/15413 2741/3280/15414 -f 2745/3284/15415 2744/3285/15416 2747/3282/15417 -f 2747/3282/15418 2746/3283/15419 2745/3284/15420 -f 2746/3283/15421 2747/3282/15422 2749/3286/15423 -f 2749/3286/15424 2748/3287/15425 2746/3283/15426 -f 2747/3282/15427 2750/3288/15428 2749/3286/15429 -f 2752/3291/15430 2751/3292/15431 2754/3289/15432 -f 2754/3289/15433 2753/3290/15434 2752/3291/15435 -f 2754/3289/15436 2755/3293/15437 2753/3290/15438 -f 2754/3289/15439 2751/3292/15440 2756/3294/15441 -f 2753/3290/15442 2755/3293/15443 2758/3295/15444 -f 2758/3295/15445 2757/3296/15446 2753/3290/15447 -f 2752/3291/15448 2753/3290/15449 2757/3296/15450 -f 2752/3291/15451 2757/3296/15452 2760/3297/15453 -f 2760/3297/15454 2759/3298/15455 2752/3291/15456 -f 2761/3301/15457 2745/3284/15458 2763/3299/15459 -f 2763/3299/15460 2762/3300/15461 2761/3301/15462 -f 2763/3299/15463 2764/3304/15464 2766/3302/15465 -f 2766/3302/15466 2765/3303/15467 2763/3299/15468 -f 2763/3299/15469 2765/3303/15470 2767/3305/15471 -f 2767/3305/15472 2762/3300/15473 2763/3299/15474 -f 2769/3308/15475 2768/3309/15476 2771/3306/15477 -f 2771/3306/15478 2770/3307/15479 2769/3308/15480 -f 2773/3310/15481 2772/3311/15482 2768/3309/15483 -f 2768/3309/15484 2769/3308/15485 2773/3310/15486 -f 2774/3313/15487 2769/3308/15488 2770/3307/15489 -f 2770/3307/15490 2775/3312/15491 2774/3313/15492 -f 2776/3315/15493 2772/3311/15494 2773/3310/15495 -f 2773/3310/15496 2777/3314/15497 2776/3315/15498 -f 2778/3316/15499 2758/3295/15500 2767/3305/15501 -f 2767/3305/15502 2765/3303/15503 2778/3316/15504 -f 2770/3307/15505 2771/3306/15506 2780/3317/15507 -f 2780/3317/15508 2779/3318/15509 2770/3307/15510 -f 2782/3321/15511 2781/3322/15512 2784/3319/15513 -f 2784/3319/15514 2783/3320/15515 2782/3321/15516 -f 2783/3320/15517 2784/3319/15518 2786/3323/15519 -f 2786/3323/15520 2785/3324/15521 2783/3320/15522 -f 2788/3327/15523 2787/3328/15524 2790/3325/15525 -f 2790/3325/15526 2789/3326/15527 2788/3327/15528 -f 2789/3326/15529 2790/3325/15530 2791/3329/15531 -f 2793/3331/15532 2792/3332/15533 2789/3326/15534 -f 2789/3326/15535 2794/3330/15536 2793/3331/15537 -f 2795/3333/15538 2794/3330/15539 2789/3326/15540 -f 2789/3326/15541 2791/3329/15542 2795/3333/15543 -f 2770/3307/15544 2796/3335/15545 2797/3334/15546 -f 2797/3334/15547 2775/3312/15548 2770/3307/15549 -f 2777/3314/15550 2798/3338/15551 2800/3336/15552 -f 2800/3336/15553 2799/3337/15554 2777/3314/15555 -f 2802/3339/15556 2801/3340/15557 2800/3336/15558 -f 2800/3336/15559 2798/3338/15560 2802/3339/15561 -f 2804/3341/15562 2803/3342/15563 2800/3336/15564 -f 2800/3336/15565 2801/3340/15566 2804/3341/15567 -f 2777/3314/15568 2773/3310/15569 2805/3343/15570 -f 2805/3343/15571 2798/3338/15572 2777/3314/15573 -f 2805/3343/15574 2773/3310/15575 2774/3313/15576 -f 2774/3313/15577 2806/3344/15578 2805/3343/15579 -f 2805/3343/15580 2806/3344/15581 2807/3345/15582 -f 2809/3346/15583 2808/3347/15584 2805/3343/15585 -f 2805/3343/15586 2807/3345/15587 2809/3346/15588 -f 2812/3348/15589 2811/3349/15590 2810/3350/15591 -f 2813/3352/15592 2794/3330/15593 2795/3333/15594 -f 2795/3333/15595 2814/3351/15596 2813/3352/15597 -f 2816/3354/15598 2815/3355/15599 2795/3333/15600 -f 2795/3333/15601 2817/3353/15602 2816/3354/15603 -f 2818/3356/15604 2814/3351/15605 2795/3333/15606 -f 2795/3333/15607 2815/3355/15608 2818/3356/15609 -f 2820/3359/15610 2819/3360/15611 2822/3357/15612 -f 2822/3357/15613 2821/3358/15614 2820/3359/15615 -f 2766/3302/15616 2821/3358/15617 2822/3357/15618 -f 2822/3357/15619 2812/3348/15620 2766/3302/15621 -f 2819/3360/15622 2823/3361/15623 2822/3357/15624 -f 2822/3357/15625 2823/3361/15626 2824/3362/15627 -f 2822/3357/15628 2824/3362/15629 2811/3349/15630 -f 2826/3365/15631 2825/3366/15632 2828/3363/15633 -f 2828/3363/15634 2827/3364/15635 2826/3365/15636 -f 2828/3363/15637 2829/3369/15638 2831/3367/15639 -f 2831/3367/15640 2830/3368/15641 2828/3363/15642 -f 2796/3335/15643 2832/3371/15644 2833/3370/15645 -f 2833/3370/15646 2797/3334/15647 2796/3335/15648 -f 2833/3370/15649 2834/3372/15650 2797/3334/15651 -f 2770/3307/15652 2779/3318/15653 2832/3371/15654 -f 2832/3371/15655 2796/3335/15656 2770/3307/15657 -f 2836/3373/15658 2835/3374/15659 2823/3361/15660 -f 2838/3376/15661 2837/3377/15662 2839/3375/15663 -f 2839/3375/15664 2836/3373/15665 2838/3376/15666 -f 2840/3379/15667 2835/3374/15668 2839/3375/15669 -f 2839/3375/15670 2841/3378/15671 2840/3379/15672 -f 2839/3375/15673 2835/3374/15674 2836/3373/15675 -f 2843/3382/15676 2842/3383/15677 2845/3380/15678 -f 2845/3380/15679 2844/3381/15680 2843/3382/15681 -f 2847/3384/15682 2846/3385/15683 2845/3380/15684 -f 2845/3380/15685 2842/3383/15686 2847/3384/15687 -f 2848/3387/15688 2844/3381/15689 2845/3380/15690 -f 2845/3380/15691 2849/3386/15692 2848/3387/15693 -f 2851/3390/15694 2850/3391/15695 2853/3388/15696 -f 2853/3388/15697 2852/3389/15698 2851/3390/15699 -f 2852/3389/15700 2854/3392/15701 2851/3390/15702 -f 2855/3395/15703 2834/3372/15704 2857/3393/15705 -f 2857/3393/15706 2856/3394/15707 2855/3395/15708 -f 2856/3394/15709 2857/3393/15710 2859/3396/15711 -f 2859/3396/15712 2858/3397/15713 2856/3394/15714 -f 2833/3370/15715 2859/3396/15716 2857/3393/15717 -f 2857/3393/15718 2834/3372/15719 2833/3370/15720 -f 2860/3399/15721 2829/3369/15722 2861/3398/15723 -f 2861/3398/15724 2840/3379/15725 2860/3399/15726 -f 2840/3379/15727 2861/3398/15728 2862/3400/15729 -f 2862/3400/15730 2835/3374/15731 2840/3379/15732 -f 2860/3399/15733 2863/3402/15734 2864/3401/15735 -f 2864/3401/15736 2829/3369/15737 2860/3399/15738 -f 2829/3369/15739 2864/3401/15740 2865/3403/15741 -f 2865/3403/15742 2831/3367/15743 2829/3369/15744 -f 2866/3404/15745 2860/3399/15746 2840/3379/15747 -f 2840/3379/15748 2841/3378/15749 2866/3404/15750 -f 2853/3388/15751 2867/3406/15752 2868/3405/15753 -f 2868/3405/15754 2852/3389/15755 2853/3388/15756 -f 2854/3392/15757 2852/3389/15758 2868/3405/15759 -f 2868/3405/15760 2869/3407/15761 2854/3392/15762 -f 2870/3408/15763 2869/3407/15764 2868/3405/15765 -f 2868/3405/15766 2867/3406/15767 2870/3408/15768 -f 2859/3396/15769 2871/3410/15770 2872/3409/15771 -f 2872/3409/15772 2858/3397/15773 2859/3396/15774 -f 2847/3384/15775 2858/3397/15776 2872/3409/15777 -f 2872/3409/15778 2873/3411/15779 2847/3384/15780 -f 2874/3412/15781 2873/3411/15782 2872/3409/15783 -f 2872/3409/15784 2871/3410/15785 2874/3412/15786 -f 2876/3413/15787 2875/3414/15788 2870/3408/15789 -f 2870/3408/15790 2867/3406/15791 2876/3413/15792 -f 2877/3415/15793 2869/3407/15794 2870/3408/15795 -f 2870/3408/15796 2875/3414/15797 2877/3415/15798 -f 2878/3416/15799 2874/3412/15800 2871/3410/15801 -f 2871/3410/15802 2859/3396/15803 2878/3416/15804 -f 2850/3391/15805 2879/3418/15806 2880/3417/15807 -f 2880/3417/15808 2853/3388/15809 2850/3391/15810 -f 2882/3419/15811 2881/3420/15812 2853/3388/15813 -f 2853/3388/15814 2880/3417/15815 2882/3419/15816 -f 2876/3413/15817 2867/3406/15818 2853/3388/15819 -f 2853/3388/15820 2881/3420/15821 2876/3413/15822 -f 2884/3423/15823 2883/3424/15824 2886/3421/15825 -f 2886/3421/15826 2885/3422/15827 2884/3423/15828 -f 2887/3426/15829 2885/3422/15830 2886/3421/15831 -f 2886/3421/15832 2888/3425/15833 2887/3426/15834 -f 2889/3427/15835 2888/3425/15836 2886/3421/15837 -f 2886/3421/15838 2883/3424/15839 2889/3427/15840 -f 2890/3429/15841 2888/3425/15842 2889/3427/15843 -f 2889/3427/15844 2891/3428/15845 2890/3429/15846 -f 2892/3430/15847 2891/3428/15848 2889/3427/15849 -f 2889/3427/15850 2883/3424/15851 2892/3430/15852 -f 2894/3431/15853 2893/3432/15854 2876/3413/15855 -f 2876/3413/15856 2881/3420/15857 2894/3431/15858 -f 2885/3422/15859 2875/3414/15860 2876/3413/15861 -f 2876/3413/15862 2884/3423/15863 2885/3422/15864 -f 2895/3433/15865 2884/3423/15866 2876/3413/15867 -f 2876/3413/15868 2893/3432/15869 2895/3433/15870 -f 2896/3435/15871 2873/3411/15872 2874/3412/15873 -f 2874/3412/15874 2897/3434/15875 2896/3435/15876 -f 2899/3438/15877 2898/3439/15878 2901/3436/15879 -f 2901/3436/15880 2900/3437/15881 2899/3438/15882 -f 2903/3441/15883 2902/3442/15884 2901/3436/15885 -f 2901/3436/15886 2904/3440/15887 2903/3441/15888 -f 2905/3443/15889 2900/3437/15890 2901/3436/15891 -f 2901/3436/15892 2902/3442/15893 2905/3443/15894 -f 2907/3446/15895 2906/3447/15896 2909/3444/15897 -f 2909/3444/15898 2908/3445/15899 2907/3446/15900 -f 2910/3449/15901 2908/3445/15902 2909/3444/15903 -f 2909/3444/15904 2911/3448/15905 2910/3449/15906 -f 2912/3450/15907 2911/3448/15908 2909/3444/15909 -f 2909/3444/15910 2906/3447/15911 2912/3450/15912 -f 2914/3453/15913 2913/3454/15914 2916/3451/15915 -f 2916/3451/15916 2915/3452/15917 2914/3453/15918 -f 2918/3455/15919 2917/3456/15920 2916/3451/15921 -f 2916/3451/15922 2913/3454/15923 2918/3455/15924 -f 2920/3457/15925 2919/3458/15926 2916/3451/15927 -f 2916/3451/15928 2917/3456/15929 2920/3457/15930 -f 2863/3402/15931 2915/3452/15932 2916/3451/15933 -f 2916/3451/15934 2921/3459/15935 2863/3402/15936 -f 2922/3460/15937 2921/3459/15938 2916/3451/15939 -f 2916/3451/15940 2919/3458/15941 2922/3460/15942 -f 2895/3433/15943 2893/3432/15944 2923/3461/15945 -f 2923/3461/15946 2918/3455/15947 2895/3433/15948 -f 2894/3431/15949 2924/3462/15950 2923/3461/15951 -f 2923/3461/15952 2893/3432/15953 2894/3431/15954 -f 2917/3456/15955 2918/3455/15956 2923/3461/15957 -f 2923/3461/15958 2925/3463/15959 2917/3456/15960 -f 2927/3466/15961 2926/3467/15962 2929/3464/15963 -f 2929/3464/15964 2928/3465/15965 2927/3466/15966 -f 2928/3465/15967 2929/3464/15968 2931/3468/15969 -f 2931/3468/15970 2930/3469/15971 2928/3465/15972 -f 2932/3470/15973 2931/3468/15974 2929/3464/15975 -f 2929/3464/15976 2926/3467/15977 2932/3470/15978 -f 2934/3473/15979 2933/3474/15980 2936/3471/15981 -f 2936/3471/15982 2935/3472/15983 2934/3473/15984 -f 2937/3476/15985 2935/3472/15986 2936/3471/15987 -f 2936/3471/15988 2938/3475/15989 2937/3476/15990 -f 2940/3477/15991 2939/3478/15992 2936/3471/15993 -f 2936/3471/15994 2933/3474/15995 2940/3477/15996 -f 2942/3481/15997 2941/3482/15998 2943/3479/15999 -f 2943/3479/16000 2940/3480/16001 2942/3481/16002 -f 2939/3478/16003 2940/3477/16004 2943/3483/16005 -f 2943/3483/16006 2944/3484/16007 2939/3478/16008 -f 2945/3485/16009 2944/3486/16010 2943/3479/16011 -f 2943/3479/16012 2941/3482/16013 2945/3485/16014 -f 2947/3489/16015 2946/3490/16016 2949/3487/16017 -f 2949/3487/16018 2948/3488/16019 2947/3489/16020 -f 2951/3493/16021 2950/3494/16022 2949/3491/16023 -f 2949/3491/16024 2952/3492/16025 2951/3493/16026 -f 2953/3495/16027 2952/3496/16028 2949/3487/16029 -f 2949/3487/16030 2946/3490/16031 2953/3495/16032 -f 2955/3499/16033 2954/3500/16034 2957/3497/16035 -f 2957/3497/16036 2956/3498/16037 2955/3499/16038 -f 2958/3502/16039 2956/3498/16040 2957/3497/16041 -f 2957/3497/16042 2959/3501/16043 2958/3502/16044 -f 2960/3504/16045 2959/3501/16046 2957/3497/16047 -f 2957/3497/16048 2961/3503/16049 2960/3504/16050 -f 2963/3507/16051 2962/3508/16052 2965/3505/16053 -f 2965/3505/16054 2964/3506/16055 2963/3507/16056 -f 2930/3469/16057 2964/3506/16058 2965/3505/16059 -f 2965/3505/16060 2966/3509/16061 2930/3469/16062 -f 2968/3510/16063 2967/3511/16064 2965/3505/16065 -f 2965/3505/16066 2962/3508/16067 2968/3510/16068 -f 2970/3512/16069 2969/3513/16070 2965/3505/16071 -f 2965/3505/16072 2967/3511/16073 2970/3512/16074 -f 2973/3514/16075 2972/3515/16076 2971/3516/16077 -f 2975/3517/16078 2974/3518/16079 2973/3514/16080 -f 2973/3514/16081 2971/3516/16082 2975/3517/16083 -f 2977/3521/16084 2976/3522/16085 2979/3519/16086 -f 2979/3519/16087 2978/3520/16088 2977/3521/16089 -f 2981/3525/16090 2980/3526/16091 2983/3523/16092 -f 2983/3523/16093 2982/3524/16094 2981/3525/16095 -f 2946/3490/16096 2947/3489/16097 2982/3524/16098 -f 2982/3524/16099 2983/3523/16100 2946/3490/16101 -f 2985/3529/16102 2984/3530/16103 2987/3527/16104 -f 2987/3527/16105 2986/3528/16106 2985/3529/16107 -f 2988/3532/16108 2986/3528/16109 2987/3527/16110 -f 2987/3527/16111 2989/3531/16112 2988/3532/16113 -f 2991/3535/16114 2990/3536/16115 2993/3533/16116 -f 2993/3533/16117 2992/3534/16118 2991/3535/16119 -f 2995/3537/16120 2994/3538/16121 2993/3533/16122 -f 2993/3533/16123 2990/3536/16124 2995/3537/16125 -f 2996/3539/16126 2992/3534/16127 2993/3533/16128 -f 2993/3533/16129 2994/3538/16130 2996/3539/16131 -f 2998/3540/16132 2997/3541/16133 2995/3537/16134 -f 3000/3544/16135 2999/3545/16136 3002/3542/16137 -f 3002/3542/16138 3001/3543/16139 3000/3544/16140 -f 3001/3543/16141 3003/3546/16142 3000/3544/16143 -f 3005/3549/16144 3004/3550/16145 3007/3547/16146 -f 3007/3547/16147 3006/3548/16148 3005/3549/16149 -f 3008/3552/16150 3006/3548/16151 3007/3547/16152 -f 3007/3547/16153 3009/3551/16154 3008/3552/16155 -f 3010/3554/16156 3009/3551/16157 3007/3547/16158 -f 3007/3547/16159 3011/3553/16160 3010/3554/16161 -f 3013/3555/16162 3005/3549/16163 3012/3556/16164 -f 2760/3297/16165 3014/3558/16166 3015/3557/16167 -f 3015/3557/16168 2759/3298/16169 2760/3297/16170 -f 3016/3560/16171 2759/3298/16172 3015/3557/16173 -f 3015/3557/16174 3017/3559/16175 3016/3560/16176 -f 3019/3563/16177 3018/3564/16178 3021/3561/16179 -f 3021/3561/16180 3020/3562/16181 3019/3563/16182 -f 3022/3566/16183 3020/3562/16184 3021/3561/16185 -f 3021/3561/16186 3023/3565/16187 3022/3566/16188 -f 3019/3563/16189 3024/3568/16190 3025/3567/16191 -f 3025/3567/16192 3018/3564/16193 3019/3563/16194 -f 3024/3568/16195 3019/3563/16196 3027/3569/16197 -f 3027/3569/16198 3026/3570/16199 3024/3568/16200 -f 3024/3568/16201 3026/3570/16202 2832/3371/16203 -f 2832/3371/16204 2779/3318/16205 3024/3568/16206 -f 2833/3370/16207 2832/3371/16208 3026/3570/16209 -f 3026/3570/16210 3028/3571/16211 2833/3370/16212 -f 3028/3571/16213 3026/3570/16214 3027/3569/16215 -f 3027/3569/16216 3029/3572/16217 3028/3571/16218 -f 3030/3573/16219 2878/3416/16220 3028/3571/16221 -f 3028/3571/16222 3029/3572/16223 3030/3573/16224 -f 2859/3396/16225 2833/3370/16226 3028/3571/16227 -f 3028/3571/16228 2878/3416/16229 2859/3396/16230 -f 3032/3574/16231 3031/3575/16232 3030/3573/16233 -f 3030/3573/16234 3029/3572/16235 3032/3574/16236 -f 2931/3468/16237 2932/3470/16238 3030/3573/16239 -f 3030/3573/16240 3031/3575/16241 2931/3468/16242 -f 2874/3412/16243 2878/3416/16244 3030/3573/16245 -f 3030/3573/16246 2932/3470/16247 2874/3412/16248 -f 3034/3576/16249 3033/3577/16250 3031/3575/16251 -f 3031/3575/16252 3032/3574/16253 3034/3576/16254 -f 3035/3578/16255 2931/3468/16256 3031/3575/16257 -f 3031/3575/16258 3033/3577/16259 3035/3578/16260 -f 3037/3579/16261 3036/3580/16262 3035/3578/16263 -f 3035/3578/16264 3033/3577/16265 3037/3579/16266 -f 2963/3507/16267 2964/3506/16268 3035/3578/16269 -f 3035/3578/16270 3036/3580/16271 2963/3507/16272 -f 2930/3469/16273 2931/3468/16274 3035/3578/16275 -f 3035/3578/16276 2964/3506/16277 2930/3469/16278 -f 3039/3581/16279 3038/3582/16280 3036/3580/16281 -f 3036/3580/16282 3037/3579/16283 3039/3581/16284 -f 3040/3583/16285 2963/3507/16286 3036/3580/16287 -f 3036/3580/16288 3038/3582/16289 3040/3583/16290 -f 2920/3584/16291 3041/3585/16292 3040/3583/16293 -f 3040/3583/16294 3038/3582/16295 2920/3584/16296 -f 2944/3486/16297 2945/3485/16298 3040/3583/16299 -f 3040/3583/16300 3041/3585/16301 2944/3486/16302 -f 2962/3508/16303 2963/3507/16304 3040/3583/16305 -f 3040/3583/16306 2945/3485/16307 2962/3508/16308 -f 2917/3456/16309 2925/3463/16310 3041/3586/16311 -f 3041/3586/16312 2920/3457/16313 2917/3456/16314 -f 2939/3478/16315 2944/3484/16316 3041/3586/16317 -f 3041/3586/16318 2925/3463/16319 2939/3478/16320 -f 2919/3587/16321 2920/3584/16322 3038/3582/16323 -f 3038/3582/16324 3039/3581/16325 2919/3587/16326 -f 3043/3588/16327 3042/3589/16328 3039/3581/16329 -f 3039/3581/16330 3037/3579/16331 3043/3588/16332 -f 2922/3590/16333 2919/3587/16334 3039/3581/16335 -f 3039/3581/16336 3042/3589/16337 2922/3590/16338 -f 3042/3589/16339 3043/3588/16340 3045/3591/16341 -f 3045/3591/16342 3044/3592/16343 3042/3589/16344 -f 3042/3589/16345 3044/3592/16346 3046/3593/16347 -f 3046/3593/16348 2922/3590/16349 3042/3589/16350 -f 3046/3594/16351 3047/3595/16352 2921/3459/16353 -f 2921/3459/16354 2922/3460/16355 3046/3594/16356 -f 3047/3595/16357 2864/3401/16358 2863/3402/16359 -f 2863/3402/16360 2921/3459/16361 3047/3595/16362 -f 3047/3595/16363 3046/3594/16364 3049/3596/16365 -f 3049/3596/16366 3048/3597/16367 3047/3595/16368 -f 3047/3595/16369 3048/3597/16370 2865/3403/16371 -f 2865/3403/16372 2864/3401/16373 3047/3595/16374 -f 3051/3598/16375 3050/3599/16376 2831/3367/16377 -f 2831/3367/16378 2865/3403/16379 3051/3598/16380 -f 3052/3600/16381 2830/3368/16382 2831/3367/16383 -f 2831/3367/16384 3050/3599/16385 3052/3600/16386 -f 3053/3602/16387 2830/3368/16388 3052/3600/16389 -f 3052/3600/16390 3054/3601/16391 3053/3602/16392 -f 3056/3605/16393 3055/3606/16394 3058/3603/16395 -f 3058/3603/16396 3057/3604/16397 3056/3605/16398 -f 3060/3607/16399 3059/3608/16400 3058/3603/16401 -f 3058/3603/16402 3055/3606/16403 3060/3607/16404 -f 3061/3610/16405 3059/3608/16406 3060/3607/16407 -f 3060/3607/16408 3062/3609/16409 3061/3610/16410 -f 3060/3607/16411 3055/3606/16412 3064/3611/16413 -f 3064/3611/16414 3063/3612/16415 3060/3607/16416 -f 3055/3606/16417 3056/3605/16418 3065/3613/16419 -f 3065/3613/16420 3064/3611/16421 3055/3606/16422 -f 3056/3605/16423 2780/3317/16424 2771/3306/16425 -f 3063/3612/16426 3066/3614/16427 3062/3609/16428 -f 3062/3609/16429 3060/3607/16430 3063/3612/16431 -f 3067/3617/16432 3063/3612/16433 3069/3615/16434 -f 3069/3615/16435 3068/3616/16436 3067/3617/16437 -f 3070/3619/16438 3068/3616/16439 3069/3615/16440 -f 3069/3615/16441 3071/3618/16442 3070/3619/16443 -f 3073/3620/16444 3072/3621/16445 3067/3617/16446 -f 3067/3617/16447 2741/3280/16448 3073/3620/16449 -f 3066/3614/16450 3063/3612/16451 3067/3617/16452 -f 3067/3617/16453 3072/3621/16454 3066/3614/16455 -f 2740/3281/16456 2741/3280/16457 3067/3617/16458 -f 3067/3617/16459 3068/3616/16460 2740/3281/16461 -f 3075/3624/16462 3074/3625/16463 3072/3622/16464 -f 3072/3622/16465 3073/3623/16466 3075/3624/16467 -f 3076/3626/16468 3066/3627/16469 3072/3622/16470 -f 3072/3622/16471 3074/3625/16472 3076/3626/16473 -f 2751/3292/16474 2752/3291/16475 3076/3626/16476 -f 3076/3626/16477 3074/3625/16478 2751/3292/16479 -f 3076/3626/16480 2752/3291/16481 2759/3298/16482 -f 2759/3298/16483 3016/3560/16484 3076/3626/16485 -f 3076/3626/16486 3016/3560/16487 3062/3628/16488 -f 3062/3628/16489 3066/3627/16490 3076/3626/16491 -f 3078/3629/16492 3077/3630/16493 2760/3297/16494 -f 2760/3297/16495 2757/3296/16496 3078/3629/16497 -f 3077/3630/16498 3078/3629/16499 3079/3631/16500 -f 3079/3631/16501 3053/3602/16502 3077/3630/16503 -f 3054/3601/16504 3080/3632/16505 3077/3630/16506 -f 3077/3630/16507 3053/3602/16508 3054/3601/16509 -f 3014/3558/16510 2760/3297/16511 3077/3630/16512 -f 3077/3630/16513 3080/3632/16514 3014/3558/16515 -f 3079/3631/16516 2828/3363/16517 2830/3368/16518 -f 2830/3368/16519 3053/3602/16520 3079/3631/16521 -f 2778/3316/16522 3081/3633/16523 3079/3631/16524 -f 3079/3631/16525 3078/3629/16526 2778/3316/16527 -f 2827/3364/16528 2828/3363/16529 3079/3631/16530 -f 3079/3631/16531 3081/3633/16532 2827/3364/16533 -f 2765/3303/16534 2810/3350/16535 3081/3633/16536 -f 3081/3633/16537 2778/3316/16538 2765/3303/16539 -f 2811/3349/16540 2827/3364/16541 3081/3633/16542 -f 3081/3633/16543 2810/3350/16544 2811/3349/16545 -f 2758/3295/16546 2778/3316/16547 3078/3629/16548 -f 3078/3629/16549 2757/3296/16550 2758/3295/16551 -f 2756/3294/16552 2751/3292/16553 3074/3625/16554 -f 3074/3625/16555 3075/3624/16556 2756/3294/16557 -f 3082/3635/16558 2756/3294/16559 3075/3624/16560 -f 3075/3624/16561 3083/3634/16562 3082/3635/16563 -f 3084/3636/16564 3083/3634/16565 3075/3624/16566 -f 3075/3624/16567 3073/3623/16568 3084/3636/16569 -f 3084/3636/16570 3085/3637/16571 3083/3634/16572 -f 3084/3638/16573 3073/3620/16574 2741/3280/16575 -f 3082/3635/16576 3083/3634/16577 3085/3637/16578 -f 3085/3637/16579 2744/3285/16580 3082/3635/16581 -f 3086/3639/16582 2750/3288/16583 3085/3637/16584 -f 3085/3637/16585 3084/3636/16586 3086/3639/16587 -f 3087/3641/16588 2750/3288/16589 3086/3639/16590 -f 3086/3639/16591 3088/3640/16592 3087/3641/16593 -f 2742/3279/16594 3089/3643/16595 3086/3642/16596 -f 3086/3642/16597 3084/3638/16598 2742/3279/16599 -f 3090/3644/16600 3088/3645/16601 3086/3642/16602 -f 3086/3642/16603 3089/3643/16604 3090/3644/16605 -f 3090/3644/16606 3091/3646/16607 3088/3645/16608 -f 3093/3647/16609 3092/3648/16610 3090/3644/16611 -f 3090/3644/16612 3089/3643/16613 3093/3647/16614 -f 3094/3649/16615 3091/3646/16616 3090/3644/16617 -f 3090/3644/16618 3092/3648/16619 3094/3649/16620 -f 3096/3650/16621 3095/3651/16622 3094/3649/16623 -f 3094/3649/16624 3092/3648/16625 3096/3650/16626 -f 3097/3652/16627 2728/3266/16628 3094/3649/16629 -f 3094/3649/16630 3095/3651/16631 3097/3652/16632 -f 2723/3260/16633 2728/3266/16634 3097/3652/16635 -f 3097/3652/16636 2724/3261/16637 2723/3260/16638 -f 3099/3653/16639 3098/3654/16640 3097/3652/16641 -f 3097/3652/16642 3095/3651/16643 3099/3653/16644 -f 2722/3258/16645 2724/3261/16646 3097/3652/16647 -f 3097/3652/16648 3098/3654/16649 2722/3258/16650 -f 3101/3655/16651 3100/3656/16652 3098/3654/16653 -f 3098/3654/16654 3099/3653/16655 3101/3655/16656 -f 2716/3252/16657 2722/3258/16658 3098/3654/16659 -f 3098/3654/16660 3100/3656/16661 2716/3252/16662 -f 2725/3264/16663 2726/3263/16664 3100/3656/16665 -f 3100/3656/16666 3101/3655/16667 2725/3264/16668 -f 2715/3253/16669 2716/3252/16670 3100/3656/16671 -f 3100/3656/16672 2726/3263/16673 2715/3253/16674 -f 3103/3657/16675 3102/3658/16676 3101/3655/16677 -f 3101/3655/16678 3099/3653/16679 3103/3657/16680 -f 3104/3659/16681 2725/3264/16682 3101/3655/16683 -f 3101/3655/16684 3102/3658/16685 3104/3659/16686 -f 3106/3660/16687 3105/3661/16688 3104/3659/16689 -f 3104/3659/16690 3102/3658/16691 3106/3660/16692 -f 3104/3659/16693 2727/3262/16694 2725/3264/16695 -f 3107/3664/16696 2739/3277/16697 3109/3662/16698 -f 3109/3662/16699 3108/3663/16700 3107/3664/16701 -f 3109/3662/16702 3110/3666/16703 3111/3665/16704 -f 3111/3665/16705 3108/3663/16706 3109/3662/16707 -f 3109/3662/16708 3112/3668/16709 3113/3667/16710 -f 3113/3667/16711 3110/3666/16712 3109/3662/16713 -f 2734/3275/16714 3114/3669/16715 3112/3668/16716 -f 3112/3668/16717 2739/3277/16718 2734/3275/16719 -f 3114/3669/16720 3115/3670/16721 3113/3667/16722 -f 3113/3667/16723 3112/3668/16724 3114/3669/16725 -f 2749/3286/16726 3116/3671/16727 3114/3669/16728 -f 3114/3669/16729 2734/3275/16730 2749/3286/16731 -f 3116/3671/16732 3117/3672/16733 3115/3670/16734 -f 3115/3670/16735 3114/3669/16736 3116/3671/16737 -f 3118/3674/16738 3115/3670/16739 3117/3672/16740 -f 3117/3672/16741 2729/3673/16742 3118/3674/16743 -f 3116/3671/16744 3087/3641/16745 3091/3675/16746 -f 3091/3675/16747 3117/3672/16748 3116/3671/16749 -f 3116/3671/16750 2749/3286/16751 2750/3288/16752 -f 2750/3288/16753 3087/3641/16754 3116/3671/16755 -f 2733/3268/16756 2739/3277/16757 3107/3664/16758 -f 3107/3664/16759 2732/3269/16760 2733/3268/16761 -f 3106/3660/16762 3119/3677/16763 3120/3676/16764 -f 3120/3676/16765 3105/3661/16766 3106/3660/16767 -f 2730/3271/16768 2731/3270/16769 3120/3676/16770 -f 3120/3676/16771 3119/3677/16772 2730/3271/16773 -f 3122/3678/16774 3121/3679/16775 2730/3271/16776 -f 2730/3271/16777 3119/3677/16778 3122/3678/16779 -f 2738/3276/16780 2730/3271/16781 3121/3679/16782 -f 3121/3679/16783 3123/3680/16784 2738/3276/16785 -f 3124/3682/16786 2736/3273/16787 2738/3276/16788 -f 2738/3276/16789 3125/3681/16790 3124/3682/16791 -f 3126/3683/16792 3125/3681/16793 2738/3276/16794 -f 2738/3276/16795 3123/3680/16796 3126/3683/16797 -f 3127/3684/16798 3125/3681/16799 3126/3683/16800 -f 3126/3683/16801 2786/3323/16802 3127/3684/16803 -f 3129/3685/16804 3128/3686/16805 3126/3683/16806 -f 3126/3683/16807 3123/3680/16808 3129/3685/16809 -f 2785/3324/16810 2786/3323/16811 3126/3683/16812 -f 3126/3683/16813 3128/3686/16814 2785/3324/16815 -f 3129/3685/16816 3130/3688/16817 3131/3687/16818 -f 3131/3687/16819 3128/3686/16820 3129/3685/16821 -f 2799/3337/16822 2785/3324/16823 3128/3686/16824 -f 3128/3686/16825 3131/3687/16826 2799/3337/16827 -f 3132/3689/16828 2776/3315/16829 3131/3687/16830 -f 3131/3687/16831 3130/3688/16832 3132/3689/16833 -f 2776/3315/16834 2777/3314/16835 2799/3337/16836 -f 2799/3337/16837 3131/3687/16838 2776/3315/16839 -f 3121/3679/16840 3133/3690/16841 3129/3685/16842 -f 3129/3685/16843 3123/3680/16844 3121/3679/16845 -f 3133/3690/16846 3134/3691/16847 3130/3688/16848 -f 3130/3688/16849 3129/3685/16850 3133/3690/16851 -f 3122/3678/16852 3135/3692/16853 3133/3690/16854 -f 3133/3690/16855 3121/3679/16856 3122/3678/16857 -f 3135/3692/16858 3136/3693/16859 3134/3691/16860 -f 3134/3691/16861 3133/3690/16862 3135/3692/16863 -f 3137/3694/16864 3093/3647/16865 3136/3693/16866 -f 3136/3693/16867 3135/3692/16868 3137/3694/16869 -f 3138/3695/16870 3137/3694/16871 3135/3692/16872 -f 3135/3692/16873 3122/3678/16874 3138/3695/16875 -f 3096/3650/16876 3137/3694/16877 3138/3695/16878 -f 3138/3695/16879 3103/3657/16880 3096/3650/16881 -f 3119/3677/16882 3106/3660/16883 3138/3695/16884 -f 3138/3695/16885 3122/3678/16886 3119/3677/16887 -f 3102/3658/16888 3103/3657/16889 3138/3695/16890 -f 3138/3695/16891 3106/3660/16892 3102/3658/16893 -f 3092/3648/16894 3093/3647/16895 3137/3694/16896 -f 3137/3694/16897 3096/3650/16898 3092/3648/16899 -f 3140/3697/16900 3139/3698/16901 3127/3684/16902 -f 3127/3684/16903 3141/3696/16904 3140/3697/16905 -f 3124/3682/16906 3125/3681/16907 3127/3684/16908 -f 3127/3684/16909 3139/3698/16910 3124/3682/16911 -f 2787/3328/16912 2788/3327/16913 3139/3698/16914 -f 3139/3698/16915 3140/3697/16916 2787/3328/16917 -f 3142/3699/16918 3124/3682/16919 3139/3698/16920 -f 3139/3698/16921 2788/3327/16922 3142/3699/16923 -f 2789/3326/16924 2792/3332/16925 3142/3699/16926 -f 3142/3699/16927 2788/3327/16928 2789/3326/16929 -f 3144/3700/16930 3143/3701/16931 3142/3699/16932 -f 3142/3699/16933 2792/3332/16934 3144/3700/16935 -f 2736/3273/16936 3124/3682/16937 3142/3699/16938 -f 3142/3699/16939 3143/3701/16940 2736/3273/16941 -f 2748/3287/16942 2735/3274/16943 3143/3701/16944 -f 3143/3701/16945 3144/3700/16946 2748/3287/16947 -f 3143/3701/16948 2735/3274/16949 2736/3273/16950 -f 2793/3331/16951 3145/3702/16952 3144/3700/16953 -f 3144/3700/16954 2792/3332/16955 2793/3331/16956 -f 2746/3283/16957 2748/3287/16958 3144/3700/16959 -f 3144/3700/16960 3145/3702/16961 2746/3283/16962 -f 2764/3304/16963 2763/3299/16964 3145/3702/16965 -f 3145/3702/16966 2793/3331/16967 2764/3304/16968 -f 2745/3284/16969 2746/3283/16970 3145/3702/16971 -f 3145/3702/16972 2763/3299/16973 2745/3284/16974 -f 2787/3328/16975 3146/3704/16976 3147/3703/16977 -f 3147/3703/16978 2790/3325/16979 2787/3328/16980 -f 3148/3705/16981 3146/3704/16982 2787/3328/16983 -f 2787/3328/16984 3140/3697/16985 3148/3705/16986 -f 2898/3439/16987 3146/3704/16988 3148/3705/16989 -f 3148/3705/16990 2901/3436/16991 2898/3439/16992 -f 3141/3696/16993 3149/3706/16994 3148/3705/16995 -f 3148/3705/16996 3140/3697/16997 3141/3696/16998 -f 2904/3440/16999 2901/3436/17000 3148/3705/17001 -f 3148/3705/17002 3149/3706/17003 2904/3440/17004 -f 3151/3707/17005 3150/3708/17006 3149/3706/17007 -f 3149/3706/17008 3141/3696/17009 3151/3707/17010 -f 3152/3709/17011 2904/3440/17012 3149/3706/17013 -f 3149/3706/17014 3150/3708/17015 3152/3709/17016 -f 2903/3441/17017 2904/3440/17018 3152/3709/17019 -f 3152/3709/17020 2951/3493/17021 2903/3441/17022 -f 2911/3448/17023 2912/3450/17024 3152/3709/17025 -f 3152/3709/17026 3150/3708/17027 2911/3448/17028 -f 2950/3494/17029 2951/3493/17030 3152/3709/17031 -f 3152/3709/17032 2912/3450/17033 2950/3494/17034 -f 2781/3322/17035 2911/3448/17036 3150/3708/17037 -f 3150/3708/17038 3151/3707/17039 2781/3322/17040 -f 2898/3439/17041 3153/3710/17042 3147/3703/17043 -f 3147/3703/17044 3146/3704/17045 2898/3439/17046 -f 3155/3711/17047 3154/3712/17048 3147/3703/17049 -f 3147/3703/17050 3153/3710/17051 3155/3711/17052 -f 3156/3713/17053 2790/3325/17054 3147/3703/17055 -f 3147/3703/17056 3154/3712/17057 3156/3713/17058 -f 2791/3329/17059 2790/3325/17060 3156/3713/17061 -f 3156/3713/17062 3157/3714/17063 2791/3329/17064 -f 2795/3333/17065 2791/3329/17066 3157/3714/17067 -f 3157/3714/17068 2817/3353/17069 2795/3333/17070 -f 3159/3717/17071 3158/3718/17072 3161/3715/17073 -f 3161/3715/17074 3160/3716/17075 3159/3717/17076 -f 2815/3355/17077 2816/3354/17078 3161/3715/17079 -f 3161/3715/17080 3158/3718/17081 2815/3355/17082 -f 3163/3719/17083 3162/3720/17084 3158/3718/17085 -f 3158/3718/17086 3159/3717/17087 3163/3719/17088 -f 2818/3356/17089 2815/3355/17090 3158/3718/17091 -f 3158/3718/17092 3162/3720/17093 2818/3356/17094 -f 3162/3720/17095 3163/3719/17096 2851/3390/17097 -f 2851/3390/17098 2837/3377/17099 3162/3720/17100 -f 3162/3720/17101 2837/3377/17102 2838/3376/17103 -f 2838/3376/17104 2818/3356/17105 3162/3720/17106 -f 2838/3376/17107 2820/3359/17108 2814/3351/17109 -f 2814/3351/17110 2818/3356/17111 2838/3376/17112 -f 2821/3358/17113 2813/3352/17114 2814/3351/17115 -f 2814/3351/17116 2820/3359/17117 2821/3358/17118 -f 2766/3302/17119 2764/3304/17120 2813/3352/17121 -f 2813/3352/17122 2821/3358/17123 2766/3302/17124 -f 3165/3721/17125 3164/3722/17126 3159/3717/17127 -f 3159/3717/17128 3160/3716/17129 3165/3721/17130 -f 2850/3391/17131 3163/3719/17132 3159/3717/17133 -f 3159/3717/17134 3164/3722/17135 2850/3391/17136 -f 3166/3723/17137 3164/3722/17138 3165/3721/17139 -f 2879/3418/17140 2850/3391/17141 3164/3722/17142 -f 3164/3722/17143 3166/3723/17144 2879/3418/17145 -f 3168/3724/17146 3167/3725/17147 2879/3418/17148 -f 2879/3418/17149 3166/3723/17150 3168/3724/17151 -f 2879/3418/17152 3167/3725/17153 2899/3438/17154 -f 2899/3438/17155 2880/3417/17156 2879/3418/17157 -f 3153/3710/17158 2898/3439/17159 2899/3438/17160 -f 2899/3438/17161 3167/3725/17162 3153/3710/17163 -f 3155/3711/17164 3153/3710/17165 3167/3725/17166 -f 3167/3725/17167 3168/3724/17168 3155/3711/17169 -f 3095/3651/17170 3096/3650/17171 3103/3657/17172 -f 3103/3657/17173 3099/3653/17174 3095/3651/17175 -f 2742/3279/17176 3136/3693/17177 3093/3647/17178 -f 3093/3647/17179 3089/3643/17180 2742/3279/17181 -f 3087/3641/17182 3088/3640/17183 3091/3675/17184 -f 2745/3284/17185 2761/3301/17186 3082/3635/17187 -f 3082/3635/17188 2744/3285/17189 2745/3284/17190 -f 2754/3289/17191 2756/3294/17192 3082/3635/17193 -f 3082/3635/17194 2761/3301/17195 2754/3289/17196 -f 3016/3560/17197 3017/3559/17198 3061/3726/17199 -f 3061/3726/17200 3062/3628/17201 3016/3560/17202 -f 3169/3727/17203 2780/3317/17204 3056/3605/17205 -f 3056/3605/17206 3057/3604/17207 3169/3727/17208 -f 3048/3597/17209 3170/3728/17210 3051/3598/17211 -f 3051/3598/17212 2865/3403/17213 3048/3597/17214 -f 3171/3729/17215 3170/3728/17216 3048/3597/17217 -f 3048/3597/17218 3049/3596/17219 3171/3729/17220 -f 3172/3732/17221 3171/3733/17222 3049/3730/17223 -f 3049/3730/17224 3173/3731/17225 3172/3732/17226 -f 3049/3730/17227 3046/3593/17228 3044/3592/17229 -f 3044/3592/17230 3173/3731/17231 3049/3730/17232 -f 3044/3592/17233 3045/3591/17234 3174/3734/17235 -f 3174/3734/17236 3173/3731/17237 3044/3592/17238 -f 3045/3591/17239 3175/3735/17240 3022/3566/17241 -f 3022/3566/17242 3174/3734/17243 3045/3591/17244 -f 3175/3735/17245 3176/3736/17246 3020/3562/17247 -f 3020/3562/17248 3022/3566/17249 3175/3735/17250 -f 3175/3735/17251 3045/3591/17252 3043/3588/17253 -f 3043/3588/17254 3034/3576/17255 3175/3735/17256 -f 3175/3735/17257 3034/3576/17258 3032/3574/17259 -f 3032/3574/17260 3176/3736/17261 3175/3735/17262 -f 3032/3574/17263 3029/3572/17264 3027/3569/17265 -f 3027/3569/17266 3176/3736/17267 3032/3574/17268 -f 3027/3569/17269 3019/3563/17270 3020/3562/17271 -f 3020/3562/17272 3176/3736/17273 3027/3569/17274 -f 3023/3565/17275 3177/3737/17276 3174/3734/17277 -f 3174/3734/17278 3022/3566/17279 3023/3565/17280 -f 3172/3732/17281 3173/3731/17282 3174/3734/17283 -f 3174/3734/17284 3177/3737/17285 3172/3732/17286 -f 3033/3577/17287 3034/3576/17288 3043/3588/17289 -f 3043/3588/17290 3037/3579/17291 3033/3577/17292 -f 3004/3550/17293 3179/3738/17294 3178/3739/17295 -f 3182/3740/17296 3181/3741/17297 3180/3742/17298 -f 3179/3738/17299 3183/3743/17300 3180/3742/17301 -f 3180/3742/17302 3178/3739/17303 3179/3738/17304 -f 3180/3742/17305 3183/3743/17306 3182/3740/17307 -f 3185/3744/17308 3184/3745/17309 3181/3741/17310 -f 3181/3741/17311 3182/3740/17312 3185/3744/17313 -f 3181/3741/17314 3184/3745/17315 3186/3746/17316 -f 3187/3747/17317 3003/3546/17318 3186/3746/17319 -f 3186/3746/17320 3184/3745/17321 3187/3747/17322 -f 3001/3543/17323 3011/3553/17324 3186/3746/17325 -f 3186/3746/17326 3003/3546/17327 3001/3543/17328 -f 3189/3749/17329 3188/3750/17330 3187/3747/17331 -f 3187/3747/17332 3190/3748/17333 3189/3749/17334 -f 3000/3544/17335 3003/3546/17336 3187/3747/17337 -f 3187/3747/17338 3188/3750/17339 3000/3544/17340 -f 3191/3751/17341 3190/3748/17342 3187/3747/17343 -f 3187/3747/17344 3184/3745/17345 3191/3751/17346 -f 3193/3752/17347 3192/3753/17348 3188/3750/17349 -f 3188/3750/17350 3189/3749/17351 3193/3752/17352 -f 2999/3545/17353 3000/3544/17354 3188/3750/17355 -f 3188/3750/17356 3192/3753/17357 2999/3545/17358 -f 3195/3754/17359 3194/3755/17360 3192/3753/17361 -f 3192/3753/17362 3193/3752/17363 3195/3754/17364 -f 3196/3756/17365 2999/3545/17366 3192/3753/17367 -f 3192/3753/17368 3194/3755/17369 3196/3756/17370 -f 3196/3756/17371 3194/3755/17372 3198/3757/17373 -f 3198/3757/17374 3197/3758/17375 3196/3756/17376 -f 3196/3756/17377 3197/3758/17378 3200/3759/17379 -f 3200/3759/17380 3199/3760/17381 3196/3756/17382 -f 3196/3756/17383 3199/3760/17384 3002/3542/17385 -f 3002/3542/17386 2999/3545/17387 3196/3756/17388 -f 3199/3760/17389 3200/3759/17390 3202/3761/17391 -f 3202/3761/17392 3201/3762/17393 3199/3760/17394 -f 3010/3554/17395 3002/3542/17396 3199/3760/17397 -f 3199/3760/17398 3201/3762/17399 3010/3554/17400 -f 3201/3762/17401 3202/3761/17402 3204/3763/17403 -f 3204/3763/17404 3203/3764/17405 3201/3762/17406 -f 3009/3551/17407 3010/3554/17408 3201/3762/17409 -f 3201/3762/17410 3203/3764/17411 3009/3551/17412 -f 3203/3764/17413 3204/3763/17414 3206/3765/17415 -f 3206/3765/17416 3205/3766/17417 3203/3764/17418 -f 3008/3552/17419 3009/3551/17420 3203/3764/17421 -f 3203/3764/17422 3205/3766/17423 3008/3552/17424 -f 3205/3766/17425 3206/3765/17426 3208/3767/17427 -f 3208/3767/17428 3207/3768/17429 3205/3766/17430 -f 3209/3769/17431 3008/3552/17432 3205/3766/17433 -f 3205/3766/17434 3207/3768/17435 3209/3769/17436 -f 3211/3770/17437 3210/3771/17438 3209/3769/17439 -f 3209/3769/17440 3207/3768/17441 3211/3770/17442 -f 3213/3772/17443 3212/3773/17444 3209/3769/17445 -f 3209/3769/17446 3210/3771/17447 3213/3772/17448 -f 3006/3548/17449 3008/3552/17450 3209/3769/17451 -f 3209/3769/17452 3212/3773/17453 3006/3548/17454 -f 3214/3774/17455 3012/3556/17456 3212/3773/17457 -f 3212/3773/17458 3213/3772/17459 3214/3774/17460 -f 3005/3549/17461 3006/3548/17462 3212/3773/17463 -f 3212/3773/17464 3012/3556/17465 3005/3549/17466 -f 3216/3775/17467 3215/3776/17468 3213/3772/17469 -f 3213/3772/17470 3210/3771/17471 3216/3775/17472 -f 3213/3772/17473 3215/3776/17474 3214/3774/17475 -f 3218/3777/17476 3217/3778/17477 3214/3774/17478 -f 3214/3774/17479 3215/3776/17480 3218/3777/17481 -f 3216/3775/17482 3219/3779/17483 3218/3777/17484 -f 3218/3777/17485 3215/3776/17486 3216/3775/17487 -f 3220/3780/17488 2996/3539/17489 3218/3777/17490 -f 3218/3777/17491 3219/3779/17492 3220/3780/17493 -f 2994/3538/17494 3217/3778/17495 3218/3777/17496 -f 3218/3777/17497 2996/3539/17498 2994/3538/17499 -f 3222/3781/17500 3221/3782/17501 3220/3780/17502 -f 3220/3780/17503 3219/3779/17504 3222/3781/17505 -f 3224/3783/17506 3223/3784/17507 3220/3780/17508 -f 3220/3780/17509 3221/3782/17510 3224/3783/17511 -f 2992/3534/17512 2996/3539/17513 3220/3780/17514 -f 3220/3780/17515 3223/3784/17516 2992/3534/17517 -f 3226/3785/17518 3225/3786/17519 3223/3784/17520 -f 3223/3784/17521 3224/3783/17522 3226/3785/17523 -f 2991/3535/17524 2992/3534/17525 3223/3784/17526 -f 3223/3784/17527 3225/3786/17528 2991/3535/17529 -f 3228/3787/17530 3227/3788/17531 3225/3786/17532 -f 3225/3786/17533 3226/3785/17534 3228/3787/17535 -f 3229/3789/17536 2991/3535/17537 3225/3786/17538 -f 3225/3786/17539 3227/3788/17540 3229/3789/17541 -f 3193/3790/17542 3189/3791/17543 3229/3789/17544 -f 3229/3789/17545 3227/3788/17546 3193/3790/17547 -f 3190/3792/17548 3230/3793/17549 3229/3789/17550 -f 3229/3789/17551 3189/3791/17552 3190/3792/17553 -f 2990/3536/17554 2991/3535/17555 3229/3789/17556 -f 3229/3789/17557 3230/3793/17558 2990/3536/17559 -f 3191/3794/17560 2998/3540/17561 3230/3793/17562 -f 3230/3793/17563 3190/3792/17564 3191/3794/17565 -f 2995/3537/17566 2990/3536/17567 3230/3793/17568 -f 3230/3793/17569 2998/3540/17570 2995/3537/17571 -f 3195/3795/17572 3193/3790/17573 3227/3788/17574 -f 3227/3788/17575 3228/3787/17576 3195/3795/17577 -f 3228/3787/17578 3226/3785/17579 3232/3796/17580 -f 3232/3796/17581 3231/3797/17582 3228/3787/17583 -f 3228/3787/17584 3231/3797/17585 3233/3798/17586 -f 3233/3798/17587 3195/3795/17588 3228/3787/17589 -f 3233/3799/17590 3198/3757/17591 3194/3755/17592 -f 3194/3755/17593 3195/3754/17594 3233/3799/17595 -f 3235/3800/17596 3234/3801/17597 3198/3757/17598 -f 3198/3757/17599 3233/3799/17600 3235/3800/17601 -f 3236/3802/17602 3197/3758/17603 3198/3757/17604 -f 3198/3757/17605 3234/3801/17606 3236/3802/17607 -f 3236/3802/17608 3237/3803/17609 3200/3759/17610 -f 3200/3759/17611 3197/3758/17612 3236/3802/17613 -f 3238/3804/17614 3202/3761/17615 3200/3759/17616 -f 3200/3759/17617 3237/3803/17618 3238/3804/17619 -f 3239/3805/17620 3204/3763/17621 3202/3761/17622 -f 3202/3761/17623 3238/3804/17624 3239/3805/17625 -f 3240/3806/17626 3206/3765/17627 3204/3763/17628 -f 3204/3763/17629 3239/3805/17630 3240/3806/17631 -f 3241/3807/17632 3208/3767/17633 3206/3765/17634 -f 3206/3765/17635 3240/3806/17636 3241/3807/17637 -f 3243/3808/17638 3242/3809/17639 3208/3767/17640 -f 3208/3767/17641 3241/3807/17642 3243/3808/17643 -f 3208/3767/17644 3242/3809/17645 3211/3770/17646 -f 3211/3770/17647 3207/3768/17648 3208/3767/17649 -f 3245/3810/17650 3244/3811/17651 3211/3770/17652 -f 3211/3770/17653 3242/3809/17654 3245/3810/17655 -f 3244/3811/17656 3245/3810/17657 3246/3812/17658 -f 3246/3812/17659 3222/3781/17660 3244/3811/17661 -f 3219/3779/17662 3216/3775/17663 3244/3811/17664 -f 3244/3811/17665 3222/3781/17666 3219/3779/17667 -f 3210/3771/17668 3211/3770/17669 3244/3811/17670 -f 3244/3811/17671 3216/3775/17672 3210/3771/17673 -f 3246/3812/17674 3247/3813/17675 3221/3782/17676 -f 3221/3782/17677 3222/3781/17678 3246/3812/17679 -f 3248/3814/17680 3224/3783/17681 3221/3782/17682 -f 3221/3782/17683 3247/3813/17684 3248/3814/17685 -f 3232/3796/17686 3226/3785/17687 3224/3783/17688 -f 3224/3783/17689 3248/3814/17690 3232/3796/17691 -f 3250/3815/17692 3249/3816/17693 3232/3796/17694 -f 3232/3796/17695 3248/3814/17696 3250/3815/17697 -f 3251/3817/17698 3231/3797/17699 3232/3796/17700 -f 3232/3796/17701 3249/3816/17702 3251/3817/17703 -f 3252/3820/17704 2969/3513/17705 3251/3818/17706 -f 3251/3818/17707 3249/3819/17708 3252/3820/17709 -f 2970/3512/17710 3235/3821/17711 3251/3818/17712 -f 3251/3818/17713 2969/3513/17714 2970/3512/17715 -f 3233/3798/17716 3231/3797/17717 3251/3817/17718 -f 3251/3817/17719 3235/3822/17720 3233/3798/17721 -f 3253/3824/17722 2966/3509/17723 3252/3820/17724 -f 3252/3820/17725 3254/3823/17726 3253/3824/17727 -f 2965/3505/17728 2969/3513/17729 3252/3820/17730 -f 3252/3820/17731 2966/3509/17732 2965/3505/17733 -f 3250/3825/17734 3254/3823/17735 3252/3820/17736 -f 3252/3820/17737 3249/3819/17738 3250/3825/17739 -f 2927/3466/17740 2928/3465/17741 3253/3824/17742 -f 3253/3824/17743 3255/3826/17744 2927/3466/17745 -f 2930/3469/17746 2966/3509/17747 3253/3824/17748 -f 3253/3824/17749 2928/3465/17750 2930/3469/17751 -f 3256/3827/17752 3255/3826/17753 3253/3824/17754 -f 3253/3824/17755 3254/3823/17756 3256/3827/17757 -f 3257/3829/17758 3255/3826/17759 3256/3827/17760 -f 3256/3827/17761 3258/3828/17762 3257/3829/17763 -f 3250/3825/17764 3259/3830/17765 3256/3827/17766 -f 3256/3827/17767 3254/3823/17768 3250/3825/17769 -f 3260/3831/17770 3258/3828/17771 3256/3827/17772 -f 3256/3827/17773 3259/3830/17774 3260/3831/17775 -f 3261/3833/17776 3258/3828/17777 3260/3831/17778 -f 3260/3831/17779 3262/3832/17780 3261/3833/17781 -f 3247/3813/17782 3246/3812/17783 3260/3834/17784 -f 3260/3834/17785 3259/3835/17786 3247/3813/17787 -f 3245/3810/17788 3262/3836/17789 3260/3834/17790 -f 3260/3834/17791 3246/3812/17792 3245/3810/17793 -f 3264/3838/17794 3263/3839/17795 3261/3833/17796 -f 3261/3833/17797 3265/3837/17798 3264/3838/17799 -f 3257/3829/17800 3258/3828/17801 3261/3833/17802 -f 3261/3833/17803 3263/3839/17804 3257/3829/17805 -f 3243/3840/17806 3265/3837/17807 3261/3833/17808 -f 3261/3833/17809 3262/3832/17810 3243/3840/17811 -f 2907/3446/17812 3266/3841/17813 3263/3839/17814 -f 3263/3839/17815 3264/3838/17816 2907/3446/17817 -f 3267/3842/17818 3257/3829/17819 3263/3839/17820 -f 3263/3839/17821 3266/3841/17822 3267/3842/17823 -f 3269/3843/17824 3268/3844/17825 3267/3842/17826 -f 3267/3842/17827 3266/3841/17828 3269/3843/17829 -f 2926/3467/17830 2927/3466/17831 3267/3842/17832 -f 3267/3842/17833 3268/3844/17834 2926/3467/17835 -f 3255/3826/17836 3257/3829/17837 3267/3842/17838 -f 3267/3842/17839 2927/3466/17840 3255/3826/17841 -f 3271/3845/17842 3270/3846/17843 3268/3844/17844 -f 3268/3844/17845 3269/3843/17846 3271/3845/17847 -f 2897/3434/17848 2926/3467/17849 3268/3844/17850 -f 3268/3844/17851 3270/3846/17852 2897/3434/17853 -f 3273/3847/17854 3272/3848/17855 3270/3846/17856 -f 3270/3846/17857 3271/3845/17858 3273/3847/17859 -f 2896/3435/17860 2897/3434/17861 3270/3846/17862 -f 3270/3846/17863 3272/3848/17864 2896/3435/17865 -f 3275/3849/17866 3274/3850/17867 3272/3848/17868 -f 3272/3848/17869 3273/3847/17870 3275/3849/17871 -f 2846/3385/17872 2896/3435/17873 3272/3848/17874 -f 3272/3848/17875 3274/3850/17876 2846/3385/17877 -f 3277/3851/17878 3276/3852/17879 3274/3850/17880 -f 3274/3850/17881 3275/3849/17882 3277/3851/17883 -f 2845/3380/17884 2846/3385/17885 3274/3850/17886 -f 3274/3850/17887 3276/3852/17888 2845/3380/17889 -f 3279/3853/17890 3278/3854/17891 3276/3852/17892 -f 3276/3852/17893 3277/3851/17894 3279/3853/17895 -f 2849/3386/17896 2845/3380/17897 3276/3852/17898 -f 3276/3852/17899 3278/3854/17900 2849/3386/17901 -f 3277/3851/17902 3280/3856/17903 3281/3855/17904 -f 3281/3855/17905 3279/3853/17906 3277/3851/17907 -f 2803/3342/17908 2804/3341/17909 3281/3855/17910 -f 3281/3855/17911 3280/3856/17912 2803/3342/17913 -f 3275/3849/17914 3282/3857/17915 3280/3856/17916 -f 3280/3856/17917 3277/3851/17918 3275/3849/17919 -f 2782/3321/17920 2803/3342/17921 3280/3856/17922 -f 3280/3856/17923 3282/3857/17924 2782/3321/17925 -f 3273/3847/17926 3283/3858/17927 3282/3857/17928 -f 3282/3857/17929 3275/3849/17930 3273/3847/17931 -f 2781/3322/17932 2782/3321/17933 3282/3857/17934 -f 3282/3857/17935 3283/3858/17936 2781/3322/17937 -f 3271/3845/17938 2910/3449/17939 3283/3858/17940 -f 3283/3858/17941 3273/3847/17942 3271/3845/17943 -f 2910/3449/17944 2911/3448/17945 2781/3322/17946 -f 2781/3322/17947 3283/3858/17948 2910/3449/17949 -f 2908/3445/17950 2910/3449/17951 3271/3845/17952 -f 3271/3845/17953 3269/3843/17954 2908/3445/17955 -f 2907/3446/17956 2908/3445/17957 3269/3843/17958 -f 3269/3843/17959 3266/3841/17960 2907/3446/17961 -f 2906/3447/17962 2907/3446/17963 3264/3838/17964 -f 3264/3838/17965 3284/3859/17966 2906/3447/17967 -f 3285/3860/17968 3284/3859/17969 3264/3838/17970 -f 3264/3838/17971 3265/3837/17972 3285/3860/17973 -f 3243/3840/17974 3241/3861/17975 3285/3860/17976 -f 3285/3860/17977 3265/3837/17978 3243/3840/17979 -f 3240/3862/17980 3286/3863/17981 3285/3860/17982 -f 3285/3860/17983 3241/3861/17984 3240/3862/17985 -f 3288/3864/17986 3287/3865/17987 2949/3491/17988 -f 2949/3491/17989 2950/3494/17990 3288/3864/17991 -f 3288/3864/17992 2906/3447/17993 3284/3859/17994 -f 3289/3866/17995 3287/3865/17996 3288/3864/17997 -f 3288/3864/17998 3286/3863/17999 3289/3866/18000 -f 3290/3868/18001 3287/3865/18002 3289/3866/18003 -f 3289/3866/18004 3291/3867/18005 3290/3868/18006 -f 3240/3862/18007 3239/3869/18008 3289/3866/18009 -f 3289/3866/18010 3286/3863/18011 3240/3862/18012 -f 3238/3870/18013 3291/3867/18014 3289/3866/18015 -f 3289/3866/18016 3239/3869/18017 3238/3870/18018 -f 3290/3868/18019 2972/3873/18020 3292/3871/18021 -f 3292/3871/18022 2948/3872/18023 3290/3868/18024 -f 3290/3868/18025 2948/3872/18026 2949/3491/18027 -f 2949/3491/18028 3287/3865/18029 3290/3868/18030 -f 3293/3874/18031 2972/3873/18032 3290/3868/18033 -f 3290/3868/18034 3291/3867/18035 3293/3874/18036 -f 3292/3876/18037 2972/3515/18038 2973/3514/18039 -f 2973/3514/18040 3294/3875/18041 3292/3876/18042 -f 3296/3879/18043 3295/3880/18044 3292/3877/18045 -f 3292/3877/18046 3294/3878/18047 3296/3879/18048 -f 2947/3489/18049 2948/3488/18050 3292/3877/18051 -f 3292/3877/18052 3295/3880/18053 2947/3489/18054 -f 3298/3881/18055 3297/3882/18056 3296/3879/18057 -f 3296/3879/18058 3294/3878/18059 3298/3881/18060 -f 3300/3883/18061 3299/3884/18062 3296/3879/18063 -f 3296/3879/18064 3297/3882/18065 3300/3883/18066 -f 3301/3885/18067 3295/3880/18068 3296/3879/18069 -f 3296/3879/18070 3299/3884/18071 3301/3885/18072 -f 2985/3529/18073 2986/3528/18074 3299/3886/18075 -f 3299/3886/18076 3300/3887/18077 2985/3529/18078 -f 2988/3532/18079 3301/3888/18080 3299/3886/18081 -f 3299/3886/18082 2986/3528/18083 2988/3532/18084 -f 3303/3889/18085 3302/3890/18086 3300/3883/18087 -f 3300/3883/18088 3297/3882/18089 3303/3889/18090 -f 3304/3892/18091 2985/3529/18092 3300/3887/18093 -f 3300/3887/18094 3302/3891/18095 3304/3892/18096 -f 3306/3893/18097 3305/3894/18098 3304/3892/18099 -f 3304/3892/18100 3302/3891/18101 3306/3893/18102 -f 3308/3895/18103 3307/3896/18104 3304/3892/18105 -f 3304/3892/18106 3305/3894/18107 3308/3895/18108 -f 2984/3530/18109 2985/3529/18110 3304/3892/18111 -f 3304/3892/18112 3307/3896/18113 2984/3530/18114 -f 3310/3897/18115 3309/3898/18116 3305/3894/18117 -f 3305/3894/18118 3306/3893/18119 3310/3897/18120 -f 3311/3899/18121 3308/3895/18122 3305/3894/18123 -f 3305/3894/18124 3309/3898/18125 3311/3899/18126 -f 2959/3501/18127 2960/3504/18128 3311/3899/18129 -f 3311/3899/18130 3309/3898/18131 2959/3501/18132 -f 3313/3902/18133 3312/3903/18134 3315/3900/18135 -f 3315/3900/18136 3314/3901/18137 3313/3902/18138 -f 2977/3521/18139 2978/3520/18140 3315/3900/18141 -f 3315/3900/18142 3312/3903/18143 2977/3521/18144 -f 3317/3904/18145 3316/3905/18146 3312/3903/18147 -f 3312/3903/18148 3313/3902/18149 3317/3904/18150 -f 3318/3906/18151 2977/3521/18152 3312/3903/18153 -f 3312/3903/18154 3316/3905/18155 3318/3906/18156 -f 3320/3907/18157 3319/3908/18158 3318/3906/18159 -f 3318/3906/18160 3316/3905/18161 3320/3907/18162 -f 2980/3909/18163 3321/3910/18164 3318/3906/18165 -f 3318/3906/18166 3319/3908/18167 2980/3909/18168 -f 2976/3522/18169 2977/3521/18170 3318/3906/18171 -f 3318/3906/18172 3321/3910/18173 2976/3522/18174 -f 2981/3911/18175 3322/3912/18176 3321/3910/18177 -f 3321/3910/18178 2980/3909/18179 2981/3911/18180 -f 3323/3913/18181 2976/3522/18182 3321/3910/18183 -f 3321/3910/18184 3322/3912/18185 3323/3913/18186 -f 3319/3916/18187 3320/3917/18188 3325/3914/18189 -f 3325/3914/18190 3324/3915/18191 3319/3916/18192 -f 3324/3915/18193 2983/3523/18194 2980/3526/18195 -f 2980/3526/18196 3319/3916/18197 3324/3915/18198 -f 3326/3918/18199 2953/3495/18200 3324/3915/18201 -f 3324/3915/18202 3325/3914/18203 3326/3918/18204 -f 2946/3490/18205 2983/3523/18206 3324/3915/18207 -f 3324/3915/18208 2953/3495/18209 2946/3490/18210 -f 3328/3919/18211 3327/3920/18212 3326/3918/18213 -f 3326/3918/18214 3325/3914/18215 3328/3919/18216 -f 3330/3921/18217 3329/3922/18218 3326/3918/18219 -f 3326/3918/18220 3327/3920/18221 3330/3921/18222 -f 2952/3496/18223 2953/3495/18224 3326/3918/18225 -f 3326/3918/18226 3329/3922/18227 2952/3496/18228 -f 2902/3442/18229 2903/3441/18230 3329/3923/18231 -f 3329/3923/18232 3330/3924/18233 2902/3442/18234 -f 2951/3493/18235 2952/3492/18236 3329/3923/18237 -f 3329/3923/18238 2903/3441/18239 2951/3493/18240 -f 3332/3925/18241 3331/3926/18242 3330/3921/18243 -f 3330/3921/18244 3327/3920/18245 3332/3925/18246 -f 2905/3443/18247 2902/3442/18248 3330/3924/18249 -f 3330/3924/18250 3331/3927/18251 2905/3443/18252 -f 3334/3929/18253 3333/3930/18254 3331/3927/18255 -f 3331/3927/18256 3332/3928/18257 3334/3929/18258 -f 3335/3931/18259 2905/3443/18260 3331/3927/18261 -f 3331/3927/18262 3333/3930/18263 3335/3931/18264 -f 2924/3462/18265 2894/3431/18266 3335/3931/18267 -f 3335/3931/18268 3333/3930/18269 2924/3462/18270 -f 2881/3420/18271 2882/3419/18272 3335/3931/18273 -f 3335/3931/18274 2894/3431/18275 2881/3420/18276 -f 2900/3437/18277 2905/3443/18278 3335/3931/18279 -f 3335/3931/18280 2882/3419/18281 2900/3437/18282 -f 2938/3475/18283 2924/3462/18284 3333/3930/18285 -f 3333/3930/18286 3334/3929/18287 2938/3475/18288 -f 2937/3476/18289 2938/3475/18290 3334/3929/18291 -f 3334/3929/18292 3336/3932/18293 2937/3476/18294 -f 3337/3934/18295 3336/3935/18296 3334/3933/18297 -f 3334/3933/18298 3332/3925/18299 3337/3934/18300 -f 3337/3934/18301 3338/3937/18302 3339/3936/18303 -f 3339/3936/18304 3336/3935/18305 3337/3934/18306 -f 3327/3920/18307 3328/3919/18308 3337/3934/18309 -f 3337/3934/18310 3332/3925/18311 3327/3920/18312 -f 3338/3937/18313 3337/3934/18314 3328/3919/18315 -f 3328/3919/18316 3340/3938/18317 3338/3937/18318 -f 3325/3914/18319 3320/3917/18320 3340/3938/18321 -f 3340/3938/18322 3328/3919/18323 3325/3914/18324 -f 3341/3941/18325 3339/3942/18326 3338/3939/18327 -f 3338/3939/18328 3342/3940/18329 3341/3941/18330 -f 3317/3904/18331 3342/3940/18332 3338/3939/18333 -f 3338/3939/18334 3340/3943/18335 3317/3904/18336 -f 3344/3945/18337 3343/3946/18338 3339/3936/18339 -f 3339/3936/18340 3341/3944/18341 3344/3945/18342 -f 3339/3936/18343 3343/3946/18344 2937/3947/18345 -f 2937/3947/18346 3336/3935/18347 3339/3936/18348 -f 3345/3948/18349 2935/3949/18350 2937/3947/18351 -f 2937/3947/18352 3343/3946/18353 3345/3948/18354 -f 3346/3950/18355 2934/3951/18356 2935/3949/18357 -f 2935/3949/18358 3345/3948/18359 3346/3950/18360 -f 3346/3954/18361 3347/3955/18362 3348/3952/18363 -f 3348/3952/18364 2934/3953/18365 3346/3954/18366 -f 3350/3956/18367 3349/3957/18368 3346/3950/18369 -f 3346/3950/18370 3345/3948/18371 3350/3956/18372 -f 3303/3889/18373 3347/3960/18374 3346/3958/18375 -f 3346/3958/18376 3349/3959/18377 3303/3889/18378 -f 3310/3961/18379 3306/3962/18380 3349/3957/18381 -f 3349/3957/18382 3350/3956/18383 3310/3961/18384 -f 3302/3890/18385 3303/3889/18386 3349/3959/18387 -f 3349/3959/18388 3306/3963/18389 3302/3890/18390 -f 3343/3946/18391 3344/3945/18392 3350/3956/18393 -f 3350/3956/18394 3345/3948/18395 3343/3946/18396 -f 2958/3964/18397 3310/3961/18398 3350/3956/18399 -f 3350/3956/18400 3344/3945/18401 2958/3964/18402 -f 3298/3965/18403 2974/3518/18404 3348/3952/18405 -f 3348/3952/18406 3347/3955/18407 3298/3965/18408 -f 2975/3517/18409 3351/3966/18410 3348/3952/18411 -f 3348/3952/18412 2974/3518/18413 2975/3517/18414 -f 2933/3967/18415 2934/3953/18416 3348/3952/18417 -f 3348/3952/18418 3351/3966/18419 2933/3967/18420 -f 3352/3968/18421 2942/3481/18422 3351/3966/18423 -f 3351/3966/18424 2975/3517/18425 3352/3968/18426 -f 2940/3480/18427 2933/3967/18428 3351/3966/18429 -f 3351/3966/18430 2942/3481/18431 2940/3480/18432 -f 2967/3511/18433 2968/3510/18434 3352/3968/18435 -f 3352/3968/18436 3353/3969/18437 2967/3511/18438 -f 2941/3482/18439 2942/3481/18440 3352/3968/18441 -f 3352/3968/18442 2968/3510/18443 2941/3482/18444 -f 2971/3516/18445 3353/3969/18446 3352/3968/18447 -f 3352/3968/18448 2975/3517/18449 2971/3516/18450 -f 2970/3512/18451 2967/3511/18452 3353/3969/18453 -f 3353/3969/18454 3354/3970/18455 2970/3512/18456 -f 3355/3971/18457 3354/3970/18458 3353/3969/18459 -f 3353/3969/18460 2971/3516/18461 3355/3971/18462 -f 3236/3972/18463 3234/3973/18464 3354/3970/18465 -f 3354/3970/18466 3355/3971/18467 3236/3972/18468 -f 3235/3821/18469 2970/3512/18470 3354/3970/18471 -f 3354/3970/18472 3234/3973/18473 3235/3821/18474 -f 3298/3965/18475 3294/3875/18476 2973/3514/18477 -f 2973/3514/18478 2974/3518/18479 3298/3965/18480 -f 3297/3882/18481 3298/3881/18482 3347/3960/18483 -f 3347/3960/18484 3303/3889/18485 3297/3882/18486 -f 2956/3498/18487 2958/3502/18488 3344/3974/18489 -f 3344/3974/18490 3341/3941/18491 2956/3498/18492 -f 2955/3499/18493 2956/3498/18494 3341/3941/18495 -f 3341/3941/18496 3342/3940/18497 2955/3499/18498 -f 3313/3902/18499 2955/3499/18500 3342/3940/18501 -f 3342/3940/18502 3317/3904/18503 3313/3902/18504 -f 3316/3905/18505 3317/3904/18506 3340/3943/18507 -f 3340/3943/18508 3320/3907/18509 3316/3905/18510 -f 2958/3502/18511 2959/3501/18512 3309/3898/18513 -f 3309/3898/18514 3310/3897/18515 2958/3502/18516 -f 3237/3975/18517 3293/3874/18518 3291/3867/18519 -f 3291/3867/18520 3238/3870/18521 3237/3975/18522 -f 3242/3809/18523 3243/3808/18524 3262/3836/18525 -f 3262/3836/18526 3245/3810/18527 3242/3809/18528 -f 3248/3814/18529 3247/3813/18530 3259/3835/18531 -f 3259/3835/18532 3250/3815/18533 3248/3814/18534 -f 3237/3977/18535 3236/3972/18536 3355/3971/18537 -f 3355/3971/18538 3293/3976/18539 3237/3977/18540 -f 3001/3543/18541 3002/3542/18542 3010/3554/18543 -f 3010/3554/18544 3011/3553/18545 3001/3543/18546 -f 3357/3978/18547 3356/3979/18548 2988/3532/18549 -f 2988/3532/18550 2989/3531/18551 3357/3978/18552 -f 3323/3913/18553 3301/3888/18554 2988/3532/18555 -f 2988/3532/18556 3356/3979/18557 3323/3913/18558 -f 2976/3522/18559 3323/3913/18560 3356/3979/18561 -f 3356/3979/18562 2979/3519/18563 2976/3522/18564 -f 2945/3485/18565 2941/3482/18566 2968/3510/18567 -f 2968/3510/18568 2962/3508/18569 2945/3485/18570 -f 2923/3461/18571 2936/3471/18572 2939/3478/18573 -f 2939/3478/18574 2925/3463/18575 2923/3461/18576 -f 2923/3461/18577 2924/3462/18578 2938/3475/18579 -f 2938/3475/18580 2936/3471/18581 2923/3461/18582 -f 2897/3434/18583 2874/3412/18584 2932/3470/18585 -f 2932/3470/18586 2926/3467/18587 2897/3434/18588 -f 2866/3404/18589 2915/3452/18590 2863/3402/18591 -f 2863/3402/18592 2860/3399/18593 2866/3404/18594 -f 2892/3430/18595 2895/3433/18596 2918/3455/18597 -f 2918/3455/18598 2913/3454/18599 2892/3430/18600 -f 2891/3428/18601 2892/3430/18602 2913/3454/18603 -f 2913/3454/18604 2914/3453/18605 2891/3428/18606 -f 2890/3429/18607 2891/3428/18608 2914/3453/18609 -f 2914/3453/18610 3358/3980/18611 2890/3429/18612 -f 2866/3404/18613 3358/3980/18614 2914/3453/18615 -f 2914/3453/18616 2915/3452/18617 2866/3404/18618 -f 3359/3982/18619 2890/3429/18620 3358/3980/18621 -f 3358/3980/18622 3360/3981/18623 3359/3982/18624 -f 2841/3378/18625 3360/3981/18626 3358/3980/18627 -f 3358/3980/18628 2866/3404/18629 2841/3378/18630 -f 2877/3415/18631 2887/3426/18632 3359/3982/18633 -f 3359/3982/18634 3361/3983/18635 2877/3415/18636 -f 2888/3425/18637 2890/3429/18638 3359/3982/18639 -f 3359/3982/18640 2887/3426/18641 2888/3425/18642 -f 3362/3984/18643 3361/3983/18644 3359/3982/18645 -f 3359/3982/18646 3360/3981/18647 3362/3984/18648 -f 2854/3392/18649 3361/3983/18650 3362/3984/18651 -f 3362/3984/18652 2851/3390/18653 2854/3392/18654 -f 2841/3378/18655 2839/3375/18656 3362/3984/18657 -f 3362/3984/18658 3360/3981/18659 2841/3378/18660 -f 2837/3377/18661 2851/3390/18662 3362/3984/18663 -f 3362/3984/18664 2839/3375/18665 2837/3377/18666 -f 2869/3407/18667 2877/3415/18668 3361/3983/18669 -f 3361/3983/18670 2854/3392/18671 2869/3407/18672 -f 2882/3419/18673 2880/3417/18674 2899/3438/18675 -f 2899/3438/18676 2900/3437/18677 2882/3419/18678 -f 2847/3384/18679 2873/3411/18680 2896/3435/18681 -f 2896/3435/18682 2846/3385/18683 2847/3384/18684 -f 2883/3424/18685 2884/3423/18686 2895/3433/18687 -f 2895/3433/18688 2892/3430/18689 2883/3424/18690 -f 2875/3414/18691 2885/3422/18692 2887/3426/18693 -f 2887/3426/18694 2877/3415/18695 2875/3414/18696 -f 2842/3383/18697 2856/3394/18698 2858/3397/18699 -f 2858/3397/18700 2847/3384/18701 2842/3383/18702 -f 3363/3985/18703 2797/3334/18704 2834/3372/18705 -f 2834/3372/18706 2855/3395/18707 3363/3985/18708 -f 3363/3985/18709 2775/3312/18710 2797/3334/18711 -f 2843/3382/18712 2806/3344/18713 3363/3985/18714 -f 3363/3985/18715 2855/3395/18716 2843/3382/18717 -f 2806/3344/18718 2774/3313/18719 2775/3312/18720 -f 2775/3312/18721 3363/3985/18722 2806/3344/18723 -f 2842/3383/18724 2843/3382/18725 2855/3395/18726 -f 2855/3395/18727 2856/3394/18728 2842/3383/18729 -f 2826/3365/18730 2862/3400/18731 2861/3398/18732 -f 2861/3398/18733 2825/3366/18734 2826/3365/18735 -f 2807/3345/18736 2844/3381/18737 2848/3387/18738 -f 2848/3387/18739 2809/3346/18740 2807/3345/18741 -f 2807/3345/18742 2806/3344/18743 2843/3382/18744 -f 2843/3382/18745 2844/3381/18746 2807/3345/18747 -f 2819/3360/18748 2820/3359/18749 2838/3376/18750 -f 2838/3376/18751 2836/3373/18752 2819/3360/18753 -f 2836/3373/18754 2823/3361/18755 2819/3360/18756 -f 2824/3362/18757 2823/3361/18758 2862/3400/18759 -f 2862/3400/18760 2826/3365/18761 2824/3362/18762 -f 2829/3369/18763 2828/3363/18764 2825/3366/18765 -f 2825/3366/18766 2861/3398/18767 2829/3369/18768 -f 2811/3349/18769 2824/3362/18770 2826/3365/18771 -f 2826/3365/18772 2827/3364/18773 2811/3349/18774 -f 2793/3331/18775 2794/3330/18776 2813/3352/18777 -f 2813/3352/18778 2764/3304/18779 2793/3331/18780 -f 2766/3302/18781 2812/3348/18782 2810/3350/18783 -f 2810/3350/18784 2765/3303/18785 2766/3302/18786 -f 2798/3338/18787 2805/3343/18788 2808/3347/18789 -f 2808/3347/18790 2802/3339/18791 2798/3338/18792 -f 2783/3320/18793 2800/3336/18794 2803/3342/18795 -f 2803/3342/18796 2782/3321/18797 2783/3320/18798 -f 2783/3320/18799 2785/3324/18800 2799/3337/18801 -f 2799/3337/18802 2800/3336/18803 2783/3320/18804 -f 2767/3305/18805 2758/3295/18806 2755/3293/18807 -f 2755/3293/18808 2762/3300/18809 2767/3305/18810 -f 3364/3986/18811 2772/3311/18812 2776/3315/18813 -f 2776/3315/18814 3132/3689/18815 3364/3986/18816 -f 2774/3313/18817 2773/3310/18818 2769/3308/18819 -f 2755/3293/18820 2754/3289/18821 2761/3301/18822 -f 2761/3301/18823 2762/3300/18824 2755/3293/18825 -f 3132/3689/18826 3070/3619/18827 3071/3618/18828 -f 3071/3618/18829 3364/3986/18830 3132/3689/18831 -f 2734/3275/18832 2735/3274/18833 2748/3287/18834 -f 2748/3287/18835 2749/3286/18836 2734/3275/18837 -f 3113/3667/18838 3115/3670/18839 3118/3674/18840 -f 3117/3672/18841 3091/3675/18842 2729/3673/18843 -f 2721/3256/18844 2715/3253/18845 2726/3263/18846 -f 2726/3263/18847 2727/3262/18848 2721/3256/18849 -f 3070/3619/18850 3365/3987/18851 2740/3281/18852 -f 2740/3281/18853 3068/3616/18854 3070/3619/18855 -f 3130/3688/18856 3365/3987/18857 3070/3619/18858 -f 3070/3619/18859 3132/3689/18860 3130/3688/18861 -f 3136/3693/18862 3365/3987/18863 3130/3688/18864 -f 3130/3688/18865 3134/3691/18866 3136/3693/18867 -f 2743/3278/18868 2740/3281/18869 3365/3987/18870 -f 2743/3278/18871 3365/3987/18872 3136/3693/18873 -f 2743/3278/18874 3136/3693/18875 2742/3279/18876 -f 3314/3901/18877 2954/3500/18878 2955/3499/18879 -f 2955/3499/18880 3313/3902/18881 3314/3901/18882 -f 3301/3885/18883 2982/3524/18884 2947/3489/18885 -f 2947/3489/18886 3295/3880/18887 3301/3885/18888 -f 3322/3912/18889 2981/3911/18890 3301/3888/18891 -f 3301/3888/18892 3323/3913/18893 3322/3912/18894 -f 3178/3739/18895 3007/3547/18896 3004/3550/18897 -f 3180/3742/18898 3181/3741/18899 3366/3988/18900 -f 3011/3553/18901 3366/3988/18902 3181/3741/18903 -f 3181/3741/18904 3186/3746/18905 3011/3553/18906 -f 3178/3739/18907 3366/3988/18908 3011/3553/18909 -f 3011/3553/18910 3007/3547/18911 3178/3739/18912 -f 3364/3986/18913 2771/3306/18914 2768/3309/18915 -f 2768/3309/18916 2772/3311/18917 3364/3986/18918 -f 3314/3901/18919 2961/3503/18920 2957/3497/18921 -f 2957/3497/18922 2954/3500/18923 3314/3901/18924 -f 2982/3524/18925 3301/3885/18926 2981/3525/18927 -f 3178/3739/18928 3180/3742/18929 3366/3988/18930 -f 2979/3519/18931 3367/3989/18932 2978/3520/18933 -f 3004/3550/18934 3005/3549/18935 3013/3555/18936 -f 3369/3990/18937 3368/3991/18938 3025/3567/18939 -f 3025/3567/18940 3024/3568/18941 3369/3990/18942 -f 3024/3568/18943 2779/3318/18944 3369/3990/18945 -f 3367/3989/18946 2979/3519/18947 3356/3979/18948 -f 3356/3979/18949 3357/3978/18950 3367/3989/18951 -f 3369/3990/18952 2780/3317/18953 3169/3727/18954 -f 3169/3727/18955 3368/3991/18956 3369/3990/18957 -f 3369/3990/18958 2779/3318/18959 2780/3317/18960 -f 3012/3556/18961 3214/3774/18962 3013/3555/18963 -f 2997/3541/18964 2998/3540/18965 3370/3992/18966 -f 2998/3540/18967 3191/3794/18968 3370/3992/18969 -f 3185/3744/18970 3370/3993/18971 3191/3751/18972 -f 3191/3751/18973 3184/3745/18974 3185/3744/18975 -f 3151/3707/18976 2786/3323/18977 2784/3319/18978 -f 2784/3319/18979 2781/3322/18980 3151/3707/18981 -f 3151/3707/18982 3141/3696/18983 3127/3684/18984 -f 3127/3684/18985 2786/3323/18986 3151/3707/18987 -f 3371/3994/18988 3118/3674/18989 2729/3673/18990 -f 2729/3673/18991 2727/3262/18992 3371/3994/18993 -f 3371/3994/18994 2727/3262/18995 3111/3665/18996 -f 3111/3665/18997 3110/3666/18998 3371/3994/18999 -f 3110/3666/19000 3113/3667/19001 3118/3674/19002 -f 3118/3674/19003 3371/3994/19004 3110/3666/19005 -f 3111/3665/19006 3104/3659/19007 3108/3663/19008 -f 2732/3269/19009 3107/3664/19010 3120/3676/19011 -f 3120/3676/19012 2731/3270/19013 2732/3269/19014 -f 3105/3661/19015 3107/3664/19016 3108/3663/19017 -f 3108/3663/19018 3104/3659/19019 3105/3661/19020 -f 3120/3676/19021 3107/3664/19022 3105/3661/19023 -f 2851/3390/19024 3163/3719/19025 2850/3391/19026 -f 3286/3863/19027 3288/3864/19028 3284/3859/19029 -f 3284/3859/19030 3285/3860/19031 3286/3863/19032 -f 2950/3494/19033 2912/3450/19034 2906/3447/19035 -f 2906/3447/19036 3288/3864/19037 2950/3494/19038 -f 3315/3900/19039 2978/3520/19040 2960/3504/19041 -f 2960/3504/19042 2961/3503/19043 3315/3900/19044 -f 2961/3503/19045 3314/3901/19046 3315/3900/19047 -f 3367/3989/19048 3357/3978/19049 3308/3895/19050 -f 3308/3895/19051 3311/3899/19052 3367/3989/19053 -f 2989/3531/19054 3307/3896/19055 3308/3895/19056 -f 3308/3895/19057 3357/3978/19058 2989/3531/19059 -f 2989/3531/19060 2987/3527/19061 2984/3530/19062 -f 2984/3530/19063 3307/3896/19064 2989/3531/19065 -f 3367/3989/19066 3311/3899/19067 2960/3504/19068 -f 2960/3504/19069 2978/3520/19070 3367/3989/19071 -f 3004/3550/19072 3013/3555/19073 3179/3738/19074 -f 3179/3738/19075 3013/3555/19076 3214/3774/19077 -f 3214/3774/19078 3217/3778/19079 3179/3738/19080 -f 2994/3538/19081 3183/3743/19082 3179/3738/19083 -f 3179/3738/19084 3217/3778/19085 2994/3538/19086 -f 2994/3538/19087 2995/3537/19088 3183/3743/19089 -f 2997/3541/19090 3370/3992/19091 3185/3744/19092 -f 3185/3744/19093 3182/3740/19094 2997/3541/19095 -f 2995/3537/19096 2997/3541/19097 3182/3740/19098 -f 3182/3740/19099 3183/3743/19100 2995/3537/19101 -f 2972/3515/19102 3293/3976/19103 3355/3971/19104 -f 3355/3971/19105 2971/3516/19106 2972/3515/19107 -f 3091/3646/19108 3094/3649/19109 2728/3266/19110 -f 2728/3266/19111 2729/3267/19112 3091/3646/19113 -f 2848/3387/19114 2849/3386/19115 3278/3854/19116 -f 3278/3854/19117 3279/3853/19118 2848/3387/19119 -f 2801/3340/19120 2802/3339/19121 2808/3347/19122 -f 2808/3347/19123 2804/3341/19124 2801/3340/19125 -f 2804/3341/19126 2808/3347/19127 2809/3346/19128 -f 2809/3346/19129 3281/3855/19130 2804/3341/19131 -f 3281/3855/19132 2809/3346/19133 2848/3387/19134 -f 2848/3387/19135 3279/3853/19136 3281/3855/19137 -f 3157/3714/19138 3156/3713/19139 2816/3354/19140 -f 2816/3354/19141 2817/3353/19142 3157/3714/19143 -f 3154/3712/19144 3161/3715/19145 2816/3354/19146 -f 2816/3354/19147 3156/3713/19148 3154/3712/19149 -f 3155/3711/19150 3160/3716/19151 3161/3715/19152 -f 3161/3715/19153 3154/3712/19154 3155/3711/19155 -f 2835/3374/19156 2862/3400/19157 2823/3361/19158 -f 2812/3348/19159 2822/3357/19160 2811/3349/19161 -f 3168/3724/19162 3165/3721/19163 3160/3716/19164 -f 3160/3716/19165 3155/3711/19166 3168/3724/19167 -f 3168/3724/19168 3166/3723/19169 3165/3721/19170 -f 3111/3665/19171 2727/3262/19172 3104/3659/19173 -f 2747/3282/19174 2744/3285/19175 3085/3637/19176 -f 3085/3637/19177 2750/3288/19178 2747/3282/19179 -f 2741/3280/19180 2742/3279/19181 3084/3638/19182 -f 3364/3986/19183 3071/3618/19184 3065/3613/19185 -f 3065/3613/19186 2771/3306/19187 3364/3986/19188 -f 3071/3618/19189 3069/3615/19190 3064/3611/19191 -f 3064/3611/19192 3065/3613/19193 3071/3618/19194 -f 3064/3611/19195 3069/3615/19196 3063/3612/19197 -f 2771/3306/19198 3065/3613/19199 3056/3605/19200 -f 2739/3277/19201 3112/3668/19202 3109/3662/19203 -f 2733/3268/19204 2730/3271/19205 2738/3276/19206 -f 3373/3997/19207 3372/3998/19208 3375/3995/19209 -f 3375/3995/19210 3374/3996/19211 3373/3997/19212 -f 3377/3999/19213 3376/4000/19214 3375/3995/19215 -f 3375/3995/19216 3372/3998/19217 3377/3999/19218 -f 3375/3995/19219 3376/4000/19220 3378/4001/19221 -f 3378/4001/19222 3374/3996/19223 3375/3995/19224 -f 3380/4002/19225 3379/4003/19226 3376/4000/19227 -f 3376/4000/19228 3377/3999/19229 3380/4002/19230 -f 3376/4000/19231 3381/4005/19232 3382/4004/19233 -f 3382/4004/19234 3378/4001/19235 3376/4000/19236 -f 3376/4000/19237 3379/4003/19238 3383/4006/19239 -f 3383/4006/19240 3381/4005/19241 3376/4000/19242 -f 3380/4002/19243 3384/4008/19244 3385/4007/19245 -f 3385/4007/19246 3379/4003/19247 3380/4002/19248 -f 3385/4007/19249 3384/4008/19250 3386/4009/19251 -f 3385/4007/19252 3386/4009/19253 3388/4010/19254 -f 3388/4010/19255 3387/4011/19256 3385/4007/19257 -f 3390/4014/19258 3389/4015/19259 3392/4012/19260 -f 3392/4012/19261 3391/4013/19262 3390/4014/19263 -f 3391/4013/19264 3393/4016/19265 3390/4014/19266 -f 3390/4014/19267 3394/4018/19268 3395/4017/19269 -f 3395/4017/19270 3389/4015/19271 3390/4014/19272 -f 3396/4020/19273 3394/4018/19274 3390/4014/19275 -f 3390/4014/19276 3397/4019/19277 3396/4020/19278 -f 3399/4023/19279 3398/4024/19280 3401/4021/19281 -f 3401/4021/19282 3400/4022/19283 3399/4023/19284 -f 3402/4025/19285 3391/4013/19286 3392/4012/19287 -f 3403/4026/19288 3402/4025/19289 3392/4012/19290 -f 3404/4029/19291 3393/4016/19292 3406/4027/19293 -f 3406/4027/19294 3405/4028/19295 3404/4029/19296 -f 3406/4027/19297 3393/4016/19298 3391/4013/19299 -f 3391/4013/19300 3402/4025/19301 3406/4027/19302 -f 3402/4025/19303 3403/4026/19304 3406/4027/19305 -f 3406/4027/19306 3403/4026/19307 3408/4030/19308 -f 3408/4030/19309 3407/4031/19310 3406/4027/19311 -f 3409/4032/19312 3407/4031/19313 3408/4030/19314 -f 3409/4032/19315 3408/4030/19316 3411/4033/19317 -f 3411/4033/19318 3410/4034/19319 3409/4032/19320 -f 3409/4032/19321 3413/4035/19322 3412/4036/19323 -f 3414/4037/19324 3407/4031/19325 3409/4032/19326 -f 3409/4032/19327 3412/4036/19328 3414/4037/19329 -f 3415/4038/19330 3386/4009/19331 3384/4008/19332 -f 3384/4008/19333 3400/4022/19334 3415/4038/19335 -f 3415/4038/19336 3416/4039/19337 3388/4010/19338 -f 3388/4010/19339 3386/4009/19340 3415/4038/19341 -f 3413/4035/19342 3409/4032/19343 3410/4034/19344 -f 3410/4034/19345 3417/4040/19346 3413/4035/19347 -f 3418/4041/19348 3412/4036/19349 3413/4035/19350 -f 3413/4035/19351 3417/4040/19352 3418/4041/19353 -f 3420/4044/19354 3419/4045/19355 3422/4042/19356 -f 3422/4042/19357 3421/4043/19358 3420/4044/19359 -f 3423/4047/19360 3419/4045/19361 3420/4044/19362 -f 3420/4044/19363 3424/4046/19364 3423/4047/19365 -f 3426/4049/19366 3425/4050/19367 3427/4048/19368 -f 3427/4048/19369 3422/4042/19370 3426/4049/19371 -f 3428/4053/19372 3426/4049/19373 3430/4051/19374 -f 3430/4051/19375 3429/4052/19376 3428/4053/19377 -f 3426/4049/19378 3428/4053/19379 3425/4050/19380 -f 3426/4049/19381 3422/4042/19382 3419/4045/19383 -f 3419/4045/19384 3431/4054/19385 3426/4049/19386 -f 3421/4043/19387 3433/4055/19388 3432/4056/19389 -f 3420/4044/19390 3421/4043/19391 3432/4056/19392 -f 3432/4056/19393 3424/4046/19394 3420/4044/19395 -f 3435/4057/19396 3434/4058/19397 3430/4051/19398 -f 3430/4051/19399 3426/4049/19400 3435/4057/19401 -f 3435/4057/19402 3426/4049/19403 3431/4054/19404 -f 3431/4054/19405 3436/4059/19406 3435/4057/19407 -f 3435/4057/19408 3437/4061/19409 3438/4060/19410 -f 3438/4060/19411 3434/4058/19412 3435/4057/19413 -f 3435/4057/19414 3436/4059/19415 3440/4062/19416 -f 3440/4062/19417 3439/4063/19418 3435/4057/19419 -f 3435/4057/19420 3439/4063/19421 3441/4064/19422 -f 3441/4064/19423 3437/4061/19424 3435/4057/19425 -f 3442/4066/19426 3423/4047/19427 3424/4046/19428 -f 3424/4046/19429 3443/4065/19430 3442/4066/19431 -f 3442/4066/19432 3444/4068/19433 3445/4067/19434 -f 3445/4067/19435 3423/4047/19436 3442/4066/19437 -f 3442/4066/19438 3443/4065/19439 3446/4069/19440 -f 3446/4069/19441 3444/4068/19442 3442/4066/19443 -f 3448/4072/19444 3447/4073/19445 3450/4070/19446 -f 3450/4070/19447 3449/4071/19448 3448/4072/19449 -f 3452/4074/19450 3451/4075/19451 3447/4073/19452 -f 3447/4073/19453 3448/4072/19454 3452/4074/19455 -f 3448/4072/19456 3449/4071/19457 3453/4076/19458 -f 3453/4076/19459 3452/4074/19460 3448/4072/19461 -f 3455/4077/19462 3454/4078/19463 3428/4053/19464 -f 3428/4053/19465 3429/4052/19466 3455/4077/19467 -f 3429/4052/19468 3430/4051/19469 3456/4079/19470 -f 3456/4079/19471 3455/4077/19472 3429/4052/19473 -f 3458/4081/19474 3457/4082/19475 3444/4068/19476 -f 3444/4068/19477 3459/4080/19478 3458/4081/19479 -f 3444/4068/19480 3457/4082/19481 3445/4067/19482 -f 3446/4069/19483 3461/4083/19484 3460/4084/19485 -f 3444/4068/19486 3446/4069/19487 3460/4084/19488 -f 3460/4084/19489 3459/4080/19490 3444/4068/19491 -f 3463/4085/19492 3462/4086/19493 3412/4036/19494 -f 3412/4036/19495 3418/4041/19496 3463/4085/19497 -f 3463/4085/19498 3418/4041/19499 3465/4087/19500 -f 3465/4087/19501 3464/4088/19502 3463/4085/19503 -f 3467/4089/19504 3466/4090/19505 3463/4085/19506 -f 3463/4085/19507 3464/4088/19508 3467/4089/19509 -f 3469/4092/19510 3468/4093/19511 3470/4091/19512 -f 3470/4091/19513 3462/4086/19514 3469/4092/19515 -f 3469/4092/19516 3471/4094/19517 3468/4093/19518 -f 3472/4097/19519 3466/4098/19520 3474/4095/19521 -f 3474/4095/19522 3473/4096/19523 3472/4097/19524 -f 3476/4101/19525 3475/4102/19526 3478/4099/19527 -f 3478/4099/19528 3477/4100/19529 3476/4101/19530 -f 3476/4101/19531 3479/4104/19532 3480/4103/19533 -f 3480/4103/19534 3475/4102/19535 3476/4101/19536 -f 3476/4101/19537 3477/4100/19538 3481/4105/19539 -f 3481/4105/19540 3479/4104/19541 3476/4101/19542 -f 3483/4108/19543 3482/4109/19544 3485/4106/19545 -f 3485/4106/19546 3484/4107/19547 3483/4108/19548 -f 3485/4106/19549 3486/4112/19550 3488/4110/19551 -f 3488/4110/19552 3487/4111/19553 3485/4106/19554 -f 3480/4103/19555 3489/4114/19556 3490/4113/19557 -f 3490/4113/19558 3475/4102/19559 3480/4103/19560 -f 3492/4117/19561 3491/4118/19562 3494/4115/19563 -f 3494/4115/19564 3493/4116/19565 3492/4117/19566 -f 3479/4104/19567 3481/4105/19568 3496/4119/19569 -f 3496/4119/19570 3495/4120/19571 3479/4104/19572 -f 3498/4123/19573 3497/4124/19574 3474/4121/19575 -f 3474/4121/19576 3499/4122/19577 3498/4123/19578 -f 3501/4125/19579 3500/4126/19580 3497/4124/19581 -f 3497/4124/19582 3498/4123/19583 3501/4125/19584 -f 3498/4123/19585 3499/4122/19586 3502/4127/19587 -f 3502/4127/19588 3501/4125/19589 3498/4123/19590 -f 3504/4129/19591 3503/4130/19592 3495/4120/19593 -f 3495/4120/19594 3505/4128/19595 3504/4129/19596 -f 3487/4111/19597 3489/4114/19598 3480/4103/19599 -f 3480/4103/19600 3503/4130/19601 3487/4111/19602 -f 3503/4130/19603 3506/4131/19604 3487/4111/19605 -f 3508/4134/19606 3507/4135/19607 3510/4132/19608 -f 3510/4132/19609 3509/4133/19610 3508/4134/19611 -f 3512/4136/19612 3511/4137/19613 3507/4135/19614 -f 3507/4135/19615 3508/4134/19616 3512/4136/19617 -f 3508/4134/19618 3509/4133/19619 3513/4138/19620 -f 3513/4138/19621 3512/4136/19622 3508/4134/19623 -f 3515/4141/19624 3514/4142/19625 3517/4139/19626 -f 3517/4139/19627 3516/4140/19628 3515/4141/19629 -f 3515/4141/19630 3516/4140/19631 3519/4143/19632 -f 3519/4143/19633 3518/4144/19634 3515/4141/19635 -f 3515/4141/19636 3518/4144/19637 3520/4145/19638 -f 3520/4145/19639 3514/4142/19640 3515/4141/19641 -f 3483/4108/19642 3484/4107/19643 3522/4146/19644 -f 3522/4146/19645 3521/4147/19646 3483/4108/19647 -f 3523/4149/19648 3521/4147/19649 3522/4146/19650 -f 3522/4146/19651 3524/4148/19652 3523/4149/19653 -f 3526/4152/19654 3525/4153/19655 3528/4150/19656 -f 3528/4150/19657 3527/4151/19658 3526/4152/19659 -f 3530/4154/19660 3529/4155/19661 3525/4153/19662 -f 3525/4153/19663 3526/4152/19664 3530/4154/19665 -f 3526/4152/19666 3527/4151/19667 3531/4156/19668 -f 3531/4156/19669 3530/4154/19670 3526/4152/19671 -f 3533/4159/19672 3532/4160/19673 3535/4157/19674 -f 3535/4157/19675 3534/4158/19676 3533/4159/19677 -f 3537/4161/19678 3536/4162/19679 3532/4160/19680 -f 3532/4160/19681 3533/4159/19682 3537/4161/19683 -f 3533/4159/19684 3534/4158/19685 3538/4163/19686 -f 3538/4163/19687 3537/4161/19688 3533/4159/19689 -f 3540/4166/19690 3539/4167/19691 3542/4164/19692 -f 3542/4164/19693 3541/4165/19694 3540/4166/19695 -f 3540/4166/19696 3541/4165/19697 3544/4168/19698 -f 3544/4168/19699 3543/4169/19700 3540/4166/19701 -f 3540/4166/19702 3535/4157/19703 3545/4170/19704 -f 3545/4170/19705 3539/4167/19706 3540/4166/19707 -f 3547/4173/19708 3546/4174/19709 3549/4171/19710 -f 3549/4171/19711 3548/4172/19712 3547/4173/19713 -f 3547/4173/19714 3548/4172/19715 3551/4175/19716 -f 3551/4175/19717 3550/4176/19718 3547/4173/19719 -f 3547/4179/19720 3552/4180/19721 3553/4177/19722 -f 3553/4177/19723 3546/4178/19724 3547/4179/19725 -f 3547/4183/19726 3554/4184/19727 3555/4181/19728 -f 3555/4181/19729 3552/4182/19730 3547/4183/19731 -f 3557/4187/19732 3556/4188/19733 3559/4185/19734 -f 3559/4185/19735 3558/4186/19736 3557/4187/19737 -f 3561/4189/19738 3560/4190/19739 3556/4188/19740 -f 3556/4188/19741 3557/4187/19742 3561/4189/19743 -f 3557/4187/19744 3558/4186/19745 3562/4191/19746 -f 3562/4191/19747 3561/4189/19748 3557/4187/19749 -f 3564/4194/19750 3563/4195/19751 3566/4192/19752 -f 3566/4192/19753 3565/4193/19754 3564/4194/19755 -f 3564/4194/19756 3565/4193/19757 3568/4196/19758 -f 3568/4196/19759 3567/4197/19760 3564/4194/19761 -f 3564/4194/19762 3569/4199/19763 3570/4198/19764 -f 3570/4198/19765 3563/4195/19766 3564/4194/19767 -f 3573/4200/19768 3572/4201/19769 3571/4202/19770 -f 3571/4202/19771 3574/4204/19772 3575/4203/19773 -f 3575/4203/19774 3573/4200/19775 3571/4202/19776 -f 3571/4202/19777 3572/4201/19778 3576/4205/19779 -f 3575/4203/19780 3574/4204/19781 3577/4206/19782 -f 3579/4207/19783 3578/4208/19784 3575/4203/19785 -f 3575/4203/19786 3577/4206/19787 3579/4207/19788 -f 3579/4211/19789 3580/4212/19790 3582/4209/19791 -f 3582/4209/19792 3581/4210/19793 3579/4211/19794 -f 3579/4207/19795 3577/4206/19796 3576/4205/19797 -f 3576/4205/19798 3583/4213/19799 3579/4207/19800 -f 3571/4202/19801 3576/4205/19802 3577/4206/19803 -f 3577/4206/19804 3574/4204/19805 3571/4202/19806 -f 3567/4216/19807 3568/4217/19808 3585/4214/19809 -f 3585/4214/19810 3584/4215/19811 3567/4216/19812 -f 3567/4216/19813 3584/4215/19814 3586/4218/19815 -f 3586/4218/19816 3564/4219/19817 3567/4216/19818 -f 3580/4220/19819 3588/4221/19820 3587/4222/19821 -f 3580/4212/19822 3587/4225/19823 3590/4223/19824 -f 3590/4223/19825 3589/4224/19826 3580/4212/19827 -f 3591/4227/19828 3590/4223/19829 3587/4225/19830 -f 3587/4225/19831 3592/4226/19832 3591/4227/19833 -f 3591/4227/19834 3592/4226/19835 3593/4228/19836 -f 3595/4229/19837 3594/4230/19838 3593/4231/19839 -f 3595/4229/19840 3593/4231/19841 3592/4232/19842 -f 3592/4232/19843 3596/4233/19844 3595/4229/19845 -f 3598/4235/19846 3597/4236/19847 3599/4234/19848 -f 3599/4234/19849 3551/4175/19850 3598/4235/19851 -f 3601/4237/19852 3600/4238/19853 3599/4234/19854 -f 3599/4234/19855 3597/4236/19856 3601/4237/19857 -f 3599/4234/19858 3602/4240/19859 3603/4239/19860 -f 3603/4239/19861 3550/4176/19862 3599/4234/19863 -f 3599/4234/19864 3600/4238/19865 3604/4241/19866 -f 3604/4241/19867 3602/4240/19868 3599/4234/19869 -f 3595/4229/19870 3596/4233/19871 3605/4242/19872 -f 3595/4229/19873 3605/4242/19874 3606/4243/19875 -f 3606/4243/19876 3594/4230/19877 3595/4229/19878 -f 3594/4230/19879 3606/4243/19880 3607/4244/19881 -f 3609/4247/19882 3608/4248/19883 3611/4245/19884 -f 3611/4245/19885 3610/4246/19886 3609/4247/19887 -f 3611/4245/19888 3608/4248/19889 3613/4249/19890 -f 3613/4249/19891 3612/4250/19892 3611/4245/19893 -f 3614/4251/19894 3610/4246/19895 3611/4245/19896 -f 3611/4245/19897 3612/4250/19898 3614/4251/19899 -f 3615/4254/19900 3585/4214/19901 3617/4252/19902 -f 3617/4252/19903 3616/4253/19904 3615/4254/19905 -f 3615/4254/19906 3616/4253/19907 3619/4255/19908 -f 3619/4255/19909 3618/4256/19910 3615/4254/19911 -f 3615/4254/19912 3620/4257/19913 3584/4215/19914 -f 3584/4215/19915 3585/4214/19916 3615/4254/19917 -f 3555/4181/19918 3621/4259/19919 3622/4258/19920 -f 3622/4258/19921 3552/4182/19922 3555/4181/19923 -f 3624/4262/19924 3623/4263/19925 3626/4260/19926 -f 3626/4260/19927 3625/4261/19928 3624/4262/19929 -f 3628/4264/19930 3627/4265/19931 3623/4263/19932 -f 3623/4263/19933 3624/4262/19934 3628/4264/19935 -f 3624/4262/19936 3625/4261/19937 3629/4266/19938 -f 3629/4266/19939 3628/4264/19940 3624/4262/19941 -f 3631/4269/19942 3630/4270/19943 3633/4267/19944 -f 3633/4267/19945 3632/4268/19946 3631/4269/19947 -f 3633/4267/19948 3634/4271/19949 3609/4247/19950 -f 3609/4247/19951 3610/4246/19952 3633/4267/19953 -f 3633/4267/19954 3630/4270/19955 3635/4272/19956 -f 3635/4272/19957 3634/4271/19958 3633/4267/19959 -f 3616/4253/19960 3617/4252/19961 3637/4273/19962 -f 3637/4273/19963 3636/4274/19964 3616/4253/19965 -f 3616/4253/19966 3638/4276/19967 3639/4275/19968 -f 3639/4275/19969 3619/4255/19970 3616/4253/19971 -f 3609/4247/19972 3640/4277/19973 3608/4248/19974 -f 3609/4247/19975 3641/4279/19976 3642/4278/19977 -f 3642/4278/19978 3640/4277/19979 3609/4247/19980 -f 3641/4279/19981 3643/4282/19982 3645/4280/19983 -f 3645/4280/19984 3644/4281/19985 3641/4279/19986 -f 3641/4279/19987 3644/4281/19988 3646/4283/19989 -f 3646/4283/19990 3642/4278/19991 3641/4279/19992 -f 3648/4286/19993 3647/4287/19994 3650/4284/19995 -f 3650/4284/19996 3649/4285/19997 3648/4286/19998 -f 3650/4284/19999 3647/4287/20000 3652/4288/20001 -f 3652/4288/20002 3651/4289/20003 3650/4284/20004 -f 3650/4284/20005 3651/4289/20006 3654/4290/20007 -f 3654/4290/20008 3653/4291/20009 3650/4284/20010 -f 3655/4293/20011 3620/4257/20012 3615/4254/20013 -f 3615/4254/20014 3656/4292/20015 3655/4293/20016 -f 3655/4293/20017 3656/4292/20018 3654/4290/20019 -f 3654/4290/20020 3651/4289/20021 3655/4293/20022 -f 3655/4293/20023 3651/4289/20024 3652/4288/20025 -f 3652/4288/20026 3620/4257/20027 3655/4293/20028 -f 3654/4290/20029 3656/4292/20030 3657/4294/20031 -f 3657/4294/20032 3653/4291/20033 3654/4290/20034 -f 3658/4297/20035 3613/4249/20036 3660/4295/20037 -f 3660/4295/20038 3659/4296/20039 3658/4297/20040 -f 3658/4297/20041 3661/4298/20042 3612/4250/20043 -f 3612/4250/20044 3613/4249/20045 3658/4297/20046 -f 3658/4297/20047 3659/4296/20048 3663/4299/20049 -f 3663/4299/20050 3662/4300/20051 3658/4297/20052 -f 3665/4303/20053 3664/4304/20054 3667/4301/20055 -f 3667/4301/20056 3666/4302/20057 3665/4303/20058 -f 3665/4303/20059 3668/4306/20060 3669/4305/20061 -f 3669/4305/20062 3664/4304/20063 3665/4303/20064 -f 3665/4303/20065 3666/4302/20066 3670/4307/20067 -f 3670/4307/20068 3668/4306/20069 3665/4303/20070 -f 3668/4306/20071 3670/4307/20072 3671/4308/20073 -f 3671/4308/20074 3669/4305/20075 3668/4306/20076 -f 3673/4311/20077 3672/4312/20078 3675/4309/20079 -f 3675/4309/20080 3674/4310/20081 3673/4311/20082 -f 3677/4314/20083 3676/4315/20084 3675/4309/20085 -f 3675/4309/20086 3678/4313/20087 3677/4314/20088 -f 3679/4316/20089 3674/4310/20090 3675/4309/20091 -f 3675/4309/20092 3676/4315/20093 3679/4316/20094 -f 3681/4318/20095 3680/4319/20096 3682/4317/20097 -f 3682/4317/20098 3666/4302/20099 3681/4318/20100 -f 3671/4308/20101 3683/4322/20102 3685/4320/20103 -f 3685/4320/20104 3684/4321/20105 3671/4308/20106 -f 3671/4308/20107 3670/4307/20108 3686/4323/20109 -f 3686/4323/20110 3683/4322/20111 3671/4308/20112 -f 3687/4325/20113 3669/4305/20114 3671/4308/20115 -f 3671/4308/20116 3688/4324/20117 3687/4325/20118 -f 3689/4326/20119 3688/4324/20120 3671/4308/20121 -f 3671/4308/20122 3684/4321/20123 3689/4326/20124 -f 3685/4320/20125 3690/4328/20126 3691/4327/20127 -f 3691/4327/20128 3684/4321/20129 3685/4320/20130 -f 3685/4320/20131 3683/4330/20132 3692/4329/20133 -f 3692/4329/20134 3690/4328/20135 3685/4320/20136 -f 3678/4313/20137 3675/4309/20138 3662/4300/20139 -f 3662/4300/20140 3693/4331/20141 3678/4313/20142 -f 3694/4332/20143 3677/4314/20144 3678/4313/20145 -f 3678/4313/20146 3693/4331/20147 3694/4332/20148 -f 3680/4335/20149 3681/4336/20150 3696/4333/20151 -f 3696/4333/20152 3695/4334/20153 3680/4335/20154 -f 3680/4335/20155 3695/4334/20156 3697/4337/20157 -f 3697/4337/20158 3682/4338/20159 3680/4335/20160 -f 3690/4328/20161 3692/4329/20162 3698/4339/20163 -f 3698/4339/20164 3691/4327/20165 3690/4328/20166 -f 3700/4342/20167 3699/4343/20168 3702/4340/20169 -f 3702/4340/20170 3701/4341/20171 3700/4342/20172 -f 3702/4340/20173 3699/4343/20174 3679/4316/20175 -f 3702/4340/20176 3703/4345/20177 3704/4344/20178 -f 3704/4344/20179 3701/4341/20180 3702/4340/20181 -f 3561/4189/20182 3705/4348/20183 3707/4346/20184 -f 3707/4346/20185 3706/4347/20186 3561/4189/20187 -f 3561/4189/20188 3562/4191/20189 3708/4349/20190 -f 3708/4349/20191 3705/4348/20192 3561/4189/20193 -f 3561/4189/20194 3706/4347/20195 3710/4350/20196 -f 3710/4350/20197 3709/4351/20198 3561/4189/20199 -f 3712/4352/20200 3711/4353/20201 3695/4334/20202 -f 3695/4334/20203 3696/4333/20204 3712/4352/20205 -f 3714/4356/20206 3713/4357/20207 3716/4354/20208 -f 3716/4354/20209 3715/4355/20210 3714/4356/20211 -f 3714/4356/20212 3715/4355/20213 3718/4358/20214 -f 3718/4358/20215 3717/4359/20216 3714/4356/20217 -f 3714/4356/20218 3717/4359/20219 3720/4360/20220 -f 3720/4360/20221 3719/4361/20222 3714/4356/20223 -f 3693/4331/20224 3721/4362/20225 3694/4332/20226 -f 3721/4362/20227 3722/4364/20228 3723/4363/20229 -f 3723/4363/20230 3694/4332/20231 3721/4362/20232 -f 3722/4364/20233 3724/4365/20234 3723/4363/20235 -f 3725/4367/20236 3703/4345/20237 3702/4340/20238 -f 3702/4340/20239 3726/4366/20240 3725/4367/20241 -f 3725/4367/20242 3726/4366/20243 3728/4368/20244 -f 3728/4368/20245 3727/4369/20246 3725/4367/20247 -f 3725/4367/20248 3727/4369/20249 3717/4359/20250 -f 3717/4359/20251 3718/4358/20252 3725/4367/20253 -f 3727/4369/20254 3728/4368/20255 3723/4363/20256 -f 3723/4363/20257 3724/4365/20258 3727/4369/20259 -f 3727/4369/20260 3724/4365/20261 3720/4360/20262 -f 3720/4360/20263 3717/4359/20264 3727/4369/20265 -f 3728/4368/20266 3677/4314/20267 3694/4332/20268 -f 3694/4332/20269 3723/4363/20270 3728/4368/20271 -f 3728/4368/20272 3726/4366/20273 3676/4315/20274 -f 3676/4315/20275 3677/4314/20276 3728/4368/20277 -f 3676/4315/20278 3726/4366/20279 3702/4340/20280 -f 3702/4340/20281 3679/4316/20282 3676/4315/20283 -f 3729/4370/20284 3674/4310/20285 3679/4316/20286 -f 3679/4316/20287 3699/4343/20288 3729/4370/20289 -f 3729/4370/20290 3699/4343/20291 3601/4371/20292 -f 3601/4371/20293 3730/4372/20294 3729/4370/20295 -f 3731/4374/20296 3729/4370/20297 3730/4372/20298 -f 3730/4372/20299 3732/4373/20300 3731/4374/20301 -f 3597/4236/20302 3733/4376/20303 3730/4375/20304 -f 3730/4375/20305 3601/4237/20306 3597/4236/20307 -f 3734/4377/20308 3732/4378/20309 3730/4375/20310 -f 3730/4375/20311 3733/4376/20312 3734/4377/20313 -f 3734/4377/20314 3733/4376/20315 3736/4379/20316 -f 3736/4379/20317 3735/4380/20318 3734/4377/20319 -f 3737/4382/20320 3734/4377/20321 3735/4380/20322 -f 3735/4380/20323 3738/4381/20324 3737/4382/20325 -f 3740/4383/20326 3739/4384/20327 3735/4380/20328 -f 3735/4380/20329 3736/4379/20330 3740/4383/20331 -f 3741/4385/20332 3738/4381/20333 3735/4380/20334 -f 3735/4380/20335 3739/4384/20336 3741/4385/20337 -f 3741/4385/20338 3739/4384/20339 3743/4386/20340 -f 3743/4386/20341 3742/4387/20342 3741/4385/20343 -f 3745/4388/20344 3744/4389/20345 3742/4387/20346 -f 3742/4387/20347 3743/4386/20348 3745/4388/20349 -f 3747/4390/20350 3746/4391/20351 3742/4387/20352 -f 3742/4387/20353 3744/4389/20354 3747/4390/20355 -f 3747/4390/20356 3744/4389/20357 3749/4392/20358 -f 3749/4392/20359 3748/4393/20360 3747/4390/20361 -f 3748/4393/20362 3749/4392/20363 3751/4394/20364 -f 3751/4394/20365 3750/4395/20366 3748/4393/20367 -f 3753/4396/20368 3752/4397/20369 3750/4395/20370 -f 3750/4395/20371 3751/4394/20372 3753/4396/20373 -f 3748/4393/20374 3754/4399/20375 3755/4398/20376 -f 3755/4398/20377 3747/4390/20378 3748/4393/20379 -f 3748/4393/20380 3750/4395/20381 3756/4400/20382 -f 3756/4400/20383 3754/4399/20384 3748/4393/20385 -f 3756/4400/20386 3750/4395/20387 3752/4397/20388 -f 3752/4397/20389 3757/4401/20390 3756/4400/20391 -f 3759/4403/20392 3758/4404/20393 3760/4402/20394 -f 3760/4402/20395 3746/4391/20396 3759/4403/20397 -f 3759/4403/20398 3746/4391/20399 3747/4390/20400 -f 3747/4390/20401 3755/4398/20402 3759/4403/20403 -f 3741/4385/20404 3742/4387/20405 3746/4391/20406 -f 3746/4391/20407 3760/4402/20408 3741/4385/20409 -f 3741/4385/20410 3760/4402/20411 3761/4405/20412 -f 3761/4405/20413 3738/4381/20414 3741/4385/20415 -f 3738/4381/20416 3761/4405/20417 3762/4406/20418 -f 3762/4406/20419 3737/4382/20420 3738/4381/20421 -f 3732/4378/20422 3734/4377/20423 3737/4382/20424 -f 3737/4382/20425 3763/4407/20426 3732/4378/20427 -f 3732/4373/20428 3763/4409/20429 3764/4408/20430 -f 3764/4408/20431 3731/4374/20432 3732/4373/20433 -f 3765/4410/20434 3673/4311/20435 3731/4374/20436 -f 3731/4374/20437 3764/4408/20438 3765/4410/20439 -f 3674/4310/20440 3729/4370/20441 3731/4374/20442 -f 3731/4374/20443 3673/4311/20444 3674/4310/20445 -f 3766/4411/20446 3672/4312/20447 3673/4311/20448 -f 3673/4311/20449 3765/4410/20450 3766/4411/20451 -f 3767/4412/20452 3661/4298/20453 3672/4312/20454 -f 3672/4312/20455 3766/4411/20456 3767/4412/20457 -f 3658/4297/20458 3675/4309/20459 3672/4312/20460 -f 3672/4312/20461 3661/4298/20462 3658/4297/20463 -f 3658/4297/20464 3662/4300/20465 3675/4309/20466 -f 3612/4250/20467 3661/4298/20468 3767/4412/20469 -f 3767/4412/20470 3614/4251/20471 3612/4250/20472 -f 3769/4413/20473 3768/4414/20474 3766/4411/20475 -f 3766/4411/20476 3765/4410/20477 3769/4413/20478 -f 3769/4413/20479 3765/4410/20480 3764/4408/20481 -f 3764/4408/20482 3770/4415/20483 3769/4413/20484 -f 3770/4415/20485 3764/4408/20486 3763/4409/20487 -f 3763/4409/20488 3771/4416/20489 3770/4415/20490 -f 3737/4382/20491 3762/4406/20492 3771/4417/20493 -f 3771/4417/20494 3763/4407/20495 3737/4382/20496 -f 3762/4406/20497 3772/4419/20498 3773/4418/20499 -f 3773/4418/20500 3771/4417/20501 3762/4406/20502 -f 3762/4406/20503 3761/4405/20504 3774/4420/20505 -f 3774/4420/20506 3772/4419/20507 3762/4406/20508 -f 3761/4405/20509 3760/4402/20510 3758/4404/20511 -f 3758/4404/20512 3774/4420/20513 3761/4405/20514 -f 3773/4421/20515 3775/4422/20516 3770/4415/20517 -f 3770/4415/20518 3771/4416/20519 3773/4421/20520 -f 3775/4422/20521 3776/4423/20522 3769/4413/20523 -f 3769/4413/20524 3770/4415/20525 3775/4422/20526 -f 3769/4413/20527 3776/4423/20528 3777/4424/20529 -f 3777/4424/20530 3768/4414/20531 3769/4413/20532 -f 3767/4412/20533 3766/4411/20534 3768/4414/20535 -f 3768/4414/20536 3778/4425/20537 3767/4412/20538 -f 3767/4412/20539 3778/4425/20540 3779/4426/20541 -f 3779/4426/20542 3614/4251/20543 3767/4412/20544 -f 3610/4246/20545 3614/4251/20546 3779/4426/20547 -f 3779/4426/20548 3632/4268/20549 3610/4246/20550 -f 3779/4426/20551 3780/4428/20552 3781/4427/20553 -f 3781/4427/20554 3632/4268/20555 3779/4426/20556 -f 3779/4426/20557 3778/4425/20558 3782/4429/20559 -f 3782/4429/20560 3780/4428/20561 3779/4426/20562 -f 3782/4429/20563 3778/4425/20564 3768/4414/20565 -f 3768/4414/20566 3777/4424/20567 3782/4429/20568 -f 3784/4430/20569 3783/4431/20570 3649/4285/20571 -f 3649/4285/20572 3631/4269/20573 3784/4430/20574 -f 3784/4430/20575 3631/4269/20576 3632/4268/20577 -f 3632/4268/20578 3781/4427/20579 3784/4430/20580 -f 3649/4285/20581 3783/4431/20582 3786/4432/20583 -f 3786/4432/20584 3785/4433/20585 3649/4285/20586 -f 3785/4433/20587 3648/4286/20588 3649/4285/20589 -f 3630/4270/20590 3631/4269/20591 3649/4285/20592 -f 3649/4285/20593 3650/4284/20594 3630/4270/20595 -f 3648/4286/20596 3785/4433/20597 3788/4434/20598 -f 3788/4434/20599 3787/4435/20600 3648/4286/20601 -f 3789/4436/20602 3647/4287/20603 3648/4286/20604 -f 3648/4286/20605 3787/4435/20606 3789/4436/20607 -f 3789/4436/20608 3787/4435/20609 3790/4437/20610 -f 3790/4437/20611 3569/4438/20612 3789/4436/20613 -f 3789/4436/20614 3569/4438/20615 3564/4219/20616 -f 3564/4219/20617 3586/4218/20618 3789/4436/20619 -f 3789/4436/20620 3586/4218/20621 3652/4288/20622 -f 3652/4288/20623 3647/4287/20624 3789/4436/20625 -f 3569/4199/20626 3790/4440/20627 3791/4439/20628 -f 3791/4439/20629 3570/4198/20630 3569/4199/20631 -f 3570/4198/20632 3791/4439/20633 3793/4441/20634 -f 3793/4441/20635 3792/4442/20636 3570/4198/20637 -f 3795/4443/20638 3794/4444/20639 3792/4442/20640 -f 3792/4442/20641 3793/4441/20642 3795/4443/20643 -f 3792/4442/20644 3794/4444/20645 3797/4445/20646 -f 3797/4445/20647 3796/4446/20648 3792/4442/20649 -f 3792/4442/20650 3796/4446/20651 3563/4195/20652 -f 3563/4195/20653 3570/4198/20654 3792/4442/20655 -f 3796/4446/20656 3797/4445/20657 3799/4447/20658 -f 3799/4447/20659 3798/4448/20660 3796/4446/20661 -f 3796/4446/20662 3798/4448/20663 3566/4192/20664 -f 3566/4192/20665 3563/4195/20666 3796/4446/20667 -f 3798/4448/20668 3799/4447/20669 3801/4449/20670 -f 3801/4449/20671 3800/4450/20672 3798/4448/20673 -f 3798/4448/20674 3800/4450/20675 3802/4451/20676 -f 3802/4451/20677 3566/4192/20678 3798/4448/20679 -f 3802/4451/20680 3800/4450/20681 3536/4162/20682 -f 3536/4162/20683 3537/4161/20684 3802/4451/20685 -f 3802/4451/20686 3537/4161/20687 3804/4452/20688 -f 3804/4452/20689 3803/4453/20690 3802/4451/20691 -f 3802/4451/20692 3803/4453/20693 3565/4193/20694 -f 3565/4193/20695 3566/4192/20696 3802/4451/20697 -f 3803/4453/20698 3804/4452/20699 3806/4454/20700 -f 3806/4454/20701 3805/4455/20702 3803/4453/20703 -f 3803/4453/20704 3805/4455/20705 3568/4196/20706 -f 3568/4196/20707 3565/4193/20708 3803/4453/20709 -f 3805/4456/20710 3806/4457/20711 3637/4273/20712 -f 3637/4273/20713 3617/4252/20714 3805/4456/20715 -f 3805/4456/20716 3617/4252/20717 3585/4214/20718 -f 3585/4214/20719 3568/4217/20720 3805/4456/20721 -f 3806/4457/20722 3807/4459/20723 3808/4458/20724 -f 3808/4458/20725 3637/4273/20726 3806/4457/20727 -f 3806/4454/20728 3804/4452/20729 3809/4460/20730 -f 3809/4460/20731 3807/4461/20732 3806/4454/20733 -f 3809/4460/20734 3810/4463/20735 3811/4462/20736 -f 3811/4462/20737 3807/4461/20738 3809/4460/20739 -f 3809/4460/20740 3804/4452/20741 3537/4161/20742 -f 3537/4161/20743 3538/4163/20744 3809/4460/20745 -f 3809/4460/20746 3538/4163/20747 3812/4464/20748 -f 3812/4464/20749 3810/4463/20750 3809/4460/20751 -f 3812/4464/20752 3813/4466/20753 3814/4465/20754 -f 3814/4465/20755 3810/4463/20756 3812/4464/20757 -f 3812/4464/20758 3538/4163/20759 3534/4158/20760 -f 3534/4158/20761 3815/4467/20762 3812/4464/20763 -f 3812/4464/20764 3815/4467/20765 3816/4468/20766 -f 3816/4468/20767 3813/4466/20768 3812/4464/20769 -f 3816/4468/20770 3817/4470/20771 3818/4469/20772 -f 3818/4469/20773 3813/4466/20774 3816/4468/20775 -f 3816/4468/20776 3815/4467/20777 3820/4471/20778 -f 3820/4471/20779 3819/4472/20780 3816/4468/20781 -f 3816/4468/20782 3819/4472/20783 3821/4473/20784 -f 3821/4473/20785 3817/4470/20786 3816/4468/20787 -f 3821/4473/20788 3572/4201/20789 3573/4200/20790 -f 3573/4200/20791 3817/4470/20792 3821/4473/20793 -f 3821/4473/20794 3819/4472/20795 3822/4474/20796 -f 3822/4474/20797 3583/4213/20798 3821/4473/20799 -f 3821/4473/20800 3583/4213/20801 3576/4205/20802 -f 3576/4205/20803 3572/4201/20804 3821/4473/20805 -f 3822/4474/20806 3819/4472/20807 3820/4471/20808 -f 3820/4471/20809 3823/4475/20810 3822/4474/20811 -f 3824/4476/20812 3605/4242/20813 3596/4233/20814 -f 3824/4476/20815 3825/4479/20816 3827/4477/20817 -f 3827/4477/20818 3826/4478/20819 3824/4476/20820 -f 3824/4476/20821 3826/4478/20822 3606/4243/20823 -f 3606/4243/20824 3605/4242/20825 3824/4476/20826 -f 3826/4478/20827 3827/4477/20828 3829/4480/20829 -f 3829/4480/20830 3828/4481/20831 3826/4478/20832 -f 3826/4478/20833 3828/4481/20834 3607/4244/20835 -f 3607/4244/20836 3606/4243/20837 3826/4478/20838 -f 3828/4481/20839 3829/4480/20840 3830/4482/20841 -f 3830/4482/20842 3590/4223/20843 3828/4481/20844 -f 3828/4481/20845 3590/4223/20846 3591/4227/20847 -f 3591/4227/20848 3607/4244/20849 3828/4481/20850 -f 3830/4482/20851 3829/4480/20852 3832/4483/20853 -f 3832/4483/20854 3831/4484/20855 3830/4482/20856 -f 3830/4482/20857 3831/4484/20858 3833/4485/20859 -f 3833/4485/20860 3589/4224/20861 3830/4482/20862 -f 3830/4482/20863 3589/4224/20864 3590/4223/20865 -f 3833/4485/20866 3831/4484/20867 3835/4486/20868 -f 3835/4486/20869 3834/4487/20870 3833/4485/20871 -f 3833/4485/20872 3834/4487/20873 3836/4488/20874 -f 3836/4488/20875 3582/4209/20876 3833/4485/20877 -f 3833/4485/20878 3582/4209/20879 3580/4212/20880 -f 3580/4212/20881 3589/4224/20882 3833/4485/20883 -f 3836/4488/20884 3834/4487/20885 3837/4489/20886 -f 3837/4489/20887 3808/4458/20888 3836/4488/20889 -f 3836/4488/20890 3808/4458/20891 3807/4459/20892 -f 3807/4459/20893 3811/4490/20894 3836/4488/20895 -f 3836/4488/20896 3811/4490/20897 3581/4210/20898 -f 3581/4210/20899 3582/4209/20900 3836/4488/20901 -f 3837/4489/20902 3834/4487/20903 3835/4486/20904 -f 3835/4486/20905 3838/4491/20906 3837/4489/20907 -f 3837/4489/20908 3838/4491/20909 3839/4492/20910 -f 3839/4492/20911 3636/4274/20912 3837/4489/20913 -f 3837/4489/20914 3636/4274/20915 3637/4273/20916 -f 3637/4273/20917 3808/4458/20918 3837/4489/20919 -f 3839/4492/20920 3838/4491/20921 3840/4493/20922 -f 3840/4493/20923 3625/4261/20924 3839/4492/20925 -f 3839/4492/20926 3625/4261/20927 3626/4260/20928 -f 3626/4260/20929 3638/4276/20930 3839/4492/20931 -f 3839/4492/20932 3638/4276/20933 3616/4253/20934 -f 3616/4253/20935 3636/4274/20936 3839/4492/20937 -f 3840/4493/20938 3841/4496/20939 3843/4494/20940 -f 3843/4494/20941 3842/4495/20942 3840/4493/20943 -f 3840/4493/20944 3842/4495/20945 3629/4266/20946 -f 3629/4266/20947 3625/4261/20948 3840/4493/20949 -f 3840/4493/20950 3838/4491/20951 3835/4486/20952 -f 3835/4486/20953 3841/4496/20954 3840/4493/20955 -f 3842/4495/20956 3843/4494/20957 3845/4497/20958 -f 3845/4497/20959 3844/4498/20960 3842/4495/20961 -f 3842/4495/20962 3844/4498/20963 3846/4499/20964 -f 3846/4499/20965 3629/4266/20966 3842/4495/20967 -f 3846/4499/20968 3847/4500/20969 3628/4264/20970 -f 3628/4264/20971 3629/4266/20972 3846/4499/20973 -f 3845/4497/20974 3843/4494/20975 3849/4501/20976 -f 3849/4501/20977 3848/4502/20978 3845/4497/20979 -f 3849/4501/20980 3827/4477/20981 3825/4479/20982 -f 3825/4479/20983 3848/4502/20984 3849/4501/20985 -f 3849/4501/20986 3843/4494/20987 3841/4496/20988 -f 3841/4496/20989 3832/4483/20990 3849/4501/20991 -f 3849/4501/20992 3832/4483/20993 3829/4480/20994 -f 3829/4480/20995 3827/4477/20996 3849/4501/20997 -f 3841/4496/20998 3835/4486/20999 3831/4484/21000 -f 3831/4484/21001 3832/4483/21002 3841/4496/21003 -f 3850/4504/21004 3823/4475/21005 3820/4471/21006 -f 3820/4471/21007 3851/4503/21008 3850/4504/21009 -f 3850/4504/21010 3851/4503/21011 3540/4166/21012 -f 3540/4166/21013 3543/4169/21014 3850/4504/21015 -f 3851/4503/21016 3820/4471/21017 3815/4467/21018 -f 3815/4467/21019 3534/4158/21020 3851/4503/21021 -f 3851/4503/21022 3534/4158/21023 3535/4157/21024 -f 3535/4157/21025 3540/4166/21026 3851/4503/21027 -f 3818/4469/21028 3575/4203/21029 3578/4208/21030 -f 3818/4469/21031 3578/4208/21032 3814/4465/21033 -f 3814/4465/21034 3813/4466/21035 3818/4469/21036 -f 3818/4469/21037 3817/4470/21038 3573/4200/21039 -f 3573/4200/21040 3575/4203/21041 3818/4469/21042 -f 3814/4465/21043 3578/4208/21044 3579/4207/21045 -f 3579/4207/21046 3581/4505/21047 3814/4465/21048 -f 3814/4465/21049 3581/4505/21050 3811/4462/21051 -f 3811/4462/21052 3810/4463/21053 3814/4465/21054 -f 3799/4447/21055 3797/4445/21056 3518/4144/21057 -f 3518/4144/21058 3519/4143/21059 3799/4447/21060 -f 3799/4447/21061 3519/4143/21062 3530/4154/21063 -f 3530/4154/21064 3801/4449/21065 3799/4447/21066 -f 3797/4445/21067 3794/4444/21068 3520/4145/21069 -f 3520/4145/21070 3518/4144/21071 3797/4445/21072 -f 3520/4145/21073 3794/4444/21074 3494/4115/21075 -f 3494/4115/21076 3491/4118/21077 3520/4145/21078 -f 3791/4439/21079 3852/4507/21080 3853/4506/21081 -f 3853/4506/21082 3793/4441/21083 3791/4439/21084 -f 3852/4507/21085 3791/4439/21086 3855/4508/21087 -f 3855/4508/21088 3854/4509/21089 3852/4507/21090 -f 3857/4512/21091 3856/4513/21092 3859/4510/21093 -f 3859/4510/21094 3858/4511/21095 3857/4512/21096 -f 3857/4512/21097 3860/4515/21098 3861/4514/21099 -f 3861/4514/21100 3856/4513/21101 3857/4512/21102 -f 3862/4517/21103 3856/4513/21104 3861/4514/21105 -f 3861/4514/21106 3863/4516/21107 3862/4517/21108 -f 3861/4514/21109 3860/4515/21110 3757/4401/21111 -f 3757/4401/21112 3752/4397/21113 3861/4514/21114 -f 3859/4510/21115 3856/4513/21116 3862/4517/21117 -f 3862/4517/21118 3506/4131/21119 3859/4510/21120 -f 3863/4516/21121 3861/4514/21122 3752/4397/21123 -f 3752/4397/21124 3753/4396/21125 3863/4516/21126 -f 3864/4519/21127 3753/4396/21128 3751/4394/21129 -f 3751/4394/21130 3865/4518/21131 3864/4519/21132 -f 3866/4520/21133 3865/4518/21134 3751/4394/21135 -f 3751/4394/21136 3749/4392/21137 3866/4520/21138 -f 3866/4520/21139 3749/4392/21140 3744/4389/21141 -f 3744/4389/21142 3745/4388/21143 3866/4520/21144 -f 3460/4084/21145 3864/4519/21146 3865/4518/21147 -f 3865/4518/21148 3459/4080/21149 3460/4084/21150 -f 3458/4081/21151 3459/4080/21152 3865/4518/21153 -f 3865/4518/21154 3866/4520/21155 3458/4081/21156 -f 3458/4081/21157 3866/4520/21158 3745/4388/21159 -f 3745/4388/21160 3867/4521/21161 3458/4081/21162 -f 3868/4522/21163 3457/4082/21164 3458/4081/21165 -f 3458/4081/21166 3867/4521/21167 3868/4522/21168 -f 3868/4522/21169 3867/4521/21170 3870/4523/21171 -f 3870/4523/21172 3869/4524/21173 3868/4522/21174 -f 3871/4525/21175 3440/4062/21176 3868/4522/21177 -f 3868/4522/21178 3869/4524/21179 3871/4525/21180 -f 3436/4059/21181 3457/4082/21182 3868/4522/21183 -f 3868/4522/21184 3440/4062/21185 3436/4059/21186 -f 3445/4067/21187 3457/4082/21188 3436/4059/21189 -f 3436/4059/21190 3431/4054/21191 3445/4067/21192 -f 3423/4047/21193 3445/4067/21194 3431/4054/21195 -f 3431/4054/21196 3419/4045/21197 3423/4047/21198 -f 3873/4526/21199 3872/4527/21200 3871/4525/21201 -f 3871/4525/21202 3869/4524/21203 3873/4526/21204 -f 3871/4525/21205 3872/4527/21206 3875/4528/21207 -f 3875/4528/21208 3874/4529/21209 3871/4525/21210 -f 3871/4525/21211 3874/4529/21212 3439/4063/21213 -f 3439/4063/21214 3440/4062/21215 3871/4525/21216 -f 3874/4529/21217 3875/4528/21218 3877/4530/21219 -f 3877/4530/21220 3876/4531/21221 3874/4529/21222 -f 3874/4529/21223 3876/4531/21224 3441/4064/21225 -f 3441/4064/21226 3439/4063/21227 3874/4529/21228 -f 3876/4531/21229 3877/4530/21230 3467/4532/21231 -f 3467/4532/21232 3878/4533/21233 3876/4531/21234 -f 3876/4531/21235 3878/4533/21236 3879/4534/21237 -f 3879/4534/21238 3441/4064/21239 3876/4531/21240 -f 3416/4039/21241 3415/4038/21242 3879/4535/21243 -f 3879/4535/21244 3878/4536/21245 3416/4039/21246 -f 3879/4534/21247 3880/4537/21248 3437/4061/21249 -f 3437/4061/21250 3441/4064/21251 3879/4534/21252 -f 3880/4537/21253 3881/4538/21254 3438/4060/21255 -f 3438/4060/21256 3437/4061/21257 3880/4537/21258 -f 3881/4538/21259 3882/4540/21260 3883/4539/21261 -f 3883/4539/21262 3438/4060/21263 3881/4538/21264 -f 3883/4539/21265 3882/4540/21266 3885/4541/21267 -f 3885/4541/21268 3884/4542/21269 3883/4539/21270 -f 3883/4539/21271 3884/4542/21272 3887/4543/21273 -f 3887/4543/21274 3886/4544/21275 3883/4539/21276 -f 3883/4539/21277 3886/4544/21278 3434/4058/21279 -f 3434/4058/21280 3438/4060/21281 3883/4539/21282 -f 3886/4544/21283 3887/4543/21284 3888/4545/21285 -f 3888/4545/21286 3456/4079/21287 3886/4544/21288 -f 3886/4544/21289 3456/4079/21290 3430/4051/21291 -f 3430/4051/21292 3434/4058/21293 3886/4544/21294 -f 3888/4545/21295 3887/4543/21296 3890/4546/21297 -f 3890/4546/21298 3889/4547/21299 3888/4545/21300 -f 3888/4545/21301 3889/4547/21302 3892/4548/21303 -f 3892/4548/21304 3891/4549/21305 3888/4545/21306 -f 3888/4545/21307 3891/4549/21308 3455/4077/21309 -f 3455/4077/21310 3456/4079/21311 3888/4545/21312 -f 3891/4549/21313 3892/4548/21314 3562/4191/21315 -f 3562/4191/21316 3558/4186/21317 3891/4549/21318 -f 3891/4549/21319 3558/4186/21320 3893/4550/21321 -f 3893/4550/21322 3455/4077/21323 3891/4549/21324 -f 3893/4550/21325 3513/4138/21326 3454/4078/21327 -f 3454/4078/21328 3455/4077/21329 3893/4550/21330 -f 3893/4550/21331 3558/4186/21332 3559/4185/21333 -f 3559/4185/21334 3894/4551/21335 3893/4550/21336 -f 3893/4550/21337 3894/4551/21338 3512/4136/21339 -f 3512/4136/21340 3513/4138/21341 3893/4550/21342 -f 3894/4551/21343 3895/4553/21344 3896/4552/21345 -f 3896/4552/21346 3512/4136/21347 3894/4551/21348 -f 3894/4551/21349 3559/4185/21350 3897/4554/21351 -f 3897/4554/21352 3895/4553/21353 3894/4551/21354 -f 3897/4554/21355 3898/4556/21356 3899/4555/21357 -f 3899/4555/21358 3895/4553/21359 3897/4554/21360 -f 3897/4554/21361 3559/4185/21362 3556/4188/21363 -f 3556/4188/21364 3900/4557/21365 3897/4554/21366 -f 3897/4554/21367 3900/4557/21368 3901/4558/21369 -f 3901/4558/21370 3898/4556/21371 3897/4554/21372 -f 3901/4558/21373 3902/4560/21374 3903/4559/21375 -f 3903/4559/21376 3898/4556/21377 3901/4558/21378 -f 3901/4558/21379 3900/4557/21380 3905/4561/21381 -f 3905/4561/21382 3904/4562/21383 3901/4558/21384 -f 3901/4558/21385 3904/4562/21386 3906/4563/21387 -f 3906/4563/21388 3902/4560/21389 3901/4558/21390 -f 3906/4563/21391 3907/4565/21392 3908/4564/21393 -f 3908/4564/21394 3902/4560/21395 3906/4563/21396 -f 3906/4563/21397 3904/4562/21398 3910/4566/21399 -f 3910/4566/21400 3909/4567/21401 3906/4563/21402 -f 3906/4563/21403 3909/4567/21404 3911/4568/21405 -f 3911/4568/21406 3907/4565/21407 3906/4563/21408 -f 3911/4568/21409 3626/4260/21410 3623/4263/21411 -f 3623/4263/21412 3907/4565/21413 3911/4568/21414 -f 3911/4568/21415 3909/4567/21416 3912/4569/21417 -f 3912/4569/21418 3639/4275/21419 3911/4568/21420 -f 3911/4568/21421 3639/4275/21422 3638/4276/21423 -f 3638/4276/21424 3626/4260/21425 3911/4568/21426 -f 3912/4569/21427 3909/4567/21428 3910/4566/21429 -f 3910/4566/21430 3913/4570/21431 3912/4569/21432 -f 3912/4569/21433 3913/4570/21434 3643/4282/21435 -f 3643/4282/21436 3914/4571/21437 3912/4569/21438 -f 3912/4569/21439 3914/4571/21440 3619/4255/21441 -f 3619/4255/21442 3639/4275/21443 3912/4569/21444 -f 3914/4571/21445 3643/4282/21446 3641/4279/21447 -f 3641/4279/21448 3915/4572/21449 3914/4571/21450 -f 3914/4571/21451 3915/4572/21452 3618/4256/21453 -f 3618/4256/21454 3619/4255/21455 3914/4571/21456 -f 3913/4570/21457 3910/4566/21458 3917/4573/21459 -f 3917/4573/21460 3916/4574/21461 3913/4570/21462 -f 3913/4570/21463 3916/4574/21464 3645/4280/21465 -f 3645/4280/21466 3643/4282/21467 3913/4570/21468 -f 3916/4574/21469 3917/4573/21470 3919/4575/21471 -f 3919/4575/21472 3918/4576/21473 3916/4574/21474 -f 3918/4576/21475 3921/4577/21476 3920/4578/21477 -f 3916/4574/21478 3918/4576/21479 3920/4578/21480 -f 3920/4578/21481 3645/4280/21482 3916/4574/21483 -f 3920/4578/21484 3921/4577/21485 3922/4579/21486 -f 3920/4578/21487 3922/4579/21488 3924/4580/21489 -f 3924/4580/21490 3923/4581/21491 3920/4578/21492 -f 3920/4578/21493 3923/4581/21494 3644/4281/21495 -f 3644/4281/21496 3645/4280/21497 3920/4578/21498 -f 3923/4581/21499 3924/4580/21500 3926/4582/21501 -f 3926/4582/21502 3925/4583/21503 3923/4581/21504 -f 3923/4581/21505 3925/4583/21506 3646/4283/21507 -f 3646/4283/21508 3644/4281/21509 3923/4581/21510 -f 3925/4583/21511 3926/4582/21512 3928/4584/21513 -f 3928/4584/21514 3927/4585/21515 3925/4583/21516 -f 3925/4583/21517 3927/4585/21518 3929/4586/21519 -f 3929/4586/21520 3646/4283/21521 3925/4583/21522 -f 3929/4586/21523 3930/4587/21524 3642/4278/21525 -f 3642/4278/21526 3646/4283/21527 3929/4586/21528 -f 3929/4586/21529 3927/4585/21530 3714/4356/21531 -f 3714/4356/21532 3719/4361/21533 3929/4586/21534 -f 3929/4586/21535 3719/4361/21536 3931/4588/21537 -f 3931/4588/21538 3930/4587/21539 3929/4586/21540 -f 3931/4588/21541 3659/4296/21542 3660/4295/21543 -f 3660/4295/21544 3930/4587/21545 3931/4588/21546 -f 3931/4588/21547 3719/4361/21548 3720/4360/21549 -f 3720/4360/21550 3932/4589/21551 3931/4588/21552 -f 3931/4588/21553 3932/4589/21554 3663/4299/21555 -f 3663/4299/21556 3659/4296/21557 3931/4588/21558 -f 3932/4589/21559 3720/4360/21560 3724/4365/21561 -f 3724/4365/21562 3722/4364/21563 3932/4589/21564 -f 3932/4589/21565 3722/4364/21566 3721/4362/21567 -f 3721/4362/21568 3663/4299/21569 3932/4589/21570 -f 3930/4587/21571 3660/4295/21572 3640/4277/21573 -f 3640/4277/21574 3642/4278/21575 3930/4587/21576 -f 3927/4585/21577 3928/4584/21578 3713/4357/21579 -f 3713/4357/21580 3714/4356/21581 3927/4585/21582 -f 3933/4590/21583 3921/4577/21584 3918/4576/21585 -f 3933/4590/21586 3918/4576/21587 3935/4591/21588 -f 3935/4591/21589 3934/4592/21590 3933/4590/21591 -f 3934/4592/21592 3935/4591/21593 3937/4593/21594 -f 3937/4593/21595 3936/4594/21596 3934/4592/21597 -f 3937/4593/21598 3935/4591/21599 3939/4595/21600 -f 3939/4595/21601 3938/4596/21602 3937/4593/21603 -f 3937/4593/21604 3938/4596/21605 3718/4358/21606 -f 3718/4358/21607 3715/4355/21608 3937/4593/21609 -f 3937/4593/21610 3715/4355/21611 3716/4354/21612 -f 3716/4354/21613 3936/4594/21614 3937/4593/21615 -f 3938/4596/21616 3939/4595/21617 3709/4351/21618 -f 3709/4351/21619 3710/4350/21620 3938/4596/21621 -f 3938/4596/21622 3710/4350/21623 3725/4367/21624 -f 3725/4367/21625 3718/4358/21626 3938/4596/21627 -f 3939/4595/21628 3918/4576/21629 3919/4575/21630 -f 3919/4575/21631 3709/4351/21632 3939/4595/21633 -f 3939/4595/21634 3935/4591/21635 3918/4576/21636 -f 3919/4575/21637 3917/4573/21638 3905/4561/21639 -f 3905/4561/21640 3560/4190/21641 3919/4575/21642 -f 3919/4575/21643 3560/4190/21644 3561/4189/21645 -f 3561/4189/21646 3709/4351/21647 3919/4575/21648 -f 3917/4573/21649 3910/4566/21650 3904/4562/21651 -f 3904/4562/21652 3905/4561/21653 3917/4573/21654 -f 3908/4564/21655 3627/4265/21656 3542/4164/21657 -f 3542/4164/21658 3940/4597/21659 3908/4564/21660 -f 3908/4564/21661 3940/4597/21662 3903/4559/21663 -f 3903/4559/21664 3902/4560/21665 3908/4564/21666 -f 3908/4564/21667 3907/4565/21668 3623/4263/21669 -f 3623/4263/21670 3627/4265/21671 3908/4564/21672 -f 3940/4597/21673 3542/4164/21674 3539/4167/21675 -f 3539/4167/21676 3941/4598/21677 3940/4597/21678 -f 3940/4597/21679 3941/4598/21680 3942/4599/21681 -f 3942/4599/21682 3903/4559/21683 3940/4597/21684 -f 3942/4599/21685 3941/4598/21686 3944/4600/21687 -f 3944/4600/21688 3943/4601/21689 3942/4599/21690 -f 3942/4599/21691 3943/4601/21692 3945/4602/21693 -f 3945/4602/21694 3899/4555/21695 3942/4599/21696 -f 3942/4599/21697 3899/4555/21698 3898/4556/21699 -f 3898/4556/21700 3903/4559/21701 3942/4599/21702 -f 3945/4602/21703 3943/4601/21704 3947/4603/21705 -f 3947/4603/21706 3946/4604/21707 3945/4602/21708 -f 3945/4602/21709 3946/4604/21710 3948/4605/21711 -f 3948/4605/21712 3896/4552/21713 3945/4602/21714 -f 3945/4602/21715 3896/4552/21716 3895/4553/21717 -f 3895/4553/21718 3899/4555/21719 3945/4602/21720 -f 3948/4605/21721 3946/4604/21722 3950/4606/21723 -f 3950/4606/21724 3949/4607/21725 3948/4605/21726 -f 3948/4605/21727 3949/4607/21728 3488/4110/21729 -f 3488/4110/21730 3511/4137/21731 3948/4605/21732 -f 3948/4605/21733 3511/4137/21734 3512/4136/21735 -f 3512/4136/21736 3896/4552/21737 3948/4605/21738 -f 3949/4607/21739 3950/4606/21740 3490/4113/21741 -f 3490/4113/21742 3489/4114/21743 3949/4607/21744 -f 3949/4607/21745 3489/4114/21746 3487/4111/21747 -f 3487/4111/21748 3488/4110/21749 3949/4607/21750 -f 3950/4606/21751 3951/4609/21752 3952/4608/21753 -f 3952/4608/21754 3490/4113/21755 3950/4606/21756 -f 3950/4606/21757 3946/4604/21758 3947/4603/21759 -f 3947/4603/21760 3951/4609/21761 3950/4606/21762 -f 3952/4608/21763 3953/4610/21764 3492/4117/21765 -f 3492/4117/21766 3478/4099/21767 3952/4608/21768 -f 3952/4608/21769 3478/4099/21770 3475/4102/21771 -f 3475/4102/21772 3490/4113/21773 3952/4608/21774 -f 3952/4608/21775 3951/4609/21776 3528/4150/21777 -f 3528/4150/21778 3953/4610/21779 3952/4608/21780 -f 3953/4610/21781 3954/4611/21782 3491/4118/21783 -f 3491/4118/21784 3492/4117/21785 3953/4610/21786 -f 3953/4610/21787 3528/4150/21788 3525/4153/21789 -f 3525/4153/21790 3954/4611/21791 3953/4610/21792 -f 3951/4609/21793 3947/4603/21794 3527/4151/21795 -f 3527/4151/21796 3528/4150/21797 3951/4609/21798 -f 3947/4603/21799 3943/4601/21800 3944/4600/21801 -f 3944/4600/21802 3527/4151/21803 3947/4603/21804 -f 3944/4600/21805 3545/4170/21806 3531/4156/21807 -f 3531/4156/21808 3527/4151/21809 3944/4600/21810 -f 3944/4600/21811 3941/4598/21812 3539/4167/21813 -f 3539/4167/21814 3545/4170/21815 3944/4600/21816 -f 3905/4561/21817 3900/4557/21818 3556/4188/21819 -f 3556/4188/21820 3560/4190/21821 3905/4561/21822 -f 3892/4548/21823 3889/4547/21824 3956/4612/21825 -f 3956/4612/21826 3955/4613/21827 3892/4548/21828 -f 3892/4548/21829 3955/4613/21830 3708/4349/21831 -f 3708/4349/21832 3562/4191/21833 3892/4548/21834 -f 3955/4613/21835 3956/4612/21836 3958/4614/21837 -f 3958/4614/21838 3957/4615/21839 3955/4613/21840 -f 3955/4613/21841 3957/4615/21842 3959/4616/21843 -f 3959/4616/21844 3708/4349/21845 3955/4613/21846 -f 3959/4616/21847 3957/4615/21848 3961/4617/21849 -f 3961/4617/21850 3960/4618/21851 3959/4616/21852 -f 3959/4616/21853 3960/4618/21854 3963/4619/21855 -f 3963/4619/21856 3962/4620/21857 3959/4616/21858 -f 3959/4616/21859 3962/4620/21860 3705/4348/21861 -f 3705/4348/21862 3708/4349/21863 3959/4616/21864 -f 3962/4620/21865 3963/4619/21866 3965/4621/21867 -f 3965/4621/21868 3964/4622/21869 3962/4620/21870 -f 3962/4620/21871 3964/4622/21872 3707/4346/21873 -f 3707/4346/21874 3705/4348/21875 3962/4620/21876 -f 3964/4622/21877 3965/4621/21878 3967/4623/21879 -f 3967/4623/21880 3966/4624/21881 3964/4622/21882 -f 3964/4622/21883 3966/4624/21884 3704/4344/21885 -f 3704/4344/21886 3707/4346/21887 3964/4622/21888 -f 3966/4624/21889 3967/4623/21890 3969/4625/21891 -f 3969/4625/21892 3968/4626/21893 3966/4624/21894 -f 3966/4624/21895 3968/4626/21896 3701/4341/21897 -f 3701/4341/21898 3704/4344/21899 3966/4624/21900 -f 3968/4626/21901 3969/4625/21902 3971/4627/21903 -f 3971/4627/21904 3970/4628/21905 3968/4626/21906 -f 3968/4626/21907 3970/4628/21908 3700/4342/21909 -f 3700/4342/21910 3701/4341/21911 3968/4626/21912 -f 3970/4628/21913 3971/4627/21914 3972/4629/21915 -f 3972/4629/21916 3604/4630/21917 3970/4628/21918 -f 3970/4628/21919 3604/4630/21920 3600/4631/21921 -f 3600/4631/21922 3700/4342/21923 3970/4628/21924 -f 3972/4634/21925 3971/4635/21926 3974/4632/21927 -f 3974/4632/21928 3973/4633/21929 3972/4634/21930 -f 3972/4634/21931 3973/4633/21932 3976/4636/21933 -f 3976/4636/21934 3975/4637/21935 3972/4634/21936 -f 3972/4638/21937 3975/4639/21938 3602/4240/21939 -f 3602/4240/21940 3604/4241/21941 3972/4638/21942 -f 3975/4637/21943 3976/4636/21944 3978/4640/21945 -f 3978/4640/21946 3977/4641/21947 3975/4637/21948 -f 3975/4639/21949 3977/4642/21950 3603/4239/21951 -f 3603/4239/21952 3602/4240/21953 3975/4639/21954 -f 3976/4636/21955 3973/4633/21956 3980/4643/21957 -f 3980/4643/21958 3979/4644/21959 3976/4636/21960 -f 3976/4636/21961 3979/4644/21962 3981/4645/21963 -f 3981/4645/21964 3978/4640/21965 3976/4636/21966 -f 3981/4645/21967 3979/4644/21968 3983/4646/21969 -f 3983/4646/21970 3982/4647/21971 3981/4645/21972 -f 3981/4650/21973 3982/4651/21974 3985/4648/21975 -f 3985/4648/21976 3984/4649/21977 3981/4650/21978 -f 3981/4650/21979 3984/4649/21980 3554/4184/21981 -f 3554/4184/21982 3978/4652/21983 3981/4650/21984 -f 3984/4649/21985 3985/4648/21986 3987/4653/21987 -f 3987/4653/21988 3986/4654/21989 3984/4649/21990 -f 3984/4649/21991 3986/4654/21992 3555/4181/21993 -f 3555/4181/21994 3554/4184/21995 3984/4649/21996 -f 3987/4653/21997 3985/4648/21998 3989/4655/21999 -f 3989/4655/22000 3988/4656/22001 3987/4653/22002 -f 3987/4653/22003 3988/4656/22004 3991/4657/22005 -f 3991/4657/22006 3990/4658/22007 3987/4653/22008 -f 3987/4653/22009 3990/4658/22010 3555/4181/22011 -f 3555/4181/22012 3986/4654/22013 3987/4653/22014 -f 3990/4658/22015 3991/4657/22016 3993/4659/22017 -f 3993/4659/22018 3992/4660/22019 3990/4658/22020 -f 3990/4658/22021 3992/4660/22022 3621/4259/22023 -f 3621/4259/22024 3555/4181/22025 3990/4658/22026 -f 3992/4660/22027 3993/4659/22028 3995/4661/22029 -f 3995/4661/22030 3994/4662/22031 3992/4660/22032 -f 3992/4660/22033 3994/4662/22034 3996/4663/22035 -f 3996/4663/22036 3621/4259/22037 3992/4660/22038 -f 3996/4663/22039 3997/4664/22040 3622/4258/22041 -f 3622/4258/22042 3621/4259/22043 3996/4663/22044 -f 3996/4663/22045 3994/4662/22046 3999/4665/22047 -f 3999/4665/22048 3998/4666/22049 3996/4663/22050 -f 3996/4663/22051 3998/4666/22052 4000/4667/22053 -f 4000/4667/22054 3997/4664/22055 3996/4663/22056 -f 4000/4669/22057 3960/4618/22058 3961/4617/22059 -f 3961/4617/22060 3997/4668/22061 4000/4669/22062 -f 4000/4667/22063 3998/4666/22064 4002/4670/22065 -f 4002/4670/22066 4001/4671/22067 4000/4667/22068 -f 4000/4669/22069 4001/4672/22070 3963/4619/22071 -f 3963/4619/22072 3960/4618/22073 4000/4669/22074 -f 4001/4671/22075 4002/4670/22076 4004/4673/22077 -f 4004/4673/22078 4003/4674/22079 4001/4671/22080 -f 4001/4672/22081 4003/4675/22082 3965/4621/22083 -f 3965/4621/22084 3963/4619/22085 4001/4672/22086 -f 4003/4674/22087 4004/4673/22088 4006/4676/22089 -f 4006/4676/22090 4005/4677/22091 4003/4674/22092 -f 4003/4675/22093 4005/4678/22094 3967/4623/22095 -f 3967/4623/22096 3965/4621/22097 4003/4675/22098 -f 4005/4677/22099 4006/4676/22100 4008/4679/22101 -f 4008/4679/22102 4007/4680/22103 4005/4677/22104 -f 4005/4678/22105 4007/4681/22106 3969/4625/22107 -f 3969/4625/22108 3967/4623/22109 4005/4678/22110 -f 4007/4680/22111 4008/4679/22112 4009/4682/22113 -f 4009/4682/22114 3974/4632/22115 4007/4680/22116 -f 4007/4681/22117 3974/4683/22118 3971/4627/22119 -f 3971/4627/22120 3969/4625/22121 4007/4681/22122 -f 4009/4682/22123 4008/4679/22124 4011/4684/22125 -f 4011/4684/22126 4010/4685/22127 4009/4682/22128 -f 4009/4682/22129 4010/4685/22130 4012/4686/22131 -f 4012/4686/22132 3980/4643/22133 4009/4682/22134 -f 4009/4682/22135 3980/4643/22136 3973/4633/22137 -f 3973/4633/22138 3974/4632/22139 4009/4682/22140 -f 4012/4686/22141 4010/4685/22142 4014/4687/22143 -f 4014/4687/22144 4013/4688/22145 4012/4686/22146 -f 4012/4686/22147 4013/4688/22148 4015/4689/22149 -f 4015/4689/22150 3983/4646/22151 4012/4686/22152 -f 4012/4686/22153 3983/4646/22154 3979/4644/22155 -f 3979/4644/22156 3980/4643/22157 4012/4686/22158 -f 4015/4689/22159 4013/4688/22160 4017/4690/22161 -f 4017/4690/22162 4016/4691/22163 4015/4689/22164 -f 4015/4689/22165 4016/4691/22166 4019/4692/22167 -f 4019/4692/22168 4018/4693/22169 4015/4689/22170 -f 4015/4689/22171 4018/4693/22172 3982/4647/22173 -f 3982/4647/22174 3983/4646/22175 4015/4689/22176 -f 4018/4695/22177 4019/4696/22178 4020/4694/22179 -f 4020/4694/22180 3989/4655/22181 4018/4695/22182 -f 4018/4695/22183 3989/4655/22184 3985/4648/22185 -f 3985/4648/22186 3982/4651/22187 4018/4695/22188 -f 4020/4694/22189 4019/4696/22190 4022/4697/22191 -f 4022/4697/22192 4021/4698/22193 4020/4694/22194 -f 4020/4694/22195 4021/4698/22196 4024/4699/22197 -f 4024/4699/22198 4023/4700/22199 4020/4694/22200 -f 4020/4694/22201 4023/4700/22202 3988/4656/22203 -f 3988/4656/22204 3989/4655/22205 4020/4694/22206 -f 4023/4700/22207 4024/4699/22208 4026/4701/22209 -f 4026/4701/22210 4025/4702/22211 4023/4700/22212 -f 4023/4700/22213 4025/4702/22214 3991/4657/22215 -f 3991/4657/22216 3988/4656/22217 4023/4700/22218 -f 4025/4702/22219 4026/4701/22220 3687/4325/22221 -f 3687/4325/22222 4027/4703/22223 4025/4702/22224 -f 4025/4702/22225 4027/4703/22226 3993/4659/22227 -f 3993/4659/22228 3991/4657/22229 4025/4702/22230 -f 4027/4703/22231 3687/4325/22232 3688/4324/22233 -f 3688/4324/22234 4028/4704/22235 4027/4703/22236 -f 4027/4703/22237 4028/4704/22238 3995/4661/22239 -f 3995/4661/22240 3993/4659/22241 4027/4703/22242 -f 4028/4704/22243 3688/4324/22244 3689/4326/22245 -f 3689/4326/22246 4029/4705/22247 4028/4704/22248 -f 4028/4704/22249 4029/4705/22250 4030/4706/22251 -f 4030/4706/22252 3995/4661/22253 4028/4704/22254 -f 4030/4706/22255 3999/4665/22256 3994/4662/22257 -f 3994/4662/22258 3995/4661/22259 4030/4706/22260 -f 4030/4706/22261 4029/4705/22262 4032/4707/22263 -f 4032/4707/22264 4031/4708/22265 4030/4706/22266 -f 4030/4706/22267 4031/4708/22268 4033/4709/22269 -f 4033/4709/22270 3999/4665/22271 4030/4706/22272 -f 4033/4709/22273 4002/4670/22274 3998/4666/22275 -f 3998/4666/22276 3999/4665/22277 4033/4709/22278 -f 4033/4709/22279 4031/4708/22280 4035/4710/22281 -f 4035/4710/22282 4034/4711/22283 4033/4709/22284 -f 4033/4709/22285 4034/4711/22286 4004/4673/22287 -f 4004/4673/22288 4002/4670/22289 4033/4709/22290 -f 4034/4711/22291 4035/4710/22292 4037/4712/22293 -f 4037/4712/22294 4036/4713/22295 4034/4711/22296 -f 4034/4711/22297 4036/4713/22298 4006/4676/22299 -f 4006/4676/22300 4004/4673/22301 4034/4711/22302 -f 4036/4713/22303 4037/4712/22304 4038/4714/22305 -f 4038/4714/22306 4011/4684/22307 4036/4713/22308 -f 4036/4713/22309 4011/4684/22310 4008/4679/22311 -f 4008/4679/22312 4006/4676/22313 4036/4713/22314 -f 4038/4714/22315 4037/4712/22316 4040/4715/22317 -f 4040/4715/22318 4039/4716/22319 4038/4714/22320 -f 4038/4714/22321 4039/4716/22322 4041/4717/22323 -f 4041/4717/22324 4014/4687/22325 4038/4714/22326 -f 4038/4714/22327 4014/4687/22328 4010/4685/22329 -f 4010/4685/22330 4011/4684/22331 4038/4714/22332 -f 4041/4717/22333 4039/4716/22334 4043/4718/22335 -f 4043/4718/22336 4042/4719/22337 4041/4717/22338 -f 4041/4717/22339 4042/4719/22340 4044/4720/22341 -f 4044/4720/22342 4017/4690/22343 4041/4717/22344 -f 4041/4717/22345 4017/4690/22346 4013/4688/22347 -f 4013/4688/22348 4014/4687/22349 4041/4717/22350 -f 3711/4353/22351 3712/4352/22352 4044/4720/22353 -f 4044/4720/22354 4042/4719/22355 3711/4353/22356 -f 3696/4333/22357 4045/4721/22358 4044/4720/22359 -f 4044/4720/22360 3712/4352/22361 3696/4333/22362 -f 4044/4720/22363 4045/4721/22364 4016/4691/22365 -f 4016/4691/22366 4017/4690/22367 4044/4720/22368 -f 3681/4336/22369 4022/4722/22370 4045/4721/22371 -f 4045/4721/22372 3696/4333/22373 3681/4336/22374 -f 4045/4721/22375 4022/4722/22376 4019/4692/22377 -f 4019/4692/22378 4016/4691/22379 4045/4721/22380 -f 4021/4698/22381 4022/4697/22382 3681/4318/22383 -f 3681/4318/22384 4046/4723/22385 4021/4698/22386 -f 4021/4698/22387 4046/4723/22388 3667/4301/22389 -f 3667/4301/22390 4024/4699/22391 4021/4698/22392 -f 4024/4699/22393 3667/4301/22394 3664/4304/22395 -f 3664/4304/22396 4026/4701/22397 4024/4699/22398 -f 4026/4701/22399 3664/4304/22400 3669/4305/22401 -f 3669/4305/22402 3687/4325/22403 4026/4701/22404 -f 3711/4353/22405 4042/4719/22406 4043/4718/22407 -f 4043/4718/22408 4047/4724/22409 3711/4353/22410 -f 4049/4725/22411 4048/4726/22412 4047/4724/22413 -f 4047/4724/22414 4043/4718/22415 4049/4725/22416 -f 4047/4724/22417 4048/4726/22418 4050/4727/22419 -f 4050/4727/22420 3697/4337/22421 4047/4724/22422 -f 4047/4724/22423 3697/4337/22424 3695/4334/22425 -f 3695/4334/22426 3711/4353/22427 4047/4724/22428 -f 4050/4727/22429 4048/4726/22430 3698/4339/22431 -f 3698/4339/22432 3692/4329/22433 4050/4727/22434 -f 4050/4727/22435 3692/4329/22436 3683/4330/22437 -f 3683/4330/22438 3686/4728/22439 4050/4727/22440 -f 4050/4727/22441 3686/4728/22442 3682/4338/22443 -f 3682/4338/22444 3697/4337/22445 4050/4727/22446 -f 4051/4729/22447 3698/4339/22448 4048/4726/22449 -f 4048/4726/22450 4049/4725/22451 4051/4729/22452 -f 3691/4327/22453 3698/4339/22454 4051/4729/22455 -f 4051/4729/22456 4052/4730/22457 3691/4327/22458 -f 4049/4725/22459 4040/4715/22460 4053/4731/22461 -f 4053/4731/22462 4051/4729/22463 4049/4725/22464 -f 4049/4725/22465 4043/4718/22466 4039/4716/22467 -f 4039/4716/22468 4040/4715/22469 4049/4725/22470 -f 4053/4731/22471 4035/4710/22472 4031/4708/22473 -f 4031/4708/22474 4032/4707/22475 4053/4731/22476 -f 4053/4731/22477 4032/4707/22478 4052/4730/22479 -f 4052/4730/22480 4051/4729/22481 4053/4731/22482 -f 4053/4731/22483 4040/4715/22484 4037/4712/22485 -f 4037/4712/22486 4035/4710/22487 4053/4731/22488 -f 3691/4327/22489 4052/4730/22490 3689/4326/22491 -f 3689/4326/22492 3684/4321/22493 3691/4327/22494 -f 4052/4730/22495 4032/4707/22496 4029/4705/22497 -f 4029/4705/22498 3689/4326/22499 4052/4730/22500 -f 3997/4668/22501 3961/4617/22502 4054/4732/22503 -f 4054/4732/22504 3622/4733/22505 3997/4668/22506 -f 4054/4732/22507 3958/4614/22508 3502/4127/22509 -f 3502/4127/22510 3553/4177/22511 4054/4732/22512 -f 4054/4732/22513 3553/4177/22514 3552/4180/22515 -f 3552/4180/22516 3622/4733/22517 4054/4732/22518 -f 4054/4732/22519 3961/4617/22520 3957/4615/22521 -f 3957/4615/22522 3958/4614/22523 4054/4732/22524 -f 3958/4614/22525 3956/4612/22526 3501/4125/22527 -f 3501/4125/22528 3502/4127/22529 3958/4614/22530 -f 3956/4612/22531 3889/4547/22532 3890/4546/22533 -f 3890/4546/22534 3501/4125/22535 3956/4612/22536 -f 3890/4546/22537 3887/4543/22538 3884/4542/22539 -f 3884/4542/22540 4055/4734/22541 3890/4546/22542 -f 3890/4546/22543 4055/4734/22544 3500/4126/22545 -f 3500/4126/22546 3501/4125/22547 3890/4546/22548 -f 4055/4734/22549 3884/4542/22550 3885/4541/22551 -f 3885/4541/22552 4056/4735/22553 4055/4734/22554 -f 4055/4734/22555 4056/4735/22556 4057/4736/22557 -f 4057/4736/22558 3500/4126/22559 4055/4734/22560 -f 4059/4739/22561 4058/4740/22562 4057/4737/22563 -f 4057/4737/22564 4060/4738/22565 4059/4739/22566 -f 4057/4736/22567 4058/4741/22568 3497/4124/22569 -f 3497/4124/22570 3500/4126/22571 4057/4736/22572 -f 3471/4094/22573 3473/4742/22574 4058/4740/22575 -f 4058/4740/22576 4059/4739/22577 3471/4094/22578 -f 4058/4741/22579 3473/4743/22580 3474/4121/22581 -f 3474/4121/22582 3497/4124/22583 4058/4741/22584 -f 3472/4744/22585 3473/4742/22586 3471/4094/22587 -f 3471/4094/22588 3469/4092/22589 3472/4744/22590 -f 3469/4092/22591 3462/4086/22592 3472/4744/22593 -f 4059/4739/22594 4060/4738/22595 4062/4745/22596 -f 4062/4745/22597 4061/4746/22598 4059/4739/22599 -f 4059/4739/22600 4061/4746/22601 3468/4093/22602 -f 3468/4093/22603 3471/4094/22604 4059/4739/22605 -f 4061/4746/22606 4062/4745/22607 4064/4747/22608 -f 4064/4747/22609 4063/4748/22610 4061/4746/22611 -f 4061/4746/22612 4063/4748/22613 3470/4091/22614 -f 3470/4091/22615 3468/4093/22616 4061/4746/22617 -f 4063/4748/22618 4064/4747/22619 3404/4029/22620 -f 3404/4029/22621 3405/4028/22622 4063/4748/22623 -f 4063/4748/22624 3405/4028/22625 3414/4037/22626 -f 3414/4037/22627 3470/4091/22628 4063/4748/22629 -f 3406/4027/22630 3407/4031/22631 3414/4037/22632 -f 3414/4037/22633 3405/4028/22634 3406/4027/22635 -f 3414/4037/22636 3412/4036/22637 3462/4086/22638 -f 3462/4086/22639 3470/4091/22640 3414/4037/22641 -f 3390/4014/22642 3393/4016/22643 3404/4029/22644 -f 3404/4029/22645 3397/4019/22646 3390/4014/22647 -f 3404/4029/22648 4064/4747/22649 4065/4749/22650 -f 4065/4749/22651 3397/4019/22652 3404/4029/22653 -f 4065/4749/22654 4066/4750/22655 3396/4020/22656 -f 3396/4020/22657 3397/4019/22658 4065/4749/22659 -f 4065/4749/22660 4064/4747/22661 4062/4745/22662 -f 4062/4745/22663 4067/4751/22664 4065/4749/22665 -f 4065/4749/22666 4067/4751/22667 4068/4752/22668 -f 4068/4752/22669 4066/4750/22670 4065/4749/22671 -f 4068/4752/22672 4069/4754/22673 4070/4753/22674 -f 4070/4753/22675 4066/4750/22676 4068/4752/22677 -f 4068/4752/22678 4067/4751/22679 4072/4755/22680 -f 4072/4755/22681 4071/4756/22682 4068/4752/22683 -f 4068/4752/22684 4071/4756/22685 4073/4757/22686 -f 4073/4757/22687 4069/4754/22688 4068/4752/22689 -f 4073/4757/22690 4074/4759/22691 4075/4758/22692 -f 4075/4758/22693 4069/4754/22694 4073/4757/22695 -f 3885/4760/22696 3882/4761/22697 4073/4757/22698 -f 4073/4757/22699 4071/4756/22700 3885/4760/22701 -f 3881/4762/22702 4074/4759/22703 4073/4757/22704 -f 4073/4757/22705 3882/4761/22706 3881/4762/22707 -f 4076/4764/22708 4074/4759/22709 3881/4762/22710 -f 3881/4762/22711 3880/4763/22712 4076/4764/22713 -f 4076/4764/22714 3415/4038/22715 3400/4022/22716 -f 3400/4022/22717 3401/4021/22718 4076/4764/22719 -f 4076/4764/22720 3401/4021/22721 4075/4758/22722 -f 4075/4758/22723 4074/4759/22724 4076/4764/22725 -f 3415/4038/22726 4076/4764/22727 3880/4763/22728 -f 3880/4763/22729 3879/4535/22730 3415/4038/22731 -f 3885/4760/22732 4071/4756/22733 4072/4755/22734 -f 4072/4755/22735 4056/4765/22736 3885/4760/22737 -f 4057/4737/22738 4056/4765/22739 4072/4755/22740 -f 4072/4755/22741 4060/4738/22742 4057/4737/22743 -f 4075/4758/22744 3401/4021/22745 3398/4024/22746 -f 3398/4024/22747 4077/4766/22748 4075/4758/22749 -f 4075/4758/22750 4077/4766/22751 4070/4753/22752 -f 4070/4753/22753 4069/4754/22754 4075/4758/22755 -f 4077/4766/22756 3398/4024/22757 3377/3999/22758 -f 3377/3999/22759 3372/3998/22760 4077/4766/22761 -f 4077/4766/22762 3372/3998/22763 3373/3997/22764 -f 3373/3997/22765 4070/4753/22766 4077/4766/22767 -f 3396/4020/22768 3373/3997/22769 3374/3996/22770 -f 3374/3996/22771 3394/4018/22772 3396/4020/22773 -f 3373/3997/22774 3396/4020/22775 4066/4750/22776 -f 4066/4750/22777 4070/4753/22778 3373/3997/22779 -f 3377/3999/22780 3398/4024/22781 3399/4023/22782 -f 3399/4023/22783 3380/4002/22784 3377/3999/22785 -f 4072/4755/22786 4067/4751/22787 4062/4745/22788 -f 4062/4745/22789 4060/4738/22790 4072/4755/22791 -f 3416/4039/22792 3878/4536/22793 3467/4767/22794 -f 3467/4767/22795 3464/4768/22796 3416/4039/22797 -f 3877/4530/22798 3875/4528/22799 3548/4172/22800 -f 3548/4172/22801 3549/4171/22802 3877/4530/22803 -f 3877/4530/22804 3549/4171/22805 4078/4769/22806 -f 4078/4769/22807 3467/4532/22808 3877/4530/22809 -f 3875/4528/22810 3872/4527/22811 3551/4175/22812 -f 3551/4175/22813 3548/4172/22814 3875/4528/22815 -f 3551/4175/22816 3872/4527/22817 3873/4526/22818 -f 3873/4526/22819 3598/4235/22820 3551/4175/22821 -f 3740/4383/22822 3736/4379/22823 3598/4235/22824 -f 3598/4235/22825 3873/4526/22826 3740/4383/22827 -f 3740/4383/22828 3873/4526/22829 3869/4524/22830 -f 3869/4524/22831 3870/4523/22832 3740/4383/22833 -f 3597/4236/22834 3598/4235/22835 3736/4379/22836 -f 3736/4379/22837 3733/4376/22838 3597/4236/22839 -f 3743/4386/22840 3739/4384/22841 3740/4383/22842 -f 3740/4383/22843 3870/4523/22844 3743/4386/22845 -f 3743/4386/22846 3870/4523/22847 3867/4521/22848 -f 3867/4521/22849 3745/4388/22850 3743/4386/22851 -f 3600/4631/22852 3601/4371/22853 3699/4343/22854 -f 3699/4343/22855 3700/4342/22856 3600/4631/22857 -f 3523/4149/22858 3864/4519/22859 3460/4084/22860 -f 3460/4084/22861 3521/4147/22862 3523/4149/22863 -f 3863/4516/22864 3753/4396/22865 3864/4519/22866 -f 3864/4519/22867 3523/4149/22868 3863/4516/22869 -f 3863/4516/22870 3523/4149/22871 3524/4148/22872 -f 3524/4148/22873 3862/4517/22874 3863/4516/22875 -f 3485/4106/22876 3487/4111/22877 3506/4131/22878 -f 3506/4131/22879 3484/4107/22880 3485/4106/22881 -f 3504/4129/22882 3505/4128/22883 4080/4770/22884 -f 4080/4770/22885 4079/4771/22886 3504/4129/22887 -f 3504/4129/22888 4079/4771/22889 3858/4511/22890 -f 3858/4511/22891 3859/4510/22892 3504/4129/22893 -f 4082/4773/22894 4081/4774/22895 4083/4772/22896 -f 4083/4772/22897 3795/4443/22898 4082/4773/22899 -f 4082/4773/22900 3795/4443/22901 3793/4441/22902 -f 3793/4441/22903 3853/4506/22904 4082/4773/22905 -f 4083/4772/22906 4081/4774/22907 4085/4775/22908 -f 4085/4775/22909 4084/4776/22910 4083/4772/22911 -f 3493/4116/22912 3494/4115/22913 4083/4772/22914 -f 4083/4772/22915 4084/4776/22916 3493/4116/22917 -f 3493/4116/22918 4084/4776/22919 4086/4777/22920 -f 4086/4777/22921 3496/4119/22922 3493/4116/22923 -f 3496/4119/22924 4086/4777/22925 3505/4128/22926 -f 3505/4128/22927 3495/4120/22928 3496/4119/22929 -f 4086/4777/22930 4084/4776/22931 4085/4775/22932 -f 4085/4775/22933 4087/4778/22934 4086/4777/22935 -f 4086/4777/22936 4087/4778/22937 4080/4770/22938 -f 4080/4770/22939 3505/4128/22940 4086/4777/22941 -f 4088/4780/22942 3854/4781/22943 3855/4779/22944 -f 3855/4779/22945 3788/4434/22946 4088/4780/22947 -f 4088/4780/22948 3788/4434/22949 3785/4433/22950 -f 3785/4433/22951 3786/4432/22952 4088/4780/22953 -f 3855/4508/22954 3791/4439/22955 3790/4440/22956 -f 3855/4779/22957 3790/4437/22958 3787/4435/22959 -f 3787/4435/22960 3788/4434/22961 3855/4779/22962 -f 3725/4367/22963 3710/4350/22964 3706/4347/22965 -f 3706/4347/22966 3703/4345/22967 3725/4367/22968 -f 3721/4362/22969 3693/4331/22970 3662/4300/22971 -f 3662/4300/22972 3663/4299/22973 3721/4362/22974 -f 3706/4347/22975 3707/4346/22976 3704/4344/22977 -f 3704/4344/22978 3703/4345/22979 3706/4347/22980 -f 3686/4323/22981 3670/4307/22982 3666/4302/22983 -f 3666/4302/22984 3682/4317/22985 3686/4323/22986 -f 3660/4295/22987 3613/4249/22988 3608/4248/22989 -f 3608/4248/22990 3640/4277/22991 3660/4295/22992 -f 3656/4292/22993 3615/4254/22994 3618/4256/22995 -f 3618/4256/22996 3657/4294/22997 3656/4292/22998 -f 3915/4572/22999 3641/4279/23000 3609/4247/23001 -f 3609/4247/23002 3634/4271/23003 3915/4572/23004 -f 3652/4288/23005 3586/4218/23006 3584/4215/23007 -f 3584/4215/23008 3620/4257/23009 3652/4288/23010 -f 3650/4284/23011 3653/4291/23012 3635/4272/23013 -f 3635/4272/23014 3630/4270/23015 3650/4284/23016 -f 3627/4265/23017 3628/4264/23018 3541/4165/23019 -f 3541/4165/23020 3542/4164/23021 3627/4265/23022 -f 3628/4264/23023 3847/4500/23024 3544/4168/23025 -f 3544/4168/23026 3541/4165/23027 3628/4264/23028 -f 3607/4244/23029 3591/4227/23030 3593/4228/23031 -f 3593/4228/23032 3594/4230/23033 3607/4244/23034 -f 3596/4233/23035 3592/4232/23036 3587/4222/23037 -f 3587/4222/23038 3824/4476/23039 3596/4233/23040 -f 3553/4177/23041 3502/4127/23042 3499/4122/23043 -f 3499/4122/23044 3546/4178/23045 3553/4177/23046 -f 3549/4171/23047 3546/4174/23048 3499/4782/23049 -f 3499/4782/23050 4078/4769/23051 3549/4171/23052 -f 3545/4170/23053 3535/4157/23054 3532/4160/23055 -f 3532/4160/23056 3531/4156/23057 3545/4170/23058 -f 3529/4155/23059 3516/4140/23060 3517/4139/23061 -f 3529/4155/23062 3517/4139/23063 3954/4611/23064 -f 3954/4611/23065 3525/4153/23066 3529/4155/23067 -f 3529/4155/23068 3530/4154/23069 3519/4143/23070 -f 3519/4143/23071 3516/4140/23072 3529/4155/23073 -f 3450/4070/23074 3482/4109/23075 3483/4108/23076 -f 3483/4108/23077 3461/4083/23078 3450/4070/23079 -f 3450/4070/23080 3461/4083/23081 4089/4783/23082 -f 4089/4783/23083 3449/4071/23084 3450/4070/23085 -f 3449/4071/23086 4089/4783/23087 3432/4056/23088 -f 3432/4056/23089 3433/4055/23090 3449/4071/23091 -f 3433/4055/23092 3427/4048/23093 3453/4076/23094 -f 3453/4076/23095 3449/4071/23096 3433/4055/23097 -f 3433/4055/23098 3421/4043/23099 3422/4042/23100 -f 3422/4042/23101 3427/4048/23102 3433/4055/23103 -f 4089/4783/23104 3461/4083/23105 3446/4069/23106 -f 3446/4069/23107 3443/4065/23108 4089/4783/23109 -f 4089/4783/23110 3443/4065/23111 3424/4046/23112 -f 3424/4046/23113 3432/4056/23114 4089/4783/23115 -f 4090/4784/23116 3482/4109/23117 3450/4070/23118 -f 3450/4070/23119 3447/4073/23120 4090/4784/23121 -f 4090/4784/23122 4091/4787/23123 4093/4785/23124 -f 4093/4785/23125 4092/4786/23126 4090/4784/23127 -f 4090/4784/23128 4092/4786/23129 3485/4106/23130 -f 3485/4106/23131 3482/4109/23132 4090/4784/23133 -f 3451/4075/23134 4091/4787/23135 4090/4784/23136 -f 4090/4784/23137 3447/4073/23138 3451/4075/23139 -f 4094/4789/23140 4091/4787/23141 3451/4075/23142 -f 3451/4075/23143 4095/4788/23144 4094/4789/23145 -f 4095/4788/23146 3451/4075/23147 3452/4074/23148 -f 3452/4074/23149 4096/4790/23150 4095/4788/23151 -f 4096/4790/23152 3452/4074/23153 4098/4791/23154 -f 4098/4791/23155 4097/4792/23156 4096/4790/23157 -f 4100/4793/23158 4099/4794/23159 4097/4792/23160 -f 4097/4792/23161 4098/4791/23162 4100/4793/23163 -f 4099/4794/23164 4100/4793/23165 4102/4795/23166 -f 4102/4795/23167 4101/4796/23168 4099/4794/23169 -f 4101/4796/23170 4102/4795/23171 4104/4797/23172 -f 4104/4797/23173 4103/4798/23174 4101/4796/23175 -f 4103/4798/23176 4104/4797/23177 4106/4799/23178 -f 4106/4799/23179 4105/4800/23180 4103/4798/23181 -f 4107/4802/23182 4105/4800/23183 4106/4799/23184 -f 4106/4799/23185 4108/4801/23186 4107/4802/23187 -f 4106/4799/23188 4104/4797/23189 3509/4133/23190 -f 3509/4133/23191 3510/4132/23192 4106/4799/23193 -f 4106/4799/23194 3510/4132/23195 4109/4803/23196 -f 4109/4803/23197 4108/4801/23198 4106/4799/23199 -f 4109/4803/23200 3486/4112/23201 3485/4106/23202 -f 3485/4106/23203 4092/4786/23204 4109/4803/23205 -f 4109/4803/23206 4092/4786/23207 4093/4785/23208 -f 4093/4785/23209 4108/4801/23210 4109/4803/23211 -f 4109/4803/23212 3510/4132/23213 3507/4135/23214 -f 3507/4135/23215 3486/4112/23216 4109/4803/23217 -f 4108/4801/23218 4093/4785/23219 4110/4804/23220 -f 4110/4804/23221 4107/4802/23222 4108/4801/23223 -f 4104/4797/23224 4102/4795/23225 4111/4805/23226 -f 4111/4805/23227 3509/4133/23228 4104/4797/23229 -f 4111/4805/23230 4102/4795/23231 4100/4793/23232 -f 4100/4793/23233 4112/4806/23234 4111/4805/23235 -f 4111/4805/23236 4112/4806/23237 3428/4053/23238 -f 3428/4053/23239 3454/4078/23240 4111/4805/23241 -f 4111/4805/23242 3454/4078/23243 3513/4138/23244 -f 3513/4138/23245 3509/4133/23246 4111/4805/23247 -f 4113/4807/23248 4112/4806/23249 4100/4793/23250 -f 4100/4793/23251 4098/4791/23252 4113/4807/23253 -f 3428/4053/23254 4112/4806/23255 4113/4807/23256 -f 4113/4807/23257 3425/4050/23258 3428/4053/23259 -f 4113/4807/23260 4098/4791/23261 3452/4074/23262 -f 3452/4074/23263 3453/4076/23264 4113/4807/23265 -f 4113/4807/23266 3453/4076/23267 3427/4048/23268 -f 3427/4048/23269 3425/4050/23270 4113/4807/23271 -f 4094/4789/23272 4110/4804/23273 4093/4785/23274 -f 4093/4785/23275 4091/4787/23276 4094/4789/23277 -f 3511/4137/23278 3488/4110/23279 3486/4112/23280 -f 3486/4112/23281 3507/4135/23282 3511/4137/23283 -f 3499/4782/23284 3474/4095/23285 3466/4098/23286 -f 3466/4098/23287 4078/4769/23288 3499/4782/23289 -f 3481/4105/23290 3477/4100/23291 3493/4116/23292 -f 3493/4116/23293 3496/4119/23294 3481/4105/23295 -f 3464/4768/23296 3465/4808/23297 3388/4010/23298 -f 3388/4010/23299 3416/4039/23300 3464/4768/23301 -f 4114/4809/23302 3465/4087/23303 3418/4041/23304 -f 3418/4041/23305 3417/4040/23306 4114/4809/23307 -f 3387/4011/23308 3388/4010/23309 3465/4808/23310 -f 3465/4808/23311 4114/4810/23312 3387/4011/23313 -f 4114/4809/23314 3417/4040/23315 3410/4034/23316 -f 3410/4034/23317 4115/4811/23318 4114/4809/23319 -f 4114/4810/23320 4115/4811/23321 4116/4812/23322 -f 4116/4812/23323 3387/4011/23324 4114/4810/23325 -f 4116/4812/23326 4115/4811/23327 4118/4813/23328 -f 4118/4813/23329 4117/4814/23330 4116/4812/23331 -f 4116/4812/23332 4117/4814/23333 4120/4815/23334 -f 4120/4815/23335 4119/4816/23336 4116/4812/23337 -f 4116/4812/23338 4119/4816/23339 3385/4007/23340 -f 3385/4007/23341 3387/4011/23342 4116/4812/23343 -f 4120/4815/23344 3383/4006/23345 3379/4003/23346 -f 3379/4003/23347 4119/4816/23348 4120/4815/23349 -f 4118/4813/23350 4115/4811/23351 3410/4034/23352 -f 3410/4034/23353 3411/4033/23354 4118/4813/23355 -f 3400/4022/23356 3384/4008/23357 3380/4002/23358 -f 3380/4002/23359 3399/4023/23360 3400/4022/23361 -f 3394/4018/23362 3374/3996/23363 3378/4001/23364 -f 3378/4001/23365 3395/4017/23366 3394/4018/23367 -f 3395/4017/23368 3378/4001/23369 3382/4004/23370 -f 3382/4004/23371 3389/4015/23372 3395/4017/23373 -f 3480/4103/23374 3479/4104/23375 3495/4120/23376 -f 3477/4100/23377 3478/4099/23378 3492/4117/23379 -f 3492/4117/23380 3493/4116/23381 3477/4100/23382 -f 3666/4302/23383 3667/4301/23384 4046/4723/23385 -f 4046/4723/23386 3681/4318/23387 3666/4302/23388 -f 3550/4176/23389 3603/4239/23390 3977/4642/23391 -f 3977/4642/23392 3547/4173/23393 3550/4176/23394 -f 3801/4449/23395 3530/4154/23396 3531/4156/23397 -f 3531/4156/23398 4121/4817/23399 3801/4449/23400 -f 3531/4156/23401 3532/4160/23402 3536/4162/23403 -f 3536/4162/23404 4121/4817/23405 3531/4156/23406 -f 3536/4162/23407 3800/4450/23408 3801/4449/23409 -f 3801/4449/23410 4121/4817/23411 3536/4162/23412 -f 3634/4271/23413 3635/4272/23414 3653/4291/23415 -f 3653/4291/23416 3915/4572/23417 3634/4271/23418 -f 3653/4291/23419 3657/4294/23420 3618/4256/23421 -f 3618/4256/23422 3915/4572/23423 3653/4291/23424 -f 3522/4146/23425 3484/4107/23426 3506/4131/23427 -f 3506/4131/23428 3524/4148/23429 3522/4146/23430 -f 3506/4131/23431 3862/4517/23432 3524/4148/23433 -f 3494/4115/23434 3794/4444/23435 3795/4443/23436 -f 3795/4443/23437 4083/4772/23438 3494/4115/23439 -f 3503/4130/23440 3480/4103/23441 3495/4120/23442 -f 3506/4131/23443 3503/4130/23444 3504/4129/23445 -f 3504/4129/23446 3859/4510/23447 3506/4131/23448 -f 3460/4084/23449 3461/4083/23450 3483/4108/23451 -f 3483/4108/23452 3521/4147/23453 3460/4084/23454 -f 3599/4234/23455 3550/4176/23456 3551/4175/23457 -f 3554/4184/23458 3547/4183/23459 3977/4818/23460 -f 3977/4818/23461 3978/4652/23462 3554/4184/23463 -f 3383/4006/23464 4120/4815/23465 3382/4004/23466 -f 3382/4004/23467 3381/4005/23468 3383/4006/23469 -f 3411/4033/23470 3408/4030/23471 3403/4026/23472 -f 4120/4815/23473 4117/4814/23474 3389/4015/23475 -f 3389/4015/23476 3382/4004/23477 4120/4815/23478 -f 4118/4813/23479 3392/4012/23480 3389/4015/23481 -f 3389/4015/23482 4117/4814/23483 4118/4813/23484 -f 3411/4033/23485 3403/4026/23486 3392/4012/23487 -f 3392/4012/23488 4118/4813/23489 3411/4033/23490 -f 3467/4532/23491 4078/4769/23492 3466/4098/23493 -f 3472/4744/23494 3462/4086/23495 3463/4085/23496 -f 3463/4085/23497 3466/4090/23498 3472/4744/23499 -f 3385/4007/23500 4119/4816/23501 3379/4003/23502 -f 3936/4594/23503 3716/4354/23504 3713/4357/23505 -f 3713/4357/23506 3928/4584/23507 3936/4594/23508 -f 3922/4579/23509 3921/4577/23510 3933/4590/23511 -f 3933/4590/23512 3934/4592/23513 3924/4580/23514 -f 3924/4580/23515 3922/4579/23516 3933/4590/23517 -f 3934/4592/23518 3936/4594/23519 3928/4584/23520 -f 3928/4584/23521 3924/4580/23522 3934/4592/23523 -f 3928/4584/23524 3926/4582/23525 3924/4580/23526 -f 4097/4792/23527 4099/4794/23528 4101/4796/23529 -f 4107/4802/23530 4101/4796/23531 4103/4798/23532 -f 4103/4798/23533 4105/4800/23534 4107/4802/23535 -f 4101/4796/23536 4107/4802/23537 4097/4792/23538 -f 4097/4792/23539 4107/4802/23540 4110/4804/23541 -f 4110/4804/23542 4096/4790/23543 4097/4792/23544 -f 4095/4788/23545 4096/4790/23546 4110/4804/23547 -f 4110/4804/23548 4094/4789/23549 4095/4788/23550 -f 3491/4118/23551 3954/4611/23552 3517/4139/23553 -f 3517/4139/23554 3514/4142/23555 3491/4118/23556 -f 3514/4142/23557 3520/4145/23558 3491/4118/23559 -f 3543/4169/23560 3544/4168/23561 3847/4500/23562 -f 3847/4500/23563 3846/4499/23564 3543/4169/23565 -f 3543/4169/23566 3846/4499/23567 3844/4498/23568 -f 3844/4498/23569 3850/4504/23570 3543/4169/23571 -f 3850/4504/23572 3844/4498/23573 3845/4497/23574 -f 3845/4497/23575 3823/4475/23576 3850/4504/23577 -f 3822/4474/23578 3823/4475/23579 3845/4497/23580 -f 3845/4497/23581 3848/4502/23582 3822/4474/23583 -f 3848/4502/23584 4122/4819/23585 3822/4474/23586 -f 3588/4221/23587 3580/4220/23588 4122/4819/23589 -f 4122/4819/23590 3825/4479/23591 3588/4221/23592 -f 3824/4476/23593 3587/4222/23594 3588/4221/23595 -f 3588/4221/23596 3825/4479/23597 3824/4476/23598 -f 4122/4819/23599 3583/4213/23600 3822/4474/23601 -f 3848/4502/23602 3825/4479/23603 4122/4819/23604 -f 3580/4220/23605 3579/4207/23606 4122/4819/23607 -f 3579/4207/23608 3583/4213/23609 4122/4819/23610 -f 3632/4268/23611 3633/4267/23612 3610/4246/23613 -f 4288/4820/23614 4281/4821/23615 4290/4822/23616 -f 4290/4822/23617 4289/4823/23618 4288/4820/23619 -f 4344/4824/23620 4288/4820/23621 4289/4823/23622 -f 4289/4823/23623 4153/4825/23624 4344/4824/23625 -f 4153/4825/23626 4329/4826/23627 4328/4827/23628 -f 4328/4827/23629 4344/4824/23630 4153/4825/23631 -f 4293/4828/23632 4185/4829/23633 4280/4830/23634 -f 4280/4830/23635 4279/4831/23636 4293/4828/23637 -f 4166/4832/23638 4290/4822/23639 4280/4830/23640 -f 4280/4830/23641 4169/4833/23642 4166/4832/23643 -f 4146/4834/23644 4289/4823/23645 4290/4822/23646 -f 4290/4822/23647 4166/4832/23648 4146/4834/23649 -f 4154/4835/23650 4153/4825/23651 4289/4823/23652 -f 4289/4823/23653 4146/4834/23654 4154/4835/23655 -f 4155/4836/23656 4329/4826/23657 4153/4825/23658 -f 4153/4825/23659 4154/4835/23660 4155/4836/23661 -f 4280/4830/23662 4185/4829/23663 4191/4837/23664 -f 4191/4837/23665 4169/4833/23666 4280/4830/23667 -f 4186/4838/23668 4185/4829/23669 4293/4828/23670 -f 4293/4828/23671 4180/4839/23672 4186/4838/23673 -f 4192/4840/23674 4191/4837/23675 4185/4829/23676 -f 4185/4829/23677 4186/4838/23678 4192/4840/23679 -f 4200/4841/23680 4186/4838/23681 4180/4839/23682 -f 4180/4839/23683 4183/4842/23684 4200/4841/23685 -f 4193/4843/23686 4192/4840/23687 4186/4838/23688 -f 4186/4838/23689 4200/4841/23690 4193/4843/23691 -f 4330/4844/23692 4329/4826/23693 4155/4836/23694 -f 4155/4836/23695 4156/4845/23696 4330/4844/23697 -f 4331/4846/23698 4328/4827/23699 4329/4826/23700 -f 4329/4826/23701 4330/4844/23702 4331/4846/23703 -f 4181/4847/23704 4200/4841/23705 4183/4842/23706 -f 4183/4842/23707 4184/4848/23708 4181/4847/23709 -f 4182/4849/23710 4193/4843/23711 4200/4841/23712 -f 4200/4841/23713 4181/4847/23714 4182/4849/23715 -f 4149/4850/23716 4330/4844/23717 4156/4845/23718 -f 4156/4845/23719 4150/4851/23720 4149/4850/23721 -f 4327/4852/23722 4331/4846/23723 4330/4844/23724 -f 4330/4844/23725 4149/4850/23726 4327/4852/23727 -f 4136/4853/23728 4181/4847/23729 4184/4848/23730 -f 4184/4848/23731 4135/4854/23732 4136/4853/23733 -f 4137/4855/23734 4182/4849/23735 4181/4847/23736 -f 4181/4847/23737 4136/4853/23738 4137/4855/23739 -f 4141/4856/23740 4149/4850/23741 4150/4851/23742 -f 4150/4851/23743 4142/4857/23744 4141/4856/23745 -f 4139/4858/23746 4327/4852/23747 4149/4850/23748 -f 4149/4850/23749 4141/4856/23750 4139/4858/23751 -f 4133/4859/23752 4141/4856/23753 4142/4857/23754 -f 4142/4857/23755 4143/4860/23756 4133/4859/23757 -f 4134/4861/23758 4139/4858/23759 4141/4856/23760 -f 4141/4856/23761 4133/4859/23762 4134/4861/23763 -f 4136/4853/23764 4133/4859/23765 4143/4860/23766 -f 4143/4860/23767 4137/4855/23768 4136/4853/23769 -f 4135/4854/23770 4134/4861/23771 4133/4859/23772 -f 4133/4859/23773 4136/4853/23774 4135/4854/23775 -f 4279/4831/23776 4280/4830/23777 4290/4822/23778 -f 4290/4822/23779 4281/4821/23780 4279/4831/23781 -f 4288/4820/23782 4201/4862/23783 4283/4863/23784 -f 4283/4863/23785 4281/4821/23786 4288/4820/23787 -f 4332/4864/23788 4201/4862/23789 4288/4820/23790 -f 4288/4820/23791 4344/4824/23792 4332/4864/23793 -f 4333/4865/23794 4332/4864/23795 4344/4824/23796 -f 4344/4824/23797 4328/4827/23798 4333/4865/23799 -f 4315/4866/23800 4333/4865/23801 4328/4827/23802 -f 4328/4827/23803 4331/4846/23804 4315/4866/23805 -f 4331/4846/23806 4327/4852/23807 4313/4867/23808 -f 4313/4867/23809 4315/4866/23810 4331/4846/23811 -f 4327/4852/23812 4139/4858/23813 4140/4868/23814 -f 4140/4868/23815 4313/4867/23816 4327/4852/23817 -f 4139/4858/23818 4134/4861/23819 4127/4869/23820 -f 4127/4869/23821 4140/4868/23822 4139/4858/23823 -f 4172/4870/23824 4127/4869/23825 4134/4861/23826 -f 4134/4861/23827 4135/4854/23828 4172/4870/23829 -f 4173/4871/23830 4172/4870/23831 4135/4854/23832 -f 4135/4854/23833 4184/4848/23834 4173/4871/23835 -f 4184/4848/23836 4183/4842/23837 4179/4872/23838 -f 4179/4872/23839 4173/4871/23840 4184/4848/23841 -f 4183/4842/23842 4180/4839/23843 4187/4873/23844 -f 4187/4873/23845 4179/4872/23846 4183/4842/23847 -f 4293/4828/23848 4291/4874/23849 4222/4875/23850 -f 4222/4875/23851 4180/4839/23852 4293/4828/23853 -f 4293/4828/23854 4279/4831/23855 4282/4876/23856 -f 4282/4876/23857 4291/4874/23858 4293/4828/23859 -f 4282/4876/23860 4279/4831/23861 4281/4821/23862 -f 4281/4821/23863 4283/4863/23864 4282/4876/23865 -f 4283/4863/23866 4284/4877/23867 4285/4878/23868 -f 4285/4878/23869 4282/4876/23870 4283/4863/23871 -f 4187/4873/23872 4188/4879/23873 4175/4880/23874 -f 4175/4880/23875 4179/4872/23876 4187/4873/23877 -f 4126/4881/23878 4123/4882/23879 4188/4879/23880 -f 4188/4879/23881 4187/4873/23882 4126/4881/23883 -f 4282/4876/23884 4285/4878/23885 4292/4883/23886 -f 4292/4883/23887 4291/4874/23888 4282/4876/23889 -f 4223/4884/23890 4292/4883/23891 4230/4885/23892 -f 4230/4885/23893 4224/4886/23894 4223/4884/23895 -f 4292/4883/23896 4285/4878/23897 4294/4887/23898 -f 4294/4887/23899 4230/4885/23900 4292/4883/23901 -f 4294/4887/23902 4232/4888/23903 4231/4889/23904 -f 4231/4889/23905 4230/4885/23906 4294/4887/23907 -f 4231/4889/23908 4219/4890/23909 4224/4886/23910 -f 4224/4886/23911 4230/4885/23912 4231/4889/23913 -f 4177/4891/23914 4173/4871/23915 4179/4872/23916 -f 4179/4872/23917 4175/4880/23918 4177/4891/23919 -f 4128/4892/23920 4322/4893/23921 4140/4868/23922 -f 4140/4868/23923 4127/4869/23924 4128/4892/23925 -f 4128/4892/23926 4127/4869/23927 4172/4870/23928 -f 4172/4870/23929 4131/4894/23930 4128/4892/23931 -f 4131/4894/23932 4172/4870/23933 4173/4871/23934 -f 4173/4871/23935 4177/4891/23936 4131/4894/23937 -f 4333/4865/23938 4315/4866/23939 4316/4895/23940 -f 4316/4895/23941 4335/4896/23942 4333/4865/23943 -f 4316/4895/23944 4315/4866/23945 4313/4867/23946 -f 4313/4867/23947 4314/4897/23948 4316/4895/23949 -f 4313/4867/23950 4140/4868/23951 4322/4893/23952 -f 4322/4893/23953 4314/4897/23954 4313/4867/23955 -f 4333/4865/23956 4335/4896/23957 4334/4898/23958 -f 4334/4898/23959 4332/4864/23960 4333/4865/23961 -f 4218/4899/23962 4211/4900/23963 4123/4882/23964 -f 4123/4882/23965 4126/4881/23966 4218/4899/23967 -f 4219/4890/23968 4209/4901/23969 4220/4902/23970 -f 4220/4902/23971 4224/4886/23972 4219/4890/23973 -f 4218/4899/23974 4220/4902/23975 4209/4901/23976 -f 4209/4901/23977 4211/4900/23978 4218/4899/23979 -f 4209/4901/23980 4214/4903/23981 4213/4904/23982 -f 4213/4904/23983 4211/4900/23984 4209/4901/23985 -f 4213/4904/23986 4214/4903/23987 4216/4905/23988 -f 4216/4905/23989 4210/4906/23990 4213/4904/23991 -f 4212/4907/23992 4211/4900/23993 4213/4904/23994 -f 4213/4904/23995 4210/4906/23996 4212/4907/23997 -f 4124/4908/23998 4123/4882/23999 4211/4900/24000 -f 4211/4900/24001 4212/4907/24002 4124/4908/24003 -f 4223/4884/24004 4224/4886/24005 4220/4902/24006 -f 4220/4902/24007 4218/4899/24008 4223/4884/24009 -f 4218/4899/24010 4126/4881/24011 4222/4875/24012 -f 4222/4875/24013 4223/4884/24014 4218/4899/24015 -f 4125/4909/24016 4188/4879/24017 4123/4882/24018 -f 4123/4882/24019 4124/4908/24020 4125/4909/24021 -f 4174/4910/24022 4175/4880/24023 4188/4879/24024 -f 4188/4879/24025 4125/4909/24026 4174/4910/24027 -f 4178/4911/24028 4177/4891/24029 4175/4880/24030 -f 4175/4880/24031 4174/4910/24032 4178/4911/24033 -f 4177/4891/24034 4178/4911/24035 4132/4912/24036 -f 4132/4912/24037 4131/4894/24038 4177/4891/24039 -f 4132/4912/24040 4130/4913/24041 4129/4914/24042 -f 4129/4914/24043 4131/4894/24044 4132/4912/24045 -f 4131/4894/24046 4129/4914/24047 4321/4915/24048 -f 4321/4915/24049 4128/4892/24050 4131/4894/24051 -f 4320/4916/24052 4322/4893/24053 4128/4892/24054 -f 4128/4892/24055 4321/4915/24056 4320/4916/24057 -f 4312/4917/24058 4314/4897/24059 4322/4893/24060 -f 4322/4893/24061 4320/4916/24062 4312/4917/24063 -f 4312/4917/24064 4318/4918/24065 4316/4895/24066 -f 4316/4895/24067 4314/4897/24068 4312/4917/24069 -f 4339/4919/24070 4335/4896/24071 4316/4895/24072 -f 4316/4895/24073 4318/4918/24074 4339/4919/24075 -f 4202/4920/24076 4201/4862/24077 4332/4864/24078 -f 4332/4864/24079 4334/4898/24080 4202/4920/24081 -f 4284/4877/24082 4283/4863/24083 4201/4862/24084 -f 4201/4862/24085 4202/4920/24086 4284/4877/24087 -f 4335/4896/24088 4339/4919/24089 4336/4921/24090 -f 4336/4921/24091 4334/4898/24092 4335/4896/24093 -f 4206/4922/24094 4202/4920/24095 4334/4898/24096 -f 4334/4898/24097 4336/4921/24098 4206/4922/24099 -f 4296/4923/24100 4284/4877/24101 4202/4920/24102 -f 4202/4920/24103 4206/4922/24104 4296/4923/24105 -f 4285/4878/24106 4284/4877/24107 4286/4924/24108 -f 4286/4924/24109 4294/4887/24110 4285/4878/24111 -f 4284/4877/24112 4296/4923/24113 4297/4925/24114 -f 4297/4925/24115 4286/4924/24116 4284/4877/24117 -f 4287/4926/24118 4232/4888/24119 4294/4887/24120 -f 4294/4887/24121 4286/4924/24122 4287/4926/24123 -f 4219/4890/24124 4221/4927/24125 4227/4928/24126 -f 4227/4928/24127 4209/4901/24128 4219/4890/24129 -f 4232/4888/24130 4234/4929/24131 4233/4930/24132 -f 4233/4930/24133 4231/4889/24134 4232/4888/24135 -f 4219/4890/24136 4231/4889/24137 4233/4930/24138 -f 4233/4930/24139 4221/4927/24140 4219/4890/24141 -f 4214/4903/24142 4209/4901/24143 4227/4928/24144 -f 4227/4928/24145 4215/4931/24146 4214/4903/24147 -f 4216/4905/24148 4214/4903/24149 4215/4931/24150 -f 4215/4931/24151 4217/4932/24152 4216/4905/24153 -f 4287/4926/24154 4237/4933/24155 4234/4929/24156 -f 4234/4929/24157 4232/4888/24158 4287/4926/24159 -f 4237/4933/24160 4253/4934/24161 4251/4935/24162 -f 4251/4935/24163 4234/4929/24164 4237/4933/24165 -f 4253/4934/24166 4245/4936/24167 4239/4937/24168 -f 4239/4937/24169 4251/4935/24170 4253/4934/24171 -f 4247/4938/24172 4244/4939/24173 4240/4940/24174 -f 4240/4940/24175 4239/4937/24176 4247/4938/24177 -f 4217/4932/24178 4215/4931/24179 4240/4940/24180 -f 4240/4940/24181 4244/4939/24182 4217/4932/24183 -f 4221/4927/24184 4225/4941/24185 4228/4942/24186 -f 4228/4942/24187 4227/4928/24188 4221/4927/24189 -f 4234/4929/24190 4236/4943/24191 4235/4944/24192 -f 4235/4944/24193 4233/4930/24194 4234/4929/24195 -f 4225/4941/24196 4221/4927/24197 4233/4930/24198 -f 4233/4930/24199 4235/4944/24200 4225/4941/24201 -f 4215/4931/24202 4227/4928/24203 4228/4942/24204 -f 4228/4942/24205 4240/4940/24206 4215/4931/24207 -f 4240/4940/24208 4242/4945/24209 4241/4946/24210 -f 4241/4946/24211 4239/4937/24212 4240/4940/24213 -f 4251/4935/24214 4239/4937/24215 4241/4946/24216 -f 4241/4946/24217 4252/4947/24218 4251/4935/24219 -f 4228/4942/24220 4243/4948/24221 4242/4945/24222 -f 4242/4945/24223 4240/4940/24224 4228/4942/24225 -f 4228/4942/24226 4225/4941/24227 4226/4949/24228 -f 4226/4949/24229 4243/4948/24230 4228/4942/24231 -f 4236/4943/24232 4234/4929/24233 4251/4935/24234 -f 4251/4935/24235 4252/4947/24236 4236/4943/24237 -f 4235/4944/24238 4236/4943/24239 4226/4949/24240 -f 4226/4949/24241 4225/4941/24242 4235/4944/24243 -f 4226/4949/24244 4236/4943/24245 4252/4947/24246 -f 4252/4947/24247 4243/4948/24248 4226/4949/24249 -f 4242/4945/24250 4243/4948/24251 4252/4947/24252 -f 4252/4947/24253 4241/4946/24254 4242/4945/24255 -f 4296/4923/24256 4203/4950/24257 4298/4951/24258 -f 4298/4951/24259 4297/4925/24260 4296/4923/24261 -f 4310/4952/24262 4298/4951/24263 4203/4950/24264 -f 4203/4950/24265 4205/4953/24266 4310/4952/24267 -f 4205/4953/24268 4204/4954/24269 4308/4955/24270 -f 4308/4955/24271 4310/4952/24272 4205/4953/24273 -f 4551/4956/24274 4261/4957/24275 4308/4955/24276 -f 4308/4955/24277 4204/4954/24278 4551/4956/24279 -f 4551/4956/24280 4549/4958/24281 4259/4959/24282 -f 4259/4959/24283 4261/4957/24284 4551/4956/24285 -f 4268/4960/24286 4259/4959/24287 4549/4958/24288 -f 4549/4958/24289 4553/4961/24290 4268/4960/24291 -f 4268/4960/24292 4553/4961/24293 4554/4962/24294 -f 4554/4962/24295 4269/4963/24296 4268/4960/24297 -f 4286/4924/24298 4297/4925/24299 4299/4964/24300 -f 4299/4964/24301 4287/4926/24302 4286/4924/24303 -f 4297/4925/24304 4298/4951/24305 4295/4965/24306 -f 4295/4965/24307 4299/4964/24308 4297/4925/24309 -f 4298/4951/24310 4310/4952/24311 4309/4966/24312 -f 4309/4966/24313 4295/4965/24314 4298/4951/24315 -f 4310/4952/24316 4308/4955/24317 4311/4967/24318 -f 4311/4967/24319 4309/4966/24320 4310/4952/24321 -f 4308/4955/24322 4261/4957/24323 4260/4968/24324 -f 4260/4968/24325 4311/4967/24326 4308/4955/24327 -f 4261/4957/24328 4259/4959/24329 4258/4969/24330 -f 4258/4969/24331 4260/4968/24332 4261/4957/24333 -f 4259/4959/24334 4268/4960/24335 4267/4970/24336 -f 4267/4970/24337 4258/4969/24338 4259/4959/24339 -f 4272/4971/24340 4271/4972/24341 4269/4963/24342 -f 4269/4963/24343 4270/4973/24344 4272/4971/24345 -f 4260/4968/24346 4256/4974/24347 4300/4975/24348 -f 4300/4975/24349 4311/4967/24350 4260/4968/24351 -f 4260/4968/24352 4258/4969/24353 4276/4976/24354 -f 4276/4976/24355 4256/4974/24356 4260/4968/24357 -f 4258/4969/24358 4267/4970/24359 4262/4977/24360 -f 4262/4977/24361 4276/4976/24362 4258/4969/24363 -f 4301/4978/24364 4309/4966/24365 4311/4967/24366 -f 4311/4967/24367 4300/4975/24368 4301/4978/24369 -f 4295/4965/24370 4309/4966/24371 4301/4978/24372 -f 4301/4978/24373 4302/4979/24374 4295/4965/24375 -f 4302/4979/24376 4306/4980/24377 4299/4964/24378 -f 4299/4964/24379 4295/4965/24380 4302/4979/24381 -f 4254/4981/24382 4287/4926/24383 4299/4964/24384 -f 4299/4964/24385 4306/4980/24386 4254/4981/24387 -f 4238/4982/24388 4237/4933/24389 4287/4926/24390 -f 4287/4926/24391 4254/4981/24392 4238/4982/24393 -f 4238/4982/24394 4229/4983/24395 4253/4934/24396 -f 4253/4934/24397 4237/4933/24398 4238/4982/24399 -f 4246/4984/24400 4245/4936/24401 4253/4934/24402 -f 4253/4934/24403 4229/4983/24404 4246/4984/24405 -f 4249/4985/24406 4248/4986/24407 4245/4936/24408 -f 4245/4936/24409 4246/4984/24410 4249/4985/24411 -f 4274/4987/24412 4262/4977/24413 4265/4988/24414 -f 4265/4988/24415 4263/4989/24416 4274/4987/24417 -f 4273/4990/24418 4276/4976/24419 4262/4977/24420 -f 4262/4977/24421 4274/4987/24422 4273/4990/24423 -f 4257/4991/24424 4256/4974/24425 4276/4976/24426 -f 4276/4976/24427 4273/4990/24428 4257/4991/24429 -f 4257/4991/24430 4303/4992/24431 4300/4975/24432 -f 4300/4975/24433 4256/4974/24434 4257/4991/24435 -f 4301/4978/24436 4300/4975/24437 4303/4992/24438 -f 4303/4992/24439 4304/4993/24440 4301/4978/24441 -f 4302/4979/24442 4301/4978/24443 4304/4993/24444 -f 4304/4993/24445 4305/4994/24446 4302/4979/24447 -f 4306/4980/24448 4302/4979/24449 4305/4994/24450 -f 4305/4994/24451 4307/4995/24452 4306/4980/24453 -f 4255/4996/24454 4254/4981/24455 4306/4980/24456 -f 4306/4980/24457 4307/4995/24458 4255/4996/24459 -f 4277/4997/24460 4238/4982/24461 4254/4981/24462 -f 4254/4981/24463 4255/4996/24464 4277/4997/24465 -f 4275/4998/24466 4229/4983/24467 4238/4982/24468 -f 4238/4982/24469 4277/4997/24470 4275/4998/24471 -f 4278/4999/24472 4246/4984/24473 4229/4983/24474 -f 4229/4983/24475 4275/4998/24476 4278/4999/24477 -f 4249/4985/24478 4246/4984/24479 4278/4999/24480 -f 4278/4999/24481 4250/5000/24482 4249/4985/24483 -f 4305/4994/24484 4304/4993/24485 4303/4992/24486 -f 4303/4992/24487 4307/4995/24488 4305/4994/24489 -f 4257/4991/24490 4255/4996/24491 4307/4995/24492 -f 4307/4995/24493 4303/4992/24494 4257/4991/24495 -f 4273/4990/24496 4277/4997/24497 4255/4996/24498 -f 4255/4996/24499 4257/4991/24500 4273/4990/24501 -f 4274/4987/24502 4275/4998/24503 4277/4997/24504 -f 4277/4997/24505 4273/4990/24506 4274/4987/24507 -f 4270/4973/24508 4269/4963/24509 4554/4962/24510 -f 4554/4962/24511 4555/5001/24512 4270/4973/24513 -f 4269/4963/24514 4271/4972/24515 4267/4970/24516 -f 4267/4970/24517 4268/4960/24518 4269/4963/24519 -f 4271/4972/24520 4265/4988/24521 4262/4977/24522 -f 4262/4977/24523 4267/4970/24524 4271/4972/24525 -f 4263/4989/24526 4265/4988/24527 4266/5002/24528 -f 4266/5002/24529 4264/5003/24530 4263/4989/24531 -f 4275/4998/24532 4274/4987/24533 4263/4989/24534 -f 4263/4989/24535 4278/4999/24536 4275/4998/24537 -f 4263/4989/24538 4264/5003/24539 4250/5000/24540 -f 4250/5000/24541 4278/4999/24542 4263/4989/24543 -f 4296/4923/24544 4206/4922/24545 4208/5004/24546 -f 4208/5004/24547 4203/4950/24548 4296/4923/24549 -f 4206/4922/24550 4336/4921/24551 4337/5005/24552 -f 4337/5005/24553 4208/5004/24554 4206/4922/24555 -f 4336/4921/24556 4339/4919/24557 4340/5006/24558 -f 4340/5006/24559 4337/5005/24560 4336/4921/24561 -f 4207/5007/24562 4205/4953/24563 4203/4950/24564 -f 4203/4950/24565 4208/5004/24566 4207/5007/24567 -f 4547/5008/24568 4204/4954/24569 4205/4953/24570 -f 4205/4953/24571 4207/5007/24572 4547/5008/24573 -f 4545/5009/24574 4551/4956/24575 4204/4954/24576 -f 4204/4954/24577 4547/5008/24578 4545/5009/24579 -f 4552/5010/24580 4549/4958/24581 4551/4956/24582 -f 4551/4956/24583 4545/5009/24584 4552/5010/24585 -f 4550/5011/24586 4553/4961/24587 4549/4958/24588 -f 4549/4958/24589 4552/5010/24590 4550/5011/24591 -f 4556/5012/24592 4554/4962/24593 4553/4961/24594 -f 4553/4961/24595 4550/5011/24596 4556/5012/24597 -f 4556/5012/24598 4557/5013/24599 4555/5001/24600 -f 4555/5001/24601 4554/4962/24602 4556/5012/24603 -f 4338/5014/24604 4207/5007/24605 4208/5004/24606 -f 4208/5004/24607 4337/5005/24608 4338/5014/24609 -f 4547/5008/24610 4207/5007/24611 4338/5014/24612 -f 4338/5014/24613 4569/5015/24614 4547/5008/24615 -f 4548/5016/24616 4545/5009/24617 4547/5008/24618 -f 4547/5008/24619 4569/5015/24620 4548/5016/24621 -f 4545/5009/24622 4548/5016/24623 4546/5017/24624 -f 4546/5017/24625 4552/5010/24626 4545/5009/24627 -f 4558/5018/24628 4550/5011/24629 4552/5010/24630 -f 4552/5010/24631 4546/5017/24632 4558/5018/24633 -f 4559/5019/24634 4556/5012/24635 4550/5011/24636 -f 4550/5011/24637 4558/5018/24638 4559/5019/24639 -f 4556/5012/24640 4559/5019/24641 4560/5020/24642 -f 4560/5020/24643 4557/5013/24644 4556/5012/24645 -f 4337/5005/24646 4342/5021/24647 4574/5022/24648 -f 4574/5022/24649 4338/5014/24650 4337/5005/24651 -f 4570/5023/24652 4569/5015/24653 4338/5014/24654 -f 4338/5014/24655 4574/5022/24656 4570/5023/24657 -f 4571/5024/24658 4548/5016/24659 4569/5015/24660 -f 4569/5015/24661 4570/5023/24662 4571/5024/24663 -f 4561/5025/24664 4546/5017/24665 4548/5016/24666 -f 4548/5016/24667 4571/5024/24668 4561/5025/24669 -f 4563/5026/24670 4558/5018/24671 4546/5017/24672 -f 4546/5017/24673 4561/5025/24674 4563/5026/24675 -f 4565/5027/24676 4559/5019/24677 4558/5018/24678 -f 4558/5018/24679 4563/5026/24680 4565/5027/24681 -f 4565/5027/24682 4564/5028/24683 4560/5020/24684 -f 4560/5020/24685 4559/5019/24686 4565/5027/24687 -f 4337/5005/24688 4340/5006/24689 4341/5029/24690 -f 4341/5029/24691 4342/5021/24692 4337/5005/24693 -f 4339/4919/24694 4318/4918/24695 4319/5030/24696 -f 4319/5030/24697 4340/5006/24698 4339/4919/24699 -f 4318/4918/24700 4312/4917/24701 4317/5031/24702 -f 4317/5031/24703 4319/5030/24704 4318/4918/24705 -f 4312/4917/24706 4320/4916/24707 4323/5032/24708 -f 4323/5032/24709 4317/5031/24710 4312/4917/24711 -f 4320/4916/24712 4321/4915/24713 4324/5033/24714 -f 4324/5033/24715 4323/5032/24716 4320/4916/24717 -f 4325/5034/24718 4324/5033/24719 4321/4915/24720 -f 4321/4915/24721 4129/4914/24722 4325/5034/24723 -f 4129/4914/24724 4130/4913/24725 4326/5035/24726 -f 4326/5035/24727 4325/5034/24728 4129/4914/24729 -f 4563/5026/24730 4566/5036/24731 4567/5037/24732 -f 4567/5037/24733 4565/5027/24734 4563/5026/24735 -f 4563/5026/24736 4561/5025/24737 4562/5038/24738 -f 4562/5038/24739 4566/5036/24740 4563/5026/24741 -f 4571/5024/24742 4572/5039/24743 4562/5038/24744 -f 4562/5038/24745 4561/5025/24746 4571/5024/24747 -f 4579/5040/24748 4572/5039/24749 4571/5024/24750 -f 4571/5024/24751 4570/5023/24752 4579/5040/24753 -f 4579/5040/24754 4570/5023/24755 4574/5022/24756 -f 4574/5022/24757 4575/5041/24758 4579/5040/24759 -f 4574/5022/24760 4342/5021/24761 4343/5042/24762 -f 4343/5042/24763 4575/5041/24764 4574/5022/24765 -f 4342/5021/24766 4341/5029/24767 4679/5043/24768 -f 4679/5043/24769 4343/5042/24770 4342/5021/24771 -f 4679/5043/24772 4680/5044/24773 4682/5045/24774 -f 4682/5045/24775 4343/5042/24776 4679/5043/24777 -f 4682/5045/24778 4576/5046/24779 4575/5041/24780 -f 4575/5041/24781 4343/5042/24782 4682/5045/24783 -f 4575/5041/24784 4576/5046/24785 4581/5047/24786 -f 4581/5047/24787 4579/5040/24788 4575/5041/24789 -f 4579/5040/24790 4581/5047/24791 4573/5048/24792 -f 4573/5048/24793 4572/5039/24794 4579/5040/24795 -f 4562/5038/24796 4572/5039/24797 4573/5048/24798 -f 4573/5048/24799 4597/5049/24800 4562/5038/24801 -f 4598/5050/24802 4566/5036/24803 4562/5038/24804 -f 4562/5038/24805 4597/5049/24806 4598/5050/24807 -f 4604/5051/24808 4567/5037/24809 4566/5036/24810 -f 4566/5036/24811 4598/5050/24812 4604/5051/24813 -f 4605/5052/24814 4568/5053/24815 4567/5037/24816 -f 4567/5037/24817 4604/5051/24818 4605/5052/24819 -f 4681/5270/24820 4684/5273/24821 4682/5274/24822 -f 4682/5274/24823 4680/5275/24824 4681/5270/24825 -f 4582/5277/24826 4581/5278/24827 4576/5279/24828 -f 4576/5279/24829 4577/5280/24830 4582/5277/24831 -f 4583/5281/24832 4573/5282/24833 4581/5278/24834 -f 4581/5278/24835 4582/5277/24836 4583/5281/24837 -f 4573/5282/24838 4583/5281/24839 4599/5283/24840 -f 4599/5283/24841 4597/5284/24842 4573/5282/24843 -f 4601/5285/24844 4598/5286/24845 4597/5284/24846 -f 4597/5284/24847 4599/5283/24848 4601/5285/24849 -f 4607/5287/24850 4604/5288/24851 4598/5286/24852 -f 4598/5286/24853 4601/5285/24854 4607/5287/24855 -f 4606/5289/24856 4605/5290/24857 4604/5288/24858 -f 4604/5288/24859 4607/5287/24860 4606/5289/24861 -f 4607/5287/24862 4614/5291/24863 4615/5292/24864 -f 4615/5292/24865 4606/5289/24866 4607/5287/24867 -f 4607/5287/24868 4601/5285/24869 4603/5293/24870 -f 4603/5293/24871 4614/5291/24872 4607/5287/24873 -f 4601/5285/24874 4599/5283/24875 4600/5294/24876 -f 4600/5294/24877 4603/5293/24878 4601/5285/24879 -f 4584/5295/24880 4600/5294/24881 4599/5283/24882 -f 4599/5283/24883 4583/5281/24884 4584/5295/24885 -f 4582/5277/24886 4580/5296/24887 4584/5295/24888 -f 4584/5295/24889 4583/5281/24890 4582/5277/24891 -f 4578/5297/24892 4580/5296/24893 4582/5277/24894 -f 4582/5277/24895 4577/5280/24896 4578/5297/24897 -f 4577/5280/24898 4576/5279/24899 4683/5298/24900 -f 4683/5298/24901 4578/5297/24902 4577/5280/24903 -f 4682/5274/24904 4684/5273/24905 4683/5298/24906 -f 4683/5298/24907 4576/5279/24908 4682/5274/24909 -f 4678/5299/24910 4688/5300/24911 4686/5301/24912 -f 4686/5301/24913 4681/5270/24914 4678/5299/24915 -f 4711/5302/24916 4683/5298/24917 4684/5273/24918 -f 4684/5273/24919 4685/5303/24920 4711/5302/24921 -f 4712/5304/24922 4578/5297/24923 4683/5298/24924 -f 4683/5298/24925 4711/5302/24926 4712/5304/24927 -f 4586/5305/24928 4580/5296/24929 4578/5297/24930 -f 4578/5297/24931 4712/5304/24932 4586/5305/24933 -f 4585/5306/24934 4584/5295/24935 4580/5296/24936 -f 4580/5296/24937 4586/5305/24938 4585/5306/24939 -f 4590/5307/24940 4600/5294/24941 4584/5295/24942 -f 4584/5295/24943 4585/5306/24944 4590/5307/24945 -f 4602/5308/24946 4603/5293/24947 4600/5294/24948 -f 4600/5294/24949 4590/5307/24950 4602/5308/24951 -f 4609/5309/24952 4614/5291/24953 4603/5293/24954 -f 4603/5293/24955 4602/5308/24956 4609/5309/24957 -f 4612/5310/24958 4613/5311/24959 4615/5292/24960 -f 4615/5292/24961 4614/5291/24962 4612/5310/24963 -f 4611/5312/24964 4612/5310/24965 4614/5291/24966 -f 4614/5291/24967 4609/5309/24968 4611/5312/24969 -f 4610/5332/24970 4611/5312/24971 4609/5309/24972 -f 4609/5309/24973 4608/5333/24974 4610/5332/24975 -f 4592/5334/24976 4608/5333/24977 4609/5309/24978 -f 4609/5309/24979 4602/5308/24980 4592/5334/24981 -f 4591/5341/24982 4592/5334/24983 4602/5308/24984 -f 4602/5308/24985 4590/5307/24986 4591/5341/24987 -f 4593/5342/24988 4591/5341/24989 4590/5307/24990 -f 4590/5307/24991 4585/5306/24992 4593/5342/24993 -f 4716/5343/24994 4593/5342/24995 4585/5306/24996 -f 4585/5306/24997 4586/5305/24998 4716/5343/24999 -f 4586/5305/25000 4712/5304/25001 4713/5344/25002 -f 4713/5344/25003 4716/5343/25004 4586/5305/25005 -f 4714/5345/25006 4713/5344/25007 4712/5304/25008 -f 4712/5304/25009 4711/5302/25010 4714/5345/25011 -f 4711/5302/25012 4685/5303/25013 4687/5347/25014 -f 4687/5347/25015 4714/5345/25016 4711/5302/25017 -f 4681/5270/25018 4686/5301/25019 4685/5303/25020 -f 4685/5303/25021 4684/5273/25022 4681/5270/25023 -f 4685/5303/25024 4686/5301/25025 4688/5300/25026 -f 4688/5300/25027 4687/5347/25028 4685/5303/25029 -f 4678/5299/25030 4689/5348/25031 4692/5349/25032 -f 4692/5349/25033 4688/5300/25034 4678/5299/25035 -f 4689/5348/25036 4690/5350/25037 4693/5351/25038 -f 4693/5351/25039 4692/5349/25040 4689/5348/25041 -f 4588/5352/25042 4610/5332/25043 4608/5333/25044 -f 4608/5333/25045 4587/5353/25046 4588/5352/25047 -f 4592/5334/25048 4596/5354/25049 4587/5353/25050 -f 4587/5353/25051 4608/5333/25052 4592/5334/25053 -f 4592/5334/25054 4591/5341/25055 4594/5355/25056 -f 4594/5355/25057 4596/5354/25058 4592/5334/25059 -f 4593/5342/25060 4724/5356/25061 4594/5355/25062 -f 4594/5355/25063 4591/5341/25064 4593/5342/25065 -f 4593/5342/25066 4716/5343/25067 4715/5357/25068 -f 4715/5357/25069 4724/5356/25070 4593/5342/25071 -f 4716/5343/25072 4713/5344/25073 4719/5358/25074 -f 4719/5358/25075 4715/5357/25076 4716/5343/25077 -f 4713/5344/25078 4714/5345/25079 4717/5359/25080 -f 4717/5359/25081 4719/5358/25082 4713/5344/25083 -f 4714/5345/25084 4687/5347/25085 4718/5360/25086 -f 4718/5360/25087 4717/5359/25088 4714/5345/25089 -f 4687/5347/25090 4688/5300/25091 4691/5361/25092 -f 4691/5361/25093 4718/5360/25094 4687/5347/25095 -f 4688/5300/25096 4692/5349/25097 4694/5362/25098 -f 4694/5362/25099 4691/5361/25100 4688/5300/25101 -f 4695/5363/25102 4694/5362/25103 4692/5349/25104 -f 4692/5349/25105 4693/5351/25106 4695/5363/25107 -f 4596/5354/25108 4595/5364/25109 4588/5352/25110 -f 4588/5352/25111 4587/5353/25112 4596/5354/25113 -f 4596/5354/25114 4594/5355/25115 4589/5365/25116 -f 4589/5365/25117 4595/5364/25118 4596/5354/25119 -f 4594/5355/25120 4724/5356/25121 4722/5366/25122 -f 4722/5366/25123 4589/5365/25124 4594/5355/25125 -f 4724/5356/25126 4715/5357/25127 4723/5367/25128 -f 4723/5367/25129 4722/5366/25130 4724/5356/25131 -f 4721/5368/25132 4723/5367/25133 4715/5357/25134 -f 4715/5357/25135 4719/5358/25136 4721/5368/25137 -f 4717/5359/25138 4720/5369/25139 4721/5368/25140 -f 4721/5368/25141 4719/5358/25142 4717/5359/25143 -f 4717/5359/25144 4718/5360/25145 4725/5370/25146 -f 4725/5370/25147 4720/5369/25148 4717/5359/25149 -f 4726/5371/25150 4725/5370/25151 4718/5360/25152 -f 4718/5360/25153 4691/5361/25154 4726/5371/25155 -f 4691/5361/25156 4694/5362/25157 4727/5372/25158 -f 4727/5372/25159 4726/5371/25160 4691/5361/25161 -f 4694/5362/25162 4695/5363/25163 4728/5373/25164 -f 4728/5373/25165 4727/5372/25166 4694/5362/25167 -f 4143/4860/25168 4163/5054/25169 4138/5055/25170 -f 4138/5055/25171 4137/4855/25172 4143/4860/25173 -f 4189/5056/25174 4182/4849/25175 4137/4855/25176 -f 4137/4855/25177 4138/5055/25178 4189/5056/25179 -f 4193/4843/25180 4182/4849/25181 4189/5056/25182 -f 4189/5056/25183 4194/5057/25184 4193/4843/25185 -f 4192/4840/25186 4193/4843/25187 4194/5057/25188 -f 4194/5057/25189 4195/5058/25190 4192/4840/25191 -f 4191/4837/25192 4192/4840/25193 4195/5058/25194 -f 4195/5058/25195 4196/5059/25196 4191/4837/25197 -f 4169/4833/25198 4191/4837/25199 4196/5059/25200 -f 4196/5059/25201 4170/5060/25202 4169/4833/25203 -f 4166/4832/25204 4169/4833/25205 4170/5060/25206 -f 4170/5060/25207 4167/5061/25208 4166/4832/25209 -f 4147/5062/25210 4146/4834/25211 4166/4832/25212 -f 4166/4832/25213 4167/5061/25214 4147/5062/25215 -f 4154/4835/25216 4146/4834/25217 4147/5062/25218 -f 4147/5062/25219 4157/5063/25220 4154/4835/25221 -f 4155/4836/25222 4154/4835/25223 4157/5063/25224 -f 4157/5063/25225 4158/5064/25226 4155/4836/25227 -f 4156/4845/25228 4155/4836/25229 4158/5064/25230 -f 4158/5064/25231 4159/5065/25232 4156/4845/25233 -f 4150/4851/25234 4156/4845/25235 4159/5065/25236 -f 4159/5065/25237 4151/5066/25238 4150/4851/25239 -f 4142/4857/25240 4150/4851/25241 4151/5066/25242 -f 4151/5066/25243 4144/5067/25244 4142/4857/25245 -f 4142/4857/25246 4144/5067/25247 4163/5054/25248 -f 4163/5054/25249 4143/4860/25250 4142/4857/25251 -f 4163/5054/25252 4164/5068/25253 4165/5069/25254 -f 4165/5069/25255 4138/5055/25256 4163/5054/25257 -f 4189/5056/25258 4138/5055/25259 4165/5069/25260 -f 4165/5069/25261 4190/5070/25262 4189/5056/25263 -f 4194/5057/25264 4189/5056/25265 4190/5070/25266 -f 4190/5070/25267 4197/5071/25268 4194/5057/25269 -f 4195/5058/25270 4194/5057/25271 4197/5071/25272 -f 4197/5071/25273 4198/5072/25274 4195/5058/25275 -f 4196/5059/25276 4195/5058/25277 4198/5072/25278 -f 4198/5072/25279 4199/5073/25280 4196/5059/25281 -f 4170/5060/25282 4196/5059/25283 4199/5073/25284 -f 4199/5073/25285 4171/5074/25286 4170/5060/25287 -f 4168/5075/25288 4167/5061/25289 4170/5060/25290 -f 4170/5060/25291 4171/5074/25292 4168/5075/25293 -f 4147/5062/25294 4167/5061/25295 4168/5075/25296 -f 4168/5075/25297 4148/5076/25298 4147/5062/25299 -f 4157/5063/25300 4147/5062/25301 4148/5076/25302 -f 4148/5076/25303 4160/5077/25304 4157/5063/25305 -f 4158/5064/25306 4157/5063/25307 4160/5077/25308 -f 4160/5077/25309 4161/5078/25310 4158/5064/25311 -f 4159/5065/25312 4158/5064/25313 4161/5078/25314 -f 4161/5078/25315 4162/5079/25316 4159/5065/25317 -f 4151/5066/25318 4159/5065/25319 4162/5079/25320 -f 4162/5079/25321 4152/5080/25322 4151/5066/25323 -f 4145/5081/25324 4144/5067/25325 4151/5066/25326 -f 4151/5066/25327 4152/5080/25328 4145/5081/25329 -f 4164/5068/25330 4163/5054/25331 4144/5067/25332 -f 4144/5067/25333 4145/5081/25334 4164/5068/25335 -f 4222/4875/25336 4291/4874/25337 4292/4883/25338 -f 4292/4883/25339 4223/4884/25340 4222/4875/25341 -f 4180/4839/25342 4222/4875/25343 4126/4881/25344 -f 4126/4881/25345 4187/4873/25346 4180/4839/25347 -f 4245/4936/25348 4248/4986/25349 4247/4938/25350 -f 4247/4938/25351 4239/4937/25352 4245/4936/25353 -f 4272/4971/25354 4266/5002/25355 4265/4988/25356 -f 4265/4988/25357 4271/4972/25358 4272/4971/25359 -f 4568/5053/25360 4564/5028/25361 4565/5027/25362 -f 4565/5027/25363 4567/5037/25364 4568/5053/25365 -f 4487/5082/25366 4486/5083/25367 4485/5084/25368 -f 4485/5084/25369 4482/5085/25370 4487/5082/25371 -f 4532/5086/25372 4411/5087/25373 4486/5083/25374 -f 4486/5083/25375 4487/5082/25376 4532/5086/25377 -f 4411/5087/25378 4532/5086/25379 4522/5088/25380 -f 4522/5088/25381 4523/5089/25382 4411/5087/25383 -f 4474/5090/25384 4475/5091/25385 4476/5092/25386 -f 4476/5092/25387 4367/5093/25388 4474/5090/25389 -f 4394/5094/25390 4381/5095/25391 4476/5092/25392 -f 4476/5092/25393 4485/5084/25394 4394/5094/25395 -f 4397/5096/25396 4394/5094/25397 4485/5084/25398 -f 4485/5084/25399 4486/5083/25400 4397/5096/25401 -f 4412/5097/25402 4397/5096/25403 4486/5083/25404 -f 4486/5083/25405 4411/5087/25406 4412/5097/25407 -f 4413/5098/25408 4412/5097/25409 4411/5087/25410 -f 4411/5087/25411 4523/5089/25412 4413/5098/25413 -f 4476/5092/25414 4381/5095/25415 4372/5099/25416 -f 4372/5099/25417 4367/5093/25418 4476/5092/25419 -f 4361/5100/25420 4358/5101/25421 4474/5090/25422 -f 4474/5090/25423 4367/5093/25424 4361/5100/25425 -f 4373/5102/25426 4361/5100/25427 4367/5093/25428 -f 4367/5093/25429 4372/5099/25430 4373/5102/25431 -f 4368/5103/25432 4359/5104/25433 4358/5101/25434 -f 4358/5101/25435 4361/5100/25436 4368/5103/25437 -f 4374/5105/25438 4368/5103/25439 4361/5100/25440 -f 4361/5100/25441 4373/5102/25442 4374/5105/25443 -f 4524/5106/25444 4414/5107/25445 4413/5098/25446 -f 4413/5098/25447 4523/5089/25448 4524/5106/25449 -f 4525/5108/25450 4524/5106/25451 4523/5089/25452 -f 4523/5089/25453 4522/5088/25454 4525/5108/25455 -f 4362/5109/25456 4360/5110/25457 4359/5104/25458 -f 4359/5104/25459 4368/5103/25460 4362/5109/25461 -f 4363/5111/25462 4362/5109/25463 4368/5103/25464 -f 4368/5103/25465 4374/5105/25466 4363/5111/25467 -f 4409/5112/25468 4410/5113/25469 4414/5107/25470 -f 4414/5107/25471 4524/5106/25472 4409/5112/25473 -f 4521/5114/25474 4409/5112/25475 4524/5106/25476 -f 4524/5106/25477 4525/5108/25478 4521/5114/25479 -f 4364/5115/25480 4355/5116/25481 4360/5110/25482 -f 4360/5110/25483 4362/5109/25484 4364/5115/25485 -f 4365/5117/25486 4364/5115/25487 4362/5109/25488 -f 4362/5109/25489 4363/5111/25490 4365/5117/25491 -f 4408/5118/25492 4390/5119/25493 4410/5113/25494 -f 4410/5113/25495 4409/5112/25496 4408/5118/25497 -f 4386/5120/25498 4408/5118/25499 4409/5112/25500 -f 4409/5112/25501 4521/5114/25502 4386/5120/25503 -f 4384/5121/25504 4391/5122/25505 4390/5119/25506 -f 4390/5119/25507 4408/5118/25508 4384/5121/25509 -f 4385/5123/25510 4384/5121/25511 4408/5118/25512 -f 4408/5118/25513 4386/5120/25514 4385/5123/25515 -f 4364/5115/25516 4365/5117/25517 4391/5122/25518 -f 4391/5122/25519 4384/5121/25520 4364/5115/25521 -f 4355/5116/25522 4364/5115/25523 4384/5121/25524 -f 4384/5121/25525 4385/5123/25526 4355/5116/25527 -f 4475/5091/25528 4482/5085/25529 4485/5084/25530 -f 4485/5084/25531 4476/5092/25532 4475/5091/25533 -f 4487/5082/25534 4482/5085/25535 4483/5124/25536 -f 4483/5124/25537 4488/5125/25538 4487/5082/25539 -f 4533/5126/25540 4532/5086/25541 4487/5082/25542 -f 4487/5082/25543 4488/5125/25544 4533/5126/25545 -f 4534/5127/25546 4522/5088/25547 4532/5086/25548 -f 4532/5086/25549 4533/5126/25550 4534/5127/25551 -f 4527/5128/25552 4525/5108/25553 4522/5088/25554 -f 4522/5088/25555 4534/5127/25556 4527/5128/25557 -f 4525/5108/25558 4527/5128/25559 4520/5129/25560 -f 4520/5129/25561 4521/5114/25562 4525/5108/25563 -f 4521/5114/25564 4520/5129/25565 4387/5130/25566 -f 4387/5130/25567 4386/5120/25568 4521/5114/25569 -f 4386/5120/25570 4387/5130/25571 4349/5131/25572 -f 4349/5131/25573 4385/5123/25574 4386/5120/25575 -f 4354/5132/25576 4355/5116/25577 4385/5123/25578 -f 4385/5123/25579 4349/5131/25580 4354/5132/25581 -f 4353/5133/25582 4360/5110/25583 4355/5116/25584 -f 4355/5116/25585 4354/5132/25586 4353/5133/25587 -f 4360/5110/25588 4353/5133/25589 4352/5134/25590 -f 4352/5134/25591 4359/5104/25592 4360/5110/25593 -f 4359/5104/25594 4352/5134/25595 4356/5135/25596 -f 4356/5135/25597 4358/5101/25598 4359/5104/25599 -f 4474/5090/25600 4358/5101/25601 4423/5136/25602 -f 4423/5136/25603 4472/5137/25604 4474/5090/25605 -f 4474/5090/25606 4472/5137/25607 4477/5138/25608 -f 4477/5138/25609 4475/5091/25610 4474/5090/25611 -f 4477/5138/25612 4483/5124/25613 4482/5085/25614 -f 4482/5085/25615 4475/5091/25616 4477/5138/25617 -f 4483/5124/25618 4477/5138/25619 4479/5139/25620 -f 4479/5139/25621 4484/5140/25622 4483/5124/25623 -f 4356/5135/25624 4352/5134/25625 4176/5141/25626 -f 4176/5141/25627 4357/5142/25628 4356/5135/25629 -f 4346/5143/25630 4356/5135/25631 4357/5142/25632 -f 4357/5142/25633 4345/5144/25634 4346/5143/25635 -f 4477/5138/25636 4472/5137/25637 4473/5145/25638 -f 4473/5145/25639 4479/5139/25640 4477/5138/25641 -f 4427/5146/25642 4428/5147/25643 4445/5148/25644 -f 4445/5148/25645 4473/5145/25646 4427/5146/25647 -f 4473/5145/25648 4445/5148/25649 4478/5149/25650 -f 4478/5149/25651 4479/5139/25652 4473/5145/25653 -f 4478/5149/25654 4445/5148/25655 4446/5150/25656 -f 4446/5150/25657 4447/5151/25658 4478/5149/25659 -f 4446/5150/25660 4445/5148/25661 4428/5147/25662 -f 4428/5147/25663 4426/5152/25664 4446/5150/25665 -f 4351/5153/25666 4176/5141/25667 4352/5134/25668 -f 4352/5134/25669 4353/5133/25670 4351/5153/25671 -f 4350/5154/25672 4349/5131/25673 4387/5130/25674 -f 4387/5130/25675 4517/5155/25676 4350/5154/25677 -f 4350/5154/25678 4348/5156/25679 4354/5132/25680 -f 4354/5132/25681 4349/5131/25682 4350/5154/25683 -f 4348/5156/25684 4351/5153/25685 4353/5133/25686 -f 4353/5133/25687 4354/5132/25688 4348/5156/25689 -f 4534/5127/25690 4535/5157/25691 4528/5158/25692 -f 4528/5158/25693 4527/5128/25694 4534/5127/25695 -f 4528/5158/25696 4526/5159/25697 4520/5129/25698 -f 4520/5129/25699 4527/5128/25700 4528/5158/25701 -f 4520/5129/25702 4526/5159/25703 4517/5155/25704 -f 4517/5155/25705 4387/5130/25706 4520/5129/25707 -f 4534/5127/25708 4533/5126/25709 4536/5160/25710 -f 4536/5160/25711 4535/5157/25712 4534/5127/25713 -f 4420/5161/25714 4346/5143/25715 4345/5144/25716 -f 4345/5144/25717 4415/5162/25718 4420/5161/25719 -f 4426/5152/25720 4428/5147/25721 4421/5163/25722 -f 4421/5163/25723 4417/5164/25724 4426/5152/25725 -f 4420/5161/25726 4415/5162/25727 4417/5164/25728 -f 4417/5164/25729 4421/5163/25730 4420/5161/25731 -f 4417/5164/25732 4415/5162/25733 4416/5165/25734 -f 4416/5165/25735 4418/5166/25736 4417/5164/25737 -f 4416/5165/25738 4210/4906/25739 4216/4905/25740 -f 4216/4905/25741 4418/5166/25742 4416/5165/25743 -f 4212/4907/25744 4210/4906/25745 4416/5165/25746 -f 4416/5165/25747 4415/5162/25748 4212/4907/25749 -f 4124/4908/25750 4212/4907/25751 4415/5162/25752 -f 4415/5162/25753 4345/5144/25754 4124/4908/25755 -f 4427/5146/25756 4420/5161/25757 4421/5163/25758 -f 4421/5163/25759 4428/5147/25760 4427/5146/25761 -f 4420/5161/25762 4427/5146/25763 4423/5136/25764 -f 4423/5136/25765 4346/5143/25766 4420/5161/25767 -f 4125/4909/25768 4124/4908/25769 4345/5144/25770 -f 4345/5144/25771 4357/5142/25772 4125/4909/25773 -f 4174/4910/25774 4125/4909/25775 4357/5142/25776 -f 4357/5142/25777 4176/5141/25778 4174/4910/25779 -f 4178/4911/25780 4174/4910/25781 4176/5141/25782 -f 4176/5141/25783 4351/5153/25784 4178/4911/25785 -f 4351/5153/25786 4348/5156/25787 4132/4912/25788 -f 4132/4912/25789 4178/4911/25790 4351/5153/25791 -f 4132/4912/25792 4348/5156/25793 4347/5167/25794 -f 4347/5167/25795 4130/4913/25796 4132/4912/25797 -f 4348/5156/25798 4350/5154/25799 4514/5168/25800 -f 4514/5168/25801 4347/5167/25802 4348/5156/25803 -f 4516/5169/25804 4514/5168/25805 4350/5154/25806 -f 4350/5154/25807 4517/5155/25808 4516/5169/25809 -f 4519/5170/25810 4516/5169/25811 4517/5155/25812 -f 4517/5155/25813 4526/5159/25814 4519/5170/25815 -f 4519/5170/25816 4526/5159/25817 4528/5158/25818 -f 4528/5158/25819 4530/5171/25820 4519/5170/25821 -f 4540/5172/25822 4530/5171/25823 4528/5158/25824 -f 4528/5158/25825 4535/5157/25826 4540/5172/25827 -f 4489/5173/25828 4536/5160/25829 4533/5126/25830 -f 4533/5126/25831 4488/5125/25832 4489/5173/25833 -f 4484/5140/25834 4489/5173/25835 4488/5125/25836 -f 4488/5125/25837 4483/5124/25838 4484/5140/25839 -f 4535/5157/25840 4536/5160/25841 4537/5174/25842 -f 4537/5174/25843 4540/5172/25844 4535/5157/25845 -f 4510/5175/25846 4537/5174/25847 4536/5160/25848 -f 4536/5160/25849 4489/5173/25850 4510/5175/25851 -f 4502/5176/25852 4510/5175/25853 4489/5173/25854 -f 4489/5173/25855 4484/5140/25856 4502/5176/25857 -f 4479/5139/25858 4478/5149/25859 4480/5177/25860 -f 4480/5177/25861 4484/5140/25862 4479/5139/25863 -f 4484/5140/25864 4480/5177/25865 4500/5178/25866 -f 4500/5178/25867 4502/5176/25868 4484/5140/25869 -f 4481/5179/25870 4480/5177/25871 4478/5149/25872 -f 4478/5149/25873 4447/5151/25874 4481/5179/25875 -f 4426/5152/25876 4417/5164/25877 4434/5180/25878 -f 4434/5180/25879 4422/5181/25880 4426/5152/25881 -f 4447/5151/25882 4446/5150/25883 4448/5182/25884 -f 4448/5182/25885 4441/5183/25886 4447/5151/25887 -f 4426/5152/25888 4422/5181/25889 4448/5182/25890 -f 4448/5182/25891 4446/5150/25892 4426/5152/25893 -f 4418/5166/25894 4419/5184/25895 4434/5180/25896 -f 4434/5180/25897 4417/5164/25898 4418/5166/25899 -f 4216/4905/25900 4217/4932/25901 4419/5184/25902 -f 4419/5184/25903 4418/5166/25904 4216/4905/25905 -f 4481/5179/25906 4447/5151/25907 4441/5183/25908 -f 4441/5183/25909 4449/5185/25910 4481/5179/25911 -f 4449/5185/25912 4441/5183/25913 4439/5186/25914 -f 4439/5186/25915 4444/5187/25916 4449/5185/25917 -f 4444/5187/25918 4439/5186/25919 4429/5188/25920 -f 4429/5188/25921 4436/5189/25922 4444/5187/25923 -f 4247/4938/25924 4429/5188/25925 4430/5190/25926 -f 4430/5190/25927 4244/4939/25928 4247/4938/25929 -f 4217/4932/25930 4244/4939/25931 4430/5190/25932 -f 4430/5190/25933 4419/5184/25934 4217/4932/25935 -f 4422/5181/25936 4434/5180/25937 4435/5191/25938 -f 4435/5191/25939 4424/5192/25940 4422/5181/25941 -f 4441/5183/25942 4448/5182/25943 4442/5193/25944 -f 4442/5193/25945 4443/5194/25946 4441/5183/25947 -f 4424/5192/25948 4442/5193/25949 4448/5182/25950 -f 4448/5182/25951 4422/5181/25952 4424/5192/25953 -f 4419/5184/25954 4430/5190/25955 4435/5191/25956 -f 4435/5191/25957 4434/5180/25958 4419/5184/25959 -f 4430/5190/25960 4429/5188/25961 4431/5195/25962 -f 4431/5195/25963 4432/5196/25964 4430/5190/25965 -f 4439/5186/25966 4440/5197/25967 4431/5195/25968 -f 4431/5195/25969 4429/5188/25970 4439/5186/25971 -f 4435/5191/25972 4430/5190/25973 4432/5196/25974 -f 4432/5196/25975 4433/5198/25976 4435/5191/25977 -f 4435/5191/25978 4433/5198/25979 4425/5199/25980 -f 4425/5199/25981 4424/5192/25982 4435/5191/25983 -f 4443/5194/25984 4440/5197/25985 4439/5186/25986 -f 4439/5186/25987 4441/5183/25988 4443/5194/25989 -f 4442/5193/25990 4424/5192/25991 4425/5199/25992 -f 4425/5199/25993 4443/5194/25994 4442/5193/25995 -f 4425/5199/25996 4433/5198/25997 4440/5197/25998 -f 4440/5197/25999 4443/5194/26000 4425/5199/26001 -f 4432/5196/26002 4431/5195/26003 4440/5197/26004 -f 4440/5197/26005 4433/5198/26006 4432/5196/26007 -f 4502/5176/26008 4500/5178/26009 4501/5200/26010 -f 4501/5200/26011 4503/5201/26012 4502/5176/26013 -f 4507/5202/26014 4509/5203/26015 4503/5201/26016 -f 4503/5201/26017 4501/5200/26018 4507/5202/26019 -f 4509/5203/26020 4507/5202/26021 4505/5204/26022 -f 4505/5204/26023 4508/5205/26024 4509/5203/26025 -f 4621/5206/26026 4508/5205/26027 4505/5204/26028 -f 4505/5204/26029 4471/5207/26030 4621/5206/26031 -f 4621/5206/26032 4471/5207/26033 4469/5208/26034 -f 4469/5208/26035 4620/5209/26036 4621/5206/26037 -f 4457/5210/26038 4617/5211/26039 4620/5209/26040 -f 4620/5209/26041 4469/5208/26042 4457/5210/26043 -f 4457/5210/26044 4454/5212/26045 4616/5213/26046 -f 4616/5213/26047 4617/5211/26048 4457/5210/26049 -f 4480/5177/26050 4481/5179/26051 4492/5214/26052 -f 4492/5214/26053 4500/5178/26054 4480/5177/26055 -f 4500/5178/26056 4492/5214/26057 4499/5215/26058 -f 4499/5215/26059 4501/5200/26060 4500/5178/26061 -f 4501/5200/26062 4499/5215/26063 4506/5216/26064 -f 4506/5216/26065 4507/5202/26066 4501/5200/26067 -f 4507/5202/26068 4506/5216/26069 4504/5217/26070 -f 4504/5217/26071 4505/5204/26072 4507/5202/26073 -f 4505/5204/26074 4504/5217/26075 4470/5218/26076 -f 4470/5218/26077 4471/5207/26078 4505/5204/26079 -f 4471/5207/26080 4470/5218/26081 4468/5219/26082 -f 4468/5219/26083 4469/5208/26084 4471/5207/26085 -f 4469/5208/26086 4468/5219/26087 4456/5220/26088 -f 4456/5220/26089 4457/5210/26090 4469/5208/26091 -f 4272/4971/26092 4270/4973/26093 4454/5212/26094 -f 4454/5212/26095 4455/5221/26096 4272/4971/26097 -f 4470/5218/26098 4504/5217/26099 4493/5222/26100 -f 4493/5222/26101 4466/5223/26102 4470/5218/26103 -f 4470/5218/26104 4466/5223/26105 4462/5224/26106 -f 4462/5224/26107 4468/5219/26108 4470/5218/26109 -f 4468/5219/26110 4462/5224/26111 4453/5225/26112 -f 4453/5225/26113 4456/5220/26114 4468/5219/26115 -f 4494/5226/26116 4493/5222/26117 4504/5217/26118 -f 4504/5217/26119 4506/5216/26120 4494/5226/26121 -f 4499/5215/26122 4495/5227/26123 4494/5226/26124 -f 4494/5226/26125 4506/5216/26126 4499/5215/26127 -f 4495/5227/26128 4499/5215/26129 4492/5214/26130 -f 4492/5214/26131 4490/5228/26132 4495/5227/26133 -f 4464/5229/26134 4490/5228/26135 4492/5214/26136 -f 4492/5214/26137 4481/5179/26138 4464/5229/26139 -f 4450/5230/26140 4464/5229/26141 4481/5179/26142 -f 4481/5179/26143 4449/5185/26144 4450/5230/26145 -f 4450/5230/26146 4449/5185/26147 4444/5187/26148 -f 4444/5187/26149 4438/5231/26150 4450/5230/26151 -f 4437/5232/26152 4438/5231/26153 4444/5187/26154 -f 4444/5187/26155 4436/5189/26156 4437/5232/26157 -f 4249/4985/26158 4437/5232/26159 4436/5189/26160 -f 4436/5189/26161 4248/4986/26162 4249/4985/26163 -f 4459/5233/26164 4451/5234/26165 4452/5235/26166 -f 4452/5235/26167 4453/5225/26168 4459/5233/26169 -f 4461/5236/26170 4459/5233/26171 4453/5225/26172 -f 4453/5225/26173 4462/5224/26174 4461/5236/26175 -f 4467/5237/26176 4461/5236/26177 4462/5224/26178 -f 4462/5224/26179 4466/5223/26180 4467/5237/26181 -f 4467/5237/26182 4466/5223/26183 4493/5222/26184 -f 4493/5222/26185 4496/5238/26186 4467/5237/26187 -f 4494/5226/26188 4497/5239/26189 4496/5238/26190 -f 4496/5238/26191 4493/5222/26192 4494/5226/26193 -f 4495/5227/26194 4498/5240/26195 4497/5239/26196 -f 4497/5239/26197 4494/5226/26198 4495/5227/26199 -f 4490/5228/26200 4491/5241/26201 4498/5240/26202 -f 4498/5240/26203 4495/5227/26204 4490/5228/26205 -f 4465/5242/26206 4491/5241/26207 4490/5228/26208 -f 4490/5228/26209 4464/5229/26210 4465/5242/26211 -f 4463/5243/26212 4465/5242/26213 4464/5229/26214 -f 4464/5229/26215 4450/5230/26216 4463/5243/26217 -f 4460/5244/26218 4463/5243/26219 4450/5230/26220 -f 4450/5230/26221 4438/5231/26222 4460/5244/26223 -f 4458/5245/26224 4460/5244/26225 4438/5231/26226 -f 4438/5231/26227 4437/5232/26228 4458/5245/26229 -f 4249/4985/26230 4250/5000/26231 4458/5245/26232 -f 4458/5245/26233 4437/5232/26234 4249/4985/26235 -f 4498/5240/26236 4491/5241/26237 4496/5238/26238 -f 4496/5238/26239 4497/5239/26240 4498/5240/26241 -f 4467/5237/26242 4496/5238/26243 4491/5241/26244 -f 4491/5241/26245 4465/5242/26246 4467/5237/26247 -f 4461/5236/26248 4467/5237/26249 4465/5242/26250 -f 4465/5242/26251 4463/5243/26252 4461/5236/26253 -f 4459/5233/26254 4461/5236/26255 4463/5243/26256 -f 4463/5243/26257 4460/5244/26258 4459/5233/26259 -f 4270/4973/26260 4555/5001/26261 4616/5213/26262 -f 4616/5213/26263 4454/5212/26264 4270/4973/26265 -f 4454/5212/26266 4457/5210/26267 4456/5220/26268 -f 4456/5220/26269 4455/5221/26270 4454/5212/26271 -f 4455/5221/26272 4456/5220/26273 4453/5225/26274 -f 4453/5225/26275 4452/5235/26276 4455/5221/26277 -f 4451/5234/26278 4264/5003/26279 4266/5002/26280 -f 4266/5002/26281 4452/5235/26282 4451/5234/26283 -f 4460/5244/26284 4458/5245/26285 4451/5234/26286 -f 4451/5234/26287 4459/5233/26288 4460/5244/26289 -f 4451/5234/26290 4458/5245/26291 4250/5000/26292 -f 4250/5000/26293 4264/5003/26294 4451/5234/26295 -f 4502/5176/26296 4503/5201/26297 4512/5246/26298 -f 4512/5246/26299 4510/5175/26300 4502/5176/26301 -f 4510/5175/26302 4512/5246/26303 4538/5247/26304 -f 4538/5247/26305 4537/5174/26306 4510/5175/26307 -f 4537/5174/26308 4538/5247/26309 4541/5248/26310 -f 4541/5248/26311 4540/5172/26312 4537/5174/26313 -f 4511/5249/26314 4512/5246/26315 4503/5201/26316 -f 4503/5201/26317 4509/5203/26318 4511/5249/26319 -f 4629/5250/26320 4511/5249/26321 4509/5203/26322 -f 4509/5203/26323 4508/5205/26324 4629/5250/26325 -f 4628/5251/26326 4629/5250/26327 4508/5205/26328 -f 4508/5205/26329 4621/5206/26330 4628/5251/26331 -f 4622/5252/26332 4628/5251/26333 4621/5206/26334 -f 4621/5206/26335 4620/5209/26336 4622/5252/26337 -f 4619/5253/26338 4622/5252/26339 4620/5209/26340 -f 4620/5209/26341 4617/5211/26342 4619/5253/26343 -f 4618/5254/26344 4619/5253/26345 4617/5211/26346 -f 4617/5211/26347 4616/5213/26348 4618/5254/26349 -f 4618/5254/26350 4616/5213/26351 4555/5001/26352 -f 4555/5001/26353 4557/5013/26354 4618/5254/26355 -f 4539/5255/26356 4538/5247/26357 4512/5246/26358 -f 4512/5246/26359 4511/5249/26360 4539/5255/26361 -f 4629/5250/26362 4638/5256/26363 4539/5255/26364 -f 4539/5255/26365 4511/5249/26366 4629/5250/26367 -f 4630/5257/26368 4638/5256/26369 4629/5250/26370 -f 4629/5250/26371 4628/5251/26372 4630/5257/26373 -f 4628/5251/26374 4622/5252/26375 4625/5258/26376 -f 4625/5258/26377 4630/5257/26378 4628/5251/26379 -f 4624/5259/26380 4625/5258/26381 4622/5252/26382 -f 4622/5252/26383 4619/5253/26384 4624/5259/26385 -f 4623/5260/26386 4624/5259/26387 4619/5253/26388 -f 4619/5253/26389 4618/5254/26390 4623/5260/26391 -f 4618/5254/26392 4557/5013/26393 4560/5020/26394 -f 4560/5020/26395 4623/5260/26396 4618/5254/26397 -f 4538/5247/26398 4539/5255/26399 4642/5261/26400 -f 4642/5261/26401 4543/5262/26402 4538/5247/26403 -f 4639/5263/26404 4642/5261/26405 4539/5255/26406 -f 4539/5255/26407 4638/5256/26408 4639/5263/26409 -f 4640/5264/26410 4639/5263/26411 4638/5256/26412 -f 4638/5256/26413 4630/5257/26414 4640/5264/26415 -f 4626/5265/26416 4640/5264/26417 4630/5257/26418 -f 4630/5257/26419 4625/5258/26420 4626/5265/26421 -f 4632/5266/26422 4626/5265/26423 4625/5258/26424 -f 4625/5258/26425 4624/5259/26426 4632/5266/26427 -f 4631/5267/26428 4632/5266/26429 4624/5259/26430 -f 4624/5259/26431 4623/5260/26432 4631/5267/26433 -f 4631/5267/26434 4623/5260/26435 4560/5020/26436 -f 4560/5020/26437 4564/5028/26438 4631/5267/26439 -f 4538/5247/26440 4543/5262/26441 4542/5268/26442 -f 4542/5268/26443 4541/5248/26444 4538/5247/26445 -f 4540/5172/26446 4541/5248/26447 4531/5269/26448 -f 4531/5269/26449 4530/5171/26450 4540/5172/26451 -f 4530/5171/26452 4531/5269/26453 4529/5271/26454 -f 4529/5271/26455 4519/5170/26456 4530/5171/26457 -f 4519/5170/26458 4529/5271/26459 4518/5272/26460 -f 4518/5272/26461 4516/5169/26462 4519/5170/26463 -f 4516/5169/26464 4518/5272/26465 4515/5276/26466 -f 4515/5276/26467 4514/5168/26468 4516/5169/26469 -f 4513/5313/26470 4347/5167/26471 4514/5168/26472 -f 4514/5168/26473 4515/5276/26474 4513/5313/26475 -f 4347/5167/26476 4513/5313/26477 4326/5035/26478 -f 4326/5035/26479 4130/4913/26480 4347/5167/26481 -f 4632/5266/26482 4631/5267/26483 4633/5314/26484 -f 4633/5314/26485 4634/5315/26486 4632/5266/26487 -f 4632/5266/26488 4634/5315/26489 4627/5316/26490 -f 4627/5316/26491 4626/5265/26492 4632/5266/26493 -f 4640/5264/26494 4626/5265/26495 4627/5316/26496 -f 4627/5316/26497 4641/5317/26498 4640/5264/26499 -f 4649/5318/26500 4639/5263/26501 4640/5264/26502 -f 4640/5264/26503 4641/5317/26504 4649/5318/26505 -f 4649/5318/26506 4643/5319/26507 4642/5261/26508 -f 4642/5261/26509 4639/5263/26510 4649/5318/26511 -f 4642/5261/26512 4643/5319/26513 4544/5320/26514 -f 4544/5320/26515 4543/5262/26516 4642/5261/26517 -f 4543/5262/26518 4544/5320/26519 4698/5321/26520 -f 4698/5321/26521 4542/5268/26522 4543/5262/26523 -f 4698/5321/26524 4544/5320/26525 4701/5322/26526 -f 4701/5322/26527 4699/5323/26528 4698/5321/26529 -f 4701/5322/26530 4544/5320/26531 4643/5319/26532 -f 4643/5319/26533 4644/5324/26534 4701/5322/26535 -f 4643/5319/26536 4649/5318/26537 4647/5325/26538 -f 4647/5325/26539 4644/5324/26540 4643/5319/26541 -f 4649/5318/26542 4641/5317/26543 4635/5326/26544 -f 4635/5326/26545 4647/5325/26546 4649/5318/26547 -f 4627/5316/26548 4658/5327/26549 4635/5326/26550 -f 4635/5326/26551 4641/5317/26552 4627/5316/26553 -f 4654/5328/26554 4658/5327/26555 4627/5316/26556 -f 4627/5316/26557 4634/5315/26558 4654/5328/26559 -f 4653/5329/26560 4654/5328/26561 4634/5315/26562 -f 4634/5315/26563 4633/5314/26564 4653/5329/26565 -f 4605/5052/26566 4653/5329/26567 4633/5314/26568 -f 4633/5314/26569 4568/5053/26570 4605/5052/26571 -f 4700/5374/26572 4699/5375/26573 4701/5377/26574 -f 4701/5377/26575 4704/5378/26576 4700/5374/26577 -f 4648/5379/26578 4645/5380/26579 4644/5381/26580 -f 4644/5381/26581 4647/5382/26582 4648/5379/26583 -f 4636/5383/26584 4648/5379/26585 4647/5382/26586 -f 4647/5382/26587 4635/5384/26588 4636/5383/26589 -f 4635/5384/26590 4658/5385/26591 4659/5386/26592 -f 4659/5386/26593 4636/5383/26594 4635/5384/26595 -f 4655/5387/26596 4659/5386/26597 4658/5385/26598 -f 4658/5385/26599 4654/5388/26600 4655/5387/26601 -f 4656/5389/26602 4655/5387/26603 4654/5388/26604 -f 4654/5388/26605 4653/5390/26606 4656/5389/26607 -f 4606/5460/26608 4656/5389/26609 4653/5390/26610 -f 4653/5390/26611 4605/5461/26612 4606/5460/26613 -f 4656/5389/26614 4606/5460/26615 4615/5462/26616 -f 4615/5462/26617 4663/5391/26618 4656/5389/26619 -f 4656/5389/26620 4663/5391/26621 4657/5392/26622 -f 4657/5392/26623 4655/5387/26624 4656/5389/26625 -f 4655/5387/26626 4657/5392/26627 4660/5393/26628 -f 4660/5393/26629 4659/5386/26630 4655/5387/26631 -f 4637/5394/26632 4636/5383/26633 4659/5386/26634 -f 4659/5386/26635 4660/5393/26636 4637/5394/26637 -f 4648/5379/26638 4636/5383/26639 4637/5394/26640 -f 4637/5394/26641 4650/5396/26642 4648/5379/26643 -f 4646/5397/26644 4645/5380/26645 4648/5379/26646 -f 4648/5379/26647 4650/5396/26648 4646/5397/26649 -f 4645/5380/26650 4646/5397/26651 4702/5398/26652 -f 4702/5398/26653 4644/5381/26654 4645/5380/26655 -f 4701/5377/26656 4644/5381/26657 4702/5398/26658 -f 4702/5398/26659 4704/5378/26660 4701/5377/26661 -f 4696/5399/26662 4700/5374/26663 4705/5400/26664 -f 4705/5400/26665 4697/5401/26666 4696/5399/26667 -f 4729/5402/26668 4703/5403/26669 4704/5378/26670 -f 4704/5378/26671 4702/5398/26672 4729/5402/26673 -f 4730/5404/26674 4729/5402/26675 4702/5398/26676 -f 4702/5398/26677 4646/5397/26678 4730/5404/26679 -f 4652/5405/26680 4730/5404/26681 4646/5397/26682 -f 4646/5397/26683 4650/5396/26684 4652/5405/26685 -f 4651/5406/26686 4652/5405/26687 4650/5396/26688 -f 4650/5396/26689 4637/5394/26690 4651/5406/26691 -f 4670/5407/26692 4651/5406/26693 4637/5394/26694 -f 4637/5394/26695 4660/5393/26696 4670/5407/26697 -f 4661/5408/26698 4670/5407/26699 4660/5393/26700 -f 4660/5393/26701 4657/5392/26702 4661/5408/26703 -f 4665/5409/26704 4661/5408/26705 4657/5392/26706 -f 4657/5392/26707 4663/5391/26708 4665/5409/26709 -f 4662/5410/26710 4663/5391/26711 4615/5462/26712 -f 4615/5462/26713 4613/5463/26714 4662/5410/26715 -f 4664/5411/26716 4665/5409/26717 4663/5391/26718 -f 4663/5391/26719 4662/5410/26720 4664/5411/26721 -f 4669/5412/26722 4666/5413/26723 4665/5409/26724 -f 4665/5409/26725 4664/5411/26726 4669/5412/26727 -f 4671/5414/26728 4661/5408/26729 4665/5409/26730 -f 4665/5409/26731 4666/5413/26732 4671/5414/26733 -f 4672/5415/26734 4670/5407/26735 4661/5408/26736 -f 4661/5408/26737 4671/5414/26738 4672/5415/26739 -f 4673/5416/26740 4651/5406/26741 4670/5407/26742 -f 4670/5407/26743 4672/5415/26744 4673/5416/26745 -f 4733/5417/26746 4652/5405/26747 4651/5406/26748 -f 4651/5406/26749 4673/5416/26750 4733/5417/26751 -f 4652/5405/26752 4733/5417/26753 4731/5418/26754 -f 4731/5418/26755 4730/5404/26756 4652/5405/26757 -f 4732/5419/26758 4729/5402/26759 4730/5404/26760 -f 4730/5404/26761 4731/5418/26762 4732/5419/26763 -f 4729/5402/26764 4732/5419/26765 4706/5420/26766 -f 4706/5420/26767 4703/5403/26768 4729/5402/26769 -f 4700/5374/26770 4704/5378/26771 4703/5403/26772 -f 4703/5403/26773 4705/5400/26774 4700/5374/26775 -f 4703/5403/26776 4706/5420/26777 4697/5401/26778 -f 4697/5401/26779 4705/5400/26780 4703/5403/26781 -f 4696/5399/26782 4697/5401/26783 4708/5421/26784 -f 4708/5421/26785 4707/5422/26786 4696/5399/26787 -f 4707/5422/26788 4708/5421/26789 4693/5465/26790 -f 4693/5465/26791 4690/5464/26792 4707/5422/26793 -f 4668/5423/26794 4667/5424/26795 4666/5413/26796 -f 4666/5413/26797 4669/5412/26798 4668/5423/26799 -f 4671/5414/26800 4666/5413/26801 4667/5424/26802 -f 4667/5424/26803 4676/5425/26804 4671/5414/26805 -f 4671/5414/26806 4676/5425/26807 4674/5426/26808 -f 4674/5426/26809 4672/5415/26810 4671/5414/26811 -f 4673/5416/26812 4672/5415/26813 4674/5426/26814 -f 4674/5426/26815 4740/5427/26816 4673/5416/26817 -f 4673/5416/26818 4740/5427/26819 4734/5428/26820 -f 4734/5428/26821 4733/5417/26822 4673/5416/26823 -f 4733/5417/26824 4734/5428/26825 4737/5429/26826 -f 4737/5429/26827 4731/5418/26828 4733/5417/26829 -f 4731/5418/26830 4737/5429/26831 4735/5430/26832 -f 4735/5430/26833 4732/5419/26834 4731/5418/26835 -f 4732/5419/26836 4735/5430/26837 4736/5431/26838 -f 4736/5431/26839 4706/5420/26840 4732/5419/26841 -f 4706/5420/26842 4736/5431/26843 4710/5432/26844 -f 4710/5432/26845 4697/5401/26846 4706/5420/26847 -f 4697/5401/26848 4710/5432/26849 4709/5433/26850 -f 4709/5433/26851 4708/5421/26852 4697/5401/26853 -f 4695/5466/26854 4693/5465/26855 4708/5421/26856 -f 4708/5421/26857 4709/5433/26858 4695/5466/26859 -f 4676/5425/26860 4667/5424/26861 4668/5423/26862 -f 4668/5423/26863 4677/5434/26864 4676/5425/26865 -f 4676/5425/26866 4677/5434/26867 4675/5435/26868 -f 4675/5435/26869 4674/5426/26870 4676/5425/26871 -f 4674/5426/26872 4675/5435/26873 4741/5436/26874 -f 4741/5436/26875 4740/5427/26876 4674/5426/26877 -f 4740/5427/26878 4741/5436/26879 4742/5437/26880 -f 4742/5437/26881 4734/5428/26882 4740/5427/26883 -f 4739/5438/26884 4737/5429/26885 4734/5428/26886 -f 4734/5428/26887 4742/5437/26888 4739/5438/26889 -f 4735/5430/26890 4737/5429/26891 4739/5438/26892 -f 4739/5438/26893 4738/5439/26894 4735/5430/26895 -f 4735/5430/26896 4738/5439/26897 4744/5440/26898 -f 4744/5440/26899 4736/5431/26900 4735/5430/26901 -f 4745/5441/26902 4710/5432/26903 4736/5431/26904 -f 4736/5431/26905 4744/5440/26906 4745/5441/26907 -f 4710/5432/26908 4745/5441/26909 4743/5442/26910 -f 4743/5442/26911 4709/5433/26912 4710/5432/26913 -f 4709/5433/26914 4743/5442/26915 4728/5467/26916 -f 4728/5467/26917 4695/5466/26918 4709/5433/26919 -f 4391/5122/26920 4365/5117/26921 4366/5330/26922 -f 4366/5330/26923 4388/5331/26924 4391/5122/26925 -f 4369/5335/26926 4366/5330/26927 4365/5117/26928 -f 4365/5117/26929 4363/5111/26930 4369/5335/26931 -f 4374/5105/26932 4375/5336/26933 4369/5335/26934 -f 4369/5335/26935 4363/5111/26936 4374/5105/26937 -f 4373/5102/26938 4376/5337/26939 4375/5336/26940 -f 4375/5336/26941 4374/5105/26942 4373/5102/26943 -f 4372/5099/26944 4377/5338/26945 4376/5337/26946 -f 4376/5337/26947 4373/5102/26948 4372/5099/26949 -f 4381/5095/26950 4382/5339/26951 4377/5338/26952 -f 4377/5338/26953 4372/5099/26954 4381/5095/26955 -f 4394/5094/26956 4395/5340/26957 4382/5339/26958 -f 4382/5339/26959 4381/5095/26960 4394/5094/26961 -f 4398/5346/26962 4395/5340/26963 4394/5094/26964 -f 4394/5094/26965 4397/5096/26966 4398/5346/26967 -f 4412/5097/26968 4402/5376/26969 4398/5346/26970 -f 4398/5346/26971 4397/5096/26972 4412/5097/26973 -f 4413/5098/26974 4403/5395/26975 4402/5376/26976 -f 4402/5376/26977 4412/5097/26978 4413/5098/26979 -f 4414/5107/26980 4404/5443/26981 4403/5395/26982 -f 4403/5395/26983 4413/5098/26984 4414/5107/26985 -f 4410/5113/26986 4400/5444/26987 4404/5443/26988 -f 4404/5443/26989 4414/5107/26990 4410/5113/26991 -f 4390/5119/26992 4392/5445/26993 4400/5444/26994 -f 4400/5444/26995 4410/5113/26996 4390/5119/26997 -f 4390/5119/26998 4391/5122/26999 4388/5331/27000 -f 4388/5331/27001 4392/5445/27002 4390/5119/27003 -f 4388/5331/27004 4366/5330/27005 4371/5446/27006 -f 4371/5446/27007 4389/5447/27008 4388/5331/27009 -f 4369/5335/27010 4370/5448/27011 4371/5446/27012 -f 4371/5446/27013 4366/5330/27014 4369/5335/27015 -f 4375/5336/27016 4378/5449/27017 4370/5448/27018 -f 4370/5448/27019 4369/5335/27020 4375/5336/27021 -f 4376/5337/27022 4379/5450/27023 4378/5449/27024 -f 4378/5449/27025 4375/5336/27026 4376/5337/27027 -f 4377/5338/27028 4380/5451/27029 4379/5450/27030 -f 4379/5450/27031 4376/5337/27032 4377/5338/27033 -f 4382/5339/27034 4383/5452/27035 4380/5451/27036 -f 4380/5451/27037 4377/5338/27038 4382/5339/27039 -f 4396/5453/27040 4383/5452/27041 4382/5339/27042 -f 4382/5339/27043 4395/5340/27044 4396/5453/27045 -f 4398/5346/27046 4399/5454/27047 4396/5453/27048 -f 4396/5453/27049 4395/5340/27050 4398/5346/27051 -f 4402/5376/27052 4405/5455/27053 4399/5454/27054 -f 4399/5454/27055 4398/5346/27056 4402/5376/27057 -f 4403/5395/27058 4406/5456/27059 4405/5455/27060 -f 4405/5455/27061 4402/5376/27062 4403/5395/27063 -f 4404/5443/27064 4407/5457/27065 4406/5456/27066 -f 4406/5456/27067 4403/5395/27068 4404/5443/27069 -f 4400/5444/27070 4401/5458/27071 4407/5457/27072 -f 4407/5457/27073 4404/5443/27074 4400/5444/27075 -f 4393/5459/27076 4401/5458/27077 4400/5444/27078 -f 4400/5444/27079 4392/5445/27080 4393/5459/27081 -f 4389/5447/27082 4393/5459/27083 4392/5445/27084 -f 4392/5445/27085 4388/5331/27086 4389/5447/27087 -f 4423/5136/27088 4427/5146/27089 4473/5145/27090 -f 4473/5145/27091 4472/5137/27092 4423/5136/27093 -f 4358/5101/27094 4356/5135/27095 4346/5143/27096 -f 4346/5143/27097 4423/5136/27098 4358/5101/27099 -f 4436/5189/27100 4429/5188/27101 4247/4938/27102 -f 4247/4938/27103 4248/4986/27104 4436/5189/27105 -f 4272/4971/27106 4455/5221/27107 4452/5235/27108 -f 4452/5235/27109 4266/5002/27110 4272/4971/27111 -f 4568/5053/27112 4633/5314/27113 4631/5267/27114 -f 4631/5267/27115 4564/5028/27116 4568/5053/27117 -f 4770/5468/27118 4771/5469/27119 4746/5470/27120 -f 4746/5470/27121 4747/5471/27122 4770/5468/27123 -f 4749/5472/27124 4748/5473/27125 4747/5471/27126 -f 4747/5471/27127 4746/5470/27128 4749/5472/27129 -f 4750/5475/27130 4748/5473/27131 4749/5472/27132 -f 4749/5472/27133 4751/5474/27134 4750/5475/27135 -f 4752/5477/27136 4750/5475/27137 4751/5474/27138 -f 4751/5474/27139 4753/5476/27140 4752/5477/27141 -f 4753/5476/27142 4755/5478/27143 4754/5479/27144 -f 4754/5479/27145 4752/5477/27146 4753/5476/27147 -f 4757/5480/27148 4754/5479/27149 4755/5478/27150 -f 4755/5478/27151 4756/5481/27152 4757/5480/27153 -f 4758/5482/27154 4759/5483/27155 4757/5480/27156 -f 4757/5480/27157 4756/5481/27158 4758/5482/27159 -f 4761/5485/27160 4759/5483/27161 4758/5482/27162 -f 4758/5482/27163 4760/5484/27164 4761/5485/27165 -f 4761/5485/27166 4760/5484/27167 4763/5487/27168 -f 4763/5487/27169 4762/5486/27170 4761/5485/27171 -f 4763/5487/27172 4765/5488/27173 4764/5489/27174 -f 4764/5489/27175 4762/5486/27176 4763/5487/27177 -f 4765/5488/27178 4767/5490/27179 4766/5491/27180 -f 4766/5491/27181 4764/5489/27182 4765/5488/27183 -f 4768/5493/27184 4766/5491/27185 4767/5490/27186 -f 4767/5490/27187 4769/5492/27188 4768/5493/27189 -f 4773/5495/27190 4771/5469/27191 4770/5468/27192 -f 4770/5468/27193 4772/5494/27194 4773/5495/27195 -f 4773/5495/27196 4772/5494/27197 4774/5496/27198 -f 4774/5496/27199 4775/5497/27200 4773/5495/27201 -f 4777/5499/27202 4775/5497/27203 4774/5496/27204 -f 4774/5496/27205 4776/5498/27206 4777/5499/27207 -f 4777/5499/27208 4776/5498/27209 4778/5500/27210 -f 4778/5500/27211 4779/5501/27212 4777/5499/27213 -f 4784/5503/27214 4785/5504/27215 4783/5505/27216 -f 4783/5505/27217 4782/5502/27218 4784/5503/27219 -f 4782/5502/27220 4783/5505/27221 4781/5506/27222 -f 4781/5506/27223 4780/5507/27224 4782/5502/27225 -f 4780/5507/27226 4781/5506/27227 4779/5501/27228 -f 4779/5501/27229 4778/5500/27230 4780/5507/27231 -f 4794/5509/27232 4795/5510/27233 4793/5511/27234 -f 4793/5511/27235 4792/5508/27236 4794/5509/27237 -f 4792/5508/27238 4793/5511/27239 4791/5512/27240 -f 4791/5512/27241 4790/5513/27242 4792/5508/27243 -f 4790/5513/27244 4791/5512/27245 4789/5514/27246 -f 4789/5514/27247 4788/5515/27248 4790/5513/27249 -f 4788/5515/27250 4789/5514/27251 4787/5516/27252 -f 4787/5516/27253 4786/5517/27254 4788/5515/27255 -f 4787/5516/27256 4785/5504/27257 4784/5503/27258 -f 4784/5503/27259 4786/5517/27260 4787/5516/27261 -f 4804/5519/27262 4768/5493/27263 4769/5492/27264 -f 4769/5492/27265 4805/5518/27266 4804/5519/27267 -f 4803/5520/27268 4802/5521/27269 4804/5519/27270 -f 4804/5519/27271 4805/5518/27272 4803/5520/27273 -f 4801/5522/27274 4800/5523/27275 4802/5521/27276 -f 4802/5521/27277 4803/5520/27278 4801/5522/27279 -f 4799/5524/27280 4798/5525/27281 4800/5523/27282 -f 4800/5523/27283 4801/5522/27284 4799/5524/27285 -f 4796/5526/27286 4798/5525/27287 4799/5524/27288 -f 4799/5524/27289 4797/5527/27290 4796/5526/27291 -f 4806/5528/27292 4800/5523/27293 4798/5525/27294 -f 4798/5525/27295 4807/5529/27296 4806/5528/27297 -f 4808/5530/27298 4807/5529/27299 4798/5525/27300 -f 4798/5525/27301 4796/5526/27302 4808/5530/27303 -f 4796/5526/27304 4794/5509/27305 4809/5531/27306 -f 4809/5531/27307 4808/5530/27308 4796/5526/27309 -f 4794/5509/27310 4792/5508/27311 4810/5532/27312 -f 4810/5532/27313 4809/5531/27314 4794/5509/27315 -f 4792/5508/27316 4790/5513/27317 4811/5533/27318 -f 4811/5533/27319 4810/5532/27320 4792/5508/27321 -f 4786/5517/27322 4813/5534/27323 4812/5535/27324 -f 4812/5535/27325 4788/5515/27326 4786/5517/27327 -f 4780/5507/27328 4815/5536/27329 4814/5537/27330 -f 4814/5537/27331 4782/5502/27332 4780/5507/27333 -f 4786/5517/27334 4784/5503/27335 4782/5502/27336 -f 4782/5502/27337 4813/5534/27338 4786/5517/27339 -f 4813/5534/27340 4782/5502/27341 4814/5537/27342 -f 4814/5537/27343 4812/5535/27344 4813/5534/27345 -f 4816/5538/27346 4802/5521/27347 4800/5523/27348 -f 4800/5523/27349 4806/5528/27350 4816/5538/27351 -f 4817/5539/27352 4804/5519/27353 4802/5521/27354 -f 4802/5521/27355 4816/5538/27356 4817/5539/27357 -f 4804/5519/27358 4817/5539/27359 4818/5540/27360 -f 4818/5540/27361 4768/5493/27362 4804/5519/27363 -f 4907/5541/27364 4766/5491/27365 4768/5493/27366 -f 4768/5493/27367 4818/5540/27368 4907/5541/27369 -f 4842/5542/27370 4764/5489/27371 4766/5491/27372 -f 4766/5491/27373 4907/5541/27374 4842/5542/27375 -f 4819/5543/27376 4762/5486/27377 4764/5489/27378 -f 4764/5489/27379 4842/5542/27380 4819/5543/27381 -f 4819/5543/27382 4759/5483/27383 4761/5485/27384 -f 4761/5485/27385 4762/5486/27386 4819/5543/27387 -f 4820/5544/27388 4757/5480/27389 4759/5483/27390 -f 4759/5483/27391 4819/5543/27392 4820/5544/27393 -f 4757/5480/27394 4820/5544/27395 4821/5545/27396 -f 4821/5545/27397 4754/5479/27398 4757/5480/27399 -f 4754/5479/27400 4821/5545/27401 4822/5546/27402 -f 4822/5546/27403 4752/5477/27404 4754/5479/27405 -f 4823/5547/27406 4750/5475/27407 4752/5477/27408 -f 4752/5477/27409 4822/5546/27410 4823/5547/27411 -f 4824/5548/27412 4748/5473/27413 4750/5475/27414 -f 4750/5475/27415 4823/5547/27416 4824/5548/27417 -f 4825/5549/27418 4747/5471/27419 4748/5473/27420 -f 4748/5473/27421 4824/5548/27422 4825/5549/27423 -f 4747/5471/27424 4825/5549/27425 4826/5550/27426 -f 4826/5550/27427 4770/5468/27428 4747/5471/27429 -f 4772/5494/27430 4770/5468/27431 4826/5550/27432 -f 4826/5550/27433 4827/5551/27434 4772/5494/27435 -f 4828/5552/27436 4829/5553/27437 4776/5498/27438 -f 4776/5498/27439 4774/5496/27440 4828/5552/27441 -f 4778/5500/27442 4776/5498/27443 4829/5553/27444 -f 4829/5553/27445 4830/5554/27446 4778/5500/27447 -f 4815/5536/27448 4780/5507/27449 4778/5500/27450 -f 4778/5500/27451 4830/5554/27452 4815/5536/27453 -f 4815/5536/27454 4831/5555/27455 4812/5535/27456 -f 4812/5535/27457 4814/5537/27458 4815/5536/27459 -f 4832/5556/27460 4833/5557/27461 4810/5532/27462 -f 4810/5532/27463 4811/5533/27464 4832/5556/27465 -f 4834/5558/27466 4831/5555/27467 4815/5536/27468 -f 4815/5536/27469 4830/5554/27470 4834/5558/27471 -f 4810/5532/27472 4833/5557/27473 4835/5559/27474 -f 4835/5559/27475 4809/5531/27476 4810/5532/27477 -f 4809/5531/27478 4835/5559/27479 4836/5560/27480 -f 4836/5560/27481 4808/5530/27482 4809/5531/27483 -f 4808/5530/27484 4836/5560/27485 4837/5561/27486 -f 4837/5561/27487 4807/5529/27488 4808/5530/27489 -f 4845/5562/27490 4806/5528/27491 4807/5529/27492 -f 4807/5529/27493 4837/5561/27494 4845/5562/27495 -f 4839/5563/27496 4817/5539/27497 4816/5538/27498 -f 4816/5538/27499 4838/5564/27500 4839/5563/27501 -f 4841/5565/27502 4840/5566/27503 4821/5545/27504 -f 4821/5545/27505 4820/5544/27506 4841/5565/27507 -f 4841/5565/27508 4820/5544/27509 4819/5543/27510 -f 4819/5543/27511 4842/5542/27512 4841/5565/27513 -f 4818/5540/27514 4906/5567/27515 4907/5541/27516 -f 4905/5569/27517 4906/5567/27518 4818/5540/27519 -f 4818/5540/27520 4843/5568/27521 4905/5569/27522 -f 4843/5568/27523 4818/5540/27524 4817/5539/27525 -f 4817/5539/27526 4839/5563/27527 4843/5568/27528 -f 4843/5568/27529 4839/5563/27530 4844/5570/27531 -f 4844/5570/27532 4840/5566/27533 4843/5568/27534 -f 4845/5562/27535 4838/5564/27536 4816/5538/27537 -f 4816/5538/27538 4806/5528/27539 4845/5562/27540 -f 4840/5566/27541 4844/5570/27542 4822/5546/27543 -f 4822/5546/27544 4821/5545/27545 4840/5566/27546 -f 4846/5571/27547 4844/5570/27548 4839/5563/27549 -f 4839/5563/27550 4838/5564/27551 4846/5571/27552 -f 4847/5572/27553 4846/5571/27554 4838/5564/27555 -f 4838/5564/27556 4845/5562/27557 4847/5572/27558 -f 4845/5562/27559 4837/5561/27560 4848/5573/27561 -f 4848/5573/27562 4847/5572/27563 4845/5562/27564 -f 4836/5560/27565 4849/5574/27566 4848/5573/27567 -f 4848/5573/27568 4837/5561/27569 4836/5560/27570 -f 4850/5575/27571 4849/5574/27572 4836/5560/27573 -f 4836/5560/27574 4835/5559/27575 4850/5575/27576 -f 4833/5557/27577 4832/5556/27578 4831/5555/27579 -f 4831/5555/27580 4834/5558/27581 4833/5557/27582 -f 4833/5557/27583 4834/5558/27584 4850/5575/27585 -f 4850/5575/27586 4835/5559/27587 4833/5557/27588 -f 4851/5576/27589 4834/5558/27590 4830/5554/27591 -f 4830/5554/27592 4829/5553/27593 4851/5576/27594 -f 4834/5558/27595 4851/5576/27596 4852/5577/27597 -f 4852/5577/27598 4850/5575/27599 4834/5558/27600 -f 4853/5578/27601 4852/5577/27602 4851/5576/27603 -f 4851/5576/27604 4829/5553/27605 4853/5578/27606 -f 4854/5579/27607 4853/5578/27608 4829/5553/27609 -f 4829/5553/27610 4828/5552/27611 4854/5579/27612 -f 4855/5580/27613 4854/5579/27614 4828/5552/27615 -f 4828/5552/27616 4827/5551/27617 4855/5580/27618 -f 4827/5551/27619 4826/5550/27620 4856/5581/27621 -f 4856/5581/27622 4855/5580/27623 4827/5551/27624 -f 4856/5581/27625 4826/5550/27626 4825/5549/27627 -f 4825/5549/27628 4857/5582/27629 4856/5581/27630 -f 4858/5583/27631 4857/5582/27632 4825/5549/27633 -f 4825/5549/27634 4824/5548/27635 4858/5583/27636 -f 4859/5584/27637 4858/5583/27638 4824/5548/27639 -f 4824/5548/27640 4823/5547/27641 4859/5584/27642 -f 4823/5547/27643 4822/5546/27644 4860/5585/27645 -f 4860/5585/27646 4859/5584/27647 4823/5547/27648 -f 4844/5570/27649 4846/5571/27650 4860/5585/27651 -f 4860/5585/27652 4822/5546/27653 4844/5570/27654 -f 4861/5586/27655 4860/5585/27656 4846/5571/27657 -f 4846/5571/27658 4847/5572/27659 4861/5586/27660 -f 4847/5572/27661 4848/5573/27662 4862/5587/27663 -f 4862/5587/27664 4861/5586/27665 4847/5572/27666 -f 4863/5588/27667 4862/5587/27668 4848/5573/27669 -f 4848/5573/27670 4849/5574/27671 4863/5588/27672 -f 4850/5575/27673 4852/5577/27674 4863/5588/27675 -f 4863/5588/27676 4849/5574/27677 4850/5575/27678 -f 4864/5589/27679 4863/5588/27680 4852/5577/27681 -f 4852/5577/27682 4853/5578/27683 4864/5589/27684 -f 4863/5588/27685 4864/5589/27686 4865/5590/27687 -f 4865/5590/27688 4862/5587/27689 4863/5588/27690 -f 4866/5591/27691 4861/5586/27692 4862/5587/27693 -f 4862/5587/27694 4865/5590/27695 4866/5591/27696 -f 4860/5585/27697 4861/5586/27698 4866/5591/27699 -f 4866/5591/27700 4859/5584/27701 4860/5585/27702 -f 4859/5584/27703 4866/5591/27704 4867/5592/27705 -f 4867/5592/27706 4858/5583/27707 4859/5584/27708 -f 4858/5583/27709 4867/5592/27710 4868/5593/27711 -f 4868/5593/27712 4857/5582/27713 4858/5583/27714 -f 4869/5594/27715 4856/5581/27716 4857/5582/27717 -f 4857/5582/27718 4868/5593/27719 4869/5594/27720 -f 4856/5581/27721 4869/5594/27722 4870/5595/27723 -f 4870/5595/27724 4855/5580/27725 4856/5581/27726 -f 4855/5580/27727 4870/5595/27728 4871/5596/27729 -f 4871/5596/27730 4854/5579/27731 4855/5580/27732 -f 4853/5578/27733 4854/5579/27734 4871/5596/27735 -f 4871/5596/27736 4864/5589/27737 4853/5578/27738 -f 4867/5592/27739 4872/5597/27740 4869/5594/27741 -f 4869/5594/27742 4868/5593/27743 4867/5592/27744 -f 4872/5597/27745 4871/5596/27746 4870/5595/27747 -f 4870/5595/27748 4869/5594/27749 4872/5597/27750 -f 4866/5591/27751 4865/5590/27752 4872/5597/27753 -f 4872/5597/27754 4867/5592/27755 4866/5591/27756 -f 4872/5597/27757 4865/5590/27758 4864/5589/27759 -f 4864/5589/27760 4871/5596/27761 4872/5597/27762 -f 4873/5598/27763 4874/5599/27764 4771/5469/27765 -f 4771/5469/27766 4773/5495/27767 4873/5598/27768 -f 4875/5600/27769 4746/5470/27770 4771/5469/27771 -f 4771/5469/27772 4874/5599/27773 4875/5600/27774 -f 4876/5601/27775 4749/5472/27776 4746/5470/27777 -f 4746/5470/27778 4875/5600/27779 4876/5601/27780 -f 4877/5602/27781 4751/5474/27782 4749/5472/27783 -f 4749/5472/27784 4876/5601/27785 4877/5602/27786 -f 4751/5474/27787 4877/5602/27788 4878/5603/27789 -f 4878/5603/27790 4753/5476/27791 4751/5474/27792 -f 4753/5476/27793 4878/5603/27794 4879/5604/27795 -f 4879/5604/27796 4755/5478/27797 4753/5476/27798 -f 4755/5478/27799 4879/5604/27800 4880/5605/27801 -f 4880/5605/27802 4756/5481/27803 4755/5478/27804 -f 4756/5481/27805 4880/5605/27806 4881/5606/27807 -f 4881/5606/27808 4758/5482/27809 4756/5481/27810 -f 4758/5482/27811 4881/5606/27812 4882/5607/27813 -f 4882/5607/27814 4760/5484/27815 4758/5482/27816 -f 4760/5484/27817 4882/5630/27818 4883/5608/27819 -f 4883/5608/27820 4763/5487/27821 4760/5484/27822 -f 4883/5608/27823 4884/5609/27824 4765/5488/27825 -f 4765/5488/27826 4763/5487/27827 4883/5608/27828 -f 4885/5610/27829 4767/5490/27830 4765/5488/27831 -f 4765/5488/27832 4884/5609/27833 4885/5610/27834 -f 4886/5611/27835 4769/5492/27836 4767/5490/27837 -f 4767/5490/27838 4885/5610/27839 4886/5611/27840 -f 4769/5492/27841 4886/5611/27842 4887/5612/27843 -f 4887/5612/27844 4805/5518/27845 4769/5492/27846 -f 4805/5518/27847 4887/5612/27848 4888/5613/27849 -f 4888/5613/27850 4803/5520/27851 4805/5518/27852 -f 4803/5520/27853 4888/5631/27854 4889/5614/27855 -f 4889/5614/27856 4801/5522/27857 4803/5520/27858 -f 4890/5615/27859 4799/5524/27860 4801/5522/27861 -f 4801/5522/27862 4889/5614/27863 4890/5615/27864 -f 4799/5524/27865 4890/5615/27866 4891/5616/27867 -f 4891/5616/27868 4797/5527/27869 4799/5524/27870 -f 4797/5527/27871 4891/5616/27872 4892/5617/27873 -f 4892/5617/27874 4795/5510/27875 4797/5527/27876 -f 4793/5511/27877 4893/5619/27878 4894/5618/27879 -f 4894/5618/27880 4791/5512/27881 4793/5511/27882 -f 4791/5512/27883 4894/5618/27884 4895/5620/27885 -f 4895/5620/27886 4789/5514/27887 4791/5512/27888 -f 4789/5514/27889 4895/5620/27890 4896/5621/27891 -f 4896/5621/27892 4787/5516/27893 4789/5514/27894 -f 4787/5516/27895 4896/5621/27896 4897/5622/27897 -f 4897/5622/27898 4785/5504/27899 4787/5516/27900 -f 4785/5504/27901 4897/5632/27902 4898/5623/27903 -f 4898/5623/27904 4783/5505/27905 4785/5504/27906 -f 4783/5505/27907 4898/5623/27908 4899/5624/27909 -f 4899/5624/27910 4781/5506/27911 4783/5505/27912 -f 4781/5506/27913 4899/5624/27914 4900/5625/27915 -f 4900/5625/27916 4779/5501/27917 4781/5506/27918 -f 4779/5501/27919 4900/5625/27920 4901/5626/27921 -f 4901/5626/27922 4777/5499/27923 4779/5501/27924 -f 4777/5499/27925 4901/5626/27926 4902/5627/27927 -f 4902/5627/27928 4775/5497/27929 4777/5499/27930 -f 4775/5497/27931 4902/5627/27932 4873/5598/27933 -f 4873/5598/27934 4773/5495/27935 4775/5497/27936 -f 4898/5623/27937 4897/5632/27938 4903/5628/27939 -f 4883/5608/27940 4882/5630/27941 4904/5629/27942 -f 4831/5555/27943 4832/5556/27944 4811/5533/27945 -f 4811/5533/27946 4812/5535/27947 4831/5555/27948 -f 4840/5566/27949 4841/5565/27950 4905/5569/27951 -f 4841/5565/27952 4906/5567/27953 4905/5569/27954 -f 4906/5567/27955 4841/5565/27956 4842/5542/27957 -f 4842/5542/27958 4907/5541/27959 4906/5567/27960 -f 4905/5569/27961 4843/5568/27962 4840/5566/27963 -f 4812/5535/27964 4811/5533/27965 4790/5513/27966 -f 4790/5513/27967 4788/5515/27968 4812/5535/27969 -f 4827/5551/27970 4828/5552/27971 4774/5496/27972 -f 4774/5496/27973 4772/5494/27974 4827/5551/27975 -f 4893/5635/27976 4793/5511/27977 4795/5510/27978 -f 4795/5510/27979 4892/5617/27980 4893/5635/27981 -f 4796/5526/27982 4797/5527/27983 4795/5510/27984 -f 4795/5510/27985 4794/5509/27986 4796/5526/27987 -f 4882/5607/27988 4881/5606/27989 4904/5634/27990 -f 4897/5622/27991 4896/5621/27992 4903/5633/27993 -f 4929/5638/27994 4924/5639/27995 5081/5636/27996 -f 5081/5636/27997 5082/5637/27998 4929/5638/27999 -f 4924/5639/28000 4936/5641/28001 5083/5640/28002 -f 5083/5640/28003 5081/5636/28004 4924/5639/28005 -f 4936/5641/28006 4942/5643/28007 5084/5642/28008 -f 5084/5642/28009 5083/5640/28010 4936/5641/28011 -f 4942/5643/28012 4948/5645/28013 5085/5644/28014 -f 5085/5644/28015 5084/5642/28016 4942/5643/28017 -f 4948/5645/28018 4954/5647/28019 5086/5646/28020 -f 5086/5646/28021 5085/5644/28022 4948/5645/28023 -f 4954/5649/28024 4929/5638/28025 5082/5637/28026 -f 5082/5637/28027 5086/5648/28028 4954/5649/28029 -f 4914/5652/28030 4920/5653/28031 4912/5650/28032 -f 4912/5650/28033 4911/5651/28034 4914/5652/28035 -f 4914/5656/28036 4911/5651/28037 4910/5654/28038 -f 4910/5654/28039 4909/5655/28040 4914/5656/28041 -f 4915/5658/28042 4920/5659/28043 4914/5657/28044 -f 4914/5657/28045 4909/5655/28046 4915/5658/28047 -f 4909/5655/28048 4916/5661/28049 4908/5660/28050 -f 4908/5660/28051 4915/5658/28052 4909/5655/28053 -f 4910/5654/28054 4917/5662/28055 4916/5661/28056 -f 4916/5661/28057 4909/5655/28058 4910/5654/28059 -f 4911/5651/28060 4918/5663/28061 4917/5662/28062 -f 4917/5662/28063 4910/5654/28064 4911/5651/28065 -f 4912/5650/28066 4919/5664/28067 4918/5663/28068 -f 4918/5663/28069 4911/5651/28070 4912/5650/28071 -f 4920/5653/28072 4913/5665/28073 4919/5664/28074 -f 4919/5664/28075 4912/5650/28076 4920/5653/28077 -f 4915/5658/28078 4908/5660/28079 4913/5666/28080 -f 4913/5666/28081 4920/5659/28082 4915/5658/28083 -f 4928/5670/28084 4925/5671/28085 5087/5668/28086 -f 5087/5668/28087 5088/5669/28088 4928/5670/28089 -f 4921/5672/28090 4932/5673/28091 4908/5660/28092 -f 4908/5660/28093 4916/5661/28094 4921/5672/28095 -f 4922/5674/28096 4931/5675/28097 4932/5673/28098 -f 4932/5673/28099 4921/5672/28100 4922/5674/28101 -f 4923/5678/28102 4930/5679/28103 5070/5676/28104 -f 5070/5676/28105 5069/5677/28106 4923/5678/28107 -f 4924/5639/28108 4929/5638/28109 5076/5680/28110 -f 5076/5680/28111 5075/5681/28112 4924/5639/28113 -f 4925/5671/28114 4937/5683/28115 5089/5682/28116 -f 5089/5682/28117 5087/5668/28118 4925/5671/28119 -f 4933/5684/28120 4921/5672/28121 4916/5661/28122 -f 4916/5661/28123 4917/5662/28124 4933/5684/28125 -f 4934/5685/28126 4922/5674/28127 4921/5672/28128 -f 4921/5672/28129 4933/5684/28130 4934/5685/28131 -f 4935/5687/28132 4923/5678/28133 5069/5677/28134 -f 5069/5677/28135 5071/5686/28136 4935/5687/28137 -f 4936/5641/28138 4924/5639/28139 5075/5681/28140 -f 5075/5681/28141 5077/5688/28142 4936/5641/28143 -f 4937/5683/28144 4943/5690/28145 5090/5689/28146 -f 5090/5689/28147 5089/5682/28148 4937/5683/28149 -f 4939/5691/28150 4933/5684/28151 4917/5662/28152 -f 4917/5662/28153 4918/5663/28154 4939/5691/28155 -f 4940/5692/28156 4934/5685/28157 4933/5684/28158 -f 4933/5684/28159 4939/5691/28160 4940/5692/28161 -f 4941/5694/28162 4935/5687/28163 5071/5686/28164 -f 5071/5686/28165 5072/5693/28166 4941/5694/28167 -f 4942/5643/28168 4936/5641/28169 5077/5688/28170 -f 5077/5688/28171 5078/5695/28172 4942/5643/28173 -f 4943/5690/28174 4949/5697/28175 5091/5696/28176 -f 5091/5696/28177 5090/5689/28178 4943/5690/28179 -f 4945/5698/28180 4939/5691/28181 4918/5663/28182 -f 4918/5663/28183 4919/5664/28184 4945/5698/28185 -f 4946/5699/28186 4940/5692/28187 4939/5691/28188 -f 4939/5691/28189 4945/5698/28190 4946/5699/28191 -f 4947/5701/28192 4941/5694/28193 5072/5693/28194 -f 5072/5693/28195 5073/5700/28196 4947/5701/28197 -f 4948/5645/28198 4942/5643/28199 5078/5695/28200 -f 5078/5695/28201 5079/5702/28202 4948/5645/28203 -f 4949/5697/28204 4955/5704/28205 5092/5703/28206 -f 5092/5703/28207 5091/5696/28208 4949/5697/28209 -f 4951/5705/28210 4945/5698/28211 4919/5664/28212 -f 4919/5664/28213 4913/5665/28214 4951/5705/28215 -f 4952/5706/28216 4946/5699/28217 4945/5698/28218 -f 4945/5698/28219 4951/5705/28220 4952/5706/28221 -f 4953/5708/28222 4947/5701/28223 5073/5700/28224 -f 5073/5700/28225 5074/5707/28226 4953/5708/28227 -f 4954/5647/28228 4948/5645/28229 5079/5702/28230 -f 5079/5702/28231 5080/5709/28232 4954/5647/28233 -f 4955/5711/28234 4928/5670/28235 5088/5669/28236 -f 5088/5669/28237 5092/5710/28238 4955/5711/28239 -f 4908/5660/28240 4932/5673/28241 4951/5712/28242 -f 4951/5712/28243 4913/5666/28244 4908/5660/28245 -f 4931/5675/28246 4952/5713/28247 4951/5712/28248 -f 4951/5712/28249 4932/5673/28250 4931/5675/28251 -f 4930/5679/28252 4953/5715/28253 5074/5714/28254 -f 5074/5714/28255 5070/5676/28256 4930/5679/28257 -f 4929/5638/28258 4954/5649/28259 5080/5716/28260 -f 5080/5716/28261 5076/5680/28262 4929/5638/28263 -f 4958/5719/28264 4957/5720/28265 5100/5717/28266 -f 5100/5717/28267 5099/5718/28268 4958/5719/28269 -f 5003/5723/28270 5004/5724/28271 5094/5721/28272 -f 5094/5721/28273 5093/5722/28274 5003/5723/28275 -f 4957/5720/28276 4962/5726/28277 5101/5725/28278 -f 5101/5725/28279 5100/5717/28280 4957/5720/28281 -f 5004/5724/28282 5005/5728/28283 5095/5727/28284 -f 5095/5727/28285 5094/5721/28286 5004/5724/28287 -f 4962/5726/28288 4965/5730/28289 5102/5729/28290 -f 5102/5729/28291 5101/5725/28292 4962/5726/28293 -f 5005/5728/28294 5006/5732/28295 5096/5731/28296 -f 5096/5731/28297 5095/5727/28298 5005/5728/28299 -f 4965/5730/28300 4968/5734/28301 5103/5733/28302 -f 5103/5733/28303 5102/5729/28304 4965/5730/28305 -f 5006/5732/28306 5007/5736/28307 5097/5735/28308 -f 5097/5735/28309 5096/5731/28310 5006/5732/28311 -f 4968/5739/28312 4971/5740/28313 5104/5737/28314 -f 5104/5737/28315 5103/5738/28316 4968/5739/28317 -f 5007/5743/28318 5008/5744/28319 5098/5741/28320 -f 5098/5741/28321 5097/5742/28322 5007/5743/28323 -f 4971/5740/28324 4958/5719/28325 5099/5718/28326 -f 5099/5718/28327 5104/5737/28328 4971/5740/28329 -f 5008/5744/28330 5003/5723/28331 5093/5722/28332 -f 5093/5722/28333 5098/5741/28334 5008/5744/28335 -s 2 -f 4974/5747/28336 4973/5748/28337 5020/5745/28338 -f 5020/5745/28339 5021/5746/28340 4974/5747/28341 -f 4975/5750/28342 4974/5747/28343 5021/5888/28344 -f 5021/5888/28345 4970/5749/28346 4975/5750/28347 -f 4976/5752/28348 4975/5750/28349 4970/5889/28350 -f 4970/5889/28351 4967/5751/28352 4976/5752/28353 -f 4977/5755/28354 4976/5756/28355 4967/5753/28356 -f 4967/5753/28357 4964/5754/28358 4977/5755/28359 -f 4978/5758/28360 4977/5755/28361 4964/5890/28362 -f 4964/5890/28363 4961/5757/28364 4978/5758/28365 -f 4973/5748/28366 4978/5758/28367 4961/5891/28368 -f 4961/5891/28369 5020/5886/28370 4973/5748/28371 -f 4980/5761/28372 4979/5762/28373 4960/5759/28374 -f 4960/5759/28375 4959/5760/28376 4980/5761/28377 -f 4981/5764/28378 4980/5761/28379 4959/5887/28380 -f 4959/5887/28381 4963/5763/28382 4981/5764/28383 -f 4982/5766/28384 4981/5764/28385 4963/5893/28386 -f 4963/5893/28387 4966/5765/28388 4982/5766/28389 -f 4983/5768/28390 4982/5766/28391 4966/5894/28392 -f 4966/5894/28393 4969/5767/28394 4983/5768/28395 -f 4984/5771/28396 4983/5772/28397 4969/5769/28398 -f 4969/5769/28399 4972/5770/28400 4984/5771/28401 -f 4979/5762/28402 4984/5771/28403 4972/5895/28404 -f 4972/5895/28405 4960/5892/28406 4979/5762/28407 -s 1 -f 4986/5773/28408 4985/5774/28409 4973/5748/28410 -f 4973/5748/28411 4974/5747/28412 4986/5773/28413 -f 4987/5775/28414 4986/5773/28415 4974/5747/28416 -f 4974/5747/28417 4975/5750/28418 4987/5775/28419 -f 4988/5776/28420 4987/5775/28421 4975/5750/28422 -f 4975/5750/28423 4976/5752/28424 4988/5776/28425 -f 4989/5777/28426 4988/5778/28427 4976/5756/28428 -f 4976/5756/28429 4977/5755/28430 4989/5777/28431 -f 4990/5779/28432 4989/5777/28433 4977/5755/28434 -f 4977/5755/28435 4978/5758/28436 4990/5779/28437 -f 4985/5774/28438 4990/5779/28439 4978/5758/28440 -f 4978/5758/28441 4973/5748/28442 4985/5774/28443 -f 4992/5780/28444 4991/5781/28445 4979/5762/28446 -f 4979/5762/28447 4980/5761/28448 4992/5780/28449 -f 4993/5782/28450 4992/5780/28451 4980/5761/28452 -f 4980/5761/28453 4981/5764/28454 4993/5782/28455 -f 4994/5783/28456 4993/5782/28457 4981/5764/28458 -f 4981/5764/28459 4982/5766/28460 4994/5783/28461 -f 4995/5784/28462 4994/5783/28463 4982/5766/28464 -f 4982/5766/28465 4983/5768/28466 4995/5784/28467 -f 4996/5785/28468 4995/5786/28469 4983/5772/28470 -f 4983/5772/28471 4984/5771/28472 4996/5785/28473 -f 4991/5781/28474 4996/5785/28475 4984/5771/28476 -f 4984/5771/28477 4979/5762/28478 4991/5781/28479 -f 4998/5787/28480 4997/5788/28481 4985/5774/28482 -f 4985/5774/28483 4986/5773/28484 4998/5787/28485 -f 4999/5789/28486 4998/5787/28487 4986/5773/28488 -f 4986/5773/28489 4987/5775/28490 4999/5789/28491 -f 5000/5790/28492 4999/5789/28493 4987/5775/28494 -f 4987/5775/28495 4988/5776/28496 5000/5790/28497 -f 5001/5791/28498 5000/5792/28499 4988/5778/28500 -f 4988/5778/28501 4989/5777/28502 5001/5791/28503 -f 5002/5793/28504 5001/5791/28505 4989/5777/28506 -f 4989/5777/28507 4990/5779/28508 5002/5793/28509 -f 4997/5788/28510 5002/5793/28511 4990/5779/28512 -f 4990/5779/28513 4985/5774/28514 4997/5788/28515 -f 5004/5724/28516 5003/5723/28517 4991/5781/28518 -f 4991/5781/28519 4992/5780/28520 5004/5724/28521 -f 5005/5728/28522 5004/5724/28523 4992/5780/28524 -f 4992/5780/28525 4993/5782/28526 5005/5728/28527 -f 5006/5732/28528 5005/5728/28529 4993/5782/28530 -f 4993/5782/28531 4994/5783/28532 5006/5732/28533 -f 5007/5736/28534 5006/5732/28535 4994/5783/28536 -f 4994/5783/28537 4995/5784/28538 5007/5736/28539 -f 5008/5744/28540 5007/5743/28541 4995/5786/28542 -f 4995/5786/28543 4996/5785/28544 5008/5744/28545 -f 5003/5723/28546 5008/5744/28547 4996/5785/28548 -f 4996/5785/28549 4991/5781/28550 5003/5723/28551 -f 5012/5796/28552 5011/5797/28553 5010/5794/28554 -f 5010/5794/28555 5009/5795/28556 5012/5796/28557 -f 5012/5796/28558 5014/5799/28559 5013/5798/28560 -f 5013/5798/28561 5011/5797/28562 5012/5796/28563 -f 5015/5800/28564 5014/5799/28565 5012/5796/28566 -f 5012/5796/28567 5009/5795/28568 5015/5800/28569 -f 5014/5799/28570 5015/5800/28571 5016/5801/28572 -f 5016/5801/28573 5017/5802/28574 5014/5799/28575 -f 5013/5798/28576 5014/5799/28577 5017/5802/28578 -f 5017/5802/28579 5022/5803/28580 5013/5798/28581 -f 5011/5885/28582 5013/5798/28583 5022/5803/28584 -f 5022/5803/28585 5018/5804/28586 5011/5885/28587 -f 5010/5806/28588 5011/5885/28589 5018/5804/28590 -f 5018/5804/28591 5019/5805/28592 5010/5806/28593 -f 5009/5884/28594 5010/5809/28595 5019/5807/28596 -f 5019/5807/28597 5023/5808/28598 5009/5884/28599 -f 5015/5800/28600 5009/5884/28601 5023/5808/28602 -f 5023/5808/28603 5016/5801/28604 5015/5800/28605 -f 5021/5878/28606 5020/5667/28607 5105/5810/28608 -f 5105/5810/28609 5106/5811/28610 5021/5878/28611 -f 5020/5667/28612 4961/5883/28613 5107/5812/28614 -f 5107/5812/28615 5105/5810/28616 5020/5667/28617 -f 4961/5883/28618 4964/5882/28619 5108/5813/28620 -f 5108/5813/28621 5107/5812/28622 4961/5883/28623 -f 4964/5882/28624 4967/5881/28625 5109/5814/28626 -f 5109/5814/28627 5108/5813/28628 4964/5882/28629 -f 4967/5880/28630 4970/5879/28631 5110/5815/28632 -f 5110/5815/28633 5109/5816/28634 4967/5880/28635 -f 4970/5879/28636 5021/5878/28637 5106/5811/28638 -f 5106/5811/28639 5110/5815/28640 4970/5879/28641 -f 5030/5819/28642 5029/5820/28643 5024/5817/28644 -f 5024/5817/28645 5025/5818/28646 5030/5819/28647 -s 2 -f 5031/5822/28648 5030/5819/28649 5025/5818/28650 -f 5025/5818/28651 5026/5821/28652 5031/5822/28653 -s 4 -f 5032/5825/28654 5031/5826/28655 5026/5823/28656 -f 5026/5823/28657 5027/5824/28658 5032/5825/28659 -f 5033/5828/28660 5032/5825/28661 5027/5824/28662 -f 5027/5824/28663 5028/5827/28664 5033/5828/28665 -s 1 -f 5029/5820/28666 5033/5828/28667 5028/5827/28668 -f 5028/5827/28669 5024/5817/28670 5029/5820/28671 -f 5035/5829/28672 5034/5830/28673 5029/5820/28674 -f 5029/5820/28675 5030/5819/28676 5035/5829/28677 -s 2 -f 5036/5831/28678 5035/5829/28679 5030/5819/28680 -f 5030/5819/28681 5031/5822/28682 5036/5831/28683 -s 4 -f 5037/5832/28684 5036/5833/28685 5031/5826/28686 -f 5031/5826/28687 5032/5825/28688 5037/5832/28689 -f 5038/5834/28690 5037/5832/28691 5032/5825/28692 -f 5032/5825/28693 5033/5828/28694 5038/5834/28695 -s 1 -f 5034/5830/28696 5038/5834/28697 5033/5828/28698 -f 5033/5828/28699 5029/5820/28700 5034/5830/28701 -f 5040/5835/28702 5039/5836/28703 5034/5830/28704 -f 5034/5830/28705 5035/5829/28706 5040/5835/28707 -s 2 -f 5041/5837/28708 5040/5835/28709 5035/5829/28710 -f 5035/5829/28711 5036/5831/28712 5041/5837/28713 -s 4 -f 5042/5838/28714 5041/5839/28715 5036/5833/28716 -f 5036/5833/28717 5037/5832/28718 5042/5838/28719 -f 5043/5840/28720 5042/5838/28721 5037/5832/28722 -f 5037/5832/28723 5038/5834/28724 5043/5840/28725 -s 1 -f 5039/5836/28726 5043/5840/28727 5038/5834/28728 -f 5038/5834/28729 5034/5830/28730 5039/5836/28731 -f 5045/5841/28732 5044/5842/28733 5039/5836/28734 -f 5039/5836/28735 5040/5835/28736 5045/5841/28737 -s 2 -f 5046/5843/28738 5045/5841/28739 5040/5835/28740 -f 5040/5835/28741 5041/5837/28742 5046/5843/28743 -s 4 -f 5047/5844/28744 5046/5845/28745 5041/5839/28746 -f 5041/5839/28747 5042/5838/28748 5047/5844/28749 -f 5048/5846/28750 5047/5844/28751 5042/5838/28752 -f 5042/5838/28753 5043/5840/28754 5048/5846/28755 -s 1 -f 5044/5842/28756 5048/5846/28757 5043/5840/28758 -f 5043/5840/28759 5039/5836/28760 5044/5842/28761 -f 5050/5847/28762 5049/5848/28763 5044/5842/28764 -f 5044/5842/28765 5045/5841/28766 5050/5847/28767 -s 2 -f 5051/5849/28768 5050/5847/28769 5045/5841/28770 -f 5045/5841/28771 5046/5843/28772 5051/5849/28773 -s 4 -f 5052/5850/28774 5051/5851/28775 5046/5845/28776 -f 5046/5845/28777 5047/5844/28778 5052/5850/28779 -f 5053/5852/28780 5052/5850/28781 5047/5844/28782 -f 5047/5844/28783 5048/5846/28784 5053/5852/28785 -s 1 -f 5049/5848/28786 5053/5852/28787 5048/5846/28788 -f 5048/5846/28789 5044/5842/28790 5049/5848/28791 -f 5055/5853/28792 5054/5854/28793 5049/5848/28794 -f 5049/5848/28795 5050/5847/28796 5055/5853/28797 -s 2 -f 5056/5855/28798 5055/5853/28799 5050/5847/28800 -f 5050/5847/28801 5051/5849/28802 5056/5855/28803 -s 4 -f 5057/5856/28804 5056/5857/28805 5051/5851/28806 -f 5051/5851/28807 5052/5850/28808 5057/5856/28809 -f 5058/5858/28810 5057/5856/28811 5052/5850/28812 -f 5052/5850/28813 5053/5852/28814 5058/5858/28815 -s 1 -f 5054/5854/28816 5058/5858/28817 5053/5852/28818 -f 5053/5852/28819 5049/5848/28820 5054/5854/28821 -f 5060/5859/28822 5059/5860/28823 5054/5854/28824 -f 5054/5854/28825 5055/5853/28826 5060/5859/28827 -s 2 -f 5061/5861/28828 5060/5859/28829 5055/5853/28830 -f 5055/5853/28831 5056/5855/28832 5061/5861/28833 -s 4 -f 5062/5862/28834 5061/5863/28835 5056/5857/28836 -f 5056/5857/28837 5057/5856/28838 5062/5862/28839 -f 5063/5864/28840 5062/5862/28841 5057/5856/28842 -f 5057/5856/28843 5058/5858/28844 5063/5864/28845 -s 1 -f 5059/5860/28846 5063/5864/28847 5058/5858/28848 -f 5058/5858/28849 5054/5854/28850 5059/5860/28851 -f 5065/5865/28852 5064/5866/28853 5059/5860/28854 -f 5059/5860/28855 5060/5859/28856 5065/5865/28857 -s 2 -f 5066/5867/28858 5065/5865/28859 5060/5859/28860 -f 5060/5859/28861 5061/5861/28862 5066/5867/28863 -s 4 -f 5067/5868/28864 5066/5869/28865 5061/5863/28866 -f 5061/5863/28867 5062/5862/28868 5067/5868/28869 -f 5068/5870/28870 5067/5868/28871 5062/5862/28872 -f 5062/5862/28873 5063/5864/28874 5068/5870/28875 -s 1 -f 5064/5866/28876 5068/5870/28877 5063/5864/28878 -f 5063/5864/28879 5059/5860/28880 5064/5866/28881 -f 5069/5677/28882 5070/5676/28883 4931/5675/28884 -f 4931/5675/28885 4922/5674/28886 5069/5677/28887 -f 5071/5686/28888 5069/5677/28889 4922/5674/28890 -f 4922/5674/28891 4934/5685/28892 5071/5686/28893 -f 5072/5693/28894 5071/5686/28895 4934/5685/28896 -f 4934/5685/28897 4940/5692/28898 5072/5693/28899 -f 5073/5700/28900 5072/5693/28901 4940/5692/28902 -f 4940/5692/28903 4946/5699/28904 5073/5700/28905 -f 5074/5707/28906 5073/5700/28907 4946/5699/28908 -f 4946/5699/28909 4952/5706/28910 5074/5707/28911 -f 5070/5676/28912 5074/5714/28913 4952/5713/28914 -f 4952/5713/28915 4931/5675/28916 5070/5676/28917 -f 5075/5681/28918 5076/5680/28919 4930/5679/28920 -f 4930/5679/28921 4923/5678/28922 5075/5681/28923 -f 5077/5688/28924 5075/5681/28925 4923/5678/28926 -f 4923/5678/28927 4935/5687/28928 5077/5688/28929 -f 5078/5695/28930 5077/5688/28931 4935/5687/28932 -f 4935/5687/28933 4941/5694/28934 5078/5695/28935 -f 5079/5702/28936 5078/5695/28937 4941/5694/28938 -f 4941/5694/28939 4947/5701/28940 5079/5702/28941 -f 5080/5709/28942 5079/5702/28943 4947/5701/28944 -f 4947/5701/28945 4953/5708/28946 5080/5709/28947 -f 5076/5680/28948 5080/5716/28949 4953/5715/28950 -f 4953/5715/28951 4930/5679/28952 5076/5680/28953 -f 5082/5637/28954 5081/5636/28955 4925/5671/28956 -f 4925/5671/28957 4928/5670/28958 5082/5637/28959 -f 5081/5636/28960 5083/5640/28961 4937/5683/28962 -f 4937/5683/28963 4925/5671/28964 5081/5636/28965 -f 5083/5640/28966 5084/5642/28967 4943/5690/28968 -f 4943/5690/28969 4937/5683/28970 5083/5640/28971 -f 5084/5642/28972 5085/5644/28973 4949/5697/28974 -f 4949/5697/28975 4943/5690/28976 5084/5642/28977 -f 5085/5644/28978 5086/5646/28979 4955/5704/28980 -f 4955/5704/28981 4949/5697/28982 5085/5644/28983 -f 5086/5648/28984 5082/5637/28985 4928/5670/28986 -f 4928/5670/28987 4955/5711/28988 5086/5648/28989 -f 5088/5669/28990 5087/5668/28991 4926/5871/28992 -f 4926/5871/28993 4927/5872/28994 5088/5669/28995 -f 5087/5668/28996 5089/5682/28997 4938/5873/28998 -f 4938/5873/28999 4926/5871/29000 5087/5668/29001 -f 5089/5682/29002 5090/5689/29003 4944/5874/29004 -f 4944/5874/29005 4938/5873/29006 5089/5682/29007 -f 5090/5689/29008 5091/5696/29009 4950/5875/29010 -f 4950/5875/29011 4944/5874/29012 5090/5689/29013 -f 5091/5696/29014 5092/5703/29015 4956/5876/29016 -f 4956/5876/29017 4950/5875/29018 5091/5696/29019 -f 5092/5710/29020 5088/5669/29021 4927/5872/29022 -f 4927/5872/29023 4956/5877/29024 5092/5710/29025 -f 5093/5722/29026 5094/5721/29027 4957/5720/29028 -f 4957/5720/29029 4958/5719/29030 5093/5722/29031 -f 5094/5721/29032 5095/5727/29033 4962/5726/29034 -f 4962/5726/29035 4957/5720/29036 5094/5721/29037 -f 5095/5727/29038 5096/5731/29039 4965/5730/29040 -f 4965/5730/29041 4962/5726/29042 5095/5727/29043 -f 5096/5731/29044 5097/5735/29045 4968/5734/29046 -f 4968/5734/29047 4965/5730/29048 5096/5731/29049 -f 5097/5742/29050 5098/5741/29051 4971/5740/29052 -f 4971/5740/29053 4968/5739/29054 5097/5742/29055 -f 5098/5741/29056 5093/5722/29057 4958/5719/29058 -f 4958/5719/29059 4971/5740/29060 5098/5741/29061 -f 5099/5718/29062 5100/5717/29063 4997/5788/29064 -f 4997/5788/29065 4998/5787/29066 5099/5718/29067 -f 5100/5717/29068 5101/5725/29069 5002/5793/29070 -f 5002/5793/29071 4997/5788/29072 5100/5717/29073 -f 5101/5725/29074 5102/5729/29075 5001/5791/29076 -f 5001/5791/29077 5002/5793/29078 5101/5725/29079 -f 5102/5729/29080 5103/5733/29081 5000/5792/29082 -f 5000/5792/29083 5001/5791/29084 5102/5729/29085 -f 5103/5738/29086 5104/5737/29087 4999/5789/29088 -f 4999/5789/29089 5000/5790/29090 5103/5738/29091 -f 5104/5737/29092 5099/5718/29093 4998/5787/29094 -f 4998/5787/29095 4999/5789/29096 5104/5737/29097 -f 5106/5811/29098 5105/5810/29099 5017/5802/29100 -f 5017/5802/29101 5016/5801/29102 5106/5811/29103 -f 5105/5810/29104 5107/5812/29105 5022/5803/29106 -f 5022/5803/29107 5017/5802/29108 5105/5810/29109 -f 5107/5812/29110 5108/5813/29111 5018/5804/29112 -f 5018/5804/29113 5022/5803/29114 5107/5812/29115 -f 5108/5813/29116 5109/5814/29117 5019/5805/29118 -f 5019/5805/29119 5018/5804/29120 5108/5813/29121 -f 5109/5816/29122 5110/5815/29123 5023/5808/29124 -f 5023/5808/29125 5019/5807/29126 5109/5816/29127 -f 5110/5815/29128 5106/5811/29129 5016/5801/29130 -f 5016/5801/29131 5023/5808/29132 5110/5815/29133 -f 5111/5898/29134 5114/5901/29135 5113/5902/29136 -f 5113/5902/29137 5112/5897/29138 5111/5898/29139 -f 5113/5902/29140 5114/5901/29141 5115/5904/29142 -f 5115/5904/29143 5116/5906/29144 5113/5902/29145 -f 5118/5910/29146 5111/5898/29147 5112/5897/29148 -f 5112/5897/29149 5117/5907/29150 5118/5910/29151 -f 5120/5924/29152 5118/5910/29153 5117/5907/29154 -f 5117/5907/29155 5119/5912/29156 5120/5924/29157 -f 5116/5906/29158 5115/5904/29159 5173/5925/29160 -f 5173/5925/29161 5172/5926/29162 5116/5906/29163 -f 5121/5927/29164 5122/5928/29165 5119/5912/29166 -f 5119/5912/29167 5117/5907/29168 5121/5927/29169 -f 5123/5929/29170 5124/5930/29171 5122/5928/29172 -f 5122/5928/29173 5121/5927/29174 5123/5929/29175 -f 5126/5932/29176 5123/5929/29177 5121/5927/29178 -f 5121/5927/29179 5125/5931/29180 5126/5932/29181 -f 5128/5934/29182 5126/5932/29183 5125/5931/29184 -f 5125/5931/29185 5127/5933/29186 5128/5934/29187 -f 5129/5935/29188 5128/5934/29189 5127/5933/29190 -f 5131/5899/29191 5126/5900/29192 5128/5903/29193 -f 5128/5903/29194 5130/5896/29195 5131/5899/29196 -f 5132/5905/29197 5133/5908/29198 5124/5909/29199 -f 5124/5909/29200 5123/5911/29201 5132/5905/29202 -f 5123/5911/29203 5126/5900/29204 5131/5899/29205 -f 5131/5899/29206 5132/5905/29207 5123/5911/29208 -f 5133/5921/29209 5132/5922/29210 5134/5919/29211 -f 5134/5919/29212 5135/5920/29213 5133/5921/29214 -f 5132/5922/29215 5131/5966/29216 5136/5969/29217 -f 5136/5969/29218 5134/5919/29219 5132/5922/29220 -f 5136/5969/29221 5131/5966/29222 5130/5970/29223 -f 5130/5970/29224 5137/5974/29225 5136/5969/29226 -f 5128/5903/29227 5129/5913/29228 5138/5914/29229 -f 5138/5914/29230 5130/5896/29231 5128/5903/29232 -f 5137/5974/29233 5130/5970/29234 5138/5976/29235 -f 5138/5976/29236 5139/5975/29237 5137/5974/29238 -f 5142/5937/29239 5125/5931/29240 5121/5927/29241 -f 5121/5927/29242 5140/5936/29243 5142/5937/29244 -f 5140/5936/29245 5121/5927/29246 5117/5907/29247 -f 5117/5907/29248 5112/5897/29249 5140/5936/29250 -f 5112/5897/29251 5113/5902/29252 5140/5936/29253 -f 5141/5938/29254 5140/5936/29255 5113/5902/29256 -f 5113/5902/29257 5116/5906/29258 5141/5938/29259 -f 5143/5939/29260 5142/5937/29261 5140/5936/29262 -f 5140/5936/29263 5141/5938/29264 5143/5939/29265 -f 5125/5931/29266 5142/5937/29267 5144/5940/29268 -f 5144/5940/29269 5127/5933/29270 5125/5931/29271 -f 5144/5940/29272 5142/5937/29273 5145/5941/29274 -f 5127/5933/29275 5144/5940/29276 5146/5942/29277 -f 5146/5942/29278 5129/5935/29279 5127/5933/29280 -f 5145/5941/29281 5148/5943/29282 5144/5940/29283 -f 5147/5944/29284 5146/5942/29285 5144/5940/29286 -f 5148/5943/29287 5147/5944/29288 5144/5940/29289 -f 5149/5945/29290 5150/5946/29291 5148/5943/29292 -f 5148/5943/29293 5145/5941/29294 5149/5945/29295 -f 5145/5941/29296 5142/5937/29297 5151/5947/29298 -f 5151/5947/29299 5149/5945/29300 5145/5941/29301 -f 5152/5948/29302 5151/5947/29303 5142/5937/29304 -f 5142/5937/29305 5143/5939/29306 5152/5948/29307 -f 5143/5939/29308 5141/5938/29309 5154/5949/29310 -f 5153/5950/29311 5152/5948/29312 5143/5939/29313 -f 5143/5939/29314 5154/5949/29315 5153/5950/29316 -f 5156/5952/29317 5154/5949/29318 5157/5953/29319 -f 5157/5953/29320 5155/5951/29321 5156/5952/29322 -f 5159/5955/29323 5157/5953/29324 5161/5956/29325 -f 5161/5956/29326 5158/5954/29327 5159/5955/29328 -f 5141/5938/29329 5116/5906/29330 5161/5956/29331 -f 5160/5957/29332 5169/5959/29333 5116/5906/29334 -f 5116/5906/29335 5172/5926/29336 5160/5957/29337 -f 5161/5956/29338 5162/5962/29339 5163/5960/29340 -f 5163/5960/29341 5183/5961/29342 5161/5956/29343 -s 2 -f 5161/5956/29344 5183/5961/29345 5164/5963/29346 -f 5164/5963/29347 5158/5954/29348 5161/5956/29349 -f 5165/5964/29350 5180/5965/29351 5153/5950/29352 -f 5153/5950/29353 5154/5949/29354 5165/5964/29355 -s 4 -f 5166/5967/29356 5165/5964/29357 5154/5949/29358 -f 5154/5949/29359 5156/5952/29360 5166/5967/29361 -f 5157/5953/29362 5159/5955/29363 5167/5968/29364 -f 5167/5968/29365 5182/5978/29366 5157/5953/29367 -s 2 -f 5157/5953/29368 5182/5978/29369 5168/5985/29370 -f 5168/5985/29371 5155/5951/29372 5157/5953/29373 -s 8 -f 5166/5967/29374 5156/5952/29375 5155/5951/29376 -f 5155/5951/29377 5168/5985/29378 5166/5967/29379 -s 4 -f 5167/5968/29380 5159/5955/29381 5158/5954/29382 -f 5158/5954/29383 5164/5963/29384 5167/5968/29385 -s 1 -f 5169/5959/29386 5161/5956/29387 5116/5906/29388 -f 5162/5962/29389 5161/5956/29390 5169/5959/29391 -f 5162/5962/29392 5169/5959/29393 5170/5986/29394 -f 5170/5986/29395 5163/5960/29396 5162/5962/29397 -f 5160/5957/29398 5171/5987/29399 5170/5986/29400 -f 5170/5986/29401 5169/5959/29402 5160/5957/29403 -f 5171/5987/29404 5160/5957/29405 5172/5926/29406 -f 5172/5926/29407 5173/5925/29408 5171/5987/29409 -s 2 -f 5129/5935/29410 5146/5942/29411 5139/5988/29412 -f 5139/5988/29413 5138/5989/29414 5129/5935/29415 -f 5146/5942/29416 5147/5944/29417 5174/5990/29418 -f 5174/5990/29419 5139/5988/29420 5146/5942/29421 -s 1 -f 5139/5975/29422 5174/5979/29423 5175/5977/29424 -f 5175/5977/29425 5137/5974/29426 5139/5975/29427 -s 4 -f 5177/5998/29428 5150/5946/29429 5149/5945/29430 -f 5149/5945/29431 5176/5997/29432 5177/5998/29433 -f 5149/5945/29434 5151/5947/29435 5178/6001/29436 -f 5178/6001/29437 5176/5997/29438 5149/5945/29439 -f 5152/5948/29440 5179/6002/29441 5178/6001/29442 -f 5178/6001/29443 5151/5947/29444 5152/5948/29445 -f 5153/5950/29446 5180/5965/29447 5179/6002/29448 -f 5179/6002/29449 5152/5948/29450 5153/5950/29451 -s 1 -f 5180/5984/29452 5165/6005/29453 5181/5981/29454 -f 5181/5981/29455 5179/5982/29456 5180/5984/29457 -f 5166/6007/29458 5168/6008/29459 5182/6006/29460 -f 5182/6006/29461 5165/6005/29462 5166/6007/29463 -f 5167/6010/29464 5164/6011/29465 5183/6009/29466 -f 5183/6009/29467 5182/6006/29468 5167/6010/29469 -f 5163/6024/29470 5170/6025/29471 5184/6012/29472 -f 5184/6012/29473 5183/6009/29474 5163/6024/29475 -f 5184/6012/29476 5170/6025/29477 5171/6032/29478 -f 5171/6032/29479 5185/6063/29480 5184/6012/29481 -f 5186/6065/29482 5185/6063/29483 5171/6032/29484 -f 5171/6032/29485 5173/6064/29486 5186/6065/29487 -f 5188/6066/29488 5303/6177/29489 5186/6065/29490 -f 5188/5915/29491 5186/5916/29492 5115/5917/29493 -f 5115/5917/29494 5114/5918/29495 5188/5915/29496 -f 5186/5916/29497 5173/5923/29498 5115/5917/29499 -f 5187/5958/29500 5188/5915/29501 5114/5918/29502 -f 5114/5918/29503 5111/5971/29504 5187/5958/29505 -f 5188/6066/29506 5187/6073/29507 5302/6176/29508 -f 5302/6176/29509 5303/6177/29510 5188/6066/29511 -f 5184/6012/29512 5189/6075/29513 5190/6079/29514 -f 5190/6079/29515 5183/6009/29516 5184/6012/29517 -f 5182/6006/29518 5183/6009/29519 5190/6079/29520 -f 5165/6005/29521 5182/6006/29522 5190/6079/29523 -f 5190/6079/29524 5189/6075/29525 5181/5981/29526 -f 5181/5981/29527 5165/6005/29528 5190/6079/29529 -f 5191/6082/29530 5178/6086/29531 5179/5982/29532 -f 5179/5982/29533 5181/5981/29534 5191/6082/29535 -f 5192/6087/29536 5176/6088/29537 5178/6086/29538 -f 5178/6086/29539 5191/6082/29540 5192/6087/29541 -f 5176/6088/29542 5192/6087/29543 5193/6089/29544 -f 5193/6089/29545 5177/6090/29546 5176/6088/29547 -s 2 -f 5148/5943/29548 5150/5946/29549 5177/5998/29550 -f 5177/5998/29551 5193/6023/29552 5148/5943/29553 -s 4 -f 5147/5944/29554 5148/5943/29555 5193/6023/29556 -f 5193/6023/29557 5174/5990/29558 5147/5944/29559 -s 1 -f 5193/6023/29560 5175/6027/29561 5174/5990/29562 -f 5193/6089/29563 5192/6087/29564 5175/5977/29565 -f 5189/6075/29566 5194/6091/29567 5191/6082/29568 -f 5191/6082/29569 5181/5981/29570 5189/6075/29571 -f 5194/6091/29572 5192/6087/29573 5191/6082/29574 -f 5137/5974/29575 5175/5977/29576 5192/6087/29577 -f 5192/6087/29578 5194/6091/29579 5137/5974/29580 -f 5136/5969/29581 5137/5974/29582 5194/6091/29583 -f 5134/5919/29584 5136/5969/29585 5194/6091/29586 -f 5195/5973/29587 5187/5958/29588 5111/5971/29589 -f 5111/5971/29590 5118/5972/29591 5195/5973/29592 -f 5197/6093/29593 5187/6073/29594 5195/6094/29595 -f 5195/6094/29596 5196/6092/29597 5197/6093/29598 -f 5197/6093/29599 5302/6176/29600 5187/6073/29601 -f 5134/5919/29602 5194/6091/29603 5197/6093/29604 -f 5197/6093/29605 5196/6092/29606 5134/5919/29607 -f 5118/5972/29608 5120/5980/29609 5198/5983/29610 -f 5198/5983/29611 5195/5973/29612 5118/5972/29613 -f 5195/6094/29614 5198/6096/29615 5199/6095/29616 -f 5199/6095/29617 5196/6092/29618 5195/6094/29619 -f 5196/6092/29620 5199/6095/29621 5135/5920/29622 -f 5135/5920/29623 5134/5919/29624 5196/6092/29625 -f 5200/6029/29626 5201/6035/29627 5119/5912/29628 -f 5119/5912/29629 5122/5928/29630 5200/6029/29631 -f 5201/6035/29632 5200/6029/29633 5202/6036/29634 -f 5202/6036/29635 5203/6037/29636 5201/6035/29637 -f 5203/6037/29638 5202/6036/29639 5204/6038/29640 -f 5204/6038/29641 5205/6039/29642 5203/6037/29643 -f 5206/6040/29644 5200/6029/29645 5122/5928/29646 -f 5122/5928/29647 5124/5930/29648 5206/6040/29649 -f 5200/6029/29650 5206/6040/29651 5207/6041/29652 -f 5207/6041/29653 5202/6036/29654 5200/6029/29655 -f 5202/6036/29656 5207/6041/29657 5208/6042/29658 -f 5208/6042/29659 5204/6038/29660 5202/6036/29661 -f 5119/5912/29662 5201/6035/29663 5209/6043/29664 -f 5209/6043/29665 5120/5924/29666 5119/5912/29667 -f 5210/6044/29668 5209/6043/29669 5201/6035/29670 -f 5201/6035/29671 5203/6037/29672 5210/6044/29673 -f 5203/6037/29674 5205/6039/29675 5211/6045/29676 -f 5211/6045/29677 5210/6044/29678 5203/6037/29679 -f 5213/6047/29680 5205/6039/29681 5204/6038/29682 -f 5204/6038/29683 5212/6046/29684 5213/6047/29685 -f 5208/6042/29686 5214/6048/29687 5212/6046/29688 -f 5212/6046/29689 5204/6038/29690 5208/6042/29691 -f 5205/6039/29692 5213/6047/29693 5215/6049/29694 -f 5215/6049/29695 5211/6045/29696 5205/6039/29697 -f 5216/6050/29698 5217/6051/29699 5213/6047/29700 -f 5213/6047/29701 5212/6046/29702 5216/6050/29703 -f 5218/6052/29704 5216/6050/29705 5212/6046/29706 -f 5212/6046/29707 5214/6048/29708 5218/6052/29709 -f 5213/6047/29710 5217/6051/29711 5219/6053/29712 -f 5219/6053/29713 5215/6049/29714 5213/6047/29715 -f 5221/6098/29716 5135/5920/29717 5199/6095/29718 -f 5199/6095/29719 5220/6097/29720 5221/6098/29721 -f 5223/6100/29722 5221/6098/29723 5220/6097/29724 -f 5220/6097/29725 5222/6099/29726 5223/6100/29727 -f 5225/6102/29728 5223/6100/29729 5222/6099/29730 -f 5222/6099/29731 5224/6101/29732 5225/6102/29733 -f 5225/6102/29734 5224/6101/29735 5226/6103/29736 -f 5226/6103/29737 5227/6104/29738 5225/6102/29739 -f 5228/6105/29740 5220/6097/29741 5199/6095/29742 -f 5199/6095/29743 5198/6096/29744 5228/6105/29745 -f 5220/6097/29746 5228/6105/29747 5229/6106/29748 -f 5229/6106/29749 5222/6099/29750 5220/6097/29751 -f 5230/6107/29752 5224/6101/29753 5222/6099/29754 -f 5222/6099/29755 5229/6106/29756 5230/6107/29757 -f 5231/6108/29758 5226/6103/29759 5224/6101/29760 -f 5224/6101/29761 5230/6107/29762 5231/6108/29763 -f 5135/5920/29764 5221/6098/29765 5232/6109/29766 -f 5232/6109/29767 5133/5921/29768 5135/5920/29769 -f 5221/6098/29770 5223/6100/29771 5233/6110/29772 -f 5233/6110/29773 5232/6109/29774 5221/6098/29775 -f 5223/6100/29776 5225/6102/29777 5234/6111/29778 -f 5234/6111/29779 5233/6110/29780 5223/6100/29781 -f 5235/6112/29782 5234/6111/29783 5225/6102/29784 -f 5225/6102/29785 5227/6104/29786 5235/6112/29787 -f 5133/5908/29788 5232/5991/29789 5206/5992/29790 -f 5206/5992/29791 5124/5909/29792 5133/5908/29793 -f 5232/5991/29794 5233/5993/29795 5207/5994/29796 -f 5207/5994/29797 5206/5992/29798 5232/5991/29799 -f 5234/5995/29800 5208/5996/29801 5207/5994/29802 -f 5207/5994/29803 5233/5993/29804 5234/5995/29805 -f 5235/5999/29806 5214/6000/29807 5208/5996/29808 -f 5208/5996/29809 5234/5995/29810 5235/5999/29811 -f 5235/5999/29812 5218/6003/29813 5214/6000/29814 -f 5209/6004/29815 5228/6013/29816 5198/5983/29817 -f 5198/5983/29818 5120/5980/29819 5209/6004/29820 -f 5210/6014/29821 5229/6015/29822 5228/6013/29823 -f 5228/6013/29824 5209/6004/29825 5210/6014/29826 -f 5211/6016/29827 5230/6017/29828 5229/6015/29829 -f 5229/6015/29830 5210/6014/29831 5211/6016/29832 -f 5211/6016/29833 5215/6018/29834 5231/6019/29835 -f 5231/6019/29836 5230/6017/29837 5211/6016/29838 -f 5215/6018/29839 5219/6020/29840 5231/6019/29841 -f 5236/6021/29842 5237/6022/29843 5218/6003/29844 -f 5218/6003/29845 5235/5999/29846 5236/6021/29847 -f 5218/6052/29848 5237/6055/29849 5238/6054/29850 -f 5238/6054/29851 5216/6050/29852 5218/6052/29853 -f 5239/6114/29854 5236/6113/29855 5235/6112/29856 -f 5235/6112/29857 5227/6104/29858 5239/6114/29859 -f 5226/6103/29860 5240/6115/29861 5239/6114/29862 -f 5239/6114/29863 5227/6104/29864 5226/6103/29865 -f 5241/6116/29866 5240/6115/29867 5226/6103/29868 -f 5226/6103/29869 5231/6108/29870 5241/6116/29871 -f 5216/6050/29872 5238/6054/29873 5242/6056/29874 -f 5242/6056/29875 5217/6051/29876 5216/6050/29877 -f 5217/6051/29878 5242/6056/29879 5243/6057/29880 -f 5243/6057/29881 5219/6053/29882 5217/6051/29883 -f 5241/6028/29884 5231/6019/29885 5219/6020/29886 -f 5219/6020/29887 5243/6026/29888 5241/6028/29889 -f 5244/6058/29890 5245/6067/29891 5243/6057/29892 -f 5243/6057/29893 5242/6056/29894 5244/6058/29895 -f 5246/6117/29896 5247/6118/29897 5240/6115/29898 -f 5240/6115/29899 5241/6116/29900 5246/6117/29901 -f 5243/6026/29902 5245/6030/29903 5246/6031/29904 -f 5246/6031/29905 5241/6028/29906 5243/6026/29907 -f 5246/6031/29908 5245/6030/29909 5248/6033/29910 -f 5248/6033/29911 5249/6034/29912 5246/6031/29913 -f 5248/6068/29914 5245/6067/29915 5244/6058/29916 -f 5249/6119/29917 5247/6118/29918 5246/6117/29919 -f 5249/6071/29920 5248/6068/29921 5250/6069/29922 -f 5250/6069/29923 5251/6070/29924 5249/6071/29925 -f 5250/6069/29926 5248/6068/29927 5244/6058/29928 -f 5252/6072/29929 5253/6074/29930 5250/6069/29931 -f 5250/6069/29932 5244/6058/29933 5252/6072/29934 -f 5254/6076/29935 5255/6077/29936 5253/6074/29937 -f 5253/6074/29938 5252/6072/29939 5254/6076/29940 -f 5256/6078/29941 5252/6072/29942 5244/6058/29943 -f 5244/6058/29944 5242/6056/29945 5256/6078/29946 -f 5256/6078/29947 5254/6076/29948 5252/6072/29949 -f 5257/6080/29950 5258/6081/29951 5254/6076/29952 -f 5254/6076/29953 5256/6078/29954 5257/6080/29955 -f 5259/6084/29956 5260/6085/29957 5254/6076/29958 -f 5254/6076/29959 5258/6081/29960 5259/6084/29961 -f 5262/6147/29962 5259/6084/29963 5258/6081/29964 -f 5258/6081/29965 5261/6146/29966 5262/6147/29967 -f 5261/6146/29968 5258/6081/29969 5257/6080/29970 -f 5264/6149/29971 5262/6147/29972 5261/6146/29973 -f 5261/6146/29974 5263/6148/29975 5264/6149/29976 -f 5265/6150/29977 5263/6148/29978 5267/6152/29979 -f 5267/6152/29980 5268/6153/29981 5265/6150/29982 -f 5270/6155/29983 5268/6153/29984 5267/6152/29985 -f 5267/6152/29986 5269/6154/29987 5270/6155/29988 -f 5261/6146/29989 5257/6080/29990 5267/6152/29991 -f 5267/6152/29992 5263/6148/29993 5261/6146/29994 -f 5271/6156/29995 5272/6157/29996 5299/6158/29997 -f 5273/6159/29998 5271/6156/29999 5267/6152/30000 -f 5267/6152/30001 5257/6080/30002 5273/6159/30003 -f 5257/6080/30004 5256/6078/30005 5242/6056/30006 -f 5242/6056/30007 5238/6054/30008 5257/6080/30009 -f 5273/6159/30010 5257/6080/30011 5238/6054/30012 -f 5274/6160/30013 5273/6159/30014 5238/6054/30015 -f 5238/6054/30016 5237/6055/30017 5274/6160/30018 -f 5275/6161/30019 5271/6156/30020 5273/6159/30021 -f 5273/6159/30022 5274/6160/30023 5275/6161/30024 -f 5276/6060/30025 5274/6059/30026 5237/6022/30027 -f 5237/6022/30028 5236/6021/30029 5276/6060/30030 -f 5274/6059/30031 5276/6060/30032 5277/6061/30033 -f 5277/6061/30034 5275/6062/30035 5274/6059/30036 -f 5278/6120/30037 5279/6121/30038 5240/6115/30039 -f 5240/6115/30040 5247/6118/30041 5278/6120/30042 -f 5286/6122/30043 5280/6123/30044 5279/6121/30045 -f 5279/6121/30046 5278/6120/30047 5286/6122/30048 -f 5239/6114/30049 5240/6115/30050 5279/6121/30051 -f 5279/6121/30052 5280/6123/30053 5239/6114/30054 -f 5281/6124/30055 5239/6114/30056 5280/6123/30057 -f 5247/6118/30058 5249/6119/30059 5251/6125/30060 -f 5251/6125/30061 5278/6120/30062 5247/6118/30063 -f 5278/6120/30064 5251/6125/30065 5282/6126/30066 -f 5282/6126/30067 5286/6122/30068 5278/6120/30069 -f 5253/6074/30070 5282/6162/30071 5251/6070/30072 -f 5251/6070/30073 5250/6069/30074 5253/6074/30075 -f 5253/6074/30076 5255/6077/30077 5283/6163/30078 -f 5283/6163/30079 5282/6162/30080 5253/6074/30081 -f 5286/6122/30082 5282/6126/30083 5283/6127/30084 -s 2 -f 5285/6165/30085 5260/6085/30086 5259/6084/30087 -f 5259/6084/30088 5284/6164/30089 5285/6165/30090 -s 1 -f 5286/6122/30091 5285/6129/30092 5284/6130/30093 -f 5284/6130/30094 5288/6128/30095 5286/6122/30096 -s 4 -f 5285/6165/30097 5286/6166/30098 5254/6076/30099 -f 5254/6076/30100 5260/6085/30101 5285/6165/30102 -s 2 -f 5283/6163/30103 5255/6077/30104 5254/6076/30105 -f 5254/6076/30106 5286/6166/30107 5283/6163/30108 -f 5259/6084/30109 5262/6147/30110 5287/6167/30111 -f 5287/6167/30112 5284/6164/30113 5259/6084/30114 -s 1 -f 5288/6128/30115 5284/6130/30116 5287/6131/30117 -s 2 -f 5262/6147/30118 5264/6149/30119 5289/6168/30120 -f 5289/6168/30121 5287/6167/30122 5262/6147/30123 -s 1 -f 5287/6131/30124 5289/6133/30125 5290/6132/30126 -f 5290/6132/30127 5288/6128/30128 5287/6131/30129 -f 5286/6122/30130 5288/6128/30131 5280/6123/30132 -f 5280/6123/30133 5288/6128/30134 5290/6132/30135 -s 2 -f 5289/6168/30136 5264/6149/30137 5266/6151/30138 -f 5266/6151/30139 5291/6169/30140 5289/6168/30141 -s 1 -f 5289/6133/30142 5291/6135/30143 5292/6134/30144 -f 5292/6134/30145 5290/6132/30146 5289/6133/30147 -f 5293/6136/30148 5294/6137/30149 5290/6132/30150 -f 5290/6132/30151 5292/6134/30152 5293/6136/30153 -f 5280/6123/30154 5290/6132/30155 5294/6137/30156 -f 5294/6137/30157 5293/6136/30158 5295/6138/30159 -f 5295/6138/30160 5296/6139/30161 5294/6137/30162 -f 5280/6123/30163 5294/6137/30164 5297/6140/30165 -f 5297/6140/30166 5281/6124/30167 5280/6123/30168 -f 5297/6140/30169 5277/6141/30170 5276/6142/30171 -f 5276/6142/30172 5281/6124/30173 5297/6140/30174 -f 5236/6113/30175 5239/6114/30176 5281/6124/30177 -f 5281/6124/30178 5276/6142/30179 5236/6113/30180 -f 5294/6137/30181 5296/6139/30182 5300/6143/30183 -f 5297/6140/30184 5294/6137/30185 5300/6143/30186 -f 5297/6140/30187 5300/6143/30188 5301/6144/30189 -f 5301/6144/30190 5298/6145/30191 5277/6141/30192 -f 5277/6141/30193 5297/6140/30194 5301/6144/30195 -f 5275/6062/30196 5277/6061/30197 5298/6083/30198 -f 5275/6161/30199 5298/6170/30200 5272/6157/30201 -f 5272/6157/30202 5271/6156/30203 5275/6161/30204 -s 4 -f 5292/6171/30205 5291/6169/30206 5266/6151/30207 -f 5266/6151/30208 5265/6150/30209 5292/6171/30210 -s 1 -f 5293/6173/30211 5268/6153/30212 5270/6155/30213 -f 5270/6155/30214 5295/6172/30215 5293/6173/30216 -f 5268/6153/30217 5293/6173/30218 5292/6171/30219 -f 5292/6171/30220 5265/6150/30221 5268/6153/30222 -f 5295/6172/30223 5270/6155/30224 5269/6154/30225 -f 5269/6154/30226 5296/6174/30227 5295/6172/30228 -f 5296/6174/30229 5269/6154/30230 5299/6158/30231 -f 5299/6158/30232 5300/6175/30233 5296/6174/30234 -f 5271/6156/30235 5299/6158/30236 5269/6154/30237 -f 5269/6154/30238 5267/6152/30239 5271/6156/30240 -f 5272/6157/30241 5298/6170/30242 5300/6175/30243 -f 5300/6175/30244 5299/6158/30245 5272/6157/30246 -f 5300/6143/30247 5298/6145/30248 5301/6144/30249 -f 5154/5949/30250 5141/5938/30251 5157/5953/30252 -f 5157/5953/30253 5141/5938/30254 5161/5956/30255 -f 5266/6151/30256 5264/6149/30257 5263/6148/30258 -f 5263/6148/30259 5265/6150/30260 5266/6151/30261 -f 5197/6093/30262 5194/6091/30263 5189/6075/30264 -f 5189/6075/30265 5302/6176/30266 5197/6093/30267 -f 5189/6075/30268 5184/6012/30269 5303/6177/30270 -f 5303/6177/30271 5302/6176/30272 5189/6075/30273 -f 5184/6012/30274 5185/6063/30275 5186/6065/30276 -f 5186/6065/30277 5303/6177/30278 5184/6012/30279 -f 5304/6180/30280 5320/6181/30281 5321/6178/30282 -f 5321/6178/30283 5305/6179/30284 5304/6180/30285 -f 5305/6179/30286 5321/6178/30287 5322/6182/30288 -f 5322/6182/30289 5306/6183/30290 5305/6179/30291 -f 5306/6183/30292 5322/6182/30293 5323/6184/30294 -f 5323/6184/30295 5307/6185/30296 5306/6183/30297 -f 5307/6185/30298 5323/6184/30299 5324/6186/30300 -f 5324/6186/30301 5308/6187/30302 5307/6185/30303 -f 5308/6187/30304 5324/6186/30305 5325/6188/30306 -f 5325/6188/30307 5309/6189/30308 5308/6187/30309 -f 5309/6189/30310 5325/6188/30311 5326/6190/30312 -f 5326/6190/30313 5310/6191/30314 5309/6189/30315 -f 5310/6191/30316 5326/6190/30317 5327/6192/30318 -f 5327/6192/30319 5311/6193/30320 5310/6191/30321 -f 5311/6193/30322 5327/6192/30323 5328/6194/30324 -f 5328/6194/30325 5312/6195/30326 5311/6193/30327 -f 5312/6195/30328 5328/6194/30329 5329/6196/30330 -f 5329/6196/30331 5313/6197/30332 5312/6195/30333 -f 5313/6197/30334 5329/6196/30335 5330/6198/30336 -f 5330/6198/30337 5314/6199/30338 5313/6197/30339 -f 5314/6199/30340 5330/6198/30341 5331/6200/30342 -f 5331/6200/30343 5315/6201/30344 5314/6199/30345 -f 5315/6201/30346 5331/6200/30347 5332/6202/30348 -f 5332/6202/30349 5316/6203/30350 5315/6201/30351 -f 5316/6203/30352 5332/6202/30353 5333/6204/30354 -f 5333/6204/30355 5317/6205/30356 5316/6203/30357 -f 5317/6205/30358 5333/6204/30359 5334/6206/30360 -f 5334/6206/30361 5318/6207/30362 5317/6205/30363 -f 5318/6207/30364 5334/6206/30365 5335/6208/30366 -f 5335/6208/30367 5319/6209/30368 5318/6207/30369 -f 5319/6209/30370 5335/6208/30371 5320/6181/30372 -f 5320/6181/30373 5304/6180/30374 5319/6209/30375 -f 5320/6181/30376 5336/6211/30377 5337/6210/30378 -f 5337/6210/30379 5321/6178/30380 5320/6181/30381 -f 5321/6178/30382 5337/6210/30383 5338/6212/30384 -f 5338/6212/30385 5322/6182/30386 5321/6178/30387 -f 5322/6182/30388 5338/6212/30389 5339/6213/30390 -f 5339/6213/30391 5323/6184/30392 5322/6182/30393 -f 5323/6184/30394 5339/6213/30395 5340/6214/30396 -f 5340/6214/30397 5324/6186/30398 5323/6184/30399 -f 5324/6186/30400 5340/6214/30401 5341/6215/30402 -f 5341/6215/30403 5325/6188/30404 5324/6186/30405 -f 5325/6188/30406 5341/6215/30407 5342/6216/30408 -f 5342/6216/30409 5326/6190/30410 5325/6188/30411 -f 5326/6190/30412 5342/6216/30413 5343/6217/30414 -f 5343/6217/30415 5327/6192/30416 5326/6190/30417 -f 5327/6192/30418 5343/6217/30419 5344/6218/30420 -f 5344/6218/30421 5328/6194/30422 5327/6192/30423 -f 5328/6194/30424 5344/6218/30425 5345/6219/30426 -f 5345/6219/30427 5329/6196/30428 5328/6194/30429 -f 5329/6196/30430 5345/6219/30431 5346/6220/30432 -f 5346/6220/30433 5330/6198/30434 5329/6196/30435 -f 5330/6198/30436 5346/6220/30437 5347/6221/30438 -f 5347/6221/30439 5331/6200/30440 5330/6198/30441 -f 5331/6200/30442 5347/6221/30443 5348/6222/30444 -f 5348/6222/30445 5332/6202/30446 5331/6200/30447 -f 5332/6202/30448 5348/6222/30449 5349/6223/30450 -f 5349/6223/30451 5333/6204/30452 5332/6202/30453 -f 5333/6204/30454 5349/6223/30455 5350/6224/30456 -f 5350/6224/30457 5334/6206/30458 5333/6204/30459 -f 5334/6206/30460 5350/6224/30461 5351/6225/30462 -f 5351/6225/30463 5335/6208/30464 5334/6206/30465 -f 5335/6208/30466 5351/6225/30467 5336/6211/30468 -f 5336/6211/30469 5320/6181/30470 5335/6208/30471 -f 5336/6211/30472 5352/6227/30473 5353/6226/30474 -f 5353/6226/30475 5337/6210/30476 5336/6211/30477 -f 5337/6210/30478 5353/6226/30479 5354/6228/30480 -f 5354/6228/30481 5338/6212/30482 5337/6210/30483 -f 5338/6212/30484 5354/6380/30485 5355/6229/30486 -f 5355/6229/30487 5339/6213/30488 5338/6212/30489 -f 5339/6213/30490 5355/6229/30491 5356/6230/30492 -f 5356/6230/30493 5340/6214/30494 5339/6213/30495 -f 5340/6214/30496 5356/6230/30497 5357/6231/30498 -f 5357/6231/30499 5341/6215/30500 5340/6214/30501 -f 5341/6215/30502 5357/6381/30503 5358/6232/30504 -f 5358/6232/30505 5342/6216/30506 5341/6215/30507 -f 5342/6216/30508 5358/6232/30509 5359/6233/30510 -f 5359/6233/30511 5343/6217/30512 5342/6216/30513 -f 5343/6217/30514 5359/6233/30515 5360/6234/30516 -f 5360/6234/30517 5344/6218/30518 5343/6217/30519 -f 5344/6218/30520 5360/6382/30521 5361/6235/30522 -f 5361/6235/30523 5345/6219/30524 5344/6218/30525 -f 5345/6219/30526 5361/6235/30527 5362/6236/30528 -f 5362/6236/30529 5346/6220/30530 5345/6219/30531 -f 5346/6220/30532 5362/6383/30533 5363/6237/30534 -f 5363/6237/30535 5347/6221/30536 5346/6220/30537 -f 5347/6221/30538 5363/6237/30539 5364/6238/30540 -f 5364/6238/30541 5348/6222/30542 5347/6221/30543 -f 5348/6222/30544 5364/6384/30545 5365/6239/30546 -f 5365/6239/30547 5349/6223/30548 5348/6222/30549 -f 5349/6223/30550 5365/6239/30551 5366/6240/30552 -f 5366/6240/30553 5350/6224/30554 5349/6223/30555 -f 5350/6224/30556 5366/6240/30557 5367/6241/30558 -f 5367/6241/30559 5351/6225/30560 5350/6224/30561 -f 5351/6225/30562 5367/6385/30563 5352/6227/30564 -f 5352/6227/30565 5336/6211/30566 5351/6225/30567 -f 5352/6227/30568 5368/6243/30569 5369/6242/30570 -f 5369/6242/30571 5353/6226/30572 5352/6227/30573 -f 5353/6226/30574 5369/6242/30575 5370/6244/30576 -f 5370/6244/30577 5354/6228/30578 5353/6226/30579 -f 5354/6380/30580 5370/6386/30581 5371/6245/30582 -f 5371/6245/30583 5355/6229/30584 5354/6380/30585 -f 5355/6229/30586 5371/6245/30587 5372/6246/30588 -f 5372/6246/30589 5356/6230/30590 5355/6229/30591 -f 5356/6230/30592 5372/6246/30593 5373/6247/30594 -f 5373/6247/30595 5357/6231/30596 5356/6230/30597 -f 5357/6381/30598 5373/6387/30599 5374/6248/30600 -f 5374/6248/30601 5358/6232/30602 5357/6381/30603 -f 5358/6232/30604 5374/6248/30605 5375/6249/30606 -f 5375/6249/30607 5359/6233/30608 5358/6232/30609 -f 5359/6233/30610 5375/6249/30611 5376/6250/30612 -f 5376/6250/30613 5360/6234/30614 5359/6233/30615 -f 5360/6382/30616 5376/6388/30617 5377/6251/30618 -f 5377/6251/30619 5361/6235/30620 5360/6382/30621 -f 5361/6235/30622 5377/6251/30623 5378/6252/30624 -f 5378/6252/30625 5362/6236/30626 5361/6235/30627 -f 5362/6383/30628 5378/6389/30629 5379/6253/30630 -f 5379/6253/30631 5363/6237/30632 5362/6383/30633 -f 5363/6237/30634 5379/6253/30635 5380/6254/30636 -f 5380/6254/30637 5364/6238/30638 5363/6237/30639 -f 5364/6384/30640 5380/6390/30641 5381/6255/30642 -f 5381/6255/30643 5365/6239/30644 5364/6384/30645 -f 5365/6239/30646 5381/6255/30647 5382/6256/30648 -f 5382/6256/30649 5366/6240/30650 5365/6239/30651 -f 5366/6240/30652 5382/6256/30653 5383/6257/30654 -f 5383/6257/30655 5367/6241/30656 5366/6240/30657 -f 5367/6385/30658 5383/6391/30659 5368/6243/30660 -f 5368/6243/30661 5352/6227/30662 5367/6385/30663 -f 5401/6260/30664 5402/6261/30665 5403/6258/30666 -f 5403/6258/30667 5388/6259/30668 5401/6260/30669 -f 5386/6264/30670 5389/6265/30671 5390/6262/30672 -f 5390/6262/30673 5385/6263/30674 5386/6264/30675 -f 5386/6264/30676 5387/6267/30677 5404/6266/30678 -f 5404/6266/30679 5389/6265/30680 5386/6264/30681 -f 5387/6267/30682 5388/6259/30683 5403/6258/30684 -f 5403/6258/30685 5404/6266/30686 5387/6267/30687 -f 5385/6263/30688 5390/6262/30689 5391/6268/30690 -f 5391/6268/30691 5384/6269/30692 5385/6263/30693 -f 5391/6268/30694 5392/6271/30695 5393/6270/30696 -f 5393/6270/30697 5384/6269/30698 5391/6268/30699 -f 5393/6270/30700 5394/6273/30701 5395/6272/30702 -f 5395/6272/30703 5384/6269/30704 5393/6270/30705 -f 5385/6263/30706 5384/6269/30707 5395/6272/30708 -f 5395/6272/30709 5396/6274/30710 5385/6263/30711 -f 5386/6264/30712 5385/6263/30713 5396/6274/30714 -f 5396/6274/30715 5397/6275/30716 5386/6264/30717 -f 5398/6276/30718 5387/6267/30719 5386/6264/30720 -f 5386/6264/30721 5397/6275/30722 5398/6276/30723 -f 5399/6277/30724 5388/6259/30725 5387/6267/30726 -f 5387/6267/30727 5398/6276/30728 5399/6277/30729 -f 5388/6259/30730 5399/6277/30731 5400/6278/30732 -f 5400/6278/30733 5401/6260/30734 5388/6259/30735 -f 5390/6262/30736 5389/6265/30737 5304/6180/30738 -f 5304/6180/30739 5305/6179/30740 5390/6262/30741 -f 5391/6268/30742 5390/6262/30743 5305/6179/30744 -f 5305/6179/30745 5306/6183/30746 5391/6268/30747 -f 5392/6271/30748 5391/6268/30749 5306/6183/30750 -f 5306/6183/30751 5307/6185/30752 5392/6271/30753 -f 5393/6270/30754 5392/6271/30755 5307/6185/30756 -f 5307/6185/30757 5308/6187/30758 5393/6270/30759 -f 5394/6273/30760 5393/6270/30761 5308/6187/30762 -f 5308/6187/30763 5309/6189/30764 5394/6273/30765 -f 5395/6272/30766 5394/6273/30767 5309/6189/30768 -f 5309/6189/30769 5310/6191/30770 5395/6272/30771 -f 5396/6274/30772 5395/6272/30773 5310/6191/30774 -f 5310/6191/30775 5311/6193/30776 5396/6274/30777 -f 5397/6275/30778 5396/6274/30779 5311/6193/30780 -f 5311/6193/30781 5312/6195/30782 5397/6275/30783 -f 5398/6276/30784 5397/6275/30785 5312/6195/30786 -f 5312/6195/30787 5313/6197/30788 5398/6276/30789 -f 5399/6277/30790 5398/6276/30791 5313/6197/30792 -f 5313/6197/30793 5314/6199/30794 5399/6277/30795 -f 5400/6278/30796 5399/6277/30797 5314/6199/30798 -f 5314/6199/30799 5315/6201/30800 5400/6278/30801 -f 5401/6260/30802 5400/6278/30803 5315/6201/30804 -f 5315/6201/30805 5316/6203/30806 5401/6260/30807 -f 5402/6261/30808 5401/6260/30809 5316/6203/30810 -f 5316/6203/30811 5317/6205/30812 5402/6261/30813 -f 5403/6258/30814 5402/6261/30815 5317/6205/30816 -f 5317/6205/30817 5318/6207/30818 5403/6258/30819 -f 5404/6266/30820 5403/6258/30821 5318/6207/30822 -f 5318/6207/30823 5319/6209/30824 5404/6266/30825 -f 5389/6265/30826 5404/6266/30827 5319/6209/30828 -f 5319/6209/30829 5304/6180/30830 5389/6265/30831 -f 5405/6281/30832 5408/6282/30833 5407/6279/30834 -f 5407/6279/30835 5406/6280/30836 5405/6281/30837 -f 5408/6282/30838 5410/6284/30839 5409/6283/30840 -f 5409/6283/30841 5407/6279/30842 5408/6282/30843 -f 5410/6284/30844 5412/6286/30845 5411/6285/30846 -f 5411/6285/30847 5409/6283/30848 5410/6284/30849 -f 5412/6286/30850 5414/6288/30851 5413/6287/30852 -f 5413/6287/30853 5411/6285/30854 5412/6286/30855 -f 5414/6288/30856 5416/6290/30857 5415/6289/30858 -f 5415/6289/30859 5413/6287/30860 5414/6288/30861 -f 5416/6290/30862 5418/6292/30863 5417/6291/30864 -f 5417/6291/30865 5415/6289/30866 5416/6290/30867 -f 5418/6292/30868 5420/6294/30869 5419/6293/30870 -f 5419/6293/30871 5417/6291/30872 5418/6292/30873 -f 5420/6294/30874 5422/6296/30875 5421/6295/30876 -f 5421/6295/30877 5419/6293/30878 5420/6294/30879 -f 5422/6296/30880 5424/6298/30881 5423/6297/30882 -f 5423/6297/30883 5421/6295/30884 5422/6296/30885 -f 5424/6298/30886 5426/6300/30887 5425/6299/30888 -f 5425/6299/30889 5423/6297/30890 5424/6298/30891 -f 5426/6300/30892 5428/6302/30893 5427/6301/30894 -f 5427/6301/30895 5425/6299/30896 5426/6300/30897 -f 5428/6302/30898 5430/6304/30899 5429/6303/30900 -f 5429/6303/30901 5427/6301/30902 5428/6302/30903 -f 5430/6304/30904 5432/6306/30905 5431/6305/30906 -f 5431/6305/30907 5429/6303/30908 5430/6304/30909 -f 5432/6306/30910 5434/6308/30911 5433/6307/30912 -f 5433/6307/30913 5431/6305/30914 5432/6306/30915 -f 5434/6308/30916 5436/6310/30917 5435/6309/30918 -f 5435/6309/30919 5433/6307/30920 5434/6308/30921 -f 5436/6310/30922 5405/6281/30923 5406/6280/30924 -f 5406/6280/30925 5435/6309/30926 5436/6310/30927 -f 5406/6280/30928 5407/6279/30929 5438/6311/30930 -f 5438/6311/30931 5437/6312/30932 5406/6280/30933 -f 5407/6279/30934 5409/6283/30935 5439/6313/30936 -f 5439/6313/30937 5438/6311/30938 5407/6279/30939 -f 5409/6283/30940 5411/6285/30941 5440/6314/30942 -f 5440/6314/30943 5439/6313/30944 5409/6283/30945 -f 5411/6285/30946 5413/6287/30947 5441/6315/30948 -f 5441/6315/30949 5440/6314/30950 5411/6285/30951 -f 5413/6287/30952 5415/6289/30953 5442/6316/30954 -f 5442/6316/30955 5441/6315/30956 5413/6287/30957 -f 5415/6289/30958 5417/6291/30959 5443/6317/30960 -f 5443/6317/30961 5442/6316/30962 5415/6289/30963 -f 5417/6291/30964 5419/6293/30965 5444/6318/30966 -f 5444/6318/30967 5443/6317/30968 5417/6291/30969 -f 5419/6293/30970 5421/6295/30971 5445/6319/30972 -f 5445/6319/30973 5444/6318/30974 5419/6293/30975 -f 5421/6295/30976 5423/6297/30977 5446/6320/30978 -f 5446/6320/30979 5445/6319/30980 5421/6295/30981 -f 5423/6297/30982 5425/6299/30983 5447/6321/30984 -f 5447/6321/30985 5446/6320/30986 5423/6297/30987 -f 5425/6299/30988 5427/6301/30989 5448/6322/30990 -f 5448/6322/30991 5447/6321/30992 5425/6299/30993 -f 5427/6301/30994 5429/6303/30995 5449/6323/30996 -f 5449/6323/30997 5448/6322/30998 5427/6301/30999 -f 5429/6303/31000 5431/6305/31001 5450/6324/31002 -f 5450/6324/31003 5449/6323/31004 5429/6303/31005 -f 5431/6305/31006 5433/6307/31007 5451/6325/31008 -f 5451/6325/31009 5450/6324/31010 5431/6305/31011 -f 5433/6307/31012 5435/6309/31013 5452/6326/31014 -f 5452/6326/31015 5451/6325/31016 5433/6307/31017 -f 5435/6309/31018 5406/6280/31019 5437/6312/31020 -f 5437/6312/31021 5452/6326/31022 5435/6309/31023 -f 5437/6312/31024 5438/6311/31025 5454/6327/31026 -f 5454/6327/31027 5453/6328/31028 5437/6312/31029 -f 5438/6311/31030 5439/6313/31031 5455/6329/31032 -f 5455/6329/31033 5454/6392/31034 5438/6311/31035 -f 5439/6313/31036 5440/6314/31037 5456/6330/31038 -f 5456/6330/31039 5455/6329/31040 5439/6313/31041 -f 5440/6314/31042 5441/6315/31043 5457/6331/31044 -f 5457/6331/31045 5456/6330/31046 5440/6314/31047 -f 5441/6315/31048 5442/6316/31049 5458/6332/31050 -f 5458/6332/31051 5457/6393/31052 5441/6315/31053 -f 5442/6316/31054 5443/6317/31055 5459/6333/31056 -f 5459/6333/31057 5458/6332/31058 5442/6316/31059 -f 5443/6317/31060 5444/6318/31061 5460/6334/31062 -f 5460/6334/31063 5459/6333/31064 5443/6317/31065 -f 5444/6318/31066 5445/6319/31067 5461/6335/31068 -f 5461/6335/31069 5460/6394/31070 5444/6318/31071 -f 5445/6319/31072 5446/6320/31073 5462/6336/31074 -f 5462/6336/31075 5461/6335/31076 5445/6319/31077 -f 5446/6320/31078 5447/6321/31079 5463/6337/31080 -f 5463/6337/31081 5462/6395/31082 5446/6320/31083 -f 5447/6321/31084 5448/6322/31085 5464/6338/31086 -f 5464/6338/31087 5463/6337/31088 5447/6321/31089 -f 5448/6322/31090 5449/6323/31091 5465/6339/31092 -f 5465/6339/31093 5464/6396/31094 5448/6322/31095 -f 5449/6323/31096 5450/6324/31097 5466/6340/31098 -f 5466/6340/31099 5465/6339/31100 5449/6323/31101 -f 5450/6324/31102 5451/6325/31103 5467/6341/31104 -f 5467/6341/31105 5466/6340/31106 5450/6324/31107 -f 5451/6325/31108 5452/6326/31109 5468/6342/31110 -f 5468/6342/31111 5467/6397/31112 5451/6325/31113 -f 5452/6326/31114 5437/6312/31115 5453/6328/31116 -f 5453/6328/31117 5468/6342/31118 5452/6326/31119 -f 5453/6328/31120 5454/6327/31121 5470/6343/31122 -f 5470/6343/31123 5469/6344/31124 5453/6328/31125 -f 5454/6392/31126 5455/6329/31127 5471/6345/31128 -f 5471/6345/31129 5470/6398/31130 5454/6392/31131 -f 5455/6329/31132 5456/6330/31133 5472/6346/31134 -f 5472/6346/31135 5471/6345/31136 5455/6329/31137 -f 5456/6330/31138 5457/6331/31139 5473/6347/31140 -f 5473/6347/31141 5472/6346/31142 5456/6330/31143 -f 5457/6393/31144 5458/6332/31145 5474/6348/31146 -f 5474/6348/31147 5473/6399/31148 5457/6393/31149 -f 5458/6332/31150 5459/6333/31151 5475/6349/31152 -f 5475/6349/31153 5474/6348/31154 5458/6332/31155 -f 5459/6333/31156 5460/6334/31157 5476/6350/31158 -f 5476/6350/31159 5475/6349/31160 5459/6333/31161 -f 5460/6394/31162 5461/6335/31163 5477/6351/31164 -f 5477/6351/31165 5476/6400/31166 5460/6394/31167 -f 5461/6335/31168 5462/6336/31169 5478/6352/31170 -f 5478/6352/31171 5477/6351/31172 5461/6335/31173 -f 5462/6395/31174 5463/6337/31175 5479/6353/31176 -f 5479/6353/31177 5478/6401/31178 5462/6395/31179 -f 5463/6337/31180 5464/6338/31181 5480/6354/31182 -f 5480/6354/31183 5479/6353/31184 5463/6337/31185 -f 5464/6396/31186 5465/6339/31187 5481/6355/31188 -f 5481/6355/31189 5480/6402/31190 5464/6396/31191 -f 5465/6339/31192 5466/6340/31193 5482/6356/31194 -f 5482/6356/31195 5481/6355/31196 5465/6339/31197 -f 5466/6340/31198 5467/6341/31199 5483/6357/31200 -f 5483/6357/31201 5482/6356/31202 5466/6340/31203 -f 5467/6397/31204 5468/6342/31205 5484/6358/31206 -f 5484/6358/31207 5483/6403/31208 5467/6397/31209 -f 5468/6342/31210 5453/6328/31211 5469/6344/31212 -f 5469/6344/31213 5484/6358/31214 5468/6342/31215 -f 5485/6361/31216 5488/6362/31217 5487/6359/31218 -f 5487/6359/31219 5486/6360/31220 5485/6361/31221 -f 5492/6365/31222 5491/6366/31223 5490/6363/31224 -f 5490/6363/31225 5489/6364/31226 5492/6365/31227 -f 5492/6365/31228 5489/6364/31229 5493/6367/31230 -f 5493/6367/31231 5494/6368/31232 5492/6365/31233 -f 5494/6368/31234 5493/6367/31235 5487/6359/31236 -f 5487/6359/31237 5488/6362/31238 5494/6368/31239 -f 5491/6366/31240 5496/6370/31241 5495/6369/31242 -f 5495/6369/31243 5490/6363/31244 5491/6366/31245 -f 5495/6369/31246 5496/6370/31247 5498/6371/31248 -f 5498/6371/31249 5497/6372/31250 5495/6369/31251 -f 5498/6371/31252 5496/6370/31253 5500/6373/31254 -f 5500/6373/31255 5499/6374/31256 5498/6371/31257 -f 5491/6366/31258 5501/6375/31259 5500/6373/31260 -f 5500/6373/31261 5496/6370/31262 5491/6366/31263 -f 5492/6365/31264 5502/6376/31265 5501/6375/31266 -f 5501/6375/31267 5491/6366/31268 5492/6365/31269 -f 5503/6377/31270 5502/6376/31271 5492/6365/31272 -f 5492/6365/31273 5494/6368/31274 5503/6377/31275 -f 5504/6378/31276 5503/6377/31277 5494/6368/31278 -f 5494/6368/31279 5488/6362/31280 5504/6378/31281 -f 5488/6362/31282 5485/6361/31283 5505/6379/31284 -f 5505/6379/31285 5504/6378/31286 5488/6362/31287 -f 5490/6363/31288 5408/6282/31289 5405/6281/31290 -f 5405/6281/31291 5489/6364/31292 5490/6363/31293 -f 5495/6369/31294 5410/6284/31295 5408/6282/31296 -f 5408/6282/31297 5490/6363/31298 5495/6369/31299 -f 5497/6372/31300 5412/6286/31301 5410/6284/31302 -f 5410/6284/31303 5495/6369/31304 5497/6372/31305 -f 5498/6371/31306 5414/6288/31307 5412/6286/31308 -f 5412/6286/31309 5497/6372/31310 5498/6371/31311 -f 5499/6374/31312 5416/6290/31313 5414/6288/31314 -f 5414/6288/31315 5498/6371/31316 5499/6374/31317 -f 5500/6373/31318 5418/6292/31319 5416/6290/31320 -f 5416/6290/31321 5499/6374/31322 5500/6373/31323 -f 5501/6375/31324 5420/6294/31325 5418/6292/31326 -f 5418/6292/31327 5500/6373/31328 5501/6375/31329 -f 5502/6376/31330 5422/6296/31331 5420/6294/31332 -f 5420/6294/31333 5501/6375/31334 5502/6376/31335 -f 5503/6377/31336 5424/6298/31337 5422/6296/31338 -f 5422/6296/31339 5502/6376/31340 5503/6377/31341 -f 5504/6378/31342 5426/6300/31343 5424/6298/31344 -f 5424/6298/31345 5503/6377/31346 5504/6378/31347 -f 5505/6379/31348 5428/6302/31349 5426/6300/31350 -f 5426/6300/31351 5504/6378/31352 5505/6379/31353 -f 5485/6361/31354 5430/6304/31355 5428/6302/31356 -f 5428/6302/31357 5505/6379/31358 5485/6361/31359 -f 5486/6360/31360 5432/6306/31361 5430/6304/31362 -f 5430/6304/31363 5485/6361/31364 5486/6360/31365 -f 5487/6359/31366 5434/6308/31367 5432/6306/31368 -f 5432/6306/31369 5486/6360/31370 5487/6359/31371 -f 5493/6367/31372 5436/6310/31373 5434/6308/31374 -f 5434/6308/31375 5487/6359/31376 5493/6367/31377 -f 5489/6364/31378 5405/6281/31379 5436/6310/31380 -f 5436/6310/31381 5493/6367/31382 5489/6364/31383 -f 5520/6406/31384 5507/6407/31385 5596/6404/31386 -f 5596/6404/31387 5521/6405/31388 5520/6406/31389 -f 5522/6408/31390 5510/6409/31391 5507/6407/31392 -f 5507/6407/31393 5520/6406/31394 5522/6408/31395 -f 5515/6412/31396 5516/6413/31397 5531/6410/31398 -f 5531/6410/31399 5529/6411/31400 5515/6412/31401 -f 5519/6416/31402 5518/6417/31403 5528/6414/31404 -f 5528/6414/31405 5527/6415/31406 5519/6416/31407 -f 5508/6420/31408 5509/6421/31409 5524/6418/31410 -f 5524/6418/31411 5523/6419/31412 5508/6420/31413 -f 5526/6422/31414 5513/6423/31415 5519/6416/31416 -f 5519/6416/31417 5527/6415/31418 5526/6422/31419 -f 5519/6416/31420 5513/6423/31421 5525/6424/31422 -f 5525/6424/31423 5523/6419/31424 5519/6416/31425 -f 5508/6420/31426 5520/6406/31427 5521/6405/31428 -f 5521/6405/31429 5509/6421/31430 5508/6420/31431 -f 5511/6425/31432 5522/6408/31433 5520/6406/31434 -f 5520/6406/31435 5508/6420/31436 5511/6425/31437 -f 5523/6419/31438 5524/6418/31439 5518/6417/31440 -f 5518/6417/31441 5519/6416/31442 5523/6419/31443 -f 5508/6420/31444 5523/6419/31445 5525/6424/31446 -f 5525/6424/31447 5511/6425/31448 5508/6420/31449 -f 5527/6415/31450 5528/6414/31451 5516/6413/31452 -f 5516/6413/31453 5515/6412/31454 5527/6415/31455 -f 5512/6426/31456 5526/6422/31457 5527/6415/31458 -f 5527/6415/31459 5515/6412/31460 5512/6426/31461 -f 5529/6411/31462 5530/6427/31463 5512/6426/31464 -f 5512/6426/31465 5515/6412/31466 5529/6411/31467 -f 5529/6411/31468 5531/6410/31469 5517/6428/31470 -f 5517/6428/31471 5599/6429/31472 5529/6411/31473 -f 5542/6430/31474 5532/6431/31475 5510/6409/31476 -f 5510/6409/31477 5522/6408/31478 5542/6430/31479 -f 5543/6432/31480 5534/6433/31481 5532/6431/31482 -f 5532/6431/31483 5542/6430/31484 5543/6432/31485 -f 5544/6436/31486 5535/6437/31487 5533/6434/31488 -f 5533/6434/31489 5545/6435/31490 5544/6436/31491 -f 5547/6440/31492 5546/6441/31493 5538/6438/31494 -f 5538/6438/31495 5539/6439/31496 5547/6440/31497 -f 5526/6422/31498 5512/6426/31499 5538/6438/31500 -f 5538/6438/31501 5546/6441/31502 5526/6422/31503 -f 5530/6427/31504 5529/6411/31505 5599/6429/31506 -f 5599/6429/31507 5606/6442/31508 5530/6427/31509 -f 5606/6442/31510 5607/6444/31511 5548/6443/31512 -f 5548/6443/31513 5530/6427/31514 5606/6442/31515 -f 5533/6434/31516 5511/6425/31517 5525/6424/31518 -f 5525/6424/31519 5545/6435/31520 5533/6434/31521 -f 5533/6434/31522 5542/6430/31523 5522/6408/31524 -f 5522/6408/31525 5511/6425/31526 5533/6434/31527 -f 5535/6437/31528 5543/6432/31529 5542/6430/31530 -f 5542/6430/31531 5533/6434/31532 5535/6437/31533 -f 5536/6446/31534 5544/6436/31535 5545/6435/31536 -f 5545/6435/31537 5537/6445/31538 5536/6446/31539 -f 5545/6435/31540 5525/6424/31541 5513/6423/31542 -f 5513/6423/31543 5537/6445/31544 5545/6435/31545 -f 5546/6441/31546 5547/6440/31547 5536/6446/31548 -f 5536/6446/31549 5537/6445/31550 5546/6441/31551 -f 5513/6423/31552 5526/6422/31553 5546/6441/31554 -f 5546/6441/31555 5537/6445/31556 5513/6423/31557 -f 5530/6427/31558 5548/6443/31559 5538/6438/31560 -f 5538/6438/31561 5512/6426/31562 5530/6427/31563 -f 5548/6443/31564 5549/6447/31565 5539/6439/31566 -f 5539/6439/31567 5538/6438/31568 5548/6443/31569 -f 5607/6444/31570 5612/6448/31571 5549/6447/31572 -f 5549/6447/31573 5548/6443/31574 5607/6444/31575 -f 5565/6453/31576 5566/6473/31577 5551/6449/31578 -f 5551/6449/31579 5552/6450/31580 5565/6453/31581 -f 5567/6475/31582 5565/6453/31583 5552/6450/31584 -f 5552/6450/31585 5555/6474/31586 5567/6475/31587 -f 5560/6457/31588 5574/6458/31589 5576/6455/31590 -f 5576/6455/31591 5561/6456/31592 5560/6457/31593 -f 5564/6461/31594 5572/6462/31595 5573/6459/31596 -f 5573/6459/31597 5563/6460/31598 5564/6461/31599 -f 5553/6465/31600 5568/6466/31601 5569/6463/31602 -f 5569/6463/31603 5554/6464/31604 5553/6465/31605 -f 5571/6468/31606 5572/6462/31607 5564/6461/31608 -f 5564/6461/31609 5558/6467/31610 5571/6468/31611 -f 5564/6461/31612 5568/6466/31613 5570/6469/31614 -f 5570/6469/31615 5558/6467/31616 5564/6461/31617 -f 5553/6465/31618 5554/6464/31619 5566/6452/31620 -f 5566/6452/31621 5565/6451/31622 5553/6465/31623 -f 5556/6470/31624 5553/6465/31625 5565/6451/31626 -f 5565/6451/31627 5567/6454/31628 5556/6470/31629 -f 5568/6466/31630 5564/6461/31631 5563/6460/31632 -f 5563/6460/31633 5569/6463/31634 5568/6466/31635 -f 5553/6465/31636 5556/6470/31637 5570/6469/31638 -f 5570/6469/31639 5568/6466/31640 5553/6465/31641 -f 5572/6462/31642 5560/6457/31643 5561/6456/31644 -f 5561/6456/31645 5573/6459/31646 5572/6462/31647 -f 5557/6471/31648 5560/6457/31649 5572/6462/31650 -f 5572/6462/31651 5571/6468/31652 5557/6471/31653 -f 5574/6458/31654 5560/6457/31655 5557/6471/31656 -f 5557/6471/31657 5575/6472/31658 5574/6458/31659 -f 5574/6480/31660 5559/6481/31661 5562/6477/31662 -f 5562/6477/31663 5576/6478/31664 5574/6480/31665 -f 5587/6486/31666 5567/6475/31667 5555/6474/31668 -f 5555/6474/31669 5577/6485/31670 5587/6486/31671 -f 5588/6489/31672 5587/6486/31673 5577/6485/31674 -f 5577/6485/31675 5579/6487/31676 5588/6489/31677 -f 5589/6493/31678 5590/6494/31679 5578/6490/31680 -f 5578/6490/31681 5580/6492/31682 5589/6493/31683 -f 5592/6497/31684 5584/6498/31685 5583/6495/31686 -f 5583/6495/31687 5591/6496/31688 5592/6497/31689 -f 5571/6468/31690 5591/6484/31691 5583/6483/31692 -f 5583/6483/31693 5557/6471/31694 5571/6468/31695 -f 5575/6499/31696 5585/6500/31697 5559/6481/31698 -f 5559/6481/31699 5574/6480/31700 5575/6499/31701 -f 5585/6500/31702 5575/6499/31703 5593/6502/31704 -f 5593/6502/31705 5586/6506/31706 5585/6500/31707 -f 5578/6479/31708 5590/6482/31709 5570/6469/31710 -f 5570/6469/31711 5556/6470/31712 5578/6479/31713 -f 5578/6479/31714 5556/6470/31715 5567/6454/31716 -f 5567/6454/31717 5587/6476/31718 5578/6479/31719 -f 5580/6492/31720 5578/6490/31721 5587/6531/31722 -f 5587/6531/31723 5588/6532/31724 5580/6492/31725 -f 5581/6503/31726 5582/6504/31727 5590/6494/31728 -f 5590/6494/31729 5589/6493/31730 5581/6503/31731 -f 5590/6482/31732 5582/6491/31733 5558/6467/31734 -f 5558/6467/31735 5570/6469/31736 5590/6482/31737 -f 5591/6496/31738 5582/6504/31739 5581/6503/31740 -f 5581/6503/31741 5592/6497/31742 5591/6496/31743 -f 5558/6467/31744 5582/6491/31745 5591/6484/31746 -f 5591/6484/31747 5571/6468/31748 5558/6467/31749 -f 5575/6472/31750 5557/6471/31751 5583/6483/31752 -f 5583/6483/31753 5593/6488/31754 5575/6472/31755 -f 5593/6501/31756 5583/6495/31757 5584/6498/31758 -f 5584/6498/31759 5594/6505/31760 5593/6501/31761 -f 5586/6506/31762 5593/6502/31763 5594/6507/31764 -f 5594/6507/31765 5595/6508/31766 5586/6506/31767 -s 2 -f 5506/6539/31768 5597/6510/31769 5552/6450/31770 -f 5552/6450/31771 5551/6449/31772 5506/6539/31773 -f 5551/6533/31774 5596/6404/31775 5506/6509/31776 -f 5597/6510/31777 5598/6511/31778 5555/6474/31779 -f 5555/6474/31780 5552/6450/31781 5597/6510/31782 -s 4 -f 5531/6410/31783 5516/6413/31784 5561/6512/31785 -f 5561/6512/31786 5576/6536/31787 5531/6410/31788 -f 5528/6414/31789 5518/6417/31790 5563/6513/31791 -f 5563/6513/31792 5573/6514/31793 5528/6414/31794 -f 5524/6418/31795 5509/6421/31796 5554/6515/31797 -f 5554/6515/31798 5569/6516/31799 5524/6418/31800 -f 5509/6421/31801 5521/6405/31802 5566/6534/31803 -f 5566/6534/31804 5554/6515/31805 5509/6421/31806 -f 5518/6417/31807 5524/6418/31808 5569/6516/31809 -f 5569/6516/31810 5563/6513/31811 5518/6417/31812 -f 5516/6413/31813 5528/6414/31814 5573/6514/31815 -f 5573/6514/31816 5561/6512/31817 5516/6413/31818 -f 5576/6536/31819 5562/6535/31820 5517/6428/31821 -f 5517/6428/31822 5531/6410/31823 5576/6536/31824 -s 1 -f 5514/6518/31825 5600/6540/31826 5562/6477/31827 -f 5562/6477/31828 5559/6481/31829 5514/6518/31830 -s 2 -f 5598/6511/31831 5601/6519/31832 5577/6485/31833 -f 5577/6485/31834 5555/6474/31835 5598/6511/31836 -f 5601/6519/31837 5602/6541/31838 5579/6487/31839 -f 5579/6487/31840 5577/6485/31841 5601/6519/31842 -s 1 -f 5602/6520/31843 5608/6521/31844 5588/6532/31845 -f 5588/6532/31846 5579/6537/31847 5602/6520/31848 -f 5603/6522/31849 5609/6523/31850 5589/6493/31851 -f 5589/6493/31852 5580/6492/31853 5603/6522/31854 -f 5610/6524/31855 5605/6525/31856 5584/6498/31857 -f 5584/6498/31858 5592/6497/31859 5610/6524/31860 -f 5540/6526/31861 5514/6518/31862 5559/6481/31863 -f 5559/6481/31864 5585/6500/31865 5540/6526/31866 -f 5541/6527/31867 5540/6526/31868 5585/6500/31869 -f 5585/6500/31870 5586/6506/31871 5541/6527/31872 -f 5608/6521/31873 5603/6522/31874 5580/6492/31875 -f 5580/6492/31876 5588/6532/31877 5608/6521/31878 -f 5609/6523/31879 5604/6528/31880 5581/6503/31881 -f 5581/6503/31882 5589/6493/31883 5609/6523/31884 -f 5604/6528/31885 5610/6524/31886 5592/6497/31887 -f 5592/6497/31888 5581/6503/31889 5604/6528/31890 -f 5605/6525/31891 5611/6529/31892 5594/6505/31893 -f 5594/6505/31894 5584/6498/31895 5605/6525/31896 -f 5611/6529/31897 5550/6542/31898 5595/6538/31899 -f 5595/6538/31900 5594/6505/31901 5611/6529/31902 -f 5550/6530/31903 5541/6527/31904 5586/6506/31905 -f 5586/6506/31906 5595/6508/31907 5550/6530/31908 -s 2 -f 5507/6407/31909 5597/6510/31910 5506/6539/31911 -f 5506/6539/31912 5596/6404/31913 5507/6407/31914 -f 5510/6409/31915 5598/6511/31916 5597/6510/31917 -f 5597/6510/31918 5507/6407/31919 5510/6409/31920 -s 1 -f 5517/6428/31921 5600/6540/31922 5514/6518/31923 -f 5514/6518/31924 5599/6429/31925 5517/6428/31926 -s 2 -f 5532/6431/31927 5601/6519/31928 5598/6511/31929 -f 5598/6511/31930 5510/6409/31931 5532/6431/31932 -s 1 -f 5543/6432/31933 5608/6521/31934 5602/6520/31935 -f 5602/6520/31936 5534/6433/31937 5543/6432/31938 -s 2 -f 5534/6433/31939 5602/6541/31940 5601/6519/31941 -f 5601/6519/31942 5532/6431/31943 5534/6433/31944 -s 1 -f 5544/6436/31945 5609/6523/31946 5603/6522/31947 -f 5603/6522/31948 5535/6437/31949 5544/6436/31950 -f 5539/6439/31951 5605/6525/31952 5610/6524/31953 -f 5610/6524/31954 5547/6440/31955 5539/6439/31956 -f 5599/6429/31957 5514/6518/31958 5540/6526/31959 -f 5540/6526/31960 5606/6442/31961 5599/6429/31962 -f 5606/6442/31963 5540/6526/31964 5541/6527/31965 -f 5541/6527/31966 5607/6444/31967 5606/6442/31968 -f 5535/6437/31969 5603/6522/31970 5608/6521/31971 -f 5608/6521/31972 5543/6432/31973 5535/6437/31974 -f 5536/6446/31975 5604/6528/31976 5609/6523/31977 -f 5609/6523/31978 5544/6436/31979 5536/6446/31980 -f 5547/6440/31981 5610/6524/31982 5604/6528/31983 -f 5604/6528/31984 5536/6446/31985 5547/6440/31986 -f 5549/6447/31987 5611/6529/31988 5605/6525/31989 -f 5605/6525/31990 5539/6439/31991 5549/6447/31992 -f 5607/6444/31993 5541/6527/31994 5550/6530/31995 -f 5550/6530/31996 5612/6448/31997 5607/6444/31998 -f 5612/6448/31999 5550/6542/32000 5611/6529/32001 -f 5611/6529/32002 5549/6447/32003 5612/6448/32004 -f 5562/6535/32005 5600/6517/32006 5517/6428/32007 -s 4 -f 5566/6534/32008 5521/6405/32009 5596/6404/32010 -f 5596/6404/32011 5551/6533/32012 5566/6534/32013 -# 10671 faces - diff --git a/examples/models/obj_loading/dwarf_diffuse.png b/examples/models/obj_loading/dwarf_diffuse.png deleted file mode 100644 index 15dee61..0000000 Binary files a/examples/models/obj_loading/dwarf_diffuse.png and /dev/null differ diff --git a/examples/models/obj_loading/main.go b/examples/models/obj_loading/main.go index 2517b22..806c726 100644 --- a/examples/models/obj_loading/main.go +++ b/examples/models/obj_loading/main.go @@ -1,52 +1,113 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "path/filepath" + "slices" + "unsafe" + + "git.terah.dev/UnrealXR/raylib-go/raylib" ) +var supportedFileTypes = []string{ + ".obj", + ".gltf", + ".glb", + ".vox", + ".iqm", + ".m3d", +} + func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [models] example - obj model loading") + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - obj model loading") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(3.0, 3.0, 3.0) - camera.Target = raylib.NewVector3(0.0, 1.5, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(50.0, 50.0, 50.0) + camera.Target = rl.NewVector3(0.0, 10.0, 0.0) + camera.Up = rl.NewVector3(0.0, 1.0, 0.0) camera.Fovy = 45.0 + camera.Projection = rl.CameraPerspective - dwarf := raylib.LoadModel("dwarf.obj") // Load OBJ model - texture := raylib.LoadTexture("dwarf_diffuse.png") // Load model texture + obj := rl.LoadModel("castle.obj") // Load OBJ model + texture := rl.LoadTexture("castle_diffuse.png") // Load model texture - dwarf.Material.Maps[raylib.MapDiffuse].Texture = texture // Set dwarf model diffuse texture + rl.SetMaterialTexture(obj.Materials, rl.MapDiffuse, texture) // Set map diffuse texture - position := raylib.NewVector3(0.0, 0.0, 0.0) // Set model position + position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position - raylib.SetTargetFPS(60) + meshes := unsafe.Slice(obj.Meshes, obj.MeshCount) + bounds := rl.GetMeshBoundingBox(meshes[0]) // Set model bounds - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + selected := false - raylib.ClearBackground(raylib.RayWhite) + rl.DisableCursor() + rl.SetTargetFPS(60) - raylib.BeginMode3D(camera) + for !rl.WindowShouldClose() { + // Update + rl.UpdateCamera(&camera, rl.CameraFirstPerson) - raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture + // Load new models/textures on drag&drop + if rl.IsFileDropped() { + droppedFiles := rl.LoadDroppedFiles() - raylib.DrawGrid(10, 1.0) // Draw a grid + 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 - raylib.DrawGizmo(position) // Draw gizmo + meshes = unsafe.Slice(obj.Meshes, obj.MeshCount) + bounds = rl.GetMeshBoundingBox(meshes[0]) - raylib.EndMode3D() + // 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 + } + } - raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray) + rl.UnloadDroppedFiles() // Unload file paths from memory + } - raylib.EndDrawing() + // 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.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 - raylib.UnloadTexture(texture) // Unload texture - raylib.UnloadModel(dwarf) // Unload model - - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/models/orthographic/main.go b/examples/models/orthographic/main.go new file mode 100644 index 0000000..977b180 --- /dev/null +++ b/examples/models/orthographic/main.go @@ -0,0 +1,80 @@ +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 new file mode 100644 index 0000000..e784465 --- /dev/null +++ b/examples/models/rlgl_solar_system/main.go @@ -0,0 +1,155 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..9307f53 --- /dev/null +++ b/examples/models/skybox/main.go @@ -0,0 +1,125 @@ +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 new file mode 100644 index 0000000..25ae075 --- /dev/null +++ b/examples/models/skybox/skybox.fs @@ -0,0 +1,19 @@ +#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 new file mode 100644 index 0000000..36a79b2 Binary files /dev/null and b/examples/models/skybox/skybox.png differ diff --git a/examples/models/skybox/skybox.vs b/examples/models/skybox/skybox.vs new file mode 100644 index 0000000..e43c329 --- /dev/null +++ b/examples/models/skybox/skybox.vs @@ -0,0 +1,24 @@ +#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 new file mode 100644 index 0000000..c921bf5 Binary files /dev/null and b/examples/models/vox_loading/knight.vox differ diff --git a/examples/models/vox_loading/main.go b/examples/models/vox_loading/main.go new file mode 100644 index 0000000..5311042 --- /dev/null +++ b/examples/models/vox_loading/main.go @@ -0,0 +1,82 @@ +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 new file mode 100644 index 0000000..fd77111 Binary files /dev/null and b/examples/models/vox_loading/monument.vox differ diff --git a/examples/models/vox_loading/sword.vox b/examples/models/vox_loading/sword.vox new file mode 100644 index 0000000..05fc482 Binary files /dev/null and b/examples/models/vox_loading/sword.vox differ diff --git a/examples/models/waving_cubes/main.go b/examples/models/waving_cubes/main.go new file mode 100644 index 0000000..5fb874f --- /dev/null +++ b/examples/models/waving_cubes/main.go @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000..4fea2f3 --- /dev/null +++ b/examples/models/yaw_pitch_roll/main.go @@ -0,0 +1,113 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..29b5944 --- /dev/null +++ b/examples/models/yaw_pitch_roll/plane.obj @@ -0,0 +1,10858 @@ +# 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 new file mode 100644 index 0000000..07371c0 Binary files /dev/null and b/examples/models/yaw_pitch_roll/plane_diffuse.png differ diff --git a/examples/others/android/example/README.md b/examples/others/android/example/README.md index b8f06e3..8ab1a50 100644 --- a/examples/others/android/example/README.md +++ b/examples/others/android/example/README.md @@ -3,23 +3,28 @@ 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: +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 ANDROID_NDK_HOME=/opt/android-ndk Add toolchain bin directory to PATH: - export PATH=${ANDROID_NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:${PATH} + export PATH=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${PATH} -Export sysroot path: +Export sysroot and libdirs: - export ANDROID_SYSROOT=${ANDROID_NDK_HOME}/platforms/android-16/arch-arm + export ANDROID_SYSROOT=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot + 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=arm-linux-androideabi-gcc \ - CGO_CFLAGS="-I${ANDROID_SYSROOT}/usr/include --sysroot=${ANDROID_SYSROOT}" \ - CGO_LDFLAGS="-L${ANDROID_SYSROOT}/usr/lib --sysroot=${ANDROID_SYSROOT}" \ + 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}" \ 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 @@ -28,9 +33,17 @@ To build apk export path to Android SDK, point to location where you unpacked ar export ANDROID_HOME=/opt/android-sdk -And build apk with ant: +And build apk: - cd android - ant clean debug + ./gradlew assembleDebug -If everything is successfully built apk can be found in bin/ directory. +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 diff --git a/examples/others/android/example/android/AndroidManifest.xml b/examples/others/android/example/android/AndroidManifest.xml index aa29fab..19b1694 100644 --- a/examples/others/android/example/android/AndroidManifest.xml +++ b/examples/others/android/example/android/AndroidManifest.xml @@ -1,10 +1,9 @@ - + @@ -15,6 +14,7 @@ diff --git a/examples/others/android/example/android/build.gradle b/examples/others/android/example/android/build.gradle new file mode 100644 index 0000000..b819fb4 --- /dev/null +++ b/examples/others/android/example/android/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.application' + +android { + namespace = "com.example.android" + compileSdkVersion 34 + buildToolsVersion '34.0.0' + + defaultConfig { + applicationId "com.example.android" + minSdkVersion 16 + targetSdkVersion 34 + versionCode 1 + versionName '1.0' + } + + buildTypes { + release { + minifyEnabled false + zipAlignEnabled true + } + } + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + + manifest.srcFile 'AndroidManifest.xml' + } + } +} + +dependencies { +} diff --git a/examples/others/android/example/android/build.xml b/examples/others/android/example/android/build.xml deleted file mode 100644 index 3e7a699..0000000 --- a/examples/others/android/example/android/build.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/others/android/example/android/project.properties b/examples/others/android/example/android/project.properties deleted file mode 100644 index 36b004b..0000000 --- a/examples/others/android/example/android/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Project target. -target=android-27 diff --git a/examples/others/android/example/androidcompile.bat b/examples/others/android/example/androidcompile.bat new file mode 100644 index 0000000..e45f342 --- /dev/null +++ b/examples/others/android/example/androidcompile.bat @@ -0,0 +1,68 @@ +@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 new file mode 100644 index 0000000..301e2dd --- /dev/null +++ b/examples/others/android/example/build.gradle @@ -0,0 +1,16 @@ +buildscript { + repositories { + jcenter() + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.2.2' + } +} + +allprojects { + repositories { + jcenter() + google() + } +} diff --git a/examples/others/android/example/gradle/wrapper/gradle-wrapper.jar b/examples/others/android/example/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/examples/others/android/example/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties b/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b05c5cc --- /dev/null +++ b/examples/others/android/example/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Nov 13 02:02:23 CET 2017 +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 diff --git a/examples/others/android/example/gradlew b/examples/others/android/example/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/examples/others/android/example/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/examples/others/android/example/gradlew.bat b/examples/others/android/example/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/examples/others/android/example/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/others/android/example/main.go b/examples/others/android/example/main.go index 9d9bea0..bfcfaa2 100644 --- a/examples/others/android/example/main.go +++ b/examples/others/android/example/main.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) // Game states @@ -16,36 +16,36 @@ const ( ) func init() { - raylib.SetCallbackFunc(main) + rl.SetCallbackFunc(main) } func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagVsyncHint) + rl.SetConfigFlags(rl.FlagVsyncHint) - raylib.InitWindow(screenWidth, screenHeight, "Android example") + rl.InitWindow(screenWidth, screenHeight, "Android example") - raylib.InitAudioDevice() + rl.InitAudioDevice() currentScreen := Logo windowShouldClose := false - texture := raylib.LoadTexture("raylib_logo.png") // Load texture (placed on assets folder) - fx := raylib.LoadSound("coin.wav") // Load WAV audio file (placed on assets folder) - ambient := raylib.LoadMusicStream("ambient.ogg") // Load music + texture := rl.LoadTexture("raylib_logo.png") // Load texture (placed on assets folder) + fx := rl.LoadSound("coin.wav") // Load WAV audio file (placed on assets folder) + ambient := rl.LoadMusicStream("ambient.ogg") // Load music - raylib.PlayMusicStream(ambient) + rl.PlayMusicStream(ambient) framesCounter := 0 // Used to count frames - //raylib.SetTargetFPS(60) + //rl.SetTargetFPS(60) for !windowShouldClose { - raylib.UpdateMusicStream(ambient) + rl.UpdateMusicStream(ambient) - if runtime.GOOS == "android" && raylib.IsKeyDown(raylib.KeyBack) || raylib.WindowShouldClose() { + if runtime.GOOS == "android" && rl.IsKeyDown(rl.KeyBack) || rl.WindowShouldClose() { windowShouldClose = true } @@ -60,64 +60,64 @@ func main() { break case Title: // Press enter to change to GamePlay screen - if raylib.IsGestureDetected(raylib.GestureTap) { - raylib.PlaySound(fx) + if rl.IsGestureDetected(rl.GestureTap) { + rl.PlaySound(fx) currentScreen = GamePlay } break case GamePlay: // Press enter to change to Ending screen - if raylib.IsGestureDetected(raylib.GestureTap) { - raylib.PlaySound(fx) + if rl.IsGestureDetected(rl.GestureTap) { + rl.PlaySound(fx) currentScreen = Ending } break case Ending: // Press enter to return to Title screen - if raylib.IsGestureDetected(raylib.GestureTap) { - raylib.PlaySound(fx) + if rl.IsGestureDetected(rl.GestureTap) { + rl.PlaySound(fx) currentScreen = Title } break } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) switch currentScreen { case Logo: - raylib.DrawText("LOGO SCREEN", 20, 20, 40, raylib.LightGray) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, raylib.White) - raylib.DrawText("WAIT for 4 SECONDS...", 290, 400, 20, raylib.Gray) + rl.DrawText("LOGO SCREEN", 20, 20, 40, rl.LightGray) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, rl.White) + rl.DrawText("WAIT for 4 SECONDS...", 290, 400, 20, rl.Gray) break case Title: - raylib.DrawRectangle(0, 0, screenWidth, screenHeight, raylib.Green) - raylib.DrawText("TITLE SCREEN", 20, 20, 40, raylib.DarkGreen) - raylib.DrawText("TAP SCREEN to JUMP to GAMEPLAY SCREEN", 160, 220, 20, raylib.DarkGreen) + rl.DrawRectangle(0, 0, screenWidth, screenHeight, rl.Green) + rl.DrawText("TITLE SCREEN", 20, 20, 40, rl.DarkGreen) + rl.DrawText("TAP SCREEN to JUMP to GAMEPLAY SCREEN", 160, 220, 20, rl.DarkGreen) break case GamePlay: - raylib.DrawRectangle(0, 0, screenWidth, screenHeight, raylib.Purple) - raylib.DrawText("GAMEPLAY SCREEN", 20, 20, 40, raylib.Maroon) - raylib.DrawText("TAP SCREEN to JUMP to ENDING SCREEN", 170, 220, 20, raylib.Maroon) + rl.DrawRectangle(0, 0, screenWidth, screenHeight, rl.Purple) + rl.DrawText("GAMEPLAY SCREEN", 20, 20, 40, rl.Maroon) + rl.DrawText("TAP SCREEN to JUMP to ENDING SCREEN", 170, 220, 20, rl.Maroon) break case Ending: - raylib.DrawRectangle(0, 0, screenWidth, screenHeight, raylib.Blue) - raylib.DrawText("ENDING SCREEN", 20, 20, 40, raylib.DarkBlue) - raylib.DrawText("TAP SCREEN to RETURN to TITLE SCREEN", 160, 220, 20, raylib.DarkBlue) + rl.DrawRectangle(0, 0, screenWidth, screenHeight, rl.Blue) + rl.DrawText("ENDING SCREEN", 20, 20, 40, rl.DarkBlue) + rl.DrawText("TAP SCREEN to RETURN to TITLE SCREEN", 160, 220, 20, rl.DarkBlue) break default: break } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadSound(fx) // Unload sound data - raylib.UnloadMusicStream(ambient) // Unload music stream data - raylib.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) - raylib.UnloadTexture(texture) // Unload texture data - raylib.CloseWindow() // Close window + rl.UnloadSound(fx) // Unload sound data + rl.UnloadMusicStream(ambient) // Unload music stream data + rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped) + rl.UnloadTexture(texture) // Unload texture data + rl.CloseWindow() // Close window os.Exit(0) } diff --git a/examples/others/android/example/settings.gradle b/examples/others/android/example/settings.gradle new file mode 100644 index 0000000..d69713c --- /dev/null +++ b/examples/others/android/example/settings.gradle @@ -0,0 +1 @@ +include ':android' diff --git a/examples/others/bunnymark/main.go b/examples/others/bunnymark/main.go index 70a12f8..cb86aa2 100644 --- a/examples/others/bunnymark/main.go +++ b/examples/others/bunnymark/main.go @@ -3,41 +3,44 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/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 raylib.Vector2 - Speed raylib.Vector2 - Color raylib.Color + Position rl.Vector2 + Speed rl.Vector2 + Color rl.Color } func main() { - screenWidth := int32(1280) - screenHeight := int32(960) + screenWidth := int32(800) + screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - Bunnymark") + rl.InitWindow(screenWidth, screenHeight, "raylib [others] example - bunnymark") - texture := raylib.LoadTexture("wabbit_alpha.png") + texture := rl.LoadTexture("wabbit_alpha.png") bunnies := make([]*Bunny, 0) - bunniesCount := 0 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { // Create more bunnies for i := 0; i < 100; i++ { b := &Bunny{} - b.Position = raylib.GetMousePosition() - b.Speed.X = float32(raylib.GetRandomValue(250, 500)) / 60.0 - b.Speed.Y = float32(raylib.GetRandomValue(250, 500)-500) / 60.0 + 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) bunnies = append(bunnies, b) - bunniesCount++ } } @@ -46,36 +49,38 @@ func main() { b.Position.X += b.Speed.X b.Position.Y += b.Speed.Y - if (b.Position.X > float32(screenWidth)) || (b.Position.X < 0) { + if ((b.Position.X + float32(texture.Width/2)) > float32(screenWidth)) || ((b.Position.X + float32(texture.Width/2)) < 0) { b.Speed.X *= -1 } - if (b.Position.Y > float32(screenHeight)) || (b.Position.Y < 0) { + if ((b.Position.Y + float32(texture.Height/2)) > float32(screenHeight)) || ((b.Position.Y + float32(texture.Height/2-40)) < 0) { b.Speed.Y *= -1 } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) for _, b := range bunnies { - // 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 - raylib.DrawTexture(texture, int32(b.Position.X), int32(b.Position.Y), raylib.RayWhite) + // 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) } - raylib.DrawRectangle(0, 0, screenWidth, 40, raylib.LightGray) - raylib.DrawText("raylib bunnymark", 10, 10, 20, raylib.DarkGray) - raylib.DrawText(fmt.Sprintf("bunnies: %d", bunniesCount), 400, 10, 20, raylib.Red) + 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) - raylib.DrawFPS(260, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) - raylib.CloseWindow() + rl.UnloadTexture(texture) + rl.CloseWindow() } diff --git a/examples/others/resources/data.h b/examples/others/resources/data.h deleted file mode 100644 index da00b6e..0000000 --- a/examples/others/resources/data.h +++ /dev/null @@ -1,8 +0,0 @@ -#define NUM_RESOURCES 6 - -#define RES_coin.wav 0x00000000 // Embedded as WAVE -#define RES_raylib_logo.gif 0x00000001 // Embedded as IMAGE -#define RES_raylib_logo.jpg 0x00000002 // Embedded as IMAGE -#define RES_raylib_logo.png 0x00000003 // Embedded as IMAGE -#define RES_raylib_logo.tga 0x00000004 // Embedded as IMAGE -#define RES_tanatana.ogg 0x00000005 // Embedded as VORBIS diff --git a/examples/others/resources/data.rres b/examples/others/resources/data.rres deleted file mode 100644 index b0d8519..0000000 Binary files a/examples/others/resources/data.rres and /dev/null differ diff --git a/examples/others/resources/main.go b/examples/others/resources/main.go deleted file mode 100644 index 1a93480..0000000 --- a/examples/others/resources/main.go +++ /dev/null @@ -1,96 +0,0 @@ -package main - -import ( - //"bytes" - - "github.com/gen2brain/raylib-go/raylib" - "github.com/gen2brain/raylib-go/rres" -) - -const numTextures = 4 - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - raylib.InitWindow(screenWidth, screenHeight, "raylib [core] example - resources loading") - - raylib.InitAudioDevice() - - // OpenAsset() will also work on Android (reads files from assets/) - reader, err := raylib.OpenAsset("data.rres") - if err != nil { - raylib.TraceLog(raylib.LogWarning, "[%s] rRES raylib resource file could not be opened: %v", "data.rres", err) - } - - defer reader.Close() - - // bindata - //b := MustAsset("data.rres") - //reader := bytes.NewReader(b) - - res := rres.LoadResource(reader, 0, []byte("passwordpassword")) - wav := raylib.LoadWaveEx(res.Data, int32(res.Param1), int32(res.Param2), int32(res.Param3), int32(res.Param4)) - snd := raylib.LoadSoundFromWave(wav) - raylib.UnloadWave(wav) - - textures := make([]raylib.Texture2D, numTextures) - for i := 0; i < numTextures; i++ { - r := rres.LoadResource(reader, i+1, []byte("passwordpassword")) - image := raylib.LoadImagePro(r.Data, int32(r.Param1), int32(r.Param2), raylib.PixelFormat(r.Param3)) - textures[i] = raylib.LoadTextureFromImage(image) - raylib.UnloadImage(image) - } - - currentTexture := 0 - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - if raylib.IsKeyPressed(raylib.KeySpace) { - raylib.PlaySound(snd) - } - - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - currentTexture = (currentTexture + 1) % numTextures // Cycle between the textures - } - - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.DrawTexture(textures[currentTexture], screenWidth/2-textures[currentTexture].Width/2, screenHeight/2-textures[currentTexture].Height/2, raylib.RayWhite) - - raylib.DrawText("MOUSE LEFT BUTTON to CYCLE TEXTURES", 40, 410, 10, raylib.Gray) - raylib.DrawText("SPACE to PLAY SOUND", 40, 430, 10, raylib.Gray) - - switch currentTexture { - case 0: - raylib.DrawText("GIF", 272, 70, 20, raylib.Gray) - break - case 1: - raylib.DrawText("JPEG", 272, 70, 20, raylib.Gray) - break - case 2: - raylib.DrawText("PNG", 272, 70, 20, raylib.Gray) - break - case 3: - raylib.DrawText("TGA", 272, 70, 20, raylib.Gray) - break - default: - break - } - - raylib.EndDrawing() - } - - raylib.UnloadSound(snd) - - for _, t := range textures { - raylib.UnloadTexture(t) - } - - raylib.CloseAudioDevice() - - raylib.CloseWindow() -} diff --git a/examples/others/rpi/basic_window/README.md b/examples/others/rpi/basic_window/README.md deleted file mode 100644 index f548f3a..0000000 --- a/examples/others/rpi/basic_window/README.md +++ /dev/null @@ -1,18 +0,0 @@ -### 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 deleted file mode 100644 index 7785d1a..0000000 --- a/examples/others/rpi/basic_window/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import "github.com/gen2brain/raylib-go/raylib" - -func main() { - raylib.InitWindow(800, 450, "raylib [rpi] example - basic window") - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.DrawText("Congrats! You created your first window!", 190, 200, 20, raylib.LightGray) - - raylib.EndDrawing() - } - - raylib.CloseWindow() -} diff --git a/examples/others/utils/utils.go b/examples/others/utils/utils.go new file mode 100644 index 0000000..97881fd --- /dev/null +++ b/examples/others/utils/utils.go @@ -0,0 +1,47 @@ +package main + +import ( + "log" + + rl "git.terah.dev/UnrealXR/raylib-go/raylib" +) + +func main() { + rl.SetTraceLogCallback(func(logType int, str string) { + level := "" + switch rl.TraceLogLevel(logType) { + case rl.LogDebug: + level = "Debug" + case rl.LogError: + level = "Error" + case rl.LogInfo: + level = "Info" + case rl.LogTrace: + level = "Trace" + case rl.LogWarning: + level = "Warning" + case rl.LogFatal: + level = "Fatal" + } + if rl.TraceLogLevel(logType) != rl.LogFatal { + log.Printf("%s - %s", level, str) + } else { + log.Fatalf("%s - %s", level, str) + } + }) + + rl.SetConfigFlags(rl.FlagVsyncHint) + rl.InitWindow(800, 450, "raylib [utils] example - SetTraceLogCallback") + + for !rl.WindowShouldClose() { + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawText("The raylib trace log is controlled in GO!", 190, 200, 20, rl.LightGray) + + rl.EndDrawing() + } + + rl.CloseWindow() +} diff --git a/examples/physics/box2d/main.go b/examples/physics/box2d/main.go index a053a4b..d2da34e 100644 --- a/examples/physics/box2d/main.go +++ b/examples/physics/box2d/main.go @@ -4,8 +4,6 @@ import ( "math" "math/rand" - "github.com/gen2brain/raylib-go/raylib" - box2d "github.com/neguse/go-box2d-lite/box2dlite" ) @@ -30,28 +28,28 @@ func (g *Game) Init() { // Update - Update game func (g *Game) Update() { // Keys 1-9 switch demos - switch raylib.GetKeyPressed() { - case raylib.KeyOne: + switch rl.GetKeyPressed() { + case rl.KeyOne: g.Demo1() - case raylib.KeyTwo: + case rl.KeyTwo: g.Demo2() - case raylib.KeyThree: + case rl.KeyThree: g.Demo3() - case raylib.KeyFour: + case rl.KeyFour: g.Demo4() - case raylib.KeyFive: + case rl.KeyFive: g.Demo5() - case raylib.KeySix: + case rl.KeySix: g.Demo6() - case raylib.KeySeven: + case rl.KeySeven: g.Demo7() - case raylib.KeyEight: + case rl.KeyEight: g.Demo8() - case raylib.KeyNine: + case rl.KeyNine: g.Demo9() } - g.TimeStep = float64(raylib.GetFrameTime()) + g.TimeStep = float64(rl.GetFrameTime()) // Physics steps calculations g.World.Step(g.TimeStep) @@ -66,7 +64,7 @@ func (g *Game) Draw() { g.DrawJoint(j) } - raylib.DrawText("Use keys 1-9 to switch current demo", 20, 20, 10, raylib.RayWhite) + rl.DrawText("Use keys 1-9 to switch current demo", 20, 20, 10, rl.RayWhite) } // DrawBody - Draw body @@ -83,10 +81,10 @@ func (g *Game) DrawBody(b *box2d.Body) { v3 := o.Add(S.MulV(x.Add(R.MulV(box2d.Vec2{h.X, h.Y})))) v4 := o.Add(S.MulV(x.Add(R.MulV(box2d.Vec2{-h.X, h.Y})))) - raylib.DrawLine(int32(v1.X), int32(v1.Y), int32(v2.X), int32(v2.Y), raylib.RayWhite) - raylib.DrawLine(int32(v2.X), int32(v2.Y), int32(v3.X), int32(v3.Y), raylib.RayWhite) - raylib.DrawLine(int32(v3.X), int32(v3.Y), int32(v4.X), int32(v4.Y), raylib.RayWhite) - raylib.DrawLine(int32(v4.X), int32(v4.Y), int32(v1.X), int32(v1.Y), raylib.RayWhite) + rl.DrawLine(int32(v1.X), int32(v1.Y), int32(v2.X), int32(v2.Y), rl.RayWhite) + rl.DrawLine(int32(v2.X), int32(v2.Y), int32(v3.X), int32(v3.Y), rl.RayWhite) + rl.DrawLine(int32(v3.X), int32(v3.Y), int32(v4.X), int32(v4.Y), rl.RayWhite) + rl.DrawLine(int32(v4.X), int32(v4.Y), int32(v1.X), int32(v1.Y), rl.RayWhite) } // DrawJoint - Draw joint @@ -111,8 +109,8 @@ func (g *Game) DrawJoint(j *box2d.Joint) { x2 = o.Add(S.MulV(x2)) p2 = o.Add(S.MulV(p2)) - raylib.DrawLine(int32(x1.X), int32(x1.Y), int32(p1.X), int32(p1.Y), raylib.RayWhite) - raylib.DrawLine(int32(x2.X), int32(x2.Y), int32(p2.X), int32(p2.Y), raylib.RayWhite) + rl.DrawLine(int32(x1.X), int32(x1.Y), int32(p1.X), int32(p1.Y), rl.RayWhite) + rl.DrawLine(int32(x2.X), int32(x2.Y), int32(p2.X), int32(p2.Y), rl.RayWhite) } // Demo1 - Single box @@ -489,25 +487,25 @@ func (g *Game) Demo9() { } func main() { - raylib.InitWindow(800, 450, "raylib [physics] example - box2d") + rl.InitWindow(800, 450, "raylib [physics] example - box2d") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) game := NewGame() game.Demo1() - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) game.Update() game.Draw() - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/physics/chipmunk/main.go b/examples/physics/chipmunk/main.go index f477d99..e304182 100644 --- a/examples/physics/chipmunk/main.go +++ b/examples/physics/chipmunk/main.go @@ -1,139 +1,163 @@ package main import ( + "fmt" "math" "math/rand" - "github.com/gen2brain/raylib-go/raylib" - - "github.com/vova616/chipmunk" - "github.com/vova616/chipmunk/vect" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" + "github.com/jakecoffman/cp" ) -const ( - ballRadius = 25 - ballMass = 1 -) - -// Game type -type Game struct { - Space *chipmunk.Space - Balls []*chipmunk.Shape - StaticLines []*chipmunk.Shape - - ticksToNextBall int +var grabbableMaskBit uint = 1 << 31 +var grabFilter = cp.ShapeFilter{ + cp.NO_GROUP, grabbableMaskBit, grabbableMaskBit, } -// NewGame - Start new game -func NewGame() (g Game) { - g.Init() - return +func randUnitCircle() cp.Vector { + v := cp.Vector{X: rand.Float64()*2.0 - 1.0, Y: rand.Float64()*2.0 - 1.0} + if v.LengthSq() < 1.0 { + return v + } + return randUnitCircle() } -// Init - Initialize game -func (g *Game) Init() { - g.createBodies() - - g.ticksToNextBall = 10 +var simpleTerrainVerts = []cp.Vector{ + {350.00, 425.07}, {336.00, 436.55}, {272.00, 435.39}, {258.00, 427.63}, {225.28, 420.00}, {202.82, 396.00}, + {191.81, 388.00}, {189.00, 381.89}, {173.00, 380.39}, {162.59, 368.00}, {150.47, 319.00}, {128.00, 311.55}, + {119.14, 286.00}, {126.84, 263.00}, {120.56, 227.00}, {141.14, 178.00}, {137.52, 162.00}, {146.51, 142.00}, + {156.23, 136.00}, {158.00, 118.27}, {170.00, 100.77}, {208.43, 84.00}, {224.00, 69.65}, {249.30, 68.00}, + {257.00, 54.77}, {363.00, 45.94}, {374.15, 54.00}, {386.00, 69.60}, {413.00, 70.73}, {456.00, 84.89}, + {468.09, 99.00}, {467.09, 123.00}, {464.92, 135.00}, {469.00, 141.03}, {497.00, 148.67}, {513.85, 180.00}, + {509.56, 223.00}, {523.51, 247.00}, {523.00, 277.00}, {497.79, 311.00}, {478.67, 348.00}, {467.90, 360.00}, + {456.76, 382.00}, {432.95, 389.00}, {417.00, 411.32}, {373.00, 433.19}, {361.00, 430.02}, {350.00, 425.07}, } -// Update - Update game -func (g *Game) Update() { - g.ticksToNextBall-- - if g.ticksToNextBall == 0 { - g.ticksToNextBall = rand.Intn(100) + 1 - g.addBall() +// creates a circle with random placement +func addCircle(space *cp.Space, radius float64) { + mass := radius * radius / 25.0 + body := space.AddBody(cp.NewBody(mass, cp.MomentForCircle(mass, 0, radius, cp.Vector{}))) + body.SetPosition(randUnitCircle().Mult(180)) + + shape := space.AddShape(cp.NewCircle(body, radius, cp.Vector{})) + shape.SetElasticity(0) + shape.SetFriction(0.9) +} + +// creates a simple terrain to contain bodies +func simpleTerrain() *cp.Space { + space := cp.NewSpace() + space.Iterations = 10 + space.SetGravity(cp.Vector{0, -100}) + space.SetCollisionSlop(0.5) + + offset := cp.Vector{X: -320, Y: -240} + for i := 0; i < len(simpleTerrainVerts)-1; i++ { + a := simpleTerrainVerts[i] + b := simpleTerrainVerts[i+1] + space.AddShape(cp.NewSegment(space.StaticBody, a.Add(offset), b.Add(offset), 0)) } - // Physics steps calculations - g.step(raylib.GetFrameTime()) -} - -// Draw - Draw game -func (g *Game) Draw() { - for i := range g.StaticLines { - x := g.StaticLines[i].GetAsSegment().A.X - y := g.StaticLines[i].GetAsSegment().A.Y - - x2 := g.StaticLines[i].GetAsSegment().B.X - y2 := g.StaticLines[i].GetAsSegment().B.Y - - raylib.DrawLine(int32(x), int32(y), int32(x2), int32(y2), raylib.DarkBlue) - } - - for _, b := range g.Balls { - pos := b.Body.Position() - raylib.DrawCircleLines(int32(pos.X), int32(pos.Y), float32(ballRadius), raylib.DarkBlue) - } -} - -// createBodies sets up the chipmunk space and static bodies -func (g *Game) createBodies() { - g.Space = chipmunk.NewSpace() - g.Space.Gravity = vect.Vect{0, 900} - - staticBody := chipmunk.NewBodyStatic() - g.StaticLines = []*chipmunk.Shape{ - chipmunk.NewSegment(vect.Vect{250.0, 240.0}, vect.Vect{550.0, 280.0}, 0), - chipmunk.NewSegment(vect.Vect{550.0, 280.0}, vect.Vect{550.0, 180.0}, 0), - } - - for _, segment := range g.StaticLines { - segment.SetElasticity(0.6) - staticBody.AddShape(segment) - } - - g.Space.AddBody(staticBody) -} - -// addBall adds ball to chipmunk space and body -func (g *Game) addBall() { - x := rand.Intn(600-200) + 200 - ball := chipmunk.NewCircle(vect.Vector_Zero, float32(ballRadius)) - ball.SetElasticity(0.95) - - body := chipmunk.NewBody(vect.Float(ballMass), ball.Moment(float32(ballMass))) - body.SetPosition(vect.Vect{vect.Float(x), 0.0}) - body.SetAngle(vect.Float(rand.Float32() * 2 * math.Pi)) - body.AddShape(ball) - - g.Space.AddBody(body) - g.Balls = append(g.Balls, ball) -} - -// step advances the physics engine and cleans up any balls that are off-screen -func (g *Game) step(dt float32) { - g.Space.Step(vect.Float(dt)) - - for i := 0; i < len(g.Balls); i++ { - p := g.Balls[i].Body.Position() - if p.Y < -100 { - g.Space.RemoveBody(g.Balls[i].Body) - g.Balls[i] = nil - g.Balls = append(g.Balls[:i], g.Balls[i+1:]...) - i-- // consider same index again - } - } + return space } func main() { - raylib.InitWindow(800, 450, "raylib [physics] example - chipmunk") + const width, height = 800, 450 + const physicsTickrate = 1.0 / 60.0 - raylib.SetTargetFPS(60) + rl.SetConfigFlags(rl.FlagVsyncHint) + rl.InitWindow(width, height, "raylib [physics] example - chipmunk") - game := NewGame() + offset := rl.Vector2{X: width / 2, Y: height / 2} + // since the example ported from elsewhere, flip the camera 180 and offset to center it + camera := rl.NewCamera2D(offset, rl.Vector2{}, 180, 1) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + space := simpleTerrain() + for i := 0; i < 1000; i++ { + addCircle(space, 5) + } + mouseBody := cp.NewKinematicBody() + var mouse cp.Vector + var mouseJoint *cp.Constraint - raylib.ClearBackground(raylib.RayWhite) + var accumulator, dt float32 + lastTime := rl.GetTime() + for !rl.WindowShouldClose() { + // calculate dt + now := rl.GetTime() + dt = float32(now - lastTime) + lastTime = now - game.Update() + // update the mouse position + mousePos := rl.GetMousePosition() + // alter the mouse coordinates based on the camera position, rotation + mouse.X = float64(mousePos.X-camera.Offset.X) * -1 + mouse.Y = float64(mousePos.Y-camera.Offset.Y) * -1 + // smooth mouse movements to new position + newPoint := mouseBody.Position().Lerp(mouse, 0.25) + mouseBody.SetVelocityVector(newPoint.Sub(mouseBody.Position()).Mult(60.0)) + mouseBody.SetPosition(newPoint) - game.Draw() + // handle grabbing + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + result := space.PointQueryNearest(mouse, 5, grabFilter) + if result.Shape != nil && result.Shape.Body().Mass() < cp.INFINITY { + var nearest cp.Vector + if result.Distance > 0 { + nearest = result.Point + } else { + nearest = mouse + } - raylib.EndDrawing() + // create a new constraint where the mouse is to draw the body towards the mouse + body := result.Shape.Body() + mouseJoint = cp.NewPivotJoint2(mouseBody, body, cp.Vector{}, body.WorldToLocal(nearest)) + mouseJoint.SetMaxForce(50000) + mouseJoint.SetErrorBias(math.Pow(1.0-0.15, 60.0)) + space.AddConstraint(mouseJoint) + } + } else if rl.IsMouseButtonReleased(rl.MouseLeftButton) && mouseJoint != nil { + space.RemoveConstraint(mouseJoint) + mouseJoint = nil + } + + // perform a fixed rate physics tick + accumulator += dt + for accumulator >= physicsTickrate { + space.Step(physicsTickrate) + accumulator -= physicsTickrate + } + + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) + rl.BeginMode2D(camera) + + // this is a generic way to iterate over the shapes in a space, + // to avoid the type switch just keep a pointer to the shapes when they've been created + space.EachShape(func(s *cp.Shape) { + switch s.Class.(type) { + case *cp.Segment: + segment := s.Class.(*cp.Segment) + a := segment.A() + b := segment.B() + rl.DrawLineV(v(a), v(b), rl.Black) + case *cp.Circle: + circle := s.Class.(*cp.Circle) + pos := circle.Body().Position() + rl.DrawCircleV(v(pos), float32(circle.Radius()), rl.Red) + default: + fmt.Println("unexpected shape", s.Class) + } + }) + + rl.EndMode2D() + rl.DrawFPS(0, 0) + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() +} + +func v(v cp.Vector) rl.Vector2 { + return rl.Vector2{X: float32(v.X), Y: float32(v.Y)} } diff --git a/examples/physics/physac/demo/main.go b/examples/physics/physac/demo/main.go index 6ca9bb1..8c64634 100644 --- a/examples/physics/physac/demo/main.go +++ b/examples/physics/physac/demo/main.go @@ -1,71 +1,74 @@ package main import ( - "github.com/gen2brain/raylib-go/physics" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/physics" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) - raylib.InitWindow(screenWidth, screenHeight, "Physac [raylib] - physics demo") + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(screenWidth, screenHeight, "Physac [raylib] - physics demo") // Physac logo drawing position - logoX := screenWidth - raylib.MeasureText("Physac", 30) - 10 + logoX := screenWidth - rl.MeasureText("Physac", 30) - 10 logoY := int32(15) // Initialize physics and default physics bodies physics.Init() // Create floor rectangle physics body - floor := physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)), 500, 100, 10) + floor := physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)), 500, 100, 10) floor.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) // Create obstacle circle physics body - circle := physics.NewBodyCircle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2), 45, 10) + circle := physics.NewBodyCircle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2), 45, 10) circle.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update created physics objects physics.Update() - if raylib.IsKeyPressed(raylib.KeyR) { // Reset physics input + if rl.IsKeyPressed(rl.KeyR) { // Reset physics input physics.Reset() - floor = physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)), 500, 100, 10) + floor = physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)), 500, 100, 10) floor.Enabled = false - circle = physics.NewBodyCircle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2), 45, 10) + circle = physics.NewBodyCircle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)/2), 45, 10) circle.Enabled = false } // Physics body creation inputs - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - physics.NewBodyPolygon(raylib.GetMousePosition(), float32(raylib.GetRandomValue(20, 80)), int(raylib.GetRandomValue(3, 8)), 10) - } else if raylib.IsMouseButtonPressed(raylib.MouseRightButton) { - physics.NewBodyCircle(raylib.GetMousePosition(), float32(raylib.GetRandomValue(10, 45)), 10) + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { + physics.NewBodyPolygon(rl.GetMousePosition(), float32(rl.GetRandomValue(20, 80)), int(rl.GetRandomValue(3, 8)), 10) + } else if rl.IsMouseButtonPressed(rl.MouseRightButton) { + physics.NewBodyCircle(rl.GetMousePosition(), float32(rl.GetRandomValue(10, 45)), 10) } // Destroy falling physics bodies - for _, body := range physics.GetBodies() { + for i := 0; i < physics.GetBodiesCount(); i++ { + body := physics.GetBody(i) if body.Position.Y > float32(screenHeight)*2 { - physics.DestroyBody(body) + body.Destroy() } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) - raylib.DrawFPS(screenWidth-90, screenHeight-30) + rl.DrawFPS(screenWidth-90, screenHeight-30) // Draw created physics bodies - for i, body := range physics.GetBodies() { + for i := 0; i < physics.GetBodiesCount(); i++ { + body := physics.GetBody(i) + vertexCount := physics.GetShapeVerticesCount(i) for j := 0; j < vertexCount; j++ { // Get physics bodies shape vertices to draw lines @@ -79,21 +82,21 @@ func main() { vertexB := body.GetShapeVertex(jj) - raylib.DrawLineV(vertexA, vertexB, raylib.Green) // Draw a line between two vertex positions + rl.DrawLineV(vertexA, vertexB, rl.Green) // Draw a line between two vertex positions } } - raylib.DrawText("Left mouse button to create a polygon", 10, 10, 10, raylib.White) - raylib.DrawText("Right mouse button to create a circle", 10, 25, 10, raylib.White) - raylib.DrawText("Press 'R' to reset example", 10, 40, 10, raylib.White) + rl.DrawText("Left mouse button to create a polygon", 10, 10, 10, rl.White) + rl.DrawText("Right mouse button to create a circle", 10, 25, 10, rl.White) + rl.DrawText("Press 'R' to reset example", 10, 40, 10, rl.White) - raylib.DrawText("Physac", logoX, logoY, 30, raylib.White) - raylib.DrawText("Powered by", logoX+50, logoY-7, 10, raylib.White) + rl.DrawText("Physac", logoX, logoY, 30, rl.White) + rl.DrawText("Powered by", logoX+50, logoY-7, 10, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } physics.Close() // Unitialize physics - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/physics/physac/friction/main.go b/examples/physics/physac/friction/main.go index 5ebe201..b384162 100644 --- a/examples/physics/physac/friction/main.go +++ b/examples/physics/physac/friction/main.go @@ -1,75 +1,75 @@ package main import ( - "github.com/gen2brain/raylib-go/physics" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/physics" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) - raylib.InitWindow(screenWidth, screenHeight, "Physac [raylib] - physics friction") + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(screenWidth, screenHeight, "Physac [raylib] - physics friction") // Physac logo drawing position - logoX := screenWidth - raylib.MeasureText("Physac", 30) - 10 + logoX := screenWidth - rl.MeasureText("Physac", 30) - 10 logoY := int32(15) // Initialize physics and default physics bodies physics.Init() // Create floor rectangle physics body - floor := physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)), float32(screenHeight), 100, 10) + floor := physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)), float32(screenHeight), 100, 10) floor.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) - wall := physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)/2, float32(screenHeight)*0.8), 10, 80, 10) + wall := physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)/2, float32(screenHeight)*0.8), 10, 80, 10) wall.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) // Create left ramp physics body - rectLeft := physics.NewBodyRectangle(raylib.NewVector2(25, float32(screenHeight)-5), 250, 250, 10) + rectLeft := physics.NewBodyRectangle(rl.NewVector2(25, float32(screenHeight)-5), 250, 250, 10) rectLeft.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) - rectLeft.SetRotation(30 * raylib.Deg2rad) + rectLeft.SetRotation(30 * rl.Deg2rad) // Create right ramp physics body - rectRight := physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)-25, float32(screenHeight)-5), 250, 250, 10) + rectRight := physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)-25, float32(screenHeight)-5), 250, 250, 10) rectRight.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) - rectRight.SetRotation(330 * raylib.Deg2rad) + rectRight.SetRotation(330 * rl.Deg2rad) // Create dynamic physics bodies - bodyA := physics.NewBodyRectangle(raylib.NewVector2(35, float32(screenHeight)*0.6), 40, 40, 10) + bodyA := physics.NewBodyRectangle(rl.NewVector2(35, float32(screenHeight)*0.6), 40, 40, 10) bodyA.StaticFriction = 0.1 bodyA.DynamicFriction = 0.1 - bodyA.SetRotation(30 * raylib.Deg2rad) + bodyA.SetRotation(30 * rl.Deg2rad) - bodyB := physics.NewBodyRectangle(raylib.NewVector2(float32(screenWidth)-35, float32(screenHeight)*0.6), 40, 40, 10) + bodyB := physics.NewBodyRectangle(rl.NewVector2(float32(screenWidth)-35, float32(screenHeight)*0.6), 40, 40, 10) bodyB.StaticFriction = 1 bodyB.DynamicFriction = 1 - bodyB.SetRotation(330 * raylib.Deg2rad) + bodyB.SetRotation(330 * rl.Deg2rad) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Physics steps calculations physics.Update() - if raylib.IsKeyPressed(raylib.KeyR) { // Reset physics input + if rl.IsKeyPressed(rl.KeyR) { // Reset physics input // Reset dynamic physics bodies position, velocity and rotation - bodyA.Position = raylib.NewVector2(35, float32(screenHeight)*0.6) - bodyA.Velocity = raylib.NewVector2(0, 0) + bodyA.Position = rl.NewVector2(35, float32(screenHeight)*0.6) + bodyA.Velocity = rl.NewVector2(0, 0) bodyA.AngularVelocity = 0 - bodyA.SetRotation(30 * raylib.Deg2rad) + bodyA.SetRotation(30 * rl.Deg2rad) - bodyB.Position = raylib.NewVector2(float32(screenWidth)-35, float32(screenHeight)*0.6) - bodyB.Velocity = raylib.NewVector2(0, 0) + bodyB.Position = rl.NewVector2(float32(screenWidth)-35, float32(screenHeight)*0.6) + bodyB.Velocity = rl.NewVector2(0, 0) bodyB.AngularVelocity = 0 - bodyB.SetRotation(330 * raylib.Deg2rad) + bodyB.SetRotation(330 * rl.Deg2rad) } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) - raylib.DrawFPS(screenWidth-90, screenHeight-30) + rl.DrawFPS(screenWidth-90, screenHeight-30) // Draw created physics bodies bodiesCount := physics.GetBodiesCount() @@ -89,25 +89,25 @@ func main() { vertexB := body.GetShapeVertex(jj) - raylib.DrawLineV(vertexA, vertexB, raylib.Green) // Draw a line between two vertex positions + rl.DrawLineV(vertexA, vertexB, rl.Green) // Draw a line between two vertex positions } } - raylib.DrawRectangle(0, screenHeight-49, screenWidth, 49, raylib.Black) + rl.DrawRectangle(0, screenHeight-49, screenWidth, 49, rl.Black) - raylib.DrawText("Friction amount", (screenWidth-raylib.MeasureText("Friction amount", 30))/2, 75, 30, raylib.White) - raylib.DrawText("0.1", int32(bodyA.Position.X)-raylib.MeasureText("0.1", 20)/2, int32(bodyA.Position.Y)-7, 20, raylib.White) - raylib.DrawText("1", int32(bodyB.Position.X)-raylib.MeasureText("1", 20)/2, int32(bodyB.Position.Y)-7, 20, raylib.White) + rl.DrawText("Friction amount", (screenWidth-rl.MeasureText("Friction amount", 30))/2, 75, 30, rl.White) + rl.DrawText("0.1", int32(bodyA.Position.X)-rl.MeasureText("0.1", 20)/2, int32(bodyA.Position.Y)-7, 20, rl.White) + rl.DrawText("1", int32(bodyB.Position.X)-rl.MeasureText("1", 20)/2, int32(bodyB.Position.Y)-7, 20, rl.White) - raylib.DrawText("Press 'R' to reset example", 10, 10, 10, raylib.White) + rl.DrawText("Press 'R' to reset example", 10, 10, 10, rl.White) - raylib.DrawText("Physac", logoX, logoY, 30, raylib.White) - raylib.DrawText("Powered by", logoX+50, logoY-7, 10, raylib.White) + rl.DrawText("Physac", logoX, logoY, 30, rl.White) + rl.DrawText("Powered by", logoX+50, logoY-7, 10, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } physics.Close() // Unitialize physics - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/physics/physac/movement/main.go b/examples/physics/physac/movement/main.go index 096ec4c..0962a67 100644 --- a/examples/physics/physac/movement/main.go +++ b/examples/physics/physac/movement/main.go @@ -1,8 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/physics" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/physics" ) const ( @@ -13,22 +12,22 @@ func main() { screenWidth := float32(800) screenHeight := float32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) - raylib.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - physics movement") + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - physics movement") // Physac logo drawing position - logoX := int32(screenWidth) - raylib.MeasureText("Physac", 30) - 10 + logoX := int32(screenWidth) - rl.MeasureText("Physac", 30) - 10 logoY := int32(15) // Initialize physics and default physics bodies physics.Init() // Create floor and walls rectangle physics body - floor := physics.NewBodyRectangle(raylib.NewVector2(screenWidth/2, screenHeight), screenWidth, 100, 10) - platformLeft := physics.NewBodyRectangle(raylib.NewVector2(screenWidth*0.25, screenHeight*0.6), screenWidth*0.25, 10, 10) - platformRight := physics.NewBodyRectangle(raylib.NewVector2(screenWidth*0.75, screenHeight*0.6), screenWidth*0.25, 10, 10) - wallLeft := physics.NewBodyRectangle(raylib.NewVector2(-5, screenHeight/2), 10, screenHeight, 10) - wallRight := physics.NewBodyRectangle(raylib.NewVector2(screenWidth+5, screenHeight/2), 10, screenHeight, 10) + floor := physics.NewBodyRectangle(rl.NewVector2(screenWidth/2, screenHeight), screenWidth, 100, 10) + platformLeft := physics.NewBodyRectangle(rl.NewVector2(screenWidth*0.25, screenHeight*0.6), screenWidth*0.25, 10, 10) + platformRight := physics.NewBodyRectangle(rl.NewVector2(screenWidth*0.75, screenHeight*0.6), screenWidth*0.25, 10, 10) + wallLeft := physics.NewBodyRectangle(rl.NewVector2(-5, screenHeight/2), 10, screenHeight, 10) + wallRight := physics.NewBodyRectangle(rl.NewVector2(screenWidth+5, screenHeight/2), 10, screenHeight, 10) // Disable dynamics to floor and walls physics bodies floor.Enabled = false @@ -38,38 +37,38 @@ func main() { wallRight.Enabled = false // Create movement physics body - body := physics.NewBodyRectangle(raylib.NewVector2(screenWidth/2, screenHeight/2), 50, 50, 1) + body := physics.NewBodyRectangle(rl.NewVector2(screenWidth/2, screenHeight/2), 50, 50, 1) body.FreezeOrient = true // Constrain body rotation to avoid little collision torque amounts - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update created physics objects physics.Update() - if raylib.IsKeyPressed(raylib.KeyR) { // Reset physics input + if rl.IsKeyPressed(rl.KeyR) { // Reset physics input // Reset movement physics body position, velocity and rotation - body.Position = raylib.NewVector2(screenWidth/2, screenHeight/2) - body.Velocity = raylib.NewVector2(0, 0) + body.Position = rl.NewVector2(screenWidth/2, screenHeight/2) + body.Velocity = rl.NewVector2(0, 0) body.SetRotation(0) } // Physics body creation inputs - if raylib.IsKeyDown(raylib.KeyRight) { + if rl.IsKeyDown(rl.KeyRight) { body.Velocity.X = velocity - } else if raylib.IsKeyDown(raylib.KeyLeft) { + } else if rl.IsKeyDown(rl.KeyLeft) { body.Velocity.X = -velocity } - if raylib.IsKeyDown(raylib.KeyUp) && body.IsGrounded { + if rl.IsKeyDown(rl.KeyUp) && body.IsGrounded { body.Velocity.Y = -velocity * 4 } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) - raylib.DrawFPS(int32(screenWidth)-90, int32(screenHeight)-30) + rl.DrawFPS(int32(screenWidth)-90, int32(screenHeight)-30) // Draw created physics bodies for i, body := range physics.GetBodies() { @@ -86,20 +85,20 @@ func main() { vertexB := body.GetShapeVertex(jj) - raylib.DrawLineV(vertexA, vertexB, raylib.Green) // Draw a line between two vertex positions + rl.DrawLineV(vertexA, vertexB, rl.Green) // Draw a line between two vertex positions } } - raylib.DrawText("Use 'ARROWS' to move player", 10, 10, 10, raylib.White) - raylib.DrawText("Press 'R' to reset example", 10, 30, 10, raylib.White) + rl.DrawText("Use 'ARROWS' to move player", 10, 10, 10, rl.White) + rl.DrawText("Press 'R' to reset example", 10, 30, 10, rl.White) - raylib.DrawText("Physac", logoX, logoY, 30, raylib.White) - raylib.DrawText("Powered by", logoX+50, logoY-7, 10, raylib.White) + rl.DrawText("Physac", logoX, logoY, 30, rl.White) + rl.DrawText("Powered by", logoX+50, logoY-7, 10, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } physics.Close() // Unitialize physics - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/physics/physac/restitution/main.go b/examples/physics/physac/restitution/main.go index 90710da..4658e40 100644 --- a/examples/physics/physac/restitution/main.go +++ b/examples/physics/physac/restitution/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/gen2brain/raylib-go/physics" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/physics" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( @@ -13,50 +13,50 @@ func main() { screenWidth := float32(800) screenHeight := float32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) - raylib.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - physics restitution") + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - physics restitution") // Physac logo drawing position - logoX := int32(screenWidth) - raylib.MeasureText("Physac", 30) - 10 + logoX := int32(screenWidth) - rl.MeasureText("Physac", 30) - 10 logoY := int32(15) // Initialize physics and default physics bodies physics.Init() // Create floor rectangle physics body - floor := physics.NewBodyRectangle(raylib.NewVector2(screenWidth/2, screenHeight), screenWidth, 100, 10) + floor := physics.NewBodyRectangle(rl.NewVector2(screenWidth/2, screenHeight), screenWidth, 100, 10) floor.Enabled = false // Disable body state to convert it to static (no dynamics, but collisions) floor.Restitution = 1 // Create circles physics body - circleA := physics.NewBodyCircle(raylib.NewVector2(screenWidth*0.25, screenHeight/2), 30, 10) + circleA := physics.NewBodyCircle(rl.NewVector2(screenWidth*0.25, screenHeight/2), 30, 10) circleA.Restitution = 0 - circleB := physics.NewBodyCircle(raylib.NewVector2(screenWidth*0.5, screenHeight/2), 30, 10) + circleB := physics.NewBodyCircle(rl.NewVector2(screenWidth*0.5, screenHeight/2), 30, 10) circleB.Restitution = 0.5 - circleC := physics.NewBodyCircle(raylib.NewVector2(screenWidth*0.75, screenHeight/2), 30, 10) + circleC := physics.NewBodyCircle(rl.NewVector2(screenWidth*0.75, screenHeight/2), 30, 10) circleC.Restitution = 1 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update created physics objects physics.Update() - if raylib.IsKeyPressed(raylib.KeyR) { // Reset physics input + if rl.IsKeyPressed(rl.KeyR) { // Reset physics input // Reset circles physics bodies position and velocity - circleA.Position = raylib.NewVector2(screenWidth*0.25, screenHeight/2) - circleA.Velocity = raylib.NewVector2(0, 0) - circleB.Position = raylib.NewVector2(screenWidth*0.5, screenHeight/2) - circleB.Velocity = raylib.NewVector2(0, 0) - circleC.Position = raylib.NewVector2(screenWidth*0.75, screenHeight/2) - circleC.Velocity = raylib.NewVector2(0, 0) + circleA.Position = rl.NewVector2(screenWidth*0.25, screenHeight/2) + circleA.Velocity = rl.NewVector2(0, 0) + circleB.Position = rl.NewVector2(screenWidth*0.5, screenHeight/2) + circleB.Velocity = rl.NewVector2(0, 0) + circleC.Position = rl.NewVector2(screenWidth*0.75, screenHeight/2) + circleC.Velocity = rl.NewVector2(0, 0) } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) - raylib.DrawFPS(int32(screenWidth)-90, int32(screenHeight)-30) + rl.DrawFPS(int32(screenWidth)-90, int32(screenHeight)-30) // Draw created physics bodies for i, body := range physics.GetBodies() { @@ -73,24 +73,24 @@ func main() { vertexB := body.GetShapeVertex(jj) - raylib.DrawLineV(vertexA, vertexB, raylib.Green) // Draw a line between two vertex positions + rl.DrawLineV(vertexA, vertexB, rl.Green) // Draw a line between two vertex positions } } - raylib.DrawText("Restitution amount", (int32(screenWidth)-raylib.MeasureText("Restitution amount", 30))/2, 75, 30, raylib.White) - raylib.DrawText("0", int32(circleA.Position.X)-raylib.MeasureText("0", 20)/2, int32(circleA.Position.Y)-7, 20, raylib.White) - raylib.DrawText("0.5", int32(circleB.Position.X)-raylib.MeasureText("0.5", 20)/2, int32(circleB.Position.Y)-7, 20, raylib.White) - raylib.DrawText("1", int32(circleC.Position.X)-raylib.MeasureText("1", 20)/2, int32(circleC.Position.Y)-7, 20, raylib.White) + rl.DrawText("Restitution amount", (int32(screenWidth)-rl.MeasureText("Restitution amount", 30))/2, 75, 30, rl.White) + rl.DrawText("0", int32(circleA.Position.X)-rl.MeasureText("0", 20)/2, int32(circleA.Position.Y)-7, 20, rl.White) + rl.DrawText("0.5", int32(circleB.Position.X)-rl.MeasureText("0.5", 20)/2, int32(circleB.Position.Y)-7, 20, rl.White) + rl.DrawText("1", int32(circleC.Position.X)-rl.MeasureText("1", 20)/2, int32(circleC.Position.Y)-7, 20, rl.White) - raylib.DrawText("Press 'R' to reset example", 10, 10, 10, raylib.White) + rl.DrawText("Press 'R' to reset example", 10, 10, 10, rl.White) - raylib.DrawText("Physac", logoX, logoY, 30, raylib.White) - raylib.DrawText("Powered by", logoX+50, logoY-7, 10, raylib.White) + rl.DrawText("Physac", logoX, logoY, 30, rl.White) + rl.DrawText("Powered by", logoX+50, logoY-7, 10, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } physics.Close() // Unitialize physics - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/physics/physac/shatter/main.go b/examples/physics/physac/shatter/main.go index eddf2cb..264a1a5 100644 --- a/examples/physics/physac/shatter/main.go +++ b/examples/physics/physac/shatter/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/gen2brain/raylib-go/physics" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/physics" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( @@ -13,11 +13,11 @@ func main() { screenWidth := float32(800) screenHeight := float32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) - raylib.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - body shatter") + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(int32(screenWidth), int32(screenHeight), "Physac [raylib] - body shatter") // Physac logo drawing position - logoX := int32(screenWidth) - raylib.MeasureText("Physac", 30) - 10 + logoX := int32(screenWidth) - rl.MeasureText("Physac", 30) - 10 logoY := int32(15) // Initialize physics and default physics bodies @@ -25,30 +25,36 @@ func main() { physics.SetGravity(0, 0) // Create random polygon physics body to shatter - physics.NewBodyPolygon(raylib.NewVector2(screenWidth/2, screenHeight/2), float32(raylib.GetRandomValue(80, 200)), int(raylib.GetRandomValue(3, 8)), 10) + physics.NewBodyPolygon(rl.NewVector2(screenWidth/2, screenHeight/2), float32(rl.GetRandomValue(80, 200)), int(rl.GetRandomValue(3, 8)), 10) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update created physics objects physics.Update() - if raylib.IsKeyPressed(raylib.KeyR) { // Reset physics input + if rl.IsKeyPressed(rl.KeyR) { // Reset physics input physics.Reset() // Create random polygon physics body to shatter - physics.NewBodyPolygon(raylib.NewVector2(screenWidth/2, screenHeight/2), float32(raylib.GetRandomValue(80, 200)), int(raylib.GetRandomValue(3, 8)), 10) + physics.NewBodyPolygon(rl.NewVector2(screenWidth/2, screenHeight/2), float32(rl.GetRandomValue(80, 200)), int(rl.GetRandomValue(3, 8)), 10) } - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - for _, b := range physics.GetBodies() { - b.Shatter(raylib.GetMousePosition(), 10/b.InverseMass) + 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) } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.Black) + rl.ClearBackground(rl.Black) // Draw created physics bodies for i, body := range physics.GetBodies() { @@ -65,19 +71,19 @@ func main() { vertexB := body.GetShapeVertex(jj) - raylib.DrawLineV(vertexA, vertexB, raylib.Green) // Draw a line between two vertex positions + rl.DrawLineV(vertexA, vertexB, rl.Green) // Draw a line between two vertex positions } } - raylib.DrawText("Left mouse button in polygon area to shatter body\nPress 'R' to reset example", 10, 10, 10, raylib.White) + rl.DrawText("Left mouse button in polygon area to shatter body\nPress 'R' to reset example", 10, 10, 10, rl.White) - raylib.DrawText("Physac", logoX, logoY, 30, raylib.White) - raylib.DrawText("Powered by", logoX+50, logoY-7, 10, raylib.White) + rl.DrawText("Physac", logoX, logoY, 30, rl.White) + rl.DrawText("Powered by", logoX+50, logoY-7, 10, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } physics.Close() // Unitialize physics - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shaders/basic_lighting/light.go b/examples/shaders/basic_lighting/light.go new file mode 100644 index 0000000..c398de0 --- /dev/null +++ b/examples/shaders/basic_lighting/light.go @@ -0,0 +1,76 @@ +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 new file mode 100644 index 0000000..58845c8 --- /dev/null +++ b/examples/shaders/basic_lighting/lighting.fs @@ -0,0 +1,82 @@ +#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 new file mode 100644 index 0000000..f8ec45f --- /dev/null +++ b/examples/shaders/basic_lighting/lighting.vs @@ -0,0 +1,32 @@ +#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 new file mode 100644 index 0000000..29c7d13 --- /dev/null +++ b/examples/shaders/basic_lighting/main.go @@ -0,0 +1,103 @@ +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/barracks.obj b/examples/shaders/custom_uniform/barracks.obj new file mode 100644 index 0000000..c462233 --- /dev/null +++ b/examples/shaders/custom_uniform/barracks.obj @@ -0,0 +1,22251 @@ +# (c) 2018 Medieval Assets Pack by Alberto Cano +# Licensed as Creative Commons Attribution-NonCommercial 4.0 + +# +# object barracks +# + +v -8.9771 5.2854 3.5742 +v -8.9771 -0.0497 3.5742 +v -8.9771 -0.0497 7.1735 +v -9.5268 8.3033 7.1735 +v -8.9770 5.2854 10.7728 +v -8.9770 -0.0497 10.7728 +v 4.0289 -0.0497 10.7728 +v 4.0289 5.2854 10.7728 +v 4.0289 5.2854 3.5742 +v 4.0289 -0.0497 3.5742 +v 4.0289 -0.0497 7.1735 +v 4.0289 8.3033 7.1735 +v -9.2884 4.0591 7.1735 +v -9.2884 4.0831 7.5774 +v -9.3565 4.9996 7.5774 +v -9.3565 5.2929 7.1735 +v -9.3222 3.9731 7.8933 +v -9.2295 3.9731 7.8933 +v -9.2295 4.1051 7.8933 +v -9.3222 4.1051 7.8933 +v -9.3902 5.0827 7.7890 +v -9.2975 5.0827 7.7890 +v -9.2975 5.5092 7.1735 +v -9.3902 5.5092 7.1735 +v -9.3222 4.1051 6.4537 +v -9.2295 4.1051 6.4537 +v -9.2295 3.9731 6.4537 +v -9.3222 3.9731 6.4537 +v -9.3222 3.9731 6.5581 +v -9.2295 3.9731 6.5581 +v -9.2295 3.9271 7.1735 +v -9.3222 3.9271 7.1735 +v -9.4239 3.9731 7.7890 +v -9.4239 4.1051 7.7890 +v -9.4239 4.0831 7.5774 +v -9.3902 4.9996 7.5774 +v -9.3902 5.2929 7.1735 +v -9.4239 4.1051 6.5581 +v -9.4239 3.9731 6.5581 +v -9.4239 4.0917 6.7696 +v -9.4239 3.9271 7.1735 +v -9.4239 4.0591 7.1735 +v -9.3565 4.9996 6.7696 +v -9.2884 4.0917 6.7696 +v -9.2975 5.0827 6.5581 +v -9.3902 5.0827 6.5581 +v -9.2295 3.9731 7.7890 +v -9.3222 3.9731 7.7890 +v -9.3902 4.9996 6.7696 +v -9.3222 4.0831 7.5774 +v -9.3222 4.0917 6.7696 +v -9.3222 4.0591 7.1735 +v -9.3222 4.1051 6.5581 +v -9.2295 4.1051 6.5581 +v -9.3222 4.1051 7.7890 +v -9.2295 4.1051 7.7890 +v -9.4239 3.9731 7.8933 +v -9.4239 4.1051 7.8933 +v -9.4239 4.1051 6.4537 +v -9.4239 3.9731 6.4537 +v -8.7325 0.3307 10.8308 +v -8.7325 0.3307 10.9332 +v 3.8501 0.3307 10.9332 +v 3.8501 0.3307 10.8308 +v -8.7325 -0.0497 10.9332 +v 3.8501 -0.0497 10.9332 +v -9.0350 0.3307 3.6224 +v -9.1375 0.3307 3.6224 +v -9.1375 0.3307 10.7569 +v -9.0350 0.3307 10.7569 +v -9.1375 -0.0497 3.6224 +v -9.1375 -0.0497 10.7569 +v 0.8922 7.8216 7.1735 +v 1.0445 5.3128 3.2348 +v -2.5490 5.2357 3.2348 +v -2.8536 7.3417 7.1735 +v -6.5995 7.8216 7.1735 +v -6.1424 5.0816 11.1122 +v -2.5490 5.0816 11.1122 +v 1.0316 4.9710 3.2348 +v -2.5747 4.8939 3.2348 +v -9.7359 5.0816 3.2348 +v -9.7875 4.7398 3.2348 +v -10.3453 8.4824 7.1735 +v -10.3453 8.8242 7.1735 +v -9.7359 5.0816 11.1122 +v -9.7359 4.7398 11.1122 +v 4.6380 5.0816 11.1122 +v 4.6380 4.7398 11.1122 +v 4.6380 8.4824 7.1735 +v 4.6380 8.8242 7.1735 +v 0.8922 7.4798 7.1735 +v -2.8536 6.9999 7.1735 +v -6.1424 5.1587 3.2348 +v 4.6380 5.3898 3.2348 +v 1.0445 5.0816 11.1122 +v -6.1811 4.8169 3.2348 +v 4.6380 5.0480 3.2348 +v 1.0445 4.7398 11.1122 +v -6.1424 4.7398 11.1122 +v -6.5995 7.4798 7.1735 +v -11.3392 8.6350 7.5749 +v -11.3392 8.6350 6.7721 +v -11.3392 7.8323 6.7721 +v -11.3392 7.8323 7.5749 +v -10.3540 7.4474 6.8345 +v -10.3540 8.1255 6.8345 +v -9.3564 7.9260 6.8671 +v -9.3564 7.3131 6.8671 +v -9.3564 7.3131 7.4800 +v -10.3540 7.4474 7.5126 +v -9.3564 7.9260 7.4800 +v -10.3540 8.1255 7.5126 +v 4.0029 0.3307 10.4457 +v 4.1053 0.3307 10.4457 +v 4.1053 0.3307 7.9969 +v 4.0029 0.3307 7.9969 +v 4.1053 -0.0497 10.4457 +v 4.1053 -0.0497 7.9969 +v -10.2556 8.5899 7.7509 +v -10.2924 8.4159 7.7509 +v -9.2822 8.2024 7.7509 +v -9.2454 8.3764 7.7509 +v -9.2064 8.5611 7.2760 +v -9.1696 8.7351 7.2760 +v -10.1798 8.9486 7.2760 +v -10.2166 8.7745 7.2760 +v -9.2039 8.5728 7.1735 +v -9.1672 8.7468 7.1735 +v -10.1773 8.9603 7.1735 +v -10.2141 8.7863 7.1735 +v -9.2822 8.2024 6.5962 +v -10.2924 8.4159 6.5962 +v -10.2556 8.5899 6.5962 +v -9.2454 8.3764 6.5962 +v -9.2064 8.5611 7.0711 +v -9.1696 8.7351 7.0711 +v -10.1798 8.9486 7.0711 +v -10.2166 8.7745 7.0711 +v -9.3847 8.1121 7.7509 +v -8.3745 7.8986 7.7509 +v -8.3377 8.0727 7.7509 +v -9.3479 8.2862 7.7509 +v -8.2619 8.4314 7.2760 +v -9.2721 8.6448 7.2760 +v -8.2987 8.2573 7.2760 +v -8.2594 8.4431 7.1735 +v -9.2696 8.6566 7.1735 +v -8.2962 8.2690 7.1735 +v -8.3377 8.0727 6.5962 +v -8.3745 7.8986 6.5962 +v -9.3847 8.1121 6.5962 +v -9.3479 8.2862 6.5962 +v -8.2619 8.4314 7.0711 +v -9.2721 8.6448 7.0711 +v -8.2987 8.2573 7.0711 +v -8.5801 7.8589 7.7509 +v -7.5630 7.6811 7.7509 +v -7.5324 7.8564 7.7509 +v -8.5495 8.0341 7.7509 +v -7.4693 8.2175 7.2760 +v -8.4864 8.3952 7.2760 +v -7.4999 8.0423 7.2760 +v -7.4672 8.2293 7.1735 +v -8.4843 8.4070 7.1735 +v -7.4978 8.0541 7.1735 +v -7.5324 7.8564 6.5962 +v -7.5630 7.6811 6.5962 +v -8.5801 7.8589 6.5962 +v -8.5495 8.0341 6.5962 +v -7.4693 8.2175 7.0711 +v -8.4864 8.3952 7.0711 +v -7.4999 8.0423 7.0711 +v -7.6752 7.6154 7.7509 +v -6.6503 7.4907 7.7509 +v -6.6288 7.6673 7.7509 +v -7.6538 7.7920 7.7509 +v -6.5846 8.0312 7.2760 +v -7.6095 8.1559 7.2760 +v -6.6061 7.8546 7.2760 +v -6.5831 8.0431 7.1735 +v -7.6081 8.1678 7.1735 +v -6.6046 7.8665 7.1735 +v -6.6288 7.6673 6.5962 +v -6.6503 7.4907 6.5962 +v -7.6752 7.6154 6.5962 +v -7.6538 7.7920 6.5962 +v -6.5846 8.0312 7.0711 +v -7.6095 8.1559 7.0711 +v -6.6061 7.8546 7.0711 +v -6.7532 7.4096 7.7509 +v -5.7283 7.2850 7.7509 +v -5.7068 7.4616 7.7509 +v -6.7318 7.5862 7.7509 +v -5.6626 7.8255 7.2760 +v -6.6875 7.9502 7.2760 +v -5.6840 7.6489 7.2760 +v -5.6611 7.8374 7.1735 +v -6.6861 7.9620 7.1735 +v -5.6826 7.6608 7.1735 +v -5.7068 7.4616 6.5962 +v -5.7283 7.2850 6.5962 +v -6.7532 7.4096 6.5962 +v -6.7318 7.5862 6.5962 +v -5.6626 7.8255 7.0711 +v -6.6875 7.9502 7.0711 +v -5.6840 7.6489 7.0711 +v -5.7708 7.2429 7.7509 +v -4.7459 7.1183 7.7509 +v -4.7244 7.2949 7.7509 +v -5.7493 7.4196 7.7509 +v -4.6801 7.6588 7.2760 +v -5.7051 7.7835 7.2760 +v -4.7016 7.4822 7.2760 +v -4.6787 7.6707 7.1735 +v -5.7036 7.7954 7.1735 +v -4.7002 7.4941 7.1735 +v -4.7244 7.2949 6.5962 +v -4.7459 7.1183 6.5962 +v -5.7708 7.2429 6.5962 +v -5.7493 7.4196 6.5962 +v -4.6801 7.6588 7.0711 +v -5.7051 7.7835 7.0711 +v -4.7016 7.4822 7.0711 +v -5.0398 7.1215 7.7509 +v -4.0088 7.0662 7.7509 +v -3.9993 7.2439 7.7509 +v -5.0303 7.2991 7.7509 +v -3.9796 7.6099 7.2760 +v -5.0107 7.6652 7.2760 +v -3.9892 7.4323 7.2760 +v -3.9790 7.6219 7.1735 +v -5.0100 7.6771 7.1735 +v -3.9885 7.4443 7.1735 +v -3.9993 7.2439 6.5962 +v -4.0088 7.0662 6.5962 +v -5.0398 7.1215 6.5962 +v -5.0303 7.2991 6.5962 +v -3.9796 7.6099 7.0711 +v -5.0107 7.6652 7.0711 +v -3.9892 7.4323 7.0711 +v 1.5002 7.7939 7.7509 +v 2.5251 7.9185 7.7508 +v 2.5036 8.0951 7.7508 +v 1.4787 7.9704 7.7509 +v 1.4344 8.3344 7.2760 +v 1.4559 8.1578 7.2760 +v 2.4594 8.4590 7.2760 +v 2.4809 8.2824 7.2760 +v 1.4545 8.1696 7.1735 +v 1.4330 8.3463 7.1735 +v 2.4579 8.4709 7.1735 +v 2.4794 8.2943 7.1735 +v 2.5036 8.0951 6.5962 +v 2.5251 7.9185 6.5962 +v 1.5002 7.7939 6.5962 +v 1.4787 7.9704 6.5962 +v 1.4559 8.1578 7.0711 +v 1.4344 8.3344 7.0711 +v 2.4594 8.4590 7.0711 +v 2.4809 8.2824 7.0711 +v 0.5583 7.8497 7.7509 +v 0.5643 7.6719 7.7509 +v 1.5962 7.7068 7.7509 +v 1.5902 7.8846 7.7509 +v 1.5778 8.2509 7.2760 +v 0.5459 8.2161 7.2760 +v 0.5519 8.0383 7.2760 +v 1.5774 8.2629 7.1735 +v 0.5455 8.2281 7.1735 +v 0.5515 8.0503 7.1735 +v 1.5962 7.7068 6.5962 +v 0.5643 7.6719 6.5962 +v 0.5583 7.8498 6.5962 +v 1.5902 7.8846 6.5962 +v 0.5459 8.2161 7.0711 +v 1.5778 8.2509 7.0711 +v 0.5519 8.0383 7.0711 +v -0.4450 7.6654 7.7509 +v -0.4298 7.4881 7.7509 +v 0.5989 7.5765 7.7509 +v 0.5837 7.7538 7.7509 +v 0.5523 8.1190 7.2760 +v -0.4764 8.0306 7.2760 +v -0.4612 7.8534 7.2760 +v 0.5513 8.1310 7.1735 +v -0.4774 8.0426 7.1735 +v -0.4622 7.8653 7.1735 +v 0.5989 7.5765 6.5962 +v -0.4298 7.4881 6.5962 +v -0.4450 7.6654 6.5962 +v 0.5837 7.7538 6.5962 +v -0.4764 8.0306 7.0711 +v 0.5523 8.1190 7.0711 +v -0.4612 7.8534 7.0711 +v -1.3304 7.4633 7.7509 +v -1.3090 7.2867 7.7509 +v -0.2840 7.4113 7.7509 +v -0.3055 7.5879 7.7509 +v -0.3498 7.9518 7.2760 +v -1.3747 7.8272 7.2760 +v -1.3532 7.6506 7.2760 +v -0.3512 7.9637 7.1735 +v -1.3761 7.8391 7.1735 +v -1.3547 7.6625 7.1735 +v -0.2840 7.4113 6.5962 +v -1.3090 7.2867 6.5962 +v -1.3304 7.4633 6.5962 +v -0.3055 7.5879 6.5962 +v -1.3747 7.8272 7.0711 +v -0.3498 7.9518 7.0711 +v -1.3532 7.6506 7.0711 +v -2.2525 7.2647 7.7509 +v -2.2310 7.0881 7.7509 +v -1.2061 7.2127 7.7509 +v -1.2275 7.3893 7.7509 +v -1.2718 7.7532 7.2760 +v -2.2967 7.6286 7.2760 +v -2.2752 7.4520 7.2760 +v -1.2732 7.7651 7.1735 +v -2.2982 7.6405 7.1735 +v -2.2767 7.4639 7.1735 +v -1.2061 7.2127 6.5962 +v -2.2310 7.0881 6.5962 +v -2.2525 7.2647 6.5962 +v -1.2275 7.3893 6.5962 +v -2.2967 7.6286 7.0711 +v -1.2718 7.7532 7.0711 +v -2.2752 7.4520 7.0711 +v -3.2517 7.1204 7.7509 +v -3.2457 6.9426 7.7509 +v -2.2138 6.9774 7.7509 +v -2.2198 7.1552 7.7509 +v -2.2321 7.5216 7.2760 +v -3.2640 7.4868 7.2760 +v -3.2580 7.3090 7.2760 +v -2.2325 7.5336 7.1735 +v -3.2644 7.4988 7.1735 +v -3.2584 7.3210 7.1735 +v -2.2138 6.9774 6.5962 +v -3.2457 6.9426 6.5962 +v -3.2517 7.1204 6.5962 +v -2.2198 7.1552 6.5962 +v -3.2640 7.4868 7.0711 +v -2.2321 7.5216 7.0711 +v -3.2580 7.3090 7.0711 +v -4.0502 7.1836 7.7509 +v -4.0717 7.0070 7.7509 +v -3.0468 6.8823 7.7509 +v -3.0253 7.0589 7.7509 +v -2.9810 7.4229 7.2760 +v -4.0060 7.5475 7.2760 +v -4.0275 7.3709 7.2760 +v -2.9796 7.4347 7.1735 +v -4.0045 7.5594 7.1735 +v -4.0260 7.3828 7.1735 +v -3.0468 6.8823 6.5962 +v -4.0717 7.0070 6.5962 +v -4.0502 7.1836 6.5962 +v -3.0253 7.0589 6.5962 +v -4.0060 7.5475 7.0711 +v -2.9810 7.4229 7.0711 +v -4.0275 7.3709 7.0711 +v 2.5178 8.0423 7.7509 +v 3.5427 8.1670 7.7508 +v 3.5213 8.3436 7.7508 +v 2.4963 8.2189 7.7509 +v 2.4521 8.5829 7.2760 +v 2.4735 8.4063 7.2760 +v 3.4770 8.7075 7.2760 +v 3.4985 8.5309 7.2760 +v 2.4721 8.4181 7.1735 +v 2.4506 8.5947 7.1735 +v 3.4756 8.7194 7.1735 +v 3.4970 8.5428 7.1735 +v 3.5213 8.3436 6.5962 +v 3.5427 8.1670 6.5962 +v 2.5178 8.0423 6.5962 +v 2.4963 8.2189 6.5962 +v 2.4735 8.4063 7.0711 +v 2.4521 8.5829 7.0711 +v 3.4770 8.7075 7.0711 +v 3.4985 8.5309 7.0711 +v 3.3558 8.2956 7.7509 +v 4.3808 8.4202 7.7508 +v 4.3593 8.5968 7.7508 +v 3.3344 8.4722 7.7509 +v 3.2901 8.8361 7.2760 +v 3.3116 8.6595 7.2760 +v 4.3150 8.9607 7.2760 +v 4.3365 8.7841 7.2760 +v 3.3101 8.6714 7.1735 +v 3.2887 8.8480 7.1735 +v 4.3136 8.9726 7.1735 +v 4.3351 8.7960 7.1735 +v 4.3593 8.5968 6.5962 +v 4.3808 8.4202 6.5962 +v 3.3558 8.2956 6.5962 +v 3.3344 8.4722 6.5962 +v 3.3116 8.6595 7.0711 +v 3.2901 8.8361 7.0711 +v 4.3150 8.9607 7.0711 +v 4.3365 8.7841 7.0711 +v -6.1361 2.4706 3.5553 +v -6.5400 2.4946 3.5553 +v -6.5299 3.4112 3.5442 +v -6.1261 3.7044 3.5442 +v -6.8559 2.3847 3.5216 +v -6.8559 2.3847 3.6143 +v -6.8559 2.5166 3.6143 +v -6.8559 2.5166 3.5216 +v -6.7415 3.4943 3.5105 +v -6.7415 3.4943 3.6032 +v -6.1261 3.9208 3.6032 +v -6.1261 3.9208 3.5105 +v -5.4163 2.5166 3.5216 +v -5.4163 2.5166 3.6143 +v -5.4163 2.3847 3.6143 +v -5.4163 2.3847 3.5216 +v -5.5207 2.3847 3.5216 +v -5.5207 2.3847 3.6143 +v -6.1361 2.3387 3.6143 +v -6.1361 2.3387 3.5216 +v -6.7515 2.3847 3.4199 +v -6.7515 2.5166 3.4199 +v -6.5400 2.4946 3.4199 +v -6.5300 3.4112 3.5105 +v -6.1261 3.7044 3.5105 +v -5.5207 2.5166 3.4199 +v -5.5207 2.3847 3.4199 +v -5.7322 2.5032 3.4199 +v -6.1361 2.3387 3.4199 +v -6.1361 2.4706 3.4199 +v -5.7222 3.4112 3.5442 +v -5.7322 2.5032 3.5553 +v -5.5106 3.4943 3.6032 +v -5.5106 3.4943 3.5105 +v -6.7516 2.3847 3.6143 +v -6.7515 2.3847 3.5216 +v -5.7222 3.4112 3.5105 +v -6.5400 2.4946 3.5216 +v -5.7322 2.5032 3.5216 +v -6.1361 2.4706 3.5216 +v -5.5207 2.5166 3.5216 +v -5.5207 2.5166 3.6143 +v -6.7515 2.5166 3.5216 +v -6.7516 2.5166 3.6143 +v -6.8559 2.3847 3.4199 +v -6.8559 2.5166 3.4199 +v -5.4164 2.5166 3.4199 +v -5.4164 2.3847 3.4199 +v 1.0773 2.4706 3.5553 +v 0.6735 2.4946 3.5553 +v 0.6835 3.4112 3.5442 +v 1.0874 3.7044 3.5442 +v 0.3576 2.3847 3.5216 +v 0.3576 2.3847 3.6143 +v 0.3576 2.5166 3.6143 +v 0.3576 2.5166 3.5216 +v 0.4719 3.4943 3.5105 +v 0.4720 3.4943 3.6032 +v 1.0874 3.9208 3.6032 +v 1.0874 3.9208 3.5105 +v 1.7971 2.5166 3.5216 +v 1.7971 2.5166 3.6143 +v 1.7971 2.3847 3.6143 +v 1.7971 2.3847 3.5216 +v 1.6928 2.3847 3.5216 +v 1.6928 2.3847 3.6143 +v 1.0774 2.3387 3.6143 +v 1.0774 2.3387 3.5216 +v 0.4619 2.3847 3.4199 +v 0.4619 2.5166 3.4199 +v 0.6735 2.4946 3.4199 +v 0.6835 3.4112 3.5105 +v 1.0874 3.7044 3.5105 +v 1.6928 2.5166 3.4199 +v 1.6928 2.3847 3.4199 +v 1.4812 2.5032 3.4199 +v 1.0774 2.3387 3.4199 +v 1.0774 2.4706 3.4199 +v 1.4913 3.4112 3.5442 +v 1.4812 2.5032 3.5553 +v 1.7028 3.4943 3.6032 +v 1.7028 3.4943 3.5105 +v 0.4619 2.3847 3.6143 +v 0.4619 2.3847 3.5216 +v 1.4913 3.4112 3.5105 +v 0.6735 2.4946 3.5216 +v 1.4812 2.5032 3.5216 +v 1.0774 2.4706 3.5216 +v 1.6928 2.5166 3.5216 +v 1.6928 2.5166 3.6143 +v 0.4619 2.5166 3.5216 +v 0.4619 2.5166 3.6143 +v 0.3576 2.3847 3.4199 +v 0.3576 2.5166 3.4199 +v 1.7971 2.5166 3.4199 +v 1.7971 2.3847 3.4199 +v 11.6321 5.5867 2.0069 +v 11.4477 5.5867 0.6063 +v 10.0464 4.2732 0.3535 +v 10.0937 4.2732 2.8951 +v 12.7529 5.5867 2.8669 +v 12.2931 4.2732 4.5828 +v 14.1534 5.5867 2.6825 +v 15.0416 4.2732 4.2209 +v 15.0134 5.5867 1.5617 +v 16.7293 4.2732 2.0215 +v 14.8290 5.5867 0.1612 +v 16.3674 4.2732 -0.7270 +v 13.7083 5.5867 -0.6988 +v 14.1680 4.2732 -2.4147 +v 12.3077 5.5867 -0.5144 +v 11.7340 4.2732 -1.8459 +v 13.2306 7.5569 1.0840 +v 10.0464 3.6592 0.3535 +v 10.0937 3.6592 2.8951 +v 12.2931 3.6592 4.5828 +v 15.0416 3.6592 4.2209 +v 16.7293 3.6592 2.0215 +v 16.3674 3.6592 -0.7270 +v 14.1680 3.6592 -2.4147 +v 11.7340 3.6592 -1.8459 +v 10.4802 3.0597 -1.8219 +v 11.4558 3.7400 -1.1388 +v 11.8295 3.7400 -1.6724 +v 10.8539 3.0597 -2.3556 +v 9.5046 2.8306 -2.5051 +v 9.8782 2.8306 -3.0387 +v 8.5289 3.2758 -3.1882 +v 8.9026 3.2758 -3.7219 +v 8.5036 2.6341 -3.2059 +v 8.8772 2.6341 -3.7396 +v 10.1065 3.0597 -1.2883 +v 11.0822 3.7400 -0.6051 +v 9.1309 2.8306 -1.9714 +v 8.1552 3.2758 -2.6546 +v 8.1299 2.6341 -2.6723 +v 9.7329 3.0597 -0.7546 +v 10.7085 3.7400 -0.0715 +v 8.7572 2.8306 -1.4378 +v 7.7816 3.2759 -2.1209 +v 7.7562 2.6341 -2.1386 +v 9.3592 3.0597 -0.2210 +v 10.3348 3.7400 0.4622 +v 8.3836 2.8306 -0.9041 +v 7.4079 3.2758 -1.5873 +v 7.3826 2.6341 -1.6050 +v 8.9361 3.5898 -3.5906 +v 9.1688 3.5898 -3.4277 +v 9.2794 3.5898 -3.5855 +v 9.0466 3.5898 -3.7485 +v 9.3343 1.7644 -3.4331 +v 9.3018 -0.0611 -3.5852 +v 9.0386 -0.0611 -3.7695 +v 9.1687 1.7644 -3.5491 +v 8.9136 -0.0611 -3.5910 +v 9.0900 1.7644 -3.4367 +v 9.1768 -0.0611 -3.4067 +v 9.2556 1.7644 -3.3207 +v 7.5317 3.5898 -1.5850 +v 7.4211 3.5898 -1.4271 +v 7.6539 3.5898 -1.2641 +v 7.7644 3.5898 -1.4220 +v 7.8160 1.7644 -1.2646 +v 7.6503 1.7644 -1.3806 +v 7.3987 -0.0611 -1.4275 +v 7.6619 -0.0611 -1.2432 +v 7.7290 1.7644 -1.4930 +v 7.5237 -0.0611 -1.6059 +v 7.8946 1.7644 -1.3770 +v 7.7869 -0.0611 -1.4217 +v 9.8150 0.4345 3.0119 +v 9.5352 -0.0497 3.1542 +v 12.0931 -0.0497 5.1170 +v 12.1868 0.4345 4.8318 +v 10.2280 1.4030 2.8047 +v 12.3265 1.4030 4.4150 +v 10.3166 2.8558 2.7664 +v 12.3597 2.8558 4.3342 +v 10.3166 3.8243 2.7664 +v 12.3597 3.8243 4.3342 +v 10.3166 4.3085 2.7664 +v 12.3597 4.3085 4.3342 +v 10.6981 0.4345 -0.6231 +v 10.6263 -0.0497 -0.6781 +v 10.8311 1.4030 -0.5770 +v 10.8994 2.8558 -0.6186 +v 10.9903 3.8243 -0.7370 +v 11.0670 4.3085 -0.7188 +v 14.2087 0.4345 -2.7141 +v 14.2737 -0.0497 -3.0212 +v 11.0309 -0.0497 -1.2054 +v 11.1026 0.4345 -1.1503 +v 14.1155 1.4030 -2.2615 +v 11.1816 1.4030 -1.0338 +v 14.1014 2.8558 -2.1661 +v 11.1591 2.8558 -0.9570 +v 14.1014 3.8243 -2.1661 +v 11.0683 3.8243 -0.8386 +v 14.1014 4.3085 -2.1661 +v 16.5805 0.4345 -0.8942 +v 16.8317 -0.0497 -1.0584 +v 16.2140 1.4030 -0.6513 +v 16.1445 2.8558 -0.5983 +v 16.1445 3.8243 -0.5983 +v 16.1445 4.3085 -0.5983 +v 16.9707 0.4345 2.0698 +v 17.2525 -0.0497 2.1382 +v 16.5592 1.4030 1.9712 +v 16.4807 2.8558 1.9549 +v 16.4807 3.8243 1.9549 +v 16.4807 4.3085 1.9549 +v 15.1508 0.4345 4.4416 +v 15.2897 -0.0497 4.6961 +v 14.9490 1.4030 4.0697 +v 14.9129 2.8558 3.9980 +v 14.9129 3.8243 3.9980 +v 14.9129 4.3085 3.9980 +v 3.7753 0.3307 3.5742 +v 3.7753 0.3307 3.4718 +v -0.7192 0.3307 3.4718 +v -0.7192 0.3307 3.5742 +v -8.5752 0.3307 3.4718 +v -8.5752 0.3307 3.5742 +v -4.0878 0.3307 3.5742 +v -4.0878 0.3307 3.4718 +v 3.7753 -0.0497 3.4718 +v -0.7192 -0.0497 3.4718 +v -8.5752 -0.0497 3.4718 +v -4.0878 -0.0497 3.4718 +v -0.6234 3.0645 3.1779 +v -4.1805 3.0645 3.1779 +v -4.1805 3.0645 3.5523 +v -0.6234 3.0645 3.5523 +v -4.1805 -0.0767 3.1779 +v -4.1805 -0.0767 3.5523 +v -0.6234 -0.0767 3.5523 +v -0.6234 -0.0767 3.1779 +v -3.7941 2.7616 3.1779 +v -3.7941 -0.0767 3.1779 +v -1.0098 2.7616 3.1779 +v -1.0098 -0.0767 3.1779 +v -3.7941 2.7616 3.5523 +v -3.7941 -0.0767 3.5523 +v -1.0098 2.7616 3.5523 +v -1.0098 -0.0767 3.5523 +v -4.7283 2.7086 0.8535 +v -4.8864 2.0913 1.4841 +v -4.9701 2.9149 1.4841 +v -4.7752 3.3618 0.6425 +v -4.8307 2.0913 1.4841 +v -4.6726 2.7086 0.8535 +v -4.7194 3.3618 2.3257 +v -4.7752 3.3618 2.3257 +v -4.7283 2.7086 2.1147 +v -4.6726 2.7086 2.1147 +v -4.9144 3.7385 1.4841 +v -4.9701 3.7385 1.4841 +v -4.8607 3.9096 2.1147 +v -4.8049 3.9096 2.1147 +v -4.7195 3.3618 0.6425 +v -4.8607 3.9096 0.8535 +v -4.8049 3.9096 0.8535 +v -4.4872 2.7086 2.1147 +v -4.3292 2.0913 1.4841 +v -4.2455 2.9149 1.4841 +v -4.4404 3.3618 2.3257 +v -4.3849 2.0913 1.4841 +v -4.5429 2.7086 2.1147 +v -4.4961 3.3618 0.6425 +v -4.4404 3.3618 0.6425 +v -4.4872 2.7086 0.8535 +v -4.5429 2.7086 0.8535 +v -4.3012 3.7385 1.4841 +v -4.2455 3.7385 1.4841 +v -4.3549 3.9096 0.8535 +v -4.4106 3.9096 0.8535 +v -4.4961 3.3618 2.3257 +v -4.3549 3.9096 2.1147 +v -4.4106 3.9096 2.1147 +v -4.8751 4.9001 3.5979 +v -4.8751 4.6254 2.3101 +v -4.8751 4.2747 2.3101 +v -4.8751 4.5494 3.5979 +v -4.3656 4.9001 3.5979 +v -4.3656 4.6254 2.3101 +v -4.3656 4.5494 3.5979 +v -4.3656 4.2747 2.3101 +v -4.8751 4.5494 1.0224 +v -4.3656 4.5494 1.0224 +v -4.8751 4.9001 1.0224 +v -4.3656 4.9001 1.0224 +v -4.8480 3.6715 1.2143 +v -4.8790 4.8495 1.2143 +v -4.9390 4.8495 1.1797 +v -4.9080 3.6715 1.1797 +v -4.8480 3.6715 1.1450 +v -4.8790 4.8495 1.1450 +v -4.7435 4.8672 1.1450 +v -4.7435 4.9272 1.1797 +v -4.7435 4.8672 1.2143 +v -4.8290 4.8723 1.2143 +v -4.8590 4.9023 1.1797 +v -4.8290 4.8723 1.1450 +v -4.3907 3.5246 1.8443 +v -4.3596 4.7026 1.8443 +v -4.2996 4.7026 1.8790 +v -4.3306 3.5246 1.8790 +v -4.3907 3.5246 1.9136 +v -4.3596 4.7026 1.9136 +v -4.4951 4.7203 1.9136 +v -4.4951 4.7803 1.8790 +v -4.4951 4.7203 1.8443 +v -4.4096 4.7254 1.8443 +v -4.3796 4.7554 1.8790 +v -4.4096 4.7254 1.9136 +v 7.6091 11.2223 7.4926 +v 7.6091 11.2223 3.6675 +v 4.2986 11.2223 3.6675 +v 4.2986 11.2223 7.4926 +v 4.2039 11.6538 3.3840 +v 7.7038 11.6676 3.3840 +v 7.9561 11.4163 3.3840 +v 3.9517 11.4005 3.3840 +v 3.9517 -0.0497 3.3840 +v 7.9561 -0.0497 3.3840 +v 3.9517 11.6528 7.5239 +v 3.9517 11.6528 3.6363 +v 3.9517 11.4005 7.7761 +v 3.9517 -0.0497 7.7761 +v 7.7038 11.6676 7.7761 +v 4.2039 11.6538 7.7761 +v 7.9561 11.4163 7.7761 +v 7.9561 -0.0497 7.7761 +v 7.9561 11.6686 3.6363 +v 7.9561 11.6686 7.5239 +v 4.2384 12.2911 3.6246 +v 4.2975 12.2911 3.6675 +v 7.6079 12.3069 3.6675 +v 7.6647 12.3069 3.6201 +v 7.7027 12.3059 3.3840 +v 4.2028 12.2921 3.3840 +v 4.2411 12.2911 7.5354 +v 4.2975 12.2911 7.4926 +v 3.9505 12.2911 3.6363 +v 3.9505 12.2911 7.5239 +v 7.6834 12.3069 7.5403 +v 7.6079 12.3069 7.4926 +v 4.2028 12.2921 7.7761 +v 7.7027 12.3059 7.7761 +v 7.9549 12.3069 7.5239 +v 7.9549 12.3069 3.6363 +v 4.2986 11.6528 3.6675 +v 7.6091 11.6686 3.6675 +v 7.6091 11.6686 7.4926 +v 4.2986 11.6528 7.4926 +v 5.9539 11.1742 2.7345 +v 8.5221 11.1742 2.7345 +v 8.5221 10.4250 2.7345 +v 5.9539 10.2869 2.7345 +v 3.3856 11.1742 5.5801 +v 3.3856 11.1742 2.7345 +v 3.3856 10.4250 2.7345 +v 3.3856 10.2869 5.5801 +v 5.9539 11.1742 8.4256 +v 3.3856 11.1742 8.4256 +v 3.3856 10.4250 8.4256 +v 5.9539 10.2869 8.4256 +v 8.5221 11.1742 5.5801 +v 8.5221 11.1742 8.4256 +v 8.5221 10.4250 8.4256 +v 8.5221 10.2869 5.5801 +v 7.9561 10.4250 3.3840 +v 7.9561 10.2869 5.5801 +v 7.9561 10.4250 7.7761 +v 5.9539 10.2869 7.7761 +v 3.9516 10.4250 7.7761 +v 3.9516 10.2869 5.5801 +v 3.9516 10.4250 3.3840 +v 5.9539 10.2869 3.3840 +v 7.9561 11.1742 3.3840 +v 5.9539 11.1742 3.3840 +v 3.9516 11.1742 3.3840 +v 3.9516 11.1742 5.5801 +v 3.9516 11.1742 7.7761 +v 5.9539 11.1742 7.7761 +v 7.9561 11.1742 7.7761 +v 7.9561 11.1742 5.5801 +v 5.9538 2.4706 3.3529 +v 5.5500 2.4946 3.3529 +v 5.5600 3.4112 3.3417 +v 5.9639 3.7044 3.3417 +v 5.2341 2.3847 3.3191 +v 5.2341 2.3847 3.4119 +v 5.2341 2.5166 3.4119 +v 5.2341 2.5166 3.3191 +v 5.3484 3.4943 3.3080 +v 5.3484 3.4943 3.4007 +v 5.9638 3.9208 3.4007 +v 5.9638 3.9208 3.3080 +v 6.6736 2.5166 3.3191 +v 6.6736 2.5166 3.4118 +v 6.6736 2.3847 3.4118 +v 6.6736 2.3847 3.3191 +v 6.5693 2.3847 3.3191 +v 6.5693 2.3847 3.4118 +v 5.9538 2.3387 3.4119 +v 5.9538 2.3387 3.3191 +v 5.3384 2.3847 3.2174 +v 5.3384 2.5166 3.2174 +v 5.5500 2.4946 3.2174 +v 5.5600 3.4112 3.3080 +v 5.9638 3.7044 3.3080 +v 6.5693 2.5166 3.2174 +v 6.5693 2.3847 3.2174 +v 6.3577 2.5032 3.2174 +v 5.9538 2.3387 3.2174 +v 5.9538 2.4706 3.2174 +v 6.3678 3.4112 3.3417 +v 6.3577 2.5032 3.3529 +v 6.5793 3.4943 3.4007 +v 6.5793 3.4943 3.3080 +v 5.3384 2.3847 3.4119 +v 5.3384 2.3847 3.3191 +v 6.3677 3.4112 3.3080 +v 5.5500 2.4946 3.3191 +v 6.3577 2.5032 3.3191 +v 5.9538 2.4706 3.3191 +v 6.5693 2.5166 3.3191 +v 6.5693 2.5166 3.4118 +v 5.3384 2.5166 3.3191 +v 5.3384 2.5166 3.4119 +v 5.2341 2.3847 3.2174 +v 5.2341 2.5166 3.2174 +v 6.6736 2.5166 3.2175 +v 6.6736 2.3847 3.2175 +v 7.7029 12.7510 3.3802 +v 7.6649 12.7520 3.6163 +v 7.9551 12.7520 3.6325 +v 3.9507 12.7362 3.6400 +v 4.2385 12.7362 3.6284 +v 4.2029 12.7372 3.3877 +v 4.2029 12.7372 7.7724 +v 4.2412 12.7362 7.5316 +v 3.9507 12.7362 7.5201 +v 7.9552 12.7520 7.5277 +v 7.6836 12.7520 7.5441 +v 7.7029 12.7510 7.7800 +v 5.9539 5.6553 2.7345 +v 8.5221 5.6552 2.7345 +v 8.5221 4.9060 2.7345 +v 5.9539 4.7680 2.7345 +v 3.3856 5.6553 5.5801 +v 3.3856 5.6552 2.7345 +v 3.3856 4.9060 2.7345 +v 3.3856 4.7680 5.5801 +v 5.9539 5.6552 8.4256 +v 3.3856 5.6552 8.4256 +v 3.3856 4.9060 8.4256 +v 5.9539 4.7680 8.4256 +v 8.5221 5.6553 5.5801 +v 8.5221 5.6552 8.4256 +v 8.5221 4.9060 8.4256 +v 8.5221 4.7680 5.5801 +v 7.9561 4.9060 3.3840 +v 7.9561 4.7680 5.5801 +v 7.9561 4.9060 7.7761 +v 5.9539 4.7680 7.7761 +v 3.9516 4.9060 7.7761 +v 3.9516 4.7680 5.5801 +v 3.9516 4.9060 3.3840 +v 5.9539 4.7680 3.3840 +v 7.9561 5.6552 3.3840 +v 5.9539 5.6553 3.3840 +v 3.9516 5.6552 3.3840 +v 3.9516 5.6553 5.5801 +v 3.9516 5.6552 7.7761 +v 5.9539 5.6552 7.7761 +v 7.9561 5.6552 7.7761 +v 7.9561 5.6553 5.5801 +v 3.8492 7.9916 3.3442 +v 4.2778 7.9916 3.2874 +v 4.3820 5.5057 3.0843 +v 3.6056 5.5057 3.0843 +v 4.3820 10.4775 3.0843 +v 3.6056 10.4775 3.0843 +v 3.6056 5.5057 3.8698 +v 3.8492 7.9916 3.7879 +v 3.6056 11.0073 3.8698 +v 4.3820 5.5057 3.8698 +v 4.2778 7.9916 3.7311 +v 4.3820 11.0073 3.8698 +v 8.0585 8.0320 3.3442 +v 8.3022 5.5461 3.0843 +v 7.5257 5.5461 3.0843 +v 7.6299 8.0320 3.2874 +v 7.5257 10.5178 3.0843 +v 8.3022 10.5178 3.0843 +v 8.0585 8.0320 3.7879 +v 8.3022 5.5461 3.8698 +v 8.3022 11.0477 3.8698 +v 7.6299 8.0320 3.7311 +v 7.5257 5.5461 3.8698 +v 7.5257 11.0477 3.8698 +v 8.0585 2.4361 3.3442 +v 8.3022 -0.0497 3.0843 +v 7.5257 -0.0497 3.0843 +v 7.6299 2.4361 3.2874 +v 7.5257 4.9220 3.0843 +v 8.3022 4.9220 3.0843 +v 8.0585 2.4361 3.7879 +v 8.3022 -0.0497 3.8698 +v 8.3022 5.4519 3.8698 +v 7.6299 2.4361 3.7311 +v 7.5257 -0.0497 3.8698 +v 7.5257 5.4519 3.8698 +v 3.8492 8.0460 7.8159 +v 3.6056 5.5601 8.0758 +v 4.3820 5.5601 8.0758 +v 4.2778 8.0460 7.8728 +v 4.3820 10.5319 8.0758 +v 3.6056 10.5319 8.0758 +v 3.8492 8.0460 7.3722 +v 3.6056 5.5601 7.2903 +v 3.6056 11.0617 7.2903 +v 4.2778 8.0460 7.4291 +v 4.3820 5.5601 7.2903 +v 4.3820 11.0617 7.2903 +v -6.1483 5.2854 13.8904 +v -6.1483 -0.0497 13.8904 +v -2.5490 -0.0497 13.8904 +v -2.5490 8.3033 14.4402 +v -6.1483 5.2854 9.5363 +v -6.1483 -0.0497 9.5363 +v 1.0503 5.2854 13.8904 +v 1.0503 -0.0497 13.8904 +v -2.5490 4.0591 14.2018 +v -2.1451 4.0831 14.2018 +v -2.1451 4.9996 14.2698 +v -2.5490 5.2929 14.2698 +v -1.8292 3.9731 14.2355 +v -1.8292 3.9731 14.1428 +v -1.8292 4.1051 14.1428 +v -1.8292 4.1051 14.2355 +v -1.9335 5.0827 14.3036 +v -1.9335 5.0827 14.2108 +v -2.5490 5.5092 14.2108 +v -2.5490 5.5092 14.3036 +v -3.2687 4.1051 14.2355 +v -3.2687 4.1051 14.1428 +v -3.2687 3.9731 14.1428 +v -3.2687 3.9731 14.2355 +v -3.1644 3.9731 14.2355 +v -3.1644 3.9731 14.1428 +v -2.5490 3.9271 14.1428 +v -2.5490 3.9271 14.2355 +v -1.9335 3.9731 14.3372 +v -1.9335 4.1051 14.3372 +v -2.1451 4.0831 14.3372 +v -2.1451 4.9996 14.3036 +v -2.5490 5.2929 14.3036 +v -3.1644 4.1051 14.3372 +v -3.1644 3.9731 14.3372 +v -2.9528 4.0916 14.3372 +v -2.5490 3.9271 14.3372 +v -2.5490 4.0591 14.3372 +v -2.9528 4.9996 14.2698 +v -2.9528 4.0916 14.2018 +v -3.1644 5.0827 14.2108 +v -3.1644 5.0827 14.3036 +v -1.9335 3.9731 14.1428 +v -1.9335 3.9731 14.2355 +v -2.9528 4.9996 14.3036 +v -2.1451 4.0831 14.2355 +v -2.9528 4.0916 14.2355 +v -2.5490 4.0591 14.2355 +v -3.1644 4.1051 14.2355 +v -3.1644 4.1051 14.1428 +v -1.9335 4.1051 14.2355 +v -1.9335 4.1051 14.1428 +v -1.8292 3.9731 14.3372 +v -1.8292 4.1051 14.3372 +v -3.2687 4.1051 14.3372 +v -3.2687 3.9731 14.3372 +v -6.1001 0.3307 13.9484 +v -6.1001 0.3307 14.0508 +v 1.0344 0.3307 14.0508 +v 1.0344 0.3307 13.9484 +v -6.1001 -0.0497 14.0508 +v 1.0344 -0.0497 14.0508 +v -2.5490 7.3417 7.3874 +v -2.5490 7.8216 11.5128 +v 1.3897 5.0816 11.0558 +v 1.3897 5.0816 9.5363 +v -6.4877 5.1674 14.6493 +v -6.4877 4.8256 14.7008 +v -2.5490 8.4824 15.2587 +v -2.5490 8.8242 15.2587 +v 1.3897 5.1674 14.6493 +v 1.3897 4.8256 14.6493 +v -6.4877 5.1587 11.0558 +v -6.4877 5.2357 9.5363 +v -6.4877 4.8169 11.0945 +v 1.3897 4.7398 11.0558 +v -2.5490 7.4798 11.5128 +v -2.1476 8.6350 16.2525 +v -2.9503 8.6350 16.2525 +v -2.9503 7.8323 16.2525 +v -2.1476 7.8323 16.2525 +v -2.8880 7.4474 15.2674 +v -2.8880 8.1255 15.2674 +v -2.8554 7.9260 14.2697 +v -2.8554 7.3131 14.2697 +v -2.2425 7.3131 14.2697 +v -2.2099 7.4474 15.2674 +v -2.2425 7.9260 14.2697 +v -2.2099 8.1255 15.2674 +v -1.9716 8.5899 15.1690 +v -1.9716 8.4159 15.2058 +v -1.9716 8.2024 14.1956 +v -1.9716 8.3764 14.1588 +v -2.4465 8.5610 14.1198 +v -2.4465 8.7351 14.0830 +v -2.4465 8.9486 15.0932 +v -2.4465 8.7745 15.1300 +v -2.5490 8.5728 14.1173 +v -2.5490 8.7468 14.0805 +v -2.5490 8.9603 15.0907 +v -2.5490 8.7863 15.1275 +v -3.1263 8.2024 14.1956 +v -3.1263 8.4159 15.2058 +v -3.1263 8.5899 15.1690 +v -3.1263 8.3764 14.1588 +v -2.6514 8.5610 14.1198 +v -2.6514 8.7351 14.0830 +v -2.6514 8.9486 15.0932 +v -2.6514 8.7745 15.1300 +v -1.9716 8.1121 14.2980 +v -1.9716 7.8986 13.2878 +v -1.9716 8.0727 13.2511 +v -1.9716 8.2862 14.2612 +v -2.4465 8.4313 13.1752 +v -2.4465 8.6448 14.1854 +v -2.4465 8.2573 13.2120 +v -2.5490 8.4431 13.1728 +v -2.5490 8.6566 14.1830 +v -2.5490 8.2690 13.2096 +v -3.1263 8.0727 13.2511 +v -3.1263 7.8986 13.2878 +v -3.1263 8.1121 14.2980 +v -3.1263 8.2862 14.2612 +v -2.6514 8.4313 13.1752 +v -2.6514 8.6448 14.1854 +v -2.6514 8.2573 13.2120 +v -1.9716 7.8588 13.4934 +v -1.9716 7.6811 12.4763 +v -1.9716 7.8564 12.4457 +v -1.9716 8.0341 13.4628 +v -2.4465 8.2175 12.3826 +v -2.4465 8.3952 13.3997 +v -2.4465 8.0423 12.4133 +v -2.5490 8.2293 12.3806 +v -2.5490 8.4070 13.3977 +v -2.5490 8.0541 12.4112 +v -3.1263 7.8564 12.4457 +v -3.1263 7.6811 12.4763 +v -3.1263 7.8588 13.4934 +v -3.1263 8.0341 13.4628 +v -2.6514 8.2175 12.3826 +v -2.6514 8.3952 13.3997 +v -2.6514 8.0423 12.4133 +v -1.9716 7.6154 12.5886 +v -1.9716 7.4907 11.5637 +v -1.9716 7.6673 11.5422 +v -1.9716 7.7920 12.5671 +v -2.4465 8.0312 11.4979 +v -2.4465 8.1559 12.5229 +v -2.4465 7.8546 11.5194 +v -2.5490 8.0431 11.4965 +v -2.5490 8.1678 12.5214 +v -2.5490 7.8665 11.5180 +v -3.1263 7.6673 11.5422 +v -3.1263 7.4907 11.5637 +v -3.1263 7.6154 12.5886 +v -3.1263 7.7920 12.5671 +v -2.6514 8.0312 11.4979 +v -2.6514 8.1559 12.5229 +v -2.6514 7.8546 11.5194 +v -1.9716 7.4096 11.6666 +v -1.9716 7.2850 10.6417 +v -1.9716 7.4616 10.6202 +v -1.9716 7.5862 11.6451 +v -2.4465 7.8255 10.5759 +v -2.4465 7.9502 11.6009 +v -2.4465 7.6489 10.5974 +v -2.5490 7.8374 10.5745 +v -2.5490 7.9620 11.5994 +v -2.5490 7.6608 10.5960 +v -3.1263 7.4616 10.6202 +v -3.1263 7.2850 10.6417 +v -3.1263 7.4096 11.6666 +v -3.1263 7.5862 11.6451 +v -2.6514 7.8255 10.5759 +v -2.6514 7.9502 11.6009 +v -2.6514 7.6489 10.5974 +v -1.9716 7.2429 10.6842 +v -1.9716 7.1183 9.6592 +v -1.9716 7.2949 9.6378 +v -1.9716 7.4195 10.6627 +v -2.4465 7.6588 9.5935 +v -2.4465 7.7835 10.6185 +v -2.4465 7.4822 9.6150 +v -2.5490 7.6707 9.5921 +v -2.5490 7.7954 10.6170 +v -2.5490 7.4941 9.6135 +v -3.1263 7.2949 9.6378 +v -3.1263 7.1183 9.6592 +v -3.1263 7.2429 10.6842 +v -3.1263 7.4195 10.6627 +v -2.6514 7.6588 9.5935 +v -2.6514 7.7835 10.6185 +v -2.6514 7.4822 9.6150 +v -1.9716 7.1215 9.9531 +v -1.9716 7.0662 8.9221 +v -1.9716 7.2439 8.9126 +v -1.9716 7.2991 9.9436 +v -2.4465 7.6099 8.8930 +v -2.4465 7.6652 9.9240 +v -2.4465 7.4323 8.9025 +v -2.5490 7.6219 8.8924 +v -2.5490 7.6771 9.9234 +v -2.5490 7.4443 8.9019 +v -3.1263 7.2439 8.9126 +v -3.1263 7.0662 8.9221 +v -3.1263 7.1215 9.9531 +v -3.1263 7.2991 9.9436 +v -2.6514 7.6099 8.8930 +v -2.6514 7.6652 9.9240 +v -2.6514 7.4323 8.9025 +v -1.9716 7.1204 8.1650 +v -1.9716 6.9426 8.1590 +v -1.9716 6.9774 7.3778 +v -1.9716 7.1552 7.3838 +v -2.4465 7.5216 7.3962 +v -2.4465 7.4868 8.1774 +v -2.4465 7.3090 8.1714 +v -2.5490 7.5336 7.3966 +v -2.5490 7.4987 8.1778 +v -2.5490 7.3210 8.1718 +v -3.1263 6.9774 7.3778 +v -3.1263 6.9426 8.1590 +v -3.1263 7.1204 8.1650 +v -3.1263 7.1552 7.3838 +v -2.6514 7.4868 8.1774 +v -2.6514 7.5216 7.3962 +v -2.6514 7.3090 8.1714 +v -1.9716 7.1836 8.9636 +v -1.9716 7.0070 8.9851 +v -1.9716 6.8823 7.9601 +v -1.9716 7.0589 7.9387 +v -2.4465 7.4228 7.8944 +v -2.4465 7.5475 8.9193 +v -2.4465 7.3709 8.9408 +v -2.5490 7.4347 7.8930 +v -2.5490 7.5594 8.9179 +v -2.5490 7.3828 8.9394 +v -3.1263 6.8823 7.9601 +v -3.1263 7.0070 8.9851 +v -3.1263 7.1836 8.9636 +v -3.1263 7.0589 7.9387 +v -2.6514 7.5475 8.9193 +v -2.6514 7.4228 7.8944 +v -2.6514 7.3709 8.9408 +v -6.2507 0.3307 13.4886 +v -6.1483 0.3307 13.4886 +v -6.1483 0.3307 9.5363 +v -6.2507 0.3307 9.5363 +v -6.2507 -0.0497 13.4886 +v -6.2507 -0.0497 9.5363 +v 1.0503 -0.0497 9.5363 +v 1.0503 5.2854 9.5363 +v 1.1083 0.3307 13.6458 +v 1.2107 0.3307 13.6458 +v 1.2107 0.3307 9.5034 +v 1.1083 0.3307 9.5034 +v 1.2107 -0.0497 13.6458 +v 1.2107 -0.0497 9.5034 +v -6.1581 2.4361 13.9934 +v -6.2150 2.4361 13.5648 +v -6.4181 -0.0497 13.4606 +v -6.4181 -0.0497 14.2371 +v -6.4181 4.9220 13.4606 +v -6.4181 4.9220 14.2371 +v -5.6326 -0.0497 14.2371 +v -5.7144 2.4361 13.9934 +v -5.6326 5.4519 14.2371 +v -5.6326 -0.0497 13.4606 +v -5.7713 2.4361 13.5648 +v -5.6326 5.4519 13.4606 +v 1.0602 2.4361 13.9934 +v 1.3202 -0.0497 14.2371 +v 1.3202 -0.0497 13.4606 +v 1.1171 2.4361 13.5648 +v 1.3202 4.9220 13.4606 +v 1.3202 4.9220 14.2371 +v 0.6165 2.4361 13.9934 +v 0.5347 -0.0497 14.2371 +v 0.5347 5.4519 14.2371 +v 0.6734 2.4361 13.5648 +v 0.5347 -0.0497 13.4606 +v 0.5347 5.4519 13.4606 +v -9.0259 2.4361 10.7880 +v -9.2695 -0.0497 11.0480 +v -8.4931 -0.0497 11.0480 +v -8.5973 2.4361 10.8449 +v -8.4931 4.9220 11.0480 +v -9.2695 4.9220 11.0480 +v -9.0258 2.4361 10.3443 +v -9.2695 -0.0497 10.2625 +v -9.2695 5.4519 10.2625 +v -8.5973 2.4361 10.4012 +v -8.4931 -0.0497 10.2625 +v -8.4931 5.4519 10.2625 +v -9.0258 2.4361 3.5590 +v -8.5973 2.4361 3.5021 +v -8.4931 -0.0497 3.2991 +v -9.2695 -0.0497 3.2991 +v -8.4931 4.9220 3.2991 +v -9.2695 4.9220 3.2991 +v -9.2695 -0.0497 4.0846 +v -9.0258 2.4361 4.0027 +v -9.2695 5.4519 4.0846 +v -8.4931 -0.0497 4.0846 +v -8.5973 2.4361 3.9458 +v -8.4931 5.4519 4.0846 +v 8.0585 2.4361 7.8159 +v 7.6299 2.4361 7.8728 +v 7.5257 -0.0497 8.0758 +v 8.3022 -0.0497 8.0758 +v 7.5257 4.9220 8.0758 +v 8.3022 4.9220 8.0758 +v 8.3022 -0.0497 7.2903 +v 8.0585 2.4361 7.3722 +v 8.3022 5.4519 7.2903 +v 7.5257 -0.0497 7.2903 +v 7.6299 2.4361 7.4291 +v 7.5257 5.4519 7.2903 +v 8.0585 8.0320 7.8159 +v 7.6299 8.0320 7.8728 +v 7.5257 5.5461 8.0758 +v 8.3022 5.5461 8.0758 +v 7.5257 10.5178 8.0758 +v 8.3022 10.5178 8.0758 +v 8.3022 5.5461 7.2903 +v 8.0585 8.0320 7.3722 +v 8.3022 11.0477 7.2903 +v 7.5257 5.5461 7.2903 +v 7.6299 8.0320 7.4291 +v 7.5257 11.0477 7.2903 +v 4.0787 2.4361 10.7880 +v 3.6501 2.4361 10.8449 +v 3.5459 -0.0497 11.0480 +v 4.3223 -0.0497 11.0480 +v 3.5459 4.9220 11.0480 +v 4.3223 4.9220 11.0480 +v 4.3223 -0.0497 10.2625 +v 4.0787 2.4361 10.3443 +v 4.3223 5.4519 10.2625 +v 3.5459 -0.0497 10.2625 +v 3.6501 2.4361 10.4012 +v 3.5459 5.4519 10.2625 +v 3.8492 2.4361 7.8159 +v 3.6056 -0.0497 8.0758 +v 4.3820 -0.0497 8.0758 +v 4.2778 2.4361 7.8728 +v 4.3820 4.9220 8.0758 +v 3.6056 4.9220 8.0758 +v 3.8492 2.4361 7.3722 +v 3.6056 -0.0497 7.2903 +v 3.6056 5.4519 7.2903 +v 4.2778 2.4361 7.4291 +v 4.3820 -0.0497 7.2903 +v 4.3820 5.4519 7.2903 +v 3.8492 2.4361 3.3442 +v 4.2778 2.4361 3.2874 +v 4.3820 -0.0497 3.0843 +v 3.6056 -0.0497 3.0843 +v 4.3820 4.9220 3.0843 +v 3.6056 4.9220 3.0843 +v 3.6056 -0.0497 3.8698 +v 3.8492 2.4361 3.7879 +v 3.6056 5.4519 3.8698 +v 4.3820 -0.0497 3.8698 +v 4.2778 2.4361 3.7311 +v 4.3820 5.4519 3.8698 +v -8.8369 0.3836 2.7871 +v -9.6622 0.0369 2.7377 +v -9.3873 0.7742 2.9950 +v -8.4314 0.9276 2.9011 +v -9.6420 0.0080 2.7808 +v -8.8167 0.3547 2.8302 +v -9.8499 1.1425 3.7831 +v -9.8702 1.1714 3.7400 +v -9.9150 0.5663 3.4157 +v -9.8947 0.5374 3.4588 +v -9.0617 1.4391 3.3601 +v -9.0819 1.4680 3.3170 +v -9.5178 1.6467 3.7829 +v -9.4975 1.6178 3.8260 +v -8.4112 0.8987 2.9442 +v -8.4397 1.4640 3.1543 +v -8.4195 1.4351 3.1975 +v -4.8751 4.0741 3.5979 +v -4.8107 4.3886 2.8279 +v -4.8107 4.3414 2.3081 +v -4.8751 3.7234 3.5979 +v -4.3656 4.0741 3.5979 +v -4.4300 4.3886 2.8279 +v -4.3656 3.7234 3.5979 +v -4.4300 4.3414 2.3081 +v -14.7300 1.7089 -16.2260 +v -14.7320 1.7089 -15.9598 +v -14.5329 1.7089 -15.9532 +v -14.5309 1.7089 -16.2194 +v -14.5148 0.8805 -16.1713 +v -14.5162 0.8805 -15.9847 +v -14.5328 0.0000 -15.9656 +v -14.5309 0.0000 -16.2070 +v -14.6657 0.8805 -16.1763 +v -14.7301 0.0000 -16.2136 +v -14.6672 0.8805 -15.9897 +v -14.7319 0.0000 -15.9722 +v -14.2891 1.8182 -16.1558 +v -14.2903 1.8182 -15.9976 +v -14.0912 1.8182 -15.9911 +v -14.0900 1.8182 -16.1492 +v -14.0714 0.8805 -16.2411 +v -14.0723 0.8805 -16.1212 +v -14.0442 0.0000 -15.9911 +v -14.0430 0.0000 -16.1492 +v -14.2223 0.8805 -16.2461 +v -14.2421 0.0000 -16.1558 +v -14.2233 0.8805 -16.1262 +v -14.2433 0.0000 -15.9976 +v -13.7487 1.4149 -16.2523 +v -13.7496 1.4149 -16.1324 +v -12.8465 1.4917 -15.9514 +v -12.8453 1.4917 -16.1096 +v -14.6517 1.5530 -16.1694 +v -14.6529 1.5530 -16.0112 +v -13.7552 1.2339 -16.2525 +v -12.8538 1.2529 -16.1099 +v -14.6603 1.3141 -16.1697 +v -13.7561 1.2339 -16.1326 +v -12.8550 1.2529 -15.9517 +v -14.6615 1.3141 -16.0115 +v -13.7507 0.5144 -15.9900 +v -13.7516 0.5144 -15.8701 +v -12.8465 0.5972 -15.9514 +v -12.8453 0.5972 -16.1096 +v -14.6517 0.6584 -16.1694 +v -14.6529 0.6584 -16.0112 +v -13.7572 0.3333 -15.9902 +v -12.8538 0.3583 -16.1099 +v -14.6603 0.4196 -16.1697 +v -13.7581 0.3333 -15.8703 +v -12.8550 0.3583 -15.9517 +v -14.6615 0.4196 -16.0115 +v -13.8315 1.8814 -16.1422 +v -13.8327 1.8814 -15.9841 +v -13.6336 1.8814 -15.9775 +v -13.6323 1.8814 -16.1356 +v -13.6560 0.8805 -16.1897 +v -13.6570 0.8805 -16.0698 +v -13.6336 0.0000 -15.9775 +v -13.6323 0.0000 -16.1356 +v -13.8070 0.8805 -16.1947 +v -13.8315 0.0000 -16.1422 +v -13.8079 0.8805 -16.0748 +v -13.8327 0.0000 -15.9841 +v -13.3832 1.6654 -16.1274 +v -13.3844 1.6654 -15.9692 +v -13.1853 1.6654 -15.9626 +v -13.1841 1.6654 -16.1208 +v -13.2307 0.8805 -16.0068 +v -13.2316 0.8805 -15.8869 +v -13.1853 0.0000 -15.9626 +v -13.1841 0.0000 -16.1208 +v -13.3816 0.8805 -16.0118 +v -13.3832 0.0000 -16.1274 +v -13.3825 0.8805 -15.8919 +v -13.3844 0.0000 -15.9692 +v -12.9829 1.7611 -16.1723 +v -12.9850 1.7611 -15.8978 +v -12.7859 1.7611 -15.8912 +v -12.7838 1.7611 -16.1657 +v -12.8386 0.8805 -16.0902 +v -12.8395 0.8805 -15.9703 +v -12.7855 0.0000 -15.9494 +v -12.7842 0.0000 -16.1076 +v -12.9896 0.8805 -16.0952 +v -12.9834 0.0000 -16.1141 +v -12.9905 0.8805 -15.9753 +v -12.9846 0.0000 -15.9560 +v -12.6474 1.7089 -16.2260 +v -12.6494 1.7089 -15.9598 +v -12.4503 1.7089 -15.9532 +v -12.4482 1.7089 -16.2194 +v -12.4322 0.8805 -16.1713 +v -12.4336 0.8805 -15.9847 +v -12.4502 0.0000 -15.9656 +v -12.4483 0.0000 -16.2070 +v -12.5831 0.8805 -16.1763 +v -12.6475 0.0000 -16.2136 +v -12.5846 0.8805 -15.9897 +v -12.6493 0.0000 -15.9722 +v -12.2065 1.8182 -16.1558 +v -12.2077 1.8182 -15.9976 +v -12.0086 1.8182 -15.9911 +v -12.0074 1.8182 -16.1492 +v -11.9888 0.8805 -16.2411 +v -11.9897 0.8805 -16.1212 +v -11.9616 0.0000 -15.9911 +v -11.9604 0.0000 -16.1492 +v -12.1397 0.8805 -16.2461 +v -12.1595 0.0000 -16.1558 +v -12.1407 0.8805 -16.1262 +v -12.1607 0.0000 -15.9976 +v -11.6661 1.4149 -16.2523 +v -11.6670 1.4149 -16.1324 +v -10.7639 1.4917 -15.9514 +v -10.7627 1.4917 -16.1096 +v -12.5691 1.5530 -16.1694 +v -12.5703 1.5530 -16.0112 +v -11.6726 1.2339 -16.2525 +v -10.7712 1.2529 -16.1099 +v -12.5777 1.3141 -16.1697 +v -11.6735 1.2339 -16.1326 +v -10.7724 1.2529 -15.9517 +v -12.5789 1.3141 -16.0115 +v -11.6681 0.5144 -15.9900 +v -11.6690 0.5144 -15.8701 +v -10.7639 0.5972 -15.9514 +v -10.7627 0.5972 -16.1096 +v -12.5691 0.6584 -16.1694 +v -12.5703 0.6584 -16.0112 +v -11.6746 0.3333 -15.9902 +v -10.7712 0.3583 -16.1099 +v -12.5777 0.4196 -16.1697 +v -11.6755 0.3333 -15.8703 +v -10.7724 0.3583 -15.9517 +v -12.5789 0.4196 -16.0115 +v -11.7489 1.8814 -16.1422 +v -11.7501 1.8814 -15.9841 +v -11.5510 1.8814 -15.9775 +v -11.5497 1.8814 -16.1356 +v -11.5734 0.8805 -16.1897 +v -11.5744 0.8805 -16.0698 +v -11.5510 0.0000 -15.9775 +v -11.5497 0.0000 -16.1356 +v -11.7244 0.8805 -16.1947 +v -11.7489 0.0000 -16.1422 +v -11.7253 0.8805 -16.0748 +v -11.7501 0.0000 -15.9841 +v -11.3006 1.6654 -16.1274 +v -11.3018 1.6654 -15.9692 +v -11.1027 1.6654 -15.9626 +v -11.1015 1.6654 -16.1208 +v -11.1481 0.8805 -16.0068 +v -11.1490 0.8805 -15.8869 +v -11.1027 0.0000 -15.9626 +v -11.1015 0.0000 -16.1208 +v -11.2990 0.8805 -16.0118 +v -11.3006 0.0000 -16.1274 +v -11.2999 0.8805 -15.8919 +v -11.3018 0.0000 -15.9692 +v -10.9003 1.7611 -16.1723 +v -10.9024 1.7611 -15.8978 +v -10.7033 1.7611 -15.8912 +v -10.7012 1.7611 -16.1657 +v -10.7560 0.8805 -16.0902 +v -10.7569 0.8805 -15.9703 +v -10.7029 0.0000 -15.9494 +v -10.7016 0.0000 -16.1076 +v -10.9069 0.8805 -16.0952 +v -10.9008 0.0000 -16.1141 +v -10.9079 0.8805 -15.9753 +v -10.9020 0.0000 -15.9560 +v -10.5648 1.7089 -16.2260 +v -10.5668 1.7089 -15.9598 +v -10.3677 1.7089 -15.9532 +v -10.3657 1.7089 -16.2194 +v -10.3496 0.8805 -16.1713 +v -10.3510 0.8805 -15.9847 +v -10.3676 0.0000 -15.9656 +v -10.3657 0.0000 -16.2070 +v -10.5005 0.8805 -16.1763 +v -10.5649 0.0000 -16.2136 +v -10.5020 0.8805 -15.9897 +v -10.5667 0.0000 -15.9722 +v -10.1239 1.8182 -16.1558 +v -10.1251 1.8182 -15.9976 +v -9.9260 1.8182 -15.9911 +v -9.9248 1.8182 -16.1492 +v -9.9062 0.8805 -16.2411 +v -9.9071 0.8805 -16.1212 +v -9.8790 0.0000 -15.9911 +v -9.8778 0.0000 -16.1492 +v -10.0571 0.8805 -16.2461 +v -10.0769 0.0000 -16.1558 +v -10.0581 0.8805 -16.1262 +v -10.0781 0.0000 -15.9976 +v -9.5835 1.4149 -16.2523 +v -9.5844 1.4149 -16.1324 +v -8.6813 1.4917 -15.9514 +v -8.6801 1.4917 -16.1096 +v -10.4865 1.5530 -16.1694 +v -10.4877 1.5530 -16.0112 +v -9.5900 1.2339 -16.2525 +v -8.6886 1.2529 -16.1099 +v -10.4951 1.3141 -16.1697 +v -9.5909 1.2339 -16.1326 +v -8.6898 1.2529 -15.9517 +v -10.4963 1.3141 -16.0115 +v -9.5855 0.5144 -15.9900 +v -9.5864 0.5144 -15.8701 +v -8.6813 0.5972 -15.9514 +v -8.6801 0.5972 -16.1096 +v -10.4865 0.6584 -16.1694 +v -10.4877 0.6584 -16.0112 +v -9.5920 0.3333 -15.9902 +v -8.6886 0.3583 -16.1099 +v -10.4951 0.4196 -16.1697 +v -9.5929 0.3333 -15.8703 +v -8.6898 0.3583 -15.9517 +v -10.4963 0.4196 -16.0115 +v -9.6663 1.8814 -16.1422 +v -9.6675 1.8814 -15.9841 +v -9.4684 1.8814 -15.9775 +v -9.4671 1.8814 -16.1356 +v -9.4908 0.8805 -16.1897 +v -9.4918 0.8805 -16.0698 +v -9.4684 0.0000 -15.9775 +v -9.4671 0.0000 -16.1356 +v -9.6418 0.8805 -16.1947 +v -9.6663 0.0000 -16.1422 +v -9.6427 0.8805 -16.0748 +v -9.6675 0.0000 -15.9841 +v -9.2180 1.6654 -16.1274 +v -9.2192 1.6654 -15.9692 +v -9.0201 1.6654 -15.9626 +v -9.0189 1.6654 -16.1208 +v -9.0655 0.8805 -16.0068 +v -9.0664 0.8805 -15.8869 +v -9.0201 0.0000 -15.9626 +v -9.0189 0.0000 -16.1208 +v -9.2164 0.8805 -16.0118 +v -9.2180 0.0000 -16.1274 +v -9.2173 0.8805 -15.8919 +v -9.2192 0.0000 -15.9692 +v -8.8177 1.7611 -16.1723 +v -8.8198 1.7611 -15.8978 +v -8.6207 1.7611 -15.8912 +v -8.6186 1.7611 -16.1657 +v -8.6734 0.8805 -16.0902 +v -8.6743 0.8805 -15.9703 +v -8.6203 0.0000 -15.9494 +v -8.6190 0.0000 -16.1076 +v -8.8243 0.8805 -16.0952 +v -8.8182 0.0000 -16.1141 +v -8.8253 0.8805 -15.9753 +v -8.8194 0.0000 -15.9560 +v -8.4822 1.7089 -16.2260 +v -8.4842 1.7089 -15.9598 +v -8.2851 1.7089 -15.9532 +v -8.2830 1.7089 -16.2194 +v -8.2670 0.8805 -16.1713 +v -8.2684 0.8805 -15.9847 +v -8.2850 0.0000 -15.9656 +v -8.2831 0.0000 -16.2070 +v -8.4179 0.8805 -16.1763 +v -8.4823 0.0000 -16.2136 +v -8.4194 0.8805 -15.9897 +v -8.4841 0.0000 -15.9722 +v -8.0413 1.8182 -16.1558 +v -8.0425 1.8182 -15.9976 +v -7.8434 1.8182 -15.9911 +v -7.8422 1.8182 -16.1492 +v -7.8236 0.8805 -16.2411 +v -7.8245 0.8805 -16.1212 +v -7.7964 0.0000 -15.9911 +v -7.7952 0.0000 -16.1492 +v -7.9745 0.8805 -16.2461 +v -7.9943 0.0000 -16.1558 +v -7.9755 0.8805 -16.1262 +v -7.9955 0.0000 -15.9976 +v -7.5009 1.4149 -16.2523 +v -7.5018 1.4149 -16.1324 +v -6.5987 1.4917 -15.9514 +v -6.5975 1.4917 -16.1096 +v -8.4039 1.5530 -16.1694 +v -8.4051 1.5530 -16.0112 +v -7.5073 1.2339 -16.2525 +v -6.6060 1.2529 -16.1099 +v -8.4125 1.3141 -16.1697 +v -7.5083 1.2339 -16.1326 +v -6.6072 1.2529 -15.9517 +v -8.4137 1.3141 -16.0115 +v -7.5029 0.5144 -15.9900 +v -7.5038 0.5144 -15.8701 +v -6.5987 0.5972 -15.9514 +v -6.5975 0.5972 -16.1096 +v -8.4039 0.6584 -16.1694 +v -8.4051 0.6584 -16.0112 +v -7.5094 0.3333 -15.9902 +v -6.6060 0.3583 -16.1099 +v -8.4125 0.4196 -16.1697 +v -7.5103 0.3333 -15.8703 +v -6.6072 0.3583 -15.9517 +v -8.4137 0.4196 -16.0115 +v -7.5837 1.8814 -16.1422 +v -7.5849 1.8814 -15.9841 +v -7.3858 1.8814 -15.9775 +v -7.3845 1.8814 -16.1356 +v -7.4082 0.8805 -16.1897 +v -7.4091 0.8805 -16.0698 +v -7.3858 0.0000 -15.9775 +v -7.3845 0.0000 -16.1356 +v -7.5592 0.8805 -16.1947 +v -7.5837 0.0000 -16.1422 +v -7.5601 0.8805 -16.0748 +v -7.5849 0.0000 -15.9841 +v -7.1354 1.6654 -16.1274 +v -7.1366 1.6654 -15.9692 +v -6.9375 1.6654 -15.9626 +v -6.9363 1.6654 -16.1208 +v -6.9829 0.8805 -16.0068 +v -6.9838 0.8805 -15.8869 +v -6.9375 0.0000 -15.9626 +v -6.9363 0.0000 -16.1208 +v -7.1338 0.8805 -16.0118 +v -7.1354 0.0000 -16.1274 +v -7.1347 0.8805 -15.8919 +v -7.1366 0.0000 -15.9692 +v -6.7351 1.7611 -16.1723 +v -6.7372 1.7611 -15.8978 +v -6.5381 1.7611 -15.8912 +v -6.5360 1.7611 -16.1657 +v -6.5908 0.8805 -16.0902 +v -6.5917 0.8805 -15.9703 +v -6.5377 0.0000 -15.9494 +v -6.5364 0.0000 -16.1076 +v -6.7417 0.8805 -16.0952 +v -6.7356 0.0000 -16.1141 +v -6.7427 0.8805 -15.9753 +v -6.7368 0.0000 -15.9560 +v -6.3996 1.7089 -16.2260 +v -6.4016 1.7089 -15.9598 +v -6.2025 1.7089 -15.9532 +v -6.2004 1.7089 -16.2194 +v -6.1844 0.8805 -16.1713 +v -6.1858 0.8805 -15.9847 +v -6.2024 0.0000 -15.9656 +v -6.2005 0.0000 -16.2070 +v -6.3353 0.8805 -16.1763 +v -6.3997 0.0000 -16.2136 +v -6.3368 0.8805 -15.9897 +v -6.4015 0.0000 -15.9722 +v -5.9587 1.8182 -16.1558 +v -5.9599 1.8182 -15.9976 +v -5.7608 1.8182 -15.9911 +v -5.7596 1.8182 -16.1492 +v -5.7410 0.8805 -16.2411 +v -5.7419 0.8805 -16.1212 +v -5.7138 0.0000 -15.9911 +v -5.7126 0.0000 -16.1492 +v -5.8919 0.8805 -16.2461 +v -5.9117 0.0000 -16.1558 +v -5.8929 0.8805 -16.1262 +v -5.9129 0.0000 -15.9976 +v -5.4183 1.4149 -16.2523 +v -5.4192 1.4149 -16.1324 +v -4.5161 1.4917 -15.9514 +v -4.5149 1.4917 -16.1096 +v -6.3213 1.5530 -16.1694 +v -6.3225 1.5530 -16.0112 +v -5.4248 1.2339 -16.2525 +v -4.5234 1.2529 -16.1099 +v -6.3299 1.3141 -16.1697 +v -5.4257 1.2339 -16.1326 +v -4.5246 1.2529 -15.9517 +v -6.3311 1.3141 -16.0115 +v -5.4203 0.5144 -15.9900 +v -5.4212 0.5144 -15.8701 +v -4.5161 0.5972 -15.9514 +v -4.5149 0.5972 -16.1096 +v -6.3213 0.6584 -16.1694 +v -6.3225 0.6584 -16.0112 +v -5.4268 0.3333 -15.9902 +v -4.5234 0.3583 -16.1099 +v -6.3299 0.4196 -16.1697 +v -5.4277 0.3333 -15.8703 +v -4.5246 0.3583 -15.9517 +v -6.3311 0.4196 -16.0115 +v -5.5011 1.8814 -16.1422 +v -5.5023 1.8814 -15.9841 +v -5.3032 1.8814 -15.9775 +v -5.3019 1.8814 -16.1356 +v -5.3256 0.8805 -16.1897 +v -5.3265 0.8805 -16.0698 +v -5.3032 0.0000 -15.9775 +v -5.3019 0.0000 -16.1356 +v -5.4766 0.8805 -16.1947 +v -5.5011 0.0000 -16.1422 +v -5.4775 0.8805 -16.0748 +v -5.5023 0.0000 -15.9841 +v -5.0528 1.6654 -16.1274 +v -5.0540 1.6654 -15.9692 +v -4.8549 1.6654 -15.9626 +v -4.8537 1.6654 -16.1208 +v -4.9003 0.8805 -16.0068 +v -4.9012 0.8805 -15.8869 +v -4.8549 0.0000 -15.9626 +v -4.8537 0.0000 -16.1208 +v -5.0512 0.8805 -16.0118 +v -5.0528 0.0000 -16.1274 +v -5.0521 0.8805 -15.8919 +v -5.0540 0.0000 -15.9692 +v -4.6525 1.7611 -16.1723 +v -4.6546 1.7611 -15.8978 +v -4.4555 1.7611 -15.8912 +v -4.4534 1.7611 -16.1657 +v -4.5082 0.8805 -16.0902 +v -4.5091 0.8805 -15.9703 +v -4.4551 0.0000 -15.9494 +v -4.4538 0.0000 -16.1076 +v -4.6591 0.8805 -16.0952 +v -4.6530 0.0000 -16.1141 +v -4.6601 0.8805 -15.9753 +v -4.6542 0.0000 -15.9560 +v -4.3170 1.7089 -16.2260 +v -4.3190 1.7089 -15.9598 +v -4.1199 1.7089 -15.9532 +v -4.1179 1.7089 -16.2194 +v -4.1018 0.8805 -16.1713 +v -4.1032 0.8805 -15.9847 +v -4.1198 0.0000 -15.9656 +v -4.1179 0.0000 -16.2070 +v -4.2527 0.8805 -16.1763 +v -4.3171 0.0000 -16.2136 +v -4.2542 0.8805 -15.9897 +v -4.3189 0.0000 -15.9722 +v -3.8761 1.8182 -16.1558 +v -3.8773 1.8182 -15.9976 +v -3.6782 1.8182 -15.9911 +v -3.6770 1.8182 -16.1492 +v -3.6584 0.8805 -16.2411 +v -3.6593 0.8805 -16.1212 +v -3.6312 0.0000 -15.9911 +v -3.6300 0.0000 -16.1492 +v -3.8093 0.8805 -16.2461 +v -3.8291 0.0000 -16.1558 +v -3.8103 0.8805 -16.1262 +v -3.8303 0.0000 -15.9976 +v -3.3357 1.4149 -16.2523 +v -3.3366 1.4149 -16.1324 +v -2.4335 1.4917 -15.9514 +v -2.4323 1.4917 -16.1096 +v -4.2387 1.5530 -16.1694 +v -4.2399 1.5530 -16.0112 +v -3.3422 1.2339 -16.2525 +v -2.4408 1.2529 -16.1099 +v -4.2473 1.3141 -16.1697 +v -3.3431 1.2339 -16.1326 +v -2.4420 1.2529 -15.9517 +v -4.2485 1.3141 -16.0115 +v -3.3377 0.5144 -15.9900 +v -3.3386 0.5144 -15.8701 +v -2.4335 0.5972 -15.9514 +v -2.4323 0.5972 -16.1096 +v -4.2387 0.6584 -16.1694 +v -4.2399 0.6584 -16.0112 +v -3.3442 0.3333 -15.9902 +v -2.4408 0.3583 -16.1099 +v -4.2473 0.4196 -16.1697 +v -3.3451 0.3333 -15.8703 +v -2.4420 0.3583 -15.9517 +v -4.2485 0.4196 -16.0115 +v -3.4185 1.8814 -16.1422 +v -3.4197 1.8814 -15.9841 +v -3.2206 1.8814 -15.9775 +v -3.2193 1.8814 -16.1356 +v -3.2430 0.8805 -16.1897 +v -3.2440 0.8805 -16.0698 +v -3.2206 0.0000 -15.9775 +v -3.2193 0.0000 -16.1356 +v -3.3940 0.8805 -16.1947 +v -3.4185 0.0000 -16.1422 +v -3.3949 0.8805 -16.0748 +v -3.4197 0.0000 -15.9841 +v -2.9702 1.6654 -16.1274 +v -2.9714 1.6654 -15.9692 +v -2.7723 1.6654 -15.9626 +v -2.7711 1.6654 -16.1208 +v -2.8177 0.8805 -16.0068 +v -2.8186 0.8805 -15.8869 +v -2.7723 0.0000 -15.9626 +v -2.7711 0.0000 -16.1208 +v -2.9686 0.8805 -16.0118 +v -2.9702 0.0000 -16.1274 +v -2.9695 0.8805 -15.8919 +v -2.9714 0.0000 -15.9692 +v -2.5699 1.7611 -16.1723 +v -2.5720 1.7611 -15.8978 +v -2.3729 1.7611 -15.8912 +v -2.3708 1.7611 -16.1657 +v -2.4256 0.8805 -16.0902 +v -2.4265 0.8805 -15.9703 +v -2.3725 0.0000 -15.9494 +v -2.3712 0.0000 -16.1076 +v -2.5765 0.8805 -16.0952 +v -2.5704 0.0000 -16.1141 +v -2.5775 0.8805 -15.9753 +v -2.5716 0.0000 -15.9560 +v -2.2344 1.7089 -16.2260 +v -2.2364 1.7089 -15.9598 +v -2.0373 1.7089 -15.9532 +v -2.0352 1.7089 -16.2194 +v -2.0192 0.8805 -16.1713 +v -2.0206 0.8805 -15.9847 +v -2.0372 0.0000 -15.9656 +v -2.0353 0.0000 -16.2070 +v -2.1701 0.8805 -16.1763 +v -2.2345 0.0000 -16.2136 +v -2.1716 0.8805 -15.9897 +v -2.2363 0.0000 -15.9722 +v -1.7935 1.8182 -16.1558 +v -1.7947 1.8182 -15.9976 +v -1.5956 1.8182 -15.9911 +v -1.5944 1.8182 -16.1492 +v -1.5758 0.8805 -16.2411 +v -1.5767 0.8805 -16.1212 +v -1.5486 0.0000 -15.9911 +v -1.5474 0.0000 -16.1492 +v -1.7267 0.8805 -16.2461 +v -1.7465 0.0000 -16.1558 +v -1.7277 0.8805 -16.1262 +v -1.7477 0.0000 -15.9976 +v -1.2531 1.4149 -16.2523 +v -1.2540 1.4149 -16.1324 +v -0.3509 1.4917 -15.9514 +v -0.3497 1.4917 -16.1096 +v -2.1561 1.5530 -16.1694 +v -2.1573 1.5530 -16.0112 +v -1.2595 1.2339 -16.2525 +v -0.3582 1.2529 -16.1099 +v -2.1647 1.3141 -16.1697 +v -1.2605 1.2339 -16.1326 +v -0.3594 1.2529 -15.9517 +v -2.1659 1.3141 -16.0115 +v -1.2551 0.5144 -15.9900 +v -1.2560 0.5144 -15.8701 +v -0.3509 0.5972 -15.9514 +v -0.3497 0.5972 -16.1096 +v -2.1561 0.6584 -16.1694 +v -2.1573 0.6584 -16.0112 +v -1.2616 0.3333 -15.9902 +v -0.3582 0.3583 -16.1099 +v -2.1647 0.4196 -16.1697 +v -1.2625 0.3333 -15.8703 +v -0.3594 0.3583 -15.9517 +v -2.1659 0.4196 -16.0115 +v -1.3359 1.8814 -16.1422 +v -1.3371 1.8814 -15.9841 +v -1.1380 1.8814 -15.9775 +v -1.1367 1.8814 -16.1356 +v -1.1604 0.8805 -16.1897 +v -1.1613 0.8805 -16.0698 +v -1.1380 0.0000 -15.9775 +v -1.1367 0.0000 -16.1356 +v -1.3114 0.8805 -16.1947 +v -1.3359 0.0000 -16.1422 +v -1.3123 0.8805 -16.0748 +v -1.3371 0.0000 -15.9841 +v -0.8876 1.6654 -16.1274 +v -0.8888 1.6654 -15.9692 +v -0.6897 1.6654 -15.9626 +v -0.6885 1.6654 -16.1208 +v -0.7351 0.8805 -16.0068 +v -0.7360 0.8805 -15.8869 +v -0.6897 0.0000 -15.9626 +v -0.6885 0.0000 -16.1208 +v -0.8860 0.8805 -16.0118 +v -0.8876 0.0000 -16.1274 +v -0.8869 0.8805 -15.8919 +v -0.8888 0.0000 -15.9692 +v -0.4873 1.7611 -16.1723 +v -0.4894 1.7611 -15.8978 +v -0.2903 1.7611 -15.8912 +v -0.2882 1.7611 -16.1657 +v -0.3430 0.8805 -16.0902 +v -0.3439 0.8805 -15.9703 +v -0.2898 0.0000 -15.9494 +v -0.2886 0.0000 -16.1076 +v -0.4939 0.8805 -16.0952 +v -0.4878 0.0000 -16.1141 +v -0.4949 0.8805 -15.9753 +v -0.4890 0.0000 -15.9560 +v -0.1518 1.7089 -16.2260 +v -0.1538 1.7089 -15.9598 +v 0.0453 1.7089 -15.9532 +v 0.0474 1.7089 -16.2194 +v 0.0634 0.8805 -16.1713 +v 0.0620 0.8805 -15.9847 +v 0.0454 0.0000 -15.9656 +v 0.0473 0.0000 -16.2070 +v -0.0875 0.8805 -16.1763 +v -0.1519 0.0000 -16.2136 +v -0.0890 0.8805 -15.9897 +v -0.1537 0.0000 -15.9722 +v 0.2891 1.8182 -16.1558 +v 0.2879 1.8182 -15.9976 +v 0.4870 1.8182 -15.9911 +v 0.4882 1.8182 -16.1492 +v 0.5068 0.8805 -16.2411 +v 0.5059 0.8805 -16.1212 +v 0.5340 0.0000 -15.9911 +v 0.5352 0.0000 -16.1492 +v 0.3559 0.8805 -16.2461 +v 0.3361 0.0000 -16.1558 +v 0.3549 0.8805 -16.1262 +v 0.3349 0.0000 -15.9976 +v 0.8295 1.4149 -16.2523 +v 0.8286 1.4149 -16.1324 +v 1.7317 1.4917 -15.9514 +v 1.7329 1.4917 -16.1096 +v -0.0735 1.5530 -16.1694 +v -0.0747 1.5530 -16.0112 +v 0.8230 1.2339 -16.2525 +v 1.7244 1.2529 -16.1099 +v -0.0821 1.3141 -16.1697 +v 0.8221 1.2339 -16.1326 +v 1.7232 1.2529 -15.9517 +v -0.0833 1.3141 -16.0115 +v 0.8275 0.5144 -15.9900 +v 0.8266 0.5144 -15.8701 +v 1.7317 0.5972 -15.9514 +v 1.7329 0.5972 -16.1096 +v -0.0735 0.6584 -16.1694 +v -0.0747 0.6584 -16.0112 +v 0.8210 0.3333 -15.9902 +v 1.7244 0.3583 -16.1099 +v -0.0821 0.4196 -16.1697 +v 0.8201 0.3333 -15.8703 +v 1.7232 0.3583 -15.9517 +v -0.0833 0.4196 -16.0115 +v 0.7467 1.8814 -16.1422 +v 0.7455 1.8814 -15.9841 +v 0.9446 1.8814 -15.9775 +v 0.9459 1.8814 -16.1356 +v 0.9222 0.8805 -16.1897 +v 0.9213 0.8805 -16.0698 +v 0.9446 0.0000 -15.9775 +v 0.9459 0.0000 -16.1356 +v 0.7712 0.8805 -16.1947 +v 0.7467 0.0000 -16.1422 +v 0.7703 0.8805 -16.0748 +v 0.7455 0.0000 -15.9841 +v 1.1950 1.6654 -16.1274 +v 1.1938 1.6654 -15.9692 +v 1.3929 1.6654 -15.9626 +v 1.3941 1.6654 -16.1208 +v 1.3475 0.8805 -16.0068 +v 1.3466 0.8805 -15.8869 +v 1.3929 0.0000 -15.9626 +v 1.3941 0.0000 -16.1208 +v 1.1966 0.8805 -16.0118 +v 1.1950 0.0000 -16.1274 +v 1.1957 0.8805 -15.8919 +v 1.1938 0.0000 -15.9692 +v 1.5953 1.7611 -16.1723 +v 1.5932 1.7611 -15.8978 +v 1.7923 1.7611 -15.8912 +v 1.7944 1.7611 -16.1657 +v 1.7396 0.8805 -16.0902 +v 1.7387 0.8805 -15.9703 +v 1.7928 0.0000 -15.9494 +v 1.7940 0.0000 -16.1076 +v 1.5887 0.8805 -16.0952 +v 1.5948 0.0000 -16.1141 +v 1.5877 0.8805 -15.9753 +v 1.5936 0.0000 -15.9560 +v 1.9308 1.7089 -16.2260 +v 1.9288 1.7089 -15.9598 +v 2.1279 1.7089 -15.9532 +v 2.1299 1.7089 -16.2194 +v 2.1460 0.8805 -16.1713 +v 2.1446 0.8805 -15.9847 +v 2.1280 0.0000 -15.9656 +v 2.1299 0.0000 -16.2070 +v 1.9951 0.8805 -16.1763 +v 1.9307 0.0000 -16.2136 +v 1.9936 0.8805 -15.9897 +v 1.9289 0.0000 -15.9722 +v 2.3717 1.8182 -16.1558 +v 2.3705 1.8182 -15.9976 +v 2.5696 1.8182 -15.9911 +v 2.5708 1.8182 -16.1492 +v 2.5894 0.8805 -16.2411 +v 2.5885 0.8805 -16.1212 +v 2.6166 0.0000 -15.9911 +v 2.6178 0.0000 -16.1492 +v 2.4385 0.8805 -16.2461 +v 2.4187 0.0000 -16.1558 +v 2.4375 0.8805 -16.1262 +v 2.4175 0.0000 -15.9976 +v 2.9121 1.4149 -16.2523 +v 2.9112 1.4149 -16.1324 +v 3.8143 1.4917 -15.9514 +v 3.8155 1.4917 -16.1096 +v 2.0091 1.5530 -16.1694 +v 2.0079 1.5530 -16.0112 +v 2.9056 1.2339 -16.2525 +v 3.8070 1.2529 -16.1099 +v 2.0005 1.3141 -16.1697 +v 2.9047 1.2339 -16.1326 +v 3.8058 1.2529 -15.9517 +v 1.9993 1.3141 -16.0115 +v 2.9101 0.5144 -15.9900 +v 2.9092 0.5144 -15.8701 +v 3.8143 0.5972 -15.9514 +v 3.8155 0.5972 -16.1096 +v 2.0091 0.6584 -16.1694 +v 2.0079 0.6584 -16.0112 +v 2.9036 0.3333 -15.9902 +v 3.8070 0.3583 -16.1099 +v 2.0005 0.4196 -16.1697 +v 2.9027 0.3333 -15.8703 +v 3.8058 0.3583 -15.9517 +v 1.9993 0.4196 -16.0115 +v 2.8293 1.8814 -16.1422 +v 2.8281 1.8814 -15.9841 +v 3.0272 1.8814 -15.9775 +v 3.0285 1.8814 -16.1356 +v 3.0048 0.8805 -16.1897 +v 3.0038 0.8805 -16.0698 +v 3.0272 0.0000 -15.9775 +v 3.0285 0.0000 -16.1356 +v 2.8538 0.8805 -16.1947 +v 2.8293 0.0000 -16.1422 +v 2.8529 0.8805 -16.0748 +v 2.8281 0.0000 -15.9841 +v 3.2776 1.6654 -16.1274 +v 3.2764 1.6654 -15.9692 +v 3.4755 1.6654 -15.9626 +v 3.4767 1.6654 -16.1208 +v 3.4301 0.8805 -16.0068 +v 3.4292 0.8805 -15.8869 +v 3.4755 0.0000 -15.9626 +v 3.4767 0.0000 -16.1208 +v 3.2792 0.8805 -16.0118 +v 3.2776 0.0000 -16.1274 +v 3.2783 0.8805 -15.8919 +v 3.2764 0.0000 -15.9692 +v 3.6779 1.7611 -16.1723 +v 3.6758 1.7611 -15.8978 +v 3.8749 1.7611 -15.8912 +v 3.8770 1.7611 -16.1657 +v 3.8222 0.8805 -16.0902 +v 3.8213 0.8805 -15.9703 +v 3.8753 0.0000 -15.9494 +v 3.8766 0.0000 -16.1076 +v 3.6713 0.8805 -16.0952 +v 3.6774 0.0000 -16.1141 +v 3.6703 0.8805 -15.9753 +v 3.6762 0.0000 -15.9560 +v 4.0134 1.7089 -16.2260 +v 4.0114 1.7089 -15.9598 +v 4.2105 1.7089 -15.9532 +v 4.2126 1.7089 -16.2194 +v 4.2286 0.8805 -16.1713 +v 4.2272 0.8805 -15.9847 +v 4.2106 0.0000 -15.9656 +v 4.2125 0.0000 -16.2070 +v 4.0777 0.8805 -16.1763 +v 4.0133 0.0000 -16.2136 +v 4.0762 0.8805 -15.9897 +v 4.0115 0.0000 -15.9722 +v 4.4543 1.8182 -16.1558 +v 4.4531 1.8182 -15.9976 +v 4.6522 1.8182 -15.9911 +v 4.6534 1.8182 -16.1492 +v 4.6720 0.8805 -16.2411 +v 4.6711 0.8805 -16.1212 +v 4.6992 0.0000 -15.9911 +v 4.7004 0.0000 -16.1492 +v 4.5211 0.8805 -16.2461 +v 4.5013 0.0000 -16.1558 +v 4.5201 0.8805 -16.1262 +v 4.5001 0.0000 -15.9976 +v 4.9947 1.4149 -16.2523 +v 4.9938 1.4149 -16.1324 +v 5.8969 1.4917 -15.9514 +v 5.8981 1.4917 -16.1096 +v 4.0917 1.5530 -16.1694 +v 4.0905 1.5530 -16.0112 +v 4.9883 1.2339 -16.2525 +v 5.8896 1.2529 -16.1099 +v 4.0831 1.3141 -16.1697 +v 4.9873 1.2339 -16.1326 +v 5.8884 1.2529 -15.9517 +v 4.0819 1.3141 -16.0115 +v 4.9927 0.5144 -15.9900 +v 4.9918 0.5144 -15.8701 +v 5.8969 0.5972 -15.9514 +v 5.8981 0.5972 -16.1096 +v 4.0917 0.6584 -16.1694 +v 4.0905 0.6584 -16.0112 +v 4.9863 0.3333 -15.9902 +v 5.8896 0.3583 -16.1099 +v 4.0831 0.4196 -16.1697 +v 4.9853 0.3333 -15.8703 +v 5.8884 0.3583 -15.9517 +v 4.0819 0.4196 -16.0115 +v 4.9119 1.8814 -16.1422 +v 4.9107 1.8814 -15.9841 +v 5.1098 1.8814 -15.9775 +v 5.1111 1.8814 -16.1356 +v 5.0874 0.8805 -16.1897 +v 5.0865 0.8805 -16.0698 +v 5.1098 0.0000 -15.9775 +v 5.1111 0.0000 -16.1356 +v 4.9364 0.8805 -16.1947 +v 4.9119 0.0000 -16.1422 +v 4.9355 0.8805 -16.0748 +v 4.9107 0.0000 -15.9841 +v 5.3602 1.6654 -16.1274 +v 5.3590 1.6654 -15.9692 +v 5.5581 1.6654 -15.9626 +v 5.5593 1.6654 -16.1208 +v 5.5127 0.8805 -16.0068 +v 5.5118 0.8805 -15.8869 +v 5.5581 0.0000 -15.9626 +v 5.5593 0.0000 -16.1208 +v 5.3618 0.8805 -16.0118 +v 5.3602 0.0000 -16.1274 +v 5.3609 0.8805 -15.8919 +v 5.3590 0.0000 -15.9692 +v 5.7605 1.7611 -16.1723 +v 5.7584 1.7611 -15.8978 +v 5.9575 1.7611 -15.8912 +v 5.9596 1.7611 -16.1657 +v 5.9048 0.8805 -16.0902 +v 5.9039 0.8805 -15.9703 +v 5.9580 0.0000 -15.9494 +v 5.9592 0.0000 -16.1076 +v 5.7539 0.8805 -16.0952 +v 5.7600 0.0000 -16.1141 +v 5.7529 0.8805 -15.9753 +v 5.7588 0.0000 -15.9560 +v 6.0960 1.7089 -16.2260 +v 6.0940 1.7089 -15.9598 +v 6.2931 1.7089 -15.9532 +v 6.2952 1.7089 -16.2194 +v 6.3112 0.8805 -16.1713 +v 6.3098 0.8805 -15.9847 +v 6.2932 0.0000 -15.9656 +v 6.2951 0.0000 -16.2070 +v 6.1603 0.8805 -16.1763 +v 6.0959 0.0000 -16.2136 +v 6.1588 0.8805 -15.9897 +v 6.0941 0.0000 -15.9722 +v 6.5369 1.8182 -16.1558 +v 6.5357 1.8182 -15.9976 +v 6.7348 1.8182 -15.9911 +v 6.7360 1.8182 -16.1492 +v 6.7546 0.8805 -16.2411 +v 6.7537 0.8805 -16.1212 +v 6.7818 0.0000 -15.9911 +v 6.7830 0.0000 -16.1492 +v 6.6037 0.8805 -16.2461 +v 6.5839 0.0000 -16.1558 +v 6.6027 0.8805 -16.1262 +v 6.5827 0.0000 -15.9976 +v 7.0773 1.4149 -16.2523 +v 7.0764 1.4149 -16.1324 +v 7.9795 1.4917 -15.9514 +v 7.9807 1.4917 -16.1096 +v 6.1743 1.5530 -16.1694 +v 6.1731 1.5530 -16.0112 +v 7.0709 1.2339 -16.2525 +v 7.9722 1.2529 -16.1099 +v 6.1657 1.3141 -16.1697 +v 7.0699 1.2339 -16.1327 +v 7.9710 1.2529 -15.9517 +v 6.1645 1.3141 -16.0115 +v 7.0753 0.5144 -15.9900 +v 7.0744 0.5144 -15.8701 +v 7.9795 0.5972 -15.9514 +v 7.9807 0.5972 -16.1096 +v 6.1743 0.6584 -16.1694 +v 6.1731 0.6584 -16.0112 +v 7.0689 0.3333 -15.9902 +v 7.9722 0.3583 -16.1099 +v 6.1657 0.4196 -16.1697 +v 7.0679 0.3333 -15.8703 +v 7.9710 0.3583 -15.9517 +v 6.1645 0.4196 -16.0115 +v 6.9945 1.8814 -16.1422 +v 6.9933 1.8814 -15.9841 +v 7.1924 1.8814 -15.9775 +v 7.1937 1.8814 -16.1356 +v 7.1700 0.8805 -16.1897 +v 7.1691 0.8805 -16.0698 +v 7.1924 0.0000 -15.9775 +v 7.1937 0.0000 -16.1356 +v 7.0190 0.8805 -16.1947 +v 6.9945 0.0000 -16.1422 +v 7.0181 0.8805 -16.0748 +v 6.9933 0.0000 -15.9841 +v 7.4428 1.6654 -16.1274 +v 7.4416 1.6654 -15.9692 +v 7.6407 1.6654 -15.9626 +v 7.6420 1.6654 -16.1208 +v 7.5953 0.8805 -16.0068 +v 7.5944 0.8805 -15.8869 +v 7.6407 0.0000 -15.9626 +v 7.6420 0.0000 -16.1208 +v 7.4444 0.8805 -16.0118 +v 7.4428 0.0000 -16.1274 +v 7.4435 0.8805 -15.8919 +v 7.4416 0.0000 -15.9692 +v 7.8431 1.7611 -16.1723 +v 7.8410 1.7611 -15.8978 +v 8.0401 1.7611 -15.8912 +v 8.0422 1.7611 -16.1657 +v 7.9874 0.8805 -16.0902 +v 7.9865 0.8805 -15.9703 +v 8.0406 0.0000 -15.9494 +v 8.0418 0.0000 -16.1076 +v 7.8365 0.8805 -16.0952 +v 7.8426 0.0000 -16.1142 +v 7.8355 0.8805 -15.9753 +v 7.8414 0.0000 -15.9560 +v 8.1786 1.7089 -16.2260 +v 8.1766 1.7089 -15.9598 +v 8.3757 1.7089 -15.9532 +v 8.3778 1.7089 -16.2194 +v 8.3938 0.8805 -16.1713 +v 8.3924 0.8805 -15.9847 +v 8.3758 0.0000 -15.9656 +v 8.3777 0.0000 -16.2070 +v 8.2429 0.8805 -16.1763 +v 8.1785 0.0000 -16.2136 +v 8.2414 0.8805 -15.9897 +v 8.1767 0.0000 -15.9722 +v 8.6195 1.8182 -16.1558 +v 8.6183 1.8182 -15.9976 +v 8.8174 1.8182 -15.9911 +v 8.8186 1.8182 -16.1492 +v 8.8372 0.8805 -16.2411 +v 8.8363 0.8805 -16.1212 +v 8.8644 0.0000 -15.9911 +v 8.8656 0.0000 -16.1492 +v 8.6863 0.8805 -16.2461 +v 8.6665 0.0000 -16.1558 +v 8.6854 0.8805 -16.1262 +v 8.6653 0.0000 -15.9976 +v 9.1599 1.4149 -16.2523 +v 9.1590 1.4149 -16.1324 +v 10.0621 1.4917 -15.9514 +v 10.0633 1.4917 -16.1096 +v 8.2569 1.5530 -16.1694 +v 8.2557 1.5530 -16.0112 +v 9.1535 1.2339 -16.2525 +v 10.0548 1.2529 -16.1099 +v 8.2483 1.3141 -16.1697 +v 9.1525 1.2339 -16.1327 +v 10.0536 1.2529 -15.9517 +v 8.2471 1.3141 -16.0115 +v 9.1579 0.5144 -15.9900 +v 9.1570 0.5144 -15.8701 +v 10.0621 0.5972 -15.9514 +v 10.0633 0.5972 -16.1096 +v 8.2569 0.6584 -16.1694 +v 8.2557 0.6584 -16.0112 +v 9.1515 0.3333 -15.9902 +v 10.0548 0.3583 -16.1099 +v 8.2483 0.4196 -16.1697 +v 9.1505 0.3333 -15.8703 +v 10.0536 0.3583 -15.9517 +v 8.2471 0.4196 -16.0115 +v 9.0771 1.8814 -16.1422 +v 9.0759 1.8814 -15.9841 +v 9.2751 1.8814 -15.9775 +v 9.2763 1.8814 -16.1356 +v 9.2526 0.8805 -16.1897 +v 9.2517 0.8805 -16.0698 +v 9.2751 0.0000 -15.9775 +v 9.2763 0.0000 -16.1356 +v 9.1016 0.8805 -16.1947 +v 9.0771 0.0000 -16.1422 +v 9.1007 0.8805 -16.0748 +v 9.0759 0.0000 -15.9841 +v 9.5254 1.6654 -16.1274 +v 9.5242 1.6654 -15.9692 +v 9.7233 1.6654 -15.9626 +v 9.7246 1.6654 -16.1208 +v 9.6779 0.8805 -16.0068 +v 9.6770 0.8805 -15.8869 +v 9.7233 0.0000 -15.9626 +v 9.7246 0.0000 -16.1208 +v 9.5270 0.8805 -16.0118 +v 9.5254 0.0000 -16.1274 +v 9.5261 0.8805 -15.8919 +v 9.5242 0.0000 -15.9692 +v 9.9257 1.7611 -16.1723 +v 9.9236 1.7611 -15.8978 +v 10.1227 1.7611 -15.8912 +v 10.1248 1.7611 -16.1657 +v 10.0700 0.8805 -16.0902 +v 10.0691 0.8805 -15.9703 +v 10.1232 0.0000 -15.9494 +v 10.1244 0.0000 -16.1076 +v 9.9191 0.8805 -16.0952 +v 9.9252 0.0000 -16.1142 +v 9.9181 0.8805 -15.9753 +v 9.9240 0.0000 -15.9560 +v 10.2612 1.7089 -16.2260 +v 10.2592 1.7089 -15.9598 +v 10.4583 1.7089 -15.9532 +v 10.4604 1.7089 -16.2194 +v 10.4764 0.8805 -16.1713 +v 10.4750 0.8805 -15.9847 +v 10.4584 0.0000 -15.9656 +v 10.4603 0.0000 -16.2070 +v 10.3255 0.8805 -16.1763 +v 10.2611 0.0000 -16.2136 +v 10.3240 0.8805 -15.9897 +v 10.2593 0.0000 -15.9722 +v 10.7021 1.8182 -16.1558 +v 10.7009 1.8182 -15.9976 +v 10.9000 1.8182 -15.9911 +v 10.9012 1.8182 -16.1492 +v 10.9198 0.8805 -16.2411 +v 10.9189 0.8805 -16.1212 +v 10.9470 0.0000 -15.9911 +v 10.9482 0.0000 -16.1492 +v 10.7689 0.8805 -16.2461 +v 10.7491 0.0000 -16.1558 +v 10.7679 0.8805 -16.1262 +v 10.7479 0.0000 -15.9976 +v 11.2425 1.4149 -16.2523 +v 11.2416 1.4149 -16.1324 +v 12.1447 1.4917 -15.9514 +v 12.1459 1.4917 -16.1096 +v 10.3395 1.5530 -16.1694 +v 10.3383 1.5530 -16.0112 +v 11.2360 1.2339 -16.2525 +v 12.1374 1.2529 -16.1099 +v 10.3309 1.3141 -16.1697 +v 11.2351 1.2339 -16.1327 +v 12.1362 1.2529 -15.9517 +v 10.3297 1.3141 -16.0115 +v 11.2405 0.5144 -15.9900 +v 11.2396 0.5144 -15.8701 +v 12.1447 0.5972 -15.9514 +v 12.1459 0.5972 -16.1096 +v 10.3395 0.6584 -16.1694 +v 10.3383 0.6584 -16.0112 +v 11.2340 0.3333 -15.9902 +v 12.1374 0.3583 -16.1099 +v 10.3309 0.4196 -16.1697 +v 11.2331 0.3333 -15.8703 +v 12.1362 0.3583 -15.9517 +v 10.3297 0.4196 -16.0115 +v 11.1597 1.8814 -16.1422 +v 11.1585 1.8814 -15.9841 +v 11.3576 1.8814 -15.9775 +v 11.3589 1.8814 -16.1356 +v 11.3352 0.8805 -16.1897 +v 11.3342 0.8805 -16.0698 +v 11.3576 0.0000 -15.9775 +v 11.3589 0.0000 -16.1356 +v 11.1842 0.8805 -16.1947 +v 11.1597 0.0000 -16.1422 +v 11.1833 0.8805 -16.0748 +v 11.1585 0.0000 -15.9841 +v 11.6080 1.6654 -16.1274 +v 11.6068 1.6654 -15.9692 +v 11.8059 1.6654 -15.9626 +v 11.8071 1.6654 -16.1208 +v 11.7605 0.8805 -16.0068 +v 11.7596 0.8805 -15.8869 +v 11.8059 0.0000 -15.9626 +v 11.8071 0.0000 -16.1208 +v 11.6096 0.8805 -16.0118 +v 11.6080 0.0000 -16.1274 +v 11.6087 0.8805 -15.8919 +v 11.6068 0.0000 -15.9692 +v 12.0083 1.7611 -16.1723 +v 12.0062 1.7611 -15.8978 +v 12.2053 1.7611 -15.8912 +v 12.2074 1.7611 -16.1657 +v 12.1526 0.8805 -16.0902 +v 12.1517 0.8805 -15.9703 +v 12.2057 0.0000 -15.9494 +v 12.2070 0.0000 -16.1076 +v 12.0017 0.8805 -16.0952 +v 12.0078 0.0000 -16.1142 +v 12.0007 0.8805 -15.9753 +v 12.0066 0.0000 -15.9560 +v 12.3438 1.7089 -16.2260 +v 12.3418 1.7089 -15.9598 +v 12.5409 1.7089 -15.9532 +v 12.5430 1.7089 -16.2194 +v 12.5590 0.8805 -16.1713 +v 12.5576 0.8805 -15.9847 +v 12.5410 0.0000 -15.9656 +v 12.5429 0.0000 -16.2070 +v 12.4081 0.8805 -16.1763 +v 12.3437 0.0000 -16.2136 +v 12.4066 0.8805 -15.9897 +v 12.3419 0.0000 -15.9722 +v 12.7847 1.8182 -16.1558 +v 12.7835 1.8182 -15.9976 +v 12.9826 1.8182 -15.9911 +v 12.9838 1.8182 -16.1492 +v 13.0024 0.8805 -16.2411 +v 13.0015 0.8805 -16.1212 +v 13.0296 0.0000 -15.9911 +v 13.0308 0.0000 -16.1492 +v 12.8515 0.8805 -16.2461 +v 12.8317 0.0000 -16.1558 +v 12.8505 0.8805 -16.1262 +v 12.8305 0.0000 -15.9976 +v 13.3251 1.4149 -16.2523 +v 13.3242 1.4149 -16.1324 +v 14.2273 1.4917 -15.9514 +v 14.2285 1.4917 -16.1096 +v 12.4221 1.5530 -16.1694 +v 12.4209 1.5530 -16.0112 +v 13.3187 1.2339 -16.2525 +v 14.2200 1.2529 -16.1099 +v 12.4135 1.3141 -16.1697 +v 13.3177 1.2339 -16.1327 +v 14.2188 1.2529 -15.9517 +v 12.4123 1.3141 -16.0115 +v 13.3231 0.5144 -15.9900 +v 13.3222 0.5144 -15.8701 +v 14.2273 0.5972 -15.9514 +v 14.2285 0.5972 -16.1096 +v 12.4221 0.6584 -16.1694 +v 12.4209 0.6584 -16.0112 +v 13.3167 0.3333 -15.9902 +v 14.2200 0.3583 -16.1099 +v 12.4135 0.4196 -16.1697 +v 13.3157 0.3333 -15.8703 +v 14.2188 0.3583 -15.9517 +v 12.4123 0.4196 -16.0115 +v 13.2423 1.8814 -16.1422 +v 13.2411 1.8814 -15.9841 +v 13.4402 1.8814 -15.9775 +v 13.4415 1.8814 -16.1356 +v 13.4178 0.8805 -16.1897 +v 13.4169 0.8805 -16.0698 +v 13.4402 0.0000 -15.9775 +v 13.4415 0.0000 -16.1356 +v 13.2668 0.8805 -16.1947 +v 13.2423 0.0000 -16.1422 +v 13.2659 0.8805 -16.0748 +v 13.2411 0.0000 -15.9841 +v 13.6906 1.6654 -16.1274 +v 13.6894 1.6654 -15.9692 +v 13.8885 1.6654 -15.9626 +v 13.8898 1.6654 -16.1208 +v 13.8432 0.8805 -16.0068 +v 13.8422 0.8805 -15.8869 +v 13.8885 0.0000 -15.9626 +v 13.8898 0.0000 -16.1208 +v 13.6922 0.8805 -16.0118 +v 13.6906 0.0000 -16.1274 +v 13.6913 0.8805 -15.8919 +v 13.6894 0.0000 -15.9692 +v 14.0909 1.7611 -16.1723 +v 14.0888 1.7611 -15.8978 +v 14.2879 1.7611 -15.8912 +v 14.2900 1.7611 -16.1657 +v 14.2352 0.8805 -16.0902 +v 14.2343 0.8805 -15.9703 +v 14.2884 0.0000 -15.9494 +v 14.2896 0.0000 -16.1076 +v 14.0843 0.8805 -16.0952 +v 14.0904 0.0000 -16.1142 +v 14.0833 0.8805 -15.9753 +v 14.0892 0.0000 -15.9560 +v 14.4264 1.7089 -16.2260 +v 14.4244 1.7089 -15.9598 +v 14.6235 1.7089 -15.9532 +v 14.6256 1.7089 -16.2194 +v 14.6416 0.8805 -16.1713 +v 14.6402 0.8805 -15.9847 +v 14.6236 0.0000 -15.9656 +v 14.6255 0.0000 -16.2070 +v 14.4907 0.8805 -16.1763 +v 14.4263 0.0000 -16.2136 +v 14.4892 0.8805 -15.9897 +v 14.4245 0.0000 -15.9722 +v 14.8673 1.8182 -16.1558 +v 14.8661 1.8182 -15.9976 +v 15.0652 1.8182 -15.9911 +v 15.0664 1.8182 -16.1492 +v 15.0850 0.8805 -16.2411 +v 15.0841 0.8805 -16.1212 +v 15.1122 0.0000 -15.9911 +v 15.1134 0.0000 -16.1492 +v 14.9341 0.8805 -16.2461 +v 14.9143 0.0000 -16.1558 +v 14.9331 0.8805 -16.1262 +v 14.9131 0.0000 -15.9976 +v 15.4077 1.4149 -16.2523 +v 15.4068 1.4149 -16.1324 +v 16.3099 1.4917 -15.9514 +v 16.3111 1.4917 -16.1096 +v 14.5047 1.5530 -16.1694 +v 14.5035 1.5530 -16.0112 +v 15.4012 1.2339 -16.2525 +v 16.3026 1.2529 -16.1099 +v 14.4961 1.3141 -16.1697 +v 15.4003 1.2339 -16.1327 +v 16.3014 1.2529 -15.9517 +v 14.4949 1.3141 -16.0115 +v 15.4057 0.5144 -15.9900 +v 15.4048 0.5144 -15.8701 +v 16.3099 0.5972 -15.9514 +v 16.3111 0.5972 -16.1096 +v 14.5047 0.6584 -16.1694 +v 14.5035 0.6584 -16.0112 +v 15.3992 0.3333 -15.9902 +v 16.3026 0.3583 -16.1099 +v 14.4961 0.4196 -16.1697 +v 15.3983 0.3333 -15.8703 +v 16.3014 0.3583 -15.9517 +v 14.4949 0.4196 -16.0115 +v 15.3249 1.8814 -16.1422 +v 15.3237 1.8814 -15.9841 +v 15.5228 1.8814 -15.9775 +v 15.5241 1.8814 -16.1356 +v 15.5004 0.8805 -16.1897 +v 15.4995 0.8805 -16.0698 +v 15.5228 0.0000 -15.9775 +v 15.5241 0.0000 -16.1356 +v 15.3494 0.8805 -16.1947 +v 15.3249 0.0000 -16.1422 +v 15.3485 0.8805 -16.0748 +v 15.3237 0.0000 -15.9841 +v 15.7732 1.6654 -16.1274 +v 15.7720 1.6654 -15.9692 +v 15.9711 1.6654 -15.9626 +v 15.9723 1.6654 -16.1208 +v 15.9257 0.8805 -16.0068 +v 15.9248 0.8805 -15.8869 +v 15.9711 0.0000 -15.9626 +v 15.9723 0.0000 -16.1208 +v 15.7748 0.8805 -16.0118 +v 15.7732 0.0000 -16.1274 +v 15.7739 0.8805 -15.8919 +v 15.7720 0.0000 -15.9692 +v 16.1735 1.7611 -16.1723 +v 16.1714 1.7611 -15.8978 +v 16.3705 1.7611 -15.8912 +v 16.3726 1.7611 -16.1657 +v 16.3178 0.8805 -16.0902 +v 16.3169 0.8805 -15.9703 +v 16.3710 0.0000 -15.9494 +v 16.3722 0.0000 -16.1076 +v 16.1669 0.8805 -16.0952 +v 16.1730 0.0000 -16.1142 +v 16.1659 0.8805 -15.9753 +v 16.1718 0.0000 -15.9560 +v 16.4188 1.7089 -16.2260 +v 16.4168 1.7089 -15.9598 +v 16.6159 1.7089 -15.9532 +v 16.6180 1.7089 -16.2194 +v 16.6340 0.8805 -16.1713 +v 16.6326 0.8805 -15.9847 +v 16.6160 0.0000 -15.9656 +v 16.6179 0.0000 -16.2070 +v 16.4831 0.8805 -16.1763 +v 16.4188 0.0000 -16.2136 +v 16.4817 0.8805 -15.9897 +v 16.4169 0.0000 -15.9722 +v 16.8597 1.8182 -16.1558 +v 16.8585 1.8182 -15.9976 +v 17.0576 1.8182 -15.9911 +v 17.0588 1.8182 -16.1492 +v 17.0774 0.8805 -16.2411 +v 17.0765 0.8805 -16.1212 +v 17.1046 0.0000 -15.9911 +v 17.1058 0.0000 -16.1492 +v 16.9265 0.8805 -16.2461 +v 16.9067 0.0000 -16.1558 +v 16.9256 0.8805 -16.1262 +v 16.9055 0.0000 -15.9976 +v 17.4001 1.4149 -16.2523 +v 17.3992 1.4149 -16.1324 +v 18.3023 1.4917 -15.9514 +v 18.3035 1.4917 -16.1096 +v 16.4971 1.5530 -16.1694 +v 16.4959 1.5530 -16.0112 +v 17.3937 1.2339 -16.2525 +v 18.2950 1.2529 -16.1099 +v 16.4886 1.3141 -16.1697 +v 17.3927 1.2339 -16.1327 +v 18.2938 1.2529 -15.9517 +v 16.4873 1.3141 -16.0115 +v 17.3981 0.5144 -15.9900 +v 17.3972 0.5144 -15.8701 +v 18.3023 0.5972 -15.9514 +v 18.3035 0.5972 -16.1096 +v 16.4971 0.6584 -16.1694 +v 16.4959 0.6584 -16.0112 +v 17.3917 0.3333 -15.9902 +v 18.2950 0.3583 -16.1099 +v 16.4886 0.4196 -16.1697 +v 17.3907 0.3333 -15.8703 +v 18.2938 0.3583 -15.9517 +v 16.4873 0.4196 -16.0115 +v 17.3173 1.8814 -16.1422 +v 17.3161 1.8814 -15.9841 +v 17.5153 1.8814 -15.9775 +v 17.5165 1.8814 -16.1356 +v 17.4928 0.8805 -16.1897 +v 17.4919 0.8805 -16.0698 +v 17.5153 0.0000 -15.9775 +v 17.5165 0.0000 -16.1356 +v 17.3418 0.8805 -16.1947 +v 17.3173 0.0000 -16.1422 +v 17.3409 0.8805 -16.0748 +v 17.3161 0.0000 -15.9841 +v 17.7656 1.6654 -16.1274 +v 17.7644 1.6654 -15.9692 +v 17.9636 1.6654 -15.9626 +v 17.9648 1.6654 -16.1208 +v 17.9182 0.8805 -16.0068 +v 17.9172 0.8805 -15.8869 +v 17.9636 0.0000 -15.9626 +v 17.9648 0.0000 -16.1208 +v 17.7672 0.8805 -16.0118 +v 17.7656 0.0000 -16.1274 +v 17.7663 0.8805 -15.8919 +v 17.7644 0.0000 -15.9692 +v 18.1659 1.7611 -16.1723 +v 18.1638 1.7611 -15.8978 +v 18.3629 1.7611 -15.8912 +v 18.3650 1.7611 -16.1657 +v 18.3102 0.8805 -16.0902 +v 18.3093 0.8805 -15.9703 +v 18.3634 0.0000 -15.9494 +v 18.3646 0.0000 -16.1076 +v 18.1593 0.8805 -16.0952 +v 18.1654 0.0000 -16.1142 +v 18.1584 0.8805 -15.9753 +v 18.1642 0.0000 -15.9560 +v 18.4203 1.7089 -15.6952 +v 18.1542 1.7089 -15.6972 +v 18.1476 1.7089 -15.4981 +v 18.4137 1.7089 -15.4960 +v 18.3657 0.8805 -15.4800 +v 18.1791 0.8805 -15.4814 +v 18.1600 0.0000 -15.4980 +v 18.4013 0.0000 -15.4961 +v 18.3707 0.8805 -15.6309 +v 18.4079 0.0000 -15.6953 +v 18.1841 0.8805 -15.6324 +v 18.1666 0.0000 -15.6971 +v 18.3502 1.8182 -15.2543 +v 18.1920 1.8182 -15.2555 +v 18.1854 1.8182 -15.0564 +v 18.3436 1.8182 -15.0552 +v 18.4355 0.8805 -15.0366 +v 18.3156 0.8805 -15.0375 +v 18.1854 0.0000 -15.0094 +v 18.3436 0.0000 -15.0082 +v 18.4405 0.8805 -15.1875 +v 18.3502 0.0000 -15.2073 +v 18.3206 0.8805 -15.1884 +v 18.1920 0.0000 -15.2085 +v 18.4467 1.4149 -14.7139 +v 18.3268 1.4149 -14.7148 +v 18.1458 1.4917 -13.8117 +v 18.3039 1.4917 -13.8105 +v 18.3637 1.5530 -15.6169 +v 18.2056 1.5530 -15.6181 +v 18.4469 1.2339 -14.7203 +v 18.3042 1.2529 -13.8190 +v 18.3640 1.3141 -15.6255 +v 18.3270 1.2339 -14.7213 +v 18.1460 1.2529 -13.8202 +v 18.2059 1.3141 -15.6267 +v 18.1843 0.5144 -14.7159 +v 18.0644 0.5144 -14.7168 +v 18.1458 0.5972 -13.8117 +v 18.3039 0.5972 -13.8105 +v 18.3637 0.6584 -15.6169 +v 18.2056 0.6584 -15.6181 +v 18.1845 0.3333 -14.7223 +v 18.3042 0.3583 -13.8190 +v 18.3640 0.4196 -15.6255 +v 18.0646 0.3333 -14.7233 +v 18.1460 0.3583 -13.8202 +v 18.2059 0.4196 -15.6267 +v 18.3366 1.8814 -14.7967 +v 18.1784 1.8814 -14.7979 +v 18.1718 1.8814 -14.5987 +v 18.3300 1.8814 -14.5975 +v 18.3841 0.8805 -14.6212 +v 18.2642 0.8805 -14.6221 +v 18.1718 0.0000 -14.5987 +v 18.3300 0.0000 -14.5975 +v 18.3891 0.8805 -14.7722 +v 18.3366 0.0000 -14.7967 +v 18.2691 0.8805 -14.7731 +v 18.1784 0.0000 -14.7979 +v 18.3218 1.6654 -14.3484 +v 18.1636 1.6654 -14.3496 +v 18.1570 1.6654 -14.1505 +v 18.3152 1.6654 -14.1492 +v 18.2012 0.8805 -14.1958 +v 18.0813 0.8805 -14.1968 +v 18.1570 0.0000 -14.1505 +v 18.3152 0.0000 -14.1492 +v 18.2062 0.8805 -14.3468 +v 18.3218 0.0000 -14.3484 +v 18.0863 0.8805 -14.3477 +v 18.1636 0.0000 -14.3496 +v 18.3667 1.7611 -13.9481 +v 18.0922 1.7611 -13.9502 +v 18.0856 1.7611 -13.7511 +v 18.3601 1.7611 -13.7490 +v 18.2846 0.8805 -13.8038 +v 18.1647 0.8805 -13.8047 +v 18.1437 0.0000 -13.7506 +v 18.3019 0.0000 -13.7494 +v 18.2896 0.8805 -13.9547 +v 18.3085 0.0000 -13.9486 +v 18.1697 0.8805 -13.9557 +v 18.1503 0.0000 -13.9498 +v 18.4203 1.7089 -13.6126 +v 18.1542 1.7089 -13.6146 +v 18.1476 1.7089 -13.4154 +v 18.4137 1.7089 -13.4134 +v 18.3657 0.8805 -13.3974 +v 18.1791 0.8805 -13.3988 +v 18.1600 0.0000 -13.4154 +v 18.4013 0.0000 -13.4135 +v 18.3707 0.8805 -13.5483 +v 18.4079 0.0000 -13.6126 +v 18.1841 0.8805 -13.5497 +v 18.1666 0.0000 -13.6145 +v 18.3502 1.8182 -13.1717 +v 18.1920 1.8182 -13.1729 +v 18.1854 1.8182 -12.9738 +v 18.3436 1.8182 -12.9726 +v 18.4355 0.8805 -12.9540 +v 18.3156 0.8805 -12.9549 +v 18.1854 0.0000 -12.9268 +v 18.3436 0.0000 -12.9256 +v 18.4405 0.8805 -13.1049 +v 18.3502 0.0000 -13.1247 +v 18.3206 0.8805 -13.1058 +v 18.1920 0.0000 -13.1259 +v 18.4467 1.4149 -12.6313 +v 18.3268 1.4149 -12.6322 +v 18.1458 1.4917 -11.7291 +v 18.3039 1.4917 -11.7279 +v 18.3637 1.5530 -13.5343 +v 18.2056 1.5530 -13.5355 +v 18.4469 1.2339 -12.6377 +v 18.3042 1.2529 -11.7364 +v 18.3640 1.3141 -13.5428 +v 18.3270 1.2339 -12.6387 +v 18.1460 1.2529 -11.7376 +v 18.2059 1.3141 -13.5441 +v 18.1843 0.5144 -12.6333 +v 18.0644 0.5144 -12.6342 +v 18.1458 0.5972 -11.7291 +v 18.3039 0.5972 -11.7279 +v 18.3637 0.6584 -13.5343 +v 18.2056 0.6584 -13.5355 +v 18.1845 0.3333 -12.6397 +v 18.3042 0.3583 -11.7364 +v 18.3640 0.4196 -13.5428 +v 18.0646 0.3333 -12.6407 +v 18.1460 0.3583 -11.7376 +v 18.2059 0.4196 -13.5441 +v 18.3366 1.8814 -12.7141 +v 18.1784 1.8814 -12.7153 +v 18.1718 1.8814 -12.5161 +v 18.3300 1.8814 -12.5149 +v 18.3841 0.8805 -12.5386 +v 18.2642 0.8805 -12.5395 +v 18.1718 0.0000 -12.5161 +v 18.3300 0.0000 -12.5149 +v 18.3891 0.8805 -12.6896 +v 18.3366 0.0000 -12.7141 +v 18.2691 0.8805 -12.6905 +v 18.1784 0.0000 -12.7153 +v 18.3218 1.6654 -12.2658 +v 18.1636 1.6654 -12.2670 +v 18.1570 1.6654 -12.0679 +v 18.3152 1.6654 -12.0666 +v 18.2012 0.8805 -12.1132 +v 18.0813 0.8805 -12.1142 +v 18.1570 0.0000 -12.0679 +v 18.3152 0.0000 -12.0666 +v 18.2062 0.8805 -12.2642 +v 18.3218 0.0000 -12.2658 +v 18.0863 0.8805 -12.2651 +v 18.1636 0.0000 -12.2670 +v 18.3667 1.7611 -11.8655 +v 18.0922 1.7611 -11.8676 +v 18.0856 1.7611 -11.6685 +v 18.3601 1.7611 -11.6664 +v 18.2846 0.8805 -11.7212 +v 18.1647 0.8805 -11.7221 +v 18.1437 0.0000 -11.6680 +v 18.3019 0.0000 -11.6668 +v 18.2896 0.8805 -11.8721 +v 18.3085 0.0000 -11.8660 +v 18.1697 0.8805 -11.8730 +v 18.1503 0.0000 -11.8672 +v 18.4203 1.7089 -11.5205 +v 18.1542 1.7089 -11.5225 +v 18.1476 1.7089 -11.3233 +v 18.4137 1.7089 -11.3213 +v 18.3657 0.8805 -11.3053 +v 18.1791 0.8805 -11.3067 +v 18.1600 0.0000 -11.3233 +v 18.4013 0.0000 -11.3214 +v 18.3707 0.8805 -11.4562 +v 18.4079 0.0000 -11.5205 +v 18.1841 0.8805 -11.4576 +v 18.1666 0.0000 -11.5224 +v 18.3502 1.8182 -11.0796 +v 18.1920 1.8182 -11.0808 +v 18.1854 1.8182 -10.8817 +v 18.3436 1.8182 -10.8805 +v 18.4355 0.8805 -10.8619 +v 18.3156 0.8805 -10.8628 +v 18.1854 0.0000 -10.8347 +v 18.3436 0.0000 -10.8335 +v 18.4405 0.8805 -11.0128 +v 18.3502 0.0000 -11.0326 +v 18.3206 0.8805 -11.0137 +v 18.1920 0.0000 -11.0338 +v 18.4467 1.4149 -10.5392 +v 18.3268 1.4149 -10.5401 +v 18.1458 1.4917 -9.6370 +v 18.3039 1.4917 -9.6358 +v 18.3637 1.5530 -11.4422 +v 18.2056 1.5530 -11.4434 +v 18.4469 1.2339 -10.5456 +v 18.3042 1.2529 -9.6443 +v 18.3640 1.3141 -11.4507 +v 18.3270 1.2339 -10.5465 +v 18.1460 1.2529 -9.6455 +v 18.2059 1.3141 -11.4520 +v 18.1843 0.5144 -10.5412 +v 18.0644 0.5144 -10.5421 +v 18.1458 0.5972 -9.6370 +v 18.3039 0.5972 -9.6358 +v 18.3637 0.6584 -11.4422 +v 18.2056 0.6584 -11.4434 +v 18.1845 0.3333 -10.5476 +v 18.3042 0.3583 -9.6443 +v 18.3640 0.4196 -11.4507 +v 18.0646 0.3333 -10.5485 +v 18.1460 0.3583 -9.6455 +v 18.2059 0.4196 -11.4520 +v 18.3366 1.8814 -10.6220 +v 18.1784 1.8814 -10.6232 +v 18.1718 1.8814 -10.4240 +v 18.3300 1.8814 -10.4228 +v 18.3841 0.8805 -10.4465 +v 18.2642 0.8805 -10.4474 +v 18.1718 0.0000 -10.4240 +v 18.3300 0.0000 -10.4228 +v 18.3891 0.8805 -10.5975 +v 18.3366 0.0000 -10.6220 +v 18.2691 0.8805 -10.5984 +v 18.1784 0.0000 -10.6232 +v 18.3218 1.6654 -10.1737 +v 18.1636 1.6654 -10.1749 +v 18.1570 1.6654 -9.9757 +v 18.3152 1.6654 -9.9745 +v 18.2012 0.8805 -10.0211 +v 18.0813 0.8805 -10.0221 +v 18.1570 0.0000 -9.9757 +v 18.3152 0.0000 -9.9745 +v 18.2062 0.8805 -10.1721 +v 18.3218 0.0000 -10.1737 +v 18.0863 0.8805 -10.1730 +v 18.1636 0.0000 -10.1749 +v 18.3667 1.7611 -9.7734 +v 18.0922 1.7611 -9.7755 +v 18.0856 1.7611 -9.5764 +v 18.3601 1.7611 -9.5743 +v 18.2846 0.8805 -9.6291 +v 18.1647 0.8805 -9.6300 +v 18.1437 0.0000 -9.5759 +v 18.3019 0.0000 -9.5747 +v 18.2896 0.8805 -9.7800 +v 18.3085 0.0000 -9.7739 +v 18.1697 0.8805 -9.7809 +v 18.1503 0.0000 -9.7751 +v 18.4203 1.7088 -9.4379 +v 18.1542 1.7088 -9.4399 +v 18.1476 1.7088 -9.2407 +v 18.4137 1.7088 -9.2387 +v 18.3657 0.8805 -9.2227 +v 18.1791 0.8805 -9.2241 +v 18.1600 0.0000 -9.2407 +v 18.4013 0.0000 -9.2388 +v 18.3707 0.8805 -9.3736 +v 18.4079 0.0000 -9.4379 +v 18.1841 0.8805 -9.3750 +v 18.1666 0.0000 -9.4398 +v 18.3502 1.8182 -8.9970 +v 18.1920 1.8182 -8.9982 +v 18.1854 1.8182 -8.7991 +v 18.3436 1.8182 -8.7979 +v 18.4355 0.8805 -8.7793 +v 18.3156 0.8805 -8.7802 +v 18.1854 0.0000 -8.7521 +v 18.3436 0.0000 -8.7509 +v 18.4405 0.8805 -8.9302 +v 18.3502 0.0000 -8.9500 +v 18.3206 0.8805 -8.9311 +v 18.1920 0.0000 -8.9512 +v 18.4467 1.4149 -8.4566 +v 18.3268 1.4149 -8.4575 +v 18.1458 1.4917 -7.5544 +v 18.3039 1.4917 -7.5532 +v 18.3637 1.5530 -9.3596 +v 18.2056 1.5530 -9.3608 +v 18.4469 1.2339 -8.4630 +v 18.3042 1.2529 -7.5617 +v 18.3640 1.3141 -9.3681 +v 18.3270 1.2339 -8.4639 +v 18.1460 1.2529 -7.5629 +v 18.2059 1.3141 -9.3694 +v 18.1843 0.5144 -8.4586 +v 18.0644 0.5144 -8.4595 +v 18.1458 0.5972 -7.5544 +v 18.3039 0.5972 -7.5532 +v 18.3637 0.6584 -9.3596 +v 18.2056 0.6584 -9.3608 +v 18.1845 0.3333 -8.4650 +v 18.3042 0.3583 -7.5617 +v 18.3640 0.4196 -9.3681 +v 18.0646 0.3333 -8.4660 +v 18.1460 0.3583 -7.5629 +v 18.2059 0.4196 -9.3694 +v 18.3366 1.8814 -8.5394 +v 18.1784 1.8814 -8.5406 +v 18.1718 1.8814 -8.3414 +v 18.3300 1.8814 -8.3402 +v 18.3841 0.8805 -8.3639 +v 18.2642 0.8805 -8.3648 +v 18.1718 0.0000 -8.3414 +v 18.3300 0.0000 -8.3402 +v 18.3891 0.8805 -8.5149 +v 18.3366 0.0000 -8.5394 +v 18.2691 0.8805 -8.5158 +v 18.1784 0.0000 -8.5406 +v 18.3218 1.6654 -8.0911 +v 18.1636 1.6654 -8.0923 +v 18.1570 1.6654 -7.8931 +v 18.3152 1.6654 -7.8919 +v 18.2012 0.8805 -7.9385 +v 18.0813 0.8805 -7.9395 +v 18.1570 0.0000 -7.8932 +v 18.3152 0.0000 -7.8919 +v 18.2062 0.8805 -8.0895 +v 18.3218 0.0000 -8.0911 +v 18.0863 0.8805 -8.0904 +v 18.1636 0.0000 -8.0923 +v 18.3667 1.7611 -7.6908 +v 18.0922 1.7611 -7.6929 +v 18.0856 1.7611 -7.4938 +v 18.3601 1.7611 -7.4917 +v 18.2846 0.8805 -7.5465 +v 18.1647 0.8805 -7.5474 +v 18.1437 0.0000 -7.4933 +v 18.3019 0.0000 -7.4921 +v 18.2896 0.8805 -7.6974 +v 18.3085 0.0000 -7.6913 +v 18.1697 0.8805 -7.6983 +v 18.1503 0.0000 -7.6925 +v 18.4203 1.7088 -7.3786 +v 18.1542 1.7088 -7.3806 +v 18.1476 1.7088 -7.1815 +v 18.4137 1.7088 -7.1795 +v 18.3657 0.8805 -7.1634 +v 18.1791 0.8805 -7.1648 +v 18.1600 0.0000 -7.1814 +v 18.4013 0.0000 -7.1795 +v 18.3707 0.8805 -7.3143 +v 18.4079 0.0000 -7.3787 +v 18.1841 0.8805 -7.3158 +v 18.1666 0.0000 -7.3805 +v 18.3502 1.8182 -6.9377 +v 18.1920 1.8182 -6.9390 +v 18.1854 1.8182 -6.7398 +v 18.3436 1.8182 -6.7386 +v 18.4355 0.8805 -6.7200 +v 18.3156 0.8805 -6.7209 +v 18.1854 0.0000 -6.6928 +v 18.3436 0.0000 -6.6916 +v 18.4405 0.8805 -6.8709 +v 18.3502 0.0000 -6.8907 +v 18.3206 0.8805 -6.8719 +v 18.1920 0.0000 -6.8919 +v 18.4467 1.4149 -6.3973 +v 18.3268 1.4149 -6.3982 +v 18.1458 1.4917 -5.4951 +v 18.3039 1.4917 -5.4939 +v 18.3637 1.5530 -7.3003 +v 18.2056 1.5530 -7.3015 +v 18.4469 1.2339 -6.4038 +v 18.3042 1.2529 -5.5024 +v 18.3640 1.3141 -7.3089 +v 18.3270 1.2339 -6.4047 +v 18.1460 1.2529 -5.5036 +v 18.2059 1.3141 -7.3101 +v 18.1843 0.5144 -6.3993 +v 18.0644 0.5144 -6.4002 +v 18.1458 0.5972 -5.4951 +v 18.3039 0.5972 -5.4939 +v 18.3637 0.6584 -7.3003 +v 18.2056 0.6584 -7.3015 +v 18.1845 0.3333 -6.4058 +v 18.3042 0.3583 -5.5024 +v 18.3640 0.4196 -7.3089 +v 18.0646 0.3333 -6.4067 +v 18.1460 0.3583 -5.5036 +v 18.2059 0.4196 -7.3101 +v 18.3366 1.8814 -6.4801 +v 18.1784 1.8814 -6.4813 +v 18.1718 1.8814 -6.2822 +v 18.3300 1.8814 -6.2810 +v 18.3841 0.8805 -6.3046 +v 18.2642 0.8805 -6.3056 +v 18.1718 0.0000 -6.2822 +v 18.3300 0.0000 -6.2810 +v 18.3891 0.8805 -6.4556 +v 18.3366 0.0000 -6.4801 +v 18.2691 0.8805 -6.4565 +v 18.1784 0.0000 -6.4813 +v 18.3218 1.6654 -6.0318 +v 18.1636 1.6654 -6.0330 +v 18.1570 1.6654 -5.8339 +v 18.3152 1.6654 -5.8327 +v 18.2012 0.8805 -5.8793 +v 18.0813 0.8805 -5.8802 +v 18.1570 0.0000 -5.8339 +v 18.3152 0.0000 -5.8327 +v 18.2062 0.8805 -6.0302 +v 18.3218 0.0000 -6.0318 +v 18.0863 0.8805 -6.0311 +v 18.1636 0.0000 -6.0330 +v 18.3667 1.7611 -5.6315 +v 18.0922 1.7611 -5.6336 +v 18.0856 1.7611 -5.4345 +v 18.3601 1.7611 -5.4324 +v 18.2846 0.8805 -5.4872 +v 18.1647 0.8805 -5.4881 +v 18.1437 0.0000 -5.4341 +v 18.3019 0.0000 -5.4329 +v 18.2896 0.8805 -5.6382 +v 18.3085 0.0000 -5.6320 +v 18.1697 0.8805 -5.6391 +v 18.1503 0.0000 -5.6332 +v 18.4203 1.7088 -5.2960 +v 18.1542 1.7088 -5.2980 +v 18.1476 1.7088 -5.0989 +v 18.4137 1.7088 -5.0969 +v 18.3657 0.8805 -5.0808 +v 18.1791 0.8805 -5.0822 +v 18.1600 0.0000 -5.0988 +v 18.4013 0.0000 -5.0969 +v 18.3707 0.8805 -5.2317 +v 18.4079 0.0000 -5.2961 +v 18.1841 0.8805 -5.2332 +v 18.1666 0.0000 -5.2979 +v 18.3502 1.8182 -4.8551 +v 18.1920 1.8182 -4.8564 +v 18.1854 1.8182 -4.6572 +v 18.3436 1.8182 -4.6560 +v 18.4355 0.8805 -4.6374 +v 18.3156 0.8805 -4.6383 +v 18.1854 0.0000 -4.6102 +v 18.3436 0.0000 -4.6090 +v 18.4405 0.8805 -4.7883 +v 18.3502 0.0000 -4.8081 +v 18.3206 0.8805 -4.7893 +v 18.1920 0.0000 -4.8093 +v 18.4467 1.4149 -4.3147 +v 18.3268 1.4149 -4.3156 +v 18.1458 1.4917 -3.4125 +v 18.3039 1.4917 -3.4113 +v 18.3637 1.5530 -5.2177 +v 18.2056 1.5530 -5.2190 +v 18.4469 1.2339 -4.3212 +v 18.3042 1.2529 -3.4198 +v 18.3640 1.3141 -5.2263 +v 18.3270 1.2339 -4.3221 +v 18.1460 1.2529 -3.4210 +v 18.2059 1.3141 -5.2275 +v 18.1843 0.5144 -4.3167 +v 18.0644 0.5144 -4.3176 +v 18.1458 0.5972 -3.4125 +v 18.3039 0.5972 -3.4113 +v 18.3637 0.6584 -5.2177 +v 18.2056 0.6584 -5.2190 +v 18.1845 0.3333 -4.3232 +v 18.3042 0.3583 -3.4198 +v 18.3640 0.4196 -5.2263 +v 18.0646 0.3333 -4.3241 +v 18.1460 0.3583 -3.4210 +v 18.2059 0.4196 -5.2275 +v 18.3366 1.8814 -4.3975 +v 18.1784 1.8814 -4.3987 +v 18.1718 1.8814 -4.1996 +v 18.3300 1.8814 -4.1984 +v 18.3841 0.8805 -4.2220 +v 18.2642 0.8805 -4.2230 +v 18.1718 0.0000 -4.1996 +v 18.3300 0.0000 -4.1984 +v 18.3891 0.8805 -4.3730 +v 18.3366 0.0000 -4.3975 +v 18.2691 0.8805 -4.3739 +v 18.1784 0.0000 -4.3987 +v 18.3218 1.6654 -3.9492 +v 18.1636 1.6654 -3.9504 +v 18.1570 1.6654 -3.7513 +v 18.3152 1.6654 -3.7501 +v 18.2012 0.8805 -3.7967 +v 18.0813 0.8805 -3.7976 +v 18.1570 0.0000 -3.7513 +v 18.3152 0.0000 -3.7501 +v 18.2062 0.8805 -3.9476 +v 18.3218 0.0000 -3.9492 +v 18.0863 0.8805 -3.9485 +v 18.1636 0.0000 -3.9504 +v 18.3667 1.7611 -3.5489 +v 18.0922 1.7611 -3.5510 +v 18.0856 1.7611 -3.3519 +v 18.3601 1.7611 -3.3498 +v 18.2846 0.8805 -3.4046 +v 18.1647 0.8805 -3.4055 +v 18.1437 0.0000 -3.3515 +v 18.3019 0.0000 -3.3503 +v 18.2896 0.8805 -3.5556 +v 18.3085 0.0000 -3.5494 +v 18.1697 0.8805 -3.5565 +v 18.1503 0.0000 -3.5506 +v 18.4203 1.7088 -3.2304 +v 18.1542 1.7088 -3.2324 +v 18.1476 1.7088 -3.0333 +v 18.4137 1.7088 -3.0313 +v 18.3657 0.8805 -3.0152 +v 18.1791 0.8805 -3.0166 +v 18.1600 0.0000 -3.0332 +v 18.4013 0.0000 -3.0314 +v 18.3707 0.8805 -3.1662 +v 18.4079 0.0000 -3.2305 +v 18.1841 0.8805 -3.1676 +v 18.1666 0.0000 -3.2323 +v 18.3502 1.8182 -2.7896 +v 18.1920 1.8182 -2.7908 +v 18.1854 1.8182 -2.5916 +v 18.3436 1.8182 -2.5904 +v 18.4355 0.8805 -2.5718 +v 18.3156 0.8805 -2.5727 +v 18.1854 0.0000 -2.5446 +v 18.3436 0.0000 -2.5434 +v 18.4405 0.8805 -2.7228 +v 18.3502 0.0000 -2.7426 +v 18.3206 0.8805 -2.7237 +v 18.1920 0.0000 -2.7438 +v 18.4467 1.4149 -2.2491 +v 18.3268 1.4149 -2.2500 +v 18.1458 1.4917 -1.3469 +v 18.3039 1.4917 -1.3457 +v 18.3637 1.5530 -3.1522 +v 18.2056 1.5530 -3.1534 +v 18.4469 1.2339 -2.2556 +v 18.3042 1.2529 -1.3543 +v 18.3640 1.3141 -3.1607 +v 18.3270 1.2339 -2.2565 +v 18.1460 1.2529 -1.3555 +v 18.2059 1.3141 -3.1619 +v 18.1843 0.5144 -2.2511 +v 18.0644 0.5144 -2.2520 +v 18.1458 0.5972 -1.3469 +v 18.3039 0.5972 -1.3457 +v 18.3637 0.6584 -3.1522 +v 18.2056 0.6584 -3.1534 +v 18.1845 0.3333 -2.2576 +v 18.3042 0.3583 -1.3543 +v 18.3640 0.4196 -3.1607 +v 18.0646 0.3333 -2.2585 +v 18.1460 0.3583 -1.3555 +v 18.2059 0.4196 -3.1619 +v 18.3366 1.8814 -2.3319 +v 18.1784 1.8814 -2.3331 +v 18.1718 1.8814 -2.1340 +v 18.3300 1.8814 -2.1328 +v 18.3841 0.8805 -2.1565 +v 18.2642 0.8805 -2.1574 +v 18.1718 0.0000 -2.1340 +v 18.3300 0.0000 -2.1328 +v 18.3891 0.8805 -2.3074 +v 18.3366 0.0000 -2.3319 +v 18.2691 0.8805 -2.3083 +v 18.1784 0.0000 -2.3331 +v 18.3218 1.6654 -1.8836 +v 18.1636 1.6654 -1.8848 +v 18.1570 1.6654 -1.6857 +v 18.3152 1.6654 -1.6845 +v 18.2012 0.8805 -1.7311 +v 18.0813 0.8805 -1.7320 +v 18.1570 0.0000 -1.6857 +v 18.3152 0.0000 -1.6845 +v 18.2062 0.8805 -1.8820 +v 18.3218 0.0000 -1.8836 +v 18.0863 0.8805 -1.8830 +v 18.1636 0.0000 -1.8848 +v 18.3667 1.7611 -1.4834 +v 18.0922 1.7611 -1.4855 +v 18.0856 1.7611 -1.2863 +v 18.3601 1.7611 -1.2842 +v 18.2846 0.8805 -1.3390 +v 18.1647 0.8805 -1.3399 +v 18.1437 0.0000 -1.2859 +v 18.3019 0.0000 -1.2847 +v 18.2896 0.8805 -1.4900 +v 18.3085 0.0000 -1.4838 +v 18.1697 0.8805 -1.4909 +v 18.1503 0.0000 -1.4850 +v 18.4203 1.7088 -1.1478 +v 18.1542 1.7088 -1.1498 +v 18.1476 1.7088 -0.9507 +v 18.4137 1.7088 -0.9487 +v 18.3657 0.8805 -0.9326 +v 18.1791 0.8805 -0.9340 +v 18.1600 0.0000 -0.9506 +v 18.4013 0.0000 -0.9488 +v 18.3707 0.8805 -1.0836 +v 18.4079 0.0000 -1.1479 +v 18.1841 0.8805 -1.0850 +v 18.1666 0.0000 -1.1497 +v 18.3502 1.8182 -0.7070 +v 18.1920 1.8182 -0.7082 +v 18.1854 1.8182 -0.5090 +v 18.3436 1.8182 -0.5078 +v 18.4355 0.8805 -0.4892 +v 18.3156 0.8805 -0.4901 +v 18.1854 0.0000 -0.4620 +v 18.3436 0.0000 -0.4608 +v 18.4405 0.8805 -0.6402 +v 18.3502 0.0000 -0.6600 +v 18.3206 0.8805 -0.6411 +v 18.1920 0.0000 -0.6612 +v 18.4467 1.4149 -0.1665 +v 18.3268 1.4149 -0.1674 +v 18.1458 1.4917 0.7357 +v 18.3039 1.4917 0.7369 +v 18.3637 1.5530 -1.0696 +v 18.2056 1.5530 -1.0708 +v 18.4469 1.2339 -0.1730 +v 18.3042 1.2529 0.7283 +v 18.3640 1.3141 -1.0781 +v 18.3270 1.2339 -0.1739 +v 18.1460 1.2529 0.7271 +v 18.2059 1.3141 -1.0793 +v 18.1843 0.5144 -0.1685 +v 18.0644 0.5144 -0.1694 +v 18.1458 0.5972 0.7357 +v 18.3039 0.5972 0.7369 +v 18.3637 0.6584 -1.0696 +v 18.2056 0.6584 -1.0708 +v 18.1845 0.3333 -0.1750 +v 18.3042 0.3583 0.7283 +v 18.3640 0.4196 -1.0781 +v 18.0646 0.3333 -0.1759 +v 18.1460 0.3583 0.7271 +v 18.2059 0.4196 -1.0793 +v 18.3366 1.8814 -0.2493 +v 18.1784 1.8814 -0.2505 +v 18.1718 1.8814 -0.0514 +v 18.3300 1.8814 -0.0502 +v 18.3841 0.8805 -0.0739 +v 18.2642 0.8805 -0.0748 +v 18.1718 0.0000 -0.0514 +v 18.3300 0.0000 -0.0502 +v 18.3891 0.8805 -0.2248 +v 18.3366 0.0000 -0.2493 +v 18.2691 0.8805 -0.2257 +v 18.1784 0.0000 -0.2505 +v 18.3218 1.6654 0.1990 +v 18.1636 1.6654 0.1978 +v 18.1570 1.6654 0.3969 +v 18.3152 1.6654 0.3981 +v 18.2012 0.8805 0.3515 +v 18.0813 0.8805 0.3506 +v 18.1570 0.0000 0.3969 +v 18.3152 0.0000 0.3981 +v 18.2062 0.8805 0.2006 +v 18.3218 0.0000 0.1990 +v 18.0863 0.8805 0.1996 +v 18.1636 0.0000 0.1978 +v 18.3667 1.7611 0.5992 +v 18.0922 1.7611 0.5971 +v 18.0856 1.7611 0.7963 +v 18.3601 1.7611 0.7984 +v 18.2846 0.8805 0.7436 +v 18.1647 0.8805 0.7427 +v 18.1437 0.0000 0.7967 +v 18.3019 0.0000 0.7979 +v 18.2896 0.8805 0.5926 +v 18.3085 0.0000 0.5988 +v 18.1697 0.8805 0.5917 +v 18.1503 0.0000 0.5976 +v 18.4203 1.7088 0.8554 +v 18.1542 1.7088 0.8534 +v 18.1476 1.7088 1.0525 +v 18.4137 1.7088 1.0545 +v 18.3657 0.8805 1.0706 +v 18.1791 0.8805 1.0692 +v 18.1600 0.0000 1.0526 +v 18.4013 0.0000 1.0544 +v 18.3707 0.8805 0.9196 +v 18.4079 0.0000 0.8553 +v 18.1841 0.8805 0.9182 +v 18.1666 0.0000 0.8535 +v 18.3502 1.8182 1.2962 +v 18.1920 1.8182 1.2950 +v 18.1854 1.8182 1.4942 +v 18.3436 1.8182 1.4954 +v 18.4355 0.8805 1.5140 +v 18.3156 0.8805 1.5131 +v 18.1854 0.0000 1.5412 +v 18.3436 0.0000 1.5424 +v 18.4405 0.8805 1.3630 +v 18.3502 0.0000 1.3432 +v 18.3206 0.8805 1.3621 +v 18.1920 0.0000 1.3420 +v 18.4467 1.4149 1.8367 +v 18.3268 1.4149 1.8358 +v 18.1458 1.4917 2.7389 +v 18.3039 1.4917 2.7401 +v 18.3637 1.5530 0.9336 +v 18.2056 1.5530 0.9324 +v 18.4469 1.2339 1.8302 +v 18.3042 1.2529 2.7315 +v 18.3640 1.3141 0.9251 +v 18.3270 1.2339 1.8293 +v 18.1460 1.2529 2.7303 +v 18.2059 1.3141 0.9239 +v 18.1843 0.5144 1.8347 +v 18.0644 0.5144 1.8338 +v 18.1458 0.5972 2.7389 +v 18.3039 0.5972 2.7401 +v 18.3637 0.6584 0.9336 +v 18.2056 0.6584 0.9324 +v 18.1845 0.3333 1.8282 +v 18.3042 0.3583 2.7315 +v 18.3640 0.4196 0.9251 +v 18.0646 0.3333 1.8273 +v 18.1460 0.3583 2.7303 +v 18.2059 0.4196 0.9239 +v 18.3366 1.8814 1.7539 +v 18.1784 1.8814 1.7527 +v 18.1718 1.8814 1.9518 +v 18.3300 1.8814 1.9530 +v 18.3841 0.8805 1.9293 +v 18.2642 0.8805 1.9284 +v 18.1718 0.0000 1.9518 +v 18.3300 0.0000 1.9530 +v 18.3891 0.8805 1.7784 +v 18.3366 0.0000 1.7539 +v 18.2691 0.8805 1.7775 +v 18.1784 0.0000 1.7527 +v 18.3218 1.6654 2.2022 +v 18.1636 1.6654 2.2010 +v 18.1570 1.6654 2.4001 +v 18.3152 1.6654 2.4013 +v 18.2012 0.8805 2.3547 +v 18.0813 0.8805 2.3538 +v 18.1570 0.0000 2.4001 +v 18.3152 0.0000 2.4013 +v 18.2062 0.8805 2.2038 +v 18.3218 0.0000 2.2022 +v 18.0863 0.8805 2.2028 +v 18.1636 0.0000 2.2010 +v 18.3667 1.7611 2.6024 +v 18.0922 1.7611 2.6003 +v 18.0856 1.7611 2.7995 +v 18.3601 1.7611 2.8016 +v 18.2846 0.8805 2.7468 +v 18.1647 0.8805 2.7459 +v 18.1437 0.0000 2.7999 +v 18.3019 0.0000 2.8011 +v 18.2896 0.8805 2.5958 +v 18.3085 0.0000 2.6020 +v 18.1697 0.8805 2.5949 +v 18.1503 0.0000 2.6008 +v 18.4203 1.7088 2.9380 +v 18.1542 1.7088 2.9360 +v 18.1476 1.7088 3.1351 +v 18.4137 1.7088 3.1371 +v 18.3657 0.8805 3.1532 +v 18.1791 0.8805 3.1518 +v 18.1600 0.0000 3.1352 +v 18.4013 0.0000 3.1370 +v 18.3707 0.8805 3.0022 +v 18.4079 0.0000 2.9379 +v 18.1841 0.8805 3.0008 +v 18.1666 0.0000 2.9361 +v 18.3502 1.8182 3.3788 +v 18.1920 1.8182 3.3776 +v 18.1854 1.8182 3.5768 +v 18.3436 1.8182 3.5780 +v 18.4355 0.8805 3.5966 +v 18.3156 0.8805 3.5957 +v 18.1854 0.0000 3.6238 +v 18.3436 0.0000 3.6250 +v 18.4405 0.8805 3.4456 +v 18.3502 0.0000 3.4258 +v 18.3206 0.8805 3.4447 +v 18.1920 0.0000 3.4246 +v 18.4467 1.4149 3.9193 +v 18.3268 1.4149 3.9184 +v 18.1458 1.4917 4.8215 +v 18.3039 1.4917 4.8227 +v 18.3637 1.5530 3.0162 +v 18.2056 1.5530 3.0150 +v 18.4469 1.2339 3.9128 +v 18.3042 1.2529 4.8141 +v 18.3640 1.3141 3.0077 +v 18.3270 1.2339 3.9119 +v 18.1460 1.2529 4.8129 +v 18.2059 1.3141 3.0065 +v 18.1843 0.5144 3.9173 +v 18.0644 0.5144 3.9164 +v 18.1458 0.5972 4.8215 +v 18.3039 0.5972 4.8227 +v 18.3637 0.6584 3.0162 +v 18.2056 0.6584 3.0150 +v 18.1845 0.3333 3.9108 +v 18.3042 0.3583 4.8141 +v 18.3640 0.4196 3.0077 +v 18.0646 0.3333 3.9099 +v 18.1460 0.3583 4.8129 +v 18.2059 0.4196 3.0065 +v 18.3366 1.8814 3.8365 +v 18.1784 1.8814 3.8353 +v 18.1718 1.8814 4.0344 +v 18.3300 1.8814 4.0356 +v 18.3841 0.8805 4.0119 +v 18.2642 0.8805 4.0110 +v 18.1718 0.0000 4.0344 +v 18.3300 0.0000 4.0356 +v 18.3891 0.8805 3.8610 +v 18.3366 0.0000 3.8365 +v 18.2691 0.8805 3.8601 +v 18.1784 0.0000 3.8353 +v 18.3218 1.6654 4.2848 +v 18.1636 1.6654 4.2836 +v 18.1570 1.6654 4.4827 +v 18.3152 1.6654 4.4839 +v 18.2012 0.8805 4.4373 +v 18.0813 0.8805 4.4364 +v 18.1570 0.0000 4.4827 +v 18.3152 0.0000 4.4839 +v 18.2062 0.8805 4.2864 +v 18.3218 0.0000 4.2848 +v 18.0863 0.8805 4.2854 +v 18.1636 0.0000 4.2836 +v 18.3667 1.7611 4.6850 +v 18.0922 1.7611 4.6829 +v 18.0856 1.7611 4.8821 +v 18.3601 1.7611 4.8842 +v 18.2846 0.8805 4.8294 +v 18.1647 0.8805 4.8285 +v 18.1437 0.0000 4.8825 +v 18.3019 0.0000 4.8837 +v 18.2896 0.8805 4.6784 +v 18.3085 0.0000 4.6846 +v 18.1697 0.8805 4.6775 +v 18.1503 0.0000 4.6834 +v 18.4203 1.7088 5.0312 +v 18.1542 1.7088 5.0291 +v 18.1476 1.7088 5.2283 +v 18.4137 1.7088 5.2303 +v 18.3657 0.8805 5.2464 +v 18.1791 0.8805 5.2449 +v 18.1600 0.0000 5.2284 +v 18.4013 0.0000 5.2302 +v 18.3707 0.8805 5.0954 +v 18.4079 0.0000 5.0311 +v 18.1841 0.8805 5.0940 +v 18.1666 0.0000 5.0292 +v 18.3502 1.8182 5.4720 +v 18.1920 1.8182 5.4708 +v 18.1854 1.8182 5.6699 +v 18.3436 1.8182 5.6711 +v 18.4355 0.8805 5.6898 +v 18.3156 0.8805 5.6889 +v 18.1854 -0.0000 5.7169 +v 18.3436 -0.0000 5.7182 +v 18.4405 0.8805 5.5388 +v 18.3502 0.0000 5.5190 +v 18.3206 0.8805 5.5379 +v 18.1920 0.0000 5.5178 +v 18.4467 1.4149 6.0125 +v 18.3268 1.4149 6.0116 +v 18.1458 1.4917 6.9147 +v 18.3039 1.4917 6.9159 +v 18.3637 1.5530 5.1094 +v 18.2056 1.5530 5.1082 +v 18.4469 1.2339 6.0060 +v 18.3042 1.2529 6.9073 +v 18.3640 1.3141 5.1009 +v 18.3270 1.2339 6.0051 +v 18.1460 1.2529 6.9061 +v 18.2059 1.3141 5.0997 +v 18.1843 0.5144 6.0105 +v 18.0644 0.5144 6.0096 +v 18.1458 0.5972 6.9147 +v 18.3039 0.5972 6.9159 +v 18.3637 0.6584 5.1094 +v 18.2056 0.6584 5.1082 +v 18.1845 0.3333 6.0040 +v 18.3042 0.3583 6.9073 +v 18.3640 0.4196 5.1009 +v 18.0646 0.3333 6.0031 +v 18.1460 0.3583 6.9061 +v 18.2059 0.4196 5.0997 +v 18.3366 1.8814 5.9297 +v 18.1784 1.8814 5.9285 +v 18.1718 1.8814 6.1276 +v 18.3300 1.8814 6.1288 +v 18.3841 0.8805 6.1051 +v 18.2642 0.8805 6.1042 +v 18.1718 -0.0000 6.1276 +v 18.3300 -0.0000 6.1288 +v 18.3891 0.8805 5.9542 +v 18.3366 -0.0000 5.9297 +v 18.2691 0.8805 5.9533 +v 18.1784 -0.0000 5.9285 +v 18.3218 1.6654 6.3780 +v 18.1636 1.6654 6.3768 +v 18.1570 1.6654 6.5759 +v 18.3152 1.6654 6.5771 +v 18.2012 0.8805 6.5305 +v 18.0813 0.8805 6.5296 +v 18.1570 -0.0000 6.5759 +v 18.3152 -0.0000 6.5771 +v 18.2062 0.8805 6.3795 +v 18.3218 -0.0000 6.3780 +v 18.0863 0.8805 6.3786 +v 18.1636 -0.0000 6.3768 +v 18.3667 1.7611 6.7782 +v 18.0922 1.7611 6.7761 +v 18.0856 1.7611 6.9753 +v 18.3601 1.7611 6.9774 +v 18.2846 0.8805 6.9226 +v 18.1647 0.8805 6.9216 +v 18.1437 -0.0000 6.9757 +v 18.3019 -0.0000 6.9769 +v 18.2896 0.8805 6.7716 +v 18.3085 -0.0000 6.7778 +v 18.1697 0.8805 6.7707 +v 18.1504 -0.0000 6.7766 +v 18.4203 1.7088 7.1138 +v 18.1542 1.7088 7.1118 +v 18.1476 1.7088 7.3109 +v 18.4137 1.7088 7.3129 +v 18.3657 0.8805 7.3290 +v 18.1791 0.8805 7.3276 +v 18.1600 -0.0000 7.3110 +v 18.4013 -0.0000 7.3128 +v 18.3707 0.8805 7.1780 +v 18.4079 -0.0000 7.1137 +v 18.1841 0.8805 7.1766 +v 18.1666 -0.0000 7.1119 +v 18.3502 1.8182 7.5546 +v 18.1920 1.8182 7.5534 +v 18.1854 1.8182 7.7526 +v 18.3436 1.8182 7.7537 +v 18.4355 0.8805 7.7724 +v 18.3156 0.8805 7.7715 +v 18.1854 -0.0000 7.7996 +v 18.3436 -0.0000 7.8008 +v 18.4405 0.8805 7.6214 +v 18.3502 -0.0000 7.6016 +v 18.3206 0.8805 7.6205 +v 18.1920 -0.0000 7.6004 +v 18.4467 1.4149 8.0951 +v 18.3268 1.4149 8.0942 +v 18.1458 1.4917 8.9973 +v 18.3039 1.4917 8.9985 +v 18.3638 1.5530 7.1920 +v 18.2056 1.5530 7.1908 +v 18.4469 1.2339 8.0886 +v 18.3042 1.2529 8.9899 +v 18.3640 1.3141 7.1835 +v 18.3270 1.2339 8.0877 +v 18.1460 1.2529 8.9887 +v 18.2059 1.3141 7.1823 +v 18.1843 0.5144 8.0931 +v 18.0644 0.5144 8.0922 +v 18.1458 0.5972 8.9973 +v 18.3039 0.5972 8.9985 +v 18.3638 0.6584 7.1920 +v 18.2056 0.6584 7.1908 +v 18.1845 0.3333 8.0866 +v 18.3042 0.3583 8.9899 +v 18.3640 0.4196 7.1835 +v 18.0646 0.3333 8.0857 +v 18.1460 0.3583 8.9887 +v 18.2059 0.4196 7.1823 +v 18.3366 1.8814 8.0123 +v 18.1784 1.8814 8.0111 +v 18.1718 1.8814 8.2102 +v 18.3300 1.8814 8.2114 +v 18.3841 0.8805 8.1877 +v 18.2642 0.8805 8.1868 +v 18.1718 0.0000 8.2102 +v 18.3300 0.0000 8.2114 +v 18.3891 0.8805 8.0368 +v 18.3366 -0.0000 8.0123 +v 18.2691 0.8805 8.0359 +v 18.1784 -0.0000 8.0111 +v 18.3218 1.6654 8.4606 +v 18.1636 1.6654 8.4594 +v 18.1570 1.6654 8.6585 +v 18.3152 1.6654 8.6597 +v 18.2012 0.8805 8.6131 +v 18.0813 0.8805 8.6122 +v 18.1570 0.0000 8.6585 +v 18.3152 0.0000 8.6597 +v 18.2062 0.8805 8.4621 +v 18.3218 0.0000 8.4606 +v 18.0863 0.8805 8.4612 +v 18.1636 0.0000 8.4594 +v 18.3667 1.7611 8.8608 +v 18.0922 1.7611 8.8587 +v 18.0856 1.7611 9.0579 +v 18.3601 1.7611 9.0600 +v 18.2846 0.8805 9.0052 +v 18.1647 0.8805 9.0043 +v 18.1437 0.0000 9.0583 +v 18.3019 0.0000 9.0595 +v 18.2896 0.8805 8.8542 +v 18.3085 0.0000 8.8604 +v 18.1697 0.8805 8.8533 +v 18.1504 0.0000 8.8592 +v 17.9256 1.7088 9.1043 +v 17.9276 1.7088 8.8382 +v 17.7285 1.7088 8.8316 +v 17.7265 1.7088 9.0977 +v 17.7104 0.8805 9.0497 +v 17.7118 0.8805 8.8631 +v 17.7284 0.0000 8.8440 +v 17.7265 0.0000 9.0853 +v 17.8613 0.8805 9.0547 +v 17.9257 0.0000 9.0919 +v 17.8628 0.8805 8.8681 +v 17.9275 0.0000 8.8506 +v 17.4847 1.8182 9.0342 +v 17.4860 1.8182 8.8760 +v 17.2868 1.8182 8.8694 +v 17.2856 1.8182 9.0276 +v 17.2670 0.8805 9.1194 +v 17.2679 0.8805 8.9995 +v 17.2398 0.0000 8.8694 +v 17.2386 0.0000 9.0276 +v 17.4179 0.8805 9.1244 +v 17.4377 0.0000 9.0342 +v 17.4189 0.8805 9.0045 +v 17.4389 0.0000 8.8760 +v 16.9443 1.4149 9.1307 +v 16.9452 1.4149 9.0108 +v 16.0421 1.4917 8.8297 +v 16.0409 1.4917 8.9879 +v 17.8473 1.5530 9.0477 +v 17.8485 1.5530 8.8895 +v 16.9508 1.2339 9.1309 +v 16.0494 1.2529 8.9882 +v 17.8559 1.3141 9.0480 +v 16.9517 1.2339 9.0110 +v 16.0506 1.2529 8.8300 +v 17.8571 1.3141 8.8898 +v 16.9463 0.5144 8.8683 +v 16.9472 0.5144 8.7484 +v 16.0421 0.5972 8.8297 +v 16.0409 0.5972 8.9879 +v 17.8473 0.6584 9.0477 +v 17.8485 0.6584 8.8895 +v 16.9528 0.3333 8.8685 +v 16.0494 0.3583 8.9882 +v 17.8559 0.4196 9.0480 +v 16.9537 0.3333 8.7486 +v 16.0506 0.3583 8.8300 +v 17.8571 0.4196 8.8898 +v 17.0271 1.8814 9.0206 +v 17.0283 1.8814 8.8624 +v 16.8292 1.8814 8.8558 +v 16.8280 1.8814 9.0140 +v 16.8516 0.8805 9.0680 +v 16.8526 0.8805 8.9481 +v 16.8292 0.0000 8.8558 +v 16.8280 0.0000 9.0140 +v 17.0026 0.8805 9.0730 +v 17.0271 0.0000 9.0206 +v 17.0035 0.8805 8.9531 +v 17.0283 0.0000 8.8624 +v 16.5788 1.6654 9.0057 +v 16.5800 1.6654 8.8475 +v 16.3809 1.6654 8.8410 +v 16.3797 1.6654 8.9991 +v 16.4263 0.8805 8.8852 +v 16.4272 0.8805 8.7653 +v 16.3809 0.0000 8.8410 +v 16.3797 0.0000 8.9991 +v 16.5772 0.8805 8.8902 +v 16.5788 0.0000 9.0057 +v 16.5781 0.8805 8.7703 +v 16.5800 0.0000 8.8475 +v 16.1785 1.7611 9.0507 +v 16.1806 1.7611 8.7761 +v 15.9815 1.7611 8.7695 +v 15.9794 1.7611 9.0441 +v 16.0342 0.8805 8.9686 +v 16.0351 0.8805 8.8487 +v 15.9811 0.0000 8.8277 +v 15.9799 0.0000 8.9859 +v 16.1852 0.8805 8.9735 +v 16.1790 0.0000 8.9925 +v 16.1861 0.8805 8.8536 +v 16.1802 0.0000 8.8343 +v 15.8430 1.7088 9.1043 +v 15.8450 1.7088 8.8382 +v 15.6459 1.7088 8.8316 +v 15.6438 1.7088 9.0977 +v 15.6278 0.8805 9.0497 +v 15.6292 0.8805 8.8631 +v 15.6458 0.0000 8.8440 +v 15.6439 0.0000 9.0853 +v 15.7787 0.8805 9.0547 +v 15.8431 0.0000 9.0919 +v 15.7802 0.8805 8.8681 +v 15.8449 0.0000 8.8506 +v 15.4021 1.8182 9.0342 +v 15.4033 1.8182 8.8760 +v 15.2042 1.8182 8.8694 +v 15.2030 1.8182 9.0276 +v 15.1844 0.8805 9.1194 +v 15.1853 0.8805 8.9995 +v 15.1572 0.0000 8.8694 +v 15.1560 0.0000 9.0276 +v 15.3353 0.8805 9.1244 +v 15.3551 0.0000 9.0342 +v 15.3363 0.8805 9.0045 +v 15.3563 0.0000 8.8760 +v 14.8617 1.4149 9.1307 +v 14.8626 1.4149 9.0108 +v 13.9595 1.4917 8.8297 +v 13.9583 1.4917 8.9879 +v 15.7647 1.5530 9.0477 +v 15.7659 1.5530 8.8895 +v 14.8682 1.2339 9.1309 +v 13.9668 1.2529 8.9882 +v 15.7733 1.3141 9.0480 +v 14.8691 1.2339 9.0110 +v 13.9680 1.2529 8.8300 +v 15.7745 1.3141 8.8898 +v 14.8637 0.5144 8.8683 +v 14.8646 0.5144 8.7484 +v 13.9595 0.5972 8.8297 +v 13.9583 0.5972 8.9879 +v 15.7647 0.6584 9.0477 +v 15.7659 0.6584 8.8895 +v 14.8702 0.3333 8.8685 +v 13.9668 0.3583 8.9882 +v 15.7733 0.4196 9.0480 +v 14.8711 0.3333 8.7486 +v 13.9680 0.3583 8.8300 +v 15.7745 0.4196 8.8898 +v 14.9445 1.8814 9.0206 +v 14.9457 1.8814 8.8624 +v 14.7466 1.8814 8.8558 +v 14.7453 1.8814 9.0140 +v 14.7690 0.8805 9.0680 +v 14.7700 0.8805 8.9481 +v 14.7466 0.0000 8.8558 +v 14.7453 0.0000 9.0140 +v 14.9200 0.8805 9.0730 +v 14.9445 0.0000 9.0206 +v 14.9209 0.8805 8.9531 +v 14.9457 0.0000 8.8624 +v 14.4962 1.6654 9.0057 +v 14.4974 1.6654 8.8475 +v 14.2983 1.6654 8.8410 +v 14.2971 1.6654 8.9991 +v 14.3437 0.8805 8.8852 +v 14.3446 0.8805 8.7653 +v 14.2983 0.0000 8.8410 +v 14.2971 0.0000 8.9991 +v 14.4946 0.8805 8.8902 +v 14.4962 0.0000 9.0057 +v 14.4955 0.8805 8.7703 +v 14.4974 0.0000 8.8475 +v 14.0959 1.7611 9.0507 +v 14.0980 1.7611 8.7761 +v 13.8989 1.7611 8.7695 +v 13.8968 1.7611 9.0441 +v 13.9516 0.8805 8.9686 +v 13.9525 0.8805 8.8487 +v 13.8985 0.0000 8.8277 +v 13.8972 0.0000 8.9859 +v 14.1025 0.8805 8.9735 +v 14.0964 0.0000 8.9925 +v 14.1035 0.8805 8.8536 +v 14.0976 0.0000 8.8343 +v 13.7498 1.7088 9.1043 +v 13.7518 1.7088 8.8382 +v 13.5527 1.7088 8.8316 +v 13.5507 1.7088 9.0977 +v 13.5346 0.8805 9.0497 +v 13.5360 0.8805 8.8631 +v 13.5526 0.0000 8.8440 +v 13.5507 0.0000 9.0853 +v 13.6855 0.8805 9.0547 +v 13.7499 0.0000 9.0919 +v 13.6870 0.8805 8.8681 +v 13.7517 0.0000 8.8506 +v 13.3089 1.8182 9.0342 +v 13.3102 1.8182 8.8760 +v 13.1110 1.8182 8.8694 +v 13.1098 1.8182 9.0276 +v 13.0912 0.8805 9.1194 +v 13.0921 0.8805 8.9995 +v 13.0640 0.0000 8.8694 +v 13.0628 0.0000 9.0276 +v 13.2421 0.8805 9.1244 +v 13.2619 0.0000 9.0342 +v 13.2431 0.8805 9.0045 +v 13.2631 0.0000 8.8760 +v 12.7685 1.4149 9.1307 +v 12.7694 1.4149 9.0108 +v 11.8663 1.4917 8.8297 +v 11.8651 1.4917 8.9879 +v 13.6715 1.5530 9.0477 +v 13.6728 1.5530 8.8895 +v 12.7750 1.2339 9.1309 +v 11.8736 1.2529 8.9882 +v 13.6801 1.3141 9.0480 +v 12.7759 1.2339 9.0110 +v 11.8748 1.2529 8.8300 +v 13.6813 1.3141 8.8898 +v 12.7705 0.5144 8.8683 +v 12.7714 0.5144 8.7484 +v 11.8663 0.5972 8.8297 +v 11.8651 0.5972 8.9879 +v 13.6715 0.6584 9.0477 +v 13.6728 0.6584 8.8895 +v 12.7770 0.3333 8.8685 +v 11.8736 0.3583 8.9882 +v 13.6801 0.4196 9.0480 +v 12.7779 0.3333 8.7486 +v 11.8748 0.3583 8.8300 +v 13.6813 0.4196 8.8898 +v 12.8513 1.8814 9.0206 +v 12.8525 1.8814 8.8624 +v 12.6534 1.8814 8.8558 +v 12.6522 1.8814 9.0140 +v 12.6758 0.8805 9.0680 +v 12.6768 0.8805 8.9481 +v 12.6534 0.0000 8.8558 +v 12.6522 0.0000 9.0140 +v 12.8268 0.8805 9.0730 +v 12.8513 0.0000 9.0206 +v 12.8277 0.8805 8.9531 +v 12.8525 0.0000 8.8624 +v 12.4030 1.6654 9.0057 +v 12.4042 1.6654 8.8475 +v 12.2051 1.6654 8.8410 +v 12.2039 1.6654 8.9991 +v 12.2505 0.8805 8.8852 +v 12.2514 0.8805 8.7653 +v 12.2051 0.0000 8.8410 +v 12.2039 0.0000 8.9991 +v 12.4014 0.8805 8.8902 +v 12.4030 0.0000 9.0057 +v 12.4023 0.8805 8.7703 +v 12.4042 0.0000 8.8475 +v 12.0027 1.7611 9.0507 +v 12.0048 1.7611 8.7761 +v 11.8057 1.7611 8.7695 +v 11.8036 1.7611 9.0441 +v 11.8584 0.8805 8.9686 +v 11.8593 0.8805 8.8487 +v 11.8053 0.0000 8.8277 +v 11.8041 0.0000 8.9859 +v 12.0094 0.8805 8.9735 +v 12.0032 0.0000 8.9925 +v 12.0103 0.8805 8.8536 +v 12.0044 0.0000 8.8343 +v 11.6672 1.7088 9.1043 +v 11.6692 1.7088 8.8382 +v 11.4701 1.7088 8.8316 +v 11.4681 1.7088 9.0977 +v 11.4520 0.8805 9.0497 +v 11.4534 0.8805 8.8631 +v 11.4700 0.0000 8.8440 +v 11.4681 0.0000 9.0853 +v 11.6030 0.8805 9.0547 +v 11.6673 0.0000 9.0919 +v 11.6044 0.8805 8.8681 +v 11.6691 0.0000 8.8506 +v 11.2264 1.8182 9.0342 +v 11.2276 1.8182 8.8760 +v 11.0284 1.8182 8.8694 +v 11.0272 1.8182 9.0276 +v 11.0086 0.8805 9.1194 +v 11.0095 0.8805 8.9995 +v 10.9814 0.0000 8.8694 +v 10.9802 0.0000 9.0276 +v 11.1595 0.8805 9.1244 +v 11.1793 0.0000 9.0342 +v 11.1605 0.8805 9.0045 +v 11.1806 0.0000 8.8760 +v 10.6859 1.4149 9.1307 +v 10.6868 1.4149 9.0108 +v 9.7837 1.4917 8.8297 +v 9.7825 1.4917 8.9879 +v 11.5889 1.5530 9.0477 +v 11.5902 1.5530 8.8895 +v 10.6924 1.2339 9.1309 +v 9.7910 1.2529 8.9882 +v 11.5975 1.3141 9.0480 +v 10.6933 1.2339 9.0110 +v 9.7923 1.2529 8.8300 +v 11.5987 1.3141 8.8898 +v 10.6879 0.5144 8.8683 +v 10.6888 0.5144 8.7484 +v 9.7837 0.5972 8.8297 +v 9.7825 0.5972 8.9879 +v 11.5889 0.6584 9.0477 +v 11.5902 0.6584 8.8895 +v 10.6944 0.3333 8.8685 +v 9.7910 0.3583 8.9882 +v 11.5975 0.4196 9.0480 +v 10.6953 0.3333 8.7486 +v 9.7923 0.3583 8.8300 +v 11.5987 0.4196 8.8898 +v 10.7687 1.8814 9.0206 +v 10.7699 1.8814 8.8624 +v 10.5708 1.8814 8.8558 +v 10.5696 1.8814 9.0140 +v 10.5932 0.8805 9.0680 +v 10.5942 0.8805 8.9481 +v 10.5708 0.0000 8.8558 +v 10.5696 0.0000 9.0140 +v 10.7442 0.8805 9.0730 +v 10.7687 0.0000 9.0206 +v 10.7451 0.8805 8.9531 +v 10.7699 0.0000 8.8624 +v 10.3204 1.6654 9.0057 +v 10.3216 1.6654 8.8475 +v 10.1225 1.6654 8.8410 +v 10.1213 1.6654 8.9991 +v 10.1679 0.8805 8.8852 +v 10.1688 0.8805 8.7653 +v 10.1225 0.0000 8.8410 +v 10.1213 0.0000 8.9991 +v 10.3188 0.8805 8.8902 +v 10.3204 0.0000 9.0057 +v 10.3197 0.8805 8.7703 +v 10.3216 0.0000 8.8475 +v 9.9201 1.7611 9.0507 +v 9.9223 1.7611 8.7761 +v 9.7231 1.7611 8.7695 +v 9.7210 1.7611 9.0441 +v 9.7758 0.8805 8.9686 +v 9.7767 0.8805 8.8487 +v 9.7227 0.0000 8.8277 +v 9.7215 0.0000 8.9859 +v 9.9268 0.8805 8.9735 +v 9.9206 0.0000 8.9925 +v 9.9277 0.8805 8.8536 +v 9.9218 0.0000 8.8343 +v 5.2841 1.7088 12.6327 +v 5.2821 1.7088 12.8988 +v 5.4812 1.7088 12.9054 +v 5.4832 1.7088 12.6393 +v 5.4993 0.8805 12.6873 +v 5.4979 0.8805 12.8739 +v 5.4813 -0.0000 12.8930 +v 5.4831 -0.0000 12.6517 +v 5.3483 0.8805 12.6823 +v 5.2840 -0.0000 12.6451 +v 5.3469 0.8805 12.8689 +v 5.2822 -0.0000 12.8865 +v 5.7249 1.8182 12.7029 +v 5.7237 1.8182 12.8610 +v 5.9229 1.8182 12.8676 +v 5.9241 1.8182 12.7094 +v 5.9427 0.8805 12.6176 +v 5.9418 0.8805 12.7375 +v 5.9699 -0.0000 12.8676 +v 5.9711 -0.0000 12.7094 +v 5.7917 0.8805 12.6126 +v 5.7719 -0.0000 12.7028 +v 5.7908 0.8805 12.7325 +v 5.7707 -0.0000 12.8610 +v 6.2654 1.4149 12.6063 +v 6.2645 1.4149 12.7262 +v 7.1676 1.4917 12.9073 +v 7.1688 1.4917 12.7491 +v 5.3623 1.5530 12.6893 +v 5.3611 1.5530 12.8475 +v 6.2589 1.2339 12.6061 +v 7.1602 1.2529 12.7488 +v 5.3538 1.3141 12.6890 +v 6.2580 1.2339 12.7260 +v 7.1590 1.2529 12.9070 +v 5.3526 1.3141 12.8472 +v 6.2634 0.5144 12.8687 +v 6.2625 0.5144 12.9886 +v 7.1676 0.5972 12.9073 +v 7.1688 0.5972 12.7491 +v 5.3623 0.6584 12.6893 +v 5.3611 0.6584 12.8475 +v 6.2569 0.3333 12.8685 +v 7.1602 0.3583 12.7488 +v 5.3538 0.4196 12.6890 +v 6.2560 0.3333 12.9884 +v 7.1590 0.3583 12.9070 +v 5.3526 0.4196 12.8472 +v 6.1826 1.8814 12.7164 +v 6.1814 1.8814 12.8746 +v 6.3805 1.8814 12.8812 +v 6.3817 1.8814 12.7230 +v 6.3580 0.8805 12.6690 +v 6.3571 0.8805 12.7889 +v 6.3805 -0.0000 12.8812 +v 6.3817 -0.0000 12.7230 +v 6.2071 0.8805 12.6640 +v 6.1826 -0.0000 12.7164 +v 6.2062 0.8805 12.7839 +v 6.1814 -0.0000 12.8746 +v 6.6309 1.6654 12.7313 +v 6.6297 1.6654 12.8895 +v 6.8288 1.6654 12.8961 +v 6.8300 1.6654 12.7379 +v 6.7834 0.8805 12.8518 +v 6.7825 0.8805 12.9717 +v 6.8288 -0.0000 12.8960 +v 6.8300 -0.0000 12.7379 +v 6.6325 0.8805 12.8468 +v 6.6309 -0.0000 12.7313 +v 6.6315 0.8805 12.9667 +v 6.6297 -0.0000 12.8895 +v 7.0311 1.7611 12.6863 +v 7.0290 1.7611 12.9609 +v 7.2282 1.7611 12.9675 +v 7.2303 1.7611 12.6929 +v 7.1755 0.8805 12.7685 +v 7.1746 0.8805 12.8884 +v 7.2286 -0.0000 12.9093 +v 7.2298 -0.0000 12.7511 +v 7.0245 0.8805 12.7635 +v 7.0307 -0.0000 12.7445 +v 7.0236 0.8805 12.8834 +v 7.0295 -0.0000 12.9027 +v 7.3667 1.7088 12.6327 +v 7.3647 1.7088 12.8988 +v 7.5638 1.7088 12.9054 +v 7.5658 1.7088 12.6393 +v 7.5819 0.8805 12.6873 +v 7.5805 0.8805 12.8739 +v 7.5639 -0.0000 12.8930 +v 7.5657 -0.0000 12.6517 +v 7.4309 0.8805 12.6823 +v 7.3666 -0.0000 12.6451 +v 7.4295 0.8805 12.8689 +v 7.3648 -0.0000 12.8865 +v 7.8075 1.8182 12.7029 +v 7.8063 1.8182 12.8610 +v 8.0055 1.8182 12.8676 +v 8.0067 1.8182 12.7094 +v 8.0253 0.8805 12.6176 +v 8.0244 0.8805 12.7375 +v 8.0525 -0.0000 12.8676 +v 8.0537 -0.0000 12.7094 +v 7.8743 0.8805 12.6126 +v 7.8545 -0.0000 12.7028 +v 7.8734 0.8805 12.7325 +v 7.8533 -0.0000 12.8610 +v 8.3480 1.4149 12.6063 +v 8.3471 1.4149 12.7262 +v 9.2502 1.4917 12.9073 +v 9.2514 1.4917 12.7491 +v 7.4449 1.5530 12.6893 +v 7.4437 1.5530 12.8475 +v 8.3415 1.2339 12.6061 +v 9.2428 1.2529 12.7488 +v 7.4364 1.3141 12.6890 +v 8.3406 1.2339 12.7260 +v 9.2416 1.2529 12.9070 +v 7.4352 1.3141 12.8472 +v 8.3460 0.5144 12.8687 +v 8.3451 0.5144 12.9886 +v 9.2502 0.5972 12.9073 +v 9.2514 0.5972 12.7491 +v 7.4449 0.6584 12.6893 +v 7.4437 0.6584 12.8475 +v 8.3395 0.3333 12.8685 +v 9.2428 0.3583 12.7488 +v 7.4364 0.4196 12.6890 +v 8.3386 0.3333 12.9884 +v 9.2416 0.3583 12.9070 +v 7.4352 0.4196 12.8472 +v 8.2652 1.8814 12.7164 +v 8.2640 1.8814 12.8746 +v 8.4631 1.8814 12.8812 +v 8.4643 1.8814 12.7230 +v 8.4406 0.8805 12.6690 +v 8.4397 0.8805 12.7889 +v 8.4631 -0.0000 12.8812 +v 8.4643 -0.0000 12.7230 +v 8.2897 0.8805 12.6640 +v 8.2652 -0.0000 12.7164 +v 8.2888 0.8805 12.7839 +v 8.2640 -0.0000 12.8746 +v 8.7135 1.6654 12.7313 +v 8.7123 1.6654 12.8895 +v 8.9114 1.6654 12.8961 +v 8.9126 1.6654 12.7379 +v 8.8660 0.8805 12.8518 +v 8.8651 0.8805 12.9717 +v 8.9114 -0.0000 12.8960 +v 8.9126 -0.0000 12.7379 +v 8.7151 0.8805 12.8468 +v 8.7135 -0.0000 12.7313 +v 8.7141 0.8805 12.9667 +v 8.7123 -0.0000 12.8895 +v 9.1137 1.7611 12.6863 +v 9.1117 1.7611 12.9609 +v 9.3108 1.7611 12.9675 +v 9.3129 1.7611 12.6929 +v 9.2581 0.8805 12.7685 +v 9.2572 0.8805 12.8884 +v 9.3112 -0.0000 12.9093 +v 9.3124 -0.0000 12.7511 +v 9.1071 0.8805 12.7635 +v 9.1133 -0.0000 12.7445 +v 9.1062 0.8805 12.8834 +v 9.1121 -0.0000 12.9027 +v 9.4214 1.7088 12.8486 +v 9.6875 1.7088 12.8506 +v 9.6941 1.7088 12.6514 +v 9.4279 1.7088 12.6494 +v 9.4760 0.8805 12.6334 +v 9.6626 0.8805 12.6348 +v 9.6817 -0.0000 12.6514 +v 9.4403 -0.0000 12.6495 +v 9.4710 0.8805 12.7843 +v 9.4337 -0.0000 12.8486 +v 9.6576 0.8805 12.7857 +v 9.6751 -0.0000 12.8505 +v 9.4915 1.8182 12.4077 +v 9.6497 1.8182 12.4089 +v 9.6563 1.8182 12.2098 +v 9.4981 1.8182 12.2086 +v 9.4062 0.8805 12.1900 +v 9.5261 0.8805 12.1909 +v 9.6563 -0.0000 12.1628 +v 9.4981 -0.0000 12.1616 +v 9.4012 0.8805 12.3409 +v 9.4915 -0.0000 12.3607 +v 9.5211 0.8805 12.3418 +v 9.6497 -0.0000 12.3619 +v 9.3950 1.4149 11.8673 +v 9.5149 1.4149 11.8682 +v 9.6959 1.4917 10.9651 +v 9.5377 1.4917 10.9639 +v 9.4779 1.5530 12.7703 +v 9.6361 1.5530 12.7715 +v 9.3948 1.2339 11.8737 +v 9.5375 1.2529 10.9724 +v 9.4777 1.3141 12.7788 +v 9.5147 1.2339 11.8746 +v 9.6956 1.2529 10.9736 +v 9.6358 1.3141 12.7801 +v 9.6574 0.5144 11.8693 +v 9.7773 0.5144 11.8702 +v 9.6959 0.5972 10.9651 +v 9.5377 0.5972 10.9639 +v 9.4779 0.6584 12.7703 +v 9.6361 0.6584 12.7715 +v 9.6571 0.3333 11.8757 +v 9.5375 0.3583 10.9724 +v 9.4777 0.4196 12.7788 +v 9.7770 0.3333 11.8767 +v 9.6956 0.3583 10.9736 +v 9.6358 0.4196 12.7801 +v 9.5051 1.8814 11.9501 +v 9.6633 1.8814 11.9513 +v 9.6698 1.8814 11.7521 +v 9.5117 1.8814 11.7509 +v 9.4576 0.8805 11.7746 +v 9.5775 0.8805 11.7755 +v 9.6698 -0.0000 11.7521 +v 9.5117 -0.0000 11.7509 +v 9.4526 0.8805 11.9256 +v 9.5051 -0.0000 11.9501 +v 9.5725 0.8805 11.9265 +v 9.6633 -0.0000 11.9513 +v 9.5199 1.6654 11.5018 +v 9.6781 1.6654 11.5030 +v 9.6847 1.6654 11.3039 +v 9.5265 1.6654 11.3026 +v 9.6405 0.8805 11.3492 +v 9.7604 0.8805 11.3502 +v 9.6847 -0.0000 11.3039 +v 9.5265 -0.0000 11.3026 +v 9.6355 0.8805 11.5002 +v 9.5199 -0.0000 11.5018 +v 9.7554 0.8805 11.5011 +v 9.6781 -0.0000 11.5030 +v 9.4750 1.7611 11.1015 +v 9.7495 1.7611 11.1036 +v 9.7561 1.7611 10.9045 +v 9.4816 1.7611 10.9024 +v 9.5571 0.8805 10.9572 +v 9.6770 0.8805 10.9581 +v 9.6979 -0.0000 10.9040 +v 9.5398 -0.0000 10.9028 +v 9.5521 0.8805 11.1081 +v 9.5332 -0.0000 11.1020 +v 9.6720 0.8805 11.1090 +v 9.6913 -0.0000 11.1032 +v 9.4214 1.7088 10.7660 +v 9.6875 1.7088 10.7680 +v 9.6941 1.7088 10.5688 +v 9.4279 1.7088 10.5668 +v 9.4760 0.8805 10.5508 +v 9.6626 0.8805 10.5522 +v 9.6817 -0.0000 10.5688 +v 9.4403 -0.0000 10.5669 +v 9.4710 0.8805 10.7017 +v 9.4337 -0.0000 10.7660 +v 9.6576 0.8805 10.7031 +v 9.6751 -0.0000 10.7679 +v 9.4915 1.8182 10.3251 +v 9.6497 1.8182 10.3263 +v 9.6563 1.8182 10.1272 +v 9.4981 1.8182 10.1260 +v 9.4062 0.8805 10.1074 +v 9.5261 0.8805 10.1083 +v 9.6563 -0.0000 10.0802 +v 9.4981 -0.0000 10.0790 +v 9.4012 0.8805 10.2583 +v 9.4915 -0.0000 10.2781 +v 9.5211 0.8805 10.2592 +v 9.6497 -0.0000 10.2793 +v 9.3950 1.4149 9.7847 +v 9.5149 1.4149 9.7856 +v 9.6959 1.4917 8.8825 +v 9.5377 1.4917 8.8813 +v 9.4779 1.5530 10.6877 +v 9.6361 1.5530 10.6889 +v 9.3948 1.2339 9.7911 +v 9.5375 1.2529 8.8898 +v 9.4777 1.3141 10.6962 +v 9.5147 1.2339 9.7920 +v 9.6956 1.2529 8.8910 +v 9.6358 1.3141 10.6975 +v 9.6574 0.5144 9.7867 +v 9.7773 0.5144 9.7876 +v 9.6959 0.5972 8.8825 +v 9.5377 0.5972 8.8813 +v 9.4779 0.6584 10.6877 +v 9.6361 0.6584 10.6889 +v 9.6571 0.3333 9.7931 +v 9.5375 0.3583 8.8898 +v 9.4777 0.4196 10.6962 +v 9.7770 0.3333 9.7941 +v 9.6956 0.3583 8.8910 +v 9.6358 0.4196 10.6975 +v 9.5051 1.8814 9.8675 +v 9.6633 1.8814 9.8687 +v 9.6698 1.8814 9.6695 +v 9.5117 1.8814 9.6683 +v 9.4576 0.8805 9.6920 +v 9.5775 0.8805 9.6929 +v 9.6698 -0.0000 9.6695 +v 9.5117 -0.0000 9.6683 +v 9.4526 0.8805 9.8430 +v 9.5051 -0.0000 9.8675 +v 9.5725 0.8805 9.8439 +v 9.6633 -0.0000 9.8687 +v 9.5199 1.6654 9.4192 +v 9.6781 1.6654 9.4204 +v 9.6847 1.6654 9.2213 +v 9.5265 1.6654 9.2200 +v 9.6405 0.8805 9.2666 +v 9.7604 0.8805 9.2676 +v 9.6847 0.0000 9.2213 +v 9.5265 0.0000 9.2200 +v 9.6355 0.8805 9.4176 +v 9.5199 -0.0000 9.4192 +v 9.7554 0.8805 9.4185 +v 9.6781 -0.0000 9.4204 +v 9.4750 1.7611 9.0189 +v 9.7495 1.7611 9.0210 +v 9.7561 1.7611 8.8219 +v 9.4816 1.7611 8.8198 +v 9.5571 0.8805 8.8746 +v 9.6770 0.8805 8.8755 +v 9.6979 0.0000 8.8214 +v 9.5398 0.0000 8.8202 +v 9.5521 0.8805 9.0255 +v 9.5332 0.0000 9.0194 +v 9.6720 0.8805 9.0264 +v 9.6913 0.0000 9.0206 +v 1.2967 1.7088 12.6327 +v 1.2947 1.7088 12.8988 +v 1.4938 1.7088 12.9054 +v 1.4958 1.7088 12.6393 +v 1.5119 0.8805 12.6873 +v 1.5105 0.8805 12.8739 +v 1.4939 -0.0000 12.8931 +v 1.4957 -0.0000 12.6517 +v 1.3609 0.8805 12.6823 +v 1.2966 -0.0000 12.6451 +v 1.3595 0.8805 12.8689 +v 1.2948 -0.0000 12.8865 +v 1.7376 1.8182 12.7029 +v 1.7363 1.8182 12.8610 +v 1.9355 1.8182 12.8676 +v 1.9367 1.8182 12.7094 +v 1.9553 0.8805 12.6176 +v 1.9544 0.8805 12.7375 +v 1.9825 -0.0000 12.8676 +v 1.9837 -0.0000 12.7094 +v 1.8044 0.8805 12.6126 +v 1.7846 -0.0000 12.7029 +v 1.8034 0.8805 12.7325 +v 1.7834 -0.0000 12.8610 +v 2.2780 1.4149 12.6063 +v 2.2771 1.4149 12.7262 +v 3.1802 1.4917 12.9073 +v 3.1814 1.4917 12.7491 +v 1.3750 1.5530 12.6893 +v 1.3737 1.5530 12.8475 +v 2.2715 1.2339 12.6061 +v 3.1729 1.2529 12.7488 +v 1.3664 1.3141 12.6890 +v 2.2706 1.2339 12.7260 +v 3.1716 1.2529 12.9070 +v 1.3652 1.3141 12.8472 +v 2.2760 0.5144 12.8687 +v 2.2751 0.5144 12.9886 +v 3.1802 0.5972 12.9073 +v 3.1814 0.5972 12.7491 +v 1.3750 0.6584 12.6893 +v 1.3737 0.6584 12.8475 +v 2.2695 0.3333 12.8685 +v 3.1729 0.3583 12.7488 +v 1.3664 0.4196 12.6890 +v 2.2686 0.3333 12.9884 +v 3.1716 0.3583 12.9070 +v 1.3652 0.4196 12.8472 +v 2.1952 1.8814 12.7164 +v 2.1940 1.8814 12.8746 +v 2.3931 1.8814 12.8812 +v 2.3943 1.8814 12.7230 +v 2.3707 0.8805 12.6690 +v 2.3697 0.8805 12.7889 +v 2.3931 -0.0000 12.8812 +v 2.3943 -0.0000 12.7230 +v 2.2197 0.8805 12.6640 +v 2.1952 -0.0000 12.7164 +v 2.2188 0.8805 12.7839 +v 2.1940 -0.0000 12.8746 +v 2.6435 1.6654 12.7313 +v 2.6423 1.6654 12.8895 +v 2.8414 1.6654 12.8961 +v 2.8426 1.6654 12.7379 +v 2.7960 0.8805 12.8518 +v 2.7951 0.8805 12.9717 +v 2.8414 -0.0000 12.8960 +v 2.8426 -0.0000 12.7379 +v 2.6451 0.8805 12.8469 +v 2.6435 -0.0000 12.7313 +v 2.6442 0.8805 12.9668 +v 2.6423 -0.0000 12.8895 +v 3.0438 1.7611 12.6863 +v 3.0417 1.7611 12.9609 +v 3.2408 1.7611 12.9675 +v 3.2429 1.7611 12.6929 +v 3.1881 0.8805 12.7685 +v 3.1872 0.8805 12.8884 +v 3.2412 -0.0000 12.9093 +v 3.2424 -0.0000 12.7511 +v 3.0371 0.8805 12.7635 +v 3.0433 -0.0000 12.7445 +v 3.0362 0.8805 12.8834 +v 3.0421 -0.0000 12.9027 +v 3.3793 1.7088 12.6327 +v 3.3773 1.7088 12.8988 +v 3.5764 1.7088 12.9054 +v 3.5784 1.7088 12.6393 +v 3.5945 0.8805 12.6873 +v 3.5931 0.8805 12.8739 +v 3.5765 -0.0000 12.8930 +v 3.5783 -0.0000 12.6517 +v 3.4435 0.8805 12.6823 +v 3.3792 -0.0000 12.6451 +v 3.4421 0.8805 12.8689 +v 3.3774 -0.0000 12.8865 +v 3.8201 1.8182 12.7029 +v 3.8189 1.8182 12.8610 +v 4.0181 1.8182 12.8676 +v 4.0193 1.8182 12.7094 +v 4.0379 0.8805 12.6176 +v 4.0370 0.8805 12.7375 +v 4.0651 -0.0000 12.8676 +v 4.0663 -0.0000 12.7094 +v 3.8869 0.8805 12.6126 +v 3.8672 -0.0000 12.7029 +v 3.8860 0.8805 12.7325 +v 3.8659 -0.0000 12.8610 +v 4.3606 1.4149 12.6063 +v 4.3597 1.4149 12.7262 +v 5.2628 1.4917 12.9073 +v 5.2640 1.4917 12.7491 +v 3.4576 1.5530 12.6893 +v 3.4563 1.5530 12.8475 +v 4.3541 1.2339 12.6061 +v 5.2555 1.2529 12.7488 +v 3.4490 1.3141 12.6890 +v 4.3532 1.2339 12.7260 +v 5.2542 1.2529 12.9070 +v 3.4478 1.3141 12.8472 +v 4.3586 0.5144 12.8687 +v 4.3577 0.5144 12.9886 +v 5.2628 0.5972 12.9073 +v 5.2640 0.5972 12.7491 +v 3.4576 0.6584 12.6893 +v 3.4563 0.6584 12.8475 +v 4.3521 0.3333 12.8685 +v 5.2555 0.3583 12.7488 +v 3.4490 0.4196 12.6890 +v 4.3512 0.3333 12.9884 +v 5.2542 0.3583 12.9070 +v 3.4478 0.4196 12.8472 +v 4.2778 1.8814 12.7164 +v 4.2766 1.8814 12.8746 +v 4.4757 1.8814 12.8812 +v 4.4769 1.8814 12.7230 +v 4.4533 0.8805 12.6690 +v 4.4523 0.8805 12.7889 +v 4.4757 -0.0000 12.8812 +v 4.4769 -0.0000 12.7230 +v 4.3023 0.8805 12.6640 +v 4.2778 -0.0000 12.7164 +v 4.3014 0.8805 12.7839 +v 4.2766 -0.0000 12.8746 +v 4.7261 1.6654 12.7313 +v 4.7249 1.6654 12.8895 +v 4.9240 1.6654 12.8961 +v 4.9252 1.6654 12.7379 +v 4.8786 0.8805 12.8518 +v 4.8777 0.8805 12.9717 +v 4.9240 -0.0000 12.8960 +v 4.9252 -0.0000 12.7379 +v 4.7277 0.8805 12.8468 +v 4.7261 -0.0000 12.7313 +v 4.7267 0.8805 12.9668 +v 4.7249 -0.0000 12.8895 +v 5.1263 1.7611 12.6863 +v 5.1242 1.7611 12.9609 +v 5.3234 1.7611 12.9675 +v 5.3255 1.7611 12.6929 +v 5.2707 0.8805 12.7685 +v 5.2698 0.8805 12.8884 +v 5.3238 -0.0000 12.9093 +v 5.3250 -0.0000 12.7511 +v 5.1197 0.8805 12.7635 +v 5.1259 -0.0000 12.7445 +v 5.1188 0.8805 12.8834 +v 5.1247 -0.0000 12.9027 +v -10.4130 1.7088 12.6327 +v -10.4151 1.7088 12.8988 +v -10.2159 1.7088 12.9054 +v -10.2139 1.7088 12.6393 +v -10.1979 0.8805 12.6873 +v -10.1993 0.8805 12.8739 +v -10.2159 -0.0000 12.8931 +v -10.2140 -0.0000 12.6517 +v -10.3488 0.8805 12.6823 +v -10.4131 -0.0000 12.6451 +v -10.3502 0.8805 12.8689 +v -10.4150 -0.0000 12.8865 +v -9.9722 1.8182 12.7029 +v -9.9734 1.8182 12.8610 +v -9.7743 1.8182 12.8676 +v -9.7731 1.8182 12.7094 +v -9.7545 0.8805 12.6176 +v -9.7554 0.8805 12.7375 +v -9.7273 -0.0000 12.8676 +v -9.7261 -0.0000 12.7095 +v -9.9054 0.8805 12.6126 +v -9.9252 -0.0000 12.7029 +v -9.9063 0.8805 12.7325 +v -9.9264 -0.0000 12.8610 +v -9.4318 1.4149 12.6063 +v -9.4327 1.4149 12.7262 +v -8.5296 1.4917 12.9073 +v -8.5284 1.4917 12.7491 +v -10.3348 1.5530 12.6893 +v -10.3360 1.5530 12.8475 +v -9.4382 1.2339 12.6061 +v -8.5369 1.2529 12.7488 +v -10.3433 1.3141 12.6890 +v -9.4391 1.2339 12.7260 +v -8.5381 1.2529 12.9070 +v -10.3445 1.3141 12.8472 +v -9.4338 0.5144 12.8687 +v -9.4347 0.5144 12.9886 +v -8.5296 0.5972 12.9073 +v -8.5284 0.5972 12.7491 +v -10.3348 0.6584 12.6893 +v -10.3360 0.6584 12.8475 +v -9.4402 0.3333 12.8685 +v -8.5369 0.3583 12.7488 +v -10.3433 0.4196 12.6890 +v -9.4411 0.3333 12.9884 +v -8.5381 0.3583 12.9070 +v -10.3445 0.4196 12.8472 +v -9.5146 1.8814 12.7164 +v -9.5158 1.8814 12.8746 +v -9.3166 1.8814 12.8812 +v -9.3154 1.8814 12.7230 +v -9.3391 0.8805 12.6690 +v -9.3400 0.8805 12.7889 +v -9.3166 -0.0000 12.8812 +v -9.3154 -0.0000 12.7230 +v -9.4900 0.8805 12.6640 +v -9.5146 -0.0000 12.7164 +v -9.4910 0.8805 12.7839 +v -9.5158 -0.0000 12.8746 +v -9.0663 1.6654 12.7313 +v -9.0675 1.6654 12.8895 +v -8.8683 1.6654 12.8961 +v -8.8671 1.6654 12.7379 +v -8.9137 0.8805 12.8518 +v -8.9146 0.8805 12.9717 +v -8.8683 -0.0000 12.8961 +v -8.8671 -0.0000 12.7379 +v -9.0647 0.8805 12.8469 +v -9.0663 -0.0000 12.7313 +v -9.0656 0.8805 12.9668 +v -9.0675 -0.0000 12.8895 +v -8.6660 1.7611 12.6864 +v -8.6681 1.7611 12.9609 +v -8.4690 1.7611 12.9675 +v -8.4669 1.7611 12.6929 +v -8.5217 0.8805 12.7685 +v -8.5226 0.8805 12.8884 +v -8.4685 -0.0000 12.9093 +v -8.4673 -0.0000 12.7511 +v -8.6726 0.8805 12.7635 +v -8.6665 -0.0000 12.7445 +v -8.6735 0.8805 12.8834 +v -8.6677 -0.0000 12.9027 +v -8.3304 1.7088 12.6327 +v -8.3325 1.7088 12.8988 +v -8.1333 1.7088 12.9054 +v -8.1313 1.7088 12.6393 +v -8.1153 0.8805 12.6873 +v -8.1167 0.8805 12.8739 +v -8.1332 -0.0000 12.8931 +v -8.1314 -0.0000 12.6517 +v -8.2662 0.8805 12.6823 +v -8.3305 -0.0000 12.6451 +v -8.2676 0.8805 12.8689 +v -8.3324 -0.0000 12.8865 +v -7.8896 1.8182 12.7029 +v -7.8908 1.8182 12.8610 +v -7.6917 1.8182 12.8676 +v -7.6905 1.8182 12.7094 +v -7.6718 0.8805 12.6176 +v -7.6728 0.8805 12.7375 +v -7.6447 -0.0000 12.8676 +v -7.6435 -0.0000 12.7095 +v -7.8228 0.8805 12.6126 +v -7.8426 -0.0000 12.7029 +v -7.8237 0.8805 12.7325 +v -7.8438 -0.0000 12.8610 +v -7.3492 1.4149 12.6063 +v -7.3501 1.4149 12.7262 +v -6.4470 1.4917 12.9073 +v -6.4458 1.4917 12.7491 +v -8.2522 1.5530 12.6893 +v -8.2534 1.5530 12.8475 +v -7.3556 1.2339 12.6061 +v -6.4543 1.2529 12.7488 +v -8.2607 1.3141 12.6890 +v -7.3565 1.2339 12.7260 +v -6.4555 1.2529 12.9070 +v -8.2619 1.3141 12.8472 +v -7.3511 0.5144 12.8687 +v -7.3521 0.5144 12.9886 +v -6.4470 0.5972 12.9073 +v -6.4458 0.5972 12.7491 +v -8.2522 0.6584 12.6893 +v -8.2534 0.6584 12.8475 +v -7.3576 0.3333 12.8685 +v -6.4543 0.3583 12.7488 +v -8.2607 0.4196 12.6890 +v -7.3585 0.3333 12.9884 +v -6.4555 0.3583 12.9070 +v -8.2619 0.4196 12.8472 +v -7.4320 1.8814 12.7164 +v -7.4332 1.8814 12.8746 +v -7.2340 1.8814 12.8812 +v -7.2328 1.8814 12.7230 +v -7.2565 0.8805 12.6690 +v -7.2574 0.8805 12.7889 +v -7.2340 -0.0000 12.8812 +v -7.2328 -0.0000 12.7230 +v -7.4074 0.8805 12.6640 +v -7.4320 -0.0000 12.7164 +v -7.4084 0.8805 12.7839 +v -7.4332 -0.0000 12.8746 +v -6.9837 1.6654 12.7313 +v -6.9849 1.6654 12.8895 +v -6.7857 1.6654 12.8961 +v -6.7845 1.6654 12.7379 +v -6.8311 0.8805 12.8518 +v -6.8320 0.8805 12.9717 +v -6.7857 -0.0000 12.8961 +v -6.7845 -0.0000 12.7379 +v -6.9821 0.8805 12.8469 +v -6.9837 -0.0000 12.7313 +v -6.9830 0.8805 12.9668 +v -6.9849 -0.0000 12.8895 +v -6.5834 1.7611 12.6864 +v -6.5855 1.7611 12.9609 +v -6.3864 1.7611 12.9675 +v -6.3843 1.7611 12.6929 +v -6.4391 0.8805 12.7685 +v -6.4400 0.8805 12.8884 +v -6.3859 -0.0000 12.9093 +v -6.3847 -0.0000 12.7511 +v -6.5900 0.8805 12.7635 +v -6.5838 -0.0000 12.7445 +v -6.5909 0.8805 12.8834 +v -6.5851 -0.0000 12.9027 +v -14.4004 1.7088 12.6327 +v -14.4025 1.7088 12.8988 +v -14.2033 1.7088 12.9054 +v -14.2013 1.7088 12.6393 +v -14.1852 0.8805 12.6873 +v -14.1867 0.8805 12.8739 +v -14.2032 -0.0000 12.8931 +v -14.2014 -0.0000 12.6517 +v -14.3362 0.8805 12.6823 +v -14.4005 -0.0000 12.6451 +v -14.3376 0.8805 12.8689 +v -14.4024 -0.0000 12.8865 +v -13.9596 1.8182 12.7029 +v -13.9608 1.8182 12.8610 +v -13.7617 1.8182 12.8676 +v -13.7605 1.8182 12.7094 +v -13.7418 0.8805 12.6176 +v -13.7428 0.8805 12.7375 +v -13.7147 -0.0000 12.8676 +v -13.7134 -0.0000 12.7095 +v -13.8928 0.8805 12.6126 +v -13.9126 -0.0000 12.7029 +v -13.8937 0.8805 12.7325 +v -13.9138 -0.0000 12.8610 +v -13.4191 1.4149 12.6063 +v -13.4201 1.4149 12.7262 +v -12.5170 1.4917 12.9073 +v -12.5157 1.4917 12.7491 +v -14.3222 1.5530 12.6893 +v -14.3234 1.5530 12.8475 +v -13.4256 1.2339 12.6061 +v -12.5243 1.2529 12.7488 +v -14.3307 1.3141 12.6890 +v -13.4265 1.2339 12.7260 +v -12.5255 1.2529 12.9070 +v -14.3319 1.3141 12.8472 +v -13.4211 0.5144 12.8687 +v -13.4221 0.5144 12.9886 +v -12.5170 0.5972 12.9073 +v -12.5157 0.5972 12.7491 +v -14.3222 0.6584 12.6893 +v -14.3234 0.6584 12.8475 +v -13.4276 0.3333 12.8685 +v -12.5243 0.3583 12.7488 +v -14.3307 0.4196 12.6890 +v -13.4285 0.3333 12.9884 +v -12.5255 0.3583 12.9070 +v -14.3319 0.4196 12.8472 +v -13.5019 1.8814 12.7164 +v -13.5031 1.8814 12.8746 +v -13.3040 1.8814 12.8812 +v -13.3028 1.8814 12.7230 +v -13.3265 0.8805 12.6690 +v -13.3274 0.8805 12.7889 +v -13.3040 -0.0000 12.8812 +v -13.3028 -0.0000 12.7230 +v -13.4774 0.8805 12.6640 +v -13.5019 -0.0000 12.7164 +v -13.4784 0.8805 12.7839 +v -13.5031 -0.0000 12.8746 +v -13.0536 1.6654 12.7313 +v -13.0549 1.6654 12.8895 +v -12.8557 1.6654 12.8961 +v -12.8545 1.6654 12.7379 +v -12.9011 0.8805 12.8518 +v -12.9020 0.8805 12.9717 +v -12.8557 -0.0000 12.8961 +v -12.8545 -0.0000 12.7379 +v -13.0521 0.8805 12.8469 +v -13.0536 -0.0000 12.7313 +v -13.0530 0.8805 12.9668 +v -13.0549 -0.0000 12.8895 +v -12.6534 1.7611 12.6864 +v -12.6555 1.7611 12.9609 +v -12.4564 1.7611 12.9675 +v -12.4543 1.7611 12.6929 +v -12.5090 0.8805 12.7685 +v -12.5100 0.8805 12.8884 +v -12.4559 -0.0000 12.9093 +v -12.4547 -0.0000 12.7511 +v -12.6600 0.8805 12.7635 +v -12.6538 -0.0000 12.7445 +v -12.6609 0.8805 12.8834 +v -12.6550 -0.0000 12.9027 +v -12.3178 1.7088 12.6327 +v -12.3199 1.7088 12.8988 +v -12.1207 1.7088 12.9054 +v -12.1187 1.7088 12.6393 +v -12.1026 0.8805 12.6873 +v -12.1041 0.8805 12.8739 +v -12.1206 -0.0000 12.8931 +v -12.1188 -0.0000 12.6517 +v -12.2536 0.8805 12.6823 +v -12.3179 -0.0000 12.6451 +v -12.2550 0.8805 12.8689 +v -12.3198 -0.0000 12.8865 +v -11.8770 1.8182 12.7029 +v -11.8782 1.8182 12.8610 +v -11.6791 1.8182 12.8676 +v -11.6779 1.8182 12.7094 +v -11.6592 0.8805 12.6176 +v -11.6602 0.8805 12.7375 +v -11.6321 -0.0000 12.8676 +v -11.6308 -0.0000 12.7095 +v -11.8102 0.8805 12.6126 +v -11.8300 -0.0000 12.7029 +v -11.8111 0.8805 12.7325 +v -11.8312 -0.0000 12.8610 +v -11.3365 1.4149 12.6063 +v -11.3375 1.4149 12.7262 +v -10.4344 1.4917 12.9073 +v -10.4332 1.4917 12.7491 +v -12.2396 1.5530 12.6893 +v -12.2408 1.5530 12.8475 +v -11.3430 1.2339 12.6061 +v -10.4417 1.2529 12.7488 +v -12.2481 1.3141 12.6890 +v -11.3439 1.2339 12.7260 +v -10.4429 1.2529 12.9070 +v -12.2493 1.3141 12.8472 +v -11.3385 0.5144 12.8687 +v -11.3395 0.5144 12.9886 +v -10.4344 0.5972 12.9073 +v -10.4332 0.5972 12.7491 +v -12.2396 0.6584 12.6893 +v -12.2408 0.6584 12.8475 +v -11.3450 0.3333 12.8685 +v -10.4417 0.3583 12.7488 +v -12.2481 0.4196 12.6890 +v -11.3459 0.3333 12.9884 +v -10.4429 0.3583 12.9070 +v -12.2493 0.4196 12.8472 +v -11.4193 1.8814 12.7164 +v -11.4205 1.8814 12.8746 +v -11.2214 1.8814 12.8812 +v -11.2202 1.8814 12.7230 +v -11.2439 0.8805 12.6690 +v -11.2448 0.8805 12.7889 +v -11.2214 -0.0000 12.8812 +v -11.2202 -0.0000 12.7230 +v -11.3948 0.8805 12.6640 +v -11.4193 -0.0000 12.7164 +v -11.3958 0.8805 12.7839 +v -11.4205 -0.0000 12.8746 +v -10.9711 1.6654 12.7313 +v -10.9723 1.6654 12.8895 +v -10.7731 1.6654 12.8961 +v -10.7719 1.6654 12.7379 +v -10.8185 0.8805 12.8518 +v -10.8194 0.8805 12.9717 +v -10.7731 -0.0000 12.8961 +v -10.7719 -0.0000 12.7379 +v -10.9695 0.8805 12.8469 +v -10.9711 -0.0000 12.7313 +v -10.9704 0.8805 12.9668 +v -10.9723 -0.0000 12.8895 +v -10.5708 1.7611 12.6864 +v -10.5729 1.7611 12.9609 +v -10.3738 1.7611 12.9675 +v -10.3717 1.7611 12.6929 +v -10.4264 0.8805 12.7685 +v -10.4274 0.8805 12.8884 +v -10.3733 -0.0000 12.9093 +v -10.3721 -0.0000 12.7511 +v -10.5774 0.8805 12.7635 +v -10.5712 -0.0000 12.7445 +v -10.5783 0.8805 12.8834 +v -10.5724 -0.0000 12.9027 +v -16.5316 1.7088 12.6327 +v -16.5337 1.7088 12.8988 +v -16.3345 1.7088 12.9054 +v -16.3325 1.7088 12.6393 +v -16.3164 0.8805 12.6873 +v -16.3179 0.8805 12.8739 +v -16.3344 -0.0000 12.8931 +v -16.3326 -0.0000 12.6517 +v -16.4674 0.8805 12.6823 +v -16.5317 -0.0000 12.6451 +v -16.4688 0.8805 12.8689 +v -16.5336 -0.0000 12.8865 +v -16.0908 1.8182 12.7029 +v -16.0920 1.8182 12.8610 +v -15.8929 1.8182 12.8676 +v -15.8917 1.8182 12.7094 +v -15.8730 0.8805 12.6176 +v -15.8740 0.8805 12.7375 +v -15.8459 -0.0000 12.8676 +v -15.8446 -0.0000 12.7095 +v -16.0240 0.8805 12.6126 +v -16.0438 -0.0000 12.7029 +v -16.0249 0.8805 12.7325 +v -16.0450 -0.0000 12.8610 +v -15.5503 1.4149 12.6063 +v -15.5513 1.4149 12.7262 +v -14.6482 1.4917 12.9073 +v -14.6470 1.4917 12.7491 +v -16.4534 1.5530 12.6893 +v -16.4546 1.5530 12.8475 +v -15.5568 1.2339 12.6061 +v -14.6555 1.2529 12.7488 +v -16.4619 1.3141 12.6890 +v -15.5577 1.2339 12.7260 +v -14.6567 1.2529 12.9070 +v -16.4631 1.3141 12.8472 +v -15.5523 0.5144 12.8687 +v -15.5533 0.5144 12.9886 +v -14.6482 0.5972 12.9073 +v -14.6470 0.5972 12.7491 +v -16.4534 0.6584 12.6893 +v -16.4546 0.6584 12.8475 +v -15.5588 0.3333 12.8685 +v -14.6555 0.3583 12.7488 +v -16.4619 0.4196 12.6890 +v -15.5597 0.3333 12.9884 +v -14.6567 0.3583 12.9070 +v -16.4631 0.4196 12.8472 +v -15.6331 1.8814 12.7164 +v -15.6343 1.8814 12.8746 +v -15.4352 1.8814 12.8812 +v -15.4340 1.8814 12.7230 +v -15.4577 0.8805 12.6690 +v -15.4586 0.8805 12.7889 +v -15.4352 -0.0000 12.8812 +v -15.4340 -0.0000 12.7230 +v -15.6086 0.8805 12.6640 +v -15.6331 -0.0000 12.7164 +v -15.6096 0.8805 12.7839 +v -15.6343 -0.0000 12.8746 +v -15.1849 1.6654 12.7313 +v -15.1861 1.6654 12.8895 +v -14.9869 1.6654 12.8961 +v -14.9857 1.6654 12.7379 +v -15.0323 0.8805 12.8518 +v -15.0332 0.8805 12.9717 +v -14.9869 -0.0000 12.8961 +v -14.9857 -0.0000 12.7379 +v -15.1833 0.8805 12.8469 +v -15.1849 -0.0000 12.7313 +v -15.1842 0.8805 12.9668 +v -15.1861 -0.0000 12.8895 +v -14.7846 1.7611 12.6864 +v -14.7867 1.7611 12.9609 +v -14.5876 1.7611 12.9675 +v -14.5855 1.7611 12.6929 +v -14.6402 0.8805 12.7685 +v -14.6412 0.8805 12.8884 +v -14.5871 -0.0000 12.9093 +v -14.5859 -0.0000 12.7511 +v -14.7912 0.8805 12.7635 +v -14.7850 -0.0000 12.7445 +v -14.7921 0.8805 12.8834 +v -14.7862 -0.0000 12.9027 +v -16.1976 1.7088 8.6138 +v -16.4638 1.7088 8.6118 +v -16.4703 1.7088 8.8109 +v -16.2042 1.7088 8.8129 +v -16.2523 0.8805 8.8290 +v -16.4388 0.8805 8.8276 +v -16.4580 0.0000 8.8110 +v -16.2166 0.0000 8.8129 +v -16.2473 0.8805 8.6781 +v -16.2100 0.0000 8.6137 +v -16.4338 0.8805 8.6766 +v -16.4514 0.0000 8.6119 +v -16.2678 1.8182 9.0547 +v -16.4259 1.8182 9.0534 +v -16.4325 1.8182 9.2526 +v -16.2744 1.8182 9.2538 +v -16.1825 0.8805 9.2724 +v -16.3024 0.8805 9.2715 +v -16.4325 -0.0000 9.2996 +v -16.2744 -0.0000 9.3008 +v -16.1775 0.8805 9.1215 +v -16.2678 0.0000 9.1017 +v -16.2974 0.8805 9.1205 +v -16.4259 0.0000 9.1005 +v -16.1713 1.4149 9.5951 +v -16.2912 1.4149 9.5942 +v -16.4722 1.4917 10.4973 +v -16.3140 1.4917 10.4985 +v -16.2542 1.5530 8.6921 +v -16.4124 1.5530 8.6909 +v -16.1710 1.2339 9.5886 +v -16.3137 1.2529 10.4900 +v -16.2539 1.3141 8.6835 +v -16.2909 1.2339 9.5877 +v -16.4719 1.2529 10.4888 +v -16.4121 1.3141 8.6823 +v -16.4336 0.5144 9.5931 +v -16.5535 0.5144 9.5922 +v -16.4722 0.5972 10.4973 +v -16.3140 0.5972 10.4985 +v -16.2542 0.6584 8.6921 +v -16.4124 0.6584 8.6909 +v -16.4334 0.3333 9.5866 +v -16.3137 0.3583 10.4900 +v -16.2539 0.4196 8.6835 +v -16.5533 0.3333 9.5857 +v -16.4719 0.3583 10.4888 +v -16.4121 0.4196 8.6823 +v -16.2814 1.8814 9.5123 +v -16.4395 1.8814 9.5111 +v -16.4461 1.8814 9.7102 +v -16.2880 1.8814 9.7114 +v -16.2339 0.8805 9.6878 +v -16.3538 0.8805 9.6868 +v -16.4461 -0.0000 9.7102 +v -16.2880 -0.0000 9.7114 +v -16.2289 0.8805 9.5368 +v -16.2814 -0.0000 9.5123 +v -16.3488 0.8805 9.5359 +v -16.4395 -0.0000 9.5111 +v -16.2962 1.6654 9.9606 +v -16.4544 1.6654 9.9594 +v -16.4610 1.6654 10.1585 +v -16.3028 1.6654 10.1597 +v -16.4168 0.8805 10.1131 +v -16.5367 0.8805 10.1122 +v -16.4610 -0.0000 10.1585 +v -16.3028 -0.0000 10.1597 +v -16.4118 0.8805 9.9622 +v -16.2962 -0.0000 9.9606 +v -16.5317 0.8805 9.9613 +v -16.4544 -0.0000 9.9594 +v -16.2513 1.7611 10.3609 +v -16.5258 1.7611 10.3588 +v -16.5324 1.7611 10.5579 +v -16.2579 1.7611 10.5600 +v -16.3334 0.8805 10.5052 +v -16.4533 0.8805 10.5043 +v -16.4742 -0.0000 10.5583 +v -16.3160 -0.0000 10.5595 +v -16.3284 0.8805 10.3542 +v -16.3094 -0.0000 10.3604 +v -16.4483 0.8805 10.3533 +v -16.4676 -0.0000 10.3592 +v -16.1976 1.7088 10.6964 +v -16.4638 1.7088 10.6944 +v -16.4703 1.7088 10.8935 +v -16.2042 1.7088 10.8955 +v -16.2523 0.8805 10.9116 +v -16.4388 0.8805 10.9102 +v -16.4580 -0.0000 10.8936 +v -16.2166 -0.0000 10.8955 +v -16.2473 0.8805 10.7607 +v -16.2100 -0.0000 10.6963 +v -16.4338 0.8805 10.7592 +v -16.4514 -0.0000 10.6945 +v -16.2678 1.8182 11.1373 +v -16.4259 1.8182 11.1361 +v -16.4325 1.8182 11.3352 +v -16.2744 1.8182 11.3364 +v -16.1825 0.8805 11.3550 +v -16.3024 0.8805 11.3541 +v -16.4325 -0.0000 11.3822 +v -16.2744 -0.0000 11.3834 +v -16.1775 0.8805 11.2041 +v -16.2678 -0.0000 11.1843 +v -16.2974 0.8805 11.2031 +v -16.4259 -0.0000 11.1831 +v -16.1713 1.4149 11.6777 +v -16.2912 1.4149 11.6768 +v -16.4722 1.4917 12.5799 +v -16.3140 1.4917 12.5811 +v -16.2542 1.5530 10.7747 +v -16.4124 1.5530 10.7735 +v -16.1710 1.2339 11.6712 +v -16.3137 1.2529 12.5726 +v -16.2539 1.3141 10.7661 +v -16.2909 1.2339 11.6703 +v -16.4719 1.2529 12.5714 +v -16.4121 1.3141 10.7649 +v -16.4336 0.5143 11.6757 +v -16.5535 0.5143 11.6748 +v -16.4722 0.5972 12.5799 +v -16.3140 0.5972 12.5811 +v -16.2542 0.6584 10.7747 +v -16.4124 0.6584 10.7735 +v -16.4334 0.3333 11.6692 +v -16.3137 0.3583 12.5726 +v -16.2539 0.4196 10.7661 +v -16.5533 0.3333 11.6683 +v -16.4719 0.3583 12.5714 +v -16.4121 0.4196 10.7649 +v -16.2814 1.8814 11.5949 +v -16.4395 1.8814 11.5937 +v -16.4461 1.8814 11.7928 +v -16.2880 1.8814 11.7941 +v -16.2339 0.8805 11.7704 +v -16.3538 0.8805 11.7694 +v -16.4461 -0.0000 11.7928 +v -16.2880 -0.0000 11.7941 +v -16.2289 0.8805 11.6194 +v -16.2814 -0.0000 11.5949 +v -16.3488 0.8805 11.6185 +v -16.4395 -0.0000 11.5937 +v -16.2962 1.6654 12.0432 +v -16.4544 1.6654 12.0420 +v -16.4610 1.6654 12.2411 +v -16.3028 1.6654 12.2423 +v -16.4168 0.8805 12.1957 +v -16.5367 0.8805 12.1948 +v -16.4610 -0.0000 12.2411 +v -16.3028 -0.0000 12.2423 +v -16.4118 0.8805 12.0448 +v -16.2962 -0.0000 12.0432 +v -16.5317 0.8805 12.0439 +v -16.4544 -0.0000 12.0420 +v -16.2513 1.7611 12.4435 +v -16.5258 1.7611 12.4414 +v -16.5324 1.7611 12.6405 +v -16.2579 1.7611 12.6426 +v -16.3334 0.8805 12.5878 +v -16.4533 0.8805 12.5869 +v -16.4742 -0.0000 12.6409 +v -16.3160 -0.0000 12.6422 +v -16.3284 0.8805 12.4368 +v -16.3094 -0.0000 12.4430 +v -16.4483 0.8805 12.4359 +v -16.4676 -0.0000 12.4418 +v -16.1976 1.7088 4.6264 +v -16.4638 1.7088 4.6244 +v -16.4703 1.7088 4.8235 +v -16.2042 1.7088 4.8256 +v -16.2523 0.8805 4.8416 +v -16.4389 0.8805 4.8402 +v -16.4580 0.0000 4.8236 +v -16.2166 0.0000 4.8255 +v -16.2473 0.8805 4.6907 +v -16.2100 0.0000 4.6263 +v -16.4338 0.8805 4.6892 +v -16.4514 0.0000 4.6245 +v -16.2678 1.8182 5.0673 +v -16.4259 1.8182 5.0661 +v -16.4325 1.8182 5.2652 +v -16.2744 1.8182 5.2664 +v -16.1825 0.8805 5.2850 +v -16.3024 0.8805 5.2841 +v -16.4325 0.0000 5.3122 +v -16.2744 0.0000 5.3134 +v -16.1775 0.8805 5.1341 +v -16.2678 0.0000 5.1143 +v -16.2974 0.8805 5.1332 +v -16.4259 0.0000 5.1131 +v -16.1713 1.4149 5.6077 +v -16.2912 1.4149 5.6068 +v -16.4722 1.4917 6.5099 +v -16.3140 1.4917 6.5111 +v -16.2542 1.5530 4.7047 +v -16.4124 1.5530 4.7035 +v -16.1710 1.2339 5.6013 +v -16.3137 1.2529 6.5026 +v -16.2539 1.3141 4.6961 +v -16.2909 1.2339 5.6003 +v -16.4719 1.2529 6.5014 +v -16.4121 1.3141 4.6949 +v -16.4336 0.5144 5.6057 +v -16.5535 0.5144 5.6048 +v -16.4722 0.5972 6.5099 +v -16.3140 0.5972 6.5111 +v -16.2542 0.6584 4.7047 +v -16.4124 0.6584 4.7035 +v -16.4334 0.3333 5.5993 +v -16.3137 0.3583 6.5026 +v -16.2539 0.4196 4.6961 +v -16.5533 0.3333 5.5983 +v -16.4719 0.3583 6.5014 +v -16.4121 0.4196 4.6949 +v -16.2814 1.8814 5.5249 +v -16.4395 1.8814 5.5237 +v -16.4461 1.8814 5.7229 +v -16.2880 1.8814 5.7241 +v -16.2339 0.8805 5.7004 +v -16.3538 0.8805 5.6995 +v -16.4461 -0.0000 5.7229 +v -16.2880 -0.0000 5.7241 +v -16.2289 0.8805 5.5494 +v -16.2814 0.0000 5.5249 +v -16.3488 0.8805 5.5485 +v -16.4395 0.0000 5.5237 +v -16.2962 1.6654 5.9732 +v -16.4544 1.6654 5.9720 +v -16.4610 1.6654 6.1711 +v -16.3028 1.6654 6.1724 +v -16.4168 0.8805 6.1258 +v -16.5367 0.8805 6.1248 +v -16.4610 -0.0000 6.1711 +v -16.3028 -0.0000 6.1724 +v -16.4118 0.8805 5.9748 +v -16.2962 -0.0000 5.9732 +v -16.5317 0.8805 5.9739 +v -16.4544 -0.0000 5.9720 +v -16.2513 1.7611 6.3735 +v -16.5258 1.7611 6.3714 +v -16.5324 1.7611 6.5705 +v -16.2579 1.7611 6.5726 +v -16.3334 0.8805 6.5178 +v -16.4533 0.8805 6.5169 +v -16.4742 -0.0000 6.5710 +v -16.3160 -0.0000 6.5722 +v -16.3284 0.8805 6.3669 +v -16.3094 -0.0000 6.3730 +v -16.4483 0.8805 6.3659 +v -16.4676 -0.0000 6.3718 +v -16.1976 1.7088 6.7090 +v -16.4638 1.7088 6.7070 +v -16.4703 1.7088 6.9061 +v -16.2042 1.7088 6.9082 +v -16.2523 0.8805 6.9242 +v -16.4388 0.8805 6.9228 +v -16.4580 -0.0000 6.9062 +v -16.2166 -0.0000 6.9081 +v -16.2473 0.8805 6.7733 +v -16.2100 -0.0000 6.7089 +v -16.4338 0.8805 6.7718 +v -16.4514 -0.0000 6.7071 +v -16.2678 1.8182 7.1499 +v -16.4259 1.8182 7.1487 +v -16.4325 1.8182 7.3478 +v -16.2744 1.8182 7.3490 +v -16.1825 0.8805 7.3676 +v -16.3024 0.8805 7.3667 +v -16.4325 -0.0000 7.3948 +v -16.2744 -0.0000 7.3960 +v -16.1775 0.8805 7.2167 +v -16.2678 -0.0000 7.1969 +v -16.2974 0.8805 7.2158 +v -16.4259 -0.0000 7.1957 +v -16.1713 1.4149 7.6903 +v -16.2912 1.4149 7.6894 +v -16.4722 1.4917 8.5925 +v -16.3140 1.4917 8.5937 +v -16.2542 1.5530 6.7873 +v -16.4124 1.5530 6.7861 +v -16.1710 1.2339 7.6839 +v -16.3137 1.2529 8.5852 +v -16.2539 1.3141 6.7788 +v -16.2909 1.2339 7.6829 +v -16.4719 1.2529 8.5840 +v -16.4121 1.3141 6.7775 +v -16.4336 0.5144 7.6883 +v -16.5535 0.5144 7.6874 +v -16.4722 0.5972 8.5925 +v -16.3140 0.5972 8.5937 +v -16.2542 0.6584 6.7873 +v -16.4124 0.6584 6.7861 +v -16.4334 0.3333 7.6819 +v -16.3137 0.3583 8.5852 +v -16.2539 0.4196 6.7788 +v -16.5533 0.3333 7.6809 +v -16.4719 0.3583 8.5840 +v -16.4121 0.4196 6.7775 +v -16.2814 1.8814 7.6075 +v -16.4395 1.8814 7.6063 +v -16.4461 1.8814 7.8055 +v -16.2880 1.8814 7.8067 +v -16.2339 0.8805 7.7830 +v -16.3538 0.8805 7.7821 +v -16.4461 -0.0000 7.8055 +v -16.2880 -0.0000 7.8067 +v -16.2289 0.8805 7.6320 +v -16.2814 -0.0000 7.6075 +v -16.3488 0.8805 7.6311 +v -16.4395 -0.0000 7.6063 +v -16.2962 1.6654 8.0558 +v -16.4544 1.6654 8.0546 +v -16.4610 1.6654 8.2537 +v -16.3028 1.6654 8.2550 +v -16.4168 0.8805 8.2084 +v -16.5367 0.8805 8.2074 +v -16.4610 0.0000 8.2537 +v -16.3028 0.0000 8.2550 +v -16.4118 0.8805 8.0574 +v -16.2962 -0.0000 8.0558 +v -16.5317 0.8805 8.0565 +v -16.4544 -0.0000 8.0546 +v -16.2513 1.7611 8.4561 +v -16.5258 1.7611 8.4540 +v -16.5324 1.7611 8.6531 +v -16.2579 1.7611 8.6552 +v -16.3334 0.8805 8.6004 +v -16.4533 0.8805 8.5995 +v -16.4742 0.0000 8.6536 +v -16.3160 0.0000 8.6548 +v -16.3284 0.8805 8.4495 +v -16.3094 0.0000 8.4556 +v -16.4483 0.8805 8.4485 +v -16.4676 0.0000 8.4544 +v -16.1976 1.7088 2.4952 +v -16.4638 1.7088 2.4932 +v -16.4703 1.7088 2.6923 +v -16.2042 1.7088 2.6944 +v -16.2523 0.8805 2.7104 +v -16.4389 0.8805 2.7090 +v -16.4580 0.0000 2.6924 +v -16.2166 0.0000 2.6943 +v -16.2473 0.8805 2.5595 +v -16.2100 0.0000 2.4951 +v -16.4338 0.8805 2.5580 +v -16.4514 0.0000 2.4933 +v -16.2678 1.8182 2.9361 +v -16.4259 1.8182 2.9349 +v -16.4325 1.8182 3.1340 +v -16.2744 1.8182 3.1352 +v -16.1825 0.8805 3.1538 +v -16.3024 0.8805 3.1529 +v -16.4325 0.0000 3.1810 +v -16.2744 0.0000 3.1822 +v -16.1775 0.8805 3.0029 +v -16.2678 0.0000 2.9831 +v -16.2974 0.8805 3.0020 +v -16.4259 0.0000 2.9819 +v -16.1713 1.4149 3.4765 +v -16.2912 1.4149 3.4756 +v -16.4722 1.4917 4.3787 +v -16.3140 1.4917 4.3799 +v -16.2542 1.5530 2.5735 +v -16.4124 1.5530 2.5723 +v -16.1710 1.2339 3.4701 +v -16.3137 1.2529 4.3714 +v -16.2539 1.3141 2.5649 +v -16.2909 1.2339 3.4691 +v -16.4719 1.2529 4.3702 +v -16.4121 1.3141 2.5637 +v -16.4336 0.5144 3.4745 +v -16.5535 0.5144 3.4736 +v -16.4722 0.5972 4.3787 +v -16.3140 0.5972 4.3799 +v -16.2542 0.6584 2.5735 +v -16.4124 0.6584 2.5723 +v -16.4334 0.3333 3.4681 +v -16.3137 0.3583 4.3714 +v -16.2539 0.4196 2.5649 +v -16.5533 0.3333 3.4671 +v -16.4719 0.3583 4.3702 +v -16.4121 0.4196 2.5637 +v -16.2814 1.8814 3.3937 +v -16.4395 1.8814 3.3925 +v -16.4461 1.8814 3.5917 +v -16.2880 1.8814 3.5929 +v -16.2339 0.8805 3.5692 +v -16.3538 0.8805 3.5683 +v -16.4461 0.0000 3.5917 +v -16.2880 0.0000 3.5929 +v -16.2289 0.8805 3.4182 +v -16.2814 0.0000 3.3937 +v -16.3488 0.8805 3.4173 +v -16.4395 0.0000 3.3925 +v -16.2962 1.6654 3.8420 +v -16.4544 1.6654 3.8408 +v -16.4610 1.6654 4.0399 +v -16.3028 1.6654 4.0412 +v -16.4168 0.8805 3.9945 +v -16.5367 0.8805 3.9936 +v -16.4610 0.0000 4.0399 +v -16.3028 0.0000 4.0412 +v -16.4118 0.8805 3.8436 +v -16.2962 0.0000 3.8420 +v -16.5317 0.8805 3.8427 +v -16.4544 0.0000 3.8408 +v -16.2513 1.7611 4.2423 +v -16.5258 1.7611 4.2402 +v -16.5324 1.7611 4.4393 +v -16.2579 1.7611 4.4414 +v -16.3334 0.8805 4.3866 +v -16.4533 0.8805 4.3857 +v -16.4742 0.0000 4.4398 +v -16.3160 0.0000 4.4410 +v -16.3284 0.8805 4.2357 +v -16.3094 0.0000 4.2418 +v -16.4483 0.8805 4.2347 +v -16.4676 0.0000 4.2406 +v -16.1976 1.7088 -1.5986 +v -16.4638 1.7088 -1.6006 +v -16.4703 1.7088 -1.4015 +v -16.2042 1.7088 -1.3994 +v -16.2523 0.8805 -1.3834 +v -16.4389 0.8805 -1.3848 +v -16.4580 0.0000 -1.4014 +v -16.2166 0.0000 -1.3995 +v -16.2473 0.8805 -1.5343 +v -16.2100 0.0000 -1.5987 +v -16.4338 0.8805 -1.5358 +v -16.4514 0.0000 -1.6005 +v -16.2678 1.8182 -1.1577 +v -16.4259 1.8182 -1.1589 +v -16.4325 1.8182 -0.9598 +v -16.2744 1.8182 -0.9586 +v -16.1825 0.8805 -0.9400 +v -16.3024 0.8805 -0.9409 +v -16.4325 0.0000 -0.9128 +v -16.2744 0.0000 -0.9116 +v -16.1775 0.8805 -1.0909 +v -16.2678 0.0000 -1.1107 +v -16.2974 0.8805 -1.0918 +v -16.4259 0.0000 -1.1119 +v -16.1713 1.4149 -0.6173 +v -16.2912 1.4149 -0.6182 +v -16.4722 1.4917 0.2849 +v -16.3140 1.4917 0.2861 +v -16.2542 1.5530 -1.5203 +v -16.4124 1.5530 -1.5215 +v -16.1710 1.2339 -0.6237 +v -16.3137 1.2529 0.2776 +v -16.2539 1.3141 -1.5289 +v -16.2909 1.2339 -0.6247 +v -16.4719 1.2529 0.2764 +v -16.4121 1.3141 -1.5301 +v -16.4336 0.5144 -0.6193 +v -16.5535 0.5144 -0.6202 +v -16.4722 0.5972 0.2849 +v -16.3140 0.5972 0.2861 +v -16.2542 0.6584 -1.5203 +v -16.4124 0.6584 -1.5215 +v -16.4334 0.3333 -0.6257 +v -16.3137 0.3583 0.2776 +v -16.2539 0.4196 -1.5289 +v -16.5533 0.3333 -0.6267 +v -16.4719 0.3583 0.2764 +v -16.4121 0.4196 -1.5301 +v -16.2814 1.8814 -0.7001 +v -16.4395 1.8814 -0.7013 +v -16.4461 1.8814 -0.5021 +v -16.2880 1.8814 -0.5009 +v -16.2339 0.8805 -0.5246 +v -16.3538 0.8805 -0.5255 +v -16.4461 0.0000 -0.5021 +v -16.2880 0.0000 -0.5009 +v -16.2289 0.8805 -0.6756 +v -16.2814 0.0000 -0.7001 +v -16.3488 0.8805 -0.6765 +v -16.4395 0.0000 -0.7013 +v -16.2962 1.6654 -0.2518 +v -16.4544 1.6654 -0.2530 +v -16.4610 1.6654 -0.0539 +v -16.3028 1.6654 -0.0526 +v -16.4168 0.8805 -0.0992 +v -16.5367 0.8805 -0.1002 +v -16.4610 0.0000 -0.0539 +v -16.3028 0.0000 -0.0526 +v -16.4118 0.8805 -0.2502 +v -16.2962 0.0000 -0.2518 +v -16.5317 0.8805 -0.2511 +v -16.4544 0.0000 -0.2530 +v -16.2513 1.7611 0.1485 +v -16.5258 1.7611 0.1464 +v -16.5324 1.7611 0.3455 +v -16.2579 1.7611 0.3476 +v -16.3334 0.8805 0.2928 +v -16.4533 0.8805 0.2919 +v -16.4742 0.0000 0.3460 +v -16.3160 0.0000 0.3472 +v -16.3284 0.8805 0.1419 +v -16.3094 0.0000 0.1480 +v -16.4483 0.8805 0.1409 +v -16.4676 0.0000 0.1468 +v -16.1976 1.7088 0.4840 +v -16.4638 1.7088 0.4820 +v -16.4703 1.7088 0.6811 +v -16.2042 1.7088 0.6832 +v -16.2523 0.8805 0.6992 +v -16.4389 0.8805 0.6978 +v -16.4580 0.0000 0.6812 +v -16.2166 0.0000 0.6831 +v -16.2473 0.8805 0.5483 +v -16.2100 0.0000 0.4839 +v -16.4338 0.8805 0.5468 +v -16.4514 0.0000 0.4821 +v -16.2678 1.8182 0.9249 +v -16.4259 1.8182 0.9237 +v -16.4325 1.8182 1.1228 +v -16.2744 1.8182 1.1240 +v -16.1825 0.8805 1.1426 +v -16.3024 0.8805 1.1417 +v -16.4325 0.0000 1.1698 +v -16.2744 0.0000 1.1710 +v -16.1775 0.8805 0.9917 +v -16.2678 0.0000 0.9719 +v -16.2974 0.8805 0.9908 +v -16.4259 0.0000 0.9707 +v -16.1713 1.4149 1.4653 +v -16.2912 1.4149 1.4644 +v -16.4722 1.4917 2.3675 +v -16.3140 1.4917 2.3687 +v -16.2542 1.5530 0.5623 +v -16.4124 1.5530 0.5611 +v -16.1710 1.2339 1.4589 +v -16.3137 1.2529 2.3602 +v -16.2539 1.3141 0.5538 +v -16.2909 1.2339 1.4579 +v -16.4719 1.2529 2.3590 +v -16.4121 1.3141 0.5525 +v -16.4336 0.5144 1.4633 +v -16.5535 0.5144 1.4624 +v -16.4722 0.5972 2.3675 +v -16.3140 0.5972 2.3687 +v -16.2542 0.6584 0.5623 +v -16.4124 0.6584 0.5611 +v -16.4334 0.3333 1.4569 +v -16.3137 0.3583 2.3602 +v -16.2539 0.4196 0.5538 +v -16.5533 0.3333 1.4559 +v -16.4719 0.3583 2.3590 +v -16.4121 0.4196 0.5525 +v -16.2814 1.8814 1.3825 +v -16.4395 1.8814 1.3813 +v -16.4461 1.8814 1.5805 +v -16.2880 1.8814 1.5817 +v -16.2339 0.8805 1.5580 +v -16.3538 0.8805 1.5571 +v -16.4461 0.0000 1.5805 +v -16.2880 0.0000 1.5817 +v -16.2289 0.8805 1.4070 +v -16.2814 0.0000 1.3825 +v -16.3488 0.8805 1.4061 +v -16.4395 0.0000 1.3813 +v -16.2962 1.6654 1.8308 +v -16.4544 1.6654 1.8296 +v -16.4610 1.6654 2.0287 +v -16.3028 1.6654 2.0300 +v -16.4168 0.8805 1.9834 +v -16.5367 0.8805 1.9824 +v -16.4610 0.0000 2.0287 +v -16.3028 0.0000 2.0300 +v -16.4118 0.8805 1.8324 +v -16.2962 0.0000 1.8308 +v -16.5317 0.8805 1.8315 +v -16.4544 0.0000 1.8296 +v -16.2513 1.7611 2.2311 +v -16.5258 1.7611 2.2290 +v -16.5324 1.7611 2.4281 +v -16.2579 1.7611 2.4302 +v -16.3334 0.8805 2.3754 +v -16.4533 0.8805 2.3745 +v -16.4742 0.0000 2.4286 +v -16.3160 0.0000 2.4298 +v -16.3284 0.8805 2.2245 +v -16.3094 0.0000 2.2306 +v -16.4483 0.8805 2.2236 +v -16.4676 0.0000 2.2294 +v -16.1976 1.7089 -15.7068 +v -16.4638 1.7089 -15.7088 +v -16.4704 1.7089 -15.5097 +v -16.2042 1.7089 -15.5076 +v -16.2523 0.8805 -15.4916 +v -16.4389 0.8805 -15.4930 +v -16.4580 0.0000 -15.5096 +v -16.2166 0.0000 -15.5077 +v -16.2473 0.8805 -15.6425 +v -16.2100 0.0000 -15.7069 +v -16.4339 0.8805 -15.6440 +v -16.4514 0.0000 -15.7087 +v -16.2678 1.8182 -15.2659 +v -16.4260 1.8182 -15.2671 +v -16.4325 1.8182 -15.0680 +v -16.2744 1.8182 -15.0668 +v -16.1825 0.8805 -15.0482 +v -16.3024 0.8805 -15.0491 +v -16.4325 0.0000 -15.0210 +v -16.2744 0.0000 -15.0198 +v -16.1775 0.8805 -15.1991 +v -16.2678 0.0000 -15.2189 +v -16.2974 0.8805 -15.2000 +v -16.4260 0.0000 -15.2201 +v -16.1713 1.4149 -14.7255 +v -16.2912 1.4149 -14.7264 +v -16.4722 1.4917 -13.8233 +v -16.3140 1.4917 -13.8221 +v -16.2542 1.5530 -15.6285 +v -16.4124 1.5530 -15.6297 +v -16.1711 1.2339 -14.7319 +v -16.3137 1.2529 -13.8306 +v -16.2539 1.3141 -15.6370 +v -16.2909 1.2339 -14.7329 +v -16.4719 1.2529 -13.8318 +v -16.4121 1.3141 -15.6383 +v -16.4336 0.5144 -14.7275 +v -16.5535 0.5144 -14.7284 +v -16.4722 0.5972 -13.8233 +v -16.3140 0.5972 -13.8221 +v -16.2542 0.6584 -15.6285 +v -16.4124 0.6584 -15.6297 +v -16.4334 0.3333 -14.7339 +v -16.3137 0.3583 -13.8306 +v -16.2539 0.4196 -15.6370 +v -16.5533 0.3333 -14.7349 +v -16.4719 0.3583 -13.8318 +v -16.4121 0.4196 -15.6383 +v -16.2814 1.8814 -14.8083 +v -16.4395 1.8814 -14.8095 +v -16.4461 1.8814 -14.6103 +v -16.2880 1.8814 -14.6091 +v -16.2339 0.8805 -14.6328 +v -16.3538 0.8805 -14.6337 +v -16.4461 0.0000 -14.6103 +v -16.2880 0.0000 -14.6091 +v -16.2289 0.8805 -14.7838 +v -16.2814 0.0000 -14.8083 +v -16.3488 0.8805 -14.7847 +v -16.4395 0.0000 -14.8095 +v -16.2962 1.6654 -14.3600 +v -16.4544 1.6654 -14.3612 +v -16.4610 1.6654 -14.1621 +v -16.3028 1.6654 -14.1608 +v -16.4168 0.8805 -14.2074 +v -16.5367 0.8805 -14.2084 +v -16.4610 0.0000 -14.1621 +v -16.3028 0.0000 -14.1608 +v -16.4118 0.8805 -14.3584 +v -16.2962 0.0000 -14.3600 +v -16.5317 0.8805 -14.3593 +v -16.4544 0.0000 -14.3612 +v -16.2513 1.7611 -13.9597 +v -16.5258 1.7611 -13.9618 +v -16.5324 1.7611 -13.7627 +v -16.2579 1.7611 -13.7606 +v -16.3334 0.8805 -13.8154 +v -16.4533 0.8805 -13.8163 +v -16.4742 0.0000 -13.7622 +v -16.3160 0.0000 -13.7610 +v -16.3284 0.8805 -13.9663 +v -16.3094 0.0000 -13.9602 +v -16.4483 0.8805 -13.9672 +v -16.4676 0.0000 -13.9614 +v -16.1976 1.7089 -13.6242 +v -16.4638 1.7089 -13.6262 +v -16.4704 1.7089 -13.4270 +v -16.2042 1.7089 -13.4250 +v -16.2523 0.8805 -13.4090 +v -16.4389 0.8805 -13.4104 +v -16.4580 0.0000 -13.4270 +v -16.2166 0.0000 -13.4251 +v -16.2473 0.8805 -13.5599 +v -16.2100 0.0000 -13.6242 +v -16.4339 0.8805 -13.5613 +v -16.4514 0.0000 -13.6261 +v -16.2678 1.8182 -13.1833 +v -16.4260 1.8182 -13.1845 +v -16.4325 1.8182 -12.9854 +v -16.2744 1.8182 -12.9842 +v -16.1825 0.8805 -12.9656 +v -16.3024 0.8805 -12.9665 +v -16.4325 0.0000 -12.9384 +v -16.2744 0.0000 -12.9372 +v -16.1775 0.8805 -13.1165 +v -16.2678 0.0000 -13.1363 +v -16.2974 0.8805 -13.1174 +v -16.4260 0.0000 -13.1375 +v -16.1713 1.4149 -12.6429 +v -16.2912 1.4149 -12.6438 +v -16.4722 1.4917 -11.7407 +v -16.3140 1.4917 -11.7395 +v -16.2542 1.5530 -13.5459 +v -16.4124 1.5530 -13.5471 +v -16.1711 1.2339 -12.6493 +v -16.3137 1.2529 -11.7480 +v -16.2539 1.3141 -13.5544 +v -16.2909 1.2339 -12.6502 +v -16.4719 1.2529 -11.7492 +v -16.4121 1.3141 -13.5557 +v -16.4336 0.5144 -12.6449 +v -16.5535 0.5144 -12.6458 +v -16.4722 0.5972 -11.7407 +v -16.3140 0.5972 -11.7395 +v -16.2542 0.6584 -13.5459 +v -16.4124 0.6584 -13.5471 +v -16.4334 0.3333 -12.6513 +v -16.3137 0.3583 -11.7480 +v -16.2539 0.4196 -13.5544 +v -16.5533 0.3333 -12.6523 +v -16.4719 0.3583 -11.7492 +v -16.4121 0.4196 -13.5557 +v -16.2814 1.8814 -12.7257 +v -16.4395 1.8814 -12.7269 +v -16.4461 1.8814 -12.5277 +v -16.2880 1.8814 -12.5265 +v -16.2339 0.8805 -12.5502 +v -16.3538 0.8805 -12.5511 +v -16.4461 0.0000 -12.5277 +v -16.2880 0.0000 -12.5265 +v -16.2289 0.8805 -12.7012 +v -16.2814 0.0000 -12.7257 +v -16.3488 0.8805 -12.7021 +v -16.4395 0.0000 -12.7269 +v -16.2962 1.6654 -12.2774 +v -16.4544 1.6654 -12.2786 +v -16.4610 1.6654 -12.0795 +v -16.3028 1.6654 -12.0782 +v -16.4168 0.8805 -12.1248 +v -16.5367 0.8805 -12.1258 +v -16.4610 0.0000 -12.0795 +v -16.3028 0.0000 -12.0782 +v -16.4118 0.8805 -12.2758 +v -16.2962 0.0000 -12.2774 +v -16.5317 0.8805 -12.2767 +v -16.4544 0.0000 -12.2786 +v -16.2513 1.7611 -11.8771 +v -16.5258 1.7611 -11.8792 +v -16.5324 1.7611 -11.6801 +v -16.2579 1.7611 -11.6780 +v -16.3334 0.8805 -11.7328 +v -16.4533 0.8805 -11.7337 +v -16.4742 0.0000 -11.6796 +v -16.3160 0.0000 -11.6784 +v -16.3284 0.8805 -11.8837 +v -16.3094 0.0000 -11.8776 +v -16.4483 0.8805 -11.8846 +v -16.4676 0.0000 -11.8788 +v -14.6277 1.7089 -15.8850 +v -14.6257 1.7089 -16.1511 +v -14.8248 1.7089 -16.1577 +v -14.8268 1.7089 -15.8916 +v -14.8429 0.8805 -15.9396 +v -14.8415 0.8805 -16.1262 +v -14.8249 0.0000 -16.1454 +v -14.8268 0.0000 -15.9040 +v -14.6919 0.8805 -15.9347 +v -14.6276 0.0000 -15.8974 +v -14.6905 0.8805 -16.1212 +v -14.6258 0.0000 -16.1388 +v -15.0685 1.8182 -15.9552 +v -15.0673 1.8182 -16.1133 +v -15.2665 1.8182 -16.1199 +v -15.2677 1.8182 -15.9618 +v -15.2863 0.8805 -15.8699 +v -15.2854 0.8805 -15.9898 +v -15.3135 0.0000 -16.1199 +v -15.3147 0.0000 -15.9618 +v -15.1354 0.8805 -15.8649 +v -15.1156 0.0000 -15.9552 +v -15.1344 0.8805 -15.9848 +v -15.1144 0.0000 -16.1133 +v -15.6090 1.4149 -15.8586 +v -15.6081 1.4149 -15.9785 +v -16.5112 1.4917 -16.1596 +v -16.5124 1.4917 -16.0014 +v -14.7060 1.5530 -15.9416 +v -14.7047 1.5530 -16.0998 +v -15.6025 1.2339 -15.8584 +v -16.5039 1.2529 -16.0011 +v -14.6974 1.3141 -15.9413 +v -15.6016 1.2339 -15.9783 +v -16.5026 1.2529 -16.1593 +v -14.6962 1.3141 -16.0995 +v -15.6070 0.5144 -16.1210 +v -15.6061 0.5144 -16.2409 +v -16.5112 0.5972 -16.1596 +v -16.5124 0.5972 -16.0014 +v -14.7060 0.6584 -15.9416 +v -14.7047 0.6584 -16.0998 +v -15.6005 0.3333 -16.1208 +v -16.5039 0.3583 -16.0011 +v -14.6974 0.4196 -15.9413 +v -15.5996 0.3333 -16.2407 +v -16.5026 0.3583 -16.1593 +v -14.6962 0.4196 -16.0995 +v -15.5262 1.8814 -15.9688 +v -15.5250 1.8814 -16.1269 +v -15.7241 1.8814 -16.1335 +v -15.7253 1.8814 -15.9753 +v -15.7016 0.8805 -15.9213 +v -15.7007 0.8805 -16.0412 +v -15.7241 0.0000 -16.1335 +v -15.7253 0.0000 -15.9753 +v -15.5507 0.8805 -15.9163 +v -15.5262 0.0000 -15.9688 +v -15.5498 0.8805 -16.0362 +v -15.5250 0.0000 -16.1269 +v -15.9745 1.6654 -15.9836 +v -15.9733 1.6654 -16.1418 +v -16.1724 1.6654 -16.1484 +v -16.1736 1.6654 -15.9902 +v -16.1270 0.8805 -16.1041 +v -16.1261 0.8805 -16.2241 +v -16.1724 0.0000 -16.1484 +v -16.1736 0.0000 -15.9902 +v -15.9761 0.8805 -16.0992 +v -15.9745 0.0000 -15.9836 +v -15.9751 0.8805 -16.2191 +v -15.9733 0.0000 -16.1418 +v -16.3747 1.7611 -15.9387 +v -16.3727 1.7611 -16.2132 +v -16.5718 1.7611 -16.2198 +v -16.5739 1.7611 -15.9452 +v -16.5191 0.8805 -16.0208 +v -16.5182 0.8805 -16.1407 +v -16.5722 0.0000 -16.1616 +v -16.5734 0.0000 -16.0034 +v -16.3681 0.8805 -16.0158 +v -16.3743 0.0000 -15.9968 +v -16.3672 0.8805 -16.1357 +v -16.3731 0.0000 -16.1550 +v -16.5007 1.7088 -1.3839 +v -16.4987 1.7088 -1.6500 +v -16.6978 1.7088 -1.6566 +v -16.6999 1.7088 -1.3905 +v -16.7159 0.8805 -1.4385 +v -16.7145 0.8805 -1.6251 +v -16.6979 0.0000 -1.6442 +v -16.6998 0.0000 -1.4028 +v -16.5650 0.8805 -1.4335 +v -16.5006 0.0000 -1.3962 +v -16.5635 0.8805 -1.6201 +v -16.4988 0.0000 -1.6376 +v -16.9416 1.8182 -1.4540 +v -16.9404 1.8182 -1.6122 +v -17.1395 1.8182 -1.6188 +v -17.1407 1.8182 -1.4606 +v -17.1593 0.8805 -1.3687 +v -17.1584 0.8805 -1.4886 +v -17.1865 0.0000 -1.6188 +v -17.1877 0.0000 -1.4606 +v -17.0084 0.8805 -1.3637 +v -16.9886 0.0000 -1.4540 +v -17.0075 0.8805 -1.4836 +v -16.9874 0.0000 -1.6122 +v -17.4820 1.4149 -1.3575 +v -17.4811 1.4149 -1.4774 +v -18.3842 1.4917 -1.6584 +v -18.3854 1.4917 -1.5002 +v -16.5790 1.5530 -1.4404 +v -16.5778 1.5530 -1.5986 +v -17.4756 1.2339 -1.3573 +v -18.3769 1.2529 -1.5000 +v -16.5704 1.3141 -1.4402 +v -17.4746 1.2339 -1.4772 +v -18.3757 1.2529 -1.6581 +v -16.5692 1.3141 -1.5983 +v -17.4800 0.5144 -1.6199 +v -17.4791 0.5144 -1.7398 +v -18.3842 0.5972 -1.6584 +v -18.3854 0.5972 -1.5002 +v -16.5790 0.6584 -1.4404 +v -16.5778 0.6584 -1.5986 +v -17.4736 0.3333 -1.6196 +v -18.3769 0.3583 -1.5000 +v -16.5704 0.4196 -1.4402 +v -17.4726 0.3333 -1.7396 +v -18.3757 0.3583 -1.6581 +v -16.5692 0.4196 -1.5983 +v -17.3992 1.8814 -1.4676 +v -17.3980 1.8814 -1.6258 +v -17.5972 1.8814 -1.6324 +v -17.5984 1.8814 -1.4742 +v -17.5747 0.8805 -1.4201 +v -17.5738 0.8805 -1.5400 +v -17.5972 0.0000 -1.6324 +v -17.5984 0.0000 -1.4742 +v -17.4237 0.8805 -1.4151 +v -17.3992 0.0000 -1.4676 +v -17.4228 0.8805 -1.5350 +v -17.3980 0.0000 -1.6258 +v -17.8475 1.6654 -1.4824 +v -17.8463 1.6654 -1.6406 +v -18.0454 1.6654 -1.6472 +v -18.0467 1.6654 -1.4890 +v -18.0001 0.8805 -1.6030 +v -17.9991 0.8805 -1.7229 +v -18.0454 0.0000 -1.6472 +v -18.0467 0.0000 -1.4890 +v -17.8491 0.8805 -1.5980 +v -17.8475 0.0000 -1.4824 +v -17.8482 0.8805 -1.7179 +v -17.8463 0.0000 -1.6406 +v -18.2478 1.7611 -1.4375 +v -18.2457 1.7611 -1.7120 +v -18.4448 1.7611 -1.7186 +v -18.4469 1.7611 -1.4441 +v -18.3921 0.8805 -1.5196 +v -18.3912 0.8805 -1.6395 +v -18.4453 0.0000 -1.6604 +v -18.4465 0.0000 -1.5023 +v -18.2412 0.8805 -1.5146 +v -18.2473 0.0000 -1.4957 +v -18.2402 0.8805 -1.6345 +v -18.2461 0.0000 -1.6538 +v -16.5007 1.7088 -11.7369 +v -16.4987 1.7088 -12.0031 +v -16.6978 1.7088 -12.0097 +v -16.6999 1.7088 -11.7435 +v -16.7159 0.8805 -11.7916 +v -16.7145 0.8805 -11.9782 +v -16.6979 0.0000 -11.9973 +v -16.6998 0.0000 -11.7559 +v -16.5650 0.8805 -11.7866 +v -16.5006 0.0000 -11.7493 +v -16.5635 0.8805 -11.9732 +v -16.4988 0.0000 -11.9907 +v -16.9416 1.8182 -11.8071 +v -16.9404 1.8182 -11.9653 +v -17.1395 1.8182 -11.9719 +v -17.1407 1.8182 -11.8137 +v -17.1593 0.8805 -11.7218 +v -17.1584 0.8805 -11.8417 +v -17.1865 0.0000 -11.9719 +v -17.1877 0.0000 -11.8137 +v -17.0084 0.8805 -11.7168 +v -16.9886 0.0000 -11.8071 +v -17.0075 0.8805 -11.8367 +v -16.9874 0.0000 -11.9653 +v -17.4820 1.4149 -11.7106 +v -17.4811 1.4149 -11.8305 +v -18.3842 1.4917 -12.0115 +v -18.3854 1.4917 -11.8533 +v -16.5790 1.5530 -11.7935 +v -16.5778 1.5530 -11.9517 +v -17.4756 1.2339 -11.7104 +v -18.3769 1.2529 -11.8531 +v -16.5705 1.3141 -11.7932 +v -17.4746 1.2339 -11.8303 +v -18.3757 1.2529 -12.0112 +v -16.5692 1.3141 -11.9514 +v -17.4800 0.5144 -11.9729 +v -17.4791 0.5144 -12.0929 +v -18.3842 0.5972 -12.0115 +v -18.3854 0.5972 -11.8533 +v -16.5790 0.6584 -11.7935 +v -16.5778 0.6584 -11.9517 +v -17.4736 0.3333 -11.9727 +v -18.3769 0.3583 -11.8531 +v -16.5705 0.4196 -11.7932 +v -17.4726 0.3333 -12.0926 +v -18.3757 0.3583 -12.0112 +v -16.5692 0.4196 -11.9514 +v -17.3992 1.8814 -11.8207 +v -17.3980 1.8814 -11.9789 +v -17.5972 1.8814 -11.9854 +v -17.5984 1.8814 -11.8273 +v -17.5747 0.8805 -11.7732 +v -17.5738 0.8805 -11.8931 +v -17.5972 0.0000 -11.9854 +v -17.5984 0.0000 -11.8273 +v -17.4237 0.8805 -11.7682 +v -17.3992 0.0000 -11.8207 +v -17.4228 0.8805 -11.8881 +v -17.3980 0.0000 -11.9789 +v -17.8475 1.6654 -11.8355 +v -17.8463 1.6654 -11.9937 +v -18.0454 1.6654 -12.0003 +v -18.0467 1.6654 -11.8421 +v -18.0001 0.8805 -11.9561 +v -17.9991 0.8805 -12.0760 +v -18.0454 0.0000 -12.0003 +v -18.0467 0.0000 -11.8421 +v -17.8491 0.8805 -11.9511 +v -17.8475 0.0000 -11.8355 +v -17.8482 0.8805 -12.0710 +v -17.8463 0.0000 -11.9937 +v -18.2478 1.7611 -11.7906 +v -18.2457 1.7611 -12.0651 +v -18.4448 1.7611 -12.0717 +v -18.4469 1.7611 -11.7972 +v -18.3921 0.8805 -11.8727 +v -18.3912 0.8805 -11.9926 +v -18.4453 0.0000 -12.0135 +v -18.4465 0.0000 -11.8553 +v -18.2412 0.8805 -11.8677 +v -18.2473 0.0000 -11.8488 +v -18.2402 0.8805 -11.9876 +v -18.2461 0.0000 -12.0069 +v -13.4333 1.3855 -14.8170 +v -13.3083 1.8860 -14.9564 +v -12.6208 1.3855 -15.1128 +v -11.7678 1.4064 -15.2974 +v -11.8082 1.3855 -15.4085 +v -11.9936 1.8860 -15.4350 +v -11.9532 1.9069 -15.3239 +v -12.4185 2.1954 -15.3383 +v -12.3781 2.2162 -15.2273 +v -12.9207 2.1954 -15.1556 +v -12.8803 2.2162 -15.0445 +v -13.2679 1.9069 -14.8454 +v -13.3929 1.4064 -14.7059 +v -13.2479 0.8850 -14.7906 +v -13.2075 0.9058 -14.6795 +v -12.8230 0.5756 -14.8872 +v -12.7826 0.5965 -14.7761 +v -12.3208 0.5756 -15.0700 +v -12.2804 0.5965 -14.9589 +v -11.9332 0.8850 -15.2691 +v -11.8928 0.9058 -15.1580 +v -12.5803 1.4064 -15.0017 +v -12.7498 1.8031 -15.1131 +v -12.6339 1.7693 -15.1536 +v -12.7051 1.7422 -15.3141 +v -12.8209 1.7759 -15.2737 +v -13.1019 0.0241 -14.6562 +v -12.9860 -0.0096 -14.6967 +v -13.1730 -0.0030 -14.8168 +v -13.0571 -0.0368 -14.8573 +v -12.7098 1.7422 -15.3601 +v -12.6611 1.7693 -15.1913 +v -12.5463 1.8031 -15.2348 +v -12.5951 1.7759 -15.4035 +v -12.0978 -0.0096 -15.0677 +v -11.9830 0.0241 -15.1111 +v -12.0317 -0.0030 -15.2799 +v -12.1465 -0.0368 -15.2364 +v -12.7132 1.7060 -15.0538 +v -12.9305 -0.0497 -15.6601 +v -12.8095 -0.0506 -15.6996 +v -12.5922 1.7051 -15.0933 +v -12.8547 0.0104 -15.8603 +v -12.6374 1.7661 -15.2539 +v -12.9757 0.0114 -15.8207 +v -12.7584 1.7670 -15.2144 +v -15.8108 1.3855 -14.3550 +v -15.7723 1.8860 -14.5383 +v -15.2550 1.3855 -15.0174 +v -14.6087 1.4064 -15.6038 +v -14.6992 1.3855 -15.6798 +v -14.8730 1.8860 -15.6100 +v -14.7824 1.9069 -15.5340 +v -15.1927 2.1954 -15.3139 +v -15.1021 2.2162 -15.2379 +v -15.5362 2.1954 -14.9045 +v -15.4456 2.2162 -14.8285 +v -15.6817 1.9069 -14.4623 +v -15.7203 1.4064 -14.2790 +v -15.6371 0.8850 -14.4248 +v -15.5465 0.9058 -14.3488 +v -15.3174 0.5756 -14.7209 +v -15.2268 0.5965 -14.6449 +v -14.9739 0.5756 -15.1303 +v -14.8833 0.5965 -15.0543 +v -14.7378 0.8850 -15.4966 +v -14.6472 0.9058 -15.4206 +v -15.1645 1.4064 -14.9414 +v -15.3669 1.8031 -14.9532 +v -15.2868 1.7693 -15.0462 +v -15.4287 1.7422 -15.1497 +v -15.5088 1.7759 -15.0567 +v -15.4434 0.0241 -14.3815 +v -15.3633 -0.0096 -14.4745 +v -15.5853 -0.0030 -14.4850 +v -15.5052 -0.0368 -14.5780 +v -15.4558 1.7422 -15.1870 +v -15.3292 1.7693 -15.0653 +v -15.2516 1.8031 -15.1603 +v -15.3781 1.7759 -15.2821 +v -14.7796 -0.0096 -15.2399 +v -14.7019 0.0241 -15.3349 +v -14.8285 -0.0030 -15.4567 +v -14.9061 -0.0368 -15.3616 +v -15.3056 1.7060 -14.9201 +v -15.7969 -0.0497 -15.3365 +v -15.7119 -0.0506 -15.4312 +v -15.2206 1.7051 -15.0148 +v -15.8314 0.0104 -15.5478 +v -15.3400 1.7661 -15.1314 +v -15.9164 0.0114 -15.4531 +v -15.4251 1.7670 -15.0366 +v -15.6943 1.3855 -11.7111 +v -15.6881 1.8860 -11.8982 +v -15.2620 1.3855 -12.4599 +v -14.7272 1.4064 -13.1496 +v -14.8296 1.3855 -13.2087 +v -14.9886 1.8860 -13.1099 +v -14.8862 1.9069 -13.0507 +v -15.2520 2.1954 -12.7627 +v -15.1496 2.2162 -12.7036 +v -15.5192 2.1954 -12.2999 +v -15.4168 2.2162 -12.2408 +v -15.5858 1.9069 -11.8391 +v -15.5919 1.4063 -11.6520 +v -15.5353 0.8850 -11.8100 +v -15.4329 0.9058 -11.7508 +v -15.2719 0.5756 -12.1571 +v -15.1695 0.5965 -12.0980 +v -15.0047 0.5756 -12.6199 +v -14.9023 0.5965 -12.5608 +v -14.8357 0.8850 -13.0216 +v -14.7334 0.9058 -12.9625 +v -15.1596 1.4063 -12.4008 +v -15.3610 1.8031 -12.3772 +v -15.2983 1.7693 -12.4827 +v -15.4560 1.7422 -12.5600 +v -15.5187 1.7759 -12.4545 +v -15.3370 0.0241 -11.8010 +v -15.2743 -0.0096 -11.9064 +v -15.4948 -0.0030 -11.8782 +v -15.4320 -0.0368 -11.9837 +v -15.4891 1.7422 -12.5921 +v -15.3433 1.7693 -12.4941 +v -15.2833 1.8031 -12.6012 +v -15.4291 1.7759 -12.6992 +v -14.8323 -0.0096 -12.7615 +v -14.7723 0.0241 -12.8686 +v -14.9181 -0.0030 -12.9666 +v -14.9781 -0.0368 -12.8595 +v -15.2948 1.7060 -12.3553 +v -15.8510 -0.0497 -12.6801 +v -15.7837 -0.0506 -12.7881 +v -15.2275 1.7051 -12.4633 +v -15.9216 0.0104 -12.8821 +v -15.3654 1.7661 -12.5574 +v -15.9889 0.0114 -12.7741 +v -15.4327 1.7670 -12.4493 +v -10.1961 1.3855 11.3643 +v -10.3684 1.8860 11.4378 +v -11.0575 1.3855 11.2889 +v -11.9086 1.4063 11.0958 +v -11.9189 1.3855 11.2136 +v -11.7621 1.8860 11.3159 +v -11.7518 1.9069 11.1981 +v -11.3362 2.1954 11.4079 +v -11.3259 2.2162 11.2901 +v -10.8038 2.1954 11.4545 +v -10.7935 2.2162 11.3367 +v -10.3580 1.9069 11.3200 +v -10.1858 1.4063 11.2465 +v -10.3530 0.8850 11.2620 +v -10.3427 0.9058 11.1442 +v -10.7789 0.5756 11.1699 +v -10.7686 0.5965 11.0522 +v -11.3113 0.5756 11.1234 +v -11.3010 0.5965 11.0056 +v -11.7467 0.8850 11.1400 +v -11.7364 0.9058 11.0223 +v -11.0472 1.4063 11.1711 +v -10.9407 1.8031 11.3437 +v -11.0628 1.7693 11.3315 +v -11.0662 1.7422 11.5071 +v -10.9441 1.7759 11.5193 +v -10.4286 0.0241 11.0785 +v -10.5507 -0.0096 11.0662 +v -10.4320 -0.0030 11.2541 +v -10.5541 -0.0368 11.2418 +v -11.0813 1.7422 11.5507 +v -11.0542 1.7693 11.3771 +v -11.1766 1.8031 11.3680 +v -11.2037 1.7759 11.5416 +v -11.5125 -0.0096 11.0270 +v -11.6349 0.0241 11.0179 +v -11.6620 -0.0030 11.1914 +v -11.5396 -0.0368 11.2005 +v -10.9488 1.7060 11.2745 +v -11.0081 -0.0497 11.9158 +v -11.1345 -0.0506 11.9005 +v -11.0752 1.7051 11.2592 +v -11.1614 0.0104 12.0653 +v -11.1021 1.7661 11.4239 +v -11.0350 0.0114 12.0806 +v -10.9758 1.7670 11.4392 +v -13.9193 1.3855 11.3643 +v -14.0915 1.8860 11.4378 +v -14.7807 1.3855 11.2889 +v -15.6318 1.4063 11.0958 +v -15.6421 1.3855 11.2136 +v -15.4853 1.8860 11.3159 +v -15.4750 1.9069 11.1981 +v -15.0594 2.1954 11.4079 +v -15.0491 2.2162 11.2901 +v -14.5270 2.1954 11.4545 +v -14.5167 2.2162 11.3367 +v -14.0812 1.9069 11.3200 +v -13.9090 1.4063 11.2465 +v -14.0762 0.8850 11.2620 +v -14.0659 0.9058 11.1442 +v -14.5021 0.5756 11.1699 +v -14.4918 0.5965 11.0522 +v -15.0345 0.5756 11.1234 +v -15.0242 0.5965 11.0056 +v -15.4699 0.8850 11.1400 +v -15.4596 0.9058 11.0223 +v -14.7704 1.4063 11.1711 +v -14.6639 1.8031 11.3437 +v -14.7860 1.7693 11.3315 +v -14.7894 1.7422 11.5071 +v -14.6673 1.7759 11.5193 +v -14.1518 0.0241 11.0785 +v -14.2739 -0.0096 11.0662 +v -14.1552 -0.0030 11.2541 +v -14.2773 -0.0368 11.2418 +v -14.8045 1.7422 11.5507 +v -14.7774 1.7693 11.3771 +v -14.8997 1.8031 11.3680 +v -14.9269 1.7759 11.5416 +v -15.2357 -0.0096 11.0270 +v -15.3581 0.0241 11.0179 +v -15.3852 -0.0030 11.1914 +v -15.2628 -0.0368 11.2005 +v -14.6720 1.7060 11.2745 +v -14.7313 -0.0497 11.9158 +v -14.8577 -0.0506 11.9005 +v -14.7984 1.7051 11.2592 +v -14.8846 0.0104 12.0653 +v -14.8253 1.7661 11.4239 +v -14.7582 0.0114 12.0806 +v -14.6989 1.7670 11.4392 +v -11.9555 1.3855 11.3643 +v -12.1277 1.8860 11.4378 +v -12.8168 1.3855 11.2889 +v -13.6679 1.4063 11.0958 +v -13.6782 1.3855 11.2136 +v -13.5214 1.8860 11.3159 +v -13.5111 1.9069 11.1981 +v -13.0955 2.1954 11.4079 +v -13.0852 2.2162 11.2901 +v -12.5631 2.1954 11.4545 +v -12.5528 2.2162 11.3367 +v -12.1173 1.9069 11.3200 +v -11.9452 1.4063 11.2465 +v -12.1123 0.8850 11.2620 +v -12.1020 0.9058 11.1442 +v -12.5382 0.5756 11.1699 +v -12.5279 0.5965 11.0522 +v -13.0706 0.5756 11.1234 +v -13.0603 0.5965 11.0056 +v -13.5060 0.8850 11.1400 +v -13.4957 0.9058 11.0223 +v -12.8065 1.4063 11.1711 +v -12.7000 1.8031 11.3437 +v -12.8222 1.7693 11.3315 +v -12.8255 1.7422 11.5071 +v -12.7034 1.7759 11.5193 +v -12.1879 0.0241 11.0785 +v -12.3100 -0.0096 11.0662 +v -12.1913 -0.0030 11.2541 +v -12.3134 -0.0368 11.2418 +v -12.8406 1.7422 11.5507 +v -12.8135 1.7693 11.3771 +v -12.9359 1.8031 11.3680 +v -12.9630 1.7759 11.5416 +v -13.2718 -0.0096 11.0270 +v -13.3942 0.0241 11.0179 +v -13.4213 -0.0030 11.1914 +v -13.2989 -0.0368 11.2005 +v -12.7081 1.7060 11.2745 +v -12.7674 -0.0497 11.9158 +v -12.8938 -0.0506 11.9005 +v -12.8345 1.7051 11.2592 +v -12.9207 0.0104 12.0653 +v -12.8614 1.7661 11.4239 +v -12.7944 0.0114 12.0806 +v -12.7351 1.7670 11.4392 +v 0.1802 0.5595 -14.7704 +v 0.1255 0.5595 -14.5283 +v -0.0289 0.9000 -14.4721 +v 0.0649 0.9000 -14.8875 +v 0.2942 0.5595 -14.8315 +v 0.2606 0.9000 -14.9924 +v 0.5261 0.5595 -14.7429 +v 0.6584 0.9000 -14.8404 +v 0.5704 0.5595 -14.6214 +v 0.7343 0.9000 -14.6318 +v 0.4497 0.5595 -14.4045 +v 0.5273 0.9000 -14.2596 +v 0.3230 0.5595 -14.3780 +v 0.3100 0.9000 -14.2141 +v 0.2022 0.5595 -14.4241 +v 0.1027 0.9000 -14.2934 +v -0.0872 1.2405 -14.4509 +v -0.0091 1.7519 -14.4793 +v 0.0797 1.7519 -14.8725 +v 0.0214 1.2405 -14.9318 +v 0.2649 1.7519 -14.9718 +v 0.2478 1.2405 -15.0531 +v 0.6415 1.7519 -14.8279 +v 0.7084 1.2405 -14.8772 +v 0.7133 1.7519 -14.6305 +v 0.7963 1.2405 -14.6357 +v 0.5173 1.7519 -14.2782 +v 0.5566 1.2405 -14.2049 +v 0.3117 1.7519 -14.2351 +v 0.3051 1.2405 -14.1523 +v 0.1154 1.7519 -14.3101 +v 0.0651 1.2405 -14.2440 +v 0.1289 1.8995 -14.5295 +v 0.1827 1.8995 -14.7679 +v 0.2949 1.8995 -14.8280 +v 0.5232 1.8995 -14.7408 +v 0.5668 1.8995 -14.6211 +v 0.4480 1.8995 -14.4076 +v 0.3233 1.8995 -14.3815 +v 0.2044 1.8995 -14.4270 +v 0.1924 2.0403 -14.5527 +v 0.2302 2.0403 -14.7197 +v 0.3088 2.0403 -14.7618 +v 0.4687 2.0403 -14.7007 +v 0.4992 2.0403 -14.6169 +v 0.4160 2.0403 -14.4672 +v 0.3287 2.0403 -14.4490 +v 0.2453 2.0403 -14.4808 +v 0.1924 2.0876 -14.5527 +v 0.2302 2.0876 -14.7197 +v 0.3088 2.0876 -14.7618 +v 0.4687 2.0876 -14.7007 +v 0.4992 2.0876 -14.6169 +v 0.4160 2.0876 -14.4672 +v 0.3287 2.0876 -14.4490 +v 0.2453 2.0876 -14.4808 +v 0.1046 2.2023 -14.5207 +v 0.1646 2.2023 -14.7863 +v 0.2897 2.2023 -14.8533 +v 0.5440 2.2023 -14.7561 +v 0.5925 2.2023 -14.6228 +v 0.4602 2.2023 -14.3849 +v 0.3213 2.2023 -14.3558 +v 0.1887 2.2023 -14.4064 +v 0.1046 2.4098 -14.5207 +v 0.1646 2.4098 -14.7863 +v 0.2897 2.4098 -14.8533 +v 0.5440 2.4098 -14.7561 +v 0.5925 2.4098 -14.6228 +v 0.4602 2.4098 -14.3849 +v 0.3213 2.4098 -14.3558 +v 0.1887 2.4098 -14.4064 +v 0.2046 2.5373 -14.5571 +v 0.2393 2.5373 -14.7104 +v 0.3114 2.5373 -14.7491 +v 0.4583 2.5373 -14.6930 +v 0.4863 2.5373 -14.6160 +v 0.4099 2.5373 -14.4787 +v 0.3297 2.5373 -14.4619 +v 0.2532 2.5373 -14.4911 +v 0.3412 2.6507 -14.6068 +v 0.5700 1.5684 -14.5433 +v 0.5610 1.6492 -14.5187 +v 0.9846 1.5228 -14.3645 +v 0.9936 1.4420 -14.3892 +v 0.5319 1.6492 -14.4388 +v 0.9555 1.5228 -14.2847 +v 0.5229 1.5684 -14.4142 +v 0.9465 1.4420 -14.2600 +v 1.5494 1.4280 -14.0401 +v 1.5584 1.3472 -14.0648 +v 1.5204 1.4280 -13.9603 +v 1.5114 1.3472 -13.9356 +v 1.5349 1.2972 -14.0002 +v 0.1252 1.5684 -14.7052 +v -0.2984 1.4420 -14.8594 +v -0.3074 1.5228 -14.8347 +v 0.1162 1.6492 -14.6805 +v -0.3364 1.5228 -14.7549 +v 0.0872 1.6492 -14.6007 +v -0.3454 1.4420 -14.7302 +v 0.0782 1.5684 -14.5760 +v -0.9396 1.3472 -14.9740 +v -0.9486 1.4280 -14.9493 +v -0.9776 1.4280 -14.8695 +v -0.9866 1.3472 -14.8448 +v -0.9631 1.2972 -14.9094 +v 0.4048 -0.0767 -14.4979 +v 0.4048 0.7107 -14.4979 +v 0.2225 0.7107 -14.5643 +v 0.2225 -0.0767 -14.5643 +v 0.2777 0.7107 -14.7157 +v 0.2777 -0.0767 -14.7157 +v 0.4599 0.7107 -14.6494 +v 0.4599 -0.0767 -14.6494 +v -1.2374 1.2649 -15.0641 +v -1.1839 1.0229 -14.6042 +v -0.9923 1.4302 -14.7777 +v -1.1680 1.5864 -15.2935 +v -1.1668 1.0029 -14.6232 +v -1.2203 1.2449 -15.0831 +v -0.4444 1.5234 -14.6335 +v -0.4615 1.5434 -14.6145 +v -0.7079 1.2328 -14.5553 +v -0.6908 1.2128 -14.5743 +v -0.7581 1.7875 -14.9989 +v -0.7751 1.8075 -14.9799 +v -0.4318 1.8305 -14.8049 +v -0.4147 1.8105 -14.8239 +v -1.1510 1.5663 -15.3125 +v -0.9612 1.8626 -15.3137 +v -0.9441 1.8426 -15.3327 +v 1.4660 1.2989 -14.0503 +v 1.5641 1.2989 -13.9816 +v 1.5222 1.3053 -13.9217 +v 1.4240 1.3053 -13.9904 +v 1.5668 3.0809 -14.1517 +v 1.5420 3.0847 -14.1162 +v 1.6001 3.0847 -14.0756 +v 1.6249 3.0809 -14.1110 +v 1.4794 1.5669 -14.0695 +v 1.5776 1.5669 -14.0008 +v 1.5356 1.5733 -13.9409 +v 1.4375 1.5733 -14.0096 +v 1.5801 1.6171 -14.0044 +v 1.4820 1.6171 -14.0731 +v 1.5382 1.6235 -13.9445 +v 1.4400 1.6235 -14.0132 +v 1.8476 1.6235 -13.7278 +v 1.8451 1.5733 -13.7242 +v 1.8870 1.5669 -13.7842 +v 1.8895 1.6171 -13.7877 +v 1.1725 1.6171 -14.2898 +v 1.1700 1.5669 -14.2862 +v 1.1281 1.5733 -14.2263 +v 1.1306 1.6235 -14.2299 +v 13.7652 5.5867 -6.7761 +v 12.4179 5.5867 -7.2009 +v 11.5965 4.2732 -6.0377 +v 13.9200 4.2732 -5.0064 +v 15.0182 5.5867 -7.4284 +v 16.3791 4.2732 -6.2865 +v 15.4430 5.5867 -8.7756 +v 17.2127 4.2732 -8.9305 +v 14.7907 5.5867 -10.0287 +v 15.9326 4.2732 -11.3895 +v 13.4434 5.5867 -10.4534 +v 13.2886 4.2732 -12.2231 +v 12.1904 5.5867 -9.8012 +v 10.8296 4.2732 -10.9430 +v 11.7656 5.5867 -8.4539 +v 10.3164 4.2732 -8.4967 +v 13.6043 7.5569 -8.6148 +v 11.5965 3.6592 -6.0377 +v 13.9200 3.6592 -5.0064 +v 16.3791 3.6592 -6.2865 +v 17.2127 3.6592 -8.9305 +v 15.9326 3.6592 -11.3895 +v 13.2886 3.6592 -12.2231 +v 10.8296 3.6592 -10.9430 +v 10.3164 3.6592 -8.4967 +v 13.9081 0.4345 -4.7045 +v 13.9188 -0.0497 -4.3908 +v 16.7787 -0.0497 -5.8795 +v 16.5598 0.4345 -6.0849 +v 13.8948 1.4030 -5.1663 +v 16.2411 1.4030 -6.3877 +v 13.8976 2.8558 -5.2628 +v 16.1819 2.8558 -6.4519 +v 13.8976 3.8243 -5.2628 +v 16.1819 3.8243 -6.4519 +v 13.8976 4.3085 -5.2628 +v 16.1819 4.3085 -6.4519 +v 10.9868 0.4345 -7.0411 +v 10.9067 -0.0497 -6.9992 +v 11.0849 1.4030 -7.1421 +v 11.0761 2.8558 -7.2216 +v 11.0071 3.8243 -7.3540 +v 11.0560 4.3085 -7.4158 +v 10.5754 0.4345 -11.1064 +v 10.3246 -0.0497 -11.2952 +v 10.5998 -0.0497 -7.5888 +v 10.6800 0.4345 -7.6304 +v 10.9462 1.4030 -10.8307 +v 10.8190 1.4030 -7.6528 +v 11.0267 2.8558 -10.7776 +v 10.8791 2.8558 -7.6000 +v 11.0267 3.8243 -10.7776 +v 10.9480 3.8243 -7.4676 +v 11.0267 4.3085 -10.7776 +v 13.2272 0.4345 -12.4869 +v 13.1845 -0.0497 -12.7839 +v 13.2924 1.4030 -12.0521 +v 13.3111 2.8558 -11.9667 +v 13.3111 3.8243 -11.9667 +v 13.3111 4.3085 -11.9667 +v 16.0784 0.4345 -11.5879 +v 16.2594 -0.0497 -11.8144 +v 15.8151 1.4030 -11.2567 +v 15.7672 2.8558 -11.1923 +v 15.7672 3.8243 -11.1923 +v 15.7672 4.3085 -11.1923 +v 17.4588 0.4345 -8.9361 +v 17.7482 -0.0497 -8.9545 +v 17.0365 1.4030 -8.9104 +v 16.9563 2.8558 -8.9080 +v 16.9563 3.8243 -8.9080 +v 16.9563 4.3085 -8.9080 +v 6.4082 5.5867 -10.5037 +v 5.2168 5.5867 -9.7447 +v 5.5799 4.2732 -8.3678 +v 7.8634 4.2732 -9.4848 +v 6.7140 5.5867 -11.8829 +v 8.4634 4.2732 -12.1914 +v 5.9549 5.5867 -13.0743 +v 6.9739 4.2732 -14.5295 +v 4.5758 5.5867 -13.3800 +v 4.2673 4.2732 -15.1295 +v 3.3844 5.5867 -12.6210 +v 1.9292 4.2732 -13.6399 +v 3.0786 5.5867 -11.2419 +v 1.3292 4.2732 -10.9334 +v 3.8376 5.5867 -10.0505 +v 2.8733 4.2732 -8.9678 +v 4.8963 7.5569 -11.5624 +v 5.5799 3.6592 -8.3678 +v 7.8634 3.6592 -9.4848 +v 8.4634 3.6592 -12.1914 +v 6.9739 3.6592 -14.5295 +v 4.2673 3.6592 -15.1295 +v 1.9292 3.6592 -13.6399 +v 1.3292 3.6592 -10.9334 +v 2.8733 3.6592 -8.9678 +v 8.0870 0.4345 -9.2816 +v 8.3342 -0.0497 -9.0881 +v 9.0320 -0.0497 -12.2359 +v 8.7340 0.4345 -12.2003 +v 7.7247 1.4030 -9.5683 +v 8.2972 1.4030 -12.1507 +v 7.6526 2.8558 -9.6324 +v 8.2099 2.8558 -12.1467 +v 7.6526 3.8243 -9.6324 +v 8.2099 3.8243 -12.1467 +v 7.6526 4.3085 -9.6324 +v 8.2099 4.3085 -12.1467 +v 4.4193 0.4345 -8.5457 +v 4.3998 -0.0497 -8.4574 +v 4.4049 1.4030 -8.6857 +v 4.3384 2.8558 -8.7301 +v 4.1927 3.8243 -8.7624 +v 4.1767 4.3085 -8.8396 +v 1.0406 0.4345 -10.8437 +v 0.7348 -0.0497 -10.7729 +v 3.7510 -0.0497 -8.6013 +v 3.7706 0.4345 -8.6895 +v 1.4902 1.4030 -10.9505 +v 3.8428 1.4030 -8.8104 +v 1.5826 2.8558 -10.9781 +v 3.9219 2.8558 -8.8224 +v 1.5826 3.8243 -10.9781 +v 4.0676 3.8243 -8.7901 +v 1.5826 4.3085 -10.9781 +v 1.6877 0.4345 -13.7624 +v 1.4327 -0.0497 -13.9206 +v 2.0627 1.4030 -13.5329 +v 2.1400 2.8558 -13.4923 +v 2.1400 3.8243 -13.4923 +v 2.1400 4.3085 -13.4923 +v 4.2091 0.4345 -15.3687 +v 4.1519 -0.0497 -15.6530 +v 4.2936 1.4030 -14.9541 +v 4.3120 2.8558 -14.8760 +v 4.3120 3.8243 -14.8760 +v 4.3120 4.3085 -14.8760 +v 7.1278 0.4345 -14.7216 +v 7.2997 -0.0497 -14.9552 +v 6.8760 1.4030 -14.3816 +v 6.8262 2.8558 -14.3186 +v 6.8262 3.8243 -14.3186 +v 6.8262 4.3085 -14.3186 +v -7.3603 0.5595 -14.6578 +v -7.2663 0.5595 -14.4280 +v -7.3605 0.9000 -14.2934 +v -7.5219 0.9000 -14.6876 +v -7.3020 0.5595 -14.7732 +v -7.4218 0.9000 -14.8857 +v -7.0612 0.5595 -14.8336 +v -7.0087 0.9000 -14.9894 +v -6.9552 0.5595 -14.7594 +v -6.8269 0.9000 -14.8620 +v -6.9297 0.5595 -14.5125 +v -6.7830 0.9000 -14.4384 +v -7.0182 0.5595 -14.4182 +v -6.9349 0.9000 -14.2765 +v -7.1437 0.5595 -14.3867 +v -7.1502 0.9000 -14.2225 +v -7.3961 1.2405 -14.2426 +v -7.3484 1.7519 -14.3107 +v -7.5012 1.7519 -14.6838 +v -7.5830 1.2405 -14.6988 +v -7.4065 1.7519 -14.8713 +v -7.4671 1.2405 -14.9281 +v -7.0154 1.7519 -14.9694 +v -6.9889 1.2405 -15.0482 +v -6.8433 1.7519 -14.8489 +v -6.7784 1.2405 -14.9008 +v -6.8018 1.7519 -14.4479 +v -6.7276 1.2405 -14.4104 +v -6.9456 1.7519 -14.2947 +v -6.9035 1.2405 -14.2230 +v -7.1494 1.7519 -14.2435 +v -7.1527 1.2405 -14.1605 +v -7.2642 1.8995 -14.4310 +v -7.3568 1.8995 -14.6571 +v -7.2994 1.8995 -14.7708 +v -7.0623 1.8995 -14.8303 +v -6.9580 1.8995 -14.7572 +v -6.9329 1.8995 -14.5141 +v -7.0200 1.8995 -14.4213 +v -7.1435 1.8995 -14.3903 +v -7.2254 2.0403 -14.4864 +v -7.2903 2.0403 -14.6448 +v -7.2500 2.0403 -14.7245 +v -7.0840 2.0403 -14.7661 +v -7.0109 2.0403 -14.7150 +v -6.9933 2.0403 -14.5447 +v -7.0543 2.0403 -14.4796 +v -7.1409 2.0403 -14.4579 +v -7.2254 2.0876 -14.4864 +v -7.2903 2.0876 -14.6448 +v -7.2500 2.0876 -14.7245 +v -7.0840 2.0876 -14.7661 +v -7.0109 2.0876 -14.7150 +v -6.9933 2.0876 -14.5447 +v -7.0543 2.0876 -14.4796 +v -7.1409 2.0876 -14.4579 +v -7.2790 2.2023 -14.4098 +v -7.3822 2.2023 -14.6618 +v -7.3182 2.2023 -14.7884 +v -7.0541 2.2023 -14.8547 +v -6.9379 2.2023 -14.7733 +v -6.9099 2.2023 -14.5025 +v -7.0069 2.2023 -14.3990 +v -7.1446 2.2023 -14.3645 +v -7.2790 2.4098 -14.4098 +v -7.3822 2.4098 -14.6618 +v -7.3182 2.4098 -14.7884 +v -7.0541 2.4098 -14.8547 +v -6.9379 2.4098 -14.7733 +v -6.9099 2.4098 -14.5025 +v -7.0069 2.4098 -14.3990 +v -7.1446 2.4098 -14.3645 +v -7.2180 2.5373 -14.4970 +v -7.2775 2.5373 -14.6425 +v -7.2406 2.5373 -14.7156 +v -7.0881 2.5373 -14.7539 +v -7.0210 2.5373 -14.7069 +v -7.0048 2.5373 -14.5505 +v -7.0609 2.5373 -14.4908 +v -7.1403 2.5373 -14.4708 +v -7.1346 2.6507 -14.6161 +v -6.9108 1.5684 -14.6953 +v -6.9040 1.6492 -14.6699 +v -6.4686 1.5228 -14.7866 +v -6.4754 1.4420 -14.8120 +v -6.8820 1.6492 -14.5879 +v -6.4466 1.5228 -14.7046 +v -6.8752 1.5684 -14.5625 +v -6.4398 1.4420 -14.6792 +v -5.8198 1.4280 -14.8449 +v -5.8266 1.3472 -14.8702 +v -5.7978 1.4280 -14.7628 +v -5.7910 1.3472 -14.7374 +v -5.8088 1.2972 -14.8038 +v -7.3680 1.5684 -14.5728 +v -7.8034 1.4420 -14.4561 +v -7.7966 1.5228 -14.4308 +v -7.3612 1.6492 -14.5474 +v -7.7746 1.5228 -14.3487 +v -7.3392 1.6492 -14.4654 +v -7.7678 1.4420 -14.3234 +v -7.3324 1.5684 -14.4400 +v -8.3943 1.3472 -14.1822 +v -8.3875 1.4280 -14.1568 +v -8.3656 1.4280 -14.0748 +v -8.3588 1.3472 -14.0494 +v -8.3766 1.2972 -14.1158 +v -7.0200 -0.0767 -14.5634 +v -7.0200 0.7107 -14.5634 +v -7.2074 0.7107 -14.5132 +v -7.2074 -0.0767 -14.5132 +v -7.2491 0.7107 -14.6688 +v -7.2491 -0.0767 -14.6688 +v -7.0618 0.7107 -14.7190 +v -7.0618 -0.0767 -14.7190 +v -8.6899 1.2649 -14.0852 +v -8.3823 1.0229 -13.7392 +v -8.3250 1.4302 -13.9912 +v -8.7648 1.5864 -14.3129 +v -8.3793 1.0029 -13.7646 +v -8.6869 1.2449 -14.1106 +v -7.7934 1.5234 -14.1874 +v -7.7965 1.5434 -14.1620 +v -7.9644 1.2328 -13.9721 +v -7.9614 1.2128 -13.9975 +v -8.2600 1.7875 -14.3068 +v -8.2630 1.8075 -14.2814 +v -7.8814 1.8305 -14.3350 +v -7.8783 1.8105 -14.3604 +v -8.7617 1.5663 -14.3383 +v -8.6069 1.8626 -14.4481 +v -8.6038 1.8426 -14.4735 +v -5.8940 1.2989 -14.8054 +v -5.7742 1.2989 -14.8054 +v -5.7742 1.3053 -14.7323 +v -5.8940 1.3053 -14.7323 +v -5.8696 3.0809 -14.9463 +v -5.8696 3.0847 -14.9030 +v -5.7987 3.0847 -14.9030 +v -5.7987 3.0809 -14.9463 +v -5.8940 1.5669 -14.8288 +v -5.7742 1.5669 -14.8288 +v -5.7742 1.5733 -14.7557 +v -5.8940 1.5733 -14.7557 +v -5.7742 1.6171 -14.8332 +v -5.8940 1.6171 -14.8332 +v -5.7742 1.6235 -14.7601 +v -5.8940 1.6235 -14.7601 +v -5.3965 1.6235 -14.7601 +v -5.3965 1.5733 -14.7557 +v -5.3965 1.5669 -14.8288 +v -5.3965 1.6171 -14.8332 +v -6.2718 1.6171 -14.8332 +v -6.2718 1.5669 -14.8288 +v -6.2718 1.5733 -14.7557 +v -6.2718 1.6235 -14.7601 +v -3.3736 0.5595 -14.7023 +v -3.3208 0.5595 -14.4598 +v -3.4370 0.9000 -14.3436 +v -3.5276 0.9000 -14.7597 +v -3.2961 0.5595 -14.8059 +v -3.3946 0.9000 -14.9374 +v -3.0485 0.5595 -14.8236 +v -2.9697 0.9000 -14.9678 +v -2.9570 0.5595 -14.7321 +v -2.8128 0.9000 -14.8109 +v -2.9747 0.5595 -14.4845 +v -2.8432 0.9000 -14.3860 +v -3.0783 0.5595 -14.4070 +v -3.0208 0.9000 -14.2530 +v -3.2073 0.5595 -14.3978 +v -3.2422 0.9000 -14.2372 +v -3.4809 1.2405 -14.2997 +v -3.4221 1.7519 -14.3584 +v -3.5078 1.7519 -14.7524 +v -3.5857 1.2405 -14.7814 +v -3.3819 1.7519 -14.9206 +v -3.4318 1.2405 -14.9871 +v -2.9798 1.7519 -14.9493 +v -2.9400 1.2405 -15.0223 +v -2.8312 1.7519 -14.8008 +v -2.7583 1.2405 -14.8406 +v -2.8600 1.7519 -14.3986 +v -2.7935 1.2405 -14.3488 +v -3.0282 1.7519 -14.2727 +v -2.9992 1.2405 -14.1949 +v -3.2377 1.7519 -14.2578 +v -3.2554 1.2405 -14.1765 +v -3.3183 1.8995 -14.4623 +v -3.3702 1.8995 -14.7011 +v -3.2939 1.8995 -14.8030 +v -3.0502 1.8995 -14.8205 +v -2.9601 1.8995 -14.7304 +v -2.9776 1.8995 -14.4866 +v -3.0795 1.8995 -14.4103 +v -3.2065 1.8995 -14.4012 +v -3.2705 2.0403 -14.5101 +v -3.3068 2.0403 -14.6774 +v -3.2534 2.0403 -14.7488 +v -3.0826 2.0403 -14.7611 +v -3.0195 2.0403 -14.6980 +v -3.0317 2.0403 -14.5272 +v -3.1032 2.0403 -14.4737 +v -3.1921 2.0403 -14.4674 +v -3.2705 2.0876 -14.5101 +v -3.3068 2.0876 -14.6774 +v -3.2534 2.0876 -14.7488 +v -3.0826 2.0876 -14.7611 +v -3.0195 2.0876 -14.6980 +v -3.0317 2.0876 -14.5272 +v -3.1032 2.0876 -14.4737 +v -3.1921 2.0876 -14.4674 +v -3.3365 2.2023 -14.4440 +v -3.3944 2.2023 -14.7101 +v -3.3094 2.2023 -14.8237 +v -3.0378 2.2023 -14.8431 +v -2.9375 2.2023 -14.7428 +v -2.9569 2.2023 -14.4712 +v -3.0705 2.2023 -14.3862 +v -3.2120 2.2023 -14.3760 +v -3.3365 2.4098 -14.4440 +v -3.3944 2.4098 -14.7101 +v -3.3094 2.4098 -14.8237 +v -3.0378 2.4098 -14.8431 +v -2.9375 2.4098 -14.7428 +v -2.9569 2.4098 -14.4712 +v -3.0705 2.4098 -14.3862 +v -3.2120 2.4098 -14.3760 +v -3.2613 2.5373 -14.5193 +v -3.2947 2.5373 -14.6729 +v -3.2456 2.5373 -14.7385 +v -3.0888 2.5373 -14.7497 +v -3.0309 2.5373 -14.6918 +v -3.0421 2.5373 -14.5350 +v -3.1077 2.5373 -14.4859 +v -3.1894 2.5373 -14.4800 +v -3.1585 2.6507 -14.6221 +v -2.9244 1.5684 -14.6612 +v -2.9221 1.6492 -14.6351 +v -2.4730 1.5228 -14.6744 +v -2.4753 1.4420 -14.7005 +v -2.9147 1.6492 -14.5504 +v -2.4656 1.5228 -14.5897 +v -2.9124 1.5684 -14.5243 +v -2.4633 1.4420 -14.5636 +v -1.8240 1.4280 -14.6191 +v -1.8263 1.3472 -14.6452 +v -1.8166 1.4280 -14.5344 +v -1.8143 1.3472 -14.5083 +v -1.8203 1.2972 -14.5768 +v -3.3959 1.5684 -14.6200 +v -3.8449 1.4420 -14.5807 +v -3.8426 1.5228 -14.5545 +v -3.3936 1.6492 -14.5938 +v -3.8352 1.5228 -14.4699 +v -3.3862 1.6492 -14.5092 +v -3.8330 1.4420 -14.4438 +v -3.3839 1.5684 -14.4830 +v -4.4745 1.3472 -14.4135 +v -4.4722 1.4280 -14.3874 +v -4.4648 1.4280 -14.3028 +v -4.4625 1.3472 -14.2766 +v -4.4685 1.2972 -14.3451 +v -3.0549 -0.0767 -14.5503 +v -3.0549 0.7107 -14.5503 +v -3.2481 0.7107 -14.5334 +v -3.2481 -0.0767 -14.5334 +v -3.2621 0.7107 -14.6939 +v -3.2621 -0.0767 -14.6939 +v -3.0689 0.7107 -14.7108 +v -3.0689 -0.0767 -14.7108 +v -4.7824 1.2649 -14.3694 +v -4.5396 1.0229 -13.9752 +v -4.4393 1.4302 -14.2134 +v -4.8166 1.5864 -14.6066 +v -4.5321 1.0029 -13.9996 +v -4.7750 1.2449 -14.3938 +v -3.8818 1.5234 -14.3143 +v -3.8892 1.5434 -14.2898 +v -4.0876 1.2328 -14.1320 +v -4.0801 1.2128 -14.1564 +v -4.3205 1.7875 -14.5129 +v -4.3279 1.8075 -14.4884 +v -3.9428 1.8305 -14.4749 +v -3.9353 1.8105 -14.4994 +v -4.8091 1.5663 -14.6311 +v -4.6376 1.8626 -14.7123 +v -4.6302 1.8426 -14.7367 +v -1.9039 1.2989 -14.5931 +v -1.7860 1.2989 -14.5723 +v -1.7986 1.3053 -14.5003 +v -1.9166 1.3053 -14.5211 +v -1.8554 3.0809 -14.7276 +v -1.8629 3.0847 -14.6849 +v -1.7931 3.0847 -14.6726 +v -1.7855 3.0809 -14.7153 +v -1.8999 1.5669 -14.6162 +v -1.7819 1.5669 -14.5954 +v -1.7946 1.5733 -14.5234 +v -1.9125 1.5733 -14.5442 +v -1.7811 1.6171 -14.5997 +v -1.8991 1.6171 -14.6205 +v -1.7938 1.6235 -14.5277 +v -1.9118 1.6235 -14.5485 +v -1.4218 1.6235 -14.4621 +v -1.4226 1.5733 -14.4578 +v -1.4099 1.5669 -14.5298 +v -1.4091 1.6171 -14.5341 +v -2.2711 1.6171 -14.6861 +v -2.2719 1.5669 -14.6818 +v -2.2845 1.5733 -14.6098 +v -2.2838 1.6235 -14.6141 +v -4.8350 0.5595 -9.5807 +v -4.8664 0.5595 -9.8270 +v -4.7405 0.9000 -9.9326 +v -4.6866 0.9000 -9.5101 +v -4.9213 0.5595 -9.4843 +v -4.8346 0.9000 -9.3447 +v -5.1695 0.5595 -9.4883 +v -5.2605 0.9000 -9.3515 +v -5.2526 0.5595 -9.5874 +v -5.4032 0.9000 -9.5215 +v -5.2134 0.5595 -9.8325 +v -5.3359 0.9000 -9.9421 +v -5.1035 0.5595 -9.9007 +v -5.1473 0.9000 -10.0591 +v -4.9741 0.5595 -9.8986 +v -4.9253 0.9000 -10.0556 +v -4.6930 1.2405 -9.9725 +v -4.7567 1.7519 -9.9191 +v -4.7056 1.7519 -9.5192 +v -4.6306 1.2405 -9.4834 +v -4.8457 1.7519 -9.3626 +v -4.8019 1.2405 -9.2920 +v -5.2488 1.7519 -9.3690 +v -5.2949 1.2405 -9.2998 +v -5.3839 1.7519 -9.5299 +v -5.4600 1.2405 -9.4966 +v -5.3202 1.7519 -9.9280 +v -5.3821 1.2405 -9.9834 +v -5.1417 1.7519 -10.0388 +v -5.1638 1.2405 -10.1189 +v -4.9316 1.7519 -10.0355 +v -4.9069 1.2405 -10.1148 +v -4.8692 1.8995 -9.8247 +v -4.8382 1.8995 -9.5823 +v -4.9231 1.8995 -9.4874 +v -5.1675 1.8995 -9.4912 +v -5.2493 1.8995 -9.5888 +v -5.2107 1.8995 -9.8301 +v -5.1025 1.8995 -9.8973 +v -4.9752 1.8995 -9.8952 +v -4.9210 2.0403 -9.7812 +v -4.8993 2.0403 -9.6114 +v -4.9588 2.0403 -9.5449 +v -5.1300 2.0403 -9.5476 +v -5.1873 2.0403 -9.6159 +v -5.1603 2.0403 -9.7850 +v -5.0845 2.0403 -9.8320 +v -4.9953 2.0403 -9.8306 +v -4.9210 2.0876 -9.7812 +v -4.8993 2.0876 -9.6114 +v -4.9588 2.0876 -9.5449 +v -5.1300 2.0876 -9.5476 +v -5.1873 2.0876 -9.6159 +v -5.1603 2.0876 -9.7850 +v -5.0845 2.0876 -9.8320 +v -4.9953 2.0876 -9.8306 +v -4.8494 2.2023 -9.8413 +v -4.8149 2.2023 -9.5712 +v -4.9095 2.2023 -9.4655 +v -5.1818 2.2023 -9.4698 +v -5.2730 2.2023 -9.5785 +v -5.2300 2.2023 -9.8473 +v -5.1094 2.2023 -9.9221 +v -4.9675 2.2023 -9.9199 +v -4.8494 2.4098 -9.8413 +v -4.8149 2.4098 -9.5712 +v -4.9095 2.4098 -9.4655 +v -5.1818 2.4098 -9.4698 +v -5.2730 2.4098 -9.5785 +v -5.2300 2.4098 -9.8473 +v -5.1094 2.4098 -9.9221 +v -4.9675 2.4098 -9.9199 +v -4.9309 2.5373 -9.7729 +v -4.9110 2.5373 -9.6169 +v -4.9656 2.5373 -9.5559 +v -5.1228 2.5373 -9.5584 +v -5.1755 2.5373 -9.6211 +v -5.1506 2.5373 -9.7763 +v -5.0810 2.5373 -9.8195 +v -4.9991 2.5373 -9.8182 +v -5.0423 2.6507 -9.6794 +v -5.2789 1.5684 -9.6608 +v -5.2789 1.6492 -9.6871 +v -5.7297 1.5228 -9.6871 +v -5.7297 1.4420 -9.6608 +v -5.2789 1.6492 -9.7720 +v -5.7297 1.5228 -9.7720 +v -5.2789 1.5684 -9.7983 +v -5.7297 1.4420 -9.7983 +v -6.3714 1.4280 -9.7987 +v -6.3714 1.3472 -9.7725 +v -6.3714 1.4280 -9.8837 +v -6.3715 1.3472 -9.9099 +v -6.3714 1.2972 -9.8412 +v -4.8056 1.5684 -9.6608 +v -4.3549 1.4420 -9.6608 +v -4.3549 1.5228 -9.6871 +v -4.8056 1.6492 -9.6871 +v -4.3549 1.5228 -9.7720 +v -4.8056 1.6492 -9.7720 +v -4.3549 1.4420 -9.7983 +v -4.8056 1.5684 -9.7983 +v -3.7131 1.3472 -9.7725 +v -3.7132 1.4280 -9.7987 +v -3.7131 1.4280 -9.8837 +v -3.7131 1.3472 -9.9099 +v -3.7131 1.2972 -9.8412 +v -5.1393 -0.0767 -9.7600 +v -5.1393 0.7107 -9.7600 +v -4.9453 0.7107 -9.7600 +v -4.9453 -0.0767 -9.7600 +v -4.9453 0.7107 -9.5988 +v -4.9453 -0.0767 -9.5988 +v -5.1393 0.7107 -9.5988 +v -5.1393 -0.0767 -9.5988 +v -3.4025 1.2649 -9.7896 +v -3.6101 1.0229 -10.2035 +v -3.7307 1.4302 -9.9749 +v -3.3892 1.5864 -9.5503 +v -3.6196 1.0029 -10.1798 +v -3.4120 1.2449 -9.7659 +v -4.2949 1.5234 -9.9230 +v -4.2854 1.5434 -9.9467 +v -4.0741 1.2328 -10.0867 +v -4.0836 1.2128 -10.0630 +v -3.8752 1.7875 -9.6869 +v -3.8657 1.8075 -9.7106 +v -4.2482 1.8305 -9.7577 +v -4.2577 1.8105 -9.7340 +v -3.3987 1.5663 -9.5266 +v -3.5767 1.8626 -9.4606 +v -3.5862 1.8426 -9.4369 +v -6.2896 1.2989 -9.8177 +v -6.4053 1.2989 -9.8487 +v -6.3864 1.3053 -9.9193 +v -6.2706 1.3053 -9.8883 +v -6.3496 3.0809 -9.6879 +v -6.3384 3.0847 -9.7297 +v -6.4069 3.0847 -9.7481 +v -6.4181 3.0809 -9.7063 +v -6.2956 1.5669 -9.7950 +v -6.4113 1.5669 -9.8260 +v -6.3924 1.5733 -9.8966 +v -6.2767 1.5733 -9.8656 +v -6.4125 1.6171 -9.8218 +v -6.2968 1.6171 -9.7908 +v -6.3936 1.6235 -9.8924 +v -6.2778 1.6235 -9.8614 +v -6.7584 1.6235 -9.9902 +v -6.7573 1.5733 -9.9944 +v -6.7762 1.5669 -9.9238 +v -6.7773 1.6171 -9.9195 +v -5.9319 1.6171 -9.6930 +v -5.9308 1.5669 -9.6972 +v -5.9118 1.5733 -9.7679 +v -5.9130 1.6235 -9.7636 +v -0.5296 0.5595 -9.5807 +v -0.5610 0.5595 -9.8270 +v -0.4351 0.9000 -9.9326 +v -0.3812 0.9000 -9.5101 +v -0.6158 0.5595 -9.4843 +v -0.5292 0.9000 -9.3447 +v -0.8640 0.5595 -9.4883 +v -0.9550 0.9000 -9.3515 +v -0.9472 0.5595 -9.5874 +v -1.0977 0.9000 -9.5215 +v -0.9079 0.5595 -9.8325 +v -1.0304 0.9000 -9.9421 +v -0.7980 0.5595 -9.9007 +v -0.8418 0.9000 -10.0591 +v -0.6687 0.5595 -9.8986 +v -0.6199 0.9000 -10.0556 +v -0.3875 1.2405 -9.9725 +v -0.4512 1.7519 -9.9191 +v -0.4002 1.7519 -9.5192 +v -0.3251 1.2405 -9.4834 +v -0.5403 1.7519 -9.3626 +v -0.4964 1.2405 -9.2920 +v -0.9434 1.7519 -9.3690 +v -0.9894 1.2405 -9.2998 +v -1.0784 1.7519 -9.5299 +v -1.1546 1.2405 -9.4966 +v -1.0147 1.7519 -9.9280 +v -1.0767 1.2405 -9.9834 +v -0.8362 1.7519 -10.0388 +v -0.8583 1.2405 -10.1189 +v -0.6261 1.7519 -10.0355 +v -0.6015 1.2405 -10.1148 +v -0.5637 1.8995 -9.8247 +v -0.5328 1.8995 -9.5823 +v -0.6177 1.8995 -9.4874 +v -0.8620 1.8995 -9.4912 +v -0.9439 1.8995 -9.5888 +v -0.9053 1.8995 -9.8301 +v -0.7971 1.8995 -9.8973 +v -0.6697 1.8995 -9.8952 +v -0.6156 2.0403 -9.7812 +v -0.5939 2.0403 -9.6114 +v -0.6534 2.0403 -9.5449 +v -0.8246 2.0403 -9.5476 +v -0.8819 2.0403 -9.6159 +v -0.8548 2.0403 -9.7850 +v -0.7790 2.0403 -9.8320 +v -0.6898 2.0403 -9.8306 +v -0.6156 2.0876 -9.7812 +v -0.5939 2.0876 -9.6114 +v -0.6534 2.0876 -9.5449 +v -0.8246 2.0876 -9.5476 +v -0.8819 2.0876 -9.6159 +v -0.8548 2.0876 -9.7850 +v -0.7790 2.0876 -9.8320 +v -0.6898 2.0876 -9.8306 +v -0.5439 2.2023 -9.8413 +v -0.5095 2.2023 -9.5712 +v -0.6041 2.2023 -9.4655 +v -0.8763 2.2023 -9.4698 +v -0.9675 2.2023 -9.5785 +v -0.9245 2.2023 -9.8473 +v -0.8039 2.2023 -9.9221 +v -0.6621 2.2023 -9.9199 +v -0.5439 2.4098 -9.8413 +v -0.5095 2.4098 -9.5712 +v -0.6041 2.4098 -9.4655 +v -0.8763 2.4098 -9.4698 +v -0.9675 2.4098 -9.5785 +v -0.9245 2.4098 -9.8473 +v -0.8039 2.4098 -9.9221 +v -0.6621 2.4098 -9.9199 +v -0.6255 2.5373 -9.7729 +v -0.6056 2.5373 -9.6169 +v -0.6602 2.5373 -9.5559 +v -0.8174 2.5373 -9.5584 +v -0.8700 2.5373 -9.6211 +v -0.8452 2.5373 -9.7763 +v -0.7756 2.5373 -9.8195 +v -0.6937 2.5373 -9.8182 +v -0.7368 2.6507 -9.6794 +v -0.9735 1.5684 -9.6608 +v -0.9735 1.6492 -9.6871 +v -1.4243 1.5228 -9.6871 +v -1.4243 1.4420 -9.6608 +v -0.9735 1.6492 -9.7720 +v -1.4243 1.5228 -9.7720 +v -0.9735 1.5684 -9.7983 +v -1.4243 1.4420 -9.7983 +v -2.0660 1.4280 -9.7987 +v -2.0660 1.3472 -9.7725 +v -2.0660 1.4280 -9.8837 +v -2.0660 1.3472 -9.9099 +v -2.0660 1.2972 -9.8412 +v -0.5002 1.5684 -9.6608 +v -0.0494 1.4420 -9.6608 +v -0.0494 1.5228 -9.6871 +v -0.5002 1.6492 -9.6871 +v -0.0494 1.5228 -9.7720 +v -0.5002 1.6492 -9.7720 +v -0.0494 1.4420 -9.7983 +v -0.5002 1.5684 -9.7983 +v 0.5923 1.3472 -9.7725 +v 0.5923 1.4280 -9.7987 +v 0.5923 1.4280 -9.8837 +v 0.5923 1.3472 -9.9099 +v 0.5923 1.2972 -9.8412 +v -0.8338 -0.0767 -9.7600 +v -0.8338 0.7107 -9.7600 +v -0.6399 0.7107 -9.7600 +v -0.6399 -0.0767 -9.7600 +v -0.6399 0.7107 -9.5988 +v -0.6399 -0.0767 -9.5988 +v -0.8338 0.7107 -9.5988 +v -0.8338 -0.0767 -9.5988 +v 0.9029 1.2649 -9.7896 +v 0.6954 1.0229 -10.2035 +v 0.5747 1.4302 -9.9749 +v 0.9163 1.5864 -9.5503 +v 0.6858 1.0029 -10.1798 +v 0.8934 1.2449 -9.7659 +v 0.0105 1.5234 -9.9230 +v 0.0201 1.5434 -9.9467 +v 0.2314 1.2328 -10.0867 +v 0.2219 1.2128 -10.0630 +v 0.4303 1.7875 -9.6869 +v 0.4398 1.8075 -9.7106 +v 0.0573 1.8305 -9.7577 +v 0.0477 1.8105 -9.7340 +v 0.9067 1.5663 -9.5266 +v 0.7288 1.8626 -9.4606 +v 0.7193 1.8426 -9.4369 +v -1.9841 1.2989 -9.8177 +v -2.0998 1.2989 -9.8487 +v -2.0809 1.3053 -9.9193 +v -1.9652 1.3053 -9.8883 +v -2.0442 3.0809 -9.6879 +v -2.0330 3.0847 -9.7297 +v -2.1015 3.0847 -9.7481 +v -2.1127 3.0809 -9.7063 +v -1.9902 1.5669 -9.7950 +v -2.1059 1.5669 -9.8260 +v -2.0870 1.5733 -9.8966 +v -1.9712 1.5733 -9.8656 +v -2.1070 1.6171 -9.8218 +v -1.9913 1.6171 -9.7908 +v -2.0881 1.6235 -9.8924 +v -1.9724 1.6235 -9.8614 +v -2.4530 1.6235 -9.9902 +v -2.4518 1.5733 -9.9944 +v -2.4708 1.5669 -9.9238 +v -2.4719 1.6171 -9.9195 +v -1.6265 1.6171 -9.6930 +v -1.6253 1.5669 -9.6972 +v -1.6064 1.5733 -9.7679 +v -1.6075 1.6235 -9.7636 +v -7.0597 1.5017 2.9909 +v -6.9399 1.5017 2.9909 +v -6.9399 1.5268 2.9219 +v -7.0597 1.5268 2.9219 +v -7.0353 -0.1729 2.3655 +v -7.0353 -0.1580 2.3246 +v -6.9643 -0.1580 2.3246 +v -6.9643 -0.1729 2.3655 +v -7.0597 1.2489 2.8989 +v -6.9399 1.2489 2.8989 +v -6.9399 1.2740 2.8299 +v -7.0597 1.2740 2.8299 +v -6.9399 1.2015 2.8816 +v -7.0597 1.2015 2.8816 +v -6.9399 1.2266 2.8127 +v -7.0597 1.2266 2.8127 +v -6.5622 1.2266 2.8127 +v -6.5622 1.2740 2.8299 +v -6.5622 1.2489 2.8989 +v -6.5622 1.2015 2.8816 +v -7.4374 1.2015 2.8816 +v -7.4374 1.2489 2.8989 +v -7.4374 1.2740 2.8299 +v -7.4374 1.2266 2.8127 +v -7.0632 0.0497 2.4800 +v -7.0653 0.0489 2.5758 +v -5.9749 0.0496 2.5758 +v -5.9776 0.0497 2.4800 +v -7.0632 -0.0767 2.4800 +v -5.9776 -0.0767 2.4800 +v -7.2299 -0.0767 2.4800 +v -7.2342 -0.0766 2.5758 +v -7.2320 0.0491 2.5758 +v -7.2299 0.0497 2.4800 +v -5.9723 -0.0761 2.5758 +v -7.0674 -0.0769 2.5758 +v -5.8058 -0.0759 2.5758 +v -5.8109 -0.0767 2.4800 +v -5.8109 0.0497 2.4800 +v -5.8083 0.0499 2.5758 +v -7.2299 1.4067 2.9473 +v -7.2299 1.4067 3.0439 +v -7.0632 1.4067 3.0439 +v -7.0632 1.4067 2.9473 +v -5.8109 1.4067 3.0439 +v -5.8109 1.4067 2.9473 +v -5.9769 1.4067 2.9473 +v -5.9769 1.4067 3.0439 +v -7.2299 1.2410 3.0439 +v -7.2299 1.2401 2.9473 +v -7.0632 1.2405 3.0439 +v -7.0632 1.2421 2.9473 +v -5.9773 1.2437 2.9473 +v -5.8109 1.2435 2.9473 +v -5.9773 1.2420 3.0439 +v -5.8109 1.2425 3.0439 +v -5.8109 1.4067 3.4851 +v -5.9769 1.4067 3.4851 +v -5.9773 1.2420 3.4851 +v -5.8109 1.2425 3.4851 +v -7.0632 1.4067 3.4851 +v -7.2299 1.4067 3.4851 +v -7.2299 1.2410 3.4851 +v -7.0632 1.2405 3.4851 +v -5.9670 -0.0755 3.3494 +v -5.9722 0.0495 3.3494 +v -5.8058 0.0500 3.3494 +v -5.8007 -0.0750 3.3494 +v -7.2384 -0.0765 3.3494 +v -7.2342 0.0485 3.3494 +v -7.0674 0.0480 3.3494 +v -7.0716 -0.0770 3.3494 +v -6.4628 0.2134 2.4968 +v -6.6246 -0.0549 2.0788 +v -6.8162 0.3198 2.3147 +v -6.5070 0.5277 2.7418 +v -6.6303 -0.0767 2.1021 +v -6.4685 0.1916 2.5202 +v -7.3877 0.3084 2.3685 +v -7.3821 0.3302 2.3451 +v -7.1185 0.0655 2.1995 +v -7.1242 0.0436 2.2229 +v -7.0219 0.6399 2.6091 +v -7.0162 0.6617 2.5857 +v -7.3967 0.6159 2.5393 +v -7.4024 0.5941 2.5626 +v -6.5126 0.5059 2.7652 +v -6.7410 0.7639 2.8365 +v -6.7467 0.7420 2.8599 +v -6.1035 1.5017 2.9909 +v -5.9837 1.5017 2.9909 +v -5.9837 1.5268 2.9219 +v -6.1035 1.5268 2.9219 +v -6.0791 -0.1729 2.3655 +v -6.0791 -0.1580 2.3246 +v -6.0081 -0.1580 2.3246 +v -6.0081 -0.1729 2.3655 +v -6.1035 1.2489 2.8989 +v -5.9837 1.2489 2.8989 +v -5.9837 1.2740 2.8299 +v -6.1035 1.2740 2.8299 +v -5.9837 1.2015 2.8816 +v -6.1035 1.2015 2.8816 +v -5.9837 1.2266 2.8127 +v -6.1035 1.2266 2.8127 +v -5.6060 1.2266 2.8127 +v -5.6060 1.2740 2.8299 +v -5.6060 1.2489 2.8989 +v -5.6060 1.2015 2.8816 +v -6.4812 1.2015 2.8816 +v -6.4812 1.2489 2.8989 +v -6.4812 1.2740 2.8299 +v -6.4812 1.2266 2.8127 +v 9.6897 1.5017 1.5610 +v 9.7404 1.5017 1.4524 +v 9.6778 1.5268 1.4232 +v 9.6272 1.5268 1.5318 +v 9.1332 -0.1729 1.2745 +v 9.0962 -0.1580 1.2572 +v 9.1262 -0.1580 1.1930 +v 9.1632 -0.1729 1.2102 +v 9.6063 1.2489 1.5221 +v 9.6569 1.2489 1.4135 +v 9.5944 1.2740 1.3844 +v 9.5438 1.2740 1.4929 +v 9.6413 1.2015 1.4062 +v 9.5907 1.2015 1.5148 +v 9.5788 1.2266 1.3771 +v 9.5282 1.2266 1.4856 +v 9.7384 1.2266 1.0347 +v 9.7541 1.2740 1.0420 +v 9.8166 1.2489 1.0712 +v 9.8009 1.2015 1.0639 +v 9.4311 1.2015 1.8571 +v 9.4467 1.2489 1.8644 +v 9.3842 1.2740 1.8353 +v 9.3685 1.2266 1.8280 +v 9.2252 0.0497 1.3482 +v 9.3111 0.0489 1.3906 +v 9.7720 0.0496 0.4024 +v 9.6840 0.0497 0.3643 +v 9.2252 -0.0767 1.3482 +v 9.6840 -0.0767 0.3643 +v 9.1547 -0.0767 1.4993 +v 9.2398 -0.0766 1.5436 +v 9.2407 0.0491 1.5417 +v 9.1547 0.0497 1.4993 +v 9.7731 -0.0761 0.4000 +v 9.3102 -0.0769 1.3925 +v 9.8434 -0.0759 0.2491 +v 9.7545 -0.0767 0.2132 +v 9.7545 0.0497 0.2132 +v 9.8423 0.0499 0.2514 +v 9.5783 1.4067 1.6968 +v 9.6658 1.4067 1.7376 +v 9.7363 1.4067 1.5865 +v 9.6488 1.4067 1.5457 +v 10.2655 1.4067 0.4516 +v 10.1780 1.4067 0.4107 +v 10.1078 1.4067 0.5612 +v 10.1954 1.4067 0.6020 +v 9.6658 1.2410 1.7376 +v 9.5783 1.2401 1.6968 +v 9.7363 1.2405 1.5865 +v 9.6488 1.2421 1.5457 +v 10.1077 1.2437 0.5615 +v 10.1780 1.2435 0.4107 +v 10.1952 1.2420 0.6024 +v 10.2655 1.2425 0.4516 +v 10.6654 1.4067 0.6380 +v 10.5952 1.4067 0.7885 +v 10.5951 1.2420 0.7888 +v 10.6654 1.2425 0.6380 +v 10.1362 1.4067 1.7730 +v 10.0657 1.4067 1.9241 +v 10.0657 1.2410 1.9241 +v 10.1362 1.2405 1.7730 +v 10.4764 -0.0755 0.7222 +v 10.4742 0.0495 0.7268 +v 10.5445 0.0500 0.5760 +v 10.5467 -0.0750 0.5714 +v 9.9391 -0.0765 1.8744 +v 9.9409 0.0485 1.8706 +v 10.0113 0.0480 1.7194 +v 10.0095 -0.0770 1.7233 +v 9.4942 0.2134 0.8112 +v 9.0469 -0.0549 0.7812 +v 9.1798 0.3198 1.0545 +v 9.6976 0.5277 0.9547 +v 9.0657 -0.0767 0.7962 +v 9.5130 0.1916 0.8262 +v 8.9869 0.3084 1.5952 +v 8.9682 0.3302 1.5802 +v 8.9476 0.0655 1.2798 +v 8.9664 0.0436 1.2948 +v 9.3596 0.6399 1.3653 +v 9.3409 0.6617 1.3503 +v 9.1379 0.6159 1.6755 +v 9.1567 0.5941 1.6905 +v 9.7163 0.5059 0.9698 +v 9.6845 0.7639 1.2069 +v 9.7032 0.7420 1.2219 +v 10.0938 1.5017 0.6944 +v 10.1445 1.5017 0.5858 +v 10.0820 1.5268 0.5566 +v 10.0313 1.5268 0.6652 +v 9.5373 -0.1729 0.4079 +v 9.5003 -0.1580 0.3906 +v 9.5303 -0.1580 0.3263 +v 9.5673 -0.1729 0.3436 +v 10.0104 1.2489 0.6555 +v 10.0611 1.2489 0.5469 +v 9.9985 1.2740 0.5177 +v 9.9479 1.2740 0.6263 +v 10.0454 1.2015 0.5396 +v 9.9948 1.2015 0.6482 +v 9.9829 1.2266 0.5105 +v 9.9323 1.2266 0.6190 +v 10.1426 1.2266 0.1681 +v 10.1582 1.2740 0.1754 +v 10.2207 1.2489 0.2045 +v 10.2051 1.2015 0.1973 +v 9.8352 1.2015 0.9905 +v 9.8508 1.2489 0.9978 +v 9.7883 1.2740 0.9687 +v 9.7726 1.2266 0.9614 +v 9.6653 1.5017 -8.2456 +v 9.5883 1.5017 -8.3374 +v 9.5355 1.5268 -8.2930 +v 9.6125 1.5268 -8.2013 +v 9.1705 -0.1729 -7.8623 +v 9.1392 -0.1580 -7.8361 +v 9.0936 -0.1580 -7.8904 +v 9.1249 -0.1729 -7.9166 +v 9.5948 1.2489 -8.1864 +v 9.5178 1.2489 -8.2782 +v 9.4650 1.2740 -8.2339 +v 9.5420 1.2740 -8.1421 +v 9.5046 1.2015 -8.2671 +v 9.5816 1.2015 -8.1754 +v 9.4518 1.2266 -8.2228 +v 9.5288 1.2266 -8.1310 +v 9.2090 1.2266 -8.5122 +v 9.2222 1.2740 -8.5232 +v 9.2750 1.2489 -8.5676 +v 9.2618 1.2015 -8.5565 +v 9.8244 1.2015 -7.8860 +v 9.8376 1.2489 -7.8971 +v 9.7848 1.2740 -7.8528 +v 9.7716 1.2266 -7.8417 +v 9.2762 0.0497 -7.9145 +v 9.3509 0.0489 -7.9745 +v 8.6500 0.0496 -8.8098 +v 8.5784 0.0497 -8.7461 +v 9.2762 -0.0767 -7.9145 +v 8.5784 -0.0767 -8.7461 +v 9.3834 -0.0767 -7.7868 +v 9.4595 -0.0766 -7.8451 +v 9.4581 0.0491 -7.8468 +v 9.3834 0.0497 -7.7868 +v 8.6484 -0.0761 -8.8118 +v 9.3523 -0.0769 -7.9729 +v 8.5413 -0.0759 -8.9393 +v 8.4712 -0.0767 -8.8738 +v 8.4712 0.0497 -8.8738 +v 8.5430 0.0499 -8.9374 +v 9.7414 1.4067 -8.0872 +v 9.8153 1.4067 -8.1493 +v 9.7082 1.4067 -8.2770 +v 9.6342 1.4067 -8.2149 +v 8.9032 1.4067 -9.2363 +v 8.8292 1.4067 -9.1742 +v 8.9359 1.4067 -9.0471 +v 9.0099 1.4067 -9.1091 +v 9.8153 1.2410 -8.1493 +v 9.7414 1.2401 -8.0872 +v 9.7082 1.2405 -8.2770 +v 9.6342 1.2421 -8.2149 +v 8.9362 1.2437 -9.0468 +v 8.8292 1.2435 -9.1742 +v 9.0102 1.2420 -9.1089 +v 8.9032 1.2425 -9.2363 +v 9.2412 1.4067 -9.5199 +v 9.3479 1.4067 -9.3927 +v 9.3481 1.2420 -9.3925 +v 9.2412 1.2425 -9.5199 +v 10.0461 1.4067 -8.5606 +v 10.1533 1.4067 -8.4329 +v 10.1533 1.2410 -8.4329 +v 10.0461 1.2405 -8.5606 +v 9.2376 -0.0755 -9.3130 +v 9.2408 0.0495 -9.3091 +v 9.1339 0.0500 -9.4366 +v 9.1306 -0.0750 -9.4405 +v 10.0548 -0.0765 -8.3391 +v 10.0520 0.0485 -8.3424 +v 9.9449 0.0480 -8.4701 +v 9.9476 -0.0770 -8.4669 +v 8.9031 0.2134 -8.3853 +v 8.6869 -0.0549 -7.9926 +v 8.9907 0.3198 -7.9975 +v 9.1192 0.5277 -8.5089 +v 8.7084 -0.0767 -8.0032 +v 8.9246 0.1916 -8.3959 +v 9.3993 0.3084 -7.5942 +v 9.3778 0.3302 -7.5835 +v 9.0969 0.0655 -7.6919 +v 9.1184 0.0436 -7.7026 +v 9.3485 0.6399 -8.0291 +v 9.3269 0.6617 -8.0185 +v 9.5360 0.6159 -7.6971 +v 9.5575 0.5941 -7.7078 +v 9.1408 0.5059 -8.5196 +v 9.3422 0.7639 -8.3905 +v 9.3637 0.7420 -8.4012 +v 9.0507 1.5017 -8.9781 +v 8.9737 1.5017 -9.0699 +v 8.9208 1.5268 -9.0255 +v 8.9978 1.5268 -8.9338 +v 8.5559 -0.1729 -8.5948 +v 8.5246 -0.1580 -8.5686 +v 8.4790 -0.1580 -8.6229 +v 8.5103 -0.1729 -8.6491 +v 8.9802 1.2489 -8.9189 +v 8.9032 1.2489 -9.0107 +v 8.8503 1.2740 -8.9664 +v 8.9274 1.2740 -8.8746 +v 8.8900 1.2015 -8.9996 +v 8.9670 1.2015 -8.9079 +v 8.8371 1.2266 -8.9553 +v 8.9141 1.2266 -8.8635 +v 8.5943 1.2266 -9.2447 +v 8.6075 1.2740 -9.2557 +v 8.6604 1.2489 -9.3001 +v 8.6472 1.2015 -9.2890 +v 9.2098 1.2015 -8.6185 +v 9.2230 1.2489 -8.6296 +v 9.1701 1.2740 -8.5853 +v 9.1569 1.2266 -8.5742 +# 7481 vertices + +vn -0.9963 -0.0483 -0.0716 +vn -1.0000 0.0000 0.0000 +vn -0.9997 -0.0248 0.0000 +vn -0.9978 -0.0657 0.0000 +vn 0.0000 -0.0000 1.0000 +vn -0.0000 0.0000 -1.0000 +vn -0.9963 -0.0483 0.0716 +vn 1.0000 0.0000 -0.0000 +vn -0.9976 -0.0691 -0.0006 +vn -0.9972 -0.0740 0.0044 +vn -0.9978 -0.0585 -0.0318 +vn -0.9985 -0.0550 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.8219 0.5696 +vn 0.0000 1.0000 0.0000 +vn -0.0000 -0.0000 -1.0000 +vn -0.0000 -0.9972 -0.0745 +vn 0.0000 -1.0000 0.0000 +vn -0.9978 -0.0586 0.0315 +vn -0.9972 -0.0747 -0.0060 +vn -0.0000 0.8219 -0.5696 +vn 0.0000 -0.9972 0.0745 +vn -0.0000 -0.8092 -0.5875 +vn 0.0000 -0.8092 0.5875 +vn 0.0000 0.9968 0.0803 +vn -0.0001 0.9968 0.0803 +vn -0.0001 0.9982 -0.0593 +vn -0.0000 0.9982 -0.0593 +vn -0.9972 -0.0747 -0.0047 +vn -0.9972 -0.0694 -0.0272 +vn -0.9972 -0.0740 0.0077 +vn -0.9972 -0.0694 0.0272 +vn -0.0000 0.9946 -0.1034 +vn 0.0000 0.9982 -0.0593 +vn 0.0000 0.9980 0.0634 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 1.0000 0.0000 +vn -0.1198 0.9926 0.0202 +vn -0.0181 0.8430 -0.5376 +vn -0.0395 0.8691 -0.4930 +vn -0.0263 0.9996 0.0128 +vn 0.1422 0.9898 0.0041 +vn 0.0244 0.8365 0.5474 +vn -0.0243 0.8529 0.5215 +vn -0.9518 0.1435 -0.2712 +vn -0.9882 -0.0000 -0.1529 +vn -0.9882 0.0000 0.1529 +vn 0.0180 -0.8430 0.5376 +vn 0.1118 -0.8730 0.4747 +vn 0.0108 0.8458 -0.5335 +vn 0.0716 0.7912 -0.6074 +vn 0.2586 0.9660 0.0000 +vn -0.0970 0.8030 -0.5881 +vn -0.2585 0.9658 0.0187 +vn 0.0000 0.8209 0.5711 +vn -0.0820 0.7799 0.6205 +vn 0.0813 0.7867 0.6120 +vn 0.0177 -0.8274 0.5613 +vn -0.1940 -0.7247 0.6612 +vn 0.0188 -0.8811 0.4725 +vn -0.1062 -0.8289 0.5492 +vn 0.1978 -0.7388 0.6442 +vn -0.0000 -0.8209 -0.5711 +vn -0.1943 -0.7259 -0.6597 +vn 0.1905 -0.7117 -0.6762 +vn 0.0453 0.0000 -0.9990 +vn 0.0509 -0.0000 -0.9987 +vn 0.0327 0.0000 -0.9995 +vn -0.2538 -0.9673 0.0000 +vn -0.1334 -0.9911 0.0000 +vn 0.0453 -0.0000 0.9990 +vn 0.0327 -0.0000 0.9995 +vn 0.0509 -0.0000 0.9987 +vn 0.3347 0.9423 -0.0000 +vn 0.1961 0.9806 -0.0000 +vn 0.0631 -0.0000 -0.9980 +vn -0.3639 -0.9315 0.0000 +vn 0.0631 -0.0000 0.9980 +vn 0.4594 0.8882 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn 0.9784 -0.2067 0.0000 +vn 0.9784 -0.2069 -0.0000 +vn 0.1637 0.7745 0.6111 +vn -0.9784 0.2067 -0.0000 +vn -0.9784 0.2068 -0.0000 +vn 0.9784 -0.2069 0.0000 +vn 0.9784 -0.2068 -0.0001 +vn 0.2054 0.9718 0.1161 +vn -0.9784 0.2068 -0.0001 +vn 0.9784 -0.2067 -0.0000 +vn 0.1637 0.7745 -0.6111 +vn 0.9784 -0.2068 0.0001 +vn 0.2054 0.9718 -0.1161 +vn -0.9784 0.2068 0.0001 +vn -0.9784 0.2068 0.0000 +vn 0.9784 -0.2068 -0.0000 +vn 0.2054 0.9718 0.1162 +vn 0.9784 -0.2068 0.0000 +vn 0.9784 -0.2067 -0.0001 +vn 0.2054 0.9718 -0.1162 +vn 0.9784 -0.2067 0.0001 +vn 0.1362 0.7798 0.6111 +vn 0.1363 0.7798 0.6111 +vn 0.9851 -0.1722 -0.0000 +vn 0.9851 -0.1721 0.0000 +vn 0.1710 0.9784 0.1162 +vn 0.9851 -0.1722 0.0001 +vn 0.9851 -0.1721 -0.0000 +vn 0.1363 0.7798 -0.6111 +vn 0.1362 0.7798 -0.6111 +vn 0.9851 -0.1722 0.0000 +vn 0.1710 0.9784 -0.1162 +vn 0.9851 -0.1722 -0.0001 +vn 0.0956 0.7858 0.6111 +vn 0.9927 -0.1207 0.0000 +vn 0.1199 0.9860 0.1162 +vn 0.1199 0.9860 0.1161 +vn 0.9927 -0.1207 -0.0000 +vn 0.0956 0.7858 -0.6111 +vn 0.1199 0.9860 -0.1162 +vn 0.1199 0.9860 -0.1161 +vn 0.9927 -0.1207 0.0001 +vn 0.0955 0.7858 -0.6111 +vn 0.9927 -0.1207 -0.0001 +vn 0.0423 0.7905 0.6111 +vn 0.9986 -0.0535 0.0000 +vn 0.0531 0.9918 0.1162 +vn 0.0531 0.9918 0.1161 +vn 0.9986 -0.0535 -0.0000 +vn 0.0423 0.7905 -0.6111 +vn 0.0531 0.9918 -0.1162 +vn 0.0531 0.9918 -0.1161 +vn -0.9927 -0.1208 -0.0000 +vn -0.9927 -0.1207 -0.0000 +vn -0.0956 0.7858 0.6111 +vn 0.9927 0.1207 -0.0000 +vn 0.9927 0.1207 0.0000 +vn -0.9927 -0.1208 0.0001 +vn -0.9927 -0.1207 -0.0001 +vn -0.1199 0.9860 0.1161 +vn 0.9927 0.1207 -0.0001 +vn 0.0000 0.0000 -1.0000 +vn -0.9927 -0.1208 0.0000 +vn -0.9927 -0.1207 0.0000 +vn -0.0956 0.7858 -0.6111 +vn -0.9927 -0.1208 -0.0001 +vn -0.9927 -0.1207 0.0001 +vn -0.1199 0.9860 -0.1161 +vn 0.9927 0.1207 0.0001 +vn -0.0267 0.7911 0.6111 +vn -0.9994 -0.0338 -0.0000 +vn -0.0335 0.9927 0.1162 +vn -0.0335 0.9927 0.1163 +vn -0.9994 -0.0337 -0.0001 +vn -0.9994 -0.0338 0.0000 +vn -0.0267 0.7911 -0.6111 +vn -0.0335 0.9927 -0.1162 +vn -0.0335 0.9927 -0.1163 +vn -0.9994 -0.0337 0.0001 +vn -0.0678 0.7887 0.6111 +vn -0.9963 -0.0856 -0.0000 +vn -0.0850 0.9896 0.1162 +vn -0.9963 -0.0855 -0.0001 +vn -0.9963 -0.0856 0.0001 +vn -0.0678 0.7887 -0.6111 +vn -0.9963 -0.0856 0.0000 +vn -0.0850 0.9896 -0.1162 +vn -0.9963 -0.0856 -0.0001 +vn -0.9963 -0.0855 0.0001 +vn -0.1199 0.9860 0.1162 +vn -0.0955 0.7858 -0.6111 +vn -0.1199 0.9860 -0.1162 +vn -0.9994 -0.0337 0.0000 +vn -0.0335 0.9927 0.1161 +vn -0.9994 -0.0337 -0.0000 +vn -0.0335 0.9927 -0.1161 +vn -0.9927 0.1207 0.0000 +vn -0.9927 0.1207 -0.0000 +vn -0.9927 0.1208 -0.0000 +vn 0.9927 0.1206 -0.0000 +vn 0.9927 0.1208 0.0000 +vn 0.9927 0.1208 -0.0001 +vn 0.0000 -0.0000 -1.0000 +vn 0.9927 0.1208 -0.0000 +vn 0.9927 0.1206 0.0000 +vn 0.9927 0.1208 0.0001 +vn 0.0001 -0.0114 -0.9999 +vn -0.0007 -0.0121 -0.9999 +vn 0.0052 -0.0096 -0.9999 +vn -0.0000 -0.0090 -1.0000 +vn -1.0000 0.0000 0.0002 +vn -0.5696 0.8219 0.0002 +vn 0.0745 -0.9972 0.0000 +vn 0.0000 -1.0000 -0.0000 +vn -0.0051 -0.0096 -0.9999 +vn 0.0010 -0.0123 -0.9999 +vn 0.5696 0.8219 -0.0001 +vn -0.0745 -0.9972 -0.0000 +vn 0.9999 -0.0110 -0.0000 +vn 0.9999 -0.0109 -0.0014 +vn 0.5875 -0.8092 -0.0009 +vn -0.5875 -0.8092 0.0009 +vn -0.5875 -0.8092 0.0006 +vn -0.9999 0.0110 0.0010 +vn -0.9999 0.0111 -0.0003 +vn -0.0803 0.9968 -0.0000 +vn -0.0803 0.9968 -0.0001 +vn 0.0593 0.9982 -0.0000 +vn 0.0008 -0.0123 -0.9999 +vn 0.0045 -0.0114 -0.9999 +vn 0.9999 -0.0102 -0.0001 +vn 0.9999 -0.0103 -0.0000 +vn 0.9999 -0.0102 -0.0002 +vn -0.9999 0.0103 -0.0001 +vn -0.9999 0.0103 -0.0002 +vn -0.9999 0.0102 0.0004 +vn -0.0012 -0.0121 -0.9999 +vn -0.0044 -0.0113 -0.9999 +vn -1.0000 -0.0000 -0.0001 +vn 0.1034 0.9946 -0.0000 +vn -0.0634 0.9980 -0.0000 +vn 1.0000 -0.0000 -0.0002 +vn -0.0745 -0.9972 0.0000 +vn -0.0000 -1.0000 0.0000 +vn 0.0001 -0.0000 -1.0000 +vn 0.0000 1.0000 -0.0000 +vn -0.5808 0.7502 0.3160 +vn -0.6749 0.7133 -0.1892 +vn -0.6402 0.7454 -0.1856 +vn -0.5286 0.8038 0.2731 +vn -0.1688 0.7582 0.6298 +vn -0.1539 0.8041 0.5743 +vn 0.3260 0.7582 0.5647 +vn 0.2973 0.8041 0.5149 +vn 0.6298 0.7582 0.1688 +vn 0.5743 0.8041 0.1539 +vn 0.5647 0.7582 -0.3260 +vn 0.5149 0.8041 -0.2973 +vn 0.1688 0.7582 -0.6298 +vn 0.1404 0.7962 -0.5885 +vn -0.3673 0.7221 -0.5862 +vn -0.3538 0.7376 -0.5751 +vn -0.7497 0.6544 0.0987 +vn -0.5999 0.6544 -0.4603 +vn -0.4603 0.6544 0.5999 +vn 0.0987 0.6544 0.7497 +vn 0.5999 0.6544 0.4603 +vn 0.7497 0.6544 -0.0987 +vn 0.4603 0.6544 -0.5999 +vn -0.0987 0.6544 -0.7497 +vn -0.9998 0.0000 0.0186 +vn -0.9998 -0.0000 0.0186 +vn -0.6088 0.0000 0.7934 +vn 0.1305 0.0000 0.9914 +vn 0.7934 -0.0000 0.6088 +vn 0.7934 0.0000 0.6088 +vn 0.9914 0.0000 -0.1305 +vn 0.6088 0.0000 -0.7934 +vn -0.2276 0.0000 -0.9738 +vn -0.7934 0.0000 -0.6088 +vn -0.2844 0.9378 -0.1991 +vn -0.4063 0.8683 -0.2845 +vn 0.0686 0.9965 0.0480 +vn -0.4506 0.8351 -0.3155 +vn -0.8182 0.0481 -0.5729 +vn 0.5736 0.0036 -0.8191 +vn 0.5726 0.0579 -0.8178 +vn -0.8191 0.0053 -0.5736 +vn -0.8126 0.1266 -0.5690 +vn -0.5736 0.0034 0.8191 +vn -0.5735 -0.0138 0.8191 +vn 0.8191 0.0049 0.5736 +vn 0.8175 -0.0623 0.5725 +vn 0.5728 -0.0511 -0.8181 +vn -0.8136 -0.1166 -0.5697 +vn -0.5735 0.0207 0.8190 +vn 0.8170 0.0724 0.5721 +vn -0.5736 0.0036 0.8191 +vn -0.5726 0.0579 0.8178 +vn 0.5736 0.0034 -0.8192 +vn 0.5735 -0.0138 -0.8191 +vn 0.8176 -0.0623 0.5724 +vn -0.5728 -0.0511 0.8181 +vn -0.8135 -0.1166 -0.5697 +vn 0.5735 0.0207 -0.8190 +vn -0.8235 0.4943 0.2784 +vn -0.7949 0.5296 0.2960 +vn -0.2250 0.5263 0.8200 +vn -0.2255 0.4770 0.8495 +vn -0.9099 0.2560 0.3265 +vn -0.2479 0.2511 0.9357 +vn -0.9314 0.0324 0.3627 +vn -0.2578 0.0300 0.9657 +vn -0.9351 0.0077 0.3543 +vn -0.2588 0.0000 0.9659 +vn -0.9386 0.0000 0.3449 +vn -0.9560 0.1873 -0.2259 +vn -0.9476 0.1711 -0.2698 +vn -0.9806 0.0934 -0.1726 +vn -0.9828 0.0501 -0.1779 +vn -0.9753 0.1168 -0.1876 +vn -0.9710 0.1469 -0.1887 +vn 0.0592 0.4877 -0.8710 +vn 0.0776 0.5413 -0.8372 +vn -0.4447 0.1942 -0.8744 +vn -0.4185 0.1747 -0.8913 +vn 0.1004 0.2548 -0.9618 +vn -0.3822 0.0939 -0.9193 +vn 0.1305 0.0324 -0.9909 +vn -0.3886 0.0526 -0.9199 +vn 0.1253 0.0041 -0.9921 +vn -0.4112 0.1412 -0.9005 +vn 0.1192 0.0119 -0.9928 +vn -0.4203 0.2169 -0.8811 +vn 0.7621 0.4770 -0.4377 +vn 0.7338 0.5263 -0.4296 +vn 0.8396 0.2511 -0.4816 +vn 0.8661 0.0300 -0.4989 +vn 0.8660 0.0000 -0.5000 +vn 0.8553 0.4643 0.2300 +vn 0.8293 0.5137 0.2200 +vn 0.9370 0.2417 0.2522 +vn 0.9655 0.0277 0.2591 +vn 0.9659 -0.0000 0.2588 +vn 0.4435 0.4643 0.7666 +vn 0.4271 0.5137 0.7441 +vn 0.4862 0.2417 0.8398 +vn 0.5001 0.0277 0.8655 +vn 0.5000 0.0000 0.8660 +vn -0.9391 -0.1373 -0.3151 +vn -0.9949 -0.1011 0.0000 +vn -0.9965 -0.0835 0.0000 +vn -0.9670 -0.0794 -0.2419 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 -0.7146 -0.6995 +vn 0.0000 0.0030 1.0000 +vn 0.0000 0.0510 0.9987 +vn 0.0000 -0.3074 0.9516 +vn -0.0000 0.9651 -0.2619 +vn -0.0000 0.0030 -1.0000 +vn -0.0000 0.0510 -0.9987 +vn -0.0000 0.3594 -0.9332 +vn -0.9391 -0.1373 0.3151 +vn -0.9670 -0.0794 0.2419 +vn 0.0000 -0.7146 0.6995 +vn 0.0000 0.9651 0.2619 +vn -0.9996 -0.0298 -0.0000 +vn -0.9784 -0.0790 -0.1912 +vn 0.0000 0.3594 0.9332 +vn -0.0000 -0.3074 -0.9516 +vn -0.9784 -0.0790 0.1912 +vn 0.9391 -0.1373 0.3151 +vn 0.9949 -0.1011 -0.0000 +vn 0.9965 -0.0835 -0.0000 +vn 0.9670 -0.0794 0.2419 +vn 0.9391 -0.1373 -0.3151 +vn 0.9670 -0.0794 -0.2419 +vn 0.9996 -0.0298 -0.0000 +vn 0.9784 -0.0790 0.1912 +vn 0.9784 -0.0790 -0.1912 +vn -0.0000 0.9780 -0.2086 +vn -0.0000 -0.9780 -0.2086 +vn 0.0000 0.9780 0.2086 +vn 0.0000 -0.9780 0.2086 +vn 0.5107 0.0135 0.8597 +vn 0.1707 0.0283 0.9849 +vn -0.9257 0.3783 -0.0000 +vn -0.9997 -0.0264 -0.0000 +vn 0.5107 0.0135 -0.8597 +vn 0.1707 0.0283 -0.9849 +vn 0.0006 -0.2982 0.9545 +vn -0.3776 0.9260 -0.0000 +vn 0.0006 -0.2982 -0.9545 +vn -0.0311 -0.5235 0.8515 +vn -0.0550 0.9985 -0.0000 +vn -0.0311 -0.5235 -0.8515 +vn -0.5107 0.0135 -0.8596 +vn -0.1707 0.0283 -0.9849 +vn 0.9257 0.3783 0.0000 +vn 0.9997 -0.0263 -0.0000 +vn -0.5107 0.0135 0.8596 +vn -0.1707 0.0283 0.9849 +vn -0.0006 -0.2982 -0.9545 +vn 0.3776 0.9260 0.0000 +vn -0.0006 -0.2982 0.9545 +vn 0.0311 -0.5235 -0.8515 +vn 0.0550 0.9985 0.0000 +vn 0.0311 -0.5235 0.8515 +vn -1.0000 -0.0007 0.0000 +vn 1.0000 0.0007 -0.0000 +vn 1.0000 -0.0000 0.0000 +vn -0.0020 1.0000 0.0024 +vn -0.0025 1.0000 0.0035 +vn -0.0024 1.0000 -0.0026 +vn -0.0021 1.0000 -0.0025 +vn -0.0045 1.0000 -0.0045 +vn -0.0040 1.0000 0.0047 +vn -0.0017 1.0000 -0.0023 +vn -0.0023 1.0000 -0.0026 +vn -0.0020 1.0000 0.0023 +vn -0.0026 1.0000 0.0041 +vn -0.0045 1.0000 -0.0046 +vn -0.0040 1.0000 0.0046 +vn -1.0000 -0.0009 -0.0000 +vn -1.0000 -0.0000 -0.0000 +vn -1.0000 0.0000 -0.0000 +vn 1.0000 0.0009 -0.0000 +vn 0.0014 -1.0000 -0.0061 +vn 0.0038 -1.0000 0.0033 +vn -0.0089 -1.0000 -0.0000 +vn 0.0014 -1.0000 0.0061 +vn 0.0038 -1.0000 -0.0033 +vn 0.0000 -1.0000 -0.0093 +vn -0.0014 -1.0000 0.0061 +vn -0.0038 -1.0000 -0.0033 +vn 0.0089 -1.0000 -0.0000 +vn -0.0014 -1.0000 -0.0061 +vn -0.0038 -1.0000 0.0033 +vn 0.0000 -1.0000 0.0093 +vn -0.5696 0.8219 0.0003 +vn -0.5696 0.8219 0.0000 +vn 0.0373 -0.9993 -0.0000 +vn 0.0373 -0.9993 0.0000 +vn -0.0019 -0.0054 -1.0000 +vn -0.0025 -0.0063 -1.0000 +vn 0.5696 0.8219 -0.0000 +vn -0.0373 -0.9993 -0.0000 +vn 0.0025 -0.0063 -1.0000 +vn 0.0019 -0.0055 -1.0000 +vn 0.9999 -0.0109 -0.0016 +vn 0.5875 -0.8092 -0.0008 +vn -0.5875 -0.8092 0.0008 +vn -0.9999 0.0110 0.0013 +vn -0.9999 0.0111 -0.0004 +vn -0.0747 0.9972 -0.0000 +vn -0.0106 0.9999 -0.0000 +vn -0.0105 0.9999 -0.0001 +vn 0.0740 0.9973 0.0000 +vn 0.0013 -0.0121 -0.9999 +vn -0.9999 0.0102 0.0005 +vn -0.0017 -0.0120 -0.9999 +vn 0.0518 0.9987 0.0000 +vn 0.0345 0.9994 0.0000 +vn 0.0814 0.9967 0.0000 +vn -0.0105 0.9999 0.0000 +vn -0.0719 0.9974 0.0000 +vn -0.0211 0.9998 0.0000 +vn -0.0317 0.9995 0.0000 +vn 1.0000 -0.0000 -0.0001 +vn -1.0000 -0.0018 -0.0000 +vn 1.0000 0.0018 -0.0000 +vn -1.0000 -0.0018 0.0000 +vn 0.5758 0.5781 -0.5781 +vn -0.5789 0.5766 -0.5766 +vn -0.5789 0.5766 0.5766 +vn 0.5758 0.5781 0.5781 +vn 0.0002 1.0000 -0.0042 +vn 0.0002 1.0000 0.0041 +vn 0.0002 1.0000 -0.0041 +vn 0.0003 1.0000 0.0042 +vn 0.7071 0.0013 -0.7071 +vn -0.7071 -0.0013 -0.7071 +vn -0.7071 -0.0013 0.7071 +vn 0.7071 0.0013 0.7071 +vn -0.9873 -0.0009 -0.1589 +vn -0.0555 0.0085 0.9984 +vn 0.7071 -0.0064 -0.7071 +vn 0.0405 -0.0084 0.9991 +vn 0.9892 0.0009 -0.1463 +vn -0.7071 0.0062 -0.7071 +vn 0.9876 0.0010 0.1571 +vn 0.0395 -0.0084 -0.9992 +vn -0.7071 0.0062 0.7071 +vn -0.0603 0.0086 -0.9981 +vn -0.9967 -0.0002 0.0813 +vn 0.7071 -0.0064 0.7071 +vn -0.1074 0.0000 -0.9942 +vn -0.1316 0.0000 -0.9913 +vn -0.0146 0.1009 -0.9948 +vn -0.0000 0.1040 -0.9946 +vn -0.0146 -0.1009 -0.9948 +vn -0.0000 -0.1040 -0.9946 +vn -0.9952 0.0976 0.0000 +vn -1.0000 0.0016 0.0053 +vn -0.9952 -0.0832 0.0507 +vn -0.9951 -0.0819 0.0553 +vn 0.1094 0.0048 0.9940 +vn 0.0000 0.0329 0.9995 +vn 0.0147 0.0360 0.9992 +vn 0.1316 0.0054 0.9913 +vn 0.0121 -0.0293 0.9995 +vn 0.0000 -0.0271 0.9996 +vn 1.0000 0.0007 0.0022 +vn 0.9991 0.0419 -0.0000 +vn 0.9991 -0.0361 0.0220 +vn 0.9991 -0.0356 0.0240 +vn 0.1073 0.0000 -0.9942 +vn 0.0146 0.1009 -0.9948 +vn 0.1316 0.0000 -0.9913 +vn 0.0146 -0.1009 -0.9948 +vn 1.0000 0.0000 0.0000 +vn 1.0000 0.0016 0.0053 +vn 0.9952 0.0976 0.0000 +vn 0.9952 0.0976 -0.0000 +vn 0.9952 -0.0832 0.0507 +vn 0.9951 -0.0819 0.0553 +vn -0.1094 0.0048 0.9940 +vn -0.1316 0.0054 0.9913 +vn -0.0147 0.0360 0.9992 +vn -0.0121 -0.0293 0.9995 +vn -1.0000 -0.0000 0.0000 +vn -0.9991 0.0419 0.0000 +vn -1.0000 0.0007 0.0022 +vn -0.9991 -0.0361 0.0220 +vn -0.9991 -0.0356 0.0240 +vn -0.1074 -0.0000 0.9942 +vn 0.0000 0.1040 0.9946 +vn -0.0146 0.1009 0.9948 +vn -0.1316 -0.0000 0.9913 +vn -0.0146 -0.1009 0.9948 +vn 0.0000 -0.1040 0.9946 +vn -1.0000 0.0016 -0.0053 +vn -0.9952 0.0976 -0.0000 +vn -0.9952 -0.0832 -0.0507 +vn -0.9951 -0.0819 -0.0553 +vn 0.1094 0.0048 -0.9940 +vn 0.1316 0.0054 -0.9913 +vn 0.0147 0.0360 -0.9992 +vn -0.0000 0.0329 -0.9995 +vn 0.0121 -0.0293 -0.9995 +vn -0.0000 -0.0271 -0.9996 +vn 1.0000 0.0007 -0.0022 +vn 0.9991 -0.0361 -0.0220 +vn 0.9991 -0.0356 -0.0240 +vn -0.0716 -0.0483 0.9963 +vn 0.0000 -0.0248 0.9997 +vn 0.0000 -0.0657 0.9978 +vn 0.0716 -0.0483 0.9963 +vn -0.0006 -0.0691 0.9976 +vn 0.0044 -0.0740 0.9972 +vn -0.0318 -0.0585 0.9978 +vn 0.0000 -0.0550 0.9985 +vn 0.0315 -0.0586 0.9978 +vn -0.0060 -0.0747 0.9972 +vn -1.0000 -0.0000 0.0001 +vn -0.5875 -0.8092 0.0001 +vn -0.5875 -0.8092 0.0000 +vn 0.5875 -0.8092 -0.0000 +vn 0.0804 0.9968 -0.0000 +vn 0.0803 0.9968 0.0001 +vn -0.0593 0.9982 0.0001 +vn -0.0593 0.9982 -0.0000 +vn -0.0047 -0.0747 0.9972 +vn -0.0272 -0.0694 0.9972 +vn 0.0077 -0.0740 0.9972 +vn 0.0272 -0.0694 0.9972 +vn -0.1034 0.9946 -0.0000 +vn 0.0803 0.9968 -0.0000 +vn 0.0634 0.9980 -0.0000 +vn 0.0128 0.9962 -0.0863 +vn 0.0042 0.9899 -0.1419 +vn 0.5477 0.8361 -0.0330 +vn 0.4977 0.8674 0.0000 +vn -0.2683 0.1436 0.9526 +vn -0.1529 0.0000 0.9882 +vn 0.1529 0.0000 0.9882 +vn -0.5290 0.8485 -0.0127 +vn -0.6020 0.7941 -0.0839 +vn -0.0000 0.9660 -0.2586 +vn -0.4518 0.8910 0.0452 +vn 0.6066 0.7895 -0.0936 +vn 0.5599 -0.8285 0.0020 +vn 0.6521 -0.7323 0.1960 +vn -0.5694 -0.8218 0.0196 +vn -0.6507 -0.7335 0.1963 +vn -0.9990 -0.0000 -0.0453 +vn -0.9987 -0.0000 -0.0509 +vn -0.9995 -0.0000 -0.0327 +vn 0.0000 -0.9673 0.2538 +vn 0.0000 -0.9911 0.1334 +vn 0.9990 -0.0000 -0.0453 +vn 0.9995 -0.0000 -0.0327 +vn 0.9987 -0.0000 -0.0509 +vn -0.0000 0.9423 -0.3347 +vn -0.0000 0.9806 -0.1961 +vn -0.9980 -0.0000 -0.0631 +vn 0.0000 -0.9315 0.3639 +vn 0.9980 -0.0000 -0.0631 +vn -0.0000 0.8882 -0.4594 +vn 0.0000 -0.2067 -0.9784 +vn -0.0000 -0.2069 -0.9784 +vn 0.6111 0.7745 -0.1637 +vn -0.0000 0.2067 0.9784 +vn 0.0000 0.2068 0.9784 +vn 0.0000 -0.2069 -0.9784 +vn -0.0001 -0.2068 -0.9784 +vn 0.1161 0.9718 -0.2054 +vn 0.1162 0.9718 -0.2054 +vn -0.0000 0.2068 0.9784 +vn -0.0001 0.2068 0.9784 +vn -0.0000 -0.2067 -0.9784 +vn -0.6111 0.7745 -0.1637 +vn 0.0001 -0.2068 -0.9784 +vn -0.1161 0.9718 -0.2054 +vn -0.1162 0.9718 -0.2054 +vn 0.0001 0.2068 0.9784 +vn 0.6110 0.7745 -0.1637 +vn -0.0000 -0.2068 -0.9784 +vn 0.0000 -0.2068 -0.9784 +vn 0.6110 0.7798 -0.1362 +vn 0.6111 0.7798 -0.1363 +vn -0.0000 -0.1721 -0.9851 +vn 0.0000 -0.1721 -0.9851 +vn 0.1162 0.9784 -0.1709 +vn 0.1162 0.9784 -0.1710 +vn 0.0001 -0.1721 -0.9851 +vn -0.6111 0.7798 -0.1363 +vn -0.6111 0.7798 -0.1362 +vn -0.1162 0.9784 -0.1709 +vn -0.1162 0.9784 -0.1710 +vn -0.0001 -0.1721 -0.9851 +vn 0.6111 0.7858 -0.0956 +vn -0.0000 -0.1207 -0.9927 +vn 0.0000 -0.1207 -0.9927 +vn 0.1162 0.9860 -0.1199 +vn 0.1161 0.9860 -0.1199 +vn -0.0001 -0.1207 -0.9927 +vn -0.6111 0.7858 -0.0956 +vn -0.1162 0.9860 -0.1199 +vn -0.1161 0.9860 -0.1199 +vn 0.0001 -0.1207 -0.9927 +vn 0.6111 0.7858 -0.0955 +vn -0.6111 0.7858 -0.0955 +vn 0.6111 0.7905 -0.0423 +vn 0.0000 -0.0535 -0.9986 +vn 0.0000 -0.0534 -0.9986 +vn 0.1162 0.9918 -0.0531 +vn 0.1161 0.9918 -0.0531 +vn -0.6111 0.7905 -0.0423 +vn -0.0000 -0.0534 -0.9986 +vn -0.0000 -0.0535 -0.9986 +vn -0.1162 0.9918 -0.0531 +vn -0.1161 0.9918 -0.0531 +vn 0.6110 0.7908 0.0353 +vn 0.0000 -0.0337 0.9994 +vn 0.1162 0.9922 0.0442 +vn 0.1161 0.9922 0.0442 +vn -0.0000 -0.0337 0.9994 +vn -0.6110 0.7908 0.0353 +vn -0.1162 0.9922 0.0442 +vn -0.1161 0.9922 0.0442 +vn 0.6110 0.7858 -0.0956 +vn 0.0000 0.1207 0.9927 +vn -0.0000 0.1207 0.9927 +vn -0.9942 -0.0000 0.1074 +vn -0.9913 0.0000 0.1316 +vn -0.9948 0.1009 0.0146 +vn -0.9946 0.1040 0.0000 +vn -0.9948 -0.1009 0.0146 +vn -0.9946 -0.1040 0.0000 +vn 0.0000 0.0976 0.9952 +vn 0.0053 0.0016 1.0000 +vn 0.0507 -0.0832 0.9952 +vn 0.0553 -0.0819 0.9951 +vn 0.9940 0.0048 -0.1094 +vn 0.9995 0.0329 -0.0000 +vn 0.9992 0.0360 -0.0147 +vn 0.9913 0.0054 -0.1316 +vn 0.9995 -0.0293 -0.0121 +vn 0.9996 -0.0271 -0.0000 +vn 0.0022 0.0007 -1.0000 +vn -0.0000 0.0419 -0.9991 +vn 0.0220 -0.0361 -0.9991 +vn 0.0240 -0.0356 -0.9991 +vn 0.9942 -0.0000 0.1074 +vn 0.9946 0.1040 -0.0000 +vn 0.9948 0.1009 0.0146 +vn 0.9913 0.0000 0.1316 +vn 0.9948 -0.1009 0.0146 +vn 0.9946 -0.1040 -0.0000 +vn -0.0000 0.0000 1.0000 +vn -0.0053 0.0016 1.0000 +vn -0.0000 0.0976 0.9952 +vn -0.0507 -0.0832 0.9952 +vn -0.0553 -0.0819 0.9951 +vn -0.9940 0.0048 -0.1094 +vn -0.9913 0.0054 -0.1316 +vn -0.9992 0.0360 -0.0147 +vn -0.9995 0.0329 0.0000 +vn -0.9995 -0.0293 -0.0121 +vn -0.9996 -0.0271 0.0000 +vn -0.0022 0.0007 -1.0000 +vn -0.0220 -0.0361 -0.9991 +vn -0.0240 -0.0356 -0.9991 +vn -0.1073 -0.0000 0.9942 +vn -1.0000 0.0016 -0.0052 +vn 0.1074 -0.0000 0.9942 +vn 0.1316 0.0000 0.9913 +vn 0.0146 0.1009 0.9948 +vn 0.0146 -0.1009 0.9948 +vn 1.0000 0.0016 -0.0052 +vn 0.9952 -0.0832 -0.0507 +vn 0.9951 -0.0819 -0.0553 +vn -0.1094 0.0048 -0.9940 +vn -0.0147 0.0360 -0.9992 +vn -0.1316 0.0054 -0.9913 +vn -0.0121 -0.0293 -0.9995 +vn -1.0000 0.0007 -0.0022 +vn -0.9991 -0.0361 -0.0220 +vn -0.9991 -0.0356 -0.0240 +vn 0.1316 -0.0000 0.9913 +vn 1.0000 0.0016 -0.0053 +vn 0.1073 -0.0000 0.9942 +vn -0.1316 0.0000 0.9913 +vn -0.1226 0.3261 -0.9374 +vn -0.3988 0.4312 -0.8094 +vn -0.3929 0.4468 -0.8037 +vn -0.1739 0.3999 -0.8999 +vn -0.3707 -0.8424 -0.3910 +vn 0.3330 -0.7033 -0.6280 +vn -0.8537 0.1474 0.4995 +vn -0.8348 0.1876 0.5176 +vn -0.9273 -0.1212 0.3541 +vn 0.3707 0.8424 0.3910 +vn 0.5816 0.7751 0.2469 +vn 0.8559 -0.1423 -0.4972 +vn 0.8726 -0.1017 -0.4778 +vn 0.9309 0.1676 -0.3245 +vn -0.6613 0.4174 -0.6233 +vn -0.5875 0.4700 -0.6588 +vn -0.8628 -0.5007 0.0693 +vn 0.1339 0.8509 0.5079 +vn -0.3741 0.4937 -0.7851 +vn -0.2212 0.4135 -0.8832 +vn -0.6644 0.4379 0.6056 +vn 0.6994 -0.3968 -0.5944 +vn -0.5481 0.4689 -0.6926 +vn -0.9988 0.0156 -0.0466 +vn -0.9862 0.1651 -0.0150 +vn -0.9953 0.0915 -0.0307 +vn -0.9988 -0.0000 -0.0498 +vn 0.0000 0.9258 0.3781 +vn 0.9976 0.0206 -0.0656 +vn 0.9962 0.0872 -0.0079 +vn 0.9969 0.0767 -0.0171 +vn 0.9965 -0.0000 -0.0833 +vn -0.0000 -0.9018 -0.4321 +vn 1.0000 0.0007 0.0076 +vn 0.9998 -0.0186 0.0077 +vn 0.9998 0.0198 0.0076 +vn 0.0331 -0.0088 -0.9994 +vn 0.0331 -0.0087 -0.9994 +vn 0.0331 0.0398 -0.9987 +vn 0.0330 -0.0572 -0.9978 +vn -1.0000 -0.0027 -0.0076 +vn -0.9973 0.0732 -0.0076 +vn -0.9969 -0.0778 -0.0076 +vn -0.0331 -0.0082 0.9994 +vn -0.0331 0.0223 0.9992 +vn -0.0331 -0.0386 0.9987 +vn 0.9996 0.0261 0.0077 +vn 0.9994 0.0330 0.0077 +vn 0.9998 0.0191 0.0076 +vn 0.0331 -0.0008 -0.9995 +vn 0.0331 -0.0040 -0.9994 +vn 0.0329 -0.1027 -0.9942 +vn 0.0329 0.0981 -0.9946 +vn -0.9997 -0.0242 -0.0077 +vn -0.9997 -0.0244 -0.0077 +vn -0.9997 0.0217 -0.0076 +vn -0.9975 -0.0703 -0.0076 +vn -0.0331 0.0059 0.9994 +vn -0.0331 0.0014 0.9995 +vn -0.0327 0.1451 0.9889 +vn -0.0328 -0.1381 0.9899 +vn 0.0356 0.9994 0.0003 +vn 0.0318 0.9995 0.0002 +vn -0.0845 0.9964 -0.0006 +vn 0.1512 0.9885 0.0012 +vn 0.0329 0.0000 -0.9995 +vn 0.0332 -0.0000 -0.9994 +vn 0.1565 -0.0044 -0.9877 +vn -0.0908 0.0044 -0.9959 +vn -0.0329 -0.9995 -0.0003 +vn -0.0347 -0.9994 -0.0003 +vn 0.0210 -0.9998 0.0002 +vn -0.0884 -0.9961 -0.0007 +vn -0.0331 -0.0000 0.9995 +vn -0.0327 -0.0000 0.9995 +vn -0.1970 0.0059 0.9804 +vn 0.1321 -0.0059 0.9912 +vn 0.0352 0.9994 0.0003 +vn 0.0314 0.9995 0.0002 +vn -0.0912 0.9958 -0.0007 +vn 0.1577 0.9875 0.0012 +vn 0.0321 0.0000 -0.9995 +vn 0.0316 0.0001 -0.9995 +vn -0.1315 0.0059 -0.9913 +vn 0.1944 -0.0058 -0.9809 +vn -0.0326 -0.9995 -0.0003 +vn -0.0345 -0.9994 -0.0003 +vn 0.0277 -0.9996 0.0002 +vn -0.0950 -0.9955 -0.0007 +vn -0.0321 -0.0000 0.9995 +vn -0.0325 -0.0000 0.9995 +vn 0.0899 -0.0044 0.9959 +vn -0.1540 0.0043 0.9881 +vn 1.0000 0.0016 0.0077 +vn 1.0000 0.0017 0.0077 +vn 0.9996 0.0274 0.0077 +vn 0.9997 -0.0241 0.0077 +vn 0.0331 -0.0037 -0.9994 +vn 0.0331 -0.0604 -0.9976 +vn 0.0331 0.0531 -0.9980 +vn -1.0000 0.0017 -0.0077 +vn -1.0000 0.0016 -0.0077 +vn -0.9996 0.0274 -0.0076 +vn -0.9997 -0.0241 -0.0076 +vn -0.0331 0.0063 0.9994 +vn -0.0329 0.1034 0.9941 +vn -0.0330 -0.0911 0.9953 +vn -0.0330 -0.0910 0.9953 +vn 1.0000 -0.0034 0.0076 +vn 1.0000 -0.0030 0.0076 +vn 0.9986 0.0519 0.0077 +vn 0.9983 -0.0582 0.0077 +vn 0.0331 -0.0079 -0.9994 +vn 0.0331 -0.0081 -0.9994 +vn 0.0328 0.1300 -0.9910 +vn 0.0327 -0.1455 -0.9888 +vn -1.0000 -0.0001 -0.0077 +vn -1.0000 -0.0002 -0.0077 +vn -1.0000 0.0028 -0.0076 +vn -1.0000 -0.0031 -0.0076 +vn -0.0331 0.0055 0.9994 +vn -0.0331 0.0053 0.9994 +vn -0.0329 -0.0873 0.9956 +vn -0.0329 0.0979 0.9947 +vn 1.0000 -0.0012 0.0077 +vn 0.9981 0.0614 0.0076 +vn 0.9981 -0.0614 0.0076 +vn 0.0330 -0.0329 -0.9989 +vn 0.0331 0.0217 -0.9992 +vn 0.0329 -0.0874 -0.9956 +vn -1.0000 0.0001 -0.0076 +vn -0.9999 -0.0068 -0.0076 +vn -0.9999 0.0068 -0.0076 +vn -0.0330 -0.0329 0.9989 +vn -0.0331 0.0217 0.9992 +vn -0.0329 -0.0874 0.9956 +vn -0.0330 -0.0874 0.9956 +vn 1.0000 0.0007 0.0077 +vn -0.0326 -0.9995 -0.0002 +vn -0.0346 -0.9994 -0.0003 +vn 1.0000 0.0016 0.0076 +vn 1.0000 0.0017 0.0076 +vn 1.0000 -0.0034 0.0077 +vn 1.0000 -0.0030 0.0077 +vn -1.0000 0.0001 -0.0077 +vn 0.9998 -0.0187 0.0077 +vn 0.9981 -0.0614 0.0077 +vn 0.9983 -0.0581 0.0077 +vn 0.0330 -0.0079 -0.9994 +vn 0.0330 -0.0081 -0.9994 +vn 0.9981 0.0615 0.0076 +vn 0.9981 -0.0615 0.0076 +vn -0.0331 -0.0329 0.9989 +vn 0.0353 0.9994 0.0003 +vn -0.9996 0.0274 -0.0077 +vn -0.9997 -0.0241 -0.0077 +vn -0.9999 -0.0068 -0.0077 +vn -1.0000 -0.0027 -0.0077 +vn -0.9997 0.0217 -0.0077 +vn -0.9975 -0.0703 -0.0077 +vn -0.9996 0.0274 -0.0075 +vn -0.9997 -0.0241 -0.0075 +vn -1.0000 -0.0001 -0.0078 +vn -1.0000 -0.0002 -0.0078 +vn -1.0000 -0.0032 -0.0076 +vn 0.9981 0.0615 0.0077 +vn -0.9999 -0.0069 -0.0076 +vn -0.9999 0.0068 -0.0077 +vn 0.9996 0.0260 0.0076 +vn 0.9996 0.0261 0.0076 +vn -0.9997 0.0217 -0.0075 +vn -1.0000 0.0028 -0.0075 +vn -1.0000 -0.0031 -0.0075 +vn -0.0076 0.0007 1.0000 +vn -0.0077 -0.0186 0.9998 +vn -0.0076 0.0198 0.9998 +vn 0.9994 -0.0088 0.0331 +vn 0.9994 -0.0087 0.0331 +vn 0.9987 0.0398 0.0331 +vn 0.9987 0.0398 0.0330 +vn 0.9978 -0.0572 0.0331 +vn 0.0076 -0.0027 -1.0000 +vn 0.0076 0.0732 -0.9973 +vn 0.0076 -0.0778 -0.9969 +vn -0.9994 -0.0082 -0.0331 +vn -0.9992 0.0223 -0.0331 +vn -0.9987 -0.0386 -0.0331 +vn -0.0077 0.0261 0.9996 +vn -0.0077 0.0330 0.9994 +vn -0.0076 0.0191 0.9998 +vn 0.9995 -0.0008 0.0331 +vn 0.9994 -0.0040 0.0331 +vn 0.9942 -0.1027 0.0329 +vn 0.9942 -0.1027 0.0330 +vn 0.9946 0.0981 0.0330 +vn 0.0077 -0.0242 -0.9997 +vn 0.0077 -0.0244 -0.9997 +vn 0.0076 0.0217 -0.9997 +vn 0.0076 -0.0703 -0.9975 +vn -0.9994 0.0059 -0.0331 +vn -0.9994 0.0014 -0.0331 +vn -0.9889 0.1451 -0.0327 +vn -0.9899 -0.1381 -0.0328 +vn -0.0003 0.9994 0.0356 +vn -0.0002 0.9995 0.0318 +vn 0.0006 0.9964 -0.0845 +vn -0.0012 0.9885 0.1512 +vn 0.9995 0.0000 0.0329 +vn 0.9994 -0.0000 0.0332 +vn 0.9877 -0.0044 0.1565 +vn 0.9959 0.0044 -0.0908 +vn 0.0003 -0.9995 -0.0329 +vn 0.0003 -0.9994 -0.0347 +vn -0.0002 -0.9998 0.0210 +vn 0.0007 -0.9961 -0.0884 +vn -0.9995 -0.0001 -0.0331 +vn -0.9995 -0.0001 -0.0327 +vn -0.9804 0.0059 -0.1970 +vn -0.9912 -0.0059 0.1321 +vn -0.0003 0.9994 0.0352 +vn -0.0002 0.9995 0.0314 +vn 0.0007 0.9958 -0.0912 +vn -0.0012 0.9875 0.1577 +vn 0.9995 0.0001 0.0321 +vn 0.9995 0.0001 0.0316 +vn 0.9913 0.0059 -0.1315 +vn 0.9809 -0.0058 0.1944 +vn 0.0003 -0.9995 -0.0326 +vn 0.0003 -0.9994 -0.0345 +vn -0.0002 -0.9996 0.0277 +vn 0.0007 -0.9955 -0.0950 +vn -0.9995 -0.0000 -0.0321 +vn -0.9995 -0.0000 -0.0325 +vn -0.9959 -0.0044 0.0899 +vn -0.9881 0.0043 -0.1540 +vn -0.0076 0.0016 1.0000 +vn -0.0076 0.0017 1.0000 +vn -0.0077 0.0274 0.9996 +vn -0.0077 -0.0241 0.9997 +vn 0.9994 -0.0037 0.0331 +vn 0.9976 -0.0604 0.0330 +vn 0.9980 0.0531 0.0330 +vn 0.0077 0.0017 -1.0000 +vn 0.0077 0.0016 -1.0000 +vn 0.0076 0.0274 -0.9996 +vn 0.0076 -0.0241 -0.9997 +vn -0.9994 0.0063 -0.0330 +vn -0.9941 0.1034 -0.0329 +vn -0.9953 -0.0910 -0.0330 +vn -0.0076 -0.0034 1.0000 +vn -0.0076 -0.0030 1.0000 +vn -0.0077 0.0519 0.9986 +vn -0.0077 -0.0582 0.9983 +vn 0.9994 -0.0079 0.0331 +vn 0.9994 -0.0081 0.0331 +vn 0.9910 0.1300 0.0328 +vn 0.9888 -0.1455 0.0328 +vn 0.0077 -0.0002 -1.0000 +vn 0.0076 0.0028 -1.0000 +vn 0.0076 -0.0031 -1.0000 +vn -0.9994 0.0055 -0.0331 +vn -0.9994 0.0053 -0.0331 +vn -0.9956 -0.0873 -0.0330 +vn -0.9947 0.0979 -0.0330 +vn -0.0077 -0.0012 1.0000 +vn -0.0076 0.0614 0.9981 +vn -0.0076 -0.0614 0.9981 +vn 0.9989 -0.0329 0.0331 +vn 0.9992 0.0217 0.0331 +vn 0.9956 -0.0874 0.0330 +vn 0.9956 -0.0874 0.0329 +vn 0.0076 0.0001 -1.0000 +vn 0.0076 -0.0068 -0.9999 +vn 0.0076 0.0068 -0.9999 +vn -0.9989 -0.0329 -0.0331 +vn -0.9992 0.0217 -0.0331 +vn -0.9956 -0.0874 -0.0330 +vn -0.0076 -0.0582 0.9983 +vn -0.0076 -0.0012 1.0000 +vn -0.0076 0.0615 0.9981 +vn -0.0076 0.0261 0.9996 +vn -0.0077 0.0016 1.0000 +vn -0.0077 0.0017 1.0000 +vn -0.0077 -0.0034 1.0000 +vn -0.0077 -0.0030 1.0000 +vn 0.0002 -0.9995 -0.0326 +vn 0.0077 0.0001 -1.0000 +vn 0.0077 -0.0001 -1.0000 +vn -1.0000 0.0007 -0.0077 +vn -1.0000 0.0007 -0.0076 +vn -0.9998 -0.0187 -0.0077 +vn -0.9998 0.0198 -0.0076 +vn -0.0331 -0.0088 0.9994 +vn -0.0331 -0.0087 0.9994 +vn -0.0331 0.0398 0.9987 +vn -0.0331 -0.0572 0.9978 +vn 1.0000 -0.0027 0.0076 +vn 0.9973 0.0732 0.0076 +vn 0.9969 -0.0778 0.0076 +vn 0.0331 -0.0082 -0.9994 +vn 0.0331 0.0223 -0.9992 +vn 0.0331 -0.0386 -0.9987 +vn -0.9996 0.0261 -0.0077 +vn -0.9994 0.0330 -0.0077 +vn -0.9998 0.0191 -0.0076 +vn -0.0331 -0.0008 0.9995 +vn -0.0331 -0.0040 0.9994 +vn -0.0329 -0.1027 0.9942 +vn -0.0329 0.0981 0.9946 +vn 0.9997 -0.0242 0.0077 +vn 0.9997 -0.0244 0.0077 +vn 0.9997 0.0217 0.0077 +vn 0.9975 -0.0703 0.0077 +vn 0.9975 -0.0703 0.0076 +vn 0.0331 0.0059 -0.9994 +vn 0.0331 0.0014 -0.9995 +vn 0.0327 0.1451 -0.9889 +vn 0.0328 -0.1381 -0.9899 +vn -0.0356 0.9994 -0.0003 +vn -0.0318 0.9995 -0.0002 +vn 0.0845 0.9964 0.0006 +vn -0.1512 0.9885 -0.0012 +vn -0.0329 -0.0000 0.9995 +vn -0.0332 -0.0000 0.9994 +vn -0.1565 -0.0044 0.9877 +vn 0.0908 0.0044 0.9959 +vn 0.0329 -0.9995 0.0003 +vn 0.0347 -0.9994 0.0003 +vn -0.0210 -0.9998 -0.0002 +vn 0.0884 -0.9961 0.0007 +vn 0.0331 -0.0000 -0.9995 +vn 0.0327 -0.0000 -0.9995 +vn 0.1970 0.0059 -0.9804 +vn -0.1321 -0.0059 -0.9912 +vn -0.0352 0.9994 -0.0003 +vn -0.0314 0.9995 -0.0002 +vn 0.0912 0.9958 0.0007 +vn -0.1577 0.9875 -0.0012 +vn -0.0321 0.0000 0.9995 +vn -0.0316 0.0000 0.9995 +vn 0.1315 0.0059 0.9913 +vn -0.1944 -0.0058 0.9809 +vn 0.0326 -0.9995 0.0002 +vn 0.0345 -0.9994 0.0003 +vn -0.0277 -0.9996 -0.0002 +vn 0.0950 -0.9955 0.0007 +vn 0.0321 -0.0000 -0.9995 +vn 0.0325 -0.0000 -0.9995 +vn -0.0899 -0.0044 -0.9959 +vn 0.1540 0.0043 -0.9881 +vn -0.0331 -0.0037 0.9994 +vn -0.0330 -0.0604 0.9976 +vn -0.0331 0.0531 0.9980 +vn 0.0331 0.0063 -0.9994 +vn 0.0329 0.1034 -0.9941 +vn 0.0330 -0.0911 -0.9953 +vn 0.0330 -0.0910 -0.9953 +vn -1.0000 -0.0034 -0.0076 +vn -1.0000 -0.0030 -0.0076 +vn -0.9986 0.0519 -0.0077 +vn -0.9983 -0.0581 -0.0077 +vn -0.0331 -0.0079 0.9994 +vn -0.0331 -0.0081 0.9994 +vn -0.0328 0.1300 0.9910 +vn -0.0327 -0.1455 0.9888 +vn 1.0000 -0.0002 0.0077 +vn 1.0000 0.0028 0.0076 +vn 1.0000 -0.0031 0.0076 +vn 0.0331 0.0055 -0.9994 +vn 0.0331 0.0053 -0.9994 +vn 0.0329 -0.0873 -0.9956 +vn 0.0329 0.0979 -0.9947 +vn -1.0000 -0.0012 -0.0077 +vn -0.9981 0.0615 -0.0076 +vn -0.9981 -0.0615 -0.0076 +vn 1.0000 0.0001 0.0077 +vn 0.9999 -0.0068 0.0076 +vn 0.9999 0.0068 0.0076 +vn 0.0331 -0.0329 -0.9989 +vn 0.0330 -0.0874 -0.9956 +vn -0.0330 -0.0572 0.9978 +vn -0.9998 0.0191 -0.0075 +vn 0.9997 0.0217 0.0076 +vn -0.0329 0.0000 0.9995 +vn -0.0316 0.0001 0.9995 +vn 1.0000 0.0018 0.0077 +vn 0.9996 0.0274 0.0076 +vn 0.9997 -0.0241 0.0076 +vn -1.0000 -0.0034 -0.0077 +vn -1.0000 -0.0030 -0.0077 +vn -0.9983 -0.0582 -0.0077 +vn 1.0000 -0.0001 0.0077 +vn 1.0000 0.0028 0.0075 +vn 1.0000 -0.0031 0.0075 +vn -0.9981 0.0614 -0.0077 +vn -0.9981 -0.0614 -0.0076 +vn 0.9999 -0.0068 0.0077 +vn -0.9998 -0.0186 -0.0077 +vn 1.0000 -0.0027 0.0077 +vn -0.0353 0.9994 -0.0003 +vn 0.0346 -0.9994 0.0003 +vn -0.9981 -0.0614 -0.0077 +vn 0.9999 -0.0069 0.0076 +vn 0.9999 0.0068 0.0077 +vn -0.9998 -0.0186 -0.0076 +vn -0.9986 0.0519 -0.0076 +vn -0.9983 -0.0582 -0.0076 +vn 1.0000 0.0001 0.0076 +vn 0.0331 -0.0572 -0.9978 +vn 0.0329 -0.0000 -0.9995 +vn 0.9981 0.0614 0.0077 +vn 0.9998 0.0191 0.0075 +vn -0.0845 0.9964 -0.0007 +vn -0.9996 0.0273 -0.0077 +vn 0.0076 0.0007 -1.0000 +vn 0.0077 -0.0186 -0.9998 +vn 0.0076 0.0198 -0.9998 +vn -0.9994 -0.0088 -0.0331 +vn -0.9994 -0.0087 -0.0331 +vn -0.9987 0.0398 -0.0331 +vn -0.9978 -0.0572 -0.0330 +vn -0.0076 -0.0027 1.0000 +vn -0.0076 0.0732 0.9973 +vn -0.0076 -0.0778 0.9969 +vn 0.9994 -0.0082 0.0331 +vn 0.9992 0.0223 0.0331 +vn 0.9987 -0.0386 0.0331 +vn 0.9987 -0.0387 0.0331 +vn 0.0077 0.0261 -0.9996 +vn 0.0076 0.0261 -0.9996 +vn 0.0077 0.0330 -0.9994 +vn 0.0076 0.0191 -0.9998 +vn -0.9995 -0.0008 -0.0331 +vn -0.9994 -0.0040 -0.0331 +vn -0.9942 -0.1027 -0.0329 +vn -0.9946 0.0981 -0.0329 +vn -0.0077 -0.0242 0.9997 +vn -0.0077 -0.0244 0.9997 +vn -0.0076 0.0217 0.9997 +vn -0.0076 -0.0703 0.9975 +vn 0.9994 0.0059 0.0331 +vn 0.9995 0.0014 0.0331 +vn 0.9889 0.1451 0.0327 +vn 0.9899 -0.1381 0.0328 +vn 0.0003 0.9994 -0.0356 +vn 0.0002 0.9995 -0.0318 +vn -0.0006 0.9964 0.0845 +vn 0.0012 0.9885 -0.1512 +vn -0.9995 0.0000 -0.0329 +vn -0.9994 -0.0000 -0.0332 +vn -0.9877 -0.0044 -0.1565 +vn -0.9959 0.0044 0.0908 +vn -0.9959 0.0043 0.0908 +vn -0.0003 -0.9995 0.0329 +vn -0.0003 -0.9994 0.0347 +vn 0.0002 -0.9998 -0.0210 +vn -0.0007 -0.9961 0.0884 +vn 0.9995 -0.0001 0.0331 +vn 0.9995 -0.0001 0.0327 +vn 0.9804 0.0059 0.1970 +vn 0.9912 -0.0059 -0.1321 +vn 0.0003 0.9994 -0.0352 +vn 0.0002 0.9995 -0.0314 +vn -0.0007 0.9958 0.0912 +vn 0.0012 0.9875 -0.1577 +vn -0.9995 0.0001 -0.0321 +vn -0.9995 0.0001 -0.0316 +vn -0.9913 0.0059 0.1315 +vn -0.9809 -0.0058 -0.1944 +vn -0.9809 -0.0059 -0.1944 +vn -0.0002 -0.9995 0.0326 +vn -0.0003 -0.9994 0.0345 +vn 0.0002 -0.9996 -0.0277 +vn -0.0007 -0.9955 0.0950 +vn 0.9995 -0.0000 0.0321 +vn 0.9995 -0.0000 0.0325 +vn 0.9959 -0.0044 -0.0899 +vn 0.9881 0.0043 0.1540 +vn 0.0077 0.0274 -0.9996 +vn 0.0077 -0.0241 -0.9997 +vn -0.9994 -0.0037 -0.0331 +vn -0.9976 -0.0604 -0.0331 +vn -0.9980 0.0531 -0.0331 +vn -0.0076 0.0274 0.9996 +vn -0.0076 -0.0241 0.9997 +vn 0.9994 0.0063 0.0330 +vn 0.9941 0.1034 0.0329 +vn 0.9953 -0.0911 0.0329 +vn 0.9953 -0.0910 0.0329 +vn 0.0076 -0.0034 -1.0000 +vn 0.0076 -0.0030 -1.0000 +vn 0.0077 0.0519 -0.9986 +vn 0.0077 -0.0582 -0.9983 +vn -0.9994 -0.0079 -0.0330 +vn -0.9994 -0.0081 -0.0330 +vn -0.9910 0.1300 -0.0328 +vn -0.9888 -0.1455 -0.0327 +vn -0.0077 -0.0001 1.0000 +vn -0.0077 -0.0002 1.0000 +vn -0.0076 0.0028 1.0000 +vn -0.0076 -0.0031 1.0000 +vn 0.9994 0.0055 0.0331 +vn 0.9994 0.0053 0.0331 +vn 0.9956 -0.0873 0.0330 +vn 0.9947 0.0979 0.0330 +vn 0.0077 -0.0012 -1.0000 +vn 0.0076 0.0614 -0.9981 +vn 0.0076 -0.0614 -0.9981 +vn -0.9956 -0.0874 -0.0329 +vn -0.0076 0.0001 1.0000 +vn -0.0076 -0.0068 0.9999 +vn -0.0076 0.0068 0.9999 +vn 0.0077 -0.0034 -1.0000 +vn 0.0077 -0.0030 -1.0000 +vn 0.0330 -0.0604 -0.9976 +vn 1.0000 -0.0012 0.0076 +vn 0.9983 -0.0582 0.0076 +vn -0.9987 -0.0387 -0.0331 +vn 0.9994 -0.0039 0.0331 +vn 0.9946 0.0981 0.0329 +vn -0.9995 0.0014 -0.0331 +vn 0.9995 -0.0000 0.0329 +vn -0.9995 -0.0000 -0.0331 +vn 0.9995 0.0000 0.0321 +vn -0.9881 0.0044 -0.1540 +vn 0.9980 0.0531 0.0331 +vn -0.9994 0.0063 -0.0331 +vn -0.9953 -0.0911 -0.0330 +vn 0.9888 -0.1455 0.0327 +vn -0.9956 -0.0873 -0.0329 +vn -0.9947 0.0979 -0.0329 +vn 0.9989 -0.0329 0.0330 +vn -0.9989 -0.0329 -0.0330 +vn 0.9978 -0.0572 0.0330 +vn -0.9889 0.1451 -0.0328 +vn 0.9976 -0.0604 0.0331 +vn -0.9994 0.0055 -0.0330 +vn -1.0000 0.0016 -0.0076 +vn -1.0000 0.0017 -0.0076 +vn -0.0331 -0.0604 0.9976 +vn 0.0329 -0.0911 -0.9953 +vn -0.9981 0.0614 -0.0076 +vn -0.3368 -0.1736 -0.9254 +vn 0.9397 0.0000 -0.3420 +vn 0.7253 0.5789 -0.3726 +vn 0.7253 0.5788 -0.3726 +vn 0.2339 0.9366 -0.2609 +vn -0.3469 0.9366 -0.0495 +vn -0.7951 0.5789 0.1808 +vn -0.9397 -0.0000 0.3420 +vn -0.7253 -0.5789 0.3726 +vn -0.2339 -0.9366 0.2609 +vn 0.3469 -0.9366 0.0495 +vn 0.7951 -0.5788 -0.1808 +vn 0.7951 -0.5789 -0.1808 +vn 0.3368 0.1736 0.9254 +vn 0.3368 0.1737 0.9254 +vn -0.3368 -0.1737 -0.9254 +vn 0.1910 0.9504 -0.2454 +vn 0.1911 0.9504 -0.2454 +vn 0.3674 0.1625 0.9158 +vn 0.3675 0.1624 0.9157 +vn -0.8968 0.2679 0.3520 +vn -0.3673 -0.1625 -0.9158 +vn 0.8968 -0.2679 -0.3520 +vn 0.8969 -0.2679 -0.3520 +vn -0.3041 0.9504 -0.0652 +vn 0.3072 0.1624 0.9377 +vn 0.3072 0.1625 0.9377 +vn 0.9133 0.2679 -0.3068 +vn -0.3073 -0.1625 -0.9377 +vn -0.9133 -0.2679 0.3068 +vn -0.9133 -0.2679 0.3069 +vn 0.2891 -0.3443 0.8933 +vn 0.2891 -0.3443 0.8932 +vn 0.9601 -0.0226 -0.2787 +vn -0.2891 0.3443 -0.8933 +vn -0.2892 0.3443 -0.8932 +vn -0.9601 0.0226 0.2787 +vn -0.7544 -0.1736 -0.6330 +vn 0.6428 0.0000 -0.7660 +vn 0.4418 0.5789 -0.6854 +vn 0.0721 0.9366 -0.3429 +vn -0.3252 0.9366 0.1306 +vn -0.5982 0.5789 0.5541 +vn -0.6428 -0.0000 0.7660 +vn -0.4418 -0.5789 0.6853 +vn -0.0721 -0.9366 0.3429 +vn 0.3252 -0.9366 -0.1306 +vn 0.5982 -0.5789 -0.5541 +vn 0.7544 0.1736 0.6330 +vn 0.7544 0.1737 0.6330 +vn -0.7544 -0.1737 -0.6330 +vn 0.0427 0.9504 -0.3081 +vn 0.7761 0.1625 0.6094 +vn 0.7761 0.1624 0.6094 +vn -0.6007 0.2679 0.7533 +vn -0.7760 -0.1625 -0.6094 +vn 0.6007 -0.2679 -0.7533 +vn 0.6006 -0.2679 -0.7533 +vn -0.2960 0.9504 0.0956 +vn 0.7349 0.1625 0.6584 +vn 0.6375 0.2679 -0.7224 +vn -0.7349 -0.1625 -0.6584 +vn -0.7350 -0.1625 -0.6584 +vn -0.6375 -0.2679 0.7224 +vn -0.6375 -0.2679 0.7223 +vn 0.6970 -0.3443 0.6291 +vn 0.6921 -0.0226 -0.7214 +vn -0.6970 0.3443 -0.6291 +vn -0.6970 0.3443 -0.6290 +vn -0.6921 0.0226 0.7214 +vn -0.8529 -0.1736 -0.4924 +vn 0.5000 0.0000 -0.8660 +vn 0.3161 0.5789 -0.7517 +vn 0.3161 0.5788 -0.7517 +vn 0.0115 0.9366 -0.3502 +vn -0.2975 0.9366 0.1850 +vn -0.2976 0.9366 0.1850 +vn -0.4929 0.5789 0.6496 +vn -0.4929 0.5788 0.6496 +vn -0.5000 -0.0000 0.8660 +vn -0.3161 -0.5789 0.7517 +vn -0.0115 -0.9366 0.3502 +vn 0.2975 -0.9366 -0.1850 +vn 0.4929 -0.5789 -0.6496 +vn 0.8529 0.1736 0.4924 +vn 0.8529 0.1737 0.4924 +vn -0.8529 -0.1737 -0.4924 +vn -0.0114 0.9504 -0.3108 +vn 0.8701 0.1625 0.4654 +vn 0.8701 0.1624 0.4653 +vn -0.4607 0.2679 0.8461 +vn -0.4608 0.2679 0.8461 +vn -0.8700 -0.1625 -0.4654 +vn -0.8701 -0.1625 -0.4654 +vn 0.4608 -0.2679 -0.8461 +vn 0.4607 -0.2679 -0.8461 +vn -0.2749 0.9504 0.1455 +vn 0.8381 0.1625 0.5208 +vn 0.5024 0.2679 -0.8221 +vn -0.8381 -0.1625 -0.5208 +vn -0.8381 -0.1625 -0.5207 +vn -0.5024 -0.2679 0.8221 +vn 0.7956 -0.3443 0.4985 +vn 0.7956 -0.3443 0.4984 +vn 0.5563 -0.0226 -0.8306 +vn 0.5564 -0.0226 -0.8306 +vn -0.7956 0.3443 -0.4985 +vn -0.7957 0.3443 -0.4984 +vn -0.5563 0.0226 0.8306 +vn -0.0858 -0.1737 0.9811 +vn -0.0858 -0.1736 0.9811 +vn -0.9962 -0.0000 -0.0872 +vn -0.8148 0.5789 0.0312 +vn -0.3222 0.9366 0.1376 +vn 0.2934 0.9366 0.1915 +vn 0.2935 0.9366 0.1915 +vn 0.7970 0.5789 0.1722 +vn 0.7970 0.5788 0.1722 +vn 0.9962 0.0000 0.0872 +vn 0.8148 -0.5789 -0.0312 +vn 0.3222 -0.9366 -0.1376 +vn -0.2934 -0.9366 -0.1914 +vn -0.2935 -0.9366 -0.1914 +vn -0.7970 -0.5789 -0.1722 +vn 0.0858 0.1736 -0.9811 +vn 0.0858 0.1737 -0.9811 +vn -0.2769 0.9504 0.1417 +vn 0.0541 0.1625 -0.9852 +vn 0.0540 0.1624 -0.9852 +vn 0.9616 0.2679 0.0600 +vn -0.0541 -0.1625 0.9852 +vn -0.9616 -0.2679 -0.0600 +vn 0.2481 0.9504 0.1876 +vn 0.1178 0.1625 -0.9797 +vn -0.9574 0.2679 -0.1079 +vn -0.1178 -0.1625 0.9797 +vn 0.9574 -0.2679 0.1079 +vn 0.1155 -0.3443 -0.9317 +vn -0.9879 -0.0226 -0.1532 +vn -0.1155 0.3443 0.9317 +vn -0.1154 0.3443 0.9318 +vn 0.9879 0.0226 0.1532 +vn 0.9962 -0.0000 0.0872 +vn -0.2934 -0.9366 -0.1915 +vn -0.2935 -0.9366 -0.1915 +vn -0.9962 0.0000 -0.0872 +vn -0.8148 0.5788 0.0312 +vn 0.9616 0.2679 0.0599 +vn -0.7291 -0.4300 -0.5325 +vn -0.8872 -0.4300 0.1675 +vn -0.9341 -0.2974 0.1975 +vn -0.7585 -0.2974 -0.5798 +vn -0.0395 -0.4300 -0.9020 +vn -0.0626 -0.2974 -0.9527 +vn 0.6308 -0.4300 -0.6459 +vn 0.6819 -0.2974 -0.6683 +vn 0.8984 -0.4300 0.0892 +vn 0.9519 -0.2974 0.0737 +vn 0.5495 -0.4299 0.7164 +vn 0.5645 -0.2974 0.7700 +vn -0.0714 -0.4346 0.8978 +vn -0.0755 -0.3029 0.9500 +vn -0.5454 -0.4346 0.7167 +vn -0.5772 -0.3029 0.7584 +vn -0.9775 -0.0091 0.2107 +vn -0.8865 0.4225 0.1889 +vn -0.7192 0.4225 -0.5516 +vn -0.7921 -0.0091 -0.6103 +vn -0.0608 0.4225 -0.9043 +vn -0.0694 -0.0091 -0.9975 +vn 0.6483 0.4225 -0.6334 +vn 0.7169 -0.0091 -0.6972 +vn 0.9038 0.4225 0.0685 +vn 0.9973 -0.0091 0.0733 +vn 0.5347 0.4225 0.7318 +vn 0.5880 -0.0091 0.8088 +vn -0.0714 0.4338 0.8982 +vn -0.0792 -0.0093 0.9968 +vn -0.5457 0.4338 0.7170 +vn -0.6056 -0.0093 0.7957 +vn -0.7892 0.5943 0.1549 +vn -0.6460 0.5943 -0.4790 +vn -0.0410 0.5943 -0.8032 +vn 0.5661 0.5943 -0.5712 +vn 0.8008 0.5943 0.0737 +vn 0.4848 0.5943 0.6416 +vn -0.0639 0.5919 0.8035 +vn -0.4882 0.5919 0.6414 +vn -0.8879 0.4284 0.1677 +vn -0.7296 0.4284 -0.5330 +vn -0.0396 0.4284 -0.9027 +vn 0.6314 0.4284 -0.6464 +vn 0.8992 0.4284 0.0892 +vn 0.5499 0.4284 0.7170 +vn -0.0714 0.4330 0.8985 +vn -0.5459 0.4330 0.7173 +vn -0.9754 -0.0000 -0.2203 +vn -0.4723 -0.0000 -0.8815 +vn 0.3569 -0.0000 -0.9341 +vn 0.9397 -0.0000 -0.3421 +vn 0.8738 0.0000 0.4862 +vn 0.2048 0.0000 0.9788 +vn -0.3569 0.0000 0.9341 +vn -0.8053 0.0000 0.5929 +vn -0.8047 -0.5652 -0.1817 +vn -0.3721 -0.6157 -0.6946 +vn 0.2944 -0.5652 -0.7706 +vn 0.7404 -0.6157 -0.2695 +vn 0.7209 -0.5652 0.4011 +vn 0.1614 -0.6157 0.7713 +vn -0.2812 -0.6157 0.7361 +vn -0.6345 -0.6157 0.4672 +vn -0.6345 -0.6157 0.4671 +vn -0.4722 -0.0000 -0.8815 +vn 0.3569 -0.0000 -0.9342 +vn 0.9397 -0.0000 -0.3420 +vn 0.8739 0.0000 0.4862 +vn 0.8739 -0.0000 0.4862 +vn 0.2048 -0.0000 0.9788 +vn -0.3569 0.0000 0.9342 +vn -0.7982 0.5747 -0.1803 +vn -0.7982 0.5748 -0.1803 +vn -0.3687 0.6252 -0.6879 +vn -0.3686 0.6252 -0.6880 +vn 0.2920 0.5747 -0.7644 +vn 0.2920 0.5748 -0.7644 +vn 0.7334 0.6252 -0.2670 +vn 0.7334 0.6252 -0.2669 +vn 0.7151 0.5747 0.3979 +vn 0.1598 0.6252 0.7639 +vn -0.2785 0.6252 0.7291 +vn -0.6285 0.6252 0.4627 +vn -0.6633 0.7332 -0.1498 +vn -0.2980 0.7759 -0.5561 +vn 0.2427 0.7332 -0.6352 +vn 0.5928 0.7759 -0.2158 +vn 0.5942 0.7332 0.3306 +vn 0.1292 0.7759 0.6175 +vn -0.2251 0.7759 0.5893 +vn -0.5080 0.7759 0.3741 +vn 0.4052 0.3079 -0.8608 +vn 0.3963 0.8168 -0.4193 +vn 0.4090 0.7639 -0.4991 +vn 0.4659 0.3054 -0.8305 +vn 0.0341 0.8168 0.5759 +vn -0.0776 0.8050 0.5881 +vn -0.2429 0.3079 0.9199 +vn -0.3547 0.3089 0.8825 +vn 0.3926 0.8026 -0.4490 +vn 0.5124 0.3023 -0.8038 +vn -0.2254 0.7568 0.6136 +vn -0.4348 0.3068 0.8467 +vn 0.9397 -0.0000 0.3420 +vn 0.9397 -0.0000 0.3421 +vn 0.9397 0.0000 0.3420 +vn 0.2429 0.3079 -0.9199 +vn 0.1770 0.3053 -0.9357 +vn 0.0075 0.7639 -0.6453 +vn -0.0341 0.8168 -0.5759 +vn -0.3186 0.8050 0.5004 +vn -0.3963 0.8168 0.4193 +vn -0.2955 0.3089 0.9040 +vn -0.4052 0.3078 0.8609 +vn 0.1242 0.3024 -0.9451 +vn -0.0121 0.8027 -0.5963 +vn -0.2218 0.7568 0.6149 +vn -0.2112 0.3068 0.9281 +vn -0.9397 0.0000 -0.3420 +vn -0.9397 0.0001 -0.3420 +vn -0.9397 -0.0001 -0.3419 +vn -0.9397 -0.0000 -0.3420 +vn -0.3420 0.0000 0.9397 +vn 0.3420 -0.0000 -0.9397 +vn -0.7828 0.4849 0.3900 +vn -0.5688 0.5340 0.6256 +vn -0.5617 0.5488 0.6191 +vn -0.7186 0.5445 0.4327 +vn -0.4524 -0.7860 0.4212 +vn -0.4525 -0.7860 0.4211 +vn -0.8273 -0.5310 -0.1832 +vn 0.7217 -0.0413 0.6910 +vn 0.7424 -0.0036 0.6700 +vn 0.5464 -0.2833 0.7882 +vn 0.4525 0.7860 -0.4212 +vn 0.2481 0.7700 -0.5878 +vn -0.7189 0.0461 -0.6936 +vn -0.6963 0.0837 -0.7129 +vn -0.5096 0.3234 -0.7973 +vn -0.3288 0.4574 0.8263 +vn -0.3700 0.5233 0.7676 +vn 0.1806 -0.5923 0.7852 +vn 0.6253 0.7471 -0.2252 +vn -0.5389 0.5930 0.5983 +vn -0.6878 0.5496 0.4742 +vn 0.8347 0.2418 0.4947 +vn -0.8246 -0.2000 -0.5292 +vn -0.8246 -0.1999 -0.5292 +vn -0.4123 0.5328 0.7390 +vn -0.0500 -0.9962 0.0714 +vn 0.0500 0.9962 -0.0714 +vn 0.5714 -0.0872 -0.8160 +vn 0.5714 -0.0872 -0.8161 +vn 0.5714 -0.0871 -0.8160 +vn 0.8192 -0.0000 0.5736 +vn 0.8191 0.0000 0.5736 +vn -0.5714 0.0871 0.8160 +vn -0.5714 0.0872 0.8160 +vn -0.8191 0.0000 -0.5736 +vn -0.8192 0.0000 -0.5736 +vn 0.5719 -0.0770 -0.8167 +vn 0.5716 -0.0821 -0.8164 +vn 0.5717 -0.0821 -0.8164 +vn 0.8200 0.0166 0.5722 +vn 0.8199 0.0166 0.5723 +vn -0.5708 0.0973 0.8153 +vn -0.5711 0.0922 0.8157 +vn -0.8182 0.0166 -0.5748 +vn -0.8182 0.0166 -0.5747 +vn 0.8191 -0.0000 0.5736 +vn -0.8191 0.0001 -0.5736 +vn 0.0410 0.7502 0.6599 +vn -0.4567 0.7133 0.5317 +vn -0.4388 0.7454 0.5018 +vn 0.0241 0.8038 0.5945 +vn 0.4995 0.7582 0.4191 +vn 0.4554 0.8041 0.3822 +vn 0.6496 0.7582 -0.0568 +vn 0.5923 0.8041 -0.0518 +vn 0.4191 0.7582 -0.4995 +vn 0.3822 0.8041 -0.4554 +vn -0.0568 0.7582 -0.6496 +vn -0.0518 0.8041 -0.5923 +vn -0.4995 0.7582 -0.4191 +vn -0.4741 0.7962 -0.3759 +vn -0.6866 0.7221 0.0852 +vn -0.6708 0.7376 0.0776 +vn -0.2274 0.6544 0.7211 +vn -0.6707 0.6544 0.3491 +vn 0.3491 0.6544 0.6707 +vn 0.7211 0.6544 0.2274 +vn 0.6707 0.6544 -0.3491 +vn 0.2274 0.6544 -0.7211 +vn -0.3491 0.6544 -0.6707 +vn -0.7211 0.6544 -0.2274 +vn -0.4057 0.0000 0.9140 +vn 0.4617 -0.0000 0.8870 +vn 0.4617 0.0000 0.8870 +vn 0.9537 -0.0000 0.3007 +vn 0.8870 0.0000 -0.4617 +vn 0.3007 0.0000 -0.9537 +vn -0.4617 0.0000 -0.8870 +vn -0.9787 -0.0000 -0.2053 +vn -0.9787 0.0000 -0.2053 +vn -0.8870 0.0000 0.4618 +vn -0.0957 0.4943 0.8640 +vn -0.0677 0.5296 0.8455 +vn 0.6481 0.5263 0.5505 +vn 0.6746 0.4770 0.5634 +vn -0.0887 0.2560 0.9626 +vn 0.7432 0.2511 0.6201 +vn -0.0649 0.0324 0.9974 +vn 0.7663 0.0300 0.6418 +vn -0.0741 0.0077 0.9972 +vn 0.7660 -0.0000 0.6428 +vn -0.0841 -0.0000 0.9965 +vn -0.6088 0.1873 0.7709 +vn -0.6450 0.1711 0.7448 +vn -0.5708 0.0934 0.8157 +vn -0.5766 0.0501 0.8155 +vn -0.5822 0.1168 0.8046 +vn -0.5813 0.1469 0.8003 +vn -0.7644 0.4877 -0.4217 +vn -0.7260 0.5413 -0.4241 +vn -0.9804 0.1942 0.0335 +vn -0.9846 0.1747 0.0026 +vn -0.8292 0.2548 -0.4975 +vn -0.9947 0.0939 -0.0422 +vn -0.8429 0.0324 -0.5370 +vn -0.9979 0.0526 -0.0365 +vn -0.8462 0.0041 -0.5328 +vn -0.9899 0.1412 -0.0079 +vn -0.8494 0.0119 -0.5276 +vn -0.9762 0.2168 0.0085 +vn -0.0746 0.4770 -0.8757 +vn -0.0792 0.5263 -0.8466 +vn -0.0817 0.2511 -0.9645 +vn -0.0862 0.0300 -0.9958 +vn -0.0872 0.0000 -0.9962 +vn -0.0872 -0.0000 -0.9962 +vn 0.5699 0.4643 -0.6779 +vn 0.5498 0.5137 -0.6586 +vn 0.6246 0.2417 -0.7426 +vn 0.6428 0.0277 -0.7655 +vn 0.6428 -0.0000 -0.7660 +vn 0.8822 0.4643 -0.0780 +vn 0.8549 0.5137 -0.0726 +vn 0.9666 0.2417 -0.0857 +vn 0.9958 0.0277 -0.0875 +vn 0.9962 0.0000 -0.0872 +vn 0.5319 0.7502 0.3928 +vn 0.1137 0.7133 0.6916 +vn 0.1023 0.7454 0.6587 +vn 0.4709 0.8038 0.3636 +vn 0.6421 0.7582 -0.1132 +vn 0.5855 0.8041 -0.1032 +vn 0.3740 0.7582 -0.5341 +vn 0.3410 0.8041 -0.4870 +vn -0.1132 0.7582 -0.6421 +vn -0.1032 0.8041 -0.5855 +vn -0.5341 0.7582 -0.3740 +vn -0.4870 0.8041 -0.3410 +vn -0.6421 0.7582 0.1132 +vn -0.5927 0.7962 0.1215 +vn -0.3761 0.7221 0.5807 +vn -0.3717 0.7376 0.5637 +vn 0.4063 0.6544 0.6377 +vn -0.1637 0.6544 0.7382 +vn 0.7382 0.6544 0.1637 +vn 0.6377 0.6544 -0.4063 +vn 0.1637 0.6544 -0.7382 +vn -0.4063 0.6544 -0.6377 +vn -0.7382 0.6544 -0.1637 +vn -0.6377 0.6544 0.4063 +vn 0.4394 -0.0000 0.8983 +vn 0.9763 -0.0000 0.2164 +vn 0.8434 0.0000 -0.5373 +vn 0.2164 0.0000 -0.9763 +vn -0.5373 0.0000 -0.8434 +vn -0.9763 0.0000 -0.2164 +vn -0.7864 0.0000 0.6178 +vn -0.7864 -0.0000 0.6178 +vn -0.2164 -0.0000 0.9763 +vn -0.2164 0.0000 0.9763 +vn 0.6004 0.4943 0.6287 +vn 0.6042 0.5296 0.5954 +vn 0.8382 0.5263 -0.1426 +vn 0.8652 0.4770 -0.1546 +vn 0.6804 0.2560 0.6867 +vn 0.9528 0.2511 -0.1708 +vn 0.7223 0.0324 0.6908 +vn 0.9842 0.0300 -0.1745 +vn 0.7163 0.0077 0.6978 +vn 0.9848 0.0000 -0.1736 +vn 0.7093 -0.0000 0.7050 +vn 0.9848 -0.0000 -0.1737 +vn 0.1992 0.1873 0.9619 +vn 0.1560 0.1711 0.9728 +vn 0.2580 0.0934 0.9616 +vn 0.2541 0.0501 0.9659 +vn 0.2422 0.1168 0.9632 +vn 0.2394 0.1469 0.9597 +vn -0.8144 0.4877 0.3145 +vn -0.7916 0.5413 0.2835 +vn -0.6045 0.1942 0.7726 +vn -0.6309 0.1747 0.7560 +vn -0.9141 0.2548 0.3155 +vn -0.6717 0.0939 0.7349 +vn -0.9532 0.0324 0.3005 +vn -0.6695 0.0526 0.7410 +vn -0.9521 0.0041 0.3058 +vn -0.6424 0.1412 0.7533 +vn -0.9502 0.0119 0.3116 +vn -0.6210 0.2169 0.7533 +vn -0.7188 0.4770 -0.5057 +vn -0.6994 0.5263 -0.4835 +vn -0.7914 0.2511 -0.5574 +vn -0.8182 0.0300 -0.5741 +vn -0.8192 -0.0000 -0.5736 +vn -0.1530 0.4643 -0.8723 +vn -0.1511 0.5137 -0.8446 +vn -0.1674 0.2417 -0.9558 +vn -0.1732 0.0277 -0.9845 +vn -0.1736 0.0000 -0.9848 +vn -0.1736 -0.0000 -0.9848 +vn 0.5073 0.4643 -0.7260 +vn 0.4939 0.5137 -0.7016 +vn 0.5557 0.2417 -0.7955 +vn 0.5730 0.0277 -0.8191 +vn 0.5736 0.0000 -0.8192 +vn 0.5736 -0.0000 -0.8192 +vn -0.9027 -0.4300 -0.0180 +vn -0.6307 -0.4300 0.6461 +vn -0.6519 -0.2974 0.6976 +vn -0.9539 -0.2974 -0.0399 +vn -0.5497 -0.4300 -0.7162 +vn -0.5977 -0.2974 -0.7445 +vn 0.1463 -0.4300 -0.8909 +vn 0.1752 -0.2974 -0.9385 +vn 0.7871 -0.4299 -0.4422 +vn 0.8220 -0.2974 -0.4857 +vn 0.8610 -0.4300 0.2716 +vn 0.9040 -0.2974 0.3070 +vn 0.4565 -0.4346 0.7764 +vn 0.4830 -0.3029 0.8215 +vn -0.0357 -0.4346 0.8999 +vn -0.0378 -0.3029 0.9523 +vn -0.6799 -0.0091 0.7332 +vn -0.6178 0.4225 0.6632 +vn -0.9055 0.4225 -0.0393 +vn -0.9989 -0.0091 -0.0457 +vn -0.5685 0.4225 -0.7059 +vn -0.6290 -0.0091 -0.7773 +vn 0.1677 0.4225 -0.8907 +vn 0.1873 -0.0091 -0.9823 +vn 0.7796 0.4225 -0.4623 +vn 0.8589 -0.0091 -0.5120 +vn 0.8578 0.4225 0.2928 +vn 0.9456 -0.0091 0.3252 +vn 0.4567 0.4338 0.7767 +vn 0.5068 -0.0093 0.8620 +vn -0.0357 0.4338 0.9003 +vn -0.0397 -0.0093 0.9992 +vn -0.5576 0.5943 0.5795 +vn -0.8039 0.5943 -0.0219 +vn -0.4943 0.5943 -0.6344 +vn 0.1361 0.5943 -0.7926 +vn 0.6983 0.5943 -0.3990 +vn 0.7652 0.5943 0.2475 +vn 0.4085 0.5919 0.6948 +vn -0.0320 0.5919 0.8054 +vn -0.6311 0.4284 0.6466 +vn -0.9034 0.4284 -0.0181 +vn -0.5503 0.4284 -0.7167 +vn 0.1465 0.4284 -0.8916 +vn 0.7878 0.4284 -0.4426 +vn 0.8617 0.4284 0.2719 +vn 0.4569 0.4330 0.7770 +vn -0.0358 0.4330 0.9007 +vn -0.9254 0.0000 0.3790 +vn -0.8924 -0.0000 -0.4512 +vn -0.2435 -0.0000 -0.9699 +vn 0.5736 -0.0000 -0.8191 +vn 0.9947 -0.0000 -0.1029 +vn 0.7292 0.0000 0.6843 +vn 0.2435 0.0000 0.9699 +vn -0.3196 0.0000 0.9476 +vn -0.7634 -0.5652 0.3127 +vn -0.7032 -0.6157 -0.3555 +vn -0.2008 -0.5652 -0.8001 +vn 0.4520 -0.6157 -0.6455 +vn 0.8206 -0.5652 -0.0849 +vn 0.5746 -0.6157 0.5392 +vn 0.1918 -0.6157 0.7642 +vn -0.2518 -0.6157 0.7466 +vn -0.7573 0.5747 0.3101 +vn -0.7573 0.5748 0.3102 +vn -0.6965 0.6252 -0.3521 +vn -0.1992 0.5747 -0.7937 +vn 0.4476 0.6252 -0.6393 +vn 0.4477 0.6252 -0.6393 +vn 0.8140 0.5747 -0.0842 +vn 0.5691 0.6252 0.5341 +vn 0.1900 0.6252 0.7570 +vn -0.2494 0.6252 0.7395 +vn -0.6293 0.7332 0.2577 +vn -0.5630 0.7759 -0.2846 +vn -0.1655 0.7332 -0.6595 +vn 0.3618 0.7759 -0.5168 +vn 0.6764 0.7332 -0.0700 +vn 0.4600 0.7759 0.4317 +vn 0.1536 0.7759 0.6119 +vn -0.2016 0.7759 0.5978 +vn -0.1618 0.3079 -0.9376 +vn 0.0842 0.8168 -0.5708 +vn 0.0488 0.7639 -0.6435 +vn -0.0948 0.3054 -0.9475 +vn 0.3583 0.8168 0.4522 +vn 0.2738 0.8050 0.5263 +vn 0.3286 0.3078 0.8929 +vn 0.2156 0.3089 0.9264 +vn 0.0641 0.8026 -0.5930 +vn -0.0413 0.3023 -0.9523 +vn 0.1674 0.7568 0.6319 +vn 0.1295 0.3068 0.9429 +vn 0.9659 0.0000 -0.2588 +vn 0.9659 0.0001 -0.2589 +vn 0.9659 0.0001 -0.2588 +vn -0.3286 0.3079 -0.8929 +vn -0.3917 0.3054 -0.8679 +vn -0.3640 0.7639 -0.5329 +vn -0.3583 0.8168 -0.4522 +vn 0.0261 0.8050 0.5927 +vn -0.0842 0.8168 0.5708 +vn 0.2765 0.3089 0.9100 +vn 0.1618 0.3079 0.9376 +vn -0.4404 0.3024 -0.8454 +vn -0.3520 0.8027 -0.4815 +vn 0.1710 0.7568 0.6309 +vn 0.3593 0.3068 0.8813 +vn -0.9659 0.0000 0.2588 +vn -0.9659 0.0001 0.2588 +vn -0.9659 -0.0000 0.2588 +vn 0.2588 0.0000 0.9659 +vn -0.2588 -0.0000 -0.9659 +vn 0.9659 -0.0000 -0.2588 +vn -0.4175 0.4850 0.7684 +vn -0.1071 0.5340 0.8387 +vn -0.1050 0.5488 0.8293 +vn -0.3405 0.5445 0.7666 +vn -0.1290 -0.7860 0.6046 +vn -0.1291 -0.7860 0.6046 +vn -0.7828 -0.5311 0.3243 +vn 0.9875 -0.0413 0.1521 +vn 0.9924 -0.0036 0.1229 +vn 0.8997 -0.2833 0.3322 +vn 0.1291 0.7860 -0.6046 +vn -0.1339 0.7701 -0.6238 +vn -0.9867 0.0461 -0.1558 +vn -0.9793 0.0837 -0.1845 +vn -0.8748 0.3234 -0.3608 +vn 0.2046 0.4574 0.8654 +vn 0.1372 0.5233 0.8410 +vn 0.5983 -0.5923 0.5396 +vn 0.3831 0.7471 -0.5432 +vn -0.0983 0.5930 0.7992 +vn -0.2914 0.5495 0.7830 +vn 0.9675 0.2417 -0.0736 +vn -0.9790 -0.2000 0.0394 +vn 0.0861 0.5328 0.8418 +vn -0.0000 -0.9962 0.0871 +vn -0.0000 -0.9962 0.0872 +vn 0.0000 -0.9962 0.0871 +vn -0.0000 0.9962 -0.0871 +vn -0.0000 -0.0872 -0.9962 +vn 0.0000 0.0872 0.9962 +vn -0.0000 -0.0770 -0.9970 +vn -0.0000 -0.0821 -0.9966 +vn 0.9999 0.0166 -0.0015 +vn 0.0000 0.0973 0.9953 +vn 0.0000 0.0922 0.9957 +vn -0.9999 0.0166 -0.0015 +vn -0.0000 0.9962 -0.0872 +vn 0.0000 0.9962 -0.0872 +vn -0.8858 -0.4300 -0.1745 +vn -0.7333 -0.4300 0.5267 +vn -0.7631 -0.2974 0.5738 +vn -0.9325 -0.2974 -0.2049 +vn -0.4170 -0.4300 -0.8008 +vn -0.4593 -0.2974 -0.8370 +vn 0.2988 -0.4300 -0.8520 +vn 0.3355 -0.2974 -0.8938 +vn 0.8520 -0.4300 -0.2988 +vn 0.8938 -0.2974 -0.3355 +vn 0.8008 -0.4300 0.4170 +vn 0.8370 -0.2974 0.4593 +vn 0.3147 -0.4346 0.8438 +vn 0.3331 -0.3029 0.8929 +vn -0.1914 -0.4346 0.8800 +vn -0.2026 -0.3029 0.9312 +vn -0.7969 -0.0091 0.6040 +vn -0.7236 0.4225 0.5458 +vn -0.8849 0.4225 -0.1959 +vn -0.9758 -0.0091 -0.2184 +vn -0.4373 0.4225 -0.7939 +vn -0.4845 -0.0091 -0.8748 +vn 0.3199 0.4225 -0.8481 +vn 0.3551 -0.0091 -0.9348 +vn 0.8481 0.4225 -0.3199 +vn 0.9348 -0.0091 -0.3551 +vn 0.7939 0.4225 0.4373 +vn 0.8747 -0.0091 0.4845 +vn 0.3149 0.4338 0.8442 +vn 0.3494 -0.0093 0.9369 +vn -0.1915 0.4338 0.8804 +vn -0.2126 -0.0093 0.9771 +vn -0.6498 0.5943 0.4739 +vn -0.7879 0.5943 -0.1612 +vn -0.3766 0.5943 -0.7106 +vn 0.2717 0.5943 -0.7570 +vn 0.7570 0.5943 -0.2717 +vn 0.7106 0.5943 0.3766 +vn 0.2817 0.5919 0.7552 +vn -0.1713 0.5919 0.7876 +vn -0.7338 0.4284 0.5272 +vn -0.8865 0.4284 -0.1748 +vn -0.4174 0.4284 -0.8014 +vn 0.2991 0.4284 -0.8526 +vn 0.8526 0.4284 -0.2991 +vn 0.8014 0.4284 0.4174 +vn 0.3150 0.4330 0.8445 +vn -0.1916 0.4331 0.8808 +vn -0.9771 0.0000 0.2126 +vn -0.8005 -0.0000 -0.5993 +vn -0.0713 -0.0000 -0.9975 +vn 0.7071 -0.0000 -0.7071 +vn 0.9975 0.0000 0.0713 +vn 0.5992 0.0000 0.8006 +vn 0.0713 0.0000 0.9975 +vn -0.4793 0.0000 0.8777 +vn -0.8061 -0.5652 0.1754 +vn -0.6308 -0.6157 -0.4722 +vn -0.0589 -0.5652 -0.8229 +vn -0.0588 -0.5652 -0.8228 +vn 0.5572 -0.6157 -0.5572 +vn 0.8229 -0.5652 0.0589 +vn 0.8229 -0.5652 0.0588 +vn 0.4722 -0.6157 0.6308 +vn 0.0562 -0.6157 0.7860 +vn -0.3776 -0.6157 0.6916 +vn 0.5993 0.0000 0.8006 +vn -0.7997 0.5747 0.1739 +vn -0.7996 0.5748 0.1740 +vn -0.6248 0.6252 -0.4676 +vn -0.6248 0.6252 -0.4677 +vn -0.0584 0.5747 -0.8163 +vn -0.0584 0.5747 -0.8162 +vn -0.0584 0.5748 -0.8162 +vn 0.5518 0.6252 -0.5519 +vn 0.5519 0.6252 -0.5519 +vn 0.8163 0.5747 0.0584 +vn 0.8162 0.5748 0.0584 +vn 0.4677 0.6252 0.6248 +vn 0.0557 0.6252 0.7785 +vn -0.3740 0.6252 0.6850 +vn -0.6644 0.7332 0.1445 +vn -0.5051 0.7759 -0.3780 +vn -0.0485 0.7332 -0.6782 +vn 0.4461 0.7759 -0.4461 +vn 0.6783 0.7332 0.0486 +vn 0.3781 0.7759 0.5050 +vn 0.0450 0.7759 0.6293 +vn -0.3023 0.7759 0.5537 +vn 0.0034 0.3079 -0.9514 +vn 0.1820 0.8168 -0.5475 +vn 0.1598 0.7639 -0.6252 +vn 0.0712 0.3054 -0.9496 +vn 0.2743 0.8168 0.5076 +vn 0.1782 0.8050 0.5658 +vn 0.1686 0.3079 0.9364 +vn 0.0515 0.3089 0.9497 +vn 0.1661 0.8027 -0.5729 +vn 0.1247 0.3023 -0.9450 +vn 0.0551 0.7568 0.6513 +vn -0.0362 0.3068 0.9511 +vn 0.9962 -0.0000 -0.0872 +vn 0.9962 -0.0001 -0.0871 +vn -0.1686 0.3079 -0.9364 +vn -0.2350 0.3053 -0.9228 +vn -0.2659 0.7639 -0.5880 +vn -0.2743 0.8168 -0.5076 +vn -0.0773 0.8050 0.5882 +vn -0.1820 0.8168 0.5475 +vn 0.1143 0.3088 0.9442 +vn -0.0034 0.3079 0.9514 +vn -0.2869 0.3024 -0.9090 +vn -0.2630 0.8027 -0.5353 +vn 0.0589 0.7568 0.6510 +vn 0.2008 0.3068 0.9303 +vn -0.9962 0.0000 0.0871 +vn -0.9962 -0.0000 0.0871 +vn -0.9962 0.0001 0.0871 +vn 0.0872 0.0000 0.9962 +vn -0.9962 -0.0000 0.0872 +vn -0.9962 0.0000 0.0872 +vn -0.5446 0.4850 0.6842 +vn -0.2511 0.5340 0.8073 +vn -0.2474 0.5488 0.7985 +vn -0.4684 0.5445 0.6958 +vn -0.2320 -0.7860 0.5730 +vn -0.2321 -0.7860 0.5729 +vn -0.8272 -0.5310 0.1836 +vn 0.9461 -0.0414 0.3212 +vn 0.9560 -0.0037 0.2933 +vn 0.8283 -0.2833 0.4834 +vn 0.2321 0.7860 -0.5730 +vn -0.0236 0.7700 -0.6375 +vn -0.0236 0.7700 -0.6376 +vn -0.9447 0.0462 -0.3247 +vn -0.9324 0.0838 -0.3517 +vn -0.7989 0.3235 -0.5071 +vn 0.0512 0.4574 0.8878 +vn -0.0110 0.5233 0.8521 +vn 0.4955 -0.5923 0.6353 +vn 0.4717 0.7470 -0.4685 +vn -0.2356 0.5930 0.7700 +vn -0.4230 0.5496 0.7205 +vn 0.9656 0.2419 0.0957 +vn 0.9656 0.2419 0.0958 +vn -0.9710 -0.2000 -0.1312 +vn -0.0614 0.5328 0.8440 +vn -0.0151 -0.9962 0.0858 +vn 0.0151 0.9962 -0.0858 +vn 0.1730 -0.0872 -0.9811 +vn 0.1730 -0.0871 -0.9811 +vn 0.9848 -0.0000 0.1736 +vn -0.1730 0.0872 0.9811 +vn -0.1730 0.0871 0.9811 +vn -0.9848 0.0000 -0.1736 +vn 0.1731 -0.0770 -0.9819 +vn 0.1731 -0.0821 -0.9815 +vn 0.9849 0.0166 0.1722 +vn 0.9849 0.0166 0.1721 +vn -0.1728 0.0973 0.9801 +vn -0.1729 0.0922 0.9806 +vn -0.9844 0.0166 -0.1751 +vn -0.9844 0.0166 -0.1750 +vn -0.9848 -0.0001 -0.1736 +vn 0.8672 -0.4300 0.2510 +vn 0.7764 -0.4300 -0.4608 +vn 0.8102 -0.2974 -0.5051 +vn 0.9111 -0.2974 0.2854 +vn 0.3456 -0.4300 0.8341 +vn 0.3846 -0.2974 0.8738 +vn -0.3719 -0.4300 0.8227 +vn -0.4122 -0.2974 0.8612 +vn -0.8748 -0.4300 0.2234 +vn -0.9197 -0.2974 0.2564 +vn -0.7614 -0.4300 -0.4852 +vn -0.7938 -0.2974 -0.5305 +vn -0.2400 -0.4346 -0.8681 +vn -0.2540 -0.3029 -0.9186 +vn 0.2674 -0.4346 -0.8600 +vn 0.2830 -0.3029 -0.9100 +vn 0.8465 -0.0091 -0.5323 +vn 0.7684 0.4225 -0.4807 +vn 0.8645 0.4225 0.2723 +vn 0.9531 -0.0091 0.3026 +vn 0.3664 0.4225 0.8290 +vn 0.4064 -0.0091 0.9136 +vn -0.3926 0.4225 0.8170 +vn -0.4352 -0.0091 0.9003 +vn -0.8727 0.4225 0.2447 +vn -0.9622 -0.0091 0.2722 +vn -0.7528 0.4225 -0.5048 +vn -0.8292 -0.0091 -0.5589 +vn -0.2401 0.4338 -0.8684 +vn -0.2665 -0.0093 -0.9638 +vn 0.2675 0.4338 -0.8604 +vn 0.2969 -0.0093 -0.9549 +vn 0.6886 0.5943 -0.4155 +vn 0.7709 0.5943 0.2292 +vn 0.3133 0.5943 0.7407 +vn -0.3366 0.5943 0.7304 +vn -0.7778 0.5943 0.2046 +vn -0.6751 0.5943 -0.4371 +vn -0.2148 0.5919 -0.7769 +vn 0.2393 0.5919 -0.7697 +vn 0.7770 0.4284 -0.4612 +vn 0.8679 0.4284 0.2513 +vn 0.3460 0.4284 0.8347 +vn -0.3724 0.4284 0.8233 +vn -0.8755 0.4284 0.2237 +vn -0.7620 0.4284 -0.4857 +vn -0.2402 0.4331 -0.8688 +vn 0.2677 0.4330 -0.8607 +vn 0.9920 -0.0000 -0.1266 +vn 0.7453 0.0000 0.6667 +vn -0.0159 0.0000 0.9999 +vn -0.7661 0.0000 0.6427 +vn -0.9874 -0.0000 -0.1580 +vn -0.5273 -0.0000 -0.8497 +vn 0.0158 -0.0000 -0.9999 +vn 0.5540 -0.0000 -0.8325 +vn 0.8183 -0.5652 -0.1044 +vn 0.5872 -0.6158 0.5254 +vn 0.5873 -0.6157 0.5253 +vn -0.0131 -0.5652 0.8249 +vn -0.0131 -0.5652 0.8248 +vn -0.6036 -0.6157 0.5065 +vn -0.6036 -0.6157 0.5064 +vn -0.8146 -0.5652 -0.1304 +vn -0.8146 -0.5652 -0.1303 +vn -0.4154 -0.6157 -0.6696 +vn -0.4155 -0.6157 -0.6696 +vn 0.0125 -0.6157 -0.7879 +vn 0.4365 -0.6157 -0.6561 +vn 0.4365 -0.6157 -0.6560 +vn 0.7453 0.0000 0.6668 +vn -0.7661 0.0000 0.6428 +vn -0.5272 -0.0000 -0.8497 +vn 0.0159 -0.0000 -0.9999 +vn 0.5539 -0.0000 -0.8326 +vn 0.8117 0.5748 -0.1036 +vn 0.5817 0.6252 0.5203 +vn 0.5817 0.6252 0.5204 +vn -0.0130 0.5747 0.8182 +vn -0.5978 0.6252 0.5017 +vn -0.5979 0.6252 0.5017 +vn -0.8081 0.5747 -0.1293 +vn -0.8080 0.5748 -0.1293 +vn -0.4115 0.6252 -0.6632 +vn 0.0124 0.6252 -0.7804 +vn 0.4323 0.6252 -0.6498 +vn 0.6745 0.7332 -0.0861 +vn 0.4702 0.7759 0.4206 +vn -0.0108 0.7332 0.6799 +vn -0.4833 0.7759 0.4055 +vn -0.6714 0.7332 -0.1075 +vn -0.3326 0.7759 -0.5361 +vn 0.0100 0.7759 -0.6308 +vn 0.3495 0.7759 -0.5253 +vn -0.0863 0.3079 0.9475 +vn -0.2290 0.8168 0.5296 +vn -0.2137 0.7639 0.6089 +vn -0.1537 0.3054 0.9398 +vn -0.2290 0.8168 -0.5296 +vn -0.1282 0.8050 -0.5792 +vn -0.0863 0.3078 -0.9475 +vn 0.0315 0.3088 -0.9506 +vn -0.2154 0.8026 0.5562 +vn -0.2066 0.3023 0.9305 +vn 0.0019 0.7568 -0.6537 +vn 0.1189 0.3068 -0.9443 +vn -1.0000 0.0001 -0.0000 +vn -1.0000 0.0001 0.0000 +vn 0.0863 0.3079 0.9475 +vn 0.1537 0.3053 0.9398 +vn 0.2137 0.7639 0.6089 +vn 0.2290 0.8168 0.5295 +vn 0.1282 0.8050 -0.5792 +vn 0.2290 0.8168 -0.5295 +vn -0.0315 0.3088 -0.9506 +vn 0.0863 0.3078 -0.9475 +vn 0.2066 0.3024 0.9305 +vn 0.2154 0.8027 0.5562 +vn -0.0019 0.7568 -0.6537 +vn -0.1189 0.3068 -0.9443 +vn 1.0000 0.0001 0.0000 +vn 1.0000 0.0001 -0.0000 +vn 1.0000 0.0001 0.0001 +vn 1.0000 0.0002 -0.0000 +vn 0.6022 0.4849 -0.6342 +vn 0.3205 0.5340 -0.7824 +vn 0.3160 0.5488 -0.7739 +vn 0.5273 0.5445 -0.6523 +vn 0.2812 -0.7860 -0.5506 +vn 0.2811 -0.7860 -0.5506 +vn 0.8401 -0.5310 -0.1108 +vn -0.9145 -0.0412 -0.4026 +vn -0.9267 -0.0035 -0.3757 +vn -0.7831 -0.2834 -0.5536 +vn -0.2811 0.7860 0.5505 +vn -0.0321 0.7700 0.6372 +vn 0.9127 0.0460 0.4061 +vn 0.8981 0.0836 0.4319 +vn 0.7516 0.3234 0.5749 +vn 0.0264 0.4574 -0.8889 +vn 0.0852 0.5233 -0.8479 +vn -0.4383 -0.5924 -0.6760 +vn -0.5106 0.7471 0.4255 +vn 0.3018 0.5930 -0.7465 +vn 0.4842 0.5496 -0.6809 +vn -0.9537 0.2416 -0.1792 +vn 0.9559 -0.2000 0.2153 +vn 0.1347 0.5328 -0.8354 +vn 0.0226 -0.9962 -0.0842 +vn -0.0226 0.9962 0.0842 +vn -0.2578 -0.0872 0.9622 +vn -0.9659 -0.0000 -0.2588 +vn -0.9659 0.0000 -0.2589 +vn 0.2579 0.0872 -0.9622 +vn 0.2578 0.0872 -0.9622 +vn -0.2581 -0.0770 0.9631 +vn -0.2580 -0.0821 0.9627 +vn -0.9662 0.0166 -0.2573 +vn -0.9662 0.0166 -0.2574 +vn 0.2576 0.0973 -0.9613 +vn 0.2577 0.0922 -0.9618 +vn 0.9654 0.0166 0.2602 +vn 0.9654 0.0166 0.2601 +vn -0.9659 -0.0000 -0.2589 +vn -0.9659 -0.0001 -0.2590 +vn -0.9659 0.0001 -0.2588 +vn 0.9659 0.0001 0.2588 +vn 0.9659 0.0000 0.2588 +vn -0.2578 -0.0872 0.9623 +vn 0.2578 0.0871 -0.9623 +vn 0.8672 -0.4300 0.2511 +vn -0.3720 -0.4300 0.8227 +vn 0.3132 0.5943 0.7407 +vn -0.2402 0.4330 -0.8688 +vn 0.5873 -0.6157 0.5254 +vn -0.1537 0.3054 0.9397 +vn -0.2290 0.8168 -0.5295 +vn -0.0863 0.3079 -0.9475 +vn 0.0315 0.3089 -0.9506 +vn -0.0315 0.3089 -0.9506 +vn 0.0863 0.3079 -0.9475 +vn 1.0000 0.0000 -0.0001 +vn -0.9145 -0.0412 -0.4025 +vn -0.9267 -0.0036 -0.3757 +vn -0.2811 0.7861 0.5505 +vn -0.0321 0.7701 0.6371 +vn 0.8980 0.0836 0.4319 +vn 0.9559 -0.2000 0.2152 +vn -0.2579 -0.0871 0.9622 +vn -0.2578 -0.0871 0.9623 +vn 0.2579 0.0871 -0.9622 +vn -0.9659 0.0000 -0.2588 +vn 0.2578 0.0872 -0.9623 +vn 0.0000 0.9397 0.3420 +vn -0.0000 0.9397 0.3420 +vn -0.0000 -0.9397 -0.3420 +vn -0.0000 -0.3420 0.9397 +vn 0.0000 -0.3420 0.9397 +vn -0.0000 0.3420 -0.9397 +vn 0.0000 -0.3516 0.9362 +vn 0.0000 -0.3468 0.9379 +vn 0.9999 -0.0156 -0.0057 +vn 0.0000 0.3324 -0.9431 +vn -0.0000 0.3372 -0.9414 +vn -0.0000 0.3373 -0.9414 +vn -0.9999 -0.0156 -0.0057 +vn 0.0000 -0.9397 -0.3420 +vn 0.0000 0.3420 -0.9397 +vn -0.0006 1.0000 0.0085 +vn -0.0007 1.0000 0.0089 +vn -0.0000 1.0000 0.0019 +vn 0.0000 1.0000 0.0015 +vn -0.9993 0.0098 -0.0349 +vn -0.9989 0.0168 -0.0441 +vn -0.9995 0.0069 -0.0311 +vn -0.9998 -0.0000 -0.0220 +vn 0.9991 0.0084 -0.0423 +vn 0.9986 -0.0000 -0.0533 +vn 0.9992 0.0119 -0.0377 +vn 0.9994 0.0203 -0.0267 +vn -0.9997 0.0104 -0.0219 +vn -0.0005 -0.3656 0.9308 +vn -0.0010 -0.3656 0.9308 +vn 0.9997 -0.0086 0.0220 +vn 1.0000 -0.0018 -0.0000 +vn -0.0000 0.3654 -0.9308 +vn -0.0042 0.3649 -0.9310 +vn -0.0000 0.3645 -0.9312 +vn 0.0004 0.3645 -0.9312 +vn -0.9995 -0.0132 0.0285 +vn -1.0000 0.0003 0.0000 +vn 0.0006 -0.3654 0.9309 +vn 0.0012 -0.3654 0.9308 +vn 0.9996 0.0104 -0.0266 +vn 1.0000 0.0021 0.0000 +vn -1.0000 0.0022 0.0000 +vn -1.0000 0.0021 0.0000 +vn -0.9992 -0.0409 0.0035 +vn -0.9998 -0.0203 0.0069 +vn 0.9991 0.0409 -0.0067 +vn 0.9998 0.0203 -0.0033 +vn -0.9994 0.0338 -0.0027 +vn -0.9998 0.0168 -0.0055 +vn 0.9994 -0.0338 0.0055 +vn 0.9999 -0.0168 0.0027 +vn -0.0034 1.0000 -0.0002 +vn -0.0017 1.0000 0.0002 +vn 0.0028 1.0000 0.0011 +vn 0.0014 1.0000 0.0008 +vn 0.5022 0.5970 -0.6256 +vn 0.2157 0.5968 -0.7728 +vn 0.2086 0.6105 -0.7641 +vn 0.4176 0.6423 -0.6427 +vn 0.4168 -0.7123 -0.5647 +vn 0.4167 -0.7124 -0.5647 +vn 0.9219 -0.3683 -0.1205 +vn -0.8934 -0.1992 -0.4027 +vn -0.9122 -0.1648 -0.3751 +vn -0.7208 -0.4106 -0.5584 +vn -0.4168 0.7123 0.5647 +vn -0.1686 0.7402 0.6509 +vn 0.8908 0.2035 0.4062 +vn 0.8697 0.2373 0.4328 +vn 0.6827 0.4439 0.5803 +vn -0.0601 0.4701 -0.8806 +vn -0.0140 0.5449 -0.8384 +vn -0.3263 -0.6499 -0.6864 +vn -0.6359 0.6347 0.4391 +vn 0.1868 0.6508 -0.7359 +vn 0.3742 0.6400 -0.6711 +vn -0.9823 0.0681 -0.1744 +vn 0.9770 -0.0274 0.2114 +vn 0.0330 0.5630 -0.8258 +vn 0.3100 0.9397 0.1445 +vn 0.3099 0.9397 0.1446 +vn 0.3100 0.9397 0.1446 +vn -0.3100 -0.9397 -0.1446 +vn -0.3101 -0.9397 -0.1446 +vn -0.3099 -0.9397 -0.1446 +vn 0.8516 -0.3420 0.3972 +vn 0.8516 -0.3421 0.3972 +vn 0.4225 0.0000 -0.9063 +vn 0.4226 0.0000 -0.9063 +vn -0.8517 0.3420 -0.3971 +vn -0.4226 -0.0000 0.9063 +vn -0.4226 0.0000 0.9063 +vn 0.8484 -0.3516 0.3958 +vn 0.8500 -0.3468 0.3964 +vn 0.8501 -0.3468 0.3964 +vn 0.4173 -0.0156 -0.9086 +vn 0.4174 -0.0156 -0.9086 +vn -0.8548 0.3324 -0.3985 +vn -0.8532 0.3372 -0.3979 +vn -0.4278 -0.0156 0.9037 +vn -0.4277 -0.0157 0.9038 +vn 0.4226 -0.0000 -0.9063 +vn 0.4227 -0.0000 -0.9063 +vn -0.3100 -0.9397 -0.1445 +vn 0.8516 -0.3422 0.3971 +vn 0.3099 0.9397 0.1445 +vn -0.8517 0.3419 -0.3972 +vn 0.8517 -0.3419 0.3971 +vn 0.8517 -0.3420 0.3971 +vn -0.8517 0.3419 -0.3971 +vn 0.0075 1.0000 0.0042 +vn 0.0078 1.0000 0.0044 +vn 0.0017 1.0000 0.0008 +vn 0.0013 1.0000 0.0006 +vn -0.9063 -0.0000 -0.4226 +vn -0.4540 0.0098 0.8909 +vn -0.4621 0.0168 0.8867 +vn -0.4506 0.0069 0.8927 +vn -0.4425 0.0000 0.8968 +vn 0.9063 0.0001 0.4226 +vn 0.9063 0.0000 0.4226 +vn 0.3839 0.0084 -0.9233 +vn 0.3738 0.0000 -0.9275 +vn 0.3882 0.0119 -0.9215 +vn 0.3983 0.0203 -0.9170 +vn -0.9063 -0.0000 -0.4227 +vn -0.9063 0.0000 -0.4226 +vn -0.4424 0.0104 0.8968 +vn 0.8433 -0.3656 0.3938 +vn 0.8432 -0.3656 0.3943 +vn 0.4424 -0.0086 -0.8968 +vn 0.4226 -0.0017 -0.9063 +vn -0.8436 0.3654 -0.3934 +vn -0.8456 0.3649 -0.3897 +vn -0.8440 0.3645 -0.3936 +vn -0.8438 0.3645 -0.3939 +vn -0.3966 -0.0132 0.9179 +vn -0.4226 0.0003 0.9063 +vn 0.8439 -0.3654 0.3928 +vn 0.8442 -0.3654 0.3922 +vn 0.3983 0.0104 -0.9172 +vn 0.4226 0.0021 -0.9063 +vn 0.9063 -0.0000 0.4226 +vn -0.4226 0.0022 0.9063 +vn -0.4226 0.0021 0.9063 +vn -0.4191 -0.0409 0.9070 +vn -0.4163 -0.0204 0.9090 +vn 0.4162 0.0410 -0.9083 +vn 0.4195 0.0203 -0.9075 +vn -0.4248 0.0338 0.9046 +vn -0.4275 0.0168 0.9039 +vn 0.4273 -0.0338 -0.9035 +vn 0.4250 -0.0168 -0.9050 +vn -0.0016 1.0000 0.0030 +vn -0.0005 1.0000 0.0016 +vn 0.0022 1.0000 -0.0021 +vn 0.0013 1.0000 -0.0009 +vn -0.3548 0.5970 -0.7195 +vn -0.6093 0.5968 -0.5221 +vn -0.6043 0.6105 -0.5120 +vn -0.4060 0.6423 -0.6501 +vn -0.3356 -0.7124 -0.6163 +vn -0.3356 -0.7124 -0.6164 +vn 0.2803 -0.3682 -0.8865 +vn -0.7425 -0.1992 0.6395 +vn -0.7255 -0.1648 0.6682 +vn -0.8106 -0.4107 0.4174 +vn 0.3355 0.7124 0.6163 +vn 0.3356 0.7124 0.6163 +vn 0.5185 0.7403 0.4278 +vn 0.7449 0.2033 -0.6355 +vn 0.7600 0.2371 -0.6051 +vn 0.8145 0.4439 -0.3735 +vn -0.8235 0.4701 -0.3177 +vn -0.7658 0.5449 -0.3416 +vn -0.7599 -0.6500 0.0056 +vn 0.1292 0.6347 0.7619 +vn -0.5880 0.6508 -0.4803 +vn -0.4501 0.6400 -0.6228 +vn -0.5732 0.0681 0.8166 +vn 0.6044 -0.0274 -0.7962 +vn -0.7345 0.5630 -0.3789 +vn -0.8516 0.3420 -0.3971 +vn -0.8516 0.3421 -0.3972 +vn -0.8516 0.3420 -0.3972 +vn 0.8484 -0.3516 0.3957 +vn 0.8500 -0.3469 0.3964 +vn -0.8547 0.3324 -0.3987 +vn -0.8532 0.3373 -0.3979 +vn -0.4277 -0.0156 0.9038 +vn 0.4226 0.0001 -0.9063 +vn -0.8516 0.3421 -0.3971 +vn 0.2620 0.9397 -0.2199 +vn -0.2620 -0.9397 0.2198 +vn 0.7198 -0.3420 -0.6040 +vn 0.7198 -0.3421 -0.6040 +vn -0.6428 -0.0000 -0.7660 +vn -0.6428 -0.0000 -0.7661 +vn -0.7198 0.3420 0.6040 +vn -0.7199 0.3420 0.6040 +vn 0.6428 -0.0000 0.7660 +vn 0.6428 0.0000 0.7660 +vn 0.6428 0.0000 0.7661 +vn 0.7172 -0.3516 -0.6017 +vn 0.7185 -0.3468 -0.6029 +vn -0.6470 -0.0157 -0.7623 +vn -0.6472 -0.0156 -0.7622 +vn -0.7225 0.3324 0.6062 +vn -0.7212 0.3372 0.6051 +vn 0.6382 -0.0156 0.7697 +vn 0.6384 -0.0157 0.7696 +vn -0.6428 0.0001 -0.7660 +vn -0.6429 0.0002 -0.7660 +vn -0.6428 0.0000 -0.7660 +vn -0.6428 -0.0001 -0.7660 +vn 0.6429 0.0001 0.7660 +vn 0.6427 -0.0000 0.7661 +vn 0.6427 -0.0001 0.7661 +vn -0.2621 -0.9397 0.2199 +vn 0.7199 -0.3419 -0.6040 +vn 0.2620 0.9397 -0.2198 +vn -0.7198 0.3421 0.6040 +vn -0.7199 0.3419 0.6041 +vn -0.2620 -0.9397 0.2199 +vn 0.0069 1.0000 -0.0050 +vn 0.0073 1.0000 -0.0052 +vn 0.0015 1.0000 -0.0012 +vn 0.0011 1.0000 -0.0009 +vn -0.7660 0.0000 0.6428 +vn 0.6156 0.0099 0.7880 +vn 0.6083 0.0169 0.7935 +vn 0.6187 0.0070 0.7856 +vn 0.6258 0.0000 0.7800 +vn 0.7660 0.0001 -0.6428 +vn 0.7660 -0.0000 -0.6428 +vn -0.6746 0.0084 -0.7382 +vn -0.6827 -0.0000 -0.7307 +vn -0.6711 0.0119 -0.7412 +vn -0.6628 0.0203 -0.7485 +vn 0.6258 0.0104 0.7799 +vn 0.7134 -0.3656 -0.5979 +vn 0.7137 -0.3656 -0.5975 +vn -0.6257 -0.0086 -0.7800 +vn -0.6428 -0.0018 -0.7660 +vn -0.7130 0.3654 0.5984 +vn -0.7105 0.3649 0.6017 +vn -0.7133 0.3645 0.5986 +vn -0.7136 0.3645 0.5983 +vn 0.6644 -0.0132 0.7473 +vn 0.6428 0.0003 0.7661 +vn 0.7127 -0.3654 -0.5988 +vn 0.7123 -0.3654 -0.5993 +vn -0.6629 0.0104 -0.7486 +vn -0.6427 0.0021 -0.7661 +vn -0.6427 -0.0000 -0.7661 +vn 0.6428 0.0022 0.7660 +vn 0.6428 0.0021 0.7660 +vn 0.6449 -0.0409 0.7631 +vn 0.6479 -0.0203 0.7615 +vn -0.6473 0.0409 -0.7611 +vn -0.6452 0.0203 -0.7638 +vn 0.6403 0.0338 0.7673 +vn 0.6385 0.0169 0.7694 +vn -0.6382 -0.0338 -0.7691 +vn -0.6406 -0.0167 -0.7677 +vn 0.0021 1.0000 0.0027 +vn 0.0012 1.0000 0.0012 +vn -0.0009 1.0000 -0.0029 +vn -0.0003 1.0000 -0.0016 +vn 0.7660 0.0000 -0.6428 +vn 0.7661 0.0000 -0.6428 +vn 0.7661 -0.0000 -0.6428 +vn -0.8020 0.5970 0.0175 +vn -0.7306 0.5969 0.3315 +vn -0.7194 0.6105 0.3313 +vn -0.7608 0.6423 0.0932 +vn -0.7003 -0.7125 0.0436 +vn -0.7003 -0.7125 0.0437 +vn -0.6849 -0.3683 -0.6288 +vn 0.2658 -0.1993 0.9432 +vn 0.2991 -0.1648 0.9399 +vn 0.0356 -0.4106 0.9111 +vn 0.7005 0.7123 -0.0437 +vn 0.6070 0.7402 -0.2892 +vn -0.2614 0.2035 -0.9435 +vn -0.2275 0.2373 -0.9444 +vn 0.0057 0.4440 -0.8960 +vn -0.6359 0.4701 0.6121 +vn -0.6332 0.5449 0.5497 +vn -0.3161 -0.6499 0.6912 +vn 0.7451 0.6347 0.2049 +vn -0.6838 0.6508 0.3300 +vn -0.7547 0.6400 0.1447 +vn 0.4978 0.0681 0.8646 +vn -0.4661 -0.0274 -0.8843 +vn -0.6538 0.5630 0.5055 +vn 0.7198 -0.3419 -0.6041 +vn 0.6427 0.0000 0.7661 +vn 0.7185 -0.3467 -0.6029 +vn -0.6471 -0.0156 -0.7623 +vn -0.7211 0.3373 0.6051 +vn 0.6383 -0.0156 0.7696 +vn -0.6428 0.0001 -0.7661 +vn -0.6428 0.0000 -0.7661 +vn -0.6428 0.0002 -0.7660 +vn 0.6428 -0.0000 0.7661 +vn 0.7199 -0.3420 -0.6040 +# 2554 vertex normals + +vt 0.6655 0.3799 0.0000 +vt 0.6655 0.2980 0.0000 +vt 0.6061 0.2980 0.0000 +vt 0.6061 0.4262 0.0000 +vt 0.3051 0.5851 0.0000 +vt 0.3051 0.5008 0.0000 +vt 0.1303 0.5008 0.0000 +vt 0.1303 0.5851 0.0000 +vt 0.0138 0.6936 0.0000 +vt 0.0138 0.6029 0.0000 +vt 0.2175 0.6029 0.0000 +vt 0.2175 0.6936 0.0000 +vt 0.5468 0.3799 0.0000 +vt 0.5468 0.2980 0.0000 +vt 0.3901 0.2905 0.0000 +vt 0.3901 0.4260 0.0000 +vt 0.3301 0.3771 0.0000 +vt 0.3301 0.2905 0.0000 +vt 0.7661 0.5332 0.0000 +vt 0.7866 0.5343 0.0000 +vt 0.7868 0.5807 0.0000 +vt 0.7665 0.5956 0.0000 +vt 0.8286 0.5719 0.0000 +vt 0.8412 0.5719 0.0000 +vt 0.8412 0.5898 0.0000 +vt 0.8286 0.5898 0.0000 +vt 0.8477 0.4969 0.0000 +vt 0.8540 0.4969 0.0000 +vt 0.8540 0.5534 0.0000 +vt 0.8477 0.5534 0.0000 +vt 0.8172 0.5898 0.0000 +vt 0.8172 0.5719 0.0000 +vt 0.7968 0.6174 0.0000 +vt 0.8003 0.6175 0.0000 +vt 0.8000 0.6420 0.0000 +vt 0.7964 0.6420 0.0000 +vt 0.8288 0.6193 0.0000 +vt 0.8388 0.6193 0.0000 +vt 0.8371 0.6353 0.0000 +vt 0.7885 0.5925 0.0000 +vt 0.8003 0.5971 0.0000 +vt 0.7661 0.6208 0.0000 +vt 0.7661 0.6088 0.0000 +vt 0.8388 0.7121 0.0000 +vt 0.8288 0.7121 0.0000 +vt 0.8378 0.6962 0.0000 +vt 0.8254 0.6657 0.0000 +vt 0.8353 0.6657 0.0000 +vt 0.7460 0.5809 0.0000 +vt 0.7457 0.5350 0.0000 +vt 0.8540 0.6098 0.0000 +vt 0.8477 0.6098 0.0000 +vt 0.7996 0.6666 0.0000 +vt 0.7960 0.6666 0.0000 +vt 0.7319 0.5971 0.0000 +vt 0.7436 0.5925 0.0000 +vt 0.8580 0.5104 0.0000 +vt 0.8580 0.4256 0.0000 +vt 0.8636 0.4256 0.0000 +vt 0.8636 0.5104 0.0000 +vt 0.8636 0.5566 0.0000 +vt 0.8580 0.5566 0.0000 +vt 0.8636 0.6027 0.0000 +vt 0.8580 0.6027 0.0000 +vt 0.8636 0.6868 0.0000 +vt 0.8580 0.6868 0.0000 +vt 0.8180 0.7079 0.0000 +vt 0.8146 0.7079 0.0000 +vt 0.8139 0.6724 0.0000 +vt 0.8173 0.6724 0.0000 +vt 0.8132 0.6370 0.0000 +vt 0.8166 0.6369 0.0000 +vt 0.7319 0.5428 0.0000 +vt 0.7436 0.5420 0.0000 +vt 0.8540 0.6835 0.0000 +vt 0.8477 0.6835 0.0000 +vt 0.8477 0.4232 0.0000 +vt 0.8540 0.4232 0.0000 +vt 0.7885 0.5415 0.0000 +vt 0.8003 0.5428 0.0000 +vt 0.8078 0.6185 0.0000 +vt 0.8129 0.6184 0.0000 +vt 0.8082 0.6371 0.0000 +vt 0.8089 0.6725 0.0000 +vt 0.8096 0.7080 0.0000 +vt 0.8150 0.7265 0.0000 +vt 0.8100 0.7266 0.0000 +vt 0.7928 0.6174 0.0000 +vt 0.7925 0.6420 0.0000 +vt 0.7921 0.6665 0.0000 +vt 0.8173 0.6091 0.0000 +vt 0.8174 0.6183 0.0000 +vt 0.8127 0.6092 0.0000 +vt 0.8076 0.6093 0.0000 +vt 0.8388 0.6115 0.0000 +vt 0.8288 0.6115 0.0000 +vt 0.7921 0.6707 0.0000 +vt 0.7960 0.6707 0.0000 +vt 0.7996 0.6707 0.0000 +vt 0.8004 0.6133 0.0000 +vt 0.7968 0.6133 0.0000 +vt 0.7929 0.6133 0.0000 +vt 0.8288 0.7200 0.0000 +vt 0.8388 0.7200 0.0000 +vt 0.8101 0.7357 0.0000 +vt 0.8152 0.7356 0.0000 +vt 0.8196 0.7264 0.0000 +vt 0.8198 0.7356 0.0000 +vt 0.1047 0.0697 0.0000 +vt 0.1047 0.0688 0.0000 +vt 0.2162 0.0689 0.0000 +vt 0.2162 0.0698 0.0000 +vt 0.1047 0.0655 0.0000 +vt 0.2162 0.0656 0.0000 +vt 0.1066 0.0572 0.0000 +vt 0.1066 0.0557 0.0000 +vt 0.2128 0.0558 0.0000 +vt 0.2128 0.0573 0.0000 +vt 0.1066 0.0500 0.0000 +vt 0.2128 0.0501 0.0000 +vt 0.2904 0.8785 0.0000 +vt 0.2914 0.9922 0.0000 +vt 0.2039 0.9913 0.0000 +vt 0.1986 0.8824 0.0000 +vt 0.2030 0.7411 0.0000 +vt 0.2963 0.7363 0.0000 +vt 0.2828 0.8546 0.0000 +vt 0.1939 0.8533 0.0000 +vt 0.5048 0.2825 0.0000 +vt 0.4197 0.2818 0.0000 +vt 0.4202 0.2737 0.0000 +vt 0.5057 0.2744 0.0000 +vt 0.7719 0.6692 0.0000 +vt 0.7719 0.6558 0.0000 +vt 0.6326 0.8027 0.0000 +vt 0.6326 0.8161 0.0000 +vt 0.4932 0.6692 0.0000 +vt 0.4932 0.6558 0.0000 +vt 0.8611 0.9882 0.0000 +vt 0.8258 0.9875 0.0000 +vt 0.8274 0.9418 0.0000 +vt 0.8643 0.9445 0.0000 +vt 0.1059 0.8750 0.0000 +vt 0.1176 0.9905 0.0000 +vt 0.0318 0.9943 0.0000 +vt 0.0116 0.8630 0.0000 +vt 0.3785 0.9940 0.0000 +vt 0.3838 0.8670 0.0000 +vt 0.1087 0.7337 0.0000 +vt 0.1063 0.8523 0.0000 +vt 0.0191 0.8558 0.0000 +vt 0.0127 0.7217 0.0000 +vt 0.3712 0.8569 0.0000 +vt 0.3909 0.7233 0.0000 +vt 0.6752 0.2842 0.0000 +vt 0.5900 0.2833 0.0000 +vt 0.5912 0.2752 0.0000 +vt 0.6767 0.2761 0.0000 +vt 0.3347 0.2731 0.0000 +vt 0.3345 0.2812 0.0000 +vt 0.5462 0.8911 0.0000 +vt 0.5462 0.8749 0.0000 +vt 0.3921 0.8749 0.0000 +vt 0.3921 0.8911 0.0000 +vt 0.3908 0.9002 0.0000 +vt 0.3908 0.9171 0.0000 +vt 0.5591 0.9171 0.0000 +vt 0.5591 0.9002 0.0000 +vt 0.6935 0.8698 0.0000 +vt 0.7024 0.8236 0.0000 +vt 0.7627 0.8394 0.0000 +vt 0.7620 0.8900 0.0000 +vt 0.8964 0.9891 0.0000 +vt 0.9012 0.9426 0.0000 +vt 0.7906 0.9872 0.0000 +vt 0.7900 0.9361 0.0000 +vt 0.8240 0.8246 0.0000 +vt 0.8310 0.8710 0.0000 +vt 0.8071 0.8858 0.0000 +vt 0.8403 0.8968 0.0000 +vt 0.7616 0.2643 0.0000 +vt 0.8091 0.2643 0.0000 +vt 0.8091 0.2168 0.0000 +vt 0.7616 0.2168 0.0000 +vt 0.4610 0.0664 0.0000 +vt 0.4159 0.0664 0.0000 +vt 0.4291 0.0051 0.0000 +vt 0.4700 0.0051 0.0000 +vt 0.5121 0.0630 0.0000 +vt 0.5104 0.0055 0.0000 +vt 0.4783 0.0055 0.0000 +vt 0.4765 0.0630 0.0000 +vt 0.4354 0.1270 0.0000 +vt 0.3819 0.1270 0.0000 +vt 0.4733 0.1197 0.0000 +vt 0.5153 0.1197 0.0000 +vt 0.1088 0.0839 0.0000 +vt 0.1088 0.0815 0.0000 +vt 0.1654 0.0805 0.0000 +vt 0.1654 0.0829 0.0000 +vt 0.1086 0.0727 0.0000 +vt 0.1652 0.0718 0.0000 +vt 0.9889 0.9266 0.0000 +vt 0.9971 0.9266 0.0000 +vt 0.9971 0.9742 0.0000 +vt 0.9889 0.9743 0.0000 +vt 0.9938 0.9809 0.0000 +vt 0.9658 0.9805 0.0000 +vt 0.9614 0.9740 0.0000 +vt 0.9614 0.9269 0.0000 +vt 0.9658 0.9203 0.0000 +vt 0.9938 0.9200 0.0000 +vt 0.9612 0.9824 0.0000 +vt 0.9570 0.9747 0.0000 +vt 0.9570 0.9261 0.0000 +vt 0.9612 0.9185 0.0000 +vt 0.9169 0.9742 0.0000 +vt 0.9169 0.9266 0.0000 +vt 0.9251 0.9266 0.0000 +vt 0.9251 0.9743 0.0000 +vt 0.9482 0.9805 0.0000 +vt 0.9202 0.9809 0.0000 +vt 0.9526 0.9740 0.0000 +vt 0.9526 0.9269 0.0000 +vt 0.9482 0.9203 0.0000 +vt 0.9202 0.9200 0.0000 +vt 0.9528 0.9824 0.0000 +vt 0.9528 0.9185 0.0000 +vt 0.9974 0.8603 0.0000 +vt 0.9974 0.9085 0.0000 +vt 0.9891 0.9085 0.0000 +vt 0.9891 0.8603 0.0000 +vt 0.9610 0.9085 0.0000 +vt 0.9611 0.8602 0.0000 +vt 0.9661 0.9151 0.0000 +vt 0.9941 0.9151 0.0000 +vt 0.9563 0.9083 0.0000 +vt 0.9563 0.8602 0.0000 +vt 0.9611 0.9169 0.0000 +vt 0.9563 0.9165 0.0000 +vt 0.9235 0.9085 0.0000 +vt 0.9152 0.9085 0.0000 +vt 0.9151 0.8603 0.0000 +vt 0.9234 0.8603 0.0000 +vt 0.9515 0.9085 0.0000 +vt 0.9514 0.8602 0.0000 +vt 0.9464 0.9151 0.0000 +vt 0.9184 0.9151 0.0000 +vt 0.9514 0.9169 0.0000 +vt 0.4631 0.5582 0.0000 +vt 0.4800 0.5614 0.0000 +vt 0.4793 0.5907 0.0000 +vt 0.4510 0.5875 0.0000 +vt 0.4489 0.5481 0.0000 +vt 0.4255 0.5698 0.0000 +vt 0.4399 0.5332 0.0000 +vt 0.4097 0.5428 0.0000 +vt 0.4381 0.5163 0.0000 +vt 0.4065 0.5108 0.0000 +vt 0.5197 0.5330 0.0000 +vt 0.5215 0.5160 0.0000 +vt 0.5531 0.5106 0.0000 +vt 0.5499 0.5426 0.0000 +vt 0.5108 0.5479 0.0000 +vt 0.5341 0.5695 0.0000 +vt 0.4968 0.5578 0.0000 +vt 0.5101 0.5840 0.0000 +vt 0.4797 0.5195 0.0000 +vt 0.4798 0.5195 0.0000 +vt 0.4798 0.6016 0.0000 +vt 0.4471 0.5975 0.0000 +vt 0.4176 0.5771 0.0000 +vt 0.3996 0.5464 0.0000 +vt 0.3950 0.5125 0.0000 +vt 0.5646 0.5123 0.0000 +vt 0.5600 0.5463 0.0000 +vt 0.5417 0.5769 0.0000 +vt 0.5143 0.5942 0.0000 +vt 0.6596 0.4838 0.0000 +vt 0.6986 0.4835 0.0000 +vt 0.6987 0.4996 0.0000 +vt 0.6597 0.4999 0.0000 +vt 0.6290 0.4840 0.0000 +vt 0.6291 0.5001 0.0000 +vt 0.5951 0.4842 0.0000 +vt 0.5952 0.5003 0.0000 +vt 0.5773 0.4843 0.0000 +vt 0.5774 0.5004 0.0000 +vt 0.6595 0.4677 0.0000 +vt 0.6985 0.4675 0.0000 +vt 0.6289 0.4679 0.0000 +vt 0.5950 0.4681 0.0000 +vt 0.5772 0.4683 0.0000 +vt 0.6594 0.4516 0.0000 +vt 0.6984 0.4514 0.0000 +vt 0.6288 0.4518 0.0000 +vt 0.5949 0.4520 0.0000 +vt 0.5771 0.4522 0.0000 +vt 0.6593 0.4356 0.0000 +vt 0.6983 0.4353 0.0000 +vt 0.6287 0.4357 0.0000 +vt 0.5948 0.4359 0.0000 +vt 0.5770 0.4361 0.0000 +vt 0.7533 0.2332 0.0000 +vt 0.7344 0.2341 0.0000 +vt 0.7338 0.2213 0.0000 +vt 0.7526 0.2204 0.0000 +vt 0.7242 0.0679 0.0000 +vt 0.7193 0.0023 0.0000 +vt 0.7081 0.0023 0.0000 +vt 0.7171 0.0679 0.0000 +vt 0.6996 0.0651 0.0000 +vt 0.6995 0.0019 0.0000 +vt 0.7062 0.0021 0.0000 +vt 0.7038 0.0652 0.0000 +vt 0.7083 0.1335 0.0000 +vt 0.7182 0.1335 0.0000 +vt 0.6996 0.1282 0.0000 +vt 0.6936 0.1280 0.0000 +vt 0.6258 0.5158 0.0000 +vt 0.6259 0.5055 0.0000 +vt 0.6675 0.5090 0.0000 +vt 0.6657 0.5191 0.0000 +vt 0.6254 0.5360 0.0000 +vt 0.6626 0.5388 0.0000 +vt 0.6246 0.5648 0.0000 +vt 0.6595 0.5672 0.0000 +vt 0.6237 0.5837 0.0000 +vt 0.6580 0.5860 0.0000 +vt 0.6232 0.5931 0.0000 +vt 0.6572 0.5954 0.0000 +vt 0.5757 0.5204 0.0000 +vt 0.5735 0.5114 0.0000 +vt 0.5783 0.5382 0.0000 +vt 0.5781 0.5653 0.0000 +vt 0.5757 0.5837 0.0000 +vt 0.5754 0.5931 0.0000 +vt 0.5225 0.4287 0.0000 +vt 0.5243 0.4192 0.0000 +vt 0.5715 0.4315 0.0000 +vt 0.5677 0.4395 0.0000 +vt 0.5189 0.4472 0.0000 +vt 0.5618 0.4553 0.0000 +vt 0.5148 0.4737 0.0000 +vt 0.5574 0.4802 0.0000 +vt 0.5128 0.4913 0.0000 +vt 0.5569 0.4974 0.0000 +vt 0.5118 0.5001 0.0000 +vt 0.5563 0.5061 0.0000 +vt 0.4825 0.4259 0.0000 +vt 0.4830 0.4164 0.0000 +vt 0.4813 0.4444 0.0000 +vt 0.4797 0.4710 0.0000 +vt 0.4786 0.4887 0.0000 +vt 0.4781 0.4974 0.0000 +vt 0.4423 0.4258 0.0000 +vt 0.4414 0.4164 0.0000 +vt 0.4439 0.4443 0.0000 +vt 0.4445 0.4711 0.0000 +vt 0.4441 0.4888 0.0000 +vt 0.4439 0.4975 0.0000 +vt 0.4023 0.4300 0.0000 +vt 0.3989 0.4212 0.0000 +vt 0.4076 0.4469 0.0000 +vt 0.4096 0.4719 0.0000 +vt 0.4094 0.4889 0.0000 +vt 0.4092 0.4976 0.0000 +vt 0.7092 0.5179 0.0000 +vt 0.7051 0.5270 0.0000 +vt 0.6984 0.5447 0.0000 +vt 0.6941 0.5714 0.0000 +vt 0.6924 0.5896 0.0000 +vt 0.6915 0.5989 0.0000 +vt 0.1069 0.0977 0.0000 +vt 0.1069 0.0953 0.0000 +vt 0.2136 0.0953 0.0000 +vt 0.2136 0.0977 0.0000 +vt 0.2145 0.1095 0.0000 +vt 0.2145 0.1119 0.0000 +vt 0.1078 0.1121 0.0000 +vt 0.1077 0.1097 0.0000 +vt 0.1069 0.0862 0.0000 +vt 0.2136 0.0862 0.0000 +vt 0.2144 0.1004 0.0000 +vt 0.1077 0.1007 0.0000 +vt 0.3056 0.3903 0.0000 +vt 0.3056 0.3114 0.0000 +vt 0.3162 0.3114 0.0000 +vt 0.3162 0.3903 0.0000 +vt 0.3056 0.2226 0.0000 +vt 0.3162 0.2226 0.0000 +vt 0.3162 0.4790 0.0000 +vt 0.3056 0.4790 0.0000 +vt 0.4444 0.1484 0.0000 +vt 0.4444 0.2592 0.0000 +vt 0.4324 0.2485 0.0000 +vt 0.4324 0.1484 0.0000 +vt 0.3337 0.2592 0.0000 +vt 0.3457 0.2485 0.0000 +vt 0.3337 0.1484 0.0000 +vt 0.3457 0.1484 0.0000 +vt 0.4664 0.1514 0.0000 +vt 0.4664 0.2622 0.0000 +vt 0.4509 0.2622 0.0000 +vt 0.4509 0.1514 0.0000 +vt 0.3528 0.1503 0.0000 +vt 0.4234 0.1503 0.0000 +vt 0.4234 0.2319 0.0000 +vt 0.3528 0.2319 0.0000 +vt 0.8774 0.7506 0.0000 +vt 0.9152 0.7151 0.0000 +vt 0.9157 0.7625 0.0000 +vt 0.8664 0.7883 0.0000 +vt 0.9124 0.7134 0.0000 +vt 0.8747 0.7491 0.0000 +vt 0.9680 0.7875 0.0000 +vt 0.9651 0.7879 0.0000 +vt 0.9535 0.7502 0.0000 +vt 0.9562 0.7487 0.0000 +vt 0.9157 0.8130 0.0000 +vt 0.9157 0.8098 0.0000 +vt 0.9526 0.8194 0.0000 +vt 0.9524 0.8226 0.0000 +vt 0.8634 0.7880 0.0000 +vt 0.8788 0.8197 0.0000 +vt 0.8757 0.8204 0.0000 +vt 0.9180 0.7134 0.0000 +vt 0.8791 0.8229 0.0000 +vt 0.9558 0.8200 0.0000 +vt 0.9673 0.1980 0.0000 +vt 0.9793 0.2576 0.0000 +vt 0.9947 0.2576 0.0000 +vt 0.9826 0.1980 0.0000 +vt 0.5207 0.1141 0.0000 +vt 0.5207 0.0595 0.0000 +vt 0.5433 0.0595 0.0000 +vt 0.5433 0.1141 0.0000 +vt 0.5433 0.0049 0.0000 +vt 0.5207 0.0049 0.0000 +vt 0.8891 0.2135 0.0000 +vt 0.8891 0.2610 0.0000 +vt 0.8303 0.2610 0.0000 +vt 0.8303 0.2135 0.0000 +vt 0.9673 0.3172 0.0000 +vt 0.9826 0.3172 0.0000 +vt 0.9082 0.6023 0.0000 +vt 0.9082 0.6496 0.0000 +vt 0.9043 0.6496 0.0000 +vt 0.9043 0.6023 0.0000 +vt 0.9136 0.6023 0.0000 +vt 0.9136 0.6496 0.0000 +vt 0.9174 0.6023 0.0000 +vt 0.9174 0.6496 0.0000 +vt 0.9335 0.6713 0.0000 +vt 0.9272 0.6930 0.0000 +vt 0.9135 0.6751 0.0000 +vt 0.9082 0.6526 0.0000 +vt 0.9043 0.6558 0.0000 +vt 0.9136 0.6526 0.0000 +vt 0.9174 0.6558 0.0000 +vt 0.9082 0.6596 0.0000 +vt 0.9041 0.6655 0.0000 +vt 0.9136 0.6596 0.0000 +vt 0.9173 0.6655 0.0000 +vt 0.5834 0.7132 0.0000 +vt 0.5834 0.6102 0.0000 +vt 0.6864 0.6102 0.0000 +vt 0.6864 0.7132 0.0000 +vt 0.0941 0.2745 0.0000 +vt 0.0152 0.2747 0.0000 +vt 0.0095 0.2691 0.0000 +vt 0.0998 0.2688 0.0000 +vt 0.0999 0.0105 0.0000 +vt 0.0096 0.0105 0.0000 +vt 0.1935 0.4614 0.0000 +vt 0.1158 0.4614 0.0000 +vt 0.1108 0.4564 0.0000 +vt 0.1985 0.4564 0.0000 +vt 0.1985 0.2278 0.0000 +vt 0.1108 0.2278 0.0000 +vt 0.2878 0.4646 0.0000 +vt 0.2157 0.4638 0.0000 +vt 0.2105 0.4586 0.0000 +vt 0.2931 0.4594 0.0000 +vt 0.2946 0.2231 0.0000 +vt 0.2121 0.2226 0.0000 +vt 0.0949 0.5244 0.0000 +vt 0.0151 0.5244 0.0000 +vt 0.0100 0.5192 0.0000 +vt 0.1001 0.5192 0.0000 +vt 0.1001 0.2840 0.0000 +vt 0.0100 0.2840 0.0000 +vt 0.9749 0.7086 0.0000 +vt 0.9729 0.7099 0.0000 +vt 0.8589 0.7099 0.0000 +vt 0.8569 0.7084 0.0000 +vt 0.8556 0.7010 0.0000 +vt 0.9762 0.7010 0.0000 +vt 0.9748 0.8312 0.0000 +vt 0.9729 0.8298 0.0000 +vt 0.9848 0.7089 0.0000 +vt 0.9848 0.8308 0.0000 +vt 0.8563 0.8313 0.0000 +vt 0.8589 0.8298 0.0000 +vt 0.9762 0.8387 0.0000 +vt 0.8556 0.8387 0.0000 +vt 0.8469 0.8308 0.0000 +vt 0.8469 0.7089 0.0000 +vt 0.6780 0.9586 0.0000 +vt 0.6780 0.9368 0.0000 +vt 0.4953 0.9368 0.0000 +vt 0.4953 0.9586 0.0000 +vt 0.9867 0.0995 0.0000 +vt 0.9867 0.1918 0.0000 +vt 0.9610 0.1918 0.0000 +vt 0.9562 0.0995 0.0000 +vt 0.9867 0.0071 0.0000 +vt 0.9610 0.0071 0.0000 +vt 0.5832 0.0338 0.0000 +vt 0.5731 0.0233 0.0000 +vt 0.5731 0.0692 0.0000 +vt 0.5832 0.0692 0.0000 +vt 0.5832 0.1046 0.0000 +vt 0.5731 0.1151 0.0000 +vt 0.6189 0.1151 0.0000 +vt 0.6189 0.1046 0.0000 +vt 0.6547 0.1046 0.0000 +vt 0.6648 0.1151 0.0000 +vt 0.6648 0.0692 0.0000 +vt 0.6547 0.0692 0.0000 +vt 0.6547 0.0338 0.0000 +vt 0.6648 0.0233 0.0000 +vt 0.6189 0.0233 0.0000 +vt 0.6189 0.0338 0.0000 +vt 0.5693 0.0201 0.0000 +vt 0.5553 0.0055 0.0000 +vt 0.6190 0.0055 0.0000 +vt 0.6190 0.0201 0.0000 +vt 0.6687 0.0201 0.0000 +vt 0.6828 0.0055 0.0000 +vt 0.6828 0.0693 0.0000 +vt 0.6687 0.0693 0.0000 +vt 0.6687 0.1185 0.0000 +vt 0.6828 0.1330 0.0000 +vt 0.6190 0.1330 0.0000 +vt 0.6190 0.1185 0.0000 +vt 0.5693 0.1185 0.0000 +vt 0.5553 0.1330 0.0000 +vt 0.5553 0.0693 0.0000 +vt 0.5693 0.0693 0.0000 +vt 0.4953 0.9908 0.0000 +vt 0.6780 0.9908 0.0000 +vt 0.2515 0.0074 0.0000 +vt 0.4019 0.0074 0.0000 +vt 0.4019 0.0321 0.0000 +vt 0.2515 0.0321 0.0000 +vt 0.0074 0.2768 0.0000 +vt 0.1019 0.2765 0.0000 +vt 0.2086 0.4657 0.0000 +vt 0.2949 0.4666 0.0000 +vt 0.8556 0.7009 0.0000 +vt 0.8569 0.7083 0.0000 +vt 0.8469 0.7088 0.0000 +vt 0.9848 0.7090 0.0000 +vt 0.9749 0.7087 0.0000 +vt 0.9761 0.7011 0.0000 +vt 0.9761 0.8386 0.0000 +vt 0.9748 0.8310 0.0000 +vt 0.9848 0.8307 0.0000 +vt 0.8469 0.8309 0.0000 +vt 0.8563 0.8314 0.0000 +vt 0.8556 0.8388 0.0000 +vt 0.4157 0.0073 0.0000 +vt 0.4157 0.0320 0.0000 +vt 0.2377 0.0073 0.0000 +vt 0.2377 0.0320 0.0000 +vt 0.9695 0.3196 0.0000 +vt 0.9833 0.3194 0.0000 +vt 0.9835 0.3421 0.0000 +vt 0.9697 0.3423 0.0000 +vt 0.9953 0.3194 0.0000 +vt 0.9955 0.3421 0.0000 +vt 0.4158 0.0492 0.0000 +vt 0.4020 0.0493 0.0000 +vt 0.2514 0.0493 0.0000 +vt 0.2376 0.0492 0.0000 +vt 0.9477 0.0973 0.0000 +vt 0.9477 0.0050 0.0000 +vt 0.9220 0.0050 0.0000 +vt 0.9173 0.0973 0.0000 +vt 0.9088 0.0951 0.0000 +vt 0.9088 0.0028 0.0000 +vt 0.8830 0.0028 0.0000 +vt 0.8783 0.0951 0.0000 +vt 0.8830 0.1875 0.0000 +vt 0.9088 0.1875 0.0000 +vt 0.9220 0.1896 0.0000 +vt 0.9477 0.1896 0.0000 +vt 0.8646 0.1042 0.0000 +vt 0.8487 0.1042 0.0000 +vt 0.8449 0.0032 0.0000 +vt 0.8736 0.0032 0.0000 +vt 0.8449 0.2052 0.0000 +vt 0.8736 0.2052 0.0000 +vt 0.7879 0.0971 0.0000 +vt 0.7980 0.0020 0.0000 +vt 0.7675 0.0020 0.0000 +vt 0.7707 0.0971 0.0000 +vt 0.7980 0.1922 0.0000 +vt 0.7675 0.2125 0.0000 +vt 0.7481 0.0989 0.0000 +vt 0.7574 0.0026 0.0000 +vt 0.7278 0.0026 0.0000 +vt 0.7317 0.0989 0.0000 +vt 0.7278 0.2157 0.0000 +vt 0.7574 0.2157 0.0000 +vt 0.8305 0.0992 0.0000 +vt 0.8132 0.0992 0.0000 +vt 0.8078 0.0042 0.0000 +vt 0.8384 0.0042 0.0000 +vt 0.8384 0.1942 0.0000 +vt 0.8078 0.2144 0.0000 +vt 0.1989 0.1865 0.0000 +vt 0.1989 0.1256 0.0000 +vt 0.1548 0.1256 0.0000 +vt 0.1548 0.2209 0.0000 +vt 0.7155 0.4921 0.0000 +vt 0.8089 0.4921 0.0000 +vt 0.8089 0.3683 0.0000 +vt 0.7155 0.3683 0.0000 +vt 0.1107 0.1865 0.0000 +vt 0.1107 0.1256 0.0000 +vt 0.1070 0.0309 0.0000 +vt 0.1070 0.0293 0.0000 +vt 0.2164 0.0298 0.0000 +vt 0.2164 0.0314 0.0000 +vt 0.1070 0.0235 0.0000 +vt 0.2165 0.0240 0.0000 +vt 0.5829 0.8473 0.0000 +vt 0.4785 0.8490 0.0000 +vt 0.4958 0.7292 0.0000 +vt 0.5339 0.7309 0.0000 +vt 0.7603 0.6599 0.0000 +vt 0.7603 0.6484 0.0000 +vt 0.6335 0.7712 0.0000 +vt 0.6335 0.7827 0.0000 +vt 0.5066 0.6599 0.0000 +vt 0.5066 0.6484 0.0000 +vt 0.4059 0.7256 0.0000 +vt 0.3820 0.8592 0.0000 +vt 0.5198 0.6276 0.0000 +vt 0.3962 0.6307 0.0000 +vt 0.3962 0.6182 0.0000 +vt 0.5198 0.6150 0.0000 +vt 0.7003 0.8135 0.0000 +vt 0.7060 0.7674 0.0000 +vt 0.7662 0.7798 0.0000 +vt 0.7681 0.8297 0.0000 +vt 0.8258 0.7622 0.0000 +vt 0.8343 0.8077 0.0000 +vt 0.7218 0.3550 0.0000 +vt 0.7654 0.3550 0.0000 +vt 0.7654 0.3114 0.0000 +vt 0.7218 0.3114 0.0000 +vt 0.9328 0.2260 0.0000 +vt 0.9566 0.2281 0.0000 +vt 0.9524 0.1954 0.0000 +vt 0.9308 0.1935 0.0000 +vt 0.9261 0.2345 0.0000 +vt 0.9251 0.1942 0.0000 +vt 0.9052 0.1942 0.0000 +vt 0.9041 0.2345 0.0000 +vt 0.9435 0.2588 0.0000 +vt 0.9717 0.2613 0.0000 +vt 0.9021 0.2743 0.0000 +vt 0.9281 0.2743 0.0000 +vt 0.2118 0.0436 0.0000 +vt 0.2118 0.0463 0.0000 +vt 0.1061 0.0468 0.0000 +vt 0.1060 0.0440 0.0000 +vt 0.2118 0.0334 0.0000 +vt 0.1060 0.0339 0.0000 +vt 0.1074 0.0204 0.0000 +vt 0.1074 0.0178 0.0000 +vt 0.2135 0.0178 0.0000 +vt 0.2135 0.0204 0.0000 +vt 0.1074 0.0081 0.0000 +vt 0.2135 0.0081 0.0000 +vt 0.8539 0.8870 0.0000 +vt 0.8785 0.8648 0.0000 +vt 0.8783 0.8952 0.0000 +vt 0.8464 0.9111 0.0000 +vt 0.8768 0.8636 0.0000 +vt 0.8522 0.8861 0.0000 +vt 0.9120 0.9113 0.0000 +vt 0.9101 0.9115 0.0000 +vt 0.9029 0.8873 0.0000 +vt 0.9046 0.8864 0.0000 +vt 0.8782 0.9276 0.0000 +vt 0.8782 0.9255 0.0000 +vt 0.9019 0.9317 0.0000 +vt 0.9017 0.9337 0.0000 +vt 0.8445 0.9109 0.0000 +vt 0.8543 0.9314 0.0000 +vt 0.8522 0.9318 0.0000 +vt 0.8803 0.8636 0.0000 +vt 0.8545 0.9334 0.0000 +vt 0.9040 0.9321 0.0000 +vt 17.5506 -12.4380 0.0000 +vt 18.4998 -11.9652 0.0000 +vt 19.1406 -12.0361 0.0000 +vt 17.5506 -12.9652 0.0000 +vt 20.2520 -12.9121 0.0000 +vt 19.9949 -11.2325 0.0000 +vt 19.4018 -11.2480 0.0000 +vt 19.4583 -12.9329 0.0000 +vt 18.3953 -11.6402 0.0000 +vt 18.9312 -11.6356 0.0000 +vt 18.7947 -9.8062 0.0000 +vt 18.3941 -9.8096 0.0000 +vt 0.8020 0.3054 0.0000 +vt 0.7651 0.3054 0.0000 +vt 0.7651 0.2802 0.0000 +vt 0.8020 0.2802 0.0000 +vt 0.6098 0.1948 0.0000 +vt 0.6195 0.1948 0.0000 +vt 0.6204 0.1386 0.0000 +vt 0.6079 0.1386 0.0000 +vt 0.6073 0.2476 0.0000 +vt 0.6211 0.2476 0.0000 +vt 0.6498 0.1976 0.0000 +vt 0.6595 0.1976 0.0000 +vt 0.6584 0.1393 0.0000 +vt 0.6457 0.1393 0.0000 +vt 0.6457 0.2525 0.0000 +vt 0.6584 0.2525 0.0000 +vt 0.6594 0.1976 0.0000 +vt 0.6497 0.1976 0.0000 +vt 0.6456 0.1393 0.0000 +vt 0.6583 0.1393 0.0000 +vt 0.6583 0.2525 0.0000 +vt 0.6456 0.2525 0.0000 +vt 0.8100 0.3534 0.0000 +vt 0.7732 0.3534 0.0000 +vt 0.7732 0.3159 0.0000 +vt 0.8100 0.3159 0.0000 +vt 0.5880 0.1906 0.0000 +vt 0.5942 0.1906 0.0000 +vt 0.6003 0.1394 0.0000 +vt 0.5925 0.1394 0.0000 +vt 0.5925 0.2451 0.0000 +vt 0.6003 0.2451 0.0000 +vt 0.6658 0.1976 0.0000 +vt 0.6754 0.1976 0.0000 +vt 0.6772 0.1393 0.0000 +vt 0.6645 0.1393 0.0000 +vt 0.6615 0.2598 0.0000 +vt 0.6742 0.2598 0.0000 +vt 0.6657 0.1976 0.0000 +vt 0.6644 0.1393 0.0000 +vt 0.6614 0.2598 0.0000 +vt 0.5376 0.2024 0.0000 +vt 0.5295 0.2030 0.0000 +vt 0.5169 0.1370 0.0000 +vt 0.5275 0.1362 0.0000 +vt 0.5326 0.2696 0.0000 +vt 0.5220 0.2704 0.0000 +vt 0.7032 0.2002 0.0000 +vt 0.7152 0.1997 0.0000 +vt 0.7202 0.1395 0.0000 +vt 0.7045 0.1401 0.0000 +vt 0.7085 0.2605 0.0000 +vt 0.7243 0.2599 0.0000 +vt 0.7152 0.1998 0.0000 +vt 0.7202 0.1396 0.0000 +vt 0.7243 0.2600 0.0000 +vt 0.7085 0.2606 0.0000 +vt 0.4828 0.1920 0.0000 +vt 0.4914 0.1920 0.0000 +vt 0.4856 0.1299 0.0000 +vt 0.4743 0.1298 0.0000 +vt 0.4700 0.2539 0.0000 +vt 0.4813 0.2540 0.0000 +vt 0.5126 0.1996 0.0000 +vt 0.4998 0.1992 0.0000 +vt 0.4939 0.1366 0.0000 +vt 0.5109 0.1372 0.0000 +vt 0.5065 0.2620 0.0000 +vt 0.4896 0.2615 0.0000 +vt 0.4914 0.1925 0.0000 +vt 0.4828 0.1924 0.0000 +vt 0.4742 0.1304 0.0000 +vt 0.4856 0.1305 0.0000 +vt 0.4813 0.2545 0.0000 +vt 0.4700 0.2545 0.0000 +vt 0.5126 0.1997 0.0000 +vt 0.4939 0.1367 0.0000 +vt 0.5065 0.2621 0.0000 +vt 0.8538 0.3510 0.0000 +vt 0.8169 0.3510 0.0000 +vt 0.8169 0.3091 0.0000 +vt 0.8538 0.3091 0.0000 +vt 0.5695 0.1957 0.0000 +vt 0.5780 0.1957 0.0000 +vt 0.5843 0.1365 0.0000 +vt 0.5731 0.1365 0.0000 +vt 0.5731 0.2630 0.0000 +vt 0.5843 0.2630 0.0000 +vt 0.6833 0.1976 0.0000 +vt 0.6930 0.1976 0.0000 +vt 0.6945 0.1393 0.0000 +vt 0.6818 0.1393 0.0000 +vt 0.6818 0.2640 0.0000 +vt 0.6945 0.2640 0.0000 +vt 0.6929 0.1976 0.0000 +vt 0.6817 0.1393 0.0000 +vt 0.6944 0.1393 0.0000 +vt 0.6944 0.2640 0.0000 +vt 0.6817 0.2640 0.0000 +vt 0.8112 0.3025 0.0000 +vt 0.8104 0.2685 0.0000 +vt 0.8495 0.2679 0.0000 +vt 0.8503 0.3018 0.0000 +vt 0.6334 0.2065 0.0000 +vt 0.6409 0.2065 0.0000 +vt 0.6363 0.1400 0.0000 +vt 0.6264 0.1400 0.0000 +vt 0.6264 0.2658 0.0000 +vt 0.6363 0.2658 0.0000 +vt 0.6458 0.1393 0.0000 +vt 0.6458 0.2525 0.0000 +vt 0.8599 0.3147 0.0000 +vt 0.8591 0.2734 0.0000 +vt 0.8876 0.2730 0.0000 +vt 0.8884 0.3143 0.0000 +vt 0.5505 0.2039 0.0000 +vt 0.5603 0.2039 0.0000 +vt 0.5620 0.1345 0.0000 +vt 0.5490 0.1345 0.0000 +vt 0.5444 0.2732 0.0000 +vt 0.5665 0.2732 0.0000 +vt 0.6499 0.1976 0.0000 +vt 0.6585 0.1393 0.0000 +vt 0.9218 0.6342 0.0000 +vt 0.9286 0.6561 0.0000 +vt 0.9576 0.6342 0.0000 +vt 0.4434 0.7103 0.0000 +vt 0.4434 0.7035 0.0000 +vt 0.4750 0.7035 0.0000 +vt 0.4750 0.7103 0.0000 +vt 0.1709 0.7103 0.0000 +vt 0.1709 0.7035 0.0000 +vt 0.2008 0.7035 0.0000 +vt 0.2008 0.7103 0.0000 +vt 0.2299 0.7035 0.0000 +vt 0.2299 0.7103 0.0000 +vt 0.2598 0.7035 0.0000 +vt 0.2598 0.7103 0.0000 +vt 0.2914 0.7035 0.0000 +vt 0.2914 0.7103 0.0000 +vt 0.3230 0.7035 0.0000 +vt 0.3230 0.7103 0.0000 +vt 0.3529 0.7035 0.0000 +vt 0.3529 0.7103 0.0000 +vt 0.3819 0.7035 0.0000 +vt 0.3819 0.7103 0.0000 +vt 0.4119 0.7035 0.0000 +vt 0.4119 0.7103 0.0000 +vt 0.9866 0.6124 0.0000 +vt 0.9934 0.6342 0.0000 +vt 0.9866 0.6561 0.0000 +vt 0.9687 0.6696 0.0000 +vt 0.9286 0.6124 0.0000 +vt 0.9687 0.5989 0.0000 +vt 0.9465 0.6696 0.0000 +vt 0.9465 0.5989 0.0000 +vt 0.8958 0.6005 0.0000 +vt 0.8832 0.6005 0.0000 +vt 0.8832 0.6195 0.0000 +vt 0.8958 0.6195 0.0000 +vt 0.8796 0.4709 0.0000 +vt 0.8714 0.4709 0.0000 +vt 0.8714 0.5890 0.0000 +vt 0.8796 0.5890 0.0000 +vt 0.8836 0.4716 0.0000 +vt 0.8950 0.4716 0.0000 +vt 0.8950 0.5947 0.0000 +vt 0.8836 0.5947 0.0000 +vt 0.9506 0.4767 0.0000 +vt 0.9378 0.4727 0.0000 +vt 0.9267 0.4894 0.0000 +vt 0.9467 0.4944 0.0000 +vt 0.9598 0.4779 0.0000 +vt 0.9572 0.4957 0.0000 +vt 0.9742 0.4789 0.0000 +vt 0.9778 0.4971 0.0000 +vt 0.9810 0.4776 0.0000 +vt 0.9884 0.4959 0.0000 +vt 0.9501 0.3524 0.0000 +vt 0.9360 0.3511 0.0000 +vt 0.9285 0.3709 0.0000 +vt 0.9509 0.3719 0.0000 +vt 0.9590 0.3514 0.0000 +vt 0.9623 0.3707 0.0000 +vt 0.9674 0.3502 0.0000 +vt 0.9737 0.3692 0.0000 +vt 0.9744 0.3479 0.0000 +vt 0.9848 0.3662 0.0000 +vt 0.9210 0.5089 0.0000 +vt 0.9255 0.5375 0.0000 +vt 0.9443 0.5347 0.0000 +vt 0.9443 0.5102 0.0000 +vt 0.9532 0.5351 0.0000 +vt 0.9553 0.5111 0.0000 +vt 0.9715 0.5382 0.0000 +vt 0.9781 0.5139 0.0000 +vt 0.9802 0.5424 0.0000 +vt 0.9900 0.5156 0.0000 +vt 0.9267 0.3919 0.0000 +vt 0.9356 0.4208 0.0000 +vt 0.9554 0.4150 0.0000 +vt 0.9520 0.3890 0.0000 +vt 0.9653 0.4142 0.0000 +vt 0.9643 0.3879 0.0000 +vt 0.9754 0.4143 0.0000 +vt 0.9768 0.3871 0.0000 +vt 0.9858 0.4163 0.0000 +vt 0.9899 0.3864 0.0000 +vt 0.9332 0.5471 0.0000 +vt 0.9455 0.5444 0.0000 +vt 0.9529 0.5446 0.0000 +vt 0.9658 0.5468 0.0000 +vt 0.9714 0.5502 0.0000 +vt 0.9446 0.4298 0.0000 +vt 0.9572 0.4254 0.0000 +vt 0.9649 0.4248 0.0000 +vt 0.9724 0.4249 0.0000 +vt 0.9792 0.4268 0.0000 +vt 0.9375 0.5535 0.0000 +vt 0.9465 0.5523 0.0000 +vt 0.9523 0.5525 0.0000 +vt 0.9618 0.5539 0.0000 +vt 0.9662 0.5554 0.0000 +vt 0.9497 0.4362 0.0000 +vt 0.9590 0.4338 0.0000 +vt 0.9648 0.4332 0.0000 +vt 0.9704 0.4331 0.0000 +vt 0.9753 0.4336 0.0000 +vt 0.9371 0.5550 0.0000 +vt 0.9463 0.5550 0.0000 +vt 0.9522 0.5551 0.0000 +vt 0.9617 0.5565 0.0000 +vt 0.9663 0.5566 0.0000 +vt 0.9497 0.4381 0.0000 +vt 0.9592 0.4368 0.0000 +vt 0.9651 0.4360 0.0000 +vt 0.9707 0.4357 0.0000 +vt 0.9756 0.4351 0.0000 +vt 0.9328 0.5621 0.0000 +vt 0.9455 0.5618 0.0000 +vt 0.9513 0.5618 0.0000 +vt 0.9635 0.5637 0.0000 +vt 0.9699 0.5637 0.0000 +vt 0.9464 0.4463 0.0000 +vt 0.9601 0.4443 0.0000 +vt 0.9665 0.4434 0.0000 +vt 0.9732 0.4431 0.0000 +vt 0.9801 0.4421 0.0000 +vt 0.9336 0.5747 0.0000 +vt 0.9455 0.5712 0.0000 +vt 0.9507 0.5709 0.0000 +vt 0.9625 0.5735 0.0000 +vt 0.9682 0.5760 0.0000 +vt 0.9488 0.4591 0.0000 +vt 0.9615 0.4542 0.0000 +vt 0.9677 0.4536 0.0000 +vt 0.9741 0.4538 0.0000 +vt 0.9809 0.4549 0.0000 +vt 0.9407 0.5825 0.0000 +vt 0.9470 0.5785 0.0000 +vt 0.9509 0.5781 0.0000 +vt 0.9582 0.5803 0.0000 +vt 0.9609 0.5830 0.0000 +vt 0.9565 0.4665 0.0000 +vt 0.9633 0.4620 0.0000 +vt 0.9676 0.4616 0.0000 +vt 0.9719 0.4622 0.0000 +vt 0.9756 0.4641 0.0000 +vt 0.9509 0.5867 0.0000 +vt 0.9668 0.4710 0.0000 +vt 0.9343 0.4652 0.0000 +vt 0.9352 0.4618 0.0000 +vt 0.9158 0.4614 0.0000 +vt 0.9150 0.4649 0.0000 +vt 0.9353 0.4583 0.0000 +vt 0.9158 0.4579 0.0000 +vt 0.9345 0.4549 0.0000 +vt 0.9153 0.4544 0.0000 +vt 0.8888 0.4581 0.0000 +vt 0.8880 0.4615 0.0000 +vt 0.8886 0.4546 0.0000 +vt 0.8884 0.4511 0.0000 +vt 0.8855 0.4593 0.0000 +vt 0.8853 0.4536 0.0000 +vt 0.8833 0.4566 0.0000 +vt 0.9201 0.5346 0.0000 +vt 0.9201 0.5950 0.0000 +vt 0.9054 0.5950 0.0000 +vt 0.9054 0.5346 0.0000 +vt 0.9061 0.4693 0.0000 +vt 0.9061 0.5278 0.0000 +vt 0.9167 0.5278 0.0000 +vt 0.9167 0.4693 0.0000 +vt 0.4954 0.3295 0.0000 +vt 0.4954 0.3372 0.0000 +vt 0.4998 0.3372 0.0000 +vt 0.4998 0.3295 0.0000 +vt 0.4905 0.3389 0.0000 +vt 0.4905 0.3465 0.0000 +vt 0.5029 0.3466 0.0000 +vt 0.5030 0.3390 0.0000 +vt 0.5409 0.3573 0.0000 +vt 0.5409 0.3495 0.0000 +vt 0.5218 0.3495 0.0000 +vt 0.5218 0.3573 0.0000 +vt 0.5278 0.3857 0.0000 +vt 0.5277 0.3906 0.0000 +vt 0.5086 0.3911 0.0000 +vt 0.5088 0.3863 0.0000 +vt 0.4148 0.3557 0.0000 +vt 0.5182 0.3573 0.0000 +vt 0.5182 0.3495 0.0000 +vt 0.4148 0.3511 0.0000 +vt 0.4012 0.3904 0.0000 +vt 0.5052 0.3864 0.0000 +vt 0.5050 0.3912 0.0000 +vt 0.4011 0.3932 0.0000 +vt 0.5151 0.2984 0.0000 +vt 0.5151 0.3464 0.0000 +vt 0.5066 0.3464 0.0000 +vt 0.5066 0.2984 0.0000 +vt 0.5182 0.3817 0.0000 +vt 0.5218 0.3817 0.0000 +vt 0.5218 0.3250 0.0000 +vt 0.5182 0.3250 0.0000 +vt 0.2714 0.0585 0.0000 +vt 0.2715 0.0626 0.0000 +vt 0.2256 0.0626 0.0000 +vt 0.2257 0.0585 0.0000 +vt 0.3377 0.0529 0.0000 +vt 0.3377 0.0578 0.0000 +vt 0.2942 0.0578 0.0000 +vt 0.2942 0.0529 0.0000 +vt 0.3393 0.1174 0.0000 +vt 0.3336 0.1174 0.0000 +vt 0.3336 0.1244 0.0000 +vt 0.3393 0.1244 0.0000 +vt 0.2940 0.0529 0.0000 +vt 0.2941 0.0578 0.0000 +vt 0.3378 0.0578 0.0000 +vt 0.3379 0.0529 0.0000 +vt 0.2837 0.1158 0.0000 +vt 0.2837 0.1205 0.0000 +vt 0.2759 0.1205 0.0000 +vt 0.2759 0.1158 0.0000 +vt 0.2174 0.1205 0.0000 +vt 0.2174 0.1158 0.0000 +vt 0.2252 0.1158 0.0000 +vt 0.2252 0.1205 0.0000 +vt 0.3444 0.0529 0.0000 +vt 0.3444 0.0578 0.0000 +vt 0.2875 0.0578 0.0000 +vt 0.2875 0.0529 0.0000 +vt 0.3058 0.1905 0.0000 +vt 0.3116 0.1905 0.0000 +vt 0.3377 0.1040 0.0000 +vt 0.3444 0.1041 0.0000 +vt 0.3336 0.1243 0.0000 +vt 0.3116 0.1906 0.0000 +vt 0.3444 0.1040 0.0000 +vt 0.3377 0.1041 0.0000 +vt 0.2942 0.1042 0.0000 +vt 0.2875 0.1042 0.0000 +vt 0.3058 0.1906 0.0000 +vt 0.3116 0.1907 0.0000 +vt 0.2874 0.0578 0.0000 +vt 0.2875 0.1041 0.0000 +vt 0.2942 0.1041 0.0000 +vt 0.3058 0.1997 0.0000 +vt 0.3116 0.1997 0.0000 +vt 0.3444 0.1105 0.0000 +vt 0.3377 0.1105 0.0000 +vt 0.2942 0.1105 0.0000 +vt 0.2875 0.1105 0.0000 +vt 0.2689 0.1124 0.0000 +vt 0.2798 0.1124 0.0000 +vt 0.2798 0.1020 0.0000 +vt 0.2689 0.1020 0.0000 +vt 0.2252 0.1417 0.0000 +vt 0.2174 0.1417 0.0000 +vt 0.2797 0.1906 0.0000 +vt 0.2797 0.1997 0.0000 +vt 0.2837 0.1417 0.0000 +vt 0.2759 0.1417 0.0000 +vt 0.2797 0.1905 0.0000 +vt 0.2877 0.1174 0.0000 +vt 0.2877 0.1244 0.0000 +vt 0.2877 0.1175 0.0000 +vt 0.2877 0.1243 0.0000 +vt 0.2255 0.0955 0.0000 +vt 0.2185 0.0955 0.0000 +vt 0.2186 0.0626 0.0000 +vt 0.2786 0.0955 0.0000 +vt 0.2715 0.0955 0.0000 +vt 0.2785 0.0626 0.0000 +# 1115 texture coords + +o barracks +g barracks +f 1/1/1 2/2/2 3/3/3 +f 3/3/3 4/4/4 1/1/1 +f 5/5/5 6/6/5 7/7/5 +f 7/7/5 8/8/5 5/5/5 +f 9/9/6 10/10/6 2/11/6 +f 2/11/6 1/12/6 9/9/6 +f 5/13/7 4/4/4 3/3/3 +f 3/3/3 6/14/2 5/13/7 +f 11/15/8 12/16/8 8/17/8 +f 8/17/8 7/18/8 11/15/8 +f 13/19/9 14/20/10 15/21/11 +f 15/21/11 16/22/12 13/19/9 +f 17/23/13 18/24/13 19/25/13 +f 19/25/13 20/26/13 17/23/13 +f 21/27/14 22/28/14 23/29/15 +f 23/29/15 24/30/15 21/27/14 +f 25/26/16 26/31/16 27/32/16 +f 27/32/16 28/23/16 25/26/16 +f 29/33/17 30/34/17 31/35/18 +f 31/35/18 32/36/18 29/33/17 +f 33/37/2 34/38/2 35/39/2 +f 36/40/2 21/41/2 24/42/2 +f 24/42/2 37/43/2 36/40/2 +f 38/44/2 39/45/2 40/46/2 +f 40/46/2 39/45/2 41/47/2 +f 41/47/2 42/48/2 40/46/2 +f 13/19/9 16/22/12 43/49/19 +f 43/49/19 44/50/20 13/19/9 +f 24/30/15 23/29/15 45/51/21 +f 45/51/21 46/52/21 24/30/15 +f 32/36/18 31/35/18 47/53/22 +f 47/53/22 48/54/22 32/36/18 +f 37/43/2 24/42/2 46/55/2 +f 46/55/2 49/56/2 37/43/2 +f 35/39/2 42/48/2 41/47/2 +f 41/47/2 33/37/2 35/39/2 +f 15/57/16 14/58/16 50/59/16 +f 50/59/16 36/60/16 15/57/16 +f 15/57/23 36/60/23 37/61/23 +f 37/61/23 16/62/23 15/57/23 +f 16/62/24 37/61/24 49/63/24 +f 49/63/24 43/64/24 16/62/24 +f 43/64/13 49/63/13 51/65/13 +f 51/65/13 44/66/13 43/64/13 +f 44/67/25 51/68/25 52/69/25 +f 52/69/26 13/70/26 44/67/26 +f 13/70/27 52/69/27 50/71/27 +f 50/71/28 14/72/28 13/70/28 +f 53/73/29 51/74/29 49/56/29 +f 49/56/30 46/55/30 53/73/30 +f 45/51/16 54/75/16 53/76/16 +f 53/76/16 46/52/16 45/51/16 +f 55/77/13 56/78/13 22/28/13 +f 22/28/13 21/27/13 55/77/13 +f 36/40/31 50/79/31 55/80/31 +f 55/80/32 21/41/32 36/40/32 +f 57/32/13 17/23/13 20/26/13 +f 20/26/13 58/31/13 57/32/13 +f 34/81/33 55/82/33 50/71/33 +f 50/71/33 35/83/33 34/81/33 +f 35/83/28 50/71/28 52/69/28 +f 52/69/34 42/84/34 35/83/34 +f 42/84/25 52/69/25 51/68/25 +f 51/68/25 40/85/25 42/84/25 +f 40/85/35 51/68/35 53/86/35 +f 53/86/35 38/87/35 40/85/35 +f 59/25/16 25/26/16 28/23/16 +f 28/23/16 60/24/16 59/25/16 +f 39/88/17 29/33/17 32/36/17 +f 32/36/17 41/89/17 39/88/17 +f 41/89/22 32/36/22 48/54/22 +f 48/54/22 33/90/22 41/89/22 +f 19/91/36 56/92/36 55/82/36 +f 55/82/36 20/93/36 19/91/36 +f 20/93/36 55/82/36 34/81/36 +f 34/81/36 58/94/36 20/93/36 +f 58/95/2 34/38/2 33/37/2 +f 33/37/2 57/96/2 58/95/2 +f 57/97/18 33/90/18 48/54/18 +f 48/54/18 17/98/18 57/97/18 +f 17/98/18 48/54/18 47/53/18 +f 47/53/18 18/99/18 17/98/18 +f 27/100/18 30/34/18 29/33/18 +f 29/33/18 28/101/18 27/100/18 +f 28/101/18 29/33/18 39/88/18 +f 39/88/18 60/102/18 28/101/18 +f 60/103/2 39/45/2 38/44/2 +f 38/44/2 59/104/2 60/103/2 +f 59/105/36 38/87/36 53/86/36 +f 53/86/36 25/106/36 59/105/36 +f 25/106/36 53/86/36 54/107/36 +f 54/107/36 26/108/36 25/106/36 +f 61/109/15 62/110/15 63/111/15 +f 63/111/15 64/112/15 61/109/15 +f 62/110/13 65/113/13 66/114/13 +f 66/114/13 63/111/13 62/110/13 +f 67/115/37 68/116/37 69/117/15 +f 69/117/15 70/118/15 67/115/37 +f 68/116/2 71/119/2 72/120/2 +f 72/120/2 69/117/2 68/116/2 +f 73/121/38 74/122/39 75/123/40 +f 75/123/40 76/124/41 73/121/38 +f 76/125/41 77/126/42 78/127/43 +f 78/127/43 79/128/44 76/125/41 +f 75/129/16 74/130/16 80/131/16 +f 80/131/6 81/132/6 75/129/6 +f 82/133/45 83/134/45 84/135/45 +f 84/135/46 85/136/46 82/133/46 +f 86/137/47 85/136/47 84/135/47 +f 84/135/47 87/138/47 86/137/47 +f 88/137/8 89/138/8 90/135/8 +f 90/135/8 91/136/8 88/137/8 +f 81/139/48 80/140/48 92/141/48 +f 92/141/49 93/142/49 81/139/49 +f 77/143/42 94/144/50 82/145/51 +f 82/145/51 85/146/52 77/143/42 +f 76/124/41 75/123/40 94/144/50 +f 94/144/50 77/143/42 76/124/41 +f 95/147/53 74/122/39 73/121/38 +f 73/121/38 91/148/54 95/147/53 +f 73/149/38 96/150/55 88/151/56 +f 88/151/56 91/152/54 73/149/38 +f 73/149/38 76/125/41 79/128/44 +f 79/128/44 96/150/55 73/149/38 +f 86/153/57 78/127/43 77/126/42 +f 77/126/42 85/154/52 86/153/57 +f 82/155/6 94/156/6 97/157/6 +f 97/157/6 83/158/6 82/155/6 +f 94/156/6 75/129/6 81/132/6 +f 81/132/6 97/157/6 94/156/6 +f 98/159/16 80/131/16 74/130/16 +f 74/130/16 95/160/16 98/159/16 +f 96/161/13 99/162/13 89/163/13 +f 89/163/13 88/164/13 96/161/13 +f 100/165/13 78/166/13 86/167/13 +f 86/167/13 87/168/13 100/165/13 +f 83/169/58 97/170/58 101/171/58 +f 101/171/59 84/172/59 83/169/59 +f 97/173/60 81/139/60 93/142/60 +f 93/142/61 101/174/61 97/173/61 +f 92/141/48 80/140/48 98/175/48 +f 98/175/62 90/176/62 92/141/62 +f 101/171/63 100/177/63 87/178/63 +f 87/178/64 84/172/64 101/171/64 +f 89/179/63 99/180/63 92/141/63 +f 92/141/65 90/176/65 89/179/65 +f 102/181/2 103/182/2 104/183/2 +f 104/183/2 105/184/2 102/181/2 +f 106/185/66 107/186/67 108/187/68 +f 108/187/68 109/188/68 106/185/66 +f 106/189/69 109/190/70 110/191/70 +f 110/191/70 111/192/69 106/189/69 +f 111/185/71 110/188/72 112/187/72 +f 112/187/72 113/186/73 111/185/71 +f 113/192/74 112/191/75 108/190/75 +f 108/190/75 107/189/74 113/192/74 +f 107/186/67 106/185/66 104/193/76 +f 104/193/76 103/194/76 107/186/67 +f 106/189/69 111/192/69 105/195/77 +f 105/195/77 104/196/77 106/189/69 +f 105/193/78 111/185/71 113/186/73 +f 113/186/73 102/194/78 105/193/78 +f 113/192/74 107/189/74 103/196/79 +f 103/196/79 102/195/79 113/192/74 +f 114/197/15 115/198/15 116/199/15 +f 116/199/15 117/200/15 114/197/15 +f 115/198/80 118/201/80 119/202/80 +f 119/202/80 116/199/80 115/198/80 +f 120/203/13 121/204/13 122/205/13 +f 122/205/13 123/206/13 120/203/13 +f 123/206/81 122/207/81 124/208/81 +f 124/208/82 125/209/82 123/206/82 +f 126/210/83 120/203/83 123/206/83 +f 123/206/83 125/209/83 126/210/83 +f 127/211/84 121/212/84 120/203/84 +f 120/203/85 126/210/85 127/211/85 +f 125/209/86 124/208/86 128/213/86 +f 128/213/87 129/214/87 125/209/87 +f 129/214/88 130/215/88 126/210/88 +f 126/210/88 125/209/88 129/214/88 +f 126/210/85 130/215/85 131/216/85 +f 131/216/89 127/211/89 126/210/89 +f 132/217/16 133/218/16 134/219/16 +f 134/219/16 135/220/16 132/217/16 +f 136/221/90 132/222/90 135/220/90 +f 135/220/86 137/223/86 136/221/86 +f 138/224/91 137/223/91 135/220/91 +f 135/220/91 134/219/91 138/224/91 +f 139/225/85 138/224/85 134/219/85 +f 134/219/85 133/226/85 139/225/85 +f 128/227/82 136/221/82 137/223/82 +f 137/223/92 129/214/92 128/227/92 +f 138/224/93 130/215/93 129/214/93 +f 129/214/93 137/223/93 138/224/93 +f 138/224/94 139/225/94 131/228/94 +f 131/228/95 130/215/95 138/224/95 +f 140/229/13 141/230/13 142/231/13 +f 142/231/13 143/232/13 140/229/13 +f 144/233/83 145/234/83 143/232/83 +f 143/232/83 142/231/83 144/233/83 +f 146/235/96 144/233/96 142/231/96 +f 142/231/96 141/236/96 146/235/96 +f 144/233/97 147/237/97 148/238/97 +f 148/238/97 145/234/97 144/233/97 +f 144/233/98 146/239/98 149/240/98 +f 149/240/99 147/237/99 144/233/99 +f 150/241/16 151/242/16 152/243/16 +f 152/243/16 153/244/16 150/241/16 +f 154/245/91 150/241/91 153/244/91 +f 153/244/91 155/246/91 154/245/91 +f 156/247/90 151/248/90 150/241/90 +f 150/241/96 154/245/96 156/247/96 +f 148/238/100 147/237/100 154/245/100 +f 154/245/100 155/246/100 148/238/100 +f 154/245/101 147/237/101 149/240/101 +f 149/240/96 156/249/96 154/245/96 +f 157/229/13 158/230/13 159/231/13 +f 159/231/13 160/232/13 157/229/13 +f 161/233/102 162/234/102 160/232/102 +f 160/232/103 159/231/103 161/233/103 +f 163/235/104 161/233/104 159/231/104 +f 159/231/105 158/236/105 163/235/105 +f 161/233/106 164/237/106 165/238/106 +f 165/238/106 162/234/106 161/233/106 +f 161/233/107 163/239/107 166/240/107 +f 166/240/108 164/237/108 161/233/108 +f 167/241/16 168/242/16 169/243/16 +f 169/243/6 170/244/6 167/241/6 +f 171/245/109 167/241/109 170/244/109 +f 170/244/110 172/246/110 171/245/110 +f 173/247/108 168/248/108 167/241/108 +f 167/241/111 171/245/111 173/247/111 +f 165/238/112 164/237/112 171/245/112 +f 171/245/112 172/246/112 165/238/112 +f 171/245/105 164/237/105 166/240/105 +f 166/240/113 173/249/113 171/245/113 +f 174/229/13 175/230/13 176/231/13 +f 176/231/13 177/232/13 174/229/13 +f 178/233/114 179/234/114 177/232/114 +f 177/232/114 176/231/114 178/233/114 +f 180/235/115 178/233/115 176/231/115 +f 176/231/115 175/236/115 180/235/115 +f 178/233/116 181/237/116 182/238/116 +f 182/238/117 179/234/117 178/233/117 +f 178/233/115 180/239/115 183/240/115 +f 183/240/118 181/237/118 178/233/118 +f 184/241/16 185/242/16 186/243/16 +f 186/243/16 187/244/16 184/241/16 +f 188/245/119 184/241/119 187/244/119 +f 187/244/119 189/246/119 188/245/119 +f 190/247/118 185/248/118 184/241/118 +f 184/241/118 188/245/118 190/247/118 +f 182/238/120 181/237/120 188/245/120 +f 188/245/121 189/246/121 182/238/121 +f 188/245/115 181/237/115 183/240/115 +f 183/240/118 190/249/118 188/245/118 +f 191/229/13 192/230/13 193/231/13 +f 193/231/13 194/232/13 191/229/13 +f 195/233/114 196/234/114 194/232/114 +f 194/232/114 193/231/114 195/233/114 +f 197/235/118 195/233/118 193/231/118 +f 193/231/118 192/236/118 197/235/118 +f 195/233/117 198/237/117 199/238/117 +f 199/238/117 196/234/117 195/233/117 +f 195/233/122 197/239/122 200/240/122 +f 200/240/115 198/237/115 195/233/115 +f 201/241/16 202/242/16 203/243/16 +f 203/243/16 204/244/16 201/241/16 +f 205/245/119 201/241/119 204/244/119 +f 204/244/123 206/246/123 205/245/123 +f 207/247/115 202/248/115 201/241/115 +f 201/241/115 205/245/115 207/247/115 +f 199/238/121 198/237/121 205/245/121 +f 205/245/121 206/246/121 199/238/121 +f 205/245/118 198/237/118 200/240/118 +f 200/240/124 207/249/124 205/245/124 +f 208/229/13 209/230/13 210/231/13 +f 210/231/13 211/232/13 208/229/13 +f 212/233/114 213/234/114 211/232/114 +f 211/232/114 210/231/114 212/233/114 +f 214/235/115 212/233/115 210/231/115 +f 210/231/115 209/236/115 214/235/115 +f 212/233/116 215/237/116 216/238/116 +f 216/238/117 213/234/117 212/233/117 +f 212/233/115 214/239/115 217/240/115 +f 217/240/115 215/237/115 212/233/115 +f 218/241/6 219/242/6 220/243/6 +f 220/243/6 221/244/6 218/241/6 +f 222/245/119 218/241/119 221/244/119 +f 221/244/119 223/246/119 222/245/119 +f 224/247/118 219/248/118 218/241/118 +f 218/241/118 222/245/118 224/247/118 +f 216/238/120 215/237/120 222/245/120 +f 222/245/121 223/246/121 216/238/121 +f 222/245/118 215/237/118 217/240/118 +f 217/240/118 224/249/118 222/245/118 +f 225/229/13 226/230/13 227/231/13 +f 227/231/13 228/232/13 225/229/13 +f 229/233/125 230/234/125 228/232/125 +f 228/232/125 227/231/125 229/233/125 +f 231/235/126 229/233/126 227/231/126 +f 227/231/126 226/236/126 231/235/126 +f 229/233/127 232/237/127 233/238/127 +f 233/238/128 230/234/128 229/233/128 +f 229/233/129 231/239/129 234/240/129 +f 234/240/129 232/237/129 229/233/129 +f 235/241/16 236/242/16 237/243/16 +f 237/243/16 238/244/16 235/241/16 +f 239/245/130 235/241/130 238/244/130 +f 238/244/130 240/246/130 239/245/130 +f 241/247/129 236/248/129 235/241/129 +f 235/241/129 239/245/129 241/247/129 +f 233/238/131 232/237/131 239/245/131 +f 239/245/132 240/246/132 233/238/132 +f 239/245/126 232/237/126 234/240/126 +f 234/240/126 241/249/126 239/245/126 +f 242/205/13 243/204/13 244/203/13 +f 244/203/5 245/206/5 242/205/5 +f 245/206/133 246/209/133 247/208/133 +f 247/208/134 242/207/134 245/206/134 +f 245/206/135 244/203/135 248/210/135 +f 248/210/135 246/209/135 245/206/135 +f 244/203/136 243/212/136 249/211/136 +f 249/211/137 248/210/137 244/203/137 +f 250/213/138 247/208/138 246/209/138 +f 246/209/139 251/214/139 250/213/139 +f 248/210/140 252/215/140 251/214/140 +f 251/214/140 246/209/140 248/210/140 +f 248/210/141 249/211/141 253/216/141 +f 253/216/136 252/215/136 248/210/136 +f 254/219/142 255/218/142 256/217/142 +f 256/217/6 257/220/6 254/219/6 +f 258/221/143 259/223/143 257/220/143 +f 257/220/144 256/222/144 258/221/144 +f 257/220/145 259/223/145 260/224/145 +f 260/224/145 254/219/145 257/220/145 +f 254/219/136 260/224/136 261/225/136 +f 261/225/136 255/226/136 254/219/136 +f 259/223/146 258/221/146 250/227/146 +f 250/227/147 251/214/147 259/223/147 +f 251/214/148 252/215/148 260/224/148 +f 260/224/148 259/223/148 251/214/148 +f 260/224/137 252/215/137 253/228/137 +f 253/228/149 261/225/149 260/224/149 +f 262/231/13 263/230/13 264/229/13 +f 264/229/13 265/232/13 262/231/13 +f 265/232/150 266/234/150 267/233/150 +f 267/233/150 262/231/150 265/232/150 +f 262/231/151 267/233/151 268/235/151 +f 268/235/151 263/236/151 262/231/151 +f 269/238/152 270/237/152 267/233/152 +f 267/233/153 266/234/153 269/238/153 +f 267/233/154 270/237/154 271/240/154 +f 271/240/155 268/239/155 267/233/155 +f 272/243/16 273/242/16 274/241/16 +f 274/241/16 275/244/16 272/243/16 +f 275/244/156 274/241/156 276/245/156 +f 276/245/156 277/246/156 275/244/156 +f 274/241/155 273/248/155 278/247/155 +f 278/247/155 276/245/155 274/241/155 +f 276/245/157 270/237/157 269/238/157 +f 269/238/158 277/246/158 276/245/158 +f 276/245/151 278/249/151 271/240/151 +f 271/240/159 270/237/159 276/245/159 +f 279/231/13 280/230/13 281/229/13 +f 281/229/13 282/232/13 279/231/13 +f 282/232/160 283/234/160 284/233/160 +f 284/233/160 279/231/160 282/232/160 +f 279/231/161 284/233/161 285/235/161 +f 285/235/161 280/236/161 279/231/161 +f 286/238/162 287/237/162 284/233/162 +f 284/233/162 283/234/162 286/238/162 +f 284/233/163 287/237/163 288/240/163 +f 288/240/164 285/239/164 284/233/164 +f 289/243/16 290/242/16 291/241/16 +f 291/241/16 292/244/16 289/243/16 +f 292/244/165 291/241/165 293/245/165 +f 293/245/165 294/246/165 292/244/165 +f 291/241/166 290/248/166 295/247/166 +f 295/247/166 293/245/166 291/241/166 +f 293/245/167 287/237/167 286/238/167 +f 286/238/167 294/246/167 293/245/167 +f 293/245/168 295/249/168 288/240/168 +f 288/240/169 287/237/169 293/245/169 +f 296/231/13 297/230/13 298/229/13 +f 298/229/13 299/232/13 296/231/13 +f 299/232/135 300/234/135 301/233/135 +f 301/233/135 296/231/135 299/232/135 +f 296/231/144 301/233/144 302/235/144 +f 302/235/144 297/236/144 296/231/144 +f 303/238/170 304/237/170 301/233/170 +f 301/233/140 300/234/140 303/238/140 +f 301/233/134 304/237/134 305/240/134 +f 305/240/144 302/239/144 301/233/144 +f 306/243/16 307/242/16 308/241/16 +f 308/241/16 309/244/16 306/243/16 +f 309/244/171 308/241/171 310/245/171 +f 310/245/145 311/246/145 309/244/145 +f 308/241/134 307/248/134 312/247/134 +f 312/247/134 310/245/134 308/241/134 +f 310/245/172 304/237/172 303/238/172 +f 303/238/148 311/246/148 310/245/148 +f 310/245/134 312/249/134 305/240/134 +f 305/240/144 304/237/144 310/245/144 +f 313/231/13 314/230/13 315/229/13 +f 315/229/13 316/232/13 313/231/13 +f 316/232/135 317/234/135 318/233/135 +f 318/233/135 313/231/135 316/232/135 +f 313/231/144 318/233/144 319/235/144 +f 319/235/144 314/236/144 313/231/144 +f 320/238/140 321/237/140 318/233/140 +f 318/233/140 317/234/140 320/238/140 +f 318/233/147 321/237/147 322/240/147 +f 322/240/144 319/239/144 318/233/144 +f 323/243/16 324/242/16 325/241/16 +f 325/241/16 326/244/16 323/243/16 +f 326/244/145 325/241/145 327/245/145 +f 327/245/145 328/246/145 326/244/145 +f 325/241/134 324/248/134 329/247/134 +f 329/247/134 327/245/134 325/241/134 +f 327/245/148 321/237/148 320/238/148 +f 320/238/148 328/246/148 327/245/148 +f 327/245/134 329/249/134 322/240/134 +f 322/240/139 321/237/139 327/245/139 +f 330/231/13 331/230/13 332/229/13 +f 332/229/13 333/232/13 330/231/13 +f 333/232/150 334/234/150 335/233/150 +f 335/233/150 330/231/150 333/232/150 +f 330/231/173 335/233/173 336/235/173 +f 336/235/173 331/236/173 330/231/173 +f 337/238/152 338/237/152 335/233/152 +f 335/233/174 334/234/174 337/238/174 +f 335/233/175 338/237/175 339/240/175 +f 339/240/175 336/239/175 335/233/175 +f 340/243/16 341/242/16 342/241/16 +f 342/241/16 343/244/16 340/243/16 +f 343/244/156 342/241/156 344/245/156 +f 344/245/156 345/246/156 343/244/156 +f 342/241/175 341/248/175 346/247/175 +f 346/247/175 344/245/175 342/241/175 +f 344/245/157 338/237/157 337/238/157 +f 337/238/176 345/246/176 344/245/176 +f 344/245/173 346/249/173 339/240/173 +f 339/240/173 338/237/173 344/245/173 +f 347/231/13 348/230/13 349/229/13 +f 349/229/13 350/232/13 347/231/13 +f 350/232/114 351/234/114 352/233/114 +f 352/233/114 347/231/114 350/232/114 +f 347/231/177 352/233/177 353/235/177 +f 353/235/177 348/236/177 347/231/177 +f 354/238/116 355/237/116 352/233/116 +f 352/233/117 351/234/117 354/238/117 +f 352/233/177 355/237/177 356/240/177 +f 356/240/178 353/239/178 352/233/178 +f 357/243/16 358/242/16 359/241/16 +f 359/241/16 360/244/16 357/243/16 +f 360/244/119 359/241/119 361/245/119 +f 361/245/119 362/246/119 360/244/119 +f 359/241/179 358/248/179 363/247/179 +f 363/247/178 361/245/178 359/241/178 +f 361/245/120 355/237/120 354/238/120 +f 354/238/121 362/246/121 361/245/121 +f 361/245/177 363/249/177 356/240/177 +f 356/240/178 355/237/178 361/245/178 +f 364/205/13 365/204/13 366/203/13 +f 366/203/13 367/206/13 364/205/13 +f 367/206/144 368/209/144 369/208/144 +f 369/208/144 364/207/144 367/206/144 +f 367/206/135 366/203/135 370/210/135 +f 370/210/135 368/209/135 367/206/135 +f 366/203/180 365/212/180 371/211/180 +f 371/211/181 370/210/181 366/203/181 +f 372/213/144 369/208/144 368/209/144 +f 368/209/134 373/214/134 372/213/134 +f 370/210/140 374/215/140 373/214/140 +f 373/214/170 368/209/170 370/210/170 +f 370/210/182 371/211/182 375/216/182 +f 375/216/141 374/215/141 370/210/141 +f 376/219/16 377/218/16 378/217/16 +f 378/217/183 379/220/183 376/219/183 +f 380/221/134 381/223/134 379/220/134 +f 379/220/134 378/222/134 380/221/134 +f 379/220/145 381/223/145 382/224/145 +f 382/224/145 376/219/145 379/220/145 +f 376/219/184 382/224/184 383/225/184 +f 383/225/185 377/226/185 376/219/185 +f 381/223/134 380/221/134 372/227/134 +f 372/227/144 373/214/144 381/223/144 +f 373/214/148 374/215/148 382/224/148 +f 382/224/172 381/223/172 373/214/172 +f 382/224/149 374/215/149 375/228/149 +f 375/228/186 383/225/186 382/224/186 +f 384/205/13 385/204/13 386/203/13 +f 386/203/13 387/206/13 384/205/13 +f 387/206/133 388/209/133 389/208/133 +f 389/208/144 384/207/144 387/206/144 +f 387/206/135 386/203/135 390/210/135 +f 390/210/135 388/209/135 387/206/135 +f 386/203/136 385/212/136 391/211/136 +f 391/211/181 390/210/181 386/203/181 +f 392/213/143 389/208/143 388/209/143 +f 388/209/139 393/214/139 392/213/139 +f 390/210/140 394/215/140 393/214/140 +f 393/214/140 388/209/140 390/210/140 +f 390/210/184 391/211/184 395/216/184 +f 395/216/136 394/215/136 390/210/136 +f 396/219/16 397/218/16 398/217/16 +f 398/217/16 399/220/16 396/219/16 +f 400/221/143 401/223/143 399/220/143 +f 399/220/134 398/222/134 400/221/134 +f 399/220/145 401/223/145 402/224/145 +f 402/224/145 396/219/145 399/220/145 +f 396/219/184 402/224/184 403/225/184 +f 403/225/137 397/226/137 396/219/137 +f 401/223/133 400/221/133 392/227/133 +f 392/227/147 393/214/147 401/223/147 +f 393/214/148 394/215/148 402/224/148 +f 402/224/148 401/223/148 393/214/148 +f 402/224/137 394/215/137 395/228/137 +f 395/228/181 403/225/181 402/224/181 +f 404/19/187 405/20/188 406/21/189 +f 406/21/189 407/22/190 404/19/187 +f 408/23/191 409/24/191 410/25/191 +f 410/25/191 411/26/191 408/23/191 +f 412/27/192 413/28/192 414/29/37 +f 414/29/37 415/30/36 412/27/192 +f 416/26/8 417/31/8 418/32/8 +f 418/32/8 419/23/8 416/26/8 +f 420/33/193 421/34/193 422/35/18 +f 422/35/18 423/36/194 420/33/193 +f 424/37/16 425/38/16 426/39/16 +f 427/40/183 412/41/183 415/42/183 +f 415/42/16 428/43/16 427/40/16 +f 429/44/183 430/45/183 431/46/183 +f 431/46/183 430/45/183 432/47/183 +f 432/47/16 433/48/16 431/46/16 +f 404/19/187 407/22/190 434/49/195 +f 434/49/195 435/50/196 404/19/187 +f 415/30/36 414/29/37 436/51/197 +f 436/51/197 437/52/197 415/30/36 +f 423/36/194 422/35/18 438/53/198 +f 438/53/198 439/54/198 423/36/194 +f 428/43/16 415/42/16 437/55/16 +f 437/55/16 440/56/16 428/43/16 +f 426/39/16 433/48/16 432/47/16 +f 432/47/6 424/37/6 426/39/6 +f 406/57/199 405/58/199 441/59/199 +f 441/59/200 427/60/200 406/57/200 +f 406/57/201 427/60/201 428/61/201 +f 428/61/201 407/62/201 406/57/201 +f 407/62/202 428/61/202 440/63/202 +f 440/63/203 434/64/203 407/62/203 +f 434/64/204 440/63/204 442/65/204 +f 442/65/205 435/66/205 434/64/205 +f 435/67/206 442/68/206 443/69/206 +f 443/69/207 404/70/207 435/67/207 +f 404/70/208 443/69/208 441/71/208 +f 441/71/208 405/72/208 404/70/208 +f 444/73/209 442/74/209 440/56/209 +f 440/56/210 437/55/210 444/73/210 +f 436/51/211 445/75/212 444/76/212 +f 444/76/212 437/52/213 436/51/211 +f 446/77/214 447/78/215 413/28/216 +f 413/28/216 412/27/216 446/77/214 +f 427/40/217 441/79/217 446/80/217 +f 446/80/218 412/41/218 427/40/218 +f 448/32/219 408/23/219 411/26/219 +f 411/26/219 449/31/219 448/32/219 +f 425/81/220 446/82/220 441/71/220 +f 441/71/220 426/83/220 425/81/220 +f 426/83/208 441/71/208 443/69/208 +f 443/69/208 433/84/208 426/83/208 +f 433/84/206 443/69/206 442/68/206 +f 442/68/206 431/85/206 433/84/206 +f 431/85/221 442/68/221 444/86/221 +f 444/86/221 429/87/221 431/85/221 +f 450/25/222 416/26/222 419/23/222 +f 419/23/222 451/24/222 450/25/222 +f 430/88/193 420/33/193 423/36/193 +f 423/36/193 432/89/193 430/88/193 +f 432/89/223 423/36/223 439/54/223 +f 439/54/223 424/90/223 432/89/223 +f 410/91/36 447/92/36 446/82/36 +f 446/82/36 411/93/36 410/91/36 +f 411/93/36 446/82/36 425/81/36 +f 425/81/36 449/94/36 411/93/36 +f 449/95/16 425/38/16 424/37/16 +f 424/37/16 448/96/16 449/95/16 +f 448/97/18 424/90/18 439/54/18 +f 439/54/18 408/98/18 448/97/18 +f 408/98/18 439/54/18 438/53/18 +f 438/53/18 409/99/18 408/98/18 +f 418/100/18 421/34/18 420/33/18 +f 420/33/18 419/101/18 418/100/18 +f 419/101/224 420/33/224 430/88/224 +f 430/88/224 451/102/224 419/101/224 +f 451/103/225 430/45/225 429/44/225 +f 429/44/225 450/104/225 451/103/225 +f 450/105/226 429/87/226 444/86/226 +f 444/86/226 416/106/226 450/105/226 +f 416/106/36 444/86/36 445/107/36 +f 445/107/36 417/108/36 416/106/36 +f 452/19/187 453/20/188 454/21/189 +f 454/21/189 455/22/190 452/19/187 +f 456/23/191 457/24/191 458/25/191 +f 458/25/191 459/26/191 456/23/191 +f 460/27/192 461/28/192 462/29/37 +f 462/29/37 463/30/36 460/27/192 +f 464/26/8 465/31/8 466/32/8 +f 466/32/8 467/23/8 464/26/8 +f 468/33/193 469/34/193 470/35/18 +f 470/35/18 471/36/194 468/33/193 +f 472/37/16 473/38/16 474/39/16 +f 475/40/183 460/41/183 463/42/183 +f 463/42/16 476/43/16 475/40/16 +f 477/44/183 478/45/183 479/46/183 +f 479/46/183 478/45/183 480/47/183 +f 480/47/16 481/48/16 479/46/16 +f 452/19/187 455/22/190 482/49/195 +f 482/49/195 483/50/196 452/19/187 +f 463/30/36 462/29/37 484/51/197 +f 484/51/197 485/52/197 463/30/36 +f 471/36/194 470/35/18 486/53/198 +f 486/53/198 487/54/198 471/36/194 +f 476/43/16 463/42/16 485/55/16 +f 485/55/16 488/56/16 476/43/16 +f 474/39/16 481/48/16 480/47/16 +f 480/47/6 472/37/6 474/39/6 +f 454/57/199 453/58/199 489/59/199 +f 489/59/200 475/60/200 454/57/200 +f 454/57/201 475/60/201 476/61/201 +f 476/61/201 455/62/201 454/57/201 +f 455/62/202 476/61/202 488/63/202 +f 488/63/203 482/64/203 455/62/203 +f 482/64/204 488/63/204 490/65/204 +f 490/65/205 483/66/205 482/64/205 +f 483/67/206 490/68/206 491/69/206 +f 491/69/207 452/70/207 483/67/207 +f 452/70/208 491/69/208 489/71/208 +f 489/71/208 453/72/208 452/70/208 +f 492/73/209 490/74/209 488/56/209 +f 488/56/210 485/55/210 492/73/210 +f 484/51/211 493/75/212 492/76/212 +f 492/76/212 485/52/213 484/51/211 +f 494/77/214 495/78/215 461/28/216 +f 461/28/216 460/27/216 494/77/214 +f 475/40/217 489/79/217 494/80/217 +f 494/80/218 460/41/218 475/40/218 +f 496/32/219 456/23/219 459/26/219 +f 459/26/219 497/31/219 496/32/219 +f 473/81/220 494/82/220 489/71/220 +f 489/71/220 474/83/220 473/81/220 +f 474/83/208 489/71/208 491/69/208 +f 491/69/208 481/84/208 474/83/208 +f 481/84/206 491/69/206 490/68/206 +f 490/68/206 479/85/206 481/84/206 +f 479/85/221 490/68/221 492/86/221 +f 492/86/221 477/87/221 479/85/221 +f 498/25/222 464/26/222 467/23/222 +f 467/23/222 499/24/222 498/25/222 +f 478/88/193 468/33/193 471/36/193 +f 471/36/193 480/89/193 478/88/193 +f 480/89/223 471/36/223 487/54/223 +f 487/54/223 472/90/223 480/89/223 +f 458/91/36 495/92/36 494/82/36 +f 494/82/36 459/93/36 458/91/36 +f 459/93/36 494/82/36 473/81/36 +f 473/81/36 497/94/36 459/93/36 +f 497/95/16 473/38/16 472/37/16 +f 472/37/16 496/96/16 497/95/16 +f 496/97/18 472/90/18 487/54/18 +f 487/54/18 456/98/18 496/97/18 +f 456/98/18 487/54/18 486/53/18 +f 486/53/18 457/99/18 456/98/18 +f 466/100/18 469/34/18 468/33/18 +f 468/33/18 467/101/18 466/100/18 +f 467/101/224 468/33/224 478/88/224 +f 478/88/224 499/102/224 467/101/224 +f 499/103/225 478/45/225 477/44/225 +f 477/44/225 498/104/225 499/103/225 +f 498/105/226 477/87/226 492/86/226 +f 492/86/226 464/106/226 498/105/226 +f 464/106/36 492/86/36 493/107/36 +f 493/107/36 465/108/36 464/106/36 +f 500/250/227 501/251/228 502/252/229 +f 502/252/229 503/253/230 500/250/227 +f 504/254/231 500/250/227 503/253/230 +f 503/253/230 505/255/232 504/254/231 +f 506/256/233 504/254/231 505/255/232 +f 505/255/232 507/257/234 506/256/233 +f 508/258/235 506/256/233 507/257/234 +f 507/257/234 509/259/236 508/258/235 +f 510/260/237 508/261/235 509/262/236 +f 509/262/236 511/263/238 510/260/237 +f 512/264/239 510/260/237 511/263/238 +f 511/263/238 513/265/240 512/264/239 +f 514/266/241 512/264/239 513/265/240 +f 513/265/240 515/267/242 514/266/241 +f 501/251/228 514/266/241 515/267/242 +f 515/267/242 502/252/229 501/251/228 +f 516/268/243 516/268/244 501/251/228 +f 501/251/228 500/250/227 516/268/243 +f 516/268/245 516/268/243 500/250/227 +f 500/250/227 504/254/231 516/268/245 +f 516/269/246 516/268/245 504/254/231 +f 504/254/231 506/256/233 516/269/246 +f 516/269/247 516/269/246 506/256/233 +f 506/256/233 508/258/235 516/269/247 +f 516/268/248 516/269/247 508/261/235 +f 508/261/235 510/260/237 516/268/248 +f 516/268/249 516/268/248 510/260/237 +f 510/260/237 512/264/239 516/268/249 +f 516/268/250 516/268/249 512/264/239 +f 512/264/239 514/266/241 516/268/250 +f 516/268/244 516/268/250 514/266/241 +f 514/266/241 501/251/228 516/268/244 +f 516/269/2 516/269/2 516/268/2 +f 516/268/2 516/268/2 516/268/2 +f 516/268/2 516/268/2 516/268/2 +f 516/268/2 516/268/2 516/268/2 +f 516/269/2 516/268/2 516/268/2 +f 516/269/2 516/268/2 516/268/2 +f 517/270/251 518/271/251 503/253/251 +f 503/253/252 502/252/252 517/270/252 +f 518/271/253 519/272/253 505/255/253 +f 505/255/253 503/253/253 518/271/253 +f 519/272/254 520/273/254 507/257/254 +f 507/257/254 505/255/254 519/272/254 +f 520/273/255 521/274/255 509/259/255 +f 509/259/256 507/257/256 520/273/256 +f 521/275/257 522/276/257 511/263/257 +f 511/263/257 509/262/257 521/275/257 +f 522/276/258 523/277/258 513/265/258 +f 513/265/258 511/263/258 522/276/258 +f 523/277/259 524/278/259 515/267/259 +f 515/267/259 513/265/259 523/277/259 +f 524/278/260 517/270/260 502/252/260 +f 502/252/260 515/267/260 524/278/260 +f 525/279/261 526/280/262 527/281/262 +f 527/281/262 528/282/261 525/279/261 +f 529/283/263 525/279/261 528/282/261 +f 528/282/261 530/284/263 529/283/263 +f 531/285/264 529/283/263 530/284/263 +f 530/284/263 532/286/264 531/285/264 +f 533/287/265 531/285/264 532/286/264 +f 532/286/264 534/288/265 533/287/265 +f 535/289/261 536/290/262 526/280/262 +f 526/280/262 525/279/261 535/289/261 +f 537/291/263 535/289/261 525/279/261 +f 525/279/261 529/283/263 537/291/263 +f 538/292/264 537/291/263 529/283/263 +f 529/283/263 531/285/264 538/292/264 +f 539/293/265 538/292/264 531/285/264 +f 531/285/264 533/287/265 539/293/265 +f 540/294/261 541/295/262 536/290/262 +f 536/290/262 535/289/261 540/294/261 +f 542/296/263 540/294/261 535/289/261 +f 535/289/261 537/291/263 542/296/263 +f 543/297/264 542/296/263 537/291/263 +f 537/291/263 538/292/264 543/297/264 +f 544/298/265 543/297/264 538/292/264 +f 538/292/264 539/293/265 544/298/265 +f 545/299/261 546/300/262 541/295/262 +f 541/295/262 540/294/261 545/299/261 +f 547/301/263 545/299/261 540/294/261 +f 540/294/261 542/296/263 547/301/263 +f 548/302/264 547/301/263 542/296/263 +f 542/296/263 543/297/264 548/302/264 +f 549/303/265 548/302/264 543/297/264 +f 543/297/264 544/298/265 549/303/265 +f 550/304/36 551/305/36 552/306/36 +f 552/306/36 553/307/36 550/304/36 +f 554/308/266 555/309/267 556/310/267 +f 556/310/267 557/311/266 554/308/266 +f 557/312/268 556/313/269 558/314/269 +f 558/314/269 559/315/268 557/312/268 +f 559/311/270 558/310/271 560/309/271 +f 560/309/271 561/308/270 559/311/270 +f 561/315/272 560/314/273 555/313/273 +f 555/313/273 554/312/272 561/315/272 +f 554/308/266 557/311/266 553/316/274 +f 553/316/274 552/317/274 554/308/266 +f 557/312/268 559/315/268 550/318/275 +f 550/318/275 553/319/275 557/312/268 +f 559/311/270 561/308/270 551/317/276 +f 551/317/276 550/316/276 559/311/270 +f 561/315/272 554/312/272 552/319/277 +f 552/319/277 551/318/277 561/315/272 +f 562/307/226 563/304/36 564/305/226 +f 564/305/226 565/306/226 562/307/226 +f 566/308/278 567/311/278 568/310/279 +f 568/310/279 569/309/279 566/308/278 +f 567/312/268 570/315/268 571/314/269 +f 571/314/269 568/313/269 567/312/268 +f 570/311/280 572/308/280 573/309/281 +f 573/309/281 571/310/281 570/311/280 +f 572/315/272 566/312/272 569/313/282 +f 569/313/282 573/314/282 572/315/272 +f 566/308/278 564/317/283 563/316/283 +f 563/316/283 567/311/278 566/308/278 +f 567/312/268 563/319/284 562/318/284 +f 562/318/284 570/315/268 567/312/268 +f 570/311/280 562/316/285 565/317/285 +f 565/317/285 572/308/280 570/311/280 +f 572/315/272 565/318/277 564/319/277 +f 564/319/277 566/312/272 572/315/272 +f 574/320/286 575/321/287 576/322/288 +f 576/322/288 577/323/289 574/320/286 +f 578/324/290 574/320/286 577/323/289 +f 577/323/289 579/325/291 578/324/290 +f 580/326/292 578/324/290 579/325/291 +f 579/325/291 581/327/293 580/326/292 +f 582/328/294 580/326/292 581/327/293 +f 581/327/293 583/329/295 582/328/294 +f 584/330/296 582/328/294 583/329/295 +f 583/329/295 585/331/295 584/330/296 +f 586/332/297 587/333/298 575/321/287 +f 575/321/287 574/320/286 586/332/297 +f 586/332/297 574/320/286 578/324/290 +f 578/324/290 588/334/299 586/332/297 +f 588/334/299 578/324/290 580/326/292 +f 580/326/292 589/335/300 588/334/299 +f 589/335/300 580/326/292 582/328/294 +f 582/328/294 590/336/301 589/335/300 +f 591/337/302 590/336/301 582/328/294 +f 582/328/294 584/330/296 591/337/302 +f 592/338/303 593/339/304 594/340/305 +f 594/340/305 595/341/306 592/338/303 +f 596/342/307 592/338/303 595/341/306 +f 595/341/306 597/343/308 596/342/307 +f 598/344/309 596/342/307 597/343/308 +f 597/343/308 599/345/310 598/344/309 +f 600/346/311 598/344/309 599/345/310 +f 599/345/310 601/347/312 600/346/311 +f 602/348/313 600/346/311 601/347/312 +f 601/347/312 591/349/314 602/348/313 +f 603/350/315 604/351/316 593/339/304 +f 593/339/304 592/338/303 603/350/315 +f 605/352/317 603/350/315 592/338/303 +f 592/338/303 596/342/307 605/352/317 +f 606/353/318 605/352/317 596/342/307 +f 596/342/307 598/344/309 606/353/318 +f 607/354/319 606/353/318 598/344/309 +f 598/344/309 600/346/311 607/354/319 +f 608/355/319 607/354/319 600/346/311 +f 600/346/311 602/348/313 608/355/319 +f 609/356/320 610/357/321 604/351/316 +f 604/351/316 603/350/315 609/356/320 +f 611/358/322 609/356/320 603/350/315 +f 603/350/315 605/352/317 611/358/322 +f 612/359/323 611/358/322 605/352/317 +f 605/352/317 606/353/318 612/359/323 +f 613/360/324 612/359/323 606/353/318 +f 606/353/318 607/354/319 613/360/324 +f 614/361/324 613/360/324 607/354/319 +f 607/354/319 608/355/319 614/361/324 +f 615/362/325 616/363/326 610/357/321 +f 610/357/321 609/356/320 615/362/325 +f 617/364/327 615/362/325 609/356/320 +f 609/356/320 611/358/322 617/364/327 +f 618/365/328 617/364/327 611/358/322 +f 611/358/322 612/359/323 618/365/328 +f 619/366/329 618/365/328 612/359/323 +f 612/359/323 613/360/324 619/366/329 +f 620/367/329 619/366/329 613/360/324 +f 613/360/324 614/361/324 620/367/329 +f 577/323/289 576/322/288 616/368/326 +f 616/368/326 615/369/325 577/323/289 +f 579/325/291 577/323/289 615/369/325 +f 615/369/325 617/370/327 579/325/291 +f 581/327/293 579/325/291 617/370/327 +f 617/370/327 618/371/328 581/327/293 +f 583/329/295 581/327/293 618/371/328 +f 618/371/328 619/372/329 583/329/295 +f 585/331/295 583/329/295 619/372/329 +f 619/372/329 620/373/329 585/331/295 +f 621/374/36 622/375/36 623/376/36 +f 623/376/36 624/377/36 621/374/36 +f 625/378/36 626/379/36 627/380/36 +f 627/380/36 628/381/36 625/378/36 +f 622/375/16 629/382/16 630/383/16 +f 630/383/16 623/376/16 622/375/16 +f 631/384/16 625/378/16 628/381/16 +f 628/381/16 632/385/16 631/384/16 +f 633/386/36 634/387/36 635/388/36 +f 635/388/36 636/389/36 633/386/36 +f 637/390/2 638/391/2 635/388/2 +f 635/388/2 634/387/2 637/390/2 +f 639/392/8 640/393/8 633/386/8 +f 633/386/8 636/389/8 639/392/8 +f 637/394/6 634/395/6 641/396/6 +f 641/396/6 642/397/6 637/394/6 +f 634/395/6 633/398/6 643/399/6 +f 643/399/6 641/396/6 634/395/6 +f 633/398/6 640/400/6 644/401/6 +f 644/401/142 643/399/142 633/398/142 +f 642/402/8 641/403/8 645/404/8 +f 645/404/8 646/405/8 642/402/8 +f 641/395/18 643/398/18 647/398/18 +f 647/398/18 645/395/18 641/395/18 +f 643/403/2 644/402/2 648/405/2 +f 648/405/2 647/404/2 643/403/2 +f 648/406/6 646/407/6 645/408/6 +f 645/408/6 647/409/16 648/406/6 +f 649/410/330 650/411/331 651/412/332 +f 651/412/332 652/413/333 649/410/330 +f 653/414/334 650/411/334 649/410/335 +f 649/410/335 654/415/335 653/414/334 +f 655/416/336 656/417/337 657/418/338 +f 657/418/338 658/419/338 655/416/336 +f 659/420/15 660/421/15 661/422/339 +f 661/422/339 662/423/339 659/420/15 +f 663/424/340 652/413/341 664/425/342 +f 664/425/342 665/426/342 663/424/340 +f 657/418/343 656/417/344 651/412/332 +f 651/412/332 650/411/331 657/418/343 +f 658/419/345 657/418/345 650/411/334 +f 650/411/334 653/427/334 658/419/345 +f 665/428/346 664/425/346 660/421/15 +f 660/421/15 659/420/15 665/428/346 +f 660/421/347 664/425/348 652/413/333 +f 652/413/333 651/412/332 660/421/347 +f 662/429/349 661/422/349 656/417/337 +f 656/417/337 655/416/336 662/429/349 +f 654/415/350 649/410/350 652/413/341 +f 652/413/341 663/424/340 654/415/350 +f 656/417/344 661/422/351 660/421/347 +f 660/421/347 651/412/332 656/417/344 +f 666/410/352 667/411/353 668/412/354 +f 668/412/354 669/413/355 666/410/352 +f 670/414/334 667/411/334 666/410/345 +f 666/410/345 671/415/345 670/414/334 +f 672/416/340 673/417/341 674/418/350 +f 674/418/350 675/419/350 672/416/340 +f 676/420/15 677/421/15 678/422/346 +f 678/422/346 679/423/346 676/420/15 +f 680/424/336 669/413/337 681/425/349 +f 681/425/349 682/426/349 680/424/336 +f 674/418/356 673/417/357 668/412/354 +f 668/412/354 667/411/353 674/418/356 +f 675/419/335 674/418/335 667/411/334 +f 667/411/334 670/427/334 675/419/335 +f 682/428/339 681/425/339 677/421/15 +f 677/421/15 676/420/15 682/428/339 +f 677/421/358 681/425/359 669/413/355 +f 669/413/355 668/412/354 677/421/358 +f 679/429/342 678/422/342 673/417/341 +f 673/417/341 672/416/340 679/429/342 +f 671/415/338 666/410/338 669/413/337 +f 669/413/337 680/424/336 671/415/338 +f 673/417/357 678/422/360 677/421/358 +f 677/421/358 668/412/354 673/417/357 +f 683/430/2 684/431/2 685/432/2 +f 685/432/2 686/433/2 683/430/2 +f 687/434/361 688/435/15 684/436/15 +f 684/436/15 683/437/361 687/434/361 +f 689/433/8 690/432/8 688/431/8 +f 688/431/8 687/430/8 689/433/8 +f 690/435/334 685/436/334 691/438/362 +f 691/438/362 692/439/362 690/435/334 +f 691/440/16 693/441/16 694/442/16 +f 694/442/16 692/443/16 691/440/16 +f 693/444/2 691/445/2 685/432/2 +f 685/432/2 684/431/2 693/444/2 +f 694/439/363 693/438/363 684/436/15 +f 684/436/15 688/435/15 694/439/363 +f 692/445/8 694/444/8 688/431/8 +f 688/431/8 690/432/8 692/445/8 +f 689/434/364 686/437/364 685/436/334 +f 685/436/334 690/435/334 689/434/364 +f 695/446/365 696/447/366 697/448/367 +f 697/448/367 698/449/368 695/446/365 +f 699/450/369 700/451/370 696/447/366 +f 696/447/366 695/446/365 699/450/369 +f 698/452/368 697/453/367 700/451/370 +f 700/451/370 699/450/369 698/452/368 +f 701/454/8 702/455/8 703/456/8 +f 696/447/366 704/457/371 705/458/372 +f 705/458/372 697/448/367 696/447/366 +f 706/459/373 704/457/371 696/447/366 +f 696/447/366 700/451/370 706/459/373 +f 705/460/372 706/459/373 700/451/370 +f 700/451/370 697/453/367 705/460/372 +f 704/457/371 703/461/374 702/462/375 +f 702/462/375 705/458/372 704/457/371 +f 701/463/376 703/461/374 704/457/371 +f 704/457/371 706/459/373 701/463/376 +f 702/464/375 701/463/376 706/459/373 +f 706/459/373 705/460/372 702/464/375 +f 707/446/377 708/447/378 709/448/379 +f 709/448/379 710/449/380 707/446/377 +f 711/450/381 712/451/382 708/447/378 +f 708/447/378 707/446/377 711/450/381 +f 710/452/380 709/453/379 712/451/382 +f 712/451/382 711/450/381 710/452/380 +f 713/454/2 714/455/2 715/456/2 +f 708/447/378 716/457/383 717/458/384 +f 717/458/384 709/448/379 708/447/378 +f 718/459/385 716/457/383 708/447/378 +f 708/447/378 712/451/382 718/459/385 +f 717/460/384 718/459/385 712/451/382 +f 712/451/382 709/453/379 717/460/384 +f 716/457/383 715/461/386 714/462/387 +f 714/462/387 717/458/384 716/457/383 +f 713/463/388 715/461/386 716/457/383 +f 716/457/383 718/459/385 713/463/388 +f 714/464/387 713/463/388 718/459/385 +f 718/459/385 717/460/384 714/464/387 +f 719/465/37 720/466/36 721/467/37 +f 721/467/37 722/468/37 719/465/37 +f 723/469/6 724/470/6 725/471/6 +f 726/472/6 723/469/6 725/471/6 +f 727/473/6 726/472/6 725/471/6 +f 727/473/6 725/471/6 728/474/142 +f 729/475/389 730/476/389 726/477/2 +f 731/478/2 729/475/389 726/477/2 +f 732/479/2 731/478/2 726/477/2 +f 732/479/2 726/477/2 727/480/2 +f 733/481/5 734/482/5 731/483/5 +f 735/484/5 733/481/5 731/483/5 +f 736/485/13 735/484/5 731/483/5 +f 736/485/13 731/483/5 732/486/13 +f 737/487/390 738/488/390 735/489/391 +f 725/490/8 737/487/390 735/489/391 +f 728/491/391 725/490/8 735/489/391 +f 728/491/391 735/489/391 736/492/391 +f 739/493/392 740/494/393 741/495/394 +f 741/495/394 742/496/395 743/497/396 +f 739/493/392 741/495/394 743/497/396 +f 744/498/397 739/493/392 743/497/396 +f 745/499/398 746/500/399 740/494/393 +f 740/494/393 739/493/392 747/501/15 +f 745/499/398 740/494/393 747/501/15 +f 748/502/15 745/499/398 747/501/15 +f 749/503/400 750/504/401 746/500/399 +f 746/500/399 745/499/398 751/505/402 +f 749/503/400 746/500/399 751/505/402 +f 752/506/403 749/503/400 751/505/402 +f 742/496/395 741/495/394 750/504/401 +f 750/504/401 749/503/400 753/507/36 +f 742/496/395 750/504/401 753/507/36 +f 754/508/37 742/496/395 753/507/36 +f 755/509/5 721/510/13 720/511/13 +f 720/511/13 756/512/5 755/509/5 +f 756/509/404 720/510/405 719/511/406 +f 719/511/406 757/512/404 756/509/404 +f 757/512/6 719/511/6 722/510/6 +f 722/510/6 758/509/6 757/512/6 +f 758/512/407 722/511/8 721/510/8 +f 721/510/8 755/509/407 758/512/407 +f 759/513/6 760/514/16 761/515/6 +f 761/515/6 762/516/6 759/513/6 +f 763/513/2 764/517/2 765/518/2 +f 765/518/2 766/516/2 763/513/2 +f 767/513/13 768/517/13 769/518/13 +f 769/518/13 770/516/13 767/513/13 +f 771/513/8 772/514/8 773/515/8 +f 773/515/8 774/516/8 771/513/8 +f 775/519/408 761/520/409 774/521/410 +f 774/521/410 776/522/334 775/519/408 +f 777/523/411 773/524/412 770/525/413 +f 770/525/413 778/526/18 777/523/411 +f 779/527/414 769/528/415 766/529/416 +f 766/529/416 780/530/334 779/527/414 +f 781/531/417 765/532/418 762/533/419 +f 762/533/419 782/534/18 781/531/417 +f 783/535/15 760/536/15 759/537/15 +f 759/537/15 784/538/226 783/535/15 +f 785/539/37 764/540/37 763/541/15 +f 763/541/15 786/542/15 785/539/37 +f 787/543/15 768/544/15 767/545/36 +f 767/545/36 788/546/36 787/543/15 +f 789/547/37 772/548/37 771/549/37 +f 771/549/37 790/550/15 789/547/37 +f 767/513/13 770/516/13 773/515/13 +f 773/515/13 772/514/13 767/513/13 +f 771/513/8 774/516/8 761/518/8 +f 761/518/8 760/517/8 771/513/8 +f 777/523/411 776/522/334 774/521/410 +f 774/521/410 773/524/412 777/523/411 +f 779/527/414 778/526/18 770/525/413 +f 770/525/413 769/528/415 779/527/414 +f 781/531/417 780/530/334 766/529/416 +f 766/529/416 765/532/418 781/531/417 +f 789/547/37 788/546/36 767/545/36 +f 767/545/36 772/548/37 789/547/37 +f 783/535/15 790/550/15 771/549/37 +f 771/549/37 760/536/15 783/535/15 +f 759/513/6 762/516/6 765/518/6 +f 765/518/6 764/517/16 759/513/6 +f 763/513/2 766/516/2 769/515/2 +f 769/515/2 768/514/2 763/513/2 +f 775/519/408 782/534/18 762/533/419 +f 762/533/419 761/520/409 775/519/408 +f 785/539/37 784/538/226 759/537/15 +f 759/537/15 764/540/37 785/539/37 +f 787/543/15 786/542/15 763/541/15 +f 763/541/15 768/544/15 787/543/15 +f 791/19/187 792/20/188 793/21/189 +f 793/21/189 794/22/190 791/19/187 +f 795/23/2 796/24/191 797/25/191 +f 797/25/191 798/26/2 795/23/2 +f 799/27/192 800/28/420 801/29/421 +f 801/29/421 802/30/421 799/27/192 +f 803/26/80 804/31/8 805/32/8 +f 805/32/8 806/23/80 803/26/80 +f 807/33/422 808/34/423 809/35/18 +f 809/35/18 810/36/194 807/33/422 +f 811/37/6 812/38/16 813/39/6 +f 814/40/424 799/41/425 802/42/16 +f 802/42/16 815/43/16 814/40/424 +f 816/44/225 817/45/225 818/46/183 +f 818/46/183 817/45/225 819/47/16 +f 819/47/16 820/48/16 818/46/183 +f 791/19/187 794/22/190 821/49/195 +f 821/49/195 822/50/196 791/19/187 +f 802/30/426 801/29/426 823/51/197 +f 823/51/197 824/52/197 802/30/426 +f 810/36/194 809/35/18 825/53/427 +f 825/53/427 826/54/427 810/36/194 +f 815/43/16 802/42/16 824/55/428 +f 824/55/428 827/56/429 815/43/16 +f 813/39/6 820/48/16 819/47/16 +f 819/47/16 811/37/6 813/39/6 +f 793/57/430 792/58/199 828/59/199 +f 828/59/199 814/60/430 793/57/430 +f 793/57/201 814/60/201 815/61/431 +f 815/61/431 794/62/431 793/57/201 +f 794/62/432 815/61/432 827/63/432 +f 827/63/432 821/64/432 794/62/432 +f 821/64/433 827/63/433 829/65/434 +f 829/65/434 822/66/434 821/64/433 +f 822/67/206 829/68/435 830/69/436 +f 830/69/436 791/70/437 822/67/206 +f 791/70/437 830/69/436 828/71/438 +f 828/71/438 792/72/208 791/70/437 +f 831/73/439 829/74/209 827/56/429 +f 827/56/429 824/55/428 831/73/439 +f 823/51/211 832/75/212 831/76/212 +f 831/76/212 824/52/213 823/51/211 +f 833/77/214 834/78/215 800/28/216 +f 800/28/216 799/27/440 833/77/214 +f 814/40/424 828/79/217 833/80/441 +f 833/80/441 799/41/425 814/40/424 +f 835/32/219 795/23/2 798/26/2 +f 798/26/2 836/31/219 835/32/219 +f 812/81/442 833/82/443 828/71/438 +f 828/71/438 813/83/444 812/81/442 +f 813/83/444 828/71/438 830/69/436 +f 830/69/436 820/84/445 813/83/444 +f 820/84/445 830/69/436 829/68/435 +f 829/68/435 818/85/446 820/84/445 +f 818/85/446 829/68/435 831/86/447 +f 831/86/447 816/87/448 818/85/446 +f 837/25/449 803/26/80 806/23/80 +f 806/23/80 838/24/449 837/25/449 +f 817/88/422 807/33/422 810/36/194 +f 810/36/194 819/89/194 817/88/422 +f 819/89/194 810/36/194 826/54/427 +f 826/54/427 811/90/427 819/89/194 +f 797/91/36 834/92/36 833/82/443 +f 833/82/443 798/93/15 797/91/36 +f 798/93/15 833/82/443 812/81/442 +f 812/81/442 836/94/15 798/93/15 +f 836/95/16 812/38/16 811/37/6 +f 811/37/6 835/96/16 836/95/16 +f 835/97/334 811/90/427 826/54/427 +f 826/54/427 795/98/334 835/97/334 +f 795/98/334 826/54/427 825/53/427 +f 825/53/427 796/99/18 795/98/334 +f 805/100/18 808/34/423 807/33/422 +f 807/33/422 806/101/194 805/100/18 +f 806/101/194 807/33/422 817/88/422 +f 817/88/422 838/102/194 806/101/194 +f 838/103/225 817/45/225 816/44/225 +f 816/44/225 837/104/225 838/103/225 +f 837/105/37 816/87/448 831/86/447 +f 831/86/447 803/106/37 837/105/37 +f 803/106/37 831/86/447 832/107/36 +f 832/107/36 804/108/36 803/106/37 +f 755/509/5 756/512/5 741/551/5 +f 741/551/5 740/552/5 755/509/5 +f 756/509/404 757/512/404 750/551/450 +f 750/551/450 741/552/450 756/509/404 +f 757/512/6 758/509/6 746/552/16 +f 746/552/16 750/551/16 757/512/6 +f 758/512/407 755/509/407 740/552/451 +f 740/552/451 746/551/451 758/512/407 +f 724/553/6 723/554/6 744/555/6 +f 744/555/6 743/556/6 724/553/6 +f 730/553/389 729/554/389 748/555/452 +f 748/555/452 747/556/452 730/553/389 +f 734/554/5 733/553/5 752/556/5 +f 752/556/5 751/555/5 734/554/5 +f 738/553/390 737/554/390 754/555/451 +f 754/555/451 753/556/451 738/553/390 +f 725/471/453 724/470/453 737/557/453 +f 726/472/454 730/558/454 723/469/454 +f 731/483/455 734/482/455 729/559/455 +f 735/484/456 738/560/456 733/481/456 +f 839/561/457 840/562/457 841/563/457 +f 842/564/458 843/565/458 844/566/458 +f 845/567/459 846/568/459 847/569/459 +f 848/570/460 849/571/460 850/572/460 +f 737/554/461 724/573/461 743/574/461 +f 743/574/461 754/555/461 737/554/461 +f 723/575/462 730/553/462 747/556/462 +f 747/556/462 744/576/462 723/575/462 +f 729/554/463 734/573/463 751/574/463 +f 751/574/463 748/555/463 729/554/463 +f 733/575/464 738/553/464 753/556/464 +f 753/556/464 752/576/464 733/575/464 +f 743/577/465 742/578/465 840/579/465 +f 840/579/465 839/580/465 743/577/465 +f 742/578/466 754/581/466 841/582/466 +f 841/582/466 840/579/466 742/578/466 +f 754/555/467 743/574/467 839/583/467 +f 839/583/467 841/584/467 754/555/467 +f 747/577/468 739/578/468 843/579/468 +f 843/579/468 842/580/468 747/577/468 +f 739/578/469 744/581/469 844/582/469 +f 844/582/469 843/579/469 739/578/469 +f 744/576/470 747/556/470 842/585/470 +f 842/585/470 844/586/470 744/576/470 +f 751/577/471 745/578/471 846/579/471 +f 846/579/471 845/580/471 751/577/471 +f 745/578/472 748/581/472 847/582/472 +f 847/582/472 846/579/472 745/578/472 +f 748/555/473 751/574/473 845/583/473 +f 845/583/473 847/584/473 748/555/473 +f 753/577/474 749/578/474 849/579/474 +f 849/579/474 848/580/474 753/577/474 +f 749/578/475 752/581/475 850/582/475 +f 850/582/475 849/579/475 749/578/475 +f 752/576/476 753/556/476 848/585/476 +f 848/585/476 850/586/476 752/576/476 +f 851/513/16 852/514/16 853/515/16 +f 853/515/16 854/516/16 851/513/16 +f 855/587/2 856/588/2 857/589/2 +f 857/589/2 858/590/2 855/587/2 +f 859/591/5 860/592/5 861/593/5 +f 861/593/5 862/594/5 859/591/5 +f 863/513/8 864/514/8 865/515/8 +f 865/515/8 866/516/8 863/513/8 +f 867/519/408 853/520/409 866/521/410 +f 866/521/410 868/522/334 867/519/408 +f 869/523/411 865/524/412 862/525/413 +f 862/525/413 870/526/18 869/523/411 +f 871/527/414 861/528/415 858/529/416 +f 858/529/416 872/530/334 871/527/414 +f 873/531/417 857/532/418 854/533/419 +f 854/533/419 874/534/194 873/531/417 +f 875/535/226 852/536/15 851/537/15 +f 851/537/15 876/538/226 875/535/226 +f 877/539/36 856/540/37 855/541/15 +f 855/541/15 878/542/15 877/539/36 +f 879/543/15 860/544/15 859/545/36 +f 859/545/36 880/546/36 879/543/15 +f 881/547/37 864/548/37 863/549/37 +f 863/549/37 882/550/15 881/547/37 +f 859/591/5 862/594/5 865/595/5 +f 865/595/5 864/596/5 859/591/5 +f 863/513/8 866/516/8 853/518/8 +f 853/518/8 852/517/8 863/513/8 +f 869/523/411 868/522/334 866/521/410 +f 866/521/410 865/524/412 869/523/411 +f 871/527/414 870/526/18 862/525/413 +f 862/525/413 861/528/415 871/527/414 +f 873/531/417 872/530/334 858/529/416 +f 858/529/416 857/532/418 873/531/417 +f 881/547/37 880/546/36 859/545/36 +f 859/545/36 864/548/37 881/547/37 +f 875/535/226 882/550/15 863/549/37 +f 863/549/37 852/536/15 875/535/226 +f 851/513/16 854/516/16 857/518/16 +f 857/518/16 856/517/16 851/513/16 +f 855/587/2 858/590/2 861/597/2 +f 861/597/2 860/598/2 855/587/2 +f 867/519/408 874/534/194 854/533/419 +f 854/533/419 853/520/409 867/519/408 +f 877/539/36 876/538/226 851/537/15 +f 851/537/15 856/540/37 877/539/36 +f 879/543/15 878/542/15 855/541/15 +f 855/541/15 860/544/15 879/543/15 +f 883/599/477 884/600/478 885/601/479 +f 885/601/479 886/602/480 883/599/477 +f 887/603/481 884/600/478 883/599/477 +f 883/599/477 888/604/482 887/603/481 +f 883/605/2 886/606/483 889/607/483 +f 889/607/483 890/608/484 883/605/2 +f 888/609/485 883/605/2 890/608/484 +f 890/608/484 891/610/486 888/609/485 +f 890/611/487 889/612/488 892/613/489 +f 892/613/489 893/614/490 890/611/487 +f 894/615/491 891/616/492 890/611/487 +f 890/611/487 893/614/490 894/615/491 +f 884/617/80 893/618/493 892/619/494 +f 892/619/494 885/620/494 884/617/80 +f 887/621/495 894/622/496 893/618/493 +f 893/618/493 884/617/80 887/621/495 +f 895/599/497 896/602/480 897/601/498 +f 897/601/498 898/600/499 895/599/497 +f 899/603/500 900/604/482 895/599/497 +f 895/599/497 898/600/499 899/603/500 +f 895/605/501 901/608/502 902/607/503 +f 902/607/503 896/606/504 895/605/501 +f 900/609/505 903/610/506 901/608/502 +f 901/608/502 895/605/501 900/609/505 +f 901/611/507 904/614/508 905/613/509 +f 905/613/509 902/612/488 901/611/507 +f 906/615/510 904/614/508 901/611/507 +f 901/611/507 903/616/492 906/615/510 +f 898/617/511 897/620/512 905/619/512 +f 905/619/512 904/618/513 898/617/511 +f 899/621/514 898/617/511 904/618/513 +f 904/618/513 906/622/515 899/621/514 +f 907/599/497 908/602/480 909/601/498 +f 909/601/498 910/600/499 907/599/497 +f 911/603/500 912/604/482 907/599/497 +f 907/599/497 910/600/499 911/603/500 +f 907/605/501 913/608/502 914/607/503 +f 914/607/503 908/606/504 907/605/501 +f 912/609/505 915/610/506 913/608/502 +f 913/608/502 907/605/501 912/609/505 +f 913/611/507 916/614/508 917/613/509 +f 917/613/509 914/612/488 913/611/507 +f 918/615/510 916/614/508 913/611/507 +f 913/611/507 915/616/492 918/615/510 +f 910/617/2 909/620/512 917/619/512 +f 917/619/512 916/618/513 910/617/2 +f 911/621/514 910/617/2 916/618/513 +f 916/618/513 918/622/515 911/621/514 +f 919/599/516 920/602/517 921/601/518 +f 921/601/518 922/600/519 919/599/516 +f 923/603/520 924/604/521 919/599/516 +f 919/599/516 922/600/519 923/603/520 +f 919/605/406 925/608/522 926/607/523 +f 926/607/523 920/606/483 919/605/406 +f 924/609/524 927/610/525 925/608/522 +f 925/608/522 919/605/406 924/609/524 +f 925/611/526 928/614/527 929/613/528 +f 929/613/528 926/612/529 925/611/526 +f 930/615/530 928/614/527 925/611/526 +f 925/611/526 927/616/531 930/615/530 +f 922/617/8 921/620/494 929/619/494 +f 929/619/494 928/618/532 922/617/8 +f 923/621/533 922/617/8 928/618/532 +f 928/618/532 930/622/534 923/621/533 +f 931/623/535 932/624/13 933/625/536 +f 933/625/536 934/626/537 931/623/535 +f 931/627/2 935/628/2 936/629/2 +f 936/629/2 932/630/2 931/627/2 +f 937/631/538 934/626/537 933/625/536 +f 933/625/536 938/632/13 937/631/538 +f 939/19/539 940/20/540 941/21/541 +f 941/21/541 942/22/542 939/19/539 +f 943/23/8 944/24/8 945/25/8 +f 945/25/8 946/26/8 943/23/8 +f 947/27/426 948/28/426 949/29/226 +f 949/29/226 950/30/226 947/27/426 +f 951/26/2 952/31/2 953/32/2 +f 953/32/2 954/23/2 951/26/2 +f 955/33/223 956/34/223 957/35/18 +f 957/35/18 958/36/18 955/33/223 +f 959/37/13 960/38/13 961/39/13 +f 962/40/13 947/41/13 950/42/13 +f 950/42/13 963/43/13 962/40/13 +f 964/44/13 965/45/13 966/46/13 +f 966/46/13 965/45/13 967/47/13 +f 967/47/13 968/48/13 966/46/13 +f 939/19/539 942/22/542 969/49/543 +f 969/49/543 970/50/544 939/19/539 +f 950/30/226 949/29/226 971/51/421 +f 971/51/421 972/52/421 950/30/226 +f 958/36/18 957/35/18 973/53/193 +f 973/53/193 974/54/193 958/36/18 +f 963/43/13 950/42/13 972/55/13 +f 972/55/13 975/56/13 963/43/13 +f 961/39/13 968/48/13 967/47/13 +f 967/47/13 959/37/13 961/39/13 +f 941/57/2 940/58/2 976/59/2 +f 976/59/545 962/60/545 941/57/545 +f 941/57/546 962/60/546 963/61/546 +f 963/61/547 942/62/547 941/57/547 +f 942/62/548 963/61/548 975/63/548 +f 975/63/548 969/64/548 942/62/548 +f 969/64/8 975/63/8 977/65/8 +f 977/65/8 970/66/8 969/64/8 +f 970/67/549 977/68/549 978/69/549 +f 978/69/550 939/70/550 970/67/550 +f 939/70/551 978/69/551 976/71/551 +f 976/71/552 940/72/552 939/70/552 +f 979/73/553 977/74/553 975/56/553 +f 975/56/554 972/55/554 979/73/554 +f 971/51/2 980/75/2 979/76/2 +f 979/76/2 972/52/2 971/51/2 +f 981/77/8 982/78/8 948/28/8 +f 948/28/8 947/27/8 981/77/8 +f 962/40/555 976/79/555 981/80/555 +f 981/80/556 947/41/556 962/40/556 +f 983/32/8 943/23/8 946/26/8 +f 946/26/8 984/31/8 983/32/8 +f 960/81/557 981/82/557 976/71/557 +f 976/71/557 961/83/557 960/81/557 +f 961/83/552 976/71/552 978/69/552 +f 978/69/552 968/84/552 961/83/552 +f 968/84/549 978/69/549 977/68/549 +f 977/68/558 966/85/558 968/84/558 +f 966/85/559 977/68/559 979/86/559 +f 979/86/559 964/87/559 966/85/559 +f 985/25/2 951/26/2 954/23/2 +f 954/23/2 986/24/2 985/25/2 +f 965/88/223 955/33/223 958/36/223 +f 958/36/223 967/89/223 965/88/223 +f 967/89/193 958/36/193 974/54/193 +f 974/54/193 959/90/193 967/89/193 +f 945/91/36 982/92/36 981/82/36 +f 981/82/36 946/93/36 945/91/36 +f 946/93/36 981/82/36 960/81/36 +f 960/81/36 984/94/36 946/93/36 +f 984/95/13 960/38/13 959/37/13 +f 959/37/13 983/96/13 984/95/13 +f 983/97/18 959/90/18 974/54/18 +f 974/54/18 943/98/18 983/97/18 +f 943/98/18 974/54/18 973/53/18 +f 973/53/18 944/99/18 943/98/18 +f 953/100/18 956/34/18 955/33/18 +f 955/33/18 954/101/18 953/100/18 +f 954/101/18 955/33/18 965/88/18 +f 965/88/18 986/102/18 954/101/18 +f 986/103/13 965/45/13 964/44/13 +f 964/44/13 985/104/13 986/103/13 +f 985/105/36 964/87/36 979/86/36 +f 979/86/36 951/106/36 985/105/36 +f 951/106/36 979/86/36 980/107/36 +f 980/107/36 952/108/36 951/106/36 +f 987/633/15 988/634/15 989/635/15 +f 989/635/15 990/636/15 987/633/15 +f 988/634/13 991/637/13 992/638/13 +f 992/638/13 989/635/13 988/634/13 +f 993/639/560 994/640/561 995/641/562 +f 995/641/562 996/642/563 993/639/560 +f 997/643/564 998/644/564 999/645/564 +f 999/645/565 1000/646/565 997/643/565 +f 1001/647/566 1000/646/566 999/645/566 +f 999/645/566 1002/648/566 1001/647/566 +f 994/640/561 1003/641/567 997/649/568 +f 997/649/568 1000/650/569 994/640/561 +f 993/639/560 1004/642/570 1003/641/567 +f 1003/641/567 994/640/561 993/639/560 +f 1001/649/571 995/641/562 994/640/561 +f 994/640/561 1000/650/569 1001/649/571 +f 997/651/2 1003/652/2 1005/653/2 +f 1005/653/2 998/654/2 997/651/2 +f 1006/654/8 995/651/8 1001/652/8 +f 1001/652/8 1002/653/8 1006/654/8 +f 998/655/572 1005/656/572 1007/657/572 +f 1007/657/573 999/658/573 998/655/573 +f 1007/657/574 1006/659/574 1002/660/574 +f 1002/660/575 999/658/575 1007/657/575 +f 1008/661/13 1009/662/13 1010/663/13 +f 1010/663/13 1011/664/13 1008/661/13 +f 1012/665/576 1013/666/577 1014/667/578 +f 1014/667/578 1015/668/578 1012/665/576 +f 1012/669/579 1015/670/580 1016/671/580 +f 1016/671/580 1017/672/579 1012/669/579 +f 1017/665/581 1016/668/582 1018/667/582 +f 1018/667/582 1019/666/583 1017/665/581 +f 1019/672/584 1018/671/585 1014/670/585 +f 1014/670/585 1013/669/584 1019/672/584 +f 1013/666/577 1012/665/576 1010/673/586 +f 1010/673/586 1009/674/586 1013/666/577 +f 1012/669/579 1017/672/579 1011/675/587 +f 1011/675/587 1010/676/587 1012/669/579 +f 1011/673/588 1017/665/581 1019/666/583 +f 1019/666/583 1008/674/588 1011/673/588 +f 1019/672/584 1013/669/584 1009/676/589 +f 1009/676/589 1008/675/589 1019/672/584 +f 1020/203/8 1021/204/8 1022/205/8 +f 1022/205/8 1023/206/8 1020/203/8 +f 1023/206/590 1022/207/590 1024/208/590 +f 1024/208/591 1025/209/591 1023/206/591 +f 1026/210/592 1020/203/592 1023/206/592 +f 1023/206/592 1025/209/592 1026/210/592 +f 1027/211/593 1021/212/593 1020/203/593 +f 1020/203/594 1026/210/594 1027/211/594 +f 1025/209/595 1024/208/595 1028/213/595 +f 1028/213/596 1029/214/596 1025/209/596 +f 1029/214/597 1030/215/597 1026/210/597 +f 1026/210/598 1025/209/598 1029/214/598 +f 1026/210/599 1030/215/599 1031/216/599 +f 1031/216/600 1027/211/600 1026/210/600 +f 1032/217/2 1033/218/2 1034/219/2 +f 1034/219/2 1035/220/2 1032/217/2 +f 1036/221/601 1032/222/601 1035/220/601 +f 1035/220/595 1037/223/595 1036/221/595 +f 1038/224/602 1037/223/602 1035/220/602 +f 1035/220/602 1034/219/602 1038/224/602 +f 1039/225/599 1038/224/599 1034/219/599 +f 1034/219/599 1033/226/599 1039/225/599 +f 1028/227/591 1036/221/591 1037/223/591 +f 1037/223/603 1029/214/603 1028/227/603 +f 1038/224/604 1030/215/604 1029/214/604 +f 1029/214/605 1037/223/605 1038/224/605 +f 1038/224/606 1039/225/606 1031/228/606 +f 1031/228/594 1030/215/594 1038/224/594 +f 1040/229/8 1041/230/8 1042/231/8 +f 1042/231/8 1043/232/8 1040/229/8 +f 1044/233/607 1045/234/607 1043/232/607 +f 1043/232/592 1042/231/592 1044/233/592 +f 1046/235/608 1044/233/608 1042/231/608 +f 1042/231/608 1041/236/608 1046/235/608 +f 1044/233/598 1047/237/598 1048/238/598 +f 1048/238/598 1045/234/598 1044/233/598 +f 1044/233/609 1046/239/609 1049/240/609 +f 1049/240/596 1047/237/596 1044/233/596 +f 1050/241/2 1051/242/2 1052/243/2 +f 1052/243/2 1053/244/2 1050/241/2 +f 1054/245/602 1050/241/602 1053/244/602 +f 1053/244/602 1055/246/602 1054/245/602 +f 1056/247/608 1051/248/608 1050/241/608 +f 1050/241/608 1054/245/608 1056/247/608 +f 1048/238/605 1047/237/605 1054/245/605 +f 1054/245/605 1055/246/605 1048/238/605 +f 1054/245/603 1047/237/603 1049/240/603 +f 1049/240/608 1056/249/608 1054/245/608 +f 1057/229/8 1058/230/8 1059/231/8 +f 1059/231/8 1060/232/8 1057/229/8 +f 1061/233/610 1062/234/610 1060/232/610 +f 1060/232/611 1059/231/611 1061/233/611 +f 1063/235/612 1061/233/612 1059/231/612 +f 1059/231/613 1058/236/613 1063/235/613 +f 1061/233/614 1064/237/614 1065/238/614 +f 1065/238/615 1062/234/615 1061/233/615 +f 1061/233/616 1063/239/616 1066/240/616 +f 1066/240/612 1064/237/612 1061/233/612 +f 1067/241/2 1068/242/2 1069/243/2 +f 1069/243/2 1070/244/2 1067/241/2 +f 1071/245/617 1067/241/617 1070/244/617 +f 1070/244/618 1072/246/618 1071/245/618 +f 1073/247/612 1068/248/612 1067/241/612 +f 1067/241/613 1071/245/613 1073/247/613 +f 1065/238/619 1064/237/619 1071/245/619 +f 1071/245/620 1072/246/620 1065/238/620 +f 1071/245/613 1064/237/613 1066/240/613 +f 1066/240/621 1073/249/621 1071/245/621 +f 1074/229/8 1075/230/8 1076/231/8 +f 1076/231/8 1077/232/8 1074/229/8 +f 1078/233/622 1079/234/622 1077/232/622 +f 1077/232/622 1076/231/622 1078/233/622 +f 1080/235/623 1078/233/623 1076/231/623 +f 1076/231/624 1075/236/624 1080/235/624 +f 1078/233/625 1081/237/625 1082/238/625 +f 1082/238/626 1079/234/626 1078/233/626 +f 1078/233/624 1080/239/624 1083/240/624 +f 1083/240/627 1081/237/627 1078/233/627 +f 1084/241/2 1085/242/2 1086/243/2 +f 1086/243/2 1087/244/2 1084/241/2 +f 1088/245/628 1084/241/628 1087/244/628 +f 1087/244/628 1089/246/628 1088/245/628 +f 1090/247/623 1085/248/623 1084/241/623 +f 1084/241/624 1088/245/624 1090/247/624 +f 1082/238/629 1081/237/629 1088/245/629 +f 1088/245/630 1089/246/630 1082/238/630 +f 1088/245/631 1081/237/631 1083/240/631 +f 1083/240/623 1090/249/623 1088/245/623 +f 1091/229/8 1092/230/8 1093/231/8 +f 1093/231/8 1094/232/8 1091/229/8 +f 1095/233/632 1096/234/632 1094/232/632 +f 1094/232/622 1093/231/622 1095/233/622 +f 1097/235/623 1095/233/623 1093/231/623 +f 1093/231/623 1092/236/623 1097/235/623 +f 1095/233/626 1098/237/626 1099/238/626 +f 1099/238/626 1096/234/626 1095/233/626 +f 1095/233/631 1097/239/631 1100/240/631 +f 1100/240/624 1098/237/624 1095/233/624 +f 1101/241/2 1102/242/2 1103/243/2 +f 1103/243/2 1104/244/2 1101/241/2 +f 1105/245/628 1101/241/628 1104/244/628 +f 1104/244/633 1106/246/633 1105/245/633 +f 1107/247/624 1102/248/624 1101/241/624 +f 1101/241/624 1105/245/624 1107/247/624 +f 1099/238/630 1098/237/630 1105/245/630 +f 1105/245/630 1106/246/630 1099/238/630 +f 1105/245/623 1098/237/623 1100/240/623 +f 1100/240/627 1107/249/627 1105/245/627 +f 1108/229/8 1109/230/8 1110/231/8 +f 1110/231/8 1111/232/8 1108/229/8 +f 1112/233/622 1113/234/622 1111/232/622 +f 1111/232/622 1110/231/622 1112/233/622 +f 1114/235/624 1112/233/624 1110/231/624 +f 1110/231/624 1109/236/624 1114/235/624 +f 1112/233/625 1115/237/625 1116/238/625 +f 1116/238/626 1113/234/626 1112/233/626 +f 1112/233/624 1114/239/624 1117/240/624 +f 1117/240/624 1115/237/624 1112/233/624 +f 1118/241/2 1119/242/2 1120/243/2 +f 1120/243/2 1121/244/2 1118/241/2 +f 1122/245/628 1118/241/628 1121/244/628 +f 1121/244/628 1123/246/628 1122/245/628 +f 1124/247/623 1119/248/623 1118/241/623 +f 1118/241/623 1122/245/623 1124/247/623 +f 1116/238/629 1115/237/629 1122/245/629 +f 1122/245/630 1123/246/630 1116/238/630 +f 1122/245/623 1115/237/623 1117/240/623 +f 1117/240/623 1124/249/623 1122/245/623 +f 1125/229/8 1126/230/8 1127/231/8 +f 1127/231/8 1128/232/8 1125/229/8 +f 1129/233/634 1130/234/634 1128/232/634 +f 1128/232/634 1127/231/634 1129/233/634 +f 1131/235/635 1129/233/635 1127/231/635 +f 1127/231/636 1126/236/636 1131/235/636 +f 1129/233/637 1132/237/637 1133/238/637 +f 1133/238/638 1130/234/638 1129/233/638 +f 1129/233/635 1131/239/635 1134/240/635 +f 1134/240/635 1132/237/635 1129/233/635 +f 1135/241/2 1136/242/2 1137/243/2 +f 1137/243/2 1138/244/2 1135/241/2 +f 1139/245/639 1135/241/639 1138/244/639 +f 1138/244/639 1140/246/639 1139/245/639 +f 1141/247/640 1136/248/640 1135/241/640 +f 1135/241/641 1139/245/641 1141/247/641 +f 1133/238/642 1132/237/642 1139/245/642 +f 1139/245/643 1140/246/643 1133/238/643 +f 1139/245/641 1132/237/641 1134/240/641 +f 1134/240/641 1141/249/641 1139/245/641 +f 1142/231/8 1143/230/8 1144/229/8 +f 1144/229/8 1145/232/8 1142/231/8 +f 1145/232/644 1146/234/644 1147/233/644 +f 1147/233/644 1142/231/644 1145/232/644 +f 1142/231/645 1147/233/645 1148/235/645 +f 1148/235/645 1143/236/645 1142/231/645 +f 1149/238/646 1150/237/646 1147/233/646 +f 1147/233/647 1146/234/647 1149/238/647 +f 1147/233/648 1150/237/648 1151/240/648 +f 1151/240/648 1148/239/648 1147/233/648 +f 1152/243/2 1153/242/2 1154/241/2 +f 1154/241/2 1155/244/2 1152/243/2 +f 1155/244/649 1154/241/649 1156/245/649 +f 1156/245/649 1157/246/649 1155/244/649 +f 1154/241/648 1153/248/648 1158/247/648 +f 1158/247/648 1156/245/648 1154/241/648 +f 1156/245/650 1150/237/650 1149/238/650 +f 1149/238/651 1157/246/651 1156/245/651 +f 1156/245/645 1158/249/645 1151/240/645 +f 1151/240/645 1150/237/645 1156/245/645 +f 1159/231/8 1160/230/8 1161/229/8 +f 1161/229/8 1162/232/8 1159/231/8 +f 1162/232/622 1163/234/622 1164/233/622 +f 1164/233/652 1159/231/652 1162/232/652 +f 1159/231/653 1164/233/653 1165/235/653 +f 1165/235/653 1160/236/653 1159/231/653 +f 1166/238/625 1167/237/625 1164/233/625 +f 1164/233/626 1163/234/626 1166/238/626 +f 1164/233/653 1167/237/653 1168/240/653 +f 1168/240/654 1165/239/654 1164/233/654 +f 1169/243/2 1170/242/2 1171/241/2 +f 1171/241/2 1172/244/2 1169/243/2 +f 1172/244/628 1171/241/628 1173/245/628 +f 1173/245/628 1174/246/628 1172/244/628 +f 1171/241/654 1170/248/654 1175/247/654 +f 1175/247/654 1173/245/654 1171/241/654 +f 1173/245/629 1167/237/629 1166/238/629 +f 1166/238/630 1174/246/630 1173/245/630 +f 1173/245/653 1175/249/653 1168/240/653 +f 1168/240/654 1167/237/654 1173/245/654 +f 1176/677/36 1177/678/36 1178/679/36 +f 1178/679/36 1179/680/36 1176/677/36 +f 1180/681/2 1176/677/2 1179/680/2 +f 1179/680/2 1181/682/2 1180/681/2 +f 937/627/8 938/630/8 1182/629/8 +f 1182/629/8 1183/628/8 937/627/8 +f 1184/683/15 1185/684/15 1186/685/15 +f 1186/685/15 1187/686/15 1184/683/15 +f 1185/684/8 1188/687/8 1189/688/8 +f 1189/688/8 1186/685/8 1185/684/8 +f 1190/599/655 1191/600/656 1192/601/657 +f 1192/601/657 1193/602/658 1190/599/655 +f 1194/603/659 1191/600/656 1190/599/655 +f 1190/599/655 1195/604/660 1194/603/659 +f 1190/605/13 1193/606/661 1196/607/661 +f 1196/607/661 1197/608/662 1190/605/13 +f 1195/609/663 1190/605/13 1197/608/662 +f 1197/608/662 1198/610/664 1195/609/663 +f 1197/611/665 1196/612/666 1199/613/667 +f 1199/613/667 1200/614/668 1197/611/665 +f 1201/615/669 1198/616/670 1197/611/665 +f 1197/611/665 1200/614/668 1201/615/669 +f 1191/617/16 1200/618/671 1199/619/672 +f 1199/619/672 1192/620/672 1191/617/16 +f 1194/621/673 1201/622/674 1200/618/671 +f 1200/618/671 1191/617/16 1194/621/673 +f 1202/599/675 1203/602/676 1204/601/677 +f 1204/601/677 1205/600/678 1202/599/675 +f 1206/603/679 1207/604/680 1202/599/675 +f 1202/599/675 1205/600/678 1206/603/679 +f 1202/605/681 1208/608/682 1209/607/683 +f 1209/607/683 1203/606/661 1202/605/681 +f 1207/609/684 1210/610/685 1208/608/682 +f 1208/608/682 1202/605/681 1207/609/684 +f 1208/611/686 1211/614/687 1212/613/688 +f 1212/613/688 1209/612/689 1208/611/686 +f 1213/615/690 1211/614/687 1208/611/686 +f 1208/611/686 1210/616/691 1213/615/690 +f 1205/617/16 1204/620/672 1212/619/672 +f 1212/619/672 1211/618/692 1205/617/16 +f 1206/621/693 1205/617/16 1211/618/692 +f 1211/618/692 1213/622/694 1206/621/693 +f 1214/599/695 1215/602/517 1216/601/518 +f 1216/601/518 1217/600/519 1214/599/695 +f 1218/603/520 1219/604/521 1214/599/695 +f 1214/599/695 1217/600/519 1218/603/520 +f 1214/605/406 1220/608/696 1221/607/523 +f 1221/607/523 1215/606/483 1214/605/406 +f 1219/609/524 1222/610/525 1220/608/696 +f 1220/608/696 1214/605/406 1219/609/524 +f 1220/611/526 1223/614/527 1224/613/528 +f 1224/613/528 1221/612/529 1220/611/526 +f 1225/615/530 1223/614/527 1220/611/526 +f 1220/611/526 1222/616/531 1225/615/530 +f 1217/617/8 1216/620/494 1224/619/494 +f 1224/619/494 1223/618/532 1217/617/8 +f 1218/621/533 1217/617/8 1223/618/532 +f 1223/618/532 1225/622/534 1218/621/533 +f 1226/599/477 1227/600/478 1228/601/479 +f 1228/601/479 1229/602/480 1226/599/477 +f 1230/603/481 1227/600/478 1226/599/477 +f 1226/599/477 1231/604/482 1230/603/481 +f 1226/605/2 1229/606/483 1232/607/483 +f 1232/607/483 1233/608/484 1226/605/2 +f 1231/609/485 1226/605/2 1233/608/484 +f 1233/608/484 1234/610/486 1231/609/485 +f 1233/611/487 1232/612/488 1235/613/489 +f 1235/613/489 1236/614/490 1233/611/487 +f 1237/615/491 1234/616/492 1233/611/487 +f 1233/611/487 1236/614/490 1237/615/491 +f 1227/617/8 1236/618/493 1235/619/494 +f 1235/619/494 1228/620/494 1227/617/8 +f 1230/621/495 1237/622/496 1236/618/493 +f 1236/618/493 1227/617/8 1230/621/495 +f 1238/599/697 1239/600/698 1240/601/699 +f 1240/601/699 1241/602/517 1238/599/697 +f 1242/603/700 1239/600/698 1238/599/697 +f 1238/599/697 1243/604/521 1242/603/700 +f 1238/605/80 1241/606/504 1244/607/504 +f 1244/607/504 1245/608/701 1238/605/80 +f 1243/609/702 1238/605/80 1245/608/701 +f 1245/608/701 1246/610/703 1243/609/702 +f 1245/611/704 1244/612/529 1247/613/705 +f 1247/613/705 1248/614/706 1245/611/704 +f 1249/615/707 1246/616/531 1245/611/704 +f 1245/611/704 1248/614/706 1249/615/707 +f 1239/617/2 1248/618/708 1247/619/512 +f 1247/619/512 1240/620/512 1239/617/2 +f 1242/621/709 1249/622/710 1248/618/708 +f 1248/618/708 1239/617/2 1242/621/709 +f 1250/599/697 1251/600/711 1252/601/699 +f 1252/601/699 1253/602/517 1250/599/697 +f 1254/603/700 1251/600/711 1250/599/697 +f 1250/599/697 1255/604/521 1254/603/700 +f 1250/605/8 1253/606/504 1256/607/504 +f 1256/607/504 1257/608/712 1250/605/8 +f 1255/609/702 1250/605/8 1257/608/712 +f 1257/608/712 1258/610/703 1255/609/702 +f 1257/611/704 1256/612/529 1259/613/705 +f 1259/613/705 1260/614/706 1257/611/704 +f 1261/615/707 1258/616/531 1257/611/704 +f 1257/611/704 1260/614/706 1261/615/707 +f 1251/617/2 1260/618/708 1259/619/512 +f 1259/619/512 1252/620/512 1251/617/2 +f 1254/621/709 1261/622/710 1260/618/708 +f 1260/618/708 1251/617/2 1254/621/709 +f 1262/599/713 1263/600/711 1264/601/699 +f 1264/601/699 1265/602/517 1262/599/713 +f 1266/603/700 1263/600/711 1262/599/713 +f 1262/599/713 1267/604/521 1266/603/700 +f 1262/605/8 1265/606/504 1268/607/504 +f 1268/607/504 1269/608/712 1262/605/8 +f 1267/609/702 1262/605/8 1269/608/712 +f 1269/608/712 1270/610/703 1267/609/702 +f 1269/611/704 1268/612/529 1271/613/705 +f 1271/613/705 1272/614/706 1269/611/704 +f 1273/615/707 1270/616/531 1269/611/704 +f 1269/611/704 1272/614/706 1273/615/707 +f 1263/617/2 1272/618/708 1271/619/512 +f 1271/619/512 1264/620/512 1263/617/2 +f 1266/621/709 1273/622/710 1272/618/708 +f 1272/618/708 1263/617/2 1266/621/709 +f 1274/599/516 1275/602/517 1276/601/518 +f 1276/601/518 1277/600/714 1274/599/516 +f 1278/603/520 1279/604/521 1274/599/516 +f 1274/599/516 1277/600/714 1278/603/520 +f 1274/605/406 1280/608/522 1281/607/523 +f 1281/607/523 1275/606/483 1274/605/406 +f 1279/609/524 1282/610/525 1280/608/522 +f 1280/608/522 1274/605/406 1279/609/524 +f 1280/611/526 1283/614/527 1284/613/528 +f 1284/613/528 1281/612/529 1280/611/526 +f 1285/615/530 1283/614/527 1280/611/526 +f 1280/611/526 1282/616/531 1285/615/530 +f 1277/617/8 1276/620/494 1284/619/494 +f 1284/619/494 1283/618/532 1277/617/8 +f 1278/621/533 1277/617/8 1283/618/532 +f 1283/618/532 1285/622/534 1278/621/533 +f 1286/599/477 1287/600/478 1288/601/479 +f 1288/601/479 1289/602/480 1286/599/477 +f 1290/603/481 1287/600/478 1286/599/477 +f 1286/599/477 1291/604/482 1290/603/481 +f 1286/605/2 1289/606/483 1292/607/483 +f 1292/607/483 1293/608/484 1286/605/2 +f 1291/609/485 1286/605/2 1293/608/484 +f 1293/608/484 1294/610/486 1291/609/485 +f 1293/611/487 1292/612/488 1295/613/489 +f 1295/613/489 1296/614/490 1293/611/487 +f 1297/615/491 1294/616/492 1293/611/487 +f 1293/611/487 1296/614/490 1297/615/491 +f 1287/617/8 1296/618/493 1295/619/494 +f 1295/619/494 1288/620/494 1287/617/8 +f 1290/621/495 1297/622/496 1296/618/493 +f 1296/618/493 1287/617/8 1290/621/495 +f 1298/689/715 1299/690/716 1300/691/717 +f 1300/691/717 1301/692/718 1298/689/715 +f 1302/693/719 1299/690/719 1298/689/720 +f 1298/689/720 1303/694/720 1302/693/719 +f 1304/695/721 1305/696/722 1306/697/723 +f 1306/697/723 1307/698/723 1304/695/721 +f 1308/699/724 1309/700/724 1310/701/725 +f 1310/701/725 1311/702/725 1308/699/724 +f 1312/703/726 1301/692/727 1313/704/728 +f 1313/704/728 1314/705/728 1312/703/726 +f 1306/697/729 1305/696/730 1300/691/717 +f 1300/691/717 1299/690/716 1306/697/729 +f 1307/698/731 1306/697/731 1299/690/719 +f 1299/690/719 1302/706/719 1307/698/731 +f 1314/707/732 1313/704/732 1309/700/724 +f 1309/700/724 1308/699/724 1314/707/732 +f 1309/700/733 1313/704/734 1301/692/718 +f 1301/692/718 1300/691/717 1309/700/733 +f 1311/708/735 1310/701/735 1305/696/722 +f 1305/696/722 1304/695/721 1311/708/735 +f 1303/694/736 1298/689/736 1301/692/727 +f 1301/692/727 1312/703/726 1303/694/736 +f 1305/696/730 1310/701/737 1309/700/733 +f 1309/700/733 1300/691/717 1305/696/730 +f 1315/709/738 1316/710/739 1317/711/740 +f 1317/711/740 1318/712/741 1315/709/738 +f 1319/713/742 1320/714/742 1316/715/742 +f 1316/715/742 1315/716/742 1319/713/742 +f 1321/712/743 1322/711/744 1320/710/745 +f 1320/710/745 1319/709/746 1321/712/743 +f 1321/717/747 1318/718/747 1317/719/747 +f 1317/719/747 1322/720/747 1321/717/747 +f 1323/721/36 1324/722/36 1325/723/36 +f 1325/723/36 1326/724/36 1323/721/36 +f 1327/725/748 1328/726/748 1329/727/749 +f 1329/727/749 1330/728/749 1327/725/748 +f 1326/729/750 1325/730/750 1328/726/748 +f 1328/726/748 1327/725/748 1326/729/750 +f 1331/731/751 1327/732/752 1330/733/753 +f 1330/733/753 1332/734/753 1331/731/751 +f 1323/735/754 1326/736/754 1327/732/752 +f 1327/732/752 1331/731/751 1323/735/754 +f 1333/726/755 1331/725/755 1332/728/756 +f 1332/728/756 1334/727/756 1333/726/755 +f 1324/730/757 1323/729/757 1331/725/755 +f 1331/725/755 1333/726/755 1324/730/757 +f 1328/737/758 1333/738/758 1334/739/759 +f 1334/739/759 1329/740/759 1328/737/758 +f 1325/741/760 1324/742/760 1333/738/758 +f 1333/738/758 1328/737/758 1325/741/760 +f 1335/743/36 1336/744/36 1337/745/36 +f 1337/745/36 1338/746/36 1335/743/36 +f 1339/747/761 1340/748/761 1341/749/762 +f 1341/749/762 1342/750/762 1339/747/761 +f 1338/751/763 1337/752/763 1340/748/761 +f 1340/748/761 1339/747/761 1338/751/763 +f 1343/753/764 1339/754/765 1342/755/766 +f 1342/755/766 1344/756/766 1343/753/764 +f 1335/757/767 1338/758/767 1339/754/765 +f 1339/754/765 1343/753/764 1335/757/767 +f 1345/748/768 1343/747/769 1344/750/770 +f 1344/750/770 1346/749/770 1345/748/768 +f 1336/752/771 1335/751/771 1343/747/769 +f 1343/747/769 1345/748/768 1336/752/771 +f 1340/754/772 1345/759/773 1346/760/774 +f 1346/760/774 1341/755/774 1340/754/772 +f 1337/758/775 1336/761/775 1345/759/773 +f 1345/759/773 1340/754/772 1337/758/775 +f 1347/762/776 1348/763/777 1349/764/778 +f 1349/764/778 1350/765/778 1347/762/776 +f 1351/766/779 1352/767/779 1348/763/777 +f 1348/763/777 1347/762/776 1351/766/779 +f 1353/768/780 1347/769/781 1350/770/782 +f 1350/770/782 1354/771/782 1353/768/780 +f 1355/772/783 1351/773/783 1347/769/781 +f 1347/769/781 1353/768/780 1355/772/783 +f 1356/763/784 1353/762/785 1354/765/786 +f 1354/765/786 1357/764/786 1356/763/784 +f 1358/767/787 1355/766/787 1353/762/785 +f 1353/762/785 1356/763/784 1358/767/787 +f 1348/774/788 1356/768/789 1357/771/790 +f 1357/771/790 1349/775/790 1348/774/788 +f 1352/776/791 1358/777/791 1356/768/789 +f 1356/768/789 1348/774/788 1352/776/791 +f 1359/778/792 1360/779/793 1361/780/794 +f 1361/780/794 1362/781/794 1359/778/792 +f 1363/782/795 1364/783/795 1360/779/793 +f 1360/779/793 1359/778/792 1363/782/795 +f 1365/784/796 1359/785/797 1362/786/798 +f 1362/786/798 1366/787/798 1365/784/796 +f 1367/788/799 1363/789/799 1359/785/797 +f 1359/785/797 1365/784/796 1367/788/799 +f 1368/790/800 1365/791/801 1366/792/802 +f 1366/792/802 1369/793/802 1368/790/800 +f 1370/794/803 1367/795/803 1365/791/801 +f 1365/791/801 1368/790/800 1370/794/803 +f 1360/785/804 1368/796/805 1369/787/806 +f 1369/787/806 1361/797/806 1360/785/804 +f 1364/789/807 1370/798/807 1368/796/805 +f 1368/796/805 1360/785/804 1364/789/807 +f 1371/799/36 1372/800/36 1373/801/36 +f 1373/801/36 1374/802/36 1371/799/36 +f 1375/803/808 1376/804/809 1377/805/810 +f 1377/805/810 1378/806/810 1375/803/808 +f 1374/807/811 1373/808/811 1376/804/809 +f 1376/804/809 1375/803/808 1374/807/811 +f 1379/809/812 1375/810/812 1378/811/813 +f 1378/811/813 1380/812/813 1379/809/812 +f 1371/813/814 1374/814/814 1375/810/812 +f 1375/810/812 1379/809/812 1371/813/814 +f 1381/804/815 1379/803/816 1380/806/817 +f 1380/806/817 1382/805/817 1381/804/815 +f 1372/808/818 1371/807/818 1379/803/816 +f 1379/803/816 1381/804/815 1372/808/818 +f 1376/815/819 1381/809/819 1382/816/820 +f 1382/816/820 1377/817/820 1376/815/819 +f 1373/818/821 1372/819/822 1381/809/819 +f 1381/809/819 1376/815/819 1373/818/821 +f 1383/820/36 1384/821/36 1385/822/36 +f 1385/822/36 1386/823/36 1383/820/36 +f 1387/824/823 1388/825/824 1389/826/825 +f 1389/826/825 1390/827/825 1387/824/823 +f 1386/828/826 1385/829/826 1388/825/824 +f 1388/825/824 1387/824/823 1386/828/826 +f 1391/737/827 1387/738/828 1390/734/829 +f 1390/734/829 1392/740/829 1391/737/827 +f 1383/741/830 1386/735/830 1387/738/828 +f 1387/738/828 1391/737/827 1383/741/830 +f 1393/825/831 1391/824/832 1392/827/833 +f 1392/827/833 1394/826/833 1393/825/831 +f 1384/829/834 1383/828/834 1391/824/832 +f 1391/824/832 1393/825/831 1384/829/834 +f 1388/731/835 1393/737/836 1394/733/837 +f 1394/733/837 1389/830/837 1388/731/835 +f 1385/831/838 1384/736/838 1393/737/836 +f 1393/737/836 1388/731/835 1385/831/838 +f 1395/832/36 1396/833/36 1397/834/36 +f 1397/834/36 1398/835/36 1395/832/36 +f 1399/836/839 1400/837/839 1401/838/840 +f 1401/838/840 1402/839/840 1399/836/839 +f 1398/840/841 1397/841/841 1400/837/839 +f 1400/837/839 1399/836/839 1398/840/841 +f 1403/737/842 1399/731/842 1402/734/843 +f 1402/734/843 1404/733/843 1403/737/842 +f 1395/741/844 1398/735/844 1399/731/842 +f 1399/731/842 1403/737/842 1395/741/844 +f 1405/837/845 1403/836/845 1404/839/846 +f 1404/839/846 1406/838/846 1405/837/845 +f 1396/841/847 1395/840/847 1403/836/845 +f 1403/836/845 1405/837/845 1396/841/847 +f 1400/842/848 1405/732/848 1406/843/849 +f 1406/843/849 1401/734/849 1400/842/848 +f 1397/831/850 1396/736/851 1405/732/848 +f 1405/732/848 1400/842/848 1397/831/850 +f 1407/721/36 1408/722/36 1409/723/36 +f 1409/723/36 1410/724/36 1407/721/36 +f 1411/725/852 1412/726/748 1413/727/749 +f 1413/727/749 1414/728/749 1411/725/852 +f 1410/729/750 1409/730/750 1412/726/748 +f 1412/726/748 1411/725/852 1410/729/750 +f 1415/731/751 1411/732/752 1414/733/753 +f 1414/733/753 1416/734/753 1415/731/751 +f 1407/735/754 1410/736/754 1411/732/752 +f 1411/732/752 1415/731/751 1407/735/754 +f 1417/726/755 1415/725/755 1416/728/756 +f 1416/728/756 1418/727/756 1417/726/755 +f 1408/730/757 1407/729/757 1415/725/755 +f 1415/725/755 1417/726/755 1408/730/757 +f 1412/737/758 1417/738/758 1418/739/759 +f 1418/739/759 1413/740/759 1412/737/758 +f 1409/741/760 1408/742/760 1417/738/758 +f 1417/738/758 1412/737/758 1409/741/760 +f 1419/743/36 1420/744/36 1421/745/36 +f 1421/745/36 1422/746/36 1419/743/36 +f 1423/747/761 1424/748/761 1425/749/762 +f 1425/749/762 1426/750/762 1423/747/761 +f 1422/751/763 1421/752/763 1424/748/761 +f 1424/748/761 1423/747/761 1422/751/763 +f 1427/753/764 1423/754/765 1426/755/766 +f 1426/755/766 1428/756/766 1427/753/764 +f 1419/757/767 1422/758/767 1423/754/765 +f 1423/754/765 1427/753/764 1419/757/767 +f 1429/748/768 1427/747/769 1428/750/770 +f 1428/750/770 1430/749/770 1429/748/768 +f 1420/752/771 1419/751/771 1427/747/769 +f 1427/747/769 1429/748/768 1420/752/771 +f 1424/754/772 1429/759/773 1430/760/774 +f 1430/760/774 1425/755/774 1424/754/772 +f 1421/758/775 1420/761/775 1429/759/773 +f 1429/759/773 1424/754/772 1421/758/775 +f 1431/762/776 1432/763/777 1433/764/778 +f 1433/764/778 1434/765/778 1431/762/776 +f 1435/766/779 1436/767/779 1432/763/777 +f 1432/763/777 1431/762/776 1435/766/779 +f 1437/768/780 1431/769/781 1434/770/782 +f 1434/770/782 1438/771/782 1437/768/780 +f 1439/772/783 1435/773/783 1431/769/781 +f 1431/769/781 1437/768/780 1439/772/783 +f 1440/763/784 1437/762/785 1438/765/786 +f 1438/765/786 1441/764/786 1440/763/784 +f 1442/767/787 1439/766/787 1437/762/785 +f 1437/762/785 1440/763/784 1442/767/787 +f 1432/774/788 1440/768/789 1441/771/790 +f 1441/771/790 1433/775/790 1432/774/788 +f 1436/776/791 1442/777/791 1440/768/789 +f 1440/768/789 1432/774/788 1436/776/791 +f 1443/778/792 1444/779/793 1445/780/794 +f 1445/780/794 1446/781/794 1443/778/792 +f 1447/782/795 1448/783/795 1444/779/793 +f 1444/779/793 1443/778/792 1447/782/795 +f 1449/784/796 1443/785/797 1446/786/798 +f 1446/786/798 1450/787/798 1449/784/796 +f 1451/788/799 1447/789/799 1443/785/797 +f 1443/785/797 1449/784/796 1451/788/799 +f 1452/790/853 1449/791/854 1450/792/802 +f 1450/792/802 1453/793/802 1452/790/853 +f 1454/794/803 1451/795/803 1449/791/854 +f 1449/791/854 1452/790/853 1454/794/803 +f 1444/785/804 1452/796/805 1453/787/806 +f 1453/787/806 1445/797/806 1444/785/804 +f 1448/789/807 1454/798/807 1452/796/805 +f 1452/796/805 1444/785/804 1448/789/807 +f 1455/799/36 1456/800/36 1457/801/36 +f 1457/801/36 1458/802/36 1455/799/36 +f 1459/803/855 1460/804/856 1461/805/810 +f 1461/805/810 1462/806/810 1459/803/855 +f 1458/807/811 1457/808/811 1460/804/856 +f 1460/804/856 1459/803/855 1458/807/811 +f 1463/809/812 1459/810/812 1462/811/813 +f 1462/811/813 1464/812/813 1463/809/812 +f 1455/813/814 1458/814/814 1459/810/812 +f 1459/810/812 1463/809/812 1455/813/814 +f 1465/804/815 1463/803/816 1464/806/817 +f 1464/806/817 1466/805/817 1465/804/815 +f 1456/808/818 1455/807/818 1463/803/816 +f 1463/803/816 1465/804/815 1456/808/818 +f 1460/815/819 1465/809/819 1466/816/820 +f 1466/816/820 1461/817/820 1460/815/819 +f 1457/818/821 1456/819/822 1465/809/819 +f 1465/809/819 1460/815/819 1457/818/821 +f 1467/820/36 1468/821/36 1469/822/36 +f 1469/822/36 1470/823/36 1467/820/36 +f 1471/824/857 1472/825/858 1473/826/825 +f 1473/826/825 1474/827/825 1471/824/857 +f 1470/828/826 1469/829/826 1472/825/858 +f 1472/825/858 1471/824/857 1470/828/826 +f 1475/737/827 1471/738/828 1474/734/829 +f 1474/734/829 1476/740/829 1475/737/827 +f 1467/741/830 1470/735/830 1471/738/828 +f 1471/738/828 1475/737/827 1467/741/830 +f 1477/825/831 1475/824/832 1476/827/833 +f 1476/827/833 1478/826/833 1477/825/831 +f 1468/829/834 1467/828/834 1475/824/832 +f 1475/824/832 1477/825/831 1468/829/834 +f 1472/731/835 1477/737/836 1478/733/837 +f 1478/733/837 1473/830/837 1472/731/835 +f 1469/831/838 1468/736/838 1477/737/836 +f 1477/737/836 1472/731/835 1469/831/838 +f 1479/832/36 1480/833/36 1481/834/36 +f 1481/834/36 1482/835/36 1479/832/36 +f 1483/836/839 1484/837/839 1485/838/840 +f 1485/838/840 1486/839/840 1483/836/839 +f 1482/840/841 1481/841/841 1484/837/839 +f 1484/837/839 1483/836/839 1482/840/841 +f 1487/737/842 1483/731/842 1486/734/843 +f 1486/734/843 1488/733/843 1487/737/842 +f 1479/741/844 1482/735/844 1483/731/842 +f 1483/731/842 1487/737/842 1479/741/844 +f 1489/837/859 1487/836/859 1488/839/846 +f 1488/839/846 1490/838/846 1489/837/859 +f 1480/841/847 1479/840/847 1487/836/859 +f 1487/836/859 1489/837/859 1480/841/847 +f 1484/842/848 1489/732/848 1490/843/849 +f 1490/843/849 1485/734/849 1484/842/848 +f 1481/831/850 1480/736/851 1489/732/848 +f 1489/732/848 1484/842/848 1481/831/850 +f 1491/721/36 1492/722/36 1493/723/36 +f 1493/723/36 1494/724/36 1491/721/36 +f 1495/725/852 1496/726/748 1497/727/860 +f 1497/727/860 1498/728/860 1495/725/852 +f 1494/729/750 1493/730/750 1496/726/748 +f 1496/726/748 1495/725/852 1494/729/750 +f 1499/731/751 1495/732/752 1498/733/753 +f 1498/733/753 1500/734/753 1499/731/751 +f 1491/735/754 1494/736/754 1495/732/752 +f 1495/732/752 1499/731/751 1491/735/754 +f 1501/726/755 1499/725/755 1500/728/756 +f 1500/728/756 1502/727/756 1501/726/755 +f 1492/730/757 1491/729/757 1499/725/755 +f 1499/725/755 1501/726/755 1492/730/757 +f 1496/737/758 1501/738/758 1502/739/759 +f 1502/739/759 1497/740/759 1496/737/758 +f 1493/741/760 1492/742/760 1501/738/758 +f 1501/738/758 1496/737/758 1493/741/760 +f 1503/743/36 1504/744/36 1505/745/36 +f 1505/745/36 1506/746/36 1503/743/36 +f 1507/747/761 1508/748/761 1509/749/762 +f 1509/749/762 1510/750/762 1507/747/761 +f 1506/751/763 1505/752/763 1508/748/761 +f 1508/748/761 1507/747/761 1506/751/763 +f 1511/753/764 1507/754/765 1510/755/766 +f 1510/755/766 1512/756/766 1511/753/764 +f 1503/757/767 1506/758/767 1507/754/765 +f 1507/754/765 1511/753/764 1503/757/767 +f 1513/748/768 1511/747/769 1512/750/770 +f 1512/750/770 1514/749/770 1513/748/768 +f 1504/752/771 1503/751/771 1511/747/769 +f 1511/747/769 1513/748/768 1504/752/771 +f 1508/754/772 1513/759/773 1514/760/774 +f 1514/760/774 1509/755/774 1508/754/772 +f 1505/758/775 1504/761/775 1513/759/773 +f 1513/759/773 1508/754/772 1505/758/775 +f 1515/762/776 1516/763/777 1517/764/778 +f 1517/764/778 1518/765/778 1515/762/776 +f 1519/766/779 1520/767/779 1516/763/777 +f 1516/763/777 1515/762/776 1519/766/779 +f 1521/768/780 1515/769/781 1518/770/782 +f 1518/770/782 1522/771/782 1521/768/780 +f 1523/772/783 1519/773/783 1515/769/781 +f 1515/769/781 1521/768/780 1523/772/783 +f 1524/763/784 1521/762/785 1522/765/786 +f 1522/765/786 1525/764/786 1524/763/784 +f 1526/767/787 1523/766/787 1521/762/785 +f 1521/762/785 1524/763/784 1526/767/787 +f 1516/774/788 1524/768/789 1525/771/790 +f 1525/771/790 1517/775/790 1516/774/788 +f 1520/776/791 1526/777/791 1524/768/789 +f 1524/768/789 1516/774/788 1520/776/791 +f 1527/778/792 1528/779/793 1529/780/794 +f 1529/780/794 1530/781/794 1527/778/792 +f 1531/782/795 1532/783/795 1528/779/793 +f 1528/779/793 1527/778/792 1531/782/795 +f 1533/784/796 1527/785/797 1530/786/798 +f 1530/786/798 1534/787/798 1533/784/796 +f 1535/788/799 1531/789/799 1527/785/797 +f 1527/785/797 1533/784/796 1535/788/799 +f 1536/790/800 1533/791/801 1534/792/802 +f 1534/792/802 1537/793/802 1536/790/800 +f 1538/794/803 1535/795/803 1533/791/801 +f 1533/791/801 1536/790/800 1538/794/803 +f 1528/785/804 1536/796/805 1537/787/806 +f 1537/787/806 1529/797/806 1528/785/804 +f 1532/789/807 1538/798/807 1536/796/805 +f 1536/796/805 1528/785/804 1532/789/807 +f 1539/799/36 1540/800/36 1541/801/36 +f 1541/801/36 1542/802/36 1539/799/36 +f 1543/803/808 1544/804/809 1545/805/810 +f 1545/805/810 1546/806/810 1543/803/808 +f 1542/807/811 1541/808/811 1544/804/809 +f 1544/804/809 1543/803/808 1542/807/811 +f 1547/809/812 1543/810/812 1546/811/813 +f 1546/811/813 1548/812/813 1547/809/812 +f 1539/813/814 1542/814/814 1543/810/812 +f 1543/810/812 1547/809/812 1539/813/814 +f 1549/804/815 1547/803/816 1548/806/817 +f 1548/806/817 1550/805/817 1549/804/815 +f 1540/808/818 1539/807/818 1547/803/816 +f 1547/803/816 1549/804/815 1540/808/818 +f 1544/815/819 1549/809/819 1550/816/820 +f 1550/816/820 1545/817/820 1544/815/819 +f 1541/818/821 1540/819/822 1549/809/819 +f 1549/809/819 1544/815/819 1541/818/821 +f 1551/820/36 1552/821/36 1553/822/36 +f 1553/822/36 1554/823/36 1551/820/36 +f 1555/824/823 1556/825/824 1557/826/825 +f 1557/826/825 1558/827/825 1555/824/823 +f 1554/828/826 1553/829/826 1556/825/824 +f 1556/825/824 1555/824/823 1554/828/826 +f 1559/737/827 1555/738/828 1558/734/829 +f 1558/734/829 1560/740/829 1559/737/827 +f 1551/741/830 1554/735/830 1555/738/828 +f 1555/738/828 1559/737/827 1551/741/830 +f 1561/825/832 1559/824/832 1560/827/833 +f 1560/827/833 1562/826/833 1561/825/832 +f 1552/829/834 1551/828/834 1559/824/832 +f 1559/824/832 1561/825/832 1552/829/834 +f 1556/731/835 1561/737/836 1562/733/837 +f 1562/733/837 1557/830/837 1556/731/835 +f 1553/831/838 1552/736/838 1561/737/836 +f 1561/737/836 1556/731/835 1553/831/838 +f 1563/832/36 1564/833/36 1565/834/36 +f 1565/834/36 1566/835/36 1563/832/36 +f 1567/836/839 1568/837/839 1569/838/840 +f 1569/838/840 1570/839/840 1567/836/839 +f 1566/840/841 1565/841/841 1568/837/839 +f 1568/837/839 1567/836/839 1566/840/841 +f 1571/737/842 1567/731/842 1570/734/843 +f 1570/734/843 1572/733/843 1571/737/842 +f 1563/741/844 1566/735/844 1567/731/842 +f 1567/731/842 1571/737/842 1563/741/844 +f 1573/837/859 1571/836/859 1572/839/846 +f 1572/839/846 1574/838/846 1573/837/859 +f 1564/841/847 1563/840/847 1571/836/859 +f 1571/836/859 1573/837/859 1564/841/847 +f 1568/842/848 1573/732/848 1574/843/849 +f 1574/843/849 1569/734/849 1568/842/848 +f 1565/831/850 1564/736/851 1573/732/848 +f 1573/732/848 1568/842/848 1565/831/850 +f 1575/721/36 1576/722/36 1577/723/36 +f 1577/723/36 1578/724/36 1575/721/36 +f 1579/725/852 1580/726/748 1581/727/860 +f 1581/727/860 1582/728/860 1579/725/852 +f 1578/729/750 1577/730/750 1580/726/748 +f 1580/726/748 1579/725/852 1578/729/750 +f 1583/731/751 1579/732/752 1582/733/753 +f 1582/733/753 1584/734/753 1583/731/751 +f 1575/735/754 1578/736/754 1579/732/752 +f 1579/732/752 1583/731/751 1575/735/754 +f 1585/726/755 1583/725/755 1584/728/756 +f 1584/728/756 1586/727/756 1585/726/755 +f 1576/730/757 1575/729/757 1583/725/755 +f 1583/725/755 1585/726/755 1576/730/757 +f 1580/737/758 1585/738/758 1586/739/759 +f 1586/739/759 1581/740/759 1580/737/758 +f 1577/741/760 1576/742/760 1585/738/758 +f 1585/738/758 1580/737/758 1577/741/760 +f 1587/743/36 1588/744/36 1589/745/36 +f 1589/745/36 1590/746/36 1587/743/36 +f 1591/747/761 1592/748/761 1593/749/762 +f 1593/749/762 1594/750/762 1591/747/761 +f 1590/751/763 1589/752/763 1592/748/761 +f 1592/748/761 1591/747/761 1590/751/763 +f 1595/753/764 1591/754/765 1594/755/766 +f 1594/755/766 1596/756/766 1595/753/764 +f 1587/757/767 1590/758/767 1591/754/765 +f 1591/754/765 1595/753/764 1587/757/767 +f 1597/748/768 1595/747/769 1596/750/770 +f 1596/750/770 1598/749/770 1597/748/768 +f 1588/752/771 1587/751/771 1595/747/769 +f 1595/747/769 1597/748/768 1588/752/771 +f 1592/754/772 1597/759/773 1598/760/774 +f 1598/760/774 1593/755/774 1592/754/772 +f 1589/758/775 1588/761/775 1597/759/773 +f 1597/759/773 1592/754/772 1589/758/775 +f 1599/762/776 1600/763/777 1601/764/778 +f 1601/764/778 1602/765/778 1599/762/776 +f 1603/766/779 1604/767/779 1600/763/777 +f 1600/763/777 1599/762/776 1603/766/779 +f 1605/768/780 1599/769/781 1602/770/782 +f 1602/770/782 1606/771/782 1605/768/780 +f 1607/772/783 1603/773/783 1599/769/781 +f 1599/769/781 1605/768/780 1607/772/783 +f 1608/763/784 1605/762/785 1606/765/786 +f 1606/765/786 1609/764/786 1608/763/784 +f 1610/767/787 1607/766/787 1605/762/785 +f 1605/762/785 1608/763/784 1610/767/787 +f 1600/774/788 1608/768/789 1609/771/790 +f 1609/771/790 1601/775/790 1600/774/788 +f 1604/776/791 1610/777/791 1608/768/789 +f 1608/768/789 1600/774/788 1604/776/791 +f 1611/778/792 1612/779/793 1613/780/794 +f 1613/780/794 1614/781/794 1611/778/792 +f 1615/782/795 1616/783/795 1612/779/793 +f 1612/779/793 1611/778/792 1615/782/795 +f 1617/784/796 1611/785/797 1614/786/798 +f 1614/786/798 1618/787/798 1617/784/796 +f 1619/788/799 1615/789/799 1611/785/797 +f 1611/785/797 1617/784/796 1619/788/799 +f 1620/790/800 1617/791/801 1618/792/802 +f 1618/792/802 1621/793/802 1620/790/800 +f 1622/794/803 1619/795/803 1617/791/801 +f 1617/791/801 1620/790/800 1622/794/803 +f 1612/785/804 1620/796/805 1621/787/806 +f 1621/787/806 1613/797/806 1612/785/804 +f 1616/789/807 1622/798/807 1620/796/805 +f 1620/796/805 1612/785/804 1616/789/807 +f 1623/799/36 1624/800/36 1625/801/36 +f 1625/801/36 1626/802/36 1623/799/36 +f 1627/803/808 1628/804/809 1629/805/810 +f 1629/805/810 1630/806/810 1627/803/808 +f 1626/807/811 1625/808/811 1628/804/809 +f 1628/804/809 1627/803/808 1626/807/811 +f 1631/809/812 1627/810/812 1630/811/813 +f 1630/811/813 1632/812/813 1631/809/812 +f 1623/813/814 1626/814/814 1627/810/812 +f 1627/810/812 1631/809/812 1623/813/814 +f 1633/804/815 1631/803/816 1632/806/817 +f 1632/806/817 1634/805/817 1633/804/815 +f 1624/808/818 1623/807/818 1631/803/816 +f 1631/803/816 1633/804/815 1624/808/818 +f 1628/815/819 1633/809/819 1634/816/820 +f 1634/816/820 1629/817/820 1628/815/819 +f 1625/818/821 1624/819/822 1633/809/819 +f 1633/809/819 1628/815/819 1625/818/821 +f 1635/820/36 1636/821/36 1637/822/36 +f 1637/822/36 1638/823/36 1635/820/36 +f 1639/824/823 1640/825/824 1641/826/825 +f 1641/826/825 1642/827/825 1639/824/823 +f 1638/828/826 1637/829/826 1640/825/824 +f 1640/825/824 1639/824/823 1638/828/826 +f 1643/737/827 1639/738/828 1642/734/829 +f 1642/734/829 1644/740/829 1643/737/827 +f 1635/741/830 1638/735/830 1639/738/828 +f 1639/738/828 1643/737/827 1635/741/830 +f 1645/825/831 1643/824/832 1644/827/833 +f 1644/827/833 1646/826/833 1645/825/831 +f 1636/829/834 1635/828/834 1643/824/832 +f 1643/824/832 1645/825/831 1636/829/834 +f 1640/731/835 1645/737/836 1646/733/837 +f 1646/733/837 1641/830/837 1640/731/835 +f 1637/831/838 1636/736/838 1645/737/836 +f 1645/737/836 1640/731/835 1637/831/838 +f 1647/832/36 1648/833/36 1649/834/36 +f 1649/834/36 1650/835/36 1647/832/36 +f 1651/836/839 1652/837/839 1653/838/840 +f 1653/838/840 1654/839/840 1651/836/839 +f 1650/840/841 1649/841/841 1652/837/839 +f 1652/837/839 1651/836/839 1650/840/841 +f 1655/737/842 1651/731/842 1654/734/843 +f 1654/734/843 1656/733/843 1655/737/842 +f 1647/741/844 1650/735/844 1651/731/842 +f 1651/731/842 1655/737/842 1647/741/844 +f 1657/837/845 1655/836/845 1656/839/846 +f 1656/839/846 1658/838/846 1657/837/845 +f 1648/841/847 1647/840/847 1655/836/845 +f 1655/836/845 1657/837/845 1648/841/847 +f 1652/842/848 1657/732/848 1658/843/849 +f 1658/843/849 1653/734/849 1652/842/848 +f 1649/831/850 1648/736/851 1657/732/848 +f 1657/732/848 1652/842/848 1649/831/850 +f 1659/721/36 1660/722/36 1661/723/36 +f 1661/723/36 1662/724/36 1659/721/36 +f 1663/725/852 1664/726/748 1665/727/749 +f 1665/727/749 1666/728/749 1663/725/852 +f 1662/729/750 1661/730/750 1664/726/748 +f 1664/726/748 1663/725/852 1662/729/750 +f 1667/731/751 1663/732/752 1666/733/753 +f 1666/733/753 1668/734/753 1667/731/751 +f 1659/735/754 1662/736/754 1663/732/752 +f 1663/732/752 1667/731/751 1659/735/754 +f 1669/726/755 1667/725/755 1668/728/756 +f 1668/728/756 1670/727/756 1669/726/755 +f 1660/730/757 1659/729/757 1667/725/755 +f 1667/725/755 1669/726/755 1660/730/757 +f 1664/737/758 1669/738/758 1670/739/759 +f 1670/739/759 1665/740/759 1664/737/758 +f 1661/741/760 1660/742/760 1669/738/758 +f 1669/738/758 1664/737/758 1661/741/760 +f 1671/743/36 1672/744/36 1673/745/36 +f 1673/745/36 1674/746/36 1671/743/36 +f 1675/747/761 1676/748/761 1677/749/762 +f 1677/749/762 1678/750/762 1675/747/761 +f 1674/751/763 1673/752/763 1676/748/761 +f 1676/748/761 1675/747/761 1674/751/763 +f 1679/753/764 1675/754/765 1678/755/766 +f 1678/755/766 1680/756/766 1679/753/764 +f 1671/757/767 1674/758/767 1675/754/765 +f 1675/754/765 1679/753/764 1671/757/767 +f 1681/748/768 1679/747/769 1680/750/770 +f 1680/750/770 1682/749/770 1681/748/768 +f 1672/752/771 1671/751/771 1679/747/769 +f 1679/747/769 1681/748/768 1672/752/771 +f 1676/754/772 1681/759/773 1682/760/774 +f 1682/760/774 1677/755/774 1676/754/772 +f 1673/758/775 1672/761/775 1681/759/773 +f 1681/759/773 1676/754/772 1673/758/775 +f 1683/762/776 1684/763/777 1685/764/778 +f 1685/764/778 1686/765/778 1683/762/776 +f 1687/766/779 1688/767/779 1684/763/777 +f 1684/763/777 1683/762/776 1687/766/779 +f 1689/768/780 1683/769/781 1686/770/782 +f 1686/770/782 1690/771/782 1689/768/780 +f 1691/772/783 1687/773/783 1683/769/781 +f 1683/769/781 1689/768/780 1691/772/783 +f 1692/763/784 1689/762/785 1690/765/786 +f 1690/765/786 1693/764/786 1692/763/784 +f 1694/767/787 1691/766/787 1689/762/785 +f 1689/762/785 1692/763/784 1694/767/787 +f 1684/774/788 1692/768/789 1693/771/790 +f 1693/771/790 1685/775/790 1684/774/788 +f 1688/776/791 1694/777/791 1692/768/789 +f 1692/768/789 1684/774/788 1688/776/791 +f 1695/778/792 1696/779/793 1697/780/794 +f 1697/780/794 1698/781/794 1695/778/792 +f 1699/782/795 1700/783/795 1696/779/793 +f 1696/779/793 1695/778/792 1699/782/795 +f 1701/784/796 1695/785/797 1698/786/798 +f 1698/786/798 1702/787/798 1701/784/796 +f 1703/788/799 1699/789/799 1695/785/797 +f 1695/785/797 1701/784/796 1703/788/799 +f 1704/790/853 1701/791/854 1702/792/802 +f 1702/792/802 1705/793/802 1704/790/853 +f 1706/794/803 1703/795/803 1701/791/854 +f 1701/791/854 1704/790/853 1706/794/803 +f 1696/785/804 1704/796/805 1705/787/806 +f 1705/787/806 1697/797/806 1696/785/804 +f 1700/789/807 1706/798/807 1704/796/805 +f 1704/796/805 1696/785/804 1700/789/807 +f 1707/799/36 1708/800/36 1709/801/36 +f 1709/801/36 1710/802/36 1707/799/36 +f 1711/803/855 1712/804/856 1713/805/810 +f 1713/805/810 1714/806/810 1711/803/855 +f 1710/807/811 1709/808/811 1712/804/856 +f 1712/804/856 1711/803/855 1710/807/811 +f 1715/809/812 1711/810/812 1714/811/813 +f 1714/811/813 1716/812/813 1715/809/812 +f 1707/813/814 1710/814/814 1711/810/812 +f 1711/810/812 1715/809/812 1707/813/814 +f 1717/804/815 1715/803/816 1716/806/817 +f 1716/806/817 1718/805/817 1717/804/815 +f 1708/808/818 1707/807/818 1715/803/816 +f 1715/803/816 1717/804/815 1708/808/818 +f 1712/815/819 1717/809/819 1718/816/820 +f 1718/816/820 1713/817/820 1712/815/819 +f 1709/818/821 1708/819/822 1717/809/819 +f 1717/809/819 1712/815/819 1709/818/821 +f 1719/820/36 1720/821/36 1721/822/36 +f 1721/822/36 1722/823/36 1719/820/36 +f 1723/824/857 1724/825/858 1725/826/825 +f 1725/826/825 1726/827/825 1723/824/857 +f 1722/828/826 1721/829/826 1724/825/858 +f 1724/825/858 1723/824/857 1722/828/826 +f 1727/737/827 1723/738/828 1726/734/829 +f 1726/734/829 1728/740/829 1727/737/827 +f 1719/741/830 1722/735/830 1723/738/828 +f 1723/738/828 1727/737/827 1719/741/830 +f 1729/825/831 1727/824/832 1728/827/833 +f 1728/827/833 1730/826/833 1729/825/831 +f 1720/829/834 1719/828/834 1727/824/832 +f 1727/824/832 1729/825/831 1720/829/834 +f 1724/731/835 1729/737/836 1730/733/837 +f 1730/733/837 1725/830/837 1724/731/835 +f 1721/831/838 1720/736/838 1729/737/836 +f 1729/737/836 1724/731/835 1721/831/838 +f 1731/832/36 1732/833/36 1733/834/36 +f 1733/834/36 1734/835/36 1731/832/36 +f 1735/836/839 1736/837/839 1737/838/840 +f 1737/838/840 1738/839/840 1735/836/839 +f 1734/840/861 1733/841/861 1736/837/839 +f 1736/837/839 1735/836/839 1734/840/861 +f 1739/737/842 1735/731/842 1738/734/843 +f 1738/734/843 1740/733/843 1739/737/842 +f 1731/741/844 1734/735/844 1735/731/842 +f 1735/731/842 1739/737/842 1731/741/844 +f 1741/837/859 1739/836/859 1740/839/846 +f 1740/839/846 1742/838/846 1741/837/859 +f 1732/841/847 1731/840/847 1739/836/859 +f 1739/836/859 1741/837/859 1732/841/847 +f 1736/842/848 1741/732/848 1742/843/849 +f 1742/843/849 1737/734/849 1736/842/848 +f 1733/831/850 1732/736/851 1741/732/848 +f 1741/732/848 1736/842/848 1733/831/850 +f 1743/721/36 1744/722/36 1745/723/36 +f 1745/723/36 1746/724/36 1743/721/36 +f 1747/725/852 1748/726/748 1749/727/860 +f 1749/727/860 1750/728/860 1747/725/852 +f 1746/729/750 1745/730/750 1748/726/748 +f 1748/726/748 1747/725/852 1746/729/750 +f 1751/731/751 1747/732/752 1750/733/753 +f 1750/733/753 1752/734/753 1751/731/751 +f 1743/735/754 1746/736/754 1747/732/752 +f 1747/732/752 1751/731/751 1743/735/754 +f 1753/726/755 1751/725/755 1752/728/756 +f 1752/728/756 1754/727/756 1753/726/755 +f 1744/730/757 1743/729/757 1751/725/755 +f 1751/725/755 1753/726/755 1744/730/757 +f 1748/737/758 1753/738/758 1754/739/759 +f 1754/739/759 1749/740/759 1748/737/758 +f 1745/741/760 1744/742/760 1753/738/758 +f 1753/738/758 1748/737/758 1745/741/760 +f 1755/743/36 1756/744/36 1757/745/36 +f 1757/745/36 1758/746/36 1755/743/36 +f 1759/747/761 1760/748/761 1761/749/762 +f 1761/749/762 1762/750/762 1759/747/761 +f 1758/751/763 1757/752/763 1760/748/761 +f 1760/748/761 1759/747/761 1758/751/763 +f 1763/753/764 1759/754/765 1762/755/766 +f 1762/755/766 1764/756/766 1763/753/764 +f 1755/757/767 1758/758/767 1759/754/765 +f 1759/754/765 1763/753/764 1755/757/767 +f 1765/748/768 1763/747/769 1764/750/770 +f 1764/750/770 1766/749/770 1765/748/768 +f 1756/752/771 1755/751/771 1763/747/769 +f 1763/747/769 1765/748/768 1756/752/771 +f 1760/754/772 1765/759/773 1766/760/774 +f 1766/760/774 1761/755/774 1760/754/772 +f 1757/758/775 1756/761/775 1765/759/773 +f 1765/759/773 1760/754/772 1757/758/775 +f 1767/762/776 1768/763/777 1769/764/778 +f 1769/764/778 1770/765/778 1767/762/776 +f 1771/766/779 1772/767/779 1768/763/777 +f 1768/763/777 1767/762/776 1771/766/779 +f 1773/768/780 1767/769/781 1770/770/782 +f 1770/770/782 1774/771/782 1773/768/780 +f 1775/772/783 1771/773/783 1767/769/781 +f 1767/769/781 1773/768/780 1775/772/783 +f 1776/763/784 1773/762/785 1774/765/786 +f 1774/765/786 1777/764/786 1776/763/784 +f 1778/767/787 1775/766/787 1773/762/785 +f 1773/762/785 1776/763/784 1778/767/787 +f 1768/774/788 1776/768/789 1777/771/790 +f 1777/771/790 1769/775/790 1768/774/788 +f 1772/776/791 1778/777/791 1776/768/789 +f 1776/768/789 1768/774/788 1772/776/791 +f 1779/778/792 1780/779/793 1781/780/794 +f 1781/780/794 1782/781/794 1779/778/792 +f 1783/782/795 1784/783/795 1780/779/793 +f 1780/779/793 1779/778/792 1783/782/795 +f 1785/784/796 1779/785/797 1782/786/798 +f 1782/786/798 1786/787/798 1785/784/796 +f 1787/788/799 1783/789/799 1779/785/797 +f 1779/785/797 1785/784/796 1787/788/799 +f 1788/790/800 1785/791/801 1786/792/802 +f 1786/792/802 1789/793/802 1788/790/800 +f 1790/794/803 1787/795/803 1785/791/801 +f 1785/791/801 1788/790/800 1790/794/803 +f 1780/785/804 1788/796/805 1789/787/806 +f 1789/787/806 1781/797/806 1780/785/804 +f 1784/789/807 1790/798/807 1788/796/805 +f 1788/796/805 1780/785/804 1784/789/807 +f 1791/799/36 1792/800/36 1793/801/36 +f 1793/801/36 1794/802/36 1791/799/36 +f 1795/803/808 1796/804/809 1797/805/810 +f 1797/805/810 1798/806/810 1795/803/808 +f 1794/807/811 1793/808/811 1796/804/809 +f 1796/804/809 1795/803/808 1794/807/811 +f 1799/809/812 1795/810/812 1798/811/813 +f 1798/811/813 1800/812/813 1799/809/812 +f 1791/813/814 1794/814/814 1795/810/812 +f 1795/810/812 1799/809/812 1791/813/814 +f 1801/804/815 1799/803/816 1800/806/817 +f 1800/806/817 1802/805/817 1801/804/815 +f 1792/808/818 1791/807/818 1799/803/816 +f 1799/803/816 1801/804/815 1792/808/818 +f 1796/815/819 1801/809/819 1802/816/820 +f 1802/816/820 1797/817/820 1796/815/819 +f 1793/818/821 1792/819/822 1801/809/819 +f 1801/809/819 1796/815/819 1793/818/821 +f 1803/820/36 1804/821/36 1805/822/36 +f 1805/822/36 1806/823/36 1803/820/36 +f 1807/824/823 1808/825/824 1809/826/825 +f 1809/826/825 1810/827/825 1807/824/823 +f 1806/828/826 1805/829/826 1808/825/824 +f 1808/825/824 1807/824/823 1806/828/826 +f 1811/737/827 1807/738/828 1810/734/829 +f 1810/734/829 1812/740/829 1811/737/827 +f 1803/741/830 1806/735/830 1807/738/828 +f 1807/738/828 1811/737/827 1803/741/830 +f 1813/825/832 1811/824/832 1812/827/833 +f 1812/827/833 1814/826/833 1813/825/832 +f 1804/829/834 1803/828/834 1811/824/832 +f 1811/824/832 1813/825/832 1804/829/834 +f 1808/731/835 1813/737/836 1814/733/837 +f 1814/733/837 1809/830/837 1808/731/835 +f 1805/831/838 1804/736/838 1813/737/836 +f 1813/737/836 1808/731/835 1805/831/838 +f 1815/832/36 1816/833/36 1817/834/36 +f 1817/834/36 1818/835/36 1815/832/36 +f 1819/836/839 1820/837/839 1821/838/840 +f 1821/838/840 1822/839/840 1819/836/839 +f 1818/840/841 1817/841/841 1820/837/839 +f 1820/837/839 1819/836/839 1818/840/841 +f 1823/737/842 1819/731/842 1822/734/843 +f 1822/734/843 1824/733/843 1823/737/842 +f 1815/741/844 1818/735/844 1819/731/842 +f 1819/731/842 1823/737/842 1815/741/844 +f 1825/837/859 1823/836/859 1824/839/846 +f 1824/839/846 1826/838/846 1825/837/859 +f 1816/841/847 1815/840/847 1823/836/859 +f 1823/836/859 1825/837/859 1816/841/847 +f 1820/842/848 1825/732/848 1826/843/849 +f 1826/843/849 1821/734/849 1820/842/848 +f 1817/831/850 1816/736/851 1825/732/848 +f 1825/732/848 1820/842/848 1817/831/850 +f 1827/721/36 1828/722/36 1829/723/36 +f 1829/723/36 1830/724/36 1827/721/36 +f 1831/725/852 1832/726/748 1833/727/860 +f 1833/727/860 1834/728/860 1831/725/852 +f 1830/729/750 1829/730/750 1832/726/748 +f 1832/726/748 1831/725/852 1830/729/750 +f 1835/731/751 1831/732/752 1834/733/753 +f 1834/733/753 1836/734/753 1835/731/751 +f 1827/735/754 1830/736/754 1831/732/752 +f 1831/732/752 1835/731/751 1827/735/754 +f 1837/726/755 1835/725/755 1836/728/756 +f 1836/728/756 1838/727/756 1837/726/755 +f 1828/730/757 1827/729/757 1835/725/755 +f 1835/725/755 1837/726/755 1828/730/757 +f 1832/737/758 1837/738/758 1838/739/759 +f 1838/739/759 1833/740/759 1832/737/758 +f 1829/741/760 1828/742/760 1837/738/758 +f 1837/738/758 1832/737/758 1829/741/760 +f 1839/743/36 1840/744/36 1841/745/36 +f 1841/745/36 1842/746/36 1839/743/36 +f 1843/747/761 1844/748/761 1845/749/762 +f 1845/749/762 1846/750/762 1843/747/761 +f 1842/751/763 1841/752/763 1844/748/761 +f 1844/748/761 1843/747/761 1842/751/763 +f 1847/753/764 1843/754/765 1846/755/766 +f 1846/755/766 1848/756/766 1847/753/764 +f 1839/757/767 1842/758/767 1843/754/765 +f 1843/754/765 1847/753/764 1839/757/767 +f 1849/748/768 1847/747/769 1848/750/770 +f 1848/750/770 1850/749/770 1849/748/768 +f 1840/752/771 1839/751/771 1847/747/769 +f 1847/747/769 1849/748/768 1840/752/771 +f 1844/754/772 1849/759/773 1850/760/774 +f 1850/760/774 1845/755/774 1844/754/772 +f 1841/758/775 1840/761/775 1849/759/773 +f 1849/759/773 1844/754/772 1841/758/775 +f 1851/762/776 1852/763/777 1853/764/778 +f 1853/764/778 1854/765/778 1851/762/776 +f 1855/766/779 1856/767/779 1852/763/777 +f 1852/763/777 1851/762/776 1855/766/779 +f 1857/768/780 1851/769/781 1854/770/782 +f 1854/770/782 1858/771/782 1857/768/780 +f 1859/772/783 1855/773/783 1851/769/781 +f 1851/769/781 1857/768/780 1859/772/783 +f 1860/763/784 1857/762/785 1858/765/786 +f 1858/765/786 1861/764/786 1860/763/784 +f 1862/767/787 1859/766/787 1857/762/785 +f 1857/762/785 1860/763/784 1862/767/787 +f 1852/774/788 1860/768/789 1861/771/790 +f 1861/771/790 1853/775/790 1852/774/788 +f 1856/776/791 1862/777/791 1860/768/789 +f 1860/768/789 1852/774/788 1856/776/791 +f 1863/778/792 1864/779/793 1865/780/794 +f 1865/780/794 1866/781/794 1863/778/792 +f 1867/782/795 1868/783/795 1864/779/793 +f 1864/779/793 1863/778/792 1867/782/795 +f 1869/784/796 1863/785/797 1866/786/798 +f 1866/786/798 1870/787/798 1869/784/796 +f 1871/788/799 1867/789/799 1863/785/797 +f 1863/785/797 1869/784/796 1871/788/799 +f 1872/790/800 1869/791/801 1870/792/802 +f 1870/792/802 1873/793/802 1872/790/800 +f 1874/794/803 1871/795/803 1869/791/801 +f 1869/791/801 1872/790/800 1874/794/803 +f 1864/785/804 1872/796/805 1873/787/806 +f 1873/787/806 1865/797/806 1864/785/804 +f 1868/789/807 1874/798/807 1872/796/805 +f 1872/796/805 1864/785/804 1868/789/807 +f 1875/799/36 1876/800/36 1877/801/36 +f 1877/801/36 1878/802/36 1875/799/36 +f 1879/803/808 1880/804/809 1881/805/810 +f 1881/805/810 1882/806/810 1879/803/808 +f 1878/807/811 1877/808/811 1880/804/809 +f 1880/804/809 1879/803/808 1878/807/811 +f 1883/809/812 1879/810/812 1882/811/813 +f 1882/811/813 1884/812/813 1883/809/812 +f 1875/813/814 1878/814/814 1879/810/812 +f 1879/810/812 1883/809/812 1875/813/814 +f 1885/804/815 1883/803/816 1884/806/817 +f 1884/806/817 1886/805/817 1885/804/815 +f 1876/808/818 1875/807/818 1883/803/816 +f 1883/803/816 1885/804/815 1876/808/818 +f 1880/815/819 1885/809/819 1886/816/820 +f 1886/816/820 1881/817/820 1880/815/819 +f 1877/818/821 1876/819/822 1885/809/819 +f 1885/809/819 1880/815/819 1877/818/821 +f 1887/820/36 1888/821/36 1889/822/36 +f 1889/822/36 1890/823/36 1887/820/36 +f 1891/824/823 1892/825/824 1893/826/825 +f 1893/826/825 1894/827/825 1891/824/823 +f 1890/828/826 1889/829/826 1892/825/824 +f 1892/825/824 1891/824/823 1890/828/826 +f 1895/737/827 1891/738/828 1894/734/829 +f 1894/734/829 1896/740/829 1895/737/827 +f 1887/741/830 1890/735/830 1891/738/828 +f 1891/738/828 1895/737/827 1887/741/830 +f 1897/825/831 1895/824/832 1896/827/833 +f 1896/827/833 1898/826/833 1897/825/831 +f 1888/829/834 1887/828/834 1895/824/832 +f 1895/824/832 1897/825/831 1888/829/834 +f 1892/731/835 1897/737/836 1898/733/837 +f 1898/733/837 1893/830/837 1892/731/835 +f 1889/831/838 1888/736/838 1897/737/836 +f 1897/737/836 1892/731/835 1889/831/838 +f 1899/832/36 1900/833/36 1901/834/36 +f 1901/834/36 1902/835/36 1899/832/36 +f 1903/836/839 1904/837/839 1905/838/840 +f 1905/838/840 1906/839/840 1903/836/839 +f 1902/840/841 1901/841/841 1904/837/839 +f 1904/837/839 1903/836/839 1902/840/841 +f 1907/737/842 1903/731/842 1906/734/843 +f 1906/734/843 1908/733/843 1907/737/842 +f 1899/741/844 1902/735/844 1903/731/842 +f 1903/731/842 1907/737/842 1899/741/844 +f 1909/837/859 1907/836/859 1908/839/846 +f 1908/839/846 1910/838/846 1909/837/859 +f 1900/841/847 1899/840/847 1907/836/859 +f 1907/836/859 1909/837/859 1900/841/847 +f 1904/842/848 1909/732/848 1910/843/849 +f 1910/843/849 1905/734/849 1904/842/848 +f 1901/831/850 1900/736/851 1909/732/848 +f 1909/732/848 1904/842/848 1901/831/850 +f 1911/721/36 1912/722/36 1913/723/36 +f 1913/723/36 1914/724/36 1911/721/36 +f 1915/725/852 1916/726/748 1917/727/749 +f 1917/727/749 1918/728/749 1915/725/852 +f 1914/729/750 1913/730/750 1916/726/748 +f 1916/726/748 1915/725/852 1914/729/750 +f 1919/731/751 1915/732/752 1918/733/753 +f 1918/733/753 1920/734/753 1919/731/751 +f 1911/735/754 1914/736/754 1915/732/752 +f 1915/732/752 1919/731/751 1911/735/754 +f 1921/726/755 1919/725/755 1920/728/756 +f 1920/728/756 1922/727/756 1921/726/755 +f 1912/730/757 1911/729/757 1919/725/755 +f 1919/725/755 1921/726/755 1912/730/757 +f 1916/737/758 1921/738/758 1922/739/759 +f 1922/739/759 1917/740/759 1916/737/758 +f 1913/741/760 1912/742/760 1921/738/758 +f 1921/738/758 1916/737/758 1913/741/760 +f 1923/743/36 1924/744/36 1925/745/36 +f 1925/745/36 1926/746/36 1923/743/36 +f 1927/747/761 1928/748/761 1929/749/762 +f 1929/749/762 1930/750/762 1927/747/761 +f 1926/751/763 1925/752/763 1928/748/761 +f 1928/748/761 1927/747/761 1926/751/763 +f 1931/753/764 1927/754/765 1930/755/766 +f 1930/755/766 1932/756/766 1931/753/764 +f 1923/757/767 1926/758/767 1927/754/765 +f 1927/754/765 1931/753/764 1923/757/767 +f 1933/748/768 1931/747/769 1932/750/770 +f 1932/750/770 1934/749/770 1933/748/768 +f 1924/752/771 1923/751/771 1931/747/769 +f 1931/747/769 1933/748/768 1924/752/771 +f 1928/754/772 1933/759/773 1934/760/774 +f 1934/760/774 1929/755/774 1928/754/772 +f 1925/758/775 1924/761/775 1933/759/773 +f 1933/759/773 1928/754/772 1925/758/775 +f 1935/762/776 1936/763/777 1937/764/778 +f 1937/764/778 1938/765/778 1935/762/776 +f 1939/766/779 1940/767/779 1936/763/777 +f 1936/763/777 1935/762/776 1939/766/779 +f 1941/768/780 1935/769/781 1938/770/782 +f 1938/770/782 1942/771/782 1941/768/780 +f 1943/772/783 1939/773/783 1935/769/781 +f 1935/769/781 1941/768/780 1943/772/783 +f 1944/763/784 1941/762/785 1942/765/786 +f 1942/765/786 1945/764/786 1944/763/784 +f 1946/767/787 1943/766/787 1941/762/785 +f 1941/762/785 1944/763/784 1946/767/787 +f 1936/774/788 1944/768/789 1945/771/790 +f 1945/771/790 1937/775/790 1936/774/788 +f 1940/776/791 1946/777/791 1944/768/789 +f 1944/768/789 1936/774/788 1940/776/791 +f 1947/778/792 1948/779/793 1949/780/794 +f 1949/780/794 1950/781/794 1947/778/792 +f 1951/782/795 1952/783/795 1948/779/793 +f 1948/779/793 1947/778/792 1951/782/795 +f 1953/784/796 1947/785/797 1950/786/798 +f 1950/786/798 1954/787/798 1953/784/796 +f 1955/788/799 1951/789/799 1947/785/797 +f 1947/785/797 1953/784/796 1955/788/799 +f 1956/790/853 1953/791/854 1954/792/802 +f 1954/792/802 1957/793/802 1956/790/853 +f 1958/794/803 1955/795/803 1953/791/854 +f 1953/791/854 1956/790/853 1958/794/803 +f 1948/785/804 1956/796/805 1957/787/806 +f 1957/787/806 1949/797/806 1948/785/804 +f 1952/789/807 1958/798/807 1956/796/805 +f 1956/796/805 1948/785/804 1952/789/807 +f 1959/799/36 1960/800/36 1961/801/36 +f 1961/801/36 1962/802/36 1959/799/36 +f 1963/803/855 1964/804/856 1965/805/810 +f 1965/805/810 1966/806/810 1963/803/855 +f 1962/807/811 1961/808/811 1964/804/856 +f 1964/804/856 1963/803/855 1962/807/811 +f 1967/809/812 1963/810/812 1966/811/813 +f 1966/811/813 1968/812/813 1967/809/812 +f 1959/813/814 1962/814/814 1963/810/812 +f 1963/810/812 1967/809/812 1959/813/814 +f 1969/804/815 1967/803/816 1968/806/817 +f 1968/806/817 1970/805/817 1969/804/815 +f 1960/808/818 1959/807/818 1967/803/816 +f 1967/803/816 1969/804/815 1960/808/818 +f 1964/815/819 1969/809/819 1970/816/820 +f 1970/816/820 1965/817/820 1964/815/819 +f 1961/818/821 1960/819/822 1969/809/819 +f 1969/809/819 1964/815/819 1961/818/821 +f 1971/820/36 1972/821/36 1973/822/36 +f 1973/822/36 1974/823/36 1971/820/36 +f 1975/824/857 1976/825/858 1977/826/825 +f 1977/826/825 1978/827/825 1975/824/857 +f 1974/828/826 1973/829/826 1976/825/858 +f 1976/825/858 1975/824/857 1974/828/826 +f 1979/737/827 1975/738/828 1978/734/829 +f 1978/734/829 1980/740/829 1979/737/827 +f 1971/741/830 1974/735/830 1975/738/828 +f 1975/738/828 1979/737/827 1971/741/830 +f 1981/825/831 1979/824/832 1980/827/833 +f 1980/827/833 1982/826/833 1981/825/831 +f 1972/829/834 1971/828/834 1979/824/832 +f 1979/824/832 1981/825/831 1972/829/834 +f 1976/731/835 1981/737/836 1982/733/837 +f 1982/733/837 1977/830/837 1976/731/835 +f 1973/831/838 1972/736/838 1981/737/836 +f 1981/737/836 1976/731/835 1973/831/838 +f 1983/832/36 1984/833/36 1985/834/36 +f 1985/834/36 1986/835/36 1983/832/36 +f 1987/836/839 1988/837/839 1989/838/840 +f 1989/838/840 1990/839/840 1987/836/839 +f 1986/840/861 1985/841/861 1988/837/839 +f 1988/837/839 1987/836/839 1986/840/861 +f 1991/737/842 1987/731/842 1990/734/843 +f 1990/734/843 1992/733/843 1991/737/842 +f 1983/741/844 1986/735/844 1987/731/842 +f 1987/731/842 1991/737/842 1983/741/844 +f 1993/837/859 1991/836/859 1992/839/846 +f 1992/839/846 1994/838/846 1993/837/859 +f 1984/841/847 1983/840/847 1991/836/859 +f 1991/836/859 1993/837/859 1984/841/847 +f 1988/842/848 1993/732/848 1994/843/849 +f 1994/843/849 1989/734/849 1988/842/848 +f 1985/831/850 1984/736/851 1993/732/848 +f 1993/732/848 1988/842/848 1985/831/850 +f 1995/721/36 1996/722/36 1997/723/36 +f 1997/723/36 1998/724/36 1995/721/36 +f 1999/725/852 2000/726/748 2001/727/860 +f 2001/727/860 2002/728/860 1999/725/852 +f 1998/729/750 1997/730/750 2000/726/748 +f 2000/726/748 1999/725/852 1998/729/750 +f 2003/731/751 1999/732/752 2002/733/753 +f 2002/733/753 2004/734/753 2003/731/751 +f 1995/735/754 1998/736/754 1999/732/752 +f 1999/732/752 2003/731/751 1995/735/754 +f 2005/726/755 2003/725/755 2004/728/756 +f 2004/728/756 2006/727/756 2005/726/755 +f 1996/730/757 1995/729/757 2003/725/755 +f 2003/725/755 2005/726/755 1996/730/757 +f 2000/737/758 2005/738/758 2006/739/759 +f 2006/739/759 2001/740/759 2000/737/758 +f 1997/741/760 1996/742/760 2005/738/758 +f 2005/738/758 2000/737/758 1997/741/760 +f 2007/743/36 2008/744/36 2009/745/36 +f 2009/745/36 2010/746/36 2007/743/36 +f 2011/747/761 2012/748/761 2013/749/762 +f 2013/749/762 2014/750/762 2011/747/761 +f 2010/751/763 2009/752/763 2012/748/761 +f 2012/748/761 2011/747/761 2010/751/763 +f 2015/753/764 2011/754/765 2014/755/766 +f 2014/755/766 2016/756/766 2015/753/764 +f 2007/757/767 2010/758/767 2011/754/765 +f 2011/754/765 2015/753/764 2007/757/767 +f 2017/748/768 2015/747/769 2016/750/770 +f 2016/750/770 2018/749/770 2017/748/768 +f 2008/752/771 2007/751/771 2015/747/769 +f 2015/747/769 2017/748/768 2008/752/771 +f 2012/754/772 2017/759/773 2018/760/774 +f 2018/760/774 2013/755/774 2012/754/772 +f 2009/758/775 2008/761/775 2017/759/773 +f 2017/759/773 2012/754/772 2009/758/775 +f 2019/762/776 2020/763/777 2021/764/778 +f 2021/764/778 2022/765/778 2019/762/776 +f 2023/766/779 2024/767/779 2020/763/777 +f 2020/763/777 2019/762/776 2023/766/779 +f 2025/768/780 2019/769/781 2022/770/782 +f 2022/770/782 2026/771/782 2025/768/780 +f 2027/772/783 2023/773/783 2019/769/781 +f 2019/769/781 2025/768/780 2027/772/783 +f 2028/763/784 2025/762/785 2026/765/786 +f 2026/765/786 2029/764/786 2028/763/784 +f 2030/767/787 2027/766/787 2025/762/785 +f 2025/762/785 2028/763/784 2030/767/787 +f 2020/774/788 2028/768/789 2029/771/790 +f 2029/771/790 2021/775/790 2020/774/788 +f 2024/776/791 2030/777/791 2028/768/789 +f 2028/768/789 2020/774/788 2024/776/791 +f 2031/778/792 2032/779/793 2033/780/794 +f 2033/780/794 2034/781/794 2031/778/792 +f 2035/782/795 2036/783/795 2032/779/793 +f 2032/779/793 2031/778/792 2035/782/795 +f 2037/784/796 2031/785/797 2034/786/798 +f 2034/786/798 2038/787/798 2037/784/796 +f 2039/788/799 2035/789/799 2031/785/797 +f 2031/785/797 2037/784/796 2039/788/799 +f 2040/790/800 2037/791/801 2038/792/802 +f 2038/792/802 2041/793/802 2040/790/800 +f 2042/794/803 2039/795/803 2037/791/801 +f 2037/791/801 2040/790/800 2042/794/803 +f 2032/785/804 2040/796/805 2041/787/806 +f 2041/787/806 2033/797/806 2032/785/804 +f 2036/789/807 2042/798/807 2040/796/805 +f 2040/796/805 2032/785/804 2036/789/807 +f 2043/799/36 2044/800/36 2045/801/36 +f 2045/801/36 2046/802/36 2043/799/36 +f 2047/803/808 2048/804/809 2049/805/810 +f 2049/805/810 2050/806/810 2047/803/808 +f 2046/807/811 2045/808/811 2048/804/809 +f 2048/804/809 2047/803/808 2046/807/811 +f 2051/809/812 2047/810/812 2050/811/813 +f 2050/811/813 2052/812/813 2051/809/812 +f 2043/813/814 2046/814/814 2047/810/812 +f 2047/810/812 2051/809/812 2043/813/814 +f 2053/804/815 2051/803/816 2052/806/817 +f 2052/806/817 2054/805/817 2053/804/815 +f 2044/808/818 2043/807/818 2051/803/816 +f 2051/803/816 2053/804/815 2044/808/818 +f 2048/815/819 2053/809/819 2054/816/820 +f 2054/816/820 2049/817/820 2048/815/819 +f 2045/818/821 2044/819/822 2053/809/819 +f 2053/809/819 2048/815/819 2045/818/821 +f 2055/820/36 2056/821/36 2057/822/36 +f 2057/822/36 2058/823/36 2055/820/36 +f 2059/824/857 2060/825/858 2061/826/825 +f 2061/826/825 2062/827/825 2059/824/857 +f 2058/828/826 2057/829/826 2060/825/858 +f 2060/825/858 2059/824/857 2058/828/826 +f 2063/737/827 2059/738/828 2062/734/829 +f 2062/734/829 2064/740/829 2063/737/827 +f 2055/741/830 2058/735/830 2059/738/828 +f 2059/738/828 2063/737/827 2055/741/830 +f 2065/825/832 2063/824/832 2064/827/833 +f 2064/827/833 2066/826/833 2065/825/832 +f 2056/829/834 2055/828/834 2063/824/832 +f 2063/824/832 2065/825/832 2056/829/834 +f 2060/731/835 2065/737/836 2066/733/837 +f 2066/733/837 2061/830/837 2060/731/835 +f 2057/831/838 2056/736/838 2065/737/836 +f 2065/737/836 2060/731/835 2057/831/838 +f 2067/832/36 2068/833/36 2069/834/36 +f 2069/834/36 2070/835/36 2067/832/36 +f 2071/836/839 2072/837/839 2073/838/840 +f 2073/838/840 2074/839/840 2071/836/839 +f 2070/840/841 2069/841/841 2072/837/839 +f 2072/837/839 2071/836/839 2070/840/841 +f 2075/737/842 2071/731/842 2074/734/843 +f 2074/734/843 2076/733/843 2075/737/842 +f 2067/741/844 2070/735/844 2071/731/842 +f 2071/731/842 2075/737/842 2067/741/844 +f 2077/837/859 2075/836/859 2076/839/846 +f 2076/839/846 2078/838/846 2077/837/859 +f 2068/841/847 2067/840/847 2075/836/859 +f 2075/836/859 2077/837/859 2068/841/847 +f 2072/842/848 2077/732/848 2078/843/849 +f 2078/843/849 2073/734/849 2072/842/848 +f 2069/831/850 2068/736/851 2077/732/848 +f 2077/732/848 2072/842/848 2069/831/850 +f 2079/721/36 2080/722/36 2081/723/36 +f 2081/723/36 2082/724/36 2079/721/36 +f 2083/725/852 2084/726/748 2085/727/860 +f 2085/727/860 2086/728/860 2083/725/852 +f 2082/729/750 2081/730/750 2084/726/748 +f 2084/726/748 2083/725/852 2082/729/750 +f 2087/731/751 2083/732/752 2086/733/753 +f 2086/733/753 2088/734/753 2087/731/751 +f 2079/735/754 2082/736/754 2083/732/752 +f 2083/732/752 2087/731/751 2079/735/754 +f 2089/726/755 2087/725/755 2088/728/756 +f 2088/728/756 2090/727/756 2089/726/755 +f 2080/730/757 2079/729/757 2087/725/755 +f 2087/725/755 2089/726/755 2080/730/757 +f 2084/737/758 2089/738/758 2090/739/759 +f 2090/739/759 2085/740/759 2084/737/758 +f 2081/741/760 2080/742/760 2089/738/758 +f 2089/738/758 2084/737/758 2081/741/760 +f 2091/743/36 2092/744/36 2093/745/36 +f 2093/745/36 2094/746/36 2091/743/36 +f 2095/747/761 2096/748/761 2097/749/762 +f 2097/749/762 2098/750/762 2095/747/761 +f 2094/751/763 2093/752/763 2096/748/761 +f 2096/748/761 2095/747/761 2094/751/763 +f 2099/753/764 2095/754/765 2098/755/766 +f 2098/755/766 2100/756/766 2099/753/764 +f 2091/757/767 2094/758/767 2095/754/765 +f 2095/754/765 2099/753/764 2091/757/767 +f 2101/748/768 2099/747/769 2100/750/770 +f 2100/750/770 2102/749/770 2101/748/768 +f 2092/752/771 2091/751/771 2099/747/769 +f 2099/747/769 2101/748/768 2092/752/771 +f 2096/754/772 2101/759/773 2102/760/774 +f 2102/760/774 2097/755/774 2096/754/772 +f 2093/758/775 2092/761/775 2101/759/773 +f 2101/759/773 2096/754/772 2093/758/775 +f 2103/762/776 2104/763/777 2105/764/778 +f 2105/764/778 2106/765/778 2103/762/776 +f 2107/766/779 2108/767/779 2104/763/777 +f 2104/763/777 2103/762/776 2107/766/779 +f 2109/768/780 2103/769/781 2106/770/782 +f 2106/770/782 2110/771/782 2109/768/780 +f 2111/772/783 2107/773/783 2103/769/781 +f 2103/769/781 2109/768/780 2111/772/783 +f 2112/763/784 2109/762/785 2110/765/786 +f 2110/765/786 2113/764/786 2112/763/784 +f 2114/767/787 2111/766/787 2109/762/785 +f 2109/762/785 2112/763/784 2114/767/787 +f 2104/774/788 2112/768/789 2113/771/790 +f 2113/771/790 2105/775/790 2104/774/788 +f 2108/776/791 2114/777/791 2112/768/789 +f 2112/768/789 2104/774/788 2108/776/791 +f 2115/778/792 2116/779/793 2117/780/794 +f 2117/780/794 2118/781/794 2115/778/792 +f 2119/782/795 2120/783/795 2116/779/793 +f 2116/779/793 2115/778/792 2119/782/795 +f 2121/784/796 2115/785/797 2118/786/798 +f 2118/786/798 2122/787/798 2121/784/796 +f 2123/788/799 2119/789/799 2115/785/797 +f 2115/785/797 2121/784/796 2123/788/799 +f 2124/790/800 2121/791/801 2122/792/802 +f 2122/792/802 2125/793/802 2124/790/800 +f 2126/794/803 2123/795/803 2121/791/801 +f 2121/791/801 2124/790/800 2126/794/803 +f 2116/785/804 2124/796/805 2125/787/806 +f 2125/787/806 2117/797/806 2116/785/804 +f 2120/789/807 2126/798/807 2124/796/805 +f 2124/796/805 2116/785/804 2120/789/807 +f 2127/799/36 2128/800/36 2129/801/36 +f 2129/801/36 2130/802/36 2127/799/36 +f 2131/803/808 2132/804/809 2133/805/810 +f 2133/805/810 2134/806/810 2131/803/808 +f 2130/807/811 2129/808/811 2132/804/809 +f 2132/804/809 2131/803/808 2130/807/811 +f 2135/809/812 2131/810/812 2134/811/813 +f 2134/811/813 2136/812/813 2135/809/812 +f 2127/813/814 2130/814/814 2131/810/812 +f 2131/810/812 2135/809/812 2127/813/814 +f 2137/804/815 2135/803/816 2136/806/817 +f 2136/806/817 2138/805/817 2137/804/815 +f 2128/808/818 2127/807/818 2135/803/816 +f 2135/803/816 2137/804/815 2128/808/818 +f 2132/815/819 2137/809/819 2138/816/820 +f 2138/816/820 2133/817/820 2132/815/819 +f 2129/818/821 2128/819/822 2137/809/819 +f 2137/809/819 2132/815/819 2129/818/821 +f 2139/820/36 2140/821/36 2141/822/36 +f 2141/822/36 2142/823/36 2139/820/36 +f 2143/824/823 2144/825/824 2145/826/825 +f 2145/826/825 2146/827/825 2143/824/823 +f 2142/828/826 2141/829/826 2144/825/824 +f 2144/825/824 2143/824/823 2142/828/826 +f 2147/737/827 2143/738/828 2146/734/829 +f 2146/734/829 2148/740/829 2147/737/827 +f 2139/741/830 2142/735/830 2143/738/828 +f 2143/738/828 2147/737/827 2139/741/830 +f 2149/825/832 2147/824/832 2148/827/833 +f 2148/827/833 2150/826/833 2149/825/832 +f 2140/829/834 2139/828/834 2147/824/832 +f 2147/824/832 2149/825/832 2140/829/834 +f 2144/731/835 2149/737/836 2150/733/837 +f 2150/733/837 2145/830/837 2144/731/835 +f 2141/831/838 2140/736/838 2149/737/836 +f 2149/737/836 2144/731/835 2141/831/838 +f 2151/832/36 2152/833/36 2153/834/36 +f 2153/834/36 2154/835/36 2151/832/36 +f 2155/836/839 2156/837/839 2157/838/840 +f 2157/838/840 2158/839/840 2155/836/839 +f 2154/840/841 2153/841/841 2156/837/839 +f 2156/837/839 2155/836/839 2154/840/841 +f 2159/737/842 2155/731/842 2158/734/843 +f 2158/734/843 2160/733/843 2159/737/842 +f 2151/741/844 2154/735/844 2155/731/842 +f 2155/731/842 2159/737/842 2151/741/844 +f 2161/837/859 2159/836/859 2160/839/846 +f 2160/839/846 2162/838/846 2161/837/859 +f 2152/841/847 2151/840/847 2159/836/859 +f 2159/836/859 2161/837/859 2152/841/847 +f 2156/842/848 2161/732/848 2162/843/849 +f 2162/843/849 2157/734/849 2156/842/848 +f 2153/831/850 2152/736/851 2161/732/848 +f 2161/732/848 2156/842/848 2153/831/850 +f 2163/721/36 2164/722/36 2165/723/36 +f 2165/723/36 2166/724/36 2163/721/36 +f 2167/725/852 2168/726/748 2169/727/749 +f 2169/727/749 2170/728/749 2167/725/852 +f 2166/729/750 2165/730/750 2168/726/748 +f 2168/726/748 2167/725/852 2166/729/750 +f 2171/731/751 2167/732/752 2170/733/753 +f 2170/733/753 2172/734/753 2171/731/751 +f 2163/735/754 2166/736/754 2167/732/752 +f 2167/732/752 2171/731/751 2163/735/754 +f 2173/726/755 2171/725/755 2172/728/756 +f 2172/728/756 2174/727/756 2173/726/755 +f 2164/730/757 2163/729/757 2171/725/755 +f 2171/725/755 2173/726/755 2164/730/757 +f 2168/737/758 2173/738/758 2174/739/759 +f 2174/739/759 2169/740/759 2168/737/758 +f 2165/741/760 2164/742/760 2173/738/758 +f 2173/738/758 2168/737/758 2165/741/760 +f 2175/743/36 2176/744/36 2177/745/36 +f 2177/745/36 2178/746/36 2175/743/36 +f 2179/747/761 2180/748/761 2181/749/762 +f 2181/749/762 2182/750/762 2179/747/761 +f 2178/751/763 2177/752/763 2180/748/761 +f 2180/748/761 2179/747/761 2178/751/763 +f 2183/753/764 2179/754/765 2182/755/766 +f 2182/755/766 2184/756/766 2183/753/764 +f 2175/757/767 2178/758/767 2179/754/765 +f 2179/754/765 2183/753/764 2175/757/767 +f 2185/748/768 2183/747/769 2184/750/770 +f 2184/750/770 2186/749/770 2185/748/768 +f 2176/752/771 2175/751/771 2183/747/769 +f 2183/747/769 2185/748/768 2176/752/771 +f 2180/754/772 2185/759/773 2186/760/774 +f 2186/760/774 2181/755/774 2180/754/772 +f 2177/758/775 2176/761/775 2185/759/773 +f 2185/759/773 2180/754/772 2177/758/775 +f 2187/762/776 2188/763/777 2189/764/778 +f 2189/764/778 2190/765/778 2187/762/776 +f 2191/766/779 2192/767/779 2188/763/777 +f 2188/763/777 2187/762/776 2191/766/779 +f 2193/768/780 2187/769/781 2190/770/782 +f 2190/770/782 2194/771/782 2193/768/780 +f 2195/772/783 2191/773/783 2187/769/781 +f 2187/769/781 2193/768/780 2195/772/783 +f 2196/763/784 2193/762/785 2194/765/786 +f 2194/765/786 2197/764/786 2196/763/784 +f 2198/767/787 2195/766/787 2193/762/785 +f 2193/762/785 2196/763/784 2198/767/787 +f 2188/774/788 2196/768/789 2197/771/790 +f 2197/771/790 2189/775/790 2188/774/788 +f 2192/776/791 2198/777/791 2196/768/789 +f 2196/768/789 2188/774/788 2192/776/791 +f 2199/778/792 2200/779/793 2201/780/794 +f 2201/780/794 2202/781/794 2199/778/792 +f 2203/782/795 2204/783/795 2200/779/793 +f 2200/779/793 2199/778/792 2203/782/795 +f 2205/784/796 2199/785/797 2202/786/798 +f 2202/786/798 2206/787/798 2205/784/796 +f 2207/788/799 2203/789/799 2199/785/797 +f 2199/785/797 2205/784/796 2207/788/799 +f 2208/790/800 2205/791/801 2206/792/802 +f 2206/792/802 2209/793/802 2208/790/800 +f 2210/794/803 2207/795/803 2205/791/801 +f 2205/791/801 2208/790/800 2210/794/803 +f 2200/785/804 2208/796/805 2209/787/806 +f 2209/787/806 2201/797/806 2200/785/804 +f 2204/789/807 2210/798/807 2208/796/805 +f 2208/796/805 2200/785/804 2204/789/807 +f 2211/799/36 2212/800/36 2213/801/36 +f 2213/801/36 2214/802/36 2211/799/36 +f 2215/803/808 2216/804/809 2217/805/810 +f 2217/805/810 2218/806/810 2215/803/808 +f 2214/807/811 2213/808/811 2216/804/809 +f 2216/804/809 2215/803/808 2214/807/811 +f 2219/809/812 2215/810/812 2218/811/813 +f 2218/811/813 2220/812/813 2219/809/812 +f 2211/813/814 2214/814/814 2215/810/812 +f 2215/810/812 2219/809/812 2211/813/814 +f 2221/804/815 2219/803/816 2220/806/817 +f 2220/806/817 2222/805/817 2221/804/815 +f 2212/808/818 2211/807/818 2219/803/816 +f 2219/803/816 2221/804/815 2212/808/818 +f 2216/815/819 2221/809/819 2222/816/820 +f 2222/816/820 2217/817/820 2216/815/819 +f 2213/818/821 2212/819/822 2221/809/819 +f 2221/809/819 2216/815/819 2213/818/821 +f 2223/820/36 2224/821/36 2225/822/36 +f 2225/822/36 2226/823/36 2223/820/36 +f 2227/824/857 2228/825/858 2229/826/825 +f 2229/826/825 2230/827/825 2227/824/857 +f 2226/828/862 2225/829/862 2228/825/858 +f 2228/825/858 2227/824/857 2226/828/862 +f 2231/737/863 2227/738/864 2230/734/829 +f 2230/734/829 2232/740/829 2231/737/863 +f 2223/741/830 2226/735/830 2227/738/864 +f 2227/738/864 2231/737/863 2223/741/830 +f 2233/825/832 2231/824/832 2232/827/833 +f 2232/827/833 2234/826/833 2233/825/832 +f 2224/829/834 2223/828/834 2231/824/832 +f 2231/824/832 2233/825/832 2224/829/834 +f 2228/731/835 2233/737/836 2234/733/837 +f 2234/733/837 2229/830/837 2228/731/835 +f 2225/831/838 2224/736/838 2233/737/836 +f 2233/737/836 2228/731/835 2225/831/838 +f 2235/832/36 2236/833/36 2237/834/36 +f 2237/834/36 2238/835/36 2235/832/36 +f 2239/836/839 2240/837/839 2241/838/865 +f 2241/838/865 2242/839/865 2239/836/839 +f 2238/840/866 2237/841/866 2240/837/839 +f 2240/837/839 2239/836/839 2238/840/866 +f 2243/737/842 2239/731/842 2242/734/843 +f 2242/734/843 2244/733/843 2243/737/842 +f 2235/741/844 2238/735/844 2239/731/842 +f 2239/731/842 2243/737/842 2235/741/844 +f 2245/837/859 2243/836/859 2244/839/846 +f 2244/839/846 2246/838/846 2245/837/859 +f 2236/841/847 2235/840/847 2243/836/859 +f 2243/836/859 2245/837/859 2236/841/847 +f 2240/842/867 2245/732/848 2246/843/849 +f 2246/843/849 2241/734/849 2240/842/867 +f 2237/831/850 2236/736/851 2245/732/848 +f 2245/732/848 2240/842/867 2237/831/850 +f 2247/721/36 2248/722/36 2249/723/36 +f 2249/723/36 2250/724/36 2247/721/36 +f 2251/725/852 2252/726/748 2253/727/860 +f 2253/727/860 2254/728/860 2251/725/852 +f 2250/729/750 2249/730/750 2252/726/748 +f 2252/726/748 2251/725/852 2250/729/750 +f 2255/731/751 2251/732/752 2254/733/753 +f 2254/733/753 2256/734/753 2255/731/751 +f 2247/735/754 2250/736/754 2251/732/752 +f 2251/732/752 2255/731/751 2247/735/754 +f 2257/726/755 2255/725/755 2256/728/756 +f 2256/728/756 2258/727/756 2257/726/755 +f 2248/730/757 2247/729/757 2255/725/755 +f 2255/725/755 2257/726/755 2248/730/757 +f 2252/737/758 2257/738/758 2258/739/759 +f 2258/739/759 2253/740/759 2252/737/758 +f 2249/741/760 2248/742/760 2257/738/758 +f 2257/738/758 2252/737/758 2249/741/760 +f 2259/743/36 2260/744/36 2261/745/36 +f 2261/745/36 2262/746/36 2259/743/36 +f 2263/747/761 2264/748/761 2265/749/762 +f 2265/749/762 2266/750/762 2263/747/761 +f 2262/751/763 2261/752/763 2264/748/761 +f 2264/748/761 2263/747/761 2262/751/763 +f 2267/753/764 2263/754/765 2266/755/766 +f 2266/755/766 2268/756/766 2267/753/764 +f 2259/757/767 2262/758/767 2263/754/765 +f 2263/754/765 2267/753/764 2259/757/767 +f 2269/748/768 2267/747/769 2268/750/770 +f 2268/750/770 2270/749/770 2269/748/768 +f 2260/752/771 2259/751/771 2267/747/769 +f 2267/747/769 2269/748/768 2260/752/771 +f 2264/754/772 2269/759/773 2270/760/774 +f 2270/760/774 2265/755/774 2264/754/772 +f 2261/758/775 2260/761/775 2269/759/773 +f 2269/759/773 2264/754/772 2261/758/775 +f 2271/762/776 2272/763/777 2273/764/778 +f 2273/764/778 2274/765/778 2271/762/776 +f 2275/766/779 2276/767/779 2272/763/777 +f 2272/763/777 2271/762/776 2275/766/779 +f 2277/768/780 2271/769/781 2274/770/782 +f 2274/770/782 2278/771/782 2277/768/780 +f 2279/772/783 2275/773/783 2271/769/781 +f 2271/769/781 2277/768/780 2279/772/783 +f 2280/763/784 2277/762/785 2278/765/786 +f 2278/765/786 2281/764/786 2280/763/784 +f 2282/767/787 2279/766/787 2277/762/785 +f 2277/762/785 2280/763/784 2282/767/787 +f 2272/774/788 2280/768/789 2281/771/790 +f 2281/771/790 2273/775/790 2272/774/788 +f 2276/776/791 2282/777/791 2280/768/789 +f 2280/768/789 2272/774/788 2276/776/791 +f 2283/778/868 2284/779/793 2285/780/794 +f 2285/780/794 2286/781/794 2283/778/868 +f 2287/782/795 2288/783/795 2284/779/793 +f 2284/779/793 2283/778/868 2287/782/795 +f 2289/784/796 2283/785/797 2286/786/798 +f 2286/786/798 2290/787/798 2289/784/796 +f 2291/788/799 2287/789/799 2283/785/797 +f 2283/785/797 2289/784/796 2291/788/799 +f 2292/790/800 2289/791/801 2290/792/802 +f 2290/792/802 2293/793/802 2292/790/800 +f 2294/794/803 2291/795/803 2289/791/801 +f 2289/791/801 2292/790/800 2294/794/803 +f 2284/785/804 2292/796/805 2293/787/806 +f 2293/787/806 2285/797/806 2284/785/804 +f 2288/789/807 2294/798/807 2292/796/805 +f 2292/796/805 2284/785/804 2288/789/807 +f 2295/799/36 2296/800/36 2297/801/36 +f 2297/801/36 2298/802/36 2295/799/36 +f 2299/803/808 2300/804/809 2301/805/810 +f 2301/805/810 2302/806/810 2299/803/808 +f 2298/807/811 2297/808/811 2300/804/809 +f 2300/804/809 2299/803/808 2298/807/811 +f 2303/809/812 2299/810/812 2302/811/813 +f 2302/811/813 2304/812/813 2303/809/812 +f 2295/813/814 2298/814/814 2299/810/812 +f 2299/810/812 2303/809/812 2295/813/814 +f 2305/804/815 2303/803/816 2304/806/869 +f 2304/806/869 2306/805/869 2305/804/815 +f 2296/808/870 2295/807/870 2303/803/816 +f 2303/803/816 2305/804/815 2296/808/870 +f 2300/815/819 2305/809/819 2306/816/820 +f 2306/816/820 2301/817/820 2300/815/819 +f 2297/818/821 2296/819/821 2305/809/819 +f 2305/809/819 2300/815/819 2297/818/821 +f 2307/820/36 2308/821/36 2309/822/36 +f 2309/822/36 2310/823/36 2307/820/36 +f 2311/824/857 2312/825/858 2313/826/825 +f 2313/826/825 2314/827/825 2311/824/857 +f 2310/828/826 2309/829/826 2312/825/858 +f 2312/825/858 2311/824/857 2310/828/826 +f 2315/737/827 2311/738/864 2314/734/829 +f 2314/734/829 2316/740/829 2315/737/827 +f 2307/741/830 2310/735/830 2311/738/864 +f 2311/738/864 2315/737/827 2307/741/830 +f 2317/825/832 2315/824/832 2316/827/833 +f 2316/827/833 2318/826/833 2317/825/832 +f 2308/829/834 2307/828/834 2315/824/832 +f 2315/824/832 2317/825/832 2308/829/834 +f 2312/731/835 2317/737/836 2318/733/837 +f 2318/733/837 2313/830/837 2312/731/835 +f 2309/831/838 2308/736/838 2317/737/836 +f 2317/737/836 2312/731/835 2309/831/838 +f 2319/832/36 2320/833/36 2321/834/36 +f 2321/834/36 2322/835/36 2319/832/36 +f 2323/836/839 2324/837/839 2325/838/840 +f 2325/838/840 2326/839/840 2323/836/839 +f 2322/840/841 2321/841/841 2324/837/839 +f 2324/837/839 2323/836/839 2322/840/841 +f 2327/737/842 2323/731/842 2326/734/843 +f 2326/734/843 2328/733/843 2327/737/842 +f 2319/741/844 2322/735/844 2323/731/842 +f 2323/731/842 2327/737/842 2319/741/844 +f 2329/837/859 2327/836/859 2328/839/871 +f 2328/839/871 2330/838/871 2329/837/859 +f 2320/841/847 2319/840/847 2327/836/859 +f 2327/836/859 2329/837/859 2320/841/847 +f 2324/842/848 2329/732/848 2330/843/849 +f 2330/843/849 2325/734/849 2324/842/848 +f 2321/831/850 2320/736/851 2329/732/848 +f 2329/732/848 2324/842/848 2321/831/850 +f 2331/721/36 2332/722/36 2333/723/36 +f 2333/723/36 2334/724/36 2331/721/36 +f 2335/725/852 2336/726/748 2337/727/860 +f 2337/727/860 2338/728/860 2335/725/852 +f 2334/729/750 2333/730/750 2336/726/748 +f 2336/726/748 2335/725/852 2334/729/750 +f 2339/731/751 2335/732/752 2338/733/753 +f 2338/733/753 2340/734/753 2339/731/751 +f 2331/735/754 2334/736/754 2335/732/752 +f 2335/732/752 2339/731/751 2331/735/754 +f 2341/726/872 2339/725/755 2340/728/756 +f 2340/728/756 2342/727/756 2341/726/872 +f 2332/730/757 2331/729/757 2339/725/755 +f 2339/725/755 2341/726/872 2332/730/757 +f 2336/737/758 2341/738/758 2342/739/759 +f 2342/739/759 2337/740/759 2336/737/758 +f 2333/741/760 2332/742/760 2341/738/758 +f 2341/738/758 2336/737/758 2333/741/760 +f 2343/743/36 2344/744/36 2345/745/36 +f 2345/745/36 2346/746/36 2343/743/36 +f 2347/747/761 2348/748/761 2349/749/762 +f 2349/749/762 2350/750/762 2347/747/761 +f 2346/751/763 2345/752/763 2348/748/761 +f 2348/748/761 2347/747/761 2346/751/763 +f 2351/753/764 2347/754/765 2350/755/766 +f 2350/755/766 2352/756/766 2351/753/764 +f 2343/757/767 2346/758/767 2347/754/765 +f 2347/754/765 2351/753/764 2343/757/767 +f 2353/748/768 2351/747/769 2352/750/873 +f 2352/750/873 2354/749/873 2353/748/768 +f 2344/752/874 2343/751/771 2351/747/769 +f 2351/747/769 2353/748/768 2344/752/874 +f 2348/754/772 2353/759/773 2354/760/774 +f 2354/760/774 2349/755/774 2348/754/772 +f 2345/758/775 2344/761/775 2353/759/773 +f 2353/759/773 2348/754/772 2345/758/775 +f 2355/762/776 2356/763/777 2357/764/778 +f 2357/764/778 2358/765/778 2355/762/776 +f 2359/766/779 2360/767/779 2356/763/777 +f 2356/763/777 2355/762/776 2359/766/779 +f 2361/768/780 2355/769/781 2358/770/782 +f 2358/770/782 2362/771/782 2361/768/780 +f 2363/772/783 2359/773/783 2355/769/781 +f 2355/769/781 2361/768/780 2363/772/783 +f 2364/763/784 2361/762/785 2362/765/786 +f 2362/765/786 2365/764/786 2364/763/784 +f 2366/767/787 2363/766/787 2361/762/785 +f 2361/762/785 2364/763/784 2366/767/787 +f 2356/774/788 2364/768/789 2365/771/790 +f 2365/771/790 2357/775/790 2356/774/788 +f 2360/776/791 2366/777/791 2364/768/789 +f 2364/768/789 2356/774/788 2360/776/791 +f 2367/778/792 2368/779/793 2369/780/794 +f 2369/780/794 2370/781/794 2367/778/792 +f 2371/782/795 2372/783/795 2368/779/793 +f 2368/779/793 2367/778/792 2371/782/795 +f 2373/784/796 2367/785/797 2370/786/798 +f 2370/786/798 2374/787/798 2373/784/796 +f 2375/788/799 2371/789/799 2367/785/797 +f 2367/785/797 2373/784/796 2375/788/799 +f 2376/790/800 2373/791/801 2374/792/802 +f 2374/792/802 2377/793/802 2376/790/800 +f 2378/794/803 2375/795/803 2373/791/801 +f 2373/791/801 2376/790/800 2378/794/803 +f 2368/785/804 2376/796/805 2377/787/806 +f 2377/787/806 2369/797/806 2368/785/804 +f 2372/789/807 2378/798/807 2376/796/805 +f 2376/796/805 2368/785/804 2372/789/807 +f 2379/799/36 2380/800/36 2381/801/36 +f 2381/801/36 2382/802/36 2379/799/36 +f 2383/803/808 2384/804/809 2385/805/810 +f 2385/805/810 2386/806/810 2383/803/808 +f 2382/807/811 2381/808/811 2384/804/809 +f 2384/804/809 2383/803/808 2382/807/811 +f 2387/809/812 2383/810/812 2386/811/813 +f 2386/811/813 2388/812/813 2387/809/812 +f 2379/813/814 2382/814/814 2383/810/812 +f 2383/810/812 2387/809/812 2379/813/814 +f 2389/804/815 2387/803/816 2388/806/875 +f 2388/806/875 2390/805/875 2389/804/815 +f 2380/808/876 2379/807/876 2387/803/816 +f 2387/803/816 2389/804/815 2380/808/876 +f 2384/815/819 2389/809/819 2390/816/820 +f 2390/816/820 2385/817/820 2384/815/819 +f 2381/818/821 2380/819/822 2389/809/819 +f 2389/809/819 2384/815/819 2381/818/821 +f 2391/820/36 2392/821/36 2393/822/36 +f 2393/822/36 2394/823/36 2391/820/36 +f 2395/824/857 2396/825/858 2397/826/825 +f 2397/826/825 2398/827/825 2395/824/857 +f 2394/828/826 2393/829/826 2396/825/858 +f 2396/825/858 2395/824/857 2394/828/826 +f 2399/737/827 2395/738/828 2398/734/829 +f 2398/734/829 2400/740/829 2399/737/827 +f 2391/741/830 2394/735/830 2395/738/828 +f 2395/738/828 2399/737/827 2391/741/830 +f 2401/825/877 2399/824/878 2400/827/833 +f 2400/827/833 2402/826/833 2401/825/877 +f 2392/829/834 2391/828/879 2399/824/878 +f 2399/824/878 2401/825/877 2392/829/834 +f 2396/731/835 2401/737/836 2402/733/837 +f 2402/733/837 2397/830/837 2396/731/835 +f 2393/831/838 2392/736/838 2401/737/836 +f 2401/737/836 2396/731/835 2393/831/838 +f 2403/832/36 2404/833/36 2405/834/36 +f 2405/834/36 2406/835/36 2403/832/36 +f 2407/836/839 2408/837/839 2409/838/880 +f 2409/838/880 2410/839/880 2407/836/839 +f 2406/840/841 2405/841/841 2408/837/839 +f 2408/837/839 2407/836/839 2406/840/841 +f 2411/737/842 2407/731/842 2410/734/843 +f 2410/734/843 2412/733/843 2411/737/842 +f 2403/741/844 2406/735/844 2407/731/842 +f 2407/731/842 2411/737/842 2403/741/844 +f 2413/837/859 2411/836/859 2412/839/881 +f 2412/839/881 2414/838/881 2413/837/859 +f 2404/841/882 2403/840/882 2411/836/859 +f 2411/836/859 2413/837/859 2404/841/882 +f 2408/842/848 2413/732/848 2414/843/849 +f 2414/843/849 2409/734/849 2408/842/848 +f 2405/831/850 2404/736/851 2413/732/848 +f 2413/732/848 2408/842/848 2405/831/850 +f 2415/721/36 2416/722/36 2417/723/36 +f 2417/723/36 2418/724/36 2415/721/36 +f 2419/725/852 2420/726/748 2421/727/860 +f 2421/727/860 2422/728/860 2419/725/852 +f 2418/729/750 2417/730/750 2420/726/748 +f 2420/726/748 2419/725/852 2418/729/750 +f 2423/731/751 2419/732/752 2422/733/753 +f 2422/733/753 2424/734/753 2423/731/751 +f 2415/735/754 2418/736/754 2419/732/752 +f 2419/732/752 2423/731/751 2415/735/754 +f 2425/726/755 2423/725/755 2424/728/756 +f 2424/728/756 2426/727/756 2425/726/755 +f 2416/730/757 2415/729/757 2423/725/755 +f 2423/725/755 2425/726/755 2416/730/757 +f 2420/737/758 2425/738/758 2426/739/759 +f 2426/739/759 2421/740/759 2420/737/758 +f 2417/741/760 2416/742/760 2425/738/758 +f 2425/738/758 2420/737/758 2417/741/760 +f 2427/743/36 2428/744/36 2429/745/36 +f 2429/745/36 2430/746/36 2427/743/36 +f 2431/747/761 2432/748/761 2433/749/762 +f 2433/749/762 2434/750/762 2431/747/761 +f 2430/751/763 2429/752/763 2432/748/761 +f 2432/748/761 2431/747/761 2430/751/763 +f 2435/753/764 2431/754/765 2434/755/766 +f 2434/755/766 2436/756/766 2435/753/764 +f 2427/757/767 2430/758/767 2431/754/765 +f 2431/754/765 2435/753/764 2427/757/767 +f 2437/748/768 2435/747/769 2436/750/873 +f 2436/750/873 2438/749/873 2437/748/768 +f 2428/752/874 2427/751/771 2435/747/769 +f 2435/747/769 2437/748/768 2428/752/874 +f 2432/754/772 2437/759/773 2438/760/774 +f 2438/760/774 2433/755/774 2432/754/772 +f 2429/758/775 2428/761/775 2437/759/773 +f 2437/759/773 2432/754/772 2429/758/775 +f 2439/762/776 2440/763/777 2441/764/778 +f 2441/764/778 2442/765/778 2439/762/776 +f 2443/766/779 2444/767/779 2440/763/777 +f 2440/763/777 2439/762/776 2443/766/779 +f 2445/768/780 2439/769/781 2442/770/782 +f 2442/770/782 2446/771/782 2445/768/780 +f 2447/772/783 2443/773/783 2439/769/781 +f 2439/769/781 2445/768/780 2447/772/783 +f 2448/763/784 2445/762/785 2446/765/786 +f 2446/765/786 2449/764/786 2448/763/784 +f 2450/767/787 2447/766/787 2445/762/785 +f 2445/762/785 2448/763/784 2450/767/787 +f 2440/774/788 2448/768/789 2449/771/790 +f 2449/771/790 2441/775/790 2440/774/788 +f 2444/776/791 2450/777/791 2448/768/789 +f 2448/768/789 2440/774/788 2444/776/791 +f 2451/778/792 2452/779/793 2453/780/794 +f 2453/780/794 2454/781/794 2451/778/792 +f 2455/782/795 2456/783/795 2452/779/793 +f 2452/779/793 2451/778/792 2455/782/795 +f 2457/784/796 2451/785/797 2454/786/798 +f 2454/786/798 2458/787/798 2457/784/796 +f 2459/788/799 2455/789/799 2451/785/797 +f 2451/785/797 2457/784/796 2459/788/799 +f 2460/790/800 2457/791/801 2458/792/802 +f 2458/792/802 2461/793/802 2460/790/800 +f 2462/794/803 2459/795/803 2457/791/801 +f 2457/791/801 2460/790/800 2462/794/803 +f 2452/785/804 2460/796/805 2461/787/806 +f 2461/787/806 2453/797/806 2452/785/804 +f 2456/789/807 2462/798/807 2460/796/805 +f 2460/796/805 2452/785/804 2456/789/807 +f 2463/799/36 2464/800/36 2465/801/36 +f 2465/801/36 2466/802/36 2463/799/36 +f 2467/803/808 2468/804/809 2469/805/810 +f 2469/805/810 2470/806/810 2467/803/808 +f 2466/807/811 2465/808/811 2468/804/809 +f 2468/804/809 2467/803/808 2466/807/811 +f 2471/809/812 2467/810/812 2470/811/813 +f 2470/811/813 2472/812/813 2471/809/812 +f 2463/813/814 2466/814/814 2467/810/812 +f 2467/810/812 2471/809/812 2463/813/814 +f 2473/804/815 2471/803/816 2472/806/869 +f 2472/806/869 2474/805/869 2473/804/815 +f 2464/808/870 2463/807/870 2471/803/816 +f 2471/803/816 2473/804/815 2464/808/870 +f 2468/815/819 2473/809/819 2474/816/820 +f 2474/816/820 2469/817/820 2468/815/819 +f 2465/818/821 2464/819/821 2473/809/819 +f 2473/809/819 2468/815/819 2465/818/821 +f 2475/820/36 2476/821/36 2477/822/36 +f 2477/822/36 2478/823/36 2475/820/36 +f 2479/824/857 2480/825/858 2481/826/825 +f 2481/826/825 2482/827/825 2479/824/857 +f 2478/828/862 2477/829/862 2480/825/858 +f 2480/825/858 2479/824/857 2478/828/862 +f 2483/737/863 2479/738/864 2482/734/829 +f 2482/734/829 2484/740/829 2483/737/863 +f 2475/741/830 2478/735/830 2479/738/864 +f 2479/738/864 2483/737/863 2475/741/830 +f 2485/825/832 2483/824/832 2484/827/833 +f 2484/827/833 2486/826/833 2485/825/832 +f 2476/829/834 2475/828/834 2483/824/832 +f 2483/824/832 2485/825/832 2476/829/834 +f 2480/731/835 2485/737/836 2486/733/837 +f 2486/733/837 2481/830/837 2480/731/835 +f 2477/831/838 2476/736/838 2485/737/836 +f 2485/737/836 2480/731/835 2477/831/838 +f 2487/832/36 2488/833/36 2489/834/36 +f 2489/834/36 2490/835/36 2487/832/36 +f 2491/836/839 2492/837/839 2493/838/865 +f 2493/838/865 2494/839/865 2491/836/839 +f 2490/840/866 2489/841/866 2492/837/839 +f 2492/837/839 2491/836/839 2490/840/866 +f 2495/737/842 2491/731/842 2494/734/843 +f 2494/734/843 2496/733/843 2495/737/842 +f 2487/741/844 2490/735/844 2491/731/842 +f 2491/731/842 2495/737/842 2487/741/844 +f 2497/837/859 2495/836/859 2496/839/846 +f 2496/839/846 2498/838/846 2497/837/859 +f 2488/841/847 2487/840/847 2495/836/859 +f 2495/836/859 2497/837/859 2488/841/847 +f 2492/842/867 2497/732/848 2498/843/849 +f 2498/843/849 2493/734/849 2492/842/867 +f 2489/831/850 2488/736/851 2497/732/848 +f 2497/732/848 2492/842/867 2489/831/850 +f 2499/721/36 2500/722/36 2501/723/36 +f 2501/723/36 2502/724/36 2499/721/36 +f 2503/725/852 2504/726/748 2505/727/749 +f 2505/727/749 2506/728/749 2503/725/852 +f 2502/729/750 2501/730/750 2504/726/748 +f 2504/726/748 2503/725/852 2502/729/750 +f 2507/731/751 2503/732/752 2506/733/753 +f 2506/733/753 2508/734/753 2507/731/751 +f 2499/735/754 2502/736/754 2503/732/752 +f 2503/732/752 2507/731/751 2499/735/754 +f 2509/726/872 2507/725/755 2508/728/756 +f 2508/728/756 2510/727/756 2509/726/872 +f 2500/730/757 2499/729/757 2507/725/755 +f 2507/725/755 2509/726/872 2500/730/757 +f 2504/737/758 2509/738/758 2510/739/759 +f 2510/739/759 2505/740/759 2504/737/758 +f 2501/741/760 2500/742/760 2509/738/758 +f 2509/738/758 2504/737/758 2501/741/760 +f 2511/743/36 2512/744/36 2513/745/36 +f 2513/745/36 2514/746/36 2511/743/36 +f 2515/747/761 2516/748/761 2517/749/762 +f 2517/749/762 2518/750/762 2515/747/761 +f 2514/751/763 2513/752/763 2516/748/761 +f 2516/748/761 2515/747/761 2514/751/763 +f 2519/753/764 2515/754/765 2518/755/766 +f 2518/755/766 2520/756/766 2519/753/764 +f 2511/757/767 2514/758/767 2515/754/765 +f 2515/754/765 2519/753/764 2511/757/767 +f 2521/748/768 2519/747/769 2520/750/873 +f 2520/750/873 2522/749/873 2521/748/768 +f 2512/752/874 2511/751/771 2519/747/769 +f 2519/747/769 2521/748/768 2512/752/874 +f 2516/754/772 2521/759/773 2522/760/774 +f 2522/760/774 2517/755/774 2516/754/772 +f 2513/758/775 2512/761/775 2521/759/773 +f 2521/759/773 2516/754/772 2513/758/775 +f 2523/762/776 2524/763/777 2525/764/778 +f 2525/764/778 2526/765/778 2523/762/776 +f 2527/766/779 2528/767/779 2524/763/777 +f 2524/763/777 2523/762/776 2527/766/779 +f 2529/768/780 2523/769/781 2526/770/782 +f 2526/770/782 2530/771/782 2529/768/780 +f 2531/772/783 2527/773/783 2523/769/781 +f 2523/769/781 2529/768/780 2531/772/783 +f 2532/763/784 2529/762/785 2530/765/786 +f 2530/765/786 2533/764/786 2532/763/784 +f 2534/767/787 2531/766/787 2529/762/785 +f 2529/762/785 2532/763/784 2534/767/787 +f 2524/774/788 2532/768/789 2533/771/790 +f 2533/771/790 2525/775/790 2524/774/788 +f 2528/776/791 2534/777/791 2532/768/789 +f 2532/768/789 2524/774/788 2528/776/791 +f 2535/778/868 2536/779/793 2537/780/794 +f 2537/780/794 2538/781/794 2535/778/868 +f 2539/782/795 2540/783/795 2536/779/793 +f 2536/779/793 2535/778/868 2539/782/795 +f 2541/784/796 2535/785/797 2538/786/798 +f 2538/786/798 2542/787/798 2541/784/796 +f 2543/788/799 2539/789/799 2535/785/797 +f 2535/785/797 2541/784/796 2543/788/799 +f 2544/790/853 2541/791/854 2542/792/802 +f 2542/792/802 2545/793/802 2544/790/853 +f 2546/794/803 2543/795/803 2541/791/854 +f 2541/791/854 2544/790/853 2546/794/803 +f 2536/785/804 2544/796/805 2545/787/806 +f 2545/787/806 2537/797/806 2536/785/804 +f 2540/789/807 2546/798/807 2544/796/805 +f 2544/796/805 2536/785/804 2540/789/807 +f 2547/799/36 2548/800/36 2549/801/36 +f 2549/801/36 2550/802/36 2547/799/36 +f 2551/803/808 2552/804/809 2553/805/810 +f 2553/805/810 2554/806/810 2551/803/808 +f 2550/807/811 2549/808/811 2552/804/809 +f 2552/804/809 2551/803/808 2550/807/811 +f 2555/809/812 2551/810/812 2554/811/813 +f 2554/811/813 2556/812/813 2555/809/812 +f 2547/813/814 2550/814/814 2551/810/812 +f 2551/810/812 2555/809/812 2547/813/814 +f 2557/804/815 2555/803/816 2556/806/869 +f 2556/806/869 2558/805/869 2557/804/815 +f 2548/808/870 2547/807/870 2555/803/816 +f 2555/803/816 2557/804/815 2548/808/870 +f 2552/815/819 2557/809/819 2558/816/820 +f 2558/816/820 2553/817/820 2552/815/819 +f 2549/818/821 2548/819/821 2557/809/819 +f 2557/809/819 2552/815/819 2549/818/821 +f 2559/820/36 2560/821/36 2561/822/36 +f 2561/822/36 2562/823/36 2559/820/36 +f 2563/824/857 2564/825/858 2565/826/825 +f 2565/826/825 2566/827/825 2563/824/857 +f 2562/828/826 2561/829/826 2564/825/858 +f 2564/825/858 2563/824/857 2562/828/826 +f 2567/737/827 2563/738/828 2566/734/829 +f 2566/734/829 2568/740/829 2567/737/827 +f 2559/741/830 2562/735/830 2563/738/828 +f 2563/738/828 2567/737/827 2559/741/830 +f 2569/825/832 2567/824/832 2568/827/833 +f 2568/827/833 2570/826/833 2569/825/832 +f 2560/829/834 2559/828/834 2567/824/832 +f 2567/824/832 2569/825/832 2560/829/834 +f 2564/731/835 2569/737/836 2570/733/837 +f 2570/733/837 2565/830/837 2564/731/835 +f 2561/831/838 2560/736/838 2569/737/836 +f 2569/737/836 2564/731/835 2561/831/838 +f 2571/832/36 2572/833/36 2573/834/36 +f 2573/834/36 2574/835/36 2571/832/36 +f 2575/836/839 2576/837/839 2577/838/865 +f 2577/838/865 2578/839/865 2575/836/839 +f 2574/840/861 2573/841/861 2576/837/839 +f 2576/837/839 2575/836/839 2574/840/861 +f 2579/737/842 2575/731/842 2578/734/843 +f 2578/734/843 2580/733/843 2579/737/842 +f 2571/741/844 2574/735/844 2575/731/842 +f 2575/731/842 2579/737/842 2571/741/844 +f 2581/837/859 2579/836/859 2580/839/881 +f 2580/839/881 2582/838/881 2581/837/859 +f 2572/841/882 2571/840/882 2579/836/859 +f 2579/836/859 2581/837/859 2572/841/882 +f 2576/842/848 2581/732/848 2582/843/849 +f 2582/843/849 2577/734/849 2576/842/848 +f 2573/831/850 2572/736/851 2581/732/848 +f 2581/732/848 2576/842/848 2573/831/850 +f 2583/721/36 2584/722/36 2585/723/36 +f 2585/723/36 2586/724/36 2583/721/36 +f 2587/725/852 2588/726/748 2589/727/860 +f 2589/727/860 2590/728/860 2587/725/852 +f 2586/729/750 2585/730/750 2588/726/748 +f 2588/726/748 2587/725/852 2586/729/750 +f 2591/731/751 2587/732/752 2590/733/753 +f 2590/733/753 2592/734/753 2591/731/751 +f 2583/735/754 2586/736/754 2587/732/752 +f 2587/732/752 2591/731/751 2583/735/754 +f 2593/726/755 2591/725/755 2592/728/756 +f 2592/728/756 2594/727/756 2593/726/755 +f 2584/730/757 2583/729/757 2591/725/755 +f 2591/725/755 2593/726/755 2584/730/757 +f 2588/737/758 2593/738/758 2594/739/759 +f 2594/739/759 2589/740/759 2588/737/758 +f 2585/741/760 2584/742/760 2593/738/758 +f 2593/738/758 2588/737/758 2585/741/760 +f 2595/743/36 2596/744/36 2597/745/36 +f 2597/745/36 2598/746/36 2595/743/36 +f 2599/747/883 2600/748/884 2601/749/762 +f 2601/749/762 2602/750/762 2599/747/883 +f 2598/751/763 2597/752/763 2600/748/884 +f 2600/748/884 2599/747/883 2598/751/763 +f 2603/753/764 2599/754/765 2602/755/766 +f 2602/755/766 2604/756/766 2603/753/764 +f 2595/757/767 2598/758/767 2599/754/765 +f 2599/754/765 2603/753/764 2595/757/767 +f 2605/748/768 2603/747/769 2604/750/885 +f 2604/750/885 2606/749/885 2605/748/768 +f 2596/752/771 2595/751/771 2603/747/769 +f 2603/747/769 2605/748/768 2596/752/771 +f 2600/754/772 2605/759/773 2606/760/774 +f 2606/760/774 2601/755/774 2600/754/772 +f 2597/758/775 2596/761/775 2605/759/773 +f 2605/759/773 2600/754/772 2597/758/775 +f 2607/762/776 2608/763/777 2609/764/778 +f 2609/764/778 2610/765/778 2607/762/776 +f 2611/766/779 2612/767/779 2608/763/777 +f 2608/763/777 2607/762/776 2611/766/779 +f 2613/768/780 2607/769/781 2610/770/782 +f 2610/770/782 2614/771/782 2613/768/780 +f 2615/772/783 2611/773/783 2607/769/781 +f 2607/769/781 2613/768/780 2615/772/783 +f 2616/763/784 2613/762/785 2614/765/786 +f 2614/765/786 2617/764/786 2616/763/784 +f 2618/767/787 2615/766/787 2613/762/785 +f 2613/762/785 2616/763/784 2618/767/787 +f 2608/774/788 2616/768/789 2617/771/790 +f 2617/771/790 2609/775/790 2608/774/788 +f 2612/776/791 2618/777/791 2616/768/789 +f 2616/768/789 2608/774/788 2612/776/791 +f 2619/778/792 2620/779/793 2621/780/794 +f 2621/780/794 2622/781/794 2619/778/792 +f 2623/782/795 2624/783/795 2620/779/793 +f 2620/779/793 2619/778/792 2623/782/795 +f 2625/784/796 2619/785/797 2622/786/798 +f 2622/786/798 2626/787/798 2625/784/796 +f 2627/788/799 2623/789/799 2619/785/797 +f 2619/785/797 2625/784/796 2627/788/799 +f 2628/790/800 2625/791/801 2626/792/802 +f 2626/792/802 2629/793/802 2628/790/800 +f 2630/794/803 2627/795/803 2625/791/801 +f 2625/791/801 2628/790/800 2630/794/803 +f 2620/785/804 2628/796/805 2629/787/806 +f 2629/787/806 2621/797/806 2620/785/804 +f 2624/789/807 2630/798/807 2628/796/805 +f 2628/796/805 2620/785/804 2624/789/807 +f 2631/799/36 2632/800/36 2633/801/36 +f 2633/801/36 2634/802/36 2631/799/36 +f 2635/803/808 2636/804/809 2637/805/810 +f 2637/805/810 2638/806/810 2635/803/808 +f 2634/807/811 2633/808/811 2636/804/809 +f 2636/804/809 2635/803/808 2634/807/811 +f 2639/809/812 2635/810/812 2638/811/813 +f 2638/811/813 2640/812/813 2639/809/812 +f 2631/813/814 2634/814/814 2635/810/812 +f 2635/810/812 2639/809/812 2631/813/814 +f 2641/804/815 2639/803/816 2640/806/869 +f 2640/806/869 2642/805/869 2641/804/815 +f 2632/808/870 2631/807/870 2639/803/816 +f 2639/803/816 2641/804/815 2632/808/870 +f 2636/815/819 2641/809/819 2642/816/820 +f 2642/816/820 2637/817/820 2636/815/819 +f 2633/818/821 2632/819/821 2641/809/819 +f 2641/809/819 2636/815/819 2633/818/821 +f 2643/820/36 2644/821/36 2645/822/36 +f 2645/822/36 2646/823/36 2643/820/36 +f 2647/824/857 2648/825/858 2649/826/825 +f 2649/826/825 2650/827/825 2647/824/857 +f 2646/828/826 2645/829/826 2648/825/858 +f 2648/825/858 2647/824/857 2646/828/826 +f 2651/737/863 2647/738/864 2650/734/829 +f 2650/734/829 2652/740/829 2651/737/863 +f 2643/741/830 2646/735/830 2647/738/864 +f 2647/738/864 2651/737/863 2643/741/830 +f 2653/825/831 2651/824/832 2652/827/833 +f 2652/827/833 2654/826/886 2653/825/831 +f 2644/829/834 2643/828/887 2651/824/832 +f 2651/824/832 2653/825/831 2644/829/834 +f 2648/731/835 2653/737/836 2654/733/837 +f 2654/733/837 2649/830/837 2648/731/835 +f 2645/831/838 2644/736/838 2653/737/836 +f 2653/737/836 2648/731/835 2645/831/838 +f 2655/832/36 2656/833/36 2657/834/36 +f 2657/834/36 2658/835/36 2655/832/36 +f 2659/836/839 2660/837/839 2661/838/840 +f 2661/838/840 2662/839/840 2659/836/839 +f 2658/840/841 2657/841/841 2660/837/839 +f 2660/837/839 2659/836/839 2658/840/841 +f 2663/737/842 2659/731/842 2662/734/843 +f 2662/734/843 2664/733/843 2663/737/842 +f 2655/741/844 2658/735/844 2659/731/842 +f 2659/731/842 2663/737/842 2655/741/844 +f 2665/837/859 2663/836/859 2664/839/871 +f 2664/839/871 2666/838/871 2665/837/859 +f 2656/841/847 2655/840/847 2663/836/859 +f 2663/836/859 2665/837/859 2656/841/847 +f 2660/842/848 2665/732/848 2666/843/849 +f 2666/843/849 2661/734/849 2660/842/848 +f 2657/831/850 2656/736/851 2665/732/848 +f 2665/732/848 2660/842/848 2657/831/850 +f 2667/721/36 2668/722/36 2669/723/36 +f 2669/723/36 2670/724/36 2667/721/36 +f 2671/725/888 2672/726/888 2673/727/889 +f 2673/727/889 2674/728/889 2671/725/888 +f 2670/729/890 2669/730/890 2672/726/888 +f 2672/726/888 2671/725/888 2670/729/890 +f 2675/731/891 2671/732/892 2674/733/893 +f 2674/733/893 2676/734/894 2675/731/891 +f 2667/735/895 2670/736/895 2671/732/892 +f 2671/732/892 2675/731/891 2667/735/895 +f 2677/726/896 2675/725/896 2676/728/897 +f 2676/728/897 2678/727/897 2677/726/896 +f 2668/730/898 2667/729/898 2675/725/896 +f 2675/725/896 2677/726/896 2668/730/898 +f 2672/737/899 2677/738/899 2678/739/900 +f 2678/739/900 2673/740/900 2672/737/899 +f 2669/741/901 2668/742/901 2677/738/899 +f 2677/738/899 2672/737/899 2669/741/901 +f 2679/743/36 2680/744/36 2681/745/36 +f 2681/745/36 2682/746/36 2679/743/36 +f 2683/747/902 2684/748/902 2685/749/903 +f 2685/749/903 2686/750/903 2683/747/902 +f 2682/751/904 2681/752/904 2684/748/902 +f 2684/748/902 2683/747/902 2682/751/904 +f 2687/753/905 2683/754/906 2686/755/907 +f 2686/755/907 2688/756/908 2687/753/905 +f 2679/757/909 2682/758/909 2683/754/906 +f 2683/754/906 2687/753/905 2679/757/909 +f 2689/748/910 2687/747/911 2688/750/912 +f 2688/750/912 2690/749/912 2689/748/910 +f 2680/752/913 2679/751/913 2687/747/911 +f 2687/747/911 2689/748/910 2680/752/913 +f 2684/754/914 2689/759/915 2690/760/916 +f 2690/760/916 2685/755/916 2684/754/914 +f 2681/758/917 2680/761/917 2689/759/915 +f 2689/759/915 2684/754/914 2681/758/917 +f 2691/762/918 2692/763/919 2693/764/920 +f 2693/764/920 2694/765/920 2691/762/918 +f 2695/766/921 2696/767/921 2692/763/919 +f 2692/763/919 2691/762/918 2695/766/921 +f 2697/768/922 2691/769/923 2694/770/924 +f 2694/770/924 2698/771/924 2697/768/922 +f 2699/772/925 2695/773/925 2691/769/923 +f 2691/769/923 2697/768/922 2699/772/925 +f 2700/763/926 2697/762/927 2698/765/928 +f 2698/765/928 2701/764/928 2700/763/926 +f 2702/767/929 2699/766/929 2697/762/927 +f 2697/762/927 2700/763/926 2702/767/929 +f 2692/774/930 2700/768/931 2701/771/932 +f 2701/771/932 2693/775/932 2692/774/930 +f 2696/776/933 2702/777/933 2700/768/931 +f 2700/768/931 2692/774/930 2696/776/933 +f 2703/778/934 2704/779/935 2705/780/936 +f 2705/780/936 2706/781/936 2703/778/934 +f 2707/782/937 2708/783/937 2704/779/935 +f 2704/779/935 2703/778/934 2707/782/937 +f 2709/784/938 2703/785/939 2706/786/940 +f 2706/786/940 2710/787/940 2709/784/938 +f 2711/788/941 2707/789/941 2703/785/939 +f 2703/785/939 2709/784/938 2711/788/941 +f 2712/790/942 2709/791/943 2710/792/944 +f 2710/792/944 2713/793/944 2712/790/942 +f 2714/794/945 2711/795/945 2709/791/943 +f 2709/791/943 2712/790/942 2714/794/945 +f 2704/785/946 2712/796/947 2713/787/948 +f 2713/787/948 2705/797/948 2704/785/946 +f 2708/789/949 2714/798/949 2712/796/947 +f 2712/796/947 2704/785/946 2708/789/949 +f 2715/799/36 2716/800/36 2717/801/36 +f 2717/801/36 2718/802/36 2715/799/36 +f 2719/803/950 2720/804/951 2721/805/952 +f 2721/805/952 2722/806/952 2719/803/950 +f 2718/807/953 2717/808/953 2720/804/951 +f 2720/804/951 2719/803/950 2718/807/953 +f 2723/809/954 2719/810/954 2722/811/955 +f 2722/811/955 2724/812/955 2723/809/954 +f 2715/813/956 2718/814/956 2719/810/954 +f 2719/810/954 2723/809/954 2715/813/956 +f 2725/804/957 2723/803/958 2724/806/959 +f 2724/806/959 2726/805/959 2725/804/957 +f 2716/808/960 2715/807/960 2723/803/958 +f 2723/803/958 2725/804/957 2716/808/960 +f 2720/815/961 2725/809/961 2726/816/962 +f 2726/816/962 2721/817/962 2720/815/961 +f 2717/818/963 2716/819/963 2725/809/961 +f 2725/809/961 2720/815/961 2717/818/963 +f 2727/820/36 2728/821/36 2729/822/36 +f 2729/822/36 2730/823/36 2727/820/36 +f 2731/824/964 2732/825/965 2733/826/966 +f 2733/826/966 2734/827/966 2731/824/964 +f 2730/828/967 2729/829/967 2732/825/965 +f 2732/825/965 2731/824/964 2730/828/967 +f 2735/737/968 2731/738/969 2734/734/970 +f 2734/734/970 2736/740/970 2735/737/968 +f 2727/741/971 2730/735/971 2731/738/969 +f 2731/738/969 2735/737/968 2727/741/971 +f 2737/825/972 2735/824/972 2736/827/973 +f 2736/827/973 2738/826/973 2737/825/972 +f 2728/829/974 2727/828/974 2735/824/972 +f 2735/824/972 2737/825/972 2728/829/974 +f 2732/731/975 2737/737/976 2738/733/977 +f 2738/733/977 2733/830/977 2732/731/975 +f 2729/831/978 2728/736/978 2737/737/976 +f 2737/737/976 2732/731/975 2729/831/978 +f 2739/832/36 2740/833/36 2741/834/36 +f 2741/834/36 2742/835/36 2739/832/36 +f 2743/836/979 2744/837/979 2745/838/980 +f 2745/838/980 2746/839/980 2743/836/979 +f 2742/840/981 2741/841/981 2744/837/979 +f 2744/837/979 2743/836/979 2742/840/981 +f 2747/737/982 2743/731/982 2746/734/983 +f 2746/734/983 2748/733/983 2747/737/982 +f 2739/741/984 2742/735/985 2743/731/982 +f 2743/731/982 2747/737/982 2739/741/984 +f 2749/837/986 2747/836/986 2748/839/987 +f 2748/839/987 2750/838/987 2749/837/986 +f 2740/841/988 2739/840/988 2747/836/986 +f 2747/836/986 2749/837/986 2740/841/988 +f 2744/842/989 2749/732/989 2750/843/990 +f 2750/843/990 2745/734/990 2744/842/989 +f 2741/831/991 2740/736/991 2749/732/989 +f 2749/732/989 2744/842/989 2741/831/991 +f 2751/721/226 2752/722/226 2753/723/226 +f 2753/723/226 2754/724/226 2751/721/226 +f 2755/725/888 2756/726/888 2757/727/889 +f 2757/727/889 2758/728/889 2755/725/888 +f 2754/729/890 2753/730/890 2756/726/888 +f 2756/726/888 2755/725/888 2754/729/890 +f 2759/731/891 2755/732/892 2758/733/893 +f 2758/733/893 2760/734/893 2759/731/891 +f 2751/735/895 2754/736/895 2755/732/892 +f 2755/732/892 2759/731/891 2751/735/895 +f 2761/726/896 2759/725/896 2760/728/897 +f 2760/728/897 2762/727/897 2761/726/896 +f 2752/730/898 2751/729/898 2759/725/896 +f 2759/725/896 2761/726/896 2752/730/898 +f 2756/737/899 2761/738/899 2762/739/900 +f 2762/739/900 2757/740/900 2756/737/899 +f 2753/741/901 2752/742/901 2761/738/899 +f 2761/738/899 2756/737/899 2753/741/901 +f 2763/743/36 2764/744/36 2765/745/36 +f 2765/745/36 2766/746/36 2763/743/36 +f 2767/747/902 2768/748/902 2769/749/903 +f 2769/749/903 2770/750/903 2767/747/902 +f 2766/751/904 2765/752/904 2768/748/902 +f 2768/748/902 2767/747/902 2766/751/904 +f 2771/753/905 2767/754/906 2770/755/907 +f 2770/755/907 2772/756/908 2771/753/905 +f 2763/757/909 2766/758/909 2767/754/906 +f 2767/754/906 2771/753/905 2763/757/909 +f 2773/748/910 2771/747/911 2772/750/912 +f 2772/750/912 2774/749/912 2773/748/910 +f 2764/752/913 2763/751/913 2771/747/911 +f 2771/747/911 2773/748/910 2764/752/913 +f 2768/754/914 2773/759/915 2774/760/916 +f 2774/760/916 2769/755/916 2768/754/914 +f 2765/758/917 2764/761/917 2773/759/915 +f 2773/759/915 2768/754/914 2765/758/917 +f 2775/762/918 2776/763/919 2777/764/920 +f 2777/764/920 2778/765/920 2775/762/918 +f 2779/766/921 2780/767/921 2776/763/919 +f 2776/763/919 2775/762/918 2779/766/921 +f 2781/768/922 2775/769/923 2778/770/924 +f 2778/770/924 2782/771/924 2781/768/922 +f 2783/772/925 2779/773/925 2775/769/923 +f 2775/769/923 2781/768/922 2783/772/925 +f 2784/763/926 2781/762/927 2782/765/928 +f 2782/765/928 2785/764/928 2784/763/926 +f 2786/767/929 2783/766/929 2781/762/927 +f 2781/762/927 2784/763/926 2786/767/929 +f 2776/774/930 2784/768/931 2785/771/932 +f 2785/771/932 2777/775/932 2776/774/930 +f 2780/776/933 2786/777/933 2784/768/931 +f 2784/768/931 2776/774/930 2780/776/933 +f 2787/778/934 2788/779/935 2789/780/936 +f 2789/780/936 2790/781/936 2787/778/934 +f 2791/782/937 2792/783/937 2788/779/935 +f 2788/779/935 2787/778/934 2791/782/937 +f 2793/784/938 2787/785/939 2790/786/940 +f 2790/786/940 2794/787/940 2793/784/938 +f 2795/788/941 2791/789/941 2787/785/939 +f 2787/785/939 2793/784/938 2795/788/941 +f 2796/790/942 2793/791/943 2794/792/944 +f 2794/792/944 2797/793/944 2796/790/942 +f 2798/794/945 2795/795/945 2793/791/943 +f 2793/791/943 2796/790/942 2798/794/945 +f 2788/785/946 2796/796/947 2797/787/948 +f 2797/787/948 2789/797/948 2788/785/946 +f 2792/789/949 2798/798/949 2796/796/947 +f 2796/796/947 2788/785/946 2792/789/949 +f 2799/799/37 2800/800/37 2801/801/37 +f 2801/801/37 2802/802/37 2799/799/37 +f 2803/803/950 2804/804/951 2805/805/952 +f 2805/805/952 2806/806/952 2803/803/950 +f 2802/807/953 2801/808/953 2804/804/951 +f 2804/804/951 2803/803/950 2802/807/953 +f 2807/809/954 2803/810/954 2806/811/955 +f 2806/811/955 2808/812/955 2807/809/954 +f 2799/813/956 2802/814/956 2803/810/954 +f 2803/810/954 2807/809/954 2799/813/956 +f 2809/804/957 2807/803/958 2808/806/959 +f 2808/806/959 2810/805/959 2809/804/957 +f 2800/808/960 2799/807/960 2807/803/958 +f 2807/803/958 2809/804/957 2800/808/960 +f 2804/815/961 2809/809/961 2810/816/962 +f 2810/816/962 2805/817/962 2804/815/961 +f 2801/818/963 2800/819/963 2809/809/961 +f 2809/809/961 2804/815/961 2801/818/963 +f 2811/820/36 2812/821/36 2813/822/36 +f 2813/822/36 2814/823/36 2811/820/36 +f 2815/824/964 2816/825/965 2817/826/966 +f 2817/826/966 2818/827/966 2815/824/964 +f 2814/828/992 2813/829/967 2816/825/965 +f 2816/825/965 2815/824/964 2814/828/992 +f 2819/737/968 2815/738/969 2818/734/970 +f 2818/734/970 2820/740/970 2819/737/968 +f 2811/741/971 2814/735/971 2815/738/969 +f 2815/738/969 2819/737/968 2811/741/971 +f 2821/825/972 2819/824/972 2820/827/973 +f 2820/827/973 2822/826/973 2821/825/972 +f 2812/829/974 2811/828/974 2819/824/972 +f 2819/824/972 2821/825/972 2812/829/974 +f 2816/731/975 2821/737/976 2822/733/977 +f 2822/733/977 2817/830/977 2816/731/975 +f 2813/831/978 2812/736/978 2821/737/976 +f 2821/737/976 2816/731/975 2813/831/978 +f 2823/832/37 2824/833/37 2825/834/37 +f 2825/834/37 2826/835/37 2823/832/37 +f 2827/836/993 2828/837/993 2829/838/994 +f 2829/838/994 2830/839/980 2827/836/993 +f 2826/840/981 2825/841/981 2828/837/993 +f 2828/837/993 2827/836/993 2826/840/981 +f 2831/737/982 2827/731/982 2830/734/983 +f 2830/734/983 2832/733/983 2831/737/982 +f 2823/741/984 2826/735/985 2827/731/982 +f 2827/731/982 2831/737/982 2823/741/984 +f 2833/837/986 2831/836/986 2832/839/987 +f 2832/839/987 2834/838/987 2833/837/986 +f 2824/841/988 2823/840/988 2831/836/986 +f 2831/836/986 2833/837/986 2824/841/988 +f 2828/842/989 2833/732/989 2834/843/990 +f 2834/843/990 2829/734/990 2828/842/989 +f 2825/831/991 2824/736/991 2833/732/989 +f 2833/732/989 2828/842/989 2825/831/991 +f 2835/721/36 2836/722/36 2837/723/36 +f 2837/723/36 2838/724/36 2835/721/36 +f 2839/725/888 2840/726/888 2841/727/889 +f 2841/727/889 2842/728/889 2839/725/888 +f 2838/729/890 2837/730/890 2840/726/888 +f 2840/726/888 2839/725/888 2838/729/890 +f 2843/731/891 2839/732/892 2842/733/893 +f 2842/733/893 2844/734/893 2843/731/891 +f 2835/735/895 2838/736/895 2839/732/892 +f 2839/732/892 2843/731/891 2835/735/895 +f 2845/726/896 2843/725/896 2844/728/897 +f 2844/728/897 2846/727/897 2845/726/896 +f 2836/730/898 2835/729/898 2843/725/896 +f 2843/725/896 2845/726/896 2836/730/898 +f 2840/737/899 2845/738/899 2846/739/900 +f 2846/739/900 2841/740/900 2840/737/899 +f 2837/741/901 2836/742/901 2845/738/899 +f 2845/738/899 2840/737/899 2837/741/901 +f 2847/743/36 2848/744/36 2849/745/36 +f 2849/745/36 2850/746/36 2847/743/36 +f 2851/747/995 2852/748/995 2853/749/903 +f 2853/749/903 2854/750/903 2851/747/995 +f 2850/751/904 2849/752/904 2852/748/995 +f 2852/748/995 2851/747/995 2850/751/904 +f 2855/753/905 2851/754/906 2854/755/907 +f 2854/755/907 2856/756/908 2855/753/905 +f 2847/757/909 2850/758/909 2851/754/906 +f 2851/754/906 2855/753/905 2847/757/909 +f 2857/748/910 2855/747/911 2856/750/912 +f 2856/750/912 2858/749/912 2857/748/910 +f 2848/752/913 2847/751/913 2855/747/911 +f 2855/747/911 2857/748/910 2848/752/913 +f 2852/754/914 2857/759/915 2858/760/916 +f 2858/760/916 2853/755/916 2852/754/914 +f 2849/758/917 2848/761/917 2857/759/915 +f 2857/759/915 2852/754/914 2849/758/917 +f 2859/762/918 2860/763/919 2861/764/920 +f 2861/764/920 2862/765/920 2859/762/918 +f 2863/766/921 2864/767/921 2860/763/919 +f 2860/763/919 2859/762/918 2863/766/921 +f 2865/768/922 2859/769/923 2862/770/924 +f 2862/770/924 2866/771/924 2865/768/922 +f 2867/772/925 2863/773/925 2859/769/923 +f 2859/769/923 2865/768/922 2867/772/925 +f 2868/763/926 2865/762/927 2866/765/928 +f 2866/765/928 2869/764/928 2868/763/926 +f 2870/767/929 2867/766/929 2865/762/927 +f 2865/762/927 2868/763/926 2870/767/929 +f 2860/774/930 2868/768/931 2869/771/932 +f 2869/771/932 2861/775/932 2860/774/930 +f 2864/776/933 2870/777/933 2868/768/931 +f 2868/768/931 2860/774/930 2864/776/933 +f 2871/778/934 2872/779/935 2873/780/936 +f 2873/780/936 2874/781/936 2871/778/934 +f 2875/782/937 2876/783/937 2872/779/935 +f 2872/779/935 2871/778/934 2875/782/937 +f 2877/784/938 2871/785/939 2874/786/940 +f 2874/786/940 2878/787/940 2877/784/938 +f 2879/788/941 2875/789/941 2871/785/939 +f 2871/785/939 2877/784/938 2879/788/941 +f 2880/790/942 2877/791/943 2878/792/944 +f 2878/792/944 2881/793/944 2880/790/942 +f 2882/794/945 2879/795/945 2877/791/943 +f 2877/791/943 2880/790/942 2882/794/945 +f 2872/785/946 2880/796/947 2881/787/948 +f 2881/787/948 2873/797/948 2872/785/946 +f 2876/789/949 2882/798/949 2880/796/947 +f 2880/796/947 2872/785/946 2876/789/949 +f 2883/799/36 2884/800/36 2885/801/36 +f 2885/801/36 2886/802/36 2883/799/36 +f 2887/803/996 2888/804/997 2889/805/952 +f 2889/805/952 2890/806/952 2887/803/996 +f 2886/807/953 2885/808/953 2888/804/997 +f 2888/804/997 2887/803/996 2886/807/953 +f 2891/809/954 2887/810/954 2890/811/955 +f 2890/811/955 2892/812/955 2891/809/954 +f 2883/813/956 2886/814/956 2887/810/954 +f 2887/810/954 2891/809/954 2883/813/956 +f 2893/804/957 2891/803/958 2892/806/959 +f 2892/806/959 2894/805/959 2893/804/957 +f 2884/808/960 2883/807/960 2891/803/958 +f 2891/803/958 2893/804/957 2884/808/960 +f 2888/815/961 2893/809/961 2894/816/962 +f 2894/816/962 2889/817/962 2888/815/961 +f 2885/818/963 2884/819/963 2893/809/961 +f 2893/809/961 2888/815/961 2885/818/963 +f 2895/820/36 2896/821/36 2897/822/36 +f 2897/822/36 2898/823/36 2895/820/36 +f 2899/824/998 2900/825/999 2901/826/966 +f 2901/826/966 2902/827/966 2899/824/998 +f 2898/828/967 2897/829/967 2900/825/999 +f 2900/825/999 2899/824/998 2898/828/967 +f 2903/737/968 2899/738/969 2902/734/970 +f 2902/734/970 2904/740/970 2903/737/968 +f 2895/741/971 2898/735/971 2899/738/969 +f 2899/738/969 2903/737/968 2895/741/971 +f 2905/825/972 2903/824/972 2904/827/973 +f 2904/827/973 2906/826/973 2905/825/972 +f 2896/829/974 2895/828/974 2903/824/972 +f 2903/824/972 2905/825/972 2896/829/974 +f 2900/731/975 2905/737/976 2906/733/977 +f 2906/733/977 2901/830/977 2900/731/975 +f 2897/831/978 2896/736/978 2905/737/976 +f 2905/737/976 2900/731/975 2897/831/978 +f 2907/832/226 2908/833/226 2909/834/226 +f 2909/834/226 2910/835/226 2907/832/226 +f 2911/836/993 2912/837/993 2913/838/980 +f 2913/838/980 2914/839/980 2911/836/993 +f 2910/840/981 2909/841/981 2912/837/993 +f 2912/837/993 2911/836/993 2910/840/981 +f 2915/737/982 2911/731/982 2914/734/983 +f 2914/734/983 2916/733/983 2915/737/982 +f 2907/741/984 2910/735/985 2911/731/982 +f 2911/731/982 2915/737/982 2907/741/984 +f 2917/837/986 2915/836/986 2916/839/987 +f 2916/839/987 2918/838/987 2917/837/986 +f 2908/841/988 2907/840/988 2915/836/986 +f 2915/836/986 2917/837/986 2908/841/988 +f 2912/842/989 2917/732/989 2918/843/990 +f 2918/843/990 2913/734/990 2912/842/989 +f 2909/831/991 2908/736/991 2917/732/989 +f 2917/732/989 2912/842/989 2909/831/991 +f 2919/721/36 2920/722/36 2921/723/36 +f 2921/723/36 2922/724/36 2919/721/36 +f 2923/725/888 2924/726/888 2925/727/889 +f 2925/727/889 2926/728/889 2923/725/888 +f 2922/729/890 2921/730/890 2924/726/888 +f 2924/726/888 2923/725/888 2922/729/890 +f 2927/731/891 2923/732/892 2926/733/893 +f 2926/733/893 2928/734/893 2927/731/891 +f 2919/735/895 2922/736/895 2923/732/892 +f 2923/732/892 2927/731/891 2919/735/895 +f 2929/726/896 2927/725/896 2928/728/897 +f 2928/728/897 2930/727/897 2929/726/896 +f 2920/730/898 2919/729/898 2927/725/896 +f 2927/725/896 2929/726/896 2920/730/898 +f 2924/737/899 2929/738/899 2930/739/900 +f 2930/739/900 2925/740/900 2924/737/899 +f 2921/741/901 2920/742/901 2929/738/899 +f 2929/738/899 2924/737/899 2921/741/901 +f 2931/743/37 2932/744/37 2933/745/37 +f 2933/745/37 2934/746/37 2931/743/37 +f 2935/747/995 2936/748/995 2937/749/903 +f 2937/749/903 2938/750/903 2935/747/995 +f 2934/751/904 2933/752/904 2936/748/995 +f 2936/748/995 2935/747/995 2934/751/904 +f 2939/753/905 2935/754/906 2938/755/907 +f 2938/755/907 2940/756/908 2939/753/905 +f 2931/757/909 2934/758/909 2935/754/906 +f 2935/754/906 2939/753/905 2931/757/909 +f 2941/748/910 2939/747/911 2940/750/912 +f 2940/750/912 2942/749/912 2941/748/910 +f 2932/752/913 2931/751/913 2939/747/911 +f 2939/747/911 2941/748/910 2932/752/913 +f 2936/754/914 2941/759/915 2942/760/916 +f 2942/760/916 2937/755/916 2936/754/914 +f 2933/758/917 2932/761/917 2941/759/915 +f 2941/759/915 2936/754/914 2933/758/917 +f 2943/762/918 2944/763/919 2945/764/920 +f 2945/764/920 2946/765/920 2943/762/918 +f 2947/766/921 2948/767/921 2944/763/919 +f 2944/763/919 2943/762/918 2947/766/921 +f 2949/768/922 2943/769/923 2946/770/924 +f 2946/770/924 2950/771/924 2949/768/922 +f 2951/772/925 2947/773/925 2943/769/923 +f 2943/769/923 2949/768/922 2951/772/925 +f 2952/763/926 2949/762/927 2950/765/928 +f 2950/765/928 2953/764/928 2952/763/926 +f 2954/767/929 2951/766/929 2949/762/927 +f 2949/762/927 2952/763/926 2954/767/929 +f 2944/774/930 2952/768/931 2953/771/932 +f 2953/771/932 2945/775/932 2944/774/930 +f 2948/776/933 2954/777/933 2952/768/931 +f 2952/768/931 2944/774/930 2948/776/933 +f 2955/778/934 2956/779/935 2957/780/936 +f 2957/780/936 2958/781/936 2955/778/934 +f 2959/782/937 2960/783/937 2956/779/935 +f 2956/779/935 2955/778/934 2959/782/937 +f 2961/784/938 2955/785/939 2958/786/940 +f 2958/786/940 2962/787/940 2961/784/938 +f 2963/788/941 2959/789/941 2955/785/939 +f 2955/785/939 2961/784/938 2963/788/941 +f 2964/790/1000 2961/791/943 2962/792/944 +f 2962/792/944 2965/793/944 2964/790/1000 +f 2966/794/945 2963/795/945 2961/791/943 +f 2961/791/943 2964/790/1000 2966/794/945 +f 2956/785/946 2964/796/947 2965/787/948 +f 2965/787/948 2957/797/948 2956/785/946 +f 2960/789/949 2966/798/949 2964/796/947 +f 2964/796/947 2956/785/946 2960/789/949 +f 2967/799/36 2968/800/36 2969/801/36 +f 2969/801/36 2970/802/36 2967/799/36 +f 2971/803/996 2972/804/997 2973/805/952 +f 2973/805/952 2974/806/952 2971/803/996 +f 2970/807/953 2969/808/953 2972/804/997 +f 2972/804/997 2971/803/996 2970/807/953 +f 2975/809/954 2971/810/954 2974/811/955 +f 2974/811/955 2976/812/955 2975/809/954 +f 2967/813/956 2970/814/956 2971/810/954 +f 2971/810/954 2975/809/954 2967/813/956 +f 2977/804/957 2975/803/958 2976/806/959 +f 2976/806/959 2978/805/959 2977/804/957 +f 2968/808/960 2967/807/960 2975/803/958 +f 2975/803/958 2977/804/957 2968/808/960 +f 2972/815/961 2977/809/961 2978/816/962 +f 2978/816/962 2973/817/962 2972/815/961 +f 2969/818/963 2968/819/963 2977/809/961 +f 2977/809/961 2972/815/961 2969/818/963 +f 2979/820/37 2980/821/37 2981/822/37 +f 2981/822/37 2982/823/37 2979/820/37 +f 2983/824/998 2984/825/999 2985/826/966 +f 2985/826/966 2986/827/966 2983/824/998 +f 2982/828/967 2981/829/967 2984/825/999 +f 2984/825/999 2983/824/998 2982/828/967 +f 2987/737/968 2983/738/969 2986/734/970 +f 2986/734/970 2988/740/970 2987/737/968 +f 2979/741/971 2982/735/971 2983/738/969 +f 2983/738/969 2987/737/968 2979/741/971 +f 2989/825/972 2987/824/972 2988/827/973 +f 2988/827/973 2990/826/973 2989/825/972 +f 2980/829/974 2979/828/974 2987/824/972 +f 2987/824/972 2989/825/972 2980/829/974 +f 2984/731/975 2989/737/976 2990/733/977 +f 2990/733/977 2985/830/977 2984/731/975 +f 2981/831/978 2980/736/978 2989/737/976 +f 2989/737/976 2984/731/975 2981/831/978 +f 2991/832/36 2992/833/36 2993/834/36 +f 2993/834/36 2994/835/36 2991/832/36 +f 2995/836/993 2996/837/993 2997/838/980 +f 2997/838/980 2998/839/980 2995/836/993 +f 2994/840/981 2993/841/981 2996/837/993 +f 2996/837/993 2995/836/993 2994/840/981 +f 2999/737/982 2995/731/982 2998/734/983 +f 2998/734/983 3000/733/983 2999/737/982 +f 2991/741/984 2994/735/985 2995/731/982 +f 2995/731/982 2999/737/982 2991/741/984 +f 3001/837/986 2999/836/986 3000/839/987 +f 3000/839/987 3002/838/987 3001/837/986 +f 2992/841/988 2991/840/988 2999/836/986 +f 2999/836/986 3001/837/986 2992/841/988 +f 2996/842/989 3001/732/989 3002/843/990 +f 3002/843/990 2997/734/990 2996/842/989 +f 2993/831/991 2992/736/991 3001/732/989 +f 3001/732/989 2996/842/989 2993/831/991 +f 3003/721/36 3004/722/36 3005/723/36 +f 3005/723/36 3006/724/36 3003/721/36 +f 3007/725/888 3008/726/888 3009/727/889 +f 3009/727/889 3010/728/889 3007/725/888 +f 3006/729/890 3005/730/890 3008/726/888 +f 3008/726/888 3007/725/888 3006/729/890 +f 3011/731/891 3007/732/892 3010/733/893 +f 3010/733/893 3012/734/893 3011/731/891 +f 3003/735/895 3006/736/895 3007/732/892 +f 3007/732/892 3011/731/891 3003/735/895 +f 3013/726/896 3011/725/896 3012/728/897 +f 3012/728/897 3014/727/897 3013/726/896 +f 3004/730/898 3003/729/898 3011/725/896 +f 3011/725/896 3013/726/896 3004/730/898 +f 3008/737/899 3013/738/899 3014/739/900 +f 3014/739/900 3009/740/900 3008/737/899 +f 3005/741/901 3004/742/901 3013/738/899 +f 3013/738/899 3008/737/899 3005/741/901 +f 3015/743/36 3016/744/36 3017/745/36 +f 3017/745/36 3018/746/36 3015/743/36 +f 3019/747/902 3020/748/902 3021/749/903 +f 3021/749/903 3022/750/903 3019/747/902 +f 3018/751/904 3017/752/904 3020/748/902 +f 3020/748/902 3019/747/902 3018/751/904 +f 3023/753/905 3019/754/906 3022/755/907 +f 3022/755/907 3024/756/908 3023/753/905 +f 3015/757/909 3018/758/909 3019/754/906 +f 3019/754/906 3023/753/905 3015/757/909 +f 3025/748/910 3023/747/911 3024/750/912 +f 3024/750/912 3026/749/912 3025/748/910 +f 3016/752/913 3015/751/913 3023/747/911 +f 3023/747/911 3025/748/910 3016/752/913 +f 3020/754/914 3025/759/915 3026/760/916 +f 3026/760/916 3021/755/916 3020/754/914 +f 3017/758/917 3016/761/917 3025/759/915 +f 3025/759/915 3020/754/914 3017/758/917 +f 3027/762/918 3028/763/919 3029/764/920 +f 3029/764/920 3030/765/920 3027/762/918 +f 3031/766/921 3032/767/921 3028/763/919 +f 3028/763/919 3027/762/918 3031/766/921 +f 3033/768/922 3027/769/923 3030/770/924 +f 3030/770/924 3034/771/924 3033/768/922 +f 3035/772/925 3031/773/925 3027/769/923 +f 3027/769/923 3033/768/922 3035/772/925 +f 3036/763/926 3033/762/927 3034/765/928 +f 3034/765/928 3037/764/928 3036/763/926 +f 3038/767/929 3035/766/929 3033/762/927 +f 3033/762/927 3036/763/926 3038/767/929 +f 3028/774/930 3036/768/931 3037/771/932 +f 3037/771/932 3029/775/932 3028/774/930 +f 3032/776/933 3038/777/933 3036/768/931 +f 3036/768/931 3028/774/930 3032/776/933 +f 3039/778/934 3040/779/935 3041/780/936 +f 3041/780/936 3042/781/936 3039/778/934 +f 3043/782/937 3044/783/937 3040/779/935 +f 3040/779/935 3039/778/934 3043/782/937 +f 3045/784/938 3039/785/939 3042/786/940 +f 3042/786/940 3046/787/940 3045/784/938 +f 3047/788/941 3043/789/941 3039/785/939 +f 3039/785/939 3045/784/938 3047/788/941 +f 3048/790/942 3045/791/943 3046/792/944 +f 3046/792/944 3049/793/944 3048/790/942 +f 3050/794/945 3047/795/945 3045/791/943 +f 3045/791/943 3048/790/942 3050/794/945 +f 3040/785/946 3048/796/947 3049/787/948 +f 3049/787/948 3041/797/948 3040/785/946 +f 3044/789/949 3050/798/949 3048/796/947 +f 3048/796/947 3040/785/946 3044/789/949 +f 3051/799/36 3052/800/36 3053/801/36 +f 3053/801/36 3054/802/36 3051/799/36 +f 3055/803/950 3056/804/951 3057/805/952 +f 3057/805/952 3058/806/952 3055/803/950 +f 3054/807/953 3053/808/953 3056/804/951 +f 3056/804/951 3055/803/950 3054/807/953 +f 3059/809/954 3055/810/954 3058/811/955 +f 3058/811/955 3060/812/955 3059/809/954 +f 3051/813/956 3054/814/956 3055/810/954 +f 3055/810/954 3059/809/954 3051/813/956 +f 3061/804/957 3059/803/958 3060/806/959 +f 3060/806/959 3062/805/959 3061/804/957 +f 3052/808/960 3051/807/960 3059/803/958 +f 3059/803/958 3061/804/957 3052/808/960 +f 3056/815/961 3061/809/961 3062/816/962 +f 3062/816/962 3057/817/962 3056/815/961 +f 3053/818/963 3052/819/963 3061/809/961 +f 3061/809/961 3056/815/961 3053/818/963 +f 3063/820/226 3064/821/226 3065/822/226 +f 3065/822/226 3066/823/226 3063/820/226 +f 3067/824/998 3068/825/999 3069/826/966 +f 3069/826/966 3070/827/966 3067/824/998 +f 3066/828/967 3065/829/967 3068/825/999 +f 3068/825/999 3067/824/998 3066/828/967 +f 3071/737/968 3067/738/969 3070/734/970 +f 3070/734/970 3072/740/970 3071/737/968 +f 3063/741/971 3066/735/971 3067/738/969 +f 3067/738/969 3071/737/968 3063/741/971 +f 3073/825/972 3071/824/972 3072/827/973 +f 3072/827/973 3074/826/973 3073/825/972 +f 3064/829/974 3063/828/974 3071/824/972 +f 3071/824/972 3073/825/972 3064/829/974 +f 3068/731/975 3073/737/976 3074/733/977 +f 3074/733/977 3069/830/977 3068/731/975 +f 3065/831/978 3064/736/978 3073/737/976 +f 3073/737/976 3068/731/975 3065/831/978 +f 3075/832/36 3076/833/36 3077/834/36 +f 3077/834/36 3078/835/36 3075/832/36 +f 3079/836/979 3080/837/979 3081/838/980 +f 3081/838/980 3082/839/980 3079/836/979 +f 3078/840/981 3077/841/981 3080/837/979 +f 3080/837/979 3079/836/979 3078/840/981 +f 3083/737/982 3079/731/982 3082/734/983 +f 3082/734/983 3084/733/983 3083/737/982 +f 3075/741/984 3078/735/985 3079/731/982 +f 3079/731/982 3083/737/982 3075/741/984 +f 3085/837/1001 3083/836/1001 3084/839/987 +f 3084/839/987 3086/838/987 3085/837/1001 +f 3076/841/988 3075/840/988 3083/836/1001 +f 3083/836/1001 3085/837/1001 3076/841/988 +f 3080/842/989 3085/732/989 3086/843/990 +f 3086/843/990 3081/734/990 3080/842/989 +f 3077/831/991 3076/736/991 3085/732/989 +f 3085/732/989 3080/842/989 3077/831/991 +f 3087/721/37 3088/722/37 3089/723/37 +f 3089/723/37 3090/724/37 3087/721/37 +f 3091/725/888 3092/726/888 3093/727/889 +f 3093/727/889 3094/728/889 3091/725/888 +f 3090/729/890 3089/730/890 3092/726/888 +f 3092/726/888 3091/725/888 3090/729/890 +f 3095/731/891 3091/732/892 3094/733/893 +f 3094/733/893 3096/734/893 3095/731/891 +f 3087/735/895 3090/736/895 3091/732/892 +f 3091/732/892 3095/731/891 3087/735/895 +f 3097/726/896 3095/725/896 3096/728/897 +f 3096/728/897 3098/727/897 3097/726/896 +f 3088/730/898 3087/729/898 3095/725/896 +f 3095/725/896 3097/726/896 3088/730/898 +f 3092/737/899 3097/738/899 3098/739/900 +f 3098/739/900 3093/740/900 3092/737/899 +f 3089/741/901 3088/742/901 3097/738/899 +f 3097/738/899 3092/737/899 3089/741/901 +f 3099/743/36 3100/744/36 3101/745/36 +f 3101/745/36 3102/746/36 3099/743/36 +f 3103/747/902 3104/748/995 3105/749/903 +f 3105/749/903 3106/750/903 3103/747/902 +f 3102/751/904 3101/752/904 3104/748/995 +f 3104/748/995 3103/747/902 3102/751/904 +f 3107/753/905 3103/754/906 3106/755/907 +f 3106/755/907 3108/756/908 3107/753/905 +f 3099/757/909 3102/758/909 3103/754/906 +f 3103/754/906 3107/753/905 3099/757/909 +f 3109/748/910 3107/747/911 3108/750/912 +f 3108/750/912 3110/749/912 3109/748/910 +f 3100/752/913 3099/751/913 3107/747/911 +f 3107/747/911 3109/748/910 3100/752/913 +f 3104/754/914 3109/759/915 3110/760/916 +f 3110/760/916 3105/755/916 3104/754/914 +f 3101/758/917 3100/761/917 3109/759/915 +f 3109/759/915 3104/754/914 3101/758/917 +f 3111/762/918 3112/763/919 3113/764/920 +f 3113/764/920 3114/765/920 3111/762/918 +f 3115/766/921 3116/767/921 3112/763/919 +f 3112/763/919 3111/762/918 3115/766/921 +f 3117/768/922 3111/769/923 3114/770/924 +f 3114/770/924 3118/771/924 3117/768/922 +f 3119/772/925 3115/773/925 3111/769/923 +f 3111/769/923 3117/768/922 3119/772/925 +f 3120/763/926 3117/762/927 3118/765/928 +f 3118/765/928 3121/764/928 3120/763/926 +f 3122/767/929 3119/766/929 3117/762/927 +f 3117/762/927 3120/763/926 3122/767/929 +f 3112/774/930 3120/768/931 3121/771/932 +f 3121/771/932 3113/775/932 3112/774/930 +f 3116/776/933 3122/777/933 3120/768/931 +f 3120/768/931 3112/774/930 3116/776/933 +f 3123/778/934 3124/779/935 3125/780/936 +f 3125/780/936 3126/781/936 3123/778/934 +f 3127/782/937 3128/783/937 3124/779/935 +f 3124/779/935 3123/778/934 3127/782/937 +f 3129/784/938 3123/785/939 3126/786/940 +f 3126/786/940 3130/787/940 3129/784/938 +f 3131/788/941 3127/789/941 3123/785/939 +f 3123/785/939 3129/784/938 3131/788/941 +f 3132/790/1000 3129/791/943 3130/792/944 +f 3130/792/944 3133/793/944 3132/790/1000 +f 3134/794/945 3131/795/945 3129/791/943 +f 3129/791/943 3132/790/1000 3134/794/945 +f 3124/785/946 3132/796/947 3133/787/948 +f 3133/787/948 3125/797/948 3124/785/946 +f 3128/789/949 3134/798/949 3132/796/947 +f 3132/796/947 3124/785/946 3128/789/949 +f 3135/799/37 3136/800/37 3137/801/37 +f 3137/801/37 3138/802/37 3135/799/37 +f 3139/803/950 3140/804/951 3141/805/952 +f 3141/805/952 3142/806/952 3139/803/950 +f 3138/807/953 3137/808/953 3140/804/951 +f 3140/804/951 3139/803/950 3138/807/953 +f 3143/809/954 3139/810/954 3142/811/955 +f 3142/811/955 3144/812/955 3143/809/954 +f 3135/813/956 3138/814/956 3139/810/954 +f 3139/810/954 3143/809/954 3135/813/956 +f 3145/804/957 3143/803/958 3144/806/959 +f 3144/806/959 3146/805/959 3145/804/957 +f 3136/808/960 3135/807/960 3143/803/958 +f 3143/803/958 3145/804/957 3136/808/960 +f 3140/815/961 3145/809/961 3146/816/962 +f 3146/816/962 3141/817/962 3140/815/961 +f 3137/818/963 3136/819/963 3145/809/961 +f 3145/809/961 3140/815/961 3137/818/963 +f 3147/820/36 3148/821/36 3149/822/36 +f 3149/822/36 3150/823/36 3147/820/36 +f 3151/824/998 3152/825/999 3153/826/966 +f 3153/826/966 3154/827/966 3151/824/998 +f 3150/828/967 3149/829/967 3152/825/999 +f 3152/825/999 3151/824/998 3150/828/967 +f 3155/737/968 3151/738/969 3154/734/970 +f 3154/734/970 3156/740/970 3155/737/968 +f 3147/741/971 3150/735/971 3151/738/969 +f 3151/738/969 3155/737/968 3147/741/971 +f 3157/825/972 3155/824/972 3156/827/973 +f 3156/827/973 3158/826/973 3157/825/972 +f 3148/829/974 3147/828/974 3155/824/972 +f 3155/824/972 3157/825/972 3148/829/974 +f 3152/731/975 3157/737/976 3158/733/977 +f 3158/733/977 3153/830/977 3152/731/975 +f 3149/831/978 3148/736/978 3157/737/976 +f 3157/737/976 3152/731/975 3149/831/978 +f 3159/832/36 3160/833/36 3161/834/36 +f 3161/834/36 3162/835/36 3159/832/36 +f 3163/836/979 3164/837/979 3165/838/994 +f 3165/838/994 3166/839/994 3163/836/979 +f 3162/840/981 3161/841/981 3164/837/979 +f 3164/837/979 3163/836/979 3162/840/981 +f 3167/737/982 3163/731/982 3166/734/983 +f 3166/734/983 3168/733/983 3167/737/982 +f 3159/741/984 3162/735/985 3163/731/982 +f 3163/731/982 3167/737/982 3159/741/984 +f 3169/837/1001 3167/836/1001 3168/839/987 +f 3168/839/987 3170/838/987 3169/837/1001 +f 3160/841/988 3159/840/988 3167/836/1001 +f 3167/836/1001 3169/837/1001 3160/841/988 +f 3164/842/989 3169/732/989 3170/843/990 +f 3170/843/990 3165/734/990 3164/842/989 +f 3161/831/991 3160/736/991 3169/732/989 +f 3169/732/989 3164/842/989 3161/831/991 +f 3171/721/36 3172/722/36 3173/723/36 +f 3173/723/36 3174/724/36 3171/721/36 +f 3175/725/888 3176/726/888 3177/727/889 +f 3177/727/889 3178/728/889 3175/725/888 +f 3174/729/890 3173/730/890 3176/726/888 +f 3176/726/888 3175/725/888 3174/729/890 +f 3179/731/891 3175/732/892 3178/733/893 +f 3178/733/893 3180/734/893 3179/731/891 +f 3171/735/895 3174/736/895 3175/732/892 +f 3175/732/892 3179/731/891 3171/735/895 +f 3181/726/896 3179/725/896 3180/728/897 +f 3180/728/897 3182/727/897 3181/726/896 +f 3172/730/898 3171/729/898 3179/725/896 +f 3179/725/896 3181/726/896 3172/730/898 +f 3176/737/899 3181/738/899 3182/739/900 +f 3182/739/900 3177/740/900 3176/737/899 +f 3173/741/901 3172/742/901 3181/738/899 +f 3181/738/899 3176/737/899 3173/741/901 +f 3183/743/36 3184/744/36 3185/745/36 +f 3185/745/36 3186/746/36 3183/743/36 +f 3187/747/995 3188/748/995 3189/749/903 +f 3189/749/903 3190/750/903 3187/747/995 +f 3186/751/904 3185/752/904 3188/748/995 +f 3188/748/995 3187/747/995 3186/751/904 +f 3191/753/905 3187/754/906 3190/755/907 +f 3190/755/907 3192/756/908 3191/753/905 +f 3183/757/909 3186/758/909 3187/754/906 +f 3187/754/906 3191/753/905 3183/757/909 +f 3193/748/910 3191/747/911 3192/750/912 +f 3192/750/912 3194/749/912 3193/748/910 +f 3184/752/913 3183/751/913 3191/747/911 +f 3191/747/911 3193/748/910 3184/752/913 +f 3188/754/914 3193/759/915 3194/760/916 +f 3194/760/916 3189/755/916 3188/754/914 +f 3185/758/917 3184/761/917 3193/759/915 +f 3193/759/915 3188/754/914 3185/758/917 +f 3195/762/918 3196/763/919 3197/764/920 +f 3197/764/920 3198/765/920 3195/762/918 +f 3199/766/921 3200/767/921 3196/763/919 +f 3196/763/919 3195/762/918 3199/766/921 +f 3201/768/922 3195/769/923 3198/770/924 +f 3198/770/924 3202/771/924 3201/768/922 +f 3203/772/925 3199/773/925 3195/769/923 +f 3195/769/923 3201/768/922 3203/772/925 +f 3204/763/926 3201/762/927 3202/765/928 +f 3202/765/928 3205/764/928 3204/763/926 +f 3206/767/929 3203/766/929 3201/762/927 +f 3201/762/927 3204/763/926 3206/767/929 +f 3196/774/930 3204/768/931 3205/771/932 +f 3205/771/932 3197/775/932 3196/774/930 +f 3200/776/933 3206/777/933 3204/768/931 +f 3204/768/931 3196/774/930 3200/776/933 +f 3207/778/934 3208/779/935 3209/780/936 +f 3209/780/936 3210/781/936 3207/778/934 +f 3211/782/937 3212/783/937 3208/779/935 +f 3208/779/935 3207/778/934 3211/782/937 +f 3213/784/938 3207/785/939 3210/786/940 +f 3210/786/940 3214/787/940 3213/784/938 +f 3215/788/941 3211/789/941 3207/785/939 +f 3207/785/939 3213/784/938 3215/788/941 +f 3216/790/1000 3213/791/943 3214/792/944 +f 3214/792/944 3217/793/944 3216/790/1000 +f 3218/794/945 3215/795/945 3213/791/943 +f 3213/791/943 3216/790/1000 3218/794/945 +f 3208/785/946 3216/796/947 3217/787/948 +f 3217/787/948 3209/797/948 3208/785/946 +f 3212/789/949 3218/798/949 3216/796/947 +f 3216/796/947 3208/785/946 3212/789/949 +f 3219/799/226 3220/800/226 3221/801/226 +f 3221/801/226 3222/802/226 3219/799/226 +f 3223/803/996 3224/804/997 3225/805/952 +f 3225/805/952 3226/806/952 3223/803/996 +f 3222/807/953 3221/808/953 3224/804/997 +f 3224/804/997 3223/803/996 3222/807/953 +f 3227/809/954 3223/810/954 3226/811/955 +f 3226/811/955 3228/812/955 3227/809/954 +f 3219/813/956 3222/814/956 3223/810/954 +f 3223/810/954 3227/809/954 3219/813/956 +f 3229/804/957 3227/803/958 3228/806/959 +f 3228/806/959 3230/805/959 3229/804/957 +f 3220/808/960 3219/807/960 3227/803/958 +f 3227/803/958 3229/804/957 3220/808/960 +f 3224/815/961 3229/809/961 3230/816/962 +f 3230/816/962 3225/817/962 3224/815/961 +f 3221/818/963 3220/819/963 3229/809/961 +f 3229/809/961 3224/815/961 3221/818/963 +f 3231/820/36 3232/821/36 3233/822/36 +f 3233/822/36 3234/823/36 3231/820/36 +f 3235/824/998 3236/825/999 3237/826/966 +f 3237/826/966 3238/827/966 3235/824/998 +f 3234/828/967 3233/829/967 3236/825/999 +f 3236/825/999 3235/824/998 3234/828/967 +f 3239/737/968 3235/738/969 3238/734/970 +f 3238/734/970 3240/740/970 3239/737/968 +f 3231/741/971 3234/735/971 3235/738/969 +f 3235/738/969 3239/737/968 3231/741/971 +f 3241/825/972 3239/824/972 3240/827/973 +f 3240/827/973 3242/826/973 3241/825/972 +f 3232/829/974 3231/828/974 3239/824/972 +f 3239/824/972 3241/825/972 3232/829/974 +f 3236/731/975 3241/737/976 3242/733/977 +f 3242/733/977 3237/830/977 3236/731/975 +f 3233/831/978 3232/736/978 3241/737/976 +f 3241/737/976 3236/731/975 3233/831/978 +f 3243/832/37 3244/833/37 3245/834/37 +f 3245/834/37 3246/835/37 3243/832/37 +f 3247/836/979 3248/837/979 3249/838/994 +f 3249/838/994 3250/839/994 3247/836/979 +f 3246/840/981 3245/841/981 3248/837/979 +f 3248/837/979 3247/836/979 3246/840/981 +f 3251/737/982 3247/731/982 3250/734/983 +f 3250/734/983 3252/733/983 3251/737/982 +f 3243/741/985 3246/735/985 3247/731/982 +f 3247/731/982 3251/737/982 3243/741/985 +f 3253/837/1001 3251/836/1001 3252/839/987 +f 3252/839/987 3254/838/987 3253/837/1001 +f 3244/841/988 3243/840/988 3251/836/1001 +f 3251/836/1001 3253/837/1001 3244/841/988 +f 3248/842/989 3253/732/989 3254/843/990 +f 3254/843/990 3249/734/990 3248/842/989 +f 3245/831/991 3244/736/991 3253/732/989 +f 3253/732/989 3248/842/989 3245/831/991 +f 3255/721/36 3256/722/36 3257/723/36 +f 3257/723/36 3258/724/36 3255/721/36 +f 3259/725/888 3260/726/888 3261/727/889 +f 3261/727/889 3262/728/889 3259/725/888 +f 3258/729/890 3257/730/890 3260/726/888 +f 3260/726/888 3259/725/888 3258/729/890 +f 3263/731/891 3259/732/892 3262/733/893 +f 3262/733/893 3264/734/893 3263/731/891 +f 3255/735/895 3258/736/895 3259/732/892 +f 3259/732/892 3263/731/891 3255/735/895 +f 3265/726/896 3263/725/896 3264/728/897 +f 3264/728/897 3266/727/897 3265/726/896 +f 3256/730/898 3255/729/898 3263/725/896 +f 3263/725/896 3265/726/896 3256/730/898 +f 3260/737/899 3265/738/899 3266/739/900 +f 3266/739/900 3261/740/900 3260/737/899 +f 3257/741/901 3256/742/901 3265/738/899 +f 3265/738/899 3260/737/899 3257/741/901 +f 3267/743/36 3268/744/36 3269/745/36 +f 3269/745/36 3270/746/36 3267/743/36 +f 3271/747/995 3272/748/995 3273/749/903 +f 3273/749/903 3274/750/903 3271/747/995 +f 3270/751/904 3269/752/904 3272/748/995 +f 3272/748/995 3271/747/995 3270/751/904 +f 3275/753/905 3271/754/906 3274/755/907 +f 3274/755/907 3276/756/908 3275/753/905 +f 3267/757/909 3270/758/909 3271/754/906 +f 3271/754/906 3275/753/905 3267/757/909 +f 3277/748/910 3275/747/911 3276/750/912 +f 3276/750/912 3278/749/912 3277/748/910 +f 3268/752/913 3267/751/913 3275/747/911 +f 3275/747/911 3277/748/910 3268/752/913 +f 3272/754/914 3277/759/915 3278/760/916 +f 3278/760/916 3273/755/916 3272/754/914 +f 3269/758/917 3268/761/917 3277/759/915 +f 3277/759/915 3272/754/914 3269/758/917 +f 3279/762/918 3280/763/919 3281/764/920 +f 3281/764/920 3282/765/920 3279/762/918 +f 3283/766/921 3284/767/921 3280/763/919 +f 3280/763/919 3279/762/918 3283/766/921 +f 3285/768/922 3279/769/923 3282/770/924 +f 3282/770/924 3286/771/924 3285/768/922 +f 3287/772/925 3283/773/925 3279/769/923 +f 3279/769/923 3285/768/922 3287/772/925 +f 3288/763/926 3285/762/927 3286/765/928 +f 3286/765/928 3289/764/928 3288/763/926 +f 3290/767/929 3287/766/929 3285/762/927 +f 3285/762/927 3288/763/926 3290/767/929 +f 3280/774/930 3288/768/931 3289/771/932 +f 3289/771/932 3281/775/932 3280/774/930 +f 3284/776/933 3290/777/933 3288/768/931 +f 3288/768/931 3280/774/930 3284/776/933 +f 3291/778/934 3292/779/935 3293/780/936 +f 3293/780/936 3294/781/936 3291/778/934 +f 3295/782/937 3296/783/937 3292/779/935 +f 3292/779/935 3291/778/934 3295/782/937 +f 3297/784/938 3291/785/939 3294/786/940 +f 3294/786/940 3298/787/940 3297/784/938 +f 3299/788/941 3295/789/941 3291/785/939 +f 3291/785/939 3297/784/938 3299/788/941 +f 3300/790/1000 3297/791/943 3298/792/944 +f 3298/792/944 3301/793/944 3300/790/1000 +f 3302/794/945 3299/795/945 3297/791/943 +f 3297/791/943 3300/790/1000 3302/794/945 +f 3292/785/946 3300/796/947 3301/787/948 +f 3301/787/948 3293/797/948 3292/785/946 +f 3296/789/949 3302/798/949 3300/796/947 +f 3300/796/947 3292/785/946 3296/789/949 +f 3303/799/36 3304/800/36 3305/801/36 +f 3305/801/36 3306/802/36 3303/799/36 +f 3307/803/996 3308/804/997 3309/805/952 +f 3309/805/952 3310/806/952 3307/803/996 +f 3306/807/953 3305/808/953 3308/804/997 +f 3308/804/997 3307/803/996 3306/807/953 +f 3311/809/954 3307/810/954 3310/811/955 +f 3310/811/955 3312/812/955 3311/809/954 +f 3303/813/956 3306/814/956 3307/810/954 +f 3307/810/954 3311/809/954 3303/813/956 +f 3313/804/957 3311/803/958 3312/806/959 +f 3312/806/959 3314/805/959 3313/804/957 +f 3304/808/960 3303/807/960 3311/803/958 +f 3311/803/958 3313/804/957 3304/808/960 +f 3308/815/961 3313/809/961 3314/816/962 +f 3314/816/962 3309/817/962 3308/815/961 +f 3305/818/963 3304/819/963 3313/809/961 +f 3313/809/961 3308/815/961 3305/818/963 +f 3315/820/36 3316/821/36 3317/822/36 +f 3317/822/36 3318/823/36 3315/820/36 +f 3319/824/998 3320/825/999 3321/826/966 +f 3321/826/966 3322/827/966 3319/824/998 +f 3318/828/967 3317/829/967 3320/825/999 +f 3320/825/999 3319/824/998 3318/828/967 +f 3323/737/968 3319/738/969 3322/734/970 +f 3322/734/970 3324/740/970 3323/737/968 +f 3315/741/971 3318/735/971 3319/738/969 +f 3319/738/969 3323/737/968 3315/741/971 +f 3325/825/972 3323/824/972 3324/827/973 +f 3324/827/973 3326/826/973 3325/825/972 +f 3316/829/974 3315/828/974 3323/824/972 +f 3323/824/972 3325/825/972 3316/829/974 +f 3320/731/975 3325/737/976 3326/733/977 +f 3326/733/977 3321/830/977 3320/731/975 +f 3317/831/978 3316/736/978 3325/737/976 +f 3325/737/976 3320/731/975 3317/831/978 +f 3327/832/36 3328/833/36 3329/834/36 +f 3329/834/36 3330/835/36 3327/832/36 +f 3331/836/993 3332/837/979 3333/838/994 +f 3333/838/994 3334/839/994 3331/836/993 +f 3330/840/981 3329/841/981 3332/837/979 +f 3332/837/979 3331/836/993 3330/840/981 +f 3335/737/982 3331/731/982 3334/734/983 +f 3334/734/983 3336/733/983 3335/737/982 +f 3327/741/984 3330/735/985 3331/731/982 +f 3331/731/982 3335/737/982 3327/741/984 +f 3337/837/1001 3335/836/1001 3336/839/987 +f 3336/839/987 3338/838/987 3337/837/1001 +f 3328/841/988 3327/840/988 3335/836/1001 +f 3335/836/1001 3337/837/1001 3328/841/988 +f 3332/842/989 3337/732/989 3338/843/990 +f 3338/843/990 3333/734/990 3332/842/989 +f 3329/831/991 3328/736/991 3337/732/989 +f 3337/732/989 3332/842/989 3329/831/991 +f 3339/721/36 3340/722/36 3341/723/36 +f 3341/723/36 3342/724/36 3339/721/36 +f 3343/725/888 3344/726/888 3345/727/889 +f 3345/727/889 3346/728/889 3343/725/888 +f 3342/729/890 3341/730/890 3344/726/888 +f 3344/726/888 3343/725/888 3342/729/890 +f 3347/731/891 3343/732/892 3346/733/893 +f 3346/733/893 3348/734/893 3347/731/891 +f 3339/735/895 3342/736/895 3343/732/892 +f 3343/732/892 3347/731/891 3339/735/895 +f 3349/726/896 3347/725/896 3348/728/897 +f 3348/728/897 3350/727/897 3349/726/896 +f 3340/730/898 3339/729/898 3347/725/896 +f 3347/725/896 3349/726/896 3340/730/898 +f 3344/737/899 3349/738/899 3350/739/900 +f 3350/739/900 3345/740/900 3344/737/899 +f 3341/741/901 3340/742/901 3349/738/899 +f 3349/738/899 3344/737/899 3341/741/901 +f 3351/743/37 3352/744/37 3353/745/37 +f 3353/745/37 3354/746/37 3351/743/37 +f 3355/747/902 3356/748/995 3357/749/903 +f 3357/749/903 3358/750/903 3355/747/902 +f 3354/751/904 3353/752/904 3356/748/995 +f 3356/748/995 3355/747/902 3354/751/904 +f 3359/753/905 3355/754/906 3358/755/907 +f 3358/755/907 3360/756/908 3359/753/905 +f 3351/757/909 3354/758/909 3355/754/906 +f 3355/754/906 3359/753/905 3351/757/909 +f 3361/748/910 3359/747/911 3360/750/912 +f 3360/750/912 3362/749/912 3361/748/910 +f 3352/752/913 3351/751/913 3359/747/911 +f 3359/747/911 3361/748/910 3352/752/913 +f 3356/754/914 3361/759/915 3362/760/916 +f 3362/760/916 3357/755/916 3356/754/914 +f 3353/758/917 3352/761/917 3361/759/915 +f 3361/759/915 3356/754/914 3353/758/917 +f 3363/762/918 3364/763/919 3365/764/920 +f 3365/764/920 3366/765/920 3363/762/918 +f 3367/766/921 3368/767/921 3364/763/919 +f 3364/763/919 3363/762/918 3367/766/921 +f 3369/768/922 3363/769/923 3366/770/924 +f 3366/770/924 3370/771/924 3369/768/922 +f 3371/772/925 3367/773/925 3363/769/923 +f 3363/769/923 3369/768/922 3371/772/925 +f 3372/763/926 3369/762/927 3370/765/928 +f 3370/765/928 3373/764/928 3372/763/926 +f 3374/767/929 3371/766/929 3369/762/927 +f 3369/762/927 3372/763/926 3374/767/929 +f 3364/774/930 3372/768/931 3373/771/932 +f 3373/771/932 3365/775/932 3364/774/930 +f 3368/776/933 3374/777/933 3372/768/931 +f 3372/768/931 3364/774/930 3368/776/933 +f 3375/778/934 3376/779/935 3377/780/936 +f 3377/780/936 3378/781/936 3375/778/934 +f 3379/782/937 3380/783/937 3376/779/935 +f 3376/779/935 3375/778/934 3379/782/937 +f 3381/784/938 3375/785/939 3378/786/940 +f 3378/786/940 3382/787/940 3381/784/938 +f 3383/788/941 3379/789/941 3375/785/939 +f 3375/785/939 3381/784/938 3383/788/941 +f 3384/790/1000 3381/791/943 3382/792/944 +f 3382/792/944 3385/793/944 3384/790/1000 +f 3386/794/945 3383/795/945 3381/791/943 +f 3381/791/943 3384/790/1000 3386/794/945 +f 3376/785/946 3384/796/947 3385/787/948 +f 3385/787/948 3377/797/948 3376/785/946 +f 3380/789/949 3386/798/949 3384/796/947 +f 3384/796/947 3376/785/946 3380/789/949 +f 3387/799/37 3388/800/37 3389/801/37 +f 3389/801/37 3390/802/37 3387/799/37 +f 3391/803/996 3392/804/997 3393/805/952 +f 3393/805/952 3394/806/952 3391/803/996 +f 3390/807/953 3389/808/953 3392/804/997 +f 3392/804/997 3391/803/996 3390/807/953 +f 3395/809/954 3391/810/954 3394/811/955 +f 3394/811/955 3396/812/955 3395/809/954 +f 3387/813/956 3390/814/956 3391/810/954 +f 3391/810/954 3395/809/954 3387/813/956 +f 3397/804/957 3395/803/958 3396/806/959 +f 3396/806/959 3398/805/959 3397/804/957 +f 3388/808/960 3387/807/960 3395/803/958 +f 3395/803/958 3397/804/957 3388/808/960 +f 3392/815/961 3397/809/961 3398/816/962 +f 3398/816/962 3393/817/962 3392/815/961 +f 3389/818/963 3388/819/963 3397/809/961 +f 3397/809/961 3392/815/961 3389/818/963 +f 3399/820/37 3400/821/37 3401/822/37 +f 3401/822/37 3402/823/37 3399/820/37 +f 3403/824/998 3404/825/999 3405/826/966 +f 3405/826/966 3406/827/966 3403/824/998 +f 3402/828/967 3401/829/967 3404/825/999 +f 3404/825/999 3403/824/998 3402/828/967 +f 3407/737/968 3403/738/969 3406/734/970 +f 3406/734/970 3408/740/970 3407/737/968 +f 3399/741/971 3402/735/971 3403/738/969 +f 3403/738/969 3407/737/968 3399/741/971 +f 3409/825/972 3407/824/972 3408/827/973 +f 3408/827/973 3410/826/973 3409/825/972 +f 3400/829/974 3399/828/974 3407/824/972 +f 3407/824/972 3409/825/972 3400/829/974 +f 3404/731/975 3409/737/976 3410/733/977 +f 3410/733/977 3405/830/977 3404/731/975 +f 3401/831/978 3400/736/978 3409/737/976 +f 3409/737/976 3404/731/975 3401/831/978 +f 3411/832/36 3412/833/36 3413/834/36 +f 3413/834/36 3414/835/36 3411/832/36 +f 3415/836/979 3416/837/979 3417/838/980 +f 3417/838/980 3418/839/980 3415/836/979 +f 3414/840/981 3413/841/981 3416/837/979 +f 3416/837/979 3415/836/979 3414/840/981 +f 3419/737/982 3415/731/982 3418/734/983 +f 3418/734/983 3420/733/983 3419/737/982 +f 3411/741/984 3414/735/985 3415/731/982 +f 3415/731/982 3419/737/982 3411/741/984 +f 3421/837/1001 3419/836/1001 3420/839/987 +f 3420/839/987 3422/838/987 3421/837/1001 +f 3412/841/988 3411/840/988 3419/836/1001 +f 3419/836/1001 3421/837/1001 3412/841/988 +f 3416/842/989 3421/732/989 3422/843/990 +f 3422/843/990 3417/734/990 3416/842/989 +f 3413/831/991 3412/736/991 3421/732/989 +f 3421/732/989 3416/842/989 3413/831/991 +f 3423/721/36 3424/722/36 3425/723/36 +f 3425/723/36 3426/724/36 3423/721/36 +f 3427/725/888 3428/726/888 3429/727/889 +f 3429/727/889 3430/728/889 3427/725/888 +f 3426/729/890 3425/730/890 3428/726/888 +f 3428/726/888 3427/725/888 3426/729/890 +f 3431/731/891 3427/732/892 3430/733/893 +f 3430/733/893 3432/734/893 3431/731/891 +f 3423/735/895 3426/736/895 3427/732/892 +f 3427/732/892 3431/731/891 3423/735/895 +f 3433/726/896 3431/725/896 3432/728/897 +f 3432/728/897 3434/727/897 3433/726/896 +f 3424/730/898 3423/729/898 3431/725/896 +f 3431/725/896 3433/726/896 3424/730/898 +f 3428/737/899 3433/738/899 3434/739/900 +f 3434/739/900 3429/740/900 3428/737/899 +f 3425/741/901 3424/742/901 3433/738/899 +f 3433/738/899 3428/737/899 3425/741/901 +f 3435/743/226 3436/744/226 3437/745/226 +f 3437/745/226 3438/746/226 3435/743/226 +f 3439/747/902 3440/748/995 3441/749/903 +f 3441/749/903 3442/750/903 3439/747/902 +f 3438/751/904 3437/752/904 3440/748/995 +f 3440/748/995 3439/747/902 3438/751/904 +f 3443/753/905 3439/754/906 3442/755/907 +f 3442/755/907 3444/756/908 3443/753/905 +f 3435/757/909 3438/758/909 3439/754/906 +f 3439/754/906 3443/753/905 3435/757/909 +f 3445/748/910 3443/747/911 3444/750/912 +f 3444/750/912 3446/749/912 3445/748/910 +f 3436/752/913 3435/751/913 3443/747/911 +f 3443/747/911 3445/748/910 3436/752/913 +f 3440/754/914 3445/759/915 3446/760/916 +f 3446/760/916 3441/755/916 3440/754/914 +f 3437/758/917 3436/761/917 3445/759/915 +f 3445/759/915 3440/754/914 3437/758/917 +f 3447/762/918 3448/763/919 3449/764/920 +f 3449/764/920 3450/765/920 3447/762/918 +f 3451/766/921 3452/767/921 3448/763/919 +f 3448/763/919 3447/762/918 3451/766/921 +f 3453/768/922 3447/769/923 3450/770/924 +f 3450/770/924 3454/771/924 3453/768/922 +f 3455/772/925 3451/773/925 3447/769/923 +f 3447/769/923 3453/768/922 3455/772/925 +f 3456/763/926 3453/762/927 3454/765/928 +f 3454/765/928 3457/764/928 3456/763/926 +f 3458/767/929 3455/766/929 3453/762/927 +f 3453/762/927 3456/763/926 3458/767/929 +f 3448/774/930 3456/768/931 3457/771/932 +f 3457/771/932 3449/775/932 3448/774/930 +f 3452/776/933 3458/777/933 3456/768/931 +f 3456/768/931 3448/774/930 3452/776/933 +f 3459/778/934 3460/779/935 3461/780/936 +f 3461/780/936 3462/781/936 3459/778/934 +f 3463/782/937 3464/783/937 3460/779/935 +f 3460/779/935 3459/778/934 3463/782/937 +f 3465/784/938 3459/785/939 3462/786/940 +f 3462/786/940 3466/787/940 3465/784/938 +f 3467/788/941 3463/789/941 3459/785/939 +f 3459/785/939 3465/784/938 3467/788/941 +f 3468/790/1000 3465/791/943 3466/792/944 +f 3466/792/944 3469/793/944 3468/790/1000 +f 3470/794/945 3467/795/945 3465/791/943 +f 3465/791/943 3468/790/1000 3470/794/945 +f 3460/785/946 3468/796/947 3469/787/948 +f 3469/787/948 3461/797/948 3460/785/946 +f 3464/789/949 3470/798/949 3468/796/947 +f 3468/796/947 3460/785/946 3464/789/949 +f 3471/799/36 3472/800/36 3473/801/36 +f 3473/801/36 3474/802/36 3471/799/36 +f 3475/803/996 3476/804/997 3477/805/952 +f 3477/805/952 3478/806/952 3475/803/996 +f 3474/807/953 3473/808/953 3476/804/997 +f 3476/804/997 3475/803/996 3474/807/953 +f 3479/809/954 3475/810/954 3478/811/955 +f 3478/811/955 3480/812/955 3479/809/954 +f 3471/813/956 3474/814/956 3475/810/954 +f 3475/810/954 3479/809/954 3471/813/956 +f 3481/804/957 3479/803/958 3480/806/959 +f 3480/806/959 3482/805/959 3481/804/957 +f 3472/808/960 3471/807/960 3479/803/958 +f 3479/803/958 3481/804/957 3472/808/960 +f 3476/815/961 3481/809/961 3482/816/962 +f 3482/816/962 3477/817/962 3476/815/961 +f 3473/818/963 3472/819/963 3481/809/961 +f 3481/809/961 3476/815/961 3473/818/963 +f 3483/820/36 3484/821/36 3485/822/36 +f 3485/822/36 3486/823/36 3483/820/36 +f 3487/824/998 3488/825/999 3489/826/966 +f 3489/826/966 3490/827/966 3487/824/998 +f 3486/828/967 3485/829/967 3488/825/999 +f 3488/825/999 3487/824/998 3486/828/967 +f 3491/737/968 3487/738/969 3490/734/970 +f 3490/734/970 3492/740/970 3491/737/968 +f 3483/741/971 3486/735/971 3487/738/969 +f 3487/738/969 3491/737/968 3483/741/971 +f 3493/825/972 3491/824/972 3492/827/973 +f 3492/827/973 3494/826/973 3493/825/972 +f 3484/829/974 3483/828/974 3491/824/972 +f 3491/824/972 3493/825/972 3484/829/974 +f 3488/731/975 3493/737/976 3494/733/977 +f 3494/733/977 3489/830/977 3488/731/975 +f 3485/831/978 3484/736/978 3493/737/976 +f 3493/737/976 3488/731/975 3485/831/978 +f 3495/832/36 3496/833/36 3497/834/36 +f 3497/834/36 3498/835/36 3495/832/36 +f 3499/836/979 3500/837/979 3501/838/980 +f 3501/838/980 3502/839/980 3499/836/979 +f 3498/840/981 3497/841/981 3500/837/979 +f 3500/837/979 3499/836/979 3498/840/981 +f 3503/737/982 3499/731/982 3502/734/983 +f 3502/734/983 3504/733/983 3503/737/982 +f 3495/741/984 3498/735/985 3499/731/982 +f 3499/731/982 3503/737/982 3495/741/984 +f 3505/837/1001 3503/836/1001 3504/839/987 +f 3504/839/987 3506/838/987 3505/837/1001 +f 3496/841/988 3495/840/988 3503/836/1001 +f 3503/836/1001 3505/837/1001 3496/841/988 +f 3500/842/989 3505/732/989 3506/843/990 +f 3506/843/990 3501/734/990 3500/842/989 +f 3497/831/991 3496/736/991 3505/732/989 +f 3505/732/989 3500/842/989 3497/831/991 +f 3507/721/37 3508/722/37 3509/723/37 +f 3509/723/37 3510/724/37 3507/721/37 +f 3511/725/888 3512/726/888 3513/727/889 +f 3513/727/889 3514/728/889 3511/725/888 +f 3510/729/890 3509/730/890 3512/726/888 +f 3512/726/888 3511/725/888 3510/729/890 +f 3515/731/891 3511/732/892 3514/733/893 +f 3514/733/893 3516/734/893 3515/731/891 +f 3507/735/895 3510/736/895 3511/732/892 +f 3511/732/892 3515/731/891 3507/735/895 +f 3517/726/896 3515/725/896 3516/728/897 +f 3516/728/897 3518/727/897 3517/726/896 +f 3508/730/898 3507/729/898 3515/725/896 +f 3515/725/896 3517/726/896 3508/730/898 +f 3512/737/899 3517/738/899 3518/739/900 +f 3518/739/900 3513/740/900 3512/737/899 +f 3509/741/901 3508/742/901 3517/738/899 +f 3517/738/899 3512/737/899 3509/741/901 +f 3519/743/37 3520/744/37 3521/745/37 +f 3521/745/37 3522/746/37 3519/743/37 +f 3523/747/902 3524/748/995 3525/749/903 +f 3525/749/903 3526/750/903 3523/747/902 +f 3522/751/904 3521/752/904 3524/748/995 +f 3524/748/995 3523/747/902 3522/751/904 +f 3527/753/905 3523/754/906 3526/755/907 +f 3526/755/907 3528/756/908 3527/753/905 +f 3519/757/909 3522/758/909 3523/754/906 +f 3523/754/906 3527/753/905 3519/757/909 +f 3529/748/910 3527/747/911 3528/750/912 +f 3528/750/912 3530/749/912 3529/748/910 +f 3520/752/913 3519/751/913 3527/747/911 +f 3527/747/911 3529/748/910 3520/752/913 +f 3524/754/914 3529/759/915 3530/760/916 +f 3530/760/916 3525/755/916 3524/754/914 +f 3521/758/917 3520/761/917 3529/759/915 +f 3529/759/915 3524/754/914 3521/758/917 +f 3531/762/918 3532/763/919 3533/764/920 +f 3533/764/920 3534/765/920 3531/762/918 +f 3535/766/921 3536/767/921 3532/763/919 +f 3532/763/919 3531/762/918 3535/766/921 +f 3537/768/922 3531/769/923 3534/770/924 +f 3534/770/924 3538/771/924 3537/768/922 +f 3539/772/925 3535/773/925 3531/769/923 +f 3531/769/923 3537/768/922 3539/772/925 +f 3540/763/926 3537/762/927 3538/765/928 +f 3538/765/928 3541/764/928 3540/763/926 +f 3542/767/929 3539/766/929 3537/762/927 +f 3537/762/927 3540/763/926 3542/767/929 +f 3532/774/930 3540/768/931 3541/771/932 +f 3541/771/932 3533/775/932 3532/774/930 +f 3536/776/933 3542/777/933 3540/768/931 +f 3540/768/931 3532/774/930 3536/776/933 +f 3543/778/934 3544/779/935 3545/780/936 +f 3545/780/936 3546/781/936 3543/778/934 +f 3547/782/937 3548/783/937 3544/779/935 +f 3544/779/935 3543/778/934 3547/782/937 +f 3549/784/938 3543/785/939 3546/786/940 +f 3546/786/940 3550/787/940 3549/784/938 +f 3551/788/941 3547/789/941 3543/785/939 +f 3543/785/939 3549/784/938 3551/788/941 +f 3552/790/1000 3549/791/943 3550/792/944 +f 3550/792/944 3553/793/944 3552/790/1000 +f 3554/794/945 3551/795/945 3549/791/943 +f 3549/791/943 3552/790/1000 3554/794/945 +f 3544/785/946 3552/796/947 3553/787/948 +f 3553/787/948 3545/797/948 3544/785/946 +f 3548/789/949 3554/798/949 3552/796/947 +f 3552/796/947 3544/785/946 3548/789/949 +f 3555/799/37 3556/800/37 3557/801/37 +f 3557/801/37 3558/802/37 3555/799/37 +f 3559/803/996 3560/804/997 3561/805/952 +f 3561/805/952 3562/806/952 3559/803/996 +f 3558/807/953 3557/808/953 3560/804/997 +f 3560/804/997 3559/803/996 3558/807/953 +f 3563/809/954 3559/810/954 3562/811/955 +f 3562/811/955 3564/812/955 3563/809/954 +f 3555/813/956 3558/814/956 3559/810/954 +f 3559/810/954 3563/809/954 3555/813/956 +f 3565/804/957 3563/803/958 3564/806/959 +f 3564/806/959 3566/805/959 3565/804/957 +f 3556/808/960 3555/807/960 3563/803/958 +f 3563/803/958 3565/804/957 3556/808/960 +f 3560/815/961 3565/809/961 3566/816/962 +f 3566/816/962 3561/817/962 3560/815/961 +f 3557/818/963 3556/819/963 3565/809/961 +f 3565/809/961 3560/815/961 3557/818/963 +f 3567/820/36 3568/821/36 3569/822/36 +f 3569/822/36 3570/823/36 3567/820/36 +f 3571/824/998 3572/825/999 3573/826/966 +f 3573/826/966 3574/827/966 3571/824/998 +f 3570/828/967 3569/829/967 3572/825/999 +f 3572/825/999 3571/824/998 3570/828/967 +f 3575/737/968 3571/738/969 3574/734/970 +f 3574/734/970 3576/740/970 3575/737/968 +f 3567/741/971 3570/735/971 3571/738/969 +f 3571/738/969 3575/737/968 3567/741/971 +f 3577/825/972 3575/824/972 3576/827/973 +f 3576/827/973 3578/826/973 3577/825/972 +f 3568/829/974 3567/828/974 3575/824/972 +f 3575/824/972 3577/825/972 3568/829/974 +f 3572/731/975 3577/737/976 3578/733/977 +f 3578/733/977 3573/830/977 3572/731/975 +f 3569/831/978 3568/736/978 3577/737/976 +f 3577/737/976 3572/731/975 3569/831/978 +f 3579/832/36 3580/833/36 3581/834/36 +f 3581/834/36 3582/835/36 3579/832/36 +f 3583/836/979 3584/837/979 3585/838/980 +f 3585/838/980 3586/839/980 3583/836/979 +f 3582/840/981 3581/841/981 3584/837/979 +f 3584/837/979 3583/836/979 3582/840/981 +f 3587/737/982 3583/731/982 3586/734/983 +f 3586/734/983 3588/733/983 3587/737/982 +f 3579/741/984 3582/735/985 3583/731/982 +f 3583/731/982 3587/737/982 3579/741/984 +f 3589/837/1001 3587/836/1001 3588/839/987 +f 3588/839/987 3590/838/987 3589/837/1001 +f 3580/841/988 3579/840/988 3587/836/1001 +f 3587/836/1001 3589/837/1001 3580/841/988 +f 3584/842/989 3589/732/989 3590/843/990 +f 3590/843/990 3585/734/990 3584/842/989 +f 3581/831/991 3580/736/991 3589/732/989 +f 3589/732/989 3584/842/989 3581/831/991 +f 3591/721/226 3592/722/226 3593/723/226 +f 3593/723/226 3594/724/226 3591/721/226 +f 3595/725/888 3596/726/888 3597/727/889 +f 3597/727/889 3598/728/889 3595/725/888 +f 3594/729/890 3593/730/890 3596/726/888 +f 3596/726/888 3595/725/888 3594/729/890 +f 3599/731/891 3595/732/892 3598/733/893 +f 3598/733/893 3600/734/893 3599/731/891 +f 3591/735/895 3594/736/895 3595/732/892 +f 3595/732/892 3599/731/891 3591/735/895 +f 3601/726/896 3599/725/896 3600/728/897 +f 3600/728/897 3602/727/897 3601/726/896 +f 3592/730/898 3591/729/898 3599/725/896 +f 3599/725/896 3601/726/896 3592/730/898 +f 3596/737/899 3601/738/899 3602/739/900 +f 3602/739/900 3597/740/900 3596/737/899 +f 3593/741/901 3592/742/901 3601/738/899 +f 3601/738/899 3596/737/899 3593/741/901 +f 3603/743/36 3604/744/36 3605/745/36 +f 3605/745/36 3606/746/36 3603/743/36 +f 3607/747/902 3608/748/995 3609/749/903 +f 3609/749/903 3610/750/903 3607/747/902 +f 3606/751/904 3605/752/904 3608/748/995 +f 3608/748/995 3607/747/902 3606/751/904 +f 3611/753/905 3607/754/906 3610/755/907 +f 3610/755/907 3612/756/908 3611/753/905 +f 3603/757/909 3606/758/909 3607/754/906 +f 3607/754/906 3611/753/905 3603/757/909 +f 3613/748/910 3611/747/911 3612/750/912 +f 3612/750/912 3614/749/912 3613/748/910 +f 3604/752/913 3603/751/913 3611/747/911 +f 3611/747/911 3613/748/910 3604/752/913 +f 3608/754/914 3613/759/915 3614/760/916 +f 3614/760/916 3609/755/916 3608/754/914 +f 3605/758/917 3604/761/917 3613/759/915 +f 3613/759/915 3608/754/914 3605/758/917 +f 3615/762/918 3616/763/919 3617/764/920 +f 3617/764/920 3618/765/920 3615/762/918 +f 3619/766/921 3620/767/921 3616/763/919 +f 3616/763/919 3615/762/918 3619/766/921 +f 3621/768/922 3615/769/923 3618/770/924 +f 3618/770/924 3622/771/924 3621/768/922 +f 3623/772/925 3619/773/925 3615/769/923 +f 3615/769/923 3621/768/922 3623/772/925 +f 3624/763/926 3621/762/927 3622/765/928 +f 3622/765/928 3625/764/928 3624/763/926 +f 3626/767/929 3623/766/929 3621/762/927 +f 3621/762/927 3624/763/926 3626/767/929 +f 3616/774/930 3624/768/931 3625/771/932 +f 3625/771/932 3617/775/932 3616/774/930 +f 3620/776/933 3626/777/933 3624/768/931 +f 3624/768/931 3616/774/930 3620/776/933 +f 3627/778/934 3628/779/935 3629/780/936 +f 3629/780/936 3630/781/936 3627/778/934 +f 3631/782/937 3632/783/937 3628/779/935 +f 3628/779/935 3627/778/934 3631/782/937 +f 3633/784/938 3627/785/939 3630/786/940 +f 3630/786/940 3634/787/940 3633/784/938 +f 3635/788/941 3631/789/941 3627/785/939 +f 3627/785/939 3633/784/938 3635/788/941 +f 3636/790/1000 3633/791/943 3634/792/944 +f 3634/792/944 3637/793/944 3636/790/1000 +f 3638/794/945 3635/795/945 3633/791/943 +f 3633/791/943 3636/790/1000 3638/794/945 +f 3628/785/946 3636/796/947 3637/787/948 +f 3637/787/948 3629/797/948 3628/785/946 +f 3632/789/949 3638/798/949 3636/796/947 +f 3636/796/947 3628/785/946 3632/789/949 +f 3639/799/36 3640/800/36 3641/801/36 +f 3641/801/36 3642/802/36 3639/799/36 +f 3643/803/996 3644/804/997 3645/805/952 +f 3645/805/952 3646/806/952 3643/803/996 +f 3642/807/953 3641/808/953 3644/804/997 +f 3644/804/997 3643/803/996 3642/807/953 +f 3647/809/954 3643/810/954 3646/811/955 +f 3646/811/955 3648/812/955 3647/809/954 +f 3639/813/956 3642/814/956 3643/810/954 +f 3643/810/954 3647/809/954 3639/813/956 +f 3649/804/957 3647/803/958 3648/806/959 +f 3648/806/959 3650/805/959 3649/804/957 +f 3640/808/960 3639/807/960 3647/803/958 +f 3647/803/958 3649/804/957 3640/808/960 +f 3644/815/961 3649/809/961 3650/816/962 +f 3650/816/962 3645/817/962 3644/815/961 +f 3641/818/963 3640/819/963 3649/809/961 +f 3649/809/961 3644/815/961 3641/818/963 +f 3651/820/36 3652/821/36 3653/822/36 +f 3653/822/36 3654/823/36 3651/820/36 +f 3655/824/964 3656/825/965 3657/826/966 +f 3657/826/966 3658/827/966 3655/824/964 +f 3654/828/967 3653/829/967 3656/825/965 +f 3656/825/965 3655/824/964 3654/828/967 +f 3659/737/968 3655/738/969 3658/734/970 +f 3658/734/970 3660/740/970 3659/737/968 +f 3651/741/971 3654/735/971 3655/738/969 +f 3655/738/969 3659/737/968 3651/741/971 +f 3661/825/1002 3659/824/972 3660/827/973 +f 3660/827/973 3662/826/973 3661/825/1002 +f 3652/829/974 3651/828/974 3659/824/972 +f 3659/824/972 3661/825/1002 3652/829/974 +f 3656/731/975 3661/737/976 3662/733/977 +f 3662/733/977 3657/830/977 3656/731/975 +f 3653/831/978 3652/736/978 3661/737/976 +f 3661/737/976 3656/731/975 3653/831/978 +f 3663/832/226 3664/833/226 3665/834/226 +f 3665/834/226 3666/835/226 3663/832/226 +f 3667/836/979 3668/837/979 3669/838/980 +f 3669/838/980 3670/839/980 3667/836/979 +f 3666/840/981 3665/841/981 3668/837/979 +f 3668/837/979 3667/836/979 3666/840/981 +f 3671/737/982 3667/731/982 3670/734/983 +f 3670/734/983 3672/733/983 3671/737/982 +f 3663/741/984 3666/735/985 3667/731/982 +f 3667/731/982 3671/737/982 3663/741/984 +f 3673/837/1001 3671/836/1001 3672/839/987 +f 3672/839/987 3674/838/987 3673/837/1001 +f 3664/841/988 3663/840/988 3671/836/1001 +f 3671/836/1001 3673/837/1001 3664/841/988 +f 3668/842/989 3673/732/989 3674/843/990 +f 3674/843/990 3669/734/990 3668/842/989 +f 3665/831/991 3664/736/991 3673/732/989 +f 3673/732/989 3668/842/989 3665/831/991 +f 3675/721/226 3676/722/226 3677/723/226 +f 3677/723/226 3678/724/226 3675/721/226 +f 3679/725/1003 3680/726/1004 3681/727/1005 +f 3681/727/1005 3682/728/1005 3679/725/1003 +f 3678/729/1006 3677/730/1006 3680/726/1004 +f 3680/726/1004 3679/725/1003 3678/729/1006 +f 3683/731/1007 3679/732/1008 3682/733/1009 +f 3682/733/1009 3684/734/1009 3683/731/1007 +f 3675/735/1010 3678/736/1010 3679/732/1008 +f 3679/732/1008 3683/731/1007 3675/735/1010 +f 3685/726/1011 3683/725/1011 3684/728/1012 +f 3684/728/1012 3686/727/1012 3685/726/1011 +f 3676/730/1013 3675/729/1013 3683/725/1011 +f 3683/725/1011 3685/726/1011 3676/730/1013 +f 3680/737/1014 3685/738/1014 3686/739/1015 +f 3686/739/1015 3681/740/1015 3680/737/1014 +f 3677/741/1016 3676/742/1016 3685/738/1014 +f 3685/738/1014 3680/737/1014 3677/741/1016 +f 3687/743/37 3688/744/37 3689/745/37 +f 3689/745/37 3690/746/37 3687/743/37 +f 3691/747/1017 3692/748/1017 3693/749/1018 +f 3693/749/1018 3694/750/1018 3691/747/1017 +f 3690/751/1019 3689/752/1019 3692/748/1017 +f 3692/748/1017 3691/747/1017 3690/751/1019 +f 3695/753/1020 3691/754/1021 3694/755/1022 +f 3694/755/1022 3696/756/1022 3695/753/1020 +f 3687/757/1023 3690/758/1023 3691/754/1021 +f 3691/754/1021 3695/753/1020 3687/757/1023 +f 3697/748/1024 3695/747/1025 3696/750/1026 +f 3696/750/1026 3698/749/1026 3697/748/1024 +f 3688/752/1027 3687/751/1028 3695/747/1025 +f 3695/747/1025 3697/748/1024 3688/752/1027 +f 3692/754/1029 3697/759/1030 3698/760/1031 +f 3698/760/1031 3693/755/1031 3692/754/1029 +f 3689/758/1032 3688/761/1032 3697/759/1030 +f 3697/759/1030 3692/754/1029 3689/758/1032 +f 3699/762/1033 3700/763/1034 3701/764/1035 +f 3701/764/1035 3702/765/1035 3699/762/1033 +f 3703/766/1036 3704/767/1036 3700/763/1034 +f 3700/763/1034 3699/762/1033 3703/766/1036 +f 3705/768/1037 3699/769/1038 3702/770/1039 +f 3702/770/1039 3706/771/1039 3705/768/1037 +f 3707/772/1040 3703/773/1040 3699/769/1038 +f 3699/769/1038 3705/768/1037 3707/772/1040 +f 3708/763/1041 3705/762/1042 3706/765/1043 +f 3706/765/1043 3709/764/1043 3708/763/1041 +f 3710/767/1044 3707/766/1044 3705/762/1042 +f 3705/762/1042 3708/763/1041 3710/767/1044 +f 3700/774/1045 3708/768/1046 3709/771/1047 +f 3709/771/1047 3701/775/1047 3700/774/1045 +f 3704/776/1048 3710/777/1048 3708/768/1046 +f 3708/768/1046 3700/774/1045 3704/776/1048 +f 3711/778/1049 3712/779/1050 3713/780/1051 +f 3713/780/1051 3714/781/1051 3711/778/1049 +f 3715/782/1052 3716/783/1052 3712/779/1050 +f 3712/779/1050 3711/778/1049 3715/782/1052 +f 3717/784/1053 3711/785/1054 3714/786/1055 +f 3714/786/1055 3718/787/1055 3717/784/1053 +f 3719/788/1056 3715/789/1056 3711/785/1054 +f 3711/785/1054 3717/784/1053 3719/788/1056 +f 3720/790/1057 3717/791/1058 3718/792/1059 +f 3718/792/1059 3721/793/1059 3720/790/1057 +f 3722/794/1060 3719/795/1060 3717/791/1058 +f 3717/791/1058 3720/790/1057 3722/794/1060 +f 3712/785/1061 3720/796/1062 3721/787/1063 +f 3721/787/1063 3713/797/1063 3712/785/1061 +f 3716/789/1064 3722/798/1064 3720/796/1062 +f 3720/796/1062 3712/785/1061 3716/789/1064 +f 3723/799/37 3724/800/37 3725/801/37 +f 3725/801/37 3726/802/37 3723/799/37 +f 3727/803/816 3728/804/815 3729/805/869 +f 3729/805/869 3730/806/869 3727/803/816 +f 3726/807/870 3725/808/870 3728/804/815 +f 3728/804/815 3727/803/816 3726/807/870 +f 3731/809/1065 3727/810/1065 3730/811/1066 +f 3730/811/1066 3732/812/1066 3731/809/1065 +f 3723/813/1067 3726/814/1067 3727/810/1065 +f 3727/810/1065 3731/809/1065 3723/813/1067 +f 3733/804/809 3731/803/808 3732/806/810 +f 3732/806/810 3734/805/810 3733/804/809 +f 3724/808/811 3723/807/811 3731/803/808 +f 3731/803/808 3733/804/809 3724/808/811 +f 3728/815/1068 3733/809/1068 3734/816/1069 +f 3734/816/1069 3729/817/1069 3728/815/1068 +f 3725/818/1070 3724/819/1071 3733/809/1068 +f 3733/809/1068 3728/815/1068 3725/818/1070 +f 3735/820/37 3736/821/37 3737/822/37 +f 3737/822/37 3738/823/37 3735/820/37 +f 3739/824/1072 3740/825/1073 3741/826/1074 +f 3741/826/1074 3742/827/1074 3739/824/1072 +f 3738/828/1075 3737/829/1075 3740/825/1073 +f 3740/825/1073 3739/824/1072 3738/828/1075 +f 3743/737/1076 3739/738/1077 3742/734/1078 +f 3742/734/1078 3744/740/1078 3743/737/1076 +f 3735/741/1079 3738/735/1079 3739/738/1077 +f 3739/738/1077 3743/737/1076 3735/741/1079 +f 3745/825/1080 3743/824/1080 3744/827/1081 +f 3744/827/1081 3746/826/1081 3745/825/1080 +f 3736/829/1082 3735/828/1082 3743/824/1080 +f 3743/824/1080 3745/825/1080 3736/829/1082 +f 3740/731/1083 3745/737/1084 3746/733/1085 +f 3746/733/1085 3741/830/1085 3740/731/1083 +f 3737/831/1086 3736/736/1086 3745/737/1084 +f 3745/737/1084 3740/731/1083 3737/831/1086 +f 3747/832/37 3748/833/37 3749/834/37 +f 3749/834/37 3750/835/37 3747/832/37 +f 3751/836/1087 3752/837/1087 3753/838/1088 +f 3753/838/1088 3754/839/1088 3751/836/1087 +f 3750/840/1089 3749/841/1089 3752/837/1087 +f 3752/837/1087 3751/836/1087 3750/840/1089 +f 3755/737/848 3751/731/848 3754/734/849 +f 3754/734/849 3756/733/849 3755/737/848 +f 3747/741/850 3750/735/850 3751/731/848 +f 3751/731/848 3755/737/848 3747/741/850 +f 3757/837/1090 3755/836/1090 3756/839/1091 +f 3756/839/1091 3758/838/1091 3757/837/1090 +f 3748/841/1092 3747/840/1092 3755/836/1090 +f 3755/836/1090 3757/837/1090 3748/841/1092 +f 3752/842/1093 3757/732/842 3758/843/843 +f 3758/843/843 3753/734/843 3752/842/1093 +f 3749/831/1094 3748/736/1094 3757/732/842 +f 3757/732/842 3752/842/1093 3749/831/1094 +f 3759/721/226 3760/722/226 3761/723/226 +f 3761/723/226 3762/724/226 3759/721/226 +f 3763/725/1003 3764/726/1004 3765/727/1005 +f 3765/727/1005 3766/728/1005 3763/725/1003 +f 3762/729/1006 3761/730/1006 3764/726/1004 +f 3764/726/1004 3763/725/1003 3762/729/1006 +f 3767/731/1007 3763/732/1008 3766/733/1009 +f 3766/733/1009 3768/734/1009 3767/731/1007 +f 3759/735/1095 3762/736/1010 3763/732/1008 +f 3763/732/1008 3767/731/1007 3759/735/1095 +f 3769/726/1011 3767/725/1011 3768/728/1012 +f 3768/728/1012 3770/727/1012 3769/726/1011 +f 3760/730/1013 3759/729/1013 3767/725/1011 +f 3767/725/1011 3769/726/1011 3760/730/1013 +f 3764/737/1014 3769/738/1014 3770/739/1015 +f 3770/739/1015 3765/740/1015 3764/737/1014 +f 3761/741/1016 3760/742/1016 3769/738/1014 +f 3769/738/1014 3764/737/1014 3761/741/1016 +f 3771/743/37 3772/744/37 3773/745/37 +f 3773/745/37 3774/746/37 3771/743/37 +f 3775/747/1017 3776/748/1017 3777/749/1018 +f 3777/749/1018 3778/750/1018 3775/747/1017 +f 3774/751/1096 3773/752/1096 3776/748/1017 +f 3776/748/1017 3775/747/1017 3774/751/1096 +f 3779/753/1020 3775/754/1021 3778/755/1022 +f 3778/755/1022 3780/756/1022 3779/753/1020 +f 3771/757/1023 3774/758/1023 3775/754/1021 +f 3775/754/1021 3779/753/1020 3771/757/1023 +f 3781/748/1024 3779/747/1025 3780/750/1097 +f 3780/750/1097 3782/749/1097 3781/748/1024 +f 3772/752/1028 3771/751/1028 3779/747/1025 +f 3779/747/1025 3781/748/1024 3772/752/1028 +f 3776/754/1029 3781/759/1030 3782/760/1031 +f 3782/760/1031 3777/755/1031 3776/754/1029 +f 3773/758/1032 3772/761/1032 3781/759/1030 +f 3781/759/1030 3776/754/1029 3773/758/1032 +f 3783/762/1033 3784/763/1034 3785/764/1035 +f 3785/764/1035 3786/765/1035 3783/762/1033 +f 3787/766/1036 3788/767/1036 3784/763/1034 +f 3784/763/1034 3783/762/1033 3787/766/1036 +f 3789/768/1098 3783/769/1038 3786/770/1039 +f 3786/770/1039 3790/771/1039 3789/768/1098 +f 3791/772/1040 3787/773/1040 3783/769/1038 +f 3783/769/1038 3789/768/1098 3791/772/1040 +f 3792/763/1041 3789/762/1042 3790/765/1043 +f 3790/765/1043 3793/764/1043 3792/763/1041 +f 3794/767/1044 3791/766/1044 3789/762/1042 +f 3789/762/1042 3792/763/1041 3794/767/1044 +f 3784/774/1045 3792/768/1046 3793/771/1047 +f 3793/771/1047 3785/775/1047 3784/774/1045 +f 3788/776/1048 3794/777/1048 3792/768/1046 +f 3792/768/1046 3784/774/1045 3788/776/1048 +f 3795/778/1049 3796/779/1050 3797/780/1051 +f 3797/780/1051 3798/781/1051 3795/778/1049 +f 3799/782/1052 3800/783/1052 3796/779/1050 +f 3796/779/1050 3795/778/1049 3799/782/1052 +f 3801/784/1053 3795/785/1099 3798/786/1055 +f 3798/786/1055 3802/787/1055 3801/784/1053 +f 3803/788/1056 3799/789/1056 3795/785/1099 +f 3795/785/1099 3801/784/1053 3803/788/1056 +f 3804/790/1057 3801/791/1058 3802/792/1059 +f 3802/792/1059 3805/793/1059 3804/790/1057 +f 3806/794/1060 3803/795/1060 3801/791/1058 +f 3801/791/1058 3804/790/1057 3806/794/1060 +f 3796/785/1061 3804/796/1062 3805/787/1063 +f 3805/787/1063 3797/797/1063 3796/785/1061 +f 3800/789/1064 3806/798/1064 3804/796/1062 +f 3804/796/1062 3796/785/1061 3800/789/1064 +f 3807/799/37 3808/800/37 3809/801/37 +f 3809/801/37 3810/802/37 3807/799/37 +f 3811/803/816 3812/804/815 3813/805/869 +f 3813/805/869 3814/806/869 3811/803/816 +f 3810/807/870 3809/808/870 3812/804/815 +f 3812/804/815 3811/803/816 3810/807/870 +f 3815/809/1065 3811/810/1065 3814/811/1066 +f 3814/811/1066 3816/812/1066 3815/809/1065 +f 3807/813/1067 3810/814/1067 3811/810/1065 +f 3811/810/1065 3815/809/1065 3807/813/1067 +f 3817/804/1100 3815/803/808 3816/806/1101 +f 3816/806/1101 3818/805/1101 3817/804/1100 +f 3808/808/1102 3807/807/1102 3815/803/808 +f 3815/803/808 3817/804/1100 3808/808/1102 +f 3812/815/1068 3817/809/1068 3818/816/1069 +f 3818/816/1069 3813/817/1069 3812/815/1068 +f 3809/818/1071 3808/819/1071 3817/809/1068 +f 3817/809/1068 3812/815/1068 3809/818/1071 +f 3819/820/37 3820/821/37 3821/822/37 +f 3821/822/37 3822/823/37 3819/820/37 +f 3823/824/1103 3824/825/1104 3825/826/1074 +f 3825/826/1074 3826/827/1074 3823/824/1103 +f 3822/828/1105 3821/829/1105 3824/825/1104 +f 3824/825/1104 3823/824/1103 3822/828/1105 +f 3827/737/1076 3823/738/1077 3826/734/1078 +f 3826/734/1078 3828/740/1078 3827/737/1076 +f 3819/741/1079 3822/735/1079 3823/738/1077 +f 3823/738/1077 3827/737/1076 3819/741/1079 +f 3829/825/1106 3827/824/1080 3828/827/1081 +f 3828/827/1081 3830/826/1107 3829/825/1106 +f 3820/829/1082 3819/828/1108 3827/824/1080 +f 3827/824/1080 3829/825/1106 3820/829/1082 +f 3824/731/1083 3829/737/1084 3830/733/1085 +f 3830/733/1085 3825/830/1085 3824/731/1083 +f 3821/831/1086 3820/736/1086 3829/737/1084 +f 3829/737/1084 3824/731/1083 3821/831/1086 +f 3831/832/37 3832/833/37 3833/834/37 +f 3833/834/37 3834/835/37 3831/832/37 +f 3835/836/1087 3836/837/1087 3837/838/1109 +f 3837/838/1109 3838/839/1109 3835/836/1087 +f 3834/840/1110 3833/841/1110 3836/837/1087 +f 3836/837/1087 3835/836/1087 3834/840/1110 +f 3839/737/848 3835/731/848 3838/734/849 +f 3838/734/849 3840/733/849 3839/737/848 +f 3831/741/850 3834/735/850 3835/731/848 +f 3835/731/848 3839/737/848 3831/741/850 +f 3841/837/1090 3839/836/1090 3840/839/1111 +f 3840/839/1111 3842/838/1111 3841/837/1090 +f 3832/841/1092 3831/840/1092 3839/836/1090 +f 3839/836/1090 3841/837/1090 3832/841/1092 +f 3836/842/842 3841/732/842 3842/843/843 +f 3842/843/843 3837/734/843 3836/842/842 +f 3833/831/1094 3832/736/1094 3841/732/842 +f 3841/732/842 3836/842/842 3833/831/1094 +f 3843/721/226 3844/722/226 3845/723/226 +f 3845/723/226 3846/724/226 3843/721/226 +f 3847/725/1004 3848/726/1004 3849/727/1112 +f 3849/727/1112 3850/728/1112 3847/725/1004 +f 3846/729/1006 3845/730/1006 3848/726/1004 +f 3848/726/1004 3847/725/1004 3846/729/1006 +f 3851/731/1007 3847/732/1008 3850/733/1009 +f 3850/733/1009 3852/734/1009 3851/731/1007 +f 3843/735/1010 3846/736/1010 3847/732/1008 +f 3847/732/1008 3851/731/1007 3843/735/1010 +f 3853/726/1113 3851/725/1011 3852/728/1012 +f 3852/728/1012 3854/727/1012 3853/726/1113 +f 3844/730/1013 3843/729/1013 3851/725/1011 +f 3851/725/1011 3853/726/1113 3844/730/1013 +f 3848/737/1014 3853/738/1014 3854/739/1015 +f 3854/739/1015 3849/740/1015 3848/737/1014 +f 3845/741/1016 3844/742/1016 3853/738/1014 +f 3853/738/1014 3848/737/1014 3845/741/1016 +f 3855/743/37 3856/744/37 3857/745/37 +f 3857/745/37 3858/746/37 3855/743/37 +f 3859/747/1017 3860/748/1017 3861/749/1018 +f 3861/749/1018 3862/750/1018 3859/747/1017 +f 3858/751/1019 3857/752/1019 3860/748/1017 +f 3860/748/1017 3859/747/1017 3858/751/1019 +f 3863/753/1020 3859/754/1021 3862/755/1022 +f 3862/755/1022 3864/756/1022 3863/753/1020 +f 3855/757/1023 3858/758/1023 3859/754/1021 +f 3859/754/1021 3863/753/1020 3855/757/1023 +f 3865/748/1024 3863/747/1025 3864/750/1026 +f 3864/750/1026 3866/749/1026 3865/748/1024 +f 3856/752/1027 3855/751/1028 3863/747/1025 +f 3863/747/1025 3865/748/1024 3856/752/1027 +f 3860/754/1029 3865/759/1030 3866/760/1031 +f 3866/760/1031 3861/755/1031 3860/754/1029 +f 3857/758/1032 3856/761/1032 3865/759/1030 +f 3865/759/1030 3860/754/1029 3857/758/1032 +f 3867/762/1033 3868/763/1034 3869/764/1035 +f 3869/764/1035 3870/765/1035 3867/762/1033 +f 3871/766/1036 3872/767/1036 3868/763/1034 +f 3868/763/1034 3867/762/1033 3871/766/1036 +f 3873/768/1098 3867/769/1038 3870/770/1039 +f 3870/770/1039 3874/771/1039 3873/768/1098 +f 3875/772/1040 3871/773/1040 3867/769/1038 +f 3867/769/1038 3873/768/1098 3875/772/1040 +f 3876/763/1041 3873/762/1042 3874/765/1043 +f 3874/765/1043 3877/764/1043 3876/763/1041 +f 3878/767/1044 3875/766/1044 3873/762/1042 +f 3873/762/1042 3876/763/1041 3878/767/1044 +f 3868/774/1045 3876/768/1046 3877/771/1047 +f 3877/771/1047 3869/775/1047 3868/774/1045 +f 3872/776/1048 3878/777/1048 3876/768/1046 +f 3876/768/1046 3868/774/1045 3872/776/1048 +f 3879/778/1114 3880/779/1050 3881/780/1051 +f 3881/780/1051 3882/781/1051 3879/778/1114 +f 3883/782/1052 3884/783/1052 3880/779/1050 +f 3880/779/1050 3879/778/1114 3883/782/1052 +f 3885/784/1053 3879/785/1099 3882/786/1055 +f 3882/786/1055 3886/787/1055 3885/784/1053 +f 3887/788/1056 3883/789/1056 3879/785/1099 +f 3879/785/1099 3885/784/1053 3887/788/1056 +f 3888/790/1057 3885/791/1115 3886/792/1059 +f 3886/792/1059 3889/793/1059 3888/790/1057 +f 3890/794/1060 3887/795/1060 3885/791/1115 +f 3885/791/1115 3888/790/1057 3890/794/1060 +f 3880/785/1061 3888/796/1062 3889/787/1063 +f 3889/787/1063 3881/797/1063 3880/785/1061 +f 3884/789/1064 3890/798/1064 3888/796/1062 +f 3888/796/1062 3880/785/1061 3884/789/1064 +f 3891/799/37 3892/800/37 3893/801/37 +f 3893/801/37 3894/802/37 3891/799/37 +f 3895/803/816 3896/804/815 3897/805/869 +f 3897/805/869 3898/806/869 3895/803/816 +f 3894/807/870 3893/808/870 3896/804/815 +f 3896/804/815 3895/803/816 3894/807/870 +f 3899/809/1065 3895/810/1065 3898/811/1066 +f 3898/811/1066 3900/812/1066 3899/809/1065 +f 3891/813/1067 3894/814/1067 3895/810/1065 +f 3895/810/1065 3899/809/1065 3891/813/1067 +f 3901/804/809 3899/803/808 3900/806/810 +f 3900/806/810 3902/805/810 3901/804/809 +f 3892/808/811 3891/807/811 3899/803/808 +f 3899/803/808 3901/804/809 3892/808/811 +f 3896/815/1068 3901/809/1068 3902/816/1069 +f 3902/816/1069 3897/817/1069 3896/815/1068 +f 3893/818/1070 3892/819/1071 3901/809/1068 +f 3901/809/1068 3896/815/1068 3893/818/1070 +f 3903/820/37 3904/821/37 3905/822/37 +f 3905/822/37 3906/823/37 3903/820/37 +f 3907/824/1103 3908/825/1104 3909/826/1074 +f 3909/826/1074 3910/827/1074 3907/824/1103 +f 3906/828/1105 3905/829/1105 3908/825/1104 +f 3908/825/1104 3907/824/1103 3906/828/1105 +f 3911/737/1076 3907/738/1077 3910/734/1078 +f 3910/734/1078 3912/740/1078 3911/737/1076 +f 3903/741/1079 3906/735/1079 3907/738/1077 +f 3907/738/1077 3911/737/1076 3903/741/1079 +f 3913/825/1080 3911/824/1080 3912/827/1081 +f 3912/827/1081 3914/826/1081 3913/825/1080 +f 3904/829/1082 3903/828/1082 3911/824/1080 +f 3911/824/1080 3913/825/1080 3904/829/1082 +f 3908/731/1083 3913/737/1084 3914/733/1085 +f 3914/733/1085 3909/830/1085 3908/731/1083 +f 3905/831/1086 3904/736/1086 3913/737/1084 +f 3913/737/1084 3908/731/1083 3905/831/1086 +f 3915/832/37 3916/833/37 3917/834/37 +f 3917/834/37 3918/835/37 3915/832/37 +f 3919/836/1087 3920/837/1087 3921/838/1088 +f 3921/838/1088 3922/839/1088 3919/836/1087 +f 3918/840/1116 3917/841/1116 3920/837/1087 +f 3920/837/1087 3919/836/1087 3918/840/1116 +f 3923/737/848 3919/731/848 3922/734/849 +f 3922/734/849 3924/733/849 3923/737/848 +f 3915/741/850 3918/735/850 3919/731/848 +f 3919/731/848 3923/737/848 3915/741/850 +f 3925/837/1090 3923/836/1090 3924/839/1117 +f 3924/839/1117 3926/838/1117 3925/837/1090 +f 3916/841/1118 3915/840/1118 3923/836/1090 +f 3923/836/1090 3925/837/1090 3916/841/1118 +f 3920/842/842 3925/732/842 3926/843/843 +f 3926/843/843 3921/734/843 3920/842/842 +f 3917/831/1094 3916/736/1094 3925/732/842 +f 3925/732/842 3920/842/842 3917/831/1094 +f 3927/721/226 3928/722/226 3929/723/226 +f 3929/723/226 3930/724/226 3927/721/226 +f 3931/725/1004 3932/726/1004 3933/727/1119 +f 3933/727/1119 3934/728/1112 3931/725/1004 +f 3930/729/1006 3929/730/1006 3932/726/1004 +f 3932/726/1004 3931/725/1004 3930/729/1006 +f 3935/731/1007 3931/732/1008 3934/733/1009 +f 3934/733/1009 3936/734/1009 3935/731/1007 +f 3927/735/1010 3930/736/1010 3931/732/1008 +f 3931/732/1008 3935/731/1007 3927/735/1010 +f 3937/726/1113 3935/725/1011 3936/728/1012 +f 3936/728/1012 3938/727/1012 3937/726/1113 +f 3928/730/1013 3927/729/1013 3935/725/1011 +f 3935/725/1011 3937/726/1113 3928/730/1013 +f 3932/737/1014 3937/738/1014 3938/739/1015 +f 3938/739/1015 3933/740/1015 3932/737/1014 +f 3929/741/1016 3928/742/1016 3937/738/1014 +f 3937/738/1014 3932/737/1014 3929/741/1016 +f 3939/743/37 3940/744/37 3941/745/37 +f 3941/745/37 3942/746/37 3939/743/37 +f 3943/747/1017 3944/748/1017 3945/749/1018 +f 3945/749/1018 3946/750/1018 3943/747/1017 +f 3942/751/1019 3941/752/1019 3944/748/1017 +f 3944/748/1017 3943/747/1017 3942/751/1019 +f 3947/753/1020 3943/754/1021 3946/755/1022 +f 3946/755/1022 3948/756/1022 3947/753/1020 +f 3939/757/1023 3942/758/1023 3943/754/1021 +f 3943/754/1021 3947/753/1020 3939/757/1023 +f 3949/748/1024 3947/747/1025 3948/750/1026 +f 3948/750/1026 3950/749/1026 3949/748/1024 +f 3940/752/1027 3939/751/1028 3947/747/1025 +f 3947/747/1025 3949/748/1024 3940/752/1027 +f 3944/754/1029 3949/759/1030 3950/760/1031 +f 3950/760/1031 3945/755/1031 3944/754/1029 +f 3941/758/1032 3940/761/1032 3949/759/1030 +f 3949/759/1030 3944/754/1029 3941/758/1032 +f 3951/762/1033 3952/763/1034 3953/764/1035 +f 3953/764/1035 3954/765/1035 3951/762/1033 +f 3955/766/1036 3956/767/1036 3952/763/1034 +f 3952/763/1034 3951/762/1033 3955/766/1036 +f 3957/768/1098 3951/769/1038 3954/770/1039 +f 3954/770/1039 3958/771/1039 3957/768/1098 +f 3959/772/1040 3955/773/1040 3951/769/1038 +f 3951/769/1038 3957/768/1098 3959/772/1040 +f 3960/763/1041 3957/762/1042 3958/765/1043 +f 3958/765/1043 3961/764/1043 3960/763/1041 +f 3962/767/1044 3959/766/1044 3957/762/1042 +f 3957/762/1042 3960/763/1041 3962/767/1044 +f 3952/774/1045 3960/768/1046 3961/771/1047 +f 3961/771/1047 3953/775/1047 3952/774/1045 +f 3956/776/1048 3962/777/1048 3960/768/1046 +f 3960/768/1046 3952/774/1045 3956/776/1048 +f 3963/778/1114 3964/779/1050 3965/780/1051 +f 3965/780/1051 3966/781/1051 3963/778/1114 +f 3967/782/1052 3968/783/1052 3964/779/1050 +f 3964/779/1050 3963/778/1114 3967/782/1052 +f 3969/784/1053 3963/785/1099 3966/786/1055 +f 3966/786/1055 3970/787/1055 3969/784/1053 +f 3971/788/1056 3967/789/1056 3963/785/1099 +f 3963/785/1099 3969/784/1053 3971/788/1056 +f 3972/790/1057 3969/791/1058 3970/792/1059 +f 3970/792/1059 3973/793/1059 3972/790/1057 +f 3974/794/1060 3971/795/1060 3969/791/1058 +f 3969/791/1058 3972/790/1057 3974/794/1060 +f 3964/785/1061 3972/796/1062 3973/787/1063 +f 3973/787/1063 3965/797/1063 3964/785/1061 +f 3968/789/1064 3974/798/1064 3972/796/1062 +f 3972/796/1062 3964/785/1061 3968/789/1064 +f 3975/799/37 3976/800/37 3977/801/37 +f 3977/801/37 3978/802/37 3975/799/37 +f 3979/803/816 3980/804/815 3981/805/869 +f 3981/805/869 3982/806/869 3979/803/816 +f 3978/807/870 3977/808/870 3980/804/815 +f 3980/804/815 3979/803/816 3978/807/870 +f 3983/809/1065 3979/810/1065 3982/811/1066 +f 3982/811/1066 3984/812/1066 3983/809/1065 +f 3975/813/1067 3978/814/1067 3979/810/1065 +f 3979/810/1065 3983/809/1065 3975/813/1067 +f 3985/804/809 3983/803/808 3984/806/810 +f 3984/806/810 3986/805/810 3985/804/809 +f 3976/808/811 3975/807/811 3983/803/808 +f 3983/803/808 3985/804/809 3976/808/811 +f 3980/815/1068 3985/809/1068 3986/816/1069 +f 3986/816/1069 3981/817/1069 3980/815/1068 +f 3977/818/1070 3976/819/1071 3985/809/1068 +f 3985/809/1068 3980/815/1068 3977/818/1070 +f 3987/820/37 3988/821/37 3989/822/37 +f 3989/822/37 3990/823/37 3987/820/37 +f 3991/824/1072 3992/825/1073 3993/826/1120 +f 3993/826/1120 3994/827/1074 3991/824/1072 +f 3990/828/1121 3989/829/1105 3992/825/1073 +f 3992/825/1073 3991/824/1072 3990/828/1121 +f 3995/737/1076 3991/738/1077 3994/734/1078 +f 3994/734/1078 3996/740/1078 3995/737/1076 +f 3987/741/1079 3990/735/1079 3991/738/1077 +f 3991/738/1077 3995/737/1076 3987/741/1079 +f 3997/825/1080 3995/824/1080 3996/827/1081 +f 3996/827/1081 3998/826/1081 3997/825/1080 +f 3988/829/1082 3987/828/1082 3995/824/1080 +f 3995/824/1080 3997/825/1080 3988/829/1082 +f 3992/731/1083 3997/737/1084 3998/733/1085 +f 3998/733/1085 3993/830/1085 3992/731/1083 +f 3989/831/1086 3988/736/1086 3997/737/1084 +f 3997/737/1084 3992/731/1083 3989/831/1086 +f 3999/832/37 4000/833/37 4001/834/37 +f 4001/834/37 4002/835/37 3999/832/37 +f 4003/836/1087 4004/837/1087 4005/838/1088 +f 4005/838/1088 4006/839/1088 4003/836/1087 +f 4002/840/1089 4001/841/1089 4004/837/1087 +f 4004/837/1087 4003/836/1087 4002/840/1089 +f 4007/737/848 4003/731/848 4006/734/849 +f 4006/734/849 4008/733/849 4007/737/848 +f 3999/741/850 4002/735/850 4003/731/848 +f 4003/731/848 4007/737/848 3999/741/850 +f 4009/837/1122 4007/836/1122 4008/839/1091 +f 4008/839/1091 4010/838/1091 4009/837/1122 +f 4000/841/1118 3999/840/1118 4007/836/1122 +f 4007/836/1122 4009/837/1122 4000/841/1118 +f 4004/842/1093 4009/732/842 4010/843/843 +f 4010/843/843 4005/734/843 4004/842/1093 +f 4001/831/1094 4000/736/1094 4009/732/842 +f 4009/732/842 4004/842/1093 4001/831/1094 +f 4011/721/226 4012/722/226 4013/723/226 +f 4013/723/226 4014/724/226 4011/721/226 +f 4015/725/852 4016/726/748 4017/727/749 +f 4017/727/749 4018/728/749 4015/725/852 +f 4014/729/750 4013/730/750 4016/726/748 +f 4016/726/748 4015/725/852 4014/729/750 +f 4019/731/751 4015/732/752 4018/733/753 +f 4018/733/753 4020/734/753 4019/731/751 +f 4011/735/1123 4014/736/1123 4015/732/752 +f 4015/732/752 4019/731/751 4011/735/1123 +f 4021/726/755 4019/725/755 4020/728/756 +f 4020/728/756 4022/727/756 4021/726/755 +f 4012/730/757 4011/729/757 4019/725/755 +f 4019/725/755 4021/726/755 4012/730/757 +f 4016/737/758 4021/738/758 4022/739/759 +f 4022/739/759 4017/740/759 4016/737/758 +f 4013/741/760 4012/742/760 4021/738/758 +f 4021/738/758 4016/737/758 4013/741/760 +f 4023/743/226 4024/744/226 4025/745/226 +f 4025/745/226 4026/746/226 4023/743/226 +f 4027/747/761 4028/748/761 4029/749/762 +f 4029/749/762 4030/750/762 4027/747/761 +f 4026/751/763 4025/752/763 4028/748/761 +f 4028/748/761 4027/747/761 4026/751/763 +f 4031/753/764 4027/754/765 4030/755/766 +f 4030/755/766 4032/756/766 4031/753/764 +f 4023/757/767 4026/758/767 4027/754/765 +f 4027/754/765 4031/753/764 4023/757/767 +f 4033/748/768 4031/747/769 4032/750/770 +f 4032/750/770 4034/749/770 4033/748/768 +f 4024/752/771 4023/751/771 4031/747/769 +f 4031/747/769 4033/748/768 4024/752/771 +f 4028/754/772 4033/759/773 4034/760/774 +f 4034/760/774 4029/755/774 4028/754/772 +f 4025/758/775 4024/761/775 4033/759/773 +f 4033/759/773 4028/754/772 4025/758/775 +f 4035/762/776 4036/763/777 4037/764/778 +f 4037/764/778 4038/765/778 4035/762/776 +f 4039/766/779 4040/767/779 4036/763/777 +f 4036/763/777 4035/762/776 4039/766/779 +f 4041/768/1124 4035/769/781 4038/770/782 +f 4038/770/782 4042/771/782 4041/768/1124 +f 4043/772/783 4039/773/783 4035/769/781 +f 4035/769/781 4041/768/1124 4043/772/783 +f 4044/763/784 4041/762/785 4042/765/786 +f 4042/765/786 4045/764/786 4044/763/784 +f 4046/767/787 4043/766/787 4041/762/785 +f 4041/762/785 4044/763/784 4046/767/787 +f 4036/774/788 4044/768/789 4045/771/790 +f 4045/771/790 4037/775/790 4036/774/788 +f 4040/776/791 4046/777/791 4044/768/789 +f 4044/768/789 4036/774/788 4040/776/791 +f 4047/778/868 4048/779/793 4049/780/794 +f 4049/780/794 4050/781/794 4047/778/868 +f 4051/782/795 4052/783/795 4048/779/793 +f 4048/779/793 4047/778/868 4051/782/795 +f 4053/784/796 4047/785/797 4050/786/798 +f 4050/786/798 4054/787/798 4053/784/796 +f 4055/788/799 4051/789/799 4047/785/797 +f 4047/785/797 4053/784/796 4055/788/799 +f 4056/790/853 4053/791/854 4054/792/802 +f 4054/792/802 4057/793/802 4056/790/853 +f 4058/794/803 4055/795/803 4053/791/854 +f 4053/791/854 4056/790/853 4058/794/803 +f 4048/785/804 4056/796/805 4057/787/806 +f 4057/787/806 4049/797/806 4048/785/804 +f 4052/789/807 4058/798/807 4056/796/805 +f 4056/796/805 4048/785/804 4052/789/807 +f 4059/799/226 4060/800/226 4061/801/226 +f 4061/801/226 4062/802/226 4059/799/226 +f 4063/803/808 4064/804/809 4065/805/810 +f 4065/805/810 4066/806/810 4063/803/808 +f 4062/807/811 4061/808/811 4064/804/809 +f 4064/804/809 4063/803/808 4062/807/811 +f 4067/809/812 4063/810/812 4066/811/813 +f 4066/811/813 4068/812/813 4067/809/812 +f 4059/813/814 4062/814/814 4063/810/812 +f 4063/810/812 4067/809/812 4059/813/814 +f 4069/804/815 4067/803/816 4068/806/817 +f 4068/806/817 4070/805/817 4069/804/815 +f 4060/808/818 4059/807/818 4067/803/816 +f 4067/803/816 4069/804/815 4060/808/818 +f 4064/815/819 4069/809/819 4070/816/820 +f 4070/816/820 4065/817/820 4064/815/819 +f 4061/818/821 4060/819/822 4069/809/819 +f 4069/809/819 4064/815/819 4061/818/821 +f 4071/820/226 4072/821/226 4073/822/226 +f 4073/822/226 4074/823/226 4071/820/226 +f 4075/824/857 4076/825/858 4077/826/825 +f 4077/826/825 4078/827/825 4075/824/857 +f 4074/828/826 4073/829/826 4076/825/858 +f 4076/825/858 4075/824/857 4074/828/826 +f 4079/737/827 4075/738/828 4078/734/829 +f 4078/734/829 4080/740/829 4079/737/827 +f 4071/741/830 4074/735/830 4075/738/828 +f 4075/738/828 4079/737/827 4071/741/830 +f 4081/825/831 4079/824/832 4080/827/833 +f 4080/827/833 4082/826/833 4081/825/831 +f 4072/829/834 4071/828/834 4079/824/832 +f 4079/824/832 4081/825/831 4072/829/834 +f 4076/731/835 4081/737/836 4082/733/837 +f 4082/733/837 4077/830/837 4076/731/835 +f 4073/831/838 4072/736/838 4081/737/836 +f 4081/737/836 4076/731/835 4073/831/838 +f 4083/832/226 4084/833/226 4085/834/226 +f 4085/834/226 4086/835/226 4083/832/226 +f 4087/836/839 4088/837/839 4089/838/1125 +f 4089/838/1125 4090/839/1125 4087/836/839 +f 4086/840/841 4085/841/841 4088/837/839 +f 4088/837/839 4087/836/839 4086/840/841 +f 4091/737/842 4087/731/842 4090/734/843 +f 4090/734/843 4092/733/843 4091/737/842 +f 4083/741/844 4086/735/844 4087/731/842 +f 4087/731/842 4091/737/842 4083/741/844 +f 4093/837/859 4091/836/859 4092/839/881 +f 4092/839/881 4094/838/881 4093/837/859 +f 4084/841/847 4083/840/847 4091/836/859 +f 4091/836/859 4093/837/859 4084/841/847 +f 4088/842/848 4093/732/848 4094/843/849 +f 4094/843/849 4089/734/849 4088/842/848 +f 4085/831/851 4084/736/851 4093/732/848 +f 4093/732/848 4088/842/848 4085/831/851 +f 4095/721/226 4096/722/226 4097/723/226 +f 4097/723/226 4098/724/226 4095/721/226 +f 4099/725/852 4100/726/748 4101/727/860 +f 4101/727/860 4102/728/860 4099/725/852 +f 4098/729/750 4097/730/750 4100/726/748 +f 4100/726/748 4099/725/852 4098/729/750 +f 4103/731/751 4099/732/752 4102/733/753 +f 4102/733/753 4104/734/753 4103/731/751 +f 4095/735/1123 4098/736/1123 4099/732/752 +f 4099/732/752 4103/731/751 4095/735/1123 +f 4105/726/755 4103/725/755 4104/728/756 +f 4104/728/756 4106/727/756 4105/726/755 +f 4096/730/757 4095/729/757 4103/725/755 +f 4103/725/755 4105/726/755 4096/730/757 +f 4100/737/758 4105/738/758 4106/739/759 +f 4106/739/759 4101/740/759 4100/737/758 +f 4097/741/760 4096/742/760 4105/738/758 +f 4105/738/758 4100/737/758 4097/741/760 +f 4107/743/226 4108/744/226 4109/745/226 +f 4109/745/226 4110/746/226 4107/743/226 +f 4111/747/761 4112/748/761 4113/749/762 +f 4113/749/762 4114/750/762 4111/747/761 +f 4110/751/1126 4109/752/1126 4112/748/761 +f 4112/748/761 4111/747/761 4110/751/1126 +f 4115/753/764 4111/754/765 4114/755/766 +f 4114/755/766 4116/756/766 4115/753/764 +f 4107/757/767 4110/758/767 4111/754/765 +f 4111/754/765 4115/753/764 4107/757/767 +f 4117/748/768 4115/747/769 4116/750/770 +f 4116/750/770 4118/749/770 4117/748/768 +f 4108/752/771 4107/751/771 4115/747/769 +f 4115/747/769 4117/748/768 4108/752/771 +f 4112/754/772 4117/759/773 4118/760/774 +f 4118/760/774 4113/755/774 4112/754/772 +f 4109/758/775 4108/761/775 4117/759/773 +f 4117/759/773 4112/754/772 4109/758/775 +f 4119/762/776 4120/763/777 4121/764/778 +f 4121/764/778 4122/765/1127 4119/762/776 +f 4123/766/779 4124/767/779 4120/763/777 +f 4120/763/777 4119/762/776 4123/766/779 +f 4125/768/1124 4119/769/781 4122/770/782 +f 4122/770/782 4126/771/782 4125/768/1124 +f 4127/772/783 4123/773/783 4119/769/781 +f 4119/769/781 4125/768/1124 4127/772/783 +f 4128/763/784 4125/762/785 4126/765/786 +f 4126/765/786 4129/764/786 4128/763/784 +f 4130/767/787 4127/766/787 4125/762/785 +f 4125/762/785 4128/763/784 4130/767/787 +f 4120/774/788 4128/768/789 4129/771/790 +f 4129/771/790 4121/775/790 4120/774/788 +f 4124/776/791 4130/777/791 4128/768/789 +f 4128/768/789 4120/774/788 4124/776/791 +f 4131/778/792 4132/779/793 4133/780/794 +f 4133/780/794 4134/781/794 4131/778/792 +f 4135/782/795 4136/783/795 4132/779/793 +f 4132/779/793 4131/778/792 4135/782/795 +f 4137/784/796 4131/785/797 4134/786/798 +f 4134/786/798 4138/787/798 4137/784/796 +f 4139/788/799 4135/789/799 4131/785/797 +f 4131/785/797 4137/784/796 4139/788/799 +f 4140/790/800 4137/791/801 4138/792/802 +f 4138/792/802 4141/793/802 4140/790/800 +f 4142/794/803 4139/795/803 4137/791/801 +f 4137/791/801 4140/790/800 4142/794/803 +f 4132/785/804 4140/796/805 4141/787/806 +f 4141/787/806 4133/797/806 4132/785/804 +f 4136/789/807 4142/798/807 4140/796/805 +f 4140/796/805 4132/785/804 4136/789/807 +f 4143/799/226 4144/800/226 4145/801/226 +f 4145/801/226 4146/802/226 4143/799/226 +f 4147/803/808 4148/804/809 4149/805/810 +f 4149/805/810 4150/806/810 4147/803/808 +f 4146/807/811 4145/808/811 4148/804/809 +f 4148/804/809 4147/803/808 4146/807/811 +f 4151/809/812 4147/810/812 4150/811/813 +f 4150/811/813 4152/812/813 4151/809/812 +f 4143/813/814 4146/814/814 4147/810/812 +f 4147/810/812 4151/809/812 4143/813/814 +f 4153/804/815 4151/803/816 4152/806/1128 +f 4152/806/1128 4154/805/1128 4153/804/815 +f 4144/808/870 4143/807/870 4151/803/816 +f 4151/803/816 4153/804/815 4144/808/870 +f 4148/815/819 4153/809/819 4154/816/820 +f 4154/816/820 4149/817/820 4148/815/819 +f 4145/818/821 4144/819/822 4153/809/819 +f 4153/809/819 4148/815/819 4145/818/821 +f 4155/820/226 4156/821/226 4157/822/226 +f 4157/822/226 4158/823/226 4155/820/226 +f 4159/824/857 4160/825/858 4161/826/825 +f 4161/826/825 4162/827/825 4159/824/857 +f 4158/828/862 4157/829/862 4160/825/858 +f 4160/825/858 4159/824/857 4158/828/862 +f 4163/737/827 4159/738/828 4162/734/829 +f 4162/734/829 4164/740/829 4163/737/827 +f 4155/741/830 4158/735/830 4159/738/828 +f 4159/738/828 4163/737/827 4155/741/830 +f 4165/825/832 4163/824/832 4164/827/833 +f 4164/827/833 4166/826/833 4165/825/832 +f 4156/829/834 4155/828/834 4163/824/832 +f 4163/824/832 4165/825/832 4156/829/834 +f 4160/731/835 4165/737/836 4166/733/837 +f 4166/733/837 4161/830/837 4160/731/835 +f 4157/831/838 4156/736/838 4165/737/836 +f 4165/737/836 4160/731/835 4157/831/838 +f 4167/832/226 4168/833/226 4169/834/226 +f 4169/834/226 4170/835/226 4167/832/226 +f 4171/836/839 4172/837/839 4173/838/865 +f 4173/838/865 4174/839/865 4171/836/839 +f 4170/840/866 4169/841/866 4172/837/839 +f 4172/837/839 4171/836/839 4170/840/866 +f 4175/737/842 4171/731/842 4174/734/843 +f 4174/734/843 4176/733/843 4175/737/842 +f 4167/741/844 4170/735/844 4171/731/842 +f 4171/731/842 4175/737/842 4167/741/844 +f 4177/837/859 4175/836/859 4176/839/871 +f 4176/839/871 4178/838/871 4177/837/859 +f 4168/841/847 4167/840/847 4175/836/859 +f 4175/836/859 4177/837/859 4168/841/847 +f 4172/842/867 4177/732/848 4178/843/849 +f 4178/843/849 4173/734/849 4172/842/867 +f 4169/831/851 4168/736/851 4177/732/848 +f 4177/732/848 4172/842/867 4169/831/851 +f 4179/721/226 4180/722/226 4181/723/226 +f 4181/723/226 4182/724/226 4179/721/226 +f 4183/725/1129 4184/726/1129 4185/727/1130 +f 4185/727/1130 4186/728/1130 4183/725/1129 +f 4182/729/1131 4181/730/1131 4184/726/1129 +f 4184/726/1129 4183/725/1129 4182/729/1131 +f 4187/731/1132 4183/732/1133 4186/733/1134 +f 4186/733/1134 4188/734/1134 4187/731/1132 +f 4179/735/1135 4182/736/1135 4183/732/1133 +f 4183/732/1133 4187/731/1132 4179/735/1135 +f 4189/726/1136 4187/725/1136 4188/728/1137 +f 4188/728/1137 4190/727/1137 4189/726/1136 +f 4180/730/1138 4179/729/1138 4187/725/1136 +f 4187/725/1136 4189/726/1136 4180/730/1138 +f 4184/737/1139 4189/738/1139 4190/739/1140 +f 4190/739/1140 4185/740/1140 4184/737/1139 +f 4181/741/1141 4180/742/1142 4189/738/1139 +f 4189/738/1139 4184/737/1139 4181/741/1141 +f 4191/743/36 4192/744/36 4193/745/36 +f 4193/745/36 4194/746/36 4191/743/36 +f 4195/747/1143 4196/748/1144 4197/749/1145 +f 4197/749/1145 4198/750/1145 4195/747/1143 +f 4194/751/1146 4193/752/1146 4196/748/1144 +f 4196/748/1144 4195/747/1143 4194/751/1146 +f 4199/753/1147 4195/754/1148 4198/755/1149 +f 4198/755/1149 4200/756/1149 4199/753/1147 +f 4191/757/1150 4194/758/1150 4195/754/1148 +f 4195/754/1148 4199/753/1147 4191/757/1150 +f 4201/748/1151 4199/747/1152 4200/750/1153 +f 4200/750/1153 4202/749/1153 4201/748/1151 +f 4192/752/1154 4191/751/1154 4199/747/1152 +f 4199/747/1152 4201/748/1151 4192/752/1154 +f 4196/754/1155 4201/759/1156 4202/760/1157 +f 4202/760/1157 4197/755/1157 4196/754/1155 +f 4193/758/1158 4192/761/1158 4201/759/1156 +f 4201/759/1156 4196/754/1155 4193/758/1158 +f 4203/762/1159 4204/763/1160 4205/764/1161 +f 4205/764/1161 4206/765/1161 4203/762/1159 +f 4207/766/1162 4208/767/1162 4204/763/1160 +f 4204/763/1160 4203/762/1159 4207/766/1162 +f 4209/768/1163 4203/769/1164 4206/770/1165 +f 4206/770/1165 4210/771/1165 4209/768/1163 +f 4211/772/1166 4207/773/1167 4203/769/1164 +f 4203/769/1164 4209/768/1163 4211/772/1166 +f 4212/763/1168 4209/762/1169 4210/765/1170 +f 4210/765/1170 4213/764/1170 4212/763/1168 +f 4214/767/1171 4211/766/1171 4209/762/1169 +f 4209/762/1169 4212/763/1168 4214/767/1171 +f 4204/774/1172 4212/768/1173 4213/771/1174 +f 4213/771/1174 4205/775/1174 4204/774/1172 +f 4208/776/1175 4214/777/1175 4212/768/1173 +f 4212/768/1173 4204/774/1172 4208/776/1175 +f 4215/778/1176 4216/779/1177 4217/780/1178 +f 4217/780/1178 4218/781/1178 4215/778/1176 +f 4219/782/1179 4220/783/1179 4216/779/1177 +f 4216/779/1177 4215/778/1176 4219/782/1179 +f 4221/784/1180 4215/785/1181 4218/786/1182 +f 4218/786/1182 4222/787/1182 4221/784/1180 +f 4223/788/1183 4219/789/1184 4215/785/1181 +f 4215/785/1181 4221/784/1180 4223/788/1183 +f 4224/790/1185 4221/791/1186 4222/792/1187 +f 4222/792/1187 4225/793/1187 4224/790/1185 +f 4226/794/1188 4223/795/1188 4221/791/1186 +f 4221/791/1186 4224/790/1185 4226/794/1188 +f 4216/785/1189 4224/796/1190 4225/787/1191 +f 4225/787/1191 4217/797/1191 4216/785/1189 +f 4220/789/1192 4226/798/1192 4224/796/1190 +f 4224/796/1190 4216/785/1189 4220/789/1192 +f 4227/799/36 4228/800/36 4229/801/36 +f 4229/801/36 4230/802/36 4227/799/36 +f 4231/803/958 4232/804/957 4233/805/1193 +f 4233/805/1193 4234/806/1193 4231/803/958 +f 4230/807/1194 4229/808/1194 4232/804/957 +f 4232/804/957 4231/803/958 4230/807/1194 +f 4235/809/1195 4231/810/1195 4234/811/1196 +f 4234/811/1196 4236/812/1196 4235/809/1195 +f 4227/813/1197 4230/814/1197 4231/810/1195 +f 4231/810/1195 4235/809/1195 4227/813/1197 +f 4237/804/997 4235/803/996 4236/806/1198 +f 4236/806/1198 4238/805/1198 4237/804/997 +f 4228/808/1199 4227/807/1199 4235/803/996 +f 4235/803/996 4237/804/997 4228/808/1199 +f 4232/815/1200 4237/809/1200 4238/816/1201 +f 4238/816/1201 4233/817/1201 4232/815/1200 +f 4229/818/1202 4228/819/1203 4237/809/1200 +f 4237/809/1200 4232/815/1200 4229/818/1202 +f 4239/820/36 4240/821/36 4241/822/36 +f 4241/822/36 4242/823/36 4239/820/36 +f 4243/824/1204 4244/825/1205 4245/826/1206 +f 4245/826/1206 4246/827/1206 4243/824/1204 +f 4242/828/1207 4241/829/1207 4244/825/1205 +f 4244/825/1205 4243/824/1204 4242/828/1207 +f 4247/737/1208 4243/738/1209 4246/734/1210 +f 4246/734/1210 4248/740/1210 4247/737/1208 +f 4239/741/1211 4242/735/1211 4243/738/1209 +f 4243/738/1209 4247/737/1208 4239/741/1211 +f 4249/825/1212 4247/824/1213 4248/827/1214 +f 4248/827/1214 4250/826/1214 4249/825/1212 +f 4240/829/1215 4239/828/1215 4247/824/1213 +f 4247/824/1213 4249/825/1212 4240/829/1215 +f 4244/731/1216 4249/737/1217 4250/733/1218 +f 4250/733/1218 4245/830/1218 4244/731/1216 +f 4241/831/1219 4240/736/1219 4249/737/1217 +f 4249/737/1217 4244/731/1216 4241/831/1219 +f 4251/832/226 4252/833/226 4253/834/226 +f 4253/834/226 4254/835/226 4251/832/226 +f 4255/836/1220 4256/837/1220 4257/838/1221 +f 4257/838/1221 4258/839/1221 4255/836/1220 +f 4254/840/1222 4253/841/1222 4256/837/1220 +f 4256/837/1220 4255/836/1220 4254/840/1222 +f 4259/737/989 4255/731/989 4258/734/990 +f 4258/734/990 4260/733/990 4259/737/989 +f 4251/741/1223 4254/735/1223 4255/731/989 +f 4255/731/989 4259/737/989 4251/741/1223 +f 4261/837/1224 4259/836/1224 4260/839/1225 +f 4260/839/1225 4262/838/1225 4261/837/1224 +f 4252/841/1226 4251/840/1226 4259/836/1224 +f 4259/836/1224 4261/837/1224 4252/841/1226 +f 4256/842/982 4261/732/982 4262/843/983 +f 4262/843/983 4257/734/983 4256/842/982 +f 4253/831/985 4252/736/985 4261/732/982 +f 4261/732/982 4256/842/982 4253/831/985 +f 4263/721/36 4264/722/36 4265/723/36 +f 4265/723/36 4266/724/36 4263/721/36 +f 4267/725/1129 4268/726/1129 4269/727/1130 +f 4269/727/1130 4270/728/1130 4267/725/1129 +f 4266/729/1131 4265/730/1131 4268/726/1129 +f 4268/726/1129 4267/725/1129 4266/729/1131 +f 4271/731/1132 4267/732/1133 4270/733/1134 +f 4270/733/1134 4272/734/1134 4271/731/1132 +f 4263/735/1135 4266/736/1135 4267/732/1133 +f 4267/732/1133 4271/731/1132 4263/735/1135 +f 4273/726/1136 4271/725/1136 4272/728/1137 +f 4272/728/1137 4274/727/1137 4273/726/1136 +f 4264/730/1138 4263/729/1138 4271/725/1136 +f 4271/725/1136 4273/726/1136 4264/730/1138 +f 4268/737/1139 4273/738/1139 4274/739/1140 +f 4274/739/1140 4269/740/1140 4268/737/1139 +f 4265/741/1141 4264/742/1142 4273/738/1139 +f 4273/738/1139 4268/737/1139 4265/741/1141 +f 4275/743/36 4276/744/36 4277/745/36 +f 4277/745/36 4278/746/36 4275/743/36 +f 4279/747/1143 4280/748/1144 4281/749/1145 +f 4281/749/1145 4282/750/1145 4279/747/1143 +f 4278/751/1146 4277/752/1146 4280/748/1144 +f 4280/748/1144 4279/747/1143 4278/751/1146 +f 4283/753/1147 4279/754/1148 4282/755/1149 +f 4282/755/1149 4284/756/1149 4283/753/1147 +f 4275/757/1150 4278/758/1150 4279/754/1148 +f 4279/754/1148 4283/753/1147 4275/757/1150 +f 4285/748/1151 4283/747/1152 4284/750/1153 +f 4284/750/1153 4286/749/1153 4285/748/1151 +f 4276/752/1154 4275/751/1154 4283/747/1152 +f 4283/747/1152 4285/748/1151 4276/752/1154 +f 4280/754/1155 4285/759/1156 4286/760/1157 +f 4286/760/1157 4281/755/1157 4280/754/1155 +f 4277/758/1158 4276/761/1158 4285/759/1156 +f 4285/759/1156 4280/754/1155 4277/758/1158 +f 4287/762/1159 4288/763/1160 4289/764/1161 +f 4289/764/1161 4290/765/1161 4287/762/1159 +f 4291/766/1162 4292/767/1162 4288/763/1160 +f 4288/763/1160 4287/762/1159 4291/766/1162 +f 4293/768/1163 4287/769/1164 4290/770/1165 +f 4290/770/1165 4294/771/1165 4293/768/1163 +f 4295/772/1166 4291/773/1167 4287/769/1164 +f 4287/769/1164 4293/768/1163 4295/772/1166 +f 4296/763/1168 4293/762/1169 4294/765/1170 +f 4294/765/1170 4297/764/1170 4296/763/1168 +f 4298/767/1171 4295/766/1171 4293/762/1169 +f 4293/762/1169 4296/763/1168 4298/767/1171 +f 4288/774/1172 4296/768/1173 4297/771/1174 +f 4297/771/1174 4289/775/1174 4288/774/1172 +f 4292/776/1175 4298/777/1175 4296/768/1173 +f 4296/768/1173 4288/774/1172 4292/776/1175 +f 4299/778/1176 4300/779/1177 4301/780/1178 +f 4301/780/1178 4302/781/1178 4299/778/1176 +f 4303/782/1179 4304/783/1179 4300/779/1177 +f 4300/779/1177 4299/778/1176 4303/782/1179 +f 4305/784/1180 4299/785/1181 4302/786/1182 +f 4302/786/1182 4306/787/1182 4305/784/1180 +f 4307/788/1183 4303/789/1184 4299/785/1181 +f 4299/785/1181 4305/784/1180 4307/788/1183 +f 4308/790/1185 4305/791/1186 4306/792/1187 +f 4306/792/1187 4309/793/1187 4308/790/1185 +f 4310/794/1188 4307/795/1188 4305/791/1186 +f 4305/791/1186 4308/790/1185 4310/794/1188 +f 4300/785/1189 4308/796/1190 4309/787/1191 +f 4309/787/1191 4301/797/1191 4300/785/1189 +f 4304/789/1192 4310/798/1192 4308/796/1190 +f 4308/796/1190 4300/785/1189 4304/789/1192 +f 4311/799/37 4312/800/37 4313/801/37 +f 4313/801/37 4314/802/37 4311/799/37 +f 4315/803/958 4316/804/957 4317/805/1193 +f 4317/805/1193 4318/806/1193 4315/803/958 +f 4314/807/1194 4313/808/1194 4316/804/957 +f 4316/804/957 4315/803/958 4314/807/1194 +f 4319/809/1195 4315/810/1195 4318/811/1196 +f 4318/811/1196 4320/812/1196 4319/809/1195 +f 4311/813/1197 4314/814/1197 4315/810/1195 +f 4315/810/1195 4319/809/1195 4311/813/1197 +f 4321/804/997 4319/803/996 4320/806/1198 +f 4320/806/1198 4322/805/1198 4321/804/997 +f 4312/808/1199 4311/807/1199 4319/803/996 +f 4319/803/996 4321/804/997 4312/808/1199 +f 4316/815/1200 4321/809/1200 4322/816/1201 +f 4322/816/1201 4317/817/1201 4316/815/1200 +f 4313/818/1202 4312/819/1203 4321/809/1200 +f 4321/809/1200 4316/815/1200 4313/818/1202 +f 4323/820/37 4324/821/37 4325/822/37 +f 4325/822/37 4326/823/37 4323/820/37 +f 4327/824/1227 4328/825/1228 4329/826/1206 +f 4329/826/1206 4330/827/1206 4327/824/1227 +f 4326/828/1207 4325/829/1207 4328/825/1228 +f 4328/825/1228 4327/824/1227 4326/828/1207 +f 4331/737/1208 4327/738/1209 4330/734/1210 +f 4330/734/1210 4332/740/1210 4331/737/1208 +f 4323/741/1211 4326/735/1211 4327/738/1209 +f 4327/738/1209 4331/737/1208 4323/741/1211 +f 4333/825/1213 4331/824/1213 4332/827/1214 +f 4332/827/1214 4334/826/1214 4333/825/1213 +f 4324/829/1215 4323/828/1215 4331/824/1213 +f 4331/824/1213 4333/825/1213 4324/829/1215 +f 4328/731/1216 4333/737/1217 4334/733/1218 +f 4334/733/1218 4329/830/1218 4328/731/1216 +f 4325/831/1219 4324/736/1219 4333/737/1217 +f 4333/737/1217 4328/731/1216 4325/831/1219 +f 4335/832/37 4336/833/37 4337/834/37 +f 4337/834/37 4338/835/37 4335/832/37 +f 4339/836/1220 4340/837/1220 4341/838/1221 +f 4341/838/1221 4342/839/1221 4339/836/1220 +f 4338/840/1222 4337/841/1222 4340/837/1220 +f 4340/837/1220 4339/836/1220 4338/840/1222 +f 4343/737/989 4339/731/989 4342/734/990 +f 4342/734/990 4344/733/990 4343/737/989 +f 4335/741/1223 4338/735/1223 4339/731/989 +f 4339/731/989 4343/737/989 4335/741/1223 +f 4345/837/1224 4343/836/1224 4344/839/1225 +f 4344/839/1225 4346/838/1225 4345/837/1224 +f 4336/841/1226 4335/840/1226 4343/836/1224 +f 4343/836/1224 4345/837/1224 4336/841/1226 +f 4340/842/982 4345/732/982 4346/843/983 +f 4346/843/983 4341/734/983 4340/842/982 +f 4337/831/985 4336/736/985 4345/732/982 +f 4345/732/982 4340/842/982 4337/831/985 +f 4347/721/226 4348/722/226 4349/723/226 +f 4349/723/226 4350/724/226 4347/721/226 +f 4351/725/852 4352/726/748 4353/727/860 +f 4353/727/860 4354/728/860 4351/725/852 +f 4350/729/750 4349/730/750 4352/726/748 +f 4352/726/748 4351/725/852 4350/729/750 +f 4355/731/751 4351/732/752 4354/733/753 +f 4354/733/753 4356/734/753 4355/731/751 +f 4347/735/754 4350/736/1123 4351/732/752 +f 4351/732/752 4355/731/751 4347/735/754 +f 4357/726/755 4355/725/755 4356/728/756 +f 4356/728/756 4358/727/756 4357/726/755 +f 4348/730/757 4347/729/757 4355/725/755 +f 4355/725/755 4357/726/755 4348/730/757 +f 4352/737/758 4357/738/758 4358/739/759 +f 4358/739/759 4353/740/759 4352/737/758 +f 4349/741/760 4348/742/760 4357/738/758 +f 4357/738/758 4352/737/758 4349/741/760 +f 4359/743/226 4360/744/226 4361/745/226 +f 4361/745/226 4362/746/226 4359/743/226 +f 4363/747/761 4364/748/761 4365/749/762 +f 4365/749/762 4366/750/762 4363/747/761 +f 4362/751/763 4361/752/763 4364/748/761 +f 4364/748/761 4363/747/761 4362/751/763 +f 4367/753/764 4363/754/765 4366/755/766 +f 4366/755/766 4368/756/766 4367/753/764 +f 4359/757/767 4362/758/767 4363/754/765 +f 4363/754/765 4367/753/764 4359/757/767 +f 4369/748/768 4367/747/769 4368/750/770 +f 4368/750/770 4370/749/770 4369/748/768 +f 4360/752/771 4359/751/771 4367/747/769 +f 4367/747/769 4369/748/768 4360/752/771 +f 4364/754/772 4369/759/773 4370/760/774 +f 4370/760/774 4365/755/774 4364/754/772 +f 4361/758/775 4360/761/775 4369/759/773 +f 4369/759/773 4364/754/772 4361/758/775 +f 4371/762/776 4372/763/777 4373/764/778 +f 4373/764/778 4374/765/778 4371/762/776 +f 4375/766/779 4376/767/779 4372/763/777 +f 4372/763/777 4371/762/776 4375/766/779 +f 4377/768/780 4371/769/781 4374/770/782 +f 4374/770/782 4378/771/782 4377/768/780 +f 4379/772/783 4375/773/783 4371/769/781 +f 4371/769/781 4377/768/780 4379/772/783 +f 4380/763/784 4377/762/785 4378/765/786 +f 4378/765/786 4381/764/786 4380/763/784 +f 4382/767/787 4379/766/787 4377/762/785 +f 4377/762/785 4380/763/784 4382/767/787 +f 4372/774/788 4380/768/789 4381/771/790 +f 4381/771/790 4373/775/790 4372/774/788 +f 4376/776/791 4382/777/791 4380/768/789 +f 4380/768/789 4372/774/788 4376/776/791 +f 4383/778/792 4384/779/793 4385/780/794 +f 4385/780/794 4386/781/794 4383/778/792 +f 4387/782/795 4388/783/795 4384/779/793 +f 4384/779/793 4383/778/792 4387/782/795 +f 4389/784/796 4383/785/797 4386/786/798 +f 4386/786/798 4390/787/798 4389/784/796 +f 4391/788/799 4387/789/799 4383/785/797 +f 4383/785/797 4389/784/796 4391/788/799 +f 4392/790/800 4389/791/801 4390/792/802 +f 4390/792/802 4393/793/802 4392/790/800 +f 4394/794/803 4391/795/803 4389/791/801 +f 4389/791/801 4392/790/800 4394/794/803 +f 4384/785/804 4392/796/805 4393/787/806 +f 4393/787/806 4385/797/806 4384/785/804 +f 4388/789/807 4394/798/807 4392/796/805 +f 4392/796/805 4384/785/804 4388/789/807 +f 4395/799/226 4396/800/226 4397/801/226 +f 4397/801/226 4398/802/226 4395/799/226 +f 4399/803/855 4400/804/856 4401/805/810 +f 4401/805/810 4402/806/810 4399/803/855 +f 4398/807/811 4397/808/811 4400/804/856 +f 4400/804/856 4399/803/855 4398/807/811 +f 4403/809/812 4399/810/812 4402/811/1229 +f 4402/811/1229 4404/812/1229 4403/809/812 +f 4395/813/814 4398/814/814 4399/810/812 +f 4399/810/812 4403/809/812 4395/813/814 +f 4405/804/815 4403/803/816 4404/806/817 +f 4404/806/817 4406/805/817 4405/804/815 +f 4396/808/818 4395/807/818 4403/803/816 +f 4403/803/816 4405/804/815 4396/808/818 +f 4400/815/819 4405/809/819 4406/816/820 +f 4406/816/820 4401/817/820 4400/815/819 +f 4397/818/822 4396/819/822 4405/809/819 +f 4405/809/819 4400/815/819 4397/818/822 +f 4407/820/226 4408/821/226 4409/822/226 +f 4409/822/226 4410/823/226 4407/820/226 +f 4411/824/857 4412/825/858 4413/826/825 +f 4413/826/825 4414/827/825 4411/824/857 +f 4410/828/826 4409/829/826 4412/825/858 +f 4412/825/858 4411/824/857 4410/828/826 +f 4415/737/827 4411/738/828 4414/734/829 +f 4414/734/829 4416/740/829 4415/737/827 +f 4407/741/830 4410/735/830 4411/738/828 +f 4411/738/828 4415/737/827 4407/741/830 +f 4417/825/832 4415/824/832 4416/827/833 +f 4416/827/833 4418/826/833 4417/825/832 +f 4408/829/834 4407/828/834 4415/824/832 +f 4415/824/832 4417/825/832 4408/829/834 +f 4412/731/835 4417/737/836 4418/733/837 +f 4418/733/837 4413/830/837 4412/731/835 +f 4409/831/838 4408/736/838 4417/737/836 +f 4417/737/836 4412/731/835 4409/831/838 +f 4419/832/226 4420/833/226 4421/834/226 +f 4421/834/226 4422/835/226 4419/832/226 +f 4423/836/1230 4424/837/1230 4425/838/865 +f 4425/838/865 4426/839/865 4423/836/1230 +f 4422/840/841 4421/841/841 4424/837/1230 +f 4424/837/1230 4423/836/1230 4422/840/841 +f 4427/737/842 4423/731/842 4426/734/843 +f 4426/734/843 4428/733/843 4427/737/842 +f 4419/741/844 4422/735/844 4423/731/842 +f 4423/731/842 4427/737/842 4419/741/844 +f 4429/837/859 4427/836/859 4428/839/846 +f 4428/839/846 4430/838/846 4429/837/859 +f 4420/841/847 4419/840/847 4427/836/859 +f 4427/836/859 4429/837/859 4420/841/847 +f 4424/842/848 4429/732/848 4430/843/849 +f 4430/843/849 4425/734/849 4424/842/848 +f 4421/831/851 4420/736/851 4429/732/848 +f 4429/732/848 4424/842/848 4421/831/851 +f 4431/721/226 4432/722/226 4433/723/226 +f 4433/723/226 4434/724/226 4431/721/226 +f 4435/725/748 4436/726/748 4437/727/749 +f 4437/727/749 4438/728/749 4435/725/748 +f 4434/729/750 4433/730/750 4436/726/748 +f 4436/726/748 4435/725/748 4434/729/750 +f 4439/731/751 4435/732/752 4438/733/753 +f 4438/733/753 4440/734/753 4439/731/751 +f 4431/735/754 4434/736/1123 4435/732/752 +f 4435/732/752 4439/731/751 4431/735/754 +f 4441/726/755 4439/725/755 4440/728/756 +f 4440/728/756 4442/727/756 4441/726/755 +f 4432/730/757 4431/729/757 4439/725/755 +f 4439/725/755 4441/726/755 4432/730/757 +f 4436/737/758 4441/738/758 4442/739/759 +f 4442/739/759 4437/740/759 4436/737/758 +f 4433/741/760 4432/742/760 4441/738/758 +f 4441/738/758 4436/737/758 4433/741/760 +f 4443/743/226 4444/744/226 4445/745/226 +f 4445/745/226 4446/746/226 4443/743/226 +f 4447/747/761 4448/748/761 4449/749/762 +f 4449/749/762 4450/750/762 4447/747/761 +f 4446/751/763 4445/752/763 4448/748/761 +f 4448/748/761 4447/747/761 4446/751/763 +f 4451/753/764 4447/754/765 4450/755/766 +f 4450/755/766 4452/756/766 4451/753/764 +f 4443/757/767 4446/758/767 4447/754/765 +f 4447/754/765 4451/753/764 4443/757/767 +f 4453/748/768 4451/747/769 4452/750/770 +f 4452/750/770 4454/749/770 4453/748/768 +f 4444/752/771 4443/751/771 4451/747/769 +f 4451/747/769 4453/748/768 4444/752/771 +f 4448/754/772 4453/759/773 4454/760/774 +f 4454/760/774 4449/755/774 4448/754/772 +f 4445/758/775 4444/761/775 4453/759/773 +f 4453/759/773 4448/754/772 4445/758/775 +f 4455/762/776 4456/763/777 4457/764/778 +f 4457/764/778 4458/765/778 4455/762/776 +f 4459/766/779 4460/767/779 4456/763/777 +f 4456/763/777 4455/762/776 4459/766/779 +f 4461/768/780 4455/769/781 4458/770/782 +f 4458/770/782 4462/771/782 4461/768/780 +f 4463/772/783 4459/773/783 4455/769/781 +f 4455/769/781 4461/768/780 4463/772/783 +f 4464/763/784 4461/762/785 4462/765/786 +f 4462/765/786 4465/764/786 4464/763/784 +f 4466/767/787 4463/766/787 4461/762/785 +f 4461/762/785 4464/763/784 4466/767/787 +f 4456/774/788 4464/768/789 4465/771/790 +f 4465/771/790 4457/775/790 4456/774/788 +f 4460/776/791 4466/777/791 4464/768/789 +f 4464/768/789 4456/774/788 4460/776/791 +f 4467/778/792 4468/779/793 4469/780/794 +f 4469/780/794 4470/781/794 4467/778/792 +f 4471/782/795 4472/783/795 4468/779/793 +f 4468/779/793 4467/778/792 4471/782/795 +f 4473/784/796 4467/785/797 4470/786/798 +f 4470/786/798 4474/787/798 4473/784/796 +f 4475/788/799 4471/789/799 4467/785/797 +f 4467/785/797 4473/784/796 4475/788/799 +f 4476/790/800 4473/791/801 4474/792/802 +f 4474/792/802 4477/793/802 4476/790/800 +f 4478/794/803 4475/795/803 4473/791/801 +f 4473/791/801 4476/790/800 4478/794/803 +f 4468/785/804 4476/796/805 4477/787/806 +f 4477/787/806 4469/797/806 4468/785/804 +f 4472/789/807 4478/798/807 4476/796/805 +f 4476/796/805 4468/785/804 4472/789/807 +f 4479/799/226 4480/800/226 4481/801/226 +f 4481/801/226 4482/802/226 4479/799/226 +f 4483/803/808 4484/804/809 4485/805/810 +f 4485/805/810 4486/806/810 4483/803/808 +f 4482/807/811 4481/808/811 4484/804/809 +f 4484/804/809 4483/803/808 4482/807/811 +f 4487/809/812 4483/810/812 4486/811/1229 +f 4486/811/1229 4488/812/1229 4487/809/812 +f 4479/813/814 4482/814/814 4483/810/812 +f 4483/810/812 4487/809/812 4479/813/814 +f 4489/804/815 4487/803/816 4488/806/817 +f 4488/806/817 4490/805/817 4489/804/815 +f 4480/808/818 4479/807/818 4487/803/816 +f 4487/803/816 4489/804/815 4480/808/818 +f 4484/815/819 4489/809/819 4490/816/820 +f 4490/816/820 4485/817/820 4484/815/819 +f 4481/818/822 4480/819/822 4489/809/819 +f 4489/809/819 4484/815/819 4481/818/822 +f 4491/820/226 4492/821/226 4493/822/226 +f 4493/822/226 4494/823/226 4491/820/226 +f 4495/824/823 4496/825/824 4497/826/825 +f 4497/826/825 4498/827/825 4495/824/823 +f 4494/828/1231 4493/829/826 4496/825/824 +f 4496/825/824 4495/824/823 4494/828/1231 +f 4499/737/827 4495/738/828 4498/734/829 +f 4498/734/829 4500/740/829 4499/737/827 +f 4491/741/830 4494/735/830 4495/738/828 +f 4495/738/828 4499/737/827 4491/741/830 +f 4501/825/831 4499/824/832 4500/827/833 +f 4500/827/833 4502/826/833 4501/825/831 +f 4492/829/834 4491/828/834 4499/824/832 +f 4499/824/832 4501/825/831 4492/829/834 +f 4496/731/835 4501/737/836 4502/733/837 +f 4502/733/837 4497/830/837 4496/731/835 +f 4493/831/838 4492/736/838 4501/737/836 +f 4501/737/836 4496/731/835 4493/831/838 +f 4503/832/226 4504/833/226 4505/834/226 +f 4505/834/226 4506/835/226 4503/832/226 +f 4507/836/839 4508/837/839 4509/838/840 +f 4509/838/840 4510/839/840 4507/836/839 +f 4506/840/841 4505/841/841 4508/837/839 +f 4508/837/839 4507/836/839 4506/840/841 +f 4511/737/842 4507/731/842 4510/734/843 +f 4510/734/843 4512/733/843 4511/737/842 +f 4503/741/844 4506/735/844 4507/731/842 +f 4507/731/842 4511/737/842 4503/741/844 +f 4513/837/845 4511/836/845 4512/839/846 +f 4512/839/846 4514/838/846 4513/837/845 +f 4504/841/847 4503/840/847 4511/836/845 +f 4511/836/845 4513/837/845 4504/841/847 +f 4508/842/867 4513/732/848 4514/843/849 +f 4514/843/849 4509/734/849 4508/842/867 +f 4505/831/851 4504/736/851 4513/732/848 +f 4513/732/848 4508/842/867 4505/831/851 +f 4515/721/226 4516/722/226 4517/723/226 +f 4517/723/226 4518/724/226 4515/721/226 +f 4519/725/748 4520/726/748 4521/727/749 +f 4521/727/749 4522/728/749 4519/725/748 +f 4518/729/750 4517/730/750 4520/726/748 +f 4520/726/748 4519/725/748 4518/729/750 +f 4523/731/751 4519/732/752 4522/733/753 +f 4522/733/753 4524/734/753 4523/731/751 +f 4515/735/754 4518/736/1123 4519/732/752 +f 4519/732/752 4523/731/751 4515/735/754 +f 4525/726/755 4523/725/755 4524/728/756 +f 4524/728/756 4526/727/756 4525/726/755 +f 4516/730/757 4515/729/757 4523/725/755 +f 4523/725/755 4525/726/755 4516/730/757 +f 4520/737/758 4525/738/758 4526/739/759 +f 4526/739/759 4521/740/759 4520/737/758 +f 4517/741/760 4516/742/760 4525/738/758 +f 4525/738/758 4520/737/758 4517/741/760 +f 4527/743/226 4528/744/226 4529/745/226 +f 4529/745/226 4530/746/226 4527/743/226 +f 4531/747/761 4532/748/761 4533/749/762 +f 4533/749/762 4534/750/762 4531/747/761 +f 4530/751/763 4529/752/763 4532/748/761 +f 4532/748/761 4531/747/761 4530/751/763 +f 4535/753/764 4531/754/765 4534/755/766 +f 4534/755/766 4536/756/766 4535/753/764 +f 4527/757/767 4530/758/767 4531/754/765 +f 4531/754/765 4535/753/764 4527/757/767 +f 4537/748/768 4535/747/769 4536/750/770 +f 4536/750/770 4538/749/770 4537/748/768 +f 4528/752/771 4527/751/771 4535/747/769 +f 4535/747/769 4537/748/768 4528/752/771 +f 4532/754/772 4537/759/773 4538/760/774 +f 4538/760/774 4533/755/774 4532/754/772 +f 4529/758/775 4528/761/775 4537/759/773 +f 4537/759/773 4532/754/772 4529/758/775 +f 4539/762/776 4540/763/777 4541/764/778 +f 4541/764/778 4542/765/778 4539/762/776 +f 4543/766/779 4544/767/779 4540/763/777 +f 4540/763/777 4539/762/776 4543/766/779 +f 4545/768/780 4539/769/781 4542/770/782 +f 4542/770/782 4546/771/782 4545/768/780 +f 4547/772/783 4543/773/783 4539/769/781 +f 4539/769/781 4545/768/780 4547/772/783 +f 4548/763/784 4545/762/785 4546/765/786 +f 4546/765/786 4549/764/786 4548/763/784 +f 4550/767/787 4547/766/787 4545/762/785 +f 4545/762/785 4548/763/784 4550/767/787 +f 4540/774/788 4548/768/789 4549/771/790 +f 4549/771/790 4541/775/790 4540/774/788 +f 4544/776/791 4550/777/791 4548/768/789 +f 4548/768/789 4540/774/788 4544/776/791 +f 4551/778/792 4552/779/793 4553/780/794 +f 4553/780/794 4554/781/794 4551/778/792 +f 4555/782/795 4556/783/795 4552/779/793 +f 4552/779/793 4551/778/792 4555/782/795 +f 4557/784/796 4551/785/797 4554/786/798 +f 4554/786/798 4558/787/798 4557/784/796 +f 4559/788/799 4555/789/799 4551/785/797 +f 4551/785/797 4557/784/796 4559/788/799 +f 4560/790/800 4557/791/801 4558/792/802 +f 4558/792/802 4561/793/802 4560/790/800 +f 4562/794/803 4559/795/803 4557/791/801 +f 4557/791/801 4560/790/800 4562/794/803 +f 4552/785/804 4560/796/805 4561/787/806 +f 4561/787/806 4553/797/806 4552/785/804 +f 4556/789/807 4562/798/807 4560/796/805 +f 4560/796/805 4552/785/804 4556/789/807 +f 4563/799/226 4564/800/226 4565/801/226 +f 4565/801/226 4566/802/226 4563/799/226 +f 4567/803/808 4568/804/809 4569/805/810 +f 4569/805/810 4570/806/810 4567/803/808 +f 4566/807/811 4565/808/811 4568/804/809 +f 4568/804/809 4567/803/808 4566/807/811 +f 4571/809/812 4567/810/812 4570/811/1229 +f 4570/811/1229 4572/812/1229 4571/809/812 +f 4563/813/814 4566/814/814 4567/810/812 +f 4567/810/812 4571/809/812 4563/813/814 +f 4573/804/815 4571/803/816 4572/806/817 +f 4572/806/817 4574/805/817 4573/804/815 +f 4564/808/818 4563/807/818 4571/803/816 +f 4571/803/816 4573/804/815 4564/808/818 +f 4568/815/819 4573/809/819 4574/816/820 +f 4574/816/820 4569/817/820 4568/815/819 +f 4565/818/822 4564/819/822 4573/809/819 +f 4573/809/819 4568/815/819 4565/818/822 +f 4575/820/226 4576/821/226 4577/822/226 +f 4577/822/226 4578/823/226 4575/820/226 +f 4579/824/823 4580/825/824 4581/826/825 +f 4581/826/825 4582/827/825 4579/824/823 +f 4578/828/826 4577/829/826 4580/825/824 +f 4580/825/824 4579/824/823 4578/828/826 +f 4583/737/827 4579/738/828 4582/734/829 +f 4582/734/829 4584/740/829 4583/737/827 +f 4575/741/830 4578/735/830 4579/738/828 +f 4579/738/828 4583/737/827 4575/741/830 +f 4585/825/831 4583/824/832 4584/827/833 +f 4584/827/833 4586/826/833 4585/825/831 +f 4576/829/834 4575/828/834 4583/824/832 +f 4583/824/832 4585/825/831 4576/829/834 +f 4580/731/835 4585/737/836 4586/733/837 +f 4586/733/837 4581/830/837 4580/731/835 +f 4577/831/838 4576/736/838 4585/737/836 +f 4585/737/836 4580/731/835 4577/831/838 +f 4587/832/226 4588/833/226 4589/834/226 +f 4589/834/226 4590/835/226 4587/832/226 +f 4591/836/839 4592/837/839 4593/838/840 +f 4593/838/840 4594/839/840 4591/836/839 +f 4590/840/841 4589/841/841 4592/837/839 +f 4592/837/839 4591/836/839 4590/840/841 +f 4595/737/842 4591/731/842 4594/734/843 +f 4594/734/843 4596/733/843 4595/737/842 +f 4587/741/844 4590/735/844 4591/731/842 +f 4591/731/842 4595/737/842 4587/741/844 +f 4597/837/845 4595/836/845 4596/839/846 +f 4596/839/846 4598/838/846 4597/837/845 +f 4588/841/847 4587/840/847 4595/836/845 +f 4595/836/845 4597/837/845 4588/841/847 +f 4592/842/867 4597/732/848 4598/843/849 +f 4598/843/849 4593/734/849 4592/842/867 +f 4589/831/851 4588/736/851 4597/732/848 +f 4597/732/848 4592/842/867 4589/831/851 +f 4599/721/226 4600/722/226 4601/723/226 +f 4601/723/226 4602/724/226 4599/721/226 +f 4603/725/748 4604/726/748 4605/727/749 +f 4605/727/749 4606/728/749 4603/725/748 +f 4602/729/750 4601/730/750 4604/726/748 +f 4604/726/748 4603/725/748 4602/729/750 +f 4607/731/751 4603/732/752 4606/733/753 +f 4606/733/753 4608/734/753 4607/731/751 +f 4599/735/754 4602/736/1123 4603/732/752 +f 4603/732/752 4607/731/751 4599/735/754 +f 4609/726/755 4607/725/755 4608/728/756 +f 4608/728/756 4610/727/756 4609/726/755 +f 4600/730/757 4599/729/757 4607/725/755 +f 4607/725/755 4609/726/755 4600/730/757 +f 4604/737/758 4609/738/758 4610/739/759 +f 4610/739/759 4605/740/759 4604/737/758 +f 4601/741/760 4600/742/760 4609/738/758 +f 4609/738/758 4604/737/758 4601/741/760 +f 4611/743/226 4612/744/226 4613/745/226 +f 4613/745/226 4614/746/226 4611/743/226 +f 4615/747/761 4616/748/761 4617/749/762 +f 4617/749/762 4618/750/762 4615/747/761 +f 4614/751/763 4613/752/763 4616/748/761 +f 4616/748/761 4615/747/761 4614/751/763 +f 4619/753/764 4615/754/765 4618/755/766 +f 4618/755/766 4620/756/766 4619/753/764 +f 4611/757/767 4614/758/767 4615/754/765 +f 4615/754/765 4619/753/764 4611/757/767 +f 4621/748/768 4619/747/769 4620/750/770 +f 4620/750/770 4622/749/770 4621/748/768 +f 4612/752/771 4611/751/771 4619/747/769 +f 4619/747/769 4621/748/768 4612/752/771 +f 4616/754/772 4621/759/773 4622/760/774 +f 4622/760/774 4617/755/774 4616/754/772 +f 4613/758/775 4612/761/775 4621/759/773 +f 4621/759/773 4616/754/772 4613/758/775 +f 4623/762/776 4624/763/777 4625/764/778 +f 4625/764/778 4626/765/778 4623/762/776 +f 4627/766/779 4628/767/779 4624/763/777 +f 4624/763/777 4623/762/776 4627/766/779 +f 4629/768/780 4623/769/781 4626/770/782 +f 4626/770/782 4630/771/782 4629/768/780 +f 4631/772/783 4627/773/783 4623/769/781 +f 4623/769/781 4629/768/780 4631/772/783 +f 4632/763/784 4629/762/785 4630/765/786 +f 4630/765/786 4633/764/786 4632/763/784 +f 4634/767/787 4631/766/787 4629/762/785 +f 4629/762/785 4632/763/784 4634/767/787 +f 4624/774/788 4632/768/789 4633/771/790 +f 4633/771/790 4625/775/790 4624/774/788 +f 4628/776/791 4634/777/791 4632/768/789 +f 4632/768/789 4624/774/788 4628/776/791 +f 4635/778/792 4636/779/793 4637/780/794 +f 4637/780/794 4638/781/794 4635/778/792 +f 4639/782/795 4640/783/795 4636/779/793 +f 4636/779/793 4635/778/792 4639/782/795 +f 4641/784/796 4635/785/797 4638/786/798 +f 4638/786/798 4642/787/798 4641/784/796 +f 4643/788/799 4639/789/799 4635/785/797 +f 4635/785/797 4641/784/796 4643/788/799 +f 4644/790/800 4641/791/801 4642/792/802 +f 4642/792/802 4645/793/802 4644/790/800 +f 4646/794/803 4643/795/803 4641/791/801 +f 4641/791/801 4644/790/800 4646/794/803 +f 4636/785/804 4644/796/805 4645/787/806 +f 4645/787/806 4637/797/806 4636/785/804 +f 4640/789/807 4646/798/807 4644/796/805 +f 4644/796/805 4636/785/804 4640/789/807 +f 4647/799/226 4648/800/226 4649/801/226 +f 4649/801/226 4650/802/226 4647/799/226 +f 4651/803/808 4652/804/809 4653/805/810 +f 4653/805/810 4654/806/810 4651/803/808 +f 4650/807/811 4649/808/811 4652/804/809 +f 4652/804/809 4651/803/808 4650/807/811 +f 4655/809/812 4651/810/812 4654/811/1229 +f 4654/811/1229 4656/812/1229 4655/809/812 +f 4647/813/814 4650/814/814 4651/810/812 +f 4651/810/812 4655/809/812 4647/813/814 +f 4657/804/815 4655/803/816 4656/806/817 +f 4656/806/817 4658/805/817 4657/804/815 +f 4648/808/818 4647/807/818 4655/803/816 +f 4655/803/816 4657/804/815 4648/808/818 +f 4652/815/819 4657/809/819 4658/816/820 +f 4658/816/820 4653/817/820 4652/815/819 +f 4649/818/822 4648/819/822 4657/809/819 +f 4657/809/819 4652/815/819 4649/818/822 +f 4659/820/226 4660/821/226 4661/822/226 +f 4661/822/226 4662/823/226 4659/820/226 +f 4663/824/823 4664/825/824 4665/826/825 +f 4665/826/825 4666/827/825 4663/824/823 +f 4662/828/1231 4661/829/826 4664/825/824 +f 4664/825/824 4663/824/823 4662/828/1231 +f 4667/737/827 4663/738/828 4666/734/829 +f 4666/734/829 4668/740/829 4667/737/827 +f 4659/741/830 4662/735/830 4663/738/828 +f 4663/738/828 4667/737/827 4659/741/830 +f 4669/825/831 4667/824/832 4668/827/833 +f 4668/827/833 4670/826/833 4669/825/831 +f 4660/829/834 4659/828/834 4667/824/832 +f 4667/824/832 4669/825/831 4660/829/834 +f 4664/731/835 4669/737/836 4670/733/837 +f 4670/733/837 4665/830/837 4664/731/835 +f 4661/831/838 4660/736/838 4669/737/836 +f 4669/737/836 4664/731/835 4661/831/838 +f 4671/832/226 4672/833/226 4673/834/226 +f 4673/834/226 4674/835/226 4671/832/226 +f 4675/836/839 4676/837/839 4677/838/840 +f 4677/838/840 4678/839/840 4675/836/839 +f 4674/840/841 4673/841/841 4676/837/839 +f 4676/837/839 4675/836/839 4674/840/841 +f 4679/737/842 4675/731/842 4678/734/843 +f 4678/734/843 4680/733/843 4679/737/842 +f 4671/741/844 4674/735/844 4675/731/842 +f 4675/731/842 4679/737/842 4671/741/844 +f 4681/837/845 4679/836/845 4680/839/846 +f 4680/839/846 4682/838/846 4681/837/845 +f 4672/841/847 4671/840/847 4679/836/845 +f 4679/836/845 4681/837/845 4672/841/847 +f 4676/842/867 4681/732/848 4682/843/849 +f 4682/843/849 4677/734/849 4676/842/867 +f 4673/831/851 4672/736/851 4681/732/848 +f 4681/732/848 4676/842/867 4673/831/851 +f 4683/721/226 4684/722/226 4685/723/226 +f 4685/723/226 4686/724/226 4683/721/226 +f 4687/725/852 4688/726/748 4689/727/860 +f 4689/727/860 4690/728/860 4687/725/852 +f 4686/729/750 4685/730/750 4688/726/748 +f 4688/726/748 4687/725/852 4686/729/750 +f 4691/731/751 4687/732/752 4690/733/753 +f 4690/733/753 4692/734/753 4691/731/751 +f 4683/735/754 4686/736/1123 4687/732/752 +f 4687/732/752 4691/731/751 4683/735/754 +f 4693/726/755 4691/725/755 4692/728/756 +f 4692/728/756 4694/727/756 4693/726/755 +f 4684/730/757 4683/729/757 4691/725/755 +f 4691/725/755 4693/726/755 4684/730/757 +f 4688/737/758 4693/738/758 4694/739/759 +f 4694/739/759 4689/740/759 4688/737/758 +f 4685/741/760 4684/742/760 4693/738/758 +f 4693/738/758 4688/737/758 4685/741/760 +f 4695/743/226 4696/744/226 4697/745/226 +f 4697/745/226 4698/746/226 4695/743/226 +f 4699/747/761 4700/748/761 4701/749/762 +f 4701/749/762 4702/750/762 4699/747/761 +f 4698/751/763 4697/752/763 4700/748/761 +f 4700/748/761 4699/747/761 4698/751/763 +f 4703/753/764 4699/754/765 4702/755/766 +f 4702/755/766 4704/756/766 4703/753/764 +f 4695/757/767 4698/758/767 4699/754/765 +f 4699/754/765 4703/753/764 4695/757/767 +f 4705/748/768 4703/747/769 4704/750/770 +f 4704/750/770 4706/749/770 4705/748/768 +f 4696/752/771 4695/751/771 4703/747/769 +f 4703/747/769 4705/748/768 4696/752/771 +f 4700/754/772 4705/759/773 4706/760/774 +f 4706/760/774 4701/755/774 4700/754/772 +f 4697/758/775 4696/761/775 4705/759/773 +f 4705/759/773 4700/754/772 4697/758/775 +f 4707/762/776 4708/763/777 4709/764/778 +f 4709/764/778 4710/765/778 4707/762/776 +f 4711/766/779 4712/767/779 4708/763/777 +f 4708/763/777 4707/762/776 4711/766/779 +f 4713/768/780 4707/769/781 4710/770/782 +f 4710/770/782 4714/771/782 4713/768/780 +f 4715/772/783 4711/773/783 4707/769/781 +f 4707/769/781 4713/768/780 4715/772/783 +f 4716/763/784 4713/762/785 4714/765/786 +f 4714/765/786 4717/764/786 4716/763/784 +f 4718/767/787 4715/766/787 4713/762/785 +f 4713/762/785 4716/763/784 4718/767/787 +f 4708/774/788 4716/768/789 4717/771/790 +f 4717/771/790 4709/775/790 4708/774/788 +f 4712/776/791 4718/777/791 4716/768/789 +f 4716/768/789 4708/774/788 4712/776/791 +f 4719/778/792 4720/779/793 4721/780/794 +f 4721/780/794 4722/781/794 4719/778/792 +f 4723/782/795 4724/783/795 4720/779/793 +f 4720/779/793 4719/778/792 4723/782/795 +f 4725/784/796 4719/785/797 4722/786/798 +f 4722/786/798 4726/787/798 4725/784/796 +f 4727/788/799 4723/789/799 4719/785/797 +f 4719/785/797 4725/784/796 4727/788/799 +f 4728/790/800 4725/791/801 4726/792/802 +f 4726/792/802 4729/793/802 4728/790/800 +f 4730/794/803 4727/795/803 4725/791/801 +f 4725/791/801 4728/790/800 4730/794/803 +f 4720/785/804 4728/796/805 4729/787/806 +f 4729/787/806 4721/797/806 4720/785/804 +f 4724/789/807 4730/798/807 4728/796/805 +f 4728/796/805 4720/785/804 4724/789/807 +f 4731/799/226 4732/800/226 4733/801/226 +f 4733/801/226 4734/802/226 4731/799/226 +f 4735/803/808 4736/804/809 4737/805/810 +f 4737/805/810 4738/806/810 4735/803/808 +f 4734/807/811 4733/808/811 4736/804/809 +f 4736/804/809 4735/803/808 4734/807/811 +f 4739/809/812 4735/810/812 4738/811/1229 +f 4738/811/1229 4740/812/1229 4739/809/812 +f 4731/813/814 4734/814/814 4735/810/812 +f 4735/810/812 4739/809/812 4731/813/814 +f 4741/804/815 4739/803/816 4740/806/817 +f 4740/806/817 4742/805/817 4741/804/815 +f 4732/808/818 4731/807/818 4739/803/816 +f 4739/803/816 4741/804/815 4732/808/818 +f 4736/815/819 4741/809/819 4742/816/820 +f 4742/816/820 4737/817/820 4736/815/819 +f 4733/818/822 4732/819/822 4741/809/819 +f 4741/809/819 4736/815/819 4733/818/822 +f 4743/820/226 4744/821/226 4745/822/226 +f 4745/822/226 4746/823/226 4743/820/226 +f 4747/824/857 4748/825/858 4749/826/825 +f 4749/826/825 4750/827/825 4747/824/857 +f 4746/828/826 4745/829/826 4748/825/858 +f 4748/825/858 4747/824/857 4746/828/826 +f 4751/737/827 4747/738/828 4750/734/829 +f 4750/734/829 4752/740/829 4751/737/827 +f 4743/741/830 4746/735/830 4747/738/828 +f 4747/738/828 4751/737/827 4743/741/830 +f 4753/825/831 4751/824/832 4752/827/833 +f 4752/827/833 4754/826/833 4753/825/831 +f 4744/829/834 4743/828/834 4751/824/832 +f 4751/824/832 4753/825/831 4744/829/834 +f 4748/731/835 4753/737/836 4754/733/837 +f 4754/733/837 4749/830/837 4748/731/835 +f 4745/831/838 4744/736/838 4753/737/836 +f 4753/737/836 4748/731/835 4745/831/838 +f 4755/832/226 4756/833/226 4757/834/226 +f 4757/834/226 4758/835/226 4755/832/226 +f 4759/836/1230 4760/837/1230 4761/838/840 +f 4761/838/840 4762/839/840 4759/836/1230 +f 4758/840/841 4757/841/841 4760/837/1230 +f 4760/837/1230 4759/836/1230 4758/840/841 +f 4763/737/842 4759/731/842 4762/734/843 +f 4762/734/843 4764/733/843 4763/737/842 +f 4755/741/844 4758/735/844 4759/731/842 +f 4759/731/842 4763/737/842 4755/741/844 +f 4765/837/859 4763/836/859 4764/839/846 +f 4764/839/846 4766/838/846 4765/837/859 +f 4756/841/847 4755/840/847 4763/836/859 +f 4763/836/859 4765/837/859 4756/841/847 +f 4760/842/848 4765/732/848 4766/843/849 +f 4766/843/849 4761/734/849 4760/842/848 +f 4757/831/851 4756/736/851 4765/732/848 +f 4765/732/848 4760/842/848 4757/831/851 +f 4767/721/226 4768/722/226 4769/723/226 +f 4769/723/226 4770/724/226 4767/721/226 +f 4771/725/748 4772/726/748 4773/727/749 +f 4773/727/749 4774/728/749 4771/725/748 +f 4770/729/750 4769/730/750 4772/726/748 +f 4772/726/748 4771/725/748 4770/729/750 +f 4775/731/751 4771/732/752 4774/733/753 +f 4774/733/753 4776/734/753 4775/731/751 +f 4767/735/754 4770/736/1123 4771/732/752 +f 4771/732/752 4775/731/751 4767/735/754 +f 4777/726/755 4775/725/755 4776/728/756 +f 4776/728/756 4778/727/756 4777/726/755 +f 4768/730/757 4767/729/757 4775/725/755 +f 4775/725/755 4777/726/755 4768/730/757 +f 4772/737/758 4777/738/758 4778/739/759 +f 4778/739/759 4773/740/759 4772/737/758 +f 4769/741/760 4768/742/760 4777/738/758 +f 4777/738/758 4772/737/758 4769/741/760 +f 4779/743/226 4780/744/226 4781/745/226 +f 4781/745/226 4782/746/226 4779/743/226 +f 4783/747/883 4784/748/884 4785/749/762 +f 4785/749/762 4786/750/762 4783/747/883 +f 4782/751/763 4781/752/763 4784/748/884 +f 4784/748/884 4783/747/883 4782/751/763 +f 4787/753/764 4783/754/765 4786/755/766 +f 4786/755/766 4788/756/766 4787/753/764 +f 4779/757/767 4782/758/767 4783/754/765 +f 4783/754/765 4787/753/764 4779/757/767 +f 4789/748/768 4787/747/769 4788/750/770 +f 4788/750/770 4790/749/770 4789/748/768 +f 4780/752/771 4779/751/771 4787/747/769 +f 4787/747/769 4789/748/768 4780/752/771 +f 4784/754/772 4789/759/773 4790/760/774 +f 4790/760/774 4785/755/774 4784/754/772 +f 4781/758/775 4780/761/775 4789/759/773 +f 4789/759/773 4784/754/772 4781/758/775 +f 4791/762/776 4792/763/777 4793/764/778 +f 4793/764/778 4794/765/778 4791/762/776 +f 4795/766/779 4796/767/779 4792/763/777 +f 4792/763/777 4791/762/776 4795/766/779 +f 4797/768/780 4791/769/781 4794/770/782 +f 4794/770/782 4798/771/782 4797/768/780 +f 4799/772/783 4795/773/783 4791/769/781 +f 4791/769/781 4797/768/780 4799/772/783 +f 4800/763/784 4797/762/785 4798/765/786 +f 4798/765/786 4801/764/786 4800/763/784 +f 4802/767/787 4799/766/787 4797/762/785 +f 4797/762/785 4800/763/784 4802/767/787 +f 4792/774/788 4800/768/789 4801/771/790 +f 4801/771/790 4793/775/790 4792/774/788 +f 4796/776/791 4802/777/791 4800/768/789 +f 4800/768/789 4792/774/788 4796/776/791 +f 4803/778/868 4804/779/793 4805/780/794 +f 4805/780/794 4806/781/794 4803/778/868 +f 4807/782/795 4808/783/795 4804/779/793 +f 4804/779/793 4803/778/868 4807/782/795 +f 4809/784/796 4803/785/797 4806/786/798 +f 4806/786/798 4810/787/798 4809/784/796 +f 4811/788/799 4807/789/799 4803/785/797 +f 4803/785/797 4809/784/796 4811/788/799 +f 4812/790/853 4809/791/854 4810/792/802 +f 4810/792/802 4813/793/802 4812/790/853 +f 4814/794/803 4811/795/803 4809/791/854 +f 4809/791/854 4812/790/853 4814/794/803 +f 4804/785/804 4812/796/805 4813/787/806 +f 4813/787/806 4805/797/806 4804/785/804 +f 4808/789/807 4814/798/807 4812/796/805 +f 4812/796/805 4804/785/804 4808/789/807 +f 4815/799/226 4816/800/226 4817/801/226 +f 4817/801/226 4818/802/226 4815/799/226 +f 4819/803/808 4820/804/809 4821/805/810 +f 4821/805/810 4822/806/810 4819/803/808 +f 4818/807/811 4817/808/811 4820/804/809 +f 4820/804/809 4819/803/808 4818/807/811 +f 4823/809/812 4819/810/812 4822/811/1229 +f 4822/811/1229 4824/812/1229 4823/809/812 +f 4815/813/814 4818/814/814 4819/810/812 +f 4819/810/812 4823/809/812 4815/813/814 +f 4825/804/815 4823/803/816 4824/806/817 +f 4824/806/817 4826/805/817 4825/804/815 +f 4816/808/818 4815/807/818 4823/803/816 +f 4823/803/816 4825/804/815 4816/808/818 +f 4820/815/819 4825/809/819 4826/816/820 +f 4826/816/820 4821/817/820 4820/815/819 +f 4817/818/822 4816/819/822 4825/809/819 +f 4825/809/819 4820/815/819 4817/818/822 +f 4827/820/226 4828/821/226 4829/822/226 +f 4829/822/226 4830/823/226 4827/820/226 +f 4831/824/857 4832/825/858 4833/826/825 +f 4833/826/825 4834/827/825 4831/824/857 +f 4830/828/826 4829/829/826 4832/825/858 +f 4832/825/858 4831/824/857 4830/828/826 +f 4835/737/827 4831/738/828 4834/734/829 +f 4834/734/829 4836/740/829 4835/737/827 +f 4827/741/830 4830/735/830 4831/738/828 +f 4831/738/828 4835/737/827 4827/741/830 +f 4837/825/831 4835/824/832 4836/827/833 +f 4836/827/833 4838/826/833 4837/825/831 +f 4828/829/834 4827/828/834 4835/824/832 +f 4835/824/832 4837/825/831 4828/829/834 +f 4832/731/835 4837/737/836 4838/733/837 +f 4838/733/837 4833/830/837 4832/731/835 +f 4829/831/838 4828/736/838 4837/737/836 +f 4837/737/836 4832/731/835 4829/831/838 +f 4839/832/226 4840/833/226 4841/834/226 +f 4841/834/226 4842/835/226 4839/832/226 +f 4843/836/839 4844/837/839 4845/838/840 +f 4845/838/840 4846/839/840 4843/836/839 +f 4842/840/861 4841/841/861 4844/837/839 +f 4844/837/839 4843/836/839 4842/840/861 +f 4847/737/842 4843/731/842 4846/734/843 +f 4846/734/843 4848/733/843 4847/737/842 +f 4839/741/844 4842/735/844 4843/731/842 +f 4843/731/842 4847/737/842 4839/741/844 +f 4849/837/845 4847/836/845 4848/839/846 +f 4848/839/846 4850/838/846 4849/837/845 +f 4840/841/847 4839/840/847 4847/836/845 +f 4847/836/845 4849/837/845 4840/841/847 +f 4844/842/867 4849/732/848 4850/843/849 +f 4850/843/849 4845/734/849 4844/842/867 +f 4841/831/851 4840/736/851 4849/732/848 +f 4849/732/848 4844/842/867 4841/831/851 +f 4851/721/226 4852/722/226 4853/723/226 +f 4853/723/226 4854/724/226 4851/721/226 +f 4855/725/852 4856/726/748 4857/727/749 +f 4857/727/749 4858/728/749 4855/725/852 +f 4854/729/750 4853/730/750 4856/726/748 +f 4856/726/748 4855/725/852 4854/729/750 +f 4859/731/751 4855/732/752 4858/733/753 +f 4858/733/753 4860/734/753 4859/731/751 +f 4851/735/754 4854/736/1123 4855/732/752 +f 4855/732/752 4859/731/751 4851/735/754 +f 4861/726/755 4859/725/755 4860/728/756 +f 4860/728/756 4862/727/756 4861/726/755 +f 4852/730/757 4851/729/757 4859/725/755 +f 4859/725/755 4861/726/755 4852/730/757 +f 4856/737/758 4861/738/758 4862/739/759 +f 4862/739/759 4857/740/759 4856/737/758 +f 4853/741/760 4852/742/760 4861/738/758 +f 4861/738/758 4856/737/758 4853/741/760 +f 4863/743/226 4864/744/226 4865/745/226 +f 4865/745/226 4866/746/226 4863/743/226 +f 4867/747/761 4868/748/761 4869/749/762 +f 4869/749/762 4870/750/762 4867/747/761 +f 4866/751/763 4865/752/763 4868/748/761 +f 4868/748/761 4867/747/761 4866/751/763 +f 4871/753/764 4867/754/765 4870/755/766 +f 4870/755/766 4872/756/766 4871/753/764 +f 4863/757/767 4866/758/767 4867/754/765 +f 4867/754/765 4871/753/764 4863/757/767 +f 4873/748/768 4871/747/769 4872/750/770 +f 4872/750/770 4874/749/770 4873/748/768 +f 4864/752/771 4863/751/771 4871/747/769 +f 4871/747/769 4873/748/768 4864/752/771 +f 4868/754/772 4873/759/773 4874/760/774 +f 4874/760/774 4869/755/774 4868/754/772 +f 4865/758/775 4864/761/775 4873/759/773 +f 4873/759/773 4868/754/772 4865/758/775 +f 4875/762/776 4876/763/777 4877/764/778 +f 4877/764/778 4878/765/778 4875/762/776 +f 4879/766/779 4880/767/779 4876/763/777 +f 4876/763/777 4875/762/776 4879/766/779 +f 4881/768/780 4875/769/781 4878/770/782 +f 4878/770/782 4882/771/782 4881/768/780 +f 4883/772/783 4879/773/783 4875/769/781 +f 4875/769/781 4881/768/780 4883/772/783 +f 4884/763/784 4881/762/785 4882/765/786 +f 4882/765/786 4885/764/786 4884/763/784 +f 4886/767/787 4883/766/787 4881/762/785 +f 4881/762/785 4884/763/784 4886/767/787 +f 4876/774/788 4884/768/789 4885/771/790 +f 4885/771/790 4877/775/790 4876/774/788 +f 4880/776/791 4886/777/791 4884/768/789 +f 4884/768/789 4876/774/788 4880/776/791 +f 4887/778/792 4888/779/793 4889/780/794 +f 4889/780/794 4890/781/794 4887/778/792 +f 4891/782/795 4892/783/795 4888/779/793 +f 4888/779/793 4887/778/792 4891/782/795 +f 4893/784/796 4887/785/797 4890/786/798 +f 4890/786/798 4894/787/798 4893/784/796 +f 4895/788/799 4891/789/799 4887/785/797 +f 4887/785/797 4893/784/796 4895/788/799 +f 4896/790/853 4893/791/854 4894/792/802 +f 4894/792/802 4897/793/802 4896/790/853 +f 4898/794/803 4895/795/803 4893/791/854 +f 4893/791/854 4896/790/853 4898/794/803 +f 4888/785/804 4896/796/805 4897/787/806 +f 4897/787/806 4889/797/806 4888/785/804 +f 4892/789/807 4898/798/807 4896/796/805 +f 4896/796/805 4888/785/804 4892/789/807 +f 4899/799/226 4900/800/226 4901/801/226 +f 4901/801/226 4902/802/226 4899/799/226 +f 4903/803/855 4904/804/856 4905/805/810 +f 4905/805/810 4906/806/810 4903/803/855 +f 4902/807/811 4901/808/811 4904/804/856 +f 4904/804/856 4903/803/855 4902/807/811 +f 4907/809/812 4903/810/812 4906/811/1229 +f 4906/811/1229 4908/812/1229 4907/809/812 +f 4899/813/814 4902/814/814 4903/810/812 +f 4903/810/812 4907/809/812 4899/813/814 +f 4909/804/815 4907/803/816 4908/806/817 +f 4908/806/817 4910/805/817 4909/804/815 +f 4900/808/818 4899/807/818 4907/803/816 +f 4907/803/816 4909/804/815 4900/808/818 +f 4904/815/819 4909/809/819 4910/816/820 +f 4910/816/820 4905/817/820 4904/815/819 +f 4901/818/822 4900/819/822 4909/809/819 +f 4909/809/819 4904/815/819 4901/818/822 +f 4911/820/226 4912/821/226 4913/822/226 +f 4913/822/226 4914/823/226 4911/820/226 +f 4915/824/857 4916/825/858 4917/826/825 +f 4917/826/825 4918/827/825 4915/824/857 +f 4914/828/826 4913/829/826 4916/825/858 +f 4916/825/858 4915/824/857 4914/828/826 +f 4919/737/827 4915/738/828 4918/734/829 +f 4918/734/829 4920/740/829 4919/737/827 +f 4911/741/830 4914/735/830 4915/738/828 +f 4915/738/828 4919/737/827 4911/741/830 +f 4921/825/831 4919/824/832 4920/827/833 +f 4920/827/833 4922/826/833 4921/825/831 +f 4912/829/834 4911/828/834 4919/824/832 +f 4919/824/832 4921/825/831 4912/829/834 +f 4916/731/835 4921/737/836 4922/733/837 +f 4922/733/837 4917/830/837 4916/731/835 +f 4913/831/838 4912/736/838 4921/737/836 +f 4921/737/836 4916/731/835 4913/831/838 +f 4923/832/226 4924/833/226 4925/834/226 +f 4925/834/226 4926/835/226 4923/832/226 +f 4927/836/839 4928/837/839 4929/838/840 +f 4929/838/840 4930/839/840 4927/836/839 +f 4926/840/861 4925/841/861 4928/837/839 +f 4928/837/839 4927/836/839 4926/840/861 +f 4931/737/842 4927/731/842 4930/734/843 +f 4930/734/843 4932/733/843 4931/737/842 +f 4923/741/844 4926/735/844 4927/731/842 +f 4927/731/842 4931/737/842 4923/741/844 +f 4933/837/859 4931/836/859 4932/839/846 +f 4932/839/846 4934/838/846 4933/837/859 +f 4924/841/847 4923/840/847 4931/836/859 +f 4931/836/859 4933/837/859 4924/841/847 +f 4928/842/848 4933/732/848 4934/843/849 +f 4934/843/849 4929/734/849 4928/842/848 +f 4925/831/851 4924/736/851 4933/732/848 +f 4933/732/848 4928/842/848 4925/831/851 +f 4935/721/36 4936/722/36 4937/723/36 +f 4937/723/36 4938/724/36 4935/721/36 +f 4939/725/888 4940/726/888 4941/727/889 +f 4941/727/889 4942/728/889 4939/725/888 +f 4938/729/890 4937/730/890 4940/726/888 +f 4940/726/888 4939/725/888 4938/729/890 +f 4943/731/891 4939/732/892 4942/733/893 +f 4942/733/893 4944/734/893 4943/731/891 +f 4935/735/895 4938/736/895 4939/732/892 +f 4939/732/892 4943/731/891 4935/735/895 +f 4945/726/896 4943/725/896 4944/728/897 +f 4944/728/897 4946/727/897 4945/726/896 +f 4936/730/898 4935/729/898 4943/725/896 +f 4943/725/896 4945/726/896 4936/730/898 +f 4940/737/899 4945/738/899 4946/739/900 +f 4946/739/900 4941/740/900 4940/737/899 +f 4937/741/901 4936/742/1232 4945/738/899 +f 4945/738/899 4940/737/899 4937/741/901 +f 4947/743/226 4948/744/226 4949/745/226 +f 4949/745/226 4950/746/226 4947/743/226 +f 4951/747/902 4952/748/995 4953/749/903 +f 4953/749/903 4954/750/903 4951/747/902 +f 4950/751/904 4949/752/904 4952/748/995 +f 4952/748/995 4951/747/902 4950/751/904 +f 4955/753/905 4951/754/1233 4954/755/907 +f 4954/755/907 4956/756/907 4955/753/905 +f 4947/757/1234 4950/758/1234 4951/754/1233 +f 4951/754/1233 4955/753/905 4947/757/1234 +f 4957/748/910 4955/747/911 4956/750/912 +f 4956/750/912 4958/749/912 4957/748/910 +f 4948/752/913 4947/751/913 4955/747/911 +f 4955/747/911 4957/748/910 4948/752/913 +f 4952/754/914 4957/759/1235 4958/760/916 +f 4958/760/916 4953/755/916 4952/754/914 +f 4949/758/917 4948/761/917 4957/759/1235 +f 4957/759/1235 4952/754/914 4949/758/917 +f 4959/762/918 4960/763/919 4961/764/920 +f 4961/764/920 4962/765/920 4959/762/918 +f 4963/766/921 4964/767/921 4960/763/919 +f 4960/763/919 4959/762/918 4963/766/921 +f 4965/768/1236 4959/769/923 4962/770/924 +f 4962/770/924 4966/771/924 4965/768/1236 +f 4967/772/925 4963/773/925 4959/769/923 +f 4959/769/923 4965/768/1236 4967/772/925 +f 4968/763/926 4965/762/927 4966/765/928 +f 4966/765/928 4969/764/928 4968/763/926 +f 4970/767/929 4967/766/929 4965/762/927 +f 4965/762/927 4968/763/926 4970/767/929 +f 4960/774/1237 4968/768/578 4969/771/932 +f 4969/771/932 4961/775/932 4960/774/1237 +f 4964/776/933 4970/777/933 4968/768/578 +f 4968/768/578 4960/774/1237 4964/776/933 +f 4971/778/934 4972/779/935 4973/780/936 +f 4973/780/936 4974/781/936 4971/778/934 +f 4975/782/937 4976/783/937 4972/779/935 +f 4972/779/935 4971/778/934 4975/782/937 +f 4977/784/1238 4971/785/939 4974/786/940 +f 4974/786/940 4978/787/940 4977/784/1238 +f 4979/788/941 4975/789/941 4971/785/939 +f 4971/785/939 4977/784/1238 4979/788/941 +f 4980/790/1000 4977/791/943 4978/792/944 +f 4978/792/944 4981/793/944 4980/790/1000 +f 4982/794/945 4979/795/945 4977/791/943 +f 4977/791/943 4980/790/1000 4982/794/945 +f 4972/785/946 4980/796/947 4981/787/948 +f 4981/787/948 4973/797/948 4972/785/946 +f 4976/789/949 4982/798/1239 4980/796/947 +f 4980/796/947 4972/785/946 4976/789/949 +f 4983/799/36 4984/800/36 4985/801/36 +f 4985/801/36 4986/802/36 4983/799/36 +f 4987/803/996 4988/804/997 4989/805/952 +f 4989/805/952 4990/806/952 4987/803/996 +f 4986/807/953 4985/808/953 4988/804/997 +f 4988/804/997 4987/803/996 4986/807/953 +f 4991/809/954 4987/810/954 4990/811/955 +f 4990/811/955 4992/812/955 4991/809/954 +f 4983/813/1240 4986/814/1240 4987/810/954 +f 4987/810/954 4991/809/954 4983/813/1240 +f 4993/804/957 4991/803/958 4992/806/959 +f 4992/806/959 4994/805/959 4993/804/957 +f 4984/808/960 4983/807/960 4991/803/958 +f 4991/803/958 4993/804/957 4984/808/960 +f 4988/815/1241 4993/809/1241 4994/816/962 +f 4994/816/962 4989/817/962 4988/815/1241 +f 4985/818/1242 4984/819/963 4993/809/1241 +f 4993/809/1241 4988/815/1241 4985/818/1242 +f 4995/820/36 4996/821/36 4997/822/36 +f 4997/822/36 4998/823/36 4995/820/36 +f 4999/824/998 5000/825/999 5001/826/966 +f 5001/826/966 5002/827/966 4999/824/998 +f 4998/828/967 4997/829/967 5000/825/999 +f 5000/825/999 4999/824/998 4998/828/967 +f 5003/737/968 4999/738/969 5002/734/970 +f 5002/734/970 5004/740/970 5003/737/968 +f 4995/741/1243 4998/735/1243 4999/738/969 +f 4999/738/969 5003/737/968 4995/741/1243 +f 5005/825/972 5003/824/972 5004/827/973 +f 5004/827/973 5006/826/973 5005/825/972 +f 4996/829/974 4995/828/974 5003/824/972 +f 5003/824/972 5005/825/972 4996/829/974 +f 5000/731/975 5005/737/976 5006/733/1244 +f 5006/733/1244 5001/830/1244 5000/731/975 +f 4997/831/1245 4996/736/1245 5005/737/976 +f 5005/737/976 5000/731/975 4997/831/1245 +f 5007/832/36 5008/833/36 5009/834/36 +f 5009/834/36 5010/835/36 5007/832/36 +f 5011/836/979 5012/837/979 5013/838/980 +f 5013/838/980 5014/839/980 5011/836/979 +f 5010/840/981 5009/841/981 5012/837/979 +f 5012/837/979 5011/836/979 5010/840/981 +f 5015/737/1246 5011/731/1246 5014/734/983 +f 5014/734/983 5016/733/983 5015/737/1246 +f 5007/741/985 5010/735/985 5011/731/1246 +f 5011/731/1246 5015/737/1246 5007/741/985 +f 5017/837/1001 5015/836/1001 5016/839/987 +f 5016/839/987 5018/838/987 5017/837/1001 +f 5008/841/988 5007/840/988 5015/836/1001 +f 5015/836/1001 5017/837/1001 5008/841/988 +f 5012/842/1247 5017/732/1247 5018/843/990 +f 5018/843/990 5013/734/990 5012/842/1247 +f 5009/831/991 5008/736/991 5017/732/1247 +f 5017/732/1247 5012/842/1247 5009/831/991 +f 5019/721/37 5020/722/37 5021/723/37 +f 5021/723/37 5022/724/37 5019/721/37 +f 5023/725/888 5024/726/888 5025/727/889 +f 5025/727/889 5026/728/889 5023/725/888 +f 5022/729/890 5021/730/890 5024/726/888 +f 5024/726/888 5023/725/888 5022/729/890 +f 5027/731/891 5023/732/892 5026/733/893 +f 5026/733/893 5028/734/893 5027/731/891 +f 5019/735/895 5022/736/895 5023/732/892 +f 5023/732/892 5027/731/891 5019/735/895 +f 5029/726/896 5027/725/896 5028/728/897 +f 5028/728/897 5030/727/897 5029/726/896 +f 5020/730/898 5019/729/898 5027/725/896 +f 5027/725/896 5029/726/896 5020/730/898 +f 5024/737/899 5029/738/899 5030/739/900 +f 5030/739/900 5025/740/900 5024/737/899 +f 5021/741/901 5020/742/1232 5029/738/899 +f 5029/738/899 5024/737/899 5021/741/901 +f 5031/743/36 5032/744/36 5033/745/36 +f 5033/745/36 5034/746/36 5031/743/36 +f 5035/747/902 5036/748/995 5037/749/903 +f 5037/749/903 5038/750/903 5035/747/902 +f 5034/751/904 5033/752/904 5036/748/995 +f 5036/748/995 5035/747/902 5034/751/904 +f 5039/753/905 5035/754/1233 5038/755/907 +f 5038/755/907 5040/756/907 5039/753/905 +f 5031/757/1234 5034/758/1234 5035/754/1233 +f 5035/754/1233 5039/753/905 5031/757/1234 +f 5041/748/910 5039/747/911 5040/750/912 +f 5040/750/912 5042/749/912 5041/748/910 +f 5032/752/913 5031/751/913 5039/747/911 +f 5039/747/911 5041/748/910 5032/752/913 +f 5036/754/914 5041/759/1235 5042/760/916 +f 5042/760/916 5037/755/916 5036/754/914 +f 5033/758/917 5032/761/917 5041/759/1235 +f 5041/759/1235 5036/754/914 5033/758/917 +f 5043/762/918 5044/763/919 5045/764/920 +f 5045/764/920 5046/765/920 5043/762/918 +f 5047/766/921 5048/767/921 5044/763/919 +f 5044/763/919 5043/762/918 5047/766/921 +f 5049/768/1236 5043/769/923 5046/770/924 +f 5046/770/924 5050/771/924 5049/768/1236 +f 5051/772/925 5047/773/925 5043/769/923 +f 5043/769/923 5049/768/1236 5051/772/925 +f 5052/763/926 5049/762/927 5050/765/928 +f 5050/765/928 5053/764/928 5052/763/926 +f 5054/767/929 5051/766/929 5049/762/927 +f 5049/762/927 5052/763/926 5054/767/929 +f 5044/774/1237 5052/768/578 5053/771/932 +f 5053/771/932 5045/775/932 5044/774/1237 +f 5048/776/933 5054/777/933 5052/768/578 +f 5052/768/578 5044/774/1237 5048/776/933 +f 5055/778/934 5056/779/935 5057/780/936 +f 5057/780/936 5058/781/936 5055/778/934 +f 5059/782/937 5060/783/937 5056/779/935 +f 5056/779/935 5055/778/934 5059/782/937 +f 5061/784/1238 5055/785/939 5058/786/940 +f 5058/786/940 5062/787/940 5061/784/1238 +f 5063/788/941 5059/789/941 5055/785/939 +f 5055/785/939 5061/784/1238 5063/788/941 +f 5064/790/1000 5061/791/943 5062/792/944 +f 5062/792/944 5065/793/944 5064/790/1000 +f 5066/794/945 5063/795/945 5061/791/943 +f 5061/791/943 5064/790/1000 5066/794/945 +f 5056/785/946 5064/796/947 5065/787/948 +f 5065/787/948 5057/797/948 5056/785/946 +f 5060/789/949 5066/798/1239 5064/796/947 +f 5064/796/947 5056/785/946 5060/789/949 +f 5067/799/37 5068/800/37 5069/801/37 +f 5069/801/37 5070/802/37 5067/799/37 +f 5071/803/996 5072/804/997 5073/805/952 +f 5073/805/952 5074/806/952 5071/803/996 +f 5070/807/953 5069/808/953 5072/804/997 +f 5072/804/997 5071/803/996 5070/807/953 +f 5075/809/954 5071/810/954 5074/811/955 +f 5074/811/955 5076/812/955 5075/809/954 +f 5067/813/1240 5070/814/1240 5071/810/954 +f 5071/810/954 5075/809/954 5067/813/1240 +f 5077/804/957 5075/803/958 5076/806/959 +f 5076/806/959 5078/805/959 5077/804/957 +f 5068/808/960 5067/807/960 5075/803/958 +f 5075/803/958 5077/804/957 5068/808/960 +f 5072/815/1241 5077/809/1241 5078/816/962 +f 5078/816/962 5073/817/962 5072/815/1241 +f 5069/818/1242 5068/819/963 5077/809/1241 +f 5077/809/1241 5072/815/1241 5069/818/1242 +f 5079/820/36 5080/821/36 5081/822/36 +f 5081/822/36 5082/823/36 5079/820/36 +f 5083/824/964 5084/825/965 5085/826/966 +f 5085/826/966 5086/827/966 5083/824/964 +f 5082/828/967 5081/829/967 5084/825/965 +f 5084/825/965 5083/824/964 5082/828/967 +f 5087/737/968 5083/738/969 5086/734/970 +f 5086/734/970 5088/740/970 5087/737/968 +f 5079/741/1243 5082/735/1243 5083/738/969 +f 5083/738/969 5087/737/968 5079/741/1243 +f 5089/825/972 5087/824/972 5088/827/973 +f 5088/827/973 5090/826/973 5089/825/972 +f 5080/829/974 5079/828/974 5087/824/972 +f 5087/824/972 5089/825/972 5080/829/974 +f 5084/731/975 5089/737/976 5090/733/1244 +f 5090/733/1244 5085/830/1244 5084/731/975 +f 5081/831/1245 5080/736/1245 5089/737/976 +f 5089/737/976 5084/731/975 5081/831/1245 +f 5091/832/36 5092/833/36 5093/834/36 +f 5093/834/36 5094/835/36 5091/832/36 +f 5095/836/979 5096/837/979 5097/838/994 +f 5097/838/994 5098/839/994 5095/836/979 +f 5094/840/981 5093/841/981 5096/837/979 +f 5096/837/979 5095/836/979 5094/840/981 +f 5099/737/1246 5095/731/1246 5098/734/983 +f 5098/734/983 5100/733/983 5099/737/1246 +f 5091/741/985 5094/735/985 5095/731/1246 +f 5095/731/1246 5099/737/1246 5091/741/985 +f 5101/837/1001 5099/836/1001 5100/839/987 +f 5100/839/987 5102/838/987 5101/837/1001 +f 5092/841/988 5091/840/988 5099/836/1001 +f 5099/836/1001 5101/837/1001 5092/841/988 +f 5096/842/1247 5101/732/1247 5102/843/990 +f 5102/843/990 5097/734/990 5096/842/1247 +f 5093/831/991 5092/736/991 5101/732/1247 +f 5101/732/1247 5096/842/1247 5093/831/991 +f 5103/721/36 5104/722/36 5105/723/36 +f 5105/723/36 5106/724/36 5103/721/36 +f 5107/725/888 5108/726/888 5109/727/889 +f 5109/727/889 5110/728/889 5107/725/888 +f 5106/729/890 5105/730/890 5108/726/888 +f 5108/726/888 5107/725/888 5106/729/890 +f 5111/731/891 5107/732/892 5110/733/893 +f 5110/733/893 5112/734/893 5111/731/891 +f 5103/735/895 5106/736/895 5107/732/892 +f 5107/732/892 5111/731/891 5103/735/895 +f 5113/726/896 5111/725/896 5112/728/897 +f 5112/728/897 5114/727/897 5113/726/896 +f 5104/730/898 5103/729/898 5111/725/896 +f 5111/725/896 5113/726/896 5104/730/898 +f 5108/737/899 5113/738/899 5114/739/900 +f 5114/739/900 5109/740/900 5108/737/899 +f 5105/741/901 5104/742/1232 5113/738/899 +f 5113/738/899 5108/737/899 5105/741/901 +f 5115/743/37 5116/744/37 5117/745/37 +f 5117/745/37 5118/746/37 5115/743/37 +f 5119/747/902 5120/748/995 5121/749/903 +f 5121/749/903 5122/750/903 5119/747/902 +f 5118/751/904 5117/752/904 5120/748/995 +f 5120/748/995 5119/747/902 5118/751/904 +f 5123/753/905 5119/754/1233 5122/755/907 +f 5122/755/907 5124/756/907 5123/753/905 +f 5115/757/1234 5118/758/1234 5119/754/1233 +f 5119/754/1233 5123/753/905 5115/757/1234 +f 5125/748/910 5123/747/911 5124/750/912 +f 5124/750/912 5126/749/912 5125/748/910 +f 5116/752/913 5115/751/913 5123/747/911 +f 5123/747/911 5125/748/910 5116/752/913 +f 5120/754/914 5125/759/1235 5126/760/916 +f 5126/760/916 5121/755/916 5120/754/914 +f 5117/758/917 5116/761/917 5125/759/1235 +f 5125/759/1235 5120/754/914 5117/758/917 +f 5127/762/918 5128/763/919 5129/764/920 +f 5129/764/920 5130/765/920 5127/762/918 +f 5131/766/921 5132/767/921 5128/763/919 +f 5128/763/919 5127/762/918 5131/766/921 +f 5133/768/1236 5127/769/923 5130/770/924 +f 5130/770/924 5134/771/924 5133/768/1236 +f 5135/772/925 5131/773/925 5127/769/923 +f 5127/769/923 5133/768/1236 5135/772/925 +f 5136/763/926 5133/762/927 5134/765/928 +f 5134/765/928 5137/764/928 5136/763/926 +f 5138/767/929 5135/766/929 5133/762/927 +f 5133/762/927 5136/763/926 5138/767/929 +f 5128/774/1237 5136/768/578 5137/771/932 +f 5137/771/932 5129/775/932 5128/774/1237 +f 5132/776/933 5138/777/933 5136/768/578 +f 5136/768/578 5128/774/1237 5132/776/933 +f 5139/778/934 5140/779/935 5141/780/936 +f 5141/780/936 5142/781/936 5139/778/934 +f 5143/782/937 5144/783/937 5140/779/935 +f 5140/779/935 5139/778/934 5143/782/937 +f 5145/784/1238 5139/785/939 5142/786/940 +f 5142/786/940 5146/787/940 5145/784/1238 +f 5147/788/941 5143/789/941 5139/785/939 +f 5139/785/939 5145/784/1238 5147/788/941 +f 5148/790/1000 5145/791/943 5146/792/944 +f 5146/792/944 5149/793/944 5148/790/1000 +f 5150/794/945 5147/795/945 5145/791/943 +f 5145/791/943 5148/790/1000 5150/794/945 +f 5140/785/946 5148/796/947 5149/787/948 +f 5149/787/948 5141/797/948 5140/785/946 +f 5144/789/949 5150/798/1239 5148/796/947 +f 5148/796/947 5140/785/946 5144/789/949 +f 5151/799/37 5152/800/37 5153/801/37 +f 5153/801/37 5154/802/37 5151/799/37 +f 5155/803/996 5156/804/997 5157/805/952 +f 5157/805/952 5158/806/952 5155/803/996 +f 5154/807/953 5153/808/953 5156/804/997 +f 5156/804/997 5155/803/996 5154/807/953 +f 5159/809/954 5155/810/954 5158/811/955 +f 5158/811/955 5160/812/955 5159/809/954 +f 5151/813/1240 5154/814/1240 5155/810/954 +f 5155/810/954 5159/809/954 5151/813/1240 +f 5161/804/957 5159/803/958 5160/806/959 +f 5160/806/959 5162/805/959 5161/804/957 +f 5152/808/960 5151/807/960 5159/803/958 +f 5159/803/958 5161/804/957 5152/808/960 +f 5156/815/1241 5161/809/1241 5162/816/962 +f 5162/816/962 5157/817/962 5156/815/1241 +f 5153/818/1242 5152/819/963 5161/809/1241 +f 5161/809/1241 5156/815/1241 5153/818/1242 +f 5163/820/37 5164/821/37 5165/822/37 +f 5165/822/37 5166/823/37 5163/820/37 +f 5167/824/998 5168/825/999 5169/826/966 +f 5169/826/966 5170/827/966 5167/824/998 +f 5166/828/967 5165/829/967 5168/825/999 +f 5168/825/999 5167/824/998 5166/828/967 +f 5171/737/968 5167/738/969 5170/734/970 +f 5170/734/970 5172/740/970 5171/737/968 +f 5163/741/1243 5166/735/1243 5167/738/969 +f 5167/738/969 5171/737/968 5163/741/1243 +f 5173/825/972 5171/824/972 5172/827/973 +f 5172/827/973 5174/826/973 5173/825/972 +f 5164/829/974 5163/828/974 5171/824/972 +f 5171/824/972 5173/825/972 5164/829/974 +f 5168/731/975 5173/737/976 5174/733/1244 +f 5174/733/1244 5169/830/1244 5168/731/975 +f 5165/831/1245 5164/736/1245 5173/737/976 +f 5173/737/976 5168/731/975 5165/831/1245 +f 5175/832/36 5176/833/36 5177/834/36 +f 5177/834/36 5178/835/36 5175/832/36 +f 5179/836/979 5180/837/979 5181/838/980 +f 5181/838/980 5182/839/980 5179/836/979 +f 5178/840/981 5177/841/981 5180/837/979 +f 5180/837/979 5179/836/979 5178/840/981 +f 5183/737/1246 5179/731/1246 5182/734/983 +f 5182/734/983 5184/733/983 5183/737/1246 +f 5175/741/985 5178/735/985 5179/731/1246 +f 5179/731/1246 5183/737/1246 5175/741/985 +f 5185/837/986 5183/836/986 5184/839/987 +f 5184/839/987 5186/838/987 5185/837/986 +f 5176/841/988 5175/840/988 5183/836/986 +f 5183/836/986 5185/837/986 5176/841/988 +f 5180/842/1247 5185/732/1247 5186/843/990 +f 5186/843/990 5181/734/990 5180/842/1247 +f 5177/831/991 5176/736/991 5185/732/1247 +f 5185/732/1247 5180/842/1247 5177/831/991 +f 5187/721/36 5188/722/36 5189/723/36 +f 5189/723/36 5190/724/36 5187/721/36 +f 5191/725/888 5192/726/888 5193/727/889 +f 5193/727/889 5194/728/889 5191/725/888 +f 5190/729/890 5189/730/890 5192/726/888 +f 5192/726/888 5191/725/888 5190/729/890 +f 5195/731/891 5191/732/892 5194/733/893 +f 5194/733/893 5196/734/893 5195/731/891 +f 5187/735/895 5190/736/895 5191/732/892 +f 5191/732/892 5195/731/891 5187/735/895 +f 5197/726/896 5195/725/896 5196/728/897 +f 5196/728/897 5198/727/897 5197/726/896 +f 5188/730/898 5187/729/898 5195/725/896 +f 5195/725/896 5197/726/896 5188/730/898 +f 5192/737/899 5197/738/899 5198/739/900 +f 5198/739/900 5193/740/900 5192/737/899 +f 5189/741/901 5188/742/1232 5197/738/899 +f 5197/738/899 5192/737/899 5189/741/901 +f 5199/743/226 5200/744/226 5201/745/226 +f 5201/745/226 5202/746/226 5199/743/226 +f 5203/747/902 5204/748/995 5205/749/903 +f 5205/749/903 5206/750/903 5203/747/902 +f 5202/751/904 5201/752/904 5204/748/995 +f 5204/748/995 5203/747/902 5202/751/904 +f 5207/753/905 5203/754/1233 5206/755/907 +f 5206/755/907 5208/756/907 5207/753/905 +f 5199/757/1234 5202/758/1234 5203/754/1233 +f 5203/754/1233 5207/753/905 5199/757/1234 +f 5209/748/910 5207/747/911 5208/750/912 +f 5208/750/912 5210/749/912 5209/748/910 +f 5200/752/913 5199/751/913 5207/747/911 +f 5207/747/911 5209/748/910 5200/752/913 +f 5204/754/914 5209/759/1235 5210/760/916 +f 5210/760/916 5205/755/916 5204/754/914 +f 5201/758/917 5200/761/917 5209/759/1235 +f 5209/759/1235 5204/754/914 5201/758/917 +f 5211/762/918 5212/763/919 5213/764/920 +f 5213/764/920 5214/765/920 5211/762/918 +f 5215/766/921 5216/767/921 5212/763/919 +f 5212/763/919 5211/762/918 5215/766/921 +f 5217/768/1236 5211/769/923 5214/770/924 +f 5214/770/924 5218/771/924 5217/768/1236 +f 5219/772/925 5215/773/925 5211/769/923 +f 5211/769/923 5217/768/1236 5219/772/925 +f 5220/763/926 5217/762/927 5218/765/928 +f 5218/765/928 5221/764/928 5220/763/926 +f 5222/767/929 5219/766/929 5217/762/927 +f 5217/762/927 5220/763/926 5222/767/929 +f 5212/774/1237 5220/768/578 5221/771/932 +f 5221/771/932 5213/775/932 5212/774/1237 +f 5216/776/933 5222/777/933 5220/768/578 +f 5220/768/578 5212/774/1237 5216/776/933 +f 5223/778/934 5224/779/935 5225/780/936 +f 5225/780/936 5226/781/936 5223/778/934 +f 5227/782/937 5228/783/937 5224/779/935 +f 5224/779/935 5223/778/934 5227/782/937 +f 5229/784/1238 5223/785/939 5226/786/940 +f 5226/786/940 5230/787/940 5229/784/1238 +f 5231/788/941 5227/789/941 5223/785/939 +f 5223/785/939 5229/784/1238 5231/788/941 +f 5232/790/1000 5229/791/943 5230/792/944 +f 5230/792/944 5233/793/944 5232/790/1000 +f 5234/794/945 5231/795/945 5229/791/943 +f 5229/791/943 5232/790/1000 5234/794/945 +f 5224/785/946 5232/796/947 5233/787/948 +f 5233/787/948 5225/797/948 5224/785/946 +f 5228/789/949 5234/798/1239 5232/796/947 +f 5232/796/947 5224/785/946 5228/789/949 +f 5235/799/36 5236/800/36 5237/801/36 +f 5237/801/36 5238/802/36 5235/799/36 +f 5239/803/950 5240/804/951 5241/805/952 +f 5241/805/952 5242/806/952 5239/803/950 +f 5238/807/953 5237/808/953 5240/804/951 +f 5240/804/951 5239/803/950 5238/807/953 +f 5243/809/954 5239/810/954 5242/811/955 +f 5242/811/955 5244/812/955 5243/809/954 +f 5235/813/1240 5238/814/1240 5239/810/954 +f 5239/810/954 5243/809/954 5235/813/1240 +f 5245/804/957 5243/803/958 5244/806/959 +f 5244/806/959 5246/805/959 5245/804/957 +f 5236/808/960 5235/807/960 5243/803/958 +f 5243/803/958 5245/804/957 5236/808/960 +f 5240/815/1241 5245/809/1241 5246/816/962 +f 5246/816/962 5241/817/962 5240/815/1241 +f 5237/818/1242 5236/819/963 5245/809/1241 +f 5245/809/1241 5240/815/1241 5237/818/1242 +f 5247/820/36 5248/821/36 5249/822/36 +f 5249/822/36 5250/823/36 5247/820/36 +f 5251/824/998 5252/825/999 5253/826/966 +f 5253/826/966 5254/827/966 5251/824/998 +f 5250/828/967 5249/829/967 5252/825/999 +f 5252/825/999 5251/824/998 5250/828/967 +f 5255/737/968 5251/738/969 5254/734/970 +f 5254/734/970 5256/740/970 5255/737/968 +f 5247/741/1243 5250/735/1243 5251/738/969 +f 5251/738/969 5255/737/968 5247/741/1243 +f 5257/825/972 5255/824/972 5256/827/973 +f 5256/827/973 5258/826/973 5257/825/972 +f 5248/829/974 5247/828/974 5255/824/972 +f 5255/824/972 5257/825/972 5248/829/974 +f 5252/731/975 5257/737/976 5258/733/1244 +f 5258/733/1244 5253/830/1244 5252/731/975 +f 5249/831/1245 5248/736/1245 5257/737/976 +f 5257/737/976 5252/731/975 5249/831/1245 +f 5259/832/36 5260/833/36 5261/834/36 +f 5261/834/36 5262/835/36 5259/832/36 +f 5263/836/979 5264/837/979 5265/838/980 +f 5265/838/980 5266/839/980 5263/836/979 +f 5262/840/981 5261/841/981 5264/837/979 +f 5264/837/979 5263/836/979 5262/840/981 +f 5267/737/1246 5263/731/1246 5266/734/983 +f 5266/734/983 5268/733/983 5267/737/1246 +f 5259/741/985 5262/735/985 5263/731/1246 +f 5263/731/1246 5267/737/1246 5259/741/985 +f 5269/837/1001 5267/836/1001 5268/839/987 +f 5268/839/987 5270/838/987 5269/837/1001 +f 5260/841/988 5259/840/988 5267/836/1001 +f 5267/836/1001 5269/837/1001 5260/841/988 +f 5264/842/1247 5269/732/1247 5270/843/990 +f 5270/843/990 5265/734/990 5264/842/1247 +f 5261/831/991 5260/736/991 5269/732/1247 +f 5269/732/1247 5264/842/1247 5261/831/991 +f 5271/721/36 5272/722/36 5273/723/36 +f 5273/723/36 5274/724/36 5271/721/36 +f 5275/725/888 5276/726/888 5277/727/889 +f 5277/727/889 5278/728/889 5275/725/888 +f 5274/729/890 5273/730/890 5276/726/888 +f 5276/726/888 5275/725/888 5274/729/890 +f 5279/731/891 5275/732/892 5278/733/893 +f 5278/733/893 5280/734/893 5279/731/891 +f 5271/735/895 5274/736/895 5275/732/892 +f 5275/732/892 5279/731/891 5271/735/895 +f 5281/726/896 5279/725/896 5280/728/897 +f 5280/728/897 5282/727/897 5281/726/896 +f 5272/730/898 5271/729/898 5279/725/896 +f 5279/725/896 5281/726/896 5272/730/898 +f 5276/737/899 5281/738/899 5282/739/900 +f 5282/739/900 5277/740/900 5276/737/899 +f 5273/741/901 5272/742/1232 5281/738/899 +f 5281/738/899 5276/737/899 5273/741/901 +f 5283/743/36 5284/744/36 5285/745/36 +f 5285/745/36 5286/746/36 5283/743/36 +f 5287/747/902 5288/748/995 5289/749/903 +f 5289/749/903 5290/750/903 5287/747/902 +f 5286/751/904 5285/752/904 5288/748/995 +f 5288/748/995 5287/747/902 5286/751/904 +f 5291/753/905 5287/754/1233 5290/755/907 +f 5290/755/907 5292/756/907 5291/753/905 +f 5283/757/1234 5286/758/1234 5287/754/1233 +f 5287/754/1233 5291/753/905 5283/757/1234 +f 5293/748/910 5291/747/911 5292/750/912 +f 5292/750/912 5294/749/912 5293/748/910 +f 5284/752/913 5283/751/913 5291/747/911 +f 5291/747/911 5293/748/910 5284/752/913 +f 5288/754/914 5293/759/1235 5294/760/916 +f 5294/760/916 5289/755/916 5288/754/914 +f 5285/758/917 5284/761/917 5293/759/1235 +f 5293/759/1235 5288/754/914 5285/758/917 +f 5295/762/918 5296/763/919 5297/764/920 +f 5297/764/920 5298/765/920 5295/762/918 +f 5299/766/921 5300/767/921 5296/763/919 +f 5296/763/919 5295/762/918 5299/766/921 +f 5301/768/1236 5295/769/923 5298/770/924 +f 5298/770/924 5302/771/924 5301/768/1236 +f 5303/772/925 5299/773/925 5295/769/923 +f 5295/769/923 5301/768/1236 5303/772/925 +f 5304/763/926 5301/762/927 5302/765/928 +f 5302/765/928 5305/764/928 5304/763/926 +f 5306/767/929 5303/766/929 5301/762/927 +f 5301/762/927 5304/763/926 5306/767/929 +f 5296/774/1237 5304/768/578 5305/771/932 +f 5305/771/932 5297/775/932 5296/774/1237 +f 5300/776/933 5306/777/933 5304/768/578 +f 5304/768/578 5296/774/1237 5300/776/933 +f 5307/778/934 5308/779/935 5309/780/936 +f 5309/780/936 5310/781/936 5307/778/934 +f 5311/782/937 5312/783/937 5308/779/935 +f 5308/779/935 5307/778/934 5311/782/937 +f 5313/784/1238 5307/785/939 5310/786/940 +f 5310/786/940 5314/787/940 5313/784/1238 +f 5315/788/941 5311/789/941 5307/785/939 +f 5307/785/939 5313/784/1238 5315/788/941 +f 5316/790/1000 5313/791/943 5314/792/944 +f 5314/792/944 5317/793/944 5316/790/1000 +f 5318/794/945 5315/795/945 5313/791/943 +f 5313/791/943 5316/790/1000 5318/794/945 +f 5308/785/946 5316/796/947 5317/787/948 +f 5317/787/948 5309/797/948 5308/785/946 +f 5312/789/949 5318/798/1239 5316/796/947 +f 5316/796/947 5308/785/946 5312/789/949 +f 5319/799/226 5320/800/226 5321/801/226 +f 5321/801/226 5322/802/226 5319/799/226 +f 5323/803/996 5324/804/997 5325/805/952 +f 5325/805/952 5326/806/952 5323/803/996 +f 5322/807/953 5321/808/953 5324/804/997 +f 5324/804/997 5323/803/996 5322/807/953 +f 5327/809/954 5323/810/954 5326/811/955 +f 5326/811/955 5328/812/955 5327/809/954 +f 5319/813/1240 5322/814/1240 5323/810/954 +f 5323/810/954 5327/809/954 5319/813/1240 +f 5329/804/957 5327/803/958 5328/806/959 +f 5328/806/959 5330/805/959 5329/804/957 +f 5320/808/960 5319/807/960 5327/803/958 +f 5327/803/958 5329/804/957 5320/808/960 +f 5324/815/1241 5329/809/1241 5330/816/962 +f 5330/816/962 5325/817/962 5324/815/1241 +f 5321/818/1242 5320/819/963 5329/809/1241 +f 5329/809/1241 5324/815/1241 5321/818/1242 +f 5331/820/36 5332/821/36 5333/822/36 +f 5333/822/36 5334/823/36 5331/820/36 +f 5335/824/998 5336/825/999 5337/826/966 +f 5337/826/966 5338/827/966 5335/824/998 +f 5334/828/967 5333/829/967 5336/825/999 +f 5336/825/999 5335/824/998 5334/828/967 +f 5339/737/968 5335/738/969 5338/734/970 +f 5338/734/970 5340/740/970 5339/737/968 +f 5331/741/1243 5334/735/1243 5335/738/969 +f 5335/738/969 5339/737/968 5331/741/1243 +f 5341/825/972 5339/824/972 5340/827/973 +f 5340/827/973 5342/826/973 5341/825/972 +f 5332/829/974 5331/828/974 5339/824/972 +f 5339/824/972 5341/825/972 5332/829/974 +f 5336/731/975 5341/737/976 5342/733/1244 +f 5342/733/1244 5337/830/1244 5336/731/975 +f 5333/831/1245 5332/736/1245 5341/737/976 +f 5341/737/976 5336/731/975 5333/831/1245 +f 5343/832/36 5344/833/36 5345/834/36 +f 5345/834/36 5346/835/36 5343/832/36 +f 5347/836/979 5348/837/979 5349/838/980 +f 5349/838/980 5350/839/980 5347/836/979 +f 5346/840/981 5345/841/981 5348/837/979 +f 5348/837/979 5347/836/979 5346/840/981 +f 5351/737/1246 5347/731/1246 5350/734/983 +f 5350/734/983 5352/733/983 5351/737/1246 +f 5343/741/985 5346/735/985 5347/731/1246 +f 5347/731/1246 5351/737/1246 5343/741/985 +f 5353/837/1001 5351/836/1001 5352/839/987 +f 5352/839/987 5354/838/987 5353/837/1001 +f 5344/841/988 5343/840/988 5351/836/1001 +f 5351/836/1001 5353/837/1001 5344/841/988 +f 5348/842/1247 5353/732/1247 5354/843/990 +f 5354/843/990 5349/734/990 5348/842/1247 +f 5345/831/991 5344/736/991 5353/732/1247 +f 5353/732/1247 5348/842/1247 5345/831/991 +f 5355/721/37 5356/722/37 5357/723/37 +f 5357/723/37 5358/724/37 5355/721/37 +f 5359/725/888 5360/726/888 5361/727/889 +f 5361/727/889 5362/728/889 5359/725/888 +f 5358/729/890 5357/730/890 5360/726/888 +f 5360/726/888 5359/725/888 5358/729/890 +f 5363/731/891 5359/732/892 5362/733/893 +f 5362/733/893 5364/734/893 5363/731/891 +f 5355/735/895 5358/736/895 5359/732/892 +f 5359/732/892 5363/731/891 5355/735/895 +f 5365/726/896 5363/725/896 5364/728/897 +f 5364/728/897 5366/727/897 5365/726/896 +f 5356/730/898 5355/729/898 5363/725/896 +f 5363/725/896 5365/726/896 5356/730/898 +f 5360/737/899 5365/738/899 5366/739/900 +f 5366/739/900 5361/740/900 5360/737/899 +f 5357/741/901 5356/742/1232 5365/738/899 +f 5365/738/899 5360/737/899 5357/741/901 +f 5367/743/36 5368/744/36 5369/745/36 +f 5369/745/36 5370/746/36 5367/743/36 +f 5371/747/902 5372/748/995 5373/749/903 +f 5373/749/903 5374/750/903 5371/747/902 +f 5370/751/904 5369/752/904 5372/748/995 +f 5372/748/995 5371/747/902 5370/751/904 +f 5375/753/905 5371/754/1233 5374/755/907 +f 5374/755/907 5376/756/907 5375/753/905 +f 5367/757/1234 5370/758/1234 5371/754/1233 +f 5371/754/1233 5375/753/905 5367/757/1234 +f 5377/748/910 5375/747/911 5376/750/912 +f 5376/750/912 5378/749/912 5377/748/910 +f 5368/752/913 5367/751/913 5375/747/911 +f 5375/747/911 5377/748/910 5368/752/913 +f 5372/754/914 5377/759/1235 5378/760/916 +f 5378/760/916 5373/755/916 5372/754/914 +f 5369/758/917 5368/761/917 5377/759/1235 +f 5377/759/1235 5372/754/914 5369/758/917 +f 5379/762/918 5380/763/919 5381/764/920 +f 5381/764/920 5382/765/920 5379/762/918 +f 5383/766/921 5384/767/921 5380/763/919 +f 5380/763/919 5379/762/918 5383/766/921 +f 5385/768/1236 5379/769/923 5382/770/924 +f 5382/770/924 5386/771/924 5385/768/1236 +f 5387/772/925 5383/773/925 5379/769/923 +f 5379/769/923 5385/768/1236 5387/772/925 +f 5388/763/926 5385/762/927 5386/765/928 +f 5386/765/928 5389/764/928 5388/763/926 +f 5390/767/929 5387/766/929 5385/762/927 +f 5385/762/927 5388/763/926 5390/767/929 +f 5380/774/1237 5388/768/578 5389/771/932 +f 5389/771/932 5381/775/932 5380/774/1237 +f 5384/776/933 5390/777/933 5388/768/578 +f 5388/768/578 5380/774/1237 5384/776/933 +f 5391/778/934 5392/779/935 5393/780/936 +f 5393/780/936 5394/781/936 5391/778/934 +f 5395/782/937 5396/783/937 5392/779/935 +f 5392/779/935 5391/778/934 5395/782/937 +f 5397/784/1238 5391/785/939 5394/786/940 +f 5394/786/940 5398/787/940 5397/784/1238 +f 5399/788/941 5395/789/941 5391/785/939 +f 5391/785/939 5397/784/1238 5399/788/941 +f 5400/790/1000 5397/791/943 5398/792/944 +f 5398/792/944 5401/793/944 5400/790/1000 +f 5402/794/945 5399/795/945 5397/791/943 +f 5397/791/943 5400/790/1000 5402/794/945 +f 5392/785/946 5400/796/947 5401/787/948 +f 5401/787/948 5393/797/948 5392/785/946 +f 5396/789/949 5402/798/1239 5400/796/947 +f 5400/796/947 5392/785/946 5396/789/949 +f 5403/799/36 5404/800/36 5405/801/36 +f 5405/801/36 5406/802/36 5403/799/36 +f 5407/803/996 5408/804/997 5409/805/952 +f 5409/805/952 5410/806/952 5407/803/996 +f 5406/807/953 5405/808/953 5408/804/997 +f 5408/804/997 5407/803/996 5406/807/953 +f 5411/809/954 5407/810/954 5410/811/955 +f 5410/811/955 5412/812/955 5411/809/954 +f 5403/813/1240 5406/814/1240 5407/810/954 +f 5407/810/954 5411/809/954 5403/813/1240 +f 5413/804/957 5411/803/958 5412/806/959 +f 5412/806/959 5414/805/959 5413/804/957 +f 5404/808/960 5403/807/960 5411/803/958 +f 5411/803/958 5413/804/957 5404/808/960 +f 5408/815/1241 5413/809/1241 5414/816/962 +f 5414/816/962 5409/817/962 5408/815/1241 +f 5405/818/1242 5404/819/963 5413/809/1241 +f 5413/809/1241 5408/815/1241 5405/818/1242 +f 5415/820/36 5416/821/36 5417/822/36 +f 5417/822/36 5418/823/36 5415/820/36 +f 5419/824/998 5420/825/999 5421/826/966 +f 5421/826/966 5422/827/966 5419/824/998 +f 5418/828/967 5417/829/967 5420/825/999 +f 5420/825/999 5419/824/998 5418/828/967 +f 5423/737/968 5419/738/969 5422/734/970 +f 5422/734/970 5424/740/970 5423/737/968 +f 5415/741/1243 5418/735/1243 5419/738/969 +f 5419/738/969 5423/737/968 5415/741/1243 +f 5425/825/972 5423/824/972 5424/827/973 +f 5424/827/973 5426/826/973 5425/825/972 +f 5416/829/974 5415/828/974 5423/824/972 +f 5423/824/972 5425/825/972 5416/829/974 +f 5420/731/975 5425/737/976 5426/733/1244 +f 5426/733/1244 5421/830/1244 5420/731/975 +f 5417/831/1245 5416/736/1245 5425/737/976 +f 5425/737/976 5420/731/975 5417/831/1245 +f 5427/832/36 5428/833/36 5429/834/36 +f 5429/834/36 5430/835/36 5427/832/36 +f 5431/836/993 5432/837/979 5433/838/994 +f 5433/838/994 5434/839/994 5431/836/993 +f 5430/840/981 5429/841/981 5432/837/979 +f 5432/837/979 5431/836/993 5430/840/981 +f 5435/737/1246 5431/731/1246 5434/734/983 +f 5434/734/983 5436/733/983 5435/737/1246 +f 5427/741/985 5430/735/985 5431/731/1246 +f 5431/731/1246 5435/737/1246 5427/741/985 +f 5437/837/1001 5435/836/1001 5436/839/987 +f 5436/839/987 5438/838/987 5437/837/1001 +f 5428/841/988 5427/840/988 5435/836/1001 +f 5435/836/1001 5437/837/1001 5428/841/988 +f 5432/842/1247 5437/732/1247 5438/843/990 +f 5438/843/990 5433/734/990 5432/842/1247 +f 5429/831/991 5428/736/991 5437/732/1247 +f 5437/732/1247 5432/842/1247 5429/831/991 +f 5439/721/36 5440/722/36 5441/723/36 +f 5441/723/36 5442/724/36 5439/721/36 +f 5443/725/888 5444/726/888 5445/727/889 +f 5445/727/889 5446/728/889 5443/725/888 +f 5442/729/890 5441/730/890 5444/726/888 +f 5444/726/888 5443/725/888 5442/729/890 +f 5447/731/891 5443/732/892 5446/733/893 +f 5446/733/893 5448/734/893 5447/731/891 +f 5439/735/895 5442/736/895 5443/732/892 +f 5443/732/892 5447/731/891 5439/735/895 +f 5449/726/896 5447/725/896 5448/728/897 +f 5448/728/897 5450/727/897 5449/726/896 +f 5440/730/898 5439/729/898 5447/725/896 +f 5447/725/896 5449/726/896 5440/730/898 +f 5444/737/899 5449/738/899 5450/739/900 +f 5450/739/900 5445/740/900 5444/737/899 +f 5441/741/901 5440/742/1232 5449/738/899 +f 5449/738/899 5444/737/899 5441/741/901 +f 5451/743/36 5452/744/36 5453/745/36 +f 5453/745/36 5454/746/36 5451/743/36 +f 5455/747/902 5456/748/995 5457/749/903 +f 5457/749/903 5458/750/903 5455/747/902 +f 5454/751/904 5453/752/904 5456/748/995 +f 5456/748/995 5455/747/902 5454/751/904 +f 5459/753/905 5455/754/1233 5458/755/907 +f 5458/755/907 5460/756/907 5459/753/905 +f 5451/757/1234 5454/758/1234 5455/754/1233 +f 5455/754/1233 5459/753/905 5451/757/1234 +f 5461/748/910 5459/747/911 5460/750/912 +f 5460/750/912 5462/749/912 5461/748/910 +f 5452/752/913 5451/751/913 5459/747/911 +f 5459/747/911 5461/748/910 5452/752/913 +f 5456/754/914 5461/759/1235 5462/760/916 +f 5462/760/916 5457/755/916 5456/754/914 +f 5453/758/917 5452/761/917 5461/759/1235 +f 5461/759/1235 5456/754/914 5453/758/917 +f 5463/762/918 5464/763/919 5465/764/920 +f 5465/764/920 5466/765/920 5463/762/918 +f 5467/766/921 5468/767/921 5464/763/919 +f 5464/763/919 5463/762/918 5467/766/921 +f 5469/768/1236 5463/769/923 5466/770/924 +f 5466/770/924 5470/771/924 5469/768/1236 +f 5471/772/925 5467/773/925 5463/769/923 +f 5463/769/923 5469/768/1236 5471/772/925 +f 5472/763/926 5469/762/927 5470/765/928 +f 5470/765/928 5473/764/928 5472/763/926 +f 5474/767/929 5471/766/929 5469/762/927 +f 5469/762/927 5472/763/926 5474/767/929 +f 5464/774/1237 5472/768/578 5473/771/932 +f 5473/771/932 5465/775/932 5464/774/1237 +f 5468/776/933 5474/777/933 5472/768/578 +f 5472/768/578 5464/774/1237 5468/776/933 +f 5475/778/934 5476/779/935 5477/780/936 +f 5477/780/936 5478/781/936 5475/778/934 +f 5479/782/937 5480/783/937 5476/779/935 +f 5476/779/935 5475/778/934 5479/782/937 +f 5481/784/1238 5475/785/939 5478/786/940 +f 5478/786/940 5482/787/940 5481/784/1238 +f 5483/788/941 5479/789/941 5475/785/939 +f 5475/785/939 5481/784/1238 5483/788/941 +f 5484/790/1000 5481/791/943 5482/792/944 +f 5482/792/944 5485/793/944 5484/790/1000 +f 5486/794/945 5483/795/945 5481/791/943 +f 5481/791/943 5484/790/1000 5486/794/945 +f 5476/785/946 5484/796/947 5485/787/948 +f 5485/787/948 5477/797/948 5476/785/946 +f 5480/789/949 5486/798/1239 5484/796/947 +f 5484/796/947 5476/785/946 5480/789/949 +f 5487/799/226 5488/800/226 5489/801/226 +f 5489/801/226 5490/802/226 5487/799/226 +f 5491/803/996 5492/804/997 5493/805/952 +f 5493/805/952 5494/806/952 5491/803/996 +f 5490/807/953 5489/808/953 5492/804/997 +f 5492/804/997 5491/803/996 5490/807/953 +f 5495/809/954 5491/810/954 5494/811/955 +f 5494/811/955 5496/812/955 5495/809/954 +f 5487/813/1240 5490/814/1240 5491/810/954 +f 5491/810/954 5495/809/954 5487/813/1240 +f 5497/804/957 5495/803/958 5496/806/959 +f 5496/806/959 5498/805/959 5497/804/957 +f 5488/808/960 5487/807/960 5495/803/958 +f 5495/803/958 5497/804/957 5488/808/960 +f 5492/815/1241 5497/809/1241 5498/816/962 +f 5498/816/962 5493/817/962 5492/815/1241 +f 5489/818/1242 5488/819/963 5497/809/1241 +f 5497/809/1241 5492/815/1241 5489/818/1242 +f 5499/820/36 5500/821/36 5501/822/36 +f 5501/822/36 5502/823/36 5499/820/36 +f 5503/824/998 5504/825/999 5505/826/966 +f 5505/826/966 5506/827/966 5503/824/998 +f 5502/828/967 5501/829/967 5504/825/999 +f 5504/825/999 5503/824/998 5502/828/967 +f 5507/737/968 5503/738/969 5506/734/970 +f 5506/734/970 5508/740/970 5507/737/968 +f 5499/741/1243 5502/735/1243 5503/738/969 +f 5503/738/969 5507/737/968 5499/741/1243 +f 5509/825/972 5507/824/972 5508/827/973 +f 5508/827/973 5510/826/973 5509/825/972 +f 5500/829/974 5499/828/974 5507/824/972 +f 5507/824/972 5509/825/972 5500/829/974 +f 5504/731/975 5509/737/976 5510/733/1244 +f 5510/733/1244 5505/830/1244 5504/731/975 +f 5501/831/1245 5500/736/1245 5509/737/976 +f 5509/737/976 5504/731/975 5501/831/1245 +f 5511/832/37 5512/833/37 5513/834/37 +f 5513/834/37 5514/835/37 5511/832/37 +f 5515/836/993 5516/837/979 5517/838/980 +f 5517/838/980 5518/839/980 5515/836/993 +f 5514/840/981 5513/841/981 5516/837/979 +f 5516/837/979 5515/836/993 5514/840/981 +f 5519/737/1246 5515/731/1246 5518/734/983 +f 5518/734/983 5520/733/983 5519/737/1246 +f 5511/741/985 5514/735/985 5515/731/1246 +f 5515/731/1246 5519/737/1246 5511/741/985 +f 5521/837/1001 5519/836/1001 5520/839/987 +f 5520/839/987 5522/838/987 5521/837/1001 +f 5512/841/988 5511/840/988 5519/836/1001 +f 5519/836/1001 5521/837/1001 5512/841/988 +f 5516/842/1247 5521/732/1247 5522/843/990 +f 5522/843/990 5517/734/990 5516/842/1247 +f 5513/831/991 5512/736/991 5521/732/1247 +f 5521/732/1247 5516/842/1247 5513/831/991 +f 5523/721/36 5524/722/36 5525/723/36 +f 5525/723/36 5526/724/36 5523/721/36 +f 5527/725/888 5528/726/888 5529/727/889 +f 5529/727/889 5530/728/889 5527/725/888 +f 5526/729/890 5525/730/890 5528/726/888 +f 5528/726/888 5527/725/888 5526/729/890 +f 5531/731/891 5527/732/892 5530/733/893 +f 5530/733/893 5532/734/893 5531/731/891 +f 5523/735/1248 5526/736/1248 5527/732/892 +f 5527/732/892 5531/731/891 5523/735/1248 +f 5533/726/896 5531/725/896 5532/728/897 +f 5532/728/897 5534/727/897 5533/726/896 +f 5524/730/898 5523/729/898 5531/725/896 +f 5531/725/896 5533/726/896 5524/730/898 +f 5528/737/899 5533/738/899 5534/739/900 +f 5534/739/900 5529/740/900 5528/737/899 +f 5525/741/901 5524/742/901 5533/738/899 +f 5533/738/899 5528/737/899 5525/741/901 +f 5535/743/36 5536/744/36 5537/745/36 +f 5537/745/36 5538/746/36 5535/743/36 +f 5539/747/995 5540/748/995 5541/749/903 +f 5541/749/903 5542/750/903 5539/747/995 +f 5538/751/904 5537/752/904 5540/748/995 +f 5540/748/995 5539/747/995 5538/751/904 +f 5543/753/905 5539/754/906 5542/755/907 +f 5542/755/907 5544/756/907 5543/753/905 +f 5535/757/1234 5538/758/1234 5539/754/906 +f 5539/754/906 5543/753/905 5535/757/1234 +f 5545/748/910 5543/747/911 5544/750/912 +f 5544/750/912 5546/749/912 5545/748/910 +f 5536/752/913 5535/751/913 5543/747/911 +f 5543/747/911 5545/748/910 5536/752/913 +f 5540/754/914 5545/759/1235 5546/760/916 +f 5546/760/916 5541/755/1249 5540/754/914 +f 5537/758/917 5536/761/917 5545/759/1235 +f 5545/759/1235 5540/754/914 5537/758/917 +f 5547/762/918 5548/763/919 5549/764/920 +f 5549/764/920 5550/765/920 5547/762/918 +f 5551/766/921 5552/767/921 5548/763/919 +f 5548/763/919 5547/762/918 5551/766/921 +f 5553/768/922 5547/769/923 5550/770/924 +f 5550/770/924 5554/771/924 5553/768/922 +f 5555/772/925 5551/773/925 5547/769/923 +f 5547/769/923 5553/768/922 5555/772/925 +f 5556/763/926 5553/762/927 5554/765/928 +f 5554/765/928 5557/764/928 5556/763/926 +f 5558/767/929 5555/766/929 5553/762/927 +f 5553/762/927 5556/763/926 5558/767/929 +f 5548/774/1237 5556/768/578 5557/771/932 +f 5557/771/932 5549/775/932 5548/774/1237 +f 5552/776/933 5558/777/933 5556/768/578 +f 5556/768/578 5548/774/1237 5552/776/933 +f 5559/778/934 5560/779/935 5561/780/936 +f 5561/780/936 5562/781/936 5559/778/934 +f 5563/782/937 5564/783/937 5560/779/935 +f 5560/779/935 5559/778/934 5563/782/937 +f 5565/784/1238 5559/785/939 5562/786/940 +f 5562/786/940 5566/787/940 5565/784/1238 +f 5567/788/941 5563/789/941 5559/785/939 +f 5559/785/939 5565/784/1238 5567/788/941 +f 5568/790/942 5565/791/943 5566/792/944 +f 5566/792/944 5569/793/944 5568/790/942 +f 5570/794/945 5567/795/945 5565/791/943 +f 5565/791/943 5568/790/942 5570/794/945 +f 5560/785/946 5568/796/947 5569/787/948 +f 5569/787/948 5561/797/948 5560/785/946 +f 5564/789/949 5570/798/949 5568/796/947 +f 5568/796/947 5560/785/946 5564/789/949 +f 5571/799/36 5572/800/36 5573/801/36 +f 5573/801/36 5574/802/36 5571/799/36 +f 5575/803/950 5576/804/951 5577/805/952 +f 5577/805/952 5578/806/952 5575/803/950 +f 5574/807/953 5573/808/953 5576/804/951 +f 5576/804/951 5575/803/950 5574/807/953 +f 5579/809/954 5575/810/954 5578/811/1250 +f 5578/811/1250 5580/812/1250 5579/809/954 +f 5571/813/1240 5574/814/1240 5575/810/954 +f 5575/810/954 5579/809/954 5571/813/1240 +f 5581/804/957 5579/803/958 5580/806/959 +f 5580/806/959 5582/805/959 5581/804/957 +f 5572/808/960 5571/807/960 5579/803/958 +f 5579/803/958 5581/804/957 5572/808/960 +f 5576/815/1241 5581/809/1241 5582/816/962 +f 5582/816/962 5577/817/962 5576/815/1241 +f 5573/818/1242 5572/819/963 5581/809/1241 +f 5581/809/1241 5576/815/1241 5573/818/1242 +f 5583/820/36 5584/821/36 5585/822/36 +f 5585/822/36 5586/823/36 5583/820/36 +f 5587/824/964 5588/825/965 5589/826/966 +f 5589/826/966 5590/827/966 5587/824/964 +f 5586/828/992 5585/829/967 5588/825/965 +f 5588/825/965 5587/824/964 5586/828/992 +f 5591/737/968 5587/738/969 5590/734/970 +f 5590/734/970 5592/740/970 5591/737/968 +f 5583/741/1243 5586/735/1243 5587/738/969 +f 5587/738/969 5591/737/968 5583/741/1243 +f 5593/825/972 5591/824/972 5592/827/973 +f 5592/827/973 5594/826/973 5593/825/972 +f 5584/829/974 5583/828/974 5591/824/972 +f 5591/824/972 5593/825/972 5584/829/974 +f 5588/731/1251 5593/737/976 5594/733/1244 +f 5594/733/1244 5589/830/977 5588/731/1251 +f 5585/831/1245 5584/736/1245 5593/737/976 +f 5593/737/976 5588/731/1251 5585/831/1245 +f 5595/832/36 5596/833/36 5597/834/36 +f 5597/834/36 5598/835/36 5595/832/36 +f 5599/836/993 5600/837/993 5601/838/980 +f 5601/838/980 5602/839/980 5599/836/993 +f 5598/840/981 5597/841/981 5600/837/993 +f 5600/837/993 5599/836/993 5598/840/981 +f 5603/737/982 5599/731/982 5602/734/983 +f 5602/734/983 5604/733/983 5603/737/982 +f 5595/741/985 5598/735/985 5599/731/982 +f 5599/731/982 5603/737/982 5595/741/985 +f 5605/837/986 5603/836/986 5604/839/987 +f 5604/839/987 5606/838/987 5605/837/986 +f 5596/841/988 5595/840/988 5603/836/986 +f 5603/836/986 5605/837/986 5596/841/988 +f 5600/842/989 5605/732/989 5606/843/990 +f 5606/843/990 5601/734/990 5600/842/989 +f 5597/831/1223 5596/736/1223 5605/732/989 +f 5605/732/989 5600/842/989 5597/831/1223 +f 5607/721/226 5608/722/226 5609/723/226 +f 5609/723/226 5610/724/226 5607/721/226 +f 5611/725/888 5612/726/888 5613/727/889 +f 5613/727/889 5614/728/889 5611/725/888 +f 5610/729/890 5609/730/890 5612/726/888 +f 5612/726/888 5611/725/888 5610/729/890 +f 5615/731/891 5611/732/892 5614/733/893 +f 5614/733/893 5616/734/893 5615/731/891 +f 5607/735/1248 5610/736/1248 5611/732/892 +f 5611/732/892 5615/731/891 5607/735/1248 +f 5617/726/896 5615/725/896 5616/728/897 +f 5616/728/897 5618/727/897 5617/726/896 +f 5608/730/898 5607/729/898 5615/725/896 +f 5615/725/896 5617/726/896 5608/730/898 +f 5612/737/899 5617/738/899 5618/739/900 +f 5618/739/900 5613/740/900 5612/737/899 +f 5609/741/901 5608/742/901 5617/738/899 +f 5617/738/899 5612/737/899 5609/741/901 +f 5619/743/36 5620/744/36 5621/745/36 +f 5621/745/36 5622/746/36 5619/743/36 +f 5623/747/995 5624/748/995 5625/749/903 +f 5625/749/903 5626/750/903 5623/747/995 +f 5622/751/904 5621/752/904 5624/748/995 +f 5624/748/995 5623/747/995 5622/751/904 +f 5627/753/905 5623/754/906 5626/755/907 +f 5626/755/907 5628/756/907 5627/753/905 +f 5619/757/1234 5622/758/1234 5623/754/906 +f 5623/754/906 5627/753/905 5619/757/1234 +f 5629/748/910 5627/747/911 5628/750/912 +f 5628/750/912 5630/749/912 5629/748/910 +f 5620/752/913 5619/751/913 5627/747/911 +f 5627/747/911 5629/748/910 5620/752/913 +f 5624/754/914 5629/759/1235 5630/760/916 +f 5630/760/916 5625/755/1249 5624/754/914 +f 5621/758/917 5620/761/917 5629/759/1235 +f 5629/759/1235 5624/754/914 5621/758/917 +f 5631/762/918 5632/763/919 5633/764/920 +f 5633/764/920 5634/765/920 5631/762/918 +f 5635/766/921 5636/767/921 5632/763/919 +f 5632/763/919 5631/762/918 5635/766/921 +f 5637/768/922 5631/769/923 5634/770/924 +f 5634/770/924 5638/771/924 5637/768/922 +f 5639/772/925 5635/773/925 5631/769/923 +f 5631/769/923 5637/768/922 5639/772/925 +f 5640/763/926 5637/762/927 5638/765/928 +f 5638/765/928 5641/764/928 5640/763/926 +f 5642/767/929 5639/766/929 5637/762/927 +f 5637/762/927 5640/763/926 5642/767/929 +f 5632/774/1237 5640/768/578 5641/771/932 +f 5641/771/932 5633/775/932 5632/774/1237 +f 5636/776/933 5642/777/933 5640/768/578 +f 5640/768/578 5632/774/1237 5636/776/933 +f 5643/778/934 5644/779/935 5645/780/936 +f 5645/780/936 5646/781/936 5643/778/934 +f 5647/782/937 5648/783/937 5644/779/935 +f 5644/779/935 5643/778/934 5647/782/937 +f 5649/784/1238 5643/785/939 5646/786/940 +f 5646/786/940 5650/787/940 5649/784/1238 +f 5651/788/941 5647/789/941 5643/785/939 +f 5643/785/939 5649/784/1238 5651/788/941 +f 5652/790/942 5649/791/943 5650/792/944 +f 5650/792/944 5653/793/944 5652/790/942 +f 5654/794/945 5651/795/945 5649/791/943 +f 5649/791/943 5652/790/942 5654/794/945 +f 5644/785/946 5652/796/947 5653/787/948 +f 5653/787/948 5645/797/948 5644/785/946 +f 5648/789/949 5654/798/949 5652/796/947 +f 5652/796/947 5644/785/946 5648/789/949 +f 5655/799/37 5656/800/37 5657/801/37 +f 5657/801/37 5658/802/37 5655/799/37 +f 5659/803/996 5660/804/997 5661/805/952 +f 5661/805/952 5662/806/952 5659/803/996 +f 5658/807/953 5657/808/953 5660/804/997 +f 5660/804/997 5659/803/996 5658/807/953 +f 5663/809/954 5659/810/954 5662/811/1250 +f 5662/811/1250 5664/812/1250 5663/809/954 +f 5655/813/1240 5658/814/1240 5659/810/954 +f 5659/810/954 5663/809/954 5655/813/1240 +f 5665/804/957 5663/803/958 5664/806/959 +f 5664/806/959 5666/805/959 5665/804/957 +f 5656/808/960 5655/807/960 5663/803/958 +f 5663/803/958 5665/804/957 5656/808/960 +f 5660/815/1241 5665/809/1241 5666/816/962 +f 5666/816/962 5661/817/962 5660/815/1241 +f 5657/818/1242 5656/819/963 5665/809/1241 +f 5665/809/1241 5660/815/1241 5657/818/1242 +f 5667/820/36 5668/821/36 5669/822/36 +f 5669/822/36 5670/823/36 5667/820/36 +f 5671/824/964 5672/825/965 5673/826/966 +f 5673/826/966 5674/827/966 5671/824/964 +f 5670/828/992 5669/829/967 5672/825/965 +f 5672/825/965 5671/824/964 5670/828/992 +f 5675/737/968 5671/738/969 5674/734/970 +f 5674/734/970 5676/740/970 5675/737/968 +f 5667/741/1243 5670/735/1243 5671/738/969 +f 5671/738/969 5675/737/968 5667/741/1243 +f 5677/825/1002 5675/824/972 5676/827/973 +f 5676/827/973 5678/826/973 5677/825/1002 +f 5668/829/974 5667/828/974 5675/824/972 +f 5675/824/972 5677/825/1002 5668/829/974 +f 5672/731/1251 5677/737/976 5678/733/1244 +f 5678/733/1244 5673/830/977 5672/731/1251 +f 5669/831/1245 5668/736/1245 5677/737/976 +f 5677/737/976 5672/731/1251 5669/831/1245 +f 5679/832/37 5680/833/37 5681/834/37 +f 5681/834/37 5682/835/37 5679/832/37 +f 5683/836/993 5684/837/993 5685/838/980 +f 5685/838/980 5686/839/980 5683/836/993 +f 5682/840/981 5681/841/981 5684/837/993 +f 5684/837/993 5683/836/993 5682/840/981 +f 5687/737/982 5683/731/982 5686/734/983 +f 5686/734/983 5688/733/983 5687/737/982 +f 5679/741/985 5682/735/985 5683/731/982 +f 5683/731/982 5687/737/982 5679/741/985 +f 5689/837/986 5687/836/986 5688/839/987 +f 5688/839/987 5690/838/987 5689/837/986 +f 5680/841/988 5679/840/988 5687/836/986 +f 5687/836/986 5689/837/986 5680/841/988 +f 5684/842/989 5689/732/989 5690/843/990 +f 5690/843/990 5685/734/990 5684/842/989 +f 5681/831/1223 5680/736/1223 5689/732/989 +f 5689/732/989 5684/842/989 5681/831/1223 +f 5691/721/36 5692/722/36 5693/723/36 +f 5693/723/36 5694/724/36 5691/721/36 +f 5695/725/1003 5696/726/1004 5697/727/1112 +f 5697/727/1112 5698/728/1112 5695/725/1003 +f 5694/729/1006 5693/730/1006 5696/726/1004 +f 5696/726/1004 5695/725/1003 5694/729/1006 +f 5699/731/1007 5695/732/1008 5698/733/1009 +f 5698/733/1009 5700/734/1009 5699/731/1007 +f 5691/735/1010 5694/736/1010 5695/732/1008 +f 5695/732/1008 5699/731/1007 5691/735/1010 +f 5701/726/1011 5699/725/1011 5700/728/1012 +f 5700/728/1012 5702/727/1012 5701/726/1011 +f 5692/730/1013 5691/729/1013 5699/725/1011 +f 5699/725/1011 5701/726/1011 5692/730/1013 +f 5696/737/1014 5701/738/1014 5702/739/1015 +f 5702/739/1015 5697/740/1015 5696/737/1014 +f 5693/741/1016 5692/742/1016 5701/738/1014 +f 5701/738/1014 5696/737/1014 5693/741/1016 +f 5703/743/36 5704/744/36 5705/745/36 +f 5705/745/36 5706/746/36 5703/743/36 +f 5707/747/1017 5708/748/1017 5709/749/1018 +f 5709/749/1018 5710/750/1018 5707/747/1017 +f 5706/751/1019 5705/752/1019 5708/748/1017 +f 5708/748/1017 5707/747/1017 5706/751/1019 +f 5711/753/1020 5707/754/1021 5710/755/1022 +f 5710/755/1022 5712/756/1022 5711/753/1020 +f 5703/757/1023 5706/758/1023 5707/754/1021 +f 5707/754/1021 5711/753/1020 5703/757/1023 +f 5713/748/1024 5711/747/1025 5712/750/1097 +f 5712/750/1097 5714/749/1097 5713/748/1024 +f 5704/752/1028 5703/751/1028 5711/747/1025 +f 5711/747/1025 5713/748/1024 5704/752/1028 +f 5708/754/1029 5713/759/1030 5714/760/1031 +f 5714/760/1031 5709/755/1031 5708/754/1029 +f 5705/758/1032 5704/761/1032 5713/759/1030 +f 5713/759/1030 5708/754/1029 5705/758/1032 +f 5715/762/1033 5716/763/1034 5717/764/1035 +f 5717/764/1035 5718/765/1035 5715/762/1033 +f 5719/766/1036 5720/767/1036 5716/763/1034 +f 5716/763/1034 5715/762/1033 5719/766/1036 +f 5721/768/1037 5715/769/1038 5718/770/1039 +f 5718/770/1039 5722/771/1039 5721/768/1037 +f 5723/772/1040 5719/773/1040 5715/769/1038 +f 5715/769/1038 5721/768/1037 5723/772/1040 +f 5724/763/1041 5721/762/1042 5722/765/1043 +f 5722/765/1043 5725/764/1043 5724/763/1041 +f 5726/767/1044 5723/766/1044 5721/762/1042 +f 5721/762/1042 5724/763/1041 5726/767/1044 +f 5716/774/1045 5724/768/1046 5725/771/1047 +f 5725/771/1047 5717/775/1047 5716/774/1045 +f 5720/776/1048 5726/777/1048 5724/768/1046 +f 5724/768/1046 5716/774/1045 5720/776/1048 +f 5727/778/1114 5728/779/1050 5729/780/1051 +f 5729/780/1051 5730/781/1051 5727/778/1114 +f 5731/782/1052 5732/783/1052 5728/779/1050 +f 5728/779/1050 5727/778/1114 5731/782/1052 +f 5733/784/1053 5727/785/1099 5730/786/1055 +f 5730/786/1055 5734/787/1055 5733/784/1053 +f 5735/788/1056 5731/789/1056 5727/785/1099 +f 5727/785/1099 5733/784/1053 5735/788/1056 +f 5736/790/1057 5733/791/1115 5734/792/1059 +f 5734/792/1059 5737/793/1059 5736/790/1057 +f 5738/794/1060 5735/795/1060 5733/791/1115 +f 5733/791/1115 5736/790/1057 5738/794/1060 +f 5728/785/1061 5736/796/1062 5737/787/1063 +f 5737/787/1063 5729/797/1063 5728/785/1061 +f 5732/789/1064 5738/798/1064 5736/796/1062 +f 5736/796/1062 5728/785/1061 5732/789/1064 +f 5739/799/36 5740/800/36 5741/801/36 +f 5741/801/36 5742/802/36 5739/799/36 +f 5743/803/1252 5744/804/1253 5745/805/869 +f 5745/805/869 5746/806/869 5743/803/1252 +f 5742/807/870 5741/808/870 5744/804/1253 +f 5744/804/1253 5743/803/1252 5742/807/870 +f 5747/809/1065 5743/810/1065 5746/811/1254 +f 5746/811/1254 5748/812/1254 5747/809/1065 +f 5739/813/1067 5742/814/1067 5743/810/1065 +f 5743/810/1065 5747/809/1065 5739/813/1067 +f 5749/804/809 5747/803/808 5748/806/1101 +f 5748/806/1101 5750/805/1101 5749/804/809 +f 5740/808/1102 5739/807/1102 5747/803/808 +f 5747/803/808 5749/804/809 5740/808/1102 +f 5744/815/1068 5749/809/1068 5750/816/1069 +f 5750/816/1069 5745/817/1069 5744/815/1068 +f 5741/818/1255 5740/819/1071 5749/809/1068 +f 5749/809/1068 5744/815/1068 5741/818/1255 +f 5751/820/36 5752/821/36 5753/822/36 +f 5753/822/36 5754/823/36 5751/820/36 +f 5755/824/1103 5756/825/1104 5757/826/1074 +f 5757/826/1074 5758/827/1074 5755/824/1103 +f 5754/828/1105 5753/829/1105 5756/825/1104 +f 5756/825/1104 5755/824/1103 5754/828/1105 +f 5759/737/1076 5755/738/1077 5758/734/1078 +f 5758/734/1078 5760/740/1078 5759/737/1076 +f 5751/741/1079 5754/735/1079 5755/738/1077 +f 5755/738/1077 5759/737/1076 5751/741/1079 +f 5761/825/1106 5759/824/1080 5760/827/1081 +f 5760/827/1081 5762/826/1081 5761/825/1106 +f 5752/829/1082 5751/828/1082 5759/824/1080 +f 5759/824/1080 5761/825/1106 5752/829/1082 +f 5756/731/1083 5761/737/1084 5762/733/1085 +f 5762/733/1085 5757/830/1085 5756/731/1083 +f 5753/831/1086 5752/736/1086 5761/737/1084 +f 5761/737/1084 5756/731/1083 5753/831/1086 +f 5763/832/36 5764/833/36 5765/834/36 +f 5765/834/36 5766/835/36 5763/832/36 +f 5767/836/1087 5768/837/1087 5769/838/1256 +f 5769/838/1256 5770/839/1256 5767/836/1087 +f 5766/840/1116 5765/841/1116 5768/837/1087 +f 5768/837/1087 5767/836/1087 5766/840/1116 +f 5771/737/848 5767/731/848 5770/734/849 +f 5770/734/849 5772/733/849 5771/737/848 +f 5763/741/850 5766/735/850 5767/731/848 +f 5767/731/848 5771/737/848 5763/741/850 +f 5773/837/1090 5771/836/1090 5772/839/1091 +f 5772/839/1091 5774/838/1091 5773/837/1090 +f 5764/841/1092 5763/840/1092 5771/836/1090 +f 5771/836/1090 5773/837/1090 5764/841/1092 +f 5768/842/842 5773/732/842 5774/843/843 +f 5774/843/843 5769/734/843 5768/842/842 +f 5765/831/844 5764/736/1094 5773/732/842 +f 5773/732/842 5768/842/842 5765/831/844 +f 5775/721/37 5776/722/37 5777/723/37 +f 5777/723/37 5778/724/37 5775/721/37 +f 5779/725/1003 5780/726/1004 5781/727/1112 +f 5781/727/1112 5782/728/1112 5779/725/1003 +f 5778/729/1006 5777/730/1006 5780/726/1004 +f 5780/726/1004 5779/725/1003 5778/729/1006 +f 5783/731/1007 5779/732/1008 5782/733/1009 +f 5782/733/1009 5784/734/1009 5783/731/1007 +f 5775/735/1010 5778/736/1010 5779/732/1008 +f 5779/732/1008 5783/731/1007 5775/735/1010 +f 5785/726/1011 5783/725/1011 5784/728/1012 +f 5784/728/1012 5786/727/1012 5785/726/1011 +f 5776/730/1013 5775/729/1013 5783/725/1011 +f 5783/725/1011 5785/726/1011 5776/730/1013 +f 5780/737/1014 5785/738/1014 5786/739/1015 +f 5786/739/1015 5781/740/1015 5780/737/1014 +f 5777/741/1016 5776/742/1016 5785/738/1014 +f 5785/738/1014 5780/737/1014 5777/741/1016 +f 5787/743/36 5788/744/36 5789/745/36 +f 5789/745/36 5790/746/36 5787/743/36 +f 5791/747/1017 5792/748/1017 5793/749/1018 +f 5793/749/1018 5794/750/1018 5791/747/1017 +f 5790/751/1019 5789/752/1019 5792/748/1017 +f 5792/748/1017 5791/747/1017 5790/751/1019 +f 5795/753/1020 5791/754/1021 5794/755/1022 +f 5794/755/1022 5796/756/1022 5795/753/1020 +f 5787/757/1023 5790/758/1023 5791/754/1021 +f 5791/754/1021 5795/753/1020 5787/757/1023 +f 5797/748/1024 5795/747/1025 5796/750/1097 +f 5796/750/1097 5798/749/1097 5797/748/1024 +f 5788/752/1028 5787/751/1028 5795/747/1025 +f 5795/747/1025 5797/748/1024 5788/752/1028 +f 5792/754/1029 5797/759/1030 5798/760/1031 +f 5798/760/1031 5793/755/1031 5792/754/1029 +f 5789/758/1032 5788/761/1032 5797/759/1030 +f 5797/759/1030 5792/754/1029 5789/758/1032 +f 5799/762/1033 5800/763/1034 5801/764/1035 +f 5801/764/1035 5802/765/1035 5799/762/1033 +f 5803/766/1036 5804/767/1036 5800/763/1034 +f 5800/763/1034 5799/762/1033 5803/766/1036 +f 5805/768/1098 5799/769/1038 5802/770/1039 +f 5802/770/1039 5806/771/1039 5805/768/1098 +f 5807/772/1040 5803/773/1040 5799/769/1038 +f 5799/769/1038 5805/768/1098 5807/772/1040 +f 5808/763/1041 5805/762/1042 5806/765/1043 +f 5806/765/1043 5809/764/1043 5808/763/1041 +f 5810/767/1044 5807/766/1044 5805/762/1042 +f 5805/762/1042 5808/763/1041 5810/767/1044 +f 5800/774/1045 5808/768/1046 5809/771/1047 +f 5809/771/1047 5801/775/1047 5800/774/1045 +f 5804/776/1048 5810/777/1048 5808/768/1046 +f 5808/768/1046 5800/774/1045 5804/776/1048 +f 5811/778/1049 5812/779/1050 5813/780/1051 +f 5813/780/1051 5814/781/1051 5811/778/1049 +f 5815/782/1052 5816/783/1052 5812/779/1050 +f 5812/779/1050 5811/778/1049 5815/782/1052 +f 5817/784/1053 5811/785/1099 5814/786/1055 +f 5814/786/1055 5818/787/1055 5817/784/1053 +f 5819/788/1056 5815/789/1056 5811/785/1099 +f 5811/785/1099 5817/784/1053 5819/788/1056 +f 5820/790/1057 5817/791/1115 5818/792/1059 +f 5818/792/1059 5821/793/1059 5820/790/1057 +f 5822/794/1060 5819/795/1060 5817/791/1115 +f 5817/791/1115 5820/790/1057 5822/794/1060 +f 5812/785/1061 5820/796/1062 5821/787/1063 +f 5821/787/1063 5813/797/1063 5812/785/1061 +f 5816/789/1064 5822/798/1064 5820/796/1062 +f 5820/796/1062 5812/785/1061 5816/789/1064 +f 5823/799/36 5824/800/36 5825/801/36 +f 5825/801/36 5826/802/36 5823/799/36 +f 5827/803/1252 5828/804/1253 5829/805/869 +f 5829/805/869 5830/806/869 5827/803/1252 +f 5826/807/870 5825/808/870 5828/804/1253 +f 5828/804/1253 5827/803/1252 5826/807/870 +f 5831/809/1065 5827/810/1065 5830/811/1066 +f 5830/811/1066 5832/812/1066 5831/809/1065 +f 5823/813/1067 5826/814/1067 5827/810/1065 +f 5827/810/1065 5831/809/1065 5823/813/1067 +f 5833/804/809 5831/803/808 5832/806/1101 +f 5832/806/1101 5834/805/1101 5833/804/809 +f 5824/808/1102 5823/807/1102 5831/803/808 +f 5831/803/808 5833/804/809 5824/808/1102 +f 5828/815/1068 5833/809/1068 5834/816/1069 +f 5834/816/1069 5829/817/1069 5828/815/1068 +f 5825/818/1071 5824/819/1071 5833/809/1068 +f 5833/809/1068 5828/815/1068 5825/818/1071 +f 5835/820/36 5836/821/36 5837/822/36 +f 5837/822/36 5838/823/36 5835/820/36 +f 5839/824/1103 5840/825/1104 5841/826/1074 +f 5841/826/1074 5842/827/1074 5839/824/1103 +f 5838/828/1105 5837/829/1105 5840/825/1104 +f 5840/825/1104 5839/824/1103 5838/828/1105 +f 5843/737/1076 5839/738/1077 5842/734/1078 +f 5842/734/1078 5844/740/1078 5843/737/1076 +f 5835/741/1079 5838/735/1079 5839/738/1077 +f 5839/738/1077 5843/737/1076 5835/741/1079 +f 5845/825/1106 5843/824/1080 5844/827/1081 +f 5844/827/1081 5846/826/1081 5845/825/1106 +f 5836/829/1082 5835/828/1082 5843/824/1080 +f 5843/824/1080 5845/825/1106 5836/829/1082 +f 5840/731/1083 5845/737/1084 5846/733/1085 +f 5846/733/1085 5841/830/1085 5840/731/1083 +f 5837/831/1086 5836/736/1086 5845/737/1084 +f 5845/737/1084 5840/731/1083 5837/831/1086 +f 5847/832/36 5848/833/36 5849/834/36 +f 5849/834/36 5850/835/36 5847/832/36 +f 5851/836/1087 5852/837/1087 5853/838/1256 +f 5853/838/1256 5854/839/1256 5851/836/1087 +f 5850/840/1110 5849/841/1110 5852/837/1087 +f 5852/837/1087 5851/836/1087 5850/840/1110 +f 5855/737/848 5851/731/848 5854/734/849 +f 5854/734/849 5856/733/849 5855/737/848 +f 5847/741/850 5850/735/850 5851/731/848 +f 5851/731/848 5855/737/848 5847/741/850 +f 5857/837/1090 5855/836/1090 5856/839/1091 +f 5856/839/1091 5858/838/1091 5857/837/1090 +f 5848/841/1092 5847/840/1092 5855/836/1090 +f 5855/836/1090 5857/837/1090 5848/841/1092 +f 5852/842/842 5857/732/842 5858/843/843 +f 5858/843/843 5853/734/843 5852/842/842 +f 5849/831/1094 5848/736/1094 5857/732/842 +f 5857/732/842 5852/842/842 5849/831/1094 +f 5859/721/36 5860/722/36 5861/723/36 +f 5861/723/36 5862/724/36 5859/721/36 +f 5863/725/1003 5864/726/1004 5865/727/1112 +f 5865/727/1112 5866/728/1112 5863/725/1003 +f 5862/729/1006 5861/730/1006 5864/726/1004 +f 5864/726/1004 5863/725/1003 5862/729/1006 +f 5867/731/1007 5863/732/1008 5866/733/1009 +f 5866/733/1009 5868/734/1009 5867/731/1007 +f 5859/735/1010 5862/736/1010 5863/732/1008 +f 5863/732/1008 5867/731/1007 5859/735/1010 +f 5869/726/1011 5867/725/1011 5868/728/1012 +f 5868/728/1012 5870/727/1012 5869/726/1011 +f 5860/730/1013 5859/729/1013 5867/725/1011 +f 5867/725/1011 5869/726/1011 5860/730/1013 +f 5864/737/1014 5869/738/1014 5870/739/1015 +f 5870/739/1015 5865/740/1015 5864/737/1014 +f 5861/741/1016 5860/742/1016 5869/738/1014 +f 5869/738/1014 5864/737/1014 5861/741/1016 +f 5871/743/36 5872/744/36 5873/745/36 +f 5873/745/36 5874/746/36 5871/743/36 +f 5875/747/1017 5876/748/1017 5877/749/1018 +f 5877/749/1018 5878/750/1018 5875/747/1017 +f 5874/751/1019 5873/752/1019 5876/748/1017 +f 5876/748/1017 5875/747/1017 5874/751/1019 +f 5879/753/1020 5875/754/1021 5878/755/1022 +f 5878/755/1022 5880/756/1022 5879/753/1020 +f 5871/757/1023 5874/758/1023 5875/754/1021 +f 5875/754/1021 5879/753/1020 5871/757/1023 +f 5881/748/1024 5879/747/1025 5880/750/1097 +f 5880/750/1097 5882/749/1097 5881/748/1024 +f 5872/752/1028 5871/751/1028 5879/747/1025 +f 5879/747/1025 5881/748/1024 5872/752/1028 +f 5876/754/1029 5881/759/1030 5882/760/1031 +f 5882/760/1031 5877/755/1031 5876/754/1029 +f 5873/758/1032 5872/761/1032 5881/759/1030 +f 5881/759/1030 5876/754/1029 5873/758/1032 +f 5883/762/1033 5884/763/1034 5885/764/1035 +f 5885/764/1035 5886/765/1035 5883/762/1033 +f 5887/766/1036 5888/767/1036 5884/763/1034 +f 5884/763/1034 5883/762/1033 5887/766/1036 +f 5889/768/1037 5883/769/1038 5886/770/1039 +f 5886/770/1039 5890/771/1039 5889/768/1037 +f 5891/772/1040 5887/773/1040 5883/769/1038 +f 5883/769/1038 5889/768/1037 5891/772/1040 +f 5892/763/1041 5889/762/1042 5890/765/1043 +f 5890/765/1043 5893/764/1043 5892/763/1041 +f 5894/767/1044 5891/766/1044 5889/762/1042 +f 5889/762/1042 5892/763/1041 5894/767/1044 +f 5884/774/1045 5892/768/1046 5893/771/1047 +f 5893/771/1047 5885/775/1047 5884/774/1045 +f 5888/776/1048 5894/777/1048 5892/768/1046 +f 5892/768/1046 5884/774/1045 5888/776/1048 +f 5895/778/1049 5896/779/1050 5897/780/1051 +f 5897/780/1051 5898/781/1051 5895/778/1049 +f 5899/782/1052 5900/783/1052 5896/779/1050 +f 5896/779/1050 5895/778/1049 5899/782/1052 +f 5901/784/1053 5895/785/1099 5898/786/1055 +f 5898/786/1055 5902/787/1055 5901/784/1053 +f 5903/788/1056 5899/789/1056 5895/785/1099 +f 5895/785/1099 5901/784/1053 5903/788/1056 +f 5904/790/1057 5901/791/1115 5902/792/1059 +f 5902/792/1059 5905/793/1059 5904/790/1057 +f 5906/794/1060 5903/795/1060 5901/791/1115 +f 5901/791/1115 5904/790/1057 5906/794/1060 +f 5896/785/1061 5904/796/1062 5905/787/1063 +f 5905/787/1063 5897/797/1063 5896/785/1061 +f 5900/789/1064 5906/798/1064 5904/796/1062 +f 5904/796/1062 5896/785/1061 5900/789/1064 +f 5907/799/36 5908/800/36 5909/801/36 +f 5909/801/36 5910/802/36 5907/799/36 +f 5911/803/1252 5912/804/1253 5913/805/869 +f 5913/805/869 5914/806/869 5911/803/1252 +f 5910/807/870 5909/808/870 5912/804/1253 +f 5912/804/1253 5911/803/1252 5910/807/870 +f 5915/809/1065 5911/810/1065 5914/811/1066 +f 5914/811/1066 5916/812/1066 5915/809/1065 +f 5907/813/1067 5910/814/1067 5911/810/1065 +f 5911/810/1065 5915/809/1065 5907/813/1067 +f 5917/804/809 5915/803/808 5916/806/1101 +f 5916/806/1101 5918/805/1101 5917/804/809 +f 5908/808/1102 5907/807/1102 5915/803/808 +f 5915/803/808 5917/804/809 5908/808/1102 +f 5912/815/1068 5917/809/1068 5918/816/1069 +f 5918/816/1069 5913/817/1069 5912/815/1068 +f 5909/818/1070 5908/819/1071 5917/809/1068 +f 5917/809/1068 5912/815/1068 5909/818/1070 +f 5919/820/36 5920/821/36 5921/822/36 +f 5921/822/36 5922/823/36 5919/820/36 +f 5923/824/1103 5924/825/1104 5925/826/1074 +f 5925/826/1074 5926/827/1074 5923/824/1103 +f 5922/828/1105 5921/829/1105 5924/825/1104 +f 5924/825/1104 5923/824/1103 5922/828/1105 +f 5927/737/1076 5923/738/1077 5926/734/1078 +f 5926/734/1078 5928/740/1078 5927/737/1076 +f 5919/741/1079 5922/735/1079 5923/738/1077 +f 5923/738/1077 5927/737/1076 5919/741/1079 +f 5929/825/1106 5927/824/1080 5928/827/1081 +f 5928/827/1081 5930/826/1081 5929/825/1106 +f 5920/829/1082 5919/828/1082 5927/824/1080 +f 5927/824/1080 5929/825/1106 5920/829/1082 +f 5924/731/1083 5929/737/1084 5930/733/1085 +f 5930/733/1085 5925/830/1085 5924/731/1083 +f 5921/831/1086 5920/736/1086 5929/737/1084 +f 5929/737/1084 5924/731/1083 5921/831/1086 +f 5931/832/36 5932/833/36 5933/834/36 +f 5933/834/36 5934/835/36 5931/832/36 +f 5935/836/1087 5936/837/1087 5937/838/1256 +f 5937/838/1256 5938/839/1256 5935/836/1087 +f 5934/840/1110 5933/841/1110 5936/837/1087 +f 5936/837/1087 5935/836/1087 5934/840/1110 +f 5939/737/848 5935/731/848 5938/734/849 +f 5938/734/849 5940/733/849 5939/737/848 +f 5931/741/850 5934/735/850 5935/731/848 +f 5935/731/848 5939/737/848 5931/741/850 +f 5941/837/1090 5939/836/1090 5940/839/1091 +f 5940/839/1091 5942/838/1091 5941/837/1090 +f 5932/841/1092 5931/840/1092 5939/836/1090 +f 5939/836/1090 5941/837/1090 5932/841/1092 +f 5936/842/842 5941/732/842 5942/843/843 +f 5942/843/843 5937/734/843 5936/842/842 +f 5933/831/844 5932/736/1094 5941/732/842 +f 5941/732/842 5936/842/842 5933/831/844 +f 5943/844/1257 5944/845/1257 5945/846/1257 +f 5946/847/1258 5947/848/1258 5948/849/1259 +f 5948/849/1259 5949/850/1260 5946/847/1258 +f 5949/851/1260 5948/852/1259 5950/853/1261 +f 5950/853/1261 5951/854/1261 5949/851/1260 +f 5951/854/1261 5950/853/1261 5952/855/1262 +f 5952/855/1262 5953/856/1262 5951/854/1261 +f 5953/856/1262 5952/855/1262 5944/857/1263 +f 5944/857/1263 5954/858/1263 5953/856/1262 +f 5954/858/1263 5944/857/1263 5943/859/1264 +f 5943/859/1264 5955/860/1264 5954/858/1263 +f 5955/860/1264 5943/859/1264 5956/861/1265 +f 5956/861/1265 5957/862/1265 5955/860/1264 +f 5957/862/1265 5956/861/1265 5958/863/1266 +f 5958/863/1266 5959/864/1266 5957/862/1265 +f 5959/864/1266 5958/863/1266 5960/865/1267 +f 5960/865/1267 5961/866/1267 5959/864/1266 +f 5961/866/1267 5960/865/1267 5962/867/1268 +f 5962/867/1268 5963/868/1269 5961/866/1267 +f 5963/868/1269 5962/867/1268 5947/848/1258 +f 5947/848/1258 5946/847/1258 5963/868/1269 +f 5963/869/1270 5946/870/1270 5964/846/1271 +f 5949/871/1270 5951/872/1271 5964/846/1271 +f 5955/844/1271 5957/873/1271 5964/846/1271 +f 5964/846/1271 5961/874/1270 5963/869/1270 +f 5953/875/1271 5954/845/1271 5964/846/1271 +f 5964/846/1271 5959/876/1271 5961/874/1270 +f 5951/872/1271 5953/875/1271 5964/846/1271 +f 5964/846/1271 5957/873/1271 5959/876/1271 +f 5946/870/1270 5949/871/1270 5964/846/1271 +f 5964/846/1271 5954/845/1271 5955/844/1271 +f 5945/846/1257 5962/869/1272 5960/874/1272 +f 5948/871/1257 5947/870/1257 5945/846/1257 +f 5945/846/1257 5947/870/1257 5962/869/1272 +f 5960/874/1272 5958/876/1272 5945/846/1257 +f 5945/846/1257 5944/845/1257 5952/875/1257 +f 5958/876/1272 5956/873/1272 5945/846/1257 +f 5945/846/1257 5952/875/1257 5950/872/1257 +f 5956/873/1272 5943/844/1257 5945/846/1257 +f 5945/846/1257 5950/872/1257 5948/871/1257 +f 5965/877/1273 5966/878/1273 5967/879/1274 +f 5967/879/1274 5968/880/1274 5965/877/1273 +f 5969/881/1275 5970/882/1275 5966/883/1276 +f 5966/883/1276 5965/884/1276 5969/881/1275 +f 5971/885/1277 5969/886/1277 5965/887/1277 +f 5965/887/1277 5968/888/1277 5971/885/1277 +f 5972/882/1278 5971/881/1278 5968/884/1278 +f 5968/884/1278 5967/883/1278 5972/882/1278 +f 5970/886/1279 5972/885/1279 5967/888/1279 +f 5967/888/1279 5966/887/1280 5970/886/1279 +f 5973/879/1281 5974/878/1281 5975/877/1281 +f 5975/877/1281 5976/880/1281 5973/879/1281 +f 5974/883/1282 5977/882/1283 5978/881/1283 +f 5978/881/1283 5975/884/1282 5974/883/1282 +f 5975/887/1284 5978/886/1284 5979/885/1284 +f 5979/885/1284 5976/888/1284 5975/887/1284 +f 5976/884/1285 5979/881/1285 5980/882/1285 +f 5980/882/1285 5973/883/1285 5976/884/1285 +f 5973/888/1286 5980/885/1287 5977/886/1287 +f 5977/886/1287 5974/887/1286 5973/888/1286 +f 5981/883/1288 5982/882/1289 5983/881/1289 +f 5983/881/1289 5984/884/1288 5981/883/1288 +f 5984/887/1290 5983/886/1290 5985/885/1290 +f 5985/885/1290 5986/888/1290 5984/887/1290 +f 5986/884/1291 5985/881/1292 5987/882/1292 +f 5987/882/1292 5988/883/1291 5986/884/1291 +f 5988/888/1293 5987/885/1293 5982/886/1293 +f 5982/886/1293 5981/887/1293 5988/888/1293 +f 5989/844/1294 5990/845/1294 5991/846/1294 +f 5992/847/1295 5993/848/1295 5994/849/1296 +f 5994/849/1296 5995/850/1296 5992/847/1295 +f 5995/851/1296 5994/852/1296 5996/853/1297 +f 5996/853/1297 5997/854/1297 5995/851/1296 +f 5997/854/1297 5996/853/1297 5998/855/1298 +f 5998/855/1298 5999/856/1298 5997/854/1297 +f 5999/856/1298 5998/855/1298 5990/857/1299 +f 5990/857/1299 6000/858/1299 5999/856/1298 +f 6000/858/1299 5990/857/1299 5989/859/1300 +f 5989/859/1300 6001/860/1300 6000/858/1299 +f 6001/860/1300 5989/859/1300 6002/861/1301 +f 6002/861/1301 6003/862/1301 6001/860/1300 +f 6003/862/1301 6002/861/1301 6004/863/1302 +f 6004/863/1302 6005/864/1302 6003/862/1301 +f 6005/864/1302 6004/863/1302 6006/865/1303 +f 6006/865/1303 6007/866/1303 6005/864/1302 +f 6007/866/1303 6006/865/1303 6008/867/1304 +f 6008/867/1304 6009/868/1304 6007/866/1303 +f 6009/868/1304 6008/867/1304 5993/848/1295 +f 5993/848/1295 5992/847/1295 6009/868/1304 +f 6009/869/1305 5992/870/1305 6010/846/1306 +f 5995/871/1306 5997/872/1306 6010/846/1306 +f 6001/844/1306 6003/873/1306 6010/846/1306 +f 6010/846/1306 6007/874/1305 6009/869/1305 +f 5999/875/1306 6000/845/1306 6010/846/1306 +f 6010/846/1306 6005/876/1305 6007/874/1305 +f 5997/872/1306 5999/875/1306 6010/846/1306 +f 6010/846/1306 6003/873/1306 6005/876/1305 +f 5992/870/1305 5995/871/1306 6010/846/1306 +f 6010/846/1306 6000/845/1306 6001/844/1306 +f 5991/846/1294 6008/869/1307 6006/874/1307 +f 5994/871/1294 5993/870/1294 5991/846/1294 +f 5991/846/1294 5993/870/1294 6008/869/1307 +f 6006/874/1307 6004/876/1307 5991/846/1294 +f 5991/846/1294 5990/845/1294 5998/875/1294 +f 6004/876/1307 6002/873/1307 5991/846/1294 +f 5991/846/1294 5998/875/1294 5996/872/1294 +f 6002/873/1307 5989/844/1294 5991/846/1294 +f 5991/846/1294 5996/872/1294 5994/871/1294 +f 6011/877/1308 6012/878/1308 6013/879/1308 +f 6013/879/1308 6014/880/1308 6011/877/1308 +f 6015/881/1309 6016/882/1309 6012/883/1310 +f 6012/883/1310 6011/884/1310 6015/881/1309 +f 6017/885/1311 6015/886/1311 6011/887/1311 +f 6011/887/1311 6014/888/1311 6017/885/1311 +f 6018/882/1312 6017/881/1312 6014/884/1312 +f 6014/884/1312 6013/883/1312 6018/882/1312 +f 6016/886/1313 6018/885/1313 6013/888/1314 +f 6013/888/1314 6012/887/1314 6016/886/1313 +f 6019/879/1315 6020/878/1315 6021/877/1315 +f 6021/877/1315 6022/880/1315 6019/879/1315 +f 6020/883/1316 6023/882/1316 6024/881/1316 +f 6024/881/1316 6021/884/1316 6020/883/1316 +f 6021/887/1317 6024/886/1317 6025/885/1317 +f 6025/885/1317 6022/888/1317 6021/887/1317 +f 6022/884/1318 6025/881/1319 6026/882/1319 +f 6026/882/1319 6019/883/1318 6022/884/1318 +f 6019/888/1320 6026/885/1321 6023/886/1321 +f 6023/886/1321 6020/887/1320 6019/888/1320 +f 6027/883/1322 6028/882/1322 6029/881/1322 +f 6029/881/1322 6030/884/1322 6027/883/1322 +f 6030/887/1323 6029/886/1323 6031/885/1323 +f 6031/885/1323 6032/888/1323 6030/887/1323 +f 6032/884/1324 6031/881/1325 6033/882/1325 +f 6033/882/1325 6034/883/1324 6032/884/1324 +f 6034/888/1326 6033/885/1326 6028/886/1326 +f 6028/886/1326 6027/887/1326 6034/888/1326 +f 6035/844/1327 6036/845/1327 6037/846/1327 +f 6038/847/1328 6039/848/1328 6040/849/1329 +f 6040/849/1329 6041/850/1330 6038/847/1328 +f 6041/851/1330 6040/852/1329 6042/853/1331 +f 6042/853/1331 6043/854/1331 6041/851/1330 +f 6043/854/1331 6042/853/1331 6044/855/1332 +f 6044/855/1332 6045/856/1333 6043/854/1331 +f 6045/856/1333 6044/855/1332 6036/857/1334 +f 6036/857/1334 6046/858/1335 6045/856/1333 +f 6046/858/1335 6036/857/1334 6035/859/1336 +f 6035/859/1336 6047/860/1336 6046/858/1335 +f 6047/860/1336 6035/859/1336 6048/861/1337 +f 6048/861/1337 6049/862/1337 6047/860/1336 +f 6049/862/1337 6048/861/1337 6050/863/1338 +f 6050/863/1338 6051/864/1338 6049/862/1337 +f 6051/864/1338 6050/863/1338 6052/865/1339 +f 6052/865/1339 6053/866/1339 6051/864/1338 +f 6053/866/1339 6052/865/1339 6054/867/1340 +f 6054/867/1340 6055/868/1340 6053/866/1339 +f 6055/868/1340 6054/867/1340 6039/848/1328 +f 6039/848/1328 6038/847/1328 6055/868/1340 +f 6055/869/1341 6038/870/1341 6056/846/1342 +f 6041/871/1342 6043/872/1342 6056/846/1342 +f 6047/844/1341 6049/873/1341 6056/846/1342 +f 6056/846/1342 6053/874/1342 6055/869/1341 +f 6045/875/1342 6046/845/1342 6056/846/1342 +f 6056/846/1342 6051/876/1341 6053/874/1342 +f 6043/872/1342 6045/875/1342 6056/846/1342 +f 6056/846/1342 6049/873/1341 6051/876/1341 +f 6038/870/1341 6041/871/1342 6056/846/1342 +f 6056/846/1342 6046/845/1342 6047/844/1341 +f 6037/846/1327 6054/869/1343 6052/874/1343 +f 6040/871/1327 6039/870/1327 6037/846/1327 +f 6037/846/1327 6039/870/1327 6054/869/1343 +f 6052/874/1343 6050/876/1343 6037/846/1327 +f 6037/846/1327 6036/845/1327 6044/875/1327 +f 6050/876/1343 6048/873/1343 6037/846/1327 +f 6037/846/1327 6044/875/1327 6042/872/1327 +f 6048/873/1343 6035/844/1327 6037/846/1327 +f 6037/846/1327 6042/872/1327 6040/871/1327 +f 6057/877/1344 6058/878/1344 6059/879/1344 +f 6059/879/1344 6060/880/1344 6057/877/1344 +f 6061/881/1345 6062/882/1345 6058/883/1346 +f 6058/883/1346 6057/884/1346 6061/881/1345 +f 6063/885/1347 6061/886/1347 6057/887/1348 +f 6057/887/1348 6060/888/1348 6063/885/1347 +f 6064/882/1349 6063/881/1349 6060/884/1350 +f 6060/884/1350 6059/883/1350 6064/882/1349 +f 6062/886/1351 6064/885/1351 6059/888/1352 +f 6059/888/1352 6058/887/1352 6062/886/1351 +f 6065/879/1353 6066/878/1353 6067/877/1353 +f 6067/877/1353 6068/880/1353 6065/879/1353 +f 6066/883/1354 6069/882/1354 6070/881/1354 +f 6070/881/1354 6067/884/1354 6066/883/1354 +f 6067/887/1355 6070/886/1355 6071/885/1355 +f 6071/885/1355 6068/888/1355 6067/887/1355 +f 6068/884/1356 6071/881/1357 6072/882/1357 +f 6072/882/1357 6065/883/1356 6068/884/1356 +f 6065/888/1358 6072/885/1358 6069/886/1358 +f 6069/886/1358 6066/887/1358 6065/888/1358 +f 6073/883/1359 6074/882/1360 6075/881/1360 +f 6075/881/1360 6076/884/1359 6073/883/1359 +f 6076/887/1361 6075/886/1362 6077/885/1362 +f 6077/885/1362 6078/888/1361 6076/887/1361 +f 6078/884/1363 6077/881/1364 6079/882/1364 +f 6079/882/1364 6080/883/1363 6078/884/1363 +f 6080/888/1365 6079/885/1365 6074/886/1365 +f 6074/886/1365 6073/887/1365 6080/888/1365 +f 6081/844/1366 6082/845/1367 6083/846/1367 +f 6084/847/1368 6085/848/1368 6086/849/1369 +f 6086/849/1369 6087/850/1369 6084/847/1368 +f 6087/851/1369 6086/852/1369 6088/853/1370 +f 6088/853/1370 6089/854/1370 6087/851/1369 +f 6089/854/1370 6088/853/1370 6090/855/1371 +f 6090/855/1371 6091/856/1372 6089/854/1370 +f 6091/856/1372 6090/855/1371 6082/857/1373 +f 6082/857/1373 6092/858/1374 6091/856/1372 +f 6092/858/1374 6082/857/1373 6081/859/1375 +f 6081/859/1375 6093/860/1375 6092/858/1374 +f 6093/860/1375 6081/859/1375 6094/861/1376 +f 6094/861/1376 6095/862/1376 6093/860/1375 +f 6095/862/1376 6094/861/1376 6096/863/1377 +f 6096/863/1377 6097/864/1377 6095/862/1376 +f 6097/864/1377 6096/863/1377 6098/865/1378 +f 6098/865/1378 6099/866/1379 6097/864/1377 +f 6099/866/1379 6098/865/1378 6100/867/1380 +f 6100/867/1380 6101/868/1380 6099/866/1379 +f 6101/868/1380 6100/867/1380 6085/848/1368 +f 6085/848/1368 6084/847/1368 6101/868/1380 +f 6101/869/1381 6084/870/1381 6102/846/1382 +f 6087/871/1381 6089/872/1382 6102/846/1382 +f 6093/844/1382 6095/873/1382 6102/846/1382 +f 6102/846/1382 6099/874/1381 6101/869/1381 +f 6091/875/1382 6092/845/1382 6102/846/1382 +f 6102/846/1382 6097/876/1381 6099/874/1381 +f 6089/872/1382 6091/875/1382 6102/846/1382 +f 6102/846/1382 6095/873/1382 6097/876/1381 +f 6084/870/1381 6087/871/1381 6102/846/1382 +f 6102/846/1382 6092/845/1382 6093/844/1382 +f 6083/846/1367 6100/869/1366 6098/874/1366 +f 6086/871/1367 6085/870/1367 6083/846/1367 +f 6083/846/1367 6085/870/1367 6100/869/1366 +f 6098/874/1366 6096/876/1366 6083/846/1367 +f 6083/846/1367 6082/845/1367 6090/875/1367 +f 6096/876/1366 6094/873/1366 6083/846/1367 +f 6083/846/1367 6090/875/1367 6088/872/1367 +f 6094/873/1366 6081/844/1366 6083/846/1367 +f 6083/846/1367 6088/872/1367 6086/871/1367 +f 6103/877/1383 6104/878/1383 6105/879/1383 +f 6105/879/1383 6106/880/1383 6103/877/1383 +f 6107/881/1384 6108/882/1384 6104/883/1385 +f 6104/883/1385 6103/884/1385 6107/881/1384 +f 6109/885/1386 6107/886/1386 6103/887/1386 +f 6103/887/1386 6106/888/1386 6109/885/1386 +f 6110/882/1387 6109/881/1387 6106/884/1387 +f 6106/884/1387 6105/883/1387 6110/882/1387 +f 6108/886/1388 6110/885/1388 6105/888/1388 +f 6105/888/1388 6104/887/1388 6108/886/1388 +f 6111/879/1389 6112/878/1389 6113/877/1389 +f 6113/877/1389 6114/880/1389 6111/879/1389 +f 6112/883/1390 6115/882/1390 6116/881/1390 +f 6116/881/1390 6113/884/1390 6112/883/1390 +f 6113/887/1391 6116/886/1391 6117/885/1391 +f 6117/885/1391 6114/888/1391 6113/887/1391 +f 6114/884/1392 6117/881/1392 6118/882/1392 +f 6118/882/1392 6111/883/1392 6114/884/1392 +f 6111/888/1393 6118/885/1393 6115/886/1393 +f 6115/886/1393 6112/887/1393 6111/888/1393 +f 6119/883/1394 6120/882/1394 6121/881/1394 +f 6121/881/1394 6122/884/1394 6119/883/1394 +f 6122/887/1395 6121/886/1395 6123/885/1395 +f 6123/885/1395 6124/888/1395 6122/887/1395 +f 6124/884/1396 6123/881/1397 6125/882/1397 +f 6125/882/1397 6126/883/1396 6124/884/1396 +f 6126/888/1398 6125/885/1398 6120/886/1398 +f 6120/886/1398 6119/887/1398 6126/888/1398 +f 6127/844/1366 6128/845/1367 6129/846/1367 +f 6130/847/1368 6131/848/1368 6132/849/1369 +f 6132/849/1369 6133/850/1369 6130/847/1368 +f 6133/851/1369 6132/852/1369 6134/853/1370 +f 6134/853/1370 6135/854/1370 6133/851/1369 +f 6135/854/1370 6134/853/1370 6136/855/1371 +f 6136/855/1371 6137/856/1371 6135/854/1370 +f 6137/856/1371 6136/855/1371 6128/857/1373 +f 6128/857/1373 6138/858/1374 6137/856/1371 +f 6138/858/1374 6128/857/1373 6127/859/1399 +f 6127/859/1399 6139/860/1399 6138/858/1374 +f 6139/860/1399 6127/859/1399 6140/861/1376 +f 6140/861/1376 6141/862/1376 6139/860/1399 +f 6141/862/1376 6140/861/1376 6142/863/1377 +f 6142/863/1377 6143/864/1377 6141/862/1376 +f 6143/864/1377 6142/863/1377 6144/865/1400 +f 6144/865/1400 6145/866/1401 6143/864/1377 +f 6145/866/1401 6144/865/1400 6146/867/1380 +f 6146/867/1380 6147/868/1380 6145/866/1401 +f 6147/868/1380 6146/867/1380 6131/848/1368 +f 6131/848/1368 6130/847/1368 6147/868/1380 +f 6147/869/1381 6130/870/1381 6148/846/1382 +f 6133/871/1381 6135/872/1382 6148/846/1382 +f 6139/844/1382 6141/873/1382 6148/846/1382 +f 6148/846/1382 6145/874/1381 6147/869/1381 +f 6137/875/1382 6138/845/1382 6148/846/1382 +f 6148/846/1382 6143/876/1381 6145/874/1381 +f 6135/872/1382 6137/875/1382 6148/846/1382 +f 6148/846/1382 6141/873/1382 6143/876/1381 +f 6130/870/1381 6133/871/1381 6148/846/1382 +f 6148/846/1382 6138/845/1382 6139/844/1382 +f 6129/846/1367 6146/869/1366 6144/874/1366 +f 6132/871/1367 6131/870/1367 6129/846/1367 +f 6129/846/1367 6131/870/1367 6146/869/1366 +f 6144/874/1366 6142/876/1366 6129/846/1367 +f 6129/846/1367 6128/845/1367 6136/875/1367 +f 6142/876/1366 6140/873/1366 6129/846/1367 +f 6129/846/1367 6136/875/1367 6134/872/1367 +f 6140/873/1366 6127/844/1366 6129/846/1367 +f 6129/846/1367 6134/872/1367 6132/871/1367 +f 6149/877/1383 6150/878/1383 6151/879/1383 +f 6151/879/1383 6152/880/1383 6149/877/1383 +f 6153/881/1384 6154/882/1384 6150/883/1385 +f 6150/883/1385 6149/884/1385 6153/881/1384 +f 6155/885/1386 6153/886/1386 6149/887/1386 +f 6149/887/1386 6152/888/1386 6155/885/1386 +f 6156/882/1387 6155/881/1387 6152/884/1387 +f 6152/884/1387 6151/883/1387 6156/882/1387 +f 6154/886/1388 6156/885/1388 6151/888/1388 +f 6151/888/1388 6150/887/1388 6154/886/1388 +f 6157/879/1389 6158/878/1389 6159/877/1389 +f 6159/877/1389 6160/880/1389 6157/879/1389 +f 6158/883/1390 6161/882/1390 6162/881/1390 +f 6162/881/1390 6159/884/1390 6158/883/1390 +f 6159/887/1391 6162/886/1391 6163/885/1391 +f 6163/885/1391 6160/888/1391 6159/887/1391 +f 6160/884/1392 6163/881/1392 6164/882/1392 +f 6164/882/1392 6157/883/1392 6160/884/1392 +f 6157/888/1393 6164/885/1393 6161/886/1393 +f 6161/886/1393 6158/887/1393 6157/888/1393 +f 6165/883/1394 6166/882/1394 6167/881/1394 +f 6167/881/1394 6168/884/1394 6165/883/1394 +f 6168/887/1395 6167/886/1395 6169/885/1395 +f 6169/885/1395 6170/888/1395 6168/887/1395 +f 6170/884/1396 6169/881/1397 6171/882/1397 +f 6171/882/1397 6172/883/1396 6170/884/1396 +f 6172/888/1398 6171/885/1398 6166/886/1398 +f 6166/886/1398 6165/887/1398 6172/888/1398 +f 6173/844/1366 6174/845/1367 6175/846/1367 +f 6176/847/1402 6177/848/1402 6178/849/1369 +f 6178/849/1369 6179/850/1403 6176/847/1402 +f 6179/851/1403 6178/852/1369 6180/853/1370 +f 6180/853/1370 6181/854/1370 6179/851/1403 +f 6181/854/1370 6180/853/1370 6182/855/1371 +f 6182/855/1371 6183/856/1371 6181/854/1370 +f 6183/856/1371 6182/855/1371 6174/857/1373 +f 6174/857/1373 6184/858/1374 6183/856/1371 +f 6184/858/1374 6174/857/1373 6173/859/1399 +f 6173/859/1399 6185/860/1399 6184/858/1374 +f 6185/860/1399 6173/859/1399 6186/861/1376 +f 6186/861/1376 6187/862/1376 6185/860/1399 +f 6187/862/1376 6186/861/1376 6188/863/1377 +f 6188/863/1377 6189/864/1377 6187/862/1376 +f 6189/864/1377 6188/863/1377 6190/865/1401 +f 6190/865/1401 6191/866/1400 6189/864/1377 +f 6191/866/1400 6190/865/1401 6192/867/1380 +f 6192/867/1380 6193/868/1380 6191/866/1400 +f 6193/868/1380 6192/867/1380 6177/848/1402 +f 6177/848/1402 6176/847/1402 6193/868/1380 +f 6193/869/1381 6176/870/1381 6194/846/1382 +f 6179/871/1381 6181/872/1382 6194/846/1382 +f 6185/844/1381 6187/873/1382 6194/846/1382 +f 6194/846/1382 6191/874/1381 6193/869/1381 +f 6183/875/1382 6184/845/1382 6194/846/1382 +f 6194/846/1382 6189/876/1382 6191/874/1381 +f 6181/872/1382 6183/875/1382 6194/846/1382 +f 6194/846/1382 6187/873/1382 6189/876/1382 +f 6176/870/1381 6179/871/1381 6194/846/1382 +f 6194/846/1382 6184/845/1382 6185/844/1381 +f 6175/846/1367 6192/869/1366 6190/874/1366 +f 6178/871/1367 6177/870/1367 6175/846/1367 +f 6175/846/1367 6177/870/1367 6192/869/1366 +f 6190/874/1366 6188/876/1366 6175/846/1367 +f 6175/846/1367 6174/845/1367 6182/875/1367 +f 6188/876/1366 6186/873/1366 6175/846/1367 +f 6175/846/1367 6182/875/1367 6180/872/1367 +f 6186/873/1366 6173/844/1366 6175/846/1367 +f 6175/846/1367 6180/872/1367 6178/871/1367 +f 6195/877/1383 6196/878/1383 6197/879/1383 +f 6197/879/1383 6198/880/1383 6195/877/1383 +f 6199/881/1384 6200/882/1384 6196/883/1385 +f 6196/883/1385 6195/884/1385 6199/881/1384 +f 6201/885/1404 6199/886/1404 6195/887/1386 +f 6195/887/1386 6198/888/1386 6201/885/1404 +f 6202/882/1387 6201/881/1387 6198/884/1387 +f 6198/884/1387 6197/883/1387 6202/882/1387 +f 6200/886/1388 6202/885/1388 6197/888/1388 +f 6197/888/1388 6196/887/1388 6200/886/1388 +f 6203/879/1389 6204/878/1389 6205/877/1389 +f 6205/877/1389 6206/880/1389 6203/879/1389 +f 6204/883/1390 6207/882/1390 6208/881/1390 +f 6208/881/1390 6205/884/1390 6204/883/1390 +f 6205/887/1391 6208/886/1391 6209/885/1391 +f 6209/885/1391 6206/888/1391 6205/887/1391 +f 6206/884/1392 6209/881/1392 6210/882/1392 +f 6210/882/1392 6203/883/1392 6206/884/1392 +f 6203/888/1393 6210/885/1393 6207/886/1393 +f 6207/886/1393 6204/887/1393 6203/888/1393 +f 6211/883/1394 6212/882/1394 6213/881/1394 +f 6213/881/1394 6214/884/1394 6211/883/1394 +f 6214/887/1395 6213/886/1395 6215/885/1395 +f 6215/885/1395 6216/888/1395 6214/887/1395 +f 6216/884/1396 6215/881/1397 6217/882/1397 +f 6217/882/1397 6218/883/1396 6216/884/1396 +f 6218/888/1398 6217/885/1398 6212/886/1398 +f 6212/886/1398 6211/887/1398 6218/888/1398 +f 6219/889/1405 6220/890/1406 6221/891/1407 +f 6221/891/1407 6222/892/1408 6219/889/1405 +f 6223/893/1409 6219/889/1405 6222/892/1408 +f 6222/892/1408 6224/894/1410 6223/893/1409 +f 6225/895/1411 6223/893/1409 6224/894/1410 +f 6224/894/1410 6226/896/1412 6225/895/1411 +f 6227/897/1413 6225/895/1411 6226/896/1412 +f 6226/896/1412 6228/898/1414 6227/897/1413 +f 6229/899/1415 6227/900/1413 6228/901/1414 +f 6228/901/1414 6230/902/1416 6229/899/1415 +f 6231/903/1417 6229/899/1415 6230/902/1416 +f 6230/902/1416 6232/904/1418 6231/903/1417 +f 6233/905/1419 6231/903/1417 6232/904/1418 +f 6232/904/1418 6234/906/1420 6233/905/1419 +f 6220/907/1406 6233/905/1419 6234/906/1420 +f 6234/906/1420 6221/908/1407 6220/907/1406 +f 6235/909/1421 6236/910/1422 6237/911/1423 +f 6237/911/1423 6238/912/1424 6235/909/1421 +f 6238/912/1424 6237/911/1423 6239/913/1425 +f 6239/913/1425 6240/914/1426 6238/912/1424 +f 6240/914/1426 6239/913/1425 6241/915/1427 +f 6241/915/1427 6242/916/1428 6240/914/1426 +f 6242/916/1428 6241/915/1427 6243/917/1429 +f 6243/917/1429 6244/918/1430 6242/916/1428 +f 6244/919/1430 6243/920/1429 6245/921/1431 +f 6245/921/1431 6246/922/1432 6244/919/1430 +f 6246/922/1432 6245/921/1431 6247/923/1433 +f 6247/923/1433 6248/924/1434 6246/922/1432 +f 6248/924/1434 6247/923/1433 6249/925/1435 +f 6249/925/1435 6250/926/1436 6248/924/1434 +f 6250/926/1436 6249/925/1435 6236/927/1422 +f 6236/927/1422 6235/928/1421 6250/926/1436 +f 6236/910/1422 6251/929/1437 6252/930/1438 +f 6252/930/1438 6237/911/1423 6236/910/1422 +f 6237/911/1423 6252/930/1438 6253/931/1439 +f 6253/931/1439 6239/913/1425 6237/911/1423 +f 6239/913/1425 6253/931/1439 6254/932/1440 +f 6254/932/1440 6241/915/1427 6239/913/1425 +f 6241/915/1427 6254/932/1440 6255/933/1441 +f 6255/933/1441 6243/917/1429 6241/915/1427 +f 6243/920/1429 6255/934/1441 6256/935/1442 +f 6256/935/1442 6245/921/1431 6243/920/1429 +f 6245/921/1431 6256/935/1442 6257/936/1443 +f 6257/936/1443 6247/923/1433 6245/921/1431 +f 6247/923/1433 6257/936/1443 6258/937/1444 +f 6258/937/1444 6249/925/1435 6247/923/1433 +f 6249/925/1435 6258/937/1444 6251/938/1437 +f 6251/938/1437 6236/927/1422 6249/925/1435 +f 6251/929/1437 6259/939/1445 6260/940/1446 +f 6260/940/1446 6252/930/1438 6251/929/1437 +f 6252/930/1438 6260/940/1446 6261/941/1447 +f 6261/941/1447 6253/931/1439 6252/930/1438 +f 6253/931/1439 6261/941/1447 6262/942/1448 +f 6262/942/1448 6254/932/1440 6253/931/1439 +f 6254/932/1440 6262/942/1448 6263/943/1449 +f 6263/943/1449 6255/933/1441 6254/932/1440 +f 6255/934/1441 6263/944/1449 6264/945/1450 +f 6264/945/1450 6256/935/1442 6255/934/1441 +f 6256/935/1442 6264/945/1450 6265/946/1451 +f 6265/946/1451 6257/936/1443 6256/935/1442 +f 6257/936/1443 6265/946/1451 6266/947/1452 +f 6266/947/1452 6258/937/1444 6257/936/1443 +f 6258/937/1444 6266/947/1452 6259/948/1445 +f 6259/948/1445 6251/938/1437 6258/937/1444 +f 6222/892/1408 6221/891/1407 6235/909/1421 +f 6235/909/1421 6238/912/1424 6222/892/1408 +f 6240/914/1426 6224/894/1410 6222/892/1408 +f 6222/892/1408 6238/912/1424 6240/914/1426 +f 6226/896/1412 6224/894/1410 6240/914/1426 +f 6240/914/1426 6242/916/1428 6226/896/1412 +f 6244/918/1430 6228/898/1414 6226/896/1412 +f 6226/896/1412 6242/916/1428 6244/918/1430 +f 6230/902/1416 6228/901/1414 6244/919/1430 +f 6244/919/1430 6246/922/1432 6230/902/1416 +f 6248/924/1434 6232/904/1418 6230/902/1416 +f 6230/902/1416 6246/922/1432 6248/924/1434 +f 6250/926/1436 6234/906/1420 6232/904/1418 +f 6232/904/1418 6248/924/1434 6250/926/1436 +f 6235/928/1421 6221/908/1407 6234/906/1420 +f 6234/906/1420 6250/926/1436 6235/928/1421 +f 6259/939/1453 6267/949/1453 6268/950/1453 +f 6268/950/1453 6260/940/1453 6259/939/1453 +f 6260/940/1454 6268/950/1454 6269/951/1454 +f 6269/951/1454 6261/941/1454 6260/940/1454 +f 6261/941/1455 6269/951/1455 6270/952/1455 +f 6270/952/1455 6262/942/1455 6261/941/1455 +f 6262/942/1456 6270/952/1456 6271/953/1456 +f 6271/953/1456 6263/943/1456 6262/942/1456 +f 6263/944/1457 6271/954/1457 6272/955/1457 +f 6272/955/1457 6264/945/1457 6263/944/1457 +f 6264/945/1458 6272/955/1458 6273/956/1458 +f 6273/956/1458 6265/946/1458 6264/945/1458 +f 6265/946/1459 6273/956/1459 6274/957/1459 +f 6274/957/1459 6266/947/1459 6265/946/1459 +f 6266/947/1460 6274/957/1460 6267/958/1460 +f 6267/958/1460 6259/948/1460 6266/947/1460 +f 6267/949/1461 6275/959/1461 6276/960/1461 +f 6276/960/1461 6268/950/1461 6267/949/1461 +f 6268/950/1462 6276/960/1462 6277/961/1462 +f 6277/961/1462 6269/951/1462 6268/950/1462 +f 6269/951/1463 6277/961/1463 6278/962/1463 +f 6278/962/1463 6270/952/1463 6269/951/1463 +f 6270/952/1464 6278/962/1464 6279/963/1464 +f 6279/963/1464 6271/953/1464 6270/952/1464 +f 6271/954/1465 6279/964/1465 6280/965/1465 +f 6280/965/1465 6272/955/1465 6271/954/1465 +f 6272/955/1466 6280/965/1466 6281/966/1466 +f 6281/966/1466 6273/956/1466 6272/955/1466 +f 6273/956/1467 6281/966/1467 6282/967/1467 +f 6282/967/1467 6274/957/1467 6273/956/1467 +f 6274/957/1468 6282/967/1468 6275/968/1468 +f 6275/968/1469 6267/958/1469 6274/957/1469 +f 6275/959/1453 6283/969/1453 6284/970/1453 +f 6284/970/1453 6276/960/1453 6275/959/1453 +f 6276/960/1470 6284/970/1470 6285/971/1470 +f 6285/971/1470 6277/961/1470 6276/960/1470 +f 6277/961/1471 6285/971/1471 6286/972/1471 +f 6286/972/1471 6278/962/1471 6277/961/1471 +f 6278/962/1472 6286/972/1472 6287/973/1472 +f 6287/973/1472 6279/963/1472 6278/962/1472 +f 6279/964/1473 6287/974/1473 6288/975/1473 +f 6288/975/1474 6280/965/1474 6279/964/1474 +f 6280/965/1475 6288/975/1475 6289/976/1475 +f 6289/976/1458 6281/966/1458 6280/965/1458 +f 6281/966/1476 6289/976/1476 6290/977/1476 +f 6290/977/1476 6282/967/1476 6281/966/1476 +f 6282/967/1460 6290/977/1460 6283/978/1460 +f 6283/978/1460 6275/968/1460 6282/967/1460 +f 6283/969/1477 6291/979/1477 6292/980/1477 +f 6292/980/1478 6284/970/1478 6283/969/1478 +f 6284/970/1479 6292/980/1479 6293/981/1479 +f 6293/981/1480 6285/971/1480 6284/970/1480 +f 6285/971/1481 6293/981/1481 6294/982/1481 +f 6294/982/1482 6286/972/1482 6285/971/1482 +f 6286/972/1483 6294/982/1483 6295/983/1483 +f 6295/983/1484 6287/973/1484 6286/972/1484 +f 6287/974/1485 6295/984/1485 6296/985/1485 +f 6296/985/1485 6288/975/1485 6287/974/1485 +f 6288/975/1486 6296/985/1486 6297/986/1486 +f 6297/986/1486 6289/976/1486 6288/975/1486 +f 6289/976/1487 6297/986/1487 6298/987/1487 +f 6298/987/1487 6290/977/1487 6289/976/1487 +f 6290/977/1488 6298/987/1488 6291/988/1488 +f 6291/988/1488 6283/978/1488 6290/977/1488 +f 6291/979/1489 6299/989/1489 6292/980/1489 +f 6292/980/1490 6299/989/1490 6293/981/1490 +f 6293/981/1491 6299/989/1491 6294/982/1491 +f 6294/982/1492 6299/989/1492 6295/983/1492 +f 6295/984/1493 6299/990/1493 6296/985/1493 +f 6296/985/1494 6299/990/1494 6297/986/1494 +f 6297/986/1495 6299/990/1495 6298/987/1495 +f 6298/987/1496 6299/990/1496 6291/988/1496 +f 6300/991/1497 6301/992/1498 6302/993/1499 +f 6302/993/1499 6303/994/1500 6300/991/1497 +f 6301/992/1498 6304/995/1501 6305/996/1502 +f 6305/996/1502 6302/993/1499 6301/992/1498 +f 6304/995/1501 6306/997/1503 6307/998/1504 +f 6307/998/1504 6305/996/1502 6304/995/1501 +f 6303/994/1500 6302/993/1499 6308/999/1505 +f 6308/999/1505 6309/1000/1506 6303/994/1500 +f 6302/993/1499 6305/996/1502 6310/1001/1507 +f 6310/1001/1507 6308/999/1505 6302/993/1499 +f 6305/996/1502 6307/998/1504 6311/1002/1508 +f 6311/1002/1508 6310/1001/1507 6305/996/1502 +f 6309/1003/1509 6308/999/1510 6310/1001/1511 +f 6310/1001/1511 6311/1004/1511 6309/1003/1509 +f 6311/1004/1511 6312/1005/1509 6309/1003/1509 +f 6313/991/1512 6314/994/1513 6315/993/1514 +f 6315/993/1514 6316/992/1515 6313/991/1512 +f 6316/992/1515 6315/993/1514 6317/996/1516 +f 6317/996/1516 6318/995/1517 6316/992/1515 +f 6318/995/1517 6317/996/1516 6319/998/1518 +f 6319/998/1518 6320/997/1519 6318/995/1517 +f 6314/994/1513 6321/1000/1520 6322/999/1521 +f 6322/999/1521 6315/993/1514 6314/994/1513 +f 6315/993/1514 6322/999/1521 6323/1001/1522 +f 6323/1001/1522 6317/996/1516 6315/993/1514 +f 6317/996/1516 6323/1001/1522 6324/1002/1523 +f 6324/1002/1523 6319/998/1518 6317/996/1516 +f 6321/1003/1524 6324/1004/1525 6323/1001/1525 +f 6323/1001/1525 6322/999/1526 6321/1003/1524 +f 6324/1004/1525 6321/1003/1524 6325/1005/1527 +f 6326/1006/1528 6327/1007/1528 6328/1008/1528 +f 6328/1008/1528 6329/1009/1528 6326/1006/1528 +f 6329/1010/1527 6328/1011/1527 6330/1012/1527 +f 6330/1012/1527 6331/1013/1527 6329/1010/1527 +f 6331/1009/1529 6330/1008/1529 6332/1007/1529 +f 6332/1007/1529 6333/1006/1529 6331/1009/1529 +f 6333/1013/1511 6332/1012/1511 6327/1011/1511 +f 6327/1011/1511 6326/1010/1511 6333/1013/1511 +f 6334/689/1530 6335/690/1531 6336/691/1532 +f 6336/691/1532 6337/692/1533 6334/689/1530 +f 6338/693/1534 6335/690/1535 6334/689/1536 +f 6334/689/1536 6339/694/1536 6338/693/1534 +f 6340/695/1537 6341/696/1538 6342/697/1539 +f 6342/697/1539 6343/698/1539 6340/695/1537 +f 6344/699/1540 6345/700/1540 6346/701/1541 +f 6346/701/1541 6347/702/1541 6344/699/1540 +f 6348/703/1542 6337/692/1543 6349/704/1544 +f 6349/704/1544 6350/705/1544 6348/703/1542 +f 6342/697/1545 6341/696/1546 6336/691/1532 +f 6336/691/1532 6335/690/1531 6342/697/1545 +f 6343/698/1547 6342/697/1547 6335/690/1535 +f 6335/690/1535 6338/706/1534 6343/698/1547 +f 6350/707/1548 6349/704/1548 6345/700/1540 +f 6345/700/1540 6344/699/1540 6350/707/1548 +f 6345/700/1549 6349/704/1550 6337/692/1533 +f 6337/692/1533 6336/691/1532 6345/700/1549 +f 6347/708/1551 6346/701/1551 6341/696/1538 +f 6341/696/1538 6340/695/1537 6347/708/1551 +f 6339/694/1552 6334/689/1553 6337/692/1543 +f 6337/692/1543 6348/703/1542 6339/694/1552 +f 6341/696/1546 6346/701/1554 6345/700/1549 +f 6345/700/1549 6336/691/1532 6341/696/1546 +f 6351/1014/1555 6352/1015/1555 6353/1016/1555 +f 6353/1016/1555 6354/1017/1555 6351/1014/1555 +f 6355/1018/1556 6356/1019/1556 6357/1020/1556 +f 6357/1020/1556 6358/1021/1556 6355/1018/1556 +f 6352/1022/1557 6351/1023/1558 6359/1024/1557 +f 6359/1024/1557 6360/1025/1559 6352/1022/1557 +f 6353/1026/1560 6352/1027/1560 6360/1028/1561 +f 6360/1028/1561 6361/1029/1561 6353/1026/1560 +f 6354/1023/1562 6353/1022/1562 6361/1025/1563 +f 6361/1025/1563 6362/1024/1562 6354/1023/1562 +f 6351/1027/1564 6354/1026/1564 6362/1029/1564 +f 6362/1029/1564 6359/1028/1565 6351/1027/1564 +f 6358/1030/1566 6363/1031/1567 6364/1032/1568 +f 6364/1032/1568 6355/1033/1566 6358/1030/1566 +f 6357/1034/1569 6365/1035/1570 6363/1036/1570 +f 6363/1036/1570 6358/1037/1569 6357/1034/1569 +f 6356/1033/1571 6366/1032/1572 6365/1031/1572 +f 6365/1031/1572 6357/1030/1571 6356/1033/1571 +f 6355/1037/1573 6364/1036/1574 6366/1035/1574 +f 6366/1035/1574 6356/1034/1573 6355/1037/1573 +f 6363/1031/1567 6360/1025/1559 6359/1024/1557 +f 6359/1024/1557 6364/1032/1568 6363/1031/1567 +f 6367/1035/1575 6368/1029/1575 6369/1028/1575 +f 6369/1028/1575 6370/1036/1561 6367/1035/1575 +f 6366/1032/1572 6362/1024/1562 6361/1025/1563 +f 6361/1025/1563 6365/1031/1572 6366/1032/1572 +f 6371/1036/1576 6372/1028/1576 6373/1029/1576 +f 6373/1029/1576 6374/1035/1576 6371/1036/1576 +f 6365/1038/1556 6367/1039/1556 6370/1040/1556 +f 6370/1040/1556 6363/1041/1556 6365/1038/1556 +f 6363/1031/1559 6370/1042/1559 6369/1043/1559 +f 6369/1043/1559 6360/1025/1559 6363/1031/1559 +f 6360/1041/1555 6369/1040/1555 6368/1039/1555 +f 6368/1039/1555 6361/1038/1555 6360/1041/1555 +f 6361/1025/1563 6368/1043/1563 6367/1042/1563 +f 6367/1042/1563 6365/1031/1563 6361/1025/1563 +f 6359/1024/1557 6372/1044/1557 6371/1045/1557 +f 6371/1045/1557 6364/1032/1557 6359/1024/1557 +f 6364/1040/1556 6371/1041/1556 6374/1038/1556 +f 6374/1038/1556 6366/1039/1556 6364/1040/1556 +f 6366/1032/1563 6374/1045/1563 6373/1044/1563 +f 6373/1044/1562 6362/1024/1562 6366/1032/1562 +f 6362/1039/1555 6373/1038/1555 6372/1041/1555 +f 6372/1041/1555 6359/1040/1555 6362/1039/1555 +f 6375/250/1577 6376/251/1578 6377/252/1579 +f 6377/252/1579 6378/253/1580 6375/250/1577 +f 6379/254/1581 6375/250/1577 6378/253/1580 +f 6378/253/1580 6380/255/1582 6379/254/1581 +f 6381/256/1583 6379/254/1581 6380/255/1582 +f 6380/255/1582 6382/257/1584 6381/256/1583 +f 6383/258/1585 6381/256/1583 6382/257/1584 +f 6382/257/1584 6384/259/1586 6383/258/1585 +f 6385/260/1587 6383/261/1585 6384/262/1586 +f 6384/262/1586 6386/263/1588 6385/260/1587 +f 6387/264/1589 6385/260/1587 6386/263/1588 +f 6386/263/1588 6388/265/1590 6387/264/1589 +f 6389/266/1591 6387/264/1589 6388/265/1590 +f 6388/265/1590 6390/267/1592 6389/266/1591 +f 6376/251/1578 6389/266/1591 6390/267/1592 +f 6390/267/1592 6377/252/1579 6376/251/1578 +f 6391/268/1593 6391/268/1594 6376/251/1578 +f 6376/251/1578 6375/250/1577 6391/268/1593 +f 6391/268/1595 6391/268/1593 6375/250/1577 +f 6375/250/1577 6379/254/1581 6391/268/1595 +f 6391/269/1596 6391/268/1595 6379/254/1581 +f 6379/254/1581 6381/256/1583 6391/269/1596 +f 6391/269/1597 6391/269/1596 6381/256/1583 +f 6381/256/1583 6383/258/1585 6391/269/1597 +f 6391/268/1598 6391/269/1597 6383/261/1585 +f 6383/261/1585 6385/260/1587 6391/268/1598 +f 6391/268/1599 6391/268/1598 6385/260/1587 +f 6385/260/1587 6387/264/1589 6391/268/1599 +f 6391/268/1600 6391/268/1599 6387/264/1589 +f 6387/264/1589 6389/266/1591 6391/268/1600 +f 6391/268/1594 6391/268/1600 6389/266/1591 +f 6389/266/1591 6376/251/1578 6391/268/1594 +f 6391/269/2 6391/269/2 6391/268/2 +f 6391/268/2 6391/268/2 6391/268/2 +f 6391/268/2 6391/268/2 6391/268/2 +f 6391/268/2 6391/268/2 6391/268/2 +f 6391/269/2 6391/268/2 6391/268/2 +f 6391/269/2 6391/268/2 6391/268/2 +f 6392/270/1601 6393/271/1601 6378/253/1601 +f 6378/253/1601 6377/252/1601 6392/270/1601 +f 6393/271/1602 6394/272/1602 6380/255/1602 +f 6380/255/1603 6378/253/1603 6393/271/1603 +f 6394/272/1604 6395/273/1604 6382/257/1604 +f 6382/257/1604 6380/255/1604 6394/272/1604 +f 6395/273/1605 6396/274/1605 6384/259/1605 +f 6384/259/1605 6382/257/1605 6395/273/1605 +f 6396/275/1606 6397/276/1606 6386/263/1606 +f 6386/263/1606 6384/262/1606 6396/275/1606 +f 6397/276/1607 6398/277/1607 6388/265/1607 +f 6388/265/1607 6386/263/1607 6397/276/1607 +f 6398/277/1608 6399/278/1608 6390/267/1608 +f 6390/267/1609 6388/265/1609 6398/277/1609 +f 6399/278/1610 6392/270/1610 6377/252/1610 +f 6377/252/1610 6390/267/1610 6399/278/1610 +f 6400/320/1611 6401/321/1612 6402/322/1613 +f 6402/322/1613 6403/323/1614 6400/320/1611 +f 6404/324/1615 6400/320/1611 6403/323/1614 +f 6403/323/1614 6405/325/1616 6404/324/1615 +f 6406/326/1617 6404/324/1615 6405/325/1616 +f 6405/325/1616 6407/327/1618 6406/326/1617 +f 6408/328/1619 6406/326/1617 6407/327/1618 +f 6407/327/1618 6409/329/1620 6408/328/1619 +f 6410/330/1621 6408/328/1619 6409/329/1620 +f 6409/329/1620 6411/331/1620 6410/330/1621 +f 6412/332/1622 6413/333/1623 6401/321/1612 +f 6401/321/1612 6400/320/1611 6412/332/1622 +f 6412/332/1622 6400/320/1611 6404/324/1615 +f 6404/324/1615 6414/334/1624 6412/332/1622 +f 6414/334/1624 6404/324/1615 6406/326/1617 +f 6406/326/1617 6415/335/1625 6414/334/1624 +f 6415/335/1625 6406/326/1617 6408/328/1619 +f 6408/328/1619 6416/336/1626 6415/335/1625 +f 6417/337/1627 6416/336/1626 6408/328/1619 +f 6408/328/1619 6410/330/1621 6417/337/1627 +f 6418/338/1628 6419/339/1629 6420/340/1630 +f 6420/340/1630 6421/341/1631 6418/338/1628 +f 6422/342/1632 6418/338/1628 6421/341/1631 +f 6421/341/1631 6423/343/1633 6422/342/1632 +f 6424/344/1634 6422/342/1632 6423/343/1633 +f 6423/343/1633 6425/345/1635 6424/344/1634 +f 6426/346/1636 6424/344/1634 6425/345/1635 +f 6425/345/1635 6427/347/1637 6426/346/1636 +f 6428/348/1638 6426/346/1636 6427/347/1637 +f 6427/347/1637 6417/349/1639 6428/348/1638 +f 6429/350/1640 6430/351/1641 6419/339/1629 +f 6419/339/1629 6418/338/1628 6429/350/1640 +f 6431/352/1642 6429/350/1640 6418/338/1628 +f 6418/338/1628 6422/342/1632 6431/352/1642 +f 6432/353/1643 6431/352/1642 6422/342/1632 +f 6422/342/1632 6424/344/1634 6432/353/1643 +f 6433/354/1644 6432/353/1643 6424/344/1634 +f 6424/344/1634 6426/346/1636 6433/354/1644 +f 6434/355/1645 6433/354/1644 6426/346/1636 +f 6426/346/1636 6428/348/1638 6434/355/1645 +f 6435/356/1646 6436/357/1647 6430/351/1641 +f 6430/351/1641 6429/350/1640 6435/356/1646 +f 6437/358/1648 6435/356/1646 6429/350/1640 +f 6429/350/1640 6431/352/1642 6437/358/1648 +f 6438/359/1649 6437/358/1648 6431/352/1642 +f 6431/352/1642 6432/353/1643 6438/359/1649 +f 6439/360/1295 6438/359/1649 6432/353/1643 +f 6432/353/1643 6433/354/1644 6439/360/1295 +f 6440/361/1650 6439/360/1295 6433/354/1644 +f 6433/354/1644 6434/355/1645 6440/361/1650 +f 6441/362/1651 6442/363/1652 6436/357/1647 +f 6436/357/1647 6435/356/1646 6441/362/1651 +f 6443/364/1653 6441/362/1651 6435/356/1646 +f 6435/356/1646 6437/358/1648 6443/364/1653 +f 6444/365/1654 6443/364/1653 6437/358/1648 +f 6437/358/1648 6438/359/1649 6444/365/1654 +f 6445/366/1655 6444/365/1654 6438/359/1649 +f 6438/359/1649 6439/360/1295 6445/366/1655 +f 6446/367/1655 6445/366/1655 6439/360/1295 +f 6439/360/1295 6440/361/1650 6446/367/1655 +f 6403/323/1614 6402/322/1613 6442/368/1652 +f 6442/368/1652 6441/369/1651 6403/323/1614 +f 6405/325/1616 6403/323/1614 6441/369/1651 +f 6441/369/1651 6443/370/1653 6405/325/1616 +f 6407/327/1618 6405/325/1616 6443/370/1653 +f 6443/370/1653 6444/371/1654 6407/327/1618 +f 6409/329/1620 6407/327/1618 6444/371/1654 +f 6444/371/1654 6445/372/1655 6409/329/1620 +f 6411/331/1620 6409/329/1620 6445/372/1655 +f 6445/372/1655 6446/373/1655 6411/331/1620 +f 6447/250/1656 6448/251/1657 6449/252/1658 +f 6449/252/1658 6450/253/1659 6447/250/1656 +f 6451/254/1660 6447/250/1656 6450/253/1659 +f 6450/253/1659 6452/255/1661 6451/254/1660 +f 6453/256/1662 6451/254/1660 6452/255/1661 +f 6452/255/1661 6454/257/1663 6453/256/1662 +f 6455/258/1664 6453/256/1662 6454/257/1663 +f 6454/257/1663 6456/259/1665 6455/258/1664 +f 6457/260/1666 6455/261/1664 6456/262/1665 +f 6456/262/1665 6458/263/1667 6457/260/1666 +f 6459/264/1668 6457/260/1666 6458/263/1667 +f 6458/263/1667 6460/265/1669 6459/264/1668 +f 6461/266/1670 6459/264/1668 6460/265/1669 +f 6460/265/1669 6462/267/1671 6461/266/1670 +f 6448/251/1657 6461/266/1670 6462/267/1671 +f 6462/267/1671 6449/252/1658 6448/251/1657 +f 6463/268/1672 6463/268/1673 6448/251/1657 +f 6448/251/1657 6447/250/1656 6463/268/1672 +f 6463/268/1674 6463/268/1672 6447/250/1656 +f 6447/250/1656 6451/254/1660 6463/268/1674 +f 6463/269/1675 6463/268/1674 6451/254/1660 +f 6451/254/1660 6453/256/1662 6463/269/1675 +f 6463/269/1676 6463/269/1675 6453/256/1662 +f 6453/256/1662 6455/258/1664 6463/269/1676 +f 6463/268/1677 6463/269/1676 6455/261/1664 +f 6455/261/1664 6457/260/1666 6463/268/1677 +f 6463/268/1678 6463/268/1677 6457/260/1666 +f 6457/260/1666 6459/264/1668 6463/268/1678 +f 6463/268/1679 6463/268/1678 6459/264/1668 +f 6459/264/1668 6461/266/1670 6463/268/1679 +f 6463/268/1673 6463/268/1679 6461/266/1670 +f 6461/266/1670 6448/251/1657 6463/268/1673 +f 6463/269/2 6463/269/2 6463/268/2 +f 6463/268/2 6463/268/2 6463/268/2 +f 6463/268/2 6463/268/2 6463/268/2 +f 6463/268/2 6463/268/2 6463/268/2 +f 6463/269/2 6463/268/2 6463/268/2 +f 6463/269/2 6463/268/2 6463/268/2 +f 6464/270/1680 6465/271/1680 6450/253/1680 +f 6450/253/1680 6449/252/1680 6464/270/1680 +f 6465/271/1681 6466/272/1681 6452/255/1681 +f 6452/255/1681 6450/253/1681 6465/271/1681 +f 6466/272/1682 6467/273/1682 6454/257/1682 +f 6454/257/1682 6452/255/1682 6466/272/1682 +f 6467/273/1683 6468/274/1683 6456/259/1683 +f 6456/259/1683 6454/257/1683 6467/273/1683 +f 6468/275/1684 6469/276/1684 6458/263/1684 +f 6458/263/1684 6456/262/1684 6468/275/1684 +f 6469/276/1685 6470/277/1685 6460/265/1685 +f 6460/265/1685 6458/263/1685 6469/276/1685 +f 6470/277/1686 6471/278/1686 6462/267/1686 +f 6462/267/1687 6460/265/1687 6470/277/1687 +f 6471/278/1688 6464/270/1688 6449/252/1688 +f 6449/252/1689 6462/267/1689 6471/278/1689 +f 6472/320/1690 6473/321/1691 6474/322/1692 +f 6474/322/1692 6475/323/1693 6472/320/1690 +f 6476/324/1694 6472/320/1690 6475/323/1693 +f 6475/323/1693 6477/325/1695 6476/324/1694 +f 6478/326/1696 6476/324/1694 6477/325/1695 +f 6477/325/1695 6479/327/1697 6478/326/1696 +f 6480/328/1698 6478/326/1696 6479/327/1697 +f 6479/327/1697 6481/329/1699 6480/328/1698 +f 6482/330/1700 6480/328/1698 6481/329/1699 +f 6481/329/1699 6483/331/1701 6482/330/1700 +f 6484/332/1702 6485/333/1703 6473/321/1691 +f 6473/321/1691 6472/320/1690 6484/332/1702 +f 6484/332/1702 6472/320/1690 6476/324/1694 +f 6476/324/1694 6486/334/1704 6484/332/1702 +f 6486/334/1704 6476/324/1694 6478/326/1696 +f 6478/326/1696 6487/335/1705 6486/334/1704 +f 6487/335/1705 6478/326/1696 6480/328/1698 +f 6480/328/1698 6488/336/1706 6487/335/1705 +f 6489/337/1707 6488/336/1706 6480/328/1698 +f 6480/328/1698 6482/330/1700 6489/337/1707 +f 6490/338/1708 6491/339/1709 6492/340/1710 +f 6492/340/1710 6493/341/1711 6490/338/1708 +f 6494/342/1712 6490/338/1708 6493/341/1711 +f 6493/341/1711 6495/343/1713 6494/342/1712 +f 6496/344/1714 6494/342/1712 6495/343/1713 +f 6495/343/1713 6497/345/1715 6496/344/1714 +f 6498/346/1716 6496/344/1714 6497/345/1715 +f 6497/345/1715 6499/347/1717 6498/346/1716 +f 6500/348/1718 6498/346/1716 6499/347/1717 +f 6499/347/1717 6489/349/1719 6500/348/1718 +f 6501/350/1720 6502/351/1721 6491/339/1709 +f 6491/339/1709 6490/338/1708 6501/350/1720 +f 6503/352/1722 6501/350/1720 6490/338/1708 +f 6490/338/1708 6494/342/1712 6503/352/1722 +f 6504/353/1723 6503/352/1722 6494/342/1712 +f 6494/342/1712 6496/344/1714 6504/353/1723 +f 6505/354/1565 6504/353/1723 6496/344/1714 +f 6496/344/1714 6498/346/1716 6505/354/1565 +f 6506/355/1724 6505/354/1565 6498/346/1716 +f 6498/346/1716 6500/348/1718 6506/355/1724 +f 6507/356/1725 6508/357/1726 6502/351/1721 +f 6502/351/1721 6501/350/1720 6507/356/1725 +f 6509/358/1727 6507/356/1725 6501/350/1720 +f 6501/350/1720 6503/352/1722 6509/358/1727 +f 6510/359/1728 6509/358/1727 6503/352/1722 +f 6503/352/1722 6504/353/1723 6510/359/1728 +f 6511/360/1729 6510/359/1728 6504/353/1723 +f 6504/353/1723 6505/354/1565 6511/360/1729 +f 6512/361/1730 6511/360/1729 6505/354/1565 +f 6505/354/1565 6506/355/1724 6512/361/1730 +f 6513/362/1731 6514/363/1732 6508/357/1726 +f 6508/357/1726 6507/356/1725 6513/362/1731 +f 6515/364/1733 6513/362/1731 6507/356/1725 +f 6507/356/1725 6509/358/1727 6515/364/1733 +f 6516/365/1734 6515/364/1733 6509/358/1727 +f 6509/358/1727 6510/359/1728 6516/365/1734 +f 6517/366/1735 6516/365/1734 6510/359/1728 +f 6510/359/1728 6511/360/1729 6517/366/1735 +f 6518/367/1736 6517/366/1735 6511/360/1729 +f 6511/360/1729 6512/361/1730 6518/367/1736 +f 6475/323/1693 6474/322/1692 6514/368/1732 +f 6514/368/1732 6513/369/1731 6475/323/1693 +f 6477/325/1695 6475/323/1693 6513/369/1731 +f 6513/369/1731 6515/370/1733 6477/325/1695 +f 6479/327/1697 6477/325/1695 6515/370/1733 +f 6515/370/1733 6516/371/1734 6479/327/1697 +f 6481/329/1699 6479/327/1697 6516/371/1734 +f 6516/371/1734 6517/372/1735 6481/329/1699 +f 6483/331/1701 6481/329/1699 6517/372/1735 +f 6517/372/1735 6518/373/1736 6483/331/1701 +f 6519/889/1737 6520/890/1738 6521/891/1739 +f 6521/891/1739 6522/892/1740 6519/889/1737 +f 6523/893/1741 6519/889/1737 6522/892/1740 +f 6522/892/1740 6524/894/1742 6523/893/1741 +f 6525/895/1743 6523/893/1741 6524/894/1742 +f 6524/894/1742 6526/896/1744 6525/895/1743 +f 6527/897/1745 6525/895/1743 6526/896/1744 +f 6526/896/1744 6528/898/1746 6527/897/1745 +f 6529/899/1747 6527/900/1745 6528/901/1746 +f 6528/901/1746 6530/902/1748 6529/899/1747 +f 6531/903/1749 6529/899/1747 6530/902/1748 +f 6530/902/1748 6532/904/1750 6531/903/1749 +f 6533/905/1751 6531/903/1749 6532/904/1750 +f 6532/904/1750 6534/906/1752 6533/905/1751 +f 6520/907/1738 6533/905/1751 6534/906/1752 +f 6534/906/1752 6521/908/1739 6520/907/1738 +f 6535/909/1753 6536/910/1754 6537/911/1755 +f 6537/911/1755 6538/912/1756 6535/909/1753 +f 6538/912/1756 6537/911/1755 6539/913/1757 +f 6539/913/1757 6540/914/1758 6538/912/1756 +f 6540/914/1758 6539/913/1757 6541/915/1759 +f 6541/915/1759 6542/916/1760 6540/914/1758 +f 6542/916/1760 6541/915/1759 6543/917/1761 +f 6543/917/1761 6544/918/1762 6542/916/1760 +f 6544/919/1762 6543/920/1761 6545/921/1763 +f 6545/921/1763 6546/922/1764 6544/919/1762 +f 6546/922/1764 6545/921/1763 6547/923/1765 +f 6547/923/1765 6548/924/1766 6546/922/1764 +f 6548/924/1766 6547/923/1765 6549/925/1767 +f 6549/925/1767 6550/926/1768 6548/924/1766 +f 6550/926/1768 6549/925/1767 6536/927/1754 +f 6536/927/1754 6535/928/1753 6550/926/1768 +f 6536/910/1754 6551/929/1769 6552/930/1770 +f 6552/930/1770 6537/911/1755 6536/910/1754 +f 6537/911/1755 6552/930/1770 6553/931/1771 +f 6553/931/1771 6539/913/1757 6537/911/1755 +f 6539/913/1757 6553/931/1771 6554/932/1772 +f 6554/932/1772 6541/915/1759 6539/913/1757 +f 6541/915/1759 6554/932/1772 6555/933/1773 +f 6555/933/1773 6543/917/1761 6541/915/1759 +f 6543/920/1761 6555/934/1773 6556/935/1774 +f 6556/935/1774 6545/921/1763 6543/920/1761 +f 6545/921/1763 6556/935/1774 6557/936/1775 +f 6557/936/1775 6547/923/1765 6545/921/1763 +f 6547/923/1765 6557/936/1775 6558/937/1776 +f 6558/937/1776 6549/925/1767 6547/923/1765 +f 6549/925/1767 6558/937/1776 6551/938/1769 +f 6551/938/1769 6536/927/1754 6549/925/1767 +f 6551/929/1769 6559/939/1777 6560/940/1778 +f 6560/940/1778 6552/930/1770 6551/929/1769 +f 6552/930/1770 6560/940/1778 6561/941/1779 +f 6561/941/1779 6553/931/1771 6552/930/1770 +f 6553/931/1771 6561/941/1779 6562/942/1780 +f 6562/942/1780 6554/932/1772 6553/931/1771 +f 6554/932/1772 6562/942/1780 6563/943/1781 +f 6563/943/1781 6555/933/1773 6554/932/1772 +f 6555/934/1773 6563/944/1781 6564/945/1782 +f 6564/945/1782 6556/935/1774 6555/934/1773 +f 6556/935/1774 6564/945/1782 6565/946/1783 +f 6565/946/1783 6557/936/1775 6556/935/1774 +f 6557/936/1775 6565/946/1783 6566/947/1784 +f 6566/947/1784 6558/937/1776 6557/936/1775 +f 6558/937/1776 6566/947/1784 6559/948/1777 +f 6559/948/1777 6551/938/1769 6558/937/1776 +f 6522/892/1740 6521/891/1739 6535/909/1753 +f 6535/909/1753 6538/912/1756 6522/892/1740 +f 6540/914/1758 6524/894/1742 6522/892/1740 +f 6522/892/1740 6538/912/1756 6540/914/1758 +f 6526/896/1744 6524/894/1742 6540/914/1758 +f 6540/914/1758 6542/916/1760 6526/896/1744 +f 6544/918/1762 6528/898/1746 6526/896/1744 +f 6526/896/1744 6542/916/1760 6544/918/1762 +f 6530/902/1748 6528/901/1746 6544/919/1762 +f 6544/919/1762 6546/922/1764 6530/902/1748 +f 6548/924/1766 6532/904/1750 6530/902/1748 +f 6530/902/1748 6546/922/1764 6548/924/1766 +f 6550/926/1768 6534/906/1752 6532/904/1750 +f 6532/904/1750 6548/924/1766 6550/926/1768 +f 6535/928/1753 6521/908/1739 6534/906/1752 +f 6534/906/1752 6550/926/1768 6535/928/1753 +f 6559/939/1785 6567/949/1785 6568/950/1785 +f 6568/950/1785 6560/940/1785 6559/939/1785 +f 6560/940/1786 6568/950/1786 6569/951/1786 +f 6569/951/1786 6561/941/1786 6560/940/1786 +f 6561/941/1787 6569/951/1787 6570/952/1787 +f 6570/952/1787 6562/942/1787 6561/941/1787 +f 6562/942/1788 6570/952/1788 6571/953/1788 +f 6571/953/1788 6563/943/1788 6562/942/1788 +f 6563/944/1789 6571/954/1789 6572/955/1789 +f 6572/955/1789 6564/945/1789 6563/944/1789 +f 6564/945/1790 6572/955/1790 6573/956/1790 +f 6573/956/1790 6565/946/1790 6564/945/1790 +f 6565/946/1791 6573/956/1791 6574/957/1791 +f 6574/957/1791 6566/947/1791 6565/946/1791 +f 6566/947/1792 6574/957/1792 6567/958/1792 +f 6567/958/1792 6559/948/1792 6566/947/1792 +f 6567/949/1793 6575/959/1793 6576/960/1793 +f 6576/960/1793 6568/950/1793 6567/949/1793 +f 6568/950/1794 6576/960/1794 6577/961/1794 +f 6577/961/1794 6569/951/1794 6568/950/1794 +f 6569/951/1795 6577/961/1795 6578/962/1795 +f 6578/962/1795 6570/952/1795 6569/951/1795 +f 6570/952/1796 6578/962/1796 6579/963/1796 +f 6579/963/1796 6571/953/1796 6570/952/1796 +f 6571/954/1797 6579/964/1797 6580/965/1797 +f 6580/965/1797 6572/955/1797 6571/954/1797 +f 6572/955/1798 6580/965/1798 6581/966/1798 +f 6581/966/1798 6573/956/1798 6572/955/1798 +f 6573/956/1799 6581/966/1799 6582/967/1799 +f 6582/967/1799 6574/957/1799 6573/956/1799 +f 6574/957/1800 6582/967/1800 6575/968/1800 +f 6575/968/1800 6567/958/1800 6574/957/1800 +f 6575/959/1785 6583/969/1785 6584/970/1785 +f 6584/970/1785 6576/960/1785 6575/959/1785 +f 6576/960/1786 6584/970/1786 6585/971/1786 +f 6585/971/1786 6577/961/1786 6576/960/1786 +f 6577/961/1787 6585/971/1787 6586/972/1787 +f 6586/972/1787 6578/962/1787 6577/961/1787 +f 6578/962/1788 6586/972/1788 6587/973/1788 +f 6587/973/1788 6579/963/1788 6578/962/1788 +f 6579/964/1789 6587/974/1789 6588/975/1789 +f 6588/975/1789 6580/965/1789 6579/964/1789 +f 6580/965/1790 6588/975/1790 6589/976/1790 +f 6589/976/1790 6581/966/1790 6580/965/1790 +f 6581/966/1791 6589/976/1791 6590/977/1791 +f 6590/977/1791 6582/967/1791 6581/966/1791 +f 6582/967/1792 6590/977/1792 6583/978/1792 +f 6583/978/1792 6575/968/1792 6582/967/1792 +f 6583/969/1801 6591/979/1801 6592/980/1801 +f 6592/980/1802 6584/970/1802 6583/969/1802 +f 6584/970/1803 6592/980/1803 6593/981/1803 +f 6593/981/1803 6585/971/1803 6584/970/1803 +f 6585/971/1804 6593/981/1804 6594/982/1804 +f 6594/982/1804 6586/972/1804 6585/971/1804 +f 6586/972/1805 6594/982/1805 6595/983/1805 +f 6595/983/1806 6587/973/1806 6586/972/1806 +f 6587/974/1807 6595/984/1807 6596/985/1807 +f 6596/985/1807 6588/975/1807 6587/974/1807 +f 6588/975/1808 6596/985/1808 6597/986/1808 +f 6597/986/1808 6589/976/1808 6588/975/1808 +f 6589/976/1809 6597/986/1809 6598/987/1809 +f 6598/987/1809 6590/977/1809 6589/976/1809 +f 6590/977/1810 6598/987/1810 6591/988/1810 +f 6591/988/1810 6583/978/1810 6590/977/1810 +f 6591/979/1811 6599/989/1811 6592/980/1811 +f 6592/980/1812 6599/989/1812 6593/981/1812 +f 6593/981/1813 6599/989/1813 6594/982/1813 +f 6594/982/1814 6599/989/1814 6595/983/1814 +f 6595/984/1815 6599/990/1815 6596/985/1815 +f 6596/985/1816 6599/990/1816 6597/986/1816 +f 6597/986/1817 6599/990/1817 6598/987/1817 +f 6598/987/1818 6599/990/1818 6591/988/1818 +f 6600/991/1819 6601/992/1820 6602/993/1821 +f 6602/993/1821 6603/994/1822 6600/991/1819 +f 6601/992/1820 6604/995/1823 6605/996/1824 +f 6605/996/1824 6602/993/1821 6601/992/1820 +f 6604/995/1823 6606/997/1825 6607/998/1826 +f 6607/998/1826 6605/996/1824 6604/995/1823 +f 6603/994/1822 6602/993/1821 6608/999/1827 +f 6608/999/1827 6609/1000/1828 6603/994/1822 +f 6602/993/1821 6605/996/1824 6610/1001/1829 +f 6610/1001/1829 6608/999/1827 6602/993/1821 +f 6605/996/1824 6607/998/1826 6611/1002/1830 +f 6611/1002/1830 6610/1001/1829 6605/996/1824 +f 6609/1003/1831 6608/999/1832 6610/1001/1831 +f 6610/1001/1831 6611/1004/1831 6609/1003/1831 +f 6611/1004/1831 6612/1005/1833 6609/1003/1831 +f 6613/991/1834 6614/994/1835 6615/993/1836 +f 6615/993/1836 6616/992/1837 6613/991/1834 +f 6616/992/1837 6615/993/1836 6617/996/1838 +f 6617/996/1838 6618/995/1839 6616/992/1837 +f 6618/995/1839 6617/996/1838 6619/998/1840 +f 6619/998/1840 6620/997/1841 6618/995/1839 +f 6614/994/1835 6621/1000/1842 6622/999/1843 +f 6622/999/1843 6615/993/1836 6614/994/1835 +f 6615/993/1836 6622/999/1843 6623/1001/1844 +f 6623/1001/1844 6617/996/1838 6615/993/1836 +f 6617/996/1838 6623/1001/1844 6624/1002/1845 +f 6624/1002/1845 6619/998/1840 6617/996/1838 +f 6621/1003/1846 6624/1004/1846 6623/1001/1847 +f 6623/1001/1847 6622/999/1847 6621/1003/1846 +f 6624/1004/1846 6621/1003/1846 6625/1005/1848 +f 6626/1006/1849 6627/1007/1849 6628/1008/1849 +f 6628/1008/1849 6629/1009/1849 6626/1006/1849 +f 6629/1010/1846 6628/1011/1846 6630/1012/1846 +f 6630/1012/1846 6631/1013/1846 6629/1010/1846 +f 6631/1009/1850 6630/1008/1850 6632/1007/1850 +f 6632/1007/1850 6633/1006/1850 6631/1009/1850 +f 6633/1013/1851 6632/1012/1851 6627/1011/1851 +f 6627/1011/1851 6626/1010/1851 6633/1013/1851 +f 6634/689/1852 6635/690/1853 6636/691/1854 +f 6636/691/1854 6637/692/1855 6634/689/1852 +f 6638/693/1856 6635/690/1857 6634/689/1858 +f 6634/689/1858 6639/694/1858 6638/693/1856 +f 6640/695/1859 6641/696/1860 6642/697/1861 +f 6642/697/1861 6643/698/1861 6640/695/1859 +f 6644/699/1862 6645/700/1862 6646/701/1863 +f 6646/701/1863 6647/702/1863 6644/699/1862 +f 6648/703/1864 6637/692/1865 6649/704/1866 +f 6649/704/1866 6650/705/1866 6648/703/1864 +f 6642/697/1867 6641/696/1868 6636/691/1854 +f 6636/691/1854 6635/690/1853 6642/697/1867 +f 6643/698/1869 6642/697/1869 6635/690/1857 +f 6635/690/1857 6638/706/1856 6643/698/1869 +f 6650/707/1870 6649/704/1870 6645/700/1862 +f 6645/700/1862 6644/699/1862 6650/707/1870 +f 6645/700/1871 6649/704/1872 6637/692/1855 +f 6637/692/1855 6636/691/1854 6645/700/1871 +f 6647/708/1873 6646/701/1873 6641/696/1860 +f 6641/696/1860 6640/695/1859 6647/708/1873 +f 6639/694/1874 6634/689/1874 6637/692/1865 +f 6637/692/1865 6648/703/1864 6639/694/1874 +f 6641/696/1868 6646/701/1875 6645/700/1871 +f 6645/700/1871 6636/691/1854 6641/696/1868 +f 6651/1014/1876 6652/1015/1877 6653/1016/1877 +f 6653/1016/1877 6654/1017/1878 6651/1014/1876 +f 6655/1018/1879 6656/1019/1879 6657/1020/1879 +f 6657/1020/1879 6658/1021/1879 6655/1018/1879 +f 6652/1022/1880 6651/1023/1880 6659/1024/1880 +f 6659/1024/1880 6660/1025/1880 6652/1022/1880 +f 6653/1026/8 6652/1027/8 6660/1028/8 +f 6660/1028/8 6661/1029/8 6653/1026/8 +f 6654/1023/1881 6653/1022/1881 6661/1025/1881 +f 6661/1025/1881 6662/1024/1881 6654/1023/1881 +f 6651/1027/2 6654/1026/2 6662/1029/2 +f 6662/1029/2 6659/1028/2 6651/1027/2 +f 6658/1030/1882 6663/1031/1883 6664/1032/1883 +f 6664/1032/1883 6655/1033/1882 6658/1030/1882 +f 6657/1034/1884 6665/1035/1884 6663/1036/1884 +f 6663/1036/1884 6658/1037/1884 6657/1034/1884 +f 6656/1033/1885 6666/1032/1886 6665/1031/1886 +f 6665/1031/1886 6657/1030/1885 6656/1033/1885 +f 6655/1037/1887 6664/1036/1887 6666/1035/1887 +f 6666/1035/1887 6656/1034/1887 6655/1037/1887 +f 6663/1031/1883 6660/1025/1880 6659/1024/1880 +f 6659/1024/1880 6664/1032/1883 6663/1031/1883 +f 6667/1035/8 6668/1029/8 6669/1028/8 +f 6669/1028/8 6670/1036/8 6667/1035/8 +f 6666/1032/1886 6662/1024/1881 6661/1025/1881 +f 6661/1025/1881 6665/1031/1886 6666/1032/1886 +f 6671/1036/2 6672/1028/2 6673/1029/2 +f 6673/1029/2 6674/1035/2 6671/1036/2 +f 6665/1038/1888 6667/1039/1888 6670/1040/1888 +f 6670/1040/1889 6663/1041/1889 6665/1038/1889 +f 6663/1031/1880 6670/1042/1880 6669/1043/1880 +f 6669/1043/1880 6660/1025/1880 6663/1031/1880 +f 6660/1041/1877 6669/1040/1877 6668/1039/1877 +f 6668/1039/1878 6661/1038/1878 6660/1041/1878 +f 6661/1025/1881 6668/1043/1881 6667/1042/1881 +f 6667/1042/1881 6665/1031/1881 6661/1025/1881 +f 6659/1024/1880 6672/1044/1880 6671/1045/1880 +f 6671/1045/1880 6664/1032/1880 6659/1024/1880 +f 6664/1040/1888 6671/1041/1888 6674/1038/1888 +f 6674/1038/1888 6666/1039/1888 6664/1040/1888 +f 6666/1032/1881 6674/1045/1881 6673/1044/1881 +f 6673/1044/1881 6662/1024/1881 6666/1032/1881 +f 6662/1039/1877 6673/1038/1877 6672/1041/1877 +f 6672/1041/1878 6659/1040/1878 6662/1039/1878 +f 6675/889/1890 6676/890/1891 6677/891/1892 +f 6677/891/1892 6678/892/1893 6675/889/1890 +f 6679/893/1894 6675/889/1890 6678/892/1893 +f 6678/892/1893 6680/894/1895 6679/893/1894 +f 6681/895/1896 6679/893/1894 6680/894/1895 +f 6680/894/1895 6682/896/1897 6681/895/1896 +f 6683/897/1898 6681/895/1896 6682/896/1897 +f 6682/896/1897 6684/898/1899 6683/897/1898 +f 6685/899/1900 6683/900/1898 6684/901/1899 +f 6684/901/1899 6686/902/1901 6685/899/1900 +f 6687/903/1902 6685/899/1900 6686/902/1901 +f 6686/902/1901 6688/904/1903 6687/903/1902 +f 6689/905/1904 6687/903/1902 6688/904/1903 +f 6688/904/1903 6690/906/1905 6689/905/1904 +f 6676/907/1891 6689/905/1904 6690/906/1905 +f 6690/906/1905 6677/908/1892 6676/907/1891 +f 6691/909/1906 6692/910/1907 6693/911/1908 +f 6693/911/1908 6694/912/1909 6691/909/1906 +f 6694/912/1909 6693/911/1908 6695/913/1910 +f 6695/913/1910 6696/914/1911 6694/912/1909 +f 6696/914/1911 6695/913/1910 6697/915/1912 +f 6697/915/1912 6698/916/1913 6696/914/1911 +f 6698/916/1913 6697/915/1912 6699/917/1914 +f 6699/917/1914 6700/918/1915 6698/916/1913 +f 6700/919/1915 6699/920/1914 6701/921/1916 +f 6701/921/1916 6702/922/1917 6700/919/1915 +f 6702/922/1917 6701/921/1916 6703/923/1918 +f 6703/923/1918 6704/924/1919 6702/922/1917 +f 6704/924/1919 6703/923/1918 6705/925/1920 +f 6705/925/1920 6706/926/1921 6704/924/1919 +f 6706/926/1921 6705/925/1920 6692/927/1907 +f 6692/927/1907 6691/928/1906 6706/926/1921 +f 6692/910/1907 6707/929/1922 6708/930/1923 +f 6708/930/1923 6693/911/1908 6692/910/1907 +f 6693/911/1908 6708/930/1923 6709/931/1924 +f 6709/931/1924 6695/913/1910 6693/911/1908 +f 6695/913/1910 6709/931/1924 6710/932/1925 +f 6710/932/1925 6697/915/1912 6695/913/1910 +f 6697/915/1912 6710/932/1925 6711/933/1926 +f 6711/933/1926 6699/917/1914 6697/915/1912 +f 6699/920/1914 6711/934/1926 6712/935/1927 +f 6712/935/1927 6701/921/1916 6699/920/1914 +f 6701/921/1916 6712/935/1927 6713/936/1928 +f 6713/936/1928 6703/923/1918 6701/921/1916 +f 6703/923/1918 6713/936/1928 6714/937/1929 +f 6714/937/1929 6705/925/1920 6703/923/1918 +f 6705/925/1920 6714/937/1929 6707/938/1922 +f 6707/938/1922 6692/927/1907 6705/925/1920 +f 6707/929/1922 6715/939/1930 6716/940/1931 +f 6716/940/1931 6708/930/1923 6707/929/1922 +f 6708/930/1923 6716/940/1931 6717/941/1932 +f 6717/941/1932 6709/931/1924 6708/930/1923 +f 6709/931/1924 6717/941/1932 6718/942/1933 +f 6718/942/1933 6710/932/1925 6709/931/1924 +f 6710/932/1925 6718/942/1933 6719/943/1934 +f 6719/943/1934 6711/933/1926 6710/932/1925 +f 6711/934/1926 6719/944/1934 6720/945/1935 +f 6720/945/1935 6712/935/1927 6711/934/1926 +f 6712/935/1927 6720/945/1935 6721/946/1936 +f 6721/946/1936 6713/936/1928 6712/935/1927 +f 6713/936/1928 6721/946/1936 6722/947/1937 +f 6722/947/1937 6714/937/1929 6713/936/1928 +f 6714/937/1929 6722/947/1937 6715/948/1930 +f 6715/948/1930 6707/938/1922 6714/937/1929 +f 6678/892/1893 6677/891/1892 6691/909/1906 +f 6691/909/1906 6694/912/1909 6678/892/1893 +f 6696/914/1911 6680/894/1895 6678/892/1893 +f 6678/892/1893 6694/912/1909 6696/914/1911 +f 6682/896/1897 6680/894/1895 6696/914/1911 +f 6696/914/1911 6698/916/1913 6682/896/1897 +f 6700/918/1915 6684/898/1899 6682/896/1897 +f 6682/896/1897 6698/916/1913 6700/918/1915 +f 6686/902/1901 6684/901/1899 6700/919/1915 +f 6700/919/1915 6702/922/1917 6686/902/1901 +f 6704/924/1919 6688/904/1903 6686/902/1901 +f 6686/902/1901 6702/922/1917 6704/924/1919 +f 6706/926/1921 6690/906/1905 6688/904/1903 +f 6688/904/1903 6704/924/1919 6706/926/1921 +f 6691/928/1906 6677/908/1892 6690/906/1905 +f 6690/906/1905 6706/926/1921 6691/928/1906 +f 6715/939/1938 6723/949/1938 6724/950/1938 +f 6724/950/1938 6716/940/1938 6715/939/1938 +f 6716/940/1939 6724/950/1939 6725/951/1939 +f 6725/951/1939 6717/941/1939 6716/940/1939 +f 6717/941/1940 6725/951/1940 6726/952/1940 +f 6726/952/1940 6718/942/1940 6717/941/1940 +f 6718/942/1941 6726/952/1941 6727/953/1941 +f 6727/953/1941 6719/943/1941 6718/942/1941 +f 6719/944/1942 6727/954/1942 6728/955/1942 +f 6728/955/1942 6720/945/1942 6719/944/1942 +f 6720/945/1943 6728/955/1943 6729/956/1943 +f 6729/956/1943 6721/946/1943 6720/945/1943 +f 6721/946/1944 6729/956/1944 6730/957/1944 +f 6730/957/1944 6722/947/1944 6721/946/1944 +f 6722/947/1945 6730/957/1945 6723/958/1945 +f 6723/958/1945 6715/948/1945 6722/947/1945 +f 6723/949/1946 6731/959/1946 6732/960/1946 +f 6732/960/1946 6724/950/1946 6723/949/1946 +f 6724/950/1947 6732/960/1947 6733/961/1947 +f 6733/961/1947 6725/951/1947 6724/950/1947 +f 6725/951/1948 6733/961/1948 6734/962/1948 +f 6734/962/1949 6726/952/1949 6725/951/1949 +f 6726/952/1950 6734/962/1950 6735/963/1950 +f 6735/963/1950 6727/953/1950 6726/952/1950 +f 6727/954/1951 6735/964/1951 6736/965/1951 +f 6736/965/1952 6728/955/1952 6727/954/1952 +f 6728/955/1953 6736/965/1953 6737/966/1953 +f 6737/966/1953 6729/956/1953 6728/955/1953 +f 6729/956/1954 6737/966/1954 6738/967/1954 +f 6738/967/1954 6730/957/1954 6729/956/1954 +f 6730/957/1955 6738/967/1955 6731/968/1955 +f 6731/968/1955 6723/958/1955 6730/957/1955 +f 6731/959/1938 6739/969/1938 6740/970/1938 +f 6740/970/1938 6732/960/1938 6731/959/1938 +f 6732/960/1939 6740/970/1939 6741/971/1939 +f 6741/971/1939 6733/961/1939 6732/960/1939 +f 6733/961/1940 6741/971/1940 6742/972/1940 +f 6742/972/1940 6734/962/1940 6733/961/1940 +f 6734/962/1941 6742/972/1941 6743/973/1941 +f 6743/973/1941 6735/963/1941 6734/962/1941 +f 6735/964/1942 6743/974/1942 6744/975/1942 +f 6744/975/1942 6736/965/1942 6735/964/1942 +f 6736/965/1956 6744/975/1956 6745/976/1956 +f 6745/976/1956 6737/966/1956 6736/965/1956 +f 6737/966/1944 6745/976/1944 6746/977/1944 +f 6746/977/1944 6738/967/1944 6737/966/1944 +f 6738/967/1945 6746/977/1945 6739/978/1945 +f 6739/978/1945 6731/968/1945 6738/967/1945 +f 6739/969/1957 6747/979/1957 6748/980/1957 +f 6748/980/1958 6740/970/1958 6739/969/1958 +f 6740/970/1959 6748/980/1959 6749/981/1959 +f 6749/981/1960 6741/971/1960 6740/970/1960 +f 6741/971/1961 6749/981/1961 6750/982/1961 +f 6750/982/1962 6742/972/1962 6741/971/1963 +f 6742/972/1964 6750/982/1964 6751/983/1964 +f 6751/983/1965 6743/973/1965 6742/972/1965 +f 6743/974/1966 6751/984/1966 6752/985/1966 +f 6752/985/1967 6744/975/1967 6743/974/1967 +f 6744/975/1968 6752/985/1968 6753/986/1968 +f 6753/986/1968 6745/976/1968 6744/975/1968 +f 6745/976/1969 6753/986/1969 6754/987/1969 +f 6754/987/1969 6746/977/1969 6745/976/1969 +f 6746/977/1970 6754/987/1970 6747/988/1970 +f 6747/988/1970 6739/978/1970 6746/977/1970 +f 6747/979/1971 6755/989/1971 6748/980/1971 +f 6748/980/1972 6755/989/1972 6749/981/1972 +f 6749/981/1973 6755/989/1973 6750/982/1973 +f 6750/982/1974 6755/989/1974 6751/983/1974 +f 6751/984/1975 6755/990/1975 6752/985/1975 +f 6752/985/1976 6755/990/1976 6753/986/1976 +f 6753/986/1977 6755/990/1977 6754/987/1977 +f 6754/987/1978 6755/990/1978 6747/988/1978 +f 6756/991/1979 6757/992/1980 6758/993/1981 +f 6758/993/1981 6759/994/1982 6756/991/1979 +f 6757/992/1980 6760/995/1983 6761/996/1984 +f 6761/996/1984 6758/993/1981 6757/992/1980 +f 6760/995/1983 6762/997/1985 6763/998/1986 +f 6763/998/1986 6761/996/1984 6760/995/1983 +f 6759/994/1982 6758/993/1981 6764/999/1987 +f 6764/999/1987 6765/1000/1988 6759/994/1982 +f 6758/993/1981 6761/996/1984 6766/1001/1989 +f 6766/1001/1989 6764/999/1987 6758/993/1981 +f 6761/996/1984 6763/998/1986 6767/1002/1990 +f 6767/1002/1990 6766/1001/1989 6761/996/1984 +f 6765/1003/1991 6764/999/1992 6766/1001/1991 +f 6766/1001/1991 6767/1004/1655 6765/1003/1991 +f 6767/1004/1655 6768/1005/1991 6765/1003/1991 +f 6769/991/1993 6770/994/1994 6771/993/1995 +f 6771/993/1995 6772/992/1996 6769/991/1993 +f 6772/992/1996 6771/993/1995 6773/996/1997 +f 6773/996/1997 6774/995/1998 6772/992/1996 +f 6774/995/1998 6773/996/1997 6775/998/1999 +f 6775/998/1999 6776/997/2000 6774/995/1998 +f 6770/994/1994 6777/1000/2001 6778/999/2002 +f 6778/999/2002 6771/993/1995 6770/994/1994 +f 6771/993/1995 6778/999/2002 6779/1001/2003 +f 6779/1001/2003 6773/996/1997 6771/993/1995 +f 6773/996/1997 6779/1001/2003 6780/1002/2004 +f 6780/1002/2004 6775/998/1999 6773/996/1997 +f 6777/1003/2005 6780/1004/2005 6779/1001/2006 +f 6779/1001/2006 6778/999/2005 6777/1003/2005 +f 6780/1004/2005 6777/1003/2005 6781/1005/2007 +f 6782/1006/2008 6783/1007/2008 6784/1008/2008 +f 6784/1008/2008 6785/1009/2008 6782/1006/2008 +f 6785/1010/2009 6784/1011/2010 6786/1012/2009 +f 6786/1012/2009 6787/1013/2009 6785/1010/2009 +f 6787/1009/1644 6786/1008/1644 6788/1007/1644 +f 6788/1007/1644 6789/1006/1645 6787/1009/1644 +f 6789/1013/1991 6788/1012/1991 6783/1011/1991 +f 6783/1011/1991 6782/1010/1991 6789/1013/1991 +f 6790/689/2011 6791/690/2012 6792/691/2013 +f 6792/691/2013 6793/692/2014 6790/689/2011 +f 6794/693/2015 6791/690/2016 6790/689/2017 +f 6790/689/2017 6795/694/2017 6794/693/2015 +f 6796/695/2018 6797/696/2019 6798/697/2020 +f 6798/697/2020 6799/698/2020 6796/695/2018 +f 6800/699/2021 6801/700/2021 6802/701/2022 +f 6802/701/2022 6803/702/2023 6800/699/2021 +f 6804/703/2024 6793/692/2025 6805/704/2026 +f 6805/704/2026 6806/705/2026 6804/703/2024 +f 6798/697/2027 6797/696/2028 6792/691/2013 +f 6792/691/2013 6791/690/2012 6798/697/2027 +f 6799/698/2029 6798/697/2029 6791/690/2016 +f 6791/690/2016 6794/706/2015 6799/698/2029 +f 6806/707/2030 6805/704/2030 6801/700/2021 +f 6801/700/2021 6800/699/2021 6806/707/2030 +f 6801/700/2031 6805/704/2032 6793/692/2014 +f 6793/692/2014 6792/691/2013 6801/700/2031 +f 6803/708/2033 6802/701/2034 6797/696/2019 +f 6797/696/2019 6796/695/2018 6803/708/2033 +f 6795/694/2035 6790/689/2035 6793/692/2025 +f 6793/692/2025 6804/703/2024 6795/694/2035 +f 6797/696/2028 6802/701/2036 6801/700/2031 +f 6801/700/2031 6792/691/2013 6797/696/2028 +f 6807/1014/2037 6808/1015/2037 6809/1016/2037 +f 6809/1016/2037 6810/1017/2037 6807/1014/2037 +f 6811/1018/2038 6812/1019/2038 6813/1020/2038 +f 6813/1020/2038 6814/1021/2038 6811/1018/2038 +f 6808/1022/2039 6807/1023/2039 6815/1024/2040 +f 6815/1024/2040 6816/1025/2040 6808/1022/2039 +f 6809/1026/2041 6808/1027/2041 6816/1028/2041 +f 6816/1028/2041 6817/1029/2041 6809/1026/2041 +f 6810/1023/2042 6809/1022/2042 6817/1025/2043 +f 6817/1025/2043 6818/1024/2043 6810/1023/2042 +f 6807/1027/2044 6810/1026/2044 6818/1029/2044 +f 6818/1029/2044 6815/1028/2044 6807/1027/2044 +f 6814/1030/2045 6819/1031/2046 6820/1032/2046 +f 6820/1032/2046 6811/1033/2045 6814/1030/2045 +f 6813/1034/2047 6821/1035/2048 6819/1036/2048 +f 6819/1036/2048 6814/1037/2047 6813/1034/2047 +f 6812/1033/2049 6822/1032/2050 6821/1031/2050 +f 6821/1031/2050 6813/1030/2049 6812/1033/2049 +f 6811/1037/2051 6820/1036/2052 6822/1035/2052 +f 6822/1035/2052 6812/1034/2051 6811/1037/2051 +f 6819/1031/2046 6816/1025/2040 6815/1024/2040 +f 6815/1024/2040 6820/1032/2046 6819/1031/2046 +f 6823/1035/2041 6824/1029/2041 6825/1028/2041 +f 6825/1028/2041 6826/1036/2041 6823/1035/2041 +f 6822/1032/2050 6818/1024/2043 6817/1025/2043 +f 6817/1025/2043 6821/1031/2050 6822/1032/2050 +f 6827/1036/2053 6828/1028/2053 6829/1029/2053 +f 6829/1029/2053 6830/1035/2053 6827/1036/2053 +f 6821/1038/2038 6823/1039/2038 6826/1040/2038 +f 6826/1040/2038 6819/1041/2038 6821/1038/2038 +f 6819/1031/2040 6826/1042/2040 6825/1043/2040 +f 6825/1043/2040 6816/1025/2040 6819/1031/2040 +f 6816/1041/2037 6825/1040/2037 6824/1039/2037 +f 6824/1039/2037 6817/1038/2037 6816/1041/2037 +f 6817/1025/2043 6824/1043/2043 6823/1042/2043 +f 6823/1042/2043 6821/1031/2043 6817/1025/2043 +f 6815/1024/2040 6828/1044/2040 6827/1045/2040 +f 6827/1045/2040 6820/1032/2040 6815/1024/2040 +f 6820/1040/2038 6827/1041/2038 6830/1038/2038 +f 6830/1038/2038 6822/1039/2038 6820/1040/2038 +f 6822/1032/2043 6830/1045/2043 6829/1044/2043 +f 6829/1044/2043 6818/1024/2043 6822/1032/2043 +f 6818/1039/2037 6829/1038/2037 6828/1041/2037 +f 6828/1041/2037 6815/1040/2037 6818/1039/2037 +f 6831/889/2054 6832/890/2055 6833/891/2056 +f 6833/891/2056 6834/892/2057 6831/889/2054 +f 6835/893/2058 6831/889/2054 6834/892/2057 +f 6834/892/2057 6836/894/2059 6835/893/2058 +f 6837/895/2060 6835/893/2058 6836/894/2059 +f 6836/894/2059 6838/896/2061 6837/895/2060 +f 6839/897/2062 6837/895/2060 6838/896/2061 +f 6838/896/2061 6840/898/2063 6839/897/2062 +f 6841/899/2064 6839/900/2062 6840/901/2063 +f 6840/901/2063 6842/902/2065 6841/899/2064 +f 6843/903/2066 6841/899/2064 6842/902/2065 +f 6842/902/2065 6844/904/2067 6843/903/2066 +f 6845/905/2068 6843/903/2066 6844/904/2067 +f 6844/904/2067 6846/906/2069 6845/905/2068 +f 6832/907/2055 6845/905/2068 6846/906/2069 +f 6846/906/2069 6833/908/2056 6832/907/2055 +f 6847/909/2070 6848/910/2071 6849/911/2072 +f 6849/911/2072 6850/912/2073 6847/909/2070 +f 6850/912/2073 6849/911/2072 6851/913/2074 +f 6851/913/2074 6852/914/2075 6850/912/2073 +f 6852/914/2075 6851/913/2074 6853/915/2076 +f 6853/915/2076 6854/916/2077 6852/914/2075 +f 6854/916/2077 6853/915/2076 6855/917/2078 +f 6855/917/2078 6856/918/2079 6854/916/2077 +f 6856/919/2079 6855/920/2078 6857/921/2080 +f 6857/921/2080 6858/922/2081 6856/919/2079 +f 6858/922/2081 6857/921/2080 6859/923/2082 +f 6859/923/2082 6860/924/2083 6858/922/2081 +f 6860/924/2083 6859/923/2082 6861/925/2084 +f 6861/925/2084 6862/926/2085 6860/924/2083 +f 6862/926/2085 6861/925/2084 6848/927/2071 +f 6848/927/2071 6847/928/2070 6862/926/2085 +f 6848/910/2071 6863/929/2086 6864/930/2087 +f 6864/930/2087 6849/911/2072 6848/910/2071 +f 6849/911/2072 6864/930/2087 6865/931/2088 +f 6865/931/2088 6851/913/2074 6849/911/2072 +f 6851/913/2074 6865/931/2088 6866/932/2089 +f 6866/932/2089 6853/915/2076 6851/913/2074 +f 6853/915/2076 6866/932/2089 6867/933/2090 +f 6867/933/2090 6855/917/2078 6853/915/2076 +f 6855/920/2078 6867/934/2090 6868/935/2091 +f 6868/935/2091 6857/921/2080 6855/920/2078 +f 6857/921/2080 6868/935/2091 6869/936/2092 +f 6869/936/2092 6859/923/2082 6857/921/2080 +f 6859/923/2082 6869/936/2092 6870/937/2093 +f 6870/937/2093 6861/925/2084 6859/923/2082 +f 6861/925/2084 6870/937/2093 6863/938/2086 +f 6863/938/2086 6848/927/2071 6861/925/2084 +f 6863/929/2086 6871/939/2094 6872/940/2095 +f 6872/940/2095 6864/930/2087 6863/929/2086 +f 6864/930/2087 6872/940/2095 6873/941/2096 +f 6873/941/2096 6865/931/2088 6864/930/2087 +f 6865/931/2088 6873/941/2096 6874/942/2097 +f 6874/942/2097 6866/932/2089 6865/931/2088 +f 6866/932/2089 6874/942/2097 6875/943/2098 +f 6875/943/2098 6867/933/2090 6866/932/2089 +f 6867/934/2090 6875/944/2098 6876/945/2099 +f 6876/945/2099 6868/935/2091 6867/934/2090 +f 6868/935/2091 6876/945/2099 6877/946/2100 +f 6877/946/2100 6869/936/2092 6868/935/2091 +f 6869/936/2092 6877/946/2100 6878/947/2101 +f 6878/947/2101 6870/937/2093 6869/936/2092 +f 6870/937/2093 6878/947/2101 6871/948/2094 +f 6871/948/2094 6863/938/2086 6870/937/2093 +f 6834/892/2057 6833/891/2056 6847/909/2070 +f 6847/909/2070 6850/912/2073 6834/892/2057 +f 6852/914/2075 6836/894/2059 6834/892/2057 +f 6834/892/2057 6850/912/2073 6852/914/2075 +f 6838/896/2061 6836/894/2059 6852/914/2075 +f 6852/914/2075 6854/916/2077 6838/896/2061 +f 6856/918/2079 6840/898/2063 6838/896/2061 +f 6838/896/2061 6854/916/2077 6856/918/2079 +f 6842/902/2065 6840/901/2063 6856/919/2079 +f 6856/919/2079 6858/922/2081 6842/902/2065 +f 6860/924/2083 6844/904/2067 6842/902/2065 +f 6842/902/2065 6858/922/2081 6860/924/2083 +f 6862/926/2085 6846/906/2069 6844/904/2067 +f 6844/904/2067 6860/924/2083 6862/926/2085 +f 6847/928/2070 6833/908/2056 6846/906/2069 +f 6846/906/2069 6862/926/2085 6847/928/2070 +f 6871/939/2102 6879/949/2102 6880/950/2102 +f 6880/950/2102 6872/940/2102 6871/939/2102 +f 6872/940/2103 6880/950/2103 6881/951/2103 +f 6881/951/2103 6873/941/2103 6872/940/2103 +f 6873/941/2104 6881/951/2104 6882/952/2104 +f 6882/952/2104 6874/942/2104 6873/941/2104 +f 6874/942/2105 6882/952/2105 6883/953/2105 +f 6883/953/2105 6875/943/2105 6874/942/2105 +f 6875/944/2106 6883/954/2106 6884/955/2106 +f 6884/955/2106 6876/945/2106 6875/944/2106 +f 6876/945/2107 6884/955/2107 6885/956/2107 +f 6885/956/2107 6877/946/2107 6876/945/2107 +f 6877/946/2108 6885/956/2108 6886/957/2108 +f 6886/957/2108 6878/947/2108 6877/946/2108 +f 6878/947/2109 6886/957/2109 6879/958/2109 +f 6879/958/2109 6871/948/2109 6878/947/2109 +f 6879/949/2110 6887/959/2110 6888/960/2110 +f 6888/960/2110 6880/950/2110 6879/949/2110 +f 6880/950/2111 6888/960/2111 6889/961/2111 +f 6889/961/2112 6881/951/2112 6880/950/2112 +f 6881/951/2113 6889/961/2113 6890/962/2113 +f 6890/962/2114 6882/952/2114 6881/951/2114 +f 6882/952/2115 6890/962/2115 6891/963/2115 +f 6891/963/2116 6883/953/2116 6882/952/2116 +f 6883/954/2117 6891/964/2117 6892/965/2117 +f 6892/965/2118 6884/955/2118 6883/954/2118 +f 6884/955/2119 6892/965/2119 6893/966/2119 +f 6893/966/2120 6885/956/2120 6884/955/2120 +f 6885/956/2121 6893/966/2121 6894/967/2121 +f 6894/967/2121 6886/957/2121 6885/956/2121 +f 6886/957/2122 6894/967/2122 6887/968/2122 +f 6887/968/2123 6879/958/2123 6886/957/2123 +f 6887/959/2102 6895/969/2102 6896/970/2102 +f 6896/970/2102 6888/960/2102 6887/959/2102 +f 6888/960/2124 6896/970/2124 6897/971/2124 +f 6897/971/2124 6889/961/2124 6888/960/2124 +f 6889/961/2104 6897/971/2104 6898/972/2104 +f 6898/972/2104 6890/962/2104 6889/961/2104 +f 6890/962/2125 6898/972/2125 6899/973/2125 +f 6899/973/2125 6891/963/2125 6890/962/2125 +f 6891/964/2106 6899/974/2106 6900/975/2106 +f 6900/975/2106 6892/965/2106 6891/964/2106 +f 6892/965/2126 6900/975/2126 6901/976/2126 +f 6901/976/2126 6893/966/2126 6892/965/2126 +f 6893/966/2127 6901/976/2127 6902/977/2127 +f 6902/977/2127 6894/967/2127 6893/966/2127 +f 6894/967/2128 6902/977/2128 6895/978/2128 +f 6895/978/2128 6887/968/2128 6894/967/2128 +f 6895/969/2129 6903/979/2129 6904/980/2129 +f 6904/980/2129 6896/970/2129 6895/969/2129 +f 6896/970/2130 6904/980/2130 6905/981/2130 +f 6905/981/2131 6897/971/2131 6896/970/2131 +f 6897/971/2132 6905/981/2132 6906/982/2132 +f 6906/982/2132 6898/972/2132 6897/971/2132 +f 6898/972/2133 6906/982/2133 6907/983/2133 +f 6907/983/2134 6899/973/2134 6898/972/2134 +f 6899/974/2135 6907/984/2135 6908/985/2135 +f 6908/985/2136 6900/975/2136 6899/974/2136 +f 6900/975/2137 6908/985/2137 6909/986/2137 +f 6909/986/2137 6901/976/2137 6900/975/2137 +f 6901/976/2138 6909/986/2138 6910/987/2138 +f 6910/987/2138 6902/977/2138 6901/976/2138 +f 6902/977/2139 6910/987/2139 6903/988/2139 +f 6903/988/2139 6895/978/2139 6902/977/2139 +f 6903/979/2140 6911/989/2140 6904/980/2140 +f 6904/980/2141 6911/989/2141 6905/981/2141 +f 6905/981/2142 6911/989/2142 6906/982/2142 +f 6906/982/2143 6911/989/2143 6907/983/2143 +f 6907/984/2144 6911/990/2144 6908/985/2144 +f 6908/985/2145 6911/990/2145 6909/986/2145 +f 6909/986/2146 6911/990/2146 6910/987/2146 +f 6910/987/2147 6911/990/2147 6903/988/2147 +f 6912/991/2148 6913/992/2149 6914/993/2150 +f 6914/993/2150 6915/994/2151 6912/991/2148 +f 6913/992/2149 6916/995/2152 6917/996/2153 +f 6917/996/2153 6914/993/2150 6913/992/2149 +f 6916/995/2152 6918/997/2154 6919/998/2155 +f 6919/998/2155 6917/996/2153 6916/995/2152 +f 6915/994/2151 6914/993/2150 6920/999/2156 +f 6920/999/2156 6921/1000/2157 6915/994/2151 +f 6914/993/2150 6917/996/2153 6922/1001/2158 +f 6922/1001/2158 6920/999/2156 6914/993/2150 +f 6917/996/2153 6919/998/2155 6923/1002/2159 +f 6923/1002/2159 6922/1001/2158 6917/996/2153 +f 6921/1003/406 6920/999/219 6922/1001/2160 +f 6922/1001/2160 6923/1004/2161 6921/1003/406 +f 6923/1004/2161 6924/1005/511 6921/1003/406 +f 6925/991/2162 6926/994/2163 6927/993/2164 +f 6927/993/2164 6928/992/2165 6925/991/2162 +f 6928/992/2165 6927/993/2164 6929/996/2166 +f 6929/996/2166 6930/995/2167 6928/992/2165 +f 6930/995/2167 6929/996/2166 6931/998/2168 +f 6931/998/2168 6932/997/2169 6930/995/2167 +f 6926/994/2163 6933/1000/2170 6934/999/2171 +f 6934/999/2171 6927/993/2164 6926/994/2163 +f 6927/993/2164 6934/999/2171 6935/1001/2172 +f 6935/1001/2172 6929/996/2166 6927/993/2164 +f 6929/996/2166 6935/1001/2172 6936/1002/2173 +f 6936/1002/2173 6931/998/2168 6929/996/2166 +f 6933/1003/2174 6936/1004/2175 6935/1001/501 +f 6935/1001/501 6934/999/2176 6933/1003/2174 +f 6936/1004/2175 6933/1003/2174 6937/1005/2177 +f 6938/1006/16 6939/1007/16 6940/1008/16 +f 6940/1008/16 6941/1009/16 6938/1006/16 +f 6941/1010/80 6940/1011/80 6942/1012/80 +f 6942/1012/80 6943/1013/80 6941/1010/80 +f 6943/1009/13 6942/1008/13 6944/1007/13 +f 6944/1007/13 6945/1006/13 6943/1009/13 +f 6945/1013/406 6944/1012/405 6939/1011/406 +f 6939/1011/406 6938/1010/2 6945/1013/406 +f 6946/689/2178 6947/690/2179 6948/691/2180 +f 6948/691/2180 6949/692/2181 6946/689/2178 +f 6950/693/2182 6947/690/2183 6946/689/2184 +f 6946/689/2184 6951/694/2184 6950/693/2182 +f 6952/695/2185 6953/696/2186 6954/697/2187 +f 6954/697/2187 6955/698/2187 6952/695/2185 +f 6956/699/2188 6957/700/2188 6958/701/2189 +f 6958/701/2189 6959/702/2189 6956/699/2188 +f 6960/703/2190 6949/692/2191 6961/704/2192 +f 6961/704/2192 6962/705/2192 6960/703/2190 +f 6954/697/2193 6953/696/2194 6948/691/2180 +f 6948/691/2180 6947/690/2179 6954/697/2193 +f 6955/698/2195 6954/697/2195 6947/690/2183 +f 6947/690/2183 6950/706/2182 6955/698/2195 +f 6962/707/2196 6961/704/2196 6957/700/2188 +f 6957/700/2188 6956/699/2188 6962/707/2196 +f 6957/700/2197 6961/704/2198 6949/692/2181 +f 6949/692/2181 6948/691/2180 6957/700/2197 +f 6959/708/2199 6958/701/2199 6953/696/2186 +f 6953/696/2186 6952/695/2185 6959/708/2199 +f 6951/694/2200 6946/689/2200 6949/692/2191 +f 6949/692/2191 6960/703/2190 6951/694/2200 +f 6953/696/2194 6958/701/2201 6957/700/2197 +f 6957/700/2197 6948/691/2180 6953/696/2194 +f 6963/1014/2202 6964/1015/2202 6965/1016/2202 +f 6965/1016/2202 6966/1017/2202 6963/1014/2202 +f 6967/1018/2203 6968/1019/2203 6969/1020/2203 +f 6969/1020/2203 6970/1021/2203 6967/1018/2203 +f 6964/1022/2204 6963/1023/2204 6971/1024/2204 +f 6971/1024/2204 6972/1025/2204 6964/1022/2204 +f 6965/1026/2205 6964/1027/2205 6972/1028/2206 +f 6972/1028/2206 6973/1029/2206 6965/1026/2205 +f 6966/1023/2207 6965/1022/2207 6973/1025/2207 +f 6973/1025/2207 6974/1024/2208 6966/1023/2207 +f 6963/1027/324 6966/1026/324 6974/1029/324 +f 6974/1029/324 6971/1028/324 6963/1027/324 +f 6970/1030/2209 6975/1031/2210 6976/1032/2210 +f 6976/1032/2210 6967/1033/2209 6970/1030/2209 +f 6969/1034/2211 6977/1035/2212 6975/1036/2212 +f 6975/1036/2212 6970/1037/2211 6969/1034/2211 +f 6968/1033/2213 6978/1032/2214 6977/1031/2214 +f 6977/1031/2214 6969/1030/2213 6968/1033/2213 +f 6967/1037/2215 6976/1036/2216 6978/1035/2216 +f 6978/1035/2216 6968/1034/2215 6967/1037/2215 +f 6975/1031/2210 6972/1025/2204 6971/1024/2204 +f 6971/1024/2204 6976/1032/2210 6975/1031/2210 +f 6979/1035/2217 6980/1029/2218 6981/1028/2217 +f 6981/1028/2217 6982/1036/2219 6979/1035/2217 +f 6978/1032/2214 6974/1024/2208 6973/1025/2207 +f 6973/1025/2207 6977/1031/2214 6978/1032/2214 +f 6983/1036/2220 6984/1028/2220 6985/1029/2220 +f 6985/1029/2220 6986/1035/2221 6983/1036/2220 +f 6977/1038/2203 6979/1039/2203 6982/1040/2203 +f 6982/1040/2203 6975/1041/2203 6977/1038/2203 +f 6975/1031/2222 6982/1042/2222 6981/1043/2222 +f 6981/1043/2222 6972/1025/2222 6975/1031/2222 +f 6972/1041/2202 6981/1040/2202 6980/1039/2202 +f 6980/1039/2202 6973/1038/2202 6972/1041/2202 +f 6973/1025/2208 6980/1043/2208 6979/1042/2208 +f 6979/1042/2208 6977/1031/2208 6973/1025/2208 +f 6971/1024/2204 6984/1044/2204 6983/1045/2204 +f 6983/1045/2204 6976/1032/2204 6971/1024/2204 +f 6976/1040/2203 6983/1041/2203 6986/1038/2203 +f 6986/1038/2203 6978/1039/2203 6976/1040/2203 +f 6978/1032/2223 6986/1045/2223 6985/1044/2223 +f 6985/1044/2208 6974/1024/2208 6978/1032/2208 +f 6974/1039/2202 6985/1038/2202 6984/1041/2202 +f 6984/1041/2202 6971/1040/2202 6974/1039/2202 +f 6987/889/2224 6988/890/2055 6989/891/2056 +f 6989/891/2056 6990/892/2057 6987/889/2224 +f 6991/893/2058 6987/889/2224 6990/892/2057 +f 6990/892/2057 6992/894/2059 6991/893/2058 +f 6993/895/2225 6991/893/2058 6992/894/2059 +f 6992/894/2059 6994/896/2061 6993/895/2225 +f 6995/897/2062 6993/895/2225 6994/896/2061 +f 6994/896/2061 6996/898/2063 6995/897/2062 +f 6997/899/2064 6995/900/2062 6996/901/2063 +f 6996/901/2063 6998/902/2065 6997/899/2064 +f 6999/903/2066 6997/899/2064 6998/902/2065 +f 6998/902/2065 7000/904/2067 6999/903/2066 +f 7001/905/2068 6999/903/2066 7000/904/2067 +f 7000/904/2067 7002/906/2069 7001/905/2068 +f 6988/907/2055 7001/905/2068 7002/906/2069 +f 7002/906/2069 6989/908/2056 6988/907/2055 +f 7003/909/2070 7004/910/2071 7005/911/2072 +f 7005/911/2072 7006/912/2073 7003/909/2070 +f 7006/912/2073 7005/911/2072 7007/913/2074 +f 7007/913/2074 7008/914/2075 7006/912/2073 +f 7008/914/2075 7007/913/2074 7009/915/2076 +f 7009/915/2076 7010/916/2077 7008/914/2075 +f 7010/916/2077 7009/915/2076 7011/917/2078 +f 7011/917/2078 7012/918/2079 7010/916/2077 +f 7012/919/2079 7011/920/2078 7013/921/2080 +f 7013/921/2080 7014/922/2081 7012/919/2079 +f 7014/922/2081 7013/921/2080 7015/923/2082 +f 7015/923/2082 7016/924/2083 7014/922/2081 +f 7016/924/2083 7015/923/2082 7017/925/2084 +f 7017/925/2084 7018/926/2085 7016/924/2083 +f 7018/926/2085 7017/925/2084 7004/927/2071 +f 7004/927/2071 7003/928/2070 7018/926/2085 +f 7004/910/2071 7019/929/2086 7020/930/2087 +f 7020/930/2087 7005/911/2072 7004/910/2071 +f 7005/911/2072 7020/930/2087 7021/931/2226 +f 7021/931/2226 7007/913/2074 7005/911/2072 +f 7007/913/2074 7021/931/2226 7022/932/2089 +f 7022/932/2089 7009/915/2076 7007/913/2074 +f 7009/915/2076 7022/932/2089 7023/933/2090 +f 7023/933/2090 7011/917/2078 7009/915/2076 +f 7011/920/2078 7023/934/2090 7024/935/2091 +f 7024/935/2091 7013/921/2080 7011/920/2078 +f 7013/921/2080 7024/935/2091 7025/936/2092 +f 7025/936/2092 7015/923/2082 7013/921/2080 +f 7015/923/2082 7025/936/2092 7026/937/2093 +f 7026/937/2093 7017/925/2084 7015/923/2082 +f 7017/925/2084 7026/937/2093 7019/938/2086 +f 7019/938/2086 7004/927/2071 7017/925/2084 +f 7019/929/2086 7027/939/2094 7028/940/2095 +f 7028/940/2095 7020/930/2087 7019/929/2086 +f 7020/930/2087 7028/940/2095 7029/941/2096 +f 7029/941/2096 7021/931/2226 7020/930/2087 +f 7021/931/2226 7029/941/2096 7030/942/2097 +f 7030/942/2097 7022/932/2089 7021/931/2226 +f 7022/932/2089 7030/942/2097 7031/943/2098 +f 7031/943/2098 7023/933/2090 7022/932/2089 +f 7023/934/2090 7031/944/2098 7032/945/2099 +f 7032/945/2099 7024/935/2091 7023/934/2090 +f 7024/935/2091 7032/945/2099 7033/946/2227 +f 7033/946/2227 7025/936/2092 7024/935/2091 +f 7025/936/2092 7033/946/2227 7034/947/2101 +f 7034/947/2101 7026/937/2093 7025/936/2092 +f 7026/937/2093 7034/947/2101 7027/948/2094 +f 7027/948/2094 7019/938/2086 7026/937/2093 +f 6990/892/2057 6989/891/2056 7003/909/2070 +f 7003/909/2070 7006/912/2073 6990/892/2057 +f 7008/914/2075 6992/894/2059 6990/892/2057 +f 6990/892/2057 7006/912/2073 7008/914/2075 +f 6994/896/2061 6992/894/2059 7008/914/2075 +f 7008/914/2075 7010/916/2077 6994/896/2061 +f 7012/918/2079 6996/898/2063 6994/896/2061 +f 6994/896/2061 7010/916/2077 7012/918/2079 +f 6998/902/2065 6996/901/2063 7012/919/2079 +f 7012/919/2079 7014/922/2081 6998/902/2065 +f 7016/924/2083 7000/904/2067 6998/902/2065 +f 6998/902/2065 7014/922/2081 7016/924/2083 +f 7018/926/2085 7002/906/2069 7000/904/2067 +f 7000/904/2067 7016/924/2083 7018/926/2085 +f 7003/928/2070 6989/908/2056 7002/906/2069 +f 7002/906/2069 7018/926/2085 7003/928/2070 +f 7027/939/2102 7035/949/2102 7036/950/2102 +f 7036/950/2102 7028/940/2102 7027/939/2102 +f 7028/940/2103 7036/950/2103 7037/951/2103 +f 7037/951/2103 7029/941/2103 7028/940/2103 +f 7029/941/2104 7037/951/2104 7038/952/2104 +f 7038/952/2104 7030/942/2104 7029/941/2104 +f 7030/942/2105 7038/952/2105 7039/953/2105 +f 7039/953/2105 7031/943/2105 7030/942/2105 +f 7031/944/2106 7039/954/2106 7040/955/2106 +f 7040/955/2106 7032/945/2106 7031/944/2106 +f 7032/945/2107 7040/955/2107 7041/956/2107 +f 7041/956/2107 7033/946/2107 7032/945/2107 +f 7033/946/2127 7041/956/2127 7042/957/2127 +f 7042/957/2127 7034/947/2127 7033/946/2127 +f 7034/947/2109 7042/957/2109 7035/958/2109 +f 7035/958/2109 7027/948/2109 7034/947/2109 +f 7035/949/2110 7043/959/2110 7044/960/2110 +f 7044/960/2110 7036/950/2110 7035/949/2110 +f 7036/950/2111 7044/960/2111 7045/961/2111 +f 7045/961/2228 7037/951/2228 7036/950/2228 +f 7037/951/2113 7045/961/2113 7046/962/2113 +f 7046/962/2113 7038/952/2113 7037/951/2113 +f 7038/952/2115 7046/962/2115 7047/963/2115 +f 7047/963/2116 7039/953/2116 7038/952/2116 +f 7039/954/2117 7047/964/2117 7048/965/2117 +f 7048/965/2118 7040/955/2118 7039/954/2118 +f 7040/955/2119 7048/965/2119 7049/966/2119 +f 7049/966/2120 7041/956/2120 7040/955/2120 +f 7041/956/2121 7049/966/2121 7050/967/2121 +f 7050/967/2121 7042/957/2121 7041/956/2121 +f 7042/957/2123 7050/967/2123 7043/968/2123 +f 7043/968/2123 7035/958/2123 7042/957/2123 +f 7043/959/2102 7051/969/2102 7052/970/2102 +f 7052/970/2102 7044/960/2102 7043/959/2102 +f 7044/960/2124 7052/970/2124 7053/971/2124 +f 7053/971/2124 7045/961/2124 7044/960/2124 +f 7045/961/2104 7053/971/2104 7054/972/2104 +f 7054/972/2104 7046/962/2104 7045/961/2104 +f 7046/962/2125 7054/972/2125 7055/973/2125 +f 7055/973/2125 7047/963/2125 7046/962/2125 +f 7047/964/2106 7055/974/2106 7056/975/2106 +f 7056/975/2106 7048/965/2106 7047/964/2106 +f 7048/965/2126 7056/975/2126 7057/976/2126 +f 7057/976/2126 7049/966/2126 7048/965/2126 +f 7049/966/2127 7057/976/2127 7058/977/2127 +f 7058/977/2127 7050/967/2127 7049/966/2127 +f 7050/967/2128 7058/977/2128 7051/978/2128 +f 7051/978/2128 7043/968/2128 7050/967/2128 +f 7051/969/2129 7059/979/2129 7060/980/2129 +f 7060/980/2129 7052/970/2129 7051/969/2129 +f 7052/970/2130 7060/980/2130 7061/981/2130 +f 7061/981/2131 7053/971/2131 7052/970/2131 +f 7053/971/2132 7061/981/2132 7062/982/2132 +f 7062/982/2132 7054/972/2132 7053/971/2132 +f 7054/972/2133 7062/982/2133 7063/983/2133 +f 7063/983/2134 7055/973/2134 7054/972/2134 +f 7055/974/2135 7063/984/2135 7064/985/2135 +f 7064/985/2136 7056/975/2136 7055/974/2136 +f 7056/975/2137 7064/985/2137 7065/986/2137 +f 7065/986/2137 7057/976/2137 7056/975/2137 +f 7057/976/2138 7065/986/2138 7066/987/2138 +f 7066/987/2138 7058/977/2138 7057/976/2138 +f 7058/977/2139 7066/987/2139 7059/988/2139 +f 7059/988/2139 7051/978/2139 7058/977/2139 +f 7059/979/2140 7067/989/2140 7060/980/2140 +f 7060/980/2141 7067/989/2141 7061/981/2141 +f 7061/981/2142 7067/989/2142 7062/982/2142 +f 7062/982/2143 7067/989/2143 7063/983/2143 +f 7063/984/2144 7067/990/2144 7064/985/2144 +f 7064/985/2145 7067/990/2145 7065/986/2145 +f 7065/986/2146 7067/990/2146 7066/987/2146 +f 7066/987/2147 7067/990/2147 7059/988/2147 +f 7068/991/2148 7069/992/2149 7070/993/2150 +f 7070/993/2150 7071/994/2229 7068/991/2148 +f 7069/992/2149 7072/995/2230 7073/996/2153 +f 7073/996/2153 7070/993/2150 7069/992/2149 +f 7072/995/2230 7074/997/2231 7075/998/2232 +f 7075/998/2232 7073/996/2153 7072/995/2230 +f 7071/994/2229 7070/993/2150 7076/999/2156 +f 7076/999/2156 7077/1000/2157 7071/994/2229 +f 7070/993/2150 7073/996/2153 7078/1001/2158 +f 7078/1001/2158 7076/999/2156 7070/993/2150 +f 7073/996/2153 7075/998/2232 7079/1002/2159 +f 7079/1002/2159 7078/1001/2158 7073/996/2153 +f 7077/1003/406 7076/999/219 7078/1001/2160 +f 7078/1001/2160 7079/1004/2161 7077/1003/406 +f 7079/1004/2161 7080/1005/511 7077/1003/406 +f 7081/991/2162 7082/994/2163 7083/993/2164 +f 7083/993/2164 7084/992/2165 7081/991/2162 +f 7084/992/2165 7083/993/2164 7085/996/2166 +f 7085/996/2166 7086/995/2167 7084/992/2165 +f 7086/995/2167 7085/996/2166 7087/998/2233 +f 7087/998/2233 7088/997/2234 7086/995/2167 +f 7082/994/2163 7089/1000/2170 7090/999/2171 +f 7090/999/2171 7083/993/2164 7082/994/2163 +f 7083/993/2164 7090/999/2171 7091/1001/2172 +f 7091/1001/2172 7085/996/2166 7083/993/2164 +f 7085/996/2166 7091/1001/2172 7092/1002/2173 +f 7092/1002/2173 7087/998/2233 7085/996/2166 +f 7089/1003/2174 7092/1004/2175 7091/1001/501 +f 7091/1001/501 7090/999/2176 7089/1003/2174 +f 7092/1004/2175 7089/1003/2174 7093/1005/2177 +f 7094/1006/16 7095/1007/16 7096/1008/16 +f 7096/1008/16 7097/1009/16 7094/1006/16 +f 7097/1010/2235 7096/1011/449 7098/1012/449 +f 7098/1012/449 7099/1013/2235 7097/1010/2235 +f 7099/1009/5 7098/1008/5 7100/1007/5 +f 7100/1007/5 7101/1006/5 7099/1009/5 +f 7101/1013/406 7100/1012/406 7095/1011/406 +f 7095/1011/406 7094/1010/2 7101/1013/406 +f 7102/689/2178 7103/690/2179 7104/691/2180 +f 7104/691/2180 7105/692/2181 7102/689/2178 +f 7106/693/2183 7103/690/2182 7102/689/2184 +f 7102/689/2184 7107/694/2184 7106/693/2183 +f 7108/695/2236 7109/696/2237 7110/697/2187 +f 7110/697/2187 7111/698/2187 7108/695/2236 +f 7112/699/2238 7113/700/2238 7114/701/2239 +f 7114/701/2239 7115/702/2239 7112/699/2238 +f 7116/703/2190 7105/692/2240 7117/704/2192 +f 7117/704/2192 7118/705/2192 7116/703/2190 +f 7110/697/2193 7109/696/2194 7104/691/2180 +f 7104/691/2180 7103/690/2179 7110/697/2193 +f 7111/698/2195 7110/697/2195 7103/690/2182 +f 7103/690/2182 7106/706/2183 7111/698/2195 +f 7118/707/2196 7117/704/2196 7113/700/2238 +f 7113/700/2238 7112/699/2238 7118/707/2196 +f 7113/700/2197 7117/704/2198 7105/692/2181 +f 7105/692/2181 7104/691/2180 7113/700/2197 +f 7115/708/2199 7114/701/2199 7109/696/2237 +f 7109/696/2237 7108/695/2236 7115/708/2199 +f 7107/694/2200 7102/689/2241 7105/692/2240 +f 7105/692/2240 7116/703/2190 7107/694/2200 +f 7109/696/2194 7114/701/2201 7113/700/2197 +f 7113/700/2197 7104/691/2180 7109/696/2194 +f 7119/1014/2202 7120/1015/2202 7121/1016/2202 +f 7121/1016/2202 7122/1017/2202 7119/1014/2202 +f 7123/1018/2203 7124/1019/2203 7125/1020/2203 +f 7125/1020/2203 7126/1021/2203 7123/1018/2203 +f 7120/1022/2204 7119/1023/2242 7127/1024/2204 +f 7127/1024/2204 7128/1025/2243 7120/1022/2204 +f 7121/1026/2205 7120/1027/2205 7128/1028/2206 +f 7128/1028/2206 7129/1029/2206 7121/1026/2205 +f 7122/1023/2244 7121/1022/2244 7129/1025/2207 +f 7129/1025/2207 7130/1024/2207 7122/1023/2244 +f 7119/1027/324 7122/1026/324 7130/1029/324 +f 7130/1029/324 7127/1028/324 7119/1027/324 +f 7126/1030/2209 7131/1031/2210 7132/1032/2210 +f 7132/1032/2210 7123/1033/2209 7126/1030/2209 +f 7125/1034/2211 7133/1035/2212 7131/1036/2212 +f 7131/1036/2212 7126/1037/2211 7125/1034/2211 +f 7124/1033/2213 7134/1032/2214 7133/1031/2214 +f 7133/1031/2214 7125/1030/2213 7124/1033/2213 +f 7123/1037/2216 7132/1036/2215 7134/1035/2215 +f 7134/1035/2215 7124/1034/2216 7123/1037/2216 +f 7131/1031/2210 7128/1025/2243 7127/1024/2204 +f 7127/1024/2204 7132/1032/2210 7131/1031/2210 +f 7135/1035/2206 7136/1029/2217 7137/1028/2245 +f 7137/1028/2245 7138/1036/2219 7135/1035/2206 +f 7134/1032/2214 7130/1024/2207 7129/1025/2207 +f 7129/1025/2207 7133/1031/2214 7134/1032/2214 +f 7139/1036/2220 7140/1028/2220 7141/1029/2220 +f 7141/1029/2220 7142/1035/2220 7139/1036/2220 +f 7133/1038/2203 7135/1039/2203 7138/1040/2203 +f 7138/1040/2203 7131/1041/2203 7133/1038/2203 +f 7131/1031/2243 7138/1042/2243 7137/1043/2243 +f 7137/1043/2243 7128/1025/2243 7131/1031/2243 +f 7128/1041/2202 7137/1040/2202 7136/1039/2202 +f 7136/1039/2202 7129/1038/2202 7128/1041/2202 +f 7129/1025/2246 7136/1043/2246 7135/1042/2246 +f 7135/1042/2246 7133/1031/2246 7129/1025/2246 +f 7127/1024/2204 7140/1044/2204 7139/1045/2204 +f 7139/1045/2204 7132/1032/2204 7127/1024/2204 +f 7132/1040/2203 7139/1041/2203 7142/1038/2203 +f 7142/1038/2203 7134/1039/2203 7132/1040/2203 +f 7134/1032/2208 7142/1045/2208 7141/1044/2208 +f 7141/1044/2208 7130/1024/2208 7134/1032/2208 +f 7130/1039/2202 7141/1038/2202 7140/1041/2202 +f 7140/1041/2202 7127/1040/2202 7130/1039/2202 +f 7143/1014/2247 7144/1015/2248 7145/1016/2248 +f 7145/1016/2248 7146/1017/2247 7143/1014/2247 +f 7147/1018/2249 7148/1019/2249 7149/1020/2249 +f 7149/1020/2249 7150/1021/2249 7147/1018/2249 +f 7144/1022/2250 7143/1023/2250 7151/1024/2250 +f 7151/1024/2250 7152/1025/2251 7144/1022/2250 +f 7145/1026/8 7144/1027/8 7152/1028/8 +f 7152/1028/8 7153/1029/8 7145/1026/8 +f 7146/1023/2252 7145/1022/2252 7153/1025/2252 +f 7153/1025/2252 7154/1024/2252 7146/1023/2252 +f 7143/1027/2 7146/1026/2 7154/1029/2 +f 7154/1029/2 7151/1028/2 7143/1027/2 +f 7150/1030/2253 7155/1031/2254 7156/1032/2254 +f 7156/1032/2254 7147/1033/2253 7150/1030/2253 +f 7149/1034/2255 7157/1035/2255 7155/1036/2255 +f 7155/1036/2255 7150/1037/2255 7149/1034/2255 +f 7148/1033/2256 7158/1032/2257 7157/1031/2258 +f 7157/1031/2258 7149/1030/2256 7148/1033/2256 +f 7147/1037/2259 7156/1036/2259 7158/1035/2259 +f 7158/1035/2259 7148/1034/2259 7147/1037/2259 +f 7155/1031/2254 7152/1025/2251 7151/1024/2250 +f 7151/1024/2250 7156/1032/2254 7155/1031/2254 +f 7159/1035/8 7160/1029/8 7161/1028/8 +f 7161/1028/8 7162/1036/8 7159/1035/8 +f 7158/1032/2257 7154/1024/2252 7153/1025/2252 +f 7153/1025/2252 7157/1031/2258 7158/1032/2257 +f 7163/1036/2 7164/1028/2 7165/1029/2 +f 7165/1029/2 7166/1035/2 7163/1036/2 +f 7157/1038/2260 7159/1039/2260 7162/1040/2260 +f 7162/1040/2260 7155/1041/2260 7157/1038/2260 +f 7155/1031/2251 7162/1042/2251 7161/1043/2251 +f 7161/1043/2251 7152/1025/2251 7155/1031/2251 +f 7152/1041/2248 7161/1040/2248 7160/1039/2248 +f 7160/1039/2248 7153/1038/2248 7152/1041/2248 +f 7153/1025/2261 7160/1043/2261 7159/1042/2261 +f 7159/1042/2261 7157/1031/2261 7153/1025/2261 +f 7151/1024/2250 7164/1044/2250 7163/1045/2250 +f 7163/1045/2250 7156/1032/2250 7151/1024/2250 +f 7156/1040/2260 7163/1041/2260 7166/1038/2260 +f 7166/1038/2260 7158/1039/2260 7156/1040/2260 +f 7158/1032/2261 7166/1045/2261 7165/1044/2261 +f 7165/1044/2252 7154/1024/2252 7158/1032/2252 +f 7154/1039/2247 7165/1038/2247 7164/1041/2247 +f 7164/1041/2248 7151/1040/2248 7154/1039/2248 +f 7167/1046/2262 7168/1047/2263 7169/1048/2264 +f 7169/1048/2264 7170/1049/2265 7167/1046/2262 +f 7171/1050/16 7167/1051/16 7170/1052/16 +f 7170/1052/16 7172/1053/16 7171/1050/16 +f 7173/1054/2266 7174/1055/2267 7175/1056/2268 +f 7175/1056/2268 7176/1057/2269 7173/1054/2266 +f 7177/1058/13 7169/1059/13 7168/1060/13 +f 7168/1060/13 7178/1061/13 7177/1058/13 +f 7179/1055/2270 7180/1054/2271 7181/1057/2272 +f 7181/1057/2272 7182/1056/2273 7179/1055/2270 +f 7183/1062/36 7184/1063/36 7185/1064/36 +f 7185/1064/36 7186/1065/36 7183/1062/36 +f 7187/1066/36 7188/1067/36 7189/1068/36 +f 7189/1068/36 7190/1069/36 7187/1066/36 +f 7173/1070/16 7176/1071/16 7167/1051/16 +f 7167/1051/16 7171/1050/16 7173/1070/16 +f 7181/1072/16 7180/1073/16 7172/1053/16 +f 7172/1053/16 7170/1052/16 7181/1072/16 +f 7176/1057/2274 7175/1056/2274 7191/1074/2274 +f 7191/1074/2 7192/1075/2 7176/1057/2 +f 7175/1071/2275 7168/1060/2275 7193/1076/2275 +f 7193/1076/2276 7191/1077/2276 7175/1071/2276 +f 7168/1078/2277 7167/1057/2277 7194/1079/2277 +f 7194/1079/2278 7193/1074/2278 7168/1078/2278 +f 7167/1051/2279 7176/1071/2279 7192/1080/2279 +f 7192/1080/2280 7194/1081/2280 7167/1051/2280 +f 7181/1072/2281 7170/1052/2281 7195/1082/2281 +f 7195/1082/2282 7196/1083/2282 7181/1072/2282 +f 7170/1057/2283 7169/1056/2283 7197/1084/2283 +f 7197/1084/2284 7195/1085/2284 7170/1057/2284 +f 7169/1059/2285 7182/1086/2285 7198/1087/2285 +f 7198/1087/2286 7197/1088/2286 7169/1059/2286 +f 7182/1056/2287 7181/1057/2287 7196/1079/2287 +f 7196/1079/2288 7198/1084/2288 7182/1056/2288 +f 7192/1075/2 7191/1074/2 7184/1089/2 +f 7184/1089/2 7183/1090/2 7192/1075/2 +f 7198/1084/8 7196/1079/8 7188/1090/8 +f 7188/1090/8 7187/1089/8 7198/1084/8 +f 7186/1065/36 7185/1064/36 7190/1069/36 +f 7190/1069/36 7189/1068/36 7186/1065/36 +f 7183/1091/6 7186/1092/6 7194/1081/6 +f 7194/1081/6 7192/1080/6 7183/1091/6 +f 7189/1093/6 7188/1094/6 7196/1083/6 +f 7196/1083/6 7195/1082/6 7189/1093/6 +f 7199/1095/5 7200/1096/5 7201/1097/5 +f 7201/1097/5 7202/1098/5 7199/1095/5 +f 7190/1093/5 7185/1092/5 7193/1076/5 +f 7193/1076/5 7197/1088/5 7190/1093/5 +f 7203/1095/5 7204/1096/5 7205/1097/5 +f 7205/1097/5 7206/1098/5 7203/1095/5 +f 7186/1092/6 7189/1093/6 7195/1082/6 +f 7195/1082/6 7194/1081/6 7186/1092/6 +f 7187/1066/36 7190/1069/36 7200/1099/36 +f 7200/1099/36 7199/1100/36 7187/1066/36 +f 7190/1089/2289 7197/1084/2289 7201/1101/2289 +f 7201/1101/2290 7200/1102/2290 7190/1089/2290 +f 7198/1084/8 7187/1089/8 7199/1102/8 +f 7199/1102/8 7202/1101/8 7198/1084/8 +f 7185/1064/36 7184/1063/36 7204/1103/36 +f 7204/1103/36 7203/1104/36 7185/1064/36 +f 7184/1089/2 7191/1074/2 7205/1105/2 +f 7205/1105/2 7204/1102/2 7184/1089/2 +f 7193/1074/8 7185/1089/8 7203/1102/8 +f 7203/1102/8 7206/1105/8 7193/1074/8 +f 7207/1106/2291 7208/1107/2291 7169/1056/2291 +f 7169/1056/2292 7177/1055/2292 7207/1106/2292 +f 7209/1107/2293 7210/1108/2293 7179/1055/2293 +f 7179/1055/2294 7182/1056/2294 7209/1107/2294 +f 7211/1106/2295 7212/1109/2295 7175/1056/2295 +f 7175/1056/2296 7174/1055/2296 7211/1106/2296 +f 7213/1109/2297 7214/1106/2297 7178/1055/2297 +f 7178/1055/2298 7168/1078/2298 7213/1109/2298 +f 7208/1110/2299 7209/1111/2299 7182/1112/2299 +f 7182/1112/2300 7169/1048/2300 7208/1110/2300 +f 7212/1113/2301 7213/1114/2301 7168/1047/2301 +f 7168/1047/2302 7175/1115/2302 7212/1113/2302 +f 7207/1097/13 7210/1098/13 7209/1095/13 +f 7209/1095/13 7208/1096/13 7207/1097/13 +f 7212/1096/13 7211/1097/13 7214/1098/13 +f 7214/1098/13 7213/1095/13 7212/1096/13 +f 7215/689/2303 7216/690/2304 7217/691/2305 +f 7217/691/2305 7218/692/2306 7215/689/2303 +f 7219/693/2307 7216/690/2308 7215/689/2309 +f 7215/689/2309 7220/694/2309 7219/693/2307 +f 7221/695/2310 7222/696/2311 7223/697/2312 +f 7223/697/2312 7224/698/2312 7221/695/2310 +f 7225/699/2313 7226/700/2313 7227/701/2314 +f 7227/701/2314 7228/702/2314 7225/699/2313 +f 7229/703/2315 7218/692/2316 7230/704/2317 +f 7230/704/2317 7231/705/2317 7229/703/2315 +f 7223/697/2318 7222/696/2319 7217/691/2305 +f 7217/691/2305 7216/690/2304 7223/697/2318 +f 7224/698/2320 7223/697/2320 7216/690/2308 +f 7216/690/2308 7219/706/2307 7224/698/2320 +f 7231/707/2321 7230/704/2321 7226/700/2313 +f 7226/700/2313 7225/699/2313 7231/707/2321 +f 7226/700/2322 7230/704/2323 7218/692/2306 +f 7218/692/2306 7217/691/2305 7226/700/2322 +f 7228/708/2324 7227/701/2324 7222/696/2311 +f 7222/696/2311 7221/695/2310 7228/708/2324 +f 7220/694/2325 7215/689/2325 7218/692/2316 +f 7218/692/2316 7229/703/2315 7220/694/2325 +f 7222/696/2319 7227/701/2326 7226/700/2322 +f 7226/700/2322 7217/691/2305 7222/696/2319 +f 7232/1014/2247 7233/1015/2248 7234/1016/2248 +f 7234/1016/2248 7235/1017/2247 7232/1014/2247 +f 7236/1018/2249 7237/1019/2249 7238/1020/2249 +f 7238/1020/2249 7239/1021/2249 7236/1018/2249 +f 7233/1022/2250 7232/1023/2250 7240/1024/2250 +f 7240/1024/2250 7241/1025/2251 7233/1022/2250 +f 7234/1026/8 7233/1027/8 7241/1028/8 +f 7241/1028/8 7242/1029/8 7234/1026/8 +f 7235/1023/2252 7234/1022/2252 7242/1025/2252 +f 7242/1025/2252 7243/1024/2252 7235/1023/2252 +f 7232/1027/2 7235/1026/2 7243/1029/2 +f 7243/1029/2 7240/1028/2 7232/1027/2 +f 7239/1030/2253 7244/1031/2254 7245/1032/2254 +f 7245/1032/2254 7236/1033/2253 7239/1030/2253 +f 7238/1034/2255 7246/1035/2255 7244/1036/2255 +f 7244/1036/2255 7239/1037/2255 7238/1034/2255 +f 7237/1033/2256 7247/1032/2257 7246/1031/2258 +f 7246/1031/2258 7238/1030/2256 7237/1033/2256 +f 7236/1037/2259 7245/1036/2259 7247/1035/2259 +f 7247/1035/2259 7237/1034/2259 7236/1037/2259 +f 7244/1031/2254 7241/1025/2251 7240/1024/2250 +f 7240/1024/2250 7245/1032/2254 7244/1031/2254 +f 7248/1035/8 7249/1029/8 7250/1028/8 +f 7250/1028/8 7251/1036/8 7248/1035/8 +f 7247/1032/2257 7243/1024/2252 7242/1025/2252 +f 7242/1025/2252 7246/1031/2258 7247/1032/2257 +f 7252/1036/2 7253/1028/2 7254/1029/2 +f 7254/1029/2 7255/1035/2 7252/1036/2 +f 7246/1038/2260 7248/1039/2260 7251/1040/2260 +f 7251/1040/2260 7244/1041/2260 7246/1038/2260 +f 7244/1031/2251 7251/1042/2251 7250/1043/2251 +f 7250/1043/2251 7241/1025/2251 7244/1031/2251 +f 7241/1041/2248 7250/1040/2248 7249/1039/2248 +f 7249/1039/2248 7242/1038/2248 7241/1041/2248 +f 7242/1025/2261 7249/1043/2261 7248/1042/2261 +f 7248/1042/2261 7246/1031/2261 7242/1025/2261 +f 7240/1024/2250 7253/1044/2250 7252/1045/2250 +f 7252/1045/2250 7245/1032/2250 7240/1024/2250 +f 7245/1040/2260 7252/1041/2260 7255/1038/2260 +f 7255/1038/2260 7247/1039/2260 7245/1040/2260 +f 7247/1032/2261 7255/1045/2261 7254/1044/2261 +f 7254/1044/2252 7243/1024/2252 7247/1032/2252 +f 7243/1039/2247 7254/1038/2247 7253/1041/2247 +f 7253/1041/2248 7240/1040/2248 7243/1039/2248 +f 7256/1014/2327 7257/1015/2328 7258/1016/2329 +f 7258/1016/2329 7259/1017/2327 7256/1014/2327 +f 7260/1018/2330 7261/1019/2331 7262/1020/2332 +f 7262/1020/2332 7263/1021/2332 7260/1018/2330 +f 7257/1022/2333 7256/1023/2333 7264/1024/2333 +f 7264/1024/2333 7265/1025/2334 7257/1022/2333 +f 7258/1026/2335 7257/1027/2335 7265/1028/2336 +f 7265/1028/2336 7266/1029/2336 7258/1026/2335 +f 7259/1023/2337 7258/1022/2337 7266/1025/2337 +f 7266/1025/2337 7267/1024/2337 7259/1023/2337 +f 7256/1027/2338 7259/1026/2338 7267/1029/2339 +f 7267/1029/2339 7264/1028/2339 7256/1027/2338 +f 7263/1030/2340 7268/1031/2341 7269/1032/2342 +f 7269/1032/2342 7260/1033/2340 7263/1030/2340 +f 7262/1034/2343 7270/1035/2344 7268/1036/2344 +f 7268/1036/2344 7263/1037/2343 7262/1034/2343 +f 7261/1033/2345 7271/1032/2346 7270/1031/2346 +f 7270/1031/2346 7262/1030/2345 7261/1033/2345 +f 7260/1037/2347 7269/1036/2348 7271/1035/2348 +f 7271/1035/2348 7261/1034/2347 7260/1037/2347 +f 7268/1031/2341 7265/1025/2334 7264/1024/2333 +f 7264/1024/2333 7269/1032/2342 7268/1031/2341 +f 7272/1035/2349 7273/1029/2350 7274/1028/2349 +f 7274/1028/2349 7275/1036/2336 7272/1035/2349 +f 7271/1032/2346 7267/1024/2337 7266/1025/2337 +f 7266/1025/2337 7270/1031/2346 7271/1032/2346 +f 7276/1036/2339 7277/1028/2339 7278/1029/2339 +f 7278/1029/2339 7279/1035/2339 7276/1036/2339 +f 7270/1038/2330 7272/1039/2330 7275/1040/2330 +f 7275/1040/2351 7268/1041/2351 7270/1038/2351 +f 7268/1031/2352 7275/1042/2352 7274/1043/2352 +f 7274/1043/2352 7265/1025/2352 7268/1031/2352 +f 7265/1041/2327 7274/1040/2327 7273/1039/2327 +f 7273/1039/2353 7266/1038/2353 7265/1041/2353 +f 7266/1025/2354 7273/1043/2354 7272/1042/2354 +f 7272/1042/2354 7270/1031/2354 7266/1025/2354 +f 7264/1024/2355 7277/1044/2355 7276/1045/2355 +f 7276/1045/2356 7269/1032/2356 7264/1024/2356 +f 7269/1040/2330 7276/1041/2330 7279/1038/2330 +f 7279/1038/2351 7271/1039/2351 7269/1040/2351 +f 7271/1032/2357 7279/1045/2357 7278/1044/2357 +f 7278/1044/2357 7267/1024/2357 7271/1032/2357 +f 7267/1039/2327 7278/1038/2327 7277/1041/2327 +f 7277/1041/2327 7264/1040/2327 7267/1039/2327 +f 7280/1046/2358 7281/1047/2359 7282/1048/2360 +f 7282/1048/2360 7283/1049/2361 7280/1046/2358 +f 7284/1050/2362 7280/1051/2362 7283/1052/2362 +f 7283/1052/2362 7285/1053/2362 7284/1050/2362 +f 7286/1054/2363 7287/1055/2364 7288/1056/2365 +f 7288/1056/2365 7289/1057/2366 7286/1054/2363 +f 7290/1058/2367 7282/1059/2367 7281/1060/2368 +f 7281/1060/2368 7291/1061/2368 7290/1058/2367 +f 7292/1055/2369 7293/1054/2370 7294/1057/2371 +f 7294/1057/2371 7295/1056/2372 7292/1055/2369 +f 7296/1062/36 7297/1063/36 7298/1064/36 +f 7298/1064/36 7299/1065/36 7296/1062/36 +f 7300/1066/37 7301/1067/37 7302/1068/37 +f 7302/1068/37 7303/1069/37 7300/1066/37 +f 7286/1070/2373 7289/1071/2373 7280/1051/2362 +f 7280/1051/2362 7284/1050/2362 7286/1070/2373 +f 7294/1072/2374 7293/1073/2374 7285/1053/2362 +f 7285/1053/2362 7283/1052/2362 7294/1072/2374 +f 7289/1057/2375 7288/1056/2375 7304/1074/2375 +f 7304/1074/2338 7305/1075/2338 7289/1057/2338 +f 7288/1071/2376 7281/1060/2376 7306/1076/2376 +f 7306/1076/2377 7304/1077/2377 7288/1071/2377 +f 7281/1078/2378 7280/1057/2378 7307/1079/2378 +f 7307/1079/2379 7306/1074/2379 7281/1078/2379 +f 7280/1051/2380 7289/1071/2380 7305/1080/2380 +f 7305/1080/2381 7307/1081/2381 7280/1051/2381 +f 7294/1072/2382 7283/1052/2382 7308/1082/2382 +f 7308/1082/2383 7309/1083/2383 7294/1072/2383 +f 7283/1057/2384 7282/1056/2384 7310/1084/2384 +f 7310/1084/2385 7308/1085/2385 7283/1057/2385 +f 7282/1059/2386 7295/1086/2386 7311/1087/2386 +f 7311/1087/2387 7310/1088/2387 7282/1059/2387 +f 7295/1056/2388 7294/1057/2388 7309/1079/2388 +f 7309/1079/2389 7311/1084/2389 7295/1056/2389 +f 7305/1075/2338 7304/1074/2338 7297/1089/2338 +f 7297/1089/2338 7296/1090/2338 7305/1075/2338 +f 7311/1084/2336 7309/1079/2336 7301/1090/2336 +f 7301/1090/2336 7300/1089/2336 7311/1084/2336 +f 7299/1065/36 7298/1064/36 7303/1069/36 +f 7303/1069/37 7302/1068/37 7299/1065/37 +f 7296/1091/2374 7299/1092/2374 7307/1081/2374 +f 7307/1081/2374 7305/1080/2374 7296/1091/2374 +f 7302/1093/2374 7301/1094/2374 7309/1083/2374 +f 7309/1083/2374 7308/1082/2374 7302/1093/2374 +f 7312/1095/2368 7313/1096/2368 7314/1097/2368 +f 7314/1097/2390 7315/1098/2390 7312/1095/2390 +f 7303/1093/2390 7298/1092/2390 7306/1076/2390 +f 7306/1076/2368 7310/1088/2368 7303/1093/2368 +f 7316/1095/2390 7317/1096/2390 7318/1097/2390 +f 7318/1097/2390 7319/1098/2390 7316/1095/2390 +f 7299/1092/2374 7302/1093/2374 7308/1082/2374 +f 7308/1082/2374 7307/1081/2374 7299/1092/2374 +f 7300/1066/37 7303/1069/37 7313/1099/37 +f 7313/1099/15 7312/1100/15 7300/1066/15 +f 7303/1089/2391 7310/1084/2391 7314/1101/2391 +f 7314/1101/2392 7313/1102/2392 7303/1089/2392 +f 7311/1084/2336 7300/1089/2336 7312/1102/2336 +f 7312/1102/2336 7315/1101/2336 7311/1084/2336 +f 7298/1064/15 7297/1063/15 7317/1103/15 +f 7317/1103/37 7316/1104/37 7298/1064/37 +f 7297/1089/2338 7304/1074/2338 7318/1105/2338 +f 7318/1105/2338 7317/1102/2338 7297/1089/2338 +f 7306/1074/2336 7298/1089/2336 7316/1102/2336 +f 7316/1102/2336 7319/1105/2336 7306/1074/2336 +f 7320/1106/2393 7321/1107/2393 7282/1056/2393 +f 7282/1056/2394 7290/1055/2394 7320/1106/2394 +f 7322/1107/2395 7323/1108/2395 7292/1055/2395 +f 7292/1055/2396 7295/1056/2396 7322/1107/2396 +f 7324/1106/2397 7325/1109/2397 7288/1056/2397 +f 7288/1056/2398 7287/1055/2398 7324/1106/2398 +f 7326/1109/2399 7327/1106/2399 7291/1055/2399 +f 7291/1055/2400 7281/1078/2400 7326/1109/2400 +f 7321/1110/2401 7322/1111/2401 7295/1112/2401 +f 7295/1112/2402 7282/1048/2402 7321/1110/2402 +f 7325/1113/2403 7326/1114/2403 7281/1047/2403 +f 7281/1047/2404 7288/1115/2404 7325/1113/2404 +f 7320/1097/2368 7323/1098/2368 7322/1095/2368 +f 7322/1095/2390 7321/1096/2390 7320/1097/2390 +f 7325/1096/2390 7324/1097/2390 7327/1098/2390 +f 7327/1098/2367 7326/1095/2367 7325/1096/2367 +f 7328/689/2405 7329/690/2406 7330/691/2407 +f 7330/691/2407 7331/692/2408 7328/689/2405 +f 7332/693/2409 7329/690/2410 7328/689/2411 +f 7328/689/2411 7333/694/2411 7332/693/2409 +f 7334/695/2412 7335/696/2413 7336/697/2414 +f 7336/697/2414 7337/698/2414 7334/695/2412 +f 7338/699/2415 7339/700/2416 7340/701/2417 +f 7340/701/2417 7341/702/2417 7338/699/2415 +f 7342/703/2418 7331/692/2419 7343/704/2420 +f 7343/704/2420 7344/705/2420 7342/703/2418 +f 7336/697/2421 7335/696/2422 7330/691/2407 +f 7330/691/2407 7329/690/2406 7336/697/2421 +f 7337/698/2423 7336/697/2423 7329/690/2410 +f 7329/690/2410 7332/706/2409 7337/698/2423 +f 7344/707/2424 7343/704/2424 7339/700/2416 +f 7339/700/2416 7338/699/2415 7344/707/2424 +f 7339/700/2425 7343/704/2426 7331/692/2408 +f 7331/692/2408 7330/691/2407 7339/700/2425 +f 7341/708/2427 7340/701/2427 7335/696/2413 +f 7335/696/2413 7334/695/2412 7341/708/2427 +f 7333/694/2428 7328/689/2428 7331/692/2419 +f 7331/692/2419 7342/703/2418 7333/694/2428 +f 7335/696/2422 7340/701/2429 7339/700/2425 +f 7339/700/2425 7330/691/2407 7335/696/2422 +f 7345/1014/2329 7346/1015/2329 7347/1016/2329 +f 7347/1016/2329 7348/1017/2329 7345/1014/2329 +f 7349/1018/2330 7350/1019/2330 7351/1020/2330 +f 7351/1020/2330 7352/1021/2330 7349/1018/2330 +f 7346/1022/2333 7345/1023/2333 7353/1024/2334 +f 7353/1024/2334 7354/1025/2356 7346/1022/2333 +f 7347/1026/2349 7346/1027/2349 7354/1028/2349 +f 7354/1028/2349 7355/1029/2350 7347/1026/2349 +f 7348/1023/2430 7347/1022/2430 7355/1025/2431 +f 7355/1025/2431 7356/1024/2432 7348/1023/2430 +f 7345/1027/2339 7348/1026/2339 7356/1029/2339 +f 7356/1029/2339 7353/1028/2339 7345/1027/2339 +f 7352/1030/2433 7357/1031/2341 7358/1032/2434 +f 7358/1032/2434 7349/1033/2433 7352/1030/2433 +f 7351/1034/2344 7359/1035/2343 7357/1036/2343 +f 7357/1036/2343 7352/1037/2344 7351/1034/2344 +f 7350/1033/2435 7360/1032/2346 7359/1031/2436 +f 7359/1031/2436 7351/1030/2435 7350/1033/2435 +f 7349/1037/2437 7358/1036/2348 7360/1035/2348 +f 7360/1035/2348 7350/1034/2437 7349/1037/2437 +f 7357/1031/2341 7354/1025/2356 7353/1024/2334 +f 7353/1024/2334 7358/1032/2434 7357/1031/2341 +f 7361/1035/2336 7362/1029/2350 7363/1028/2438 +f 7363/1028/2438 7364/1036/2438 7361/1035/2336 +f 7360/1032/2346 7356/1024/2432 7355/1025/2431 +f 7355/1025/2431 7359/1031/2436 7360/1032/2346 +f 7365/1036/2338 7366/1028/2338 7367/1029/2338 +f 7367/1029/2338 7368/1035/2339 7365/1036/2338 +f 7359/1038/2330 7361/1039/2330 7364/1040/2330 +f 7364/1040/2351 7357/1041/2351 7359/1038/2351 +f 7357/1031/2356 7364/1042/2356 7363/1043/2356 +f 7363/1043/2356 7354/1025/2356 7357/1031/2356 +f 7354/1041/2327 7363/1040/2327 7362/1039/2327 +f 7362/1039/2327 7355/1038/2327 7354/1041/2327 +f 7355/1025/2357 7362/1043/2357 7361/1042/2357 +f 7361/1042/2439 7359/1031/2439 7355/1025/2439 +f 7353/1024/2352 7366/1044/2352 7365/1045/2352 +f 7365/1045/2352 7358/1032/2352 7353/1024/2352 +f 7358/1040/2351 7365/1041/2351 7368/1038/2351 +f 7368/1038/2351 7360/1039/2351 7358/1040/2351 +f 7360/1032/2357 7368/1045/2357 7367/1044/2357 +f 7367/1044/2357 7356/1024/2357 7360/1032/2357 +f 7356/1039/2353 7367/1038/2353 7366/1041/2353 +f 7366/1041/2353 7353/1040/2353 7356/1039/2353 +f 7369/1014/2440 7370/1015/2440 7371/1016/2440 +f 7371/1016/2440 7372/1017/2440 7369/1014/2440 +f 7373/1018/2441 7374/1019/2441 7375/1020/2441 +f 7375/1020/2441 7376/1021/2441 7373/1018/2441 +f 7370/1022/2442 7369/1023/2442 7377/1024/2443 +f 7377/1024/2443 7378/1025/2443 7370/1022/2442 +f 7371/1026/2444 7370/1027/2444 7378/1028/2445 +f 7378/1028/2445 7379/1029/2445 7371/1026/2444 +f 7372/1023/2446 7371/1022/2446 7379/1025/2447 +f 7379/1025/2447 7380/1024/2446 7372/1023/2446 +f 7369/1027/2448 7372/1026/2448 7380/1029/2449 +f 7380/1029/2449 7377/1028/2450 7369/1027/2448 +f 7376/1030/2451 7381/1031/2452 7382/1032/2452 +f 7382/1032/2452 7373/1033/2451 7376/1030/2451 +f 7375/1034/2453 7383/1035/2454 7381/1036/2454 +f 7381/1036/2454 7376/1037/2453 7375/1034/2453 +f 7374/1033/2455 7384/1032/2456 7383/1031/2456 +f 7383/1031/2456 7375/1030/2455 7374/1033/2455 +f 7373/1037/2457 7382/1036/2458 7384/1035/2458 +f 7384/1035/2458 7374/1034/2457 7373/1037/2457 +f 7381/1031/2452 7378/1025/2443 7377/1024/2443 +f 7377/1024/2443 7382/1032/2452 7381/1031/2452 +f 7385/1035/2459 7386/1029/2460 7387/1028/2461 +f 7387/1028/2461 7388/1036/2462 7385/1035/2459 +f 7384/1032/2456 7380/1024/2446 7379/1025/2447 +f 7379/1025/2447 7383/1031/2456 7384/1032/2456 +f 7389/1036/2448 7390/1028/2463 7391/1029/2464 +f 7391/1029/2464 7392/1035/2465 7389/1036/2448 +f 7383/1038/2441 7385/1039/2441 7388/1040/2441 +f 7388/1040/2466 7381/1041/2466 7383/1038/2466 +f 7381/1031/2467 7388/1042/2467 7387/1043/2467 +f 7387/1043/2443 7378/1025/2443 7381/1031/2443 +f 7378/1041/2440 7387/1040/2440 7386/1039/2440 +f 7386/1039/2468 7379/1038/2468 7378/1041/2468 +f 7379/1025/2469 7386/1043/2469 7385/1042/2469 +f 7385/1042/2470 7383/1031/2470 7379/1025/2470 +f 7377/1024/2467 7390/1044/2467 7389/1045/2467 +f 7389/1045/2443 7382/1032/2443 7377/1024/2443 +f 7382/1040/2441 7389/1041/2441 7392/1038/2441 +f 7392/1038/2471 7384/1039/2471 7382/1040/2471 +f 7384/1032/2469 7392/1045/2469 7391/1044/2469 +f 7391/1044/2446 7380/1024/2446 7384/1032/2446 +f 7380/1039/2440 7391/1038/2440 7390/1041/2440 +f 7390/1041/2468 7377/1040/2468 7380/1039/2468 +f 7393/1046/2472 7394/1047/2473 7395/1048/2474 +f 7395/1048/2474 7396/1049/2475 7393/1046/2472 +f 7397/1050/2476 7393/1051/2476 7396/1052/2476 +f 7396/1052/2476 7398/1053/2476 7397/1050/2476 +f 7399/1054/2477 7400/1055/2478 7401/1056/2479 +f 7401/1056/2479 7402/1057/2480 7399/1054/2477 +f 7403/1058/2481 7395/1059/2481 7394/1060/2482 +f 7394/1060/2482 7404/1061/2482 7403/1058/2481 +f 7405/1055/2483 7406/1054/2484 7407/1057/2485 +f 7407/1057/2485 7408/1056/2486 7405/1055/2483 +f 7409/1062/36 7410/1063/36 7411/1064/36 +f 7411/1064/36 7412/1065/36 7409/1062/36 +f 7413/1066/36 7414/1067/36 7415/1068/36 +f 7415/1068/36 7416/1069/36 7413/1066/36 +f 7399/1070/2476 7402/1071/2476 7393/1051/2476 +f 7393/1051/2476 7397/1050/2476 7399/1070/2476 +f 7407/1072/2476 7406/1073/2476 7398/1053/2476 +f 7398/1053/2476 7396/1052/2476 7407/1072/2476 +f 7402/1057/2487 7401/1056/2487 7417/1074/2487 +f 7417/1074/2448 7418/1075/2448 7402/1057/2448 +f 7401/1071/2488 7394/1060/2488 7419/1076/2488 +f 7419/1076/2489 7417/1077/2489 7401/1071/2489 +f 7394/1078/2490 7393/1057/2490 7420/1079/2490 +f 7420/1079/2491 7419/1074/2491 7394/1078/2491 +f 7393/1051/2492 7402/1071/2492 7418/1080/2492 +f 7418/1080/2493 7420/1081/2493 7393/1051/2493 +f 7407/1072/2494 7396/1052/2494 7421/1082/2494 +f 7421/1082/2495 7422/1083/2495 7407/1072/2495 +f 7396/1057/2496 7395/1056/2496 7423/1084/2496 +f 7423/1084/2497 7421/1085/2497 7396/1057/2497 +f 7395/1059/2498 7408/1086/2498 7424/1087/2498 +f 7424/1087/2499 7423/1088/2499 7395/1059/2499 +f 7408/1056/2500 7407/1057/2500 7422/1079/2500 +f 7422/1079/2501 7424/1084/2501 7408/1056/2501 +f 7418/1075/2449 7417/1074/2449 7410/1089/2449 +f 7410/1089/2449 7409/1090/2449 7418/1075/2449 +f 7424/1084/2502 7422/1079/2502 7414/1090/2502 +f 7414/1090/2502 7413/1089/2502 7424/1084/2502 +f 7412/1065/15 7411/1064/15 7416/1069/15 +f 7416/1069/15 7415/1068/15 7412/1065/15 +f 7409/1091/2476 7412/1092/2476 7420/1081/2476 +f 7420/1081/2476 7418/1080/2476 7409/1091/2476 +f 7415/1093/2476 7414/1094/2476 7422/1083/2476 +f 7422/1083/2476 7421/1082/2476 7415/1093/2476 +f 7425/1095/2482 7426/1096/2482 7427/1097/2482 +f 7427/1097/2482 7428/1098/2482 7425/1095/2482 +f 7416/1093/2482 7411/1092/2482 7419/1076/2482 +f 7419/1076/2482 7423/1088/2482 7416/1093/2482 +f 7429/1095/2482 7430/1096/2482 7431/1097/2482 +f 7431/1097/2482 7432/1098/2482 7429/1095/2482 +f 7412/1092/2476 7415/1093/2476 7421/1082/2476 +f 7421/1082/2476 7420/1081/2476 7412/1092/2476 +f 7413/1066/36 7416/1069/36 7426/1099/36 +f 7426/1099/15 7425/1100/15 7413/1066/15 +f 7416/1089/2503 7423/1084/2503 7427/1101/2503 +f 7427/1101/2504 7426/1102/2504 7416/1089/2504 +f 7424/1084/2444 7413/1089/2444 7425/1102/2444 +f 7425/1102/2444 7428/1101/2444 7424/1084/2444 +f 7411/1064/36 7410/1063/36 7430/1103/36 +f 7430/1103/36 7429/1104/36 7411/1064/36 +f 7410/1089/2450 7417/1074/2450 7431/1105/2450 +f 7431/1105/2450 7430/1102/2450 7410/1089/2450 +f 7419/1074/2444 7411/1089/2444 7429/1102/2444 +f 7429/1102/2444 7432/1105/2444 7419/1074/2444 +f 7433/1106/2505 7434/1107/2505 7395/1056/2505 +f 7395/1056/2506 7403/1055/2506 7433/1106/2506 +f 7435/1107/2507 7436/1108/2507 7405/1055/2507 +f 7405/1055/2508 7408/1056/2508 7435/1107/2508 +f 7437/1106/2509 7438/1109/2509 7401/1056/2509 +f 7401/1056/2510 7400/1055/2510 7437/1106/2510 +f 7439/1109/2511 7440/1106/2511 7404/1055/2511 +f 7404/1055/2512 7394/1078/2512 7439/1109/2512 +f 7434/1110/2513 7435/1111/2513 7408/1112/2513 +f 7408/1112/2514 7395/1048/2514 7434/1110/2514 +f 7438/1113/2515 7439/1114/2515 7394/1047/2515 +f 7394/1047/2516 7401/1115/2516 7438/1113/2516 +f 7433/1097/2517 7436/1098/2517 7435/1095/2517 +f 7435/1095/2517 7434/1096/2517 7433/1097/2517 +f 7438/1096/2518 7437/1097/2518 7440/1098/2518 +f 7440/1098/2519 7439/1095/2519 7438/1096/2519 +f 7441/689/2520 7442/690/2521 7443/691/2522 +f 7443/691/2522 7444/692/2523 7441/689/2520 +f 7445/693/2524 7442/690/2525 7441/689/2526 +f 7441/689/2526 7446/694/2526 7445/693/2524 +f 7447/695/2527 7448/696/2528 7449/697/2529 +f 7449/697/2529 7450/698/2529 7447/695/2527 +f 7451/699/2530 7452/700/2530 7453/701/2531 +f 7453/701/2531 7454/702/2531 7451/699/2530 +f 7455/703/2532 7444/692/2533 7456/704/2534 +f 7456/704/2534 7457/705/2534 7455/703/2532 +f 7449/697/2535 7448/696/2536 7443/691/2522 +f 7443/691/2522 7442/690/2521 7449/697/2535 +f 7450/698/2537 7449/697/2537 7442/690/2525 +f 7442/690/2525 7445/706/2524 7450/698/2537 +f 7457/707/2538 7456/704/2538 7452/700/2530 +f 7452/700/2530 7451/699/2530 7457/707/2538 +f 7452/700/2539 7456/704/2540 7444/692/2523 +f 7444/692/2523 7443/691/2522 7452/700/2539 +f 7454/708/2541 7453/701/2541 7448/696/2528 +f 7448/696/2528 7447/695/2527 7454/708/2541 +f 7446/694/2542 7441/689/2542 7444/692/2533 +f 7444/692/2533 7455/703/2532 7446/694/2542 +f 7448/696/2536 7453/701/2543 7452/700/2539 +f 7452/700/2539 7443/691/2522 7448/696/2536 +f 7458/1014/2440 7459/1015/2440 7460/1016/2440 +f 7460/1016/2440 7461/1017/2468 7458/1014/2440 +f 7462/1018/2471 7463/1019/2471 7464/1020/2471 +f 7464/1020/2471 7465/1021/2441 7462/1018/2471 +f 7459/1022/2442 7458/1023/2442 7466/1024/2442 +f 7466/1024/2442 7467/1025/2544 7459/1022/2442 +f 7460/1026/2461 7459/1027/2461 7467/1028/2461 +f 7467/1028/2461 7468/1029/2461 7460/1026/2461 +f 7461/1023/2446 7460/1022/2447 7468/1025/2469 +f 7468/1025/2469 7469/1024/2469 7461/1023/2446 +f 7458/1027/2450 7461/1026/2545 7469/1029/2448 +f 7469/1029/2448 7466/1028/2448 7458/1027/2450 +f 7465/1030/2451 7470/1031/2546 7471/1032/2452 +f 7471/1032/2452 7462/1033/2451 7465/1030/2451 +f 7464/1034/2547 7472/1035/2453 7470/1036/2453 +f 7470/1036/2453 7465/1037/2547 7464/1034/2547 +f 7463/1033/2455 7473/1032/2548 7472/1031/2548 +f 7472/1031/2548 7464/1030/2455 7463/1033/2455 +f 7462/1037/2549 7471/1036/2549 7473/1035/2549 +f 7473/1035/2549 7463/1034/2549 7462/1037/2549 +f 7470/1031/2546 7467/1025/2544 7466/1024/2442 +f 7466/1024/2442 7471/1032/2452 7470/1031/2546 +f 7474/1035/2550 7475/1029/2551 7476/1028/2459 +f 7476/1028/2459 7477/1036/2552 7474/1035/2550 +f 7473/1032/2548 7469/1024/2469 7468/1025/2469 +f 7468/1025/2469 7472/1031/2548 7473/1032/2548 +f 7478/1036/2448 7479/1028/2553 7480/1029/2449 +f 7480/1029/2449 7481/1035/2449 7478/1036/2448 +f 7472/1038/2471 7474/1039/2471 7477/1040/2471 +f 7477/1040/2441 7470/1041/2441 7472/1038/2441 +f 7470/1031/2443 7477/1042/2443 7476/1043/2443 +f 7476/1043/2467 7467/1025/2467 7470/1031/2467 +f 7467/1041/2468 7476/1040/2468 7475/1039/2468 +f 7475/1039/2440 7468/1038/2440 7467/1041/2440 +f 7468/1025/2446 7475/1043/2446 7474/1042/2446 +f 7474/1042/2469 7472/1031/2469 7468/1025/2469 +f 7466/1024/2554 7479/1044/2554 7478/1045/2554 +f 7478/1045/2554 7471/1032/2554 7466/1024/2554 +f 7471/1040/2471 7478/1041/2471 7481/1038/2471 +f 7481/1038/2441 7473/1039/2441 7471/1040/2441 +f 7473/1032/2470 7481/1045/2470 7480/1044/2470 +f 7480/1044/2469 7469/1024/2469 7473/1032/2469 +f 7469/1039/2468 7480/1038/2468 7479/1041/2468 +f 7479/1041/2440 7466/1040/2440 7469/1039/2440 +# 11084 faces + diff --git a/examples/shaders/custom_uniform/barracks_diffuse.png b/examples/shaders/custom_uniform/barracks_diffuse.png new file mode 100644 index 0000000..ee81621 Binary files /dev/null and b/examples/shaders/custom_uniform/barracks_diffuse.png differ diff --git a/examples/shaders/custom_uniform/dwarf.obj b/examples/shaders/custom_uniform/dwarf.obj deleted file mode 100644 index a24f0c1..0000000 --- a/examples/shaders/custom_uniform/dwarf.obj +++ /dev/null @@ -1,54966 +0,0 @@ -# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware -# File Created: 28.05.2015 21:59:00 - -mtllib Enano_Final_001.mtl - -# -# object Box001 -# - -v 0.387459278107 0.001037180424 -0.000000000000 -v 0.357966661453 0.000561296940 -0.148274183273 -v 0.273977041245 0.000000000000 -0.273975044489 -v 0.148276805878 -0.000561356544 -0.357965648174 -v 0.000002622604 -0.001037240028 -0.387459248304 -v -0.148271799088 -0.001355171204 -0.357965648174 -v -0.273973226547 -0.001466870308 -0.273975044489 -v -0.357964754105 -0.001355171204 -0.148274242878 -v -0.387459278107 -0.001037240028 -0.000000059605 -v -0.357966899872 -0.000561356544 0.148274183273 -v -0.273977279663 -0.000000059605 0.273975014687 -v -0.148276805878 0.000561296940 0.357965707779 -v -0.000002861023 0.001037180424 0.387459278107 -v 0.148271799088 0.001355111599 0.357965588570 -v 0.273973226547 0.001466810703 0.273974895477 -v 0.357964634895 0.001355111599 0.148274123669 -v 0.387031078339 0.161010622978 -0.000428199768 -v 0.357538461685 0.160534739494 -0.148702442646 -v 0.273548841476 0.159973442554 -0.274403274059 -v 0.147848606110 0.159412086010 -0.358393877745 -v -0.000425577164 0.158936202526 -0.387887477875 -v -0.148699998856 0.158618271351 -0.358393877745 -v -0.274401426315 0.158506572247 -0.274403274059 -v -0.358391761780 0.158147990704 -0.148701190948 -v -0.387881040573 0.156506061554 -0.000421762466 -v -0.358393907547 0.158941805363 0.147847235203 -v -0.274405479431 0.159973382950 0.273546814919 -v -0.148705244064 0.160534739494 0.357537508011 -v -0.000431060791 0.161010622978 0.387031078339 -v 0.147843360901 0.161328554153 0.357537388802 -v 0.273545026779 0.161440253258 0.273546695709 -v 0.357536435127 0.161328554153 0.147845864296 -v 0.353100299835 0.160919785500 -0.000428199768 -v 0.326190590858 0.160485565662 -0.135717749596 -v 0.249556064606 0.159973442554 -0.250410705805 -v 0.134863615036 0.159461259842 -0.327046126127 -v -0.000425815582 0.159027040005 -0.353956878185 -v -0.135715484619 0.158736944199 -0.327046126127 -v -0.250409126282 0.158635079861 -0.250410705805 -v -0.327044963837 0.158685207367 -0.135717630386 -v -0.353955745697 0.158622086048 -0.000427186489 -v -0.327047109604 0.159409523010 0.134861409664 -v -0.250412702560 0.159973382950 0.249554216862 -v -0.135720252991 0.160485565662 0.326189637184 -v -0.000430822372 0.160919785500 0.353100419044 -v 0.134859085083 0.161209881306 0.326189637184 -v 0.249552488327 0.161311805248 0.249554157257 -v 0.326188802719 0.161209881306 0.134861171246 -v 0.353296518326 0.087664961815 -0.000232100487 -v 0.326386690140 0.087230741978 -0.135521650314 -v 0.249752044678 0.086718618870 -0.250214606524 -v 0.135059833527 0.086206436157 -0.326850026846 -v -0.000229597092 0.085772216320 -0.353760749102 -v -0.135519504547 0.085482120514 -0.326850026846 -v -0.250212907791 0.085380256176 -0.250214606524 -v -0.326848983765 0.085482120514 -0.135521650314 -v -0.353760719299 0.085772216320 -0.000232160091 -v -0.326851129532 0.086206436157 0.135057389736 -v -0.250216484070 0.086718559265 0.249750316143 -v -0.135524034500 0.087230741978 0.326385736465 -v -0.000234603882 0.087664961815 0.353296518326 -v 0.135055065155 0.087955057621 0.326385736465 -v 0.249748706818 0.088056981564 0.249750256538 -v 0.326384902000 0.087955057621 0.135057270527 -v 0.375676870346 0.177378296852 -0.000472128391 -v 0.364366769791 0.177348017693 -0.000472128391 -v 0.347045183182 0.176916301250 -0.144418120384 -v 0.336596012115 0.176899909973 -0.140089869499 -v 0.265507221222 0.176371395588 -0.266449689865 -v 0.257509708405 0.176371395588 -0.258452177048 -v 0.143476247787 0.175826430321 -0.347988516092 -v 0.139147996902 0.175842821598 -0.337539315224 -v -0.000469446182 0.175364434719 -0.376621156931 -v -0.000469684601 0.175394713879 -0.365310996771 -v -0.144415855408 0.175055742264 -0.347988516092 -v -0.140087604523 0.175095319748 -0.337539315224 -v -0.266447782516 0.174947381020 -0.266449689865 -v -0.258450269699 0.174990177155 -0.258452177048 -v -0.347987651825 0.175055742264 -0.144418120384 -v -0.337538242340 0.175095319748 -0.140089929104 -v -0.376621246338 0.175364434719 -0.000472187996 -v -0.365311145782 0.175394713879 -0.000472187996 -v -0.347989559174 0.175826430321 0.143473863602 -v -0.337540388107 0.175842821598 0.139145612717 -v -0.266451835632 0.176371335983 0.265505313873 -v -0.258454084396 0.176371335983 0.257507801056 -v -0.144420623779 0.176916301250 0.347044229507 -v -0.140092372894 0.176899909973 0.336595058441 -v -0.000474929810 0.177378296852 0.375676870346 -v -0.000474691391 0.177348017693 0.364366769791 -v 0.143471479416 0.177686989307 0.347044229507 -v 0.139143228531 0.177647411823 0.336595058441 -v 0.265503644943 0.177795350552 0.265505313873 -v 0.257506132126 0.177752554417 0.257507801056 -v 0.347043275833 0.177686989307 0.143473744392 -v 0.336594104767 0.177647411823 0.139145493507 -v -0.260723114014 0.157754421234 -0.259547352791 -v 0.188534498215 0.162128329277 0.220312714577 -v 0.150835990906 0.255903840065 -0.122018277645 -v -0.367745399475 0.145474791527 -0.000509381294 -v 0.326006412506 0.188046872616 0.061991870403 -v -0.140351295471 0.145963966846 0.338536977768 -v -0.092543125153 0.133517801762 0.209983170033 -v -0.045091629028 0.219104647636 0.071014165878 -v 0.117162466049 0.138920009136 0.148487687111 -v 0.094516038895 0.211338222027 0.006093084812 -v 0.141849040985 0.167456209660 -0.338641077280 -v -0.132145881653 0.224308967590 -0.168267190456 -v -0.290617465973 0.153861880302 0.041577756405 -v 0.232747793198 0.220157623291 -0.020193576813 -v -0.104435920715 0.156720459461 0.107542216778 -v 0.261220932007 0.215893089771 0.140530586243 -v 0.339339137077 0.144055008888 0.139837384224 -v 0.232198715210 0.238567829132 -0.074207901955 -v 0.139328241348 0.221993207932 -0.251845806837 -v 0.001096725464 0.115566849709 0.232506930828 -v 0.235008478165 0.183093011379 -0.224647879601 -v 0.025869607925 0.220658242702 0.010586977005 -v -0.260028839111 0.142340183258 0.258761763573 -v 0.149353027344 0.195868253708 0.071023166180 -v -0.312650203705 0.150955259800 0.143607854843 -v -0.012047052383 0.257859528065 -0.223151683807 -v -0.092512130737 0.135187923908 0.292060732841 -v -0.015312671661 0.255189657211 -0.138771057129 -v 0.137337684631 0.183658897877 -0.296297132969 -v -0.172811269760 0.177352190018 -0.007483303547 -v 0.223266124725 0.217488348484 0.090728402138 -v 0.064405202866 0.252335906029 -0.226450979710 -v -0.188626766205 0.189203381538 -0.061699330807 -v 0.016028881073 0.124756276608 0.299646496773 -v 0.089669704437 0.233257532120 -0.075778305531 -v 0.139914751053 0.137555956841 0.338332772255 -v 0.284914731979 0.198863744736 -0.022770822048 -v 0.304054975510 0.196833968163 0.028051853180 -v -0.097067356110 0.222885787487 -0.054254412651 -v -0.237313508987 0.144842386246 0.232705712318 -v 0.269050121307 0.216346383095 0.051027357578 -v -0.120793342590 0.202318608761 0.021182298660 -v -0.339625835419 0.138534486294 0.138899505138 -v 0.037177801132 0.231764197350 -0.090419173241 -v 0.143469810486 0.149774491787 0.195432603359 -v 0.293514966965 0.187747895718 -0.097219467163 -v -0.168785572052 0.151870310307 0.060518741608 -v 0.020806550980 0.266882598400 -0.172512531281 -v 0.259666919708 0.145984232426 0.258646607399 -v 0.034334182739 0.252145409584 -0.135116934776 -v -0.140362977982 0.156036436558 -0.339551180601 -v 0.032037258148 0.132924497128 0.150658845901 -v 0.366469740868 0.153844237328 -0.000785291195 -v -0.013993501663 0.172754645348 0.088831484318 -v 0.075382471085 0.258517682552 -0.122498214245 -v -0.144392013550 0.200841248035 -0.234057486057 -v 0.200603008270 0.174400389194 0.172962725163 -v -0.017191648483 0.226316809654 0.000772595406 -v 0.077378988266 0.224100291729 -0.039400041103 -v -0.000497341156 0.134032607079 0.366490840912 -v 0.338284015656 0.156314671040 -0.141668856144 -v -0.153885364532 0.204451203346 -0.099687397480 -v 0.195820569992 0.205458104610 0.131933152676 -v 0.216483592987 0.239142835140 -0.141529560089 -v -0.048132896423 0.252258181572 -0.187425732613 -v 0.048329114914 0.181412041187 0.058874249458 -v 0.297631740570 0.188538789749 0.118461728096 -v 0.094685554504 0.275856882334 -0.177895724773 -v 0.291773080826 0.176003396511 0.168679654598 -v 0.258277654648 0.169047772884 -0.258827954531 -v -0.025267601013 0.222986042500 -0.080369651318 -v -0.082452535629 0.196722209454 -0.287426501513 -v -0.052076101303 0.149037420750 0.130536139011 -v 0.078437328339 0.166446685791 -0.351232022047 -v -0.079320430756 0.196040034294 0.077153921127 -v 0.147503852844 0.252151966095 -0.186089634895 -v -0.237520694733 0.165661454201 -0.003286302090 -v -0.029679536819 0.118149220943 0.186804175377 -v 0.181889533997 0.212109684944 -0.008958518505 -v -0.094622135162 0.229876041412 -0.137650251389 -v 0.069519281387 0.135161101818 0.174413204193 -v 0.278537750244 0.214016139507 0.012907266617 -v -0.000745296478 0.139973580837 0.130587935448 -v 0.161170482635 0.208140671253 0.035515487194 -v -0.166126012802 0.139393448830 0.192975401878 -v 0.290117979050 0.177705764771 -0.146035611629 -v 0.020158529282 0.206230044365 0.052492976189 -v -0.134399890900 0.143064141273 0.142413377762 -v -0.266332864761 0.169014453888 -0.063792705536 -v 0.132324457169 0.250333786011 -0.097359597683 -v 0.001193761826 0.159170746803 -0.367280960083 -v -0.188598394394 0.189268946648 -0.191226005554 -v 0.097879648209 0.156538784504 0.109527528286 -v 0.203623294830 0.224369049072 -0.037161529064 -v -0.129595041275 0.211527705193 -0.041961491108 -v -0.339376449585 0.143820405006 -0.140513777733 -v 0.205133199692 0.213180243969 -0.004063129425 -v 0.233246803284 0.214453101158 -0.008401036263 -v 0.206484079361 0.212388336658 0.016018033028 -v 0.242507219315 0.213977515697 0.010456264019 -v 0.209819316864 0.211635589600 0.041306018829 -v 0.251682043076 0.213515639305 0.034897506237 -v 0.219023942947 0.211915493011 0.102876901627 -v 0.255498886108 0.213328659534 0.102843940258 -v 0.209807872772 0.211321473122 0.073793649673 -v 0.260978460312 0.213306427002 0.070012688637 -v 0.218056917191 0.213957488537 -0.009956002235 -v 0.237318038940 0.212719857693 0.106576442719 -v 0.201871395111 0.223009884357 -0.005214691162 -v 0.234170436859 0.224603056908 -0.010290384293 -v 0.201443910599 0.221436142921 0.017751872540 -v 0.247167825699 0.223902463913 0.009773075581 -v 0.204860687256 0.220546007156 0.042006075382 -v 0.256182670593 0.223231375217 0.033681809902 -v 0.217150449753 0.220006823540 0.104498565197 -v 0.257226705551 0.222062766552 0.105154514313 -v 0.202792167664 0.219771981239 0.074708163738 -v 0.266690969467 0.222605288029 0.069311499596 -v 0.216041564941 0.224303185940 -0.016883432865 -v 0.236886978149 0.220857679844 0.113419055939 -v 0.201165676117 0.241792380810 -0.002464711666 -v 0.235595226288 0.243774831295 -0.008793592453 -v 0.200091838837 0.239008307457 0.019165515900 -v 0.248582601547 0.241591095924 0.009618818760 -v 0.203350067139 0.236650824547 0.041424393654 -v 0.256637573242 0.239299356937 0.032281756401 -v 0.218260288239 0.230036914349 0.104059219360 -v 0.253784656525 0.232075154781 0.103391885757 -v 0.206028461456 0.232413649559 0.076064765453 -v 0.216443300247 0.243729174137 -0.014796018600 -v 0.236021757126 0.231211543083 0.111301779747 -v 0.247812032700 0.238879442215 0.099651157856 -v 0.235158205032 0.239502251148 0.103205502033 -v 0.262071609497 0.235375046730 0.069712936878 -v 0.252540349960 0.260097324848 0.055052101612 -v 0.222467422485 0.237549602985 0.101014792919 -v 0.212550878525 0.258014202118 0.062277555466 -v 0.201892614365 0.345312535763 0.008776485920 -v 0.242216825485 0.349303513765 0.009433805943 -v 0.191249847412 0.342574447393 0.028094410896 -v 0.255865812302 0.346988528967 0.028772234917 -v 0.196735858917 0.339674323797 0.052435636520 -v 0.258110046387 0.343376874924 0.052006244659 -v 0.221249341965 0.348548620939 0.002917945385 -v 0.222075462341 0.356713175774 0.034231722355 -v 0.229865312576 0.337269216776 0.076513707638 -v 0.232888221741 0.263725697994 0.063763737679 -v 0.204312324524 0.270660489798 0.003390491009 -v 0.236067295074 0.272651731968 -0.001152694225 -v 0.200947046280 0.266749739647 0.023094773293 -v 0.249783754349 0.268808007240 0.012558996677 -v 0.202597379684 0.262279391289 0.042629957199 -v 0.255157470703 0.263839781284 0.032649099827 -v 0.218951225281 0.272833973169 -0.005811095238 -v 0.248102664948 0.339510381222 0.071823954582 -v 0.211038351059 0.337233841419 0.072277426720 -v 0.212896347046 0.211532533169 0.087992787361 -v 0.260196208954 0.213362693787 0.086466848850 -v 0.206652641296 0.219657599926 0.088583350182 -v 0.265573501587 0.222268044949 0.086174011230 -v 0.208487510681 0.231236219406 0.089933633804 -v 0.261114358902 0.233485519886 0.086178541183 -v 0.249599456787 0.241804718971 0.087328910828 -v 0.218761682510 0.240887939930 0.090320706367 -v 0.234282970428 0.244165539742 0.089901387691 -v 0.249197959900 0.245250940323 0.071763932705 -v 0.233741044998 0.248610019684 0.075530111790 -v 0.218100309372 0.243478000164 0.076156377792 -v 0.259891033173 0.237450182438 0.052915513515 -v 0.262217521667 0.222825467587 0.053764879704 -v 0.257991552353 0.213336646557 0.054791927338 -v 0.209878206253 0.211354732513 0.060339868069 -v 0.203500509262 0.219918906689 0.060940921307 -v 0.205494880676 0.234648823738 0.060976922512 -v 0.232362031937 0.296486437321 0.068670928478 -v 0.247957706451 0.297481447458 0.058879435062 -v 0.214935302734 0.296461522579 0.063020169735 -v 0.256248474121 0.300734728575 0.041230976582 -v 0.205139160156 0.308436393738 0.010030686855 -v 0.238288879395 0.311282992363 0.009258210659 -v 0.199443340302 0.304088622332 0.028930902481 -v 0.251448392868 0.306685805321 0.022934615612 -v 0.202795028687 0.299219369888 0.047689616680 -v 0.221186876297 0.311318457127 0.002745151520 -v 0.225008487701 0.352216601372 0.053049981594 -v 0.202267408371 0.358467698097 0.014773547649 -v 0.193837165833 0.356905907393 0.031560063362 -v 0.200456142426 0.354091018438 0.051699697971 -v 0.214915990829 0.351570516825 0.066617071629 -v 0.227507829666 0.352972269058 0.069517612457 -v 0.240033149719 0.354288905859 0.067502856255 -v 0.247437715530 0.356183379889 0.048327982426 -v 0.255626201630 0.361346334219 0.031195163727 -v 0.243300676346 0.363204896450 0.016159296036 -v 0.220804214478 0.361127465963 0.011520028114 -v -0.006412744522 0.219254732132 -0.070368289948 -v -0.034497737885 0.219416260719 -0.075179994106 -v -0.007551431656 0.219255983829 -0.050698041916 -v -0.043589591980 0.219416618347 -0.056793034077 -v -0.010588407516 0.219317317009 -0.025610864162 -v -0.052551269531 0.219525873661 -0.032343029976 -v -0.019434452057 0.219501733780 0.036931097507 -v -0.056055307388 0.219407021999 0.036677896976 -v -0.010255813599 0.219376742840 0.007310867310 -v -0.061593055725 0.219416677952 0.003298044205 -v -0.019374847412 0.219313621521 -0.076339542866 -v -0.037804126740 0.219456374645 0.040600121021 -v -0.003419399261 0.229272305965 -0.072110950947 -v -0.035720348358 0.229651033878 -0.077736675739 -v -0.002564668655 0.228819966316 -0.049440383911 -v -0.048538923264 0.229538142681 -0.058115601540 -v -0.005802154541 0.228773951530 -0.025171041489 -v -0.057313680649 0.229480981827 -0.033867120743 -v -0.017800569534 0.228000402451 0.038410604000 -v -0.058048009872 0.228443384171 0.038873791695 -v -0.003192663193 0.228343427181 0.008078634739 -v -0.067610979080 0.228918552399 0.002470076084 -v -0.017654657364 0.229513227940 -0.083801627159 -v -0.037597417831 0.228035628796 0.047402024269 -v -0.003135919571 0.248828172684 -0.071072876453 -v -0.037687301636 0.249413430691 -0.078146457672 -v -0.001599311829 0.247187077999 -0.049244463444 -v -0.050426006317 0.247864484787 -0.059458792210 -v -0.004717350006 0.245696306229 -0.026384413242 -v -0.058178663254 0.246295332909 -0.035779118538 -v -0.019185543060 0.238504111767 0.037673413754 -v -0.054839372635 0.239117026329 0.036907553673 -v -0.006999969482 0.241730749607 0.009231150150 -v -0.018567800522 0.249538004398 -0.083647012711 -v -0.037009954453 0.238889813423 0.044985234737 -v -0.049028873444 0.246678113937 0.033095300198 -v -0.036361932755 0.247815668583 0.036695182323 -v -0.063289403915 0.242662429810 0.002855598927 -v -0.054507970810 0.268849194050 -0.014230966568 -v -0.023601055145 0.246319174767 0.034479141235 -v -0.014294147491 0.268415987492 -0.006592750549 -v -0.007125854492 0.352546513081 -0.070307731628 -v -0.047215461731 0.354491233826 -0.074513196945 -v 0.003531694412 0.351069599390 -0.050791621208 -v -0.060627460480 0.352100074291 -0.057532072067 -v -0.001306772232 0.349359750748 -0.028730213642 -v -0.062292337418 0.349174886942 -0.036085724831 -v -0.026328802109 0.354579001665 -0.078574538231 -v -0.027374744415 0.363825768232 -0.050758659840 -v -0.033916950226 0.346315592527 -0.004494011402 -v -0.034796714783 0.273458153009 -0.005827486515 -v -0.007123708725 0.278406739235 -0.068862497807 -v -0.038926839828 0.278996378183 -0.074869096279 -v -0.003371477127 0.275840729475 -0.048226654530 -v -0.052319049835 0.275491327047 -0.060075223446 -v -0.004662275314 0.272252291441 -0.027530074120 -v -0.057320117950 0.271499335766 -0.038320362568 -v -0.021856307983 0.279480308294 -0.079001605511 -v -0.051886796951 0.346334606409 -0.018019616604 -v -0.015472888947 0.347499132156 -0.012708246708 -v -0.013341426849 0.219453394413 0.021781980991 -v -0.060760498047 0.219377577305 0.020002603531 -v -0.007234573364 0.228128254414 0.022226035595 -v -0.066421747208 0.228480756283 0.019553661346 -v -0.009428262711 0.240280926228 0.023335456848 -v -0.062236309052 0.240545749664 0.019495189190 -v -0.050906419754 0.249981880188 0.020713865757 -v -0.019988298416 0.250182330608 0.023671388626 -v -0.035615205765 0.253143727779 0.023297965527 -v -0.050571680069 0.253851354122 0.004940390587 -v -0.035207986832 0.258085966110 0.008688688278 -v -0.019476890564 0.253200232983 0.009263873100 -v -0.061208486557 0.244841516018 -0.014327108860 -v -0.063190460205 0.229270637035 -0.013317525387 -v -0.058711767197 0.219515621662 -0.012146055698 -v -0.010442733765 0.219379901886 -0.006376981735 -v -0.004127025604 0.228489577770 -0.005963206291 -v -0.006670236588 0.244056880474 -0.006213486195 -v -0.035041809082 0.306504577398 -0.012205660343 -v -0.050817012787 0.305917531252 -0.022203505039 -v -0.017575979233 0.306866586208 -0.015941679478 -v -0.059380531311 0.307994395494 -0.039807379246 -v -0.009127378464 0.316277623177 -0.068142294884 -v -0.042343616486 0.317533701658 -0.072862088680 -v -0.003009557724 0.313361108303 -0.048151373863 -v -0.055118322372 0.313115835190 -0.059049367905 -v -0.005843162537 0.309433162212 -0.029619455338 -v -0.025185585022 0.317963033915 -0.077642977238 -v -0.029360532761 0.360437393188 -0.033840239048 -v -0.013695001602 0.365091145039 -0.063374280930 -v -0.005713224411 0.364561080933 -0.049769103527 -v -0.006861448288 0.363386452198 -0.031659960747 -v -0.019543409348 0.360915482044 -0.018560290337 -v -0.032689571381 0.360493153334 -0.010817825794 -v -0.045087814331 0.359358161688 -0.021629929543 -v -0.058130502701 0.362013280392 -0.034903645515 -v -0.055710792542 0.363338232040 -0.056892096996 -v -0.040955543518 0.367505073547 -0.065858364105 -v -0.026666879654 0.366931766272 -0.066344976425 -v 0.019335746765 0.891146719456 0.147463440895 -v 0.077193498611 0.876855552197 -0.156872689724 -v 0.077016353607 0.674709022045 -0.110481500626 -v 0.026651859283 0.777218222618 0.134643375874 -v 0.027640104294 0.662163913250 0.117864131927 -v 0.092115879059 0.819933474064 0.165385544300 -v 0.022340536118 0.851363182068 0.150859296322 -v 0.081831455231 0.861464142799 0.176887631416 -v 0.145524740219 0.883852779865 0.172923028469 -v 0.158493518829 0.841617703438 0.157872855663 -v 0.277504920959 1.007843017578 0.047269701958 -v 0.272853851318 1.025377511978 0.051120281219 -v 0.286534786224 1.034585952759 0.047402620316 -v 0.302318572998 0.995641767979 0.049039125443 -v 0.262354612350 0.997510433197 0.039628624916 -v 0.254748582840 1.029515981674 0.052300691605 -v 0.286922931671 0.964170455933 0.051867485046 -v 0.263444900513 0.934777021408 -0.010773301125 -v 0.278232336044 0.898669064045 -0.017279744148 -v 0.282225131989 0.895403862000 -0.048148393631 -v 0.268206119537 0.922013401985 -0.048899114132 -v 0.263873815536 0.932216346264 -0.047488868237 -v 0.249542474747 0.950950801373 -0.014343142509 -v 0.242866039276 0.973144650459 0.013231754303 -v 0.257011651993 0.958706617355 0.025045931339 -v 0.272060394287 0.937663674355 0.036257743835 -v 0.267414808273 0.922991752625 0.012871444225 -v 0.282770156860 0.902756571770 0.011130094528 -v 0.123666524887 0.582465767860 -0.075673460960 -v 0.149766921997 0.525964796543 -0.038310170174 -v 0.177918195724 0.547954797745 -0.041567981243 -v 0.164103984833 0.607049584389 -0.064459025860 -v 0.103845834732 0.528503477573 -0.026832699776 -v 0.132575511932 0.506744384766 -0.010294854641 -v 0.262545824051 0.962624549866 -0.120018243790 -v 0.277079582214 0.942464232445 -0.121075093746 -v 0.283565044403 0.978037595749 -0.130021154881 -v 0.242907762527 1.002508759499 -0.135505557060 -v 0.261280298233 0.944051027298 -0.092559337616 -v 0.272555112839 0.925887763500 -0.087273895741 -v 0.231066703796 0.961506426334 -0.136641144753 -v 0.218405961990 0.840843498707 0.091216206551 -v 0.210432529449 0.794565856457 0.084894001484 -v 0.186074256897 0.768438935280 0.106157541275 -v 0.168217658997 0.802124977112 0.130858242512 -v 0.239678859711 0.831269502640 0.040043413639 -v 0.225566387177 0.781253993511 0.055830478668 -v 0.209580659866 0.882061362267 0.132225513458 -v 0.155940294266 0.740337014198 0.119884729385 -v 0.106715440750 0.770864248276 0.151021718979 -v 0.178981781006 0.699676811695 0.084566056728 -v 0.182432651520 0.725065171719 0.095114350319 -v 0.204370975494 0.743299126625 0.076818108559 -v 0.213043212891 0.707077801228 0.041539013386 -v 0.136242151260 0.711864829063 0.109547138214 -v 0.155378341675 0.589013695717 0.109423935413 -v 0.137723207474 0.638659536839 0.112122654915 -v 0.171539545059 0.636296868324 0.090351223946 -v 0.201073408127 0.608585000038 0.070430636406 -v 0.217098474503 0.565734565258 0.062991678715 -v 0.191636562347 0.555289149284 0.088190674782 -v 0.150764703751 1.090515971184 0.031594216824 -v 0.133168458939 1.064684152603 0.068517208099 -v 0.107606649399 1.083139657974 0.037304639816 -v 0.119329452515 1.104554176331 0.014675736427 -v 0.187176704407 1.110415458679 0.029244542122 -v 0.202834844589 1.080092191696 0.052686989307 -v 0.179083585739 1.058245539665 0.064180791378 -v 0.160923242569 1.034242868423 0.096240758896 -v 0.254607439041 1.061115264893 0.052536368370 -v 0.220592498779 1.047652482986 0.058174490929 -v 0.231979370117 1.086294531822 0.047397136688 -v 0.231719017029 1.019516706467 0.049612939358 -v 0.293545246124 0.912459313869 0.040535092354 -v 0.235724687576 1.107659101486 0.028177142143 -v 0.274882793427 1.085638523102 0.028672218323 -v 0.096796751022 0.524665117264 0.020752966404 -v 0.121049642563 1.164031744003 -0.039851784706 -v 0.109050750732 1.171761870384 -0.060386240482 -v 0.151132822037 1.143172383308 -0.073541879654 -v 0.162862539291 1.139242529869 -0.047275900841 -v 0.166463375092 1.129762411118 -0.013145327568 -v 0.125269412994 1.148490905762 -0.022257208824 -v 0.222014427185 1.136164307594 -0.085919082165 -v 0.229552507401 1.134870767593 -0.049831032753 -v 0.233881950378 1.128509044647 -0.008981227875 -v 0.281436681747 1.108168125153 -0.051254689693 -v 0.281991004944 1.102712631226 -0.009698688984 -v 0.317685604095 1.067490458488 -0.049807429314 -v 0.317203044891 1.065495610237 -0.009583413601 -v 0.306344747543 1.052000999451 0.026935875416 -v 0.343569040298 1.024486541748 -0.007518947124 -v 0.329200625420 1.013627648354 0.025783419609 -v 0.366793274879 0.985834360123 -0.007350325584 -v 0.354122877121 0.976988136768 0.026278495789 -v 0.334745645523 0.958747029305 0.052049517632 -v 0.379283428192 0.947536230087 0.020861685276 -v 0.362321138382 0.928932666779 0.043664336205 -v 0.342812895775 0.907195210457 0.044864654541 -v 0.314275741577 0.935671687126 0.057043790817 -v 0.319790363312 0.888074278831 0.029314041138 -v 0.379310607910 0.902640283108 0.024499237537 -v 0.358928322792 0.880074322224 0.019105792046 -v 0.338169336319 0.861247479916 0.001740396023 -v 0.400299787521 0.877586364746 0.025739133358 -v 0.380050063133 0.852149724960 0.022235631943 -v 0.363364696503 0.827350735664 0.010587811470 -v 0.362974047661 0.811894834042 -0.017841279507 -v 0.332549810410 0.850514173508 -0.031367659569 -v 0.376002192497 0.802355408669 -0.049095809460 -v 0.339113950729 0.838486850262 -0.071368515491 -v 0.312850952148 0.871554672718 -0.076692581177 -v 0.306100845337 0.872793436050 -0.043697237968 -v 0.402581334114 0.810562849045 -0.068494379520 -v 0.367998600006 0.846436321735 -0.105324327946 -v 0.326204538345 0.882910430431 -0.107103466988 -v 0.432064533234 0.831387817860 -0.069692969322 -v 0.409785628319 0.862663328648 -0.103722870350 -v 0.452204942703 0.860042333603 -0.057465374470 -v 0.432444095612 0.890474557877 -0.088653087616 -v 0.403483510017 0.924710273743 -0.103032827377 -v 0.390702843666 0.900007128716 -0.125450611115 -v 0.458554625511 0.884764671326 -0.038810074329 -v 0.440712213516 0.916401028633 -0.064721584320 -v 0.409626007080 0.946123480797 -0.076701641083 -v 0.377049446106 0.978414773941 -0.079899370670 -v 0.369030594826 0.959930837154 -0.107197761536 -v 0.434939265251 0.931571722031 -0.036256074905 -v 0.403420209885 0.955381631851 -0.043758153915 -v 0.375007867813 0.986278414726 -0.043334543705 -v 0.346902847290 1.024103283882 -0.045506417751 -v 0.346037387848 1.015392422676 -0.082815170288 -v 0.391106963158 0.955277502537 -0.011757612228 -v 0.418347239494 0.931938529015 -0.009633421898 -v 0.398629426956 0.921277165413 0.011540293694 -v 0.441792011261 0.907627224922 0.005505323410 -v 0.420485854149 0.897287666798 0.019965410233 -v 0.454711556435 0.901762425900 -0.017239570618 -v 0.312911748886 1.057415366173 -0.085565030575 -v 0.301878452301 1.036462783813 -0.110103130341 -v 0.341517090797 0.998458266258 -0.115687966347 -v 0.291906356812 1.012423157692 -0.127237200737 -v 0.328496098518 0.970709323883 -0.136209249496 -v 0.354727029800 0.934686720371 -0.121113419533 -v 0.311561107635 0.939342975616 -0.134227514267 -v 0.340052127838 0.908680558205 -0.124131619930 -v 0.367459774017 0.884051918983 -0.123385787010 -v 0.297220230103 0.911664009094 -0.117913901806 -v 0.289204835892 0.899315834045 -0.083201110363 -v 0.250025033951 1.053760290146 -0.137834787369 -v 0.264823913574 1.083865046501 -0.119606435299 -v 0.201839447021 1.117434144020 -0.118024945259 -v 0.189693689346 1.079212427139 -0.142952740192 -v 0.277281999588 1.102975010872 -0.089239239693 -v 0.120431184769 1.085181832314 -0.138198077679 -v 0.121253252029 1.037931799889 -0.155860960484 -v 0.184354066849 1.029958724976 -0.157751560211 -v 0.119925260544 1.132153749466 -0.108325600624 -v 0.123482465744 0.987731099129 -0.170279264450 -v 0.180538892746 0.979573845863 -0.163978517056 -v 0.125545501709 0.932765841484 -0.173250615597 -v 0.179258108139 0.925383329391 -0.162734568119 -v 0.227316141129 0.914090216160 -0.128659784794 -v 0.178707361221 0.866539001465 -0.151616394520 -v 0.224370002747 0.859528779984 -0.116147398949 -v 0.256502151489 0.857412219048 -0.071282267570 -v 0.259006500244 0.905853331089 -0.084065675735 -v 0.258020401001 0.867200314999 -0.023059964180 -v 0.263725519180 0.906981647015 -0.038188934326 -v 0.246686458588 0.885027527809 0.019917786121 -v 0.248519420624 0.927023947239 0.000404238701 -v 0.239131689072 0.904338777065 0.060729622841 -v 0.241918325424 0.948883771896 0.032647311687 -v 0.229748249054 0.932023048401 0.094542920589 -v 0.231833934784 0.972128450871 0.056386351585 -v 0.237094879150 0.996514856815 0.032092094421 -v 0.225894212723 0.997993648052 0.079689145088 -v 0.216531753540 0.964301168919 0.116260170937 -v 0.190495014191 0.998777031898 0.114465355873 -v 0.204521656036 1.026806235313 0.079624712467 -v 0.192690134048 0.921263933182 0.150567412376 -v 0.164333105087 0.961874485016 0.145105898380 -v 0.135314941406 1.002291202545 0.123882234097 -v 0.122396469116 0.928251743317 0.165373027325 -v 0.099461555481 0.973314642906 0.142395615578 -v 0.080953598022 1.017653703690 0.112643778324 -v 0.110545635223 1.040468931198 0.096353948116 -v 0.067555904388 1.051582455635 0.072920858860 -v 0.089736461639 1.065327763557 0.058615803719 -v 0.057373523712 0.952757716179 0.147553682327 -v 0.047913312912 1.000822305679 0.117389440536 -v 0.042551279068 1.041895747185 0.078767657280 -v 0.069515228271 0.905283331871 0.168992578983 -v 0.244445800781 0.817365288734 -0.006311953068 -v 0.244346380234 0.804270505905 -0.054641485214 -v 0.217851400375 0.751652359962 -0.033641099930 -v 0.227277755737 0.763818323612 0.012114584446 -v 0.197771310806 0.745314657688 -0.074247181416 -v 0.188985824585 0.683782935143 -0.054120063782 -v 0.209798336029 0.693763196468 -0.014226317406 -v 0.216273546219 0.801639676094 -0.098835766315 -v 0.174543857574 0.806066751480 -0.130712211132 -v 0.165594577789 0.745285034180 -0.103144109249 -v 0.123121976852 0.748481452465 -0.116453528404 -v 0.120306491852 0.673266887665 -0.099647700787 -v 0.158249378204 0.678283751011 -0.080645978451 -v 0.126316308975 0.812821507454 -0.142758727074 -v 0.126960277557 0.873750686646 -0.163805663586 -v 0.068856477737 0.984705030918 -0.177298188210 -v 0.055420398712 1.084348678589 -0.154314756393 -v 0.046322107315 1.128087520599 -0.128710865974 -v 0.075109720230 0.593776226044 -0.089249253273 -v 0.192573547363 0.621916353703 -0.036496400833 -v 0.203611850739 0.571760535240 -0.021339297295 -v 0.217868804932 0.595229387283 0.017003238201 -v 0.213207960129 0.638992846012 0.003613412380 -v 0.204703092575 0.652575969696 0.048748970032 -v 0.170325040817 0.665199697018 0.078543841839 -v 0.130563020706 0.677610635757 0.104269742966 -v 0.083450555801 0.650120198727 0.126545190811 -v 0.081408262253 0.691678225994 0.131133735180 -v 0.086372137070 0.729118704796 0.137566983700 -v 0.026894569397 0.740492343903 0.127000212669 -v 0.088793277740 0.606545627117 0.116948366165 -v 0.091482639313 0.568313062191 0.093596041203 -v 0.093423366547 0.540040552616 0.060054659843 -v 0.137021780014 0.550631523132 0.090929865837 -v 0.129982471466 0.524636745453 0.061635315418 -v 0.129219055176 0.512163639069 0.027145802975 -v 0.155890464783 0.512163281441 0.061540365219 -v 0.151852607727 0.501129508018 0.032996356487 -v 0.151466369629 0.490233093500 0.004889369011 -v 0.164501428604 0.473722547293 0.017774462700 -v 0.166211366653 0.483703285456 0.041170895100 -v 0.176519632339 0.462068229914 0.050208270550 -v 0.178006410599 0.457004278898 0.029782295227 -v 0.190201759338 0.459076434374 0.014697730541 -v 0.178750276566 0.478803396225 0.000907838345 -v 0.166320323944 0.497839301825 -0.015286624432 -v 0.207526922226 0.465957105160 0.009304404259 -v 0.199348926544 0.490522235632 -0.004005312920 -v 0.189775466919 0.514920592308 -0.020356297493 -v 0.225358963013 0.475811570883 0.017339110374 -v 0.221742391586 0.505469441414 0.004819691181 -v 0.213993549347 0.536153674126 -0.007584154606 -v 0.236834526062 0.485237836838 0.038113415241 -v 0.233140468597 0.520117580891 0.029869019985 -v 0.226602554321 0.556548476219 0.023947119713 -v 0.239451885223 0.491162627935 0.065631270409 -v 0.229833841324 0.528143048286 0.060667395592 -v 0.239911079407 0.454511433840 0.042522192001 -v 0.245521306992 0.457225382328 0.067053318024 -v 0.237636566162 0.455539733171 0.084717154503 -v 0.226967334747 0.489047199488 0.082951843739 -v 0.211964607239 0.523329734802 0.080300390720 -v 0.217800378799 0.450385510921 0.087392747402 -v 0.206350564957 0.480243116617 0.084223449230 -v 0.190374135971 0.509804129601 0.078286647797 -v 0.183592557907 0.468741506338 0.072134256363 -v 0.173839807510 0.494874238968 0.062670707703 -v 0.168895244598 0.532966911793 0.083921194077 -v 0.194311380386 0.443297296762 0.078714847565 -v 0.186420440674 0.440069437027 0.057327508926 -v 0.193065404892 0.417387604713 0.057190775871 -v 0.203305721283 0.417975842953 0.076225996017 -v 0.205404996872 0.391247153282 0.066273987293 -v 0.194074869156 0.392329305410 0.049775362015 -v 0.190062761307 0.393557667732 0.030566751957 -v 0.192551136017 0.417236864567 0.037556171417 -v 0.188753843307 0.438155025244 0.037616431713 -v 0.199758052826 0.395951777697 0.012652158737 -v 0.201189756393 0.418664783239 0.020802915096 -v 0.198827505112 0.439186781645 0.022741913795 -v 0.220117330551 0.398994356394 0.008019566536 -v 0.217715263367 0.422239899635 0.015295565128 -v 0.213492631912 0.443650007248 0.018471002579 -v 0.236896991730 0.400686651468 0.011681675911 -v 0.232114553452 0.425558745861 0.022678315639 -v 0.227942943573 0.449451982975 0.025451838970 -v 0.247877597809 0.399994522333 0.024417579174 -v 0.242132186890 0.427206337452 0.038007915020 -v 0.250198125839 0.367911368608 0.023290991783 -v 0.239138841629 0.370674878359 0.011764705181 -v 0.234215259552 0.326959192753 0.024860799313 -v 0.239667415619 0.325394153595 0.032651007175 -v 0.239298582077 0.323285490274 0.041500747204 -v 0.250197172165 0.363285213709 0.041953921318 -v 0.248555660248 0.397186785936 0.044638574123 -v 0.236860036850 0.320421725512 0.050307810307 -v 0.239134788513 0.358723700047 0.058663964272 -v 0.239214897156 0.393967717886 0.063256323338 -v 0.230540990829 0.316507697105 0.058507502079 -v 0.225771665573 0.354905188084 0.069335877895 -v 0.224077701569 0.390892267227 0.075807273388 -v 0.220066547394 0.317402213812 0.054555177689 -v 0.211529970169 0.357036679983 0.059551179409 -v 0.212295293808 0.320155978203 0.044720351696 -v 0.198891878128 0.359852999449 0.045892953873 -v 0.208841085434 0.323172211647 0.033653140068 -v 0.194800376892 0.364280372858 0.028407096863 -v 0.212930202484 0.325841575861 0.024493038654 -v 0.203210353851 0.368161261082 0.013654232025 -v 0.223614931107 0.327202796936 0.020913243294 -v 0.221999883652 0.371129333973 0.011114120483 -v 0.299593925476 0.875928103924 -0.016731262207 -v 0.305377960205 0.881739974022 0.006167829037 -v 0.124761581421 1.127089619637 -0.005370020866 -v 0.144920587540 1.114051818848 -0.000504493713 -v 0.320274353027 0.867451727390 -0.003048002720 -v 0.317344665527 0.863656222820 -0.015280425549 -v 0.081691741943 1.171155452728 -0.082533001900 -v 0.489620566368 0.754746913910 0.055047810078 -v 0.492703795433 0.744488835335 0.057417750359 -v 0.500872254372 0.748085975647 0.052790284157 -v 0.503330826759 0.759612381458 0.050021946430 -v 0.455907583237 0.767686963081 0.180662214756 -v 0.448605775833 0.763490140438 0.179388940334 -v 0.454131126404 0.774452686310 0.183209419250 -v 0.512239336967 0.719803869724 0.108971118927 -v 0.513665318489 0.712346911430 0.098931610584 -v 0.501137852669 0.723156571388 0.088684141636 -v 0.498448848724 0.729723930359 0.098093867302 -v 0.506369471550 0.735136747360 0.129543185234 -v 0.510510444641 0.727772593498 0.119067549706 -v 0.495698451996 0.736607313156 0.107330560684 -v 0.491642713547 0.742265939713 0.117717981339 -v 0.492995619774 0.730934858322 0.070337891579 -v 0.488109588623 0.732578217983 0.080537736416 -v 0.505285978317 0.719612061977 0.078231096268 -v 0.525172829628 0.681995272636 0.167945027351 -v 0.521392345428 0.683978497982 0.175799846649 -v 0.521812319756 0.691806197166 0.180061340332 -v 0.519139647484 0.787753224373 0.090079247952 -v 0.529436826706 0.773348331451 0.102756619453 -v 0.523522257805 0.779470205307 0.115589499474 -v 0.511284351349 0.795331001282 0.102586388588 -v 0.539867997169 0.729618787766 0.089468300343 -v 0.531417727470 0.747590124607 0.073452115059 -v 0.527307748795 0.738277912140 0.066966652870 -v 0.535834193230 0.725835144520 0.077996909618 -v 0.523569345474 0.720503687859 0.128831326962 -v 0.526804924011 0.719818413258 0.135298848152 -v 0.537645578384 0.725556254387 0.133212625980 -v 0.540601491928 0.730802595615 0.123283326626 -v 0.534850597382 0.748413085938 0.143720269203 -v 0.533050775528 0.738149583340 0.147188425064 -v 0.521691203117 0.732560038567 0.148685574532 -v 0.515544414520 0.738024771214 0.147808253765 -v 0.521300554276 0.711467444897 0.118006944656 -v 0.506483316422 0.747644484043 0.153991520405 -v 0.502677559853 0.742156207561 0.140237092972 -v 0.501390576363 0.751134574413 0.149526238441 -v 0.541826605797 0.742310583591 0.123451471329 -v 0.541710376740 0.746488988400 0.128475904465 -v 0.540703296661 0.751621305943 0.123491525650 -v 0.541983366013 0.746656119823 0.119618058205 -v 0.532743930817 0.764434099197 0.148749291897 -v 0.529609441757 0.768829822540 0.144122123718 -v 0.533065080643 0.763605058193 0.139945745468 -v 0.534711122513 0.759675085545 0.143647730350 -v 0.519114732742 0.724147796631 0.142600655556 -v 0.515840530396 0.728727519512 0.137992262840 -v 0.540112376213 0.734770715237 0.138869524002 -v 0.540696740150 0.740617036819 0.133606433868 -v 0.522036075592 0.709590852261 0.079642355442 -v 0.515752315521 0.708322763443 0.088428199291 -v 0.523067712784 0.698891818523 0.096575498581 -v 0.528108596802 0.700006604195 0.087751507759 -v 0.538988947868 0.715688526630 0.081110537052 -v 0.540867447853 0.712676644325 0.084093391895 -v 0.543041229248 0.715164959431 0.088397443295 -v 0.540838479996 0.719581723213 0.084006726742 -v 0.506251692772 0.761048257351 0.153887510300 -v 0.509725928307 0.757334053516 0.158531010151 -v 0.525017738342 0.770337998867 0.149724423885 -v 0.527247309685 0.767623901367 0.152778089046 -v 0.526124477386 0.703662514687 0.107429325581 -v 0.541818618774 0.721548616886 0.089130938053 -v 0.543096542358 0.717609286308 0.092653989792 -v 0.514024734497 0.685954689980 0.172047317028 -v 0.515303611755 0.692099928856 0.177232980728 -v 0.518338084221 0.682923436165 0.165953993797 -v 0.535277485847 0.708344936371 0.147681176662 -v 0.524157166481 0.704845070839 0.148237943649 -v 0.523532152176 0.699540019035 0.152397453785 -v 0.534913420677 0.702481508255 0.152555465698 -v 0.519562959671 0.716747760773 0.161118566990 -v 0.530426263809 0.720963180065 0.161624073982 -v 0.530594706535 0.714648783207 0.166401624680 -v 0.519082903862 0.711292505264 0.165497899055 -v 0.516831398010 0.709372937679 0.154453039169 -v 0.516183376312 0.703925609589 0.158576548100 -v 0.538677573204 0.715157747269 0.155361831188 -v 0.538471341133 0.711140751839 0.158608913422 -v 0.533556699753 0.693566560745 0.159267961979 -v 0.521171927452 0.692192018032 0.156506180763 -v 0.519478797913 0.686819851398 0.160811662674 -v 0.531105518341 0.687699437141 0.163550257683 -v 0.516932487488 0.704223155975 0.170683681965 -v 0.529407978058 0.705302298069 0.173214852810 -v 0.527298688889 0.699028372765 0.177262067795 -v 0.515662312508 0.698305785656 0.174661695957 -v 0.512620925903 0.697871327400 0.162089228630 -v 0.511643767357 0.691746532917 0.166646361351 -v 0.537143468857 0.698810040951 0.168046832085 -v 0.535217404366 0.695275962353 0.170467853546 -v 0.537539839745 0.719420015812 0.138411521912 -v 0.526125192642 0.715106844902 0.139984965324 -v 0.524770259857 0.710178494453 0.144071102142 -v 0.534347414970 0.711749315262 0.141898036003 -v 0.521291613579 0.727184534073 0.152451038361 -v 0.531763315201 0.732593894005 0.152449965477 -v 0.526586532593 0.727051615715 0.158230066299 -v 0.519834280014 0.721794843674 0.156188130379 -v 0.519172072411 0.719282746315 0.146682977676 -v 0.518319606781 0.714717566967 0.150376081467 -v 0.542425036430 0.726674139500 0.146438956261 -v 0.541626691818 0.720945656300 0.142000854015 -v 0.540896654129 0.716939508915 0.144021809101 -v 0.542814254761 0.723198592663 0.149447917938 -v 0.538549065590 0.730741381645 0.152049660683 -v 0.537324070930 0.727843642235 0.155685722828 -v 0.540292024612 0.714531242847 0.147353291512 -v 0.541417002678 0.719230473042 0.152375280857 -v 0.537661671638 0.723493218422 0.157489120960 -v 0.522315740585 0.696558475494 0.153652429581 -v 0.532957553864 0.696634590626 0.154145359993 -v 0.526823282242 0.710777997971 0.170685768127 -v 0.517996311188 0.707997262478 0.167178988457 -v 0.514600038528 0.702156662941 0.159258484840 -v 0.540738582611 0.708825647831 0.160881042480 -v 0.539718866348 0.703809440136 0.156380772591 -v 0.539808750153 0.700395345688 0.157848179340 -v 0.541602373123 0.705698668957 0.163604915142 -v 0.537238717079 0.712285995483 0.166008591652 -v 0.536659955978 0.709942877293 0.169121146202 -v 0.539298772812 0.698089897633 0.160789132118 -v 0.540274739265 0.702055811882 0.166186392307 -v 0.536662101746 0.706197261810 0.170638501644 -v 0.540821313858 0.729771852493 0.143572688103 -v 0.534619212151 0.690335750580 0.174641072750 -v 0.534919500351 0.687159657478 0.171165943146 -v 0.534467816353 0.684770822525 0.172516167164 -v 0.533648490906 0.687150001526 0.176869094372 -v 0.533669948578 0.692957580090 0.178517937660 -v 0.532203197479 0.690804123878 0.179874420166 -v 0.528633236885 0.684847950935 0.177231550217 -v 0.531227588654 0.682927608490 0.170618474483 -v 0.534844160080 0.687096238136 0.168217778206 -v 0.534787893295 0.692861855030 0.172489643097 -v 0.532088637352 0.695515155792 0.178507089615 -v 0.528244614601 0.691161870956 0.180853903294 -v 0.542320370674 0.728663325310 0.099375784397 -v 0.542763829231 0.724370181561 0.102947711945 -v 0.543692111969 0.728317677975 0.108140170574 -v 0.543245792389 0.733878433704 0.103289365768 -v 0.539205074310 0.750491321087 0.133062005043 -v 0.538523197174 0.754346132278 0.129205644131 -v 0.543280839920 0.732618570328 0.112749457359 -v 0.543036103249 0.737028181553 0.108903169632 -v 0.531576871872 0.715822875500 0.076436996460 -v 0.537781238556 0.706454157829 0.084965169430 -v 0.516264319420 0.770024180412 0.150568723679 -v 0.521349906921 0.763900756836 0.157923758030 -v 0.548167467117 0.667905509472 0.148447632790 -v 0.546362757683 0.670237898827 0.157298624516 -v 0.545064449310 0.678077816963 0.161700785160 -v 0.530092954636 0.702552258968 0.114723563194 -v 0.540755271912 0.707639873028 0.112147867680 -v 0.542485356331 0.714294910431 0.102276742458 -v 0.538369178772 0.719116032124 0.127693057060 -v 0.527642726898 0.713942587376 0.130929112434 -v 0.524290800095 0.705752372742 0.123955726624 -v 0.543419122696 0.722295403481 0.112965941429 -v 0.543574094772 0.715997815132 0.118450582027 -v 0.538602828979 0.668676257133 0.156609654427 -v 0.538909435272 0.675573229790 0.161329925060 -v 0.541661739349 0.665838003159 0.149098932743 -v 0.544516205788 0.691595375538 0.125912368298 -v 0.534333825111 0.686268508434 0.128116250038 -v 0.535755872726 0.680908918381 0.132590770721 -v 0.546100020409 0.686485588551 0.130807101727 -v 0.530930757523 0.697768330574 0.144220829010 -v 0.540539383888 0.703372836113 0.142738342285 -v 0.542316913605 0.698138594627 0.147101879120 -v 0.532684803009 0.692637383938 0.148399233818 -v 0.528201103210 0.689944863319 0.137334823608 -v 0.529621005058 0.684429168701 0.141547918320 -v 0.547267079353 0.699201166630 0.134586215019 -v 0.548285603523 0.695777177811 0.137413918972 -v 0.549032688141 0.678514897823 0.138707518578 -v 0.538316488266 0.672254383564 0.139705061913 -v 0.539997816086 0.668147265911 0.143931210041 -v 0.549917817116 0.673808932304 0.142802059650 -v 0.535045385361 0.684714317322 0.155533432961 -v 0.545179843903 0.690104901791 0.154163777828 -v 0.546261072159 0.685271203518 0.157988131046 -v 0.536641716957 0.680283010006 0.159242749214 -v 0.531511306763 0.676025629044 0.148519396782 -v 0.533580183983 0.671684741974 0.152756392956 -v 0.551849842072 0.686028897762 0.146424531937 -v 0.552071809769 0.683168113232 0.148839414120 -v 0.542264461517 0.702010095119 0.117023289204 -v 0.531574487686 0.696618914604 0.119827747345 -v 0.533209562302 0.691803276539 0.124981045723 -v 0.542015671730 0.694402575493 0.120017051697 -v 0.527886033058 0.708098948002 0.135989665985 -v 0.538574695587 0.713628768921 0.133871257305 -v 0.536827564240 0.708746492863 0.140737891197 -v 0.529211044312 0.702663362026 0.140047073364 -v 0.525272846222 0.700050890446 0.129155695438 -v 0.527511239052 0.695425748825 0.133208036423 -v 0.547236084938 0.709693551064 0.126150548458 -v 0.546826839447 0.704466640949 0.120804965496 -v 0.547609567642 0.700840175152 0.122550547123 -v 0.548392534256 0.706934809685 0.128966629505 -v 0.544142603874 0.712298274040 0.132492303848 -v 0.544166088104 0.709887802601 0.136017978191 -v 0.548007726669 0.698595046997 0.125999212265 -v 0.548170447350 0.703358292580 0.131739497185 -v 0.545077085495 0.706430852413 0.137581646442 -v 0.536803126335 0.676721870899 0.136981487274 -v 0.546262025833 0.680178046227 0.133575916290 -v 0.541578054428 0.694177865982 0.152556836605 -v 0.533885598183 0.688042283058 0.151733100414 -v 0.530973911285 0.680204808712 0.144950151443 -v 0.550747156143 0.694574475288 0.139328360558 -v 0.550565600395 0.689205110073 0.134101927280 -v 0.551587820053 0.686272799969 0.135594725609 -v 0.551995396614 0.692323207855 0.141612648964 -v 0.547929286957 0.697340607643 0.145395517349 -v 0.548542022705 0.695518493652 0.148347735405 -v 0.552347660065 0.684621572495 0.138660132885 -v 0.552754878998 0.689439475536 0.144070029259 -v 0.549746870995 0.692574083805 0.149577498436 -v 0.544905066490 0.711640059948 0.123353600502 -v 0.554090023041 0.679983973503 0.152069270611 -v 0.554366350174 0.676740288734 0.148733615875 -v 0.555369496346 0.674915611744 0.149775743484 -v 0.555078744888 0.677470684052 0.154006123543 -v 0.553590416908 0.682599842548 0.155873715878 -v 0.553566455841 0.680583536625 0.157422304153 -v 0.552198171616 0.673865497112 0.155969619751 -v 0.553200006485 0.671683013439 0.148962199688 -v 0.553523778915 0.675942182541 0.146138072014 -v 0.552976369858 0.681672930717 0.150468468666 -v 0.551427602768 0.684173226357 0.156823754311 -v 0.550627708435 0.679804623127 0.159817218781 -v 0.561773300171 0.667005836964 0.108489274979 -v 0.562437891960 0.667055547237 0.116291821003 -v 0.561485767365 0.672465205193 0.121660053730 -v 0.532580971718 0.693629801273 0.092338800430 -v 0.540351271629 0.699979722500 0.089606344700 -v 0.542522072792 0.705165266991 0.104129672050 -v 0.533750057220 0.698765039444 0.106722295284 -v 0.530255436897 0.693876147270 0.100649118423 -v 0.544795274734 0.705484151840 0.095455408096 -v 0.543451189995 0.710095763206 0.092419564724 -v 0.556688308716 0.663857758045 0.117876172066 -v 0.557191729546 0.668581724167 0.123596191406 -v 0.557321429253 0.663886785507 0.110297203064 -v 0.550040364265 0.687514245510 0.096655666828 -v 0.542815566063 0.681384682655 0.099399805069 -v 0.546362757683 0.677153646946 0.101630270481 -v 0.552957534790 0.683309435844 0.099402546883 -v 0.543991684914 0.686676859856 0.113965272903 -v 0.550568699837 0.692732572556 0.109966218472 -v 0.552548170090 0.688747942448 0.112151980400 -v 0.546415090561 0.682839512825 0.116651713848 -v 0.540330171585 0.681044578552 0.107999801636 -v 0.543417692184 0.676724195480 0.110768854618 -v 0.553754329681 0.691745519638 0.102674782276 -v 0.555277824402 0.688932120800 0.104441046715 -v 0.558210253716 0.676781058311 0.102892100811 -v 0.551411271095 0.670395851135 0.105135142803 -v 0.554313540459 0.666436553001 0.107223451138 -v 0.560604929924 0.672852039337 0.104644954205 -v 0.551035642624 0.676183104515 0.121510207653 -v 0.557325959206 0.682806491852 0.115938246250 -v 0.559729456902 0.679148495197 0.118263065815 -v 0.554118156433 0.672260820866 0.123688340187 -v 0.547722101212 0.669512152672 0.114816784859 -v 0.551224112511 0.665718138218 0.116806447506 -v 0.561138749123 0.681422650814 0.108677029610 -v 0.562478303909 0.679623842239 0.109518647194 -v 0.544580936432 0.695759892464 0.091603696346 -v 0.536828517914 0.688898324966 0.094865858555 -v 0.539610147476 0.684746026993 0.097163736820 -v 0.545929908752 0.689909696579 0.093230366707 -v 0.538297772408 0.693749725819 0.109103918076 -v 0.546232938766 0.700979232788 0.105687260628 -v 0.547426342964 0.696206927299 0.109800815582 -v 0.541006326675 0.689810454845 0.111045122147 -v 0.534368872643 0.688101053238 0.103304982185 -v 0.538012027740 0.685010075569 0.105363309383 -v 0.550858020782 0.700949549675 0.097763538361 -v 0.549491643906 0.697909832001 0.093589007854 -v 0.550813794136 0.695187926292 0.094435930252 -v 0.552393674850 0.698510527611 0.099156975746 -v 0.550143718719 0.701255559921 0.102890193462 -v 0.551577091217 0.699175059795 0.104868292809 -v 0.552265882492 0.693053603172 0.096573829651 -v 0.553521633148 0.695399820805 0.100726366043 -v 0.552729487419 0.696392178535 0.105458736420 -v 0.549271106720 0.673505485058 0.104050397873 -v 0.554521441460 0.678445816040 0.100325822830 -v 0.553958654404 0.685331046581 0.116456747055 -v 0.548520803452 0.679022014141 0.118942022324 -v 0.546076059341 0.673519492149 0.112744927406 -v 0.557391166687 0.687807381153 0.105319499969 -v 0.556760072708 0.685200691223 0.101653337479 -v 0.558141469955 0.683105111122 0.102121174335 -v 0.559174299240 0.686151802540 0.106331229210 -v 0.556374430656 0.688750267029 0.109533429146 -v 0.557712197304 0.687251687050 0.111271739006 -v 0.559688806534 0.681563556194 0.103728890419 -v 0.560254931450 0.683878600597 0.107563853264 -v 0.559006214142 0.685161352158 0.111566960812 -v 0.547902107239 0.702368199825 0.096936225891 -v 0.564785003662 0.677279114723 0.110871613026 -v 0.565037727356 0.675400853157 0.107921242714 -v 0.566116333008 0.673743724823 0.108678221703 -v 0.566264390945 0.674956560135 0.112121045589 -v 0.564288020134 0.678330838680 0.113956749439 -v 0.565272808075 0.676626622677 0.115107536316 -v 0.565854787827 0.671615004539 0.113909065723 -v 0.565153121948 0.671011805534 0.108082771301 -v 0.564292907715 0.675019502640 0.105877757072 -v 0.563846707344 0.678827285767 0.109954953194 -v 0.563235521317 0.679445624352 0.115319430828 -v 0.564523458481 0.675631463528 0.117880046368 -v 0.508027791977 0.705808162689 0.185932517052 -v 0.503305912018 0.708674609661 0.193543970585 -v 0.504237651825 0.716933488846 0.197534382343 -v 0.514192581177 0.739058196545 0.152600765228 -v 0.527436256409 0.742018103600 0.152551293373 -v 0.521233081818 0.757511794567 0.163559794426 -v 0.510088562965 0.753134310246 0.162780582905 -v 0.506630778313 0.744708418846 0.157582461834 -v 0.531264781952 0.752472937107 0.158268332481 -v 0.532356500626 0.758174300194 0.153628230095 -v 0.496481537819 0.711037337780 0.188681483269 -v 0.497926712036 0.717670679092 0.193979084492 -v 0.501640081406 0.707217693329 0.182956755161 -v 0.524531006813 0.727519810200 0.166848421097 -v 0.513245224953 0.726689815521 0.165383756161 -v 0.511902570724 0.722795486450 0.168308913708 -v 0.523548841476 0.723003327847 0.171342372894 -v 0.509620904922 0.739431321621 0.176361441612 -v 0.520829081535 0.741701781750 0.179257631302 -v 0.519819498062 0.736979722977 0.183732628822 -v 0.508016705513 0.736198961735 0.179792046547 -v 0.506378054619 0.732324659824 0.169591844082 -v 0.504464268684 0.729115188122 0.172098159790 -v 0.528473019600 0.734543383121 0.174971342087 -v 0.527720928192 0.731290459633 0.178188145161 -v 0.518843531609 0.715346276760 0.178183495998 -v 0.507250308990 0.715426683426 0.173481583595 -v 0.504154086113 0.710596859455 0.177767276764 -v 0.515055418015 0.710507869720 0.182130753994 -v 0.502767324448 0.729494333267 0.186172127724 -v 0.514684081078 0.728843152523 0.190630316734 -v 0.510843634605 0.723370432854 0.194603562355 -v 0.499645948410 0.723829448223 0.190759420395 -v 0.498818874359 0.722565889359 0.177140593529 -v 0.495809078217 0.716866850853 0.182247757912 -v 0.521199822426 0.721097052097 0.187072217464 -v 0.518935918808 0.718163132668 0.189251482487 -v 0.525767803192 0.736793160439 0.157169640064 -v 0.513168215752 0.734809756279 0.157476186752 -v 0.513290882111 0.730967700481 0.161826848984 -v 0.522656917572 0.730214118958 0.160739362240 -v 0.510023117065 0.747913599014 0.168063998222 -v 0.522023916245 0.752246916294 0.169538915157 -v 0.518543243408 0.747491836548 0.175433754921 -v 0.509775161743 0.743234395981 0.172257661819 -v 0.506842017174 0.740149796009 0.162537455559 -v 0.507179975510 0.736026167870 0.166410088539 -v 0.533026695251 0.745195150375 0.165490031242 -v 0.531216979027 0.738591969013 0.161130785942 -v 0.530287504196 0.734632968903 0.163438796997 -v 0.532566308975 0.741663217545 0.168802976608 -v 0.529102921486 0.749674737453 0.170213341713 -v 0.527972817421 0.746949017048 0.173987030983 -v 0.529739618301 0.732569515705 0.167208254337 -v 0.531125068665 0.737987637520 0.172155261040 -v 0.527689337730 0.742842078209 0.176281332970 -v 0.509422302246 0.719553887844 0.170410692692 -v 0.519722938538 0.717905282974 0.172781825066 -v 0.514890789986 0.734458565712 0.187463164330 -v 0.505210161209 0.733366072178 0.182220578194 -v 0.502490282059 0.726530313492 0.174150884151 -v 0.528773427010 0.728935301304 0.181077003479 -v 0.527782201767 0.723789393902 0.176339983940 -v 0.526475429535 0.720672547817 0.177816569805 -v 0.527674317360 0.726253092289 0.183694541454 -v 0.525176644325 0.733416676521 0.184952259064 -v 0.523093461990 0.731555163860 0.187405228615 -v 0.524735569954 0.719069778919 0.180645465851 -v 0.525143027306 0.723502397537 0.185845911503 -v 0.521940231323 0.728395640850 0.189189791679 -v 0.531512737274 0.747916936874 0.162386298180 -v 0.516651630402 0.713900744915 0.192825019360 -v 0.516959309578 0.710621714592 0.189882099628 -v 0.516236543655 0.708358943462 0.191311597824 -v 0.515579700470 0.710943758488 0.195346117020 -v 0.515369772911 0.716586649418 0.195921123028 -v 0.514391779900 0.714817166328 0.197931408882 -v 0.510539889336 0.709055662155 0.195576369762 -v 0.513627529144 0.706451058388 0.189301311970 -v 0.517277002335 0.710314393044 0.187095999718 -v 0.517525792122 0.716093361378 0.190888464451 -v 0.514751195908 0.719347119331 0.196116745472 -v 0.510549068451 0.715662777424 0.198681712151 -v 0.533120870590 0.762782216072 0.130480825901 -v 0.524248719215 0.772845745087 0.138786017895 -v 0.540866613388 0.746797680855 0.109364151955 -v 0.537410974503 0.759103238583 0.116162776947 -v 0.540438890457 0.742126762867 0.095553338528 -v 0.520689725876 0.728452146053 0.065447509289 -v 0.512445688248 0.721606135368 0.069535374641 -v 0.484276175499 0.737580657005 0.089107573032 -v 0.532676100731 0.765493094921 0.091823399067 -v 0.533045768738 0.757094204426 0.081643581390 -v 0.514222741127 0.784138381481 0.129911184311 -v 0.490095019341 0.767989397049 0.145252108574 -v 0.479055404663 0.768541455269 0.143870294094 -v 0.488378524780 0.780031323433 0.144005358219 -v 0.498183012009 0.777795016766 0.142598867416 -v 0.481902122498 0.759345829487 0.139733493328 -v 0.467978596687 0.763386905193 0.133951485157 -v 0.455418944359 0.777963399887 0.119988799095 -v 0.451926827431 0.777264595032 0.134350359440 -v 0.458689928055 0.767885684967 0.141088008881 -v 0.468816995621 0.769495069981 0.148243069649 -v 0.476413726807 0.779487848282 0.150034487247 -v 0.438565135002 0.771156847477 0.177375793457 -v 0.441770315170 0.764434158802 0.175460696220 -v 0.444827079773 0.770441770554 0.183847427368 -v 0.469913721085 0.779009222984 0.155741333961 -v 0.463364720345 0.769138574600 0.153375625610 -v 0.460401535034 0.767174780369 0.158601582050 -v 0.467330098152 0.775935709476 0.162042737007 -v 0.453510165215 0.769425153732 0.147249221802 -v 0.450202226639 0.768634498119 0.153188824654 -v 0.467652678490 0.791541039944 0.152924060822 -v 0.464564323425 0.787662565708 0.161086738110 -v 0.456722617149 0.792148888111 0.148283004761 -v 0.454262137413 0.790213525295 0.153603911400 -v 0.449564695358 0.782195746899 0.142867326736 -v 0.445333719254 0.781309008598 0.150482535362 -v 0.462369918823 0.796061277390 0.131073176861 -v 0.470566511154 0.799281775951 0.136529088020 -v 0.469121217728 0.797714054585 0.143102586269 -v 0.460547566414 0.795852959156 0.138329267502 -v 0.455207109451 0.789058446884 0.126723527908 -v 0.453316926956 0.788498997688 0.133789181709 -v 0.477501153946 0.792452573776 0.146006584167 -v 0.465461015701 0.796401441097 0.147136926651 -v 0.458685755730 0.794838547707 0.143734753132 -v 0.453046441078 0.789503097534 0.139946758747 -v 0.477824330330 0.801583707333 0.131692588329 -v 0.462747812271 0.795654177666 0.121492981911 -v 0.461746931076 0.769132852554 0.174213290215 -v 0.453706622124 0.761957705021 0.170404195786 -v 0.443747997284 0.765161931515 0.166959524155 -v 0.460104227066 0.781512916088 0.175598621368 -v 0.445243358612 0.784041821957 0.176206707954 -v 0.449878454208 0.784194827080 0.178927242756 -v 0.448585391045 0.782106339931 0.182242095470 -v 0.443793654442 0.781242489815 0.181344807148 -v 0.440421819687 0.782552838326 0.174964666367 -v 0.439622640610 0.780634343624 0.178736805916 -v 0.438029885292 0.777883410454 0.165846407413 -v 0.457392096519 0.764703154564 0.162105917931 -v 0.465457439423 0.772188305855 0.166752159595 -v 0.447040438652 0.767057418823 0.158573865891 -v 0.465133786201 0.783054172993 0.168668568134 -v 0.452129364014 0.790718674660 0.158209085464 -v 0.459192514420 0.790737628937 0.162641108036 -v 0.459162950516 0.789255976677 0.167319536209 -v 0.450338006020 0.789745509624 0.162790656090 -v 0.445508122444 0.787147641182 0.154866278172 -v 0.442550182343 0.785621106625 0.158436417580 -v 0.440964460373 0.777064740658 0.156837046146 -v 0.456962108612 0.787429749966 0.170820236206 -v 0.448460698128 0.787783861160 0.167056441307 -v 0.441197395325 0.784746885300 0.163089811802 -v 0.447333574295 0.785258412361 0.169726729393 -v 0.443022251129 0.777300119400 0.184506356716 -v 0.450631856918 0.780292212963 0.183982253075 -v 0.453623771667 0.784703671932 0.178378582001 -v 0.445952057838 0.786179065704 0.172527611256 -v 0.438473701477 0.781861722469 0.171767473221 -v 0.437908291817 0.777420401573 0.178881585598 -v 0.492766499519 0.755644321442 0.143515646458 -v 0.486923098564 0.747458815575 0.130217909813 -v 0.466797590256 0.757182359695 0.099651396275 -v 0.472083091736 0.750997185707 0.089635670185 -v 0.469869136810 0.760206878185 0.083161294460 -v 0.463792681694 0.773227989674 0.097641050816 -v 0.480604887009 0.743164718151 0.097418367863 -v 0.509183526039 0.740819334984 0.056642234325 -v 0.515854835510 0.750867664814 0.056534111500 -v 0.500680327415 0.800476849079 0.113281011581 -v 0.480252742767 0.809417188168 0.104322493076 -v 0.496218204498 0.805853843689 0.093608915806 -v 0.494943737984 0.789026916027 0.136653363705 -v 0.501828312874 0.788901865482 0.133081078529 -v 0.507851958275 0.797888576984 0.081428110600 -v 0.522942423820 0.779709160328 0.077857553959 -v 0.499507188797 0.765030682087 0.148840188980 -v 0.507470130920 0.774820327759 0.144708752632 -v 0.476036071777 0.746732592583 0.106510400772 -v 0.493361711502 0.803006708622 0.122841835022 -v 0.478899002075 0.807841002941 0.117558896542 -v 0.463644027710 0.796741485596 0.111424744129 -v 0.465716123581 0.794997811317 0.103478550911 -v 0.458229780197 0.777908682823 0.107420504093 -v 0.462887525558 0.761031866074 0.109043002129 -v 0.471899509430 0.750320196152 0.116126954556 -v 0.478152394295 0.753174483776 0.131771326065 -v 0.468824982643 0.755779623985 0.124225437641 -v 0.461404800415 0.763227701187 0.116893410683 -v 0.489722132683 0.797489106655 0.133335888386 -v 0.486714601517 0.789863348007 0.141924619675 -v 0.484797358513 0.741189062595 0.067133903503 -v 0.478503465652 0.751935124397 0.068854808807 -v 0.500882506371 0.734169185162 0.061571240425 -v 0.477385044098 0.744656562805 0.080763101578 -v 0.481624126434 0.739364206791 0.075847864151 -v 0.500677943230 0.775840044022 0.048178792000 -v 0.488707780838 0.765670180321 0.051871418953 -v 0.477584242821 0.762718737125 0.063034832478 -v 0.467450737953 0.766845524311 0.076912343502 -v 0.461498498917 0.778625905514 0.089994966984 -v 0.461806297302 0.795562386513 0.096759736538 -v 0.470135807991 0.809676170349 0.096153378487 -v 0.483797073364 0.812756240368 0.088045477867 -v 0.497678637505 0.805696189404 0.075719475746 -v 0.504785418510 0.791619062424 0.059249997139 -v 0.513334751129 0.788233518600 0.068128407001 -v 0.511568665504 0.770020723343 0.053026437759 -v 0.520908117294 0.761221706867 0.061087131500 -v 0.497784495354 0.788155913353 0.046932697296 -v 0.488117575645 0.775684356689 0.047841131687 -v 0.475840330124 0.770089447498 0.057217180729 -v 0.463661313057 0.771884500980 0.069685220718 -v 0.455235481262 0.782279491425 0.081061065197 -v 0.454746246338 0.798582255840 0.087480664253 -v 0.461082696915 0.812864422798 0.088064253330 -v 0.473519444466 0.820378422737 0.082788586617 -v 0.488731861115 0.816120684147 0.070775330067 -v 0.498112678528 0.803522765636 0.056562244892 -v 0.494563221931 0.799096226692 0.042310714722 -v 0.486902475357 0.808524429798 0.030907094479 -v 0.478900671005 0.793341755867 0.029809832573 -v 0.486203432083 0.785064756870 0.041563153267 -v 0.464779496193 0.783073127270 0.035595595837 -v 0.472564697266 0.777089834213 0.049066007137 -v 0.450284838676 0.780604720116 0.044155120850 -v 0.458022236824 0.776483118534 0.058857560158 -v 0.440367698669 0.784753084183 0.049066960812 -v 0.443802475929 0.787280976772 0.064302384853 -v 0.444123268127 0.804896831512 0.073245406151 -v 0.451916456223 0.821180701256 0.076650619507 -v 0.464986562729 0.832542598248 0.073360800743 -v 0.480245232582 0.831362009048 0.059292852879 -v 0.481340765953 0.834166049957 0.044129669666 -v 0.492998480797 0.814772903919 0.050042569637 -v 0.486271023750 0.822800278664 0.037332177162 -v 0.523271918297 0.770754814148 0.068353176117 -v 0.514518499374 0.778774738312 0.058889150620 -v 0.507184267044 0.776329338551 0.050279438496 -v 0.508969664574 0.781902492046 0.054183304310 -v 0.244488239288 0.426662117243 0.058280527592 -v 0.238626718521 0.424758225679 0.073367774487 -v 0.224532604218 0.421156793833 0.082624495029 -v 0.024168014526 0.813921332359 0.149686336517 -v -0.045492410660 0.811454951763 0.138143301010 -v -0.043429851532 0.849619209766 0.152232885361 -v -0.103686809540 0.858773767948 0.124039173126 -v -0.105726003647 0.821566998959 0.105698108673 -v -0.216044902802 1.015913844109 -0.065555334091 -v -0.209439516068 0.999427437782 -0.058619439602 -v -0.211006164551 0.987861990929 -0.064142704010 -v -0.230187892914 0.988817870617 -0.073895573616 -v -0.197565555573 0.993671536446 -0.052417397499 -v -0.196903944016 0.968688607216 -0.066415429115 -v -0.226006031036 0.954002797604 -0.069144666195 -v -0.186616420746 0.850906968117 -0.171889841557 -v -0.197167158127 0.860019028187 -0.140617847443 -v -0.179961204529 0.897772192955 -0.115278422832 -v -0.166189670563 0.875091910362 -0.153516530991 -v -0.148694753647 0.880870044231 -0.136985838413 -v -0.150884389877 0.907215118408 -0.104235470295 -v -0.157392501831 0.931122899055 -0.078570246696 -v -0.191499710083 0.929601490498 -0.075881302357 -v -0.215350627899 0.919599175453 -0.078258514404 -v -0.203397989273 0.897285580635 -0.100253224373 -v -0.217379808426 0.875960350037 -0.118124604225 -v -0.029005050659 0.571525335312 -0.088107168674 -v 0.002735614777 0.548631310463 -0.070256829262 -v 0.027010679245 0.590999245644 -0.090317308903 -v -0.018280744553 0.620064198971 -0.103850007057 -v 0.018197059631 0.528473854065 -0.041200280190 -v 0.039121389389 0.542406558990 -0.043555021286 -v -0.148338317871 0.925767302513 -0.247407793999 -v -0.147905111313 0.887462854385 -0.231083989143 -v -0.130671024323 0.907526671886 -0.214898705482 -v -0.110074996948 0.950674951077 -0.223033547401 -v -0.158329963684 0.874756038189 -0.191096603870 -v -0.134732007980 0.893178164959 -0.177285671234 -v -0.090615749359 0.914829909801 -0.207994282246 -v -0.112192392349 0.762768864632 0.047738432884 -v -0.126791477203 0.781367957592 0.019289433956 -v -0.137742519379 0.815532445908 0.021429121494 -v -0.104435205460 0.789754331112 0.077099800110 -v -0.129538536072 0.770201504230 -0.012699365616 -v -0.138639211655 0.806268036366 -0.033546984196 -v -0.147496223450 0.848499417305 0.061839640141 -v -0.089931488037 0.741834282875 0.071407139301 -v -0.054453372955 0.767961084843 0.118939399719 -v -0.098224401474 0.709381341934 0.028533697128 -v -0.111907958984 0.714046895504 -0.023087024689 -v -0.118014335632 0.742692947388 0.013800978661 -v -0.105286121368 0.729441761971 0.038245499134 -v -0.068748474121 0.719616711140 0.068620622158 -v -0.085082054138 0.653443753719 0.027877748013 -v -0.058162212372 0.656390905380 0.056895077229 -v -0.050686836243 0.607604086399 0.047678053379 -v -0.099447727203 0.621420621872 0.005962431431 -v -0.068820476532 0.563984632492 0.037404358387 -v -0.093855857849 0.573501050472 0.006214916706 -v -0.061287641525 1.064289569855 0.001488387585 -v -0.092086315155 1.040367364883 0.017865002155 -v -0.100042343140 1.063028454781 -0.025874853134 -v -0.068414211273 1.083276271820 -0.024904131889 -v -0.152829885483 1.043263196945 -0.030532896519 -v -0.132411718369 1.076464056969 -0.043527424335 -v -0.132525444031 1.024463057518 -0.009899616241 -v -0.121130466461 1.003944158554 0.032351315022 -v -0.171019792557 1.007393002510 -0.034520506859 -v -0.196717739105 1.027601242065 -0.048720419407 -v -0.173523902893 1.051656365395 -0.044109880924 -v -0.172769784927 0.976805567741 -0.047324657440 -v -0.238524913788 0.893932402134 -0.094456076622 -v -0.167498588562 1.074029922485 -0.061905801296 -v -0.199609756470 1.058331489563 -0.076546132565 -v 0.035741090775 0.537817895412 0.004574596882 -v 0.063968896866 0.537479221821 0.012407362461 -v 0.069581508636 0.543589949608 -0.037130057812 -v -0.067850828171 1.115831255913 -0.122188806534 -v -0.044815301895 1.153640151024 -0.091253459454 -v -0.061902284622 1.142533540726 -0.076420962811 -v -0.087494134903 1.110044360161 -0.101176381111 -v -0.102974891663 1.099434852600 -0.071468591690 -v -0.069273948669 1.125692009926 -0.061185836792 -v -0.110057592392 1.099711656570 -0.165807723999 -v -0.129351377487 1.099599599838 -0.132730364799 -v -0.150191068649 1.093798398972 -0.095395982265 -v -0.167793750763 1.074134111404 -0.162128686905 -v -0.187201261520 1.073685646057 -0.118393898010 -v -0.200552225113 1.044490218163 -0.186491847038 -v -0.215443849564 1.052723646164 -0.141018509865 -v -0.222080469131 1.039790749550 -0.094145119190 -v -0.239657878876 1.022207856178 -0.158943414688 -v -0.241830825806 1.013184070587 -0.110611021519 -v -0.260427713394 0.986940979958 -0.176530241966 -v -0.263617753983 0.981970906258 -0.132411062717 -v -0.260305166245 0.958638668060 -0.098890125751 -v -0.278702974319 0.955592036247 -0.163595557213 -v -0.278200626373 0.932817518711 -0.130598545074 -v -0.271001577377 0.901743829250 -0.119967401028 -v -0.252998113632 0.927197396755 -0.088302910328 -v -0.255738973618 0.872728466988 -0.122977674007 -v -0.288134813309 0.917696714401 -0.166244506836 -v -0.280348777771 0.886196553707 -0.155893802643 -v -0.267940998077 0.855949759483 -0.158157467842 -v -0.322344541550 0.899317681789 -0.184273540974 -v -0.314202308655 0.871414363384 -0.169530987740 -v -0.304754018784 0.841402471066 -0.163097262383 -v -0.351705789566 0.865829944611 -0.176985263824 -v -0.346288204193 0.842895746231 -0.165701746941 -v -0.342967510223 0.821778357029 -0.172056436539 -v -0.297340869904 0.818372488022 -0.180801868439 -v -0.255311727524 0.834150016308 -0.184277534485 -v -0.344840049744 0.807662725449 -0.190519332886 -v -0.298639774323 0.802460789680 -0.209736287594 -v -0.253891229630 0.813284337521 -0.222991466522 -v -0.215986251831 0.835866868496 -0.183695673943 -v -0.214768171310 0.830051660538 -0.219524562359 -v -0.309920310974 0.802444458008 -0.240571200848 -v -0.261218309402 0.820708096027 -0.265693724155 -v -0.202613115311 0.844021797180 -0.252863943577 -v -0.351272106171 0.804853558540 -0.214755058289 -v -0.361089944839 0.814315497875 -0.239227890968 -v -0.324601888657 0.821000874043 -0.263598829508 -v -0.283481359482 0.848797678947 -0.284017473459 -v -0.368223667145 0.837127387524 -0.253749161959 -v -0.336348056793 0.853153288364 -0.277962535620 -v -0.297395467758 0.883530080318 -0.294476032257 -v -0.240055322647 0.874735951424 -0.304646462202 -v -0.264170885086 0.907689154148 -0.292484790087 -v -0.343079566956 0.886833965778 -0.280547678471 -v -0.304080247879 0.919566035271 -0.288546800613 -v -0.274107933044 0.937634170055 -0.272911608219 -v -0.237725257874 0.939036250114 -0.275381207466 -v -0.246447801590 0.963879764080 -0.250892400742 -v -0.299230575562 0.941379368305 -0.261109113693 -v -0.274475336075 0.952009916306 -0.239782989025 -v -0.254629850388 0.977320313454 -0.217426180840 -v -0.217944860458 0.993275702000 -0.236558616161 -v -0.229768037796 1.010393023491 -0.203123748302 -v -0.274976491928 0.958194017410 -0.204134941101 -v -0.294450044632 0.945626258850 -0.227268993855 -v -0.291128396988 0.938337326050 -0.193792879581 -v -0.336385011673 0.927444577217 -0.237453699112 -v -0.328366279602 0.918976187706 -0.207168340683 -v -0.373788356781 0.900349020958 -0.237839400768 -v -0.367165803909 0.902696073055 -0.212942600250 -v -0.358767509460 0.887838721275 -0.192018508911 -v -0.399082183838 0.886386156082 -0.210687160492 -v -0.391416311264 0.878774166107 -0.190892636776 -v -0.385291337967 0.862347722054 -0.175807774067 -v -0.380799770355 0.844238936901 -0.168828010559 -v -0.377043247223 0.828504204750 -0.168903589249 -v -0.378103971481 0.815952479839 -0.178110599518 -v -0.382728338242 0.809657692909 -0.196520686150 -v -0.389034032822 0.812136590481 -0.218078017235 -v -0.393783569336 0.826233685017 -0.232942044735 -v -0.374763011932 0.861356377602 -0.261329650879 -v -0.397455453873 0.845723807812 -0.239633858204 -v -0.401363134384 0.864607393742 -0.240126490593 -v -0.377741813660 0.885030388832 -0.257234215736 -v -0.342441082001 0.914424657822 -0.266438513994 -v -0.402511835098 0.878381252289 -0.229500651360 -v -0.170168876648 1.000604867935 -0.237006545067 -v -0.184483528137 1.026935815811 -0.219662249088 -v -0.204886913300 0.972634196281 -0.262749642134 -v -0.159294366837 0.967827081680 -0.247309863567 -v -0.191198587418 0.937436878681 -0.281654030085 -v -0.222276926041 0.905950903893 -0.284064441919 -v -0.177347660065 0.896951436996 -0.278299987316 -v -0.199582099915 0.874506413937 -0.276412338018 -v -0.219844818115 0.853652238846 -0.284712314606 -v -0.174687385559 0.863596737385 -0.250282466412 -v -0.181549310684 0.849696934223 -0.207981944084 -v -0.116446971893 1.003559350967 -0.234433829784 -v -0.131599664688 1.042656898499 -0.224299788475 -v -0.063884496689 1.038912057877 -0.210333466530 -v -0.085042953491 1.078667521477 -0.191534459591 -v -0.149874925613 1.067245244980 -0.198640346527 -v 0.006145715714 1.018314838409 -0.186279118061 -v -0.007123947144 1.064264893532 -0.171564280987 -v -0.048004388809 0.991492629051 -0.217727243900 -v -0.026478528976 1.111588954926 -0.142706692219 -v 0.017360448837 0.970607042313 -0.195879101753 -v -0.035747051239 0.945858657360 -0.214797735214 -v 0.026816844940 0.918899655342 -0.194363832474 -v -0.025933980942 0.897993922234 -0.206000804901 -v -0.080864667892 0.874895334244 -0.192031383514 -v -0.018188714981 0.847238957882 -0.190483808517 -v -0.072869777679 0.831310868263 -0.174542069435 -v -0.116947174072 0.821985781193 -0.144294202328 -v -0.121940612793 0.859033942223 -0.160447001457 -v -0.136636972427 0.828852474689 -0.101162433624 -v -0.142194747925 0.857307851315 -0.121078729630 -v -0.143414735794 0.845660209656 -0.058004975319 -v -0.144388198853 0.880819320679 -0.082161068916 -v -0.153039455414 0.862532734871 -0.018098533154 -v -0.153266906738 0.903006434441 -0.052416980267 -v -0.161772251129 0.888247668743 0.014432668686 -v -0.160099267960 0.926342248917 -0.032119214535 -v -0.164556503296 0.953284680843 -0.062894344330 -v -0.171996355057 0.952526032925 -0.012361943722 -v -0.164795875549 0.921657145023 0.036377131939 -v -0.147756576538 0.961669743061 0.040470600128 -v -0.158525466919 0.986356794834 -0.006434679031 -v -0.145291805267 0.885101556778 0.083670973778 -v -0.126105070114 0.929664313793 0.086600899696 -v -0.100680828094 0.976286113262 0.074836552143 -v -0.088333368301 0.904943823814 0.124103307724 -v -0.068841934204 0.954400718212 0.109162628651 -v -0.050687789917 1.002869248390 0.086499452591 -v -0.076419353485 1.019973993301 0.056980848312 -v -0.031089067459 1.040452837944 0.053422629833 -v -0.048895835876 1.049849748611 0.030142068863 -v -0.028286457062 0.943060517311 0.130822718143 -v -0.018934726715 0.993253171444 0.104324102402 -v -0.008577823639 1.036106586456 0.068773925304 -v 0.016984224319 0.938255190849 0.132273197174 -v 0.016255617142 0.988211154938 0.106916069984 -v 0.017256975174 1.034857988358 0.074777126312 -v -0.037022590637 0.893554985523 0.148184359074 -v -0.125862836838 0.795052647591 -0.077642142773 -v -0.088509559631 0.748381972313 -0.091158628464 -v -0.106392145157 0.784361839294 -0.120982527733 -v -0.114890336990 0.757017672062 -0.053101658821 -v -0.051238536835 0.693981826305 -0.101675391197 -v -0.053010225296 0.743843674660 -0.121231853962 -v -0.086938619614 0.703561365604 -0.072716116905 -v -0.064249753952 0.786670446396 -0.151442766190 -v -0.010465383530 0.743931651115 -0.136873304844 -v -0.013234376907 0.796020328999 -0.166346788406 -v 0.032855987549 0.676068127155 -0.117384016514 -v 0.034677505493 0.748068869114 -0.133399724960 -v -0.010420322418 0.684079170227 -0.115326344967 -v 0.036463499069 0.808236598969 -0.159694790840 -v 0.077756881714 0.752460122108 -0.118776857853 -v 0.079266071320 0.817305207253 -0.140415549278 -v 0.034280061722 0.864266276360 -0.182166934013 -v 0.072944402695 0.932042717934 -0.169168591499 -v 0.063047170639 1.036345005035 -0.171650230885 -v -0.058959484100 0.640669405460 -0.090303719044 -v -0.066095590591 0.592738807201 -0.077589452267 -v -0.097780227661 0.609835147858 -0.045422494411 -v -0.095155477524 0.656358480453 -0.060826182365 -v -0.105790376663 0.668013811111 -0.016322851181 -v -0.087153911591 0.680714309216 0.023537695408 -v -0.060539484024 0.690345466137 0.063132166862 -v -0.022153139114 0.659986138344 0.099782228470 -v -0.026333808899 0.697329998016 0.108290851116 -v -0.032596349716 0.731493532658 0.113822937012 -v 0.026883125305 0.702849328518 0.121817588806 -v -0.007471561432 0.622038125992 0.083720922470 -v 0.033208370209 0.620859384537 0.106691539288 -v 0.010722160339 0.584229052067 0.067391037941 -v 0.046667098999 0.584562242031 0.083252370358 -v 0.025924444199 0.553159415722 0.041892528534 -v 0.057153224945 0.554712772369 0.051456034184 -v -0.020308732986 0.569664835930 0.051660239697 -v 0.001250267029 0.543498456478 0.031863629818 -v 0.013638973236 0.532003760338 -0.001672267914 -v -0.000382900238 0.520153343678 -0.005273222923 -v -0.012644290924 0.528460025787 0.023336231709 -v 0.006472110748 0.512750744820 -0.036196351051 -v -0.007425308228 0.474734485149 -0.000116705894 -v -0.005846261978 0.500033557415 -0.004471659660 -v 0.000211715698 0.494048833847 -0.030069172382 -v -0.006864786148 0.472749769688 -0.022261261940 -v -0.018941164017 0.475434243679 -0.039400577545 -v -0.014056682587 0.499557584524 -0.049792110920 -v -0.007712841034 0.522083699703 -0.061311900616 -v -0.037567615509 0.480722934008 -0.046939432621 -v -0.037078142166 0.509507179260 -0.057908356190 -v -0.034726858139 0.538039565086 -0.071861624718 -v -0.058244705200 0.486637681723 -0.040571570396 -v -0.064287900925 0.519816040993 -0.052058398724 -v -0.066971778870 0.554416954517 -0.064069986343 -v -0.073494434357 0.490894377232 -0.019915223122 -v -0.083090543747 0.529140114784 -0.027455270290 -v -0.092357873917 0.568181574345 -0.034658551216 -v -0.079753637314 0.491208374500 0.009451150894 -v -0.086676597595 0.532695353031 0.006102561951 -v -0.073581457138 0.454350113869 0.007979691029 -v -0.066380023956 0.457608014345 -0.017444491386 -v -0.067813158035 0.488057374954 0.029619216919 -v -0.066108465195 0.450441658497 0.027257204056 -v -0.069606781006 0.527580559254 0.030218899250 -v -0.044326543808 0.482478886843 0.033305048943 -v -0.044793844223 0.448259085417 0.031902611256 -v -0.042425155640 0.517599105835 0.031794846058 -v -0.017328262329 0.477021217346 0.022542297840 -v -0.018852710724 0.507313489914 0.017633438110 -v -0.037883758545 0.545025348663 0.042228996754 -v -0.019141912460 0.447015106678 0.024648547173 -v -0.009853363037 0.448897719383 0.002969503403 -v -0.010138511658 0.424218118191 -0.001672625542 -v -0.006133556366 0.399529516697 -0.015495121479 -v -0.017596960068 0.394342869520 -0.000591039658 -v -0.020816802979 0.419395595789 0.016798019409 -v -0.009426116943 0.427912145853 -0.021588802338 -v -0.001868963242 0.404415190220 -0.034041702747 -v -0.011332273483 0.450134307146 -0.017913401127 -v -0.018124103546 0.431156426668 -0.039218008518 -v -0.011564016342 0.408847093582 -0.052631855011 -v -0.021310806274 0.452264279127 -0.034315645695 -v -0.035163879395 0.433271795511 -0.046046972275 -v -0.032569646835 0.410334706306 -0.058933556080 -v -0.036829233170 0.455296754837 -0.040022969246 -v -0.050311565399 0.433117091656 -0.039737045765 -v -0.049625396729 0.409451037645 -0.056582272053 -v -0.052719354630 0.457712709904 -0.034135818481 -v -0.060839176178 0.430344671011 -0.025123417377 -v -0.060647249222 0.405378311872 -0.044947326183 -v -0.039075374603 0.333637267351 -0.059441745281 -v -0.046819448471 0.377576559782 -0.066945731640 -v -0.057845830917 0.373610943556 -0.056396543980 -v -0.044396162033 0.332225650549 -0.051878690720 -v -0.043912887573 0.330512613058 -0.042705893517 -v -0.057412862778 0.368281006813 -0.038785338402 -v -0.061007261276 0.399160534143 -0.025505304337 -v -0.041280269623 0.328136712313 -0.033087968826 -v -0.046390056610 0.364219039679 -0.022349596024 -v -0.051404714584 0.393975228071 -0.006930351257 -v -0.035102367401 0.325139790773 -0.023742496967 -v -0.033584117889 0.360739827156 -0.011030375957 -v -0.036393165588 0.389957576990 0.006403863430 -v -0.024703979492 0.326273173094 -0.026353597641 -v -0.019546747208 0.364557057619 -0.018281936646 -v -0.016890287399 0.328833460808 -0.035211801529 -v -0.006627321243 0.368008077145 -0.028945624828 -v -0.013489007950 0.331431388855 -0.046256422997 -v -0.002036094666 0.373024463654 -0.045083582401 -v -0.017686605453 0.333469033241 -0.056734740734 -v -0.010092020035 0.377158254385 -0.060950160027 -v -0.028373241425 0.334166795015 -0.062248706818 -v -0.029481172562 0.378683656454 -0.066067218781 -v -0.219955444336 0.842094063759 -0.154961943626 -v -0.235270023346 0.857862532139 -0.137915790081 -v -0.087909221649 1.087654352188 -0.050910711288 -v -0.070798635483 1.104470491409 -0.045316457748 -v -0.247585058212 0.849854946136 -0.153714001179 -v -0.240604400635 0.840870857239 -0.163044929504 -v -0.011443376541 1.160188794136 -0.101308941841 -v 0.036525011063 1.165561199188 -0.098447144032 -v -0.447368383408 0.797736108303 -0.173693537712 -v -0.447412490845 0.796239554882 -0.162157893181 -v -0.443197250366 0.802235960960 -0.155865490437 -v -0.438388586044 0.805791616440 -0.164553344250 -v -0.494693517685 0.893587052822 -0.106214702129 -v -0.495902061462 0.900918126106 -0.105787515640 -v -0.493417978287 0.900910675526 -0.096440255642 -v -0.491146326065 0.891790270805 -0.099022448063 -v -0.489644289017 0.821257293224 -0.123335301876 -v -0.471888542175 0.823015093803 -0.132293999195 -v -0.468766212463 0.813135862350 -0.129689037800 -v -0.484895229340 0.811676740646 -0.120194315910 -v -0.476134061813 0.841621756554 -0.135791420937 -v -0.474495887756 0.832299590111 -0.135184764862 -v -0.494080066681 0.831160485744 -0.126861453056 -v -0.496844291687 0.842333674431 -0.129078328609 -v -0.451151609421 0.806489586830 -0.139960348606 -v -0.466060161591 0.802223086357 -0.129936814308 -v -0.452974319458 0.816859483719 -0.137552082539 -v -0.485681533813 0.851063311100 -0.187404632568 -v -0.502808094025 0.846567988396 -0.173310935497 -v -0.499794721603 0.830486893654 -0.174043655396 -v -0.483735561371 0.833467781544 -0.188756585121 -v -0.491135358810 0.786839187145 -0.137906074524 -v -0.477485179901 0.788113296032 -0.152600586414 -v -0.484442234039 0.794747292995 -0.160152792931 -v -0.501042604446 0.794560611248 -0.139316618443 -v -0.508388519287 0.830364823341 -0.119966745377 -v -0.521482229233 0.819912433624 -0.130728006363 -v -0.523111343384 0.828098714352 -0.121222257614 -v -0.512018680573 0.834384858608 -0.118249833584 -v -0.514605045319 0.853373050690 -0.127098441124 -v -0.517944812775 0.850607991219 -0.124822854996 -v -0.530208826065 0.845044076443 -0.127292752266 -v -0.531853437424 0.844683170319 -0.137332379818 -v -0.500032663345 0.821590065956 -0.116037189960 -v -0.509562015533 0.864964723587 -0.132301747799 -v -0.504422664642 0.864491283894 -0.132351279259 -v -0.500204324722 0.853452622890 -0.129730045795 -v -0.520584106445 0.822443604469 -0.147195518017 -v -0.522242069244 0.828122496605 -0.150109887123 -v -0.526848316193 0.828633189201 -0.143665313721 -v -0.523217201233 0.823370218277 -0.141705751419 -v -0.528179168701 0.850113034248 -0.151596605778 -v -0.527724266052 0.857582092285 -0.153711855412 -v -0.533334732056 0.857348978519 -0.147594749928 -v -0.531985759735 0.850167274475 -0.146348357201 -v -0.507945299149 0.843233942986 -0.123751223087 -v -0.509826183319 0.844902992249 -0.121303021908 -v -0.529620647430 0.830736279488 -0.135385751724 -v -0.531349182129 0.833562910557 -0.126550495625 -v -0.487643718719 0.804054796696 -0.111395001411 -v -0.480391025543 0.801913261414 -0.119697570801 -v -0.480456352234 0.792149066925 -0.122189939022 -v -0.488045692444 0.794178664684 -0.112424015999 -v -0.495940208435 0.784620106220 -0.126145541668 -v -0.499251127243 0.786586403847 -0.129543840885 -v -0.504209518433 0.787554085255 -0.123033821583 -v -0.499408006668 0.785145521164 -0.121613442898 -v -0.510551452637 0.871032297611 -0.138833642006 -v -0.515317440033 0.871675372124 -0.137129485607 -v -0.526596546173 0.864687561989 -0.151889979839 -v -0.530538082123 0.864613473415 -0.148025453091 -v -0.497328281403 0.811198830605 -0.112283110619 -v -0.503155469894 0.790419399738 -0.130545675755 -v -0.506678104401 0.791445076466 -0.125318050385 -v -0.493824243546 0.871466159821 -0.085897326469 -v -0.490470170975 0.869438707829 -0.092285215855 -v -0.485040903091 0.863280296326 -0.091263115406 -v -0.487308979034 0.865945041180 -0.082743287086 -v -0.485924720764 0.855860471725 -0.088013470173 -v -0.489061117172 0.856862902641 -0.081349372864 -v -0.520172119141 0.836955487728 -0.100135803223 -v -0.515067815781 0.840695142746 -0.093722283840 -v -0.506313800812 0.841244280338 -0.101609706879 -v -0.510276794434 0.838908553123 -0.105833172798 -v -0.512242078781 0.857203602791 -0.107409000397 -v -0.522161960602 0.857336878777 -0.099027633667 -v -0.526552677155 0.854199707508 -0.105519115925 -v -0.515424251556 0.854900300503 -0.111687183380 -v -0.508421897888 0.847175776958 -0.111868441105 -v -0.505060672760 0.849078774452 -0.108070075512 -v -0.524366140366 0.847588360310 -0.093832015991 -v -0.527771949768 0.845007956028 -0.098792850971 -v -0.504534959793 0.847885608673 -0.086177408695 -v -0.498050689697 0.852172255516 -0.082087755203 -v -0.490575790405 0.850792109966 -0.091464221478 -v -0.496593952179 0.846407592297 -0.095529913902 -v -0.496419668198 0.867350459099 -0.096872746944 -v -0.503741264343 0.868512868881 -0.087242722511 -v -0.511126995087 0.864330530167 -0.091117858887 -v -0.503080606461 0.863209724426 -0.101341784000 -v -0.495740175247 0.854071259499 -0.103795528412 -v -0.489275217056 0.858667314053 -0.098730802536 -v -0.510396480560 0.857069015503 -0.083190023899 -v -0.506175994873 0.859634041786 -0.081316232681 -v -0.511812210083 0.838328003883 -0.109384715557 -v -0.512324810028 0.836986780167 -0.113109648228 -v -0.523508548737 0.831316888332 -0.112718701363 -v -0.519570350647 0.833538651466 -0.105941951275 -v -0.527900457382 0.853996634483 -0.113405644894 -v -0.530893802643 0.848428845406 -0.119828045368 -v -0.517930030823 0.852390527725 -0.120005369186 -v -0.516858100891 0.853576421738 -0.115721166134 -v -0.510461807251 0.846561253071 -0.116781532764 -v -0.510272741318 0.846948623657 -0.114067971706 -v -0.528704881668 0.833988189697 -0.105706632137 -v -0.529921531677 0.832707405090 -0.110456645489 -v -0.535176277161 0.837255477905 -0.113185763359 -v -0.535221815109 0.839498996735 -0.107395589352 -v -0.535897016525 0.844757020473 -0.115204930305 -v -0.535224437714 0.848018705845 -0.110409140587 -v -0.527960300446 0.836800575256 -0.101769506931 -v -0.532390594482 0.842326819897 -0.102183938026 -v -0.532948493958 0.849078893661 -0.105126917362 -v -0.501554489136 0.843218922615 -0.099216759205 -v -0.507042169571 0.842735946178 -0.091056108475 -v -0.515851497650 0.862206101418 -0.097064733505 -v -0.508196115494 0.859079062939 -0.104793012142 -v -0.501304626465 0.850616335869 -0.106691837311 -v -0.514235734940 0.845977485180 -0.086078166962 -v -0.518186092377 0.844501137733 -0.088461101055 -v -0.522804021835 0.849747896194 -0.088824689388 -v -0.519546508789 0.852388918400 -0.085314571857 -v -0.523418426514 0.855972528458 -0.091820836067 -v -0.520101308823 0.859155178070 -0.089708983898 -v -0.511596202850 0.849000573158 -0.083929896355 -v -0.515213012695 0.854938268661 -0.083392798901 -v -0.516395092010 0.860537409782 -0.087069749832 -v -0.532750368118 0.836167395115 -0.118552982807 -v -0.497567176819 0.865602970123 -0.074603199959 -v -0.496635437012 0.860588312149 -0.074069917202 -v -0.499092817307 0.859558403492 -0.075726687908 -v -0.501167774200 0.863645672798 -0.076683282852 -v -0.499398469925 0.869491815567 -0.076963126659 -v -0.502336740494 0.868161380291 -0.077675879002 -v -0.493256807327 0.858881592751 -0.076175630093 -v -0.492352008820 0.866495013237 -0.076975762844 -v -0.499328136444 0.856431543827 -0.076817274094 -v -0.503676176071 0.861703813076 -0.079042315483 -v -0.503543376923 0.868796229362 -0.080610632896 -v -0.497124195099 0.871228098869 -0.080048918724 -v -0.508443832397 0.800419390202 -0.136265814304 -v -0.511143684387 0.804700791836 -0.140411615372 -v -0.514699935913 0.806024491787 -0.133704960346 -v -0.511139869690 0.801549851894 -0.131215751171 -v -0.524834394455 0.834584176540 -0.149969577789 -v -0.528397083282 0.835094690323 -0.144962668419 -v -0.514429330826 0.810142576694 -0.141759753227 -v -0.517162799835 0.811100900173 -0.136384963989 -v -0.496298074722 0.786881387234 -0.115870833397 -v -0.486750125885 0.785451531410 -0.128098964691 -v -0.527594327927 0.869485437870 -0.141907572746 -v -0.518058300018 0.869149982929 -0.149671852589 -v -0.510817766190 0.799105167389 -0.121699333191 -v -0.512484073639 0.806650936604 -0.113031685352 -v -0.502429008484 0.813118338585 -0.111305117607 -v -0.508829832077 0.828153192997 -0.116886317730 -v -0.518706083298 0.822669982910 -0.117713034153 -v -0.501774787903 0.822176635265 -0.114453732967 -v -0.519619703293 0.812057256699 -0.116438627243 -v -0.517436027527 0.808292090893 -0.126053214073 -v -0.483708858490 0.853024780750 -0.088355422020 -v -0.481112241745 0.850262880325 -0.093426942825 -v -0.475982189178 0.844028592110 -0.091422438622 -v -0.477612257004 0.847269892693 -0.084727108479 -v -0.475871086121 0.837056696415 -0.086321115494 -v -0.478466987610 0.838783323765 -0.080502748489 -v -0.504234790802 0.817612648010 -0.093765556812 -v -0.500945329666 0.822281956673 -0.087224364281 -v -0.490716695786 0.824029862881 -0.093403875828 -v -0.494282245636 0.819924414158 -0.099487662315 -v -0.496157646179 0.841752350330 -0.100961446762 -v -0.505415439606 0.841348707676 -0.095487833023 -v -0.508846998215 0.836988449097 -0.101620197296 -v -0.499357938766 0.838020980358 -0.106621682644 -v -0.492764949799 0.830117106438 -0.105411946774 -v -0.489102363586 0.833834648132 -0.099696338177 -v -0.508481979370 0.830541670322 -0.089690744877 -v -0.510588169098 0.827774941921 -0.093720853329 -v -0.492753744125 0.831151664257 -0.079553246498 -v -0.486364841461 0.835210800171 -0.078461050987 -v -0.479637861252 0.832388997078 -0.086949884892 -v -0.484333038330 0.829082310200 -0.088134169579 -v -0.485946178436 0.848959863186 -0.095764815807 -v -0.492048025131 0.851611673832 -0.087720692158 -v -0.497788429260 0.848133265972 -0.089569866657 -v -0.490402221680 0.846298635006 -0.097313344479 -v -0.483847379684 0.837090373039 -0.096990287304 -v -0.479485511780 0.840040266514 -0.095492541790 -v -0.497706413269 0.841334342957 -0.080382227898 -v -0.493602514267 0.843913137913 -0.079816043377 -v -0.498492002487 0.817435145378 -0.105219185352 -v -0.501165628433 0.814163446426 -0.109083890915 -v -0.511910438538 0.809615671635 -0.104608774185 -v -0.505473136902 0.811411023140 -0.099508881569 -v -0.510790824890 0.835031032562 -0.109548807144 -v -0.516519069672 0.828535556793 -0.111123204231 -v -0.506266832352 0.830387651920 -0.115914404392 -v -0.502544403076 0.833584547043 -0.112453937531 -v -0.499927043915 0.823450028896 -0.114233195782 -v -0.497344493866 0.826164782047 -0.110643565655 -v -0.513412475586 0.815074205399 -0.096650004387 -v -0.516290664673 0.813745021820 -0.099655687809 -v -0.519789934158 0.819998562336 -0.101308584213 -v -0.517743349075 0.822623610497 -0.098065078259 -v -0.519121646881 0.827042996883 -0.104812145233 -v -0.516560077667 0.830451726913 -0.103179037571 -v -0.511471986771 0.818441748619 -0.094288408756 -v -0.514646053314 0.825179815292 -0.095527946949 -v -0.514303207397 0.831783711910 -0.099781036377 -v -0.487943172455 0.827379703522 -0.090247273445 -v -0.495469808578 0.824954450130 -0.082411110401 -v -0.500364780426 0.846157968044 -0.094868063927 -v -0.493069171906 0.843513786793 -0.098693013191 -v -0.487038612366 0.835436344147 -0.097534894943 -v -0.502112865448 0.828593492508 -0.079975128174 -v -0.504857540131 0.826588690281 -0.083056867123 -v -0.508306980133 0.833120644093 -0.085304498672 -v -0.506083965302 0.836166918278 -0.082021951675 -v -0.507864236832 0.840063154697 -0.089241921902 -v -0.505406856537 0.843329131603 -0.087880432606 -v -0.499519109726 0.832336187363 -0.078415036201 -v -0.502271652222 0.839114248753 -0.080325365067 -v -0.502671241760 0.844747602940 -0.085275530815 -v -0.520011425018 0.816879510880 -0.107176601887 -v -0.485849618912 0.848793625832 -0.077213406563 -v -0.484879255295 0.844172120094 -0.075477480888 -v -0.486962318420 0.843352615833 -0.076518177986 -v -0.488926410675 0.847343027592 -0.078180730343 -v -0.487652778625 0.852373063564 -0.079998552799 -v -0.490156412125 0.851481437683 -0.079959809780 -v -0.482032775879 0.841814160347 -0.076701343060 -v -0.481650590897 0.848758876324 -0.079696655273 -v -0.487200260162 0.840355038643 -0.076348960400 -v -0.491241216660 0.845820188522 -0.079050183296 -v -0.491406917572 0.852079093456 -0.082417190075 -v -0.486078977585 0.853447556496 -0.083156108856 -v -0.498555898666 0.789247334003 -0.110209047794 -v -0.490535259247 0.795914649963 -0.107083380222 -v -0.499561071396 0.808594465256 -0.109262883663 -v -0.509321451187 0.801345944405 -0.113677084446 -v -0.491660594940 0.804835021496 -0.106762707233 -v -0.506342411041 0.790087342262 -0.117207169533 -v -0.507618427277 0.792013823986 -0.113375782967 -v -0.489049196243 0.826286792755 -0.079535543919 -v -0.485815525055 0.826620817184 -0.084511041641 -v -0.480561256409 0.821815013885 -0.084118247032 -v -0.483257293701 0.822232902050 -0.077751755714 -v -0.479671239853 0.815304994583 -0.082047581673 -v -0.482170104980 0.815054416656 -0.077047288418 -v -0.498437404633 0.795974731445 -0.094222247601 -v -0.495993852615 0.799155712128 -0.089099407196 -v -0.488581657410 0.803750157356 -0.092741906643 -v -0.489798069000 0.801814615726 -0.097452342510 -v -0.499174118042 0.816335558891 -0.095021665096 -v -0.505331993103 0.810285627842 -0.091094553471 -v -0.508020877838 0.806802392006 -0.096497237682 -v -0.500244140625 0.813882708549 -0.098373711109 -v -0.491198301315 0.810434281826 -0.099174976349 -v -0.490566730499 0.812255382538 -0.095983982086 -v -0.504388093948 0.801935672760 -0.089532196522 -v -0.506303787231 0.799559772015 -0.093178451061 -v -0.490227460861 0.806715846062 -0.080041587353 -v -0.486819744110 0.810494184494 -0.077443838120 -v -0.481586694717 0.811227262020 -0.084623336792 -v -0.484838962555 0.807765960693 -0.087508916855 -v -0.489450216293 0.825551927090 -0.087533473969 -v -0.494817018509 0.822417318821 -0.080430269241 -v -0.498338937759 0.818705558777 -0.082634210587 -v -0.493239879608 0.822486460209 -0.090337991714 -v -0.485663890839 0.816083729267 -0.092872619629 -v -0.482256412506 0.819070279598 -0.089587986469 -v -0.495429277420 0.813326537609 -0.077522575855 -v -0.493692398071 0.815349698067 -0.076042175293 -v -0.490639209747 0.799663007259 -0.100690245628 -v -0.491382598877 0.797495901585 -0.103254914284 -v -0.500654220581 0.789737641811 -0.104475378990 -v -0.497671604156 0.792602598667 -0.098903775215 -v -0.509530782700 0.806396782398 -0.102260172367 -v -0.511167049408 0.801594376564 -0.108417809010 -v -0.500758171082 0.809814274311 -0.105136036873 -v -0.500140190125 0.811406195164 -0.101884782314 -v -0.491745948792 0.806727945805 -0.103401362896 -v -0.492305278778 0.808004617691 -0.101605892181 -v -0.505864143372 0.790762722492 -0.098364591599 -v -0.506949424744 0.789222061634 -0.102397680283 -v -0.511898517609 0.792011439800 -0.104481697083 -v -0.511413574219 0.793921768665 -0.099860727787 -v -0.513942241669 0.797082841396 -0.105452656746 -v -0.513425111771 0.799474656582 -0.101383924484 -v -0.505221366882 0.793554723263 -0.095338940620 -v -0.509412050247 0.796497941017 -0.095882833004 -v -0.511485099792 0.800802588463 -0.097495257854 -v -0.487203598022 0.805865585804 -0.089809119701 -v -0.491508483887 0.801817178726 -0.084747970104 -v -0.501916170120 0.816967248917 -0.087054252625 -v -0.496026515961 0.819197714329 -0.092714369297 -v -0.489030599594 0.813616871834 -0.094238102436 -v -0.496573925018 0.803260147572 -0.081626772881 -v -0.499391555786 0.800740122795 -0.084920167923 -v -0.503435134888 0.803725183010 -0.085128188133 -v -0.500617980957 0.807261526585 -0.080836713314 -v -0.505204677582 0.808161199093 -0.085975766182 -v -0.502797126770 0.812113285065 -0.082701086998 -v -0.494894981384 0.806727290154 -0.079006910324 -v -0.497905254364 0.810785889626 -0.078416407108 -v -0.500154018402 0.814402937889 -0.080199837685 -v -0.509780406952 0.792054593563 -0.109013736248 -v -0.489554882050 0.819736123085 -0.072930335999 -v -0.487940311432 0.816487431526 -0.072609961033 -v -0.489381313324 0.815415918827 -0.073478043079 -v -0.491574764252 0.818117618561 -0.074059128761 -v -0.491600751877 0.822124600410 -0.074348628521 -v -0.493067026138 0.820745110512 -0.075044274330 -v -0.485497951508 0.815698802471 -0.073549985886 -v -0.486885070801 0.821202099323 -0.073756098747 -v -0.488751888275 0.812952458858 -0.073907077312 -v -0.492937803268 0.816626131535 -0.074767291546 -v -0.494431257248 0.821339190006 -0.076288044453 -v -0.491227149963 0.824168622494 -0.075623750687 -v -0.527001857758 0.853478670120 -0.125246942043 -v -0.513896465302 0.857641816139 -0.126969873905 -v -0.517309665680 0.873407602310 -0.133468151093 -v -0.529544591904 0.871562659740 -0.133002638817 -v -0.510344266891 0.866749882698 -0.130797505379 -v -0.535715341568 0.858517348766 -0.139212429523 -v -0.535772323608 0.861216902733 -0.129334509373 -v -0.490445613861 0.890650033951 -0.100051939487 -v -0.488363265991 0.888513207436 -0.107455074787 -v -0.485354423523 0.880579829216 -0.108673691750 -v -0.485455274582 0.882985472679 -0.099698960781 -v -0.487403631210 0.872754931450 -0.105823457241 -v -0.488933801651 0.873876035213 -0.098851382732 -v -0.518436908722 0.863012790680 -0.108661413193 -v -0.512920618057 0.866162419319 -0.104191660881 -v -0.507155895233 0.865417718887 -0.113856613636 -v -0.510566711426 0.863865315914 -0.116527736187 -v -0.512574672699 0.881888926029 -0.117601990700 -v -0.519688844681 0.883390605450 -0.107507109642 -v -0.524630069733 0.880152225494 -0.113091707230 -v -0.515925884247 0.879324555397 -0.120808780193 -v -0.509762763977 0.871237039566 -0.122120618820 -v -0.506671428680 0.872891902924 -0.120059609413 -v -0.521101236343 0.874487102032 -0.101826131344 -v -0.524887323380 0.872092723846 -0.105790376663 -v -0.502747774124 0.870004713535 -0.100400567055 -v -0.497266054153 0.871715247631 -0.097897529602 -v -0.492583751678 0.869514763355 -0.108082056046 -v -0.498463630676 0.867662549019 -0.110751748085 -v -0.494890928268 0.888140499592 -0.110826432705 -v -0.499839544296 0.889504313469 -0.100029766560 -v -0.507523536682 0.887580394745 -0.102457940578 -v -0.502919435501 0.885920166969 -0.114045023918 -v -0.498455524445 0.875417351723 -0.118292808533 -v -0.491332054138 0.877597153187 -0.115070879459 -v -0.506424903870 0.879839777946 -0.096214175224 -v -0.503129482269 0.880639374256 -0.095109224319 -v -0.512672424316 0.862300992012 -0.120484471321 -v -0.513113737106 0.860535264015 -0.123115837574 -v -0.525039196014 0.856878221035 -0.118569016457 -v -0.519091129303 0.858681201935 -0.114477872849 -v -0.526840448380 0.879119575024 -0.120443284512 -v -0.530992031097 0.874435842037 -0.125046432018 -v -0.518256187439 0.875537931919 -0.128518223763 -v -0.517742633820 0.876998245716 -0.124922633171 -v -0.511662721634 0.868683815002 -0.127072453499 -v -0.511864900589 0.869614481926 -0.124864697456 -v -0.530849933624 0.860190629959 -0.111503541470 -v -0.533360242844 0.859168589115 -0.115616202354 -v -0.536691904068 0.865351617336 -0.116629421711 -v -0.534475564957 0.867561042309 -0.111754179001 -v -0.535916090012 0.871988415718 -0.118930697441 -v -0.533593416214 0.874997556210 -0.115182757378 -v -0.527114391327 0.863506555557 -0.108078002930 -v -0.529962301254 0.869924604893 -0.107841134071 -v -0.530357837677 0.875990808010 -0.111109972000 -v -0.503102540970 0.866510391235 -0.113218367100 -v -0.505452632904 0.866206705570 -0.104708135128 -v -0.513443470001 0.887060940266 -0.106990933418 -v -0.508520841599 0.883631944656 -0.116348564625 -v -0.503959178925 0.873957514763 -0.119046747684 -v -0.510499000549 0.870763242245 -0.097471833229 -v -0.514724016190 0.870366811752 -0.098390698433 -v -0.518878698349 0.876383900642 -0.097725093365 -v -0.514991760254 0.878054201603 -0.095596671104 -v -0.519540309906 0.882226943970 -0.100633978844 -v -0.515974521637 0.884334146976 -0.099541544914 -v -0.507736682892 0.872971475124 -0.096328496933 -v -0.510526895523 0.879325091839 -0.095016777515 -v -0.511901855469 0.884887933731 -0.097839653492 -v -0.535580873489 0.863515138626 -0.121753752232 -v -0.494115114212 0.883353888988 -0.090229034424 -v -0.494159221649 0.878465473652 -0.090765476227 -v -0.496655464172 0.878225266933 -0.091974556446 -v -0.497776508331 0.882385611534 -0.092055082321 -v -0.494970798492 0.887757301331 -0.091351509094 -v -0.497639894485 0.886616647243 -0.092495083809 -v -0.491739749908 0.876264393330 -0.093018054962 -v -0.489335536957 0.883648872375 -0.093107581139 -v -0.497393131256 0.875543773174 -0.093272686005 -v -0.500410795212 0.881527364254 -0.093731045723 -v -0.499048471451 0.888204634190 -0.094248950481 -v -0.492660522461 0.889721930027 -0.094091176987 -v -0.521483898163 0.842776119709 -0.155532121658 -v -0.518549919128 0.858851313591 -0.158480763435 -v -0.513115406036 0.815885305405 -0.150368809700 -v -0.514750003815 0.828490138054 -0.158624708652 -v -0.504255294800 0.803942263126 -0.149980843067 -v -0.471243858337 0.786971271038 -0.142925024033 -v -0.466823101044 0.792440652847 -0.134708881378 -v -0.454370021820 0.826037108898 -0.138828337193 -v -0.495823860168 0.816522121429 -0.171279489994 -v -0.490122318268 0.804616093636 -0.166800975800 -v -0.501922845840 0.864825129509 -0.167882800102 -v -0.488729238510 0.869901716709 -0.140693187714 -v -0.494021654129 0.873752593994 -0.152330935001 -v -0.487847566605 0.878740549088 -0.152684986591 -v -0.480398416519 0.872110724449 -0.138898909092 -v -0.463868141174 0.866027951241 -0.132292509079 -v -0.478146791458 0.862194061279 -0.133633494377 -v -0.463702440262 0.875368595123 -0.127856612206 -v -0.453201293945 0.882918894291 -0.131946742535 -v -0.446355819702 0.873552322388 -0.141134619713 -v -0.483682394028 0.883540391922 -0.145150899887 -v -0.476632833481 0.876343607903 -0.133325040340 -v -0.484167098999 0.901457369328 -0.093008697033 -v -0.485260963440 0.893595635891 -0.095105886459 -v -0.483138322830 0.889306485653 -0.131258606911 -v -0.477747440338 0.882396876812 -0.121179759502 -v -0.476070404053 0.880022823811 -0.127019524574 -v -0.481888771057 0.887317419052 -0.138192296028 -v -0.468255043030 0.884616315365 -0.116226017475 -v -0.464697837830 0.881538629532 -0.122920870781 -v -0.479435443878 0.900566041470 -0.136166751385 -v -0.477606296539 0.898043036461 -0.145556926727 -v -0.468045234680 0.902096092701 -0.133089959621 -v -0.465980529785 0.900569677353 -0.139554977417 -v -0.462095737457 0.895440816879 -0.121656596661 -v -0.457749605179 0.892096400261 -0.130192101002 -v -0.470758438110 0.897547125816 -0.155327796936 -v -0.466237306595 0.894115865231 -0.159044146538 -v -0.457171916962 0.892076790333 -0.153369426727 -v -0.461186885834 0.897225439548 -0.149793088436 -v -0.450381755829 0.887220442295 -0.144794583321 -v -0.453635215759 0.891810834408 -0.140942871571 -v -0.480525970459 0.891566216946 -0.156198561192 -v -0.471389532089 0.900366127491 -0.149930894375 -v -0.463864564896 0.900258302689 -0.145290255547 -v -0.457410335541 0.896189451218 -0.139161109924 -v -0.469795703888 0.888008773327 -0.165396869183 -v -0.452988624573 0.883881807327 -0.157703280449 -v -0.491194486618 0.891927838326 -0.114754319191 -v -0.486534357071 0.885707378387 -0.106756806374 -v -0.479014396667 0.889679074287 -0.100693225861 -v -0.489616870880 0.903515696526 -0.117441117764 -v -0.487568616867 0.908877730370 -0.099188625813 -v -0.490461826324 0.908248662949 -0.103589415550 -v -0.486899375916 0.906276345253 -0.106632411480 -v -0.481706142426 0.906772732735 -0.103209018707 -v -0.484368562698 0.908297657967 -0.096467256546 -v -0.480246782303 0.906286239624 -0.099046111107 -v -0.472922801971 0.901211500168 -0.101609766483 -v -0.481368541718 0.883780658245 -0.114653468132 -v -0.486560106277 0.890575349331 -0.123603880405 -v -0.473132371902 0.886498153210 -0.109143614769 -v -0.485536098480 0.901406943798 -0.128164887428 -v -0.480238437653 0.907655954361 -0.126654922962 -v -0.476631164551 0.906661093235 -0.131565809250 -v -0.469987869263 0.906214416027 -0.128223299980 -v -0.473164319992 0.908138692379 -0.122179150581 -v -0.465127468109 0.902755975723 -0.122632205486 -v -0.467630147934 0.903878688812 -0.116376280785 -v -0.467125654221 0.895816802979 -0.111212134361 -v -0.482595682144 0.906823217869 -0.120295464993 -v -0.477108955383 0.906865596771 -0.115525126457 -v -0.472041606903 0.904061913490 -0.110747873783 -v -0.477966785431 0.905460000038 -0.110133111477 -v -0.493883132935 0.907011985779 -0.104439914227 -v -0.491958379745 0.907425343990 -0.096913754940 -v -0.489140272141 0.905874848366 -0.111298918724 -v -0.479014158249 0.906400084496 -0.107349276543 -v -0.476996898651 0.905042469501 -0.099129199982 -v -0.484606742859 0.906890451908 -0.093938052654 -v -0.491485834122 0.862887859344 -0.133998870850 -v -0.478189468384 0.851019322872 -0.133088052273 -v -0.436126470566 0.836560726166 -0.156523883343 -v -0.442461729050 0.835687577724 -0.147658109665 -v -0.441426515579 0.845188915730 -0.148403167725 -v -0.437577724457 0.854609191418 -0.159161508083 -v -0.454926490784 0.834215760231 -0.140588104725 -v -0.462005615234 0.792235910892 -0.166105270386 -v -0.456657409668 0.791631460190 -0.155758082867 -v -0.483422994614 0.867121934891 -0.181242167950 -v -0.468945980072 0.855017066002 -0.193509101868 -v -0.462913751602 0.870561540127 -0.183496356010 -v -0.491529464722 0.874752402306 -0.165132880211 -v -0.487841367722 0.878770470619 -0.162872314453 -v -0.468900203705 0.836523592472 -0.196922063828 -v -0.479998111725 0.818049311638 -0.186679184437 -v -0.499879121780 0.870677828789 -0.139983534813 -v -0.504315376282 0.871536970139 -0.151580274105 -v -0.454349756241 0.840840578079 -0.139953255653 -v -0.480731725693 0.877718329430 -0.174314856529 -v -0.464861869812 0.879262804985 -0.174113869667 -v -0.446362018585 0.868979811668 -0.170653223991 -v -0.449486732483 0.874917387962 -0.165948867798 -v -0.440111875534 0.863788783550 -0.154974460602 -v -0.441115617752 0.851662218571 -0.146024465561 -v -0.454034090042 0.845933496952 -0.138140499592 -v -0.456007719040 0.854448795319 -0.133829414845 -v -0.469702482224 0.854526937008 -0.132327675819 -v -0.444778442383 0.858243584633 -0.139310777187 -v -0.481812000275 0.882776081562 -0.167174339294 -v -0.484746932983 0.884817302227 -0.160003304482 -v -0.442131519318 0.811856746674 -0.148359179497 -v -0.436752319336 0.819676995277 -0.155522286892 -v -0.452622652054 0.797102570534 -0.146845281124 -v -0.443253278732 0.825838088989 -0.145939826965 -v -0.444576740265 0.818954288960 -0.143559813499 -v -0.433326005936 0.807289421558 -0.173588871956 -v -0.441542625427 0.803750753403 -0.187457442284 -v -0.430660247803 0.819438576698 -0.164661586285 -v -0.430188417435 0.836086511612 -0.162424981594 -v -0.432472229004 0.853630959988 -0.163688778877 -v -0.439163208008 0.866289258003 -0.172386646271 -v -0.448523044586 0.868499755859 -0.185838401318 -v -0.454426765442 0.857727229595 -0.197017431259 -v -0.454931259155 0.839325785637 -0.202164053917 -v -0.465736627579 0.819396853447 -0.194947898388 -v -0.450971364975 0.817552566528 -0.198323130608 -v -0.456123352051 0.800768375397 -0.183851480484 -v -0.468741416931 0.797707617283 -0.175054907799 -v -0.425196409225 0.807017326355 -0.182153224945 -v -0.429808616638 0.808018207550 -0.197672486305 -v -0.423538684845 0.817356407642 -0.170044660568 -v -0.423536777496 0.833735704422 -0.165797650814 -v -0.425173997879 0.851301014423 -0.165531635284 -v -0.430070877075 0.863844513893 -0.173078656197 -v -0.436095714569 0.867850482464 -0.187229573727 -v -0.440057992935 0.861827850342 -0.201652050018 -v -0.439754009247 0.844789445400 -0.210174918175 -v -0.435653448105 0.823165953159 -0.207971274853 -v -0.419240474701 0.811311781406 -0.205702304840 -v -0.414561510086 0.807009160519 -0.189636647701 -v -0.403192281723 0.809433162212 -0.199932932854 -v -0.409330129623 0.817718327045 -0.216658353806 -v -0.413339853287 0.815283596516 -0.174596428871 -v -0.399246454239 0.813498079777 -0.181282222271 -v -0.413203001022 0.829875349998 -0.168070018291 -v -0.397543668747 0.824719786644 -0.171226143837 -v -0.395318984985 0.834834337234 -0.168890595436 -v -0.408400058746 0.846953988075 -0.167888164520 -v -0.413450241089 0.863622665405 -0.173395872116 -v -0.419510841370 0.872239351273 -0.188069701195 -v -0.424756288528 0.871203422546 -0.206108510494 -v -0.424194335938 0.854732930660 -0.219132661819 -v -0.414286136627 0.851325511932 -0.227738976479 -v -0.424114227295 0.828399658203 -0.215525388718 -v -0.413206815720 0.834980130196 -0.225028336048 -v -0.474735736847 0.806489527225 -0.181779563427 -v -0.461838483810 0.807741761208 -0.190207779408 -v -0.450213432312 0.803499877453 -0.189132690430 -v -0.453882694244 0.808152139187 -0.192983090878 -v -0.063398599625 0.425415545702 -0.004801809788 -v -0.057441711426 0.421231210232 0.011059165001 -v -0.042950868607 0.417842894793 0.021519958973 -v 0.144121408463 0.511780261993 0.077085554600 -v 0.108297348022 0.528908789158 0.076607823372 -v 0.103316783905 0.511069953442 0.013130068779 -v 0.120876550674 0.499709635973 0.015783727169 -v 0.143322706223 0.510246276855 0.023608624935 -v 0.161252737045 0.523530781269 0.064749538898 -v 0.152065515518 0.501725971699 -0.009824156761 -v 0.140231609344 0.498346298933 -0.030532300472 -v 0.192918300629 0.507425546646 -0.030843675137 -v 0.185611486435 0.508959054947 -0.011636078358 -v 0.187336921692 0.531630814075 -0.041304111481 -v 0.124450206757 0.523272991180 -0.047710359097 -v 0.227248430252 0.552403509617 -0.004147112370 -v 0.228659629822 0.532396197319 -0.002932310104 -v 0.227637529373 0.592922449112 0.034270524979 -v 0.233801364899 0.565752506256 0.035560011864 -v 0.223552703857 0.587897717953 -0.008055388927 -v 0.221391916275 0.630149424076 0.032777488232 -v 0.188503026962 0.624325811863 0.092208683491 -v 0.197622060776 0.591138243675 0.090726375580 -v 0.214549303055 0.686934411526 0.045682489872 -v 0.187195301056 0.673267960548 0.099526941776 -v 0.216737031937 0.692575335503 -0.008495330811 -v 0.199777126312 0.701083362103 -0.008754312992 -v 0.194094419479 0.686676740646 0.034240126610 -v 0.220711708069 0.636359512806 -0.020351350307 -v 0.182755708694 0.725424706936 -0.089372277260 -v 0.179335832596 0.729352295399 -0.071519851685 -v 0.187209367752 0.650559663773 -0.072877883911 -v 0.166259288788 0.675132751465 0.078442573547 -v 0.195732593536 0.668351173401 0.035658538342 -v 0.165970325470 0.662057161331 0.079006195068 -v 0.184274196625 0.697052001953 -0.025637030602 -v 0.136685848236 0.621061325073 0.124828457832 -v 0.146819353104 0.581296682358 0.115078270435 -v 0.209793090820 0.565983176231 0.086855173111 -v 0.165661096573 0.548517227173 0.104174733162 -v 0.134027719498 0.671311855316 0.129685342312 -v 0.078870058060 0.624179244041 0.127473473549 -v 0.088960170746 0.573084473610 0.105961620808 -v 0.077410221100 0.682400047779 0.141914546490 -v 0.184307813644 0.588923692703 -0.058013796806 -v 0.129453897476 0.595893144608 -0.086390793324 -v 0.133975744247 0.663929998875 -0.106234252453 -v 0.236451148987 0.552949547768 0.037623882294 -v 0.224511861801 0.541902184486 0.036363959312 -v 0.211948394775 0.525437772274 0.006383121014 -v 0.214318037033 0.545253038406 0.069983601570 -v 0.212549924850 0.552964806557 0.068517923355 -v 0.224463939667 0.549749970436 0.033728003502 -v 0.218957901001 0.557131946087 0.083203673363 -v 0.187869310379 0.532874941826 0.092133939266 -v 0.187714338303 0.534057557583 0.080063939095 -v 0.181240797043 0.545281291008 0.081068098545 -v 0.146420955658 0.531102359295 0.067861676216 -v 0.212937355042 0.534900724888 0.000919044018 -v 0.184135675430 0.516894340515 -0.018340229988 -v 0.071259021759 0.544855475426 -0.057795166969 -v 0.062549352646 0.523616433144 0.002657234669 -v 0.072495937347 0.605195105076 -0.099032998085 -v 0.012754201889 0.670661449432 -0.129763662815 -v 0.074255228043 0.671743631363 -0.122924923897 -v 0.016004562378 0.604284882545 -0.108093738556 -v -0.047175407410 0.665716767311 -0.120963096619 -v -0.047187089920 0.735366821289 -0.127462327480 -v 0.014084577560 0.746303260326 -0.145008087158 -v -0.093496322632 0.661609470844 -0.084233760834 -v -0.096379756927 0.725130677223 -0.084452211857 -v -0.035370826721 0.739451408386 -0.115991532803 -v 0.016326665878 0.748082160950 -0.129412829876 -v -0.076249361038 0.729390442371 -0.078382790089 -v -0.043362140656 0.605586290359 -0.104780077934 -v -0.089107990265 0.608498692513 -0.073513865471 -v -0.114396095276 0.659402668476 -0.028737843037 -v -0.114691495895 0.720096588135 -0.025828123093 -v -0.112749338150 0.613461971283 -0.024391472340 -v 0.026057243347 0.539770305157 -0.068712770939 -v -0.036364793777 0.558640837669 -0.091128528118 -v 0.081735372543 0.748860776424 -0.142071723938 -v 0.138632535934 0.742601990700 -0.123913228512 -v 0.074531555176 0.752696514130 -0.124717712402 -v 0.130490541458 0.744501113892 -0.108744025230 -v 0.031629323959 0.521139383316 -0.005045592785 -v 0.039030313492 0.551695644855 0.056075632572 -v -0.001458644867 0.553142666817 0.050433158875 -v 0.022727251053 0.514308512211 -0.007078170776 -v 0.018694400787 0.521275639534 -0.064219474792 -v -0.013375759125 0.545891344547 0.025897085667 -v 0.010625362396 0.528762698174 -0.008753895760 -v -0.013785123825 0.537784159184 0.044802665710 -v -0.003431797028 0.556365251541 0.031631588936 -v 0.021438360214 0.537024855614 -0.007674217224 -v -0.044837236404 0.555213034153 0.041083216667 -v -0.037632226944 0.567453145981 0.046529829502 -v -0.051511764526 0.550408124924 0.056568264961 -v -0.049501657486 0.569334208965 0.059367895126 -v -0.012590885162 0.593995332718 0.081816494465 -v -0.056488513947 0.606606721878 0.067150175571 -v 0.028929233551 0.585341632366 0.093791067600 -v 0.008466243744 0.527554392815 -0.046013593674 -v 0.015324592590 0.539409756660 -0.046251296997 -v -0.025128364563 0.548998892307 -0.059863686562 -v -0.028495788574 0.536334693432 -0.059524655342 -v -0.034542560577 0.529292702675 -0.083323836327 -v 0.145991802216 0.508340239525 -0.014416158199 -v 0.131390333176 0.516479372978 0.021855235100 -v 0.026699304581 0.634563446045 0.117274522781 -v -0.020232677460 0.642315804958 0.100721597672 -v -0.026278018951 0.702590823174 0.111697435379 -v -0.068937778473 0.706630170345 0.078983545303 -v -0.064911603928 0.651495337486 0.071269571781 -v -0.015012741089 0.704616785049 0.095527708530 -v -0.054348468781 0.709064245224 0.065617680550 -v 0.026480436325 0.697825789452 0.111364364624 -v 0.025828838348 0.691604137421 0.109849214554 -v -0.014955997467 0.698180437088 0.094332814217 -v 0.071362495422 0.688030838966 0.115027904510 -v 0.069956779480 0.677348077297 0.113705933094 -v 0.121142864227 0.674957156181 0.104752779007 -v 0.119457006454 0.664903819561 0.103474259377 -v 0.021538257599 0.694689214230 0.131033778191 -v -0.053185701370 0.703009426594 0.064263105392 -v -0.084846496582 0.713242530823 0.025584518909 -v -0.102933645248 0.712332844734 0.035015225410 -v -0.095738649368 0.717043399811 -0.024513781071 -v -0.100670337677 0.658007621765 0.027561366558 -v -0.096192121506 0.614809751511 0.028727471828 -v -0.093750953674 0.575753808022 0.032837092876 -v -0.107775926590 0.575954735279 -0.015404582024 -v -0.076748132706 0.721031785011 -0.079203486443 -v -0.095304489136 0.708831727505 -0.024215877056 -v -0.035797357559 0.727729797363 -0.117839038372 -v 0.016345024109 0.738378584385 -0.135166823864 -v -0.084352016449 0.707949042320 0.025263905525 -v -0.074731111526 0.537435054779 -0.053000748158 -v -0.060385465622 0.543911695480 -0.041588306427 -v -0.085829257965 0.563987195492 -0.064947962761 -v -0.100173950195 0.556139528751 -0.010330975056 -v -0.076323747635 0.554702341557 -0.007672071457 -v -0.072488784790 0.558982849121 0.027619063854 -v -0.093396186829 0.559440493584 0.031786739826 -v -0.076028823853 0.564334809780 -0.006530702114 -v -0.068377733231 0.567896723747 0.030334770679 -v -0.061259269714 0.555227398872 -0.041971862316 -v 0.073889255524 0.745370209217 -0.123060703278 -v 0.128804206848 0.738630473614 -0.107519149780 -v 0.170720815659 0.713177621365 -0.074004113674 -v 0.014654159546 0.516860008240 -0.008520841599 -v 0.013562679291 0.518869280815 -0.057164371014 -v -0.016606330872 0.536776065826 0.037213981152 -v -0.049576044083 0.547559082508 0.050266206264 -v -0.032561779022 0.526100814342 -0.075417101383 -v -0.081507205963 0.541957616806 -0.059140264988 -v -0.090506315231 0.551226019859 -0.008307635784 -v -0.086373806000 0.554394304752 0.030092954636 -v 0.154227733612 0.513570308685 0.073047876358 -v 0.132213592529 0.500396609306 0.018915951252 -v 0.146581411362 0.496055126190 -0.020876288414 -v 0.191246986389 0.503775417805 -0.022085011005 -v 0.222658157349 0.525225639343 0.000867187977 -v 0.230988979340 0.543813467026 0.037524938583 -v 0.219683170319 0.549111723900 0.076172590256 -v 0.182136535645 0.536433517933 0.100669324398 -v 0.046369791031 0.719563126564 0.135822176933 -v 0.042241811752 0.721289813519 0.120435237885 -v -0.003053903580 0.735716164112 0.113252401352 -v -0.001557350159 0.734151005745 0.128390729427 -v 0.048724651337 0.693842947483 0.145092248917 -v 0.088016271591 0.680101275444 0.143559694290 -v 0.088751792908 0.712511181831 0.134645402431 -v -0.005078792572 0.687308907509 0.133116126060 -v 0.005204916000 0.678244352341 0.114929139614 -v 0.045290470123 0.679847002029 0.130735397339 -v -0.046638011932 0.679906129837 0.107797205448 -v -0.036025047302 0.673013865948 0.093445062637 -v -0.047019481659 0.748887658119 0.117437124252 -v -0.043670654297 0.749698400497 0.105795860291 -v -0.083326578140 0.758892953396 0.081229805946 -v -0.092339754105 0.758642017841 0.089627742767 -v -0.084635972977 0.674705922604 0.074784040451 -v -0.118670225143 0.769500553608 0.044728934765 -v -0.110567569733 0.675210475922 0.032601892948 -v -0.073696851730 0.668749451637 0.062748491764 -v -0.096913099289 0.669786691666 0.024165332317 -v -0.136384248734 0.778806865215 -0.006764948368 -v -0.125165224075 0.685560584068 -0.010455846786 -v -0.128728628159 0.779637575150 -0.004121005535 -v -0.123834848404 0.788750588894 -0.051987946033 -v -0.134121894836 0.787187457085 -0.055941343307 -v -0.112501621246 0.770408868790 0.043770790100 -v -0.125114917755 0.696647584438 -0.048348546028 -v 0.088402271271 0.679888308048 0.132619023323 -v 0.127837419510 0.673484921455 0.119722843170 -v 0.132176876068 0.673645257950 0.122276902199 -v 0.162997484207 0.673051953316 0.104590058327 -v 0.168073177338 0.673548042774 0.111319541931 -v 0.194190502167 0.675714135170 0.075663864613 -v 0.201750755310 0.681370317936 0.081253111362 -v 0.160883426666 0.700167834759 0.107342004776 -v 0.126739978790 0.702453672886 0.123044371605 -v 0.196573019028 0.701241195202 0.081610202789 -v 0.218851804733 0.692234337330 0.023782670498 -v 0.218031644821 0.722697138786 0.022761344910 -v 0.211975812912 0.697270512581 -0.019005358219 -v 0.210978746414 0.684415698051 0.022575974464 -v 0.206652164459 0.696023881435 -0.015635728836 -v 0.217346906662 0.742312967777 -0.024935722351 -v 0.212719678879 0.723642468452 0.022974371910 -v 0.189186811447 0.703710496426 0.071625590324 -v 0.151532173157 0.701240718365 0.096213757992 -v 0.119452953339 0.703918457031 0.109877347946 -v 0.084906578064 0.714441061020 0.121117770672 -v -0.109468936920 0.675620913506 -0.013445198536 -v -0.102214574814 0.688136637211 -0.049785196781 -v -0.112360954285 0.709139764309 -0.096938610077 -v -0.090363025665 0.703007459641 -0.084746301174 -v -0.079424858093 0.723271906376 -0.131462454796 -v -0.063344240189 0.716237366199 -0.108357429504 -v -0.031183481216 0.732107281685 -0.152232766151 -v -0.028877019882 0.723726272583 -0.136132776737 -v 0.020634174347 0.744759976864 -0.156958043575 -v 0.014694929123 0.733487784863 -0.142659604549 -v 0.069174766541 0.743137419224 -0.152602612972 -v 0.061331748962 0.735695242882 -0.140975654125 -v 0.110146522522 0.735085666180 -0.144149661064 -v 0.103978872299 0.731820046902 -0.132717370987 -v 0.077984094620 0.798910439014 -0.141461968422 -v 0.119859457016 0.790866315365 -0.137311816216 -v 0.074426889420 0.802294850349 -0.135301411152 -v 0.116223812103 0.793579339981 -0.130329132080 -v 0.161331653595 0.781449317932 -0.127611219883 -v 0.152729034424 0.728924751282 -0.130435585976 -v 0.157443046570 0.783650875092 -0.121536970139 -v 0.016957759857 0.807849287987 -0.168082594872 -v 0.013961553574 0.810384929180 -0.162219345570 -v 0.142093658447 0.720312654972 -0.115514278412 -v 0.183982133865 0.712360918522 -0.110098004341 -v 0.172728776932 0.703007578850 -0.095244884491 -v 0.204134464264 0.694908976555 -0.070124804974 -v 0.194279670715 0.698028326035 -0.065750300884 -v 0.193339109421 0.770651638508 -0.104809045792 -v 0.212558984756 0.760952532291 -0.071953296661 -v -0.037868022919 0.804407358170 -0.172462224960 -v -0.085999965668 0.798096537590 -0.150223016739 -v -0.079912900925 0.801035761833 -0.145433545113 -v -0.039311408997 0.806997716427 -0.165538191795 -v -0.114581584930 0.791720926762 -0.122836530209 -v -0.107570171356 0.793677270412 -0.103108108044 -v 0.188315153122 0.773532092571 -0.101306200027 -v 0.206870555878 0.763117253780 -0.069325089455 -v 0.211477041245 0.744883477688 -0.024265110493 -v 0.042490959167 0.714094579220 0.143952012062 -v 0.087229490280 0.708064198494 0.141458809376 -v -0.003680706024 0.725511908531 0.134795546532 -v -0.046833276749 0.736211478710 0.117370963097 -v -0.090959787369 0.743731617928 0.091760039330 -v -0.118830442429 0.753062367439 0.045624971390 -v -0.137614011765 0.761805653572 -0.004316985607 -v -0.138007164001 0.771108925343 -0.055927753448 -v 0.164827346802 0.696167469025 0.115181803703 -v 0.129087686539 0.698045313358 0.129442453384 -v 0.202077627182 0.697257161140 0.083701729774 -v 0.223474979401 0.716901838779 0.021489858627 -v 0.219713687897 0.734807431698 -0.024288654327 -v 0.116148948669 0.780359745026 -0.140539228916 -v 0.075758695602 0.788216233253 -0.143896400928 -v 0.158277511597 0.770472466946 -0.130922555923 -v 0.016254663467 0.794478595257 -0.169810354710 -v 0.214664697647 0.750561535358 -0.070789575577 -v 0.193098306656 0.760572731495 -0.107543230057 -v -0.038340330124 0.789423942566 -0.169972777367 -v -0.089158058167 0.786127924919 -0.148080706596 -v -0.117129564285 0.774500608444 -0.117468833923 -v 0.042947053909 0.680678486824 0.141971707344 -v 0.088331699371 0.690217196941 0.148079514503 -v 0.003902912140 0.677657604218 0.129070520401 -v -0.041256189346 0.671179771423 0.103981673717 -v -0.082117557526 0.666609048843 0.067920327187 -v -0.102604150772 0.668240845203 0.030974626541 -v -0.117699861526 0.673860788345 -0.010850131512 -v -0.117666482925 0.687893807888 -0.057794094086 -v 0.130661725998 0.680747628212 0.129106581211 -v 0.167012929916 0.680982887745 0.119741201401 -v 0.203903198242 0.687600016594 0.084002554417 -v 0.223474740982 0.696553647518 0.024260759354 -v 0.218124628067 0.702928543091 -0.021467387676 -v -0.105328559875 0.700765669346 -0.090611577034 -v -0.074398279190 0.714329957962 -0.125499725342 -v -0.027653694153 0.722540020943 -0.144668102264 -v 0.022192239761 0.732428669930 -0.150135040283 -v 0.065891504288 0.733176171780 -0.148831009865 -v 0.109828948975 0.726947844028 -0.140057563782 -v 0.145726919174 0.717888236046 -0.127151072025 -v 0.178150177002 0.702635169029 -0.105906605721 -v 0.208762645721 0.699994683266 -0.072454273701 -v 0.474818944931 0.829751849174 0.080761909485 -v 0.447371721268 0.827144682407 0.082335829735 -v 0.436402082443 0.801355779171 0.076726853848 -v 0.437137126923 0.782028198242 0.062518715858 -v 0.449114084244 0.774479269981 0.043720185757 -v 0.466235399246 0.780543923378 0.026742458344 -v 0.482433199883 0.796503424644 0.020002663136 -v 0.497534036636 0.817176282406 0.030400276184 -v 0.490592956543 0.825681328773 0.062343478203 -v 0.416083812714 0.856479287148 0.063238620758 -v 0.397818565369 0.822540879250 0.058679580688 -v 0.394402980804 0.790257930756 0.037392973900 -v 0.409307241440 0.778394103050 -0.000016272068 -v 0.435056686401 0.793707430363 -0.030144393444 -v 0.461454987526 0.821685552597 -0.037738919258 -v 0.478555798531 0.853732824326 -0.014944911003 -v 0.468921065331 0.879577338696 0.027264356613 -v 0.445375442505 0.880728542805 0.053184807301 -v 0.466699838638 0.886996567249 -0.046786844730 -v 0.444378852844 0.847988784313 -0.076629161835 -v 0.406841993332 0.809575557709 -0.076438903809 -v 0.371905088425 0.787828385830 -0.042897462845 -v 0.357719540596 0.804510772228 0.005992591381 -v 0.362805366516 0.843034982681 0.036714971066 -v 0.391008257866 0.879716992378 0.041662096977 -v 0.425895571709 0.907973527908 0.033029556274 -v 0.459516048431 0.908767938614 0.004759609699 -v 0.474973201752 0.818710982800 0.074997305870 -v 0.461808919907 0.809670209885 0.079118371010 -v 0.456480264664 0.798067808151 0.076258957386 -v 0.455782771111 0.786437451839 0.067734181881 -v 0.461717367172 0.781551599503 0.053859353065 -v 0.471699953079 0.783859133720 0.044202029705 -v 0.482946038246 0.793918967247 0.038748741150 -v 0.489899158478 0.805950462818 0.046118319035 -v 0.486937761307 0.816467463970 0.063097000122 -v 0.441228270531 0.887848794460 -0.051129221916 -v 0.419926643372 0.855345606804 -0.080606341362 -v 0.393717527390 0.828494906425 -0.076067388058 -v 0.370517253876 0.811828851700 -0.047418713570 -v 0.361316323280 0.823268711567 -0.005200862885 -v 0.369323611259 0.850542843342 0.018845379353 -v 0.388053059578 0.882371962070 0.021297752857 -v 0.414115905762 0.906186938286 0.015702068806 -v 0.435689449310 0.907421112061 -0.006201267242 -v 0.457625389099 0.893979549408 -0.053317129612 -v 0.432103991508 0.851549267769 -0.084864497185 -v 0.397927403450 0.816684424877 -0.084416866302 -v 0.365631699562 0.796897709370 -0.048830389977 -v 0.351232051849 0.811093628407 -0.000877141953 -v 0.357836484909 0.846324503422 0.031680703163 -v 0.384871840477 0.884247660637 0.031613469124 -v 0.419532299042 0.913497269154 0.023943066597 -v 0.448849439621 0.918320059776 -0.001152694225 -v 0.468704581261 0.841255605221 0.076112985611 -v 0.455493927002 0.817524373531 0.086187958717 -v 0.447009682655 0.798206448555 0.080420792103 -v 0.444962501526 0.781422913074 0.068031430244 -v 0.455179333687 0.774285674095 0.049756467342 -v 0.471616744995 0.778853714466 0.036065757275 -v 0.486483812332 0.790827751160 0.029048442841 -v 0.496397018433 0.808861613274 0.039405584335 -v 0.487864613533 0.835947692394 0.054146111012 -v 0.153582811356 1.146741271019 -0.023735761642 -v 0.146487712860 1.131359100342 -0.001364409924 -v 0.166741371155 1.124185800552 0.018122673035 -v 0.193145751953 1.149736404419 -0.011541187763 -v 0.155054807663 1.159122467041 -0.049359142780 -v 0.204403400421 1.165102362633 -0.054153501987 -v 0.122463703156 1.154211997986 -0.012223064899 -v 0.122359752655 1.165279030800 -0.031655430794 -v 0.111874103546 1.145521163940 -0.014831602573 -v 0.108873367310 1.130098581314 0.001646161079 -v 0.118844747543 1.140482068062 0.008030056953 -v 0.112039089203 1.157532334328 -0.030208945274 -v 0.117567777634 1.174703359604 -0.051419258118 -v 0.107257843018 1.165954709053 -0.045900940895 -v 0.104554653168 1.179394125938 -0.069682717323 -v 0.096223115921 1.169898509979 -0.061130762100 -v 0.078921318054 1.169709205627 -0.074586033821 -v 0.084147691727 1.179101228714 -0.084845960140 -v 0.060791492462 1.176911592484 -0.095880866051 -v 0.057977199554 1.167713642120 -0.084590315819 -v 0.036164999008 1.174309372902 -0.102829873562 -v 0.034911155701 1.165031433105 -0.090920388699 -v 0.010727643967 1.171227931976 -0.105658352375 -v 0.011106491089 1.162466049194 -0.093655586243 -v 0.043484210968 1.148231267929 -0.125569045544 -v 0.015298843384 1.144926548004 -0.130406677723 -v 0.071163892746 1.151486396790 -0.119160473347 -v 0.099195003510 1.154577970505 -0.109847664833 -v 0.129453897476 1.156361937523 -0.098611533642 -v 0.148039340973 1.161061882973 -0.075409770012 -v 0.194738388062 1.157809615135 -0.093097984791 -v 0.166496038437 1.133596062660 -0.120083212852 -v 0.241148471832 1.147128343582 -0.110760331154 -v 0.205090999603 1.108767747879 -0.138120114803 -v 0.296813964844 1.119970321655 -0.113083600998 -v 0.248097181320 1.079767704010 -0.139568984509 -v 0.314052343369 1.139110684395 -0.062264442444 -v 0.255768775940 1.160152196884 -0.056023120880 -v 0.125734090805 1.143847703934 -0.100883603096 -v 0.157966852188 1.121018052101 -0.115687131882 -v 0.195927619934 1.096690416336 -0.130942702293 -v 0.102578163147 1.110636472702 0.020105242729 -v 0.110338211060 1.120410561562 0.029318034649 -v 0.135500192642 1.112133264542 0.027387619019 -v 0.121419668198 1.085264921188 0.053761780262 -v 0.096231937408 1.096061944962 0.048072874546 -v 0.121106386185 1.072343826294 0.043408513069 -v 0.135016918182 1.098165869713 0.015953302383 -v 0.146015644073 1.118869185448 -0.003721117973 -v 0.161901235580 1.110084056854 0.008137762547 -v 0.196237564087 1.113056898117 0.041670143604 -v 0.231638908386 1.147067785263 0.005591809750 -v 0.187341213226 1.099266767502 0.029134333134 -v 0.101557731628 1.063514590263 0.082820892334 -v 0.102081298828 1.052370190620 0.074180006981 -v 0.079520702362 1.077967882156 0.068052530289 -v 0.091128826141 1.087718725204 0.037324488163 -v 0.076925516129 1.069971561432 0.055388748646 -v 0.073636531830 1.045414447784 0.104310035706 -v 0.060042619705 1.063298940659 0.085158526897 -v 0.060029506683 1.056650996208 0.070179820061 -v 0.076045036316 1.035140991211 0.095563471317 -v 0.043664932251 1.024097084999 0.109484314919 -v 0.049406528473 1.016946673393 0.102544367313 -v -0.092731475830 1.104547619820 -0.051223099232 -v -0.113844156265 1.093252182007 -0.044122219086 -v -0.106844902039 1.081219434738 -0.051757276058 -v -0.089383363724 1.092386722565 -0.054474711418 -v -0.142742395401 1.079518079758 -0.034633517265 -v -0.133426666260 1.067001342773 -0.045482337475 -v -0.184802770615 1.058834671974 -0.039483308792 -v -0.173303604126 1.048474073410 -0.050417959690 -v -0.212892293930 1.028311491013 -0.072805166245 -v -0.225590705872 1.036243677139 -0.063136100769 -v -0.252138376236 1.016947031021 -0.094444274902 -v -0.238336086273 1.010701894760 -0.105198681355 -v -0.261181116104 1.009418725967 -0.139634251595 -v -0.249701499939 1.001395821571 -0.147045373917 -v -0.236275196075 1.050160169601 -0.116216957569 -v -0.220269918442 1.051454544067 -0.180383503437 -v -0.255511283875 1.006905913353 -0.191586971283 -v -0.200874567032 1.088705539703 -0.091722786427 -v -0.183070182800 1.090037822723 -0.163334965706 -v -0.194282293320 1.042732954025 -0.226393222809 -v -0.229079723358 1.004474639893 -0.227474808693 -v -0.159255266190 1.014430284500 -0.241221547127 -v -0.196877479553 1.004197716713 -0.243847310543 -v -0.161328792572 1.084260106087 -0.219420254230 -v -0.119579792023 1.036281943321 -0.230625808239 -v -0.244533061981 0.997296631336 -0.191611886024 -v -0.223453521729 0.995631098747 -0.221788883209 -v -0.153653621674 1.110693693161 -0.078140616417 -v -0.146693229675 1.116624593735 -0.140892207623 -v -0.119409322739 1.117959380150 -0.075315594673 -v -0.110646963120 1.127498865128 -0.118036568165 -v -0.091603517532 1.119367361069 -0.072633266449 -v -0.084799051285 1.131223559380 -0.097159922123 -v -0.115998268127 1.108692765236 -0.190854609013 -v -0.089858293533 1.122802376747 -0.153536438942 -v -0.082515239716 1.073935151100 -0.031460642815 -v -0.089494943619 1.087044239044 -0.020607233047 -v -0.073734283447 1.050684690475 0.000546932220 -v -0.080284357071 1.062893509865 0.010187029839 -v -0.068449974060 1.044618606567 0.047623455524 -v -0.062891244888 1.033905506134 0.039388358593 -v -0.047109127045 1.031812429428 0.080443978310 -v -0.031396150589 1.052964568138 0.067215263844 -v -0.045845985413 1.064046025276 0.042960286140 -v -0.017226934433 1.017256498337 0.097646474838 -v -0.012994289398 1.040772914886 0.082050144672 -v -0.024281263351 1.047124743462 0.053621292114 -v -0.036925554276 1.057082414627 0.032743573189 -v -0.047004699707 1.072139143944 0.009349822998 -v -0.057619094849 1.078983664513 0.016488373280 -v -0.069085836411 1.100236415863 -0.007317364216 -v -0.056204557419 1.092651844025 -0.012012958527 -v -0.059460639954 1.110859036446 -0.031832396984 -v -0.073314666748 1.118509888649 -0.030457615852 -v -0.059396266937 1.125840187073 -0.048513889313 -v -0.072108268738 1.131877303123 -0.050584912300 -v -0.009020328522 1.040055990219 0.067265510559 -v -0.008279085159 1.048065781593 0.086258769035 -v -0.001708984375 1.044293761253 0.063691854477 -v -0.011102437973 1.013419628143 0.107842206955 -v 0.012402534485 1.014568805695 0.111340701580 -v -0.007885932922 1.000435948372 0.096706688404 -v 0.016772985458 0.998014330864 0.098615229130 -v -0.018301010132 1.009325742722 0.089410901070 -v 0.012949943542 1.049798607826 0.088101744652 -v 0.018573284149 1.045927882195 0.061640202999 -v 0.036473512650 1.048622608185 0.071156620979 -v 0.042591094971 1.045850872993 0.077319562435 -v 0.032891273499 1.053035736084 0.094713449478 -v -0.043589353561 1.021625638008 0.071766734123 -v -0.062194108963 1.102410316467 -0.172938823700 -v -0.045767784119 1.134480834007 -0.135547220707 -v -0.039524316788 1.122236609459 -0.136410057545 -v -0.056471109390 1.089962005615 -0.166750788689 -v -0.069718599319 1.135420084000 -0.119947195053 -v -0.057276010513 1.154541730881 -0.085973024368 -v -0.039468765259 1.162768602371 -0.098182201385 -v -0.047900676727 1.148107647896 -0.076298177242 -v -0.032938718796 1.155064463615 -0.086415827274 -v -0.067025423050 1.143415451050 -0.068977236748 -v -0.056419372559 1.138137459755 -0.063298463821 -v -0.015136957169 1.167805433273 -0.104464530945 -v -0.012070894241 1.159346342087 -0.092343151569 -v -0.014311790466 1.140978336334 -0.133057236671 -v -0.011669158936 1.129227042198 -0.125870227814 -v 0.016017198563 1.133123755455 -0.120839774609 -v 0.042919397354 1.136187195778 -0.116020321846 -v 0.069320917130 1.139438748360 -0.110212624073 -v 0.096272230148 1.142657041550 -0.103571355343 -v -0.084033012390 1.068661570549 -0.209112644196 -v -0.079619884491 1.055715084076 -0.200545787811 -v -0.114229202271 1.024448990822 -0.220436096191 -v -0.152589321136 1.005478620529 -0.229532003403 -v -0.190863609314 0.997435450554 -0.232511520386 -v 0.283624172211 1.127811551094 0.019655466080 -v 0.238133430481 1.093801021576 0.054984629154 -v 0.281615972519 1.070061683655 0.051802158356 -v 0.324586987495 1.083217859268 0.015623211861 -v 0.317109346390 1.049089670181 0.037077486515 -v 0.344853520393 1.035368323326 0.004752695560 -v 0.272841930389 1.062416911125 0.039141774178 -v 0.309236288071 1.042762875557 0.023036181927 -v 0.228971004486 1.083329319954 0.041944861412 -v 0.336932301521 1.026821017265 -0.005697131157 -v 0.352009296417 1.016058206558 -0.045218408108 -v 0.363454222679 1.025239586830 -0.041483044624 -v 0.350228548050 1.082829117775 -0.050576865673 -v 0.331254720688 1.069567441940 -0.102947354317 -v 0.354001879692 1.020647644997 -0.085915803909 -v 0.344488024712 1.012196183205 -0.082506895065 -v 0.291500329971 1.049303770065 -0.131860733032 -v 0.316508769989 1.020089149475 -0.108288466930 -v 0.278244972229 1.045682430267 -0.121770381927 -v 0.329316139221 1.025645136833 -0.117285430431 -v 0.237555980682 1.070979237556 -0.131267666817 -v 0.035062551498 1.018665790558 0.116485953331 -v 0.040465593338 1.046646237373 0.092548847198 -v 0.039201974869 1.005905747414 0.105759739876 -v 0.407534599304 1.049324989319 -0.053019642830 -v 0.407415151596 1.048302650452 -0.055281043053 -v 0.409241080284 1.045540690422 -0.054215550423 -v 0.409348964691 1.045631766319 -0.052197813988 -v 0.407567024231 1.045038938522 -0.053497850895 -v 0.408619165421 1.045577406883 -0.051431357861 -v 0.405469179153 1.048570752144 -0.051153659821 -v 0.405564785004 1.047778606415 -0.056019663811 -v 0.403634786606 1.047237396240 -0.053114891052 -v 0.403636693954 1.047934293747 -0.055059254169 -v 0.400758862495 1.061518907547 -0.057837843895 -v 0.404543042183 1.054217815399 -0.054585695267 -v 0.403454065323 1.053356051445 -0.050477862358 -v 0.400370597839 1.052134513855 -0.054630398750 -v 0.400712847710 1.052084445953 -0.049256503582 -v 0.390304088593 1.109333515167 -0.057016730309 -v 0.388536572456 1.106098771095 -0.056595444679 -v 0.390356302261 1.105766057968 -0.046931087971 -v 0.392881512642 1.108199954033 -0.046167612076 -v 0.386311173439 1.096173763275 -0.029934227467 -v 0.384410738945 1.113091945648 -0.026496827602 -v 0.389004111290 1.130117177963 -0.037221312523 -v 0.392682909966 1.108635425568 -0.037295579910 -v 0.393145322800 1.127447843552 -0.052910566330 -v 0.390158653259 1.094229102135 -0.034627795219 -v 0.365346193314 1.095366001129 -0.075250387192 -v 0.361508131027 1.084615111351 -0.066927909851 -v 0.372699022293 1.087730288506 -0.066918432713 -v 0.371014833450 1.094595193863 -0.072323203087 -v 0.361182332039 1.096700906754 -0.029368877411 -v 0.354959249496 1.107748985291 -0.019379496574 -v 0.363673329353 1.110366463661 -0.021963655949 -v 0.367691278458 1.100643992424 -0.026672244072 -v 0.374418973923 1.110103130341 -0.023161590099 -v 0.377149462700 1.091655015945 -0.026055395603 -v 0.373545646667 1.081293344498 -0.038487195969 -v 0.338927745819 1.093048810959 -0.023161709309 -v 0.335716485977 1.096756339073 -0.022189855576 -v 0.333831310272 1.101293921471 -0.015252113342 -v 0.339010357857 1.099372625351 -0.015726268291 -v 0.336115360260 1.103556871414 -0.011844396591 -v 0.344871759415 1.091088294983 -0.023372709751 -v 0.330793619156 1.106926560402 -0.018525958061 -v 0.326990127563 1.115554690361 -0.016181170940 -v 0.328750967979 1.092396497726 -0.021561920643 -v 0.325265884399 1.098267674446 -0.019644141197 -v 0.346914052963 1.103241682053 -0.017480194569 -v 0.338825702667 1.108204364777 -0.011111140251 -v 0.344290256500 1.120107769966 -0.013092637062 -v 0.340465307236 1.136773347855 -0.015785038471 -v 0.324753522873 1.125427603722 -0.015070736408 -v 0.325292944908 1.136361837387 -0.017429172993 -v 0.329348087311 1.116966009140 -0.013588488102 -v 0.332792520523 1.118334770203 -0.096988618374 -v 0.332243442535 1.122267842293 -0.094619393349 -v 0.323136806488 1.125333309174 -0.083494544029 -v 0.327710032463 1.113504409790 -0.092576861382 -v 0.341573119164 1.120945453644 -0.094311773777 -v 0.335590600967 1.131715416908 -0.092355489731 -v 0.328661322594 1.133670330048 -0.089798271656 -v 0.324473619461 1.135583043098 -0.085328757763 -v 0.353020310402 1.126932740211 -0.091999888420 -v 0.346932053566 1.140344977379 -0.090539395809 -v 0.324019074440 1.120222568512 -0.017995357513 -v 0.289908170700 1.127960801125 -0.085108101368 -v 0.304053783417 1.121056914330 -0.078729987144 -v 0.358429908752 1.193968534470 -0.088134527206 -v 0.357683658600 1.184876799583 -0.100257873535 -v 0.363889813423 1.171106338501 -0.087482929230 -v 0.366210937500 1.176288127899 -0.080222189426 -v 0.368631839752 1.159053325653 -0.078640401363 -v 0.373743414879 1.167661428452 -0.066681802273 -v 0.375433444977 1.182421684265 -0.018816709518 -v 0.371500611305 1.164965748787 -0.026864171028 -v 0.360645771027 1.163048863411 -0.020475804806 -v 0.365925073624 1.182272315025 -0.013802051544 -v 0.355728268623 1.168922543526 -0.016866326332 -v 0.365192413330 1.144321084023 -0.023384571075 -v 0.351355433464 1.141466021538 -0.019072234631 -v 0.347202420235 1.153388857841 -0.018843293190 -v 0.341611385345 1.160166978836 -0.015560805798 -v 0.308113574982 1.139430522919 -0.086172342300 -v 0.313164234161 1.145732045174 -0.091821610928 -v 0.344058752060 1.152563452721 -0.093004882336 -v 0.359626531601 1.152780056000 -0.086724877357 -v 0.353022336960 1.166682362556 -0.092923939228 -v 0.347189664841 1.169834375381 -0.094244897366 -v 0.342811346054 1.158735275269 -0.094510555267 -v 0.353778600693 1.178154706955 -0.104299247265 -v 0.348872900009 1.177428722382 -0.102648377419 -v 0.331777811050 1.146316647530 -0.093712210655 -v 0.320755481720 1.145852565765 -0.098560571671 -v 0.323286175728 1.148737668991 -0.101337194443 -v 0.333321571350 1.152906417847 -0.097986042500 -v 0.326210260391 1.151933670044 -0.103993952274 -v 0.320780992508 1.131242513657 -0.019613742828 -v 0.316488265991 1.137263059616 -0.026703536510 -v 0.320133447647 1.137962102890 -0.020618379116 -v 0.337424993515 1.147775053978 -0.018649101257 -v 0.334059238434 1.153875350952 -0.016800880432 -v 0.332339167595 1.160215377808 -0.011005222797 -v 0.333034753799 1.162801146507 -0.010488092899 -v 0.342080116272 1.164801001549 -0.014642059803 -v 0.329650044441 1.156030654907 -0.012940168381 -v 0.320695400238 1.147234559059 -0.025550961494 -v 0.324349880219 1.148427605629 -0.021465837955 -v 0.324996113777 1.144489049911 -0.022029399872 -v 0.319767236710 1.142206072807 -0.025610327721 -v 0.316439867020 1.145988821983 -0.028391957283 -v 0.314030408859 1.140980482101 -0.030016005039 -v 0.306605100632 1.136893630028 -0.031398415565 -v 0.311094760895 1.138293743134 -0.030661761761 -v 0.314454317093 1.133188128471 -0.029211819172 -v 0.307747125626 1.131512522697 -0.031591475010 -v 0.291517019272 1.138318657875 -0.033916234970 -v 0.304842948914 1.122800350189 -0.030405402184 -v 0.289185523987 1.130287408829 -0.033323228359 -v 0.286009788513 1.137142181396 -0.090150713921 -v 0.292701721191 1.141978979111 -0.107457876205 -v 0.304615020752 1.142538189888 -0.102706909180 -v 0.309559822083 1.150496006012 -0.024630010128 -v 0.318125486374 1.150960326195 -0.022390007973 -v 0.317887067795 1.153405547142 -0.009570956230 -v 0.321745395660 1.151527643204 -0.017602443695 -v 0.312289476395 1.154029130936 -0.016137778759 -v 0.300724506378 1.151372194290 -0.025900006294 -v 0.302543878555 1.155046701431 -0.016855716705 -v 0.311131477356 1.148434042931 -0.121525228024 -v 0.314778566360 1.145795822144 -0.111356735229 -v 0.318232536316 1.148830175400 -0.113018929958 -v 0.316641569138 1.155373811722 -0.125974237919 -v 0.310946226120 1.160884141922 -0.130396544933 -v 0.305948495865 1.152399063110 -0.128264009953 -v 0.322793602943 1.153211474419 -0.114452242851 -v 0.319596290588 1.160681724548 -0.123025000095 -v 0.319034099579 1.171830296516 0.017393767834 -v 0.317905664444 1.160627365112 0.008475244045 -v 0.311162710190 1.163662672043 0.014921247959 -v 0.310447931290 1.172396779060 0.019649803638 -v 0.309610843658 1.159015893936 0.012034296989 -v 0.310906410217 1.144272089005 -0.107071161270 -v 0.306469917297 1.144841670990 -0.117874324322 -v 0.302479743958 1.143570303917 -0.114495694637 -v 0.301431417465 1.147624731064 -0.126265466213 -v 0.295472621918 1.145630240440 -0.120796620846 -v 0.288472175598 1.148880720139 -0.025115370750 -v 0.301652908325 1.141206622124 -0.031471252441 -v 0.309620141983 1.142498731613 -0.029031515121 -v 0.273790359497 1.148244857788 -0.025866985321 -v 0.272537946701 1.142426609993 -0.030830979347 -v 0.272406339645 1.134789586067 -0.032956182957 -v 0.291519165039 1.153991341591 -0.016412615776 -v 0.305040836334 1.167021632195 0.019629895687 -v 0.307030200958 1.163709878922 0.017679572105 -v 0.305133104324 1.161130547523 0.017725169659 -v 0.303712606430 1.163359761238 0.020457804203 -v 0.294210910797 1.150454163551 -0.129565417767 -v 0.297544717789 1.151566028595 -0.131443619728 -v 0.299007177353 1.157061815262 -0.131160855293 -v 0.289251804352 1.162134289742 -0.127951741219 -v 0.300848484039 1.162901401520 0.020725965500 -v 0.299931526184 1.168733119965 0.019787251949 -v 0.302267789841 1.160912990570 0.017476558685 -v 0.284586906433 1.155997037888 -0.118712186813 -v 0.320478677750 1.183388590813 0.019893288612 -v 0.315504550934 1.185158967972 0.021765649319 -v 0.304894447327 1.174435973167 0.020509123802 -v 0.311547279358 1.187007069588 0.021684288979 -v 0.294510126114 1.164358973503 0.015730142593 -v 0.295584678650 1.166682958603 0.018493294716 -v 0.298225879669 1.162472367287 0.019704580307 -v 0.296677112579 1.161968946457 0.018077135086 -v 0.299949407578 1.160799622536 0.016491711140 -v 0.297479152679 1.160787940025 0.014298200607 -v 0.295337200165 1.162495613098 0.013063669205 -v 0.297493457794 1.159226298332 0.006240844727 -v 0.292984724045 1.162090659142 0.007228136063 -v 0.289747714996 1.165970087051 0.009980738163 -v 0.293587207794 1.173587322235 0.017361879349 -v 0.295882701874 1.184546113014 0.019877433777 -v 0.289324522018 1.170376300812 0.013289868832 -v 0.304202318192 1.163235664368 -0.131868004799 -v 0.295037984848 1.173500776291 -0.132903218269 -v 0.339935421944 1.204928994179 0.011042654514 -v 0.323164343834 1.198740124702 0.019174516201 -v 0.319356679916 1.202640295029 0.017888188362 -v 0.333619713783 1.216896772385 0.006251335144 -v 0.316392660141 1.223941683769 0.004564166069 -v 0.318291187286 1.236307144165 -0.009308457375 -v 0.339412450790 1.232521295547 -0.013116896152 -v 0.309664726257 1.210659503937 0.013969600201 -v 0.320227146149 1.235717296600 -0.089737355709 -v 0.315104484558 1.228830337524 -0.112790822983 -v 0.326388478279 1.222050905228 -0.113814830780 -v 0.333210706711 1.227595806122 -0.095670104027 -v 0.337775707245 1.211602926254 -0.112435698509 -v 0.344557762146 1.216145873070 -0.082126915455 -v 0.326203584671 1.226114869118 -0.064788460732 -v 0.278375148773 1.164562225342 0.002692937851 -v 0.286962032318 1.159514427185 -0.002162218094 -v 0.278234004974 1.155510902405 -0.013907790184 -v 0.260844707489 1.160049319267 -0.009037494659 -v 0.253694772720 1.171441078186 0.002056777477 -v 0.274199008942 1.172616839409 0.009002089500 -v 0.241376399994 1.164381980896 -0.022117018700 -v 0.236744165421 1.171596884727 -0.017185091972 -v 0.257408142090 1.154074668884 -0.020835101604 -v 0.240831613541 1.161932706833 -0.027496337891 -v 0.272498369217 1.184606671333 0.015063345432 -v 0.283818006516 1.195466637611 0.018259227276 -v 0.251496076584 1.179788351059 0.004774987698 -v 0.280345439911 1.187177538872 -0.130770325661 -v 0.278849363327 1.200135588646 -0.128845155239 -v 0.264022827148 1.197203159332 -0.124487996101 -v 0.263042688370 1.188585639000 -0.125758051872 -v 0.247735500336 1.194719552994 -0.112018883228 -v 0.248827695847 1.181841850281 -0.113283038139 -v 0.269680976868 1.173762202263 -0.124203026295 -v 0.254821300507 1.213196992874 -0.005989432335 -v 0.259692907333 1.217268109322 -0.002873539925 -v 0.264866352081 1.212918281555 0.006526708603 -v 0.262398242950 1.203422427177 0.007279813290 -v 0.274141788483 1.213083267212 0.013194501400 -v 0.276415348053 1.206676006317 0.013642489910 -v 0.247564315796 1.194469571114 -0.000649333000 -v 0.245563030243 1.205689191818 -0.011326313019 -v 0.232998371124 1.204849720001 -0.033008277416 -v 0.242313385010 1.215915679932 -0.027005612850 -v 0.237220525742 1.198678970337 -0.018567323685 -v 0.235009908676 1.188932180405 -0.016125142574 -v 0.229682207108 1.194204092026 -0.034655272961 -v 0.280081987381 1.256208896637 -0.019527673721 -v 0.266340732574 1.257276535034 -0.021893620491 -v 0.272911071777 1.248642563820 -0.034798681736 -v 0.289152145386 1.246002078056 -0.035115897655 -v 0.308747768402 1.234785199165 -0.048455655575 -v 0.315008163452 1.240252733231 -0.028551578522 -v 0.295452594757 1.246342897415 -0.017771065235 -v 0.291768074036 1.252464294434 -0.011624932289 -v 0.272852182388 1.246320486069 0.026719093323 -v 0.274995565414 1.244897484779 0.026039719582 -v 0.270889520645 1.239411234856 0.026342213154 -v 0.269581317902 1.240408897400 0.026497364044 -v 0.264169454575 1.234132766724 0.025929450989 -v 0.263763427734 1.235451221466 0.026660978794 -v 0.263376712799 1.240142583847 0.021522641182 -v 0.268235921860 1.245139122009 0.023626983166 -v 0.227350234985 1.201413989067 -0.060404598713 -v 0.226505756378 1.187961101532 -0.062663376331 -v 0.232470035553 1.193228960037 -0.089262902737 -v 0.238893508911 1.210202097893 -0.088255286217 -v 0.253223896027 1.206307768822 -0.110778868198 -v 0.239593505859 1.224539875984 -0.073748230934 -v 0.232012033463 1.216619491577 -0.053089022636 -v 0.252145767212 1.219983339310 -0.097832560539 -v 0.250634193420 1.229226589203 -0.085364758968 -v 0.252376794815 1.238263368607 -0.057780742645 -v 0.267105579376 1.240937113762 -0.056898772717 -v 0.258289337158 1.241248607635 -0.051965177059 -v 0.252767086029 1.235920786858 -0.034247636795 -v 0.247609376907 1.233851552010 -0.039491355419 -v 0.265551090240 1.267001390457 0.009194791317 -v 0.272844314575 1.261870384216 0.012323737144 -v 0.270809888840 1.260163426399 0.015809416771 -v 0.262974262238 1.263656973839 0.012956202030 -v 0.268976211548 1.265585422516 0.000393331051 -v 0.258705377579 1.266561031342 -0.002085030079 -v 0.261866092682 1.261532545090 -0.010348796844 -v 0.274395465851 1.261371612549 -0.009189963341 -v 0.238660573959 1.248261332512 0.003617167473 -v 0.232067346573 1.245571255684 0.001219451427 -v 0.233589172363 1.253527522087 -0.000213980675 -v 0.238280773163 1.252982854843 0.002291560173 -v 0.241975069046 1.261794805527 0.000397861004 -v 0.244624614716 1.256234288216 0.001851916313 -v 0.222787380219 1.257822632790 -0.151930749416 -v 0.228422880173 1.254693269730 -0.147209823132 -v 0.230664730072 1.257706403732 -0.153383851051 -v 0.225557327271 1.260083436966 -0.156076908112 -v 0.224181652069 1.269489765167 -0.164974153042 -v 0.218438386917 1.260652661324 -0.156715095043 -v 0.235471725464 1.260826349258 -0.157907843590 -v 0.216721296310 1.261644721031 -0.151875853539 -v 0.215643405914 1.258587121964 -0.150196969509 -v 0.234998703003 1.261462807655 -0.124403178692 -v 0.224088907242 1.267516016960 -0.134056270123 -v 0.228742599487 1.274905562401 -0.138475537300 -v 0.243557214737 1.273823022842 -0.127884268761 -v 0.218826293945 1.271217346191 -0.139695227146 -v 0.223790407181 1.282513380051 -0.156298041344 -v 0.229401111603 1.281741142273 -0.159395992756 -v 0.243339538574 1.285583496094 -0.155722141266 -v 0.240149497986 1.285640001297 -0.147173225880 -v 0.263746500015 1.284044027328 -0.144365310669 -v 0.256647109985 1.283450603485 -0.135616004467 -v 0.249143123627 1.278396368027 -0.130899667740 -v 0.231034517288 1.281445980072 -0.142535567284 -v 0.228749275208 1.279866695404 -0.162645876408 -v 0.225111246109 1.280306816101 -0.161672592163 -v 0.326325416565 1.095832467079 -0.026897907257 -v 0.328660488129 1.092162013054 -0.027155876160 -v 0.334224581718 1.083390593529 -0.031802475452 -v 0.331976652145 1.086985468864 -0.036189317703 -v 0.244880199432 1.142374873161 -0.073979854584 -v 0.242966175079 1.142764568329 -0.078356206417 -v 0.235785722733 1.146784543991 -0.078433096409 -v 0.238635778427 1.145627975464 -0.074249148369 -v 0.232438325882 1.149214863777 -0.073069214821 -v 0.236898422241 1.147114753723 -0.069623470306 -v 0.255175828934 1.136546134949 -0.077648699284 -v 0.255682229996 1.136946439743 -0.070239722729 -v 0.269840002060 1.141850829124 -0.088529407978 -v 0.257449388504 1.150468826294 -0.085283041000 -v 0.282135963440 1.148957133293 -0.107223212719 -v 0.262875080109 1.157893180847 -0.106579840183 -v 0.264955282211 1.164611697197 -0.115844190121 -v 0.244687318802 1.169971346855 -0.105285048485 -v 0.246577739716 1.164339303970 -0.095911860466 -v 0.234338521957 1.172934412956 -0.084621906281 -v 0.237678050995 1.167568325996 -0.080495774746 -v 0.230271100998 1.181651115417 -0.088845074177 -v 0.227655649185 1.178839325905 -0.062708079815 -v 0.231756448746 1.172751188278 -0.062062919140 -v 0.229456424713 1.177902221680 -0.036529541016 -v 0.232846736908 1.170946717262 -0.038640320301 -v 0.227507114410 1.182419776917 -0.036165595055 -v 0.234830379486 1.176739931107 -0.015439331532 -v 0.235546827316 1.166122555733 -0.040820002556 -v 0.235387325287 1.167956709862 -0.061342179775 -v 0.236512184143 1.160708308220 -0.043142557144 -v 0.237915754318 1.161495804787 -0.059940874577 -v 0.241000175476 1.156659126282 -0.029682040215 -v 0.256223201752 1.147885084152 -0.025309741497 -v 0.252270221710 1.141531467438 -0.026705861092 -v 0.236812353134 1.148920893669 -0.030205547810 -v 0.290362834930 1.128957509995 -0.035883367062 -v 0.271513700485 1.134885430336 -0.035297334194 -v 0.306781768799 1.119673848152 -0.033734023571 -v 0.317042827606 1.112375974655 -0.022598922253 -v 0.317406177521 1.108932733536 -0.028873980045 -v 0.332089543343 1.094723105431 -0.085125267506 -v 0.322933316231 1.108649253845 -0.085476875305 -v 0.319103002548 1.109926819801 -0.080069780350 -v 0.329759955406 1.096952438354 -0.079336047173 -v 0.334635496140 1.087565541267 -0.070015192032 -v 0.337785124779 1.084333658218 -0.074962139130 -v 0.336755514145 1.081413388252 -0.053044438362 -v 0.338276147842 1.079147696495 -0.053146123886 -v 0.346428036690 1.085549473763 -0.069611251354 -v 0.343625307083 1.093718051910 -0.081809461117 -v 0.333607673645 1.104474425316 -0.090680718422 -v 0.343541741371 1.081957101822 -0.052684903145 -v 0.353684067726 1.082917213440 -0.067507863045 -v 0.358879923820 1.093483090401 -0.077935218811 -v 0.351037502289 1.092784404755 -0.080610275269 -v 0.360334396362 1.102306008339 -0.085941970348 -v 0.347621440887 1.101400613785 -0.092805027962 -v 0.345952153206 1.079882979393 -0.052633166313 -v 0.355161905289 1.077038049698 -0.051688134670 -v 0.343386173248 1.084547519684 -0.034452319145 -v 0.352032899857 1.082792043686 -0.035345792770 -v 0.340294599533 1.086036086082 -0.034663975239 -v 0.321768999100 1.104483842850 -0.020316779613 -v 0.326095461845 1.115695357323 -0.020195245743 -v 0.319353103638 1.123223304749 -0.025029301643 -v 0.322834372520 1.101128458977 -0.027329206467 -v 0.321851253510 1.127054452896 -0.022767901421 -v 0.353766679764 1.095177173615 -0.026385903358 -v 0.359876632690 1.086948037148 -0.037192046642 -v 0.368791699409 1.081473231316 -0.054299533367 -v 0.366416454315 1.085834145546 -0.039678335190 -v 0.375720381737 1.077826261520 -0.054867923260 -v 0.385641813278 1.069572925568 -0.047519683838 -v 0.386780261993 1.068247556686 -0.054583191872 -v 0.379089593887 1.078935027122 -0.064835965633 -v 0.387892365456 1.068310856819 -0.060149490833 -v 0.394519090652 1.059546113014 -0.055611908436 -v 0.389144182205 1.068464994431 -0.063209295273 -v 0.381745100021 1.079965829849 -0.068755567074 -v 0.395897269249 1.059724450111 -0.058292984962 -v 0.397762775421 1.058734893799 -0.060246050358 -v 0.390513181686 1.068549633026 -0.065918266773 -v 0.401293635368 1.052220582962 -0.057137370110 -v 0.402930855751 1.052381992340 -0.058841645718 -v 0.399328708649 1.059069991112 -0.062133789063 -v 0.404549121857 1.052707433701 -0.057922661304 -v 0.400724768639 1.060495495796 -0.061055362225 -v 0.394371271133 1.071512341499 -0.065981507301 -v 0.392708420753 1.069672346115 -0.067366063595 -v 0.394284963608 1.071869850159 -0.062373280525 -v 0.388498425484 1.083336234093 -0.066320896149 -v 0.388929486275 1.082942962646 -0.069176137447 -v 0.389878511429 1.092170119286 -0.038135766983 -v 0.392562985420 1.073132753372 -0.038371622562 -v 0.393902897835 1.072458386421 -0.036485314369 -v 0.400479316711 1.060284376144 -0.040919661522 -v 0.400619268417 1.059895157814 -0.042878329754 -v 0.392677068710 1.071635484695 -0.034626603127 -v 0.399963617325 1.058247804642 -0.039560496807 -v 0.389219284058 1.072089076042 -0.033550858498 -v 0.398481249809 1.057546377182 -0.040394842625 -v 0.385063409805 1.070487856865 -0.035343050957 -v 0.395586490631 1.058170080185 -0.044803380966 -v 0.402001142502 1.052767753601 -0.042411684990 -v 0.388577699661 1.095486879349 -0.066482841969 -v 0.387288451195 1.094378232956 -0.064481914043 -v 0.389545917511 1.108287096024 -0.069271624088 -v 0.387219429016 1.094375610352 -0.071040332317 -v 0.390260934830 1.124660015106 -0.067944049835 -v 0.383810281754 1.146947145462 -0.036770582199 -v 0.387935638428 1.145303487778 -0.049735426903 -v 0.385385751724 1.144845247269 -0.066654205322 -v 0.379234194756 1.167300224304 -0.047699809074 -v 0.378260374069 1.142871618271 -0.078380703926 -v 0.384638786316 1.121478676796 -0.079748928547 -v 0.371328830719 1.114236831665 -0.083621263504 -v 0.366134643555 1.134753823280 -0.086642682552 -v 0.358268737793 1.111678957939 -0.091841936111 -v 0.384584784508 1.105457901955 -0.077077627182 -v 0.377453684807 1.103823542595 -0.078171491623 -v 0.383101344109 1.092535972595 -0.074570477009 -v 0.376216292381 1.093980312347 -0.073397576809 -v 0.384114503860 1.080561161041 -0.071538448334 -v 0.387168884277 1.081826567650 -0.071408987045 -v 0.378217101097 1.166335225105 -0.036741614342 -v 0.376491785049 1.185984611511 -0.027371287346 -v 0.375539779663 1.191256642342 -0.040807008743 -v 0.376024484634 1.146698236465 -0.028571903706 -v 0.380968809128 1.128817915916 -0.027356445789 -v 0.372819066048 1.124244213104 -0.021395444870 -v 0.357726931572 1.123675107956 -0.019232869148 -v 0.363764047623 1.199695229530 -0.003253161907 -v 0.359092354774 1.192318797112 -0.001357376575 -v 0.363418817520 1.207986116409 -0.009030759335 -v 0.363287687302 1.216881036758 -0.024423658848 -v 0.353446960449 1.214913725853 -0.051911473274 -v 0.367811679840 1.192584276199 -0.062469363213 -v 0.335019469261 1.232254981995 -0.039931237698 -v 0.341472268105 1.196155428886 0.010244071484 -v 0.354283452034 1.192304849625 -0.001765370369 -v 0.339673757553 1.196221947670 0.007006824017 -v 0.363298535347 1.182292938232 -0.012944102287 -v 0.354795575142 1.171777725220 -0.016488790512 -v 0.327435612679 1.161281824112 -0.002656698227 -v 0.324092507362 1.165798902512 0.006462395191 -v 0.322525382042 1.168064355850 0.004236161709 -v 0.326949238777 1.164337635040 -0.003446638584 -v 0.325284123421 1.158543467522 -0.003361463547 -v 0.322180032730 1.162310838699 0.007995128632 -v 0.320963859558 1.172976732254 0.015366852283 -v 0.319886207581 1.174322366714 0.011200785637 -v 0.321480035782 1.183079004288 0.017309784889 -v 0.326878428459 1.193821310997 0.018233954906 -v 0.327511191368 1.192236304283 0.015911042690 -v 0.303445339203 1.120934963226 -0.074148416519 -v 0.251810550690 1.141942739487 -0.031309187412 -v 0.241466999054 1.146666526794 -0.036401212215 -v 0.236400604248 1.148872971535 -0.047140300274 -v 0.230206489563 1.152073264122 -0.044595956802 -v 0.229574203491 1.151367187500 -0.061807334423 -v 0.239748239517 1.160202145576 -0.073878407478 -v 0.247816801071 1.157876133919 -0.081561207771 -v 0.234130144119 1.149081230164 -0.061738610268 -v 0.224230289459 1.281635522842 -0.153767704964 -v 0.223762512207 1.278146028519 -0.159069538116 -v 0.219611406326 1.279417753220 -0.152326762676 -v 0.213749408722 1.273561835289 -0.144396305084 -v 0.217382907867 1.273008942604 -0.147697806358 -v 0.221839427948 1.275884628296 -0.154915273190 -v 0.210401773453 1.265159130096 -0.141010046005 -v 0.213674545288 1.265947461128 -0.146045088768 -v 0.217527627945 1.274109721184 -0.141741633415 -v 0.215512275696 1.264181613922 -0.138061285019 -v 0.220313549042 1.262314796448 -0.135805130005 -v 0.220573663712 1.257741451263 -0.138237059116 -v 0.216372489929 1.257721900940 -0.141187667847 -v 0.212907791138 1.258577108383 -0.145352184772 -v 0.233858585358 1.256473422050 -0.125267803669 -v 0.234248638153 1.251918315887 -0.127823233604 -v 0.246033430099 1.251870393753 -0.112772464752 -v 0.246748685837 1.247483968735 -0.115507006645 -v 0.247130870819 1.256455659866 -0.111137330532 -v 0.258541584015 1.245236992836 -0.084437072277 -v 0.256093978882 1.239906072617 -0.086883187294 -v 0.257097005844 1.266151666641 -0.110764563084 -v 0.266882419586 1.251339793205 -0.085104942322 -v 0.267502307892 1.270240545273 -0.112958729267 -v 0.275364637375 1.256015896797 -0.091180860996 -v 0.275161266327 1.274131059647 -0.118503391743 -v 0.285532474518 1.258744239807 -0.098316013813 -v 0.281810045242 1.273761987686 -0.128352165222 -v 0.294841051102 1.259177684784 -0.109563946724 -v 0.285378694534 1.267878890038 -0.136893749237 -v 0.299645662308 1.256075739861 -0.122435271740 -v 0.267150640488 1.279207229614 -0.152110457420 -v 0.266644477844 1.272503018379 -0.155482232571 -v 0.285328865051 1.260385632515 -0.145259499550 -v 0.245440483093 1.281306147575 -0.162130832672 -v 0.247352838516 1.277317881584 -0.164401888847 -v 0.226536273956 1.277150392532 -0.165146172047 -v 0.244216680527 1.272458314896 -0.165734708309 -v 0.265185594559 1.264242410660 -0.158591628075 -v 0.225196361542 1.271236658096 -0.164832949638 -v 0.240829467773 1.264716506004 -0.164158344269 -v 0.256122827530 1.256213188171 -0.158023118973 -v 0.249283313751 1.251091122627 -0.154383540154 -v 0.264867782593 1.238259196281 -0.149782478809 -v 0.271236419678 1.243698835373 -0.152746677399 -v 0.242131233215 1.248456358910 -0.149258136749 -v 0.259697437286 1.235559821129 -0.143175721169 -v 0.238021850586 1.246404170990 -0.140355885029 -v 0.255519628525 1.235976219177 -0.134220600128 -v 0.235714912415 1.248224496841 -0.132601261139 -v 0.249901533127 1.242415428162 -0.121484637260 -v 0.225628137589 1.255354166031 -0.141528964043 -v 0.219279289246 1.256212234497 -0.146652877331 -v 0.261144638062 1.227618336678 -0.105385541916 -v 0.265067815781 1.218194127083 -0.118982553482 -v 0.255488157272 1.234093666077 -0.095165371895 -v 0.257819652557 1.237515091896 -0.082652032375 -v 0.256304979324 1.231330990791 -0.090660393238 -v 0.261433124542 1.242497920990 -0.080974459648 -v 0.269018650055 1.247485637665 -0.080007076263 -v 0.276544094086 1.249154090881 -0.084097981453 -v 0.286174535751 1.250129461288 -0.091734588146 -v 0.297051906586 1.250920057297 -0.101950109005 -v 0.304772377014 1.248518705368 -0.115050077438 -v 0.297762155533 1.245796918869 -0.131601870060 -v 0.303509950638 1.239294528961 -0.125708818436 -v 0.278063774109 1.251515507698 -0.150501132011 -v 0.292453289032 1.234364628792 -0.138768732548 -v 0.285548925400 1.222070693970 -0.138958930969 -v 0.275888442993 1.216582298279 -0.135062336922 -v 0.269642829895 1.214331030846 -0.127090573311 -v 0.265042543411 1.214603662491 -0.116683065891 -v 0.270244359970 1.211904883385 -0.125036418438 -v 0.259296417236 1.223366022110 -0.101866900921 -v 0.260845899582 1.212415218353 -0.112328946590 -v 0.266552209854 1.205083847046 -0.122853875160 -v 0.268821239471 1.210025906563 -0.123203098774 -v 0.277948856354 1.207428336143 -0.128034055233 -v 0.277915716171 1.211367130280 -0.128684759140 -v 0.288717508316 1.213802814484 -0.129420161247 -v 0.287309169769 1.217238068581 -0.130407452583 -v 0.277626991272 1.213335871696 -0.130287289619 -v 0.286727428436 1.219543695450 -0.133292317390 -v 0.297491550446 1.224069118500 -0.127825796604 -v 0.295832872391 1.229104042053 -0.133770406246 -v 0.299275398254 1.222613096237 -0.126457333565 -v 0.306288719177 1.231516838074 -0.115943133831 -v 0.303650856018 1.233008384705 -0.119831323624 -v 0.304522037506 1.218244671822 -0.125307500362 -v 0.291501283646 1.207969903946 -0.129891932011 -v 0.295377254486 1.198327302933 -0.132311940193 -v 0.312335252762 1.210624575615 -0.126865327358 -v 0.307499647141 1.182762622833 -0.133446455002 -v 0.321811676025 1.199660181999 -0.127626895905 -v 0.313686370850 1.178631782532 -0.132702827454 -v 0.327832698822 1.190094709396 -0.127820491791 -v 0.318174362183 1.174999833107 -0.130550682545 -v 0.329443216324 1.184651136398 -0.126586496830 -v 0.320348262787 1.172263383865 -0.127011775970 -v 0.329268336296 1.182359218597 -0.124253869057 -v 0.319159746170 1.172549962997 -0.124517083168 -v 0.327510595322 1.181082725525 -0.121122121811 -v 0.341977953911 1.186866998672 -0.119443237782 -v 0.340240001678 1.181673407555 -0.114829957485 -v 0.342066526413 1.190820455551 -0.118938207626 -v 0.343557119370 1.197325468063 -0.114280879498 -v 0.308367967606 1.238885641098 -0.100797057152 -v 0.302496671677 1.241308212280 -0.108589589596 -v 0.297030925751 1.244460582733 -0.094559252262 -v 0.288425922394 1.242414832115 -0.070966482162 -v 0.300933361053 1.241560339928 -0.084082663059 -v 0.287242650986 1.245997667313 -0.082513213158 -v 0.276428461075 1.242347240448 -0.063216865063 -v 0.276814937592 1.246329665184 -0.074558973312 -v 0.262533426285 1.248234033585 -0.033080637455 -v 0.268426895142 1.245181202888 -0.070157289505 -v 0.255537271500 1.244341135025 -0.030193269253 -v 0.255340337753 1.255470871925 -0.021258711815 -v 0.248293161392 1.248656272888 -0.019238531590 -v 0.246406555176 1.241610646248 -0.014172136784 -v 0.252004623413 1.238135337830 -0.023450851440 -v 0.240248918533 1.252865195274 -0.008260846138 -v 0.236009836197 1.244751214981 -0.002041816711 -v 0.250643014908 1.260913610458 -0.006915748119 -v 0.241449356079 1.238094210625 0.000856995583 -v 0.248243808746 1.235244989395 -0.007029771805 -v 0.236295223236 1.238589763641 0.006947577000 -v 0.244088888168 1.237448453903 0.010651528835 -v 0.245872020721 1.235504984856 0.007974743843 -v 0.240644693375 1.243501543999 0.007078409195 -v 0.245250463486 1.240480542183 0.010777413845 -v 0.252675771713 1.233302831650 0.020247042179 -v 0.254426479340 1.231533646584 0.017972588539 -v 0.254062652588 1.237539768219 0.019096493721 -v 0.276159763336 1.255128741264 0.018554508686 -v 0.275947093964 1.249229311943 0.022302091122 -v 0.272867918015 1.249667882919 0.024674117565 -v 0.271744251251 1.251732468605 0.021295309067 -v 0.283636093140 1.255234718323 0.014072477818 -v 0.280255317688 1.247575402260 0.019362986088 -v 0.276215314865 1.261920690536 0.008904576302 -v 0.278604030609 1.259399175644 0.004241228104 -v 0.285460472107 1.252817630768 0.010138630867 -v 0.266534566879 1.266445875168 0.005049049854 -v 0.258428096771 1.268704891205 0.002973020077 -v 0.254645347595 1.267239928246 0.003869831562 -v 0.287663459778 1.258239984512 -0.004414916039 -v 0.298110485077 1.250542998314 0.003384351730 -v 0.298449993134 1.244361400604 -0.001860737801 -v 0.299829959869 1.234122157097 0.006569683552 -v 0.298758268356 1.238474845886 0.010709106922 -v 0.303976297379 1.239164352417 -0.006211340427 -v 0.305155038834 1.229295969009 0.004372239113 -v 0.300870895386 1.218429088593 0.011674880981 -v 0.295304775238 1.223464488983 0.011802554131 -v 0.293110609055 1.205903887749 0.015846788883 -v 0.286343812943 1.213704109192 0.013587355614 -v 0.302354812622 1.196681976318 0.018828034401 -v 0.283874988556 1.219200730324 0.015126287937 -v 0.293270826340 1.227752089500 0.015739440918 -v 0.283052444458 1.240837812424 0.023119628429 -v 0.276622056961 1.233630180359 0.024268507957 -v 0.286540031433 1.246751070023 0.017804086208 -v 0.272910356522 1.237592816353 0.025359690189 -v 0.278305053711 1.243288516998 0.024740695953 -v 0.267666101456 1.227963447571 0.022224366665 -v 0.264769792557 1.232656955719 0.024754941463 -v 0.260413408279 1.224851250648 0.011581957340 -v 0.257379055023 1.225758671761 -0.000789821148 -v 0.253545045853 1.232021093369 -0.012868225574 -v 0.254851341248 1.226656675339 -0.018729388714 -v 0.251304626465 1.230217099190 0.003005683422 -v 0.256979942322 1.228909850121 0.014670252800 -v 0.250156402588 1.223106861115 -0.021990776062 -v 0.239892244339 1.227292776108 -0.045880913734 -v 0.245432853699 1.234084725380 -0.064319491386 -v 0.254643917084 1.237128496170 -0.077797412872 -v 0.259204149246 1.241605043411 -0.074413061142 -v 0.253374576569 1.265572071075 0.004234373569 -v 0.252619743347 1.259510278702 0.004528701305 -v 0.295717954636 1.157437562943 -0.004984855652 -v 0.302157163620 1.158133268356 0.007280886173 -v 0.303221464157 1.155419707298 -0.004480600357 -v 0.306118011475 1.158186078072 0.009157180786 -v 0.309594392776 1.154529452324 -0.002081036568 -v 0.317309141159 1.145281672478 -0.095512390137 -v 0.342793583870 1.111549854279 -0.096035361290 -v 0.370063781738 1.103682756424 -0.078702569008 -v 0.223846435547 1.280663371086 -0.149150192738 -v 0.262922763824 1.260004043579 0.011266469955 -v 0.278262376785 1.128904223442 -0.071313738823 -v 0.278782129288 1.129065513611 -0.078170895576 -v 0.214526414871 1.261890172958 -0.147512257099 -v 0.403749704361 1.053897500038 -0.044087231159 -v -0.173335313797 1.189228773117 -0.074161946774 -v -0.172501087189 1.194711208344 -0.077600002289 -v -0.156718730927 1.200044989586 -0.067752003670 -v -0.159983634949 1.195769190788 -0.064942240715 -v -0.157345533371 1.192241907120 -0.064338445663 -v -0.176035165787 1.182665348053 -0.074862539768 -v -0.153723001480 1.198203325272 -0.067141354084 -v -0.154419660568 1.185277462006 -0.061343967915 -v -0.174031734467 1.176616787910 -0.076530218124 -v -0.153948068619 1.192448616028 -0.066138029099 -v -0.152566671371 1.196974277496 -0.068748712540 -v -0.149900436401 1.188096642494 -0.064178586006 -v -0.167804479599 1.171906828880 -0.078679144382 -v -0.151026010513 1.177392482758 -0.069037199020 -v -0.159547805786 1.170724391937 -0.081492185593 -v -0.137443780899 1.179318189621 -0.071261107922 -v -0.151052713394 1.171566128731 -0.090630888939 -v -0.145410776138 1.202758073807 -0.074415385723 -v -0.146416664124 1.204916477203 -0.073959469795 -v -0.142997503281 1.206828117371 -0.075007200241 -v -0.139394283295 1.203434348106 -0.075942695141 -v -0.143990516663 1.207095742226 -0.077334642410 -v -0.152405261993 1.204598784447 -0.072375178337 -v -0.150315523148 1.201716780663 -0.070241928101 -v -0.169452428818 1.199298620224 -0.083030939102 -v -0.163226604462 1.203215003014 -0.090547025204 -v -0.193114757538 1.175109863281 -0.086916208267 -v -0.185326576233 1.171366214752 -0.082843124866 -v -0.186292409897 1.165282964706 -0.088589191437 -v -0.200573444366 1.166569828987 -0.092627763748 -v -0.138775825500 1.205187916756 -0.076617836952 -v -0.135615825653 1.203529238701 -0.077090024948 -v -0.155732393265 1.203607797623 -0.096656978130 -v -0.149366855621 1.200804471970 -0.100724101067 -v -0.137942790985 1.205677509308 -0.079242825508 -v -0.131234407425 1.203546047211 -0.080529451370 -v -0.130687952042 1.197476148605 -0.079052925110 -v -0.130004167557 1.197584390640 -0.081454098225 -v -0.129281997681 1.189852356911 -0.077395677567 -v -0.131329774857 1.190665483475 -0.076595366001 -v -0.141457080841 1.192768573761 -0.102260649204 -v -0.127812385559 1.196197390556 -0.082319319248 -v -0.144458770752 1.197188854218 -0.101949512959 -v -0.177466392517 1.161493182182 -0.094907760620 -v -0.163338899612 1.165530800819 -0.106261909008 -v -0.128491640091 1.187958240509 -0.082086682320 -v -0.140712261200 1.182583570480 -0.100011527538 -v -0.210927009583 1.107810139656 -0.110981822014 -v -0.211072683334 1.103303790092 -0.109917879105 -v -0.213212490082 1.101778507233 -0.109918236732 -v -0.214309692383 1.109030246735 -0.111766934395 -v -0.204130172729 1.105494737625 -0.113910675049 -v -0.205763339996 1.099799871445 -0.112921178341 -v -0.223363876343 1.117204904556 -0.114630222321 -v -0.214059114456 1.124341964722 -0.111509382725 -v -0.219065189362 1.105570316315 -0.114096760750 -v -0.238481521606 1.129768848419 -0.130072593689 -v -0.234876394272 1.134552240372 -0.130008339882 -v -0.223749637604 1.136018037796 -0.118461847305 -v -0.207642078400 1.120860934258 -0.111469984055 -v -0.208950042725 1.096844553947 -0.112857937813 -v -0.215140581131 1.098256349564 -0.112100958824 -v -0.209567785263 1.147545337677 -0.113711655140 -v -0.197745561600 1.140209794044 -0.107432365417 -v -0.193334102631 1.132169842720 -0.107758402824 -v -0.193572998047 1.150783538818 -0.107727050781 -v -0.203800201416 1.156490325928 -0.111603617668 -v -0.175592660904 1.145561695099 -0.106927514076 -v -0.172769784927 1.138006210327 -0.105781555176 -v -0.177102327347 1.152362346649 -0.109004378319 -v -0.203049182892 1.103446960449 -0.115947484970 -v -0.205771446228 1.097857356071 -0.116888880730 -v -0.200581550598 1.109675526619 -0.119850099087 -v -0.202297449112 1.114114880562 -0.116474270821 -v -0.205280303955 1.096752166748 -0.122693479061 -v -0.225318193436 1.093360424042 -0.128429234028 -v -0.225040435791 1.096657991409 -0.123039066792 -v -0.220809221268 1.096151828766 -0.119270980358 -v -0.221869707108 1.091606855392 -0.126757025719 -v -0.228603363037 1.095641136169 -0.129044175148 -v -0.228597879410 1.101918220520 -0.122385978699 -v -0.224291801453 1.103944659233 -0.118215620518 -v -0.247853517532 1.125877380371 -0.145480275154 -v -0.241319656372 1.134932279587 -0.146954476833 -v -0.224902391434 1.146563768387 -0.131057977676 -v -0.189874410629 1.125573754311 -0.113757431507 -v -0.188519477844 1.120980858803 -0.117558717728 -v -0.197483062744 1.107985734940 -0.124557018280 -v -0.203064918518 1.094104051590 -0.134538710117 -v -0.212108135223 1.091883540154 -0.125092267990 -v -0.146539926529 1.190650701523 -0.114794254303 -v -0.146754264832 1.180134177208 -0.115530133247 -v -0.152557849884 1.174678444862 -0.113840103149 -v -0.143783569336 1.177394032478 -0.097335398197 -v -0.152518033981 1.177743196487 -0.127124845982 -v -0.154675722122 1.168212413788 -0.123611927032 -v -0.152200698853 1.192405939102 -0.124226093292 -v -0.149080038071 1.190506696701 -0.121930062771 -v -0.149870634079 1.194133043289 -0.115894854069 -v -0.152212619781 1.190471172333 -0.127474963665 -v -0.152487754822 1.182887434959 -0.127529799938 -v -0.154866933823 1.185299873352 -0.129990160465 -v -0.154926300049 1.181805968285 -0.133388638496 -v -0.233518838882 1.051918983459 -0.153825461864 -v -0.234681367874 1.048460602760 -0.154123127460 -v -0.235526800156 1.045760154724 -0.156687140465 -v -0.238681077957 1.048464179039 -0.156781077385 -v -0.229362010956 1.049855709076 -0.154987037182 -v -0.227258443832 1.057394742966 -0.153537988663 -v -0.231667280197 1.046329975128 -0.156813800335 -v -0.223042964935 1.088201880455 -0.145084559917 -v -0.215483188629 1.087337613106 -0.146565556526 -v -0.215860605240 1.081712245941 -0.155044794083 -v -0.226407766342 1.085251331329 -0.153320491314 -v -0.235337972641 1.090702056885 -0.156869351864 -v -0.226635932922 1.075340270996 -0.153673052788 -v -0.235593795776 1.084217786789 -0.159696042538 -v -0.230427265167 1.064726591110 -0.154860198498 -v -0.235838890076 1.056318044662 -0.154584050179 -v -0.244804859161 1.037203311920 -0.166494607925 -v -0.242951393127 1.043129205704 -0.159860074520 -v -0.236907005310 1.041309475899 -0.161783397198 -v -0.243432760239 1.035140395164 -0.168893754482 -v -0.224668979645 1.052752375603 -0.157276332378 -v -0.230270862579 1.046147704124 -0.159191727638 -v -0.159595966339 1.184921741486 -0.135831117630 -v -0.160187005997 1.181343317032 -0.141996622086 -v -0.153135061264 1.179491877556 -0.142091393471 -v -0.169377088547 1.185044288635 -0.136880159378 -v -0.170533895493 1.181570768356 -0.151052296162 -v -0.160138130188 1.174441456795 -0.159372687340 -v -0.222903490067 1.065987110138 -0.152610003948 -v -0.210915327072 1.058199882507 -0.158076643944 -v -0.219084739685 1.052546024323 -0.157240092754 -v -0.209656953812 1.069716095924 -0.156206488609 -v -0.242612361908 1.097414970398 -0.161309957504 -v -0.247563600540 1.103350877762 -0.164090692997 -v -0.248119831085 1.110607266426 -0.158350706100 -v -0.241690874100 1.101655244827 -0.159433066845 -v -0.244697809219 1.092168807983 -0.164222717285 -v -0.251339673996 1.101027250290 -0.169793009758 -v -0.253261089325 1.111646056175 -0.160615861416 -v -0.246266365051 1.039236307144 -0.166336178780 -v -0.249294042587 1.037806272507 -0.168891787529 -v -0.250867843628 1.039080262184 -0.168178379536 -v -0.247174024582 1.041245818138 -0.164608359337 -v -0.252528667450 1.034430623055 -0.174002289772 -v -0.255876541138 1.036398887634 -0.174964785576 -v -0.248456478119 1.035744786263 -0.171986579895 -v -0.207899332047 1.087407350540 -0.147547543049 -v -0.209868431091 1.082488656044 -0.153715491295 -v -0.206011295319 1.082607984543 -0.148635447025 -v -0.207342624664 1.075194835663 -0.155124664307 -v -0.252168178558 1.045034170151 -0.165443241596 -v -0.258034706116 1.046116113663 -0.173089325428 -v -0.262003183365 1.051245570183 -0.178000867367 -v -0.252234935760 1.049173116684 -0.164762079716 -v -0.252549409866 1.041483521461 -0.167263507843 -v -0.259843349457 1.041425228119 -0.177599608898 -v -0.270201206207 1.045489907265 -0.187091112137 -v -0.276372432709 1.040201425552 -0.192463517189 -v -0.278449535370 1.034975290298 -0.196169674397 -v -0.284775257111 1.029717683792 -0.197532415390 -v -0.284212112427 1.040760636330 -0.193028330803 -v -0.271418571472 1.038434147835 -0.194264531136 -v -0.273589372635 1.034032583237 -0.199454545975 -v -0.281298398972 1.027353167534 -0.202217400074 -v -0.285241842270 1.052183389664 -0.197862207890 -v -0.287758827209 1.044720053673 -0.200536787510 -v -0.285270452499 1.052050352097 -0.209925532341 -v -0.284770965576 1.056814908981 -0.208144426346 -v -0.286429882050 1.041720151901 -0.204202711582 -v -0.282965183258 1.049952030182 -0.209141969681 -v -0.281043052673 1.048063278198 -0.188708662987 -v -0.144400358200 1.176907896996 -0.151417970657 -v -0.135134458542 1.175758123398 -0.166907787323 -v -0.129020690918 1.170335769653 -0.138893842697 -v -0.141971826553 1.174503087997 -0.135131359100 -v -0.119428634644 1.164143443108 -0.165285944939 -v -0.116199493408 1.159146547318 -0.141210973263 -v -0.142082691193 1.176310896873 -0.178735315800 -v -0.151244163513 1.175081014633 -0.169050514698 -v -0.125181674957 1.176591157913 -0.177203238010 -v -0.130443096161 1.183761119843 -0.186303555965 -v -0.245208501816 1.111506700516 -0.205009043217 -v -0.232599973679 1.125318527222 -0.206095397472 -v -0.240747690201 1.128869056702 -0.186226844788 -v -0.252095937729 1.110360264778 -0.190840721130 -v -0.230934619904 1.112748980522 -0.219200611115 -v -0.201740980148 1.135213136673 -0.227704524994 -v -0.210019588470 1.145615220070 -0.203961193562 -v -0.256554365158 1.026075959206 -0.197485446930 -v -0.252297163010 1.025413274765 -0.206123828888 -v -0.262440681458 1.028629183769 -0.203707456589 -v -0.262872934341 1.028875350952 -0.197542905807 -v -0.253294944763 1.027410507202 -0.211396694183 -v -0.259093761444 1.029339194298 -0.211079478264 -v -0.246476411819 1.024986743927 -0.206110835075 -v -0.252317905426 1.024993419647 -0.197774946690 -v -0.311765909195 0.993130266666 -0.226933717728 -v -0.310108184814 0.996098339558 -0.225180983543 -v -0.310272455215 0.995082259178 -0.224124073982 -v -0.309615135193 0.992788553238 -0.226431727409 -v -0.307722568512 0.995178222656 -0.223333239555 -v -0.308899879456 0.997443914413 -0.225597083569 -v -0.306552886963 0.996318519115 -0.226082086563 -v -0.301561355591 0.999858021736 -0.221365690231 -v -0.301273822784 0.999540150166 -0.223513543606 -v -0.300451040268 0.999494612217 -0.225161433220 -v -0.291275262833 1.008644461632 -0.219689548016 -v -0.289765357971 1.008863568306 -0.223312497139 -v -0.303882122040 1.002618789673 -0.222436308861 -v -0.245472908020 1.029212474823 -0.216191470623 -v -0.251756668091 1.032742142677 -0.216125905514 -v -0.240088224411 1.029202461243 -0.212740898132 -v -0.305489063263 0.996842980385 -0.228073120117 -v -0.301641464233 1.000535249710 -0.226922750473 -v -0.297816038132 1.000618338585 -0.226435422897 -v -0.304344177246 0.995790660381 -0.228550374508 -v -0.307172536850 0.993706703186 -0.230047941208 -v -0.308262586594 0.994648814201 -0.229670286179 -v -0.308869600296 0.993044137955 -0.230499446392 -v -0.308663368225 0.993162393570 -0.231502115726 -v -0.309333801270 0.993721485138 -0.231109619141 -v -0.308087825775 0.994998931885 -0.231224834919 -v -0.103364944458 1.130733013153 -0.165089964867 -v -0.107626914978 1.133225798607 -0.140607297421 -v -0.110349178314 1.147431254387 -0.169585108757 -v -0.118245124817 1.140465259552 -0.188436806202 -v -0.112480401993 1.127350330353 -0.185356020927 -v -0.119234800339 1.154477119446 -0.179611444473 -v -0.122121334076 1.162646651268 -0.173162460327 -v -0.123259067535 1.147673130035 -0.192043066025 -v -0.307780742645 0.994723260403 -0.231847167015 -v -0.307749986649 0.993669688702 -0.231788516045 -v -0.306983709335 0.993704020977 -0.230996787548 -v -0.193033456802 1.081855773926 -0.203872740269 -v -0.194959878922 1.074067234993 -0.206613779068 -v -0.192106723785 1.074653506279 -0.197215080261 -v -0.189585685730 1.081505656242 -0.199741780758 -v -0.181468963623 1.087621688843 -0.203916847706 -v -0.182246923447 1.086801290512 -0.208190560341 -v -0.180797338486 1.080666303635 -0.200190067291 -v -0.238004446030 1.038412332535 -0.221756696701 -v -0.255303144455 1.040868282318 -0.221722602844 -v -0.259346246719 1.034848093987 -0.217119097710 -v -0.226242780685 1.046014308929 -0.223912119865 -v -0.243605136871 1.045503258705 -0.225179314613 -v -0.229806661606 1.033677101135 -0.221885204315 -v -0.128174781799 1.188377022743 -0.200627446175 -v -0.148290157318 1.179109573364 -0.194076895714 -v -0.271722316742 1.054550886154 -0.227642059326 -v -0.274076938629 1.049859046936 -0.228212535381 -v -0.270540475845 1.041400551796 -0.231285452843 -v -0.265389442444 1.048523783684 -0.231947541237 -v -0.279670238495 1.057693004608 -0.219425976276 -v -0.279539346695 1.051576972008 -0.220776438713 -v -0.275705814362 1.041727423668 -0.228427529335 -v -0.199706077576 1.055555105209 -0.210151553154 -v -0.194469451904 1.055464029312 -0.201491832733 -v -0.188562631607 1.062397480011 -0.194959938526 -v -0.193209409714 1.067214727402 -0.202750325203 -v -0.197559595108 1.061594724655 -0.212190330029 -v -0.199322462082 1.054384827614 -0.212732195854 -v -0.264539003372 1.034891843796 -0.224602222443 -v -0.264505386353 1.033686161041 -0.220391511917 -v -0.259446859360 1.043034553528 -0.228882968426 -v -0.253154993057 1.049899816513 -0.229087173939 -v -0.192896127701 1.083252668381 -0.207294523716 -v -0.205631494522 1.076366066933 -0.214735269547 -v -0.194759368896 1.084827780724 -0.212751626968 -v -0.223470926285 1.074144601822 -0.221447348595 -v -0.204793214798 1.086842775345 -0.216361939907 -v -0.216625213623 1.087888479233 -0.219625651836 -v -0.195574283600 1.087720632553 -0.216327428818 -v -0.220762968063 1.036061048508 -0.216470956802 -v -0.213054895401 1.035783767700 -0.213620066643 -v -0.201663494110 1.045588612556 -0.206914484501 -v -0.209848642349 1.043720960617 -0.214580178261 -v -0.216307878494 1.038053512573 -0.218539953232 -v -0.226351261139 1.035285830498 -0.218240320683 -v -0.205461740494 1.046299815178 -0.217294871807 -v -0.213101387024 1.042110800743 -0.219072997570 -v -0.220921278000 1.039087295532 -0.221290767193 -v -0.220387458801 1.042260169983 -0.223516404629 -v -0.213362932205 1.046354770660 -0.223494648933 -v -0.166803121567 1.090283155441 -0.212349832058 -v -0.172270536423 1.087766289711 -0.218560039997 -v -0.183573484421 1.086018800735 -0.212494730949 -v -0.167399406433 1.091666579247 -0.207822561264 -v -0.158848285675 1.093401670456 -0.218638300896 -v -0.162909030914 1.089765548706 -0.223327994347 -v -0.030130147934 1.186614990234 -0.177592396736 -v -0.028016805649 1.185017704964 -0.176330447197 -v -0.027128219604 1.182949185371 -0.177097141743 -v -0.030794620514 1.185065984726 -0.177214145660 -v -0.027263402939 1.185469865799 -0.176604092121 -v -0.029033184052 1.187615036964 -0.178278744221 -v -0.025565147400 1.183858990669 -0.176834225655 -v -0.026248216629 1.187106251717 -0.178503096104 -v -0.155820369720 1.101422905922 -0.208842039108 -v -0.143939018250 1.110964536667 -0.203809499741 -v -0.147772073746 1.116233944893 -0.210553169250 -v -0.153800964355 1.103918313980 -0.216478586197 -v -0.151521444321 1.110116600990 -0.224545180798 -v -0.153570175171 1.098989486694 -0.229076087475 -v -0.153712034225 1.098475694656 -0.221522092819 -v -0.143598556519 1.121090412140 -0.215590834618 -v -0.025197982788 1.179040908813 -0.178160905838 -v -0.028691530228 1.180666327477 -0.177641034126 -v -0.024049282074 1.180395364761 -0.178064346313 -v -0.023061275482 1.183145642281 -0.176922082901 -v -0.024633884430 1.187012076378 -0.180191814899 -v -0.022006034851 1.183752536774 -0.176543354988 -v -0.023281335831 1.181692600250 -0.177503108978 -v -0.041700124741 1.194597840309 -0.188832759857 -v -0.040053844452 1.195041775703 -0.191445589066 -v -0.038641691208 1.194105863571 -0.194117784500 -v -0.021546125412 1.184016108513 -0.178950071335 -v -0.023211956024 1.185567021370 -0.181426763535 -v -0.020884990692 1.182555675507 -0.179597258568 -v -0.155306577682 1.094101190567 -0.223596096039 -v -0.153067588806 1.095505952835 -0.230197072029 -v -0.024875402451 1.176557660103 -0.180157959461 -v -0.029001712799 1.177595734596 -0.180325567722 -v -0.022265434265 1.178601741791 -0.180594265461 -v -0.022731781006 1.183528065681 -0.182420313358 -v -0.129092454910 1.126704692841 -0.201514482498 -v -0.129842519760 1.138575315475 -0.203304290771 -v -0.140452623367 1.137107372284 -0.216508805752 -v -0.143960952759 1.126296997070 -0.219137907028 -v -0.154357194901 1.127161264420 -0.228255271912 -v -0.149726629257 1.136419534683 -0.223747491837 -v -0.174418687820 1.142764806747 -0.223434805870 -v -0.169390678406 1.132646441460 -0.235435843468 -v -0.159634113312 1.138588905334 -0.227177619934 -v -0.183374881744 1.151468753815 -0.210604786873 -v -0.202531337738 1.122591972351 -0.235654771328 -v -0.174713850021 1.123547434807 -0.239896833897 -v -0.026677846909 1.177809119225 -0.182901620865 -v -0.028857231140 1.177586197853 -0.182363390923 -v -0.180840730667 1.098434567451 -0.228965997696 -v -0.177192926407 1.093732595444 -0.232580184937 -v -0.174651861191 1.104560375214 -0.238290369511 -v -0.178368806839 1.106090188026 -0.233393609524 -v -0.168076038361 1.097283363342 -0.234453976154 -v -0.169014692307 1.107891798019 -0.237803101540 -v -0.176104545593 1.089681625366 -0.227148771286 -v -0.167286634445 1.091750741005 -0.230993151665 -v -0.157043457031 1.091841936111 -0.227160215378 -v -0.159157276154 1.091518163681 -0.229555249214 -v -0.155268907547 1.095846176147 -0.231792688370 -v -0.160398960114 1.094118118286 -0.232700586319 -v -0.161424636841 1.113683462143 -0.233527243137 -v -0.153696537018 1.112774372101 -0.227253794670 -v -0.160377740860 1.100663542747 -0.232878029346 -v -0.155321598053 1.101318359375 -0.229982614517 -v -0.129415988922 1.121230006218 -0.195909500122 -v -0.115429162979 1.119397759438 -0.179361224174 -v -0.130902051926 1.117012500763 -0.191515922546 -v -0.115962266922 1.118604898453 -0.176315546036 -v -0.110272169113 1.120705842972 -0.160776674747 -v -0.113960504532 1.119729280472 -0.159553110600 -v -0.120643854141 1.123042941093 -0.142679691315 -v -0.116504192352 1.124894142151 -0.141778171062 -v -0.116237640381 1.119012355804 -0.159137606621 -v -0.121575117111 1.122238159180 -0.143324553967 -v -0.133432149887 1.123821258545 -0.128500640392 -v -0.129076957703 1.126407384872 -0.125177204609 -v -0.133791923523 1.122404217720 -0.126223802567 -v -0.151261806488 1.118286848068 -0.116750955582 -v -0.150382995605 1.123445391655 -0.118158876896 -v -0.165156841278 1.112223029137 -0.114312648773 -v -0.168798208237 1.119785189629 -0.114506125450 -v -0.146946668625 1.111286401749 -0.115677714348 -v -0.159301757813 1.103829860687 -0.112823069096 -v -0.169470071793 1.095391631126 -0.113259613514 -v -0.176546573639 1.104174375534 -0.116012811661 -v -0.181593179703 1.086678743362 -0.119435906410 -v -0.187299728394 1.095249652863 -0.122014880180 -v -0.192334890366 1.079224348068 -0.132685303688 -v -0.196459770203 1.086544990540 -0.133203148842 -v -0.167187929153 1.093284368515 -0.118592262268 -v -0.158042192459 1.100373268127 -0.117775142193 -v -0.177332639694 1.085744619370 -0.124823093414 -v -0.188689470291 1.078408122063 -0.135257482529 -v -0.133802890778 1.114060878754 -0.127829909325 -v -0.147693157196 1.107499122620 -0.121569573879 -v -0.130974292755 1.116622328758 -0.124757289886 -v -0.118712902069 1.116385936737 -0.142161726952 -v -0.114444732666 1.114831447601 -0.156344830990 -v -0.116871118546 1.115381836891 -0.173745512962 -v -0.127918481827 1.112462520599 -0.189754128456 -v -0.140444517136 1.105615377426 -0.201572239399 -v -0.153226137161 1.096442341805 -0.206420838833 -v -0.166574478149 1.087847948074 -0.204887628555 -v -0.148325681686 1.084455490112 -0.202776551247 -v -0.132059097290 1.095326542854 -0.197568535805 -v -0.118970394135 1.104256153107 -0.183249711990 -v -0.113605022430 1.110781550407 -0.171092212200 -v -0.119467735291 1.110980629921 -0.156059205532 -v -0.118595600128 1.107293367386 -0.167004108429 -v -0.122451543808 1.113593697548 -0.145232379436 -v -0.123160123825 1.101921558380 -0.179320454597 -v -0.134120464325 1.093572258949 -0.190831780434 -v -0.149135828018 1.083696126938 -0.196358323097 -v -0.164771795273 1.075974822044 -0.199542462826 -v -0.178263664246 1.069347739220 -0.194986939430 -v -0.178308486938 1.067918300629 -0.193336069584 -v -0.187574863434 1.061674833298 -0.193846702576 -v -0.165014982224 1.074935913086 -0.195628762245 -v -0.203114748001 1.047059774399 -0.203367710114 -v -0.194963455200 1.055162310600 -0.198111474514 -v -0.211767911911 1.036029338837 -0.208810448647 -v -0.212155818939 1.037373661995 -0.206103205681 -v -0.226508617401 1.025479078293 -0.212446689606 -v -0.223773002625 1.027394175529 -0.209277987480 -v -0.234503984451 1.028979897499 -0.212858796120 -v -0.240490436554 1.019392728806 -0.204267203808 -v -0.244890213013 1.018656373024 -0.196853935719 -v -0.253900766373 1.026709318161 -0.190710783005 -v -0.246401309967 1.020783185959 -0.188246011734 -v -0.252592563629 1.030183553696 -0.180509030819 -v -0.245979547501 1.024557352066 -0.179143786430 -v -0.256746768951 1.027064442635 -0.190641164780 -v -0.255533695221 1.030755162239 -0.181877255440 -v -0.261640310287 1.031444549561 -0.191453814507 -v -0.259487628937 1.033203363419 -0.183249652386 -v -0.265381097794 1.035956144333 -0.193069219589 -v -0.262969732285 1.038062810898 -0.186465203762 -v -0.266802787781 1.033626079559 -0.198642969131 -v -0.266010284424 1.031839489937 -0.204385280609 -v -0.270675420761 1.031339287758 -0.205536782742 -v -0.263313770294 1.031893968582 -0.211139619350 -v -0.266834974289 1.031145095825 -0.212556302547 -v -0.272355556488 1.027421116829 -0.214405179024 -v -0.271020889282 1.027558326721 -0.222151696682 -v -0.277619600296 1.026623606682 -0.207558810711 -v -0.287308216095 1.017905473709 -0.209584236145 -v -0.281747341156 1.017393589020 -0.217522501945 -v -0.290399074554 1.018112540245 -0.206793189049 -v -0.296507358551 1.008396148682 -0.213786959648 -v -0.293893098831 1.008637905121 -0.215864181519 -v -0.293311119080 1.018383622169 -0.204794526100 -v -0.298957824707 1.008759021759 -0.211997389793 -v -0.304624319077 1.000485181808 -0.218563914299 -v -0.302252292633 1.000493049622 -0.219046711922 -v -0.300442457199 1.010485529900 -0.212966322899 -v -0.295816421509 1.020895838737 -0.206146836281 -v -0.304791212082 1.002254843712 -0.220315814018 -v -0.298930644989 1.011639118195 -0.215272247791 -v -0.294509649277 1.021376132965 -0.208923101425 -v -0.305289983749 0.996663510799 -0.231430888176 -v -0.299525260925 1.002564072609 -0.230026721954 -v -0.304598808289 0.995765805244 -0.231520950794 -v -0.298396825790 1.001657962799 -0.230945348740 -v -0.303261518478 0.995977520943 -0.230365991592 -v -0.297660827637 1.000682115555 -0.229683041573 -v -0.297706365585 1.000391125679 -0.228264808655 -v -0.289501190186 1.008563995361 -0.227962017059 -v -0.289624452591 1.008912801743 -0.230370998383 -v -0.289333820343 1.008850455284 -0.225851535797 -v -0.279825210571 1.017765641212 -0.226271927357 -v -0.280007839203 1.018149375916 -0.228962600231 -v -0.279944658279 1.017497062683 -0.223519802094 -v -0.270844221115 1.027772903442 -0.226072430611 -v -0.271415948868 1.028410196304 -0.229272961617 -v -0.265730381012 1.036768198013 -0.229641437531 -v -0.273293256760 1.029914379120 -0.231202602386 -v -0.281020164490 1.019194722176 -0.231097579002 -v -0.275867462158 1.031501293182 -0.230385065079 -v -0.282980203629 1.020815610886 -0.230529665947 -v -0.276958703995 1.032087326050 -0.227720260620 -v -0.283688306808 1.021362662315 -0.227996766567 -v -0.275023937225 1.041705608368 -0.224775314331 -v -0.277465105057 1.049158096313 -0.218947708607 -v -0.292066335678 1.011417031288 -0.228806972504 -v -0.291158199310 1.010475993156 -0.230765581131 -v -0.289323091507 1.031211256981 -0.203581392765 -v -0.290323972702 1.031991720200 -0.200689315796 -v -0.239644289017 1.023190736771 -0.194890260696 -v -0.243260860443 1.023399710655 -0.188031911850 -v -0.234212636948 1.023423552513 -0.201564133167 -v -0.236090183258 1.021491050720 -0.202814877033 -v -0.199890851974 1.066753745079 -0.155146598816 -v -0.198434829712 1.067134857178 -0.156990110874 -v -0.202668666840 1.063336849213 -0.159977316856 -v -0.203597068787 1.063326001167 -0.157728374004 -v -0.194704532623 1.071926832199 -0.149038195610 -v -0.198426008224 1.071671962738 -0.146451592445 -v -0.204805612564 1.071662425995 -0.154704451561 -v -0.202652454376 1.077832579613 -0.147649407387 -v -0.199759483337 1.090992927551 -0.134201765060 -v -0.193034887314 1.103491783142 -0.123884439468 -v -0.185172319412 1.115739107132 -0.117173492908 -v -0.169998168945 1.124291777611 -0.114598035812 -v -0.171854734421 1.130073547363 -0.107446432114 -v -0.148004770279 1.133014440536 -0.109064579010 -v -0.149436950684 1.126783370972 -0.117963194847 -v -0.150363683701 1.141389131546 -0.109232008457 -v -0.129365682602 1.151356697083 -0.121360957623 -v -0.122787952423 1.133342862129 -0.118729412556 -v -0.155005455017 1.151965379715 -0.112209022045 -v -0.138591766357 1.161190986633 -0.122988164425 -v -0.160556554794 1.158395051956 -0.114823222160 -v -0.147845268250 1.166557192802 -0.123666226864 -v -0.164972066879 1.160841345787 -0.116209328175 -v -0.178743362427 1.155038595200 -0.107457756996 -v -0.193982124329 1.154866933823 -0.105260729790 -v -0.203804731369 1.162194013596 -0.107664465904 -v -0.203792333603 1.170711994171 -0.114600837231 -v -0.206958532333 1.165179967880 -0.118471503258 -v -0.199360370636 1.174407482147 -0.126586496830 -v -0.196566343307 1.177967667580 -0.121480822563 -v -0.211217403412 1.155824661255 -0.123464763165 -v -0.203953742981 1.165765166283 -0.134148895741 -v -0.217429161072 1.159095644951 -0.144569456577 -v -0.199710369110 1.170780539513 -0.160428583622 -v -0.189121007919 1.175161838531 -0.143832862377 -v -0.234441280365 1.145398378372 -0.158812522888 -v -0.208461523056 1.159196853638 -0.180670976639 -v -0.252185583115 1.116116285324 -0.170371294022 -v -0.254233121872 1.105154395103 -0.180382847786 -v -0.260434627533 1.096214771271 -0.185628652573 -v -0.256431102753 1.092083334923 -0.177367925644 -v -0.260645627975 1.097700595856 -0.194319903851 -v -0.270902156830 1.083015918732 -0.199528574944 -v -0.269893407822 1.081749439240 -0.189446091652 -v -0.256181478500 1.098464727402 -0.206231713295 -v -0.266798496246 1.083191156387 -0.212066352367 -v -0.273687601089 1.068179607391 -0.216568171978 -v -0.278900146484 1.067694902420 -0.202702641487 -v -0.258903264999 1.083254337311 -0.220462024212 -v -0.247154474258 1.097606897354 -0.216386973858 -v -0.265223979950 1.066669940948 -0.225265324116 -v -0.269017219543 1.059843063354 -0.226757824421 -v -0.277544975281 1.061369776726 -0.218553006649 -v -0.256574153900 1.063487887383 -0.228868722916 -v -0.250155687332 1.081251740456 -0.223481357098 -v -0.261117696762 1.055521845818 -0.231173992157 -v -0.248385906219 1.057556748390 -0.228811144829 -v -0.238748550415 1.076548695564 -0.223608195782 -v -0.234692811966 1.056388735771 -0.223354101181 -v -0.211627244949 1.056368947029 -0.221282124519 -v -0.228275060654 1.091947317123 -0.220990777016 -v -0.238418102264 1.094660639763 -0.219326555729 -v -0.216057777405 1.107417821884 -0.225473523140 -v -0.224503517151 1.109220266342 -0.227116346359 -v -0.211361885071 1.098301529884 -0.220512151718 -v -0.212726354599 1.104912161827 -0.221194267273 -v -0.207950830460 1.100727200508 -0.218157291412 -v -0.203674316406 1.092759370804 -0.219182014465 -v -0.202742576599 1.096199750900 -0.218188643456 -v -0.196501970291 1.090510606766 -0.218953371048 -v -0.196993589401 1.093491673470 -0.220363080502 -v -0.187599182129 1.091245770454 -0.224233686924 -v -0.188641786575 1.095030307770 -0.223733663559 -v -0.186239719391 1.088770151138 -0.220787882805 -v -0.185178756714 1.086016893387 -0.216318964958 -v -0.174246788025 1.087175607681 -0.223291456699 -v -0.165641307831 1.089258909225 -0.227088153362 -v -0.211334466934 1.109454154968 -0.224141299725 -v -0.196863412857 1.116337895393 -0.232053399086 -v -0.198950290680 1.117026805878 -0.234745264053 -v -0.180886983871 1.115268468857 -0.233694016933 -v -0.180615663528 1.115485668182 -0.236742198467 -v -0.177260398865 1.118756055832 -0.240124464035 -v -0.201287984848 1.117602467537 -0.238141715527 -v -0.282895326614 1.060189247131 -0.204914152622 -v -0.282418012619 1.057005047798 -0.194644689560 -v -0.277503967285 1.065804839134 -0.192061483860 -v -0.270702600479 1.064300417900 -0.181479215622 -v -0.276010751724 1.054841160774 -0.184064984322 -v -0.264964342117 1.078153371811 -0.180190920830 -v -0.254631042480 1.068855047226 -0.170619845390 -v -0.259245395660 1.057962894440 -0.174149036407 -v -0.248440742493 1.082378029823 -0.167859196663 -v -0.239177227020 1.074390888214 -0.160453259945 -v -0.243740320206 1.063062429428 -0.160507678986 -v -0.249438762665 1.055111646652 -0.162672996521 -v -0.241800546646 1.051291108131 -0.157198011875 -v -0.245920419693 1.046977758408 -0.160051584244 -v -0.247624635696 1.043250799179 -0.161501169205 -v -0.185623407364 1.163547277451 -0.191922187805 -v -0.178851366043 1.168696165085 -0.170140326023 -v -0.171039104462 1.162240505219 -0.197747766972 -v -0.167164564133 1.171891689301 -0.179815948009 -v -0.169514179230 1.153752446175 -0.212879836559 -v -0.163647174835 1.155890226364 -0.217210114002 -v -0.164894342422 1.163555622101 -0.203335464001 -v -0.162951707840 1.147874236107 -0.221974015236 -v -0.158002376556 1.151909351349 -0.223278760910 -v -0.154706716537 1.144289135933 -0.224242210388 -v -0.152066946030 1.148701906204 -0.224407970905 -v -0.146767616272 1.142306327820 -0.221583485603 -v -0.143728017807 1.146293640137 -0.221992492676 -v -0.138458013535 1.141785860062 -0.215267539024 -v -0.135710000992 1.144933223724 -0.215805530548 -v -0.130891323090 1.143802881241 -0.204370617867 -v -0.129570007324 1.146505594254 -0.206188857555 -v -0.125153064728 1.151684284210 -0.194277405739 -v -0.120690345764 1.156343221664 -0.196658849716 -v -0.123557567596 1.151302337646 -0.207581400871 -v -0.123983860016 1.158541202545 -0.182885527611 -v -0.120908975601 1.161676406860 -0.185635268688 -v -0.127824783325 1.167345404625 -0.175681769848 -v -0.122528076172 1.169641494751 -0.178976297379 -v -0.113455295563 1.165868759155 -0.187700688839 -v -0.108748197556 1.163328170776 -0.198548078537 -v -0.110469579697 1.173360347748 -0.185494899750 -v -0.091323852539 1.179773807526 -0.191483795643 -v -0.090184450150 1.176342606544 -0.194954812527 -v -0.111765384674 1.178711295128 -0.185415387154 -v -0.092939138412 1.184199452400 -0.190637469292 -v -0.113289833069 1.182440042496 -0.187966227531 -v -0.095153093338 1.187181711197 -0.191652655602 -v -0.073956251144 1.192005038261 -0.192678928375 -v -0.073637962341 1.188065290451 -0.191455483437 -v -0.099256277084 1.190625190735 -0.194961786270 -v -0.073813676834 1.195713639259 -0.195692181587 -v -0.096777915955 1.196445703506 -0.206112921238 -v -0.072917699814 1.198483467102 -0.200721621513 -v -0.095563650131 1.196424365044 -0.214924454689 -v -0.071158885956 1.198626756668 -0.206956505775 -v -0.129826784134 1.190738201141 -0.212317109108 -v -0.157343387604 1.172712326050 -0.208674550056 -v -0.128477811813 1.186428785324 -0.221658170223 -v -0.093955516815 1.193287849426 -0.221389353275 -v -0.154647350311 1.168583154678 -0.219737291336 -v -0.149827718735 1.162814021111 -0.225700199604 -v -0.124877214432 1.179793953896 -0.226911485195 -v -0.144460201263 1.156676888466 -0.227152824402 -v -0.120687484741 1.171841144562 -0.228286266327 -v -0.139381647110 1.150594115257 -0.223807334900 -v -0.117116689682 1.165078282356 -0.225237190723 -v -0.128769636154 1.149663209915 -0.217538893223 -v -0.111747980118 1.161472201347 -0.217855334282 -v -0.109767198563 1.161700129509 -0.209116935730 -v -0.088203907013 1.172519445419 -0.211088180542 -v -0.088263034821 1.173820972443 -0.218165874481 -v -0.089234113693 1.173993110657 -0.201246440411 -v -0.071101665497 1.179669737816 -0.199828505516 -v -0.069531917572 1.179702758789 -0.205872833729 -v -0.072219848633 1.181545853615 -0.195242881775 -v -0.056831598282 1.183016300201 -0.193188905716 -v -0.055566310883 1.181527018547 -0.196716129780 -v -0.073021411896 1.184370517731 -0.192374467850 -v -0.057552337646 1.185418963432 -0.190718352795 -v -0.057724237442 1.188611626625 -0.189705491066 -v -0.045343875885 1.186881065369 -0.185175061226 -v -0.045280933380 1.183866500854 -0.186353206635 -v -0.057383060455 1.192056655884 -0.190340936184 -v -0.044640541077 1.190080165863 -0.185317754745 -v -0.056554079056 1.195130228996 -0.192540347576 -v -0.043342113495 1.192810654640 -0.186669468880 -v -0.055220603943 1.197255134583 -0.196023941040 -v -0.053610086441 1.197649002075 -0.200031757355 -v -0.052100419998 1.196197032928 -0.203523576260 -v -0.069370269775 1.196292161942 -0.211897075176 -v -0.068021297455 1.192861676216 -0.214833736420 -v -0.050945520401 1.193327188492 -0.205915927887 -v -0.092361450195 1.188226699829 -0.224879384041 -v -0.090728044510 1.182599067688 -0.225352346897 -v -0.067334413528 1.188707113266 -0.215543806553 -v -0.089248895645 1.177467584610 -0.223018467426 -v -0.067439317703 1.184669256210 -0.214068412781 -v -0.068172216415 1.181514143944 -0.210815250874 -v -0.052105903625 1.183036804199 -0.204133033752 -v -0.050871849060 1.185964107513 -0.206329762936 -v -0.053818464279 1.181404590607 -0.200728774071 -v -0.041506052017 1.180616259575 -0.193893551826 -v -0.039731979370 1.182307600975 -0.196195423603 -v -0.043209075928 1.180416822433 -0.191138744354 -v -0.044537305832 1.181544065475 -0.188471496105 -v -0.031432151794 1.183127760887 -0.177642107010 -v -0.023880004883 1.179421424866 -0.182783424854 -v -0.023120403290 1.181398153305 -0.182788312435 -v -0.038379907608 1.185227513313 -0.197383880615 -v -0.021365642548 1.180629491806 -0.180217981339 -v -0.037654399872 1.188567876816 -0.197493553162 -v -0.037757396698 1.191774725914 -0.196288704872 -v -0.050418376923 1.189674615860 -0.206975281239 -v -0.158075809479 1.171878576279 -0.187048196793 -v -0.184828758240 1.181181192398 -0.133212804794 -v -0.183850765228 1.183899402618 -0.127866744995 -v -0.169936895370 1.187874436378 -0.131015658379 -v -0.160047531128 1.187471389771 -0.131462752819 -v -0.157574653625 1.192477464676 -0.129109740257 -v -0.170529127121 1.193306446075 -0.127960264683 -v -0.157630920410 1.193547725677 -0.127042472363 -v -0.168020248413 1.194449782372 -0.126551985741 -v -0.155678272247 1.197181582451 -0.117395758629 -v -0.168904304504 1.200421571732 -0.116072595119 -v -0.177747726440 1.199375391006 -0.109128236771 -v -0.186355590820 1.196253895760 -0.100548923016 -v -0.188017368317 1.190521001816 -0.119188547134 -v -0.194039821625 1.188312888145 -0.112169504166 -v -0.203054904938 1.179349541664 -0.106702864170 -v -0.192745685577 1.189022660255 -0.093927919865 -v -0.195131540298 1.185600280762 -0.119000375271 -v -0.185272932053 1.190236568451 -0.123825550079 -v -0.202980279922 1.177518606186 -0.111484885216 -v -0.206887245178 1.169745087624 -0.105333983898 -v -0.206416130066 1.174813270569 -0.101252019405 -v -0.199194669724 1.162851572037 -0.099504411221 -v -0.197700738907 1.180861234665 -0.091671824455 -v -0.150561571121 1.174575209618 -0.132039248943 -v -0.209591627121 1.058356404305 -0.160460770130 -v -0.217305183411 1.052603721619 -0.160649895668 -v -0.238281965256 1.033112168312 -0.170957684517 -v -0.244051933289 1.025660991669 -0.180232465267 -v -0.239808082581 1.032481074333 -0.169264376163 -v -0.232315063477 1.036808967590 -0.161297738552 -v -0.230905294418 1.037472367287 -0.163685441017 -v -0.225137472153 1.044082164764 -0.158028185368 -v -0.223443984985 1.044231295586 -0.160395681858 -v -0.223054885864 1.028931379318 -0.207141757011 -v -0.210240125656 1.094408273697 -0.117802858353 -v -0.226145267487 1.091406583786 -0.144528210163 -v -0.228773593903 1.093539595604 -0.144238770008 -v -0.229978561401 1.091392636299 -0.150956988335 -v -0.231330394745 1.094696521759 -0.150297284126 -v -0.228517770767 1.097494721413 -0.144955992699 -v -0.229495048523 1.099721908569 -0.131893873215 -v -0.229601860046 1.105694532394 -0.127975225449 -v -0.230824470520 1.112782955170 -0.126599431038 -v -0.231130123138 1.112404465675 -0.120916366577 -v -0.238191127777 1.121705651283 -0.135489940643 -v -0.240043640137 1.121748328209 -0.132544755936 -v -0.242587566376 1.117125391960 -0.144999742508 -v -0.246487855911 1.119711399078 -0.144290924072 -v -0.241481542587 1.113143205643 -0.153935611248 -v -0.245183229446 1.112014532089 -0.156490027905 -v -0.238260984421 1.105642080307 -0.157133936882 -v -0.240424156189 1.103380203247 -0.159065842628 -v -0.233463764191 1.100573539734 -0.154703736305 -v -0.235453605652 1.097964048386 -0.155216693878 -v -0.235904932022 1.095326662064 -0.155326545238 -v -0.230455398560 1.097877264023 -0.150153517723 -v -0.249421119690 1.121675491333 -0.144378840923 -v -0.240281105042 1.124884128571 -0.131052792072 -v -0.227780818939 1.113982677460 -0.117298245430 -v -0.130397796631 1.182343721390 -0.076600074768 -v -0.129862308502 1.183777570724 -0.072378516197 -v -0.136162042618 1.179548740387 -0.069244503975 -v -0.137062549591 1.183297991753 -0.068274199963 -v -0.133409261703 1.184647083282 -0.072437226772 -v -0.144817352295 1.180659770966 -0.065627694130 -v -0.142683744431 1.184700131416 -0.066475808620 -v -0.271175146103 1.039876699448 -0.190005302429 -v -0.301822423935 1.001146674156 -0.225157797337 -v 0.040446281433 1.266857385635 0.129650652409 -v 0.045840978622 1.267236709595 0.128639698029 -v 0.042178869247 1.272785186768 0.116086125374 -v 0.035976171494 1.262238383293 0.125946938992 -v -0.000801801682 1.292400956154 0.102130472660 -v -0.000761747360 1.303220987320 0.093628942966 -v 0.015448331833 1.314785122871 0.084255039692 -v 0.030528545380 1.315371155739 0.082960784435 -v 0.019721984863 1.301102638245 0.098109424114 -v 0.034617424011 1.303159475327 0.095117151737 -v -0.001373052597 1.277826786041 0.111266195774 -v -0.001722097397 1.284371614456 0.109198451042 -v 0.011536121368 1.282118082047 0.111050844193 -v 0.009827852249 1.276010155678 0.111163258553 -v 0.008899927139 1.272522568703 0.108775258064 -v 0.007982730865 1.269812107086 0.108590006828 -v -0.013120889664 1.280258178711 0.103836178780 -v -0.013952493668 1.287459611893 0.096029043198 -v -0.010375499725 1.274148821831 0.106453537941 -v -0.007061481476 1.270083665848 0.105696380138 -v 0.000071287155 1.273618578911 0.108782231808 -v -0.005353450775 1.267195701599 0.105669260025 -v -0.003715276718 1.265943884850 0.104040384293 -v -0.004131793976 1.253381729126 0.104748189449 -v -0.003669261932 1.256071329117 0.105417490005 -v -0.002878904343 1.257432699203 0.105259358883 -v -0.013543844223 1.267071247101 0.099097788334 -v -0.009968519211 1.265434265137 0.100078165531 -v -0.008393764496 1.263895630836 0.101276814938 -v -0.006794929504 1.262893676758 0.101056635380 -v -0.010854721069 1.252157211304 0.098580598831 -v -0.008997440338 1.255574226379 0.100211143494 -v -0.010912179947 1.258270978928 0.096816718578 -v -0.011093616486 1.261292099953 0.096696496010 -v -0.007898807526 1.257424354553 0.101626813412 -v -0.009550809860 1.259004950523 0.098516225815 -v -0.009840488434 1.260907649994 0.098658919334 -v -0.006556272507 1.258249044418 0.101993978024 -v -0.008103132248 1.259290218353 0.099143624306 -v -0.008106708527 1.260651588440 0.098746120930 -v 0.000634908676 1.269962787628 0.108458042145 -v 0.001318454742 1.268399953842 0.106259763241 -v 0.007476329803 1.268658280373 0.106844902039 -v 0.003443002701 1.252889513969 0.108284533024 -v 0.002853155136 1.255975246429 0.108673334122 -v 0.002923965454 1.257455945015 0.107795357704 -v 0.011467933655 1.255045294762 0.108669996262 -v 0.009955406189 1.257626056671 0.108927190304 -v 0.009441614151 1.258421897888 0.107399821281 -v 0.014464855194 1.289756536484 0.104732036591 -v 0.025943517685 1.283508300781 0.107297778130 -v 0.039303779602 1.279110550880 0.106710374355 -v 0.036115169525 1.278290748596 0.107457518578 -v 0.042536735535 1.278733968735 0.105807304382 -v 0.030768871307 1.288198709488 0.104064941406 -v 0.037350654602 1.289890766144 0.102047562599 -v 0.032482862473 1.275633811951 0.108351588249 -v 0.028729915619 1.263514757156 0.113653242588 -v 0.018857955933 1.271643638611 0.108702600002 -v 0.016063928604 1.269024133682 0.106653332710 -v 0.028270483017 1.270699024200 0.108028233051 -v 0.022220373154 1.277044057846 0.110479056835 -v 0.019372463226 1.258092880249 0.110031247139 -v 0.023556232452 1.262869477272 0.107618689537 -v 0.035057067871 1.268901348114 0.115687489510 -v 0.039037466049 1.272062182426 0.116605579853 -v 0.014039754868 1.267450094223 0.106931269169 -v 0.012716054916 1.266707539558 0.106147646904 -v 0.017132282257 1.259011745453 0.106750369072 -v 0.020047903061 1.262408375740 0.104903697968 -v 0.019694805145 1.265416860580 0.105079472065 -v 0.017275571823 1.264821529388 0.105033516884 -v 0.017734289169 1.262517094612 0.104454278946 -v 0.015003919601 1.260491371155 0.107061386108 -v 0.015677213669 1.264597892761 0.104555845261 -v 0.016396999359 1.262519359589 0.103408336639 -v 0.014380216599 1.260196924210 0.104527294636 -v 0.023535966873 1.267078399658 0.106167256832 -v -0.012151002884 1.235135316849 0.109545886517 -v -0.016305923462 1.224170684814 0.110445380211 -v -0.010377168655 1.200674295425 0.124419331551 -v -0.006423950195 1.185832023621 0.138172209263 -v -0.010899543762 1.192893743515 0.129531621933 -v -0.017629623413 1.210340738297 0.107257723808 -v -0.026541233063 1.185374736786 0.118990361691 -v -0.022340297699 1.197549104691 0.109548330307 -v 0.035350084305 1.248472332954 0.142883300781 -v 0.051932334900 1.253603696823 0.148347139359 -v 0.041118383408 1.258031487465 0.142182707787 -v 0.049641847610 1.260149955750 0.141103088856 -v 0.044825792313 1.252733945847 0.148908674717 -v 0.042319774628 1.246564269066 0.148949384689 -v 0.041991710663 1.241669535637 0.144866228104 -v 0.052286386490 1.246867418289 0.148005247116 -v 0.051711082458 1.241842269897 0.144327402115 -v 0.035593986511 1.255735874176 0.134251892567 -v 0.029677391052 1.244845509529 0.136716425419 -v 0.033319473267 1.250971555710 0.137745916843 -v 0.031243801117 1.242845058441 0.136967241764 -v 0.030688762665 1.256210803986 0.122289538383 -v 0.030338525772 1.250825643539 0.129136621952 -v 0.028740406036 1.247478961945 0.134274959564 -v 0.033815860748 1.242522120476 0.134662628174 -v 0.036343336105 1.243577361107 0.131516873837 -v 0.035639047623 1.243583917618 0.141259193420 -v 0.038025856018 1.243572592735 0.136724710464 -v 0.038744688034 1.229243755341 0.136170148849 -v 0.024222373962 1.241967678070 0.129807054996 -v 0.026626348495 1.240379929543 0.132212758064 -v 0.025287628174 1.233862161636 0.128705739975 -v 0.029455423355 1.240218400955 0.133426547050 -v 0.032053232193 1.237096786499 0.129116058350 -v 0.032113552094 1.241108894348 0.132747650146 -v 0.035292625427 1.241956233978 0.129371285439 -v 0.030912876129 1.229870319366 0.131015717983 -v 0.030648946762 1.224499464035 0.134449362755 -v 0.044306993484 1.238245844841 0.135809302330 -v 0.043252468109 1.240461349487 0.139098584652 -v 0.042135715485 1.240919113159 0.133995532990 -v 0.041716814041 1.241783857346 0.135482788086 -v 0.039429187775 1.243738889694 0.133056044579 -v 0.050420999527 1.240142822266 0.139068543911 -v 0.044756889343 1.234812498093 0.136098802090 -v 0.045078516006 1.231711387634 0.137417495251 -v 0.049524068832 1.238426923752 0.135339796543 -v 0.049675464630 1.235311508179 0.135039925575 -v 0.049990892410 1.232141256332 0.135455429554 -v 0.050583839417 1.228020906448 0.136361002922 -v 0.039813756943 1.238145470619 0.129698514938 -v 0.039825677872 1.242085576057 0.130345582962 -v 0.038737535477 1.233376264572 0.133297681808 -v 0.021462440491 1.217258930206 0.132264912128 -v 0.022056579590 1.212752580643 0.133517026901 -v 0.018235683441 1.205214858055 0.139099240303 -v 0.020352602005 1.209083795547 0.136137485504 -v 0.026568651199 1.202765941620 0.148095548153 -v 0.023966073990 1.192803263664 0.152344107628 -v 0.016592502594 1.199261784554 0.141214609146 -v 0.012834787369 1.191551685333 0.144409120083 -v 0.037743806839 1.215576529503 0.149055123329 -v 0.045881509781 1.225828409195 0.145537972450 -v 0.052435159683 1.227740526199 0.144624948502 -v 0.046445846558 1.218936204910 0.150274634361 -v 0.053923368454 1.220834851265 0.149113297462 -v 0.037250757217 1.206232309341 0.152749001980 -v 0.035874843597 1.194463729858 0.157640993595 -v 0.046791553497 1.196104288101 0.159853577614 -v 0.056510210037 1.197567701340 0.158931136131 -v 0.046874284744 1.208952426910 0.154512763023 -v 0.055248498917 1.210875630379 0.153577446938 -v 0.029203891754 1.216282963753 0.141427814960 -v 0.038281440735 1.222136378288 0.144550740719 -v 0.039469957352 1.224807739258 0.138187825680 -v 0.027691841125 1.210708260536 0.145226716995 -v 0.031136751175 1.219664812088 0.136600375175 -v 0.045809268951 1.227646589279 0.138405919075 -v 0.014129638672 1.249409794807 0.115332782269 -v 0.012882471085 1.252357363701 0.110826134682 -v 0.003088235855 1.244774341583 0.113203525543 -v 0.015806198120 1.243852615356 0.119367957115 -v 0.002343654633 1.237422823906 0.117558121681 -v 0.001748561859 1.226236939430 0.122058868408 -v 0.018728971481 1.236750602722 0.120574116707 -v 0.013330936432 1.222983598709 0.124980926514 -v 0.020515918732 1.223115921021 0.129145741463 -v -0.008113384247 1.243763685226 0.107061862946 -v -0.005330562592 1.249330997467 0.104984104633 -v 0.003616333008 1.249160528183 0.109515726566 -v 0.024304866791 1.250104308128 0.120198249817 -v 0.023406744003 1.245513081551 0.126008749008 -v 0.022205352783 1.255663037300 0.115017294884 -v 0.022286176682 1.233654975891 0.123781740665 -v 0.005661487579 1.202055335045 0.129107356071 -v -0.006587982178 1.211276650429 0.122517585754 -v 0.004577875137 1.210666298866 0.126435041428 -v 0.000176429749 1.201238393784 0.127685189247 -v 0.010596990585 1.210288167000 0.128963351250 -v 0.011595726013 1.201239705086 0.133424997330 -v 0.008545637131 1.200110793114 0.130007266998 -v 0.008605241776 1.202653884888 0.129701614380 -v 0.013861179352 1.203346967697 0.131477773190 -v 0.010287761688 1.201593160629 0.130020737648 -v 0.010378360748 1.202918767929 0.129963099957 -v 0.013339757919 1.208619117737 0.130371451378 -v 0.014328479767 1.206321358681 0.130973219872 -v 0.004492282867 1.192520976067 0.136268198490 -v 0.005780458450 1.198042392731 0.130144894123 -v 0.000226497650 1.195833086967 0.130556583405 -v 0.009120702744 1.197683811188 0.134836256504 -v -0.030488014221 1.283267021179 0.061819374561 -v -0.020040273666 1.274581432343 0.086394488811 -v -0.024308919907 1.279701232910 0.074724912643 -v -0.023217916489 1.261051177979 0.081465482712 -v -0.028754949570 1.261417388916 0.070602059364 -v -0.036482095718 1.283128738403 0.047661483288 -v -0.035109758377 1.260555624962 0.058661758900 -v -0.041009902954 1.257912158966 0.046594083309 -v -0.021064043045 1.302900314331 0.072026371956 -v -0.003322601318 1.312586545944 0.080484449863 -v -0.016522645950 1.296046495438 0.085470199585 -v -0.025208473206 1.303212285042 0.054149925709 -v -0.007358551025 1.313477158546 0.060375809669 -v 0.010043859482 1.317523241043 0.063381493092 -v 0.024682044983 1.319341421127 0.062246799469 -v -0.017404079437 1.270059585571 0.095172524452 -v -0.018391847610 1.253546833992 0.091046571732 -v -0.013947963715 1.256553530693 0.094790697098 -v -0.014717340469 1.261037349701 0.094909310341 -v -0.018908500671 1.260896086693 0.090010643005 -v -0.020776271820 1.238931417465 0.095742464066 -v -0.023503780365 1.249016761780 0.084496319294 -v -0.025747776031 1.229195833206 0.091487228870 -v -0.028454780579 1.243663668633 0.075471043587 -v -0.028841972351 1.217222690582 0.085641384125 -v -0.036760330200 1.200345516205 0.081055641174 -v -0.043103218079 1.175856351852 0.098108768463 -v -0.034443616867 1.237311244011 0.066220164299 -v -0.040151596069 1.230180382729 0.055966675282 -v -0.047009706497 1.225324869156 0.042491793633 -v -0.047743082047 1.194535493851 0.058303952217 -v -0.054014205933 1.190686464310 0.040780961514 -v -0.015044689178 1.246884107590 0.097714483738 -v 0.051012039185 1.267523407936 0.126842677593 -v 0.053725004196 1.263754844666 0.121200740337 -v 0.044191360474 1.316711425781 0.076770126820 -v 0.049160242081 1.303004741669 0.090367913246 -v 0.070050954819 1.296021223068 0.083691716194 -v 0.064377546310 1.307411193848 0.076644003391 -v 0.044227600098 1.289105176926 0.100519239902 -v 0.046434164047 1.276561975479 0.104707181454 -v 0.050604581833 1.285138130188 0.100853264332 -v 0.058474540710 1.292474508286 0.093251526356 -v 0.065127134323 1.284862875938 0.097177326679 -v 0.048618316650 1.269841313362 0.112119197845 -v 0.045237541199 1.272487878799 0.114981353283 -v 0.053706645966 1.265324115753 0.107027411461 -v 0.050548315048 1.272162795067 0.102230787277 -v 0.056096792221 1.279160976410 0.101499915123 -v 0.055377244949 1.264985799789 0.099373936653 -v 0.058884382248 1.273606300354 0.098348557949 -v 0.060819864273 1.270249724388 0.095299720764 -v 0.067456960678 1.278015136719 0.096721053123 -v 0.067724943161 1.273309826851 0.094431757927 -v 0.068783521652 1.270277500153 0.094106316566 -v 0.060762882233 1.261790990829 0.099568009377 -v 0.054175376892 1.268918275833 0.098160982132 -v 0.062816143036 1.268297910690 0.094869017601 -v 0.063694953918 1.267551422119 0.093782484531 -v 0.068581581116 1.269197702408 0.092460989952 -v 0.061268568039 1.263207793236 0.095967531204 -v 0.057333707809 1.264688968658 0.095514893532 -v 0.057271957397 1.267230391502 0.095370531082 -v 0.059454441071 1.266519188881 0.094323635101 -v 0.059153795242 1.264902830124 0.094141185284 -v 0.062749862671 1.265080451965 0.095315635204 -v 0.060599803925 1.266317009926 0.093307375908 -v 0.059796094894 1.264950871468 0.092611730099 -v 0.062308549881 1.264286756516 0.092826724052 -v 0.067521333694 1.262562036514 0.095242917538 -v 0.068541765213 1.265034556389 0.094969451427 -v 0.068204641342 1.265207529068 0.093506395817 -v 0.077112913132 1.279425144196 0.091373026371 -v 0.075383424759 1.286835432053 0.089299082756 -v 0.082441329956 1.283947467804 0.079257071018 -v 0.078902959824 1.292372465134 0.071949005127 -v 0.075701475143 1.271097064018 0.090313911438 -v 0.074272155762 1.269963860512 0.088880062103 -v 0.080384016037 1.272943258286 0.083734631538 -v 0.075593948364 1.274363636971 0.090127468109 -v 0.079707145691 1.270199537277 0.084501504898 -v 0.077773094177 1.269171714783 0.084009110928 -v 0.074470520020 1.262153863907 0.091184914112 -v 0.074804306030 1.264805197716 0.091423273087 -v 0.074141263962 1.265561819077 0.090759217739 -v 0.079296112061 1.262190818787 0.084158301353 -v 0.078951358795 1.264721870422 0.085185348988 -v 0.078058242798 1.265552878380 0.085563898087 -v 0.080155134201 1.268244743347 0.078729867935 -v 0.078858852386 1.267360806465 0.079410076141 -v 0.080429077148 1.264863848686 0.079188346863 -v 0.080001354218 1.264985084534 0.075401127338 -v 0.080117464066 1.266297817230 0.075324594975 -v 0.079468488693 1.265514373779 0.080408871174 -v 0.079141855240 1.265153050423 0.076866209507 -v 0.078771829605 1.266029000282 0.076456785202 -v 0.082354784012 1.277361154556 0.082759082317 -v 0.082641601563 1.272576570511 0.074128508568 -v 0.080540895462 1.270089030266 0.076882600784 -v 0.081943511963 1.258766055107 0.074625015259 -v 0.080802440643 1.262812852859 0.077187001705 -v 0.080394029617 1.264332532883 0.073039591312 -v 0.080169439316 1.266933917999 0.072909772396 -v 0.057654857635 1.259309649467 0.137847244740 -v 0.058503150940 1.253966927528 0.145442008972 -v 0.064238071442 1.251279354095 0.135221183300 -v 0.061223030090 1.248335599899 0.143793106079 -v 0.060226678848 1.243742227554 0.139886677265 -v 0.058931112289 1.258131980896 0.127938270569 -v 0.063202142715 1.254297494888 0.129694104195 -v 0.065549135208 1.247506380081 0.127456486225 -v 0.057339906693 1.259414553642 0.114988744259 -v 0.062293052673 1.246687650681 0.126744151115 -v 0.058286666870 1.246920347214 0.125443816185 -v 0.066583871841 1.249766945839 0.126530528069 -v 0.061671018600 1.255462884903 0.120306611061 -v 0.065866470337 1.252713918686 0.123935759068 -v 0.054228067398 1.239598989487 0.133096814156 -v 0.056482315063 1.242153167725 0.135511994362 -v 0.054856777191 1.242565155029 0.130528688431 -v 0.055840969086 1.243560433388 0.131651639938 -v 0.056303262711 1.246041178703 0.128419876099 -v 0.063732147217 1.246660113335 0.133645892143 -v 0.059375524521 1.246311187744 0.130905628204 -v 0.054415225983 1.236288070679 0.133475065231 -v 0.055111885071 1.233415126801 0.134682297707 -v 0.059905767441 1.232897996902 0.130329132080 -v 0.055068492889 1.240468859673 0.125481486320 -v 0.054852485657 1.244311332703 0.126182913780 -v 0.061526775360 1.241811394691 0.120923161507 -v 0.062999248505 1.245989322662 0.124036252499 -v 0.058302879333 1.245635032654 0.122877240181 -v 0.058226346970 1.236359000206 0.127980589867 -v 0.068130016327 1.248301506042 0.117564380169 -v 0.067496299744 1.246428251266 0.120817005634 -v 0.067075014114 1.240431427956 0.117183685303 -v 0.065690279007 1.245734214783 0.123227000237 -v 0.063593864441 1.235562324524 0.122017323971 -v 0.065532922745 1.231557369232 0.124712467194 -v 0.058642148972 1.228264093399 0.141964733601 -v 0.060995340347 1.221785545349 0.146217465401 -v 0.067803859711 1.221554160118 0.140724539757 -v 0.065596818924 1.198537349701 0.155037641525 -v 0.063088893890 1.211889743805 0.150147914886 -v 0.070540428162 1.212059378624 0.143783211708 -v 0.074363708496 1.199054241180 0.147871077061 -v 0.055469512939 1.229463577271 0.135724365711 -v 0.064706325531 1.227428913116 0.137217521667 -v 0.060773849487 1.229086875916 0.132322847843 -v 0.070334196091 1.226015686989 0.129881024361 -v 0.073707818985 1.221224188805 0.132331371307 -v 0.066503286362 1.228003025055 0.126726925373 -v 0.071586132050 1.228841543198 0.118208587170 -v 0.071873664856 1.225707650185 0.119430422783 -v 0.077915668488 1.220404744148 0.122084975243 -v 0.074536085129 1.223444819450 0.120662927628 -v 0.076755285263 1.212785243988 0.134442687035 -v 0.081811666489 1.200371980667 0.137430131435 -v 0.080988883972 1.214165449142 0.123166322708 -v 0.086687803268 1.203819513321 0.124526441097 -v 0.062492609024 1.254801988602 0.109791696072 -v 0.066610813141 1.251634597778 0.113950848579 -v 0.061021566391 1.259107947350 0.104773223400 -v 0.068827152252 1.254087090492 0.101265370846 -v 0.067484378815 1.258732795715 0.097137033939 -v 0.069918870926 1.248601675034 0.105034232140 -v 0.067322969437 1.240279912949 0.111719012260 -v 0.068537473679 1.242500543594 0.107286572456 -v 0.075018405914 1.232970237732 0.108255088329 -v 0.070877790451 1.232767581940 0.115252256393 -v 0.077867746353 1.249896764755 0.094340682030 -v 0.081087350845 1.242408514023 0.097182273865 -v 0.083758115768 1.234669685364 0.100204110146 -v 0.075211763382 1.256941318512 0.091831862926 -v 0.080814123154 1.256867170334 0.083383440971 -v 0.084712028503 1.249413847923 0.083412945271 -v 0.090125322342 1.240862131119 0.083279728889 -v 0.094750881195 1.231421947479 0.081762373447 -v 0.077249050140 1.224474191666 0.112283647060 -v 0.076828718185 1.222699880600 0.113141000271 -v 0.078745365143 1.225707769394 0.109818100929 -v 0.080643415451 1.218926310539 0.113611519337 -v 0.081604242325 1.218360304832 0.109059333801 -v 0.081132650375 1.220607519150 0.109011828899 -v 0.077664852142 1.220381379128 0.113147377968 -v 0.080033540726 1.219517707825 0.110023081303 -v 0.079794406891 1.220654487610 0.110094487667 -v 0.083391666412 1.220073938370 0.107060670853 -v 0.082854270935 1.225638270378 0.104710161686 -v 0.087911605835 1.218507766724 0.103260695934 -v 0.091594696045 1.224019408226 0.096191704273 -v 0.096889257431 1.214898347855 0.095897138119 -v 0.083808422089 1.215420007706 0.113558650017 -v 0.089332103729 1.208635091782 0.112731575966 -v 0.084277868271 1.216469287872 0.107762217522 -v 0.089827299118 1.213289976120 0.105555117130 -v 0.101368904114 1.198026537895 0.110524892807 -v 0.100582122803 1.206828474998 0.100248575211 -v 0.095614671707 1.219149708748 0.078378736973 -v 0.110302448273 1.196131229401 0.085673749447 -v 0.101401090622 1.207566261292 0.078618407249 -v 0.038086652756 1.319437146187 0.056139290333 -v 0.058758258820 1.316738009453 0.064338445663 -v 0.052024126053 1.317465305328 0.045089304447 -v 0.071031332016 1.309057235718 0.048146665096 -v 0.074790716171 1.301920175552 0.061692059040 -v 0.065555095673 1.309342384338 0.030936956406 -v 0.076519966125 1.290452003479 0.034301042557 -v 0.081107854843 1.281051397324 0.059998869896 -v 0.083610057831 1.276207208633 0.068830192089 -v 0.084535121918 1.260300159454 0.064144432545 -v 0.082194328308 1.262906312943 0.069637179375 -v 0.082393407822 1.267321228981 0.069480359554 -v 0.083597660065 1.267654538155 0.063186764717 -v 0.078208923340 1.286485910416 0.048090279102 -v 0.083045482635 1.268104314804 0.053750872612 -v 0.082231521606 1.268839240074 0.041879594326 -v 0.074455499649 1.290663003922 0.019667565823 -v 0.081685543060 1.268450379372 0.028919160366 -v 0.080770254135 1.266295671463 0.016477346420 -v 0.085688114166 1.253255128860 0.071567714214 -v 0.090450763702 1.245868682861 0.066874861717 -v 0.086171150208 1.256250977516 0.055930197239 -v 0.086350440979 1.251328825951 0.045859992504 -v 0.093620538712 1.236952662468 0.060706198215 -v 0.094166755676 1.225640654564 0.054646670818 -v 0.099492788315 1.210208415985 0.048777282238 -v 0.114588975906 1.187431573868 0.062622427940 -v 0.087287187576 1.245572805405 0.035482227802 -v 0.087604761124 1.239173889160 0.025138556957 -v 0.087361097336 1.235268592834 0.012534439564 -v 0.098117351532 1.205789446831 0.027765154839 -v 0.095893383026 1.203208208084 0.014717459679 -v -0.011510133743 1.163360238075 0.149067997932 -v -0.004560947418 1.134804606438 0.155196785927 -v -0.023927450180 1.173175573349 0.133506655693 -v -0.025471687317 1.141367435455 0.137405753136 -v 0.017634153366 1.178678154945 0.157647490501 -v 0.025628328323 1.157846570015 0.168135166168 -v 0.003703117371 1.180795431137 0.148849606514 -v 0.006724596024 1.158563613892 0.161044716835 -v 0.032204389572 1.178767085075 0.163424730301 -v 0.045523643494 1.179651737213 0.165940761566 -v 0.057294130325 1.180637598038 0.164849698544 -v 0.042539596558 1.158673048019 0.171049177647 -v 0.056924104691 1.159794092178 0.170381605625 -v 0.017149686813 1.133303642273 0.166976332664 -v 0.037201642990 1.133634090424 0.172211468220 -v 0.054214477539 1.134839653969 0.171566545963 -v -0.010805606842 1.115299701691 0.134994447231 -v -0.012533187866 1.105522513390 0.110044121742 -v 0.010537385941 1.112756729126 0.149111986160 -v 0.047211885452 1.112629652023 0.157582700253 -v 0.030074119568 1.112287878990 0.156457722187 -v 0.006142139435 1.103373646736 0.121430158615 -v 0.022053003311 1.103733062744 0.127525568008 -v 0.036193370819 1.104734897614 0.128820121288 -v -0.040673494339 1.155994772911 0.117093861103 -v -0.049955368042 1.141332268715 0.095714688301 -v -0.032525300980 1.123396158218 0.116316258907 -v -0.032552003860 1.114442110062 0.094371557236 -v -0.031067371368 1.110062003136 0.075444519520 -v -0.052037954330 1.167015790939 0.075356423855 -v -0.056231737137 1.161347627640 0.056636929512 -v -0.059476852417 1.156821727753 0.039392709732 -v -0.059850692749 1.140776157379 0.039435088634 -v -0.061575651169 1.141006946564 0.028368413448 -v -0.050864934921 1.133266210556 0.076295912266 -v -0.056070089340 1.117838740349 0.039700746536 -v -0.049790382385 1.128654956818 0.061231255531 -v -0.052109718323 1.122534751892 0.050932705402 -v -0.034054994583 1.104509353638 0.060616970062 -v -0.043396234512 1.096928238869 0.048614859581 -v -0.048959255219 1.091627120972 0.033554553986 -v -0.056957721710 1.112890362740 0.023788034916 -v -0.035567522049 1.043387889862 0.047449171543 -v -0.039433956146 1.039121747017 0.052413821220 -v -0.064744234085 1.050780534744 0.014951646328 -v -0.038980245590 1.074284434319 0.043637633324 -v -0.041082859039 1.069077014923 0.029278635979 -v -0.034406661987 1.055065155029 0.043360531330 -v -0.047071218491 1.085974812508 0.015686988831 -v -0.049998521805 1.061222076416 0.019102632999 -v -0.053887367249 1.043840646744 0.036689996719 -v -0.042478322983 1.050164461136 0.036054790020 -v -0.014271974564 1.099223375320 0.086969316006 -v 0.000830411911 1.094314455986 0.095309138298 -v -0.019607543945 1.090406298637 0.068407773972 -v -0.029613494873 1.080608129501 0.054361045361 -v -0.005763530731 1.081238627434 0.073860049248 -v -0.027546405792 1.059183478355 0.053171813488 -v -0.013939142227 1.067626953125 0.057299792767 -v 0.014307975769 1.093263268471 0.099898755550 -v 0.027014970779 1.094081640244 0.101382076740 -v 0.021053075790 1.074604153633 0.082123875618 -v 0.007202863693 1.075435996056 0.078675389290 -v -0.027371644974 1.043602824211 0.054658472538 -v -0.017439126968 1.044979572296 0.062561631203 -v -0.024429798126 1.035316348076 0.064470529556 -v -0.010132312775 1.032010316849 0.071531534195 -v 0.004372358322 1.030398845673 0.073763489723 -v 0.017338514328 1.031093001366 0.076553463936 -v 0.000297546387 1.051457285881 0.063539087772 -v 0.017464637756 1.050814867020 0.071853816509 -v 0.068420410156 1.181527853012 0.160425603390 -v 0.079635143280 1.182518243790 0.152125537395 -v 0.070542097092 1.160900115967 0.164953768253 -v 0.085201978683 1.162357091904 0.154878497124 -v 0.090045928955 1.184562206268 0.140001475811 -v 0.098061561584 1.189689755440 0.125387966633 -v 0.099827289581 1.165438413620 0.139908611774 -v 0.070614814758 1.136290311813 0.165854871273 -v 0.088030338287 1.138740301132 0.153091609478 -v 0.104446411133 1.143034815788 0.133147954941 -v 0.097229003906 1.124236106873 0.117044687271 -v 0.083167791367 1.114722371101 0.099347352982 -v 0.111231565475 1.172423601151 0.120619416237 -v 0.114904880524 1.183718919754 0.100513756275 -v 0.116925716400 1.151993751526 0.107569992542 -v 0.063422679901 1.115132212639 0.151529729366 -v 0.080619335175 1.118611931801 0.138225674629 -v 0.050387620926 1.106717824936 0.125205457211 -v 0.066112041473 1.109486579895 0.115795731544 -v 0.086173295975 1.122708439827 0.068399488926 -v 0.080250263214 1.118033289909 0.063007235527 -v 0.082655668259 1.112149238586 0.061163365841 -v 0.121577978134 1.167878985405 0.081856548786 -v 0.119044303894 1.154315471649 0.063807129860 -v 0.111441612244 1.134985923767 0.090731918812 -v 0.098887205124 1.126488447189 0.077325224876 -v 0.111427545547 1.179712891579 0.043127000332 -v 0.106110334396 1.175122380257 0.031305313110 -v 0.102075576782 1.172155618668 0.024685502052 -v 0.102116584778 1.157317161560 0.033418297768 -v 0.101032018661 1.158340215683 0.029302597046 -v 0.100531339645 1.143308043480 0.048263728619 -v 0.097441434860 1.138330459595 0.048066020012 -v 0.109502553940 1.146957397461 0.052747786045 -v 0.096754789352 1.134839057922 0.047012090683 -v 0.085198402405 1.107511401176 0.055232167244 -v 0.094857692719 1.130478262901 0.041637301445 -v 0.040197134018 1.096347808838 0.099944472313 -v 0.054687500000 1.100618243217 0.094639301300 -v 0.048788309097 1.088074207306 0.078770637512 -v 0.035143613815 1.078818082809 0.081493318081 -v 0.048858642578 1.075313687325 0.068564772606 -v 0.070461988449 1.108810186386 0.084021329880 -v 0.064486742020 1.100866556168 0.073438167572 -v 0.065836668015 1.092562913895 0.068579912186 -v 0.060715675354 1.069221019745 0.070371031761 -v 0.030231714249 1.033327579498 0.078828334808 -v 0.035176753998 1.055608034134 0.070235610008 -v 0.043811559677 1.038117885590 0.082073748112 -v 0.050953388214 1.052722811699 0.075931191444 -v 0.063144207001 1.053842663765 0.072386682034 -v 0.073226213455 1.055658340454 0.068940043449 -v 0.075714349747 1.052077531815 0.075281441212 -v 0.058623790741 1.044714212418 0.080729842186 -v 0.072857141495 1.087235689163 0.064580619335 -v 0.071193933487 1.066993713379 0.064158737659 -v 0.079437494278 1.082699298859 0.053134381771 -v 0.086660146713 1.101273775101 0.041690945625 -v 0.092396974564 1.077137112617 0.048476576805 -v 0.108497619629 1.069890260696 0.052235901356 -v 0.082067012787 1.064140319824 0.061126887798 -v 0.093047380447 1.060159802437 0.067036211491 -v -0.040343284607 1.237436652184 -0.032936990261 -v -0.052459239960 1.221552133560 0.028179645538 -v -0.056158065796 1.218947887421 0.012705385685 -v -0.055384397507 1.217468619347 -0.008952379227 -v -0.058702945709 1.188291907310 0.024425923824 -v -0.061626672745 1.162003040314 0.018809258938 -v -0.061149597168 1.186267733574 0.006660997868 -v -0.059507608414 1.179691553116 -0.010669171810 -v -0.055477380753 1.198352456093 -0.021095275879 -v -0.052834749222 1.169609308243 -0.030598759651 -v -0.042055368423 1.195482850075 -0.042439877987 -v -0.019744396210 1.243911266327 -0.053574860096 -v 0.005693435669 1.249059438705 -0.062779784203 -v -0.040396451950 1.167162179947 -0.069658398628 -v -0.015247583389 1.206512212753 -0.057519495487 -v 0.014311552048 1.212281465530 -0.062326133251 -v -0.013623714447 1.176701664925 -0.078638434410 -v 0.025074958801 1.182491421700 -0.078897595406 -v 0.055553436279 1.246190905571 -0.042324364185 -v 0.072591066360 1.207378625870 -0.039697229862 -v 0.085914134979 1.232458949089 0.001026153564 -v 0.083698034286 1.230814695358 -0.009619951248 -v 0.077988386154 1.229747176170 -0.023236691952 -v 0.094089031219 1.202184319496 0.005038857460 -v 0.098302841187 1.178545475006 0.013474762440 -v 0.091052532196 1.195588827133 -0.011169850826 -v 0.092413902283 1.201389551163 -0.004166901112 -v 0.082178831100 1.212141036987 -0.025714099407 -v 0.089784622192 1.185250520706 -0.019735872746 -v 0.032395839691 1.248675107956 -0.057501971722 -v 0.044507265091 1.212738394737 -0.056064784527 -v 0.063519954681 1.185031294823 -0.068458735943 -v 0.090191364288 1.181271433830 -0.050654113293 -v -0.059590101242 1.158144712448 0.001819372177 -v -0.060241460800 1.136449337006 0.012746274471 -v -0.055771827698 1.128415822983 -0.007795572281 -v -0.056196689606 1.149477005005 -0.018423438072 -v -0.059613704681 1.094871759415 -0.017021775246 -v -0.052507877350 1.106217026711 0.003190934658 -v -0.061356782913 1.135336041451 -0.044591844082 -v -0.055210590363 1.152688622475 -0.057234942913 -v -0.061703920364 1.115628957748 -0.031736850739 -v -0.076354265213 1.118670940399 -0.068626523018 -v -0.078945398331 1.100923299789 -0.053504228592 -v -0.072272777557 1.063135385513 -0.010518550873 -v -0.077728748322 1.081091284752 -0.034207820892 -v -0.055848836899 1.076079010963 0.000701248646 -v -0.070124626160 1.134061932564 -0.082705259323 -v -0.052391529083 1.145668983459 -0.097816407681 -v -0.014596939087 1.152688741684 -0.108650863171 -v 0.038563251495 1.158075928688 -0.105544686317 -v 0.095056056976 1.175324201584 0.007279813290 -v 0.097741365433 1.154363512993 0.024574756622 -v 0.096329450607 1.145889043808 0.014402627945 -v 0.095551252365 1.166598796844 -0.001544177532 -v 0.092842340469 1.122950792313 0.029080450535 -v 0.106817960739 1.113699555397 0.016706228256 -v 0.110495090485 1.154946565628 -0.013335943222 -v 0.104727029800 1.170523405075 -0.031004786491 -v 0.110179185867 1.135258436203 0.001379370689 -v 0.134946107864 1.143305301666 -0.026512145996 -v 0.134920597076 1.125534772873 -0.009499669075 -v 0.100990295410 1.093693971634 0.033296287060 -v 0.121155023575 1.084573626518 0.031806349754 -v 0.130618572235 1.104586720467 0.010483145714 -v 0.088234901428 1.164701461792 -0.088147342205 -v 0.131562232971 1.157645463943 -0.042793512344 -v 0.118981122971 1.165749549866 -0.063742041588 -v 0.061493158340 1.307609081268 0.082881748676 -v 0.060327529907 1.318495154381 0.079182028770 -v 0.072385311127 1.317370176315 0.066087126732 -v 0.075205326080 1.306590318680 0.068933367729 -v 0.076874732971 1.311258077621 0.048126757145 -v 0.079223632813 1.301067113876 0.051980793476 -v 0.079833984375 1.300073146820 0.031079173088 -v 0.080294847488 1.289757966995 0.038935780525 -v 0.084419488907 1.282017230988 0.020341932774 -v 0.084472656250 1.274614810944 0.031600832939 -v 0.089787960052 1.257214426994 0.028529644012 -v 0.093410491943 1.257125258446 0.016011953354 -v 0.093643188477 1.237569332123 0.028812587261 -v 0.099745988846 1.236010193825 0.015180408955 -v 0.101211547852 1.209712862968 0.029784440994 -v 0.105703353882 1.216141939163 0.016078948975 -v 0.107604503632 1.206364512444 0.004519283772 -v 0.106831312180 1.196551799774 0.008540511131 -v 0.103477239609 1.200936555862 -0.016821682453 -v 0.102436780930 1.189777612686 -0.016660988331 -v 0.094894409180 1.201877832413 -0.033474504948 -v 0.091467142105 1.192241907120 -0.033644795418 -v 0.081027984619 1.205593347549 -0.044518053532 -v 0.078697204590 1.196267604828 -0.045972108841 -v 0.030203104019 1.317878961563 0.092599034309 -v 0.031599044800 1.306848764420 0.096550464630 -v 0.000533103943 1.315608501434 0.092406988144 -v 0.001453638077 1.304747343063 0.097599565983 -v -0.019915580750 1.309429168701 0.081647753716 -v -0.018998622894 1.298553228378 0.086916089058 -v -0.033011198044 1.297790884972 0.064219474792 -v -0.029258489609 1.289492845535 0.072676897049 -v -0.041879415512 1.274564981461 0.053379595280 -v -0.035678148270 1.269248962402 0.063527703285 -v -0.049278259277 1.251981019974 0.053342640400 -v -0.040801525116 1.249933481216 0.062599599361 -v -0.052246570587 1.230650424957 0.054706454277 -v -0.042381286621 1.229251742363 0.063888192177 -v -0.056648731232 1.206089735031 0.058673679829 -v -0.047176122665 1.203041553497 0.068685829639 -v -0.063978195190 1.193070888519 0.045640826225 -v -0.059770822525 1.182946562767 0.046971440315 -v -0.068000316620 1.188966512680 0.023967921734 -v -0.064295291901 1.178698301315 0.022614359856 -v -0.068785667419 1.192012310028 0.001784324646 -v -0.065010547638 1.183354616165 -0.002156734467 -v -0.066419363022 1.198132634163 -0.014372169971 -v -0.061841726303 1.189954519272 -0.018084764481 -v -0.056248426437 1.205180168152 -0.032190322876 -v -0.050663232803 1.196324706078 -0.035794079304 -v -0.035155773163 1.208442568779 -0.053844273090 -v -0.033224582672 1.197817921638 -0.051412761211 -v -0.008906602859 1.210032224655 -0.066920220852 -v -0.007337331772 1.200033903122 -0.065757989883 -v 0.025993824005 1.211974382401 -0.073480010033 -v 0.026358604431 1.201002120972 -0.069385886192 -v 0.049157142639 1.212844133377 -0.068056046963 -v 0.048957347870 1.202935099602 -0.064820349216 -v 0.065938234329 1.210010766983 -0.056550920010 -v 0.063969373703 1.200293183327 -0.057101726532 -v 0.026063919067 1.253668546677 -0.073655724525 -v -0.009798765182 1.251827239990 -0.066984713078 -v -0.036081075668 1.251029968262 -0.053802967072 -v -0.053255796432 1.248492121696 -0.030867159367 -v -0.061401128769 1.237682819366 -0.006527304649 -v -0.065071582794 1.235451579094 0.005308210850 -v -0.066051959991 1.232313632965 0.024793028831 -v -0.063958168030 1.215806245804 0.036684691906 -v -0.058470249176 1.244234442711 0.038768827915 -v -0.056696653366 1.254055619240 0.036476075649 -v 0.047235488892 1.252357602119 -0.067458629608 -v 0.065943956375 1.248579740524 -0.052758038044 -v 0.082094430923 1.242822408676 -0.039423704147 -v 0.101416587830 1.234602212906 0.000243604183 -v 0.095574378967 1.254433631897 -0.000831246376 -v 0.081856250763 1.282060623169 0.002210915089 -v 0.070363283157 1.305048108101 0.002756774426 -v 0.064732551575 1.325939893723 0.037348568439 -v 0.059475421906 1.330581545830 0.056172847748 -v 0.051770687103 1.331991195679 0.066862940788 -v 0.026969909668 1.331480026245 0.080155074596 -v 0.000534296036 1.328585267067 0.078154027462 -v -0.016364336014 1.321949958801 0.068262755871 -v -0.032131671906 1.307672977448 0.049133062363 -v -0.046026468277 1.281006813049 0.033047616482 -v -0.057170391083 1.264941453934 0.018052995205 -v -0.059194087982 1.260551929474 0.005703926086 -v -0.056351184845 1.267251372337 -0.005363285542 -v -0.049419403076 1.281430959702 0.018636167049 -v -0.050104856491 1.281523466110 -0.026480972767 -v -0.032762527466 1.285117030144 -0.046894788742 -v -0.006237030029 1.288429498672 -0.060750246048 -v 0.045986413956 1.285272717476 -0.059156835079 -v 0.060814857483 1.282638311386 -0.047715902328 -v 0.081722974777 1.278753519058 -0.015161991119 -v 0.093460798264 1.257528543472 -0.016839504242 -v 0.099166631699 1.234176397324 -0.016934752464 -v 0.080812215805 1.267979621887 -0.031077861786 -v 0.066226243973 1.297156810760 -0.022842288017 -v 0.025224208832 1.286554098129 -0.066509544849 -v 0.046222925186 1.308892011642 -0.040655016899 -v 0.025389671326 1.311321735382 -0.048380911350 -v -0.002219676971 1.312392711639 -0.044137835503 -v -0.024477481842 1.309771776199 -0.033741474152 -v -0.040723323822 1.304569959641 -0.014032125473 -v -0.038681983948 1.307122945786 0.022028684616 -v -0.033923625946 1.316653251648 0.007554233074 -v -0.022377967834 1.325628161430 0.032776713371 -v -0.011242151260 1.334012389183 0.047734975815 -v 0.005346775055 1.339532971382 0.057651221752 -v 0.023217439651 1.341475963593 0.059436559677 -v 0.043385505676 1.340054035187 0.050687074661 -v 0.050596475601 1.337354063988 0.041210770607 -v 0.055289745331 1.331090807915 0.023640811443 -v 0.054258584976 1.323943614960 -0.003970444202 -v 0.035431385040 1.330586671829 -0.015784919262 -v 0.002865314484 1.329736113548 -0.018387377262 -v -0.017127513885 1.325981378555 -0.009942293167 -v -0.009388685226 1.335545063019 0.010651230812 -v 0.008429527283 1.339061737061 0.003008246422 -v 0.036308050156 1.338485956192 0.004922389984 -v 0.036141872406 1.342529535294 0.023647129536 -v 0.034445047379 1.343819022179 0.035101830959 -v 0.020200014114 1.344961047173 0.038254320621 -v 0.006144762039 1.343188524246 0.040450692177 -v -0.003520011902 1.340352535248 0.030388653278 -v 0.015350580215 1.343349337578 0.023720622063 -v 0.002131700516 1.294373512268 0.084310173988 -v 0.032253980637 1.296369910240 0.083501935005 -v 0.053240537643 1.297918319702 0.073384404182 -v 0.063632249832 1.297773361206 0.063727974892 -v 0.066441297531 1.292367458344 0.051250755787 -v 0.069464921951 1.284128427505 0.042113184929 -v 0.072947740555 1.268516302109 0.036393523216 -v 0.077996730804 1.254851579666 0.034342646599 -v 0.082294940948 1.238687992096 0.033778369427 -v 0.096078634262 1.210922002792 0.033141076565 -v 0.093547344208 1.197418689728 0.010111808777 -v 0.088402271271 1.190471649170 -0.012344717979 -v 0.079278945923 1.192068338394 -0.027221798897 -v 0.067305803299 1.196002244949 -0.037115812302 -v 0.056254863739 1.199710249901 -0.045009076595 -v 0.043886661530 1.202761530876 -0.050360381603 -v 0.028577089310 1.203777551651 -0.055042266846 -v 0.000556945801 1.202123761177 -0.054026365280 -v -0.022556543350 1.199745535851 -0.042454838753 -v -0.037118673325 1.196506142616 -0.027604460716 -v -0.044364452362 1.191485524178 -0.013580024242 -v -0.048760175705 1.185310840607 0.001701295376 -v -0.049472093582 1.181732654572 0.018289864063 -v -0.043260574341 1.188125729561 0.041829228401 -v -0.042436599731 1.200907945633 0.067196130753 -v -0.029914379120 1.229040384293 0.062778651714 -v -0.028822183609 1.249405384064 0.061480879784 -v -0.026416063309 1.267934322357 0.062469124794 -v -0.020500183105 1.284778714180 0.069266617298 -v -0.011813879013 1.290825963020 0.077379345894 -v -0.036173343658 1.205227851868 0.065852403641 -v 0.089926242828 1.212391614914 0.033588826656 -v 0.086484670639 1.264750957489 -0.025318682194 -v 0.090276241302 1.249650478363 -0.029009580612 -v 0.093374252319 1.235239744186 -0.028121829033 -v -0.680430412292 1.393068790436 -0.320257246494 -v -0.698494911194 1.408102989197 -0.328137785196 -v -0.705596685410 1.403319478035 -0.332353264093 -v -0.702425003052 1.401414155960 -0.341219663620 -v -0.693487405777 1.401706576347 -0.345480948687 -v -0.677313804626 1.388596534729 -0.332979142666 -v -0.696997642517 1.407511115074 -0.337174981833 -v -0.689204931259 1.409341335297 -0.330315768719 -v -0.693303585052 1.391095876694 -0.314780384302 -v -0.703037500381 1.384432554245 -0.323003411293 -v -0.699735164642 1.379808068275 -0.336086094379 -v -0.686516761780 1.382108569145 -0.341215163469 -v -0.688117027283 1.406664133072 -0.339293509722 -v -0.671191692352 1.325040817261 -0.285161167383 -v -0.653577566147 1.274054050446 -0.263464331627 -v -0.622252702713 1.186689734459 -0.227236688137 -v -0.589787960052 1.099176168442 -0.192291796207 -v -0.552791118622 1.003217101097 -0.157474160194 -v -0.510915994644 0.897739231586 -0.121878385544 -v -0.492876291275 0.902821123600 -0.129963815212 -v -0.535413742065 1.007634758949 -0.164884626865 -v -0.573541641235 1.102779388428 -0.199071943760 -v -0.606878757477 1.189758062363 -0.233704805374 -v -0.639323711395 1.276522159576 -0.269631683826 -v -0.656749725342 1.327616810799 -0.290879905224 -v -0.681891918182 1.317631244659 -0.293967366219 -v -0.664569854736 1.266501188278 -0.272399932146 -v -0.634156942368 1.178615331650 -0.236648023129 -v -0.601839542389 1.090810775757 -0.202318966389 -v -0.566227912903 0.994425058365 -0.168143510818 -v -0.525188207626 0.888482391834 -0.133112192154 -v -0.678204059601 1.312798857689 -0.308455199003 -v -0.660619258881 1.261751770973 -0.287267655134 -v -0.630073070526 1.173742771149 -0.252752542496 -v -0.597980260849 1.085862278938 -0.219300508499 -v -0.562275886536 0.989962458611 -0.186343669891 -v -0.521363496780 0.884423673153 -0.152287662029 -v -0.663713693619 1.315396070480 -0.314257442951 -v -0.645992040634 1.264471530914 -0.293223381042 -v -0.614400863647 1.176954030991 -0.259143769741 -v -0.581530570984 1.089387059212 -0.226521193981 -v -0.544843912125 0.994354009628 -0.193900704384 -v -0.503242254257 0.889585494995 -0.160271108150 -v -0.653139591217 1.322819709778 -0.305283248425 -v -0.635165929794 1.272057771683 -0.284064382315 -v -0.603127479553 1.184988617897 -0.249243974686 -v -0.569592237473 1.097936868668 -0.215854406357 -v -0.531643867493 1.003189921379 -0.182969391346 -v -0.488971471786 0.898870944977 -0.149086236954 -v -0.484921455383 0.834170520306 -0.089892804623 -v -0.460219383240 0.840958893299 -0.100384473801 -v -0.511497497559 0.901323735714 -0.132468283176 -v -0.501404762268 0.904189109802 -0.136912345886 -v -0.472644090652 0.759641647339 -0.086778938770 -v -0.504419326782 0.821840167046 -0.105421543121 -v -0.519470214844 0.896225512028 -0.138695955276 -v -0.467942714691 0.754820764065 -0.108005642891 -v -0.499197244644 0.815808892250 -0.131774783134 -v -0.517336845398 0.893964409828 -0.149376213551 -v -0.448551177979 0.760925114155 -0.116835474968 -v -0.474140167236 0.822419762611 -0.142395973206 -v -0.507234096527 0.896824002266 -0.153811216354 -v -0.433065176010 0.771692276001 -0.104480087757 -v -0.455140352249 0.835817098618 -0.126966357231 -v -0.499275684357 0.901945590973 -0.147596955299 -v -0.459559202194 0.773626148701 -0.068398654461 -v -0.433999776840 0.781386613846 -0.079760193825 -v -0.427901983261 0.774820268154 -0.107565879822 -v -0.447791576385 0.760745763779 -0.123485684395 -v -0.472889900208 0.752940356731 -0.112041771412 -v -0.479088068008 0.758860111237 -0.084373116493 -v -0.491303682327 0.910904347897 -0.129152178764 -v -0.514250516891 0.904531538486 -0.118242800236 -v -0.533769607544 0.893227875233 -0.132516324520 -v -0.528328418732 0.887990593910 -0.157591700554 -v -0.504444837570 0.894635677338 -0.168278694153 -v -0.485826730728 0.906584739685 -0.153679370880 -v -0.461875915527 0.779266953468 -0.070306479931 -v -0.436331748962 0.787207782269 -0.081280946732 -v -0.430136680603 0.780604958534 -0.109252929688 -v -0.449860572815 0.765928268433 -0.125815510750 -v -0.475796222687 0.757836759090 -0.114095747471 -v -0.482009410858 0.764635562897 -0.085911035538 -v -0.487102031708 0.905195295811 -0.125341534615 -v -0.511810302734 0.898107171059 -0.114347636700 -v -0.531330347061 0.885510385036 -0.129618883133 -v -0.526210784912 0.880015254021 -0.155877709389 -v -0.501423597336 0.887129247189 -0.166869044304 -v -0.482195377350 0.899640679359 -0.151460170746 -v -0.462564945221 0.780975162983 -0.071647465229 -v -0.437812328339 0.788343131542 -0.082418143749 -v -0.431942939758 0.781991302967 -0.109270632267 -v -0.450904846191 0.768045961857 -0.124982774258 -v -0.475512504578 0.760414898396 -0.113783419132 -v -0.481489181519 0.767017781734 -0.087105572224 -v -0.487062454224 0.902436256409 -0.125205695629 -v -0.510672807693 0.895664632320 -0.114782571793 -v -0.529201984406 0.883543848991 -0.129371404648 -v -0.524323225021 0.878087401390 -0.154505074024 -v -0.500638008118 0.884852886200 -0.164988815784 -v -0.482070446014 0.897029280663 -0.150350451469 -v -0.424216270447 0.726895034313 -0.088332355022 -v -0.433250427246 0.720961630344 -0.097859382629 -v -0.445126295090 0.718145370483 -0.091281771660 -v -0.435346364975 0.722274005413 -0.082853138447 -v -0.449822902679 0.721979498863 -0.078244268894 -v -0.438974618912 0.728516280651 -0.071362376213 -v -0.426059484482 0.732701241970 -0.075176239014 -v -0.425045013428 0.742575645447 -0.074277520180 -v -0.443370342255 0.737635374069 -0.066380739212 -v -0.452912092209 0.722330808640 -0.097539663315 -v -0.434735298157 0.726553499699 -0.105409443378 -v -0.457568168640 0.770726919174 -0.074224233627 -v -0.438102483749 0.776775538921 -0.083273649216 -v -0.457084417343 0.727426528931 -0.078251421452 -v -0.421734809875 0.737034559250 -0.093638539314 -v -0.440868854523 0.726467907429 -0.079293847084 -v -0.441762924194 0.723804175854 -0.084031581879 -v -0.437235593796 0.723723113537 -0.086625933647 -v -0.433544158936 0.726360797882 -0.083503544331 -v -0.435790300369 0.728097319603 -0.078992664814 -v -0.435076475143 0.716530799866 -0.078679621220 -v -0.436748027802 0.715161144733 -0.083459377289 -v -0.433470964432 0.717130362988 -0.086149096489 -v -0.429803609848 0.719704866409 -0.082996487617 -v -0.430795431137 0.719356417656 -0.078405201435 -v -0.426370620728 0.708177804947 -0.082949578762 -v -0.429102659225 0.708031177521 -0.087148606777 -v -0.427751302719 0.711654126644 -0.088896811008 -v -0.424102544785 0.714181125164 -0.085791230202 -v -0.423462867737 0.712011873722 -0.082427322865 -v -0.417178869247 0.705715954304 -0.092401742935 -v -0.421164512634 0.705772161484 -0.095329344273 -v -0.421780347824 0.710141003132 -0.095210850239 -v -0.418033361435 0.712694764137 -0.092156529427 -v -0.415308475494 0.709888398647 -0.090527355671 -v -0.411131381989 0.710895836353 -0.103977918625 -v -0.416023015976 0.710323870182 -0.105279445648 -v -0.418101072311 0.713830649853 -0.102593660355 -v -0.414386272430 0.716481685638 -0.099799752235 -v -0.409998416901 0.714512467384 -0.100628316402 -v -0.412442445755 0.723457217216 -0.112111985683 -v -0.417440891266 0.721303761005 -0.112163603306 -v -0.419823646545 0.722338557243 -0.107104063034 -v -0.416396379471 0.725583493710 -0.104684352875 -v -0.411242246628 0.725655853748 -0.107722580433 -v -0.419799089432 0.736344456673 -0.113022804260 -v -0.424517631531 0.732703447342 -0.112453818321 -v -0.425635576248 0.730973005295 -0.106811225414 -v -0.422138690948 0.734303593636 -0.103965282440 -v -0.418025732040 0.737095832825 -0.108072340488 -v -0.427905082703 0.742825925350 -0.108273148537 -v -0.431505441666 0.737993359566 -0.108103752136 -v -0.431043863297 0.735172092915 -0.103496670723 -v -0.427010297775 0.737998902798 -0.100774705410 -v -0.425103187561 0.742438733578 -0.103610634804 -v -0.434395790100 0.745493888855 -0.102516651154 -v -0.437351465225 0.740055739880 -0.103321194649 -v -0.434785366058 0.735876679420 -0.100580215454 -v -0.429973125458 0.739280521870 -0.096914887428 -v -0.430575609207 0.744815766811 -0.098116934299 -v -0.638014793396 1.230491757393 -0.244978487492 -v -0.622946262360 1.233280658722 -0.251465588808 -v -0.649592638016 1.222546815872 -0.254358708858 -v -0.645442724228 1.217762947083 -0.269892901182 -v -0.630394697189 1.220943450928 -0.275375068188 -v -0.619070529938 1.228546142578 -0.266649246216 -v -0.606110572815 1.143009781837 -0.209524273872 -v -0.590292215347 1.146337389946 -0.216171145439 -v -0.617876529694 1.134744167328 -0.219516158104 -v -0.614089488983 1.129821658134 -0.235923349857 -v -0.598005294800 1.133176445961 -0.242772758007 -v -0.586416721344 1.141480803490 -0.232462942600 -v -0.572516918182 1.054052591324 -0.175565481186 -v -0.555697917938 1.058142900467 -0.182277798653 -v -0.585446357727 1.045498132706 -0.185521006584 -v -0.581245422363 1.040752649307 -0.203099846840 -v -0.564207553864 1.044691920280 -0.210411846638 -v -0.551835060120 1.053359389305 -0.199682593346 -v -0.530359745026 0.946404516697 -0.139006793499 -v -0.512903213501 0.951150536537 -0.146695137024 -v -0.544089317322 0.937598705292 -0.149761617184 -v -0.540381193161 0.933445930481 -0.168263316154 -v -0.522706985474 0.938259720802 -0.175991654396 -v -0.508960247040 0.947188973427 -0.165071189404 -v -0.473415136337 0.870537042618 -0.112968623638 -v -0.496746063232 0.863225281239 -0.101937651634 -v -0.516067743301 0.851110696793 -0.117046415806 -v -0.510797500610 0.845018565655 -0.142522931099 -v -0.486820697784 0.852223873138 -0.153340578079 -v -0.467840671539 0.864946663380 -0.138649642467 -v -0.447163105011 0.810840010643 -0.089115977287 -v -0.472838640213 0.805846035480 -0.079120457172 -v -0.492668628693 0.793564498425 -0.095415353775 -v -0.486189365387 0.784938633442 -0.121517777443 -v -0.460333108902 0.791131556034 -0.131569087505 -v -0.440885305405 0.803529441357 -0.115472018719 -v -0.450312852859 0.753731548786 -0.070098817348 -v -0.431421279907 0.759420990944 -0.078914582729 -v -0.465086460114 0.742805838585 -0.082118272781 -v -0.460514783859 0.737773180008 -0.103004276752 -v -0.441336154938 0.743454098701 -0.111343443394 -v -0.426443099976 0.754368603230 -0.099310636520 -v -0.731904268265 1.409023046494 -0.283832073212 -v -0.731420993805 1.409527540207 -0.277567297220 -v -0.769669771194 1.473773002625 -0.284856706858 -v -0.769919872284 1.473968267441 -0.288533568382 -v -0.807954311371 1.532006978989 -0.292883962393 -v -0.809309005737 1.532471895218 -0.288937449455 -v -0.723148822784 1.397814750671 -0.277460843325 -v -0.725734949112 1.400135159492 -0.284406632185 -v -0.701467037201 1.393261909485 -0.299498915672 -v -0.702801704407 1.394067406654 -0.304610729218 -v -0.697797775269 1.322681307793 -0.245903372765 -v -0.678847789764 1.325425028801 -0.269638597965 -v -0.699045181274 1.318197965622 -0.247449636459 -v -0.679080247879 1.320086479187 -0.270336747169 -v -0.698448657990 1.258418440819 -0.191542923450 -v -0.699070453644 1.255869746208 -0.195368707180 -v -0.698896884918 1.187084913254 -0.134619593620 -v -0.700427770615 1.184316277504 -0.138689637184 -v -0.701871871948 1.162669658661 -0.121972262859 -v -0.711782455444 1.180882930756 -0.144968867302 -v -0.710798740387 1.249737977982 -0.202855288982 -v -0.711197614670 1.311830759048 -0.256590962410 -v -0.690308570862 1.311554193497 -0.279663801193 -v -0.713588476181 1.315556406975 -0.259247243404 -v -0.693629026413 1.312055587769 -0.281306147575 -v -0.714844465256 1.249986529350 -0.202514290810 -v -0.714670181274 1.182743430138 -0.144470751286 -v -0.703557968140 1.160912275314 -0.124656915665 -v -0.734780550003 1.184387803078 -0.107548713684 -v -0.803620576859 1.413166880608 -0.193729162216 -v -0.844019651413 1.455053806305 -0.184393405914 -v -0.807727098465 1.321138620377 -0.116503834724 -v -0.837025165558 1.372961163521 -0.126379728317 -v -0.771314382553 1.244080543518 -0.100617885590 -v -0.793653011322 1.271091222763 -0.097309827805 -v -0.731769084930 1.187012553215 -0.105778515339 -v -0.778274536133 1.234176158905 -0.089952230453 -v -0.774795055389 1.242721438408 -0.096917808056 -v -0.802556514740 1.267426371574 -0.087716221809 -v -0.781018733978 1.239013910294 -0.089828252792 -v -0.831202745438 1.315947771072 -0.093698978424 -v -0.857189416885 1.373258233070 -0.109514474869 -v -0.872247457504 1.439273834229 -0.146919488907 -v -0.862528800964 1.441547393799 -0.156704366207 -v -0.872767448425 1.465386867523 -0.168636918068 -v -0.871892452240 1.446012973785 -0.152757167816 -v -0.870913505554 1.465698003769 -0.171075582504 -v -0.872616052628 1.496040582657 -0.196074187756 -v -0.873492717743 1.469481587410 -0.172275424004 -v -0.844311237335 1.563365578651 -0.288278520107 -v -0.867714643478 1.493918657303 -0.196815609932 -v -0.870485305786 1.498056888580 -0.198610186577 -v -0.873506069183 1.498218655586 -0.200232744217 -v -0.873781919479 1.495349645615 -0.197271823883 -v -0.868160724640 1.436191439629 -0.160237908363 -v -0.874623298645 1.443897843361 -0.155241250992 -v -0.875429630280 1.468093872070 -0.173968076706 -v -0.875430583954 1.464208483696 -0.170832037926 -v -0.861469507217 1.539059877396 -0.244808673859 -v -0.864252090454 1.538134932518 -0.246580541134 -v -0.846224308014 1.561979532242 -0.289737492800 -v -0.836484193802 1.567539691925 -0.300393223763 -v -0.837390184402 1.566413164139 -0.303441166878 -v -0.780709743500 1.232831001282 -0.092110395432 -v -0.770603179932 1.241312861443 -0.120023488998 -v -0.805193901062 1.265119791031 -0.089168965816 -v -0.783527612686 1.236857414246 -0.091316342354 -v -0.834095478058 1.314088821411 -0.095762848854 -v -0.860008001328 1.371434450150 -0.112266540527 -v -0.874962329865 1.439385414124 -0.149586439133 -v -0.845883846283 1.368828058243 -0.133463740349 -v -0.873351573944 1.462928771973 -0.173678338528 -v -0.871895790100 1.493336915970 -0.199328541756 -v -0.840737104416 1.510570049286 -0.263315886259 -v -0.833376646042 1.531134724617 -0.288762927055 -v -0.817931175232 1.526331186295 -0.300622344017 -v -0.746751785278 1.402173876762 -0.290421187878 -v -0.796869993210 1.488108158112 -0.299173355103 -v -0.803301095963 1.423126697540 -0.242137193680 -v -0.853743076324 1.448746681213 -0.194176614285 -v -0.821331739426 1.314145565033 -0.119208931923 -v -0.793041229248 1.273641824722 -0.120415627956 -v -0.779705524445 1.238341212273 -0.096930265427 -v -0.758402109146 1.325504183769 -0.214042127132 -v -0.734133243561 1.393293976784 -0.292042940855 -v -0.736127614975 1.383604526520 -0.289822369814 -v -0.747549772263 1.393516778946 -0.284139096737 -v -0.713304281235 1.387033820152 -0.312869518995 -v -0.716605424881 1.378824830055 -0.315402686596 -v -0.667083024979 1.332947969437 -0.272325456142 -v -0.686036825180 1.396254181862 -0.300350457430 -v -0.652807712555 1.335969448090 -0.279133826494 -v -0.671698808670 1.397094845772 -0.306801915169 -v -0.641156673431 1.331952333450 -0.292787551880 -v -0.662131309509 1.392925381660 -0.323805451393 -v -0.665781974792 1.324501156807 -0.274403363466 -v -0.653313159943 1.326481461525 -0.280657827854 -v -0.643545627594 1.325591325760 -0.292931616306 -v -0.687883615494 1.396928071976 -0.306693255901 -v -0.677305936813 1.397392749786 -0.311640799046 -v -0.668898105621 1.393209457397 -0.326097100973 -v -0.639791965485 1.324838161469 -0.306407392025 -v -0.661513090134 1.386579990387 -0.338125854731 -v -0.642078876495 1.321270823479 -0.304058849812 -v -0.667977333069 1.387650251389 -0.338719785213 -v -0.640511274338 1.320248246193 -0.313241720200 -v -0.661991596222 1.385642766953 -0.342326313257 -v -0.643562793732 1.316686630249 -0.313483148813 -v -0.666442394257 1.385178923607 -0.344291776419 -v -0.716503143311 1.372074604034 -0.326735794544 -v -0.694771766663 1.309220075607 -0.296694934368 -v -0.710252761841 1.365118026733 -0.340708762407 -v -0.689024686813 1.304324030876 -0.313677370548 -v -0.695271492004 1.365952491760 -0.350932478905 -v -0.673334360123 1.305315852165 -0.323754280806 -v -0.676507711411 1.373834609985 -0.354276686907 -v -0.657118558884 1.312539339066 -0.327110052109 -v -0.713317871094 1.378292798996 -0.329542458057 -v -0.708588600159 1.374512910843 -0.340065002441 -v -0.695788145065 1.374732732773 -0.347389072180 -v -0.678169250488 1.378413438797 -0.351348221302 -v -0.690240859985 1.306376218796 -0.295807123184 -v -0.685710668564 1.302699327469 -0.310207158327 -v -0.671741962433 1.304181456566 -0.319831520319 -v -0.655930995941 1.309202790260 -0.323127806187 -v -0.634047985077 1.305329561234 -0.344313293695 -v -0.623847723007 1.313705205917 -0.334188282490 -v -0.622318029404 1.319812774658 -0.335038781166 -v -0.636306285858 1.308283686638 -0.347529143095 -v -0.657687187195 1.368595123291 -0.372926771641 -v -0.657169342041 1.375516891479 -0.371039777994 -v -0.642990112305 1.381778359413 -0.362855851650 -v -0.649636030197 1.380834460258 -0.366766542196 -v -0.621777534485 1.454902648926 -0.452792227268 -v -0.627440929413 1.456566333771 -0.455327212811 -v -0.631230592728 1.454094767570 -0.456920742989 -v -0.635877132416 1.447454333305 -0.459561079741 -v -0.624344110489 1.466953277588 -0.470377117395 -v -0.627939224243 1.463238477707 -0.473223686218 -v -0.611341238022 1.455082416534 -0.477429419756 -v -0.615406513214 1.452845573425 -0.479317456484 -v -0.596461057663 1.429937839508 -0.461888015270 -v -0.585901737213 1.430440187454 -0.486534267664 -v -0.568025112152 1.390513300896 -0.463041514158 -v -0.556784152985 1.394706368446 -0.490542352200 -v -0.620961666107 1.366299271584 -0.374592006207 -v -0.602149963379 1.328221082687 -0.365407556295 -v -0.554142475128 1.359774947166 -0.457094848156 -v -0.544462203979 1.367879867554 -0.489594697952 -v -0.554653167725 1.386860847473 -0.492153495550 -v -0.540938138962 1.330043315887 -0.446610987186 -v -0.526558876038 1.326992034912 -0.474644184113 -v -0.532519340515 1.298381805420 -0.428922235966 -v -0.517386436462 1.295669794083 -0.456924021244 -v -0.517901897430 1.258272409439 -0.422607213259 -v -0.512837409973 1.254708290100 -0.429519742727 -v -0.540863037109 1.262001872063 -0.384749233723 -v -0.516560077667 1.256026744843 -0.420525699854 -v -0.516956090927 1.229684472084 -0.400133073330 -v -0.512316942215 1.247911930084 -0.421232968569 -v -0.543984174728 1.231948614120 -0.360431998968 -v -0.536952972412 1.211765289307 -0.364224553108 -v -0.613957405090 1.310405731201 -0.337616801262 -v -0.617177486420 1.305488467216 -0.336197882891 -v -0.547671794891 1.226849794388 -0.359812885523 -v -0.623764514923 1.295241832733 -0.345131874084 -v -0.550174236298 1.224074363708 -0.363058030605 -v -0.611073017120 1.422493457794 -0.469076097012 -v -0.633231639862 1.343430519104 -0.382424205542 -v -0.617163181305 1.313082218170 -0.376247048378 -v -0.627777338028 1.298094511032 -0.349091798067 -v -0.587876319885 1.425273895264 -0.487512648106 -v -0.559880733490 1.391711711884 -0.492971718311 -v -0.546575784683 1.364702701569 -0.491101324558 -v -0.556817054749 1.384633302689 -0.494335830212 -v -0.581263065338 1.378509998322 -0.469431370497 -v -0.528251409531 1.325081706047 -0.475629925728 -v -0.562163352966 1.334616303444 -0.456040829420 -v -0.519301652908 1.293952107430 -0.458499312401 -v -0.546352624893 1.291024565697 -0.436513841152 -v -0.514696121216 1.253158092499 -0.430215626955 -v -0.520211696625 1.255135059357 -0.424808651209 -v -0.520582675934 1.251160979271 -0.424345523119 -v -0.549528598785 1.249001860619 -0.397651523352 -v -0.514673948288 1.245489358902 -0.423131406307 -v -0.518534421921 1.226596713066 -0.399023622274 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.538474559784 1.209404468536 -0.364824950695 -v -0.528185606003 1.214612126350 -0.376569181681 -v -0.529793500900 1.213744163513 -0.379284560680 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.752520561218 1.404311418533 -0.285495400429 -v -0.799973726273 1.489697456360 -0.296636253595 -v 0.070177555084 1.274966716766 0.089686870575 -v 0.067983150482 1.274402737617 0.090926527977 -v 0.066224336624 1.272931575775 0.092114746571 -v 0.065168857574 1.270776987076 0.093070566654 -v 0.064977169037 1.268267154694 0.093648433685 -v 0.065678596497 1.265784263611 0.093760550022 -v 0.067166328430 1.263706088066 0.093389570713 -v 0.069213867188 1.262349128723 0.092592179775 -v 0.071509599686 1.261919736862 0.091489672661 -v 0.073703765869 1.262483835220 0.090249955654 -v 0.075462818146 1.263954997063 0.089061796665 -v 0.076518297195 1.266109466553 0.088105916977 -v 0.076709985733 1.268619298935 0.087528049946 -v 0.076008558273 1.271102190018 0.087416052818 -v 0.074520826340 1.273180484772 0.087786972523 -v 0.072473287582 1.274537563324 0.088584363461 -v 0.068333148956 1.278423786163 0.086334288120 -v 0.064796447754 1.277514934540 0.088332414627 -v 0.061961412430 1.275143623352 0.090247511864 -v 0.060260057449 1.271671056747 0.091788053513 -v 0.059951066971 1.267625689507 0.092719554901 -v 0.061081647873 1.263623714447 0.092900037766 -v 0.063479423523 1.260274052620 0.092302203178 -v 0.066779851913 1.258086919785 0.091017007828 -v 0.070479869843 1.257395267487 0.089240074158 -v 0.074016571045 1.258304119110 0.087241888046 -v 0.076851606369 1.260675430298 0.085326790810 -v 0.078552961349 1.264147996902 0.083786249161 -v 0.078861951828 1.268193244934 0.082854807377 -v 0.077731370926 1.272195339203 0.082674264908 -v 0.075333595276 1.275544881821 0.083272099495 -v 0.072033166885 1.277732014656 0.084557354450 -v 0.065737485886 1.280808687210 0.081495702267 -v 0.061116695404 1.279621124268 0.084106385708 -v 0.057412624359 1.276522874832 0.086608529091 -v 0.055189609528 1.271985650063 0.088621377945 -v 0.054785966873 1.266700267792 0.089838445187 -v 0.056262969971 1.261471390724 0.090074300766 -v 0.059396028519 1.257094979286 0.089293181896 -v 0.063708066940 1.254237174988 0.087613999844 -v 0.068542480469 1.253333449364 0.085292279720 -v 0.073163509369 1.254521012306 0.082681596279 -v 0.076867341995 1.257619142532 0.080179393291 -v 0.079090595245 1.262156486511 0.078166604042 -v 0.079494237900 1.267441749573 0.076949536800 -v 0.078016996384 1.272670745850 0.076713681221 -v 0.074883937836 1.277047157288 0.077494800091 -v 0.070571899414 1.279904842377 0.079174041748 -v 0.062948465347 1.280951499939 0.076157152653 -v 0.057946681976 1.279666066170 0.078983008862 -v 0.053937673569 1.276312589645 0.081691384315 -v 0.051531553268 1.271401524544 0.083870053291 -v 0.051094532013 1.265680670738 0.085187315941 -v 0.052693367004 1.260020971298 0.085442662239 -v 0.056084394455 1.255283951759 0.084597170353 -v 0.060751676559 1.252190828323 0.082779586315 -v 0.065984487534 1.251212596893 0.080266594887 -v 0.070986270905 1.252498149872 0.077440857887 -v 0.074995517731 1.255851507187 0.074732422829 -v 0.077401638031 1.260762453079 0.072553753853 -v 0.077838659286 1.266483306885 0.071236491203 -v 0.076239824295 1.272143006325 0.070981144905 -v 0.072848558426 1.276880025864 0.071826636791 -v 0.068181276321 1.279973268509 0.073644220829 -v 0.060390472412 1.278830766678 0.071131527424 -v 0.055769443512 1.277642965317 0.073742210865 -v 0.052065610886 1.274544715881 0.076244413853 -v 0.049842596054 1.270007610321 0.078257262707 -v 0.049438953400 1.264722228050 0.079474270344 -v 0.050915956497 1.259493350983 0.079710185528 -v 0.054049015045 1.255116820335 0.078929066658 -v 0.058361053467 1.252259254456 0.077249825001 -v 0.063195466995 1.251355409622 0.074928104877 -v 0.067816495895 1.252542972565 0.072317481041 -v 0.071520328522 1.255641222000 0.069815278053 -v 0.073743581772 1.260178327560 0.067802429199 -v 0.074147224426 1.265463709831 0.066585421562 -v 0.072669982910 1.270692825317 0.066349506378 -v 0.069536924362 1.275068998337 0.067130684853 -v 0.065225124359 1.277926802635 0.068809866905 -v 0.067524909973 1.268451929092 0.093102991581 -v 0.069175004959 1.268501400948 0.092242240906 -v 0.071127653122 1.268560051918 0.091223716736 -v 0.073080301285 1.268618583679 0.090205192566 -v 0.074730157852 1.268668174744 0.089344441891 -v 0.070652723312 1.273131608963 0.090560674667 -v 0.068799734116 1.272726535797 0.091593861580 -v 0.067301273346 1.271686553955 0.092565476894 -v 0.066444635391 1.270407199860 0.093231320381 -v 0.066426753998 1.268414258957 0.093641161919 -v 0.066850900650 1.266429066658 0.093780994415 -v 0.067962169647 1.265214204788 0.093459844589 -v 0.069663047791 1.264270186424 0.092762410641 -v 0.071587085724 1.263978362083 0.091825425625 -v 0.073440074921 1.264383435249 0.090792238712 -v 0.074938535690 1.265423536301 0.089820683002 -v 0.075786352158 1.266697168350 0.089119791985 -v 0.075813055038 1.268695831299 0.088744938374 -v 0.075380325317 1.270675182343 0.088570117950 -v 0.074277639389 1.271895647049 0.088926315308 -v 0.072576761246 1.272839784622 0.089623689651 -v 0.004819393158 1.270663738251 0.106835365295 -v 0.004348754883 1.274211406708 0.103122293949 -v 0.008491754532 1.273808002472 0.103105425835 -v 0.007389783859 1.270413398743 0.106824874878 -v 0.012167453766 1.271865367889 0.103312313557 -v 0.009670257568 1.269208192825 0.106953203678 -v 0.014816045761 1.268679141998 0.103711485863 -v 0.011313676834 1.267231464386 0.107200860977 -v 0.016034841537 1.264734506607 0.104242146015 -v 0.012069702148 1.264783978462 0.107530117035 -v 0.015637636185 1.260631918907 0.104823470116 -v 0.011823415756 1.262238621712 0.107890844345 -v 0.013685464859 1.256995797157 0.105367064476 -v 0.010612010956 1.259982705116 0.108228087425 -v 0.010475158691 1.254379987717 0.105790019035 -v 0.008620262146 1.258359789848 0.108490467072 -v 0.006495475769 1.253182649612 0.106028079987 -v 0.006151199341 1.257616877556 0.108638167381 -v 0.002352476120 1.253586053848 0.106044888496 -v 0.003580808640 1.257867097855 0.108648657799 -v -0.001322984695 1.255528688431 0.105838000774 -v 0.001300334930 1.259072422981 0.108520269394 -v -0.003971815109 1.258714914322 0.105438828468 -v -0.000343084335 1.261049270630 0.108272612095 -v -0.005190372467 1.262659549713 0.104908168316 -v -0.001099109650 1.263496637344 0.107943356037 -v -0.004793405533 1.266762256622 0.104326844215 -v -0.000852823257 1.266042113304 0.107582688332 -v -0.002841234207 1.270398139954 0.103783249855 -v 0.000358581543 1.268298029900 0.107245445251 -v 0.000369071960 1.273014068604 0.103360295296 -v 0.002350330353 1.269920825958 0.106983006001 -v 0.003931760788 1.276739597321 0.097712039948 -v 0.009344816208 1.276212692261 0.097690045834 -v 0.014147281647 1.273674488068 0.097960352898 -v 0.017608165741 1.269511461258 0.098481893539 -v 0.019200325012 1.264357566833 0.099175214767 -v 0.018681526184 1.258997201920 0.099934816360 -v 0.016130685806 1.254246473312 0.100645005703 -v 0.011936426163 1.250828742981 0.101197659969 -v 0.006736755371 1.249264478683 0.101508677006 -v 0.001323699951 1.249791383743 0.101530730724 -v -0.003478765488 1.252329587936 0.101260423660 -v -0.006939411163 1.256492614746 0.100738883018 -v -0.008531808853 1.261646509171 0.100045561790 -v -0.008013010025 1.267006874084 0.099285960197 -v -0.005462169647 1.271757602692 0.098575711250 -v -0.001267671585 1.275175333023 0.098023056984 -v 0.003712654114 1.277051687241 0.091699361801 -v 0.009571552277 1.276481389999 0.091675460339 -v 0.014769792557 1.273733854294 0.091968059540 -v 0.018515825272 1.269227981567 0.092532575130 -v 0.020239114761 1.263649225235 0.093283057213 -v 0.019677639008 1.257847428322 0.094105184078 -v 0.016916751862 1.252705335617 0.094873905182 -v 0.012376546860 1.249006032944 0.095472097397 -v 0.006748676300 1.247312784195 0.095808684826 -v 0.000889539719 1.247883200645 0.095832526684 -v -0.004308462143 1.250630378723 0.095539927483 -v -0.008054494858 1.255136489868 0.094975411892 -v -0.009777784348 1.260715007782 0.094224989414 -v -0.009216308594 1.266516923904 0.093402862549 -v -0.006455421448 1.271659016609 0.092634141445 -v -0.001915454865 1.275358438492 0.092035949230 -v 0.003724575043 1.275099992752 0.085999369621 -v 0.009137630463 1.274572968483 0.085977315903 -v 0.013940095901 1.272034764290 0.086247682571 -v 0.017400741577 1.267871737480 0.086769223213 -v 0.018993139267 1.262717843056 0.087462544441 -v 0.018474340439 1.257357597351 0.088222086430 -v 0.015923500061 1.252606868744 0.088932335377 -v 0.011729001999 1.249189138412 0.089484930038 -v 0.006529569626 1.247624635696 0.089795947075 -v 0.001116514206 1.248151659966 0.089817941189 -v -0.003685951233 1.250689744949 0.089547634125 -v -0.007146835327 1.254852890968 0.089026153088 -v -0.008738994598 1.260006904602 0.088332772255 -v -0.008220195770 1.265367150307 0.087573230267 -v -0.005669355392 1.270117759705 0.086863040924 -v -0.001475095749 1.273535490036 0.086310386658 -v 0.000261068344 1.263721823692 0.108568012714 -v 0.000306606293 1.265732765198 0.108267664909 -v 0.001283168793 1.267090082169 0.108078360558 -v 0.001492738724 1.263846516609 0.108560204506 -v 0.005061388016 1.268813371658 0.107770264149 -v 0.007216453552 1.268672227859 0.107751905918 -v 0.007727861404 1.264456152916 0.108364582062 -v 0.005536317825 1.264241814613 0.108433365822 -v 0.002977371216 1.268257856369 0.107884883881 -v 0.003344774246 1.264027595520 0.108502089977 -v 0.009113311768 1.267855644226 0.107832670212 -v 0.009579896927 1.264637112617 0.108306467533 -v 0.010335683823 1.266713142395 0.107952952385 -v 0.010796070099 1.264751791954 0.108237385750 -v 0.010741710663 1.262735128403 0.108502686024 -v 0.009773969650 1.261383295059 0.108727037907 -v 0.008079767227 1.260215759277 0.108920395374 -v 0.005995750427 1.259660124779 0.109035074711 -v 0.003840684891 1.259801387787 0.109053432941 -v 0.001943826675 1.260617733002 0.108972728252 -v 0.000712633133 1.261754751205 0.108817398548 -v -0.090843439102 0.711956977844 -0.100321829319 -v -0.097157239914 0.660702586174 -0.115609467030 -v -0.006523370743 0.676110148430 -0.150974154472 -v -0.006254673004 0.734257340431 -0.141055881977 -v -0.106460332870 0.595456779003 -0.120525121689 -v -0.013854026794 0.609138488770 -0.144045293331 -v 0.159080028534 0.595945835114 -0.117241799831 -v 0.082373142242 0.601140439510 -0.140979409218 -v 0.217724084854 0.633673191071 -0.043690085411 -v 0.161948204041 0.658787310123 -0.116667926311 -v 0.161992549896 0.716392397881 -0.109141111374 -v 0.200988769531 0.700885295868 -0.057521402836 -v 0.082037210464 0.736163735390 -0.142028212547 -v 0.083940982819 0.671887874603 -0.145761489868 -v -0.052839994431 0.668570876122 -0.136453270912 -v -0.051985740662 0.724966228008 -0.126949429512 -v -0.060494899750 0.603041768074 -0.130789637566 -v 0.039752244949 0.676460027695 -0.152075648308 -v 0.039582014084 0.736532151699 -0.145459830761 -v 0.035222053528 0.606680989265 -0.146267235279 -v 0.123104095459 0.599229633808 -0.133650958538 -v 0.124687910080 0.666198194027 -0.136043965816 -v 0.123418569565 0.728347480297 -0.130160868168 -v 0.192488431931 0.646883368492 -0.081060171127 -v 0.192901372910 0.580796957016 -0.078956365585 -v 0.191608905792 0.708395838737 -0.080889344215 -v -0.110157966614 0.521872341633 -0.123427271843 -v -0.020442485809 0.542563259602 -0.144708812237 -v -0.109526634216 0.464789211750 -0.130063176155 -v -0.029718160629 0.474508851767 -0.155036568642 -v 0.068801403046 0.477472692728 -0.140547931194 -v 0.076097488403 0.537705183029 -0.135993599892 -v 0.162404775620 0.526327550411 -0.118127703667 -v 0.165109157562 0.450441986322 -0.139342069626 -v 0.228643178940 0.555671572685 -0.027355194092 -v 0.238083362579 0.474860131741 -0.044692456722 -v -0.066143035889 0.532799482346 -0.133282661438 -v -0.084163904190 0.454995065928 -0.141852140427 -v 0.016598701477 0.487684130669 -0.148972153664 -v 0.027564287186 0.544286847115 -0.143417119980 -v 0.122592210770 0.530475378036 -0.130063533783 -v 0.122491121292 0.461961984634 -0.139939665794 -v 0.199285984039 0.507649183273 -0.092158377171 -v 0.206475257874 0.438298881054 -0.125071763992 -v 0.236012935638 0.432352960110 -0.098448753357 -v -0.090003728867 0.713547110558 -0.098060905933 -v -0.096627950668 0.660236895084 -0.111967146397 -v -0.006083011627 0.675602138042 -0.146969020367 -v -0.005826711655 0.733766078949 -0.137710273266 -v -0.104192733765 0.594722390175 -0.114763200283 -v -0.013294696808 0.609091877937 -0.139524400234 -v 0.157139778137 0.595473289490 -0.113379478455 -v 0.081852197647 0.601088523865 -0.137477576733 -v 0.215976238251 0.632654249668 -0.042290151119 -v 0.160015106201 0.658218741417 -0.113578557968 -v 0.160174369812 0.716303348541 -0.106486916542 -v 0.199095010757 0.698588788509 -0.055205583572 -v 0.081353425980 0.736018717289 -0.138786435127 -v 0.083306312561 0.671617090702 -0.142443776131 -v -0.051246881485 0.668073892593 -0.131973326206 -v -0.051016092300 0.724832594395 -0.123342573643 -v -0.058906555176 0.602810740471 -0.125979125500 -v 0.039349555969 0.676087617874 -0.148158311844 -v 0.039282560349 0.736191391945 -0.142057716846 -v 0.034797668457 0.606659471989 -0.142599940300 -v 0.122372865677 0.599070608616 -0.130384206772 -v 0.123716592789 0.665827274323 -0.132826924324 -v 0.122337818146 0.727991521358 -0.127091944218 -v 0.189619779587 0.645916223526 -0.078319907188 -v 0.190189838409 0.580016136169 -0.076071262360 -v 0.189076185226 0.708024799824 -0.078644990921 -v -0.109309196472 0.521241247654 -0.119572401047 -v -0.019951820374 0.542360663414 -0.139999091625 -v -0.107759237289 0.462610036135 -0.125670790672 -v -0.029715299606 0.473200440407 -0.152146577835 -v 0.068043947220 0.475595116615 -0.137133598328 -v 0.075683832169 0.537864387035 -0.132634162903 -v 0.160769462585 0.526261806488 -0.115079045296 -v 0.163467884064 0.450367748737 -0.135400056839 -v 0.221496105194 0.555388748646 -0.030082941055 -v 0.230763673782 0.473996579647 -0.045731902122 -v -0.064914464951 0.532697319984 -0.129568278790 -v -0.083212852478 0.454447656870 -0.137265324593 -v 0.015990495682 0.486549288034 -0.145901143551 -v 0.027146339417 0.544277787209 -0.140076875687 -v 0.121834754944 0.530655384064 -0.126233458519 -v 0.121745109558 0.460826694965 -0.136413335800 -v 0.196135759354 0.507262945175 -0.088767468929 -v 0.203240156174 0.436599731445 -0.122523009777 -v 0.234281539917 0.431487858295 -0.096786618233 -v -0.090369224548 0.714081227779 -0.101824402809 -v -0.097647190094 0.660447895527 -0.114232182503 -v -0.108165264130 0.595181941986 -0.117026686668 -v 0.217889308929 0.634391546249 -0.045080006123 -v 0.200847625732 0.698190927505 -0.056285917759 -v -0.110817670822 0.521583199501 -0.122230708599 -v -0.109757661819 0.463707029819 -0.127314388752 -v -0.029812097549 0.473399698734 -0.154148936272 -v 0.068494558334 0.476215690374 -0.139647960663 -v 0.164371013641 0.449653983116 -0.137532711029 -v 0.229068279266 0.556188762188 -0.032200336456 -v 0.238276958466 0.475655049086 -0.049598276615 -v -0.083764553070 0.453088641167 -0.140538215637 -v 0.016265869141 0.486640363932 -0.148057878017 -v 0.122293949127 0.461069822311 -0.137957692146 -v 0.204746484756 0.437017977238 -0.123723983765 -v 0.236302852631 0.434788256884 -0.099483311176 -# 5612 vertices - -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000006930147 0.002676741453 0.999996423721 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.161999627948 0.909521639347 0.382787853479 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000007515317 0.002677260898 0.999996423721 -vn 0.382675856352 0.003497111378 0.923876047134 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.047306902707 0.969304382801 0.241269692779 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.248550355434 0.968081712723 0.032257635146 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.665100693703 0.708603322506 0.235631942749 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.208323746920 0.938979506493 0.273712754250 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.704381942749 0.650786757469 0.283412605524 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.375906050205 0.924689590931 0.060363583267 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.433224350214 0.852531194687 0.292416185141 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.232279226184 0.908129572868 0.348349064589 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.410649836063 0.890585064888 0.195512071252 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.109717316926 0.925979495049 0.361281156540 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.089727103710 0.922582089901 0.375221759081 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129825502634 0.989126026630 0.069101937115 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.140165805817 0.920780718327 0.364028096199 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.647070944309 0.737142920494 0.194729119539 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.289651811123 0.940054774284 0.179996877909 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.132732138038 0.979921698570 0.148780390620 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.026919174939 0.987045407295 0.158166885376 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.207886472344 0.974640905857 0.082815110683 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.788730025291 0.571293294430 0.226999789476 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.841550469398 0.399582356215 0.363492399454 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.546461105347 0.726369321346 0.416854739189 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.618004083633 0.135420069098 0.774423897266 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.543861091137 0.085662640631 0.834791600704 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.819668352604 0.424242556095 0.384918212891 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.813350260258 0.528666734695 0.242843255401 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.407970279455 0.717792689800 0.564210891724 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.605787634850 0.494257092476 0.623483181000 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.969513058662 0.062274549156 0.236994311213 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.059391405433 0.995314598083 0.076298937201 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.030940596014 0.946716606617 0.320578128099 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.972541630268 0.205112487078 0.109961979091 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.572210907936 0.744452595711 0.344042211771 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.036019083112 0.815896332264 0.577075183392 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.811857640743 0.316165834665 0.490842521191 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.505996525288 0.084093302488 0.858426392078 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.372912973166 0.711369335651 0.595726132393 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.075495623052 0.638999342918 0.765493452549 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.237984761596 0.763823807240 0.599947035313 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.171342536807 0.505555272102 0.845609605312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.209175691009 0.608960092068 0.765122950077 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.209175691009 0.608960092068 0.765122950077 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.908309876919 0.015843641013 0.417997717857 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.448863714933 0.183967590332 0.874458312988 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.819909214973 0.467708528042 0.330147922039 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.972455918789 0.091722354293 0.214281424880 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.707751631737 0.511009931564 0.487807840109 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.648009002209 0.425326675177 0.631808161736 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.716207981110 0.499084711075 0.487812042236 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.629050672054 0.575037002563 0.523094296455 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.496823996305 0.472443997860 0.727985262871 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.521306455135 0.467230886221 0.714097201824 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.787957370281 0.477610796690 0.388601541519 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.518603384495 0.300804406404 0.800354421139 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.997338175774 0.072519011796 0.007588622160 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.700886607170 0.338039726019 0.628082096577 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.571633458138 0.247708499432 0.782224833965 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.674985289574 0.334197402000 0.657804667950 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.655655622482 0.397478044033 0.641971111298 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.605633556843 0.573746502399 0.551382780075 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.578698873520 0.646696209908 0.496881872416 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.734525084496 0.400696694851 0.547644972801 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.519214332104 0.253620952368 0.816145122051 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.508684575558 0.100909605622 0.855018854141 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.482553303242 0.293915122747 0.825079500675 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.143501415849 0.469171375036 0.871369957924 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.532382369041 0.165311589837 0.830205440521 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.265235602856 0.751007497311 0.604679942131 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.438396394253 0.250405520201 0.863195061684 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.184828087687 0.570850193501 0.799980401993 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.339759290218 0.652270197868 0.677574515343 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.975914239883 0.216983765364 0.022570852190 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.437682479620 0.131488755345 0.889463186264 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.693001866341 0.498886138201 0.520443081856 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.890769839287 0.184809222817 0.415180265903 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.616071522236 0.741670787334 0.265292972326 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.983508825302 0.178707674146 0.027819553390 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.657146453857 0.579351842403 0.482192873955 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.677771806717 0.617188751698 0.399629086256 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.610949575901 0.705598056316 0.358987480402 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.518502652645 0.501994550228 0.692211270332 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.461553364992 0.375474810600 0.803733229637 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.731816112995 0.506709039211 0.455731421709 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.310053557158 0.172868609428 0.934870719910 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.531211972237 0.828068792820 0.179209098220 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.296533823013 0.937092840672 0.184186592698 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.879008293152 0.327037870884 0.346973568201 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.418872237206 0.170925334096 0.891813099384 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.073301777244 0.768137931824 0.636074662209 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.106712952256 0.917102098465 0.384104311466 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.482846260071 0.869433462620 0.104618154466 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.087274819613 0.444357991219 0.891587972641 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.383311569691 0.245430797338 0.890413403511 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.368794947863 0.655544221401 0.658978044987 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.432463288307 0.539263606071 0.722613453865 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.196437984705 0.667735934258 0.718011736870 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.606201291084 0.206537902355 0.768024802208 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.513534486294 0.648863255978 0.561479091644 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.426534503698 0.658479154110 0.620059251785 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.449752897024 0.215031251311 0.866881728172 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.220938414335 0.246594354510 0.943598151207 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.525134205818 0.469024330378 0.710105836391 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.518878757954 0.427382588387 0.740343809128 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.418460667133 0.901152551174 0.113202057779 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.898592233658 0.382915318012 0.214261218905 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.582837760448 0.017110457644 0.812408387661 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.125691637397 0.965929806232 0.226232767105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.716074943542 0.144961029291 0.682805240154 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.429535895586 0.902928054333 0.014827483334 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.925961256027 0.377290695906 0.015729881823 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.934488713741 0.355977147818 0.003339467803 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn -0.364090979099 0.029598439112 0.930892944336 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.030472742394 0.502272367477 0.864172399044 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.048600327224 0.791139721870 0.609701573849 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.441782504320 0.297333627939 0.846416532993 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.184340089560 0.964558541775 0.188800379634 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.964621126652 0.160373017192 0.209252431989 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.945016801357 0.013837653212 0.326728969812 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.757342994213 0.639263868332 0.133316561580 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.689539670944 0.551088571548 0.469932347536 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.934458494186 0.322290331125 0.151381283998 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.547749757767 0.077166840434 0.833075940609 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.777829766273 0.488033413887 0.395985156298 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.326971471310 0.053588666022 0.943513572216 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.067655861378 0.094781979918 0.993196368217 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.004601359833 0.522861719131 0.852405130863 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.423879355192 0.904768526554 0.041475951672 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.313855469227 0.815999209881 0.485427707434 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.952248871326 0.304680645466 0.019794657826 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.343221575022 0.333233237267 0.878154039383 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.765450656414 0.598935127258 0.235291317105 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.720277249813 0.069460451603 0.690199911594 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.301544338465 0.953448176384 0.002751463326 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.793979823589 0.261099308729 0.549020230770 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn 0.229095175862 0.971845209599 0.055066000670 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.298334419727 0.949311316013 0.099018156528 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.195449680090 0.978367269039 0.067800879478 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.580564439297 0.618157505989 0.529930353165 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.148294940591 0.763890028000 0.628076970577 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.260491907597 0.307280063629 0.915272057056 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.162017181516 0.796604990959 0.582383811474 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.094890594482 0.167634546757 0.981271862984 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.965605020523 0.107465490699 0.236765861511 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.068652406335 0.974390566349 0.214125752449 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.716325759888 0.585582971573 0.379433780909 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.930489718914 -0.261996328831 -0.256021112204 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.967172682285 0.241761222482 0.078284777701 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn -0.344990402460 -0.115646079183 -0.931454539299 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.255546450615 -0.236742943525 -0.937362670898 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn 0.385443925858 0.300371497869 -0.872473478317 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.817613303661 0.347829401493 0.458828032017 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn 0.624225676060 -0.733383476734 -0.269241482019 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.913559436798 -0.390938848257 -0.112142503262 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.434841871262 0.650471568108 -0.622735321522 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.206277325749 0.496593266726 -0.843116104603 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.275574177504 0.178359404206 0.944588184357 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.318132579327 0.109800979495 0.941666305065 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.864802479744 0.500968754292 0.033867362887 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.609832704067 0.779186606407 0.144818082452 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.676929712296 0.735970973969 0.010624704883 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.730528593063 0.682668983936 0.017058826983 -vn 0.676929712296 0.735970973969 0.010624704883 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.067695811391 0.526292204857 0.847604751587 -vn -0.394177705050 0.541026473045 0.742909312248 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.052583612502 0.985693454742 0.160135433078 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.026022652164 0.988108336926 0.151541069150 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn 0.116307489574 0.990462958813 0.073862694204 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.040402501822 0.989431560040 0.139258161187 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.052583612502 0.985693454742 0.160135433078 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.134896829724 0.973662376404 0.183805242181 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.011763782240 0.995036125183 0.098816752434 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.026022652164 0.988108336926 0.151541069150 -vn -0.018820434809 0.989357590675 0.144282087684 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.914270520210 -0.374885022640 -0.153527349234 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.469311714172 -0.101307049394 0.877202033997 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn 0.465971797705 0.054153501987 -0.883140802383 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.448319792747 0.129651442170 -0.884420633316 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.167976438999 0.232479542494 0.957985997200 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.301698088646 0.951182126999 0.065044857562 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.171455085278 0.914633154869 0.366127461195 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.215676337481 0.968818902969 0.121957629919 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.473818302155 0.648060023785 0.596250295639 -vn 0.116785392165 0.979833245277 0.162135779858 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.248102903366 0.886689305305 0.390162765980 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.745227813721 0.633083999157 0.209380432963 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.812033295631 0.514916896820 0.274704486132 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.237624734640 0.624630987644 0.743888854980 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.454803496599 0.485992193222 0.746301114559 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.382084578276 0.771323442459 0.508990705013 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.392548322678 0.780418395996 0.486675381660 -vn -0.382084578276 0.771323442459 0.508990705013 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.218308880925 0.796049535275 0.564487636089 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.147346720099 0.889737486839 0.432037174702 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.598508119583 0.249849140644 0.761159241199 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.181642502546 0.885934293270 0.426762789488 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.424639850855 0.811399281025 0.401636928320 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.077389903367 0.914463222027 0.397199958563 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.669492661953 0.064479798079 0.740014791489 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.545027732849 0.737514972687 0.398768693209 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.743179678917 0.068944804370 0.665530264378 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.553945541382 0.699680268764 0.451211482286 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.436596006155 0.685988366604 0.582068622112 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.436596006155 0.685988366604 0.582068622112 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.298728913069 0.741523385048 0.600752949715 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.936779797077 0.026538468897 0.348911702633 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887424767017 0.078465610743 0.454225122929 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.030449874699 -0.613143086433 -0.789384782314 -vn -0.030449874699 -0.613143146038 -0.789384782314 -vn -0.030449876562 -0.613143146038 -0.789384782314 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295757294 -0.699427545071 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.373588293791 0.906539082527 0.196516364813 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.388561308384 0.831142783165 0.397771000862 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.008125438355 0.822232007980 0.569094419479 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.114516958594 0.788044095039 0.604873836040 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.415789157152 0.681671321392 0.602032840252 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.143064171076 0.886963069439 0.439123153687 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.829526424408 0.541623890400 0.136123031378 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.564102113247 0.009641343728 0.825648725033 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.236986622214 0.101993352175 0.966144263744 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.203997373581 0.026348058134 0.978616833687 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.132363051176 0.588919281960 0.797279179096 -vn 0.370204120874 0.758121490479 0.536843240261 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.227597177029 0.752148985863 0.618442714214 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.671189248562 0.679710924625 0.295800745487 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.132539749146 0.945317745209 0.298005938530 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.263727605343 0.610503315926 0.746815502644 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.020327450708 0.685757458210 0.727546215057 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.047376774251 0.985158741474 0.164977937937 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.050312381238 0.219402447343 0.974336326122 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.075094878674 0.432029217482 0.898727715015 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.263161271811 0.103435955942 0.959190905094 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.453169703484 0.481266558170 0.750346422195 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.660578846931 0.637442171574 0.396614521742 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.204309478402 0.943660676479 0.260311752558 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.179308205843 0.861584722996 0.474889785051 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.196217641234 0.079919569194 0.977298080921 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.087292499840 0.331456899643 0.939423382282 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.534430682659 0.838877797127 0.103285685182 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.560695827007 0.078877851367 0.824256300926 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.881415486336 0.472221165895 0.010672469623 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.283379137516 0.492464959621 0.822906136513 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.131599500775 0.737507283688 0.662393093109 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.119672834873 0.101008400321 0.987661719322 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.354700446129 0.034820698202 0.934331357479 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.314111679792 0.058616135269 0.947574794292 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.027125038207 0.236739024520 0.971194565296 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.334633797407 0.108778014779 0.936048924923 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.987220883369 0.152396500111 0.046585436910 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.506033003330 0.457370489836 0.731261134148 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.290093451738 0.940565109253 0.176587253809 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.645085215569 0.203440889716 0.736530244350 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.254643589258 0.460702836514 0.850240886211 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.317261904478 0.790387809277 0.524053394794 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.487584769726 0.575793743134 0.656294643879 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.288535594940 0.014455531724 0.957360029221 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.936993002892 0.101482637227 0.334283322096 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.234883025289 0.208845853806 0.949322581291 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.094372428954 0.461883842945 0.881905436516 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.125300318003 0.134481579065 0.982962131500 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.092569380999 0.481423765421 0.871585965157 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.090679392219 0.816002249718 0.570891857147 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.065149024129 0.968082070351 0.242018088698 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.214608341455 0.516929745674 0.828689873219 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.363941878080 0.109785512090 0.924928903580 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.327142566442 0.847049534321 0.418909132481 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.373320966959 0.424053817987 0.825111985207 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.378446906805 0.448631554842 0.809634268284 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.182598531246 0.715381562710 0.674453139305 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.421047270298 0.334669202566 0.843039572239 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.883379578590 0.453356623650 0.118778400123 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.334695070982 0.126260608435 0.933829486370 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.748294830322 0.242019072175 0.617641985416 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.291076213121 0.481702655554 0.826581597328 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.190369337797 0.409592747688 0.892184555531 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.270152628422 0.623499035835 0.733666479588 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.193748310208 0.389752209187 0.900308191776 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.080102473497 0.828760683537 0.553840458393 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.469709098339 0.664078414440 0.581698536873 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn 0.057261314243 0.891568779945 0.449250817299 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.489686667919 0.504504680634 0.711113214493 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.465997457504 0.474939972162 0.746510803699 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.104101993144 0.368369311094 0.923832714558 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.256318479776 0.039006829262 0.965804994106 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.148606613278 0.474946022034 0.867376685143 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.012771333568 0.858014822006 0.513466119766 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.067125074565 0.157456219196 0.985242009163 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.202230855823 0.135011807084 0.969986855984 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.027015432715 0.338717550039 0.940500199795 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.069257460535 0.874967575073 0.479202568531 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.266394942999 0.146734341979 0.952629387379 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.069257460535 0.874967575073 0.479202568531 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.125801399350 0.381812900305 0.915637969971 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.246009349823 0.853070199490 0.460163712502 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.084336921573 0.993597984314 0.075168356299 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.211031064391 0.334258556366 0.918551623821 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.005775345955 0.566921889782 0.823751330376 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.022682305425 0.700176298618 0.713609576225 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.158913969994 0.649801671505 0.743306219578 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.425227582455 0.791610717773 0.438786923885 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.905587971210 0.151429876685 0.396206259727 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.506390750408 0.538258075714 0.673681437969 -vn -0.299555271864 0.546643376350 0.781951189041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.203431159258 0.979057490826 0.007884264924 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.288760930300 0.908043682575 0.303436666727 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.707089662552 0.699392676353 0.104278922081 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.105939380825 0.093255937099 0.989989995956 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.924340128899 0.360457271338 0.125163570046 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.395210921764 0.116690479219 0.911148548126 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.215249896049 0.259879410267 0.941344857216 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.347879409790 0.817592084408 0.458827942610 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.254123061895 0.426116853952 0.868242979050 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.201308771968 0.240931555629 0.949434995651 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.240289658308 0.320749431849 0.916177213192 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.680037975311 0.480506420135 0.553770661354 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.219177588820 0.295268416405 0.929934263229 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.225854665041 0.275281429291 0.934456944466 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.680287778378 0.480499923229 0.553469419479 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.658345997334 0.509523391724 0.554045557976 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.211771011353 0.234253704548 0.948829948902 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.213284403086 0.286679387093 0.933983266354 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn 0.570412695408 0.657898664474 0.491730272770 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.227320805192 0.221673280001 0.948254287243 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.153622061014 0.138630852103 0.978356659412 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.551810741425 0.698545396328 0.455564767122 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.543161213398 0.695157170296 0.470884680748 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.263800501823 0.365938633680 0.892467498779 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.117148451507 0.034600071609 0.992511510849 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.706371426582 0.398818373680 0.584793448448 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.168904587626 0.153192564845 0.973654627800 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.696267127991 0.416324853897 0.584709942341 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.804239809513 -0.440206110477 0.399270415306 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473841011524 -0.329637020826 -0.816586852074 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.838858008385 0.494629532099 0.227285787463 -vn 0.804961979389 0.551999032497 0.217562019825 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.675563931465 0.163798823953 0.718876481056 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn -0.600282192230 -0.662484288216 -0.448080182076 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.223079264164 -0.842810750008 0.489801704884 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.769818246365 0.161918729544 0.617383360863 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.769818246365 0.161918729544 0.617383360863 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn 0.298304438591 0.947766005993 -0.112933620811 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.218723073602 0.307124495506 0.926193714142 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.676530897617 0.479380965233 0.559016883373 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.231893524528 0.286410689354 0.929620504379 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.681994259357 0.479156374931 0.552533268929 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.206624403596 0.240915045142 0.948296546936 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.206473186612 0.250022917986 0.945968985558 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.226969450712 0.276726186275 0.933759868145 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.272610336542 0.367797374725 0.889049291611 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.582295238972 0.388309806585 0.714246273041 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.660991668701 0.493317723274 0.565444648266 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.370886951685 0.612930238247 0.697681427002 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn 0.229398831725 0.792460381985 -0.565139591694 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.221627816558 0.735603809357 -0.640131354332 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn 0.199336946011 0.966365575790 -0.162488013506 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.526178479195 0.778710901737 -0.341680556536 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.005032873247 -0.546992003918 0.837122738361 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.058633551002 -0.727339625359 0.683768332005 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.601092875004 -0.198408842087 0.774158477783 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.286670923233 0.777926385403 -0.559151470661 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.316740483046 0.940792977810 -0.120764441788 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.766251981258 0.386263102293 0.513477087021 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.679944336414 0.429292380810 0.594460844994 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755384206772 0.451619952917 0.474799036980 -vn -0.714168488979 0.133881628513 0.687050998211 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.696129977703 0.598392426968 0.396647810936 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.218742683530 -0.747778773308 0.626880049706 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.336433708668 -0.580547392368 0.741469502449 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.292118996382 -0.289201915264 0.911607801914 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.676289498806 0.234662115574 0.698259413242 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.822031438351 -0.366936504841 -0.435455977917 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.833994865417 -0.328578948975 -0.443270176649 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.667977154255 -0.468124926090 -0.578502893448 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn 0.605304896832 -0.786918938160 0.119852282107 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.644578337669 -0.723311424255 0.247667729855 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.576117694378 0.644429028034 0.502791821957 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.706421017647 0.534547507763 0.463927060366 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.041993357241 0.797598063946 0.601725757122 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.378463476896 0.783811092377 0.492346972227 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.740822911263 0.609460711479 0.282381057739 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.817769885063 0.481556564569 0.315207391977 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn 0.581513226032 0.206123635173 -0.786991357803 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.595149517059 -0.417273491621 -0.686789572239 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn -0.537571310997 0.772639870644 -0.337705105543 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.495952785015 0.803755402565 -0.328645855188 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.629080116749 -0.764525115490 0.140568733215 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627170860767 -0.766199529171 0.139982149005 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.599086761475 -0.409433424473 -0.688083827496 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.700512945652 -0.458336979151 -0.546999812126 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.572836101055 0.156684830785 0.804554939270 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn 0.354127824306 -0.701984345913 0.617908954620 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.356339871883 -0.698108613491 0.621020376682 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.830982983112 0.368793278933 0.416483879089 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.830982983112 0.368793278933 0.416483879089 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.221020415425 0.617830932140 0.754609107971 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.235830068588 0.898830175400 0.369443446398 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.395072251558 0.917763888836 0.040340516716 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.169255286455 0.259556770325 0.950780153275 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.194399654865 0.158964470029 0.967956125736 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.197535604239 0.024697216228 0.979984581470 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.427116841078 0.346271544695 0.835264742374 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.226580724120 0.800231337547 0.555239558220 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.274038642645 0.932397603989 0.235664024949 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.067393772304 0.322359681129 0.944215178490 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.074658878148 0.311024487019 0.947464942932 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155109524727 0.599816203117 0.784959554672 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.990912795067 0.127940833569 0.041508488357 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.171049833298 0.970419943333 0.170373469591 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.086038894951 0.984414279461 0.153381422162 -vn 0.083577327430 0.994467854500 0.063627921045 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.023173412308 0.995078146458 0.096345901489 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.063926614821 0.963856279850 0.258639603853 -vn -0.375237524509 0.793154478073 0.479690253735 -vn -0.350450277328 0.809412717819 0.471206605434 -vn -0.350450277328 0.809412717819 0.471206605434 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.577268898487 0.306803852320 0.756724536419 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.185570269823 0.171825677156 0.967491388321 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.487122595310 0.042172510177 0.872314751148 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn -0.268814533949 0.206545710564 0.940785646439 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.180396959186 0.971246838570 0.155359238386 -vn -0.194942057133 0.976504385471 0.091851882637 -# 32013 vertex normals - -vt 0.377155363560 0.858360707760 0.000000000000 -vt 0.377155363560 0.848666846752 0.000000000000 -vt 0.387879788876 0.848666846752 0.000000000000 -vt 0.387879788876 0.858360707760 0.000000000000 -vt 0.377155363560 0.838978648186 0.000000000000 -vt 0.387879788876 0.838978648186 0.000000000000 -vt 0.377155363560 0.829283058643 0.000000000000 -vt 0.387879788876 0.829283058643 0.000000000000 -vt 0.377155363560 0.984480679035 0.000000000000 -vt 0.377155363560 0.974780797958 0.000000000000 -vt 0.387879788876 0.974780797958 0.000000000000 -vt 0.387879788876 0.984480679035 0.000000000000 -vt 0.377155363560 0.965079963207 0.000000000000 -vt 0.387879788876 0.965079963207 0.000000000000 -vt 0.377155363560 0.955380022526 0.000000000000 -vt 0.387879788876 0.955380022526 0.000000000000 -vt 0.377155363560 0.945681273937 0.000000000000 -vt 0.387879788876 0.945681273937 0.000000000000 -vt 0.377155363560 0.935981333256 0.000000000000 -vt 0.387879788876 0.935981333256 0.000000000000 -vt 0.377155363560 0.926279187202 0.000000000000 -vt 0.387879788876 0.926279187202 0.000000000000 -vt 0.377155363560 0.916576147079 0.000000000000 -vt 0.387879788876 0.916576147079 0.000000000000 -vt 0.377155363560 0.906873524189 0.000000000000 -vt 0.387879788876 0.906873524189 0.000000000000 -vt 0.377155363560 0.897172033787 0.000000000000 -vt 0.387879788876 0.897172033787 0.000000000000 -vt 0.377155363560 0.887470304966 0.000000000000 -vt 0.387879788876 0.887470304966 0.000000000000 -vt 0.377155363560 0.877766370773 0.000000000000 -vt 0.387879788876 0.877766370773 0.000000000000 -vt 0.377155363560 0.868061482906 0.000000000000 -vt 0.387879788876 0.868061482906 0.000000000000 -vt 0.389967858791 0.848666846752 0.000000000000 -vt 0.389967858791 0.858360707760 0.000000000000 -vt 0.389223754406 0.858360707760 0.000000000000 -vt 0.389223754406 0.848666846752 0.000000000000 -vt 0.389967858791 0.838978648186 0.000000000000 -vt 0.389223754406 0.838978648186 0.000000000000 -vt 0.389967858791 0.829283058643 0.000000000000 -vt 0.389223754406 0.829283058643 0.000000000000 -vt 0.389967858791 0.974780797958 0.000000000000 -vt 0.389967858791 0.984480679035 0.000000000000 -vt 0.389223754406 0.984480679035 0.000000000000 -vt 0.389223754406 0.974780797958 0.000000000000 -vt 0.389967858791 0.965079963207 0.000000000000 -vt 0.389223754406 0.965079963207 0.000000000000 -vt 0.389967858791 0.955380022526 0.000000000000 -vt 0.389223754406 0.955380022526 0.000000000000 -vt 0.389967858791 0.945681273937 0.000000000000 -vt 0.389223754406 0.945681273937 0.000000000000 -vt 0.389967858791 0.935981333256 0.000000000000 -vt 0.389223754406 0.935981333256 0.000000000000 -vt 0.389967858791 0.926279187202 0.000000000000 -vt 0.389223754406 0.926279187202 0.000000000000 -vt 0.389967858791 0.916576147079 0.000000000000 -vt 0.389223754406 0.916576147079 0.000000000000 -vt 0.389967858791 0.906873524189 0.000000000000 -vt 0.389223754406 0.906873524189 0.000000000000 -vt 0.389967858791 0.897172033787 0.000000000000 -vt 0.389223754406 0.897172033787 0.000000000000 -vt 0.389967858791 0.887470304966 0.000000000000 -vt 0.389223754406 0.887470304966 0.000000000000 -vt 0.389967858791 0.877766370773 0.000000000000 -vt 0.389223754406 0.877766370773 0.000000000000 -vt 0.389967858791 0.868061482906 0.000000000000 -vt 0.389223754406 0.868061482906 0.000000000000 -vt 0.391293346882 0.858360707760 0.000000000000 -vt 0.391293346882 0.848666846752 0.000000000000 -vt 0.396203100681 0.848666846752 0.000000000000 -vt 0.396203100681 0.858360707760 0.000000000000 -vt 0.391293346882 0.838978648186 0.000000000000 -vt 0.396203100681 0.838978648186 0.000000000000 -vt 0.391293346882 0.829283058643 0.000000000000 -vt 0.396203100681 0.829283058643 0.000000000000 -vt 0.391293346882 0.984480679035 0.000000000000 -vt 0.391293346882 0.974780797958 0.000000000000 -vt 0.396203100681 0.974780797958 0.000000000000 -vt 0.396203100681 0.984480679035 0.000000000000 -vt 0.391293346882 0.965079963207 0.000000000000 -vt 0.396203100681 0.965079963207 0.000000000000 -vt 0.391293346882 0.955380022526 0.000000000000 -vt 0.396203100681 0.955380022526 0.000000000000 -vt 0.391293346882 0.945681273937 0.000000000000 -vt 0.396203100681 0.945681273937 0.000000000000 -vt 0.391293346882 0.935981333256 0.000000000000 -vt 0.396203100681 0.935981333256 0.000000000000 -vt 0.391293346882 0.926279187202 0.000000000000 -vt 0.396203100681 0.926279187202 0.000000000000 -vt 0.391293346882 0.916576147079 0.000000000000 -vt 0.396203100681 0.916576147079 0.000000000000 -vt 0.391293346882 0.906873524189 0.000000000000 -vt 0.396203100681 0.906873524189 0.000000000000 -vt 0.391293346882 0.897172033787 0.000000000000 -vt 0.396203100681 0.897172033787 0.000000000000 -vt 0.391293346882 0.887470304966 0.000000000000 -vt 0.396203100681 0.887470304966 0.000000000000 -vt 0.391293346882 0.877766370773 0.000000000000 -vt 0.396203100681 0.877766370773 0.000000000000 -vt 0.391293346882 0.868061482906 0.000000000000 -vt 0.396203100681 0.868061482906 0.000000000000 -vt 0.409175425768 0.672242879868 0.000000000000 -vt 0.452760726213 0.666515350342 0.000000000000 -vt 0.431881427765 0.692003369331 0.000000000000 -vt 0.481934756041 0.680083930492 0.000000000000 -vt 0.508225858212 0.789766192436 0.000000000000 -vt 0.553140699863 0.792127192020 0.000000000000 -vt 0.543430626392 0.810674130917 0.000000000000 -vt 0.493056267500 0.761313557625 0.000000000000 -vt 0.498380273581 0.738467097282 0.000000000000 -vt 0.515042841434 0.755405724049 0.000000000000 -vt 0.550852000713 0.845992863178 0.000000000000 -vt 0.577347338200 0.824143350124 0.000000000000 -vt 0.609382450581 0.854941427708 0.000000000000 -vt 0.665927231312 0.810042083263 0.000000000000 -vt 0.669713199139 0.747112154961 0.000000000000 -vt 0.691940128803 0.688431560993 0.000000000000 -vt 0.480293363333 0.580234348774 0.000000000000 -vt 0.515759050846 0.550068080425 0.000000000000 -vt 0.567890584469 0.594532608986 0.000000000000 -vt 0.623778641224 0.602010011673 0.000000000000 -vt 0.572804629803 0.544676065445 0.000000000000 -vt 0.631756961346 0.573595166206 0.000000000000 -vt 0.610680639744 0.688212931156 0.000000000000 -vt 0.650606334209 0.643516659737 0.000000000000 -vt 0.631374895573 0.713805377483 0.000000000000 -vt 0.451538383961 0.699487090111 0.000000000000 -vt 0.488095849752 0.712747395039 0.000000000000 -vt 0.505906522274 0.654317796230 0.000000000000 -vt 0.514503896236 0.621594429016 0.000000000000 -vt 0.546522319317 0.636798501015 0.000000000000 -vt 0.620644509792 0.650109648705 0.000000000000 -vt 0.536644995213 0.674807369709 0.000000000000 -vt 0.559180438519 0.677152156830 0.000000000000 -vt 0.546803295612 0.700395822525 0.000000000000 -vt 0.580495297909 0.670894205570 0.000000000000 -vt 0.560229241848 0.708388805389 0.000000000000 -vt 0.583466589451 0.746397972107 0.000000000000 -vt 0.590534269810 0.714147150517 0.000000000000 -vt 0.632254183292 0.742581784725 0.000000000000 -vt 0.392473429441 0.735891520977 0.000000000000 -vt 0.401782691479 0.699883401394 0.000000000000 -vt 0.437636852264 0.750069797039 0.000000000000 -vt 0.443033576012 0.728961050510 0.000000000000 -vt 0.467387497425 0.731456875801 0.000000000000 -vt 0.397550672293 0.599925756454 0.000000000000 -vt 0.443568110466 0.613210141659 0.000000000000 -vt 0.366362631321 0.656876027584 0.000000000000 -vt 0.447481751442 0.559440612793 0.000000000000 -vt 0.601355612278 0.819214940071 0.000000000000 -vt 0.636718928814 0.797729492188 0.000000000000 -vt 0.619128763676 0.819936096668 0.000000000000 -vt 0.559825360775 0.776961624622 0.000000000000 -vt 0.572190821171 0.759399116039 0.000000000000 -vt 0.604671776295 0.773796379566 0.000000000000 -vt 0.554654181004 0.617363810539 0.000000000000 -vt 0.567634403706 0.651618182659 0.000000000000 -vt 0.590938866138 0.618936240673 0.000000000000 -vt 0.596868813038 0.647921144962 0.000000000000 -vt 0.651719510555 0.782778739929 0.000000000000 -vt 0.614525854588 0.755118906498 0.000000000000 -vt 0.455462366343 0.816022455692 0.000000000000 -vt 0.450997769833 0.780333817005 0.000000000000 -vt 0.483516186476 0.802494883537 0.000000000000 -vt 0.485845893621 0.853235423565 0.000000000000 -vt 0.417244762182 0.840927124023 0.000000000000 -vt 0.433641225100 0.829533994198 0.000000000000 -vt 0.477579563856 0.870459556580 0.000000000000 -vt 0.530758202076 0.857129693031 0.000000000000 -vt 0.544338524342 0.876446247101 0.000000000000 -vt 0.532405674458 0.712911307812 0.000000000000 -vt 0.526134669781 0.742851078510 0.000000000000 -vt 0.547361195087 0.739448964596 0.000000000000 -vt 0.567548215389 0.558903396130 0.000000000000 -vt 0.397433131933 0.817093312740 0.000000000000 -vt 0.514106690884 0.777620911598 0.000000000000 -vt 0.462766647339 0.752251565456 0.000000000000 -vt 0.460485816002 0.643762111664 0.000000000000 -vt 0.485318392515 0.636485338211 0.000000000000 -vt 0.480034440756 0.664412677288 0.000000000000 -vt 0.630446612835 0.777688920498 0.000000000000 -vt 0.600008070469 0.799526214600 0.000000000000 -vt 0.476415723562 0.779506325722 0.000000000000 -vt 0.473682790995 0.610604822636 0.000000000000 -vt 0.675627768040 0.625576317310 0.000000000000 -vt 0.565741121769 0.800483822823 0.000000000000 -vt 0.356244146824 0.722902357578 0.000000000000 -vt 0.588402211666 0.811188578606 0.000000000000 -vt 0.518669903278 0.699171006680 0.000000000000 -vt 0.535777628422 0.658217966557 0.000000000000 -vt 0.508222043514 0.539263308048 0.000000000000 -vt 0.648145139217 0.728081822395 0.000000000000 -vt 0.514887988567 0.819228231907 0.000000000000 -vt 0.480209141970 0.748140454292 0.000000000000 -vt 0.594826638699 0.678737699986 0.000000000000 -vt 0.609615743160 0.711115896702 0.000000000000 -vt 0.374209046364 0.788166940212 0.000000000000 -vt 0.696136057377 0.841438889503 0.000000000000 -vt 0.697102844715 0.847001552582 0.000000000000 -vt 0.687970817089 0.838945984840 0.000000000000 -vt 0.676894485950 0.837039768696 0.000000000000 -vt 0.668740808964 0.834839344025 0.000000000000 -vt 0.658680617809 0.855564236641 0.000000000000 -vt 0.651980459690 0.853254318237 0.000000000000 -vt 0.694596707821 0.852629542351 0.000000000000 -vt 0.685916483402 0.854809284210 0.000000000000 -vt 0.674534022808 0.855843186378 0.000000000000 -vt 0.665389955044 0.856125533581 0.000000000000 -vt 0.650012195110 0.834412455559 0.000000000000 -vt 0.656730353832 0.833129286766 0.000000000000 -vt 0.646296203136 0.841373562813 0.000000000000 -vt 0.688886702061 0.834426641464 0.000000000000 -vt 0.699207842350 0.838674664497 0.000000000000 -vt 0.697359144688 0.855724990368 0.000000000000 -vt 0.686487972736 0.859591126442 0.000000000000 -vt 0.702463567257 0.847452104092 0.000000000000 -vt 0.677858173847 0.832566380501 0.000000000000 -vt 0.674788177013 0.860633373260 0.000000000000 -vt 0.656709134579 0.828647792339 0.000000000000 -vt 0.663522779942 0.828503489494 0.000000000000 -vt 0.663026511669 0.833329021931 0.000000000000 -vt 0.665229976177 0.860744595528 0.000000000000 -vt 0.646054327488 0.849184870720 0.000000000000 -vt 0.944440543652 0.577088952065 0.000000000000 -vt 0.934413731098 0.578397750854 0.000000000000 -vt 0.933311760426 0.570732593536 0.000000000000 -vt 0.942559897900 0.569070458412 0.000000000000 -vt 0.878645479679 0.586926877499 0.000000000000 -vt 0.868258655071 0.588900566101 0.000000000000 -vt 0.867458641529 0.580585360527 0.000000000000 -vt 0.877176105976 0.579317748547 0.000000000000 -vt 0.952389657497 0.575497746468 0.000000000000 -vt 0.950832903385 0.567034423351 0.000000000000 -vt 0.923831403255 0.579496085644 0.000000000000 -vt 0.923619329929 0.572405040264 0.000000000000 -vt 0.628452599049 0.873331427574 0.000000000000 -vt 0.632204830647 0.876753568649 0.000000000000 -vt 0.628753483295 0.881655633450 0.000000000000 -vt 0.623970210552 0.878167748451 0.000000000000 -vt 0.646685302258 0.866765677929 0.000000000000 -vt 0.656351864338 0.871634185314 0.000000000000 -vt 0.653122007847 0.874798536301 0.000000000000 -vt 0.645847260952 0.871063649654 0.000000000000 -vt 0.726799309254 0.837845385075 0.000000000000 -vt 0.661485850811 0.880055904388 0.000000000000 -vt 0.656600654125 0.882020831108 0.000000000000 -vt 0.636110603809 0.868256449699 0.000000000000 -vt 0.637845695019 0.872147083282 0.000000000000 -vt 0.649987399578 0.877419590950 0.000000000000 -vt 0.644934833050 0.875803411007 0.000000000000 -vt 0.639724314213 0.875453293324 0.000000000000 -vt 0.650543510914 0.882872819901 0.000000000000 -vt 0.637335002422 0.879814982414 0.000000000000 -vt 0.635132730007 0.885670363903 0.000000000000 -vt 0.643860280514 0.881775856018 0.000000000000 -vt 0.642733037472 0.850792288780 0.000000000000 -vt 0.641889035702 0.840179145336 0.000000000000 -vt 0.669664084911 0.830182671547 0.000000000000 -vt 0.650239527225 0.857445180416 0.000000000000 -vt 0.648015201092 0.831698417664 0.000000000000 -vt 0.642690360546 0.888261675835 0.000000000000 -vt 0.663629949093 0.887337207794 0.000000000000 -vt 0.657781779766 0.889087080956 0.000000000000 -vt 0.889635980129 0.584733188152 0.000000000000 -vt 0.887632310390 0.577965676785 0.000000000000 -vt 0.898609101772 0.583011865616 0.000000000000 -vt 0.896672070026 0.576863348484 0.000000000000 -vt 0.915674507618 0.580389678478 0.000000000000 -vt 0.915229618549 0.574002265930 0.000000000000 -vt 0.657724201679 0.860278069973 0.000000000000 -vt 0.930922925472 0.558675527573 0.000000000000 -vt 0.650379359722 0.889898777008 0.000000000000 -vt 0.939678132534 0.556469440460 0.000000000000 -vt 0.867106497288 0.567602217197 0.000000000000 -vt 0.875806748867 0.567502915859 0.000000000000 -vt 0.947033226490 0.554314255714 0.000000000000 -vt 0.922403037548 0.561220228672 0.000000000000 -vt 0.885274112225 0.567466676235 0.000000000000 -vt 0.658997356892 0.896231293678 0.000000000000 -vt 0.649604141712 0.899704515934 0.000000000000 -vt 0.895252883434 0.566620349884 0.000000000000 -vt 0.719376146793 0.837280273438 0.000000000000 -vt 0.918815433979 0.545299708843 0.000000000000 -vt 0.910051763058 0.547324061394 0.000000000000 -vt 0.907046377659 0.529140114784 0.000000000000 -vt 0.916585505009 0.527373969555 0.000000000000 -vt 0.899707138538 0.530310690403 0.000000000000 -vt 0.641025960445 0.896537065506 0.000000000000 -vt 0.901793301105 0.548481404781 0.000000000000 -vt 0.927321612835 0.542573332787 0.000000000000 -vt 0.632426559925 0.894321084023 0.000000000000 -vt 0.625132262707 0.886998593807 0.000000000000 -vt 0.717746436596 0.831090271473 0.000000000000 -vt 0.725946605206 0.830549895763 0.000000000000 -vt 0.735287845135 0.838093996048 0.000000000000 -vt 0.734414517879 0.830852091312 0.000000000000 -vt 0.717679798603 0.825329720974 0.000000000000 -vt 0.723944962025 0.823542177677 0.000000000000 -vt 0.732950508595 0.823792576790 0.000000000000 -vt 0.739792287350 0.825830638409 0.000000000000 -vt 0.741621911526 0.831147015095 0.000000000000 -vt 0.741378247738 0.836689889431 0.000000000000 -vt 0.665112435818 0.894209623337 0.000000000000 -vt 0.620138943195 0.882827579975 0.000000000000 -vt 0.936108648777 0.539952039719 0.000000000000 -vt 0.867212593555 0.550016939640 0.000000000000 -vt 0.875978291035 0.550476253033 0.000000000000 -vt 0.943726122379 0.537669897079 0.000000000000 -vt 0.884841740131 0.551008760929 0.000000000000 -vt 0.913087069988 0.563861310482 0.000000000000 -vt 0.893644869328 0.550148010254 0.000000000000 -vt 0.892628490925 0.531013190746 0.000000000000 -vt 0.904061496258 0.562744498253 0.000000000000 -vt 0.926213800907 0.525771796703 0.000000000000 -vt 0.934501111507 0.523906171322 0.000000000000 -vt 0.865935027599 0.533409059048 0.000000000000 -vt 0.875216186047 0.532836914063 0.000000000000 -vt 0.942422688007 0.521042168140 0.000000000000 -vt 0.884195983410 0.531999826431 0.000000000000 -vt 0.924653232098 0.517368316650 0.000000000000 -vt 0.932635247707 0.517127633095 0.000000000000 -vt 0.914257109165 0.519580006599 0.000000000000 -vt 0.906176626682 0.522352159023 0.000000000000 -vt 0.899168789387 0.522687613964 0.000000000000 -vt 0.892163813114 0.523706674576 0.000000000000 -vt 0.884188354015 0.523065209389 0.000000000000 -vt 0.873883426189 0.524219810963 0.000000000000 -vt 0.865347802639 0.526163995266 0.000000000000 -vt 0.858433783054 0.526082932949 0.000000000000 -vt 0.859899699688 0.590485215187 0.000000000000 -vt 0.858855664730 0.581898033619 0.000000000000 -vt 0.859369337559 0.568410336971 0.000000000000 -vt 0.859169065952 0.551045894623 0.000000000000 -vt 0.856827557087 0.534337580204 0.000000000000 -vt 0.937964379787 0.513839006424 0.000000000000 -vt 0.693465530872 0.814677596092 0.000000000000 -vt 0.700085699558 0.824197411537 0.000000000000 -vt 0.694888770580 0.822570204735 0.000000000000 -vt 0.692891776562 0.803992629051 0.000000000000 -vt 0.691710650921 0.795865237713 0.000000000000 -vt 0.711294472218 0.782084345818 0.000000000000 -vt 0.712714016438 0.788840830326 0.000000000000 -vt 0.708831012249 0.814877569675 0.000000000000 -vt 0.705738484859 0.822653293610 0.000000000000 -vt 0.711153686047 0.804187417030 0.000000000000 -vt 0.712479650974 0.795391499996 0.000000000000 -vt 0.700650393963 0.775034308434 0.000000000000 -vt 0.691504657269 0.783996403217 0.000000000000 -vt 0.693565666676 0.777675151825 0.000000000000 -vt 0.691854059696 0.825260579586 0.000000000000 -vt 0.688908874989 0.815112352371 0.000000000000 -vt 0.713424861431 0.816177845001 0.000000000000 -vt 0.708342850208 0.825807273388 0.000000000000 -vt 0.699830830097 0.829423010349 0.000000000000 -vt 0.688347995281 0.804415702820 0.000000000000 -vt 0.715837776661 0.805065751076 0.000000000000 -vt 0.690926015377 0.790131390095 0.000000000000 -vt 0.686091244221 0.790077388287 0.000000000000 -vt 0.687085330486 0.783463239670 0.000000000000 -vt 0.717056095600 0.795820415020 0.000000000000 -vt 0.700017035007 0.770576894283 0.000000000000 -vt 0.914225161076 0.695051312447 0.000000000000 -vt 0.916345059872 0.684997260571 0.000000000000 -vt 0.924999296665 0.686340272427 0.000000000000 -vt 0.923253715038 0.697034716606 0.000000000000 -vt 0.917016923428 0.620534837246 0.000000000000 -vt 0.915503799915 0.609951913357 0.000000000000 -vt 0.924802958965 0.608696460724 0.000000000000 -vt 0.925778567791 0.619882166386 0.000000000000 -vt 0.912027418613 0.704157292843 0.000000000000 -vt 0.921499311924 0.705678403378 0.000000000000 -vt 0.918580591679 0.674305975437 0.000000000000 -vt 0.926661670208 0.674895882607 0.000000000000 -vt 0.718583166599 0.876050651073 0.000000000000 -vt 0.713863432407 0.879810035229 0.000000000000 -vt 0.710420310497 0.875060856342 0.000000000000 -vt 0.714020431042 0.871412634850 0.000000000000 -vt 0.697144329548 0.869657814503 0.000000000000 -vt 0.690142214298 0.873365402222 0.000000000000 -vt 0.686877906322 0.870136678219 0.000000000000 -vt 0.696207225323 0.865324914455 0.000000000000 -vt 0.723377764225 0.855088472366 0.000000000000 -vt 0.686818659306 0.880428075790 0.000000000000 -vt 0.681876957417 0.878385961056 0.000000000000 -vt 0.704877674580 0.870628654957 0.000000000000 -vt 0.706442534924 0.866614162922 0.000000000000 -vt 0.698146879673 0.874422729015 0.000000000000 -vt 0.693293511868 0.876017093658 0.000000000000 -vt 0.703139483929 0.874020636082 0.000000000000 -vt 0.692841827869 0.881317675114 0.000000000000 -vt 0.707678377628 0.883993208408 0.000000000000 -vt 0.705496728420 0.878273785114 0.000000000000 -vt 0.700505435467 0.886600732803 0.000000000000 -vt 0.710137546062 0.772817432880 0.000000000000 -vt 0.708110511303 0.775850474834 0.000000000000 -vt 0.686994135380 0.796237647533 0.000000000000 -vt 0.715639293194 0.780954062939 0.000000000000 -vt 0.691104710102 0.775407373905 0.000000000000 -vt 0.699277937412 0.880255401134 0.000000000000 -vt 0.685730040073 0.887317180634 0.000000000000 -vt 0.679790914059 0.885531485081 0.000000000000 -vt 0.918968498707 0.632217705250 0.000000000000 -vt 0.927030384541 0.632067978382 0.000000000000 -vt 0.920924723148 0.642282843590 0.000000000000 -vt 0.928346455097 0.642091691494 0.000000000000 -vt 0.920858919621 0.665029823780 0.000000000000 -vt 0.928194463253 0.665964901447 0.000000000000 -vt 0.717470824718 0.788531899452 0.000000000000 -vt 0.900251805782 0.692512214184 0.000000000000 -vt 0.693121254444 0.888164877892 0.000000000000 -vt 0.902859151363 0.682655394077 0.000000000000 -vt 0.903970539570 0.621789634228 0.000000000000 -vt 0.901585161686 0.612310171127 0.000000000000 -vt 0.898017823696 0.700807869434 0.000000000000 -vt 0.905948698521 0.673050761223 0.000000000000 -vt 0.906874597073 0.632321536541 0.000000000000 -vt 0.693904578686 0.898468434811 0.000000000000 -vt 0.684614479542 0.894367456436 0.000000000000 -vt 0.909317672253 0.643546879292 0.000000000000 -vt 0.731463849545 0.855961382389 0.000000000000 -vt 0.869329869747 0.669516265392 0.000000000000 -vt 0.870946586132 0.660611331463 0.000000000000 -vt 0.890423119068 0.661864340305 0.000000000000 -vt 0.888348281384 0.670855045319 0.000000000000 -vt 0.890978634357 0.652710914612 0.000000000000 -vt 0.702305495739 0.895358145237 0.000000000000 -vt 0.871763646603 0.652749598026 0.000000000000 -vt 0.882360517979 0.689871191978 0.000000000000 -vt 0.710604488850 0.892980515957 0.000000000000 -vt 0.717464387417 0.885056376457 0.000000000000 -vt 0.730221688747 0.863188624382 0.000000000000 -vt 0.722860634327 0.863828301430 0.000000000000 -vt 0.714506924152 0.854860365391 0.000000000000 -vt 0.713789999485 0.863633096218 0.000000000000 -vt 0.724120557308 0.846761763096 0.000000000000 -vt 0.730854570866 0.849116206169 0.000000000000 -vt 0.714706599712 0.846446990967 0.000000000000 -vt 0.706338703632 0.855344653130 0.000000000000 -vt 0.707510411739 0.848723769188 0.000000000000 -vt 0.707069814205 0.861884772778 0.000000000000 -vt 0.678365886211 0.892260015011 0.000000000000 -vt 0.722407639027 0.880594253540 0.000000000000 -vt 0.885312139988 0.679928541183 0.000000000000 -vt 0.886436760426 0.624270200729 0.000000000000 -vt 0.883410274982 0.615363061428 0.000000000000 -vt 0.879997313023 0.698587834835 0.000000000000 -vt 0.889629900455 0.633672416210 0.000000000000 -vt 0.909305155277 0.662700593472 0.000000000000 -vt 0.891184151173 0.643255293369 0.000000000000 -vt 0.871766149998 0.644696950912 0.000000000000 -vt 0.907031238079 0.653394460678 0.000000000000 -vt 0.865283668041 0.687783956528 0.000000000000 -vt 0.867546260357 0.678728938103 0.000000000000 -vt 0.868419826031 0.627362251282 0.000000000000 -vt 0.866138994694 0.618586599827 0.000000000000 -vt 0.862232387066 0.696758449078 0.000000000000 -vt 0.870358645916 0.636041104794 0.000000000000 -vt 0.858235895634 0.685826241970 0.000000000000 -vt 0.858604013920 0.677683055401 0.000000000000 -vt 0.860833942890 0.667493700981 0.000000000000 -vt 0.863862931728 0.659794270992 0.000000000000 -vt 0.864249050617 0.652788579464 0.000000000000 -vt 0.864739954472 0.645918428898 0.000000000000 -vt 0.861379206181 0.638689100742 0.000000000000 -vt 0.859226524830 0.628483951092 0.000000000000 -vt 0.858618676662 0.620088815689 0.000000000000 -vt 0.856225430965 0.613054513931 0.000000000000 -vt 0.914761722088 0.600589513779 0.000000000000 -vt 0.924306929111 0.599584639072 0.000000000000 -vt 0.900618851185 0.603945910931 0.000000000000 -vt 0.882335126400 0.606884181499 0.000000000000 -vt 0.864254891872 0.609210252762 0.000000000000 -vt 0.854927241802 0.691868305206 0.000000000000 -vt 0.837422072887 0.841993212700 0.000000000000 -vt 0.887628972530 0.127281382680 0.000000000000 -vt 0.891492426395 0.109981805086 0.000000000000 -vt 0.853538930416 0.841780006886 0.000000000000 -vt 0.446142524481 0.173150673509 0.000000000000 -vt 0.852221906185 0.869813799858 0.000000000000 -vt 0.834832131863 0.866848766804 0.000000000000 -vt 0.827377617359 0.891240715981 0.000000000000 -vt 0.844508349895 0.896685421467 0.000000000000 -vt 0.876590073109 0.913664817810 0.000000000000 -vt 0.631155192852 0.291285961866 0.000000000000 -vt 0.626378953457 0.296571254730 0.000000000000 -vt 0.619356811047 0.293236494064 0.000000000000 -vt 0.617115795612 0.281405717134 0.000000000000 -vt 0.627076447010 0.304564028978 0.000000000000 -vt 0.612752139568 0.299342244864 0.000000000000 -vt 0.603455007076 0.284176468849 0.000000000000 -vt 0.551565110683 0.292362421751 0.000000000000 -vt 0.563377797604 0.287606924772 0.000000000000 -vt 0.575475394726 0.299903571606 0.000000000000 -vt 0.558976709843 0.303807973862 0.000000000000 -vt 0.562288582325 0.307399660349 0.000000000000 -vt 0.579733312130 0.307971090078 0.000000000000 -vt 0.596043288708 0.307672083378 0.000000000000 -vt 0.594420373440 0.298339635134 0.000000000000 -vt 0.590357482433 0.287719279528 0.000000000000 -vt 0.579626619816 0.290383100510 0.000000000000 -vt 0.573159515858 0.282042890787 0.000000000000 -vt 0.578718960285 0.044730942696 0.000000000000 -vt 0.566518962383 0.050097059458 0.000000000000 -vt 0.561770737171 0.022569365799 0.000000000000 -vt 0.579452574253 0.019849490374 0.000000000000 -vt 0.557008445263 0.060779999942 0.000000000000 -vt 0.548213899136 0.048078324646 0.000000000000 -vt 0.693731248379 0.210530251265 0.000000000000 -vt 0.693874895573 0.194242313504 0.000000000000 -vt 0.701992332935 0.200576603413 0.000000000000 -vt 0.711977064610 0.218270197511 0.000000000000 -vt 0.698697388172 0.178742393851 0.000000000000 -vt 0.704717457294 0.185912460089 0.000000000000 -vt 0.903121650219 0.125584170222 0.000000000000 -vt 0.867082893848 0.928871572018 0.000000000000 -vt 0.847567975521 0.932113111019 0.000000000000 -vt 0.861807763577 0.903646290302 0.000000000000 -vt 0.874533474445 0.941229879856 0.000000000000 -vt 0.854254424572 0.953694105148 0.000000000000 -vt 0.828710377216 0.919355154037 0.000000000000 -vt 0.886985480785 0.898062467575 0.000000000000 -vt 0.872782289982 0.875068247318 0.000000000000 -vt 0.906435072422 0.912213265896 0.000000000000 -vt 0.907167255878 0.936152637005 0.000000000000 -vt 0.888857185841 0.925772547722 0.000000000000 -vt 0.894924700260 0.912269532681 0.000000000000 -vt 0.909523308277 0.137212976813 0.000000000000 -vt 0.900375425816 0.890851438046 0.000000000000 -vt 0.647988855839 0.030116569251 0.000000000000 -vt 0.663214385509 0.030034158379 0.000000000000 -vt 0.655444204807 0.048680160195 0.000000000000 -vt 0.633447468281 0.039773471653 0.000000000000 -vt 0.639170706272 0.061737354845 0.000000000000 -vt 0.625266969204 0.055919121951 0.000000000000 -vt 0.724736869335 0.892238378525 0.000000000000 -vt 0.741851985455 0.899839401245 0.000000000000 -vt 0.725909292698 0.912707686424 0.000000000000 -vt 0.713663756847 0.901688575745 0.000000000000 -vt 0.650711238384 0.327391177416 0.000000000000 -vt 0.634856283665 0.320250153542 0.000000000000 -vt 0.740120351315 0.933756113052 0.000000000000 -vt 0.722898066044 0.930224955082 0.000000000000 -vt 0.640473186970 0.306113332510 0.000000000000 -vt 0.652059733868 0.314922749996 0.000000000000 -vt 0.621949970722 0.313803285360 0.000000000000 -vt 0.583925902843 0.276038467884 0.000000000000 -vt 0.669873058796 0.330044180155 0.000000000000 -vt 0.663455307484 0.311076432467 0.000000000000 -vt 0.653194963932 0.296154946089 0.000000000000 -vt 0.537551581860 0.063254460692 0.000000000000 -vt 0.855031669140 0.035574551672 0.000000000000 -vt 0.837493717670 0.022007379681 0.000000000000 -vt 0.709798753262 0.290995299816 0.000000000000 -vt 0.720909416676 0.320390880108 0.000000000000 -vt 0.708561480045 0.322530746460 0.000000000000 -vt 0.747772991657 0.921521842480 0.000000000000 -vt 0.695623576641 0.297934114933 0.000000000000 -vt 0.680082261562 0.305459260941 0.000000000000 -vt 0.693427860737 0.329764753580 0.000000000000 -vt 0.681907594204 0.278335958719 0.000000000000 -vt 0.667823493481 0.287369400263 0.000000000000 -vt 0.667146265507 0.261673122644 0.000000000000 -vt 0.654371798038 0.271894037724 0.000000000000 -vt 0.641373217106 0.281966120005 0.000000000000 -vt 0.639975368977 0.258212238550 0.000000000000 -vt 0.628611147404 0.269090384245 0.000000000000 -vt 0.626621663570 0.244766697288 0.000000000000 -vt 0.616053998470 0.255464911461 0.000000000000 -vt 0.605184614658 0.264766514301 0.000000000000 -vt 0.605853140354 0.242097690701 0.000000000000 -vt 0.595517814159 0.250885695219 0.000000000000 -vt 0.585814058781 0.256739497185 0.000000000000 -vt 0.595492184162 0.270403504372 0.000000000000 -vt 0.574711024761 0.264054805040 0.000000000000 -vt 0.585790932178 0.239443764091 0.000000000000 -vt 0.572891771793 0.246539995074 0.000000000000 -vt 0.559696972370 0.254923403263 0.000000000000 -vt 0.577001988888 0.228986665606 0.000000000000 -vt 0.564495980740 0.234662607312 0.000000000000 -vt 0.551713407040 0.238481923938 0.000000000000 -vt 0.545511305332 0.261512130499 0.000000000000 -vt 0.538646757603 0.241494938731 0.000000000000 -vt 0.661286294460 0.149169623852 0.000000000000 -vt 0.643085420132 0.133995741606 0.000000000000 -vt 0.684797942638 0.147779509425 0.000000000000 -vt 0.676565825939 0.159141749144 0.000000000000 -vt 0.630804598331 0.144728660583 0.000000000000 -vt 0.649197280407 0.162055477500 0.000000000000 -vt 0.669700562954 0.172124639153 0.000000000000 -vt 0.633624017239 0.171124503016 0.000000000000 -vt 0.617616355419 0.157551243901 0.000000000000 -vt 0.624203979969 0.183554634452 0.000000000000 -vt 0.607319533825 0.173306703568 0.000000000000 -vt 0.645736873150 0.185071289539 0.000000000000 -vt 0.638931095600 0.196221649647 0.000000000000 -vt 0.601086556911 0.187993124127 0.000000000000 -vt 0.617492735386 0.196533486247 0.000000000000 -vt 0.632214725018 0.207936018705 0.000000000000 -vt 0.654465734959 0.209547683597 0.000000000000 -vt 0.646386682987 0.221093416214 0.000000000000 -vt 0.611703574657 0.208597302437 0.000000000000 -vt 0.624510347843 0.219911128283 0.000000000000 -vt 0.636621057987 0.233212843537 0.000000000000 -vt 0.661210715771 0.235190823674 0.000000000000 -vt 0.651021778584 0.247041419148 0.000000000000 -vt 0.615979254246 0.231477782130 0.000000000000 -vt 0.605249464512 0.220229938626 0.000000000000 -vt 0.596773326397 0.230893954635 0.000000000000 -vt 0.592077195644 0.211689129472 0.000000000000 -vt 0.586139500141 0.221562415361 0.000000000000 -vt 0.596748054028 0.200712144375 0.000000000000 -vt 0.686020314693 0.238807246089 0.000000000000 -vt 0.677805483341 0.250549525023 0.000000000000 -vt 0.669185936451 0.222903206944 0.000000000000 -vt 0.691701591015 0.226273551583 0.000000000000 -vt 0.675190150738 0.210060581565 0.000000000000 -vt 0.660946547985 0.197643056512 0.000000000000 -vt 0.679371058941 0.196919396520 0.000000000000 -vt 0.665786325932 0.185841768980 0.000000000000 -vt 0.653169095516 0.177967861295 0.000000000000 -vt 0.682948529720 0.183452650905 0.000000000000 -vt 0.688856303692 0.169335424900 0.000000000000 -vt 0.712051331997 0.240907743573 0.000000000000 -vt 0.705046594143 0.257047295570 0.000000000000 -vt 0.693947613239 0.268588751554 0.000000000000 -vt 0.846441566944 0.016312304884 0.000000000000 -vt 0.725233733654 0.280963063240 0.000000000000 -vt 0.864230215549 0.027330722660 0.000000000000 -vt 0.867542684078 0.077758729458 0.000000000000 -vt 0.873992264271 0.059032347053 0.000000000000 -vt 0.900698363781 0.073607310653 0.000000000000 -vt 0.893409788609 0.088153243065 0.000000000000 -vt 0.837527215481 0.094833135605 0.000000000000 -vt 0.838087618351 0.073169842362 0.000000000000 -vt 0.864491522312 0.098964735866 0.000000000000 -vt 0.839568436146 0.049210395664 0.000000000000 -vt 0.838048279285 0.117027804255 0.000000000000 -vt 0.862743914127 0.119909122586 0.000000000000 -vt 0.839784204960 0.140174224973 0.000000000000 -vt 0.862825214863 0.142299681902 0.000000000000 -vt 0.887471616268 0.147722780704 0.000000000000 -vt 0.864518344402 0.167147815228 0.000000000000 -vt 0.760909855366 0.908550620079 0.000000000000 -vt 0.702537238598 0.924268066883 0.000000000000 -vt 0.688291251659 0.928146779537 0.000000000000 -vt 0.681064426899 0.908967435360 0.000000000000 -vt 0.690809547901 0.908960223198 0.000000000000 -vt 0.831720411777 0.965238690376 0.000000000000 -vt 0.609436690807 0.309842139482 0.000000000000 -vt 0.841262519360 0.982780098915 0.000000000000 -vt 0.824164688587 0.990950345993 0.000000000000 -vt 0.813748776913 0.974472284317 0.000000000000 -vt 0.803931534290 0.981341362000 0.000000000000 -vt 0.813704669476 0.995644569397 0.000000000000 -vt 0.821433365345 0.949445426464 0.000000000000 -vt 0.802491247654 0.961359918118 0.000000000000 -vt 0.792442619801 0.969731867313 0.000000000000 -vt 0.808618605137 0.936246752739 0.000000000000 -vt 0.791009962559 0.950495541096 0.000000000000 -vt 0.780412495136 0.960320413113 0.000000000000 -vt 0.779733002186 0.938618302345 0.000000000000 -vt 0.769098222256 0.949621915817 0.000000000000 -vt 0.795302093029 0.925809264183 0.000000000000 -vt 0.779587566853 0.917365670204 0.000000000000 -vt 0.765330970287 0.930258750916 0.000000000000 -vt 0.755919754505 0.940638661385 0.000000000000 -vt 0.888226568699 0.171349883080 0.000000000000 -vt 0.910776436329 0.175429016352 0.000000000000 -vt 0.910029232502 0.154122352600 0.000000000000 -vt 0.931366503239 0.177302077413 0.000000000000 -vt 0.929215371609 0.158224686980 0.000000000000 -vt 0.927563607693 0.146612986922 0.000000000000 -vt 0.907406389713 0.225816711783 0.000000000000 -vt 0.909843504429 0.199414119124 0.000000000000 -vt 0.930679738522 0.201603308320 0.000000000000 -vt 0.928200304508 0.226828783751 0.000000000000 -vt 0.887493193150 0.252168864012 0.000000000000 -vt 0.887319624424 0.224217891693 0.000000000000 -vt 0.907594621181 0.252231895924 0.000000000000 -vt 0.932080924511 0.253668844700 0.000000000000 -vt 0.888279378414 0.197011262178 0.000000000000 -vt 0.868254363537 0.222412139177 0.000000000000 -vt 0.866531431675 0.193962886930 0.000000000000 -vt 0.850991070271 0.254400819540 0.000000000000 -vt 0.425416767597 0.169557422400 0.000000000000 -vt 0.527126252651 0.054304089397 0.000000000000 -vt 0.537031948566 0.037999924272 0.000000000000 -vt 0.594819605350 0.021248605102 0.000000000000 -vt 0.593616664410 0.041817199439 0.000000000000 -vt 0.611463606358 0.039550118148 0.000000000000 -vt 0.612102329731 0.021802034229 0.000000000000 -vt 0.629308164120 0.021318852901 0.000000000000 -vt 0.684654057026 0.026047337800 0.000000000000 -vt 0.686814010143 0.010275442153 0.000000000000 -vt 0.813150346279 0.910948097706 0.000000000000 -vt 0.795561254025 0.902303934097 0.000000000000 -vt 0.708547055721 0.008438628167 0.000000000000 -vt 0.706763446331 0.024136669934 0.000000000000 -vt 0.681121885777 0.042657937855 0.000000000000 -vt 0.703326165676 0.040577050298 0.000000000000 -vt 0.679071128368 0.059330899268 0.000000000000 -vt 0.697736203671 0.057211738080 0.000000000000 -vt 0.679068386555 0.075802132487 0.000000000000 -vt 0.694422185421 0.074145883322 0.000000000000 -vt 0.660856544971 0.065091490746 0.000000000000 -vt 0.664182245731 0.079712390900 0.000000000000 -vt 0.667562067509 0.093277320266 0.000000000000 -vt 0.658718883991 0.094275429845 0.000000000000 -vt 0.653593957424 0.083498373628 0.000000000000 -vt 0.562429010868 0.070872798562 0.000000000000 -vt 0.561431109905 0.091275691986 0.000000000000 -vt 0.651631176472 0.096843779087 0.000000000000 -vt 0.566199004650 0.079591929913 0.000000000000 -vt 0.568919837475 0.088470026851 0.000000000000 -vt 0.576352179050 0.086408510804 0.000000000000 -vt 0.573891699314 0.075738176703 0.000000000000 -vt 0.570575177670 0.065078660846 0.000000000000 -vt 0.584147036076 0.084593981504 0.000000000000 -vt 0.582864105701 0.072689130902 0.000000000000 -vt 0.580894887447 0.060486171395 0.000000000000 -vt 0.593160688877 0.083160415292 0.000000000000 -vt 0.593804895878 0.070337161422 0.000000000000 -vt 0.593818604946 0.057107713073 0.000000000000 -vt 0.603601753712 0.082686245441 0.000000000000 -vt 0.606147468090 0.069071784616 0.000000000000 -vt 0.609074890614 0.054980006069 0.000000000000 -vt 0.614769279957 0.083682104945 0.000000000000 -vt 0.619084775448 0.069891348481 0.000000000000 -vt 0.610922992229 0.095825180411 0.000000000000 -vt 0.601321876049 0.094617664814 0.000000000000 -vt 0.622694909573 0.086109951138 0.000000000000 -vt 0.617340266705 0.097710400820 0.000000000000 -vt 0.629761517048 0.073689267039 0.000000000000 -vt 0.629895031452 0.090603604913 0.000000000000 -vt 0.623498737812 0.100945651531 0.000000000000 -vt 0.638310372829 0.080408573151 0.000000000000 -vt 0.638113796711 0.097320660949 0.000000000000 -vt 0.645590126514 0.088923722506 0.000000000000 -vt 0.647677242756 0.071726813912 0.000000000000 -vt 0.631511867046 0.105762854218 0.000000000000 -vt 0.638789474964 0.110335975885 0.000000000000 -vt 0.562276422977 0.105178341269 0.000000000000 -vt 0.630611360073 0.128678917885 0.000000000000 -vt 0.623610913754 0.125340327621 0.000000000000 -vt 0.626384556293 0.114658728242 0.000000000000 -vt 0.569847881794 0.105211660266 0.000000000000 -vt 0.570068538189 0.114621803164 0.000000000000 -vt 0.570002615452 0.097111940384 0.000000000000 -vt 0.577380478382 0.104798287153 0.000000000000 -vt 0.576979458332 0.114249393344 0.000000000000 -vt 0.577486932278 0.096096485853 0.000000000000 -vt 0.584565103054 0.104308113456 0.000000000000 -vt 0.583777844906 0.114008486271 0.000000000000 -vt 0.584677040577 0.095082387328 0.000000000000 -vt 0.591241061687 0.104193970561 0.000000000000 -vt 0.589022576809 0.114581719041 0.000000000000 -vt 0.592356622219 0.094391390681 0.000000000000 -vt 0.598587095737 0.105026379228 0.000000000000 -vt 0.594260156155 0.115820080042 0.000000000000 -vt 0.586750924587 0.143253445625 0.000000000000 -vt 0.588111102581 0.125869661570 0.000000000000 -vt 0.593005359173 0.127749264240 0.000000000000 -vt 0.591630995274 0.144661337137 0.000000000000 -vt 0.596110045910 0.146092429757 0.000000000000 -vt 0.598921716213 0.130493223667 0.000000000000 -vt 0.601200044155 0.117737725377 0.000000000000 -vt 0.600308954716 0.147598937154 0.000000000000 -vt 0.605599582195 0.133385121822 0.000000000000 -vt 0.608710825443 0.120034545660 0.000000000000 -vt 0.604579865932 0.149645149708 0.000000000000 -vt 0.611486494541 0.135846063495 0.000000000000 -vt 0.615960538387 0.122533097863 0.000000000000 -vt 0.608992874622 0.150967940688 0.000000000000 -vt 0.617690265179 0.137778565288 0.000000000000 -vt 0.624459326267 0.140183672309 0.000000000000 -vt 0.613782465458 0.152489989996 0.000000000000 -vt 0.570089280605 0.125959947705 0.000000000000 -vt 0.557442963123 0.275540649891 0.000000000000 -vt 0.566006243229 0.270970880985 0.000000000000 -vt 0.775371730328 0.893757700920 0.000000000000 -vt 0.808763206005 0.883916676044 0.000000000000 -vt 0.559562146664 0.264112442732 0.000000000000 -vt 0.554663598537 0.266600191593 0.000000000000 -vt 0.848581612110 0.221785306931 0.000000000000 -vt 0.393582761288 0.484183341265 0.000000000000 -vt 0.396767795086 0.480453461409 0.000000000000 -vt 0.400794714689 0.480809420347 0.000000000000 -vt 0.399765521288 0.485055834055 0.000000000000 -vt 0.439470499754 0.511713802814 0.000000000000 -vt 0.440386444330 0.513542473316 0.000000000000 -vt 0.437012046576 0.514041662216 0.000000000000 -vt 0.437573134899 0.511677742004 0.000000000000 -vt 0.422013103962 0.460037946701 0.000000000000 -vt 0.418047666550 0.470334529877 0.000000000000 -vt 0.412509530783 0.468371391296 0.000000000000 -vt 0.414865106344 0.458373844624 0.000000000000 -vt 0.429023534060 0.476388931274 0.000000000000 -vt 0.423462659121 0.473014324903 0.000000000000 -vt 0.429314196110 0.462833255529 0.000000000000 -vt 0.436214298010 0.467371255159 0.000000000000 -vt 0.406041711569 0.475491911173 0.000000000000 -vt 0.406945496798 0.467524141073 0.000000000000 -vt 0.410694092512 0.476356506348 0.000000000000 -vt 0.435092151165 0.452288359404 0.000000000000 -vt 0.438309162855 0.447881609201 0.000000000000 -vt 0.359971135855 0.090370342135 0.000000000000 -vt 0.368420302868 0.099629849195 0.000000000000 -vt 0.362833082676 0.104876860976 0.000000000000 -vt 0.354921132326 0.096900969744 0.000000000000 -vt 0.352515369654 0.130700588226 0.000000000000 -vt 0.345492541790 0.124132826924 0.000000000000 -vt 0.349532276392 0.119571164250 0.000000000000 -vt 0.358871489763 0.128728002310 0.000000000000 -vt 0.438525289297 0.449985921383 0.000000000000 -vt 0.439274400473 0.451704740524 0.000000000000 -vt 0.449622303247 0.464140743017 0.000000000000 -vt 0.448981046677 0.460056871176 0.000000000000 -vt 0.450336039066 0.460677176714 0.000000000000 -vt 0.452015697956 0.460444808006 0.000000000000 -vt 0.425263881683 0.450979530811 0.000000000000 -vt 0.453179091215 0.473780065775 0.000000000000 -vt 0.449453443289 0.477478682995 0.000000000000 -vt 0.442929327488 0.472293376923 0.000000000000 -vt 0.441622525454 0.459930330515 0.000000000000 -vt 0.444129645824 0.456388652325 0.000000000000 -vt 0.373616009951 0.118581384420 0.000000000000 -vt 0.375112146139 0.115701422095 0.000000000000 -vt 0.377992779016 0.117945536971 0.000000000000 -vt 0.375868886709 0.120479449630 0.000000000000 -vt 0.382243275642 0.107223436236 0.000000000000 -vt 0.383732229471 0.103787556291 0.000000000000 -vt 0.386310935020 0.106139764190 0.000000000000 -vt 0.384451150894 0.109020173550 0.000000000000 -vt 0.409286201000 0.450759083033 0.000000000000 -vt 0.408566385508 0.458585023880 0.000000000000 -vt 0.376690715551 0.126454398036 0.000000000000 -vt 0.381214976311 0.120371833444 0.000000000000 -vt 0.403114914894 0.459155589342 0.000000000000 -vt 0.403876841068 0.452309519053 0.000000000000 -vt 0.454835981131 0.482029527426 0.000000000000 -vt 0.457485169172 0.479463666677 0.000000000000 -vt 0.384555608034 0.122786611319 0.000000000000 -vt 0.382433533669 0.128221631050 0.000000000000 -vt 0.385892122984 0.114606484771 0.000000000000 -vt 0.389199435711 0.119001969695 0.000000000000 -vt 0.416368693113 0.447328180075 0.000000000000 -vt 0.461556434631 0.440214395523 0.000000000000 -vt 0.354810804129 0.135790005326 0.000000000000 -vt 0.356487303972 0.133928865194 0.000000000000 -vt 0.459117084742 0.440935134888 0.000000000000 -vt 0.359035402536 0.136161059141 0.000000000000 -vt 0.356604158878 0.137259811163 0.000000000000 -vt 0.456829965115 0.439723789692 0.000000000000 -vt 0.458451539278 0.437272518873 0.000000000000 -vt 0.454769343138 0.438526421785 0.000000000000 -vt 0.454550951719 0.435967743397 0.000000000000 -vt 0.441826075315 0.444921255112 0.000000000000 -vt 0.443551659584 0.442011803389 0.000000000000 -vt 0.448256731033 0.443818241358 0.000000000000 -vt 0.446299463511 0.446265220642 0.000000000000 -vt 0.455544114113 0.449857115746 0.000000000000 -vt 0.458855003119 0.454671829939 0.000000000000 -vt 0.455724000931 0.457280248404 0.000000000000 -vt 0.453310787678 0.452473431826 0.000000000000 -vt 0.450308114290 0.448847740889 0.000000000000 -vt 0.386408418417 0.101448193192 0.000000000000 -vt 0.387978881598 0.103007167578 0.000000000000 -vt 0.452250301838 0.446324646473 0.000000000000 -vt 0.447152793407 0.437671035528 0.000000000000 -vt 0.450194656849 0.436007380486 0.000000000000 -vt 0.452898085117 0.439646780491 0.000000000000 -vt 0.450881361961 0.441238403320 0.000000000000 -vt 0.458574026823 0.443444490433 0.000000000000 -vt 0.463303625584 0.444895386696 0.000000000000 -vt 0.462563782930 0.448778629303 0.000000000000 -vt 0.457480877638 0.446133941412 0.000000000000 -vt 0.454026341438 0.443802684546 0.000000000000 -vt 0.359097301960 0.132905989885 0.000000000000 -vt 0.361074864864 0.134876102209 0.000000000000 -vt 0.455461025238 0.441745221615 0.000000000000 -vt 0.444298267365 0.448686748743 0.000000000000 -vt 0.442074418068 0.450537770987 0.000000000000 -vt 0.439655810595 0.449115246534 0.000000000000 -vt 0.441199243069 0.447540730238 0.000000000000 -vt 0.451972931623 0.458101630211 0.000000000000 -vt 0.450596332550 0.459385693073 0.000000000000 -vt 0.449565351009 0.457458138466 0.000000000000 -vt 0.450939685106 0.454803764820 0.000000000000 -vt 0.446267724037 0.453737437725 0.000000000000 -vt 0.397592544556 0.132566675544 0.000000000000 -vt 0.395102560520 0.138213351369 0.000000000000 -vt 0.392103701830 0.135889068246 0.000000000000 -vt 0.395304739475 0.130839735270 0.000000000000 -vt 0.399295836687 0.125662967563 0.000000000000 -vt 0.402231425047 0.128127291799 0.000000000000 -vt 0.404049992561 0.137433633208 0.000000000000 -vt 0.405965834856 0.138806402683 0.000000000000 -vt 0.404163688421 0.144568577409 0.000000000000 -vt 0.448208779097 0.451402574778 0.000000000000 -vt 0.449387699366 0.442756623030 0.000000000000 -vt 0.445775300264 0.440066248178 0.000000000000 -vt 0.459970653057 0.451159417629 0.000000000000 -vt 0.456270694733 0.448136717081 0.000000000000 -vt 0.400764316320 0.142388850451 0.000000000000 -vt 0.410871744156 0.135244905949 0.000000000000 -vt 0.407858490944 0.132529079914 0.000000000000 -vt 0.389080792665 0.131361424923 0.000000000000 -vt 0.387762486935 0.129610389471 0.000000000000 -vt 0.389104187489 0.126333042979 0.000000000000 -vt 0.390812218189 0.127695217729 0.000000000000 -vt 0.391797959805 0.123638600111 0.000000000000 -vt 0.393867135048 0.124303475022 0.000000000000 -vt 0.390969157219 0.132123574615 0.000000000000 -vt 0.392821729183 0.129185527563 0.000000000000 -vt 0.395075976849 0.126136258245 0.000000000000 -vt 0.398736566305 0.138166293502 0.000000000000 -vt 0.397700846195 0.136793285608 0.000000000000 -vt 0.399035334587 0.133746489882 0.000000000000 -vt 0.400510340929 0.134889379144 0.000000000000 -vt 0.401520818472 0.131361871958 0.000000000000 -vt 0.403166472912 0.131912827492 0.000000000000 -vt 0.400330662727 0.138775110245 0.000000000000 -vt 0.402200579643 0.136118054390 0.000000000000 -vt 0.404188245535 0.133363723755 0.000000000000 -vt 0.385480999947 0.131040126085 0.000000000000 -vt 0.387488692999 0.124964997172 0.000000000000 -vt 0.392740219831 0.120471790433 0.000000000000 -vt 0.397779881954 0.121211871505 0.000000000000 -vt 0.388019412756 0.135536253452 0.000000000000 -vt 0.406621724367 0.128388255835 0.000000000000 -vt 0.396779060364 0.141935378313 0.000000000000 -vt 0.409657478333 0.141405150294 0.000000000000 -vt 0.408238559961 0.143032342196 0.000000000000 -vt 0.452826261520 0.445473134518 0.000000000000 -vt 0.398223191500 0.453096210957 0.000000000000 -vt 0.397748589516 0.459203541279 0.000000000000 -vt 0.461537957191 0.483292669058 0.000000000000 -vt 0.458966463804 0.486215561628 0.000000000000 -vt 0.417104929686 0.441364258528 0.000000000000 -vt 0.418126702309 0.442871898413 0.000000000000 -vt 0.420422822237 0.444641411304 0.000000000000 -vt 0.433500528336 0.448079735041 0.000000000000 -vt 0.436020672321 0.448221594095 0.000000000000 -vt 0.427099138498 0.446181684732 0.000000000000 -vt 0.438960522413 0.423234313726 0.000000000000 -vt 0.436720907688 0.424649864435 0.000000000000 -vt 0.407253503799 0.142381638288 0.000000000000 -vt 0.408249586821 0.140351876616 0.000000000000 -vt 0.434051692486 0.423569798470 0.000000000000 -vt 0.434879601002 0.420804440975 0.000000000000 -vt 0.431214749813 0.423123985529 0.000000000000 -vt 0.430086702108 0.420641422272 0.000000000000 -vt 0.419274091721 0.434574037790 0.000000000000 -vt 0.420379161835 0.430852890015 0.000000000000 -vt 0.426141530275 0.431651085615 0.000000000000 -vt 0.424853444099 0.434927970171 0.000000000000 -vt 0.436181217432 0.434532612562 0.000000000000 -vt 0.441298097372 0.437351107597 0.000000000000 -vt 0.439914047718 0.441069751978 0.000000000000 -vt 0.435192108154 0.437948435545 0.000000000000 -vt 0.430372446775 0.435908526182 0.000000000000 -vt 0.410810738802 0.139599621296 0.000000000000 -vt 0.409828603268 0.138812705874 0.000000000000 -vt 0.431275308132 0.432643771172 0.000000000000 -vt 0.423234343529 0.424417972565 0.000000000000 -vt 0.425667136908 0.422001600266 0.000000000000 -vt 0.429718136787 0.424738824368 0.000000000000 -vt 0.428410202265 0.426783442497 0.000000000000 -vt 0.437025994062 0.426789969206 0.000000000000 -vt 0.441838681698 0.426870137453 0.000000000000 -vt 0.442383557558 0.430333465338 0.000000000000 -vt 0.436957329512 0.429274797440 0.000000000000 -vt 0.432621270418 0.428078770638 0.000000000000 -vt 0.414452850819 0.144986689091 0.000000000000 -vt 0.409147053957 0.147766679525 0.000000000000 -vt 0.433331876993 0.425908029079 0.000000000000 -vt 0.423957765102 0.438147932291 0.000000000000 -vt 0.422544687986 0.441486746073 0.000000000000 -vt 0.418296456337 0.441183239222 0.000000000000 -vt 0.419304251671 0.438087821007 0.000000000000 -vt 0.437636613846 0.443893879652 0.000000000000 -vt 0.436708301306 0.446964770555 0.000000000000 -vt 0.433489710093 0.444419175386 0.000000000000 -vt 0.434133440256 0.441165685654 0.000000000000 -vt 0.428444206715 0.442456930876 0.000000000000 -vt 0.408575177193 0.144754558802 0.000000000000 -vt 0.411639750004 0.142881035805 0.000000000000 -vt 0.406258314848 0.142990231514 0.000000000000 -vt 0.407059431076 0.139547616243 0.000000000000 -vt 0.410056680441 0.137724533677 0.000000000000 -vt 0.415505886078 0.139094606042 0.000000000000 -vt 0.412565827370 0.139450341463 0.000000000000 -vt 0.364202499390 0.128939658403 0.000000000000 -vt 0.366093575954 0.126167103648 0.000000000000 -vt 0.429390072823 0.439258158207 0.000000000000 -vt 0.427526712418 0.428991526365 0.000000000000 -vt 0.422490209341 0.427620559931 0.000000000000 -vt 0.441317677498 0.433453887701 0.000000000000 -vt 0.436557680368 0.431637555361 0.000000000000 -vt 0.368825376034 0.128782272339 0.000000000000 -vt 0.366221219301 0.131002977490 0.000000000000 -vt 0.377708643675 0.113558173180 0.000000000000 -vt 0.379947811365 0.115249529481 0.000000000000 -vt 0.368792057037 0.124293580651 0.000000000000 -vt 0.370973348618 0.126337096095 0.000000000000 -vt 0.379835903645 0.132157340646 0.000000000000 -vt 0.374702155590 0.134804278612 0.000000000000 -vt 0.371608525515 0.131661787629 0.000000000000 -vt 0.385006606579 0.145867496729 0.000000000000 -vt 0.380806565285 0.150551855564 0.000000000000 -vt 0.378436356783 0.147939816117 0.000000000000 -vt 0.383413165808 0.143897384405 0.000000000000 -vt 0.388382792473 0.140254378319 0.000000000000 -vt 0.390580326319 0.142940923572 0.000000000000 -vt 0.389787077904 0.151387169957 0.000000000000 -vt 0.391084223986 0.152869373560 0.000000000000 -vt 0.387653529644 0.157836511731 0.000000000000 -vt 0.385402202606 0.155462026596 0.000000000000 -vt 0.396483421326 0.150470122695 0.000000000000 -vt 0.394613981247 0.147955358028 0.000000000000 -vt 0.377133131027 0.143021076918 0.000000000000 -vt 0.431962937117 0.430194556713 0.000000000000 -vt 0.398509591818 0.449473470449 0.000000000000 -vt 0.403451532125 0.447545230389 0.000000000000 -vt 0.412772059441 0.443381220102 0.000000000000 -vt 0.415262728930 0.442666351795 0.000000000000 -vt 0.408193081617 0.445362567902 0.000000000000 -vt 0.402572304010 0.417491078377 0.000000000000 -vt 0.401636779308 0.420146107674 0.000000000000 -vt 0.376334518194 0.141268029809 0.000000000000 -vt 0.378864586353 0.138637766242 0.000000000000 -vt 0.398579388857 0.420967459679 0.000000000000 -vt 0.397203922272 0.418318748474 0.000000000000 -vt 0.395930439234 0.422812163830 0.000000000000 -vt 0.393101811409 0.421740859747 0.000000000000 -vt 0.393963277340 0.440714478493 0.000000000000 -vt 0.392591178417 0.436948060989 0.000000000000 -vt 0.397990405560 0.434073746204 0.000000000000 -vt 0.399504780769 0.437697380781 0.000000000000 -vt 0.408009588718 0.428790479898 0.000000000000 -vt 0.414924532175 0.428841352463 0.000000000000 -vt 0.416294604540 0.432789921761 0.000000000000 -vt 0.409434139729 0.432349741459 0.000000000000 -vt 0.404077023268 0.434443891048 0.000000000000 -vt 0.380261212587 0.140083029866 0.000000000000 -vt 0.382164925337 0.137022957206 0.000000000000 -vt 0.402819514275 0.430790752172 0.000000000000 -vt 0.390489786863 0.430026113987 0.000000000000 -vt 0.390550136566 0.426381319761 0.000000000000 -vt 0.395857959986 0.425411134958 0.000000000000 -vt 0.396276742220 0.428331613541 0.000000000000 -vt 0.403288513422 0.421578973532 0.000000000000 -vt 0.408246427774 0.418946474791 0.000000000000 -vt 0.411142379045 0.421542286873 0.000000000000 -vt 0.405009150505 0.423732370138 0.000000000000 -vt 0.400750786066 0.425774753094 0.000000000000 -vt 0.383944779634 0.138014540076 0.000000000000 -vt 0.378778368235 0.144098669291 0.000000000000 -vt 0.399727702141 0.423417359591 0.000000000000 -vt 0.400881379843 0.440771222115 0.000000000000 -vt 0.401966422796 0.443919539452 0.000000000000 -vt 0.396847724915 0.446899026632 0.000000000000 -vt 0.396342486143 0.443651407957 0.000000000000 -vt 0.415956437588 0.436509907246 0.000000000000 -vt 0.416573584080 0.440072774887 0.000000000000 -vt 0.411374956369 0.439379304647 0.000000000000 -vt 0.410169273615 0.436066806316 0.000000000000 -vt 0.406326770782 0.441095888615 0.000000000000 -vt 0.381734192371 0.141807720065 0.000000000000 -vt 0.384717941284 0.139707922935 0.000000000000 -vt 0.384294420481 0.151226192713 0.000000000000 -vt 0.383655220270 0.149787440896 0.000000000000 -vt 0.386135309935 0.147063747048 0.000000000000 -vt 0.387247562408 0.148301199079 0.000000000000 -vt 0.389312237501 0.145468518138 0.000000000000 -vt 0.390688598156 0.146293267608 0.000000000000 -vt 0.385713368654 0.152030900121 0.000000000000 -vt 0.405239045620 0.437882453203 0.000000000000 -vt 0.396997690201 0.430689215660 0.000000000000 -vt 0.392160445452 0.433128327131 0.000000000000 -vt 0.412164151669 0.424938082695 0.000000000000 -vt 0.406307399273 0.426028043032 0.000000000000 -vt 0.388458669186 0.149755924940 0.000000000000 -vt 0.391224920750 0.147718727589 0.000000000000 -vt 0.373405694962 0.142156943679 0.000000000000 -vt 0.377377659082 0.137248560786 0.000000000000 -vt 0.383390426636 0.134469017386 0.000000000000 -vt 0.387974828482 0.136217564344 0.000000000000 -vt 0.374564796686 0.146659821272 0.000000000000 -vt 0.394345581532 0.144419968128 0.000000000000 -vt 0.381775170565 0.154543623328 0.000000000000 -vt 0.393369078636 0.155557274818 0.000000000000 -vt 0.391563802958 0.156876459718 0.000000000000 -vt 0.390937179327 0.156117007136 0.000000000000 -vt 0.392488509417 0.154420018196 0.000000000000 -vt 0.395006179810 0.154078006744 0.000000000000 -vt 0.394348293543 0.153221741319 0.000000000000 -vt 0.396971106529 0.159922137856 0.000000000000 -vt 0.391263425350 0.161551579833 0.000000000000 -vt 0.391377806664 0.158593714237 0.000000000000 -vt 0.394818872213 0.157320469618 0.000000000000 -vt 0.389807134867 0.156631037593 0.000000000000 -vt 0.391787588596 0.153602257371 0.000000000000 -vt 0.395006865263 0.152312338352 0.000000000000 -vt 0.401779532433 0.428116351366 0.000000000000 -vt 0.452458798885 0.462447345257 0.000000000000 -vt 0.452626556158 0.465537369251 0.000000000000 -vt 0.459379166365 0.476943254471 0.000000000000 -vt 0.462601810694 0.480663985014 0.000000000000 -vt 0.455803722143 0.471922338009 0.000000000000 -vt 0.479603260756 0.461800038815 0.000000000000 -vt 0.477074772120 0.461461395025 0.000000000000 -vt 0.399524837732 0.154673993587 0.000000000000 -vt 0.396705895662 0.154279291630 0.000000000000 -vt 0.475300759077 0.459207594395 0.000000000000 -vt 0.477906495333 0.457540988922 0.000000000000 -vt 0.473629444838 0.457062989473 0.000000000000 -vt 0.474505990744 0.454424381256 0.000000000000 -vt 0.457420319319 0.456922262907 0.000000000000 -vt 0.460104405880 0.454761892557 0.000000000000 -vt 0.463730514050 0.459742784500 0.000000000000 -vt 0.461280167103 0.461182653904 0.000000000000 -vt 0.469485044479 0.469264149666 0.000000000000 -vt 0.472566455603 0.474419951439 0.000000000000 -vt 0.469833135605 0.475842684507 0.000000000000 -vt 0.467271775007 0.470811873674 0.000000000000 -vt 0.464453041553 0.465783476830 0.000000000000 -vt 0.371207743883 0.139285087585 0.000000000000 -vt 0.356069415808 0.140628591180 0.000000000000 -vt 0.466606199741 0.464368134737 0.000000000000 -vt 0.466347038746 0.452607154846 0.000000000000 -vt 0.470105797052 0.452469378710 0.000000000000 -vt 0.471197992563 0.457316517830 0.000000000000 -vt 0.468378633261 0.458023726940 0.000000000000 -vt 0.475411504507 0.463598579168 0.000000000000 -vt 0.478970795870 0.466784060001 0.000000000000 -vt 0.476854532957 0.469994544983 0.000000000000 -vt 0.473139971495 0.465840876102 0.000000000000 -vt 0.470534920692 0.462002217770 0.000000000000 -vt 0.361092180014 0.138868093491 0.000000000000 -vt 0.362757891417 0.141520425677 0.000000000000 -vt 0.473011165857 0.460577666759 0.000000000000 -vt 0.458834081888 0.463209271431 0.000000000000 -vt 0.456127494574 0.464871376753 0.000000000000 -vt 0.453364372253 0.461712449789 0.000000000000 -vt 0.455975264311 0.460149645805 0.000000000000 -vt 0.466653943062 0.476451963186 0.000000000000 -vt 0.464873641729 0.479033142328 0.000000000000 -vt 0.462096124887 0.474372893572 0.000000000000 -vt 0.464624851942 0.472282111645 0.000000000000 -vt 0.459239572287 0.469601660967 0.000000000000 -vt 0.358396410942 0.143731668591 0.000000000000 -vt 0.366143107414 0.136179968715 0.000000000000 -vt 0.367462068796 0.140748366714 0.000000000000 -vt 0.367624849081 0.152154952288 0.000000000000 -vt 0.363851904869 0.154144421220 0.000000000000 -vt 0.362488389015 0.151757776737 0.000000000000 -vt 0.366743355989 0.150309801102 0.000000000000 -vt 0.370945870876 0.149034306407 0.000000000000 -vt 0.371946483850 0.151283830404 0.000000000000 -vt 0.461986482143 0.467537879944 0.000000000000 -vt 0.466021031141 0.459026336670 0.000000000000 -vt 0.463648796082 0.454296290874 0.000000000000 -vt 0.474090546370 0.471629172564 0.000000000000 -vt 0.471038132906 0.467538326979 0.000000000000 -vt 0.369695812464 0.157271832228 0.000000000000 -vt 0.370106279850 0.158484742045 0.000000000000 -vt 0.366340100765 0.161045432091 0.000000000000 -vt 0.365696161985 0.158691659570 0.000000000000 -vt 0.374921888113 0.158001109958 0.000000000000 -vt 0.373830109835 0.155684486032 0.000000000000 -vt 0.362566053867 0.147848188877 0.000000000000 -vt 0.362277865410 0.146466180682 0.000000000000 -vt 0.364509135485 0.145325541496 0.000000000000 -vt 0.365181237459 0.146691560745 0.000000000000 -vt 0.366957485676 0.145109176636 0.000000000000 -vt 0.367903143167 0.146292820573 0.000000000000 -vt 0.363559901714 0.149057939649 0.000000000000 -vt 0.365885078907 0.148352980614 0.000000000000 -vt 0.368204176426 0.147704318166 0.000000000000 -vt 0.366324573755 0.155576184392 0.000000000000 -vt 0.366173952818 0.154380381107 0.000000000000 -vt 0.368186831474 0.153372362256 0.000000000000 -vt 0.368705600500 0.154601037502 0.000000000000 -vt 0.370330303907 0.152888730168 0.000000000000 -vt 0.371147632599 0.153870403767 0.000000000000 -vt 0.367092341185 0.156595915556 0.000000000000 -vt 0.369238078594 0.155905812979 0.000000000000 -vt 0.371273934841 0.155043467879 0.000000000000 -vt 0.359594911337 0.146293044090 0.000000000000 -vt 0.363820612431 0.143866091967 0.000000000000 -vt 0.368623167276 0.143500894308 0.000000000000 -vt 0.468312889338 0.463350683451 0.000000000000 -vt 0.396901309490 0.467744559050 0.000000000000 -vt 0.401809483767 0.467451632023 0.000000000000 -vt 0.371416240931 0.146074414253 0.000000000000 -vt 0.359569907188 0.149919614196 0.000000000000 -vt 0.374465495348 0.153269469738 0.000000000000 -vt 0.414790123701 0.478396862745 0.000000000000 -vt 0.447205245495 0.489582329988 0.000000000000 -vt 0.452684849501 0.491852372885 0.000000000000 -vt 0.449784398079 0.494581252337 0.000000000000 -vt 0.442751228809 0.493985742331 0.000000000000 -vt 0.434156626463 0.494034796953 0.000000000000 -vt 0.440118283033 0.488046973944 0.000000000000 -vt 0.434461027384 0.500024855137 0.000000000000 -vt 0.430395841599 0.501698195934 0.000000000000 -vt 0.425874501467 0.499181836843 0.000000000000 -vt 0.446397393942 0.499464601278 0.000000000000 -vt 0.440220713615 0.499364227057 0.000000000000 -vt 0.434654891491 0.512679457664 0.000000000000 -vt 0.435968428850 0.511407136917 0.000000000000 -vt 0.443066686392 0.505874812603 0.000000000000 -vt 0.438906043768 0.505390286446 0.000000000000 -vt 0.439353436232 0.502900302410 0.000000000000 -vt 0.444775164127 0.503243684769 0.000000000000 -vt 0.435113310814 0.505446374416 0.000000000000 -vt 0.434737980366 0.503206968307 0.000000000000 -vt 0.447127133608 0.507210433483 0.000000000000 -vt 0.449805349112 0.505035459995 0.000000000000 -vt 0.363566637039 0.157027080655 0.000000000000 -vt 0.371184110641 0.161255732179 0.000000000000 -vt 0.431567996740 0.505946636200 0.000000000000 -vt 0.430854707956 0.504090666771 0.000000000000 -vt 0.369521766901 0.161624297500 0.000000000000 -vt 0.369182020426 0.160728856921 0.000000000000 -vt 0.370721399784 0.159941717982 0.000000000000 -vt 0.372713804245 0.160549417138 0.000000000000 -vt 0.372284442186 0.159536883235 0.000000000000 -vt 0.372968226671 0.165679350495 0.000000000000 -vt 0.452052175999 0.500936031342 0.000000000000 -vt 0.368058949709 0.165135830641 0.000000000000 -vt 0.368970602751 0.162820771337 0.000000000000 -vt 0.371845602989 0.162883594632 0.000000000000 -vt 0.368251889944 0.160784929991 0.000000000000 -vt 0.370353937149 0.159135669470 0.000000000000 -vt 0.440568357706 0.509817063808 0.000000000000 -vt 0.437990337610 0.509382963181 0.000000000000 -vt 0.435604155064 0.509494423866 0.000000000000 -vt 0.443635433912 0.511720776558 0.000000000000 -vt 0.373006284237 0.158982783556 0.000000000000 -vt 0.376509696245 0.162375643849 0.000000000000 -vt 0.374031394720 0.161057814956 0.000000000000 -vt 0.389625668526 0.108183041215 0.000000000000 -vt 0.393046200275 0.109792903066 0.000000000000 -vt 0.392523407936 0.116342663765 0.000000000000 -vt 0.432401984930 0.510016977787 0.000000000000 -vt 0.438322216272 0.506984829903 0.000000000000 -vt 0.441790044308 0.507623851299 0.000000000000 -vt 0.435307621956 0.507277548313 0.000000000000 -vt 0.444958448410 0.509229838848 0.000000000000 -vt 0.392005532980 0.101636424661 0.000000000000 -vt 0.395671516657 0.103756263852 0.000000000000 -vt 0.407296061516 0.115123912692 0.000000000000 -vt 0.406397461891 0.121328055859 0.000000000000 -vt 0.403196871281 0.120348632336 0.000000000000 -vt 0.404978096485 0.114345774055 0.000000000000 -vt 0.432492733002 0.507707357407 0.000000000000 -vt 0.406864881516 0.108425304294 0.000000000000 -vt 0.409913033247 0.109619542956 0.000000000000 -vt 0.414692848921 0.117440745234 0.000000000000 -vt 0.416797161102 0.118163943291 0.000000000000 -vt 0.416874825954 0.124142721295 0.000000000000 -vt 0.413157969713 0.123205170035 0.000000000000 -vt 0.420296519995 0.113394036889 0.000000000000 -vt 0.416648089886 0.111873343587 0.000000000000 -vt 0.399549156427 0.117066100240 0.000000000000 -vt 0.397761642933 0.115746006370 0.000000000000 -vt 0.444640964270 0.482646912336 0.000000000000 -vt 0.435251086950 0.480776757002 0.000000000000 -vt 0.412997663021 0.489607781172 0.000000000000 -vt 0.415611475706 0.485968559980 0.000000000000 -vt 0.419600337744 0.489331930876 0.000000000000 -vt 0.418021112680 0.495383232832 0.000000000000 -vt 0.418760269880 0.480955928564 0.000000000000 -vt 0.451327174902 0.485552281141 0.000000000000 -vt 0.397986561060 0.111830547452 0.000000000000 -vt 0.400141090155 0.112691327929 0.000000000000 -vt 0.399654954672 0.108637854457 0.000000000000 -vt 0.401813089848 0.108847483993 0.000000000000 -vt 0.401618987322 0.117125526071 0.000000000000 -vt 0.402521193027 0.113518998027 0.000000000000 -vt 0.403585493565 0.110106542706 0.000000000000 -vt 0.409883081913 0.119960919023 0.000000000000 -vt 0.455791562796 0.489336222410 0.000000000000 -vt 0.422770082951 0.483635991812 0.000000000000 -vt 0.423145622015 0.491761177778 0.000000000000 -vt 0.408528327942 0.119000181556 0.000000000000 -vt 0.408956587315 0.115644469857 0.000000000000 -vt 0.410606950521 0.116135522723 0.000000000000 -vt 0.410386979580 0.112677589059 0.000000000000 -vt 0.421489149332 0.498041182756 0.000000000000 -vt 0.426815658808 0.486486226320 0.000000000000 -vt 0.430106759071 0.489818543196 0.000000000000 -vt 0.434814959764 0.486344844103 0.000000000000 -vt 0.426011174917 0.493239969015 0.000000000000 -vt 0.405869930983 0.480812519789 0.000000000000 -vt 0.412047952414 0.112628281116 0.000000000000 -vt 0.406924337149 0.485618025064 0.000000000000 -vt 0.401090562344 0.475320100784 0.000000000000 -vt 0.396311402321 0.475648850203 0.000000000000 -vt 0.411765158176 0.482897728682 0.000000000000 -vt 0.409521043301 0.480445533991 0.000000000000 -vt 0.453219145536 0.496879428625 0.000000000000 -vt 0.411550819874 0.119953945279 0.000000000000 -vt 0.412490606308 0.116729035974 0.000000000000 -vt 0.413484215736 0.113597795367 0.000000000000 -vt 0.395627617836 0.118285313249 0.000000000000 -vt 0.396080166101 0.111090466380 0.000000000000 -vt 0.399283915758 0.105090305209 0.000000000000 -vt 0.404269516468 0.104768797755 0.000000000000 -vt 0.398505777121 0.120832040906 0.000000000000 -vt 0.413978666067 0.108735352755 0.000000000000 -vt 0.409310519695 0.124303475022 0.000000000000 -vt 0.420999675989 0.119554504752 0.000000000000 -vt 0.420234143734 0.121525302529 0.000000000000 -vt 0.419045567513 0.121159419417 0.000000000000 -vt 0.419289410114 0.118994310498 0.000000000000 -vt 0.421489626169 0.117538690567 0.000000000000 -vt 0.420303285122 0.117139488459 0.000000000000 -vt 0.426694989204 0.121457740664 0.000000000000 -vt 0.422340482473 0.125688865781 0.000000000000 -vt 0.420924037695 0.122998699546 0.000000000000 -vt 0.423304349184 0.120309680700 0.000000000000 -vt 0.418264955282 0.122074902058 0.000000000000 -vt 0.417998820543 0.118570342660 0.000000000000 -vt 0.420178323984 0.115989848971 0.000000000000 -vt 0.425800204277 0.115537062287 0.000000000000 -vt 0.423050165176 0.116810753942 0.000000000000 -vt 0.377677112818 0.108308449388 0.000000000000 -vt 0.380777746439 0.100671857595 0.000000000000 -vt 0.387641370296 0.097277656198 0.000000000000 -vt 0.368460386992 0.119178041816 0.000000000000 -vt 0.370848834515 0.112134292722 0.000000000000 -vt 0.361701697111 0.122205942869 0.000000000000 -vt 0.350305467844 0.135973051190 0.000000000000 -vt 0.358212679625 0.109973028302 0.000000000000 -vt 0.353615224361 0.114691153169 0.000000000000 -vt 0.374976605177 0.093655571342 0.000000000000 -vt 0.389860272408 0.064062759280 0.000000000000 -vt 0.392403393984 0.070562094450 0.000000000000 -vt 0.387591153383 0.070836335421 0.000000000000 -vt 0.386600703001 0.064674735069 0.000000000000 -vt 0.390128880739 0.057090383023 0.000000000000 -vt 0.385809719563 0.057704154402 0.000000000000 -vt 0.381569832563 0.070360124111 0.000000000000 -vt 0.378056943417 0.070291683078 0.000000000000 -vt 0.376780331135 0.065116941929 0.000000000000 -vt 0.571491539478 0.142689660192 0.000000000000 -vt 0.576072752476 0.124807611108 0.000000000000 -vt 0.575986921787 0.141870543361 0.000000000000 -vt 0.787393748760 0.876816630363 0.000000000000 -vt 0.764766037464 0.871043145657 0.000000000000 -vt 0.754721701145 0.886201500893 0.000000000000 -vt 0.742770016193 0.866340160370 0.000000000000 -vt 0.734950125217 0.879857540131 0.000000000000 -vt 0.639134943485 0.405957043171 0.000000000000 -vt 0.626996815205 0.399863898754 0.000000000000 -vt 0.634920418262 0.394428640604 0.000000000000 -vt 0.639219582081 0.397930711508 0.000000000000 -vt 0.634795248508 0.383935958147 0.000000000000 -vt 0.643223226070 0.392979323864 0.000000000000 -vt 0.621101796627 0.387013614178 0.000000000000 -vt 0.588396847248 0.330318629742 0.000000000000 -vt 0.604378163815 0.331369876862 0.000000000000 -vt 0.613536059856 0.349697083235 0.000000000000 -vt 0.593470990658 0.343456894159 0.000000000000 -vt 0.615174353123 0.332106143236 0.000000000000 -vt 0.627085506916 0.345775991678 0.000000000000 -vt 0.635642707348 0.359163492918 0.000000000000 -vt 0.624931395054 0.369269371033 0.000000000000 -vt 0.614598810673 0.373340398073 0.000000000000 -vt 0.608756959438 0.360698610544 0.000000000000 -vt 0.595678865910 0.357187539339 0.000000000000 -vt 0.436208903790 0.152205392718 0.000000000000 -vt 0.456390678883 0.160455301404 0.000000000000 -vt 0.470007836819 0.150451436639 0.000000000000 -vt 0.463308125734 0.141743332148 0.000000000000 -vt 0.426335632801 0.240489169955 0.000000000000 -vt 0.436077862978 0.227415770292 0.000000000000 -vt 0.568314850330 0.508301794529 0.000000000000 -vt 0.585736811161 0.522079706192 0.000000000000 -vt 0.563862621784 0.526518404484 0.000000000000 -vt 0.552698671818 0.519208967686 0.000000000000 -vt 0.611942946911 0.313467800617 0.000000000000 -vt 0.543040931225 0.535523951054 0.000000000000 -vt 0.869499862194 0.252641230822 0.000000000000 -vt 0.794922888279 0.858771979809 0.000000000000 -vt 0.771254837513 0.855260670185 0.000000000000 -vt 0.747811377048 0.852186858654 0.000000000000 -vt 0.797975599766 0.840329766273 0.000000000000 -vt 0.773927867413 0.839067518711 0.000000000000 -vt 0.750024020672 0.837795853615 0.000000000000 -vt 0.816554009914 0.862926125526 0.000000000000 -vt 0.819631397724 0.841430306435 0.000000000000 -vt 0.863419592381 0.971586704254 0.000000000000 -vt 0.886208474636 0.956715881824 0.000000000000 -vt 0.845495879650 0.192380949855 0.000000000000 -vt 0.921158373356 0.909126162529 0.000000000000 -vt 0.928987085819 0.927418887615 0.000000000000 -vt 0.914810121059 0.888543367386 0.000000000000 -vt 0.449255734682 0.250441461802 0.000000000000 -vt 0.429135203362 0.255882352591 0.000000000000 -vt 0.454719811678 0.222426101565 0.000000000000 -vt 0.463549941778 0.236386403441 0.000000000000 -vt 0.480748862028 0.132810741663 0.000000000000 -vt 0.460707813501 0.129074752331 0.000000000000 -vt 0.890980184078 0.866303682327 0.000000000000 -vt 0.906893670559 0.863792300224 0.000000000000 -vt 0.901800453663 0.838266909122 0.000000000000 -vt 0.885961711407 0.839472353458 0.000000000000 -vt 0.672634780407 0.403682291508 0.000000000000 -vt 0.870305716991 0.840758919716 0.000000000000 -vt 0.709015905857 0.913828730583 0.000000000000 -vt 0.702005445957 0.906553089619 0.000000000000 -vt 0.664313495159 0.411870300770 0.000000000000 -vt 0.651246488094 0.405295312405 0.000000000000 -vt 0.658828794956 0.392099201679 0.000000000000 -vt 0.648704469204 0.380986869335 0.000000000000 -vt 0.598465621471 0.371364206076 0.000000000000 -vt 0.649795591831 0.422901540995 0.000000000000 -vt 0.666176021099 0.425574362278 0.000000000000 -vt 0.478667050600 0.121633604169 0.000000000000 -vt 0.439155727625 0.188678041101 0.000000000000 -vt 0.419110178947 0.186491340399 0.000000000000 -vt 0.828646361828 0.222074419260 0.000000000000 -vt 0.825475156307 0.193224608898 0.000000000000 -vt 0.842488110065 0.165252909064 0.000000000000 -vt 0.821768820286 0.166762799025 0.000000000000 -vt 0.836636006832 0.816951870918 0.000000000000 -vt 0.852425515652 0.813404560089 0.000000000000 -vt 0.638719737530 0.461908787489 0.000000000000 -vt 0.645538747311 0.442247092724 0.000000000000 -vt 0.666097700596 0.445383280516 0.000000000000 -vt 0.662395417690 0.464661508799 0.000000000000 -vt 0.617127835751 0.458045125008 0.000000000000 -vt 0.627697288990 0.440409153700 0.000000000000 -vt 0.635399162769 0.421377927065 0.000000000000 -vt 0.609715163708 0.435786485672 0.000000000000 -vt 0.619829595089 0.417641699314 0.000000000000 -vt 0.590706527233 0.430238008499 0.000000000000 -vt 0.600633800030 0.414015561342 0.000000000000 -vt 0.605100929737 0.397916287184 0.000000000000 -vt 0.580789983273 0.413832962513 0.000000000000 -vt 0.585207521915 0.396601408720 0.000000000000 -vt 0.583855688572 0.381996691227 0.000000000000 -vt 0.602939188480 0.384962439537 0.000000000000 -vt 0.583396375179 0.371497720480 0.000000000000 -vt 0.567030251026 0.398448109627 0.000000000000 -vt 0.565822064877 0.380739450455 0.000000000000 -vt 0.565940558910 0.366790413857 0.000000000000 -vt 0.546947419643 0.397279322147 0.000000000000 -vt 0.547453343868 0.381623625755 0.000000000000 -vt 0.546291291714 0.366621524096 0.000000000000 -vt 0.529646694660 0.384682595730 0.000000000000 -vt 0.528711616993 0.373113870621 0.000000000000 -vt 0.526230156422 0.363655120134 0.000000000000 -vt 0.543110311031 0.353565901518 0.000000000000 -vt 0.560514271259 0.346006095409 0.000000000000 -vt 0.521848142147 0.354256451130 0.000000000000 -vt 0.537153065205 0.340497672558 0.000000000000 -vt 0.550614297390 0.329262435436 0.000000000000 -vt 0.573693096638 0.334259301424 0.000000000000 -vt 0.565188109875 0.321530610323 0.000000000000 -vt 0.481604665518 0.473584860563 0.000000000000 -vt 0.503952205181 0.484111279249 0.000000000000 -vt 0.523758590221 0.503893256187 0.000000000000 -vt 0.516087591648 0.344791620970 0.000000000000 -vt 0.508227407932 0.335609555244 0.000000000000 -vt 0.518797814846 0.319672405720 0.000000000000 -vt 0.510983765125 0.468507856131 0.000000000000 -vt 0.490077227354 0.435670107603 0.000000000000 -vt 0.502925693989 0.448421299458 0.000000000000 -vt 0.522674977779 0.457363337278 0.000000000000 -vt 0.530655562878 0.477804929018 0.000000000000 -vt 0.538420259953 0.463601946831 0.000000000000 -vt 0.515796720982 0.440703213215 0.000000000000 -vt 0.534934461117 0.448625057936 0.000000000000 -vt 0.549823939800 0.452839523554 0.000000000000 -vt 0.557107031345 0.466927945614 0.000000000000 -vt 0.568541586399 0.456593096256 0.000000000000 -vt 0.547232806683 0.441114574671 0.000000000000 -vt 0.561775863171 0.442336261272 0.000000000000 -vt 0.578855931759 0.444288581610 0.000000000000 -vt 0.586479246616 0.463815152645 0.000000000000 -vt 0.597201764584 0.451105147600 0.000000000000 -vt 0.571721136570 0.429578959942 0.000000000000 -vt 0.557132422924 0.430043905973 0.000000000000 -vt 0.564029395580 0.415538519621 0.000000000000 -vt 0.537347137928 0.424302697182 0.000000000000 -vt 0.544077932835 0.411527603865 0.000000000000 -vt 0.518473088741 0.418114066124 0.000000000000 -vt 0.524959385395 0.408595174551 0.000000000000 -vt 0.528635084629 0.397043138742 0.000000000000 -vt 0.509449779987 0.404620736837 0.000000000000 -vt 0.513173401356 0.395612955093 0.000000000000 -vt 0.514248788357 0.385702759027 0.000000000000 -vt 0.513777077198 0.377086073160 0.000000000000 -vt 0.512884557247 0.370190680027 0.000000000000 -vt 0.510034501553 0.363916963339 0.000000000000 -vt 0.505580484867 0.356326758862 0.000000000000 -vt 0.500341594219 0.348006844521 0.000000000000 -vt 0.481183856726 0.423593431711 0.000000000000 -vt 0.500625789165 0.430742353201 0.000000000000 -vt 0.490146607161 0.420840919018 0.000000000000 -vt 0.498169153929 0.417084664106 0.000000000000 -vt 0.510002553463 0.425448060036 0.000000000000 -vt 0.527178347111 0.433869749308 0.000000000000 -vt 0.503946959972 0.411769419909 0.000000000000 -vt 0.596737325191 0.484501451254 0.000000000000 -vt 0.576489269733 0.474731117487 0.000000000000 -vt 0.606985628605 0.472689867020 0.000000000000 -vt 0.584141671658 0.495642870665 0.000000000000 -vt 0.563076555729 0.485377997160 0.000000000000 -vt 0.546334922314 0.479332834482 0.000000000000 -vt 0.550337493420 0.497008413076 0.000000000000 -vt 0.537908732891 0.494894415140 0.000000000000 -vt 0.526974737644 0.490041226149 0.000000000000 -vt 0.537790954113 0.509640336037 0.000000000000 -vt 0.527427136898 0.525675892830 0.000000000000 -vt 0.605959832668 0.507260859013 0.000000000000 -vt 0.620633423328 0.493587821722 0.000000000000 -vt 0.631438195705 0.478594750166 0.000000000000 -vt 0.817847788334 0.142355754972 0.000000000000 -vt 0.814487040043 0.119411304593 0.000000000000 -vt 0.658278763294 0.481082051992 0.000000000000 -vt 0.811750113964 0.097056999803 0.000000000000 -vt 0.809368431568 0.075157731771 0.000000000000 -vt 0.807133018970 0.053564000875 0.000000000000 -vt 0.831686437130 0.254841685295 0.000000000000 -vt 0.856208741665 0.293983995914 0.000000000000 -vt 0.835455358028 0.290136784315 0.000000000000 -vt 0.873124063015 0.283648252487 0.000000000000 -vt 0.889739573002 0.279546380043 0.000000000000 -vt 0.909207642078 0.276814579964 0.000000000000 -vt 0.929072201252 0.276617109776 0.000000000000 -vt 0.884098351002 0.044427882880 0.000000000000 -vt 0.824312150478 0.028333339840 0.000000000000 -vt 0.804996788502 0.032941136509 0.000000000000 -vt 0.745384037495 0.153986141086 0.000000000000 -vt 0.727315604687 0.170344561338 0.000000000000 -vt 0.831523954868 0.792076110840 0.000000000000 -vt 0.846453726292 0.786361873150 0.000000000000 -vt 0.871971428394 0.766853511333 0.000000000000 -vt 0.860507428646 0.778107702732 0.000000000000 -vt 0.849813520908 0.750272214413 0.000000000000 -vt 0.864782273769 0.752571046352 0.000000000000 -vt 0.641757309437 0.369858145714 0.000000000000 -vt 0.871010005474 0.740061163902 0.000000000000 -vt 0.856036365032 0.728532135487 0.000000000000 -vt 0.833810746670 0.763259589672 0.000000000000 -vt 0.880542218685 0.781249523163 0.000000000000 -vt 0.870216548443 0.805862307549 0.000000000000 -vt 0.895947515965 0.765040814877 0.000000000000 -vt 0.886363804340 0.766362249851 0.000000000000 -vt 0.881665766239 0.753908455372 0.000000000000 -vt 0.896844565868 0.741948008537 0.000000000000 -vt 0.892329037189 0.786806523800 0.000000000000 -vt 0.730150520802 0.779693901539 0.000000000000 -vt 0.720385253429 0.768897235394 0.000000000000 -vt 0.732248246670 0.757981956005 0.000000000000 -vt 0.746850073338 0.773370444775 0.000000000000 -vt 0.746807038784 0.737674295902 0.000000000000 -vt 0.754076421261 0.750202596188 0.000000000000 -vt 0.729847013950 0.741506457329 0.000000000000 -vt 0.766269385815 0.766434729099 0.000000000000 -vt 0.732167899609 0.725132286549 0.000000000000 -vt 0.744101583958 0.727173089981 0.000000000000 -vt 0.726897180080 0.154936745763 0.000000000000 -vt 0.736608207226 0.138647675514 0.000000000000 -vt 0.757733404636 0.048427533358 0.000000000000 -vt 0.748305857182 0.039854753762 0.000000000000 -vt 0.762275159359 0.025697443634 0.000000000000 -vt 0.771673381329 0.029945448041 0.000000000000 -vt 0.737863123417 0.066377580166 0.000000000000 -vt 0.730143487453 0.052494283766 0.000000000000 -vt 0.754568159580 0.099855229259 0.000000000000 -vt 0.731352865696 0.116734221578 0.000000000000 -vt 0.725217759609 0.099748730659 0.000000000000 -vt 0.746904551983 0.081010863185 0.000000000000 -vt 0.718968212605 0.084019616246 0.000000000000 -vt 0.786774814129 0.105366572738 0.000000000000 -vt 0.761492788792 0.119630172849 0.000000000000 -vt 0.781676113605 0.084223598242 0.000000000000 -vt 0.775007426739 0.059413980693 0.000000000000 -vt 0.791212141514 0.126294299960 0.000000000000 -vt 0.767748415470 0.138232484460 0.000000000000 -vt 0.435300618410 0.206924617290 0.000000000000 -vt 0.415769994259 0.205245867372 0.000000000000 -vt 0.415477305651 0.223549634218 0.000000000000 -vt 0.415708750486 0.260153979063 0.000000000000 -vt 0.415216326714 0.241337999701 0.000000000000 -vt 0.431532442570 0.277840822935 0.000000000000 -vt 0.416861325502 0.282650142908 0.000000000000 -vt 0.437933146954 0.297910034657 0.000000000000 -vt 0.422700941563 0.304020076990 0.000000000000 -vt 0.710437953472 0.745294928551 0.000000000000 -vt 0.448528498411 0.274154812098 0.000000000000 -vt 0.453730016947 0.292313814163 0.000000000000 -vt 0.466458499432 0.272584140301 0.000000000000 -vt 0.470066845417 0.288187146187 0.000000000000 -vt 0.483627885580 0.271198511124 0.000000000000 -vt 0.486174434423 0.284226238728 0.000000000000 -vt 0.468398451805 0.256950020790 0.000000000000 -vt 0.484410136938 0.259565204382 0.000000000000 -vt 0.499547928572 0.260835975409 0.000000000000 -vt 0.488594621420 0.251296162605 0.000000000000 -vt 0.500861465931 0.255602240562 0.000000000000 -vt 0.476949125528 0.155961647630 0.000000000000 -vt 0.496368080378 0.154256105423 0.000000000000 -vt 0.493585199118 0.162589550018 0.000000000000 -vt 0.484565943480 0.159969419241 0.000000000000 -vt 0.504522025585 0.250607877970 0.000000000000 -vt 0.490841835737 0.170824587345 0.000000000000 -vt 0.479497641325 0.168406203389 0.000000000000 -vt 0.468820154667 0.165049582720 0.000000000000 -vt 0.487937420607 0.179314747453 0.000000000000 -vt 0.474618524313 0.178034290671 0.000000000000 -vt 0.461312592030 0.176021173596 0.000000000000 -vt 0.485546678305 0.188977956772 0.000000000000 -vt 0.470588952303 0.189741462469 0.000000000000 -vt 0.455546349287 0.189690113068 0.000000000000 -vt 0.484867841005 0.200385212898 0.000000000000 -vt 0.468716144562 0.203217670321 0.000000000000 -vt 0.452557861805 0.205941826105 0.000000000000 -vt 0.486695379019 0.212983325124 0.000000000000 -vt 0.470563501120 0.217475160956 0.000000000000 -vt 0.498891204596 0.197758778930 0.000000000000 -vt 0.500793755054 0.208588525653 0.000000000000 -vt 0.503768861294 0.215860128403 0.000000000000 -vt 0.490694373846 0.221827194095 0.000000000000 -vt 0.476610749960 0.228770300746 0.000000000000 -vt 0.508271515369 0.222307890654 0.000000000000 -vt 0.496900588274 0.229248985648 0.000000000000 -vt 0.485334604979 0.237566873431 0.000000000000 -vt 0.505223691463 0.237320348620 0.000000000000 -vt 0.495418399572 0.244713291526 0.000000000000 -vt 0.475383609533 0.245258644223 0.000000000000 -vt 0.514443337917 0.230237171054 0.000000000000 -vt 0.519902884960 0.237665936351 0.000000000000 -vt 0.511179625988 0.154767423868 0.000000000000 -vt 0.523703515530 0.224226221442 0.000000000000 -vt 0.534955561161 0.219976648688 0.000000000000 -vt 0.539630472660 0.226309135556 0.000000000000 -vt 0.522125780582 0.163012161851 0.000000000000 -vt 0.511400759220 0.162948891521 0.000000000000 -vt 0.502651274204 0.163395151496 0.000000000000 -vt 0.521724998951 0.170782491565 0.000000000000 -vt 0.510841667652 0.171353936195 0.000000000000 -vt 0.501311361790 0.171751782298 0.000000000000 -vt 0.521135985851 0.178479418159 0.000000000000 -vt 0.510029613972 0.179412469268 0.000000000000 -vt 0.499761670828 0.179692775011 0.000000000000 -vt 0.521464765072 0.184219524264 0.000000000000 -vt 0.509710252285 0.186720550060 0.000000000000 -vt 0.498645514250 0.187971740961 0.000000000000 -vt 0.522567331791 0.189815983176 0.000000000000 -vt 0.510646045208 0.194714680314 0.000000000000 -vt 0.552625119686 0.181308269501 0.000000000000 -vt 0.553095877171 0.186058148742 0.000000000000 -vt 0.535693705082 0.186998158693 0.000000000000 -vt 0.534666717052 0.182170838118 0.000000000000 -vt 0.553785145283 0.190441906452 0.000000000000 -vt 0.537737786770 0.193066775799 0.000000000000 -vt 0.524687230587 0.197172924876 0.000000000000 -vt 0.554820120335 0.194571927190 0.000000000000 -vt 0.540497124195 0.200262054801 0.000000000000 -vt 0.527609050274 0.205128788948 0.000000000000 -vt 0.556690990925 0.198639363050 0.000000000000 -vt 0.543533384800 0.206711396575 0.000000000000 -vt 0.531002581120 0.212646707892 0.000000000000 -vt 0.558761537075 0.202166423202 0.000000000000 -vt 0.546805322170 0.212670803070 0.000000000000 -vt 0.550771892071 0.218399211764 0.000000000000 -vt 0.561493337154 0.206085249782 0.000000000000 -vt 0.535221517086 0.163484767079 0.000000000000 -vt 0.552473127842 0.164653763175 0.000000000000 -vt 0.534547865391 0.169898986816 0.000000000000 -vt 0.552217543125 0.170028448105 0.000000000000 -vt 0.534365713596 0.176693260670 0.000000000000 -vt 0.552374064922 0.175845101476 0.000000000000 -vt 0.432602375746 0.133366212249 0.000000000000 -vt 0.579707443714 0.344648867846 0.000000000000 -vt 0.582962691784 0.359227657318 0.000000000000 -vt 0.699510276318 0.760418593884 0.000000000000 -vt 0.690002620220 0.760535240173 0.000000000000 -vt 0.573572456837 0.358697652817 0.000000000000 -vt 0.571034729481 0.348925471306 0.000000000000 -vt 0.795890152454 0.148126482964 0.000000000000 -vt 0.773672997952 0.158082619309 0.000000000000 -vt 0.761886537075 0.368884116411 0.000000000000 -vt 0.756864488125 0.374716073275 0.000000000000 -vt 0.752732694149 0.371530354023 0.000000000000 -vt 0.756020605564 0.368056684732 0.000000000000 -vt 0.745198905468 0.426691144705 0.000000000000 -vt 0.748513877392 0.424927502871 0.000000000000 -vt 0.751336514950 0.428736001253 0.000000000000 -vt 0.745641887188 0.430311173201 0.000000000000 -vt 0.718655884266 0.367600291967 0.000000000000 -vt 0.723707854748 0.362223118544 0.000000000000 -vt 0.731543242931 0.368654459715 0.000000000000 -vt 0.727982223034 0.373404115438 0.000000000000 -vt 0.723776161671 0.384299814701 0.000000000000 -vt 0.712015807629 0.382623314857 0.000000000000 -vt 0.714580357075 0.374560505152 0.000000000000 -vt 0.725447237492 0.378716200590 0.000000000000 -vt 0.743162930012 0.370530217886 0.000000000000 -vt 0.739214956760 0.374083191156 0.000000000000 -vt 0.736095726490 0.364764451981 0.000000000000 -vt 0.470379114151 0.072487622499 0.000000000000 -vt 0.476932018995 0.067091092467 0.000000000000 -vt 0.483967453241 0.075338751078 0.000000000000 -vt 0.477926939726 0.080794483423 0.000000000000 -vt 0.511079013348 0.066174268723 0.000000000000 -vt 0.508617579937 0.072203919291 0.000000000000 -vt 0.499857753515 0.062445472926 0.000000000000 -vt 0.504508316517 0.058762382716 0.000000000000 -vt 0.705864846706 0.371028959751 0.000000000000 -vt 0.701381266117 0.375573486090 0.000000000000 -vt 0.698225557804 0.370354384184 0.000000000000 -vt 0.697068870068 0.367405295372 0.000000000000 -vt 0.701902329922 0.391683101654 0.000000000000 -vt 0.691578447819 0.393901556730 0.000000000000 -vt 0.693959891796 0.392793804407 0.000000000000 -vt 0.699081957340 0.388415664434 0.000000000000 -vt 0.712482511997 0.363048106432 0.000000000000 -vt 0.706260859966 0.399656295776 0.000000000000 -vt 0.710350573063 0.390655279160 0.000000000000 -vt 0.709410727024 0.398413658142 0.000000000000 -vt 0.497506469488 0.086208790541 0.000000000000 -vt 0.499487847090 0.088523834944 0.000000000000 -vt 0.496975511312 0.090857118368 0.000000000000 -vt 0.494485110044 0.087826982141 0.000000000000 -vt 0.485454589128 0.095807611942 0.000000000000 -vt 0.487140089273 0.098796099424 0.000000000000 -vt 0.483731955290 0.100186884403 0.000000000000 -vt 0.481757134199 0.096767678857 0.000000000000 -vt 0.701098263264 0.382279485464 0.000000000000 -vt 0.704454600811 0.381990849972 0.000000000000 -vt 0.505547583103 0.089302882552 0.000000000000 -vt 0.507946908474 0.095191136003 0.000000000000 -vt 0.725627362728 0.354063272476 0.000000000000 -vt 0.730535089970 0.352071553469 0.000000000000 -vt 0.733845055103 0.356517255306 0.000000000000 -vt 0.729133427143 0.358981132507 0.000000000000 -vt 0.502358973026 0.098305702209 0.000000000000 -vt 0.499749034643 0.094421327114 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.499274820089 0.102383270860 0.000000000000 -vt 0.709335625172 0.404707193375 0.000000000000 -vt 0.707483947277 0.405635058880 0.000000000000 -vt 0.516392290592 0.069226473570 0.000000000000 -vt 0.518077909946 0.071355760098 0.000000000000 -vt 0.718284785748 0.355620443821 0.000000000000 -vt 0.516956746578 0.073715612292 0.000000000000 -vt 0.514483392239 0.070643588901 0.000000000000 -vt 0.668390452862 0.386624544859 0.000000000000 -vt 0.667060911655 0.380806088448 0.000000000000 -vt 0.671376407146 0.380861908197 0.000000000000 -vt 0.671312749386 0.384570688009 0.000000000000 -vt 0.669187486172 0.375094115734 0.000000000000 -vt 0.671998560429 0.377249538898 0.000000000000 -vt 0.691448748112 0.370133042336 0.000000000000 -vt 0.690848052502 0.375890284777 0.000000000000 -vt 0.686910808086 0.375525057316 0.000000000000 -vt 0.687306106091 0.369519740343 0.000000000000 -vt 0.686368644238 0.386486738920 0.000000000000 -vt 0.689943373203 0.386325776577 0.000000000000 -vt 0.688951313496 0.392648577690 0.000000000000 -vt 0.685665905476 0.393045514822 0.000000000000 -vt 0.690709650517 0.381118148565 0.000000000000 -vt 0.686853349209 0.380862385035 0.000000000000 -vt 0.480086654425 0.100869327784 0.000000000000 -vt 0.478839308023 0.098695233464 0.000000000000 -vt 0.678826630116 0.369220048189 0.000000000000 -vt 0.679812729359 0.375340670347 0.000000000000 -vt 0.675520837307 0.375914126635 0.000000000000 -vt 0.673433959484 0.370380729437 0.000000000000 -vt 0.674808919430 0.385995447636 0.000000000000 -vt 0.679343521595 0.386584460735 0.000000000000 -vt 0.678030192852 0.392984062433 0.000000000000 -vt 0.672598540783 0.391514003277 0.000000000000 -vt 0.680286943913 0.380828380585 0.000000000000 -vt 0.675836026669 0.380848854780 0.000000000000 -vt 0.515295088291 0.075423642993 0.000000000000 -vt 0.513281047344 0.073069870472 0.000000000000 -vt 0.693681657314 0.376642733812 0.000000000000 -vt 0.693711340427 0.371875762939 0.000000000000 -vt 0.696114480495 0.370918631554 0.000000000000 -vt 0.696933090687 0.376871287823 0.000000000000 -vt 0.691533505917 0.391513794661 0.000000000000 -vt 0.692914068699 0.386218369007 0.000000000000 -vt 0.695932805538 0.386784404516 0.000000000000 -vt 0.693213999271 0.392598807812 0.000000000000 -vt 0.693558990955 0.381606072187 0.000000000000 -vt 0.696726262569 0.381991982460 0.000000000000 -vt 0.512632310390 0.113346979022 0.000000000000 -vt 0.510703504086 0.110827267170 0.000000000000 -vt 0.515379965305 0.107007056475 0.000000000000 -vt 0.518175065517 0.110701844096 0.000000000000 -vt 0.505509078503 0.114236339927 0.000000000000 -vt 0.508307397366 0.117514595389 0.000000000000 -vt 0.518149077892 0.121353730559 0.000000000000 -vt 0.522928655148 0.117672875524 0.000000000000 -vt 0.525190651417 0.121514260769 0.000000000000 -vt 0.683571517467 0.375538796186 0.000000000000 -vt 0.683092653751 0.370623677969 0.000000000000 -vt 0.682278931141 0.392029613256 0.000000000000 -vt 0.683356225491 0.386358857155 0.000000000000 -vt 0.684057652950 0.380769610405 0.000000000000 -vt 0.519570291042 0.123483464122 0.000000000000 -vt 0.516307771206 0.128428325057 0.000000000000 -vt 0.513406455517 0.124672070146 0.000000000000 -vt 0.511565864086 0.103494629264 0.000000000000 -vt 0.507416427135 0.106189742684 0.000000000000 -vt 0.506013691425 0.103982776403 0.000000000000 -vt 0.509203732014 0.102665841579 0.000000000000 -vt 0.504296243191 0.108756288886 0.000000000000 -vt 0.503382742405 0.106384947896 0.000000000000 -vt 0.511651098728 0.106469616294 0.000000000000 -vt 0.509026229382 0.108525276184 0.000000000000 -vt 0.506196796894 0.110484585166 0.000000000000 -vt 0.518708407879 0.115314379334 0.000000000000 -vt 0.515459358692 0.117382884026 0.000000000000 -vt 0.514127433300 0.115409389138 0.000000000000 -vt 0.518203437328 0.112691774964 0.000000000000 -vt 0.512567102909 0.119688019156 0.000000000000 -vt 0.511780798435 0.117559626698 0.000000000000 -vt 0.519389688969 0.117316469550 0.000000000000 -vt 0.516777694225 0.119350507855 0.000000000000 -vt 0.514133274555 0.121143206954 0.000000000000 -vt 0.510631144047 0.099778667092 0.000000000000 -vt 0.504632174969 0.101817682385 0.000000000000 -vt 0.499871104956 0.106421664357 0.000000000000 -vt 0.500889837742 0.111934348941 0.000000000000 -vt 0.514839589596 0.101724907756 0.000000000000 -vt 0.509192049503 0.122385606170 0.000000000000 -vt 0.522657573223 0.113145455718 0.000000000000 -vt 0.522569835186 0.127797886729 0.000000000000 -vt 0.521396934986 0.126231938601 0.000000000000 -vt 0.735525667667 0.349380731583 0.000000000000 -vt 0.738029062748 0.353152751923 0.000000000000 -vt 0.709487140179 0.411515235901 0.000000000000 -vt 0.706850707531 0.412472575903 0.000000000000 -vt 0.713795721531 0.355628103018 0.000000000000 -vt 0.714886367321 0.349705845118 0.000000000000 -vt 0.715047299862 0.346170902252 0.000000000000 -vt 0.700704872608 0.366192162037 0.000000000000 -vt 0.705918371677 0.365258455276 0.000000000000 -vt 0.710480749607 0.361039042473 0.000000000000 -vt 0.523268878460 0.125216260552 0.000000000000 -vt 0.523997724056 0.126300171018 0.000000000000 -vt 0.687866628170 0.342219889164 0.000000000000 -vt 0.691187441349 0.337702393532 0.000000000000 -vt 0.693574011326 0.340425401926 0.000000000000 -vt 0.690801203251 0.342919677496 0.000000000000 -vt 0.696296155453 0.334926456213 0.000000000000 -vt 0.696642935276 0.338050007820 0.000000000000 -vt 0.711912453175 0.345587313175 0.000000000000 -vt 0.707153379917 0.348584800959 0.000000000000 -vt 0.704814493656 0.344684004784 0.000000000000 -vt 0.710185706615 0.341764390469 0.000000000000 -vt 0.695865690708 0.351892799139 0.000000000000 -vt 0.699073016644 0.355076700449 0.000000000000 -vt 0.695596873760 0.359068036079 0.000000000000 -vt 0.692301213741 0.356082707644 0.000000000000 -vt 0.702675044537 0.351823449135 0.000000000000 -vt 0.699874341488 0.348093301058 0.000000000000 -vt 0.520938813686 0.128895744681 0.000000000000 -vt 0.520082056522 0.127839773893 0.000000000000 -vt 0.705446422100 0.335541337729 0.000000000000 -vt 0.701623976231 0.340389162302 0.000000000000 -vt 0.699281990528 0.338887810707 0.000000000000 -vt 0.701398193836 0.333822280169 0.000000000000 -vt 0.691363513470 0.345513224602 0.000000000000 -vt 0.692718684673 0.347970575094 0.000000000000 -vt 0.688071906567 0.350903898478 0.000000000000 -vt 0.686495840549 0.347062766552 0.000000000000 -vt 0.697414934635 0.344720244408 0.000000000000 -vt 0.695644319057 0.342764317989 0.000000000000 -vt 0.526300132275 0.132303252816 0.000000000000 -vt 0.524093449116 0.129697531462 0.000000000000 -vt 0.709353864193 0.352346479893 0.000000000000 -vt 0.712929904461 0.348732739687 0.000000000000 -vt 0.714268267155 0.349192053080 0.000000000000 -vt 0.711979806423 0.354660391808 0.000000000000 -vt 0.699490010738 0.361016511917 0.000000000000 -vt 0.702696144581 0.358416646719 0.000000000000 -vt 0.704991638660 0.361978620291 0.000000000000 -vt 0.700050175190 0.364112406969 0.000000000000 -vt 0.705978453159 0.355808466673 0.000000000000 -vt 0.708694994450 0.358966708183 0.000000000000 -vt 0.525715887547 0.126499876380 0.000000000000 -vt 0.528771936893 0.126690357924 0.000000000000 -vt 0.523779094219 0.124067738652 0.000000000000 -vt 0.520451605320 0.124855801463 0.000000000000 -vt 0.518978536129 0.127953931689 0.000000000000 -vt 0.520814955235 0.130581036210 0.000000000000 -vt 0.520374357700 0.133407860994 0.000000000000 -vt 0.508442223072 0.077186152339 0.000000000000 -vt 0.510329902172 0.079375565052 0.000000000000 -vt 0.703039348125 0.342263132334 0.000000000000 -vt 0.707691013813 0.338801592588 0.000000000000 -vt 0.691107928753 0.352693885565 0.000000000000 -vt 0.694404184818 0.349684000015 0.000000000000 -vt 0.698663651943 0.346254229546 0.000000000000 -vt 0.508014619350 0.081564977765 0.000000000000 -vt 0.505533874035 0.078727111220 0.000000000000 -vt 0.494260638952 0.093220800161 0.000000000000 -vt 0.492302030325 0.090663939714 0.000000000000 -vt 0.505529224873 0.083532154560 0.000000000000 -vt 0.503514945507 0.081306725740 0.000000000000 -vt 0.510711610317 0.084656804800 0.000000000000 -vt 0.514165699482 0.088350698352 0.000000000000 -vt 0.511911690235 0.093188375235 0.000000000000 -vt 0.527652680874 0.098926231265 0.000000000000 -vt 0.525356113911 0.097472637892 0.000000000000 -vt 0.528094470501 0.091692224145 0.000000000000 -vt 0.531258046627 0.093997821212 0.000000000000 -vt 0.521796643734 0.102959886193 0.000000000000 -vt 0.525596559048 0.105276063085 0.000000000000 -vt 0.534857928753 0.104219183326 0.000000000000 -vt 0.537856757641 0.099045574665 0.000000000000 -vt 0.540888249874 0.101543441415 0.000000000000 -vt 0.536647617817 0.105644643307 0.000000000000 -vt 0.534925162792 0.111184135079 0.000000000000 -vt 0.531729161739 0.109336286783 0.000000000000 -vt 0.523591578007 0.091089487076 0.000000000000 -vt 0.730021059513 0.349459081888 0.000000000000 -vt 0.735328376293 0.349237293005 0.000000000000 -vt 0.715811312199 0.346691012383 0.000000000000 -vt 0.720742166042 0.350149869919 0.000000000000 -vt 0.725372970104 0.349892735481 0.000000000000 -vt 0.521666467190 0.094739928842 0.000000000000 -vt 0.520136296749 0.093459248543 0.000000000000 -vt 0.731795966625 0.325470387936 0.000000000000 -vt 0.736351430416 0.326853275299 0.000000000000 -vt 0.734878718853 0.329794704914 0.000000000000 -vt 0.732054173946 0.328241348267 0.000000000000 -vt 0.739810764790 0.330046653748 0.000000000000 -vt 0.737516939640 0.331477284431 0.000000000000 -vt 0.737019240856 0.345520436764 0.000000000000 -vt 0.732173502445 0.343047350645 0.000000000000 -vt 0.734046399593 0.340439140797 0.000000000000 -vt 0.738021910191 0.343094855547 0.000000000000 -vt 0.725114047527 0.336557924747 0.000000000000 -vt 0.723978340626 0.339484244585 0.000000000000 -vt 0.718742549419 0.338676393032 0.000000000000 -vt 0.720449268818 0.335456222296 0.000000000000 -vt 0.728333771229 0.341184616089 0.000000000000 -vt 0.729620277882 0.338552564383 0.000000000000 -vt 0.521848857403 0.090589866042 0.000000000000 -vt 0.519341766834 0.098529517651 0.000000000000 -vt 0.741242706776 0.337124168873 0.000000000000 -vt 0.736575305462 0.336675226688 0.000000000000 -vt 0.737431108952 0.333985060453 0.000000000000 -vt 0.741768896580 0.333650708199 0.000000000000 -vt 0.730156362057 0.329479277134 0.000000000000 -vt 0.728279173374 0.331620484591 0.000000000000 -vt 0.724462211132 0.328425318003 0.000000000000 -vt 0.727317392826 0.325960755348 0.000000000000 -vt 0.732129871845 0.334760516882 0.000000000000 -vt 0.733519494534 0.332428127527 0.000000000000 -vt 0.518350422382 0.096643164754 0.000000000000 -vt 0.524855554104 0.092653632164 0.000000000000 -vt 0.731151521206 0.345263779163 0.000000000000 -vt 0.735784590244 0.347043156624 0.000000000000 -vt 0.736424624920 0.348627597094 0.000000000000 -vt 0.730661809444 0.347184121609 0.000000000000 -vt 0.718040287495 0.341615349054 0.000000000000 -vt 0.723183095455 0.342720180750 0.000000000000 -vt 0.721934854984 0.345855712891 0.000000000000 -vt 0.715493619442 0.344276010990 0.000000000000 -vt 0.727172791958 0.344054907560 0.000000000000 -vt 0.726349413395 0.346510440111 0.000000000000 -vt 0.523354947567 0.096010923386 0.000000000000 -vt 0.521311223507 0.099254280329 0.000000000000 -vt 0.533330857754 0.097978785634 0.000000000000 -vt 0.531335532665 0.101454958320 0.000000000000 -vt 0.529585421085 0.100170671940 0.000000000000 -vt 0.531549036503 0.097181737423 0.000000000000 -vt 0.529571712017 0.105359822512 0.000000000000 -vt 0.528426826000 0.103743880987 0.000000000000 -vt 0.534639537334 0.099621966481 0.000000000000 -vt 0.735392153263 0.338480740786 0.000000000000 -vt 0.739044845104 0.340150952339 0.000000000000 -vt 0.723158061504 0.331868380308 0.000000000000 -vt 0.726885974407 0.334070175886 0.000000000000 -vt 0.730814039707 0.336822479963 0.000000000000 -vt 0.533084571362 0.102829977870 0.000000000000 -vt 0.531313717365 0.105897054076 0.000000000000 -vt 0.521283328533 0.087026789784 0.000000000000 -vt 0.517856895924 0.091663181782 0.000000000000 -vt 0.514960706234 0.097525775433 0.000000000000 -vt 0.517828285694 0.100980103016 0.000000000000 -vt 0.526034533978 0.087389066815 0.000000000000 -vt 0.527589142323 0.109247803688 0.000000000000 -vt 0.535756528378 0.095117062330 0.000000000000 -vt 0.539837419987 0.107863321900 0.000000000000 -vt 0.538558781147 0.107128873467 0.000000000000 -vt 0.539949953556 0.105316147208 0.000000000000 -vt 0.540825903416 0.105864629149 0.000000000000 -vt 0.538582384586 0.109620437026 0.000000000000 -vt 0.537616670132 0.109082773328 0.000000000000 -vt 0.544267117977 0.110548302531 0.000000000000 -vt 0.541652381420 0.108950823545 0.000000000000 -vt 0.542387545109 0.105380535126 0.000000000000 -vt 0.545064866543 0.104814276099 0.000000000000 -vt 0.540196716785 0.104028716683 0.000000000000 -vt 0.537597596645 0.106465324759 0.000000000000 -vt 0.536735951900 0.109748318791 0.000000000000 -vt 0.701508939266 0.396991372108 0.000000000000 -vt 0.695306599140 0.396085560322 0.000000000000 -vt 0.705828607082 0.412745684385 0.000000000000 -vt 0.705876052380 0.406576901674 0.000000000000 -vt 0.704530298710 0.401503235102 0.000000000000 -vt 0.538923561573 0.111143380404 0.000000000000 -vt 0.539531409740 0.113621219993 0.000000000000 -vt 0.688302695751 0.427976310253 0.000000000000 -vt 0.683832943439 0.424098700285 0.000000000000 -vt 0.687000572681 0.421046495438 0.000000000000 -vt 0.689052641392 0.424283087254 0.000000000000 -vt 0.681496918201 0.418339222670 0.000000000000 -vt 0.684903800488 0.417768895626 0.000000000000 -vt 0.690302073956 0.401867091656 0.000000000000 -vt 0.694480240345 0.405638903379 0.000000000000 -vt 0.692191779613 0.407944500446 0.000000000000 -vt 0.687600672245 0.404441058636 0.000000000000 -vt 0.699370443821 0.415826499462 0.000000000000 -vt 0.700973808765 0.413097828627 0.000000000000 -vt 0.704431712627 0.417759448290 0.000000000000 -vt 0.703326642513 0.420762330294 0.000000000000 -vt 0.697867929935 0.408945530653 0.000000000000 -vt 0.695929110050 0.411309421062 0.000000000000 -vt 0.517626106739 0.084983274341 0.000000000000 -vt 0.521136224270 0.070760220289 0.000000000000 -vt 0.683233559132 0.409444689751 0.000000000000 -vt 0.688319623470 0.412122905254 0.000000000000 -vt 0.686133563519 0.414829730988 0.000000000000 -vt 0.680900275707 0.412907809019 0.000000000000 -vt 0.692204892635 0.422975838184 0.000000000000 -vt 0.695665299892 0.420329362154 0.000000000000 -vt 0.698658287525 0.425916135311 0.000000000000 -vt 0.694272696972 0.428446441889 0.000000000000 -vt 0.692554771900 0.415226012468 0.000000000000 -vt 0.689908921719 0.417935758829 0.000000000000 -vt 0.523216187954 0.072577908635 0.000000000000 -vt 0.520890176296 0.077228039503 0.000000000000 -vt 0.697199761868 0.403361231089 0.000000000000 -vt 0.693439781666 0.400654852390 0.000000000000 -vt 0.693814694881 0.397902786732 0.000000000000 -vt 0.699269115925 0.401036739349 0.000000000000 -vt 0.704553306103 0.414974272251 0.000000000000 -vt 0.702452123165 0.410426139832 0.000000000000 -vt 0.703826010227 0.408506244421 0.000000000000 -vt 0.705401599407 0.414679765701 0.000000000000 -vt 0.700053751469 0.406474679708 0.000000000000 -vt 0.701919615269 0.404333680868 0.000000000000 -vt 0.519232571125 0.075901642442 0.000000000000 -vt 0.515266001225 0.080151677132 0.000000000000 -vt 0.519640505314 0.081991866231 0.000000000000 -vt 0.533958613873 0.080200076103 0.000000000000 -vt 0.531604349613 0.079964339733 0.000000000000 -vt 0.532588779926 0.075347989798 0.000000000000 -vt 0.535456359386 0.075775325298 0.000000000000 -vt 0.531062185764 0.084430292249 0.000000000000 -vt 0.534919083118 0.084616497159 0.000000000000 -vt 0.690639078617 0.410164058208 0.000000000000 -vt 0.686743676662 0.408009111881 0.000000000000 -vt 0.700886189938 0.422482520342 0.000000000000 -vt 0.697773873806 0.417764842510 0.000000000000 -vt 0.694584786892 0.413028031588 0.000000000000 -vt 0.543268382549 0.081021666527 0.000000000000 -vt 0.542410075665 0.076548516750 0.000000000000 -vt 0.545253694057 0.076710179448 0.000000000000 -vt 0.544744908810 0.081107899547 0.000000000000 -vt 0.545586764812 0.085359513760 0.000000000000 -vt 0.542715609074 0.085166096687 0.000000000000 -vt 0.528137505054 0.076546490192 0.000000000000 -vt 0.526995480061 0.079263880849 0.000000000000 -vt 0.524926722050 0.078719690442 0.000000000000 -vt 0.526245653629 0.076403737068 0.000000000000 -vt 0.526619493961 0.081934899092 0.000000000000 -vt 0.524678170681 0.081073686481 0.000000000000 -vt 0.529789626598 0.077268108726 0.000000000000 -vt 0.529239356518 0.079652726650 0.000000000000 -vt 0.528736531734 0.081992313266 0.000000000000 -vt 0.539014041424 0.077833026648 0.000000000000 -vt 0.539221823215 0.080529257655 0.000000000000 -vt 0.536268293858 0.080332249403 0.000000000000 -vt 0.536676228046 0.078035444021 0.000000000000 -vt 0.539300858974 0.083174824715 0.000000000000 -vt 0.536652386189 0.082537859678 0.000000000000 -vt 0.541114032269 0.078451976180 0.000000000000 -vt 0.541567981243 0.080870822072 0.000000000000 -vt 0.541349947453 0.083064511418 0.000000000000 -vt 0.525810420513 0.073440477252 0.000000000000 -vt 0.522990167141 0.078078895807 0.000000000000 -vt 0.522753298283 0.083092421293 0.000000000000 -vt 0.744985520840 0.358051896095 0.000000000000 -vt 0.740702569485 0.361511409283 0.000000000000 -vt 0.737015068531 0.377986699343 0.000000000000 -vt 0.527110517025 0.085661664605 0.000000000000 -vt 0.529920637608 0.072953239083 0.000000000000 -vt 0.539422690868 0.086372941732 0.000000000000 -vt 0.720288455486 0.404917716980 0.000000000000 -vt 0.725336492062 0.406646698713 0.000000000000 -vt 0.719956338406 0.413258612156 0.000000000000 -vt 0.717335283756 0.410958647728 0.000000000000 -vt 0.723915517330 0.398037433624 0.000000000000 -vt 0.731581389904 0.399601578712 0.000000000000 -vt 0.741063773632 0.398945480585 0.000000000000 -vt 0.741147696972 0.402583092451 0.000000000000 -vt 0.735348403454 0.405078500509 0.000000000000 -vt 0.724570930004 0.415234774351 0.000000000000 -vt 0.730074822903 0.409371733665 0.000000000000 -vt 0.755069792271 0.423953682184 0.000000000000 -vt 0.751188337803 0.423076480627 0.000000000000 -vt 0.732347548008 0.419561594725 0.000000000000 -vt 0.728611052036 0.417487025261 0.000000000000 -vt 0.734247624874 0.412292242050 0.000000000000 -vt 0.737663686275 0.415086418390 0.000000000000 -vt 0.739005625248 0.408245295286 0.000000000000 -vt 0.742154181004 0.411730021238 0.000000000000 -vt 0.728346526623 0.424829334021 0.000000000000 -vt 0.724365770817 0.423212945461 0.000000000000 -vt 0.539046466351 0.074854224920 0.000000000000 -vt 0.547604382038 0.081218689680 0.000000000000 -vt 0.744521200657 0.403573781252 0.000000000000 -vt 0.746637046337 0.406587243080 0.000000000000 -vt 0.546402513981 0.081313252449 0.000000000000 -vt 0.546436250210 0.079620987177 0.000000000000 -vt 0.547303736210 0.079606115818 0.000000000000 -vt 0.547511637211 0.082779005170 0.000000000000 -vt 0.546545684338 0.082813456655 0.000000000000 -vt 0.551446378231 0.080884099007 0.000000000000 -vt 0.719365775585 0.420285463333 0.000000000000 -vt 0.548926889896 0.081119611859 0.000000000000 -vt 0.547964394093 0.078651010990 0.000000000000 -vt 0.549326121807 0.076903134584 0.000000000000 -vt 0.546006023884 0.078606888652 0.000000000000 -vt 0.545527517796 0.081211924553 0.000000000000 -vt 0.740861833096 0.424791932106 0.000000000000 -vt 0.744636476040 0.421375900507 0.000000000000 -vt 0.748865187168 0.419236689806 0.000000000000 -vt 0.738058149815 0.430005639791 0.000000000000 -vt 0.546189963818 0.083545655012 0.000000000000 -vt 0.548156440258 0.083578765392 0.000000000000 -vt 0.549798786640 0.085083246231 0.000000000000 -vt 0.493128985167 0.107532128692 0.000000000000 -vt 0.487130194902 0.108177408576 0.000000000000 -vt 0.484787672758 0.104095578194 0.000000000000 -vt 0.754294574261 0.415865898132 0.000000000000 -vt 0.741011559963 0.418052166700 0.000000000000 -vt 0.736329138279 0.422021627426 0.000000000000 -vt 0.745218575001 0.415226459503 0.000000000000 -vt 0.732700407505 0.426749676466 0.000000000000 -vt 0.477795451880 0.104249805212 0.000000000000 -vt 0.480690747499 0.109506055713 0.000000000000 -vt 0.493065744638 0.123880639672 0.000000000000 -vt 0.492350906134 0.121099308133 0.000000000000 -vt 0.498245447874 0.118749126792 0.000000000000 -vt 0.499274820089 0.122994199395 0.000000000000 -vt 0.749212324619 0.411244809628 0.000000000000 -vt 0.486499279737 0.122255474329 0.000000000000 -vt 0.487754553556 0.125899389386 0.000000000000 -vt 0.495414823294 0.131725952029 0.000000000000 -vt 0.501138865948 0.129815727472 0.000000000000 -vt 0.501795589924 0.132985696197 0.000000000000 -vt 0.496015042067 0.133395478129 0.000000000000 -vt 0.491779893637 0.137110754848 0.000000000000 -vt 0.490246385336 0.133341893554 0.000000000000 -vt 0.493753403425 0.114416465163 0.000000000000 -vt 0.490512460470 0.116016864777 0.000000000000 -vt 0.716776549816 0.397952318192 0.000000000000 -vt 0.722395479679 0.390428304672 0.000000000000 -vt 0.748906552792 0.386245161295 0.000000000000 -vt 0.748211801052 0.394017070532 0.000000000000 -vt 0.743617475033 0.387832283974 0.000000000000 -vt 0.743471086025 0.384143799543 0.000000000000 -vt 0.735934555531 0.381866127253 0.000000000000 -vt 0.489763349295 0.113667383790 0.000000000000 -vt 0.714425027370 0.404076099396 0.000000000000 -vt 0.492669016123 0.112787023187 0.000000000000 -vt 0.487121194601 0.117388963699 0.000000000000 -vt 0.486971467733 0.115077972412 0.000000000000 -vt 0.494484215975 0.116980090737 0.000000000000 -vt 0.491517156363 0.118607267737 0.000000000000 -vt 0.488306194544 0.119425490499 0.000000000000 -vt 0.498060315847 0.127201452851 0.000000000000 -vt 0.713693201542 0.410189747810 0.000000000000 -vt 0.735486447811 0.385052949190 0.000000000000 -vt 0.746610701084 0.396617144346 0.000000000000 -vt 0.494058936834 0.127958431840 0.000000000000 -vt 0.493515819311 0.126024797559 0.000000000000 -vt 0.496876925230 0.125608488917 0.000000000000 -vt 0.490766674280 0.128856346011 0.000000000000 -vt 0.743014752865 0.389892905951 0.000000000000 -vt 0.735056340694 0.387602627277 0.000000000000 -vt 0.727178633213 0.392949610949 0.000000000000 -vt 0.733748018742 0.392339646816 0.000000000000 -vt 0.739848792553 0.392785251141 0.000000000000 -vt 0.747750461102 0.374964654446 0.000000000000 -vt 0.490720719099 0.127026960254 0.000000000000 -vt 0.750498473644 0.379568845034 0.000000000000 -vt 0.752317011356 0.363459676504 0.000000000000 -vt 0.747864067554 0.366984248161 0.000000000000 -vt 0.743768513203 0.380047321320 0.000000000000 -vt 0.743770778179 0.376911133528 0.000000000000 -vt 0.716933429241 0.416927278042 0.000000000000 -vt 0.497924119234 0.128914669156 0.000000000000 -vt 0.494692295790 0.129884406924 0.000000000000 -vt 0.491763919592 0.130519121885 0.000000000000 -vt 0.495831340551 0.110157430172 0.000000000000 -vt 0.489241451025 0.111455008388 0.000000000000 -vt 0.483312696218 0.114056900144 0.000000000000 -vt 0.482924073935 0.118979677558 0.000000000000 -vt 0.499466627836 0.113667383790 0.000000000000 -vt 0.487026840448 0.130218312144 0.000000000000 -vt 0.502736389637 0.126097753644 0.000000000000 -vt 0.497383981943 0.137650460005 0.000000000000 -vt 0.496828526258 0.135942205787 0.000000000000 -vt 0.498790949583 0.135475009680 0.000000000000 -vt 0.489594787359 0.354463160038 0.000000000000 -vt 0.493529766798 0.348664730787 0.000000000000 -vt 0.466066062450 0.416784971952 0.000000000000 -vt 0.492370694876 0.361383527517 0.000000000000 -vt 0.500243246555 0.364317297935 0.000000000000 -vt 0.494832962751 0.368273258209 0.000000000000 -vt 0.503132641315 0.370268374681 0.000000000000 -vt 0.497408539057 0.374473363161 0.000000000000 -vt 0.505711734295 0.374342322350 0.000000000000 -vt 0.501966536045 0.380494236946 0.000000000000 -vt 0.502037703991 0.387555330992 0.000000000000 -vt 0.500600278378 0.394303470850 0.000000000000 -vt 0.497024863958 0.400832056999 0.000000000000 -vt 0.490292042494 0.406675279140 0.000000000000 -vt 0.490373104811 0.412000209093 0.000000000000 -vt 0.478659600019 0.408653289080 0.000000000000 -vt 0.483080357313 0.413705527782 0.000000000000 -vt 0.483867734671 0.400707095861 0.000000000000 -vt 0.475096553564 0.403399050236 0.000000000000 -vt 0.490063995123 0.397259533405 0.000000000000 -vt 0.493380278349 0.393484354019 0.000000000000 -vt 0.495144337416 0.389038652182 0.000000000000 -vt 0.495407789946 0.384074211121 0.000000000000 -vt 0.493809431791 0.377649396658 0.000000000000 -vt 0.491057127714 0.371400237083 0.000000000000 -vt 0.488305300474 0.365160942078 0.000000000000 -vt 0.485417455435 0.358706206083 0.000000000000 -vt 0.499160021544 0.136612713337 0.000000000000 -vt 0.495681852102 0.138441428542 0.000000000000 -vt 0.495292752981 0.137186184525 0.000000000000 -vt 0.499904841185 0.142935067415 0.000000000000 -vt 0.512892186642 0.203441917896 0.000000000000 -vt 0.515536010265 0.210260972381 0.000000000000 -vt 0.519058048725 0.216575443745 0.000000000000 -vt 0.498339504004 0.139838293195 0.000000000000 -vt 0.500721871853 0.137117296457 0.000000000000 -vt 0.503684222698 0.138030976057 0.000000000000 -vt 0.499697417021 0.134602531791 0.000000000000 -vt 0.496406823397 0.134647563100 0.000000000000 -vt 0.494290322065 0.137108504772 0.000000000000 -vt 0.495159000158 0.139991164207 0.000000000000 -vt 0.493990033865 0.142434999347 0.000000000000 -vt 0.486728996038 0.090575456619 0.000000000000 -vt 0.478315383196 0.092991143465 0.000000000000 -vt 0.474077731371 0.098476827145 0.000000000000 -vt 0.498264402151 0.081063106656 0.000000000000 -vt 0.490895956755 0.083478346467 0.000000000000 -vt 0.501754701138 0.074368119240 0.000000000000 -vt 0.516297876835 0.064490333200 0.000000000000 -vt 0.489585071802 0.070763155818 0.000000000000 -vt 0.494673103094 0.066240236163 0.000000000000 -vt 0.470336109400 0.086715623736 0.000000000000 -vt 0.436086863279 0.092820927501 0.000000000000 -vt 0.438066899776 0.090013250709 0.000000000000 -vt 0.444520950317 0.092675030231 0.000000000000 -vt 0.441438585520 0.096161559224 0.000000000000 -vt 0.428543061018 0.092088505626 0.000000000000 -vt 0.430847972631 0.087048172951 0.000000000000 -vt 0.445708662271 0.087137565017 0.000000000000 -vt 0.440775513649 0.085114762187 0.000000000000 -vt 0.441083967686 0.081669896841 0.000000000000 -vt 0.445867836475 0.084105402231 0.000000000000 -vt 0.434993296862 0.082800179720 0.000000000000 -vt 0.435679793358 0.079566493630 0.000000000000 -vt 0.443775683641 0.089068949223 0.000000000000 -vt 0.439778298140 0.087716892362 0.000000000000 -vt 0.435482561588 0.085728764534 0.000000000000 -vt 0.449968576431 0.082234129310 0.000000000000 -vt 0.441662847996 0.076967298985 0.000000000000 -vt 0.431835711002 0.073218241334 0.000000000000 -vt 0.428974449635 0.081223636866 0.000000000000 -vt 0.450840383768 0.089633405209 0.000000000000 -vt 0.429250478745 0.110776379704 0.000000000000 -vt 0.428867727518 0.107335552573 0.000000000000 -vt 0.431848555803 0.108271300793 0.000000000000 -vt 0.431623846292 0.110644668341 0.000000000000 -vt 0.427443832159 0.110487952828 0.000000000000 -vt 0.426816552877 0.108107388020 0.000000000000 -vt 0.437157928944 0.099945515394 0.000000000000 -vt 0.433482289314 0.098722696304 0.000000000000 -vt 0.434810459614 0.095693901181 0.000000000000 -vt 0.437838792801 0.097269997001 0.000000000000 -vt 0.429327040911 0.097964599729 0.000000000000 -vt 0.431027412415 0.095057398081 0.000000000000 -vt 0.435632973909 0.102705463767 0.000000000000 -vt 0.431967437267 0.102064222097 0.000000000000 -vt 0.428185939789 0.101327285171 0.000000000000 -vt 0.424739956856 0.097438409925 0.000000000000 -vt 0.424326807261 0.104374542832 0.000000000000 -vt 0.430121839046 0.103951931000 0.000000000000 -vt 0.436985909939 0.106490775943 0.000000000000 -vt 0.440761536360 0.101641386747 0.000000000000 -vt 0.429635047913 0.115833595395 0.000000000000 -vt 0.429685264826 0.112943276763 0.000000000000 -vt 0.432830691338 0.111719325185 0.000000000000 -vt 0.435101598501 0.113605901599 0.000000000000 -vt 0.434298694134 0.107984006405 0.000000000000 -vt 0.429523140192 0.105171591043 0.000000000000 -vt 0.425729721785 0.106971934438 0.000000000000 -vt 0.426668196917 0.111298739910 0.000000000000 -vt 0.424650788307 0.112406730652 0.000000000000 -vt 0.509388387203 0.055841218680 0.000000000000 -vt 0.498403996229 0.043372806162 0.000000000000 -vt 0.502433478832 0.048159595579 0.000000000000 -vt 0.497449725866 0.051044743508 0.000000000000 -vt 0.492421835661 0.043788667768 0.000000000000 -vt 0.463615030050 0.077348947525 0.000000000000 -vt 0.455456525087 0.070783421397 0.000000000000 -vt 0.464122295380 0.066180795431 0.000000000000 -vt 0.462868630886 0.093436956406 0.000000000000 -vt 0.458721280098 0.092571005225 0.000000000000 -vt 0.459522604942 0.087591469288 0.000000000000 -vt 0.462670952082 0.086979731917 0.000000000000 -vt 0.471514105797 0.060662243515 0.000000000000 -vt 0.482812136412 0.062291014940 0.000000000000 -vt 0.467946112156 0.095136195421 0.000000000000 -vt 0.458524495363 0.080985873938 0.000000000000 -vt 0.452050387859 0.076159223914 0.000000000000 -vt 0.443986207247 0.071658372879 0.000000000000 -vt 0.445354491472 0.066013723612 0.000000000000 -vt 0.436717092991 0.065082713962 0.000000000000 -vt 0.437832713127 0.058958042413 0.000000000000 -vt 0.456312119961 0.084696203470 0.000000000000 -vt 0.455533295870 0.088533744216 0.000000000000 -vt 0.442759126425 0.026406910270 0.000000000000 -vt 0.439107567072 0.033566392958 0.000000000000 -vt 0.433614879847 0.033746067435 0.000000000000 -vt 0.436550229788 0.040571421385 0.000000000000 -vt 0.431009620428 0.041979093105 0.000000000000 -vt 0.436738461256 0.048520524055 0.000000000000 -vt 0.433239340782 0.050523724407 0.000000000000 -vt 0.439432889223 0.056393977255 0.000000000000 -vt 0.444673389196 0.062197577208 0.000000000000 -vt 0.452080547810 0.064230725169 0.000000000000 -vt 0.459633141756 0.061068650335 0.000000000000 -vt 0.466834276915 0.054884534329 0.000000000000 -vt 0.476173490286 0.048398043960 0.000000000000 -vt 0.478311985731 0.055618535727 0.000000000000 -vt 0.487611383200 0.048637155443 0.000000000000 -vt 0.492559403181 0.054551754147 0.000000000000 -vt 0.450314640999 0.028678275645 0.000000000000 -vt 0.445344805717 0.034261446446 0.000000000000 -vt 0.441385686398 0.039831560105 0.000000000000 -vt 0.440092831850 0.046508762985 0.000000000000 -vt 0.441298097372 0.053300123662 0.000000000000 -vt 0.444251447916 0.058152657002 0.000000000000 -vt 0.449525713921 0.059440102428 0.000000000000 -vt 0.455304324627 0.055676858872 0.000000000000 -vt 0.461506903172 0.049404706806 0.000000000000 -vt 0.469306051731 0.042024347931 0.000000000000 -vt 0.487811952829 0.058225836605 0.000000000000 -vt 0.483524292707 0.052073474973 0.000000000000 -vt 0.484311491251 0.046199399978 0.000000000000 -vt 0.481747001410 0.048475492746 0.000000000000 -vt 0.380680233240 0.065514564514 0.000000000000 -vt 0.376588284969 0.059708710760 0.000000000000 -vt 0.380253583193 0.059918548912 0.000000000000 -vt 0.384085476398 0.069081693888 0.000000000000 -vt 0.495234221220 0.099533021450 0.000000000000 -vt 0.383714437485 0.065352901816 0.000000000000 -vt 0.383114397526 0.061096791178 0.000000000000 -vt 0.374451309443 0.073164209723 0.000000000000 -vt 0.372015357018 0.063677519560 0.000000000000 -vt 0.374059766531 0.053939338773 0.000000000000 -vt 0.381692320108 0.054332684726 0.000000000000 -vt 0.383103370667 0.075196906924 0.000000000000 -vt 0.405146718025 0.062567278743 0.000000000000 -vt 0.405029207468 0.064906865358 0.000000000000 -vt 0.403085887432 0.065327689052 0.000000000000 -vt 0.402291089296 0.062788158655 0.000000000000 -vt 0.404567837715 0.060321133584 0.000000000000 -vt 0.402513980865 0.060236703604 0.000000000000 -vt 0.396065324545 0.068468824029 0.000000000000 -vt 0.393785178661 0.067805290222 0.000000000000 -vt 0.392409473658 0.063877239823 0.000000000000 -vt 0.394892245531 0.063695982099 0.000000000000 -vt 0.392374575138 0.059808004647 0.000000000000 -vt 0.394494861364 0.058848392218 0.000000000000 -vt 0.398127049208 0.067958623171 0.000000000000 -vt 0.397333174944 0.063290476799 0.000000000000 -vt 0.396797299385 0.058876764029 0.000000000000 -vt 0.394452542067 0.054397072643 0.000000000000 -vt 0.399751543999 0.055975642055 0.000000000000 -vt 0.399062365294 0.062898263335 0.000000000000 -vt 0.401548743248 0.070496574044 0.000000000000 -vt 0.397002875805 0.072747439146 0.000000000000 -vt 0.410708278418 0.061957109720 0.000000000000 -vt 0.408443450928 0.068036526442 0.000000000000 -vt 0.406104087830 0.065834060311 0.000000000000 -vt 0.407416969538 0.062223013490 0.000000000000 -vt 0.402603596449 0.067001029849 0.000000000000 -vt 0.400384694338 0.062776446342 0.000000000000 -vt 0.401618093252 0.058767784387 0.000000000000 -vt 0.407653838396 0.056897196919 0.000000000000 -vt 0.405660539865 0.059153925627 0.000000000000 -vt 0.342144489288 0.129252389073 0.000000000000 -vt 0.330034285784 0.118232384324 0.000000000000 -vt 0.331073820591 0.111910715699 0.000000000000 -vt 0.337948709726 0.117126211524 0.000000000000 -vt 0.334675848484 0.122342392802 0.000000000000 -vt 0.364498108625 0.084034025669 0.000000000000 -vt 0.353841513395 0.081475362182 0.000000000000 -vt 0.359023243189 0.072227567434 0.000000000000 -vt 0.383939355612 0.087411120534 0.000000000000 -vt 0.376194030046 0.086917132139 0.000000000000 -vt 0.378380954266 0.083674445748 0.000000000000 -vt 0.385140568018 0.082588523626 0.000000000000 -vt 0.348989427090 0.090118840337 0.000000000000 -vt 0.349848628044 0.102441802621 0.000000000000 -vt 0.384516656399 0.092244535685 0.000000000000 -vt 0.368901699781 0.080153703690 0.000000000000 -vt 0.366300255060 0.072573855519 0.000000000000 -vt 0.362025469542 0.061230536550 0.000000000000 -vt 0.366504251957 0.062840163708 0.000000000000 -vt 0.364860385656 0.049893748015 0.000000000000 -vt 0.368391275406 0.052941676229 0.000000000000 -vt 0.375058352947 0.079524159431 0.000000000000 -vt 0.381066381931 0.079621434212 0.000000000000 -vt 0.369406282902 0.023787003011 0.000000000000 -vt 0.363827377558 0.021882418543 0.000000000000 -vt 0.362167745829 0.013727746904 0.000000000000 -vt 0.369875043631 0.032330740243 0.000000000000 -vt 0.363867014647 0.030249182135 0.000000000000 -vt 0.367265045643 0.040660582483 0.000000000000 -vt 0.362684249878 0.039418853819 0.000000000000 -vt 0.360803991556 0.049217607826 0.000000000000 -vt 0.358212471008 0.058879461139 0.000000000000 -vt 0.354023665190 0.067041784525 0.000000000000 -vt 0.349367916584 0.074845895171 0.000000000000 -vt 0.344372838736 0.084569439292 0.000000000000 -vt 0.343579858541 0.097275629640 0.000000000000 -vt 0.337548166513 0.094781354070 0.000000000000 -vt 0.336168199778 0.107096001506 0.000000000000 -vt 0.341732889414 0.112160399556 0.000000000000 -vt 0.358703076839 0.019574124366 0.000000000000 -vt 0.356585264206 0.011583819985 0.000000000000 -vt 0.359179943800 0.028422724456 0.000000000000 -vt 0.358128011227 0.037861227989 0.000000000000 -vt 0.355775833130 0.047059264034 0.000000000000 -vt 0.352667778730 0.055755432695 0.000000000000 -vt 0.348802536726 0.062798514962 0.000000000000 -vt 0.344516932964 0.069515347481 0.000000000000 -vt 0.339693903923 0.078744009137 0.000000000000 -vt 0.334405004978 0.088547706604 0.000000000000 -vt 0.351488649845 0.008813511580 0.000000000000 -vt 0.353146910667 0.017157759517 0.000000000000 -vt 0.344804912806 0.016256015748 0.000000000000 -vt 0.343273401260 0.007860429585 0.000000000000 -vt 0.353605329990 0.026377867907 0.000000000000 -vt 0.345076918602 0.024861443788 0.000000000000 -vt 0.351858347654 0.035421445966 0.000000000000 -vt 0.343469291925 0.032606557012 0.000000000000 -vt 0.329398661852 0.083495229483 0.000000000000 -vt 0.321584880352 0.080222144723 0.000000000000 -vt 0.345637321472 0.107405588031 0.000000000000 -vt 0.339709669352 0.102807238698 0.000000000000 -vt 0.334294229746 0.103572994471 0.000000000000 -vt 0.336519658566 0.100833073258 0.000000000000 -vt 0.331020236015 0.072261109948 0.000000000000 -vt 0.336660385132 0.064951002598 0.000000000000 -vt 0.434932053089 0.026294331998 0.000000000000 -vt 0.340934514999 0.059087056667 0.000000000000 -vt 0.343839913607 0.051737319678 0.000000000000 -vt 0.346170932055 0.042951311916 0.000000000000 -vt 0.340638875961 0.037561997771 0.000000000000 -vt 0.323255330324 0.073237612844 0.000000000000 -vt 0.695959985256 0.741854548454 0.000000000000 -vt 0.714866340160 0.723106801510 0.000000000000 -vt 0.697431623936 0.719995796680 0.000000000000 -vt 0.483988851309 0.041881825775 0.000000000000 -vt 0.839606106281 0.716192245483 0.000000000000 -vt 0.824899375439 0.704895555973 0.000000000000 -vt 0.836511552334 0.689590156078 0.000000000000 -vt 0.848930418491 0.699052095413 0.000000000000 -vt 0.814055740833 0.694797575474 0.000000000000 -vt 0.477539271116 0.036895312369 0.000000000000 -vt 0.826638519764 0.681990265846 0.000000000000 -vt 0.829895794392 0.731659770012 0.000000000000 -vt 0.813143789768 0.716623902321 0.000000000000 -vt 0.801700055599 0.705101132393 0.000000000000 -vt 0.817305624485 0.743863582611 0.000000000000 -vt 0.801387965679 0.725039482117 0.000000000000 -vt 0.789851725101 0.712394773960 0.000000000000 -vt 0.788582026958 0.734670758247 0.000000000000 -vt 0.777517497540 0.721166849136 0.000000000000 -vt 0.803215801716 0.752814412117 0.000000000000 -vt 0.786242902279 0.759428799152 0.000000000000 -vt 0.773034870625 0.741466820240 0.000000000000 -vt 0.763387620449 0.729409098625 0.000000000000 -vt 0.819508969784 0.771108031273 0.000000000000 -vt 0.801594197750 0.778130888939 0.000000000000 -vt 0.780358016491 0.784393787384 0.000000000000 -vt 0.813161194324 0.798096477985 0.000000000000 -vt 0.791216671467 0.802965700626 0.000000000000 -vt 0.768060982227 0.806276857853 0.000000000000 -vt 0.758998692036 0.789613127708 0.000000000000 -vt 0.745742022991 0.808515787125 0.000000000000 -vt 0.739104449749 0.793780505657 0.000000000000 -vt 0.796912372112 0.821695029736 0.000000000000 -vt 0.772977530956 0.822699189186 0.000000000000 -vt 0.749330580235 0.823236882687 0.000000000000 -vt 0.818778097630 0.819741129875 0.000000000000 -vt 0.864375889301 0.710809707642 0.000000000000 -vt 0.880953133106 0.724374651909 0.000000000000 -vt 0.915635168552 0.748171925545 0.000000000000 -vt 0.908841907978 0.766230940819 0.000000000000 -vt 0.905186593533 0.787342846394 0.000000000000 -vt 0.887137472630 0.812209010124 0.000000000000 -vt 0.901950418949 0.812799155712 0.000000000000 -vt 0.716777384281 0.755539953709 0.000000000000 -vt 0.709918677807 0.762999296188 0.000000000000 -vt 0.751775801182 0.171791642904 0.000000000000 -vt 0.779532253742 0.179935947061 0.000000000000 -vt 0.757754266262 0.191265076399 0.000000000000 -vt 0.738353550434 0.202746644616 0.000000000000 -vt 0.733651459217 0.186159908772 0.000000000000 -vt 0.720768034458 0.212536171079 0.000000000000 -vt 0.718448698521 0.197526648641 0.000000000000 -vt 0.715862095356 0.185371875763 0.000000000000 -vt 0.749988734722 0.241413876414 0.000000000000 -vt 0.731017768383 0.248716101050 0.000000000000 -vt 0.725487768650 0.230310603976 0.000000000000 -vt 0.743789970875 0.221092060208 0.000000000000 -vt 0.774173557758 0.257214367390 0.000000000000 -vt 0.754297435284 0.261839717627 0.000000000000 -vt 0.769551694393 0.234550252557 0.000000000000 -vt 0.731539070606 0.269993722439 0.000000000000 -vt 0.763681709766 0.212278813124 0.000000000000 -vt 0.789024770260 0.228903159499 0.000000000000 -vt 0.784669578075 0.203588500619 0.000000000000 -vt 0.812417447567 0.255994260311 0.000000000000 -vt 0.793350636959 0.255872875452 0.000000000000 -vt 0.808808386326 0.224819734693 0.000000000000 -vt 0.805518686771 0.196942374110 0.000000000000 -vt 0.801068723202 0.171566486359 0.000000000000 -vt 0.816036999226 0.293190568686 0.000000000000 -vt 0.796044886112 0.283715814352 0.000000000000 -vt 0.777438461781 0.280535697937 0.000000000000 -vt 0.757886707783 0.282600164413 0.000000000000 -vt 0.739174664021 0.287719726563 0.000000000000 -vt 0.785341441631 0.033302962780 0.000000000000 -vt 0.582609474659 0.124908477068 0.000000000000 -vt 0.581306993961 0.142187565565 0.000000000000 -vt 0.545368969440 0.011624570936 0.000000000000 -vt 0.646641552448 0.018267553300 0.000000000000 -vt 0.606483757496 0.106701299548 0.000000000000 -vt 0.612616598606 0.108521446586 0.000000000000 -vt 0.618627488613 0.111129656434 0.000000000000 -vt 0.665071904659 0.014743648469 0.000000000000 -vt 0.370113700628 0.016160547733 0.000000000000 -vt 0.331191360950 0.103096559644 0.000000000000 -vt 0.330383718014 0.097089871764 0.000000000000 -vt 0.327046245337 0.092111021280 0.000000000000 -vt 0.319549947977 0.088000133634 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.696907937527 0.156802833080 0.000000000000 -vt 0.707364618778 0.164915174246 0.000000000000 -vt 0.711468279362 0.167301818728 0.000000000000 -vt 0.672648847103 0.136169388890 0.000000000000 -vt 0.654392778873 0.123681157827 0.000000000000 -vt 0.546281397343 0.277987629175 0.000000000000 -vt 0.555889427662 0.542913317680 0.000000000000 -vt 0.598048627377 0.315594613552 0.000000000000 -vt 0.474871605635 0.487518340349 0.000000000000 -vt 0.493717104197 0.499704867601 0.000000000000 -vt 0.510663211346 0.513657331467 0.000000000000 -vt 0.529695570469 0.328777670860 0.000000000000 -vt 0.478573888540 0.439885228872 0.000000000000 -vt 0.489638179541 0.458603054285 0.000000000000 -vt 0.472153753042 0.424974769354 0.000000000000 -vt 0.581608593464 0.316328614950 0.000000000000 -vt 0.469933092594 0.410422533751 0.000000000000 -vt 0.474573940039 0.415574103594 0.000000000000 -vt 0.496727436781 0.356613397598 0.000000000000 -vt 0.467020928860 0.405297100544 0.000000000000 -vt 0.680720627308 0.091846004128 0.000000000000 -vt 0.694580972195 0.090741172433 0.000000000000 -vt 0.547491371632 0.071579337120 0.000000000000 -vt 0.553497970104 0.078128427267 0.000000000000 -vt 0.645280063152 0.102942556143 0.000000000000 -vt 0.557917654514 0.084493562579 0.000000000000 -vt 0.562383949757 0.098196953535 0.000000000000 -vt 0.633653700352 0.118626862764 0.000000000000 -vt 0.562888324261 0.114720419049 0.000000000000 -vt 0.563672840595 0.128326103091 0.000000000000 -vt 0.567211091518 0.144699171185 0.000000000000 -vt 0.500136196613 0.268927842379 0.000000000000 -vt 0.502436935902 0.280043512583 0.000000000000 -vt 0.482790559530 0.140759631991 0.000000000000 -vt 0.485283464193 0.145932793617 0.000000000000 -vt 0.511669576168 0.244729980826 0.000000000000 -vt 0.489596575499 0.150636732578 0.000000000000 -vt 0.503686726093 0.155002936721 0.000000000000 -vt 0.528804123402 0.231279209256 0.000000000000 -vt 0.521844804287 0.155472621322 0.000000000000 -vt 0.536552846432 0.156950756907 0.000000000000 -vt 0.553597509861 0.159783437848 0.000000000000 -vt 0.307654768229 0.609554529190 0.000000000000 -vt 0.290467321873 0.613707244396 0.000000000000 -vt 0.204575508833 0.719810605049 0.000000000000 -vt 0.210707157850 0.703682720661 0.000000000000 -vt 0.284538298845 0.585472345352 0.000000000000 -vt 0.223060980439 0.709351420403 0.000000000000 -vt 0.213785484433 0.729282855988 0.000000000000 -vt 0.294191390276 0.583933651447 0.000000000000 -vt 0.193332836032 0.738901257515 0.000000000000 -vt 0.188829287887 0.728674709797 0.000000000000 -vt 0.197825804353 0.749223530293 0.000000000000 -vt 0.225497603416 0.740132212639 0.000000000000 -vt 0.172644689679 0.756999909878 0.000000000000 -vt 0.173354595900 0.748063921928 0.000000000000 -vt 0.153877779841 0.774228334427 0.000000000000 -vt 0.153797164559 0.760271430016 0.000000000000 -vt 0.173445329070 0.773155450821 0.000000000000 -vt 0.149432986975 0.820051431656 0.000000000000 -vt 0.173765048385 0.821435034275 0.000000000000 -vt 0.175114631653 0.829998791218 0.000000000000 -vt 0.154235765338 0.830059587955 0.000000000000 -vt 0.154094830155 0.792689681053 0.000000000000 -vt 0.177844420075 0.795601427555 0.000000000000 -vt 0.212241590023 0.836606919765 0.000000000000 -vt 0.307616710663 0.586260378361 0.000000000000 -vt 0.319666564465 0.604332268238 0.000000000000 -vt 0.206351310015 0.841337859631 0.000000000000 -vt 0.357945650816 0.653928995132 0.000000000000 -vt 0.205141782761 0.802912175655 0.000000000000 -vt 0.181257992983 0.838490307331 0.000000000000 -vt 0.150479733944 0.836383342743 0.000000000000 -vt 0.202541679144 0.774786055088 0.000000000000 -vt 0.230581372976 0.776787877083 0.000000000000 -vt 0.232835412025 0.808410942554 0.000000000000 -vt 0.153742238879 0.753254890442 0.000000000000 -vt 0.354879945517 0.670894861221 0.000000000000 -vt 0.156122118235 0.742229044437 0.000000000000 -vt 0.325383484364 0.664160490036 0.000000000000 -vt 0.172345682979 0.736270546913 0.000000000000 -vt 0.329998701811 0.649386703968 0.000000000000 -vt 0.344495564699 0.695504546165 0.000000000000 -vt 0.319999575615 0.685368955135 0.000000000000 -vt 0.340014070272 0.705360293388 0.000000000000 -vt 0.316662311554 0.697957396507 0.000000000000 -vt 0.335703253746 0.712217569351 0.000000000000 -vt 0.314472913742 0.703338801861 0.000000000000 -vt 0.298693358898 0.660711348057 0.000000000000 -vt 0.305291980505 0.643745899200 0.000000000000 -vt 0.335656195879 0.638233840466 0.000000000000 -vt 0.170275822282 0.731788814068 0.000000000000 -vt 0.154652982950 0.738835036755 0.000000000000 -vt 0.186667352915 0.724648237228 0.000000000000 -vt 0.232443422079 0.711409807205 0.000000000000 -vt 0.252836883068 0.745151817799 0.000000000000 -vt 0.251037418842 0.715631723404 0.000000000000 -vt 0.257062584162 0.778479039669 0.000000000000 -vt 0.286519646645 0.808762609959 0.000000000000 -vt 0.259915977716 0.810499906540 0.000000000000 -vt 0.282630771399 0.777449607849 0.000000000000 -vt 0.312265455723 0.804308831692 0.000000000000 -vt 0.315088212490 0.835467398167 0.000000000000 -vt 0.288638800383 0.843417167664 0.000000000000 -vt 0.337379038334 0.797992110252 0.000000000000 -vt 0.342023313046 0.826052308083 0.000000000000 -vt 0.314613372087 0.842931270599 0.000000000000 -vt 0.360430896282 0.641259968281 0.000000000000 -vt 0.314939886332 0.630025804043 0.000000000000 -vt 0.289557874203 0.850114881992 0.000000000000 -vt 0.294469684362 0.682716429234 0.000000000000 -vt 0.273877441883 0.659004628658 0.000000000000 -vt 0.280411213636 0.635718882084 0.000000000000 -vt 0.270008593798 0.684478938580 0.000000000000 -vt 0.359717398882 0.625162005424 0.000000000000 -vt 0.343318879604 0.624738991261 0.000000000000 -vt 0.344458639622 0.621523499489 0.000000000000 -vt 0.360369205475 0.621685206890 0.000000000000 -vt 0.360682636499 0.635098338127 0.000000000000 -vt 0.339501827955 0.634016931057 0.000000000000 -vt 0.340652346611 0.835465610027 0.000000000000 -vt 0.309305101633 0.776968240738 0.000000000000 -vt 0.334473401308 0.773887217045 0.000000000000 -vt 0.363107293844 0.791482627392 0.000000000000 -vt 0.368501096964 0.820234537125 0.000000000000 -vt 0.358934253454 0.769033312798 0.000000000000 -vt 0.275969982147 0.743224263191 0.000000000000 -vt 0.305437386036 0.756031274796 0.000000000000 -vt 0.260169744492 0.846379280090 0.000000000000 -vt 0.235436409712 0.844436645508 0.000000000000 -vt 0.262015789747 0.854236066341 0.000000000000 -vt 0.234238356352 0.851540505886 0.000000000000 -vt 0.263981163502 0.715166091919 0.000000000000 -vt 0.267965942621 0.713351130486 0.000000000000 -vt 0.281729459763 0.734891474247 0.000000000000 -vt 0.288172066212 0.722100436687 0.000000000000 -vt 0.277648299932 0.707795619965 0.000000000000 -vt 0.291222691536 0.716961920261 0.000000000000 -vt 0.308623343706 0.723172843456 0.000000000000 -vt 0.307381391525 0.728834807873 0.000000000000 -vt 0.281491696835 0.703531861305 0.000000000000 -vt 0.305040448904 0.743083953857 0.000000000000 -vt 0.201677769423 0.717027664185 0.000000000000 -vt 0.205799683928 0.700485944748 0.000000000000 -vt 0.367262303829 0.829703629017 0.000000000000 -vt 0.341758757830 0.839105904102 0.000000000000 -vt 0.368334710598 0.833229362965 0.000000000000 -vt 0.316586196423 0.847852051258 0.000000000000 -vt 0.290764272213 0.854788422585 0.000000000000 -vt 0.327047795057 0.738471865654 0.000000000000 -vt 0.326124876738 0.730000674725 0.000000000000 -vt 0.330911010504 0.754280507565 0.000000000000 -vt 0.355491876602 0.749867677689 0.000000000000 -vt 0.351486146450 0.739300012589 0.000000000000 -vt 0.326873511076 0.724973142147 0.000000000000 -vt 0.344539195299 0.722123146057 0.000000000000 -vt 0.344190418720 0.726383745670 0.000000000000 -vt 0.261989206076 0.857144653797 0.000000000000 -vt 0.233581811190 0.854094266891 0.000000000000 -vt 0.204417899251 0.849156141281 0.000000000000 -vt 0.326887309551 0.621081113815 0.000000000000 -vt 0.252677500248 0.583962917328 0.000000000000 -vt 0.265231251717 0.586087048054 0.000000000000 -vt 0.256276845932 0.613264143467 0.000000000000 -vt 0.236884176731 0.612185239792 0.000000000000 -vt 0.225397676229 0.592031359673 0.000000000000 -vt 0.240359246731 0.578182041645 0.000000000000 -vt 0.249482765794 0.581659138203 0.000000000000 -vt 0.230406701565 0.604802131653 0.000000000000 -vt 0.221547290683 0.586520910263 0.000000000000 -vt 0.237664133310 0.573132932186 0.000000000000 -vt 0.211196690798 0.601164758205 0.000000000000 -vt 0.209809958935 0.594907939434 0.000000000000 -vt 0.213919267058 0.613228797913 0.000000000000 -vt 0.215259835124 0.621791481972 0.000000000000 -vt 0.233155399561 0.635776519775 0.000000000000 -vt 0.212040349841 0.638687551022 0.000000000000 -vt 0.329966962337 0.616993844509 0.000000000000 -vt 0.252798855305 0.635614156723 0.000000000000 -vt 0.333201110363 0.612495720387 0.000000000000 -vt 0.324382007122 0.598686695099 0.000000000000 -vt 0.311093568802 0.581733644009 0.000000000000 -vt 0.250871539116 0.659518659115 0.000000000000 -vt 0.246007040143 0.695468783379 0.000000000000 -vt 0.267591327429 0.695985734463 0.000000000000 -vt 0.229620695114 0.658928096294 0.000000000000 -vt 0.224895358086 0.685685992241 0.000000000000 -vt 0.202963665128 0.683032333851 0.000000000000 -vt 0.206480368972 0.658463180065 0.000000000000 -vt 0.225187152624 0.694258570671 0.000000000000 -vt 0.267994135618 0.700619399548 0.000000000000 -vt 0.246059074998 0.698300302029 0.000000000000 -vt 0.202539697289 0.691807746887 0.000000000000 -vt 0.292167007923 0.695293128490 0.000000000000 -vt 0.291803628206 0.699824810028 0.000000000000 -vt 0.246173635125 0.686428308487 0.000000000000 -vt 0.225166440010 0.697112381458 0.000000000000 -vt 0.202534750104 0.694576680660 0.000000000000 -vt 0.179447337985 0.689694881439 0.000000000000 -vt 0.179994687438 0.681011319160 0.000000000000 -vt 0.156249374151 0.689290702343 0.000000000000 -vt 0.153237923980 0.680606484413 0.000000000000 -vt 0.181782424450 0.657110214233 0.000000000000 -vt 0.156527668238 0.653305292130 0.000000000000 -vt 0.186954230070 0.638771533966 0.000000000000 -vt 0.162625998259 0.633767902851 0.000000000000 -vt 0.191838979721 0.622671365738 0.000000000000 -vt 0.169981136918 0.618435740471 0.000000000000 -vt 0.179694786668 0.692102015018 0.000000000000 -vt 0.157019853592 0.692945420742 0.000000000000 -vt 0.174810484052 0.610164642334 0.000000000000 -vt 0.181283250451 0.599177777767 0.000000000000 -vt 0.196757718921 0.604870617390 0.000000000000 -vt 0.192525476217 0.616066217422 0.000000000000 -vt 0.183410972357 0.595816195011 0.000000000000 -vt 0.198278859258 0.601250529289 0.000000000000 -vt 0.244824290276 0.579442679882 0.000000000000 -vt 0.273151040077 0.710567533970 0.000000000000 -vt 0.285232663155 0.728684842587 0.000000000000 -vt 0.227200508118 0.598817527294 0.000000000000 -vt 0.212605252862 0.606770217419 0.000000000000 -vt 0.305614590645 0.736904382706 0.000000000000 -vt 0.328240215778 0.744696319103 0.000000000000 -vt 0.178053170443 0.604644119740 0.000000000000 -vt 0.348152697086 0.732621014118 0.000000000000 -vt 0.194131508470 0.610380828381 0.000000000000 -vt 0.313762992620 0.607308149338 0.000000000000 -vt 0.300771087408 0.584314823151 0.000000000000 -vt 0.216887891293 0.707050144672 0.000000000000 -vt 0.208923026919 0.724448800087 0.000000000000 -vt 0.190924808383 0.733412683010 0.000000000000 -vt 0.173134177923 0.741575896740 0.000000000000 -vt 0.154957845807 0.745678186417 0.000000000000 -vt 0.360251009464 0.628313779831 0.000000000000 -vt 0.342385172844 0.628576755524 0.000000000000 -vt 0.322390943766 0.625243067741 0.000000000000 -vt 0.255816608667 0.538961172104 0.000000000000 -vt 0.255609929562 0.531903445721 0.000000000000 -vt 0.276532471180 0.523902297020 0.000000000000 -vt 0.276766628027 0.530665338039 0.000000000000 -vt 0.258155763149 0.542869150639 0.000000000000 -vt 0.239253938198 0.549565970898 0.000000000000 -vt 0.237569808960 0.546314954758 0.000000000000 -vt 0.259632319212 0.557646989822 0.000000000000 -vt 0.278000265360 0.557606041431 0.000000000000 -vt 0.280406028032 0.561680853367 0.000000000000 -vt 0.259857028723 0.562739551067 0.000000000000 -vt 0.301217794418 0.558059513569 0.000000000000 -vt 0.301868736744 0.561496496201 0.000000000000 -vt 0.280528068542 0.552090644836 0.000000000000 -vt 0.277729153633 0.535347640514 0.000000000000 -vt 0.297178983688 0.528205513954 0.000000000000 -vt 0.301819860935 0.553178787231 0.000000000000 -vt 0.296229928732 0.518692255020 0.000000000000 -vt 0.297345817089 0.522403001785 0.000000000000 -vt 0.317796647549 0.513919591904 0.000000000000 -vt 0.319642692804 0.516018092632 0.000000000000 -vt 0.318866372108 0.522611498833 0.000000000000 -vt 0.323723644018 0.553826808929 0.000000000000 -vt 0.342375040054 0.518720626831 0.000000000000 -vt 0.345081865788 0.553842306137 0.000000000000 -vt 0.325454175472 0.558225631714 0.000000000000 -vt 0.324885904789 0.562544107437 0.000000000000 -vt 0.344201058149 0.558419764042 0.000000000000 -vt 0.346064895391 0.561874091625 0.000000000000 -vt 0.367183536291 0.508728206158 0.000000000000 -vt 0.365877866745 0.516082882881 0.000000000000 -vt 0.342823565006 0.511460900307 0.000000000000 -vt 0.365199923515 0.505763173103 0.000000000000 -vt 0.387129127979 0.502111792564 0.000000000000 -vt 0.389222174883 0.506725013256 0.000000000000 -vt 0.341677963734 0.508929491043 0.000000000000 -vt 0.382050991058 0.547588169575 0.000000000000 -vt 0.364945054054 0.550378084183 0.000000000000 -vt 0.388924062252 0.514224946499 0.000000000000 -vt 0.256348222494 0.552059113979 0.000000000000 -vt 0.239861428738 0.565382003784 0.000000000000 -vt 0.239956676960 0.562402725220 0.000000000000 -vt 0.220832422376 0.568670809269 0.000000000000 -vt 0.219239458442 0.567124247551 0.000000000000 -vt 0.203210204840 0.570883214474 0.000000000000 -vt 0.201898008585 0.568920969963 0.000000000000 -vt 0.182944670320 0.570823550224 0.000000000000 -vt 0.183698490262 0.567600429058 0.000000000000 -vt 0.203983396292 0.564405024052 0.000000000000 -vt 0.204041033983 0.557649910450 0.000000000000 -vt 0.220529600978 0.554902791977 0.000000000000 -vt 0.220537245274 0.562811851501 0.000000000000 -vt 0.183808818460 0.564445316792 0.000000000000 -vt 0.182822406292 0.557343244553 0.000000000000 -vt 0.156297102571 0.564277827740 0.000000000000 -vt 0.153392598033 0.552050530910 0.000000000000 -vt 0.137154191732 0.566353738308 0.000000000000 -vt 0.156789526343 0.566984176636 0.000000000000 -vt 0.156581923366 0.569497346878 0.000000000000 -vt 0.138306304812 0.569090723991 0.000000000000 -vt 0.154402419925 0.548665106297 0.000000000000 -vt 0.132301419973 0.547170519829 0.000000000000 -vt 0.131927892566 0.543763041496 0.000000000000 -vt 0.183378085494 0.554381549358 0.000000000000 -vt 0.155377343297 0.546469151974 0.000000000000 -vt 0.182058230042 0.549026727676 0.000000000000 -vt 0.203520476818 0.547020137310 0.000000000000 -vt 0.203194230795 0.553471744061 0.000000000000 -vt 0.219951391220 0.551127851009 0.000000000000 -vt 0.219577863812 0.544329047203 0.000000000000 -vt 0.236548244953 0.540101110935 0.000000000000 -vt 0.239640295506 0.557557404041 0.000000000000 -vt 0.364015817642 0.556429386139 0.000000000000 -vt 0.364667207003 0.559019565582 0.000000000000 -vt 0.385533690453 0.553289771080 0.000000000000 -vt 0.382902741432 0.557026267052 0.000000000000 -vt 0.154217123985 0.713813722134 0.000000000000 -vt 0.157158553600 0.710084676743 0.000000000000 -vt 0.139992043376 0.697338879108 0.000000000000 -vt 0.145032361150 0.694776415825 0.000000000000 -vt 0.129598200321 0.676885545254 0.000000000000 -vt 0.133522659540 0.676785171032 0.000000000000 -vt 0.121781267226 0.655710399151 0.000000000000 -vt 0.125936508179 0.658108294010 0.000000000000 -vt 0.117115393281 0.636653959751 0.000000000000 -vt 0.121172465384 0.637733101845 0.000000000000 -vt 0.116183921695 0.616349458694 0.000000000000 -vt 0.120485514402 0.618173420429 0.000000000000 -vt 0.084196135402 0.636717438698 0.000000000000 -vt 0.084505945444 0.617743194103 0.000000000000 -vt 0.089589498937 0.618903636932 0.000000000000 -vt 0.089312784374 0.636993050575 0.000000000000 -vt 0.080862037838 0.637916862965 0.000000000000 -vt 0.081022799015 0.618841469288 0.000000000000 -vt 0.085008040071 0.598570287228 0.000000000000 -vt 0.090116359293 0.599607348442 0.000000000000 -vt 0.081807009876 0.598996996880 0.000000000000 -vt 0.086025521159 0.666380286217 0.000000000000 -vt 0.083288080990 0.667724907398 0.000000000000 -vt 0.115721911192 0.657637059689 0.000000000000 -vt 0.091839924455 0.665398180485 0.000000000000 -vt 0.112071022391 0.636431932449 0.000000000000 -vt 0.116621181369 0.598775207996 0.000000000000 -vt 0.122074656188 0.598256886005 0.000000000000 -vt 0.117822155356 0.580991744995 0.000000000000 -vt 0.122807092965 0.579663336277 0.000000000000 -vt 0.118204921484 0.561226546764 0.000000000000 -vt 0.122930236161 0.561480045319 0.000000000000 -vt 0.086409181356 0.580696821213 0.000000000000 -vt 0.088303416967 0.563481450081 0.000000000000 -vt 0.092769816518 0.562017738819 0.000000000000 -vt 0.090972624719 0.580980956554 0.000000000000 -vt 0.112636163831 0.581119179726 0.000000000000 -vt 0.110782906413 0.597800493240 0.000000000000 -vt 0.092613331974 0.689584314823 0.000000000000 -vt 0.099071905017 0.688045859337 0.000000000000 -vt 0.108099728823 0.710213482380 0.000000000000 -vt 0.102641746402 0.710727512836 0.000000000000 -vt 0.099205419421 0.711480677128 0.000000000000 -vt 0.090210475028 0.691667914391 0.000000000000 -vt 0.112440273166 0.725039958954 0.000000000000 -vt 0.109685271978 0.733518600464 0.000000000000 -vt 0.120316430926 0.724148333073 0.000000000000 -vt 0.149469718337 0.716144502163 0.000000000000 -vt 0.083509407938 0.581079363823 0.000000000000 -vt 0.085539408028 0.563082933426 0.000000000000 -vt 0.091403126717 0.541651070118 0.000000000000 -vt 0.135661408305 0.562481999397 0.000000000000 -vt 0.112166255713 0.617554724216 0.000000000000 -vt 0.115233764052 0.561244547367 0.000000000000 -vt 0.124406136572 0.679192543030 0.000000000000 -vt 0.135345742106 0.699786543846 0.000000000000 -vt 0.124257989228 0.753876924515 0.000000000000 -vt 0.128552585840 0.751157760620 0.000000000000 -vt 0.165847733617 0.731854498386 0.000000000000 -vt 0.135802805424 0.748261570930 0.000000000000 -vt 0.166685536504 0.724866151810 0.000000000000 -vt 0.170482099056 0.722631275654 0.000000000000 -vt 0.118092343211 0.538387894630 0.000000000000 -vt 0.120958782732 0.537692189217 0.000000000000 -vt 0.098085269332 0.540873169899 0.000000000000 -vt 0.094365492463 0.541822671890 0.000000000000 -vt 0.132603570819 0.540962100029 0.000000000000 -vt 0.113834425807 0.538623392582 0.000000000000 -vt 0.319482028484 0.899047315121 0.000000000000 -vt 0.309817373753 0.903006970882 0.000000000000 -vt 0.303308844566 0.883904874325 0.000000000000 -vt 0.314649820328 0.880987823009 0.000000000000 -vt 0.328109025955 0.880558192730 0.000000000000 -vt 0.328658103943 0.897744834423 0.000000000000 -vt 0.341684728861 0.882348120213 0.000000000000 -vt 0.338721781969 0.899649322033 0.000000000000 -vt 0.355538994074 0.885123133659 0.000000000000 -vt 0.346919715405 0.902684092522 0.000000000000 -vt 0.264496624470 0.923883795738 0.000000000000 -vt 0.285223543644 0.930731534958 0.000000000000 -vt 0.267435461283 0.909074544907 0.000000000000 -vt 0.288075894117 0.921931266785 0.000000000000 -vt 0.274401426315 0.897557139397 0.000000000000 -vt 0.292297661304 0.914312303066 0.000000000000 -vt 0.287088751793 0.890229046345 0.000000000000 -vt 0.300147175789 0.908530831337 0.000000000000 -vt 0.310877472162 0.867308914661 0.000000000000 -vt 0.326778471470 0.865757822990 0.000000000000 -vt 0.343281567097 0.865718007088 0.000000000000 -vt 0.361255347729 0.866305887699 0.000000000000 -vt 0.245798677206 0.914549648762 0.000000000000 -vt 0.250797957182 0.897025287151 0.000000000000 -vt 0.263053983450 0.883340418339 0.000000000000 -vt 0.278658270836 0.875975549221 0.000000000000 -vt 0.297883272171 0.872081577778 0.000000000000 -vt 0.321375846863 0.908167660236 0.000000000000 -vt 0.313384771347 0.911024928093 0.000000000000 -vt 0.312286227942 0.907532513142 0.000000000000 -vt 0.320597171783 0.903883635998 0.000000000000 -vt 0.329484283924 0.906974732876 0.000000000000 -vt 0.329025387764 0.902560055256 0.000000000000 -vt 0.335602283478 0.907388985157 0.000000000000 -vt 0.336900919676 0.903732657433 0.000000000000 -vt 0.340975165367 0.909342050552 0.000000000000 -vt 0.344243913889 0.905984163284 0.000000000000 -vt 0.292275160551 0.931756854057 0.000000000000 -vt 0.288374781609 0.931339025497 0.000000000000 -vt 0.294533699751 0.926007986069 0.000000000000 -vt 0.291681826115 0.923927128315 0.000000000000 -vt 0.298611998558 0.919755756855 0.000000000000 -vt 0.295432448387 0.917401850224 0.000000000000 -vt 0.304809689522 0.915081322193 0.000000000000 -vt 0.302478045225 0.912388324738 0.000000000000 -vt 0.309649169445 0.859347939491 0.000000000000 -vt 0.325541138649 0.857225894928 0.000000000000 -vt 0.326330006123 0.861102938652 0.000000000000 -vt 0.309487581253 0.863262355328 0.000000000000 -vt 0.341508537531 0.857451260090 0.000000000000 -vt 0.343136012554 0.863369047642 0.000000000000 -vt 0.356366693974 0.855853736401 0.000000000000 -vt 0.360483229160 0.861095964909 0.000000000000 -vt 0.237906411290 0.910131931305 0.000000000000 -vt 0.242411300540 0.912403225899 0.000000000000 -vt 0.243345454335 0.892147541046 0.000000000000 -vt 0.247076600790 0.894490242004 0.000000000000 -vt 0.255101680756 0.878566741943 0.000000000000 -vt 0.258435934782 0.881105363369 0.000000000000 -vt 0.274271398783 0.868584036827 0.000000000000 -vt 0.276469051838 0.872065901756 0.000000000000 -vt 0.295189887285 0.862639725208 0.000000000000 -vt 0.297131747007 0.866627097130 0.000000000000 -vt 0.264509558678 0.939163446426 0.000000000000 -vt 0.284231007099 0.939391553402 0.000000000000 -vt 0.245086982846 0.933630704880 0.000000000000 -vt 0.292607039213 0.937922894955 0.000000000000 -vt 0.288247227669 0.939458549023 0.000000000000 -vt 0.234031543136 0.927958786488 0.000000000000 -vt 0.239948898554 0.931120336056 0.000000000000 -vt 0.303108215332 0.259901374578 0.000000000000 -vt 0.299691259861 0.272608458996 0.000000000000 -vt 0.227741092443 0.179622754455 0.000000000000 -vt 0.241408705711 0.177819043398 0.000000000000 -vt 0.288645803928 0.272444993258 0.000000000000 -vt 0.249047771096 0.186873659492 0.000000000000 -vt 0.294585645199 0.259171187878 0.000000000000 -vt 0.304501682520 0.254701167345 0.000000000000 -vt 0.313444852829 0.253634393215 0.000000000000 -vt 0.312482535839 0.259582310915 0.000000000000 -vt 0.296862632036 0.254683613777 0.000000000000 -vt 0.286406427622 0.256932258606 0.000000000000 -vt 0.289906680584 0.252584934235 0.000000000000 -vt 0.279214531183 0.252052009106 0.000000000000 -vt 0.283777058125 0.248220309615 0.000000000000 -vt 0.278458207846 0.270513832569 0.000000000000 -vt 0.212318181992 0.149050965905 0.000000000000 -vt 0.220562011003 0.146735697985 0.000000000000 -vt 0.222703933716 0.152291625738 0.000000000000 -vt 0.213263839483 0.154687494040 0.000000000000 -vt 0.203408792615 0.155836462975 0.000000000000 -vt 0.203189268708 0.150103569031 0.000000000000 -vt 0.193548575044 0.156050369143 0.000000000000 -vt 0.193696498871 0.150199025869 0.000000000000 -vt 0.183689251542 0.155369937420 0.000000000000 -vt 0.184210494161 0.149640426040 0.000000000000 -vt 0.193191483617 0.169719755650 0.000000000000 -vt 0.182228907943 0.169336318970 0.000000000000 -vt 0.268187999725 0.265260279179 0.000000000000 -vt 0.324253201485 0.252125859261 0.000000000000 -vt 0.231818437576 0.195312470198 0.000000000000 -vt 0.212309181690 0.181552782655 0.000000000000 -vt 0.213149681687 0.200687378645 0.000000000000 -vt 0.197734892368 0.182133242488 0.000000000000 -vt 0.196059510112 0.201420485973 0.000000000000 -vt 0.178108111024 0.197619631886 0.000000000000 -vt 0.184773385525 0.179257780313 0.000000000000 -vt 0.193671286106 0.220274075866 0.000000000000 -vt 0.204073458910 0.169701069593 0.000000000000 -vt 0.171984791756 0.217511638999 0.000000000000 -vt 0.196902945638 0.242536947131 0.000000000000 -vt 0.323984831572 0.258038192987 0.000000000000 -vt 0.310539454222 0.271224856377 0.000000000000 -vt 0.324096947908 0.268115252256 0.000000000000 -vt 0.339193135500 0.265587210655 0.000000000000 -vt 0.336792320013 0.254855424166 0.000000000000 -vt 0.340972989798 0.271843373775 0.000000000000 -vt 0.325516790152 0.274833887815 0.000000000000 -vt 0.313507229090 0.275261014700 0.000000000000 -vt 0.171768411994 0.240901872516 0.000000000000 -vt 0.215576186776 0.241010859609 0.000000000000 -vt 0.215113937855 0.219385609031 0.000000000000 -vt 0.179179176688 0.179597318172 0.000000000000 -vt 0.354237109423 0.261272788048 0.000000000000 -vt 0.356365293264 0.266201436520 0.000000000000 -vt 0.348684787750 0.251001656055 0.000000000000 -vt 0.335720360279 0.249260529876 0.000000000000 -vt 0.346057444811 0.245707139373 0.000000000000 -vt 0.367124110460 0.254228800535 0.000000000000 -vt 0.359250634909 0.246444091201 0.000000000000 -vt 0.355434030294 0.241601213813 0.000000000000 -vt 0.369936972857 0.258326172829 0.000000000000 -vt 0.169737070799 0.113030180335 0.000000000000 -vt 0.170575097203 0.120991900563 0.000000000000 -vt 0.297219276428 0.135332033038 0.000000000000 -vt 0.283211469650 0.234442397952 0.000000000000 -vt 0.292599529028 0.237945362926 0.000000000000 -vt 0.298478573561 0.140298739076 0.000000000000 -vt 0.290076673031 0.243708446622 0.000000000000 -vt 0.282434672117 0.239781066775 0.000000000000 -vt 0.305352568626 0.241858348250 0.000000000000 -vt 0.303028285503 0.248206838965 0.000000000000 -vt 0.324729174376 0.241821423173 0.000000000000 -vt 0.321562141180 0.249174103141 0.000000000000 -vt 0.347120851278 0.237402305007 0.000000000000 -vt 0.343635231256 0.232021078467 0.000000000000 -vt 0.357544183731 0.220489770174 0.000000000000 -vt 0.362244993448 0.226528212428 0.000000000000 -vt 0.363515973091 0.202669411898 0.000000000000 -vt 0.368934571743 0.200474381447 0.000000000000 -vt 0.344842731953 0.210690349340 0.000000000000 -vt 0.342417836189 0.185361966491 0.000000000000 -vt 0.364349514246 0.181216180325 0.000000000000 -vt 0.324543416500 0.218253985047 0.000000000000 -vt 0.321842014790 0.191119849682 0.000000000000 -vt 0.337232500315 0.165248394012 0.000000000000 -vt 0.356791496277 0.164284512401 0.000000000000 -vt 0.332506477833 0.147537469864 0.000000000000 -vt 0.347481101751 0.153085976839 0.000000000000 -vt 0.318637371063 0.169776722789 0.000000000000 -vt 0.312718063593 0.146633028984 0.000000000000 -vt 0.370308697224 0.181861028075 0.000000000000 -vt 0.360243141651 0.161985456944 0.000000000000 -vt 0.304652988911 0.221441268921 0.000000000000 -vt 0.303939700127 0.197721183300 0.000000000000 -vt 0.289470791817 0.148055776954 0.000000000000 -vt 0.285560518503 0.142270863056 0.000000000000 -vt 0.291176348925 0.221764370799 0.000000000000 -vt 0.288291871548 0.203909799457 0.000000000000 -vt 0.276085317135 0.156505629420 0.000000000000 -vt 0.272780030966 0.150750204921 0.000000000000 -vt 0.258125126362 0.158074513078 0.000000000000 -vt 0.260224252939 0.163233041763 0.000000000000 -vt 0.243465483189 0.162214890122 0.000000000000 -vt 0.243714034557 0.151190385222 0.000000000000 -vt 0.254636585712 0.146920993924 0.000000000000 -vt 0.229478836060 0.163604542613 0.000000000000 -vt 0.233701616526 0.153107583523 0.000000000000 -vt 0.167218700051 0.121271774173 0.000000000000 -vt 0.166369423270 0.112692907453 0.000000000000 -vt 0.243073940277 0.145069316030 0.000000000000 -vt 0.252761274576 0.141263067722 0.000000000000 -vt 0.263089358807 0.136896863580 0.000000000000 -vt 0.266313344240 0.141587063670 0.000000000000 -vt 0.277861565351 0.135119035840 0.000000000000 -vt 0.273413181305 0.131129965186 0.000000000000 -vt 0.282169669867 0.124930545688 0.000000000000 -vt 0.287077844143 0.128512978554 0.000000000000 -vt 0.289280533791 0.119594141841 0.000000000000 -vt 0.293950706720 0.122467115521 0.000000000000 -vt 0.168387711048 0.136361449957 0.000000000000 -vt 0.172123029828 0.133879333735 0.000000000000 -vt 0.159614548087 0.137594163418 0.000000000000 -vt 0.170139640570 0.142349898815 0.000000000000 -vt 0.159916698933 0.145990878344 0.000000000000 -vt 0.175263956189 0.137986391783 0.000000000000 -vt 0.158946737647 0.121140733361 0.000000000000 -vt 0.158538520336 0.111063912511 0.000000000000 -vt 0.150848120451 0.113286182284 0.000000000000 -vt 0.147537663579 0.113875642419 0.000000000000 -vt 0.150810301304 0.122010722756 0.000000000000 -vt 0.150818631053 0.137049511075 0.000000000000 -vt 0.146893724799 0.134909197688 0.000000000000 -vt 0.234794318676 0.147171825171 0.000000000000 -vt 0.280413031578 0.223018944263 0.000000000000 -vt 0.244322419167 0.167136326432 0.000000000000 -vt 0.215430051088 0.169227793813 0.000000000000 -vt 0.276956439018 0.210102006793 0.000000000000 -vt 0.230842590332 0.168110579252 0.000000000000 -vt 0.304748684168 0.128483712673 0.000000000000 -vt 0.319317579269 0.112706646323 0.000000000000 -vt 0.304126799107 0.108920201659 0.000000000000 -vt 0.306201845407 0.100410684943 0.000000000000 -vt 0.324304103851 0.102940306067 0.000000000000 -vt 0.298506706953 0.108017548919 0.000000000000 -vt 0.227834999561 0.168783783913 0.000000000000 -vt 0.173827692866 0.153802856803 0.000000000000 -vt 0.164431959391 0.150985270739 0.000000000000 -vt 0.166879624128 0.145447134972 0.000000000000 -vt 0.175091713667 0.148140892386 0.000000000000 -vt 0.170737877488 0.168616726995 0.000000000000 -vt 0.158358171582 0.168257147074 0.000000000000 -vt 0.171079888940 0.173917546868 0.000000000000 -vt 0.298551976681 0.176225617528 0.000000000000 -vt 0.284409761429 0.187349408865 0.000000000000 -vt 0.278388887644 0.172707334161 0.000000000000 -vt 0.265587240458 0.188653051853 0.000000000000 -vt 0.263487190008 0.183533251286 0.000000000000 -vt 0.172304287553 0.195576354861 0.000000000000 -vt 0.166341051459 0.215843468904 0.000000000000 -vt 0.246410295367 0.175310358405 0.000000000000 -vt 0.253420293331 0.181435257196 0.000000000000 -vt 0.258993119001 0.199986010790 0.000000000000 -vt 0.238587737083 0.209960162640 0.000000000000 -vt 0.263290882111 0.194039210677 0.000000000000 -vt 0.244794785976 0.230162426829 0.000000000000 -vt 0.267062664032 0.219509899616 0.000000000000 -vt 0.265724569559 0.241132006049 0.000000000000 -vt 0.247063919902 0.252580881119 0.000000000000 -vt 0.260249704123 0.258537381887 0.000000000000 -vt 0.247949019074 0.272692441940 0.000000000000 -vt 0.271840006113 0.241458699107 0.000000000000 -vt 0.267441391945 0.259758830070 0.000000000000 -vt 0.274886131287 0.221160054207 0.000000000000 -vt 0.248786136508 0.278353273869 0.000000000000 -vt 0.233543574810 0.288995474577 0.000000000000 -vt 0.228813290596 0.284420073032 0.000000000000 -vt 0.222581654787 0.263455659151 0.000000000000 -vt 0.201069429517 0.264848470688 0.000000000000 -vt 0.147332772613 0.121980324388 0.000000000000 -vt 0.149485930800 0.143096730113 0.000000000000 -vt 0.144085362554 0.139203354716 0.000000000000 -vt 0.274613022804 0.168164387345 0.000000000000 -vt 0.272586405277 0.198066562414 0.000000000000 -vt 0.292887955904 0.156603798270 0.000000000000 -vt 0.289811223745 0.151691362262 0.000000000000 -vt 0.308121502399 0.141383305192 0.000000000000 -vt 0.331666439772 0.141558468342 0.000000000000 -vt 0.346801817417 0.147019162774 0.000000000000 -vt 0.208444163203 0.284849673510 0.000000000000 -vt 0.207779288292 0.289209812880 0.000000000000 -vt 0.329524755478 0.248061582446 0.000000000000 -vt 0.180802538991 0.263033509254 0.000000000000 -vt 0.364997059107 0.218376457691 0.000000000000 -vt 0.185599476099 0.280001878738 0.000000000000 -vt 0.174449339509 0.263261795044 0.000000000000 -vt 0.192701548338 0.278811007738 0.000000000000 -vt 0.367429643869 0.175568386912 0.000000000000 -vt 0.166094049811 0.244550302625 0.000000000000 -vt 0.159377232194 0.173221364617 0.000000000000 -vt 0.182153701782 0.175170764327 0.000000000000 -vt 0.193075969815 0.175665423274 0.000000000000 -vt 0.313833713531 0.139958515763 0.000000000000 -vt 0.352484732866 0.149898454547 0.000000000000 -vt 0.203923046589 0.175497695804 0.000000000000 -vt 0.214893281460 0.174428433180 0.000000000000 -vt 0.226242244244 0.173432335258 0.000000000000 -vt 0.378087341785 0.245563969016 0.000000000000 -vt 0.380262136459 0.249743267894 0.000000000000 -vt 0.367841005325 0.240881398320 0.000000000000 -vt 0.362897038460 0.237351402640 0.000000000000 -vt 0.300132334232 0.100594177842 0.000000000000 -vt 0.299615830183 0.116130575538 0.000000000000 -vt 0.294845253229 0.114346668124 0.000000000000 -vt 0.312476694584 0.120818093419 0.000000000000 -vt 0.262099564075 0.265859633684 0.000000000000 -vt 0.271560132504 0.212059065700 0.000000000000 -vt 0.224148511887 0.289957106113 0.000000000000 -vt 0.191555723548 0.285657763481 0.000000000000 -vt 0.165448531508 0.236725702882 0.000000000000 -vt 0.048055123538 0.175203412771 0.000000000000 -vt 0.048704918474 0.175287619233 0.000000000000 -vt 0.049519758672 0.175945073366 0.000000000000 -vt 0.048962052912 0.176530927420 0.000000000000 -vt 0.048142258078 0.174550458789 0.000000000000 -vt 0.048840459436 0.174907326698 0.000000000000 -vt 0.048184361309 0.177168339491 0.000000000000 -vt 0.047785613686 0.175479233265 0.000000000000 -vt 0.050077687949 0.175508722663 0.000000000000 -vt 0.049611847848 0.173526674509 0.000000000000 -vt 0.050155591220 0.174321472645 0.000000000000 -vt 0.050484325737 0.174935474992 0.000000000000 -vt 0.049262631685 0.178634554148 0.000000000000 -vt 0.050630893558 0.177782341838 0.000000000000 -vt 0.053486991674 0.179326459765 0.000000000000 -vt 0.051250975579 0.172665014863 0.000000000000 -vt 0.052335549146 0.174432024360 0.000000000000 -vt 0.052290286869 0.172393932939 0.000000000000 -vt 0.060022119433 0.196368679404 0.000000000000 -vt 0.059825789183 0.195150136948 0.000000000000 -vt 0.062848724425 0.193425223231 0.000000000000 -vt 0.063640370965 0.194470614195 0.000000000000 -vt 0.057444769889 0.198157310486 0.000000000000 -vt 0.061123806983 0.204831123352 0.000000000000 -vt 0.054434444755 0.202152684331 0.000000000000 -vt 0.052125032991 0.196384206414 0.000000000000 -vt 0.065405808389 0.200892046094 0.000000000000 -vt 0.053650680929 0.194501906633 0.000000000000 -vt 0.071322210133 0.182865217328 0.000000000000 -vt 0.069051973522 0.180266022682 0.000000000000 -vt 0.072467572987 0.177512601018 0.000000000000 -vt 0.073771677911 0.182455211878 0.000000000000 -vt 0.046373885125 0.201640009880 0.000000000000 -vt 0.047620352358 0.205844104290 0.000000000000 -vt 0.044672172517 0.207344532013 0.000000000000 -vt 0.043322812766 0.201532378793 0.000000000000 -vt 0.048094075173 0.197172701359 0.000000000000 -vt 0.050799090415 0.203515991569 0.000000000000 -vt 0.043212261051 0.193465515971 0.000000000000 -vt 0.038478370756 0.209311038256 0.000000000000 -vt 0.037481162697 0.210909873247 0.000000000000 -vt 0.035782586783 0.208673626184 0.000000000000 -vt 0.036327917129 0.206941053271 0.000000000000 -vt 0.038885008544 0.211182534695 0.000000000000 -vt 0.037817772478 0.205236405134 0.000000000000 -vt 0.037915710360 0.216193586588 0.000000000000 -vt 0.036525826901 0.213128775358 0.000000000000 -vt 0.033292595297 0.211684182286 0.000000000000 -vt 0.032988864928 0.209396824241 0.000000000000 -vt 0.044357400388 0.213697507977 0.000000000000 -vt 0.040415156633 0.211841553450 0.000000000000 -vt 0.041487347335 0.208158016205 0.000000000000 -vt 0.042062167078 0.222331538796 0.000000000000 -vt 0.039700064808 0.219182297587 0.000000000000 -vt 0.046859998256 0.219299152493 0.000000000000 -vt 0.039277669042 0.216008275747 0.000000000000 -vt 0.090955741704 0.182833924890 0.000000000000 -vt 0.095942027867 0.185236781836 0.000000000000 -vt 0.091125510633 0.186936691403 0.000000000000 -vt 0.090062774718 0.185735270381 0.000000000000 -vt 0.091737933457 0.190855517983 0.000000000000 -vt 0.087909393013 0.188273668289 0.000000000000 -vt 0.096602633595 0.188918739557 0.000000000000 -vt 0.094589523971 0.190106213093 0.000000000000 -vt 0.088805288076 0.195824697614 0.000000000000 -vt 0.085034608841 0.192018002272 0.000000000000 -vt 0.037808310241 0.218160092831 0.000000000000 -vt 0.101674705744 0.180272325873 0.000000000000 -vt 0.108147457242 0.181930154562 0.000000000000 -vt 0.084888033569 0.212164208293 0.000000000000 -vt 0.086827971041 0.209401324391 0.000000000000 -vt 0.092867530882 0.213331192732 0.000000000000 -vt 0.090507008135 0.217772141099 0.000000000000 -vt 0.078402668238 0.211174651980 0.000000000000 -vt 0.081946156919 0.206284955144 0.000000000000 -vt 0.064126476645 0.226784884930 0.000000000000 -vt 0.059163603932 0.221614643931 0.000000000000 -vt 0.063531167805 0.218933045864 0.000000000000 -vt 0.066850177944 0.224536255002 0.000000000000 -vt 0.058718021959 0.224759161472 0.000000000000 -vt 0.052740599960 0.222449973226 0.000000000000 -vt 0.051313344389 0.218079030514 0.000000000000 -vt 0.056304361671 0.215266615152 0.000000000000 -vt 0.052650313824 0.225943475962 0.000000000000 -vt 0.101671561599 0.191067621112 0.000000000000 -vt 0.102857217193 0.187916800380 0.000000000000 -vt 0.090246729553 0.206087037921 0.000000000000 -vt 0.085568904877 0.202257156372 0.000000000000 -vt 0.091549478471 0.199667423964 0.000000000000 -vt 0.092842765152 0.201647892594 0.000000000000 -vt 0.092551417649 0.205803573132 0.000000000000 -vt 0.094774819911 0.209103897214 0.000000000000 -vt 0.094059728086 0.210680663586 0.000000000000 -vt 0.095144078135 0.195538073778 0.000000000000 -vt 0.099691078067 0.194344520569 0.000000000000 -vt 0.099405810237 0.196164458990 0.000000000000 -vt 0.099158152938 0.198102816939 0.000000000000 -vt 0.095910727978 0.198648139834 0.000000000000 -vt 0.040310692042 0.223760381341 0.000000000000 -vt 0.038051482290 0.225095763803 0.000000000000 -vt 0.039297934622 0.221828088164 0.000000000000 -vt 0.048715729266 0.226211413741 0.000000000000 -vt 0.048271726817 0.223471954465 0.000000000000 -vt 0.054012056440 0.227152556181 0.000000000000 -vt 0.051328878850 0.229439899325 0.000000000000 -vt 0.050317708403 0.229129895568 0.000000000000 -vt 0.048270147294 0.228640601039 0.000000000000 -vt 0.040398042649 0.225845307112 0.000000000000 -vt 0.043110940605 0.225429221988 0.000000000000 -vt 0.043746557087 0.226806730032 0.000000000000 -vt 0.041524719447 0.227182060480 0.000000000000 -vt 0.039583209902 0.227637097239 0.000000000000 -vt 0.037672769278 0.226903319359 0.000000000000 -vt 0.033523153514 0.225719004869 0.000000000000 -vt 0.036088127643 0.224684417248 0.000000000000 -vt 0.036136310548 0.226817533374 0.000000000000 -vt 0.034433234483 0.227448642254 0.000000000000 -vt 0.027782825753 0.229924663901 0.000000000000 -vt 0.030765233561 0.223758801818 0.000000000000 -vt 0.030333613977 0.231470361352 0.000000000000 -vt 0.110832214355 0.191612944007 0.000000000000 -vt 0.111078530550 0.184968620539 0.000000000000 -vt 0.106155976653 0.192477762699 0.000000000000 -vt 0.041945312172 0.228952214122 0.000000000000 -vt 0.038930263370 0.230628952384 0.000000000000 -vt 0.041834760457 0.232057794929 0.000000000000 -vt 0.044282648712 0.228836938739 0.000000000000 -vt 0.044818740338 0.232165411115 0.000000000000 -vt 0.039072107524 0.234580442309 0.000000000000 -vt 0.036424513906 0.232783898711 0.000000000000 -vt 0.106855750084 0.201680526137 0.000000000000 -vt 0.103606760502 0.198020190001 0.000000000000 -vt 0.104195758700 0.196577385068 0.000000000000 -vt 0.107200011611 0.198694974184 0.000000000000 -vt 0.109750792384 0.200388818979 0.000000000000 -vt 0.109513923526 0.203364923596 0.000000000000 -vt 0.105775907636 0.203093826771 0.000000000000 -vt 0.102690592408 0.199908792973 0.000000000000 -vt 0.050538811833 0.243682101369 0.000000000000 -vt 0.048396233469 0.240920796990 0.000000000000 -vt 0.048424374312 0.237581744790 0.000000000000 -vt 0.051719974726 0.241248175502 0.000000000000 -vt 0.046845819801 0.239993855357 0.000000000000 -vt 0.108550950885 0.195103302598 0.000000000000 -vt 0.107877954841 0.196638181806 0.000000000000 -vt 0.104663178325 0.194704324007 0.000000000000 -vt 0.111446216702 0.196098938584 0.000000000000 -vt 0.110371097922 0.198414430022 0.000000000000 -vt 0.033939246088 0.229781255126 0.000000000000 -vt 0.032943610102 0.235806867480 0.000000000000 -vt 0.036778222769 0.228347703815 0.000000000000 -vt 0.026748239994 0.237935468554 0.000000000000 -vt 0.029005868360 0.239583835006 0.000000000000 -vt 0.024600934237 0.235979780555 0.000000000000 -vt 0.036203410476 0.237542793155 0.000000000000 -vt 0.047933544964 0.242292001843 0.000000000000 -vt 0.048371467739 0.243713185191 0.000000000000 -vt 0.047026615590 0.242233023047 0.000000000000 -vt 0.047408472747 0.243272319436 0.000000000000 -vt 0.112042874098 0.199774816632 0.000000000000 -vt 0.112708196044 0.198945805430 0.000000000000 -vt 0.112421587110 0.201317355037 0.000000000000 -vt 0.115999296308 0.201012045145 0.000000000000 -vt 0.047676410526 0.245324388146 0.000000000000 -vt 0.046835009009 0.243697628379 0.000000000000 -vt 0.046366009861 0.242653593421 0.000000000000 -vt 0.116282775998 0.196683213115 0.000000000000 -vt 0.054629202932 0.245314940810 0.000000000000 -vt 0.055006336421 0.243421837687 0.000000000000 -vt 0.054401572794 0.246826633811 0.000000000000 -vt 0.049971643835 0.245547279716 0.000000000000 -vt 0.045614894480 0.244002953172 0.000000000000 -vt 0.046210203320 0.243990585208 0.000000000000 -vt 0.046083893627 0.245279118419 0.000000000000 -vt 0.044977705926 0.244760379195 0.000000000000 -vt 0.044843737036 0.243163123727 0.000000000000 -vt 0.045724090189 0.242940440774 0.000000000000 -vt 0.044279497117 0.243847146630 0.000000000000 -vt 0.042543780059 0.243463918567 0.000000000000 -vt 0.042998816818 0.241575345397 0.000000000000 -vt 0.043060954660 0.245589390397 0.000000000000 -vt 0.050320636481 0.250064343214 0.000000000000 -vt 0.046863149852 0.247579082847 0.000000000000 -vt 0.044486861676 0.247248783708 0.000000000000 -vt 0.115950897336 0.205869093537 0.000000000000 -vt 0.111902818084 0.203687563539 0.000000000000 -vt 0.067590266466 0.245651528239 0.000000000000 -vt 0.060156088322 0.247964099050 0.000000000000 -vt 0.059522051364 0.246006831527 0.000000000000 -vt 0.064255714417 0.241894826293 0.000000000000 -vt 0.075842648745 0.243643149734 0.000000000000 -vt 0.076406665146 0.251217573881 0.000000000000 -vt 0.068737201393 0.251990318298 0.000000000000 -vt 0.061447802931 0.252729058266 0.000000000000 -vt 0.101252302527 0.229214087129 0.000000000000 -vt 0.107055231929 0.225204750896 0.000000000000 -vt 0.110550090671 0.228503510356 0.000000000000 -vt 0.103125378489 0.234605416656 0.000000000000 -vt 0.093981824815 0.227124422789 0.000000000000 -vt 0.102826148272 0.221592798829 0.000000000000 -vt 0.093353867531 0.237001970410 0.000000000000 -vt 0.031605061144 0.248132273555 0.000000000000 -vt 0.033780287951 0.241846427321 0.000000000000 -vt 0.038934987038 0.242647275329 0.000000000000 -vt 0.038883429021 0.246692433953 0.000000000000 -vt 0.040764149278 0.250432223082 0.000000000000 -vt 0.034480068833 0.253740221262 0.000000000000 -vt 0.026098441333 0.256615221500 0.000000000000 -vt 0.024784889072 0.253078043461 0.000000000000 -vt 0.027103310451 0.246195510030 0.000000000000 -vt 0.022952351719 0.252045035362 0.000000000000 -vt 0.043932076544 0.254584789276 0.000000000000 -vt 0.049854788929 0.255521208048 0.000000000000 -vt 0.035871531814 0.256568402052 0.000000000000 -vt 0.127526775002 0.205384328961 0.000000000000 -vt 0.129298523068 0.208109617233 0.000000000000 -vt 0.124919943511 0.212541341782 0.000000000000 -vt 0.122282020748 0.208313822746 0.000000000000 -vt 0.130605995655 0.199026852846 0.000000000000 -vt 0.134021386504 0.202176094055 0.000000000000 -vt 0.123184211552 0.201524719596 0.000000000000 -vt 0.043590750545 0.262480288744 0.000000000000 -vt 0.045658569783 0.265317708254 0.000000000000 -vt 0.042624827474 0.268781721592 0.000000000000 -vt 0.040003802627 0.268262714148 0.000000000000 -vt 0.049783188850 0.260548025370 0.000000000000 -vt 0.050202202052 0.262952446938 0.000000000000 -vt 0.035101722926 0.267388671637 0.000000000000 -vt 0.036307651550 0.262090772390 0.000000000000 -vt 0.158384069800 0.177545472980 0.000000000000 -vt 0.163128763437 0.177713662386 0.000000000000 -vt 0.161081433296 0.184286177158 0.000000000000 -vt 0.155855119228 0.182891562581 0.000000000000 -vt 0.030163845047 0.266456753016 0.000000000000 -vt 0.028748972341 0.262917995453 0.000000000000 -vt 0.152635857463 0.180741325021 0.000000000000 -vt 0.156146481633 0.174547314644 0.000000000000 -vt 0.108293592930 0.175105020404 0.000000000000 -vt 0.103180319071 0.172587782145 0.000000000000 -vt 0.102925881743 0.166502520442 0.000000000000 -vt 0.107659325004 0.167699888349 0.000000000000 -vt 0.091472923756 0.255974650383 0.000000000000 -vt 0.083825305104 0.257546931505 0.000000000000 -vt 0.084012404084 0.249293193221 0.000000000000 -vt 0.091871894896 0.246349737048 0.000000000000 -vt 0.112725540996 0.167742446065 0.000000000000 -vt 0.113225832582 0.171109184623 0.000000000000 -vt 0.035772006959 0.183283552527 0.000000000000 -vt 0.035782817751 0.183923900127 0.000000000000 -vt 0.033255446702 0.184070467949 0.000000000000 -vt 0.033405173570 0.183254063129 0.000000000000 -vt 0.038481753320 0.182127386332 0.000000000000 -vt 0.038974162191 0.182417154312 0.000000000000 -vt 0.034431885928 0.181669190526 0.000000000000 -vt 0.036685016006 0.180374324322 0.000000000000 -vt 0.144137382507 0.199537962675 0.000000000000 -vt 0.139657467604 0.194585889578 0.000000000000 -vt 0.144188717008 0.186229258776 0.000000000000 -vt 0.148093581200 0.188943728805 0.000000000000 -vt 0.136400818825 0.206110462546 0.000000000000 -vt 0.153703317046 0.190900772810 0.000000000000 -vt 0.151239663363 0.198920801282 0.000000000000 -vt 0.150279834867 0.205067992210 0.000000000000 -vt 0.143856838346 0.206392586231 0.000000000000 -vt 0.163417190313 0.198642060161 0.000000000000 -vt 0.164253860712 0.202018722892 0.000000000000 -vt 0.160158962011 0.199008166790 0.000000000000 -vt 0.162906080484 0.192356184125 0.000000000000 -vt 0.165629789233 0.191846653819 0.000000000000 -vt 0.028680523857 0.176149964333 0.000000000000 -vt 0.028775541112 0.179067075253 0.000000000000 -vt 0.027133254334 0.179045230150 0.000000000000 -vt 0.026841904968 0.175766751170 0.000000000000 -vt 0.107328131795 0.163071155548 0.000000000000 -vt 0.102894365788 0.161774039268 0.000000000000 -vt 0.103162080050 0.158067077398 0.000000000000 -vt 0.107190564275 0.158765062690 0.000000000000 -vt 0.034622143954 0.168636307120 0.000000000000 -vt 0.034757684916 0.167032986879 0.000000000000 -vt 0.037417437881 0.167039290071 0.000000000000 -vt 0.036150719970 0.169255033135 0.000000000000 -vt 0.032856475562 0.170001432300 0.000000000000 -vt 0.031410526484 0.168317034841 0.000000000000 -vt 0.071371294558 0.162234246731 0.000000000000 -vt 0.072683498263 0.160097971559 0.000000000000 -vt 0.074752002954 0.160783797503 0.000000000000 -vt 0.072475455701 0.163342237473 0.000000000000 -vt 0.070219628513 0.164971008897 0.000000000000 -vt 0.067989014089 0.162172779441 0.000000000000 -vt 0.070951156318 0.158560618758 0.000000000000 -vt 0.071128129959 0.166468963027 0.000000000000 -vt 0.069623641670 0.166651114821 0.000000000000 -vt 0.052506666631 0.160904929042 0.000000000000 -vt 0.057779353112 0.165149331093 0.000000000000 -vt 0.056724499911 0.167911082506 0.000000000000 -vt 0.050493102521 0.165551453829 0.000000000000 -vt 0.060259658843 0.168007910252 0.000000000000 -vt 0.059231828898 0.159990578890 0.000000000000 -vt 0.061392862350 0.158380940557 0.000000000000 -vt 0.063771635294 0.161536499858 0.000000000000 -vt 0.063607268035 0.163274914026 0.000000000000 -vt 0.055211450905 0.155678853393 0.000000000000 -vt 0.057744000107 0.153191789985 0.000000000000 -vt 0.058993611485 0.163293376565 0.000000000000 -vt 0.053434979171 0.158556342125 0.000000000000 -vt 0.064857780933 0.162417531013 0.000000000000 -vt 0.064824908972 0.161404550076 0.000000000000 -vt 0.031159481034 0.208711221814 0.000000000000 -vt 0.030880516395 0.210443794727 0.000000000000 -vt 0.029724342749 0.204800054431 0.000000000000 -vt 0.031837198883 0.204756379128 0.000000000000 -vt 0.128212377429 0.176210075617 0.000000000000 -vt 0.128955841064 0.177864745259 0.000000000000 -vt 0.126242950559 0.177906855941 0.000000000000 -vt 0.125418648124 0.176409572363 0.000000000000 -vt 0.129953056574 0.174939975142 0.000000000000 -vt 0.130758658051 0.176998347044 0.000000000000 -vt 0.121036924422 0.175653725863 0.000000000000 -vt 0.121420361102 0.178308978677 0.000000000000 -vt 0.123617418110 0.183743998408 0.000000000000 -vt 0.117588669062 0.183899804950 0.000000000000 -vt 0.115403994918 0.191726654768 0.000000000000 -vt 0.122710488737 0.192234605551 0.000000000000 -vt 0.123056329787 0.196519747376 0.000000000000 -vt 0.128924548626 0.189431414008 0.000000000000 -vt 0.129672512412 0.193513929844 0.000000000000 -vt 0.133775278926 0.185372322798 0.000000000000 -vt 0.134995400906 0.187966778874 0.000000000000 -vt 0.136989831924 0.191276341677 0.000000000000 -vt 0.139916166663 0.181990936399 0.000000000000 -vt 0.141775041819 0.183941915631 0.000000000000 -vt 0.145468041301 0.175736352801 0.000000000000 -vt 0.147888004780 0.177232280374 0.000000000000 -vt 0.149156302214 0.178392961621 0.000000000000 -vt 0.151406511664 0.170416608453 0.000000000000 -vt 0.153140649199 0.171435669065 0.000000000000 -vt 0.026889864355 0.258701503277 0.000000000000 -vt 0.148213580251 0.169269666076 0.000000000000 -vt 0.138399973512 0.180339202285 0.000000000000 -vt 0.143568634987 0.174784168601 0.000000000000 -vt 0.146306514740 0.170045778155 0.000000000000 -vt 0.137052193284 0.178213953972 0.000000000000 -vt 0.141616314650 0.173843026161 0.000000000000 -vt 0.144707694650 0.169350728393 0.000000000000 -vt 0.021730657667 0.250446200371 0.000000000000 -vt 0.024742785841 0.244501665235 0.000000000000 -vt 0.018961701542 0.249092146754 0.000000000000 -vt 0.022073570639 0.243767663836 0.000000000000 -vt 0.023706618696 0.235825523734 0.000000000000 -vt 0.027095658705 0.229019328952 0.000000000000 -vt 0.029609059915 0.222379729152 0.000000000000 -vt 0.030542327091 0.216693878174 0.000000000000 -vt 0.033057313412 0.217472910881 0.000000000000 -vt 0.087314084172 0.175335809588 0.000000000000 -vt 0.094248183072 0.178092375398 0.000000000000 -vt 0.092181935906 0.179499372840 0.000000000000 -vt 0.085963152349 0.177274391055 0.000000000000 -vt 0.081338465214 0.174150139093 0.000000000000 -vt 0.082193829119 0.172002837062 0.000000000000 -vt 0.076521947980 0.167970299721 0.000000000000 -vt 0.077380686998 0.167476311326 0.000000000000 -vt 0.081656381488 0.178617432714 0.000000000000 -vt 0.077681265771 0.174922868609 0.000000000000 -vt 0.087579086423 0.180975034833 0.000000000000 -vt 0.074853092432 0.169260442257 0.000000000000 -vt 0.079015091062 0.179725423455 0.000000000000 -vt 0.076188489795 0.181088745594 0.000000000000 -vt 0.074826754630 0.175708204508 0.000000000000 -vt 0.082938641310 0.183109730482 0.000000000000 -vt 0.078197099268 0.184789612889 0.000000000000 -vt 0.070867173374 0.171145886183 0.000000000000 -vt 0.073829539120 0.169667065144 0.000000000000 -vt 0.031271602958 0.196384206414 0.000000000000 -vt 0.033982921392 0.194425582886 0.000000000000 -vt 0.037058766931 0.199865102768 0.000000000000 -vt 0.034688781947 0.202102705836 0.000000000000 -vt 0.033738177270 0.202948838472 0.000000000000 -vt 0.030448889360 0.197130590677 0.000000000000 -vt 0.028569748625 0.198085710406 0.000000000000 -vt 0.036571081728 0.216693878174 0.000000000000 -vt 0.033219423145 0.214136794209 0.000000000000 -vt 0.035667311400 0.220581635833 0.000000000000 -vt 0.030702864751 0.212936937809 0.000000000000 -vt 0.037512231618 0.221022486687 0.000000000000 -vt 0.039851140231 0.198102816939 0.000000000000 -vt 0.041124176234 0.203433588147 0.000000000000 -vt 0.037788044661 0.191379234195 0.000000000000 -vt 0.041217606515 0.195904180408 0.000000000000 -vt 0.067828707397 0.174960240722 0.000000000000 -vt 0.038927104324 0.189132183790 0.000000000000 -vt 0.041049417108 0.184728831053 0.000000000000 -vt 0.043036188930 0.186458468437 0.000000000000 -vt 0.065335564315 0.175491616130 0.000000000000 -vt 0.064928933978 0.179175376892 0.000000000000 -vt 0.059944216162 0.177007809281 0.000000000000 -vt 0.060216885060 0.175005495548 0.000000000000 -vt 0.055878814310 0.175014957786 0.000000000000 -vt 0.064486503601 0.180831611156 0.000000000000 -vt 0.059665244073 0.178134486079 0.000000000000 -vt 0.055603001267 0.176066651940 0.000000000000 -vt 0.059327062219 0.179134845734 0.000000000000 -vt 0.054891061038 0.176806747913 0.000000000000 -vt 0.052252914757 0.175443425775 0.000000000000 -vt 0.054579224437 0.177642062306 0.000000000000 -vt 0.051933418959 0.176275372505 0.000000000000 -vt 0.054217841476 0.178369775414 0.000000000000 -vt 0.051375713199 0.176691457629 0.000000000000 -vt 0.058970417827 0.180060461164 0.000000000000 -vt 0.058582257479 0.180961072445 0.000000000000 -vt 0.057680051774 0.181828826666 0.000000000000 -vt 0.062502883375 0.183891922235 0.000000000000 -vt 0.061697278172 0.184658572078 0.000000000000 -vt 0.050166402012 0.187552273273 0.000000000000 -vt 0.051037531346 0.187452524900 0.000000000000 -vt 0.054431293160 0.193168088794 0.000000000000 -vt 0.049586858600 0.182190433145 0.000000000000 -vt 0.049161311239 0.182690724730 0.000000000000 -vt 0.048391725868 0.182542562485 0.000000000000 -vt 0.049334455281 0.187815472484 0.000000000000 -vt 0.048377547413 0.188716322184 0.000000000000 -vt 0.047788541764 0.182509928942 0.000000000000 -vt 0.046637099236 0.188832953572 0.000000000000 -vt 0.046065207571 0.182266756892 0.000000000000 -vt 0.047180842608 0.178921401501 0.000000000000 -vt 0.047978799790 0.180811345577 0.000000000000 -vt 0.042535897344 0.180803701282 0.000000000000 -vt 0.063310064375 0.188303396106 0.000000000000 -vt 0.064299397171 0.188258126378 0.000000000000 -vt 0.065667442977 0.187005370855 0.000000000000 -vt 0.067313097417 0.191977471113 0.000000000000 -vt 0.069538079202 0.197437480092 0.000000000000 -vt 0.067683927715 0.207009509206 0.000000000000 -vt 0.063888035715 0.210395619273 0.000000000000 -vt 0.073146872222 0.203862056136 0.000000000000 -vt 0.071523271501 0.214295744896 0.000000000000 -vt 0.073026858270 0.194442689419 0.000000000000 -vt 0.077325977385 0.201174154878 0.000000000000 -vt 0.081237144768 0.196533709764 0.000000000000 -vt 0.076219789684 0.190154388547 0.000000000000 -vt 0.081086061895 0.187698617578 0.000000000000 -vt 0.069806240499 0.189532741904 0.000000000000 -vt 0.071710377932 0.187683090568 0.000000000000 -vt 0.067168101668 0.185359716415 0.000000000000 -vt 0.069611258805 0.183986946940 0.000000000000 -vt 0.063944101334 0.182054877281 0.000000000000 -vt 0.063255354762 0.183039709926 0.000000000000 -vt 0.074488565326 0.222574487329 0.000000000000 -vt 0.069771796465 0.223591953516 0.000000000000 -vt 0.067730538547 0.216421216726 0.000000000000 -vt 0.060474004596 0.213022723794 0.000000000000 -vt 0.053378012031 0.208070665598 0.000000000000 -vt 0.057214211673 0.207134246826 0.000000000000 -vt 0.049100745469 0.211366251111 0.000000000000 -vt 0.064397566020 0.232721552253 0.000000000000 -vt 0.067054398358 0.233078405261 0.000000000000 -vt 0.070033647120 0.233986899257 0.000000000000 -vt 0.075478121638 0.233488187194 0.000000000000 -vt 0.081782467663 0.220023691654 0.000000000000 -vt 0.083951614797 0.230261281133 0.000000000000 -vt 0.084691703320 0.240565523505 0.000000000000 -vt 0.062245752662 0.239568278193 0.000000000000 -vt 0.061321716756 0.238784536719 0.000000000000 -vt 0.063168220222 0.233371362090 0.000000000000 -vt 0.063390895724 0.227339446545 0.000000000000 -vt 0.058965694159 0.225806355476 0.000000000000 -vt 0.050889376551 0.232737079263 0.000000000000 -vt 0.051590736955 0.236221358180 0.000000000000 -vt 0.050666701049 0.236511155963 0.000000000000 -vt 0.049805026501 0.232663914561 0.000000000000 -vt 0.049557130784 0.236889854074 0.000000000000 -vt 0.048572305590 0.232626542449 0.000000000000 -vt 0.052862185985 0.239495113492 0.000000000000 -vt 0.052227925509 0.240581259131 0.000000000000 -vt 0.055151116103 0.242463573813 0.000000000000 -vt 0.058518532664 0.242689415812 0.000000000000 -vt 0.058837804943 0.243750557303 0.000000000000 -vt 0.027835739776 0.198754191399 0.000000000000 -vt 0.102103173733 0.178665846586 0.000000000000 -vt 0.020530804992 0.243255212903 0.000000000000 -vt 0.017403624952 0.246614530683 0.000000000000 -vt 0.142661705613 0.167488694191 0.000000000000 -vt 0.138711810112 0.171222224832 0.000000000000 -vt 0.136936917901 0.169240176678 0.000000000000 -vt 0.140343055129 0.166225120425 0.000000000000 -vt 0.133923217654 0.174637824297 0.000000000000 -vt 0.132665947080 0.181584313512 0.000000000000 -vt 0.128641068935 0.183620840311 0.000000000000 -vt 0.132804647088 0.173296123743 0.000000000000 -vt 0.065053895116 0.163422614336 0.000000000000 -vt 0.063069596887 0.163681775331 0.000000000000 -vt 0.064668200910 0.167430609465 0.000000000000 -vt 0.063209198415 0.168160781264 0.000000000000 -vt 0.063756324351 0.165098443627 0.000000000000 -vt 0.065168723464 0.164823085070 0.000000000000 -vt 0.065913312137 0.169554486871 0.000000000000 -vt 0.062940359116 0.170286476612 0.000000000000 -vt 0.061481129378 0.167505130172 0.000000000000 -vt 0.060151811689 0.170392528176 0.000000000000 -vt 0.060107905418 0.172657802701 0.000000000000 -vt 0.057210605592 0.172009363770 0.000000000000 -vt 0.057532805949 0.170253381133 0.000000000000 -vt 0.063048884273 0.172646328807 0.000000000000 -vt 0.048934575170 0.168896585703 0.000000000000 -vt 0.049731176347 0.167191714048 0.000000000000 -vt 0.042593311518 0.164057999849 0.000000000000 -vt 0.043497528881 0.162384659052 0.000000000000 -vt 0.044287156314 0.160732463002 0.000000000000 -vt 0.033884081990 0.156096965075 0.000000000000 -vt 0.034770067781 0.153932109475 0.000000000000 -vt 0.036515694112 0.150483399630 0.000000000000 -vt 0.046103026718 0.155740767717 0.000000000000 -vt 0.039584781975 0.147428721189 0.000000000000 -vt 0.047613140196 0.151688650250 0.000000000000 -vt 0.043061178178 0.143725812435 0.000000000000 -vt 0.050141181797 0.149046242237 0.000000000000 -vt 0.047894362360 0.140243798494 0.000000000000 -vt 0.053615551442 0.146738171577 0.000000000000 -vt 0.053296964616 0.138070821762 0.000000000000 -vt 0.056939747185 0.144772797823 0.000000000000 -vt 0.060318645090 0.151515960693 0.000000000000 -vt 0.060732934624 0.143554925919 0.000000000000 -vt 0.062500409782 0.150664418936 0.000000000000 -vt 0.064538739622 0.156376838684 0.000000000000 -vt 0.063412509859 0.157254040241 0.000000000000 -vt 0.065951131284 0.161686450243 0.000000000000 -vt 0.064260445535 0.149016290903 0.000000000000 -vt 0.065228387713 0.155802473426 0.000000000000 -vt 0.067762054503 0.156014785171 0.000000000000 -vt 0.067490294576 0.161968335509 0.000000000000 -vt 0.068041928113 0.150318130851 0.000000000000 -vt 0.072004206479 0.152485474944 0.000000000000 -vt 0.068994782865 0.144661113620 0.000000000000 -vt 0.072091117501 0.145224899054 0.000000000000 -vt 0.075190380216 0.145809859037 0.000000000000 -vt 0.074453443289 0.154495447874 0.000000000000 -vt 0.078592248261 0.146916940808 0.000000000000 -vt 0.077539868653 0.155462488532 0.000000000000 -vt 0.083513915539 0.149794429541 0.000000000000 -vt 0.080134786665 0.156474098563 0.000000000000 -vt 0.076403960586 0.162150710821 0.000000000000 -vt 0.082034416497 0.157592907548 0.000000000000 -vt 0.077113650739 0.164572715759 0.000000000000 -vt 0.075192175806 0.166414484382 0.000000000000 -vt 0.073551476002 0.164994657040 0.000000000000 -vt 0.072395749390 0.167818546295 0.000000000000 -vt 0.086013361812 0.151608720422 0.000000000000 -vt 0.082925580442 0.138807758689 0.000000000000 -vt 0.088270992041 0.142190933228 0.000000000000 -vt 0.092381425202 0.144706368446 0.000000000000 -vt 0.033781412989 0.159828022122 0.000000000000 -vt 0.032040510327 0.158961847425 0.000000000000 -vt 0.032221313566 0.155238896608 0.000000000000 -vt 0.033128913492 0.152995914221 0.000000000000 -vt 0.034247931093 0.149646267295 0.000000000000 -vt 0.036089029163 0.146674454212 0.000000000000 -vt 0.039337117225 0.142542183399 0.000000000000 -vt 0.044477183372 0.138003721833 0.000000000000 -vt 0.051182758063 0.134617850184 0.000000000000 -vt 0.057887878269 0.132730364799 0.000000000000 -vt 0.058954205364 0.136307403445 0.000000000000 -vt 0.065197318792 0.135614156723 0.000000000000 -vt 0.065236717463 0.143920347095 0.000000000000 -vt 0.070889234543 0.135065451264 0.000000000000 -vt 0.075503565371 0.136102512479 0.000000000000 -vt 0.079501420259 0.136758163571 0.000000000000 -vt 0.080287218094 0.135892897844 0.000000000000 -vt 0.083798281848 0.137524142861 0.000000000000 -vt 0.089716039598 0.140691623092 0.000000000000 -vt 0.143560752273 0.209685027599 0.000000000000 -vt 0.135448858142 0.212041050196 0.000000000000 -vt 0.136980593204 0.209762930870 0.000000000000 -vt 0.149614498019 0.207925885916 0.000000000000 -vt 0.093936122954 0.143564611673 0.000000000000 -vt 0.131235316396 0.212935358286 0.000000000000 -vt 0.130912885070 0.210914373398 0.000000000000 -vt 0.130802333355 0.214139938354 0.000000000000 -vt 0.126496925950 0.214841082692 0.000000000000 -vt 0.127033010125 0.216304361820 0.000000000000 -vt 0.123436622322 0.220508232713 0.000000000000 -vt 0.122662074864 0.219344407320 0.000000000000 -vt 0.127302527428 0.217270508409 0.000000000000 -vt 0.124103523791 0.221681743860 0.000000000000 -vt 0.121738053858 0.226466968656 0.000000000000 -vt 0.119399368763 0.224682837725 0.000000000000 -vt 0.071574836969 0.132907792926 0.000000000000 -vt 0.076760835946 0.134390205145 0.000000000000 -vt 0.065341189504 0.132802188396 0.000000000000 -vt 0.115896403790 0.229595944285 0.000000000000 -vt 0.113967284560 0.229628607631 0.000000000000 -vt 0.118455067277 0.224354103208 0.000000000000 -vt 0.118444040418 0.231105849147 0.000000000000 -vt 0.116246968508 0.222922116518 0.000000000000 -vt 0.121256656945 0.217508718371 0.000000000000 -vt 0.113348767161 0.220198199153 0.000000000000 -vt 0.118779063225 0.214370504022 0.000000000000 -vt 0.109506264329 0.216642320156 0.000000000000 -vt 0.113111913204 0.210065305233 0.000000000000 -vt 0.106790229678 0.213530674577 0.000000000000 -vt 0.110659286380 0.209100753069 0.000000000000 -vt 0.105615362525 0.211812064052 0.000000000000 -vt 0.108720943332 0.208151713014 0.000000000000 -vt 0.104931339622 0.210859879851 0.000000000000 -vt 0.107262387872 0.207199767232 0.000000000000 -vt 0.104268938303 0.209731861949 0.000000000000 -vt 0.106411516666 0.206867888570 0.000000000000 -vt 0.099854543805 0.210535883904 0.000000000000 -vt 0.101010948420 0.212820082903 0.000000000000 -vt 0.101252302527 0.214150756598 0.000000000000 -vt 0.100541725755 0.216653347015 0.000000000000 -vt 0.109188362956 0.234976246953 0.000000000000 -vt 0.112999781966 0.234926506877 0.000000000000 -vt 0.116525933146 0.235893979669 0.000000000000 -vt 0.113097950816 0.239953324199 0.000000000000 -vt 0.109616830945 0.240531280637 0.000000000000 -vt 0.105305328965 0.241614267230 0.000000000000 -vt 0.103323295712 0.248255476356 0.000000000000 -vt 0.107525810599 0.246296599507 0.000000000000 -vt 0.106832340360 0.251131802797 0.000000000000 -vt 0.103008523583 0.253494113684 0.000000000000 -vt 0.111104875803 0.245297834277 0.000000000000 -vt 0.110048457980 0.249654576182 0.000000000000 -vt 0.096914246678 0.264147579670 0.000000000000 -vt 0.095100626349 0.260864347219 0.000000000000 -vt 0.103348061442 0.257600039244 0.000000000000 -vt 0.106801033020 0.254496067762 0.000000000000 -vt 0.169106185436 0.192728593946 0.000000000000 -vt 0.170338675380 0.195399373770 0.000000000000 -vt 0.099874362350 0.170928612351 0.000000000000 -vt 0.097011074424 0.169942215085 0.000000000000 -vt 0.095663733780 0.165094852448 0.000000000000 -vt 0.099198222160 0.165355354548 0.000000000000 -vt 0.093683719635 0.168949723244 0.000000000000 -vt 0.092458203435 0.165013566613 0.000000000000 -vt 0.090356379747 0.159508973360 0.000000000000 -vt 0.094260796905 0.160128593445 0.000000000000 -vt 0.099197551608 0.159526988864 0.000000000000 -vt 0.033023308963 0.163863465190 0.000000000000 -vt 0.037694837898 0.165538623929 0.000000000000 -vt 0.027775174007 0.166775852442 0.000000000000 -vt 0.088919214904 0.165129065514 0.000000000000 -vt 0.087757416070 0.161358624697 0.000000000000 -vt 0.041305195540 0.168003618717 0.000000000000 -vt 0.039413448423 0.169479295611 0.000000000000 -vt 0.041364412755 0.172144010663 0.000000000000 -vt 0.039971377701 0.172480389476 0.000000000000 -vt 0.038754414767 0.172880932689 0.000000000000 -vt 0.037746172398 0.170685455203 0.000000000000 -vt 0.041679184884 0.177758023143 0.000000000000 -vt 0.040490355343 0.177621126175 0.000000000000 -vt 0.038885232061 0.177430868149 0.000000000000 -vt 0.031558681279 0.181349694729 0.000000000000 -vt 0.032375093549 0.182451382279 0.000000000000 -vt 0.031321812421 0.183208808303 0.000000000000 -vt 0.029306901619 0.181765779853 0.000000000000 -vt 0.030110931024 0.184735804796 0.000000000000 -vt 0.026748467237 0.183448821306 0.000000000000 -vt 0.025492548943 0.179579749703 0.000000000000 -vt 0.025225963444 0.184383660555 0.000000000000 -vt 0.023586835712 0.180322989821 0.000000000000 -vt 0.023586835712 0.175274342299 0.000000000000 -vt 0.025453597307 0.175285145640 0.000000000000 -vt 0.025660742074 0.170873910189 0.000000000000 -vt 0.026788990945 0.172416672111 0.000000000000 -vt 0.028133621439 0.171821355820 0.000000000000 -vt 0.117384001613 0.164725363255 0.000000000000 -vt 0.112397044897 0.164127796888 0.000000000000 -vt 0.111941114068 0.159629434347 0.000000000000 -vt 0.116640761495 0.160034939647 0.000000000000 -vt 0.117678731680 0.167584165931 0.000000000000 -vt 0.121842063963 0.165160596371 0.000000000000 -vt 0.122367806733 0.167285159230 0.000000000000 -vt 0.123244337738 0.169767260551 0.000000000000 -vt 0.118570342660 0.170628488064 0.000000000000 -vt 0.076927222311 0.256597876549 0.000000000000 -vt 0.069735996425 0.256459414959 0.000000000000 -vt 0.126834645867 0.166902616620 0.000000000000 -vt 0.127785488963 0.169480189681 0.000000000000 -vt 0.062401559204 0.256990790367 0.000000000000 -vt 0.061513323337 0.259970039129 0.000000000000 -vt 0.055246125907 0.260234832764 0.000000000000 -vt 0.055534552783 0.256361246109 0.000000000000 -vt 0.055091898888 0.251717656851 0.000000000000 -vt 0.055174525827 0.262654781342 0.000000000000 -vt 0.131237342954 0.166645258665 0.000000000000 -vt 0.126206025481 0.164752155542 0.000000000000 -vt 0.130478784442 0.164564833045 0.000000000000 -vt 0.128323823214 0.157905861735 0.000000000000 -vt 0.124372817576 0.158351898193 0.000000000000 -vt 0.120934464037 0.159285396338 0.000000000000 -vt 0.031951349229 0.187119752169 0.000000000000 -vt 0.032728809863 0.185262441635 0.000000000000 -vt 0.035856213421 0.185055300593 0.000000000000 -vt 0.035672266036 0.187161847949 0.000000000000 -vt 0.028532592580 0.186527818441 0.000000000000 -vt 0.128893464804 0.155811250210 0.000000000000 -vt 0.132322803140 0.155696868896 0.000000000000 -vt 0.132445976138 0.157863765955 0.000000000000 -vt 0.134399861097 0.164290815592 0.000000000000 -vt 0.137302115560 0.158585160971 0.000000000000 -vt 0.138255640864 0.163551405072 0.000000000000 -vt 0.141750499606 0.159247785807 0.000000000000 -vt 0.142176494002 0.162172332406 0.000000000000 -vt 0.167481020093 0.185227319598 0.000000000000 -vt 0.170263931155 0.178922742605 0.000000000000 -vt 0.172615230083 0.181126117706 0.000000000000 -vt 0.170385509729 0.185613691807 0.000000000000 -vt 0.137086644769 0.156343296170 0.000000000000 -vt 0.141829982400 0.156543448567 0.000000000000 -vt 0.084312535822 0.167729392648 0.000000000000 -vt 0.084777034819 0.164774447680 0.000000000000 -vt 0.089359387755 0.168153122067 0.000000000000 -vt 0.136736750603 0.154593154788 0.000000000000 -vt 0.141693994403 0.153399839997 0.000000000000 -vt 0.084533862770 0.161654248834 0.000000000000 -vt 0.132128268480 0.155035361648 0.000000000000 -vt 0.168764844537 0.189312979579 0.000000000000 -vt 0.165124982595 0.185052827001 0.000000000000 -vt 0.167759761214 0.178524002433 0.000000000000 -vt 0.158733054996 0.192014843225 0.000000000000 -vt 0.156409904361 0.199086070061 0.000000000000 -vt 0.155019804835 0.205063492060 0.000000000000 -vt 0.157773226500 0.205484077334 0.000000000000 -vt 0.157165527344 0.207992762327 0.000000000000 -vt 0.154318660498 0.207045525312 0.000000000000 -vt 0.039390247315 0.183007746935 0.000000000000 -vt 0.109839722514 0.252810090780 0.000000000000 -vt 0.161794945598 0.206194669008 0.000000000000 -vt 0.160380065441 0.209382638335 0.000000000000 -vt 0.030997594818 0.172260865569 0.000000000000 -vt 0.028872353956 0.171737149358 0.000000000000 -vt 0.040024068207 0.239364311099 0.000000000000 -vt 0.041931357235 0.237304374576 0.000000000000 -vt 0.044145528227 0.240434691310 0.000000000000 -vt 0.045424859971 0.239937767386 0.000000000000 -vt 0.044002104551 0.236135587096 0.000000000000 -vt 0.100529327989 0.192775428295 0.000000000000 -vt 0.086145527661 0.185369163752 0.000000000000 -vt 0.074024297297 0.186244800687 0.000000000000 -vt 0.062078233808 0.164369389415 0.000000000000 -vt 0.030012762174 0.176220208406 0.000000000000 -vt 0.112108394504 0.179039835930 0.000000000000 -vt 0.112108394504 0.176560640335 0.000000000000 -vt 0.069380022585 0.168249264359 0.000000000000 -vt 0.065014265478 0.171704053879 0.000000000000 -vt 0.048454102129 0.180325239897 0.000000000000 -vt 0.146105453372 0.080951645970 0.000000000000 -vt 0.144684508443 0.079957589507 0.000000000000 -vt 0.149933993816 0.076390907168 0.000000000000 -vt 0.151316225529 0.078695371747 0.000000000000 -vt 0.153613030910 0.080021530390 0.000000000000 -vt 0.145809382200 0.082432046533 0.000000000000 -vt 0.143933385611 0.080989018083 0.000000000000 -vt 0.154818966985 0.082354143262 0.000000000000 -vt 0.145563289523 0.085070192814 0.000000000000 -vt 0.143352255225 0.081543803215 0.000000000000 -vt 0.144436612725 0.082785755396 0.000000000000 -vt 0.143652841449 0.084858089685 0.000000000000 -vt 0.146591797471 0.088287875056 0.000000000000 -vt 0.154597863555 0.085654467344 0.000000000000 -vt 0.153173521161 0.089168235660 0.000000000000 -vt 0.152664005756 0.094450607896 0.000000000000 -vt 0.140441447496 0.090233892202 0.000000000000 -vt 0.138348862529 0.080004423857 0.000000000000 -vt 0.139517411590 0.078812226653 0.000000000000 -vt 0.140799894929 0.078904315829 0.000000000000 -vt 0.140338554978 0.079870223999 0.000000000000 -vt 0.139646649361 0.078048720956 0.000000000000 -vt 0.142411112785 0.080079168081 0.000000000000 -vt 0.142763257027 0.078845098615 0.000000000000 -vt 0.144676625729 0.071552544832 0.000000000000 -vt 0.147951960564 0.073969364166 0.000000000000 -vt 0.165310516953 0.075303182006 0.000000000000 -vt 0.162680253386 0.081052973866 0.000000000000 -vt 0.159637063742 0.079843878746 0.000000000000 -vt 0.160642147064 0.076046422124 0.000000000000 -vt 0.138225704432 0.079229891300 0.000000000000 -vt 0.137284547091 0.079804927111 0.000000000000 -vt 0.137759849429 0.078385323286 0.000000000000 -vt 0.137967005372 0.069246500731 0.000000000000 -vt 0.141144156456 0.069925799966 0.000000000000 -vt 0.135236993432 0.081436410546 0.000000000000 -vt 0.135894671082 0.079535424709 0.000000000000 -vt 0.134577959776 0.080499768257 0.000000000000 -vt 0.135107755661 0.084568321705 0.000000000000 -vt 0.134055823088 0.084435924888 0.000000000000 -vt 0.133896872401 0.080932959914 0.000000000000 -vt 0.133128866553 0.069963172078 0.000000000000 -vt 0.135289907455 0.069450497627 0.000000000000 -vt 0.163844078779 0.085923969746 0.000000000000 -vt 0.162402868271 0.094224542379 0.000000000000 -vt 0.132371440530 0.082354143262 0.000000000000 -vt 0.128753200173 0.071022763848 0.000000000000 -vt 0.105484560132 0.044374290854 0.000000000000 -vt 0.104406282306 0.042068254203 0.000000000000 -vt 0.105255573988 0.042082216591 0.000000000000 -vt 0.106301188469 0.043263372034 0.000000000000 -vt 0.105341121554 0.039797786623 0.000000000000 -vt 0.107362121344 0.040538098663 0.000000000000 -vt 0.102971151471 0.044095326215 0.000000000000 -vt 0.109018579125 0.049298208207 0.000000000000 -vt 0.103879645467 0.048260468990 0.000000000000 -vt 0.106288582087 0.055648040026 0.000000000000 -vt 0.099673971534 0.057078447193 0.000000000000 -vt 0.097955361009 0.055400144309 0.000000000000 -vt 0.110525324941 0.046463962644 0.000000000000 -vt 0.102905854583 0.041538458318 0.000000000000 -vt 0.103917017579 0.039889875799 0.000000000000 -vt 0.118358477950 0.052561160177 0.000000000000 -vt 0.113901987672 0.058519665152 0.000000000000 -vt 0.118132635951 0.047917779535 0.000000000000 -vt 0.118020296097 0.061421241611 0.000000000000 -vt 0.122165165842 0.055722784251 0.000000000000 -vt 0.126941144466 0.044675100595 0.000000000000 -vt 0.128192335367 0.048273082823 0.000000000000 -vt 0.129756718874 0.051271017641 0.000000000000 -vt 0.104457631707 0.038520034403 0.000000000000 -vt 0.106935217977 0.039335094392 0.000000000000 -vt 0.110430315137 0.041719038039 0.000000000000 -vt 0.109509423375 0.038915853947 0.000000000000 -vt 0.103522777557 0.036517728120 0.000000000000 -vt 0.097110807896 0.038964264095 0.000000000000 -vt 0.099772140384 0.040999215096 0.000000000000 -vt 0.097977206111 0.041525851935 0.000000000000 -vt 0.096010699868 0.040015961975 0.000000000000 -vt 0.098011419177 0.043816577643 0.000000000000 -vt 0.095403008163 0.041276607662 0.000000000000 -vt 0.100398525596 0.044103201479 0.000000000000 -vt 0.092719830573 0.059615265578 0.000000000000 -vt 0.090432256460 0.055584091693 0.000000000000 -vt 0.103748843074 0.062081839889 0.000000000000 -vt 0.109088838100 0.036444552243 0.000000000000 -vt 0.116189554334 0.040374409407 0.000000000000 -vt 0.117214694619 0.043208893389 0.000000000000 -vt 0.100217953324 0.036773279309 0.000000000000 -vt 0.101216748357 0.031871203333 0.000000000000 -vt 0.129965662956 0.062457408756 0.000000000000 -vt 0.134202405810 0.063657253981 0.000000000000 -vt 0.126032650471 0.071523055434 0.000000000000 -vt 0.126584276557 0.061618920416 0.000000000000 -vt 0.126425325871 0.056240197271 0.000000000000 -vt 0.131047084928 0.056420769542 0.000000000000 -vt 0.136421307921 0.063021421432 0.000000000000 -vt 0.135489389300 0.060313250870 0.000000000000 -vt 0.137195616961 0.059194456786 0.000000000000 -vt 0.136729776859 0.057686138898 0.000000000000 -vt 0.156631231308 0.049092646688 0.000000000000 -vt 0.157220244408 0.050672557205 0.000000000000 -vt 0.155348747969 0.051238145679 0.000000000000 -vt 0.152967959642 0.049707990140 0.000000000000 -vt 0.072539396584 0.024206470698 0.000000000000 -vt 0.073009975255 0.022490788251 0.000000000000 -vt 0.074167720973 0.023411672562 0.000000000000 -vt 0.075313083827 0.024346742779 0.000000000000 -vt 0.078608684242 0.024770483375 0.000000000000 -vt 0.076113961637 0.022561032325 0.000000000000 -vt 0.074407733977 0.021668069065 0.000000000000 -vt 0.085832558572 0.034895710647 0.000000000000 -vt 0.088694959879 0.030288133770 0.000000000000 -vt 0.092079266906 0.032754708081 0.000000000000 -vt 0.090345121920 0.035805787891 0.000000000000 -vt 0.080766797066 0.037424653769 0.000000000000 -vt 0.083163343370 0.031321149319 0.000000000000 -vt 0.082765944302 0.039579611272 0.000000000000 -vt 0.075439170003 0.026426948607 0.000000000000 -vt 0.079141400754 0.028394807130 0.000000000000 -vt 0.065825045109 0.019637845457 0.000000000000 -vt 0.070792645216 0.020507168025 0.000000000000 -vt 0.069720685482 0.023076642305 0.000000000000 -vt 0.066453002393 0.021015118808 0.000000000000 -vt 0.074630416930 0.020555578172 0.000000000000 -vt 0.078393660486 0.021780196577 0.000000000000 -vt 0.118059247732 0.097139850259 0.000000000000 -vt 0.114740446210 0.098579719663 0.000000000000 -vt 0.114250972867 0.095418095589 0.000000000000 -vt 0.117238104343 0.094657748938 0.000000000000 -vt 0.109638676047 0.091790616512 0.000000000000 -vt 0.115868493915 0.090512856841 0.000000000000 -vt 0.106643870473 0.097877010703 0.000000000000 -vt 0.080275960267 0.020345281810 0.000000000000 -vt 0.084542199969 0.020472947508 0.000000000000 -vt 0.082198783755 0.026802506298 0.000000000000 -vt 0.087908044457 0.024324897677 0.000000000000 -vt 0.082033514977 0.045575719327 0.000000000000 -vt 0.083040185273 0.050441998988 0.000000000000 -vt 0.079672768712 0.048204403371 0.000000000000 -vt 0.080490976572 0.044366639107 0.000000000000 -vt 0.076486371458 0.049105029553 0.000000000000 -vt 0.078130230308 0.043149676174 0.000000000000 -vt 0.081851139665 0.052377205342 0.000000000000 -vt 0.066788040102 0.023179534823 0.000000000000 -vt 0.064600206912 0.023336920887 0.000000000000 -vt 0.064584665000 0.022389467806 0.000000000000 -vt 0.066289320588 0.022115226835 0.000000000000 -vt 0.060966644436 0.023584589362 0.000000000000 -vt 0.061784636229 0.022029668093 0.000000000000 -vt 0.063617177308 0.021110359579 0.000000000000 -vt 0.091050982475 0.028800085187 0.000000000000 -vt 0.094201579690 0.030098102987 0.000000000000 -vt 0.090151712298 0.025628998876 0.000000000000 -vt 0.093743383884 0.027991328388 0.000000000000 -vt 0.066948570311 0.027383632958 0.000000000000 -vt 0.060868475586 0.030944012105 0.000000000000 -vt 0.062462348491 0.027807373554 0.000000000000 -vt 0.066029265523 0.025897156447 0.000000000000 -vt 0.059814978391 0.026431452483 0.000000000000 -vt 0.064851254225 0.024653624743 0.000000000000 -vt 0.054694723338 0.030345775187 0.000000000000 -vt 0.047921154648 0.032958924770 0.000000000000 -vt 0.043463084847 0.030261565000 0.000000000000 -vt 0.047107893974 0.029183298349 0.000000000000 -vt 0.050095032901 0.030151013285 0.000000000000 -vt 0.047431897372 0.026514083147 0.000000000000 -vt 0.050590369850 0.027707632631 0.000000000000 -vt 0.042810361832 0.027617346495 0.000000000000 -vt 0.047869820148 0.042448315769 0.000000000000 -vt 0.045954655856 0.041697423905 0.000000000000 -vt 0.046084117144 0.036520879716 0.000000000000 -vt 0.049386020750 0.038101017475 0.000000000000 -vt 0.044854771346 0.041064735502 0.000000000000 -vt 0.043885473162 0.036986950785 0.000000000000 -vt 0.051757570356 0.034210111946 0.000000000000 -vt 0.154328122735 0.043087299913 0.000000000000 -vt 0.154911056161 0.037254884839 0.000000000000 -vt 0.167563647032 0.034898862243 0.000000000000 -vt 0.161921262741 0.041362386197 0.000000000000 -vt 0.153502255678 0.030707374215 0.000000000000 -vt 0.163250565529 0.027692098171 0.000000000000 -vt 0.103868618608 0.102910131216 0.000000000000 -vt 0.111994698644 0.103447571397 0.000000000000 -vt 0.106992870569 0.109234735370 0.000000000000 -vt 0.101400464773 0.108030393720 0.000000000000 -vt 0.096481271088 0.122771069407 0.000000000000 -vt 0.089952446520 0.124826297164 0.000000000000 -vt 0.088087268174 0.119303897023 0.000000000000 -vt 0.094165779650 0.117781624198 0.000000000000 -vt 0.070482604206 0.058522816747 0.000000000000 -vt 0.077887058258 0.065487995744 0.000000000000 -vt 0.071217961609 0.071155369282 0.000000000000 -vt 0.066381409764 0.064373925328 0.000000000000 -vt 0.070337608457 0.087279632688 0.000000000000 -vt 0.063515856862 0.072370767593 0.000000000000 -vt 0.079217955470 0.082213863730 0.000000000000 -vt 0.050732221454 0.021630693227 0.000000000000 -vt 0.048374619335 0.020630329847 0.000000000000 -vt 0.048564653844 0.016099080443 0.000000000000 -vt 0.051573622972 0.018779102713 0.000000000000 -vt 0.045837800950 0.018292993307 0.000000000000 -vt 0.046268071979 0.015899594873 0.000000000000 -vt 0.051961567253 0.016921799630 0.000000000000 -vt 0.048754904419 0.013884905726 0.000000000000 -vt 0.026494264603 0.028064500540 0.000000000000 -vt 0.026460040361 0.028243724257 0.000000000000 -vt 0.026340033859 0.028218735009 0.000000000000 -vt 0.026315040886 0.028072383255 0.000000000000 -vt 0.026271361858 0.028111334890 0.000000000000 -vt 0.026316616684 0.028287407011 0.000000000000 -vt 0.026220027357 0.028083190322 0.000000000000 -vt 0.025830507278 0.027961608022 0.000000000000 -vt 0.026793498546 0.027743656188 0.000000000000 -vt 0.022305700928 0.037761259824 0.000000000000 -vt 0.020612087101 0.038116555661 0.000000000000 -vt 0.018779549748 0.032605204731 0.000000000000 -vt 0.019568044692 0.032413598150 0.000000000000 -vt 0.026293199509 0.029374904931 0.000000000000 -vt 0.026729550213 0.056939747185 0.000000000000 -vt 0.025282029063 0.059646341950 0.000000000000 -vt 0.023371588439 0.056319449097 0.000000000000 -vt 0.024051103741 0.054049205035 0.000000000000 -vt 0.023613180965 0.061910506338 0.000000000000 -vt 0.020778700709 0.056646820158 0.000000000000 -vt 0.024753816426 0.028824850917 0.000000000000 -vt 0.024046380073 0.029639910907 0.000000000000 -vt 0.021925639361 0.027996055782 0.000000000000 -vt 0.019233010709 0.029932837933 0.000000000000 -vt 0.020827110857 0.032996300608 0.000000000000 -vt 0.018511611968 0.030085492879 0.000000000000 -vt 0.018042616546 0.028514813632 0.000000000000 -vt 0.018695343286 0.028449516743 0.000000000000 -vt 0.018340270966 0.027692098171 0.000000000000 -vt 0.019049059600 0.027235481888 0.000000000000 -vt 0.018784277141 0.027503643185 0.000000000000 -vt 0.018855873495 0.026894371957 0.000000000000 -vt 0.019962288439 0.026958312839 0.000000000000 -vt 0.019748840481 0.027567584068 0.000000000000 -vt 0.160484761000 0.020033445209 0.000000000000 -vt 0.147482961416 0.021641500294 0.000000000000 -vt 0.154410749674 0.015146899968 0.000000000000 -vt 0.161012977362 0.008924962953 0.000000000000 -vt 0.166393518448 0.013308282942 0.000000000000 -vt 0.166352987289 0.025851901621 0.000000000000 -vt 0.166651993990 0.020915377885 0.000000000000 -vt 0.170089438558 0.015492964536 0.000000000000 -vt 0.019588306546 0.027807373554 0.000000000000 -vt 0.019134845585 0.027851056308 0.000000000000 -vt 0.019064817578 0.028270293027 0.000000000000 -vt 0.038729425520 0.090958446264 0.000000000000 -vt 0.036177065223 0.089736983180 0.000000000000 -vt 0.038676287979 0.085981622338 0.000000000000 -vt 0.040239315480 0.089066922665 0.000000000000 -vt 0.042406659573 0.093741580844 0.000000000000 -vt 0.040854658931 0.094687461853 0.000000000000 -vt 0.037749316543 0.094786986709 0.000000000000 -vt 0.027898332104 0.053784426302 0.000000000000 -vt 0.031369995326 0.055613588542 0.000000000000 -vt 0.030157541856 0.062759563327 0.000000000000 -vt 0.033898938447 0.060758832842 0.000000000000 -vt 0.032940682024 0.067951634526 0.000000000000 -vt 0.027729919180 0.065882235765 0.000000000000 -vt 0.093380436301 0.131579592824 0.000000000000 -vt 0.101789981127 0.126331463456 0.000000000000 -vt 0.037756975740 0.051755558699 0.000000000000 -vt 0.035693880171 0.048643913120 0.000000000000 -vt 0.039868485183 0.048481795937 0.000000000000 -vt 0.041482623667 0.049996417016 0.000000000000 -vt 0.042654555291 0.045740988106 0.000000000000 -vt 0.045040067285 0.046664800495 0.000000000000 -vt 0.036985594779 0.046448197216 0.000000000000 -vt 0.034682709724 0.086651682854 0.000000000000 -vt 0.030933646485 0.089648038149 0.000000000000 -vt 0.029764866456 0.085144937038 0.000000000000 -vt 0.031592678279 0.081364586949 0.000000000000 -vt 0.034569006413 0.082026988268 0.000000000000 -vt 0.032102201134 0.080329999328 0.000000000000 -vt 0.028744241223 0.051196273416 0.000000000000 -vt 0.030639147386 0.050709929317 0.000000000000 -vt 0.036769222468 0.056941326708 0.000000000000 -vt 0.034461375326 0.053469661623 0.000000000000 -vt 0.041688408703 0.088625833392 0.000000000000 -vt 0.044041287154 0.087036460638 0.000000000000 -vt 0.042447183281 0.080775573850 0.000000000000 -vt 0.049191255122 0.076541990042 0.000000000000 -vt 0.046822618693 0.081983312964 0.000000000000 -vt 0.044226806611 0.072259977460 0.000000000000 -vt 0.046158861369 0.086456924677 0.000000000000 -vt 0.027991769835 0.075538471341 0.000000000000 -vt 0.027059858665 0.080196022987 0.000000000000 -vt 0.025024902076 0.073586151004 0.000000000000 -vt 0.026086058468 0.070214003325 0.000000000000 -vt 0.026441354305 0.067705318332 0.000000000000 -vt 0.028167841956 0.071457535028 0.000000000000 -vt 0.028880013153 0.073195055127 0.000000000000 -vt 0.030567547306 0.076351955533 0.000000000000 -vt 0.030551789328 0.069745004177 0.000000000000 -vt 0.029026357457 0.069470763206 0.000000000000 -vt 0.030614150688 0.072523415089 0.000000000000 -vt 0.043936815113 0.092527776957 0.000000000000 -vt 0.046364661306 0.097238019109 0.000000000000 -vt 0.044538419694 0.100720718503 0.000000000000 -vt 0.042931716889 0.101345524192 0.000000000000 -vt 0.048817273229 0.100172251463 0.000000000000 -vt 0.048457246274 0.102738559246 0.000000000000 -vt 0.137558788061 0.098332047462 0.000000000000 -vt 0.139102905989 0.097345650196 0.000000000000 -vt 0.138733655214 0.098258882761 0.000000000000 -vt 0.137797236443 0.098970815539 0.000000000000 -vt 0.138197556138 0.099481925368 0.000000000000 -vt 0.139004737139 0.098487854004 0.000000000000 -vt 0.139805614948 0.097956493497 0.000000000000 -vt 0.139377146959 0.099524021149 0.000000000000 -vt 0.050679307431 0.107523784041 0.000000000000 -vt 0.054135438055 0.112569287419 0.000000000000 -vt 0.050330314785 0.114288136363 0.000000000000 -vt 0.047148425132 0.107650101185 0.000000000000 -vt 0.050964351743 0.104889020324 0.000000000000 -vt 0.053239319474 0.103625223041 0.000000000000 -vt 0.055646907538 0.107062682509 0.000000000000 -vt 0.058104019612 0.112983807921 0.000000000000 -vt 0.140801474452 0.096658468246 0.000000000000 -vt 0.138233363628 0.096205011010 0.000000000000 -vt 0.140344858170 0.095949456096 0.000000000000 -vt 0.142007410526 0.098663926125 0.000000000000 -vt 0.140017718077 0.100223585963 0.000000000000 -vt 0.141385748982 0.098199442029 0.000000000000 -vt 0.141155198216 0.097431436181 0.000000000000 -vt 0.133312597871 0.105359598994 0.000000000000 -vt 0.132514864206 0.104310825467 0.000000000000 -vt 0.134183719754 0.106383368373 0.000000000000 -vt 0.140815436840 0.100723877549 0.000000000000 -vt 0.141863986850 0.099782720208 0.000000000000 -vt 0.142421916127 0.100219070911 0.000000000000 -vt 0.142892494798 0.098935022950 0.000000000000 -vt 0.050447177142 0.103112548590 0.000000000000 -vt 0.052483703941 0.102864876390 0.000000000000 -vt 0.144728183746 0.104067876935 0.000000000000 -vt 0.144224733114 0.102514311671 0.000000000000 -vt 0.145186141133 0.101699247956 0.000000000000 -vt 0.146470203996 0.103851273656 0.000000000000 -vt 0.143584400415 0.101527899504 0.000000000000 -vt 0.144430533051 0.100561767817 0.000000000000 -vt 0.141550794244 0.101287886500 0.000000000000 -vt 0.061257999390 0.112659797072 0.000000000000 -vt 0.065134719014 0.115944370627 0.000000000000 -vt 0.061873342842 0.123118489981 0.000000000000 -vt 0.056573864073 0.121722295880 0.000000000000 -vt 0.067445486784 0.110573291779 0.000000000000 -vt 0.063640370965 0.107372716069 0.000000000000 -vt 0.069648854434 0.106004670262 0.000000000000 -vt 0.066685140133 0.100748866796 0.000000000000 -vt 0.072863399982 0.099591121078 0.000000000000 -vt 0.079629309475 0.095017760992 0.000000000000 -vt 0.063420616090 0.097499877214 0.000000000000 -vt 0.064508341253 0.086475610733 0.000000000000 -vt 0.143850758672 0.104326352477 0.000000000000 -vt 0.143411472440 0.103562861681 0.000000000000 -vt 0.056262250990 0.094160601497 0.000000000000 -vt 0.056469622999 0.096354737878 0.000000000000 -vt 0.051992859691 0.094852507114 0.000000000000 -vt 0.052877943963 0.092719376087 0.000000000000 -vt 0.057681854814 0.098607867956 0.000000000000 -vt 0.053764607757 0.098246261477 0.000000000000 -vt 0.051455195993 0.098188623786 0.000000000000 -vt 0.049526061863 0.095104902983 0.000000000000 -vt 0.050771173090 0.101749226451 0.000000000000 -vt 0.052848231047 0.102208778262 0.000000000000 -vt 0.051238592714 0.100907593966 0.000000000000 -vt 0.052483703941 0.100563332438 0.000000000000 -vt 0.057426307350 0.106243103743 0.000000000000 -vt 0.059230696410 0.102589055896 0.000000000000 -vt 0.054297324270 0.103461548686 0.000000000000 -vt 0.054697874933 0.101320534945 0.000000000000 -vt 0.052963506430 0.122161805630 0.000000000000 -vt 0.052379231900 0.131099566817 0.000000000000 -vt 0.048094075173 0.130477920175 0.000000000000 -vt 0.046760257334 0.130856394768 0.000000000000 -vt 0.050066884607 0.122128933668 0.000000000000 -vt 0.156333580613 0.006823139265 0.000000000000 -vt 0.149899765849 0.012613456696 0.000000000000 -vt 0.148388311267 0.011923130602 0.000000000000 -vt 0.154814451933 0.007212657481 0.000000000000 -vt 0.143572017550 0.018695119768 0.000000000000 -vt 0.142008990049 0.017630811781 0.000000000000 -vt 0.141720786691 0.017121285200 0.000000000000 -vt 0.147525057197 0.011396490037 0.000000000000 -vt 0.137385874987 0.025342378765 0.000000000000 -vt 0.135559633374 0.023885395378 0.000000000000 -vt 0.134478226304 0.023776423186 0.000000000000 -vt 0.129616662860 0.030687112361 0.000000000000 -vt 0.127787277102 0.029326722026 0.000000000000 -vt 0.122677840292 0.035132572055 0.000000000000 -vt 0.121847249568 0.031333755702 0.000000000000 -vt 0.121459312737 0.026788320392 0.000000000000 -vt 0.126799300313 0.025711629540 0.000000000000 -vt 0.116022720933 0.031031373888 0.000000000000 -vt 0.116498008370 0.026107456535 0.000000000000 -vt 0.109646543860 0.029707010835 0.000000000000 -vt 0.110188722610 0.025318961591 0.000000000000 -vt 0.102204486728 0.027808953077 0.000000000000 -vt 0.102347925305 0.024181474000 0.000000000000 -vt 0.120979495347 0.024089615792 0.000000000000 -vt 0.116271957755 0.023522447795 0.000000000000 -vt 0.110184207559 0.022347588092 0.000000000000 -vt 0.102416366339 0.022239964455 0.000000000000 -vt 0.133086755872 0.021283280104 0.000000000000 -vt 0.125700771809 0.022800825536 0.000000000000 -vt 0.131805852056 0.019698411226 0.000000000000 -vt 0.140229582787 0.014688935131 0.000000000000 -vt 0.145475924015 0.010294806212 0.000000000000 -vt 0.152886912227 0.006676563993 0.000000000000 -vt 0.047576893121 0.122769504786 0.000000000000 -vt 0.044946629554 0.130904808640 0.000000000000 -vt 0.047352414578 0.114989265800 0.000000000000 -vt 0.044636588544 0.108223572373 0.000000000000 -vt 0.040943596512 0.101545020938 0.000000000000 -vt 0.041778694838 0.117057085037 0.000000000000 -vt 0.038933407515 0.109159991145 0.000000000000 -vt 0.042194779962 0.125491634011 0.000000000000 -vt 0.042258728296 0.131637245417 0.000000000000 -vt 0.150459289551 0.005439335480 0.000000000000 -vt 0.147406622767 0.004468692467 0.000000000000 -vt 0.143596783280 0.008389092982 0.000000000000 -vt 0.139240026474 0.012483991683 0.000000000000 -vt 0.039006810635 0.131603017449 0.000000000000 -vt 0.039525572211 0.125474527478 0.000000000000 -vt 0.038843121380 0.117890611291 0.000000000000 -vt 0.036237854511 0.109794244170 0.000000000000 -vt 0.035265412182 0.101655572653 0.000000000000 -vt 0.032339062542 0.095125168562 0.000000000000 -vt 0.030368058011 0.090082809329 0.000000000000 -vt 0.031399492174 0.094974085689 0.000000000000 -vt 0.033498387784 0.101733475924 0.000000000000 -vt 0.028639992699 0.086095318198 0.000000000000 -vt 0.025852348655 0.081437990069 0.000000000000 -vt 0.022753085941 0.076138511300 0.000000000000 -vt 0.023653708398 0.075184747577 0.000000000000 -vt 0.020847376436 0.069434955716 0.000000000000 -vt 0.021620105952 0.067643180490 0.000000000000 -vt 0.023307643831 0.064264953136 0.000000000000 -vt 0.017721544951 0.061841826886 0.000000000000 -vt 0.020375225693 0.059083905071 0.000000000000 -vt 0.053222205490 0.012929573655 0.000000000000 -vt 0.050235074013 0.010815139860 0.000000000000 -vt 0.056510146707 0.014634449035 0.000000000000 -vt 0.054663654417 0.018612489104 0.000000000000 -vt 0.060259204358 0.016382552683 0.000000000000 -vt 0.059049900621 0.020086579025 0.000000000000 -vt 0.058030847460 0.021122742444 0.000000000000 -vt 0.054247569293 0.019831027836 0.000000000000 -vt 0.056996259838 0.023039262742 0.000000000000 -vt 0.053340639919 0.022660780698 0.000000000000 -vt 0.055484797806 0.025647688657 0.000000000000 -vt 0.052176591009 0.025117896497 0.000000000000 -vt 0.049496565014 0.024186205119 0.000000000000 -vt 0.045745935291 0.023629847914 0.000000000000 -vt 0.047365020961 0.022347588092 0.000000000000 -vt 0.044394996017 0.020589802414 0.000000000000 -vt 0.045242708176 0.019883941859 0.000000000000 -vt 0.024909622967 0.052349288017 0.000000000000 -vt 0.025043588132 0.050973366946 0.000000000000 -vt 0.027739373967 0.047426950186 0.000000000000 -vt 0.024479579180 0.048439692706 0.000000000000 -vt 0.042350593954 0.024865496904 0.000000000000 -vt 0.042051356286 0.021227214485 0.000000000000 -vt 0.036529209465 0.022210467607 0.000000000000 -vt 0.037055846304 0.026330355555 0.000000000000 -vt 0.036963980645 0.028058420867 0.000000000000 -vt 0.031510043889 0.025784809142 0.000000000000 -vt 0.031432140619 0.027294699103 0.000000000000 -vt 0.036716084927 0.029509097338 0.000000000000 -vt 0.031419757754 0.028624013066 0.000000000000 -vt 0.027148788795 0.027899462730 0.000000000000 -vt 0.027295140550 0.028648782521 0.000000000000 -vt 0.036427881569 0.031031373888 0.000000000000 -vt 0.031274754554 0.029678862542 0.000000000000 -vt 0.027111416683 0.029242511839 0.000000000000 -vt 0.030949188396 0.030895829201 0.000000000000 -vt 0.035843607038 0.032156471163 0.000000000000 -vt 0.020707104355 0.028784547001 0.000000000000 -vt 0.022812303156 0.031886737794 0.000000000000 -vt 0.020281784236 0.029052484781 0.000000000000 -vt 0.023458946496 0.031434852630 0.000000000000 -vt 0.022109370679 0.032270174474 0.000000000000 -vt 0.020171005279 0.029769152403 0.000000000000 -vt 0.021504826844 0.032532032579 0.000000000000 -vt 0.025012519211 0.036299776286 0.000000000000 -vt 0.024063490331 0.036756169051 0.000000000000 -vt 0.023340519518 0.037314102054 0.000000000000 -vt 0.027483826503 0.041390310973 0.000000000000 -vt 0.026430319995 0.041890602559 0.000000000000 -vt 0.025338094682 0.042350146919 0.000000000000 -vt 0.029316132888 0.046764533967 0.000000000000 -vt 0.022701527923 0.043102841824 0.000000000000 -vt 0.030600195751 0.046093124896 0.000000000000 -vt 0.032929647714 0.049832727760 0.000000000000 -vt 0.031767170876 0.045388620347 0.000000000000 -vt 0.029398767278 0.040288627148 0.000000000000 -vt 0.032870430499 0.044547211379 0.000000000000 -vt 0.028457617387 0.040873128921 0.000000000000 -vt 0.030336765572 0.039641980082 0.000000000000 -vt 0.033799197525 0.043578144163 0.000000000000 -vt 0.037752252072 0.045114379376 0.000000000000 -vt 0.041783425957 0.044548790902 0.000000000000 -vt 0.025857076049 0.035843163729 0.000000000000 -vt 0.026734281331 0.035361554474 0.000000000000 -vt 0.041914243251 0.032859180123 0.000000000000 -vt 0.040793869644 0.033786371350 0.000000000000 -vt 0.030941305682 0.023799840361 0.000000000000 -vt 0.057466831058 0.013119827956 0.000000000000 -vt 0.054774206132 0.010378789157 0.000000000000 -vt 0.051085937768 0.008826795965 0.000000000000 -vt 0.051754426211 0.007754832506 0.000000000000 -vt 0.088373884559 0.020429264754 0.000000000000 -vt 0.088517308235 0.019399408251 0.000000000000 -vt 0.090854644775 0.019729707390 0.000000000000 -vt 0.090842038393 0.020712960511 0.000000000000 -vt 0.094946391881 0.022414457053 0.000000000000 -vt 0.095091395080 0.020460564643 0.000000000000 -vt 0.094299748540 0.025574509054 0.000000000000 -vt 0.090377770364 0.023751430213 0.000000000000 -vt 0.109390988946 0.033906377852 0.000000000000 -vt 0.101716801524 0.030102606863 0.000000000000 -vt 0.116005614400 0.037482291460 0.000000000000 -vt 0.123491324484 0.037183284760 0.000000000000 -vt 0.125074386597 0.041345056146 0.000000000000 -vt 0.130738392472 0.031681168824 0.000000000000 -vt 0.133287593722 0.035913188010 0.000000000000 -vt 0.135103031993 0.039498783648 0.000000000000 -vt 0.140455409884 0.028768789023 0.000000000000 -vt 0.144802927971 0.035279151052 0.000000000000 -vt 0.146699190140 0.040768656880 0.000000000000 -vt 0.137726977468 0.044129770249 0.000000000000 -vt 0.147504791617 0.045349668711 0.000000000000 -vt 0.138828665018 0.047825690359 0.000000000000 -vt 0.146984457970 0.048285465688 0.000000000000 -vt 0.138644710183 0.050088282675 0.000000000000 -vt 0.129806697369 0.052833821625 0.000000000000 -vt 0.169347777963 0.087803125381 0.000000000000 -vt 0.166878044605 0.096072614193 0.000000000000 -vt 0.123137615621 0.057648766786 0.000000000000 -vt 0.120253384113 0.063675940037 0.000000000000 -vt 0.115961924195 0.067340791225 0.000000000000 -vt 0.118732467294 0.069205984473 0.000000000000 -vt 0.118006333709 0.075494781137 0.000000000000 -vt 0.115131542087 0.074644148350 0.000000000000 -vt 0.109959736466 0.072775810957 0.000000000000 -vt 0.111552253366 0.064712107182 0.000000000000 -vt 0.102553710341 0.070056840777 0.000000000000 -vt 0.109609171748 0.082248091698 0.000000000000 -vt 0.100861445069 0.081328779459 0.000000000000 -vt 0.090299867094 0.080892428756 0.000000000000 -vt 0.091694474220 0.066030398011 0.000000000000 -vt 0.079119786620 0.055774118751 0.000000000000 -vt 0.072969444096 0.053520996124 0.000000000000 -vt 0.071013972163 0.047288250178 0.000000000000 -vt 0.068132661283 0.051054421812 0.000000000000 -vt 0.065332636237 0.054049205035 0.000000000000 -vt 0.061893608421 0.046331342310 0.000000000000 -vt 0.058749314398 0.049416642636 0.000000000000 -vt 0.061658326536 0.058715995401 0.000000000000 -vt 0.055071856827 0.053793657571 0.000000000000 -vt 0.052937161177 0.044756155461 0.000000000000 -vt 0.049072828144 0.049751672894 0.000000000000 -vt 0.058147702366 0.064059153199 0.000000000000 -vt 0.052524227649 0.058092769235 0.000000000000 -vt 0.045923579484 0.053873132914 0.000000000000 -vt 0.046409692615 0.047785166651 0.000000000000 -vt 0.043375950307 0.051665265113 0.000000000000 -vt 0.050428483635 0.061640765518 0.000000000000 -vt 0.043210681528 0.056986581534 0.000000000000 -vt 0.040099035949 0.054348435253 0.000000000000 -vt 0.039909008890 0.059638466686 0.000000000000 -vt 0.047191876918 0.065960139036 0.000000000000 -vt 0.038101460785 0.065509825945 0.000000000000 -vt 0.035400953144 0.074902862310 0.000000000000 -vt 0.055581387132 0.067733466625 0.000000000000 -vt 0.052806120366 0.071872040629 0.000000000000 -vt 0.060378994793 0.075755074620 0.000000000000 -vt 0.058071371168 0.078776419163 0.000000000000 -vt 0.055618759245 0.080065205693 0.000000000000 -vt 0.052734520286 0.079525962472 0.000000000000 -vt 0.053052444011 0.081367731094 0.000000000000 -vt 0.050789859146 0.083292141557 0.000000000000 -vt 0.049432624131 0.082779452205 0.000000000000 -vt 0.049594733864 0.085844501853 0.000000000000 -vt 0.048008512706 0.086075052619 0.000000000000 -vt 0.050535883754 0.089364573359 0.000000000000 -vt 0.049192603678 0.090299412608 0.000000000000 -vt 0.047464769334 0.090754449368 0.000000000000 -vt 0.045393791050 0.091461896896 0.000000000000 -vt 0.047896388918 0.095926046371 0.000000000000 -vt 0.049828443676 0.098826035857 0.000000000000 -vt 0.057419996709 0.081000059843 0.000000000000 -vt 0.060966644436 0.087109863758 0.000000000000 -vt 0.059794712812 0.087519645691 0.000000000000 -vt 0.060287129134 0.094168484211 0.000000000000 -vt 0.059352282435 0.093295782804 0.000000000000 -vt 0.062393907458 0.086673513055 0.000000000000 -vt 0.061801750213 0.096052348614 0.000000000000 -vt 0.049892392009 0.042724128813 0.000000000000 -vt 0.052075494081 0.038878478110 0.000000000000 -vt 0.055960100144 0.041236083955 0.000000000000 -vt 0.055889848620 0.035288382322 0.000000000000 -vt 0.060157891363 0.037993393838 0.000000000000 -vt 0.065116032958 0.042724128813 0.000000000000 -vt 0.064106442034 0.032941814512 0.000000000000 -vt 0.068679787219 0.036249794066 0.000000000000 -vt 0.074156686664 0.040447585285 0.000000000000 -vt 0.073277905583 0.031112428755 0.000000000000 -vt 0.077270135283 0.034540414810 0.000000000000 -vt 0.072071976960 0.025901664048 0.000000000000 -vt 0.069379344583 0.029083553702 0.000000000000 -vt 0.069463558495 0.025113392621 0.000000000000 -vt 0.067841313779 0.024271763861 0.000000000000 -vt 0.099162861705 0.091220304370 0.000000000000 -vt 0.089000269771 0.092127218843 0.000000000000 -vt 0.097078159451 0.097934648395 0.000000000000 -vt 0.087571434677 0.099022373557 0.000000000000 -vt 0.079772509634 0.101554468274 0.000000000000 -vt 0.086257882416 0.102638825774 0.000000000000 -vt 0.079043231905 0.105086937547 0.000000000000 -vt 0.075504690409 0.108024075627 0.000000000000 -vt 0.074613302946 0.105156958103 0.000000000000 -vt 0.073125250638 0.110627785325 0.000000000000 -vt 0.071593523026 0.108968392015 0.000000000000 -vt 0.070599466562 0.114607393742 0.000000000000 -vt 0.069200120866 0.112909048796 0.000000000000 -vt 0.067964471877 0.119090452790 0.000000000000 -vt 0.066672757268 0.117705300450 0.000000000000 -vt 0.065623983741 0.124006733298 0.000000000000 -vt 0.064179614186 0.123651430011 0.000000000000 -vt 0.064288586378 0.130211338401 0.000000000000 -vt 0.062253635377 0.130234748125 0.000000000000 -vt 0.058482732624 0.130786374211 0.000000000000 -vt 0.122141756117 0.148486047983 0.000000000000 -vt 0.127875998616 0.147998362780 0.000000000000 -vt 0.127665698528 0.150818660855 0.000000000000 -vt 0.122073300183 0.151981130242 0.000000000000 -vt 0.133205190301 0.149006605148 0.000000000000 -vt 0.133069649339 0.151248708367 0.000000000000 -vt 0.172021716833 0.016547817737 0.000000000000 -vt 0.169503584504 0.022040475160 0.000000000000 -vt 0.137767508626 0.149533241987 0.000000000000 -vt 0.137985691428 0.152411177754 0.000000000000 -vt 0.168945640326 0.028130020946 0.000000000000 -vt 0.129772469401 0.142226740718 0.000000000000 -vt 0.133960813284 0.145277813077 0.000000000000 -vt 0.137136399746 0.143440544605 0.000000000000 -vt 0.135624930263 0.133524268866 0.000000000000 -vt 0.137717753649 0.134089857340 0.000000000000 -vt 0.109607592225 0.111450493336 0.000000000000 -vt 0.100973561406 0.115215316415 0.000000000000 -vt 0.100111901760 0.112997993827 0.000000000000 -vt 0.109063848853 0.109449759126 0.000000000000 -vt 0.094076842070 0.114406555891 0.000000000000 -vt 0.109662085772 0.113127216697 0.000000000000 -vt 0.101924166083 0.117096036673 0.000000000000 -vt 0.118073418736 0.107520863414 0.000000000000 -vt 0.118896141648 0.109094470739 0.000000000000 -vt 0.119979143143 0.110803857446 0.000000000000 -vt 0.109627857804 0.115891456604 0.000000000000 -vt 0.121512211859 0.112745359540 0.000000000000 -vt 0.113743022084 0.119411528111 0.000000000000 -vt 0.123366601765 0.114860013127 0.000000000000 -vt 0.116215899587 0.122188150883 0.000000000000 -vt 0.104867622256 0.130242630839 0.000000000000 -vt 0.095320373774 0.140049934387 0.000000000000 -vt 0.118313208222 0.124379143119 0.000000000000 -vt 0.107863992453 0.133408755064 0.000000000000 -vt 0.099661588669 0.143760040402 0.000000000000 -vt 0.087192721665 0.108221992850 0.000000000000 -vt 0.082525931299 0.110838308930 0.000000000000 -vt 0.110880628228 0.135783463717 0.000000000000 -vt 0.103619366884 0.146102100611 0.000000000000 -vt 0.078900031745 0.113002493978 0.000000000000 -vt 0.114026710391 0.137971296906 0.000000000000 -vt 0.107220500708 0.147809907794 0.000000000000 -vt 0.075743131340 0.114870831370 0.000000000000 -vt 0.117038622499 0.139775693417 0.000000000000 -vt 0.110938265920 0.149550363421 0.000000000000 -vt 0.072325952351 0.116807609797 0.000000000000 -vt 0.121297188103 0.140570491552 0.000000000000 -vt 0.116660133004 0.148486047983 0.000000000000 -vt 0.070322073996 0.122125789523 0.000000000000 -vt 0.125169411302 0.141371369362 0.000000000000 -vt 0.067821048200 0.126478031278 0.000000000000 -vt 0.126182377338 0.130125775933 0.000000000000 -vt 0.128910809755 0.131200894713 0.000000000000 -vt 0.132871732116 0.132607877254 0.000000000000 -vt 0.133273646235 0.122961118817 0.000000000000 -vt 0.135723099113 0.124199911952 0.000000000000 -vt 0.137808039784 0.124982103705 0.000000000000 -vt 0.138423606753 0.117220535874 0.000000000000 -vt 0.140033245087 0.117920324206 0.000000000000 -vt 0.141472890973 0.118429854512 0.000000000000 -vt 0.139520570636 0.125482171774 0.000000000000 -vt 0.124876491725 0.103963419795 0.000000000000 -vt 0.117411032319 0.105984404683 0.000000000000 -vt 0.124236144125 0.102663815022 0.000000000000 -vt 0.129794090986 0.099442973733 0.000000000000 -vt 0.130341216922 0.100725457072 0.000000000000 -vt 0.131000250578 0.101975068450 0.000000000000 -vt 0.125632330775 0.105312764645 0.000000000000 -vt 0.131731107831 0.103181213140 0.000000000000 -vt 0.126520335674 0.106766596437 0.000000000000 -vt 0.127601757646 0.108326464891 0.000000000000 -vt 0.128798455000 0.109823748469 0.000000000000 -vt 0.130024880171 0.111135736108 0.000000000000 -vt 0.125136762857 0.116662845016 0.000000000000 -vt 0.131293177605 0.112291902304 0.000000000000 -vt 0.126648217440 0.118099555373 0.000000000000 -vt 0.120172336698 0.126228556037 0.000000000000 -vt 0.128081783652 0.119333624840 0.000000000000 -vt 0.122010938823 0.127758711576 0.000000000000 -vt 0.129577711225 0.120530337095 0.000000000000 -vt 0.123975865543 0.129045933485 0.000000000000 -vt 0.131254225969 0.121706768870 0.000000000000 -vt 0.133884489536 0.114366039634 0.000000000000 -vt 0.135243296623 0.115338250995 0.000000000000 -vt 0.136775031686 0.116316780448 0.000000000000 -vt 0.138644710183 0.110085606575 0.000000000000 -vt 0.139880597591 0.110813304782 0.000000000000 -vt 0.141141012311 0.111453637481 0.000000000000 -vt 0.142396926880 0.111997395754 0.000000000000 -vt 0.143704399467 0.112458750606 0.000000000000 -vt 0.137226909399 0.097607508302 0.000000000000 -vt 0.142870649695 0.102392718196 0.000000000000 -vt 0.137440353632 0.109256580472 0.000000000000 -vt 0.142222434282 0.101855054498 0.000000000000 -vt 0.143068566918 0.100842311978 0.000000000000 -vt 0.143592044711 0.099678248167 0.000000000000 -vt 0.136274725199 0.108363851905 0.000000000000 -vt 0.135182499886 0.107386663556 0.000000000000 -vt 0.132592767477 0.113364085555 0.000000000000 -vt 0.095187984407 0.102827504277 0.000000000000 -vt 0.094770319760 0.109039977193 0.000000000000 -vt 0.115190759301 0.083002358675 0.000000000000 -vt 0.117822378874 0.083010017872 0.000000000000 -vt 0.118609294295 0.089811727405 0.000000000000 -vt 0.145974636078 0.053520996124 0.000000000000 -vt 0.146114915609 0.056235466152 0.000000000000 -vt 0.139495581388 0.056631293148 0.000000000000 -vt 0.139889821410 0.054191056639 0.000000000000 -vt 0.119352757931 0.094131112099 0.000000000000 -vt 0.136199980974 0.055359613150 0.000000000000 -vt 0.119957312942 0.096627399325 0.000000000000 -vt 0.133549451828 0.056533124298 0.000000000000 -vt 0.144910335541 0.057005267590 0.000000000000 -vt 0.139738738537 0.057558249682 0.000000000000 -vt 0.145398020744 0.061774957925 0.000000000000 -vt 0.139342918992 0.061978947371 0.000000000000 -vt 0.149662911892 0.063947036862 0.000000000000 -vt 0.153687775135 0.067230239511 0.000000000000 -vt 0.155149489641 0.059760045260 0.000000000000 -vt 0.158387213945 0.062926396728 0.000000000000 -vt 0.157279461622 0.070296630263 0.000000000000 -vt 0.163594841957 0.066641241312 0.000000000000 -vt 0.153912261128 0.057711135596 0.000000000000 -vt 0.159546762705 0.060358505696 0.000000000000 -vt 0.164818108082 0.064783707261 0.000000000000 -vt 0.165087610483 0.069813668728 0.000000000000 -vt 0.167392298579 0.069913417101 0.000000000000 -vt 0.162909239531 0.058806512505 0.000000000000 -vt 0.168085560203 0.065015837550 0.000000000000 -vt 0.170962139964 0.071387514472 0.000000000000 -vt 0.171663269401 0.079518079758 0.000000000000 -vt 0.168453454971 0.075633481145 0.000000000000 -vt 0.154616549611 0.054712962359 0.000000000000 -vt 0.160480037332 0.072431325912 0.000000000000 -vt 0.165078386664 0.102370887995 0.000000000000 -vt 0.160031303763 0.101119697094 0.000000000000 -vt 0.153291955590 0.047032695264 0.000000000000 -vt 0.081070527434 0.018897537142 0.000000000000 -vt 0.085028529167 0.019402559847 0.000000000000 -vt 0.066250368953 0.017697680742 0.000000000000 -vt 0.060628462583 0.015371378511 0.000000000000 -vt 0.066359564662 0.016670975834 0.000000000000 -vt 0.071543760598 0.016661521047 0.000000000000 -vt 0.071405068040 0.017848987132 0.000000000000 -vt 0.075989224017 0.018615640700 0.000000000000 -vt 0.076596923172 0.017573174089 0.000000000000 -vt 0.017198059708 0.064038887620 0.000000000000 -vt 0.020149167627 0.070380836725 0.000000000000 -vt 0.016810115427 0.065315067768 0.000000000000 -vt 0.158577471972 0.046223942190 0.000000000000 -vt 0.102452382445 0.038576319814 0.000000000000 -vt 0.089843250811 0.037739418447 0.000000000000 -vt 0.086650550365 0.040033075958 0.000000000000 -vt 0.086444757879 0.038370531052 0.000000000000 -vt 0.089615844190 0.039254039526 0.000000000000 -vt 0.094363689423 0.042627539486 0.000000000000 -vt 0.089279234409 0.040964987129 0.000000000000 -vt 0.096154123545 0.044999096543 0.000000000000 -vt 0.099321827292 0.047730680555 0.000000000000 -vt 0.097085818648 0.047713566571 0.000000000000 -vt 0.095434077084 0.052601691335 0.000000000000 -vt 0.094276331365 0.051693182439 0.000000000000 -vt 0.089904040098 0.052642215043 0.000000000000 -vt 0.089681141078 0.050836246461 0.000000000000 -vt 0.084422186017 0.049848269671 0.000000000000 -vt 0.086022593081 0.049033429474 0.000000000000 -vt 0.082889109850 0.045797046274 0.000000000000 -vt 0.084425337613 0.045902874321 0.000000000000 -vt 0.084310062230 0.042319070548 0.000000000000 -vt 0.085408590734 0.043013904244 0.000000000000 -vt 0.083744473755 0.041396614164 0.000000000000 -vt 0.087161652744 0.041465062648 0.000000000000 -vt 0.089801147580 0.053888674825 0.000000000000 -vt 0.096400216222 0.053726788610 0.000000000000 -vt 0.101375699043 0.047830428928 0.000000000000 -vt 0.150993570685 0.099017649889 0.000000000000 -vt 0.131135791540 0.085984766483 0.000000000000 -vt 0.137482464314 0.092382773757 0.000000000000 -vt 0.135268285871 0.088904798031 0.000000000000 -vt 0.139503464103 0.089568555355 0.000000000000 -vt 0.136636331677 0.087804690003 0.000000000000 -vt 0.139095246792 0.088097617030 0.000000000000 -vt 0.141262590885 0.086944609880 0.000000000000 -vt 0.143028035760 0.087709680200 0.000000000000 -vt 0.052647162229 0.028242152184 0.000000000000 -vt 0.091367103159 0.114521846175 0.000000000000 -vt 0.024943847209 0.029597807676 0.000000000000 -vt 0.082706280053 0.355134129524 0.000000000000 -vt 0.085947386920 0.363250732422 0.000000000000 -vt 0.082174688578 0.364220470190 0.000000000000 -vt 0.079061470926 0.357818633318 0.000000000000 -vt 0.076576210558 0.349433183670 0.000000000000 -vt 0.074389949441 0.353636831045 0.000000000000 -vt 0.070025764406 0.352275311947 0.000000000000 -vt 0.069683760405 0.347608089447 0.000000000000 -vt 0.084169343114 0.377381920815 0.000000000000 -vt 0.080777153373 0.375979661942 0.000000000000 -vt 0.082553848624 0.370932579041 0.000000000000 -vt 0.086099147797 0.371338099241 0.000000000000 -vt 0.079547807574 0.364964604378 0.000000000000 -vt 0.080153018236 0.370642364025 0.000000000000 -vt 0.076729759574 0.359675943851 0.000000000000 -vt 0.073228374124 0.356270015240 0.000000000000 -vt 0.070341885090 0.355011194944 0.000000000000 -vt 0.078728012741 0.374791979790 0.000000000000 -vt 0.078406266868 0.379009783268 0.000000000000 -vt 0.081292532384 0.382708638906 0.000000000000 -vt 0.077228710055 0.376913607121 0.000000000000 -vt 0.076079964638 0.380043476820 0.000000000000 -vt 0.075517080724 0.383981227875 0.000000000000 -vt 0.075921684504 0.377626001835 0.000000000000 -vt 0.067173950374 0.353658229113 0.000000000000 -vt 0.068672135472 0.355914741755 0.000000000000 -vt 0.064776502550 0.349804252386 0.000000000000 -vt 0.072278216481 0.378946751356 0.000000000000 -vt 0.069932326674 0.382139891386 0.000000000000 -vt 0.073346585035 0.376760721207 0.000000000000 -vt 0.065008409321 0.358051896095 0.000000000000 -vt 0.067364208400 0.359130382538 0.000000000000 -vt 0.061515796930 0.356177270412 0.000000000000 -vt 0.067828252912 0.375058323145 0.000000000000 -vt 0.064983420074 0.377222746611 0.000000000000 -vt 0.069865681231 0.373641878366 0.000000000000 -vt 0.063662886620 0.364159464836 0.000000000000 -vt 0.066595532000 0.364011079073 0.000000000000 -vt 0.059879150242 0.364149570465 0.000000000000 -vt 0.064561255276 0.369833588600 0.000000000000 -vt 0.067180253565 0.369111299515 0.000000000000 -vt 0.061178293079 0.370929658413 0.000000000000 -vt 0.087921552360 0.351186037064 0.000000000000 -vt 0.091303609312 0.361563861370 0.000000000000 -vt 0.079885534942 0.343255817890 0.000000000000 -vt 0.069204851985 0.340724855661 0.000000000000 -vt 0.060809489340 0.344233006239 0.000000000000 -vt 0.055593322963 0.353128671646 0.000000000000 -vt 0.053862329572 0.363875776529 0.000000000000 -vt 0.055507313460 0.372740805149 0.000000000000 -vt 0.060099344701 0.380897492170 0.000000000000 -vt 0.066655874252 0.386289954185 0.000000000000 -vt 0.073765367270 0.388392239809 0.000000000000 -vt 0.081145055592 0.388035595417 0.000000000000 -vt 0.088785246015 0.377678692341 0.000000000000 -vt 0.087788932025 0.382556229830 0.000000000000 -vt 0.090708971024 0.371422529221 0.000000000000 -vt 0.098516449332 0.359101116657 0.000000000000 -vt 0.095570974052 0.371151894331 0.000000000000 -vt 0.081494718790 0.391452759504 0.000000000000 -vt 0.072904601693 0.391978055239 0.000000000000 -vt 0.087930560112 0.387041747570 0.000000000000 -vt 0.089069843292 0.390307635069 0.000000000000 -vt 0.093086160719 0.377379685640 0.000000000000 -vt 0.092234395444 0.382332623005 0.000000000000 -vt 0.096012048423 0.378206431866 0.000000000000 -vt 0.095273993909 0.382441610098 0.000000000000 -vt 0.098627001047 0.372742831707 0.000000000000 -vt 0.100691899657 0.375768691301 0.000000000000 -vt 0.097777709365 0.379422277212 0.000000000000 -vt 0.096909299493 0.382944613695 0.000000000000 -vt 0.064227119088 0.390731811523 0.000000000000 -vt 0.047463636845 0.374592483044 0.000000000000 -vt 0.045266803354 0.362910062075 0.000000000000 -vt 0.053129222244 0.386380702257 0.000000000000 -vt 0.055269774050 0.337182939053 0.000000000000 -vt 0.068264156580 0.332182705402 0.000000000000 -vt 0.047308508307 0.348847329617 0.000000000000 -vt 0.083508059382 0.335973203182 0.000000000000 -vt 0.092679306865 0.386310219765 0.000000000000 -vt 0.094604156911 0.389197170734 0.000000000000 -vt 0.096809998155 0.386411547661 0.000000000000 -vt 0.095029927790 0.385251104832 0.000000000000 -vt 0.098225995898 0.388757675886 0.000000000000 -vt 0.097066685557 0.389816790819 0.000000000000 -vt 0.098929613829 0.391160309315 0.000000000000 -vt 0.097326502204 0.391429573298 0.000000000000 -vt 0.094737671316 0.391862779856 0.000000000000 -vt 0.089453734457 0.392666131258 0.000000000000 -vt 0.081771887839 0.393726825714 0.000000000000 -vt 0.072946928442 0.394806444645 0.000000000000 -vt 0.063999712467 0.395681649446 0.000000000000 -vt 0.053615327924 0.396396279335 0.000000000000 -vt 0.041419353336 0.396926730871 0.000000000000 -vt 0.039976555854 0.386726528406 0.000000000000 -vt 0.037052463740 0.374329954386 0.000000000000 -vt 0.035149227828 0.359872728586 0.000000000000 -vt 0.038212914020 0.342804163694 0.000000000000 -vt 0.049577396363 0.328440159559 0.000000000000 -vt 0.067996665835 0.322506874800 0.000000000000 -vt 0.093688450754 0.346306473017 0.000000000000 -vt 0.088374562562 0.327701002359 0.000000000000 -vt 0.100369259715 0.339963853359 0.000000000000 -vt 0.105655893683 0.350941717625 0.000000000000 -vt 0.103044107556 0.365339487791 0.000000000000 -vt 0.108533605933 0.357757389545 0.000000000000 -vt 0.105408892035 0.369979262352 0.000000000000 -vt 0.098068401217 0.383108973503 0.000000000000 -vt 0.098497763276 0.385625302792 0.000000000000 -vt 0.101734369993 0.380148172379 0.000000000000 -vt 0.098705813289 0.380785822868 0.000000000000 -vt 0.099697157741 0.387924820185 0.000000000000 -vt 0.100644618273 0.390900254250 0.000000000000 -vt 0.105129703879 0.377691507339 0.000000000000 -vt 0.105785802007 0.382571756840 0.000000000000 -vt 0.103088900447 0.383172452450 0.000000000000 -vt 0.106459483504 0.386435866356 0.000000000000 -vt 0.104129120708 0.386695683002 0.000000000000 -vt 0.104879111052 0.390249550343 0.000000000000 -vt 0.102643325925 0.390611141920 0.000000000000 -vt 0.101812496781 0.387293249369 0.000000000000 -vt 0.099612280726 0.383124738932 0.000000000000 -vt 0.100343361497 0.384889960289 0.000000000000 -vt 0.101334720850 0.382499039173 0.000000000000 -vt 0.099765837193 0.381787300110 0.000000000000 -vt 0.101950511336 0.385482788086 0.000000000000 -vt 0.102647826076 0.385179489851 0.000000000000 -vt 0.102046653628 0.383690536022 0.000000000000 -vt 0.101413294673 0.384207725525 0.000000000000 -vt 0.101018831134 0.383238196373 0.000000000000 -vt 0.111804887652 0.347057133913 0.000000000000 -vt 0.113323777914 0.353700101376 0.000000000000 -vt 0.116853311658 0.353322982788 0.000000000000 -vt 0.117552861571 0.346509546041 0.000000000000 -vt 0.123864643276 0.349401652813 0.000000000000 -vt 0.120530322194 0.355773121119 0.000000000000 -vt 0.129755362868 0.355360180140 0.000000000000 -vt 0.124298743904 0.360911160707 0.000000000000 -vt 0.134041413665 0.362597793341 0.000000000000 -vt 0.127354532480 0.367429167032 0.000000000000 -vt 0.129645943642 0.373671829700 0.000000000000 -vt 0.136888504028 0.369591563940 0.000000000000 -vt 0.138823032379 0.375629991293 0.000000000000 -vt 0.131178572774 0.379008889198 0.000000000000 -vt 0.110230609775 0.361257672310 0.000000000000 -vt 0.113775447011 0.356992095709 0.000000000000 -vt 0.115981966257 0.356578052044 0.000000000000 -vt 0.118140742183 0.358845561743 0.000000000000 -vt 0.120337590575 0.363843351603 0.000000000000 -vt 0.122301377356 0.370323300362 0.000000000000 -vt 0.123794607818 0.376463502645 0.000000000000 -vt 0.125330835581 0.385786980391 0.000000000000 -vt 0.124756477773 0.381512612104 0.000000000000 -vt 0.132145613432 0.383721172810 0.000000000000 -vt 0.117319837213 0.365754455328 0.000000000000 -vt 0.116345807910 0.360568702221 0.000000000000 -vt 0.118315473199 0.372491776943 0.000000000000 -vt 0.119095861912 0.378632873297 0.000000000000 -vt 0.115259900689 0.358279764652 0.000000000000 -vt 0.113950163126 0.358692705631 0.000000000000 -vt 0.111850589514 0.362477779388 0.000000000000 -vt 0.109477445483 0.369221389294 0.000000000000 -vt 0.108606114984 0.376295775175 0.000000000000 -vt 0.108548924327 0.381853967905 0.000000000000 -vt 0.108668252826 0.385990947485 0.000000000000 -vt 0.109056636691 0.389389663935 0.000000000000 -vt 0.106977775693 0.389831870794 0.000000000000 -vt 0.115236923099 0.380258053541 0.000000000000 -vt 0.119639605284 0.383368134499 0.000000000000 -vt 0.115580737591 0.384713888168 0.000000000000 -vt 0.114937916398 0.374172329903 0.000000000000 -vt 0.114662095904 0.367107868195 0.000000000000 -vt 0.114699468017 0.361614972353 0.000000000000 -vt 0.114764764905 0.359385490417 0.000000000000 -vt 0.114121511579 0.359670996666 0.000000000000 -vt 0.113303065300 0.362503677607 0.000000000000 -vt 0.112174823880 0.368418276310 0.000000000000 -vt 0.111594587564 0.375343382359 0.000000000000 -vt 0.111402764916 0.381200790405 0.000000000000 -vt 0.111436754465 0.385559558868 0.000000000000 -vt 0.111605182290 0.388848632574 0.000000000000 -vt 0.140208870173 0.380911469460 0.000000000000 -vt 0.120046690106 0.387208133936 0.000000000000 -vt 0.116041406989 0.388132423162 0.000000000000 -vt 0.108075186610 0.335427641869 0.000000000000 -vt 0.097032681108 0.317022114992 0.000000000000 -vt 0.068101368845 0.311556011438 0.000000000000 -vt 0.117994397879 0.334477722645 0.000000000000 -vt 0.128177925944 0.338179260492 0.000000000000 -vt 0.136790558696 0.345966488123 0.000000000000 -vt 0.142394453287 0.355307698250 0.000000000000 -vt 0.145550668240 0.364030212164 0.000000000000 -vt 0.147579327226 0.371295541525 0.000000000000 -vt 0.149121865630 0.377288043499 0.000000000000 -vt 0.117433980107 0.316912233829 0.000000000000 -vt 0.132998272777 0.322530061007 0.000000000000 -vt 0.144912809134 0.333580464125 0.000000000000 -vt 0.151742890477 0.346387058496 0.000000000000 -vt 0.155101761222 0.357449173927 0.000000000000 -vt 0.157138064504 0.366050541401 0.000000000000 -vt 0.158694103360 0.372791916132 0.000000000000 -vt 0.093021988869 0.298639088869 0.000000000000 -vt 0.116434976459 0.299687176943 0.000000000000 -vt 0.137037336826 0.306387364864 0.000000000000 -vt 0.152599602938 0.319078207016 0.000000000000 -vt 0.161577224731 0.334434717894 0.000000000000 -vt 0.165657475591 0.348677575588 0.000000000000 -vt 0.167427644134 0.359111487865 0.000000000000 -vt 0.169053271413 0.366990566254 0.000000000000 -vt 0.066684693098 0.299283713102 0.000000000000 -vt 0.044727105647 0.318464457989 0.000000000000 -vt 0.029994530603 0.333837360144 0.000000000000 -vt 0.023920066655 0.352325320244 0.000000000000 -vt 0.023143958300 0.369406253099 0.000000000000 -vt 0.024057183415 0.384051918983 0.000000000000 -vt 0.024341106415 0.396830379963 0.000000000000 -vt 0.177712291479 0.335085839033 0.000000000000 -vt 0.181121811271 0.347459256649 0.000000000000 -vt 0.170949757099 0.319616109133 0.000000000000 -vt 0.158325985074 0.304390668869 0.000000000000 -vt 0.139046162367 0.292386740446 0.000000000000 -vt 0.114894911647 0.285406500101 0.000000000000 -vt 0.089810602367 0.284732818604 0.000000000000 -vt 0.064246259630 0.287257254124 0.000000000000 -vt 0.060561817139 0.275299966335 0.000000000000 -vt 0.085912264884 0.272128403187 0.000000000000 -vt 0.112814709544 0.271828740835 0.000000000000 -vt 0.139997899532 0.280653685331 0.000000000000 -vt 0.162012219429 0.289723157883 0.000000000000 -vt 0.177664101124 0.300114750862 0.000000000000 -vt 0.190142661333 0.313898980618 0.000000000000 -vt 0.198672652245 0.327432364225 0.000000000000 -vt 0.205239757895 0.340885162354 0.000000000000 -vt 0.183992534876 0.357445776463 0.000000000000 -vt 0.069244705141 0.368339478970 0.000000000000 -vt 0.071158297360 0.372511804104 0.000000000000 -vt 0.073666974902 0.375427126884 0.000000000000 -vt 0.075608938932 0.376399338245 0.000000000000 -vt 0.076639704406 0.375857174397 0.000000000000 -vt 0.077665731311 0.373797893524 0.000000000000 -vt 0.078264869750 0.370282560587 0.000000000000 -vt 0.077448233962 0.365520745516 0.000000000000 -vt 0.075266703963 0.360965639353 0.000000000000 -vt 0.072741590440 0.357893168926 0.000000000000 -vt 0.070687949657 0.356488436460 0.000000000000 -vt 0.069615535438 0.357108056545 0.000000000000 -vt 0.068887837231 0.359731346369 0.000000000000 -vt 0.068630032241 0.363813161850 0.000000000000 -vt 0.070949353278 0.367750674486 0.000000000000 -vt 0.072260208428 0.371762514114 0.000000000000 -vt 0.074021823704 0.374623537064 0.000000000000 -vt 0.075438044965 0.375722974539 0.000000000000 -vt 0.076083339751 0.375304430723 0.000000000000 -vt 0.076256714761 0.373671144247 0.000000000000 -vt 0.077135719359 0.370294928551 0.000000000000 -vt 0.076337769628 0.365889549255 0.000000000000 -vt 0.074512436986 0.361760437489 0.000000000000 -vt 0.072514630854 0.358907490969 0.000000000000 -vt 0.070951603353 0.357409089804 0.000000000000 -vt 0.070442758501 0.357752889395 0.000000000000 -vt 0.070120111108 0.359841883183 0.000000000000 -vt 0.070317119360 0.363489836454 0.000000000000 -vt 0.095527067780 0.433499604464 0.000000000000 -vt 0.089006572962 0.431389659643 0.000000000000 -vt 0.089679561555 0.423253923655 0.000000000000 -vt 0.095813460648 0.423289269209 0.000000000000 -vt 0.090270593762 0.442476540804 0.000000000000 -vt 0.085782580078 0.438130587339 0.000000000000 -vt 0.082391515374 0.447095155716 0.000000000000 -vt 0.081284202635 0.441373258829 0.000000000000 -vt 0.088421173394 0.409246772528 0.000000000000 -vt 0.092461802065 0.414794385433 0.000000000000 -vt 0.088074430823 0.416153192520 0.000000000000 -vt 0.085401162505 0.411531209946 0.000000000000 -vt 0.085601098835 0.423056453466 0.000000000000 -vt 0.085188619792 0.417149722576 0.000000000000 -vt 0.084852233529 0.429683655500 0.000000000000 -vt 0.083113588393 0.435138046741 0.000000000000 -vt 0.080847173929 0.437920957804 0.000000000000 -vt 0.083637073636 0.413283139467 0.000000000000 -vt 0.082392193377 0.409229904413 0.000000000000 -vt 0.084188699722 0.404711484909 0.000000000000 -vt 0.081871181726 0.411629140377 0.000000000000 -vt 0.079863473773 0.408857047558 0.000000000000 -vt 0.078159049153 0.404978066683 0.000000000000 -vt 0.080601528287 0.411386430264 0.000000000000 -vt 0.077497541904 0.440609782934 0.000000000000 -vt 0.078839689493 0.437481015921 0.000000000000 -vt 0.075624249876 0.445949316025 0.000000000000 -vt 0.076512485743 0.410979568958 0.000000000000 -vt 0.072959765792 0.408222317696 0.000000000000 -vt 0.078687265515 0.412980526686 0.000000000000 -vt 0.074185512960 0.435919106007 0.000000000000 -vt 0.076881967485 0.434023529291 0.000000000000 -vt 0.070257902145 0.439116775990 0.000000000000 -vt 0.073384404182 0.416101634502 0.000000000000 -vt 0.069238848984 0.414494931698 0.000000000000 -vt 0.076494477689 0.417049527168 0.000000000000 -vt 0.072321221232 0.429132491350 0.000000000000 -vt 0.075570665300 0.428600221872 0.000000000000 -vt 0.067612551153 0.430139392614 0.000000000000 -vt 0.072135694325 0.422728389502 0.000000000000 -vt 0.075469121337 0.422917068005 0.000000000000 -vt 0.067447289824 0.422248363495 0.000000000000 -vt 0.102335080504 0.423187494278 0.000000000000 -vt 0.103228494525 0.435963690281 0.000000000000 -vt 0.096575386822 0.448499649763 0.000000000000 -vt 0.084121152759 0.455617934465 0.000000000000 -vt 0.072271011770 0.453928828239 0.000000000000 -vt 0.063513830304 0.444215625525 0.000000000000 -vt 0.059691589326 0.431783914566 0.000000000000 -vt 0.059796515852 0.421276837587 0.000000000000 -vt 0.062896229327 0.411542922258 0.000000000000 -vt 0.068578697741 0.404683113098 0.000000000000 -vt 0.075288772583 0.400957018137 0.000000000000 -vt 0.082664631307 0.399442404509 0.000000000000 -vt 0.090280279517 0.402916997671 0.000000000000 -vt 0.092445820570 0.407546848059 0.000000000000 -vt 0.097145929933 0.413269847631 0.000000000000 -vt 0.101524755359 0.411767631769 0.000000000000 -vt 0.108704730868 0.422636747360 0.000000000000 -vt 0.073573760688 0.397591859102 0.000000000000 -vt 0.082102417946 0.395999342203 0.000000000000 -vt 0.089554600418 0.398501247168 0.000000000000 -vt 0.089799568057 0.395039051771 0.000000000000 -vt 0.096459656954 0.406454414129 0.000000000000 -vt 0.094413220882 0.401787608862 0.000000000000 -vt 0.097341135144 0.400798738003 0.000000000000 -vt 0.099026650190 0.404693007469 0.000000000000 -vt 0.103435859084 0.409006088972 0.000000000000 -vt 0.100435674191 0.402943789959 0.000000000000 -vt 0.104281768203 0.405376374722 0.000000000000 -vt 0.098907768726 0.399778544903 0.000000000000 -vt 0.065163768828 0.400598347187 0.000000000000 -vt 0.049860190600 0.420209825039 0.000000000000 -vt 0.048853974789 0.434106171131 0.000000000000 -vt 0.054477673024 0.406693518162 0.000000000000 -vt 0.086032271385 0.466448366642 0.000000000000 -vt 0.067181386054 0.464296758175 0.000000000000 -vt 0.053818415850 0.451216369867 0.000000000000 -vt 0.103748381138 0.455393463373 0.000000000000 -vt 0.094275876880 0.397762984037 0.000000000000 -vt 0.095426648855 0.394399613142 0.000000000000 -vt 0.096762046218 0.398063540459 0.000000000000 -vt 0.098227351904 0.396364301443 0.000000000000 -vt 0.097545132041 0.393038094044 0.000000000000 -vt 0.098932549357 0.393664687872 0.000000000000 -vt 0.040455233306 0.407481104136 0.000000000000 -vt 0.037843432277 0.421338081360 0.000000000000 -vt 0.036472912878 0.438838243484 0.000000000000 -vt 0.042982604355 0.460524737835 0.000000000000 -vt 0.062214907259 0.477089822292 0.000000000000 -vt 0.089566305280 0.478372305632 0.000000000000 -vt 0.111008062959 0.438808530569 0.000000000000 -vt 0.113180801272 0.462344437838 0.000000000000 -vt 0.120472237468 0.442430824041 0.000000000000 -vt 0.117490500212 0.428076952696 0.000000000000 -vt 0.109111800790 0.414127260447 0.000000000000 -vt 0.115140110254 0.419330358505 0.000000000000 -vt 0.109508290887 0.408478111029 0.000000000000 -vt 0.099965557456 0.396614462137 0.000000000000 -vt 0.100016877055 0.399250566959 0.000000000000 -vt 0.101089760661 0.401380300522 0.000000000000 -vt 0.104426547885 0.401133537292 0.000000000000 -vt 0.100525066257 0.394041150808 0.000000000000 -vt 0.108131244779 0.401879489422 0.000000000000 -vt 0.105194106698 0.397765219212 0.000000000000 -vt 0.107807472348 0.397282481194 0.000000000000 -vt 0.105133533478 0.393932640553 0.000000000000 -vt 0.107335999608 0.393302202225 0.000000000000 -vt 0.102719649673 0.394079893827 0.000000000000 -vt 0.101905718446 0.396900862455 0.000000000000 -vt 0.101522728801 0.398900896311 0.000000000000 -vt 0.101974606514 0.400191038847 0.000000000000 -vt 0.103468522429 0.399126052856 0.000000000000 -vt 0.104171678424 0.395909041166 0.000000000000 -vt 0.103377550840 0.395803213120 0.000000000000 -vt 0.103972420096 0.397658735514 0.000000000000 -vt 0.103157803416 0.397318959236 0.000000000000 -vt 0.102937594056 0.398482114077 0.000000000000 -vt 0.120900921524 0.421827554703 0.000000000000 -vt 0.125391185284 0.429458737373 0.000000000000 -vt 0.124984331429 0.420799940825 0.000000000000 -vt 0.132154166698 0.427056103945 0.000000000000 -vt 0.128460273147 0.416311025620 0.000000000000 -vt 0.138081595302 0.420313149691 0.000000000000 -vt 0.142197445035 0.410675615072 0.000000000000 -vt 0.131676614285 0.408927738667 0.000000000000 -vt 0.133587732911 0.401068240404 0.000000000000 -vt 0.143351808190 0.401146143675 0.000000000000 -vt 0.133652120829 0.394226670265 0.000000000000 -vt 0.142618030310 0.392982929945 0.000000000000 -vt 0.132911369205 0.388540625572 0.000000000000 -vt 0.141394317150 0.386369884014 0.000000000000 -vt 0.114809587598 0.414815992117 0.000000000000 -vt 0.119088873267 0.418000578880 0.000000000000 -vt 0.121582247317 0.417691677809 0.000000000000 -vt 0.123152919114 0.414221823215 0.000000000000 -vt 0.124552257359 0.408110886812 0.000000000000 -vt 0.125927954912 0.401200413704 0.000000000000 -vt 0.126286625862 0.395116031170 0.000000000000 -vt 0.125815823674 0.390080004930 0.000000000000 -vt 0.120327234268 0.413139492273 0.000000000000 -vt 0.120299309492 0.407533794641 0.000000000000 -vt 0.120726875961 0.401063978672 0.000000000000 -vt 0.120826847851 0.395488440990 0.000000000000 -vt 0.119930967689 0.416081815958 0.000000000000 -vt 0.118429407477 0.416086316109 0.000000000000 -vt 0.115609556437 0.412894517183 0.000000000000 -vt 0.112695828080 0.407353222370 0.000000000000 -vt 0.111295580864 0.401569455862 0.000000000000 -vt 0.110395416617 0.396767795086 0.000000000000 -vt 0.109471604228 0.392846018076 0.000000000000 -vt 0.116785764694 0.395642906427 0.000000000000 -vt 0.116270169616 0.391529113054 0.000000000000 -vt 0.120401531458 0.391011029482 0.000000000000 -vt 0.117080941796 0.400902092457 0.000000000000 -vt 0.117325022817 0.407227128744 0.000000000000 -vt 0.118285760283 0.412657201290 0.000000000000 -vt 0.118986204267 0.415048807859 0.000000000000 -vt 0.118248149753 0.414979010820 0.000000000000 -vt 0.116768434644 0.412282764912 0.000000000000 -vt 0.114910230041 0.406959205866 0.000000000000 -vt 0.113860324025 0.401094585657 0.000000000000 -vt 0.113027706742 0.396125406027 0.000000000000 -vt 0.112157255411 0.392097175121 0.000000000000 -vt 0.130801886320 0.442939460278 0.000000000000 -vt 0.128610894084 0.468570888042 0.000000000000 -vt 0.094356708229 0.491361290216 0.000000000000 -vt 0.141893029213 0.437752097845 0.000000000000 -vt 0.150102630258 0.427333265543 0.000000000000 -vt 0.154337808490 0.414093464613 0.000000000000 -vt 0.154476270080 0.401521474123 0.000000000000 -vt 0.152643069625 0.391335010529 0.000000000000 -vt 0.150666207075 0.383463352919 0.000000000000 -vt 0.151377916336 0.454670488834 0.000000000000 -vt 0.163681745529 0.437636584044 0.000000000000 -vt 0.168372631073 0.418352723122 0.000000000000 -vt 0.166913852096 0.401432096958 0.000000000000 -vt 0.163569614291 0.388818919659 0.000000000000 -vt 0.160684034228 0.379647225142 0.000000000000 -vt 0.159950926900 0.471008867025 0.000000000000 -vt 0.132880300283 0.489435285330 0.000000000000 -vt 0.177281573415 0.447766780853 0.000000000000 -vt 0.184215664864 0.422988891602 0.000000000000 -vt 0.181977853179 0.401209205389 0.000000000000 -vt 0.176495552063 0.385539740324 0.000000000000 -vt 0.171912297606 0.374865829945 0.000000000000 -vt 0.098764792085 0.505384683609 0.000000000000 -vt 0.058615576476 0.491276592016 0.000000000000 -vt 0.294122487307 0.343028873205 0.000000000000 -vt 0.033512126654 0.473827123642 0.000000000000 -vt 0.022036869079 0.449060529470 0.000000000000 -vt 0.304196149111 0.365502059460 0.000000000000 -vt 0.294669389725 0.374178409576 0.000000000000 -vt 0.283370435238 0.353863328695 0.000000000000 -vt 0.021253105253 0.427221357822 0.000000000000 -vt 0.316540300846 0.419560700655 0.000000000000 -vt 0.308288812637 0.422085821629 0.000000000000 -vt 0.304480075836 0.396445810795 0.000000000000 -vt 0.312906295061 0.403799384832 0.000000000000 -vt 0.320418357849 0.438478231430 0.000000000000 -vt 0.309799134731 0.442829579115 0.000000000000 -vt 0.322631418705 0.453612715006 0.000000000000 -vt 0.308162033558 0.458434849977 0.000000000000 -vt 0.322842836380 0.466000735760 0.000000000000 -vt 0.304739683867 0.470083713531 0.000000000000 -vt 0.321488976479 0.476586610079 0.000000000000 -vt 0.301276564598 0.479211658239 0.000000000000 -vt 0.318110078573 0.486222833395 0.000000000000 -vt 0.298631459475 0.487806051970 0.000000000000 -vt 0.342029422522 0.477887094021 0.000000000000 -vt 0.335520654917 0.489814013243 0.000000000000 -vt 0.338924765587 0.462258905172 0.000000000000 -vt 0.335986942053 0.447854578495 0.000000000000 -vt 0.331019103527 0.432695329189 0.000000000000 -vt 0.324403166771 0.415379106998 0.000000000000 -vt 0.317968666553 0.397860914469 0.000000000000 -vt 0.311544537544 0.382980197668 0.000000000000 -vt 0.292794078588 0.320117980242 0.000000000000 -vt 0.322062432766 0.330567449331 0.000000000000 -vt 0.310178071260 0.344646602869 0.000000000000 -vt 0.321752399206 0.375562220812 0.000000000000 -vt 0.315860539675 0.358816295862 0.000000000000 -vt 0.327765852213 0.391973108053 0.000000000000 -vt 0.334508121014 0.409605920315 0.000000000000 -vt 0.341052263975 0.426227092743 0.000000000000 -vt 0.345613449812 0.441917032003 0.000000000000 -vt 0.349559307098 0.456911921501 0.000000000000 -vt 0.353330194950 0.470938861370 0.000000000000 -vt 0.352067083120 0.491384476423 0.000000000000 -vt 0.346471965313 0.498636275530 0.000000000000 -vt 0.357014626265 0.482859700918 0.000000000000 -vt 0.023049619049 0.410277992487 0.000000000000 -vt 0.188200235367 0.367613345385 0.000000000000 -vt 0.193979293108 0.380675494671 0.000000000000 -vt 0.199914619327 0.400077104568 0.000000000000 -vt 0.200497537851 0.426822185516 0.000000000000 -vt 0.188813567162 0.456079959869 0.000000000000 -vt 0.165967300534 0.483203917742 0.000000000000 -vt 0.135587558150 0.503403544426 0.000000000000 -vt 0.101455852389 0.518397510052 0.000000000000 -vt 0.136549651623 0.514204204082 0.000000000000 -vt 0.102526023984 0.530645966530 0.000000000000 -vt 0.170128390193 0.491040199995 0.000000000000 -vt 0.198282465339 0.460966050625 0.000000000000 -vt 0.217465236783 0.429308772087 0.000000000000 -vt 0.220426246524 0.397770404816 0.000000000000 -vt 0.216484680772 0.373772233725 0.000000000000 -vt 0.211094245315 0.355721533298 0.000000000000 -vt 0.078403115273 0.417854249477 0.000000000000 -vt 0.077661454678 0.423130065203 0.000000000000 -vt 0.361433088779 0.473092228174 0.000000000000 -vt 0.358897387981 0.464050680399 0.000000000000 -vt 0.356920510530 0.451468318701 0.000000000000 -vt 0.079683125019 0.414227455854 0.000000000000 -vt 0.080865636468 0.412698864937 0.000000000000 -vt 0.081717401743 0.412858963013 0.000000000000 -vt 0.082934811711 0.414582073689 0.000000000000 -vt 0.083612754941 0.417999476194 0.000000000000 -vt 0.083627842367 0.422989368439 0.000000000000 -vt 0.355338811874 0.436321228743 0.000000000000 -vt 0.352934360504 0.420035988092 0.000000000000 -vt 0.348425179720 0.402650177479 0.000000000000 -vt 0.342104852200 0.385241180658 0.000000000000 -vt 0.336092978716 0.368649065495 0.000000000000 -vt 0.083053693175 0.428555428982 0.000000000000 -vt 0.331038475037 0.351473778486 0.000000000000 -vt 0.295939028263 0.301119387150 0.000000000000 -vt 0.322564095259 0.306299775839 0.000000000000 -vt 0.297336816788 0.282364428043 0.000000000000 -vt 0.323178768158 0.284241318703 0.000000000000 -vt 0.367684066296 0.461390703917 0.000000000000 -vt 0.363470733166 0.458035647869 0.000000000000 -vt 0.364652335644 0.447590470314 0.000000000000 -vt 0.365994274616 0.432411193848 0.000000000000 -vt 0.366280674934 0.415150791407 0.000000000000 -vt 0.364420890808 0.396647334099 0.000000000000 -vt 0.360572069883 0.378713041544 0.000000000000 -vt 0.356490701437 0.362032413483 0.000000000000 -vt 0.353067219257 0.345778703690 0.000000000000 -vt 0.350522726774 0.327914893627 0.000000000000 -vt 0.348939448595 0.305953025818 0.000000000000 -vt 0.346083581448 0.277952730656 0.000000000000 -vt 0.373975127935 0.447995543480 0.000000000000 -vt 0.379207283258 0.431906849146 0.000000000000 -vt 0.382956564426 0.412491261959 0.000000000000 -vt 0.384116321802 0.392035484314 0.000000000000 -vt 0.382254749537 0.373682171106 0.000000000000 -vt 0.379626274109 0.358964234591 0.000000000000 -vt 0.377992331982 0.345823734999 0.000000000000 -vt 0.377301573753 0.329902321100 0.000000000000 -vt 0.376336544752 0.303653508425 0.000000000000 -vt 0.370527774096 0.266846507788 0.000000000000 -vt 0.216167435050 0.467717558146 0.000000000000 -vt 0.210370138288 0.459447145462 0.000000000000 -vt 0.081996142864 0.433199465275 0.000000000000 -vt 0.222096204758 0.439130961895 0.000000000000 -vt 0.226445078850 0.444121509790 0.000000000000 -vt 0.233966410160 0.386992007494 0.000000000000 -vt 0.231436342001 0.403846651316 0.000000000000 -vt 0.228788286448 0.415274649858 0.000000000000 -vt 0.231669127941 0.390098005533 0.000000000000 -vt 0.233401954174 0.365559697151 0.000000000000 -vt 0.227946877480 0.368952572346 0.000000000000 -vt 0.222369551659 0.352989733219 0.000000000000 -vt 0.231268167496 0.347663909197 0.000000000000 -vt 0.228197038174 0.333069592714 0.000000000000 -vt 0.215772062540 0.341411590576 0.000000000000 -vt 0.225630939007 0.321423888206 0.000000000000 -vt 0.210557922721 0.332115828991 0.000000000000 -vt 0.240293502808 0.310512185097 0.000000000000 -vt 0.238473564386 0.327548325062 0.000000000000 -vt 0.237924396992 0.344880312681 0.000000000000 -vt 0.237548619509 0.364148646593 0.000000000000 -vt 0.080796964467 0.435884207487 0.000000000000 -vt 0.235683202744 0.385488867760 0.000000000000 -vt 0.233118027449 0.406267970800 0.000000000000 -vt 0.231307089329 0.424209684134 0.000000000000 -vt 0.210896104574 0.489333540201 0.000000000000 -vt 0.228112816811 0.462109386921 0.000000000000 -vt 0.236405730247 0.472126305103 0.000000000000 -vt 0.236261844635 0.426290810108 0.000000000000 -vt 0.232935667038 0.445951789618 0.000000000000 -vt 0.237997591496 0.406573981047 0.000000000000 -vt 0.240250259638 0.385305374861 0.000000000000 -vt 0.242734611034 0.364867120981 0.000000000000 -vt 0.244929671288 0.346436828375 0.000000000000 -vt 0.247872665524 0.330308973789 0.000000000000 -vt 0.250990182161 0.316065877676 0.000000000000 -vt 0.249255821109 0.295715004206 0.000000000000 -vt 0.254375159740 0.304102927446 0.000000000000 -vt 0.259052336216 0.313747882843 0.000000000000 -vt 0.256746292114 0.322819858789 0.000000000000 -vt 0.255218595266 0.335408508778 0.000000000000 -vt 0.254195064306 0.350621551275 0.000000000000 -vt 0.252835571766 0.367554813623 0.000000000000 -vt 0.250323951244 0.386674314737 0.000000000000 -vt 0.247343555093 0.407099246979 0.000000000000 -vt 0.244989335537 0.426806420088 0.000000000000 -vt 0.242804884911 0.447076678276 0.000000000000 -vt 0.235569059849 0.496732383966 0.000000000000 -vt 0.210636273026 0.507261335850 0.000000000000 -vt 0.265602082014 0.325080633163 0.000000000000 -vt 0.261477023363 0.328609049320 0.000000000000 -vt 0.262952446938 0.338707923889 0.000000000000 -vt 0.264598786831 0.353362590075 0.000000000000 -vt 0.265408009291 0.370452553034 0.000000000000 -vt 0.264614790678 0.389507651329 0.000000000000 -vt 0.262594908476 0.408623784781 0.000000000000 -vt 0.260723888874 0.426476329565 0.000000000000 -vt 0.259777098894 0.444406121969 0.000000000000 -vt 0.259517729282 0.464280545712 0.000000000000 -vt 0.259723722935 0.488092929125 0.000000000000 -vt 0.272190570831 0.337464153767 0.000000000000 -vt 0.277376800776 0.352163642645 0.000000000000 -vt 0.281132608652 0.370615124702 0.000000000000 -vt 0.283069849014 0.391205787659 0.000000000000 -vt 0.282786369324 0.410528808832 0.000000000000 -vt 0.281975150108 0.425936192274 0.000000000000 -vt 0.281850397587 0.438871800900 0.000000000000 -vt 0.282650381327 0.454188883305 0.000000000000 -vt 0.285106837749 0.479603022337 0.000000000000 -vt 0.079694159329 0.435663342476 0.000000000000 -vt 0.078524023294 0.432797789574 0.000000000000 -vt 0.077620923519 0.428230971098 0.000000000000 -vt 0.079657681286 0.418213814497 0.000000000000 -vt 0.079307116568 0.423214733601 0.000000000000 -vt 0.080295994878 0.414836943150 0.000000000000 -vt 0.080963805318 0.413298457861 0.000000000000 -vt 0.081294111907 0.413456052542 0.000000000000 -vt 0.081488415599 0.414713323116 0.000000000000 -vt 0.082648865879 0.418150305748 0.000000000000 -vt 0.082757845521 0.422904253006 0.000000000000 -vt 0.082332074642 0.427900880575 0.000000000000 -vt 0.081549659371 0.432032704353 0.000000000000 -vt 0.080782778561 0.434659361839 0.000000000000 -vt 0.080355659127 0.434551537037 0.000000000000 -vt 0.079714648426 0.432231515646 0.000000000000 -vt 0.079296082258 0.428110510111 0.000000000000 -vt 0.221947401762 0.311564117670 0.000000000000 -vt 0.206676691771 0.323618710041 0.000000000000 -vt 0.234236359596 0.298808634281 0.000000000000 -vt 0.243671953678 0.288532763720 0.000000000000 -vt 0.210074737668 0.525931179523 0.000000000000 -vt 0.234980046749 0.519074082375 0.000000000000 -vt 0.258448451757 0.516759932041 0.000000000000 -vt 0.285151630640 0.516420423985 0.000000000000 -vt 0.195827364922 0.027920853347 0.000000000000 -vt 0.193216472864 0.025534208864 0.000000000000 -vt 0.208045646548 0.014590993524 0.000000000000 -vt 0.209939867258 0.017815891653 0.000000000000 -vt 0.219733223319 0.012098524719 0.000000000000 -vt 0.219577640295 0.015777334571 0.000000000000 -vt 0.231459319592 0.012075107545 0.000000000000 -vt 0.230521082878 0.016644857824 0.000000000000 -vt 0.243238985538 0.012886568904 0.000000000000 -vt 0.242090910673 0.019283901900 0.000000000000 -vt 0.254986017942 0.014112763107 0.000000000000 -vt 0.254209905863 0.020853456110 0.000000000000 -vt 0.268618255854 0.021859001368 0.000000000000 -vt 0.266599744558 0.015186753124 0.000000000000 -vt 0.278297692537 0.015581674874 0.000000000000 -vt 0.280311465263 0.022918354720 0.000000000000 -vt 0.294243395329 0.017284523696 0.000000000000 -vt 0.290962666273 0.024005178362 0.000000000000 -vt 0.296158790588 0.030226442963 0.000000000000 -vt 0.300414890051 0.029313210398 0.000000000000 -vt 0.303686618805 0.042154934257 0.000000000000 -vt 0.299199730158 0.041589122266 0.000000000000 -vt 0.303400695324 0.052850034088 0.000000000000 -vt 0.299067586660 0.051488291472 0.000000000000 -vt 0.301245510578 0.063028395176 0.000000000000 -vt 0.297050625086 0.061028119177 0.000000000000 -vt 0.188072130084 0.041658472270 0.000000000000 -vt 0.184647515416 0.040359999985 0.000000000000 -vt 0.185590237379 0.054300930351 0.000000000000 -vt 0.180999323726 0.054078709334 0.000000000000 -vt 0.186842098832 0.067733690143 0.000000000000 -vt 0.180815145373 0.066969290376 0.000000000000 -vt 0.187923297286 0.082707628608 0.000000000000 -vt 0.181074976921 0.081876814365 0.000000000000 -vt 0.187377303839 0.107746466994 0.000000000000 -vt 0.187539190054 0.120622426271 0.000000000000 -vt 0.181078135967 0.122370526195 0.000000000000 -vt 0.180750086904 0.106961801648 0.000000000000 -vt 0.181374669075 0.094601452351 0.000000000000 -vt 0.187665045261 0.095849484205 0.000000000000 -vt 0.227798283100 0.129312291741 0.000000000000 -vt 0.238564521074 0.124569609761 0.000000000000 -vt 0.243330389261 0.127270132303 0.000000000000 -vt 0.231010556221 0.133791074157 0.000000000000 -vt 0.220073655248 0.135354548693 0.000000000000 -vt 0.218523919582 0.131200432777 0.000000000000 -vt 0.206768333912 0.135661438107 0.000000000000 -vt 0.206591814756 0.131151124835 0.000000000000 -vt 0.194878339767 0.131718292832 0.000000000000 -vt 0.195264026523 0.127670004964 0.000000000000 -vt 0.297571629286 0.073909014463 0.000000000000 -vt 0.293510973454 0.071692824364 0.000000000000 -vt 0.293531447649 0.085388556123 0.000000000000 -vt 0.288804322481 0.082740962505 0.000000000000 -vt 0.284273296595 0.097582057118 0.000000000000 -vt 0.281252384186 0.094275429845 0.000000000000 -vt 0.270511358976 0.111514881253 0.000000000000 -vt 0.267813563347 0.108745023608 0.000000000000 -vt 0.253925532103 0.117747187614 0.000000000000 -vt 0.256331086159 0.121454820037 0.000000000000 -vt 0.267415255308 0.081492692232 0.000000000000 -vt 0.255906671286 0.094144165516 0.000000000000 -vt 0.244139820337 0.101001486182 0.000000000000 -vt 0.231230318546 0.105198845267 0.000000000000 -vt 0.219598352909 0.110711082816 0.000000000000 -vt 0.213647723198 0.110525771976 0.000000000000 -vt 0.198271200061 0.116921544075 0.000000000000 -vt 0.203886121511 0.110362097621 0.000000000000 -vt 0.196813777089 0.098104864359 0.000000000000 -vt 0.196252465248 0.102853164077 0.000000000000 -vt 0.272518634796 0.073012456298 0.000000000000 -vt 0.276711463928 0.062691569328 0.000000000000 -vt 0.280104994774 0.053172681481 0.000000000000 -vt 0.283575773239 0.045879449695 0.000000000000 -vt 0.283506870270 0.039421103895 0.000000000000 -vt 0.282259076834 0.030528377742 0.000000000000 -vt 0.272425651550 0.030439440161 0.000000000000 -vt 0.257659971714 0.030192218721 0.000000000000 -vt 0.247058525681 0.033215377480 0.000000000000 -vt 0.228341341019 0.025837715715 0.000000000000 -vt 0.218866378069 0.024133518338 0.000000000000 -vt 0.212634310126 0.025178913027 0.000000000000 -vt 0.200903266668 0.032452777028 0.000000000000 -vt 0.194876089692 0.044088792056 0.000000000000 -vt 0.193243041635 0.053994949907 0.000000000000 -vt 0.194931253791 0.067793801427 0.000000000000 -vt 0.198766767979 0.084062173963 0.000000000000 -vt 0.206359907985 0.094736546278 0.000000000000 -vt 0.212366148829 0.098234102130 0.000000000000 -vt 0.217166453600 0.096218973398 0.000000000000 -vt 0.205443292856 0.087112799287 0.000000000000 -vt 0.226509511471 0.090840920806 0.000000000000 -vt 0.237037748098 0.087899029255 0.000000000000 -vt 0.246875688434 0.081057921052 0.000000000000 -vt 0.256278872490 0.072482436895 0.000000000000 -vt 0.260736495256 0.057795342058 0.000000000000 -vt 0.259254723787 0.064904838800 0.000000000000 -vt 0.272691100836 0.038979575038 0.000000000000 -vt 0.262009739876 0.038989257067 0.000000000000 -vt 0.276944041252 0.045822035521 0.000000000000 -vt 0.268426418304 0.047114204615 0.000000000000 -vt 0.269619315863 0.043809827417 0.000000000000 -vt 0.253669768572 0.045147921890 0.000000000000 -vt 0.248847588897 0.056667540222 0.000000000000 -vt 0.246177032590 0.064497530460 0.000000000000 -vt 0.239239543676 0.071869567037 0.000000000000 -vt 0.232059359550 0.077080324292 0.000000000000 -vt 0.222070574760 0.079870447516 0.000000000000 -vt 0.206698760390 0.074161648750 0.000000000000 -vt 0.213897421956 0.072432681918 0.000000000000 -vt 0.205729246140 0.062620416284 0.000000000000 -vt 0.203790888190 0.054370727390 0.000000000000 -vt 0.204770088196 0.045650247484 0.000000000000 -vt 0.208388775587 0.038391694427 0.000000000000 -vt 0.216515302658 0.032267022878 0.000000000000 -vt 0.221525013447 0.031139671803 0.000000000000 -vt 0.229856431484 0.032532032579 0.000000000000 -vt 0.240117192268 0.040356174111 0.000000000000 -vt 0.238003432751 0.049525838345 0.000000000000 -vt 0.230851382017 0.062317129225 0.000000000000 -vt 0.223892956972 0.068100020289 0.000000000000 -vt 0.218158707023 0.060949768871 0.000000000000 -vt 0.224889278412 0.055608633906 0.000000000000 -vt 0.231338173151 0.044668566436 0.000000000000 -vt 0.224949836731 0.040866594762 0.000000000000 -vt 0.220517441630 0.039209909737 0.000000000000 -vt 0.215718701482 0.043925788254 0.000000000000 -vt 0.211569100618 0.049045812339 0.000000000000 -vt 0.212551221251 0.054835002869 0.000000000000 -vt 0.219418004155 0.048615094274 0.000000000000 -vt 0.177896246314 0.039324510843 0.000000000000 -vt 0.189204439521 0.020011376590 0.000000000000 -vt 0.204814672470 0.008875429630 0.000000000000 -vt 0.218808963895 0.005773015320 0.000000000000 -vt 0.232130467892 0.004795841873 0.000000000000 -vt 0.243434399366 0.006405927241 0.000000000000 -vt 0.255707651377 0.007152091712 0.000000000000 -vt 0.266037523746 0.008445382118 0.000000000000 -vt 0.276542603970 0.009638480842 0.000000000000 -vt 0.291882872581 0.013886258006 0.000000000000 -vt 0.305758953094 0.026801381260 0.000000000000 -vt 0.310110300779 0.042010162026 0.000000000000 -vt 0.309658646584 0.054701257497 0.000000000000 -vt 0.307640582323 0.066039174795 0.000000000000 -vt 0.304315268993 0.075605571270 0.000000000000 -vt 0.302689433098 0.083687961102 0.000000000000 -vt 0.289600938559 0.101637110114 0.000000000000 -vt 0.275979250669 0.114943787456 0.000000000000 -vt 0.261293739080 0.125751689076 0.000000000000 -vt 0.248583957553 0.132909372449 0.000000000000 -vt 0.218775406480 0.143254563212 0.000000000000 -vt 0.228658616543 0.143950298429 0.000000000000 -vt 0.206840604544 0.142785564065 0.000000000000 -vt 0.190907508135 0.138325244188 0.000000000000 -vt 0.181003153324 0.126772314310 0.000000000000 -vt 0.174718171358 0.105727061629 0.000000000000 -vt 0.175457358360 0.093386068940 0.000000000000 -vt 0.176170423627 0.080959752202 0.000000000000 -vt 0.175519734621 0.067012742162 0.000000000000 -vt 0.174860477448 0.054189030081 0.000000000000 -vt 0.175442948937 0.118314579129 0.000000000000 -vt 0.299658834934 0.013686995953 0.000000000000 -vt 0.297007620335 0.015501294285 0.000000000000 -vt 0.296986013651 0.094732716680 0.000000000000 -vt 0.178140535951 0.121313422918 0.000000000000 -vt 0.178094834089 0.129377126694 0.000000000000 -vt 0.290370285511 0.010927941650 0.000000000000 -vt 0.240662753582 0.138773083687 0.000000000000 -vt 0.059489179403 0.582100212574 0.000000000000 -vt 0.068415686488 0.582416296005 0.000000000000 -vt 0.067261539400 0.606926023960 0.000000000000 -vt 0.058599364012 0.606609225273 0.000000000000 -vt 0.050634499639 0.581815600395 0.000000000000 -vt 0.050033342093 0.606300354004 0.000000000000 -vt 0.041638877243 0.581597447395 0.000000000000 -vt 0.041299115866 0.606083035469 0.000000000000 -vt 0.032489020377 0.581519067287 0.000000000000 -vt 0.032466728240 0.605973839760 0.000000000000 -vt 0.023544281721 0.581574916840 0.000000000000 -vt 0.023710895330 0.605970263481 0.000000000000 -vt 0.077301658690 0.582797050476 0.000000000000 -vt 0.075893089175 0.607333362103 0.000000000000 -vt 0.035480882972 0.775563001633 0.000000000000 -vt 0.040293347090 0.776472151279 0.000000000000 -vt 0.036699648947 0.779854416847 0.000000000000 -vt 0.032038930804 0.777974605560 0.000000000000 -vt 0.044753897935 0.775144159794 0.000000000000 -vt 0.049120556563 0.776610195637 0.000000000000 -vt 0.044636141509 0.779394447803 0.000000000000 -vt 0.050690788776 0.780745148659 0.000000000000 -vt 0.054302733392 0.776831269264 0.000000000000 -vt 0.056948300451 0.779902398586 0.000000000000 -vt 0.057442288846 0.767054140568 0.000000000000 -vt 0.051350947469 0.766096353531 0.000000000000 -vt 0.045185070485 0.765643537045 0.000000000000 -vt 0.039071660489 0.765589058399 0.000000000000 -vt 0.032788928598 0.766110718250 0.000000000000 -vt 0.026467472315 0.767407417297 0.000000000000 -vt 0.063698008657 0.768436372280 0.000000000000 -vt 0.410184800625 0.205661505461 0.000000000000 -vt 0.061233457178 0.523812234402 0.000000000000 -vt 0.070765629411 0.524310529232 0.000000000000 -vt 0.069685108960 0.554912924767 0.000000000000 -vt 0.060390468687 0.554528176785 0.000000000000 -vt 0.053767081350 0.729990005493 0.000000000000 -vt 0.061261150986 0.730732798576 0.000000000000 -vt 0.054995980114 0.702194809914 0.000000000000 -vt 0.062634825706 0.702704548836 0.000000000000 -vt 0.064006246626 0.678737044334 0.000000000000 -vt 0.055990491062 0.678335130215 0.000000000000 -vt 0.056928943843 0.654432654381 0.000000000000 -vt 0.065110854805 0.654795587063 0.000000000000 -vt 0.066195428371 0.630862057209 0.000000000000 -vt 0.057763587683 0.630513489246 0.000000000000 -vt 0.051746767014 0.523659586906 0.000000000000 -vt 0.051160465926 0.554318308830 0.000000000000 -vt 0.046276170760 0.729541480541 0.000000000000 -vt 0.047176342458 0.701836824417 0.000000000000 -vt 0.047830644995 0.678016304970 0.000000000000 -vt 0.048644352704 0.654150307178 0.000000000000 -vt 0.049303833395 0.630233883858 0.000000000000 -vt 0.042389769107 0.523753523827 0.000000000000 -vt 0.041977059096 0.554233670235 0.000000000000 -vt 0.038769047707 0.729471445084 0.000000000000 -vt 0.039331037551 0.701696574688 0.000000000000 -vt 0.039704795927 0.677826702595 0.000000000000 -vt 0.040310915560 0.653930783272 0.000000000000 -vt 0.040829222649 0.630019962788 0.000000000000 -vt 0.032788697630 0.523885667324 0.000000000000 -vt 0.032603625208 0.554248988628 0.000000000000 -vt 0.031183568761 0.729752242565 0.000000000000 -vt 0.031547192484 0.701745390892 0.000000000000 -vt 0.031793061644 0.677753329277 0.000000000000 -vt 0.032022494823 0.653800427914 0.000000000000 -vt 0.032241348177 0.629892110825 0.000000000000 -vt 0.023286256939 0.523862004280 0.000000000000 -vt 0.023312594742 0.554275989532 0.000000000000 -vt 0.023615654558 0.730087935925 0.000000000000 -vt 0.023773714900 0.701748549938 0.000000000000 -vt 0.023966450244 0.677748382092 0.000000000000 -vt 0.023824151605 0.653813481331 0.000000000000 -vt 0.023755025119 0.629873633385 0.000000000000 -vt 0.080035939813 0.524939179420 0.000000000000 -vt 0.078819200397 0.555354475975 0.000000000000 -vt 0.068714916706 0.731523096561 0.000000000000 -vt 0.070204541087 0.703219473362 0.000000000000 -vt 0.071883074939 0.679210066795 0.000000000000 -vt 0.073152050376 0.655230820179 0.000000000000 -vt 0.074596188962 0.631297707558 0.000000000000 -vt 0.427655726671 0.333007007837 0.000000000000 -vt 0.440372914076 0.328327596188 0.000000000000 -vt 0.444987475872 0.344597071409 0.000000000000 -vt 0.432079792023 0.348230421543 0.000000000000 -vt 0.436833947897 0.363906830549 0.000000000000 -vt 0.449768215418 0.360880523920 0.000000000000 -vt 0.454692780972 0.378165900707 0.000000000000 -vt 0.441895663738 0.381562143564 0.000000000000 -vt 0.414691954851 0.337748318911 0.000000000000 -vt 0.419402211905 0.352767288685 0.000000000000 -vt 0.424107730389 0.368486940861 0.000000000000 -vt 0.429422736168 0.385863065720 0.000000000000 -vt 0.401303559542 0.341026574373 0.000000000000 -vt 0.406823009253 0.357325315475 0.000000000000 -vt 0.411697834730 0.372874319553 0.000000000000 -vt 0.417245209217 0.390449941158 0.000000000000 -vt 0.387970775366 0.344980746508 0.000000000000 -vt 0.393820285797 0.361572891474 0.000000000000 -vt 0.399133056402 0.377458244562 0.000000000000 -vt 0.404806077480 0.394824922085 0.000000000000 -vt 0.453473359346 0.324476778507 0.000000000000 -vt 0.466956764460 0.321778506041 0.000000000000 -vt 0.471398383379 0.338798433542 0.000000000000 -vt 0.458161979914 0.342115193605 0.000000000000 -vt 0.462697505951 0.358080714941 0.000000000000 -vt 0.475638061762 0.355021774769 0.000000000000 -vt 0.480182796717 0.372735410929 0.000000000000 -vt 0.467404156923 0.375559061766 0.000000000000 -vt 0.423334538937 0.312670528889 0.000000000000 -vt 0.433873385191 0.309838533401 0.000000000000 -vt 0.436265200377 0.312351495028 0.000000000000 -vt 0.422530740499 0.315895646811 0.000000000000 -vt 0.447797864676 0.306353360415 0.000000000000 -vt 0.450094014406 0.308744937181 0.000000000000 -vt 0.461704343557 0.302910506725 0.000000000000 -vt 0.463915377855 0.305326640606 0.000000000000 -vt 0.382604420185 0.326017051935 0.000000000000 -vt 0.392749220133 0.322181522846 0.000000000000 -vt 0.395257681608 0.324275016785 0.000000000000 -vt 0.382101863623 0.329265147448 0.000000000000 -vt 0.406064450741 0.317371100187 0.000000000000 -vt 0.408690214157 0.319537758827 0.000000000000 -vt 0.454164594412 0.389897853136 0.000000000000 -vt 0.448823004961 0.391495555639 0.000000000000 -vt 0.443516105413 0.386446684599 0.000000000000 -vt 0.456138074398 0.383067548275 0.000000000000 -vt 0.437463909388 0.395830690861 0.000000000000 -vt 0.431178033352 0.391206234694 0.000000000000 -vt 0.424428552389 0.400618851185 0.000000000000 -vt 0.419008165598 0.395644724369 0.000000000000 -vt 0.412200152874 0.404757648706 0.000000000000 -vt 0.406511843204 0.400167405605 0.000000000000 -vt 0.479276150465 0.385172754526 0.000000000000 -vt 0.473846048117 0.386270821095 0.000000000000 -vt 0.468606919050 0.380785584450 0.000000000000 -vt 0.481370300055 0.378176510334 0.000000000000 -vt 0.436999201775 0.315413832664 0.000000000000 -vt 0.423440814018 0.318899452686 0.000000000000 -vt 0.450722873211 0.311825752258 0.000000000000 -vt 0.464657485485 0.308184534311 0.000000000000 -vt 0.396297454834 0.327027112246 0.000000000000 -vt 0.382932245731 0.332121223211 0.000000000000 -vt 0.409763991833 0.322595357895 0.000000000000 -vt 0.442299365997 0.382790595293 0.000000000000 -vt 0.455049455166 0.379350900650 0.000000000000 -vt 0.429864943027 0.387207239866 0.000000000000 -vt 0.417697101831 0.391777902842 0.000000000000 -vt 0.404973804951 0.396399646997 0.000000000000 -vt 0.467713981867 0.376910001040 0.000000000000 -vt 0.480817049742 0.374158143997 0.000000000000 -vt 0.437278181314 0.316399097443 0.000000000000 -vt 0.423721343279 0.319981753826 0.000000000000 -vt 0.450930684805 0.312892526388 0.000000000000 -vt 0.464460253716 0.309410959482 0.000000000000 -vt 0.396746635437 0.328152865171 0.000000000000 -vt 0.383763283491 0.333080857992 0.000000000000 -vt 0.410141348839 0.323806256056 0.000000000000 -vt 0.371242642403 0.206788405776 0.000000000000 -vt 0.375714451075 0.200254172087 0.000000000000 -vt 0.379231601954 0.206475213170 0.000000000000 -vt 0.375783115625 0.212909027934 0.000000000000 -vt 0.383946120739 0.214252978563 0.000000000000 -vt 0.385994136333 0.206152796745 0.000000000000 -vt 0.383823841810 0.198206618428 0.000000000000 -vt 0.389040261507 0.196492955089 0.000000000000 -vt 0.391231000423 0.205955997109 0.000000000000 -vt 0.388896137476 0.215648040175 0.000000000000 -vt 0.386244505644 0.225284442306 0.000000000000 -vt 0.381366074085 0.234502539039 0.000000000000 -vt 0.377654612064 0.230434879661 0.000000000000 -vt 0.380352199078 0.177962914109 0.000000000000 -vt 0.385863542557 0.187034189701 0.000000000000 -vt 0.376735985279 0.182071089745 0.000000000000 -vt 0.400243073702 0.205795019865 0.000000000000 -vt 0.398853629827 0.194475561380 0.000000000000 -vt 0.398457139730 0.217155665159 0.000000000000 -vt 0.395268946886 0.228200212121 0.000000000000 -vt 0.391248136759 0.239007428288 0.000000000000 -vt 0.395271182060 0.183712929487 0.000000000000 -vt 0.390099167824 0.173236235976 0.000000000000 -vt 0.404895007610 0.295395046473 0.000000000000 -vt 0.401947498322 0.296175211668 0.000000000000 -vt 0.399637848139 0.292153716087 0.000000000000 -vt 0.401830643415 0.291295886040 0.000000000000 -vt 0.399310708046 0.296199768782 0.000000000000 -vt 0.397574305534 0.292755782604 0.000000000000 -vt 0.408904105425 0.288272053003 0.000000000000 -vt 0.407307982445 0.290285140276 0.000000000000 -vt 0.404559284449 0.287732571363 0.000000000000 -vt 0.406326085329 0.285840153694 0.000000000000 -vt 0.406662702560 0.292970359325 0.000000000000 -vt 0.403447926044 0.289671152830 0.000000000000 -vt 0.396660417318 0.287977755070 0.000000000000 -vt 0.398700773716 0.286984145641 0.000000000000 -vt 0.394956201315 0.288790345192 0.000000000000 -vt 0.401856094599 0.284300088882 0.000000000000 -vt 0.403861761093 0.282722651958 0.000000000000 -vt 0.400499969721 0.285655498505 0.000000000000 -vt 0.393806338310 0.283442467451 0.000000000000 -vt 0.395833194256 0.282441198826 0.000000000000 -vt 0.392093360424 0.284306377172 0.000000000000 -vt 0.399467855692 0.280218929052 0.000000000000 -vt 0.401700288057 0.278968840837 0.000000000000 -vt 0.397831201553 0.281272202730 0.000000000000 -vt 0.391297876835 0.278489261866 0.000000000000 -vt 0.393293648958 0.277554869652 0.000000000000 -vt 0.389414459467 0.279250085354 0.000000000000 -vt 0.397396445274 0.275657951832 0.000000000000 -vt 0.399793207645 0.274844229221 0.000000000000 -vt 0.395377457142 0.276584476233 0.000000000000 -vt 0.389087766409 0.272915095091 0.000000000000 -vt 0.391173362732 0.272055685520 0.000000000000 -vt 0.386810988188 0.273582458496 0.000000000000 -vt 0.395762920380 0.270275622606 0.000000000000 -vt 0.398250907660 0.270135104656 0.000000000000 -vt 0.393281280994 0.271341711283 0.000000000000 -vt 0.387520015240 0.266913384199 0.000000000000 -vt 0.389951229095 0.266276419163 0.000000000000 -vt 0.384966522455 0.267515212297 0.000000000000 -vt 0.394670933485 0.264871448278 0.000000000000 -vt 0.397267192602 0.265005409718 0.000000000000 -vt 0.392056882381 0.265746623278 0.000000000000 -vt 0.386280536652 0.262535691261 0.000000000000 -vt 0.389030128717 0.261800318956 0.000000000000 -vt 0.383825421333 0.263225555420 0.000000000000 -vt 0.394305050373 0.261209517717 0.000000000000 -vt 0.396993845701 0.261318951845 0.000000000000 -vt 0.391601622105 0.261423856020 0.000000000000 -vt 0.384926229715 0.259148895741 0.000000000000 -vt 0.388205587864 0.257940262556 0.000000000000 -vt 0.382767438889 0.261004865170 0.000000000000 -vt 0.394367873669 0.258704215288 0.000000000000 -vt 0.397562384605 0.259168028831 0.000000000000 -vt 0.391579329967 0.257740765810 0.000000000000 -vt 0.062066528946 0.497222512960 0.000000000000 -vt 0.071865737438 0.497819632292 0.000000000000 -vt 0.052253138274 0.497047573328 0.000000000000 -vt 0.042627077550 0.497259229422 0.000000000000 -vt 0.032757628709 0.497487276793 0.000000000000 -vt 0.022930733860 0.497487515211 0.000000000000 -vt 0.081421323121 0.498642355204 0.000000000000 -vt 0.408895790577 0.192783519626 0.000000000000 -vt 0.405064105988 0.180669501424 0.000000000000 -vt 0.400167405605 0.169291511178 0.000000000000 -vt 0.401480078697 0.242461070418 0.000000000000 -vt 0.405161798000 0.230870768428 0.000000000000 -vt 0.408491641283 0.218653172255 0.000000000000 -vt 0.380247503519 0.189571470022 0.000000000000 -vt 0.381086647511 0.223131284118 0.000000000000 -vt 0.420218378305 0.313499540091 0.000000000000 -vt 0.442574709654 0.393686324358 0.000000000000 -vt 0.437170535326 0.308998465538 0.000000000000 -vt 0.450992375612 0.305552929640 0.000000000000 -vt 0.395807057619 0.321048557758 0.000000000000 -vt 0.409543335438 0.316259503365 0.000000000000 -vt 0.460468471050 0.388684481382 0.000000000000 -vt 0.429571330547 0.398836284876 0.000000000000 -vt 0.417428702116 0.402817249298 0.000000000000 -vt 0.465852618217 0.387890368700 0.000000000000 -vt 0.165486067533 0.985748410225 0.000000000000 -vt 0.153918713331 0.884558439255 0.000000000000 -vt 0.153763413429 0.881860136986 0.000000000000 -vt 0.204113468528 0.982658386230 0.000000000000 -vt 0.204646229744 0.989186286926 0.000000000000 -vt 0.186044186354 0.877731442451 0.000000000000 -vt 0.185995131731 0.879323482513 0.000000000000 -vt 0.165391892195 0.991528987885 0.000000000000 -vt 0.215989306569 0.874527692795 0.000000000000 -vt 0.239299163222 0.979033589363 0.000000000000 -vt 0.216438904405 0.876245737076 0.000000000000 -vt 0.147602885962 0.884569108486 0.000000000000 -vt 0.252690643072 0.979669451714 0.000000000000 -vt 0.252580404282 0.986951112747 0.000000000000 -vt 0.149314463139 0.881703615189 0.000000000000 -vt 0.239499345422 0.986131906509 0.000000000000 -vt 0.139916136861 0.872989058495 0.000000000000 -vt 0.153603509068 0.992006182671 0.000000000000 -vt 0.153609484434 0.990444540977 0.000000000000 -vt 0.010600453243 0.824086070061 0.000000000000 -vt 0.012143557891 0.805372476578 0.000000000000 -vt 0.018072610721 0.805904865265 0.000000000000 -vt 0.018011515960 0.835803985596 0.000000000000 -vt 0.854685604572 0.394145637751 0.000000000000 -vt 0.856347262859 0.406974732876 0.000000000000 -vt 0.854803860188 0.407253265381 0.000000000000 -vt 0.852515399456 0.394508123398 0.000000000000 -vt 0.014217739925 0.786286652088 0.000000000000 -vt 0.141516894102 0.871268332005 0.000000000000 -vt 0.236085057259 0.870658397675 0.000000000000 -vt 0.235590070486 0.871755778790 0.000000000000 -vt 0.115637660027 0.902860224247 0.000000000000 -vt 0.110983915627 0.890343248844 0.000000000000 -vt 0.113721966743 0.903127968311 0.000000000000 -vt 0.108955033123 0.891542613506 0.000000000000 -vt 0.094152219594 0.932179987431 0.000000000000 -vt 0.092673666775 0.930834054947 0.000000000000 -vt 0.070010572672 0.963107407093 0.000000000000 -vt 0.068242847919 0.961778044701 0.000000000000 -vt 0.061999842525 0.971761763096 0.000000000000 -vt 0.174994021654 0.927675366402 0.000000000000 -vt 0.144831538200 0.970289051533 0.000000000000 -vt 0.200194299221 0.932316362858 0.000000000000 -vt 0.170293733478 0.964262902737 0.000000000000 -vt 0.108677349985 0.981302440166 0.000000000000 -vt 0.124079853296 0.982393920422 0.000000000000 -vt 0.078137099743 0.979704558849 0.000000000000 -vt 0.109282203019 0.983950555325 0.000000000000 -vt 0.105039052665 0.987083256245 0.000000000000 -vt 0.125474229455 0.988127648830 0.000000000000 -vt 0.111332640052 0.988403081894 0.000000000000 -vt 0.149527281523 0.983822643757 0.000000000000 -vt 0.175797849894 0.974198222160 0.000000000000 -vt 0.200493484735 0.947993755341 0.000000000000 -vt 0.202181890607 0.953875601292 0.000000000000 -vt 0.210946768522 0.941928744316 0.000000000000 -vt 0.204716980457 0.950321793556 0.000000000000 -vt 0.211182147264 0.940664827824 0.000000000000 -vt 0.221946761012 0.927524268627 0.000000000000 -vt 0.212981313467 0.939730703831 0.000000000000 -vt 0.219961285591 0.926237881184 0.000000000000 -vt 0.236418157816 0.878085970879 0.000000000000 -vt 0.009088402614 0.867007911205 0.000000000000 -vt 0.233274430037 0.900619506836 0.000000000000 -vt 0.223317831755 0.925070583820 0.000000000000 -vt 0.222155556083 0.926465988159 0.000000000000 -vt 0.221913784742 0.924954414368 0.000000000000 -vt 0.222598418593 0.927596032619 0.000000000000 -vt 0.201231330633 0.949153244495 0.000000000000 -vt 0.203538969159 0.953897118568 0.000000000000 -vt 0.818132102489 0.385249525309 0.000000000000 -vt 0.205010369420 0.951609432697 0.000000000000 -vt 0.213920146227 0.940414905548 0.000000000000 -vt 0.818589150906 0.383544415236 0.000000000000 -vt 0.780589759350 0.374358534813 0.000000000000 -vt 0.016577487811 0.868200361729 0.000000000000 -vt 0.016604727134 0.872863054276 0.000000000000 -vt 0.010927146301 0.873423874378 0.000000000000 -vt 0.781472146511 0.373139113188 0.000000000000 -vt 0.775797307491 0.355791121721 0.000000000000 -vt 0.767820060253 0.372488409281 0.000000000000 -vt 0.802661955357 0.343176126480 0.000000000000 -vt 0.212836444378 0.942034363747 0.000000000000 -vt 0.794418156147 0.332618147135 0.000000000000 -vt 0.017825072631 0.886228740215 0.000000000000 -vt 0.859027683735 0.311750322580 0.000000000000 -vt 0.856714665890 0.300876915455 0.000000000000 -vt 0.011322205886 0.886385619640 0.000000000000 -vt 0.890980184078 0.300591170788 0.000000000000 -vt 0.212094113231 0.942788124084 0.000000000000 -vt 0.234720200300 0.900862038136 0.000000000000 -vt 0.237578302622 0.878117561340 0.000000000000 -vt 0.077356182039 0.981415390968 0.000000000000 -vt 0.060611370951 0.973357379436 0.000000000000 -vt 0.105943888426 0.988982677460 0.000000000000 -vt 0.258138507605 0.974806785583 0.000000000000 -vt 0.257529258728 0.990823626518 0.000000000000 -vt 0.264203071594 0.971977353096 0.000000000000 -vt 0.263009667397 0.993429660797 0.000000000000 -vt 0.271215617657 0.974126696587 0.000000000000 -vt 0.269773542881 0.993223547935 0.000000000000 -vt 0.125471040606 0.989767909050 0.000000000000 -vt 0.110437445343 0.990312933922 0.000000000000 -vt 0.276588261127 0.979046463966 0.000000000000 -vt 0.273934006691 0.990138053894 0.000000000000 -vt 0.150033578277 0.985471129417 0.000000000000 -vt 0.176784589887 0.975747346878 0.000000000000 -vt 0.276720821857 0.986530065536 0.000000000000 -vt 0.022495752200 0.890904963017 0.000000000000 -vt 0.891464889050 0.306228846312 0.000000000000 -vt 0.904646217823 0.305932313204 0.000000000000 -vt 0.893834292889 0.301968216896 0.000000000000 -vt 0.904706299305 0.304305553436 0.000000000000 -vt 0.921183407307 0.310902148485 0.000000000000 -vt 0.906808555126 0.304849773645 0.000000000000 -vt 0.921672403812 0.309491783381 0.000000000000 -vt 0.938244044781 0.337644517422 0.000000000000 -vt 0.005772059783 0.892303645611 0.000000000000 -vt 0.024704044685 0.895432829857 0.000000000000 -vt 0.004067962989 0.897250592709 0.000000000000 -vt 0.023151105270 0.902699828148 0.000000000000 -vt 0.006364827976 0.903177917004 0.000000000000 -vt 0.019447928295 0.907367289066 0.000000000000 -vt 0.011597758159 0.909153997898 0.000000000000 -vt 0.018155282363 0.909749448299 0.000000000000 -vt 0.289794445038 0.979737758636 0.000000000000 -vt 0.289097309113 0.986868619919 0.000000000000 -vt 0.108699530363 0.986913800240 0.000000000000 -vt 0.923338353634 0.310172647238 0.000000000000 -vt 0.947028934956 0.322753190994 0.000000000000 -vt 0.017324453220 0.921973764896 0.000000000000 -vt 0.107475332916 0.990945875645 0.000000000000 -vt 0.012956982478 0.921561121941 0.000000000000 -vt 0.109573453665 0.884426295757 0.000000000000 -vt 0.020662194118 0.973094761372 0.000000000000 -vt 0.018618410453 0.972752928734 0.000000000000 -vt 0.963379323483 0.338597148657 0.000000000000 -vt 0.020546024665 0.981108963490 0.000000000000 -vt 0.018002038822 0.980931103230 0.000000000000 -vt 0.135590508580 0.867567420006 0.000000000000 -vt 0.106516152620 0.878543734550 0.000000000000 -vt 0.131759136915 0.862308800220 0.000000000000 -vt 0.101919859648 0.872579514980 0.000000000000 -vt 0.127446323633 0.855293273926 0.000000000000 -vt 0.106182672083 0.886078596115 0.000000000000 -vt 0.102917589247 0.880396783352 0.000000000000 -vt 0.099388279021 0.873800635338 0.000000000000 -vt 0.137774154544 0.865794837475 0.000000000000 -vt 0.134449630976 0.860945940018 0.000000000000 -vt 0.129994958639 0.853814363480 0.000000000000 -vt 0.098041392863 0.867455244064 0.000000000000 -vt 0.123956769705 0.849580526352 0.000000000000 -vt 0.096607387066 0.868979096413 0.000000000000 -vt 0.126601263881 0.848501205444 0.000000000000 -vt 0.095606558025 0.864713788033 0.000000000000 -vt 0.123283371329 0.847612500191 0.000000000000 -vt 0.093895524740 0.865760445595 0.000000000000 -vt 0.125174984336 0.846612274647 0.000000000000 -vt 0.090208120644 0.853443682194 0.000000000000 -vt 0.088275067508 0.855292141438 0.000000000000 -vt 0.116189479828 0.837091147900 0.000000000000 -vt 0.119325831532 0.836723268032 0.000000000000 -vt 0.133553490043 0.788949906826 0.000000000000 -vt 0.293736696243 0.986775279045 0.000000000000 -vt 0.295940577984 0.980653762817 0.000000000000 -vt 0.340545475483 0.984447240829 0.000000000000 -vt 0.340072214603 0.986525893211 0.000000000000 -vt 0.950552880764 0.345313966274 0.000000000000 -vt 0.967208921909 0.344859838486 0.000000000000 -vt 0.950094163418 0.353987187147 0.000000000000 -vt 0.933797061443 0.363659620285 0.000000000000 -vt 0.136295691133 0.788761913776 0.000000000000 -vt 0.138059511781 0.780847370625 0.000000000000 -vt 0.130408823490 0.777872502804 0.000000000000 -vt 0.131355047226 0.775953590870 0.000000000000 -vt 0.138569056988 0.778319716454 0.000000000000 -vt 0.118060231209 0.785308957100 0.000000000000 -vt 0.896019995213 0.384664356709 0.000000000000 -vt 0.115173012018 0.774169325829 0.000000000000 -vt 0.898356497288 0.351344764233 0.000000000000 -vt 0.096679173410 0.785911738873 0.000000000000 -vt 0.095730684698 0.772729396820 0.000000000000 -vt 0.104705169797 0.831313431263 0.000000000000 -vt 0.902008712292 0.319425404072 0.000000000000 -vt 0.086956694722 0.837567865849 0.000000000000 -vt 0.082478508353 0.790962874889 0.000000000000 -vt 0.833729565144 0.320394694805 0.000000000000 -vt 0.348657131195 0.984760761261 0.000000000000 -vt 0.081306569278 0.775940597057 0.000000000000 -vt 0.089978247881 0.773647964001 0.000000000000 -vt 0.829791605473 0.309479862452 0.000000000000 -vt 0.816609799862 0.333315908909 0.000000000000 -vt 0.807817518711 0.321131646633 0.000000000000 -vt 0.797316968441 0.333731085062 0.000000000000 -vt 0.795922100544 0.331054210663 0.000000000000 -vt 0.852600395679 0.366287618876 0.000000000000 -vt 0.888158023357 0.389725148678 0.000000000000 -vt 0.891561090946 0.383528649807 0.000000000000 -vt 0.892443001270 0.390044867992 0.000000000000 -vt 0.890115559101 0.403733402491 0.000000000000 -vt 0.893740594387 0.402232736349 0.000000000000 -vt 0.889661490917 0.409355312586 0.000000000000 -vt 0.859144628048 0.413082540035 0.000000000000 -vt 0.889299809933 0.416188776493 0.000000000000 -vt 0.860674321651 0.420680373907 0.000000000000 -vt 0.890587747097 0.423362225294 0.000000000000 -vt 0.861845076084 0.428339481354 0.000000000000 -vt 0.893469750881 0.431529492140 0.000000000000 -vt 0.863975346088 0.435634076595 0.000000000000 -vt 0.892712771893 0.409693717957 0.000000000000 -vt 0.893171131611 0.415372341871 0.000000000000 -vt 0.894341528416 0.422278076410 0.000000000000 -vt 0.895548760891 0.430168658495 0.000000000000 -vt 0.856991708279 0.413939237595 0.000000000000 -vt 0.858568608761 0.420849025249 0.000000000000 -vt 0.860028803349 0.428554058075 0.000000000000 -vt 0.861705243587 0.435540854931 0.000000000000 -vt 0.862937510014 0.448144823313 0.000000000000 -vt 0.865016877651 0.448156058788 0.000000000000 -vt 0.894014537334 0.443118661642 0.000000000000 -vt 0.896675527096 0.441695034504 0.000000000000 -vt 0.942015469074 0.465249389410 0.000000000000 -vt 0.938968360424 0.467184603214 0.000000000000 -vt 0.947230279446 0.471932232380 0.000000000000 -vt 0.929851353168 0.479779750109 0.000000000000 -vt 0.884821474552 0.455685496330 0.000000000000 -vt 0.911414802074 0.493092268705 0.000000000000 -vt 0.871183216572 0.461694657803 0.000000000000 -vt 0.860978066921 0.452166974545 0.000000000000 -vt 0.943686783314 0.478628307581 0.000000000000 -vt 0.933102667332 0.492131799459 0.000000000000 -vt 0.919620096684 0.505386710167 0.000000000000 -vt 0.891063272953 0.499169915915 0.000000000000 -vt 0.916852533817 0.507224857807 0.000000000000 -vt 0.908044636250 0.511230826378 0.000000000000 -vt 0.888901054859 0.516245007515 0.000000000000 -vt 0.869810879230 0.502536654472 0.000000000000 -vt 0.873295843601 0.517087996006 0.000000000000 -vt 0.852177441120 0.511175870895 0.000000000000 -vt 0.852176964283 0.514577090740 0.000000000000 -vt 0.850538194180 0.510758638382 0.000000000000 -vt 0.846698939800 0.494376987219 0.000000000000 -vt 0.847678959370 0.512833237648 0.000000000000 -vt 0.836011469364 0.506721198559 0.000000000000 -vt 0.830273568630 0.488239735365 0.000000000000 -vt 0.829936563969 0.486338347197 0.000000000000 -vt 0.858301818371 0.452152788639 0.000000000000 -vt 0.827840387821 0.498115986586 0.000000000000 -vt 0.829935252666 0.487876564264 0.000000000000 -vt 0.823986113071 0.491719275713 0.000000000000 -vt 0.069046996534 0.797405838966 0.000000000000 -vt 0.063239946961 0.785030543804 0.000000000000 -vt 0.056414369494 0.807498395443 0.000000000000 -vt 0.050693791360 0.794903695583 0.000000000000 -vt 0.038561563939 0.813347876072 0.000000000000 -vt 0.035990972072 0.810181796551 0.000000000000 -vt 0.047508850694 0.830956161022 0.000000000000 -vt 0.037681039423 0.814844489098 0.000000000000 -vt 0.029368514195 0.826868057251 0.000000000000 -vt 0.033771704882 0.815734088421 0.000000000000 -vt 0.038801524788 0.845296800137 0.000000000000 -vt 0.029519105330 0.846085309982 0.000000000000 -vt 0.027892099693 0.839723408222 0.000000000000 -vt 0.084708891809 0.852553844452 0.000000000000 -vt 0.083767443895 0.854980945587 0.000000000000 -vt 0.037650745362 0.847761273384 0.000000000000 -vt 0.114381492138 0.771946310997 0.000000000000 -vt 0.094816014171 0.771821796894 0.000000000000 -vt 0.080136142671 0.774619162083 0.000000000000 -vt 0.090211994946 0.772520661354 0.000000000000 -vt 0.095953144133 0.783221781254 0.000000000000 -vt 0.062365397811 0.784237205982 0.000000000000 -vt 0.049735300243 0.794033586979 0.000000000000 -vt 0.035117056221 0.810181081295 0.000000000000 -vt 0.028672711924 0.846871018410 0.000000000000 -vt 0.036163691431 0.812595427036 0.000000000000 -vt 0.032508853823 0.815019369125 0.000000000000 -vt 0.035413723439 0.813524901867 0.000000000000 -vt 0.028211543337 0.827950716019 0.000000000000 -vt 0.026609050110 0.839356005192 0.000000000000 -vt 0.896258294582 0.381265163422 0.000000000000 -vt 0.934112012386 0.361818969250 0.000000000000 -vt 0.059123776853 0.925175607204 0.000000000000 -vt 0.055362485349 0.926216900349 0.000000000000 -vt 0.054541967809 0.924610912800 0.000000000000 -vt 0.057503841817 0.922102153301 0.000000000000 -vt 0.059521101415 0.928506195545 0.000000000000 -vt 0.055455230176 0.928037106991 0.000000000000 -vt 0.058347843587 0.931667983532 0.000000000000 -vt 0.054807446897 0.929809391499 0.000000000000 -vt 0.056133113801 0.934393584728 0.000000000000 -vt 0.053610645235 0.931369364262 0.000000000000 -vt 0.053249321878 0.936173141003 0.000000000000 -vt 0.051895163953 0.932276666164 0.000000000000 -vt 0.049887977540 0.936500608921 0.000000000000 -vt 0.050015471876 0.932548344135 0.000000000000 -vt 0.046488307416 0.935653746128 0.000000000000 -vt 0.048176728189 0.932161509991 0.000000000000 -vt 0.043682835996 0.933717668056 0.000000000000 -vt 0.046699486673 0.931114256382 0.000000000000 -vt 0.042096994817 0.930674016476 0.000000000000 -vt 0.045871280134 0.929518997669 0.000000000000 -vt 0.041774652898 0.927204310894 0.000000000000 -vt 0.045793555677 0.927666127682 0.000000000000 -vt 0.042907558382 0.923894703388 0.000000000000 -vt 0.046437762678 0.925861775875 0.000000000000 -vt 0.045091055334 0.921195805073 0.000000000000 -vt 0.047651670873 0.924327433109 0.000000000000 -vt 0.048192583025 0.919690430164 0.000000000000 -vt 0.049426577985 0.923481881618 0.000000000000 -vt 0.051677010953 0.919228494167 0.000000000000 -vt 0.051336131990 0.923179805279 0.000000000000 -vt 0.054966412485 0.919925153255 0.000000000000 -vt 0.053134106100 0.923531472683 0.000000000000 -vt 0.063366554677 0.923810899258 0.000000000000 -vt 0.060973726213 0.919329464436 0.000000000000 -vt 0.064595483243 0.929011166096 0.000000000000 -vt 0.062306247652 0.933849632740 0.000000000000 -vt 0.059110067785 0.937792122364 0.000000000000 -vt 0.054868541658 0.941029012203 0.000000000000 -vt 0.049543462694 0.940982162952 0.000000000000 -vt 0.044648133218 0.939702689648 0.000000000000 -vt 0.040030620992 0.937077343464 0.000000000000 -vt 0.037820480764 0.932063996792 0.000000000000 -vt 0.036892317235 0.926711142063 0.000000000000 -vt 0.038925252855 0.921679198742 0.000000000000 -vt 0.042036972940 0.917214572430 0.000000000000 -vt 0.046976409853 0.915347874165 0.000000000000 -vt 0.051998518407 0.914744794369 0.000000000000 -vt 0.057310722768 0.915426671505 0.000000000000 -vt 0.067497454584 0.921644866467 0.000000000000 -vt 0.065058015287 0.917089760303 0.000000000000 -vt 0.069694779813 0.926195323467 0.000000000000 -vt 0.065975569189 0.936767637730 0.000000000000 -vt 0.062733851373 0.940771758556 0.000000000000 -vt 0.059423707426 0.944580018520 0.000000000000 -vt 0.048389576375 0.945518910885 0.000000000000 -vt 0.043406806886 0.944201171398 0.000000000000 -vt 0.038586281240 0.942701995373 0.000000000000 -vt 0.033321164548 0.933438599110 0.000000000000 -vt 0.031816206872 0.928624808788 0.000000000000 -vt 0.034770034254 0.919423639774 0.000000000000 -vt 0.037123106420 0.914970576763 0.000000000000 -vt 0.046392939985 0.910692512989 0.000000000000 -vt 0.051504157484 0.910091817379 0.000000000000 -vt 0.056533597410 0.909688174725 0.000000000000 -vt 0.071821056306 0.919187366962 0.000000000000 -vt 0.069497846067 0.914850890636 0.000000000000 -vt 0.074104093015 0.923345625401 0.000000000000 -vt 0.069763801992 0.939998447895 0.000000000000 -vt 0.066682241857 0.943804800510 0.000000000000 -vt 0.063756071031 0.947524607182 0.000000000000 -vt 0.046995721757 0.950295627117 0.000000000000 -vt 0.042247436941 0.949036777020 0.000000000000 -vt 0.037652872503 0.947865664959 0.000000000000 -vt 0.028527699411 0.934890091419 0.000000000000 -vt 0.027052603662 0.930507719517 0.000000000000 -vt 0.030363760889 0.917036354542 0.000000000000 -vt 0.032438538969 0.912907421589 0.000000000000 -vt 0.045932315290 0.905737102032 0.000000000000 -vt 0.050800107419 0.905163943768 0.000000000000 -vt 0.055495165288 0.904551923275 0.000000000000 -vt 0.050987325609 0.924352467060 0.000000000000 -vt 0.048744998872 0.925625741482 0.000000000000 -vt 0.048258863389 0.925050437450 0.000000000000 -vt 0.049704097211 0.924391329288 0.000000000000 -vt 0.054107807577 0.926788032055 0.000000000000 -vt 0.051701687276 0.929121911526 0.000000000000 -vt 0.050647579134 0.927882850170 0.000000000000 -vt 0.053451858461 0.925569355488 0.000000000000 -vt 0.052362285554 0.924720108509 0.000000000000 -vt 0.049598239362 0.926641643047 0.000000000000 -vt 0.054247222841 0.928189814091 0.000000000000 -vt 0.052564702928 0.930132806301 0.000000000000 -vt 0.053045056760 0.930693566799 0.000000000000 -vt 0.053973041475 0.929413259029 0.000000000000 -vt 0.050350688398 0.931418359280 0.000000000000 -vt 0.051625333726 0.931378662586 0.000000000000 -vt 0.048955641687 0.931039512157 0.000000000000 -vt 0.047835491598 0.930190026760 0.000000000000 -vt 0.047166489065 0.928965747356 0.000000000000 -vt 0.047026477754 0.927548825741 0.000000000000 -vt 0.047300122678 0.926310837269 0.000000000000 -vt 0.076263017952 0.889852464199 0.000000000000 -vt 0.072937078774 0.890983402729 0.000000000000 -vt 0.072223909199 0.886963069439 0.000000000000 -vt 0.073955483735 0.886285126209 0.000000000000 -vt 0.078647918999 0.887252748013 0.000000000000 -vt 0.075236566365 0.884860932827 0.000000000000 -vt 0.080082006752 0.883868515491 0.000000000000 -vt 0.075974173844 0.882985889912 0.000000000000 -vt 0.080343849957 0.880316436291 0.000000000000 -vt 0.076127000153 0.880949914455 0.000000000000 -vt 0.078979976475 0.877020061016 0.000000000000 -vt 0.075315542519 0.879069387913 0.000000000000 -vt 0.076549418271 0.874237835407 0.000000000000 -vt 0.074006743729 0.877511203289 0.000000000000 -vt 0.073425479233 0.872460305691 0.000000000000 -vt 0.072319932282 0.876525342464 0.000000000000 -vt 0.069821424782 0.872302711010 0.000000000000 -vt 0.070436544716 0.876380264759 0.000000000000 -vt 0.066397853196 0.873569548130 0.000000000000 -vt 0.068679399788 0.877089798450 0.000000000000 -vt 0.063854344189 0.876202642918 0.000000000000 -vt 0.067366369069 0.878527104855 0.000000000000 -vt 0.062428124249 0.879545271397 0.000000000000 -vt 0.066652543843 0.880400240421 0.000000000000 -vt 0.062527008355 0.883167207241 0.000000000000 -vt 0.066598244011 0.882463753223 0.000000000000 -vt 0.063823170960 0.886639058590 0.000000000000 -vt 0.067381329834 0.884392201900 0.000000000000 -vt 0.066064722836 0.889388978481 0.000000000000 -vt 0.068642385304 0.885931313038 0.000000000000 -vt 0.069291241467 0.890806376934 0.000000000000 -vt 0.070335276425 0.886830031872 0.000000000000 -vt 0.079105265439 0.894360721111 0.000000000000 -vt 0.073614127934 0.895603239536 0.000000000000 -vt 0.082558877766 0.889905154705 0.000000000000 -vt 0.084692724049 0.885016143322 0.000000000000 -vt 0.085654027760 0.879498064518 0.000000000000 -vt 0.083038873971 0.874549567699 0.000000000000 -vt 0.079515941441 0.870571315289 0.000000000000 -vt 0.074898667634 0.867442429066 0.000000000000 -vt 0.069151528180 0.867639601231 0.000000000000 -vt 0.063656993210 0.869233548641 0.000000000000 -vt 0.059899874032 0.873542368412 0.000000000000 -vt 0.057234056294 0.878605186939 0.000000000000 -vt 0.057885952294 0.884120523930 0.000000000000 -vt 0.059755094349 0.889095604420 0.000000000000 -vt 0.062920100987 0.893733680248 0.000000000000 -vt 0.068280227482 0.895384490490 0.000000000000 -vt 0.078785724938 0.900479376316 0.000000000000 -vt 0.073472566903 0.900497257710 0.000000000000 -vt 0.087039537728 0.891929209232 0.000000000000 -vt 0.089219875634 0.886968076229 0.000000000000 -vt 0.091177947819 0.882038056850 0.000000000000 -vt 0.086754925549 0.871306598186 0.000000000000 -vt 0.083158977330 0.867264211178 0.000000000000 -vt 0.079480238259 0.863445341587 0.000000000000 -vt 0.068381793797 0.862759649754 0.000000000000 -vt 0.063137896359 0.863549411297 0.000000000000 -vt 0.055807478726 0.870739161968 0.000000000000 -vt 0.052770502865 0.875079214573 0.000000000000 -vt 0.053255327046 0.885821878910 0.000000000000 -vt 0.055160112679 0.890882432461 0.000000000000 -vt 0.057204969227 0.895774066448 0.000000000000 -vt 0.068046040833 0.900283634663 0.000000000000 -vt 0.078120060265 0.905958473682 0.000000000000 -vt 0.073138959706 0.905713617802 0.000000000000 -vt 0.091880030930 0.893913924694 0.000000000000 -vt 0.093954570591 0.889196693897 0.000000000000 -vt 0.096018739045 0.884667575359 0.000000000000 -vt 0.090575344861 0.867730081081 0.000000000000 -vt 0.087147958577 0.863881051540 0.000000000000 -vt 0.083878643811 0.860125720501 0.000000000000 -vt 0.067553706467 0.857561290264 0.000000000000 -vt 0.062731571496 0.858179271221 0.000000000000 -vt 0.051463313401 0.867761790752 0.000000000000 -vt 0.048594601452 0.871683299541 0.000000000000 -vt 0.048404522240 0.887782871723 0.000000000000 -vt 0.050217278302 0.892602741718 0.000000000000 -vt 0.051908619702 0.897282183170 0.000000000000 -vt 0.067971713841 0.905510962009 0.000000000000 -vt 0.069196112454 0.884744703770 0.000000000000 -vt 0.068222053349 0.883839309216 0.000000000000 -vt 0.067552991211 0.882304251194 0.000000000000 -vt 0.068320401013 0.882175028324 0.000000000000 -vt 0.073343880475 0.884937107563 0.000000000000 -vt 0.071995504200 0.885450780392 0.000000000000 -vt 0.071372933686 0.881675302982 0.000000000000 -vt 0.073059923947 0.881411254406 0.000000000000 -vt 0.070542402565 0.885377347469 0.000000000000 -vt 0.069689460099 0.881946742535 0.000000000000 -vt 0.074404723942 0.883906543255 0.000000000000 -vt 0.074438758194 0.881199419498 0.000000000000 -vt 0.075204439461 0.881086766720 0.000000000000 -vt 0.075038559735 0.882739722729 0.000000000000 -vt 0.073512084782 0.878659069538 0.000000000000 -vt 0.074500329792 0.879579484463 0.000000000000 -vt 0.072161979973 0.877989232540 0.000000000000 -vt 0.070704765618 0.877902209759 0.000000000000 -vt 0.069342859089 0.878422200680 0.000000000000 -vt 0.068271823227 0.879460871220 0.000000000000 -vt 0.067647464573 0.880636036396 0.000000000000 -vt 0.069012485445 0.932736814022 0.000000000000 -vt 0.053315483034 0.946615636349 0.000000000000 -vt 0.034739337862 0.938278734684 0.000000000000 -vt 0.032324932516 0.923826873302 0.000000000000 -vt 0.041412316263 0.911473333836 0.000000000000 -vt 0.062483809888 0.912739932537 0.000000000000 -vt 0.072793565691 0.936362326145 0.000000000000 -vt 0.051563642919 0.951559722424 0.000000000000 -vt 0.029731415212 0.939354598522 0.000000000000 -vt 0.028038166463 0.921029269695 0.000000000000 -vt 0.041223250329 0.906235873699 0.000000000000 -vt 0.067299149930 0.910646736622 0.000000000000 -vt 0.084724672139 0.896705806255 0.000000000000 -vt 0.090130694211 0.875394165516 0.000000000000 -vt 0.073611505330 0.861880958080 0.000000000000 -vt 0.058759339154 0.866340816021 0.000000000000 -vt 0.051577635109 0.880795300007 0.000000000000 -vt 0.062752433121 0.899852573872 0.000000000000 -vt 0.089935369790 0.898496687412 0.000000000000 -vt 0.093930847943 0.871406018734 0.000000000000 -vt 0.072329230607 0.856650412083 0.000000000000 -vt 0.054085560143 0.863671362400 0.000000000000 -vt 0.046596772969 0.883146226406 0.000000000000 -vt 0.062987215817 0.905366241932 0.000000000000 -vt 0.724434196949 0.690520286560 0.000000000000 -vt 0.714673578739 0.670199394226 0.000000000000 -vt 0.738192379475 0.658733546734 0.000000000000 -vt 0.749425828457 0.679554581642 0.000000000000 -vt 0.766880452633 0.648001551628 0.000000000000 -vt 0.778476417065 0.667455196381 0.000000000000 -vt 0.658123552799 0.561918437481 0.000000000000 -vt 0.681013524532 0.545336842537 0.000000000000 -vt 0.691574394703 0.565115392208 0.000000000000 -vt 0.668605864048 0.578333139420 0.000000000000 -vt 0.678273379803 0.596119463444 0.000000000000 -vt 0.700517117977 0.582515180111 0.000000000000 -vt 0.708820402622 0.600191891193 0.000000000000 -vt 0.686416089535 0.614063024521 0.000000000000 -vt 0.693850934505 0.631938755512 0.000000000000 -vt 0.717175424099 0.619349181652 0.000000000000 -vt 0.726578891277 0.638749718666 0.000000000000 -vt 0.702835142612 0.650949716568 0.000000000000 -vt 0.727393448353 0.566789627075 0.000000000000 -vt 0.737516939640 0.584310531616 0.000000000000 -vt 0.746533215046 0.605367720127 0.000000000000 -vt 0.755558550358 0.627303957939 0.000000000000 -vt 0.717193305492 0.550311207771 0.000000000000 -vt 0.707122027874 0.527874290943 0.000000000000 -vt 0.648476541042 0.550091445446 0.000000000000 -vt 0.670800983906 0.526029586792 0.000000000000 -vt 0.796826541424 0.635315418243 0.000000000000 -vt 0.810074508190 0.653544664383 0.000000000000 -vt 0.828041613102 0.628299355507 0.000000000000 -vt 0.837326347828 0.640173137188 0.000000000000 -vt 0.784561932087 0.614920377731 0.000000000000 -vt 0.774542272091 0.593422353268 0.000000000000 -vt 0.802680790424 0.583606719971 0.000000000000 -vt 0.815609514713 0.603868663311 0.000000000000 -vt 0.744441092014 0.531438291073 0.000000000000 -vt 0.776179373264 0.512288391590 0.000000000000 -vt 0.783609092236 0.532737612724 0.000000000000 -vt 0.755129158497 0.549743592739 0.000000000000 -vt 0.697984158993 0.500902295113 0.000000000000 -vt 0.737360656261 0.508947730064 0.000000000000 -vt 0.730104506016 0.483820885420 0.000000000000 -vt 0.765154659748 0.571034491062 0.000000000000 -vt 0.792746603489 0.558559775352 0.000000000000 -vt 0.768725693226 0.492010682821 0.000000000000 -vt 0.757663547993 0.472875863314 0.000000000000 -vt 0.725043118000 0.693508327007 0.000000000000 -vt 0.750067889690 0.685739338398 0.000000000000 -vt 0.791203796864 0.399861633778 0.000000000000 -vt 0.779777586460 0.399193614721 0.000000000000 -vt 0.752974689007 0.710415661335 0.000000000000 -vt 0.804506599903 0.398513197899 0.000000000000 -vt 0.782004177570 0.452414214611 0.000000000000 -vt 0.780603945255 0.444166988134 0.000000000000 -vt 0.791876137257 0.443759024143 0.000000000000 -vt 0.793968260288 0.453128397465 0.000000000000 -vt 0.779418051243 0.435353308916 0.000000000000 -vt 0.778252422810 0.426639556885 0.000000000000 -vt 0.789694845676 0.427197962999 0.000000000000 -vt 0.790620148182 0.435532063246 0.000000000000 -vt 0.777533710003 0.418020188808 0.000000000000 -vt 0.777940571308 0.408807516098 0.000000000000 -vt 0.789442360401 0.409360051155 0.000000000000 -vt 0.789057195187 0.418372094631 0.000000000000 -vt 0.803890883923 0.427518129349 0.000000000000 -vt 0.804031312466 0.435820281506 0.000000000000 -vt 0.803060233593 0.417909622192 0.000000000000 -vt 0.802897393703 0.408120334148 0.000000000000 -vt 0.804555714130 0.443755626678 0.000000000000 -vt 0.807329356670 0.454006284475 0.000000000000 -vt 0.725099384785 0.716310918331 0.000000000000 -vt 0.779836833477 0.674231469631 0.000000000000 -vt 0.783605754375 0.697045505047 0.000000000000 -vt 0.818779408932 0.398010879755 0.000000000000 -vt 0.643724501133 0.545761525631 0.000000000000 -vt 0.628008902073 0.541231870651 0.000000000000 -vt 0.816486179829 0.407289743423 0.000000000000 -vt 0.643818080425 0.512760996819 0.000000000000 -vt 0.665438830853 0.521224975586 0.000000000000 -vt 0.815758764744 0.416817396879 0.000000000000 -vt 0.818642079830 0.444537609816 0.000000000000 -vt 0.817937195301 0.436300307512 0.000000000000 -vt 0.811494052410 0.658484101295 0.000000000000 -vt 0.816042482853 0.680989921093 0.000000000000 -vt 0.840249359608 0.645133495331 0.000000000000 -vt 0.822369277477 0.453545153141 0.000000000000 -vt 0.847676336765 0.654553532600 0.000000000000 -vt 0.848686635494 0.579840302467 0.000000000000 -vt 0.816775619984 0.426806628704 0.000000000000 -vt 0.821314275265 0.600943446159 0.000000000000 -vt 0.813257277012 0.578419387341 0.000000000000 -vt 0.838545382023 0.561789393425 0.000000000000 -vt 0.819137394428 0.502666831017 0.000000000000 -vt 0.823779404163 0.522105157375 0.000000000000 -vt 0.790229976177 0.529961049557 0.000000000000 -vt 0.781899273396 0.510464847088 0.000000000000 -vt 0.668055117130 0.483010739088 0.000000000000 -vt 0.692842900753 0.497021466494 0.000000000000 -vt 0.808572947979 0.481489390135 0.000000000000 -vt 0.704506456852 0.458266437054 0.000000000000 -vt 0.801172792912 0.554602205753 0.000000000000 -vt 0.830090582371 0.542637288570 0.000000000000 -vt 0.773884236813 0.490298360586 0.000000000000 -vt 0.726107180119 0.478320568800 0.000000000000 -vt 0.745716154575 0.441092967987 0.000000000000 -vt 0.753030359745 0.462626129389 0.000000000000 -vt 0.722523391247 0.691917836666 0.000000000000 -vt 0.749568045139 0.682414948940 0.000000000000 -vt 0.779008090496 0.670675337315 0.000000000000 -vt 0.667049825191 0.578830957413 0.000000000000 -vt 0.684892475605 0.614746153355 0.000000000000 -vt 0.676726400852 0.596634447575 0.000000000000 -vt 0.701373159885 0.652009308338 0.000000000000 -vt 0.692301928997 0.632841825485 0.000000000000 -vt 0.646996915340 0.549704909325 0.000000000000 -vt 0.667850673199 0.524221837521 0.000000000000 -vt 0.810716688633 0.655620336533 0.000000000000 -vt 0.839727461338 0.639870941639 0.000000000000 -vt 0.830280363560 0.627509713173 0.000000000000 -vt 0.818201720715 0.602329492569 0.000000000000 -vt 0.807740032673 0.580971300602 0.000000000000 -vt 0.786967098713 0.531335592270 0.000000000000 -vt 0.778827011585 0.511309623718 0.000000000000 -vt 0.695696294308 0.499585956335 0.000000000000 -vt 0.728171169758 0.480036228895 0.000000000000 -vt 0.796798646450 0.556795895100 0.000000000000 -vt 0.771090447903 0.491387873888 0.000000000000 -vt 0.755518972874 0.467876076698 0.000000000000 -vt 0.857891857624 0.600561559200 0.000000000000 -vt 0.832526981831 0.625968098640 0.000000000000 -vt 0.721892893314 0.690372586250 0.000000000000 -vt 0.713340461254 0.671590626240 0.000000000000 -vt 0.646686851978 0.550678908825 0.000000000000 -vt 0.656452476978 0.562453389168 0.000000000000 -vt 0.842236578465 0.638690054417 0.000000000000 -vt 0.764252245426 0.471054345369 0.000000000000 -vt 0.725051343441 0.691869199276 0.000000000000 -vt 0.646329224110 0.548061668873 0.000000000000 -vt 0.838410317898 0.642666935921 0.000000000000 -vt 0.759749114513 0.472487002611 0.000000000000 -# 6542 texture coords - -g Box001 -usemtl Material__283 -s 1 -f 18/3/1 17/4/2 1/1/3 -f 1/1/4 2/2/5 18/3/6 -f 19/6/7 18/3/8 2/2/9 -f 2/2/10 3/5/11 19/6/12 -f 20/8/13 19/6/14 3/5/15 -f 3/5/16 4/7/17 20/8/18 -f 21/11/19 20/12/20 4/9/21 -f 4/9/22 5/10/23 21/11/24 -f 22/14/25 21/11/26 5/10/27 -f 5/10/28 6/13/29 22/14/30 -f 23/16/31 22/14/32 6/13/33 -f 6/13/34 7/15/35 23/16/36 -f 24/18/37 23/16/38 7/15/39 -f 7/15/40 8/17/41 24/18/42 -f 25/20/43 24/18/44 8/17/45 -f 8/17/46 9/19/47 25/20/48 -f 26/22/49 25/20/50 9/19/51 -f 9/19/52 10/21/53 26/22/54 -f 27/24/55 26/22/56 10/21/57 -f 10/21/58 11/23/59 27/24/60 -f 28/26/61 27/24/62 11/23/63 -f 11/23/64 12/25/65 28/26/66 -f 29/28/67 28/26/68 12/25/69 -f 12/25/70 13/27/71 29/28/72 -f 30/30/73 29/28/74 13/27/75 -f 13/27/76 14/29/77 30/30/78 -f 31/32/79 30/30/80 14/29/81 -f 14/29/82 15/31/83 31/32/84 -f 32/34/85 31/32/86 15/31/87 -f 15/31/88 16/33/89 32/34/90 -f 17/4/91 32/34/92 16/33/93 -f 16/33/94 1/1/95 17/4/96 -f 65/37/97 67/38/98 68/35/99 -f 68/35/100 66/36/101 65/37/102 -f 67/38/103 69/40/104 70/39/105 -f 70/39/106 68/35/107 67/38/108 -f 69/40/109 71/42/110 72/41/111 -f 72/41/112 70/39/113 69/40/114 -f 71/45/115 73/46/116 74/43/117 -f 74/43/118 72/44/119 71/45/120 -f 73/46/121 75/48/122 76/47/123 -f 76/47/124 74/43/125 73/46/126 -f 75/48/127 77/50/128 78/49/129 -f 78/49/130 76/47/131 75/48/132 -f 77/50/133 79/52/134 80/51/135 -f 80/51/136 78/49/137 77/50/138 -f 79/52/139 81/54/140 82/53/141 -f 82/53/142 80/51/143 79/52/144 -f 81/54/145 83/56/146 84/55/147 -f 84/55/148 82/53/149 81/54/150 -f 83/56/151 85/58/152 86/57/153 -f 86/57/154 84/55/155 83/56/156 -f 85/58/157 87/60/158 88/59/159 -f 88/59/160 86/57/161 85/58/162 -f 87/60/163 89/62/164 90/61/165 -f 90/61/166 88/59/167 87/60/168 -f 89/62/169 91/64/170 92/63/171 -f 92/63/172 90/61/173 89/62/174 -f 91/64/175 93/66/176 94/65/177 -f 94/65/178 92/63/179 91/64/180 -f 93/66/181 95/68/182 96/67/183 -f 96/67/184 94/65/185 93/66/186 -f 95/68/187 65/37/188 66/36/189 -f 66/36/190 96/67/191 95/68/192 -f 50/71/193 49/72/194 33/69/195 -f 33/69/196 34/70/197 50/71/198 -f 51/74/199 50/71/200 34/70/201 -f 34/70/202 35/73/203 51/74/204 -f 52/76/205 51/74/206 35/73/207 -f 35/73/208 36/75/209 52/76/210 -f 53/79/211 52/80/212 36/77/213 -f 36/77/214 37/78/215 53/79/216 -f 54/82/217 53/79/218 37/78/219 -f 37/78/220 38/81/221 54/82/222 -f 55/84/223 54/82/224 38/81/225 -f 38/81/226 39/83/227 55/84/228 -f 56/86/229 55/84/230 39/83/231 -f 39/83/232 40/85/233 56/86/234 -f 57/88/235 56/86/236 40/85/237 -f 40/85/238 41/87/239 57/88/240 -f 58/90/241 57/88/242 41/87/243 -f 41/87/244 42/89/245 58/90/246 -f 59/92/247 58/90/248 42/89/249 -f 42/89/250 43/91/251 59/92/252 -f 60/94/253 59/92/254 43/91/255 -f 43/91/256 44/93/257 60/94/258 -f 61/96/259 60/94/260 44/93/261 -f 44/93/262 45/95/263 61/96/264 -f 62/98/265 61/96/266 45/95/267 -f 45/95/268 46/97/269 62/98/270 -f 63/100/271 62/98/272 46/97/273 -f 46/97/274 47/99/275 63/100/276 -f 64/102/277 63/100/278 47/99/279 -f 47/99/280 48/101/281 64/102/282 -f 49/72/283 64/102/284 48/101/285 -f 48/101/286 33/69/287 49/72/288 -f 66/36/289 68/35/290 34/70/291 -f 34/70/292 33/69/293 66/36/294 -f 67/38/295 65/37/296 17/4/297 -f 17/4/298 18/3/299 67/38/300 -f 68/35/301 70/39/302 35/73/303 -f 35/73/304 34/70/305 68/35/306 -f 69/40/307 67/38/308 18/3/309 -f 18/3/310 19/6/311 69/40/312 -f 70/39/313 72/41/314 36/75/315 -f 36/75/316 35/73/317 70/39/318 -f 71/42/319 69/40/320 19/6/321 -f 19/6/322 20/8/323 71/42/324 -f 72/44/325 74/43/326 37/78/327 -f 37/78/328 36/77/329 72/44/330 -f 73/46/331 71/45/332 20/12/333 -f 20/12/334 21/11/335 73/46/336 -f 74/43/337 76/47/338 38/81/339 -f 38/81/340 37/78/341 74/43/342 -f 75/48/343 73/46/344 21/11/345 -f 21/11/346 22/14/347 75/48/348 -f 76/47/349 78/49/350 39/83/351 -f 39/83/352 38/81/353 76/47/354 -f 77/50/355 75/48/356 22/14/357 -f 22/14/358 23/16/359 77/50/360 -f 78/49/361 80/51/362 40/85/363 -f 40/85/364 39/83/365 78/49/366 -f 79/52/367 77/50/368 23/16/369 -f 23/16/370 24/18/371 79/52/372 -f 80/51/373 82/53/374 41/87/375 -f 41/87/376 40/85/377 80/51/378 -f 81/54/379 79/52/380 24/18/381 -f 24/18/382 25/20/383 81/54/384 -f 82/53/385 84/55/386 42/89/387 -f 42/89/388 41/87/389 82/53/390 -f 83/56/391 81/54/392 25/20/393 -f 25/20/394 26/22/395 83/56/396 -f 84/55/397 86/57/398 43/91/399 -f 43/91/400 42/89/401 84/55/402 -f 85/58/403 83/56/404 26/22/405 -f 26/22/406 27/24/407 85/58/408 -f 86/57/409 88/59/410 44/93/411 -f 44/93/412 43/91/413 86/57/414 -f 87/60/415 85/58/416 27/24/417 -f 27/24/418 28/26/419 87/60/420 -f 88/59/421 90/61/422 45/95/423 -f 45/95/424 44/93/425 88/59/426 -f 89/62/427 87/60/428 28/26/429 -f 28/26/430 29/28/431 89/62/432 -f 90/61/433 92/63/434 46/97/435 -f 46/97/436 45/95/437 90/61/438 -f 91/64/439 89/62/440 29/28/441 -f 29/28/442 30/30/443 91/64/444 -f 92/63/445 94/65/446 47/99/447 -f 47/99/448 46/97/449 92/63/450 -f 93/66/451 91/64/452 30/30/453 -f 30/30/454 31/32/455 93/66/456 -f 94/65/457 96/67/458 48/101/459 -f 48/101/460 47/99/461 94/65/462 -f 95/68/463 93/66/464 31/32/465 -f 31/32/466 32/34/467 95/68/468 -f 96/67/469 66/36/470 33/69/471 -f 33/69/472 48/101/473 96/67/474 -f 65/37/475 95/68/476 32/34/477 -f 32/34/478 17/4/479 65/37/480 -f 188/103/481 158/104/482 108/105/483 -f 108/105/484 158/104/485 135/106/486 -f 99/107/487 190/108/488 114/109/489 -f 151/110/490 140/111/491 131/112/492 -f 142/113/493 133/114/494 149/115/495 -f 113/116/496 145/117/497 132/118/498 -f 109/119/499 121/120/500 181/121/501 -f 123/122/502 119/123/503 102/124/504 -f 177/125/505 130/126/506 141/127/507 -f 176/128/508 135/106/509 167/129/510 -f 138/130/511 143/131/512 111/132/513 -f 116/133/514 123/122/515 130/126/516 -f 104/134/517 150/135/518 183/136/519 -f 150/135/520 179/137/521 162/138/522 -f 120/139/523 189/140/524 153/141/525 -f 168/142/526 152/143/527 122/144/528 -f 152/143/529 161/145/530 122/144/531 -f 176/128/532 167/129/533 124/146/534 -f 192/147/535 185/148/536 97/149/537 -f 192/147/538 100/150/539 185/148/540 -f 134/151/541 163/152/542 101/153/543 -f 175/154/544 180/155/545 127/156/546 -f 143/131/547 181/121/548 184/157/549 -f 169/158/550 103/159/551 174/160/552 -f 165/161/553 145/117/554 113/116/555 -f 120/139/556 153/141/557 159/162/558 -f 142/113/559 114/109/560 133/114/561 -f 115/163/562 128/164/563 172/165/564 -f 115/163/565 172/165/566 117/166/567 -f 107/167/568 125/168/569 166/169/570 -f 177/125/571 116/133/572 130/126/573 -f 125/168/574 117/166/575 166/169/576 -f 166/169/577 182/170/578 157/171/579 -f 104/134/580 183/136/581 118/172/582 -f 131/112/583 155/173/584 106/174/585 -f 100/150/586 121/120/587 109/119/588 -f 162/138/589 189/140/590 120/139/591 -f 175/154/592 106/174/593 180/155/594 -f 121/120/595 136/175/596 181/121/597 -f 122/144/598 128/164/599 170/176/600 -f 103/159/601 123/122/602 116/133/603 -f 181/121/604 136/175/605 123/122/606 -f 99/107/607 186/177/608 190/108/609 -f 122/144/610 144/178/611 128/164/612 -f 115/163/613 117/166/614 125/168/615 -f 129/179/616 126/180/617 191/181/618 -f 109/119/619 181/121/620 143/131/621 -f 127/156/622 112/182/623 137/183/624 -f 159/162/625 153/141/626 112/182/627 -f 128/164/628 144/178/629 164/184/630 -f 128/164/631 164/184/632 172/165/633 -f 129/179/634 173/185/635 126/180/636 -f 188/103/637 185/148/638 158/104/639 -f 123/122/640 102/124/641 130/126/642 -f 141/127/643 130/126/644 156/186/645 -f 186/177/646 175/154/647 190/108/648 -f 175/154/649 127/156/650 137/183/651 -f 130/126/652 102/124/653 156/186/654 -f 110/187/655 133/114/656 114/109/657 -f 133/114/658 134/151/659 149/115/660 -f 97/149/661 185/148/662 188/103/663 -f 147/188/664 152/143/665 168/142/666 -f 190/108/667 175/154/668 137/183/669 -f 133/114/670 110/187/671 178/189/672 -f 135/106/673 154/190/674 167/129/675 -f 138/130/676 171/191/677 104/134/678 -f 136/175/679 119/123/680 123/122/681 -f 139/192/682 119/123/683 136/175/684 -f 137/183/685 112/182/686 134/151/687 -f 133/114/688 178/189/689 134/151/690 -f 138/130/691 104/134/692 135/106/693 -f 191/181/694 126/180/695 138/130/696 -f 112/182/697 163/152/698 134/151/699 -f 112/182/700 98/193/701 165/161/702 -f 139/192/703 136/175/704 121/120/705 -f 100/150/706 139/192/707 121/120/708 -f 131/112/709 140/111/710 155/173/711 -f 154/190/712 118/172/713 167/129/714 -f 141/127/715 156/186/716 98/193/717 -f 153/141/718 98/193/719 112/182/720 -f 166/169/721 117/166/722 182/170/723 -f 117/166/724 160/194/725 182/170/726 -f 126/180/727 143/131/728 138/130/729 -f 173/185/730 143/131/731 126/180/732 -f 144/178/733 146/195/734 164/184/735 -f 161/145/736 176/128/737 124/146/738 -f 98/193/739 145/117/740 165/161/741 -f 98/193/742 132/118/743 145/117/744 -f 161/145/745 124/146/746 144/178/747 -f 124/146/748 140/111/749 146/195/750 -f 97/149/751 152/143/752 147/188/753 -f 177/125/754 148/196/755 116/133/756 -f 103/159/757 116/133/758 174/160/759 -f 134/151/760 101/153/761 149/115/762 -f 169/158/763 179/137/764 150/135/765 -f 138/130/766 111/132/767 171/191/768 -f 140/111/769 151/110/770 146/195/771 -f 146/195/772 151/110/773 164/184/774 -f 152/143/775 97/149/776 188/103/777 -f 188/103/778 108/105/779 152/143/780 -f 105/197/781 141/127/782 153/141/783 -f 141/127/784 98/193/785 153/141/786 -f 135/106/787 104/134/788 154/190/789 -f 154/190/790 104/134/791 118/172/792 -f 122/144/793 161/145/794 144/178/795 -f 155/173/796 118/172/797 106/174/798 -f 167/129/799 118/172/800 155/173/801 -f 98/193/802 156/186/803 132/118/804 -f 142/113/805 149/115/806 157/171/807 -f 129/179/808 191/181/809 158/104/810 -f 158/104/811 185/148/812 129/179/813 -f 120/139/814 159/162/815 127/156/816 -f 127/156/817 159/162/818 112/182/819 -f 160/194/820 114/109/821 142/113/822 -f 99/107/823 114/109/824 160/194/825 -f 108/105/826 161/145/827 152/143/828 -f 176/128/829 108/105/830 135/106/831 -f 118/172/832 162/138/833 106/174/834 -f 106/174/835 162/138/836 120/139/837 -f 165/161/838 113/116/839 163/152/840 -f 164/184/841 186/177/842 99/107/843 -f 164/184/844 99/107/845 172/165/846 -f 112/182/847 165/161/848 163/152/849 -f 167/129/850 155/173/851 140/111/852 -f 124/146/853 167/129/854 140/111/855 -f 100/150/856 109/119/857 185/148/858 -f 109/119/859 143/131/860 173/185/861 -f 189/140/862 105/197/863 153/141/864 -f 170/176/865 125/168/866 107/167/867 -f 172/165/868 99/107/869 160/194/870 -f 172/165/871 160/194/872 117/166/873 -f 171/191/874 111/132/875 169/158/876 -f 184/157/877 103/159/878 169/158/879 -f 187/198/880 168/142/881 122/144/882 -f 147/188/883 168/142/884 187/198/885 -f 171/191/886 150/135/887 104/134/888 -f 171/191/889 169/158/890 150/135/891 -f 109/119/892 173/185/893 185/148/894 -f 185/148/895 173/185/896 129/179/897 -f 169/158/898 174/160/899 179/137/900 -f 148/196/901 174/160/902 116/133/903 -f 131/112/904 175/154/905 186/177/906 -f 131/112/907 106/174/908 175/154/909 -f 161/145/910 108/105/911 176/128/912 -f 105/197/913 177/125/914 141/127/915 -f 177/125/916 105/197/917 189/140/918 -f 178/189/919 137/183/920 134/151/921 -f 110/187/922 137/183/923 178/189/924 -f 179/137/925 174/160/926 148/196/927 -f 179/137/928 148/196/929 162/138/930 -f 180/155/931 120/139/932 127/156/933 -f 106/174/934 120/139/935 180/155/936 -f 103/159/937 181/121/938 123/122/939 -f 184/157/940 181/121/941 103/159/942 -f 182/170/943 142/113/944 157/171/945 -f 160/194/946 142/113/947 182/170/948 -f 183/136/949 150/135/950 162/138/951 -f 118/172/952 183/136/953 162/138/954 -f 111/132/955 184/157/956 169/158/957 -f 143/131/958 184/157/959 111/132/960 -f 164/184/961 151/110/962 186/177/963 -f 151/110/964 131/112/965 186/177/966 -f 149/115/967 101/153/968 163/152/969 -f 163/152/970 113/116/971 149/115/972 -f 187/198/973 122/144/974 170/176/975 -f 189/140/976 162/138/977 148/196/978 -f 189/140/979 148/196/980 177/125/981 -f 190/108/982 137/183/983 110/187/984 -f 190/108/985 110/187/986 114/109/987 -f 191/181/988 138/130/989 135/106/990 -f 158/104/991 191/181/992 135/106/993 -f 125/168/994 170/176/995 128/164/996 -f 128/164/997 115/163/998 125/168/999 -f 124/146/1000 146/195/1001 144/178/1002 -s 2 -f 207/213/1003 205/214/1004 193/199/1005 -f 193/199/1006 195/201/1007 207/213/1008 -f 206/215/1009 208/216/1010 196/207/1011 -f 196/207/1012 194/206/1013 206/215/1014 -f 205/214/1015 215/217/1016 203/200/1017 -f 203/200/1018 193/199/1019 205/214/1020 -f 209/218/1021 207/213/1022 195/201/1023 -f 195/201/1024 197/202/1025 209/218/1026 -f 208/216/1027 210/219/1028 198/208/1029 -f 198/208/1030 196/207/1031 208/216/1032 -f 213/221/1033 201/222/1034 253/211/1035 -f 253/211/1036 255/220/1037 213/221/1038 -f 266/223/1039 267/209/1040 198/208/1041 -f 198/208/1042 210/219/1043 266/223/1044 -f 212/257/1045 216/258/1046 204/212/1047 -f 204/212/1048 200/224/1049 212/257/1050 -f 209/218/1051 197/202/1052 268/203/1053 -f 268/203/1054 269/259/1055 209/218/1056 -f 212/257/1057 200/224/1058 254/205/1059 -f 254/205/1060 256/260/1061 212/257/1062 -f 215/217/1063 206/215/1064 194/206/1065 -f 194/206/1066 203/200/1067 215/217/1068 -f 216/258/1069 211/261/1070 199/210/1071 -f 199/210/1072 204/212/1073 216/258/1074 -f 219/227/1075 217/228/1076 205/225/1077 -f 205/225/1078 207/226/1079 219/227/1080 -f 218/231/1081 220/232/1082 208/229/1083 -f 208/229/1084 206/230/1085 218/231/1086 -f 217/228/1087 226/234/1088 215/233/1089 -f 215/233/1090 205/225/1091 217/228/1092 -f 221/236/1093 219/227/1094 207/226/1095 -f 207/226/1096 209/235/1097 221/236/1098 -f 220/232/1099 222/266/1100 210/265/1101 -f 210/265/1102 208/229/1103 220/232/1104 -f 225/239/1105 213/240/1106 255/237/1107 -f 255/237/1108 257/238/1109 225/239/1110 -f 222/266/1111 265/268/1112 266/267/1113 -f 266/267/1114 210/265/1115 222/266/1116 -f 224/243/1117 227/244/1118 216/241/1119 -f 216/241/1120 212/242/1121 224/243/1122 -f 270/270/1123 221/236/1124 209/235/1125 -f 209/235/1126 269/269/1127 270/270/1128 -f 224/243/1129 212/242/1130 256/246/1131 -f 256/246/1132 258/247/1133 224/243/1134 -f 226/332/1135 218/231/1136 206/230/1137 -f 206/230/1138 215/331/1139 226/332/1140 -f 227/244/1141 223/249/1142 211/248/1143 -f 211/248/1144 216/241/1145 227/244/1146 -f 228/250/1147 229/251/1148 227/244/1149 -f 227/244/1150 224/243/1151 228/250/1152 -f 229/251/1153 232/252/1154 223/249/1155 -f 223/249/1156 227/244/1157 229/251/1158 -f 258/247/1159 259/253/1160 228/250/1161 -f 228/250/1162 224/243/1163 258/247/1164 -f 260/254/1165 264/255/1166 225/239/1167 -f 225/239/1168 257/238/1169 260/254/1170 -f 244/274/1171 217/228/1172 219/227/1173 -f 219/227/1174 246/272/1175 244/274/1176 -f 247/276/1177 220/232/1178 218/231/1179 -f 218/231/1180 245/275/1181 247/276/1182 -f 250/277/1183 226/234/1184 217/228/1185 -f 217/228/1186 244/274/1187 250/277/1188 -f 246/272/1189 219/227/1190 221/236/1191 -f 221/236/1192 248/278/1193 246/272/1194 -f 249/279/1195 222/266/1196 220/232/1197 -f 220/232/1198 247/276/1199 249/279/1200 -f 245/275/1201 218/231/1202 226/332/1203 -f 226/332/1204 250/333/1205 245/275/1206 -f 231/282/1207 265/268/1208 222/266/1209 -f 222/266/1210 249/279/1211 231/282/1212 -f 252/286/1213 238/287/1214 279/284/1215 -f 279/284/1216 273/285/1217 252/286/1218 -f 273/285/1219 271/290/1220 242/288/1221 -f 242/288/1222 252/286/1223 273/285/1224 -f 291/294/1225 241/295/1226 289/245/1227 -f 289/245/1228 290/283/1229 291/294/1230 -f 241/295/1231 281/297/1232 288/296/1233 -f 288/296/1234 289/245/1235 241/295/1236 -f 283/299/1237 241/295/1238 291/294/1239 -f 291/294/1240 282/298/1241 283/299/1242 -f 281/297/1243 241/295/1244 283/299/1245 -f 283/299/1246 284/300/1247 281/297/1248 -f 263/262/1249 264/255/1250 260/254/1251 -f 260/254/1252 261/256/1253 263/262/1254 -f 261/256/1255 229/251/1256 228/250/1257 -f 228/250/1258 259/253/1259 261/256/1260 -f 275/306/1261 244/274/1262 246/272/1263 -f 246/272/1264 277/291/1265 275/306/1266 -f 247/276/1267 245/275/1268 276/307/1269 -f 276/307/1270 278/308/1271 247/276/1272 -f 280/309/1273 250/277/1274 244/274/1275 -f 244/274/1276 275/306/1277 280/309/1278 -f 246/272/1279 248/278/1280 279/284/1281 -f 279/284/1282 277/291/1283 246/272/1284 -f 274/310/1285 249/279/1286 247/276/1287 -f 247/276/1288 278/308/1289 274/310/1290 -f 245/275/1291 250/333/1292 280/334/1293 -f 280/334/1294 276/307/1295 245/275/1296 -f 233/311/1297 248/278/1298 221/236/1299 -f 221/236/1300 270/270/1301 233/311/1302 -f 272/312/1303 231/282/1304 249/279/1305 -f 249/279/1306 274/310/1307 272/312/1308 -f 272/312/1309 251/313/1310 242/288/1311 -f 242/288/1312 271/290/1313 272/312/1314 -f 255/220/1315 253/211/1316 199/210/1317 -f 199/210/1318 211/261/1319 255/220/1320 -f 256/260/1321 254/205/1322 202/204/1323 -f 202/204/1324 214/271/1325 256/260/1326 -f 257/238/1327 255/237/1328 211/248/1329 -f 211/248/1330 223/249/1331 257/238/1332 -f 258/247/1333 256/246/1334 214/263/1335 -f 214/263/1336 230/264/1337 258/247/1338 -f 259/253/1339 258/247/1340 230/264/1341 -f 230/264/1342 262/273/1343 259/253/1344 -f 232/252/1345 260/254/1346 257/238/1347 -f 257/238/1348 223/249/1349 232/252/1350 -f 261/256/1351 260/254/1352 232/252/1353 -f 232/252/1354 229/251/1355 261/256/1356 -f 263/262/1357 261/256/1358 259/253/1359 -f 259/253/1360 262/273/1361 263/262/1362 -f 231/281/1363 262/273/1364 230/264/1365 -f 230/264/1366 265/280/1367 231/281/1368 -f 243/289/1369 263/262/1370 262/273/1371 -f 262/273/1372 231/281/1373 243/289/1374 -f 264/255/1375 263/262/1376 243/289/1377 -f 243/289/1378 233/292/1379 264/255/1380 -f 270/293/1381 225/239/1382 264/255/1383 -f 264/255/1384 233/292/1385 270/293/1386 -f 266/304/1387 265/280/1388 230/264/1389 -f 230/264/1390 214/263/1391 266/304/1392 -f 267/209/1393 266/223/1394 214/271/1395 -f 214/271/1396 202/204/1397 267/209/1398 -f 269/259/1399 268/203/1400 201/222/1401 -f 201/222/1402 213/221/1403 269/259/1404 -f 225/239/1405 270/293/1406 269/305/1407 -f 269/305/1408 213/240/1409 225/239/1410 -f 243/314/1411 271/290/1412 273/285/1413 -f 273/285/1414 233/311/1415 243/314/1416 -f 231/282/1417 272/312/1418 271/290/1419 -f 271/290/1420 243/314/1421 231/282/1422 -f 234/316/1423 275/306/1424 277/291/1425 -f 277/291/1426 236/315/1427 234/316/1428 -f 278/308/1429 276/307/1430 235/317/1431 -f 235/317/1432 237/318/1433 278/308/1434 -f 240/319/1435 280/309/1436 275/306/1437 -f 275/306/1438 234/316/1439 240/319/1440 -f 277/291/1441 279/284/1442 238/287/1443 -f 238/287/1444 236/315/1445 277/291/1446 -f 239/320/1447 274/310/1448 278/308/1449 -f 278/308/1450 237/318/1451 239/320/1452 -f 276/307/1453 280/334/1454 240/335/1455 -f 240/335/1456 235/317/1457 276/307/1458 -f 251/313/1459 272/312/1460 274/310/1461 -f 274/310/1462 239/320/1463 251/313/1464 -f 273/285/1465 279/284/1466 248/278/1467 -f 248/278/1468 233/311/1469 273/285/1470 -f 281/297/1471 284/300/1472 285/301/1473 -f 285/301/1474 286/302/1475 281/297/1476 -f 287/303/1477 288/296/1478 281/297/1479 -f 281/297/1480 286/302/1481 287/303/1482 -f 283/321/1483 282/322/1484 234/316/1485 -f 234/316/1486 236/315/1487 283/321/1488 -f 284/323/1489 283/321/1490 236/315/1491 -f 236/315/1492 238/287/1493 284/323/1494 -f 285/324/1495 284/323/1496 238/287/1497 -f 238/287/1498 252/286/1499 285/324/1500 -f 286/325/1501 285/324/1502 252/286/1503 -f 252/286/1504 242/288/1505 286/325/1506 -f 287/326/1507 286/325/1508 242/288/1509 -f 242/288/1510 251/313/1511 287/326/1512 -f 288/327/1513 287/326/1514 251/313/1515 -f 251/313/1516 239/320/1517 288/327/1518 -f 289/328/1519 288/327/1520 239/320/1521 -f 239/320/1522 237/318/1523 289/328/1524 -f 290/329/1525 289/328/1526 237/318/1527 -f 237/318/1528 235/317/1529 290/329/1530 -f 291/330/1531 290/329/1532 235/317/1533 -f 235/317/1534 240/335/1535 291/330/1536 -f 282/322/1537 291/336/1538 240/319/1539 -f 240/319/1540 234/316/1541 282/322/1542 -s 1 -f 294/337/1543 292/339/1544 304/351/1545 -f 304/351/1546 306/352/1547 294/337/1548 -f 293/345/1549 295/344/1550 307/353/1551 -f 307/353/1552 305/354/1553 293/345/1554 -f 292/339/1555 302/338/1556 314/355/1557 -f 314/355/1558 304/351/1559 292/339/1560 -f 296/340/1561 294/337/1562 306/352/1563 -f 306/352/1564 308/356/1565 296/340/1566 -f 295/344/1567 297/346/1568 309/357/1569 -f 309/357/1570 307/353/1571 295/344/1572 -f 354/360/1573 352/349/1574 300/358/1575 -f 300/358/1576 312/359/1577 354/360/1578 -f 309/357/1579 297/346/1580 366/347/1581 -f 366/347/1582 365/361/1583 309/357/1584 -f 299/396/1585 303/348/1586 315/362/1587 -f 315/362/1588 311/395/1589 299/396/1590 -f 368/397/1591 367/341/1592 296/340/1593 -f 296/340/1594 308/356/1595 368/397/1596 -f 355/398/1597 353/342/1598 299/396/1599 -f 299/396/1600 311/395/1601 355/398/1602 -f 302/338/1603 293/345/1604 305/354/1605 -f 305/354/1606 314/355/1607 302/338/1608 -f 303/348/1609 298/350/1610 310/399/1611 -f 310/399/1612 315/362/1613 303/348/1614 -f 306/365/1615 304/366/1616 316/363/1617 -f 316/363/1618 318/364/1619 306/365/1620 -f 305/369/1621 307/370/1622 319/367/1623 -f 319/367/1624 317/368/1625 305/369/1626 -f 304/366/1627 314/372/1628 325/371/1629 -f 325/371/1630 316/363/1631 304/366/1632 -f 308/374/1633 306/365/1634 318/364/1635 -f 318/364/1636 320/373/1637 308/374/1638 -f 307/370/1639 309/404/1640 321/403/1641 -f 321/403/1642 319/367/1643 307/370/1644 -f 356/377/1645 354/378/1646 312/375/1647 -f 312/375/1648 324/376/1649 356/377/1650 -f 309/404/1651 365/406/1652 364/405/1653 -f 364/405/1654 321/403/1655 309/404/1656 -f 311/381/1657 315/382/1658 326/379/1659 -f 326/379/1660 323/380/1661 311/381/1662 -f 368/408/1663 308/374/1664 320/373/1665 -f 320/373/1666 369/407/1667 368/408/1668 -f 357/384/1669 355/385/1670 311/381/1671 -f 311/381/1672 323/380/1673 357/384/1674 -f 314/470/1675 305/369/1676 317/368/1677 -f 317/368/1678 325/469/1679 314/470/1680 -f 315/382/1681 310/387/1682 322/386/1683 -f 322/386/1684 326/379/1685 315/382/1686 -f 323/380/1687 326/379/1688 328/388/1689 -f 328/388/1690 327/389/1691 323/380/1692 -f 326/379/1693 322/386/1694 331/390/1695 -f 331/390/1696 328/388/1697 326/379/1698 -f 323/380/1699 327/389/1700 358/391/1701 -f 358/391/1702 357/384/1703 323/380/1704 -f 356/377/1705 324/376/1706 363/392/1707 -f 363/392/1708 359/393/1709 356/377/1710 -f 345/412/1711 318/364/1712 316/363/1713 -f 316/363/1714 343/410/1715 345/412/1716 -f 344/414/1717 317/368/1718 319/367/1719 -f 319/367/1720 346/413/1721 344/414/1722 -f 343/410/1723 316/363/1724 325/371/1725 -f 325/371/1726 349/415/1727 343/410/1728 -f 347/416/1729 320/373/1730 318/364/1731 -f 318/364/1732 345/412/1733 347/416/1734 -f 346/413/1735 319/367/1736 321/403/1737 -f 321/403/1738 348/417/1739 346/413/1740 -f 349/471/1741 325/469/1742 317/368/1743 -f 317/368/1744 344/414/1745 349/471/1746 -f 348/417/1747 321/403/1748 364/405/1749 -f 364/405/1750 330/420/1751 348/417/1752 -f 372/424/1753 378/425/1754 337/422/1755 -f 337/422/1756 351/423/1757 372/424/1758 -f 351/423/1759 341/428/1760 370/426/1761 -f 370/426/1762 372/424/1763 351/423/1764 -f 389/432/1765 388/433/1766 340/383/1767 -f 340/383/1768 390/421/1769 389/432/1770 -f 388/433/1771 387/435/1772 380/434/1773 -f 380/434/1774 340/383/1775 388/433/1776 -f 381/437/1777 390/421/1778 340/383/1779 -f 340/383/1780 382/436/1781 381/437/1782 -f 383/438/1783 382/436/1784 340/383/1785 -f 340/383/1786 380/434/1787 383/438/1788 -f 360/400/1789 359/393/1790 363/392/1791 -f 363/392/1792 362/394/1793 360/400/1794 -f 358/391/1795 327/389/1796 328/388/1797 -f 328/388/1798 360/400/1799 358/391/1800 -f 376/444/1801 345/412/1802 343/410/1803 -f 343/410/1804 374/429/1805 376/444/1806 -f 377/445/1807 375/446/1808 344/414/1809 -f 344/414/1810 346/413/1811 377/445/1812 -f 374/429/1813 343/410/1814 349/415/1815 -f 349/415/1816 379/447/1817 374/429/1818 -f 376/444/1819 378/425/1820 347/416/1821 -f 347/416/1822 345/412/1823 376/444/1824 -f 377/445/1825 346/413/1826 348/417/1827 -f 348/417/1828 373/448/1829 377/445/1830 -f 375/446/1831 379/472/1832 349/471/1833 -f 349/471/1834 344/414/1835 375/446/1836 -f 369/407/1837 320/373/1838 347/416/1839 -f 347/416/1840 332/449/1841 369/407/1842 -f 373/448/1843 348/417/1844 330/420/1845 -f 330/420/1846 371/450/1847 373/448/1848 -f 370/426/1849 341/428/1850 350/451/1851 -f 350/451/1852 371/450/1853 370/426/1854 -f 310/399/1855 298/350/1856 352/349/1857 -f 352/349/1858 354/360/1859 310/399/1860 -f 313/409/1861 301/343/1862 353/342/1863 -f 353/342/1864 355/398/1865 313/409/1866 -f 322/386/1867 310/387/1868 354/378/1869 -f 354/378/1870 356/377/1871 322/386/1872 -f 329/401/1873 313/402/1874 355/385/1875 -f 355/385/1876 357/384/1877 329/401/1878 -f 361/411/1879 329/401/1880 357/384/1881 -f 357/384/1882 358/391/1883 361/411/1884 -f 322/386/1885 356/377/1886 359/393/1887 -f 359/393/1888 331/390/1889 322/386/1890 -f 328/388/1891 331/390/1892 359/393/1893 -f 359/393/1894 360/400/1895 328/388/1896 -f 361/411/1897 358/391/1898 360/400/1899 -f 360/400/1900 362/394/1901 361/411/1902 -f 364/419/1903 329/401/1904 361/411/1905 -f 361/411/1906 330/418/1907 364/419/1908 -f 330/418/1909 361/411/1910 362/394/1911 -f 362/394/1912 342/427/1913 330/418/1914 -f 332/430/1915 342/427/1916 362/394/1917 -f 362/394/1918 363/392/1919 332/430/1920 -f 332/430/1921 363/392/1922 324/376/1923 -f 324/376/1924 369/431/1925 332/430/1926 -f 313/402/1927 329/401/1928 364/419/1929 -f 364/419/1930 365/442/1931 313/402/1932 -f 301/343/1933 313/409/1934 365/361/1935 -f 365/361/1936 366/347/1937 301/343/1938 -f 312/359/1939 300/358/1940 367/341/1941 -f 367/341/1942 368/397/1943 312/359/1944 -f 312/375/1945 368/443/1946 369/431/1947 -f 369/431/1948 324/376/1949 312/375/1950 -f 332/449/1951 372/424/1952 370/426/1953 -f 370/426/1954 342/452/1955 332/449/1956 -f 342/452/1957 370/426/1958 371/450/1959 -f 371/450/1960 330/420/1961 342/452/1962 -f 335/454/1963 376/444/1964 374/429/1965 -f 374/429/1966 333/453/1967 335/454/1968 -f 336/455/1969 334/456/1970 375/446/1971 -f 375/446/1972 377/445/1973 336/455/1974 -f 333/453/1975 374/429/1976 379/447/1977 -f 379/447/1978 339/457/1979 333/453/1980 -f 335/454/1981 337/422/1982 378/425/1983 -f 378/425/1984 376/444/1985 335/454/1986 -f 336/455/1987 377/445/1988 373/448/1989 -f 373/448/1990 338/458/1991 336/455/1992 -f 334/456/1993 339/473/1994 379/472/1995 -f 379/472/1996 375/446/1997 334/456/1998 -f 338/458/1999 373/448/2000 371/450/2001 -f 371/450/2002 350/451/2003 338/458/2004 -f 332/449/2005 347/416/2006 378/425/2007 -f 378/425/2008 372/424/2009 332/449/2010 -f 385/439/2011 384/440/2012 383/438/2013 -f 383/438/2014 380/434/2015 385/439/2016 -f 385/439/2017 380/434/2018 387/435/2019 -f 387/435/2020 386/441/2021 385/439/2022 -f 335/454/2023 333/453/2024 381/459/2025 -f 381/459/2026 382/460/2027 335/454/2028 -f 337/422/2029 335/454/2030 382/460/2031 -f 382/460/2032 383/461/2033 337/422/2034 -f 351/423/2035 337/422/2036 383/461/2037 -f 383/461/2038 384/462/2039 351/423/2040 -f 341/428/2041 351/423/2042 384/462/2043 -f 384/462/2044 385/463/2045 341/428/2046 -f 350/451/2047 341/428/2048 385/463/2049 -f 385/463/2050 386/464/2051 350/451/2052 -f 338/458/2053 350/451/2054 386/464/2055 -f 386/464/2056 387/465/2057 338/458/2058 -f 336/455/2059 338/458/2060 387/465/2061 -f 387/465/2062 388/466/2063 336/455/2064 -f 334/456/2065 336/455/2066 388/466/2067 -f 388/466/2068 389/467/2069 334/456/2070 -f 339/473/2071 334/456/2072 389/467/2073 -f 389/467/2074 390/468/2075 339/473/2076 -f 333/453/2077 339/457/2078 390/474/2079 -f 390/474/2080 381/459/2081 333/453/2082 -f 396/480/2083 398/481/2084 397/475/2085 -f 397/475/2086 1269/478/2087 396/480/2088 -f 396/480/2089 400/483/2090 399/482/2091 -f 399/482/2092 398/481/2093 396/480/2094 -f 401/487/2095 404/488/2096 403/485/2097 -f 403/485/2098 402/486/2099 401/487/2100 -f 405/490/2101 401/487/2102 402/486/2103 -f 402/486/2104 406/489/2105 405/490/2106 -f 401/487/2107 405/490/2108 407/491/2109 -f 407/491/2110 404/488/2111 401/487/2112 -f 408/494/2113 411/495/2114 410/492/2115 -f 410/492/2116 409/493/2117 408/494/2118 -f 408/494/2119 413/497/2120 412/496/2121 -f 412/496/2122 411/495/2123 408/494/2124 -f 408/494/2125 415/499/2126 414/498/2127 -f 414/498/2128 413/497/2129 408/494/2130 -f 408/494/2131 417/501/2132 416/500/2133 -f 416/500/2134 415/499/2135 408/494/2136 -f 408/494/2137 409/493/2138 418/502/2139 -f 418/502/2140 417/501/2141 408/494/2142 -f 419/505/2143 422/506/2144 421/503/2145 -f 421/503/2146 420/504/2147 419/505/2148 -f 419/505/2149 420/504/2150 424/507/2151 -f 424/507/2152 423/508/2153 419/505/2154 -f 425/511/2155 428/512/2156 427/509/2157 -f 427/509/2158 426/510/2159 425/511/2160 -f 429/514/2161 425/511/2162 426/510/2163 -f 426/510/2164 430/513/2165 429/514/2166 -f 425/515/2167 429/528/2168 431/476/2169 -f 431/476/2170 428/477/2171 425/515/2172 -f 432/517/2173 435/518/2174 434/484/2175 -f 434/484/2176 433/516/2177 432/517/2178 -f 432/517/2179 433/516/2180 437/519/2181 -f 437/519/2182 436/520/2183 432/517/2184 -f 432/517/2185 438/521/2186 400/483/2187 -f 400/483/2188 435/518/2189 432/517/2190 -f 435/518/2191 440/523/2192 439/522/2193 -f 439/522/2194 434/484/2195 435/518/2196 -f 443/526/2197 442/527/2198 441/524/2199 -f 441/524/2200 444/525/2201 443/526/2202 -f 442/527/2203 443/526/2204 434/484/2205 -f 434/484/2206 439/522/2207 442/527/2208 -f 442/527/2209 439/522/2210 445/529/2211 -f 445/529/2212 441/524/2213 442/527/2214 -f 446/532/2215 449/533/2216 448/530/2217 -f 448/530/2218 447/531/2219 446/532/2220 -f 451/534/2221 450/535/2222 449/533/2223 -f 449/533/2224 446/532/2225 451/534/2226 -f 433/516/2227 434/484/2228 443/526/2229 -f 443/526/2230 437/519/2231 433/516/2232 -f 452/538/2233 455/539/2234 454/536/2235 -f 454/536/2236 453/537/2237 452/538/2238 -f 452/538/2239 458/557/2240 457/542/2241 -f 457/542/2242 456/543/2243 452/538/2244 -f 452/538/2245 453/537/2246 459/644/2247 -f 459/644/2248 458/557/2249 452/538/2250 -f 460/544/2251 462/545/2252 457/540/2253 -f 457/540/2254 461/541/2255 460/544/2256 -f 460/544/2257 406/489/2258 402/486/2259 -f 402/486/2260 403/485/2261 460/544/2262 -f 460/544/2263 461/541/2264 463/546/2265 -f 463/546/2266 406/489/2267 460/544/2268 -f 417/501/2269 418/502/2270 464/547/2271 -f 464/547/2272 416/500/2273 417/501/2274 -f 462/545/2275 465/549/2276 456/548/2277 -f 456/548/2278 457/540/2279 462/545/2280 -f 462/545/2281 460/544/2282 466/550/2283 -f 466/550/2284 465/549/2285 462/545/2286 -f 1342/688/2287 423/508/2288 467/551/2289 -f 467/551/2290 1341/687/2291 1342/688/2292 -f 468/627/2293 471/629/2294 470/552/2295 -f 470/552/2296 469/553/2297 468/627/2298 -f 468/647/2299 473/648/2300 472/645/2301 -f 472/645/2302 471/646/2303 468/647/2304 -f 471/556/2305 475/558/2306 474/554/2307 -f 474/554/2308 470/555/2309 471/556/2310 -f 471/556/2311 472/560/2312 476/559/2313 -f 476/559/2314 475/558/2315 471/556/2316 -f 476/559/2317 478/562/2318 477/561/2319 -f 477/561/2320 475/558/2321 476/559/2322 -f 476/559/2323 465/549/2324 466/550/2325 -f 466/550/2326 478/562/2327 476/559/2328 -f 476/559/2329 472/560/2330 456/548/2331 -f 456/548/2332 465/549/2333 476/559/2334 -f 478/562/2335 480/564/2336 479/563/2337 -f 479/563/2338 477/561/2339 478/562/2340 -f 478/562/2341 466/550/2342 481/565/2343 -f 481/565/2344 480/564/2345 478/562/2346 -f 481/565/2347 483/567/2348 482/566/2349 -f 482/566/2350 480/564/2351 481/565/2352 -f 481/565/2353 403/485/2354 404/488/2355 -f 404/488/2356 483/567/2357 481/565/2358 -f 481/565/2359 466/550/2360 460/544/2361 -f 460/544/2362 403/485/2363 481/565/2364 -f 483/567/2365 485/569/2366 484/568/2367 -f 484/568/2368 482/566/2369 483/567/2370 -f 483/567/2371 404/488/2372 486/570/2373 -f 486/570/2374 485/569/2375 483/567/2376 -f 486/570/2377 488/572/2378 487/571/2379 -f 487/571/2380 485/569/2381 486/570/2382 -f 486/570/2383 490/574/2384 489/573/2385 -f 489/573/2386 488/572/2387 486/570/2388 -f 486/570/2389 404/488/2390 407/491/2391 -f 407/491/2392 490/574/2393 486/570/2394 -f 490/574/2395 464/547/2396 491/575/2397 -f 491/575/2398 489/573/2399 490/574/2400 -f 490/574/2401 407/491/2402 416/500/2403 -f 416/500/2404 464/547/2405 490/574/2406 -f 489/573/2407 493/577/2408 492/576/2409 -f 492/576/2410 488/572/2411 489/573/2412 -f 489/573/2413 491/575/2414 494/578/2415 -f 494/578/2416 493/577/2417 489/573/2418 -f 493/577/2419 496/580/2420 495/579/2421 -f 495/579/2422 492/576/2423 493/577/2424 -f 493/577/2425 494/578/2426 497/581/2427 -f 497/581/2428 496/580/2429 493/577/2430 -f 497/581/2431 494/578/2432 499/582/2433 -f 499/582/2434 498/583/2435 497/581/2436 -f 498/2584/2437 499/2583/2438 501/584/2439 -f 501/584/2440 500/585/2441 498/2584/2442 -f 501/584/2443 499/2583/2444 503/586/2445 -f 503/586/2446 502/587/2447 501/584/2448 -f 501/584/2449 505/589/2450 504/588/2451 -f 504/588/2452 500/585/2453 501/584/2454 -f 501/584/2455 502/587/2456 506/590/2457 -f 506/590/2458 505/589/2459 501/584/2460 -f 504/588/2461 505/589/2462 508/591/2463 -f 508/591/2464 507/592/2465 504/588/2466 -f 507/592/2467 508/591/2468 510/593/2469 -f 510/593/2470 509/594/2471 507/592/2472 -f 510/593/2473 508/591/2474 512/595/2475 -f 512/595/2476 511/596/2477 510/593/2478 -f 510/593/2479 514/598/2480 513/597/2481 -f 513/597/2482 509/594/2483 510/593/2484 -f 510/593/2485 511/596/2486 515/599/2487 -f 515/599/2488 514/598/2489 510/593/2490 -f 515/599/2491 511/596/2492 517/600/2493 -f 517/600/2494 516/601/2495 515/599/2496 -f 515/599/2497 519/603/2498 518/602/2499 -f 518/602/2500 514/598/2501 515/599/2502 -f 515/599/2503 516/601/2504 520/604/2505 -f 520/604/2506 519/603/2507 515/599/2508 -f 520/604/2509 516/601/2510 522/605/2511 -f 522/605/2512 521/606/2513 520/604/2514 -f 520/604/2515 484/568/2516 523/607/2517 -f 523/607/2518 519/603/2519 520/604/2520 -f 520/604/2521 521/606/2522 482/566/2523 -f 482/566/2524 484/568/2525 520/604/2526 -f 523/607/2527 524/608/2528 518/602/2529 -f 518/602/2530 519/603/2531 523/607/2532 -f 523/607/2533 487/571/2534 525/609/2535 -f 525/609/2536 524/608/2537 523/607/2538 -f 523/607/2539 484/568/2540 485/569/2541 -f 485/569/2542 487/571/2543 523/607/2544 -f 525/609/2545 527/611/2546 526/610/2547 -f 526/610/2548 524/608/2549 525/609/2550 -f 525/609/2551 492/576/2552 495/579/2553 -f 495/579/2554 527/611/2555 525/609/2556 -f 525/609/2557 487/571/2558 488/572/2559 -f 488/572/2560 492/576/2561 525/609/2562 -f 528/612/2563 513/597/2564 514/598/2565 -f 514/598/2566 518/602/2567 528/612/2568 -f 528/612/2569 518/602/2570 524/608/2571 -f 524/608/2572 526/610/2573 528/612/2574 -f 522/605/2575 531/615/2576 530/613/2577 -f 530/613/2578 529/614/2579 522/605/2580 -f 522/605/2581 516/601/2582 517/600/2583 -f 517/600/2584 531/615/2585 522/605/2586 -f 522/605/2587 529/614/2588 479/563/2589 -f 479/563/2590 521/606/2591 522/605/2592 -f 531/615/2593 533/617/2594 532/616/2595 -f 532/616/2596 530/613/2597 531/615/2598 -f 531/615/2599 517/600/2600 534/618/2601 -f 534/618/2602 533/617/2603 531/615/2604 -f 534/618/2605 536/620/2606 535/619/2607 -f 535/619/2608 533/617/2609 534/618/2610 -f 534/618/2611 512/595/2612 537/621/2613 -f 537/621/2614 536/620/2615 534/618/2616 -f 534/618/2617 517/600/2618 511/596/2619 -f 511/596/2620 512/595/2621 534/618/2622 -f 535/619/2623 538/622/2624 426/510/2625 -f 426/510/2626 427/509/2627 535/619/2628 -f 535/619/2629 536/620/2630 506/590/2631 -f 506/590/2632 538/622/2633 535/619/2634 -f 535/619/2635 427/509/2636 532/616/2637 -f 532/616/2638 533/617/2639 535/619/2640 -f 538/622/2641 539/623/2642 430/513/2643 -f 430/513/2644 426/510/2645 538/622/2646 -f 538/622/2647 506/590/2648 502/587/2649 -f 502/587/2650 539/623/2651 538/622/2652 -f 539/623/2653 410/2580/2654 411/2581/2655 -f 411/2581/2656 430/513/2657 539/623/2658 -f 539/623/2659 502/587/2660 503/586/2661 -f 503/586/2662 410/2580/2663 539/623/2664 -f 532/616/2665 427/509/2666 428/512/2667 -f 428/512/2668 540/624/2669 532/616/2670 -f 532/616/2671 540/624/2672 541/625/2673 -f 541/625/2674 530/613/2675 532/616/2676 -f 541/632/2677 540/633/2678 543/630/2679 -f 543/630/2680 542/631/2681 541/632/2682 -f 541/625/2683 544/626/2684 529/614/2685 -f 529/614/2686 530/613/2687 541/625/2688 -f 541/625/2689 542/628/2690 474/554/2691 -f 474/554/2692 544/626/2693 541/625/2694 -f 544/626/2695 477/561/2696 479/563/2697 -f 479/563/2698 529/614/2699 544/626/2700 -f 544/626/2701 474/554/2702 475/558/2703 -f 475/558/2704 477/561/2705 544/626/2706 -f 543/630/2707 547/636/2708 546/634/2709 -f 546/634/2710 545/635/2711 543/630/2712 -f 543/630/2713 540/633/2714 428/477/2715 -f 428/477/2716 547/636/2717 543/630/2718 -f 543/630/2719 545/635/2720 548/637/2721 -f 548/637/2722 542/631/2723 543/630/2724 -f 547/636/2725 550/639/2726 549/638/2727 -f 549/638/2728 546/634/2729 547/636/2730 -f 547/636/2731 428/477/2732 431/476/2733 -f 431/476/2734 550/639/2735 547/636/2736 -f 550/639/2737 552/641/2738 551/640/2739 -f 551/640/2740 549/638/2741 550/639/2742 -f 550/639/2743 431/476/2744 553/642/2745 -f 553/642/2746 552/641/2747 550/639/2748 -f 553/642/2749 555/668/2750 554/643/2751 -f 554/643/2752 552/641/2753 553/642/2754 -f 553/642/2755 557/670/2756 556/669/2757 -f 556/669/2758 555/668/2759 553/642/2760 -f 553/642/2761 431/476/2762 429/528/2763 -f 429/528/2764 557/670/2765 553/642/2766 -f 557/670/2767 559/672/2768 558/671/2769 -f 558/671/2770 556/669/2771 557/670/2772 -f 557/670/2773 429/528/2774 412/673/2775 -f 412/673/2776 559/672/2777 557/670/2778 -f 559/652/2779 561/653/2780 560/649/2781 -f 560/649/2782 558/651/2783 559/652/2784 -f 559/652/2785 412/655/2786 413/654/2787 -f 413/654/2788 561/653/2789 559/652/2790 -f 561/653/2791 563/657/2792 562/656/2793 -f 562/656/2794 560/649/2795 561/653/2796 -f 561/653/2797 413/654/2798 414/658/2799 -f 414/658/2800 563/657/2801 561/653/2802 -f 563/657/2803 565/660/2804 564/659/2805 -f 564/659/2806 562/656/2807 563/657/2808 -f 563/657/2809 414/658/2810 566/661/2811 -f 566/661/2812 565/660/2813 563/657/2814 -f 566/661/2815 463/663/2816 567/662/2817 -f 567/662/2818 565/660/2819 566/661/2820 -f 566/650/2821 405/490/2822 406/489/2823 -f 406/489/2824 463/546/2825 566/650/2826 -f 566/650/2827 414/498/2828 415/499/2829 -f 415/499/2830 405/490/2831 566/650/2832 -f 567/662/2833 568/664/2834 564/659/2835 -f 564/659/2836 565/660/2837 567/662/2838 -f 567/662/2839 570/666/2840 569/665/2841 -f 569/665/2842 568/664/2843 567/662/2844 -f 567/662/2845 463/663/2846 461/667/2847 -f 461/667/2848 570/666/2849 567/662/2850 -f 570/666/2851 458/557/2852 459/644/2853 -f 459/644/2854 569/665/2855 570/666/2856 -f 570/666/2857 461/667/2858 457/542/2859 -f 457/542/2860 458/557/2861 570/666/2862 -f 569/665/2863 572/697/2864 571/696/2865 -f 571/696/2866 568/664/2867 569/665/2868 -f 569/665/2869 459/644/2870 573/781/2871 -f 573/781/2872 572/697/2873 569/665/2874 -f 573/781/2875 575/1353/2876 574/782/2877 -f 574/782/2878 572/697/2879 573/781/2880 -f 573/781/2881 577/1355/2882 576/1354/2883 -f 576/1354/2884 575/1353/2885 573/781/2886 -f 573/781/2887 459/644/2888 453/537/2889 -f 453/537/2890 577/1355/2891 573/781/2892 -f 577/1355/2893 579/1357/2894 578/1356/2895 -f 578/1356/2896 576/1354/2897 577/1355/2898 -f 577/1355/2899 453/537/2900 454/536/2901 -f 454/536/2902 579/1357/2903 577/1355/2904 -f 576/1354/2905 581/1390/2906 580/1389/2907 -f 580/1389/2908 575/1353/2909 576/1354/2910 -f 576/1354/2911 578/1356/2912 582/1391/2913 -f 582/1391/2914 581/1390/2915 576/1354/2916 -f 581/1390/2917 1483/1393/2918 1482/1392/2919 -f 1482/1392/2920 580/1389/2921 581/1390/2922 -f 581/1390/2923 582/1391/2924 1484/1394/2925 -f 1484/1394/2926 1483/1393/2927 581/1390/2928 -f 1482/1392/2929 391/1396/2930 583/1395/2931 -f 583/1395/2932 580/1389/2933 1482/1392/2934 -f 391/1396/2935 397/475/2936 398/481/2937 -f 398/481/2938 583/1395/2939 391/1396/2940 -f 583/1395/2941 574/782/2942 575/1353/2943 -f 575/1353/2944 580/1389/2945 583/1395/2946 -f 583/1395/2947 398/481/2948 399/482/2949 -f 399/482/2950 574/782/2951 583/1395/2952 -f 574/782/2953 399/482/2954 571/696/2955 -f 571/696/2956 572/697/2957 574/782/2958 -f 571/696/2959 399/482/2960 400/483/2961 -f 400/483/2962 438/521/2963 571/696/2964 -f 571/696/2965 438/521/2966 564/659/2967 -f 564/659/2968 568/664/2969 571/696/2970 -f 564/659/2971 438/521/2972 432/517/2973 -f 432/517/2974 562/656/2975 564/659/2976 -f 562/656/2977 432/517/2978 436/520/2979 -f 436/520/2980 560/649/2981 562/656/2982 -f 560/649/2983 436/520/2984 584/1397/2985 -f 584/1397/2986 558/651/2987 560/649/2988 -f 584/676/2989 587/677/2990 586/674/2991 -f 586/674/2992 585/675/2993 584/676/2994 -f 584/1397/2995 436/520/2996 437/519/2997 -f 437/519/2998 587/1398/2999 584/1397/3000 -f 584/676/3001 585/675/3002 556/669/3003 -f 556/669/3004 558/671/3005 584/676/3006 -f 586/674/3007 590/680/3008 589/678/3009 -f 589/678/3010 588/679/3011 586/674/3012 -f 586/674/3013 587/677/3014 444/681/3015 -f 444/681/3016 590/680/3017 586/674/3018 -f 586/674/3019 588/679/3020 591/682/3021 -f 591/682/3022 585/675/3023 586/674/3024 -f 591/682/3025 588/679/3026 593/683/3027 -f 593/683/3028 592/684/3029 591/682/3030 -f 591/682/3031 555/668/3032 556/669/3033 -f 556/669/3034 585/675/3035 591/682/3036 -f 591/682/3037 592/684/3038 554/643/3039 -f 554/643/3040 555/668/3041 591/682/3042 -f 593/683/3043 596/1388/3044 595/685/3045 -f 595/685/3046 594/785/3047 593/683/3048 -f 593/683/3049 588/679/3050 589/678/3051 -f 589/678/3052 596/1388/3053 593/683/3054 -f 593/683/3055 594/785/3056 597/1399/3057 -f 597/1399/3058 592/684/3059 593/683/3060 -f 597/1399/3061 594/785/3062 1500/1427/3063 -f 1500/1427/3064 1501/1428/3065 597/1399/3066 -f 597/1399/3067 598/1429/3068 554/643/3069 -f 554/643/3070 592/684/3071 597/1399/3072 -f 597/1399/3073 1501/1428/3074 392/1430/3075 -f 392/1430/3076 598/1429/3077 597/1399/3078 -f 392/1430/3079 1503/1525/3080 551/640/3081 -f 551/640/3082 598/1429/3083 392/1430/3084 -f 1503/1525/3085 599/1526/3086 549/638/3087 -f 549/638/3088 551/640/3089 1503/1525/3090 -f 599/1526/3091 1504/1528/3092 546/634/3093 -f 546/634/3094 549/638/3095 599/1526/3096 -f 1504/1528/3097 600/1529/3098 545/635/3099 -f 545/635/3100 546/634/3101 1504/1528/3102 -f 600/1529/3103 601/1530/3104 548/637/3105 -f 548/637/3106 545/635/3107 600/1529/3108 -f 598/1429/3109 551/640/3110 552/641/3111 -f 552/641/3112 554/643/3113 598/1429/3114 -f 1500/1427/3115 594/785/3116 595/685/3117 -f 595/685/3118 393/1531/3119 1500/1427/3120 -f 393/1531/3121 595/685/3122 419/1532/3123 -f 419/1532/3124 602/1533/3125 393/1531/3126 -f 596/1388/3127 422/1534/3128 419/1532/3129 -f 419/1532/3130 595/685/3131 596/1388/3132 -f 596/1388/3133 589/678/3134 603/1535/3135 -f 603/1535/3136 422/1534/3137 596/1388/3138 -f 603/689/3139 604/690/3140 421/503/3141 -f 421/503/3142 422/506/3143 603/689/3144 -f 603/689/3145 606/692/3146 605/691/3147 -f 605/691/3148 604/690/3149 603/689/3150 -f 603/1535/3151 589/678/3152 590/680/3153 -f 590/680/3154 606/1536/3155 603/1535/3156 -f 607/693/3157 449/533/3158 605/691/3159 -f 605/691/3160 606/692/3161 607/693/3162 -f 606/1536/3163 590/680/3164 444/681/3165 -f 444/681/3166 607/1537/3167 606/1536/3168 -f 607/1401/3169 444/525/3170 441/524/3171 -f 441/524/3172 608/1400/3173 607/1401/3174 -f 608/1400/3175 441/524/3176 445/529/3177 -f 445/529/3178 609/1402/3179 608/1400/3180 -f 609/1402/3181 445/529/3182 612/1409/3183 -f 612/1409/3184 611/1410/3185 609/1402/3186 -f 612/1409/3187 445/529/3188 439/522/3189 -f 439/522/3190 440/523/3191 612/1409/3192 -f 612/1409/3193 613/1412/3194 1515/1411/3195 -f 1515/1411/3196 611/1410/3197 612/1409/3198 -f 612/1409/3199 440/523/3200 394/1414/3201 -f 394/1414/3202 613/1412/3203 612/1409/3204 -f 1515/698/3205 395/699/3206 610/694/3207 -f 610/694/3208 611/695/3209 1515/698/3210 -f 395/699/3211 1517/701/3212 614/700/3213 -f 614/700/3214 610/694/3215 395/699/3216 -f 1517/701/3217 1519/703/3218 615/702/3219 -f 615/702/3220 614/700/3221 1517/701/3222 -f 1519/703/3223 1521/705/3224 616/704/3225 -f 616/704/3226 615/702/3227 1519/703/3228 -f 1521/705/3229 1341/2601/3230 467/2600/3231 -f 467/2600/3232 616/704/3233 1521/705/3234 -f 616/704/3235 618/707/3236 617/706/3237 -f 617/706/3238 615/702/3239 616/704/3240 -f 616/704/3241 467/2600/3242 619/708/3243 -f 619/708/3244 618/707/3245 616/704/3246 -f 620/710/3247 618/707/3248 619/708/3249 -f 619/708/3250 621/709/3251 620/710/3252 -f 424/507/3253 622/711/3254 621/2603/3255 -f 621/2603/3256 619/2602/3257 424/507/3258 -f 619/2602/3259 467/551/3260 423/508/3261 -f 423/508/3262 424/507/3263 619/2602/3264 -f 623/714/3265 626/715/3266 625/712/3267 -f 625/712/3268 624/2605/3269 623/714/3270 -f 623/714/3271 628/717/3272 627/716/3273 -f 627/716/3274 626/715/3275 623/714/3276 -f 622/711/3277 629/718/3278 628/717/3279 -f 628/717/3280 623/714/3281 622/711/3282 -f 628/717/3283 631/720/3284 630/719/3285 -f 630/719/3286 627/716/3287 628/717/3288 -f 629/718/3289 632/721/3290 631/720/3291 -f 631/720/3292 628/717/3293 629/718/3294 -f 631/720/3295 634/723/3296 633/722/3297 -f 633/722/3298 630/719/3299 631/720/3300 -f 632/721/3301 635/724/3302 634/723/3303 -f 634/723/3304 631/720/3305 632/721/3306 -f 634/723/3307 637/726/3308 636/725/3309 -f 636/725/3310 633/722/3311 634/723/3312 -f 635/724/3313 638/727/3314 637/726/3315 -f 637/726/3316 634/723/3317 635/724/3318 -f 637/726/3319 640/729/3320 639/728/3321 -f 639/728/3322 636/725/3323 637/726/3324 -f 638/727/3325 450/535/3326 640/729/3327 -f 640/729/3328 637/726/3329 638/727/3330 -f 642/730/3331 641/731/3332 636/725/3333 -f 636/725/3334 639/728/3335 642/730/3336 -f 644/732/3337 643/733/3338 642/730/3339 -f 642/730/3340 639/728/3341 644/732/3342 -f 639/728/3343 640/729/3344 645/734/3345 -f 645/734/3346 644/732/3347 639/728/3348 -f 647/735/3349 646/736/3350 643/733/3351 -f 643/733/3352 644/732/3353 647/735/3354 -f 644/732/3355 645/734/3356 648/737/3357 -f 648/737/3358 647/735/3359 644/732/3360 -f 648/737/3361 650/739/3362 649/738/3363 -f 649/738/3364 647/735/3365 648/737/3366 -f 620/710/3367 650/739/3368 648/737/3369 -f 648/737/3370 651/740/3371 620/710/3372 -f 645/734/3373 451/534/3374 651/740/3375 -f 651/740/3376 648/737/3377 645/734/3378 -f 646/736/3379 647/735/3380 649/738/3381 -f 649/738/3382 652/741/3383 646/736/3384 -f 653/742/3385 652/741/3386 649/738/3387 -f 649/738/3388 625/2604/3389 653/742/3390 -f 649/738/3391 650/739/3392 624/713/3393 -f 624/713/3394 625/2604/3395 649/738/3396 -f 656/745/3397 655/746/3398 654/2607/3399 -f 654/2607/3400 657/744/3401 656/745/3402 -f 659/747/3403 658/748/3404 657/2608/3405 -f 657/2608/3406 654/743/3407 659/747/3408 -f 653/2606/3409 660/749/3410 659/747/3411 -f 659/747/3412 654/743/3413 653/2606/3414 -f 662/750/3415 661/751/3416 658/748/3417 -f 658/748/3418 659/747/3419 662/750/3420 -f 660/749/3421 663/752/3422 662/750/3423 -f 662/750/3424 659/747/3425 660/749/3426 -f 665/753/3427 664/754/3428 661/751/3429 -f 661/751/3430 662/750/3431 665/753/3432 -f 663/752/3433 666/755/3434 665/753/3435 -f 665/753/3436 662/750/3437 663/752/3438 -f 667/757/3439 664/754/3440 665/753/3441 -f 665/753/3442 668/756/3443 667/757/3444 -f 666/755/3445 669/758/3446 668/756/3447 -f 668/756/3448 665/753/3449 666/755/3450 -f 670/760/3451 667/757/3452 668/756/3453 -f 668/756/3454 671/759/3455 670/760/3456 -f 641/731/3457 671/759/3458 668/756/3459 -f 668/756/3460 669/758/3461 641/731/3462 -f 672/763/3463 675/764/3464 674/761/3465 -f 674/761/3466 673/762/3467 672/763/3468 -f 672/763/3469 677/766/3470 676/765/3471 -f 676/765/3472 675/764/3473 672/763/3474 -f 670/760/3475 678/767/3476 677/766/3477 -f 677/766/3478 672/763/3479 670/760/3480 -f 677/766/3481 680/769/3482 679/768/3483 -f 679/768/3484 676/765/3485 677/766/3486 -f 678/767/3487 681/770/3488 680/769/3489 -f 680/769/3490 677/766/3491 678/767/3492 -f 680/769/3493 683/772/3494 682/771/3495 -f 682/771/3496 679/768/3497 680/769/3498 -f 681/770/3499 684/773/3500 683/772/3501 -f 683/772/3502 680/769/3503 681/770/3504 -f 683/772/3505 686/775/3506 685/774/3507 -f 685/774/3508 682/771/3509 683/772/3510 -f 656/745/3511 686/775/3512 683/772/3513 -f 683/772/3514 684/773/3515 656/745/3516 -f 685/774/3517 686/775/3518 688/776/3519 -f 688/776/3520 687/777/3521 685/774/3522 -f 687/2610/3523 688/2609/3524 690/778/3525 -f 690/778/3526 689/1350/3527 687/2610/3528 -f 689/1350/3529 690/778/3530 692/1351/3531 -f 692/1351/3532 691/1352/3533 689/1350/3534 -f 691/1352/3535 692/1351/3536 694/2566/3537 -f 694/2566/3538 693/2567/3539 691/1352/3540 -f 693/2567/3541 694/2566/3542 673/762/3543 -f 673/762/3544 674/761/3545 693/2567/3546 -f 617/706/3547 446/532/3548 614/700/3549 -f 614/700/3550 615/702/3551 617/706/3552 -f 542/631/3553 548/637/3554 470/552/3555 -f 470/552/3556 474/1538/3557 542/631/3558 -f 521/606/3559 479/563/3560 480/564/3561 -f 480/564/3562 482/566/3563 521/606/3564 -f 503/2585/3565 695/779/3566 409/493/3567 -f 409/493/3568 410/492/3569 503/2585/3570 -f 491/575/3571 464/547/3572 418/502/3573 -f 418/502/3574 696/780/3575 491/575/3576 -f 455/539/3577 452/538/3578 698/1415/3579 -f 698/1415/3580 697/1416/3581 455/539/3582 -f 430/513/3583 411/2581/3584 412/2582/3585 -f 412/2582/3586 429/514/3587 430/513/3588 -f 1342/688/3589 602/2568/3590 419/505/3591 -f 419/505/3592 423/508/3593 1342/688/3594 -f 698/1415/3595 472/645/3596 473/648/3597 -f 473/648/3598 697/1416/3599 698/1415/3600 -f 698/1415/3601 452/538/3602 456/543/3603 -f 456/543/3604 472/645/3605 698/1415/3606 -f 418/502/3607 409/493/3608 695/779/3609 -f 695/779/3610 696/780/3611 418/502/3612 -f 416/500/3613 407/491/3614 405/490/3615 -f 405/490/3616 415/499/3617 416/500/3618 -f 1269/478/3619 394/1414/3620 440/523/3621 -f 440/523/3622 396/480/3623 1269/478/3624 -f 537/621/3625 505/589/3626 506/590/3627 -f 506/590/3628 536/620/3629 537/621/3630 -f 537/621/3631 512/595/3632 508/591/3633 -f 508/591/3634 505/589/3635 537/621/3636 -f 435/518/3637 400/483/3638 396/480/3639 -f 396/480/3640 440/523/3641 435/518/3642 -f 695/779/3643 700/784/3644 699/783/3645 -f 699/783/3646 696/780/3647 695/779/3648 -f 491/575/3649 696/780/3650 699/783/3651 -f 699/783/3652 494/578/3653 491/575/3654 -f 700/784/3655 499/582/3656 494/578/3657 -f 494/578/3658 699/783/3659 700/784/3660 -f 503/2585/3661 499/582/3662 700/784/3663 -f 700/784/3664 695/779/3665 503/2585/3666 -f 601/1530/3667 1607/1540/3668 701/1539/3669 -f 701/1539/3670 548/637/3671 601/1530/3672 -f 548/637/3673 701/1539/3674 469/553/3675 -f 469/553/3676 470/552/3677 548/637/3678 -f 703/788/3679 702/789/3680 705/786/3681 -f 705/786/3682 704/787/3683 703/788/3684 -f 1129/792/3685 707/793/3686 706/790/3687 -f 706/790/3688 708/791/3689 1129/792/3690 -f 711/796/3691 710/797/3692 709/794/3693 -f 709/794/3694 712/795/3695 711/796/3696 -f 714/800/3697 713/801/3698 716/798/3699 -f 716/798/3700 715/799/3701 714/800/3702 -f 711/796/3703 718/804/3704 717/802/3705 -f 717/802/3706 719/803/3707 711/796/3708 -f 724/809/3709 723/810/3710 726/807/3711 -f 726/807/3712 725/808/3713 724/809/3714 -f 728/813/3715 727/814/3716 730/811/3717 -f 730/811/3718 729/812/3719 728/813/3720 -f 733/815/3721 732/816/3722 731/805/3723 -f 731/805/3724 734/806/3725 733/815/3726 -f 736/819/3727 735/820/3728 738/817/3729 -f 738/817/3730 737/818/3731 736/819/3732 -f 739/821/3733 731/805/3734 714/800/3735 -f 714/800/3736 709/794/3737 739/821/3738 -f 741/824/3739 738/817/3740 740/822/3741 -f 740/822/3742 742/823/3743 741/824/3744 -f 744/829/3745 743/830/3746 746/827/3747 -f 746/827/3748 745/828/3749 744/829/3750 -f 747/833/3751 750/834/3752 749/831/3753 -f 749/831/3754 748/832/3755 747/833/3756 -f 751/826/3757 737/818/3758 738/817/3759 -f 738/817/3760 752/825/3761 751/826/3762 -f 751/826/3763 752/825/3764 731/805/3765 -f 731/805/3766 732/816/3767 751/826/3768 -f 753/843/3769 733/844/3770 734/837/3771 -f 734/837/3772 754/838/3773 753/843/3774 -f 753/843/3775 754/838/3776 735/845/3777 -f 735/845/3778 736/846/3779 753/843/3780 -f 755/839/3781 758/840/3782 757/835/3783 -f 757/835/3784 756/836/3785 755/839/3786 -f 761/852/3787 760/853/3788 759/849/3789 -f 759/849/3790 762/850/3791 761/852/3792 -f 740/822/3793 764/842/3794 763/841/3795 -f 763/841/3796 742/823/3797 740/822/3798 -f 765/867/3799 766/868/3800 747/833/3801 -f 747/833/3802 748/832/3803 765/867/3804 -f 710/797/3805 767/847/3806 739/821/3807 -f 739/821/3808 709/794/3809 710/797/3810 -f 768/879/3811 769/880/3812 761/852/3813 -f 761/852/3814 762/850/3815 768/879/3816 -f 770/854/3817 721/855/3818 722/848/3819 -f 722/848/3820 771/851/3821 770/854/3822 -f 772/856/3823 720/857/3824 721/855/3825 -f 721/855/3826 770/854/3827 772/856/3828 -f 775/860/3829 774/861/3830 773/858/3831 -f 773/858/3832 776/859/3833 775/860/3834 -f 778/864/3835 777/865/3836 780/862/3837 -f 780/862/3838 779/863/3839 778/864/3840 -f 780/862/3841 777/865/3842 781/866/3843 -f 781/866/3844 782/869/3845 780/862/3846 -f 781/866/3847 774/861/3848 775/860/3849 -f 775/860/3850 782/869/3851 781/866/3852 -f 773/893/3853 783/894/3854 784/891/3855 -f 784/891/3856 776/892/3857 773/893/3858 -f 784/891/3859 783/894/3860 778/895/3861 -f 778/895/3862 779/896/3863 784/891/3864 -f 787/872/3865 786/873/3866 785/870/3867 -f 785/870/3868 788/871/3869 787/872/3870 -f 790/876/3871 789/877/3872 792/874/3873 -f 792/874/3874 791/875/3875 790/876/3876 -f 792/874/3877 789/877/3878 793/878/3879 -f 793/878/3880 794/881/3881 792/874/3882 -f 793/878/3883 786/873/3884 787/872/3885 -f 787/872/3886 794/881/3887 793/878/3888 -f 788/899/3889 785/905/3890 795/897/3891 -f 795/897/3892 796/898/3893 788/899/3894 -f 795/897/3895 790/907/3896 791/906/3897 -f 791/906/3898 796/898/3899 795/897/3900 -f 797/884/3901 800/885/3902 799/882/3903 -f 799/882/3904 798/883/3905 797/884/3906 -f 801/888/3907 804/889/3908 803/886/3909 -f 803/886/3910 802/887/3911 801/888/3912 -f 805/890/3913 806/900/3914 804/889/3915 -f 804/889/3916 801/888/3917 805/890/3918 -f 798/883/3919 799/882/3920 806/900/3921 -f 806/900/3922 805/890/3923 798/883/3924 -f 807/910/3925 810/911/3926 809/908/3927 -f 809/908/3928 808/909/3929 807/910/3930 -f 811/912/3931 812/913/3932 810/911/3933 -f 810/911/3934 807/910/3935 811/912/3936 -f 800/885/3937 773/858/3938 774/861/3939 -f 774/861/3940 799/882/3941 800/885/3942 -f 804/889/3943 777/865/3944 778/864/3945 -f 778/864/3946 803/886/3947 804/889/3948 -f 806/900/3949 781/866/3950 777/865/3951 -f 777/865/3952 804/889/3953 806/900/3954 -f 799/882/3955 774/861/3956 781/866/3957 -f 781/866/3958 806/900/3959 799/882/3960 -f 810/911/3961 814/915/3962 813/914/3963 -f 813/914/3964 809/908/3965 810/911/3966 -f 812/913/3967 815/916/3968 814/915/3969 -f 814/915/3970 810/911/3971 812/913/3972 -f 776/859/3973 817/902/3974 816/901/3975 -f 816/901/3976 775/860/3977 776/859/3978 -f 780/862/3979 819/904/3980 818/903/3981 -f 818/903/3982 779/863/3983 780/862/3984 -f 782/869/3985 820/935/3986 819/904/3987 -f 819/904/3988 780/862/3989 782/869/3990 -f 775/860/3991 816/901/3992 820/935/3993 -f 820/935/3994 782/869/3995 775/860/3996 -f 821/919/3997 824/920/3998 823/917/3999 -f 823/917/4000 822/918/4001 821/919/4002 -f 825/921/4003 826/922/4004 824/920/4005 -f 824/920/4006 821/919/4007 825/921/4008 -f 817/902/4009 785/870/4010 786/873/4011 -f 786/873/4012 816/901/4013 817/902/4014 -f 819/904/4015 789/877/4016 790/876/4017 -f 790/876/4018 818/903/4019 819/904/4020 -f 820/935/4021 793/878/4022 789/877/4023 -f 789/877/4024 819/904/4025 820/935/4026 -f 816/901/4027 786/873/4028 793/878/4029 -f 793/878/4030 820/935/4031 816/901/4032 -f 824/920/4033 828/924/4034 827/923/4035 -f 827/923/4036 823/917/4037 824/920/4038 -f 826/922/4039 829/925/4040 828/924/4041 -f 828/924/4042 824/920/4043 826/922/4044 -f 807/910/4045 808/909/4046 797/926/4047 -f 797/926/4048 830/927/4049 807/910/4050 -f 811/912/4051 807/910/4052 830/927/4053 -f 830/927/4054 802/928/4055 811/912/4056 -f 812/913/4057 811/912/4058 802/928/4059 -f 802/928/4060 803/929/4061 812/913/4062 -f 815/916/4063 812/913/4064 803/929/4065 -f 803/929/4066 778/895/4067 815/916/4068 -f 814/915/4069 815/916/4070 778/895/4071 -f 778/895/4072 783/894/4073 814/915/4074 -f 813/914/4075 814/915/4076 783/894/4077 -f 783/894/4078 773/893/4079 813/914/4080 -f 809/908/4081 813/914/4082 773/893/4083 -f 773/893/4084 800/930/4085 809/908/4086 -f 808/909/4087 809/908/4088 800/930/4089 -f 800/930/4090 797/926/4091 808/909/4092 -f 821/919/4093 822/918/4094 776/892/4095 -f 776/892/4096 784/891/4097 821/919/4098 -f 825/921/4099 821/919/4100 784/891/4101 -f 784/891/4102 779/896/4103 825/921/4104 -f 826/922/4105 825/921/4106 779/896/4107 -f 779/896/4108 818/931/4109 826/922/4110 -f 829/925/4111 826/922/4112 818/931/4113 -f 818/931/4114 790/907/4115 829/925/4116 -f 828/924/4117 829/925/4118 790/907/4119 -f 790/907/4120 795/897/4121 828/924/4122 -f 827/923/4123 828/924/4124 795/897/4125 -f 795/897/4126 785/905/4127 827/923/4128 -f 823/917/4129 827/923/4130 785/905/4131 -f 785/905/4132 817/932/4133 823/917/4134 -f 822/918/4135 823/917/4136 817/932/4137 -f 817/932/4138 776/892/4139 822/918/4140 -f 772/856/4141 787/872/4142 788/871/4143 -f 788/871/4144 720/857/4145 772/856/4146 -f 791/875/4147 792/874/4148 771/851/4149 -f 771/851/4150 722/848/4151 791/875/4152 -f 771/851/4153 792/874/4154 794/881/4155 -f 794/881/4156 770/854/4157 771/851/4158 -f 794/881/4159 787/872/4160 772/856/4161 -f 772/856/4162 770/854/4163 794/881/4164 -f 832/948/4165 831/949/4166 834/933/4167 -f 834/933/4168 833/934/4169 832/948/4170 -f 831/949/4171 835/964/4172 836/963/4173 -f 836/963/4174 834/933/4175 831/949/4176 -f 838/987/4177 837/988/4178 721/975/4179 -f 721/975/4180 720/976/4181 838/987/4182 -f 839/989/4183 838/987/4184 720/976/4185 -f 720/976/4186 788/899/4187 839/989/4188 -f 840/990/4189 839/989/4190 788/899/4191 -f 788/899/4192 796/898/4193 840/990/4194 -f 841/991/4195 840/990/4196 796/898/4197 -f 796/898/4198 791/906/4199 841/991/4200 -f 842/993/4201 841/991/4202 791/906/4203 -f 791/906/4204 722/992/4205 842/993/4206 -f 837/988/4207 842/993/4208 722/992/4209 -f 722/992/4210 721/975/4211 837/988/4212 -f 833/934/4213 834/933/4214 837/988/4215 -f 837/988/4216 838/987/4217 833/934/4218 -f 832/948/4219 833/934/4220 838/987/4221 -f 838/987/4222 839/989/4223 832/948/4224 -f 831/949/4225 832/948/4226 839/989/4227 -f 839/989/4228 840/990/4229 831/949/4230 -f 835/964/4231 831/949/4232 840/990/4233 -f 840/990/4234 841/991/4235 835/964/4236 -f 836/963/4237 835/964/4238 841/991/4239 -f 841/991/4240 842/993/4241 836/963/4242 -f 834/933/4243 836/963/4244 842/993/4245 -f 842/993/4246 837/988/4247 834/933/4248 -f 845/1001/4249 844/1002/4250 843/994/4251 -f 843/994/4252 846/995/4253 845/1001/4254 -f 848/1003/4255 847/1004/4256 744/829/4257 -f 744/829/4258 745/828/4259 848/1003/4260 -f 850/1005/4261 849/1006/4262 845/1001/4263 -f 845/1001/4264 846/995/4265 850/1005/4266 -f 714/800/4267 731/805/4268 752/825/4269 -f 752/825/4270 713/801/4271 714/800/4272 -f 752/825/4273 738/817/4274 741/824/4275 -f 741/824/4276 713/801/4277 752/825/4278 -f 757/835/4279 767/847/4280 710/797/4281 -f 710/797/4282 756/836/4283 757/835/4284 -f 755/839/4285 851/937/4286 852/936/4287 -f 852/936/4288 758/840/4289 755/839/4290 -f 853/939/4291 763/841/4292 764/842/4293 -f 764/842/4294 854/938/4295 853/939/4296 -f 732/816/4297 733/815/4298 797/884/4299 -f 797/884/4300 798/883/4301 732/816/4302 -f 802/887/4303 736/819/4304 737/818/4305 -f 737/818/4306 801/888/4307 802/887/4308 -f 737/818/4309 751/826/4310 805/890/4311 -f 805/890/4312 801/888/4313 737/818/4314 -f 805/890/4315 751/826/4316 732/816/4317 -f 732/816/4318 798/883/4319 805/890/4320 -f 733/844/4321 753/843/4322 830/927/4323 -f 830/927/4324 797/926/4325 733/844/4326 -f 830/927/4327 753/843/4328 736/846/4329 -f 736/846/4330 802/928/4331 830/927/4332 -f 859/941/4333 858/942/4334 767/847/4335 -f 767/847/4336 860/940/4337 859/941/4338 -f 861/944/4339 734/806/4340 731/805/4341 -f 731/805/4342 862/943/4343 861/944/4344 -f 863/945/4345 862/943/4346 731/805/4347 -f 731/805/4348 739/821/4349 863/945/4350 -f 863/945/4351 739/821/4352 767/847/4353 -f 767/847/4354 858/942/4355 863/945/4356 -f 865/1008/4357 864/1009/4358 734/837/4359 -f 734/837/4360 861/1007/4361 865/1008/4362 -f 866/950/4363 856/951/4364 857/946/4365 -f 857/946/4366 867/947/4367 866/950/4368 -f 868/952/4369 855/953/4370 856/951/4371 -f 856/951/4372 866/950/4373 868/952/4374 -f 871/956/4375 870/957/4376 869/954/4377 -f 869/954/4378 872/955/4379 871/956/4380 -f 874/960/4381 873/961/4382 876/958/4383 -f 876/958/4384 875/959/4385 874/960/4386 -f 876/958/4387 873/961/4388 877/962/4389 -f 877/962/4390 878/965/4391 876/958/4392 -f 877/962/4393 870/957/4394 871/956/4395 -f 871/956/4396 878/965/4397 877/962/4398 -f 869/1012/4399 879/1013/4400 880/1010/4401 -f 880/1010/4402 872/1011/4403 869/1012/4404 -f 880/1010/4405 879/1013/4406 874/1014/4407 -f 874/1014/4408 875/1015/4409 880/1010/4410 -f 883/968/4411 882/969/4412 881/966/4413 -f 881/966/4414 884/967/4415 883/968/4416 -f 886/972/4417 885/973/4418 888/970/4419 -f 888/970/4420 887/971/4421 886/972/4422 -f 888/970/4423 885/973/4424 889/974/4425 -f 889/974/4426 890/977/4427 888/970/4428 -f 889/974/4429 882/969/4430 883/968/4431 -f 883/968/4432 890/977/4433 889/974/4434 -f 884/1018/4435 881/1019/4436 891/1016/4437 -f 891/1016/4438 892/1017/4439 884/1018/4440 -f 891/1016/4441 886/1021/4442 887/1020/4443 -f 887/1020/4444 892/1017/4445 891/1016/4446 -f 893/980/4447 896/981/4448 895/978/4449 -f 895/978/4450 894/979/4451 893/980/4452 -f 897/984/4453 900/985/4454 899/982/4455 -f 899/982/4456 898/983/4457 897/984/4458 -f 901/986/4459 902/996/4460 900/985/4461 -f 900/985/4462 897/984/4463 901/986/4464 -f 894/979/4465 895/978/4466 902/996/4467 -f 902/996/4468 901/986/4469 894/979/4470 -f 903/1032/4471 906/1046/4472 905/1022/4473 -f 905/1022/4474 904/1031/4475 903/1032/4476 -f 907/1047/4477 908/1058/4478 906/1046/4479 -f 906/1046/4480 903/1032/4481 907/1047/4482 -f 896/981/4483 869/954/4484 870/957/4485 -f 870/957/4486 895/978/4487 896/981/4488 -f 900/985/4489 873/961/4490 874/960/4491 -f 874/960/4492 899/982/4493 900/985/4494 -f 902/996/4495 877/962/4496 873/961/4497 -f 873/961/4498 900/985/4499 902/996/4500 -f 895/978/4501 870/957/4502 877/962/4503 -f 877/962/4504 902/996/4505 895/978/4506 -f 906/1046/4507 910/1070/4508 909/1059/4509 -f 909/1059/4510 905/1022/4511 906/1046/4512 -f 908/1058/4513 911/1071/4514 910/1070/4515 -f 910/1070/4516 906/1046/4517 908/1058/4518 -f 872/955/4519 913/998/4520 912/997/4521 -f 912/997/4522 871/956/4523 872/955/4524 -f 876/958/4525 915/1000/4526 914/999/4527 -f 914/999/4528 875/959/4529 876/958/4530 -f 878/965/4531 916/1023/4532 915/1000/4533 -f 915/1000/4534 876/958/4535 878/965/4536 -f 871/956/4537 912/997/4538 916/1023/4539 -f 916/1023/4540 878/965/4541 871/956/4542 -f 917/1074/4543 920/1075/4544 919/1072/4545 -f 919/1072/4546 918/1073/4547 917/1074/4548 -f 921/1076/4549 922/1077/4550 920/1075/4551 -f 920/1075/4552 917/1074/4553 921/1076/4554 -f 913/998/4555 881/966/4556 882/969/4557 -f 882/969/4558 912/997/4559 913/998/4560 -f 915/1000/4561 885/973/4562 886/972/4563 -f 886/972/4564 914/999/4565 915/1000/4566 -f 916/1023/4567 889/974/4568 885/973/4569 -f 885/973/4570 915/1000/4571 916/1023/4572 -f 912/997/4573 882/969/4574 889/974/4575 -f 889/974/4576 916/1023/4577 912/997/4578 -f 920/1075/4579 924/1084/4580 923/1078/4581 -f 923/1078/4582 919/1072/4583 920/1075/4584 -f 922/1077/4585 925/1085/4586 924/1084/4587 -f 924/1084/4588 920/1075/4589 922/1077/4590 -f 903/1032/4591 904/1031/4592 893/1086/4593 -f 893/1086/4594 926/1087/4595 903/1032/4596 -f 907/1047/4597 903/1032/4598 926/1087/4599 -f 926/1087/4600 898/1088/4601 907/1047/4602 -f 908/1058/4603 907/1047/4604 898/1088/4605 -f 898/1088/4606 899/1089/4607 908/1058/4608 -f 911/1071/4609 908/1058/4610 899/1089/4611 -f 899/1089/4612 874/1014/4613 911/1071/4614 -f 910/1070/4615 911/1071/4616 874/1014/4617 -f 874/1014/4618 879/1013/4619 910/1070/4620 -f 909/1059/4621 910/1070/4622 879/1013/4623 -f 879/1013/4624 869/1012/4625 909/1059/4626 -f 905/1022/4627 909/1059/4628 869/1012/4629 -f 869/1012/4630 896/1090/4631 905/1022/4632 -f 904/1031/4633 905/1022/4634 896/1090/4635 -f 896/1090/4636 893/1086/4637 904/1031/4638 -f 917/1074/4639 918/1073/4640 872/1011/4641 -f 872/1011/4642 880/1010/4643 917/1074/4644 -f 921/1076/4645 917/1074/4646 880/1010/4647 -f 880/1010/4648 875/1015/4649 921/1076/4650 -f 922/1077/4651 921/1076/4652 875/1015/4653 -f 875/1015/4654 914/1091/4655 922/1077/4656 -f 925/1085/4657 922/1077/4658 914/1091/4659 -f 914/1091/4660 886/1021/4661 925/1085/4662 -f 924/1084/4663 925/1085/4664 886/1021/4665 -f 886/1021/4666 891/1016/4667 924/1084/4668 -f 923/1078/4669 924/1084/4670 891/1016/4671 -f 891/1016/4672 881/1019/4673 923/1078/4674 -f 919/1072/4675 923/1078/4676 881/1019/4677 -f 881/1019/4678 913/1092/4679 919/1072/4680 -f 918/1073/4681 919/1072/4682 913/1092/4683 -f 913/1092/4684 872/1011/4685 918/1073/4686 -f 868/952/4687 883/968/4688 884/967/4689 -f 884/967/4690 855/953/4691 868/952/4692 -f 887/971/4693 888/970/4694 867/947/4695 -f 867/947/4696 857/946/4697 887/971/4698 -f 867/947/4699 888/970/4700 890/977/4701 -f 890/977/4702 866/950/4703 867/947/4704 -f 890/977/4705 883/968/4706 868/952/4707 -f 868/952/4708 866/950/4709 890/977/4710 -f 928/1095/4711 927/1096/4712 930/1093/4713 -f 930/1093/4714 929/1094/4715 928/1095/4716 -f 927/1096/4717 931/1098/4718 932/1097/4719 -f 932/1097/4720 930/1093/4721 927/1096/4722 -f 934/1101/4723 933/1102/4724 856/1099/4725 -f 856/1099/4726 855/1100/4727 934/1101/4728 -f 935/1103/4729 934/1101/4730 855/1100/4731 -f 855/1100/4732 884/1018/4733 935/1103/4734 -f 936/1104/4735 935/1103/4736 884/1018/4737 -f 884/1018/4738 892/1017/4739 936/1104/4740 -f 937/1105/4741 936/1104/4742 892/1017/4743 -f 892/1017/4744 887/1020/4745 937/1105/4746 -f 938/1115/4747 937/1105/4748 887/1020/4749 -f 887/1020/4750 857/1114/4751 938/1115/4752 -f 933/1102/4753 938/1115/4754 857/1114/4755 -f 857/1114/4756 856/1099/4757 933/1102/4758 -f 929/1094/4759 930/1093/4760 933/1102/4761 -f 933/1102/4762 934/1101/4763 929/1094/4764 -f 928/1095/4765 929/1094/4766 934/1101/4767 -f 934/1101/4768 935/1103/4769 928/1095/4770 -f 927/1096/4771 928/1095/4772 935/1103/4773 -f 935/1103/4774 936/1104/4775 927/1096/4776 -f 931/1098/4777 927/1096/4778 936/1104/4779 -f 936/1104/4780 937/1105/4781 931/1098/4782 -f 932/1097/4783 931/1098/4784 937/1105/4785 -f 937/1105/4786 938/1115/4787 932/1097/4788 -f 930/1093/4789 932/1097/4790 938/1115/4791 -f 938/1115/4792 933/1102/4793 930/1093/4794 -f 858/942/4795 859/941/4796 893/980/4797 -f 893/980/4798 894/979/4799 858/942/4800 -f 898/983/4801 861/944/4802 862/943/4803 -f 862/943/4804 897/984/4805 898/983/4806 -f 862/943/4807 863/945/4808 901/986/4809 -f 901/986/4810 897/984/4811 862/943/4812 -f 901/986/4813 863/945/4814 858/942/4815 -f 858/942/4816 894/979/4817 901/986/4818 -f 859/1129/4819 865/1008/4820 926/1087/4821 -f 926/1087/4822 893/1086/4823 859/1129/4824 -f 926/1087/4825 865/1008/4826 861/1007/4827 -f 861/1007/4828 898/1088/4829 926/1087/4830 -f 943/1024/4831 942/1025/4832 758/840/4833 -f 758/840/4834 852/936/4835 943/1024/4836 -f 944/1027/4837 860/940/4838 767/847/4839 -f 767/847/4840 945/1026/4841 944/1027/4842 -f 946/1028/4843 945/1026/4844 767/847/4845 -f 767/847/4846 757/835/4847 946/1028/4848 -f 946/1028/4849 757/835/4850 758/840/4851 -f 758/840/4852 942/1025/4853 946/1028/4854 -f 947/1142/4855 943/1153/4856 852/1130/4857 -f 852/1130/4858 948/1141/4859 947/1142/4860 -f 947/1142/4861 948/1141/4862 860/1154/4863 -f 860/1154/4864 944/1155/4865 947/1142/4866 -f 949/1033/4867 940/1034/4868 941/1029/4869 -f 941/1029/4870 950/1030/4871 949/1033/4872 -f 951/1035/4873 939/1036/4874 940/1034/4875 -f 940/1034/4876 949/1033/4877 951/1035/4878 -f 954/1039/4879 953/1040/4880 952/1037/4881 -f 952/1037/4882 955/1038/4883 954/1039/4884 -f 957/1043/4885 956/1044/4886 959/1041/4887 -f 959/1041/4888 958/1042/4889 957/1043/4890 -f 959/1041/4891 956/1044/4892 960/1045/4893 -f 960/1045/4894 961/1048/4895 959/1041/4896 -f 960/1045/4897 953/1040/4898 954/1039/4899 -f 954/1039/4900 961/1048/4901 960/1045/4902 -f 952/1158/4903 962/1159/4904 963/1156/4905 -f 963/1156/4906 955/1157/4907 952/1158/4908 -f 963/1156/4909 962/1159/4910 957/1160/4911 -f 957/1160/4912 958/1161/4913 963/1156/4914 -f 966/1051/4915 965/1052/4916 964/1049/4917 -f 964/1049/4918 967/1050/4919 966/1051/4920 -f 969/1055/4921 968/1056/4922 971/1053/4923 -f 971/1053/4924 970/1054/4925 969/1055/4926 -f 971/1053/4927 968/1056/4928 972/1057/4929 -f 972/1057/4930 973/1060/4931 971/1053/4932 -f 972/1057/4933 965/1052/4934 966/1051/4935 -f 966/1051/4936 973/1060/4937 972/1057/4938 -f 967/1169/4939 964/1170/4940 974/1167/4941 -f 974/1167/4942 975/1168/4943 967/1169/4944 -f 974/1167/4945 969/1172/4946 970/1171/4947 -f 970/1171/4948 975/1168/4949 974/1167/4950 -f 976/1063/4951 979/1064/4952 978/1061/4953 -f 978/1061/4954 977/1062/4955 976/1063/4956 -f 980/1067/4957 983/1068/4958 982/1065/4959 -f 982/1065/4960 981/1066/4961 980/1067/4962 -f 984/1069/4963 985/1079/4964 983/1068/4965 -f 983/1068/4966 980/1067/4967 984/1069/4968 -f 977/1062/4969 978/1061/4970 985/1079/4971 -f 985/1079/4972 984/1069/4973 977/1062/4974 -f 986/1175/4975 989/1176/4976 988/1173/4977 -f 988/1173/4978 987/1174/4979 986/1175/4980 -f 990/1177/4981 991/1178/4982 989/1176/4983 -f 989/1176/4984 986/1175/4985 990/1177/4986 -f 979/1064/4987 952/1037/4988 953/1040/4989 -f 953/1040/4990 978/1061/4991 979/1064/4992 -f 983/1068/4993 956/1044/4994 957/1043/4995 -f 957/1043/4996 982/1065/4997 983/1068/4998 -f 985/1079/4999 960/1045/5000 956/1044/5001 -f 956/1044/5002 983/1068/5003 985/1079/5004 -f 978/1061/5005 953/1040/5006 960/1045/5007 -f 960/1045/5008 985/1079/5009 978/1061/5010 -f 989/1176/5011 993/1180/5012 992/1179/5013 -f 992/1179/5014 988/1173/5015 989/1176/5016 -f 991/1178/5017 994/1181/5018 993/1180/5019 -f 993/1180/5020 989/1176/5021 991/1178/5022 -f 955/1038/5023 996/1081/5024 995/1080/5025 -f 995/1080/5026 954/1039/5027 955/1038/5028 -f 959/1041/5029 998/1083/5030 997/1082/5031 -f 997/1082/5032 958/1042/5033 959/1041/5034 -f 961/1048/5035 999/1106/5036 998/1083/5037 -f 998/1083/5038 959/1041/5039 961/1048/5040 -f 954/1039/5041 995/1080/5042 999/1106/5043 -f 999/1106/5044 961/1048/5045 954/1039/5046 -f 1000/1184/5047 1003/1185/5048 1002/1182/5049 -f 1002/1182/5050 1001/1183/5051 1000/1184/5052 -f 1004/1186/5053 1005/1187/5054 1003/1185/5055 -f 1003/1185/5056 1000/1184/5057 1004/1186/5058 -f 996/1081/5059 964/1049/5060 965/1052/5061 -f 965/1052/5062 995/1080/5063 996/1081/5064 -f 998/1083/5065 968/1056/5066 969/1055/5067 -f 969/1055/5068 997/1082/5069 998/1083/5070 -f 999/1106/5071 972/1057/5072 968/1056/5073 -f 968/1056/5074 998/1083/5075 999/1106/5076 -f 995/1080/5077 965/1052/5078 972/1057/5079 -f 972/1057/5080 999/1106/5081 995/1080/5082 -f 1003/1185/5083 1007/1189/5084 1006/1188/5085 -f 1006/1188/5086 1002/1182/5087 1003/1185/5088 -f 1005/1187/5089 1008/1190/5090 1007/1189/5091 -f 1007/1189/5092 1003/1185/5093 1005/1187/5094 -f 986/1175/5095 987/1174/5096 976/1191/5097 -f 976/1191/5098 1009/1192/5099 986/1175/5100 -f 990/1177/5101 986/1175/5102 1009/1192/5103 -f 1009/1192/5104 981/1193/5105 990/1177/5106 -f 991/1178/5107 990/1177/5108 981/1193/5109 -f 981/1193/5110 982/1197/5111 991/1178/5112 -f 994/1181/5113 991/1178/5114 982/1197/5115 -f 982/1197/5116 957/1160/5117 994/1181/5118 -f 993/1180/5119 994/1181/5120 957/1160/5121 -f 957/1160/5122 962/1159/5123 993/1180/5124 -f 992/1179/5125 993/1180/5126 962/1159/5127 -f 962/1159/5128 952/1158/5129 992/1179/5130 -f 988/1173/5131 992/1179/5132 952/1158/5133 -f 952/1158/5134 979/1198/5135 988/1173/5136 -f 987/1174/5137 988/1173/5138 979/1198/5139 -f 979/1198/5140 976/1191/5141 987/1174/5142 -f 1000/1184/5143 1001/1183/5144 955/1157/5145 -f 955/1157/5146 963/1156/5147 1000/1184/5148 -f 1004/1186/5149 1000/1184/5150 963/1156/5151 -f 963/1156/5152 958/1161/5153 1004/1186/5154 -f 1005/1187/5155 1004/1186/5156 958/1161/5157 -f 958/1161/5158 997/1199/5159 1005/1187/5160 -f 1008/1190/5161 1005/1187/5162 997/1199/5163 -f 997/1199/5164 969/1172/5165 1008/1190/5166 -f 1007/1189/5167 1008/1190/5168 969/1172/5169 -f 969/1172/5170 974/1167/5171 1007/1189/5172 -f 1006/1188/5173 1007/1189/5174 974/1167/5175 -f 974/1167/5176 964/1170/5177 1006/1188/5178 -f 1002/1182/5179 1006/1188/5180 964/1170/5181 -f 964/1170/5182 996/1222/5183 1002/1182/5184 -f 1001/1183/5185 1002/1182/5186 996/1222/5187 -f 996/1222/5188 955/1157/5189 1001/1183/5190 -f 951/1035/5191 966/1051/5192 967/1050/5193 -f 967/1050/5194 939/1036/5195 951/1035/5196 -f 970/1054/5197 971/1053/5198 950/1030/5199 -f 950/1030/5200 941/1029/5201 970/1054/5202 -f 950/1030/5203 971/1053/5204 973/1060/5205 -f 973/1060/5206 949/1033/5207 950/1030/5208 -f 973/1060/5209 966/1051/5210 951/1035/5211 -f 951/1035/5212 949/1033/5213 973/1060/5214 -f 1011/1227/5215 1010/1228/5216 1013/1223/5217 -f 1013/1223/5218 1012/1226/5219 1011/1227/5220 -f 1010/1228/5221 1014/1230/5222 1015/1229/5223 -f 1015/1229/5224 1013/1223/5225 1010/1228/5226 -f 1017/1234/5227 1016/1235/5228 940/1231/5229 -f 940/1231/5230 939/1233/5231 1017/1234/5232 -f 1018/1236/5233 1017/1234/5234 939/1233/5235 -f 939/1233/5236 967/1169/5237 1018/1236/5238 -f 1019/1237/5239 1018/1236/5240 967/1169/5241 -f 967/1169/5242 975/1168/5243 1019/1237/5244 -f 1020/1242/5245 1019/1237/5246 975/1168/5247 -f 975/1168/5248 970/1171/5249 1020/1242/5250 -f 1021/1244/5251 1020/1242/5252 970/1171/5253 -f 970/1171/5254 941/1243/5255 1021/1244/5256 -f 1016/1235/5257 1021/1244/5258 941/1243/5259 -f 941/1243/5260 940/1231/5261 1016/1235/5262 -f 1012/1226/5263 1013/1223/5264 1016/1235/5265 -f 1016/1235/5266 1017/1234/5267 1012/1226/5268 -f 1011/1227/5269 1012/1226/5270 1017/1234/5271 -f 1017/1234/5272 1018/1236/5273 1011/1227/5274 -f 1010/1228/5275 1011/1227/5276 1018/1236/5277 -f 1018/1236/5278 1019/1237/5279 1010/1228/5280 -f 1014/1230/5281 1010/1228/5282 1019/1237/5283 -f 1019/1237/5284 1020/1242/5285 1014/1230/5286 -f 1015/1229/5287 1014/1230/5288 1020/1242/5289 -f 1020/1242/5290 1021/1244/5291 1015/1229/5292 -f 1013/1223/5293 1015/1229/5294 1021/1244/5295 -f 1021/1244/5296 1016/1235/5297 1013/1223/5298 -f 942/1025/5299 943/1024/5300 976/1063/5301 -f 976/1063/5302 977/1062/5303 942/1025/5304 -f 981/1066/5305 944/1027/5306 945/1026/5307 -f 945/1026/5308 980/1067/5309 981/1066/5310 -f 945/1026/5311 946/1028/5312 984/1069/5313 -f 984/1069/5314 980/1067/5315 945/1026/5316 -f 984/1069/5317 946/1028/5318 942/1025/5319 -f 942/1025/5320 977/1062/5321 984/1069/5322 -f 943/1153/5323 947/1142/5324 1009/1192/5325 -f 1009/1192/5326 976/1191/5327 943/1153/5328 -f 1009/1192/5329 947/1142/5330 944/1155/5331 -f 944/1155/5332 981/1193/5333 1009/1192/5334 -f 1026/1107/5335 1025/1108/5336 738/817/5337 -f 738/817/5338 735/820/5339 1026/1107/5340 -f 1027/1110/5341 854/938/5342 764/842/5343 -f 764/842/5344 1028/1109/5345 1027/1110/5346 -f 1029/1111/5347 1028/1109/5348 764/842/5349 -f 764/842/5350 740/822/5351 1029/1111/5352 -f 1029/1111/5353 740/822/5354 738/817/5355 -f 738/817/5356 1025/1108/5357 1029/1111/5358 -f 1030/1246/5359 1026/1247/5360 735/845/5361 -f 735/845/5362 1031/1245/5363 1030/1246/5364 -f 1030/1246/5365 1031/1245/5366 854/1253/5367 -f 854/1253/5368 1027/1254/5369 1030/1246/5370 -f 1032/1116/5371 1023/1117/5372 1024/1112/5373 -f 1024/1112/5374 1033/1113/5375 1032/1116/5376 -f 1034/1118/5377 1022/1119/5378 1023/1117/5379 -f 1023/1117/5380 1032/1116/5381 1034/1118/5382 -f 1037/1122/5383 1036/1123/5384 1035/1120/5385 -f 1035/1120/5386 1038/1121/5387 1037/1122/5388 -f 1040/1126/5389 1039/1127/5390 1042/1124/5391 -f 1042/1124/5392 1041/1125/5393 1040/1126/5394 -f 1042/1124/5395 1039/1127/5396 1043/1128/5397 -f 1043/1128/5398 1044/1131/5399 1042/1124/5400 -f 1043/1128/5401 1036/1123/5402 1037/1122/5403 -f 1037/1122/5404 1044/1131/5405 1043/1128/5406 -f 1035/1257/5407 1045/1258/5408 1046/1255/5409 -f 1046/1255/5410 1038/1256/5411 1035/1257/5412 -f 1046/1255/5413 1045/1258/5414 1040/1260/5415 -f 1040/1260/5416 1041/1261/5417 1046/1255/5418 -f 1049/1134/5419 1048/1135/5420 1047/1132/5421 -f 1047/1132/5422 1050/1133/5423 1049/1134/5424 -f 1052/1138/5425 1051/1139/5426 1054/1136/5427 -f 1054/1136/5428 1053/1137/5429 1052/1138/5430 -f 1054/1136/5431 1051/1139/5432 1055/1140/5433 -f 1055/1140/5434 1056/1143/5435 1054/1136/5436 -f 1055/1140/5437 1048/1135/5438 1049/1134/5439 -f 1049/1134/5440 1056/1143/5441 1055/1140/5442 -f 1050/1264/5443 1047/1265/5444 1057/1262/5445 -f 1057/1262/5446 1058/1263/5447 1050/1264/5448 -f 1057/1262/5449 1052/1267/5450 1053/1266/5451 -f 1053/1266/5452 1058/1263/5453 1057/1262/5454 -f 1059/1146/5455 1062/1147/5456 1061/1144/5457 -f 1061/1144/5458 1060/1145/5459 1059/1146/5460 -f 1063/1150/5461 1066/1151/5462 1065/1148/5463 -f 1065/1148/5464 1064/1149/5465 1063/1150/5466 -f 1067/1152/5467 1068/1162/5468 1066/1151/5469 -f 1066/1151/5470 1063/1150/5471 1067/1152/5472 -f 1060/1145/5473 1061/1144/5474 1068/1162/5475 -f 1068/1162/5476 1067/1152/5477 1060/1145/5478 -f 1069/1278/5479 1072/1279/5480 1071/1268/5481 -f 1071/1268/5482 1070/1269/5483 1069/1278/5484 -f 1073/1280/5485 1074/1281/5486 1072/1279/5487 -f 1072/1279/5488 1069/1278/5489 1073/1280/5490 -f 1062/1147/5491 1035/1120/5492 1036/1123/5493 -f 1036/1123/5494 1061/1144/5495 1062/1147/5496 -f 1066/1151/5497 1039/1127/5498 1040/1126/5499 -f 1040/1126/5500 1065/1148/5501 1066/1151/5502 -f 1068/1162/5503 1043/1128/5504 1039/1127/5505 -f 1039/1127/5506 1066/1151/5507 1068/1162/5508 -f 1061/1144/5509 1036/1123/5510 1043/1128/5511 -f 1043/1128/5512 1068/1162/5513 1061/1144/5514 -f 1072/1279/5515 1076/1283/5516 1075/1282/5517 -f 1075/1282/5518 1071/1268/5519 1072/1279/5520 -f 1074/1281/5521 1077/1284/5522 1076/1283/5523 -f 1076/1283/5524 1072/1279/5525 1074/1281/5526 -f 1038/1121/5527 1079/1164/5528 1078/1163/5529 -f 1078/1163/5530 1037/1122/5531 1038/1121/5532 -f 1042/1124/5533 1081/1166/5534 1080/1165/5535 -f 1080/1165/5536 1041/1125/5537 1042/1124/5538 -f 1044/1131/5539 1082/1194/5540 1081/1166/5541 -f 1081/1166/5542 1042/1124/5543 1044/1131/5544 -f 1037/1122/5545 1078/1163/5546 1082/1194/5547 -f 1082/1194/5548 1044/1131/5549 1037/1122/5550 -f 1083/1290/5551 1086/1291/5552 1085/1285/5553 -f 1085/1285/5554 1084/1289/5555 1083/1290/5556 -f 1087/1292/5557 1088/1299/5558 1086/1291/5559 -f 1086/1291/5560 1083/1290/5561 1087/1292/5562 -f 1079/1164/5563 1047/1132/5564 1048/1135/5565 -f 1048/1135/5566 1078/1163/5567 1079/1164/5568 -f 1081/1166/5569 1051/1139/5570 1052/1138/5571 -f 1052/1138/5572 1080/1165/5573 1081/1166/5574 -f 1082/1194/5575 1055/1140/5576 1051/1139/5577 -f 1051/1139/5578 1081/1166/5579 1082/1194/5580 -f 1078/1163/5581 1048/1135/5582 1055/1140/5583 -f 1055/1140/5584 1082/1194/5585 1078/1163/5586 -f 1086/1291/5587 1090/1307/5588 1089/1306/5589 -f 1089/1306/5590 1085/1285/5591 1086/1291/5592 -f 1088/1299/5593 1091/1308/5594 1090/1307/5595 -f 1090/1307/5596 1086/1291/5597 1088/1299/5598 -f 1069/1278/5599 1070/1269/5600 1059/1309/5601 -f 1059/1309/5602 1092/1310/5603 1069/1278/5604 -f 1073/1280/5605 1069/1278/5606 1092/1310/5607 -f 1092/1310/5608 1064/1311/5609 1073/1280/5610 -f 1074/1281/5611 1073/1280/5612 1064/1311/5613 -f 1064/1311/5614 1065/1312/5615 1074/1281/5616 -f 1077/1284/5617 1074/1281/5618 1065/1312/5619 -f 1065/1312/5620 1040/1260/5621 1077/1284/5622 -f 1076/1283/5623 1077/1284/5624 1040/1260/5625 -f 1040/1260/5626 1045/1258/5627 1076/1283/5628 -f 1075/1282/5629 1076/1283/5630 1045/1258/5631 -f 1045/1258/5632 1035/1257/5633 1075/1282/5634 -f 1071/1268/5635 1075/1282/5636 1035/1257/5637 -f 1035/1257/5638 1062/1313/5639 1071/1268/5640 -f 1070/1269/5641 1071/1268/5642 1062/1313/5643 -f 1062/1313/5644 1059/1309/5645 1070/1269/5646 -f 1083/1290/5647 1084/1289/5648 1038/1256/5649 -f 1038/1256/5650 1046/1255/5651 1083/1290/5652 -f 1087/1292/5653 1083/1290/5654 1046/1255/5655 -f 1046/1255/5656 1041/1261/5657 1087/1292/5658 -f 1088/1299/5659 1087/1292/5660 1041/1261/5661 -f 1041/1261/5662 1080/1314/5663 1088/1299/5664 -f 1091/1308/5665 1088/1299/5666 1080/1314/5667 -f 1080/1314/5668 1052/1267/5669 1091/1308/5670 -f 1090/1307/5671 1091/1308/5672 1052/1267/5673 -f 1052/1267/5674 1057/1262/5675 1090/1307/5676 -f 1089/1306/5677 1090/1307/5678 1057/1262/5679 -f 1057/1262/5680 1047/1265/5681 1089/1306/5682 -f 1085/1285/5683 1089/1306/5684 1047/1265/5685 -f 1047/1265/5686 1079/1315/5687 1085/1285/5688 -f 1084/1289/5689 1085/1285/5690 1079/1315/5691 -f 1079/1315/5692 1038/1256/5693 1084/1289/5694 -f 1034/1118/5695 1049/1134/5696 1050/1133/5697 -f 1050/1133/5698 1022/1119/5699 1034/1118/5700 -f 1053/1137/5701 1054/1136/5702 1033/1113/5703 -f 1033/1113/5704 1024/1112/5705 1053/1137/5706 -f 1033/1113/5707 1054/1136/5708 1056/1143/5709 -f 1056/1143/5710 1032/1116/5711 1033/1113/5712 -f 1056/1143/5713 1049/1134/5714 1034/1118/5715 -f 1034/1118/5716 1032/1116/5717 1056/1143/5718 -f 1094/1318/5719 1093/1319/5720 1096/1316/5721 -f 1096/1316/5722 1095/1317/5723 1094/1318/5724 -f 1093/1319/5725 1097/1321/5726 1098/1320/5727 -f 1098/1320/5728 1096/1316/5729 1093/1319/5730 -f 1100/1324/5731 1099/1325/5732 1023/1322/5733 -f 1023/1322/5734 1022/1323/5735 1100/1324/5736 -f 1101/1326/5737 1100/1324/5738 1022/1323/5739 -f 1022/1323/5740 1050/1264/5741 1101/1326/5742 -f 1102/1327/5743 1101/1326/5744 1050/1264/5745 -f 1050/1264/5746 1058/1263/5747 1102/1327/5748 -f 1103/1328/5749 1102/1327/5750 1058/1263/5751 -f 1058/1263/5752 1053/1266/5753 1103/1328/5754 -f 1104/1330/5755 1103/1328/5756 1053/1266/5757 -f 1053/1266/5758 1024/1329/5759 1104/1330/5760 -f 1099/1325/5761 1104/1330/5762 1024/1329/5763 -f 1024/1329/5764 1023/1322/5765 1099/1325/5766 -f 1095/1317/5767 1096/1316/5768 1099/1325/5769 -f 1099/1325/5770 1100/1324/5771 1095/1317/5772 -f 1094/1318/5773 1095/1317/5774 1100/1324/5775 -f 1100/1324/5776 1101/1326/5777 1094/1318/5778 -f 1093/1319/5779 1094/1318/5780 1101/1326/5781 -f 1101/1326/5782 1102/1327/5783 1093/1319/5784 -f 1097/1321/5785 1093/1319/5786 1102/1327/5787 -f 1102/1327/5788 1103/1328/5789 1097/1321/5790 -f 1098/1320/5791 1097/1321/5792 1103/1328/5793 -f 1103/1328/5794 1104/1330/5795 1098/1320/5796 -f 1096/1316/5797 1098/1320/5798 1104/1330/5799 -f 1104/1330/5800 1099/1325/5801 1096/1316/5802 -f 1025/1108/5803 1026/1107/5804 1059/1146/5805 -f 1059/1146/5806 1060/1145/5807 1025/1108/5808 -f 1064/1149/5809 1027/1110/5810 1028/1109/5811 -f 1028/1109/5812 1063/1150/5813 1064/1149/5814 -f 1028/1109/5815 1029/1111/5816 1067/1152/5817 -f 1067/1152/5818 1063/1150/5819 1028/1109/5820 -f 1067/1152/5821 1029/1111/5822 1025/1108/5823 -f 1025/1108/5824 1060/1145/5825 1067/1152/5826 -f 1026/1247/5827 1030/1246/5828 1092/1310/5829 -f 1092/1310/5830 1059/1309/5831 1026/1247/5832 -f 1092/1310/5833 1030/1246/5834 1027/1254/5835 -f 1027/1254/5836 1064/1311/5837 1092/1310/5838 -f 750/834/5839 747/833/5840 1031/1245/5841 -f 1031/1245/5842 735/845/5843 750/834/5844 -f 749/831/5845 750/834/5846 735/845/5847 -f 735/845/5848 1105/1331/5849 749/831/5850 -f 748/832/5851 749/831/5852 1105/1331/5853 -f 1105/1331/5854 1106/1332/5855 748/832/5856 -f 765/867/5857 748/832/5858 1106/1332/5859 -f 1106/1332/5860 853/1333/5861 765/867/5862 -f 766/868/5863 765/867/5864 853/1333/5865 -f 853/1333/5866 854/1253/5867 766/868/5868 -f 747/833/5869 766/868/5870 854/1253/5871 -f 854/1253/5872 1031/1245/5873 747/833/5874 -f 743/830/5875 744/829/5876 754/838/5877 -f 754/838/5878 734/837/5879 743/830/5880 -f 746/827/5881 743/830/5882 734/837/5883 -f 734/837/5884 1107/1334/5885 746/827/5886 -f 745/828/5887 746/827/5888 1107/1334/5889 -f 1107/1334/5890 1108/1335/5891 745/828/5892 -f 848/1003/5893 745/828/5894 1108/1335/5895 -f 1108/1335/5896 1105/1331/5897 848/1003/5898 -f 847/1004/5899 848/1003/5900 1105/1331/5901 -f 1105/1331/5902 735/845/5903 847/1004/5904 -f 744/829/5905 847/1004/5906 735/845/5907 -f 735/845/5908 754/838/5909 744/829/5910 -f 845/1001/5911 849/1006/5912 734/837/5913 -f 734/837/5914 864/1009/5915 845/1001/5916 -f 844/1002/5917 845/1001/5918 864/1009/5919 -f 864/1009/5920 860/1154/5921 844/1002/5922 -f 843/994/5923 844/1002/5924 860/1154/5925 -f 860/1154/5926 727/814/5927 843/994/5928 -f 846/995/5929 843/994/5930 727/814/5931 -f 727/814/5932 1109/1336/5933 846/995/5934 -f 850/1005/5935 846/995/5936 1109/1336/5937 -f 1109/1336/5938 1107/1334/5939 850/1005/5940 -f 849/1006/5941 850/1005/5942 1107/1334/5943 -f 1107/1334/5944 734/837/5945 849/1006/5946 -f 760/853/5947 761/852/5948 948/1141/5949 -f 948/1141/5950 852/1130/5951 760/853/5952 -f 759/849/5953 760/853/5954 852/1130/5955 -f 852/1130/5956 851/1337/5957 759/849/5958 -f 762/850/5959 759/849/5960 851/1337/5961 -f 851/1337/5962 730/811/5963 762/850/5964 -f 768/879/5965 762/850/5966 730/811/5967 -f 730/811/5968 727/814/5969 768/879/5970 -f 769/880/5971 768/879/5972 727/814/5973 -f 727/814/5974 860/1154/5975 769/880/5976 -f 761/852/5977 769/880/5978 860/1154/5979 -f 860/1154/5980 948/1141/5981 761/852/5982 -f 859/1129/5983 860/1154/5984 864/1009/5985 -f 864/1009/5986 865/1008/5987 859/1129/5988 -f 755/839/5989 1111/1196/5990 1110/1195/5991 -f 1110/1195/5992 851/937/5993 755/839/5994 -f 712/795/5995 1112/1200/5996 718/804/5997 -f 718/804/5998 711/796/5999 712/795/6000 -f 1109/1336/6001 1114/1339/6002 1113/1338/6003 -f 1113/1338/6004 1107/1334/6005 1109/1336/6006 -f 719/803/6007 756/836/6008 710/797/6009 -f 710/797/6010 711/796/6011 719/803/6012 -f 725/808/6013 1115/1340/6014 1106/1332/6015 -f 1106/1332/6016 1105/1331/6017 725/808/6018 -f 1108/1335/6019 724/809/6020 725/808/6021 -f 725/808/6022 1105/1331/6023 1108/1335/6024 -f 1118/1203/6025 1117/1204/6026 1116/1201/6027 -f 1116/1201/6028 1119/1202/6029 1118/1203/6030 -f 1121/1205/6031 1120/1206/6032 1116/1201/6033 -f 1116/1201/6034 1117/1204/6035 1121/1205/6036 -f 1123/1208/6037 1122/1209/6038 1121/1205/6039 -f 1121/1205/6040 1124/1207/6041 1123/1208/6042 -f 1117/1204/6043 1118/1203/6044 1126/1210/6045 -f 1126/1210/6046 1125/1211/6047 1117/1204/6048 -f 1124/1207/6049 1121/1205/6050 1117/1204/6051 -f 1117/1204/6052 1125/1211/6053 1124/1207/6054 -f 707/793/6055 1129/792/6056 1127/1212/6057 -f 1127/1212/6058 1128/1213/6059 707/793/6060 -f 1131/1216/6061 1130/1217/6062 1133/1214/6063 -f 1133/1214/6064 1132/1215/6065 1131/1216/6066 -f 1135/1218/6067 1134/1219/6068 1131/1216/6069 -f 1131/1216/6070 1132/1215/6071 1135/1218/6072 -f 1130/1217/6073 1136/1221/6074 1137/1220/6075 -f 1137/1220/6076 1133/1214/6077 1130/1217/6078 -f 1136/1343/6079 1138/1344/6080 1139/1341/6081 -f 1139/1341/6082 1137/1342/6083 1136/1343/6084 -f 1138/1344/6085 1140/1346/6086 1141/1345/6087 -f 1141/1345/6088 1139/1341/6089 1138/1344/6090 -f 1141/1224/6091 1140/1225/6092 1134/1219/6093 -f 1134/1219/6094 1135/1218/6095 1141/1224/6096 -f 1142/1349/6097 1145/2379/6098 1144/1347/6099 -f 1144/1347/6100 1143/1348/6101 1142/1349/6102 -f 1146/2380/6103 1147/2381/6104 1145/2379/6105 -f 1145/2379/6106 1142/1349/6107 1146/2380/6108 -f 1126/1210/6109 1130/1217/6110 1131/1216/6111 -f 1131/1216/6112 1125/1211/6113 1126/1210/6114 -f 1125/1211/6115 1131/1216/6116 1134/1219/6117 -f 1134/1219/6118 1124/1207/6119 1125/1211/6120 -f 1148/1232/6121 1136/1221/6122 1130/1217/6123 -f 1130/1217/6124 1126/1210/6125 1148/1232/6126 -f 1145/2379/6127 1150/2384/6128 1149/2382/6129 -f 1149/2382/6130 1144/1347/6131 1145/2379/6132 -f 1147/2381/6133 1151/2385/6134 1150/2384/6135 -f 1150/2384/6136 1145/2379/6137 1147/2381/6138 -f 1124/1207/6139 1134/1219/6140 1140/1225/6141 -f 1140/1225/6142 1123/1208/6143 1124/1207/6144 -f 1142/1349/6145 1143/1348/6146 1152/2386/6147 -f 1152/2386/6148 1153/2387/6149 1142/1349/6150 -f 1146/2380/6151 1142/1349/6152 1153/2387/6153 -f 1153/2387/6154 1122/2388/6155 1146/2380/6156 -f 1147/2381/6157 1146/2380/6158 1122/2388/6159 -f 1122/2388/6160 1123/2389/6161 1147/2381/6162 -f 1151/2385/6163 1147/2381/6164 1123/2389/6165 -f 1123/2389/6166 1140/1346/6167 1151/2385/6168 -f 1150/2384/6169 1151/2385/6170 1140/1346/6171 -f 1140/1346/6172 1138/1344/6173 1150/2384/6174 -f 1149/2382/6175 1150/2384/6176 1138/1344/6177 -f 1138/1344/6178 1136/1343/6179 1149/2382/6180 -f 1144/1347/6181 1149/2382/6182 1136/1343/6183 -f 1136/1343/6184 1148/2390/6185 1144/1347/6186 -f 1143/1348/6187 1144/1347/6188 1148/2390/6189 -f 1148/2390/6190 1152/2386/6191 1143/1348/6192 -f 707/793/6193 1155/1239/6194 1154/1238/6195 -f 1154/1238/6196 706/790/6197 707/793/6198 -f 1128/1213/6199 1156/1240/6200 1155/1239/6201 -f 1155/1239/6202 707/793/6203 1128/1213/6204 -f 1154/1238/6205 1157/1241/6206 708/791/6207 -f 708/791/6208 706/790/6209 1154/1238/6210 -f 1159/2393/6211 1158/2394/6212 1161/2391/6213 -f 1161/2391/6214 1160/2392/6215 1159/2393/6216 -f 1158/2394/6217 1162/2396/6218 1163/2395/6219 -f 1163/2395/6220 1161/2391/6221 1158/2394/6222 -f 1164/1248/6223 1156/1240/6224 1128/1213/6225 -f 1128/1213/6226 1127/1212/6227 1164/1248/6228 -f 1133/1214/6229 1166/1250/6230 1165/1249/6231 -f 1165/1249/6232 1132/1215/6233 1133/1214/6234 -f 1132/1215/6235 1165/1249/6236 1167/1251/6237 -f 1167/1251/6238 1135/1218/6239 1132/1215/6240 -f 1137/1220/6241 1168/1252/6242 1166/1250/6243 -f 1166/1250/6244 1133/1214/6245 1137/1220/6246 -f 1169/2399/6247 1172/2400/6248 1171/2397/6249 -f 1171/2397/6250 1170/2398/6251 1169/2399/6252 -f 1173/2401/6253 1174/2402/6254 1172/2400/6255 -f 1172/2400/6256 1169/2399/6257 1173/2401/6258 -f 1135/1218/6259 1167/1251/6260 1175/1259/6261 -f 1175/1259/6262 1141/1224/6263 1135/1218/6264 -f 1166/1250/6265 1154/1238/6266 1155/1239/6267 -f 1155/1239/6268 1165/1249/6269 1166/1250/6270 -f 1165/1249/6271 1155/1239/6272 1156/1240/6273 -f 1156/1240/6274 1167/1251/6275 1165/1249/6276 -f 1168/1252/6277 1157/1241/6278 1154/1238/6279 -f 1154/1238/6280 1166/1250/6281 1168/1252/6282 -f 1172/2400/6283 1177/2404/6284 1176/2403/6285 -f 1176/2403/6286 1171/2397/6287 1172/2400/6288 -f 1174/2402/6289 1178/2405/6290 1177/2404/6291 -f 1177/2404/6292 1172/2400/6293 1174/2402/6294 -f 1167/1251/6295 1156/1240/6296 1164/1248/6297 -f 1164/1248/6298 1175/1259/6299 1167/1251/6300 -f 1169/2399/6301 1170/2398/6302 1137/1342/6303 -f 1137/1342/6304 1139/1341/6305 1169/2399/6306 -f 1173/2401/6307 1169/2399/6308 1139/1341/6309 -f 1139/1341/6310 1141/1345/6311 1173/2401/6312 -f 1174/2402/6313 1173/2401/6314 1141/1345/6315 -f 1141/1345/6316 1175/2406/6317 1174/2402/6318 -f 1178/2405/6319 1174/2402/6320 1175/2406/6321 -f 1175/2406/6322 1164/2407/6323 1178/2405/6324 -f 1177/2404/6325 1178/2405/6326 1164/2407/6327 -f 1164/2407/6328 1179/2408/6329 1177/2404/6330 -f 1176/2403/6331 1177/2404/6332 1179/2408/6333 -f 1179/2408/6334 1157/2409/6335 1176/2403/6336 -f 1171/2397/6337 1176/2403/6338 1157/2409/6339 -f 1157/2409/6340 1168/2410/6341 1171/2397/6342 -f 1170/2398/6343 1171/2397/6344 1168/2410/6345 -f 1168/2410/6346 1137/1342/6347 1170/2398/6348 -f 1181/2413/6349 1180/2414/6350 1129/2411/6351 -f 1129/2411/6352 708/2412/6353 1181/2413/6354 -f 1182/2415/6355 1181/2413/6356 708/2412/6357 -f 708/2412/6358 1157/2409/6359 1182/2415/6360 -f 1183/2416/6361 1182/2415/6362 1157/2409/6363 -f 1157/2409/6364 1179/2408/6365 1183/2416/6366 -f 1184/2417/6367 1183/2416/6368 1179/2408/6369 -f 1179/2408/6370 1164/2407/6371 1184/2417/6372 -f 1185/2419/6373 1184/2417/6374 1164/2407/6375 -f 1164/2407/6376 1127/2418/6377 1185/2419/6378 -f 1180/2414/6379 1185/2419/6380 1127/2418/6381 -f 1127/2418/6382 1129/2411/6383 1180/2414/6384 -f 1160/2392/6385 1161/2391/6386 1180/2414/6387 -f 1180/2414/6388 1181/2413/6389 1160/2392/6390 -f 1159/2393/6391 1160/2392/6392 1181/2413/6393 -f 1181/2413/6394 1182/2415/6395 1159/2393/6396 -f 1158/2394/6397 1159/2393/6398 1182/2415/6399 -f 1182/2415/6400 1183/2416/6401 1158/2394/6402 -f 1162/2396/6403 1158/2394/6404 1183/2416/6405 -f 1183/2416/6406 1184/2417/6407 1162/2396/6408 -f 1163/2395/6409 1162/2396/6410 1184/2417/6411 -f 1184/2417/6412 1185/2419/6413 1163/2395/6414 -f 1161/2391/6415 1163/2395/6416 1185/2419/6417 -f 1185/2419/6418 1180/2414/6419 1161/2391/6420 -f 741/824/6421 742/823/6422 1186/1270/6423 -f 1186/1270/6424 1187/1271/6425 741/824/6426 -f 1188/1274/6427 1191/1275/6428 1190/1272/6429 -f 1190/1272/6430 1189/1273/6431 1188/1274/6432 -f 1192/1276/6433 1112/1200/6434 712/795/6435 -f 712/795/6436 715/799/6437 1192/1276/6438 -f 1110/2420/6439 729/812/6440 730/811/6441 -f 730/811/6442 851/1337/6443 1110/2420/6444 -f 1194/2423/6445 1193/2424/6446 704/2421/6447 -f 704/2421/6448 705/2422/6449 1194/2423/6450 -f 728/813/6451 1114/1339/6452 1109/1336/6453 -f 1109/1336/6454 727/814/6455 728/813/6456 -f 1197/2426/6457 1196/2427/6458 1195/2425/6459 -f 1195/2425/6460 726/807/6461 1197/2426/6462 -f 725/808/6463 726/807/6464 1195/2425/6465 -f 1195/2425/6466 1115/1340/6467 725/808/6468 -f 1198/2430/6469 1118/2431/6470 1119/2428/6471 -f 1119/2428/6472 1199/2429/6473 1198/2430/6474 -f 1113/1338/6475 724/809/6476 1108/1335/6477 -f 1108/1335/6478 1107/1334/6479 1113/1338/6480 -f 1197/2426/6481 726/807/6482 723/810/6483 -f 723/810/6484 1200/2432/6485 1197/2426/6486 -f 1113/1338/6487 1201/2433/6488 723/810/6489 -f 723/810/6490 724/809/6491 1113/1338/6492 -f 1202/1277/6493 1186/1270/6494 742/823/6495 -f 742/823/6496 763/841/6497 1202/1277/6498 -f 853/939/6499 1203/1286/6500 1202/1277/6501 -f 1202/1277/6502 763/841/6503 853/939/6504 -f 1106/1332/6505 1115/1340/6506 1203/2434/6507 -f 1203/2434/6508 853/1333/6509 1106/1332/6510 -f 1204/1287/6511 1192/1276/6512 715/799/6513 -f 715/799/6514 716/798/6515 1204/1287/6516 -f 1205/2435/6517 1199/2429/6518 1115/1340/6519 -f 1115/1340/6520 1195/2425/6521 1205/2435/6522 -f 1206/2436/6523 1205/2435/6524 1195/2425/6525 -f 1195/2425/6526 1196/2427/6527 1206/2436/6528 -f 1207/2438/6529 1206/2436/6530 1196/2427/6531 -f 1196/2427/6532 1208/2437/6533 1207/2438/6534 -f 1209/2440/6535 1207/2438/6536 1208/2437/6537 -f 1208/2437/6538 1191/2439/6539 1209/2440/6540 -f 1210/1288/6541 1209/1293/6542 1191/1275/6543 -f 1191/1275/6544 1188/1274/6545 1210/1288/6546 -f 1187/1271/6547 1211/1294/6548 1204/1287/6549 -f 1204/1287/6550 716/798/6551 1187/1271/6552 -f 1211/1294/6553 1210/1288/6554 1188/1274/6555 -f 1188/1274/6556 1204/1287/6557 1211/1294/6558 -f 1213/1295/6559 1212/1296/6560 1120/1206/6561 -f 1120/1206/6562 1121/1205/6563 1213/1295/6564 -f 1153/2387/6565 1152/2386/6566 1206/2436/6567 -f 1206/2436/6568 1207/2438/6569 1153/2387/6570 -f 1209/2440/6571 1122/2388/6572 1153/2387/6573 -f 1153/2387/6574 1207/2438/6575 1209/2440/6576 -f 1214/1297/6577 1122/1209/6578 1209/1293/6579 -f 1209/1293/6580 1210/1288/6581 1214/1297/6582 -f 1211/1294/6583 1213/1295/6584 1214/1297/6585 -f 1214/1297/6586 1210/1288/6587 1211/1294/6588 -f 1187/1271/6589 1212/1296/6590 1213/1295/6591 -f 1213/1295/6592 1211/1294/6593 1187/1271/6594 -f 1186/1270/6595 1120/1206/6596 1212/1296/6597 -f 1212/1296/6598 1187/1271/6599 1186/1270/6600 -f 1203/1286/6601 1119/1202/6602 1116/1201/6603 -f 1116/1201/6604 1202/1277/6605 1203/1286/6606 -f 1199/2429/6607 1119/2428/6608 1203/2434/6609 -f 1203/2434/6610 1115/1340/6611 1199/2429/6612 -f 1206/2436/6613 1152/2386/6614 1215/2441/6615 -f 1215/2441/6616 1205/2435/6617 1206/2436/6618 -f 1116/1201/6619 1120/1206/6620 1186/1270/6621 -f 1186/1270/6622 1202/1277/6623 1116/1201/6624 -f 1198/2430/6625 1199/2429/6626 1205/2435/6627 -f 1205/2435/6628 1215/2441/6629 1198/2430/6630 -f 1198/2430/6631 1215/2441/6632 1216/2442/6633 -f 1216/2442/6634 1118/2431/6635 1198/2430/6636 -f 702/789/6637 703/788/6638 1217/1298/6639 -f 1217/1298/6640 1218/1300/6641 702/789/6642 -f 755/839/6643 756/836/6644 719/803/6645 -f 719/803/6646 1111/1196/6647 755/839/6648 -f 1194/2423/6649 729/812/6650 1110/2420/6651 -f 1110/2420/6652 1193/2424/6653 1194/2423/6654 -f 1219/1301/6655 1193/1302/6656 1110/1195/6657 -f 1110/1195/6658 1111/1196/6659 1219/1301/6660 -f 717/802/6661 1219/1301/6662 1111/1196/6663 -f 1111/1196/6664 719/803/6665 717/802/6666 -f 716/798/6667 713/801/6668 741/824/6669 -f 741/824/6670 1187/1271/6671 716/798/6672 -f 715/799/6673 712/795/6674 709/794/6675 -f 709/794/6676 714/800/6677 715/799/6678 -f 1112/1200/6679 1192/1276/6680 1189/1273/6681 -f 1189/1273/6682 1220/1303/6683 1112/1200/6684 -f 1204/1287/6685 1188/1274/6686 1189/1273/6687 -f 1189/1273/6688 1192/1276/6689 1204/1287/6690 -f 1217/1298/6691 1221/1304/6692 1220/1303/6693 -f 1220/1303/6694 1218/1300/6695 1217/1298/6696 -f 703/788/6697 704/787/6698 1193/1302/6699 -f 1193/1302/6700 1219/1301/6701 703/788/6702 -f 717/802/6703 1217/1298/6704 703/788/6705 -f 703/788/6706 1219/1301/6707 717/802/6708 -f 1221/1304/6709 1217/1298/6710 717/802/6711 -f 717/802/6712 718/804/6713 1221/1304/6714 -f 1112/1200/6715 1220/1303/6716 1221/1304/6717 -f 1221/1304/6718 718/804/6719 1112/1200/6720 -f 1190/1272/6721 1218/1300/6722 1220/1303/6723 -f 1220/1303/6724 1189/1273/6725 1190/1272/6726 -f 1223/2444/6727 1222/2445/6728 705/2574/6729 -f 705/2574/6730 702/2443/6731 1223/2444/6732 -f 1224/2447/6733 1223/2444/6734 702/2443/6735 -f 702/2443/6736 1218/2446/6737 1224/2447/6738 -f 1225/2449/6739 1224/2447/6740 1218/2446/6741 -f 1218/2446/6742 1190/2448/6743 1225/2449/6744 -f 1226/2450/6745 1225/2449/6746 1190/2448/6747 -f 1190/2448/6748 1191/2439/6749 1226/2450/6750 -f 1227/2451/6751 1226/2450/6752 1191/2439/6753 -f 1191/2439/6754 1208/2437/6755 1227/2451/6756 -f 1228/2452/6757 1227/2451/6758 1208/2437/6759 -f 1208/2437/6760 1196/2427/6761 1228/2452/6762 -f 1229/2453/6763 1228/2452/6764 1196/2427/6765 -f 1196/2427/6766 1197/2426/6767 1229/2453/6768 -f 1230/2454/6769 1229/2453/6770 1197/2426/6771 -f 1197/2426/6772 1200/2432/6773 1230/2454/6774 -f 1231/2456/6775 1230/2454/6776 1200/2432/6777 -f 1200/2432/6778 1232/2455/6779 1231/2456/6780 -f 1194/2423/6781 705/2422/6782 1233/2457/6783 -f 1233/2457/6784 1234/2458/6785 1194/2423/6786 -f 1201/2433/6787 1232/2455/6788 1200/2432/6789 -f 1200/2432/6790 723/810/6791 1201/2433/6792 -f 1235/2460/6793 1222/2445/6794 1223/2444/6795 -f 1223/2444/6796 1236/2459/6797 1235/2460/6798 -f 1237/2461/6799 1236/2459/6800 1223/2444/6801 -f 1223/2444/6802 1224/2447/6803 1237/2461/6804 -f 1237/2461/6805 1224/2447/6806 1225/2449/6807 -f 1225/2449/6808 1238/2462/6809 1237/2461/6810 -f 1238/2462/6811 1225/2449/6812 1226/2450/6813 -f 1226/2450/6814 1239/2463/6815 1238/2462/6816 -f 1239/2463/6817 1226/2450/6818 1227/2451/6819 -f 1227/2451/6820 1240/2464/6821 1239/2463/6822 -f 1241/2465/6823 1240/2464/6824 1227/2451/6825 -f 1227/2451/6826 1228/2452/6827 1241/2465/6828 -f 1242/2466/6829 1241/2465/6830 1228/2452/6831 -f 1228/2452/6832 1229/2453/6833 1242/2466/6834 -f 1243/2467/6835 1242/2466/6836 1229/2453/6837 -f 1229/2453/6838 1230/2454/6839 1243/2467/6840 -f 1243/2467/6841 1230/2454/6842 1231/2456/6843 -f 1231/2456/6844 1244/2468/6845 1243/2467/6846 -f 1244/2468/6847 1231/2456/6848 1222/2575/6849 -f 1222/2575/6850 1235/2576/6851 1244/2468/6852 -f 1213/1295/6853 1121/1205/6854 1122/1209/6855 -f 1122/1209/6856 1214/1297/6857 1213/1295/6858 -f 1118/1203/6859 1216/1305/6860 1148/1232/6861 -f 1148/1232/6862 1126/1210/6863 1118/1203/6864 -f 1148/2390/6865 1216/2442/6866 1215/2441/6867 -f 1215/2441/6868 1152/2386/6869 1148/2390/6870 -f 1247/2471/6871 1246/2472/6872 1245/2469/6873 -f 1245/2469/6874 1248/2470/6875 1247/2471/6876 -f 1250/2473/6877 1249/2474/6878 1247/2471/6879 -f 1247/2471/6880 1248/2470/6881 1250/2473/6882 -f 1251/2476/6883 1249/2474/6884 1250/2473/6885 -f 1250/2473/6886 1252/2475/6887 1251/2476/6888 -f 1246/2578/6889 1261/2478/6890 1260/2477/6891 -f 1260/2477/6892 1245/2577/6893 1246/2578/6894 -f 1194/2423/6895 1234/2458/6896 728/813/6897 -f 728/813/6898 729/812/6899 1194/2423/6900 -f 1262/2479/6901 1114/1339/6902 728/813/6903 -f 728/813/6904 1234/2458/6905 1262/2479/6906 -f 1114/1339/6907 1262/2479/6908 1201/2433/6909 -f 1201/2433/6910 1113/1338/6911 1114/1339/6912 -f 1263/2480/6913 1262/2479/6914 1234/2458/6915 -f 1234/2458/6916 1233/2457/6917 1263/2480/6918 -f 1264/2481/6919 1233/2457/6920 705/2422/6921 -f 705/2422/6922 1222/2575/6923 1264/2481/6924 -f 1231/2456/6925 1265/2482/6926 1264/2481/6927 -f 1264/2481/6928 1222/2575/6929 1231/2456/6930 -f 1263/2480/6931 1233/2457/6932 1264/2481/6933 -f 1264/2481/6934 1265/2482/6935 1263/2480/6936 -f 1232/2455/6937 1263/2480/6938 1265/2482/6939 -f 1265/2482/6940 1231/2456/6941 1232/2455/6942 -f 1262/2479/6943 1263/2480/6944 1232/2455/6945 -f 1232/2455/6946 1201/2433/6947 1262/2479/6948 -f 1260/2477/6949 1258/2483/6950 1243/2467/6951 -f 1243/2467/6952 1244/2468/6953 1260/2477/6954 -f 1257/2484/6955 1242/2466/6956 1243/2467/6957 -f 1243/2467/6958 1258/2483/6959 1257/2484/6960 -f 1256/2486/6961 1241/2465/6962 1242/2466/6963 -f 1242/2466/6964 1257/2484/6965 1256/2486/6966 -f 1255/2487/6967 1240/2464/6968 1241/2465/6969 -f 1241/2465/6970 1256/2486/6971 1255/2487/6972 -f 1254/2488/6973 1239/2463/6974 1240/2464/6975 -f 1240/2464/6976 1255/2487/6977 1254/2488/6978 -f 1252/2475/6979 1254/2488/6980 1253/2489/6981 -f 1253/2489/6982 1251/2476/6983 1252/2475/6984 -f 1237/2461/6985 1238/2462/6986 1252/2475/6987 -f 1252/2475/6988 1250/2473/6989 1237/2461/6990 -f 1236/2459/6991 1237/2461/6992 1250/2473/6993 -f 1250/2473/6994 1248/2470/6995 1236/2459/6996 -f 1245/2469/6997 1235/2460/6998 1236/2459/6999 -f 1236/2459/7000 1248/2470/7001 1245/2469/7002 -f 1244/2468/7003 1235/2576/7004 1245/2577/7005 -f 1245/2577/7006 1260/2477/7007 1244/2468/7008 -f 1260/2477/7009 1261/2478/7010 1259/2490/7011 -f 1259/2490/7012 1258/2483/7013 1260/2477/7014 -f 1252/2475/7015 1238/2462/7016 1239/2463/7017 -f 1239/2463/7018 1254/2488/7019 1252/2475/7020 -f 587/1398/7021 437/519/7022 443/526/7023 -f 443/526/7024 444/525/7025 587/1398/7026 -f 645/734/7027 640/729/7028 450/535/7029 -f 450/535/7030 451/534/7031 645/734/7032 -f 621/709/7033 624/713/7034 650/739/7035 -f 650/739/7036 620/710/7037 621/709/7038 -f 622/711/7039 623/714/7040 624/2605/7041 -f 624/2605/7042 621/2603/7043 622/711/7044 -f 424/507/7045 420/504/7046 629/718/7047 -f 629/718/7048 622/711/7049 424/507/7050 -f 420/504/7051 421/503/7052 632/721/7053 -f 632/721/7054 629/718/7055 420/504/7056 -f 421/503/7057 604/690/7058 635/724/7059 -f 635/724/7060 632/721/7061 421/503/7062 -f 604/690/7063 605/691/7064 638/727/7065 -f 638/727/7066 635/724/7067 604/690/7068 -f 605/691/7069 449/533/7070 450/535/7071 -f 450/535/7072 638/727/7073 605/691/7074 -f 651/740/7075 617/706/7076 618/707/7077 -f 618/707/7078 620/710/7079 651/740/7080 -f 451/534/7081 446/532/7082 617/706/7083 -f 617/706/7084 651/740/7085 451/534/7086 -f 607/693/7087 608/2569/7088 448/530/7089 -f 448/530/7090 449/533/7091 607/693/7092 -f 642/730/7093 1266/2570/7094 671/759/7095 -f 671/759/7096 641/731/7097 642/730/7098 -f 643/733/7099 1267/2571/7100 1266/2570/7101 -f 1266/2570/7102 642/730/7103 643/733/7104 -f 1268/2572/7105 1267/2571/7106 643/733/7107 -f 643/733/7108 646/736/7109 1268/2572/7110 -f 655/746/7111 1268/2572/7112 646/736/7113 -f 646/736/7114 652/741/7115 655/746/7116 -f 654/2607/7117 655/746/7118 652/741/7119 -f 652/741/7120 653/742/7121 654/2607/7122 -f 653/2606/7123 625/712/7124 626/715/7125 -f 626/715/7126 660/749/7127 653/2606/7128 -f 626/715/7129 627/716/7130 663/752/7131 -f 663/752/7132 660/749/7133 626/715/7134 -f 627/716/7135 630/719/7136 666/755/7137 -f 666/755/7138 663/752/7139 627/716/7140 -f 630/719/7141 633/722/7142 669/758/7143 -f 669/758/7144 666/755/7145 630/719/7146 -f 633/722/7147 636/725/7148 641/731/7149 -f 641/731/7150 669/758/7151 633/722/7152 -f 657/744/7153 688/776/7154 686/775/7155 -f 686/775/7156 656/745/7157 657/744/7158 -f 658/748/7159 690/778/7160 688/2609/7161 -f 688/2609/7162 657/2608/7163 658/748/7164 -f 661/751/7165 692/1351/7166 690/778/7167 -f 690/778/7168 658/748/7169 661/751/7170 -f 664/754/7171 694/2566/7172 692/1351/7173 -f 692/1351/7174 661/751/7175 664/754/7176 -f 673/762/7177 694/2566/7178 664/754/7179 -f 664/754/7180 667/757/7181 673/762/7182 -f 672/763/7183 673/762/7184 667/757/7185 -f 667/757/7186 670/760/7187 672/763/7188 -f 671/759/7189 1266/2570/7190 678/767/7191 -f 678/767/7192 670/760/7193 671/759/7194 -f 1266/2570/7195 1267/2571/7196 681/770/7197 -f 681/770/7198 678/767/7199 1266/2570/7200 -f 1267/2571/7201 1268/2572/7202 684/773/7203 -f 684/773/7204 681/770/7205 1267/2571/7206 -f 684/773/7207 1268/2572/7208 655/746/7209 -f 655/746/7210 656/745/7211 684/773/7212 -f 1270/1432/7213 1269/478/7214 397/475/7215 -f 397/475/7216 1271/1431/7217 1270/1432/7218 -f 1270/1432/7219 1271/1431/7220 1272/1543/7221 -f 1272/1543/7222 1273/1544/7223 1270/1432/7224 -f 1276/1360/7225 1275/1361/7226 1274/1358/7227 -f 1274/1358/7228 1277/1359/7229 1276/1360/7230 -f 1279/1362/7231 1278/1363/7232 1275/1361/7233 -f 1275/1361/7234 1276/1360/7235 1279/1362/7236 -f 1276/1360/7237 1277/1359/7238 1280/1364/7239 -f 1280/1364/7240 1279/1362/7241 1276/1360/7242 -f 1283/1367/7243 1282/1368/7244 1281/1365/7245 -f 1281/1365/7246 1284/1366/7247 1283/1367/7248 -f 1283/1367/7249 1284/1366/7250 1285/1369/7251 -f 1285/1369/7252 1286/1370/7253 1283/1367/7254 -f 1283/1367/7255 1286/1370/7256 1287/1371/7257 -f 1287/1371/7258 1288/1372/7259 1283/1367/7260 -f 1283/1367/7261 1288/1372/7262 1289/1373/7263 -f 1289/1373/7264 1290/1374/7265 1283/1367/7266 -f 1283/1367/7267 1290/1374/7268 1291/1375/7269 -f 1291/1375/7270 1282/1368/7271 1283/1367/7272 -f 1294/1376/7273 1293/1377/7274 1292/479/7275 -f 1292/479/7276 1295/686/7277 1294/1376/7278 -f 1294/1376/7279 1297/1379/7280 1296/1378/7281 -f 1296/1378/7282 1293/1377/7283 1294/1376/7284 -f 1300/1384/7285 1299/1385/7286 1298/1382/7287 -f 1298/1382/7288 1301/1383/7289 1300/1384/7290 -f 1303/2586/7291 1302/1387/7292 1299/1385/7293 -f 1299/1385/7294 1300/1384/7295 1303/2586/7296 -f 1300/1570/7297 1301/1571/7298 1304/1541/7299 -f 1304/1541/7300 1303/1542/7301 1300/1570/7302 -f 1307/1547/7303 1306/1548/7304 1305/1545/7305 -f 1305/1545/7306 1308/1546/7307 1307/1547/7308 -f 1307/1547/7309 1310/1551/7310 1309/1550/7311 -f 1309/1550/7312 1306/1548/7313 1307/1547/7314 -f 1307/1547/7315 1308/1546/7316 1273/1544/7317 -f 1273/1544/7318 1311/1552/7319 1307/1547/7320 -f 1308/1546/7321 1305/1545/7322 1312/1553/7323 -f 1312/1553/7324 1313/1554/7325 1308/1546/7326 -f 1316/1557/7327 1315/1558/7328 1314/1555/7329 -f 1314/1555/7330 1317/1556/7331 1316/1557/7332 -f 1317/1556/7333 1312/1553/7334 1305/1545/7335 -f 1305/1545/7336 1316/1557/7337 1317/1556/7338 -f 1317/1556/7339 1314/1555/7340 1318/1559/7341 -f 1318/1559/7342 1312/1553/7343 1317/1556/7344 -f 1321/1403/7345 1320/1404/7346 1319/1380/7347 -f 1319/1380/7348 1322/1381/7349 1321/1403/7350 -f 1323/1406/7351 1321/1403/7352 1322/1381/7353 -f 1322/1381/7354 1324/1405/7355 1323/1406/7356 -f 1306/1548/7357 1309/1550/7358 1316/1557/7359 -f 1316/1557/7360 1305/1545/7361 1306/1548/7362 -f 1327/1562/7363 1326/1563/7364 1325/1560/7365 -f 1325/1560/7366 1328/1561/7367 1327/1562/7368 -f 1327/1562/7369 1330/1566/7370 1329/1564/7371 -f 1329/1564/7372 1331/1565/7373 1327/1562/7374 -f 1327/1562/7375 1331/1565/7376 1332/1567/7377 -f 1332/1567/7378 1326/1563/7379 1327/1562/7380 -f 1334/1418/7381 1333/1419/7382 1329/1413/7383 -f 1329/1413/7384 1335/1417/7385 1334/1418/7386 -f 1334/1418/7387 1274/1358/7388 1275/1361/7389 -f 1275/1361/7390 1278/1363/7391 1334/1418/7392 -f 1334/1418/7393 1278/1363/7394 1336/1420/7395 -f 1336/1420/7396 1333/1419/7397 1334/1418/7398 -f 1290/1374/7399 1289/1373/7400 1337/1421/7401 -f 1337/1421/7402 1291/1375/7403 1290/1374/7404 -f 1335/1569/7405 1329/1564/7406 1330/1566/7407 -f 1330/1566/7408 1338/1568/7409 1335/1569/7410 -f 1335/1417/7411 1338/1423/7412 1339/1422/7413 -f 1339/1422/7414 1334/1418/7415 1335/1417/7416 -f 1342/1408/7417 1341/1424/7418 1340/1407/7419 -f 1340/1407/7420 1297/1379/7421 1342/1408/7422 -f 1345/1574/7423 1344/1575/7424 1343/1572/7425 -f 1343/1572/7426 1346/1573/7427 1345/1574/7428 -f 1345/1687/7429 1346/2491/7430 1347/1598/7431 -f 1347/1598/7432 1348/1686/7433 1345/1687/7434 -f 1346/1573/7435 1343/1572/7436 1349/1576/7437 -f 1349/1576/7438 1350/1577/7439 1346/1573/7440 -f 1346/2491/7441 1350/2493/7442 1351/2492/7443 -f 1351/2492/7444 1347/1598/7445 1346/2491/7446 -f 1351/1435/7447 1350/1436/7448 1352/1433/7449 -f 1352/1433/7450 1353/1434/7451 1351/1435/7452 -f 1351/1435/7453 1353/1434/7454 1339/1422/7455 -f 1339/1422/7456 1338/1423/7457 1351/1435/7458 -f 1351/2492/7459 1338/1568/7460 1330/1566/7461 -f 1330/1566/7462 1347/1598/7463 1351/2492/7464 -f 1353/1434/7465 1352/1433/7466 1354/1437/7467 -f 1354/1437/7468 1355/1438/7469 1353/1434/7470 -f 1353/1434/7471 1355/1438/7472 1356/1439/7473 -f 1356/1439/7474 1339/1422/7475 1353/1434/7476 -f 1356/1439/7477 1355/1438/7478 1357/1440/7479 -f 1357/1440/7480 1358/1441/7481 1356/1439/7482 -f 1356/1439/7483 1358/1441/7484 1277/1359/7485 -f 1277/1359/7486 1274/1358/7487 1356/1439/7488 -f 1356/1439/7489 1274/1358/7490 1334/1418/7491 -f 1334/1418/7492 1339/1422/7493 1356/1439/7494 -f 1358/1441/7495 1357/1440/7496 1359/1442/7497 -f 1359/1442/7498 1360/1443/7499 1358/1441/7500 -f 1358/1441/7501 1360/1443/7502 1361/1444/7503 -f 1361/1444/7504 1277/1359/7505 1358/1441/7506 -f 1361/1444/7507 1360/1443/7508 1362/1445/7509 -f 1362/1445/7510 1363/1446/7511 1361/1444/7512 -f 1361/1444/7513 1363/1446/7514 1364/1447/7515 -f 1364/1447/7516 1365/1448/7517 1361/1444/7518 -f 1361/1444/7519 1365/1448/7520 1280/1364/7521 -f 1280/1364/7522 1277/1359/7523 1361/1444/7524 -f 1365/1448/7525 1364/1447/7526 1366/1449/7527 -f 1366/1449/7528 1337/1421/7529 1365/1448/7530 -f 1365/1448/7531 1337/1421/7532 1289/1373/7533 -f 1289/1373/7534 1280/1364/7535 1365/1448/7536 -f 1364/1447/7537 1363/1446/7538 1367/1450/7539 -f 1367/1450/7540 1368/1451/7541 1364/1447/7542 -f 1364/1447/7543 1368/1451/7544 1369/1452/7545 -f 1369/1452/7546 1366/1449/7547 1364/1447/7548 -f 1368/1451/7549 1367/1450/7550 1370/1453/7551 -f 1370/1453/7552 1371/1454/7553 1368/1451/7554 -f 1368/1451/7555 1371/1454/7556 1372/1455/7557 -f 1372/1455/7558 1369/1452/7559 1368/1451/7560 -f 1372/1455/7561 1371/1454/7562 1373/1456/7563 -f 1373/1456/7564 1374/1457/7565 1372/1455/7566 -f 1372/1455/7567 1374/1457/7568 1375/1458/7569 -f 1375/1458/7570 1376/1459/7571 1372/1455/7572 -f 1372/1455/7573 1376/1459/7574 1377/1460/7575 -f 1377/1460/7576 1369/1452/7577 1372/1455/7578 -f 1376/1459/7579 1375/1458/7580 1378/1461/7581 -f 1378/1461/7582 1379/1462/7583 1376/1459/7584 -f 1376/1459/7585 1379/1462/7586 1380/1463/7587 -f 1380/1463/7588 1377/1460/7589 1376/1459/7590 -f 1380/1463/7591 1382/1465/7592 1381/1464/7593 -f 1381/1464/7594 1377/1460/7595 1380/1463/7596 -f 1380/2589/7597 1379/2588/7598 1383/1466/7599 -f 1383/1466/7600 1384/1467/7601 1380/2589/7602 -f 1380/2589/7603 1384/1467/7604 1385/1468/7605 -f 1385/1468/7606 1382/2590/7607 1380/2589/7608 -f 1383/2591/7609 1379/1462/7610 1378/1461/7611 -f 1378/1461/7612 1386/1469/7613 1383/2591/7614 -f 1383/2591/7615 1386/1469/7616 1387/1470/7617 -f 1387/1470/7618 1388/1471/7619 1383/2591/7620 -f 1383/1466/7621 1388/2593/7622 1389/1472/7623 -f 1389/1472/7624 1384/1467/7625 1383/1466/7626 -f 1388/2593/7627 1387/2592/7628 1390/1473/7629 -f 1390/1473/7630 1391/1474/7631 1388/2593/7632 -f 1388/2593/7633 1391/1474/7634 1392/1475/7635 -f 1392/1475/7636 1389/1472/7637 1388/2593/7638 -f 1392/1475/7639 1394/1477/7640 1393/1476/7641 -f 1393/1476/7642 1389/1472/7643 1392/1475/7644 -f 1392/1475/7645 1391/1474/7646 1395/1478/7647 -f 1395/1478/7648 1396/1479/7649 1392/1475/7650 -f 1392/1475/7651 1396/1479/7652 1397/1480/7653 -f 1397/1480/7654 1394/1477/7655 1392/1475/7656 -f 1397/1480/7657 1399/1482/7658 1398/1481/7659 -f 1398/1481/7660 1394/1477/7661 1397/1480/7662 -f 1397/1480/7663 1396/1479/7664 1400/1483/7665 -f 1400/1483/7666 1401/1484/7667 1397/1480/7668 -f 1397/1480/7669 1401/1484/7670 1402/1485/7671 -f 1402/1485/7672 1399/1482/7673 1397/1480/7674 -f 1402/1485/7675 1404/1487/7676 1403/1486/7677 -f 1403/1486/7678 1399/1482/7679 1402/1485/7680 -f 1402/1485/7681 1401/1484/7682 1405/1488/7683 -f 1405/1488/7684 1359/1442/7685 1402/1485/7686 -f 1402/1485/7687 1359/1442/7688 1357/1440/7689 -f 1357/1440/7690 1404/1487/7691 1402/1485/7692 -f 1405/1488/7693 1401/1484/7694 1400/1483/7695 -f 1400/1483/7696 1406/1489/7697 1405/1488/7698 -f 1405/1488/7699 1406/1489/7700 1407/1490/7701 -f 1407/1490/7702 1362/1445/7703 1405/1488/7704 -f 1405/1488/7705 1362/1445/7706 1360/1443/7707 -f 1360/1443/7708 1359/1442/7709 1405/1488/7710 -f 1407/1490/7711 1406/1489/7712 1408/1491/7713 -f 1408/1491/7714 1409/1492/7715 1407/1490/7716 -f 1407/1490/7717 1409/1492/7718 1370/1453/7719 -f 1370/1453/7720 1367/1450/7721 1407/1490/7722 -f 1407/1490/7723 1367/1450/7724 1363/1446/7725 -f 1363/1446/7726 1362/1445/7727 1407/1490/7728 -f 1409/1492/7729 1408/1491/7730 1410/1493/7731 -f 1410/1493/7732 1411/1494/7733 1409/1492/7734 -f 1409/1492/7735 1411/1494/7736 1412/1495/7737 -f 1412/1495/7738 1370/1453/7739 1409/1492/7740 -f 1412/1495/7741 1411/1494/7742 1413/1496/7743 -f 1413/1496/7744 1414/1497/7745 1412/1495/7746 -f 1412/1495/7747 1414/1497/7748 1415/1498/7749 -f 1415/1498/7750 1373/1456/7751 1412/1495/7752 -f 1412/1495/7753 1373/1456/7754 1371/1454/7755 -f 1371/1454/7756 1370/1453/7757 1412/1495/7758 -f 1415/1498/7759 1416/1499/7760 1374/1457/7761 -f 1374/1457/7762 1373/1456/7763 1415/1498/7764 -f 1416/1499/7765 1417/1500/7766 1375/1458/7767 -f 1375/1458/7768 1374/1457/7769 1416/1499/7770 -f 1417/1500/7771 1418/1501/7772 1378/1461/7773 -f 1378/1461/7774 1375/1458/7775 1417/1500/7776 -f 1418/1501/7777 1419/1502/7778 1386/1469/7779 -f 1386/1469/7780 1378/1461/7781 1418/1501/7782 -f 1419/1502/7783 1420/1503/7784 1387/1470/7785 -f 1387/1470/7786 1386/1469/7787 1419/1502/7788 -f 1420/2594/7789 1421/1504/7790 1390/1473/7791 -f 1390/1473/7792 1387/2592/7793 1420/2594/7794 -f 1421/1504/7795 1423/1506/7796 1422/1505/7797 -f 1422/1505/7798 1390/1473/7799 1421/1504/7800 -f 1422/1505/7801 1395/1478/7802 1391/1474/7803 -f 1391/1474/7804 1390/1473/7805 1422/1505/7806 -f 1422/1505/7807 1423/1506/7808 1424/1507/7809 -f 1424/1507/7810 1425/1508/7811 1422/1505/7812 -f 1422/1505/7813 1425/1508/7814 1426/1509/7815 -f 1426/1509/7816 1395/1478/7817 1422/1505/7818 -f 1426/1509/7819 1400/1483/7820 1396/1479/7821 -f 1396/1479/7822 1395/1478/7823 1426/1509/7824 -f 1426/1509/7825 1425/1508/7826 1410/1493/7827 -f 1410/1493/7828 1408/1491/7829 1426/1509/7830 -f 1426/1509/7831 1408/1491/7832 1406/1489/7833 -f 1406/1489/7834 1400/1483/7835 1426/1509/7836 -f 1425/1508/7837 1424/1507/7838 1427/1510/7839 -f 1427/1510/7840 1410/1493/7841 1425/1508/7842 -f 1427/1510/7843 1413/1496/7844 1411/1494/7845 -f 1411/1494/7846 1410/1493/7847 1427/1510/7848 -f 1403/1486/7849 1429/1513/7850 1428/1511/7851 -f 1428/1511/7852 1430/1512/7853 1403/1486/7854 -f 1403/1486/7855 1430/1512/7856 1398/1481/7857 -f 1398/1481/7858 1399/1482/7859 1403/1486/7860 -f 1403/1486/7861 1404/1487/7862 1354/1437/7863 -f 1354/1437/7864 1429/1513/7865 1403/1486/7866 -f 1430/1512/7867 1428/1511/7868 1431/1514/7869 -f 1431/1514/7870 1432/1515/7871 1430/1512/7872 -f 1430/1512/7873 1432/1515/7874 1433/1516/7875 -f 1433/1516/7876 1398/1481/7877 1430/1512/7878 -f 1433/1516/7879 1432/1515/7880 1434/1517/7881 -f 1434/1517/7882 1435/1518/7883 1433/1516/7884 -f 1433/1516/7885 1435/1518/7886 1436/1519/7887 -f 1436/1519/7888 1393/1476/7889 1433/1516/7890 -f 1433/1516/7891 1393/1476/7892 1394/1477/7893 -f 1394/1477/7894 1398/1481/7895 1433/1516/7896 -f 1434/1517/7897 1298/1382/7898 1299/1385/7899 -f 1299/1385/7900 1437/1520/7901 1434/1517/7902 -f 1434/1517/7903 1437/1520/7904 1385/1468/7905 -f 1385/1468/7906 1435/1518/7907 1434/1517/7908 -f 1434/1517/7909 1432/1515/7910 1431/1514/7911 -f 1431/1514/7912 1298/1382/7913 1434/1517/7914 -f 1437/1520/7915 1299/1385/7916 1302/1387/7917 -f 1302/1387/7918 1438/1521/7919 1437/1520/7920 -f 1437/1520/7921 1438/1521/7922 1382/2590/7923 -f 1382/2590/7924 1385/1468/7925 1437/1520/7926 -f 1438/2595/7927 1302/2587/7928 1284/1366/7929 -f 1284/1366/7930 1281/1365/7931 1438/2595/7932 -f 1438/2595/7933 1281/1365/7934 1381/1464/7935 -f 1381/1464/7936 1382/1465/7937 1438/2595/7938 -f 1431/1514/7939 1439/1522/7940 1301/1383/7941 -f 1301/1383/7942 1298/1382/7943 1431/1514/7944 -f 1431/1514/7945 1428/1511/7946 1440/1523/7947 -f 1440/1523/7948 1439/1522/7949 1431/1514/7950 -f 1440/1580/7951 1442/1581/7952 1441/1578/7953 -f 1441/1578/7954 1439/1579/7955 1440/1580/7956 -f 1440/1523/7957 1428/1511/7958 1429/1513/7959 -f 1429/1513/7960 1443/1524/7961 1440/1523/7962 -f 1440/1580/7963 1443/1582/7964 1349/1576/7965 -f 1349/1576/7966 1442/1581/7967 1440/1580/7968 -f 1443/1524/7969 1429/1513/7970 1354/1437/7971 -f 1354/1437/7972 1352/1433/7973 1443/1524/7974 -f 1443/1524/7975 1352/1433/7976 1350/1436/7977 -f 1350/1436/7978 1349/1527/7979 1443/1524/7980 -f 1441/1578/7981 1445/1585/7982 1444/1583/7983 -f 1444/1583/7984 1446/1584/7985 1441/1578/7986 -f 1441/1578/7987 1446/1584/7988 1301/1571/7989 -f 1301/1571/7990 1439/1579/7991 1441/1578/7992 -f 1441/1578/7993 1442/1581/7994 1447/1586/7995 -f 1447/1586/7996 1445/1585/7997 1441/1578/7998 -f 1446/1584/7999 1444/1583/8000 1448/1587/8001 -f 1448/1587/8002 1449/1588/8003 1446/1584/8004 -f 1446/1584/8005 1449/1588/8006 1304/1541/8007 -f 1304/1541/8008 1301/1571/8009 1446/1584/8010 -f 1449/1588/8011 1448/1587/8012 1450/1690/8013 -f 1450/1690/8014 1451/1691/8015 1449/1588/8016 -f 1449/1588/8017 1451/1691/8018 1452/2536/8019 -f 1452/2536/8020 1304/1541/8021 1449/1588/8022 -f 1452/2536/8023 1451/1691/8024 1453/2537/8025 -f 1453/2537/8026 1454/2538/8027 1452/2536/8028 -f 1452/2536/8029 1454/2538/8030 1455/2539/8031 -f 1455/2539/8032 1456/2540/8033 1452/2536/8034 -f 1452/2536/8035 1456/2540/8036 1303/1542/8037 -f 1303/1542/8038 1304/1541/8039 1452/2536/8040 -f 1456/2540/8041 1455/2539/8042 1457/2541/8043 -f 1457/2541/8044 1458/2542/8045 1456/2540/8046 -f 1456/2540/8047 1458/2542/8048 1285/2543/8049 -f 1285/2543/8050 1303/1542/8051 1456/2540/8052 -f 1458/2497/8053 1457/2498/8054 1459/2495/8055 -f 1459/2495/8056 1460/2496/8057 1458/2497/8058 -f 1458/2497/8059 1460/2496/8060 1286/2499/8061 -f 1286/2499/8062 1285/2501/8063 1458/2497/8064 -f 1460/2496/8065 1459/2495/8066 1461/2502/8067 -f 1461/2502/8068 1462/2503/8069 1460/2496/8070 -f 1460/2496/8071 1462/2503/8072 1287/2504/8073 -f 1287/2504/8074 1286/2499/8075 1460/2496/8076 -f 1462/2503/8077 1461/2502/8078 1463/2505/8079 -f 1463/2505/8080 1464/2506/8081 1462/2503/8082 -f 1462/2503/8083 1464/2506/8084 1465/2507/8085 -f 1465/2507/8086 1287/2504/8087 1462/2503/8088 -f 1465/2507/8089 1464/2506/8090 1466/2508/8091 -f 1466/2508/8092 1336/2509/8093 1465/2507/8094 -f 1465/1549/8095 1336/1420/8096 1278/1363/8097 -f 1278/1363/8098 1279/1362/8099 1465/1549/8100 -f 1465/1549/8101 1279/1362/8102 1288/1372/8103 -f 1288/1372/8104 1287/1371/8105 1465/1549/8106 -f 1466/2508/8107 1464/2506/8108 1463/2505/8109 -f 1463/2505/8110 1467/2510/8111 1466/2508/8112 -f 1466/2508/8113 1467/2510/8114 1468/2511/8115 -f 1468/2511/8116 1469/2512/8117 1466/2508/8118 -f 1466/2508/8119 1469/2512/8120 1333/2513/8121 -f 1333/2513/8122 1336/2509/8123 1466/2508/8124 -f 1469/2512/8125 1468/2511/8126 1332/1567/8127 -f 1332/1567/8128 1331/1565/8129 1469/2512/8130 -f 1469/2512/8131 1331/1565/8132 1329/1564/8133 -f 1329/1564/8134 1333/2513/8135 1469/2512/8136 -f 1468/2511/8137 1467/2510/8138 1470/2514/8139 -f 1470/2514/8140 1471/2515/8141 1468/2511/8142 -f 1468/2511/8143 1471/2515/8144 1472/2516/8145 -f 1472/2516/8146 1332/1567/8147 1468/2511/8148 -f 1472/2516/8149 1471/2515/8150 1473/2517/8151 -f 1473/2517/8152 1474/2518/8153 1472/2516/8154 -f 1472/2516/8155 1474/2518/8156 1475/2519/8157 -f 1475/2519/8158 1476/2520/8159 1472/2516/8160 -f 1472/2516/8161 1476/2520/8162 1326/1563/8163 -f 1326/1563/8164 1332/1567/8165 1472/2516/8166 -f 1476/2520/8167 1475/2519/8168 1477/2521/8169 -f 1477/2521/8170 1478/2522/8171 1476/2520/8172 -f 1476/2520/8173 1478/2522/8174 1325/1560/8175 -f 1325/1560/8176 1326/1563/8177 1476/2520/8178 -f 1475/2519/8179 1474/2518/8180 1479/2523/8181 -f 1479/2523/8182 1480/2524/8183 1475/2519/8184 -f 1475/2519/8185 1480/2524/8186 1481/2525/8187 -f 1481/2525/8188 1477/2521/8189 1475/2519/8190 -f 1480/2524/8191 1479/2523/8192 1482/1392/8193 -f 1482/1392/8194 1483/1393/8195 1480/2524/8196 -f 1480/2524/8197 1483/1393/8198 1484/1394/8199 -f 1484/1394/8200 1481/2525/8201 1480/2524/8202 -f 1482/1392/8203 1479/2523/8204 1485/2526/8205 -f 1485/2526/8206 391/1396/8207 1482/1392/8208 -f 391/1396/8209 1485/2526/8210 1271/1431/8211 -f 1271/1431/8212 397/475/8213 391/1396/8214 -f 1485/2526/8215 1479/2523/8216 1474/2518/8217 -f 1474/2518/8218 1473/2517/8219 1485/2526/8220 -f 1485/2526/8221 1473/2517/8222 1272/1543/8223 -f 1272/1543/8224 1271/1431/8225 1485/2526/8226 -f 1473/2517/8227 1471/2515/8228 1470/2514/8229 -f 1470/2514/8230 1272/1543/8231 1473/2517/8232 -f 1470/2514/8233 1311/1552/8234 1273/1544/8235 -f 1273/1544/8236 1272/1543/8237 1470/2514/8238 -f 1470/2514/8239 1467/2510/8240 1463/2505/8241 -f 1463/2505/8242 1311/1552/8243 1470/2514/8244 -f 1463/2505/8245 1461/2502/8246 1307/1547/8247 -f 1307/1547/8248 1311/1552/8249 1463/2505/8250 -f 1461/2502/8251 1459/2495/8252 1310/1551/8253 -f 1310/1551/8254 1307/1547/8255 1461/2502/8256 -f 1459/2495/8257 1457/2498/8258 1486/2527/8259 -f 1486/2527/8260 1310/1551/8261 1459/2495/8262 -f 1486/2546/8263 1488/2547/8264 1487/2544/8265 -f 1487/2544/8266 1489/2545/8267 1486/2546/8268 -f 1486/2527/8269 1489/2528/8270 1309/1550/8271 -f 1309/1550/8272 1310/1551/8273 1486/2527/8274 -f 1486/2546/8275 1457/2541/8276 1455/2539/8277 -f 1455/2539/8278 1488/2547/8279 1486/2546/8280 -f 1487/2544/8281 1491/2550/8282 1490/2548/8283 -f 1490/2548/8284 1492/2549/8285 1487/2544/8286 -f 1487/2544/8287 1492/2549/8288 1315/2551/8289 -f 1315/2551/8290 1489/2545/8291 1487/2544/8292 -f 1487/2544/8293 1488/2547/8294 1493/2552/8295 -f 1493/2552/8296 1491/2550/8297 1487/2544/8298 -f 1493/2552/8299 1495/2554/8300 1494/2553/8301 -f 1494/2553/8302 1491/2550/8303 1493/2552/8304 -f 1493/2552/8305 1488/2547/8306 1455/2539/8307 -f 1455/2539/8308 1454/2538/8309 1493/2552/8310 -f 1493/2552/8311 1454/2538/8312 1453/2537/8313 -f 1453/2537/8314 1495/2554/8315 1493/2552/8316 -f 1494/2553/8317 1497/2557/8318 1496/2555/8319 -f 1496/2555/8320 1498/2556/8321 1494/2553/8322 -f 1494/2553/8323 1498/2556/8324 1490/2548/8325 -f 1490/2548/8326 1491/2550/8327 1494/2553/8328 -f 1494/2553/8329 1495/2554/8330 1499/2558/8331 -f 1499/2558/8332 1497/2557/8333 1494/2553/8334 -f 1499/2558/8335 1501/1428/8336 1500/1427/8337 -f 1500/1427/8338 1497/2557/8339 1499/2558/8340 -f 1499/2558/8341 1495/2554/8342 1453/2537/8343 -f 1453/2537/8344 1502/2559/8345 1499/2558/8346 -f 1499/2558/8347 1502/2559/8348 392/1430/8349 -f 392/1430/8350 1501/1428/8351 1499/2558/8352 -f 392/1430/8353 1502/2559/8354 1450/1690/8355 -f 1450/1690/8356 1503/1525/8357 392/1430/8358 -f 1503/1525/8359 1450/1690/8360 1448/1587/8361 -f 1448/1587/8362 599/1526/8363 1503/1525/8364 -f 599/1526/8365 1448/1587/8366 1444/1583/8367 -f 1444/1583/8368 1504/1528/8369 599/1526/8370 -f 1504/1528/8371 1444/1583/8372 1445/1585/8373 -f 1445/1585/8374 600/1529/8375 1504/1528/8376 -f 600/1529/8377 1445/1585/8378 1447/1586/8379 -f 1447/1586/8380 601/1530/8381 600/1529/8382 -f 1502/2559/8383 1453/2537/8384 1451/1691/8385 -f 1451/1691/8386 1450/1690/8387 1502/2559/8388 -f 1500/1427/8389 393/1531/8390 1496/2555/8391 -f 1496/2555/8392 1497/2557/8393 1500/1427/8394 -f 393/1531/8395 602/1533/8396 1294/2560/8397 -f 1294/2560/8398 1496/2555/8399 393/1531/8400 -f 1498/2556/8401 1496/2555/8402 1294/2560/8403 -f 1294/2560/8404 1295/2561/8405 1498/2556/8406 -f 1498/2556/8407 1295/2561/8408 1505/2562/8409 -f 1505/2562/8410 1490/2548/8411 1498/2556/8412 -f 1505/1426/8413 1295/686/8414 1292/479/8415 -f 1292/479/8416 1506/1425/8417 1505/1426/8418 -f 1505/1426/8419 1506/1425/8420 1507/1589/8421 -f 1507/1589/8422 1508/1590/8423 1505/1426/8424 -f 1505/2562/8425 1508/2563/8426 1492/2549/8427 -f 1492/2549/8428 1490/2548/8429 1505/2562/8430 -f 1509/1591/8431 1508/1590/8432 1507/1589/8433 -f 1507/1589/8434 1322/1381/8435 1509/1591/8436 -f 1508/2563/8437 1509/2564/8438 1315/2551/8439 -f 1315/2551/8440 1492/2549/8441 1508/2563/8442 -f 1509/2529/8443 1510/2530/8444 1314/1555/8445 -f 1314/1555/8446 1315/1558/8447 1509/2529/8448 -f 1510/1593/8449 1319/1380/8450 1320/1404/8451 -f 1320/1404/8452 1511/1592/8453 1510/1593/8454 -f 1510/2530/8455 1511/2531/8456 1318/1559/8457 -f 1318/1559/8458 1314/1555/8459 1510/2530/8460 -f 1511/1592/8461 1320/1404/8462 1512/1594/8463 -f 1512/1594/8464 1513/1595/8465 1511/1592/8466 -f 1511/2531/8467 1513/2533/8468 1514/2532/8469 -f 1514/2532/8470 1318/1559/8471 1511/2531/8472 -f 1514/2532/8473 1313/1554/8474 1312/1553/8475 -f 1312/1553/8476 1318/1559/8477 1514/2532/8478 -f 1514/2532/8479 1513/2533/8480 1515/1411/8481 -f 1515/1411/8482 613/1412/8483 1514/2532/8484 -f 1514/2532/8485 613/1412/8486 394/1414/8487 -f 394/1414/8488 1313/1554/8489 1514/2532/8490 -f 1515/1597/8491 1513/1595/8492 1512/1594/8493 -f 1512/1594/8494 395/1596/8495 1515/1597/8496 -f 395/1596/8497 1512/1594/8498 1516/1599/8499 -f 1516/1599/8500 1517/1600/8501 395/1596/8502 -f 1517/1600/8503 1516/1599/8504 1518/1601/8505 -f 1518/1601/8506 1519/1602/8507 1517/1600/8508 -f 1519/1602/8509 1518/1601/8510 1520/1603/8511 -f 1520/1603/8512 1521/1604/8513 1519/1602/8514 -f 1521/1604/8515 1520/1603/8516 1340/2611/8517 -f 1340/2611/8518 1341/2612/8519 1521/1604/8520 -f 1520/1603/8521 1518/1601/8522 1522/1605/8523 -f 1522/1605/8524 1523/1606/8525 1520/1603/8526 -f 1520/1603/8527 1523/1606/8528 1524/1607/8529 -f 1524/1607/8530 1340/2611/8531 1520/1603/8532 -f 1526/1608/8533 1525/1609/8534 1524/1607/8535 -f 1524/1607/8536 1523/1606/8537 1526/1608/8538 -f 1296/1378/8539 1524/2613/8540 1525/2614/8541 -f 1525/2614/8542 1527/1610/8543 1296/1378/8544 -f 1524/2613/8545 1296/1378/8546 1297/1379/8547 -f 1297/1379/8548 1340/1407/8549 1524/2613/8550 -f 1530/1613/8551 1529/2616/8552 1528/1611/8553 -f 1528/1611/8554 1531/1612/8555 1530/1613/8556 -f 1530/1613/8557 1531/1612/8558 1532/1615/8559 -f 1532/1615/8560 1533/1616/8561 1530/1613/8562 -f 1527/1610/8563 1530/1613/8564 1533/1616/8565 -f 1533/1616/8566 1534/1617/8567 1527/1610/8568 -f 1533/1616/8569 1532/1615/8570 1535/1618/8571 -f 1535/1618/8572 1536/1619/8573 1533/1616/8574 -f 1534/1617/8575 1533/1616/8576 1536/1619/8577 -f 1536/1619/8578 1537/1620/8579 1534/1617/8580 -f 1536/1619/8581 1535/1618/8582 1538/1621/8583 -f 1538/1621/8584 1539/1622/8585 1536/1619/8586 -f 1537/1620/8587 1536/1619/8588 1539/1622/8589 -f 1539/1622/8590 1540/1623/8591 1537/1620/8592 -f 1539/1622/8593 1538/1621/8594 1541/1624/8595 -f 1541/1624/8596 1542/1625/8597 1539/1622/8598 -f 1540/1623/8599 1539/1622/8600 1542/1625/8601 -f 1542/1625/8602 1543/1626/8603 1540/1623/8604 -f 1542/1625/8605 1541/1624/8606 1544/1627/8607 -f 1544/1627/8608 1545/1628/8609 1542/1625/8610 -f 1543/1626/8611 1542/1625/8612 1545/1628/8613 -f 1545/1628/8614 1324/1405/8615 1543/1626/8616 -f 1546/1630/8617 1544/1627/8618 1541/1624/8619 -f 1541/1624/8620 1547/1629/8621 1546/1630/8622 -f 1548/1632/8623 1544/1627/8624 1546/1630/8625 -f 1546/1630/8626 1549/1631/8627 1548/1632/8628 -f 1544/1627/8629 1548/1632/8630 1550/1633/8631 -f 1550/1633/8632 1545/1628/8633 1544/1627/8634 -f 1551/1635/8635 1548/1632/8636 1549/1631/8637 -f 1549/1631/8638 1552/1634/8639 1551/1635/8640 -f 1548/1632/8641 1551/1635/8642 1553/1636/8643 -f 1553/1636/8644 1550/1633/8645 1548/1632/8646 -f 1553/1636/8647 1551/1635/8648 1554/1637/8649 -f 1554/1637/8650 1555/1638/8651 1553/1636/8652 -f 1526/1608/8653 1556/1639/8654 1553/1636/8655 -f 1553/1636/8656 1555/1638/8657 1526/1608/8658 -f 1550/1633/8659 1553/1636/8660 1556/1639/8661 -f 1556/1639/8662 1323/1406/8663 1550/1633/8664 -f 1552/1634/8665 1557/1640/8666 1554/1637/8667 -f 1554/1637/8668 1551/1635/8669 1552/1634/8670 -f 1558/1641/8671 1528/2615/8672 1554/1637/8673 -f 1554/1637/8674 1557/1640/8675 1558/1641/8676 -f 1554/1637/8677 1528/2615/8678 1529/1614/8679 -f 1529/1614/8680 1555/1638/8681 1554/1637/8682 -f 1561/1644/8683 1560/1645/8684 1559/2618/8685 -f 1559/2618/8686 1562/1643/8687 1561/1644/8688 -f 1563/1647/8689 1559/1642/8690 1560/2619/8691 -f 1560/2619/8692 1564/1646/8693 1563/1647/8694 -f 1558/2617/8695 1559/1642/8696 1563/1647/8697 -f 1563/1647/8698 1565/1648/8699 1558/2617/8700 -f 1566/1650/8701 1563/1647/8702 1564/1646/8703 -f 1564/1646/8704 1567/1649/8705 1566/1650/8706 -f 1565/1648/8707 1563/1647/8708 1566/1650/8709 -f 1566/1650/8710 1568/1651/8711 1565/1648/8712 -f 1569/1653/8713 1566/1650/8714 1567/1649/8715 -f 1567/1649/8716 1570/1652/8717 1569/1653/8718 -f 1568/1651/8719 1566/1650/8720 1569/1653/8721 -f 1569/1653/8722 1571/1654/8723 1568/1651/8724 -f 1573/1655/8725 1572/1656/8726 1569/1653/8727 -f 1569/1653/8728 1570/1652/8729 1573/1655/8730 -f 1571/1654/8731 1569/1653/8732 1572/1656/8733 -f 1572/1656/8734 1574/1657/8735 1571/1654/8736 -f 1576/1658/8737 1575/1659/8738 1572/1656/8739 -f 1572/1656/8740 1573/1655/8741 1576/1658/8742 -f 1547/1629/8743 1574/1657/8744 1572/1656/8745 -f 1572/1656/8746 1575/1659/8747 1547/1629/8748 -f 1579/1662/8749 1578/1663/8750 1577/1660/8751 -f 1577/1660/8752 1580/1661/8753 1579/1662/8754 -f 1579/1662/8755 1580/1661/8756 1581/1664/8757 -f 1581/1664/8758 1582/1665/8759 1579/1662/8760 -f 1576/1658/8761 1579/1662/8762 1582/1665/8763 -f 1582/1665/8764 1583/1666/8765 1576/1658/8766 -f 1582/1665/8767 1581/1664/8768 1584/1667/8769 -f 1584/1667/8770 1585/1668/8771 1582/1665/8772 -f 1583/1666/8773 1582/1665/8774 1585/1668/8775 -f 1585/1668/8776 1586/1669/8777 1583/1666/8778 -f 1585/1668/8779 1584/1667/8780 1587/1670/8781 -f 1587/1670/8782 1588/1671/8783 1585/1668/8784 -f 1586/1669/8785 1585/1668/8786 1588/1671/8787 -f 1588/1671/8788 1589/1672/8789 1586/1669/8790 -f 1588/1671/8791 1587/1670/8792 1590/1673/8793 -f 1590/1673/8794 1591/1674/8795 1588/1671/8796 -f 1561/1644/8797 1589/1672/8798 1588/1671/8799 -f 1588/1671/8800 1591/1674/8801 1561/1644/8802 -f 1590/1673/8803 1592/1676/8804 1593/1675/8805 -f 1593/1675/8806 1591/1674/8807 1590/1673/8808 -f 1592/2621/8809 1594/1678/8810 1595/1677/8811 -f 1595/1677/8812 1593/2620/8813 1592/2621/8814 -f 1594/1678/8815 1596/1680/8816 1597/1679/8817 -f 1597/1679/8818 1595/1677/8819 1594/1678/8820 -f 1596/1680/8821 1598/1682/8822 1599/1681/8823 -f 1599/1681/8824 1597/1679/8825 1596/1680/8826 -f 1598/1682/8827 1577/1660/8828 1578/1663/8829 -f 1578/1663/8830 1599/1681/8831 1598/1682/8832 -f 1522/1605/8833 1518/1601/8834 1516/1599/8835 -f 1516/1599/8836 1321/1403/8837 1522/1605/8838 -f 1516/1599/8839 1512/1594/8840 1320/1404/8841 -f 1320/1404/8842 1321/1403/8843 1516/1599/8844 -f 1442/1581/8845 1349/1576/8846 1343/1572/8847 -f 1343/1572/8848 1447/1586/8849 1442/1581/8850 -f 1404/1487/8851 1357/1440/8852 1355/1438/8853 -f 1355/1438/8854 1354/1437/8855 1404/1487/8856 -f 1381/1464/8857 1281/1365/8858 1282/1368/8859 -f 1282/1368/8860 1600/1684/8861 1381/1464/8862 -f 1366/1449/8863 1601/1685/8864 1291/1375/8865 -f 1291/1375/8866 1337/1421/8867 1366/1449/8868 -f 1328/1561/8869 1603/2535/8870 1602/2534/8871 -f 1602/2534/8872 1327/1562/8873 1328/1561/8874 -f 1302/2587/8875 1303/1386/8876 1285/1369/8877 -f 1285/1369/8878 1284/1366/8879 1302/2587/8880 -f 1342/1408/8881 1297/1379/8882 1294/1376/8883 -f 1294/1376/8884 602/1683/8885 1342/1408/8886 -f 1602/2534/8887 1603/2535/8888 1348/1686/8889 -f 1348/1686/8890 1347/1598/8891 1602/2534/8892 -f 1602/2534/8893 1347/1598/8894 1330/1566/8895 -f 1330/1566/8896 1327/1562/8897 1602/2534/8898 -f 1291/1375/8899 1601/1685/8900 1600/1684/8901 -f 1600/1684/8902 1282/1368/8903 1291/1375/8904 -f 1289/1373/8905 1288/1372/8906 1279/1362/8907 -f 1279/1362/8908 1280/1364/8909 1289/1373/8910 -f 1269/478/8911 1270/1432/8912 1313/1554/8913 -f 1313/1554/8914 394/1414/8915 1269/478/8916 -f 1436/1519/8917 1435/1518/8918 1385/1468/8919 -f 1385/1468/8920 1384/1467/8921 1436/1519/8922 -f 1436/1519/8923 1384/1467/8924 1389/1472/8925 -f 1389/1472/8926 1393/1476/8927 1436/1519/8928 -f 1308/1546/8929 1313/1554/8930 1270/1432/8931 -f 1270/1432/8932 1273/1544/8933 1308/1546/8934 -f 1600/1684/8935 1601/1685/8936 1604/1688/8937 -f 1604/1688/8938 1605/1689/8939 1600/1684/8940 -f 1366/1449/8941 1369/1452/8942 1604/1688/8943 -f 1604/1688/8944 1601/1685/8945 1366/1449/8946 -f 1605/1689/8947 1604/1688/8948 1369/1452/8949 -f 1369/1452/8950 1377/1460/8951 1605/1689/8952 -f 1381/1464/8953 1600/1684/8954 1605/1689/8955 -f 1605/1689/8956 1377/1460/8957 1381/1464/8958 -f 601/1530/8959 1447/1586/8960 1606/2565/8961 -f 1606/2565/8962 1607/1540/8963 601/1530/8964 -f 1447/1586/8965 1343/1572/8966 1344/1575/8967 -f 1344/1575/8968 1606/2565/8969 1447/1586/8970 -f 1610/1694/8971 1609/1695/8972 1608/1692/8973 -f 1608/1692/8974 1611/1693/8975 1610/1694/8976 -f 1614/1698/8977 1613/1699/8978 1612/1696/8979 -f 1612/1696/8980 1615/1697/8981 1614/1698/8982 -f 1618/1702/8983 1617/1703/8984 1616/1700/8985 -f 1616/1700/8986 1619/1701/8987 1618/1702/8988 -f 1622/1706/8989 1621/1707/8990 1620/1704/8991 -f 1620/1704/8992 1623/1705/8993 1622/1706/8994 -f 1618/1702/8995 1625/1710/8996 1624/1708/8997 -f 1624/1708/8998 1626/1709/8999 1618/1702/9000 -f 1629/1713/9001 1628/1714/9002 1627/1711/9003 -f 1627/1711/9004 1630/1712/9005 1629/1713/9006 -f 1633/1717/9007 1632/1718/9008 1631/1715/9009 -f 1631/1715/9010 1634/1716/9011 1633/1717/9012 -f 1637/1721/9013 1636/1722/9014 1635/1719/9015 -f 1635/1719/9016 1638/1720/9017 1637/1721/9018 -f 1641/1725/9019 1640/1726/9020 1639/1723/9021 -f 1639/1723/9022 1642/1724/9023 1641/1725/9024 -f 1643/1727/9025 1616/1700/9026 1622/1706/9027 -f 1622/1706/9028 1635/1719/9029 1643/1727/9030 -f 1646/1729/9031 1645/1730/9032 1644/1728/9033 -f 1644/1728/9034 1639/1723/9035 1646/1729/9036 -f 1649/1733/9037 1648/1734/9038 1647/1731/9039 -f 1647/1731/9040 1650/1732/9041 1649/1733/9042 -f 1653/1737/9043 1652/1738/9044 1651/1735/9045 -f 1651/1735/9046 1654/1736/9047 1653/1737/9048 -f 1656/1739/9049 1655/1740/9050 1639/1723/9051 -f 1639/1723/9052 1640/1726/9053 1656/1739/9054 -f 1656/1739/9055 1638/1720/9056 1635/1719/9057 -f 1635/1719/9058 1655/1740/9059 1656/1739/9060 -f 1658/1747/9061 1657/1748/9062 1636/1741/9063 -f 1636/1741/9064 1637/1742/9065 1658/1747/9066 -f 1658/1747/9067 1641/1750/9068 1642/2383/9069 -f 1642/2383/9070 1657/1748/9071 1658/1747/9072 -f 1661/1745/9073 1660/1746/9074 1659/1743/9075 -f 1659/1743/9076 1662/1744/9077 1661/1745/9078 -f 1665/1756/9079 1664/1757/9080 1663/1753/9081 -f 1663/1753/9082 1666/1754/9083 1665/1756/9084 -f 1644/1728/9085 1645/1730/9086 1667/1751/9087 -f 1667/1751/9088 1668/1752/9089 1644/1728/9090 -f 1669/1775/9091 1652/1738/9092 1653/1737/9093 -f 1653/1737/9094 1670/1774/9095 1669/1775/9096 -f 1619/1701/9097 1616/1700/9098 1643/1727/9099 -f 1643/1727/9100 1671/1755/9101 1619/1701/9102 -f 1672/1787/9103 1664/1757/9104 1665/1756/9105 -f 1665/1756/9106 1673/1786/9107 1672/1787/9108 -f 1676/1760/9109 1675/1761/9110 1674/1758/9111 -f 1674/1758/9112 1677/1759/9113 1676/1760/9114 -f 1678/1763/9115 1676/1760/9116 1677/1759/9117 -f 1677/1759/9118 1679/1762/9119 1678/1763/9120 -f 1682/1766/9121 1681/1767/9122 1680/1764/9123 -f 1680/1764/9124 1683/1765/9125 1682/1766/9126 -f 1686/1770/9127 1685/1771/9128 1684/1768/9129 -f 1684/1768/9130 1687/1769/9131 1686/1770/9132 -f 1684/1768/9133 1689/1773/9134 1688/1772/9135 -f 1688/1772/9136 1687/1769/9137 1684/1768/9138 -f 1688/1772/9139 1689/1773/9140 1682/1766/9141 -f 1682/1766/9142 1683/1765/9143 1688/1772/9144 -f 1680/1800/9145 1681/1801/9146 1690/1798/9147 -f 1690/1798/9148 1691/1799/9149 1680/1800/9150 -f 1690/1798/9151 1685/1803/9152 1686/1802/9153 -f 1686/1802/9154 1691/1799/9155 1690/1798/9156 -f 1694/1778/9157 1693/1779/9158 1692/1776/9159 -f 1692/1776/9160 1695/1777/9161 1694/1778/9162 -f 1698/1782/9163 1697/1783/9164 1696/1780/9165 -f 1696/1780/9166 1699/1781/9167 1698/1782/9168 -f 1696/1780/9169 1701/1785/9170 1700/1784/9171 -f 1700/1784/9172 1699/1781/9173 1696/1780/9174 -f 1700/1784/9175 1701/1785/9176 1694/1778/9177 -f 1694/1778/9178 1695/1777/9179 1700/1784/9180 -f 1693/1806/9181 1703/1812/9182 1702/1804/9183 -f 1702/1804/9184 1692/1805/9185 1693/1806/9186 -f 1702/1804/9187 1703/1812/9188 1697/1813/9189 -f 1697/1813/9190 1698/1814/9191 1702/1804/9192 -f 1706/1790/9193 1705/1791/9194 1704/1788/9195 -f 1704/1788/9196 1707/1789/9197 1706/1790/9198 -f 1710/1794/9199 1709/1795/9200 1708/1792/9201 -f 1708/1792/9202 1711/1793/9203 1710/1794/9204 -f 1712/1797/9205 1710/1794/9206 1711/1793/9207 -f 1711/1793/9208 1713/1796/9209 1712/1797/9210 -f 1705/1791/9211 1712/1797/9212 1713/1796/9213 -f 1713/1796/9214 1704/1788/9215 1705/1791/9216 -f 1716/1817/9217 1715/1818/9218 1714/1815/9219 -f 1714/1815/9220 1717/1816/9221 1716/1817/9222 -f 1718/1820/9223 1716/1817/9224 1717/1816/9225 -f 1717/1816/9226 1719/1819/9227 1718/1820/9228 -f 1707/1789/9229 1704/1788/9230 1683/1765/9231 -f 1683/1765/9232 1680/1764/9233 1707/1789/9234 -f 1711/1793/9235 1708/1792/9236 1686/1770/9237 -f 1686/1770/9238 1687/1769/9239 1711/1793/9240 -f 1713/1796/9241 1711/1793/9242 1687/1769/9243 -f 1687/1769/9244 1688/1772/9245 1713/1796/9246 -f 1704/1788/9247 1713/1796/9248 1688/1772/9249 -f 1688/1772/9250 1683/1765/9251 1704/1788/9252 -f 1717/1816/9253 1714/1815/9254 1720/1821/9255 -f 1720/1821/9256 1721/1822/9257 1717/1816/9258 -f 1719/1819/9259 1717/1816/9260 1721/1822/9261 -f 1721/1822/9262 1722/1823/9263 1719/1819/9264 -f 1681/1767/9265 1682/1766/9266 1723/1807/9267 -f 1723/1807/9268 1724/1808/9269 1681/1767/9270 -f 1684/1768/9271 1685/1771/9272 1725/1809/9273 -f 1725/1809/9274 1726/1810/9275 1684/1768/9276 -f 1689/1773/9277 1684/1768/9278 1726/1810/9279 -f 1726/1810/9280 1727/1811/9281 1689/1773/9282 -f 1682/1766/9283 1689/1773/9284 1727/1811/9285 -f 1727/1811/9286 1723/1807/9287 1682/1766/9288 -f 1730/1826/9289 1729/1827/9290 1728/1824/9291 -f 1728/1824/9292 1731/1825/9293 1730/1826/9294 -f 1732/1829/9295 1730/1826/9296 1731/1825/9297 -f 1731/1825/9298 1733/1828/9299 1732/1829/9300 -f 1724/1808/9301 1723/1807/9302 1695/1777/9303 -f 1695/1777/9304 1692/1776/9305 1724/1808/9306 -f 1726/1810/9307 1725/1809/9308 1698/1782/9309 -f 1698/1782/9310 1699/1781/9311 1726/1810/9312 -f 1727/1811/9313 1726/1810/9314 1699/1781/9315 -f 1699/1781/9316 1700/1784/9317 1727/1811/9318 -f 1723/1807/9319 1727/1811/9320 1700/1784/9321 -f 1700/1784/9322 1695/1777/9323 1723/1807/9324 -f 1731/1825/9325 1728/1824/9326 1734/1830/9327 -f 1734/1830/9328 1735/1831/9329 1731/1825/9330 -f 1733/1828/9331 1731/1825/9332 1735/1831/9333 -f 1735/1831/9334 1736/1832/9335 1733/1828/9336 -f 1716/1817/9337 1737/1834/9338 1706/1833/9339 -f 1706/1833/9340 1715/1818/9341 1716/1817/9342 -f 1718/1820/9343 1709/1835/9344 1737/1834/9345 -f 1737/1834/9346 1716/1817/9347 1718/1820/9348 -f 1719/1819/9349 1708/1836/9350 1709/1835/9351 -f 1709/1835/9352 1718/1820/9353 1719/1819/9354 -f 1722/1823/9355 1686/1802/9356 1708/1836/9357 -f 1708/1836/9358 1719/1819/9359 1722/1823/9360 -f 1721/1822/9361 1691/1799/9362 1686/1802/9363 -f 1686/1802/9364 1722/1823/9365 1721/1822/9366 -f 1720/1821/9367 1680/1800/9368 1691/1799/9369 -f 1691/1799/9370 1721/1822/9371 1720/1821/9372 -f 1714/1815/9373 1707/1837/9374 1680/1800/9375 -f 1680/1800/9376 1720/1821/9377 1714/1815/9378 -f 1715/1818/9379 1706/1833/9380 1707/1837/9381 -f 1707/1837/9382 1714/1815/9383 1715/1818/9384 -f 1730/1826/9385 1690/1798/9386 1681/1801/9387 -f 1681/1801/9388 1729/1827/9389 1730/1826/9390 -f 1732/1829/9391 1685/1803/9392 1690/1798/9393 -f 1690/1798/9394 1730/1826/9395 1732/1829/9396 -f 1733/1828/9397 1725/1838/9398 1685/1803/9399 -f 1685/1803/9400 1732/1829/9401 1733/1828/9402 -f 1736/1832/9403 1698/1814/9404 1725/1838/9405 -f 1725/1838/9406 1733/1828/9407 1736/1832/9408 -f 1735/1831/9409 1702/1804/9410 1698/1814/9411 -f 1698/1814/9412 1736/1832/9413 1735/1831/9414 -f 1734/1830/9415 1692/1805/9416 1702/1804/9417 -f 1702/1804/9418 1735/1831/9419 1734/1830/9420 -f 1728/1824/9421 1724/1839/9422 1692/1805/9423 -f 1692/1805/9424 1734/1830/9425 1728/1824/9426 -f 1729/1827/9427 1681/1801/9428 1724/1839/9429 -f 1724/1839/9430 1728/1824/9431 1729/1827/9432 -f 1678/1763/9433 1679/1762/9434 1693/1779/9435 -f 1693/1779/9436 1694/1778/9437 1678/1763/9438 -f 1697/1783/9439 1674/1758/9440 1675/1761/9441 -f 1675/1761/9442 1696/1780/9443 1697/1783/9444 -f 1675/1761/9445 1676/1760/9446 1701/1785/9447 -f 1701/1785/9448 1696/1780/9449 1675/1761/9450 -f 1701/1785/9451 1676/1760/9452 1678/1763/9453 -f 1678/1763/9454 1694/1778/9455 1701/1785/9456 -f 1740/1852/9457 1739/1853/9458 1738/1840/9459 -f 1738/1840/9460 1741/1841/9461 1740/1852/9462 -f 1741/1841/9463 1738/1840/9464 1742/1870/9465 -f 1742/1870/9466 1743/1871/9467 1741/1841/9468 -f 1744/1894/9469 1679/1895/9470 1677/1882/9471 -f 1677/1882/9472 1745/1883/9473 1744/1894/9474 -f 1746/1896/9475 1693/1806/9476 1679/1895/9477 -f 1679/1895/9478 1744/1894/9479 1746/1896/9480 -f 1747/1897/9481 1703/1812/9482 1693/1806/9483 -f 1693/1806/9484 1746/1896/9485 1747/1897/9486 -f 1748/1898/9487 1697/1813/9488 1703/1812/9489 -f 1703/1812/9490 1747/1897/9491 1748/1898/9492 -f 1749/1899/9493 1674/1900/9494 1697/1813/9495 -f 1697/1813/9496 1748/1898/9497 1749/1899/9498 -f 1745/1883/9499 1677/1882/9500 1674/1900/9501 -f 1674/1900/9502 1749/1899/9503 1745/1883/9504 -f 1739/1853/9505 1744/1894/9506 1745/1883/9507 -f 1745/1883/9508 1738/1840/9509 1739/1853/9510 -f 1740/1852/9511 1746/1896/9512 1744/1894/9513 -f 1744/1894/9514 1739/1853/9515 1740/1852/9516 -f 1741/1841/9517 1747/1897/9518 1746/1896/9519 -f 1746/1896/9520 1740/1852/9521 1741/1841/9522 -f 1743/1871/9523 1748/1898/9524 1747/1897/9525 -f 1747/1897/9526 1741/1841/9527 1743/1871/9528 -f 1742/1870/9529 1749/1899/9530 1748/1898/9531 -f 1748/1898/9532 1743/1871/9533 1742/1870/9534 -f 1738/1840/9535 1745/1883/9536 1749/1899/9537 -f 1749/1899/9538 1742/1870/9539 1738/1840/9540 -f 1752/1908/9541 1751/1909/9542 1750/1901/9543 -f 1750/1901/9544 1753/1902/9545 1752/1908/9546 -f 1754/1911/9547 1648/1734/9548 1649/1733/9549 -f 1649/1733/9550 1755/1910/9551 1754/1911/9552 -f 1756/1913/9553 1751/1909/9554 1752/1908/9555 -f 1752/1908/9556 1757/1912/9557 1756/1913/9558 -f 1622/1706/9559 1623/1705/9560 1655/1740/9561 -f 1655/1740/9562 1635/1719/9563 1622/1706/9564 -f 1655/1740/9565 1623/1705/9566 1646/1729/9567 -f 1646/1729/9568 1639/1723/9569 1655/1740/9570 -f 1659/1743/9571 1660/1746/9572 1619/1701/9573 -f 1619/1701/9574 1671/1755/9575 1659/1743/9576 -f 1661/1745/9577 1662/1744/9578 1758/1842/9579 -f 1758/1842/9580 1759/1843/9581 1661/1745/9582 -f 1761/1844/9583 1760/1845/9584 1668/1752/9585 -f 1668/1752/9586 1667/1751/9587 1761/1844/9588 -f 1638/1720/9589 1705/1791/9590 1706/1790/9591 -f 1706/1790/9592 1637/1721/9593 1638/1720/9594 -f 1709/1795/9595 1710/1794/9596 1640/1726/9597 -f 1640/1726/9598 1641/1725/9599 1709/1795/9600 -f 1640/1726/9601 1710/1794/9602 1712/1797/9603 -f 1712/1797/9604 1656/1739/9605 1640/1726/9606 -f 1712/1797/9607 1705/1791/9608 1638/1720/9609 -f 1638/1720/9610 1656/1739/9611 1712/1797/9612 -f 1637/1742/9613 1706/1833/9614 1737/1834/9615 -f 1737/1834/9616 1658/1747/9617 1637/1742/9618 -f 1737/1834/9619 1709/1835/9620 1641/1750/9621 -f 1641/1750/9622 1658/1747/9623 1737/1834/9624 -f 1763/1847/9625 1762/1848/9626 1671/1755/9627 -f 1671/1755/9628 1764/1846/9629 1763/1847/9630 -f 1766/1849/9631 1765/1850/9632 1635/1719/9633 -f 1635/1719/9634 1636/1722/9635 1766/1849/9636 -f 1767/1851/9637 1643/1727/9638 1635/1719/9639 -f 1635/1719/9640 1765/1850/9641 1767/1851/9642 -f 1767/1851/9643 1764/1846/9644 1671/1755/9645 -f 1671/1755/9646 1643/1727/9647 1767/1851/9648 -f 1768/1915/9649 1766/1916/9650 1636/1741/9651 -f 1636/1741/9652 1769/1914/9653 1768/1915/9654 -f 1772/1856/9655 1771/1857/9656 1770/1854/9657 -f 1770/1854/9658 1773/1855/9659 1772/1856/9660 -f 1774/1859/9661 1772/1856/9662 1773/1855/9663 -f 1773/1855/9664 1775/1858/9665 1774/1859/9666 -f 1778/1862/9667 1777/1863/9668 1776/1860/9669 -f 1776/1860/9670 1779/1861/9671 1778/1862/9672 -f 1782/1866/9673 1781/1867/9674 1780/1864/9675 -f 1780/1864/9676 1783/1865/9677 1782/1866/9678 -f 1780/1864/9679 1785/1869/9680 1784/1868/9681 -f 1784/1868/9682 1783/1865/9683 1780/1864/9684 -f 1784/1868/9685 1785/1869/9686 1778/1862/9687 -f 1778/1862/9688 1779/1861/9689 1784/1868/9690 -f 1776/1919/9691 1777/1920/9692 1786/1917/9693 -f 1786/1917/9694 1787/1918/9695 1776/1919/9696 -f 1786/1917/9697 1781/1922/9698 1782/1921/9699 -f 1782/1921/9700 1787/1918/9701 1786/1917/9702 -f 1790/1874/9703 1789/1875/9704 1788/1872/9705 -f 1788/1872/9706 1791/1873/9707 1790/1874/9708 -f 1794/1878/9709 1793/1879/9710 1792/1876/9711 -f 1792/1876/9712 1795/1877/9713 1794/1878/9714 -f 1792/1876/9715 1797/1881/9716 1796/1880/9717 -f 1796/1880/9718 1795/1877/9719 1792/1876/9720 -f 1796/1880/9721 1797/1881/9722 1790/1874/9723 -f 1790/1874/9724 1791/1873/9725 1796/1880/9726 -f 1789/1925/9727 1799/1926/9728 1798/1923/9729 -f 1798/1923/9730 1788/1924/9731 1789/1925/9732 -f 1798/1923/9733 1799/1926/9734 1793/1927/9735 -f 1793/1927/9736 1794/1928/9737 1798/1923/9738 -f 1802/1886/9739 1801/1887/9740 1800/1884/9741 -f 1800/1884/9742 1803/1885/9743 1802/1886/9744 -f 1806/1890/9745 1805/1891/9746 1804/1888/9747 -f 1804/1888/9748 1807/1889/9749 1806/1890/9750 -f 1808/1893/9751 1806/1890/9752 1807/1889/9753 -f 1807/1889/9754 1809/1892/9755 1808/1893/9756 -f 1801/1887/9757 1808/1893/9758 1809/1892/9759 -f 1809/1892/9760 1800/1884/9761 1801/1887/9762 -f 1812/1936/9763 1811/1953/9764 1810/1929/9765 -f 1810/1929/9766 1813/1935/9767 1812/1936/9768 -f 1814/1965/9769 1812/1936/9770 1813/1935/9771 -f 1813/1935/9772 1815/1954/9773 1814/1965/9774 -f 1803/1885/9775 1800/1884/9776 1779/1861/9777 -f 1779/1861/9778 1776/1860/9779 1803/1885/9780 -f 1807/1889/9781 1804/1888/9782 1782/1866/9783 -f 1782/1866/9784 1783/1865/9785 1807/1889/9786 -f 1809/1892/9787 1807/1889/9788 1783/1865/9789 -f 1783/1865/9790 1784/1868/9791 1809/1892/9792 -f 1800/1884/9793 1809/1892/9794 1784/1868/9795 -f 1784/1868/9796 1779/1861/9797 1800/1884/9798 -f 1813/1935/9799 1810/1929/9800 1816/1966/9801 -f 1816/1966/9802 1817/1977/9803 1813/1935/9804 -f 1815/1954/9805 1813/1935/9806 1817/1977/9807 -f 1817/1977/9808 1818/1978/9809 1815/1954/9810 -f 1777/1863/9811 1778/1862/9812 1819/1903/9813 -f 1819/1903/9814 1820/1904/9815 1777/1863/9816 -f 1780/1864/9817 1781/1867/9818 1821/1905/9819 -f 1821/1905/9820 1822/1906/9821 1780/1864/9822 -f 1785/1869/9823 1780/1864/9824 1822/1906/9825 -f 1822/1906/9826 1823/1907/9827 1785/1869/9828 -f 1778/1862/9829 1785/1869/9830 1823/1907/9831 -f 1823/1907/9832 1819/1903/9833 1778/1862/9834 -f 1826/1981/9835 1825/1982/9836 1824/1979/9837 -f 1824/1979/9838 1827/1980/9839 1826/1981/9840 -f 1828/1984/9841 1826/1981/9842 1827/1980/9843 -f 1827/1980/9844 1829/1983/9845 1828/1984/9846 -f 1820/1904/9847 1819/1903/9848 1791/1873/9849 -f 1791/1873/9850 1788/1872/9851 1820/1904/9852 -f 1822/1906/9853 1821/1905/9854 1794/1878/9855 -f 1794/1878/9856 1795/1877/9857 1822/1906/9858 -f 1823/1907/9859 1822/1906/9860 1795/1877/9861 -f 1795/1877/9862 1796/1880/9863 1823/1907/9864 -f 1819/1903/9865 1823/1907/9866 1796/1880/9867 -f 1796/1880/9868 1791/1873/9869 1819/1903/9870 -f 1827/1980/9871 1824/1979/9872 1830/1985/9873 -f 1830/1985/9874 1831/1991/9875 1827/1980/9876 -f 1829/1983/9877 1827/1980/9878 1831/1991/9879 -f 1831/1991/9880 1832/1992/9881 1829/1983/9882 -f 1812/1936/9883 1833/1994/9884 1802/1993/9885 -f 1802/1993/9886 1811/1953/9887 1812/1936/9888 -f 1814/1965/9889 1805/1995/9890 1833/1994/9891 -f 1833/1994/9892 1812/1936/9893 1814/1965/9894 -f 1815/1954/9895 1804/1996/9896 1805/1995/9897 -f 1805/1995/9898 1814/1965/9899 1815/1954/9900 -f 1818/1978/9901 1782/1921/9902 1804/1996/9903 -f 1804/1996/9904 1815/1954/9905 1818/1978/9906 -f 1817/1977/9907 1787/1918/9908 1782/1921/9909 -f 1782/1921/9910 1818/1978/9911 1817/1977/9912 -f 1816/1966/9913 1776/1919/9914 1787/1918/9915 -f 1787/1918/9916 1817/1977/9917 1816/1966/9918 -f 1810/1929/9919 1803/1997/9920 1776/1919/9921 -f 1776/1919/9922 1816/1966/9923 1810/1929/9924 -f 1811/1953/9925 1802/1993/9926 1803/1997/9927 -f 1803/1997/9928 1810/1929/9929 1811/1953/9930 -f 1826/1981/9931 1786/1917/9932 1777/1920/9933 -f 1777/1920/9934 1825/1982/9935 1826/1981/9936 -f 1828/1984/9937 1781/1922/9938 1786/1917/9939 -f 1786/1917/9940 1826/1981/9941 1828/1984/9942 -f 1829/1983/9943 1821/1998/9944 1781/1922/9945 -f 1781/1922/9946 1828/1984/9947 1829/1983/9948 -f 1832/1992/9949 1794/1928/9950 1821/1998/9951 -f 1821/1998/9952 1829/1983/9953 1832/1992/9954 -f 1831/1991/9955 1798/1923/9956 1794/1928/9957 -f 1794/1928/9958 1832/1992/9959 1831/1991/9960 -f 1830/1985/9961 1788/1924/9962 1798/1923/9963 -f 1798/1923/9964 1831/1991/9965 1830/1985/9966 -f 1824/1979/9967 1820/1999/9968 1788/1924/9969 -f 1788/1924/9970 1830/1985/9971 1824/1979/9972 -f 1825/1982/9973 1777/1920/9974 1820/1999/9975 -f 1820/1999/9976 1824/1979/9977 1825/1982/9978 -f 1774/1859/9979 1775/1858/9980 1789/1875/9981 -f 1789/1875/9982 1790/1874/9983 1774/1859/9984 -f 1793/1879/9985 1770/1854/9986 1771/1857/9987 -f 1771/1857/9988 1792/1876/9989 1793/1879/9990 -f 1771/1857/9991 1772/1856/9992 1797/1881/9993 -f 1797/1881/9994 1792/1876/9995 1771/1857/9996 -f 1797/1881/9997 1772/1856/9998 1774/1859/9999 -f 1774/1859/10000 1790/1874/10001 1797/1881/10002 -f 1836/2002/10003 1835/2003/10004 1834/2000/10005 -f 1834/2000/10006 1837/2001/10007 1836/2002/10008 -f 1837/2001/10009 1834/2000/10010 1838/2004/10011 -f 1838/2004/10012 1839/2005/10013 1837/2001/10014 -f 1840/2008/10015 1775/2009/10016 1773/2006/10017 -f 1773/2006/10018 1841/2007/10019 1840/2008/10020 -f 1842/2010/10021 1789/1925/10022 1775/2009/10023 -f 1775/2009/10024 1840/2008/10025 1842/2010/10026 -f 1843/2011/10027 1799/1926/10028 1789/1925/10029 -f 1789/1925/10030 1842/2010/10031 1843/2011/10032 -f 1844/2012/10033 1793/1927/10034 1799/1926/10035 -f 1799/1926/10036 1843/2011/10037 1844/2012/10038 -f 1845/2018/10039 1770/2019/10040 1793/1927/10041 -f 1793/1927/10042 1844/2012/10043 1845/2018/10044 -f 1841/2007/10045 1773/2006/10046 1770/2019/10047 -f 1770/2019/10048 1845/2018/10049 1841/2007/10050 -f 1835/2003/10051 1840/2008/10052 1841/2007/10053 -f 1841/2007/10054 1834/2000/10055 1835/2003/10056 -f 1836/2002/10057 1842/2010/10058 1840/2008/10059 -f 1840/2008/10060 1835/2003/10061 1836/2002/10062 -f 1837/2001/10063 1843/2011/10064 1842/2010/10065 -f 1842/2010/10066 1836/2002/10067 1837/2001/10068 -f 1839/2005/10069 1844/2012/10070 1843/2011/10071 -f 1843/2011/10072 1837/2001/10073 1839/2005/10074 -f 1838/2004/10075 1845/2018/10076 1844/2012/10077 -f 1844/2012/10078 1839/2005/10079 1838/2004/10080 -f 1834/2000/10081 1841/2007/10082 1845/2018/10083 -f 1845/2018/10084 1838/2004/10085 1834/2000/10086 -f 1764/1846/10087 1801/1887/10088 1802/1886/10089 -f 1802/1886/10090 1763/1847/10091 1764/1846/10092 -f 1805/1891/10093 1806/1890/10094 1765/1850/10095 -f 1765/1850/10096 1766/1849/10097 1805/1891/10098 -f 1765/1850/10099 1806/1890/10100 1808/1893/10101 -f 1808/1893/10102 1767/1851/10103 1765/1850/10104 -f 1808/1893/10105 1801/1887/10106 1764/1846/10107 -f 1764/1846/10108 1767/1851/10109 1808/1893/10110 -f 1763/2036/10111 1802/1993/10112 1833/1994/10113 -f 1833/1994/10114 1768/1915/10115 1763/2036/10116 -f 1833/1994/10117 1805/1995/10118 1766/1916/10119 -f 1766/1916/10120 1768/1915/10121 1833/1994/10122 -f 1846/1931/10123 1758/1842/10124 1662/1744/10125 -f 1662/1744/10126 1847/1930/10127 1846/1931/10128 -f 1849/1932/10129 1848/1933/10130 1671/1755/10131 -f 1671/1755/10132 1762/1848/10133 1849/1932/10134 -f 1850/1934/10135 1659/1743/10136 1671/1755/10137 -f 1671/1755/10138 1848/1933/10139 1850/1934/10140 -f 1850/1934/10141 1847/1930/10142 1662/1744/10143 -f 1662/1744/10144 1659/1743/10145 1850/1934/10146 -f 1852/2049/10147 1851/2060/10148 1758/2037/10149 -f 1758/2037/10150 1846/2048/10151 1852/2049/10152 -f 1852/2049/10153 1849/2062/10154 1762/2061/10155 -f 1762/2061/10156 1851/2060/10157 1852/2049/10158 -f 1855/1939/10159 1854/1940/10160 1853/1937/10161 -f 1853/1937/10162 1856/1938/10163 1855/1939/10164 -f 1857/1942/10165 1855/1939/10166 1856/1938/10167 -f 1856/1938/10168 1858/1941/10169 1857/1942/10170 -f 1861/1945/10171 1860/1946/10172 1859/1943/10173 -f 1859/1943/10174 1862/1944/10175 1861/1945/10176 -f 1865/1949/10177 1864/1950/10178 1863/1947/10179 -f 1863/1947/10180 1866/1948/10181 1865/1949/10182 -f 1863/1947/10183 1868/1952/10184 1867/1951/10185 -f 1867/1951/10186 1866/1948/10187 1863/1947/10188 -f 1867/1951/10189 1868/1952/10190 1861/1945/10191 -f 1861/1945/10192 1862/1944/10193 1867/1951/10194 -f 1859/2065/10195 1860/2066/10196 1869/2063/10197 -f 1869/2063/10198 1870/2064/10199 1859/2065/10200 -f 1869/2063/10201 1864/2068/10202 1865/2067/10203 -f 1865/2067/10204 1870/2064/10205 1869/2063/10206 -f 1873/1957/10207 1872/1958/10208 1871/1955/10209 -f 1871/1955/10210 1874/1956/10211 1873/1957/10212 -f 1877/1961/10213 1876/1962/10214 1875/1959/10215 -f 1875/1959/10216 1878/1960/10217 1877/1961/10218 -f 1875/1959/10219 1880/1964/10220 1879/1963/10221 -f 1879/1963/10222 1878/1960/10223 1875/1959/10224 -f 1879/1963/10225 1880/1964/10226 1873/1957/10227 -f 1873/1957/10228 1874/1956/10229 1879/1963/10230 -f 1872/2076/10231 1882/2077/10232 1881/2074/10233 -f 1881/2074/10234 1871/2075/10235 1872/2076/10236 -f 1881/2074/10237 1882/2077/10238 1876/2078/10239 -f 1876/2078/10240 1877/2079/10241 1881/2074/10242 -f 1885/1969/10243 1884/1970/10244 1883/1967/10245 -f 1883/1967/10246 1886/1968/10247 1885/1969/10248 -f 1889/1973/10249 1888/1974/10250 1887/1971/10251 -f 1887/1971/10252 1890/1972/10253 1889/1973/10254 -f 1891/1976/10255 1889/1973/10256 1890/1972/10257 -f 1890/1972/10258 1892/1975/10259 1891/1976/10260 -f 1884/1970/10261 1891/1976/10262 1892/1975/10263 -f 1892/1975/10264 1883/1967/10265 1884/1970/10266 -f 1895/2082/10267 1894/2083/10268 1893/2080/10269 -f 1893/2080/10270 1896/2081/10271 1895/2082/10272 -f 1897/2085/10273 1895/2082/10274 1896/2081/10275 -f 1896/2081/10276 1898/2084/10277 1897/2085/10278 -f 1886/1968/10279 1883/1967/10280 1862/1944/10281 -f 1862/1944/10282 1859/1943/10283 1886/1968/10284 -f 1890/1972/10285 1887/1971/10286 1865/1949/10287 -f 1865/1949/10288 1866/1948/10289 1890/1972/10290 -f 1892/1975/10291 1890/1972/10292 1866/1948/10293 -f 1866/1948/10294 1867/1951/10295 1892/1975/10296 -f 1883/1967/10297 1892/1975/10298 1867/1951/10299 -f 1867/1951/10300 1862/1944/10301 1883/1967/10302 -f 1896/2081/10303 1893/2080/10304 1899/2086/10305 -f 1899/2086/10306 1900/2087/10307 1896/2081/10308 -f 1898/2084/10309 1896/2081/10310 1900/2087/10311 -f 1900/2087/10312 1901/2088/10313 1898/2084/10314 -f 1860/1946/10315 1861/1945/10316 1902/1986/10317 -f 1902/1986/10318 1903/1987/10319 1860/1946/10320 -f 1863/1947/10321 1864/1950/10322 1904/1988/10323 -f 1904/1988/10324 1905/1989/10325 1863/1947/10326 -f 1868/1952/10327 1863/1947/10328 1905/1989/10329 -f 1905/1989/10330 1906/1990/10331 1868/1952/10332 -f 1861/1945/10333 1868/1952/10334 1906/1990/10335 -f 1906/1990/10336 1902/1986/10337 1861/1945/10338 -f 1909/2091/10339 1908/2092/10340 1907/2089/10341 -f 1907/2089/10342 1910/2090/10343 1909/2091/10344 -f 1911/2094/10345 1909/2091/10346 1910/2090/10347 -f 1910/2090/10348 1912/2093/10349 1911/2094/10350 -f 1903/1987/10351 1902/1986/10352 1874/1956/10353 -f 1874/1956/10354 1871/1955/10355 1903/1987/10356 -f 1905/1989/10357 1904/1988/10358 1877/1961/10359 -f 1877/1961/10360 1878/1960/10361 1905/1989/10362 -f 1906/1990/10363 1905/1989/10364 1878/1960/10365 -f 1878/1960/10366 1879/1963/10367 1906/1990/10368 -f 1902/1986/10369 1906/1990/10370 1879/1963/10371 -f 1879/1963/10372 1874/1956/10373 1902/1986/10374 -f 1910/2090/10375 1907/2089/10376 1913/2095/10377 -f 1913/2095/10378 1914/2096/10379 1910/2090/10380 -f 1912/2093/10381 1910/2090/10382 1914/2096/10383 -f 1914/2096/10384 1915/2097/10385 1912/2093/10386 -f 1895/2082/10387 1916/2099/10388 1885/2098/10389 -f 1885/2098/10390 1894/2083/10391 1895/2082/10392 -f 1897/2085/10393 1888/2100/10394 1916/2099/10395 -f 1916/2099/10396 1895/2082/10397 1897/2085/10398 -f 1898/2084/10399 1887/2104/10400 1888/2100/10401 -f 1888/2100/10402 1897/2085/10403 1898/2084/10404 -f 1901/2088/10405 1865/2067/10406 1887/2104/10407 -f 1887/2104/10408 1898/2084/10409 1901/2088/10410 -f 1900/2087/10411 1870/2064/10412 1865/2067/10413 -f 1865/2067/10414 1901/2088/10415 1900/2087/10416 -f 1899/2086/10417 1859/2065/10418 1870/2064/10419 -f 1870/2064/10420 1900/2087/10421 1899/2086/10422 -f 1893/2080/10423 1886/2105/10424 1859/2065/10425 -f 1859/2065/10426 1899/2086/10427 1893/2080/10428 -f 1894/2083/10429 1885/2098/10430 1886/2105/10431 -f 1886/2105/10432 1893/2080/10433 1894/2083/10434 -f 1909/2091/10435 1869/2063/10436 1860/2066/10437 -f 1860/2066/10438 1908/2092/10439 1909/2091/10440 -f 1911/2094/10441 1864/2068/10442 1869/2063/10443 -f 1869/2063/10444 1909/2091/10445 1911/2094/10446 -f 1912/2093/10447 1904/2106/10448 1864/2068/10449 -f 1864/2068/10450 1911/2094/10451 1912/2093/10452 -f 1915/2097/10453 1877/2079/10454 1904/2106/10455 -f 1904/2106/10456 1912/2093/10457 1915/2097/10458 -f 1914/2096/10459 1881/2074/10460 1877/2079/10461 -f 1877/2079/10462 1915/2097/10463 1914/2096/10464 -f 1913/2095/10465 1871/2075/10466 1881/2074/10467 -f 1881/2074/10468 1914/2096/10469 1913/2095/10470 -f 1907/2089/10471 1903/2128/10472 1871/2075/10473 -f 1871/2075/10474 1913/2095/10475 1907/2089/10476 -f 1908/2092/10477 1860/2066/10478 1903/2128/10479 -f 1903/2128/10480 1907/2089/10481 1908/2092/10482 -f 1857/1942/10483 1858/1941/10484 1872/1958/10485 -f 1872/1958/10486 1873/1957/10487 1857/1942/10488 -f 1876/1962/10489 1853/1937/10490 1854/1940/10491 -f 1854/1940/10492 1875/1959/10493 1876/1962/10494 -f 1854/1940/10495 1855/1939/10496 1880/1964/10497 -f 1880/1964/10498 1875/1959/10499 1854/1940/10500 -f 1880/1964/10501 1855/1939/10502 1857/1942/10503 -f 1857/1942/10504 1873/1957/10505 1880/1964/10506 -f 1919/2133/10507 1918/2134/10508 1917/2129/10509 -f 1917/2129/10510 1920/2132/10511 1919/2133/10512 -f 1920/2132/10513 1917/2129/10514 1921/2135/10515 -f 1921/2135/10516 1922/2136/10517 1920/2132/10518 -f 1923/2140/10519 1858/2141/10520 1856/2137/10521 -f 1856/2137/10522 1924/2139/10523 1923/2140/10524 -f 1925/2142/10525 1872/2076/10526 1858/2141/10527 -f 1858/2141/10528 1923/2140/10529 1925/2142/10530 -f 1926/2143/10531 1882/2077/10532 1872/2076/10533 -f 1872/2076/10534 1925/2142/10535 1926/2143/10536 -f 1927/2148/10537 1876/2078/10538 1882/2077/10539 -f 1882/2077/10540 1926/2143/10541 1927/2148/10542 -f 1928/2149/10543 1853/2150/10544 1876/2078/10545 -f 1876/2078/10546 1927/2148/10547 1928/2149/10548 -f 1924/2139/10549 1856/2137/10550 1853/2150/10551 -f 1853/2150/10552 1928/2149/10553 1924/2139/10554 -f 1918/2134/10555 1923/2140/10556 1924/2139/10557 -f 1924/2139/10558 1917/2129/10559 1918/2134/10560 -f 1919/2133/10561 1925/2142/10562 1923/2140/10563 -f 1923/2140/10564 1918/2134/10565 1919/2133/10566 -f 1920/2132/10567 1926/2143/10568 1925/2142/10569 -f 1925/2142/10570 1919/2133/10571 1920/2132/10572 -f 1922/2136/10573 1927/2148/10574 1926/2143/10575 -f 1926/2143/10576 1920/2132/10577 1922/2136/10578 -f 1921/2135/10579 1928/2149/10580 1927/2148/10581 -f 1927/2148/10582 1922/2136/10583 1921/2135/10584 -f 1917/2129/10585 1924/2139/10586 1928/2149/10587 -f 1928/2149/10588 1921/2135/10589 1917/2129/10590 -f 1847/1930/10591 1884/1970/10592 1885/1969/10593 -f 1885/1969/10594 1846/1931/10595 1847/1930/10596 -f 1888/1974/10597 1889/1973/10598 1848/1933/10599 -f 1848/1933/10600 1849/1932/10601 1888/1974/10602 -f 1848/1933/10603 1889/1973/10604 1891/1976/10605 -f 1891/1976/10606 1850/1934/10607 1848/1933/10608 -f 1891/1976/10609 1884/1970/10610 1847/1930/10611 -f 1847/1930/10612 1850/1934/10613 1891/1976/10614 -f 1846/2048/10615 1885/2098/10616 1916/2099/10617 -f 1916/2099/10618 1852/2049/10619 1846/2048/10620 -f 1916/2099/10621 1888/2100/10622 1849/2062/10623 -f 1849/2062/10624 1852/2049/10625 1916/2099/10626 -f 1929/2014/10627 1642/1724/10628 1639/1723/10629 -f 1639/1723/10630 1930/2013/10631 1929/2014/10632 -f 1932/2015/10633 1931/2016/10634 1668/1752/10635 -f 1668/1752/10636 1760/1845/10637 1932/2015/10638 -f 1933/2017/10639 1644/1728/10640 1668/1752/10641 -f 1668/1752/10642 1931/2016/10643 1933/2017/10644 -f 1933/2017/10645 1930/2013/10646 1639/1723/10647 -f 1639/1723/10648 1644/1728/10649 1933/2017/10650 -f 1935/2152/10651 1934/2153/10652 1642/1749/10653 -f 1642/1749/10654 1929/2151/10655 1935/2152/10656 -f 1935/2152/10657 1932/2160/10658 1760/2159/10659 -f 1760/2159/10660 1934/2153/10661 1935/2152/10662 -f 1938/2022/10663 1937/2023/10664 1936/2020/10665 -f 1936/2020/10666 1939/2021/10667 1938/2022/10668 -f 1940/2025/10669 1938/2022/10670 1939/2021/10671 -f 1939/2021/10672 1941/2024/10673 1940/2025/10674 -f 1944/2028/10675 1943/2029/10676 1942/2026/10677 -f 1942/2026/10678 1945/2027/10679 1944/2028/10680 -f 1948/2032/10681 1947/2033/10682 1946/2030/10683 -f 1946/2030/10684 1949/2031/10685 1948/2032/10686 -f 1946/2030/10687 1951/2035/10688 1950/2034/10689 -f 1950/2034/10690 1949/2031/10691 1946/2030/10692 -f 1950/2034/10693 1951/2035/10694 1944/2028/10695 -f 1944/2028/10696 1945/2027/10697 1950/2034/10698 -f 1942/2163/10699 1943/2164/10700 1952/2161/10701 -f 1952/2161/10702 1953/2162/10703 1942/2163/10704 -f 1952/2161/10705 1947/2167/10706 1948/2166/10707 -f 1948/2166/10708 1953/2162/10709 1952/2161/10710 -f 1956/2040/10711 1955/2041/10712 1954/2038/10713 -f 1954/2038/10714 1957/2039/10715 1956/2040/10716 -f 1960/2044/10717 1959/2045/10718 1958/2042/10719 -f 1958/2042/10720 1961/2043/10721 1960/2044/10722 -f 1958/2042/10723 1963/2047/10724 1962/2046/10725 -f 1962/2046/10726 1961/2043/10727 1958/2042/10728 -f 1962/2046/10729 1963/2047/10730 1956/2040/10731 -f 1956/2040/10732 1957/2039/10733 1962/2046/10734 -f 1955/2170/10735 1965/2171/10736 1964/2168/10737 -f 1964/2168/10738 1954/2169/10739 1955/2170/10740 -f 1964/2168/10741 1965/2171/10742 1959/2172/10743 -f 1959/2172/10744 1960/2173/10745 1964/2168/10746 -f 1968/2052/10747 1967/2053/10748 1966/2050/10749 -f 1966/2050/10750 1969/2051/10751 1968/2052/10752 -f 1972/2056/10753 1971/2057/10754 1970/2054/10755 -f 1970/2054/10756 1973/2055/10757 1972/2056/10758 -f 1974/2059/10759 1972/2056/10760 1973/2055/10761 -f 1973/2055/10762 1975/2058/10763 1974/2059/10764 -f 1967/2053/10765 1974/2059/10766 1975/2058/10767 -f 1975/2058/10768 1966/2050/10769 1967/2053/10770 -f 1978/2183/10771 1977/2185/10772 1976/2174/10773 -f 1976/2174/10774 1979/2175/10775 1978/2183/10776 -f 1980/2187/10777 1978/2183/10778 1979/2175/10779 -f 1979/2175/10780 1981/2186/10781 1980/2187/10782 -f 1969/2051/10783 1966/2050/10784 1945/2027/10785 -f 1945/2027/10786 1942/2026/10787 1969/2051/10788 -f 1973/2055/10789 1970/2054/10790 1948/2032/10791 -f 1948/2032/10792 1949/2031/10793 1973/2055/10794 -f 1975/2058/10795 1973/2055/10796 1949/2031/10797 -f 1949/2031/10798 1950/2034/10799 1975/2058/10800 -f 1966/2050/10801 1975/2058/10802 1950/2034/10803 -f 1950/2034/10804 1945/2027/10805 1966/2050/10806 -f 1979/2175/10807 1976/2174/10808 1982/2188/10809 -f 1982/2188/10810 1983/2189/10811 1979/2175/10812 -f 1981/2186/10813 1979/2175/10814 1983/2189/10815 -f 1983/2189/10816 1984/2190/10817 1981/2186/10818 -f 1943/2029/10819 1944/2028/10820 1985/2069/10821 -f 1985/2069/10822 1986/2070/10823 1943/2029/10824 -f 1946/2030/10825 1947/2033/10826 1987/2071/10827 -f 1987/2071/10828 1988/2072/10829 1946/2030/10830 -f 1951/2035/10831 1946/2030/10832 1988/2072/10833 -f 1988/2072/10834 1989/2073/10835 1951/2035/10836 -f 1944/2028/10837 1951/2035/10838 1989/2073/10839 -f 1989/2073/10840 1985/2069/10841 1944/2028/10842 -f 1992/2196/10843 1991/2197/10844 1990/2191/10845 -f 1990/2191/10846 1993/2195/10847 1992/2196/10848 -f 1994/2205/10849 1992/2196/10850 1993/2195/10851 -f 1993/2195/10852 1995/2198/10853 1994/2205/10854 -f 1986/2070/10855 1985/2069/10856 1957/2039/10857 -f 1957/2039/10858 1954/2038/10859 1986/2070/10860 -f 1988/2072/10861 1987/2071/10862 1960/2044/10863 -f 1960/2044/10864 1961/2043/10865 1988/2072/10866 -f 1989/2073/10867 1988/2072/10868 1961/2043/10869 -f 1961/2043/10870 1962/2046/10871 1989/2073/10872 -f 1985/2069/10873 1989/2073/10874 1962/2046/10875 -f 1962/2046/10876 1957/2039/10877 1985/2069/10878 -f 1993/2195/10879 1990/2191/10880 1996/2212/10881 -f 1996/2212/10882 1997/2213/10883 1993/2195/10884 -f 1995/2198/10885 1993/2195/10886 1997/2213/10887 -f 1997/2213/10888 1998/2214/10889 1995/2198/10890 -f 1978/2183/10891 1999/2216/10892 1968/2215/10893 -f 1968/2215/10894 1977/2185/10895 1978/2183/10896 -f 1980/2187/10897 1971/2217/10898 1999/2216/10899 -f 1999/2216/10900 1978/2183/10901 1980/2187/10902 -f 1981/2186/10903 1970/2218/10904 1971/2217/10905 -f 1971/2217/10906 1980/2187/10907 1981/2186/10908 -f 1984/2190/10909 1948/2166/10910 1970/2218/10911 -f 1970/2218/10912 1981/2186/10913 1984/2190/10914 -f 1983/2189/10915 1953/2162/10916 1948/2166/10917 -f 1948/2166/10918 1984/2190/10919 1983/2189/10920 -f 1982/2188/10921 1942/2163/10922 1953/2162/10923 -f 1953/2162/10924 1983/2189/10925 1982/2188/10926 -f 1976/2174/10927 1969/2219/10928 1942/2163/10929 -f 1942/2163/10930 1982/2188/10931 1976/2174/10932 -f 1977/2185/10933 1968/2215/10934 1969/2219/10935 -f 1969/2219/10936 1976/2174/10937 1977/2185/10938 -f 1992/2196/10939 1952/2161/10940 1943/2164/10941 -f 1943/2164/10942 1991/2197/10943 1992/2196/10944 -f 1994/2205/10945 1947/2167/10946 1952/2161/10947 -f 1952/2161/10948 1992/2196/10949 1994/2205/10950 -f 1995/2198/10951 1987/2220/10952 1947/2167/10953 -f 1947/2167/10954 1994/2205/10955 1995/2198/10956 -f 1998/2214/10957 1960/2173/10958 1987/2220/10959 -f 1987/2220/10960 1995/2198/10961 1998/2214/10962 -f 1997/2213/10963 1964/2168/10964 1960/2173/10965 -f 1960/2173/10966 1998/2214/10967 1997/2213/10968 -f 1996/2212/10969 1954/2169/10970 1964/2168/10971 -f 1964/2168/10972 1997/2213/10973 1996/2212/10974 -f 1990/2191/10975 1986/2221/10976 1954/2169/10977 -f 1954/2169/10978 1996/2212/10979 1990/2191/10980 -f 1991/2197/10981 1943/2164/10982 1986/2221/10983 -f 1986/2221/10984 1990/2191/10985 1991/2197/10986 -f 1940/2025/10987 1941/2024/10988 1955/2041/10989 -f 1955/2041/10990 1956/2040/10991 1940/2025/10992 -f 1959/2045/10993 1936/2020/10994 1937/2023/10995 -f 1937/2023/10996 1958/2042/10997 1959/2045/10998 -f 1937/2023/10999 1938/2022/11000 1963/2047/11001 -f 1963/2047/11002 1958/2042/11003 1937/2023/11004 -f 1963/2047/11005 1938/2022/11006 1940/2025/11007 -f 1940/2025/11008 1956/2040/11009 1963/2047/11010 -f 2002/2224/11011 2001/2252/11012 2000/2222/11013 -f 2000/2222/11014 2003/2223/11015 2002/2224/11016 -f 2003/2223/11017 2000/2222/11018 2004/2253/11019 -f 2004/2253/11020 2005/2254/11021 2003/2223/11022 -f 2006/2260/11023 1941/2261/11024 1939/2255/11025 -f 1939/2255/11026 2007/2259/11027 2006/2260/11028 -f 2008/2262/11029 1955/2170/11030 1941/2261/11031 -f 1941/2261/11032 2006/2260/11033 2008/2262/11034 -f 2009/2263/11035 1965/2171/11036 1955/2170/11037 -f 1955/2170/11038 2008/2262/11039 2009/2263/11040 -f 2010/2264/11041 1959/2172/11042 1965/2171/11043 -f 1965/2171/11044 2009/2263/11045 2010/2264/11046 -f 2011/2265/11047 1936/2266/11048 1959/2172/11049 -f 1959/2172/11050 2010/2264/11051 2011/2265/11052 -f 2007/2259/11053 1939/2255/11054 1936/2266/11055 -f 1936/2266/11056 2011/2265/11057 2007/2259/11058 -f 2001/2252/11059 2006/2260/11060 2007/2259/11061 -f 2007/2259/11062 2000/2222/11063 2001/2252/11064 -f 2002/2224/11065 2008/2262/11066 2006/2260/11067 -f 2006/2260/11068 2001/2252/11069 2002/2224/11070 -f 2003/2223/11071 2009/2263/11072 2008/2262/11073 -f 2008/2262/11074 2002/2224/11075 2003/2223/11076 -f 2005/2254/11077 2010/2264/11078 2009/2263/11079 -f 2009/2263/11080 2003/2223/11081 2005/2254/11082 -f 2004/2253/11083 2011/2265/11084 2010/2264/11085 -f 2010/2264/11086 2005/2254/11087 2004/2253/11088 -f 2000/2222/11089 2007/2259/11090 2011/2265/11091 -f 2011/2265/11092 2004/2253/11093 2000/2222/11094 -f 1930/2013/11095 1967/2053/11096 1968/2052/11097 -f 1968/2052/11098 1929/2014/11099 1930/2013/11100 -f 1971/2057/11101 1972/2056/11102 1931/2016/11103 -f 1931/2016/11104 1932/2015/11105 1971/2057/11106 -f 1931/2016/11107 1972/2056/11108 1974/2059/11109 -f 1974/2059/11110 1933/2017/11111 1931/2016/11112 -f 1974/2059/11113 1967/2053/11114 1930/2013/11115 -f 1930/2013/11116 1933/2017/11117 1974/2059/11118 -f 1929/2151/11119 1968/2215/11120 1999/2216/11121 -f 1999/2216/11122 1935/2152/11123 1929/2151/11124 -f 1999/2216/11125 1971/2217/11126 1932/2160/11127 -f 1932/2160/11128 1935/2152/11129 1999/2216/11130 -f 1654/1736/11131 1642/1749/11132 1934/2153/11133 -f 1934/2153/11134 1653/1737/11135 1654/1736/11136 -f 1651/1735/11137 2012/2267/11138 1642/2579/11139 -f 1642/2579/11140 1654/1736/11141 1651/1735/11142 -f 1652/1738/11143 2013/2268/11144 2012/2267/11145 -f 2012/2267/11146 1651/1735/11147 1652/1738/11148 -f 1669/1775/11149 1761/2269/11150 2013/2268/11151 -f 2013/2268/11152 1652/1738/11153 1669/1775/11154 -f 1670/1774/11155 1760/2159/11156 1761/2269/11157 -f 1761/2269/11158 1669/1775/11159 1670/1774/11160 -f 1653/1737/11161 1934/2153/11162 1760/2159/11163 -f 1760/2159/11164 1670/1774/11165 1653/1737/11166 -f 1650/1732/11167 1636/1741/11168 1657/1748/11169 -f 1657/1748/11170 1649/1733/11171 1650/1732/11172 -f 1647/1731/11173 2014/2270/11174 1636/1741/11175 -f 1636/1741/11176 1650/1732/11177 1647/1731/11178 -f 1648/1734/11179 2015/2271/11180 2014/2270/11181 -f 2014/2270/11182 1647/1731/11183 1648/1734/11184 -f 1754/1911/11185 2012/2267/11186 2015/2271/11187 -f 2015/2271/11188 1648/1734/11189 1754/1911/11190 -f 1755/1910/11191 1642/2579/11192 2012/2267/11193 -f 2012/2267/11194 1754/1911/11195 1755/1910/11196 -f 1649/1733/11197 1657/1748/11198 1642/2383/11199 -f 1642/2383/11200 1755/1910/11201 1649/1733/11202 -f 1752/1908/11203 1769/1914/11204 1636/1741/11205 -f 1636/1741/11206 1757/1912/11207 1752/1908/11208 -f 1753/1902/11209 1762/2061/11210 1769/1914/11211 -f 1769/1914/11212 1752/1908/11213 1753/1902/11214 -f 1750/1901/11215 1634/1716/11216 1762/2061/11217 -f 1762/2061/11218 1753/1902/11219 1750/1901/11220 -f 1751/1909/11221 2016/2272/11222 1634/1716/11223 -f 1634/1716/11224 1750/1901/11225 1751/1909/11226 -f 1756/1913/11227 2014/2270/11228 2016/2272/11229 -f 2016/2272/11230 1751/1909/11231 1756/1913/11232 -f 1757/1912/11233 1636/1741/11234 2014/2270/11235 -f 2014/2270/11236 1756/1913/11237 1757/1912/11238 -f 1666/1754/11239 1758/2037/11240 1851/2060/11241 -f 1851/2060/11242 1665/1756/11243 1666/1754/11244 -f 1663/1753/11245 1759/2273/11246 1758/2037/11247 -f 1758/2037/11248 1666/1754/11249 1663/1753/11250 -f 1664/1757/11251 1631/1715/11252 1759/2273/11253 -f 1759/2273/11254 1663/1753/11255 1664/1757/11256 -f 1672/1787/11257 1634/1716/11258 1631/1715/11259 -f 1631/1715/11260 1664/1757/11261 1672/1787/11262 -f 1673/1786/11263 1762/2061/11264 1634/1716/11265 -f 1634/1716/11266 1672/1787/11267 1673/1786/11268 -f 1665/1756/11269 1851/2060/11270 1762/2061/11271 -f 1762/2061/11272 1673/1786/11273 1665/1756/11274 -f 1763/2036/11275 1768/1915/11276 1769/1914/11277 -f 1769/1914/11278 1762/2061/11279 1763/2036/11280 -f 1661/1745/11281 1759/1843/11282 2017/2101/11283 -f 2017/2101/11284 2018/2102/11285 1661/1745/11286 -f 1617/1703/11287 1618/1702/11288 1626/1709/11289 -f 1626/1709/11290 2019/2103/11291 1617/1703/11292 -f 2016/2272/11293 2014/2270/11294 2020/2274/11295 -f 2020/2274/11296 2021/2275/11297 2016/2272/11298 -f 1625/1710/11299 1618/1702/11300 1619/1701/11301 -f 1619/1701/11302 1660/1746/11303 1625/1710/11304 -f 1628/1714/11305 2012/2267/11306 2013/2268/11307 -f 2013/2268/11308 2022/2276/11309 1628/1714/11310 -f 2015/2271/11311 2012/2267/11312 1628/1714/11313 -f 1628/1714/11314 1629/1713/11315 2015/2271/11316 -f 2025/2109/11317 2024/2110/11318 2023/2107/11319 -f 2023/2107/11320 2026/2108/11321 2025/2109/11322 -f 2027/2112/11323 2026/2108/11324 2023/2107/11325 -f 2023/2107/11326 2028/2111/11327 2027/2112/11328 -f 2030/2114/11329 2029/2115/11330 2027/2112/11331 -f 2027/2112/11332 2031/2113/11333 2030/2114/11334 -f 2026/2108/11335 2033/2117/11336 2032/2116/11337 -f 2032/2116/11338 2025/2109/11339 2026/2108/11340 -f 2029/2115/11341 2033/2117/11342 2026/2108/11343 -f 2026/2108/11344 2027/2112/11345 2029/2115/11346 -f 1615/1697/11347 2035/2119/11348 2034/2118/11349 -f 2034/2118/11350 1614/1698/11351 1615/1697/11352 -f 2038/2122/11353 2037/2123/11354 2036/2120/11355 -f 2036/2120/11356 2039/2121/11357 2038/2122/11358 -f 2040/2125/11359 2037/2123/11360 2038/2122/11361 -f 2038/2122/11362 2041/2124/11363 2040/2125/11364 -f 2039/2121/11365 2036/2120/11366 2042/2126/11367 -f 2042/2126/11368 2043/2127/11369 2039/2121/11370 -f 2043/2279/11371 2042/2280/11372 2044/2277/11373 -f 2044/2277/11374 2045/2278/11375 2043/2279/11376 -f 2045/2278/11377 2044/2277/11378 2046/2281/11379 -f 2046/2281/11380 2047/2282/11381 2045/2278/11382 -f 2046/2131/11383 2040/2125/11384 2041/2124/11385 -f 2041/2124/11386 2047/2130/11387 2046/2131/11388 -f 2050/2285/11389 2049/2286/11390 2048/2283/11391 -f 2048/2283/11392 2051/2284/11393 2050/2285/11394 -f 2052/2288/11395 2050/2285/11396 2051/2284/11397 -f 2051/2284/11398 2053/2287/11399 2052/2288/11400 -f 2032/2116/11401 2033/2117/11402 2038/2122/11403 -f 2038/2122/11404 2039/2121/11405 2032/2116/11406 -f 2033/2117/11407 2029/2115/11408 2041/2124/11409 -f 2041/2124/11410 2038/2122/11411 2033/2117/11412 -f 2054/2138/11413 2032/2116/11414 2039/2121/11415 -f 2039/2121/11416 2043/2127/11417 2054/2138/11418 -f 2051/2284/11419 2048/2283/11420 2055/2289/11421 -f 2055/2289/11422 2056/2290/11423 2051/2284/11424 -f 2053/2287/11425 2051/2284/11426 2056/2290/11427 -f 2056/2290/11428 2057/2291/11429 2053/2287/11430 -f 2029/2115/11431 2030/2114/11432 2047/2130/11433 -f 2047/2130/11434 2041/2124/11435 2029/2115/11436 -f 2050/2285/11437 2059/2293/11438 2058/2292/11439 -f 2058/2292/11440 2049/2286/11441 2050/2285/11442 -f 2052/2288/11443 2031/2294/11444 2059/2293/11445 -f 2059/2293/11446 2050/2285/11447 2052/2288/11448 -f 2053/2287/11449 2030/2295/11450 2031/2294/11451 -f 2031/2294/11452 2052/2288/11453 2053/2287/11454 -f 2057/2291/11455 2047/2282/11456 2030/2295/11457 -f 2030/2295/11458 2053/2287/11459 2057/2291/11460 -f 2056/2290/11461 2045/2278/11462 2047/2282/11463 -f 2047/2282/11464 2057/2291/11465 2056/2290/11466 -f 2055/2289/11467 2043/2279/11468 2045/2278/11469 -f 2045/2278/11470 2056/2290/11471 2055/2289/11472 -f 2048/2283/11473 2054/2296/11474 2043/2279/11475 -f 2043/2279/11476 2055/2289/11477 2048/2283/11478 -f 2049/2286/11479 2058/2292/11480 2054/2296/11481 -f 2054/2296/11482 2048/2283/11483 2049/2286/11484 -f 1615/1697/11485 1612/1696/11486 2060/2144/11487 -f 2060/2144/11488 2061/2145/11489 1615/1697/11490 -f 2035/2119/11491 1615/1697/11492 2061/2145/11493 -f 2061/2145/11494 2062/2146/11495 2035/2119/11496 -f 2060/2144/11497 1612/1696/11498 1613/1699/11499 -f 1613/1699/11500 2063/2147/11501 2060/2144/11502 -f 2066/2299/11503 2065/2300/11504 2064/2297/11505 -f 2064/2297/11506 2067/2298/11507 2066/2299/11508 -f 2067/2298/11509 2064/2297/11510 2068/2301/11511 -f 2068/2301/11512 2069/2302/11513 2067/2298/11514 -f 2070/2154/11515 2034/2118/11516 2035/2119/11517 -f 2035/2119/11518 2062/2146/11519 2070/2154/11520 -f 2036/2120/11521 2037/2123/11522 2071/2155/11523 -f 2071/2155/11524 2072/2156/11525 2036/2120/11526 -f 2037/2123/11527 2040/2125/11528 2073/2157/11529 -f 2073/2157/11530 2071/2155/11531 2037/2123/11532 -f 2042/2126/11533 2036/2120/11534 2072/2156/11535 -f 2072/2156/11536 2074/2158/11537 2042/2126/11538 -f 2077/2305/11539 2076/2306/11540 2075/2303/11541 -f 2075/2303/11542 2078/2304/11543 2077/2305/11544 -f 2079/2308/11545 2077/2305/11546 2078/2304/11547 -f 2078/2304/11548 2080/2307/11549 2079/2308/11550 -f 2040/2125/11551 2046/2131/11552 2081/2165/11553 -f 2081/2165/11554 2073/2157/11555 2040/2125/11556 -f 2072/2156/11557 2071/2155/11558 2061/2145/11559 -f 2061/2145/11560 2060/2144/11561 2072/2156/11562 -f 2071/2155/11563 2073/2157/11564 2062/2146/11565 -f 2062/2146/11566 2061/2145/11567 2071/2155/11568 -f 2074/2158/11569 2072/2156/11570 2060/2144/11571 -f 2060/2144/11572 2063/2147/11573 2074/2158/11574 -f 2078/2304/11575 2075/2303/11576 2082/2309/11577 -f 2082/2309/11578 2083/2310/11579 2078/2304/11580 -f 2080/2307/11581 2078/2304/11582 2083/2310/11583 -f 2083/2310/11584 2084/2311/11585 2080/2307/11586 -f 2073/2157/11587 2081/2165/11588 2070/2154/11589 -f 2070/2154/11590 2062/2146/11591 2073/2157/11592 -f 2077/2305/11593 2044/2277/11594 2042/2280/11595 -f 2042/2280/11596 2076/2306/11597 2077/2305/11598 -f 2079/2308/11599 2046/2281/11600 2044/2277/11601 -f 2044/2277/11602 2077/2305/11603 2079/2308/11604 -f 2080/2307/11605 2081/2312/11606 2046/2281/11607 -f 2046/2281/11608 2079/2308/11609 2080/2307/11610 -f 2084/2311/11611 2070/2313/11612 2081/2312/11613 -f 2081/2312/11614 2080/2307/11615 2084/2311/11616 -f 2083/2310/11617 2085/2314/11618 2070/2313/11619 -f 2070/2313/11620 2084/2311/11621 2083/2310/11622 -f 2082/2309/11623 2063/2315/11624 2085/2314/11625 -f 2085/2314/11626 2083/2310/11627 2082/2309/11628 -f 2075/2303/11629 2074/2316/11630 2063/2315/11631 -f 2063/2315/11632 2082/2309/11633 2075/2303/11634 -f 2076/2306/11635 2042/2280/11636 2074/2316/11637 -f 2074/2316/11638 2075/2303/11639 2076/2306/11640 -f 2086/2319/11641 1613/2320/11642 1614/2317/11643 -f 1614/2317/11644 2087/2318/11645 2086/2319/11646 -f 2088/2321/11647 2063/2315/11648 1613/2320/11649 -f 1613/2320/11650 2086/2319/11651 2088/2321/11652 -f 2089/2322/11653 2085/2314/11654 2063/2315/11655 -f 2063/2315/11656 2088/2321/11657 2089/2322/11658 -f 2090/2323/11659 2070/2313/11660 2085/2314/11661 -f 2085/2314/11662 2089/2322/11663 2090/2323/11664 -f 2091/2324/11665 2034/2325/11666 2070/2313/11667 -f 2070/2313/11668 2090/2323/11669 2091/2324/11670 -f 2087/2318/11671 1614/2317/11672 2034/2325/11673 -f 2034/2325/11674 2091/2324/11675 2087/2318/11676 -f 2065/2300/11677 2086/2319/11678 2087/2318/11679 -f 2087/2318/11680 2064/2297/11681 2065/2300/11682 -f 2066/2299/11683 2088/2321/11684 2086/2319/11685 -f 2086/2319/11686 2065/2300/11687 2066/2299/11688 -f 2067/2298/11689 2089/2322/11690 2088/2321/11691 -f 2088/2321/11692 2066/2299/11693 2067/2298/11694 -f 2069/2302/11695 2090/2323/11696 2089/2322/11697 -f 2089/2322/11698 2067/2298/11699 2069/2302/11700 -f 2068/2301/11701 2091/2324/11702 2090/2323/11703 -f 2090/2323/11704 2069/2302/11705 2068/2301/11706 -f 2064/2297/11707 2087/2318/11708 2091/2324/11709 -f 2091/2324/11710 2068/2301/11711 2064/2297/11712 -f 1646/1729/11713 2093/2177/11714 2092/2176/11715 -f 2092/2176/11716 1645/1730/11717 1646/1729/11718 -f 2096/2180/11719 2095/2181/11720 2094/2178/11721 -f 2094/2178/11722 2097/2179/11723 2096/2180/11724 -f 2098/2182/11725 1621/1707/11726 1617/1703/11727 -f 1617/1703/11728 2019/2103/11729 2098/2182/11730 -f 2017/2326/11731 1759/2273/11732 1631/1715/11733 -f 1631/1715/11734 1632/1718/11735 2017/2326/11736 -f 2099/2329/11737 1608/2330/11738 1609/2327/11739 -f 1609/2327/11740 2100/2328/11741 2099/2329/11742 -f 1633/1717/11743 1634/1716/11744 2016/2272/11745 -f 2016/2272/11746 2021/2275/11747 1633/1717/11748 -f 2102/2333/11749 1627/1711/11750 2101/2331/11751 -f 2101/2331/11752 2103/2332/11753 2102/2333/11754 -f 1628/1714/11755 2022/2276/11756 2101/2331/11757 -f 2101/2331/11758 1627/1711/11759 1628/1714/11760 -f 2105/2336/11761 2104/2337/11762 2024/2334/11763 -f 2024/2334/11764 2025/2335/11765 2105/2336/11766 -f 2020/2274/11767 2014/2270/11768 2015/2271/11769 -f 2015/2271/11770 1629/1713/11771 2020/2274/11772 -f 2102/2333/11773 2106/2338/11774 1630/1712/11775 -f 1630/1712/11776 1627/1711/11777 2102/2333/11778 -f 2020/2274/11779 1629/1713/11780 1630/1712/11781 -f 1630/1712/11782 2107/2339/11783 2020/2274/11784 -f 2108/2184/11785 1667/1751/11786 1645/1730/11787 -f 1645/1730/11788 2092/2176/11789 2108/2184/11790 -f 1761/1844/11791 1667/1751/11792 2108/2184/11793 -f 2108/2184/11794 2109/2192/11795 1761/1844/11796 -f 2013/2268/11797 1761/2269/11798 2109/2340/11799 -f 2109/2340/11800 2022/2276/11801 2013/2268/11802 -f 2110/2193/11803 1620/1704/11804 1621/1707/11805 -f 1621/1707/11806 2098/2182/11807 2110/2193/11808 -f 2111/2341/11809 2101/2331/11810 2022/2276/11811 -f 2022/2276/11812 2104/2337/11813 2111/2341/11814 -f 2112/2342/11815 2103/2332/11816 2101/2331/11817 -f 2101/2331/11818 2111/2341/11819 2112/2342/11820 -f 2114/2343/11821 2113/2344/11822 2103/2332/11823 -f 2103/2332/11824 2112/2342/11825 2114/2343/11826 -f 2115/2345/11827 2097/2346/11828 2113/2344/11829 -f 2113/2344/11830 2114/2343/11831 2115/2345/11832 -f 2116/2199/11833 2096/2180/11834 2097/2179/11835 -f 2097/2179/11836 2115/2194/11837 2116/2199/11838 -f 2093/2177/11839 1620/1704/11840 2110/2193/11841 -f 2110/2193/11842 2117/2200/11843 2093/2177/11844 -f 2117/2200/11845 2110/2193/11846 2096/2180/11847 -f 2096/2180/11848 2116/2199/11849 2117/2200/11850 -f 2118/2202/11851 2027/2112/11852 2028/2111/11853 -f 2028/2111/11854 2119/2201/11855 2118/2202/11856 -f 2059/2293/11857 2114/2343/11858 2112/2342/11859 -f 2112/2342/11860 2058/2292/11861 2059/2293/11862 -f 2115/2345/11863 2114/2343/11864 2059/2293/11865 -f 2059/2293/11866 2031/2294/11867 2115/2345/11868 -f 2120/2203/11869 2116/2199/11870 2115/2194/11871 -f 2115/2194/11872 2031/2113/11873 2120/2203/11874 -f 2117/2200/11875 2116/2199/11876 2120/2203/11877 -f 2120/2203/11878 2118/2202/11879 2117/2200/11880 -f 2093/2177/11881 2117/2200/11882 2118/2202/11883 -f 2118/2202/11884 2119/2201/11885 2093/2177/11886 -f 2092/2176/11887 2093/2177/11888 2119/2201/11889 -f 2119/2201/11890 2028/2111/11891 2092/2176/11892 -f 2109/2192/11893 2108/2184/11894 2023/2107/11895 -f 2023/2107/11896 2024/2110/11897 2109/2192/11898 -f 2104/2337/11899 2022/2276/11900 2109/2340/11901 -f 2109/2340/11902 2024/2334/11903 2104/2337/11904 -f 2112/2342/11905 2111/2341/11906 2121/2347/11907 -f 2121/2347/11908 2058/2292/11909 2112/2342/11910 -f 2023/2107/11911 2108/2184/11912 2092/2176/11913 -f 2092/2176/11914 2028/2111/11915 2023/2107/11916 -f 2105/2336/11917 2121/2347/11918 2111/2341/11919 -f 2111/2341/11920 2104/2337/11921 2105/2336/11922 -f 2105/2336/11923 2025/2335/11924 2122/2348/11925 -f 2122/2348/11926 2121/2347/11927 2105/2336/11928 -f 1611/1693/11929 2124/2206/11930 2123/2204/11931 -f 2123/2204/11932 1610/1694/11933 1611/1693/11934 -f 1661/1745/11935 2018/2102/11936 1625/1710/11937 -f 1625/1710/11938 1660/1746/11939 1661/1745/11940 -f 2099/2329/11941 2100/2328/11942 2017/2326/11943 -f 2017/2326/11944 1632/1718/11945 2099/2329/11946 -f 2125/2208/11947 2018/2102/11948 2017/2101/11949 -f 2017/2101/11950 2100/2207/11951 2125/2208/11952 -f 1624/1708/11953 1625/1710/11954 2018/2102/11955 -f 2018/2102/11956 2125/2208/11957 1624/1708/11958 -f 1620/1704/11959 2093/2177/11960 1646/1729/11961 -f 1646/1729/11962 1623/1705/11963 1620/1704/11964 -f 1621/1707/11965 1622/1706/11966 1616/1700/11967 -f 1616/1700/11968 1617/1703/11969 1621/1707/11970 -f 2019/2103/11971 2126/2209/11972 2095/2181/11973 -f 2095/2181/11974 2098/2182/11975 2019/2103/11976 -f 2110/2193/11977 2098/2182/11978 2095/2181/11979 -f 2095/2181/11980 2096/2180/11981 2110/2193/11982 -f 2123/2204/11983 2124/2206/11984 2126/2209/11985 -f 2126/2209/11986 2127/2210/11987 2123/2204/11988 -f 1610/1694/11989 2125/2208/11990 2100/2207/11991 -f 2100/2207/11992 1609/1695/11993 1610/1694/11994 -f 1624/1708/11995 2125/2208/11996 1610/1694/11997 -f 1610/1694/11998 2123/2204/11999 1624/1708/12000 -f 2127/2210/12001 1626/1709/12002 1624/1708/12003 -f 1624/1708/12004 2123/2204/12005 2127/2210/12006 -f 2019/2103/12007 1626/1709/12008 2127/2210/12009 -f 2127/2210/12010 2126/2209/12011 2019/2103/12012 -f 2094/2178/12013 2095/2181/12014 2126/2209/12015 -f 2126/2209/12016 2124/2206/12017 2094/2178/12018 -f 2128/2350/12019 1611/2351/12020 1608/2485/12021 -f 1608/2485/12022 2129/2349/12023 2128/2350/12024 -f 2130/2352/12025 2124/2353/12026 1611/2351/12027 -f 1611/2351/12028 2128/2350/12029 2130/2352/12030 -f 2131/2354/12031 2094/2355/12032 2124/2353/12033 -f 2124/2353/12034 2130/2352/12035 2131/2354/12036 -f 2132/2356/12037 2097/2346/12038 2094/2355/12039 -f 2094/2355/12040 2131/2354/12041 2132/2356/12042 -f 2133/2357/12043 2113/2344/12044 2097/2346/12045 -f 2097/2346/12046 2132/2356/12047 2133/2357/12048 -f 2134/2358/12049 2103/2332/12050 2113/2344/12051 -f 2113/2344/12052 2133/2357/12053 2134/2358/12054 -f 2135/2359/12055 2102/2333/12056 2103/2332/12057 -f 2103/2332/12058 2134/2358/12059 2135/2359/12060 -f 2136/2360/12061 2106/2338/12062 2102/2333/12063 -f 2102/2333/12064 2135/2359/12065 2136/2360/12066 -f 2138/2361/12067 2137/2362/12068 2106/2338/12069 -f 2106/2338/12070 2136/2360/12071 2138/2361/12072 -f 2099/2329/12073 2140/2364/12074 2139/2363/12075 -f 2139/2363/12076 1608/2330/12077 2099/2329/12078 -f 2107/2339/12079 1630/1712/12080 2106/2338/12081 -f 2106/2338/12082 2137/2362/12083 2107/2339/12084 -f 2142/2365/12085 2141/2366/12086 2128/2350/12087 -f 2128/2350/12088 2129/2349/12089 2142/2365/12090 -f 2143/2367/12091 2130/2352/12092 2128/2350/12093 -f 2128/2350/12094 2141/2366/12095 2143/2367/12096 -f 2143/2367/12097 2144/2368/12098 2131/2354/12099 -f 2131/2354/12100 2130/2352/12101 2143/2367/12102 -f 2144/2368/12103 2145/2369/12104 2132/2356/12105 -f 2132/2356/12106 2131/2354/12107 2144/2368/12108 -f 2145/2369/12109 2146/2370/12110 2133/2357/12111 -f 2133/2357/12112 2132/2356/12113 2145/2369/12114 -f 2147/2371/12115 2134/2358/12116 2133/2357/12117 -f 2133/2357/12118 2146/2370/12119 2147/2371/12120 -f 2148/2372/12121 2135/2359/12122 2134/2358/12123 -f 2134/2358/12124 2147/2371/12125 2148/2372/12126 -f 2149/2373/12127 2136/2360/12128 2135/2359/12129 -f 2135/2359/12130 2148/2372/12131 2149/2373/12132 -f 2149/2373/12133 2150/2374/12134 2138/2361/12135 -f 2138/2361/12136 2136/2360/12137 2149/2373/12138 -f 2150/2374/12139 2142/2500/12140 2129/2494/12141 -f 2129/2494/12142 2138/2361/12143 2150/2374/12144 -f 2118/2202/12145 2120/2203/12146 2031/2113/12147 -f 2031/2113/12148 2027/2112/12149 2118/2202/12150 -f 2025/2109/12151 2032/2116/12152 2054/2138/12153 -f 2054/2138/12154 2122/2211/12155 2025/2109/12156 -f 2054/2296/12157 2058/2292/12158 2121/2347/12159 -f 2121/2347/12160 2122/2348/12161 2054/2296/12162 -f 2153/2598/12163 2152/2228/12164 2151/2225/12165 -f 2151/2225/12166 2154/2226/12167 2153/2598/12168 -f 2155/2230/12169 2152/2228/12170 2153/2598/12171 -f 2153/2598/12172 2156/2229/12173 2155/2230/12174 -f 2158/2231/12175 2157/2232/12176 2155/2230/12177 -f 2155/2230/12178 2156/2229/12179 2158/2231/12180 -f 1416/1499/12181 2160/2234/12182 2159/2233/12183 -f 2159/2233/12184 1417/1500/12185 1416/1499/12186 -f 1415/1498/12187 2161/2235/12188 2160/2234/12189 -f 2160/2234/12190 1416/1499/12191 1415/1498/12192 -f 2162/2236/12193 2161/2235/12194 1415/1498/12195 -f 1415/1498/12196 1414/1497/12197 2162/2236/12198 -f 2163/2237/12199 2162/2236/12200 1414/1497/12201 -f 1414/1497/12202 1413/1496/12203 2163/2237/12204 -f 2164/2238/12205 2163/2237/12206 1413/1496/12207 -f 1413/1496/12208 1427/1510/12209 2164/2238/12210 -f 1427/1510/12211 1424/1507/12212 2165/2239/12213 -f 2165/2239/12214 2164/2238/12215 1427/1510/12216 -f 2154/2597/12217 2151/2596/12218 2166/2240/12219 -f 2166/2240/12220 2167/2241/12221 2154/2597/12222 -f 2099/2329/12223 1632/1718/12224 1633/1717/12225 -f 1633/1717/12226 2140/2364/12227 2099/2329/12228 -f 2168/2375/12229 2140/2364/12230 1633/1717/12231 -f 1633/1717/12232 2021/2275/12233 2168/2375/12234 -f 2021/2275/12235 2020/2274/12236 2107/2339/12237 -f 2107/2339/12238 2168/2375/12239 2021/2275/12240 -f 2169/2376/12241 2139/2363/12242 2140/2364/12243 -f 2140/2364/12244 2168/2375/12245 2169/2376/12246 -f 2170/2377/12247 2129/2494/12248 1608/2330/12249 -f 1608/2330/12250 2139/2363/12251 2170/2377/12252 -f 2138/2361/12253 2129/2494/12254 2170/2377/12255 -f 2170/2377/12256 2171/2378/12257 2138/2361/12258 -f 2169/2376/12259 2171/2378/12260 2170/2377/12261 -f 2170/2377/12262 2139/2363/12263 2169/2376/12264 -f 2137/2362/12265 2138/2361/12266 2171/2378/12267 -f 2171/2378/12268 2169/2376/12269 2137/2362/12270 -f 2168/2375/12271 2107/2339/12272 2137/2362/12273 -f 2137/2362/12274 2169/2376/12275 2168/2375/12276 -f 2166/2240/12277 2150/2243/12278 2149/2242/12279 -f 2149/2242/12280 2164/2238/12281 2166/2240/12282 -f 2163/2237/12283 2164/2238/12284 2149/2242/12285 -f 2149/2242/12286 2148/2244/12287 2163/2237/12288 -f 2162/2236/12289 2163/2237/12290 2148/2244/12291 -f 2148/2244/12292 2147/2245/12293 2162/2236/12294 -f 2161/2235/12295 2162/2236/12296 2147/2245/12297 -f 2147/2245/12298 2146/2246/12299 2161/2235/12300 -f 2160/2234/12301 2161/2235/12302 2146/2246/12303 -f 2146/2246/12304 2145/2247/12305 2160/2234/12306 -f 2157/2232/12307 2158/2231/12308 2159/2233/12309 -f 2159/2233/12310 2160/2234/12311 2157/2232/12312 -f 2143/2249/12313 2155/2230/12314 2157/2232/12315 -f 2157/2232/12316 2144/2248/12317 2143/2249/12318 -f 2141/2250/12319 2152/2228/12320 2155/2230/12321 -f 2155/2230/12322 2143/2249/12323 2141/2250/12324 -f 2151/2225/12325 2152/2228/12326 2141/2250/12327 -f 2141/2250/12328 2142/2251/12329 2151/2225/12330 -f 2150/2243/12331 2166/2240/12332 2151/2596/12333 -f 2151/2596/12334 2142/2599/12335 2150/2243/12336 -f 1423/1506/12337 2167/2241/12338 2165/2239/12339 -f 2165/2239/12340 1424/1507/12341 1423/1506/12342 -f 1421/1504/12343 2154/2597/12344 2167/2241/12345 -f 2167/2241/12346 1423/1506/12347 1421/1504/12348 -f 1420/2594/12349 2153/2227/12350 2154/2597/12351 -f 2154/2597/12352 1421/1504/12353 1420/2594/12354 -f 2156/2229/12355 2153/2598/12356 1420/1503/12357 -f 1420/1503/12358 1419/1502/12359 2156/2229/12360 -f 2158/2231/12361 2156/2229/12362 1419/1502/12363 -f 1419/1502/12364 1418/1501/12365 2158/2231/12366 -f 1417/1500/12367 2159/2233/12368 2158/2231/12369 -f 2158/2231/12370 1418/1501/12371 1417/1500/12372 -f 2166/2240/12373 2164/2238/12374 2165/2239/12375 -f 2165/2239/12376 2167/2241/12377 2166/2240/12378 -f 2157/2232/12379 2160/2234/12380 2145/2247/12381 -f 2145/2247/12382 2144/2248/12383 2157/2232/12384 -f 1489/2528/12385 1315/1558/12386 1316/1557/12387 -f 1316/1557/12388 1309/1550/12389 1489/2528/12390 -f 1550/1633/12391 1323/1406/12392 1324/1405/12393 -f 1324/1405/12394 1545/1628/12395 1550/1633/12396 -f 1525/1609/12397 1526/1608/12398 1555/1638/12399 -f 1555/1638/12400 1529/1614/12401 1525/1609/12402 -f 1527/1610/12403 1525/2614/12404 1529/2616/12405 -f 1529/2616/12406 1530/1613/12407 1527/1610/12408 -f 1296/1378/12409 1527/1610/12410 1534/1617/12411 -f 1534/1617/12412 1293/1377/12413 1296/1378/12414 -f 1293/1377/12415 1534/1617/12416 1537/1620/12417 -f 1537/1620/12418 1292/479/12419 1293/1377/12420 -f 1292/479/12421 1537/1620/12422 1540/1623/12423 -f 1540/1623/12424 1506/1425/12425 1292/479/12426 -f 1506/1425/12427 1540/1623/12428 1543/1626/12429 -f 1543/1626/12430 1507/1589/12431 1506/1425/12432 -f 1507/1589/12433 1543/1626/12434 1324/1405/12435 -f 1324/1405/12436 1322/1381/12437 1507/1589/12438 -f 1556/1639/12439 1526/1608/12440 1523/1606/12441 -f 1523/1606/12442 1522/1605/12443 1556/1639/12444 -f 1323/1406/12445 1556/1639/12446 1522/1605/12447 -f 1522/1605/12448 1321/1403/12449 1323/1406/12450 -f 1509/1591/12451 1322/1381/12452 1319/1380/12453 -f 1319/1380/12454 1510/1593/12455 1509/1591/12456 -f 1546/1630/12457 1547/1629/12458 1575/1659/12459 -f 1575/1659/12460 2172/2256/12461 1546/1630/12462 -f 1549/1631/12463 1546/1630/12464 2172/2256/12465 -f 2172/2256/12466 2173/2257/12467 1549/1631/12468 -f 2174/2258/12469 1552/1634/12470 1549/1631/12471 -f 1549/1631/12472 2173/2257/12473 2174/2258/12474 -f 1562/1643/12475 1557/1640/12476 1552/1634/12477 -f 1552/1634/12478 2174/2258/12479 1562/1643/12480 -f 1559/2618/12481 1558/1641/12482 1557/1640/12483 -f 1557/1640/12484 1562/1643/12485 1559/2618/12486 -f 1558/2617/12487 1565/1648/12488 1531/1612/12489 -f 1531/1612/12490 1528/1611/12491 1558/2617/12492 -f 1531/1612/12493 1565/1648/12494 1568/1651/12495 -f 1568/1651/12496 1532/1615/12497 1531/1612/12498 -f 1532/1615/12499 1568/1651/12500 1571/1654/12501 -f 1571/1654/12502 1535/1618/12503 1532/1615/12504 -f 1535/1618/12505 1571/1654/12506 1574/1657/12507 -f 1574/1657/12508 1538/1621/12509 1535/1618/12510 -f 1538/1621/12511 1574/1657/12512 1547/1629/12513 -f 1547/1629/12514 1541/1624/12515 1538/1621/12516 -f 1560/1645/12517 1561/1644/12518 1591/1674/12519 -f 1591/1674/12520 1593/1675/12521 1560/1645/12522 -f 1564/1646/12523 1560/2619/12524 1593/2620/12525 -f 1593/2620/12526 1595/1677/12527 1564/1646/12528 -f 1567/1649/12529 1564/1646/12530 1595/1677/12531 -f 1595/1677/12532 1597/1679/12533 1567/1649/12534 -f 1570/1652/12535 1567/1649/12536 1597/1679/12537 -f 1597/1679/12538 1599/1681/12539 1570/1652/12540 -f 1578/1663/12541 1573/1655/12542 1570/1652/12543 -f 1570/1652/12544 1599/1681/12545 1578/1663/12546 -f 1579/1662/12547 1576/1658/12548 1573/1655/12549 -f 1573/1655/12550 1578/1663/12551 1579/1662/12552 -f 1575/1659/12553 1576/1658/12554 1583/1666/12555 -f 1583/1666/12556 2172/2256/12557 1575/1659/12558 -f 2172/2256/12559 1583/1666/12560 1586/1669/12561 -f 1586/1669/12562 2173/2257/12563 2172/2256/12564 -f 2173/2257/12565 1586/1669/12566 1589/1672/12567 -f 1589/1672/12568 2174/2258/12569 2173/2257/12570 -f 1589/1672/12571 1561/1644/12572 1562/1643/12573 -f 1562/1643/12574 2174/2258/12575 1589/1672/12576 -f 608/2569/12577 609/2573/12578 447/531/12579 -f 447/531/12580 448/530/12581 608/2569/12582 -f 609/2573/12583 611/695/12584 610/694/12585 -f 610/694/12586 447/531/12587 609/2573/12588 -f 614/700/12589 446/532/12590 447/531/12591 -f 447/531/12592 610/694/12593 614/700/12594 -f 2175/2622/12595 2176/2623/12596 2177/2626/12597 -f 2177/2626/12598 2178/2629/12599 2175/2622/12600 -f 2330/2806/12601 2331/2807/12602 2179/2646/12603 -f 2179/2646/12604 2180/2647/12605 2330/2806/12606 -f 2181/2624/12607 2179/2625/12608 2331/2808/12609 -f 2331/2808/12610 2332/2809/12611 2181/2624/12612 -f 2181/2624/12613 2332/2809/12614 2333/2810/12615 -f 2333/2810/12616 2184/2631/12617 2181/2624/12618 -f 2185/2632/12619 2183/2630/12620 2182/2628/12621 -f 2182/2628/12622 2186/2633/12623 2185/2632/12624 -f 2187/2634/12625 2188/2635/12626 2183/2630/12627 -f 2183/2630/12628 2185/2632/12629 2187/2634/12630 -f 2189/2636/12631 2190/2637/12632 2187/2634/12633 -f 2187/2634/12634 2191/2638/12635 2189/2636/12636 -f 2189/2649/12637 2192/2657/12638 2193/2659/12639 -f 2193/2659/12640 2194/2661/12641 2189/2649/12642 -f 2192/2657/12643 2195/2662/12644 2196/2663/12645 -f 2196/2663/12646 2193/2659/12647 2192/2657/12648 -s 2 -f 2195/2639/12649 2197/2640/12650 2198/2641/12651 -f 2198/2641/12652 2199/2642/12653 2195/2639/12654 -s 1 -f 2192/2643/12655 2200/2644/12656 2197/2640/12657 -f 2197/2640/12658 2195/2639/12659 2192/2643/12660 -s 2 -f 2201/2645/12661 2202/2648/12662 2198/2641/12663 -f 2198/2641/12664 2197/2640/12665 2201/2645/12666 -s 1 -f 2200/2644/12667 2203/2650/12668 2201/2645/12669 -f 2201/2645/12670 2197/2640/12671 2200/2644/12672 -s 2 -f 2196/2663/12673 2195/2662/12674 2199/2664/12675 -f 2199/2664/12676 2204/2665/12677 2196/2663/12678 -s 1 -f 2205/2666/12679 2206/2667/12680 2204/2665/12681 -f 2204/2665/12682 2199/2664/12683 2205/2666/12684 -f 2198/2641/12685 2207/2651/12686 2205/2652/12687 -f 2205/2652/12688 2199/2642/12689 2198/2641/12690 -f 2194/2661/12691 2193/2659/12692 2208/2668/12693 -f 2208/2668/12694 2209/2669/12695 2194/2661/12696 -f 2194/2661/12697 2210/2670/12698 2190/2687/12699 -f 2190/2687/12700 2189/2649/12701 2194/2661/12702 -f 2209/2669/12703 2211/2688/12704 2210/2670/12705 -f 2210/2670/12706 2194/2661/12707 2209/2669/12708 -f 2212/2690/12709 2208/2668/12710 2193/2659/12711 -f 2193/2659/12712 2196/2663/12713 2212/2690/12714 -f 2213/2691/12715 2214/2692/12716 2209/2669/12717 -f 2209/2669/12718 2208/2668/12719 2213/2691/12720 -f 2213/2691/12721 2208/2668/12722 2212/2690/12723 -f 2212/2690/12724 2215/2693/12725 2213/2691/12726 -f 2189/2636/12727 2191/2638/12728 2200/2644/12729 -f 2200/2644/12730 2192/2643/12731 2189/2636/12732 -f 2191/2638/12733 2216/2653/12734 2203/2650/12735 -f 2203/2650/12736 2200/2644/12737 2191/2638/12738 -f 2216/2653/12739 2217/2654/12740 2218/2655/12741 -f 2218/2655/12742 2203/2650/12743 2216/2653/12744 -f 2217/2654/12745 2216/2653/12746 2185/2632/12747 -f 2185/2632/12748 2186/2633/12749 2217/2654/12750 -f 2185/2632/12751 2216/2653/12752 2191/2638/12753 -f 2191/2638/12754 2187/2634/12755 2185/2632/12756 -f 2219/2656/12757 2188/2635/12758 2187/2634/12759 -f 2187/2634/12760 2190/2637/12761 2219/2656/12762 -f 2335/2812/12763 2220/2658/12764 2221/2660/12765 -f 2221/2660/12766 2334/2811/12767 2335/2812/12768 -s 2 -f 2220/2694/12769 2222/2695/12770 2223/2696/12771 -f 2223/2696/12772 2224/2697/12773 2220/2694/12774 -s 1 -f 2335/2813/12775 2336/2814/12776 2222/2695/12777 -f 2222/2695/12778 2220/2694/12779 2335/2813/12780 -f 2226/2740/12781 2227/2757/12782 2222/2695/12783 -f 2222/2695/12784 2336/2814/12785 2226/2740/12786 -f 2210/2670/12787 2211/2688/12788 2337/2815/12789 -f 2337/2815/12790 2225/2699/12791 2210/2670/12792 -f 2190/2687/12793 2210/2670/12794 2225/2699/12795 -f 2225/2699/12796 2219/2698/12797 2190/2687/12798 -s 4 -f 2227/2757/12799 2228/2759/12800 2223/2696/12801 -f 2223/2696/12802 2222/2695/12803 2227/2757/12804 -s 8 -f 2228/2759/12805 2227/2757/12806 2180/2647/12807 -f 2180/2647/12808 2229/2760/12809 2228/2759/12810 -s 2 -f 2230/2671/12811 2221/2660/12812 2220/2658/12813 -f 2220/2658/12814 2224/2672/12815 2230/2671/12816 -f 2221/2660/12817 2230/2671/12818 2231/2673/12819 -f 2231/2673/12820 2184/2631/12821 2221/2660/12822 -s 1 -f 2334/2811/12823 2221/2660/12824 2184/2631/12825 -f 2184/2631/12826 2333/2810/12827 2334/2811/12828 -f 2177/2674/12829 2186/2633/12830 2182/2628/12831 -f 2182/2628/12832 2178/2627/12833 2177/2674/12834 -f 2232/2675/12835 2186/2633/12836 2177/2674/12837 -f 2177/2674/12838 2233/2676/12839 2232/2675/12840 -f 2232/2675/12841 2234/2677/12842 2217/2654/12843 -f 2217/2654/12844 2186/2633/12845 2232/2675/12846 -f 2235/2678/12847 2236/2679/12848 2234/2677/12849 -f 2234/2677/12850 2237/2680/12851 2235/2678/12852 -f 2235/2678/12853 2238/2681/12854 2239/2682/12855 -f 2239/2682/12856 2240/2683/12857 2235/2678/12858 -f 2239/2682/12859 2238/2681/12860 2241/2684/12861 -f 2241/2684/12862 2242/2685/12863 2239/2682/12864 -s 2 -f 2239/2682/12865 2243/2686/12866 2244/2689/12867 -f 2244/2689/12868 2240/2683/12869 2239/2682/12870 -f 2243/2686/12871 2239/2682/12872 2242/2685/12873 -f 2242/2685/12874 2245/2700/12875 2243/2686/12876 -s 1 -f 2238/2681/12877 2246/2701/12878 2247/2702/12879 -f 2247/2702/12880 2241/2684/12881 2238/2681/12882 -f 2241/2684/12883 2248/2703/12884 2249/2704/12885 -f 2249/2704/12886 2242/2685/12887 2241/2684/12888 -f 2247/2702/12889 2250/2705/12890 2248/2703/12891 -f 2248/2703/12892 2241/2684/12893 2247/2702/12894 -f 2237/2680/12895 2246/2701/12896 2238/2681/12897 -f 2238/2681/12898 2235/2678/12899 2237/2680/12900 -f 2251/2706/12901 2252/2707/12902 2246/2701/12903 -f 2246/2701/12904 2237/2680/12905 2251/2706/12906 -f 2234/2677/12907 2232/2675/12908 2251/2706/12909 -f 2251/2706/12910 2237/2680/12911 2234/2677/12912 -f 2236/2679/12913 2235/2678/12914 2240/2683/12915 -f 2240/2683/12916 2253/2708/12917 2236/2679/12918 -f 2217/2654/12919 2234/2677/12920 2236/2679/12921 -f 2236/2679/12922 2218/2655/12923 2217/2654/12924 -f 2236/2679/12925 2253/2708/12926 2254/2709/12927 -f 2254/2709/12928 2218/2655/12929 2236/2679/12930 -s 2 -f 2254/2709/12931 2253/2708/12932 2255/2710/12933 -f 2255/2710/12934 2256/2711/12935 2254/2709/12936 -f 2240/2683/12937 2244/2689/12938 2255/2710/12939 -f 2255/2710/12940 2253/2708/12941 2240/2683/12942 -s 1 -f 2233/2676/12943 2257/2712/12944 2251/2706/12945 -f 2251/2706/12946 2232/2675/12947 2233/2676/12948 -f 2257/2741/12949 2233/2742/12950 2258/2743/12951 -f 2258/2743/12952 2259/2744/12953 2257/2741/12954 -s 2 -f 2251/2706/12955 2257/2712/12956 2260/2713/12957 -f 2260/2713/12958 2261/2714/12959 2251/2706/12960 -s 1 -f 2262/2745/12961 2263/2746/12962 2322/2796/12963 -f 2322/2796/12964 2324/2799/12965 2262/2745/12966 -s 2 -f 2262/2745/12967 2265/2749/12968 2266/2750/12969 -f 2266/2750/12970 2263/2746/12971 2262/2745/12972 -f 2265/2749/12973 2262/2745/12974 2267/2751/12975 -f 2267/2751/12976 2268/2752/12977 2265/2749/12978 -s 1 -f 2324/2799/12979 2325/2800/12980 2267/2751/12981 -f 2267/2751/12982 2262/2745/12983 2324/2799/12984 -f 2259/2744/12985 2264/2748/12986 2260/2747/12987 -f 2260/2747/12988 2257/2741/12989 2259/2744/12990 -f 2259/2744/12991 2270/2754/12992 2269/2753/12993 -f 2269/2753/12994 2264/2748/12995 2259/2744/12996 -f 2259/2744/12997 2271/2755/12998 2272/2756/12999 -f 2272/2756/13000 2270/2754/13001 2259/2744/13002 -f 2273/2758/13003 2271/2755/13004 2259/2744/13005 -f 2259/2744/13006 2258/2743/13007 2273/2758/13008 -f 2274/2715/13009 2323/2798/13010 2322/2797/13011 -f 2322/2797/13012 2263/2716/13013 2274/2715/13014 -s 2 -f 2274/2715/13015 2275/2717/13016 2276/2718/13017 -f 2276/2718/13018 2277/2719/13019 2274/2715/13020 -s 4 -f 2275/2717/13021 2274/2715/13022 2263/2716/13023 -f 2263/2716/13024 2266/2720/13025 2275/2717/13026 -s 1 -f 2323/2798/13027 2274/2715/13028 2277/2719/13029 -f 2277/2719/13030 2326/2801/13031 2323/2798/13032 -f 2177/2626/13033 2176/2623/13034 2258/2743/13035 -f 2258/2743/13036 2233/2742/13037 2177/2626/13038 -s 8 -f 2279/2722/13039 2280/2723/13040 2179/2625/13041 -f 2179/2625/13042 2181/2624/13043 2279/2722/13044 -s 2 -f 2184/2631/13045 2231/2673/13046 2279/2722/13047 -f 2279/2722/13048 2181/2624/13049 2184/2631/13050 -s 8 -f 2280/2761/13051 2229/2760/13052 2180/2647/13053 -f 2180/2647/13054 2179/2646/13055 2280/2761/13056 -s 1 -f 2176/2623/13057 2175/2622/13058 2337/2815/13059 -f 2337/2815/13060 2211/2688/13061 2176/2623/13062 -f 2227/2757/13063 2226/2740/13064 2330/2806/13065 -f 2330/2806/13066 2180/2647/13067 2227/2757/13068 -f 2214/2692/13069 2273/2758/13070 2258/2743/13071 -f 2258/2743/13072 2176/2623/13073 2214/2692/13074 -f 2176/2623/13075 2211/2688/13076 2209/2669/13077 -f 2209/2669/13078 2214/2692/13079 2176/2623/13080 -f 2214/2692/13081 2213/2691/13082 2281/2762/13083 -f 2281/2762/13084 2273/2758/13085 2214/2692/13086 -f 2281/2762/13087 2282/2765/13088 2271/2755/13089 -f 2271/2755/13090 2273/2758/13091 2281/2762/13092 -f 2282/2765/13093 2283/2766/13094 2284/2767/13095 -f 2284/2767/13096 2285/2768/13097 2282/2765/13098 -s 2 -f 2283/2766/13099 2286/2769/13100 2287/2772/13101 -f 2287/2772/13102 2284/2767/13103 2283/2766/13104 -s 1 -f 2286/2769/13105 2288/2763/13106 2289/2771/13107 -f 2289/2771/13108 2290/2776/13109 2286/2769/13110 -f 2288/2763/13111 2291/2764/13112 2292/2770/13113 -f 2292/2770/13114 2289/2771/13115 2288/2763/13116 -f 2293/2773/13117 2294/2774/13118 2292/2770/13119 -f 2292/2770/13120 2291/2764/13121 2293/2773/13122 -f 2294/2774/13123 2293/2773/13124 2204/2665/13125 -f 2204/2665/13126 2206/2667/13127 2294/2774/13128 -s 2 -f 2212/2690/13129 2196/2663/13130 2204/2665/13131 -f 2204/2665/13132 2293/2773/13133 2212/2690/13134 -f 2215/2693/13135 2212/2690/13136 2293/2773/13137 -f 2293/2773/13138 2291/2764/13139 2215/2693/13140 -f 2215/2693/13141 2291/2764/13142 2288/2763/13143 -f 2288/2763/13144 2295/2775/13145 2215/2693/13146 -f 2288/2763/13147 2286/2769/13148 2283/2766/13149 -f 2283/2766/13150 2295/2775/13151 2288/2763/13152 -s 1 -f 2213/2691/13153 2215/2693/13154 2295/2775/13155 -f 2295/2775/13156 2281/2762/13157 2213/2691/13158 -f 2281/2762/13159 2295/2775/13160 2283/2766/13161 -f 2283/2766/13162 2282/2765/13163 2281/2762/13164 -f 2287/2772/13165 2286/2769/13166 2290/2776/13167 -f 2290/2776/13168 2296/2777/13169 2287/2772/13170 -s 2 -f 2287/2772/13171 2297/2778/13172 2298/2779/13173 -f 2298/2779/13174 2284/2767/13175 2287/2772/13176 -f 2298/2779/13177 2297/2778/13178 2299/2780/13179 -f 2299/2780/13180 2249/2781/13181 2298/2779/13182 -s 1 -f 2298/2779/13183 2300/2782/13184 2285/2768/13185 -f 2285/2768/13186 2284/2767/13187 2298/2779/13188 -f 2298/2779/13189 2249/2781/13190 2248/2783/13191 -f 2248/2783/13192 2300/2782/13193 2298/2779/13194 -f 2300/2782/13195 2301/2784/13196 2272/2756/13197 -f 2272/2756/13198 2285/2768/13199 2300/2782/13200 -f 2301/2784/13201 2300/2782/13202 2248/2783/13203 -f 2248/2783/13204 2250/2785/13205 2301/2784/13206 -f 2270/2754/13207 2272/2756/13208 2301/2784/13209 -f 2301/2784/13210 2302/2786/13211 2270/2754/13212 -f 2250/2785/13213 2303/2787/13214 2302/2786/13215 -f 2302/2786/13216 2301/2784/13217 2250/2785/13218 -f 2271/2755/13219 2282/2765/13220 2285/2768/13221 -f 2285/2768/13222 2272/2756/13223 2271/2755/13224 -s 2 -f 2242/2685/13225 2249/2704/13226 2299/2724/13227 -f 2299/2724/13228 2245/2700/13229 2242/2685/13230 -s 1 -f 2304/2725/13231 2245/2700/13232 2299/2724/13233 -f 2299/2724/13234 2305/2726/13235 2304/2725/13236 -f 2306/2727/13237 2243/2686/13238 2245/2700/13239 -f 2245/2700/13240 2304/2725/13241 2306/2727/13242 -f 2244/2689/13243 2243/2686/13244 2306/2727/13245 -f 2306/2727/13246 2307/2728/13247 2244/2689/13248 -f 2299/2780/13249 2297/2778/13250 2308/2788/13251 -f 2308/2788/13252 2305/2789/13253 2299/2780/13254 -f 2287/2772/13255 2296/2777/13256 2308/2788/13257 -f 2308/2788/13258 2297/2778/13259 2287/2772/13260 -f 2254/2709/13261 2201/2645/13262 2203/2650/13263 -f 2203/2650/13264 2218/2655/13265 2254/2709/13266 -s 2 -f 2254/2709/13267 2256/2711/13268 2202/2648/13269 -f 2202/2648/13270 2201/2645/13271 2254/2709/13272 -s 1 -f 2261/2714/13273 2278/2721/13274 2252/2707/13275 -f 2252/2707/13276 2251/2706/13277 2261/2714/13278 -f 2309/2729/13279 2326/2801/13280 2277/2719/13281 -f 2277/2719/13282 2310/2730/13283 2309/2729/13284 -f 2278/2721/13285 2327/2802/13286 2311/2731/13287 -f 2311/2731/13288 2252/2707/13289 2278/2721/13290 -f 2247/2702/13291 2246/2701/13292 2252/2707/13293 -f 2252/2707/13294 2311/2731/13295 2247/2702/13296 -f 2303/2732/13297 2250/2705/13298 2247/2702/13299 -f 2247/2702/13300 2311/2731/13301 2303/2732/13302 -f 2312/2733/13303 2303/2732/13304 2311/2731/13305 -f 2311/2731/13306 2327/2802/13307 2312/2733/13308 -f 2328/2803/13309 2313/2791/13310 2314/2792/13311 -f 2314/2792/13312 2329/2805/13313 2328/2803/13314 -s 4 -f 2316/2794/13315 2317/2795/13316 2314/2792/13317 -f 2314/2792/13318 2313/2791/13319 2316/2794/13320 -f 2318/2734/13321 2316/2735/13322 2313/2736/13323 -f 2313/2736/13324 2310/2730/13325 2318/2734/13326 -f 2276/2718/13327 2318/2734/13328 2310/2730/13329 -f 2310/2730/13330 2277/2719/13331 2276/2718/13332 -s 1 -f 2328/2804/13333 2309/2729/13334 2310/2730/13335 -f 2310/2730/13336 2313/2736/13337 2328/2804/13338 -s 8 -f 2314/2792/13339 2317/2795/13340 2268/2752/13341 -f 2268/2752/13342 2267/2751/13343 2314/2792/13344 -s 1 -f 2325/2800/13345 2329/2805/13346 2314/2792/13347 -f 2314/2792/13348 2267/2751/13349 2325/2800/13350 -f 2302/2786/13351 2303/2787/13352 2312/2790/13353 -f 2312/2790/13354 2315/2793/13355 2302/2786/13356 -f 2315/2793/13357 2269/2753/13358 2270/2754/13359 -f 2270/2754/13360 2302/2786/13361 2315/2793/13362 -f 2319/2737/13363 2255/2710/13364 2244/2689/13365 -f 2244/2689/13366 2307/2728/13367 2319/2737/13368 -f 2320/2738/13369 2256/2711/13370 2255/2710/13371 -f 2255/2710/13372 2319/2737/13373 2320/2738/13374 -f 2256/2711/13375 2320/2738/13376 2321/2739/13377 -f 2321/2739/13378 2202/2648/13379 2256/2711/13380 -f 2321/2739/13381 2207/2651/13382 2198/2641/13383 -f 2198/2641/13384 2202/2648/13385 2321/2739/13386 -f 2260/2713/13387 2322/2797/13388 2323/2798/13389 -f 2323/2798/13390 2261/2714/13391 2260/2713/13392 -f 2322/2796/13393 2260/2747/13394 2264/2748/13395 -f 2264/2748/13396 2324/2799/13397 2322/2796/13398 -f 2324/2799/13399 2264/2748/13400 2269/2753/13401 -f 2269/2753/13402 2325/2800/13403 2324/2799/13404 -f 2326/2801/13405 2278/2721/13406 2261/2714/13407 -f 2261/2714/13408 2323/2798/13409 2326/2801/13410 -f 2309/2729/13411 2327/2802/13412 2278/2721/13413 -f 2278/2721/13414 2326/2801/13415 2309/2729/13416 -f 2327/2802/13417 2309/2729/13418 2328/2804/13419 -f 2328/2804/13420 2312/2733/13421 2327/2802/13422 -f 2329/2805/13423 2315/2793/13424 2312/2790/13425 -f 2312/2790/13426 2328/2803/13427 2329/2805/13428 -f 2325/2800/13429 2269/2753/13430 2315/2793/13431 -f 2315/2793/13432 2329/2805/13433 2325/2800/13434 -f 2178/2629/13435 2331/2807/13436 2330/2806/13437 -f 2330/2806/13438 2175/2622/13439 2178/2629/13440 -f 2331/2808/13441 2178/2627/13442 2182/2628/13443 -f 2182/2628/13444 2332/2809/13445 2331/2808/13446 -f 2332/2809/13447 2182/2628/13448 2183/2630/13449 -f 2183/2630/13450 2333/2810/13451 2332/2809/13452 -f 2188/2635/13453 2334/2811/13454 2333/2810/13455 -f 2333/2810/13456 2183/2630/13457 2188/2635/13458 -f 2219/2656/13459 2335/2812/13460 2334/2811/13461 -f 2334/2811/13462 2188/2635/13463 2219/2656/13464 -f 2335/2813/13465 2219/2698/13466 2225/2699/13467 -f 2225/2699/13468 2336/2814/13469 2335/2813/13470 -f 2336/2814/13471 2225/2699/13472 2337/2815/13473 -f 2337/2815/13474 2226/2740/13475 2336/2814/13476 -f 2175/2622/13477 2330/2806/13478 2226/2740/13479 -f 2226/2740/13480 2337/2815/13481 2175/2622/13482 -f 2340/2818/13483 2341/2819/13484 2338/2816/13485 -f 2338/2816/13486 2339/2817/13487 2340/2818/13488 -f 2426/2820/13489 2427/2821/13490 2344/2822/13491 -f 2344/2822/13492 2338/2816/13493 2426/2820/13494 -f 2346/2825/13495 2347/2826/13496 2448/2823/13497 -f 2448/2823/13498 2450/2824/13499 2346/2825/13500 -f 2451/2827/13501 2349/2828/13502 2346/2825/13503 -f 2346/2825/13504 2450/2824/13505 2451/2827/13506 -f 2428/2830/13507 2429/2831/13508 2348/2832/13509 -f 2348/2832/13510 2345/2829/13511 2428/2830/13512 -f 2351/2833/13513 2350/2834/13514 2341/2819/13515 -f 2341/2819/13516 2340/2818/13517 2351/2833/13518 -f 2352/2835/13519 2353/2836/13520 2350/2834/13521 -f 2350/2834/13522 2351/2833/13523 2352/2835/13524 -f 2350/2834/13525 2353/2836/13526 2430/2837/13527 -f 2430/2837/13528 2429/2831/13529 2350/2834/13530 -f 2354/2838/13531 2430/2837/13532 2431/2839/13533 -f 2431/2839/13534 2356/2840/13535 2354/2838/13536 -f 2357/2842/13537 2349/2828/13538 2451/2827/13539 -f 2451/2827/13540 2452/2841/13541 2357/2842/13542 -f 2358/2844/13543 2357/2842/13544 2452/2841/13545 -f 2452/2841/13546 2453/2843/13547 2358/2844/13548 -f 2432/2846/13549 2431/2839/13550 2355/2847/13551 -f 2355/2847/13552 2359/2845/13553 2432/2846/13554 -f 2362/2849/13555 2363/2850/13556 2359/2845/13557 -f 2359/2845/13558 2361/2848/13559 2362/2849/13560 -f 2361/2848/13561 2359/2845/13562 2355/2847/13563 -f 2355/2847/13564 2364/2851/13565 2361/2848/13566 -f 2365/2852/13567 2360/2853/13568 2432/2846/13569 -f 2432/2846/13570 2433/2854/13571 2365/2852/13572 -f 2355/2847/13573 2353/2836/13574 2352/2835/13575 -f 2352/2835/13576 2364/2851/13577 2355/2847/13578 -f 2345/2829/13579 2342/2855/13580 2426/2820/13581 -f 2426/2820/13582 2428/2830/13583 2345/2829/13584 -f 2366/2856/13585 2343/2857/13586 2448/2823/13587 -f 2448/2823/13588 2347/2826/13589 2366/2856/13590 -f 2368/2859/13591 2343/2857/13592 2366/2856/13593 -f 2366/2856/13594 2367/2858/13595 2368/2859/13596 -f 2370/2861/13597 2368/2859/13598 2367/2858/13599 -f 2367/2858/13600 2369/2860/13601 2370/2861/13602 -f 2371/2862/13603 2372/2863/13604 2370/2861/13605 -f 2370/2861/13606 2369/2860/13607 2371/2862/13608 -f 2434/2865/13609 2435/2866/13610 2456/2867/13611 -f 2456/2867/13612 2457/2864/13613 2434/2865/13614 -f 2458/2868/13615 2436/2869/13616 2434/2865/13617 -f 2434/2865/13618 2457/2864/13619 2458/2868/13620 -f 2459/2870/13621 2437/2871/13622 2436/2869/13623 -f 2436/2869/13624 2458/2868/13625 2459/2870/13626 -f 2379/2874/13627 2380/2875/13628 2378/2872/13629 -f 2378/2872/13630 2376/2873/13631 2379/2874/13632 -f 2371/2862/13633 2379/2874/13634 2376/2873/13635 -f 2376/2873/13636 2372/2863/13637 2371/2862/13638 -f 2377/2876/13639 2437/2871/13640 2438/2877/13641 -f 2438/2877/13642 2381/2878/13643 2377/2876/13644 -f 2382/2880/13645 2383/2881/13646 2375/2879/13647 -f 2375/2879/13648 2377/2876/13649 2382/2880/13650 -f 2375/2879/13651 2383/2881/13652 2384/2882/13653 -f 2384/2882/13654 2373/2883/13655 2375/2879/13656 -f 2384/2882/13657 2385/2885/13658 2374/2884/13659 -f 2374/2884/13660 2373/2883/13661 2384/2882/13662 -f 2386/2886/13663 2344/2822/13664 2374/2884/13665 -f 2374/2884/13666 2385/2885/13667 2386/2886/13668 -f 2344/2822/13669 2386/2886/13670 2339/2817/13671 -f 2339/2817/13672 2338/2816/13673 2344/2822/13674 -f 2449/2887/13675 2456/2867/13676 2435/2866/13677 -f 2435/2866/13678 2427/2821/13679 2449/2887/13680 -f 2454/2888/13681 2387/2889/13682 2358/2844/13683 -f 2358/2844/13684 2453/2843/13685 2454/2888/13686 -f 2388/2891/13687 2387/2889/13688 2454/2888/13689 -f 2454/2888/13690 2455/2890/13691 2388/2891/13692 -f 2390/2893/13693 2388/2953/13694 2455/2952/13695 -f 2455/2952/13696 2461/2892/13697 2390/2893/13698 -f 2392/2895/13699 2390/2893/13700 2461/2892/13701 -f 2461/2892/13702 2462/2894/13703 2392/2895/13704 -f 2392/2895/13705 2462/2894/13706 2463/2896/13707 -f 2463/2896/13708 2394/2897/13709 2392/2895/13710 -f 2394/2897/13711 2463/2896/13712 2464/2898/13713 -f 2464/2898/13714 2396/2899/13715 2394/2897/13716 -f 2396/2899/13717 2464/2898/13718 2465/2900/13719 -f 2465/2900/13720 2398/2901/13721 2396/2899/13722 -f 2400/2903/13723 2398/2901/13724 2465/2900/13725 -f 2465/2900/13726 2466/2902/13727 2400/2903/13728 -f 2402/2905/13729 2439/2906/13730 2440/2907/13731 -f 2440/2907/13732 2401/2904/13733 2402/2905/13734 -f 2403/2908/13735 2404/2909/13736 2402/2905/13737 -f 2402/2905/13738 2401/2904/13739 2403/2908/13740 -f 2405/2910/13741 2441/2911/13742 2439/2906/13743 -f 2439/2906/13744 2402/2905/13745 2405/2910/13746 -f 2405/2910/13747 2402/2905/13748 2404/2909/13749 -f 2404/2909/13750 2407/2912/13751 2405/2910/13752 -f 2409/2914/13753 2403/2908/13754 2401/2904/13755 -f 2401/2904/13756 2408/2913/13757 2409/2914/13758 -f 2442/2916/13759 2440/2907/13760 2397/2917/13761 -f 2397/2917/13762 2395/2915/13763 2442/2916/13764 -f 2467/2918/13765 2410/2919/13766 2400/2903/13767 -f 2400/2903/13768 2466/2902/13769 2467/2918/13770 -f 2412/2921/13771 2410/2919/13772 2467/2918/13773 -f 2467/2918/13774 2468/2920/13775 2412/2921/13776 -f 2413/2922/13777 2414/2923/13778 2412/2921/13779 -f 2412/2921/13780 2468/2920/13781 2413/2922/13782 -f 2416/2925/13783 2443/2926/13784 2444/2927/13785 -f 2444/2927/13786 2415/2924/13787 2416/2925/13788 -f 2406/2929/13789 2441/2911/13790 2444/2927/13791 -f 2444/2927/13792 2411/2928/13793 2406/2929/13794 -f 2417/2930/13795 2408/2913/13796 2442/2916/13797 -f 2442/2916/13798 2445/2931/13799 2417/2930/13800 -f 2445/2931/13801 2446/2932/13802 2418/2933/13803 -f 2418/2933/13804 2417/2930/13805 2445/2931/13806 -f 2420/2935/13807 2417/2930/13808 2418/2933/13809 -f 2418/2933/13810 2419/2934/13811 2420/2935/13812 -f 2422/2937/13813 2419/2934/13814 2418/2933/13815 -f 2418/2933/13816 2421/2936/13817 2422/2937/13818 -f 2421/2936/13819 2418/2933/13820 2446/2932/13821 -f 2446/2932/13822 2447/2938/13823 2421/2936/13824 -f 2363/2949/13825 2362/2948/13826 2422/2937/13827 -f 2422/2937/13828 2421/2936/13829 2363/2949/13830 -f 2433/2951/13831 2447/2938/13832 2389/2939/13833 -f 2389/2939/13834 2365/2950/13835 2433/2951/13836 -f 2409/2914/13837 2408/2913/13838 2417/2930/13839 -f 2417/2930/13840 2420/2935/13841 2409/2914/13842 -f 2405/2910/13843 2407/2912/13844 2423/2940/13845 -f 2423/2940/13846 2415/2924/13847 2405/2910/13848 -f 2423/2940/13849 2424/2941/13850 2416/2925/13851 -f 2416/2925/13852 2415/2924/13853 2423/2940/13854 -f 2425/2942/13855 2381/2957/13856 2416/2925/13857 -f 2416/2925/13858 2424/2941/13859 2425/2942/13860 -f 2377/2876/13861 2381/2878/13862 2425/2958/13863 -f 2425/2958/13864 2382/2880/13865 2377/2876/13866 -f 2381/2957/13867 2438/2956/13868 2443/2926/13869 -f 2443/2926/13870 2416/2925/13871 2381/2957/13872 -f 2378/2954/13873 2380/2955/13874 2414/2923/13875 -f 2414/2923/13876 2413/2922/13877 2378/2954/13878 -f 2342/2855/13879 2449/2887/13880 2427/2821/13881 -f 2427/2821/13882 2426/2820/13883 2342/2855/13884 -f 2341/2819/13885 2350/2834/13886 2429/2831/13887 -f 2429/2831/13888 2428/2830/13889 2341/2819/13890 -f 2430/2837/13891 2354/2838/13892 2348/2832/13893 -f 2348/2832/13894 2429/2831/13895 2430/2837/13896 -f 2353/2836/13897 2355/2847/13898 2431/2839/13899 -f 2431/2839/13900 2430/2837/13901 2353/2836/13902 -f 2360/2853/13903 2356/2840/13904 2431/2839/13905 -f 2431/2839/13906 2432/2846/13907 2360/2853/13908 -f 2359/2845/13909 2363/2850/13910 2433/2854/13911 -f 2433/2854/13912 2432/2846/13913 2359/2845/13914 -f 2338/2816/13915 2341/2819/13916 2428/2830/13917 -f 2428/2830/13918 2426/2820/13919 2338/2816/13920 -f 2373/2883/13921 2374/2884/13922 2435/2866/13923 -f 2435/2866/13924 2434/2865/13925 2373/2883/13926 -f 2436/2869/13927 2375/2879/13928 2373/2883/13929 -f 2373/2883/13930 2434/2865/13931 2436/2869/13932 -f 2437/2871/13933 2377/2876/13934 2375/2879/13935 -f 2375/2879/13936 2436/2869/13937 2437/2871/13938 -f 2437/2871/13939 2459/2870/13940 2460/2943/13941 -f 2460/2943/13942 2438/2877/13943 2437/2871/13944 -f 2374/2884/13945 2344/2822/13946 2427/2821/13947 -f 2427/2821/13948 2435/2866/13949 2374/2884/13950 -f 2399/2944/13951 2397/2917/13952 2440/2907/13953 -f 2440/2907/13954 2439/2906/13955 2399/2944/13956 -f 2441/2911/13957 2406/2929/13958 2399/2944/13959 -f 2399/2944/13960 2439/2906/13961 2441/2911/13962 -f 2442/2916/13963 2408/2913/13964 2401/2904/13965 -f 2401/2904/13966 2440/2907/13967 2442/2916/13968 -f 2443/2926/13969 2469/2945/13970 2411/2928/13971 -f 2411/2928/13972 2444/2927/13973 2443/2926/13974 -f 2441/2911/13975 2405/2910/13976 2415/2924/13977 -f 2415/2924/13978 2444/2927/13979 2441/2911/13980 -f 2395/2915/13981 2393/2946/13982 2445/2931/13983 -f 2445/2931/13984 2442/2916/13985 2395/2915/13986 -f 2393/2946/13987 2391/2947/13988 2446/2932/13989 -f 2446/2932/13990 2445/2931/13991 2393/2946/13992 -f 2391/2947/13993 2389/2939/13994 2447/2938/13995 -f 2447/2938/13996 2446/2932/13997 2391/2947/13998 -f 2363/2949/13999 2421/2936/14000 2447/2938/14001 -f 2447/2938/14002 2433/2951/14003 2363/2949/14004 -f 2438/2956/14005 2460/2959/14006 2469/2945/14007 -f 2469/2945/14008 2443/2926/14009 2438/2956/14010 -f 2342/2855/14011 2448/2823/14012 2343/2857/14013 -f 2343/2857/14014 2449/2887/14015 2342/2855/14016 -f 2448/2823/14017 2342/2855/14018 2345/2829/14019 -f 2345/2829/14020 2450/2824/14021 2448/2823/14022 -f 2450/2824/14023 2345/2829/14024 2348/2832/14025 -f 2348/2832/14026 2451/2827/14027 2450/2824/14028 -f 2354/2838/14029 2452/2841/14030 2451/2827/14031 -f 2451/2827/14032 2348/2832/14033 2354/2838/14034 -f 2356/2840/14035 2453/2843/14036 2452/2841/14037 -f 2452/2841/14038 2354/2838/14039 2356/2840/14040 -f 2360/2853/14041 2454/2888/14042 2453/2843/14043 -f 2453/2843/14044 2356/2840/14045 2360/2853/14046 -f 2365/2852/14047 2455/2890/14048 2454/2888/14049 -f 2454/2888/14050 2360/2853/14051 2365/2852/14052 -f 2368/2859/14053 2456/2867/14054 2449/2887/14055 -f 2449/2887/14056 2343/2857/14057 2368/2859/14058 -f 2370/2861/14059 2457/2864/14060 2456/2867/14061 -f 2456/2867/14062 2368/2859/14063 2370/2861/14064 -f 2372/2863/14065 2458/2868/14066 2457/2864/14067 -f 2457/2864/14068 2370/2861/14069 2372/2863/14070 -f 2458/2868/14071 2372/2863/14072 2376/2873/14073 -f 2376/2873/14074 2459/2870/14075 2458/2868/14076 -f 2378/2872/14077 2460/2943/14078 2459/2870/14079 -f 2459/2870/14080 2376/2873/14081 2378/2872/14082 -f 2455/2952/14083 2365/2950/14084 2389/2939/14085 -f 2389/2939/14086 2461/2892/14087 2455/2952/14088 -f 2461/2892/14089 2389/2939/14090 2391/2947/14091 -f 2391/2947/14092 2462/2894/14093 2461/2892/14094 -f 2462/2894/14095 2391/2947/14096 2393/2946/14097 -f 2393/2946/14098 2463/2896/14099 2462/2894/14100 -f 2463/2896/14101 2393/2946/14102 2395/2915/14103 -f 2395/2915/14104 2464/2898/14105 2463/2896/14106 -f 2464/2898/14107 2395/2915/14108 2397/2917/14109 -f 2397/2917/14110 2465/2900/14111 2464/2898/14112 -f 2465/2900/14113 2397/2917/14114 2399/2944/14115 -f 2399/2944/14116 2466/2902/14117 2465/2900/14118 -f 2406/2929/14119 2467/2918/14120 2466/2902/14121 -f 2466/2902/14122 2399/2944/14123 2406/2929/14124 -f 2467/2918/14125 2406/2929/14126 2411/2928/14127 -f 2411/2928/14128 2468/2920/14129 2467/2918/14130 -f 2468/2920/14131 2411/2928/14132 2469/2945/14133 -f 2469/2945/14134 2413/2922/14135 2468/2920/14136 -f 2460/2959/14137 2378/2954/14138 2413/2922/14139 -f 2413/2922/14140 2469/2945/14141 2460/2959/14142 -f 2486/2962/14143 2487/2963/14144 2524/2960/14145 -f 2524/2960/14146 2532/2961/14147 2486/2962/14148 -f 2471/2965/14149 2524/2960/14150 2487/2963/14151 -f 2487/2963/14152 2479/2964/14153 2471/2965/14154 -f 2472/2967/14155 2471/2965/14156 2479/2964/14157 -f 2479/2964/14158 2480/2966/14159 2472/2967/14160 -f 2473/2969/14161 2472/2967/14162 2480/2966/14163 -f 2480/2966/14164 2481/2968/14165 2473/2969/14166 -f 2474/2971/14167 2473/3024/14168 2481/3023/14169 -f 2481/3023/14170 2482/2970/14171 2474/2971/14172 -f 2475/2973/14173 2474/2971/14174 2482/2970/14175 -f 2482/2970/14176 2483/2972/14177 2475/2973/14178 -f 2476/2975/14179 2475/2973/14180 2483/2972/14181 -f 2483/2972/14182 2484/2974/14183 2476/2975/14184 -f 2477/2977/14185 2476/2975/14186 2484/2974/14187 -f 2484/2974/14188 2485/2976/14189 2477/2977/14190 -f 2532/2961/14191 2477/2977/14192 2485/2976/14193 -f 2485/2976/14194 2486/2962/14195 2532/2961/14196 -f 2495/2978/14197 2494/2979/14198 2479/2964/14199 -f 2479/2964/14200 2487/2963/14201 2495/2978/14202 -f 2480/2966/14203 2479/2964/14204 2494/2979/14205 -f 2494/2979/14206 2493/2980/14207 2480/2966/14208 -f 2481/2968/14209 2480/2966/14210 2493/2980/14211 -f 2493/2980/14212 2492/2981/14213 2481/2968/14214 -f 2482/2970/14215 2481/3023/14216 2492/3025/14217 -f 2492/3025/14218 2491/2982/14219 2482/2970/14220 -f 2483/2972/14221 2482/2970/14222 2491/2982/14223 -f 2491/2982/14224 2490/2983/14225 2483/2972/14226 -f 2484/2974/14227 2483/2972/14228 2490/2983/14229 -f 2490/2983/14230 2489/2984/14231 2484/2974/14232 -f 2485/2976/14233 2484/2974/14234 2489/2984/14235 -f 2489/2984/14236 2488/2985/14237 2485/2976/14238 -f 2486/2962/14239 2485/2976/14240 2488/2985/14241 -f 2488/2985/14242 2496/2986/14243 2486/2962/14244 -f 2487/2963/14245 2486/2962/14246 2496/2986/14247 -f 2496/2986/14248 2495/2978/14249 2487/2963/14250 -f 2478/2989/14251 2470/2990/14252 2497/2987/14253 -f 2497/2987/14254 2505/2988/14255 2478/2989/14256 -f 2470/2990/14257 2525/2992/14258 2498/2991/14259 -f 2498/2991/14260 2497/2987/14261 2470/2990/14262 -f 2525/2992/14263 2526/2994/14264 2499/2993/14265 -f 2499/2993/14266 2498/2991/14267 2525/2992/14268 -f 2526/2994/14269 2527/2996/14270 2500/2995/14271 -f 2500/2995/14272 2499/2993/14273 2526/2994/14274 -f 2527/3027/14275 2528/2998/14276 2501/2997/14277 -f 2501/2997/14278 2500/3026/14279 2527/3027/14280 -f 2528/2998/14281 2529/3000/14282 2502/2999/14283 -f 2502/2999/14284 2501/2997/14285 2528/2998/14286 -f 2529/3000/14287 2530/3002/14288 2503/3001/14289 -f 2503/3001/14290 2502/2999/14291 2529/3000/14292 -f 2530/3002/14293 2531/3004/14294 2504/3003/14295 -f 2504/3003/14296 2503/3001/14297 2530/3002/14298 -f 2531/3004/14299 2478/2989/14300 2505/2988/14301 -f 2505/2988/14302 2504/3003/14303 2531/3004/14304 -f 2521/3007/14305 2522/3008/14306 2513/3005/14307 -f 2513/3005/14308 2512/3006/14309 2521/3007/14310 -f 2520/3010/14311 2521/3007/14312 2512/3006/14313 -f 2512/3006/14314 2511/3009/14315 2520/3010/14316 -f 2519/3012/14317 2520/3010/14318 2511/3009/14319 -f 2511/3009/14320 2510/3011/14321 2519/3012/14322 -f 2518/3014/14323 2519/3029/14324 2510/3028/14325 -f 2510/3028/14326 2509/3013/14327 2518/3014/14328 -f 2517/3016/14329 2518/3014/14330 2509/3013/14331 -f 2509/3013/14332 2508/3015/14333 2517/3016/14334 -f 2516/3018/14335 2517/3016/14336 2508/3015/14337 -f 2508/3015/14338 2507/3017/14339 2516/3018/14340 -f 2515/3020/14341 2516/3018/14342 2507/3017/14343 -f 2507/3017/14344 2506/3019/14345 2515/3020/14346 -f 2523/3022/14347 2515/3020/14348 2506/3019/14349 -f 2506/3019/14350 2514/3021/14351 2523/3022/14352 -f 2522/3008/14353 2523/3022/14354 2514/3021/14355 -f 2514/3021/14356 2513/3005/14357 2522/3008/14358 -f 2495/2978/14359 2522/3008/14360 2521/3007/14361 -f 2521/3007/14362 2494/2979/14363 2495/2978/14364 -f 2494/2979/14365 2521/3007/14366 2520/3010/14367 -f 2520/3010/14368 2493/2980/14369 2494/2979/14370 -f 2493/2980/14371 2520/3010/14372 2519/3012/14373 -f 2519/3012/14374 2492/2981/14375 2493/2980/14376 -f 2492/3025/14377 2519/3029/14378 2518/3014/14379 -f 2518/3014/14380 2491/2982/14381 2492/3025/14382 -f 2491/2982/14383 2518/3014/14384 2517/3016/14385 -f 2517/3016/14386 2490/2983/14387 2491/2982/14388 -f 2490/2983/14389 2517/3016/14390 2516/3018/14391 -f 2516/3018/14392 2489/2984/14393 2490/2983/14394 -f 2489/2984/14395 2516/3018/14396 2515/3020/14397 -f 2515/3020/14398 2488/2985/14399 2489/2984/14400 -f 2488/2985/14401 2515/3020/14402 2523/3022/14403 -f 2523/3022/14404 2496/2986/14405 2488/2985/14406 -f 2496/2986/14407 2523/3022/14408 2522/3008/14409 -f 2522/3008/14410 2495/2978/14411 2496/2986/14412 -f 2524/2960/14413 2470/2990/14414 2478/2989/14415 -f 2478/2989/14416 2532/2961/14417 2524/2960/14418 -f 2471/2965/14419 2525/2992/14420 2470/2990/14421 -f 2470/2990/14422 2524/2960/14423 2471/2965/14424 -f 2472/2967/14425 2526/2994/14426 2525/2992/14427 -f 2525/2992/14428 2471/2965/14429 2472/2967/14430 -f 2473/2969/14431 2527/2996/14432 2526/2994/14433 -f 2526/2994/14434 2472/2967/14435 2473/2969/14436 -f 2474/2971/14437 2528/2998/14438 2527/3027/14439 -f 2527/3027/14440 2473/3024/14441 2474/2971/14442 -f 2475/2973/14443 2529/3000/14444 2528/2998/14445 -f 2528/2998/14446 2474/2971/14447 2475/2973/14448 -f 2476/2975/14449 2530/3002/14450 2529/3000/14451 -f 2529/3000/14452 2475/2973/14453 2476/2975/14454 -f 2477/2977/14455 2531/3004/14456 2530/3002/14457 -f 2530/3002/14458 2476/2975/14459 2477/2977/14460 -f 2532/2961/14461 2478/2989/14462 2531/3004/14463 -f 2531/3004/14464 2477/2977/14465 2532/2961/14466 -f 2535/3035/14467 2536/3060/14468 2533/3032/14469 -f 2533/3032/14470 2534/3033/14471 2535/3035/14472 -f 2536/3060/14473 2538/3062/14474 2537/3061/14475 -f 2537/3061/14476 2533/3032/14477 2536/3060/14478 -f 2537/3034/14479 2540/3036/14480 2539/3030/14481 -f 2539/3030/14482 2533/3031/14483 2537/3034/14484 -f 2542/3038/14485 2543/3039/14486 2539/3030/14487 -f 2539/3030/14488 2541/3037/14489 2542/3038/14490 -f 2539/3030/14491 2540/3036/14492 2544/3040/14493 -f 2544/3040/14494 2541/3037/14495 2539/3030/14496 -f 2544/3040/14497 2540/3036/14498 2545/3041/14499 -f 2545/3041/14500 2546/3042/14501 2544/3040/14502 -f 2548/3044/14503 2546/3042/14504 2545/3041/14505 -f 2545/3041/14506 2547/3043/14507 2548/3044/14508 -f 2547/3048/14509 2550/3049/14510 2549/3046/14511 -f 2549/3046/14512 2548/3047/14513 2547/3048/14514 -f 2549/3046/14515 2550/3049/14516 2551/3050/14517 -f 2551/3050/14518 2552/3051/14519 2549/3046/14520 -f 2554/3053/14521 2552/3051/14522 2551/3050/14523 -f 2551/3050/14524 2553/3052/14525 2554/3053/14526 -f 2555/3054/14527 2556/3055/14528 2554/3053/14529 -f 2554/3053/14530 2553/3052/14531 2555/3054/14532 -f 2557/3056/14533 2558/3057/14534 2555/3054/14535 -f 2555/3054/14536 2553/3052/14537 2557/3056/14538 -f 2559/3068/14539 2557/3056/14540 2553/3052/14541 -f 2553/3052/14542 2551/3050/14543 2559/3068/14544 -f 2559/3068/14545 2551/3050/14546 2550/3049/14547 -f 2550/3049/14548 2560/3166/14549 2559/3068/14550 -f 2550/3049/14551 2547/3048/14552 2561/3175/14553 -f 2561/3175/14554 2560/3166/14555 2550/3049/14556 -f 2562/3045/14557 2561/3058/14558 2547/3043/14559 -f 2547/3043/14560 2545/3041/14561 2562/3045/14562 -f 2564/3065/14563 2561/3066/14564 2562/3063/14565 -f 2562/3063/14566 2563/3064/14567 2564/3065/14568 -f 2566/3069/14569 2564/3065/14570 2563/3064/14571 -f 2563/3064/14572 2565/3067/14573 2566/3069/14574 -f 2567/3070/14575 2568/3079/14576 2566/3069/14577 -f 2566/3069/14578 2565/3067/14579 2567/3070/14580 -f 2565/3067/14581 2570/3081/14582 2569/3080/14583 -f 2569/3080/14584 2567/3070/14585 2565/3067/14586 -f 2538/3062/14587 2570/3081/14588 2565/3067/14589 -f 2565/3067/14590 2563/3064/14591 2538/3062/14592 -f 2564/3065/14593 2572/3188/14594 2571/3082/14595 -f 2571/3082/14596 2561/3066/14597 2564/3065/14598 -f 2566/3069/14599 2573/3189/14600 2572/3188/14601 -f 2572/3188/14602 2564/3065/14603 2566/3069/14604 -f 2538/3062/14605 2563/3064/14606 2562/3063/14607 -f 2562/3063/14608 2537/3061/14609 2538/3062/14610 -f 2562/3045/14611 2545/3041/14612 2540/3036/14613 -f 2540/3036/14614 2537/3034/14615 2562/3045/14616 -f 2574/3059/14617 2575/3071/14618 2543/3039/14619 -f 2543/3039/14620 2542/3038/14621 2574/3059/14622 -f 2539/3030/14623 2543/3039/14624 2534/3072/14625 -f 2534/3072/14626 2533/3031/14627 2539/3030/14628 -f 2576/3073/14629 2534/3072/14630 2543/3039/14631 -f 2543/3039/14632 2575/3071/14633 2576/3073/14634 -f 2575/3071/14635 2578/3075/14636 2577/3074/14637 -f 2577/3074/14638 2576/3073/14639 2575/3071/14640 -f 2579/3076/14641 2580/3077/14642 2576/3073/14643 -f 2576/3073/14644 2577/3074/14645 2579/3076/14646 -f 2576/3073/14647 2580/3077/14648 2581/3078/14649 -f 2581/3078/14650 2534/3072/14651 2576/3073/14652 -f 2581/3190/14653 2582/3191/14654 2535/3035/14655 -f 2535/3035/14656 2534/3033/14657 2581/3190/14658 -f 2584/3193/14659 2536/3060/14660 2535/3035/14661 -f 2535/3035/14662 2583/3192/14663 2584/3193/14664 -f 2585/3194/14665 2583/3192/14666 2535/3035/14667 -f 2535/3035/14668 2582/3191/14669 2585/3194/14670 -f 2586/3083/14671 2587/3084/14672 2579/3076/14673 -f 2579/3076/14674 2577/3074/14675 2586/3083/14676 -f 2577/3074/14677 2578/3075/14678 2588/3085/14679 -f 2588/3085/14680 2586/3083/14681 2577/3074/14682 -f 2589/3086/14683 2590/3087/14684 2588/3085/14685 -f 2588/3085/14686 2578/3075/14687 2589/3086/14688 -f 2588/3085/14689 2592/3089/14690 2591/3088/14691 -f 2591/3088/14692 2586/3083/14693 2588/3085/14694 -f 2588/3085/14695 2590/3087/14696 2593/3090/14697 -f 2593/3090/14698 2592/3089/14699 2588/3085/14700 -f 2587/3084/14701 2586/3083/14702 2591/3088/14703 -f 2591/3088/14704 2594/3091/14705 2587/3084/14706 -f 2594/3091/14707 2591/3088/14708 2595/3237/14709 -f 2595/3237/14710 2596/3238/14711 2594/3091/14712 -f 2578/3075/14713 2575/3071/14714 2574/3059/14715 -f 2574/3059/14716 2589/3086/14717 2578/3075/14718 -f 2599/3098/14719 2600/3099/14720 2597/3095/14721 -f 2597/3095/14722 2598/3096/14723 2599/3098/14724 -f 2602/3101/14725 2599/3098/14726 2598/3096/14727 -f 2598/3096/14728 2601/3100/14729 2602/3101/14730 -f 2604/3103/14731 2602/3101/14732 2601/3100/14733 -f 2601/3100/14734 2603/3102/14735 2604/3103/14736 -f 2603/3102/14737 2606/3105/14738 2605/3104/14739 -f 2605/3104/14740 2604/3221/14741 2603/3102/14742 -f 2605/3104/14743 2606/3105/14744 2607/3106/14745 -f 2607/3106/14746 2608/3107/14747 2605/3104/14748 -f 2608/3223/14749 2607/3106/14750 2609/3108/14751 -f 2609/3108/14752 2610/3109/14753 2608/3223/14754 -f 2612/3111/14755 2613/3112/14756 2609/3108/14757 -f 2609/3108/14758 2611/3110/14759 2612/3111/14760 -f 2606/3105/14761 2603/3102/14762 2614/3113/14763 -f 2614/3113/14764 2611/3110/14765 2606/3105/14766 -f 2614/3113/14767 2615/3114/14768 2612/3111/14769 -f 2612/3111/14770 2611/3110/14771 2614/3113/14772 -f 2617/3116/14773 2613/3112/14774 2612/3111/14775 -f 2612/3111/14776 2616/3115/14777 2617/3116/14778 -f 2618/3117/14779 2619/3118/14780 2617/3116/14781 -f 2617/3116/14782 2616/3115/14783 2618/3117/14784 -f 2621/3120/14785 2618/3117/14786 2616/3115/14787 -f 2616/3115/14788 2620/3119/14789 2621/3120/14790 -f 2612/3111/14791 2615/3114/14792 2620/3119/14793 -f 2620/3119/14794 2616/3115/14795 2612/3111/14796 -f 2610/3109/14797 2609/3108/14798 2613/3112/14799 -f 2613/3112/14800 2622/3121/14801 2610/3109/14802 -f 2623/3122/14803 2622/3227/14804 2613/3112/14805 -f 2613/3112/14806 2617/3116/14807 2623/3122/14808 -f 2615/3114/14809 2614/3113/14810 2624/3123/14811 -f 2624/3123/14812 2625/3124/14813 2615/3114/14814 -f 2627/3128/14815 2625/3124/14816 2624/3123/14817 -f 2624/3123/14818 2626/3127/14819 2627/3128/14820 -f 2601/3100/14821 2598/3096/14822 2626/3127/14823 -f 2626/3127/14824 2624/3123/14825 2601/3100/14826 -f 2629/3167/14827 2627/3128/14828 2626/3127/14829 -f 2626/3127/14830 2628/3164/14831 2629/3167/14832 -f 2628/3164/14833 2626/3127/14834 2598/3096/14835 -f 2598/3096/14836 2597/3095/14837 2628/3164/14838 -f 2630/3183/14839 2620/3119/14840 2615/3114/14841 -f 2615/3114/14842 2625/3124/14843 2630/3183/14844 -f 2631/3184/14845 2630/3183/14846 2625/3124/14847 -f 2625/3124/14848 2627/3128/14849 2631/3184/14850 -f 2614/3113/14851 2603/3102/14852 2601/3100/14853 -f 2601/3100/14854 2624/3123/14855 2614/3113/14856 -f 2606/3105/14857 2611/3110/14858 2609/3108/14859 -f 2609/3108/14860 2607/3106/14861 2606/3105/14862 -f 2632/3125/14863 2633/3126/14864 2597/3094/14865 -f 2597/3094/14866 2600/3097/14867 2632/3125/14868 -f 2633/3126/14869 2632/3125/14870 2634/3129/14871 -f 2634/3129/14872 2635/3130/14873 2633/3126/14874 -f 2634/3129/14875 2637/3132/14876 2636/3131/14877 -f 2636/3131/14878 2635/3130/14879 2634/3129/14880 -f 2639/3134/14881 2640/3135/14882 2636/3131/14883 -f 2636/3131/14884 2638/3133/14885 2639/3134/14886 -f 2641/3136/14887 2642/3137/14888 2639/3134/14889 -f 2639/3134/14890 2638/3133/14891 2641/3136/14892 -f 2643/3140/14893 2644/3141/14894 2640/3135/14895 -f 2640/3135/14896 2639/3134/14897 2643/3140/14898 -f 2646/3143/14899 2640/3135/14900 2644/3141/14901 -f 2644/3141/14902 2645/3142/14903 2646/3143/14904 -f 2645/3142/14905 2648/3145/14906 2647/3144/14907 -f 2647/3144/14908 2646/3143/14909 2645/3142/14910 -f 2650/3147/14911 2647/3144/14912 2648/3145/14913 -f 2648/3145/14914 2649/3146/14915 2650/3147/14916 -f 2650/3147/14917 2649/3146/14918 2651/3148/14919 -f 2651/3148/14920 2652/3149/14921 2650/3147/14922 -f 2635/3130/14923 2646/3143/14924 2647/3144/14925 -f 2647/3144/14926 2633/3126/14927 2635/3130/14928 -f 2647/3144/14929 2650/3147/14930 2597/3094/14931 -f 2597/3094/14932 2633/3126/14933 2647/3144/14934 -f 2640/3135/14935 2646/3143/14936 2635/3130/14937 -f 2635/3130/14938 2636/3131/14939 2640/3135/14940 -f 2639/3134/14941 2642/3137/14942 2653/3163/14943 -f 2653/3163/14944 2643/3140/14945 2639/3134/14946 -f 2654/3138/14947 2655/3139/14948 2653/3092/14949 -f 2653/3092/14950 2642/3093/14951 2654/3138/14952 -f 2642/3093/14953 2641/3151/14954 2656/3150/14955 -f 2656/3150/14956 2654/3138/14957 2642/3093/14958 -f 2658/3153/14959 2659/3154/14960 2657/3152/14961 -f 2657/3152/14962 2656/3150/14963 2658/3153/14964 -f 2656/3150/14965 2641/3151/14966 2660/3155/14967 -f 2660/3155/14968 2658/3153/14969 2656/3150/14970 -f 2657/3152/14971 2661/3156/14972 2654/3138/14973 -f 2654/3138/14974 2656/3150/14975 2657/3152/14976 -s 2 -f 2662/3157/14977 2653/3092/14978 2655/3139/14979 -s 4 -f 2662/3157/14980 2663/3158/14981 2664/3159/14982 -s 1 -f 2662/3157/14983 2661/3156/14984 2665/3160/14985 -f 2665/3160/14986 2663/3158/14987 2662/3157/14988 -f 2661/3156/14989 2662/3157/14990 2655/3139/14991 -f 2655/3139/14992 2654/3138/14993 2661/3156/14994 -f 2660/3168/14995 2641/3136/14996 2638/3133/14997 -f 2638/3133/14998 2666/3165/14999 2660/3168/15000 -f 2666/3165/15001 2638/3133/15002 2636/3131/15003 -f 2636/3131/15004 2637/3132/15005 2666/3165/15006 -f 2650/3147/15007 2652/3149/15008 2628/3169/15009 -f 2628/3169/15010 2597/3094/15011 2650/3147/15012 -f 2669/3187/15013 2670/3212/15014 2667/3185/15015 -f 2667/3185/15016 2668/3186/15017 2669/3187/15018 -f 2631/3184/15019 2671/3213/15020 2668/3186/15021 -f 2668/3186/15022 2667/3185/15023 2631/3184/15024 -f 2673/3172/15025 2668/3173/15026 2671/3170/15027 -f 2671/3170/15028 2672/3171/15029 2673/3172/15030 -f 2675/3241/15031 2673/3172/15032 2672/3171/15033 -f 2672/3171/15034 2674/3174/15035 2675/3241/15036 -f 2676/3242/15037 2677/3243/15038 2674/3174/15039 -f 2674/3174/15040 2672/3171/15041 2676/3242/15042 -f 2652/3149/15043 2651/3148/15044 2677/3243/15045 -f 2677/3243/15046 2676/3242/15047 2652/3149/15048 -f 2652/3149/15049 2676/3242/15050 2629/3244/15051 -f 2629/3244/15052 2628/3169/15053 2652/3149/15054 -f 2672/3171/15055 2671/3170/15056 2629/3244/15057 -f 2629/3244/15058 2676/3242/15059 2672/3171/15060 -f 2675/3178/15061 2679/3179/15062 2678/3176/15063 -f 2678/3176/15064 2673/3177/15065 2675/3178/15066 -f 2558/3057/15067 2680/3180/15068 2678/3176/15069 -f 2678/3176/15070 2555/3054/15071 2558/3057/15072 -f 2680/3180/15073 2668/3181/15074 2673/3177/15075 -f 2673/3177/15076 2678/3176/15077 2680/3180/15078 -f 2669/3229/15079 2668/3181/15080 2680/3180/15081 -f 2680/3180/15082 2681/3182/15083 2669/3229/15084 -f 2682/3230/15085 2681/3182/15086 2680/3180/15087 -f 2680/3180/15088 2558/3057/15089 2682/3230/15090 -f 2682/3230/15091 2558/3057/15092 2557/3056/15093 -f 2557/3056/15094 2683/3231/15095 2682/3230/15096 -f 2557/3056/15097 2559/3068/15098 2684/3234/15099 -f 2684/3234/15100 2683/3231/15101 2557/3056/15102 -f 2684/3234/15103 2559/3068/15104 2560/3166/15105 -f 2560/3166/15106 2685/3235/15107 2684/3234/15108 -f 2556/3055/15109 2555/3054/15110 2678/3176/15111 -f 2678/3176/15112 2679/3179/15113 2556/3055/15114 -f 2631/3184/15115 2627/3128/15116 2629/3167/15117 -f 2629/3167/15118 2671/3213/15119 2631/3184/15120 -f 2686/3214/15121 2630/3183/15122 2631/3184/15123 -f 2631/3184/15124 2667/3185/15125 2686/3214/15126 -f 2620/3119/15127 2630/3183/15128 2686/3214/15129 -f 2686/3214/15130 2621/3120/15131 2620/3119/15132 -f 2621/3120/15133 2686/3214/15134 2687/3215/15135 -f 2687/3215/15136 2688/3216/15137 2621/3120/15138 -f 2670/3212/15139 2687/3215/15140 2686/3214/15141 -f 2686/3214/15142 2667/3185/15143 2670/3212/15144 -f 2689/3217/15145 2618/3117/15146 2621/3120/15147 -f 2621/3120/15148 2688/3232/15149 2689/3217/15150 -f 2690/3218/15151 2619/3118/15152 2618/3117/15153 -f 2618/3117/15154 2689/3217/15155 2690/3218/15156 -f 2690/3233/15157 2623/3122/15158 2617/3116/15159 -f 2617/3116/15160 2619/3118/15161 2690/3233/15162 -f 2561/3175/15163 2571/3236/15164 2685/3235/15165 -f 2685/3235/15166 2560/3166/15167 2561/3175/15168 -f 2584/3193/15169 2570/3081/15170 2538/3062/15171 -f 2538/3062/15172 2536/3060/15173 2584/3193/15174 -f 2691/3195/15175 2569/3080/15176 2570/3081/15177 -f 2570/3081/15178 2584/3193/15179 2691/3195/15180 -f 2691/3195/15181 2584/3193/15182 2583/3192/15183 -f 2583/3192/15184 2692/3196/15185 2691/3195/15186 -f 2694/3198/15187 2691/3195/15188 2692/3196/15189 -f 2692/3196/15190 2693/3197/15191 2694/3198/15192 -f 2696/3200/15193 2694/3198/15194 2693/3197/15195 -f 2693/3197/15196 2695/3199/15197 2696/3200/15198 -f 2698/3202/15199 2695/3199/15200 2693/3197/15201 -f 2693/3197/15202 2697/3201/15203 2698/3202/15204 -f 2692/3196/15205 2699/3203/15206 2697/3201/15207 -f 2697/3201/15208 2693/3197/15209 2692/3196/15210 -f 2583/3192/15211 2585/3194/15212 2699/3246/15213 -f 2699/3246/15214 2692/3196/15215 2583/3192/15216 -f 2696/3200/15217 2695/3199/15218 2698/3245/15219 -f 2698/3245/15220 2700/3204/15221 2696/3200/15222 -f 2701/3205/15223 2702/3206/15224 2696/3200/15225 -f 2696/3200/15226 2700/3204/15227 2701/3205/15228 -f 2696/3200/15229 2702/3206/15230 2703/3207/15231 -f 2703/3207/15232 2694/3198/15233 2696/3200/15234 -f 2567/3070/15235 2569/3080/15236 2703/3207/15237 -f 2703/3207/15238 2704/3208/15239 2567/3070/15240 -f 2705/3219/15241 2704/3208/15242 2703/3207/15243 -f 2703/3207/15244 2702/3206/15245 2705/3219/15246 -f 2701/3247/15247 2706/3220/15248 2705/3219/15249 -f 2705/3219/15250 2702/3206/15251 2701/3247/15252 -f 2704/3208/15253 2707/3222/15254 2568/3079/15255 -f 2568/3079/15256 2567/3070/15257 2704/3208/15258 -f 2707/3222/15259 2710/3226/15260 2708/3224/15261 -f 2708/3224/15262 2709/3225/15263 2707/3222/15264 -f 2710/3226/15265 2707/3222/15266 2704/3208/15267 -f 2704/3208/15268 2705/3219/15269 2710/3226/15270 -f 2707/3222/15271 2709/3225/15272 2711/3228/15273 -f 2711/3228/15274 2568/3079/15275 2707/3222/15276 -f 2694/3198/15277 2703/3207/15278 2569/3080/15279 -f 2569/3080/15280 2691/3195/15281 2694/3198/15282 -f 2712/3161/15283 2665/3160/15284 2661/3156/15285 -f 2661/3156/15286 2657/3152/15287 2712/3161/15288 -f 2595/3162/15289 2713/3209/15290 2665/3160/15291 -f 2665/3160/15292 2712/3161/15293 2595/3162/15294 -f 2591/3088/15295 2592/3089/15296 2713/3239/15297 -f 2713/3239/15298 2595/3237/15299 2591/3088/15300 -f 2664/3159/15301 2663/3158/15302 2665/3160/15303 -f 2665/3160/15304 2713/3209/15305 2664/3159/15306 -f 2592/3089/15307 2593/3090/15308 2664/3240/15309 -f 2664/3240/15310 2713/3239/15311 2592/3089/15312 -f 2714/3210/15313 2596/3211/15314 2595/3162/15315 -f 2595/3162/15316 2712/3161/15317 2714/3210/15318 -f 2659/3154/15319 2714/3210/15320 2712/3161/15321 -f 2712/3161/15322 2657/3152/15323 2659/3154/15324 -f 2573/3189/15325 2566/3069/15326 2568/3079/15327 -f 2568/3079/15328 2711/3249/15329 2573/3189/15330 -f 2708/3248/15331 2710/3226/15332 2705/3219/15333 -f 2705/3219/15334 2706/3220/15335 2708/3248/15336 -f 2716/3252/15337 2715/3253/15338 2718/3250/15339 -f 2718/3250/15340 2717/3251/15341 2716/3252/15342 -f 2719/3255/15343 2717/3251/15344 2718/3250/15345 -f 2718/3250/15346 2720/3254/15347 2719/3255/15348 -f 2721/3256/15349 2720/3257/15350 2718/3250/15351 -f 2718/3250/15352 2715/3253/15353 2721/3256/15354 -f 2722/3258/15355 2716/3252/15356 2717/3251/15357 -f 2717/3251/15358 2719/3255/15359 2722/3258/15360 -f 2723/3260/15361 2719/3255/15362 2720/3254/15363 -f 2720/3254/15364 2721/3259/15365 2723/3260/15366 -f 2719/3255/15367 2723/3260/15368 2724/3261/15369 -f 2724/3261/15370 2722/3258/15371 2719/3255/15372 -f 2727/3262/15373 2726/3263/15374 2725/3264/15375 -f 2723/3260/15376 2721/3259/15377 2727/3265/15378 -f 2727/3265/15379 2728/3266/15380 2723/3260/15381 -f 2727/3265/15382 2729/3267/15383 2728/3266/15384 -f 2731/3270/15385 2730/3271/15386 2733/3268/15387 -f 2733/3268/15388 2732/3269/15389 2731/3270/15390 -f 2735/3274/15391 2734/3275/15392 2737/3272/15393 -f 2737/3272/15394 2736/3273/15395 2735/3274/15396 -f 2738/3276/15397 2736/3273/15398 2737/3272/15399 -f 2737/3272/15400 2733/3268/15401 2738/3276/15402 -f 2739/3277/15403 2733/3268/15404 2737/3272/15405 -f 2737/3272/15406 2734/3275/15407 2739/3277/15408 -f 2741/3280/15409 2740/3281/15410 2743/3278/15411 -f 2743/3278/15412 2742/3279/15413 2741/3280/15414 -f 2745/3284/15415 2744/3285/15416 2747/3282/15417 -f 2747/3282/15418 2746/3283/15419 2745/3284/15420 -f 2746/3283/15421 2747/3282/15422 2749/3286/15423 -f 2749/3286/15424 2748/3287/15425 2746/3283/15426 -f 2747/3282/15427 2750/3288/15428 2749/3286/15429 -f 2752/3291/15430 2751/3292/15431 2754/3289/15432 -f 2754/3289/15433 2753/3290/15434 2752/3291/15435 -f 2754/3289/15436 2755/3293/15437 2753/3290/15438 -f 2754/3289/15439 2751/3292/15440 2756/3294/15441 -f 2753/3290/15442 2755/3293/15443 2758/3295/15444 -f 2758/3295/15445 2757/3296/15446 2753/3290/15447 -f 2752/3291/15448 2753/3290/15449 2757/3296/15450 -f 2752/3291/15451 2757/3296/15452 2760/3297/15453 -f 2760/3297/15454 2759/3298/15455 2752/3291/15456 -f 2761/3301/15457 2745/3284/15458 2763/3299/15459 -f 2763/3299/15460 2762/3300/15461 2761/3301/15462 -f 2763/3299/15463 2764/3304/15464 2766/3302/15465 -f 2766/3302/15466 2765/3303/15467 2763/3299/15468 -f 2763/3299/15469 2765/3303/15470 2767/3305/15471 -f 2767/3305/15472 2762/3300/15473 2763/3299/15474 -f 2769/3308/15475 2768/3309/15476 2771/3306/15477 -f 2771/3306/15478 2770/3307/15479 2769/3308/15480 -f 2773/3310/15481 2772/3311/15482 2768/3309/15483 -f 2768/3309/15484 2769/3308/15485 2773/3310/15486 -f 2774/3313/15487 2769/3308/15488 2770/3307/15489 -f 2770/3307/15490 2775/3312/15491 2774/3313/15492 -f 2776/3315/15493 2772/3311/15494 2773/3310/15495 -f 2773/3310/15496 2777/3314/15497 2776/3315/15498 -f 2778/3316/15499 2758/3295/15500 2767/3305/15501 -f 2767/3305/15502 2765/3303/15503 2778/3316/15504 -f 2770/3307/15505 2771/3306/15506 2780/3317/15507 -f 2780/3317/15508 2779/3318/15509 2770/3307/15510 -f 2782/3321/15511 2781/3322/15512 2784/3319/15513 -f 2784/3319/15514 2783/3320/15515 2782/3321/15516 -f 2783/3320/15517 2784/3319/15518 2786/3323/15519 -f 2786/3323/15520 2785/3324/15521 2783/3320/15522 -f 2788/3327/15523 2787/3328/15524 2790/3325/15525 -f 2790/3325/15526 2789/3326/15527 2788/3327/15528 -f 2789/3326/15529 2790/3325/15530 2791/3329/15531 -f 2793/3331/15532 2792/3332/15533 2789/3326/15534 -f 2789/3326/15535 2794/3330/15536 2793/3331/15537 -f 2795/3333/15538 2794/3330/15539 2789/3326/15540 -f 2789/3326/15541 2791/3329/15542 2795/3333/15543 -f 2770/3307/15544 2796/3335/15545 2797/3334/15546 -f 2797/3334/15547 2775/3312/15548 2770/3307/15549 -f 2777/3314/15550 2798/3338/15551 2800/3336/15552 -f 2800/3336/15553 2799/3337/15554 2777/3314/15555 -f 2802/3339/15556 2801/3340/15557 2800/3336/15558 -f 2800/3336/15559 2798/3338/15560 2802/3339/15561 -f 2804/3341/15562 2803/3342/15563 2800/3336/15564 -f 2800/3336/15565 2801/3340/15566 2804/3341/15567 -f 2777/3314/15568 2773/3310/15569 2805/3343/15570 -f 2805/3343/15571 2798/3338/15572 2777/3314/15573 -f 2805/3343/15574 2773/3310/15575 2774/3313/15576 -f 2774/3313/15577 2806/3344/15578 2805/3343/15579 -f 2805/3343/15580 2806/3344/15581 2807/3345/15582 -f 2809/3346/15583 2808/3347/15584 2805/3343/15585 -f 2805/3343/15586 2807/3345/15587 2809/3346/15588 -f 2812/3348/15589 2811/3349/15590 2810/3350/15591 -f 2813/3352/15592 2794/3330/15593 2795/3333/15594 -f 2795/3333/15595 2814/3351/15596 2813/3352/15597 -f 2816/3354/15598 2815/3355/15599 2795/3333/15600 -f 2795/3333/15601 2817/3353/15602 2816/3354/15603 -f 2818/3356/15604 2814/3351/15605 2795/3333/15606 -f 2795/3333/15607 2815/3355/15608 2818/3356/15609 -f 2820/3359/15610 2819/3360/15611 2822/3357/15612 -f 2822/3357/15613 2821/3358/15614 2820/3359/15615 -f 2766/3302/15616 2821/3358/15617 2822/3357/15618 -f 2822/3357/15619 2812/3348/15620 2766/3302/15621 -f 2819/3360/15622 2823/3361/15623 2822/3357/15624 -f 2822/3357/15625 2823/3361/15626 2824/3362/15627 -f 2822/3357/15628 2824/3362/15629 2811/3349/15630 -f 2826/3365/15631 2825/3366/15632 2828/3363/15633 -f 2828/3363/15634 2827/3364/15635 2826/3365/15636 -f 2828/3363/15637 2829/3369/15638 2831/3367/15639 -f 2831/3367/15640 2830/3368/15641 2828/3363/15642 -f 2796/3335/15643 2832/3371/15644 2833/3370/15645 -f 2833/3370/15646 2797/3334/15647 2796/3335/15648 -f 2833/3370/15649 2834/3372/15650 2797/3334/15651 -f 2770/3307/15652 2779/3318/15653 2832/3371/15654 -f 2832/3371/15655 2796/3335/15656 2770/3307/15657 -f 2836/3373/15658 2835/3374/15659 2823/3361/15660 -f 2838/3376/15661 2837/3377/15662 2839/3375/15663 -f 2839/3375/15664 2836/3373/15665 2838/3376/15666 -f 2840/3379/15667 2835/3374/15668 2839/3375/15669 -f 2839/3375/15670 2841/3378/15671 2840/3379/15672 -f 2839/3375/15673 2835/3374/15674 2836/3373/15675 -f 2843/3382/15676 2842/3383/15677 2845/3380/15678 -f 2845/3380/15679 2844/3381/15680 2843/3382/15681 -f 2847/3384/15682 2846/3385/15683 2845/3380/15684 -f 2845/3380/15685 2842/3383/15686 2847/3384/15687 -f 2848/3387/15688 2844/3381/15689 2845/3380/15690 -f 2845/3380/15691 2849/3386/15692 2848/3387/15693 -f 2851/3390/15694 2850/3391/15695 2853/3388/15696 -f 2853/3388/15697 2852/3389/15698 2851/3390/15699 -f 2852/3389/15700 2854/3392/15701 2851/3390/15702 -f 2855/3395/15703 2834/3372/15704 2857/3393/15705 -f 2857/3393/15706 2856/3394/15707 2855/3395/15708 -f 2856/3394/15709 2857/3393/15710 2859/3396/15711 -f 2859/3396/15712 2858/3397/15713 2856/3394/15714 -f 2833/3370/15715 2859/3396/15716 2857/3393/15717 -f 2857/3393/15718 2834/3372/15719 2833/3370/15720 -f 2860/3399/15721 2829/3369/15722 2861/3398/15723 -f 2861/3398/15724 2840/3379/15725 2860/3399/15726 -f 2840/3379/15727 2861/3398/15728 2862/3400/15729 -f 2862/3400/15730 2835/3374/15731 2840/3379/15732 -f 2860/3399/15733 2863/3402/15734 2864/3401/15735 -f 2864/3401/15736 2829/3369/15737 2860/3399/15738 -f 2829/3369/15739 2864/3401/15740 2865/3403/15741 -f 2865/3403/15742 2831/3367/15743 2829/3369/15744 -f 2866/3404/15745 2860/3399/15746 2840/3379/15747 -f 2840/3379/15748 2841/3378/15749 2866/3404/15750 -f 2853/3388/15751 2867/3406/15752 2868/3405/15753 -f 2868/3405/15754 2852/3389/15755 2853/3388/15756 -f 2854/3392/15757 2852/3389/15758 2868/3405/15759 -f 2868/3405/15760 2869/3407/15761 2854/3392/15762 -f 2870/3408/15763 2869/3407/15764 2868/3405/15765 -f 2868/3405/15766 2867/3406/15767 2870/3408/15768 -f 2859/3396/15769 2871/3410/15770 2872/3409/15771 -f 2872/3409/15772 2858/3397/15773 2859/3396/15774 -f 2847/3384/15775 2858/3397/15776 2872/3409/15777 -f 2872/3409/15778 2873/3411/15779 2847/3384/15780 -f 2874/3412/15781 2873/3411/15782 2872/3409/15783 -f 2872/3409/15784 2871/3410/15785 2874/3412/15786 -f 2876/3413/15787 2875/3414/15788 2870/3408/15789 -f 2870/3408/15790 2867/3406/15791 2876/3413/15792 -f 2877/3415/15793 2869/3407/15794 2870/3408/15795 -f 2870/3408/15796 2875/3414/15797 2877/3415/15798 -f 2878/3416/15799 2874/3412/15800 2871/3410/15801 -f 2871/3410/15802 2859/3396/15803 2878/3416/15804 -f 2850/3391/15805 2879/3418/15806 2880/3417/15807 -f 2880/3417/15808 2853/3388/15809 2850/3391/15810 -f 2882/3419/15811 2881/3420/15812 2853/3388/15813 -f 2853/3388/15814 2880/3417/15815 2882/3419/15816 -f 2876/3413/15817 2867/3406/15818 2853/3388/15819 -f 2853/3388/15820 2881/3420/15821 2876/3413/15822 -f 2884/3423/15823 2883/3424/15824 2886/3421/15825 -f 2886/3421/15826 2885/3422/15827 2884/3423/15828 -f 2887/3426/15829 2885/3422/15830 2886/3421/15831 -f 2886/3421/15832 2888/3425/15833 2887/3426/15834 -f 2889/3427/15835 2888/3425/15836 2886/3421/15837 -f 2886/3421/15838 2883/3424/15839 2889/3427/15840 -f 2890/3429/15841 2888/3425/15842 2889/3427/15843 -f 2889/3427/15844 2891/3428/15845 2890/3429/15846 -f 2892/3430/15847 2891/3428/15848 2889/3427/15849 -f 2889/3427/15850 2883/3424/15851 2892/3430/15852 -f 2894/3431/15853 2893/3432/15854 2876/3413/15855 -f 2876/3413/15856 2881/3420/15857 2894/3431/15858 -f 2885/3422/15859 2875/3414/15860 2876/3413/15861 -f 2876/3413/15862 2884/3423/15863 2885/3422/15864 -f 2895/3433/15865 2884/3423/15866 2876/3413/15867 -f 2876/3413/15868 2893/3432/15869 2895/3433/15870 -f 2896/3435/15871 2873/3411/15872 2874/3412/15873 -f 2874/3412/15874 2897/3434/15875 2896/3435/15876 -f 2899/3438/15877 2898/3439/15878 2901/3436/15879 -f 2901/3436/15880 2900/3437/15881 2899/3438/15882 -f 2903/3441/15883 2902/3442/15884 2901/3436/15885 -f 2901/3436/15886 2904/3440/15887 2903/3441/15888 -f 2905/3443/15889 2900/3437/15890 2901/3436/15891 -f 2901/3436/15892 2902/3442/15893 2905/3443/15894 -f 2907/3446/15895 2906/3447/15896 2909/3444/15897 -f 2909/3444/15898 2908/3445/15899 2907/3446/15900 -f 2910/3449/15901 2908/3445/15902 2909/3444/15903 -f 2909/3444/15904 2911/3448/15905 2910/3449/15906 -f 2912/3450/15907 2911/3448/15908 2909/3444/15909 -f 2909/3444/15910 2906/3447/15911 2912/3450/15912 -f 2914/3453/15913 2913/3454/15914 2916/3451/15915 -f 2916/3451/15916 2915/3452/15917 2914/3453/15918 -f 2918/3455/15919 2917/3456/15920 2916/3451/15921 -f 2916/3451/15922 2913/3454/15923 2918/3455/15924 -f 2920/3457/15925 2919/3458/15926 2916/3451/15927 -f 2916/3451/15928 2917/3456/15929 2920/3457/15930 -f 2863/3402/15931 2915/3452/15932 2916/3451/15933 -f 2916/3451/15934 2921/3459/15935 2863/3402/15936 -f 2922/3460/15937 2921/3459/15938 2916/3451/15939 -f 2916/3451/15940 2919/3458/15941 2922/3460/15942 -f 2895/3433/15943 2893/3432/15944 2923/3461/15945 -f 2923/3461/15946 2918/3455/15947 2895/3433/15948 -f 2894/3431/15949 2924/3462/15950 2923/3461/15951 -f 2923/3461/15952 2893/3432/15953 2894/3431/15954 -f 2917/3456/15955 2918/3455/15956 2923/3461/15957 -f 2923/3461/15958 2925/3463/15959 2917/3456/15960 -f 2927/3466/15961 2926/3467/15962 2929/3464/15963 -f 2929/3464/15964 2928/3465/15965 2927/3466/15966 -f 2928/3465/15967 2929/3464/15968 2931/3468/15969 -f 2931/3468/15970 2930/3469/15971 2928/3465/15972 -f 2932/3470/15973 2931/3468/15974 2929/3464/15975 -f 2929/3464/15976 2926/3467/15977 2932/3470/15978 -f 2934/3473/15979 2933/3474/15980 2936/3471/15981 -f 2936/3471/15982 2935/3472/15983 2934/3473/15984 -f 2937/3476/15985 2935/3472/15986 2936/3471/15987 -f 2936/3471/15988 2938/3475/15989 2937/3476/15990 -f 2940/3477/15991 2939/3478/15992 2936/3471/15993 -f 2936/3471/15994 2933/3474/15995 2940/3477/15996 -f 2942/3481/15997 2941/3482/15998 2943/3479/15999 -f 2943/3479/16000 2940/3480/16001 2942/3481/16002 -f 2939/3478/16003 2940/3477/16004 2943/3483/16005 -f 2943/3483/16006 2944/3484/16007 2939/3478/16008 -f 2945/3485/16009 2944/3486/16010 2943/3479/16011 -f 2943/3479/16012 2941/3482/16013 2945/3485/16014 -f 2947/3489/16015 2946/3490/16016 2949/3487/16017 -f 2949/3487/16018 2948/3488/16019 2947/3489/16020 -f 2951/3493/16021 2950/3494/16022 2949/3491/16023 -f 2949/3491/16024 2952/3492/16025 2951/3493/16026 -f 2953/3495/16027 2952/3496/16028 2949/3487/16029 -f 2949/3487/16030 2946/3490/16031 2953/3495/16032 -f 2955/3499/16033 2954/3500/16034 2957/3497/16035 -f 2957/3497/16036 2956/3498/16037 2955/3499/16038 -f 2958/3502/16039 2956/3498/16040 2957/3497/16041 -f 2957/3497/16042 2959/3501/16043 2958/3502/16044 -f 2960/3504/16045 2959/3501/16046 2957/3497/16047 -f 2957/3497/16048 2961/3503/16049 2960/3504/16050 -f 2963/3507/16051 2962/3508/16052 2965/3505/16053 -f 2965/3505/16054 2964/3506/16055 2963/3507/16056 -f 2930/3469/16057 2964/3506/16058 2965/3505/16059 -f 2965/3505/16060 2966/3509/16061 2930/3469/16062 -f 2968/3510/16063 2967/3511/16064 2965/3505/16065 -f 2965/3505/16066 2962/3508/16067 2968/3510/16068 -f 2970/3512/16069 2969/3513/16070 2965/3505/16071 -f 2965/3505/16072 2967/3511/16073 2970/3512/16074 -f 2973/3514/16075 2972/3515/16076 2971/3516/16077 -f 2975/3517/16078 2974/3518/16079 2973/3514/16080 -f 2973/3514/16081 2971/3516/16082 2975/3517/16083 -f 2977/3521/16084 2976/3522/16085 2979/3519/16086 -f 2979/3519/16087 2978/3520/16088 2977/3521/16089 -f 2981/3525/16090 2980/3526/16091 2983/3523/16092 -f 2983/3523/16093 2982/3524/16094 2981/3525/16095 -f 2946/3490/16096 2947/3489/16097 2982/3524/16098 -f 2982/3524/16099 2983/3523/16100 2946/3490/16101 -f 2985/3529/16102 2984/3530/16103 2987/3527/16104 -f 2987/3527/16105 2986/3528/16106 2985/3529/16107 -f 2988/3532/16108 2986/3528/16109 2987/3527/16110 -f 2987/3527/16111 2989/3531/16112 2988/3532/16113 -f 2991/3535/16114 2990/3536/16115 2993/3533/16116 -f 2993/3533/16117 2992/3534/16118 2991/3535/16119 -f 2995/3537/16120 2994/3538/16121 2993/3533/16122 -f 2993/3533/16123 2990/3536/16124 2995/3537/16125 -f 2996/3539/16126 2992/3534/16127 2993/3533/16128 -f 2993/3533/16129 2994/3538/16130 2996/3539/16131 -f 2998/3540/16132 2997/3541/16133 2995/3537/16134 -f 3000/3544/16135 2999/3545/16136 3002/3542/16137 -f 3002/3542/16138 3001/3543/16139 3000/3544/16140 -f 3001/3543/16141 3003/3546/16142 3000/3544/16143 -f 3005/3549/16144 3004/3550/16145 3007/3547/16146 -f 3007/3547/16147 3006/3548/16148 3005/3549/16149 -f 3008/3552/16150 3006/3548/16151 3007/3547/16152 -f 3007/3547/16153 3009/3551/16154 3008/3552/16155 -f 3010/3554/16156 3009/3551/16157 3007/3547/16158 -f 3007/3547/16159 3011/3553/16160 3010/3554/16161 -f 3013/3555/16162 3005/3549/16163 3012/3556/16164 -f 2760/3297/16165 3014/3558/16166 3015/3557/16167 -f 3015/3557/16168 2759/3298/16169 2760/3297/16170 -f 3016/3560/16171 2759/3298/16172 3015/3557/16173 -f 3015/3557/16174 3017/3559/16175 3016/3560/16176 -f 3019/3563/16177 3018/3564/16178 3021/3561/16179 -f 3021/3561/16180 3020/3562/16181 3019/3563/16182 -f 3022/3566/16183 3020/3562/16184 3021/3561/16185 -f 3021/3561/16186 3023/3565/16187 3022/3566/16188 -f 3019/3563/16189 3024/3568/16190 3025/3567/16191 -f 3025/3567/16192 3018/3564/16193 3019/3563/16194 -f 3024/3568/16195 3019/3563/16196 3027/3569/16197 -f 3027/3569/16198 3026/3570/16199 3024/3568/16200 -f 3024/3568/16201 3026/3570/16202 2832/3371/16203 -f 2832/3371/16204 2779/3318/16205 3024/3568/16206 -f 2833/3370/16207 2832/3371/16208 3026/3570/16209 -f 3026/3570/16210 3028/3571/16211 2833/3370/16212 -f 3028/3571/16213 3026/3570/16214 3027/3569/16215 -f 3027/3569/16216 3029/3572/16217 3028/3571/16218 -f 3030/3573/16219 2878/3416/16220 3028/3571/16221 -f 3028/3571/16222 3029/3572/16223 3030/3573/16224 -f 2859/3396/16225 2833/3370/16226 3028/3571/16227 -f 3028/3571/16228 2878/3416/16229 2859/3396/16230 -f 3032/3574/16231 3031/3575/16232 3030/3573/16233 -f 3030/3573/16234 3029/3572/16235 3032/3574/16236 -f 2931/3468/16237 2932/3470/16238 3030/3573/16239 -f 3030/3573/16240 3031/3575/16241 2931/3468/16242 -f 2874/3412/16243 2878/3416/16244 3030/3573/16245 -f 3030/3573/16246 2932/3470/16247 2874/3412/16248 -f 3034/3576/16249 3033/3577/16250 3031/3575/16251 -f 3031/3575/16252 3032/3574/16253 3034/3576/16254 -f 3035/3578/16255 2931/3468/16256 3031/3575/16257 -f 3031/3575/16258 3033/3577/16259 3035/3578/16260 -f 3037/3579/16261 3036/3580/16262 3035/3578/16263 -f 3035/3578/16264 3033/3577/16265 3037/3579/16266 -f 2963/3507/16267 2964/3506/16268 3035/3578/16269 -f 3035/3578/16270 3036/3580/16271 2963/3507/16272 -f 2930/3469/16273 2931/3468/16274 3035/3578/16275 -f 3035/3578/16276 2964/3506/16277 2930/3469/16278 -f 3039/3581/16279 3038/3582/16280 3036/3580/16281 -f 3036/3580/16282 3037/3579/16283 3039/3581/16284 -f 3040/3583/16285 2963/3507/16286 3036/3580/16287 -f 3036/3580/16288 3038/3582/16289 3040/3583/16290 -f 2920/3584/16291 3041/3585/16292 3040/3583/16293 -f 3040/3583/16294 3038/3582/16295 2920/3584/16296 -f 2944/3486/16297 2945/3485/16298 3040/3583/16299 -f 3040/3583/16300 3041/3585/16301 2944/3486/16302 -f 2962/3508/16303 2963/3507/16304 3040/3583/16305 -f 3040/3583/16306 2945/3485/16307 2962/3508/16308 -f 2917/3456/16309 2925/3463/16310 3041/3586/16311 -f 3041/3586/16312 2920/3457/16313 2917/3456/16314 -f 2939/3478/16315 2944/3484/16316 3041/3586/16317 -f 3041/3586/16318 2925/3463/16319 2939/3478/16320 -f 2919/3587/16321 2920/3584/16322 3038/3582/16323 -f 3038/3582/16324 3039/3581/16325 2919/3587/16326 -f 3043/3588/16327 3042/3589/16328 3039/3581/16329 -f 3039/3581/16330 3037/3579/16331 3043/3588/16332 -f 2922/3590/16333 2919/3587/16334 3039/3581/16335 -f 3039/3581/16336 3042/3589/16337 2922/3590/16338 -f 3042/3589/16339 3043/3588/16340 3045/3591/16341 -f 3045/3591/16342 3044/3592/16343 3042/3589/16344 -f 3042/3589/16345 3044/3592/16346 3046/3593/16347 -f 3046/3593/16348 2922/3590/16349 3042/3589/16350 -f 3046/3594/16351 3047/3595/16352 2921/3459/16353 -f 2921/3459/16354 2922/3460/16355 3046/3594/16356 -f 3047/3595/16357 2864/3401/16358 2863/3402/16359 -f 2863/3402/16360 2921/3459/16361 3047/3595/16362 -f 3047/3595/16363 3046/3594/16364 3049/3596/16365 -f 3049/3596/16366 3048/3597/16367 3047/3595/16368 -f 3047/3595/16369 3048/3597/16370 2865/3403/16371 -f 2865/3403/16372 2864/3401/16373 3047/3595/16374 -f 3051/3598/16375 3050/3599/16376 2831/3367/16377 -f 2831/3367/16378 2865/3403/16379 3051/3598/16380 -f 3052/3600/16381 2830/3368/16382 2831/3367/16383 -f 2831/3367/16384 3050/3599/16385 3052/3600/16386 -f 3053/3602/16387 2830/3368/16388 3052/3600/16389 -f 3052/3600/16390 3054/3601/16391 3053/3602/16392 -f 3056/3605/16393 3055/3606/16394 3058/3603/16395 -f 3058/3603/16396 3057/3604/16397 3056/3605/16398 -f 3060/3607/16399 3059/3608/16400 3058/3603/16401 -f 3058/3603/16402 3055/3606/16403 3060/3607/16404 -f 3061/3610/16405 3059/3608/16406 3060/3607/16407 -f 3060/3607/16408 3062/3609/16409 3061/3610/16410 -f 3060/3607/16411 3055/3606/16412 3064/3611/16413 -f 3064/3611/16414 3063/3612/16415 3060/3607/16416 -f 3055/3606/16417 3056/3605/16418 3065/3613/16419 -f 3065/3613/16420 3064/3611/16421 3055/3606/16422 -f 3056/3605/16423 2780/3317/16424 2771/3306/16425 -f 3063/3612/16426 3066/3614/16427 3062/3609/16428 -f 3062/3609/16429 3060/3607/16430 3063/3612/16431 -f 3067/3617/16432 3063/3612/16433 3069/3615/16434 -f 3069/3615/16435 3068/3616/16436 3067/3617/16437 -f 3070/3619/16438 3068/3616/16439 3069/3615/16440 -f 3069/3615/16441 3071/3618/16442 3070/3619/16443 -f 3073/3620/16444 3072/3621/16445 3067/3617/16446 -f 3067/3617/16447 2741/3280/16448 3073/3620/16449 -f 3066/3614/16450 3063/3612/16451 3067/3617/16452 -f 3067/3617/16453 3072/3621/16454 3066/3614/16455 -f 2740/3281/16456 2741/3280/16457 3067/3617/16458 -f 3067/3617/16459 3068/3616/16460 2740/3281/16461 -f 3075/3624/16462 3074/3625/16463 3072/3622/16464 -f 3072/3622/16465 3073/3623/16466 3075/3624/16467 -f 3076/3626/16468 3066/3627/16469 3072/3622/16470 -f 3072/3622/16471 3074/3625/16472 3076/3626/16473 -f 2751/3292/16474 2752/3291/16475 3076/3626/16476 -f 3076/3626/16477 3074/3625/16478 2751/3292/16479 -f 3076/3626/16480 2752/3291/16481 2759/3298/16482 -f 2759/3298/16483 3016/3560/16484 3076/3626/16485 -f 3076/3626/16486 3016/3560/16487 3062/3628/16488 -f 3062/3628/16489 3066/3627/16490 3076/3626/16491 -f 3078/3629/16492 3077/3630/16493 2760/3297/16494 -f 2760/3297/16495 2757/3296/16496 3078/3629/16497 -f 3077/3630/16498 3078/3629/16499 3079/3631/16500 -f 3079/3631/16501 3053/3602/16502 3077/3630/16503 -f 3054/3601/16504 3080/3632/16505 3077/3630/16506 -f 3077/3630/16507 3053/3602/16508 3054/3601/16509 -f 3014/3558/16510 2760/3297/16511 3077/3630/16512 -f 3077/3630/16513 3080/3632/16514 3014/3558/16515 -f 3079/3631/16516 2828/3363/16517 2830/3368/16518 -f 2830/3368/16519 3053/3602/16520 3079/3631/16521 -f 2778/3316/16522 3081/3633/16523 3079/3631/16524 -f 3079/3631/16525 3078/3629/16526 2778/3316/16527 -f 2827/3364/16528 2828/3363/16529 3079/3631/16530 -f 3079/3631/16531 3081/3633/16532 2827/3364/16533 -f 2765/3303/16534 2810/3350/16535 3081/3633/16536 -f 3081/3633/16537 2778/3316/16538 2765/3303/16539 -f 2811/3349/16540 2827/3364/16541 3081/3633/16542 -f 3081/3633/16543 2810/3350/16544 2811/3349/16545 -f 2758/3295/16546 2778/3316/16547 3078/3629/16548 -f 3078/3629/16549 2757/3296/16550 2758/3295/16551 -f 2756/3294/16552 2751/3292/16553 3074/3625/16554 -f 3074/3625/16555 3075/3624/16556 2756/3294/16557 -f 3082/3635/16558 2756/3294/16559 3075/3624/16560 -f 3075/3624/16561 3083/3634/16562 3082/3635/16563 -f 3084/3636/16564 3083/3634/16565 3075/3624/16566 -f 3075/3624/16567 3073/3623/16568 3084/3636/16569 -f 3084/3636/16570 3085/3637/16571 3083/3634/16572 -f 3084/3638/16573 3073/3620/16574 2741/3280/16575 -f 3082/3635/16576 3083/3634/16577 3085/3637/16578 -f 3085/3637/16579 2744/3285/16580 3082/3635/16581 -f 3086/3639/16582 2750/3288/16583 3085/3637/16584 -f 3085/3637/16585 3084/3636/16586 3086/3639/16587 -f 3087/3641/16588 2750/3288/16589 3086/3639/16590 -f 3086/3639/16591 3088/3640/16592 3087/3641/16593 -f 2742/3279/16594 3089/3643/16595 3086/3642/16596 -f 3086/3642/16597 3084/3638/16598 2742/3279/16599 -f 3090/3644/16600 3088/3645/16601 3086/3642/16602 -f 3086/3642/16603 3089/3643/16604 3090/3644/16605 -f 3090/3644/16606 3091/3646/16607 3088/3645/16608 -f 3093/3647/16609 3092/3648/16610 3090/3644/16611 -f 3090/3644/16612 3089/3643/16613 3093/3647/16614 -f 3094/3649/16615 3091/3646/16616 3090/3644/16617 -f 3090/3644/16618 3092/3648/16619 3094/3649/16620 -f 3096/3650/16621 3095/3651/16622 3094/3649/16623 -f 3094/3649/16624 3092/3648/16625 3096/3650/16626 -f 3097/3652/16627 2728/3266/16628 3094/3649/16629 -f 3094/3649/16630 3095/3651/16631 3097/3652/16632 -f 2723/3260/16633 2728/3266/16634 3097/3652/16635 -f 3097/3652/16636 2724/3261/16637 2723/3260/16638 -f 3099/3653/16639 3098/3654/16640 3097/3652/16641 -f 3097/3652/16642 3095/3651/16643 3099/3653/16644 -f 2722/3258/16645 2724/3261/16646 3097/3652/16647 -f 3097/3652/16648 3098/3654/16649 2722/3258/16650 -f 3101/3655/16651 3100/3656/16652 3098/3654/16653 -f 3098/3654/16654 3099/3653/16655 3101/3655/16656 -f 2716/3252/16657 2722/3258/16658 3098/3654/16659 -f 3098/3654/16660 3100/3656/16661 2716/3252/16662 -f 2725/3264/16663 2726/3263/16664 3100/3656/16665 -f 3100/3656/16666 3101/3655/16667 2725/3264/16668 -f 2715/3253/16669 2716/3252/16670 3100/3656/16671 -f 3100/3656/16672 2726/3263/16673 2715/3253/16674 -f 3103/3657/16675 3102/3658/16676 3101/3655/16677 -f 3101/3655/16678 3099/3653/16679 3103/3657/16680 -f 3104/3659/16681 2725/3264/16682 3101/3655/16683 -f 3101/3655/16684 3102/3658/16685 3104/3659/16686 -f 3106/3660/16687 3105/3661/16688 3104/3659/16689 -f 3104/3659/16690 3102/3658/16691 3106/3660/16692 -f 3104/3659/16693 2727/3262/16694 2725/3264/16695 -f 3107/3664/16696 2739/3277/16697 3109/3662/16698 -f 3109/3662/16699 3108/3663/16700 3107/3664/16701 -f 3109/3662/16702 3110/3666/16703 3111/3665/16704 -f 3111/3665/16705 3108/3663/16706 3109/3662/16707 -f 3109/3662/16708 3112/3668/16709 3113/3667/16710 -f 3113/3667/16711 3110/3666/16712 3109/3662/16713 -f 2734/3275/16714 3114/3669/16715 3112/3668/16716 -f 3112/3668/16717 2739/3277/16718 2734/3275/16719 -f 3114/3669/16720 3115/3670/16721 3113/3667/16722 -f 3113/3667/16723 3112/3668/16724 3114/3669/16725 -f 2749/3286/16726 3116/3671/16727 3114/3669/16728 -f 3114/3669/16729 2734/3275/16730 2749/3286/16731 -f 3116/3671/16732 3117/3672/16733 3115/3670/16734 -f 3115/3670/16735 3114/3669/16736 3116/3671/16737 -f 3118/3674/16738 3115/3670/16739 3117/3672/16740 -f 3117/3672/16741 2729/3673/16742 3118/3674/16743 -f 3116/3671/16744 3087/3641/16745 3091/3675/16746 -f 3091/3675/16747 3117/3672/16748 3116/3671/16749 -f 3116/3671/16750 2749/3286/16751 2750/3288/16752 -f 2750/3288/16753 3087/3641/16754 3116/3671/16755 -f 2733/3268/16756 2739/3277/16757 3107/3664/16758 -f 3107/3664/16759 2732/3269/16760 2733/3268/16761 -f 3106/3660/16762 3119/3677/16763 3120/3676/16764 -f 3120/3676/16765 3105/3661/16766 3106/3660/16767 -f 2730/3271/16768 2731/3270/16769 3120/3676/16770 -f 3120/3676/16771 3119/3677/16772 2730/3271/16773 -f 3122/3678/16774 3121/3679/16775 2730/3271/16776 -f 2730/3271/16777 3119/3677/16778 3122/3678/16779 -f 2738/3276/16780 2730/3271/16781 3121/3679/16782 -f 3121/3679/16783 3123/3680/16784 2738/3276/16785 -f 3124/3682/16786 2736/3273/16787 2738/3276/16788 -f 2738/3276/16789 3125/3681/16790 3124/3682/16791 -f 3126/3683/16792 3125/3681/16793 2738/3276/16794 -f 2738/3276/16795 3123/3680/16796 3126/3683/16797 -f 3127/3684/16798 3125/3681/16799 3126/3683/16800 -f 3126/3683/16801 2786/3323/16802 3127/3684/16803 -f 3129/3685/16804 3128/3686/16805 3126/3683/16806 -f 3126/3683/16807 3123/3680/16808 3129/3685/16809 -f 2785/3324/16810 2786/3323/16811 3126/3683/16812 -f 3126/3683/16813 3128/3686/16814 2785/3324/16815 -f 3129/3685/16816 3130/3688/16817 3131/3687/16818 -f 3131/3687/16819 3128/3686/16820 3129/3685/16821 -f 2799/3337/16822 2785/3324/16823 3128/3686/16824 -f 3128/3686/16825 3131/3687/16826 2799/3337/16827 -f 3132/3689/16828 2776/3315/16829 3131/3687/16830 -f 3131/3687/16831 3130/3688/16832 3132/3689/16833 -f 2776/3315/16834 2777/3314/16835 2799/3337/16836 -f 2799/3337/16837 3131/3687/16838 2776/3315/16839 -f 3121/3679/16840 3133/3690/16841 3129/3685/16842 -f 3129/3685/16843 3123/3680/16844 3121/3679/16845 -f 3133/3690/16846 3134/3691/16847 3130/3688/16848 -f 3130/3688/16849 3129/3685/16850 3133/3690/16851 -f 3122/3678/16852 3135/3692/16853 3133/3690/16854 -f 3133/3690/16855 3121/3679/16856 3122/3678/16857 -f 3135/3692/16858 3136/3693/16859 3134/3691/16860 -f 3134/3691/16861 3133/3690/16862 3135/3692/16863 -f 3137/3694/16864 3093/3647/16865 3136/3693/16866 -f 3136/3693/16867 3135/3692/16868 3137/3694/16869 -f 3138/3695/16870 3137/3694/16871 3135/3692/16872 -f 3135/3692/16873 3122/3678/16874 3138/3695/16875 -f 3096/3650/16876 3137/3694/16877 3138/3695/16878 -f 3138/3695/16879 3103/3657/16880 3096/3650/16881 -f 3119/3677/16882 3106/3660/16883 3138/3695/16884 -f 3138/3695/16885 3122/3678/16886 3119/3677/16887 -f 3102/3658/16888 3103/3657/16889 3138/3695/16890 -f 3138/3695/16891 3106/3660/16892 3102/3658/16893 -f 3092/3648/16894 3093/3647/16895 3137/3694/16896 -f 3137/3694/16897 3096/3650/16898 3092/3648/16899 -f 3140/3697/16900 3139/3698/16901 3127/3684/16902 -f 3127/3684/16903 3141/3696/16904 3140/3697/16905 -f 3124/3682/16906 3125/3681/16907 3127/3684/16908 -f 3127/3684/16909 3139/3698/16910 3124/3682/16911 -f 2787/3328/16912 2788/3327/16913 3139/3698/16914 -f 3139/3698/16915 3140/3697/16916 2787/3328/16917 -f 3142/3699/16918 3124/3682/16919 3139/3698/16920 -f 3139/3698/16921 2788/3327/16922 3142/3699/16923 -f 2789/3326/16924 2792/3332/16925 3142/3699/16926 -f 3142/3699/16927 2788/3327/16928 2789/3326/16929 -f 3144/3700/16930 3143/3701/16931 3142/3699/16932 -f 3142/3699/16933 2792/3332/16934 3144/3700/16935 -f 2736/3273/16936 3124/3682/16937 3142/3699/16938 -f 3142/3699/16939 3143/3701/16940 2736/3273/16941 -f 2748/3287/16942 2735/3274/16943 3143/3701/16944 -f 3143/3701/16945 3144/3700/16946 2748/3287/16947 -f 3143/3701/16948 2735/3274/16949 2736/3273/16950 -f 2793/3331/16951 3145/3702/16952 3144/3700/16953 -f 3144/3700/16954 2792/3332/16955 2793/3331/16956 -f 2746/3283/16957 2748/3287/16958 3144/3700/16959 -f 3144/3700/16960 3145/3702/16961 2746/3283/16962 -f 2764/3304/16963 2763/3299/16964 3145/3702/16965 -f 3145/3702/16966 2793/3331/16967 2764/3304/16968 -f 2745/3284/16969 2746/3283/16970 3145/3702/16971 -f 3145/3702/16972 2763/3299/16973 2745/3284/16974 -f 2787/3328/16975 3146/3704/16976 3147/3703/16977 -f 3147/3703/16978 2790/3325/16979 2787/3328/16980 -f 3148/3705/16981 3146/3704/16982 2787/3328/16983 -f 2787/3328/16984 3140/3697/16985 3148/3705/16986 -f 2898/3439/16987 3146/3704/16988 3148/3705/16989 -f 3148/3705/16990 2901/3436/16991 2898/3439/16992 -f 3141/3696/16993 3149/3706/16994 3148/3705/16995 -f 3148/3705/16996 3140/3697/16997 3141/3696/16998 -f 2904/3440/16999 2901/3436/17000 3148/3705/17001 -f 3148/3705/17002 3149/3706/17003 2904/3440/17004 -f 3151/3707/17005 3150/3708/17006 3149/3706/17007 -f 3149/3706/17008 3141/3696/17009 3151/3707/17010 -f 3152/3709/17011 2904/3440/17012 3149/3706/17013 -f 3149/3706/17014 3150/3708/17015 3152/3709/17016 -f 2903/3441/17017 2904/3440/17018 3152/3709/17019 -f 3152/3709/17020 2951/3493/17021 2903/3441/17022 -f 2911/3448/17023 2912/3450/17024 3152/3709/17025 -f 3152/3709/17026 3150/3708/17027 2911/3448/17028 -f 2950/3494/17029 2951/3493/17030 3152/3709/17031 -f 3152/3709/17032 2912/3450/17033 2950/3494/17034 -f 2781/3322/17035 2911/3448/17036 3150/3708/17037 -f 3150/3708/17038 3151/3707/17039 2781/3322/17040 -f 2898/3439/17041 3153/3710/17042 3147/3703/17043 -f 3147/3703/17044 3146/3704/17045 2898/3439/17046 -f 3155/3711/17047 3154/3712/17048 3147/3703/17049 -f 3147/3703/17050 3153/3710/17051 3155/3711/17052 -f 3156/3713/17053 2790/3325/17054 3147/3703/17055 -f 3147/3703/17056 3154/3712/17057 3156/3713/17058 -f 2791/3329/17059 2790/3325/17060 3156/3713/17061 -f 3156/3713/17062 3157/3714/17063 2791/3329/17064 -f 2795/3333/17065 2791/3329/17066 3157/3714/17067 -f 3157/3714/17068 2817/3353/17069 2795/3333/17070 -f 3159/3717/17071 3158/3718/17072 3161/3715/17073 -f 3161/3715/17074 3160/3716/17075 3159/3717/17076 -f 2815/3355/17077 2816/3354/17078 3161/3715/17079 -f 3161/3715/17080 3158/3718/17081 2815/3355/17082 -f 3163/3719/17083 3162/3720/17084 3158/3718/17085 -f 3158/3718/17086 3159/3717/17087 3163/3719/17088 -f 2818/3356/17089 2815/3355/17090 3158/3718/17091 -f 3158/3718/17092 3162/3720/17093 2818/3356/17094 -f 3162/3720/17095 3163/3719/17096 2851/3390/17097 -f 2851/3390/17098 2837/3377/17099 3162/3720/17100 -f 3162/3720/17101 2837/3377/17102 2838/3376/17103 -f 2838/3376/17104 2818/3356/17105 3162/3720/17106 -f 2838/3376/17107 2820/3359/17108 2814/3351/17109 -f 2814/3351/17110 2818/3356/17111 2838/3376/17112 -f 2821/3358/17113 2813/3352/17114 2814/3351/17115 -f 2814/3351/17116 2820/3359/17117 2821/3358/17118 -f 2766/3302/17119 2764/3304/17120 2813/3352/17121 -f 2813/3352/17122 2821/3358/17123 2766/3302/17124 -f 3165/3721/17125 3164/3722/17126 3159/3717/17127 -f 3159/3717/17128 3160/3716/17129 3165/3721/17130 -f 2850/3391/17131 3163/3719/17132 3159/3717/17133 -f 3159/3717/17134 3164/3722/17135 2850/3391/17136 -f 3166/3723/17137 3164/3722/17138 3165/3721/17139 -f 2879/3418/17140 2850/3391/17141 3164/3722/17142 -f 3164/3722/17143 3166/3723/17144 2879/3418/17145 -f 3168/3724/17146 3167/3725/17147 2879/3418/17148 -f 2879/3418/17149 3166/3723/17150 3168/3724/17151 -f 2879/3418/17152 3167/3725/17153 2899/3438/17154 -f 2899/3438/17155 2880/3417/17156 2879/3418/17157 -f 3153/3710/17158 2898/3439/17159 2899/3438/17160 -f 2899/3438/17161 3167/3725/17162 3153/3710/17163 -f 3155/3711/17164 3153/3710/17165 3167/3725/17166 -f 3167/3725/17167 3168/3724/17168 3155/3711/17169 -f 3095/3651/17170 3096/3650/17171 3103/3657/17172 -f 3103/3657/17173 3099/3653/17174 3095/3651/17175 -f 2742/3279/17176 3136/3693/17177 3093/3647/17178 -f 3093/3647/17179 3089/3643/17180 2742/3279/17181 -f 3087/3641/17182 3088/3640/17183 3091/3675/17184 -f 2745/3284/17185 2761/3301/17186 3082/3635/17187 -f 3082/3635/17188 2744/3285/17189 2745/3284/17190 -f 2754/3289/17191 2756/3294/17192 3082/3635/17193 -f 3082/3635/17194 2761/3301/17195 2754/3289/17196 -f 3016/3560/17197 3017/3559/17198 3061/3726/17199 -f 3061/3726/17200 3062/3628/17201 3016/3560/17202 -f 3169/3727/17203 2780/3317/17204 3056/3605/17205 -f 3056/3605/17206 3057/3604/17207 3169/3727/17208 -f 3048/3597/17209 3170/3728/17210 3051/3598/17211 -f 3051/3598/17212 2865/3403/17213 3048/3597/17214 -f 3171/3729/17215 3170/3728/17216 3048/3597/17217 -f 3048/3597/17218 3049/3596/17219 3171/3729/17220 -f 3172/3732/17221 3171/3733/17222 3049/3730/17223 -f 3049/3730/17224 3173/3731/17225 3172/3732/17226 -f 3049/3730/17227 3046/3593/17228 3044/3592/17229 -f 3044/3592/17230 3173/3731/17231 3049/3730/17232 -f 3044/3592/17233 3045/3591/17234 3174/3734/17235 -f 3174/3734/17236 3173/3731/17237 3044/3592/17238 -f 3045/3591/17239 3175/3735/17240 3022/3566/17241 -f 3022/3566/17242 3174/3734/17243 3045/3591/17244 -f 3175/3735/17245 3176/3736/17246 3020/3562/17247 -f 3020/3562/17248 3022/3566/17249 3175/3735/17250 -f 3175/3735/17251 3045/3591/17252 3043/3588/17253 -f 3043/3588/17254 3034/3576/17255 3175/3735/17256 -f 3175/3735/17257 3034/3576/17258 3032/3574/17259 -f 3032/3574/17260 3176/3736/17261 3175/3735/17262 -f 3032/3574/17263 3029/3572/17264 3027/3569/17265 -f 3027/3569/17266 3176/3736/17267 3032/3574/17268 -f 3027/3569/17269 3019/3563/17270 3020/3562/17271 -f 3020/3562/17272 3176/3736/17273 3027/3569/17274 -f 3023/3565/17275 3177/3737/17276 3174/3734/17277 -f 3174/3734/17278 3022/3566/17279 3023/3565/17280 -f 3172/3732/17281 3173/3731/17282 3174/3734/17283 -f 3174/3734/17284 3177/3737/17285 3172/3732/17286 -f 3033/3577/17287 3034/3576/17288 3043/3588/17289 -f 3043/3588/17290 3037/3579/17291 3033/3577/17292 -f 3004/3550/17293 3179/3738/17294 3178/3739/17295 -f 3182/3740/17296 3181/3741/17297 3180/3742/17298 -f 3179/3738/17299 3183/3743/17300 3180/3742/17301 -f 3180/3742/17302 3178/3739/17303 3179/3738/17304 -f 3180/3742/17305 3183/3743/17306 3182/3740/17307 -f 3185/3744/17308 3184/3745/17309 3181/3741/17310 -f 3181/3741/17311 3182/3740/17312 3185/3744/17313 -f 3181/3741/17314 3184/3745/17315 3186/3746/17316 -f 3187/3747/17317 3003/3546/17318 3186/3746/17319 -f 3186/3746/17320 3184/3745/17321 3187/3747/17322 -f 3001/3543/17323 3011/3553/17324 3186/3746/17325 -f 3186/3746/17326 3003/3546/17327 3001/3543/17328 -f 3189/3749/17329 3188/3750/17330 3187/3747/17331 -f 3187/3747/17332 3190/3748/17333 3189/3749/17334 -f 3000/3544/17335 3003/3546/17336 3187/3747/17337 -f 3187/3747/17338 3188/3750/17339 3000/3544/17340 -f 3191/3751/17341 3190/3748/17342 3187/3747/17343 -f 3187/3747/17344 3184/3745/17345 3191/3751/17346 -f 3193/3752/17347 3192/3753/17348 3188/3750/17349 -f 3188/3750/17350 3189/3749/17351 3193/3752/17352 -f 2999/3545/17353 3000/3544/17354 3188/3750/17355 -f 3188/3750/17356 3192/3753/17357 2999/3545/17358 -f 3195/3754/17359 3194/3755/17360 3192/3753/17361 -f 3192/3753/17362 3193/3752/17363 3195/3754/17364 -f 3196/3756/17365 2999/3545/17366 3192/3753/17367 -f 3192/3753/17368 3194/3755/17369 3196/3756/17370 -f 3196/3756/17371 3194/3755/17372 3198/3757/17373 -f 3198/3757/17374 3197/3758/17375 3196/3756/17376 -f 3196/3756/17377 3197/3758/17378 3200/3759/17379 -f 3200/3759/17380 3199/3760/17381 3196/3756/17382 -f 3196/3756/17383 3199/3760/17384 3002/3542/17385 -f 3002/3542/17386 2999/3545/17387 3196/3756/17388 -f 3199/3760/17389 3200/3759/17390 3202/3761/17391 -f 3202/3761/17392 3201/3762/17393 3199/3760/17394 -f 3010/3554/17395 3002/3542/17396 3199/3760/17397 -f 3199/3760/17398 3201/3762/17399 3010/3554/17400 -f 3201/3762/17401 3202/3761/17402 3204/3763/17403 -f 3204/3763/17404 3203/3764/17405 3201/3762/17406 -f 3009/3551/17407 3010/3554/17408 3201/3762/17409 -f 3201/3762/17410 3203/3764/17411 3009/3551/17412 -f 3203/3764/17413 3204/3763/17414 3206/3765/17415 -f 3206/3765/17416 3205/3766/17417 3203/3764/17418 -f 3008/3552/17419 3009/3551/17420 3203/3764/17421 -f 3203/3764/17422 3205/3766/17423 3008/3552/17424 -f 3205/3766/17425 3206/3765/17426 3208/3767/17427 -f 3208/3767/17428 3207/3768/17429 3205/3766/17430 -f 3209/3769/17431 3008/3552/17432 3205/3766/17433 -f 3205/3766/17434 3207/3768/17435 3209/3769/17436 -f 3211/3770/17437 3210/3771/17438 3209/3769/17439 -f 3209/3769/17440 3207/3768/17441 3211/3770/17442 -f 3213/3772/17443 3212/3773/17444 3209/3769/17445 -f 3209/3769/17446 3210/3771/17447 3213/3772/17448 -f 3006/3548/17449 3008/3552/17450 3209/3769/17451 -f 3209/3769/17452 3212/3773/17453 3006/3548/17454 -f 3214/3774/17455 3012/3556/17456 3212/3773/17457 -f 3212/3773/17458 3213/3772/17459 3214/3774/17460 -f 3005/3549/17461 3006/3548/17462 3212/3773/17463 -f 3212/3773/17464 3012/3556/17465 3005/3549/17466 -f 3216/3775/17467 3215/3776/17468 3213/3772/17469 -f 3213/3772/17470 3210/3771/17471 3216/3775/17472 -f 3213/3772/17473 3215/3776/17474 3214/3774/17475 -f 3218/3777/17476 3217/3778/17477 3214/3774/17478 -f 3214/3774/17479 3215/3776/17480 3218/3777/17481 -f 3216/3775/17482 3219/3779/17483 3218/3777/17484 -f 3218/3777/17485 3215/3776/17486 3216/3775/17487 -f 3220/3780/17488 2996/3539/17489 3218/3777/17490 -f 3218/3777/17491 3219/3779/17492 3220/3780/17493 -f 2994/3538/17494 3217/3778/17495 3218/3777/17496 -f 3218/3777/17497 2996/3539/17498 2994/3538/17499 -f 3222/3781/17500 3221/3782/17501 3220/3780/17502 -f 3220/3780/17503 3219/3779/17504 3222/3781/17505 -f 3224/3783/17506 3223/3784/17507 3220/3780/17508 -f 3220/3780/17509 3221/3782/17510 3224/3783/17511 -f 2992/3534/17512 2996/3539/17513 3220/3780/17514 -f 3220/3780/17515 3223/3784/17516 2992/3534/17517 -f 3226/3785/17518 3225/3786/17519 3223/3784/17520 -f 3223/3784/17521 3224/3783/17522 3226/3785/17523 -f 2991/3535/17524 2992/3534/17525 3223/3784/17526 -f 3223/3784/17527 3225/3786/17528 2991/3535/17529 -f 3228/3787/17530 3227/3788/17531 3225/3786/17532 -f 3225/3786/17533 3226/3785/17534 3228/3787/17535 -f 3229/3789/17536 2991/3535/17537 3225/3786/17538 -f 3225/3786/17539 3227/3788/17540 3229/3789/17541 -f 3193/3790/17542 3189/3791/17543 3229/3789/17544 -f 3229/3789/17545 3227/3788/17546 3193/3790/17547 -f 3190/3792/17548 3230/3793/17549 3229/3789/17550 -f 3229/3789/17551 3189/3791/17552 3190/3792/17553 -f 2990/3536/17554 2991/3535/17555 3229/3789/17556 -f 3229/3789/17557 3230/3793/17558 2990/3536/17559 -f 3191/3794/17560 2998/3540/17561 3230/3793/17562 -f 3230/3793/17563 3190/3792/17564 3191/3794/17565 -f 2995/3537/17566 2990/3536/17567 3230/3793/17568 -f 3230/3793/17569 2998/3540/17570 2995/3537/17571 -f 3195/3795/17572 3193/3790/17573 3227/3788/17574 -f 3227/3788/17575 3228/3787/17576 3195/3795/17577 -f 3228/3787/17578 3226/3785/17579 3232/3796/17580 -f 3232/3796/17581 3231/3797/17582 3228/3787/17583 -f 3228/3787/17584 3231/3797/17585 3233/3798/17586 -f 3233/3798/17587 3195/3795/17588 3228/3787/17589 -f 3233/3799/17590 3198/3757/17591 3194/3755/17592 -f 3194/3755/17593 3195/3754/17594 3233/3799/17595 -f 3235/3800/17596 3234/3801/17597 3198/3757/17598 -f 3198/3757/17599 3233/3799/17600 3235/3800/17601 -f 3236/3802/17602 3197/3758/17603 3198/3757/17604 -f 3198/3757/17605 3234/3801/17606 3236/3802/17607 -f 3236/3802/17608 3237/3803/17609 3200/3759/17610 -f 3200/3759/17611 3197/3758/17612 3236/3802/17613 -f 3238/3804/17614 3202/3761/17615 3200/3759/17616 -f 3200/3759/17617 3237/3803/17618 3238/3804/17619 -f 3239/3805/17620 3204/3763/17621 3202/3761/17622 -f 3202/3761/17623 3238/3804/17624 3239/3805/17625 -f 3240/3806/17626 3206/3765/17627 3204/3763/17628 -f 3204/3763/17629 3239/3805/17630 3240/3806/17631 -f 3241/3807/17632 3208/3767/17633 3206/3765/17634 -f 3206/3765/17635 3240/3806/17636 3241/3807/17637 -f 3243/3808/17638 3242/3809/17639 3208/3767/17640 -f 3208/3767/17641 3241/3807/17642 3243/3808/17643 -f 3208/3767/17644 3242/3809/17645 3211/3770/17646 -f 3211/3770/17647 3207/3768/17648 3208/3767/17649 -f 3245/3810/17650 3244/3811/17651 3211/3770/17652 -f 3211/3770/17653 3242/3809/17654 3245/3810/17655 -f 3244/3811/17656 3245/3810/17657 3246/3812/17658 -f 3246/3812/17659 3222/3781/17660 3244/3811/17661 -f 3219/3779/17662 3216/3775/17663 3244/3811/17664 -f 3244/3811/17665 3222/3781/17666 3219/3779/17667 -f 3210/3771/17668 3211/3770/17669 3244/3811/17670 -f 3244/3811/17671 3216/3775/17672 3210/3771/17673 -f 3246/3812/17674 3247/3813/17675 3221/3782/17676 -f 3221/3782/17677 3222/3781/17678 3246/3812/17679 -f 3248/3814/17680 3224/3783/17681 3221/3782/17682 -f 3221/3782/17683 3247/3813/17684 3248/3814/17685 -f 3232/3796/17686 3226/3785/17687 3224/3783/17688 -f 3224/3783/17689 3248/3814/17690 3232/3796/17691 -f 3250/3815/17692 3249/3816/17693 3232/3796/17694 -f 3232/3796/17695 3248/3814/17696 3250/3815/17697 -f 3251/3817/17698 3231/3797/17699 3232/3796/17700 -f 3232/3796/17701 3249/3816/17702 3251/3817/17703 -f 3252/3820/17704 2969/3513/17705 3251/3818/17706 -f 3251/3818/17707 3249/3819/17708 3252/3820/17709 -f 2970/3512/17710 3235/3821/17711 3251/3818/17712 -f 3251/3818/17713 2969/3513/17714 2970/3512/17715 -f 3233/3798/17716 3231/3797/17717 3251/3817/17718 -f 3251/3817/17719 3235/3822/17720 3233/3798/17721 -f 3253/3824/17722 2966/3509/17723 3252/3820/17724 -f 3252/3820/17725 3254/3823/17726 3253/3824/17727 -f 2965/3505/17728 2969/3513/17729 3252/3820/17730 -f 3252/3820/17731 2966/3509/17732 2965/3505/17733 -f 3250/3825/17734 3254/3823/17735 3252/3820/17736 -f 3252/3820/17737 3249/3819/17738 3250/3825/17739 -f 2927/3466/17740 2928/3465/17741 3253/3824/17742 -f 3253/3824/17743 3255/3826/17744 2927/3466/17745 -f 2930/3469/17746 2966/3509/17747 3253/3824/17748 -f 3253/3824/17749 2928/3465/17750 2930/3469/17751 -f 3256/3827/17752 3255/3826/17753 3253/3824/17754 -f 3253/3824/17755 3254/3823/17756 3256/3827/17757 -f 3257/3829/17758 3255/3826/17759 3256/3827/17760 -f 3256/3827/17761 3258/3828/17762 3257/3829/17763 -f 3250/3825/17764 3259/3830/17765 3256/3827/17766 -f 3256/3827/17767 3254/3823/17768 3250/3825/17769 -f 3260/3831/17770 3258/3828/17771 3256/3827/17772 -f 3256/3827/17773 3259/3830/17774 3260/3831/17775 -f 3261/3833/17776 3258/3828/17777 3260/3831/17778 -f 3260/3831/17779 3262/3832/17780 3261/3833/17781 -f 3247/3813/17782 3246/3812/17783 3260/3834/17784 -f 3260/3834/17785 3259/3835/17786 3247/3813/17787 -f 3245/3810/17788 3262/3836/17789 3260/3834/17790 -f 3260/3834/17791 3246/3812/17792 3245/3810/17793 -f 3264/3838/17794 3263/3839/17795 3261/3833/17796 -f 3261/3833/17797 3265/3837/17798 3264/3838/17799 -f 3257/3829/17800 3258/3828/17801 3261/3833/17802 -f 3261/3833/17803 3263/3839/17804 3257/3829/17805 -f 3243/3840/17806 3265/3837/17807 3261/3833/17808 -f 3261/3833/17809 3262/3832/17810 3243/3840/17811 -f 2907/3446/17812 3266/3841/17813 3263/3839/17814 -f 3263/3839/17815 3264/3838/17816 2907/3446/17817 -f 3267/3842/17818 3257/3829/17819 3263/3839/17820 -f 3263/3839/17821 3266/3841/17822 3267/3842/17823 -f 3269/3843/17824 3268/3844/17825 3267/3842/17826 -f 3267/3842/17827 3266/3841/17828 3269/3843/17829 -f 2926/3467/17830 2927/3466/17831 3267/3842/17832 -f 3267/3842/17833 3268/3844/17834 2926/3467/17835 -f 3255/3826/17836 3257/3829/17837 3267/3842/17838 -f 3267/3842/17839 2927/3466/17840 3255/3826/17841 -f 3271/3845/17842 3270/3846/17843 3268/3844/17844 -f 3268/3844/17845 3269/3843/17846 3271/3845/17847 -f 2897/3434/17848 2926/3467/17849 3268/3844/17850 -f 3268/3844/17851 3270/3846/17852 2897/3434/17853 -f 3273/3847/17854 3272/3848/17855 3270/3846/17856 -f 3270/3846/17857 3271/3845/17858 3273/3847/17859 -f 2896/3435/17860 2897/3434/17861 3270/3846/17862 -f 3270/3846/17863 3272/3848/17864 2896/3435/17865 -f 3275/3849/17866 3274/3850/17867 3272/3848/17868 -f 3272/3848/17869 3273/3847/17870 3275/3849/17871 -f 2846/3385/17872 2896/3435/17873 3272/3848/17874 -f 3272/3848/17875 3274/3850/17876 2846/3385/17877 -f 3277/3851/17878 3276/3852/17879 3274/3850/17880 -f 3274/3850/17881 3275/3849/17882 3277/3851/17883 -f 2845/3380/17884 2846/3385/17885 3274/3850/17886 -f 3274/3850/17887 3276/3852/17888 2845/3380/17889 -f 3279/3853/17890 3278/3854/17891 3276/3852/17892 -f 3276/3852/17893 3277/3851/17894 3279/3853/17895 -f 2849/3386/17896 2845/3380/17897 3276/3852/17898 -f 3276/3852/17899 3278/3854/17900 2849/3386/17901 -f 3277/3851/17902 3280/3856/17903 3281/3855/17904 -f 3281/3855/17905 3279/3853/17906 3277/3851/17907 -f 2803/3342/17908 2804/3341/17909 3281/3855/17910 -f 3281/3855/17911 3280/3856/17912 2803/3342/17913 -f 3275/3849/17914 3282/3857/17915 3280/3856/17916 -f 3280/3856/17917 3277/3851/17918 3275/3849/17919 -f 2782/3321/17920 2803/3342/17921 3280/3856/17922 -f 3280/3856/17923 3282/3857/17924 2782/3321/17925 -f 3273/3847/17926 3283/3858/17927 3282/3857/17928 -f 3282/3857/17929 3275/3849/17930 3273/3847/17931 -f 2781/3322/17932 2782/3321/17933 3282/3857/17934 -f 3282/3857/17935 3283/3858/17936 2781/3322/17937 -f 3271/3845/17938 2910/3449/17939 3283/3858/17940 -f 3283/3858/17941 3273/3847/17942 3271/3845/17943 -f 2910/3449/17944 2911/3448/17945 2781/3322/17946 -f 2781/3322/17947 3283/3858/17948 2910/3449/17949 -f 2908/3445/17950 2910/3449/17951 3271/3845/17952 -f 3271/3845/17953 3269/3843/17954 2908/3445/17955 -f 2907/3446/17956 2908/3445/17957 3269/3843/17958 -f 3269/3843/17959 3266/3841/17960 2907/3446/17961 -f 2906/3447/17962 2907/3446/17963 3264/3838/17964 -f 3264/3838/17965 3284/3859/17966 2906/3447/17967 -f 3285/3860/17968 3284/3859/17969 3264/3838/17970 -f 3264/3838/17971 3265/3837/17972 3285/3860/17973 -f 3243/3840/17974 3241/3861/17975 3285/3860/17976 -f 3285/3860/17977 3265/3837/17978 3243/3840/17979 -f 3240/3862/17980 3286/3863/17981 3285/3860/17982 -f 3285/3860/17983 3241/3861/17984 3240/3862/17985 -f 3288/3864/17986 3287/3865/17987 2949/3491/17988 -f 2949/3491/17989 2950/3494/17990 3288/3864/17991 -f 3288/3864/17992 2906/3447/17993 3284/3859/17994 -f 3289/3866/17995 3287/3865/17996 3288/3864/17997 -f 3288/3864/17998 3286/3863/17999 3289/3866/18000 -f 3290/3868/18001 3287/3865/18002 3289/3866/18003 -f 3289/3866/18004 3291/3867/18005 3290/3868/18006 -f 3240/3862/18007 3239/3869/18008 3289/3866/18009 -f 3289/3866/18010 3286/3863/18011 3240/3862/18012 -f 3238/3870/18013 3291/3867/18014 3289/3866/18015 -f 3289/3866/18016 3239/3869/18017 3238/3870/18018 -f 3290/3868/18019 2972/3873/18020 3292/3871/18021 -f 3292/3871/18022 2948/3872/18023 3290/3868/18024 -f 3290/3868/18025 2948/3872/18026 2949/3491/18027 -f 2949/3491/18028 3287/3865/18029 3290/3868/18030 -f 3293/3874/18031 2972/3873/18032 3290/3868/18033 -f 3290/3868/18034 3291/3867/18035 3293/3874/18036 -f 3292/3876/18037 2972/3515/18038 2973/3514/18039 -f 2973/3514/18040 3294/3875/18041 3292/3876/18042 -f 3296/3879/18043 3295/3880/18044 3292/3877/18045 -f 3292/3877/18046 3294/3878/18047 3296/3879/18048 -f 2947/3489/18049 2948/3488/18050 3292/3877/18051 -f 3292/3877/18052 3295/3880/18053 2947/3489/18054 -f 3298/3881/18055 3297/3882/18056 3296/3879/18057 -f 3296/3879/18058 3294/3878/18059 3298/3881/18060 -f 3300/3883/18061 3299/3884/18062 3296/3879/18063 -f 3296/3879/18064 3297/3882/18065 3300/3883/18066 -f 3301/3885/18067 3295/3880/18068 3296/3879/18069 -f 3296/3879/18070 3299/3884/18071 3301/3885/18072 -f 2985/3529/18073 2986/3528/18074 3299/3886/18075 -f 3299/3886/18076 3300/3887/18077 2985/3529/18078 -f 2988/3532/18079 3301/3888/18080 3299/3886/18081 -f 3299/3886/18082 2986/3528/18083 2988/3532/18084 -f 3303/3889/18085 3302/3890/18086 3300/3883/18087 -f 3300/3883/18088 3297/3882/18089 3303/3889/18090 -f 3304/3892/18091 2985/3529/18092 3300/3887/18093 -f 3300/3887/18094 3302/3891/18095 3304/3892/18096 -f 3306/3893/18097 3305/3894/18098 3304/3892/18099 -f 3304/3892/18100 3302/3891/18101 3306/3893/18102 -f 3308/3895/18103 3307/3896/18104 3304/3892/18105 -f 3304/3892/18106 3305/3894/18107 3308/3895/18108 -f 2984/3530/18109 2985/3529/18110 3304/3892/18111 -f 3304/3892/18112 3307/3896/18113 2984/3530/18114 -f 3310/3897/18115 3309/3898/18116 3305/3894/18117 -f 3305/3894/18118 3306/3893/18119 3310/3897/18120 -f 3311/3899/18121 3308/3895/18122 3305/3894/18123 -f 3305/3894/18124 3309/3898/18125 3311/3899/18126 -f 2959/3501/18127 2960/3504/18128 3311/3899/18129 -f 3311/3899/18130 3309/3898/18131 2959/3501/18132 -f 3313/3902/18133 3312/3903/18134 3315/3900/18135 -f 3315/3900/18136 3314/3901/18137 3313/3902/18138 -f 2977/3521/18139 2978/3520/18140 3315/3900/18141 -f 3315/3900/18142 3312/3903/18143 2977/3521/18144 -f 3317/3904/18145 3316/3905/18146 3312/3903/18147 -f 3312/3903/18148 3313/3902/18149 3317/3904/18150 -f 3318/3906/18151 2977/3521/18152 3312/3903/18153 -f 3312/3903/18154 3316/3905/18155 3318/3906/18156 -f 3320/3907/18157 3319/3908/18158 3318/3906/18159 -f 3318/3906/18160 3316/3905/18161 3320/3907/18162 -f 2980/3909/18163 3321/3910/18164 3318/3906/18165 -f 3318/3906/18166 3319/3908/18167 2980/3909/18168 -f 2976/3522/18169 2977/3521/18170 3318/3906/18171 -f 3318/3906/18172 3321/3910/18173 2976/3522/18174 -f 2981/3911/18175 3322/3912/18176 3321/3910/18177 -f 3321/3910/18178 2980/3909/18179 2981/3911/18180 -f 3323/3913/18181 2976/3522/18182 3321/3910/18183 -f 3321/3910/18184 3322/3912/18185 3323/3913/18186 -f 3319/3916/18187 3320/3917/18188 3325/3914/18189 -f 3325/3914/18190 3324/3915/18191 3319/3916/18192 -f 3324/3915/18193 2983/3523/18194 2980/3526/18195 -f 2980/3526/18196 3319/3916/18197 3324/3915/18198 -f 3326/3918/18199 2953/3495/18200 3324/3915/18201 -f 3324/3915/18202 3325/3914/18203 3326/3918/18204 -f 2946/3490/18205 2983/3523/18206 3324/3915/18207 -f 3324/3915/18208 2953/3495/18209 2946/3490/18210 -f 3328/3919/18211 3327/3920/18212 3326/3918/18213 -f 3326/3918/18214 3325/3914/18215 3328/3919/18216 -f 3330/3921/18217 3329/3922/18218 3326/3918/18219 -f 3326/3918/18220 3327/3920/18221 3330/3921/18222 -f 2952/3496/18223 2953/3495/18224 3326/3918/18225 -f 3326/3918/18226 3329/3922/18227 2952/3496/18228 -f 2902/3442/18229 2903/3441/18230 3329/3923/18231 -f 3329/3923/18232 3330/3924/18233 2902/3442/18234 -f 2951/3493/18235 2952/3492/18236 3329/3923/18237 -f 3329/3923/18238 2903/3441/18239 2951/3493/18240 -f 3332/3925/18241 3331/3926/18242 3330/3921/18243 -f 3330/3921/18244 3327/3920/18245 3332/3925/18246 -f 2905/3443/18247 2902/3442/18248 3330/3924/18249 -f 3330/3924/18250 3331/3927/18251 2905/3443/18252 -f 3334/3929/18253 3333/3930/18254 3331/3927/18255 -f 3331/3927/18256 3332/3928/18257 3334/3929/18258 -f 3335/3931/18259 2905/3443/18260 3331/3927/18261 -f 3331/3927/18262 3333/3930/18263 3335/3931/18264 -f 2924/3462/18265 2894/3431/18266 3335/3931/18267 -f 3335/3931/18268 3333/3930/18269 2924/3462/18270 -f 2881/3420/18271 2882/3419/18272 3335/3931/18273 -f 3335/3931/18274 2894/3431/18275 2881/3420/18276 -f 2900/3437/18277 2905/3443/18278 3335/3931/18279 -f 3335/3931/18280 2882/3419/18281 2900/3437/18282 -f 2938/3475/18283 2924/3462/18284 3333/3930/18285 -f 3333/3930/18286 3334/3929/18287 2938/3475/18288 -f 2937/3476/18289 2938/3475/18290 3334/3929/18291 -f 3334/3929/18292 3336/3932/18293 2937/3476/18294 -f 3337/3934/18295 3336/3935/18296 3334/3933/18297 -f 3334/3933/18298 3332/3925/18299 3337/3934/18300 -f 3337/3934/18301 3338/3937/18302 3339/3936/18303 -f 3339/3936/18304 3336/3935/18305 3337/3934/18306 -f 3327/3920/18307 3328/3919/18308 3337/3934/18309 -f 3337/3934/18310 3332/3925/18311 3327/3920/18312 -f 3338/3937/18313 3337/3934/18314 3328/3919/18315 -f 3328/3919/18316 3340/3938/18317 3338/3937/18318 -f 3325/3914/18319 3320/3917/18320 3340/3938/18321 -f 3340/3938/18322 3328/3919/18323 3325/3914/18324 -f 3341/3941/18325 3339/3942/18326 3338/3939/18327 -f 3338/3939/18328 3342/3940/18329 3341/3941/18330 -f 3317/3904/18331 3342/3940/18332 3338/3939/18333 -f 3338/3939/18334 3340/3943/18335 3317/3904/18336 -f 3344/3945/18337 3343/3946/18338 3339/3936/18339 -f 3339/3936/18340 3341/3944/18341 3344/3945/18342 -f 3339/3936/18343 3343/3946/18344 2937/3947/18345 -f 2937/3947/18346 3336/3935/18347 3339/3936/18348 -f 3345/3948/18349 2935/3949/18350 2937/3947/18351 -f 2937/3947/18352 3343/3946/18353 3345/3948/18354 -f 3346/3950/18355 2934/3951/18356 2935/3949/18357 -f 2935/3949/18358 3345/3948/18359 3346/3950/18360 -f 3346/3954/18361 3347/3955/18362 3348/3952/18363 -f 3348/3952/18364 2934/3953/18365 3346/3954/18366 -f 3350/3956/18367 3349/3957/18368 3346/3950/18369 -f 3346/3950/18370 3345/3948/18371 3350/3956/18372 -f 3303/3889/18373 3347/3960/18374 3346/3958/18375 -f 3346/3958/18376 3349/3959/18377 3303/3889/18378 -f 3310/3961/18379 3306/3962/18380 3349/3957/18381 -f 3349/3957/18382 3350/3956/18383 3310/3961/18384 -f 3302/3890/18385 3303/3889/18386 3349/3959/18387 -f 3349/3959/18388 3306/3963/18389 3302/3890/18390 -f 3343/3946/18391 3344/3945/18392 3350/3956/18393 -f 3350/3956/18394 3345/3948/18395 3343/3946/18396 -f 2958/3964/18397 3310/3961/18398 3350/3956/18399 -f 3350/3956/18400 3344/3945/18401 2958/3964/18402 -f 3298/3965/18403 2974/3518/18404 3348/3952/18405 -f 3348/3952/18406 3347/3955/18407 3298/3965/18408 -f 2975/3517/18409 3351/3966/18410 3348/3952/18411 -f 3348/3952/18412 2974/3518/18413 2975/3517/18414 -f 2933/3967/18415 2934/3953/18416 3348/3952/18417 -f 3348/3952/18418 3351/3966/18419 2933/3967/18420 -f 3352/3968/18421 2942/3481/18422 3351/3966/18423 -f 3351/3966/18424 2975/3517/18425 3352/3968/18426 -f 2940/3480/18427 2933/3967/18428 3351/3966/18429 -f 3351/3966/18430 2942/3481/18431 2940/3480/18432 -f 2967/3511/18433 2968/3510/18434 3352/3968/18435 -f 3352/3968/18436 3353/3969/18437 2967/3511/18438 -f 2941/3482/18439 2942/3481/18440 3352/3968/18441 -f 3352/3968/18442 2968/3510/18443 2941/3482/18444 -f 2971/3516/18445 3353/3969/18446 3352/3968/18447 -f 3352/3968/18448 2975/3517/18449 2971/3516/18450 -f 2970/3512/18451 2967/3511/18452 3353/3969/18453 -f 3353/3969/18454 3354/3970/18455 2970/3512/18456 -f 3355/3971/18457 3354/3970/18458 3353/3969/18459 -f 3353/3969/18460 2971/3516/18461 3355/3971/18462 -f 3236/3972/18463 3234/3973/18464 3354/3970/18465 -f 3354/3970/18466 3355/3971/18467 3236/3972/18468 -f 3235/3821/18469 2970/3512/18470 3354/3970/18471 -f 3354/3970/18472 3234/3973/18473 3235/3821/18474 -f 3298/3965/18475 3294/3875/18476 2973/3514/18477 -f 2973/3514/18478 2974/3518/18479 3298/3965/18480 -f 3297/3882/18481 3298/3881/18482 3347/3960/18483 -f 3347/3960/18484 3303/3889/18485 3297/3882/18486 -f 2956/3498/18487 2958/3502/18488 3344/3974/18489 -f 3344/3974/18490 3341/3941/18491 2956/3498/18492 -f 2955/3499/18493 2956/3498/18494 3341/3941/18495 -f 3341/3941/18496 3342/3940/18497 2955/3499/18498 -f 3313/3902/18499 2955/3499/18500 3342/3940/18501 -f 3342/3940/18502 3317/3904/18503 3313/3902/18504 -f 3316/3905/18505 3317/3904/18506 3340/3943/18507 -f 3340/3943/18508 3320/3907/18509 3316/3905/18510 -f 2958/3502/18511 2959/3501/18512 3309/3898/18513 -f 3309/3898/18514 3310/3897/18515 2958/3502/18516 -f 3237/3975/18517 3293/3874/18518 3291/3867/18519 -f 3291/3867/18520 3238/3870/18521 3237/3975/18522 -f 3242/3809/18523 3243/3808/18524 3262/3836/18525 -f 3262/3836/18526 3245/3810/18527 3242/3809/18528 -f 3248/3814/18529 3247/3813/18530 3259/3835/18531 -f 3259/3835/18532 3250/3815/18533 3248/3814/18534 -f 3237/3977/18535 3236/3972/18536 3355/3971/18537 -f 3355/3971/18538 3293/3976/18539 3237/3977/18540 -f 3001/3543/18541 3002/3542/18542 3010/3554/18543 -f 3010/3554/18544 3011/3553/18545 3001/3543/18546 -f 3357/3978/18547 3356/3979/18548 2988/3532/18549 -f 2988/3532/18550 2989/3531/18551 3357/3978/18552 -f 3323/3913/18553 3301/3888/18554 2988/3532/18555 -f 2988/3532/18556 3356/3979/18557 3323/3913/18558 -f 2976/3522/18559 3323/3913/18560 3356/3979/18561 -f 3356/3979/18562 2979/3519/18563 2976/3522/18564 -f 2945/3485/18565 2941/3482/18566 2968/3510/18567 -f 2968/3510/18568 2962/3508/18569 2945/3485/18570 -f 2923/3461/18571 2936/3471/18572 2939/3478/18573 -f 2939/3478/18574 2925/3463/18575 2923/3461/18576 -f 2923/3461/18577 2924/3462/18578 2938/3475/18579 -f 2938/3475/18580 2936/3471/18581 2923/3461/18582 -f 2897/3434/18583 2874/3412/18584 2932/3470/18585 -f 2932/3470/18586 2926/3467/18587 2897/3434/18588 -f 2866/3404/18589 2915/3452/18590 2863/3402/18591 -f 2863/3402/18592 2860/3399/18593 2866/3404/18594 -f 2892/3430/18595 2895/3433/18596 2918/3455/18597 -f 2918/3455/18598 2913/3454/18599 2892/3430/18600 -f 2891/3428/18601 2892/3430/18602 2913/3454/18603 -f 2913/3454/18604 2914/3453/18605 2891/3428/18606 -f 2890/3429/18607 2891/3428/18608 2914/3453/18609 -f 2914/3453/18610 3358/3980/18611 2890/3429/18612 -f 2866/3404/18613 3358/3980/18614 2914/3453/18615 -f 2914/3453/18616 2915/3452/18617 2866/3404/18618 -f 3359/3982/18619 2890/3429/18620 3358/3980/18621 -f 3358/3980/18622 3360/3981/18623 3359/3982/18624 -f 2841/3378/18625 3360/3981/18626 3358/3980/18627 -f 3358/3980/18628 2866/3404/18629 2841/3378/18630 -f 2877/3415/18631 2887/3426/18632 3359/3982/18633 -f 3359/3982/18634 3361/3983/18635 2877/3415/18636 -f 2888/3425/18637 2890/3429/18638 3359/3982/18639 -f 3359/3982/18640 2887/3426/18641 2888/3425/18642 -f 3362/3984/18643 3361/3983/18644 3359/3982/18645 -f 3359/3982/18646 3360/3981/18647 3362/3984/18648 -f 2854/3392/18649 3361/3983/18650 3362/3984/18651 -f 3362/3984/18652 2851/3390/18653 2854/3392/18654 -f 2841/3378/18655 2839/3375/18656 3362/3984/18657 -f 3362/3984/18658 3360/3981/18659 2841/3378/18660 -f 2837/3377/18661 2851/3390/18662 3362/3984/18663 -f 3362/3984/18664 2839/3375/18665 2837/3377/18666 -f 2869/3407/18667 2877/3415/18668 3361/3983/18669 -f 3361/3983/18670 2854/3392/18671 2869/3407/18672 -f 2882/3419/18673 2880/3417/18674 2899/3438/18675 -f 2899/3438/18676 2900/3437/18677 2882/3419/18678 -f 2847/3384/18679 2873/3411/18680 2896/3435/18681 -f 2896/3435/18682 2846/3385/18683 2847/3384/18684 -f 2883/3424/18685 2884/3423/18686 2895/3433/18687 -f 2895/3433/18688 2892/3430/18689 2883/3424/18690 -f 2875/3414/18691 2885/3422/18692 2887/3426/18693 -f 2887/3426/18694 2877/3415/18695 2875/3414/18696 -f 2842/3383/18697 2856/3394/18698 2858/3397/18699 -f 2858/3397/18700 2847/3384/18701 2842/3383/18702 -f 3363/3985/18703 2797/3334/18704 2834/3372/18705 -f 2834/3372/18706 2855/3395/18707 3363/3985/18708 -f 3363/3985/18709 2775/3312/18710 2797/3334/18711 -f 2843/3382/18712 2806/3344/18713 3363/3985/18714 -f 3363/3985/18715 2855/3395/18716 2843/3382/18717 -f 2806/3344/18718 2774/3313/18719 2775/3312/18720 -f 2775/3312/18721 3363/3985/18722 2806/3344/18723 -f 2842/3383/18724 2843/3382/18725 2855/3395/18726 -f 2855/3395/18727 2856/3394/18728 2842/3383/18729 -f 2826/3365/18730 2862/3400/18731 2861/3398/18732 -f 2861/3398/18733 2825/3366/18734 2826/3365/18735 -f 2807/3345/18736 2844/3381/18737 2848/3387/18738 -f 2848/3387/18739 2809/3346/18740 2807/3345/18741 -f 2807/3345/18742 2806/3344/18743 2843/3382/18744 -f 2843/3382/18745 2844/3381/18746 2807/3345/18747 -f 2819/3360/18748 2820/3359/18749 2838/3376/18750 -f 2838/3376/18751 2836/3373/18752 2819/3360/18753 -f 2836/3373/18754 2823/3361/18755 2819/3360/18756 -f 2824/3362/18757 2823/3361/18758 2862/3400/18759 -f 2862/3400/18760 2826/3365/18761 2824/3362/18762 -f 2829/3369/18763 2828/3363/18764 2825/3366/18765 -f 2825/3366/18766 2861/3398/18767 2829/3369/18768 -f 2811/3349/18769 2824/3362/18770 2826/3365/18771 -f 2826/3365/18772 2827/3364/18773 2811/3349/18774 -f 2793/3331/18775 2794/3330/18776 2813/3352/18777 -f 2813/3352/18778 2764/3304/18779 2793/3331/18780 -f 2766/3302/18781 2812/3348/18782 2810/3350/18783 -f 2810/3350/18784 2765/3303/18785 2766/3302/18786 -f 2798/3338/18787 2805/3343/18788 2808/3347/18789 -f 2808/3347/18790 2802/3339/18791 2798/3338/18792 -f 2783/3320/18793 2800/3336/18794 2803/3342/18795 -f 2803/3342/18796 2782/3321/18797 2783/3320/18798 -f 2783/3320/18799 2785/3324/18800 2799/3337/18801 -f 2799/3337/18802 2800/3336/18803 2783/3320/18804 -f 2767/3305/18805 2758/3295/18806 2755/3293/18807 -f 2755/3293/18808 2762/3300/18809 2767/3305/18810 -f 3364/3986/18811 2772/3311/18812 2776/3315/18813 -f 2776/3315/18814 3132/3689/18815 3364/3986/18816 -f 2774/3313/18817 2773/3310/18818 2769/3308/18819 -f 2755/3293/18820 2754/3289/18821 2761/3301/18822 -f 2761/3301/18823 2762/3300/18824 2755/3293/18825 -f 3132/3689/18826 3070/3619/18827 3071/3618/18828 -f 3071/3618/18829 3364/3986/18830 3132/3689/18831 -f 2734/3275/18832 2735/3274/18833 2748/3287/18834 -f 2748/3287/18835 2749/3286/18836 2734/3275/18837 -f 3113/3667/18838 3115/3670/18839 3118/3674/18840 -f 3117/3672/18841 3091/3675/18842 2729/3673/18843 -f 2721/3256/18844 2715/3253/18845 2726/3263/18846 -f 2726/3263/18847 2727/3262/18848 2721/3256/18849 -f 3070/3619/18850 3365/3987/18851 2740/3281/18852 -f 2740/3281/18853 3068/3616/18854 3070/3619/18855 -f 3130/3688/18856 3365/3987/18857 3070/3619/18858 -f 3070/3619/18859 3132/3689/18860 3130/3688/18861 -f 3136/3693/18862 3365/3987/18863 3130/3688/18864 -f 3130/3688/18865 3134/3691/18866 3136/3693/18867 -f 2743/3278/18868 2740/3281/18869 3365/3987/18870 -f 2743/3278/18871 3365/3987/18872 3136/3693/18873 -f 2743/3278/18874 3136/3693/18875 2742/3279/18876 -f 3314/3901/18877 2954/3500/18878 2955/3499/18879 -f 2955/3499/18880 3313/3902/18881 3314/3901/18882 -f 3301/3885/18883 2982/3524/18884 2947/3489/18885 -f 2947/3489/18886 3295/3880/18887 3301/3885/18888 -f 3322/3912/18889 2981/3911/18890 3301/3888/18891 -f 3301/3888/18892 3323/3913/18893 3322/3912/18894 -f 3178/3739/18895 3007/3547/18896 3004/3550/18897 -f 3180/3742/18898 3181/3741/18899 3366/3988/18900 -f 3011/3553/18901 3366/3988/18902 3181/3741/18903 -f 3181/3741/18904 3186/3746/18905 3011/3553/18906 -f 3178/3739/18907 3366/3988/18908 3011/3553/18909 -f 3011/3553/18910 3007/3547/18911 3178/3739/18912 -f 3364/3986/18913 2771/3306/18914 2768/3309/18915 -f 2768/3309/18916 2772/3311/18917 3364/3986/18918 -f 3314/3901/18919 2961/3503/18920 2957/3497/18921 -f 2957/3497/18922 2954/3500/18923 3314/3901/18924 -f 2982/3524/18925 3301/3885/18926 2981/3525/18927 -f 3178/3739/18928 3180/3742/18929 3366/3988/18930 -f 2979/3519/18931 3367/3989/18932 2978/3520/18933 -f 3004/3550/18934 3005/3549/18935 3013/3555/18936 -f 3369/3990/18937 3368/3991/18938 3025/3567/18939 -f 3025/3567/18940 3024/3568/18941 3369/3990/18942 -f 3024/3568/18943 2779/3318/18944 3369/3990/18945 -f 3367/3989/18946 2979/3519/18947 3356/3979/18948 -f 3356/3979/18949 3357/3978/18950 3367/3989/18951 -f 3369/3990/18952 2780/3317/18953 3169/3727/18954 -f 3169/3727/18955 3368/3991/18956 3369/3990/18957 -f 3369/3990/18958 2779/3318/18959 2780/3317/18960 -f 3012/3556/18961 3214/3774/18962 3013/3555/18963 -f 2997/3541/18964 2998/3540/18965 3370/3992/18966 -f 2998/3540/18967 3191/3794/18968 3370/3992/18969 -f 3185/3744/18970 3370/3993/18971 3191/3751/18972 -f 3191/3751/18973 3184/3745/18974 3185/3744/18975 -f 3151/3707/18976 2786/3323/18977 2784/3319/18978 -f 2784/3319/18979 2781/3322/18980 3151/3707/18981 -f 3151/3707/18982 3141/3696/18983 3127/3684/18984 -f 3127/3684/18985 2786/3323/18986 3151/3707/18987 -f 3371/3994/18988 3118/3674/18989 2729/3673/18990 -f 2729/3673/18991 2727/3262/18992 3371/3994/18993 -f 3371/3994/18994 2727/3262/18995 3111/3665/18996 -f 3111/3665/18997 3110/3666/18998 3371/3994/18999 -f 3110/3666/19000 3113/3667/19001 3118/3674/19002 -f 3118/3674/19003 3371/3994/19004 3110/3666/19005 -f 3111/3665/19006 3104/3659/19007 3108/3663/19008 -f 2732/3269/19009 3107/3664/19010 3120/3676/19011 -f 3120/3676/19012 2731/3270/19013 2732/3269/19014 -f 3105/3661/19015 3107/3664/19016 3108/3663/19017 -f 3108/3663/19018 3104/3659/19019 3105/3661/19020 -f 3120/3676/19021 3107/3664/19022 3105/3661/19023 -f 2851/3390/19024 3163/3719/19025 2850/3391/19026 -f 3286/3863/19027 3288/3864/19028 3284/3859/19029 -f 3284/3859/19030 3285/3860/19031 3286/3863/19032 -f 2950/3494/19033 2912/3450/19034 2906/3447/19035 -f 2906/3447/19036 3288/3864/19037 2950/3494/19038 -f 3315/3900/19039 2978/3520/19040 2960/3504/19041 -f 2960/3504/19042 2961/3503/19043 3315/3900/19044 -f 2961/3503/19045 3314/3901/19046 3315/3900/19047 -f 3367/3989/19048 3357/3978/19049 3308/3895/19050 -f 3308/3895/19051 3311/3899/19052 3367/3989/19053 -f 2989/3531/19054 3307/3896/19055 3308/3895/19056 -f 3308/3895/19057 3357/3978/19058 2989/3531/19059 -f 2989/3531/19060 2987/3527/19061 2984/3530/19062 -f 2984/3530/19063 3307/3896/19064 2989/3531/19065 -f 3367/3989/19066 3311/3899/19067 2960/3504/19068 -f 2960/3504/19069 2978/3520/19070 3367/3989/19071 -f 3004/3550/19072 3013/3555/19073 3179/3738/19074 -f 3179/3738/19075 3013/3555/19076 3214/3774/19077 -f 3214/3774/19078 3217/3778/19079 3179/3738/19080 -f 2994/3538/19081 3183/3743/19082 3179/3738/19083 -f 3179/3738/19084 3217/3778/19085 2994/3538/19086 -f 2994/3538/19087 2995/3537/19088 3183/3743/19089 -f 2997/3541/19090 3370/3992/19091 3185/3744/19092 -f 3185/3744/19093 3182/3740/19094 2997/3541/19095 -f 2995/3537/19096 2997/3541/19097 3182/3740/19098 -f 3182/3740/19099 3183/3743/19100 2995/3537/19101 -f 2972/3515/19102 3293/3976/19103 3355/3971/19104 -f 3355/3971/19105 2971/3516/19106 2972/3515/19107 -f 3091/3646/19108 3094/3649/19109 2728/3266/19110 -f 2728/3266/19111 2729/3267/19112 3091/3646/19113 -f 2848/3387/19114 2849/3386/19115 3278/3854/19116 -f 3278/3854/19117 3279/3853/19118 2848/3387/19119 -f 2801/3340/19120 2802/3339/19121 2808/3347/19122 -f 2808/3347/19123 2804/3341/19124 2801/3340/19125 -f 2804/3341/19126 2808/3347/19127 2809/3346/19128 -f 2809/3346/19129 3281/3855/19130 2804/3341/19131 -f 3281/3855/19132 2809/3346/19133 2848/3387/19134 -f 2848/3387/19135 3279/3853/19136 3281/3855/19137 -f 3157/3714/19138 3156/3713/19139 2816/3354/19140 -f 2816/3354/19141 2817/3353/19142 3157/3714/19143 -f 3154/3712/19144 3161/3715/19145 2816/3354/19146 -f 2816/3354/19147 3156/3713/19148 3154/3712/19149 -f 3155/3711/19150 3160/3716/19151 3161/3715/19152 -f 3161/3715/19153 3154/3712/19154 3155/3711/19155 -f 2835/3374/19156 2862/3400/19157 2823/3361/19158 -f 2812/3348/19159 2822/3357/19160 2811/3349/19161 -f 3168/3724/19162 3165/3721/19163 3160/3716/19164 -f 3160/3716/19165 3155/3711/19166 3168/3724/19167 -f 3168/3724/19168 3166/3723/19169 3165/3721/19170 -f 3111/3665/19171 2727/3262/19172 3104/3659/19173 -f 2747/3282/19174 2744/3285/19175 3085/3637/19176 -f 3085/3637/19177 2750/3288/19178 2747/3282/19179 -f 2741/3280/19180 2742/3279/19181 3084/3638/19182 -f 3364/3986/19183 3071/3618/19184 3065/3613/19185 -f 3065/3613/19186 2771/3306/19187 3364/3986/19188 -f 3071/3618/19189 3069/3615/19190 3064/3611/19191 -f 3064/3611/19192 3065/3613/19193 3071/3618/19194 -f 3064/3611/19195 3069/3615/19196 3063/3612/19197 -f 2771/3306/19198 3065/3613/19199 3056/3605/19200 -f 2739/3277/19201 3112/3668/19202 3109/3662/19203 -f 2733/3268/19204 2730/3271/19205 2738/3276/19206 -f 3373/3997/19207 3372/3998/19208 3375/3995/19209 -f 3375/3995/19210 3374/3996/19211 3373/3997/19212 -f 3377/3999/19213 3376/4000/19214 3375/3995/19215 -f 3375/3995/19216 3372/3998/19217 3377/3999/19218 -f 3375/3995/19219 3376/4000/19220 3378/4001/19221 -f 3378/4001/19222 3374/3996/19223 3375/3995/19224 -f 3380/4002/19225 3379/4003/19226 3376/4000/19227 -f 3376/4000/19228 3377/3999/19229 3380/4002/19230 -f 3376/4000/19231 3381/4005/19232 3382/4004/19233 -f 3382/4004/19234 3378/4001/19235 3376/4000/19236 -f 3376/4000/19237 3379/4003/19238 3383/4006/19239 -f 3383/4006/19240 3381/4005/19241 3376/4000/19242 -f 3380/4002/19243 3384/4008/19244 3385/4007/19245 -f 3385/4007/19246 3379/4003/19247 3380/4002/19248 -f 3385/4007/19249 3384/4008/19250 3386/4009/19251 -f 3385/4007/19252 3386/4009/19253 3388/4010/19254 -f 3388/4010/19255 3387/4011/19256 3385/4007/19257 -f 3390/4014/19258 3389/4015/19259 3392/4012/19260 -f 3392/4012/19261 3391/4013/19262 3390/4014/19263 -f 3391/4013/19264 3393/4016/19265 3390/4014/19266 -f 3390/4014/19267 3394/4018/19268 3395/4017/19269 -f 3395/4017/19270 3389/4015/19271 3390/4014/19272 -f 3396/4020/19273 3394/4018/19274 3390/4014/19275 -f 3390/4014/19276 3397/4019/19277 3396/4020/19278 -f 3399/4023/19279 3398/4024/19280 3401/4021/19281 -f 3401/4021/19282 3400/4022/19283 3399/4023/19284 -f 3402/4025/19285 3391/4013/19286 3392/4012/19287 -f 3403/4026/19288 3402/4025/19289 3392/4012/19290 -f 3404/4029/19291 3393/4016/19292 3406/4027/19293 -f 3406/4027/19294 3405/4028/19295 3404/4029/19296 -f 3406/4027/19297 3393/4016/19298 3391/4013/19299 -f 3391/4013/19300 3402/4025/19301 3406/4027/19302 -f 3402/4025/19303 3403/4026/19304 3406/4027/19305 -f 3406/4027/19306 3403/4026/19307 3408/4030/19308 -f 3408/4030/19309 3407/4031/19310 3406/4027/19311 -f 3409/4032/19312 3407/4031/19313 3408/4030/19314 -f 3409/4032/19315 3408/4030/19316 3411/4033/19317 -f 3411/4033/19318 3410/4034/19319 3409/4032/19320 -f 3409/4032/19321 3413/4035/19322 3412/4036/19323 -f 3414/4037/19324 3407/4031/19325 3409/4032/19326 -f 3409/4032/19327 3412/4036/19328 3414/4037/19329 -f 3415/4038/19330 3386/4009/19331 3384/4008/19332 -f 3384/4008/19333 3400/4022/19334 3415/4038/19335 -f 3415/4038/19336 3416/4039/19337 3388/4010/19338 -f 3388/4010/19339 3386/4009/19340 3415/4038/19341 -f 3413/4035/19342 3409/4032/19343 3410/4034/19344 -f 3410/4034/19345 3417/4040/19346 3413/4035/19347 -f 3418/4041/19348 3412/4036/19349 3413/4035/19350 -f 3413/4035/19351 3417/4040/19352 3418/4041/19353 -f 3420/4044/19354 3419/4045/19355 3422/4042/19356 -f 3422/4042/19357 3421/4043/19358 3420/4044/19359 -f 3423/4047/19360 3419/4045/19361 3420/4044/19362 -f 3420/4044/19363 3424/4046/19364 3423/4047/19365 -f 3426/4049/19366 3425/4050/19367 3427/4048/19368 -f 3427/4048/19369 3422/4042/19370 3426/4049/19371 -f 3428/4053/19372 3426/4049/19373 3430/4051/19374 -f 3430/4051/19375 3429/4052/19376 3428/4053/19377 -f 3426/4049/19378 3428/4053/19379 3425/4050/19380 -f 3426/4049/19381 3422/4042/19382 3419/4045/19383 -f 3419/4045/19384 3431/4054/19385 3426/4049/19386 -f 3421/4043/19387 3433/4055/19388 3432/4056/19389 -f 3420/4044/19390 3421/4043/19391 3432/4056/19392 -f 3432/4056/19393 3424/4046/19394 3420/4044/19395 -f 3435/4057/19396 3434/4058/19397 3430/4051/19398 -f 3430/4051/19399 3426/4049/19400 3435/4057/19401 -f 3435/4057/19402 3426/4049/19403 3431/4054/19404 -f 3431/4054/19405 3436/4059/19406 3435/4057/19407 -f 3435/4057/19408 3437/4061/19409 3438/4060/19410 -f 3438/4060/19411 3434/4058/19412 3435/4057/19413 -f 3435/4057/19414 3436/4059/19415 3440/4062/19416 -f 3440/4062/19417 3439/4063/19418 3435/4057/19419 -f 3435/4057/19420 3439/4063/19421 3441/4064/19422 -f 3441/4064/19423 3437/4061/19424 3435/4057/19425 -f 3442/4066/19426 3423/4047/19427 3424/4046/19428 -f 3424/4046/19429 3443/4065/19430 3442/4066/19431 -f 3442/4066/19432 3444/4068/19433 3445/4067/19434 -f 3445/4067/19435 3423/4047/19436 3442/4066/19437 -f 3442/4066/19438 3443/4065/19439 3446/4069/19440 -f 3446/4069/19441 3444/4068/19442 3442/4066/19443 -f 3448/4072/19444 3447/4073/19445 3450/4070/19446 -f 3450/4070/19447 3449/4071/19448 3448/4072/19449 -f 3452/4074/19450 3451/4075/19451 3447/4073/19452 -f 3447/4073/19453 3448/4072/19454 3452/4074/19455 -f 3448/4072/19456 3449/4071/19457 3453/4076/19458 -f 3453/4076/19459 3452/4074/19460 3448/4072/19461 -f 3455/4077/19462 3454/4078/19463 3428/4053/19464 -f 3428/4053/19465 3429/4052/19466 3455/4077/19467 -f 3429/4052/19468 3430/4051/19469 3456/4079/19470 -f 3456/4079/19471 3455/4077/19472 3429/4052/19473 -f 3458/4081/19474 3457/4082/19475 3444/4068/19476 -f 3444/4068/19477 3459/4080/19478 3458/4081/19479 -f 3444/4068/19480 3457/4082/19481 3445/4067/19482 -f 3446/4069/19483 3461/4083/19484 3460/4084/19485 -f 3444/4068/19486 3446/4069/19487 3460/4084/19488 -f 3460/4084/19489 3459/4080/19490 3444/4068/19491 -f 3463/4085/19492 3462/4086/19493 3412/4036/19494 -f 3412/4036/19495 3418/4041/19496 3463/4085/19497 -f 3463/4085/19498 3418/4041/19499 3465/4087/19500 -f 3465/4087/19501 3464/4088/19502 3463/4085/19503 -f 3467/4089/19504 3466/4090/19505 3463/4085/19506 -f 3463/4085/19507 3464/4088/19508 3467/4089/19509 -f 3469/4092/19510 3468/4093/19511 3470/4091/19512 -f 3470/4091/19513 3462/4086/19514 3469/4092/19515 -f 3469/4092/19516 3471/4094/19517 3468/4093/19518 -f 3472/4097/19519 3466/4098/19520 3474/4095/19521 -f 3474/4095/19522 3473/4096/19523 3472/4097/19524 -f 3476/4101/19525 3475/4102/19526 3478/4099/19527 -f 3478/4099/19528 3477/4100/19529 3476/4101/19530 -f 3476/4101/19531 3479/4104/19532 3480/4103/19533 -f 3480/4103/19534 3475/4102/19535 3476/4101/19536 -f 3476/4101/19537 3477/4100/19538 3481/4105/19539 -f 3481/4105/19540 3479/4104/19541 3476/4101/19542 -f 3483/4108/19543 3482/4109/19544 3485/4106/19545 -f 3485/4106/19546 3484/4107/19547 3483/4108/19548 -f 3485/4106/19549 3486/4112/19550 3488/4110/19551 -f 3488/4110/19552 3487/4111/19553 3485/4106/19554 -f 3480/4103/19555 3489/4114/19556 3490/4113/19557 -f 3490/4113/19558 3475/4102/19559 3480/4103/19560 -f 3492/4117/19561 3491/4118/19562 3494/4115/19563 -f 3494/4115/19564 3493/4116/19565 3492/4117/19566 -f 3479/4104/19567 3481/4105/19568 3496/4119/19569 -f 3496/4119/19570 3495/4120/19571 3479/4104/19572 -f 3498/4123/19573 3497/4124/19574 3474/4121/19575 -f 3474/4121/19576 3499/4122/19577 3498/4123/19578 -f 3501/4125/19579 3500/4126/19580 3497/4124/19581 -f 3497/4124/19582 3498/4123/19583 3501/4125/19584 -f 3498/4123/19585 3499/4122/19586 3502/4127/19587 -f 3502/4127/19588 3501/4125/19589 3498/4123/19590 -f 3504/4129/19591 3503/4130/19592 3495/4120/19593 -f 3495/4120/19594 3505/4128/19595 3504/4129/19596 -f 3487/4111/19597 3489/4114/19598 3480/4103/19599 -f 3480/4103/19600 3503/4130/19601 3487/4111/19602 -f 3503/4130/19603 3506/4131/19604 3487/4111/19605 -f 3508/4134/19606 3507/4135/19607 3510/4132/19608 -f 3510/4132/19609 3509/4133/19610 3508/4134/19611 -f 3512/4136/19612 3511/4137/19613 3507/4135/19614 -f 3507/4135/19615 3508/4134/19616 3512/4136/19617 -f 3508/4134/19618 3509/4133/19619 3513/4138/19620 -f 3513/4138/19621 3512/4136/19622 3508/4134/19623 -f 3515/4141/19624 3514/4142/19625 3517/4139/19626 -f 3517/4139/19627 3516/4140/19628 3515/4141/19629 -f 3515/4141/19630 3516/4140/19631 3519/4143/19632 -f 3519/4143/19633 3518/4144/19634 3515/4141/19635 -f 3515/4141/19636 3518/4144/19637 3520/4145/19638 -f 3520/4145/19639 3514/4142/19640 3515/4141/19641 -f 3483/4108/19642 3484/4107/19643 3522/4146/19644 -f 3522/4146/19645 3521/4147/19646 3483/4108/19647 -f 3523/4149/19648 3521/4147/19649 3522/4146/19650 -f 3522/4146/19651 3524/4148/19652 3523/4149/19653 -f 3526/4152/19654 3525/4153/19655 3528/4150/19656 -f 3528/4150/19657 3527/4151/19658 3526/4152/19659 -f 3530/4154/19660 3529/4155/19661 3525/4153/19662 -f 3525/4153/19663 3526/4152/19664 3530/4154/19665 -f 3526/4152/19666 3527/4151/19667 3531/4156/19668 -f 3531/4156/19669 3530/4154/19670 3526/4152/19671 -f 3533/4159/19672 3532/4160/19673 3535/4157/19674 -f 3535/4157/19675 3534/4158/19676 3533/4159/19677 -f 3537/4161/19678 3536/4162/19679 3532/4160/19680 -f 3532/4160/19681 3533/4159/19682 3537/4161/19683 -f 3533/4159/19684 3534/4158/19685 3538/4163/19686 -f 3538/4163/19687 3537/4161/19688 3533/4159/19689 -f 3540/4166/19690 3539/4167/19691 3542/4164/19692 -f 3542/4164/19693 3541/4165/19694 3540/4166/19695 -f 3540/4166/19696 3541/4165/19697 3544/4168/19698 -f 3544/4168/19699 3543/4169/19700 3540/4166/19701 -f 3540/4166/19702 3535/4157/19703 3545/4170/19704 -f 3545/4170/19705 3539/4167/19706 3540/4166/19707 -f 3547/4173/19708 3546/4174/19709 3549/4171/19710 -f 3549/4171/19711 3548/4172/19712 3547/4173/19713 -f 3547/4173/19714 3548/4172/19715 3551/4175/19716 -f 3551/4175/19717 3550/4176/19718 3547/4173/19719 -f 3547/4179/19720 3552/4180/19721 3553/4177/19722 -f 3553/4177/19723 3546/4178/19724 3547/4179/19725 -f 3547/4183/19726 3554/4184/19727 3555/4181/19728 -f 3555/4181/19729 3552/4182/19730 3547/4183/19731 -f 3557/4187/19732 3556/4188/19733 3559/4185/19734 -f 3559/4185/19735 3558/4186/19736 3557/4187/19737 -f 3561/4189/19738 3560/4190/19739 3556/4188/19740 -f 3556/4188/19741 3557/4187/19742 3561/4189/19743 -f 3557/4187/19744 3558/4186/19745 3562/4191/19746 -f 3562/4191/19747 3561/4189/19748 3557/4187/19749 -f 3564/4194/19750 3563/4195/19751 3566/4192/19752 -f 3566/4192/19753 3565/4193/19754 3564/4194/19755 -f 3564/4194/19756 3565/4193/19757 3568/4196/19758 -f 3568/4196/19759 3567/4197/19760 3564/4194/19761 -f 3564/4194/19762 3569/4199/19763 3570/4198/19764 -f 3570/4198/19765 3563/4195/19766 3564/4194/19767 -f 3573/4200/19768 3572/4201/19769 3571/4202/19770 -f 3571/4202/19771 3574/4204/19772 3575/4203/19773 -f 3575/4203/19774 3573/4200/19775 3571/4202/19776 -f 3571/4202/19777 3572/4201/19778 3576/4205/19779 -f 3575/4203/19780 3574/4204/19781 3577/4206/19782 -f 3579/4207/19783 3578/4208/19784 3575/4203/19785 -f 3575/4203/19786 3577/4206/19787 3579/4207/19788 -f 3579/4211/19789 3580/4212/19790 3582/4209/19791 -f 3582/4209/19792 3581/4210/19793 3579/4211/19794 -f 3579/4207/19795 3577/4206/19796 3576/4205/19797 -f 3576/4205/19798 3583/4213/19799 3579/4207/19800 -f 3571/4202/19801 3576/4205/19802 3577/4206/19803 -f 3577/4206/19804 3574/4204/19805 3571/4202/19806 -f 3567/4216/19807 3568/4217/19808 3585/4214/19809 -f 3585/4214/19810 3584/4215/19811 3567/4216/19812 -f 3567/4216/19813 3584/4215/19814 3586/4218/19815 -f 3586/4218/19816 3564/4219/19817 3567/4216/19818 -f 3580/4220/19819 3588/4221/19820 3587/4222/19821 -f 3580/4212/19822 3587/4225/19823 3590/4223/19824 -f 3590/4223/19825 3589/4224/19826 3580/4212/19827 -f 3591/4227/19828 3590/4223/19829 3587/4225/19830 -f 3587/4225/19831 3592/4226/19832 3591/4227/19833 -f 3591/4227/19834 3592/4226/19835 3593/4228/19836 -f 3595/4229/19837 3594/4230/19838 3593/4231/19839 -f 3595/4229/19840 3593/4231/19841 3592/4232/19842 -f 3592/4232/19843 3596/4233/19844 3595/4229/19845 -f 3598/4235/19846 3597/4236/19847 3599/4234/19848 -f 3599/4234/19849 3551/4175/19850 3598/4235/19851 -f 3601/4237/19852 3600/4238/19853 3599/4234/19854 -f 3599/4234/19855 3597/4236/19856 3601/4237/19857 -f 3599/4234/19858 3602/4240/19859 3603/4239/19860 -f 3603/4239/19861 3550/4176/19862 3599/4234/19863 -f 3599/4234/19864 3600/4238/19865 3604/4241/19866 -f 3604/4241/19867 3602/4240/19868 3599/4234/19869 -f 3595/4229/19870 3596/4233/19871 3605/4242/19872 -f 3595/4229/19873 3605/4242/19874 3606/4243/19875 -f 3606/4243/19876 3594/4230/19877 3595/4229/19878 -f 3594/4230/19879 3606/4243/19880 3607/4244/19881 -f 3609/4247/19882 3608/4248/19883 3611/4245/19884 -f 3611/4245/19885 3610/4246/19886 3609/4247/19887 -f 3611/4245/19888 3608/4248/19889 3613/4249/19890 -f 3613/4249/19891 3612/4250/19892 3611/4245/19893 -f 3614/4251/19894 3610/4246/19895 3611/4245/19896 -f 3611/4245/19897 3612/4250/19898 3614/4251/19899 -f 3615/4254/19900 3585/4214/19901 3617/4252/19902 -f 3617/4252/19903 3616/4253/19904 3615/4254/19905 -f 3615/4254/19906 3616/4253/19907 3619/4255/19908 -f 3619/4255/19909 3618/4256/19910 3615/4254/19911 -f 3615/4254/19912 3620/4257/19913 3584/4215/19914 -f 3584/4215/19915 3585/4214/19916 3615/4254/19917 -f 3555/4181/19918 3621/4259/19919 3622/4258/19920 -f 3622/4258/19921 3552/4182/19922 3555/4181/19923 -f 3624/4262/19924 3623/4263/19925 3626/4260/19926 -f 3626/4260/19927 3625/4261/19928 3624/4262/19929 -f 3628/4264/19930 3627/4265/19931 3623/4263/19932 -f 3623/4263/19933 3624/4262/19934 3628/4264/19935 -f 3624/4262/19936 3625/4261/19937 3629/4266/19938 -f 3629/4266/19939 3628/4264/19940 3624/4262/19941 -f 3631/4269/19942 3630/4270/19943 3633/4267/19944 -f 3633/4267/19945 3632/4268/19946 3631/4269/19947 -f 3633/4267/19948 3634/4271/19949 3609/4247/19950 -f 3609/4247/19951 3610/4246/19952 3633/4267/19953 -f 3633/4267/19954 3630/4270/19955 3635/4272/19956 -f 3635/4272/19957 3634/4271/19958 3633/4267/19959 -f 3616/4253/19960 3617/4252/19961 3637/4273/19962 -f 3637/4273/19963 3636/4274/19964 3616/4253/19965 -f 3616/4253/19966 3638/4276/19967 3639/4275/19968 -f 3639/4275/19969 3619/4255/19970 3616/4253/19971 -f 3609/4247/19972 3640/4277/19973 3608/4248/19974 -f 3609/4247/19975 3641/4279/19976 3642/4278/19977 -f 3642/4278/19978 3640/4277/19979 3609/4247/19980 -f 3641/4279/19981 3643/4282/19982 3645/4280/19983 -f 3645/4280/19984 3644/4281/19985 3641/4279/19986 -f 3641/4279/19987 3644/4281/19988 3646/4283/19989 -f 3646/4283/19990 3642/4278/19991 3641/4279/19992 -f 3648/4286/19993 3647/4287/19994 3650/4284/19995 -f 3650/4284/19996 3649/4285/19997 3648/4286/19998 -f 3650/4284/19999 3647/4287/20000 3652/4288/20001 -f 3652/4288/20002 3651/4289/20003 3650/4284/20004 -f 3650/4284/20005 3651/4289/20006 3654/4290/20007 -f 3654/4290/20008 3653/4291/20009 3650/4284/20010 -f 3655/4293/20011 3620/4257/20012 3615/4254/20013 -f 3615/4254/20014 3656/4292/20015 3655/4293/20016 -f 3655/4293/20017 3656/4292/20018 3654/4290/20019 -f 3654/4290/20020 3651/4289/20021 3655/4293/20022 -f 3655/4293/20023 3651/4289/20024 3652/4288/20025 -f 3652/4288/20026 3620/4257/20027 3655/4293/20028 -f 3654/4290/20029 3656/4292/20030 3657/4294/20031 -f 3657/4294/20032 3653/4291/20033 3654/4290/20034 -f 3658/4297/20035 3613/4249/20036 3660/4295/20037 -f 3660/4295/20038 3659/4296/20039 3658/4297/20040 -f 3658/4297/20041 3661/4298/20042 3612/4250/20043 -f 3612/4250/20044 3613/4249/20045 3658/4297/20046 -f 3658/4297/20047 3659/4296/20048 3663/4299/20049 -f 3663/4299/20050 3662/4300/20051 3658/4297/20052 -f 3665/4303/20053 3664/4304/20054 3667/4301/20055 -f 3667/4301/20056 3666/4302/20057 3665/4303/20058 -f 3665/4303/20059 3668/4306/20060 3669/4305/20061 -f 3669/4305/20062 3664/4304/20063 3665/4303/20064 -f 3665/4303/20065 3666/4302/20066 3670/4307/20067 -f 3670/4307/20068 3668/4306/20069 3665/4303/20070 -f 3668/4306/20071 3670/4307/20072 3671/4308/20073 -f 3671/4308/20074 3669/4305/20075 3668/4306/20076 -f 3673/4311/20077 3672/4312/20078 3675/4309/20079 -f 3675/4309/20080 3674/4310/20081 3673/4311/20082 -f 3677/4314/20083 3676/4315/20084 3675/4309/20085 -f 3675/4309/20086 3678/4313/20087 3677/4314/20088 -f 3679/4316/20089 3674/4310/20090 3675/4309/20091 -f 3675/4309/20092 3676/4315/20093 3679/4316/20094 -f 3681/4318/20095 3680/4319/20096 3682/4317/20097 -f 3682/4317/20098 3666/4302/20099 3681/4318/20100 -f 3671/4308/20101 3683/4322/20102 3685/4320/20103 -f 3685/4320/20104 3684/4321/20105 3671/4308/20106 -f 3671/4308/20107 3670/4307/20108 3686/4323/20109 -f 3686/4323/20110 3683/4322/20111 3671/4308/20112 -f 3687/4325/20113 3669/4305/20114 3671/4308/20115 -f 3671/4308/20116 3688/4324/20117 3687/4325/20118 -f 3689/4326/20119 3688/4324/20120 3671/4308/20121 -f 3671/4308/20122 3684/4321/20123 3689/4326/20124 -f 3685/4320/20125 3690/4328/20126 3691/4327/20127 -f 3691/4327/20128 3684/4321/20129 3685/4320/20130 -f 3685/4320/20131 3683/4330/20132 3692/4329/20133 -f 3692/4329/20134 3690/4328/20135 3685/4320/20136 -f 3678/4313/20137 3675/4309/20138 3662/4300/20139 -f 3662/4300/20140 3693/4331/20141 3678/4313/20142 -f 3694/4332/20143 3677/4314/20144 3678/4313/20145 -f 3678/4313/20146 3693/4331/20147 3694/4332/20148 -f 3680/4335/20149 3681/4336/20150 3696/4333/20151 -f 3696/4333/20152 3695/4334/20153 3680/4335/20154 -f 3680/4335/20155 3695/4334/20156 3697/4337/20157 -f 3697/4337/20158 3682/4338/20159 3680/4335/20160 -f 3690/4328/20161 3692/4329/20162 3698/4339/20163 -f 3698/4339/20164 3691/4327/20165 3690/4328/20166 -f 3700/4342/20167 3699/4343/20168 3702/4340/20169 -f 3702/4340/20170 3701/4341/20171 3700/4342/20172 -f 3702/4340/20173 3699/4343/20174 3679/4316/20175 -f 3702/4340/20176 3703/4345/20177 3704/4344/20178 -f 3704/4344/20179 3701/4341/20180 3702/4340/20181 -f 3561/4189/20182 3705/4348/20183 3707/4346/20184 -f 3707/4346/20185 3706/4347/20186 3561/4189/20187 -f 3561/4189/20188 3562/4191/20189 3708/4349/20190 -f 3708/4349/20191 3705/4348/20192 3561/4189/20193 -f 3561/4189/20194 3706/4347/20195 3710/4350/20196 -f 3710/4350/20197 3709/4351/20198 3561/4189/20199 -f 3712/4352/20200 3711/4353/20201 3695/4334/20202 -f 3695/4334/20203 3696/4333/20204 3712/4352/20205 -f 3714/4356/20206 3713/4357/20207 3716/4354/20208 -f 3716/4354/20209 3715/4355/20210 3714/4356/20211 -f 3714/4356/20212 3715/4355/20213 3718/4358/20214 -f 3718/4358/20215 3717/4359/20216 3714/4356/20217 -f 3714/4356/20218 3717/4359/20219 3720/4360/20220 -f 3720/4360/20221 3719/4361/20222 3714/4356/20223 -f 3693/4331/20224 3721/4362/20225 3694/4332/20226 -f 3721/4362/20227 3722/4364/20228 3723/4363/20229 -f 3723/4363/20230 3694/4332/20231 3721/4362/20232 -f 3722/4364/20233 3724/4365/20234 3723/4363/20235 -f 3725/4367/20236 3703/4345/20237 3702/4340/20238 -f 3702/4340/20239 3726/4366/20240 3725/4367/20241 -f 3725/4367/20242 3726/4366/20243 3728/4368/20244 -f 3728/4368/20245 3727/4369/20246 3725/4367/20247 -f 3725/4367/20248 3727/4369/20249 3717/4359/20250 -f 3717/4359/20251 3718/4358/20252 3725/4367/20253 -f 3727/4369/20254 3728/4368/20255 3723/4363/20256 -f 3723/4363/20257 3724/4365/20258 3727/4369/20259 -f 3727/4369/20260 3724/4365/20261 3720/4360/20262 -f 3720/4360/20263 3717/4359/20264 3727/4369/20265 -f 3728/4368/20266 3677/4314/20267 3694/4332/20268 -f 3694/4332/20269 3723/4363/20270 3728/4368/20271 -f 3728/4368/20272 3726/4366/20273 3676/4315/20274 -f 3676/4315/20275 3677/4314/20276 3728/4368/20277 -f 3676/4315/20278 3726/4366/20279 3702/4340/20280 -f 3702/4340/20281 3679/4316/20282 3676/4315/20283 -f 3729/4370/20284 3674/4310/20285 3679/4316/20286 -f 3679/4316/20287 3699/4343/20288 3729/4370/20289 -f 3729/4370/20290 3699/4343/20291 3601/4371/20292 -f 3601/4371/20293 3730/4372/20294 3729/4370/20295 -f 3731/4374/20296 3729/4370/20297 3730/4372/20298 -f 3730/4372/20299 3732/4373/20300 3731/4374/20301 -f 3597/4236/20302 3733/4376/20303 3730/4375/20304 -f 3730/4375/20305 3601/4237/20306 3597/4236/20307 -f 3734/4377/20308 3732/4378/20309 3730/4375/20310 -f 3730/4375/20311 3733/4376/20312 3734/4377/20313 -f 3734/4377/20314 3733/4376/20315 3736/4379/20316 -f 3736/4379/20317 3735/4380/20318 3734/4377/20319 -f 3737/4382/20320 3734/4377/20321 3735/4380/20322 -f 3735/4380/20323 3738/4381/20324 3737/4382/20325 -f 3740/4383/20326 3739/4384/20327 3735/4380/20328 -f 3735/4380/20329 3736/4379/20330 3740/4383/20331 -f 3741/4385/20332 3738/4381/20333 3735/4380/20334 -f 3735/4380/20335 3739/4384/20336 3741/4385/20337 -f 3741/4385/20338 3739/4384/20339 3743/4386/20340 -f 3743/4386/20341 3742/4387/20342 3741/4385/20343 -f 3745/4388/20344 3744/4389/20345 3742/4387/20346 -f 3742/4387/20347 3743/4386/20348 3745/4388/20349 -f 3747/4390/20350 3746/4391/20351 3742/4387/20352 -f 3742/4387/20353 3744/4389/20354 3747/4390/20355 -f 3747/4390/20356 3744/4389/20357 3749/4392/20358 -f 3749/4392/20359 3748/4393/20360 3747/4390/20361 -f 3748/4393/20362 3749/4392/20363 3751/4394/20364 -f 3751/4394/20365 3750/4395/20366 3748/4393/20367 -f 3753/4396/20368 3752/4397/20369 3750/4395/20370 -f 3750/4395/20371 3751/4394/20372 3753/4396/20373 -f 3748/4393/20374 3754/4399/20375 3755/4398/20376 -f 3755/4398/20377 3747/4390/20378 3748/4393/20379 -f 3748/4393/20380 3750/4395/20381 3756/4400/20382 -f 3756/4400/20383 3754/4399/20384 3748/4393/20385 -f 3756/4400/20386 3750/4395/20387 3752/4397/20388 -f 3752/4397/20389 3757/4401/20390 3756/4400/20391 -f 3759/4403/20392 3758/4404/20393 3760/4402/20394 -f 3760/4402/20395 3746/4391/20396 3759/4403/20397 -f 3759/4403/20398 3746/4391/20399 3747/4390/20400 -f 3747/4390/20401 3755/4398/20402 3759/4403/20403 -f 3741/4385/20404 3742/4387/20405 3746/4391/20406 -f 3746/4391/20407 3760/4402/20408 3741/4385/20409 -f 3741/4385/20410 3760/4402/20411 3761/4405/20412 -f 3761/4405/20413 3738/4381/20414 3741/4385/20415 -f 3738/4381/20416 3761/4405/20417 3762/4406/20418 -f 3762/4406/20419 3737/4382/20420 3738/4381/20421 -f 3732/4378/20422 3734/4377/20423 3737/4382/20424 -f 3737/4382/20425 3763/4407/20426 3732/4378/20427 -f 3732/4373/20428 3763/4409/20429 3764/4408/20430 -f 3764/4408/20431 3731/4374/20432 3732/4373/20433 -f 3765/4410/20434 3673/4311/20435 3731/4374/20436 -f 3731/4374/20437 3764/4408/20438 3765/4410/20439 -f 3674/4310/20440 3729/4370/20441 3731/4374/20442 -f 3731/4374/20443 3673/4311/20444 3674/4310/20445 -f 3766/4411/20446 3672/4312/20447 3673/4311/20448 -f 3673/4311/20449 3765/4410/20450 3766/4411/20451 -f 3767/4412/20452 3661/4298/20453 3672/4312/20454 -f 3672/4312/20455 3766/4411/20456 3767/4412/20457 -f 3658/4297/20458 3675/4309/20459 3672/4312/20460 -f 3672/4312/20461 3661/4298/20462 3658/4297/20463 -f 3658/4297/20464 3662/4300/20465 3675/4309/20466 -f 3612/4250/20467 3661/4298/20468 3767/4412/20469 -f 3767/4412/20470 3614/4251/20471 3612/4250/20472 -f 3769/4413/20473 3768/4414/20474 3766/4411/20475 -f 3766/4411/20476 3765/4410/20477 3769/4413/20478 -f 3769/4413/20479 3765/4410/20480 3764/4408/20481 -f 3764/4408/20482 3770/4415/20483 3769/4413/20484 -f 3770/4415/20485 3764/4408/20486 3763/4409/20487 -f 3763/4409/20488 3771/4416/20489 3770/4415/20490 -f 3737/4382/20491 3762/4406/20492 3771/4417/20493 -f 3771/4417/20494 3763/4407/20495 3737/4382/20496 -f 3762/4406/20497 3772/4419/20498 3773/4418/20499 -f 3773/4418/20500 3771/4417/20501 3762/4406/20502 -f 3762/4406/20503 3761/4405/20504 3774/4420/20505 -f 3774/4420/20506 3772/4419/20507 3762/4406/20508 -f 3761/4405/20509 3760/4402/20510 3758/4404/20511 -f 3758/4404/20512 3774/4420/20513 3761/4405/20514 -f 3773/4421/20515 3775/4422/20516 3770/4415/20517 -f 3770/4415/20518 3771/4416/20519 3773/4421/20520 -f 3775/4422/20521 3776/4423/20522 3769/4413/20523 -f 3769/4413/20524 3770/4415/20525 3775/4422/20526 -f 3769/4413/20527 3776/4423/20528 3777/4424/20529 -f 3777/4424/20530 3768/4414/20531 3769/4413/20532 -f 3767/4412/20533 3766/4411/20534 3768/4414/20535 -f 3768/4414/20536 3778/4425/20537 3767/4412/20538 -f 3767/4412/20539 3778/4425/20540 3779/4426/20541 -f 3779/4426/20542 3614/4251/20543 3767/4412/20544 -f 3610/4246/20545 3614/4251/20546 3779/4426/20547 -f 3779/4426/20548 3632/4268/20549 3610/4246/20550 -f 3779/4426/20551 3780/4428/20552 3781/4427/20553 -f 3781/4427/20554 3632/4268/20555 3779/4426/20556 -f 3779/4426/20557 3778/4425/20558 3782/4429/20559 -f 3782/4429/20560 3780/4428/20561 3779/4426/20562 -f 3782/4429/20563 3778/4425/20564 3768/4414/20565 -f 3768/4414/20566 3777/4424/20567 3782/4429/20568 -f 3784/4430/20569 3783/4431/20570 3649/4285/20571 -f 3649/4285/20572 3631/4269/20573 3784/4430/20574 -f 3784/4430/20575 3631/4269/20576 3632/4268/20577 -f 3632/4268/20578 3781/4427/20579 3784/4430/20580 -f 3649/4285/20581 3783/4431/20582 3786/4432/20583 -f 3786/4432/20584 3785/4433/20585 3649/4285/20586 -f 3785/4433/20587 3648/4286/20588 3649/4285/20589 -f 3630/4270/20590 3631/4269/20591 3649/4285/20592 -f 3649/4285/20593 3650/4284/20594 3630/4270/20595 -f 3648/4286/20596 3785/4433/20597 3788/4434/20598 -f 3788/4434/20599 3787/4435/20600 3648/4286/20601 -f 3789/4436/20602 3647/4287/20603 3648/4286/20604 -f 3648/4286/20605 3787/4435/20606 3789/4436/20607 -f 3789/4436/20608 3787/4435/20609 3790/4437/20610 -f 3790/4437/20611 3569/4438/20612 3789/4436/20613 -f 3789/4436/20614 3569/4438/20615 3564/4219/20616 -f 3564/4219/20617 3586/4218/20618 3789/4436/20619 -f 3789/4436/20620 3586/4218/20621 3652/4288/20622 -f 3652/4288/20623 3647/4287/20624 3789/4436/20625 -f 3569/4199/20626 3790/4440/20627 3791/4439/20628 -f 3791/4439/20629 3570/4198/20630 3569/4199/20631 -f 3570/4198/20632 3791/4439/20633 3793/4441/20634 -f 3793/4441/20635 3792/4442/20636 3570/4198/20637 -f 3795/4443/20638 3794/4444/20639 3792/4442/20640 -f 3792/4442/20641 3793/4441/20642 3795/4443/20643 -f 3792/4442/20644 3794/4444/20645 3797/4445/20646 -f 3797/4445/20647 3796/4446/20648 3792/4442/20649 -f 3792/4442/20650 3796/4446/20651 3563/4195/20652 -f 3563/4195/20653 3570/4198/20654 3792/4442/20655 -f 3796/4446/20656 3797/4445/20657 3799/4447/20658 -f 3799/4447/20659 3798/4448/20660 3796/4446/20661 -f 3796/4446/20662 3798/4448/20663 3566/4192/20664 -f 3566/4192/20665 3563/4195/20666 3796/4446/20667 -f 3798/4448/20668 3799/4447/20669 3801/4449/20670 -f 3801/4449/20671 3800/4450/20672 3798/4448/20673 -f 3798/4448/20674 3800/4450/20675 3802/4451/20676 -f 3802/4451/20677 3566/4192/20678 3798/4448/20679 -f 3802/4451/20680 3800/4450/20681 3536/4162/20682 -f 3536/4162/20683 3537/4161/20684 3802/4451/20685 -f 3802/4451/20686 3537/4161/20687 3804/4452/20688 -f 3804/4452/20689 3803/4453/20690 3802/4451/20691 -f 3802/4451/20692 3803/4453/20693 3565/4193/20694 -f 3565/4193/20695 3566/4192/20696 3802/4451/20697 -f 3803/4453/20698 3804/4452/20699 3806/4454/20700 -f 3806/4454/20701 3805/4455/20702 3803/4453/20703 -f 3803/4453/20704 3805/4455/20705 3568/4196/20706 -f 3568/4196/20707 3565/4193/20708 3803/4453/20709 -f 3805/4456/20710 3806/4457/20711 3637/4273/20712 -f 3637/4273/20713 3617/4252/20714 3805/4456/20715 -f 3805/4456/20716 3617/4252/20717 3585/4214/20718 -f 3585/4214/20719 3568/4217/20720 3805/4456/20721 -f 3806/4457/20722 3807/4459/20723 3808/4458/20724 -f 3808/4458/20725 3637/4273/20726 3806/4457/20727 -f 3806/4454/20728 3804/4452/20729 3809/4460/20730 -f 3809/4460/20731 3807/4461/20732 3806/4454/20733 -f 3809/4460/20734 3810/4463/20735 3811/4462/20736 -f 3811/4462/20737 3807/4461/20738 3809/4460/20739 -f 3809/4460/20740 3804/4452/20741 3537/4161/20742 -f 3537/4161/20743 3538/4163/20744 3809/4460/20745 -f 3809/4460/20746 3538/4163/20747 3812/4464/20748 -f 3812/4464/20749 3810/4463/20750 3809/4460/20751 -f 3812/4464/20752 3813/4466/20753 3814/4465/20754 -f 3814/4465/20755 3810/4463/20756 3812/4464/20757 -f 3812/4464/20758 3538/4163/20759 3534/4158/20760 -f 3534/4158/20761 3815/4467/20762 3812/4464/20763 -f 3812/4464/20764 3815/4467/20765 3816/4468/20766 -f 3816/4468/20767 3813/4466/20768 3812/4464/20769 -f 3816/4468/20770 3817/4470/20771 3818/4469/20772 -f 3818/4469/20773 3813/4466/20774 3816/4468/20775 -f 3816/4468/20776 3815/4467/20777 3820/4471/20778 -f 3820/4471/20779 3819/4472/20780 3816/4468/20781 -f 3816/4468/20782 3819/4472/20783 3821/4473/20784 -f 3821/4473/20785 3817/4470/20786 3816/4468/20787 -f 3821/4473/20788 3572/4201/20789 3573/4200/20790 -f 3573/4200/20791 3817/4470/20792 3821/4473/20793 -f 3821/4473/20794 3819/4472/20795 3822/4474/20796 -f 3822/4474/20797 3583/4213/20798 3821/4473/20799 -f 3821/4473/20800 3583/4213/20801 3576/4205/20802 -f 3576/4205/20803 3572/4201/20804 3821/4473/20805 -f 3822/4474/20806 3819/4472/20807 3820/4471/20808 -f 3820/4471/20809 3823/4475/20810 3822/4474/20811 -f 3824/4476/20812 3605/4242/20813 3596/4233/20814 -f 3824/4476/20815 3825/4479/20816 3827/4477/20817 -f 3827/4477/20818 3826/4478/20819 3824/4476/20820 -f 3824/4476/20821 3826/4478/20822 3606/4243/20823 -f 3606/4243/20824 3605/4242/20825 3824/4476/20826 -f 3826/4478/20827 3827/4477/20828 3829/4480/20829 -f 3829/4480/20830 3828/4481/20831 3826/4478/20832 -f 3826/4478/20833 3828/4481/20834 3607/4244/20835 -f 3607/4244/20836 3606/4243/20837 3826/4478/20838 -f 3828/4481/20839 3829/4480/20840 3830/4482/20841 -f 3830/4482/20842 3590/4223/20843 3828/4481/20844 -f 3828/4481/20845 3590/4223/20846 3591/4227/20847 -f 3591/4227/20848 3607/4244/20849 3828/4481/20850 -f 3830/4482/20851 3829/4480/20852 3832/4483/20853 -f 3832/4483/20854 3831/4484/20855 3830/4482/20856 -f 3830/4482/20857 3831/4484/20858 3833/4485/20859 -f 3833/4485/20860 3589/4224/20861 3830/4482/20862 -f 3830/4482/20863 3589/4224/20864 3590/4223/20865 -f 3833/4485/20866 3831/4484/20867 3835/4486/20868 -f 3835/4486/20869 3834/4487/20870 3833/4485/20871 -f 3833/4485/20872 3834/4487/20873 3836/4488/20874 -f 3836/4488/20875 3582/4209/20876 3833/4485/20877 -f 3833/4485/20878 3582/4209/20879 3580/4212/20880 -f 3580/4212/20881 3589/4224/20882 3833/4485/20883 -f 3836/4488/20884 3834/4487/20885 3837/4489/20886 -f 3837/4489/20887 3808/4458/20888 3836/4488/20889 -f 3836/4488/20890 3808/4458/20891 3807/4459/20892 -f 3807/4459/20893 3811/4490/20894 3836/4488/20895 -f 3836/4488/20896 3811/4490/20897 3581/4210/20898 -f 3581/4210/20899 3582/4209/20900 3836/4488/20901 -f 3837/4489/20902 3834/4487/20903 3835/4486/20904 -f 3835/4486/20905 3838/4491/20906 3837/4489/20907 -f 3837/4489/20908 3838/4491/20909 3839/4492/20910 -f 3839/4492/20911 3636/4274/20912 3837/4489/20913 -f 3837/4489/20914 3636/4274/20915 3637/4273/20916 -f 3637/4273/20917 3808/4458/20918 3837/4489/20919 -f 3839/4492/20920 3838/4491/20921 3840/4493/20922 -f 3840/4493/20923 3625/4261/20924 3839/4492/20925 -f 3839/4492/20926 3625/4261/20927 3626/4260/20928 -f 3626/4260/20929 3638/4276/20930 3839/4492/20931 -f 3839/4492/20932 3638/4276/20933 3616/4253/20934 -f 3616/4253/20935 3636/4274/20936 3839/4492/20937 -f 3840/4493/20938 3841/4496/20939 3843/4494/20940 -f 3843/4494/20941 3842/4495/20942 3840/4493/20943 -f 3840/4493/20944 3842/4495/20945 3629/4266/20946 -f 3629/4266/20947 3625/4261/20948 3840/4493/20949 -f 3840/4493/20950 3838/4491/20951 3835/4486/20952 -f 3835/4486/20953 3841/4496/20954 3840/4493/20955 -f 3842/4495/20956 3843/4494/20957 3845/4497/20958 -f 3845/4497/20959 3844/4498/20960 3842/4495/20961 -f 3842/4495/20962 3844/4498/20963 3846/4499/20964 -f 3846/4499/20965 3629/4266/20966 3842/4495/20967 -f 3846/4499/20968 3847/4500/20969 3628/4264/20970 -f 3628/4264/20971 3629/4266/20972 3846/4499/20973 -f 3845/4497/20974 3843/4494/20975 3849/4501/20976 -f 3849/4501/20977 3848/4502/20978 3845/4497/20979 -f 3849/4501/20980 3827/4477/20981 3825/4479/20982 -f 3825/4479/20983 3848/4502/20984 3849/4501/20985 -f 3849/4501/20986 3843/4494/20987 3841/4496/20988 -f 3841/4496/20989 3832/4483/20990 3849/4501/20991 -f 3849/4501/20992 3832/4483/20993 3829/4480/20994 -f 3829/4480/20995 3827/4477/20996 3849/4501/20997 -f 3841/4496/20998 3835/4486/20999 3831/4484/21000 -f 3831/4484/21001 3832/4483/21002 3841/4496/21003 -f 3850/4504/21004 3823/4475/21005 3820/4471/21006 -f 3820/4471/21007 3851/4503/21008 3850/4504/21009 -f 3850/4504/21010 3851/4503/21011 3540/4166/21012 -f 3540/4166/21013 3543/4169/21014 3850/4504/21015 -f 3851/4503/21016 3820/4471/21017 3815/4467/21018 -f 3815/4467/21019 3534/4158/21020 3851/4503/21021 -f 3851/4503/21022 3534/4158/21023 3535/4157/21024 -f 3535/4157/21025 3540/4166/21026 3851/4503/21027 -f 3818/4469/21028 3575/4203/21029 3578/4208/21030 -f 3818/4469/21031 3578/4208/21032 3814/4465/21033 -f 3814/4465/21034 3813/4466/21035 3818/4469/21036 -f 3818/4469/21037 3817/4470/21038 3573/4200/21039 -f 3573/4200/21040 3575/4203/21041 3818/4469/21042 -f 3814/4465/21043 3578/4208/21044 3579/4207/21045 -f 3579/4207/21046 3581/4505/21047 3814/4465/21048 -f 3814/4465/21049 3581/4505/21050 3811/4462/21051 -f 3811/4462/21052 3810/4463/21053 3814/4465/21054 -f 3799/4447/21055 3797/4445/21056 3518/4144/21057 -f 3518/4144/21058 3519/4143/21059 3799/4447/21060 -f 3799/4447/21061 3519/4143/21062 3530/4154/21063 -f 3530/4154/21064 3801/4449/21065 3799/4447/21066 -f 3797/4445/21067 3794/4444/21068 3520/4145/21069 -f 3520/4145/21070 3518/4144/21071 3797/4445/21072 -f 3520/4145/21073 3794/4444/21074 3494/4115/21075 -f 3494/4115/21076 3491/4118/21077 3520/4145/21078 -f 3791/4439/21079 3852/4507/21080 3853/4506/21081 -f 3853/4506/21082 3793/4441/21083 3791/4439/21084 -f 3852/4507/21085 3791/4439/21086 3855/4508/21087 -f 3855/4508/21088 3854/4509/21089 3852/4507/21090 -f 3857/4512/21091 3856/4513/21092 3859/4510/21093 -f 3859/4510/21094 3858/4511/21095 3857/4512/21096 -f 3857/4512/21097 3860/4515/21098 3861/4514/21099 -f 3861/4514/21100 3856/4513/21101 3857/4512/21102 -f 3862/4517/21103 3856/4513/21104 3861/4514/21105 -f 3861/4514/21106 3863/4516/21107 3862/4517/21108 -f 3861/4514/21109 3860/4515/21110 3757/4401/21111 -f 3757/4401/21112 3752/4397/21113 3861/4514/21114 -f 3859/4510/21115 3856/4513/21116 3862/4517/21117 -f 3862/4517/21118 3506/4131/21119 3859/4510/21120 -f 3863/4516/21121 3861/4514/21122 3752/4397/21123 -f 3752/4397/21124 3753/4396/21125 3863/4516/21126 -f 3864/4519/21127 3753/4396/21128 3751/4394/21129 -f 3751/4394/21130 3865/4518/21131 3864/4519/21132 -f 3866/4520/21133 3865/4518/21134 3751/4394/21135 -f 3751/4394/21136 3749/4392/21137 3866/4520/21138 -f 3866/4520/21139 3749/4392/21140 3744/4389/21141 -f 3744/4389/21142 3745/4388/21143 3866/4520/21144 -f 3460/4084/21145 3864/4519/21146 3865/4518/21147 -f 3865/4518/21148 3459/4080/21149 3460/4084/21150 -f 3458/4081/21151 3459/4080/21152 3865/4518/21153 -f 3865/4518/21154 3866/4520/21155 3458/4081/21156 -f 3458/4081/21157 3866/4520/21158 3745/4388/21159 -f 3745/4388/21160 3867/4521/21161 3458/4081/21162 -f 3868/4522/21163 3457/4082/21164 3458/4081/21165 -f 3458/4081/21166 3867/4521/21167 3868/4522/21168 -f 3868/4522/21169 3867/4521/21170 3870/4523/21171 -f 3870/4523/21172 3869/4524/21173 3868/4522/21174 -f 3871/4525/21175 3440/4062/21176 3868/4522/21177 -f 3868/4522/21178 3869/4524/21179 3871/4525/21180 -f 3436/4059/21181 3457/4082/21182 3868/4522/21183 -f 3868/4522/21184 3440/4062/21185 3436/4059/21186 -f 3445/4067/21187 3457/4082/21188 3436/4059/21189 -f 3436/4059/21190 3431/4054/21191 3445/4067/21192 -f 3423/4047/21193 3445/4067/21194 3431/4054/21195 -f 3431/4054/21196 3419/4045/21197 3423/4047/21198 -f 3873/4526/21199 3872/4527/21200 3871/4525/21201 -f 3871/4525/21202 3869/4524/21203 3873/4526/21204 -f 3871/4525/21205 3872/4527/21206 3875/4528/21207 -f 3875/4528/21208 3874/4529/21209 3871/4525/21210 -f 3871/4525/21211 3874/4529/21212 3439/4063/21213 -f 3439/4063/21214 3440/4062/21215 3871/4525/21216 -f 3874/4529/21217 3875/4528/21218 3877/4530/21219 -f 3877/4530/21220 3876/4531/21221 3874/4529/21222 -f 3874/4529/21223 3876/4531/21224 3441/4064/21225 -f 3441/4064/21226 3439/4063/21227 3874/4529/21228 -f 3876/4531/21229 3877/4530/21230 3467/4532/21231 -f 3467/4532/21232 3878/4533/21233 3876/4531/21234 -f 3876/4531/21235 3878/4533/21236 3879/4534/21237 -f 3879/4534/21238 3441/4064/21239 3876/4531/21240 -f 3416/4039/21241 3415/4038/21242 3879/4535/21243 -f 3879/4535/21244 3878/4536/21245 3416/4039/21246 -f 3879/4534/21247 3880/4537/21248 3437/4061/21249 -f 3437/4061/21250 3441/4064/21251 3879/4534/21252 -f 3880/4537/21253 3881/4538/21254 3438/4060/21255 -f 3438/4060/21256 3437/4061/21257 3880/4537/21258 -f 3881/4538/21259 3882/4540/21260 3883/4539/21261 -f 3883/4539/21262 3438/4060/21263 3881/4538/21264 -f 3883/4539/21265 3882/4540/21266 3885/4541/21267 -f 3885/4541/21268 3884/4542/21269 3883/4539/21270 -f 3883/4539/21271 3884/4542/21272 3887/4543/21273 -f 3887/4543/21274 3886/4544/21275 3883/4539/21276 -f 3883/4539/21277 3886/4544/21278 3434/4058/21279 -f 3434/4058/21280 3438/4060/21281 3883/4539/21282 -f 3886/4544/21283 3887/4543/21284 3888/4545/21285 -f 3888/4545/21286 3456/4079/21287 3886/4544/21288 -f 3886/4544/21289 3456/4079/21290 3430/4051/21291 -f 3430/4051/21292 3434/4058/21293 3886/4544/21294 -f 3888/4545/21295 3887/4543/21296 3890/4546/21297 -f 3890/4546/21298 3889/4547/21299 3888/4545/21300 -f 3888/4545/21301 3889/4547/21302 3892/4548/21303 -f 3892/4548/21304 3891/4549/21305 3888/4545/21306 -f 3888/4545/21307 3891/4549/21308 3455/4077/21309 -f 3455/4077/21310 3456/4079/21311 3888/4545/21312 -f 3891/4549/21313 3892/4548/21314 3562/4191/21315 -f 3562/4191/21316 3558/4186/21317 3891/4549/21318 -f 3891/4549/21319 3558/4186/21320 3893/4550/21321 -f 3893/4550/21322 3455/4077/21323 3891/4549/21324 -f 3893/4550/21325 3513/4138/21326 3454/4078/21327 -f 3454/4078/21328 3455/4077/21329 3893/4550/21330 -f 3893/4550/21331 3558/4186/21332 3559/4185/21333 -f 3559/4185/21334 3894/4551/21335 3893/4550/21336 -f 3893/4550/21337 3894/4551/21338 3512/4136/21339 -f 3512/4136/21340 3513/4138/21341 3893/4550/21342 -f 3894/4551/21343 3895/4553/21344 3896/4552/21345 -f 3896/4552/21346 3512/4136/21347 3894/4551/21348 -f 3894/4551/21349 3559/4185/21350 3897/4554/21351 -f 3897/4554/21352 3895/4553/21353 3894/4551/21354 -f 3897/4554/21355 3898/4556/21356 3899/4555/21357 -f 3899/4555/21358 3895/4553/21359 3897/4554/21360 -f 3897/4554/21361 3559/4185/21362 3556/4188/21363 -f 3556/4188/21364 3900/4557/21365 3897/4554/21366 -f 3897/4554/21367 3900/4557/21368 3901/4558/21369 -f 3901/4558/21370 3898/4556/21371 3897/4554/21372 -f 3901/4558/21373 3902/4560/21374 3903/4559/21375 -f 3903/4559/21376 3898/4556/21377 3901/4558/21378 -f 3901/4558/21379 3900/4557/21380 3905/4561/21381 -f 3905/4561/21382 3904/4562/21383 3901/4558/21384 -f 3901/4558/21385 3904/4562/21386 3906/4563/21387 -f 3906/4563/21388 3902/4560/21389 3901/4558/21390 -f 3906/4563/21391 3907/4565/21392 3908/4564/21393 -f 3908/4564/21394 3902/4560/21395 3906/4563/21396 -f 3906/4563/21397 3904/4562/21398 3910/4566/21399 -f 3910/4566/21400 3909/4567/21401 3906/4563/21402 -f 3906/4563/21403 3909/4567/21404 3911/4568/21405 -f 3911/4568/21406 3907/4565/21407 3906/4563/21408 -f 3911/4568/21409 3626/4260/21410 3623/4263/21411 -f 3623/4263/21412 3907/4565/21413 3911/4568/21414 -f 3911/4568/21415 3909/4567/21416 3912/4569/21417 -f 3912/4569/21418 3639/4275/21419 3911/4568/21420 -f 3911/4568/21421 3639/4275/21422 3638/4276/21423 -f 3638/4276/21424 3626/4260/21425 3911/4568/21426 -f 3912/4569/21427 3909/4567/21428 3910/4566/21429 -f 3910/4566/21430 3913/4570/21431 3912/4569/21432 -f 3912/4569/21433 3913/4570/21434 3643/4282/21435 -f 3643/4282/21436 3914/4571/21437 3912/4569/21438 -f 3912/4569/21439 3914/4571/21440 3619/4255/21441 -f 3619/4255/21442 3639/4275/21443 3912/4569/21444 -f 3914/4571/21445 3643/4282/21446 3641/4279/21447 -f 3641/4279/21448 3915/4572/21449 3914/4571/21450 -f 3914/4571/21451 3915/4572/21452 3618/4256/21453 -f 3618/4256/21454 3619/4255/21455 3914/4571/21456 -f 3913/4570/21457 3910/4566/21458 3917/4573/21459 -f 3917/4573/21460 3916/4574/21461 3913/4570/21462 -f 3913/4570/21463 3916/4574/21464 3645/4280/21465 -f 3645/4280/21466 3643/4282/21467 3913/4570/21468 -f 3916/4574/21469 3917/4573/21470 3919/4575/21471 -f 3919/4575/21472 3918/4576/21473 3916/4574/21474 -f 3918/4576/21475 3921/4577/21476 3920/4578/21477 -f 3916/4574/21478 3918/4576/21479 3920/4578/21480 -f 3920/4578/21481 3645/4280/21482 3916/4574/21483 -f 3920/4578/21484 3921/4577/21485 3922/4579/21486 -f 3920/4578/21487 3922/4579/21488 3924/4580/21489 -f 3924/4580/21490 3923/4581/21491 3920/4578/21492 -f 3920/4578/21493 3923/4581/21494 3644/4281/21495 -f 3644/4281/21496 3645/4280/21497 3920/4578/21498 -f 3923/4581/21499 3924/4580/21500 3926/4582/21501 -f 3926/4582/21502 3925/4583/21503 3923/4581/21504 -f 3923/4581/21505 3925/4583/21506 3646/4283/21507 -f 3646/4283/21508 3644/4281/21509 3923/4581/21510 -f 3925/4583/21511 3926/4582/21512 3928/4584/21513 -f 3928/4584/21514 3927/4585/21515 3925/4583/21516 -f 3925/4583/21517 3927/4585/21518 3929/4586/21519 -f 3929/4586/21520 3646/4283/21521 3925/4583/21522 -f 3929/4586/21523 3930/4587/21524 3642/4278/21525 -f 3642/4278/21526 3646/4283/21527 3929/4586/21528 -f 3929/4586/21529 3927/4585/21530 3714/4356/21531 -f 3714/4356/21532 3719/4361/21533 3929/4586/21534 -f 3929/4586/21535 3719/4361/21536 3931/4588/21537 -f 3931/4588/21538 3930/4587/21539 3929/4586/21540 -f 3931/4588/21541 3659/4296/21542 3660/4295/21543 -f 3660/4295/21544 3930/4587/21545 3931/4588/21546 -f 3931/4588/21547 3719/4361/21548 3720/4360/21549 -f 3720/4360/21550 3932/4589/21551 3931/4588/21552 -f 3931/4588/21553 3932/4589/21554 3663/4299/21555 -f 3663/4299/21556 3659/4296/21557 3931/4588/21558 -f 3932/4589/21559 3720/4360/21560 3724/4365/21561 -f 3724/4365/21562 3722/4364/21563 3932/4589/21564 -f 3932/4589/21565 3722/4364/21566 3721/4362/21567 -f 3721/4362/21568 3663/4299/21569 3932/4589/21570 -f 3930/4587/21571 3660/4295/21572 3640/4277/21573 -f 3640/4277/21574 3642/4278/21575 3930/4587/21576 -f 3927/4585/21577 3928/4584/21578 3713/4357/21579 -f 3713/4357/21580 3714/4356/21581 3927/4585/21582 -f 3933/4590/21583 3921/4577/21584 3918/4576/21585 -f 3933/4590/21586 3918/4576/21587 3935/4591/21588 -f 3935/4591/21589 3934/4592/21590 3933/4590/21591 -f 3934/4592/21592 3935/4591/21593 3937/4593/21594 -f 3937/4593/21595 3936/4594/21596 3934/4592/21597 -f 3937/4593/21598 3935/4591/21599 3939/4595/21600 -f 3939/4595/21601 3938/4596/21602 3937/4593/21603 -f 3937/4593/21604 3938/4596/21605 3718/4358/21606 -f 3718/4358/21607 3715/4355/21608 3937/4593/21609 -f 3937/4593/21610 3715/4355/21611 3716/4354/21612 -f 3716/4354/21613 3936/4594/21614 3937/4593/21615 -f 3938/4596/21616 3939/4595/21617 3709/4351/21618 -f 3709/4351/21619 3710/4350/21620 3938/4596/21621 -f 3938/4596/21622 3710/4350/21623 3725/4367/21624 -f 3725/4367/21625 3718/4358/21626 3938/4596/21627 -f 3939/4595/21628 3918/4576/21629 3919/4575/21630 -f 3919/4575/21631 3709/4351/21632 3939/4595/21633 -f 3939/4595/21634 3935/4591/21635 3918/4576/21636 -f 3919/4575/21637 3917/4573/21638 3905/4561/21639 -f 3905/4561/21640 3560/4190/21641 3919/4575/21642 -f 3919/4575/21643 3560/4190/21644 3561/4189/21645 -f 3561/4189/21646 3709/4351/21647 3919/4575/21648 -f 3917/4573/21649 3910/4566/21650 3904/4562/21651 -f 3904/4562/21652 3905/4561/21653 3917/4573/21654 -f 3908/4564/21655 3627/4265/21656 3542/4164/21657 -f 3542/4164/21658 3940/4597/21659 3908/4564/21660 -f 3908/4564/21661 3940/4597/21662 3903/4559/21663 -f 3903/4559/21664 3902/4560/21665 3908/4564/21666 -f 3908/4564/21667 3907/4565/21668 3623/4263/21669 -f 3623/4263/21670 3627/4265/21671 3908/4564/21672 -f 3940/4597/21673 3542/4164/21674 3539/4167/21675 -f 3539/4167/21676 3941/4598/21677 3940/4597/21678 -f 3940/4597/21679 3941/4598/21680 3942/4599/21681 -f 3942/4599/21682 3903/4559/21683 3940/4597/21684 -f 3942/4599/21685 3941/4598/21686 3944/4600/21687 -f 3944/4600/21688 3943/4601/21689 3942/4599/21690 -f 3942/4599/21691 3943/4601/21692 3945/4602/21693 -f 3945/4602/21694 3899/4555/21695 3942/4599/21696 -f 3942/4599/21697 3899/4555/21698 3898/4556/21699 -f 3898/4556/21700 3903/4559/21701 3942/4599/21702 -f 3945/4602/21703 3943/4601/21704 3947/4603/21705 -f 3947/4603/21706 3946/4604/21707 3945/4602/21708 -f 3945/4602/21709 3946/4604/21710 3948/4605/21711 -f 3948/4605/21712 3896/4552/21713 3945/4602/21714 -f 3945/4602/21715 3896/4552/21716 3895/4553/21717 -f 3895/4553/21718 3899/4555/21719 3945/4602/21720 -f 3948/4605/21721 3946/4604/21722 3950/4606/21723 -f 3950/4606/21724 3949/4607/21725 3948/4605/21726 -f 3948/4605/21727 3949/4607/21728 3488/4110/21729 -f 3488/4110/21730 3511/4137/21731 3948/4605/21732 -f 3948/4605/21733 3511/4137/21734 3512/4136/21735 -f 3512/4136/21736 3896/4552/21737 3948/4605/21738 -f 3949/4607/21739 3950/4606/21740 3490/4113/21741 -f 3490/4113/21742 3489/4114/21743 3949/4607/21744 -f 3949/4607/21745 3489/4114/21746 3487/4111/21747 -f 3487/4111/21748 3488/4110/21749 3949/4607/21750 -f 3950/4606/21751 3951/4609/21752 3952/4608/21753 -f 3952/4608/21754 3490/4113/21755 3950/4606/21756 -f 3950/4606/21757 3946/4604/21758 3947/4603/21759 -f 3947/4603/21760 3951/4609/21761 3950/4606/21762 -f 3952/4608/21763 3953/4610/21764 3492/4117/21765 -f 3492/4117/21766 3478/4099/21767 3952/4608/21768 -f 3952/4608/21769 3478/4099/21770 3475/4102/21771 -f 3475/4102/21772 3490/4113/21773 3952/4608/21774 -f 3952/4608/21775 3951/4609/21776 3528/4150/21777 -f 3528/4150/21778 3953/4610/21779 3952/4608/21780 -f 3953/4610/21781 3954/4611/21782 3491/4118/21783 -f 3491/4118/21784 3492/4117/21785 3953/4610/21786 -f 3953/4610/21787 3528/4150/21788 3525/4153/21789 -f 3525/4153/21790 3954/4611/21791 3953/4610/21792 -f 3951/4609/21793 3947/4603/21794 3527/4151/21795 -f 3527/4151/21796 3528/4150/21797 3951/4609/21798 -f 3947/4603/21799 3943/4601/21800 3944/4600/21801 -f 3944/4600/21802 3527/4151/21803 3947/4603/21804 -f 3944/4600/21805 3545/4170/21806 3531/4156/21807 -f 3531/4156/21808 3527/4151/21809 3944/4600/21810 -f 3944/4600/21811 3941/4598/21812 3539/4167/21813 -f 3539/4167/21814 3545/4170/21815 3944/4600/21816 -f 3905/4561/21817 3900/4557/21818 3556/4188/21819 -f 3556/4188/21820 3560/4190/21821 3905/4561/21822 -f 3892/4548/21823 3889/4547/21824 3956/4612/21825 -f 3956/4612/21826 3955/4613/21827 3892/4548/21828 -f 3892/4548/21829 3955/4613/21830 3708/4349/21831 -f 3708/4349/21832 3562/4191/21833 3892/4548/21834 -f 3955/4613/21835 3956/4612/21836 3958/4614/21837 -f 3958/4614/21838 3957/4615/21839 3955/4613/21840 -f 3955/4613/21841 3957/4615/21842 3959/4616/21843 -f 3959/4616/21844 3708/4349/21845 3955/4613/21846 -f 3959/4616/21847 3957/4615/21848 3961/4617/21849 -f 3961/4617/21850 3960/4618/21851 3959/4616/21852 -f 3959/4616/21853 3960/4618/21854 3963/4619/21855 -f 3963/4619/21856 3962/4620/21857 3959/4616/21858 -f 3959/4616/21859 3962/4620/21860 3705/4348/21861 -f 3705/4348/21862 3708/4349/21863 3959/4616/21864 -f 3962/4620/21865 3963/4619/21866 3965/4621/21867 -f 3965/4621/21868 3964/4622/21869 3962/4620/21870 -f 3962/4620/21871 3964/4622/21872 3707/4346/21873 -f 3707/4346/21874 3705/4348/21875 3962/4620/21876 -f 3964/4622/21877 3965/4621/21878 3967/4623/21879 -f 3967/4623/21880 3966/4624/21881 3964/4622/21882 -f 3964/4622/21883 3966/4624/21884 3704/4344/21885 -f 3704/4344/21886 3707/4346/21887 3964/4622/21888 -f 3966/4624/21889 3967/4623/21890 3969/4625/21891 -f 3969/4625/21892 3968/4626/21893 3966/4624/21894 -f 3966/4624/21895 3968/4626/21896 3701/4341/21897 -f 3701/4341/21898 3704/4344/21899 3966/4624/21900 -f 3968/4626/21901 3969/4625/21902 3971/4627/21903 -f 3971/4627/21904 3970/4628/21905 3968/4626/21906 -f 3968/4626/21907 3970/4628/21908 3700/4342/21909 -f 3700/4342/21910 3701/4341/21911 3968/4626/21912 -f 3970/4628/21913 3971/4627/21914 3972/4629/21915 -f 3972/4629/21916 3604/4630/21917 3970/4628/21918 -f 3970/4628/21919 3604/4630/21920 3600/4631/21921 -f 3600/4631/21922 3700/4342/21923 3970/4628/21924 -f 3972/4634/21925 3971/4635/21926 3974/4632/21927 -f 3974/4632/21928 3973/4633/21929 3972/4634/21930 -f 3972/4634/21931 3973/4633/21932 3976/4636/21933 -f 3976/4636/21934 3975/4637/21935 3972/4634/21936 -f 3972/4638/21937 3975/4639/21938 3602/4240/21939 -f 3602/4240/21940 3604/4241/21941 3972/4638/21942 -f 3975/4637/21943 3976/4636/21944 3978/4640/21945 -f 3978/4640/21946 3977/4641/21947 3975/4637/21948 -f 3975/4639/21949 3977/4642/21950 3603/4239/21951 -f 3603/4239/21952 3602/4240/21953 3975/4639/21954 -f 3976/4636/21955 3973/4633/21956 3980/4643/21957 -f 3980/4643/21958 3979/4644/21959 3976/4636/21960 -f 3976/4636/21961 3979/4644/21962 3981/4645/21963 -f 3981/4645/21964 3978/4640/21965 3976/4636/21966 -f 3981/4645/21967 3979/4644/21968 3983/4646/21969 -f 3983/4646/21970 3982/4647/21971 3981/4645/21972 -f 3981/4650/21973 3982/4651/21974 3985/4648/21975 -f 3985/4648/21976 3984/4649/21977 3981/4650/21978 -f 3981/4650/21979 3984/4649/21980 3554/4184/21981 -f 3554/4184/21982 3978/4652/21983 3981/4650/21984 -f 3984/4649/21985 3985/4648/21986 3987/4653/21987 -f 3987/4653/21988 3986/4654/21989 3984/4649/21990 -f 3984/4649/21991 3986/4654/21992 3555/4181/21993 -f 3555/4181/21994 3554/4184/21995 3984/4649/21996 -f 3987/4653/21997 3985/4648/21998 3989/4655/21999 -f 3989/4655/22000 3988/4656/22001 3987/4653/22002 -f 3987/4653/22003 3988/4656/22004 3991/4657/22005 -f 3991/4657/22006 3990/4658/22007 3987/4653/22008 -f 3987/4653/22009 3990/4658/22010 3555/4181/22011 -f 3555/4181/22012 3986/4654/22013 3987/4653/22014 -f 3990/4658/22015 3991/4657/22016 3993/4659/22017 -f 3993/4659/22018 3992/4660/22019 3990/4658/22020 -f 3990/4658/22021 3992/4660/22022 3621/4259/22023 -f 3621/4259/22024 3555/4181/22025 3990/4658/22026 -f 3992/4660/22027 3993/4659/22028 3995/4661/22029 -f 3995/4661/22030 3994/4662/22031 3992/4660/22032 -f 3992/4660/22033 3994/4662/22034 3996/4663/22035 -f 3996/4663/22036 3621/4259/22037 3992/4660/22038 -f 3996/4663/22039 3997/4664/22040 3622/4258/22041 -f 3622/4258/22042 3621/4259/22043 3996/4663/22044 -f 3996/4663/22045 3994/4662/22046 3999/4665/22047 -f 3999/4665/22048 3998/4666/22049 3996/4663/22050 -f 3996/4663/22051 3998/4666/22052 4000/4667/22053 -f 4000/4667/22054 3997/4664/22055 3996/4663/22056 -f 4000/4669/22057 3960/4618/22058 3961/4617/22059 -f 3961/4617/22060 3997/4668/22061 4000/4669/22062 -f 4000/4667/22063 3998/4666/22064 4002/4670/22065 -f 4002/4670/22066 4001/4671/22067 4000/4667/22068 -f 4000/4669/22069 4001/4672/22070 3963/4619/22071 -f 3963/4619/22072 3960/4618/22073 4000/4669/22074 -f 4001/4671/22075 4002/4670/22076 4004/4673/22077 -f 4004/4673/22078 4003/4674/22079 4001/4671/22080 -f 4001/4672/22081 4003/4675/22082 3965/4621/22083 -f 3965/4621/22084 3963/4619/22085 4001/4672/22086 -f 4003/4674/22087 4004/4673/22088 4006/4676/22089 -f 4006/4676/22090 4005/4677/22091 4003/4674/22092 -f 4003/4675/22093 4005/4678/22094 3967/4623/22095 -f 3967/4623/22096 3965/4621/22097 4003/4675/22098 -f 4005/4677/22099 4006/4676/22100 4008/4679/22101 -f 4008/4679/22102 4007/4680/22103 4005/4677/22104 -f 4005/4678/22105 4007/4681/22106 3969/4625/22107 -f 3969/4625/22108 3967/4623/22109 4005/4678/22110 -f 4007/4680/22111 4008/4679/22112 4009/4682/22113 -f 4009/4682/22114 3974/4632/22115 4007/4680/22116 -f 4007/4681/22117 3974/4683/22118 3971/4627/22119 -f 3971/4627/22120 3969/4625/22121 4007/4681/22122 -f 4009/4682/22123 4008/4679/22124 4011/4684/22125 -f 4011/4684/22126 4010/4685/22127 4009/4682/22128 -f 4009/4682/22129 4010/4685/22130 4012/4686/22131 -f 4012/4686/22132 3980/4643/22133 4009/4682/22134 -f 4009/4682/22135 3980/4643/22136 3973/4633/22137 -f 3973/4633/22138 3974/4632/22139 4009/4682/22140 -f 4012/4686/22141 4010/4685/22142 4014/4687/22143 -f 4014/4687/22144 4013/4688/22145 4012/4686/22146 -f 4012/4686/22147 4013/4688/22148 4015/4689/22149 -f 4015/4689/22150 3983/4646/22151 4012/4686/22152 -f 4012/4686/22153 3983/4646/22154 3979/4644/22155 -f 3979/4644/22156 3980/4643/22157 4012/4686/22158 -f 4015/4689/22159 4013/4688/22160 4017/4690/22161 -f 4017/4690/22162 4016/4691/22163 4015/4689/22164 -f 4015/4689/22165 4016/4691/22166 4019/4692/22167 -f 4019/4692/22168 4018/4693/22169 4015/4689/22170 -f 4015/4689/22171 4018/4693/22172 3982/4647/22173 -f 3982/4647/22174 3983/4646/22175 4015/4689/22176 -f 4018/4695/22177 4019/4696/22178 4020/4694/22179 -f 4020/4694/22180 3989/4655/22181 4018/4695/22182 -f 4018/4695/22183 3989/4655/22184 3985/4648/22185 -f 3985/4648/22186 3982/4651/22187 4018/4695/22188 -f 4020/4694/22189 4019/4696/22190 4022/4697/22191 -f 4022/4697/22192 4021/4698/22193 4020/4694/22194 -f 4020/4694/22195 4021/4698/22196 4024/4699/22197 -f 4024/4699/22198 4023/4700/22199 4020/4694/22200 -f 4020/4694/22201 4023/4700/22202 3988/4656/22203 -f 3988/4656/22204 3989/4655/22205 4020/4694/22206 -f 4023/4700/22207 4024/4699/22208 4026/4701/22209 -f 4026/4701/22210 4025/4702/22211 4023/4700/22212 -f 4023/4700/22213 4025/4702/22214 3991/4657/22215 -f 3991/4657/22216 3988/4656/22217 4023/4700/22218 -f 4025/4702/22219 4026/4701/22220 3687/4325/22221 -f 3687/4325/22222 4027/4703/22223 4025/4702/22224 -f 4025/4702/22225 4027/4703/22226 3993/4659/22227 -f 3993/4659/22228 3991/4657/22229 4025/4702/22230 -f 4027/4703/22231 3687/4325/22232 3688/4324/22233 -f 3688/4324/22234 4028/4704/22235 4027/4703/22236 -f 4027/4703/22237 4028/4704/22238 3995/4661/22239 -f 3995/4661/22240 3993/4659/22241 4027/4703/22242 -f 4028/4704/22243 3688/4324/22244 3689/4326/22245 -f 3689/4326/22246 4029/4705/22247 4028/4704/22248 -f 4028/4704/22249 4029/4705/22250 4030/4706/22251 -f 4030/4706/22252 3995/4661/22253 4028/4704/22254 -f 4030/4706/22255 3999/4665/22256 3994/4662/22257 -f 3994/4662/22258 3995/4661/22259 4030/4706/22260 -f 4030/4706/22261 4029/4705/22262 4032/4707/22263 -f 4032/4707/22264 4031/4708/22265 4030/4706/22266 -f 4030/4706/22267 4031/4708/22268 4033/4709/22269 -f 4033/4709/22270 3999/4665/22271 4030/4706/22272 -f 4033/4709/22273 4002/4670/22274 3998/4666/22275 -f 3998/4666/22276 3999/4665/22277 4033/4709/22278 -f 4033/4709/22279 4031/4708/22280 4035/4710/22281 -f 4035/4710/22282 4034/4711/22283 4033/4709/22284 -f 4033/4709/22285 4034/4711/22286 4004/4673/22287 -f 4004/4673/22288 4002/4670/22289 4033/4709/22290 -f 4034/4711/22291 4035/4710/22292 4037/4712/22293 -f 4037/4712/22294 4036/4713/22295 4034/4711/22296 -f 4034/4711/22297 4036/4713/22298 4006/4676/22299 -f 4006/4676/22300 4004/4673/22301 4034/4711/22302 -f 4036/4713/22303 4037/4712/22304 4038/4714/22305 -f 4038/4714/22306 4011/4684/22307 4036/4713/22308 -f 4036/4713/22309 4011/4684/22310 4008/4679/22311 -f 4008/4679/22312 4006/4676/22313 4036/4713/22314 -f 4038/4714/22315 4037/4712/22316 4040/4715/22317 -f 4040/4715/22318 4039/4716/22319 4038/4714/22320 -f 4038/4714/22321 4039/4716/22322 4041/4717/22323 -f 4041/4717/22324 4014/4687/22325 4038/4714/22326 -f 4038/4714/22327 4014/4687/22328 4010/4685/22329 -f 4010/4685/22330 4011/4684/22331 4038/4714/22332 -f 4041/4717/22333 4039/4716/22334 4043/4718/22335 -f 4043/4718/22336 4042/4719/22337 4041/4717/22338 -f 4041/4717/22339 4042/4719/22340 4044/4720/22341 -f 4044/4720/22342 4017/4690/22343 4041/4717/22344 -f 4041/4717/22345 4017/4690/22346 4013/4688/22347 -f 4013/4688/22348 4014/4687/22349 4041/4717/22350 -f 3711/4353/22351 3712/4352/22352 4044/4720/22353 -f 4044/4720/22354 4042/4719/22355 3711/4353/22356 -f 3696/4333/22357 4045/4721/22358 4044/4720/22359 -f 4044/4720/22360 3712/4352/22361 3696/4333/22362 -f 4044/4720/22363 4045/4721/22364 4016/4691/22365 -f 4016/4691/22366 4017/4690/22367 4044/4720/22368 -f 3681/4336/22369 4022/4722/22370 4045/4721/22371 -f 4045/4721/22372 3696/4333/22373 3681/4336/22374 -f 4045/4721/22375 4022/4722/22376 4019/4692/22377 -f 4019/4692/22378 4016/4691/22379 4045/4721/22380 -f 4021/4698/22381 4022/4697/22382 3681/4318/22383 -f 3681/4318/22384 4046/4723/22385 4021/4698/22386 -f 4021/4698/22387 4046/4723/22388 3667/4301/22389 -f 3667/4301/22390 4024/4699/22391 4021/4698/22392 -f 4024/4699/22393 3667/4301/22394 3664/4304/22395 -f 3664/4304/22396 4026/4701/22397 4024/4699/22398 -f 4026/4701/22399 3664/4304/22400 3669/4305/22401 -f 3669/4305/22402 3687/4325/22403 4026/4701/22404 -f 3711/4353/22405 4042/4719/22406 4043/4718/22407 -f 4043/4718/22408 4047/4724/22409 3711/4353/22410 -f 4049/4725/22411 4048/4726/22412 4047/4724/22413 -f 4047/4724/22414 4043/4718/22415 4049/4725/22416 -f 4047/4724/22417 4048/4726/22418 4050/4727/22419 -f 4050/4727/22420 3697/4337/22421 4047/4724/22422 -f 4047/4724/22423 3697/4337/22424 3695/4334/22425 -f 3695/4334/22426 3711/4353/22427 4047/4724/22428 -f 4050/4727/22429 4048/4726/22430 3698/4339/22431 -f 3698/4339/22432 3692/4329/22433 4050/4727/22434 -f 4050/4727/22435 3692/4329/22436 3683/4330/22437 -f 3683/4330/22438 3686/4728/22439 4050/4727/22440 -f 4050/4727/22441 3686/4728/22442 3682/4338/22443 -f 3682/4338/22444 3697/4337/22445 4050/4727/22446 -f 4051/4729/22447 3698/4339/22448 4048/4726/22449 -f 4048/4726/22450 4049/4725/22451 4051/4729/22452 -f 3691/4327/22453 3698/4339/22454 4051/4729/22455 -f 4051/4729/22456 4052/4730/22457 3691/4327/22458 -f 4049/4725/22459 4040/4715/22460 4053/4731/22461 -f 4053/4731/22462 4051/4729/22463 4049/4725/22464 -f 4049/4725/22465 4043/4718/22466 4039/4716/22467 -f 4039/4716/22468 4040/4715/22469 4049/4725/22470 -f 4053/4731/22471 4035/4710/22472 4031/4708/22473 -f 4031/4708/22474 4032/4707/22475 4053/4731/22476 -f 4053/4731/22477 4032/4707/22478 4052/4730/22479 -f 4052/4730/22480 4051/4729/22481 4053/4731/22482 -f 4053/4731/22483 4040/4715/22484 4037/4712/22485 -f 4037/4712/22486 4035/4710/22487 4053/4731/22488 -f 3691/4327/22489 4052/4730/22490 3689/4326/22491 -f 3689/4326/22492 3684/4321/22493 3691/4327/22494 -f 4052/4730/22495 4032/4707/22496 4029/4705/22497 -f 4029/4705/22498 3689/4326/22499 4052/4730/22500 -f 3997/4668/22501 3961/4617/22502 4054/4732/22503 -f 4054/4732/22504 3622/4733/22505 3997/4668/22506 -f 4054/4732/22507 3958/4614/22508 3502/4127/22509 -f 3502/4127/22510 3553/4177/22511 4054/4732/22512 -f 4054/4732/22513 3553/4177/22514 3552/4180/22515 -f 3552/4180/22516 3622/4733/22517 4054/4732/22518 -f 4054/4732/22519 3961/4617/22520 3957/4615/22521 -f 3957/4615/22522 3958/4614/22523 4054/4732/22524 -f 3958/4614/22525 3956/4612/22526 3501/4125/22527 -f 3501/4125/22528 3502/4127/22529 3958/4614/22530 -f 3956/4612/22531 3889/4547/22532 3890/4546/22533 -f 3890/4546/22534 3501/4125/22535 3956/4612/22536 -f 3890/4546/22537 3887/4543/22538 3884/4542/22539 -f 3884/4542/22540 4055/4734/22541 3890/4546/22542 -f 3890/4546/22543 4055/4734/22544 3500/4126/22545 -f 3500/4126/22546 3501/4125/22547 3890/4546/22548 -f 4055/4734/22549 3884/4542/22550 3885/4541/22551 -f 3885/4541/22552 4056/4735/22553 4055/4734/22554 -f 4055/4734/22555 4056/4735/22556 4057/4736/22557 -f 4057/4736/22558 3500/4126/22559 4055/4734/22560 -f 4059/4739/22561 4058/4740/22562 4057/4737/22563 -f 4057/4737/22564 4060/4738/22565 4059/4739/22566 -f 4057/4736/22567 4058/4741/22568 3497/4124/22569 -f 3497/4124/22570 3500/4126/22571 4057/4736/22572 -f 3471/4094/22573 3473/4742/22574 4058/4740/22575 -f 4058/4740/22576 4059/4739/22577 3471/4094/22578 -f 4058/4741/22579 3473/4743/22580 3474/4121/22581 -f 3474/4121/22582 3497/4124/22583 4058/4741/22584 -f 3472/4744/22585 3473/4742/22586 3471/4094/22587 -f 3471/4094/22588 3469/4092/22589 3472/4744/22590 -f 3469/4092/22591 3462/4086/22592 3472/4744/22593 -f 4059/4739/22594 4060/4738/22595 4062/4745/22596 -f 4062/4745/22597 4061/4746/22598 4059/4739/22599 -f 4059/4739/22600 4061/4746/22601 3468/4093/22602 -f 3468/4093/22603 3471/4094/22604 4059/4739/22605 -f 4061/4746/22606 4062/4745/22607 4064/4747/22608 -f 4064/4747/22609 4063/4748/22610 4061/4746/22611 -f 4061/4746/22612 4063/4748/22613 3470/4091/22614 -f 3470/4091/22615 3468/4093/22616 4061/4746/22617 -f 4063/4748/22618 4064/4747/22619 3404/4029/22620 -f 3404/4029/22621 3405/4028/22622 4063/4748/22623 -f 4063/4748/22624 3405/4028/22625 3414/4037/22626 -f 3414/4037/22627 3470/4091/22628 4063/4748/22629 -f 3406/4027/22630 3407/4031/22631 3414/4037/22632 -f 3414/4037/22633 3405/4028/22634 3406/4027/22635 -f 3414/4037/22636 3412/4036/22637 3462/4086/22638 -f 3462/4086/22639 3470/4091/22640 3414/4037/22641 -f 3390/4014/22642 3393/4016/22643 3404/4029/22644 -f 3404/4029/22645 3397/4019/22646 3390/4014/22647 -f 3404/4029/22648 4064/4747/22649 4065/4749/22650 -f 4065/4749/22651 3397/4019/22652 3404/4029/22653 -f 4065/4749/22654 4066/4750/22655 3396/4020/22656 -f 3396/4020/22657 3397/4019/22658 4065/4749/22659 -f 4065/4749/22660 4064/4747/22661 4062/4745/22662 -f 4062/4745/22663 4067/4751/22664 4065/4749/22665 -f 4065/4749/22666 4067/4751/22667 4068/4752/22668 -f 4068/4752/22669 4066/4750/22670 4065/4749/22671 -f 4068/4752/22672 4069/4754/22673 4070/4753/22674 -f 4070/4753/22675 4066/4750/22676 4068/4752/22677 -f 4068/4752/22678 4067/4751/22679 4072/4755/22680 -f 4072/4755/22681 4071/4756/22682 4068/4752/22683 -f 4068/4752/22684 4071/4756/22685 4073/4757/22686 -f 4073/4757/22687 4069/4754/22688 4068/4752/22689 -f 4073/4757/22690 4074/4759/22691 4075/4758/22692 -f 4075/4758/22693 4069/4754/22694 4073/4757/22695 -f 3885/4760/22696 3882/4761/22697 4073/4757/22698 -f 4073/4757/22699 4071/4756/22700 3885/4760/22701 -f 3881/4762/22702 4074/4759/22703 4073/4757/22704 -f 4073/4757/22705 3882/4761/22706 3881/4762/22707 -f 4076/4764/22708 4074/4759/22709 3881/4762/22710 -f 3881/4762/22711 3880/4763/22712 4076/4764/22713 -f 4076/4764/22714 3415/4038/22715 3400/4022/22716 -f 3400/4022/22717 3401/4021/22718 4076/4764/22719 -f 4076/4764/22720 3401/4021/22721 4075/4758/22722 -f 4075/4758/22723 4074/4759/22724 4076/4764/22725 -f 3415/4038/22726 4076/4764/22727 3880/4763/22728 -f 3880/4763/22729 3879/4535/22730 3415/4038/22731 -f 3885/4760/22732 4071/4756/22733 4072/4755/22734 -f 4072/4755/22735 4056/4765/22736 3885/4760/22737 -f 4057/4737/22738 4056/4765/22739 4072/4755/22740 -f 4072/4755/22741 4060/4738/22742 4057/4737/22743 -f 4075/4758/22744 3401/4021/22745 3398/4024/22746 -f 3398/4024/22747 4077/4766/22748 4075/4758/22749 -f 4075/4758/22750 4077/4766/22751 4070/4753/22752 -f 4070/4753/22753 4069/4754/22754 4075/4758/22755 -f 4077/4766/22756 3398/4024/22757 3377/3999/22758 -f 3377/3999/22759 3372/3998/22760 4077/4766/22761 -f 4077/4766/22762 3372/3998/22763 3373/3997/22764 -f 3373/3997/22765 4070/4753/22766 4077/4766/22767 -f 3396/4020/22768 3373/3997/22769 3374/3996/22770 -f 3374/3996/22771 3394/4018/22772 3396/4020/22773 -f 3373/3997/22774 3396/4020/22775 4066/4750/22776 -f 4066/4750/22777 4070/4753/22778 3373/3997/22779 -f 3377/3999/22780 3398/4024/22781 3399/4023/22782 -f 3399/4023/22783 3380/4002/22784 3377/3999/22785 -f 4072/4755/22786 4067/4751/22787 4062/4745/22788 -f 4062/4745/22789 4060/4738/22790 4072/4755/22791 -f 3416/4039/22792 3878/4536/22793 3467/4767/22794 -f 3467/4767/22795 3464/4768/22796 3416/4039/22797 -f 3877/4530/22798 3875/4528/22799 3548/4172/22800 -f 3548/4172/22801 3549/4171/22802 3877/4530/22803 -f 3877/4530/22804 3549/4171/22805 4078/4769/22806 -f 4078/4769/22807 3467/4532/22808 3877/4530/22809 -f 3875/4528/22810 3872/4527/22811 3551/4175/22812 -f 3551/4175/22813 3548/4172/22814 3875/4528/22815 -f 3551/4175/22816 3872/4527/22817 3873/4526/22818 -f 3873/4526/22819 3598/4235/22820 3551/4175/22821 -f 3740/4383/22822 3736/4379/22823 3598/4235/22824 -f 3598/4235/22825 3873/4526/22826 3740/4383/22827 -f 3740/4383/22828 3873/4526/22829 3869/4524/22830 -f 3869/4524/22831 3870/4523/22832 3740/4383/22833 -f 3597/4236/22834 3598/4235/22835 3736/4379/22836 -f 3736/4379/22837 3733/4376/22838 3597/4236/22839 -f 3743/4386/22840 3739/4384/22841 3740/4383/22842 -f 3740/4383/22843 3870/4523/22844 3743/4386/22845 -f 3743/4386/22846 3870/4523/22847 3867/4521/22848 -f 3867/4521/22849 3745/4388/22850 3743/4386/22851 -f 3600/4631/22852 3601/4371/22853 3699/4343/22854 -f 3699/4343/22855 3700/4342/22856 3600/4631/22857 -f 3523/4149/22858 3864/4519/22859 3460/4084/22860 -f 3460/4084/22861 3521/4147/22862 3523/4149/22863 -f 3863/4516/22864 3753/4396/22865 3864/4519/22866 -f 3864/4519/22867 3523/4149/22868 3863/4516/22869 -f 3863/4516/22870 3523/4149/22871 3524/4148/22872 -f 3524/4148/22873 3862/4517/22874 3863/4516/22875 -f 3485/4106/22876 3487/4111/22877 3506/4131/22878 -f 3506/4131/22879 3484/4107/22880 3485/4106/22881 -f 3504/4129/22882 3505/4128/22883 4080/4770/22884 -f 4080/4770/22885 4079/4771/22886 3504/4129/22887 -f 3504/4129/22888 4079/4771/22889 3858/4511/22890 -f 3858/4511/22891 3859/4510/22892 3504/4129/22893 -f 4082/4773/22894 4081/4774/22895 4083/4772/22896 -f 4083/4772/22897 3795/4443/22898 4082/4773/22899 -f 4082/4773/22900 3795/4443/22901 3793/4441/22902 -f 3793/4441/22903 3853/4506/22904 4082/4773/22905 -f 4083/4772/22906 4081/4774/22907 4085/4775/22908 -f 4085/4775/22909 4084/4776/22910 4083/4772/22911 -f 3493/4116/22912 3494/4115/22913 4083/4772/22914 -f 4083/4772/22915 4084/4776/22916 3493/4116/22917 -f 3493/4116/22918 4084/4776/22919 4086/4777/22920 -f 4086/4777/22921 3496/4119/22922 3493/4116/22923 -f 3496/4119/22924 4086/4777/22925 3505/4128/22926 -f 3505/4128/22927 3495/4120/22928 3496/4119/22929 -f 4086/4777/22930 4084/4776/22931 4085/4775/22932 -f 4085/4775/22933 4087/4778/22934 4086/4777/22935 -f 4086/4777/22936 4087/4778/22937 4080/4770/22938 -f 4080/4770/22939 3505/4128/22940 4086/4777/22941 -f 4088/4780/22942 3854/4781/22943 3855/4779/22944 -f 3855/4779/22945 3788/4434/22946 4088/4780/22947 -f 4088/4780/22948 3788/4434/22949 3785/4433/22950 -f 3785/4433/22951 3786/4432/22952 4088/4780/22953 -f 3855/4508/22954 3791/4439/22955 3790/4440/22956 -f 3855/4779/22957 3790/4437/22958 3787/4435/22959 -f 3787/4435/22960 3788/4434/22961 3855/4779/22962 -f 3725/4367/22963 3710/4350/22964 3706/4347/22965 -f 3706/4347/22966 3703/4345/22967 3725/4367/22968 -f 3721/4362/22969 3693/4331/22970 3662/4300/22971 -f 3662/4300/22972 3663/4299/22973 3721/4362/22974 -f 3706/4347/22975 3707/4346/22976 3704/4344/22977 -f 3704/4344/22978 3703/4345/22979 3706/4347/22980 -f 3686/4323/22981 3670/4307/22982 3666/4302/22983 -f 3666/4302/22984 3682/4317/22985 3686/4323/22986 -f 3660/4295/22987 3613/4249/22988 3608/4248/22989 -f 3608/4248/22990 3640/4277/22991 3660/4295/22992 -f 3656/4292/22993 3615/4254/22994 3618/4256/22995 -f 3618/4256/22996 3657/4294/22997 3656/4292/22998 -f 3915/4572/22999 3641/4279/23000 3609/4247/23001 -f 3609/4247/23002 3634/4271/23003 3915/4572/23004 -f 3652/4288/23005 3586/4218/23006 3584/4215/23007 -f 3584/4215/23008 3620/4257/23009 3652/4288/23010 -f 3650/4284/23011 3653/4291/23012 3635/4272/23013 -f 3635/4272/23014 3630/4270/23015 3650/4284/23016 -f 3627/4265/23017 3628/4264/23018 3541/4165/23019 -f 3541/4165/23020 3542/4164/23021 3627/4265/23022 -f 3628/4264/23023 3847/4500/23024 3544/4168/23025 -f 3544/4168/23026 3541/4165/23027 3628/4264/23028 -f 3607/4244/23029 3591/4227/23030 3593/4228/23031 -f 3593/4228/23032 3594/4230/23033 3607/4244/23034 -f 3596/4233/23035 3592/4232/23036 3587/4222/23037 -f 3587/4222/23038 3824/4476/23039 3596/4233/23040 -f 3553/4177/23041 3502/4127/23042 3499/4122/23043 -f 3499/4122/23044 3546/4178/23045 3553/4177/23046 -f 3549/4171/23047 3546/4174/23048 3499/4782/23049 -f 3499/4782/23050 4078/4769/23051 3549/4171/23052 -f 3545/4170/23053 3535/4157/23054 3532/4160/23055 -f 3532/4160/23056 3531/4156/23057 3545/4170/23058 -f 3529/4155/23059 3516/4140/23060 3517/4139/23061 -f 3529/4155/23062 3517/4139/23063 3954/4611/23064 -f 3954/4611/23065 3525/4153/23066 3529/4155/23067 -f 3529/4155/23068 3530/4154/23069 3519/4143/23070 -f 3519/4143/23071 3516/4140/23072 3529/4155/23073 -f 3450/4070/23074 3482/4109/23075 3483/4108/23076 -f 3483/4108/23077 3461/4083/23078 3450/4070/23079 -f 3450/4070/23080 3461/4083/23081 4089/4783/23082 -f 4089/4783/23083 3449/4071/23084 3450/4070/23085 -f 3449/4071/23086 4089/4783/23087 3432/4056/23088 -f 3432/4056/23089 3433/4055/23090 3449/4071/23091 -f 3433/4055/23092 3427/4048/23093 3453/4076/23094 -f 3453/4076/23095 3449/4071/23096 3433/4055/23097 -f 3433/4055/23098 3421/4043/23099 3422/4042/23100 -f 3422/4042/23101 3427/4048/23102 3433/4055/23103 -f 4089/4783/23104 3461/4083/23105 3446/4069/23106 -f 3446/4069/23107 3443/4065/23108 4089/4783/23109 -f 4089/4783/23110 3443/4065/23111 3424/4046/23112 -f 3424/4046/23113 3432/4056/23114 4089/4783/23115 -f 4090/4784/23116 3482/4109/23117 3450/4070/23118 -f 3450/4070/23119 3447/4073/23120 4090/4784/23121 -f 4090/4784/23122 4091/4787/23123 4093/4785/23124 -f 4093/4785/23125 4092/4786/23126 4090/4784/23127 -f 4090/4784/23128 4092/4786/23129 3485/4106/23130 -f 3485/4106/23131 3482/4109/23132 4090/4784/23133 -f 3451/4075/23134 4091/4787/23135 4090/4784/23136 -f 4090/4784/23137 3447/4073/23138 3451/4075/23139 -f 4094/4789/23140 4091/4787/23141 3451/4075/23142 -f 3451/4075/23143 4095/4788/23144 4094/4789/23145 -f 4095/4788/23146 3451/4075/23147 3452/4074/23148 -f 3452/4074/23149 4096/4790/23150 4095/4788/23151 -f 4096/4790/23152 3452/4074/23153 4098/4791/23154 -f 4098/4791/23155 4097/4792/23156 4096/4790/23157 -f 4100/4793/23158 4099/4794/23159 4097/4792/23160 -f 4097/4792/23161 4098/4791/23162 4100/4793/23163 -f 4099/4794/23164 4100/4793/23165 4102/4795/23166 -f 4102/4795/23167 4101/4796/23168 4099/4794/23169 -f 4101/4796/23170 4102/4795/23171 4104/4797/23172 -f 4104/4797/23173 4103/4798/23174 4101/4796/23175 -f 4103/4798/23176 4104/4797/23177 4106/4799/23178 -f 4106/4799/23179 4105/4800/23180 4103/4798/23181 -f 4107/4802/23182 4105/4800/23183 4106/4799/23184 -f 4106/4799/23185 4108/4801/23186 4107/4802/23187 -f 4106/4799/23188 4104/4797/23189 3509/4133/23190 -f 3509/4133/23191 3510/4132/23192 4106/4799/23193 -f 4106/4799/23194 3510/4132/23195 4109/4803/23196 -f 4109/4803/23197 4108/4801/23198 4106/4799/23199 -f 4109/4803/23200 3486/4112/23201 3485/4106/23202 -f 3485/4106/23203 4092/4786/23204 4109/4803/23205 -f 4109/4803/23206 4092/4786/23207 4093/4785/23208 -f 4093/4785/23209 4108/4801/23210 4109/4803/23211 -f 4109/4803/23212 3510/4132/23213 3507/4135/23214 -f 3507/4135/23215 3486/4112/23216 4109/4803/23217 -f 4108/4801/23218 4093/4785/23219 4110/4804/23220 -f 4110/4804/23221 4107/4802/23222 4108/4801/23223 -f 4104/4797/23224 4102/4795/23225 4111/4805/23226 -f 4111/4805/23227 3509/4133/23228 4104/4797/23229 -f 4111/4805/23230 4102/4795/23231 4100/4793/23232 -f 4100/4793/23233 4112/4806/23234 4111/4805/23235 -f 4111/4805/23236 4112/4806/23237 3428/4053/23238 -f 3428/4053/23239 3454/4078/23240 4111/4805/23241 -f 4111/4805/23242 3454/4078/23243 3513/4138/23244 -f 3513/4138/23245 3509/4133/23246 4111/4805/23247 -f 4113/4807/23248 4112/4806/23249 4100/4793/23250 -f 4100/4793/23251 4098/4791/23252 4113/4807/23253 -f 3428/4053/23254 4112/4806/23255 4113/4807/23256 -f 4113/4807/23257 3425/4050/23258 3428/4053/23259 -f 4113/4807/23260 4098/4791/23261 3452/4074/23262 -f 3452/4074/23263 3453/4076/23264 4113/4807/23265 -f 4113/4807/23266 3453/4076/23267 3427/4048/23268 -f 3427/4048/23269 3425/4050/23270 4113/4807/23271 -f 4094/4789/23272 4110/4804/23273 4093/4785/23274 -f 4093/4785/23275 4091/4787/23276 4094/4789/23277 -f 3511/4137/23278 3488/4110/23279 3486/4112/23280 -f 3486/4112/23281 3507/4135/23282 3511/4137/23283 -f 3499/4782/23284 3474/4095/23285 3466/4098/23286 -f 3466/4098/23287 4078/4769/23288 3499/4782/23289 -f 3481/4105/23290 3477/4100/23291 3493/4116/23292 -f 3493/4116/23293 3496/4119/23294 3481/4105/23295 -f 3464/4768/23296 3465/4808/23297 3388/4010/23298 -f 3388/4010/23299 3416/4039/23300 3464/4768/23301 -f 4114/4809/23302 3465/4087/23303 3418/4041/23304 -f 3418/4041/23305 3417/4040/23306 4114/4809/23307 -f 3387/4011/23308 3388/4010/23309 3465/4808/23310 -f 3465/4808/23311 4114/4810/23312 3387/4011/23313 -f 4114/4809/23314 3417/4040/23315 3410/4034/23316 -f 3410/4034/23317 4115/4811/23318 4114/4809/23319 -f 4114/4810/23320 4115/4811/23321 4116/4812/23322 -f 4116/4812/23323 3387/4011/23324 4114/4810/23325 -f 4116/4812/23326 4115/4811/23327 4118/4813/23328 -f 4118/4813/23329 4117/4814/23330 4116/4812/23331 -f 4116/4812/23332 4117/4814/23333 4120/4815/23334 -f 4120/4815/23335 4119/4816/23336 4116/4812/23337 -f 4116/4812/23338 4119/4816/23339 3385/4007/23340 -f 3385/4007/23341 3387/4011/23342 4116/4812/23343 -f 4120/4815/23344 3383/4006/23345 3379/4003/23346 -f 3379/4003/23347 4119/4816/23348 4120/4815/23349 -f 4118/4813/23350 4115/4811/23351 3410/4034/23352 -f 3410/4034/23353 3411/4033/23354 4118/4813/23355 -f 3400/4022/23356 3384/4008/23357 3380/4002/23358 -f 3380/4002/23359 3399/4023/23360 3400/4022/23361 -f 3394/4018/23362 3374/3996/23363 3378/4001/23364 -f 3378/4001/23365 3395/4017/23366 3394/4018/23367 -f 3395/4017/23368 3378/4001/23369 3382/4004/23370 -f 3382/4004/23371 3389/4015/23372 3395/4017/23373 -f 3480/4103/23374 3479/4104/23375 3495/4120/23376 -f 3477/4100/23377 3478/4099/23378 3492/4117/23379 -f 3492/4117/23380 3493/4116/23381 3477/4100/23382 -f 3666/4302/23383 3667/4301/23384 4046/4723/23385 -f 4046/4723/23386 3681/4318/23387 3666/4302/23388 -f 3550/4176/23389 3603/4239/23390 3977/4642/23391 -f 3977/4642/23392 3547/4173/23393 3550/4176/23394 -f 3801/4449/23395 3530/4154/23396 3531/4156/23397 -f 3531/4156/23398 4121/4817/23399 3801/4449/23400 -f 3531/4156/23401 3532/4160/23402 3536/4162/23403 -f 3536/4162/23404 4121/4817/23405 3531/4156/23406 -f 3536/4162/23407 3800/4450/23408 3801/4449/23409 -f 3801/4449/23410 4121/4817/23411 3536/4162/23412 -f 3634/4271/23413 3635/4272/23414 3653/4291/23415 -f 3653/4291/23416 3915/4572/23417 3634/4271/23418 -f 3653/4291/23419 3657/4294/23420 3618/4256/23421 -f 3618/4256/23422 3915/4572/23423 3653/4291/23424 -f 3522/4146/23425 3484/4107/23426 3506/4131/23427 -f 3506/4131/23428 3524/4148/23429 3522/4146/23430 -f 3506/4131/23431 3862/4517/23432 3524/4148/23433 -f 3494/4115/23434 3794/4444/23435 3795/4443/23436 -f 3795/4443/23437 4083/4772/23438 3494/4115/23439 -f 3503/4130/23440 3480/4103/23441 3495/4120/23442 -f 3506/4131/23443 3503/4130/23444 3504/4129/23445 -f 3504/4129/23446 3859/4510/23447 3506/4131/23448 -f 3460/4084/23449 3461/4083/23450 3483/4108/23451 -f 3483/4108/23452 3521/4147/23453 3460/4084/23454 -f 3599/4234/23455 3550/4176/23456 3551/4175/23457 -f 3554/4184/23458 3547/4183/23459 3977/4818/23460 -f 3977/4818/23461 3978/4652/23462 3554/4184/23463 -f 3383/4006/23464 4120/4815/23465 3382/4004/23466 -f 3382/4004/23467 3381/4005/23468 3383/4006/23469 -f 3411/4033/23470 3408/4030/23471 3403/4026/23472 -f 4120/4815/23473 4117/4814/23474 3389/4015/23475 -f 3389/4015/23476 3382/4004/23477 4120/4815/23478 -f 4118/4813/23479 3392/4012/23480 3389/4015/23481 -f 3389/4015/23482 4117/4814/23483 4118/4813/23484 -f 3411/4033/23485 3403/4026/23486 3392/4012/23487 -f 3392/4012/23488 4118/4813/23489 3411/4033/23490 -f 3467/4532/23491 4078/4769/23492 3466/4098/23493 -f 3472/4744/23494 3462/4086/23495 3463/4085/23496 -f 3463/4085/23497 3466/4090/23498 3472/4744/23499 -f 3385/4007/23500 4119/4816/23501 3379/4003/23502 -f 3936/4594/23503 3716/4354/23504 3713/4357/23505 -f 3713/4357/23506 3928/4584/23507 3936/4594/23508 -f 3922/4579/23509 3921/4577/23510 3933/4590/23511 -f 3933/4590/23512 3934/4592/23513 3924/4580/23514 -f 3924/4580/23515 3922/4579/23516 3933/4590/23517 -f 3934/4592/23518 3936/4594/23519 3928/4584/23520 -f 3928/4584/23521 3924/4580/23522 3934/4592/23523 -f 3928/4584/23524 3926/4582/23525 3924/4580/23526 -f 4097/4792/23527 4099/4794/23528 4101/4796/23529 -f 4107/4802/23530 4101/4796/23531 4103/4798/23532 -f 4103/4798/23533 4105/4800/23534 4107/4802/23535 -f 4101/4796/23536 4107/4802/23537 4097/4792/23538 -f 4097/4792/23539 4107/4802/23540 4110/4804/23541 -f 4110/4804/23542 4096/4790/23543 4097/4792/23544 -f 4095/4788/23545 4096/4790/23546 4110/4804/23547 -f 4110/4804/23548 4094/4789/23549 4095/4788/23550 -f 3491/4118/23551 3954/4611/23552 3517/4139/23553 -f 3517/4139/23554 3514/4142/23555 3491/4118/23556 -f 3514/4142/23557 3520/4145/23558 3491/4118/23559 -f 3543/4169/23560 3544/4168/23561 3847/4500/23562 -f 3847/4500/23563 3846/4499/23564 3543/4169/23565 -f 3543/4169/23566 3846/4499/23567 3844/4498/23568 -f 3844/4498/23569 3850/4504/23570 3543/4169/23571 -f 3850/4504/23572 3844/4498/23573 3845/4497/23574 -f 3845/4497/23575 3823/4475/23576 3850/4504/23577 -f 3822/4474/23578 3823/4475/23579 3845/4497/23580 -f 3845/4497/23581 3848/4502/23582 3822/4474/23583 -f 3848/4502/23584 4122/4819/23585 3822/4474/23586 -f 3588/4221/23587 3580/4220/23588 4122/4819/23589 -f 4122/4819/23590 3825/4479/23591 3588/4221/23592 -f 3824/4476/23593 3587/4222/23594 3588/4221/23595 -f 3588/4221/23596 3825/4479/23597 3824/4476/23598 -f 4122/4819/23599 3583/4213/23600 3822/4474/23601 -f 3848/4502/23602 3825/4479/23603 4122/4819/23604 -f 3580/4220/23605 3579/4207/23606 4122/4819/23607 -f 3579/4207/23608 3583/4213/23609 4122/4819/23610 -f 3632/4268/23611 3633/4267/23612 3610/4246/23613 -f 4288/4820/23614 4281/4821/23615 4290/4822/23616 -f 4290/4822/23617 4289/4823/23618 4288/4820/23619 -f 4344/4824/23620 4288/4820/23621 4289/4823/23622 -f 4289/4823/23623 4153/4825/23624 4344/4824/23625 -f 4153/4825/23626 4329/4826/23627 4328/4827/23628 -f 4328/4827/23629 4344/4824/23630 4153/4825/23631 -f 4293/4828/23632 4185/4829/23633 4280/4830/23634 -f 4280/4830/23635 4279/4831/23636 4293/4828/23637 -f 4166/4832/23638 4290/4822/23639 4280/4830/23640 -f 4280/4830/23641 4169/4833/23642 4166/4832/23643 -f 4146/4834/23644 4289/4823/23645 4290/4822/23646 -f 4290/4822/23647 4166/4832/23648 4146/4834/23649 -f 4154/4835/23650 4153/4825/23651 4289/4823/23652 -f 4289/4823/23653 4146/4834/23654 4154/4835/23655 -f 4155/4836/23656 4329/4826/23657 4153/4825/23658 -f 4153/4825/23659 4154/4835/23660 4155/4836/23661 -f 4280/4830/23662 4185/4829/23663 4191/4837/23664 -f 4191/4837/23665 4169/4833/23666 4280/4830/23667 -f 4186/4838/23668 4185/4829/23669 4293/4828/23670 -f 4293/4828/23671 4180/4839/23672 4186/4838/23673 -f 4192/4840/23674 4191/4837/23675 4185/4829/23676 -f 4185/4829/23677 4186/4838/23678 4192/4840/23679 -f 4200/4841/23680 4186/4838/23681 4180/4839/23682 -f 4180/4839/23683 4183/4842/23684 4200/4841/23685 -f 4193/4843/23686 4192/4840/23687 4186/4838/23688 -f 4186/4838/23689 4200/4841/23690 4193/4843/23691 -f 4330/4844/23692 4329/4826/23693 4155/4836/23694 -f 4155/4836/23695 4156/4845/23696 4330/4844/23697 -f 4331/4846/23698 4328/4827/23699 4329/4826/23700 -f 4329/4826/23701 4330/4844/23702 4331/4846/23703 -f 4181/4847/23704 4200/4841/23705 4183/4842/23706 -f 4183/4842/23707 4184/4848/23708 4181/4847/23709 -f 4182/4849/23710 4193/4843/23711 4200/4841/23712 -f 4200/4841/23713 4181/4847/23714 4182/4849/23715 -f 4149/4850/23716 4330/4844/23717 4156/4845/23718 -f 4156/4845/23719 4150/4851/23720 4149/4850/23721 -f 4327/4852/23722 4331/4846/23723 4330/4844/23724 -f 4330/4844/23725 4149/4850/23726 4327/4852/23727 -f 4136/4853/23728 4181/4847/23729 4184/4848/23730 -f 4184/4848/23731 4135/4854/23732 4136/4853/23733 -f 4137/4855/23734 4182/4849/23735 4181/4847/23736 -f 4181/4847/23737 4136/4853/23738 4137/4855/23739 -f 4141/4856/23740 4149/4850/23741 4150/4851/23742 -f 4150/4851/23743 4142/4857/23744 4141/4856/23745 -f 4139/4858/23746 4327/4852/23747 4149/4850/23748 -f 4149/4850/23749 4141/4856/23750 4139/4858/23751 -f 4133/4859/23752 4141/4856/23753 4142/4857/23754 -f 4142/4857/23755 4143/4860/23756 4133/4859/23757 -f 4134/4861/23758 4139/4858/23759 4141/4856/23760 -f 4141/4856/23761 4133/4859/23762 4134/4861/23763 -f 4136/4853/23764 4133/4859/23765 4143/4860/23766 -f 4143/4860/23767 4137/4855/23768 4136/4853/23769 -f 4135/4854/23770 4134/4861/23771 4133/4859/23772 -f 4133/4859/23773 4136/4853/23774 4135/4854/23775 -f 4279/4831/23776 4280/4830/23777 4290/4822/23778 -f 4290/4822/23779 4281/4821/23780 4279/4831/23781 -f 4288/4820/23782 4201/4862/23783 4283/4863/23784 -f 4283/4863/23785 4281/4821/23786 4288/4820/23787 -f 4332/4864/23788 4201/4862/23789 4288/4820/23790 -f 4288/4820/23791 4344/4824/23792 4332/4864/23793 -f 4333/4865/23794 4332/4864/23795 4344/4824/23796 -f 4344/4824/23797 4328/4827/23798 4333/4865/23799 -f 4315/4866/23800 4333/4865/23801 4328/4827/23802 -f 4328/4827/23803 4331/4846/23804 4315/4866/23805 -f 4331/4846/23806 4327/4852/23807 4313/4867/23808 -f 4313/4867/23809 4315/4866/23810 4331/4846/23811 -f 4327/4852/23812 4139/4858/23813 4140/4868/23814 -f 4140/4868/23815 4313/4867/23816 4327/4852/23817 -f 4139/4858/23818 4134/4861/23819 4127/4869/23820 -f 4127/4869/23821 4140/4868/23822 4139/4858/23823 -f 4172/4870/23824 4127/4869/23825 4134/4861/23826 -f 4134/4861/23827 4135/4854/23828 4172/4870/23829 -f 4173/4871/23830 4172/4870/23831 4135/4854/23832 -f 4135/4854/23833 4184/4848/23834 4173/4871/23835 -f 4184/4848/23836 4183/4842/23837 4179/4872/23838 -f 4179/4872/23839 4173/4871/23840 4184/4848/23841 -f 4183/4842/23842 4180/4839/23843 4187/4873/23844 -f 4187/4873/23845 4179/4872/23846 4183/4842/23847 -f 4293/4828/23848 4291/4874/23849 4222/4875/23850 -f 4222/4875/23851 4180/4839/23852 4293/4828/23853 -f 4293/4828/23854 4279/4831/23855 4282/4876/23856 -f 4282/4876/23857 4291/4874/23858 4293/4828/23859 -f 4282/4876/23860 4279/4831/23861 4281/4821/23862 -f 4281/4821/23863 4283/4863/23864 4282/4876/23865 -f 4283/4863/23866 4284/4877/23867 4285/4878/23868 -f 4285/4878/23869 4282/4876/23870 4283/4863/23871 -f 4187/4873/23872 4188/4879/23873 4175/4880/23874 -f 4175/4880/23875 4179/4872/23876 4187/4873/23877 -f 4126/4881/23878 4123/4882/23879 4188/4879/23880 -f 4188/4879/23881 4187/4873/23882 4126/4881/23883 -f 4282/4876/23884 4285/4878/23885 4292/4883/23886 -f 4292/4883/23887 4291/4874/23888 4282/4876/23889 -f 4223/4884/23890 4292/4883/23891 4230/4885/23892 -f 4230/4885/23893 4224/4886/23894 4223/4884/23895 -f 4292/4883/23896 4285/4878/23897 4294/4887/23898 -f 4294/4887/23899 4230/4885/23900 4292/4883/23901 -f 4294/4887/23902 4232/4888/23903 4231/4889/23904 -f 4231/4889/23905 4230/4885/23906 4294/4887/23907 -f 4231/4889/23908 4219/4890/23909 4224/4886/23910 -f 4224/4886/23911 4230/4885/23912 4231/4889/23913 -f 4177/4891/23914 4173/4871/23915 4179/4872/23916 -f 4179/4872/23917 4175/4880/23918 4177/4891/23919 -f 4128/4892/23920 4322/4893/23921 4140/4868/23922 -f 4140/4868/23923 4127/4869/23924 4128/4892/23925 -f 4128/4892/23926 4127/4869/23927 4172/4870/23928 -f 4172/4870/23929 4131/4894/23930 4128/4892/23931 -f 4131/4894/23932 4172/4870/23933 4173/4871/23934 -f 4173/4871/23935 4177/4891/23936 4131/4894/23937 -f 4333/4865/23938 4315/4866/23939 4316/4895/23940 -f 4316/4895/23941 4335/4896/23942 4333/4865/23943 -f 4316/4895/23944 4315/4866/23945 4313/4867/23946 -f 4313/4867/23947 4314/4897/23948 4316/4895/23949 -f 4313/4867/23950 4140/4868/23951 4322/4893/23952 -f 4322/4893/23953 4314/4897/23954 4313/4867/23955 -f 4333/4865/23956 4335/4896/23957 4334/4898/23958 -f 4334/4898/23959 4332/4864/23960 4333/4865/23961 -f 4218/4899/23962 4211/4900/23963 4123/4882/23964 -f 4123/4882/23965 4126/4881/23966 4218/4899/23967 -f 4219/4890/23968 4209/4901/23969 4220/4902/23970 -f 4220/4902/23971 4224/4886/23972 4219/4890/23973 -f 4218/4899/23974 4220/4902/23975 4209/4901/23976 -f 4209/4901/23977 4211/4900/23978 4218/4899/23979 -f 4209/4901/23980 4214/4903/23981 4213/4904/23982 -f 4213/4904/23983 4211/4900/23984 4209/4901/23985 -f 4213/4904/23986 4214/4903/23987 4216/4905/23988 -f 4216/4905/23989 4210/4906/23990 4213/4904/23991 -f 4212/4907/23992 4211/4900/23993 4213/4904/23994 -f 4213/4904/23995 4210/4906/23996 4212/4907/23997 -f 4124/4908/23998 4123/4882/23999 4211/4900/24000 -f 4211/4900/24001 4212/4907/24002 4124/4908/24003 -f 4223/4884/24004 4224/4886/24005 4220/4902/24006 -f 4220/4902/24007 4218/4899/24008 4223/4884/24009 -f 4218/4899/24010 4126/4881/24011 4222/4875/24012 -f 4222/4875/24013 4223/4884/24014 4218/4899/24015 -f 4125/4909/24016 4188/4879/24017 4123/4882/24018 -f 4123/4882/24019 4124/4908/24020 4125/4909/24021 -f 4174/4910/24022 4175/4880/24023 4188/4879/24024 -f 4188/4879/24025 4125/4909/24026 4174/4910/24027 -f 4178/4911/24028 4177/4891/24029 4175/4880/24030 -f 4175/4880/24031 4174/4910/24032 4178/4911/24033 -f 4177/4891/24034 4178/4911/24035 4132/4912/24036 -f 4132/4912/24037 4131/4894/24038 4177/4891/24039 -f 4132/4912/24040 4130/4913/24041 4129/4914/24042 -f 4129/4914/24043 4131/4894/24044 4132/4912/24045 -f 4131/4894/24046 4129/4914/24047 4321/4915/24048 -f 4321/4915/24049 4128/4892/24050 4131/4894/24051 -f 4320/4916/24052 4322/4893/24053 4128/4892/24054 -f 4128/4892/24055 4321/4915/24056 4320/4916/24057 -f 4312/4917/24058 4314/4897/24059 4322/4893/24060 -f 4322/4893/24061 4320/4916/24062 4312/4917/24063 -f 4312/4917/24064 4318/4918/24065 4316/4895/24066 -f 4316/4895/24067 4314/4897/24068 4312/4917/24069 -f 4339/4919/24070 4335/4896/24071 4316/4895/24072 -f 4316/4895/24073 4318/4918/24074 4339/4919/24075 -f 4202/4920/24076 4201/4862/24077 4332/4864/24078 -f 4332/4864/24079 4334/4898/24080 4202/4920/24081 -f 4284/4877/24082 4283/4863/24083 4201/4862/24084 -f 4201/4862/24085 4202/4920/24086 4284/4877/24087 -f 4335/4896/24088 4339/4919/24089 4336/4921/24090 -f 4336/4921/24091 4334/4898/24092 4335/4896/24093 -f 4206/4922/24094 4202/4920/24095 4334/4898/24096 -f 4334/4898/24097 4336/4921/24098 4206/4922/24099 -f 4296/4923/24100 4284/4877/24101 4202/4920/24102 -f 4202/4920/24103 4206/4922/24104 4296/4923/24105 -f 4285/4878/24106 4284/4877/24107 4286/4924/24108 -f 4286/4924/24109 4294/4887/24110 4285/4878/24111 -f 4284/4877/24112 4296/4923/24113 4297/4925/24114 -f 4297/4925/24115 4286/4924/24116 4284/4877/24117 -f 4287/4926/24118 4232/4888/24119 4294/4887/24120 -f 4294/4887/24121 4286/4924/24122 4287/4926/24123 -f 4219/4890/24124 4221/4927/24125 4227/4928/24126 -f 4227/4928/24127 4209/4901/24128 4219/4890/24129 -f 4232/4888/24130 4234/4929/24131 4233/4930/24132 -f 4233/4930/24133 4231/4889/24134 4232/4888/24135 -f 4219/4890/24136 4231/4889/24137 4233/4930/24138 -f 4233/4930/24139 4221/4927/24140 4219/4890/24141 -f 4214/4903/24142 4209/4901/24143 4227/4928/24144 -f 4227/4928/24145 4215/4931/24146 4214/4903/24147 -f 4216/4905/24148 4214/4903/24149 4215/4931/24150 -f 4215/4931/24151 4217/4932/24152 4216/4905/24153 -f 4287/4926/24154 4237/4933/24155 4234/4929/24156 -f 4234/4929/24157 4232/4888/24158 4287/4926/24159 -f 4237/4933/24160 4253/4934/24161 4251/4935/24162 -f 4251/4935/24163 4234/4929/24164 4237/4933/24165 -f 4253/4934/24166 4245/4936/24167 4239/4937/24168 -f 4239/4937/24169 4251/4935/24170 4253/4934/24171 -f 4247/4938/24172 4244/4939/24173 4240/4940/24174 -f 4240/4940/24175 4239/4937/24176 4247/4938/24177 -f 4217/4932/24178 4215/4931/24179 4240/4940/24180 -f 4240/4940/24181 4244/4939/24182 4217/4932/24183 -f 4221/4927/24184 4225/4941/24185 4228/4942/24186 -f 4228/4942/24187 4227/4928/24188 4221/4927/24189 -f 4234/4929/24190 4236/4943/24191 4235/4944/24192 -f 4235/4944/24193 4233/4930/24194 4234/4929/24195 -f 4225/4941/24196 4221/4927/24197 4233/4930/24198 -f 4233/4930/24199 4235/4944/24200 4225/4941/24201 -f 4215/4931/24202 4227/4928/24203 4228/4942/24204 -f 4228/4942/24205 4240/4940/24206 4215/4931/24207 -f 4240/4940/24208 4242/4945/24209 4241/4946/24210 -f 4241/4946/24211 4239/4937/24212 4240/4940/24213 -f 4251/4935/24214 4239/4937/24215 4241/4946/24216 -f 4241/4946/24217 4252/4947/24218 4251/4935/24219 -f 4228/4942/24220 4243/4948/24221 4242/4945/24222 -f 4242/4945/24223 4240/4940/24224 4228/4942/24225 -f 4228/4942/24226 4225/4941/24227 4226/4949/24228 -f 4226/4949/24229 4243/4948/24230 4228/4942/24231 -f 4236/4943/24232 4234/4929/24233 4251/4935/24234 -f 4251/4935/24235 4252/4947/24236 4236/4943/24237 -f 4235/4944/24238 4236/4943/24239 4226/4949/24240 -f 4226/4949/24241 4225/4941/24242 4235/4944/24243 -f 4226/4949/24244 4236/4943/24245 4252/4947/24246 -f 4252/4947/24247 4243/4948/24248 4226/4949/24249 -f 4242/4945/24250 4243/4948/24251 4252/4947/24252 -f 4252/4947/24253 4241/4946/24254 4242/4945/24255 -f 4296/4923/24256 4203/4950/24257 4298/4951/24258 -f 4298/4951/24259 4297/4925/24260 4296/4923/24261 -f 4310/4952/24262 4298/4951/24263 4203/4950/24264 -f 4203/4950/24265 4205/4953/24266 4310/4952/24267 -f 4205/4953/24268 4204/4954/24269 4308/4955/24270 -f 4308/4955/24271 4310/4952/24272 4205/4953/24273 -f 4551/4956/24274 4261/4957/24275 4308/4955/24276 -f 4308/4955/24277 4204/4954/24278 4551/4956/24279 -f 4551/4956/24280 4549/4958/24281 4259/4959/24282 -f 4259/4959/24283 4261/4957/24284 4551/4956/24285 -f 4268/4960/24286 4259/4959/24287 4549/4958/24288 -f 4549/4958/24289 4553/4961/24290 4268/4960/24291 -f 4268/4960/24292 4553/4961/24293 4554/4962/24294 -f 4554/4962/24295 4269/4963/24296 4268/4960/24297 -f 4286/4924/24298 4297/4925/24299 4299/4964/24300 -f 4299/4964/24301 4287/4926/24302 4286/4924/24303 -f 4297/4925/24304 4298/4951/24305 4295/4965/24306 -f 4295/4965/24307 4299/4964/24308 4297/4925/24309 -f 4298/4951/24310 4310/4952/24311 4309/4966/24312 -f 4309/4966/24313 4295/4965/24314 4298/4951/24315 -f 4310/4952/24316 4308/4955/24317 4311/4967/24318 -f 4311/4967/24319 4309/4966/24320 4310/4952/24321 -f 4308/4955/24322 4261/4957/24323 4260/4968/24324 -f 4260/4968/24325 4311/4967/24326 4308/4955/24327 -f 4261/4957/24328 4259/4959/24329 4258/4969/24330 -f 4258/4969/24331 4260/4968/24332 4261/4957/24333 -f 4259/4959/24334 4268/4960/24335 4267/4970/24336 -f 4267/4970/24337 4258/4969/24338 4259/4959/24339 -f 4272/4971/24340 4271/4972/24341 4269/4963/24342 -f 4269/4963/24343 4270/4973/24344 4272/4971/24345 -f 4260/4968/24346 4256/4974/24347 4300/4975/24348 -f 4300/4975/24349 4311/4967/24350 4260/4968/24351 -f 4260/4968/24352 4258/4969/24353 4276/4976/24354 -f 4276/4976/24355 4256/4974/24356 4260/4968/24357 -f 4258/4969/24358 4267/4970/24359 4262/4977/24360 -f 4262/4977/24361 4276/4976/24362 4258/4969/24363 -f 4301/4978/24364 4309/4966/24365 4311/4967/24366 -f 4311/4967/24367 4300/4975/24368 4301/4978/24369 -f 4295/4965/24370 4309/4966/24371 4301/4978/24372 -f 4301/4978/24373 4302/4979/24374 4295/4965/24375 -f 4302/4979/24376 4306/4980/24377 4299/4964/24378 -f 4299/4964/24379 4295/4965/24380 4302/4979/24381 -f 4254/4981/24382 4287/4926/24383 4299/4964/24384 -f 4299/4964/24385 4306/4980/24386 4254/4981/24387 -f 4238/4982/24388 4237/4933/24389 4287/4926/24390 -f 4287/4926/24391 4254/4981/24392 4238/4982/24393 -f 4238/4982/24394 4229/4983/24395 4253/4934/24396 -f 4253/4934/24397 4237/4933/24398 4238/4982/24399 -f 4246/4984/24400 4245/4936/24401 4253/4934/24402 -f 4253/4934/24403 4229/4983/24404 4246/4984/24405 -f 4249/4985/24406 4248/4986/24407 4245/4936/24408 -f 4245/4936/24409 4246/4984/24410 4249/4985/24411 -f 4274/4987/24412 4262/4977/24413 4265/4988/24414 -f 4265/4988/24415 4263/4989/24416 4274/4987/24417 -f 4273/4990/24418 4276/4976/24419 4262/4977/24420 -f 4262/4977/24421 4274/4987/24422 4273/4990/24423 -f 4257/4991/24424 4256/4974/24425 4276/4976/24426 -f 4276/4976/24427 4273/4990/24428 4257/4991/24429 -f 4257/4991/24430 4303/4992/24431 4300/4975/24432 -f 4300/4975/24433 4256/4974/24434 4257/4991/24435 -f 4301/4978/24436 4300/4975/24437 4303/4992/24438 -f 4303/4992/24439 4304/4993/24440 4301/4978/24441 -f 4302/4979/24442 4301/4978/24443 4304/4993/24444 -f 4304/4993/24445 4305/4994/24446 4302/4979/24447 -f 4306/4980/24448 4302/4979/24449 4305/4994/24450 -f 4305/4994/24451 4307/4995/24452 4306/4980/24453 -f 4255/4996/24454 4254/4981/24455 4306/4980/24456 -f 4306/4980/24457 4307/4995/24458 4255/4996/24459 -f 4277/4997/24460 4238/4982/24461 4254/4981/24462 -f 4254/4981/24463 4255/4996/24464 4277/4997/24465 -f 4275/4998/24466 4229/4983/24467 4238/4982/24468 -f 4238/4982/24469 4277/4997/24470 4275/4998/24471 -f 4278/4999/24472 4246/4984/24473 4229/4983/24474 -f 4229/4983/24475 4275/4998/24476 4278/4999/24477 -f 4249/4985/24478 4246/4984/24479 4278/4999/24480 -f 4278/4999/24481 4250/5000/24482 4249/4985/24483 -f 4305/4994/24484 4304/4993/24485 4303/4992/24486 -f 4303/4992/24487 4307/4995/24488 4305/4994/24489 -f 4257/4991/24490 4255/4996/24491 4307/4995/24492 -f 4307/4995/24493 4303/4992/24494 4257/4991/24495 -f 4273/4990/24496 4277/4997/24497 4255/4996/24498 -f 4255/4996/24499 4257/4991/24500 4273/4990/24501 -f 4274/4987/24502 4275/4998/24503 4277/4997/24504 -f 4277/4997/24505 4273/4990/24506 4274/4987/24507 -f 4270/4973/24508 4269/4963/24509 4554/4962/24510 -f 4554/4962/24511 4555/5001/24512 4270/4973/24513 -f 4269/4963/24514 4271/4972/24515 4267/4970/24516 -f 4267/4970/24517 4268/4960/24518 4269/4963/24519 -f 4271/4972/24520 4265/4988/24521 4262/4977/24522 -f 4262/4977/24523 4267/4970/24524 4271/4972/24525 -f 4263/4989/24526 4265/4988/24527 4266/5002/24528 -f 4266/5002/24529 4264/5003/24530 4263/4989/24531 -f 4275/4998/24532 4274/4987/24533 4263/4989/24534 -f 4263/4989/24535 4278/4999/24536 4275/4998/24537 -f 4263/4989/24538 4264/5003/24539 4250/5000/24540 -f 4250/5000/24541 4278/4999/24542 4263/4989/24543 -f 4296/4923/24544 4206/4922/24545 4208/5004/24546 -f 4208/5004/24547 4203/4950/24548 4296/4923/24549 -f 4206/4922/24550 4336/4921/24551 4337/5005/24552 -f 4337/5005/24553 4208/5004/24554 4206/4922/24555 -f 4336/4921/24556 4339/4919/24557 4340/5006/24558 -f 4340/5006/24559 4337/5005/24560 4336/4921/24561 -f 4207/5007/24562 4205/4953/24563 4203/4950/24564 -f 4203/4950/24565 4208/5004/24566 4207/5007/24567 -f 4547/5008/24568 4204/4954/24569 4205/4953/24570 -f 4205/4953/24571 4207/5007/24572 4547/5008/24573 -f 4545/5009/24574 4551/4956/24575 4204/4954/24576 -f 4204/4954/24577 4547/5008/24578 4545/5009/24579 -f 4552/5010/24580 4549/4958/24581 4551/4956/24582 -f 4551/4956/24583 4545/5009/24584 4552/5010/24585 -f 4550/5011/24586 4553/4961/24587 4549/4958/24588 -f 4549/4958/24589 4552/5010/24590 4550/5011/24591 -f 4556/5012/24592 4554/4962/24593 4553/4961/24594 -f 4553/4961/24595 4550/5011/24596 4556/5012/24597 -f 4556/5012/24598 4557/5013/24599 4555/5001/24600 -f 4555/5001/24601 4554/4962/24602 4556/5012/24603 -f 4338/5014/24604 4207/5007/24605 4208/5004/24606 -f 4208/5004/24607 4337/5005/24608 4338/5014/24609 -f 4547/5008/24610 4207/5007/24611 4338/5014/24612 -f 4338/5014/24613 4569/5015/24614 4547/5008/24615 -f 4548/5016/24616 4545/5009/24617 4547/5008/24618 -f 4547/5008/24619 4569/5015/24620 4548/5016/24621 -f 4545/5009/24622 4548/5016/24623 4546/5017/24624 -f 4546/5017/24625 4552/5010/24626 4545/5009/24627 -f 4558/5018/24628 4550/5011/24629 4552/5010/24630 -f 4552/5010/24631 4546/5017/24632 4558/5018/24633 -f 4559/5019/24634 4556/5012/24635 4550/5011/24636 -f 4550/5011/24637 4558/5018/24638 4559/5019/24639 -f 4556/5012/24640 4559/5019/24641 4560/5020/24642 -f 4560/5020/24643 4557/5013/24644 4556/5012/24645 -f 4337/5005/24646 4342/5021/24647 4574/5022/24648 -f 4574/5022/24649 4338/5014/24650 4337/5005/24651 -f 4570/5023/24652 4569/5015/24653 4338/5014/24654 -f 4338/5014/24655 4574/5022/24656 4570/5023/24657 -f 4571/5024/24658 4548/5016/24659 4569/5015/24660 -f 4569/5015/24661 4570/5023/24662 4571/5024/24663 -f 4561/5025/24664 4546/5017/24665 4548/5016/24666 -f 4548/5016/24667 4571/5024/24668 4561/5025/24669 -f 4563/5026/24670 4558/5018/24671 4546/5017/24672 -f 4546/5017/24673 4561/5025/24674 4563/5026/24675 -f 4565/5027/24676 4559/5019/24677 4558/5018/24678 -f 4558/5018/24679 4563/5026/24680 4565/5027/24681 -f 4565/5027/24682 4564/5028/24683 4560/5020/24684 -f 4560/5020/24685 4559/5019/24686 4565/5027/24687 -f 4337/5005/24688 4340/5006/24689 4341/5029/24690 -f 4341/5029/24691 4342/5021/24692 4337/5005/24693 -f 4339/4919/24694 4318/4918/24695 4319/5030/24696 -f 4319/5030/24697 4340/5006/24698 4339/4919/24699 -f 4318/4918/24700 4312/4917/24701 4317/5031/24702 -f 4317/5031/24703 4319/5030/24704 4318/4918/24705 -f 4312/4917/24706 4320/4916/24707 4323/5032/24708 -f 4323/5032/24709 4317/5031/24710 4312/4917/24711 -f 4320/4916/24712 4321/4915/24713 4324/5033/24714 -f 4324/5033/24715 4323/5032/24716 4320/4916/24717 -f 4325/5034/24718 4324/5033/24719 4321/4915/24720 -f 4321/4915/24721 4129/4914/24722 4325/5034/24723 -f 4129/4914/24724 4130/4913/24725 4326/5035/24726 -f 4326/5035/24727 4325/5034/24728 4129/4914/24729 -f 4563/5026/24730 4566/5036/24731 4567/5037/24732 -f 4567/5037/24733 4565/5027/24734 4563/5026/24735 -f 4563/5026/24736 4561/5025/24737 4562/5038/24738 -f 4562/5038/24739 4566/5036/24740 4563/5026/24741 -f 4571/5024/24742 4572/5039/24743 4562/5038/24744 -f 4562/5038/24745 4561/5025/24746 4571/5024/24747 -f 4579/5040/24748 4572/5039/24749 4571/5024/24750 -f 4571/5024/24751 4570/5023/24752 4579/5040/24753 -f 4579/5040/24754 4570/5023/24755 4574/5022/24756 -f 4574/5022/24757 4575/5041/24758 4579/5040/24759 -f 4574/5022/24760 4342/5021/24761 4343/5042/24762 -f 4343/5042/24763 4575/5041/24764 4574/5022/24765 -f 4342/5021/24766 4341/5029/24767 4679/5043/24768 -f 4679/5043/24769 4343/5042/24770 4342/5021/24771 -f 4679/5043/24772 4680/5044/24773 4682/5045/24774 -f 4682/5045/24775 4343/5042/24776 4679/5043/24777 -f 4682/5045/24778 4576/5046/24779 4575/5041/24780 -f 4575/5041/24781 4343/5042/24782 4682/5045/24783 -f 4575/5041/24784 4576/5046/24785 4581/5047/24786 -f 4581/5047/24787 4579/5040/24788 4575/5041/24789 -f 4579/5040/24790 4581/5047/24791 4573/5048/24792 -f 4573/5048/24793 4572/5039/24794 4579/5040/24795 -f 4562/5038/24796 4572/5039/24797 4573/5048/24798 -f 4573/5048/24799 4597/5049/24800 4562/5038/24801 -f 4598/5050/24802 4566/5036/24803 4562/5038/24804 -f 4562/5038/24805 4597/5049/24806 4598/5050/24807 -f 4604/5051/24808 4567/5037/24809 4566/5036/24810 -f 4566/5036/24811 4598/5050/24812 4604/5051/24813 -f 4605/5052/24814 4568/5053/24815 4567/5037/24816 -f 4567/5037/24817 4604/5051/24818 4605/5052/24819 -f 4681/5270/24820 4684/5273/24821 4682/5274/24822 -f 4682/5274/24823 4680/5275/24824 4681/5270/24825 -f 4582/5277/24826 4581/5278/24827 4576/5279/24828 -f 4576/5279/24829 4577/5280/24830 4582/5277/24831 -f 4583/5281/24832 4573/5282/24833 4581/5278/24834 -f 4581/5278/24835 4582/5277/24836 4583/5281/24837 -f 4573/5282/24838 4583/5281/24839 4599/5283/24840 -f 4599/5283/24841 4597/5284/24842 4573/5282/24843 -f 4601/5285/24844 4598/5286/24845 4597/5284/24846 -f 4597/5284/24847 4599/5283/24848 4601/5285/24849 -f 4607/5287/24850 4604/5288/24851 4598/5286/24852 -f 4598/5286/24853 4601/5285/24854 4607/5287/24855 -f 4606/5289/24856 4605/5290/24857 4604/5288/24858 -f 4604/5288/24859 4607/5287/24860 4606/5289/24861 -f 4607/5287/24862 4614/5291/24863 4615/5292/24864 -f 4615/5292/24865 4606/5289/24866 4607/5287/24867 -f 4607/5287/24868 4601/5285/24869 4603/5293/24870 -f 4603/5293/24871 4614/5291/24872 4607/5287/24873 -f 4601/5285/24874 4599/5283/24875 4600/5294/24876 -f 4600/5294/24877 4603/5293/24878 4601/5285/24879 -f 4584/5295/24880 4600/5294/24881 4599/5283/24882 -f 4599/5283/24883 4583/5281/24884 4584/5295/24885 -f 4582/5277/24886 4580/5296/24887 4584/5295/24888 -f 4584/5295/24889 4583/5281/24890 4582/5277/24891 -f 4578/5297/24892 4580/5296/24893 4582/5277/24894 -f 4582/5277/24895 4577/5280/24896 4578/5297/24897 -f 4577/5280/24898 4576/5279/24899 4683/5298/24900 -f 4683/5298/24901 4578/5297/24902 4577/5280/24903 -f 4682/5274/24904 4684/5273/24905 4683/5298/24906 -f 4683/5298/24907 4576/5279/24908 4682/5274/24909 -f 4678/5299/24910 4688/5300/24911 4686/5301/24912 -f 4686/5301/24913 4681/5270/24914 4678/5299/24915 -f 4711/5302/24916 4683/5298/24917 4684/5273/24918 -f 4684/5273/24919 4685/5303/24920 4711/5302/24921 -f 4712/5304/24922 4578/5297/24923 4683/5298/24924 -f 4683/5298/24925 4711/5302/24926 4712/5304/24927 -f 4586/5305/24928 4580/5296/24929 4578/5297/24930 -f 4578/5297/24931 4712/5304/24932 4586/5305/24933 -f 4585/5306/24934 4584/5295/24935 4580/5296/24936 -f 4580/5296/24937 4586/5305/24938 4585/5306/24939 -f 4590/5307/24940 4600/5294/24941 4584/5295/24942 -f 4584/5295/24943 4585/5306/24944 4590/5307/24945 -f 4602/5308/24946 4603/5293/24947 4600/5294/24948 -f 4600/5294/24949 4590/5307/24950 4602/5308/24951 -f 4609/5309/24952 4614/5291/24953 4603/5293/24954 -f 4603/5293/24955 4602/5308/24956 4609/5309/24957 -f 4612/5310/24958 4613/5311/24959 4615/5292/24960 -f 4615/5292/24961 4614/5291/24962 4612/5310/24963 -f 4611/5312/24964 4612/5310/24965 4614/5291/24966 -f 4614/5291/24967 4609/5309/24968 4611/5312/24969 -f 4610/5332/24970 4611/5312/24971 4609/5309/24972 -f 4609/5309/24973 4608/5333/24974 4610/5332/24975 -f 4592/5334/24976 4608/5333/24977 4609/5309/24978 -f 4609/5309/24979 4602/5308/24980 4592/5334/24981 -f 4591/5341/24982 4592/5334/24983 4602/5308/24984 -f 4602/5308/24985 4590/5307/24986 4591/5341/24987 -f 4593/5342/24988 4591/5341/24989 4590/5307/24990 -f 4590/5307/24991 4585/5306/24992 4593/5342/24993 -f 4716/5343/24994 4593/5342/24995 4585/5306/24996 -f 4585/5306/24997 4586/5305/24998 4716/5343/24999 -f 4586/5305/25000 4712/5304/25001 4713/5344/25002 -f 4713/5344/25003 4716/5343/25004 4586/5305/25005 -f 4714/5345/25006 4713/5344/25007 4712/5304/25008 -f 4712/5304/25009 4711/5302/25010 4714/5345/25011 -f 4711/5302/25012 4685/5303/25013 4687/5347/25014 -f 4687/5347/25015 4714/5345/25016 4711/5302/25017 -f 4681/5270/25018 4686/5301/25019 4685/5303/25020 -f 4685/5303/25021 4684/5273/25022 4681/5270/25023 -f 4685/5303/25024 4686/5301/25025 4688/5300/25026 -f 4688/5300/25027 4687/5347/25028 4685/5303/25029 -f 4678/5299/25030 4689/5348/25031 4692/5349/25032 -f 4692/5349/25033 4688/5300/25034 4678/5299/25035 -f 4689/5348/25036 4690/5350/25037 4693/5351/25038 -f 4693/5351/25039 4692/5349/25040 4689/5348/25041 -f 4588/5352/25042 4610/5332/25043 4608/5333/25044 -f 4608/5333/25045 4587/5353/25046 4588/5352/25047 -f 4592/5334/25048 4596/5354/25049 4587/5353/25050 -f 4587/5353/25051 4608/5333/25052 4592/5334/25053 -f 4592/5334/25054 4591/5341/25055 4594/5355/25056 -f 4594/5355/25057 4596/5354/25058 4592/5334/25059 -f 4593/5342/25060 4724/5356/25061 4594/5355/25062 -f 4594/5355/25063 4591/5341/25064 4593/5342/25065 -f 4593/5342/25066 4716/5343/25067 4715/5357/25068 -f 4715/5357/25069 4724/5356/25070 4593/5342/25071 -f 4716/5343/25072 4713/5344/25073 4719/5358/25074 -f 4719/5358/25075 4715/5357/25076 4716/5343/25077 -f 4713/5344/25078 4714/5345/25079 4717/5359/25080 -f 4717/5359/25081 4719/5358/25082 4713/5344/25083 -f 4714/5345/25084 4687/5347/25085 4718/5360/25086 -f 4718/5360/25087 4717/5359/25088 4714/5345/25089 -f 4687/5347/25090 4688/5300/25091 4691/5361/25092 -f 4691/5361/25093 4718/5360/25094 4687/5347/25095 -f 4688/5300/25096 4692/5349/25097 4694/5362/25098 -f 4694/5362/25099 4691/5361/25100 4688/5300/25101 -f 4695/5363/25102 4694/5362/25103 4692/5349/25104 -f 4692/5349/25105 4693/5351/25106 4695/5363/25107 -f 4596/5354/25108 4595/5364/25109 4588/5352/25110 -f 4588/5352/25111 4587/5353/25112 4596/5354/25113 -f 4596/5354/25114 4594/5355/25115 4589/5365/25116 -f 4589/5365/25117 4595/5364/25118 4596/5354/25119 -f 4594/5355/25120 4724/5356/25121 4722/5366/25122 -f 4722/5366/25123 4589/5365/25124 4594/5355/25125 -f 4724/5356/25126 4715/5357/25127 4723/5367/25128 -f 4723/5367/25129 4722/5366/25130 4724/5356/25131 -f 4721/5368/25132 4723/5367/25133 4715/5357/25134 -f 4715/5357/25135 4719/5358/25136 4721/5368/25137 -f 4717/5359/25138 4720/5369/25139 4721/5368/25140 -f 4721/5368/25141 4719/5358/25142 4717/5359/25143 -f 4717/5359/25144 4718/5360/25145 4725/5370/25146 -f 4725/5370/25147 4720/5369/25148 4717/5359/25149 -f 4726/5371/25150 4725/5370/25151 4718/5360/25152 -f 4718/5360/25153 4691/5361/25154 4726/5371/25155 -f 4691/5361/25156 4694/5362/25157 4727/5372/25158 -f 4727/5372/25159 4726/5371/25160 4691/5361/25161 -f 4694/5362/25162 4695/5363/25163 4728/5373/25164 -f 4728/5373/25165 4727/5372/25166 4694/5362/25167 -f 4143/4860/25168 4163/5054/25169 4138/5055/25170 -f 4138/5055/25171 4137/4855/25172 4143/4860/25173 -f 4189/5056/25174 4182/4849/25175 4137/4855/25176 -f 4137/4855/25177 4138/5055/25178 4189/5056/25179 -f 4193/4843/25180 4182/4849/25181 4189/5056/25182 -f 4189/5056/25183 4194/5057/25184 4193/4843/25185 -f 4192/4840/25186 4193/4843/25187 4194/5057/25188 -f 4194/5057/25189 4195/5058/25190 4192/4840/25191 -f 4191/4837/25192 4192/4840/25193 4195/5058/25194 -f 4195/5058/25195 4196/5059/25196 4191/4837/25197 -f 4169/4833/25198 4191/4837/25199 4196/5059/25200 -f 4196/5059/25201 4170/5060/25202 4169/4833/25203 -f 4166/4832/25204 4169/4833/25205 4170/5060/25206 -f 4170/5060/25207 4167/5061/25208 4166/4832/25209 -f 4147/5062/25210 4146/4834/25211 4166/4832/25212 -f 4166/4832/25213 4167/5061/25214 4147/5062/25215 -f 4154/4835/25216 4146/4834/25217 4147/5062/25218 -f 4147/5062/25219 4157/5063/25220 4154/4835/25221 -f 4155/4836/25222 4154/4835/25223 4157/5063/25224 -f 4157/5063/25225 4158/5064/25226 4155/4836/25227 -f 4156/4845/25228 4155/4836/25229 4158/5064/25230 -f 4158/5064/25231 4159/5065/25232 4156/4845/25233 -f 4150/4851/25234 4156/4845/25235 4159/5065/25236 -f 4159/5065/25237 4151/5066/25238 4150/4851/25239 -f 4142/4857/25240 4150/4851/25241 4151/5066/25242 -f 4151/5066/25243 4144/5067/25244 4142/4857/25245 -f 4142/4857/25246 4144/5067/25247 4163/5054/25248 -f 4163/5054/25249 4143/4860/25250 4142/4857/25251 -f 4163/5054/25252 4164/5068/25253 4165/5069/25254 -f 4165/5069/25255 4138/5055/25256 4163/5054/25257 -f 4189/5056/25258 4138/5055/25259 4165/5069/25260 -f 4165/5069/25261 4190/5070/25262 4189/5056/25263 -f 4194/5057/25264 4189/5056/25265 4190/5070/25266 -f 4190/5070/25267 4197/5071/25268 4194/5057/25269 -f 4195/5058/25270 4194/5057/25271 4197/5071/25272 -f 4197/5071/25273 4198/5072/25274 4195/5058/25275 -f 4196/5059/25276 4195/5058/25277 4198/5072/25278 -f 4198/5072/25279 4199/5073/25280 4196/5059/25281 -f 4170/5060/25282 4196/5059/25283 4199/5073/25284 -f 4199/5073/25285 4171/5074/25286 4170/5060/25287 -f 4168/5075/25288 4167/5061/25289 4170/5060/25290 -f 4170/5060/25291 4171/5074/25292 4168/5075/25293 -f 4147/5062/25294 4167/5061/25295 4168/5075/25296 -f 4168/5075/25297 4148/5076/25298 4147/5062/25299 -f 4157/5063/25300 4147/5062/25301 4148/5076/25302 -f 4148/5076/25303 4160/5077/25304 4157/5063/25305 -f 4158/5064/25306 4157/5063/25307 4160/5077/25308 -f 4160/5077/25309 4161/5078/25310 4158/5064/25311 -f 4159/5065/25312 4158/5064/25313 4161/5078/25314 -f 4161/5078/25315 4162/5079/25316 4159/5065/25317 -f 4151/5066/25318 4159/5065/25319 4162/5079/25320 -f 4162/5079/25321 4152/5080/25322 4151/5066/25323 -f 4145/5081/25324 4144/5067/25325 4151/5066/25326 -f 4151/5066/25327 4152/5080/25328 4145/5081/25329 -f 4164/5068/25330 4163/5054/25331 4144/5067/25332 -f 4144/5067/25333 4145/5081/25334 4164/5068/25335 -f 4222/4875/25336 4291/4874/25337 4292/4883/25338 -f 4292/4883/25339 4223/4884/25340 4222/4875/25341 -f 4180/4839/25342 4222/4875/25343 4126/4881/25344 -f 4126/4881/25345 4187/4873/25346 4180/4839/25347 -f 4245/4936/25348 4248/4986/25349 4247/4938/25350 -f 4247/4938/25351 4239/4937/25352 4245/4936/25353 -f 4272/4971/25354 4266/5002/25355 4265/4988/25356 -f 4265/4988/25357 4271/4972/25358 4272/4971/25359 -f 4568/5053/25360 4564/5028/25361 4565/5027/25362 -f 4565/5027/25363 4567/5037/25364 4568/5053/25365 -f 4487/5082/25366 4486/5083/25367 4485/5084/25368 -f 4485/5084/25369 4482/5085/25370 4487/5082/25371 -f 4532/5086/25372 4411/5087/25373 4486/5083/25374 -f 4486/5083/25375 4487/5082/25376 4532/5086/25377 -f 4411/5087/25378 4532/5086/25379 4522/5088/25380 -f 4522/5088/25381 4523/5089/25382 4411/5087/25383 -f 4474/5090/25384 4475/5091/25385 4476/5092/25386 -f 4476/5092/25387 4367/5093/25388 4474/5090/25389 -f 4394/5094/25390 4381/5095/25391 4476/5092/25392 -f 4476/5092/25393 4485/5084/25394 4394/5094/25395 -f 4397/5096/25396 4394/5094/25397 4485/5084/25398 -f 4485/5084/25399 4486/5083/25400 4397/5096/25401 -f 4412/5097/25402 4397/5096/25403 4486/5083/25404 -f 4486/5083/25405 4411/5087/25406 4412/5097/25407 -f 4413/5098/25408 4412/5097/25409 4411/5087/25410 -f 4411/5087/25411 4523/5089/25412 4413/5098/25413 -f 4476/5092/25414 4381/5095/25415 4372/5099/25416 -f 4372/5099/25417 4367/5093/25418 4476/5092/25419 -f 4361/5100/25420 4358/5101/25421 4474/5090/25422 -f 4474/5090/25423 4367/5093/25424 4361/5100/25425 -f 4373/5102/25426 4361/5100/25427 4367/5093/25428 -f 4367/5093/25429 4372/5099/25430 4373/5102/25431 -f 4368/5103/25432 4359/5104/25433 4358/5101/25434 -f 4358/5101/25435 4361/5100/25436 4368/5103/25437 -f 4374/5105/25438 4368/5103/25439 4361/5100/25440 -f 4361/5100/25441 4373/5102/25442 4374/5105/25443 -f 4524/5106/25444 4414/5107/25445 4413/5098/25446 -f 4413/5098/25447 4523/5089/25448 4524/5106/25449 -f 4525/5108/25450 4524/5106/25451 4523/5089/25452 -f 4523/5089/25453 4522/5088/25454 4525/5108/25455 -f 4362/5109/25456 4360/5110/25457 4359/5104/25458 -f 4359/5104/25459 4368/5103/25460 4362/5109/25461 -f 4363/5111/25462 4362/5109/25463 4368/5103/25464 -f 4368/5103/25465 4374/5105/25466 4363/5111/25467 -f 4409/5112/25468 4410/5113/25469 4414/5107/25470 -f 4414/5107/25471 4524/5106/25472 4409/5112/25473 -f 4521/5114/25474 4409/5112/25475 4524/5106/25476 -f 4524/5106/25477 4525/5108/25478 4521/5114/25479 -f 4364/5115/25480 4355/5116/25481 4360/5110/25482 -f 4360/5110/25483 4362/5109/25484 4364/5115/25485 -f 4365/5117/25486 4364/5115/25487 4362/5109/25488 -f 4362/5109/25489 4363/5111/25490 4365/5117/25491 -f 4408/5118/25492 4390/5119/25493 4410/5113/25494 -f 4410/5113/25495 4409/5112/25496 4408/5118/25497 -f 4386/5120/25498 4408/5118/25499 4409/5112/25500 -f 4409/5112/25501 4521/5114/25502 4386/5120/25503 -f 4384/5121/25504 4391/5122/25505 4390/5119/25506 -f 4390/5119/25507 4408/5118/25508 4384/5121/25509 -f 4385/5123/25510 4384/5121/25511 4408/5118/25512 -f 4408/5118/25513 4386/5120/25514 4385/5123/25515 -f 4364/5115/25516 4365/5117/25517 4391/5122/25518 -f 4391/5122/25519 4384/5121/25520 4364/5115/25521 -f 4355/5116/25522 4364/5115/25523 4384/5121/25524 -f 4384/5121/25525 4385/5123/25526 4355/5116/25527 -f 4475/5091/25528 4482/5085/25529 4485/5084/25530 -f 4485/5084/25531 4476/5092/25532 4475/5091/25533 -f 4487/5082/25534 4482/5085/25535 4483/5124/25536 -f 4483/5124/25537 4488/5125/25538 4487/5082/25539 -f 4533/5126/25540 4532/5086/25541 4487/5082/25542 -f 4487/5082/25543 4488/5125/25544 4533/5126/25545 -f 4534/5127/25546 4522/5088/25547 4532/5086/25548 -f 4532/5086/25549 4533/5126/25550 4534/5127/25551 -f 4527/5128/25552 4525/5108/25553 4522/5088/25554 -f 4522/5088/25555 4534/5127/25556 4527/5128/25557 -f 4525/5108/25558 4527/5128/25559 4520/5129/25560 -f 4520/5129/25561 4521/5114/25562 4525/5108/25563 -f 4521/5114/25564 4520/5129/25565 4387/5130/25566 -f 4387/5130/25567 4386/5120/25568 4521/5114/25569 -f 4386/5120/25570 4387/5130/25571 4349/5131/25572 -f 4349/5131/25573 4385/5123/25574 4386/5120/25575 -f 4354/5132/25576 4355/5116/25577 4385/5123/25578 -f 4385/5123/25579 4349/5131/25580 4354/5132/25581 -f 4353/5133/25582 4360/5110/25583 4355/5116/25584 -f 4355/5116/25585 4354/5132/25586 4353/5133/25587 -f 4360/5110/25588 4353/5133/25589 4352/5134/25590 -f 4352/5134/25591 4359/5104/25592 4360/5110/25593 -f 4359/5104/25594 4352/5134/25595 4356/5135/25596 -f 4356/5135/25597 4358/5101/25598 4359/5104/25599 -f 4474/5090/25600 4358/5101/25601 4423/5136/25602 -f 4423/5136/25603 4472/5137/25604 4474/5090/25605 -f 4474/5090/25606 4472/5137/25607 4477/5138/25608 -f 4477/5138/25609 4475/5091/25610 4474/5090/25611 -f 4477/5138/25612 4483/5124/25613 4482/5085/25614 -f 4482/5085/25615 4475/5091/25616 4477/5138/25617 -f 4483/5124/25618 4477/5138/25619 4479/5139/25620 -f 4479/5139/25621 4484/5140/25622 4483/5124/25623 -f 4356/5135/25624 4352/5134/25625 4176/5141/25626 -f 4176/5141/25627 4357/5142/25628 4356/5135/25629 -f 4346/5143/25630 4356/5135/25631 4357/5142/25632 -f 4357/5142/25633 4345/5144/25634 4346/5143/25635 -f 4477/5138/25636 4472/5137/25637 4473/5145/25638 -f 4473/5145/25639 4479/5139/25640 4477/5138/25641 -f 4427/5146/25642 4428/5147/25643 4445/5148/25644 -f 4445/5148/25645 4473/5145/25646 4427/5146/25647 -f 4473/5145/25648 4445/5148/25649 4478/5149/25650 -f 4478/5149/25651 4479/5139/25652 4473/5145/25653 -f 4478/5149/25654 4445/5148/25655 4446/5150/25656 -f 4446/5150/25657 4447/5151/25658 4478/5149/25659 -f 4446/5150/25660 4445/5148/25661 4428/5147/25662 -f 4428/5147/25663 4426/5152/25664 4446/5150/25665 -f 4351/5153/25666 4176/5141/25667 4352/5134/25668 -f 4352/5134/25669 4353/5133/25670 4351/5153/25671 -f 4350/5154/25672 4349/5131/25673 4387/5130/25674 -f 4387/5130/25675 4517/5155/25676 4350/5154/25677 -f 4350/5154/25678 4348/5156/25679 4354/5132/25680 -f 4354/5132/25681 4349/5131/25682 4350/5154/25683 -f 4348/5156/25684 4351/5153/25685 4353/5133/25686 -f 4353/5133/25687 4354/5132/25688 4348/5156/25689 -f 4534/5127/25690 4535/5157/25691 4528/5158/25692 -f 4528/5158/25693 4527/5128/25694 4534/5127/25695 -f 4528/5158/25696 4526/5159/25697 4520/5129/25698 -f 4520/5129/25699 4527/5128/25700 4528/5158/25701 -f 4520/5129/25702 4526/5159/25703 4517/5155/25704 -f 4517/5155/25705 4387/5130/25706 4520/5129/25707 -f 4534/5127/25708 4533/5126/25709 4536/5160/25710 -f 4536/5160/25711 4535/5157/25712 4534/5127/25713 -f 4420/5161/25714 4346/5143/25715 4345/5144/25716 -f 4345/5144/25717 4415/5162/25718 4420/5161/25719 -f 4426/5152/25720 4428/5147/25721 4421/5163/25722 -f 4421/5163/25723 4417/5164/25724 4426/5152/25725 -f 4420/5161/25726 4415/5162/25727 4417/5164/25728 -f 4417/5164/25729 4421/5163/25730 4420/5161/25731 -f 4417/5164/25732 4415/5162/25733 4416/5165/25734 -f 4416/5165/25735 4418/5166/25736 4417/5164/25737 -f 4416/5165/25738 4210/4906/25739 4216/4905/25740 -f 4216/4905/25741 4418/5166/25742 4416/5165/25743 -f 4212/4907/25744 4210/4906/25745 4416/5165/25746 -f 4416/5165/25747 4415/5162/25748 4212/4907/25749 -f 4124/4908/25750 4212/4907/25751 4415/5162/25752 -f 4415/5162/25753 4345/5144/25754 4124/4908/25755 -f 4427/5146/25756 4420/5161/25757 4421/5163/25758 -f 4421/5163/25759 4428/5147/25760 4427/5146/25761 -f 4420/5161/25762 4427/5146/25763 4423/5136/25764 -f 4423/5136/25765 4346/5143/25766 4420/5161/25767 -f 4125/4909/25768 4124/4908/25769 4345/5144/25770 -f 4345/5144/25771 4357/5142/25772 4125/4909/25773 -f 4174/4910/25774 4125/4909/25775 4357/5142/25776 -f 4357/5142/25777 4176/5141/25778 4174/4910/25779 -f 4178/4911/25780 4174/4910/25781 4176/5141/25782 -f 4176/5141/25783 4351/5153/25784 4178/4911/25785 -f 4351/5153/25786 4348/5156/25787 4132/4912/25788 -f 4132/4912/25789 4178/4911/25790 4351/5153/25791 -f 4132/4912/25792 4348/5156/25793 4347/5167/25794 -f 4347/5167/25795 4130/4913/25796 4132/4912/25797 -f 4348/5156/25798 4350/5154/25799 4514/5168/25800 -f 4514/5168/25801 4347/5167/25802 4348/5156/25803 -f 4516/5169/25804 4514/5168/25805 4350/5154/25806 -f 4350/5154/25807 4517/5155/25808 4516/5169/25809 -f 4519/5170/25810 4516/5169/25811 4517/5155/25812 -f 4517/5155/25813 4526/5159/25814 4519/5170/25815 -f 4519/5170/25816 4526/5159/25817 4528/5158/25818 -f 4528/5158/25819 4530/5171/25820 4519/5170/25821 -f 4540/5172/25822 4530/5171/25823 4528/5158/25824 -f 4528/5158/25825 4535/5157/25826 4540/5172/25827 -f 4489/5173/25828 4536/5160/25829 4533/5126/25830 -f 4533/5126/25831 4488/5125/25832 4489/5173/25833 -f 4484/5140/25834 4489/5173/25835 4488/5125/25836 -f 4488/5125/25837 4483/5124/25838 4484/5140/25839 -f 4535/5157/25840 4536/5160/25841 4537/5174/25842 -f 4537/5174/25843 4540/5172/25844 4535/5157/25845 -f 4510/5175/25846 4537/5174/25847 4536/5160/25848 -f 4536/5160/25849 4489/5173/25850 4510/5175/25851 -f 4502/5176/25852 4510/5175/25853 4489/5173/25854 -f 4489/5173/25855 4484/5140/25856 4502/5176/25857 -f 4479/5139/25858 4478/5149/25859 4480/5177/25860 -f 4480/5177/25861 4484/5140/25862 4479/5139/25863 -f 4484/5140/25864 4480/5177/25865 4500/5178/25866 -f 4500/5178/25867 4502/5176/25868 4484/5140/25869 -f 4481/5179/25870 4480/5177/25871 4478/5149/25872 -f 4478/5149/25873 4447/5151/25874 4481/5179/25875 -f 4426/5152/25876 4417/5164/25877 4434/5180/25878 -f 4434/5180/25879 4422/5181/25880 4426/5152/25881 -f 4447/5151/25882 4446/5150/25883 4448/5182/25884 -f 4448/5182/25885 4441/5183/25886 4447/5151/25887 -f 4426/5152/25888 4422/5181/25889 4448/5182/25890 -f 4448/5182/25891 4446/5150/25892 4426/5152/25893 -f 4418/5166/25894 4419/5184/25895 4434/5180/25896 -f 4434/5180/25897 4417/5164/25898 4418/5166/25899 -f 4216/4905/25900 4217/4932/25901 4419/5184/25902 -f 4419/5184/25903 4418/5166/25904 4216/4905/25905 -f 4481/5179/25906 4447/5151/25907 4441/5183/25908 -f 4441/5183/25909 4449/5185/25910 4481/5179/25911 -f 4449/5185/25912 4441/5183/25913 4439/5186/25914 -f 4439/5186/25915 4444/5187/25916 4449/5185/25917 -f 4444/5187/25918 4439/5186/25919 4429/5188/25920 -f 4429/5188/25921 4436/5189/25922 4444/5187/25923 -f 4247/4938/25924 4429/5188/25925 4430/5190/25926 -f 4430/5190/25927 4244/4939/25928 4247/4938/25929 -f 4217/4932/25930 4244/4939/25931 4430/5190/25932 -f 4430/5190/25933 4419/5184/25934 4217/4932/25935 -f 4422/5181/25936 4434/5180/25937 4435/5191/25938 -f 4435/5191/25939 4424/5192/25940 4422/5181/25941 -f 4441/5183/25942 4448/5182/25943 4442/5193/25944 -f 4442/5193/25945 4443/5194/25946 4441/5183/25947 -f 4424/5192/25948 4442/5193/25949 4448/5182/25950 -f 4448/5182/25951 4422/5181/25952 4424/5192/25953 -f 4419/5184/25954 4430/5190/25955 4435/5191/25956 -f 4435/5191/25957 4434/5180/25958 4419/5184/25959 -f 4430/5190/25960 4429/5188/25961 4431/5195/25962 -f 4431/5195/25963 4432/5196/25964 4430/5190/25965 -f 4439/5186/25966 4440/5197/25967 4431/5195/25968 -f 4431/5195/25969 4429/5188/25970 4439/5186/25971 -f 4435/5191/25972 4430/5190/25973 4432/5196/25974 -f 4432/5196/25975 4433/5198/25976 4435/5191/25977 -f 4435/5191/25978 4433/5198/25979 4425/5199/25980 -f 4425/5199/25981 4424/5192/25982 4435/5191/25983 -f 4443/5194/25984 4440/5197/25985 4439/5186/25986 -f 4439/5186/25987 4441/5183/25988 4443/5194/25989 -f 4442/5193/25990 4424/5192/25991 4425/5199/25992 -f 4425/5199/25993 4443/5194/25994 4442/5193/25995 -f 4425/5199/25996 4433/5198/25997 4440/5197/25998 -f 4440/5197/25999 4443/5194/26000 4425/5199/26001 -f 4432/5196/26002 4431/5195/26003 4440/5197/26004 -f 4440/5197/26005 4433/5198/26006 4432/5196/26007 -f 4502/5176/26008 4500/5178/26009 4501/5200/26010 -f 4501/5200/26011 4503/5201/26012 4502/5176/26013 -f 4507/5202/26014 4509/5203/26015 4503/5201/26016 -f 4503/5201/26017 4501/5200/26018 4507/5202/26019 -f 4509/5203/26020 4507/5202/26021 4505/5204/26022 -f 4505/5204/26023 4508/5205/26024 4509/5203/26025 -f 4621/5206/26026 4508/5205/26027 4505/5204/26028 -f 4505/5204/26029 4471/5207/26030 4621/5206/26031 -f 4621/5206/26032 4471/5207/26033 4469/5208/26034 -f 4469/5208/26035 4620/5209/26036 4621/5206/26037 -f 4457/5210/26038 4617/5211/26039 4620/5209/26040 -f 4620/5209/26041 4469/5208/26042 4457/5210/26043 -f 4457/5210/26044 4454/5212/26045 4616/5213/26046 -f 4616/5213/26047 4617/5211/26048 4457/5210/26049 -f 4480/5177/26050 4481/5179/26051 4492/5214/26052 -f 4492/5214/26053 4500/5178/26054 4480/5177/26055 -f 4500/5178/26056 4492/5214/26057 4499/5215/26058 -f 4499/5215/26059 4501/5200/26060 4500/5178/26061 -f 4501/5200/26062 4499/5215/26063 4506/5216/26064 -f 4506/5216/26065 4507/5202/26066 4501/5200/26067 -f 4507/5202/26068 4506/5216/26069 4504/5217/26070 -f 4504/5217/26071 4505/5204/26072 4507/5202/26073 -f 4505/5204/26074 4504/5217/26075 4470/5218/26076 -f 4470/5218/26077 4471/5207/26078 4505/5204/26079 -f 4471/5207/26080 4470/5218/26081 4468/5219/26082 -f 4468/5219/26083 4469/5208/26084 4471/5207/26085 -f 4469/5208/26086 4468/5219/26087 4456/5220/26088 -f 4456/5220/26089 4457/5210/26090 4469/5208/26091 -f 4272/4971/26092 4270/4973/26093 4454/5212/26094 -f 4454/5212/26095 4455/5221/26096 4272/4971/26097 -f 4470/5218/26098 4504/5217/26099 4493/5222/26100 -f 4493/5222/26101 4466/5223/26102 4470/5218/26103 -f 4470/5218/26104 4466/5223/26105 4462/5224/26106 -f 4462/5224/26107 4468/5219/26108 4470/5218/26109 -f 4468/5219/26110 4462/5224/26111 4453/5225/26112 -f 4453/5225/26113 4456/5220/26114 4468/5219/26115 -f 4494/5226/26116 4493/5222/26117 4504/5217/26118 -f 4504/5217/26119 4506/5216/26120 4494/5226/26121 -f 4499/5215/26122 4495/5227/26123 4494/5226/26124 -f 4494/5226/26125 4506/5216/26126 4499/5215/26127 -f 4495/5227/26128 4499/5215/26129 4492/5214/26130 -f 4492/5214/26131 4490/5228/26132 4495/5227/26133 -f 4464/5229/26134 4490/5228/26135 4492/5214/26136 -f 4492/5214/26137 4481/5179/26138 4464/5229/26139 -f 4450/5230/26140 4464/5229/26141 4481/5179/26142 -f 4481/5179/26143 4449/5185/26144 4450/5230/26145 -f 4450/5230/26146 4449/5185/26147 4444/5187/26148 -f 4444/5187/26149 4438/5231/26150 4450/5230/26151 -f 4437/5232/26152 4438/5231/26153 4444/5187/26154 -f 4444/5187/26155 4436/5189/26156 4437/5232/26157 -f 4249/4985/26158 4437/5232/26159 4436/5189/26160 -f 4436/5189/26161 4248/4986/26162 4249/4985/26163 -f 4459/5233/26164 4451/5234/26165 4452/5235/26166 -f 4452/5235/26167 4453/5225/26168 4459/5233/26169 -f 4461/5236/26170 4459/5233/26171 4453/5225/26172 -f 4453/5225/26173 4462/5224/26174 4461/5236/26175 -f 4467/5237/26176 4461/5236/26177 4462/5224/26178 -f 4462/5224/26179 4466/5223/26180 4467/5237/26181 -f 4467/5237/26182 4466/5223/26183 4493/5222/26184 -f 4493/5222/26185 4496/5238/26186 4467/5237/26187 -f 4494/5226/26188 4497/5239/26189 4496/5238/26190 -f 4496/5238/26191 4493/5222/26192 4494/5226/26193 -f 4495/5227/26194 4498/5240/26195 4497/5239/26196 -f 4497/5239/26197 4494/5226/26198 4495/5227/26199 -f 4490/5228/26200 4491/5241/26201 4498/5240/26202 -f 4498/5240/26203 4495/5227/26204 4490/5228/26205 -f 4465/5242/26206 4491/5241/26207 4490/5228/26208 -f 4490/5228/26209 4464/5229/26210 4465/5242/26211 -f 4463/5243/26212 4465/5242/26213 4464/5229/26214 -f 4464/5229/26215 4450/5230/26216 4463/5243/26217 -f 4460/5244/26218 4463/5243/26219 4450/5230/26220 -f 4450/5230/26221 4438/5231/26222 4460/5244/26223 -f 4458/5245/26224 4460/5244/26225 4438/5231/26226 -f 4438/5231/26227 4437/5232/26228 4458/5245/26229 -f 4249/4985/26230 4250/5000/26231 4458/5245/26232 -f 4458/5245/26233 4437/5232/26234 4249/4985/26235 -f 4498/5240/26236 4491/5241/26237 4496/5238/26238 -f 4496/5238/26239 4497/5239/26240 4498/5240/26241 -f 4467/5237/26242 4496/5238/26243 4491/5241/26244 -f 4491/5241/26245 4465/5242/26246 4467/5237/26247 -f 4461/5236/26248 4467/5237/26249 4465/5242/26250 -f 4465/5242/26251 4463/5243/26252 4461/5236/26253 -f 4459/5233/26254 4461/5236/26255 4463/5243/26256 -f 4463/5243/26257 4460/5244/26258 4459/5233/26259 -f 4270/4973/26260 4555/5001/26261 4616/5213/26262 -f 4616/5213/26263 4454/5212/26264 4270/4973/26265 -f 4454/5212/26266 4457/5210/26267 4456/5220/26268 -f 4456/5220/26269 4455/5221/26270 4454/5212/26271 -f 4455/5221/26272 4456/5220/26273 4453/5225/26274 -f 4453/5225/26275 4452/5235/26276 4455/5221/26277 -f 4451/5234/26278 4264/5003/26279 4266/5002/26280 -f 4266/5002/26281 4452/5235/26282 4451/5234/26283 -f 4460/5244/26284 4458/5245/26285 4451/5234/26286 -f 4451/5234/26287 4459/5233/26288 4460/5244/26289 -f 4451/5234/26290 4458/5245/26291 4250/5000/26292 -f 4250/5000/26293 4264/5003/26294 4451/5234/26295 -f 4502/5176/26296 4503/5201/26297 4512/5246/26298 -f 4512/5246/26299 4510/5175/26300 4502/5176/26301 -f 4510/5175/26302 4512/5246/26303 4538/5247/26304 -f 4538/5247/26305 4537/5174/26306 4510/5175/26307 -f 4537/5174/26308 4538/5247/26309 4541/5248/26310 -f 4541/5248/26311 4540/5172/26312 4537/5174/26313 -f 4511/5249/26314 4512/5246/26315 4503/5201/26316 -f 4503/5201/26317 4509/5203/26318 4511/5249/26319 -f 4629/5250/26320 4511/5249/26321 4509/5203/26322 -f 4509/5203/26323 4508/5205/26324 4629/5250/26325 -f 4628/5251/26326 4629/5250/26327 4508/5205/26328 -f 4508/5205/26329 4621/5206/26330 4628/5251/26331 -f 4622/5252/26332 4628/5251/26333 4621/5206/26334 -f 4621/5206/26335 4620/5209/26336 4622/5252/26337 -f 4619/5253/26338 4622/5252/26339 4620/5209/26340 -f 4620/5209/26341 4617/5211/26342 4619/5253/26343 -f 4618/5254/26344 4619/5253/26345 4617/5211/26346 -f 4617/5211/26347 4616/5213/26348 4618/5254/26349 -f 4618/5254/26350 4616/5213/26351 4555/5001/26352 -f 4555/5001/26353 4557/5013/26354 4618/5254/26355 -f 4539/5255/26356 4538/5247/26357 4512/5246/26358 -f 4512/5246/26359 4511/5249/26360 4539/5255/26361 -f 4629/5250/26362 4638/5256/26363 4539/5255/26364 -f 4539/5255/26365 4511/5249/26366 4629/5250/26367 -f 4630/5257/26368 4638/5256/26369 4629/5250/26370 -f 4629/5250/26371 4628/5251/26372 4630/5257/26373 -f 4628/5251/26374 4622/5252/26375 4625/5258/26376 -f 4625/5258/26377 4630/5257/26378 4628/5251/26379 -f 4624/5259/26380 4625/5258/26381 4622/5252/26382 -f 4622/5252/26383 4619/5253/26384 4624/5259/26385 -f 4623/5260/26386 4624/5259/26387 4619/5253/26388 -f 4619/5253/26389 4618/5254/26390 4623/5260/26391 -f 4618/5254/26392 4557/5013/26393 4560/5020/26394 -f 4560/5020/26395 4623/5260/26396 4618/5254/26397 -f 4538/5247/26398 4539/5255/26399 4642/5261/26400 -f 4642/5261/26401 4543/5262/26402 4538/5247/26403 -f 4639/5263/26404 4642/5261/26405 4539/5255/26406 -f 4539/5255/26407 4638/5256/26408 4639/5263/26409 -f 4640/5264/26410 4639/5263/26411 4638/5256/26412 -f 4638/5256/26413 4630/5257/26414 4640/5264/26415 -f 4626/5265/26416 4640/5264/26417 4630/5257/26418 -f 4630/5257/26419 4625/5258/26420 4626/5265/26421 -f 4632/5266/26422 4626/5265/26423 4625/5258/26424 -f 4625/5258/26425 4624/5259/26426 4632/5266/26427 -f 4631/5267/26428 4632/5266/26429 4624/5259/26430 -f 4624/5259/26431 4623/5260/26432 4631/5267/26433 -f 4631/5267/26434 4623/5260/26435 4560/5020/26436 -f 4560/5020/26437 4564/5028/26438 4631/5267/26439 -f 4538/5247/26440 4543/5262/26441 4542/5268/26442 -f 4542/5268/26443 4541/5248/26444 4538/5247/26445 -f 4540/5172/26446 4541/5248/26447 4531/5269/26448 -f 4531/5269/26449 4530/5171/26450 4540/5172/26451 -f 4530/5171/26452 4531/5269/26453 4529/5271/26454 -f 4529/5271/26455 4519/5170/26456 4530/5171/26457 -f 4519/5170/26458 4529/5271/26459 4518/5272/26460 -f 4518/5272/26461 4516/5169/26462 4519/5170/26463 -f 4516/5169/26464 4518/5272/26465 4515/5276/26466 -f 4515/5276/26467 4514/5168/26468 4516/5169/26469 -f 4513/5313/26470 4347/5167/26471 4514/5168/26472 -f 4514/5168/26473 4515/5276/26474 4513/5313/26475 -f 4347/5167/26476 4513/5313/26477 4326/5035/26478 -f 4326/5035/26479 4130/4913/26480 4347/5167/26481 -f 4632/5266/26482 4631/5267/26483 4633/5314/26484 -f 4633/5314/26485 4634/5315/26486 4632/5266/26487 -f 4632/5266/26488 4634/5315/26489 4627/5316/26490 -f 4627/5316/26491 4626/5265/26492 4632/5266/26493 -f 4640/5264/26494 4626/5265/26495 4627/5316/26496 -f 4627/5316/26497 4641/5317/26498 4640/5264/26499 -f 4649/5318/26500 4639/5263/26501 4640/5264/26502 -f 4640/5264/26503 4641/5317/26504 4649/5318/26505 -f 4649/5318/26506 4643/5319/26507 4642/5261/26508 -f 4642/5261/26509 4639/5263/26510 4649/5318/26511 -f 4642/5261/26512 4643/5319/26513 4544/5320/26514 -f 4544/5320/26515 4543/5262/26516 4642/5261/26517 -f 4543/5262/26518 4544/5320/26519 4698/5321/26520 -f 4698/5321/26521 4542/5268/26522 4543/5262/26523 -f 4698/5321/26524 4544/5320/26525 4701/5322/26526 -f 4701/5322/26527 4699/5323/26528 4698/5321/26529 -f 4701/5322/26530 4544/5320/26531 4643/5319/26532 -f 4643/5319/26533 4644/5324/26534 4701/5322/26535 -f 4643/5319/26536 4649/5318/26537 4647/5325/26538 -f 4647/5325/26539 4644/5324/26540 4643/5319/26541 -f 4649/5318/26542 4641/5317/26543 4635/5326/26544 -f 4635/5326/26545 4647/5325/26546 4649/5318/26547 -f 4627/5316/26548 4658/5327/26549 4635/5326/26550 -f 4635/5326/26551 4641/5317/26552 4627/5316/26553 -f 4654/5328/26554 4658/5327/26555 4627/5316/26556 -f 4627/5316/26557 4634/5315/26558 4654/5328/26559 -f 4653/5329/26560 4654/5328/26561 4634/5315/26562 -f 4634/5315/26563 4633/5314/26564 4653/5329/26565 -f 4605/5052/26566 4653/5329/26567 4633/5314/26568 -f 4633/5314/26569 4568/5053/26570 4605/5052/26571 -f 4700/5374/26572 4699/5375/26573 4701/5377/26574 -f 4701/5377/26575 4704/5378/26576 4700/5374/26577 -f 4648/5379/26578 4645/5380/26579 4644/5381/26580 -f 4644/5381/26581 4647/5382/26582 4648/5379/26583 -f 4636/5383/26584 4648/5379/26585 4647/5382/26586 -f 4647/5382/26587 4635/5384/26588 4636/5383/26589 -f 4635/5384/26590 4658/5385/26591 4659/5386/26592 -f 4659/5386/26593 4636/5383/26594 4635/5384/26595 -f 4655/5387/26596 4659/5386/26597 4658/5385/26598 -f 4658/5385/26599 4654/5388/26600 4655/5387/26601 -f 4656/5389/26602 4655/5387/26603 4654/5388/26604 -f 4654/5388/26605 4653/5390/26606 4656/5389/26607 -f 4606/5460/26608 4656/5389/26609 4653/5390/26610 -f 4653/5390/26611 4605/5461/26612 4606/5460/26613 -f 4656/5389/26614 4606/5460/26615 4615/5462/26616 -f 4615/5462/26617 4663/5391/26618 4656/5389/26619 -f 4656/5389/26620 4663/5391/26621 4657/5392/26622 -f 4657/5392/26623 4655/5387/26624 4656/5389/26625 -f 4655/5387/26626 4657/5392/26627 4660/5393/26628 -f 4660/5393/26629 4659/5386/26630 4655/5387/26631 -f 4637/5394/26632 4636/5383/26633 4659/5386/26634 -f 4659/5386/26635 4660/5393/26636 4637/5394/26637 -f 4648/5379/26638 4636/5383/26639 4637/5394/26640 -f 4637/5394/26641 4650/5396/26642 4648/5379/26643 -f 4646/5397/26644 4645/5380/26645 4648/5379/26646 -f 4648/5379/26647 4650/5396/26648 4646/5397/26649 -f 4645/5380/26650 4646/5397/26651 4702/5398/26652 -f 4702/5398/26653 4644/5381/26654 4645/5380/26655 -f 4701/5377/26656 4644/5381/26657 4702/5398/26658 -f 4702/5398/26659 4704/5378/26660 4701/5377/26661 -f 4696/5399/26662 4700/5374/26663 4705/5400/26664 -f 4705/5400/26665 4697/5401/26666 4696/5399/26667 -f 4729/5402/26668 4703/5403/26669 4704/5378/26670 -f 4704/5378/26671 4702/5398/26672 4729/5402/26673 -f 4730/5404/26674 4729/5402/26675 4702/5398/26676 -f 4702/5398/26677 4646/5397/26678 4730/5404/26679 -f 4652/5405/26680 4730/5404/26681 4646/5397/26682 -f 4646/5397/26683 4650/5396/26684 4652/5405/26685 -f 4651/5406/26686 4652/5405/26687 4650/5396/26688 -f 4650/5396/26689 4637/5394/26690 4651/5406/26691 -f 4670/5407/26692 4651/5406/26693 4637/5394/26694 -f 4637/5394/26695 4660/5393/26696 4670/5407/26697 -f 4661/5408/26698 4670/5407/26699 4660/5393/26700 -f 4660/5393/26701 4657/5392/26702 4661/5408/26703 -f 4665/5409/26704 4661/5408/26705 4657/5392/26706 -f 4657/5392/26707 4663/5391/26708 4665/5409/26709 -f 4662/5410/26710 4663/5391/26711 4615/5462/26712 -f 4615/5462/26713 4613/5463/26714 4662/5410/26715 -f 4664/5411/26716 4665/5409/26717 4663/5391/26718 -f 4663/5391/26719 4662/5410/26720 4664/5411/26721 -f 4669/5412/26722 4666/5413/26723 4665/5409/26724 -f 4665/5409/26725 4664/5411/26726 4669/5412/26727 -f 4671/5414/26728 4661/5408/26729 4665/5409/26730 -f 4665/5409/26731 4666/5413/26732 4671/5414/26733 -f 4672/5415/26734 4670/5407/26735 4661/5408/26736 -f 4661/5408/26737 4671/5414/26738 4672/5415/26739 -f 4673/5416/26740 4651/5406/26741 4670/5407/26742 -f 4670/5407/26743 4672/5415/26744 4673/5416/26745 -f 4733/5417/26746 4652/5405/26747 4651/5406/26748 -f 4651/5406/26749 4673/5416/26750 4733/5417/26751 -f 4652/5405/26752 4733/5417/26753 4731/5418/26754 -f 4731/5418/26755 4730/5404/26756 4652/5405/26757 -f 4732/5419/26758 4729/5402/26759 4730/5404/26760 -f 4730/5404/26761 4731/5418/26762 4732/5419/26763 -f 4729/5402/26764 4732/5419/26765 4706/5420/26766 -f 4706/5420/26767 4703/5403/26768 4729/5402/26769 -f 4700/5374/26770 4704/5378/26771 4703/5403/26772 -f 4703/5403/26773 4705/5400/26774 4700/5374/26775 -f 4703/5403/26776 4706/5420/26777 4697/5401/26778 -f 4697/5401/26779 4705/5400/26780 4703/5403/26781 -f 4696/5399/26782 4697/5401/26783 4708/5421/26784 -f 4708/5421/26785 4707/5422/26786 4696/5399/26787 -f 4707/5422/26788 4708/5421/26789 4693/5465/26790 -f 4693/5465/26791 4690/5464/26792 4707/5422/26793 -f 4668/5423/26794 4667/5424/26795 4666/5413/26796 -f 4666/5413/26797 4669/5412/26798 4668/5423/26799 -f 4671/5414/26800 4666/5413/26801 4667/5424/26802 -f 4667/5424/26803 4676/5425/26804 4671/5414/26805 -f 4671/5414/26806 4676/5425/26807 4674/5426/26808 -f 4674/5426/26809 4672/5415/26810 4671/5414/26811 -f 4673/5416/26812 4672/5415/26813 4674/5426/26814 -f 4674/5426/26815 4740/5427/26816 4673/5416/26817 -f 4673/5416/26818 4740/5427/26819 4734/5428/26820 -f 4734/5428/26821 4733/5417/26822 4673/5416/26823 -f 4733/5417/26824 4734/5428/26825 4737/5429/26826 -f 4737/5429/26827 4731/5418/26828 4733/5417/26829 -f 4731/5418/26830 4737/5429/26831 4735/5430/26832 -f 4735/5430/26833 4732/5419/26834 4731/5418/26835 -f 4732/5419/26836 4735/5430/26837 4736/5431/26838 -f 4736/5431/26839 4706/5420/26840 4732/5419/26841 -f 4706/5420/26842 4736/5431/26843 4710/5432/26844 -f 4710/5432/26845 4697/5401/26846 4706/5420/26847 -f 4697/5401/26848 4710/5432/26849 4709/5433/26850 -f 4709/5433/26851 4708/5421/26852 4697/5401/26853 -f 4695/5466/26854 4693/5465/26855 4708/5421/26856 -f 4708/5421/26857 4709/5433/26858 4695/5466/26859 -f 4676/5425/26860 4667/5424/26861 4668/5423/26862 -f 4668/5423/26863 4677/5434/26864 4676/5425/26865 -f 4676/5425/26866 4677/5434/26867 4675/5435/26868 -f 4675/5435/26869 4674/5426/26870 4676/5425/26871 -f 4674/5426/26872 4675/5435/26873 4741/5436/26874 -f 4741/5436/26875 4740/5427/26876 4674/5426/26877 -f 4740/5427/26878 4741/5436/26879 4742/5437/26880 -f 4742/5437/26881 4734/5428/26882 4740/5427/26883 -f 4739/5438/26884 4737/5429/26885 4734/5428/26886 -f 4734/5428/26887 4742/5437/26888 4739/5438/26889 -f 4735/5430/26890 4737/5429/26891 4739/5438/26892 -f 4739/5438/26893 4738/5439/26894 4735/5430/26895 -f 4735/5430/26896 4738/5439/26897 4744/5440/26898 -f 4744/5440/26899 4736/5431/26900 4735/5430/26901 -f 4745/5441/26902 4710/5432/26903 4736/5431/26904 -f 4736/5431/26905 4744/5440/26906 4745/5441/26907 -f 4710/5432/26908 4745/5441/26909 4743/5442/26910 -f 4743/5442/26911 4709/5433/26912 4710/5432/26913 -f 4709/5433/26914 4743/5442/26915 4728/5467/26916 -f 4728/5467/26917 4695/5466/26918 4709/5433/26919 -f 4391/5122/26920 4365/5117/26921 4366/5330/26922 -f 4366/5330/26923 4388/5331/26924 4391/5122/26925 -f 4369/5335/26926 4366/5330/26927 4365/5117/26928 -f 4365/5117/26929 4363/5111/26930 4369/5335/26931 -f 4374/5105/26932 4375/5336/26933 4369/5335/26934 -f 4369/5335/26935 4363/5111/26936 4374/5105/26937 -f 4373/5102/26938 4376/5337/26939 4375/5336/26940 -f 4375/5336/26941 4374/5105/26942 4373/5102/26943 -f 4372/5099/26944 4377/5338/26945 4376/5337/26946 -f 4376/5337/26947 4373/5102/26948 4372/5099/26949 -f 4381/5095/26950 4382/5339/26951 4377/5338/26952 -f 4377/5338/26953 4372/5099/26954 4381/5095/26955 -f 4394/5094/26956 4395/5340/26957 4382/5339/26958 -f 4382/5339/26959 4381/5095/26960 4394/5094/26961 -f 4398/5346/26962 4395/5340/26963 4394/5094/26964 -f 4394/5094/26965 4397/5096/26966 4398/5346/26967 -f 4412/5097/26968 4402/5376/26969 4398/5346/26970 -f 4398/5346/26971 4397/5096/26972 4412/5097/26973 -f 4413/5098/26974 4403/5395/26975 4402/5376/26976 -f 4402/5376/26977 4412/5097/26978 4413/5098/26979 -f 4414/5107/26980 4404/5443/26981 4403/5395/26982 -f 4403/5395/26983 4413/5098/26984 4414/5107/26985 -f 4410/5113/26986 4400/5444/26987 4404/5443/26988 -f 4404/5443/26989 4414/5107/26990 4410/5113/26991 -f 4390/5119/26992 4392/5445/26993 4400/5444/26994 -f 4400/5444/26995 4410/5113/26996 4390/5119/26997 -f 4390/5119/26998 4391/5122/26999 4388/5331/27000 -f 4388/5331/27001 4392/5445/27002 4390/5119/27003 -f 4388/5331/27004 4366/5330/27005 4371/5446/27006 -f 4371/5446/27007 4389/5447/27008 4388/5331/27009 -f 4369/5335/27010 4370/5448/27011 4371/5446/27012 -f 4371/5446/27013 4366/5330/27014 4369/5335/27015 -f 4375/5336/27016 4378/5449/27017 4370/5448/27018 -f 4370/5448/27019 4369/5335/27020 4375/5336/27021 -f 4376/5337/27022 4379/5450/27023 4378/5449/27024 -f 4378/5449/27025 4375/5336/27026 4376/5337/27027 -f 4377/5338/27028 4380/5451/27029 4379/5450/27030 -f 4379/5450/27031 4376/5337/27032 4377/5338/27033 -f 4382/5339/27034 4383/5452/27035 4380/5451/27036 -f 4380/5451/27037 4377/5338/27038 4382/5339/27039 -f 4396/5453/27040 4383/5452/27041 4382/5339/27042 -f 4382/5339/27043 4395/5340/27044 4396/5453/27045 -f 4398/5346/27046 4399/5454/27047 4396/5453/27048 -f 4396/5453/27049 4395/5340/27050 4398/5346/27051 -f 4402/5376/27052 4405/5455/27053 4399/5454/27054 -f 4399/5454/27055 4398/5346/27056 4402/5376/27057 -f 4403/5395/27058 4406/5456/27059 4405/5455/27060 -f 4405/5455/27061 4402/5376/27062 4403/5395/27063 -f 4404/5443/27064 4407/5457/27065 4406/5456/27066 -f 4406/5456/27067 4403/5395/27068 4404/5443/27069 -f 4400/5444/27070 4401/5458/27071 4407/5457/27072 -f 4407/5457/27073 4404/5443/27074 4400/5444/27075 -f 4393/5459/27076 4401/5458/27077 4400/5444/27078 -f 4400/5444/27079 4392/5445/27080 4393/5459/27081 -f 4389/5447/27082 4393/5459/27083 4392/5445/27084 -f 4392/5445/27085 4388/5331/27086 4389/5447/27087 -f 4423/5136/27088 4427/5146/27089 4473/5145/27090 -f 4473/5145/27091 4472/5137/27092 4423/5136/27093 -f 4358/5101/27094 4356/5135/27095 4346/5143/27096 -f 4346/5143/27097 4423/5136/27098 4358/5101/27099 -f 4436/5189/27100 4429/5188/27101 4247/4938/27102 -f 4247/4938/27103 4248/4986/27104 4436/5189/27105 -f 4272/4971/27106 4455/5221/27107 4452/5235/27108 -f 4452/5235/27109 4266/5002/27110 4272/4971/27111 -f 4568/5053/27112 4633/5314/27113 4631/5267/27114 -f 4631/5267/27115 4564/5028/27116 4568/5053/27117 -f 4770/5468/27118 4771/5469/27119 4746/5470/27120 -f 4746/5470/27121 4747/5471/27122 4770/5468/27123 -f 4749/5472/27124 4748/5473/27125 4747/5471/27126 -f 4747/5471/27127 4746/5470/27128 4749/5472/27129 -f 4750/5475/27130 4748/5473/27131 4749/5472/27132 -f 4749/5472/27133 4751/5474/27134 4750/5475/27135 -f 4752/5477/27136 4750/5475/27137 4751/5474/27138 -f 4751/5474/27139 4753/5476/27140 4752/5477/27141 -f 4753/5476/27142 4755/5478/27143 4754/5479/27144 -f 4754/5479/27145 4752/5477/27146 4753/5476/27147 -f 4757/5480/27148 4754/5479/27149 4755/5478/27150 -f 4755/5478/27151 4756/5481/27152 4757/5480/27153 -f 4758/5482/27154 4759/5483/27155 4757/5480/27156 -f 4757/5480/27157 4756/5481/27158 4758/5482/27159 -f 4761/5485/27160 4759/5483/27161 4758/5482/27162 -f 4758/5482/27163 4760/5484/27164 4761/5485/27165 -f 4761/5485/27166 4760/5484/27167 4763/5487/27168 -f 4763/5487/27169 4762/5486/27170 4761/5485/27171 -f 4763/5487/27172 4765/5488/27173 4764/5489/27174 -f 4764/5489/27175 4762/5486/27176 4763/5487/27177 -f 4765/5488/27178 4767/5490/27179 4766/5491/27180 -f 4766/5491/27181 4764/5489/27182 4765/5488/27183 -f 4768/5493/27184 4766/5491/27185 4767/5490/27186 -f 4767/5490/27187 4769/5492/27188 4768/5493/27189 -f 4773/5495/27190 4771/5469/27191 4770/5468/27192 -f 4770/5468/27193 4772/5494/27194 4773/5495/27195 -f 4773/5495/27196 4772/5494/27197 4774/5496/27198 -f 4774/5496/27199 4775/5497/27200 4773/5495/27201 -f 4777/5499/27202 4775/5497/27203 4774/5496/27204 -f 4774/5496/27205 4776/5498/27206 4777/5499/27207 -f 4777/5499/27208 4776/5498/27209 4778/5500/27210 -f 4778/5500/27211 4779/5501/27212 4777/5499/27213 -f 4784/5503/27214 4785/5504/27215 4783/5505/27216 -f 4783/5505/27217 4782/5502/27218 4784/5503/27219 -f 4782/5502/27220 4783/5505/27221 4781/5506/27222 -f 4781/5506/27223 4780/5507/27224 4782/5502/27225 -f 4780/5507/27226 4781/5506/27227 4779/5501/27228 -f 4779/5501/27229 4778/5500/27230 4780/5507/27231 -f 4794/5509/27232 4795/5510/27233 4793/5511/27234 -f 4793/5511/27235 4792/5508/27236 4794/5509/27237 -f 4792/5508/27238 4793/5511/27239 4791/5512/27240 -f 4791/5512/27241 4790/5513/27242 4792/5508/27243 -f 4790/5513/27244 4791/5512/27245 4789/5514/27246 -f 4789/5514/27247 4788/5515/27248 4790/5513/27249 -f 4788/5515/27250 4789/5514/27251 4787/5516/27252 -f 4787/5516/27253 4786/5517/27254 4788/5515/27255 -f 4787/5516/27256 4785/5504/27257 4784/5503/27258 -f 4784/5503/27259 4786/5517/27260 4787/5516/27261 -f 4804/5519/27262 4768/5493/27263 4769/5492/27264 -f 4769/5492/27265 4805/5518/27266 4804/5519/27267 -f 4803/5520/27268 4802/5521/27269 4804/5519/27270 -f 4804/5519/27271 4805/5518/27272 4803/5520/27273 -f 4801/5522/27274 4800/5523/27275 4802/5521/27276 -f 4802/5521/27277 4803/5520/27278 4801/5522/27279 -f 4799/5524/27280 4798/5525/27281 4800/5523/27282 -f 4800/5523/27283 4801/5522/27284 4799/5524/27285 -f 4796/5526/27286 4798/5525/27287 4799/5524/27288 -f 4799/5524/27289 4797/5527/27290 4796/5526/27291 -f 4806/5528/27292 4800/5523/27293 4798/5525/27294 -f 4798/5525/27295 4807/5529/27296 4806/5528/27297 -f 4808/5530/27298 4807/5529/27299 4798/5525/27300 -f 4798/5525/27301 4796/5526/27302 4808/5530/27303 -f 4796/5526/27304 4794/5509/27305 4809/5531/27306 -f 4809/5531/27307 4808/5530/27308 4796/5526/27309 -f 4794/5509/27310 4792/5508/27311 4810/5532/27312 -f 4810/5532/27313 4809/5531/27314 4794/5509/27315 -f 4792/5508/27316 4790/5513/27317 4811/5533/27318 -f 4811/5533/27319 4810/5532/27320 4792/5508/27321 -f 4786/5517/27322 4813/5534/27323 4812/5535/27324 -f 4812/5535/27325 4788/5515/27326 4786/5517/27327 -f 4780/5507/27328 4815/5536/27329 4814/5537/27330 -f 4814/5537/27331 4782/5502/27332 4780/5507/27333 -f 4786/5517/27334 4784/5503/27335 4782/5502/27336 -f 4782/5502/27337 4813/5534/27338 4786/5517/27339 -f 4813/5534/27340 4782/5502/27341 4814/5537/27342 -f 4814/5537/27343 4812/5535/27344 4813/5534/27345 -f 4816/5538/27346 4802/5521/27347 4800/5523/27348 -f 4800/5523/27349 4806/5528/27350 4816/5538/27351 -f 4817/5539/27352 4804/5519/27353 4802/5521/27354 -f 4802/5521/27355 4816/5538/27356 4817/5539/27357 -f 4804/5519/27358 4817/5539/27359 4818/5540/27360 -f 4818/5540/27361 4768/5493/27362 4804/5519/27363 -f 4907/5541/27364 4766/5491/27365 4768/5493/27366 -f 4768/5493/27367 4818/5540/27368 4907/5541/27369 -f 4842/5542/27370 4764/5489/27371 4766/5491/27372 -f 4766/5491/27373 4907/5541/27374 4842/5542/27375 -f 4819/5543/27376 4762/5486/27377 4764/5489/27378 -f 4764/5489/27379 4842/5542/27380 4819/5543/27381 -f 4819/5543/27382 4759/5483/27383 4761/5485/27384 -f 4761/5485/27385 4762/5486/27386 4819/5543/27387 -f 4820/5544/27388 4757/5480/27389 4759/5483/27390 -f 4759/5483/27391 4819/5543/27392 4820/5544/27393 -f 4757/5480/27394 4820/5544/27395 4821/5545/27396 -f 4821/5545/27397 4754/5479/27398 4757/5480/27399 -f 4754/5479/27400 4821/5545/27401 4822/5546/27402 -f 4822/5546/27403 4752/5477/27404 4754/5479/27405 -f 4823/5547/27406 4750/5475/27407 4752/5477/27408 -f 4752/5477/27409 4822/5546/27410 4823/5547/27411 -f 4824/5548/27412 4748/5473/27413 4750/5475/27414 -f 4750/5475/27415 4823/5547/27416 4824/5548/27417 -f 4825/5549/27418 4747/5471/27419 4748/5473/27420 -f 4748/5473/27421 4824/5548/27422 4825/5549/27423 -f 4747/5471/27424 4825/5549/27425 4826/5550/27426 -f 4826/5550/27427 4770/5468/27428 4747/5471/27429 -f 4772/5494/27430 4770/5468/27431 4826/5550/27432 -f 4826/5550/27433 4827/5551/27434 4772/5494/27435 -f 4828/5552/27436 4829/5553/27437 4776/5498/27438 -f 4776/5498/27439 4774/5496/27440 4828/5552/27441 -f 4778/5500/27442 4776/5498/27443 4829/5553/27444 -f 4829/5553/27445 4830/5554/27446 4778/5500/27447 -f 4815/5536/27448 4780/5507/27449 4778/5500/27450 -f 4778/5500/27451 4830/5554/27452 4815/5536/27453 -f 4815/5536/27454 4831/5555/27455 4812/5535/27456 -f 4812/5535/27457 4814/5537/27458 4815/5536/27459 -f 4832/5556/27460 4833/5557/27461 4810/5532/27462 -f 4810/5532/27463 4811/5533/27464 4832/5556/27465 -f 4834/5558/27466 4831/5555/27467 4815/5536/27468 -f 4815/5536/27469 4830/5554/27470 4834/5558/27471 -f 4810/5532/27472 4833/5557/27473 4835/5559/27474 -f 4835/5559/27475 4809/5531/27476 4810/5532/27477 -f 4809/5531/27478 4835/5559/27479 4836/5560/27480 -f 4836/5560/27481 4808/5530/27482 4809/5531/27483 -f 4808/5530/27484 4836/5560/27485 4837/5561/27486 -f 4837/5561/27487 4807/5529/27488 4808/5530/27489 -f 4845/5562/27490 4806/5528/27491 4807/5529/27492 -f 4807/5529/27493 4837/5561/27494 4845/5562/27495 -f 4839/5563/27496 4817/5539/27497 4816/5538/27498 -f 4816/5538/27499 4838/5564/27500 4839/5563/27501 -f 4841/5565/27502 4840/5566/27503 4821/5545/27504 -f 4821/5545/27505 4820/5544/27506 4841/5565/27507 -f 4841/5565/27508 4820/5544/27509 4819/5543/27510 -f 4819/5543/27511 4842/5542/27512 4841/5565/27513 -f 4818/5540/27514 4906/5567/27515 4907/5541/27516 -f 4905/5569/27517 4906/5567/27518 4818/5540/27519 -f 4818/5540/27520 4843/5568/27521 4905/5569/27522 -f 4843/5568/27523 4818/5540/27524 4817/5539/27525 -f 4817/5539/27526 4839/5563/27527 4843/5568/27528 -f 4843/5568/27529 4839/5563/27530 4844/5570/27531 -f 4844/5570/27532 4840/5566/27533 4843/5568/27534 -f 4845/5562/27535 4838/5564/27536 4816/5538/27537 -f 4816/5538/27538 4806/5528/27539 4845/5562/27540 -f 4840/5566/27541 4844/5570/27542 4822/5546/27543 -f 4822/5546/27544 4821/5545/27545 4840/5566/27546 -f 4846/5571/27547 4844/5570/27548 4839/5563/27549 -f 4839/5563/27550 4838/5564/27551 4846/5571/27552 -f 4847/5572/27553 4846/5571/27554 4838/5564/27555 -f 4838/5564/27556 4845/5562/27557 4847/5572/27558 -f 4845/5562/27559 4837/5561/27560 4848/5573/27561 -f 4848/5573/27562 4847/5572/27563 4845/5562/27564 -f 4836/5560/27565 4849/5574/27566 4848/5573/27567 -f 4848/5573/27568 4837/5561/27569 4836/5560/27570 -f 4850/5575/27571 4849/5574/27572 4836/5560/27573 -f 4836/5560/27574 4835/5559/27575 4850/5575/27576 -f 4833/5557/27577 4832/5556/27578 4831/5555/27579 -f 4831/5555/27580 4834/5558/27581 4833/5557/27582 -f 4833/5557/27583 4834/5558/27584 4850/5575/27585 -f 4850/5575/27586 4835/5559/27587 4833/5557/27588 -f 4851/5576/27589 4834/5558/27590 4830/5554/27591 -f 4830/5554/27592 4829/5553/27593 4851/5576/27594 -f 4834/5558/27595 4851/5576/27596 4852/5577/27597 -f 4852/5577/27598 4850/5575/27599 4834/5558/27600 -f 4853/5578/27601 4852/5577/27602 4851/5576/27603 -f 4851/5576/27604 4829/5553/27605 4853/5578/27606 -f 4854/5579/27607 4853/5578/27608 4829/5553/27609 -f 4829/5553/27610 4828/5552/27611 4854/5579/27612 -f 4855/5580/27613 4854/5579/27614 4828/5552/27615 -f 4828/5552/27616 4827/5551/27617 4855/5580/27618 -f 4827/5551/27619 4826/5550/27620 4856/5581/27621 -f 4856/5581/27622 4855/5580/27623 4827/5551/27624 -f 4856/5581/27625 4826/5550/27626 4825/5549/27627 -f 4825/5549/27628 4857/5582/27629 4856/5581/27630 -f 4858/5583/27631 4857/5582/27632 4825/5549/27633 -f 4825/5549/27634 4824/5548/27635 4858/5583/27636 -f 4859/5584/27637 4858/5583/27638 4824/5548/27639 -f 4824/5548/27640 4823/5547/27641 4859/5584/27642 -f 4823/5547/27643 4822/5546/27644 4860/5585/27645 -f 4860/5585/27646 4859/5584/27647 4823/5547/27648 -f 4844/5570/27649 4846/5571/27650 4860/5585/27651 -f 4860/5585/27652 4822/5546/27653 4844/5570/27654 -f 4861/5586/27655 4860/5585/27656 4846/5571/27657 -f 4846/5571/27658 4847/5572/27659 4861/5586/27660 -f 4847/5572/27661 4848/5573/27662 4862/5587/27663 -f 4862/5587/27664 4861/5586/27665 4847/5572/27666 -f 4863/5588/27667 4862/5587/27668 4848/5573/27669 -f 4848/5573/27670 4849/5574/27671 4863/5588/27672 -f 4850/5575/27673 4852/5577/27674 4863/5588/27675 -f 4863/5588/27676 4849/5574/27677 4850/5575/27678 -f 4864/5589/27679 4863/5588/27680 4852/5577/27681 -f 4852/5577/27682 4853/5578/27683 4864/5589/27684 -f 4863/5588/27685 4864/5589/27686 4865/5590/27687 -f 4865/5590/27688 4862/5587/27689 4863/5588/27690 -f 4866/5591/27691 4861/5586/27692 4862/5587/27693 -f 4862/5587/27694 4865/5590/27695 4866/5591/27696 -f 4860/5585/27697 4861/5586/27698 4866/5591/27699 -f 4866/5591/27700 4859/5584/27701 4860/5585/27702 -f 4859/5584/27703 4866/5591/27704 4867/5592/27705 -f 4867/5592/27706 4858/5583/27707 4859/5584/27708 -f 4858/5583/27709 4867/5592/27710 4868/5593/27711 -f 4868/5593/27712 4857/5582/27713 4858/5583/27714 -f 4869/5594/27715 4856/5581/27716 4857/5582/27717 -f 4857/5582/27718 4868/5593/27719 4869/5594/27720 -f 4856/5581/27721 4869/5594/27722 4870/5595/27723 -f 4870/5595/27724 4855/5580/27725 4856/5581/27726 -f 4855/5580/27727 4870/5595/27728 4871/5596/27729 -f 4871/5596/27730 4854/5579/27731 4855/5580/27732 -f 4853/5578/27733 4854/5579/27734 4871/5596/27735 -f 4871/5596/27736 4864/5589/27737 4853/5578/27738 -f 4867/5592/27739 4872/5597/27740 4869/5594/27741 -f 4869/5594/27742 4868/5593/27743 4867/5592/27744 -f 4872/5597/27745 4871/5596/27746 4870/5595/27747 -f 4870/5595/27748 4869/5594/27749 4872/5597/27750 -f 4866/5591/27751 4865/5590/27752 4872/5597/27753 -f 4872/5597/27754 4867/5592/27755 4866/5591/27756 -f 4872/5597/27757 4865/5590/27758 4864/5589/27759 -f 4864/5589/27760 4871/5596/27761 4872/5597/27762 -f 4873/5598/27763 4874/5599/27764 4771/5469/27765 -f 4771/5469/27766 4773/5495/27767 4873/5598/27768 -f 4875/5600/27769 4746/5470/27770 4771/5469/27771 -f 4771/5469/27772 4874/5599/27773 4875/5600/27774 -f 4876/5601/27775 4749/5472/27776 4746/5470/27777 -f 4746/5470/27778 4875/5600/27779 4876/5601/27780 -f 4877/5602/27781 4751/5474/27782 4749/5472/27783 -f 4749/5472/27784 4876/5601/27785 4877/5602/27786 -f 4751/5474/27787 4877/5602/27788 4878/5603/27789 -f 4878/5603/27790 4753/5476/27791 4751/5474/27792 -f 4753/5476/27793 4878/5603/27794 4879/5604/27795 -f 4879/5604/27796 4755/5478/27797 4753/5476/27798 -f 4755/5478/27799 4879/5604/27800 4880/5605/27801 -f 4880/5605/27802 4756/5481/27803 4755/5478/27804 -f 4756/5481/27805 4880/5605/27806 4881/5606/27807 -f 4881/5606/27808 4758/5482/27809 4756/5481/27810 -f 4758/5482/27811 4881/5606/27812 4882/5607/27813 -f 4882/5607/27814 4760/5484/27815 4758/5482/27816 -f 4760/5484/27817 4882/5630/27818 4883/5608/27819 -f 4883/5608/27820 4763/5487/27821 4760/5484/27822 -f 4883/5608/27823 4884/5609/27824 4765/5488/27825 -f 4765/5488/27826 4763/5487/27827 4883/5608/27828 -f 4885/5610/27829 4767/5490/27830 4765/5488/27831 -f 4765/5488/27832 4884/5609/27833 4885/5610/27834 -f 4886/5611/27835 4769/5492/27836 4767/5490/27837 -f 4767/5490/27838 4885/5610/27839 4886/5611/27840 -f 4769/5492/27841 4886/5611/27842 4887/5612/27843 -f 4887/5612/27844 4805/5518/27845 4769/5492/27846 -f 4805/5518/27847 4887/5612/27848 4888/5613/27849 -f 4888/5613/27850 4803/5520/27851 4805/5518/27852 -f 4803/5520/27853 4888/5631/27854 4889/5614/27855 -f 4889/5614/27856 4801/5522/27857 4803/5520/27858 -f 4890/5615/27859 4799/5524/27860 4801/5522/27861 -f 4801/5522/27862 4889/5614/27863 4890/5615/27864 -f 4799/5524/27865 4890/5615/27866 4891/5616/27867 -f 4891/5616/27868 4797/5527/27869 4799/5524/27870 -f 4797/5527/27871 4891/5616/27872 4892/5617/27873 -f 4892/5617/27874 4795/5510/27875 4797/5527/27876 -f 4793/5511/27877 4893/5619/27878 4894/5618/27879 -f 4894/5618/27880 4791/5512/27881 4793/5511/27882 -f 4791/5512/27883 4894/5618/27884 4895/5620/27885 -f 4895/5620/27886 4789/5514/27887 4791/5512/27888 -f 4789/5514/27889 4895/5620/27890 4896/5621/27891 -f 4896/5621/27892 4787/5516/27893 4789/5514/27894 -f 4787/5516/27895 4896/5621/27896 4897/5622/27897 -f 4897/5622/27898 4785/5504/27899 4787/5516/27900 -f 4785/5504/27901 4897/5632/27902 4898/5623/27903 -f 4898/5623/27904 4783/5505/27905 4785/5504/27906 -f 4783/5505/27907 4898/5623/27908 4899/5624/27909 -f 4899/5624/27910 4781/5506/27911 4783/5505/27912 -f 4781/5506/27913 4899/5624/27914 4900/5625/27915 -f 4900/5625/27916 4779/5501/27917 4781/5506/27918 -f 4779/5501/27919 4900/5625/27920 4901/5626/27921 -f 4901/5626/27922 4777/5499/27923 4779/5501/27924 -f 4777/5499/27925 4901/5626/27926 4902/5627/27927 -f 4902/5627/27928 4775/5497/27929 4777/5499/27930 -f 4775/5497/27931 4902/5627/27932 4873/5598/27933 -f 4873/5598/27934 4773/5495/27935 4775/5497/27936 -f 4898/5623/27937 4897/5632/27938 4903/5628/27939 -f 4883/5608/27940 4882/5630/27941 4904/5629/27942 -f 4831/5555/27943 4832/5556/27944 4811/5533/27945 -f 4811/5533/27946 4812/5535/27947 4831/5555/27948 -f 4840/5566/27949 4841/5565/27950 4905/5569/27951 -f 4841/5565/27952 4906/5567/27953 4905/5569/27954 -f 4906/5567/27955 4841/5565/27956 4842/5542/27957 -f 4842/5542/27958 4907/5541/27959 4906/5567/27960 -f 4905/5569/27961 4843/5568/27962 4840/5566/27963 -f 4812/5535/27964 4811/5533/27965 4790/5513/27966 -f 4790/5513/27967 4788/5515/27968 4812/5535/27969 -f 4827/5551/27970 4828/5552/27971 4774/5496/27972 -f 4774/5496/27973 4772/5494/27974 4827/5551/27975 -f 4893/5635/27976 4793/5511/27977 4795/5510/27978 -f 4795/5510/27979 4892/5617/27980 4893/5635/27981 -f 4796/5526/27982 4797/5527/27983 4795/5510/27984 -f 4795/5510/27985 4794/5509/27986 4796/5526/27987 -f 4882/5607/27988 4881/5606/27989 4904/5634/27990 -f 4897/5622/27991 4896/5621/27992 4903/5633/27993 -f 4929/5638/27994 4924/5639/27995 5081/5636/27996 -f 5081/5636/27997 5082/5637/27998 4929/5638/27999 -f 4924/5639/28000 4936/5641/28001 5083/5640/28002 -f 5083/5640/28003 5081/5636/28004 4924/5639/28005 -f 4936/5641/28006 4942/5643/28007 5084/5642/28008 -f 5084/5642/28009 5083/5640/28010 4936/5641/28011 -f 4942/5643/28012 4948/5645/28013 5085/5644/28014 -f 5085/5644/28015 5084/5642/28016 4942/5643/28017 -f 4948/5645/28018 4954/5647/28019 5086/5646/28020 -f 5086/5646/28021 5085/5644/28022 4948/5645/28023 -f 4954/5649/28024 4929/5638/28025 5082/5637/28026 -f 5082/5637/28027 5086/5648/28028 4954/5649/28029 -f 4914/5652/28030 4920/5653/28031 4912/5650/28032 -f 4912/5650/28033 4911/5651/28034 4914/5652/28035 -f 4914/5656/28036 4911/5651/28037 4910/5654/28038 -f 4910/5654/28039 4909/5655/28040 4914/5656/28041 -f 4915/5658/28042 4920/5659/28043 4914/5657/28044 -f 4914/5657/28045 4909/5655/28046 4915/5658/28047 -f 4909/5655/28048 4916/5661/28049 4908/5660/28050 -f 4908/5660/28051 4915/5658/28052 4909/5655/28053 -f 4910/5654/28054 4917/5662/28055 4916/5661/28056 -f 4916/5661/28057 4909/5655/28058 4910/5654/28059 -f 4911/5651/28060 4918/5663/28061 4917/5662/28062 -f 4917/5662/28063 4910/5654/28064 4911/5651/28065 -f 4912/5650/28066 4919/5664/28067 4918/5663/28068 -f 4918/5663/28069 4911/5651/28070 4912/5650/28071 -f 4920/5653/28072 4913/5665/28073 4919/5664/28074 -f 4919/5664/28075 4912/5650/28076 4920/5653/28077 -f 4915/5658/28078 4908/5660/28079 4913/5666/28080 -f 4913/5666/28081 4920/5659/28082 4915/5658/28083 -f 4928/5670/28084 4925/5671/28085 5087/5668/28086 -f 5087/5668/28087 5088/5669/28088 4928/5670/28089 -f 4921/5672/28090 4932/5673/28091 4908/5660/28092 -f 4908/5660/28093 4916/5661/28094 4921/5672/28095 -f 4922/5674/28096 4931/5675/28097 4932/5673/28098 -f 4932/5673/28099 4921/5672/28100 4922/5674/28101 -f 4923/5678/28102 4930/5679/28103 5070/5676/28104 -f 5070/5676/28105 5069/5677/28106 4923/5678/28107 -f 4924/5639/28108 4929/5638/28109 5076/5680/28110 -f 5076/5680/28111 5075/5681/28112 4924/5639/28113 -f 4925/5671/28114 4937/5683/28115 5089/5682/28116 -f 5089/5682/28117 5087/5668/28118 4925/5671/28119 -f 4933/5684/28120 4921/5672/28121 4916/5661/28122 -f 4916/5661/28123 4917/5662/28124 4933/5684/28125 -f 4934/5685/28126 4922/5674/28127 4921/5672/28128 -f 4921/5672/28129 4933/5684/28130 4934/5685/28131 -f 4935/5687/28132 4923/5678/28133 5069/5677/28134 -f 5069/5677/28135 5071/5686/28136 4935/5687/28137 -f 4936/5641/28138 4924/5639/28139 5075/5681/28140 -f 5075/5681/28141 5077/5688/28142 4936/5641/28143 -f 4937/5683/28144 4943/5690/28145 5090/5689/28146 -f 5090/5689/28147 5089/5682/28148 4937/5683/28149 -f 4939/5691/28150 4933/5684/28151 4917/5662/28152 -f 4917/5662/28153 4918/5663/28154 4939/5691/28155 -f 4940/5692/28156 4934/5685/28157 4933/5684/28158 -f 4933/5684/28159 4939/5691/28160 4940/5692/28161 -f 4941/5694/28162 4935/5687/28163 5071/5686/28164 -f 5071/5686/28165 5072/5693/28166 4941/5694/28167 -f 4942/5643/28168 4936/5641/28169 5077/5688/28170 -f 5077/5688/28171 5078/5695/28172 4942/5643/28173 -f 4943/5690/28174 4949/5697/28175 5091/5696/28176 -f 5091/5696/28177 5090/5689/28178 4943/5690/28179 -f 4945/5698/28180 4939/5691/28181 4918/5663/28182 -f 4918/5663/28183 4919/5664/28184 4945/5698/28185 -f 4946/5699/28186 4940/5692/28187 4939/5691/28188 -f 4939/5691/28189 4945/5698/28190 4946/5699/28191 -f 4947/5701/28192 4941/5694/28193 5072/5693/28194 -f 5072/5693/28195 5073/5700/28196 4947/5701/28197 -f 4948/5645/28198 4942/5643/28199 5078/5695/28200 -f 5078/5695/28201 5079/5702/28202 4948/5645/28203 -f 4949/5697/28204 4955/5704/28205 5092/5703/28206 -f 5092/5703/28207 5091/5696/28208 4949/5697/28209 -f 4951/5705/28210 4945/5698/28211 4919/5664/28212 -f 4919/5664/28213 4913/5665/28214 4951/5705/28215 -f 4952/5706/28216 4946/5699/28217 4945/5698/28218 -f 4945/5698/28219 4951/5705/28220 4952/5706/28221 -f 4953/5708/28222 4947/5701/28223 5073/5700/28224 -f 5073/5700/28225 5074/5707/28226 4953/5708/28227 -f 4954/5647/28228 4948/5645/28229 5079/5702/28230 -f 5079/5702/28231 5080/5709/28232 4954/5647/28233 -f 4955/5711/28234 4928/5670/28235 5088/5669/28236 -f 5088/5669/28237 5092/5710/28238 4955/5711/28239 -f 4908/5660/28240 4932/5673/28241 4951/5712/28242 -f 4951/5712/28243 4913/5666/28244 4908/5660/28245 -f 4931/5675/28246 4952/5713/28247 4951/5712/28248 -f 4951/5712/28249 4932/5673/28250 4931/5675/28251 -f 4930/5679/28252 4953/5715/28253 5074/5714/28254 -f 5074/5714/28255 5070/5676/28256 4930/5679/28257 -f 4929/5638/28258 4954/5649/28259 5080/5716/28260 -f 5080/5716/28261 5076/5680/28262 4929/5638/28263 -f 4958/5719/28264 4957/5720/28265 5100/5717/28266 -f 5100/5717/28267 5099/5718/28268 4958/5719/28269 -f 5003/5723/28270 5004/5724/28271 5094/5721/28272 -f 5094/5721/28273 5093/5722/28274 5003/5723/28275 -f 4957/5720/28276 4962/5726/28277 5101/5725/28278 -f 5101/5725/28279 5100/5717/28280 4957/5720/28281 -f 5004/5724/28282 5005/5728/28283 5095/5727/28284 -f 5095/5727/28285 5094/5721/28286 5004/5724/28287 -f 4962/5726/28288 4965/5730/28289 5102/5729/28290 -f 5102/5729/28291 5101/5725/28292 4962/5726/28293 -f 5005/5728/28294 5006/5732/28295 5096/5731/28296 -f 5096/5731/28297 5095/5727/28298 5005/5728/28299 -f 4965/5730/28300 4968/5734/28301 5103/5733/28302 -f 5103/5733/28303 5102/5729/28304 4965/5730/28305 -f 5006/5732/28306 5007/5736/28307 5097/5735/28308 -f 5097/5735/28309 5096/5731/28310 5006/5732/28311 -f 4968/5739/28312 4971/5740/28313 5104/5737/28314 -f 5104/5737/28315 5103/5738/28316 4968/5739/28317 -f 5007/5743/28318 5008/5744/28319 5098/5741/28320 -f 5098/5741/28321 5097/5742/28322 5007/5743/28323 -f 4971/5740/28324 4958/5719/28325 5099/5718/28326 -f 5099/5718/28327 5104/5737/28328 4971/5740/28329 -f 5008/5744/28330 5003/5723/28331 5093/5722/28332 -f 5093/5722/28333 5098/5741/28334 5008/5744/28335 -s 2 -f 4974/5747/28336 4973/5748/28337 5020/5745/28338 -f 5020/5745/28339 5021/5746/28340 4974/5747/28341 -f 4975/5750/28342 4974/5747/28343 5021/5888/28344 -f 5021/5888/28345 4970/5749/28346 4975/5750/28347 -f 4976/5752/28348 4975/5750/28349 4970/5889/28350 -f 4970/5889/28351 4967/5751/28352 4976/5752/28353 -f 4977/5755/28354 4976/5756/28355 4967/5753/28356 -f 4967/5753/28357 4964/5754/28358 4977/5755/28359 -f 4978/5758/28360 4977/5755/28361 4964/5890/28362 -f 4964/5890/28363 4961/5757/28364 4978/5758/28365 -f 4973/5748/28366 4978/5758/28367 4961/5891/28368 -f 4961/5891/28369 5020/5886/28370 4973/5748/28371 -f 4980/5761/28372 4979/5762/28373 4960/5759/28374 -f 4960/5759/28375 4959/5760/28376 4980/5761/28377 -f 4981/5764/28378 4980/5761/28379 4959/5887/28380 -f 4959/5887/28381 4963/5763/28382 4981/5764/28383 -f 4982/5766/28384 4981/5764/28385 4963/5893/28386 -f 4963/5893/28387 4966/5765/28388 4982/5766/28389 -f 4983/5768/28390 4982/5766/28391 4966/5894/28392 -f 4966/5894/28393 4969/5767/28394 4983/5768/28395 -f 4984/5771/28396 4983/5772/28397 4969/5769/28398 -f 4969/5769/28399 4972/5770/28400 4984/5771/28401 -f 4979/5762/28402 4984/5771/28403 4972/5895/28404 -f 4972/5895/28405 4960/5892/28406 4979/5762/28407 -s 1 -f 4986/5773/28408 4985/5774/28409 4973/5748/28410 -f 4973/5748/28411 4974/5747/28412 4986/5773/28413 -f 4987/5775/28414 4986/5773/28415 4974/5747/28416 -f 4974/5747/28417 4975/5750/28418 4987/5775/28419 -f 4988/5776/28420 4987/5775/28421 4975/5750/28422 -f 4975/5750/28423 4976/5752/28424 4988/5776/28425 -f 4989/5777/28426 4988/5778/28427 4976/5756/28428 -f 4976/5756/28429 4977/5755/28430 4989/5777/28431 -f 4990/5779/28432 4989/5777/28433 4977/5755/28434 -f 4977/5755/28435 4978/5758/28436 4990/5779/28437 -f 4985/5774/28438 4990/5779/28439 4978/5758/28440 -f 4978/5758/28441 4973/5748/28442 4985/5774/28443 -f 4992/5780/28444 4991/5781/28445 4979/5762/28446 -f 4979/5762/28447 4980/5761/28448 4992/5780/28449 -f 4993/5782/28450 4992/5780/28451 4980/5761/28452 -f 4980/5761/28453 4981/5764/28454 4993/5782/28455 -f 4994/5783/28456 4993/5782/28457 4981/5764/28458 -f 4981/5764/28459 4982/5766/28460 4994/5783/28461 -f 4995/5784/28462 4994/5783/28463 4982/5766/28464 -f 4982/5766/28465 4983/5768/28466 4995/5784/28467 -f 4996/5785/28468 4995/5786/28469 4983/5772/28470 -f 4983/5772/28471 4984/5771/28472 4996/5785/28473 -f 4991/5781/28474 4996/5785/28475 4984/5771/28476 -f 4984/5771/28477 4979/5762/28478 4991/5781/28479 -f 4998/5787/28480 4997/5788/28481 4985/5774/28482 -f 4985/5774/28483 4986/5773/28484 4998/5787/28485 -f 4999/5789/28486 4998/5787/28487 4986/5773/28488 -f 4986/5773/28489 4987/5775/28490 4999/5789/28491 -f 5000/5790/28492 4999/5789/28493 4987/5775/28494 -f 4987/5775/28495 4988/5776/28496 5000/5790/28497 -f 5001/5791/28498 5000/5792/28499 4988/5778/28500 -f 4988/5778/28501 4989/5777/28502 5001/5791/28503 -f 5002/5793/28504 5001/5791/28505 4989/5777/28506 -f 4989/5777/28507 4990/5779/28508 5002/5793/28509 -f 4997/5788/28510 5002/5793/28511 4990/5779/28512 -f 4990/5779/28513 4985/5774/28514 4997/5788/28515 -f 5004/5724/28516 5003/5723/28517 4991/5781/28518 -f 4991/5781/28519 4992/5780/28520 5004/5724/28521 -f 5005/5728/28522 5004/5724/28523 4992/5780/28524 -f 4992/5780/28525 4993/5782/28526 5005/5728/28527 -f 5006/5732/28528 5005/5728/28529 4993/5782/28530 -f 4993/5782/28531 4994/5783/28532 5006/5732/28533 -f 5007/5736/28534 5006/5732/28535 4994/5783/28536 -f 4994/5783/28537 4995/5784/28538 5007/5736/28539 -f 5008/5744/28540 5007/5743/28541 4995/5786/28542 -f 4995/5786/28543 4996/5785/28544 5008/5744/28545 -f 5003/5723/28546 5008/5744/28547 4996/5785/28548 -f 4996/5785/28549 4991/5781/28550 5003/5723/28551 -f 5012/5796/28552 5011/5797/28553 5010/5794/28554 -f 5010/5794/28555 5009/5795/28556 5012/5796/28557 -f 5012/5796/28558 5014/5799/28559 5013/5798/28560 -f 5013/5798/28561 5011/5797/28562 5012/5796/28563 -f 5015/5800/28564 5014/5799/28565 5012/5796/28566 -f 5012/5796/28567 5009/5795/28568 5015/5800/28569 -f 5014/5799/28570 5015/5800/28571 5016/5801/28572 -f 5016/5801/28573 5017/5802/28574 5014/5799/28575 -f 5013/5798/28576 5014/5799/28577 5017/5802/28578 -f 5017/5802/28579 5022/5803/28580 5013/5798/28581 -f 5011/5885/28582 5013/5798/28583 5022/5803/28584 -f 5022/5803/28585 5018/5804/28586 5011/5885/28587 -f 5010/5806/28588 5011/5885/28589 5018/5804/28590 -f 5018/5804/28591 5019/5805/28592 5010/5806/28593 -f 5009/5884/28594 5010/5809/28595 5019/5807/28596 -f 5019/5807/28597 5023/5808/28598 5009/5884/28599 -f 5015/5800/28600 5009/5884/28601 5023/5808/28602 -f 5023/5808/28603 5016/5801/28604 5015/5800/28605 -f 5021/5878/28606 5020/5667/28607 5105/5810/28608 -f 5105/5810/28609 5106/5811/28610 5021/5878/28611 -f 5020/5667/28612 4961/5883/28613 5107/5812/28614 -f 5107/5812/28615 5105/5810/28616 5020/5667/28617 -f 4961/5883/28618 4964/5882/28619 5108/5813/28620 -f 5108/5813/28621 5107/5812/28622 4961/5883/28623 -f 4964/5882/28624 4967/5881/28625 5109/5814/28626 -f 5109/5814/28627 5108/5813/28628 4964/5882/28629 -f 4967/5880/28630 4970/5879/28631 5110/5815/28632 -f 5110/5815/28633 5109/5816/28634 4967/5880/28635 -f 4970/5879/28636 5021/5878/28637 5106/5811/28638 -f 5106/5811/28639 5110/5815/28640 4970/5879/28641 -f 5030/5819/28642 5029/5820/28643 5024/5817/28644 -f 5024/5817/28645 5025/5818/28646 5030/5819/28647 -s 2 -f 5031/5822/28648 5030/5819/28649 5025/5818/28650 -f 5025/5818/28651 5026/5821/28652 5031/5822/28653 -s 4 -f 5032/5825/28654 5031/5826/28655 5026/5823/28656 -f 5026/5823/28657 5027/5824/28658 5032/5825/28659 -f 5033/5828/28660 5032/5825/28661 5027/5824/28662 -f 5027/5824/28663 5028/5827/28664 5033/5828/28665 -s 1 -f 5029/5820/28666 5033/5828/28667 5028/5827/28668 -f 5028/5827/28669 5024/5817/28670 5029/5820/28671 -f 5035/5829/28672 5034/5830/28673 5029/5820/28674 -f 5029/5820/28675 5030/5819/28676 5035/5829/28677 -s 2 -f 5036/5831/28678 5035/5829/28679 5030/5819/28680 -f 5030/5819/28681 5031/5822/28682 5036/5831/28683 -s 4 -f 5037/5832/28684 5036/5833/28685 5031/5826/28686 -f 5031/5826/28687 5032/5825/28688 5037/5832/28689 -f 5038/5834/28690 5037/5832/28691 5032/5825/28692 -f 5032/5825/28693 5033/5828/28694 5038/5834/28695 -s 1 -f 5034/5830/28696 5038/5834/28697 5033/5828/28698 -f 5033/5828/28699 5029/5820/28700 5034/5830/28701 -f 5040/5835/28702 5039/5836/28703 5034/5830/28704 -f 5034/5830/28705 5035/5829/28706 5040/5835/28707 -s 2 -f 5041/5837/28708 5040/5835/28709 5035/5829/28710 -f 5035/5829/28711 5036/5831/28712 5041/5837/28713 -s 4 -f 5042/5838/28714 5041/5839/28715 5036/5833/28716 -f 5036/5833/28717 5037/5832/28718 5042/5838/28719 -f 5043/5840/28720 5042/5838/28721 5037/5832/28722 -f 5037/5832/28723 5038/5834/28724 5043/5840/28725 -s 1 -f 5039/5836/28726 5043/5840/28727 5038/5834/28728 -f 5038/5834/28729 5034/5830/28730 5039/5836/28731 -f 5045/5841/28732 5044/5842/28733 5039/5836/28734 -f 5039/5836/28735 5040/5835/28736 5045/5841/28737 -s 2 -f 5046/5843/28738 5045/5841/28739 5040/5835/28740 -f 5040/5835/28741 5041/5837/28742 5046/5843/28743 -s 4 -f 5047/5844/28744 5046/5845/28745 5041/5839/28746 -f 5041/5839/28747 5042/5838/28748 5047/5844/28749 -f 5048/5846/28750 5047/5844/28751 5042/5838/28752 -f 5042/5838/28753 5043/5840/28754 5048/5846/28755 -s 1 -f 5044/5842/28756 5048/5846/28757 5043/5840/28758 -f 5043/5840/28759 5039/5836/28760 5044/5842/28761 -f 5050/5847/28762 5049/5848/28763 5044/5842/28764 -f 5044/5842/28765 5045/5841/28766 5050/5847/28767 -s 2 -f 5051/5849/28768 5050/5847/28769 5045/5841/28770 -f 5045/5841/28771 5046/5843/28772 5051/5849/28773 -s 4 -f 5052/5850/28774 5051/5851/28775 5046/5845/28776 -f 5046/5845/28777 5047/5844/28778 5052/5850/28779 -f 5053/5852/28780 5052/5850/28781 5047/5844/28782 -f 5047/5844/28783 5048/5846/28784 5053/5852/28785 -s 1 -f 5049/5848/28786 5053/5852/28787 5048/5846/28788 -f 5048/5846/28789 5044/5842/28790 5049/5848/28791 -f 5055/5853/28792 5054/5854/28793 5049/5848/28794 -f 5049/5848/28795 5050/5847/28796 5055/5853/28797 -s 2 -f 5056/5855/28798 5055/5853/28799 5050/5847/28800 -f 5050/5847/28801 5051/5849/28802 5056/5855/28803 -s 4 -f 5057/5856/28804 5056/5857/28805 5051/5851/28806 -f 5051/5851/28807 5052/5850/28808 5057/5856/28809 -f 5058/5858/28810 5057/5856/28811 5052/5850/28812 -f 5052/5850/28813 5053/5852/28814 5058/5858/28815 -s 1 -f 5054/5854/28816 5058/5858/28817 5053/5852/28818 -f 5053/5852/28819 5049/5848/28820 5054/5854/28821 -f 5060/5859/28822 5059/5860/28823 5054/5854/28824 -f 5054/5854/28825 5055/5853/28826 5060/5859/28827 -s 2 -f 5061/5861/28828 5060/5859/28829 5055/5853/28830 -f 5055/5853/28831 5056/5855/28832 5061/5861/28833 -s 4 -f 5062/5862/28834 5061/5863/28835 5056/5857/28836 -f 5056/5857/28837 5057/5856/28838 5062/5862/28839 -f 5063/5864/28840 5062/5862/28841 5057/5856/28842 -f 5057/5856/28843 5058/5858/28844 5063/5864/28845 -s 1 -f 5059/5860/28846 5063/5864/28847 5058/5858/28848 -f 5058/5858/28849 5054/5854/28850 5059/5860/28851 -f 5065/5865/28852 5064/5866/28853 5059/5860/28854 -f 5059/5860/28855 5060/5859/28856 5065/5865/28857 -s 2 -f 5066/5867/28858 5065/5865/28859 5060/5859/28860 -f 5060/5859/28861 5061/5861/28862 5066/5867/28863 -s 4 -f 5067/5868/28864 5066/5869/28865 5061/5863/28866 -f 5061/5863/28867 5062/5862/28868 5067/5868/28869 -f 5068/5870/28870 5067/5868/28871 5062/5862/28872 -f 5062/5862/28873 5063/5864/28874 5068/5870/28875 -s 1 -f 5064/5866/28876 5068/5870/28877 5063/5864/28878 -f 5063/5864/28879 5059/5860/28880 5064/5866/28881 -f 5069/5677/28882 5070/5676/28883 4931/5675/28884 -f 4931/5675/28885 4922/5674/28886 5069/5677/28887 -f 5071/5686/28888 5069/5677/28889 4922/5674/28890 -f 4922/5674/28891 4934/5685/28892 5071/5686/28893 -f 5072/5693/28894 5071/5686/28895 4934/5685/28896 -f 4934/5685/28897 4940/5692/28898 5072/5693/28899 -f 5073/5700/28900 5072/5693/28901 4940/5692/28902 -f 4940/5692/28903 4946/5699/28904 5073/5700/28905 -f 5074/5707/28906 5073/5700/28907 4946/5699/28908 -f 4946/5699/28909 4952/5706/28910 5074/5707/28911 -f 5070/5676/28912 5074/5714/28913 4952/5713/28914 -f 4952/5713/28915 4931/5675/28916 5070/5676/28917 -f 5075/5681/28918 5076/5680/28919 4930/5679/28920 -f 4930/5679/28921 4923/5678/28922 5075/5681/28923 -f 5077/5688/28924 5075/5681/28925 4923/5678/28926 -f 4923/5678/28927 4935/5687/28928 5077/5688/28929 -f 5078/5695/28930 5077/5688/28931 4935/5687/28932 -f 4935/5687/28933 4941/5694/28934 5078/5695/28935 -f 5079/5702/28936 5078/5695/28937 4941/5694/28938 -f 4941/5694/28939 4947/5701/28940 5079/5702/28941 -f 5080/5709/28942 5079/5702/28943 4947/5701/28944 -f 4947/5701/28945 4953/5708/28946 5080/5709/28947 -f 5076/5680/28948 5080/5716/28949 4953/5715/28950 -f 4953/5715/28951 4930/5679/28952 5076/5680/28953 -f 5082/5637/28954 5081/5636/28955 4925/5671/28956 -f 4925/5671/28957 4928/5670/28958 5082/5637/28959 -f 5081/5636/28960 5083/5640/28961 4937/5683/28962 -f 4937/5683/28963 4925/5671/28964 5081/5636/28965 -f 5083/5640/28966 5084/5642/28967 4943/5690/28968 -f 4943/5690/28969 4937/5683/28970 5083/5640/28971 -f 5084/5642/28972 5085/5644/28973 4949/5697/28974 -f 4949/5697/28975 4943/5690/28976 5084/5642/28977 -f 5085/5644/28978 5086/5646/28979 4955/5704/28980 -f 4955/5704/28981 4949/5697/28982 5085/5644/28983 -f 5086/5648/28984 5082/5637/28985 4928/5670/28986 -f 4928/5670/28987 4955/5711/28988 5086/5648/28989 -f 5088/5669/28990 5087/5668/28991 4926/5871/28992 -f 4926/5871/28993 4927/5872/28994 5088/5669/28995 -f 5087/5668/28996 5089/5682/28997 4938/5873/28998 -f 4938/5873/28999 4926/5871/29000 5087/5668/29001 -f 5089/5682/29002 5090/5689/29003 4944/5874/29004 -f 4944/5874/29005 4938/5873/29006 5089/5682/29007 -f 5090/5689/29008 5091/5696/29009 4950/5875/29010 -f 4950/5875/29011 4944/5874/29012 5090/5689/29013 -f 5091/5696/29014 5092/5703/29015 4956/5876/29016 -f 4956/5876/29017 4950/5875/29018 5091/5696/29019 -f 5092/5710/29020 5088/5669/29021 4927/5872/29022 -f 4927/5872/29023 4956/5877/29024 5092/5710/29025 -f 5093/5722/29026 5094/5721/29027 4957/5720/29028 -f 4957/5720/29029 4958/5719/29030 5093/5722/29031 -f 5094/5721/29032 5095/5727/29033 4962/5726/29034 -f 4962/5726/29035 4957/5720/29036 5094/5721/29037 -f 5095/5727/29038 5096/5731/29039 4965/5730/29040 -f 4965/5730/29041 4962/5726/29042 5095/5727/29043 -f 5096/5731/29044 5097/5735/29045 4968/5734/29046 -f 4968/5734/29047 4965/5730/29048 5096/5731/29049 -f 5097/5742/29050 5098/5741/29051 4971/5740/29052 -f 4971/5740/29053 4968/5739/29054 5097/5742/29055 -f 5098/5741/29056 5093/5722/29057 4958/5719/29058 -f 4958/5719/29059 4971/5740/29060 5098/5741/29061 -f 5099/5718/29062 5100/5717/29063 4997/5788/29064 -f 4997/5788/29065 4998/5787/29066 5099/5718/29067 -f 5100/5717/29068 5101/5725/29069 5002/5793/29070 -f 5002/5793/29071 4997/5788/29072 5100/5717/29073 -f 5101/5725/29074 5102/5729/29075 5001/5791/29076 -f 5001/5791/29077 5002/5793/29078 5101/5725/29079 -f 5102/5729/29080 5103/5733/29081 5000/5792/29082 -f 5000/5792/29083 5001/5791/29084 5102/5729/29085 -f 5103/5738/29086 5104/5737/29087 4999/5789/29088 -f 4999/5789/29089 5000/5790/29090 5103/5738/29091 -f 5104/5737/29092 5099/5718/29093 4998/5787/29094 -f 4998/5787/29095 4999/5789/29096 5104/5737/29097 -f 5106/5811/29098 5105/5810/29099 5017/5802/29100 -f 5017/5802/29101 5016/5801/29102 5106/5811/29103 -f 5105/5810/29104 5107/5812/29105 5022/5803/29106 -f 5022/5803/29107 5017/5802/29108 5105/5810/29109 -f 5107/5812/29110 5108/5813/29111 5018/5804/29112 -f 5018/5804/29113 5022/5803/29114 5107/5812/29115 -f 5108/5813/29116 5109/5814/29117 5019/5805/29118 -f 5019/5805/29119 5018/5804/29120 5108/5813/29121 -f 5109/5816/29122 5110/5815/29123 5023/5808/29124 -f 5023/5808/29125 5019/5807/29126 5109/5816/29127 -f 5110/5815/29128 5106/5811/29129 5016/5801/29130 -f 5016/5801/29131 5023/5808/29132 5110/5815/29133 -f 5111/5898/29134 5114/5901/29135 5113/5902/29136 -f 5113/5902/29137 5112/5897/29138 5111/5898/29139 -f 5113/5902/29140 5114/5901/29141 5115/5904/29142 -f 5115/5904/29143 5116/5906/29144 5113/5902/29145 -f 5118/5910/29146 5111/5898/29147 5112/5897/29148 -f 5112/5897/29149 5117/5907/29150 5118/5910/29151 -f 5120/5924/29152 5118/5910/29153 5117/5907/29154 -f 5117/5907/29155 5119/5912/29156 5120/5924/29157 -f 5116/5906/29158 5115/5904/29159 5173/5925/29160 -f 5173/5925/29161 5172/5926/29162 5116/5906/29163 -f 5121/5927/29164 5122/5928/29165 5119/5912/29166 -f 5119/5912/29167 5117/5907/29168 5121/5927/29169 -f 5123/5929/29170 5124/5930/29171 5122/5928/29172 -f 5122/5928/29173 5121/5927/29174 5123/5929/29175 -f 5126/5932/29176 5123/5929/29177 5121/5927/29178 -f 5121/5927/29179 5125/5931/29180 5126/5932/29181 -f 5128/5934/29182 5126/5932/29183 5125/5931/29184 -f 5125/5931/29185 5127/5933/29186 5128/5934/29187 -f 5129/5935/29188 5128/5934/29189 5127/5933/29190 -f 5131/5899/29191 5126/5900/29192 5128/5903/29193 -f 5128/5903/29194 5130/5896/29195 5131/5899/29196 -f 5132/5905/29197 5133/5908/29198 5124/5909/29199 -f 5124/5909/29200 5123/5911/29201 5132/5905/29202 -f 5123/5911/29203 5126/5900/29204 5131/5899/29205 -f 5131/5899/29206 5132/5905/29207 5123/5911/29208 -f 5133/5921/29209 5132/5922/29210 5134/5919/29211 -f 5134/5919/29212 5135/5920/29213 5133/5921/29214 -f 5132/5922/29215 5131/5966/29216 5136/5969/29217 -f 5136/5969/29218 5134/5919/29219 5132/5922/29220 -f 5136/5969/29221 5131/5966/29222 5130/5970/29223 -f 5130/5970/29224 5137/5974/29225 5136/5969/29226 -f 5128/5903/29227 5129/5913/29228 5138/5914/29229 -f 5138/5914/29230 5130/5896/29231 5128/5903/29232 -f 5137/5974/29233 5130/5970/29234 5138/5976/29235 -f 5138/5976/29236 5139/5975/29237 5137/5974/29238 -f 5142/5937/29239 5125/5931/29240 5121/5927/29241 -f 5121/5927/29242 5140/5936/29243 5142/5937/29244 -f 5140/5936/29245 5121/5927/29246 5117/5907/29247 -f 5117/5907/29248 5112/5897/29249 5140/5936/29250 -f 5112/5897/29251 5113/5902/29252 5140/5936/29253 -f 5141/5938/29254 5140/5936/29255 5113/5902/29256 -f 5113/5902/29257 5116/5906/29258 5141/5938/29259 -f 5143/5939/29260 5142/5937/29261 5140/5936/29262 -f 5140/5936/29263 5141/5938/29264 5143/5939/29265 -f 5125/5931/29266 5142/5937/29267 5144/5940/29268 -f 5144/5940/29269 5127/5933/29270 5125/5931/29271 -f 5144/5940/29272 5142/5937/29273 5145/5941/29274 -f 5127/5933/29275 5144/5940/29276 5146/5942/29277 -f 5146/5942/29278 5129/5935/29279 5127/5933/29280 -f 5145/5941/29281 5148/5943/29282 5144/5940/29283 -f 5147/5944/29284 5146/5942/29285 5144/5940/29286 -f 5148/5943/29287 5147/5944/29288 5144/5940/29289 -f 5149/5945/29290 5150/5946/29291 5148/5943/29292 -f 5148/5943/29293 5145/5941/29294 5149/5945/29295 -f 5145/5941/29296 5142/5937/29297 5151/5947/29298 -f 5151/5947/29299 5149/5945/29300 5145/5941/29301 -f 5152/5948/29302 5151/5947/29303 5142/5937/29304 -f 5142/5937/29305 5143/5939/29306 5152/5948/29307 -f 5143/5939/29308 5141/5938/29309 5154/5949/29310 -f 5153/5950/29311 5152/5948/29312 5143/5939/29313 -f 5143/5939/29314 5154/5949/29315 5153/5950/29316 -f 5156/5952/29317 5154/5949/29318 5157/5953/29319 -f 5157/5953/29320 5155/5951/29321 5156/5952/29322 -f 5159/5955/29323 5157/5953/29324 5161/5956/29325 -f 5161/5956/29326 5158/5954/29327 5159/5955/29328 -f 5141/5938/29329 5116/5906/29330 5161/5956/29331 -f 5160/5957/29332 5169/5959/29333 5116/5906/29334 -f 5116/5906/29335 5172/5926/29336 5160/5957/29337 -f 5161/5956/29338 5162/5962/29339 5163/5960/29340 -f 5163/5960/29341 5183/5961/29342 5161/5956/29343 -s 2 -f 5161/5956/29344 5183/5961/29345 5164/5963/29346 -f 5164/5963/29347 5158/5954/29348 5161/5956/29349 -f 5165/5964/29350 5180/5965/29351 5153/5950/29352 -f 5153/5950/29353 5154/5949/29354 5165/5964/29355 -s 4 -f 5166/5967/29356 5165/5964/29357 5154/5949/29358 -f 5154/5949/29359 5156/5952/29360 5166/5967/29361 -f 5157/5953/29362 5159/5955/29363 5167/5968/29364 -f 5167/5968/29365 5182/5978/29366 5157/5953/29367 -s 2 -f 5157/5953/29368 5182/5978/29369 5168/5985/29370 -f 5168/5985/29371 5155/5951/29372 5157/5953/29373 -s 8 -f 5166/5967/29374 5156/5952/29375 5155/5951/29376 -f 5155/5951/29377 5168/5985/29378 5166/5967/29379 -s 4 -f 5167/5968/29380 5159/5955/29381 5158/5954/29382 -f 5158/5954/29383 5164/5963/29384 5167/5968/29385 -s 1 -f 5169/5959/29386 5161/5956/29387 5116/5906/29388 -f 5162/5962/29389 5161/5956/29390 5169/5959/29391 -f 5162/5962/29392 5169/5959/29393 5170/5986/29394 -f 5170/5986/29395 5163/5960/29396 5162/5962/29397 -f 5160/5957/29398 5171/5987/29399 5170/5986/29400 -f 5170/5986/29401 5169/5959/29402 5160/5957/29403 -f 5171/5987/29404 5160/5957/29405 5172/5926/29406 -f 5172/5926/29407 5173/5925/29408 5171/5987/29409 -s 2 -f 5129/5935/29410 5146/5942/29411 5139/5988/29412 -f 5139/5988/29413 5138/5989/29414 5129/5935/29415 -f 5146/5942/29416 5147/5944/29417 5174/5990/29418 -f 5174/5990/29419 5139/5988/29420 5146/5942/29421 -s 1 -f 5139/5975/29422 5174/5979/29423 5175/5977/29424 -f 5175/5977/29425 5137/5974/29426 5139/5975/29427 -s 4 -f 5177/5998/29428 5150/5946/29429 5149/5945/29430 -f 5149/5945/29431 5176/5997/29432 5177/5998/29433 -f 5149/5945/29434 5151/5947/29435 5178/6001/29436 -f 5178/6001/29437 5176/5997/29438 5149/5945/29439 -f 5152/5948/29440 5179/6002/29441 5178/6001/29442 -f 5178/6001/29443 5151/5947/29444 5152/5948/29445 -f 5153/5950/29446 5180/5965/29447 5179/6002/29448 -f 5179/6002/29449 5152/5948/29450 5153/5950/29451 -s 1 -f 5180/5984/29452 5165/6005/29453 5181/5981/29454 -f 5181/5981/29455 5179/5982/29456 5180/5984/29457 -f 5166/6007/29458 5168/6008/29459 5182/6006/29460 -f 5182/6006/29461 5165/6005/29462 5166/6007/29463 -f 5167/6010/29464 5164/6011/29465 5183/6009/29466 -f 5183/6009/29467 5182/6006/29468 5167/6010/29469 -f 5163/6024/29470 5170/6025/29471 5184/6012/29472 -f 5184/6012/29473 5183/6009/29474 5163/6024/29475 -f 5184/6012/29476 5170/6025/29477 5171/6032/29478 -f 5171/6032/29479 5185/6063/29480 5184/6012/29481 -f 5186/6065/29482 5185/6063/29483 5171/6032/29484 -f 5171/6032/29485 5173/6064/29486 5186/6065/29487 -f 5188/6066/29488 5303/6177/29489 5186/6065/29490 -f 5188/5915/29491 5186/5916/29492 5115/5917/29493 -f 5115/5917/29494 5114/5918/29495 5188/5915/29496 -f 5186/5916/29497 5173/5923/29498 5115/5917/29499 -f 5187/5958/29500 5188/5915/29501 5114/5918/29502 -f 5114/5918/29503 5111/5971/29504 5187/5958/29505 -f 5188/6066/29506 5187/6073/29507 5302/6176/29508 -f 5302/6176/29509 5303/6177/29510 5188/6066/29511 -f 5184/6012/29512 5189/6075/29513 5190/6079/29514 -f 5190/6079/29515 5183/6009/29516 5184/6012/29517 -f 5182/6006/29518 5183/6009/29519 5190/6079/29520 -f 5165/6005/29521 5182/6006/29522 5190/6079/29523 -f 5190/6079/29524 5189/6075/29525 5181/5981/29526 -f 5181/5981/29527 5165/6005/29528 5190/6079/29529 -f 5191/6082/29530 5178/6086/29531 5179/5982/29532 -f 5179/5982/29533 5181/5981/29534 5191/6082/29535 -f 5192/6087/29536 5176/6088/29537 5178/6086/29538 -f 5178/6086/29539 5191/6082/29540 5192/6087/29541 -f 5176/6088/29542 5192/6087/29543 5193/6089/29544 -f 5193/6089/29545 5177/6090/29546 5176/6088/29547 -s 2 -f 5148/5943/29548 5150/5946/29549 5177/5998/29550 -f 5177/5998/29551 5193/6023/29552 5148/5943/29553 -s 4 -f 5147/5944/29554 5148/5943/29555 5193/6023/29556 -f 5193/6023/29557 5174/5990/29558 5147/5944/29559 -s 1 -f 5193/6023/29560 5175/6027/29561 5174/5990/29562 -f 5193/6089/29563 5192/6087/29564 5175/5977/29565 -f 5189/6075/29566 5194/6091/29567 5191/6082/29568 -f 5191/6082/29569 5181/5981/29570 5189/6075/29571 -f 5194/6091/29572 5192/6087/29573 5191/6082/29574 -f 5137/5974/29575 5175/5977/29576 5192/6087/29577 -f 5192/6087/29578 5194/6091/29579 5137/5974/29580 -f 5136/5969/29581 5137/5974/29582 5194/6091/29583 -f 5134/5919/29584 5136/5969/29585 5194/6091/29586 -f 5195/5973/29587 5187/5958/29588 5111/5971/29589 -f 5111/5971/29590 5118/5972/29591 5195/5973/29592 -f 5197/6093/29593 5187/6073/29594 5195/6094/29595 -f 5195/6094/29596 5196/6092/29597 5197/6093/29598 -f 5197/6093/29599 5302/6176/29600 5187/6073/29601 -f 5134/5919/29602 5194/6091/29603 5197/6093/29604 -f 5197/6093/29605 5196/6092/29606 5134/5919/29607 -f 5118/5972/29608 5120/5980/29609 5198/5983/29610 -f 5198/5983/29611 5195/5973/29612 5118/5972/29613 -f 5195/6094/29614 5198/6096/29615 5199/6095/29616 -f 5199/6095/29617 5196/6092/29618 5195/6094/29619 -f 5196/6092/29620 5199/6095/29621 5135/5920/29622 -f 5135/5920/29623 5134/5919/29624 5196/6092/29625 -f 5200/6029/29626 5201/6035/29627 5119/5912/29628 -f 5119/5912/29629 5122/5928/29630 5200/6029/29631 -f 5201/6035/29632 5200/6029/29633 5202/6036/29634 -f 5202/6036/29635 5203/6037/29636 5201/6035/29637 -f 5203/6037/29638 5202/6036/29639 5204/6038/29640 -f 5204/6038/29641 5205/6039/29642 5203/6037/29643 -f 5206/6040/29644 5200/6029/29645 5122/5928/29646 -f 5122/5928/29647 5124/5930/29648 5206/6040/29649 -f 5200/6029/29650 5206/6040/29651 5207/6041/29652 -f 5207/6041/29653 5202/6036/29654 5200/6029/29655 -f 5202/6036/29656 5207/6041/29657 5208/6042/29658 -f 5208/6042/29659 5204/6038/29660 5202/6036/29661 -f 5119/5912/29662 5201/6035/29663 5209/6043/29664 -f 5209/6043/29665 5120/5924/29666 5119/5912/29667 -f 5210/6044/29668 5209/6043/29669 5201/6035/29670 -f 5201/6035/29671 5203/6037/29672 5210/6044/29673 -f 5203/6037/29674 5205/6039/29675 5211/6045/29676 -f 5211/6045/29677 5210/6044/29678 5203/6037/29679 -f 5213/6047/29680 5205/6039/29681 5204/6038/29682 -f 5204/6038/29683 5212/6046/29684 5213/6047/29685 -f 5208/6042/29686 5214/6048/29687 5212/6046/29688 -f 5212/6046/29689 5204/6038/29690 5208/6042/29691 -f 5205/6039/29692 5213/6047/29693 5215/6049/29694 -f 5215/6049/29695 5211/6045/29696 5205/6039/29697 -f 5216/6050/29698 5217/6051/29699 5213/6047/29700 -f 5213/6047/29701 5212/6046/29702 5216/6050/29703 -f 5218/6052/29704 5216/6050/29705 5212/6046/29706 -f 5212/6046/29707 5214/6048/29708 5218/6052/29709 -f 5213/6047/29710 5217/6051/29711 5219/6053/29712 -f 5219/6053/29713 5215/6049/29714 5213/6047/29715 -f 5221/6098/29716 5135/5920/29717 5199/6095/29718 -f 5199/6095/29719 5220/6097/29720 5221/6098/29721 -f 5223/6100/29722 5221/6098/29723 5220/6097/29724 -f 5220/6097/29725 5222/6099/29726 5223/6100/29727 -f 5225/6102/29728 5223/6100/29729 5222/6099/29730 -f 5222/6099/29731 5224/6101/29732 5225/6102/29733 -f 5225/6102/29734 5224/6101/29735 5226/6103/29736 -f 5226/6103/29737 5227/6104/29738 5225/6102/29739 -f 5228/6105/29740 5220/6097/29741 5199/6095/29742 -f 5199/6095/29743 5198/6096/29744 5228/6105/29745 -f 5220/6097/29746 5228/6105/29747 5229/6106/29748 -f 5229/6106/29749 5222/6099/29750 5220/6097/29751 -f 5230/6107/29752 5224/6101/29753 5222/6099/29754 -f 5222/6099/29755 5229/6106/29756 5230/6107/29757 -f 5231/6108/29758 5226/6103/29759 5224/6101/29760 -f 5224/6101/29761 5230/6107/29762 5231/6108/29763 -f 5135/5920/29764 5221/6098/29765 5232/6109/29766 -f 5232/6109/29767 5133/5921/29768 5135/5920/29769 -f 5221/6098/29770 5223/6100/29771 5233/6110/29772 -f 5233/6110/29773 5232/6109/29774 5221/6098/29775 -f 5223/6100/29776 5225/6102/29777 5234/6111/29778 -f 5234/6111/29779 5233/6110/29780 5223/6100/29781 -f 5235/6112/29782 5234/6111/29783 5225/6102/29784 -f 5225/6102/29785 5227/6104/29786 5235/6112/29787 -f 5133/5908/29788 5232/5991/29789 5206/5992/29790 -f 5206/5992/29791 5124/5909/29792 5133/5908/29793 -f 5232/5991/29794 5233/5993/29795 5207/5994/29796 -f 5207/5994/29797 5206/5992/29798 5232/5991/29799 -f 5234/5995/29800 5208/5996/29801 5207/5994/29802 -f 5207/5994/29803 5233/5993/29804 5234/5995/29805 -f 5235/5999/29806 5214/6000/29807 5208/5996/29808 -f 5208/5996/29809 5234/5995/29810 5235/5999/29811 -f 5235/5999/29812 5218/6003/29813 5214/6000/29814 -f 5209/6004/29815 5228/6013/29816 5198/5983/29817 -f 5198/5983/29818 5120/5980/29819 5209/6004/29820 -f 5210/6014/29821 5229/6015/29822 5228/6013/29823 -f 5228/6013/29824 5209/6004/29825 5210/6014/29826 -f 5211/6016/29827 5230/6017/29828 5229/6015/29829 -f 5229/6015/29830 5210/6014/29831 5211/6016/29832 -f 5211/6016/29833 5215/6018/29834 5231/6019/29835 -f 5231/6019/29836 5230/6017/29837 5211/6016/29838 -f 5215/6018/29839 5219/6020/29840 5231/6019/29841 -f 5236/6021/29842 5237/6022/29843 5218/6003/29844 -f 5218/6003/29845 5235/5999/29846 5236/6021/29847 -f 5218/6052/29848 5237/6055/29849 5238/6054/29850 -f 5238/6054/29851 5216/6050/29852 5218/6052/29853 -f 5239/6114/29854 5236/6113/29855 5235/6112/29856 -f 5235/6112/29857 5227/6104/29858 5239/6114/29859 -f 5226/6103/29860 5240/6115/29861 5239/6114/29862 -f 5239/6114/29863 5227/6104/29864 5226/6103/29865 -f 5241/6116/29866 5240/6115/29867 5226/6103/29868 -f 5226/6103/29869 5231/6108/29870 5241/6116/29871 -f 5216/6050/29872 5238/6054/29873 5242/6056/29874 -f 5242/6056/29875 5217/6051/29876 5216/6050/29877 -f 5217/6051/29878 5242/6056/29879 5243/6057/29880 -f 5243/6057/29881 5219/6053/29882 5217/6051/29883 -f 5241/6028/29884 5231/6019/29885 5219/6020/29886 -f 5219/6020/29887 5243/6026/29888 5241/6028/29889 -f 5244/6058/29890 5245/6067/29891 5243/6057/29892 -f 5243/6057/29893 5242/6056/29894 5244/6058/29895 -f 5246/6117/29896 5247/6118/29897 5240/6115/29898 -f 5240/6115/29899 5241/6116/29900 5246/6117/29901 -f 5243/6026/29902 5245/6030/29903 5246/6031/29904 -f 5246/6031/29905 5241/6028/29906 5243/6026/29907 -f 5246/6031/29908 5245/6030/29909 5248/6033/29910 -f 5248/6033/29911 5249/6034/29912 5246/6031/29913 -f 5248/6068/29914 5245/6067/29915 5244/6058/29916 -f 5249/6119/29917 5247/6118/29918 5246/6117/29919 -f 5249/6071/29920 5248/6068/29921 5250/6069/29922 -f 5250/6069/29923 5251/6070/29924 5249/6071/29925 -f 5250/6069/29926 5248/6068/29927 5244/6058/29928 -f 5252/6072/29929 5253/6074/29930 5250/6069/29931 -f 5250/6069/29932 5244/6058/29933 5252/6072/29934 -f 5254/6076/29935 5255/6077/29936 5253/6074/29937 -f 5253/6074/29938 5252/6072/29939 5254/6076/29940 -f 5256/6078/29941 5252/6072/29942 5244/6058/29943 -f 5244/6058/29944 5242/6056/29945 5256/6078/29946 -f 5256/6078/29947 5254/6076/29948 5252/6072/29949 -f 5257/6080/29950 5258/6081/29951 5254/6076/29952 -f 5254/6076/29953 5256/6078/29954 5257/6080/29955 -f 5259/6084/29956 5260/6085/29957 5254/6076/29958 -f 5254/6076/29959 5258/6081/29960 5259/6084/29961 -f 5262/6147/29962 5259/6084/29963 5258/6081/29964 -f 5258/6081/29965 5261/6146/29966 5262/6147/29967 -f 5261/6146/29968 5258/6081/29969 5257/6080/29970 -f 5264/6149/29971 5262/6147/29972 5261/6146/29973 -f 5261/6146/29974 5263/6148/29975 5264/6149/29976 -f 5265/6150/29977 5263/6148/29978 5267/6152/29979 -f 5267/6152/29980 5268/6153/29981 5265/6150/29982 -f 5270/6155/29983 5268/6153/29984 5267/6152/29985 -f 5267/6152/29986 5269/6154/29987 5270/6155/29988 -f 5261/6146/29989 5257/6080/29990 5267/6152/29991 -f 5267/6152/29992 5263/6148/29993 5261/6146/29994 -f 5271/6156/29995 5272/6157/29996 5299/6158/29997 -f 5273/6159/29998 5271/6156/29999 5267/6152/30000 -f 5267/6152/30001 5257/6080/30002 5273/6159/30003 -f 5257/6080/30004 5256/6078/30005 5242/6056/30006 -f 5242/6056/30007 5238/6054/30008 5257/6080/30009 -f 5273/6159/30010 5257/6080/30011 5238/6054/30012 -f 5274/6160/30013 5273/6159/30014 5238/6054/30015 -f 5238/6054/30016 5237/6055/30017 5274/6160/30018 -f 5275/6161/30019 5271/6156/30020 5273/6159/30021 -f 5273/6159/30022 5274/6160/30023 5275/6161/30024 -f 5276/6060/30025 5274/6059/30026 5237/6022/30027 -f 5237/6022/30028 5236/6021/30029 5276/6060/30030 -f 5274/6059/30031 5276/6060/30032 5277/6061/30033 -f 5277/6061/30034 5275/6062/30035 5274/6059/30036 -f 5278/6120/30037 5279/6121/30038 5240/6115/30039 -f 5240/6115/30040 5247/6118/30041 5278/6120/30042 -f 5286/6122/30043 5280/6123/30044 5279/6121/30045 -f 5279/6121/30046 5278/6120/30047 5286/6122/30048 -f 5239/6114/30049 5240/6115/30050 5279/6121/30051 -f 5279/6121/30052 5280/6123/30053 5239/6114/30054 -f 5281/6124/30055 5239/6114/30056 5280/6123/30057 -f 5247/6118/30058 5249/6119/30059 5251/6125/30060 -f 5251/6125/30061 5278/6120/30062 5247/6118/30063 -f 5278/6120/30064 5251/6125/30065 5282/6126/30066 -f 5282/6126/30067 5286/6122/30068 5278/6120/30069 -f 5253/6074/30070 5282/6162/30071 5251/6070/30072 -f 5251/6070/30073 5250/6069/30074 5253/6074/30075 -f 5253/6074/30076 5255/6077/30077 5283/6163/30078 -f 5283/6163/30079 5282/6162/30080 5253/6074/30081 -f 5286/6122/30082 5282/6126/30083 5283/6127/30084 -s 2 -f 5285/6165/30085 5260/6085/30086 5259/6084/30087 -f 5259/6084/30088 5284/6164/30089 5285/6165/30090 -s 1 -f 5286/6122/30091 5285/6129/30092 5284/6130/30093 -f 5284/6130/30094 5288/6128/30095 5286/6122/30096 -s 4 -f 5285/6165/30097 5286/6166/30098 5254/6076/30099 -f 5254/6076/30100 5260/6085/30101 5285/6165/30102 -s 2 -f 5283/6163/30103 5255/6077/30104 5254/6076/30105 -f 5254/6076/30106 5286/6166/30107 5283/6163/30108 -f 5259/6084/30109 5262/6147/30110 5287/6167/30111 -f 5287/6167/30112 5284/6164/30113 5259/6084/30114 -s 1 -f 5288/6128/30115 5284/6130/30116 5287/6131/30117 -s 2 -f 5262/6147/30118 5264/6149/30119 5289/6168/30120 -f 5289/6168/30121 5287/6167/30122 5262/6147/30123 -s 1 -f 5287/6131/30124 5289/6133/30125 5290/6132/30126 -f 5290/6132/30127 5288/6128/30128 5287/6131/30129 -f 5286/6122/30130 5288/6128/30131 5280/6123/30132 -f 5280/6123/30133 5288/6128/30134 5290/6132/30135 -s 2 -f 5289/6168/30136 5264/6149/30137 5266/6151/30138 -f 5266/6151/30139 5291/6169/30140 5289/6168/30141 -s 1 -f 5289/6133/30142 5291/6135/30143 5292/6134/30144 -f 5292/6134/30145 5290/6132/30146 5289/6133/30147 -f 5293/6136/30148 5294/6137/30149 5290/6132/30150 -f 5290/6132/30151 5292/6134/30152 5293/6136/30153 -f 5280/6123/30154 5290/6132/30155 5294/6137/30156 -f 5294/6137/30157 5293/6136/30158 5295/6138/30159 -f 5295/6138/30160 5296/6139/30161 5294/6137/30162 -f 5280/6123/30163 5294/6137/30164 5297/6140/30165 -f 5297/6140/30166 5281/6124/30167 5280/6123/30168 -f 5297/6140/30169 5277/6141/30170 5276/6142/30171 -f 5276/6142/30172 5281/6124/30173 5297/6140/30174 -f 5236/6113/30175 5239/6114/30176 5281/6124/30177 -f 5281/6124/30178 5276/6142/30179 5236/6113/30180 -f 5294/6137/30181 5296/6139/30182 5300/6143/30183 -f 5297/6140/30184 5294/6137/30185 5300/6143/30186 -f 5297/6140/30187 5300/6143/30188 5301/6144/30189 -f 5301/6144/30190 5298/6145/30191 5277/6141/30192 -f 5277/6141/30193 5297/6140/30194 5301/6144/30195 -f 5275/6062/30196 5277/6061/30197 5298/6083/30198 -f 5275/6161/30199 5298/6170/30200 5272/6157/30201 -f 5272/6157/30202 5271/6156/30203 5275/6161/30204 -s 4 -f 5292/6171/30205 5291/6169/30206 5266/6151/30207 -f 5266/6151/30208 5265/6150/30209 5292/6171/30210 -s 1 -f 5293/6173/30211 5268/6153/30212 5270/6155/30213 -f 5270/6155/30214 5295/6172/30215 5293/6173/30216 -f 5268/6153/30217 5293/6173/30218 5292/6171/30219 -f 5292/6171/30220 5265/6150/30221 5268/6153/30222 -f 5295/6172/30223 5270/6155/30224 5269/6154/30225 -f 5269/6154/30226 5296/6174/30227 5295/6172/30228 -f 5296/6174/30229 5269/6154/30230 5299/6158/30231 -f 5299/6158/30232 5300/6175/30233 5296/6174/30234 -f 5271/6156/30235 5299/6158/30236 5269/6154/30237 -f 5269/6154/30238 5267/6152/30239 5271/6156/30240 -f 5272/6157/30241 5298/6170/30242 5300/6175/30243 -f 5300/6175/30244 5299/6158/30245 5272/6157/30246 -f 5300/6143/30247 5298/6145/30248 5301/6144/30249 -f 5154/5949/30250 5141/5938/30251 5157/5953/30252 -f 5157/5953/30253 5141/5938/30254 5161/5956/30255 -f 5266/6151/30256 5264/6149/30257 5263/6148/30258 -f 5263/6148/30259 5265/6150/30260 5266/6151/30261 -f 5197/6093/30262 5194/6091/30263 5189/6075/30264 -f 5189/6075/30265 5302/6176/30266 5197/6093/30267 -f 5189/6075/30268 5184/6012/30269 5303/6177/30270 -f 5303/6177/30271 5302/6176/30272 5189/6075/30273 -f 5184/6012/30274 5185/6063/30275 5186/6065/30276 -f 5186/6065/30277 5303/6177/30278 5184/6012/30279 -f 5304/6180/30280 5320/6181/30281 5321/6178/30282 -f 5321/6178/30283 5305/6179/30284 5304/6180/30285 -f 5305/6179/30286 5321/6178/30287 5322/6182/30288 -f 5322/6182/30289 5306/6183/30290 5305/6179/30291 -f 5306/6183/30292 5322/6182/30293 5323/6184/30294 -f 5323/6184/30295 5307/6185/30296 5306/6183/30297 -f 5307/6185/30298 5323/6184/30299 5324/6186/30300 -f 5324/6186/30301 5308/6187/30302 5307/6185/30303 -f 5308/6187/30304 5324/6186/30305 5325/6188/30306 -f 5325/6188/30307 5309/6189/30308 5308/6187/30309 -f 5309/6189/30310 5325/6188/30311 5326/6190/30312 -f 5326/6190/30313 5310/6191/30314 5309/6189/30315 -f 5310/6191/30316 5326/6190/30317 5327/6192/30318 -f 5327/6192/30319 5311/6193/30320 5310/6191/30321 -f 5311/6193/30322 5327/6192/30323 5328/6194/30324 -f 5328/6194/30325 5312/6195/30326 5311/6193/30327 -f 5312/6195/30328 5328/6194/30329 5329/6196/30330 -f 5329/6196/30331 5313/6197/30332 5312/6195/30333 -f 5313/6197/30334 5329/6196/30335 5330/6198/30336 -f 5330/6198/30337 5314/6199/30338 5313/6197/30339 -f 5314/6199/30340 5330/6198/30341 5331/6200/30342 -f 5331/6200/30343 5315/6201/30344 5314/6199/30345 -f 5315/6201/30346 5331/6200/30347 5332/6202/30348 -f 5332/6202/30349 5316/6203/30350 5315/6201/30351 -f 5316/6203/30352 5332/6202/30353 5333/6204/30354 -f 5333/6204/30355 5317/6205/30356 5316/6203/30357 -f 5317/6205/30358 5333/6204/30359 5334/6206/30360 -f 5334/6206/30361 5318/6207/30362 5317/6205/30363 -f 5318/6207/30364 5334/6206/30365 5335/6208/30366 -f 5335/6208/30367 5319/6209/30368 5318/6207/30369 -f 5319/6209/30370 5335/6208/30371 5320/6181/30372 -f 5320/6181/30373 5304/6180/30374 5319/6209/30375 -f 5320/6181/30376 5336/6211/30377 5337/6210/30378 -f 5337/6210/30379 5321/6178/30380 5320/6181/30381 -f 5321/6178/30382 5337/6210/30383 5338/6212/30384 -f 5338/6212/30385 5322/6182/30386 5321/6178/30387 -f 5322/6182/30388 5338/6212/30389 5339/6213/30390 -f 5339/6213/30391 5323/6184/30392 5322/6182/30393 -f 5323/6184/30394 5339/6213/30395 5340/6214/30396 -f 5340/6214/30397 5324/6186/30398 5323/6184/30399 -f 5324/6186/30400 5340/6214/30401 5341/6215/30402 -f 5341/6215/30403 5325/6188/30404 5324/6186/30405 -f 5325/6188/30406 5341/6215/30407 5342/6216/30408 -f 5342/6216/30409 5326/6190/30410 5325/6188/30411 -f 5326/6190/30412 5342/6216/30413 5343/6217/30414 -f 5343/6217/30415 5327/6192/30416 5326/6190/30417 -f 5327/6192/30418 5343/6217/30419 5344/6218/30420 -f 5344/6218/30421 5328/6194/30422 5327/6192/30423 -f 5328/6194/30424 5344/6218/30425 5345/6219/30426 -f 5345/6219/30427 5329/6196/30428 5328/6194/30429 -f 5329/6196/30430 5345/6219/30431 5346/6220/30432 -f 5346/6220/30433 5330/6198/30434 5329/6196/30435 -f 5330/6198/30436 5346/6220/30437 5347/6221/30438 -f 5347/6221/30439 5331/6200/30440 5330/6198/30441 -f 5331/6200/30442 5347/6221/30443 5348/6222/30444 -f 5348/6222/30445 5332/6202/30446 5331/6200/30447 -f 5332/6202/30448 5348/6222/30449 5349/6223/30450 -f 5349/6223/30451 5333/6204/30452 5332/6202/30453 -f 5333/6204/30454 5349/6223/30455 5350/6224/30456 -f 5350/6224/30457 5334/6206/30458 5333/6204/30459 -f 5334/6206/30460 5350/6224/30461 5351/6225/30462 -f 5351/6225/30463 5335/6208/30464 5334/6206/30465 -f 5335/6208/30466 5351/6225/30467 5336/6211/30468 -f 5336/6211/30469 5320/6181/30470 5335/6208/30471 -f 5336/6211/30472 5352/6227/30473 5353/6226/30474 -f 5353/6226/30475 5337/6210/30476 5336/6211/30477 -f 5337/6210/30478 5353/6226/30479 5354/6228/30480 -f 5354/6228/30481 5338/6212/30482 5337/6210/30483 -f 5338/6212/30484 5354/6380/30485 5355/6229/30486 -f 5355/6229/30487 5339/6213/30488 5338/6212/30489 -f 5339/6213/30490 5355/6229/30491 5356/6230/30492 -f 5356/6230/30493 5340/6214/30494 5339/6213/30495 -f 5340/6214/30496 5356/6230/30497 5357/6231/30498 -f 5357/6231/30499 5341/6215/30500 5340/6214/30501 -f 5341/6215/30502 5357/6381/30503 5358/6232/30504 -f 5358/6232/30505 5342/6216/30506 5341/6215/30507 -f 5342/6216/30508 5358/6232/30509 5359/6233/30510 -f 5359/6233/30511 5343/6217/30512 5342/6216/30513 -f 5343/6217/30514 5359/6233/30515 5360/6234/30516 -f 5360/6234/30517 5344/6218/30518 5343/6217/30519 -f 5344/6218/30520 5360/6382/30521 5361/6235/30522 -f 5361/6235/30523 5345/6219/30524 5344/6218/30525 -f 5345/6219/30526 5361/6235/30527 5362/6236/30528 -f 5362/6236/30529 5346/6220/30530 5345/6219/30531 -f 5346/6220/30532 5362/6383/30533 5363/6237/30534 -f 5363/6237/30535 5347/6221/30536 5346/6220/30537 -f 5347/6221/30538 5363/6237/30539 5364/6238/30540 -f 5364/6238/30541 5348/6222/30542 5347/6221/30543 -f 5348/6222/30544 5364/6384/30545 5365/6239/30546 -f 5365/6239/30547 5349/6223/30548 5348/6222/30549 -f 5349/6223/30550 5365/6239/30551 5366/6240/30552 -f 5366/6240/30553 5350/6224/30554 5349/6223/30555 -f 5350/6224/30556 5366/6240/30557 5367/6241/30558 -f 5367/6241/30559 5351/6225/30560 5350/6224/30561 -f 5351/6225/30562 5367/6385/30563 5352/6227/30564 -f 5352/6227/30565 5336/6211/30566 5351/6225/30567 -f 5352/6227/30568 5368/6243/30569 5369/6242/30570 -f 5369/6242/30571 5353/6226/30572 5352/6227/30573 -f 5353/6226/30574 5369/6242/30575 5370/6244/30576 -f 5370/6244/30577 5354/6228/30578 5353/6226/30579 -f 5354/6380/30580 5370/6386/30581 5371/6245/30582 -f 5371/6245/30583 5355/6229/30584 5354/6380/30585 -f 5355/6229/30586 5371/6245/30587 5372/6246/30588 -f 5372/6246/30589 5356/6230/30590 5355/6229/30591 -f 5356/6230/30592 5372/6246/30593 5373/6247/30594 -f 5373/6247/30595 5357/6231/30596 5356/6230/30597 -f 5357/6381/30598 5373/6387/30599 5374/6248/30600 -f 5374/6248/30601 5358/6232/30602 5357/6381/30603 -f 5358/6232/30604 5374/6248/30605 5375/6249/30606 -f 5375/6249/30607 5359/6233/30608 5358/6232/30609 -f 5359/6233/30610 5375/6249/30611 5376/6250/30612 -f 5376/6250/30613 5360/6234/30614 5359/6233/30615 -f 5360/6382/30616 5376/6388/30617 5377/6251/30618 -f 5377/6251/30619 5361/6235/30620 5360/6382/30621 -f 5361/6235/30622 5377/6251/30623 5378/6252/30624 -f 5378/6252/30625 5362/6236/30626 5361/6235/30627 -f 5362/6383/30628 5378/6389/30629 5379/6253/30630 -f 5379/6253/30631 5363/6237/30632 5362/6383/30633 -f 5363/6237/30634 5379/6253/30635 5380/6254/30636 -f 5380/6254/30637 5364/6238/30638 5363/6237/30639 -f 5364/6384/30640 5380/6390/30641 5381/6255/30642 -f 5381/6255/30643 5365/6239/30644 5364/6384/30645 -f 5365/6239/30646 5381/6255/30647 5382/6256/30648 -f 5382/6256/30649 5366/6240/30650 5365/6239/30651 -f 5366/6240/30652 5382/6256/30653 5383/6257/30654 -f 5383/6257/30655 5367/6241/30656 5366/6240/30657 -f 5367/6385/30658 5383/6391/30659 5368/6243/30660 -f 5368/6243/30661 5352/6227/30662 5367/6385/30663 -f 5401/6260/30664 5402/6261/30665 5403/6258/30666 -f 5403/6258/30667 5388/6259/30668 5401/6260/30669 -f 5386/6264/30670 5389/6265/30671 5390/6262/30672 -f 5390/6262/30673 5385/6263/30674 5386/6264/30675 -f 5386/6264/30676 5387/6267/30677 5404/6266/30678 -f 5404/6266/30679 5389/6265/30680 5386/6264/30681 -f 5387/6267/30682 5388/6259/30683 5403/6258/30684 -f 5403/6258/30685 5404/6266/30686 5387/6267/30687 -f 5385/6263/30688 5390/6262/30689 5391/6268/30690 -f 5391/6268/30691 5384/6269/30692 5385/6263/30693 -f 5391/6268/30694 5392/6271/30695 5393/6270/30696 -f 5393/6270/30697 5384/6269/30698 5391/6268/30699 -f 5393/6270/30700 5394/6273/30701 5395/6272/30702 -f 5395/6272/30703 5384/6269/30704 5393/6270/30705 -f 5385/6263/30706 5384/6269/30707 5395/6272/30708 -f 5395/6272/30709 5396/6274/30710 5385/6263/30711 -f 5386/6264/30712 5385/6263/30713 5396/6274/30714 -f 5396/6274/30715 5397/6275/30716 5386/6264/30717 -f 5398/6276/30718 5387/6267/30719 5386/6264/30720 -f 5386/6264/30721 5397/6275/30722 5398/6276/30723 -f 5399/6277/30724 5388/6259/30725 5387/6267/30726 -f 5387/6267/30727 5398/6276/30728 5399/6277/30729 -f 5388/6259/30730 5399/6277/30731 5400/6278/30732 -f 5400/6278/30733 5401/6260/30734 5388/6259/30735 -f 5390/6262/30736 5389/6265/30737 5304/6180/30738 -f 5304/6180/30739 5305/6179/30740 5390/6262/30741 -f 5391/6268/30742 5390/6262/30743 5305/6179/30744 -f 5305/6179/30745 5306/6183/30746 5391/6268/30747 -f 5392/6271/30748 5391/6268/30749 5306/6183/30750 -f 5306/6183/30751 5307/6185/30752 5392/6271/30753 -f 5393/6270/30754 5392/6271/30755 5307/6185/30756 -f 5307/6185/30757 5308/6187/30758 5393/6270/30759 -f 5394/6273/30760 5393/6270/30761 5308/6187/30762 -f 5308/6187/30763 5309/6189/30764 5394/6273/30765 -f 5395/6272/30766 5394/6273/30767 5309/6189/30768 -f 5309/6189/30769 5310/6191/30770 5395/6272/30771 -f 5396/6274/30772 5395/6272/30773 5310/6191/30774 -f 5310/6191/30775 5311/6193/30776 5396/6274/30777 -f 5397/6275/30778 5396/6274/30779 5311/6193/30780 -f 5311/6193/30781 5312/6195/30782 5397/6275/30783 -f 5398/6276/30784 5397/6275/30785 5312/6195/30786 -f 5312/6195/30787 5313/6197/30788 5398/6276/30789 -f 5399/6277/30790 5398/6276/30791 5313/6197/30792 -f 5313/6197/30793 5314/6199/30794 5399/6277/30795 -f 5400/6278/30796 5399/6277/30797 5314/6199/30798 -f 5314/6199/30799 5315/6201/30800 5400/6278/30801 -f 5401/6260/30802 5400/6278/30803 5315/6201/30804 -f 5315/6201/30805 5316/6203/30806 5401/6260/30807 -f 5402/6261/30808 5401/6260/30809 5316/6203/30810 -f 5316/6203/30811 5317/6205/30812 5402/6261/30813 -f 5403/6258/30814 5402/6261/30815 5317/6205/30816 -f 5317/6205/30817 5318/6207/30818 5403/6258/30819 -f 5404/6266/30820 5403/6258/30821 5318/6207/30822 -f 5318/6207/30823 5319/6209/30824 5404/6266/30825 -f 5389/6265/30826 5404/6266/30827 5319/6209/30828 -f 5319/6209/30829 5304/6180/30830 5389/6265/30831 -f 5405/6281/30832 5408/6282/30833 5407/6279/30834 -f 5407/6279/30835 5406/6280/30836 5405/6281/30837 -f 5408/6282/30838 5410/6284/30839 5409/6283/30840 -f 5409/6283/30841 5407/6279/30842 5408/6282/30843 -f 5410/6284/30844 5412/6286/30845 5411/6285/30846 -f 5411/6285/30847 5409/6283/30848 5410/6284/30849 -f 5412/6286/30850 5414/6288/30851 5413/6287/30852 -f 5413/6287/30853 5411/6285/30854 5412/6286/30855 -f 5414/6288/30856 5416/6290/30857 5415/6289/30858 -f 5415/6289/30859 5413/6287/30860 5414/6288/30861 -f 5416/6290/30862 5418/6292/30863 5417/6291/30864 -f 5417/6291/30865 5415/6289/30866 5416/6290/30867 -f 5418/6292/30868 5420/6294/30869 5419/6293/30870 -f 5419/6293/30871 5417/6291/30872 5418/6292/30873 -f 5420/6294/30874 5422/6296/30875 5421/6295/30876 -f 5421/6295/30877 5419/6293/30878 5420/6294/30879 -f 5422/6296/30880 5424/6298/30881 5423/6297/30882 -f 5423/6297/30883 5421/6295/30884 5422/6296/30885 -f 5424/6298/30886 5426/6300/30887 5425/6299/30888 -f 5425/6299/30889 5423/6297/30890 5424/6298/30891 -f 5426/6300/30892 5428/6302/30893 5427/6301/30894 -f 5427/6301/30895 5425/6299/30896 5426/6300/30897 -f 5428/6302/30898 5430/6304/30899 5429/6303/30900 -f 5429/6303/30901 5427/6301/30902 5428/6302/30903 -f 5430/6304/30904 5432/6306/30905 5431/6305/30906 -f 5431/6305/30907 5429/6303/30908 5430/6304/30909 -f 5432/6306/30910 5434/6308/30911 5433/6307/30912 -f 5433/6307/30913 5431/6305/30914 5432/6306/30915 -f 5434/6308/30916 5436/6310/30917 5435/6309/30918 -f 5435/6309/30919 5433/6307/30920 5434/6308/30921 -f 5436/6310/30922 5405/6281/30923 5406/6280/30924 -f 5406/6280/30925 5435/6309/30926 5436/6310/30927 -f 5406/6280/30928 5407/6279/30929 5438/6311/30930 -f 5438/6311/30931 5437/6312/30932 5406/6280/30933 -f 5407/6279/30934 5409/6283/30935 5439/6313/30936 -f 5439/6313/30937 5438/6311/30938 5407/6279/30939 -f 5409/6283/30940 5411/6285/30941 5440/6314/30942 -f 5440/6314/30943 5439/6313/30944 5409/6283/30945 -f 5411/6285/30946 5413/6287/30947 5441/6315/30948 -f 5441/6315/30949 5440/6314/30950 5411/6285/30951 -f 5413/6287/30952 5415/6289/30953 5442/6316/30954 -f 5442/6316/30955 5441/6315/30956 5413/6287/30957 -f 5415/6289/30958 5417/6291/30959 5443/6317/30960 -f 5443/6317/30961 5442/6316/30962 5415/6289/30963 -f 5417/6291/30964 5419/6293/30965 5444/6318/30966 -f 5444/6318/30967 5443/6317/30968 5417/6291/30969 -f 5419/6293/30970 5421/6295/30971 5445/6319/30972 -f 5445/6319/30973 5444/6318/30974 5419/6293/30975 -f 5421/6295/30976 5423/6297/30977 5446/6320/30978 -f 5446/6320/30979 5445/6319/30980 5421/6295/30981 -f 5423/6297/30982 5425/6299/30983 5447/6321/30984 -f 5447/6321/30985 5446/6320/30986 5423/6297/30987 -f 5425/6299/30988 5427/6301/30989 5448/6322/30990 -f 5448/6322/30991 5447/6321/30992 5425/6299/30993 -f 5427/6301/30994 5429/6303/30995 5449/6323/30996 -f 5449/6323/30997 5448/6322/30998 5427/6301/30999 -f 5429/6303/31000 5431/6305/31001 5450/6324/31002 -f 5450/6324/31003 5449/6323/31004 5429/6303/31005 -f 5431/6305/31006 5433/6307/31007 5451/6325/31008 -f 5451/6325/31009 5450/6324/31010 5431/6305/31011 -f 5433/6307/31012 5435/6309/31013 5452/6326/31014 -f 5452/6326/31015 5451/6325/31016 5433/6307/31017 -f 5435/6309/31018 5406/6280/31019 5437/6312/31020 -f 5437/6312/31021 5452/6326/31022 5435/6309/31023 -f 5437/6312/31024 5438/6311/31025 5454/6327/31026 -f 5454/6327/31027 5453/6328/31028 5437/6312/31029 -f 5438/6311/31030 5439/6313/31031 5455/6329/31032 -f 5455/6329/31033 5454/6392/31034 5438/6311/31035 -f 5439/6313/31036 5440/6314/31037 5456/6330/31038 -f 5456/6330/31039 5455/6329/31040 5439/6313/31041 -f 5440/6314/31042 5441/6315/31043 5457/6331/31044 -f 5457/6331/31045 5456/6330/31046 5440/6314/31047 -f 5441/6315/31048 5442/6316/31049 5458/6332/31050 -f 5458/6332/31051 5457/6393/31052 5441/6315/31053 -f 5442/6316/31054 5443/6317/31055 5459/6333/31056 -f 5459/6333/31057 5458/6332/31058 5442/6316/31059 -f 5443/6317/31060 5444/6318/31061 5460/6334/31062 -f 5460/6334/31063 5459/6333/31064 5443/6317/31065 -f 5444/6318/31066 5445/6319/31067 5461/6335/31068 -f 5461/6335/31069 5460/6394/31070 5444/6318/31071 -f 5445/6319/31072 5446/6320/31073 5462/6336/31074 -f 5462/6336/31075 5461/6335/31076 5445/6319/31077 -f 5446/6320/31078 5447/6321/31079 5463/6337/31080 -f 5463/6337/31081 5462/6395/31082 5446/6320/31083 -f 5447/6321/31084 5448/6322/31085 5464/6338/31086 -f 5464/6338/31087 5463/6337/31088 5447/6321/31089 -f 5448/6322/31090 5449/6323/31091 5465/6339/31092 -f 5465/6339/31093 5464/6396/31094 5448/6322/31095 -f 5449/6323/31096 5450/6324/31097 5466/6340/31098 -f 5466/6340/31099 5465/6339/31100 5449/6323/31101 -f 5450/6324/31102 5451/6325/31103 5467/6341/31104 -f 5467/6341/31105 5466/6340/31106 5450/6324/31107 -f 5451/6325/31108 5452/6326/31109 5468/6342/31110 -f 5468/6342/31111 5467/6397/31112 5451/6325/31113 -f 5452/6326/31114 5437/6312/31115 5453/6328/31116 -f 5453/6328/31117 5468/6342/31118 5452/6326/31119 -f 5453/6328/31120 5454/6327/31121 5470/6343/31122 -f 5470/6343/31123 5469/6344/31124 5453/6328/31125 -f 5454/6392/31126 5455/6329/31127 5471/6345/31128 -f 5471/6345/31129 5470/6398/31130 5454/6392/31131 -f 5455/6329/31132 5456/6330/31133 5472/6346/31134 -f 5472/6346/31135 5471/6345/31136 5455/6329/31137 -f 5456/6330/31138 5457/6331/31139 5473/6347/31140 -f 5473/6347/31141 5472/6346/31142 5456/6330/31143 -f 5457/6393/31144 5458/6332/31145 5474/6348/31146 -f 5474/6348/31147 5473/6399/31148 5457/6393/31149 -f 5458/6332/31150 5459/6333/31151 5475/6349/31152 -f 5475/6349/31153 5474/6348/31154 5458/6332/31155 -f 5459/6333/31156 5460/6334/31157 5476/6350/31158 -f 5476/6350/31159 5475/6349/31160 5459/6333/31161 -f 5460/6394/31162 5461/6335/31163 5477/6351/31164 -f 5477/6351/31165 5476/6400/31166 5460/6394/31167 -f 5461/6335/31168 5462/6336/31169 5478/6352/31170 -f 5478/6352/31171 5477/6351/31172 5461/6335/31173 -f 5462/6395/31174 5463/6337/31175 5479/6353/31176 -f 5479/6353/31177 5478/6401/31178 5462/6395/31179 -f 5463/6337/31180 5464/6338/31181 5480/6354/31182 -f 5480/6354/31183 5479/6353/31184 5463/6337/31185 -f 5464/6396/31186 5465/6339/31187 5481/6355/31188 -f 5481/6355/31189 5480/6402/31190 5464/6396/31191 -f 5465/6339/31192 5466/6340/31193 5482/6356/31194 -f 5482/6356/31195 5481/6355/31196 5465/6339/31197 -f 5466/6340/31198 5467/6341/31199 5483/6357/31200 -f 5483/6357/31201 5482/6356/31202 5466/6340/31203 -f 5467/6397/31204 5468/6342/31205 5484/6358/31206 -f 5484/6358/31207 5483/6403/31208 5467/6397/31209 -f 5468/6342/31210 5453/6328/31211 5469/6344/31212 -f 5469/6344/31213 5484/6358/31214 5468/6342/31215 -f 5485/6361/31216 5488/6362/31217 5487/6359/31218 -f 5487/6359/31219 5486/6360/31220 5485/6361/31221 -f 5492/6365/31222 5491/6366/31223 5490/6363/31224 -f 5490/6363/31225 5489/6364/31226 5492/6365/31227 -f 5492/6365/31228 5489/6364/31229 5493/6367/31230 -f 5493/6367/31231 5494/6368/31232 5492/6365/31233 -f 5494/6368/31234 5493/6367/31235 5487/6359/31236 -f 5487/6359/31237 5488/6362/31238 5494/6368/31239 -f 5491/6366/31240 5496/6370/31241 5495/6369/31242 -f 5495/6369/31243 5490/6363/31244 5491/6366/31245 -f 5495/6369/31246 5496/6370/31247 5498/6371/31248 -f 5498/6371/31249 5497/6372/31250 5495/6369/31251 -f 5498/6371/31252 5496/6370/31253 5500/6373/31254 -f 5500/6373/31255 5499/6374/31256 5498/6371/31257 -f 5491/6366/31258 5501/6375/31259 5500/6373/31260 -f 5500/6373/31261 5496/6370/31262 5491/6366/31263 -f 5492/6365/31264 5502/6376/31265 5501/6375/31266 -f 5501/6375/31267 5491/6366/31268 5492/6365/31269 -f 5503/6377/31270 5502/6376/31271 5492/6365/31272 -f 5492/6365/31273 5494/6368/31274 5503/6377/31275 -f 5504/6378/31276 5503/6377/31277 5494/6368/31278 -f 5494/6368/31279 5488/6362/31280 5504/6378/31281 -f 5488/6362/31282 5485/6361/31283 5505/6379/31284 -f 5505/6379/31285 5504/6378/31286 5488/6362/31287 -f 5490/6363/31288 5408/6282/31289 5405/6281/31290 -f 5405/6281/31291 5489/6364/31292 5490/6363/31293 -f 5495/6369/31294 5410/6284/31295 5408/6282/31296 -f 5408/6282/31297 5490/6363/31298 5495/6369/31299 -f 5497/6372/31300 5412/6286/31301 5410/6284/31302 -f 5410/6284/31303 5495/6369/31304 5497/6372/31305 -f 5498/6371/31306 5414/6288/31307 5412/6286/31308 -f 5412/6286/31309 5497/6372/31310 5498/6371/31311 -f 5499/6374/31312 5416/6290/31313 5414/6288/31314 -f 5414/6288/31315 5498/6371/31316 5499/6374/31317 -f 5500/6373/31318 5418/6292/31319 5416/6290/31320 -f 5416/6290/31321 5499/6374/31322 5500/6373/31323 -f 5501/6375/31324 5420/6294/31325 5418/6292/31326 -f 5418/6292/31327 5500/6373/31328 5501/6375/31329 -f 5502/6376/31330 5422/6296/31331 5420/6294/31332 -f 5420/6294/31333 5501/6375/31334 5502/6376/31335 -f 5503/6377/31336 5424/6298/31337 5422/6296/31338 -f 5422/6296/31339 5502/6376/31340 5503/6377/31341 -f 5504/6378/31342 5426/6300/31343 5424/6298/31344 -f 5424/6298/31345 5503/6377/31346 5504/6378/31347 -f 5505/6379/31348 5428/6302/31349 5426/6300/31350 -f 5426/6300/31351 5504/6378/31352 5505/6379/31353 -f 5485/6361/31354 5430/6304/31355 5428/6302/31356 -f 5428/6302/31357 5505/6379/31358 5485/6361/31359 -f 5486/6360/31360 5432/6306/31361 5430/6304/31362 -f 5430/6304/31363 5485/6361/31364 5486/6360/31365 -f 5487/6359/31366 5434/6308/31367 5432/6306/31368 -f 5432/6306/31369 5486/6360/31370 5487/6359/31371 -f 5493/6367/31372 5436/6310/31373 5434/6308/31374 -f 5434/6308/31375 5487/6359/31376 5493/6367/31377 -f 5489/6364/31378 5405/6281/31379 5436/6310/31380 -f 5436/6310/31381 5493/6367/31382 5489/6364/31383 -f 5520/6406/31384 5507/6407/31385 5596/6404/31386 -f 5596/6404/31387 5521/6405/31388 5520/6406/31389 -f 5522/6408/31390 5510/6409/31391 5507/6407/31392 -f 5507/6407/31393 5520/6406/31394 5522/6408/31395 -f 5515/6412/31396 5516/6413/31397 5531/6410/31398 -f 5531/6410/31399 5529/6411/31400 5515/6412/31401 -f 5519/6416/31402 5518/6417/31403 5528/6414/31404 -f 5528/6414/31405 5527/6415/31406 5519/6416/31407 -f 5508/6420/31408 5509/6421/31409 5524/6418/31410 -f 5524/6418/31411 5523/6419/31412 5508/6420/31413 -f 5526/6422/31414 5513/6423/31415 5519/6416/31416 -f 5519/6416/31417 5527/6415/31418 5526/6422/31419 -f 5519/6416/31420 5513/6423/31421 5525/6424/31422 -f 5525/6424/31423 5523/6419/31424 5519/6416/31425 -f 5508/6420/31426 5520/6406/31427 5521/6405/31428 -f 5521/6405/31429 5509/6421/31430 5508/6420/31431 -f 5511/6425/31432 5522/6408/31433 5520/6406/31434 -f 5520/6406/31435 5508/6420/31436 5511/6425/31437 -f 5523/6419/31438 5524/6418/31439 5518/6417/31440 -f 5518/6417/31441 5519/6416/31442 5523/6419/31443 -f 5508/6420/31444 5523/6419/31445 5525/6424/31446 -f 5525/6424/31447 5511/6425/31448 5508/6420/31449 -f 5527/6415/31450 5528/6414/31451 5516/6413/31452 -f 5516/6413/31453 5515/6412/31454 5527/6415/31455 -f 5512/6426/31456 5526/6422/31457 5527/6415/31458 -f 5527/6415/31459 5515/6412/31460 5512/6426/31461 -f 5529/6411/31462 5530/6427/31463 5512/6426/31464 -f 5512/6426/31465 5515/6412/31466 5529/6411/31467 -f 5529/6411/31468 5531/6410/31469 5517/6428/31470 -f 5517/6428/31471 5599/6429/31472 5529/6411/31473 -f 5542/6430/31474 5532/6431/31475 5510/6409/31476 -f 5510/6409/31477 5522/6408/31478 5542/6430/31479 -f 5543/6432/31480 5534/6433/31481 5532/6431/31482 -f 5532/6431/31483 5542/6430/31484 5543/6432/31485 -f 5544/6436/31486 5535/6437/31487 5533/6434/31488 -f 5533/6434/31489 5545/6435/31490 5544/6436/31491 -f 5547/6440/31492 5546/6441/31493 5538/6438/31494 -f 5538/6438/31495 5539/6439/31496 5547/6440/31497 -f 5526/6422/31498 5512/6426/31499 5538/6438/31500 -f 5538/6438/31501 5546/6441/31502 5526/6422/31503 -f 5530/6427/31504 5529/6411/31505 5599/6429/31506 -f 5599/6429/31507 5606/6442/31508 5530/6427/31509 -f 5606/6442/31510 5607/6444/31511 5548/6443/31512 -f 5548/6443/31513 5530/6427/31514 5606/6442/31515 -f 5533/6434/31516 5511/6425/31517 5525/6424/31518 -f 5525/6424/31519 5545/6435/31520 5533/6434/31521 -f 5533/6434/31522 5542/6430/31523 5522/6408/31524 -f 5522/6408/31525 5511/6425/31526 5533/6434/31527 -f 5535/6437/31528 5543/6432/31529 5542/6430/31530 -f 5542/6430/31531 5533/6434/31532 5535/6437/31533 -f 5536/6446/31534 5544/6436/31535 5545/6435/31536 -f 5545/6435/31537 5537/6445/31538 5536/6446/31539 -f 5545/6435/31540 5525/6424/31541 5513/6423/31542 -f 5513/6423/31543 5537/6445/31544 5545/6435/31545 -f 5546/6441/31546 5547/6440/31547 5536/6446/31548 -f 5536/6446/31549 5537/6445/31550 5546/6441/31551 -f 5513/6423/31552 5526/6422/31553 5546/6441/31554 -f 5546/6441/31555 5537/6445/31556 5513/6423/31557 -f 5530/6427/31558 5548/6443/31559 5538/6438/31560 -f 5538/6438/31561 5512/6426/31562 5530/6427/31563 -f 5548/6443/31564 5549/6447/31565 5539/6439/31566 -f 5539/6439/31567 5538/6438/31568 5548/6443/31569 -f 5607/6444/31570 5612/6448/31571 5549/6447/31572 -f 5549/6447/31573 5548/6443/31574 5607/6444/31575 -f 5565/6453/31576 5566/6473/31577 5551/6449/31578 -f 5551/6449/31579 5552/6450/31580 5565/6453/31581 -f 5567/6475/31582 5565/6453/31583 5552/6450/31584 -f 5552/6450/31585 5555/6474/31586 5567/6475/31587 -f 5560/6457/31588 5574/6458/31589 5576/6455/31590 -f 5576/6455/31591 5561/6456/31592 5560/6457/31593 -f 5564/6461/31594 5572/6462/31595 5573/6459/31596 -f 5573/6459/31597 5563/6460/31598 5564/6461/31599 -f 5553/6465/31600 5568/6466/31601 5569/6463/31602 -f 5569/6463/31603 5554/6464/31604 5553/6465/31605 -f 5571/6468/31606 5572/6462/31607 5564/6461/31608 -f 5564/6461/31609 5558/6467/31610 5571/6468/31611 -f 5564/6461/31612 5568/6466/31613 5570/6469/31614 -f 5570/6469/31615 5558/6467/31616 5564/6461/31617 -f 5553/6465/31618 5554/6464/31619 5566/6452/31620 -f 5566/6452/31621 5565/6451/31622 5553/6465/31623 -f 5556/6470/31624 5553/6465/31625 5565/6451/31626 -f 5565/6451/31627 5567/6454/31628 5556/6470/31629 -f 5568/6466/31630 5564/6461/31631 5563/6460/31632 -f 5563/6460/31633 5569/6463/31634 5568/6466/31635 -f 5553/6465/31636 5556/6470/31637 5570/6469/31638 -f 5570/6469/31639 5568/6466/31640 5553/6465/31641 -f 5572/6462/31642 5560/6457/31643 5561/6456/31644 -f 5561/6456/31645 5573/6459/31646 5572/6462/31647 -f 5557/6471/31648 5560/6457/31649 5572/6462/31650 -f 5572/6462/31651 5571/6468/31652 5557/6471/31653 -f 5574/6458/31654 5560/6457/31655 5557/6471/31656 -f 5557/6471/31657 5575/6472/31658 5574/6458/31659 -f 5574/6480/31660 5559/6481/31661 5562/6477/31662 -f 5562/6477/31663 5576/6478/31664 5574/6480/31665 -f 5587/6486/31666 5567/6475/31667 5555/6474/31668 -f 5555/6474/31669 5577/6485/31670 5587/6486/31671 -f 5588/6489/31672 5587/6486/31673 5577/6485/31674 -f 5577/6485/31675 5579/6487/31676 5588/6489/31677 -f 5589/6493/31678 5590/6494/31679 5578/6490/31680 -f 5578/6490/31681 5580/6492/31682 5589/6493/31683 -f 5592/6497/31684 5584/6498/31685 5583/6495/31686 -f 5583/6495/31687 5591/6496/31688 5592/6497/31689 -f 5571/6468/31690 5591/6484/31691 5583/6483/31692 -f 5583/6483/31693 5557/6471/31694 5571/6468/31695 -f 5575/6499/31696 5585/6500/31697 5559/6481/31698 -f 5559/6481/31699 5574/6480/31700 5575/6499/31701 -f 5585/6500/31702 5575/6499/31703 5593/6502/31704 -f 5593/6502/31705 5586/6506/31706 5585/6500/31707 -f 5578/6479/31708 5590/6482/31709 5570/6469/31710 -f 5570/6469/31711 5556/6470/31712 5578/6479/31713 -f 5578/6479/31714 5556/6470/31715 5567/6454/31716 -f 5567/6454/31717 5587/6476/31718 5578/6479/31719 -f 5580/6492/31720 5578/6490/31721 5587/6531/31722 -f 5587/6531/31723 5588/6532/31724 5580/6492/31725 -f 5581/6503/31726 5582/6504/31727 5590/6494/31728 -f 5590/6494/31729 5589/6493/31730 5581/6503/31731 -f 5590/6482/31732 5582/6491/31733 5558/6467/31734 -f 5558/6467/31735 5570/6469/31736 5590/6482/31737 -f 5591/6496/31738 5582/6504/31739 5581/6503/31740 -f 5581/6503/31741 5592/6497/31742 5591/6496/31743 -f 5558/6467/31744 5582/6491/31745 5591/6484/31746 -f 5591/6484/31747 5571/6468/31748 5558/6467/31749 -f 5575/6472/31750 5557/6471/31751 5583/6483/31752 -f 5583/6483/31753 5593/6488/31754 5575/6472/31755 -f 5593/6501/31756 5583/6495/31757 5584/6498/31758 -f 5584/6498/31759 5594/6505/31760 5593/6501/31761 -f 5586/6506/31762 5593/6502/31763 5594/6507/31764 -f 5594/6507/31765 5595/6508/31766 5586/6506/31767 -s 2 -f 5506/6539/31768 5597/6510/31769 5552/6450/31770 -f 5552/6450/31771 5551/6449/31772 5506/6539/31773 -f 5551/6533/31774 5596/6404/31775 5506/6509/31776 -f 5597/6510/31777 5598/6511/31778 5555/6474/31779 -f 5555/6474/31780 5552/6450/31781 5597/6510/31782 -s 4 -f 5531/6410/31783 5516/6413/31784 5561/6512/31785 -f 5561/6512/31786 5576/6536/31787 5531/6410/31788 -f 5528/6414/31789 5518/6417/31790 5563/6513/31791 -f 5563/6513/31792 5573/6514/31793 5528/6414/31794 -f 5524/6418/31795 5509/6421/31796 5554/6515/31797 -f 5554/6515/31798 5569/6516/31799 5524/6418/31800 -f 5509/6421/31801 5521/6405/31802 5566/6534/31803 -f 5566/6534/31804 5554/6515/31805 5509/6421/31806 -f 5518/6417/31807 5524/6418/31808 5569/6516/31809 -f 5569/6516/31810 5563/6513/31811 5518/6417/31812 -f 5516/6413/31813 5528/6414/31814 5573/6514/31815 -f 5573/6514/31816 5561/6512/31817 5516/6413/31818 -f 5576/6536/31819 5562/6535/31820 5517/6428/31821 -f 5517/6428/31822 5531/6410/31823 5576/6536/31824 -s 1 -f 5514/6518/31825 5600/6540/31826 5562/6477/31827 -f 5562/6477/31828 5559/6481/31829 5514/6518/31830 -s 2 -f 5598/6511/31831 5601/6519/31832 5577/6485/31833 -f 5577/6485/31834 5555/6474/31835 5598/6511/31836 -f 5601/6519/31837 5602/6541/31838 5579/6487/31839 -f 5579/6487/31840 5577/6485/31841 5601/6519/31842 -s 1 -f 5602/6520/31843 5608/6521/31844 5588/6532/31845 -f 5588/6532/31846 5579/6537/31847 5602/6520/31848 -f 5603/6522/31849 5609/6523/31850 5589/6493/31851 -f 5589/6493/31852 5580/6492/31853 5603/6522/31854 -f 5610/6524/31855 5605/6525/31856 5584/6498/31857 -f 5584/6498/31858 5592/6497/31859 5610/6524/31860 -f 5540/6526/31861 5514/6518/31862 5559/6481/31863 -f 5559/6481/31864 5585/6500/31865 5540/6526/31866 -f 5541/6527/31867 5540/6526/31868 5585/6500/31869 -f 5585/6500/31870 5586/6506/31871 5541/6527/31872 -f 5608/6521/31873 5603/6522/31874 5580/6492/31875 -f 5580/6492/31876 5588/6532/31877 5608/6521/31878 -f 5609/6523/31879 5604/6528/31880 5581/6503/31881 -f 5581/6503/31882 5589/6493/31883 5609/6523/31884 -f 5604/6528/31885 5610/6524/31886 5592/6497/31887 -f 5592/6497/31888 5581/6503/31889 5604/6528/31890 -f 5605/6525/31891 5611/6529/31892 5594/6505/31893 -f 5594/6505/31894 5584/6498/31895 5605/6525/31896 -f 5611/6529/31897 5550/6542/31898 5595/6538/31899 -f 5595/6538/31900 5594/6505/31901 5611/6529/31902 -f 5550/6530/31903 5541/6527/31904 5586/6506/31905 -f 5586/6506/31906 5595/6508/31907 5550/6530/31908 -s 2 -f 5507/6407/31909 5597/6510/31910 5506/6539/31911 -f 5506/6539/31912 5596/6404/31913 5507/6407/31914 -f 5510/6409/31915 5598/6511/31916 5597/6510/31917 -f 5597/6510/31918 5507/6407/31919 5510/6409/31920 -s 1 -f 5517/6428/31921 5600/6540/31922 5514/6518/31923 -f 5514/6518/31924 5599/6429/31925 5517/6428/31926 -s 2 -f 5532/6431/31927 5601/6519/31928 5598/6511/31929 -f 5598/6511/31930 5510/6409/31931 5532/6431/31932 -s 1 -f 5543/6432/31933 5608/6521/31934 5602/6520/31935 -f 5602/6520/31936 5534/6433/31937 5543/6432/31938 -s 2 -f 5534/6433/31939 5602/6541/31940 5601/6519/31941 -f 5601/6519/31942 5532/6431/31943 5534/6433/31944 -s 1 -f 5544/6436/31945 5609/6523/31946 5603/6522/31947 -f 5603/6522/31948 5535/6437/31949 5544/6436/31950 -f 5539/6439/31951 5605/6525/31952 5610/6524/31953 -f 5610/6524/31954 5547/6440/31955 5539/6439/31956 -f 5599/6429/31957 5514/6518/31958 5540/6526/31959 -f 5540/6526/31960 5606/6442/31961 5599/6429/31962 -f 5606/6442/31963 5540/6526/31964 5541/6527/31965 -f 5541/6527/31966 5607/6444/31967 5606/6442/31968 -f 5535/6437/31969 5603/6522/31970 5608/6521/31971 -f 5608/6521/31972 5543/6432/31973 5535/6437/31974 -f 5536/6446/31975 5604/6528/31976 5609/6523/31977 -f 5609/6523/31978 5544/6436/31979 5536/6446/31980 -f 5547/6440/31981 5610/6524/31982 5604/6528/31983 -f 5604/6528/31984 5536/6446/31985 5547/6440/31986 -f 5549/6447/31987 5611/6529/31988 5605/6525/31989 -f 5605/6525/31990 5539/6439/31991 5549/6447/31992 -f 5607/6444/31993 5541/6527/31994 5550/6530/31995 -f 5550/6530/31996 5612/6448/31997 5607/6444/31998 -f 5612/6448/31999 5550/6542/32000 5611/6529/32001 -f 5611/6529/32002 5549/6447/32003 5612/6448/32004 -f 5562/6535/32005 5600/6517/32006 5517/6428/32007 -s 4 -f 5566/6534/32008 5521/6405/32009 5596/6404/32010 -f 5596/6404/32011 5551/6533/32012 5566/6534/32013 -# 10671 faces - diff --git a/examples/shaders/custom_uniform/dwarf_diffuse.png b/examples/shaders/custom_uniform/dwarf_diffuse.png deleted file mode 100644 index 15dee61..0000000 Binary files a/examples/shaders/custom_uniform/dwarf_diffuse.png and /dev/null differ diff --git a/examples/shaders/custom_uniform/glsl330/swirl.fs b/examples/shaders/custom_uniform/glsl330/swirl.fs index 4741e59..b2a53ca 100644 --- a/examples/shaders/custom_uniform/glsl330/swirl.fs +++ b/examples/shaders/custom_uniform/glsl330/swirl.fs @@ -11,8 +11,6 @@ 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; @@ -20,6 +18,7 @@ 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() @@ -41,7 +40,7 @@ void main() } tc += center; - vec4 color = texture2D(texture0, tc/texSize)*colDiffuse*fragColor;; + vec4 color = texture(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 8742189..82c10f5 100644 --- a/examples/shaders/custom_uniform/main.go +++ b/examples/shaders/custom_uniform/main.go @@ -1,97 +1,100 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) + rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - custom uniform variable") + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - custom uniform variable") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(3.0, 3.0, 3.0) - camera.Target = raylib.NewVector3(0.0, 1.5, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(8.0, 8.0, 8.0) + camera.Target = rl.NewVector3(0.0, 1.5, 0.0) + camera.Up = rl.NewVector3(0.0, 1.0, 0.0) camera.Fovy = 45.0 + camera.Projection = rl.CameraPerspective - dwarf := raylib.LoadModel("dwarf.obj") // Load OBJ model - texture := raylib.LoadTexture("dwarf_diffuse.png") // Load model texture + obj := rl.LoadModel("barracks.obj") // Load OBJ model + texture := rl.LoadTexture("barracks_diffuse.png") // Load model texture - dwarf.Material.Maps[raylib.MapDiffuse].Texture = texture // Set dwarf model diffuse texture + rl.SetMaterialTexture(obj.Materials, rl.MapDiffuse, texture) // Set obj model diffuse texture - position := raylib.NewVector3(0.0, 0.0, 0.0) // Set model position + position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position - shader := raylib.LoadShader("glsl330/base.vs", "glsl330/swirl.fs") // Load postpro shader + shader := rl.LoadShader("", "glsl330/swirl.fs") // 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 := raylib.GetShaderLocation(shader, "center") + 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 swirlCenter[1] = float32(screenHeight) / 2 // Create a RenderTexture2D to be used for render to texture - target := raylib.LoadRenderTexture(screenWidth, screenHeight) + target := rl.LoadRenderTexture(screenWidth, screenHeight) - // Setup orbital camera - raylib.SetCameraMode(camera, raylib.CameraOrbital) // Set an orbital camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update //---------------------------------------------------------------------------------- - mousePosition := raylib.GetMousePosition() + mousePosition := rl.GetMousePosition() swirlCenter[0] = mousePosition.X swirlCenter[1] = float32(screenHeight) - mousePosition.Y // Send new value to the shader to be used on drawing - raylib.SetShaderValue(shader, swirlCenterLoc, swirlCenter, 2) + rl.SetShaderValue(shader, swirlCenterLoc, swirlCenter, rl.ShaderUniformVec2) - raylib.UpdateCamera(&camera) // Update camera + rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginTextureMode(target) // Enable drawing to texture + rl.BeginTextureMode(target) // Enable drawing to texture - raylib.BeginMode3D(camera) + rl.ClearBackground(rl.RayWhite) - raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture + rl.BeginMode3D(camera) - raylib.DrawGrid(10, 1.0) // Draw a grid + rl.DrawModel(obj, position, 0.5, rl.White) // Draw 3d model with texture - raylib.EndMode3D() + rl.DrawGrid(10, 1.0) // Draw a grid - raylib.DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, raylib.Red) + rl.EndMode3D() - raylib.EndTextureMode() // End drawing to texture (now we have a texture available for next passes) + rl.DrawText("TEXT DRAWN IN RENDER TEXTURE", 200, 10, 30, rl.Red) - raylib.BeginShaderMode(shader) + rl.EndTextureMode() // End drawing to texture (now we have a texture available for next passes) + + rl.BeginShaderMode(shader) // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) - raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), raylib.NewVector2(0, 0), raylib.White) + rl.DrawTextureRec(target.Texture, rl.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), rl.NewVector2(0, 0), rl.White) - raylib.EndShaderMode() + rl.EndShaderMode() - raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray) + rl.DrawText("(c) Barracks 3D model by Alberto Cano", screenWidth-200, screenHeight-20, 10, rl.Gray) - raylib.DrawFPS(10, 10) + rl.DrawFPS(10, 10) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadShader(shader) // Unload shader - raylib.UnloadTexture(texture) // Unload texture - raylib.UnloadModel(dwarf) // Unload model - raylib.UnloadRenderTexture(target) // Unload render texture + rl.UnloadShader(shader) // Unload shader + rl.UnloadTexture(texture) // Unload texture + rl.UnloadModel(obj) // Unload model + rl.UnloadRenderTexture(target) // Unload render texture - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shaders/eratosthenes/eratosthenes.fs b/examples/shaders/eratosthenes/eratosthenes.fs new file mode 100644 index 0000000..644e38d --- /dev/null +++ b/examples/shaders/eratosthenes/eratosthenes.fs @@ -0,0 +1,59 @@ +#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 new file mode 100644 index 0000000..62b070f --- /dev/null +++ b/examples/shaders/eratosthenes/main.go @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000..d198efe --- /dev/null +++ b/examples/shaders/mesh_instancing/glsl330/base_lighting_instanced.vs @@ -0,0 +1,36 @@ +#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 new file mode 100644 index 0000000..6877c1c --- /dev/null +++ b/examples/shaders/mesh_instancing/glsl330/lighting.fs @@ -0,0 +1,82 @@ +#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 new file mode 100644 index 0000000..c398de0 --- /dev/null +++ b/examples/shaders/mesh_instancing/light.go @@ -0,0 +1,76 @@ +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 new file mode 100644 index 0000000..ce5862c --- /dev/null +++ b/examples/shaders/mesh_instancing/main.go @@ -0,0 +1,251 @@ +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 4c8e19e..8c13f79 100644 --- a/examples/shaders/model_shader/main.go +++ b/examples/shaders/model_shader/main.go @@ -3,64 +3,62 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) + rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader") + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(3.0, 3.0, 3.0) - camera.Target = raylib.NewVector3(0.0, 1.5, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(3.0, 3.0, 3.0) + camera.Target = rl.NewVector3(0.0, 1.5, 0.0) + camera.Up = rl.NewVector3(0.0, 1.0, 0.0) camera.Fovy = 45.0 - dwarf := raylib.LoadModel("dwarf.obj") // Load OBJ model - texture := raylib.LoadTexture("dwarf_diffuse.png") // Load model texture - shader := raylib.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs") // Load model shader + dwarf := rl.LoadModel("dwarf.obj") // Load OBJ model + texture := rl.LoadTexture("dwarf_diffuse.png") // Load model texture + shader := rl.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs") // Load model shader - dwarf.Material.Shader = shader // Set shader effect to 3d model - dwarf.Material.Maps[raylib.MapDiffuse].Texture = texture // Set dwarf model diffuse texture + rl.SetMaterialTexture(dwarf.Materials, rl.MapDiffuse, texture) + dwarf.Materials.Shader = shader // Set shader effect to 3d model - position := raylib.NewVector3(0.0, 0.0, 0.0) // Set model position + position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position - raylib.SetCameraMode(camera, raylib.CameraFree) // Set free camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera + rl.BeginDrawing() - raylib.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.ClearBackground(raylib.RayWhite) + rl.BeginMode3D(camera) - raylib.BeginMode3D(camera) + rl.DrawModel(dwarf, position, 2.0, rl.White) // Draw 3d model with texture - raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture + rl.DrawGrid(10, 1.0) // Draw a grid - raylib.DrawGrid(10, 1.0) // Draw a grid + rl.EndMode3D() - raylib.EndMode3D() + rl.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, rl.Gray) - raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.Gray) + rl.DrawText(fmt.Sprintf("Camera position: (%.2f, %.2f, %.2f)", camera.Position.X, camera.Position.Y, camera.Position.Z), 600, 20, 10, rl.Black) + rl.DrawText(fmt.Sprintf("Camera target: (%.2f, %.2f, %.2f)", camera.Target.X, camera.Target.Y, camera.Target.Z), 600, 40, 10, rl.Gray) - raylib.DrawText(fmt.Sprintf("Camera position: (%.2f, %.2f, %.2f)", camera.Position.X, camera.Position.Y, camera.Position.Z), 600, 20, 10, raylib.Black) - raylib.DrawText(fmt.Sprintf("Camera target: (%.2f, %.2f, %.2f)", camera.Target.X, camera.Target.Y, camera.Target.Z), 600, 40, 10, raylib.Gray) + rl.DrawFPS(10, 10) - raylib.DrawFPS(10, 10) - - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadShader(shader) // Unload shader - raylib.UnloadTexture(texture) // Unload texture - raylib.UnloadModel(dwarf) // Unload model + rl.UnloadShader(shader) // Unload shader + rl.UnloadTexture(texture) // Unload texture + rl.UnloadModel(dwarf) // Unload model - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shaders/multi_sample2d/color_mix.fs b/examples/shaders/multi_sample2d/color_mix.fs new file mode 100644 index 0000000..e794d32 --- /dev/null +++ b/examples/shaders/multi_sample2d/color_mix.fs @@ -0,0 +1,27 @@ +#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 new file mode 100644 index 0000000..b85f5ff --- /dev/null +++ b/examples/shaders/multi_sample2d/main.go @@ -0,0 +1,69 @@ +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 new file mode 100644 index 0000000..0448073 --- /dev/null +++ b/examples/shaders/pbr/glsl330/pbr.fs @@ -0,0 +1,296 @@ +#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 new file mode 100644 index 0000000..53b0d0f --- /dev/null +++ b/examples/shaders/pbr/glsl330/pbr.vs @@ -0,0 +1,50 @@ +#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 new file mode 100644 index 0000000..d99c9e0 --- /dev/null +++ b/examples/shaders/pbr/light.go @@ -0,0 +1,213 @@ +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 new file mode 100644 index 0000000..28dba9f --- /dev/null +++ b/examples/shaders/pbr/main.go @@ -0,0 +1,83 @@ +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 new file mode 100644 index 0000000..d8b3c83 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_d.png differ diff --git a/examples/shaders/pbr/models/old_car_e.png b/examples/shaders/pbr/models/old_car_e.png new file mode 100644 index 0000000..23f01c0 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_e.png differ diff --git a/examples/shaders/pbr/models/old_car_mra.png b/examples/shaders/pbr/models/old_car_mra.png new file mode 100644 index 0000000..0fb46b3 Binary files /dev/null and b/examples/shaders/pbr/models/old_car_mra.png differ diff --git a/examples/shaders/pbr/models/old_car_n.png b/examples/shaders/pbr/models/old_car_n.png new file mode 100644 index 0000000..11f689f Binary files /dev/null and b/examples/shaders/pbr/models/old_car_n.png differ diff --git a/examples/shaders/pbr/models/old_car_new.glb b/examples/shaders/pbr/models/old_car_new.glb new file mode 100644 index 0000000..119995c Binary files /dev/null and b/examples/shaders/pbr/models/old_car_new.glb differ diff --git a/examples/shaders/pbr/models/plane.glb b/examples/shaders/pbr/models/plane.glb new file mode 100644 index 0000000..452e1c5 Binary files /dev/null and b/examples/shaders/pbr/models/plane.glb differ diff --git a/examples/shaders/pbr/models/road_a.png b/examples/shaders/pbr/models/road_a.png new file mode 100644 index 0000000..1037773 Binary files /dev/null and b/examples/shaders/pbr/models/road_a.png differ diff --git a/examples/shaders/pbr/models/road_mra.png b/examples/shaders/pbr/models/road_mra.png new file mode 100644 index 0000000..988c839 Binary files /dev/null and b/examples/shaders/pbr/models/road_mra.png differ diff --git a/examples/shaders/pbr/models/road_n.png b/examples/shaders/pbr/models/road_n.png new file mode 100644 index 0000000..a5f3548 Binary files /dev/null and b/examples/shaders/pbr/models/road_n.png differ diff --git a/examples/shaders/pbr/pbr.go b/examples/shaders/pbr/pbr.go new file mode 100644 index 0000000..b43ed5a --- /dev/null +++ b/examples/shaders/pbr/pbr.go @@ -0,0 +1,218 @@ +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/church.obj b/examples/shaders/postprocessing/church.obj new file mode 100644 index 0000000..109bb00 --- /dev/null +++ b/examples/shaders/postprocessing/church.obj @@ -0,0 +1,5116 @@ +# (c) 2018 Medieval Assets Pack by Alberto Cano +# Licensed as Creative Commons Attribution-NonCommercial 4.0 + +# +# object church +# + +v 4.672987 1.366374 3.687210 +v 4.749157 3.915673 3.641246 +v 4.749157 3.915673 3.108021 +v 4.672987 1.366374 2.958931 +v 4.671515 6.920380 3.688683 +v 4.756666 9.021092 3.633739 +v 4.756666 9.021092 3.115528 +v 4.671515 6.920380 2.957458 +v 5.401266 1.366374 3.687210 +v 5.282382 3.915673 3.641246 +v 5.402740 6.920380 3.688683 +v 5.274876 9.021092 3.633739 +v 5.401266 1.366374 2.958931 +v 5.282382 3.915673 3.108021 +v 5.402740 6.920380 2.957458 +v 5.274876 9.021092 3.115528 +v 4.770980 11.140738 3.629622 +v 4.770384 11.093080 2.940483 +v 5.461159 11.111799 3.631026 +v 5.460562 11.064143 2.941886 +v 4.896648 12.594810 3.494706 +v 4.896199 12.558983 2.976627 +v 5.415511 12.573055 3.495761 +v 5.415061 12.537227 2.977682 +v 4.900036 14.058286 3.421423 +v 4.899451 14.011499 2.744879 +v 5.577600 14.029880 3.422802 +v 5.577015 13.983093 2.746257 +v 2.816255 3.971905 3.105294 +v 2.816255 3.971905 3.638519 +v 2.892425 1.422606 3.684482 +v 2.892425 1.422606 2.956204 +v 2.622373 9.077326 3.099698 +v 2.622373 9.077326 3.617908 +v 2.893899 6.976612 3.685956 +v 2.893899 6.976612 2.954731 +v 2.283030 3.971905 3.638519 +v 2.164147 1.422606 3.684483 +v 2.104162 9.077326 3.617908 +v 2.162674 6.976612 3.685956 +v 2.283030 3.971905 3.105293 +v 2.164147 1.422606 2.956204 +v 2.104162 9.077326 3.099698 +v 2.162674 6.976612 2.954730 +v 2.795031 11.149311 2.937756 +v 2.794435 11.196969 3.626895 +v 2.104256 11.168032 3.628299 +v 2.104853 11.120375 2.939159 +v 2.669216 12.615214 2.973899 +v 2.668766 12.651041 3.491978 +v 2.149904 12.629287 3.493033 +v 2.150354 12.593460 2.974954 +v 2.665964 14.067732 2.742152 +v 2.665379 14.114518 3.418696 +v 1.987815 14.086112 3.420074 +v 1.988400 14.039326 2.743530 +v -8.203741 1.267261 4.004546 +v -8.203739 4.908214 4.004546 +v -8.203739 4.908214 0.802546 +v -8.203741 1.267261 0.802546 +v -3.030087 1.267261 7.206547 +v -3.030086 4.908213 7.206547 +v -8.203740 4.908214 7.206547 +v -8.203741 1.267261 7.206547 +v 2.143568 1.259508 0.802546 +v 2.143569 4.895408 0.802546 +v 7.977185 4.887452 0.802547 +v 7.977185 1.239670 0.802547 +v 7.977185 1.239670 7.206548 +v 7.977185 4.887452 7.206548 +v 2.143569 4.908213 7.206547 +v 2.143568 1.267260 7.206547 +v -3.030086 4.895409 0.802546 +v -3.030086 1.259509 0.802546 +v -8.203739 10.730635 4.004546 +v -8.203739 5.665551 0.802546 +v -3.030086 5.665551 7.206547 +v -8.203740 5.665551 7.206547 +v 2.143569 5.665550 0.802546 +v 7.977185 5.644517 0.802547 +v 7.977186 5.654397 7.206548 +v 2.143569 5.665550 7.206547 +v -3.030086 5.665551 0.802546 +v 7.977187 10.730632 4.004547 +v 7.977186 5.718971 4.004547 +v 7.977186 4.866691 4.004547 +v 7.977186 1.212080 4.004547 +v -3.030086 5.359768 -2.546745 +v -0.443258 8.104138 -2.546745 +v -0.443259 1.251756 -2.546746 +v -3.030086 1.259509 -2.546746 +v 2.143569 5.359767 -2.546745 +v 2.143569 1.259508 -2.546746 +v -8.714131 5.502876 0.667329 +v -8.925464 11.117952 4.004546 +v -8.925464 11.472882 4.004546 +v -8.713030 5.806002 0.574254 +v -8.714132 5.502876 7.341763 +v -8.713031 5.806002 7.434839 +v -3.030086 5.435468 7.397793 +v -3.030086 5.738945 7.490578 +v 2.142987 5.435467 7.397793 +v 2.143709 5.738945 7.490578 +v 8.617522 5.747605 7.341550 +v 8.617887 6.050475 7.434840 +v 8.829270 11.117949 4.004547 +v 8.829270 11.472879 4.004460 +v 8.617038 5.479570 0.667705 +v 8.618862 5.782260 0.574270 +v 2.142472 5.435469 0.611300 +v 2.143834 5.738945 0.518517 +v -3.030086 5.435468 0.611301 +v -3.030086 5.738945 0.518516 +v -3.030086 9.579156 4.004547 +v 2.143569 9.579155 4.004547 +v -0.443258 8.104138 -3.207969 +v -0.443258 7.168501 0.117055 +v -3.213754 4.686915 0.117055 +v -3.779471 4.686916 -3.207970 +v 2.892955 4.686915 -3.207969 +v 2.327237 4.686915 0.117055 +v -3.213754 5.170498 0.117055 +v -0.443258 7.700984 0.117055 +v -0.443258 8.636621 -3.207969 +v -3.779471 5.170498 -3.207970 +v 2.327237 5.170497 0.117055 +v 2.892955 5.170497 -3.207969 +v 2.520533 5.170497 2.329992 +v 2.520532 4.686915 2.329992 +v -3.407049 5.170498 2.329992 +v -0.443258 8.653279 3.336201 +v -3.407049 4.686916 2.329992 +v -3.224798 1.267537 -2.724316 +v -3.084860 3.428520 -2.599412 +v -2.647470 3.428521 -2.599412 +v -2.623512 1.267537 -2.724316 +v -3.157254 5.298322 -2.724316 +v -2.623511 6.106331 -2.724316 +v -2.647470 3.428521 -2.162023 +v -2.623512 1.267537 -2.123031 +v -2.623511 6.106331 -2.123031 +v -3.084860 3.428520 -2.162023 +v -3.224798 1.267537 -2.123032 +v -3.157254 5.298322 -2.123032 +v 5.234885 8.894447 3.493170 +v 2.152004 8.894447 3.493169 +v 2.152004 7.017791 3.493169 +v 5.234885 7.017790 3.493170 +v 5.234885 8.894447 0.286462 +v 5.234885 7.017790 0.286462 +v 2.152004 8.894447 0.286462 +v 2.152004 7.017791 0.286462 +v 5.952550 15.008949 3.864073 +v 5.919468 14.222457 3.918490 +v 5.915528 13.907810 -0.631487 +v 5.948610 14.694304 -0.685903 +v 1.914264 14.863439 -0.694107 +v 1.881181 14.076944 -0.639690 +v 1.885121 14.391590 3.910287 +v 1.918204 15.178086 3.855870 +v 5.474879 14.982239 3.187648 +v 5.472109 14.761015 -0.011418 +v 2.391937 14.890150 -0.017681 +v 2.394707 15.111373 3.181385 +v 2.217420 10.741338 0.269374 +v 5.297592 10.612206 0.275636 +v 2.333891 13.665580 3.281420 +v 5.414063 13.536447 3.287683 +v 5.411294 13.315219 0.088616 +v 2.331121 13.444352 0.082352 +v 5.486740 10.843854 3.738632 +v 5.515079 11.517557 3.692019 +v 2.062607 11.662299 3.684999 +v 2.034268 10.988593 3.731612 +v 1.965690 7.017790 3.757348 +v 1.965690 6.341883 3.757348 +v 5.421199 6.341884 3.757348 +v 5.421199 7.017790 3.757348 +v 5.511854 11.259878 -0.034147 +v 5.483515 10.586176 0.012467 +v 5.421198 6.341883 0.022284 +v 5.421199 7.017789 0.022284 +v 2.059381 11.404618 -0.041167 +v 2.031041 10.730916 0.005447 +v 1.965690 6.341884 0.022284 +v 1.965690 7.017791 0.022284 +v 5.328701 11.507136 3.428090 +v 2.248529 11.636267 3.421828 +v 5.325932 11.285909 0.229024 +v 2.245759 11.415044 0.222760 +v 5.234885 1.267260 3.493170 +v 5.234885 1.267260 0.286462 +v 5.234884 6.341884 0.286462 +v 5.234885 6.341884 3.493170 +v 2.152003 1.267260 0.286462 +v 2.152003 1.267260 3.493169 +v 2.152004 6.341884 3.493169 +v 2.152004 6.341884 0.286462 +v 5.300362 10.833432 3.474704 +v 2.220190 10.962566 3.468441 +v 5.488289 18.351477 3.106055 +v 5.432454 17.024092 3.197897 +v 4.727269 17.622326 3.157138 +v 4.759225 18.382044 3.104573 +v 2.572030 18.473740 3.100126 +v 2.516194 17.146355 3.191967 +v 2.536664 17.653803 2.280275 +v 2.568621 18.413523 2.227710 +v 5.484882 18.291260 2.233640 +v 5.452925 17.531544 2.286205 +v 2.558395 18.232864 -0.389533 +v 2.502560 16.905474 -0.297690 +v 3.255504 17.442579 -0.335485 +v 3.287461 18.202299 -0.388049 +v 2.540192 17.758495 1.396451 +v 2.529847 17.533363 0.535445 +v 2.561804 18.293085 0.482883 +v 2.565212 18.353300 1.355296 +v 5.478065 18.170820 0.488811 +v 5.446108 17.411100 0.541375 +v 5.456454 17.636234 1.402380 +v 5.481473 18.231041 1.361226 +v 4.005140 17.817806 3.144246 +v 3.269139 17.683460 3.154172 +v 3.301096 18.443176 3.101608 +v 4.030159 18.412611 3.103090 +v 3.991506 17.576929 -0.345412 +v 4.713634 17.381447 -0.332521 +v 4.745591 18.141167 -0.385084 +v 4.016526 18.171734 -0.386568 +v 5.474657 18.110600 -0.383604 +v 5.418821 16.783216 -0.291762 +v 3.997826 16.598362 1.977675 +v 3.994203 16.949141 1.871554 +v 3.789942 16.880709 1.870981 +v 3.665688 16.619816 1.866170 +v 4.328650 16.625895 1.863629 +v 4.199675 16.884468 1.869411 +v 3.991053 17.170544 1.579510 +v 3.660552 17.059816 1.578584 +v 3.459630 16.623966 1.570518 +v 4.532324 16.633802 1.566407 +v 4.323511 17.065897 1.576043 +v 3.989580 17.178001 1.213095 +v 3.659078 17.067278 1.212169 +v 3.458157 16.631430 1.204104 +v 4.530852 16.641268 1.199993 +v 4.322040 17.073357 1.209629 +v 3.990347 16.968672 0.912267 +v 3.786086 16.900236 0.911694 +v 3.661832 16.639343 0.906882 +v 4.324994 16.623236 0.903889 +v 4.195817 16.903996 0.910123 +v 3.993060 16.622505 0.791931 +v 3.671349 15.997251 1.853473 +v 4.003486 15.975796 1.964978 +v 4.334309 16.003332 1.850932 +v 3.465291 16.001406 1.557822 +v 4.537985 16.011242 1.553711 +v 3.463817 16.008863 1.191407 +v 4.536512 16.018700 1.187296 +v 3.667492 16.016775 0.894185 +v 4.330656 16.000673 0.891191 +v 3.998720 15.999939 0.779234 +v 3.580832 15.762773 1.983916 +v 4.006256 15.741533 2.126885 +v 4.430108 15.770563 1.980661 +v 3.316867 15.768097 1.605178 +v 4.691021 15.780697 1.599911 +v 3.314979 15.777655 1.135790 +v 4.689136 15.790258 1.130522 +v 3.575893 15.787792 0.755039 +v 4.425369 15.773392 0.751331 +v 4.000150 15.772456 0.607910 +v 4.167738 17.082762 1.436337 +v 4.095740 17.077181 1.311860 +v 4.061117 17.358999 1.372744 +v 4.086811 17.360991 1.417166 +v 3.951960 17.083208 1.311568 +v 4.009803 17.361153 1.372640 +v 3.880177 17.094818 1.435752 +v 3.984187 17.365295 1.416957 +v 3.952176 17.100401 1.560228 +v 4.009881 17.367289 1.461380 +v 4.095956 17.094372 1.560521 +v 4.061193 17.365131 1.461485 +v 4.558943 27.996582 0.730314 +v 4.537374 27.918690 0.756207 +v 4.568421 27.933918 0.755143 +v 4.573010 27.905622 0.715098 +v 4.537475 27.912605 0.718652 +v 1.614795 18.854746 4.138235 +v 1.414524 18.344713 4.508417 +v 6.716858 18.122417 4.519198 +v 6.561485 18.647366 4.148293 +v 6.711414 17.687864 -1.764677 +v 6.556619 18.258890 -1.469291 +v 1.409083 17.910166 -1.775456 +v 1.609931 18.466276 -1.479349 +v 6.093621 18.893530 3.795330 +v 2.103048 19.060829 3.787216 +v 2.098763 18.718649 -1.160881 +v 6.089338 18.551348 -1.152767 +v -8.713030 1.267262 7.639588 +v -3.030087 1.267261 7.639588 +v -3.407052 1.267261 -0.038095 +v -8.713031 1.267262 -0.038094 +v 2.520563 1.267260 -0.038094 +v 2.520563 1.267260 7.639587 +v 8.698908 1.267259 7.639589 +v 8.698908 1.267259 -0.038093 +v -9.071366 -0.000000 -0.523111 +v -9.071365 -0.000000 8.126415 +v -3.030088 -0.000001 8.126415 +v 2.520563 -0.000001 8.126415 +v 9.071366 -0.000002 8.126415 +v 9.071366 -0.000002 -0.523110 +v 2.520565 -0.000001 -0.523111 +v -3.407052 -0.000001 -0.523112 +v 2.520564 1.267260 -2.724314 +v -3.407051 1.267261 -2.724315 +v 2.520564 -0.000001 -2.724314 +v -3.407050 -0.000001 -2.724315 +v 1.736992 0.241523 -6.928524 +v 1.736992 -0.033319 -6.928524 +v -2.623513 -0.033318 -6.928524 +v -2.623513 0.241524 -6.928524 +v -2.623513 0.241524 -6.420866 +v 1.736992 0.241523 -6.420866 +v 1.736992 0.504688 -6.420866 +v -2.623513 0.504689 -6.420866 +v -2.623513 0.505858 -5.913212 +v 1.736992 0.504688 -5.913212 +v 1.736992 0.767854 -5.913212 +v -2.623513 0.769023 -5.913212 +v -2.623513 0.769023 -5.405557 +v 1.736992 0.769022 -5.405555 +v 1.736992 1.032188 -5.405555 +v -2.623513 1.032188 -5.405557 +v -2.623513 1.032188 -4.897901 +v 1.736992 1.032188 -4.897901 +v 1.736992 1.267537 -4.897901 +v -2.623513 1.267537 -4.897901 +v -2.623513 1.267537 -4.390244 +v 1.736992 1.267537 -4.390244 +v -2.623513 1.267537 -2.724316 +v 1.736991 1.267537 -2.724316 +v -3.407050 1.735000 -4.234435 +v -2.623512 1.734999 -4.234435 +v -2.623512 0.994722 -5.744554 +v -3.407050 0.994722 -5.744554 +v -3.407050 -0.000001 -4.234435 +v -3.407050 -0.000001 -5.744554 +v -3.407050 -0.000001 -2.724316 +v -2.623512 -0.000001 -2.724315 +v -2.623512 1.734999 -2.724315 +v -3.407050 1.734999 -2.724316 +v -2.623512 -0.000001 -5.744554 +v -2.623512 -0.000001 -4.234435 +v -2.623512 -0.000001 -8.126418 +v -3.407050 -0.000001 -8.126418 +v -3.407050 0.632338 -8.126418 +v -2.623512 0.632338 -8.126418 +v -2.623512 0.632338 -7.254672 +v -3.407050 0.632338 -7.254672 +v -3.407050 -0.000001 -7.254672 +v -2.623512 -0.000001 -7.254672 +v -3.407050 1.109609 -7.254672 +v -2.623512 1.109609 -7.254672 +v -2.623512 1.109609 -8.126418 +v -3.407050 1.109609 -8.126418 +v 1.736992 0.994721 -5.744554 +v 1.736992 1.734999 -4.234435 +v 2.520530 1.734999 -4.234435 +v 2.520530 0.994721 -5.744554 +v 2.520530 -0.000001 -4.234435 +v 2.520530 -0.000001 -5.744554 +v 2.520530 -0.000001 -2.724315 +v 2.520530 1.734999 -2.724315 +v 1.736992 1.734999 -2.724315 +v 1.736992 -0.000001 -2.724315 +v 1.736992 -0.000001 -5.744554 +v 1.736992 -0.000001 -4.234435 +v 1.736992 -0.000001 -8.126418 +v 1.736992 0.632338 -8.126418 +v 2.520530 0.632338 -8.126418 +v 2.520530 -0.000001 -8.126418 +v 2.520530 0.632338 -7.254672 +v 1.736992 0.632338 -7.254672 +v 2.520530 -0.000001 -7.254672 +v 1.736992 -0.000001 -7.254672 +v 2.520530 1.109609 -7.254672 +v 2.520530 1.109609 -8.126418 +v 1.736992 1.109609 -8.126418 +v 1.736992 1.109609 -7.254672 +v -1.410326 3.088244 -2.720418 +v -1.410326 3.088244 -2.538141 +v -1.140453 3.592780 -2.538141 +v -1.140452 3.592780 -2.720418 +v -1.221802 3.088244 -2.619900 +v -1.221802 3.088244 -2.720418 +v -1.004539 3.477115 -2.720418 +v -1.004539 3.477115 -2.619900 +v -0.443259 4.069920 -2.538140 +v -0.443259 4.069920 -2.720418 +v -0.443259 3.875959 -2.720418 +v -0.443259 3.875959 -2.619900 +v 0.253934 3.592780 -2.538140 +v 0.253934 3.592780 -2.720418 +v 0.118021 3.477115 -2.720418 +v 0.118021 3.477115 -2.619900 +v 0.523807 3.088244 -2.538140 +v 0.523807 3.088244 -2.720418 +v 0.335284 3.088244 -2.720418 +v 0.335284 3.088244 -2.619900 +v -1.410326 1.267537 -2.720418 +v -1.410326 1.267537 -2.538140 +v -1.221803 1.267537 -2.619900 +v -1.221803 1.267537 -2.720418 +v 0.523807 1.267537 -2.538140 +v 0.523807 1.267537 -2.720418 +v 0.335284 1.267537 -2.720418 +v 0.335284 1.267537 -2.619900 +v -5.806923 3.909048 0.771220 +v -5.485344 4.409725 0.771220 +v -5.485344 2.303240 0.771220 +v -5.806923 2.344218 0.771220 +v -6.058448 2.381772 0.790385 +v -6.058448 2.381772 0.716560 +v -6.058448 2.156472 0.716560 +v -6.058448 2.156473 0.790385 +v -5.485344 4.779102 0.790385 +v -5.485344 4.779102 0.716560 +v -5.975380 4.050927 0.716560 +v -5.975380 4.050927 0.790385 +v -4.912240 2.156472 0.790385 +v -4.912240 2.156472 0.716560 +v -4.912240 2.381772 0.716560 +v -4.912240 2.381772 0.790385 +v -5.485344 2.077940 0.790385 +v -5.485344 2.077940 0.716562 +v -4.995306 2.156472 0.716560 +v -4.995306 2.156472 0.790385 +v -5.975381 2.156472 0.635584 +v -5.975381 2.381772 0.635584 +v -5.806923 2.344218 0.635584 +v -5.485344 4.409725 0.716562 +v -5.806923 3.909048 0.716560 +v -4.995306 2.381772 0.635584 +v -4.995306 2.156472 0.635584 +v -5.163763 2.358823 0.635584 +v -5.485344 2.077940 0.635584 +v -5.485344 2.303240 0.635584 +v -5.163763 3.909048 0.771220 +v -5.163763 2.358823 0.771220 +v -4.995306 4.050928 0.790385 +v -4.995306 4.050928 0.716560 +v -5.975381 2.156473 0.790385 +v -5.975381 2.156472 0.716560 +v -5.163763 3.909048 0.716560 +v -5.806923 2.344218 0.716560 +v -5.163763 2.358823 0.716560 +v -5.485344 2.303239 0.716560 +v -4.995306 2.381772 0.716560 +v -4.995306 2.381772 0.790385 +v -5.975381 2.381772 0.716560 +v -5.975381 2.381772 0.790385 +v -6.058448 2.381772 0.635584 +v -6.058448 2.156472 0.635584 +v -4.912240 2.156472 0.635584 +v -4.912240 2.381772 0.635584 +v 6.141209 3.909047 0.771221 +v 6.462788 4.409724 0.771221 +v 6.462787 2.303238 0.771221 +v 6.141208 2.344216 0.771221 +v 5.889685 2.381771 0.790385 +v 5.889685 2.381771 0.716561 +v 5.889685 2.156471 0.716561 +v 5.889685 2.156471 0.790385 +v 6.462788 4.779100 0.790385 +v 6.462788 4.779100 0.716561 +v 5.972752 4.050926 0.716561 +v 5.972752 4.050926 0.790386 +v 7.035892 2.156471 0.790385 +v 7.035892 2.156471 0.716561 +v 7.035892 2.381771 0.716561 +v 7.035892 2.381771 0.790385 +v 6.462787 2.077938 0.790386 +v 6.462787 2.077938 0.716562 +v 6.952826 2.156471 0.716561 +v 6.952826 2.156471 0.790385 +v 5.972751 2.156471 0.635585 +v 5.972751 2.381771 0.635585 +v 6.141208 2.344216 0.635585 +v 6.462788 4.409724 0.716562 +v 6.141209 3.909047 0.716561 +v 6.952826 2.381771 0.635585 +v 6.952826 2.156471 0.635585 +v 6.784369 2.358821 0.635585 +v 6.462787 2.077938 0.635585 +v 6.462787 2.303238 0.635585 +v 6.784369 3.909047 0.771221 +v 6.784369 2.358821 0.771221 +v 6.952826 4.050926 0.790386 +v 6.952826 4.050926 0.716561 +v 5.972751 2.156471 0.790385 +v 5.972751 2.156471 0.716561 +v 6.784369 3.909047 0.716561 +v 6.141208 2.344216 0.716561 +v 6.784369 2.358821 0.716561 +v 6.462787 2.303238 0.716561 +v 6.952826 2.381771 0.716561 +v 6.952826 2.381771 0.790385 +v 5.972751 2.381771 0.716561 +v 5.972751 2.381771 0.790385 +v 5.889685 2.381771 0.635585 +v 5.889685 2.156471 0.635585 +v 7.035892 2.156471 0.635585 +v 7.035892 2.381771 0.635585 +v -8.175412 8.783850 4.004546 +v -8.306676 8.783850 4.004546 +v -8.306676 8.517238 4.737058 +v -8.175412 8.517238 4.737058 +v -8.230400 8.702679 4.004546 +v -8.230400 7.644264 4.004546 +v -8.230400 8.455057 4.684882 +v -8.306676 7.842151 5.126819 +v -8.175412 7.842151 5.126819 +v -8.230400 7.828055 5.046881 +v -8.306676 7.074471 4.991457 +v -8.175412 7.074471 4.991457 +v -8.230400 7.115057 4.921160 +v -8.306676 6.573403 4.394308 +v -8.175412 6.573403 4.394308 +v -8.230400 6.649680 4.366545 +v -8.306675 6.573403 3.614785 +v -8.175411 6.573404 3.614785 +v -8.230399 6.649680 3.642547 +v -8.306675 7.074471 3.017636 +v -8.175411 7.074471 3.017636 +v -8.230399 7.115057 3.087933 +v -8.306675 7.842151 2.882273 +v -8.175411 7.842151 2.882274 +v -8.230399 7.828057 2.962212 +v -8.306676 8.517239 3.272035 +v -8.175412 8.517239 3.272035 +v -8.230400 8.455057 3.324211 +v -8.306676 8.702679 4.004546 +v -8.306676 8.455057 4.684882 +v -8.306676 8.455057 3.324211 +v -8.306675 7.828057 2.962212 +v -8.306675 7.115057 3.087933 +v -8.306675 6.649680 3.642547 +v -8.306676 6.649680 4.366545 +v -8.306676 7.115057 4.921160 +v -8.306676 7.828055 5.046881 +v 0.032073 2.303239 7.208142 +v 0.032074 4.409725 7.208142 +v -0.289506 3.909048 7.208142 +v -0.289506 2.344217 7.208142 +v -0.541030 2.156472 7.262802 +v -0.541030 2.381772 7.262802 +v -0.541030 2.381772 7.188977 +v -0.541030 2.156472 7.188977 +v -0.457963 4.050927 7.262802 +v 0.032074 4.779101 7.262802 +v 0.032074 4.779101 7.188977 +v -0.457963 4.050927 7.188977 +v 0.605178 2.381771 7.262802 +v 0.605178 2.156471 7.262802 +v 0.605178 2.156472 7.188977 +v 0.605178 2.381771 7.188977 +v 0.522112 2.156471 7.262802 +v 0.032073 2.077939 7.262800 +v 0.032073 2.077939 7.188977 +v 0.522112 2.156472 7.188977 +v -0.457963 2.156472 7.343778 +v -0.289506 2.344217 7.343778 +v -0.457963 2.381772 7.343778 +v -0.289506 3.909048 7.262802 +v 0.032074 4.409725 7.262800 +v 0.522112 2.381771 7.343778 +v 0.353654 2.358822 7.343778 +v 0.522112 2.156471 7.343778 +v 0.032073 2.303239 7.343778 +v 0.032073 2.077939 7.343778 +v 0.353654 2.358822 7.208142 +v 0.353655 3.909048 7.208142 +v 0.522112 4.050927 7.262802 +v 0.522112 4.050927 7.188977 +v -0.457963 2.156472 7.262802 +v -0.457963 2.156472 7.188977 +v 0.353655 3.909048 7.262802 +v -0.289506 2.344217 7.262802 +v 0.353654 2.358822 7.262802 +v 0.032073 2.303238 7.262802 +v 0.522112 2.381771 7.262802 +v 0.522112 2.381771 7.188977 +v -0.457963 2.381772 7.262802 +v -0.457963 2.381772 7.188977 +v -0.541030 2.156472 7.343778 +v -0.541030 2.381772 7.343778 +v 0.605178 2.381771 7.343778 +v 0.605178 2.156471 7.343778 +v -5.485344 2.303240 7.221334 +v -5.485344 4.409725 7.221334 +v -5.806924 3.909048 7.221334 +v -5.806924 2.344218 7.221334 +v -6.058448 2.156472 7.275995 +v -6.058448 2.381772 7.275995 +v -6.058448 2.381772 7.202170 +v -6.058448 2.156473 7.202170 +v -5.975380 4.050927 7.275995 +v -5.485344 4.779102 7.275995 +v -5.485344 4.779102 7.202170 +v -5.975380 4.050927 7.202169 +v -4.912241 2.381772 7.275996 +v -4.912241 2.156472 7.275996 +v -4.912241 2.156472 7.202171 +v -4.912241 2.381772 7.202171 +v -4.995306 2.156472 7.275996 +v -5.485344 2.077940 7.275994 +v -5.485344 2.077940 7.202169 +v -4.995306 2.156472 7.202171 +v -5.975381 2.156472 7.356970 +v -5.806924 2.344218 7.356970 +v -5.975381 2.381772 7.356970 +v -5.806924 3.909048 7.275995 +v -5.485344 4.409725 7.275994 +v -4.995306 2.381772 7.356971 +v -5.163763 2.358823 7.356971 +v -4.995306 2.156472 7.356971 +v -5.485344 2.303240 7.356970 +v -5.485344 2.077940 7.356970 +v -5.163763 2.358823 7.221335 +v -5.163763 3.909048 7.221335 +v -4.995306 4.050928 7.275996 +v -4.995306 4.050928 7.202170 +v -5.975381 2.156472 7.275995 +v -5.975381 2.156473 7.202170 +v -5.163763 3.909048 7.275996 +v -5.806924 2.344218 7.275995 +v -5.163763 2.358823 7.275996 +v -5.485344 2.303239 7.275995 +v -4.995306 2.381772 7.275996 +v -4.995306 2.381772 7.202171 +v -5.975381 2.381772 7.275995 +v -5.975381 2.381772 7.202170 +v -6.058448 2.156472 7.356970 +v -6.058448 2.381772 7.356970 +v -4.912241 2.381772 7.356971 +v -4.912241 2.156472 7.356971 +v 6.462788 2.303238 7.217344 +v 6.462788 4.409724 7.217344 +v 6.141209 3.909047 7.217344 +v 6.141208 2.344216 7.217344 +v 5.889684 2.156471 7.272005 +v 5.889684 2.381771 7.272005 +v 5.889684 2.381771 7.198180 +v 5.889684 2.156471 7.198180 +v 5.972752 4.050926 7.272005 +v 6.462788 4.779101 7.272005 +v 6.462788 4.779101 7.198180 +v 5.972752 4.050926 7.198179 +v 7.035892 2.381771 7.272005 +v 7.035892 2.156471 7.272005 +v 7.035892 2.156471 7.198180 +v 7.035892 2.381771 7.198180 +v 6.952826 2.156471 7.272005 +v 6.462788 2.077938 7.272003 +v 6.462788 2.077938 7.198179 +v 6.952826 2.156471 7.198180 +v 5.972751 2.156471 7.352980 +v 6.141208 2.344216 7.352980 +v 5.972751 2.381771 7.352980 +v 6.141209 3.909047 7.272005 +v 6.462788 4.409724 7.272003 +v 6.952826 2.381771 7.352980 +v 6.784369 2.358821 7.352980 +v 6.952826 2.156471 7.352980 +v 6.462788 2.303238 7.352980 +v 6.462788 2.077938 7.352980 +v 6.784369 2.358821 7.217344 +v 6.784369 3.909047 7.217344 +v 6.952826 4.050926 7.272005 +v 6.952826 4.050926 7.198179 +v 5.972751 2.156471 7.272005 +v 5.972751 2.156471 7.198180 +v 6.784369 3.909047 7.272005 +v 6.141208 2.344216 7.272005 +v 6.784369 2.358821 7.272005 +v 6.462788 2.303238 7.272005 +v 6.952826 2.381771 7.272005 +v 6.952826 2.381771 7.198180 +v 5.972751 2.381771 7.272005 +v 5.972751 2.381771 7.198180 +v 5.889684 2.156471 7.352980 +v 5.889684 2.381771 7.352980 +v 7.035892 2.381771 7.352980 +v 7.035892 2.156471 7.352980 +v 7.989504 2.303238 4.004544 +v 7.989505 4.409724 4.004544 +v 7.989505 3.909046 4.326124 +v 7.989504 2.344216 4.326124 +v 8.044166 2.156471 4.577648 +v 8.044166 2.381770 4.577648 +v 7.970341 2.381771 4.577648 +v 7.970341 2.156471 4.577648 +v 8.044167 4.050926 4.494581 +v 8.044167 4.779100 4.004544 +v 7.970342 4.779100 4.004544 +v 7.970340 4.050926 4.494581 +v 8.044166 2.381770 3.431440 +v 8.044166 2.156471 3.431440 +v 7.970341 2.156471 3.431440 +v 7.970341 2.381771 3.431440 +v 8.044166 2.156471 3.514506 +v 8.044165 2.077938 4.004544 +v 7.970340 2.077938 4.004544 +v 7.970341 2.156471 3.514506 +v 8.125142 2.156471 4.494581 +v 8.125142 2.344216 4.326124 +v 8.125142 2.381770 4.494581 +v 8.044167 3.909046 4.326124 +v 8.044165 4.409724 4.004544 +v 8.125142 2.381770 3.514506 +v 8.125142 2.358821 3.682963 +v 8.125142 2.156471 3.514506 +v 8.125142 2.303238 4.004544 +v 8.125142 2.077938 4.004544 +v 7.989504 2.358821 3.682963 +v 7.989505 3.909046 3.682963 +v 8.044167 4.050926 3.514506 +v 7.970340 4.050926 3.514506 +v 8.044166 2.156471 4.494581 +v 7.970341 2.156471 4.494581 +v 8.044167 3.909046 3.682963 +v 8.044166 2.344216 4.326124 +v 8.044166 2.358821 3.682963 +v 8.044166 2.303237 4.004544 +v 8.044166 2.381770 3.514506 +v 7.970341 2.381771 3.514506 +v 8.044166 2.381770 4.494581 +v 7.970341 2.381771 4.494581 +v 8.125142 2.156471 4.577648 +v 8.125142 2.381770 4.577648 +v 8.125142 2.381770 3.431440 +v 8.125142 2.156471 3.431440 +v 4.175653 23.253054 1.207701 +v 4.483004 23.283512 1.216166 +v 4.533489 23.226915 0.793925 +v 4.182594 23.240883 0.830203 +v 4.671747 1.267260 0.817280 +v 4.747917 3.816559 0.771316 +v 4.747917 3.816559 0.238091 +v 4.671747 1.267260 0.089002 +v 4.670274 6.821266 0.818753 +v 4.755424 8.921979 0.763809 +v 4.755424 8.921979 0.245598 +v 4.670274 6.821266 0.087529 +v 5.400025 1.267260 0.817280 +v 5.281142 3.816559 0.771317 +v 5.401499 6.821266 0.818754 +v 5.273635 8.921979 0.763809 +v 5.400025 1.267260 0.089002 +v 5.281142 3.816559 0.238091 +v 5.401499 6.821266 0.087528 +v 5.273635 8.921979 0.245599 +v 4.769739 11.041625 0.759693 +v 4.769143 10.993966 0.070554 +v 5.459918 11.012686 0.761097 +v 5.459321 10.965030 0.071956 +v 4.895408 12.495696 0.624777 +v 4.894958 12.459869 0.106697 +v 5.414269 12.473943 0.625831 +v 5.413820 12.438114 0.107753 +v 4.898796 13.959171 0.551494 +v 4.898210 13.912385 -0.125050 +v 5.576359 13.930765 0.552872 +v 5.575775 13.883979 -0.123673 +v 2.338280 1.267536 -2.724316 +v 1.736995 1.267536 -2.724316 +v 1.760954 3.428520 -2.599412 +v 2.198343 3.428520 -2.599412 +v 1.736995 6.106330 -2.724316 +v 2.270738 5.298322 -2.724316 +v 1.736994 1.267536 -2.123031 +v 1.760954 3.428520 -2.162023 +v 1.736995 6.106330 -2.123031 +v 2.338280 1.267536 -2.123031 +v 2.198343 3.428520 -2.162023 +v 2.270738 5.298322 -2.123031 +v 2.815015 3.872790 0.235364 +v 2.815015 3.872790 0.768590 +v 2.891185 1.323491 0.814553 +v 2.891185 1.323491 0.086274 +v 2.633949 8.978212 0.242871 +v 2.633949 8.978212 0.761081 +v 2.892659 6.877498 0.816026 +v 2.892659 6.877498 0.084801 +v 2.281790 3.872790 0.768590 +v 2.162907 1.323491 0.814553 +v 2.115738 8.978212 0.761081 +v 2.161434 6.877498 0.816027 +v 2.281790 3.872790 0.235364 +v 2.162907 1.323491 0.086275 +v 2.115738 8.978212 0.242871 +v 2.161434 6.877498 0.084801 +v 2.793791 11.050198 0.067826 +v 2.793195 11.097857 0.756965 +v 2.103016 11.068916 0.758370 +v 2.103613 11.021260 0.069229 +v 2.667976 12.516101 0.103970 +v 2.667526 12.551928 0.622049 +v 2.148664 12.530173 0.623104 +v 2.149114 12.494345 0.105025 +v 2.664724 13.968618 -0.127777 +v 2.664139 14.015405 0.548767 +v 1.986575 13.986998 0.550145 +v 1.987160 13.940212 -0.126399 +v -0.927404 6.114937 -2.576771 +v -0.443259 6.846743 -2.576771 +v -0.443259 4.995204 -2.576771 +v -0.927404 4.995204 -2.576771 +v -1.026729 4.941527 -2.511324 +v -1.026729 6.124244 -2.511324 +v -1.026729 6.124244 -2.623685 +v -1.026729 4.941527 -2.623685 +v -0.443259 7.006183 -2.511324 +v -0.443259 7.006183 -2.623685 +v 0.140211 6.124244 -2.511324 +v 0.140211 4.941527 -2.511324 +v 0.140211 4.941527 -2.623685 +v 0.140211 6.124244 -2.623685 +v -0.443259 4.941527 -2.511324 +v -0.443259 4.941527 -2.623685 +v 0.040887 6.114937 -2.576771 +v 0.040887 4.995204 -2.576771 +v -0.927404 6.114937 -2.623685 +v -0.927404 4.995204 -2.623685 +v -0.443259 6.846743 -2.623685 +v 0.040887 6.114937 -2.623685 +v 0.040887 4.995204 -2.623685 +v -0.443259 4.995204 -2.623685 +v -7.676232 1.226863 0.579004 +v -7.820205 3.717741 0.740305 +v -7.820205 3.717741 1.244465 +v -7.676232 1.226863 1.272082 +v -7.676232 5.872984 0.656859 +v -7.676232 6.804344 1.272082 +v -8.324365 3.717741 1.244465 +v -8.369309 1.226863 1.272081 +v -8.369308 6.804344 1.272081 +v -8.324365 3.717741 0.740305 +v -8.369309 1.226863 0.579004 +v -8.369308 5.872984 0.656858 +v -8.369309 1.226863 7.430092 +v -8.225338 3.717741 7.268791 +v -8.225337 3.717741 6.764630 +v -8.369309 1.226863 6.737015 +v -8.369309 5.872984 7.352238 +v -8.369309 6.804344 6.737015 +v -7.721177 3.717741 6.764631 +v -7.676233 1.226863 6.737015 +v -7.676232 6.804344 6.737015 +v -7.721177 3.717741 7.268792 +v -7.676233 1.226863 7.430092 +v -7.676232 5.872984 7.352238 +v 0.125889 8.220344 -3.247035 +v 0.125889 8.388115 -3.195977 +v 0.125889 8.091660 -2.222249 +v 0.125889 7.923891 -2.273325 +v -0.342264 8.269616 -2.168066 +v -0.342264 8.437381 -2.116987 +v -0.342264 8.733835 -3.090707 +v -0.342264 8.566062 -3.141786 +v -0.443258 8.448682 -2.113552 +v -0.443258 8.280909 -2.164633 +v -0.443257 8.745133 -3.087272 +v -0.443257 8.577360 -3.138354 +v -1.012404 8.220344 -3.247035 +v -1.012405 7.923891 -2.273325 +v -1.012405 8.091661 -2.222249 +v -1.012404 8.388114 -3.195960 +v -0.544251 8.437383 -2.116987 +v -0.544251 8.733835 -3.090707 +v -0.544251 8.566062 -3.141786 +v -0.544251 8.269616 -2.168066 +v 0.125888 7.964036 2.305606 +v 0.125889 8.134858 2.265937 +v 0.125889 8.364986 3.257439 +v 0.125889 8.194155 3.297090 +v -0.342264 8.546191 3.215383 +v -0.342264 8.717019 3.175738 +v -0.342264 8.486897 2.184243 +v -0.342264 8.316061 2.223894 +v -0.443258 8.728525 3.173060 +v -0.443258 8.557688 3.212710 +v -0.443258 8.498399 2.181570 +v -0.443258 8.327562 2.221221 +v -1.012405 7.964036 2.305606 +v -1.012405 8.194155 3.297090 +v -1.012405 8.364986 3.257439 +v -1.012405 8.134868 2.265952 +v -0.544251 8.546191 3.215383 +v -0.544251 8.717019 3.175738 +v -0.544252 8.486897 2.184243 +v -0.544252 8.316061 2.223894 +v 0.125888 7.729860 1.719361 +v 0.125888 7.900682 1.679691 +v 0.125889 8.130809 2.671193 +v 0.125889 7.959977 2.710845 +v -0.342264 8.252721 1.597998 +v -0.342264 8.482843 2.589495 +v -0.342264 8.081886 1.637649 +v -0.443258 8.264222 1.595326 +v -0.443258 8.494348 2.586816 +v -0.443258 8.093387 1.634976 +v -1.012405 7.729860 1.719361 +v -1.012405 7.959979 2.710845 +v -1.012405 8.130811 2.671193 +v -1.012405 7.900692 1.679708 +v -0.544251 8.482843 2.589495 +v -0.544252 8.252721 1.597998 +v -0.544252 8.081886 1.637649 +v 0.125888 7.490499 0.975419 +v 0.125888 7.661322 0.935747 +v 0.125889 7.891449 1.927253 +v 0.125889 7.720617 1.966902 +v -0.342264 8.013359 0.854055 +v -0.342265 8.243484 1.845551 +v -0.342264 7.842525 0.893705 +v -0.443258 8.024862 0.851382 +v -0.443258 8.254988 1.842874 +v -0.443258 7.854025 0.891033 +v -1.012405 7.490499 0.975419 +v -1.012405 7.720617 1.966902 +v -1.012405 7.891449 1.927253 +v -1.012405 7.661330 0.935764 +v -0.544251 8.243484 1.845551 +v -0.544252 8.013359 0.854055 +v -0.544252 7.842525 0.893705 +v 0.125888 7.219489 0.257531 +v 0.125888 7.390311 0.217859 +v 0.125889 7.620439 1.209362 +v 0.125889 7.449607 1.249013 +v -0.342264 7.742350 0.136167 +v -0.342265 7.972472 1.127663 +v -0.342264 7.571515 0.175817 +v -0.443258 7.753851 0.133495 +v -0.443258 7.983978 1.124985 +v -0.443258 7.583015 0.173146 +v -1.012405 7.219489 0.257531 +v -1.012405 7.449607 1.249013 +v -1.012405 7.620439 1.209362 +v -1.012405 7.390321 0.217876 +v -0.544251 7.972472 1.127663 +v -0.544252 7.742350 0.136167 +v -0.544252 7.571515 0.175817 +v 0.125888 7.426631 -0.952069 +v 0.125889 7.598213 -0.915829 +v 0.125889 7.387752 0.080035 +v 0.125889 7.216172 0.043773 +v -0.342265 7.569754 0.118501 +v -0.342265 7.741333 0.154765 +v -0.342264 7.951793 -0.841090 +v -0.443258 7.752889 0.157200 +v -0.443258 7.581305 0.120936 +v -0.443258 7.963347 -0.838653 +v -1.012405 7.426631 -0.952069 +v -1.012405 7.216172 0.043773 +v -1.012405 7.387752 0.080035 +v -1.012405 7.598215 -0.915812 +v -0.544252 7.569755 0.118501 +v -0.544252 7.741333 0.154765 +v -0.544252 7.951794 -0.841090 +v 0.125888 7.548561 -1.378403 +v 0.125889 7.720144 -1.342160 +v 0.125889 7.509683 -0.346299 +v 0.125889 7.338101 -0.382559 +v -0.342265 7.691683 -0.307832 +v -0.342264 7.863263 -0.271568 +v -0.342264 8.073722 -1.267423 +v -0.443258 7.874820 -0.269133 +v -0.443258 7.703234 -0.305397 +v -0.443258 8.085277 -1.264985 +v -1.012405 7.548561 -1.378403 +v -1.012405 7.338101 -0.382559 +v -1.012405 7.509683 -0.346299 +v -1.012405 7.720146 -1.342143 +v -0.544251 7.691683 -0.307832 +v -0.544251 7.863263 -0.271568 +v -0.544252 8.073724 -1.267423 +v 0.125888 7.832724 -2.270370 +v 0.125889 8.004307 -2.234131 +v 0.125889 7.793845 -1.238266 +v 0.125889 7.622263 -1.274529 +v -0.342264 7.975846 -1.199801 +v -0.342264 8.147426 -1.163537 +v -0.342264 8.357885 -2.159392 +v -0.443258 8.158981 -1.161102 +v -0.443258 7.987396 -1.197366 +v -0.443257 8.369440 -2.156955 +v -1.012405 7.832724 -2.270370 +v -1.012405 7.622263 -1.274529 +v -1.012405 7.793846 -1.238266 +v -1.012404 8.004307 -2.234112 +v -0.544251 7.975846 -1.199801 +v -0.544251 8.147426 -1.163537 +v -0.544251 8.357885 -2.159392 +v -8.912474 11.031324 3.435404 +v -8.846989 11.194007 3.435404 +v -7.902801 10.813814 3.435403 +v -7.968303 10.651135 3.435403 +v -7.833316 10.986370 3.903557 +v -7.767808 11.149046 3.903557 +v -8.711987 11.529237 3.903556 +v -8.777492 11.366553 3.903556 +v -7.763401 11.160003 4.004550 +v -7.828911 10.997322 4.004550 +v -8.707580 11.540192 4.004550 +v -8.773089 11.377510 4.004550 +v -8.912474 11.031324 4.573697 +v -7.968303 10.651135 4.573697 +v -7.902801 10.813814 4.573697 +v -8.846970 11.194004 4.573697 +v -7.833316 10.986370 4.105544 +v -7.767808 11.149046 4.105544 +v -8.711987 11.529237 4.105544 +v -8.777492 11.366553 4.105544 +v -4.525187 9.604162 3.435403 +v -5.521032 9.814617 3.435403 +v -5.484768 9.986203 3.435403 +v -4.488920 9.775745 3.435403 +v -5.410044 10.339779 3.903555 +v -4.414185 10.129323 3.903555 +v -4.450459 9.957743 3.903555 +v -4.411753 10.140882 4.004549 +v -5.407596 10.351342 4.004549 +v -4.448018 9.969293 4.004549 +v -4.525187 9.604162 4.573696 +v -4.488922 9.775754 4.573696 +v -5.484768 9.986203 4.573695 +v -5.521032 9.814617 4.573695 +v -4.414185 10.129323 4.105543 +v -5.410044 10.339779 4.105543 +v -4.450459 9.957743 4.105543 +v -3.725210 9.404657 3.435403 +v -4.727868 9.579854 3.435403 +v -4.697678 9.752620 3.435403 +v -3.695029 9.577415 3.435403 +v -4.635478 10.108606 3.903555 +v -3.632823 9.933414 3.903555 +v -3.663011 9.760663 3.903555 +v -3.630792 9.945055 4.004549 +v -4.633441 10.120243 4.004549 +v -3.660975 9.772294 4.004549 +v -3.725210 9.404657 4.573696 +v -3.695029 9.577424 4.573696 +v -4.697678 9.752620 4.573696 +v -4.727868 9.579854 4.573696 +v -3.632823 9.933414 4.105543 +v -4.635478 10.108606 4.105543 +v -3.663011 9.760663 4.105543 +v -2.825487 9.253774 3.435403 +v -3.835884 9.376645 3.435403 +v -3.814717 9.550737 3.435403 +v -2.804317 9.427873 3.435403 +v -3.771090 9.909484 3.903555 +v -2.760688 9.786617 3.903555 +v -2.781863 9.612530 3.903555 +v -2.759268 9.798346 4.004549 +v -3.769664 9.921204 4.004549 +v -2.780437 9.624252 4.004549 +v -2.825487 9.253774 4.573696 +v -2.804320 9.427876 4.573696 +v -3.814718 9.550737 4.573696 +v -3.835882 9.376645 4.573696 +v -2.760688 9.786617 4.105543 +v -3.771090 9.909484 4.105543 +v -2.781864 9.612530 4.105543 +v -1.916558 9.099153 3.435403 +v -2.926955 9.222018 3.435403 +v -2.905781 9.396115 3.435403 +v -1.895385 9.273246 3.435403 +v -2.862163 9.754860 3.903555 +v -1.851764 9.631997 3.903556 +v -1.872930 9.457903 3.903556 +v -1.850336 9.643720 4.004549 +v -2.860733 9.766582 4.004549 +v -1.871507 9.469625 4.004549 +v -1.916558 9.099153 4.573696 +v -1.895386 9.273250 4.573696 +v -2.905782 9.396115 4.573696 +v -2.926952 9.222018 4.573696 +v -1.851764 9.631997 4.105543 +v -2.862163 9.754860 4.105543 +v -1.872930 9.457903 4.105543 +v -0.916265 9.037489 3.435403 +v -1.933530 9.071821 3.435403 +v -1.927615 9.247103 3.435403 +v -0.910350 9.212770 3.435403 +v -1.915416 9.608285 3.903556 +v -0.898164 9.573951 3.903556 +v -0.904077 9.398677 3.903556 +v -0.897761 9.585756 4.004549 +v -1.915027 9.620090 4.004549 +v -0.903672 9.410481 4.004550 +v -0.916265 9.037489 4.573696 +v -0.910350 9.212770 4.573696 +v -1.927615 9.247103 4.573696 +v -1.933530 9.071821 4.573696 +v -0.898164 9.573951 4.105543 +v -1.915416 9.608285 4.105543 +v -0.904077 9.398677 4.105543 +v 0.098525 9.003066 3.435403 +v -0.917858 9.057508 3.435403 +v -0.908479 9.232633 3.435403 +v 0.107901 9.178195 3.435403 +v -0.889152 9.593499 3.903556 +v 0.127235 9.539063 3.903556 +v 0.117852 9.363945 3.903556 +v 0.127864 9.550862 4.004550 +v -0.888523 9.605289 4.004550 +v 0.118487 9.375740 4.004550 +v 0.098525 9.003066 4.573697 +v 0.107898 9.178195 4.573697 +v -0.908477 9.232633 4.573697 +v -0.917858 9.057508 4.573697 +v 0.127235 9.539063 4.105543 +v -0.889152 9.593499 4.105544 +v 0.117852 9.363945 4.105543 +v -7.140497 10.367755 3.435403 +v -8.136342 10.578209 3.435403 +v -8.100086 10.749797 3.435403 +v -7.104231 10.539337 3.435402 +v -8.025360 11.103369 3.903555 +v -7.029497 10.892917 3.903555 +v -7.065768 10.721334 3.903555 +v -7.027062 10.904475 4.004548 +v -8.022904 11.114935 4.004548 +v -7.063326 10.732885 4.004549 +v -7.140497 10.367755 4.573695 +v -7.104231 10.539345 4.573695 +v -8.100086 10.749797 4.573695 +v -8.136342 10.578209 4.573695 +v -7.029497 10.892917 4.105542 +v -8.025360 11.103369 4.105542 +v -7.065768 10.721334 4.105542 +v -6.225498 10.090338 3.435403 +v -7.221344 10.300794 3.435403 +v -7.185081 10.472381 3.435403 +v -6.189229 10.261920 3.435403 +v -7.110355 10.825954 3.903555 +v -6.114499 10.615499 3.903555 +v -6.150771 10.443917 3.903555 +v -6.112064 10.627060 4.004549 +v -7.107907 10.837520 4.004548 +v -6.148331 10.455468 4.004549 +v -6.225498 10.090338 4.573695 +v -6.189230 10.261928 4.573695 +v -7.185081 10.472381 4.573695 +v -7.221344 10.300794 4.573695 +v -6.114499 10.615499 4.105542 +v -7.110355 10.825954 4.105542 +v -6.150771 10.443917 4.105542 +v -5.302460 9.829968 3.435403 +v -6.298305 10.040421 3.435403 +v -6.262042 10.212009 3.435403 +v -5.266192 10.001551 3.435403 +v -6.187316 10.565583 3.903555 +v -5.191457 10.355129 3.903555 +v -5.227733 10.183548 3.903555 +v -5.189027 10.366690 4.004549 +v -6.184870 10.577147 4.004548 +v -5.225292 10.195098 4.004549 +v -5.302460 9.829968 4.573696 +v -5.266193 10.001559 4.573696 +v -6.262042 10.212009 4.573695 +v -6.298305 10.040421 4.573695 +v -5.191457 10.355129 4.105543 +v -6.187316 10.565583 4.105542 +v -5.227733 10.183548 4.105543 +v 8.751835 11.073284 3.435406 +v 7.807665 10.693095 3.435405 +v 7.742163 10.855774 3.435405 +v 8.686349 11.235967 3.435405 +v 7.672678 11.028330 3.903558 +v 7.607171 11.191006 3.903558 +v 8.551349 11.571197 3.903558 +v 8.616853 11.408513 3.903558 +v 7.668272 11.039282 4.004552 +v 7.602763 11.201962 4.004552 +v 8.546941 11.582151 4.004552 +v 8.612451 11.419469 4.004552 +v 8.751835 11.073284 4.573699 +v 8.686330 11.235964 4.573699 +v 7.742163 10.855774 4.573699 +v 7.807665 10.693095 4.573699 +v 7.607171 11.191006 4.105546 +v 7.672678 11.028330 4.105546 +v 8.551349 11.571197 4.105546 +v 8.616853 11.408513 4.105546 +v 4.364550 9.646123 3.435404 +v 4.328283 9.817705 3.435404 +v 5.324131 10.028165 3.435404 +v 5.360395 9.856579 3.435404 +v 5.249407 10.381739 3.903557 +v 4.253548 10.171285 3.903557 +v 4.289822 9.999702 3.903557 +v 4.251115 10.182843 4.004550 +v 5.246959 10.393303 4.004550 +v 4.287380 10.011253 4.004550 +v 4.364550 9.646123 4.573697 +v 5.360395 9.856579 4.573697 +v 5.324131 10.028165 4.573697 +v 4.328284 9.817715 4.573697 +v 5.249407 10.381739 4.105544 +v 4.253548 10.171285 4.105544 +v 4.289822 9.999702 4.105544 +v 3.564572 9.446617 3.435404 +v 3.534391 9.619375 3.435404 +v 4.537041 9.794579 3.435404 +v 4.567231 9.621816 3.435404 +v 4.474841 10.150567 3.903557 +v 3.472185 9.975375 3.903557 +v 3.502373 9.802625 3.903557 +v 3.470154 9.987017 4.004550 +v 4.472804 10.162204 4.004550 +v 3.500337 9.814256 4.004550 +v 3.564572 9.446617 4.573697 +v 4.567231 9.621816 4.573697 +v 4.537041 9.794579 4.573697 +v 3.534391 9.619385 4.573697 +v 4.474841 10.150567 4.105544 +v 3.472185 9.975375 4.105544 +v 3.502373 9.802625 4.105544 +v 2.664850 9.295735 3.435404 +v 2.643680 9.469832 3.435404 +v 3.654080 9.592699 3.435404 +v 3.675246 9.418605 3.435404 +v 3.610452 9.951445 3.903557 +v 2.600050 9.828578 3.903557 +v 2.621226 9.654490 3.903557 +v 2.598630 9.840306 4.004550 +v 3.609026 9.963165 4.004550 +v 2.619799 9.666214 4.004550 +v 2.664849 9.295735 4.573697 +v 3.675245 9.418605 4.573697 +v 3.654080 9.592699 4.573697 +v 2.643682 9.469836 4.573697 +v 3.610452 9.951445 4.105544 +v 2.600050 9.828578 4.105544 +v 2.621225 9.654490 4.105544 +v 1.755920 9.141115 3.435405 +v 1.734747 9.315207 3.435405 +v 2.745144 9.438076 3.435405 +v 2.766317 9.263979 3.435405 +v 2.701525 9.796821 3.903557 +v 1.691126 9.673960 3.903557 +v 1.712292 9.499866 3.903557 +v 1.689698 9.685682 4.004550 +v 2.700094 9.808544 4.004550 +v 1.710869 9.511588 4.004550 +v 1.755920 9.141115 4.573697 +v 2.766314 9.263979 4.573697 +v 2.745143 9.438076 4.573697 +v 1.734749 9.315212 4.573697 +v 2.701525 9.796821 4.105544 +v 1.691126 9.673960 4.105544 +v 1.712292 9.499866 4.105544 +v 0.755627 9.079452 3.435405 +v 0.749712 9.254731 3.435405 +v 1.766977 9.289065 3.435405 +v 1.772892 9.113784 3.435405 +v 1.754778 9.650248 3.903557 +v 0.737526 9.615912 3.903557 +v 0.743439 9.440639 3.903557 +v 0.737123 9.627718 4.004551 +v 1.754389 9.662052 4.004550 +v 0.743034 9.452444 4.004551 +v 0.755627 9.079452 4.573698 +v 1.772892 9.113784 4.573697 +v 1.766977 9.289065 4.573697 +v 0.749712 9.254731 4.573698 +v 1.754778 9.650248 4.105544 +v 0.737526 9.615912 4.105544 +v 0.743439 9.440639 4.105544 +v -0.259163 9.045029 3.435405 +v -0.268539 9.220156 3.435405 +v 0.747841 9.274595 3.435405 +v 0.757220 9.099471 3.435405 +v 0.728514 9.635462 3.903558 +v -0.287873 9.581025 3.903558 +v -0.278490 9.405908 3.903558 +v -0.288501 9.592824 4.004551 +v 0.727885 9.647251 4.004551 +v -0.279125 9.417702 4.004551 +v -0.259163 9.045029 4.573698 +v 0.757220 9.099471 4.573698 +v 0.747839 9.274595 4.573698 +v -0.268536 9.220156 4.573698 +v 0.728514 9.635462 4.105545 +v -0.287873 9.581025 4.105545 +v -0.278490 9.405908 4.105545 +v 6.979859 10.409715 3.435404 +v 6.943593 10.581297 3.435404 +v 7.939448 10.791757 3.435404 +v 7.975703 10.620169 3.435404 +v 7.864722 11.145329 3.903557 +v 6.868859 10.934876 3.903557 +v 6.905130 10.763294 3.903557 +v 6.866425 10.946435 4.004550 +v 7.862266 11.156895 4.004550 +v 6.902688 10.774845 4.004550 +v 6.979859 10.409715 4.573698 +v 7.975703 10.620169 4.573698 +v 7.939448 10.791757 4.573698 +v 6.943593 10.581305 4.573698 +v 7.864722 11.145329 4.105545 +v 6.868859 10.934876 4.105545 +v 6.905130 10.763294 4.105545 +v 6.064860 10.132298 3.435404 +v 6.028591 10.303881 3.435404 +v 7.024443 10.514339 3.435404 +v 7.060706 10.342753 3.435404 +v 6.949717 10.867913 3.903557 +v 5.953861 10.657460 3.903557 +v 5.990133 10.485878 3.903557 +v 5.951426 10.669021 4.004550 +v 6.947268 10.879478 4.004550 +v 5.987692 10.497428 4.004550 +v 6.064860 10.132298 4.573698 +v 7.060706 10.342753 4.573698 +v 7.024443 10.514339 4.573698 +v 6.028593 10.303889 4.573698 +v 6.949717 10.867913 4.105545 +v 5.953861 10.657460 4.105545 +v 5.990133 10.485878 4.105545 +v 5.141823 9.871928 3.435404 +v 5.105555 10.043512 3.435404 +v 6.101403 10.253970 3.435404 +v 6.137667 10.082383 3.435404 +v 6.026678 10.607544 3.903557 +v 5.030820 10.397090 3.903557 +v 5.067095 10.225510 3.903557 +v 5.028390 10.408650 4.004550 +v 6.024232 10.619107 4.004550 +v 5.064654 10.237059 4.004550 +v 5.141823 9.871928 4.573697 +v 6.137667 10.082383 4.573698 +v 6.101403 10.253970 4.573698 +v 5.105556 10.043520 4.573697 +v 6.026678 10.607544 4.105545 +v 5.030820 10.397090 4.105544 +v 5.067095 10.225510 4.105544 +v 2.417334 14.879411 -0.157506 +v 1.994648 16.926769 -0.298724 +v 1.909423 14.900703 -0.158539 +v 2.416871 14.842373 -0.693086 +v 2.502082 16.867332 -0.849278 +v 1.908945 14.862559 -0.710127 +v 1.994170 16.888626 -0.850310 +v 2.431423 15.156576 3.856914 +v 2.516649 17.182642 3.716730 +v 2.008737 17.203936 3.715697 +v 1.923512 15.177868 3.855881 +v 2.430969 15.120289 3.332151 +v 1.923057 15.141580 3.331118 +v 2.008282 17.167650 3.190934 +v 5.957858 15.008731 3.864084 +v 6.043084 17.034801 3.723900 +v 5.432909 17.060381 3.722659 +v 5.347682 15.034313 3.862843 +v 5.957404 14.972442 3.339320 +v 6.042629 16.998512 3.199137 +v 5.347229 14.998023 3.338081 +v 5.943770 14.731565 -0.150338 +v 6.028995 16.757635 -0.290521 +v 5.333596 14.757145 -0.151578 +v 5.943306 14.694530 -0.685914 +v 6.028533 16.720596 -0.826100 +v 5.333131 14.720112 -0.687156 +v 5.418357 16.746176 -0.827341 +v 2.050006 18.216015 -0.942151 +v 2.557918 18.194719 -0.941118 +v 2.050484 18.254158 -0.390564 +v 2.572484 18.510031 3.624888 +v 2.064573 18.531321 3.623855 +v 2.064118 18.495035 3.099093 +v 6.098918 18.362185 3.632058 +v 5.488744 18.387768 3.630818 +v 6.098464 18.325901 3.107296 +v 6.084368 18.047983 -0.917941 +v 6.084832 18.085020 -0.382363 +v 5.474193 18.073565 -0.919182 +v 3.269593 17.719748 3.678935 +v 3.301549 18.479464 3.626372 +v 2.060710 18.434816 2.226678 +v 2.028753 17.675097 2.279243 +v 6.088240 18.145241 0.490052 +v 6.056282 17.385523 0.542615 +v 4.713170 17.344410 -0.868099 +v 4.745127 18.104128 -0.920664 +v 2.053892 18.314373 0.481849 +v 2.021935 17.554659 0.534413 +v 2.032281 17.779789 1.395418 +v 2.057301 18.374592 1.354263 +v 6.095054 18.265676 2.234881 +v 6.063099 17.505959 2.287445 +v 6.066626 17.610653 1.403620 +v 6.091649 18.205460 1.362466 +v 4.005594 17.854092 3.669007 +v 4.727724 17.658613 3.681900 +v 4.759680 18.418335 3.629336 +v 4.030614 18.448900 3.627853 +v 3.991043 17.539890 -0.880991 +v 3.255026 17.404434 -0.887071 +v 3.286984 18.164152 -0.939638 +v 4.016048 18.133589 -0.938154 +v 8.254710 1.226861 0.591258 +v 8.110739 3.717739 0.752560 +v 8.110739 3.717739 1.256720 +v 8.254710 1.226861 1.284336 +v 8.254711 5.872983 0.669113 +v 8.254711 6.804342 1.284336 +v 7.606578 3.717739 1.256720 +v 7.561633 1.226862 1.284336 +v 7.561633 6.804342 1.284336 +v 7.606578 3.717739 0.752560 +v 7.561633 1.226862 0.591258 +v 7.561633 5.872983 0.669112 +v 7.472826 1.226862 7.432425 +v 7.616798 3.717739 7.271124 +v 7.616798 3.717739 6.766964 +v 7.472826 1.226862 6.739347 +v 7.472826 5.872983 7.354571 +v 7.472826 6.804342 6.739347 +v 8.120959 3.717739 6.766964 +v 8.165903 1.226861 6.739347 +v 8.165903 6.804342 6.739347 +v 8.120958 3.717739 7.271124 +v 8.165903 1.226861 7.432425 +v 8.165903 5.872983 7.354571 +# 1444 vertices + +vn -0.999554 0.029865 -0.000000 +vn -0.999998 0.002037 -0.000000 +vn -0.999998 0.002089 -0.000000 +vn -0.999974 0.007228 -0.000000 +vn -0.999718 0.023752 0.000114 +vn -0.999722 0.023555 0.000115 +vn -0.999975 0.007064 -0.000000 +vn -0.000000 0.018027 0.999837 +vn -0.000000 0.001155 0.999999 +vn -0.000000 0.001142 0.999999 +vn -0.000000 0.018027 0.999838 +vn -0.000000 0.005038 0.999987 +vn -0.000566 0.013807 0.999904 +vn -0.000553 0.014094 0.999900 +vn -0.000000 0.005081 0.999987 +vn 0.998914 0.046583 -0.000000 +vn 0.999994 0.003393 -0.000000 +vn 0.999994 0.003313 -0.000000 +vn 0.999950 0.009961 -0.000000 +vn 0.999892 -0.014626 0.001529 +vn 0.999904 -0.013758 0.001511 +vn 0.999948 0.010210 -0.000000 +vn 0.000000 0.058383 -0.998294 +vn 0.000000 0.004243 -0.999991 +vn 0.000000 0.004284 -0.999991 +vn -0.000000 0.012221 -0.999925 +vn -0.000427 -0.003510 -0.999994 +vn -0.000437 -0.005415 -0.999985 +vn -0.000000 0.012093 -0.999927 +vn -0.998903 0.046770 -0.002455 +vn -0.998976 0.045185 -0.002349 +vn 0.000347 0.046611 0.998913 +vn 0.000356 0.046871 0.998901 +vn 0.999523 -0.030871 0.000094 +vn 0.999595 -0.028451 -0.000027 +vn 0.001092 -0.030196 -0.999543 +vn 0.001081 -0.030485 -0.999535 +vn -0.999025 0.044088 -0.002184 +vn -0.999025 0.044085 -0.002184 +vn 0.000955 0.071164 0.997464 +vn 0.000955 0.071165 0.997464 +vn 0.999211 -0.039658 0.001877 +vn 0.999212 -0.039653 0.001877 +vn -0.000770 -0.066737 -0.997770 +vn -0.000770 -0.066739 -0.997770 +vn -0.999997 0.002351 0.000703 +vn 0.000066 0.050011 0.998749 +vn 0.993882 -0.110243 0.006764 +vn -0.004598 -0.157544 -0.987501 +vn 0.999998 0.002089 0.000000 +vn 0.999998 0.002037 0.000000 +vn 0.999554 0.029865 0.000000 +vn 0.999734 0.023007 0.001877 +vn 0.999705 0.024236 0.001855 +vn 0.998703 0.050923 0.000000 +vn 0.998706 0.050864 0.000000 +vn 0.000000 0.001142 0.999999 +vn 0.000000 0.001155 0.999999 +vn 0.000000 0.018027 0.999837 +vn 0.000628 0.014125 0.999900 +vn 0.000643 0.013698 0.999906 +vn 0.000000 0.008820 0.999961 +vn 0.000000 0.007470 0.999972 +vn -0.999994 0.003313 -0.000001 +vn -0.999994 0.003394 -0.000001 +vn -0.998914 0.046583 -0.000001 +vn -0.999902 -0.013957 -0.000249 +vn -0.999905 -0.013796 -0.000251 +vn -0.999423 -0.033972 -0.000000 +vn -0.999423 -0.033966 -0.000000 +vn -0.000000 0.004284 -0.999991 +vn -0.000000 0.004243 -0.999991 +vn -0.000000 0.058383 -0.998294 +vn 0.000361 -0.005318 -0.999986 +vn 0.000353 -0.003672 -0.999993 +vn 0.000000 0.007374 -0.999973 +vn 0.000000 0.010706 -0.999943 +vn 1.000000 -0.000423 -0.000549 +vn 0.999994 0.003281 -0.000743 +vn -0.000326 0.045127 0.998981 +vn -0.000227 0.042047 0.999115 +vn -0.999873 0.015817 -0.001775 +vn -0.999884 0.015136 -0.001720 +vn -0.001102 -0.028818 -0.999584 +vn -0.001224 -0.025521 -0.999673 +vn 0.999025 0.044085 -0.002184 +vn 0.999025 0.044088 -0.002184 +vn -0.000955 0.071165 0.997464 +vn -0.000955 0.071164 0.997464 +vn -0.999212 -0.039653 0.001876 +vn -0.999211 -0.039658 0.001877 +vn 0.000770 -0.066739 -0.997770 +vn 0.000770 -0.066737 -0.997770 +vn 0.999997 0.002350 0.000704 +vn -0.000066 0.050011 0.998749 +vn -0.993882 -0.110243 0.006763 +vn 0.004598 -0.157544 -0.987501 +vn -1.000000 0.000000 -0.000000 +vn -0.000000 0.000000 1.000000 +vn 0.000000 0.000000 -1.000000 +vn 1.000000 -0.000000 -0.000000 +vn 1.000000 -0.000000 0.000000 +vn 1.000000 0.000000 -0.000000 +vn -0.000000 0.000000 -1.000000 +vn -0.998585 -0.005804 -0.052854 +vn -0.998585 -0.005804 0.052854 +vn -0.012865 -0.292908 0.956054 +vn -0.000000 -0.292378 0.956303 +vn 0.022394 -0.293337 0.955747 +vn 0.998709 -0.007669 0.050213 +vn 0.998867 -0.009404 -0.046641 +vn 0.010261 -0.293697 -0.955844 +vn 0.000000 -0.292377 -0.956303 +vn -0.012865 -0.292906 -0.956055 +vn -0.185816 -0.515752 0.836345 +vn -0.185816 -0.515752 -0.836345 +vn -0.185816 -0.515751 -0.836345 +vn 0.241136 -0.518426 -0.820419 +vn 0.153141 -0.516646 0.842392 +vn 0.095537 0.586991 -0.803937 +vn 0.051136 0.628276 -0.776308 +vn 0.047656 0.631386 -0.774003 +vn 0.095537 0.586991 -0.803936 +vn -0.044076 0.628164 -0.776832 +vn -0.041412 0.630921 -0.774741 +vn -0.082915 0.586497 -0.805696 +vn -0.082915 0.586497 -0.805697 +vn -0.096650 0.596920 0.796458 +vn 0.095537 0.586991 0.803936 +vn 0.000000 0.672137 0.740426 +vn -0.000000 -0.976053 -0.217533 +vn 0.686000 -0.710178 -0.158277 +vn -0.686000 -0.710177 -0.158277 +vn -0.705809 0.708353 0.008360 +vn 0.000000 0.999973 0.007343 +vn 0.000000 0.975770 0.218799 +vn -0.691847 0.704549 0.157982 +vn 0.705809 0.708353 0.008360 +vn 0.691847 0.704549 0.157983 +vn -0.999172 -0.000000 0.040688 +vn -0.985833 -0.000000 0.167729 +vn 0.999172 -0.000000 0.040688 +vn 0.996207 -0.000000 -0.087016 +vn -0.703444 0.695396 -0.146941 +vn 0.000000 0.978396 -0.206740 +vn 0.703444 0.695396 -0.146941 +vn -0.996207 -0.000000 -0.087016 +vn -0.996207 -0.000000 -0.087017 +vn 0.985833 -0.000000 0.167729 +vn 0.000000 0.057703 -0.998334 +vn 0.022455 0.002147 -0.999745 +vn 0.022621 0.001736 -0.999743 +vn 0.045190 -0.054313 -0.997501 +vn 0.999938 0.011086 0.000000 +vn 0.999999 0.001104 0.000000 +vn 0.999999 0.001081 0.000000 +vn 0.999939 0.011086 0.000000 +vn 0.999960 -0.008947 0.000000 +vn -0.000000 0.018041 0.999837 +vn 0.007066 0.000536 0.999975 +vn 0.007014 0.000664 0.999975 +vn 0.014139 -0.016993 0.999756 +vn -0.997910 0.064621 -0.000000 +vn -0.999916 0.012938 -0.000000 +vn -0.999917 0.012841 -0.000000 +vn -0.999251 -0.038689 -0.000000 +vn -0.000399 0.005460 0.999985 +vn -0.000391 0.005345 0.999986 +vn 0.999846 -0.017551 0.000390 +vn 0.999847 -0.017463 0.000388 +vn -0.999856 0.016986 -0.000371 +vn -0.999854 0.017101 -0.000374 +vn -1.000000 0.000000 0.000000 +vn 0.999120 -0.041885 0.002031 +vn -0.999120 0.041887 -0.002031 +vn 0.041928 0.996738 -0.068963 +vn 0.000431 -0.003976 -0.999992 +vn 0.000421 -0.003886 -0.999992 +vn 0.000851 -0.007861 -0.999969 +vn 0.000864 0.068989 0.997617 +vn -0.000864 -0.068988 -0.997617 +vn 0.041927 0.996738 -0.068964 +vn 0.041928 0.996738 -0.068966 +vn 0.041928 0.996737 -0.068966 +vn 0.041925 0.996738 -0.068964 +vn 0.041928 0.996737 -0.068967 +vn -0.029387 -0.664760 0.746478 +vn 0.785550 -0.617370 0.042013 +vn -0.030594 -0.761180 -0.647818 +vn -0.030594 -0.761181 -0.647818 +vn -0.834630 -0.549448 0.038719 +vn 0.999120 -0.041887 0.002032 +vn -0.000864 -0.068989 -0.997617 +vn -0.041924 -0.996738 0.068964 +vn -0.041927 -0.996738 0.068963 +vn -0.041919 -0.996738 0.068964 +vn -0.041927 -0.996738 0.068960 +vn 0.041923 0.996738 -0.068964 +vn 0.041927 0.996737 -0.068973 +vn 0.041931 0.996737 -0.068965 +vn 0.041927 0.996737 -0.068968 +vn -0.000002 1.000000 0.000000 +vn 0.000000 1.000000 -0.000001 +vn 0.000002 1.000000 -0.000000 +vn 0.000000 1.000000 0.000001 +vn -0.000002 -1.000000 0.000000 +vn -0.000000 -1.000000 0.000001 +vn 0.000004 -1.000000 -0.000000 +vn 0.000000 -1.000000 -0.000003 +vn -0.000790 0.010805 0.999941 +vn 0.999386 -0.035026 0.000778 +vn -0.999418 0.034098 -0.000745 +vn 0.999113 -0.042096 -0.000998 +vn -0.999113 0.042096 0.000996 +vn -0.999113 0.042096 0.000997 +vn 0.000863 0.068989 0.997617 +vn -0.999113 0.042096 0.000998 +vn -0.999113 0.042095 0.000998 +vn 0.000864 0.068988 0.997617 +vn 0.000864 0.068987 0.997617 +vn 0.000865 0.068987 0.997617 +vn 0.003029 0.086035 0.996287 +vn -0.002550 0.609183 0.793026 +vn -0.425768 0.455283 0.781945 +vn -0.616656 0.126337 0.777029 +vn 0.620173 0.137676 0.772289 +vn 0.423329 0.463070 0.778690 +vn -0.007517 0.950080 0.311916 +vn -0.634637 0.710693 0.303563 +vn -0.937738 0.189764 0.290924 +vn 0.936303 0.206948 0.283742 +vn 0.623805 0.722234 0.298739 +vn -0.009867 0.961986 -0.272922 +vn -0.636938 0.722357 -0.269277 +vn -0.940015 0.201295 -0.275414 +vn 0.933279 0.219492 -0.284277 +vn 0.622277 0.732187 -0.276900 +vn -0.008821 0.640957 -0.767526 +vn -0.431962 0.486657 -0.759324 +vn -0.622857 0.157753 -0.766265 +vn 0.613295 0.157703 -0.773950 +vn 0.420238 0.490248 -0.763581 +vn -0.003692 0.127027 -0.991892 +vn -0.566625 0.297364 0.768447 +vn 0.000723 0.317426 0.948283 +vn 0.566950 0.307758 0.764102 +vn -0.908330 0.300469 0.290954 +vn 0.904870 0.317099 0.284005 +vn -0.910589 0.311916 -0.271174 +vn 0.901315 0.324511 -0.286921 +vn -0.572732 0.328305 -0.751128 +vn 0.558652 0.347419 -0.753132 +vn 0.003194 0.351418 -0.936213 +vn -0.474948 0.563099 0.676272 +vn -0.002007 0.563939 0.825814 +vn 0.469712 0.571762 0.672650 +vn -0.789424 0.555310 0.261610 +vn 0.781089 0.569713 0.255591 +vn -0.791408 0.565372 -0.232438 +vn 0.771590 0.582525 -0.255566 +vn -0.480274 0.590081 -0.648954 +vn 0.467557 0.594236 -0.654426 +vn 0.010773 0.599402 -0.800376 +vn 0.960382 0.277963 -0.020043 +vn 0.486168 0.241186 -0.839923 +vn 0.486157 0.241186 -0.839929 +vn 0.960383 0.277962 -0.020062 +vn -0.460862 0.280888 -0.841848 +vn -0.460864 0.280888 -0.841847 +vn -0.933659 0.357366 -0.023898 +vn -0.933659 0.357365 -0.023902 +vn -0.459434 0.394146 0.795971 +vn -0.459451 0.394146 0.795961 +vn 0.487583 0.354444 0.797892 +vn 0.487575 0.354445 0.797897 +vn -0.138249 0.346685 0.927737 +vn -0.065922 0.173150 0.982687 +vn -0.101006 0.257400 0.961011 +vn 0.988384 0.151858 0.005960 +vn 0.994413 0.094040 0.047938 +vn 0.995334 0.035884 0.089566 +vn -0.068252 0.154321 -0.985660 +vn -0.089341 0.053897 -0.994542 +vn -0.085707 0.071566 -0.993747 +vn -0.966451 0.253119 -0.043631 +vn -0.987884 0.152192 -0.030391 +vn -0.986268 0.162080 -0.031693 +vn 0.022720 0.581381 0.813314 +vn 0.962377 0.271010 -0.019575 +vn 0.962378 0.271010 -0.019575 +vn 0.021249 0.463891 -0.885637 +vn -0.936228 0.350611 -0.023435 +vn 0.034133 0.840407 0.540880 +vn -0.425650 0.902757 -0.062060 +vn 0.033101 0.757959 -0.651461 +vn 0.499962 0.863954 -0.060179 +vn 0.000000 1.000000 0.000000 +vn -0.962270 0.272095 0.000000 +vn 0.000000 0.358606 0.933489 +vn 0.000000 0.358607 0.933489 +vn -0.000000 0.358607 0.933489 +vn 0.959420 0.281982 0.000000 +vn 0.000000 0.357443 -0.933935 +vn -0.000000 0.357444 -0.933935 +vn 1.000000 0.000001 0.000000 +vn 0.000134 0.999999 -0.001151 +vn 0.000000 -0.000000 -1.000000 +vn 0.000000 0.974144 -0.225925 +vn 0.000000 0.974145 -0.225925 +vn 0.000000 0.940855 -0.338810 +vn -1.000000 0.000001 -0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.000000 0.972394 -0.233346 +vn 1.000000 -0.000001 0.000000 +vn -1.000000 -0.000000 -0.000000 +vn -0.000000 0.974144 -0.225925 +vn -0.000000 1.000000 0.000000 +vn -0.000000 1.000000 -0.000000 +vn -0.881781 0.471659 -0.000000 +vn -0.744571 0.667543 0.000000 +vn 0.872989 -0.487741 0.000000 +vn 0.744342 -0.667798 0.000000 +vn -0.000000 -1.000000 -0.000000 +vn 0.744571 0.667543 0.000001 +vn -0.744342 -0.667798 -0.000000 +vn 0.881781 0.471659 0.000000 +vn -0.872988 -0.487741 -0.000000 +vn -0.000001 1.000000 -0.000000 +vn -0.829630 0.558313 -0.000000 +vn -0.000000 -1.000000 0.000002 +vn 0.158239 -0.987401 0.000002 +vn 0.000004 -0.000001 -1.000000 +vn 0.829630 0.558314 0.000000 +vn -0.158240 -0.987401 0.000002 +vn -0.000004 -0.000001 -1.000000 +vn 0.841396 -0.540419 0.000000 +vn -0.841394 -0.540422 -0.000000 +vn -0.170318 0.985389 -0.000006 +vn 0.126406 0.991979 -0.000006 +vn 0.217590 0.976040 0.000000 +vn 0.126406 0.991979 0.000004 +vn -0.170318 0.985389 0.000004 +vn -0.134986 0.990847 -0.000000 +vn 0.158239 -0.987401 0.000000 +vn -0.158240 -0.987401 -0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000005 +vn 0.829629 0.558315 0.000000 +vn -0.170318 0.985389 -0.000008 +vn 0.126405 0.991979 -0.000008 +vn 0.217591 0.976040 0.000000 +vn 0.126405 0.991979 0.000005 +vn -0.170318 0.985389 0.000005 +vn -0.134987 0.990847 -0.000000 +vn 0.000002 1.000000 0.000000 +vn -0.000002 -1.000000 0.000005 +vn -0.000002 -1.000000 -0.000000 +vn -0.000000 1.000000 0.000001 +vn -0.000000 0.766045 0.642787 +vn -1.000000 0.000001 0.000000 +vn -0.000000 0.173648 0.984808 +vn -1.000000 0.000000 0.000001 +vn -0.000000 -0.500000 0.866025 +vn 0.000001 -0.939693 0.342020 +vn 0.000003 -0.939693 -0.342020 +vn 0.000003 -0.939692 -0.342021 +vn 0.000001 -0.500000 -0.866025 +vn 0.000000 0.173648 -0.984808 +vn -1.000000 0.000001 -0.000001 +vn -0.000000 0.766045 -0.642787 +vn -1.000000 0.000000 -0.000001 +vn 0.000000 -0.939693 -0.342020 +vn 0.000000 -0.939693 0.342020 +vn -0.000000 0.766044 0.642788 +vn -0.000000 0.766044 -0.642788 +vn 0.000000 0.173649 -0.984808 +vn 0.000000 -0.499999 -0.866026 +vn 0.158239 -0.987401 -0.000002 +vn -0.000000 -1.000000 -0.000002 +vn 0.000006 -0.000002 1.000000 +vn -0.158240 -0.987401 -0.000002 +vn -0.000006 -0.000002 1.000000 +vn -0.841395 -0.540421 -0.000000 +vn -0.170318 0.985389 0.000009 +vn 0.126405 0.991979 0.000009 +vn 0.217593 0.976040 0.000000 +vn 0.126405 0.991979 -0.000006 +vn 0.000000 -1.000000 -0.000005 +vn -0.829631 0.558313 -0.000000 +vn 0.000004 -0.000001 1.000000 +vn -0.000004 -0.000001 1.000000 +vn 0.841395 -0.540420 0.000000 +vn -0.170318 0.985389 0.000006 +vn 0.126405 0.991979 0.000006 +vn 0.126405 0.991979 -0.000004 +vn -0.170318 0.985389 -0.000004 +vn 0.158240 -0.987401 -0.000002 +vn -0.841394 -0.540421 -0.000000 +vn -0.170318 0.985389 0.000008 +vn 0.126405 0.991979 0.000008 +vn 0.217592 0.976040 0.000000 +vn 0.126405 0.991979 -0.000005 +vn -0.170318 0.985389 -0.000005 +vn -0.000002 -1.000000 -0.000005 +vn -0.000000 0.558313 0.829630 +vn -0.000002 -0.987401 -0.158239 +vn 1.000000 -0.000001 -0.000004 +vn 0.000000 0.558314 -0.829630 +vn -0.000002 -0.987401 0.158240 +vn 1.000000 -0.000001 0.000004 +vn 0.000000 -0.540419 -0.841396 +vn -0.000000 -0.540421 0.841395 +vn 0.000011 0.985389 0.170318 +vn 0.000011 0.991979 -0.126405 +vn -0.000000 0.976040 -0.217591 +vn -0.000006 0.991979 -0.126405 +vn -0.000006 0.985389 0.170318 +vn -0.000000 0.990847 0.134986 +vn 0.000000 -0.987401 -0.158239 +vn 0.000000 -0.987401 0.158240 +vn -0.000005 -1.000000 -0.000000 +vn -0.006697 0.353906 0.935257 +vn 0.013078 0.514621 0.857318 +vn -0.010448 0.321920 0.946709 +vn 0.982803 0.178718 0.046448 +vn 0.944296 0.328693 -0.016283 +vn 0.979997 0.194992 0.039803 +vn -0.040836 0.217230 -0.975266 +vn 0.010446 0.393041 -0.919461 +vn -0.041468 0.214980 -0.975738 +vn -0.902971 0.428723 -0.028976 +vn -0.958504 0.283917 -0.025700 +vn -0.960518 0.277042 -0.025533 +vn -0.000001 0.005038 0.999987 +vn -0.000001 0.005081 0.999987 +vn 0.000347 0.046610 0.998913 +vn 0.999212 -0.039653 0.001876 +vn -0.999997 0.002351 0.000704 +vn 0.993882 -0.110244 0.006763 +vn 0.993881 -0.110244 0.006763 +vn -0.004597 -0.157544 -0.987501 +vn -0.022621 0.001736 -0.999743 +vn -0.022455 0.002147 -0.999745 +vn -0.045190 -0.054313 -0.997501 +vn -0.999938 0.011086 -0.000000 +vn -0.999939 0.011086 -0.000000 +vn -0.999999 0.001081 -0.000000 +vn -0.999999 0.001104 -0.000000 +vn -0.999960 -0.008947 -0.000000 +vn -0.007014 0.000664 0.999975 +vn -0.007066 0.000536 0.999975 +vn -0.014139 -0.016993 0.999756 +vn 0.997910 0.064621 0.000000 +vn 0.999917 0.012840 -0.000000 +vn 0.999916 0.012937 -0.000000 +vn 0.999251 -0.038689 -0.000000 +vn 0.999732 0.023065 0.001755 +vn 0.999705 0.024228 0.001735 +vn 0.998843 0.048088 0.000000 +vn 0.998860 0.047729 0.000000 +vn 0.000554 0.014040 0.999901 +vn 0.000567 0.013756 0.999905 +vn 0.000000 0.005596 0.999984 +vn 0.000000 0.004504 0.999990 +vn -0.999903 -0.013953 -0.000127 +vn -0.999904 -0.013862 -0.000129 +vn -0.999520 -0.030963 -0.000000 +vn -0.999522 -0.030917 -0.000000 +vn 0.000438 -0.005436 -0.999985 +vn 0.000428 -0.003641 -0.999993 +vn 0.000000 0.010501 -0.999945 +vn 0.000000 0.013756 -0.999905 +vn 0.999996 0.002869 -0.000680 +vn 0.999981 0.006111 -0.000852 +vn -0.000395 0.048066 0.998844 +vn -0.000307 0.045364 0.998970 +vn -0.999918 0.012734 -0.001652 +vn -0.999927 0.011992 -0.001597 +vn -0.001027 -0.031991 -0.999488 +vn -0.001145 -0.028713 -0.999587 +vn 0.999025 0.044085 -0.002183 +vn 0.999025 0.044088 -0.002183 +vn -0.999212 -0.039653 0.001877 +vn -0.999212 -0.039658 0.001877 +vn 0.999997 0.002351 0.000704 +vn -1.000000 -0.000000 0.000000 +vn -0.834004 0.551758 -0.000000 +vn 0.834004 0.551758 0.000000 +vn 0.834004 -0.551758 0.000000 +vn -0.834005 -0.551757 -0.000000 +vn 0.998334 0.057704 0.000000 +vn 0.999745 0.002147 0.022456 +vn 0.999743 0.001736 0.022621 +vn 0.997501 -0.054314 0.045191 +vn -0.000001 0.011086 0.999938 +vn -0.000001 0.001104 0.999999 +vn -0.000001 0.001081 0.999999 +vn -0.000001 0.011086 0.999939 +vn -0.000001 -0.008947 0.999960 +vn -0.999837 0.018041 -0.000000 +vn -0.999975 0.000536 0.007066 +vn -0.999975 0.000664 0.007014 +vn -0.999756 -0.016993 0.014139 +vn 0.000000 0.064621 -0.997910 +vn 0.000000 0.012937 -0.999916 +vn 0.000000 0.012840 -0.999917 +vn 0.000001 -0.038689 -0.999251 +vn -0.998334 0.057704 -0.000000 +vn -0.999745 0.002147 -0.022455 +vn -0.999743 0.001736 -0.022621 +vn -0.997501 -0.054313 -0.045190 +vn 0.000001 0.011086 -0.999938 +vn 0.000001 0.001104 -0.999999 +vn 0.000001 0.001081 -0.999999 +vn 0.000001 -0.008947 -0.999960 +vn 0.999837 0.018041 0.000000 +vn 0.999975 0.000535 -0.007066 +vn 0.999975 0.000664 -0.007014 +vn 0.999756 -0.016994 -0.014139 +vn -0.000001 0.064621 0.997910 +vn -0.000001 0.012937 0.999916 +vn -0.000001 0.012840 0.999918 +vn -0.000001 -0.038689 0.999251 +vn 1.000000 -0.000001 -0.000001 +vn 0.000005 -0.291256 0.956645 +vn 0.611063 0.757263 0.230552 +vn -0.000053 0.291199 -0.956662 +vn -0.000054 -0.291265 0.956642 +vn 0.116145 0.950171 0.289283 +vn 0.000060 0.291261 -0.956644 +vn -0.611061 0.757265 0.230553 +vn -0.000001 0.291245 -0.956648 +vn 0.000051 -0.291264 0.956643 +vn -0.116138 0.950172 0.289283 +vn -0.000060 0.291261 -0.956644 +vn 1.000000 -0.000001 -0.000000 +vn -0.000000 0.226080 0.974109 +vn 0.611062 0.771086 -0.178968 +vn 0.611063 0.771086 -0.178968 +vn -0.000055 -0.226150 -0.974092 +vn -0.000055 -0.226150 -0.974093 +vn -0.000062 0.226071 0.974111 +vn 0.116153 0.967513 -0.224559 +vn 0.000036 -0.226091 -0.974106 +vn 0.000000 0.226080 0.974109 +vn -0.611059 0.771089 -0.178966 +vn -0.000001 -0.226102 -0.974104 +vn 0.000062 0.226071 0.974111 +vn -0.116153 0.967513 -0.224559 +vn -0.000035 -0.226091 -0.974106 +vn 0.611063 0.771085 -0.178967 +vn -0.000056 -0.226150 -0.974092 +vn 0.116145 0.967514 -0.224558 +vn 0.000029 -0.226087 -0.974107 +vn -0.000005 -0.226098 -0.974104 +vn -0.116145 0.967514 -0.224558 +vn -0.000029 -0.226087 -0.974107 +vn 0.116151 0.967513 -0.224559 +vn 0.116151 0.967514 -0.224559 +vn 0.000026 -0.226086 -0.974107 +vn -0.611060 0.771088 -0.178966 +vn -0.116151 0.967513 -0.224559 +vn -0.000026 -0.226086 -0.974107 +vn 0.000028 -0.226086 -0.974107 +vn -0.000028 -0.226086 -0.974107 +vn -0.000002 -0.206781 0.978387 +vn 0.611063 0.774475 0.163674 +vn -0.000065 -0.206784 0.978386 +vn -0.000065 -0.206784 0.978387 +vn 0.116142 0.971769 0.205369 +vn 0.000002 -0.206782 0.978387 +vn -0.611061 0.774477 0.163677 +vn 0.000064 -0.206785 0.978386 +vn -0.116136 0.971769 0.205370 +vn 1.000000 -0.000000 -0.000001 +vn 0.000004 -0.206776 0.978388 +vn 0.000004 -0.206777 0.978388 +vn 0.611062 0.774477 0.163675 +vn 0.611062 0.774476 0.163675 +vn -0.000066 -0.206783 0.978387 +vn 0.116148 0.971768 0.205368 +vn 0.116149 0.971768 0.205368 +vn -0.000004 -0.206776 0.978388 +vn -0.611060 0.774478 0.163677 +vn 0.000066 -0.206783 0.978387 +vn -0.116142 0.971769 0.205369 +vn -0.000001 -0.206780 0.978387 +vn 0.611063 0.774476 0.163675 +vn -0.000063 -0.206783 0.978387 +vn 0.000000 -0.206779 0.978388 +vn -0.611060 0.774478 0.163676 +vn 0.000063 -0.206783 0.978387 +vn -0.000001 0.000000 -1.000000 +vn 0.927622 -0.373520 -0.000006 +vn 0.295674 0.734288 -0.611063 +vn -0.927645 0.373463 0.000060 +vn 0.927614 -0.373539 0.000043 +vn 0.370995 0.921344 -0.116140 +vn -0.927620 0.373524 -0.000059 +vn 0.927622 -0.373520 0.000006 +vn 0.295676 0.734289 0.611060 +vn -0.927625 0.373512 0.000001 +vn 0.927614 -0.373539 -0.000043 +vn 0.370995 0.921344 0.116139 +vn -0.927620 0.373524 0.000059 +vn 0.163673 0.774479 -0.611059 +vn 0.978379 -0.206820 0.000025 +vn 0.205367 0.971762 -0.116202 +vn 0.978381 -0.206808 0.000049 +vn 0.163671 0.774483 0.611054 +vn 0.978381 -0.206811 -0.000015 +vn 0.205367 0.971762 0.116202 +vn 0.978381 -0.206808 -0.000049 +vn 0.136253 0.779771 -0.611058 +vn 0.985077 -0.172116 -0.000001 +vn 0.170952 0.978403 -0.116198 +vn 0.985076 -0.172122 0.000000 +vn 0.136250 0.779776 0.611053 +vn 0.985077 -0.172111 0.000007 +vn 0.170952 0.978403 0.116198 +vn 0.985076 -0.172122 -0.000000 +vn 0.095554 0.785796 -0.611060 +vn 0.992685 -0.120729 0.000008 +vn 0.992686 -0.120729 0.000008 +vn 0.119892 0.985969 -0.116149 +vn 0.992686 -0.120727 0.000027 +vn -0.000000 0.000001 1.000000 +vn 0.095553 0.785797 0.611058 +vn 0.095553 0.785797 0.611059 +vn 0.992687 -0.120720 0.000002 +vn 0.119892 0.985969 0.116149 +vn 0.992686 -0.120727 -0.000027 +vn 0.095554 0.785794 -0.611062 +vn 0.992688 -0.120710 -0.000002 +vn 0.119892 0.985970 -0.116144 +vn 0.992688 -0.120705 0.000001 +vn 0.000000 0.000002 1.000000 +vn 0.095553 0.785796 0.611060 +vn 0.992688 -0.120705 0.000008 +vn 0.119892 0.985970 0.116143 +vn 0.992688 -0.120705 -0.000001 +vn 0.026702 0.791134 -0.611060 +vn 0.999431 -0.033724 0.000000 +vn 0.033504 0.992665 -0.116161 +vn 0.999431 -0.033713 -0.000060 +vn 0.026701 0.791135 0.611058 +vn 0.999431 -0.033724 -0.000000 +vn 0.033504 0.992665 0.116161 +vn 0.999431 -0.033713 0.000060 +vn 0.999432 -0.033713 0.000060 +vn 0.042337 0.790455 -0.611056 +vn 0.042337 0.790455 -0.611055 +vn 0.998569 -0.053480 -0.000007 +vn 0.053116 0.991809 -0.116160 +vn 0.998569 -0.053484 0.000002 +vn 0.042337 0.790455 0.611055 +vn 0.998569 -0.053472 0.000016 +vn 0.053116 0.991809 0.116160 +vn 0.998569 -0.053484 -0.000002 +vn -0.000000 -0.000001 -1.000000 +vn 0.163672 0.774480 -0.611058 +vn 0.978381 -0.206808 0.000015 +vn 0.205365 0.971760 -0.116225 +vn 0.978384 -0.206796 0.000039 +vn 0.163670 0.774484 0.611054 +vn 0.978382 -0.206804 -0.000010 +vn 0.205365 0.971760 0.116224 +vn 0.978384 -0.206796 -0.000039 +vn 0.163674 0.774479 -0.611059 +vn 0.978379 -0.206818 0.000029 +vn 0.205367 0.971760 -0.116218 +vn 0.978382 -0.206807 0.000049 +vn 0.163672 0.774483 0.611054 +vn 0.978381 -0.206811 -0.000021 +vn 0.205367 0.971760 0.116217 +vn 0.978382 -0.206807 -0.000049 +vn 0.163673 0.774480 -0.611058 +vn 0.163673 0.774480 -0.611059 +vn 0.978377 -0.206828 0.000032 +vn 0.205365 0.971761 -0.116211 +vn 0.978381 -0.206811 0.000068 +vn 0.978379 -0.206819 -0.000022 +vn 0.205365 0.971761 0.116210 +vn 0.978381 -0.206811 -0.000068 +vn 0.000001 -0.000001 -1.000000 +vn -0.927621 -0.373522 -0.000006 +vn -0.295674 0.734288 -0.611063 +vn 0.927644 0.373464 0.000060 +vn -0.927614 -0.373539 0.000043 +vn -0.370995 0.921344 -0.116139 +vn 0.927621 0.373523 -0.000056 +vn -0.927621 -0.373522 0.000006 +vn -0.295677 0.734289 0.611061 +vn -0.295677 0.734289 0.611060 +vn 0.927624 0.373514 0.000002 +vn -0.927614 -0.373539 -0.000043 +vn -0.370995 0.921344 0.116139 +vn 0.927621 0.373523 0.000056 +vn -0.163673 0.774479 -0.611059 +vn -0.978379 -0.206820 0.000025 +vn -0.205366 0.971761 -0.116209 +vn -0.978382 -0.206807 0.000047 +vn -0.163671 0.774484 0.611054 +vn -0.978381 -0.206810 -0.000015 +vn -0.205366 0.971761 0.116208 +vn -0.978382 -0.206808 -0.000047 +vn -0.978382 -0.206807 -0.000047 +vn -0.136252 0.779771 -0.611059 +vn -0.985077 -0.172116 -0.000002 +vn -0.170952 0.978403 -0.116199 +vn -0.985076 -0.172122 0.000000 +vn -0.136250 0.779775 0.611054 +vn -0.985078 -0.172111 0.000007 +vn -0.170952 0.978403 0.116198 +vn -0.985076 -0.172122 -0.000000 +vn -0.095554 0.785795 -0.611061 +vn -0.992685 -0.120729 0.000008 +vn -0.119892 0.985969 -0.116150 +vn -0.992686 -0.120726 0.000026 +vn 0.000000 0.000000 1.000000 +vn -0.095553 0.785797 0.611059 +vn -0.992686 -0.120720 0.000001 +vn -0.992687 -0.120720 0.000001 +vn -0.119892 0.985969 0.116149 +vn -0.992686 -0.120726 -0.000026 +vn -0.095553 0.785794 -0.611062 +vn -0.992688 -0.120708 -0.000003 +vn -0.119891 0.985970 -0.116144 +vn -0.992688 -0.120704 0.000000 +vn -0.095552 0.785796 0.611060 +vn -0.095552 0.785796 0.611059 +vn -0.992689 -0.120703 0.000009 +vn -0.119891 0.985970 0.116143 +vn -0.992688 -0.120704 -0.000000 +vn -0.026702 0.791135 -0.611059 +vn -0.026702 0.791134 -0.611059 +vn -0.999431 -0.033723 -0.000000 +vn -0.033505 0.992664 -0.116168 +vn -0.999431 -0.033712 -0.000060 +vn -0.999432 -0.033712 -0.000060 +vn -0.026702 0.791135 0.611058 +vn -0.999431 -0.033723 0.000000 +vn -0.033504 0.992664 0.116167 +vn -0.999432 -0.033712 0.000060 +vn -0.999431 -0.033712 0.000060 +vn -0.042337 0.790454 -0.611056 +vn -0.998569 -0.053480 -0.000007 +vn -0.053116 0.991809 -0.116160 +vn -0.998569 -0.053484 0.000002 +vn 0.000001 0.000000 1.000000 +vn -0.042337 0.790454 0.611056 +vn -0.998569 -0.053472 0.000016 +vn -0.053116 0.991809 0.116160 +vn -0.998569 -0.053484 -0.000002 +vn -0.163672 0.774480 -0.611058 +vn -0.978381 -0.206809 0.000015 +vn -0.205365 0.971760 -0.116226 +vn -0.978384 -0.206796 0.000039 +vn -0.163670 0.774484 0.611054 +vn -0.978382 -0.206804 -0.000010 +vn -0.205365 0.971760 0.116225 +vn -0.978384 -0.206796 -0.000039 +vn -0.978379 -0.206818 0.000029 +vn -0.205365 0.971760 -0.116224 +vn -0.978382 -0.206806 0.000047 +vn -0.163670 0.774483 0.611054 +vn -0.978381 -0.206809 -0.000019 +vn -0.205365 0.971760 0.116223 +vn -0.978382 -0.206806 -0.000047 +vn -0.000000 -0.000000 -1.000000 +vn -0.163673 0.774480 -0.611058 +vn -0.978378 -0.206827 0.000031 +vn -0.978377 -0.206827 0.000031 +vn -0.205365 0.971762 -0.116204 +vn -0.978381 -0.206811 0.000068 +vn -0.163671 0.774483 0.611054 +vn -0.978379 -0.206819 -0.000021 +vn -0.205365 0.971762 0.116204 +vn -0.978381 -0.206811 -0.000068 +vn 0.000862 0.068989 0.997617 +vn 0.014737 -0.073574 -0.997181 +vn 0.006937 -0.071283 -0.997432 +vn 0.999120 -0.041887 0.002031 +vn -0.000863 -0.068989 -0.997617 +vn 0.999120 -0.041886 0.002031 +vn -0.000865 -0.068989 -0.997617 +vn -0.999120 0.041887 -0.002033 +vn -0.000862 -0.068990 -0.997617 +vn -0.999120 0.041887 -0.002030 +vn -0.000863 -0.068988 -0.997617 +vn 0.999113 -0.042097 -0.000997 +vn 0.999113 -0.042098 -0.000996 +vn 0.002580 -0.073569 -0.997287 +vn 0.003711 -0.075073 -0.997171 +vn 0.999113 -0.042095 -0.000998 +vn 0.999113 -0.042098 -0.000997 +vn 0.000863 0.068988 0.997617 +vn 0.009625 -0.081209 -0.996651 +vn 0.003587 -0.073611 -0.997281 +vn 0.005050 -0.075129 -0.997161 +vn 0.009626 -0.081209 -0.996651 +vn 0.998334 0.057703 0.000000 +vn 0.999745 0.002147 0.022455 +vn 0.997501 -0.054313 0.045190 +vn -0.000000 0.011086 0.999939 +vn -0.000000 0.001104 0.999999 +vn -0.000000 0.001081 0.999999 +vn -0.000000 0.011086 0.999938 +vn -0.000000 -0.008947 0.999960 +vn -0.999756 -0.016994 0.014139 +vn 0.000000 0.011086 -0.999938 +vn 0.000000 0.001104 -0.999999 +vn 0.000000 0.001081 -0.999999 +vn 0.000000 -0.008947 -0.999960 +vn -0.000000 0.064621 0.997910 +vn -0.000000 0.012937 0.999916 +vn -0.000000 0.012840 0.999918 +vn -0.000000 -0.038689 0.999251 +# 818 vertex normals + +vt 0.012654 0.016752 0.000000 +vt 0.015619 0.138501 0.000000 +vt 0.043488 0.139032 0.000000 +vt 0.050718 0.017477 0.000000 +vt 0.012572 0.283086 0.000000 +vt 0.016071 0.383270 0.000000 +vt 0.043156 0.383786 0.000000 +vt 0.050790 0.283815 0.000000 +vt 0.306432 0.349196 0.000000 +vt 0.301565 0.462757 0.000000 +vt 0.279736 0.462757 0.000000 +vt 0.276617 0.349196 0.000000 +vt 0.306492 0.596584 0.000000 +vt 0.301257 0.690228 0.000000 +vt 0.280042 0.690228 0.000000 +vt 0.276557 0.596584 0.000000 +vt 0.154007 0.443754 0.000000 +vt 0.139840 0.553525 0.000000 +vt 0.114834 0.553187 0.000000 +vt 0.119853 0.443293 0.000000 +vt 0.138443 0.683100 0.000000 +vt 0.125112 0.773560 0.000000 +vt 0.100810 0.773226 0.000000 +vt 0.104151 0.682633 0.000000 +vt 0.264590 0.346411 0.000000 +vt 0.261105 0.459646 0.000000 +vt 0.236710 0.459646 0.000000 +vt 0.231271 0.346411 0.000000 +vt 0.264658 0.592874 0.000000 +vt 0.260763 0.686591 0.000000 +vt 0.237054 0.686588 0.000000 +vt 0.231204 0.592874 0.000000 +vt 0.016394 0.484813 0.000000 +vt 0.052407 0.483219 0.000000 +vt 0.308880 0.783296 0.000000 +vt 0.280626 0.784595 0.000000 +vt 0.127489 0.861824 0.000000 +vt 0.095037 0.863425 0.000000 +vt 0.260064 0.779286 0.000000 +vt 0.228487 0.778003 0.000000 +vt 0.024370 0.553781 0.000000 +vt 0.051444 0.552583 0.000000 +vt 0.307118 0.849434 0.000000 +vt 0.285877 0.850413 0.000000 +vt 0.121656 0.925271 0.000000 +vt 0.097260 0.926474 0.000000 +vt 0.254255 0.844051 0.000000 +vt 0.230518 0.843067 0.000000 +vt 0.028226 0.624007 0.000000 +vt 0.063581 0.622442 0.000000 +vt 0.313756 0.914610 0.000000 +vt 0.286017 0.915881 0.000000 +vt 0.128424 0.987856 0.000000 +vt 0.096565 0.989425 0.000000 +vt 0.253591 0.911283 0.000000 +vt 0.222598 0.909968 0.000000 +vt 0.598216 0.822103 0.000000 +vt 0.598216 0.887276 0.000000 +vt 0.542564 0.887276 0.000000 +vt 0.542564 0.822103 0.000000 +vt 0.159201 0.432211 0.000000 +vt 0.211562 0.432211 0.000000 +vt 0.211562 0.360839 0.000000 +vt 0.159201 0.360839 0.000000 +vt 0.380910 0.380190 0.000000 +vt 0.380910 0.426720 0.000000 +vt 0.311123 0.426618 0.000000 +vt 0.311123 0.379936 0.000000 +vt 0.653868 0.822103 0.000000 +vt 0.653868 0.887276 0.000000 +vt 0.158804 0.584058 0.000000 +vt 0.211263 0.584058 0.000000 +vt 0.211562 0.503582 0.000000 +vt 0.159201 0.503582 0.000000 +vt 0.845303 0.426501 0.000000 +vt 0.845303 0.490898 0.000000 +vt 0.759763 0.490671 0.000000 +vt 0.759763 0.426364 0.000000 +vt 0.598216 0.991496 0.000000 +vt 0.542564 0.900832 0.000000 +vt 0.222453 0.432211 0.000000 +vt 0.222453 0.360839 0.000000 +vt 0.380910 0.436575 0.000000 +vt 0.311123 0.436306 0.000000 +vt 0.653868 0.900832 0.000000 +vt 0.222293 0.584058 0.000000 +vt 0.222453 0.503582 0.000000 +vt 0.845303 0.504293 0.000000 +vt 0.759763 0.504293 0.000000 +vt 0.479696 0.989375 0.000000 +vt 0.479696 0.902035 0.000000 +vt 0.428608 0.900737 0.000000 +vt 0.530784 0.900909 0.000000 +vt 0.479696 0.887182 0.000000 +vt 0.428608 0.887543 0.000000 +vt 0.530784 0.887543 0.000000 +vt 0.479696 0.823491 0.000000 +vt 0.428608 0.823972 0.000000 +vt 0.530784 0.823972 0.000000 +vt 0.074071 0.768585 0.000000 +vt 0.040225 0.803286 0.000000 +vt 0.040225 0.716642 0.000000 +vt 0.074071 0.716740 0.000000 +vt 0.006380 0.768585 0.000000 +vt 0.006380 0.716740 0.000000 +vt 0.649273 0.544755 0.000000 +vt 0.704771 0.651648 0.000000 +vt 0.704771 0.658405 0.000000 +vt 0.647725 0.550526 0.000000 +vt 0.760270 0.544755 0.000000 +vt 0.761818 0.550526 0.000000 +vt 0.682519 0.517566 0.000000 +vt 0.683102 0.476980 0.000000 +vt 0.680476 0.476980 0.000000 +vt 0.679896 0.517558 0.000000 +vt 0.683102 0.440043 0.000000 +vt 0.680476 0.440038 0.000000 +vt 0.682626 0.393813 0.000000 +vt 0.680005 0.393810 0.000000 +vt 0.760266 0.544520 0.000000 +vt 0.704770 0.658405 0.000000 +vt 0.761818 0.550286 0.000000 +vt 0.649279 0.544312 0.000000 +vt 0.647725 0.550074 0.000000 +vt 0.676633 0.392784 0.000000 +vt 0.677001 0.437206 0.000000 +vt 0.674473 0.437196 0.000000 +vt 0.674113 0.392771 0.000000 +vt 0.677001 0.472695 0.000000 +vt 0.674473 0.472695 0.000000 +vt 0.676439 0.511693 0.000000 +vt 0.673915 0.511685 0.000000 +vt 0.880490 0.265007 0.000000 +vt 0.875035 0.421400 0.000000 +vt 0.851796 0.425875 0.000000 +vt 0.865906 0.258865 0.000000 +vt 0.563428 0.166591 0.000000 +vt 0.420693 0.148576 0.000000 +vt 0.421709 0.006334 0.000000 +vt 0.557908 0.007751 0.000000 +vt 0.304001 0.148362 0.000000 +vt 0.305082 0.006132 0.000000 +vt 0.144407 0.165881 0.000000 +vt 0.144465 0.006815 0.000000 +vt 0.834700 0.160504 0.000000 +vt 0.839679 0.007073 0.000000 +vt 0.983625 0.009514 0.000000 +vt 0.994303 0.181157 0.000000 +vt 0.717472 0.159443 0.000000 +vt 0.573324 0.177295 0.000000 +vt 0.583421 0.006146 0.000000 +vt 0.722519 0.006002 0.000000 +vt 0.071790 0.704248 0.000000 +vt 0.071790 0.631420 0.000000 +vt 0.006608 0.631420 0.000000 +vt 0.006608 0.713549 0.000000 +vt 0.825580 0.588546 0.000000 +vt 0.825923 0.543295 0.000000 +vt 0.870063 0.540987 0.000000 +vt 0.884018 0.585390 0.000000 +vt 0.767192 0.585203 0.000000 +vt 0.781820 0.540845 0.000000 +vt 0.241745 0.180801 0.000000 +vt 0.242412 0.314925 0.000000 +vt 0.137253 0.345905 0.000000 +vt 0.152192 0.173809 0.000000 +vt 0.350255 0.176300 0.000000 +vt 0.351367 0.353486 0.000000 +vt 0.794937 0.518783 0.000000 +vt 0.794937 0.532460 0.000000 +vt 0.677625 0.532460 0.000000 +vt 0.677625 0.518783 0.000000 +vt 0.873013 0.532460 0.000000 +vt 0.873013 0.518783 0.000000 +vt 0.409725 0.580382 0.000000 +vt 0.468744 0.682506 0.000000 +vt 0.468744 0.698419 0.000000 +vt 0.409725 0.594834 0.000000 +vt 0.527763 0.580382 0.000000 +vt 0.527763 0.594834 0.000000 +vt 0.608578 0.643922 0.000000 +vt 0.613396 0.718112 0.000000 +vt 0.628458 0.718112 0.000000 +vt 0.629283 0.643922 0.000000 +vt 0.610904 0.782131 0.000000 +vt 0.629283 0.809836 0.000000 +vt 0.581721 0.644497 0.000000 +vt 0.586133 0.718594 0.000000 +vt 0.601582 0.718594 0.000000 +vt 0.602960 0.644497 0.000000 +vt 0.581721 0.810411 0.000000 +vt 0.602960 0.810411 0.000000 +vt 0.632638 0.641697 0.000000 +vt 0.633549 0.719692 0.000000 +vt 0.650190 0.719692 0.000000 +vt 0.655514 0.641697 0.000000 +vt 0.632638 0.816339 0.000000 +vt 0.652944 0.787177 0.000000 +vt 0.550433 0.645429 0.000000 +vt 0.552106 0.730829 0.000000 +vt 0.570873 0.730829 0.000000 +vt 0.576232 0.645429 0.000000 +vt 0.550433 0.804685 0.000000 +vt 0.576232 0.804685 0.000000 +vt 0.773557 0.867934 0.000000 +vt 0.840422 0.867934 0.000000 +vt 0.840422 0.826098 0.000000 +vt 0.773557 0.826098 0.000000 +vt 0.891346 0.603267 0.000000 +vt 0.990701 0.603267 0.000000 +vt 0.990701 0.541171 0.000000 +vt 0.891346 0.541171 0.000000 +vt 0.992386 0.740190 0.000000 +vt 0.887207 0.740190 0.000000 +vt 0.887207 0.676957 0.000000 +vt 0.992386 0.676957 0.000000 +vt 0.553286 0.299789 0.000000 +vt 0.553286 0.265645 0.000000 +vt 0.737493 0.265645 0.000000 +vt 0.737493 0.299789 0.000000 +vt 0.388378 0.615284 0.000000 +vt 0.327459 0.615225 0.000000 +vt 0.327340 0.549019 0.000000 +vt 0.388258 0.549079 0.000000 +vt 0.785189 0.740342 0.000000 +vt 0.876932 0.740372 0.000000 +vt 0.874984 0.800315 0.000000 +vt 0.783322 0.796078 0.000000 +vt 0.314459 0.538752 0.000000 +vt 0.401102 0.538836 0.000000 +vt 0.314615 0.625467 0.000000 +vt 0.401258 0.625551 0.000000 +vt 0.509781 0.206548 0.000000 +vt 0.357211 0.205633 0.000000 +vt 0.377797 0.165799 0.000000 +vt 0.494283 0.166497 0.000000 +vt 0.693759 0.181598 0.000000 +vt 0.693759 0.215435 0.000000 +vt 0.515102 0.215435 0.000000 +vt 0.515102 0.181598 0.000000 +vt 0.553844 0.261520 0.000000 +vt 0.553844 0.221410 0.000000 +vt 0.718262 0.221410 0.000000 +vt 0.718262 0.261520 0.000000 +vt 0.851109 0.817325 0.000000 +vt 0.852945 0.909014 0.000000 +vt 0.993694 0.906713 0.000000 +vt 0.991859 0.815024 0.000000 +vt 0.928227 0.913432 0.000000 +vt 0.881093 0.913432 0.000000 +vt 0.881093 0.993091 0.000000 +vt 0.928227 0.993091 0.000000 +vt 0.938580 0.912794 0.000000 +vt 0.989721 0.912794 0.000000 +vt 0.989721 0.995932 0.000000 +vt 0.938580 0.995932 0.000000 +vt 0.661001 0.668572 0.000000 +vt 0.760821 0.668572 0.000000 +vt 0.760821 0.823572 0.000000 +vt 0.661001 0.823572 0.000000 +vt 0.450275 0.711749 0.000000 +vt 0.530937 0.712014 0.000000 +vt 0.537699 0.707113 0.000000 +vt 0.443746 0.706804 0.000000 +vt 0.529009 0.793474 0.000000 +vt 0.535537 0.798418 0.000000 +vt 0.448346 0.793209 0.000000 +vt 0.441585 0.798110 0.000000 +vt 0.316679 0.520855 0.000000 +vt 0.391288 0.521632 0.000000 +vt 0.397322 0.526228 0.000000 +vt 0.310420 0.525323 0.000000 +vt 0.393156 0.446644 0.000000 +vt 0.399416 0.442177 0.000000 +vt 0.318547 0.445867 0.000000 +vt 0.312514 0.441272 0.000000 +vt 0.772137 0.911161 0.000000 +vt 0.838943 0.914039 0.000000 +vt 0.891011 0.660106 0.000000 +vt 0.990129 0.667426 0.000000 +vt 0.991575 0.809874 0.000000 +vt 0.886646 0.802420 0.000000 +vt 0.785189 0.679488 0.000000 +vt 0.876932 0.679518 0.000000 +vt 0.748662 0.658551 0.000000 +vt 0.747808 0.590020 0.000000 +vt 0.781400 0.619258 0.000000 +vt 0.781889 0.658481 0.000000 +vt 0.881570 0.658273 0.000000 +vt 0.880715 0.589743 0.000000 +vt 0.847854 0.619120 0.000000 +vt 0.848343 0.658343 0.000000 +vt 0.814733 0.627703 0.000000 +vt 0.815116 0.658412 0.000000 +vt 0.880576 0.589867 0.000000 +vt 0.986675 0.334672 0.000000 +vt 0.979742 0.358697 0.000000 +vt 0.972902 0.349958 0.000000 +vt 0.973024 0.331887 0.000000 +vt 0.902677 0.327736 0.000000 +vt 0.920954 0.326430 0.000000 +vt 0.920822 0.344541 0.000000 +vt 0.909314 0.353106 0.000000 +vt 0.957160 0.373699 0.000000 +vt 0.956701 0.358251 0.000000 +vt 0.956901 0.327704 0.000000 +vt 0.937242 0.325641 0.000000 +vt 0.937032 0.356202 0.000000 +vt 0.936115 0.371536 0.000000 +vt 0.974496 0.289445 0.000000 +vt 0.988547 0.292644 0.000000 +vt 0.901255 0.285624 0.000000 +vt 0.919933 0.283913 0.000000 +vt 0.957520 0.285542 0.000000 +vt 0.937042 0.283448 0.000000 +vt 0.937043 0.283448 0.000000 +vt 0.981229 0.271638 0.000000 +vt 0.997045 0.276516 0.000000 +vt 0.892894 0.267828 0.000000 +vt 0.913436 0.264758 0.000000 +vt 0.960239 0.268701 0.000000 +vt 0.934572 0.266051 0.000000 +vt 0.015551 0.792427 0.000000 +vt 0.023494 0.796012 0.000000 +vt 0.015618 0.803217 0.000000 +vt 0.012784 0.801938 0.000000 +vt 0.025262 0.798531 0.000000 +vt 0.016249 0.804116 0.000000 +vt 0.026392 0.807158 0.000000 +vt 0.016653 0.807195 0.000000 +vt 0.027028 0.815850 0.000000 +vt 0.016879 0.810297 0.000000 +vt 0.025423 0.818476 0.000000 +vt 0.016307 0.811234 0.000000 +vt 0.017230 0.821408 0.000000 +vt 0.013383 0.812281 0.000000 +vt 0.950316 0.244776 0.000000 +vt 0.926254 0.196651 0.000000 +vt 0.974379 0.196651 0.000000 +vt 0.942154 0.196651 0.000000 +vt 0.990279 0.196651 0.000000 +vt 0.703969 0.202333 0.000000 +vt 0.697153 0.177971 0.000000 +vt 0.907151 0.179861 0.000000 +vt 0.899881 0.204096 0.000000 +vt 0.880852 0.215670 0.000000 +vt 0.722807 0.214248 0.000000 +vt 0.084867 0.833080 0.000000 +vt 0.084867 0.885652 0.000000 +vt 0.005583 0.882165 0.000000 +vt 0.005583 0.833080 0.000000 +vt 0.005583 0.937001 0.000000 +vt 0.084867 0.937001 0.000000 +vt 0.084867 0.994156 0.000000 +vt 0.005583 0.994156 0.000000 +vt 0.365766 0.294652 0.000000 +vt 0.354834 0.263612 0.000000 +vt 0.549777 0.263612 0.000000 +vt 0.538805 0.294652 0.000000 +vt 0.745197 0.306229 0.000000 +vt 0.631636 0.306229 0.000000 +vt 0.631636 0.336052 0.000000 +vt 0.738461 0.336052 0.000000 +vt 0.527297 0.336052 0.000000 +vt 0.527297 0.306229 0.000000 +vt 0.404158 0.306229 0.000000 +vt 0.411159 0.336052 0.000000 +vt 0.522137 0.259512 0.000000 +vt 0.532271 0.218463 0.000000 +vt 0.372073 0.218463 0.000000 +vt 0.372073 0.259512 0.000000 +vt 0.111379 0.354608 0.000000 +vt 0.111379 0.482986 0.000000 +vt 0.061331 0.482986 0.000000 +vt 0.061331 0.354608 0.000000 +vt 0.589293 0.386857 0.000000 +vt 0.577062 0.354081 0.000000 +vt 0.521553 0.354081 0.000000 +vt 0.521553 0.386857 0.000000 +vt 0.532188 0.405203 0.000000 +vt 0.532188 0.396280 0.000000 +vt 0.668419 0.396280 0.000000 +vt 0.668419 0.405203 0.000000 +vt 0.226251 0.593539 0.000000 +vt 0.226251 0.687977 0.000000 +vt 0.216792 0.687977 0.000000 +vt 0.216792 0.593539 0.000000 +vt 0.207334 0.687977 0.000000 +vt 0.207334 0.593539 0.000000 +vt 0.197876 0.687977 0.000000 +vt 0.197876 0.593539 0.000000 +vt 0.188417 0.687977 0.000000 +vt 0.188417 0.593539 0.000000 +vt 0.178959 0.687977 0.000000 +vt 0.178959 0.593539 0.000000 +vt 0.668419 0.413746 0.000000 +vt 0.532188 0.413746 0.000000 +vt 0.668419 0.413784 0.000000 +vt 0.668419 0.422328 0.000000 +vt 0.532188 0.422290 0.000000 +vt 0.532188 0.422328 0.000000 +vt 0.668419 0.430871 0.000000 +vt 0.532188 0.430871 0.000000 +vt 0.668419 0.438512 0.000000 +vt 0.532188 0.438512 0.000000 +vt 0.147921 0.687977 0.000000 +vt 0.147921 0.593539 0.000000 +vt 0.656788 0.499130 0.000000 +vt 0.656788 0.506294 0.000000 +vt 0.641636 0.506294 0.000000 +vt 0.641636 0.499130 0.000000 +vt 0.483471 0.354081 0.000000 +vt 0.483471 0.398954 0.000000 +vt 0.445389 0.379808 0.000000 +vt 0.445389 0.354081 0.000000 +vt 0.971480 0.382404 0.000000 +vt 0.992499 0.382404 0.000000 +vt 0.992499 0.432430 0.000000 +vt 0.971480 0.432430 0.000000 +vt 0.663376 0.353810 0.000000 +vt 0.663376 0.381263 0.000000 +vt 0.708301 0.401693 0.000000 +vt 0.708301 0.353810 0.000000 +vt 0.609076 0.496745 0.000000 +vt 0.614053 0.496745 0.000000 +vt 0.614053 0.501251 0.000000 +vt 0.609076 0.501251 0.000000 +vt 0.671939 0.499130 0.000000 +vt 0.671939 0.506294 0.000000 +vt 0.626484 0.506294 0.000000 +vt 0.626484 0.499130 0.000000 +vt 0.521553 0.398954 0.000000 +vt 0.407308 0.370435 0.000000 +vt 0.407308 0.354081 0.000000 +vt 0.618451 0.353810 0.000000 +vt 0.618451 0.371261 0.000000 +vt 0.753225 0.401693 0.000000 +vt 0.753225 0.353810 0.000000 +vt 0.385324 0.370435 0.000000 +vt 0.385324 0.354081 0.000000 +vt 0.617737 0.506294 0.000000 +vt 0.617737 0.499130 0.000000 +vt 0.592518 0.353810 0.000000 +vt 0.592518 0.371261 0.000000 +vt 0.208022 0.723085 0.000000 +vt 0.147200 0.723085 0.000000 +vt 0.147200 0.761660 0.000000 +vt 0.208022 0.761660 0.000000 +vt 0.592518 0.384433 0.000000 +vt 0.618451 0.384433 0.000000 +vt 0.614053 0.504652 0.000000 +vt 0.609076 0.504652 0.000000 +vt 0.407308 0.382779 0.000000 +vt 0.385324 0.382779 0.000000 +vt 0.560023 0.509239 0.000000 +vt 0.565549 0.509234 0.000000 +vt 0.565552 0.528147 0.000000 +vt 0.560026 0.528151 0.000000 +vt 0.555594 0.557173 0.000000 +vt 0.550396 0.557173 0.000000 +vt 0.550396 0.578514 0.000000 +vt 0.555594 0.578514 0.000000 +vt 0.410936 0.740343 0.000000 +vt 0.421208 0.740343 0.000000 +vt 0.406503 0.769423 0.000000 +vt 0.399096 0.762757 0.000000 +vt 0.565556 0.553898 0.000000 +vt 0.560030 0.553902 0.000000 +vt 0.550396 0.600403 0.000000 +vt 0.555594 0.600403 0.000000 +vt 0.368512 0.796925 0.000000 +vt 0.368512 0.785745 0.000000 +vt 0.330521 0.769423 0.000000 +vt 0.337927 0.762757 0.000000 +vt 0.315815 0.740343 0.000000 +vt 0.326088 0.740343 0.000000 +vt 0.560011 0.459369 0.000000 +vt 0.565538 0.459365 0.000000 +vt 0.555594 0.457250 0.000000 +vt 0.550396 0.457250 0.000000 +vt 0.410936 0.635400 0.000000 +vt 0.421208 0.635400 0.000000 +vt 0.315815 0.635400 0.000000 +vt 0.326088 0.635400 0.000000 +vt 0.332052 0.648468 0.000000 +vt 0.400478 0.648468 0.000000 +vt 0.400478 0.733099 0.000000 +vt 0.332052 0.733099 0.000000 +vt 0.390930 0.751175 0.000000 +vt 0.341600 0.751175 0.000000 +vt 0.602906 0.554954 0.000000 +vt 0.591929 0.572188 0.000000 +vt 0.591753 0.500200 0.000000 +vt 0.602776 0.501478 0.000000 +vt 0.596456 0.495586 0.000000 +vt 0.583391 0.495586 0.000000 +vt 0.583391 0.455565 0.000000 +vt 0.596456 0.455565 0.000000 +vt 0.636479 0.572732 0.000000 +vt 0.635085 0.572732 0.000000 +vt 0.635085 0.545743 0.000000 +vt 0.636479 0.545743 0.000000 +vt 0.571480 0.455566 0.000000 +vt 0.571480 0.495586 0.000000 +vt 0.619447 0.466800 0.000000 +vt 0.619458 0.461970 0.000000 +vt 0.634974 0.462453 0.000000 +vt 0.634962 0.467284 0.000000 +vt 0.635032 0.487322 0.000000 +vt 0.635032 0.494721 0.000000 +vt 0.629485 0.493488 0.000000 +vt 0.591712 0.601289 0.000000 +vt 0.591712 0.587412 0.000000 +vt 0.603827 0.568601 0.000000 +vt 0.610173 0.573931 0.000000 +vt 0.602761 0.494721 0.000000 +vt 0.602761 0.487322 0.000000 +vt 0.608308 0.493967 0.000000 +vt 0.618896 0.484744 0.000000 +vt 0.618896 0.492142 0.000000 +vt 0.580867 0.555200 0.000000 +vt 0.580738 0.502223 0.000000 +vt 0.636479 0.599721 0.000000 +vt 0.635085 0.599721 0.000000 +vt 0.603932 0.466323 0.000000 +vt 0.603943 0.461492 0.000000 +vt 0.573251 0.573931 0.000000 +vt 0.579597 0.568601 0.000000 +vt 0.639689 0.512074 0.000000 +vt 0.639689 0.552623 0.000000 +vt 0.638434 0.552623 0.000000 +vt 0.638435 0.512074 0.000000 +vt 0.639689 0.574705 0.000000 +vt 0.638434 0.574705 0.000000 +vt 0.639689 0.596786 0.000000 +vt 0.638434 0.596786 0.000000 +vt 0.639688 0.636957 0.000000 +vt 0.638434 0.636957 0.000000 +vt 0.609435 0.478820 0.000000 +vt 0.623688 0.478221 0.000000 +vt 0.623715 0.481135 0.000000 +vt 0.609462 0.481735 0.000000 +vt 0.637919 0.477613 0.000000 +vt 0.637946 0.480528 0.000000 +vt 0.579597 0.510357 0.000000 +vt 0.573251 0.511220 0.000000 +vt 0.635085 0.634959 0.000000 +vt 0.636478 0.634959 0.000000 +vt 0.635085 0.510506 0.000000 +vt 0.636478 0.510506 0.000000 +vt 0.610173 0.511219 0.000000 +vt 0.603827 0.509808 0.000000 +vt 0.645402 0.477287 0.000000 +vt 0.637879 0.473296 0.000000 +vt 0.645360 0.472969 0.000000 +vt 0.623648 0.473903 0.000000 +vt 0.609396 0.474502 0.000000 +vt 0.601977 0.479126 0.000000 +vt 0.601939 0.474808 0.000000 +vt 0.619470 0.456671 0.000000 +vt 0.634986 0.457154 0.000000 +vt 0.603955 0.456193 0.000000 +vt 0.645440 0.481223 0.000000 +vt 0.649071 0.477125 0.000000 +vt 0.649109 0.481061 0.000000 +vt 0.649030 0.472807 0.000000 +vt 0.637767 0.487322 0.000000 +vt 0.637767 0.494721 0.000000 +vt 0.601320 0.461412 0.000000 +vt 0.601332 0.456113 0.000000 +vt 0.601309 0.466242 0.000000 +vt 0.637596 0.462535 0.000000 +vt 0.637585 0.467366 0.000000 +vt 0.637609 0.457236 0.000000 +vt 0.600026 0.494721 0.000000 +vt 0.600026 0.487322 0.000000 +vt 0.598308 0.479275 0.000000 +vt 0.598269 0.474957 0.000000 +vt 0.602012 0.483062 0.000000 +vt 0.598343 0.483211 0.000000 +vt 0.884496 0.219498 0.000000 +vt 0.888541 0.219498 0.000000 +vt 0.888541 0.241973 0.000000 +vt 0.884496 0.241973 0.000000 +vt 0.924947 0.535069 0.000000 +vt 0.924947 0.477954 0.000000 +vt 0.961102 0.521707 0.000000 +vt 0.888541 0.264448 0.000000 +vt 0.884496 0.264448 0.000000 +vt 0.980339 0.487872 0.000000 +vt 0.888541 0.286923 0.000000 +vt 0.884496 0.286923 0.000000 +vt 0.973658 0.449397 0.000000 +vt 0.888541 0.309398 0.000000 +vt 0.884496 0.309398 0.000000 +vt 0.944184 0.424284 0.000000 +vt 0.888541 0.331873 0.000000 +vt 0.884496 0.331873 0.000000 +vt 0.905709 0.424284 0.000000 +vt 0.888541 0.354348 0.000000 +vt 0.884496 0.354348 0.000000 +vt 0.876235 0.449397 0.000000 +vt 0.888541 0.376823 0.000000 +vt 0.884496 0.376823 0.000000 +vt 0.869554 0.487872 0.000000 +vt 0.888541 0.399298 0.000000 +vt 0.884496 0.399298 0.000000 +vt 0.888792 0.521707 0.000000 +vt 0.888541 0.421773 0.000000 +vt 0.884496 0.421773 0.000000 +vt 0.963875 0.525062 0.000000 +vt 0.924947 0.539449 0.000000 +vt 0.886019 0.525062 0.000000 +vt 0.865306 0.488633 0.000000 +vt 0.872500 0.447207 0.000000 +vt 0.904234 0.420168 0.000000 +vt 0.945660 0.420168 0.000000 +vt 0.977394 0.447207 0.000000 +vt 0.984588 0.488633 0.000000 +vt 0.401014 0.341234 0.000000 +vt 0.447104 0.341234 0.000000 +vt 0.447104 0.345197 0.000000 +vt 0.401014 0.345197 0.000000 +vt 0.493194 0.341234 0.000000 +vt 0.493194 0.345197 0.000000 +vt 0.539486 0.341234 0.000000 +vt 0.539486 0.345197 0.000000 +vt 0.585100 0.341234 0.000000 +vt 0.585100 0.345197 0.000000 +vt 0.629242 0.341234 0.000000 +vt 0.629242 0.345197 0.000000 +vt 0.672616 0.341234 0.000000 +vt 0.672616 0.345197 0.000000 +vt 0.716758 0.341234 0.000000 +vt 0.716758 0.345197 0.000000 +vt 0.762371 0.341234 0.000000 +vt 0.762371 0.345197 0.000000 +vt 0.354722 0.341234 0.000000 +vt 0.354722 0.345197 0.000000 +vt 0.790019 0.413304 0.000000 +vt 0.803916 0.413397 0.000000 +vt 0.119499 0.326743 0.000000 +vt 0.130081 0.007811 0.000000 +vt 0.096761 0.006483 0.000000 +vt 0.116257 0.328175 0.000000 +vt 0.119470 0.326596 0.000000 +vt 0.498268 0.533072 0.000000 +vt 0.470453 0.570431 0.000000 +vt 0.470453 0.475910 0.000000 +vt 0.498268 0.475910 0.000000 +vt 0.522481 0.428644 0.000000 +vt 0.522481 0.515713 0.000000 +vt 0.515700 0.515713 0.000000 +vt 0.515700 0.428644 0.000000 +vt 0.522481 0.580639 0.000000 +vt 0.515700 0.580639 0.000000 +vt 0.466087 0.450004 0.000000 +vt 0.466087 0.460441 0.000000 +vt 0.420424 0.460441 0.000000 +vt 0.420424 0.450004 0.000000 +vt 0.442637 0.533072 0.000000 +vt 0.442637 0.475910 0.000000 +vt 0.511751 0.450004 0.000000 +vt 0.511751 0.460441 0.000000 +vt 0.508683 0.468273 0.000000 +vt 0.508683 0.538480 0.000000 +vt 0.502048 0.537927 0.000000 +vt 0.502048 0.471459 0.000000 +vt 0.469704 0.590832 0.000000 +vt 0.469704 0.581367 0.000000 +vt 0.430725 0.538480 0.000000 +vt 0.437360 0.537927 0.000000 +vt 0.430725 0.468273 0.000000 +vt 0.437360 0.471459 0.000000 +vt 0.469704 0.468273 0.000000 +vt 0.469704 0.471459 0.000000 +vt 0.539319 0.451928 0.000000 +vt 0.539319 0.542477 0.000000 +vt 0.543092 0.542477 0.000000 +vt 0.543092 0.451928 0.000000 +vt 0.539319 0.601655 0.000000 +vt 0.543092 0.601655 0.000000 +vt 0.526992 0.576193 0.000000 +vt 0.526992 0.514563 0.000000 +vt 0.532984 0.514563 0.000000 +vt 0.532984 0.576193 0.000000 +vt 0.526992 0.452933 0.000000 +vt 0.532984 0.452933 0.000000 +vt 0.790647 0.935920 0.000000 +vt 0.782447 0.935886 0.000000 +vt 0.782447 0.983549 0.000000 +vt 0.790648 0.983515 0.000000 +vt 0.759349 0.989810 0.000000 +vt 0.787288 0.990184 0.000000 +vt 0.754938 0.983231 0.000000 +vt 0.754937 0.936204 0.000000 +vt 0.787287 0.929251 0.000000 +vt 0.759348 0.929626 0.000000 +vt 0.750508 0.984014 0.000000 +vt 0.754669 0.991672 0.000000 +vt 0.750507 0.935422 0.000000 +vt 0.754669 0.927764 0.000000 +vt 0.710367 0.935921 0.000000 +vt 0.710368 0.983515 0.000000 +vt 0.718568 0.983550 0.000000 +vt 0.718568 0.935886 0.000000 +vt 0.746078 0.983231 0.000000 +vt 0.746077 0.936204 0.000000 +vt 0.741666 0.929625 0.000000 +vt 0.713727 0.929251 0.000000 +vt 0.741667 0.989810 0.000000 +vt 0.746347 0.991672 0.000000 +vt 0.746346 0.927763 0.000000 +vt 0.713728 0.990185 0.000000 +vt 0.757808 0.910781 0.000000 +vt 0.757875 0.862545 0.000000 +vt 0.749564 0.862534 0.000000 +vt 0.749497 0.910769 0.000000 +vt 0.721537 0.862463 0.000000 +vt 0.721470 0.910762 0.000000 +vt 0.726547 0.917343 0.000000 +vt 0.754574 0.917349 0.000000 +vt 0.716707 0.910532 0.000000 +vt 0.716705 0.862426 0.000000 +vt 0.716707 0.918714 0.000000 +vt 0.721574 0.919201 0.000000 +vt 0.675605 0.910783 0.000000 +vt 0.683916 0.910771 0.000000 +vt 0.683846 0.862536 0.000000 +vt 0.675535 0.862548 0.000000 +vt 0.711943 0.910762 0.000000 +vt 0.711873 0.862463 0.000000 +vt 0.678840 0.917351 0.000000 +vt 0.706867 0.917343 0.000000 +vt 0.711839 0.919201 0.000000 +vt 0.417124 0.887121 0.000000 +vt 0.417124 0.992542 0.000000 +vt 0.391801 0.992542 0.000000 +vt 0.391801 0.887121 0.000000 +vt 0.374133 0.805636 0.000000 +vt 0.377162 0.912849 0.000000 +vt 0.353026 0.912595 0.000000 +vt 0.349996 0.805381 0.000000 +vt 0.189495 0.803714 0.000000 +vt 0.192525 0.910927 0.000000 +vt 0.167881 0.910314 0.000000 +vt 0.164862 0.803454 0.000000 +vt 0.167891 0.910667 0.000000 +vt 0.379147 0.983090 0.000000 +vt 0.355011 0.982836 0.000000 +vt 0.194509 0.981168 0.000000 +vt 0.169876 0.980909 0.000000 +vt 0.233499 0.941383 0.000000 +vt 0.234635 0.981585 0.000000 +vt 0.314885 0.982419 0.000000 +vt 0.313749 0.942217 0.000000 +vt 0.273870 0.950527 0.000000 +vt 0.274760 0.982002 0.000000 +# 758 texture coords + +o church +g church +f 1/1/1 2/2/2 3/3/3 +f 3/3/3 4/4/1 1/1/1 +f 5/5/4 6/6/5 7/7/6 +f 7/7/6 8/8/7 5/5/4 +f 9/9/8 10/10/9 2/11/10 +f 2/11/10 1/12/11 9/9/8 +f 11/13/12 12/14/13 6/15/14 +f 6/15/14 5/16/15 11/13/12 +f 13/17/16 14/18/17 10/19/18 +f 10/19/18 9/20/16 13/17/16 +f 15/21/19 16/22/20 12/23/21 +f 12/23/21 11/24/22 15/21/19 +f 4/25/23 3/26/24 14/27/25 +f 14/27/25 13/28/23 4/25/23 +f 8/29/26 7/30/27 16/31/28 +f 16/31/28 15/32/29 8/29/26 +f 5/5/4 8/8/7 3/3/3 +f 3/3/3 2/2/2 5/5/4 +f 17/33/30 18/34/31 7/7/6 +f 7/7/6 6/6/5 17/33/30 +f 11/13/12 5/16/15 2/11/10 +f 2/11/10 10/10/9 11/13/12 +f 19/35/32 17/36/33 6/15/14 +f 6/15/14 12/14/13 19/35/32 +f 15/21/19 11/24/22 10/19/18 +f 10/19/18 14/18/17 15/21/19 +f 20/37/34 19/38/35 12/23/21 +f 12/23/21 16/22/20 20/37/34 +f 8/29/26 15/32/29 14/27/25 +f 14/27/25 3/26/24 8/29/26 +f 18/39/36 20/40/37 16/31/28 +f 16/31/28 7/30/27 18/39/36 +f 21/41/38 22/42/39 18/34/31 +f 18/34/31 17/33/30 21/41/38 +f 23/43/40 21/44/41 17/36/33 +f 17/36/33 19/35/32 23/43/40 +f 24/45/42 23/46/43 19/38/35 +f 19/38/35 20/37/34 24/45/42 +f 22/47/44 24/48/45 20/40/37 +f 20/40/37 18/39/36 22/47/44 +f 25/49/46 26/50/46 22/42/39 +f 22/42/39 21/41/38 25/49/46 +f 27/51/47 25/52/47 21/44/41 +f 21/44/41 23/43/40 27/51/47 +f 28/53/48 27/54/48 23/46/43 +f 23/46/43 24/45/42 28/53/48 +f 26/55/49 28/56/49 24/48/45 +f 24/48/45 22/47/44 26/55/49 +f 29/3/50 30/2/51 31/1/52 +f 31/1/52 32/4/52 29/3/50 +f 33/7/53 34/6/54 35/5/55 +f 35/5/55 36/8/56 33/7/53 +f 30/11/57 37/10/58 38/9/59 +f 38/9/59 31/12/59 30/11/57 +f 34/15/60 39/14/61 40/13/62 +f 40/13/62 35/16/63 34/15/60 +f 37/19/64 41/18/65 42/17/66 +f 42/17/66 38/20/66 37/19/64 +f 39/23/67 43/22/68 44/21/69 +f 44/21/69 40/24/70 39/23/67 +f 41/27/71 29/26/72 32/25/73 +f 32/25/73 42/28/73 41/27/71 +f 43/31/74 33/30/75 36/29/76 +f 36/29/76 44/32/77 43/31/74 +f 29/3/50 36/8/56 35/5/55 +f 35/5/55 30/2/51 29/3/50 +f 33/7/53 45/34/78 46/33/79 +f 46/33/79 34/6/54 33/7/53 +f 30/11/57 35/16/63 40/13/62 +f 40/13/62 37/10/58 30/11/57 +f 34/15/60 46/36/80 47/35/81 +f 47/35/81 39/14/61 34/15/60 +f 37/19/64 40/24/70 44/21/69 +f 44/21/69 41/18/65 37/19/64 +f 39/23/67 47/38/82 48/37/83 +f 48/37/83 43/22/68 39/23/67 +f 41/27/71 44/32/77 36/29/76 +f 36/29/76 29/26/72 41/27/71 +f 43/31/74 48/40/84 45/39/85 +f 45/39/85 33/30/75 43/31/74 +f 45/34/78 49/42/86 50/41/87 +f 50/41/87 46/33/79 45/34/78 +f 46/36/80 50/44/88 51/43/89 +f 51/43/89 47/35/81 46/36/80 +f 47/38/82 51/46/90 52/45/91 +f 52/45/91 48/37/83 47/38/82 +f 48/40/84 52/48/92 49/47/93 +f 49/47/93 45/39/85 48/40/84 +f 49/42/86 53/50/94 54/49/94 +f 54/49/94 50/41/87 49/42/86 +f 50/44/88 54/52/95 55/51/95 +f 55/51/95 51/43/89 50/44/88 +f 51/46/90 55/54/96 56/53/96 +f 56/53/96 52/45/91 51/46/90 +f 52/48/92 56/56/97 53/55/97 +f 53/55/97 49/47/93 52/48/92 +f 57/57/98 58/58/98 59/59/98 +f 59/59/98 60/60/98 57/57/98 +f 61/61/99 62/62/99 63/63/99 +f 63/63/99 64/64/99 61/61/99 +f 65/65/100 66/66/100 67/67/100 +f 67/67/100 68/68/100 65/65/100 +f 57/57/98 64/69/98 63/70/98 +f 63/70/98 58/58/98 57/57/98 +f 69/71/99 70/72/99 71/73/99 +f 71/73/99 72/74/99 69/71/99 +f 60/75/100 59/76/100 73/77/100 +f 73/77/100 74/78/100 60/75/100 +f 58/58/98 75/79/98 76/80/98 +f 76/80/98 59/59/98 58/58/98 +f 77/81/99 78/82/99 63/63/99 +f 63/63/99 62/62/99 77/81/99 +f 79/83/100 80/84/100 67/67/100 +f 67/67/100 66/66/100 79/83/100 +f 78/85/98 75/79/98 58/58/98 +f 58/58/98 63/70/98 78/85/98 +f 81/86/99 82/87/99 71/73/99 +f 71/73/99 70/72/99 81/86/99 +f 82/87/99 77/81/99 62/62/99 +f 62/62/99 71/73/99 82/87/99 +f 76/88/100 83/89/100 73/77/100 +f 73/77/100 59/76/100 76/88/100 +f 84/90/101 85/91/101 80/92/101 +f 84/90/102 81/93/102 85/91/102 +f 80/92/103 85/91/103 86/94/103 +f 86/94/103 67/95/103 80/92/103 +f 85/91/102 81/93/102 70/96/102 +f 70/96/102 86/94/102 85/91/102 +f 67/95/101 86/94/101 87/97/101 +f 87/97/101 68/98/101 67/95/101 +f 86/94/102 70/96/102 69/99/102 +f 69/99/102 87/97/102 86/94/102 +f 62/62/99 61/61/99 72/74/99 +f 72/74/99 71/73/99 62/62/99 +f 88/100/104 89/101/104 90/102/104 +f 90/102/104 91/103/104 88/100/104 +f 89/101/100 92/104/100 93/105/100 +f 93/105/100 90/102/100 89/101/100 +f 94/106/105 95/107/105 96/108/105 +f 96/108/105 97/109/105 94/106/105 +f 95/107/106 98/110/106 99/111/106 +f 99/111/106 96/108/106 95/107/106 +f 98/112/107 100/113/107 101/114/107 +f 101/114/107 99/115/107 98/112/107 +f 102/116/108 103/117/108 101/114/108 +f 101/114/108 100/113/108 102/116/108 +f 102/116/109 104/118/109 105/119/109 +f 105/119/109 103/117/109 102/116/109 +f 104/120/110 106/107/110 107/121/110 +f 107/121/110 105/122/110 104/120/110 +f 106/107/111 108/123/111 109/124/111 +f 109/124/111 107/121/111 106/107/111 +f 108/125/112 110/126/112 111/127/112 +f 111/127/112 109/128/112 108/125/112 +f 112/129/113 113/130/113 111/127/113 +f 111/127/113 110/126/113 112/129/113 +f 112/129/114 94/131/114 97/132/114 +f 97/132/114 113/130/114 112/129/114 +f 76/133/115 75/134/115 95/135/115 +f 95/135/115 94/136/115 76/133/115 +f 75/134/116 78/133/117 98/136/117 +f 98/136/117 95/135/116 75/134/116 +f 81/133/118 84/134/118 106/135/118 +f 106/135/118 104/136/118 81/133/118 +f 84/134/119 80/133/119 108/136/119 +f 108/136/119 106/135/119 84/134/119 +f 96/137/120 114/138/121 113/139/122 +f 113/139/122 97/140/123 96/137/120 +f 115/141/124 111/142/125 113/139/122 +f 113/139/122 114/138/121 115/141/124 +f 107/143/126 109/144/127 111/142/125 +f 111/142/125 115/141/124 107/143/126 +f 115/145/128 103/146/128 105/147/128 +f 105/147/128 107/148/128 115/145/128 +f 114/149/129 96/150/129 99/151/129 +f 99/151/129 101/152/129 114/149/129 +f 66/153/102 65/154/102 93/155/102 +f 93/155/102 92/156/102 66/153/102 +f 74/154/98 73/153/98 88/156/98 +f 88/156/98 91/155/98 74/154/98 +f 115/145/130 114/149/130 101/152/130 +f 101/152/130 103/146/130 115/145/130 +f 116/157/131 117/158/131 118/159/132 +f 118/159/132 119/160/132 116/157/131 +f 120/161/133 121/162/133 117/158/131 +f 117/158/131 116/157/131 120/161/133 +f 122/163/134 123/164/135 124/165/136 +f 124/165/136 125/166/137 122/163/134 +f 123/164/135 126/163/138 127/167/139 +f 127/167/139 124/168/136 123/164/135 +f 118/169/140 122/170/140 125/171/141 +f 125/171/141 119/172/141 118/169/140 +f 121/169/142 126/170/142 128/173/143 +f 128/173/143 129/174/143 121/169/142 +f 120/175/100 116/176/100 124/177/100 +f 124/177/100 127/178/100 120/175/100 +f 116/176/100 119/179/100 125/180/100 +f 125/180/100 124/177/100 116/176/100 +f 130/167/144 131/168/145 123/164/135 +f 123/164/135 122/163/134 130/167/144 +f 131/165/145 128/166/146 126/163/138 +f 126/163/138 123/164/135 131/165/145 +f 132/174/147 130/173/148 122/170/140 +f 122/170/140 118/169/140 132/174/147 +f 120/172/149 127/171/149 126/170/142 +f 126/170/142 121/169/142 120/172/149 +f 133/181/150 134/182/151 135/183/152 +f 135/183/152 136/184/150 133/181/150 +f 134/182/151 137/185/153 138/186/153 +f 138/186/153 135/183/152 134/182/151 +f 136/187/154 135/188/155 139/189/156 +f 139/189/156 140/190/157 136/187/154 +f 135/188/155 138/191/158 141/192/158 +f 141/192/158 139/189/156 135/188/155 +f 140/193/159 139/194/160 142/195/161 +f 142/195/161 143/196/159 140/193/159 +f 139/194/160 141/197/162 144/198/162 +f 144/198/162 142/195/161 139/194/160 +f 143/199/163 142/200/164 134/201/165 +f 134/201/165 133/202/163 143/199/163 +f 142/200/164 144/203/166 137/204/166 +f 137/204/166 134/201/165 142/200/164 +f 145/205/167 146/206/168 147/207/99 +f 147/207/99 148/208/99 145/205/167 +f 149/209/169 145/210/170 148/211/102 +f 148/211/102 150/212/102 149/209/169 +f 146/213/171 151/214/172 152/215/173 +f 152/215/173 147/216/173 146/213/171 +f 153/217/174 154/218/174 155/219/174 +f 155/219/174 156/220/174 153/217/174 +f 157/217/175 158/218/175 159/219/175 +f 159/219/175 160/220/175 157/217/175 +f 161/221/176 162/222/176 163/223/176 +f 163/223/176 164/224/176 161/221/176 +f 149/225/177 151/226/178 165/227/179 +f 165/227/179 166/228/179 149/225/177 +f 153/220/180 160/217/180 159/218/180 +f 159/218/180 154/219/180 153/220/180 +f 157/220/181 156/217/181 155/218/181 +f 155/218/181 158/219/181 157/220/181 +f 164/224/182 163/223/182 157/229/182 +f 157/229/182 160/230/182 164/224/182 +f 163/223/183 162/222/183 156/231/183 +f 156/231/183 157/229/184 163/223/183 +f 162/222/185 161/221/185 153/232/185 +f 153/232/185 156/231/185 162/222/185 +f 164/224/186 160/230/186 153/232/186 +f 153/232/186 161/221/186 164/224/186 +f 154/233/187 159/234/187 167/235/187 +f 167/235/187 168/236/187 154/233/187 +f 168/235/188 169/236/188 155/233/188 +f 155/233/188 154/234/188 168/235/188 +f 170/236/189 158/233/190 155/234/189 +f 155/234/189 169/235/189 170/236/189 +f 170/235/191 167/236/191 159/233/191 +f 159/233/191 158/234/191 170/235/191 +f 171/237/180 172/238/180 173/239/180 +f 173/239/180 174/240/180 171/237/180 +f 175/241/99 176/242/99 177/243/99 +f 177/243/99 178/244/99 175/241/99 +f 179/238/192 172/239/192 171/240/192 +f 171/240/192 180/237/192 179/238/192 +f 177/242/101 181/243/101 182/244/101 +f 182/244/101 178/241/101 177/242/101 +f 173/238/175 183/239/175 184/240/175 +f 184/240/175 174/237/175 173/238/175 +f 185/242/173 176/243/173 175/244/173 +f 175/244/173 186/241/173 185/242/173 +f 182/241/100 181/242/100 185/243/100 +f 185/243/100 186/244/100 182/241/100 +f 184/237/193 183/238/193 179/239/193 +f 179/239/193 180/240/193 184/237/193 +f 187/245/180 168/246/180 167/247/180 +f 167/247/180 188/248/180 187/245/180 +f 169/246/192 168/247/192 187/248/192 +f 187/248/192 189/245/192 169/246/192 +f 167/247/175 170/246/175 190/245/175 +f 190/245/175 188/248/175 167/247/175 +f 170/247/193 169/246/193 189/245/193 +f 189/245/193 190/248/193 170/247/193 +f 191/249/101 192/250/101 193/251/101 +f 193/251/101 194/252/101 191/249/101 +f 195/253/173 196/254/173 197/255/173 +f 197/255/173 198/256/173 195/253/173 +f 192/257/100 195/258/100 198/259/100 +f 198/259/100 193/260/100 192/257/100 +f 199/261/194 166/262/194 180/263/194 +f 180/263/194 171/264/194 199/261/194 +f 166/262/195 165/265/195 184/266/195 +f 184/266/195 180/263/195 166/262/195 +f 165/265/196 200/267/196 174/268/196 +f 174/268/196 184/266/196 165/265/196 +f 200/267/197 199/261/197 171/264/197 +f 171/264/197 174/268/197 200/267/197 +f 188/267/198 190/265/198 183/266/198 +f 183/266/198 173/268/198 188/267/198 +f 190/265/199 189/262/199 179/263/199 +f 179/263/199 183/266/199 190/265/199 +f 189/262/200 187/261/200 172/264/200 +f 172/264/200 179/263/200 189/262/200 +f 187/261/201 188/267/201 173/268/201 +f 173/268/201 172/264/201 187/261/201 +f 147/269/202 152/270/202 186/271/202 +f 186/271/202 175/272/202 147/269/202 +f 152/270/203 150/273/203 182/274/203 +f 182/274/203 186/271/203 152/270/203 +f 150/273/204 148/275/204 178/276/204 +f 178/276/204 182/274/204 150/273/204 +f 148/275/205 147/269/205 175/272/205 +f 175/272/205 178/276/205 148/275/205 +f 194/275/206 193/273/206 181/274/206 +f 181/274/206 177/276/206 194/275/206 +f 193/273/207 198/270/207 185/271/207 +f 185/271/207 181/274/207 193/273/207 +f 198/270/208 197/269/208 176/272/208 +f 176/272/208 185/271/208 198/270/208 +f 197/269/209 194/275/209 177/276/209 +f 177/276/209 176/272/209 197/269/209 +f 199/277/210 200/278/210 146/206/168 +f 146/206/168 145/205/167 199/277/210 +f 166/279/211 199/280/211 145/210/170 +f 145/210/170 149/209/169 166/279/211 +f 200/281/212 165/282/212 151/214/172 +f 151/214/172 146/213/171 200/281/212 +f 150/283/100 152/284/100 151/226/178 +f 151/226/178 149/225/177 150/283/100 +f 201/285/193 202/286/193 203/287/193 +f 203/287/193 204/288/193 201/285/193 +f 205/289/213 206/290/213 207/291/213 +f 207/291/213 208/292/213 205/289/213 +f 201/285/214 209/288/215 210/287/215 +f 210/287/215 202/286/214 201/285/214 +f 211/289/216 212/290/216 213/291/180 +f 213/291/180 214/292/180 211/289/216 +f 215/293/213 216/287/213 217/288/213 +f 217/288/213 218/294/213 215/293/213 +f 219/292/217 220/291/217 221/293/218 +f 221/293/218 222/294/218 219/292/217 +f 223/293/193 224/291/193 225/292/193 +f 225/292/193 226/294/193 223/293/193 +f 227/293/219 228/287/220 229/288/220 +f 229/288/220 230/294/219 227/293/219 +f 223/293/193 226/294/193 204/288/193 +f 204/288/193 203/287/193 223/293/193 +f 215/293/213 218/294/213 208/292/213 +f 208/292/213 207/291/213 215/293/213 +f 209/288/215 222/294/218 221/293/218 +f 221/293/218 210/287/215 209/288/215 +f 227/293/219 230/294/219 214/292/180 +f 214/292/180 213/291/180 227/293/219 +f 216/287/213 212/286/213 211/285/213 +f 211/285/213 217/288/213 216/287/213 +f 231/289/217 232/290/217 220/291/217 +f 220/291/217 219/292/217 231/289/217 +f 224/291/193 206/295/193 205/289/193 +f 205/289/193 225/292/193 224/291/193 +f 228/287/220 232/286/221 231/285/221 +f 231/285/221 229/288/220 228/287/220 +f 233/296/222 234/297/223 235/298/224 +f 233/296/222 235/298/224 236/299/225 +f 233/300/222 237/301/226 238/302/227 +f 233/300/222 238/302/227 234/303/223 +f 234/297/223 239/304/228 240/305/229 +f 240/305/229 235/298/224 234/297/223 +f 235/298/224 240/305/229 241/306/230 +f 241/306/230 236/299/225 235/298/224 +f 237/301/226 242/307/231 243/308/232 +f 243/308/232 238/302/227 237/301/226 +f 238/302/227 243/308/232 239/309/228 +f 239/309/228 234/303/223 238/302/227 +f 239/304/228 244/309/233 245/308/234 +f 245/308/234 240/305/229 239/304/228 +f 240/305/229 245/308/234 246/307/235 +f 246/307/235 241/306/230 240/305/229 +f 242/307/231 247/306/236 248/305/237 +f 248/305/237 243/308/232 242/307/231 +f 243/308/232 248/305/237 244/304/233 +f 244/304/233 239/309/228 243/308/232 +f 244/309/233 249/303/238 250/302/239 +f 250/302/239 245/308/234 244/309/233 +f 245/308/234 250/302/239 251/301/240 +f 251/301/240 246/307/235 245/308/234 +f 247/306/236 252/299/241 253/298/242 +f 253/298/242 248/305/237 247/306/236 +f 248/305/237 253/298/242 249/297/238 +f 249/297/238 244/304/233 248/305/237 +f 254/300/243 250/302/239 249/303/238 +f 254/300/243 251/301/240 250/302/239 +f 254/296/243 253/298/242 252/299/241 +f 254/296/243 249/297/238 253/298/242 +f 233/296/222 236/299/225 255/310/244 +f 255/310/244 256/311/245 233/296/222 +f 237/301/226 233/300/222 256/312/245 +f 256/312/245 257/313/246 237/301/226 +f 236/299/225 241/306/230 258/314/247 +f 258/314/247 255/310/244 236/299/225 +f 242/307/231 237/301/226 257/313/246 +f 257/313/246 259/315/248 242/307/231 +f 241/306/230 246/307/235 260/316/249 +f 260/316/249 258/314/247 241/306/230 +f 247/306/236 242/307/231 259/315/248 +f 259/315/248 261/314/250 247/306/236 +f 246/307/235 251/301/240 262/313/251 +f 262/313/251 260/316/249 246/307/235 +f 252/299/241 247/306/236 261/314/250 +f 261/314/250 263/310/252 252/299/241 +f 251/301/240 254/300/243 264/312/253 +f 264/312/253 262/313/251 251/301/240 +f 254/296/243 252/299/241 263/310/252 +f 263/310/252 264/311/253 254/296/243 +f 256/311/245 255/310/244 265/317/254 +f 265/317/254 266/318/255 256/311/245 +f 257/313/246 256/312/245 266/319/255 +f 266/319/255 267/320/256 257/313/246 +f 255/310/244 258/314/247 268/321/257 +f 268/321/257 265/317/254 255/310/244 +f 259/315/248 257/313/246 267/320/256 +f 267/320/256 269/322/258 259/315/248 +f 258/314/247 260/316/249 270/322/259 +f 270/322/259 268/321/257 258/314/247 +f 261/314/250 259/315/248 269/322/258 +f 269/322/258 271/321/260 261/314/250 +f 260/316/249 262/313/251 272/320/261 +f 272/320/261 270/322/259 260/316/249 +f 263/310/252 261/314/250 271/321/260 +f 271/321/260 273/317/262 263/310/252 +f 262/313/251 264/312/253 274/319/263 +f 274/319/263 272/320/261 262/313/251 +f 264/311/253 263/310/252 273/317/262 +f 273/317/262 274/318/263 264/311/253 +f 275/323/264 276/324/265 277/325/266 +f 277/325/266 278/326/267 275/323/264 +f 276/324/265 279/327/268 280/328/269 +f 280/328/269 277/325/266 276/324/265 +f 279/327/268 281/329/270 282/330/271 +f 282/330/271 280/328/269 279/327/268 +f 281/329/270 283/331/272 284/332/273 +f 284/332/273 282/330/271 281/329/270 +f 283/331/272 285/333/274 286/334/275 +f 286/334/275 284/332/273 283/331/272 +f 285/333/274 275/335/264 278/336/267 +f 278/336/267 286/334/275 285/333/274 +f 287/337/276 288/338/277 289/339/278 +f 287/337/279 289/340/280 290/341/281 +f 287/337/282 290/338/283 291/339/284 +f 287/337/285 291/340/286 288/341/287 +f 292/342/288 293/343/288 294/344/288 +f 294/344/288 295/345/288 292/342/288 +f 295/342/289 294/343/289 296/344/290 +f 296/344/290 297/345/289 295/342/289 +f 297/342/291 296/343/291 298/344/291 +f 298/344/291 299/345/291 297/342/291 +f 299/342/292 298/343/292 293/344/292 +f 293/344/292 292/345/292 299/342/292 +f 300/346/293 301/347/293 292/342/293 +f 292/342/293 295/345/293 300/346/293 +f 301/346/294 302/347/294 299/342/294 +f 299/342/294 292/345/294 301/346/294 +f 302/346/295 303/347/295 297/342/295 +f 297/342/295 299/345/295 302/346/295 +f 303/346/296 300/347/296 295/342/296 +f 295/342/296 297/345/296 303/346/296 +f 304/348/297 305/349/297 306/350/297 +f 306/350/297 307/351/297 304/348/297 +f 308/352/297 309/353/297 310/354/297 +f 310/354/297 311/355/297 308/352/297 +f 307/356/298 312/357/298 313/358/298 +f 313/358/298 304/359/298 307/356/298 +f 313/360/299 314/361/299 305/362/299 +f 305/362/299 304/363/299 313/360/299 +f 309/364/300 315/365/300 316/366/301 +f 316/366/301 310/367/301 309/364/300 +f 310/359/302 316/358/302 317/357/302 +f 317/357/302 311/356/302 310/359/302 +f 311/368/303 317/369/303 318/370/303 +f 318/370/303 308/371/303 311/368/303 +f 309/353/297 308/352/297 306/350/297 +f 306/350/297 305/349/297 309/353/297 +f 315/365/300 309/364/300 305/362/299 +f 305/362/299 314/361/299 315/365/300 +f 312/369/304 307/368/304 306/371/304 +f 306/371/304 319/370/304 312/369/304 +f 306/372/297 308/373/297 320/374/297 +f 320/374/297 321/375/297 306/372/297 +f 308/376/305 318/377/305 322/378/305 +f 322/378/305 320/379/305 308/376/305 +f 319/377/98 306/376/98 321/379/98 +f 321/379/98 323/378/98 319/377/98 +f 324/380/100 325/381/100 326/382/100 +f 326/382/100 327/383/100 324/380/100 +f 324/384/297 327/385/297 328/386/297 +f 328/386/297 329/387/297 324/384/297 +f 330/387/306 331/386/306 332/388/306 +f 332/388/306 333/389/306 330/387/306 +f 334/389/306 335/388/306 336/390/306 +f 336/390/306 337/391/306 334/389/306 +f 338/391/297 339/390/297 340/392/297 +f 340/392/297 341/393/297 338/391/297 +f 342/393/297 343/392/297 344/394/297 +f 344/394/297 345/395/297 342/393/297 +f 329/380/100 328/383/100 331/396/100 +f 331/396/100 330/397/100 329/380/100 +f 333/397/100 332/398/100 335/399/100 +f 335/399/100 334/400/100 333/397/100 +f 337/401/307 336/399/307 339/402/307 +f 339/402/307 338/403/307 337/401/307 +f 341/403/100 340/402/100 343/404/100 +f 343/404/100 342/405/100 341/403/100 +f 345/395/297 344/394/297 346/406/297 +f 346/406/297 347/407/297 345/395/297 +f 348/408/308 349/409/309 350/410/310 +f 350/410/310 351/411/310 348/408/308 +f 352/412/98 348/413/98 351/414/311 +f 351/414/311 353/415/311 352/412/98 +f 354/416/99 355/417/99 356/418/99 +f 356/418/99 357/419/99 354/416/99 +f 358/420/103 350/421/103 349/422/312 +f 349/422/312 359/423/312 358/420/103 +f 360/424/100 361/425/100 362/426/100 +f 362/426/100 363/427/100 360/424/100 +f 357/428/297 356/429/297 349/409/309 +f 349/409/309 348/408/308 357/428/297 +f 364/430/313 365/431/313 351/411/310 +f 351/411/310 350/410/310 364/430/313 +f 354/378/98 357/432/98 348/413/98 +f 348/413/98 352/412/98 354/378/98 +f 365/433/311 366/434/311 353/415/311 +f 353/415/311 351/414/311 365/433/311 +f 367/435/103 364/436/103 350/421/103 +f 350/421/103 358/420/103 367/435/103 +f 356/437/312 355/438/312 359/423/312 +f 359/423/312 349/422/312 356/437/312 +f 366/434/311 365/433/311 362/439/311 +f 362/439/311 361/440/311 366/434/311 +f 368/431/297 369/430/297 370/441/297 +f 370/441/297 371/442/297 368/431/297 +f 364/436/305 367/435/305 360/443/305 +f 360/443/305 363/444/305 364/436/305 +f 365/445/99 364/446/99 369/447/99 +f 369/447/99 368/448/99 365/445/99 +f 364/436/314 363/444/314 370/449/314 +f 370/449/314 369/450/314 364/436/314 +f 363/427/100 362/426/100 371/451/100 +f 371/451/100 370/452/100 363/427/100 +f 362/439/315 365/433/315 368/453/315 +f 368/453/315 371/454/315 362/439/315 +f 372/411/310 373/408/316 374/409/316 +f 374/409/316 375/410/310 372/411/310 +f 375/414/103 374/413/102 376/412/102 +f 376/412/102 377/415/103 375/414/103 +f 378/416/99 379/419/99 380/418/99 +f 380/418/99 381/417/99 378/416/99 +f 373/422/98 372/421/98 382/420/98 +f 382/420/98 383/423/98 373/422/98 +f 384/425/100 385/426/100 386/427/100 +f 386/427/100 387/424/100 384/425/100 +f 373/408/316 380/428/317 379/429/317 +f 379/429/317 374/409/316 373/408/316 +f 375/410/310 388/430/313 389/431/313 +f 389/431/313 372/411/310 375/410/310 +f 374/413/102 379/432/102 378/378/102 +f 378/378/102 376/412/102 374/413/102 +f 377/415/103 390/434/103 388/433/103 +f 388/433/103 375/414/103 377/415/103 +f 372/421/98 389/436/98 391/435/98 +f 391/435/98 382/420/98 372/421/98 +f 383/423/98 381/438/173 380/437/173 +f 380/437/173 373/422/98 383/423/98 +f 390/434/305 387/440/305 386/439/305 +f 386/439/305 388/433/305 390/434/305 +f 392/430/318 393/441/318 394/442/318 +f 394/442/318 395/431/318 392/430/318 +f 389/436/98 385/444/98 384/443/98 +f 384/443/98 391/435/98 389/436/98 +f 388/446/99 392/447/99 395/448/99 +f 395/448/99 389/445/99 388/446/99 +f 389/436/98 395/450/98 394/449/98 +f 394/449/98 385/444/98 389/436/98 +f 385/426/100 394/451/100 393/452/100 +f 393/452/100 386/427/100 385/426/100 +f 386/439/102 393/454/102 392/453/102 +f 392/453/102 388/433/102 386/439/102 +f 396/455/319 397/456/319 398/457/320 +f 398/457/320 399/458/320 396/455/319 +f 400/459/321 401/460/321 402/461/322 +f 402/461/322 403/462/322 400/459/321 +f 401/463/100 396/464/100 399/465/100 +f 399/465/100 402/466/100 401/463/100 +f 399/458/320 398/457/320 404/467/205 +f 404/467/205 405/468/205 399/458/320 +f 403/462/322 402/461/322 406/469/323 +f 406/469/323 407/470/323 403/462/322 +f 402/466/100 399/465/100 405/471/100 +f 405/471/100 406/472/100 402/466/100 +f 405/467/205 404/468/205 408/458/324 +f 408/458/324 409/457/324 405/467/205 +f 407/470/323 406/469/323 410/461/325 +f 410/461/325 411/462/325 407/470/323 +f 406/472/100 405/471/100 409/473/100 +f 409/473/100 410/474/100 406/472/100 +f 409/457/324 408/458/324 412/455/326 +f 412/455/326 413/456/326 409/457/324 +f 411/462/325 410/461/325 414/460/327 +f 414/460/327 415/459/327 411/462/325 +f 410/474/100 409/473/100 413/475/100 +f 413/475/100 414/476/100 410/474/100 +f 397/456/98 396/455/98 416/477/98 +f 416/477/98 417/478/98 397/456/98 +f 401/460/102 400/459/102 418/479/102 +f 418/479/102 419/480/102 401/460/102 +f 396/464/100 401/463/100 419/481/100 +f 419/481/100 416/482/100 396/464/100 +f 413/456/102 412/455/102 420/477/102 +f 420/477/102 421/478/102 413/456/102 +f 415/459/98 414/460/98 422/480/98 +f 422/480/98 423/479/98 415/459/98 +f 414/476/100 413/475/100 421/483/100 +f 421/483/100 422/484/100 414/476/100 +f 423/485/100 418/486/100 400/487/100 +f 400/487/100 415/488/100 423/485/100 +f 415/488/100 400/487/100 403/489/100 +f 403/489/100 411/490/100 415/488/100 +f 424/491/100 425/492/100 426/493/100 +f 426/493/100 427/494/100 424/491/100 +f 428/495/315 429/496/315 430/497/315 +f 430/497/315 431/498/315 428/495/315 +f 432/499/328 433/500/328 434/501/329 +f 434/501/329 435/502/329 432/499/328 +f 436/503/312 437/497/312 438/496/312 +f 438/496/312 439/504/312 436/503/312 +f 440/505/330 441/506/330 442/507/331 +f 442/507/331 443/508/331 440/505/330 +f 444/509/100 445/510/100 446/511/100 +f 433/512/332 447/513/332 448/514/332 +f 448/514/332 434/515/332 433/512/332 +f 449/516/100 450/517/100 451/518/100 +f 452/519/100 453/520/100 451/518/100 +f 451/518/100 450/517/100 452/519/100 +f 454/521/100 455/522/100 426/493/100 +f 426/493/100 425/492/100 454/521/100 +f 456/523/333 457/524/333 433/500/328 +f 433/500/328 432/499/328 456/523/333 +f 458/525/334 459/526/334 441/506/330 +f 441/506/330 440/505/330 458/525/334 +f 433/512/335 457/527/335 460/528/335 +f 460/528/335 447/513/335 433/512/335 +f 452/519/100 444/509/100 446/511/100 +f 446/511/100 453/520/100 452/519/100 +f 461/529/102 448/530/102 424/531/102 +f 424/531/102 427/532/102 461/529/102 +f 448/530/336 447/533/336 425/534/336 +f 425/534/336 424/531/336 448/530/336 +f 447/533/337 460/535/337 454/536/337 +f 454/536/337 425/534/337 447/533/337 +f 460/535/98 462/537/98 455/538/98 +f 455/538/98 454/536/98 460/535/98 +f 462/539/338 463/540/338 426/541/338 +f 426/541/338 455/542/338 462/539/338 +f 463/540/339 461/543/339 427/544/339 +f 427/544/339 426/541/339 463/540/339 +f 462/545/100 460/528/100 457/527/100 +f 457/527/100 464/546/100 462/545/100 +f 464/547/102 457/524/102 456/523/102 +f 456/523/102 465/548/102 464/547/102 +f 435/502/98 434/501/98 466/549/98 +f 466/549/98 467/550/98 435/502/98 +f 466/551/100 434/515/100 448/514/100 +f 448/514/100 461/552/100 466/551/100 +f 430/497/315 429/496/315 468/504/315 +f 468/504/315 469/503/315 430/497/315 +f 466/553/340 461/543/340 446/554/340 +f 446/554/340 445/555/340 466/553/340 +f 461/543/341 463/540/341 453/556/341 +f 453/556/341 446/554/341 461/543/341 +f 463/540/342 462/539/342 451/557/342 +f 451/557/342 453/556/342 463/540/342 +f 462/539/343 464/558/343 449/559/343 +f 449/559/343 451/557/343 462/539/343 +f 438/496/312 437/497/312 470/498/312 +f 470/498/312 471/495/312 438/496/312 +f 442/507/344 441/506/344 452/560/344 +f 452/560/344 450/561/344 442/507/344 +f 441/506/345 459/526/345 444/562/345 +f 444/562/345 452/560/345 441/506/345 +f 467/563/318 466/553/318 429/564/318 +f 429/564/318 428/565/318 467/563/318 +f 466/553/318 445/555/318 468/566/318 +f 468/566/318 429/564/318 466/553/318 +f 445/510/100 444/509/100 469/567/100 +f 469/567/100 468/568/100 445/510/100 +f 444/562/346 459/526/346 430/569/346 +f 430/569/346 469/570/346 444/562/346 +f 459/526/347 458/525/347 431/571/347 +f 431/571/347 430/569/347 459/526/347 +f 443/508/347 442/507/347 437/572/347 +f 437/572/347 436/573/347 443/508/347 +f 442/507/346 450/561/346 470/574/346 +f 470/574/346 437/572/346 442/507/346 +f 450/517/100 449/516/100 471/575/100 +f 471/575/100 470/576/100 450/517/100 +f 449/559/318 464/558/318 438/577/318 +f 438/577/318 471/578/318 449/559/318 +f 464/558/318 465/579/318 439/580/318 +f 439/580/318 438/577/318 464/558/318 +f 472/491/100 473/492/100 474/493/100 +f 474/493/100 475/494/100 472/491/100 +f 476/495/315 477/496/315 478/497/315 +f 478/497/315 479/498/315 476/495/315 +f 480/499/328 481/500/328 482/501/329 +f 482/501/329 483/502/329 480/499/328 +f 484/503/312 485/497/312 486/496/312 +f 486/496/312 487/504/312 484/503/312 +f 488/505/330 489/506/330 490/507/331 +f 490/507/331 491/508/331 488/505/330 +f 492/509/100 493/510/100 494/511/100 +f 481/512/332 495/513/332 496/514/332 +f 496/514/332 482/515/332 481/512/332 +f 497/516/100 498/517/100 499/518/100 +f 500/519/100 501/520/100 499/518/100 +f 499/518/100 498/517/100 500/519/100 +f 502/521/100 503/522/100 474/493/100 +f 474/493/100 473/492/100 502/521/100 +f 504/523/348 505/524/348 481/500/328 +f 481/500/328 480/499/328 504/523/348 +f 506/525/334 507/526/334 489/506/330 +f 489/506/330 488/505/330 506/525/334 +f 481/512/335 505/527/335 508/528/335 +f 508/528/335 495/513/335 481/512/335 +f 500/519/100 492/509/100 494/511/100 +f 494/511/100 501/520/100 500/519/100 +f 509/529/102 496/530/102 472/531/102 +f 472/531/102 475/532/102 509/529/102 +f 496/530/336 495/533/336 473/534/336 +f 473/534/336 472/531/336 496/530/336 +f 495/533/337 508/535/337 502/536/337 +f 502/536/337 473/534/337 495/533/337 +f 508/535/98 510/537/98 503/538/98 +f 503/538/98 502/536/98 508/535/98 +f 510/539/349 511/540/349 474/541/349 +f 474/541/349 503/542/349 510/539/349 +f 511/540/350 509/543/350 475/544/350 +f 475/544/350 474/541/350 511/540/350 +f 510/545/100 508/528/100 505/527/100 +f 505/527/100 512/546/100 510/545/100 +f 512/547/102 505/524/102 504/523/102 +f 504/523/102 513/548/102 512/547/102 +f 483/502/98 482/501/98 514/549/98 +f 514/549/98 515/550/98 483/502/98 +f 514/551/100 482/515/100 496/514/100 +f 496/514/100 509/552/100 514/551/100 +f 478/497/315 477/496/315 516/504/315 +f 516/504/315 517/503/315 478/497/315 +f 514/553/351 509/543/351 494/554/351 +f 494/554/351 493/555/351 514/553/351 +f 509/543/352 511/540/352 501/556/352 +f 501/556/352 494/554/352 509/543/352 +f 511/540/353 510/539/353 499/557/353 +f 499/557/353 501/556/353 511/540/353 +f 510/539/354 512/558/354 497/559/354 +f 497/559/354 499/557/354 510/539/354 +f 486/496/312 485/497/312 518/498/312 +f 518/498/312 519/495/312 486/496/312 +f 490/507/344 489/506/344 500/560/344 +f 500/560/344 498/561/344 490/507/344 +f 489/506/345 507/526/345 492/562/345 +f 492/562/345 500/560/345 489/506/345 +f 515/563/355 514/553/355 477/564/355 +f 477/564/355 476/565/355 515/563/355 +f 514/553/355 493/555/355 516/566/355 +f 516/566/355 477/564/355 514/553/355 +f 493/510/100 492/509/100 517/567/100 +f 517/567/100 516/568/100 493/510/100 +f 492/562/346 507/526/346 478/569/346 +f 478/569/346 517/570/346 492/562/346 +f 507/526/347 506/525/347 479/571/347 +f 479/571/347 478/569/347 507/526/347 +f 491/508/356 490/507/356 485/572/356 +f 485/572/356 484/573/356 491/508/356 +f 490/507/357 498/561/357 518/574/357 +f 518/574/357 485/572/357 490/507/357 +f 498/517/100 497/516/100 519/575/100 +f 519/575/100 518/576/100 498/517/100 +f 497/559/318 512/558/318 486/577/318 +f 486/577/318 519/578/318 497/559/318 +f 512/558/318 513/579/318 487/580/318 +f 487/580/318 486/577/318 512/558/318 +f 520/581/358 521/582/358 522/583/359 +f 522/583/359 523/584/359 520/581/358 +f 524/585/360 525/586/360 526/587/360 +f 523/584/359 522/583/359 527/588/361 +f 527/588/361 528/589/361 523/584/359 +f 526/587/362 525/586/362 529/590/362 +f 528/589/361 527/588/361 530/591/363 +f 530/591/363 531/592/363 528/589/361 +f 529/590/360 525/586/360 532/593/360 +f 531/592/363 530/591/363 533/594/364 +f 533/594/364 534/595/364 531/592/363 +f 532/593/315 525/586/315 535/596/315 +f 534/595/364 533/594/364 536/597/365 +f 536/597/365 537/598/366 534/595/364 +f 535/596/315 525/586/315 538/599/315 +f 537/598/366 536/597/365 539/600/367 +f 539/600/367 540/601/367 537/598/366 +f 538/599/315 525/586/315 541/602/315 +f 540/601/367 539/600/367 542/603/368 +f 542/603/368 543/604/368 540/601/367 +f 541/602/369 525/586/369 544/605/369 +f 543/604/368 542/603/368 545/606/370 +f 545/606/370 546/607/370 543/604/368 +f 544/605/371 525/586/371 547/608/371 +f 546/607/370 545/606/370 521/609/358 +f 521/609/358 520/610/358 546/607/370 +f 547/608/311 525/586/311 524/585/311 +f 522/611/315 521/612/315 548/585/315 +f 548/585/315 549/587/315 522/611/315 +f 521/612/315 545/613/315 550/608/315 +f 550/608/315 548/585/315 521/612/315 +f 545/613/315 542/614/315 551/605/315 +f 551/605/315 550/608/315 545/613/315 +f 542/614/311 539/615/311 552/602/311 +f 552/602/311 551/605/311 542/614/311 +f 539/615/315 536/616/315 553/599/315 +f 553/599/315 552/602/315 539/615/315 +f 536/616/315 533/617/315 554/596/315 +f 554/596/315 553/599/315 536/616/315 +f 533/617/315 530/618/315 555/593/315 +f 555/593/315 554/596/315 533/617/315 +f 530/618/360 527/619/360 556/590/360 +f 556/590/360 555/593/360 530/618/360 +f 527/619/315 522/611/315 549/587/315 +f 549/587/315 556/590/315 527/619/315 +f 549/620/372 548/621/372 524/622/372 +f 524/622/372 526/623/372 549/620/372 +f 548/621/373 550/624/373 547/625/373 +f 547/625/373 524/622/373 548/621/373 +f 550/624/363 551/626/363 544/627/363 +f 544/627/363 547/625/363 550/624/363 +f 551/626/361 552/628/361 541/629/361 +f 541/629/361 544/627/361 551/626/361 +f 552/628/374 553/630/374 538/631/374 +f 538/631/374 541/629/374 552/628/374 +f 553/630/318 554/632/318 535/633/318 +f 535/633/318 538/631/318 553/630/318 +f 554/632/375 555/634/375 532/635/375 +f 532/635/375 535/633/375 554/632/375 +f 555/634/376 556/636/376 529/637/376 +f 529/637/376 532/635/376 555/634/376 +f 556/638/377 549/620/377 526/623/377 +f 526/623/377 529/639/377 556/638/377 +f 557/493/99 558/492/99 559/491/99 +f 559/491/99 560/494/99 557/493/99 +f 561/497/98 562/496/98 563/495/98 +f 563/495/98 564/498/98 561/497/98 +f 565/501/329 566/500/328 567/499/328 +f 567/499/328 568/502/329 565/501/329 +f 569/496/312 570/497/312 571/503/312 +f 571/503/312 572/504/312 569/496/312 +f 573/507/378 574/506/379 575/505/379 +f 575/505/379 576/508/378 573/507/378 +f 577/509/99 578/511/99 579/510/99 +f 580/514/380 581/513/380 566/512/380 +f 566/512/380 565/515/380 580/514/380 +f 582/516/99 583/518/99 584/517/99 +f 583/518/99 585/520/99 586/519/99 +f 586/519/99 584/517/99 583/518/99 +f 557/493/99 587/522/99 588/521/99 +f 588/521/99 558/492/99 557/493/99 +f 566/500/328 589/524/333 590/523/333 +f 590/523/333 567/499/328 566/500/328 +f 574/506/379 591/526/381 592/525/381 +f 592/525/381 575/505/379 574/506/379 +f 566/512/382 581/513/382 593/528/382 +f 593/528/382 589/527/382 566/512/382 +f 586/519/99 585/520/99 578/511/99 +f 578/511/99 577/509/99 586/519/99 +f 594/529/102 560/532/102 559/531/102 +f 559/531/102 580/530/102 594/529/102 +f 580/530/336 559/531/336 558/534/336 +f 558/534/336 581/533/336 580/530/336 +f 581/533/383 558/534/383 588/536/383 +f 588/536/383 593/535/383 581/533/383 +f 593/535/98 588/536/98 587/538/98 +f 587/538/98 595/537/98 593/535/98 +f 595/539/384 587/542/384 557/541/384 +f 557/541/384 596/540/384 595/539/384 +f 596/540/385 557/541/385 560/544/385 +f 560/544/385 594/543/385 596/540/385 +f 595/545/99 597/546/99 589/527/99 +f 589/527/99 593/528/99 595/545/99 +f 597/547/102 598/548/102 590/523/102 +f 590/523/102 589/524/102 597/547/102 +f 599/549/98 565/501/98 568/502/98 +f 568/502/98 600/550/98 599/549/98 +f 599/551/99 594/552/99 580/514/99 +f 580/514/99 565/515/99 599/551/99 +f 561/497/98 601/503/98 602/504/98 +f 602/504/98 562/496/98 561/497/98 +f 599/553/386 579/555/386 578/554/386 +f 578/554/386 594/543/386 599/553/386 +f 594/543/387 578/554/387 585/556/387 +f 585/556/387 596/540/387 594/543/387 +f 596/540/338 585/556/338 583/557/338 +f 583/557/338 595/539/338 596/540/338 +f 595/539/343 583/557/343 582/559/343 +f 582/559/343 597/558/343 595/539/343 +f 569/496/312 603/495/312 604/498/312 +f 604/498/312 570/497/312 569/496/312 +f 573/507/344 584/561/344 586/560/344 +f 586/560/344 574/506/344 573/507/344 +f 574/506/345 586/560/345 577/562/345 +f 577/562/345 591/526/345 574/506/345 +f 600/563/318 563/565/318 562/564/318 +f 562/564/318 599/553/318 600/563/318 +f 599/553/318 562/564/318 602/566/318 +f 602/566/318 579/555/318 599/553/318 +f 579/510/99 602/568/99 601/567/99 +f 601/567/99 577/509/99 579/510/99 +f 577/562/346 601/570/346 561/569/346 +f 561/569/346 591/526/346 577/562/346 +f 591/526/388 561/569/388 564/571/388 +f 564/571/388 592/525/388 591/526/388 +f 576/508/388 571/573/388 570/572/388 +f 570/572/388 573/507/388 576/508/388 +f 573/507/346 570/572/346 604/574/346 +f 604/574/346 584/561/346 573/507/346 +f 584/517/99 604/576/99 603/575/99 +f 603/575/99 582/516/99 584/517/99 +f 582/559/318 603/578/318 569/577/318 +f 569/577/318 597/558/318 582/559/318 +f 597/558/318 569/577/318 572/580/318 +f 572/580/318 598/579/318 597/558/318 +f 605/493/99 606/492/99 607/491/99 +f 607/491/99 608/494/99 605/493/99 +f 609/497/315 610/496/315 611/495/315 +f 611/495/315 612/498/315 609/497/315 +f 613/501/389 614/500/328 615/499/328 +f 615/499/328 616/502/389 613/501/389 +f 617/496/312 618/497/312 619/503/312 +f 619/503/312 620/504/312 617/496/312 +f 621/507/378 622/506/379 623/505/379 +f 623/505/379 624/508/378 621/507/378 +f 625/509/99 626/511/99 627/510/99 +f 628/514/390 629/513/390 614/512/390 +f 614/512/390 613/515/390 628/514/390 +f 630/516/99 631/518/99 632/517/99 +f 631/518/99 633/520/99 634/519/99 +f 634/519/99 632/517/99 631/518/99 +f 605/493/99 635/522/99 636/521/99 +f 636/521/99 606/492/99 605/493/99 +f 614/500/328 637/524/333 638/523/333 +f 638/523/333 615/499/328 614/500/328 +f 622/506/379 639/526/381 640/525/381 +f 640/525/381 623/505/379 622/506/379 +f 614/512/391 629/513/391 641/528/391 +f 641/528/391 637/527/391 614/512/391 +f 634/519/99 633/520/99 626/511/99 +f 626/511/99 625/509/99 634/519/99 +f 642/529/312 608/532/312 607/531/312 +f 607/531/312 628/530/312 642/529/312 +f 628/530/392 607/531/392 606/534/392 +f 606/534/392 629/533/392 628/530/392 +f 629/533/337 606/534/337 636/536/337 +f 636/536/337 641/535/337 629/533/337 +f 641/535/98 636/536/98 635/538/98 +f 635/538/98 643/537/98 641/535/98 +f 643/539/393 635/542/393 605/541/393 +f 605/541/393 644/540/393 643/539/393 +f 644/540/394 605/541/394 608/544/394 +f 608/544/394 642/543/394 644/540/394 +f 643/545/99 645/546/99 637/527/99 +f 637/527/99 641/528/99 643/545/99 +f 645/547/102 646/548/102 638/523/102 +f 638/523/102 637/524/102 645/547/102 +f 647/549/98 613/501/98 616/502/98 +f 616/502/98 648/550/98 647/549/98 +f 647/551/99 642/552/99 628/514/99 +f 628/514/99 613/515/99 647/551/99 +f 609/497/315 649/503/315 650/504/315 +f 650/504/315 610/496/315 609/497/315 +f 647/553/351 627/555/351 626/554/351 +f 626/554/351 642/543/351 647/553/351 +f 642/543/395 626/554/395 633/556/395 +f 633/556/395 644/540/395 642/543/395 +f 644/540/396 633/556/396 631/557/396 +f 631/557/396 643/539/396 644/540/396 +f 643/539/343 631/557/343 630/559/343 +f 630/559/343 645/558/343 643/539/343 +f 617/496/312 651/495/312 652/498/312 +f 652/498/312 618/497/312 617/496/312 +f 621/507/344 632/561/344 634/560/344 +f 634/560/344 622/506/344 621/507/344 +f 622/506/345 634/560/345 625/562/345 +f 625/562/345 639/526/345 622/506/345 +f 648/563/318 611/565/318 610/564/318 +f 610/564/318 647/553/318 648/563/318 +f 647/553/318 610/564/318 650/566/318 +f 650/566/318 627/555/318 647/553/318 +f 627/510/99 650/568/99 649/567/99 +f 649/567/99 625/509/99 627/510/99 +f 625/562/346 649/570/346 609/569/346 +f 609/569/346 639/526/346 625/562/346 +f 639/526/388 609/569/388 612/571/388 +f 612/571/388 640/525/388 639/526/388 +f 624/508/388 619/573/388 618/572/388 +f 618/572/388 621/507/388 624/508/388 +f 621/507/346 618/572/346 652/574/346 +f 652/574/346 632/561/346 621/507/346 +f 632/517/99 652/576/99 651/575/99 +f 651/575/99 630/516/99 632/517/99 +f 630/559/318 651/578/318 617/577/318 +f 617/577/318 645/558/318 630/559/318 +f 645/558/318 617/577/318 620/580/318 +f 620/580/318 646/579/318 645/558/318 +f 653/493/99 654/492/99 655/491/99 +f 655/491/99 656/494/99 653/493/99 +f 657/497/315 658/496/315 659/495/315 +f 659/495/315 660/498/315 657/497/315 +f 661/501/389 662/500/328 663/499/328 +f 663/499/328 664/502/389 661/501/389 +f 665/496/312 666/497/312 667/503/312 +f 667/503/312 668/504/312 665/496/312 +f 669/507/397 670/506/379 671/505/379 +f 671/505/379 672/508/397 669/507/397 +f 673/509/99 674/511/99 675/510/99 +f 676/514/380 677/513/380 662/512/380 +f 662/512/380 661/515/380 676/514/380 +f 678/516/99 679/518/99 680/517/99 +f 679/518/99 681/520/99 682/519/99 +f 682/519/99 680/517/99 679/518/99 +f 653/493/99 683/522/99 684/521/99 +f 684/521/99 654/492/99 653/493/99 +f 662/500/328 685/524/333 686/523/333 +f 686/523/333 663/499/328 662/500/328 +f 670/506/379 687/526/381 688/525/381 +f 688/525/381 671/505/379 670/506/379 +f 662/512/382 677/513/382 689/528/382 +f 689/528/382 685/527/382 662/512/382 +f 682/519/99 681/520/99 674/511/99 +f 674/511/99 673/509/99 682/519/99 +f 690/529/102 656/532/102 655/531/102 +f 655/531/102 676/530/102 690/529/102 +f 676/530/392 655/531/392 654/534/392 +f 654/534/392 677/533/392 676/530/392 +f 677/533/383 654/534/383 684/536/383 +f 684/536/383 689/535/398 677/533/383 +f 689/535/98 684/536/98 683/538/98 +f 683/538/98 691/537/98 689/535/98 +f 691/539/399 683/542/399 653/541/399 +f 653/541/399 692/540/399 691/539/399 +f 692/540/400 653/541/400 656/544/400 +f 656/544/400 690/543/400 692/540/400 +f 691/545/99 693/546/99 685/527/99 +f 685/527/99 689/528/99 691/545/99 +f 693/547/102 694/548/102 686/523/102 +f 686/523/102 685/524/102 693/547/102 +f 695/549/98 661/501/98 664/502/98 +f 664/502/98 696/550/98 695/549/98 +f 695/551/99 690/552/99 676/514/99 +f 676/514/99 661/515/99 695/551/99 +f 657/497/315 697/503/315 698/504/315 +f 698/504/315 658/496/315 657/497/315 +f 695/553/401 675/555/401 674/554/401 +f 674/554/401 690/543/401 695/553/401 +f 690/543/402 674/554/402 681/556/402 +f 681/556/402 692/540/402 690/543/402 +f 692/540/403 681/556/403 679/557/403 +f 679/557/403 691/539/403 692/540/403 +f 691/539/354 679/557/354 678/559/354 +f 678/559/354 693/558/354 691/539/354 +f 665/496/312 699/495/312 700/498/312 +f 700/498/312 666/497/312 665/496/312 +f 669/507/344 680/561/344 682/560/344 +f 682/560/344 670/506/344 669/507/344 +f 670/506/345 682/560/345 673/562/345 +f 673/562/345 687/526/345 670/506/345 +f 696/563/355 659/565/355 658/564/355 +f 658/564/355 695/553/355 696/563/355 +f 695/553/355 658/564/355 698/566/355 +f 698/566/355 675/555/355 695/553/355 +f 675/510/99 698/568/99 697/567/99 +f 697/567/99 673/509/99 675/510/99 +f 673/562/346 697/570/346 657/569/346 +f 657/569/346 687/526/346 673/562/346 +f 687/526/388 657/569/388 660/571/388 +f 660/571/388 688/525/388 687/526/388 +f 672/508/404 667/573/404 666/572/404 +f 666/572/404 669/507/404 672/508/404 +f 669/507/357 666/572/357 700/574/357 +f 700/574/357 680/561/357 669/507/357 +f 680/517/99 700/576/99 699/575/99 +f 699/575/99 678/516/99 680/517/99 +f 678/559/318 699/578/318 665/577/318 +f 665/577/318 693/558/318 678/559/318 +f 693/558/318 665/577/318 668/580/318 +f 668/580/318 694/579/318 693/558/318 +f 701/493/102 702/492/102 703/491/101 +f 703/491/101 704/494/101 701/493/102 +f 705/497/99 706/496/99 707/495/99 +f 707/495/99 708/498/99 705/497/99 +f 709/501/405 710/500/358 711/499/358 +f 711/499/358 712/502/405 709/501/405 +f 713/496/100 714/497/100 715/503/100 +f 715/503/100 716/504/100 713/496/100 +f 717/507/406 718/506/206 719/505/206 +f 719/505/206 720/508/406 717/507/406 +f 721/509/312 722/511/312 723/510/312 +f 724/514/407 725/513/407 710/512/407 +f 710/512/407 709/515/407 724/514/407 +f 726/516/312 727/518/312 728/517/312 +f 727/518/312 729/520/312 730/519/312 +f 730/519/312 728/517/312 727/518/312 +f 701/493/102 731/522/102 732/521/102 +f 732/521/102 702/492/102 701/493/102 +f 710/500/358 733/524/408 734/523/408 +f 734/523/408 711/499/358 710/500/358 +f 718/506/206 735/526/409 736/525/409 +f 736/525/409 719/505/206 718/506/206 +f 710/512/410 725/513/410 737/528/410 +f 737/528/410 733/527/410 710/512/410 +f 730/519/312 729/520/312 722/511/312 +f 722/511/312 721/509/312 730/519/312 +f 738/529/100 704/532/100 703/531/100 +f 703/531/100 724/530/100 738/529/100 +f 724/530/411 703/531/411 702/534/411 +f 702/534/411 725/533/411 724/530/411 +f 725/533/412 702/534/412 732/536/412 +f 732/536/412 737/535/412 725/533/412 +f 737/535/99 732/536/99 731/538/99 +f 731/538/99 739/537/99 737/535/99 +f 739/539/413 731/542/413 701/541/413 +f 701/541/413 740/540/413 739/539/413 +f 740/540/414 701/541/414 704/544/414 +f 704/544/414 738/543/414 740/540/414 +f 739/545/101 741/546/101 733/527/101 +f 733/527/101 737/528/101 739/545/101 +f 741/547/100 742/548/100 734/523/100 +f 734/523/100 733/524/100 741/547/100 +f 743/549/99 709/501/99 712/502/99 +f 712/502/99 744/550/99 743/549/99 +f 743/551/102 738/552/102 724/514/102 +f 724/514/102 709/515/102 743/551/102 +f 705/497/99 745/503/99 746/504/99 +f 746/504/99 706/496/99 705/497/99 +f 743/553/415 723/555/415 722/554/415 +f 722/554/415 738/543/415 743/553/415 +f 738/543/416 722/554/416 729/556/416 +f 729/556/416 740/540/416 738/543/416 +f 740/540/417 729/556/417 727/557/417 +f 727/557/417 739/539/417 740/540/417 +f 739/539/418 727/557/418 726/559/418 +f 726/559/418 741/558/418 739/539/418 +f 713/496/100 747/495/100 748/498/100 +f 748/498/100 714/497/100 713/496/100 +f 717/507/419 728/561/419 730/560/419 +f 730/560/419 718/506/419 717/507/419 +f 718/506/420 730/560/420 721/562/420 +f 721/562/420 735/526/420 718/506/420 +f 744/563/355 707/565/355 706/564/355 +f 706/564/355 743/553/355 744/563/355 +f 743/553/318 706/564/318 746/566/318 +f 746/566/318 723/555/318 743/553/318 +f 723/510/312 746/568/312 745/567/312 +f 745/567/312 721/509/312 723/510/312 +f 721/562/346 745/570/346 705/569/346 +f 705/569/346 735/526/346 721/562/346 +f 735/526/421 705/569/421 708/571/421 +f 708/571/421 736/525/421 735/526/421 +f 720/508/421 715/573/421 714/572/421 +f 714/572/421 717/507/421 720/508/421 +f 717/507/346 714/572/346 748/574/346 +f 748/574/346 728/561/346 717/507/346 +f 728/517/312 748/576/312 747/575/312 +f 747/575/312 726/516/312 728/517/312 +f 726/559/318 747/578/318 713/577/318 +f 713/577/318 741/558/318 726/559/318 +f 741/558/355 713/577/355 716/580/355 +f 716/580/355 742/579/355 741/558/355 +f 749/640/422 301/347/423 300/346/423 +f 300/346/423 750/641/424 749/640/422 +f 750/640/425 300/347/426 303/346/426 +f 303/346/426 751/641/427 750/640/425 +f 751/640/428 303/347/429 302/346/429 +f 302/346/429 752/641/430 751/640/428 +f 302/347/431 301/346/431 749/641/432 +f 749/641/432 752/640/433 302/347/431 +f 288/642/277 749/643/422 750/644/424 +f 750/644/424 289/645/278 288/642/277 +f 289/645/280 750/644/425 751/643/427 +f 751/643/427 290/642/281 289/645/280 +f 290/645/283 751/644/428 752/643/430 +f 752/643/430 291/646/284 290/645/283 +f 752/644/433 749/643/432 288/642/287 +f 288/642/287 291/645/286 752/644/433 +f 753/1/1 754/2/2 755/3/3 +f 755/3/3 756/4/1 753/1/1 +f 757/5/4 758/6/5 759/7/6 +f 759/7/6 760/8/7 757/5/4 +f 761/9/8 762/10/9 754/11/10 +f 754/11/10 753/12/8 761/9/8 +f 763/13/434 764/14/13 758/15/14 +f 758/15/14 757/16/435 763/13/434 +f 765/17/16 766/18/17 762/19/18 +f 762/19/18 761/20/16 765/17/16 +f 767/21/19 768/22/20 764/23/21 +f 764/23/21 763/24/22 767/21/19 +f 756/25/23 755/26/72 766/27/71 +f 766/27/71 765/28/23 756/25/23 +f 760/29/26 759/30/27 768/31/28 +f 768/31/28 767/32/29 760/29/26 +f 757/5/4 760/8/7 755/3/3 +f 755/3/3 754/2/2 757/5/4 +f 769/33/30 770/34/31 759/7/6 +f 759/7/6 758/6/5 769/33/30 +f 763/13/434 757/16/435 754/11/10 +f 754/11/10 762/10/9 763/13/434 +f 771/35/436 769/36/33 758/15/14 +f 758/15/14 764/14/13 771/35/436 +f 767/21/19 763/24/22 762/19/18 +f 762/19/18 766/18/17 767/21/19 +f 772/37/34 771/38/35 764/23/21 +f 764/23/21 768/22/20 772/37/34 +f 760/29/26 767/32/29 766/27/71 +f 766/27/71 755/26/72 760/29/26 +f 770/39/36 772/40/37 768/31/28 +f 768/31/28 759/30/27 770/39/36 +f 773/41/38 774/42/39 770/34/31 +f 770/34/31 769/33/30 773/41/38 +f 775/43/40 773/44/41 769/36/33 +f 769/36/33 771/35/436 775/43/40 +f 776/45/42 775/46/437 771/38/35 +f 771/38/35 772/37/34 776/45/42 +f 774/47/44 776/48/45 772/40/37 +f 772/40/37 770/39/36 774/47/44 +f 777/49/438 778/50/438 774/42/39 +f 774/42/39 773/41/38 777/49/438 +f 779/51/47 777/52/47 773/44/41 +f 773/44/41 775/43/40 779/51/47 +f 780/53/439 779/54/440 775/46/437 +f 775/46/437 776/45/42 780/53/439 +f 778/55/441 780/56/441 776/48/45 +f 776/48/45 774/47/44 778/55/441 +f 781/181/150 782/184/150 783/183/442 +f 783/183/442 784/182/443 781/181/150 +f 784/182/443 783/183/442 785/186/444 +f 785/186/444 786/185/444 784/182/443 +f 782/187/445 787/190/446 788/189/447 +f 788/189/447 783/188/448 782/187/445 +f 783/188/448 788/189/447 789/192/449 +f 789/192/449 785/191/449 783/188/448 +f 787/193/159 790/196/159 791/195/450 +f 791/195/450 788/194/451 787/193/159 +f 788/194/451 791/195/450 792/198/452 +f 792/198/452 789/197/452 788/194/451 +f 790/199/453 781/202/453 784/201/454 +f 784/201/454 791/200/455 790/199/453 +f 791/200/455 784/201/454 786/204/456 +f 786/204/456 792/203/456 791/200/455 +f 793/3/50 794/2/51 795/1/52 +f 795/1/52 796/4/52 793/3/50 +f 797/7/457 798/6/458 799/5/459 +f 799/5/459 800/8/460 797/7/457 +f 794/11/57 801/10/58 802/9/59 +f 802/9/59 795/12/59 794/11/57 +f 798/15/461 803/14/462 804/13/463 +f 804/13/463 799/16/464 798/15/461 +f 801/19/64 805/18/65 806/17/66 +f 806/17/66 802/20/66 801/19/64 +f 803/23/465 807/22/466 808/21/467 +f 808/21/467 804/24/468 803/23/465 +f 805/27/71 793/26/72 796/25/73 +f 796/25/73 806/28/73 805/27/71 +f 807/31/469 797/30/470 800/29/471 +f 800/29/471 808/32/472 807/31/469 +f 793/3/50 800/8/460 799/5/459 +f 799/5/459 794/2/51 793/3/50 +f 797/7/457 809/34/473 810/33/474 +f 810/33/474 798/6/458 797/7/457 +f 794/11/57 799/16/464 804/13/463 +f 804/13/463 801/10/58 794/11/57 +f 798/15/461 810/36/475 811/35/476 +f 811/35/476 803/14/462 798/15/461 +f 801/19/64 804/24/468 808/21/467 +f 808/21/467 805/18/65 801/19/64 +f 803/23/465 811/38/477 812/37/478 +f 812/37/478 807/22/466 803/23/465 +f 805/27/71 808/32/472 800/29/471 +f 800/29/471 793/26/72 805/27/71 +f 807/31/469 812/40/479 809/39/480 +f 809/39/480 797/30/470 807/31/469 +f 809/34/473 813/42/481 814/41/482 +f 814/41/482 810/33/474 809/34/473 +f 810/36/475 814/44/88 815/43/89 +f 815/43/89 811/35/476 810/36/475 +f 811/38/477 815/46/483 816/45/484 +f 816/45/484 812/37/478 811/38/477 +f 812/40/479 816/48/92 813/47/93 +f 813/47/93 809/39/480 812/40/479 +f 813/42/481 817/50/485 818/49/485 +f 818/49/485 814/41/482 813/42/481 +f 814/44/88 818/52/95 819/51/95 +f 819/51/95 815/43/89 814/44/88 +f 815/46/483 819/54/96 820/53/96 +f 820/53/96 816/45/484 815/46/483 +f 816/48/92 820/56/97 817/55/97 +f 817/55/97 813/47/93 816/48/92 +f 821/647/100 822/648/100 823/649/100 +f 823/649/100 824/650/100 821/647/100 +f 825/651/486 826/652/486 827/653/486 +f 827/653/486 828/654/486 825/651/486 +f 829/655/297 830/656/297 827/653/487 +f 827/653/487 826/652/487 829/655/297 +f 831/652/102 832/651/102 833/654/102 +f 833/654/102 834/653/102 831/652/102 +f 835/657/346 836/658/346 833/659/346 +f 833/659/346 832/660/346 835/657/346 +f 837/661/100 838/662/100 823/649/100 +f 823/649/100 822/648/100 837/661/100 +f 831/652/488 834/653/488 830/656/297 +f 830/656/297 829/655/297 831/652/488 +f 825/663/346 828/664/346 836/658/346 +f 836/658/346 835/657/346 825/663/346 +f 828/665/100 827/666/100 839/667/100 +f 839/667/100 840/668/100 828/665/100 +f 827/666/100 830/669/100 841/670/100 +f 841/670/100 839/667/100 827/666/100 +f 830/669/100 834/671/100 842/672/100 +f 842/672/100 841/670/100 830/669/100 +f 834/671/100 833/673/100 843/674/100 +f 843/674/100 842/672/100 834/671/100 +f 833/673/100 836/675/100 844/676/100 +f 844/676/100 843/674/100 833/673/100 +f 836/675/100 828/665/100 840/668/100 +f 840/668/100 844/676/100 836/675/100 +f 840/677/312 839/678/312 821/679/312 +f 821/679/312 824/680/312 840/677/312 +f 839/678/489 841/681/489 822/682/489 +f 822/682/489 821/679/489 839/678/489 +f 841/681/490 842/678/490 837/679/490 +f 837/679/490 822/682/490 841/681/490 +f 842/678/98 843/677/98 838/680/98 +f 838/680/98 837/679/98 842/678/98 +f 843/683/318 844/684/318 823/685/318 +f 823/685/318 838/686/318 843/683/318 +f 844/684/318 840/687/318 824/688/318 +f 824/688/318 823/685/318 844/684/318 +f 845/181/491 846/182/492 847/183/493 +f 847/183/493 848/184/491 845/181/491 +f 846/182/492 849/185/494 850/186/494 +f 850/186/494 847/183/493 846/182/492 +f 848/187/495 847/188/496 851/189/497 +f 851/189/497 852/190/498 848/187/495 +f 847/188/496 850/191/499 853/192/499 +f 853/192/499 851/189/497 847/188/496 +f 852/193/500 851/194/501 854/195/502 +f 854/195/502 855/196/500 852/193/500 +f 851/194/501 853/197/503 856/198/503 +f 856/198/503 854/195/502 851/194/501 +f 855/199/504 854/200/505 846/201/506 +f 846/201/506 845/202/504 855/199/504 +f 854/200/505 856/203/507 849/204/507 +f 849/204/507 846/201/506 854/200/505 +f 857/181/508 858/182/509 859/183/510 +f 859/183/510 860/184/508 857/181/508 +f 858/182/509 861/185/511 862/186/511 +f 862/186/511 859/183/510 858/182/509 +f 860/187/512 859/188/513 863/189/514 +f 863/189/514 864/190/512 860/187/512 +f 859/188/513 862/191/515 865/192/515 +f 865/192/515 863/189/514 859/188/513 +f 864/193/516 863/194/517 866/195/518 +f 866/195/518 867/196/516 864/193/516 +f 863/194/517 865/197/519 868/198/519 +f 868/198/519 866/195/518 863/194/517 +f 867/199/520 866/200/521 858/201/522 +f 858/201/522 857/202/520 867/199/520 +f 866/200/521 868/203/523 861/204/523 +f 861/204/523 858/201/522 866/200/521 +f 869/689/524 870/690/524 871/691/524 +f 871/691/524 872/692/524 869/689/524 +f 873/693/525 872/694/525 871/691/525 +f 871/691/525 874/695/525 873/693/525 +f 870/690/526 875/696/526 874/695/526 +f 874/695/526 871/691/526 870/690/526 +f 869/697/527 876/698/527 875/696/527 +f 875/696/527 870/690/527 869/697/527 +f 873/693/528 874/695/528 877/699/528 +f 877/699/528 878/700/528 873/693/528 +f 879/701/529 877/699/529 874/695/529 +f 874/695/529 875/696/529 879/701/529 +f 880/702/530 879/701/530 875/696/530 +f 875/696/530 876/698/530 880/702/530 +f 881/703/311 882/704/311 883/705/311 +f 883/705/311 884/706/311 881/703/311 +f 885/707/531 886/708/531 884/706/531 +f 884/706/531 883/705/531 885/707/531 +f 886/708/532 887/709/532 881/710/532 +f 881/710/532 884/706/532 886/708/532 +f 888/711/533 878/712/533 877/699/533 +f 877/699/533 885/707/533 888/711/533 +f 879/701/534 886/708/534 885/707/534 +f 885/707/534 877/699/534 879/701/534 +f 880/713/535 887/709/535 886/708/535 +f 886/708/535 879/701/535 880/713/535 +f 889/689/536 890/690/536 891/691/536 +f 891/691/536 892/692/536 889/689/536 +f 893/693/537 892/694/537 891/691/537 +f 891/691/537 894/695/537 893/693/537 +f 890/690/538 895/696/539 894/695/538 +f 894/695/538 891/691/539 890/690/538 +f 889/697/540 896/698/541 895/696/541 +f 895/696/541 890/690/541 889/697/540 +f 893/693/542 894/695/542 897/699/542 +f 897/699/542 898/700/542 893/693/542 +f 899/701/543 897/699/543 894/695/543 +f 894/695/543 895/696/543 899/701/543 +f 900/702/544 899/701/544 895/696/544 +f 895/696/544 896/698/544 900/702/544 +f 901/703/98 902/704/98 903/705/98 +f 903/705/98 904/706/98 901/703/98 +f 903/705/545 902/714/545 905/711/545 +f 905/711/545 906/707/545 903/705/545 +f 906/707/546 907/708/546 904/706/546 +f 904/706/546 903/705/546 906/707/546 +f 907/708/547 908/709/547 901/710/547 +f 901/710/547 904/706/547 907/708/547 +f 905/711/548 898/712/548 897/699/548 +f 897/699/548 906/707/548 905/711/548 +f 899/701/549 907/708/549 906/707/549 +f 906/707/549 897/699/549 899/701/549 +f 900/713/550 908/709/550 907/708/550 +f 907/708/550 899/701/550 900/713/550 +f 909/689/536 910/690/536 911/691/536 +f 911/691/536 912/692/536 909/689/536 +f 910/690/551 913/696/551 914/695/551 +f 914/695/551 911/691/551 910/690/551 +f 909/697/552 915/698/552 913/696/552 +f 913/696/552 910/690/552 909/697/552 +f 916/701/553 917/699/553 914/695/553 +f 914/695/553 913/696/553 916/701/553 +f 918/702/554 916/701/554 913/696/554 +f 913/696/554 915/698/554 918/702/554 +f 919/703/311 920/704/311 921/705/311 +f 921/705/311 922/706/311 919/703/311 +f 923/707/546 924/708/546 922/706/546 +f 922/706/546 921/705/546 923/707/546 +f 924/708/555 925/709/555 919/710/555 +f 919/710/555 922/706/555 924/708/555 +f 916/701/556 924/708/556 923/707/556 +f 923/707/556 917/699/556 916/701/556 +f 918/713/557 925/709/557 924/708/557 +f 924/708/557 916/701/557 918/713/557 +f 926/689/536 927/690/536 928/691/536 +f 928/691/536 929/692/536 926/689/536 +f 927/690/539 930/696/539 931/695/539 +f 931/695/539 928/691/539 927/690/539 +f 926/697/541 932/698/540 930/696/540 +f 930/696/540 927/690/541 926/697/541 +f 933/701/558 934/699/558 931/695/559 +f 931/695/559 930/696/558 933/701/558 +f 935/702/560 933/701/560 930/696/560 +f 930/696/560 932/698/560 935/702/560 +f 936/703/98 937/704/98 938/705/98 +f 938/705/98 939/706/98 936/703/98 +f 940/707/561 941/708/561 939/706/561 +f 939/706/561 938/705/561 940/707/561 +f 941/708/555 942/709/555 936/710/555 +f 936/710/555 939/706/555 941/708/555 +f 933/701/562 941/708/562 940/707/562 +f 940/707/562 934/699/562 933/701/562 +f 935/713/563 942/709/563 941/708/563 +f 941/708/563 933/701/563 935/713/563 +f 943/689/536 944/690/536 945/691/536 +f 945/691/536 946/692/536 943/689/536 +f 944/690/538 947/696/538 948/695/538 +f 948/695/538 945/691/538 944/690/538 +f 943/697/552 949/698/552 947/696/552 +f 947/696/552 944/690/552 943/697/552 +f 950/701/543 951/699/543 948/695/543 +f 948/695/543 947/696/543 950/701/543 +f 952/702/564 950/701/564 947/696/564 +f 947/696/564 949/698/564 952/702/564 +f 953/703/98 954/704/98 955/705/98 +f 955/705/98 956/706/98 953/703/98 +f 957/707/546 958/708/546 956/706/546 +f 956/706/546 955/705/546 957/707/546 +f 958/708/555 959/709/555 953/710/555 +f 953/710/555 956/706/555 958/708/555 +f 950/701/549 958/708/549 957/707/549 +f 957/707/549 951/699/549 950/701/549 +f 952/713/565 959/709/565 958/708/565 +f 958/708/565 950/701/565 952/713/565 +f 960/689/524 961/690/524 962/691/524 +f 962/691/524 963/692/524 960/689/524 +f 964/693/566 963/694/566 962/691/566 +f 962/691/566 965/695/566 964/693/566 +f 961/690/567 966/696/567 965/695/567 +f 965/695/567 962/691/567 961/690/567 +f 964/693/568 965/695/569 967/699/568 +f 967/699/568 968/700/568 964/693/568 +f 969/701/570 967/699/570 965/695/570 +f 965/695/570 966/696/570 969/701/570 +f 970/703/311 971/704/311 972/705/311 +f 972/705/311 973/706/311 970/703/311 +f 972/705/571 971/714/571 974/711/571 +f 974/711/571 975/707/571 972/705/571 +f 975/707/572 976/708/572 973/706/572 +f 973/706/572 972/705/572 975/707/572 +f 974/711/573 968/712/573 967/699/573 +f 967/699/573 975/707/573 974/711/573 +f 969/701/574 976/708/574 975/707/574 +f 975/707/574 967/699/574 969/701/574 +f 977/689/575 978/690/575 979/691/575 +f 979/691/575 980/692/575 977/689/575 +f 981/693/576 980/694/576 979/691/577 +f 979/691/577 982/695/576 981/693/576 +f 978/690/578 983/696/579 982/695/579 +f 982/695/579 979/691/579 978/690/578 +f 981/693/580 982/695/580 984/699/580 +f 984/699/580 985/700/580 981/693/580 +f 986/701/581 984/699/581 982/695/582 +f 982/695/582 983/696/581 986/701/581 +f 987/703/311 988/704/311 989/705/311 +f 989/705/311 990/706/311 987/703/311 +f 989/705/583 988/714/583 991/711/583 +f 991/711/583 992/707/583 989/705/583 +f 992/707/584 993/708/584 990/706/584 +f 990/706/584 989/705/584 992/707/584 +f 991/711/585 985/712/585 984/699/585 +f 984/699/585 992/707/585 991/711/585 +f 986/701/586 993/708/586 992/707/586 +f 992/707/586 984/699/586 986/701/586 +f 994/689/524 995/690/524 996/691/524 +f 996/691/524 997/692/524 994/689/524 +f 998/693/587 997/694/587 996/691/587 +f 996/691/587 999/695/587 998/693/587 +f 995/690/588 1000/696/588 999/695/588 +f 999/695/588 996/691/588 995/690/588 +f 998/693/589 999/695/589 1001/699/589 +f 1001/699/589 1002/700/589 998/693/589 +f 1003/701/570 1001/699/570 999/695/570 +f 999/695/570 1000/696/570 1003/701/570 +f 1004/703/311 1005/704/311 1006/705/311 +f 1006/705/311 1007/706/311 1004/703/311 +f 1006/705/590 1005/714/590 1008/711/590 +f 1008/711/590 1009/707/590 1006/705/590 +f 1009/707/591 1010/708/591 1007/706/591 +f 1007/706/591 1006/705/591 1009/707/591 +f 1008/711/592 1002/712/592 1001/699/592 +f 1001/699/592 1009/707/592 1008/711/592 +f 1003/701/586 1010/708/586 1009/707/586 +f 1009/707/586 1001/699/586 1003/701/586 +f 1011/689/593 1012/690/593 1013/691/593 +f 1013/691/593 1014/692/593 1011/689/593 +f 1015/693/594 1014/694/594 1013/691/594 +f 1013/691/594 1016/695/594 1015/693/594 +f 1012/690/595 1017/696/595 1016/695/595 +f 1016/695/595 1013/691/595 1012/690/595 +f 1011/697/596 1018/698/596 1017/696/596 +f 1017/696/596 1012/690/596 1011/697/596 +f 1015/693/597 1016/695/597 1019/699/597 +f 1019/699/597 1020/700/597 1015/693/597 +f 1021/701/598 1019/699/598 1016/695/598 +f 1016/695/598 1017/696/598 1021/701/598 +f 1022/702/599 1021/701/599 1017/696/599 +f 1017/696/599 1018/698/599 1022/702/599 +f 1023/703/99 1024/704/99 1025/705/99 +f 1025/705/99 1026/706/99 1023/703/99 +f 1025/705/600 1024/714/600 1027/711/600 +f 1027/711/600 1028/707/600 1025/705/600 +f 1028/707/601 1029/708/601 1026/706/601 +f 1026/706/601 1025/705/601 1028/707/601 +f 1029/708/602 1030/709/602 1023/710/602 +f 1023/710/602 1026/706/602 1029/708/602 +f 1027/711/603 1020/712/603 1019/699/603 +f 1019/699/603 1028/707/603 1027/711/603 +f 1021/701/604 1029/708/604 1028/707/604 +f 1028/707/604 1019/699/604 1021/701/604 +f 1022/713/605 1030/709/605 1029/708/605 +f 1029/708/605 1021/701/605 1022/713/605 +f 1031/715/100 1032/716/100 1033/717/100 +f 1033/717/100 1034/718/100 1031/715/100 +f 1035/719/606 1036/720/606 1034/718/606 +f 1034/718/606 1033/717/606 1035/719/606 +f 1036/720/607 1037/721/607 1031/722/607 +f 1031/722/607 1034/718/607 1036/720/607 +f 1038/723/608 1036/720/608 1035/719/608 +f 1035/719/608 1039/724/608 1038/723/608 +f 1040/725/609 1037/726/609 1036/720/609 +f 1036/720/609 1038/723/609 1040/725/609 +f 1041/727/99 1042/728/99 1043/729/99 +f 1043/729/99 1044/730/99 1041/727/99 +f 1042/728/610 1045/731/610 1046/732/610 +f 1046/732/610 1043/729/610 1042/728/610 +f 1041/733/611 1047/734/611 1045/731/611 +f 1045/731/611 1042/728/611 1041/733/611 +f 1038/723/612 1039/724/612 1046/732/612 +f 1046/732/612 1045/731/612 1038/723/612 +f 1040/725/613 1038/723/613 1045/731/613 +f 1045/731/613 1047/735/613 1040/725/613 +f 1048/715/100 1049/716/100 1050/717/100 +f 1050/717/100 1051/718/100 1048/715/100 +f 1052/719/614 1053/720/614 1051/718/614 +f 1051/718/614 1050/717/614 1052/719/614 +f 1053/720/615 1054/721/615 1048/722/615 +f 1048/722/615 1051/718/615 1053/720/615 +f 1055/723/616 1053/720/616 1052/719/616 +f 1052/719/616 1056/724/616 1055/723/616 +f 1057/725/617 1054/726/617 1053/720/617 +f 1053/720/617 1055/723/617 1057/725/617 +f 1058/727/99 1059/728/99 1060/729/99 +f 1060/729/99 1061/730/99 1058/727/99 +f 1059/728/618 1062/731/618 1063/732/618 +f 1063/732/618 1060/729/618 1059/728/618 +f 1058/733/619 1064/734/619 1062/731/619 +f 1062/731/619 1059/728/619 1058/733/619 +f 1055/723/620 1056/724/620 1063/732/620 +f 1063/732/620 1062/731/620 1055/723/620 +f 1057/725/621 1055/723/621 1062/731/621 +f 1062/731/621 1064/735/621 1057/725/621 +f 1065/715/100 1066/716/100 1067/717/100 +f 1067/717/100 1068/718/100 1065/715/100 +f 1069/719/622 1070/720/622 1068/718/622 +f 1068/718/622 1067/717/622 1069/719/622 +f 1070/720/623 1071/721/623 1065/722/624 +f 1065/722/624 1068/718/623 1070/720/623 +f 1072/723/625 1070/720/625 1069/719/625 +f 1069/719/625 1073/724/625 1072/723/625 +f 1074/725/626 1071/726/626 1070/720/626 +f 1070/720/626 1072/723/626 1074/725/626 +f 1075/727/627 1076/728/627 1077/729/627 +f 1077/729/627 1078/730/627 1075/727/627 +f 1076/728/628 1079/731/628 1080/732/629 +f 1080/732/629 1077/729/628 1076/728/628 +f 1075/733/630 1081/734/630 1079/731/630 +f 1079/731/630 1076/728/630 1075/733/630 +f 1072/723/631 1073/724/631 1080/732/631 +f 1080/732/631 1079/731/631 1072/723/631 +f 1074/725/632 1072/723/632 1079/731/632 +f 1079/731/632 1081/735/632 1074/725/632 +f 1082/715/100 1083/716/100 1084/717/100 +f 1084/717/100 1085/718/100 1082/715/100 +f 1086/719/633 1087/720/633 1085/718/633 +f 1085/718/633 1084/717/633 1086/719/633 +f 1087/720/634 1088/721/634 1082/722/634 +f 1082/722/634 1085/718/634 1087/720/634 +f 1089/723/635 1087/720/635 1086/719/635 +f 1086/719/635 1090/724/635 1089/723/635 +f 1091/725/636 1088/726/636 1087/720/636 +f 1087/720/636 1089/723/636 1091/725/636 +f 1092/727/637 1093/728/637 1094/729/637 +f 1094/729/637 1095/730/637 1092/727/637 +f 1093/728/638 1096/731/638 1097/732/638 +f 1097/732/638 1094/729/638 1093/728/638 +f 1092/733/639 1098/734/639 1096/731/639 +f 1096/731/639 1093/728/639 1092/733/639 +f 1089/723/640 1090/724/640 1097/732/640 +f 1097/732/640 1096/731/640 1089/723/640 +f 1091/725/641 1089/723/641 1096/731/641 +f 1096/731/641 1098/735/641 1091/725/641 +f 1099/715/100 1100/716/100 1101/717/100 +f 1101/717/100 1102/718/100 1099/715/100 +f 1103/719/642 1104/720/642 1102/718/642 +f 1102/718/642 1101/717/642 1103/719/642 +f 1104/720/643 1105/721/643 1099/722/643 +f 1099/722/643 1102/718/643 1104/720/643 +f 1106/723/644 1104/720/644 1103/719/644 +f 1103/719/644 1107/724/644 1106/723/644 +f 1108/725/645 1105/726/645 1104/720/645 +f 1104/720/645 1106/723/645 1108/725/645 +f 1109/727/99 1110/728/99 1111/729/99 +f 1111/729/99 1112/730/99 1109/727/99 +f 1110/728/646 1113/731/646 1114/732/646 +f 1114/732/646 1111/729/646 1110/728/646 +f 1109/733/647 1115/734/647 1113/731/647 +f 1113/731/647 1110/728/647 1109/733/647 +f 1106/723/648 1107/724/648 1114/732/648 +f 1114/732/648 1113/731/648 1106/723/648 +f 1108/725/649 1106/723/650 1113/731/649 +f 1113/731/649 1115/735/649 1108/725/649 +f 1116/715/100 1117/716/100 1118/717/100 +f 1118/717/100 1119/718/100 1116/715/100 +f 1120/719/651 1121/720/652 1119/718/651 +f 1119/718/651 1118/717/651 1120/719/651 +f 1121/720/653 1122/721/653 1116/722/653 +f 1116/722/653 1119/718/653 1121/720/653 +f 1123/723/654 1121/720/654 1120/719/654 +f 1120/719/654 1124/724/654 1123/723/654 +f 1125/725/655 1122/726/655 1121/720/655 +f 1121/720/655 1123/723/655 1125/725/655 +f 1126/727/99 1127/728/99 1128/729/99 +f 1128/729/99 1129/730/99 1126/727/99 +f 1127/728/656 1130/731/656 1131/732/656 +f 1131/732/656 1128/729/656 1127/728/656 +f 1126/733/657 1132/734/657 1130/731/657 +f 1130/731/657 1127/728/657 1126/733/657 +f 1123/723/658 1124/724/658 1131/732/658 +f 1131/732/658 1130/731/658 1123/723/658 +f 1125/725/659 1123/723/659 1130/731/659 +f 1130/731/659 1132/735/659 1125/725/659 +f 1133/715/660 1134/716/660 1135/717/660 +f 1135/717/660 1136/718/660 1133/715/660 +f 1137/719/661 1138/720/661 1136/718/661 +f 1136/718/661 1135/717/661 1137/719/661 +f 1138/720/662 1139/721/662 1133/722/662 +f 1133/722/662 1136/718/662 1138/720/662 +f 1140/723/663 1138/720/663 1137/719/663 +f 1137/719/663 1141/724/663 1140/723/663 +f 1142/725/664 1139/726/664 1138/720/664 +f 1138/720/664 1140/723/664 1142/725/664 +f 1143/727/99 1144/728/99 1145/729/99 +f 1145/729/99 1146/730/99 1143/727/99 +f 1144/728/665 1147/731/665 1148/732/665 +f 1148/732/665 1145/729/665 1144/728/665 +f 1143/733/666 1149/734/666 1147/731/666 +f 1147/731/666 1144/728/666 1143/733/666 +f 1140/723/667 1141/724/667 1148/732/667 +f 1148/732/667 1147/731/667 1140/723/667 +f 1142/725/668 1140/723/668 1147/731/668 +f 1147/731/668 1149/735/668 1142/725/668 +f 1150/715/100 1151/716/100 1152/717/100 +f 1152/717/100 1153/718/100 1150/715/100 +f 1154/719/669 1155/720/669 1153/718/669 +f 1153/718/669 1152/717/669 1154/719/669 +f 1155/720/670 1156/721/670 1150/722/670 +f 1150/722/670 1153/718/670 1155/720/670 +f 1157/723/671 1155/720/671 1154/719/671 +f 1154/719/671 1158/724/671 1157/723/671 +f 1159/725/672 1156/726/672 1155/720/672 +f 1155/720/672 1157/723/672 1159/725/672 +f 1160/727/99 1161/728/99 1162/729/99 +f 1162/729/99 1163/730/99 1160/727/99 +f 1161/728/673 1164/731/673 1165/732/673 +f 1165/732/673 1162/729/673 1161/728/673 +f 1160/733/674 1166/734/674 1164/731/674 +f 1164/731/674 1161/728/674 1160/733/674 +f 1157/723/675 1158/724/675 1165/732/675 +f 1165/732/675 1164/731/675 1157/723/675 +f 1159/725/676 1157/723/676 1164/731/676 +f 1164/731/676 1166/735/676 1159/725/676 +f 1167/715/100 1168/716/100 1169/717/100 +f 1169/717/100 1170/718/100 1167/715/100 +f 1171/719/677 1172/720/677 1170/718/678 +f 1170/718/678 1169/717/677 1171/719/677 +f 1172/720/679 1173/721/679 1167/722/679 +f 1167/722/679 1170/718/679 1172/720/679 +f 1174/723/680 1172/720/680 1171/719/680 +f 1171/719/680 1175/724/680 1174/723/680 +f 1176/725/681 1173/726/681 1172/720/681 +f 1172/720/681 1174/723/681 1176/725/681 +f 1177/727/99 1178/728/99 1179/729/99 +f 1179/729/99 1180/730/99 1177/727/99 +f 1178/728/665 1181/731/665 1182/732/665 +f 1182/732/665 1179/729/665 1178/728/665 +f 1177/733/682 1183/734/682 1181/731/682 +f 1181/731/682 1178/728/682 1177/733/682 +f 1174/723/683 1175/724/683 1182/732/683 +f 1182/732/683 1181/731/683 1174/723/683 +f 1176/725/684 1174/723/684 1181/731/684 +f 1181/731/684 1183/735/684 1176/725/684 +f 1184/689/685 1185/692/685 1186/691/685 +f 1186/691/685 1187/690/685 1184/689/685 +f 1188/693/686 1189/695/686 1186/691/686 +f 1186/691/686 1185/694/686 1188/693/686 +f 1187/690/687 1186/691/687 1189/695/687 +f 1189/695/687 1190/696/687 1187/690/687 +f 1184/697/688 1187/690/688 1190/696/688 +f 1190/696/688 1191/698/688 1184/697/688 +f 1188/693/689 1192/700/689 1193/699/689 +f 1193/699/689 1189/695/689 1188/693/689 +f 1194/701/690 1190/696/690 1189/695/690 +f 1189/695/690 1193/699/690 1194/701/690 +f 1195/702/691 1191/698/691 1190/696/691 +f 1190/696/691 1194/701/691 1195/702/691 +f 1196/703/99 1197/706/99 1198/705/99 +f 1198/705/99 1199/704/99 1196/703/99 +f 1198/705/692 1200/707/692 1201/711/692 +f 1201/711/692 1199/714/692 1198/705/692 +f 1200/707/693 1198/705/693 1197/706/694 +f 1197/706/694 1202/708/694 1200/707/693 +f 1202/708/695 1197/706/695 1196/710/695 +f 1196/710/695 1203/709/695 1202/708/695 +f 1201/711/696 1200/707/696 1193/699/696 +f 1193/699/696 1192/712/696 1201/711/696 +f 1194/701/697 1193/699/697 1200/707/697 +f 1200/707/697 1202/708/697 1194/701/697 +f 1195/713/698 1194/701/698 1202/708/698 +f 1202/708/698 1203/709/698 1195/713/698 +f 1204/715/100 1205/718/100 1206/717/100 +f 1206/717/100 1207/716/100 1204/715/100 +f 1208/719/699 1206/717/699 1205/718/699 +f 1205/718/699 1209/720/699 1208/719/699 +f 1209/720/700 1205/718/700 1204/722/700 +f 1204/722/700 1210/721/700 1209/720/700 +f 1211/723/701 1212/724/701 1208/719/701 +f 1208/719/701 1209/720/701 1211/723/701 +f 1213/725/702 1211/723/702 1209/720/702 +f 1209/720/702 1210/726/702 1213/725/702 +f 1214/727/99 1215/730/99 1216/729/99 +f 1216/729/99 1217/728/99 1214/727/99 +f 1217/728/703 1216/729/703 1218/732/703 +f 1218/732/703 1219/731/703 1217/728/703 +f 1214/733/704 1217/728/704 1219/731/704 +f 1219/731/704 1220/734/704 1214/733/704 +f 1211/723/705 1219/731/705 1218/732/705 +f 1218/732/705 1212/724/705 1211/723/705 +f 1213/725/706 1220/735/707 1219/731/706 +f 1219/731/706 1211/723/706 1213/725/706 +f 1221/715/100 1222/718/100 1223/717/100 +f 1223/717/100 1224/716/100 1221/715/100 +f 1225/719/708 1223/717/708 1222/718/708 +f 1222/718/708 1226/720/708 1225/719/708 +f 1226/720/709 1222/718/709 1221/722/709 +f 1221/722/709 1227/721/709 1226/720/709 +f 1228/723/710 1229/724/710 1225/719/710 +f 1225/719/710 1226/720/710 1228/723/710 +f 1230/725/711 1228/723/711 1226/720/711 +f 1226/720/711 1227/726/711 1230/725/711 +f 1231/727/99 1232/730/99 1233/729/99 +f 1233/729/99 1234/728/99 1231/727/99 +f 1234/728/712 1233/729/712 1235/732/712 +f 1235/732/712 1236/731/712 1234/728/712 +f 1231/733/713 1234/728/713 1236/731/713 +f 1236/731/713 1237/734/713 1231/733/713 +f 1228/723/714 1236/731/714 1235/732/714 +f 1235/732/714 1229/724/714 1228/723/714 +f 1230/725/715 1237/735/715 1236/731/715 +f 1236/731/715 1228/723/715 1230/725/715 +f 1238/715/100 1239/718/100 1240/717/100 +f 1240/717/100 1241/716/100 1238/715/100 +f 1242/719/716 1240/717/716 1239/718/716 +f 1239/718/716 1243/720/716 1242/719/716 +f 1243/720/717 1239/718/717 1238/722/717 +f 1238/722/717 1244/721/717 1243/720/717 +f 1245/723/718 1246/724/718 1242/719/718 +f 1242/719/718 1243/720/718 1245/723/718 +f 1247/725/719 1245/723/719 1243/720/719 +f 1243/720/719 1244/726/719 1247/725/719 +f 1248/727/720 1249/730/720 1250/729/720 +f 1250/729/720 1251/728/720 1248/727/720 +f 1251/728/721 1250/729/721 1252/732/721 +f 1252/732/721 1253/731/721 1251/728/721 +f 1248/733/722 1251/728/723 1253/731/723 +f 1253/731/723 1254/734/723 1248/733/722 +f 1245/723/724 1253/731/724 1252/732/724 +f 1252/732/724 1246/724/724 1245/723/724 +f 1247/725/725 1254/735/725 1253/731/725 +f 1253/731/725 1245/723/725 1247/725/725 +f 1255/715/100 1256/718/100 1257/717/100 +f 1257/717/100 1258/716/100 1255/715/100 +f 1259/719/726 1257/717/726 1256/718/726 +f 1256/718/726 1260/720/726 1259/719/726 +f 1260/720/727 1256/718/727 1255/722/727 +f 1255/722/727 1261/721/727 1260/720/727 +f 1262/723/728 1263/724/728 1259/719/728 +f 1259/719/728 1260/720/728 1262/723/728 +f 1264/725/729 1262/723/729 1260/720/729 +f 1260/720/729 1261/726/729 1264/725/729 +f 1265/727/99 1266/730/99 1267/729/99 +f 1267/729/99 1268/728/99 1265/727/99 +f 1268/728/730 1267/729/730 1269/732/730 +f 1269/732/730 1270/731/731 1268/728/730 +f 1265/733/732 1268/728/732 1270/731/732 +f 1270/731/732 1271/734/732 1265/733/732 +f 1262/723/733 1270/731/733 1269/732/733 +f 1269/732/733 1263/724/733 1262/723/733 +f 1264/725/734 1271/735/734 1270/731/734 +f 1270/731/734 1262/723/734 1264/725/734 +f 1272/715/100 1273/718/100 1274/717/100 +f 1274/717/100 1275/716/100 1272/715/100 +f 1276/719/735 1274/717/735 1273/718/736 +f 1273/718/736 1277/720/735 1276/719/735 +f 1277/720/737 1273/718/737 1272/722/737 +f 1272/722/737 1278/721/737 1277/720/737 +f 1279/723/738 1280/724/738 1276/719/738 +f 1276/719/738 1277/720/738 1279/723/738 +f 1281/725/739 1279/723/740 1277/720/740 +f 1277/720/740 1278/726/739 1281/725/739 +f 1282/727/720 1283/730/720 1284/729/720 +f 1284/729/720 1285/728/720 1282/727/720 +f 1285/728/741 1284/729/741 1286/732/741 +f 1286/732/741 1287/731/741 1285/728/741 +f 1282/733/742 1285/728/742 1287/731/742 +f 1287/731/742 1288/734/742 1282/733/742 +f 1279/723/743 1287/731/743 1286/732/743 +f 1286/732/743 1280/724/743 1279/723/743 +f 1281/725/744 1288/735/745 1287/731/744 +f 1287/731/744 1279/723/744 1281/725/744 +f 1289/715/100 1290/718/100 1291/717/100 +f 1291/717/100 1292/716/100 1289/715/100 +f 1293/719/746 1291/717/746 1290/718/746 +f 1290/718/746 1294/720/746 1293/719/746 +f 1294/720/747 1290/718/747 1289/722/747 +f 1289/722/747 1295/721/747 1294/720/747 +f 1296/723/748 1297/724/748 1293/719/748 +f 1293/719/748 1294/720/748 1296/723/748 +f 1298/725/749 1296/723/749 1294/720/749 +f 1294/720/749 1295/726/749 1298/725/749 +f 1299/727/750 1300/730/750 1301/729/750 +f 1301/729/750 1302/728/750 1299/727/750 +f 1302/728/751 1301/729/751 1303/732/751 +f 1303/732/751 1304/731/751 1302/728/751 +f 1299/733/752 1302/728/752 1304/731/752 +f 1304/731/752 1305/734/752 1299/733/752 +f 1296/723/753 1304/731/753 1303/732/753 +f 1303/732/753 1297/724/753 1296/723/753 +f 1298/725/754 1305/735/754 1304/731/754 +f 1304/731/754 1296/723/754 1298/725/754 +f 1306/715/100 1307/718/100 1308/717/100 +f 1308/717/100 1309/716/100 1306/715/100 +f 1310/719/755 1308/717/755 1307/718/755 +f 1307/718/755 1311/720/755 1310/719/755 +f 1311/720/756 1307/718/756 1306/722/756 +f 1306/722/756 1312/721/756 1311/720/756 +f 1313/723/757 1314/724/757 1310/719/757 +f 1310/719/757 1311/720/757 1313/723/757 +f 1315/725/758 1313/723/758 1311/720/758 +f 1311/720/758 1312/726/758 1315/725/758 +f 1316/727/99 1317/730/99 1318/729/99 +f 1318/729/99 1319/728/99 1316/727/99 +f 1319/728/759 1318/729/759 1320/732/759 +f 1320/732/759 1321/731/759 1319/728/759 +f 1316/733/760 1319/728/760 1321/731/760 +f 1321/731/760 1322/734/760 1316/733/760 +f 1313/723/761 1321/731/761 1320/732/761 +f 1320/732/761 1314/724/761 1313/723/761 +f 1315/725/762 1322/735/762 1321/731/762 +f 1321/731/762 1313/723/762 1315/725/762 +f 1323/715/100 1324/718/100 1325/717/100 +f 1325/717/100 1326/716/100 1323/715/100 +f 1327/719/755 1325/717/755 1324/718/755 +f 1324/718/755 1328/720/755 1327/719/755 +f 1328/720/763 1324/718/763 1323/722/763 +f 1323/722/763 1329/721/763 1328/720/763 +f 1330/723/764 1331/724/764 1327/719/764 +f 1327/719/764 1328/720/764 1330/723/764 +f 1332/725/765 1330/723/765 1328/720/765 +f 1328/720/765 1329/726/765 1332/725/765 +f 1333/727/99 1334/730/99 1335/729/99 +f 1335/729/99 1336/728/99 1333/727/99 +f 1336/728/766 1335/729/766 1337/732/766 +f 1337/732/766 1338/731/766 1336/728/766 +f 1333/733/767 1336/728/767 1338/731/767 +f 1338/731/767 1339/734/767 1333/733/767 +f 1330/723/768 1338/731/768 1337/732/768 +f 1337/732/768 1331/724/768 1330/723/768 +f 1332/725/769 1339/735/769 1338/731/769 +f 1338/731/769 1330/723/769 1332/725/769 +f 1340/715/770 1341/718/770 1342/717/770 +f 1342/717/770 1343/716/770 1340/715/770 +f 1344/719/771 1342/717/771 1341/718/771 +f 1341/718/771 1345/720/771 1344/719/771 +f 1345/720/772 1341/718/773 1340/722/772 +f 1340/722/772 1346/721/773 1345/720/772 +f 1347/723/774 1348/724/774 1344/719/774 +f 1344/719/774 1345/720/774 1347/723/774 +f 1349/725/775 1347/723/775 1345/720/775 +f 1345/720/775 1346/726/775 1349/725/775 +f 1350/727/99 1351/730/99 1352/729/99 +f 1352/729/99 1353/728/99 1350/727/99 +f 1353/728/703 1352/729/703 1354/732/703 +f 1354/732/703 1355/731/776 1353/728/703 +f 1350/733/777 1353/728/777 1355/731/777 +f 1355/731/777 1356/734/777 1350/733/777 +f 1347/723/778 1355/731/778 1354/732/778 +f 1354/732/778 1348/724/778 1347/723/778 +f 1349/725/779 1356/735/779 1355/731/779 +f 1355/731/779 1347/723/779 1349/725/779 +f 1357/736/780 212/737/780 1358/738/780 +f 1358/738/780 1359/739/780 1357/736/780 +f 1360/736/192 1361/737/192 212/738/192 +f 212/738/192 1357/739/192 1360/736/192 +f 1362/740/781 1363/741/782 1361/742/782 +f 1361/742/782 1360/743/781 1362/740/781 +f 1359/744/175 1358/745/175 1363/746/175 +f 1363/746/175 1362/747/175 1359/744/175 +f 1364/744/216 1365/745/216 1366/748/216 +f 1366/748/216 1367/747/216 1364/744/216 +f 1368/736/783 206/737/783 1365/738/783 +f 1365/738/783 1364/739/783 1368/736/783 +f 1369/736/784 1370/737/784 206/738/784 +f 206/738/784 1368/739/784 1369/736/784 +f 1367/740/175 1366/741/175 1370/742/175 +f 1370/742/175 1369/743/175 1367/740/175 +f 1371/740/180 1372/741/180 1373/742/180 +f 1373/742/180 1374/743/180 1371/740/180 +f 1375/743/783 1376/742/785 1372/741/785 +f 1372/741/785 1371/740/783 1375/743/783 +f 1377/736/786 202/737/786 1376/738/786 +f 1376/738/786 1375/739/786 1377/736/786 +f 1374/736/787 1373/737/787 202/738/787 +f 202/738/787 1377/739/787 1374/736/787 +f 1378/736/180 1379/737/180 232/738/180 +f 232/738/180 1380/739/180 1378/736/180 +f 1381/747/783 1382/748/783 1379/745/783 +f 1379/745/783 1378/744/783 1381/747/783 +f 1383/744/788 1384/745/784 1382/748/784 +f 1382/748/784 1381/747/788 1383/744/788 +f 1380/736/789 232/737/789 1384/738/789 +f 1384/738/789 1383/739/789 1380/736/789 +f 1385/749/181 1386/750/181 1361/742/782 +f 1361/742/782 1363/741/782 1385/749/181 +f 1387/751/175 1385/752/175 1363/746/175 +f 1363/746/175 1358/745/175 1387/751/175 +f 1388/751/216 1389/752/216 1366/748/216 +f 1366/748/216 1365/745/216 1388/751/216 +f 1389/749/175 1390/750/175 1370/742/175 +f 1370/742/175 1366/741/175 1389/749/175 +f 1391/749/180 1392/750/180 1373/742/180 +f 1373/742/180 1372/741/180 1391/749/180 +f 1393/750/785 1391/749/785 1372/741/785 +f 1372/741/785 1376/742/785 1393/750/785 +f 1394/752/783 1395/751/783 1379/745/783 +f 1379/745/783 1382/748/783 1394/752/783 +f 1396/751/790 1394/752/790 1382/748/784 +f 1382/748/784 1384/745/784 1396/751/790 +f 1388/751/219 1365/745/219 1397/753/219 +f 1397/753/219 1398/754/219 1388/751/219 +f 1390/750/217 1399/755/217 1400/756/217 +f 1400/756/217 1370/742/217 1390/750/217 +f 1395/751/791 1401/754/792 1402/753/792 +f 1402/753/792 1379/745/791 1395/751/791 +f 1396/751/181 1384/745/181 1403/753/793 +f 1403/753/793 1404/754/794 1396/751/181 +f 1405/754/217 1406/753/217 1407/757/217 +f 1407/757/217 1408/758/217 1405/754/217 +f 1409/755/795 1410/756/795 1411/757/796 +f 1411/757/796 1412/758/796 1409/755/795 +f 1413/757/220 1414/756/797 1415/755/797 +f 1415/755/797 1416/758/220 1413/757/220 +f 1417/757/798 1418/756/799 1419/755/800 +f 1419/755/800 1420/758/801 1417/757/798 +f 1413/757/220 1416/758/220 1398/754/219 +f 1398/754/219 1397/753/219 1413/757/220 +f 1399/755/217 1408/758/217 1407/757/217 +f 1407/757/217 1400/756/217 1399/755/217 +f 1401/754/792 1412/758/796 1411/757/796 +f 1411/757/796 1402/753/792 1401/754/792 +f 1417/757/798 1420/758/801 1404/754/794 +f 1404/754/794 1403/753/793 1417/757/798 +f 1387/751/217 1358/745/217 1406/753/217 +f 1406/753/217 1405/754/217 1387/751/217 +f 1393/750/795 1376/742/795 1410/756/795 +f 1410/756/795 1409/755/795 1393/750/795 +f 1414/756/797 1373/742/797 1392/750/797 +f 1392/750/797 1415/755/797 1414/756/797 +f 1418/756/799 1361/742/786 1386/750/786 +f 1386/750/786 1419/755/800 1418/756/799 +f 1421/181/802 1422/182/803 1423/183/493 +f 1423/183/493 1424/184/802 1421/181/802 +f 1422/182/803 1425/185/804 1426/186/804 +f 1426/186/804 1423/183/493 1422/182/803 +f 1424/187/805 1423/188/806 1427/189/807 +f 1427/189/807 1428/190/808 1424/187/805 +f 1423/188/806 1426/191/809 1429/192/809 +f 1429/192/809 1427/189/807 1423/188/806 +f 1428/193/500 1427/194/501 1430/195/502 +f 1430/195/502 1431/196/500 1428/193/500 +f 1427/194/501 1429/197/810 1432/198/810 +f 1432/198/810 1430/195/502 1427/194/501 +f 1431/199/504 1430/200/505 1422/201/506 +f 1422/201/506 1421/202/504 1431/199/504 +f 1430/200/505 1432/203/507 1425/204/507 +f 1425/204/507 1422/201/506 1430/200/505 +f 1433/181/508 1434/182/509 1435/183/510 +f 1435/183/510 1436/184/508 1433/181/508 +f 1434/182/509 1437/185/511 1438/186/511 +f 1438/186/511 1435/183/510 1434/182/509 +f 1436/187/811 1435/188/812 1439/189/813 +f 1439/189/813 1440/190/811 1436/187/811 +f 1435/188/812 1438/191/814 1441/192/814 +f 1441/192/814 1439/189/813 1435/188/812 +f 1440/193/516 1439/194/517 1442/195/518 +f 1442/195/518 1443/196/516 1440/193/516 +f 1439/194/517 1441/197/519 1444/198/519 +f 1444/198/519 1442/195/518 1439/194/517 +f 1443/199/815 1442/200/816 1434/201/817 +f 1434/201/817 1433/202/815 1443/199/815 +f 1442/200/816 1444/203/818 1437/204/818 +f 1437/204/818 1434/201/817 1442/200/816 +# 2079 faces + diff --git a/examples/shaders/postprocessing/church_diffuse.png b/examples/shaders/postprocessing/church_diffuse.png new file mode 100644 index 0000000..73b9fb7 Binary files /dev/null and b/examples/shaders/postprocessing/church_diffuse.png differ diff --git a/examples/shaders/postprocessing/dwarf.obj b/examples/shaders/postprocessing/dwarf.obj deleted file mode 100644 index a24f0c1..0000000 --- a/examples/shaders/postprocessing/dwarf.obj +++ /dev/null @@ -1,54966 +0,0 @@ -# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware -# File Created: 28.05.2015 21:59:00 - -mtllib Enano_Final_001.mtl - -# -# object Box001 -# - -v 0.387459278107 0.001037180424 -0.000000000000 -v 0.357966661453 0.000561296940 -0.148274183273 -v 0.273977041245 0.000000000000 -0.273975044489 -v 0.148276805878 -0.000561356544 -0.357965648174 -v 0.000002622604 -0.001037240028 -0.387459248304 -v -0.148271799088 -0.001355171204 -0.357965648174 -v -0.273973226547 -0.001466870308 -0.273975044489 -v -0.357964754105 -0.001355171204 -0.148274242878 -v -0.387459278107 -0.001037240028 -0.000000059605 -v -0.357966899872 -0.000561356544 0.148274183273 -v -0.273977279663 -0.000000059605 0.273975014687 -v -0.148276805878 0.000561296940 0.357965707779 -v -0.000002861023 0.001037180424 0.387459278107 -v 0.148271799088 0.001355111599 0.357965588570 -v 0.273973226547 0.001466810703 0.273974895477 -v 0.357964634895 0.001355111599 0.148274123669 -v 0.387031078339 0.161010622978 -0.000428199768 -v 0.357538461685 0.160534739494 -0.148702442646 -v 0.273548841476 0.159973442554 -0.274403274059 -v 0.147848606110 0.159412086010 -0.358393877745 -v -0.000425577164 0.158936202526 -0.387887477875 -v -0.148699998856 0.158618271351 -0.358393877745 -v -0.274401426315 0.158506572247 -0.274403274059 -v -0.358391761780 0.158147990704 -0.148701190948 -v -0.387881040573 0.156506061554 -0.000421762466 -v -0.358393907547 0.158941805363 0.147847235203 -v -0.274405479431 0.159973382950 0.273546814919 -v -0.148705244064 0.160534739494 0.357537508011 -v -0.000431060791 0.161010622978 0.387031078339 -v 0.147843360901 0.161328554153 0.357537388802 -v 0.273545026779 0.161440253258 0.273546695709 -v 0.357536435127 0.161328554153 0.147845864296 -v 0.353100299835 0.160919785500 -0.000428199768 -v 0.326190590858 0.160485565662 -0.135717749596 -v 0.249556064606 0.159973442554 -0.250410705805 -v 0.134863615036 0.159461259842 -0.327046126127 -v -0.000425815582 0.159027040005 -0.353956878185 -v -0.135715484619 0.158736944199 -0.327046126127 -v -0.250409126282 0.158635079861 -0.250410705805 -v -0.327044963837 0.158685207367 -0.135717630386 -v -0.353955745697 0.158622086048 -0.000427186489 -v -0.327047109604 0.159409523010 0.134861409664 -v -0.250412702560 0.159973382950 0.249554216862 -v -0.135720252991 0.160485565662 0.326189637184 -v -0.000430822372 0.160919785500 0.353100419044 -v 0.134859085083 0.161209881306 0.326189637184 -v 0.249552488327 0.161311805248 0.249554157257 -v 0.326188802719 0.161209881306 0.134861171246 -v 0.353296518326 0.087664961815 -0.000232100487 -v 0.326386690140 0.087230741978 -0.135521650314 -v 0.249752044678 0.086718618870 -0.250214606524 -v 0.135059833527 0.086206436157 -0.326850026846 -v -0.000229597092 0.085772216320 -0.353760749102 -v -0.135519504547 0.085482120514 -0.326850026846 -v -0.250212907791 0.085380256176 -0.250214606524 -v -0.326848983765 0.085482120514 -0.135521650314 -v -0.353760719299 0.085772216320 -0.000232160091 -v -0.326851129532 0.086206436157 0.135057389736 -v -0.250216484070 0.086718559265 0.249750316143 -v -0.135524034500 0.087230741978 0.326385736465 -v -0.000234603882 0.087664961815 0.353296518326 -v 0.135055065155 0.087955057621 0.326385736465 -v 0.249748706818 0.088056981564 0.249750256538 -v 0.326384902000 0.087955057621 0.135057270527 -v 0.375676870346 0.177378296852 -0.000472128391 -v 0.364366769791 0.177348017693 -0.000472128391 -v 0.347045183182 0.176916301250 -0.144418120384 -v 0.336596012115 0.176899909973 -0.140089869499 -v 0.265507221222 0.176371395588 -0.266449689865 -v 0.257509708405 0.176371395588 -0.258452177048 -v 0.143476247787 0.175826430321 -0.347988516092 -v 0.139147996902 0.175842821598 -0.337539315224 -v -0.000469446182 0.175364434719 -0.376621156931 -v -0.000469684601 0.175394713879 -0.365310996771 -v -0.144415855408 0.175055742264 -0.347988516092 -v -0.140087604523 0.175095319748 -0.337539315224 -v -0.266447782516 0.174947381020 -0.266449689865 -v -0.258450269699 0.174990177155 -0.258452177048 -v -0.347987651825 0.175055742264 -0.144418120384 -v -0.337538242340 0.175095319748 -0.140089929104 -v -0.376621246338 0.175364434719 -0.000472187996 -v -0.365311145782 0.175394713879 -0.000472187996 -v -0.347989559174 0.175826430321 0.143473863602 -v -0.337540388107 0.175842821598 0.139145612717 -v -0.266451835632 0.176371335983 0.265505313873 -v -0.258454084396 0.176371335983 0.257507801056 -v -0.144420623779 0.176916301250 0.347044229507 -v -0.140092372894 0.176899909973 0.336595058441 -v -0.000474929810 0.177378296852 0.375676870346 -v -0.000474691391 0.177348017693 0.364366769791 -v 0.143471479416 0.177686989307 0.347044229507 -v 0.139143228531 0.177647411823 0.336595058441 -v 0.265503644943 0.177795350552 0.265505313873 -v 0.257506132126 0.177752554417 0.257507801056 -v 0.347043275833 0.177686989307 0.143473744392 -v 0.336594104767 0.177647411823 0.139145493507 -v -0.260723114014 0.157754421234 -0.259547352791 -v 0.188534498215 0.162128329277 0.220312714577 -v 0.150835990906 0.255903840065 -0.122018277645 -v -0.367745399475 0.145474791527 -0.000509381294 -v 0.326006412506 0.188046872616 0.061991870403 -v -0.140351295471 0.145963966846 0.338536977768 -v -0.092543125153 0.133517801762 0.209983170033 -v -0.045091629028 0.219104647636 0.071014165878 -v 0.117162466049 0.138920009136 0.148487687111 -v 0.094516038895 0.211338222027 0.006093084812 -v 0.141849040985 0.167456209660 -0.338641077280 -v -0.132145881653 0.224308967590 -0.168267190456 -v -0.290617465973 0.153861880302 0.041577756405 -v 0.232747793198 0.220157623291 -0.020193576813 -v -0.104435920715 0.156720459461 0.107542216778 -v 0.261220932007 0.215893089771 0.140530586243 -v 0.339339137077 0.144055008888 0.139837384224 -v 0.232198715210 0.238567829132 -0.074207901955 -v 0.139328241348 0.221993207932 -0.251845806837 -v 0.001096725464 0.115566849709 0.232506930828 -v 0.235008478165 0.183093011379 -0.224647879601 -v 0.025869607925 0.220658242702 0.010586977005 -v -0.260028839111 0.142340183258 0.258761763573 -v 0.149353027344 0.195868253708 0.071023166180 -v -0.312650203705 0.150955259800 0.143607854843 -v -0.012047052383 0.257859528065 -0.223151683807 -v -0.092512130737 0.135187923908 0.292060732841 -v -0.015312671661 0.255189657211 -0.138771057129 -v 0.137337684631 0.183658897877 -0.296297132969 -v -0.172811269760 0.177352190018 -0.007483303547 -v 0.223266124725 0.217488348484 0.090728402138 -v 0.064405202866 0.252335906029 -0.226450979710 -v -0.188626766205 0.189203381538 -0.061699330807 -v 0.016028881073 0.124756276608 0.299646496773 -v 0.089669704437 0.233257532120 -0.075778305531 -v 0.139914751053 0.137555956841 0.338332772255 -v 0.284914731979 0.198863744736 -0.022770822048 -v 0.304054975510 0.196833968163 0.028051853180 -v -0.097067356110 0.222885787487 -0.054254412651 -v -0.237313508987 0.144842386246 0.232705712318 -v 0.269050121307 0.216346383095 0.051027357578 -v -0.120793342590 0.202318608761 0.021182298660 -v -0.339625835419 0.138534486294 0.138899505138 -v 0.037177801132 0.231764197350 -0.090419173241 -v 0.143469810486 0.149774491787 0.195432603359 -v 0.293514966965 0.187747895718 -0.097219467163 -v -0.168785572052 0.151870310307 0.060518741608 -v 0.020806550980 0.266882598400 -0.172512531281 -v 0.259666919708 0.145984232426 0.258646607399 -v 0.034334182739 0.252145409584 -0.135116934776 -v -0.140362977982 0.156036436558 -0.339551180601 -v 0.032037258148 0.132924497128 0.150658845901 -v 0.366469740868 0.153844237328 -0.000785291195 -v -0.013993501663 0.172754645348 0.088831484318 -v 0.075382471085 0.258517682552 -0.122498214245 -v -0.144392013550 0.200841248035 -0.234057486057 -v 0.200603008270 0.174400389194 0.172962725163 -v -0.017191648483 0.226316809654 0.000772595406 -v 0.077378988266 0.224100291729 -0.039400041103 -v -0.000497341156 0.134032607079 0.366490840912 -v 0.338284015656 0.156314671040 -0.141668856144 -v -0.153885364532 0.204451203346 -0.099687397480 -v 0.195820569992 0.205458104610 0.131933152676 -v 0.216483592987 0.239142835140 -0.141529560089 -v -0.048132896423 0.252258181572 -0.187425732613 -v 0.048329114914 0.181412041187 0.058874249458 -v 0.297631740570 0.188538789749 0.118461728096 -v 0.094685554504 0.275856882334 -0.177895724773 -v 0.291773080826 0.176003396511 0.168679654598 -v 0.258277654648 0.169047772884 -0.258827954531 -v -0.025267601013 0.222986042500 -0.080369651318 -v -0.082452535629 0.196722209454 -0.287426501513 -v -0.052076101303 0.149037420750 0.130536139011 -v 0.078437328339 0.166446685791 -0.351232022047 -v -0.079320430756 0.196040034294 0.077153921127 -v 0.147503852844 0.252151966095 -0.186089634895 -v -0.237520694733 0.165661454201 -0.003286302090 -v -0.029679536819 0.118149220943 0.186804175377 -v 0.181889533997 0.212109684944 -0.008958518505 -v -0.094622135162 0.229876041412 -0.137650251389 -v 0.069519281387 0.135161101818 0.174413204193 -v 0.278537750244 0.214016139507 0.012907266617 -v -0.000745296478 0.139973580837 0.130587935448 -v 0.161170482635 0.208140671253 0.035515487194 -v -0.166126012802 0.139393448830 0.192975401878 -v 0.290117979050 0.177705764771 -0.146035611629 -v 0.020158529282 0.206230044365 0.052492976189 -v -0.134399890900 0.143064141273 0.142413377762 -v -0.266332864761 0.169014453888 -0.063792705536 -v 0.132324457169 0.250333786011 -0.097359597683 -v 0.001193761826 0.159170746803 -0.367280960083 -v -0.188598394394 0.189268946648 -0.191226005554 -v 0.097879648209 0.156538784504 0.109527528286 -v 0.203623294830 0.224369049072 -0.037161529064 -v -0.129595041275 0.211527705193 -0.041961491108 -v -0.339376449585 0.143820405006 -0.140513777733 -v 0.205133199692 0.213180243969 -0.004063129425 -v 0.233246803284 0.214453101158 -0.008401036263 -v 0.206484079361 0.212388336658 0.016018033028 -v 0.242507219315 0.213977515697 0.010456264019 -v 0.209819316864 0.211635589600 0.041306018829 -v 0.251682043076 0.213515639305 0.034897506237 -v 0.219023942947 0.211915493011 0.102876901627 -v 0.255498886108 0.213328659534 0.102843940258 -v 0.209807872772 0.211321473122 0.073793649673 -v 0.260978460312 0.213306427002 0.070012688637 -v 0.218056917191 0.213957488537 -0.009956002235 -v 0.237318038940 0.212719857693 0.106576442719 -v 0.201871395111 0.223009884357 -0.005214691162 -v 0.234170436859 0.224603056908 -0.010290384293 -v 0.201443910599 0.221436142921 0.017751872540 -v 0.247167825699 0.223902463913 0.009773075581 -v 0.204860687256 0.220546007156 0.042006075382 -v 0.256182670593 0.223231375217 0.033681809902 -v 0.217150449753 0.220006823540 0.104498565197 -v 0.257226705551 0.222062766552 0.105154514313 -v 0.202792167664 0.219771981239 0.074708163738 -v 0.266690969467 0.222605288029 0.069311499596 -v 0.216041564941 0.224303185940 -0.016883432865 -v 0.236886978149 0.220857679844 0.113419055939 -v 0.201165676117 0.241792380810 -0.002464711666 -v 0.235595226288 0.243774831295 -0.008793592453 -v 0.200091838837 0.239008307457 0.019165515900 -v 0.248582601547 0.241591095924 0.009618818760 -v 0.203350067139 0.236650824547 0.041424393654 -v 0.256637573242 0.239299356937 0.032281756401 -v 0.218260288239 0.230036914349 0.104059219360 -v 0.253784656525 0.232075154781 0.103391885757 -v 0.206028461456 0.232413649559 0.076064765453 -v 0.216443300247 0.243729174137 -0.014796018600 -v 0.236021757126 0.231211543083 0.111301779747 -v 0.247812032700 0.238879442215 0.099651157856 -v 0.235158205032 0.239502251148 0.103205502033 -v 0.262071609497 0.235375046730 0.069712936878 -v 0.252540349960 0.260097324848 0.055052101612 -v 0.222467422485 0.237549602985 0.101014792919 -v 0.212550878525 0.258014202118 0.062277555466 -v 0.201892614365 0.345312535763 0.008776485920 -v 0.242216825485 0.349303513765 0.009433805943 -v 0.191249847412 0.342574447393 0.028094410896 -v 0.255865812302 0.346988528967 0.028772234917 -v 0.196735858917 0.339674323797 0.052435636520 -v 0.258110046387 0.343376874924 0.052006244659 -v 0.221249341965 0.348548620939 0.002917945385 -v 0.222075462341 0.356713175774 0.034231722355 -v 0.229865312576 0.337269216776 0.076513707638 -v 0.232888221741 0.263725697994 0.063763737679 -v 0.204312324524 0.270660489798 0.003390491009 -v 0.236067295074 0.272651731968 -0.001152694225 -v 0.200947046280 0.266749739647 0.023094773293 -v 0.249783754349 0.268808007240 0.012558996677 -v 0.202597379684 0.262279391289 0.042629957199 -v 0.255157470703 0.263839781284 0.032649099827 -v 0.218951225281 0.272833973169 -0.005811095238 -v 0.248102664948 0.339510381222 0.071823954582 -v 0.211038351059 0.337233841419 0.072277426720 -v 0.212896347046 0.211532533169 0.087992787361 -v 0.260196208954 0.213362693787 0.086466848850 -v 0.206652641296 0.219657599926 0.088583350182 -v 0.265573501587 0.222268044949 0.086174011230 -v 0.208487510681 0.231236219406 0.089933633804 -v 0.261114358902 0.233485519886 0.086178541183 -v 0.249599456787 0.241804718971 0.087328910828 -v 0.218761682510 0.240887939930 0.090320706367 -v 0.234282970428 0.244165539742 0.089901387691 -v 0.249197959900 0.245250940323 0.071763932705 -v 0.233741044998 0.248610019684 0.075530111790 -v 0.218100309372 0.243478000164 0.076156377792 -v 0.259891033173 0.237450182438 0.052915513515 -v 0.262217521667 0.222825467587 0.053764879704 -v 0.257991552353 0.213336646557 0.054791927338 -v 0.209878206253 0.211354732513 0.060339868069 -v 0.203500509262 0.219918906689 0.060940921307 -v 0.205494880676 0.234648823738 0.060976922512 -v 0.232362031937 0.296486437321 0.068670928478 -v 0.247957706451 0.297481447458 0.058879435062 -v 0.214935302734 0.296461522579 0.063020169735 -v 0.256248474121 0.300734728575 0.041230976582 -v 0.205139160156 0.308436393738 0.010030686855 -v 0.238288879395 0.311282992363 0.009258210659 -v 0.199443340302 0.304088622332 0.028930902481 -v 0.251448392868 0.306685805321 0.022934615612 -v 0.202795028687 0.299219369888 0.047689616680 -v 0.221186876297 0.311318457127 0.002745151520 -v 0.225008487701 0.352216601372 0.053049981594 -v 0.202267408371 0.358467698097 0.014773547649 -v 0.193837165833 0.356905907393 0.031560063362 -v 0.200456142426 0.354091018438 0.051699697971 -v 0.214915990829 0.351570516825 0.066617071629 -v 0.227507829666 0.352972269058 0.069517612457 -v 0.240033149719 0.354288905859 0.067502856255 -v 0.247437715530 0.356183379889 0.048327982426 -v 0.255626201630 0.361346334219 0.031195163727 -v 0.243300676346 0.363204896450 0.016159296036 -v 0.220804214478 0.361127465963 0.011520028114 -v -0.006412744522 0.219254732132 -0.070368289948 -v -0.034497737885 0.219416260719 -0.075179994106 -v -0.007551431656 0.219255983829 -0.050698041916 -v -0.043589591980 0.219416618347 -0.056793034077 -v -0.010588407516 0.219317317009 -0.025610864162 -v -0.052551269531 0.219525873661 -0.032343029976 -v -0.019434452057 0.219501733780 0.036931097507 -v -0.056055307388 0.219407021999 0.036677896976 -v -0.010255813599 0.219376742840 0.007310867310 -v -0.061593055725 0.219416677952 0.003298044205 -v -0.019374847412 0.219313621521 -0.076339542866 -v -0.037804126740 0.219456374645 0.040600121021 -v -0.003419399261 0.229272305965 -0.072110950947 -v -0.035720348358 0.229651033878 -0.077736675739 -v -0.002564668655 0.228819966316 -0.049440383911 -v -0.048538923264 0.229538142681 -0.058115601540 -v -0.005802154541 0.228773951530 -0.025171041489 -v -0.057313680649 0.229480981827 -0.033867120743 -v -0.017800569534 0.228000402451 0.038410604000 -v -0.058048009872 0.228443384171 0.038873791695 -v -0.003192663193 0.228343427181 0.008078634739 -v -0.067610979080 0.228918552399 0.002470076084 -v -0.017654657364 0.229513227940 -0.083801627159 -v -0.037597417831 0.228035628796 0.047402024269 -v -0.003135919571 0.248828172684 -0.071072876453 -v -0.037687301636 0.249413430691 -0.078146457672 -v -0.001599311829 0.247187077999 -0.049244463444 -v -0.050426006317 0.247864484787 -0.059458792210 -v -0.004717350006 0.245696306229 -0.026384413242 -v -0.058178663254 0.246295332909 -0.035779118538 -v -0.019185543060 0.238504111767 0.037673413754 -v -0.054839372635 0.239117026329 0.036907553673 -v -0.006999969482 0.241730749607 0.009231150150 -v -0.018567800522 0.249538004398 -0.083647012711 -v -0.037009954453 0.238889813423 0.044985234737 -v -0.049028873444 0.246678113937 0.033095300198 -v -0.036361932755 0.247815668583 0.036695182323 -v -0.063289403915 0.242662429810 0.002855598927 -v -0.054507970810 0.268849194050 -0.014230966568 -v -0.023601055145 0.246319174767 0.034479141235 -v -0.014294147491 0.268415987492 -0.006592750549 -v -0.007125854492 0.352546513081 -0.070307731628 -v -0.047215461731 0.354491233826 -0.074513196945 -v 0.003531694412 0.351069599390 -0.050791621208 -v -0.060627460480 0.352100074291 -0.057532072067 -v -0.001306772232 0.349359750748 -0.028730213642 -v -0.062292337418 0.349174886942 -0.036085724831 -v -0.026328802109 0.354579001665 -0.078574538231 -v -0.027374744415 0.363825768232 -0.050758659840 -v -0.033916950226 0.346315592527 -0.004494011402 -v -0.034796714783 0.273458153009 -0.005827486515 -v -0.007123708725 0.278406739235 -0.068862497807 -v -0.038926839828 0.278996378183 -0.074869096279 -v -0.003371477127 0.275840729475 -0.048226654530 -v -0.052319049835 0.275491327047 -0.060075223446 -v -0.004662275314 0.272252291441 -0.027530074120 -v -0.057320117950 0.271499335766 -0.038320362568 -v -0.021856307983 0.279480308294 -0.079001605511 -v -0.051886796951 0.346334606409 -0.018019616604 -v -0.015472888947 0.347499132156 -0.012708246708 -v -0.013341426849 0.219453394413 0.021781980991 -v -0.060760498047 0.219377577305 0.020002603531 -v -0.007234573364 0.228128254414 0.022226035595 -v -0.066421747208 0.228480756283 0.019553661346 -v -0.009428262711 0.240280926228 0.023335456848 -v -0.062236309052 0.240545749664 0.019495189190 -v -0.050906419754 0.249981880188 0.020713865757 -v -0.019988298416 0.250182330608 0.023671388626 -v -0.035615205765 0.253143727779 0.023297965527 -v -0.050571680069 0.253851354122 0.004940390587 -v -0.035207986832 0.258085966110 0.008688688278 -v -0.019476890564 0.253200232983 0.009263873100 -v -0.061208486557 0.244841516018 -0.014327108860 -v -0.063190460205 0.229270637035 -0.013317525387 -v -0.058711767197 0.219515621662 -0.012146055698 -v -0.010442733765 0.219379901886 -0.006376981735 -v -0.004127025604 0.228489577770 -0.005963206291 -v -0.006670236588 0.244056880474 -0.006213486195 -v -0.035041809082 0.306504577398 -0.012205660343 -v -0.050817012787 0.305917531252 -0.022203505039 -v -0.017575979233 0.306866586208 -0.015941679478 -v -0.059380531311 0.307994395494 -0.039807379246 -v -0.009127378464 0.316277623177 -0.068142294884 -v -0.042343616486 0.317533701658 -0.072862088680 -v -0.003009557724 0.313361108303 -0.048151373863 -v -0.055118322372 0.313115835190 -0.059049367905 -v -0.005843162537 0.309433162212 -0.029619455338 -v -0.025185585022 0.317963033915 -0.077642977238 -v -0.029360532761 0.360437393188 -0.033840239048 -v -0.013695001602 0.365091145039 -0.063374280930 -v -0.005713224411 0.364561080933 -0.049769103527 -v -0.006861448288 0.363386452198 -0.031659960747 -v -0.019543409348 0.360915482044 -0.018560290337 -v -0.032689571381 0.360493153334 -0.010817825794 -v -0.045087814331 0.359358161688 -0.021629929543 -v -0.058130502701 0.362013280392 -0.034903645515 -v -0.055710792542 0.363338232040 -0.056892096996 -v -0.040955543518 0.367505073547 -0.065858364105 -v -0.026666879654 0.366931766272 -0.066344976425 -v 0.019335746765 0.891146719456 0.147463440895 -v 0.077193498611 0.876855552197 -0.156872689724 -v 0.077016353607 0.674709022045 -0.110481500626 -v 0.026651859283 0.777218222618 0.134643375874 -v 0.027640104294 0.662163913250 0.117864131927 -v 0.092115879059 0.819933474064 0.165385544300 -v 0.022340536118 0.851363182068 0.150859296322 -v 0.081831455231 0.861464142799 0.176887631416 -v 0.145524740219 0.883852779865 0.172923028469 -v 0.158493518829 0.841617703438 0.157872855663 -v 0.277504920959 1.007843017578 0.047269701958 -v 0.272853851318 1.025377511978 0.051120281219 -v 0.286534786224 1.034585952759 0.047402620316 -v 0.302318572998 0.995641767979 0.049039125443 -v 0.262354612350 0.997510433197 0.039628624916 -v 0.254748582840 1.029515981674 0.052300691605 -v 0.286922931671 0.964170455933 0.051867485046 -v 0.263444900513 0.934777021408 -0.010773301125 -v 0.278232336044 0.898669064045 -0.017279744148 -v 0.282225131989 0.895403862000 -0.048148393631 -v 0.268206119537 0.922013401985 -0.048899114132 -v 0.263873815536 0.932216346264 -0.047488868237 -v 0.249542474747 0.950950801373 -0.014343142509 -v 0.242866039276 0.973144650459 0.013231754303 -v 0.257011651993 0.958706617355 0.025045931339 -v 0.272060394287 0.937663674355 0.036257743835 -v 0.267414808273 0.922991752625 0.012871444225 -v 0.282770156860 0.902756571770 0.011130094528 -v 0.123666524887 0.582465767860 -0.075673460960 -v 0.149766921997 0.525964796543 -0.038310170174 -v 0.177918195724 0.547954797745 -0.041567981243 -v 0.164103984833 0.607049584389 -0.064459025860 -v 0.103845834732 0.528503477573 -0.026832699776 -v 0.132575511932 0.506744384766 -0.010294854641 -v 0.262545824051 0.962624549866 -0.120018243790 -v 0.277079582214 0.942464232445 -0.121075093746 -v 0.283565044403 0.978037595749 -0.130021154881 -v 0.242907762527 1.002508759499 -0.135505557060 -v 0.261280298233 0.944051027298 -0.092559337616 -v 0.272555112839 0.925887763500 -0.087273895741 -v 0.231066703796 0.961506426334 -0.136641144753 -v 0.218405961990 0.840843498707 0.091216206551 -v 0.210432529449 0.794565856457 0.084894001484 -v 0.186074256897 0.768438935280 0.106157541275 -v 0.168217658997 0.802124977112 0.130858242512 -v 0.239678859711 0.831269502640 0.040043413639 -v 0.225566387177 0.781253993511 0.055830478668 -v 0.209580659866 0.882061362267 0.132225513458 -v 0.155940294266 0.740337014198 0.119884729385 -v 0.106715440750 0.770864248276 0.151021718979 -v 0.178981781006 0.699676811695 0.084566056728 -v 0.182432651520 0.725065171719 0.095114350319 -v 0.204370975494 0.743299126625 0.076818108559 -v 0.213043212891 0.707077801228 0.041539013386 -v 0.136242151260 0.711864829063 0.109547138214 -v 0.155378341675 0.589013695717 0.109423935413 -v 0.137723207474 0.638659536839 0.112122654915 -v 0.171539545059 0.636296868324 0.090351223946 -v 0.201073408127 0.608585000038 0.070430636406 -v 0.217098474503 0.565734565258 0.062991678715 -v 0.191636562347 0.555289149284 0.088190674782 -v 0.150764703751 1.090515971184 0.031594216824 -v 0.133168458939 1.064684152603 0.068517208099 -v 0.107606649399 1.083139657974 0.037304639816 -v 0.119329452515 1.104554176331 0.014675736427 -v 0.187176704407 1.110415458679 0.029244542122 -v 0.202834844589 1.080092191696 0.052686989307 -v 0.179083585739 1.058245539665 0.064180791378 -v 0.160923242569 1.034242868423 0.096240758896 -v 0.254607439041 1.061115264893 0.052536368370 -v 0.220592498779 1.047652482986 0.058174490929 -v 0.231979370117 1.086294531822 0.047397136688 -v 0.231719017029 1.019516706467 0.049612939358 -v 0.293545246124 0.912459313869 0.040535092354 -v 0.235724687576 1.107659101486 0.028177142143 -v 0.274882793427 1.085638523102 0.028672218323 -v 0.096796751022 0.524665117264 0.020752966404 -v 0.121049642563 1.164031744003 -0.039851784706 -v 0.109050750732 1.171761870384 -0.060386240482 -v 0.151132822037 1.143172383308 -0.073541879654 -v 0.162862539291 1.139242529869 -0.047275900841 -v 0.166463375092 1.129762411118 -0.013145327568 -v 0.125269412994 1.148490905762 -0.022257208824 -v 0.222014427185 1.136164307594 -0.085919082165 -v 0.229552507401 1.134870767593 -0.049831032753 -v 0.233881950378 1.128509044647 -0.008981227875 -v 0.281436681747 1.108168125153 -0.051254689693 -v 0.281991004944 1.102712631226 -0.009698688984 -v 0.317685604095 1.067490458488 -0.049807429314 -v 0.317203044891 1.065495610237 -0.009583413601 -v 0.306344747543 1.052000999451 0.026935875416 -v 0.343569040298 1.024486541748 -0.007518947124 -v 0.329200625420 1.013627648354 0.025783419609 -v 0.366793274879 0.985834360123 -0.007350325584 -v 0.354122877121 0.976988136768 0.026278495789 -v 0.334745645523 0.958747029305 0.052049517632 -v 0.379283428192 0.947536230087 0.020861685276 -v 0.362321138382 0.928932666779 0.043664336205 -v 0.342812895775 0.907195210457 0.044864654541 -v 0.314275741577 0.935671687126 0.057043790817 -v 0.319790363312 0.888074278831 0.029314041138 -v 0.379310607910 0.902640283108 0.024499237537 -v 0.358928322792 0.880074322224 0.019105792046 -v 0.338169336319 0.861247479916 0.001740396023 -v 0.400299787521 0.877586364746 0.025739133358 -v 0.380050063133 0.852149724960 0.022235631943 -v 0.363364696503 0.827350735664 0.010587811470 -v 0.362974047661 0.811894834042 -0.017841279507 -v 0.332549810410 0.850514173508 -0.031367659569 -v 0.376002192497 0.802355408669 -0.049095809460 -v 0.339113950729 0.838486850262 -0.071368515491 -v 0.312850952148 0.871554672718 -0.076692581177 -v 0.306100845337 0.872793436050 -0.043697237968 -v 0.402581334114 0.810562849045 -0.068494379520 -v 0.367998600006 0.846436321735 -0.105324327946 -v 0.326204538345 0.882910430431 -0.107103466988 -v 0.432064533234 0.831387817860 -0.069692969322 -v 0.409785628319 0.862663328648 -0.103722870350 -v 0.452204942703 0.860042333603 -0.057465374470 -v 0.432444095612 0.890474557877 -0.088653087616 -v 0.403483510017 0.924710273743 -0.103032827377 -v 0.390702843666 0.900007128716 -0.125450611115 -v 0.458554625511 0.884764671326 -0.038810074329 -v 0.440712213516 0.916401028633 -0.064721584320 -v 0.409626007080 0.946123480797 -0.076701641083 -v 0.377049446106 0.978414773941 -0.079899370670 -v 0.369030594826 0.959930837154 -0.107197761536 -v 0.434939265251 0.931571722031 -0.036256074905 -v 0.403420209885 0.955381631851 -0.043758153915 -v 0.375007867813 0.986278414726 -0.043334543705 -v 0.346902847290 1.024103283882 -0.045506417751 -v 0.346037387848 1.015392422676 -0.082815170288 -v 0.391106963158 0.955277502537 -0.011757612228 -v 0.418347239494 0.931938529015 -0.009633421898 -v 0.398629426956 0.921277165413 0.011540293694 -v 0.441792011261 0.907627224922 0.005505323410 -v 0.420485854149 0.897287666798 0.019965410233 -v 0.454711556435 0.901762425900 -0.017239570618 -v 0.312911748886 1.057415366173 -0.085565030575 -v 0.301878452301 1.036462783813 -0.110103130341 -v 0.341517090797 0.998458266258 -0.115687966347 -v 0.291906356812 1.012423157692 -0.127237200737 -v 0.328496098518 0.970709323883 -0.136209249496 -v 0.354727029800 0.934686720371 -0.121113419533 -v 0.311561107635 0.939342975616 -0.134227514267 -v 0.340052127838 0.908680558205 -0.124131619930 -v 0.367459774017 0.884051918983 -0.123385787010 -v 0.297220230103 0.911664009094 -0.117913901806 -v 0.289204835892 0.899315834045 -0.083201110363 -v 0.250025033951 1.053760290146 -0.137834787369 -v 0.264823913574 1.083865046501 -0.119606435299 -v 0.201839447021 1.117434144020 -0.118024945259 -v 0.189693689346 1.079212427139 -0.142952740192 -v 0.277281999588 1.102975010872 -0.089239239693 -v 0.120431184769 1.085181832314 -0.138198077679 -v 0.121253252029 1.037931799889 -0.155860960484 -v 0.184354066849 1.029958724976 -0.157751560211 -v 0.119925260544 1.132153749466 -0.108325600624 -v 0.123482465744 0.987731099129 -0.170279264450 -v 0.180538892746 0.979573845863 -0.163978517056 -v 0.125545501709 0.932765841484 -0.173250615597 -v 0.179258108139 0.925383329391 -0.162734568119 -v 0.227316141129 0.914090216160 -0.128659784794 -v 0.178707361221 0.866539001465 -0.151616394520 -v 0.224370002747 0.859528779984 -0.116147398949 -v 0.256502151489 0.857412219048 -0.071282267570 -v 0.259006500244 0.905853331089 -0.084065675735 -v 0.258020401001 0.867200314999 -0.023059964180 -v 0.263725519180 0.906981647015 -0.038188934326 -v 0.246686458588 0.885027527809 0.019917786121 -v 0.248519420624 0.927023947239 0.000404238701 -v 0.239131689072 0.904338777065 0.060729622841 -v 0.241918325424 0.948883771896 0.032647311687 -v 0.229748249054 0.932023048401 0.094542920589 -v 0.231833934784 0.972128450871 0.056386351585 -v 0.237094879150 0.996514856815 0.032092094421 -v 0.225894212723 0.997993648052 0.079689145088 -v 0.216531753540 0.964301168919 0.116260170937 -v 0.190495014191 0.998777031898 0.114465355873 -v 0.204521656036 1.026806235313 0.079624712467 -v 0.192690134048 0.921263933182 0.150567412376 -v 0.164333105087 0.961874485016 0.145105898380 -v 0.135314941406 1.002291202545 0.123882234097 -v 0.122396469116 0.928251743317 0.165373027325 -v 0.099461555481 0.973314642906 0.142395615578 -v 0.080953598022 1.017653703690 0.112643778324 -v 0.110545635223 1.040468931198 0.096353948116 -v 0.067555904388 1.051582455635 0.072920858860 -v 0.089736461639 1.065327763557 0.058615803719 -v 0.057373523712 0.952757716179 0.147553682327 -v 0.047913312912 1.000822305679 0.117389440536 -v 0.042551279068 1.041895747185 0.078767657280 -v 0.069515228271 0.905283331871 0.168992578983 -v 0.244445800781 0.817365288734 -0.006311953068 -v 0.244346380234 0.804270505905 -0.054641485214 -v 0.217851400375 0.751652359962 -0.033641099930 -v 0.227277755737 0.763818323612 0.012114584446 -v 0.197771310806 0.745314657688 -0.074247181416 -v 0.188985824585 0.683782935143 -0.054120063782 -v 0.209798336029 0.693763196468 -0.014226317406 -v 0.216273546219 0.801639676094 -0.098835766315 -v 0.174543857574 0.806066751480 -0.130712211132 -v 0.165594577789 0.745285034180 -0.103144109249 -v 0.123121976852 0.748481452465 -0.116453528404 -v 0.120306491852 0.673266887665 -0.099647700787 -v 0.158249378204 0.678283751011 -0.080645978451 -v 0.126316308975 0.812821507454 -0.142758727074 -v 0.126960277557 0.873750686646 -0.163805663586 -v 0.068856477737 0.984705030918 -0.177298188210 -v 0.055420398712 1.084348678589 -0.154314756393 -v 0.046322107315 1.128087520599 -0.128710865974 -v 0.075109720230 0.593776226044 -0.089249253273 -v 0.192573547363 0.621916353703 -0.036496400833 -v 0.203611850739 0.571760535240 -0.021339297295 -v 0.217868804932 0.595229387283 0.017003238201 -v 0.213207960129 0.638992846012 0.003613412380 -v 0.204703092575 0.652575969696 0.048748970032 -v 0.170325040817 0.665199697018 0.078543841839 -v 0.130563020706 0.677610635757 0.104269742966 -v 0.083450555801 0.650120198727 0.126545190811 -v 0.081408262253 0.691678225994 0.131133735180 -v 0.086372137070 0.729118704796 0.137566983700 -v 0.026894569397 0.740492343903 0.127000212669 -v 0.088793277740 0.606545627117 0.116948366165 -v 0.091482639313 0.568313062191 0.093596041203 -v 0.093423366547 0.540040552616 0.060054659843 -v 0.137021780014 0.550631523132 0.090929865837 -v 0.129982471466 0.524636745453 0.061635315418 -v 0.129219055176 0.512163639069 0.027145802975 -v 0.155890464783 0.512163281441 0.061540365219 -v 0.151852607727 0.501129508018 0.032996356487 -v 0.151466369629 0.490233093500 0.004889369011 -v 0.164501428604 0.473722547293 0.017774462700 -v 0.166211366653 0.483703285456 0.041170895100 -v 0.176519632339 0.462068229914 0.050208270550 -v 0.178006410599 0.457004278898 0.029782295227 -v 0.190201759338 0.459076434374 0.014697730541 -v 0.178750276566 0.478803396225 0.000907838345 -v 0.166320323944 0.497839301825 -0.015286624432 -v 0.207526922226 0.465957105160 0.009304404259 -v 0.199348926544 0.490522235632 -0.004005312920 -v 0.189775466919 0.514920592308 -0.020356297493 -v 0.225358963013 0.475811570883 0.017339110374 -v 0.221742391586 0.505469441414 0.004819691181 -v 0.213993549347 0.536153674126 -0.007584154606 -v 0.236834526062 0.485237836838 0.038113415241 -v 0.233140468597 0.520117580891 0.029869019985 -v 0.226602554321 0.556548476219 0.023947119713 -v 0.239451885223 0.491162627935 0.065631270409 -v 0.229833841324 0.528143048286 0.060667395592 -v 0.239911079407 0.454511433840 0.042522192001 -v 0.245521306992 0.457225382328 0.067053318024 -v 0.237636566162 0.455539733171 0.084717154503 -v 0.226967334747 0.489047199488 0.082951843739 -v 0.211964607239 0.523329734802 0.080300390720 -v 0.217800378799 0.450385510921 0.087392747402 -v 0.206350564957 0.480243116617 0.084223449230 -v 0.190374135971 0.509804129601 0.078286647797 -v 0.183592557907 0.468741506338 0.072134256363 -v 0.173839807510 0.494874238968 0.062670707703 -v 0.168895244598 0.532966911793 0.083921194077 -v 0.194311380386 0.443297296762 0.078714847565 -v 0.186420440674 0.440069437027 0.057327508926 -v 0.193065404892 0.417387604713 0.057190775871 -v 0.203305721283 0.417975842953 0.076225996017 -v 0.205404996872 0.391247153282 0.066273987293 -v 0.194074869156 0.392329305410 0.049775362015 -v 0.190062761307 0.393557667732 0.030566751957 -v 0.192551136017 0.417236864567 0.037556171417 -v 0.188753843307 0.438155025244 0.037616431713 -v 0.199758052826 0.395951777697 0.012652158737 -v 0.201189756393 0.418664783239 0.020802915096 -v 0.198827505112 0.439186781645 0.022741913795 -v 0.220117330551 0.398994356394 0.008019566536 -v 0.217715263367 0.422239899635 0.015295565128 -v 0.213492631912 0.443650007248 0.018471002579 -v 0.236896991730 0.400686651468 0.011681675911 -v 0.232114553452 0.425558745861 0.022678315639 -v 0.227942943573 0.449451982975 0.025451838970 -v 0.247877597809 0.399994522333 0.024417579174 -v 0.242132186890 0.427206337452 0.038007915020 -v 0.250198125839 0.367911368608 0.023290991783 -v 0.239138841629 0.370674878359 0.011764705181 -v 0.234215259552 0.326959192753 0.024860799313 -v 0.239667415619 0.325394153595 0.032651007175 -v 0.239298582077 0.323285490274 0.041500747204 -v 0.250197172165 0.363285213709 0.041953921318 -v 0.248555660248 0.397186785936 0.044638574123 -v 0.236860036850 0.320421725512 0.050307810307 -v 0.239134788513 0.358723700047 0.058663964272 -v 0.239214897156 0.393967717886 0.063256323338 -v 0.230540990829 0.316507697105 0.058507502079 -v 0.225771665573 0.354905188084 0.069335877895 -v 0.224077701569 0.390892267227 0.075807273388 -v 0.220066547394 0.317402213812 0.054555177689 -v 0.211529970169 0.357036679983 0.059551179409 -v 0.212295293808 0.320155978203 0.044720351696 -v 0.198891878128 0.359852999449 0.045892953873 -v 0.208841085434 0.323172211647 0.033653140068 -v 0.194800376892 0.364280372858 0.028407096863 -v 0.212930202484 0.325841575861 0.024493038654 -v 0.203210353851 0.368161261082 0.013654232025 -v 0.223614931107 0.327202796936 0.020913243294 -v 0.221999883652 0.371129333973 0.011114120483 -v 0.299593925476 0.875928103924 -0.016731262207 -v 0.305377960205 0.881739974022 0.006167829037 -v 0.124761581421 1.127089619637 -0.005370020866 -v 0.144920587540 1.114051818848 -0.000504493713 -v 0.320274353027 0.867451727390 -0.003048002720 -v 0.317344665527 0.863656222820 -0.015280425549 -v 0.081691741943 1.171155452728 -0.082533001900 -v 0.489620566368 0.754746913910 0.055047810078 -v 0.492703795433 0.744488835335 0.057417750359 -v 0.500872254372 0.748085975647 0.052790284157 -v 0.503330826759 0.759612381458 0.050021946430 -v 0.455907583237 0.767686963081 0.180662214756 -v 0.448605775833 0.763490140438 0.179388940334 -v 0.454131126404 0.774452686310 0.183209419250 -v 0.512239336967 0.719803869724 0.108971118927 -v 0.513665318489 0.712346911430 0.098931610584 -v 0.501137852669 0.723156571388 0.088684141636 -v 0.498448848724 0.729723930359 0.098093867302 -v 0.506369471550 0.735136747360 0.129543185234 -v 0.510510444641 0.727772593498 0.119067549706 -v 0.495698451996 0.736607313156 0.107330560684 -v 0.491642713547 0.742265939713 0.117717981339 -v 0.492995619774 0.730934858322 0.070337891579 -v 0.488109588623 0.732578217983 0.080537736416 -v 0.505285978317 0.719612061977 0.078231096268 -v 0.525172829628 0.681995272636 0.167945027351 -v 0.521392345428 0.683978497982 0.175799846649 -v 0.521812319756 0.691806197166 0.180061340332 -v 0.519139647484 0.787753224373 0.090079247952 -v 0.529436826706 0.773348331451 0.102756619453 -v 0.523522257805 0.779470205307 0.115589499474 -v 0.511284351349 0.795331001282 0.102586388588 -v 0.539867997169 0.729618787766 0.089468300343 -v 0.531417727470 0.747590124607 0.073452115059 -v 0.527307748795 0.738277912140 0.066966652870 -v 0.535834193230 0.725835144520 0.077996909618 -v 0.523569345474 0.720503687859 0.128831326962 -v 0.526804924011 0.719818413258 0.135298848152 -v 0.537645578384 0.725556254387 0.133212625980 -v 0.540601491928 0.730802595615 0.123283326626 -v 0.534850597382 0.748413085938 0.143720269203 -v 0.533050775528 0.738149583340 0.147188425064 -v 0.521691203117 0.732560038567 0.148685574532 -v 0.515544414520 0.738024771214 0.147808253765 -v 0.521300554276 0.711467444897 0.118006944656 -v 0.506483316422 0.747644484043 0.153991520405 -v 0.502677559853 0.742156207561 0.140237092972 -v 0.501390576363 0.751134574413 0.149526238441 -v 0.541826605797 0.742310583591 0.123451471329 -v 0.541710376740 0.746488988400 0.128475904465 -v 0.540703296661 0.751621305943 0.123491525650 -v 0.541983366013 0.746656119823 0.119618058205 -v 0.532743930817 0.764434099197 0.148749291897 -v 0.529609441757 0.768829822540 0.144122123718 -v 0.533065080643 0.763605058193 0.139945745468 -v 0.534711122513 0.759675085545 0.143647730350 -v 0.519114732742 0.724147796631 0.142600655556 -v 0.515840530396 0.728727519512 0.137992262840 -v 0.540112376213 0.734770715237 0.138869524002 -v 0.540696740150 0.740617036819 0.133606433868 -v 0.522036075592 0.709590852261 0.079642355442 -v 0.515752315521 0.708322763443 0.088428199291 -v 0.523067712784 0.698891818523 0.096575498581 -v 0.528108596802 0.700006604195 0.087751507759 -v 0.538988947868 0.715688526630 0.081110537052 -v 0.540867447853 0.712676644325 0.084093391895 -v 0.543041229248 0.715164959431 0.088397443295 -v 0.540838479996 0.719581723213 0.084006726742 -v 0.506251692772 0.761048257351 0.153887510300 -v 0.509725928307 0.757334053516 0.158531010151 -v 0.525017738342 0.770337998867 0.149724423885 -v 0.527247309685 0.767623901367 0.152778089046 -v 0.526124477386 0.703662514687 0.107429325581 -v 0.541818618774 0.721548616886 0.089130938053 -v 0.543096542358 0.717609286308 0.092653989792 -v 0.514024734497 0.685954689980 0.172047317028 -v 0.515303611755 0.692099928856 0.177232980728 -v 0.518338084221 0.682923436165 0.165953993797 -v 0.535277485847 0.708344936371 0.147681176662 -v 0.524157166481 0.704845070839 0.148237943649 -v 0.523532152176 0.699540019035 0.152397453785 -v 0.534913420677 0.702481508255 0.152555465698 -v 0.519562959671 0.716747760773 0.161118566990 -v 0.530426263809 0.720963180065 0.161624073982 -v 0.530594706535 0.714648783207 0.166401624680 -v 0.519082903862 0.711292505264 0.165497899055 -v 0.516831398010 0.709372937679 0.154453039169 -v 0.516183376312 0.703925609589 0.158576548100 -v 0.538677573204 0.715157747269 0.155361831188 -v 0.538471341133 0.711140751839 0.158608913422 -v 0.533556699753 0.693566560745 0.159267961979 -v 0.521171927452 0.692192018032 0.156506180763 -v 0.519478797913 0.686819851398 0.160811662674 -v 0.531105518341 0.687699437141 0.163550257683 -v 0.516932487488 0.704223155975 0.170683681965 -v 0.529407978058 0.705302298069 0.173214852810 -v 0.527298688889 0.699028372765 0.177262067795 -v 0.515662312508 0.698305785656 0.174661695957 -v 0.512620925903 0.697871327400 0.162089228630 -v 0.511643767357 0.691746532917 0.166646361351 -v 0.537143468857 0.698810040951 0.168046832085 -v 0.535217404366 0.695275962353 0.170467853546 -v 0.537539839745 0.719420015812 0.138411521912 -v 0.526125192642 0.715106844902 0.139984965324 -v 0.524770259857 0.710178494453 0.144071102142 -v 0.534347414970 0.711749315262 0.141898036003 -v 0.521291613579 0.727184534073 0.152451038361 -v 0.531763315201 0.732593894005 0.152449965477 -v 0.526586532593 0.727051615715 0.158230066299 -v 0.519834280014 0.721794843674 0.156188130379 -v 0.519172072411 0.719282746315 0.146682977676 -v 0.518319606781 0.714717566967 0.150376081467 -v 0.542425036430 0.726674139500 0.146438956261 -v 0.541626691818 0.720945656300 0.142000854015 -v 0.540896654129 0.716939508915 0.144021809101 -v 0.542814254761 0.723198592663 0.149447917938 -v 0.538549065590 0.730741381645 0.152049660683 -v 0.537324070930 0.727843642235 0.155685722828 -v 0.540292024612 0.714531242847 0.147353291512 -v 0.541417002678 0.719230473042 0.152375280857 -v 0.537661671638 0.723493218422 0.157489120960 -v 0.522315740585 0.696558475494 0.153652429581 -v 0.532957553864 0.696634590626 0.154145359993 -v 0.526823282242 0.710777997971 0.170685768127 -v 0.517996311188 0.707997262478 0.167178988457 -v 0.514600038528 0.702156662941 0.159258484840 -v 0.540738582611 0.708825647831 0.160881042480 -v 0.539718866348 0.703809440136 0.156380772591 -v 0.539808750153 0.700395345688 0.157848179340 -v 0.541602373123 0.705698668957 0.163604915142 -v 0.537238717079 0.712285995483 0.166008591652 -v 0.536659955978 0.709942877293 0.169121146202 -v 0.539298772812 0.698089897633 0.160789132118 -v 0.540274739265 0.702055811882 0.166186392307 -v 0.536662101746 0.706197261810 0.170638501644 -v 0.540821313858 0.729771852493 0.143572688103 -v 0.534619212151 0.690335750580 0.174641072750 -v 0.534919500351 0.687159657478 0.171165943146 -v 0.534467816353 0.684770822525 0.172516167164 -v 0.533648490906 0.687150001526 0.176869094372 -v 0.533669948578 0.692957580090 0.178517937660 -v 0.532203197479 0.690804123878 0.179874420166 -v 0.528633236885 0.684847950935 0.177231550217 -v 0.531227588654 0.682927608490 0.170618474483 -v 0.534844160080 0.687096238136 0.168217778206 -v 0.534787893295 0.692861855030 0.172489643097 -v 0.532088637352 0.695515155792 0.178507089615 -v 0.528244614601 0.691161870956 0.180853903294 -v 0.542320370674 0.728663325310 0.099375784397 -v 0.542763829231 0.724370181561 0.102947711945 -v 0.543692111969 0.728317677975 0.108140170574 -v 0.543245792389 0.733878433704 0.103289365768 -v 0.539205074310 0.750491321087 0.133062005043 -v 0.538523197174 0.754346132278 0.129205644131 -v 0.543280839920 0.732618570328 0.112749457359 -v 0.543036103249 0.737028181553 0.108903169632 -v 0.531576871872 0.715822875500 0.076436996460 -v 0.537781238556 0.706454157829 0.084965169430 -v 0.516264319420 0.770024180412 0.150568723679 -v 0.521349906921 0.763900756836 0.157923758030 -v 0.548167467117 0.667905509472 0.148447632790 -v 0.546362757683 0.670237898827 0.157298624516 -v 0.545064449310 0.678077816963 0.161700785160 -v 0.530092954636 0.702552258968 0.114723563194 -v 0.540755271912 0.707639873028 0.112147867680 -v 0.542485356331 0.714294910431 0.102276742458 -v 0.538369178772 0.719116032124 0.127693057060 -v 0.527642726898 0.713942587376 0.130929112434 -v 0.524290800095 0.705752372742 0.123955726624 -v 0.543419122696 0.722295403481 0.112965941429 -v 0.543574094772 0.715997815132 0.118450582027 -v 0.538602828979 0.668676257133 0.156609654427 -v 0.538909435272 0.675573229790 0.161329925060 -v 0.541661739349 0.665838003159 0.149098932743 -v 0.544516205788 0.691595375538 0.125912368298 -v 0.534333825111 0.686268508434 0.128116250038 -v 0.535755872726 0.680908918381 0.132590770721 -v 0.546100020409 0.686485588551 0.130807101727 -v 0.530930757523 0.697768330574 0.144220829010 -v 0.540539383888 0.703372836113 0.142738342285 -v 0.542316913605 0.698138594627 0.147101879120 -v 0.532684803009 0.692637383938 0.148399233818 -v 0.528201103210 0.689944863319 0.137334823608 -v 0.529621005058 0.684429168701 0.141547918320 -v 0.547267079353 0.699201166630 0.134586215019 -v 0.548285603523 0.695777177811 0.137413918972 -v 0.549032688141 0.678514897823 0.138707518578 -v 0.538316488266 0.672254383564 0.139705061913 -v 0.539997816086 0.668147265911 0.143931210041 -v 0.549917817116 0.673808932304 0.142802059650 -v 0.535045385361 0.684714317322 0.155533432961 -v 0.545179843903 0.690104901791 0.154163777828 -v 0.546261072159 0.685271203518 0.157988131046 -v 0.536641716957 0.680283010006 0.159242749214 -v 0.531511306763 0.676025629044 0.148519396782 -v 0.533580183983 0.671684741974 0.152756392956 -v 0.551849842072 0.686028897762 0.146424531937 -v 0.552071809769 0.683168113232 0.148839414120 -v 0.542264461517 0.702010095119 0.117023289204 -v 0.531574487686 0.696618914604 0.119827747345 -v 0.533209562302 0.691803276539 0.124981045723 -v 0.542015671730 0.694402575493 0.120017051697 -v 0.527886033058 0.708098948002 0.135989665985 -v 0.538574695587 0.713628768921 0.133871257305 -v 0.536827564240 0.708746492863 0.140737891197 -v 0.529211044312 0.702663362026 0.140047073364 -v 0.525272846222 0.700050890446 0.129155695438 -v 0.527511239052 0.695425748825 0.133208036423 -v 0.547236084938 0.709693551064 0.126150548458 -v 0.546826839447 0.704466640949 0.120804965496 -v 0.547609567642 0.700840175152 0.122550547123 -v 0.548392534256 0.706934809685 0.128966629505 -v 0.544142603874 0.712298274040 0.132492303848 -v 0.544166088104 0.709887802601 0.136017978191 -v 0.548007726669 0.698595046997 0.125999212265 -v 0.548170447350 0.703358292580 0.131739497185 -v 0.545077085495 0.706430852413 0.137581646442 -v 0.536803126335 0.676721870899 0.136981487274 -v 0.546262025833 0.680178046227 0.133575916290 -v 0.541578054428 0.694177865982 0.152556836605 -v 0.533885598183 0.688042283058 0.151733100414 -v 0.530973911285 0.680204808712 0.144950151443 -v 0.550747156143 0.694574475288 0.139328360558 -v 0.550565600395 0.689205110073 0.134101927280 -v 0.551587820053 0.686272799969 0.135594725609 -v 0.551995396614 0.692323207855 0.141612648964 -v 0.547929286957 0.697340607643 0.145395517349 -v 0.548542022705 0.695518493652 0.148347735405 -v 0.552347660065 0.684621572495 0.138660132885 -v 0.552754878998 0.689439475536 0.144070029259 -v 0.549746870995 0.692574083805 0.149577498436 -v 0.544905066490 0.711640059948 0.123353600502 -v 0.554090023041 0.679983973503 0.152069270611 -v 0.554366350174 0.676740288734 0.148733615875 -v 0.555369496346 0.674915611744 0.149775743484 -v 0.555078744888 0.677470684052 0.154006123543 -v 0.553590416908 0.682599842548 0.155873715878 -v 0.553566455841 0.680583536625 0.157422304153 -v 0.552198171616 0.673865497112 0.155969619751 -v 0.553200006485 0.671683013439 0.148962199688 -v 0.553523778915 0.675942182541 0.146138072014 -v 0.552976369858 0.681672930717 0.150468468666 -v 0.551427602768 0.684173226357 0.156823754311 -v 0.550627708435 0.679804623127 0.159817218781 -v 0.561773300171 0.667005836964 0.108489274979 -v 0.562437891960 0.667055547237 0.116291821003 -v 0.561485767365 0.672465205193 0.121660053730 -v 0.532580971718 0.693629801273 0.092338800430 -v 0.540351271629 0.699979722500 0.089606344700 -v 0.542522072792 0.705165266991 0.104129672050 -v 0.533750057220 0.698765039444 0.106722295284 -v 0.530255436897 0.693876147270 0.100649118423 -v 0.544795274734 0.705484151840 0.095455408096 -v 0.543451189995 0.710095763206 0.092419564724 -v 0.556688308716 0.663857758045 0.117876172066 -v 0.557191729546 0.668581724167 0.123596191406 -v 0.557321429253 0.663886785507 0.110297203064 -v 0.550040364265 0.687514245510 0.096655666828 -v 0.542815566063 0.681384682655 0.099399805069 -v 0.546362757683 0.677153646946 0.101630270481 -v 0.552957534790 0.683309435844 0.099402546883 -v 0.543991684914 0.686676859856 0.113965272903 -v 0.550568699837 0.692732572556 0.109966218472 -v 0.552548170090 0.688747942448 0.112151980400 -v 0.546415090561 0.682839512825 0.116651713848 -v 0.540330171585 0.681044578552 0.107999801636 -v 0.543417692184 0.676724195480 0.110768854618 -v 0.553754329681 0.691745519638 0.102674782276 -v 0.555277824402 0.688932120800 0.104441046715 -v 0.558210253716 0.676781058311 0.102892100811 -v 0.551411271095 0.670395851135 0.105135142803 -v 0.554313540459 0.666436553001 0.107223451138 -v 0.560604929924 0.672852039337 0.104644954205 -v 0.551035642624 0.676183104515 0.121510207653 -v 0.557325959206 0.682806491852 0.115938246250 -v 0.559729456902 0.679148495197 0.118263065815 -v 0.554118156433 0.672260820866 0.123688340187 -v 0.547722101212 0.669512152672 0.114816784859 -v 0.551224112511 0.665718138218 0.116806447506 -v 0.561138749123 0.681422650814 0.108677029610 -v 0.562478303909 0.679623842239 0.109518647194 -v 0.544580936432 0.695759892464 0.091603696346 -v 0.536828517914 0.688898324966 0.094865858555 -v 0.539610147476 0.684746026993 0.097163736820 -v 0.545929908752 0.689909696579 0.093230366707 -v 0.538297772408 0.693749725819 0.109103918076 -v 0.546232938766 0.700979232788 0.105687260628 -v 0.547426342964 0.696206927299 0.109800815582 -v 0.541006326675 0.689810454845 0.111045122147 -v 0.534368872643 0.688101053238 0.103304982185 -v 0.538012027740 0.685010075569 0.105363309383 -v 0.550858020782 0.700949549675 0.097763538361 -v 0.549491643906 0.697909832001 0.093589007854 -v 0.550813794136 0.695187926292 0.094435930252 -v 0.552393674850 0.698510527611 0.099156975746 -v 0.550143718719 0.701255559921 0.102890193462 -v 0.551577091217 0.699175059795 0.104868292809 -v 0.552265882492 0.693053603172 0.096573829651 -v 0.553521633148 0.695399820805 0.100726366043 -v 0.552729487419 0.696392178535 0.105458736420 -v 0.549271106720 0.673505485058 0.104050397873 -v 0.554521441460 0.678445816040 0.100325822830 -v 0.553958654404 0.685331046581 0.116456747055 -v 0.548520803452 0.679022014141 0.118942022324 -v 0.546076059341 0.673519492149 0.112744927406 -v 0.557391166687 0.687807381153 0.105319499969 -v 0.556760072708 0.685200691223 0.101653337479 -v 0.558141469955 0.683105111122 0.102121174335 -v 0.559174299240 0.686151802540 0.106331229210 -v 0.556374430656 0.688750267029 0.109533429146 -v 0.557712197304 0.687251687050 0.111271739006 -v 0.559688806534 0.681563556194 0.103728890419 -v 0.560254931450 0.683878600597 0.107563853264 -v 0.559006214142 0.685161352158 0.111566960812 -v 0.547902107239 0.702368199825 0.096936225891 -v 0.564785003662 0.677279114723 0.110871613026 -v 0.565037727356 0.675400853157 0.107921242714 -v 0.566116333008 0.673743724823 0.108678221703 -v 0.566264390945 0.674956560135 0.112121045589 -v 0.564288020134 0.678330838680 0.113956749439 -v 0.565272808075 0.676626622677 0.115107536316 -v 0.565854787827 0.671615004539 0.113909065723 -v 0.565153121948 0.671011805534 0.108082771301 -v 0.564292907715 0.675019502640 0.105877757072 -v 0.563846707344 0.678827285767 0.109954953194 -v 0.563235521317 0.679445624352 0.115319430828 -v 0.564523458481 0.675631463528 0.117880046368 -v 0.508027791977 0.705808162689 0.185932517052 -v 0.503305912018 0.708674609661 0.193543970585 -v 0.504237651825 0.716933488846 0.197534382343 -v 0.514192581177 0.739058196545 0.152600765228 -v 0.527436256409 0.742018103600 0.152551293373 -v 0.521233081818 0.757511794567 0.163559794426 -v 0.510088562965 0.753134310246 0.162780582905 -v 0.506630778313 0.744708418846 0.157582461834 -v 0.531264781952 0.752472937107 0.158268332481 -v 0.532356500626 0.758174300194 0.153628230095 -v 0.496481537819 0.711037337780 0.188681483269 -v 0.497926712036 0.717670679092 0.193979084492 -v 0.501640081406 0.707217693329 0.182956755161 -v 0.524531006813 0.727519810200 0.166848421097 -v 0.513245224953 0.726689815521 0.165383756161 -v 0.511902570724 0.722795486450 0.168308913708 -v 0.523548841476 0.723003327847 0.171342372894 -v 0.509620904922 0.739431321621 0.176361441612 -v 0.520829081535 0.741701781750 0.179257631302 -v 0.519819498062 0.736979722977 0.183732628822 -v 0.508016705513 0.736198961735 0.179792046547 -v 0.506378054619 0.732324659824 0.169591844082 -v 0.504464268684 0.729115188122 0.172098159790 -v 0.528473019600 0.734543383121 0.174971342087 -v 0.527720928192 0.731290459633 0.178188145161 -v 0.518843531609 0.715346276760 0.178183495998 -v 0.507250308990 0.715426683426 0.173481583595 -v 0.504154086113 0.710596859455 0.177767276764 -v 0.515055418015 0.710507869720 0.182130753994 -v 0.502767324448 0.729494333267 0.186172127724 -v 0.514684081078 0.728843152523 0.190630316734 -v 0.510843634605 0.723370432854 0.194603562355 -v 0.499645948410 0.723829448223 0.190759420395 -v 0.498818874359 0.722565889359 0.177140593529 -v 0.495809078217 0.716866850853 0.182247757912 -v 0.521199822426 0.721097052097 0.187072217464 -v 0.518935918808 0.718163132668 0.189251482487 -v 0.525767803192 0.736793160439 0.157169640064 -v 0.513168215752 0.734809756279 0.157476186752 -v 0.513290882111 0.730967700481 0.161826848984 -v 0.522656917572 0.730214118958 0.160739362240 -v 0.510023117065 0.747913599014 0.168063998222 -v 0.522023916245 0.752246916294 0.169538915157 -v 0.518543243408 0.747491836548 0.175433754921 -v 0.509775161743 0.743234395981 0.172257661819 -v 0.506842017174 0.740149796009 0.162537455559 -v 0.507179975510 0.736026167870 0.166410088539 -v 0.533026695251 0.745195150375 0.165490031242 -v 0.531216979027 0.738591969013 0.161130785942 -v 0.530287504196 0.734632968903 0.163438796997 -v 0.532566308975 0.741663217545 0.168802976608 -v 0.529102921486 0.749674737453 0.170213341713 -v 0.527972817421 0.746949017048 0.173987030983 -v 0.529739618301 0.732569515705 0.167208254337 -v 0.531125068665 0.737987637520 0.172155261040 -v 0.527689337730 0.742842078209 0.176281332970 -v 0.509422302246 0.719553887844 0.170410692692 -v 0.519722938538 0.717905282974 0.172781825066 -v 0.514890789986 0.734458565712 0.187463164330 -v 0.505210161209 0.733366072178 0.182220578194 -v 0.502490282059 0.726530313492 0.174150884151 -v 0.528773427010 0.728935301304 0.181077003479 -v 0.527782201767 0.723789393902 0.176339983940 -v 0.526475429535 0.720672547817 0.177816569805 -v 0.527674317360 0.726253092289 0.183694541454 -v 0.525176644325 0.733416676521 0.184952259064 -v 0.523093461990 0.731555163860 0.187405228615 -v 0.524735569954 0.719069778919 0.180645465851 -v 0.525143027306 0.723502397537 0.185845911503 -v 0.521940231323 0.728395640850 0.189189791679 -v 0.531512737274 0.747916936874 0.162386298180 -v 0.516651630402 0.713900744915 0.192825019360 -v 0.516959309578 0.710621714592 0.189882099628 -v 0.516236543655 0.708358943462 0.191311597824 -v 0.515579700470 0.710943758488 0.195346117020 -v 0.515369772911 0.716586649418 0.195921123028 -v 0.514391779900 0.714817166328 0.197931408882 -v 0.510539889336 0.709055662155 0.195576369762 -v 0.513627529144 0.706451058388 0.189301311970 -v 0.517277002335 0.710314393044 0.187095999718 -v 0.517525792122 0.716093361378 0.190888464451 -v 0.514751195908 0.719347119331 0.196116745472 -v 0.510549068451 0.715662777424 0.198681712151 -v 0.533120870590 0.762782216072 0.130480825901 -v 0.524248719215 0.772845745087 0.138786017895 -v 0.540866613388 0.746797680855 0.109364151955 -v 0.537410974503 0.759103238583 0.116162776947 -v 0.540438890457 0.742126762867 0.095553338528 -v 0.520689725876 0.728452146053 0.065447509289 -v 0.512445688248 0.721606135368 0.069535374641 -v 0.484276175499 0.737580657005 0.089107573032 -v 0.532676100731 0.765493094921 0.091823399067 -v 0.533045768738 0.757094204426 0.081643581390 -v 0.514222741127 0.784138381481 0.129911184311 -v 0.490095019341 0.767989397049 0.145252108574 -v 0.479055404663 0.768541455269 0.143870294094 -v 0.488378524780 0.780031323433 0.144005358219 -v 0.498183012009 0.777795016766 0.142598867416 -v 0.481902122498 0.759345829487 0.139733493328 -v 0.467978596687 0.763386905193 0.133951485157 -v 0.455418944359 0.777963399887 0.119988799095 -v 0.451926827431 0.777264595032 0.134350359440 -v 0.458689928055 0.767885684967 0.141088008881 -v 0.468816995621 0.769495069981 0.148243069649 -v 0.476413726807 0.779487848282 0.150034487247 -v 0.438565135002 0.771156847477 0.177375793457 -v 0.441770315170 0.764434158802 0.175460696220 -v 0.444827079773 0.770441770554 0.183847427368 -v 0.469913721085 0.779009222984 0.155741333961 -v 0.463364720345 0.769138574600 0.153375625610 -v 0.460401535034 0.767174780369 0.158601582050 -v 0.467330098152 0.775935709476 0.162042737007 -v 0.453510165215 0.769425153732 0.147249221802 -v 0.450202226639 0.768634498119 0.153188824654 -v 0.467652678490 0.791541039944 0.152924060822 -v 0.464564323425 0.787662565708 0.161086738110 -v 0.456722617149 0.792148888111 0.148283004761 -v 0.454262137413 0.790213525295 0.153603911400 -v 0.449564695358 0.782195746899 0.142867326736 -v 0.445333719254 0.781309008598 0.150482535362 -v 0.462369918823 0.796061277390 0.131073176861 -v 0.470566511154 0.799281775951 0.136529088020 -v 0.469121217728 0.797714054585 0.143102586269 -v 0.460547566414 0.795852959156 0.138329267502 -v 0.455207109451 0.789058446884 0.126723527908 -v 0.453316926956 0.788498997688 0.133789181709 -v 0.477501153946 0.792452573776 0.146006584167 -v 0.465461015701 0.796401441097 0.147136926651 -v 0.458685755730 0.794838547707 0.143734753132 -v 0.453046441078 0.789503097534 0.139946758747 -v 0.477824330330 0.801583707333 0.131692588329 -v 0.462747812271 0.795654177666 0.121492981911 -v 0.461746931076 0.769132852554 0.174213290215 -v 0.453706622124 0.761957705021 0.170404195786 -v 0.443747997284 0.765161931515 0.166959524155 -v 0.460104227066 0.781512916088 0.175598621368 -v 0.445243358612 0.784041821957 0.176206707954 -v 0.449878454208 0.784194827080 0.178927242756 -v 0.448585391045 0.782106339931 0.182242095470 -v 0.443793654442 0.781242489815 0.181344807148 -v 0.440421819687 0.782552838326 0.174964666367 -v 0.439622640610 0.780634343624 0.178736805916 -v 0.438029885292 0.777883410454 0.165846407413 -v 0.457392096519 0.764703154564 0.162105917931 -v 0.465457439423 0.772188305855 0.166752159595 -v 0.447040438652 0.767057418823 0.158573865891 -v 0.465133786201 0.783054172993 0.168668568134 -v 0.452129364014 0.790718674660 0.158209085464 -v 0.459192514420 0.790737628937 0.162641108036 -v 0.459162950516 0.789255976677 0.167319536209 -v 0.450338006020 0.789745509624 0.162790656090 -v 0.445508122444 0.787147641182 0.154866278172 -v 0.442550182343 0.785621106625 0.158436417580 -v 0.440964460373 0.777064740658 0.156837046146 -v 0.456962108612 0.787429749966 0.170820236206 -v 0.448460698128 0.787783861160 0.167056441307 -v 0.441197395325 0.784746885300 0.163089811802 -v 0.447333574295 0.785258412361 0.169726729393 -v 0.443022251129 0.777300119400 0.184506356716 -v 0.450631856918 0.780292212963 0.183982253075 -v 0.453623771667 0.784703671932 0.178378582001 -v 0.445952057838 0.786179065704 0.172527611256 -v 0.438473701477 0.781861722469 0.171767473221 -v 0.437908291817 0.777420401573 0.178881585598 -v 0.492766499519 0.755644321442 0.143515646458 -v 0.486923098564 0.747458815575 0.130217909813 -v 0.466797590256 0.757182359695 0.099651396275 -v 0.472083091736 0.750997185707 0.089635670185 -v 0.469869136810 0.760206878185 0.083161294460 -v 0.463792681694 0.773227989674 0.097641050816 -v 0.480604887009 0.743164718151 0.097418367863 -v 0.509183526039 0.740819334984 0.056642234325 -v 0.515854835510 0.750867664814 0.056534111500 -v 0.500680327415 0.800476849079 0.113281011581 -v 0.480252742767 0.809417188168 0.104322493076 -v 0.496218204498 0.805853843689 0.093608915806 -v 0.494943737984 0.789026916027 0.136653363705 -v 0.501828312874 0.788901865482 0.133081078529 -v 0.507851958275 0.797888576984 0.081428110600 -v 0.522942423820 0.779709160328 0.077857553959 -v 0.499507188797 0.765030682087 0.148840188980 -v 0.507470130920 0.774820327759 0.144708752632 -v 0.476036071777 0.746732592583 0.106510400772 -v 0.493361711502 0.803006708622 0.122841835022 -v 0.478899002075 0.807841002941 0.117558896542 -v 0.463644027710 0.796741485596 0.111424744129 -v 0.465716123581 0.794997811317 0.103478550911 -v 0.458229780197 0.777908682823 0.107420504093 -v 0.462887525558 0.761031866074 0.109043002129 -v 0.471899509430 0.750320196152 0.116126954556 -v 0.478152394295 0.753174483776 0.131771326065 -v 0.468824982643 0.755779623985 0.124225437641 -v 0.461404800415 0.763227701187 0.116893410683 -v 0.489722132683 0.797489106655 0.133335888386 -v 0.486714601517 0.789863348007 0.141924619675 -v 0.484797358513 0.741189062595 0.067133903503 -v 0.478503465652 0.751935124397 0.068854808807 -v 0.500882506371 0.734169185162 0.061571240425 -v 0.477385044098 0.744656562805 0.080763101578 -v 0.481624126434 0.739364206791 0.075847864151 -v 0.500677943230 0.775840044022 0.048178792000 -v 0.488707780838 0.765670180321 0.051871418953 -v 0.477584242821 0.762718737125 0.063034832478 -v 0.467450737953 0.766845524311 0.076912343502 -v 0.461498498917 0.778625905514 0.089994966984 -v 0.461806297302 0.795562386513 0.096759736538 -v 0.470135807991 0.809676170349 0.096153378487 -v 0.483797073364 0.812756240368 0.088045477867 -v 0.497678637505 0.805696189404 0.075719475746 -v 0.504785418510 0.791619062424 0.059249997139 -v 0.513334751129 0.788233518600 0.068128407001 -v 0.511568665504 0.770020723343 0.053026437759 -v 0.520908117294 0.761221706867 0.061087131500 -v 0.497784495354 0.788155913353 0.046932697296 -v 0.488117575645 0.775684356689 0.047841131687 -v 0.475840330124 0.770089447498 0.057217180729 -v 0.463661313057 0.771884500980 0.069685220718 -v 0.455235481262 0.782279491425 0.081061065197 -v 0.454746246338 0.798582255840 0.087480664253 -v 0.461082696915 0.812864422798 0.088064253330 -v 0.473519444466 0.820378422737 0.082788586617 -v 0.488731861115 0.816120684147 0.070775330067 -v 0.498112678528 0.803522765636 0.056562244892 -v 0.494563221931 0.799096226692 0.042310714722 -v 0.486902475357 0.808524429798 0.030907094479 -v 0.478900671005 0.793341755867 0.029809832573 -v 0.486203432083 0.785064756870 0.041563153267 -v 0.464779496193 0.783073127270 0.035595595837 -v 0.472564697266 0.777089834213 0.049066007137 -v 0.450284838676 0.780604720116 0.044155120850 -v 0.458022236824 0.776483118534 0.058857560158 -v 0.440367698669 0.784753084183 0.049066960812 -v 0.443802475929 0.787280976772 0.064302384853 -v 0.444123268127 0.804896831512 0.073245406151 -v 0.451916456223 0.821180701256 0.076650619507 -v 0.464986562729 0.832542598248 0.073360800743 -v 0.480245232582 0.831362009048 0.059292852879 -v 0.481340765953 0.834166049957 0.044129669666 -v 0.492998480797 0.814772903919 0.050042569637 -v 0.486271023750 0.822800278664 0.037332177162 -v 0.523271918297 0.770754814148 0.068353176117 -v 0.514518499374 0.778774738312 0.058889150620 -v 0.507184267044 0.776329338551 0.050279438496 -v 0.508969664574 0.781902492046 0.054183304310 -v 0.244488239288 0.426662117243 0.058280527592 -v 0.238626718521 0.424758225679 0.073367774487 -v 0.224532604218 0.421156793833 0.082624495029 -v 0.024168014526 0.813921332359 0.149686336517 -v -0.045492410660 0.811454951763 0.138143301010 -v -0.043429851532 0.849619209766 0.152232885361 -v -0.103686809540 0.858773767948 0.124039173126 -v -0.105726003647 0.821566998959 0.105698108673 -v -0.216044902802 1.015913844109 -0.065555334091 -v -0.209439516068 0.999427437782 -0.058619439602 -v -0.211006164551 0.987861990929 -0.064142704010 -v -0.230187892914 0.988817870617 -0.073895573616 -v -0.197565555573 0.993671536446 -0.052417397499 -v -0.196903944016 0.968688607216 -0.066415429115 -v -0.226006031036 0.954002797604 -0.069144666195 -v -0.186616420746 0.850906968117 -0.171889841557 -v -0.197167158127 0.860019028187 -0.140617847443 -v -0.179961204529 0.897772192955 -0.115278422832 -v -0.166189670563 0.875091910362 -0.153516530991 -v -0.148694753647 0.880870044231 -0.136985838413 -v -0.150884389877 0.907215118408 -0.104235470295 -v -0.157392501831 0.931122899055 -0.078570246696 -v -0.191499710083 0.929601490498 -0.075881302357 -v -0.215350627899 0.919599175453 -0.078258514404 -v -0.203397989273 0.897285580635 -0.100253224373 -v -0.217379808426 0.875960350037 -0.118124604225 -v -0.029005050659 0.571525335312 -0.088107168674 -v 0.002735614777 0.548631310463 -0.070256829262 -v 0.027010679245 0.590999245644 -0.090317308903 -v -0.018280744553 0.620064198971 -0.103850007057 -v 0.018197059631 0.528473854065 -0.041200280190 -v 0.039121389389 0.542406558990 -0.043555021286 -v -0.148338317871 0.925767302513 -0.247407793999 -v -0.147905111313 0.887462854385 -0.231083989143 -v -0.130671024323 0.907526671886 -0.214898705482 -v -0.110074996948 0.950674951077 -0.223033547401 -v -0.158329963684 0.874756038189 -0.191096603870 -v -0.134732007980 0.893178164959 -0.177285671234 -v -0.090615749359 0.914829909801 -0.207994282246 -v -0.112192392349 0.762768864632 0.047738432884 -v -0.126791477203 0.781367957592 0.019289433956 -v -0.137742519379 0.815532445908 0.021429121494 -v -0.104435205460 0.789754331112 0.077099800110 -v -0.129538536072 0.770201504230 -0.012699365616 -v -0.138639211655 0.806268036366 -0.033546984196 -v -0.147496223450 0.848499417305 0.061839640141 -v -0.089931488037 0.741834282875 0.071407139301 -v -0.054453372955 0.767961084843 0.118939399719 -v -0.098224401474 0.709381341934 0.028533697128 -v -0.111907958984 0.714046895504 -0.023087024689 -v -0.118014335632 0.742692947388 0.013800978661 -v -0.105286121368 0.729441761971 0.038245499134 -v -0.068748474121 0.719616711140 0.068620622158 -v -0.085082054138 0.653443753719 0.027877748013 -v -0.058162212372 0.656390905380 0.056895077229 -v -0.050686836243 0.607604086399 0.047678053379 -v -0.099447727203 0.621420621872 0.005962431431 -v -0.068820476532 0.563984632492 0.037404358387 -v -0.093855857849 0.573501050472 0.006214916706 -v -0.061287641525 1.064289569855 0.001488387585 -v -0.092086315155 1.040367364883 0.017865002155 -v -0.100042343140 1.063028454781 -0.025874853134 -v -0.068414211273 1.083276271820 -0.024904131889 -v -0.152829885483 1.043263196945 -0.030532896519 -v -0.132411718369 1.076464056969 -0.043527424335 -v -0.132525444031 1.024463057518 -0.009899616241 -v -0.121130466461 1.003944158554 0.032351315022 -v -0.171019792557 1.007393002510 -0.034520506859 -v -0.196717739105 1.027601242065 -0.048720419407 -v -0.173523902893 1.051656365395 -0.044109880924 -v -0.172769784927 0.976805567741 -0.047324657440 -v -0.238524913788 0.893932402134 -0.094456076622 -v -0.167498588562 1.074029922485 -0.061905801296 -v -0.199609756470 1.058331489563 -0.076546132565 -v 0.035741090775 0.537817895412 0.004574596882 -v 0.063968896866 0.537479221821 0.012407362461 -v 0.069581508636 0.543589949608 -0.037130057812 -v -0.067850828171 1.115831255913 -0.122188806534 -v -0.044815301895 1.153640151024 -0.091253459454 -v -0.061902284622 1.142533540726 -0.076420962811 -v -0.087494134903 1.110044360161 -0.101176381111 -v -0.102974891663 1.099434852600 -0.071468591690 -v -0.069273948669 1.125692009926 -0.061185836792 -v -0.110057592392 1.099711656570 -0.165807723999 -v -0.129351377487 1.099599599838 -0.132730364799 -v -0.150191068649 1.093798398972 -0.095395982265 -v -0.167793750763 1.074134111404 -0.162128686905 -v -0.187201261520 1.073685646057 -0.118393898010 -v -0.200552225113 1.044490218163 -0.186491847038 -v -0.215443849564 1.052723646164 -0.141018509865 -v -0.222080469131 1.039790749550 -0.094145119190 -v -0.239657878876 1.022207856178 -0.158943414688 -v -0.241830825806 1.013184070587 -0.110611021519 -v -0.260427713394 0.986940979958 -0.176530241966 -v -0.263617753983 0.981970906258 -0.132411062717 -v -0.260305166245 0.958638668060 -0.098890125751 -v -0.278702974319 0.955592036247 -0.163595557213 -v -0.278200626373 0.932817518711 -0.130598545074 -v -0.271001577377 0.901743829250 -0.119967401028 -v -0.252998113632 0.927197396755 -0.088302910328 -v -0.255738973618 0.872728466988 -0.122977674007 -v -0.288134813309 0.917696714401 -0.166244506836 -v -0.280348777771 0.886196553707 -0.155893802643 -v -0.267940998077 0.855949759483 -0.158157467842 -v -0.322344541550 0.899317681789 -0.184273540974 -v -0.314202308655 0.871414363384 -0.169530987740 -v -0.304754018784 0.841402471066 -0.163097262383 -v -0.351705789566 0.865829944611 -0.176985263824 -v -0.346288204193 0.842895746231 -0.165701746941 -v -0.342967510223 0.821778357029 -0.172056436539 -v -0.297340869904 0.818372488022 -0.180801868439 -v -0.255311727524 0.834150016308 -0.184277534485 -v -0.344840049744 0.807662725449 -0.190519332886 -v -0.298639774323 0.802460789680 -0.209736287594 -v -0.253891229630 0.813284337521 -0.222991466522 -v -0.215986251831 0.835866868496 -0.183695673943 -v -0.214768171310 0.830051660538 -0.219524562359 -v -0.309920310974 0.802444458008 -0.240571200848 -v -0.261218309402 0.820708096027 -0.265693724155 -v -0.202613115311 0.844021797180 -0.252863943577 -v -0.351272106171 0.804853558540 -0.214755058289 -v -0.361089944839 0.814315497875 -0.239227890968 -v -0.324601888657 0.821000874043 -0.263598829508 -v -0.283481359482 0.848797678947 -0.284017473459 -v -0.368223667145 0.837127387524 -0.253749161959 -v -0.336348056793 0.853153288364 -0.277962535620 -v -0.297395467758 0.883530080318 -0.294476032257 -v -0.240055322647 0.874735951424 -0.304646462202 -v -0.264170885086 0.907689154148 -0.292484790087 -v -0.343079566956 0.886833965778 -0.280547678471 -v -0.304080247879 0.919566035271 -0.288546800613 -v -0.274107933044 0.937634170055 -0.272911608219 -v -0.237725257874 0.939036250114 -0.275381207466 -v -0.246447801590 0.963879764080 -0.250892400742 -v -0.299230575562 0.941379368305 -0.261109113693 -v -0.274475336075 0.952009916306 -0.239782989025 -v -0.254629850388 0.977320313454 -0.217426180840 -v -0.217944860458 0.993275702000 -0.236558616161 -v -0.229768037796 1.010393023491 -0.203123748302 -v -0.274976491928 0.958194017410 -0.204134941101 -v -0.294450044632 0.945626258850 -0.227268993855 -v -0.291128396988 0.938337326050 -0.193792879581 -v -0.336385011673 0.927444577217 -0.237453699112 -v -0.328366279602 0.918976187706 -0.207168340683 -v -0.373788356781 0.900349020958 -0.237839400768 -v -0.367165803909 0.902696073055 -0.212942600250 -v -0.358767509460 0.887838721275 -0.192018508911 -v -0.399082183838 0.886386156082 -0.210687160492 -v -0.391416311264 0.878774166107 -0.190892636776 -v -0.385291337967 0.862347722054 -0.175807774067 -v -0.380799770355 0.844238936901 -0.168828010559 -v -0.377043247223 0.828504204750 -0.168903589249 -v -0.378103971481 0.815952479839 -0.178110599518 -v -0.382728338242 0.809657692909 -0.196520686150 -v -0.389034032822 0.812136590481 -0.218078017235 -v -0.393783569336 0.826233685017 -0.232942044735 -v -0.374763011932 0.861356377602 -0.261329650879 -v -0.397455453873 0.845723807812 -0.239633858204 -v -0.401363134384 0.864607393742 -0.240126490593 -v -0.377741813660 0.885030388832 -0.257234215736 -v -0.342441082001 0.914424657822 -0.266438513994 -v -0.402511835098 0.878381252289 -0.229500651360 -v -0.170168876648 1.000604867935 -0.237006545067 -v -0.184483528137 1.026935815811 -0.219662249088 -v -0.204886913300 0.972634196281 -0.262749642134 -v -0.159294366837 0.967827081680 -0.247309863567 -v -0.191198587418 0.937436878681 -0.281654030085 -v -0.222276926041 0.905950903893 -0.284064441919 -v -0.177347660065 0.896951436996 -0.278299987316 -v -0.199582099915 0.874506413937 -0.276412338018 -v -0.219844818115 0.853652238846 -0.284712314606 -v -0.174687385559 0.863596737385 -0.250282466412 -v -0.181549310684 0.849696934223 -0.207981944084 -v -0.116446971893 1.003559350967 -0.234433829784 -v -0.131599664688 1.042656898499 -0.224299788475 -v -0.063884496689 1.038912057877 -0.210333466530 -v -0.085042953491 1.078667521477 -0.191534459591 -v -0.149874925613 1.067245244980 -0.198640346527 -v 0.006145715714 1.018314838409 -0.186279118061 -v -0.007123947144 1.064264893532 -0.171564280987 -v -0.048004388809 0.991492629051 -0.217727243900 -v -0.026478528976 1.111588954926 -0.142706692219 -v 0.017360448837 0.970607042313 -0.195879101753 -v -0.035747051239 0.945858657360 -0.214797735214 -v 0.026816844940 0.918899655342 -0.194363832474 -v -0.025933980942 0.897993922234 -0.206000804901 -v -0.080864667892 0.874895334244 -0.192031383514 -v -0.018188714981 0.847238957882 -0.190483808517 -v -0.072869777679 0.831310868263 -0.174542069435 -v -0.116947174072 0.821985781193 -0.144294202328 -v -0.121940612793 0.859033942223 -0.160447001457 -v -0.136636972427 0.828852474689 -0.101162433624 -v -0.142194747925 0.857307851315 -0.121078729630 -v -0.143414735794 0.845660209656 -0.058004975319 -v -0.144388198853 0.880819320679 -0.082161068916 -v -0.153039455414 0.862532734871 -0.018098533154 -v -0.153266906738 0.903006434441 -0.052416980267 -v -0.161772251129 0.888247668743 0.014432668686 -v -0.160099267960 0.926342248917 -0.032119214535 -v -0.164556503296 0.953284680843 -0.062894344330 -v -0.171996355057 0.952526032925 -0.012361943722 -v -0.164795875549 0.921657145023 0.036377131939 -v -0.147756576538 0.961669743061 0.040470600128 -v -0.158525466919 0.986356794834 -0.006434679031 -v -0.145291805267 0.885101556778 0.083670973778 -v -0.126105070114 0.929664313793 0.086600899696 -v -0.100680828094 0.976286113262 0.074836552143 -v -0.088333368301 0.904943823814 0.124103307724 -v -0.068841934204 0.954400718212 0.109162628651 -v -0.050687789917 1.002869248390 0.086499452591 -v -0.076419353485 1.019973993301 0.056980848312 -v -0.031089067459 1.040452837944 0.053422629833 -v -0.048895835876 1.049849748611 0.030142068863 -v -0.028286457062 0.943060517311 0.130822718143 -v -0.018934726715 0.993253171444 0.104324102402 -v -0.008577823639 1.036106586456 0.068773925304 -v 0.016984224319 0.938255190849 0.132273197174 -v 0.016255617142 0.988211154938 0.106916069984 -v 0.017256975174 1.034857988358 0.074777126312 -v -0.037022590637 0.893554985523 0.148184359074 -v -0.125862836838 0.795052647591 -0.077642142773 -v -0.088509559631 0.748381972313 -0.091158628464 -v -0.106392145157 0.784361839294 -0.120982527733 -v -0.114890336990 0.757017672062 -0.053101658821 -v -0.051238536835 0.693981826305 -0.101675391197 -v -0.053010225296 0.743843674660 -0.121231853962 -v -0.086938619614 0.703561365604 -0.072716116905 -v -0.064249753952 0.786670446396 -0.151442766190 -v -0.010465383530 0.743931651115 -0.136873304844 -v -0.013234376907 0.796020328999 -0.166346788406 -v 0.032855987549 0.676068127155 -0.117384016514 -v 0.034677505493 0.748068869114 -0.133399724960 -v -0.010420322418 0.684079170227 -0.115326344967 -v 0.036463499069 0.808236598969 -0.159694790840 -v 0.077756881714 0.752460122108 -0.118776857853 -v 0.079266071320 0.817305207253 -0.140415549278 -v 0.034280061722 0.864266276360 -0.182166934013 -v 0.072944402695 0.932042717934 -0.169168591499 -v 0.063047170639 1.036345005035 -0.171650230885 -v -0.058959484100 0.640669405460 -0.090303719044 -v -0.066095590591 0.592738807201 -0.077589452267 -v -0.097780227661 0.609835147858 -0.045422494411 -v -0.095155477524 0.656358480453 -0.060826182365 -v -0.105790376663 0.668013811111 -0.016322851181 -v -0.087153911591 0.680714309216 0.023537695408 -v -0.060539484024 0.690345466137 0.063132166862 -v -0.022153139114 0.659986138344 0.099782228470 -v -0.026333808899 0.697329998016 0.108290851116 -v -0.032596349716 0.731493532658 0.113822937012 -v 0.026883125305 0.702849328518 0.121817588806 -v -0.007471561432 0.622038125992 0.083720922470 -v 0.033208370209 0.620859384537 0.106691539288 -v 0.010722160339 0.584229052067 0.067391037941 -v 0.046667098999 0.584562242031 0.083252370358 -v 0.025924444199 0.553159415722 0.041892528534 -v 0.057153224945 0.554712772369 0.051456034184 -v -0.020308732986 0.569664835930 0.051660239697 -v 0.001250267029 0.543498456478 0.031863629818 -v 0.013638973236 0.532003760338 -0.001672267914 -v -0.000382900238 0.520153343678 -0.005273222923 -v -0.012644290924 0.528460025787 0.023336231709 -v 0.006472110748 0.512750744820 -0.036196351051 -v -0.007425308228 0.474734485149 -0.000116705894 -v -0.005846261978 0.500033557415 -0.004471659660 -v 0.000211715698 0.494048833847 -0.030069172382 -v -0.006864786148 0.472749769688 -0.022261261940 -v -0.018941164017 0.475434243679 -0.039400577545 -v -0.014056682587 0.499557584524 -0.049792110920 -v -0.007712841034 0.522083699703 -0.061311900616 -v -0.037567615509 0.480722934008 -0.046939432621 -v -0.037078142166 0.509507179260 -0.057908356190 -v -0.034726858139 0.538039565086 -0.071861624718 -v -0.058244705200 0.486637681723 -0.040571570396 -v -0.064287900925 0.519816040993 -0.052058398724 -v -0.066971778870 0.554416954517 -0.064069986343 -v -0.073494434357 0.490894377232 -0.019915223122 -v -0.083090543747 0.529140114784 -0.027455270290 -v -0.092357873917 0.568181574345 -0.034658551216 -v -0.079753637314 0.491208374500 0.009451150894 -v -0.086676597595 0.532695353031 0.006102561951 -v -0.073581457138 0.454350113869 0.007979691029 -v -0.066380023956 0.457608014345 -0.017444491386 -v -0.067813158035 0.488057374954 0.029619216919 -v -0.066108465195 0.450441658497 0.027257204056 -v -0.069606781006 0.527580559254 0.030218899250 -v -0.044326543808 0.482478886843 0.033305048943 -v -0.044793844223 0.448259085417 0.031902611256 -v -0.042425155640 0.517599105835 0.031794846058 -v -0.017328262329 0.477021217346 0.022542297840 -v -0.018852710724 0.507313489914 0.017633438110 -v -0.037883758545 0.545025348663 0.042228996754 -v -0.019141912460 0.447015106678 0.024648547173 -v -0.009853363037 0.448897719383 0.002969503403 -v -0.010138511658 0.424218118191 -0.001672625542 -v -0.006133556366 0.399529516697 -0.015495121479 -v -0.017596960068 0.394342869520 -0.000591039658 -v -0.020816802979 0.419395595789 0.016798019409 -v -0.009426116943 0.427912145853 -0.021588802338 -v -0.001868963242 0.404415190220 -0.034041702747 -v -0.011332273483 0.450134307146 -0.017913401127 -v -0.018124103546 0.431156426668 -0.039218008518 -v -0.011564016342 0.408847093582 -0.052631855011 -v -0.021310806274 0.452264279127 -0.034315645695 -v -0.035163879395 0.433271795511 -0.046046972275 -v -0.032569646835 0.410334706306 -0.058933556080 -v -0.036829233170 0.455296754837 -0.040022969246 -v -0.050311565399 0.433117091656 -0.039737045765 -v -0.049625396729 0.409451037645 -0.056582272053 -v -0.052719354630 0.457712709904 -0.034135818481 -v -0.060839176178 0.430344671011 -0.025123417377 -v -0.060647249222 0.405378311872 -0.044947326183 -v -0.039075374603 0.333637267351 -0.059441745281 -v -0.046819448471 0.377576559782 -0.066945731640 -v -0.057845830917 0.373610943556 -0.056396543980 -v -0.044396162033 0.332225650549 -0.051878690720 -v -0.043912887573 0.330512613058 -0.042705893517 -v -0.057412862778 0.368281006813 -0.038785338402 -v -0.061007261276 0.399160534143 -0.025505304337 -v -0.041280269623 0.328136712313 -0.033087968826 -v -0.046390056610 0.364219039679 -0.022349596024 -v -0.051404714584 0.393975228071 -0.006930351257 -v -0.035102367401 0.325139790773 -0.023742496967 -v -0.033584117889 0.360739827156 -0.011030375957 -v -0.036393165588 0.389957576990 0.006403863430 -v -0.024703979492 0.326273173094 -0.026353597641 -v -0.019546747208 0.364557057619 -0.018281936646 -v -0.016890287399 0.328833460808 -0.035211801529 -v -0.006627321243 0.368008077145 -0.028945624828 -v -0.013489007950 0.331431388855 -0.046256422997 -v -0.002036094666 0.373024463654 -0.045083582401 -v -0.017686605453 0.333469033241 -0.056734740734 -v -0.010092020035 0.377158254385 -0.060950160027 -v -0.028373241425 0.334166795015 -0.062248706818 -v -0.029481172562 0.378683656454 -0.066067218781 -v -0.219955444336 0.842094063759 -0.154961943626 -v -0.235270023346 0.857862532139 -0.137915790081 -v -0.087909221649 1.087654352188 -0.050910711288 -v -0.070798635483 1.104470491409 -0.045316457748 -v -0.247585058212 0.849854946136 -0.153714001179 -v -0.240604400635 0.840870857239 -0.163044929504 -v -0.011443376541 1.160188794136 -0.101308941841 -v 0.036525011063 1.165561199188 -0.098447144032 -v -0.447368383408 0.797736108303 -0.173693537712 -v -0.447412490845 0.796239554882 -0.162157893181 -v -0.443197250366 0.802235960960 -0.155865490437 -v -0.438388586044 0.805791616440 -0.164553344250 -v -0.494693517685 0.893587052822 -0.106214702129 -v -0.495902061462 0.900918126106 -0.105787515640 -v -0.493417978287 0.900910675526 -0.096440255642 -v -0.491146326065 0.891790270805 -0.099022448063 -v -0.489644289017 0.821257293224 -0.123335301876 -v -0.471888542175 0.823015093803 -0.132293999195 -v -0.468766212463 0.813135862350 -0.129689037800 -v -0.484895229340 0.811676740646 -0.120194315910 -v -0.476134061813 0.841621756554 -0.135791420937 -v -0.474495887756 0.832299590111 -0.135184764862 -v -0.494080066681 0.831160485744 -0.126861453056 -v -0.496844291687 0.842333674431 -0.129078328609 -v -0.451151609421 0.806489586830 -0.139960348606 -v -0.466060161591 0.802223086357 -0.129936814308 -v -0.452974319458 0.816859483719 -0.137552082539 -v -0.485681533813 0.851063311100 -0.187404632568 -v -0.502808094025 0.846567988396 -0.173310935497 -v -0.499794721603 0.830486893654 -0.174043655396 -v -0.483735561371 0.833467781544 -0.188756585121 -v -0.491135358810 0.786839187145 -0.137906074524 -v -0.477485179901 0.788113296032 -0.152600586414 -v -0.484442234039 0.794747292995 -0.160152792931 -v -0.501042604446 0.794560611248 -0.139316618443 -v -0.508388519287 0.830364823341 -0.119966745377 -v -0.521482229233 0.819912433624 -0.130728006363 -v -0.523111343384 0.828098714352 -0.121222257614 -v -0.512018680573 0.834384858608 -0.118249833584 -v -0.514605045319 0.853373050690 -0.127098441124 -v -0.517944812775 0.850607991219 -0.124822854996 -v -0.530208826065 0.845044076443 -0.127292752266 -v -0.531853437424 0.844683170319 -0.137332379818 -v -0.500032663345 0.821590065956 -0.116037189960 -v -0.509562015533 0.864964723587 -0.132301747799 -v -0.504422664642 0.864491283894 -0.132351279259 -v -0.500204324722 0.853452622890 -0.129730045795 -v -0.520584106445 0.822443604469 -0.147195518017 -v -0.522242069244 0.828122496605 -0.150109887123 -v -0.526848316193 0.828633189201 -0.143665313721 -v -0.523217201233 0.823370218277 -0.141705751419 -v -0.528179168701 0.850113034248 -0.151596605778 -v -0.527724266052 0.857582092285 -0.153711855412 -v -0.533334732056 0.857348978519 -0.147594749928 -v -0.531985759735 0.850167274475 -0.146348357201 -v -0.507945299149 0.843233942986 -0.123751223087 -v -0.509826183319 0.844902992249 -0.121303021908 -v -0.529620647430 0.830736279488 -0.135385751724 -v -0.531349182129 0.833562910557 -0.126550495625 -v -0.487643718719 0.804054796696 -0.111395001411 -v -0.480391025543 0.801913261414 -0.119697570801 -v -0.480456352234 0.792149066925 -0.122189939022 -v -0.488045692444 0.794178664684 -0.112424015999 -v -0.495940208435 0.784620106220 -0.126145541668 -v -0.499251127243 0.786586403847 -0.129543840885 -v -0.504209518433 0.787554085255 -0.123033821583 -v -0.499408006668 0.785145521164 -0.121613442898 -v -0.510551452637 0.871032297611 -0.138833642006 -v -0.515317440033 0.871675372124 -0.137129485607 -v -0.526596546173 0.864687561989 -0.151889979839 -v -0.530538082123 0.864613473415 -0.148025453091 -v -0.497328281403 0.811198830605 -0.112283110619 -v -0.503155469894 0.790419399738 -0.130545675755 -v -0.506678104401 0.791445076466 -0.125318050385 -v -0.493824243546 0.871466159821 -0.085897326469 -v -0.490470170975 0.869438707829 -0.092285215855 -v -0.485040903091 0.863280296326 -0.091263115406 -v -0.487308979034 0.865945041180 -0.082743287086 -v -0.485924720764 0.855860471725 -0.088013470173 -v -0.489061117172 0.856862902641 -0.081349372864 -v -0.520172119141 0.836955487728 -0.100135803223 -v -0.515067815781 0.840695142746 -0.093722283840 -v -0.506313800812 0.841244280338 -0.101609706879 -v -0.510276794434 0.838908553123 -0.105833172798 -v -0.512242078781 0.857203602791 -0.107409000397 -v -0.522161960602 0.857336878777 -0.099027633667 -v -0.526552677155 0.854199707508 -0.105519115925 -v -0.515424251556 0.854900300503 -0.111687183380 -v -0.508421897888 0.847175776958 -0.111868441105 -v -0.505060672760 0.849078774452 -0.108070075512 -v -0.524366140366 0.847588360310 -0.093832015991 -v -0.527771949768 0.845007956028 -0.098792850971 -v -0.504534959793 0.847885608673 -0.086177408695 -v -0.498050689697 0.852172255516 -0.082087755203 -v -0.490575790405 0.850792109966 -0.091464221478 -v -0.496593952179 0.846407592297 -0.095529913902 -v -0.496419668198 0.867350459099 -0.096872746944 -v -0.503741264343 0.868512868881 -0.087242722511 -v -0.511126995087 0.864330530167 -0.091117858887 -v -0.503080606461 0.863209724426 -0.101341784000 -v -0.495740175247 0.854071259499 -0.103795528412 -v -0.489275217056 0.858667314053 -0.098730802536 -v -0.510396480560 0.857069015503 -0.083190023899 -v -0.506175994873 0.859634041786 -0.081316232681 -v -0.511812210083 0.838328003883 -0.109384715557 -v -0.512324810028 0.836986780167 -0.113109648228 -v -0.523508548737 0.831316888332 -0.112718701363 -v -0.519570350647 0.833538651466 -0.105941951275 -v -0.527900457382 0.853996634483 -0.113405644894 -v -0.530893802643 0.848428845406 -0.119828045368 -v -0.517930030823 0.852390527725 -0.120005369186 -v -0.516858100891 0.853576421738 -0.115721166134 -v -0.510461807251 0.846561253071 -0.116781532764 -v -0.510272741318 0.846948623657 -0.114067971706 -v -0.528704881668 0.833988189697 -0.105706632137 -v -0.529921531677 0.832707405090 -0.110456645489 -v -0.535176277161 0.837255477905 -0.113185763359 -v -0.535221815109 0.839498996735 -0.107395589352 -v -0.535897016525 0.844757020473 -0.115204930305 -v -0.535224437714 0.848018705845 -0.110409140587 -v -0.527960300446 0.836800575256 -0.101769506931 -v -0.532390594482 0.842326819897 -0.102183938026 -v -0.532948493958 0.849078893661 -0.105126917362 -v -0.501554489136 0.843218922615 -0.099216759205 -v -0.507042169571 0.842735946178 -0.091056108475 -v -0.515851497650 0.862206101418 -0.097064733505 -v -0.508196115494 0.859079062939 -0.104793012142 -v -0.501304626465 0.850616335869 -0.106691837311 -v -0.514235734940 0.845977485180 -0.086078166962 -v -0.518186092377 0.844501137733 -0.088461101055 -v -0.522804021835 0.849747896194 -0.088824689388 -v -0.519546508789 0.852388918400 -0.085314571857 -v -0.523418426514 0.855972528458 -0.091820836067 -v -0.520101308823 0.859155178070 -0.089708983898 -v -0.511596202850 0.849000573158 -0.083929896355 -v -0.515213012695 0.854938268661 -0.083392798901 -v -0.516395092010 0.860537409782 -0.087069749832 -v -0.532750368118 0.836167395115 -0.118552982807 -v -0.497567176819 0.865602970123 -0.074603199959 -v -0.496635437012 0.860588312149 -0.074069917202 -v -0.499092817307 0.859558403492 -0.075726687908 -v -0.501167774200 0.863645672798 -0.076683282852 -v -0.499398469925 0.869491815567 -0.076963126659 -v -0.502336740494 0.868161380291 -0.077675879002 -v -0.493256807327 0.858881592751 -0.076175630093 -v -0.492352008820 0.866495013237 -0.076975762844 -v -0.499328136444 0.856431543827 -0.076817274094 -v -0.503676176071 0.861703813076 -0.079042315483 -v -0.503543376923 0.868796229362 -0.080610632896 -v -0.497124195099 0.871228098869 -0.080048918724 -v -0.508443832397 0.800419390202 -0.136265814304 -v -0.511143684387 0.804700791836 -0.140411615372 -v -0.514699935913 0.806024491787 -0.133704960346 -v -0.511139869690 0.801549851894 -0.131215751171 -v -0.524834394455 0.834584176540 -0.149969577789 -v -0.528397083282 0.835094690323 -0.144962668419 -v -0.514429330826 0.810142576694 -0.141759753227 -v -0.517162799835 0.811100900173 -0.136384963989 -v -0.496298074722 0.786881387234 -0.115870833397 -v -0.486750125885 0.785451531410 -0.128098964691 -v -0.527594327927 0.869485437870 -0.141907572746 -v -0.518058300018 0.869149982929 -0.149671852589 -v -0.510817766190 0.799105167389 -0.121699333191 -v -0.512484073639 0.806650936604 -0.113031685352 -v -0.502429008484 0.813118338585 -0.111305117607 -v -0.508829832077 0.828153192997 -0.116886317730 -v -0.518706083298 0.822669982910 -0.117713034153 -v -0.501774787903 0.822176635265 -0.114453732967 -v -0.519619703293 0.812057256699 -0.116438627243 -v -0.517436027527 0.808292090893 -0.126053214073 -v -0.483708858490 0.853024780750 -0.088355422020 -v -0.481112241745 0.850262880325 -0.093426942825 -v -0.475982189178 0.844028592110 -0.091422438622 -v -0.477612257004 0.847269892693 -0.084727108479 -v -0.475871086121 0.837056696415 -0.086321115494 -v -0.478466987610 0.838783323765 -0.080502748489 -v -0.504234790802 0.817612648010 -0.093765556812 -v -0.500945329666 0.822281956673 -0.087224364281 -v -0.490716695786 0.824029862881 -0.093403875828 -v -0.494282245636 0.819924414158 -0.099487662315 -v -0.496157646179 0.841752350330 -0.100961446762 -v -0.505415439606 0.841348707676 -0.095487833023 -v -0.508846998215 0.836988449097 -0.101620197296 -v -0.499357938766 0.838020980358 -0.106621682644 -v -0.492764949799 0.830117106438 -0.105411946774 -v -0.489102363586 0.833834648132 -0.099696338177 -v -0.508481979370 0.830541670322 -0.089690744877 -v -0.510588169098 0.827774941921 -0.093720853329 -v -0.492753744125 0.831151664257 -0.079553246498 -v -0.486364841461 0.835210800171 -0.078461050987 -v -0.479637861252 0.832388997078 -0.086949884892 -v -0.484333038330 0.829082310200 -0.088134169579 -v -0.485946178436 0.848959863186 -0.095764815807 -v -0.492048025131 0.851611673832 -0.087720692158 -v -0.497788429260 0.848133265972 -0.089569866657 -v -0.490402221680 0.846298635006 -0.097313344479 -v -0.483847379684 0.837090373039 -0.096990287304 -v -0.479485511780 0.840040266514 -0.095492541790 -v -0.497706413269 0.841334342957 -0.080382227898 -v -0.493602514267 0.843913137913 -0.079816043377 -v -0.498492002487 0.817435145378 -0.105219185352 -v -0.501165628433 0.814163446426 -0.109083890915 -v -0.511910438538 0.809615671635 -0.104608774185 -v -0.505473136902 0.811411023140 -0.099508881569 -v -0.510790824890 0.835031032562 -0.109548807144 -v -0.516519069672 0.828535556793 -0.111123204231 -v -0.506266832352 0.830387651920 -0.115914404392 -v -0.502544403076 0.833584547043 -0.112453937531 -v -0.499927043915 0.823450028896 -0.114233195782 -v -0.497344493866 0.826164782047 -0.110643565655 -v -0.513412475586 0.815074205399 -0.096650004387 -v -0.516290664673 0.813745021820 -0.099655687809 -v -0.519789934158 0.819998562336 -0.101308584213 -v -0.517743349075 0.822623610497 -0.098065078259 -v -0.519121646881 0.827042996883 -0.104812145233 -v -0.516560077667 0.830451726913 -0.103179037571 -v -0.511471986771 0.818441748619 -0.094288408756 -v -0.514646053314 0.825179815292 -0.095527946949 -v -0.514303207397 0.831783711910 -0.099781036377 -v -0.487943172455 0.827379703522 -0.090247273445 -v -0.495469808578 0.824954450130 -0.082411110401 -v -0.500364780426 0.846157968044 -0.094868063927 -v -0.493069171906 0.843513786793 -0.098693013191 -v -0.487038612366 0.835436344147 -0.097534894943 -v -0.502112865448 0.828593492508 -0.079975128174 -v -0.504857540131 0.826588690281 -0.083056867123 -v -0.508306980133 0.833120644093 -0.085304498672 -v -0.506083965302 0.836166918278 -0.082021951675 -v -0.507864236832 0.840063154697 -0.089241921902 -v -0.505406856537 0.843329131603 -0.087880432606 -v -0.499519109726 0.832336187363 -0.078415036201 -v -0.502271652222 0.839114248753 -0.080325365067 -v -0.502671241760 0.844747602940 -0.085275530815 -v -0.520011425018 0.816879510880 -0.107176601887 -v -0.485849618912 0.848793625832 -0.077213406563 -v -0.484879255295 0.844172120094 -0.075477480888 -v -0.486962318420 0.843352615833 -0.076518177986 -v -0.488926410675 0.847343027592 -0.078180730343 -v -0.487652778625 0.852373063564 -0.079998552799 -v -0.490156412125 0.851481437683 -0.079959809780 -v -0.482032775879 0.841814160347 -0.076701343060 -v -0.481650590897 0.848758876324 -0.079696655273 -v -0.487200260162 0.840355038643 -0.076348960400 -v -0.491241216660 0.845820188522 -0.079050183296 -v -0.491406917572 0.852079093456 -0.082417190075 -v -0.486078977585 0.853447556496 -0.083156108856 -v -0.498555898666 0.789247334003 -0.110209047794 -v -0.490535259247 0.795914649963 -0.107083380222 -v -0.499561071396 0.808594465256 -0.109262883663 -v -0.509321451187 0.801345944405 -0.113677084446 -v -0.491660594940 0.804835021496 -0.106762707233 -v -0.506342411041 0.790087342262 -0.117207169533 -v -0.507618427277 0.792013823986 -0.113375782967 -v -0.489049196243 0.826286792755 -0.079535543919 -v -0.485815525055 0.826620817184 -0.084511041641 -v -0.480561256409 0.821815013885 -0.084118247032 -v -0.483257293701 0.822232902050 -0.077751755714 -v -0.479671239853 0.815304994583 -0.082047581673 -v -0.482170104980 0.815054416656 -0.077047288418 -v -0.498437404633 0.795974731445 -0.094222247601 -v -0.495993852615 0.799155712128 -0.089099407196 -v -0.488581657410 0.803750157356 -0.092741906643 -v -0.489798069000 0.801814615726 -0.097452342510 -v -0.499174118042 0.816335558891 -0.095021665096 -v -0.505331993103 0.810285627842 -0.091094553471 -v -0.508020877838 0.806802392006 -0.096497237682 -v -0.500244140625 0.813882708549 -0.098373711109 -v -0.491198301315 0.810434281826 -0.099174976349 -v -0.490566730499 0.812255382538 -0.095983982086 -v -0.504388093948 0.801935672760 -0.089532196522 -v -0.506303787231 0.799559772015 -0.093178451061 -v -0.490227460861 0.806715846062 -0.080041587353 -v -0.486819744110 0.810494184494 -0.077443838120 -v -0.481586694717 0.811227262020 -0.084623336792 -v -0.484838962555 0.807765960693 -0.087508916855 -v -0.489450216293 0.825551927090 -0.087533473969 -v -0.494817018509 0.822417318821 -0.080430269241 -v -0.498338937759 0.818705558777 -0.082634210587 -v -0.493239879608 0.822486460209 -0.090337991714 -v -0.485663890839 0.816083729267 -0.092872619629 -v -0.482256412506 0.819070279598 -0.089587986469 -v -0.495429277420 0.813326537609 -0.077522575855 -v -0.493692398071 0.815349698067 -0.076042175293 -v -0.490639209747 0.799663007259 -0.100690245628 -v -0.491382598877 0.797495901585 -0.103254914284 -v -0.500654220581 0.789737641811 -0.104475378990 -v -0.497671604156 0.792602598667 -0.098903775215 -v -0.509530782700 0.806396782398 -0.102260172367 -v -0.511167049408 0.801594376564 -0.108417809010 -v -0.500758171082 0.809814274311 -0.105136036873 -v -0.500140190125 0.811406195164 -0.101884782314 -v -0.491745948792 0.806727945805 -0.103401362896 -v -0.492305278778 0.808004617691 -0.101605892181 -v -0.505864143372 0.790762722492 -0.098364591599 -v -0.506949424744 0.789222061634 -0.102397680283 -v -0.511898517609 0.792011439800 -0.104481697083 -v -0.511413574219 0.793921768665 -0.099860727787 -v -0.513942241669 0.797082841396 -0.105452656746 -v -0.513425111771 0.799474656582 -0.101383924484 -v -0.505221366882 0.793554723263 -0.095338940620 -v -0.509412050247 0.796497941017 -0.095882833004 -v -0.511485099792 0.800802588463 -0.097495257854 -v -0.487203598022 0.805865585804 -0.089809119701 -v -0.491508483887 0.801817178726 -0.084747970104 -v -0.501916170120 0.816967248917 -0.087054252625 -v -0.496026515961 0.819197714329 -0.092714369297 -v -0.489030599594 0.813616871834 -0.094238102436 -v -0.496573925018 0.803260147572 -0.081626772881 -v -0.499391555786 0.800740122795 -0.084920167923 -v -0.503435134888 0.803725183010 -0.085128188133 -v -0.500617980957 0.807261526585 -0.080836713314 -v -0.505204677582 0.808161199093 -0.085975766182 -v -0.502797126770 0.812113285065 -0.082701086998 -v -0.494894981384 0.806727290154 -0.079006910324 -v -0.497905254364 0.810785889626 -0.078416407108 -v -0.500154018402 0.814402937889 -0.080199837685 -v -0.509780406952 0.792054593563 -0.109013736248 -v -0.489554882050 0.819736123085 -0.072930335999 -v -0.487940311432 0.816487431526 -0.072609961033 -v -0.489381313324 0.815415918827 -0.073478043079 -v -0.491574764252 0.818117618561 -0.074059128761 -v -0.491600751877 0.822124600410 -0.074348628521 -v -0.493067026138 0.820745110512 -0.075044274330 -v -0.485497951508 0.815698802471 -0.073549985886 -v -0.486885070801 0.821202099323 -0.073756098747 -v -0.488751888275 0.812952458858 -0.073907077312 -v -0.492937803268 0.816626131535 -0.074767291546 -v -0.494431257248 0.821339190006 -0.076288044453 -v -0.491227149963 0.824168622494 -0.075623750687 -v -0.527001857758 0.853478670120 -0.125246942043 -v -0.513896465302 0.857641816139 -0.126969873905 -v -0.517309665680 0.873407602310 -0.133468151093 -v -0.529544591904 0.871562659740 -0.133002638817 -v -0.510344266891 0.866749882698 -0.130797505379 -v -0.535715341568 0.858517348766 -0.139212429523 -v -0.535772323608 0.861216902733 -0.129334509373 -v -0.490445613861 0.890650033951 -0.100051939487 -v -0.488363265991 0.888513207436 -0.107455074787 -v -0.485354423523 0.880579829216 -0.108673691750 -v -0.485455274582 0.882985472679 -0.099698960781 -v -0.487403631210 0.872754931450 -0.105823457241 -v -0.488933801651 0.873876035213 -0.098851382732 -v -0.518436908722 0.863012790680 -0.108661413193 -v -0.512920618057 0.866162419319 -0.104191660881 -v -0.507155895233 0.865417718887 -0.113856613636 -v -0.510566711426 0.863865315914 -0.116527736187 -v -0.512574672699 0.881888926029 -0.117601990700 -v -0.519688844681 0.883390605450 -0.107507109642 -v -0.524630069733 0.880152225494 -0.113091707230 -v -0.515925884247 0.879324555397 -0.120808780193 -v -0.509762763977 0.871237039566 -0.122120618820 -v -0.506671428680 0.872891902924 -0.120059609413 -v -0.521101236343 0.874487102032 -0.101826131344 -v -0.524887323380 0.872092723846 -0.105790376663 -v -0.502747774124 0.870004713535 -0.100400567055 -v -0.497266054153 0.871715247631 -0.097897529602 -v -0.492583751678 0.869514763355 -0.108082056046 -v -0.498463630676 0.867662549019 -0.110751748085 -v -0.494890928268 0.888140499592 -0.110826432705 -v -0.499839544296 0.889504313469 -0.100029766560 -v -0.507523536682 0.887580394745 -0.102457940578 -v -0.502919435501 0.885920166969 -0.114045023918 -v -0.498455524445 0.875417351723 -0.118292808533 -v -0.491332054138 0.877597153187 -0.115070879459 -v -0.506424903870 0.879839777946 -0.096214175224 -v -0.503129482269 0.880639374256 -0.095109224319 -v -0.512672424316 0.862300992012 -0.120484471321 -v -0.513113737106 0.860535264015 -0.123115837574 -v -0.525039196014 0.856878221035 -0.118569016457 -v -0.519091129303 0.858681201935 -0.114477872849 -v -0.526840448380 0.879119575024 -0.120443284512 -v -0.530992031097 0.874435842037 -0.125046432018 -v -0.518256187439 0.875537931919 -0.128518223763 -v -0.517742633820 0.876998245716 -0.124922633171 -v -0.511662721634 0.868683815002 -0.127072453499 -v -0.511864900589 0.869614481926 -0.124864697456 -v -0.530849933624 0.860190629959 -0.111503541470 -v -0.533360242844 0.859168589115 -0.115616202354 -v -0.536691904068 0.865351617336 -0.116629421711 -v -0.534475564957 0.867561042309 -0.111754179001 -v -0.535916090012 0.871988415718 -0.118930697441 -v -0.533593416214 0.874997556210 -0.115182757378 -v -0.527114391327 0.863506555557 -0.108078002930 -v -0.529962301254 0.869924604893 -0.107841134071 -v -0.530357837677 0.875990808010 -0.111109972000 -v -0.503102540970 0.866510391235 -0.113218367100 -v -0.505452632904 0.866206705570 -0.104708135128 -v -0.513443470001 0.887060940266 -0.106990933418 -v -0.508520841599 0.883631944656 -0.116348564625 -v -0.503959178925 0.873957514763 -0.119046747684 -v -0.510499000549 0.870763242245 -0.097471833229 -v -0.514724016190 0.870366811752 -0.098390698433 -v -0.518878698349 0.876383900642 -0.097725093365 -v -0.514991760254 0.878054201603 -0.095596671104 -v -0.519540309906 0.882226943970 -0.100633978844 -v -0.515974521637 0.884334146976 -0.099541544914 -v -0.507736682892 0.872971475124 -0.096328496933 -v -0.510526895523 0.879325091839 -0.095016777515 -v -0.511901855469 0.884887933731 -0.097839653492 -v -0.535580873489 0.863515138626 -0.121753752232 -v -0.494115114212 0.883353888988 -0.090229034424 -v -0.494159221649 0.878465473652 -0.090765476227 -v -0.496655464172 0.878225266933 -0.091974556446 -v -0.497776508331 0.882385611534 -0.092055082321 -v -0.494970798492 0.887757301331 -0.091351509094 -v -0.497639894485 0.886616647243 -0.092495083809 -v -0.491739749908 0.876264393330 -0.093018054962 -v -0.489335536957 0.883648872375 -0.093107581139 -v -0.497393131256 0.875543773174 -0.093272686005 -v -0.500410795212 0.881527364254 -0.093731045723 -v -0.499048471451 0.888204634190 -0.094248950481 -v -0.492660522461 0.889721930027 -0.094091176987 -v -0.521483898163 0.842776119709 -0.155532121658 -v -0.518549919128 0.858851313591 -0.158480763435 -v -0.513115406036 0.815885305405 -0.150368809700 -v -0.514750003815 0.828490138054 -0.158624708652 -v -0.504255294800 0.803942263126 -0.149980843067 -v -0.471243858337 0.786971271038 -0.142925024033 -v -0.466823101044 0.792440652847 -0.134708881378 -v -0.454370021820 0.826037108898 -0.138828337193 -v -0.495823860168 0.816522121429 -0.171279489994 -v -0.490122318268 0.804616093636 -0.166800975800 -v -0.501922845840 0.864825129509 -0.167882800102 -v -0.488729238510 0.869901716709 -0.140693187714 -v -0.494021654129 0.873752593994 -0.152330935001 -v -0.487847566605 0.878740549088 -0.152684986591 -v -0.480398416519 0.872110724449 -0.138898909092 -v -0.463868141174 0.866027951241 -0.132292509079 -v -0.478146791458 0.862194061279 -0.133633494377 -v -0.463702440262 0.875368595123 -0.127856612206 -v -0.453201293945 0.882918894291 -0.131946742535 -v -0.446355819702 0.873552322388 -0.141134619713 -v -0.483682394028 0.883540391922 -0.145150899887 -v -0.476632833481 0.876343607903 -0.133325040340 -v -0.484167098999 0.901457369328 -0.093008697033 -v -0.485260963440 0.893595635891 -0.095105886459 -v -0.483138322830 0.889306485653 -0.131258606911 -v -0.477747440338 0.882396876812 -0.121179759502 -v -0.476070404053 0.880022823811 -0.127019524574 -v -0.481888771057 0.887317419052 -0.138192296028 -v -0.468255043030 0.884616315365 -0.116226017475 -v -0.464697837830 0.881538629532 -0.122920870781 -v -0.479435443878 0.900566041470 -0.136166751385 -v -0.477606296539 0.898043036461 -0.145556926727 -v -0.468045234680 0.902096092701 -0.133089959621 -v -0.465980529785 0.900569677353 -0.139554977417 -v -0.462095737457 0.895440816879 -0.121656596661 -v -0.457749605179 0.892096400261 -0.130192101002 -v -0.470758438110 0.897547125816 -0.155327796936 -v -0.466237306595 0.894115865231 -0.159044146538 -v -0.457171916962 0.892076790333 -0.153369426727 -v -0.461186885834 0.897225439548 -0.149793088436 -v -0.450381755829 0.887220442295 -0.144794583321 -v -0.453635215759 0.891810834408 -0.140942871571 -v -0.480525970459 0.891566216946 -0.156198561192 -v -0.471389532089 0.900366127491 -0.149930894375 -v -0.463864564896 0.900258302689 -0.145290255547 -v -0.457410335541 0.896189451218 -0.139161109924 -v -0.469795703888 0.888008773327 -0.165396869183 -v -0.452988624573 0.883881807327 -0.157703280449 -v -0.491194486618 0.891927838326 -0.114754319191 -v -0.486534357071 0.885707378387 -0.106756806374 -v -0.479014396667 0.889679074287 -0.100693225861 -v -0.489616870880 0.903515696526 -0.117441117764 -v -0.487568616867 0.908877730370 -0.099188625813 -v -0.490461826324 0.908248662949 -0.103589415550 -v -0.486899375916 0.906276345253 -0.106632411480 -v -0.481706142426 0.906772732735 -0.103209018707 -v -0.484368562698 0.908297657967 -0.096467256546 -v -0.480246782303 0.906286239624 -0.099046111107 -v -0.472922801971 0.901211500168 -0.101609766483 -v -0.481368541718 0.883780658245 -0.114653468132 -v -0.486560106277 0.890575349331 -0.123603880405 -v -0.473132371902 0.886498153210 -0.109143614769 -v -0.485536098480 0.901406943798 -0.128164887428 -v -0.480238437653 0.907655954361 -0.126654922962 -v -0.476631164551 0.906661093235 -0.131565809250 -v -0.469987869263 0.906214416027 -0.128223299980 -v -0.473164319992 0.908138692379 -0.122179150581 -v -0.465127468109 0.902755975723 -0.122632205486 -v -0.467630147934 0.903878688812 -0.116376280785 -v -0.467125654221 0.895816802979 -0.111212134361 -v -0.482595682144 0.906823217869 -0.120295464993 -v -0.477108955383 0.906865596771 -0.115525126457 -v -0.472041606903 0.904061913490 -0.110747873783 -v -0.477966785431 0.905460000038 -0.110133111477 -v -0.493883132935 0.907011985779 -0.104439914227 -v -0.491958379745 0.907425343990 -0.096913754940 -v -0.489140272141 0.905874848366 -0.111298918724 -v -0.479014158249 0.906400084496 -0.107349276543 -v -0.476996898651 0.905042469501 -0.099129199982 -v -0.484606742859 0.906890451908 -0.093938052654 -v -0.491485834122 0.862887859344 -0.133998870850 -v -0.478189468384 0.851019322872 -0.133088052273 -v -0.436126470566 0.836560726166 -0.156523883343 -v -0.442461729050 0.835687577724 -0.147658109665 -v -0.441426515579 0.845188915730 -0.148403167725 -v -0.437577724457 0.854609191418 -0.159161508083 -v -0.454926490784 0.834215760231 -0.140588104725 -v -0.462005615234 0.792235910892 -0.166105270386 -v -0.456657409668 0.791631460190 -0.155758082867 -v -0.483422994614 0.867121934891 -0.181242167950 -v -0.468945980072 0.855017066002 -0.193509101868 -v -0.462913751602 0.870561540127 -0.183496356010 -v -0.491529464722 0.874752402306 -0.165132880211 -v -0.487841367722 0.878770470619 -0.162872314453 -v -0.468900203705 0.836523592472 -0.196922063828 -v -0.479998111725 0.818049311638 -0.186679184437 -v -0.499879121780 0.870677828789 -0.139983534813 -v -0.504315376282 0.871536970139 -0.151580274105 -v -0.454349756241 0.840840578079 -0.139953255653 -v -0.480731725693 0.877718329430 -0.174314856529 -v -0.464861869812 0.879262804985 -0.174113869667 -v -0.446362018585 0.868979811668 -0.170653223991 -v -0.449486732483 0.874917387962 -0.165948867798 -v -0.440111875534 0.863788783550 -0.154974460602 -v -0.441115617752 0.851662218571 -0.146024465561 -v -0.454034090042 0.845933496952 -0.138140499592 -v -0.456007719040 0.854448795319 -0.133829414845 -v -0.469702482224 0.854526937008 -0.132327675819 -v -0.444778442383 0.858243584633 -0.139310777187 -v -0.481812000275 0.882776081562 -0.167174339294 -v -0.484746932983 0.884817302227 -0.160003304482 -v -0.442131519318 0.811856746674 -0.148359179497 -v -0.436752319336 0.819676995277 -0.155522286892 -v -0.452622652054 0.797102570534 -0.146845281124 -v -0.443253278732 0.825838088989 -0.145939826965 -v -0.444576740265 0.818954288960 -0.143559813499 -v -0.433326005936 0.807289421558 -0.173588871956 -v -0.441542625427 0.803750753403 -0.187457442284 -v -0.430660247803 0.819438576698 -0.164661586285 -v -0.430188417435 0.836086511612 -0.162424981594 -v -0.432472229004 0.853630959988 -0.163688778877 -v -0.439163208008 0.866289258003 -0.172386646271 -v -0.448523044586 0.868499755859 -0.185838401318 -v -0.454426765442 0.857727229595 -0.197017431259 -v -0.454931259155 0.839325785637 -0.202164053917 -v -0.465736627579 0.819396853447 -0.194947898388 -v -0.450971364975 0.817552566528 -0.198323130608 -v -0.456123352051 0.800768375397 -0.183851480484 -v -0.468741416931 0.797707617283 -0.175054907799 -v -0.425196409225 0.807017326355 -0.182153224945 -v -0.429808616638 0.808018207550 -0.197672486305 -v -0.423538684845 0.817356407642 -0.170044660568 -v -0.423536777496 0.833735704422 -0.165797650814 -v -0.425173997879 0.851301014423 -0.165531635284 -v -0.430070877075 0.863844513893 -0.173078656197 -v -0.436095714569 0.867850482464 -0.187229573727 -v -0.440057992935 0.861827850342 -0.201652050018 -v -0.439754009247 0.844789445400 -0.210174918175 -v -0.435653448105 0.823165953159 -0.207971274853 -v -0.419240474701 0.811311781406 -0.205702304840 -v -0.414561510086 0.807009160519 -0.189636647701 -v -0.403192281723 0.809433162212 -0.199932932854 -v -0.409330129623 0.817718327045 -0.216658353806 -v -0.413339853287 0.815283596516 -0.174596428871 -v -0.399246454239 0.813498079777 -0.181282222271 -v -0.413203001022 0.829875349998 -0.168070018291 -v -0.397543668747 0.824719786644 -0.171226143837 -v -0.395318984985 0.834834337234 -0.168890595436 -v -0.408400058746 0.846953988075 -0.167888164520 -v -0.413450241089 0.863622665405 -0.173395872116 -v -0.419510841370 0.872239351273 -0.188069701195 -v -0.424756288528 0.871203422546 -0.206108510494 -v -0.424194335938 0.854732930660 -0.219132661819 -v -0.414286136627 0.851325511932 -0.227738976479 -v -0.424114227295 0.828399658203 -0.215525388718 -v -0.413206815720 0.834980130196 -0.225028336048 -v -0.474735736847 0.806489527225 -0.181779563427 -v -0.461838483810 0.807741761208 -0.190207779408 -v -0.450213432312 0.803499877453 -0.189132690430 -v -0.453882694244 0.808152139187 -0.192983090878 -v -0.063398599625 0.425415545702 -0.004801809788 -v -0.057441711426 0.421231210232 0.011059165001 -v -0.042950868607 0.417842894793 0.021519958973 -v 0.144121408463 0.511780261993 0.077085554600 -v 0.108297348022 0.528908789158 0.076607823372 -v 0.103316783905 0.511069953442 0.013130068779 -v 0.120876550674 0.499709635973 0.015783727169 -v 0.143322706223 0.510246276855 0.023608624935 -v 0.161252737045 0.523530781269 0.064749538898 -v 0.152065515518 0.501725971699 -0.009824156761 -v 0.140231609344 0.498346298933 -0.030532300472 -v 0.192918300629 0.507425546646 -0.030843675137 -v 0.185611486435 0.508959054947 -0.011636078358 -v 0.187336921692 0.531630814075 -0.041304111481 -v 0.124450206757 0.523272991180 -0.047710359097 -v 0.227248430252 0.552403509617 -0.004147112370 -v 0.228659629822 0.532396197319 -0.002932310104 -v 0.227637529373 0.592922449112 0.034270524979 -v 0.233801364899 0.565752506256 0.035560011864 -v 0.223552703857 0.587897717953 -0.008055388927 -v 0.221391916275 0.630149424076 0.032777488232 -v 0.188503026962 0.624325811863 0.092208683491 -v 0.197622060776 0.591138243675 0.090726375580 -v 0.214549303055 0.686934411526 0.045682489872 -v 0.187195301056 0.673267960548 0.099526941776 -v 0.216737031937 0.692575335503 -0.008495330811 -v 0.199777126312 0.701083362103 -0.008754312992 -v 0.194094419479 0.686676740646 0.034240126610 -v 0.220711708069 0.636359512806 -0.020351350307 -v 0.182755708694 0.725424706936 -0.089372277260 -v 0.179335832596 0.729352295399 -0.071519851685 -v 0.187209367752 0.650559663773 -0.072877883911 -v 0.166259288788 0.675132751465 0.078442573547 -v 0.195732593536 0.668351173401 0.035658538342 -v 0.165970325470 0.662057161331 0.079006195068 -v 0.184274196625 0.697052001953 -0.025637030602 -v 0.136685848236 0.621061325073 0.124828457832 -v 0.146819353104 0.581296682358 0.115078270435 -v 0.209793090820 0.565983176231 0.086855173111 -v 0.165661096573 0.548517227173 0.104174733162 -v 0.134027719498 0.671311855316 0.129685342312 -v 0.078870058060 0.624179244041 0.127473473549 -v 0.088960170746 0.573084473610 0.105961620808 -v 0.077410221100 0.682400047779 0.141914546490 -v 0.184307813644 0.588923692703 -0.058013796806 -v 0.129453897476 0.595893144608 -0.086390793324 -v 0.133975744247 0.663929998875 -0.106234252453 -v 0.236451148987 0.552949547768 0.037623882294 -v 0.224511861801 0.541902184486 0.036363959312 -v 0.211948394775 0.525437772274 0.006383121014 -v 0.214318037033 0.545253038406 0.069983601570 -v 0.212549924850 0.552964806557 0.068517923355 -v 0.224463939667 0.549749970436 0.033728003502 -v 0.218957901001 0.557131946087 0.083203673363 -v 0.187869310379 0.532874941826 0.092133939266 -v 0.187714338303 0.534057557583 0.080063939095 -v 0.181240797043 0.545281291008 0.081068098545 -v 0.146420955658 0.531102359295 0.067861676216 -v 0.212937355042 0.534900724888 0.000919044018 -v 0.184135675430 0.516894340515 -0.018340229988 -v 0.071259021759 0.544855475426 -0.057795166969 -v 0.062549352646 0.523616433144 0.002657234669 -v 0.072495937347 0.605195105076 -0.099032998085 -v 0.012754201889 0.670661449432 -0.129763662815 -v 0.074255228043 0.671743631363 -0.122924923897 -v 0.016004562378 0.604284882545 -0.108093738556 -v -0.047175407410 0.665716767311 -0.120963096619 -v -0.047187089920 0.735366821289 -0.127462327480 -v 0.014084577560 0.746303260326 -0.145008087158 -v -0.093496322632 0.661609470844 -0.084233760834 -v -0.096379756927 0.725130677223 -0.084452211857 -v -0.035370826721 0.739451408386 -0.115991532803 -v 0.016326665878 0.748082160950 -0.129412829876 -v -0.076249361038 0.729390442371 -0.078382790089 -v -0.043362140656 0.605586290359 -0.104780077934 -v -0.089107990265 0.608498692513 -0.073513865471 -v -0.114396095276 0.659402668476 -0.028737843037 -v -0.114691495895 0.720096588135 -0.025828123093 -v -0.112749338150 0.613461971283 -0.024391472340 -v 0.026057243347 0.539770305157 -0.068712770939 -v -0.036364793777 0.558640837669 -0.091128528118 -v 0.081735372543 0.748860776424 -0.142071723938 -v 0.138632535934 0.742601990700 -0.123913228512 -v 0.074531555176 0.752696514130 -0.124717712402 -v 0.130490541458 0.744501113892 -0.108744025230 -v 0.031629323959 0.521139383316 -0.005045592785 -v 0.039030313492 0.551695644855 0.056075632572 -v -0.001458644867 0.553142666817 0.050433158875 -v 0.022727251053 0.514308512211 -0.007078170776 -v 0.018694400787 0.521275639534 -0.064219474792 -v -0.013375759125 0.545891344547 0.025897085667 -v 0.010625362396 0.528762698174 -0.008753895760 -v -0.013785123825 0.537784159184 0.044802665710 -v -0.003431797028 0.556365251541 0.031631588936 -v 0.021438360214 0.537024855614 -0.007674217224 -v -0.044837236404 0.555213034153 0.041083216667 -v -0.037632226944 0.567453145981 0.046529829502 -v -0.051511764526 0.550408124924 0.056568264961 -v -0.049501657486 0.569334208965 0.059367895126 -v -0.012590885162 0.593995332718 0.081816494465 -v -0.056488513947 0.606606721878 0.067150175571 -v 0.028929233551 0.585341632366 0.093791067600 -v 0.008466243744 0.527554392815 -0.046013593674 -v 0.015324592590 0.539409756660 -0.046251296997 -v -0.025128364563 0.548998892307 -0.059863686562 -v -0.028495788574 0.536334693432 -0.059524655342 -v -0.034542560577 0.529292702675 -0.083323836327 -v 0.145991802216 0.508340239525 -0.014416158199 -v 0.131390333176 0.516479372978 0.021855235100 -v 0.026699304581 0.634563446045 0.117274522781 -v -0.020232677460 0.642315804958 0.100721597672 -v -0.026278018951 0.702590823174 0.111697435379 -v -0.068937778473 0.706630170345 0.078983545303 -v -0.064911603928 0.651495337486 0.071269571781 -v -0.015012741089 0.704616785049 0.095527708530 -v -0.054348468781 0.709064245224 0.065617680550 -v 0.026480436325 0.697825789452 0.111364364624 -v 0.025828838348 0.691604137421 0.109849214554 -v -0.014955997467 0.698180437088 0.094332814217 -v 0.071362495422 0.688030838966 0.115027904510 -v 0.069956779480 0.677348077297 0.113705933094 -v 0.121142864227 0.674957156181 0.104752779007 -v 0.119457006454 0.664903819561 0.103474259377 -v 0.021538257599 0.694689214230 0.131033778191 -v -0.053185701370 0.703009426594 0.064263105392 -v -0.084846496582 0.713242530823 0.025584518909 -v -0.102933645248 0.712332844734 0.035015225410 -v -0.095738649368 0.717043399811 -0.024513781071 -v -0.100670337677 0.658007621765 0.027561366558 -v -0.096192121506 0.614809751511 0.028727471828 -v -0.093750953674 0.575753808022 0.032837092876 -v -0.107775926590 0.575954735279 -0.015404582024 -v -0.076748132706 0.721031785011 -0.079203486443 -v -0.095304489136 0.708831727505 -0.024215877056 -v -0.035797357559 0.727729797363 -0.117839038372 -v 0.016345024109 0.738378584385 -0.135166823864 -v -0.084352016449 0.707949042320 0.025263905525 -v -0.074731111526 0.537435054779 -0.053000748158 -v -0.060385465622 0.543911695480 -0.041588306427 -v -0.085829257965 0.563987195492 -0.064947962761 -v -0.100173950195 0.556139528751 -0.010330975056 -v -0.076323747635 0.554702341557 -0.007672071457 -v -0.072488784790 0.558982849121 0.027619063854 -v -0.093396186829 0.559440493584 0.031786739826 -v -0.076028823853 0.564334809780 -0.006530702114 -v -0.068377733231 0.567896723747 0.030334770679 -v -0.061259269714 0.555227398872 -0.041971862316 -v 0.073889255524 0.745370209217 -0.123060703278 -v 0.128804206848 0.738630473614 -0.107519149780 -v 0.170720815659 0.713177621365 -0.074004113674 -v 0.014654159546 0.516860008240 -0.008520841599 -v 0.013562679291 0.518869280815 -0.057164371014 -v -0.016606330872 0.536776065826 0.037213981152 -v -0.049576044083 0.547559082508 0.050266206264 -v -0.032561779022 0.526100814342 -0.075417101383 -v -0.081507205963 0.541957616806 -0.059140264988 -v -0.090506315231 0.551226019859 -0.008307635784 -v -0.086373806000 0.554394304752 0.030092954636 -v 0.154227733612 0.513570308685 0.073047876358 -v 0.132213592529 0.500396609306 0.018915951252 -v 0.146581411362 0.496055126190 -0.020876288414 -v 0.191246986389 0.503775417805 -0.022085011005 -v 0.222658157349 0.525225639343 0.000867187977 -v 0.230988979340 0.543813467026 0.037524938583 -v 0.219683170319 0.549111723900 0.076172590256 -v 0.182136535645 0.536433517933 0.100669324398 -v 0.046369791031 0.719563126564 0.135822176933 -v 0.042241811752 0.721289813519 0.120435237885 -v -0.003053903580 0.735716164112 0.113252401352 -v -0.001557350159 0.734151005745 0.128390729427 -v 0.048724651337 0.693842947483 0.145092248917 -v 0.088016271591 0.680101275444 0.143559694290 -v 0.088751792908 0.712511181831 0.134645402431 -v -0.005078792572 0.687308907509 0.133116126060 -v 0.005204916000 0.678244352341 0.114929139614 -v 0.045290470123 0.679847002029 0.130735397339 -v -0.046638011932 0.679906129837 0.107797205448 -v -0.036025047302 0.673013865948 0.093445062637 -v -0.047019481659 0.748887658119 0.117437124252 -v -0.043670654297 0.749698400497 0.105795860291 -v -0.083326578140 0.758892953396 0.081229805946 -v -0.092339754105 0.758642017841 0.089627742767 -v -0.084635972977 0.674705922604 0.074784040451 -v -0.118670225143 0.769500553608 0.044728934765 -v -0.110567569733 0.675210475922 0.032601892948 -v -0.073696851730 0.668749451637 0.062748491764 -v -0.096913099289 0.669786691666 0.024165332317 -v -0.136384248734 0.778806865215 -0.006764948368 -v -0.125165224075 0.685560584068 -0.010455846786 -v -0.128728628159 0.779637575150 -0.004121005535 -v -0.123834848404 0.788750588894 -0.051987946033 -v -0.134121894836 0.787187457085 -0.055941343307 -v -0.112501621246 0.770408868790 0.043770790100 -v -0.125114917755 0.696647584438 -0.048348546028 -v 0.088402271271 0.679888308048 0.132619023323 -v 0.127837419510 0.673484921455 0.119722843170 -v 0.132176876068 0.673645257950 0.122276902199 -v 0.162997484207 0.673051953316 0.104590058327 -v 0.168073177338 0.673548042774 0.111319541931 -v 0.194190502167 0.675714135170 0.075663864613 -v 0.201750755310 0.681370317936 0.081253111362 -v 0.160883426666 0.700167834759 0.107342004776 -v 0.126739978790 0.702453672886 0.123044371605 -v 0.196573019028 0.701241195202 0.081610202789 -v 0.218851804733 0.692234337330 0.023782670498 -v 0.218031644821 0.722697138786 0.022761344910 -v 0.211975812912 0.697270512581 -0.019005358219 -v 0.210978746414 0.684415698051 0.022575974464 -v 0.206652164459 0.696023881435 -0.015635728836 -v 0.217346906662 0.742312967777 -0.024935722351 -v 0.212719678879 0.723642468452 0.022974371910 -v 0.189186811447 0.703710496426 0.071625590324 -v 0.151532173157 0.701240718365 0.096213757992 -v 0.119452953339 0.703918457031 0.109877347946 -v 0.084906578064 0.714441061020 0.121117770672 -v -0.109468936920 0.675620913506 -0.013445198536 -v -0.102214574814 0.688136637211 -0.049785196781 -v -0.112360954285 0.709139764309 -0.096938610077 -v -0.090363025665 0.703007459641 -0.084746301174 -v -0.079424858093 0.723271906376 -0.131462454796 -v -0.063344240189 0.716237366199 -0.108357429504 -v -0.031183481216 0.732107281685 -0.152232766151 -v -0.028877019882 0.723726272583 -0.136132776737 -v 0.020634174347 0.744759976864 -0.156958043575 -v 0.014694929123 0.733487784863 -0.142659604549 -v 0.069174766541 0.743137419224 -0.152602612972 -v 0.061331748962 0.735695242882 -0.140975654125 -v 0.110146522522 0.735085666180 -0.144149661064 -v 0.103978872299 0.731820046902 -0.132717370987 -v 0.077984094620 0.798910439014 -0.141461968422 -v 0.119859457016 0.790866315365 -0.137311816216 -v 0.074426889420 0.802294850349 -0.135301411152 -v 0.116223812103 0.793579339981 -0.130329132080 -v 0.161331653595 0.781449317932 -0.127611219883 -v 0.152729034424 0.728924751282 -0.130435585976 -v 0.157443046570 0.783650875092 -0.121536970139 -v 0.016957759857 0.807849287987 -0.168082594872 -v 0.013961553574 0.810384929180 -0.162219345570 -v 0.142093658447 0.720312654972 -0.115514278412 -v 0.183982133865 0.712360918522 -0.110098004341 -v 0.172728776932 0.703007578850 -0.095244884491 -v 0.204134464264 0.694908976555 -0.070124804974 -v 0.194279670715 0.698028326035 -0.065750300884 -v 0.193339109421 0.770651638508 -0.104809045792 -v 0.212558984756 0.760952532291 -0.071953296661 -v -0.037868022919 0.804407358170 -0.172462224960 -v -0.085999965668 0.798096537590 -0.150223016739 -v -0.079912900925 0.801035761833 -0.145433545113 -v -0.039311408997 0.806997716427 -0.165538191795 -v -0.114581584930 0.791720926762 -0.122836530209 -v -0.107570171356 0.793677270412 -0.103108108044 -v 0.188315153122 0.773532092571 -0.101306200027 -v 0.206870555878 0.763117253780 -0.069325089455 -v 0.211477041245 0.744883477688 -0.024265110493 -v 0.042490959167 0.714094579220 0.143952012062 -v 0.087229490280 0.708064198494 0.141458809376 -v -0.003680706024 0.725511908531 0.134795546532 -v -0.046833276749 0.736211478710 0.117370963097 -v -0.090959787369 0.743731617928 0.091760039330 -v -0.118830442429 0.753062367439 0.045624971390 -v -0.137614011765 0.761805653572 -0.004316985607 -v -0.138007164001 0.771108925343 -0.055927753448 -v 0.164827346802 0.696167469025 0.115181803703 -v 0.129087686539 0.698045313358 0.129442453384 -v 0.202077627182 0.697257161140 0.083701729774 -v 0.223474979401 0.716901838779 0.021489858627 -v 0.219713687897 0.734807431698 -0.024288654327 -v 0.116148948669 0.780359745026 -0.140539228916 -v 0.075758695602 0.788216233253 -0.143896400928 -v 0.158277511597 0.770472466946 -0.130922555923 -v 0.016254663467 0.794478595257 -0.169810354710 -v 0.214664697647 0.750561535358 -0.070789575577 -v 0.193098306656 0.760572731495 -0.107543230057 -v -0.038340330124 0.789423942566 -0.169972777367 -v -0.089158058167 0.786127924919 -0.148080706596 -v -0.117129564285 0.774500608444 -0.117468833923 -v 0.042947053909 0.680678486824 0.141971707344 -v 0.088331699371 0.690217196941 0.148079514503 -v 0.003902912140 0.677657604218 0.129070520401 -v -0.041256189346 0.671179771423 0.103981673717 -v -0.082117557526 0.666609048843 0.067920327187 -v -0.102604150772 0.668240845203 0.030974626541 -v -0.117699861526 0.673860788345 -0.010850131512 -v -0.117666482925 0.687893807888 -0.057794094086 -v 0.130661725998 0.680747628212 0.129106581211 -v 0.167012929916 0.680982887745 0.119741201401 -v 0.203903198242 0.687600016594 0.084002554417 -v 0.223474740982 0.696553647518 0.024260759354 -v 0.218124628067 0.702928543091 -0.021467387676 -v -0.105328559875 0.700765669346 -0.090611577034 -v -0.074398279190 0.714329957962 -0.125499725342 -v -0.027653694153 0.722540020943 -0.144668102264 -v 0.022192239761 0.732428669930 -0.150135040283 -v 0.065891504288 0.733176171780 -0.148831009865 -v 0.109828948975 0.726947844028 -0.140057563782 -v 0.145726919174 0.717888236046 -0.127151072025 -v 0.178150177002 0.702635169029 -0.105906605721 -v 0.208762645721 0.699994683266 -0.072454273701 -v 0.474818944931 0.829751849174 0.080761909485 -v 0.447371721268 0.827144682407 0.082335829735 -v 0.436402082443 0.801355779171 0.076726853848 -v 0.437137126923 0.782028198242 0.062518715858 -v 0.449114084244 0.774479269981 0.043720185757 -v 0.466235399246 0.780543923378 0.026742458344 -v 0.482433199883 0.796503424644 0.020002663136 -v 0.497534036636 0.817176282406 0.030400276184 -v 0.490592956543 0.825681328773 0.062343478203 -v 0.416083812714 0.856479287148 0.063238620758 -v 0.397818565369 0.822540879250 0.058679580688 -v 0.394402980804 0.790257930756 0.037392973900 -v 0.409307241440 0.778394103050 -0.000016272068 -v 0.435056686401 0.793707430363 -0.030144393444 -v 0.461454987526 0.821685552597 -0.037738919258 -v 0.478555798531 0.853732824326 -0.014944911003 -v 0.468921065331 0.879577338696 0.027264356613 -v 0.445375442505 0.880728542805 0.053184807301 -v 0.466699838638 0.886996567249 -0.046786844730 -v 0.444378852844 0.847988784313 -0.076629161835 -v 0.406841993332 0.809575557709 -0.076438903809 -v 0.371905088425 0.787828385830 -0.042897462845 -v 0.357719540596 0.804510772228 0.005992591381 -v 0.362805366516 0.843034982681 0.036714971066 -v 0.391008257866 0.879716992378 0.041662096977 -v 0.425895571709 0.907973527908 0.033029556274 -v 0.459516048431 0.908767938614 0.004759609699 -v 0.474973201752 0.818710982800 0.074997305870 -v 0.461808919907 0.809670209885 0.079118371010 -v 0.456480264664 0.798067808151 0.076258957386 -v 0.455782771111 0.786437451839 0.067734181881 -v 0.461717367172 0.781551599503 0.053859353065 -v 0.471699953079 0.783859133720 0.044202029705 -v 0.482946038246 0.793918967247 0.038748741150 -v 0.489899158478 0.805950462818 0.046118319035 -v 0.486937761307 0.816467463970 0.063097000122 -v 0.441228270531 0.887848794460 -0.051129221916 -v 0.419926643372 0.855345606804 -0.080606341362 -v 0.393717527390 0.828494906425 -0.076067388058 -v 0.370517253876 0.811828851700 -0.047418713570 -v 0.361316323280 0.823268711567 -0.005200862885 -v 0.369323611259 0.850542843342 0.018845379353 -v 0.388053059578 0.882371962070 0.021297752857 -v 0.414115905762 0.906186938286 0.015702068806 -v 0.435689449310 0.907421112061 -0.006201267242 -v 0.457625389099 0.893979549408 -0.053317129612 -v 0.432103991508 0.851549267769 -0.084864497185 -v 0.397927403450 0.816684424877 -0.084416866302 -v 0.365631699562 0.796897709370 -0.048830389977 -v 0.351232051849 0.811093628407 -0.000877141953 -v 0.357836484909 0.846324503422 0.031680703163 -v 0.384871840477 0.884247660637 0.031613469124 -v 0.419532299042 0.913497269154 0.023943066597 -v 0.448849439621 0.918320059776 -0.001152694225 -v 0.468704581261 0.841255605221 0.076112985611 -v 0.455493927002 0.817524373531 0.086187958717 -v 0.447009682655 0.798206448555 0.080420792103 -v 0.444962501526 0.781422913074 0.068031430244 -v 0.455179333687 0.774285674095 0.049756467342 -v 0.471616744995 0.778853714466 0.036065757275 -v 0.486483812332 0.790827751160 0.029048442841 -v 0.496397018433 0.808861613274 0.039405584335 -v 0.487864613533 0.835947692394 0.054146111012 -v 0.153582811356 1.146741271019 -0.023735761642 -v 0.146487712860 1.131359100342 -0.001364409924 -v 0.166741371155 1.124185800552 0.018122673035 -v 0.193145751953 1.149736404419 -0.011541187763 -v 0.155054807663 1.159122467041 -0.049359142780 -v 0.204403400421 1.165102362633 -0.054153501987 -v 0.122463703156 1.154211997986 -0.012223064899 -v 0.122359752655 1.165279030800 -0.031655430794 -v 0.111874103546 1.145521163940 -0.014831602573 -v 0.108873367310 1.130098581314 0.001646161079 -v 0.118844747543 1.140482068062 0.008030056953 -v 0.112039089203 1.157532334328 -0.030208945274 -v 0.117567777634 1.174703359604 -0.051419258118 -v 0.107257843018 1.165954709053 -0.045900940895 -v 0.104554653168 1.179394125938 -0.069682717323 -v 0.096223115921 1.169898509979 -0.061130762100 -v 0.078921318054 1.169709205627 -0.074586033821 -v 0.084147691727 1.179101228714 -0.084845960140 -v 0.060791492462 1.176911592484 -0.095880866051 -v 0.057977199554 1.167713642120 -0.084590315819 -v 0.036164999008 1.174309372902 -0.102829873562 -v 0.034911155701 1.165031433105 -0.090920388699 -v 0.010727643967 1.171227931976 -0.105658352375 -v 0.011106491089 1.162466049194 -0.093655586243 -v 0.043484210968 1.148231267929 -0.125569045544 -v 0.015298843384 1.144926548004 -0.130406677723 -v 0.071163892746 1.151486396790 -0.119160473347 -v 0.099195003510 1.154577970505 -0.109847664833 -v 0.129453897476 1.156361937523 -0.098611533642 -v 0.148039340973 1.161061882973 -0.075409770012 -v 0.194738388062 1.157809615135 -0.093097984791 -v 0.166496038437 1.133596062660 -0.120083212852 -v 0.241148471832 1.147128343582 -0.110760331154 -v 0.205090999603 1.108767747879 -0.138120114803 -v 0.296813964844 1.119970321655 -0.113083600998 -v 0.248097181320 1.079767704010 -0.139568984509 -v 0.314052343369 1.139110684395 -0.062264442444 -v 0.255768775940 1.160152196884 -0.056023120880 -v 0.125734090805 1.143847703934 -0.100883603096 -v 0.157966852188 1.121018052101 -0.115687131882 -v 0.195927619934 1.096690416336 -0.130942702293 -v 0.102578163147 1.110636472702 0.020105242729 -v 0.110338211060 1.120410561562 0.029318034649 -v 0.135500192642 1.112133264542 0.027387619019 -v 0.121419668198 1.085264921188 0.053761780262 -v 0.096231937408 1.096061944962 0.048072874546 -v 0.121106386185 1.072343826294 0.043408513069 -v 0.135016918182 1.098165869713 0.015953302383 -v 0.146015644073 1.118869185448 -0.003721117973 -v 0.161901235580 1.110084056854 0.008137762547 -v 0.196237564087 1.113056898117 0.041670143604 -v 0.231638908386 1.147067785263 0.005591809750 -v 0.187341213226 1.099266767502 0.029134333134 -v 0.101557731628 1.063514590263 0.082820892334 -v 0.102081298828 1.052370190620 0.074180006981 -v 0.079520702362 1.077967882156 0.068052530289 -v 0.091128826141 1.087718725204 0.037324488163 -v 0.076925516129 1.069971561432 0.055388748646 -v 0.073636531830 1.045414447784 0.104310035706 -v 0.060042619705 1.063298940659 0.085158526897 -v 0.060029506683 1.056650996208 0.070179820061 -v 0.076045036316 1.035140991211 0.095563471317 -v 0.043664932251 1.024097084999 0.109484314919 -v 0.049406528473 1.016946673393 0.102544367313 -v -0.092731475830 1.104547619820 -0.051223099232 -v -0.113844156265 1.093252182007 -0.044122219086 -v -0.106844902039 1.081219434738 -0.051757276058 -v -0.089383363724 1.092386722565 -0.054474711418 -v -0.142742395401 1.079518079758 -0.034633517265 -v -0.133426666260 1.067001342773 -0.045482337475 -v -0.184802770615 1.058834671974 -0.039483308792 -v -0.173303604126 1.048474073410 -0.050417959690 -v -0.212892293930 1.028311491013 -0.072805166245 -v -0.225590705872 1.036243677139 -0.063136100769 -v -0.252138376236 1.016947031021 -0.094444274902 -v -0.238336086273 1.010701894760 -0.105198681355 -v -0.261181116104 1.009418725967 -0.139634251595 -v -0.249701499939 1.001395821571 -0.147045373917 -v -0.236275196075 1.050160169601 -0.116216957569 -v -0.220269918442 1.051454544067 -0.180383503437 -v -0.255511283875 1.006905913353 -0.191586971283 -v -0.200874567032 1.088705539703 -0.091722786427 -v -0.183070182800 1.090037822723 -0.163334965706 -v -0.194282293320 1.042732954025 -0.226393222809 -v -0.229079723358 1.004474639893 -0.227474808693 -v -0.159255266190 1.014430284500 -0.241221547127 -v -0.196877479553 1.004197716713 -0.243847310543 -v -0.161328792572 1.084260106087 -0.219420254230 -v -0.119579792023 1.036281943321 -0.230625808239 -v -0.244533061981 0.997296631336 -0.191611886024 -v -0.223453521729 0.995631098747 -0.221788883209 -v -0.153653621674 1.110693693161 -0.078140616417 -v -0.146693229675 1.116624593735 -0.140892207623 -v -0.119409322739 1.117959380150 -0.075315594673 -v -0.110646963120 1.127498865128 -0.118036568165 -v -0.091603517532 1.119367361069 -0.072633266449 -v -0.084799051285 1.131223559380 -0.097159922123 -v -0.115998268127 1.108692765236 -0.190854609013 -v -0.089858293533 1.122802376747 -0.153536438942 -v -0.082515239716 1.073935151100 -0.031460642815 -v -0.089494943619 1.087044239044 -0.020607233047 -v -0.073734283447 1.050684690475 0.000546932220 -v -0.080284357071 1.062893509865 0.010187029839 -v -0.068449974060 1.044618606567 0.047623455524 -v -0.062891244888 1.033905506134 0.039388358593 -v -0.047109127045 1.031812429428 0.080443978310 -v -0.031396150589 1.052964568138 0.067215263844 -v -0.045845985413 1.064046025276 0.042960286140 -v -0.017226934433 1.017256498337 0.097646474838 -v -0.012994289398 1.040772914886 0.082050144672 -v -0.024281263351 1.047124743462 0.053621292114 -v -0.036925554276 1.057082414627 0.032743573189 -v -0.047004699707 1.072139143944 0.009349822998 -v -0.057619094849 1.078983664513 0.016488373280 -v -0.069085836411 1.100236415863 -0.007317364216 -v -0.056204557419 1.092651844025 -0.012012958527 -v -0.059460639954 1.110859036446 -0.031832396984 -v -0.073314666748 1.118509888649 -0.030457615852 -v -0.059396266937 1.125840187073 -0.048513889313 -v -0.072108268738 1.131877303123 -0.050584912300 -v -0.009020328522 1.040055990219 0.067265510559 -v -0.008279085159 1.048065781593 0.086258769035 -v -0.001708984375 1.044293761253 0.063691854477 -v -0.011102437973 1.013419628143 0.107842206955 -v 0.012402534485 1.014568805695 0.111340701580 -v -0.007885932922 1.000435948372 0.096706688404 -v 0.016772985458 0.998014330864 0.098615229130 -v -0.018301010132 1.009325742722 0.089410901070 -v 0.012949943542 1.049798607826 0.088101744652 -v 0.018573284149 1.045927882195 0.061640202999 -v 0.036473512650 1.048622608185 0.071156620979 -v 0.042591094971 1.045850872993 0.077319562435 -v 0.032891273499 1.053035736084 0.094713449478 -v -0.043589353561 1.021625638008 0.071766734123 -v -0.062194108963 1.102410316467 -0.172938823700 -v -0.045767784119 1.134480834007 -0.135547220707 -v -0.039524316788 1.122236609459 -0.136410057545 -v -0.056471109390 1.089962005615 -0.166750788689 -v -0.069718599319 1.135420084000 -0.119947195053 -v -0.057276010513 1.154541730881 -0.085973024368 -v -0.039468765259 1.162768602371 -0.098182201385 -v -0.047900676727 1.148107647896 -0.076298177242 -v -0.032938718796 1.155064463615 -0.086415827274 -v -0.067025423050 1.143415451050 -0.068977236748 -v -0.056419372559 1.138137459755 -0.063298463821 -v -0.015136957169 1.167805433273 -0.104464530945 -v -0.012070894241 1.159346342087 -0.092343151569 -v -0.014311790466 1.140978336334 -0.133057236671 -v -0.011669158936 1.129227042198 -0.125870227814 -v 0.016017198563 1.133123755455 -0.120839774609 -v 0.042919397354 1.136187195778 -0.116020321846 -v 0.069320917130 1.139438748360 -0.110212624073 -v 0.096272230148 1.142657041550 -0.103571355343 -v -0.084033012390 1.068661570549 -0.209112644196 -v -0.079619884491 1.055715084076 -0.200545787811 -v -0.114229202271 1.024448990822 -0.220436096191 -v -0.152589321136 1.005478620529 -0.229532003403 -v -0.190863609314 0.997435450554 -0.232511520386 -v 0.283624172211 1.127811551094 0.019655466080 -v 0.238133430481 1.093801021576 0.054984629154 -v 0.281615972519 1.070061683655 0.051802158356 -v 0.324586987495 1.083217859268 0.015623211861 -v 0.317109346390 1.049089670181 0.037077486515 -v 0.344853520393 1.035368323326 0.004752695560 -v 0.272841930389 1.062416911125 0.039141774178 -v 0.309236288071 1.042762875557 0.023036181927 -v 0.228971004486 1.083329319954 0.041944861412 -v 0.336932301521 1.026821017265 -0.005697131157 -v 0.352009296417 1.016058206558 -0.045218408108 -v 0.363454222679 1.025239586830 -0.041483044624 -v 0.350228548050 1.082829117775 -0.050576865673 -v 0.331254720688 1.069567441940 -0.102947354317 -v 0.354001879692 1.020647644997 -0.085915803909 -v 0.344488024712 1.012196183205 -0.082506895065 -v 0.291500329971 1.049303770065 -0.131860733032 -v 0.316508769989 1.020089149475 -0.108288466930 -v 0.278244972229 1.045682430267 -0.121770381927 -v 0.329316139221 1.025645136833 -0.117285430431 -v 0.237555980682 1.070979237556 -0.131267666817 -v 0.035062551498 1.018665790558 0.116485953331 -v 0.040465593338 1.046646237373 0.092548847198 -v 0.039201974869 1.005905747414 0.105759739876 -v 0.407534599304 1.049324989319 -0.053019642830 -v 0.407415151596 1.048302650452 -0.055281043053 -v 0.409241080284 1.045540690422 -0.054215550423 -v 0.409348964691 1.045631766319 -0.052197813988 -v 0.407567024231 1.045038938522 -0.053497850895 -v 0.408619165421 1.045577406883 -0.051431357861 -v 0.405469179153 1.048570752144 -0.051153659821 -v 0.405564785004 1.047778606415 -0.056019663811 -v 0.403634786606 1.047237396240 -0.053114891052 -v 0.403636693954 1.047934293747 -0.055059254169 -v 0.400758862495 1.061518907547 -0.057837843895 -v 0.404543042183 1.054217815399 -0.054585695267 -v 0.403454065323 1.053356051445 -0.050477862358 -v 0.400370597839 1.052134513855 -0.054630398750 -v 0.400712847710 1.052084445953 -0.049256503582 -v 0.390304088593 1.109333515167 -0.057016730309 -v 0.388536572456 1.106098771095 -0.056595444679 -v 0.390356302261 1.105766057968 -0.046931087971 -v 0.392881512642 1.108199954033 -0.046167612076 -v 0.386311173439 1.096173763275 -0.029934227467 -v 0.384410738945 1.113091945648 -0.026496827602 -v 0.389004111290 1.130117177963 -0.037221312523 -v 0.392682909966 1.108635425568 -0.037295579910 -v 0.393145322800 1.127447843552 -0.052910566330 -v 0.390158653259 1.094229102135 -0.034627795219 -v 0.365346193314 1.095366001129 -0.075250387192 -v 0.361508131027 1.084615111351 -0.066927909851 -v 0.372699022293 1.087730288506 -0.066918432713 -v 0.371014833450 1.094595193863 -0.072323203087 -v 0.361182332039 1.096700906754 -0.029368877411 -v 0.354959249496 1.107748985291 -0.019379496574 -v 0.363673329353 1.110366463661 -0.021963655949 -v 0.367691278458 1.100643992424 -0.026672244072 -v 0.374418973923 1.110103130341 -0.023161590099 -v 0.377149462700 1.091655015945 -0.026055395603 -v 0.373545646667 1.081293344498 -0.038487195969 -v 0.338927745819 1.093048810959 -0.023161709309 -v 0.335716485977 1.096756339073 -0.022189855576 -v 0.333831310272 1.101293921471 -0.015252113342 -v 0.339010357857 1.099372625351 -0.015726268291 -v 0.336115360260 1.103556871414 -0.011844396591 -v 0.344871759415 1.091088294983 -0.023372709751 -v 0.330793619156 1.106926560402 -0.018525958061 -v 0.326990127563 1.115554690361 -0.016181170940 -v 0.328750967979 1.092396497726 -0.021561920643 -v 0.325265884399 1.098267674446 -0.019644141197 -v 0.346914052963 1.103241682053 -0.017480194569 -v 0.338825702667 1.108204364777 -0.011111140251 -v 0.344290256500 1.120107769966 -0.013092637062 -v 0.340465307236 1.136773347855 -0.015785038471 -v 0.324753522873 1.125427603722 -0.015070736408 -v 0.325292944908 1.136361837387 -0.017429172993 -v 0.329348087311 1.116966009140 -0.013588488102 -v 0.332792520523 1.118334770203 -0.096988618374 -v 0.332243442535 1.122267842293 -0.094619393349 -v 0.323136806488 1.125333309174 -0.083494544029 -v 0.327710032463 1.113504409790 -0.092576861382 -v 0.341573119164 1.120945453644 -0.094311773777 -v 0.335590600967 1.131715416908 -0.092355489731 -v 0.328661322594 1.133670330048 -0.089798271656 -v 0.324473619461 1.135583043098 -0.085328757763 -v 0.353020310402 1.126932740211 -0.091999888420 -v 0.346932053566 1.140344977379 -0.090539395809 -v 0.324019074440 1.120222568512 -0.017995357513 -v 0.289908170700 1.127960801125 -0.085108101368 -v 0.304053783417 1.121056914330 -0.078729987144 -v 0.358429908752 1.193968534470 -0.088134527206 -v 0.357683658600 1.184876799583 -0.100257873535 -v 0.363889813423 1.171106338501 -0.087482929230 -v 0.366210937500 1.176288127899 -0.080222189426 -v 0.368631839752 1.159053325653 -0.078640401363 -v 0.373743414879 1.167661428452 -0.066681802273 -v 0.375433444977 1.182421684265 -0.018816709518 -v 0.371500611305 1.164965748787 -0.026864171028 -v 0.360645771027 1.163048863411 -0.020475804806 -v 0.365925073624 1.182272315025 -0.013802051544 -v 0.355728268623 1.168922543526 -0.016866326332 -v 0.365192413330 1.144321084023 -0.023384571075 -v 0.351355433464 1.141466021538 -0.019072234631 -v 0.347202420235 1.153388857841 -0.018843293190 -v 0.341611385345 1.160166978836 -0.015560805798 -v 0.308113574982 1.139430522919 -0.086172342300 -v 0.313164234161 1.145732045174 -0.091821610928 -v 0.344058752060 1.152563452721 -0.093004882336 -v 0.359626531601 1.152780056000 -0.086724877357 -v 0.353022336960 1.166682362556 -0.092923939228 -v 0.347189664841 1.169834375381 -0.094244897366 -v 0.342811346054 1.158735275269 -0.094510555267 -v 0.353778600693 1.178154706955 -0.104299247265 -v 0.348872900009 1.177428722382 -0.102648377419 -v 0.331777811050 1.146316647530 -0.093712210655 -v 0.320755481720 1.145852565765 -0.098560571671 -v 0.323286175728 1.148737668991 -0.101337194443 -v 0.333321571350 1.152906417847 -0.097986042500 -v 0.326210260391 1.151933670044 -0.103993952274 -v 0.320780992508 1.131242513657 -0.019613742828 -v 0.316488265991 1.137263059616 -0.026703536510 -v 0.320133447647 1.137962102890 -0.020618379116 -v 0.337424993515 1.147775053978 -0.018649101257 -v 0.334059238434 1.153875350952 -0.016800880432 -v 0.332339167595 1.160215377808 -0.011005222797 -v 0.333034753799 1.162801146507 -0.010488092899 -v 0.342080116272 1.164801001549 -0.014642059803 -v 0.329650044441 1.156030654907 -0.012940168381 -v 0.320695400238 1.147234559059 -0.025550961494 -v 0.324349880219 1.148427605629 -0.021465837955 -v 0.324996113777 1.144489049911 -0.022029399872 -v 0.319767236710 1.142206072807 -0.025610327721 -v 0.316439867020 1.145988821983 -0.028391957283 -v 0.314030408859 1.140980482101 -0.030016005039 -v 0.306605100632 1.136893630028 -0.031398415565 -v 0.311094760895 1.138293743134 -0.030661761761 -v 0.314454317093 1.133188128471 -0.029211819172 -v 0.307747125626 1.131512522697 -0.031591475010 -v 0.291517019272 1.138318657875 -0.033916234970 -v 0.304842948914 1.122800350189 -0.030405402184 -v 0.289185523987 1.130287408829 -0.033323228359 -v 0.286009788513 1.137142181396 -0.090150713921 -v 0.292701721191 1.141978979111 -0.107457876205 -v 0.304615020752 1.142538189888 -0.102706909180 -v 0.309559822083 1.150496006012 -0.024630010128 -v 0.318125486374 1.150960326195 -0.022390007973 -v 0.317887067795 1.153405547142 -0.009570956230 -v 0.321745395660 1.151527643204 -0.017602443695 -v 0.312289476395 1.154029130936 -0.016137778759 -v 0.300724506378 1.151372194290 -0.025900006294 -v 0.302543878555 1.155046701431 -0.016855716705 -v 0.311131477356 1.148434042931 -0.121525228024 -v 0.314778566360 1.145795822144 -0.111356735229 -v 0.318232536316 1.148830175400 -0.113018929958 -v 0.316641569138 1.155373811722 -0.125974237919 -v 0.310946226120 1.160884141922 -0.130396544933 -v 0.305948495865 1.152399063110 -0.128264009953 -v 0.322793602943 1.153211474419 -0.114452242851 -v 0.319596290588 1.160681724548 -0.123025000095 -v 0.319034099579 1.171830296516 0.017393767834 -v 0.317905664444 1.160627365112 0.008475244045 -v 0.311162710190 1.163662672043 0.014921247959 -v 0.310447931290 1.172396779060 0.019649803638 -v 0.309610843658 1.159015893936 0.012034296989 -v 0.310906410217 1.144272089005 -0.107071161270 -v 0.306469917297 1.144841670990 -0.117874324322 -v 0.302479743958 1.143570303917 -0.114495694637 -v 0.301431417465 1.147624731064 -0.126265466213 -v 0.295472621918 1.145630240440 -0.120796620846 -v 0.288472175598 1.148880720139 -0.025115370750 -v 0.301652908325 1.141206622124 -0.031471252441 -v 0.309620141983 1.142498731613 -0.029031515121 -v 0.273790359497 1.148244857788 -0.025866985321 -v 0.272537946701 1.142426609993 -0.030830979347 -v 0.272406339645 1.134789586067 -0.032956182957 -v 0.291519165039 1.153991341591 -0.016412615776 -v 0.305040836334 1.167021632195 0.019629895687 -v 0.307030200958 1.163709878922 0.017679572105 -v 0.305133104324 1.161130547523 0.017725169659 -v 0.303712606430 1.163359761238 0.020457804203 -v 0.294210910797 1.150454163551 -0.129565417767 -v 0.297544717789 1.151566028595 -0.131443619728 -v 0.299007177353 1.157061815262 -0.131160855293 -v 0.289251804352 1.162134289742 -0.127951741219 -v 0.300848484039 1.162901401520 0.020725965500 -v 0.299931526184 1.168733119965 0.019787251949 -v 0.302267789841 1.160912990570 0.017476558685 -v 0.284586906433 1.155997037888 -0.118712186813 -v 0.320478677750 1.183388590813 0.019893288612 -v 0.315504550934 1.185158967972 0.021765649319 -v 0.304894447327 1.174435973167 0.020509123802 -v 0.311547279358 1.187007069588 0.021684288979 -v 0.294510126114 1.164358973503 0.015730142593 -v 0.295584678650 1.166682958603 0.018493294716 -v 0.298225879669 1.162472367287 0.019704580307 -v 0.296677112579 1.161968946457 0.018077135086 -v 0.299949407578 1.160799622536 0.016491711140 -v 0.297479152679 1.160787940025 0.014298200607 -v 0.295337200165 1.162495613098 0.013063669205 -v 0.297493457794 1.159226298332 0.006240844727 -v 0.292984724045 1.162090659142 0.007228136063 -v 0.289747714996 1.165970087051 0.009980738163 -v 0.293587207794 1.173587322235 0.017361879349 -v 0.295882701874 1.184546113014 0.019877433777 -v 0.289324522018 1.170376300812 0.013289868832 -v 0.304202318192 1.163235664368 -0.131868004799 -v 0.295037984848 1.173500776291 -0.132903218269 -v 0.339935421944 1.204928994179 0.011042654514 -v 0.323164343834 1.198740124702 0.019174516201 -v 0.319356679916 1.202640295029 0.017888188362 -v 0.333619713783 1.216896772385 0.006251335144 -v 0.316392660141 1.223941683769 0.004564166069 -v 0.318291187286 1.236307144165 -0.009308457375 -v 0.339412450790 1.232521295547 -0.013116896152 -v 0.309664726257 1.210659503937 0.013969600201 -v 0.320227146149 1.235717296600 -0.089737355709 -v 0.315104484558 1.228830337524 -0.112790822983 -v 0.326388478279 1.222050905228 -0.113814830780 -v 0.333210706711 1.227595806122 -0.095670104027 -v 0.337775707245 1.211602926254 -0.112435698509 -v 0.344557762146 1.216145873070 -0.082126915455 -v 0.326203584671 1.226114869118 -0.064788460732 -v 0.278375148773 1.164562225342 0.002692937851 -v 0.286962032318 1.159514427185 -0.002162218094 -v 0.278234004974 1.155510902405 -0.013907790184 -v 0.260844707489 1.160049319267 -0.009037494659 -v 0.253694772720 1.171441078186 0.002056777477 -v 0.274199008942 1.172616839409 0.009002089500 -v 0.241376399994 1.164381980896 -0.022117018700 -v 0.236744165421 1.171596884727 -0.017185091972 -v 0.257408142090 1.154074668884 -0.020835101604 -v 0.240831613541 1.161932706833 -0.027496337891 -v 0.272498369217 1.184606671333 0.015063345432 -v 0.283818006516 1.195466637611 0.018259227276 -v 0.251496076584 1.179788351059 0.004774987698 -v 0.280345439911 1.187177538872 -0.130770325661 -v 0.278849363327 1.200135588646 -0.128845155239 -v 0.264022827148 1.197203159332 -0.124487996101 -v 0.263042688370 1.188585639000 -0.125758051872 -v 0.247735500336 1.194719552994 -0.112018883228 -v 0.248827695847 1.181841850281 -0.113283038139 -v 0.269680976868 1.173762202263 -0.124203026295 -v 0.254821300507 1.213196992874 -0.005989432335 -v 0.259692907333 1.217268109322 -0.002873539925 -v 0.264866352081 1.212918281555 0.006526708603 -v 0.262398242950 1.203422427177 0.007279813290 -v 0.274141788483 1.213083267212 0.013194501400 -v 0.276415348053 1.206676006317 0.013642489910 -v 0.247564315796 1.194469571114 -0.000649333000 -v 0.245563030243 1.205689191818 -0.011326313019 -v 0.232998371124 1.204849720001 -0.033008277416 -v 0.242313385010 1.215915679932 -0.027005612850 -v 0.237220525742 1.198678970337 -0.018567323685 -v 0.235009908676 1.188932180405 -0.016125142574 -v 0.229682207108 1.194204092026 -0.034655272961 -v 0.280081987381 1.256208896637 -0.019527673721 -v 0.266340732574 1.257276535034 -0.021893620491 -v 0.272911071777 1.248642563820 -0.034798681736 -v 0.289152145386 1.246002078056 -0.035115897655 -v 0.308747768402 1.234785199165 -0.048455655575 -v 0.315008163452 1.240252733231 -0.028551578522 -v 0.295452594757 1.246342897415 -0.017771065235 -v 0.291768074036 1.252464294434 -0.011624932289 -v 0.272852182388 1.246320486069 0.026719093323 -v 0.274995565414 1.244897484779 0.026039719582 -v 0.270889520645 1.239411234856 0.026342213154 -v 0.269581317902 1.240408897400 0.026497364044 -v 0.264169454575 1.234132766724 0.025929450989 -v 0.263763427734 1.235451221466 0.026660978794 -v 0.263376712799 1.240142583847 0.021522641182 -v 0.268235921860 1.245139122009 0.023626983166 -v 0.227350234985 1.201413989067 -0.060404598713 -v 0.226505756378 1.187961101532 -0.062663376331 -v 0.232470035553 1.193228960037 -0.089262902737 -v 0.238893508911 1.210202097893 -0.088255286217 -v 0.253223896027 1.206307768822 -0.110778868198 -v 0.239593505859 1.224539875984 -0.073748230934 -v 0.232012033463 1.216619491577 -0.053089022636 -v 0.252145767212 1.219983339310 -0.097832560539 -v 0.250634193420 1.229226589203 -0.085364758968 -v 0.252376794815 1.238263368607 -0.057780742645 -v 0.267105579376 1.240937113762 -0.056898772717 -v 0.258289337158 1.241248607635 -0.051965177059 -v 0.252767086029 1.235920786858 -0.034247636795 -v 0.247609376907 1.233851552010 -0.039491355419 -v 0.265551090240 1.267001390457 0.009194791317 -v 0.272844314575 1.261870384216 0.012323737144 -v 0.270809888840 1.260163426399 0.015809416771 -v 0.262974262238 1.263656973839 0.012956202030 -v 0.268976211548 1.265585422516 0.000393331051 -v 0.258705377579 1.266561031342 -0.002085030079 -v 0.261866092682 1.261532545090 -0.010348796844 -v 0.274395465851 1.261371612549 -0.009189963341 -v 0.238660573959 1.248261332512 0.003617167473 -v 0.232067346573 1.245571255684 0.001219451427 -v 0.233589172363 1.253527522087 -0.000213980675 -v 0.238280773163 1.252982854843 0.002291560173 -v 0.241975069046 1.261794805527 0.000397861004 -v 0.244624614716 1.256234288216 0.001851916313 -v 0.222787380219 1.257822632790 -0.151930749416 -v 0.228422880173 1.254693269730 -0.147209823132 -v 0.230664730072 1.257706403732 -0.153383851051 -v 0.225557327271 1.260083436966 -0.156076908112 -v 0.224181652069 1.269489765167 -0.164974153042 -v 0.218438386917 1.260652661324 -0.156715095043 -v 0.235471725464 1.260826349258 -0.157907843590 -v 0.216721296310 1.261644721031 -0.151875853539 -v 0.215643405914 1.258587121964 -0.150196969509 -v 0.234998703003 1.261462807655 -0.124403178692 -v 0.224088907242 1.267516016960 -0.134056270123 -v 0.228742599487 1.274905562401 -0.138475537300 -v 0.243557214737 1.273823022842 -0.127884268761 -v 0.218826293945 1.271217346191 -0.139695227146 -v 0.223790407181 1.282513380051 -0.156298041344 -v 0.229401111603 1.281741142273 -0.159395992756 -v 0.243339538574 1.285583496094 -0.155722141266 -v 0.240149497986 1.285640001297 -0.147173225880 -v 0.263746500015 1.284044027328 -0.144365310669 -v 0.256647109985 1.283450603485 -0.135616004467 -v 0.249143123627 1.278396368027 -0.130899667740 -v 0.231034517288 1.281445980072 -0.142535567284 -v 0.228749275208 1.279866695404 -0.162645876408 -v 0.225111246109 1.280306816101 -0.161672592163 -v 0.326325416565 1.095832467079 -0.026897907257 -v 0.328660488129 1.092162013054 -0.027155876160 -v 0.334224581718 1.083390593529 -0.031802475452 -v 0.331976652145 1.086985468864 -0.036189317703 -v 0.244880199432 1.142374873161 -0.073979854584 -v 0.242966175079 1.142764568329 -0.078356206417 -v 0.235785722733 1.146784543991 -0.078433096409 -v 0.238635778427 1.145627975464 -0.074249148369 -v 0.232438325882 1.149214863777 -0.073069214821 -v 0.236898422241 1.147114753723 -0.069623470306 -v 0.255175828934 1.136546134949 -0.077648699284 -v 0.255682229996 1.136946439743 -0.070239722729 -v 0.269840002060 1.141850829124 -0.088529407978 -v 0.257449388504 1.150468826294 -0.085283041000 -v 0.282135963440 1.148957133293 -0.107223212719 -v 0.262875080109 1.157893180847 -0.106579840183 -v 0.264955282211 1.164611697197 -0.115844190121 -v 0.244687318802 1.169971346855 -0.105285048485 -v 0.246577739716 1.164339303970 -0.095911860466 -v 0.234338521957 1.172934412956 -0.084621906281 -v 0.237678050995 1.167568325996 -0.080495774746 -v 0.230271100998 1.181651115417 -0.088845074177 -v 0.227655649185 1.178839325905 -0.062708079815 -v 0.231756448746 1.172751188278 -0.062062919140 -v 0.229456424713 1.177902221680 -0.036529541016 -v 0.232846736908 1.170946717262 -0.038640320301 -v 0.227507114410 1.182419776917 -0.036165595055 -v 0.234830379486 1.176739931107 -0.015439331532 -v 0.235546827316 1.166122555733 -0.040820002556 -v 0.235387325287 1.167956709862 -0.061342179775 -v 0.236512184143 1.160708308220 -0.043142557144 -v 0.237915754318 1.161495804787 -0.059940874577 -v 0.241000175476 1.156659126282 -0.029682040215 -v 0.256223201752 1.147885084152 -0.025309741497 -v 0.252270221710 1.141531467438 -0.026705861092 -v 0.236812353134 1.148920893669 -0.030205547810 -v 0.290362834930 1.128957509995 -0.035883367062 -v 0.271513700485 1.134885430336 -0.035297334194 -v 0.306781768799 1.119673848152 -0.033734023571 -v 0.317042827606 1.112375974655 -0.022598922253 -v 0.317406177521 1.108932733536 -0.028873980045 -v 0.332089543343 1.094723105431 -0.085125267506 -v 0.322933316231 1.108649253845 -0.085476875305 -v 0.319103002548 1.109926819801 -0.080069780350 -v 0.329759955406 1.096952438354 -0.079336047173 -v 0.334635496140 1.087565541267 -0.070015192032 -v 0.337785124779 1.084333658218 -0.074962139130 -v 0.336755514145 1.081413388252 -0.053044438362 -v 0.338276147842 1.079147696495 -0.053146123886 -v 0.346428036690 1.085549473763 -0.069611251354 -v 0.343625307083 1.093718051910 -0.081809461117 -v 0.333607673645 1.104474425316 -0.090680718422 -v 0.343541741371 1.081957101822 -0.052684903145 -v 0.353684067726 1.082917213440 -0.067507863045 -v 0.358879923820 1.093483090401 -0.077935218811 -v 0.351037502289 1.092784404755 -0.080610275269 -v 0.360334396362 1.102306008339 -0.085941970348 -v 0.347621440887 1.101400613785 -0.092805027962 -v 0.345952153206 1.079882979393 -0.052633166313 -v 0.355161905289 1.077038049698 -0.051688134670 -v 0.343386173248 1.084547519684 -0.034452319145 -v 0.352032899857 1.082792043686 -0.035345792770 -v 0.340294599533 1.086036086082 -0.034663975239 -v 0.321768999100 1.104483842850 -0.020316779613 -v 0.326095461845 1.115695357323 -0.020195245743 -v 0.319353103638 1.123223304749 -0.025029301643 -v 0.322834372520 1.101128458977 -0.027329206467 -v 0.321851253510 1.127054452896 -0.022767901421 -v 0.353766679764 1.095177173615 -0.026385903358 -v 0.359876632690 1.086948037148 -0.037192046642 -v 0.368791699409 1.081473231316 -0.054299533367 -v 0.366416454315 1.085834145546 -0.039678335190 -v 0.375720381737 1.077826261520 -0.054867923260 -v 0.385641813278 1.069572925568 -0.047519683838 -v 0.386780261993 1.068247556686 -0.054583191872 -v 0.379089593887 1.078935027122 -0.064835965633 -v 0.387892365456 1.068310856819 -0.060149490833 -v 0.394519090652 1.059546113014 -0.055611908436 -v 0.389144182205 1.068464994431 -0.063209295273 -v 0.381745100021 1.079965829849 -0.068755567074 -v 0.395897269249 1.059724450111 -0.058292984962 -v 0.397762775421 1.058734893799 -0.060246050358 -v 0.390513181686 1.068549633026 -0.065918266773 -v 0.401293635368 1.052220582962 -0.057137370110 -v 0.402930855751 1.052381992340 -0.058841645718 -v 0.399328708649 1.059069991112 -0.062133789063 -v 0.404549121857 1.052707433701 -0.057922661304 -v 0.400724768639 1.060495495796 -0.061055362225 -v 0.394371271133 1.071512341499 -0.065981507301 -v 0.392708420753 1.069672346115 -0.067366063595 -v 0.394284963608 1.071869850159 -0.062373280525 -v 0.388498425484 1.083336234093 -0.066320896149 -v 0.388929486275 1.082942962646 -0.069176137447 -v 0.389878511429 1.092170119286 -0.038135766983 -v 0.392562985420 1.073132753372 -0.038371622562 -v 0.393902897835 1.072458386421 -0.036485314369 -v 0.400479316711 1.060284376144 -0.040919661522 -v 0.400619268417 1.059895157814 -0.042878329754 -v 0.392677068710 1.071635484695 -0.034626603127 -v 0.399963617325 1.058247804642 -0.039560496807 -v 0.389219284058 1.072089076042 -0.033550858498 -v 0.398481249809 1.057546377182 -0.040394842625 -v 0.385063409805 1.070487856865 -0.035343050957 -v 0.395586490631 1.058170080185 -0.044803380966 -v 0.402001142502 1.052767753601 -0.042411684990 -v 0.388577699661 1.095486879349 -0.066482841969 -v 0.387288451195 1.094378232956 -0.064481914043 -v 0.389545917511 1.108287096024 -0.069271624088 -v 0.387219429016 1.094375610352 -0.071040332317 -v 0.390260934830 1.124660015106 -0.067944049835 -v 0.383810281754 1.146947145462 -0.036770582199 -v 0.387935638428 1.145303487778 -0.049735426903 -v 0.385385751724 1.144845247269 -0.066654205322 -v 0.379234194756 1.167300224304 -0.047699809074 -v 0.378260374069 1.142871618271 -0.078380703926 -v 0.384638786316 1.121478676796 -0.079748928547 -v 0.371328830719 1.114236831665 -0.083621263504 -v 0.366134643555 1.134753823280 -0.086642682552 -v 0.358268737793 1.111678957939 -0.091841936111 -v 0.384584784508 1.105457901955 -0.077077627182 -v 0.377453684807 1.103823542595 -0.078171491623 -v 0.383101344109 1.092535972595 -0.074570477009 -v 0.376216292381 1.093980312347 -0.073397576809 -v 0.384114503860 1.080561161041 -0.071538448334 -v 0.387168884277 1.081826567650 -0.071408987045 -v 0.378217101097 1.166335225105 -0.036741614342 -v 0.376491785049 1.185984611511 -0.027371287346 -v 0.375539779663 1.191256642342 -0.040807008743 -v 0.376024484634 1.146698236465 -0.028571903706 -v 0.380968809128 1.128817915916 -0.027356445789 -v 0.372819066048 1.124244213104 -0.021395444870 -v 0.357726931572 1.123675107956 -0.019232869148 -v 0.363764047623 1.199695229530 -0.003253161907 -v 0.359092354774 1.192318797112 -0.001357376575 -v 0.363418817520 1.207986116409 -0.009030759335 -v 0.363287687302 1.216881036758 -0.024423658848 -v 0.353446960449 1.214913725853 -0.051911473274 -v 0.367811679840 1.192584276199 -0.062469363213 -v 0.335019469261 1.232254981995 -0.039931237698 -v 0.341472268105 1.196155428886 0.010244071484 -v 0.354283452034 1.192304849625 -0.001765370369 -v 0.339673757553 1.196221947670 0.007006824017 -v 0.363298535347 1.182292938232 -0.012944102287 -v 0.354795575142 1.171777725220 -0.016488790512 -v 0.327435612679 1.161281824112 -0.002656698227 -v 0.324092507362 1.165798902512 0.006462395191 -v 0.322525382042 1.168064355850 0.004236161709 -v 0.326949238777 1.164337635040 -0.003446638584 -v 0.325284123421 1.158543467522 -0.003361463547 -v 0.322180032730 1.162310838699 0.007995128632 -v 0.320963859558 1.172976732254 0.015366852283 -v 0.319886207581 1.174322366714 0.011200785637 -v 0.321480035782 1.183079004288 0.017309784889 -v 0.326878428459 1.193821310997 0.018233954906 -v 0.327511191368 1.192236304283 0.015911042690 -v 0.303445339203 1.120934963226 -0.074148416519 -v 0.251810550690 1.141942739487 -0.031309187412 -v 0.241466999054 1.146666526794 -0.036401212215 -v 0.236400604248 1.148872971535 -0.047140300274 -v 0.230206489563 1.152073264122 -0.044595956802 -v 0.229574203491 1.151367187500 -0.061807334423 -v 0.239748239517 1.160202145576 -0.073878407478 -v 0.247816801071 1.157876133919 -0.081561207771 -v 0.234130144119 1.149081230164 -0.061738610268 -v 0.224230289459 1.281635522842 -0.153767704964 -v 0.223762512207 1.278146028519 -0.159069538116 -v 0.219611406326 1.279417753220 -0.152326762676 -v 0.213749408722 1.273561835289 -0.144396305084 -v 0.217382907867 1.273008942604 -0.147697806358 -v 0.221839427948 1.275884628296 -0.154915273190 -v 0.210401773453 1.265159130096 -0.141010046005 -v 0.213674545288 1.265947461128 -0.146045088768 -v 0.217527627945 1.274109721184 -0.141741633415 -v 0.215512275696 1.264181613922 -0.138061285019 -v 0.220313549042 1.262314796448 -0.135805130005 -v 0.220573663712 1.257741451263 -0.138237059116 -v 0.216372489929 1.257721900940 -0.141187667847 -v 0.212907791138 1.258577108383 -0.145352184772 -v 0.233858585358 1.256473422050 -0.125267803669 -v 0.234248638153 1.251918315887 -0.127823233604 -v 0.246033430099 1.251870393753 -0.112772464752 -v 0.246748685837 1.247483968735 -0.115507006645 -v 0.247130870819 1.256455659866 -0.111137330532 -v 0.258541584015 1.245236992836 -0.084437072277 -v 0.256093978882 1.239906072617 -0.086883187294 -v 0.257097005844 1.266151666641 -0.110764563084 -v 0.266882419586 1.251339793205 -0.085104942322 -v 0.267502307892 1.270240545273 -0.112958729267 -v 0.275364637375 1.256015896797 -0.091180860996 -v 0.275161266327 1.274131059647 -0.118503391743 -v 0.285532474518 1.258744239807 -0.098316013813 -v 0.281810045242 1.273761987686 -0.128352165222 -v 0.294841051102 1.259177684784 -0.109563946724 -v 0.285378694534 1.267878890038 -0.136893749237 -v 0.299645662308 1.256075739861 -0.122435271740 -v 0.267150640488 1.279207229614 -0.152110457420 -v 0.266644477844 1.272503018379 -0.155482232571 -v 0.285328865051 1.260385632515 -0.145259499550 -v 0.245440483093 1.281306147575 -0.162130832672 -v 0.247352838516 1.277317881584 -0.164401888847 -v 0.226536273956 1.277150392532 -0.165146172047 -v 0.244216680527 1.272458314896 -0.165734708309 -v 0.265185594559 1.264242410660 -0.158591628075 -v 0.225196361542 1.271236658096 -0.164832949638 -v 0.240829467773 1.264716506004 -0.164158344269 -v 0.256122827530 1.256213188171 -0.158023118973 -v 0.249283313751 1.251091122627 -0.154383540154 -v 0.264867782593 1.238259196281 -0.149782478809 -v 0.271236419678 1.243698835373 -0.152746677399 -v 0.242131233215 1.248456358910 -0.149258136749 -v 0.259697437286 1.235559821129 -0.143175721169 -v 0.238021850586 1.246404170990 -0.140355885029 -v 0.255519628525 1.235976219177 -0.134220600128 -v 0.235714912415 1.248224496841 -0.132601261139 -v 0.249901533127 1.242415428162 -0.121484637260 -v 0.225628137589 1.255354166031 -0.141528964043 -v 0.219279289246 1.256212234497 -0.146652877331 -v 0.261144638062 1.227618336678 -0.105385541916 -v 0.265067815781 1.218194127083 -0.118982553482 -v 0.255488157272 1.234093666077 -0.095165371895 -v 0.257819652557 1.237515091896 -0.082652032375 -v 0.256304979324 1.231330990791 -0.090660393238 -v 0.261433124542 1.242497920990 -0.080974459648 -v 0.269018650055 1.247485637665 -0.080007076263 -v 0.276544094086 1.249154090881 -0.084097981453 -v 0.286174535751 1.250129461288 -0.091734588146 -v 0.297051906586 1.250920057297 -0.101950109005 -v 0.304772377014 1.248518705368 -0.115050077438 -v 0.297762155533 1.245796918869 -0.131601870060 -v 0.303509950638 1.239294528961 -0.125708818436 -v 0.278063774109 1.251515507698 -0.150501132011 -v 0.292453289032 1.234364628792 -0.138768732548 -v 0.285548925400 1.222070693970 -0.138958930969 -v 0.275888442993 1.216582298279 -0.135062336922 -v 0.269642829895 1.214331030846 -0.127090573311 -v 0.265042543411 1.214603662491 -0.116683065891 -v 0.270244359970 1.211904883385 -0.125036418438 -v 0.259296417236 1.223366022110 -0.101866900921 -v 0.260845899582 1.212415218353 -0.112328946590 -v 0.266552209854 1.205083847046 -0.122853875160 -v 0.268821239471 1.210025906563 -0.123203098774 -v 0.277948856354 1.207428336143 -0.128034055233 -v 0.277915716171 1.211367130280 -0.128684759140 -v 0.288717508316 1.213802814484 -0.129420161247 -v 0.287309169769 1.217238068581 -0.130407452583 -v 0.277626991272 1.213335871696 -0.130287289619 -v 0.286727428436 1.219543695450 -0.133292317390 -v 0.297491550446 1.224069118500 -0.127825796604 -v 0.295832872391 1.229104042053 -0.133770406246 -v 0.299275398254 1.222613096237 -0.126457333565 -v 0.306288719177 1.231516838074 -0.115943133831 -v 0.303650856018 1.233008384705 -0.119831323624 -v 0.304522037506 1.218244671822 -0.125307500362 -v 0.291501283646 1.207969903946 -0.129891932011 -v 0.295377254486 1.198327302933 -0.132311940193 -v 0.312335252762 1.210624575615 -0.126865327358 -v 0.307499647141 1.182762622833 -0.133446455002 -v 0.321811676025 1.199660181999 -0.127626895905 -v 0.313686370850 1.178631782532 -0.132702827454 -v 0.327832698822 1.190094709396 -0.127820491791 -v 0.318174362183 1.174999833107 -0.130550682545 -v 0.329443216324 1.184651136398 -0.126586496830 -v 0.320348262787 1.172263383865 -0.127011775970 -v 0.329268336296 1.182359218597 -0.124253869057 -v 0.319159746170 1.172549962997 -0.124517083168 -v 0.327510595322 1.181082725525 -0.121122121811 -v 0.341977953911 1.186866998672 -0.119443237782 -v 0.340240001678 1.181673407555 -0.114829957485 -v 0.342066526413 1.190820455551 -0.118938207626 -v 0.343557119370 1.197325468063 -0.114280879498 -v 0.308367967606 1.238885641098 -0.100797057152 -v 0.302496671677 1.241308212280 -0.108589589596 -v 0.297030925751 1.244460582733 -0.094559252262 -v 0.288425922394 1.242414832115 -0.070966482162 -v 0.300933361053 1.241560339928 -0.084082663059 -v 0.287242650986 1.245997667313 -0.082513213158 -v 0.276428461075 1.242347240448 -0.063216865063 -v 0.276814937592 1.246329665184 -0.074558973312 -v 0.262533426285 1.248234033585 -0.033080637455 -v 0.268426895142 1.245181202888 -0.070157289505 -v 0.255537271500 1.244341135025 -0.030193269253 -v 0.255340337753 1.255470871925 -0.021258711815 -v 0.248293161392 1.248656272888 -0.019238531590 -v 0.246406555176 1.241610646248 -0.014172136784 -v 0.252004623413 1.238135337830 -0.023450851440 -v 0.240248918533 1.252865195274 -0.008260846138 -v 0.236009836197 1.244751214981 -0.002041816711 -v 0.250643014908 1.260913610458 -0.006915748119 -v 0.241449356079 1.238094210625 0.000856995583 -v 0.248243808746 1.235244989395 -0.007029771805 -v 0.236295223236 1.238589763641 0.006947577000 -v 0.244088888168 1.237448453903 0.010651528835 -v 0.245872020721 1.235504984856 0.007974743843 -v 0.240644693375 1.243501543999 0.007078409195 -v 0.245250463486 1.240480542183 0.010777413845 -v 0.252675771713 1.233302831650 0.020247042179 -v 0.254426479340 1.231533646584 0.017972588539 -v 0.254062652588 1.237539768219 0.019096493721 -v 0.276159763336 1.255128741264 0.018554508686 -v 0.275947093964 1.249229311943 0.022302091122 -v 0.272867918015 1.249667882919 0.024674117565 -v 0.271744251251 1.251732468605 0.021295309067 -v 0.283636093140 1.255234718323 0.014072477818 -v 0.280255317688 1.247575402260 0.019362986088 -v 0.276215314865 1.261920690536 0.008904576302 -v 0.278604030609 1.259399175644 0.004241228104 -v 0.285460472107 1.252817630768 0.010138630867 -v 0.266534566879 1.266445875168 0.005049049854 -v 0.258428096771 1.268704891205 0.002973020077 -v 0.254645347595 1.267239928246 0.003869831562 -v 0.287663459778 1.258239984512 -0.004414916039 -v 0.298110485077 1.250542998314 0.003384351730 -v 0.298449993134 1.244361400604 -0.001860737801 -v 0.299829959869 1.234122157097 0.006569683552 -v 0.298758268356 1.238474845886 0.010709106922 -v 0.303976297379 1.239164352417 -0.006211340427 -v 0.305155038834 1.229295969009 0.004372239113 -v 0.300870895386 1.218429088593 0.011674880981 -v 0.295304775238 1.223464488983 0.011802554131 -v 0.293110609055 1.205903887749 0.015846788883 -v 0.286343812943 1.213704109192 0.013587355614 -v 0.302354812622 1.196681976318 0.018828034401 -v 0.283874988556 1.219200730324 0.015126287937 -v 0.293270826340 1.227752089500 0.015739440918 -v 0.283052444458 1.240837812424 0.023119628429 -v 0.276622056961 1.233630180359 0.024268507957 -v 0.286540031433 1.246751070023 0.017804086208 -v 0.272910356522 1.237592816353 0.025359690189 -v 0.278305053711 1.243288516998 0.024740695953 -v 0.267666101456 1.227963447571 0.022224366665 -v 0.264769792557 1.232656955719 0.024754941463 -v 0.260413408279 1.224851250648 0.011581957340 -v 0.257379055023 1.225758671761 -0.000789821148 -v 0.253545045853 1.232021093369 -0.012868225574 -v 0.254851341248 1.226656675339 -0.018729388714 -v 0.251304626465 1.230217099190 0.003005683422 -v 0.256979942322 1.228909850121 0.014670252800 -v 0.250156402588 1.223106861115 -0.021990776062 -v 0.239892244339 1.227292776108 -0.045880913734 -v 0.245432853699 1.234084725380 -0.064319491386 -v 0.254643917084 1.237128496170 -0.077797412872 -v 0.259204149246 1.241605043411 -0.074413061142 -v 0.253374576569 1.265572071075 0.004234373569 -v 0.252619743347 1.259510278702 0.004528701305 -v 0.295717954636 1.157437562943 -0.004984855652 -v 0.302157163620 1.158133268356 0.007280886173 -v 0.303221464157 1.155419707298 -0.004480600357 -v 0.306118011475 1.158186078072 0.009157180786 -v 0.309594392776 1.154529452324 -0.002081036568 -v 0.317309141159 1.145281672478 -0.095512390137 -v 0.342793583870 1.111549854279 -0.096035361290 -v 0.370063781738 1.103682756424 -0.078702569008 -v 0.223846435547 1.280663371086 -0.149150192738 -v 0.262922763824 1.260004043579 0.011266469955 -v 0.278262376785 1.128904223442 -0.071313738823 -v 0.278782129288 1.129065513611 -0.078170895576 -v 0.214526414871 1.261890172958 -0.147512257099 -v 0.403749704361 1.053897500038 -0.044087231159 -v -0.173335313797 1.189228773117 -0.074161946774 -v -0.172501087189 1.194711208344 -0.077600002289 -v -0.156718730927 1.200044989586 -0.067752003670 -v -0.159983634949 1.195769190788 -0.064942240715 -v -0.157345533371 1.192241907120 -0.064338445663 -v -0.176035165787 1.182665348053 -0.074862539768 -v -0.153723001480 1.198203325272 -0.067141354084 -v -0.154419660568 1.185277462006 -0.061343967915 -v -0.174031734467 1.176616787910 -0.076530218124 -v -0.153948068619 1.192448616028 -0.066138029099 -v -0.152566671371 1.196974277496 -0.068748712540 -v -0.149900436401 1.188096642494 -0.064178586006 -v -0.167804479599 1.171906828880 -0.078679144382 -v -0.151026010513 1.177392482758 -0.069037199020 -v -0.159547805786 1.170724391937 -0.081492185593 -v -0.137443780899 1.179318189621 -0.071261107922 -v -0.151052713394 1.171566128731 -0.090630888939 -v -0.145410776138 1.202758073807 -0.074415385723 -v -0.146416664124 1.204916477203 -0.073959469795 -v -0.142997503281 1.206828117371 -0.075007200241 -v -0.139394283295 1.203434348106 -0.075942695141 -v -0.143990516663 1.207095742226 -0.077334642410 -v -0.152405261993 1.204598784447 -0.072375178337 -v -0.150315523148 1.201716780663 -0.070241928101 -v -0.169452428818 1.199298620224 -0.083030939102 -v -0.163226604462 1.203215003014 -0.090547025204 -v -0.193114757538 1.175109863281 -0.086916208267 -v -0.185326576233 1.171366214752 -0.082843124866 -v -0.186292409897 1.165282964706 -0.088589191437 -v -0.200573444366 1.166569828987 -0.092627763748 -v -0.138775825500 1.205187916756 -0.076617836952 -v -0.135615825653 1.203529238701 -0.077090024948 -v -0.155732393265 1.203607797623 -0.096656978130 -v -0.149366855621 1.200804471970 -0.100724101067 -v -0.137942790985 1.205677509308 -0.079242825508 -v -0.131234407425 1.203546047211 -0.080529451370 -v -0.130687952042 1.197476148605 -0.079052925110 -v -0.130004167557 1.197584390640 -0.081454098225 -v -0.129281997681 1.189852356911 -0.077395677567 -v -0.131329774857 1.190665483475 -0.076595366001 -v -0.141457080841 1.192768573761 -0.102260649204 -v -0.127812385559 1.196197390556 -0.082319319248 -v -0.144458770752 1.197188854218 -0.101949512959 -v -0.177466392517 1.161493182182 -0.094907760620 -v -0.163338899612 1.165530800819 -0.106261909008 -v -0.128491640091 1.187958240509 -0.082086682320 -v -0.140712261200 1.182583570480 -0.100011527538 -v -0.210927009583 1.107810139656 -0.110981822014 -v -0.211072683334 1.103303790092 -0.109917879105 -v -0.213212490082 1.101778507233 -0.109918236732 -v -0.214309692383 1.109030246735 -0.111766934395 -v -0.204130172729 1.105494737625 -0.113910675049 -v -0.205763339996 1.099799871445 -0.112921178341 -v -0.223363876343 1.117204904556 -0.114630222321 -v -0.214059114456 1.124341964722 -0.111509382725 -v -0.219065189362 1.105570316315 -0.114096760750 -v -0.238481521606 1.129768848419 -0.130072593689 -v -0.234876394272 1.134552240372 -0.130008339882 -v -0.223749637604 1.136018037796 -0.118461847305 -v -0.207642078400 1.120860934258 -0.111469984055 -v -0.208950042725 1.096844553947 -0.112857937813 -v -0.215140581131 1.098256349564 -0.112100958824 -v -0.209567785263 1.147545337677 -0.113711655140 -v -0.197745561600 1.140209794044 -0.107432365417 -v -0.193334102631 1.132169842720 -0.107758402824 -v -0.193572998047 1.150783538818 -0.107727050781 -v -0.203800201416 1.156490325928 -0.111603617668 -v -0.175592660904 1.145561695099 -0.106927514076 -v -0.172769784927 1.138006210327 -0.105781555176 -v -0.177102327347 1.152362346649 -0.109004378319 -v -0.203049182892 1.103446960449 -0.115947484970 -v -0.205771446228 1.097857356071 -0.116888880730 -v -0.200581550598 1.109675526619 -0.119850099087 -v -0.202297449112 1.114114880562 -0.116474270821 -v -0.205280303955 1.096752166748 -0.122693479061 -v -0.225318193436 1.093360424042 -0.128429234028 -v -0.225040435791 1.096657991409 -0.123039066792 -v -0.220809221268 1.096151828766 -0.119270980358 -v -0.221869707108 1.091606855392 -0.126757025719 -v -0.228603363037 1.095641136169 -0.129044175148 -v -0.228597879410 1.101918220520 -0.122385978699 -v -0.224291801453 1.103944659233 -0.118215620518 -v -0.247853517532 1.125877380371 -0.145480275154 -v -0.241319656372 1.134932279587 -0.146954476833 -v -0.224902391434 1.146563768387 -0.131057977676 -v -0.189874410629 1.125573754311 -0.113757431507 -v -0.188519477844 1.120980858803 -0.117558717728 -v -0.197483062744 1.107985734940 -0.124557018280 -v -0.203064918518 1.094104051590 -0.134538710117 -v -0.212108135223 1.091883540154 -0.125092267990 -v -0.146539926529 1.190650701523 -0.114794254303 -v -0.146754264832 1.180134177208 -0.115530133247 -v -0.152557849884 1.174678444862 -0.113840103149 -v -0.143783569336 1.177394032478 -0.097335398197 -v -0.152518033981 1.177743196487 -0.127124845982 -v -0.154675722122 1.168212413788 -0.123611927032 -v -0.152200698853 1.192405939102 -0.124226093292 -v -0.149080038071 1.190506696701 -0.121930062771 -v -0.149870634079 1.194133043289 -0.115894854069 -v -0.152212619781 1.190471172333 -0.127474963665 -v -0.152487754822 1.182887434959 -0.127529799938 -v -0.154866933823 1.185299873352 -0.129990160465 -v -0.154926300049 1.181805968285 -0.133388638496 -v -0.233518838882 1.051918983459 -0.153825461864 -v -0.234681367874 1.048460602760 -0.154123127460 -v -0.235526800156 1.045760154724 -0.156687140465 -v -0.238681077957 1.048464179039 -0.156781077385 -v -0.229362010956 1.049855709076 -0.154987037182 -v -0.227258443832 1.057394742966 -0.153537988663 -v -0.231667280197 1.046329975128 -0.156813800335 -v -0.223042964935 1.088201880455 -0.145084559917 -v -0.215483188629 1.087337613106 -0.146565556526 -v -0.215860605240 1.081712245941 -0.155044794083 -v -0.226407766342 1.085251331329 -0.153320491314 -v -0.235337972641 1.090702056885 -0.156869351864 -v -0.226635932922 1.075340270996 -0.153673052788 -v -0.235593795776 1.084217786789 -0.159696042538 -v -0.230427265167 1.064726591110 -0.154860198498 -v -0.235838890076 1.056318044662 -0.154584050179 -v -0.244804859161 1.037203311920 -0.166494607925 -v -0.242951393127 1.043129205704 -0.159860074520 -v -0.236907005310 1.041309475899 -0.161783397198 -v -0.243432760239 1.035140395164 -0.168893754482 -v -0.224668979645 1.052752375603 -0.157276332378 -v -0.230270862579 1.046147704124 -0.159191727638 -v -0.159595966339 1.184921741486 -0.135831117630 -v -0.160187005997 1.181343317032 -0.141996622086 -v -0.153135061264 1.179491877556 -0.142091393471 -v -0.169377088547 1.185044288635 -0.136880159378 -v -0.170533895493 1.181570768356 -0.151052296162 -v -0.160138130188 1.174441456795 -0.159372687340 -v -0.222903490067 1.065987110138 -0.152610003948 -v -0.210915327072 1.058199882507 -0.158076643944 -v -0.219084739685 1.052546024323 -0.157240092754 -v -0.209656953812 1.069716095924 -0.156206488609 -v -0.242612361908 1.097414970398 -0.161309957504 -v -0.247563600540 1.103350877762 -0.164090692997 -v -0.248119831085 1.110607266426 -0.158350706100 -v -0.241690874100 1.101655244827 -0.159433066845 -v -0.244697809219 1.092168807983 -0.164222717285 -v -0.251339673996 1.101027250290 -0.169793009758 -v -0.253261089325 1.111646056175 -0.160615861416 -v -0.246266365051 1.039236307144 -0.166336178780 -v -0.249294042587 1.037806272507 -0.168891787529 -v -0.250867843628 1.039080262184 -0.168178379536 -v -0.247174024582 1.041245818138 -0.164608359337 -v -0.252528667450 1.034430623055 -0.174002289772 -v -0.255876541138 1.036398887634 -0.174964785576 -v -0.248456478119 1.035744786263 -0.171986579895 -v -0.207899332047 1.087407350540 -0.147547543049 -v -0.209868431091 1.082488656044 -0.153715491295 -v -0.206011295319 1.082607984543 -0.148635447025 -v -0.207342624664 1.075194835663 -0.155124664307 -v -0.252168178558 1.045034170151 -0.165443241596 -v -0.258034706116 1.046116113663 -0.173089325428 -v -0.262003183365 1.051245570183 -0.178000867367 -v -0.252234935760 1.049173116684 -0.164762079716 -v -0.252549409866 1.041483521461 -0.167263507843 -v -0.259843349457 1.041425228119 -0.177599608898 -v -0.270201206207 1.045489907265 -0.187091112137 -v -0.276372432709 1.040201425552 -0.192463517189 -v -0.278449535370 1.034975290298 -0.196169674397 -v -0.284775257111 1.029717683792 -0.197532415390 -v -0.284212112427 1.040760636330 -0.193028330803 -v -0.271418571472 1.038434147835 -0.194264531136 -v -0.273589372635 1.034032583237 -0.199454545975 -v -0.281298398972 1.027353167534 -0.202217400074 -v -0.285241842270 1.052183389664 -0.197862207890 -v -0.287758827209 1.044720053673 -0.200536787510 -v -0.285270452499 1.052050352097 -0.209925532341 -v -0.284770965576 1.056814908981 -0.208144426346 -v -0.286429882050 1.041720151901 -0.204202711582 -v -0.282965183258 1.049952030182 -0.209141969681 -v -0.281043052673 1.048063278198 -0.188708662987 -v -0.144400358200 1.176907896996 -0.151417970657 -v -0.135134458542 1.175758123398 -0.166907787323 -v -0.129020690918 1.170335769653 -0.138893842697 -v -0.141971826553 1.174503087997 -0.135131359100 -v -0.119428634644 1.164143443108 -0.165285944939 -v -0.116199493408 1.159146547318 -0.141210973263 -v -0.142082691193 1.176310896873 -0.178735315800 -v -0.151244163513 1.175081014633 -0.169050514698 -v -0.125181674957 1.176591157913 -0.177203238010 -v -0.130443096161 1.183761119843 -0.186303555965 -v -0.245208501816 1.111506700516 -0.205009043217 -v -0.232599973679 1.125318527222 -0.206095397472 -v -0.240747690201 1.128869056702 -0.186226844788 -v -0.252095937729 1.110360264778 -0.190840721130 -v -0.230934619904 1.112748980522 -0.219200611115 -v -0.201740980148 1.135213136673 -0.227704524994 -v -0.210019588470 1.145615220070 -0.203961193562 -v -0.256554365158 1.026075959206 -0.197485446930 -v -0.252297163010 1.025413274765 -0.206123828888 -v -0.262440681458 1.028629183769 -0.203707456589 -v -0.262872934341 1.028875350952 -0.197542905807 -v -0.253294944763 1.027410507202 -0.211396694183 -v -0.259093761444 1.029339194298 -0.211079478264 -v -0.246476411819 1.024986743927 -0.206110835075 -v -0.252317905426 1.024993419647 -0.197774946690 -v -0.311765909195 0.993130266666 -0.226933717728 -v -0.310108184814 0.996098339558 -0.225180983543 -v -0.310272455215 0.995082259178 -0.224124073982 -v -0.309615135193 0.992788553238 -0.226431727409 -v -0.307722568512 0.995178222656 -0.223333239555 -v -0.308899879456 0.997443914413 -0.225597083569 -v -0.306552886963 0.996318519115 -0.226082086563 -v -0.301561355591 0.999858021736 -0.221365690231 -v -0.301273822784 0.999540150166 -0.223513543606 -v -0.300451040268 0.999494612217 -0.225161433220 -v -0.291275262833 1.008644461632 -0.219689548016 -v -0.289765357971 1.008863568306 -0.223312497139 -v -0.303882122040 1.002618789673 -0.222436308861 -v -0.245472908020 1.029212474823 -0.216191470623 -v -0.251756668091 1.032742142677 -0.216125905514 -v -0.240088224411 1.029202461243 -0.212740898132 -v -0.305489063263 0.996842980385 -0.228073120117 -v -0.301641464233 1.000535249710 -0.226922750473 -v -0.297816038132 1.000618338585 -0.226435422897 -v -0.304344177246 0.995790660381 -0.228550374508 -v -0.307172536850 0.993706703186 -0.230047941208 -v -0.308262586594 0.994648814201 -0.229670286179 -v -0.308869600296 0.993044137955 -0.230499446392 -v -0.308663368225 0.993162393570 -0.231502115726 -v -0.309333801270 0.993721485138 -0.231109619141 -v -0.308087825775 0.994998931885 -0.231224834919 -v -0.103364944458 1.130733013153 -0.165089964867 -v -0.107626914978 1.133225798607 -0.140607297421 -v -0.110349178314 1.147431254387 -0.169585108757 -v -0.118245124817 1.140465259552 -0.188436806202 -v -0.112480401993 1.127350330353 -0.185356020927 -v -0.119234800339 1.154477119446 -0.179611444473 -v -0.122121334076 1.162646651268 -0.173162460327 -v -0.123259067535 1.147673130035 -0.192043066025 -v -0.307780742645 0.994723260403 -0.231847167015 -v -0.307749986649 0.993669688702 -0.231788516045 -v -0.306983709335 0.993704020977 -0.230996787548 -v -0.193033456802 1.081855773926 -0.203872740269 -v -0.194959878922 1.074067234993 -0.206613779068 -v -0.192106723785 1.074653506279 -0.197215080261 -v -0.189585685730 1.081505656242 -0.199741780758 -v -0.181468963623 1.087621688843 -0.203916847706 -v -0.182246923447 1.086801290512 -0.208190560341 -v -0.180797338486 1.080666303635 -0.200190067291 -v -0.238004446030 1.038412332535 -0.221756696701 -v -0.255303144455 1.040868282318 -0.221722602844 -v -0.259346246719 1.034848093987 -0.217119097710 -v -0.226242780685 1.046014308929 -0.223912119865 -v -0.243605136871 1.045503258705 -0.225179314613 -v -0.229806661606 1.033677101135 -0.221885204315 -v -0.128174781799 1.188377022743 -0.200627446175 -v -0.148290157318 1.179109573364 -0.194076895714 -v -0.271722316742 1.054550886154 -0.227642059326 -v -0.274076938629 1.049859046936 -0.228212535381 -v -0.270540475845 1.041400551796 -0.231285452843 -v -0.265389442444 1.048523783684 -0.231947541237 -v -0.279670238495 1.057693004608 -0.219425976276 -v -0.279539346695 1.051576972008 -0.220776438713 -v -0.275705814362 1.041727423668 -0.228427529335 -v -0.199706077576 1.055555105209 -0.210151553154 -v -0.194469451904 1.055464029312 -0.201491832733 -v -0.188562631607 1.062397480011 -0.194959938526 -v -0.193209409714 1.067214727402 -0.202750325203 -v -0.197559595108 1.061594724655 -0.212190330029 -v -0.199322462082 1.054384827614 -0.212732195854 -v -0.264539003372 1.034891843796 -0.224602222443 -v -0.264505386353 1.033686161041 -0.220391511917 -v -0.259446859360 1.043034553528 -0.228882968426 -v -0.253154993057 1.049899816513 -0.229087173939 -v -0.192896127701 1.083252668381 -0.207294523716 -v -0.205631494522 1.076366066933 -0.214735269547 -v -0.194759368896 1.084827780724 -0.212751626968 -v -0.223470926285 1.074144601822 -0.221447348595 -v -0.204793214798 1.086842775345 -0.216361939907 -v -0.216625213623 1.087888479233 -0.219625651836 -v -0.195574283600 1.087720632553 -0.216327428818 -v -0.220762968063 1.036061048508 -0.216470956802 -v -0.213054895401 1.035783767700 -0.213620066643 -v -0.201663494110 1.045588612556 -0.206914484501 -v -0.209848642349 1.043720960617 -0.214580178261 -v -0.216307878494 1.038053512573 -0.218539953232 -v -0.226351261139 1.035285830498 -0.218240320683 -v -0.205461740494 1.046299815178 -0.217294871807 -v -0.213101387024 1.042110800743 -0.219072997570 -v -0.220921278000 1.039087295532 -0.221290767193 -v -0.220387458801 1.042260169983 -0.223516404629 -v -0.213362932205 1.046354770660 -0.223494648933 -v -0.166803121567 1.090283155441 -0.212349832058 -v -0.172270536423 1.087766289711 -0.218560039997 -v -0.183573484421 1.086018800735 -0.212494730949 -v -0.167399406433 1.091666579247 -0.207822561264 -v -0.158848285675 1.093401670456 -0.218638300896 -v -0.162909030914 1.089765548706 -0.223327994347 -v -0.030130147934 1.186614990234 -0.177592396736 -v -0.028016805649 1.185017704964 -0.176330447197 -v -0.027128219604 1.182949185371 -0.177097141743 -v -0.030794620514 1.185065984726 -0.177214145660 -v -0.027263402939 1.185469865799 -0.176604092121 -v -0.029033184052 1.187615036964 -0.178278744221 -v -0.025565147400 1.183858990669 -0.176834225655 -v -0.026248216629 1.187106251717 -0.178503096104 -v -0.155820369720 1.101422905922 -0.208842039108 -v -0.143939018250 1.110964536667 -0.203809499741 -v -0.147772073746 1.116233944893 -0.210553169250 -v -0.153800964355 1.103918313980 -0.216478586197 -v -0.151521444321 1.110116600990 -0.224545180798 -v -0.153570175171 1.098989486694 -0.229076087475 -v -0.153712034225 1.098475694656 -0.221522092819 -v -0.143598556519 1.121090412140 -0.215590834618 -v -0.025197982788 1.179040908813 -0.178160905838 -v -0.028691530228 1.180666327477 -0.177641034126 -v -0.024049282074 1.180395364761 -0.178064346313 -v -0.023061275482 1.183145642281 -0.176922082901 -v -0.024633884430 1.187012076378 -0.180191814899 -v -0.022006034851 1.183752536774 -0.176543354988 -v -0.023281335831 1.181692600250 -0.177503108978 -v -0.041700124741 1.194597840309 -0.188832759857 -v -0.040053844452 1.195041775703 -0.191445589066 -v -0.038641691208 1.194105863571 -0.194117784500 -v -0.021546125412 1.184016108513 -0.178950071335 -v -0.023211956024 1.185567021370 -0.181426763535 -v -0.020884990692 1.182555675507 -0.179597258568 -v -0.155306577682 1.094101190567 -0.223596096039 -v -0.153067588806 1.095505952835 -0.230197072029 -v -0.024875402451 1.176557660103 -0.180157959461 -v -0.029001712799 1.177595734596 -0.180325567722 -v -0.022265434265 1.178601741791 -0.180594265461 -v -0.022731781006 1.183528065681 -0.182420313358 -v -0.129092454910 1.126704692841 -0.201514482498 -v -0.129842519760 1.138575315475 -0.203304290771 -v -0.140452623367 1.137107372284 -0.216508805752 -v -0.143960952759 1.126296997070 -0.219137907028 -v -0.154357194901 1.127161264420 -0.228255271912 -v -0.149726629257 1.136419534683 -0.223747491837 -v -0.174418687820 1.142764806747 -0.223434805870 -v -0.169390678406 1.132646441460 -0.235435843468 -v -0.159634113312 1.138588905334 -0.227177619934 -v -0.183374881744 1.151468753815 -0.210604786873 -v -0.202531337738 1.122591972351 -0.235654771328 -v -0.174713850021 1.123547434807 -0.239896833897 -v -0.026677846909 1.177809119225 -0.182901620865 -v -0.028857231140 1.177586197853 -0.182363390923 -v -0.180840730667 1.098434567451 -0.228965997696 -v -0.177192926407 1.093732595444 -0.232580184937 -v -0.174651861191 1.104560375214 -0.238290369511 -v -0.178368806839 1.106090188026 -0.233393609524 -v -0.168076038361 1.097283363342 -0.234453976154 -v -0.169014692307 1.107891798019 -0.237803101540 -v -0.176104545593 1.089681625366 -0.227148771286 -v -0.167286634445 1.091750741005 -0.230993151665 -v -0.157043457031 1.091841936111 -0.227160215378 -v -0.159157276154 1.091518163681 -0.229555249214 -v -0.155268907547 1.095846176147 -0.231792688370 -v -0.160398960114 1.094118118286 -0.232700586319 -v -0.161424636841 1.113683462143 -0.233527243137 -v -0.153696537018 1.112774372101 -0.227253794670 -v -0.160377740860 1.100663542747 -0.232878029346 -v -0.155321598053 1.101318359375 -0.229982614517 -v -0.129415988922 1.121230006218 -0.195909500122 -v -0.115429162979 1.119397759438 -0.179361224174 -v -0.130902051926 1.117012500763 -0.191515922546 -v -0.115962266922 1.118604898453 -0.176315546036 -v -0.110272169113 1.120705842972 -0.160776674747 -v -0.113960504532 1.119729280472 -0.159553110600 -v -0.120643854141 1.123042941093 -0.142679691315 -v -0.116504192352 1.124894142151 -0.141778171062 -v -0.116237640381 1.119012355804 -0.159137606621 -v -0.121575117111 1.122238159180 -0.143324553967 -v -0.133432149887 1.123821258545 -0.128500640392 -v -0.129076957703 1.126407384872 -0.125177204609 -v -0.133791923523 1.122404217720 -0.126223802567 -v -0.151261806488 1.118286848068 -0.116750955582 -v -0.150382995605 1.123445391655 -0.118158876896 -v -0.165156841278 1.112223029137 -0.114312648773 -v -0.168798208237 1.119785189629 -0.114506125450 -v -0.146946668625 1.111286401749 -0.115677714348 -v -0.159301757813 1.103829860687 -0.112823069096 -v -0.169470071793 1.095391631126 -0.113259613514 -v -0.176546573639 1.104174375534 -0.116012811661 -v -0.181593179703 1.086678743362 -0.119435906410 -v -0.187299728394 1.095249652863 -0.122014880180 -v -0.192334890366 1.079224348068 -0.132685303688 -v -0.196459770203 1.086544990540 -0.133203148842 -v -0.167187929153 1.093284368515 -0.118592262268 -v -0.158042192459 1.100373268127 -0.117775142193 -v -0.177332639694 1.085744619370 -0.124823093414 -v -0.188689470291 1.078408122063 -0.135257482529 -v -0.133802890778 1.114060878754 -0.127829909325 -v -0.147693157196 1.107499122620 -0.121569573879 -v -0.130974292755 1.116622328758 -0.124757289886 -v -0.118712902069 1.116385936737 -0.142161726952 -v -0.114444732666 1.114831447601 -0.156344830990 -v -0.116871118546 1.115381836891 -0.173745512962 -v -0.127918481827 1.112462520599 -0.189754128456 -v -0.140444517136 1.105615377426 -0.201572239399 -v -0.153226137161 1.096442341805 -0.206420838833 -v -0.166574478149 1.087847948074 -0.204887628555 -v -0.148325681686 1.084455490112 -0.202776551247 -v -0.132059097290 1.095326542854 -0.197568535805 -v -0.118970394135 1.104256153107 -0.183249711990 -v -0.113605022430 1.110781550407 -0.171092212200 -v -0.119467735291 1.110980629921 -0.156059205532 -v -0.118595600128 1.107293367386 -0.167004108429 -v -0.122451543808 1.113593697548 -0.145232379436 -v -0.123160123825 1.101921558380 -0.179320454597 -v -0.134120464325 1.093572258949 -0.190831780434 -v -0.149135828018 1.083696126938 -0.196358323097 -v -0.164771795273 1.075974822044 -0.199542462826 -v -0.178263664246 1.069347739220 -0.194986939430 -v -0.178308486938 1.067918300629 -0.193336069584 -v -0.187574863434 1.061674833298 -0.193846702576 -v -0.165014982224 1.074935913086 -0.195628762245 -v -0.203114748001 1.047059774399 -0.203367710114 -v -0.194963455200 1.055162310600 -0.198111474514 -v -0.211767911911 1.036029338837 -0.208810448647 -v -0.212155818939 1.037373661995 -0.206103205681 -v -0.226508617401 1.025479078293 -0.212446689606 -v -0.223773002625 1.027394175529 -0.209277987480 -v -0.234503984451 1.028979897499 -0.212858796120 -v -0.240490436554 1.019392728806 -0.204267203808 -v -0.244890213013 1.018656373024 -0.196853935719 -v -0.253900766373 1.026709318161 -0.190710783005 -v -0.246401309967 1.020783185959 -0.188246011734 -v -0.252592563629 1.030183553696 -0.180509030819 -v -0.245979547501 1.024557352066 -0.179143786430 -v -0.256746768951 1.027064442635 -0.190641164780 -v -0.255533695221 1.030755162239 -0.181877255440 -v -0.261640310287 1.031444549561 -0.191453814507 -v -0.259487628937 1.033203363419 -0.183249652386 -v -0.265381097794 1.035956144333 -0.193069219589 -v -0.262969732285 1.038062810898 -0.186465203762 -v -0.266802787781 1.033626079559 -0.198642969131 -v -0.266010284424 1.031839489937 -0.204385280609 -v -0.270675420761 1.031339287758 -0.205536782742 -v -0.263313770294 1.031893968582 -0.211139619350 -v -0.266834974289 1.031145095825 -0.212556302547 -v -0.272355556488 1.027421116829 -0.214405179024 -v -0.271020889282 1.027558326721 -0.222151696682 -v -0.277619600296 1.026623606682 -0.207558810711 -v -0.287308216095 1.017905473709 -0.209584236145 -v -0.281747341156 1.017393589020 -0.217522501945 -v -0.290399074554 1.018112540245 -0.206793189049 -v -0.296507358551 1.008396148682 -0.213786959648 -v -0.293893098831 1.008637905121 -0.215864181519 -v -0.293311119080 1.018383622169 -0.204794526100 -v -0.298957824707 1.008759021759 -0.211997389793 -v -0.304624319077 1.000485181808 -0.218563914299 -v -0.302252292633 1.000493049622 -0.219046711922 -v -0.300442457199 1.010485529900 -0.212966322899 -v -0.295816421509 1.020895838737 -0.206146836281 -v -0.304791212082 1.002254843712 -0.220315814018 -v -0.298930644989 1.011639118195 -0.215272247791 -v -0.294509649277 1.021376132965 -0.208923101425 -v -0.305289983749 0.996663510799 -0.231430888176 -v -0.299525260925 1.002564072609 -0.230026721954 -v -0.304598808289 0.995765805244 -0.231520950794 -v -0.298396825790 1.001657962799 -0.230945348740 -v -0.303261518478 0.995977520943 -0.230365991592 -v -0.297660827637 1.000682115555 -0.229683041573 -v -0.297706365585 1.000391125679 -0.228264808655 -v -0.289501190186 1.008563995361 -0.227962017059 -v -0.289624452591 1.008912801743 -0.230370998383 -v -0.289333820343 1.008850455284 -0.225851535797 -v -0.279825210571 1.017765641212 -0.226271927357 -v -0.280007839203 1.018149375916 -0.228962600231 -v -0.279944658279 1.017497062683 -0.223519802094 -v -0.270844221115 1.027772903442 -0.226072430611 -v -0.271415948868 1.028410196304 -0.229272961617 -v -0.265730381012 1.036768198013 -0.229641437531 -v -0.273293256760 1.029914379120 -0.231202602386 -v -0.281020164490 1.019194722176 -0.231097579002 -v -0.275867462158 1.031501293182 -0.230385065079 -v -0.282980203629 1.020815610886 -0.230529665947 -v -0.276958703995 1.032087326050 -0.227720260620 -v -0.283688306808 1.021362662315 -0.227996766567 -v -0.275023937225 1.041705608368 -0.224775314331 -v -0.277465105057 1.049158096313 -0.218947708607 -v -0.292066335678 1.011417031288 -0.228806972504 -v -0.291158199310 1.010475993156 -0.230765581131 -v -0.289323091507 1.031211256981 -0.203581392765 -v -0.290323972702 1.031991720200 -0.200689315796 -v -0.239644289017 1.023190736771 -0.194890260696 -v -0.243260860443 1.023399710655 -0.188031911850 -v -0.234212636948 1.023423552513 -0.201564133167 -v -0.236090183258 1.021491050720 -0.202814877033 -v -0.199890851974 1.066753745079 -0.155146598816 -v -0.198434829712 1.067134857178 -0.156990110874 -v -0.202668666840 1.063336849213 -0.159977316856 -v -0.203597068787 1.063326001167 -0.157728374004 -v -0.194704532623 1.071926832199 -0.149038195610 -v -0.198426008224 1.071671962738 -0.146451592445 -v -0.204805612564 1.071662425995 -0.154704451561 -v -0.202652454376 1.077832579613 -0.147649407387 -v -0.199759483337 1.090992927551 -0.134201765060 -v -0.193034887314 1.103491783142 -0.123884439468 -v -0.185172319412 1.115739107132 -0.117173492908 -v -0.169998168945 1.124291777611 -0.114598035812 -v -0.171854734421 1.130073547363 -0.107446432114 -v -0.148004770279 1.133014440536 -0.109064579010 -v -0.149436950684 1.126783370972 -0.117963194847 -v -0.150363683701 1.141389131546 -0.109232008457 -v -0.129365682602 1.151356697083 -0.121360957623 -v -0.122787952423 1.133342862129 -0.118729412556 -v -0.155005455017 1.151965379715 -0.112209022045 -v -0.138591766357 1.161190986633 -0.122988164425 -v -0.160556554794 1.158395051956 -0.114823222160 -v -0.147845268250 1.166557192802 -0.123666226864 -v -0.164972066879 1.160841345787 -0.116209328175 -v -0.178743362427 1.155038595200 -0.107457756996 -v -0.193982124329 1.154866933823 -0.105260729790 -v -0.203804731369 1.162194013596 -0.107664465904 -v -0.203792333603 1.170711994171 -0.114600837231 -v -0.206958532333 1.165179967880 -0.118471503258 -v -0.199360370636 1.174407482147 -0.126586496830 -v -0.196566343307 1.177967667580 -0.121480822563 -v -0.211217403412 1.155824661255 -0.123464763165 -v -0.203953742981 1.165765166283 -0.134148895741 -v -0.217429161072 1.159095644951 -0.144569456577 -v -0.199710369110 1.170780539513 -0.160428583622 -v -0.189121007919 1.175161838531 -0.143832862377 -v -0.234441280365 1.145398378372 -0.158812522888 -v -0.208461523056 1.159196853638 -0.180670976639 -v -0.252185583115 1.116116285324 -0.170371294022 -v -0.254233121872 1.105154395103 -0.180382847786 -v -0.260434627533 1.096214771271 -0.185628652573 -v -0.256431102753 1.092083334923 -0.177367925644 -v -0.260645627975 1.097700595856 -0.194319903851 -v -0.270902156830 1.083015918732 -0.199528574944 -v -0.269893407822 1.081749439240 -0.189446091652 -v -0.256181478500 1.098464727402 -0.206231713295 -v -0.266798496246 1.083191156387 -0.212066352367 -v -0.273687601089 1.068179607391 -0.216568171978 -v -0.278900146484 1.067694902420 -0.202702641487 -v -0.258903264999 1.083254337311 -0.220462024212 -v -0.247154474258 1.097606897354 -0.216386973858 -v -0.265223979950 1.066669940948 -0.225265324116 -v -0.269017219543 1.059843063354 -0.226757824421 -v -0.277544975281 1.061369776726 -0.218553006649 -v -0.256574153900 1.063487887383 -0.228868722916 -v -0.250155687332 1.081251740456 -0.223481357098 -v -0.261117696762 1.055521845818 -0.231173992157 -v -0.248385906219 1.057556748390 -0.228811144829 -v -0.238748550415 1.076548695564 -0.223608195782 -v -0.234692811966 1.056388735771 -0.223354101181 -v -0.211627244949 1.056368947029 -0.221282124519 -v -0.228275060654 1.091947317123 -0.220990777016 -v -0.238418102264 1.094660639763 -0.219326555729 -v -0.216057777405 1.107417821884 -0.225473523140 -v -0.224503517151 1.109220266342 -0.227116346359 -v -0.211361885071 1.098301529884 -0.220512151718 -v -0.212726354599 1.104912161827 -0.221194267273 -v -0.207950830460 1.100727200508 -0.218157291412 -v -0.203674316406 1.092759370804 -0.219182014465 -v -0.202742576599 1.096199750900 -0.218188643456 -v -0.196501970291 1.090510606766 -0.218953371048 -v -0.196993589401 1.093491673470 -0.220363080502 -v -0.187599182129 1.091245770454 -0.224233686924 -v -0.188641786575 1.095030307770 -0.223733663559 -v -0.186239719391 1.088770151138 -0.220787882805 -v -0.185178756714 1.086016893387 -0.216318964958 -v -0.174246788025 1.087175607681 -0.223291456699 -v -0.165641307831 1.089258909225 -0.227088153362 -v -0.211334466934 1.109454154968 -0.224141299725 -v -0.196863412857 1.116337895393 -0.232053399086 -v -0.198950290680 1.117026805878 -0.234745264053 -v -0.180886983871 1.115268468857 -0.233694016933 -v -0.180615663528 1.115485668182 -0.236742198467 -v -0.177260398865 1.118756055832 -0.240124464035 -v -0.201287984848 1.117602467537 -0.238141715527 -v -0.282895326614 1.060189247131 -0.204914152622 -v -0.282418012619 1.057005047798 -0.194644689560 -v -0.277503967285 1.065804839134 -0.192061483860 -v -0.270702600479 1.064300417900 -0.181479215622 -v -0.276010751724 1.054841160774 -0.184064984322 -v -0.264964342117 1.078153371811 -0.180190920830 -v -0.254631042480 1.068855047226 -0.170619845390 -v -0.259245395660 1.057962894440 -0.174149036407 -v -0.248440742493 1.082378029823 -0.167859196663 -v -0.239177227020 1.074390888214 -0.160453259945 -v -0.243740320206 1.063062429428 -0.160507678986 -v -0.249438762665 1.055111646652 -0.162672996521 -v -0.241800546646 1.051291108131 -0.157198011875 -v -0.245920419693 1.046977758408 -0.160051584244 -v -0.247624635696 1.043250799179 -0.161501169205 -v -0.185623407364 1.163547277451 -0.191922187805 -v -0.178851366043 1.168696165085 -0.170140326023 -v -0.171039104462 1.162240505219 -0.197747766972 -v -0.167164564133 1.171891689301 -0.179815948009 -v -0.169514179230 1.153752446175 -0.212879836559 -v -0.163647174835 1.155890226364 -0.217210114002 -v -0.164894342422 1.163555622101 -0.203335464001 -v -0.162951707840 1.147874236107 -0.221974015236 -v -0.158002376556 1.151909351349 -0.223278760910 -v -0.154706716537 1.144289135933 -0.224242210388 -v -0.152066946030 1.148701906204 -0.224407970905 -v -0.146767616272 1.142306327820 -0.221583485603 -v -0.143728017807 1.146293640137 -0.221992492676 -v -0.138458013535 1.141785860062 -0.215267539024 -v -0.135710000992 1.144933223724 -0.215805530548 -v -0.130891323090 1.143802881241 -0.204370617867 -v -0.129570007324 1.146505594254 -0.206188857555 -v -0.125153064728 1.151684284210 -0.194277405739 -v -0.120690345764 1.156343221664 -0.196658849716 -v -0.123557567596 1.151302337646 -0.207581400871 -v -0.123983860016 1.158541202545 -0.182885527611 -v -0.120908975601 1.161676406860 -0.185635268688 -v -0.127824783325 1.167345404625 -0.175681769848 -v -0.122528076172 1.169641494751 -0.178976297379 -v -0.113455295563 1.165868759155 -0.187700688839 -v -0.108748197556 1.163328170776 -0.198548078537 -v -0.110469579697 1.173360347748 -0.185494899750 -v -0.091323852539 1.179773807526 -0.191483795643 -v -0.090184450150 1.176342606544 -0.194954812527 -v -0.111765384674 1.178711295128 -0.185415387154 -v -0.092939138412 1.184199452400 -0.190637469292 -v -0.113289833069 1.182440042496 -0.187966227531 -v -0.095153093338 1.187181711197 -0.191652655602 -v -0.073956251144 1.192005038261 -0.192678928375 -v -0.073637962341 1.188065290451 -0.191455483437 -v -0.099256277084 1.190625190735 -0.194961786270 -v -0.073813676834 1.195713639259 -0.195692181587 -v -0.096777915955 1.196445703506 -0.206112921238 -v -0.072917699814 1.198483467102 -0.200721621513 -v -0.095563650131 1.196424365044 -0.214924454689 -v -0.071158885956 1.198626756668 -0.206956505775 -v -0.129826784134 1.190738201141 -0.212317109108 -v -0.157343387604 1.172712326050 -0.208674550056 -v -0.128477811813 1.186428785324 -0.221658170223 -v -0.093955516815 1.193287849426 -0.221389353275 -v -0.154647350311 1.168583154678 -0.219737291336 -v -0.149827718735 1.162814021111 -0.225700199604 -v -0.124877214432 1.179793953896 -0.226911485195 -v -0.144460201263 1.156676888466 -0.227152824402 -v -0.120687484741 1.171841144562 -0.228286266327 -v -0.139381647110 1.150594115257 -0.223807334900 -v -0.117116689682 1.165078282356 -0.225237190723 -v -0.128769636154 1.149663209915 -0.217538893223 -v -0.111747980118 1.161472201347 -0.217855334282 -v -0.109767198563 1.161700129509 -0.209116935730 -v -0.088203907013 1.172519445419 -0.211088180542 -v -0.088263034821 1.173820972443 -0.218165874481 -v -0.089234113693 1.173993110657 -0.201246440411 -v -0.071101665497 1.179669737816 -0.199828505516 -v -0.069531917572 1.179702758789 -0.205872833729 -v -0.072219848633 1.181545853615 -0.195242881775 -v -0.056831598282 1.183016300201 -0.193188905716 -v -0.055566310883 1.181527018547 -0.196716129780 -v -0.073021411896 1.184370517731 -0.192374467850 -v -0.057552337646 1.185418963432 -0.190718352795 -v -0.057724237442 1.188611626625 -0.189705491066 -v -0.045343875885 1.186881065369 -0.185175061226 -v -0.045280933380 1.183866500854 -0.186353206635 -v -0.057383060455 1.192056655884 -0.190340936184 -v -0.044640541077 1.190080165863 -0.185317754745 -v -0.056554079056 1.195130228996 -0.192540347576 -v -0.043342113495 1.192810654640 -0.186669468880 -v -0.055220603943 1.197255134583 -0.196023941040 -v -0.053610086441 1.197649002075 -0.200031757355 -v -0.052100419998 1.196197032928 -0.203523576260 -v -0.069370269775 1.196292161942 -0.211897075176 -v -0.068021297455 1.192861676216 -0.214833736420 -v -0.050945520401 1.193327188492 -0.205915927887 -v -0.092361450195 1.188226699829 -0.224879384041 -v -0.090728044510 1.182599067688 -0.225352346897 -v -0.067334413528 1.188707113266 -0.215543806553 -v -0.089248895645 1.177467584610 -0.223018467426 -v -0.067439317703 1.184669256210 -0.214068412781 -v -0.068172216415 1.181514143944 -0.210815250874 -v -0.052105903625 1.183036804199 -0.204133033752 -v -0.050871849060 1.185964107513 -0.206329762936 -v -0.053818464279 1.181404590607 -0.200728774071 -v -0.041506052017 1.180616259575 -0.193893551826 -v -0.039731979370 1.182307600975 -0.196195423603 -v -0.043209075928 1.180416822433 -0.191138744354 -v -0.044537305832 1.181544065475 -0.188471496105 -v -0.031432151794 1.183127760887 -0.177642107010 -v -0.023880004883 1.179421424866 -0.182783424854 -v -0.023120403290 1.181398153305 -0.182788312435 -v -0.038379907608 1.185227513313 -0.197383880615 -v -0.021365642548 1.180629491806 -0.180217981339 -v -0.037654399872 1.188567876816 -0.197493553162 -v -0.037757396698 1.191774725914 -0.196288704872 -v -0.050418376923 1.189674615860 -0.206975281239 -v -0.158075809479 1.171878576279 -0.187048196793 -v -0.184828758240 1.181181192398 -0.133212804794 -v -0.183850765228 1.183899402618 -0.127866744995 -v -0.169936895370 1.187874436378 -0.131015658379 -v -0.160047531128 1.187471389771 -0.131462752819 -v -0.157574653625 1.192477464676 -0.129109740257 -v -0.170529127121 1.193306446075 -0.127960264683 -v -0.157630920410 1.193547725677 -0.127042472363 -v -0.168020248413 1.194449782372 -0.126551985741 -v -0.155678272247 1.197181582451 -0.117395758629 -v -0.168904304504 1.200421571732 -0.116072595119 -v -0.177747726440 1.199375391006 -0.109128236771 -v -0.186355590820 1.196253895760 -0.100548923016 -v -0.188017368317 1.190521001816 -0.119188547134 -v -0.194039821625 1.188312888145 -0.112169504166 -v -0.203054904938 1.179349541664 -0.106702864170 -v -0.192745685577 1.189022660255 -0.093927919865 -v -0.195131540298 1.185600280762 -0.119000375271 -v -0.185272932053 1.190236568451 -0.123825550079 -v -0.202980279922 1.177518606186 -0.111484885216 -v -0.206887245178 1.169745087624 -0.105333983898 -v -0.206416130066 1.174813270569 -0.101252019405 -v -0.199194669724 1.162851572037 -0.099504411221 -v -0.197700738907 1.180861234665 -0.091671824455 -v -0.150561571121 1.174575209618 -0.132039248943 -v -0.209591627121 1.058356404305 -0.160460770130 -v -0.217305183411 1.052603721619 -0.160649895668 -v -0.238281965256 1.033112168312 -0.170957684517 -v -0.244051933289 1.025660991669 -0.180232465267 -v -0.239808082581 1.032481074333 -0.169264376163 -v -0.232315063477 1.036808967590 -0.161297738552 -v -0.230905294418 1.037472367287 -0.163685441017 -v -0.225137472153 1.044082164764 -0.158028185368 -v -0.223443984985 1.044231295586 -0.160395681858 -v -0.223054885864 1.028931379318 -0.207141757011 -v -0.210240125656 1.094408273697 -0.117802858353 -v -0.226145267487 1.091406583786 -0.144528210163 -v -0.228773593903 1.093539595604 -0.144238770008 -v -0.229978561401 1.091392636299 -0.150956988335 -v -0.231330394745 1.094696521759 -0.150297284126 -v -0.228517770767 1.097494721413 -0.144955992699 -v -0.229495048523 1.099721908569 -0.131893873215 -v -0.229601860046 1.105694532394 -0.127975225449 -v -0.230824470520 1.112782955170 -0.126599431038 -v -0.231130123138 1.112404465675 -0.120916366577 -v -0.238191127777 1.121705651283 -0.135489940643 -v -0.240043640137 1.121748328209 -0.132544755936 -v -0.242587566376 1.117125391960 -0.144999742508 -v -0.246487855911 1.119711399078 -0.144290924072 -v -0.241481542587 1.113143205643 -0.153935611248 -v -0.245183229446 1.112014532089 -0.156490027905 -v -0.238260984421 1.105642080307 -0.157133936882 -v -0.240424156189 1.103380203247 -0.159065842628 -v -0.233463764191 1.100573539734 -0.154703736305 -v -0.235453605652 1.097964048386 -0.155216693878 -v -0.235904932022 1.095326662064 -0.155326545238 -v -0.230455398560 1.097877264023 -0.150153517723 -v -0.249421119690 1.121675491333 -0.144378840923 -v -0.240281105042 1.124884128571 -0.131052792072 -v -0.227780818939 1.113982677460 -0.117298245430 -v -0.130397796631 1.182343721390 -0.076600074768 -v -0.129862308502 1.183777570724 -0.072378516197 -v -0.136162042618 1.179548740387 -0.069244503975 -v -0.137062549591 1.183297991753 -0.068274199963 -v -0.133409261703 1.184647083282 -0.072437226772 -v -0.144817352295 1.180659770966 -0.065627694130 -v -0.142683744431 1.184700131416 -0.066475808620 -v -0.271175146103 1.039876699448 -0.190005302429 -v -0.301822423935 1.001146674156 -0.225157797337 -v 0.040446281433 1.266857385635 0.129650652409 -v 0.045840978622 1.267236709595 0.128639698029 -v 0.042178869247 1.272785186768 0.116086125374 -v 0.035976171494 1.262238383293 0.125946938992 -v -0.000801801682 1.292400956154 0.102130472660 -v -0.000761747360 1.303220987320 0.093628942966 -v 0.015448331833 1.314785122871 0.084255039692 -v 0.030528545380 1.315371155739 0.082960784435 -v 0.019721984863 1.301102638245 0.098109424114 -v 0.034617424011 1.303159475327 0.095117151737 -v -0.001373052597 1.277826786041 0.111266195774 -v -0.001722097397 1.284371614456 0.109198451042 -v 0.011536121368 1.282118082047 0.111050844193 -v 0.009827852249 1.276010155678 0.111163258553 -v 0.008899927139 1.272522568703 0.108775258064 -v 0.007982730865 1.269812107086 0.108590006828 -v -0.013120889664 1.280258178711 0.103836178780 -v -0.013952493668 1.287459611893 0.096029043198 -v -0.010375499725 1.274148821831 0.106453537941 -v -0.007061481476 1.270083665848 0.105696380138 -v 0.000071287155 1.273618578911 0.108782231808 -v -0.005353450775 1.267195701599 0.105669260025 -v -0.003715276718 1.265943884850 0.104040384293 -v -0.004131793976 1.253381729126 0.104748189449 -v -0.003669261932 1.256071329117 0.105417490005 -v -0.002878904343 1.257432699203 0.105259358883 -v -0.013543844223 1.267071247101 0.099097788334 -v -0.009968519211 1.265434265137 0.100078165531 -v -0.008393764496 1.263895630836 0.101276814938 -v -0.006794929504 1.262893676758 0.101056635380 -v -0.010854721069 1.252157211304 0.098580598831 -v -0.008997440338 1.255574226379 0.100211143494 -v -0.010912179947 1.258270978928 0.096816718578 -v -0.011093616486 1.261292099953 0.096696496010 -v -0.007898807526 1.257424354553 0.101626813412 -v -0.009550809860 1.259004950523 0.098516225815 -v -0.009840488434 1.260907649994 0.098658919334 -v -0.006556272507 1.258249044418 0.101993978024 -v -0.008103132248 1.259290218353 0.099143624306 -v -0.008106708527 1.260651588440 0.098746120930 -v 0.000634908676 1.269962787628 0.108458042145 -v 0.001318454742 1.268399953842 0.106259763241 -v 0.007476329803 1.268658280373 0.106844902039 -v 0.003443002701 1.252889513969 0.108284533024 -v 0.002853155136 1.255975246429 0.108673334122 -v 0.002923965454 1.257455945015 0.107795357704 -v 0.011467933655 1.255045294762 0.108669996262 -v 0.009955406189 1.257626056671 0.108927190304 -v 0.009441614151 1.258421897888 0.107399821281 -v 0.014464855194 1.289756536484 0.104732036591 -v 0.025943517685 1.283508300781 0.107297778130 -v 0.039303779602 1.279110550880 0.106710374355 -v 0.036115169525 1.278290748596 0.107457518578 -v 0.042536735535 1.278733968735 0.105807304382 -v 0.030768871307 1.288198709488 0.104064941406 -v 0.037350654602 1.289890766144 0.102047562599 -v 0.032482862473 1.275633811951 0.108351588249 -v 0.028729915619 1.263514757156 0.113653242588 -v 0.018857955933 1.271643638611 0.108702600002 -v 0.016063928604 1.269024133682 0.106653332710 -v 0.028270483017 1.270699024200 0.108028233051 -v 0.022220373154 1.277044057846 0.110479056835 -v 0.019372463226 1.258092880249 0.110031247139 -v 0.023556232452 1.262869477272 0.107618689537 -v 0.035057067871 1.268901348114 0.115687489510 -v 0.039037466049 1.272062182426 0.116605579853 -v 0.014039754868 1.267450094223 0.106931269169 -v 0.012716054916 1.266707539558 0.106147646904 -v 0.017132282257 1.259011745453 0.106750369072 -v 0.020047903061 1.262408375740 0.104903697968 -v 0.019694805145 1.265416860580 0.105079472065 -v 0.017275571823 1.264821529388 0.105033516884 -v 0.017734289169 1.262517094612 0.104454278946 -v 0.015003919601 1.260491371155 0.107061386108 -v 0.015677213669 1.264597892761 0.104555845261 -v 0.016396999359 1.262519359589 0.103408336639 -v 0.014380216599 1.260196924210 0.104527294636 -v 0.023535966873 1.267078399658 0.106167256832 -v -0.012151002884 1.235135316849 0.109545886517 -v -0.016305923462 1.224170684814 0.110445380211 -v -0.010377168655 1.200674295425 0.124419331551 -v -0.006423950195 1.185832023621 0.138172209263 -v -0.010899543762 1.192893743515 0.129531621933 -v -0.017629623413 1.210340738297 0.107257723808 -v -0.026541233063 1.185374736786 0.118990361691 -v -0.022340297699 1.197549104691 0.109548330307 -v 0.035350084305 1.248472332954 0.142883300781 -v 0.051932334900 1.253603696823 0.148347139359 -v 0.041118383408 1.258031487465 0.142182707787 -v 0.049641847610 1.260149955750 0.141103088856 -v 0.044825792313 1.252733945847 0.148908674717 -v 0.042319774628 1.246564269066 0.148949384689 -v 0.041991710663 1.241669535637 0.144866228104 -v 0.052286386490 1.246867418289 0.148005247116 -v 0.051711082458 1.241842269897 0.144327402115 -v 0.035593986511 1.255735874176 0.134251892567 -v 0.029677391052 1.244845509529 0.136716425419 -v 0.033319473267 1.250971555710 0.137745916843 -v 0.031243801117 1.242845058441 0.136967241764 -v 0.030688762665 1.256210803986 0.122289538383 -v 0.030338525772 1.250825643539 0.129136621952 -v 0.028740406036 1.247478961945 0.134274959564 -v 0.033815860748 1.242522120476 0.134662628174 -v 0.036343336105 1.243577361107 0.131516873837 -v 0.035639047623 1.243583917618 0.141259193420 -v 0.038025856018 1.243572592735 0.136724710464 -v 0.038744688034 1.229243755341 0.136170148849 -v 0.024222373962 1.241967678070 0.129807054996 -v 0.026626348495 1.240379929543 0.132212758064 -v 0.025287628174 1.233862161636 0.128705739975 -v 0.029455423355 1.240218400955 0.133426547050 -v 0.032053232193 1.237096786499 0.129116058350 -v 0.032113552094 1.241108894348 0.132747650146 -v 0.035292625427 1.241956233978 0.129371285439 -v 0.030912876129 1.229870319366 0.131015717983 -v 0.030648946762 1.224499464035 0.134449362755 -v 0.044306993484 1.238245844841 0.135809302330 -v 0.043252468109 1.240461349487 0.139098584652 -v 0.042135715485 1.240919113159 0.133995532990 -v 0.041716814041 1.241783857346 0.135482788086 -v 0.039429187775 1.243738889694 0.133056044579 -v 0.050420999527 1.240142822266 0.139068543911 -v 0.044756889343 1.234812498093 0.136098802090 -v 0.045078516006 1.231711387634 0.137417495251 -v 0.049524068832 1.238426923752 0.135339796543 -v 0.049675464630 1.235311508179 0.135039925575 -v 0.049990892410 1.232141256332 0.135455429554 -v 0.050583839417 1.228020906448 0.136361002922 -v 0.039813756943 1.238145470619 0.129698514938 -v 0.039825677872 1.242085576057 0.130345582962 -v 0.038737535477 1.233376264572 0.133297681808 -v 0.021462440491 1.217258930206 0.132264912128 -v 0.022056579590 1.212752580643 0.133517026901 -v 0.018235683441 1.205214858055 0.139099240303 -v 0.020352602005 1.209083795547 0.136137485504 -v 0.026568651199 1.202765941620 0.148095548153 -v 0.023966073990 1.192803263664 0.152344107628 -v 0.016592502594 1.199261784554 0.141214609146 -v 0.012834787369 1.191551685333 0.144409120083 -v 0.037743806839 1.215576529503 0.149055123329 -v 0.045881509781 1.225828409195 0.145537972450 -v 0.052435159683 1.227740526199 0.144624948502 -v 0.046445846558 1.218936204910 0.150274634361 -v 0.053923368454 1.220834851265 0.149113297462 -v 0.037250757217 1.206232309341 0.152749001980 -v 0.035874843597 1.194463729858 0.157640993595 -v 0.046791553497 1.196104288101 0.159853577614 -v 0.056510210037 1.197567701340 0.158931136131 -v 0.046874284744 1.208952426910 0.154512763023 -v 0.055248498917 1.210875630379 0.153577446938 -v 0.029203891754 1.216282963753 0.141427814960 -v 0.038281440735 1.222136378288 0.144550740719 -v 0.039469957352 1.224807739258 0.138187825680 -v 0.027691841125 1.210708260536 0.145226716995 -v 0.031136751175 1.219664812088 0.136600375175 -v 0.045809268951 1.227646589279 0.138405919075 -v 0.014129638672 1.249409794807 0.115332782269 -v 0.012882471085 1.252357363701 0.110826134682 -v 0.003088235855 1.244774341583 0.113203525543 -v 0.015806198120 1.243852615356 0.119367957115 -v 0.002343654633 1.237422823906 0.117558121681 -v 0.001748561859 1.226236939430 0.122058868408 -v 0.018728971481 1.236750602722 0.120574116707 -v 0.013330936432 1.222983598709 0.124980926514 -v 0.020515918732 1.223115921021 0.129145741463 -v -0.008113384247 1.243763685226 0.107061862946 -v -0.005330562592 1.249330997467 0.104984104633 -v 0.003616333008 1.249160528183 0.109515726566 -v 0.024304866791 1.250104308128 0.120198249817 -v 0.023406744003 1.245513081551 0.126008749008 -v 0.022205352783 1.255663037300 0.115017294884 -v 0.022286176682 1.233654975891 0.123781740665 -v 0.005661487579 1.202055335045 0.129107356071 -v -0.006587982178 1.211276650429 0.122517585754 -v 0.004577875137 1.210666298866 0.126435041428 -v 0.000176429749 1.201238393784 0.127685189247 -v 0.010596990585 1.210288167000 0.128963351250 -v 0.011595726013 1.201239705086 0.133424997330 -v 0.008545637131 1.200110793114 0.130007266998 -v 0.008605241776 1.202653884888 0.129701614380 -v 0.013861179352 1.203346967697 0.131477773190 -v 0.010287761688 1.201593160629 0.130020737648 -v 0.010378360748 1.202918767929 0.129963099957 -v 0.013339757919 1.208619117737 0.130371451378 -v 0.014328479767 1.206321358681 0.130973219872 -v 0.004492282867 1.192520976067 0.136268198490 -v 0.005780458450 1.198042392731 0.130144894123 -v 0.000226497650 1.195833086967 0.130556583405 -v 0.009120702744 1.197683811188 0.134836256504 -v -0.030488014221 1.283267021179 0.061819374561 -v -0.020040273666 1.274581432343 0.086394488811 -v -0.024308919907 1.279701232910 0.074724912643 -v -0.023217916489 1.261051177979 0.081465482712 -v -0.028754949570 1.261417388916 0.070602059364 -v -0.036482095718 1.283128738403 0.047661483288 -v -0.035109758377 1.260555624962 0.058661758900 -v -0.041009902954 1.257912158966 0.046594083309 -v -0.021064043045 1.302900314331 0.072026371956 -v -0.003322601318 1.312586545944 0.080484449863 -v -0.016522645950 1.296046495438 0.085470199585 -v -0.025208473206 1.303212285042 0.054149925709 -v -0.007358551025 1.313477158546 0.060375809669 -v 0.010043859482 1.317523241043 0.063381493092 -v 0.024682044983 1.319341421127 0.062246799469 -v -0.017404079437 1.270059585571 0.095172524452 -v -0.018391847610 1.253546833992 0.091046571732 -v -0.013947963715 1.256553530693 0.094790697098 -v -0.014717340469 1.261037349701 0.094909310341 -v -0.018908500671 1.260896086693 0.090010643005 -v -0.020776271820 1.238931417465 0.095742464066 -v -0.023503780365 1.249016761780 0.084496319294 -v -0.025747776031 1.229195833206 0.091487228870 -v -0.028454780579 1.243663668633 0.075471043587 -v -0.028841972351 1.217222690582 0.085641384125 -v -0.036760330200 1.200345516205 0.081055641174 -v -0.043103218079 1.175856351852 0.098108768463 -v -0.034443616867 1.237311244011 0.066220164299 -v -0.040151596069 1.230180382729 0.055966675282 -v -0.047009706497 1.225324869156 0.042491793633 -v -0.047743082047 1.194535493851 0.058303952217 -v -0.054014205933 1.190686464310 0.040780961514 -v -0.015044689178 1.246884107590 0.097714483738 -v 0.051012039185 1.267523407936 0.126842677593 -v 0.053725004196 1.263754844666 0.121200740337 -v 0.044191360474 1.316711425781 0.076770126820 -v 0.049160242081 1.303004741669 0.090367913246 -v 0.070050954819 1.296021223068 0.083691716194 -v 0.064377546310 1.307411193848 0.076644003391 -v 0.044227600098 1.289105176926 0.100519239902 -v 0.046434164047 1.276561975479 0.104707181454 -v 0.050604581833 1.285138130188 0.100853264332 -v 0.058474540710 1.292474508286 0.093251526356 -v 0.065127134323 1.284862875938 0.097177326679 -v 0.048618316650 1.269841313362 0.112119197845 -v 0.045237541199 1.272487878799 0.114981353283 -v 0.053706645966 1.265324115753 0.107027411461 -v 0.050548315048 1.272162795067 0.102230787277 -v 0.056096792221 1.279160976410 0.101499915123 -v 0.055377244949 1.264985799789 0.099373936653 -v 0.058884382248 1.273606300354 0.098348557949 -v 0.060819864273 1.270249724388 0.095299720764 -v 0.067456960678 1.278015136719 0.096721053123 -v 0.067724943161 1.273309826851 0.094431757927 -v 0.068783521652 1.270277500153 0.094106316566 -v 0.060762882233 1.261790990829 0.099568009377 -v 0.054175376892 1.268918275833 0.098160982132 -v 0.062816143036 1.268297910690 0.094869017601 -v 0.063694953918 1.267551422119 0.093782484531 -v 0.068581581116 1.269197702408 0.092460989952 -v 0.061268568039 1.263207793236 0.095967531204 -v 0.057333707809 1.264688968658 0.095514893532 -v 0.057271957397 1.267230391502 0.095370531082 -v 0.059454441071 1.266519188881 0.094323635101 -v 0.059153795242 1.264902830124 0.094141185284 -v 0.062749862671 1.265080451965 0.095315635204 -v 0.060599803925 1.266317009926 0.093307375908 -v 0.059796094894 1.264950871468 0.092611730099 -v 0.062308549881 1.264286756516 0.092826724052 -v 0.067521333694 1.262562036514 0.095242917538 -v 0.068541765213 1.265034556389 0.094969451427 -v 0.068204641342 1.265207529068 0.093506395817 -v 0.077112913132 1.279425144196 0.091373026371 -v 0.075383424759 1.286835432053 0.089299082756 -v 0.082441329956 1.283947467804 0.079257071018 -v 0.078902959824 1.292372465134 0.071949005127 -v 0.075701475143 1.271097064018 0.090313911438 -v 0.074272155762 1.269963860512 0.088880062103 -v 0.080384016037 1.272943258286 0.083734631538 -v 0.075593948364 1.274363636971 0.090127468109 -v 0.079707145691 1.270199537277 0.084501504898 -v 0.077773094177 1.269171714783 0.084009110928 -v 0.074470520020 1.262153863907 0.091184914112 -v 0.074804306030 1.264805197716 0.091423273087 -v 0.074141263962 1.265561819077 0.090759217739 -v 0.079296112061 1.262190818787 0.084158301353 -v 0.078951358795 1.264721870422 0.085185348988 -v 0.078058242798 1.265552878380 0.085563898087 -v 0.080155134201 1.268244743347 0.078729867935 -v 0.078858852386 1.267360806465 0.079410076141 -v 0.080429077148 1.264863848686 0.079188346863 -v 0.080001354218 1.264985084534 0.075401127338 -v 0.080117464066 1.266297817230 0.075324594975 -v 0.079468488693 1.265514373779 0.080408871174 -v 0.079141855240 1.265153050423 0.076866209507 -v 0.078771829605 1.266029000282 0.076456785202 -v 0.082354784012 1.277361154556 0.082759082317 -v 0.082641601563 1.272576570511 0.074128508568 -v 0.080540895462 1.270089030266 0.076882600784 -v 0.081943511963 1.258766055107 0.074625015259 -v 0.080802440643 1.262812852859 0.077187001705 -v 0.080394029617 1.264332532883 0.073039591312 -v 0.080169439316 1.266933917999 0.072909772396 -v 0.057654857635 1.259309649467 0.137847244740 -v 0.058503150940 1.253966927528 0.145442008972 -v 0.064238071442 1.251279354095 0.135221183300 -v 0.061223030090 1.248335599899 0.143793106079 -v 0.060226678848 1.243742227554 0.139886677265 -v 0.058931112289 1.258131980896 0.127938270569 -v 0.063202142715 1.254297494888 0.129694104195 -v 0.065549135208 1.247506380081 0.127456486225 -v 0.057339906693 1.259414553642 0.114988744259 -v 0.062293052673 1.246687650681 0.126744151115 -v 0.058286666870 1.246920347214 0.125443816185 -v 0.066583871841 1.249766945839 0.126530528069 -v 0.061671018600 1.255462884903 0.120306611061 -v 0.065866470337 1.252713918686 0.123935759068 -v 0.054228067398 1.239598989487 0.133096814156 -v 0.056482315063 1.242153167725 0.135511994362 -v 0.054856777191 1.242565155029 0.130528688431 -v 0.055840969086 1.243560433388 0.131651639938 -v 0.056303262711 1.246041178703 0.128419876099 -v 0.063732147217 1.246660113335 0.133645892143 -v 0.059375524521 1.246311187744 0.130905628204 -v 0.054415225983 1.236288070679 0.133475065231 -v 0.055111885071 1.233415126801 0.134682297707 -v 0.059905767441 1.232897996902 0.130329132080 -v 0.055068492889 1.240468859673 0.125481486320 -v 0.054852485657 1.244311332703 0.126182913780 -v 0.061526775360 1.241811394691 0.120923161507 -v 0.062999248505 1.245989322662 0.124036252499 -v 0.058302879333 1.245635032654 0.122877240181 -v 0.058226346970 1.236359000206 0.127980589867 -v 0.068130016327 1.248301506042 0.117564380169 -v 0.067496299744 1.246428251266 0.120817005634 -v 0.067075014114 1.240431427956 0.117183685303 -v 0.065690279007 1.245734214783 0.123227000237 -v 0.063593864441 1.235562324524 0.122017323971 -v 0.065532922745 1.231557369232 0.124712467194 -v 0.058642148972 1.228264093399 0.141964733601 -v 0.060995340347 1.221785545349 0.146217465401 -v 0.067803859711 1.221554160118 0.140724539757 -v 0.065596818924 1.198537349701 0.155037641525 -v 0.063088893890 1.211889743805 0.150147914886 -v 0.070540428162 1.212059378624 0.143783211708 -v 0.074363708496 1.199054241180 0.147871077061 -v 0.055469512939 1.229463577271 0.135724365711 -v 0.064706325531 1.227428913116 0.137217521667 -v 0.060773849487 1.229086875916 0.132322847843 -v 0.070334196091 1.226015686989 0.129881024361 -v 0.073707818985 1.221224188805 0.132331371307 -v 0.066503286362 1.228003025055 0.126726925373 -v 0.071586132050 1.228841543198 0.118208587170 -v 0.071873664856 1.225707650185 0.119430422783 -v 0.077915668488 1.220404744148 0.122084975243 -v 0.074536085129 1.223444819450 0.120662927628 -v 0.076755285263 1.212785243988 0.134442687035 -v 0.081811666489 1.200371980667 0.137430131435 -v 0.080988883972 1.214165449142 0.123166322708 -v 0.086687803268 1.203819513321 0.124526441097 -v 0.062492609024 1.254801988602 0.109791696072 -v 0.066610813141 1.251634597778 0.113950848579 -v 0.061021566391 1.259107947350 0.104773223400 -v 0.068827152252 1.254087090492 0.101265370846 -v 0.067484378815 1.258732795715 0.097137033939 -v 0.069918870926 1.248601675034 0.105034232140 -v 0.067322969437 1.240279912949 0.111719012260 -v 0.068537473679 1.242500543594 0.107286572456 -v 0.075018405914 1.232970237732 0.108255088329 -v 0.070877790451 1.232767581940 0.115252256393 -v 0.077867746353 1.249896764755 0.094340682030 -v 0.081087350845 1.242408514023 0.097182273865 -v 0.083758115768 1.234669685364 0.100204110146 -v 0.075211763382 1.256941318512 0.091831862926 -v 0.080814123154 1.256867170334 0.083383440971 -v 0.084712028503 1.249413847923 0.083412945271 -v 0.090125322342 1.240862131119 0.083279728889 -v 0.094750881195 1.231421947479 0.081762373447 -v 0.077249050140 1.224474191666 0.112283647060 -v 0.076828718185 1.222699880600 0.113141000271 -v 0.078745365143 1.225707769394 0.109818100929 -v 0.080643415451 1.218926310539 0.113611519337 -v 0.081604242325 1.218360304832 0.109059333801 -v 0.081132650375 1.220607519150 0.109011828899 -v 0.077664852142 1.220381379128 0.113147377968 -v 0.080033540726 1.219517707825 0.110023081303 -v 0.079794406891 1.220654487610 0.110094487667 -v 0.083391666412 1.220073938370 0.107060670853 -v 0.082854270935 1.225638270378 0.104710161686 -v 0.087911605835 1.218507766724 0.103260695934 -v 0.091594696045 1.224019408226 0.096191704273 -v 0.096889257431 1.214898347855 0.095897138119 -v 0.083808422089 1.215420007706 0.113558650017 -v 0.089332103729 1.208635091782 0.112731575966 -v 0.084277868271 1.216469287872 0.107762217522 -v 0.089827299118 1.213289976120 0.105555117130 -v 0.101368904114 1.198026537895 0.110524892807 -v 0.100582122803 1.206828474998 0.100248575211 -v 0.095614671707 1.219149708748 0.078378736973 -v 0.110302448273 1.196131229401 0.085673749447 -v 0.101401090622 1.207566261292 0.078618407249 -v 0.038086652756 1.319437146187 0.056139290333 -v 0.058758258820 1.316738009453 0.064338445663 -v 0.052024126053 1.317465305328 0.045089304447 -v 0.071031332016 1.309057235718 0.048146665096 -v 0.074790716171 1.301920175552 0.061692059040 -v 0.065555095673 1.309342384338 0.030936956406 -v 0.076519966125 1.290452003479 0.034301042557 -v 0.081107854843 1.281051397324 0.059998869896 -v 0.083610057831 1.276207208633 0.068830192089 -v 0.084535121918 1.260300159454 0.064144432545 -v 0.082194328308 1.262906312943 0.069637179375 -v 0.082393407822 1.267321228981 0.069480359554 -v 0.083597660065 1.267654538155 0.063186764717 -v 0.078208923340 1.286485910416 0.048090279102 -v 0.083045482635 1.268104314804 0.053750872612 -v 0.082231521606 1.268839240074 0.041879594326 -v 0.074455499649 1.290663003922 0.019667565823 -v 0.081685543060 1.268450379372 0.028919160366 -v 0.080770254135 1.266295671463 0.016477346420 -v 0.085688114166 1.253255128860 0.071567714214 -v 0.090450763702 1.245868682861 0.066874861717 -v 0.086171150208 1.256250977516 0.055930197239 -v 0.086350440979 1.251328825951 0.045859992504 -v 0.093620538712 1.236952662468 0.060706198215 -v 0.094166755676 1.225640654564 0.054646670818 -v 0.099492788315 1.210208415985 0.048777282238 -v 0.114588975906 1.187431573868 0.062622427940 -v 0.087287187576 1.245572805405 0.035482227802 -v 0.087604761124 1.239173889160 0.025138556957 -v 0.087361097336 1.235268592834 0.012534439564 -v 0.098117351532 1.205789446831 0.027765154839 -v 0.095893383026 1.203208208084 0.014717459679 -v -0.011510133743 1.163360238075 0.149067997932 -v -0.004560947418 1.134804606438 0.155196785927 -v -0.023927450180 1.173175573349 0.133506655693 -v -0.025471687317 1.141367435455 0.137405753136 -v 0.017634153366 1.178678154945 0.157647490501 -v 0.025628328323 1.157846570015 0.168135166168 -v 0.003703117371 1.180795431137 0.148849606514 -v 0.006724596024 1.158563613892 0.161044716835 -v 0.032204389572 1.178767085075 0.163424730301 -v 0.045523643494 1.179651737213 0.165940761566 -v 0.057294130325 1.180637598038 0.164849698544 -v 0.042539596558 1.158673048019 0.171049177647 -v 0.056924104691 1.159794092178 0.170381605625 -v 0.017149686813 1.133303642273 0.166976332664 -v 0.037201642990 1.133634090424 0.172211468220 -v 0.054214477539 1.134839653969 0.171566545963 -v -0.010805606842 1.115299701691 0.134994447231 -v -0.012533187866 1.105522513390 0.110044121742 -v 0.010537385941 1.112756729126 0.149111986160 -v 0.047211885452 1.112629652023 0.157582700253 -v 0.030074119568 1.112287878990 0.156457722187 -v 0.006142139435 1.103373646736 0.121430158615 -v 0.022053003311 1.103733062744 0.127525568008 -v 0.036193370819 1.104734897614 0.128820121288 -v -0.040673494339 1.155994772911 0.117093861103 -v -0.049955368042 1.141332268715 0.095714688301 -v -0.032525300980 1.123396158218 0.116316258907 -v -0.032552003860 1.114442110062 0.094371557236 -v -0.031067371368 1.110062003136 0.075444519520 -v -0.052037954330 1.167015790939 0.075356423855 -v -0.056231737137 1.161347627640 0.056636929512 -v -0.059476852417 1.156821727753 0.039392709732 -v -0.059850692749 1.140776157379 0.039435088634 -v -0.061575651169 1.141006946564 0.028368413448 -v -0.050864934921 1.133266210556 0.076295912266 -v -0.056070089340 1.117838740349 0.039700746536 -v -0.049790382385 1.128654956818 0.061231255531 -v -0.052109718323 1.122534751892 0.050932705402 -v -0.034054994583 1.104509353638 0.060616970062 -v -0.043396234512 1.096928238869 0.048614859581 -v -0.048959255219 1.091627120972 0.033554553986 -v -0.056957721710 1.112890362740 0.023788034916 -v -0.035567522049 1.043387889862 0.047449171543 -v -0.039433956146 1.039121747017 0.052413821220 -v -0.064744234085 1.050780534744 0.014951646328 -v -0.038980245590 1.074284434319 0.043637633324 -v -0.041082859039 1.069077014923 0.029278635979 -v -0.034406661987 1.055065155029 0.043360531330 -v -0.047071218491 1.085974812508 0.015686988831 -v -0.049998521805 1.061222076416 0.019102632999 -v -0.053887367249 1.043840646744 0.036689996719 -v -0.042478322983 1.050164461136 0.036054790020 -v -0.014271974564 1.099223375320 0.086969316006 -v 0.000830411911 1.094314455986 0.095309138298 -v -0.019607543945 1.090406298637 0.068407773972 -v -0.029613494873 1.080608129501 0.054361045361 -v -0.005763530731 1.081238627434 0.073860049248 -v -0.027546405792 1.059183478355 0.053171813488 -v -0.013939142227 1.067626953125 0.057299792767 -v 0.014307975769 1.093263268471 0.099898755550 -v 0.027014970779 1.094081640244 0.101382076740 -v 0.021053075790 1.074604153633 0.082123875618 -v 0.007202863693 1.075435996056 0.078675389290 -v -0.027371644974 1.043602824211 0.054658472538 -v -0.017439126968 1.044979572296 0.062561631203 -v -0.024429798126 1.035316348076 0.064470529556 -v -0.010132312775 1.032010316849 0.071531534195 -v 0.004372358322 1.030398845673 0.073763489723 -v 0.017338514328 1.031093001366 0.076553463936 -v 0.000297546387 1.051457285881 0.063539087772 -v 0.017464637756 1.050814867020 0.071853816509 -v 0.068420410156 1.181527853012 0.160425603390 -v 0.079635143280 1.182518243790 0.152125537395 -v 0.070542097092 1.160900115967 0.164953768253 -v 0.085201978683 1.162357091904 0.154878497124 -v 0.090045928955 1.184562206268 0.140001475811 -v 0.098061561584 1.189689755440 0.125387966633 -v 0.099827289581 1.165438413620 0.139908611774 -v 0.070614814758 1.136290311813 0.165854871273 -v 0.088030338287 1.138740301132 0.153091609478 -v 0.104446411133 1.143034815788 0.133147954941 -v 0.097229003906 1.124236106873 0.117044687271 -v 0.083167791367 1.114722371101 0.099347352982 -v 0.111231565475 1.172423601151 0.120619416237 -v 0.114904880524 1.183718919754 0.100513756275 -v 0.116925716400 1.151993751526 0.107569992542 -v 0.063422679901 1.115132212639 0.151529729366 -v 0.080619335175 1.118611931801 0.138225674629 -v 0.050387620926 1.106717824936 0.125205457211 -v 0.066112041473 1.109486579895 0.115795731544 -v 0.086173295975 1.122708439827 0.068399488926 -v 0.080250263214 1.118033289909 0.063007235527 -v 0.082655668259 1.112149238586 0.061163365841 -v 0.121577978134 1.167878985405 0.081856548786 -v 0.119044303894 1.154315471649 0.063807129860 -v 0.111441612244 1.134985923767 0.090731918812 -v 0.098887205124 1.126488447189 0.077325224876 -v 0.111427545547 1.179712891579 0.043127000332 -v 0.106110334396 1.175122380257 0.031305313110 -v 0.102075576782 1.172155618668 0.024685502052 -v 0.102116584778 1.157317161560 0.033418297768 -v 0.101032018661 1.158340215683 0.029302597046 -v 0.100531339645 1.143308043480 0.048263728619 -v 0.097441434860 1.138330459595 0.048066020012 -v 0.109502553940 1.146957397461 0.052747786045 -v 0.096754789352 1.134839057922 0.047012090683 -v 0.085198402405 1.107511401176 0.055232167244 -v 0.094857692719 1.130478262901 0.041637301445 -v 0.040197134018 1.096347808838 0.099944472313 -v 0.054687500000 1.100618243217 0.094639301300 -v 0.048788309097 1.088074207306 0.078770637512 -v 0.035143613815 1.078818082809 0.081493318081 -v 0.048858642578 1.075313687325 0.068564772606 -v 0.070461988449 1.108810186386 0.084021329880 -v 0.064486742020 1.100866556168 0.073438167572 -v 0.065836668015 1.092562913895 0.068579912186 -v 0.060715675354 1.069221019745 0.070371031761 -v 0.030231714249 1.033327579498 0.078828334808 -v 0.035176753998 1.055608034134 0.070235610008 -v 0.043811559677 1.038117885590 0.082073748112 -v 0.050953388214 1.052722811699 0.075931191444 -v 0.063144207001 1.053842663765 0.072386682034 -v 0.073226213455 1.055658340454 0.068940043449 -v 0.075714349747 1.052077531815 0.075281441212 -v 0.058623790741 1.044714212418 0.080729842186 -v 0.072857141495 1.087235689163 0.064580619335 -v 0.071193933487 1.066993713379 0.064158737659 -v 0.079437494278 1.082699298859 0.053134381771 -v 0.086660146713 1.101273775101 0.041690945625 -v 0.092396974564 1.077137112617 0.048476576805 -v 0.108497619629 1.069890260696 0.052235901356 -v 0.082067012787 1.064140319824 0.061126887798 -v 0.093047380447 1.060159802437 0.067036211491 -v -0.040343284607 1.237436652184 -0.032936990261 -v -0.052459239960 1.221552133560 0.028179645538 -v -0.056158065796 1.218947887421 0.012705385685 -v -0.055384397507 1.217468619347 -0.008952379227 -v -0.058702945709 1.188291907310 0.024425923824 -v -0.061626672745 1.162003040314 0.018809258938 -v -0.061149597168 1.186267733574 0.006660997868 -v -0.059507608414 1.179691553116 -0.010669171810 -v -0.055477380753 1.198352456093 -0.021095275879 -v -0.052834749222 1.169609308243 -0.030598759651 -v -0.042055368423 1.195482850075 -0.042439877987 -v -0.019744396210 1.243911266327 -0.053574860096 -v 0.005693435669 1.249059438705 -0.062779784203 -v -0.040396451950 1.167162179947 -0.069658398628 -v -0.015247583389 1.206512212753 -0.057519495487 -v 0.014311552048 1.212281465530 -0.062326133251 -v -0.013623714447 1.176701664925 -0.078638434410 -v 0.025074958801 1.182491421700 -0.078897595406 -v 0.055553436279 1.246190905571 -0.042324364185 -v 0.072591066360 1.207378625870 -0.039697229862 -v 0.085914134979 1.232458949089 0.001026153564 -v 0.083698034286 1.230814695358 -0.009619951248 -v 0.077988386154 1.229747176170 -0.023236691952 -v 0.094089031219 1.202184319496 0.005038857460 -v 0.098302841187 1.178545475006 0.013474762440 -v 0.091052532196 1.195588827133 -0.011169850826 -v 0.092413902283 1.201389551163 -0.004166901112 -v 0.082178831100 1.212141036987 -0.025714099407 -v 0.089784622192 1.185250520706 -0.019735872746 -v 0.032395839691 1.248675107956 -0.057501971722 -v 0.044507265091 1.212738394737 -0.056064784527 -v 0.063519954681 1.185031294823 -0.068458735943 -v 0.090191364288 1.181271433830 -0.050654113293 -v -0.059590101242 1.158144712448 0.001819372177 -v -0.060241460800 1.136449337006 0.012746274471 -v -0.055771827698 1.128415822983 -0.007795572281 -v -0.056196689606 1.149477005005 -0.018423438072 -v -0.059613704681 1.094871759415 -0.017021775246 -v -0.052507877350 1.106217026711 0.003190934658 -v -0.061356782913 1.135336041451 -0.044591844082 -v -0.055210590363 1.152688622475 -0.057234942913 -v -0.061703920364 1.115628957748 -0.031736850739 -v -0.076354265213 1.118670940399 -0.068626523018 -v -0.078945398331 1.100923299789 -0.053504228592 -v -0.072272777557 1.063135385513 -0.010518550873 -v -0.077728748322 1.081091284752 -0.034207820892 -v -0.055848836899 1.076079010963 0.000701248646 -v -0.070124626160 1.134061932564 -0.082705259323 -v -0.052391529083 1.145668983459 -0.097816407681 -v -0.014596939087 1.152688741684 -0.108650863171 -v 0.038563251495 1.158075928688 -0.105544686317 -v 0.095056056976 1.175324201584 0.007279813290 -v 0.097741365433 1.154363512993 0.024574756622 -v 0.096329450607 1.145889043808 0.014402627945 -v 0.095551252365 1.166598796844 -0.001544177532 -v 0.092842340469 1.122950792313 0.029080450535 -v 0.106817960739 1.113699555397 0.016706228256 -v 0.110495090485 1.154946565628 -0.013335943222 -v 0.104727029800 1.170523405075 -0.031004786491 -v 0.110179185867 1.135258436203 0.001379370689 -v 0.134946107864 1.143305301666 -0.026512145996 -v 0.134920597076 1.125534772873 -0.009499669075 -v 0.100990295410 1.093693971634 0.033296287060 -v 0.121155023575 1.084573626518 0.031806349754 -v 0.130618572235 1.104586720467 0.010483145714 -v 0.088234901428 1.164701461792 -0.088147342205 -v 0.131562232971 1.157645463943 -0.042793512344 -v 0.118981122971 1.165749549866 -0.063742041588 -v 0.061493158340 1.307609081268 0.082881748676 -v 0.060327529907 1.318495154381 0.079182028770 -v 0.072385311127 1.317370176315 0.066087126732 -v 0.075205326080 1.306590318680 0.068933367729 -v 0.076874732971 1.311258077621 0.048126757145 -v 0.079223632813 1.301067113876 0.051980793476 -v 0.079833984375 1.300073146820 0.031079173088 -v 0.080294847488 1.289757966995 0.038935780525 -v 0.084419488907 1.282017230988 0.020341932774 -v 0.084472656250 1.274614810944 0.031600832939 -v 0.089787960052 1.257214426994 0.028529644012 -v 0.093410491943 1.257125258446 0.016011953354 -v 0.093643188477 1.237569332123 0.028812587261 -v 0.099745988846 1.236010193825 0.015180408955 -v 0.101211547852 1.209712862968 0.029784440994 -v 0.105703353882 1.216141939163 0.016078948975 -v 0.107604503632 1.206364512444 0.004519283772 -v 0.106831312180 1.196551799774 0.008540511131 -v 0.103477239609 1.200936555862 -0.016821682453 -v 0.102436780930 1.189777612686 -0.016660988331 -v 0.094894409180 1.201877832413 -0.033474504948 -v 0.091467142105 1.192241907120 -0.033644795418 -v 0.081027984619 1.205593347549 -0.044518053532 -v 0.078697204590 1.196267604828 -0.045972108841 -v 0.030203104019 1.317878961563 0.092599034309 -v 0.031599044800 1.306848764420 0.096550464630 -v 0.000533103943 1.315608501434 0.092406988144 -v 0.001453638077 1.304747343063 0.097599565983 -v -0.019915580750 1.309429168701 0.081647753716 -v -0.018998622894 1.298553228378 0.086916089058 -v -0.033011198044 1.297790884972 0.064219474792 -v -0.029258489609 1.289492845535 0.072676897049 -v -0.041879415512 1.274564981461 0.053379595280 -v -0.035678148270 1.269248962402 0.063527703285 -v -0.049278259277 1.251981019974 0.053342640400 -v -0.040801525116 1.249933481216 0.062599599361 -v -0.052246570587 1.230650424957 0.054706454277 -v -0.042381286621 1.229251742363 0.063888192177 -v -0.056648731232 1.206089735031 0.058673679829 -v -0.047176122665 1.203041553497 0.068685829639 -v -0.063978195190 1.193070888519 0.045640826225 -v -0.059770822525 1.182946562767 0.046971440315 -v -0.068000316620 1.188966512680 0.023967921734 -v -0.064295291901 1.178698301315 0.022614359856 -v -0.068785667419 1.192012310028 0.001784324646 -v -0.065010547638 1.183354616165 -0.002156734467 -v -0.066419363022 1.198132634163 -0.014372169971 -v -0.061841726303 1.189954519272 -0.018084764481 -v -0.056248426437 1.205180168152 -0.032190322876 -v -0.050663232803 1.196324706078 -0.035794079304 -v -0.035155773163 1.208442568779 -0.053844273090 -v -0.033224582672 1.197817921638 -0.051412761211 -v -0.008906602859 1.210032224655 -0.066920220852 -v -0.007337331772 1.200033903122 -0.065757989883 -v 0.025993824005 1.211974382401 -0.073480010033 -v 0.026358604431 1.201002120972 -0.069385886192 -v 0.049157142639 1.212844133377 -0.068056046963 -v 0.048957347870 1.202935099602 -0.064820349216 -v 0.065938234329 1.210010766983 -0.056550920010 -v 0.063969373703 1.200293183327 -0.057101726532 -v 0.026063919067 1.253668546677 -0.073655724525 -v -0.009798765182 1.251827239990 -0.066984713078 -v -0.036081075668 1.251029968262 -0.053802967072 -v -0.053255796432 1.248492121696 -0.030867159367 -v -0.061401128769 1.237682819366 -0.006527304649 -v -0.065071582794 1.235451579094 0.005308210850 -v -0.066051959991 1.232313632965 0.024793028831 -v -0.063958168030 1.215806245804 0.036684691906 -v -0.058470249176 1.244234442711 0.038768827915 -v -0.056696653366 1.254055619240 0.036476075649 -v 0.047235488892 1.252357602119 -0.067458629608 -v 0.065943956375 1.248579740524 -0.052758038044 -v 0.082094430923 1.242822408676 -0.039423704147 -v 0.101416587830 1.234602212906 0.000243604183 -v 0.095574378967 1.254433631897 -0.000831246376 -v 0.081856250763 1.282060623169 0.002210915089 -v 0.070363283157 1.305048108101 0.002756774426 -v 0.064732551575 1.325939893723 0.037348568439 -v 0.059475421906 1.330581545830 0.056172847748 -v 0.051770687103 1.331991195679 0.066862940788 -v 0.026969909668 1.331480026245 0.080155074596 -v 0.000534296036 1.328585267067 0.078154027462 -v -0.016364336014 1.321949958801 0.068262755871 -v -0.032131671906 1.307672977448 0.049133062363 -v -0.046026468277 1.281006813049 0.033047616482 -v -0.057170391083 1.264941453934 0.018052995205 -v -0.059194087982 1.260551929474 0.005703926086 -v -0.056351184845 1.267251372337 -0.005363285542 -v -0.049419403076 1.281430959702 0.018636167049 -v -0.050104856491 1.281523466110 -0.026480972767 -v -0.032762527466 1.285117030144 -0.046894788742 -v -0.006237030029 1.288429498672 -0.060750246048 -v 0.045986413956 1.285272717476 -0.059156835079 -v 0.060814857483 1.282638311386 -0.047715902328 -v 0.081722974777 1.278753519058 -0.015161991119 -v 0.093460798264 1.257528543472 -0.016839504242 -v 0.099166631699 1.234176397324 -0.016934752464 -v 0.080812215805 1.267979621887 -0.031077861786 -v 0.066226243973 1.297156810760 -0.022842288017 -v 0.025224208832 1.286554098129 -0.066509544849 -v 0.046222925186 1.308892011642 -0.040655016899 -v 0.025389671326 1.311321735382 -0.048380911350 -v -0.002219676971 1.312392711639 -0.044137835503 -v -0.024477481842 1.309771776199 -0.033741474152 -v -0.040723323822 1.304569959641 -0.014032125473 -v -0.038681983948 1.307122945786 0.022028684616 -v -0.033923625946 1.316653251648 0.007554233074 -v -0.022377967834 1.325628161430 0.032776713371 -v -0.011242151260 1.334012389183 0.047734975815 -v 0.005346775055 1.339532971382 0.057651221752 -v 0.023217439651 1.341475963593 0.059436559677 -v 0.043385505676 1.340054035187 0.050687074661 -v 0.050596475601 1.337354063988 0.041210770607 -v 0.055289745331 1.331090807915 0.023640811443 -v 0.054258584976 1.323943614960 -0.003970444202 -v 0.035431385040 1.330586671829 -0.015784919262 -v 0.002865314484 1.329736113548 -0.018387377262 -v -0.017127513885 1.325981378555 -0.009942293167 -v -0.009388685226 1.335545063019 0.010651230812 -v 0.008429527283 1.339061737061 0.003008246422 -v 0.036308050156 1.338485956192 0.004922389984 -v 0.036141872406 1.342529535294 0.023647129536 -v 0.034445047379 1.343819022179 0.035101830959 -v 0.020200014114 1.344961047173 0.038254320621 -v 0.006144762039 1.343188524246 0.040450692177 -v -0.003520011902 1.340352535248 0.030388653278 -v 0.015350580215 1.343349337578 0.023720622063 -v 0.002131700516 1.294373512268 0.084310173988 -v 0.032253980637 1.296369910240 0.083501935005 -v 0.053240537643 1.297918319702 0.073384404182 -v 0.063632249832 1.297773361206 0.063727974892 -v 0.066441297531 1.292367458344 0.051250755787 -v 0.069464921951 1.284128427505 0.042113184929 -v 0.072947740555 1.268516302109 0.036393523216 -v 0.077996730804 1.254851579666 0.034342646599 -v 0.082294940948 1.238687992096 0.033778369427 -v 0.096078634262 1.210922002792 0.033141076565 -v 0.093547344208 1.197418689728 0.010111808777 -v 0.088402271271 1.190471649170 -0.012344717979 -v 0.079278945923 1.192068338394 -0.027221798897 -v 0.067305803299 1.196002244949 -0.037115812302 -v 0.056254863739 1.199710249901 -0.045009076595 -v 0.043886661530 1.202761530876 -0.050360381603 -v 0.028577089310 1.203777551651 -0.055042266846 -v 0.000556945801 1.202123761177 -0.054026365280 -v -0.022556543350 1.199745535851 -0.042454838753 -v -0.037118673325 1.196506142616 -0.027604460716 -v -0.044364452362 1.191485524178 -0.013580024242 -v -0.048760175705 1.185310840607 0.001701295376 -v -0.049472093582 1.181732654572 0.018289864063 -v -0.043260574341 1.188125729561 0.041829228401 -v -0.042436599731 1.200907945633 0.067196130753 -v -0.029914379120 1.229040384293 0.062778651714 -v -0.028822183609 1.249405384064 0.061480879784 -v -0.026416063309 1.267934322357 0.062469124794 -v -0.020500183105 1.284778714180 0.069266617298 -v -0.011813879013 1.290825963020 0.077379345894 -v -0.036173343658 1.205227851868 0.065852403641 -v 0.089926242828 1.212391614914 0.033588826656 -v 0.086484670639 1.264750957489 -0.025318682194 -v 0.090276241302 1.249650478363 -0.029009580612 -v 0.093374252319 1.235239744186 -0.028121829033 -v -0.680430412292 1.393068790436 -0.320257246494 -v -0.698494911194 1.408102989197 -0.328137785196 -v -0.705596685410 1.403319478035 -0.332353264093 -v -0.702425003052 1.401414155960 -0.341219663620 -v -0.693487405777 1.401706576347 -0.345480948687 -v -0.677313804626 1.388596534729 -0.332979142666 -v -0.696997642517 1.407511115074 -0.337174981833 -v -0.689204931259 1.409341335297 -0.330315768719 -v -0.693303585052 1.391095876694 -0.314780384302 -v -0.703037500381 1.384432554245 -0.323003411293 -v -0.699735164642 1.379808068275 -0.336086094379 -v -0.686516761780 1.382108569145 -0.341215163469 -v -0.688117027283 1.406664133072 -0.339293509722 -v -0.671191692352 1.325040817261 -0.285161167383 -v -0.653577566147 1.274054050446 -0.263464331627 -v -0.622252702713 1.186689734459 -0.227236688137 -v -0.589787960052 1.099176168442 -0.192291796207 -v -0.552791118622 1.003217101097 -0.157474160194 -v -0.510915994644 0.897739231586 -0.121878385544 -v -0.492876291275 0.902821123600 -0.129963815212 -v -0.535413742065 1.007634758949 -0.164884626865 -v -0.573541641235 1.102779388428 -0.199071943760 -v -0.606878757477 1.189758062363 -0.233704805374 -v -0.639323711395 1.276522159576 -0.269631683826 -v -0.656749725342 1.327616810799 -0.290879905224 -v -0.681891918182 1.317631244659 -0.293967366219 -v -0.664569854736 1.266501188278 -0.272399932146 -v -0.634156942368 1.178615331650 -0.236648023129 -v -0.601839542389 1.090810775757 -0.202318966389 -v -0.566227912903 0.994425058365 -0.168143510818 -v -0.525188207626 0.888482391834 -0.133112192154 -v -0.678204059601 1.312798857689 -0.308455199003 -v -0.660619258881 1.261751770973 -0.287267655134 -v -0.630073070526 1.173742771149 -0.252752542496 -v -0.597980260849 1.085862278938 -0.219300508499 -v -0.562275886536 0.989962458611 -0.186343669891 -v -0.521363496780 0.884423673153 -0.152287662029 -v -0.663713693619 1.315396070480 -0.314257442951 -v -0.645992040634 1.264471530914 -0.293223381042 -v -0.614400863647 1.176954030991 -0.259143769741 -v -0.581530570984 1.089387059212 -0.226521193981 -v -0.544843912125 0.994354009628 -0.193900704384 -v -0.503242254257 0.889585494995 -0.160271108150 -v -0.653139591217 1.322819709778 -0.305283248425 -v -0.635165929794 1.272057771683 -0.284064382315 -v -0.603127479553 1.184988617897 -0.249243974686 -v -0.569592237473 1.097936868668 -0.215854406357 -v -0.531643867493 1.003189921379 -0.182969391346 -v -0.488971471786 0.898870944977 -0.149086236954 -v -0.484921455383 0.834170520306 -0.089892804623 -v -0.460219383240 0.840958893299 -0.100384473801 -v -0.511497497559 0.901323735714 -0.132468283176 -v -0.501404762268 0.904189109802 -0.136912345886 -v -0.472644090652 0.759641647339 -0.086778938770 -v -0.504419326782 0.821840167046 -0.105421543121 -v -0.519470214844 0.896225512028 -0.138695955276 -v -0.467942714691 0.754820764065 -0.108005642891 -v -0.499197244644 0.815808892250 -0.131774783134 -v -0.517336845398 0.893964409828 -0.149376213551 -v -0.448551177979 0.760925114155 -0.116835474968 -v -0.474140167236 0.822419762611 -0.142395973206 -v -0.507234096527 0.896824002266 -0.153811216354 -v -0.433065176010 0.771692276001 -0.104480087757 -v -0.455140352249 0.835817098618 -0.126966357231 -v -0.499275684357 0.901945590973 -0.147596955299 -v -0.459559202194 0.773626148701 -0.068398654461 -v -0.433999776840 0.781386613846 -0.079760193825 -v -0.427901983261 0.774820268154 -0.107565879822 -v -0.447791576385 0.760745763779 -0.123485684395 -v -0.472889900208 0.752940356731 -0.112041771412 -v -0.479088068008 0.758860111237 -0.084373116493 -v -0.491303682327 0.910904347897 -0.129152178764 -v -0.514250516891 0.904531538486 -0.118242800236 -v -0.533769607544 0.893227875233 -0.132516324520 -v -0.528328418732 0.887990593910 -0.157591700554 -v -0.504444837570 0.894635677338 -0.168278694153 -v -0.485826730728 0.906584739685 -0.153679370880 -v -0.461875915527 0.779266953468 -0.070306479931 -v -0.436331748962 0.787207782269 -0.081280946732 -v -0.430136680603 0.780604958534 -0.109252929688 -v -0.449860572815 0.765928268433 -0.125815510750 -v -0.475796222687 0.757836759090 -0.114095747471 -v -0.482009410858 0.764635562897 -0.085911035538 -v -0.487102031708 0.905195295811 -0.125341534615 -v -0.511810302734 0.898107171059 -0.114347636700 -v -0.531330347061 0.885510385036 -0.129618883133 -v -0.526210784912 0.880015254021 -0.155877709389 -v -0.501423597336 0.887129247189 -0.166869044304 -v -0.482195377350 0.899640679359 -0.151460170746 -v -0.462564945221 0.780975162983 -0.071647465229 -v -0.437812328339 0.788343131542 -0.082418143749 -v -0.431942939758 0.781991302967 -0.109270632267 -v -0.450904846191 0.768045961857 -0.124982774258 -v -0.475512504578 0.760414898396 -0.113783419132 -v -0.481489181519 0.767017781734 -0.087105572224 -v -0.487062454224 0.902436256409 -0.125205695629 -v -0.510672807693 0.895664632320 -0.114782571793 -v -0.529201984406 0.883543848991 -0.129371404648 -v -0.524323225021 0.878087401390 -0.154505074024 -v -0.500638008118 0.884852886200 -0.164988815784 -v -0.482070446014 0.897029280663 -0.150350451469 -v -0.424216270447 0.726895034313 -0.088332355022 -v -0.433250427246 0.720961630344 -0.097859382629 -v -0.445126295090 0.718145370483 -0.091281771660 -v -0.435346364975 0.722274005413 -0.082853138447 -v -0.449822902679 0.721979498863 -0.078244268894 -v -0.438974618912 0.728516280651 -0.071362376213 -v -0.426059484482 0.732701241970 -0.075176239014 -v -0.425045013428 0.742575645447 -0.074277520180 -v -0.443370342255 0.737635374069 -0.066380739212 -v -0.452912092209 0.722330808640 -0.097539663315 -v -0.434735298157 0.726553499699 -0.105409443378 -v -0.457568168640 0.770726919174 -0.074224233627 -v -0.438102483749 0.776775538921 -0.083273649216 -v -0.457084417343 0.727426528931 -0.078251421452 -v -0.421734809875 0.737034559250 -0.093638539314 -v -0.440868854523 0.726467907429 -0.079293847084 -v -0.441762924194 0.723804175854 -0.084031581879 -v -0.437235593796 0.723723113537 -0.086625933647 -v -0.433544158936 0.726360797882 -0.083503544331 -v -0.435790300369 0.728097319603 -0.078992664814 -v -0.435076475143 0.716530799866 -0.078679621220 -v -0.436748027802 0.715161144733 -0.083459377289 -v -0.433470964432 0.717130362988 -0.086149096489 -v -0.429803609848 0.719704866409 -0.082996487617 -v -0.430795431137 0.719356417656 -0.078405201435 -v -0.426370620728 0.708177804947 -0.082949578762 -v -0.429102659225 0.708031177521 -0.087148606777 -v -0.427751302719 0.711654126644 -0.088896811008 -v -0.424102544785 0.714181125164 -0.085791230202 -v -0.423462867737 0.712011873722 -0.082427322865 -v -0.417178869247 0.705715954304 -0.092401742935 -v -0.421164512634 0.705772161484 -0.095329344273 -v -0.421780347824 0.710141003132 -0.095210850239 -v -0.418033361435 0.712694764137 -0.092156529427 -v -0.415308475494 0.709888398647 -0.090527355671 -v -0.411131381989 0.710895836353 -0.103977918625 -v -0.416023015976 0.710323870182 -0.105279445648 -v -0.418101072311 0.713830649853 -0.102593660355 -v -0.414386272430 0.716481685638 -0.099799752235 -v -0.409998416901 0.714512467384 -0.100628316402 -v -0.412442445755 0.723457217216 -0.112111985683 -v -0.417440891266 0.721303761005 -0.112163603306 -v -0.419823646545 0.722338557243 -0.107104063034 -v -0.416396379471 0.725583493710 -0.104684352875 -v -0.411242246628 0.725655853748 -0.107722580433 -v -0.419799089432 0.736344456673 -0.113022804260 -v -0.424517631531 0.732703447342 -0.112453818321 -v -0.425635576248 0.730973005295 -0.106811225414 -v -0.422138690948 0.734303593636 -0.103965282440 -v -0.418025732040 0.737095832825 -0.108072340488 -v -0.427905082703 0.742825925350 -0.108273148537 -v -0.431505441666 0.737993359566 -0.108103752136 -v -0.431043863297 0.735172092915 -0.103496670723 -v -0.427010297775 0.737998902798 -0.100774705410 -v -0.425103187561 0.742438733578 -0.103610634804 -v -0.434395790100 0.745493888855 -0.102516651154 -v -0.437351465225 0.740055739880 -0.103321194649 -v -0.434785366058 0.735876679420 -0.100580215454 -v -0.429973125458 0.739280521870 -0.096914887428 -v -0.430575609207 0.744815766811 -0.098116934299 -v -0.638014793396 1.230491757393 -0.244978487492 -v -0.622946262360 1.233280658722 -0.251465588808 -v -0.649592638016 1.222546815872 -0.254358708858 -v -0.645442724228 1.217762947083 -0.269892901182 -v -0.630394697189 1.220943450928 -0.275375068188 -v -0.619070529938 1.228546142578 -0.266649246216 -v -0.606110572815 1.143009781837 -0.209524273872 -v -0.590292215347 1.146337389946 -0.216171145439 -v -0.617876529694 1.134744167328 -0.219516158104 -v -0.614089488983 1.129821658134 -0.235923349857 -v -0.598005294800 1.133176445961 -0.242772758007 -v -0.586416721344 1.141480803490 -0.232462942600 -v -0.572516918182 1.054052591324 -0.175565481186 -v -0.555697917938 1.058142900467 -0.182277798653 -v -0.585446357727 1.045498132706 -0.185521006584 -v -0.581245422363 1.040752649307 -0.203099846840 -v -0.564207553864 1.044691920280 -0.210411846638 -v -0.551835060120 1.053359389305 -0.199682593346 -v -0.530359745026 0.946404516697 -0.139006793499 -v -0.512903213501 0.951150536537 -0.146695137024 -v -0.544089317322 0.937598705292 -0.149761617184 -v -0.540381193161 0.933445930481 -0.168263316154 -v -0.522706985474 0.938259720802 -0.175991654396 -v -0.508960247040 0.947188973427 -0.165071189404 -v -0.473415136337 0.870537042618 -0.112968623638 -v -0.496746063232 0.863225281239 -0.101937651634 -v -0.516067743301 0.851110696793 -0.117046415806 -v -0.510797500610 0.845018565655 -0.142522931099 -v -0.486820697784 0.852223873138 -0.153340578079 -v -0.467840671539 0.864946663380 -0.138649642467 -v -0.447163105011 0.810840010643 -0.089115977287 -v -0.472838640213 0.805846035480 -0.079120457172 -v -0.492668628693 0.793564498425 -0.095415353775 -v -0.486189365387 0.784938633442 -0.121517777443 -v -0.460333108902 0.791131556034 -0.131569087505 -v -0.440885305405 0.803529441357 -0.115472018719 -v -0.450312852859 0.753731548786 -0.070098817348 -v -0.431421279907 0.759420990944 -0.078914582729 -v -0.465086460114 0.742805838585 -0.082118272781 -v -0.460514783859 0.737773180008 -0.103004276752 -v -0.441336154938 0.743454098701 -0.111343443394 -v -0.426443099976 0.754368603230 -0.099310636520 -v -0.731904268265 1.409023046494 -0.283832073212 -v -0.731420993805 1.409527540207 -0.277567297220 -v -0.769669771194 1.473773002625 -0.284856706858 -v -0.769919872284 1.473968267441 -0.288533568382 -v -0.807954311371 1.532006978989 -0.292883962393 -v -0.809309005737 1.532471895218 -0.288937449455 -v -0.723148822784 1.397814750671 -0.277460843325 -v -0.725734949112 1.400135159492 -0.284406632185 -v -0.701467037201 1.393261909485 -0.299498915672 -v -0.702801704407 1.394067406654 -0.304610729218 -v -0.697797775269 1.322681307793 -0.245903372765 -v -0.678847789764 1.325425028801 -0.269638597965 -v -0.699045181274 1.318197965622 -0.247449636459 -v -0.679080247879 1.320086479187 -0.270336747169 -v -0.698448657990 1.258418440819 -0.191542923450 -v -0.699070453644 1.255869746208 -0.195368707180 -v -0.698896884918 1.187084913254 -0.134619593620 -v -0.700427770615 1.184316277504 -0.138689637184 -v -0.701871871948 1.162669658661 -0.121972262859 -v -0.711782455444 1.180882930756 -0.144968867302 -v -0.710798740387 1.249737977982 -0.202855288982 -v -0.711197614670 1.311830759048 -0.256590962410 -v -0.690308570862 1.311554193497 -0.279663801193 -v -0.713588476181 1.315556406975 -0.259247243404 -v -0.693629026413 1.312055587769 -0.281306147575 -v -0.714844465256 1.249986529350 -0.202514290810 -v -0.714670181274 1.182743430138 -0.144470751286 -v -0.703557968140 1.160912275314 -0.124656915665 -v -0.734780550003 1.184387803078 -0.107548713684 -v -0.803620576859 1.413166880608 -0.193729162216 -v -0.844019651413 1.455053806305 -0.184393405914 -v -0.807727098465 1.321138620377 -0.116503834724 -v -0.837025165558 1.372961163521 -0.126379728317 -v -0.771314382553 1.244080543518 -0.100617885590 -v -0.793653011322 1.271091222763 -0.097309827805 -v -0.731769084930 1.187012553215 -0.105778515339 -v -0.778274536133 1.234176158905 -0.089952230453 -v -0.774795055389 1.242721438408 -0.096917808056 -v -0.802556514740 1.267426371574 -0.087716221809 -v -0.781018733978 1.239013910294 -0.089828252792 -v -0.831202745438 1.315947771072 -0.093698978424 -v -0.857189416885 1.373258233070 -0.109514474869 -v -0.872247457504 1.439273834229 -0.146919488907 -v -0.862528800964 1.441547393799 -0.156704366207 -v -0.872767448425 1.465386867523 -0.168636918068 -v -0.871892452240 1.446012973785 -0.152757167816 -v -0.870913505554 1.465698003769 -0.171075582504 -v -0.872616052628 1.496040582657 -0.196074187756 -v -0.873492717743 1.469481587410 -0.172275424004 -v -0.844311237335 1.563365578651 -0.288278520107 -v -0.867714643478 1.493918657303 -0.196815609932 -v -0.870485305786 1.498056888580 -0.198610186577 -v -0.873506069183 1.498218655586 -0.200232744217 -v -0.873781919479 1.495349645615 -0.197271823883 -v -0.868160724640 1.436191439629 -0.160237908363 -v -0.874623298645 1.443897843361 -0.155241250992 -v -0.875429630280 1.468093872070 -0.173968076706 -v -0.875430583954 1.464208483696 -0.170832037926 -v -0.861469507217 1.539059877396 -0.244808673859 -v -0.864252090454 1.538134932518 -0.246580541134 -v -0.846224308014 1.561979532242 -0.289737492800 -v -0.836484193802 1.567539691925 -0.300393223763 -v -0.837390184402 1.566413164139 -0.303441166878 -v -0.780709743500 1.232831001282 -0.092110395432 -v -0.770603179932 1.241312861443 -0.120023488998 -v -0.805193901062 1.265119791031 -0.089168965816 -v -0.783527612686 1.236857414246 -0.091316342354 -v -0.834095478058 1.314088821411 -0.095762848854 -v -0.860008001328 1.371434450150 -0.112266540527 -v -0.874962329865 1.439385414124 -0.149586439133 -v -0.845883846283 1.368828058243 -0.133463740349 -v -0.873351573944 1.462928771973 -0.173678338528 -v -0.871895790100 1.493336915970 -0.199328541756 -v -0.840737104416 1.510570049286 -0.263315886259 -v -0.833376646042 1.531134724617 -0.288762927055 -v -0.817931175232 1.526331186295 -0.300622344017 -v -0.746751785278 1.402173876762 -0.290421187878 -v -0.796869993210 1.488108158112 -0.299173355103 -v -0.803301095963 1.423126697540 -0.242137193680 -v -0.853743076324 1.448746681213 -0.194176614285 -v -0.821331739426 1.314145565033 -0.119208931923 -v -0.793041229248 1.273641824722 -0.120415627956 -v -0.779705524445 1.238341212273 -0.096930265427 -v -0.758402109146 1.325504183769 -0.214042127132 -v -0.734133243561 1.393293976784 -0.292042940855 -v -0.736127614975 1.383604526520 -0.289822369814 -v -0.747549772263 1.393516778946 -0.284139096737 -v -0.713304281235 1.387033820152 -0.312869518995 -v -0.716605424881 1.378824830055 -0.315402686596 -v -0.667083024979 1.332947969437 -0.272325456142 -v -0.686036825180 1.396254181862 -0.300350457430 -v -0.652807712555 1.335969448090 -0.279133826494 -v -0.671698808670 1.397094845772 -0.306801915169 -v -0.641156673431 1.331952333450 -0.292787551880 -v -0.662131309509 1.392925381660 -0.323805451393 -v -0.665781974792 1.324501156807 -0.274403363466 -v -0.653313159943 1.326481461525 -0.280657827854 -v -0.643545627594 1.325591325760 -0.292931616306 -v -0.687883615494 1.396928071976 -0.306693255901 -v -0.677305936813 1.397392749786 -0.311640799046 -v -0.668898105621 1.393209457397 -0.326097100973 -v -0.639791965485 1.324838161469 -0.306407392025 -v -0.661513090134 1.386579990387 -0.338125854731 -v -0.642078876495 1.321270823479 -0.304058849812 -v -0.667977333069 1.387650251389 -0.338719785213 -v -0.640511274338 1.320248246193 -0.313241720200 -v -0.661991596222 1.385642766953 -0.342326313257 -v -0.643562793732 1.316686630249 -0.313483148813 -v -0.666442394257 1.385178923607 -0.344291776419 -v -0.716503143311 1.372074604034 -0.326735794544 -v -0.694771766663 1.309220075607 -0.296694934368 -v -0.710252761841 1.365118026733 -0.340708762407 -v -0.689024686813 1.304324030876 -0.313677370548 -v -0.695271492004 1.365952491760 -0.350932478905 -v -0.673334360123 1.305315852165 -0.323754280806 -v -0.676507711411 1.373834609985 -0.354276686907 -v -0.657118558884 1.312539339066 -0.327110052109 -v -0.713317871094 1.378292798996 -0.329542458057 -v -0.708588600159 1.374512910843 -0.340065002441 -v -0.695788145065 1.374732732773 -0.347389072180 -v -0.678169250488 1.378413438797 -0.351348221302 -v -0.690240859985 1.306376218796 -0.295807123184 -v -0.685710668564 1.302699327469 -0.310207158327 -v -0.671741962433 1.304181456566 -0.319831520319 -v -0.655930995941 1.309202790260 -0.323127806187 -v -0.634047985077 1.305329561234 -0.344313293695 -v -0.623847723007 1.313705205917 -0.334188282490 -v -0.622318029404 1.319812774658 -0.335038781166 -v -0.636306285858 1.308283686638 -0.347529143095 -v -0.657687187195 1.368595123291 -0.372926771641 -v -0.657169342041 1.375516891479 -0.371039777994 -v -0.642990112305 1.381778359413 -0.362855851650 -v -0.649636030197 1.380834460258 -0.366766542196 -v -0.621777534485 1.454902648926 -0.452792227268 -v -0.627440929413 1.456566333771 -0.455327212811 -v -0.631230592728 1.454094767570 -0.456920742989 -v -0.635877132416 1.447454333305 -0.459561079741 -v -0.624344110489 1.466953277588 -0.470377117395 -v -0.627939224243 1.463238477707 -0.473223686218 -v -0.611341238022 1.455082416534 -0.477429419756 -v -0.615406513214 1.452845573425 -0.479317456484 -v -0.596461057663 1.429937839508 -0.461888015270 -v -0.585901737213 1.430440187454 -0.486534267664 -v -0.568025112152 1.390513300896 -0.463041514158 -v -0.556784152985 1.394706368446 -0.490542352200 -v -0.620961666107 1.366299271584 -0.374592006207 -v -0.602149963379 1.328221082687 -0.365407556295 -v -0.554142475128 1.359774947166 -0.457094848156 -v -0.544462203979 1.367879867554 -0.489594697952 -v -0.554653167725 1.386860847473 -0.492153495550 -v -0.540938138962 1.330043315887 -0.446610987186 -v -0.526558876038 1.326992034912 -0.474644184113 -v -0.532519340515 1.298381805420 -0.428922235966 -v -0.517386436462 1.295669794083 -0.456924021244 -v -0.517901897430 1.258272409439 -0.422607213259 -v -0.512837409973 1.254708290100 -0.429519742727 -v -0.540863037109 1.262001872063 -0.384749233723 -v -0.516560077667 1.256026744843 -0.420525699854 -v -0.516956090927 1.229684472084 -0.400133073330 -v -0.512316942215 1.247911930084 -0.421232968569 -v -0.543984174728 1.231948614120 -0.360431998968 -v -0.536952972412 1.211765289307 -0.364224553108 -v -0.613957405090 1.310405731201 -0.337616801262 -v -0.617177486420 1.305488467216 -0.336197882891 -v -0.547671794891 1.226849794388 -0.359812885523 -v -0.623764514923 1.295241832733 -0.345131874084 -v -0.550174236298 1.224074363708 -0.363058030605 -v -0.611073017120 1.422493457794 -0.469076097012 -v -0.633231639862 1.343430519104 -0.382424205542 -v -0.617163181305 1.313082218170 -0.376247048378 -v -0.627777338028 1.298094511032 -0.349091798067 -v -0.587876319885 1.425273895264 -0.487512648106 -v -0.559880733490 1.391711711884 -0.492971718311 -v -0.546575784683 1.364702701569 -0.491101324558 -v -0.556817054749 1.384633302689 -0.494335830212 -v -0.581263065338 1.378509998322 -0.469431370497 -v -0.528251409531 1.325081706047 -0.475629925728 -v -0.562163352966 1.334616303444 -0.456040829420 -v -0.519301652908 1.293952107430 -0.458499312401 -v -0.546352624893 1.291024565697 -0.436513841152 -v -0.514696121216 1.253158092499 -0.430215626955 -v -0.520211696625 1.255135059357 -0.424808651209 -v -0.520582675934 1.251160979271 -0.424345523119 -v -0.549528598785 1.249001860619 -0.397651523352 -v -0.514673948288 1.245489358902 -0.423131406307 -v -0.518534421921 1.226596713066 -0.399023622274 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.538474559784 1.209404468536 -0.364824950695 -v -0.528185606003 1.214612126350 -0.376569181681 -v -0.529793500900 1.213744163513 -0.379284560680 -v -0.549133777618 1.221839308739 -0.366844773293 -v -0.752520561218 1.404311418533 -0.285495400429 -v -0.799973726273 1.489697456360 -0.296636253595 -v 0.070177555084 1.274966716766 0.089686870575 -v 0.067983150482 1.274402737617 0.090926527977 -v 0.066224336624 1.272931575775 0.092114746571 -v 0.065168857574 1.270776987076 0.093070566654 -v 0.064977169037 1.268267154694 0.093648433685 -v 0.065678596497 1.265784263611 0.093760550022 -v 0.067166328430 1.263706088066 0.093389570713 -v 0.069213867188 1.262349128723 0.092592179775 -v 0.071509599686 1.261919736862 0.091489672661 -v 0.073703765869 1.262483835220 0.090249955654 -v 0.075462818146 1.263954997063 0.089061796665 -v 0.076518297195 1.266109466553 0.088105916977 -v 0.076709985733 1.268619298935 0.087528049946 -v 0.076008558273 1.271102190018 0.087416052818 -v 0.074520826340 1.273180484772 0.087786972523 -v 0.072473287582 1.274537563324 0.088584363461 -v 0.068333148956 1.278423786163 0.086334288120 -v 0.064796447754 1.277514934540 0.088332414627 -v 0.061961412430 1.275143623352 0.090247511864 -v 0.060260057449 1.271671056747 0.091788053513 -v 0.059951066971 1.267625689507 0.092719554901 -v 0.061081647873 1.263623714447 0.092900037766 -v 0.063479423523 1.260274052620 0.092302203178 -v 0.066779851913 1.258086919785 0.091017007828 -v 0.070479869843 1.257395267487 0.089240074158 -v 0.074016571045 1.258304119110 0.087241888046 -v 0.076851606369 1.260675430298 0.085326790810 -v 0.078552961349 1.264147996902 0.083786249161 -v 0.078861951828 1.268193244934 0.082854807377 -v 0.077731370926 1.272195339203 0.082674264908 -v 0.075333595276 1.275544881821 0.083272099495 -v 0.072033166885 1.277732014656 0.084557354450 -v 0.065737485886 1.280808687210 0.081495702267 -v 0.061116695404 1.279621124268 0.084106385708 -v 0.057412624359 1.276522874832 0.086608529091 -v 0.055189609528 1.271985650063 0.088621377945 -v 0.054785966873 1.266700267792 0.089838445187 -v 0.056262969971 1.261471390724 0.090074300766 -v 0.059396028519 1.257094979286 0.089293181896 -v 0.063708066940 1.254237174988 0.087613999844 -v 0.068542480469 1.253333449364 0.085292279720 -v 0.073163509369 1.254521012306 0.082681596279 -v 0.076867341995 1.257619142532 0.080179393291 -v 0.079090595245 1.262156486511 0.078166604042 -v 0.079494237900 1.267441749573 0.076949536800 -v 0.078016996384 1.272670745850 0.076713681221 -v 0.074883937836 1.277047157288 0.077494800091 -v 0.070571899414 1.279904842377 0.079174041748 -v 0.062948465347 1.280951499939 0.076157152653 -v 0.057946681976 1.279666066170 0.078983008862 -v 0.053937673569 1.276312589645 0.081691384315 -v 0.051531553268 1.271401524544 0.083870053291 -v 0.051094532013 1.265680670738 0.085187315941 -v 0.052693367004 1.260020971298 0.085442662239 -v 0.056084394455 1.255283951759 0.084597170353 -v 0.060751676559 1.252190828323 0.082779586315 -v 0.065984487534 1.251212596893 0.080266594887 -v 0.070986270905 1.252498149872 0.077440857887 -v 0.074995517731 1.255851507187 0.074732422829 -v 0.077401638031 1.260762453079 0.072553753853 -v 0.077838659286 1.266483306885 0.071236491203 -v 0.076239824295 1.272143006325 0.070981144905 -v 0.072848558426 1.276880025864 0.071826636791 -v 0.068181276321 1.279973268509 0.073644220829 -v 0.060390472412 1.278830766678 0.071131527424 -v 0.055769443512 1.277642965317 0.073742210865 -v 0.052065610886 1.274544715881 0.076244413853 -v 0.049842596054 1.270007610321 0.078257262707 -v 0.049438953400 1.264722228050 0.079474270344 -v 0.050915956497 1.259493350983 0.079710185528 -v 0.054049015045 1.255116820335 0.078929066658 -v 0.058361053467 1.252259254456 0.077249825001 -v 0.063195466995 1.251355409622 0.074928104877 -v 0.067816495895 1.252542972565 0.072317481041 -v 0.071520328522 1.255641222000 0.069815278053 -v 0.073743581772 1.260178327560 0.067802429199 -v 0.074147224426 1.265463709831 0.066585421562 -v 0.072669982910 1.270692825317 0.066349506378 -v 0.069536924362 1.275068998337 0.067130684853 -v 0.065225124359 1.277926802635 0.068809866905 -v 0.067524909973 1.268451929092 0.093102991581 -v 0.069175004959 1.268501400948 0.092242240906 -v 0.071127653122 1.268560051918 0.091223716736 -v 0.073080301285 1.268618583679 0.090205192566 -v 0.074730157852 1.268668174744 0.089344441891 -v 0.070652723312 1.273131608963 0.090560674667 -v 0.068799734116 1.272726535797 0.091593861580 -v 0.067301273346 1.271686553955 0.092565476894 -v 0.066444635391 1.270407199860 0.093231320381 -v 0.066426753998 1.268414258957 0.093641161919 -v 0.066850900650 1.266429066658 0.093780994415 -v 0.067962169647 1.265214204788 0.093459844589 -v 0.069663047791 1.264270186424 0.092762410641 -v 0.071587085724 1.263978362083 0.091825425625 -v 0.073440074921 1.264383435249 0.090792238712 -v 0.074938535690 1.265423536301 0.089820683002 -v 0.075786352158 1.266697168350 0.089119791985 -v 0.075813055038 1.268695831299 0.088744938374 -v 0.075380325317 1.270675182343 0.088570117950 -v 0.074277639389 1.271895647049 0.088926315308 -v 0.072576761246 1.272839784622 0.089623689651 -v 0.004819393158 1.270663738251 0.106835365295 -v 0.004348754883 1.274211406708 0.103122293949 -v 0.008491754532 1.273808002472 0.103105425835 -v 0.007389783859 1.270413398743 0.106824874878 -v 0.012167453766 1.271865367889 0.103312313557 -v 0.009670257568 1.269208192825 0.106953203678 -v 0.014816045761 1.268679141998 0.103711485863 -v 0.011313676834 1.267231464386 0.107200860977 -v 0.016034841537 1.264734506607 0.104242146015 -v 0.012069702148 1.264783978462 0.107530117035 -v 0.015637636185 1.260631918907 0.104823470116 -v 0.011823415756 1.262238621712 0.107890844345 -v 0.013685464859 1.256995797157 0.105367064476 -v 0.010612010956 1.259982705116 0.108228087425 -v 0.010475158691 1.254379987717 0.105790019035 -v 0.008620262146 1.258359789848 0.108490467072 -v 0.006495475769 1.253182649612 0.106028079987 -v 0.006151199341 1.257616877556 0.108638167381 -v 0.002352476120 1.253586053848 0.106044888496 -v 0.003580808640 1.257867097855 0.108648657799 -v -0.001322984695 1.255528688431 0.105838000774 -v 0.001300334930 1.259072422981 0.108520269394 -v -0.003971815109 1.258714914322 0.105438828468 -v -0.000343084335 1.261049270630 0.108272612095 -v -0.005190372467 1.262659549713 0.104908168316 -v -0.001099109650 1.263496637344 0.107943356037 -v -0.004793405533 1.266762256622 0.104326844215 -v -0.000852823257 1.266042113304 0.107582688332 -v -0.002841234207 1.270398139954 0.103783249855 -v 0.000358581543 1.268298029900 0.107245445251 -v 0.000369071960 1.273014068604 0.103360295296 -v 0.002350330353 1.269920825958 0.106983006001 -v 0.003931760788 1.276739597321 0.097712039948 -v 0.009344816208 1.276212692261 0.097690045834 -v 0.014147281647 1.273674488068 0.097960352898 -v 0.017608165741 1.269511461258 0.098481893539 -v 0.019200325012 1.264357566833 0.099175214767 -v 0.018681526184 1.258997201920 0.099934816360 -v 0.016130685806 1.254246473312 0.100645005703 -v 0.011936426163 1.250828742981 0.101197659969 -v 0.006736755371 1.249264478683 0.101508677006 -v 0.001323699951 1.249791383743 0.101530730724 -v -0.003478765488 1.252329587936 0.101260423660 -v -0.006939411163 1.256492614746 0.100738883018 -v -0.008531808853 1.261646509171 0.100045561790 -v -0.008013010025 1.267006874084 0.099285960197 -v -0.005462169647 1.271757602692 0.098575711250 -v -0.001267671585 1.275175333023 0.098023056984 -v 0.003712654114 1.277051687241 0.091699361801 -v 0.009571552277 1.276481389999 0.091675460339 -v 0.014769792557 1.273733854294 0.091968059540 -v 0.018515825272 1.269227981567 0.092532575130 -v 0.020239114761 1.263649225235 0.093283057213 -v 0.019677639008 1.257847428322 0.094105184078 -v 0.016916751862 1.252705335617 0.094873905182 -v 0.012376546860 1.249006032944 0.095472097397 -v 0.006748676300 1.247312784195 0.095808684826 -v 0.000889539719 1.247883200645 0.095832526684 -v -0.004308462143 1.250630378723 0.095539927483 -v -0.008054494858 1.255136489868 0.094975411892 -v -0.009777784348 1.260715007782 0.094224989414 -v -0.009216308594 1.266516923904 0.093402862549 -v -0.006455421448 1.271659016609 0.092634141445 -v -0.001915454865 1.275358438492 0.092035949230 -v 0.003724575043 1.275099992752 0.085999369621 -v 0.009137630463 1.274572968483 0.085977315903 -v 0.013940095901 1.272034764290 0.086247682571 -v 0.017400741577 1.267871737480 0.086769223213 -v 0.018993139267 1.262717843056 0.087462544441 -v 0.018474340439 1.257357597351 0.088222086430 -v 0.015923500061 1.252606868744 0.088932335377 -v 0.011729001999 1.249189138412 0.089484930038 -v 0.006529569626 1.247624635696 0.089795947075 -v 0.001116514206 1.248151659966 0.089817941189 -v -0.003685951233 1.250689744949 0.089547634125 -v -0.007146835327 1.254852890968 0.089026153088 -v -0.008738994598 1.260006904602 0.088332772255 -v -0.008220195770 1.265367150307 0.087573230267 -v -0.005669355392 1.270117759705 0.086863040924 -v -0.001475095749 1.273535490036 0.086310386658 -v 0.000261068344 1.263721823692 0.108568012714 -v 0.000306606293 1.265732765198 0.108267664909 -v 0.001283168793 1.267090082169 0.108078360558 -v 0.001492738724 1.263846516609 0.108560204506 -v 0.005061388016 1.268813371658 0.107770264149 -v 0.007216453552 1.268672227859 0.107751905918 -v 0.007727861404 1.264456152916 0.108364582062 -v 0.005536317825 1.264241814613 0.108433365822 -v 0.002977371216 1.268257856369 0.107884883881 -v 0.003344774246 1.264027595520 0.108502089977 -v 0.009113311768 1.267855644226 0.107832670212 -v 0.009579896927 1.264637112617 0.108306467533 -v 0.010335683823 1.266713142395 0.107952952385 -v 0.010796070099 1.264751791954 0.108237385750 -v 0.010741710663 1.262735128403 0.108502686024 -v 0.009773969650 1.261383295059 0.108727037907 -v 0.008079767227 1.260215759277 0.108920395374 -v 0.005995750427 1.259660124779 0.109035074711 -v 0.003840684891 1.259801387787 0.109053432941 -v 0.001943826675 1.260617733002 0.108972728252 -v 0.000712633133 1.261754751205 0.108817398548 -v -0.090843439102 0.711956977844 -0.100321829319 -v -0.097157239914 0.660702586174 -0.115609467030 -v -0.006523370743 0.676110148430 -0.150974154472 -v -0.006254673004 0.734257340431 -0.141055881977 -v -0.106460332870 0.595456779003 -0.120525121689 -v -0.013854026794 0.609138488770 -0.144045293331 -v 0.159080028534 0.595945835114 -0.117241799831 -v 0.082373142242 0.601140439510 -0.140979409218 -v 0.217724084854 0.633673191071 -0.043690085411 -v 0.161948204041 0.658787310123 -0.116667926311 -v 0.161992549896 0.716392397881 -0.109141111374 -v 0.200988769531 0.700885295868 -0.057521402836 -v 0.082037210464 0.736163735390 -0.142028212547 -v 0.083940982819 0.671887874603 -0.145761489868 -v -0.052839994431 0.668570876122 -0.136453270912 -v -0.051985740662 0.724966228008 -0.126949429512 -v -0.060494899750 0.603041768074 -0.130789637566 -v 0.039752244949 0.676460027695 -0.152075648308 -v 0.039582014084 0.736532151699 -0.145459830761 -v 0.035222053528 0.606680989265 -0.146267235279 -v 0.123104095459 0.599229633808 -0.133650958538 -v 0.124687910080 0.666198194027 -0.136043965816 -v 0.123418569565 0.728347480297 -0.130160868168 -v 0.192488431931 0.646883368492 -0.081060171127 -v 0.192901372910 0.580796957016 -0.078956365585 -v 0.191608905792 0.708395838737 -0.080889344215 -v -0.110157966614 0.521872341633 -0.123427271843 -v -0.020442485809 0.542563259602 -0.144708812237 -v -0.109526634216 0.464789211750 -0.130063176155 -v -0.029718160629 0.474508851767 -0.155036568642 -v 0.068801403046 0.477472692728 -0.140547931194 -v 0.076097488403 0.537705183029 -0.135993599892 -v 0.162404775620 0.526327550411 -0.118127703667 -v 0.165109157562 0.450441986322 -0.139342069626 -v 0.228643178940 0.555671572685 -0.027355194092 -v 0.238083362579 0.474860131741 -0.044692456722 -v -0.066143035889 0.532799482346 -0.133282661438 -v -0.084163904190 0.454995065928 -0.141852140427 -v 0.016598701477 0.487684130669 -0.148972153664 -v 0.027564287186 0.544286847115 -0.143417119980 -v 0.122592210770 0.530475378036 -0.130063533783 -v 0.122491121292 0.461961984634 -0.139939665794 -v 0.199285984039 0.507649183273 -0.092158377171 -v 0.206475257874 0.438298881054 -0.125071763992 -v 0.236012935638 0.432352960110 -0.098448753357 -v -0.090003728867 0.713547110558 -0.098060905933 -v -0.096627950668 0.660236895084 -0.111967146397 -v -0.006083011627 0.675602138042 -0.146969020367 -v -0.005826711655 0.733766078949 -0.137710273266 -v -0.104192733765 0.594722390175 -0.114763200283 -v -0.013294696808 0.609091877937 -0.139524400234 -v 0.157139778137 0.595473289490 -0.113379478455 -v 0.081852197647 0.601088523865 -0.137477576733 -v 0.215976238251 0.632654249668 -0.042290151119 -v 0.160015106201 0.658218741417 -0.113578557968 -v 0.160174369812 0.716303348541 -0.106486916542 -v 0.199095010757 0.698588788509 -0.055205583572 -v 0.081353425980 0.736018717289 -0.138786435127 -v 0.083306312561 0.671617090702 -0.142443776131 -v -0.051246881485 0.668073892593 -0.131973326206 -v -0.051016092300 0.724832594395 -0.123342573643 -v -0.058906555176 0.602810740471 -0.125979125500 -v 0.039349555969 0.676087617874 -0.148158311844 -v 0.039282560349 0.736191391945 -0.142057716846 -v 0.034797668457 0.606659471989 -0.142599940300 -v 0.122372865677 0.599070608616 -0.130384206772 -v 0.123716592789 0.665827274323 -0.132826924324 -v 0.122337818146 0.727991521358 -0.127091944218 -v 0.189619779587 0.645916223526 -0.078319907188 -v 0.190189838409 0.580016136169 -0.076071262360 -v 0.189076185226 0.708024799824 -0.078644990921 -v -0.109309196472 0.521241247654 -0.119572401047 -v -0.019951820374 0.542360663414 -0.139999091625 -v -0.107759237289 0.462610036135 -0.125670790672 -v -0.029715299606 0.473200440407 -0.152146577835 -v 0.068043947220 0.475595116615 -0.137133598328 -v 0.075683832169 0.537864387035 -0.132634162903 -v 0.160769462585 0.526261806488 -0.115079045296 -v 0.163467884064 0.450367748737 -0.135400056839 -v 0.221496105194 0.555388748646 -0.030082941055 -v 0.230763673782 0.473996579647 -0.045731902122 -v -0.064914464951 0.532697319984 -0.129568278790 -v -0.083212852478 0.454447656870 -0.137265324593 -v 0.015990495682 0.486549288034 -0.145901143551 -v 0.027146339417 0.544277787209 -0.140076875687 -v 0.121834754944 0.530655384064 -0.126233458519 -v 0.121745109558 0.460826694965 -0.136413335800 -v 0.196135759354 0.507262945175 -0.088767468929 -v 0.203240156174 0.436599731445 -0.122523009777 -v 0.234281539917 0.431487858295 -0.096786618233 -v -0.090369224548 0.714081227779 -0.101824402809 -v -0.097647190094 0.660447895527 -0.114232182503 -v -0.108165264130 0.595181941986 -0.117026686668 -v 0.217889308929 0.634391546249 -0.045080006123 -v 0.200847625732 0.698190927505 -0.056285917759 -v -0.110817670822 0.521583199501 -0.122230708599 -v -0.109757661819 0.463707029819 -0.127314388752 -v -0.029812097549 0.473399698734 -0.154148936272 -v 0.068494558334 0.476215690374 -0.139647960663 -v 0.164371013641 0.449653983116 -0.137532711029 -v 0.229068279266 0.556188762188 -0.032200336456 -v 0.238276958466 0.475655049086 -0.049598276615 -v -0.083764553070 0.453088641167 -0.140538215637 -v 0.016265869141 0.486640363932 -0.148057878017 -v 0.122293949127 0.461069822311 -0.137957692146 -v 0.204746484756 0.437017977238 -0.123723983765 -v 0.236302852631 0.434788256884 -0.099483311176 -# 5612 vertices - -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.923878908157 0.001448502531 -0.382682144642 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.707109510899 -0.000000117219 -0.707104086876 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.382688552141 -0.001448765281 -0.923876285553 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn 0.000007046216 -0.002676850883 -0.999996423721 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.382675558329 -0.003497409867 -0.923876166344 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.707099020481 -0.003785590874 -0.707104384899 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.923873543739 -0.003497653874 -0.382681846619 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.999996423721 -0.002677109092 -0.000000101558 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.923879206181 -0.001448904164 0.382681488991 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.707109510899 -0.000000233324 0.707104027271 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.382688343525 0.001448100782 0.923876345158 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000006930147 0.002676741453 0.999996423721 -vn -0.000006930147 0.002676741453 0.999996423721 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.382675796747 0.003497589612 0.923876047134 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.707099556923 0.003785443027 0.707103908062 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.923873484135 0.003497370984 0.382681995630 -vn 0.999996423721 0.002676663222 -0.000000290167 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.161999627948 0.909521639347 0.382787853479 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.002309706295 0.862733006477 0.505654513836 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.923878908157 -0.001449008239 0.382682144642 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.707109570503 0.000000921165 0.707103967667 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.382688790560 0.001448393799 0.923876166344 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000007515317 0.002677260898 0.999996423721 -vn 0.382675856352 0.003497111378 0.923876047134 -vn -0.000007515317 0.002677260898 0.999996423721 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.382675856352 0.003497111378 0.923876047134 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.707099318504 0.003786612069 0.707104086876 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923873662949 0.003498079954 0.382681578398 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.999996423721 0.002677112818 0.000000715744 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.923879086971 0.001448885887 -0.382681787014 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.707109153271 0.000000960799 -0.707104384899 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn 0.382688552141 -0.001448108349 -0.923876285553 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn 0.000006867277 -0.002676919103 -0.999996423721 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.382675290108 -0.003497047350 -0.923876285553 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.707099556923 -0.003786611836 -0.707103848457 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.923873543739 -0.003497794271 -0.382681936026 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.999996423721 -0.002678310033 0.000000691564 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn -0.387655943632 0.908313095570 0.157131060958 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.879678249359 0.306997478008 0.363206148148 -vn -0.387655943632 0.908313095570 0.157131060958 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.466990172863 0.862108767033 -0.196694195271 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.884146511555 0.288732856512 -0.367312192917 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn -0.297270774841 0.908917307854 0.292402744293 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.673473477364 0.308375716209 0.671816885471 -vn -0.297270774841 0.908917307854 0.292402744293 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.356879383326 0.861372649670 -0.361488968134 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.676519215107 0.287345170975 -0.678052008152 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.364863395691 0.309753358364 0.878024816513 -vn -0.161999627948 0.909521639347 0.382787853479 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn 0.192085474730 0.860636472702 -0.471601516008 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn 0.365780502558 0.285957038403 -0.885682344437 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.002435945906 0.910033643246 0.414527237415 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.363199502230 0.311703413725 0.878024518490 -vn -0.000832362915 0.310922086239 0.950435042381 -vn -0.002435945906 0.910033643246 0.414527237415 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.002301780041 0.860012233257 -0.510268211365 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.000762594282 0.284779965878 -0.958592593670 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn 0.157127469778 0.910376429558 0.382786720991 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.363199502230 0.311703413725 0.878024518490 -vn 0.157127469778 0.910376429558 0.382786720991 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.196692228317 0.859594523907 -0.471603065729 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.367305964231 0.283993542194 -0.885682761669 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn 0.292393177748 0.910480380058 0.292458146811 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.671762645245 0.312008947134 0.671852231026 -vn 0.292393177748 0.910480380058 0.292458146811 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.361486196518 0.859449326992 -0.361489385366 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.678074896336 0.283721566200 -0.678023934364 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn 0.383436083794 0.909999251366 0.157727986574 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.878018319607 0.311181575060 0.363661736250 -vn 0.383436083794 0.909999251366 0.157727986574 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.477124124765 0.856146216393 -0.198409363627 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.887559294701 0.277858316898 -0.367468625307 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.952386975288 0.304889559746 -0.001184566994 -vn 0.419054031372 0.907957196236 -0.002726748353 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.537731587887 0.843116044998 -0.000231951766 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.966829180717 0.255422860384 0.000686888874 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.478781968355 0.856518745422 0.192726433277 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.878229558468 0.308965355158 -0.365038722754 -vn 0.383312255144 0.909254193306 -0.162260696292 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.478781968355 0.856518745422 0.192726433277 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.887661576271 0.281107932329 0.364739954472 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.362025827169 0.861238956451 0.356657683849 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.671819388866 0.308373540640 -0.673471987247 -vn 0.292405992746 0.908916473389 -0.297270208597 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.362025827169 0.861238956451 0.356657683849 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.678293824196 0.287600427866 0.676168203354 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.196696266532 0.862110078335 0.466986924410 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn 0.363212913275 0.306997478008 -0.879675447941 -vn 0.157133415341 0.908313214779 -0.387654781342 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.196696266532 0.862110078335 0.466986924410 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.367318838835 0.288734763861 0.884143173695 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.000818260538 0.305829584599 -0.952085912228 -vn -0.002430373104 0.907801330090 -0.419393360615 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.002309706295 0.862733006477 0.505654513836 -vn -0.000775693450 0.289909631014 0.957053720951 -vn -0.000775693450 0.289909631014 0.957053720951 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.192080840468 0.863147914410 0.466991037130 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.364851683378 0.305047988892 -0.879675507545 -vn -0.161994606256 0.907458484173 -0.387655526400 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.192080840468 0.863147914410 0.466991037130 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.365767657757 0.290692329407 0.884144783020 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.356875717640 0.863294601440 0.356878399849 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.673463225365 0.304775089025 -0.673468232155 -vn -0.297265231609 0.907339751720 -0.297267436981 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.356875717640 0.863294601440 0.356878399849 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.676509499550 0.290970236063 0.676514029503 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.466988563538 0.863148868084 0.192082583904 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn -0.419391274452 0.907802283764 -0.002433230868 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.952085435390 0.305831164122 -0.000825389929 -vn -0.879673719406 0.305046916008 -0.364856868982 -vn -0.387655198574 0.907458126545 -0.161997377872 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn 0.466988563538 0.863148868084 0.192082583904 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.884141802788 0.290693789721 0.365773707628 -vn 0.957053661346 0.289909809828 -0.000769271341 -vn 0.505654692650 0.862732887268 -0.002306047129 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.047306902707 0.969304382801 0.241269692779 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.265035003424 0.962137639523 -0.063620537519 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.248550355434 0.968081712723 0.032257635146 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.665100693703 0.708603322506 0.235631942749 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.208323746920 0.938979506493 0.273712754250 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.704381942749 0.650786757469 0.283412605524 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.236780017614 0.949869990349 0.204162240028 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.169224634767 0.977109313011 0.128920063376 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.072743989527 0.993828594685 0.083743982017 -vn 0.058749053627 0.997522294521 0.038701053709 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.375906050205 0.924689590931 0.060363583267 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.263052493334 0.964336454868 0.029301045462 -vn -0.144750267267 0.977827727795 -0.151328608394 -vn 0.083970263600 0.986458778381 -0.140883311629 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.042956437916 0.949172854424 0.311810165644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.021251596510 0.999252557755 0.032289963216 -vn 0.005805051886 0.998719394207 0.050258178264 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.502480626106 0.858713567257 -0.100619092584 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.433224350214 0.852531194687 0.292416185141 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.232279226184 0.908129572868 0.348349064589 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.410649836063 0.890585064888 0.195512071252 -vn 0.005805051886 0.998719394207 0.050258178264 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.410649836063 0.890585064888 0.195512071252 -vn -0.236780017614 0.949869990349 0.204162240028 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.109717316926 0.925979495049 0.361281156540 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.266191989183 0.936656773090 -0.227631047368 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.343298017979 0.890991687775 0.297119945288 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.089727103710 0.922582089901 0.375221759081 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn 0.522200107574 0.730581760406 0.439951479435 -vn -0.111254252493 0.972327888012 0.205428630114 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.561204314232 -0.064809150994 0.825136005878 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129825502634 0.989126026630 0.069101937115 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.140165805817 0.920780718327 0.364028096199 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.299751222134 0.938948035240 -0.168895721436 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.384581267834 0.919836223125 -0.077450178564 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.456301867962 0.849555730820 0.264657646418 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.042343866080 0.998464703560 0.035709671676 -vn 0.042343866080 0.998464703560 0.035709671676 -vn -0.043550744653 0.799514293671 0.599066138268 -vn 0.165170222521 0.957066774368 0.238205745816 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.081451788545 0.994412124157 0.067157849669 -vn 0.014983816072 0.979317367077 0.201774612069 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.111254252493 0.972327888012 0.205428630114 -vn -0.015371610411 0.996984004974 -0.076069392264 -vn 0.047306902707 0.969304382801 0.241269692779 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.289651811123 0.940054774284 0.179996877909 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.439923584461 0.807062745094 0.393848896027 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.125670656562 0.990344762802 0.058515954763 -vn -0.439923584461 0.807062745094 0.393848896027 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.332912445068 0.935498297215 0.118373312056 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.333094507456 0.894973516464 -0.296766668558 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.017310172319 0.949390113354 0.313621997833 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.288402497768 0.898042201996 0.332181036472 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.232279226184 0.908129572868 0.348349064589 -vn 0.522200107574 0.730581760406 0.439951479435 -vn 0.647070944309 0.737142920494 0.194729119539 -vn -0.057531148195 0.978615164757 0.197490662336 -vn 0.014983816072 0.979317367077 0.201774612069 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.057531148195 0.978615164757 0.197490662336 -vn -0.109717316926 0.925979495049 0.361281156540 -vn -0.199486538768 0.979446530342 0.029826447368 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.456301867962 0.849555730820 0.264657646418 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.118587732315 0.931522011757 -0.343807578087 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.169224634767 0.977109313011 0.128920063376 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.347528815269 0.883869111538 -0.313048154116 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.376402616501 0.870327353477 -0.317571073771 -vn -0.316314905882 0.721284568310 0.616192698479 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn -0.209413021803 0.874598622322 -0.437291055918 -vn -0.227070003748 0.845175921917 -0.483856230974 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.043550744653 0.799514293671 0.599066138268 -vn -0.316314905882 0.721284568310 0.616192698479 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.190288290381 0.690781593323 0.697575151920 -vn -0.072743989527 0.993828594685 0.083743982017 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.248550355434 0.968081712723 0.032257635146 -vn -0.127242460847 0.969856739044 0.207815438509 -vn -0.289651811123 0.940054774284 0.179996877909 -vn 0.091195181012 0.875910937786 0.473775774240 -vn 0.129505842924 0.973472297192 0.188626378775 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.070133388042 0.997155189514 -0.027619177476 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.086222581565 0.921112477779 0.379628002644 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.079861029983 0.974357426167 0.210356533527 -vn -0.304748833179 0.951287627220 -0.046690292656 -vn -0.403406798840 0.914197862148 -0.038797721267 -vn -0.212906122208 0.964604198933 0.155594840646 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.278063863516 0.960172414780 -0.027374736965 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.229664877057 0.936510980129 0.264955163002 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.516481220722 0.854483306408 -0.055726669729 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.412922382355 0.903982520103 -0.110953569412 -vn 0.052971653640 0.880331635475 0.471391826868 -vn 0.129505842924 0.973472297192 0.188626378775 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.052971653640 0.880331635475 0.471391826868 -vn -0.108999080956 0.947661638260 0.300094276667 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.132732138038 0.979921698570 0.148780390620 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.125670656562 0.990344762802 0.058515954763 -vn 0.017310172319 0.949390113354 0.313621997833 -vn -0.288402497768 0.898042201996 0.332181036472 -vn -0.132732138038 0.979921698570 0.148780390620 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.106234900653 0.990496456623 -0.087355382740 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.058749053627 0.997522294521 0.038701053709 -vn 0.129825502634 0.989126026630 0.069101937115 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.452575981617 0.878102481365 -0.155277132988 -vn 0.434929758310 0.873234093189 -0.219768777490 -vn 0.551331520081 0.825408220291 -0.121387138963 -vn 0.490755349398 0.841338574886 -0.226514041424 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.190288290381 0.690781593323 0.697575151920 -vn 0.097139805555 0.825904786587 0.555378377438 -vn 0.165170222521 0.957066774368 0.238205745816 -vn 0.397790223360 0.740713775158 0.541392683983 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.231376439333 0.864601671696 0.446014404297 -vn -0.026919174939 0.987045407295 0.158166885376 -vn 0.091195181012 0.875910937786 0.473775774240 -vn -0.208323746920 0.938979506493 0.273712754250 -vn -0.026919174939 0.987045407295 0.158166885376 -vn -0.231376439333 0.864601671696 0.446014404297 -vn 0.098980821669 0.985227704048 -0.139746829867 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.005251220893 0.929640710354 0.368429929018 -vn -0.140165805817 0.920780718327 0.364028096199 -vn -0.086222581565 0.921112477779 0.379628002644 -vn -0.005251220893 0.929640710354 0.368429929018 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn 0.665100693703 0.708603322506 0.235631942749 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.647070944309 0.737142920494 0.194729119539 -vn 0.704381942749 0.650786757469 0.283412605524 -vn 0.576594769955 0.816482365131 -0.029916584492 -vn -0.054100811481 0.828716099262 -0.557048261166 -vn -0.138562649488 0.930660605431 -0.338631451130 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn -0.182488054037 0.870233118534 0.457594156265 -vn 0.097139805555 0.825904786587 0.555378377438 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.182488054037 0.870233118534 0.457594156265 -vn -0.108999080956 0.947661638260 0.300094276667 -vn -0.160416513681 0.982015252113 0.099561758339 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.263052493334 0.964336454868 0.029301045462 -vn 0.207886472344 0.974640905857 0.082815110683 -vn -0.042956437916 0.949172854424 0.311810165644 -vn 0.207886472344 0.974640905857 0.082815110683 -vn 0.332912445068 0.935498297215 0.118373312056 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.433224350214 0.852531194687 0.292416185141 -vn -0.183472141623 0.979701697826 0.080762445927 -vn -0.375906050205 0.924689590931 0.060363583267 -vn -0.361099243164 0.921951770782 0.140043884516 -vn -0.183472141623 0.979701697826 0.080762445927 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn 0.105120658875 0.848330736160 -0.518926382065 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.079431578517 0.878160119057 -0.471726000309 -vn 0.285025328398 0.782720506191 -0.553271353245 -vn 0.230715706944 0.852206826210 -0.469588965178 -vn -0.158789232373 0.938167393208 0.307616591454 -vn -0.089727103710 0.922582089901 0.375221759081 -vn -0.081451788545 0.994412124157 0.067157849669 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.770359873772 -0.349873751402 -0.533042252064 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.866471350193 -0.494451045990 0.068887792528 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.826196610928 -0.378474891186 -0.417319893837 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.852627336979 -0.427872687578 -0.299919277430 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.871176719666 -0.488596260548 0.048216242343 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.653992474079 -0.311724781990 0.689290583134 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn 0.627201139927 -0.266793459654 -0.731737613678 -vn -0.189701020718 -0.520030140877 -0.832815766335 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn 0.094348020852 -0.600384652615 0.794126391411 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.857243716717 -0.179066479206 -0.482771545649 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.957598209381 -0.281897366047 0.059494148940 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.862867891788 -0.238618478179 -0.445556133986 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.916644573212 -0.249014675617 -0.312657028437 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.955888688564 -0.287579327822 0.059791229665 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.697271823883 -0.023023240268 0.716436982155 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.586331486702 0.507154703140 0.631671965122 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn 0.616477489471 -0.097230568528 -0.781346082687 -vn -0.188239112496 -0.195517256856 -0.962465107441 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn 0.030176481232 -0.196037560701 0.980131983757 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.024219894782 0.431608676910 0.901735723019 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.361748665571 0.813761413097 0.454895913601 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.024219894782 0.431608676910 0.901735723019 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.586331486702 0.507154703140 0.631671965122 -vn 0.788730025291 0.571293294430 0.226999789476 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.888961076736 0.118842542171 -0.442294716835 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999191582203 -0.010015186854 0.038934446871 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.888148248196 -0.021853355691 -0.459037214518 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.577633500099 0.091577179730 -0.811143100262 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.191112756729 0.195641577244 -0.961873292923 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.972279310226 0.057422913611 -0.226661652327 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063498787582 0.973852574825 0.218126371503 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.037171285599 0.822442770004 0.567632138729 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.361748665571 0.813761413097 0.454895913601 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.834776818752 0.152970641851 -0.528911769390 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.999251008034 0.013329065405 -0.036328140646 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.875802159309 0.071516327560 -0.477342694998 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.163492619991 0.253283262253 -0.953476667404 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.513145685196 0.198423847556 -0.835050582886 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.986457169056 -0.011852054857 0.163590267301 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.997116386890 0.036253526807 -0.066668137908 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.750959277153 -0.606336772442 0.261564284563 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.582415580750 -0.402489781380 0.706253528595 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.859460055828 -0.470979452133 0.198763057590 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.906085193157 -0.229097962379 0.355701744556 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.642385125160 -0.092330209911 0.760799884796 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.841550469398 0.399582356215 0.363492399454 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.971231758595 -0.076657757163 0.225460559130 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.788730025291 0.571293294430 0.226999789476 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.419445157051 0.878340363503 0.229311823845 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.841550469398 0.399582356215 0.363492399454 -vn -0.580725133419 0.329724341631 0.744338750839 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.008953621611 0.951425194740 0.307749807835 -vn -0.464551985264 0.831402301788 0.304896056652 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.372339665890 0.707525014877 0.600642621517 -vn -0.037171285599 0.822442770004 0.567632138729 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.038015794009 0.828824400902 0.558215856552 -vn -0.008953621611 0.951425194740 0.307749807835 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.419445157051 0.878340363503 0.229311823845 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.470861792564 0.752460539341 0.460534811020 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.546461105347 0.726369321346 0.416854739189 -vn 0.038015794009 0.828824400902 0.558215856552 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.126355975866 0.264645785093 0.956031799316 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.546461105347 0.726369321346 0.416854739189 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.957649767399 0.245865628123 0.149856701493 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.965529382229 0.233773931861 -0.114467352629 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.875472187996 0.477126717567 0.076801784337 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn 0.961319506168 -0.138755530119 -0.237932249904 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.992323935032 -0.083550423384 -0.091172911227 -vn 0.849181652069 -0.524824261665 -0.058736898005 -vn 0.863608837128 -0.437417209148 -0.250691026449 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.815200567245 -0.578349769115 -0.030977522954 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.770887374878 -0.633049786091 0.070573315024 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.871704638004 0.468953579664 0.142174378037 -vn -0.957649767399 0.245865628123 0.149856701493 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.969217240810 -0.242572203279 -0.042150840163 -vn -0.972319781780 -0.213734969497 0.094401150942 -vn -0.871704638004 0.468953579664 0.142174378037 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.684937596321 0.226348280907 0.692551016808 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.119840741158 -0.145645618439 0.982051730156 -vn 0.126355975866 0.264645785093 0.956031799316 -vn 0.861327946186 0.282207727432 0.422460556030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.761057138443 0.020005665720 -0.648376286030 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.992354273796 -0.096318662167 -0.077173262835 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.891179800034 0.028979845345 -0.452723652124 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn -0.047363005579 0.108990550041 -0.992913782597 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.554184734821 0.067802697420 -0.829627692699 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.762222051620 -0.094720840454 0.640347957611 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.995116412640 -0.054380711168 0.082377523184 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.618004083633 0.135420069098 0.774423897266 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.915692329407 -0.125990331173 0.381620287895 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.960119843483 -0.019330935553 0.278919726610 -vn -0.684937596321 0.226348280907 0.692551016808 -vn -0.562489032745 -0.146002635360 0.813811600208 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.063902124763 0.991366446018 0.114494979382 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.063902124763 0.991366446018 0.114494979382 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.718663275242 0.692803204060 0.059554707259 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.989123642445 0.008415753953 -0.146845534444 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.542900204659 0.733694672585 0.408596962690 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.902310669422 0.044389050454 0.428794890642 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.102175161242 0.812571227551 0.573836445808 -vn -0.337740659714 0.766057550907 0.546888530254 -vn -0.543861091137 0.085662640631 0.834791600704 -vn -0.543861091137 0.085662640631 0.834791600704 -vn 0.020976897329 0.060557164252 0.997944295406 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.284465849400 0.811888277531 0.509820163250 -vn -0.102175161242 0.812571227551 0.573836445808 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.020976897329 0.060557164252 0.997944295406 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.284465849400 0.811888277531 0.509820163250 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.618004083633 0.135420069098 0.774423897266 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.287292629480 0.892159521580 0.348589122295 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.930269777775 0.234372481704 0.282254606485 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.674404442310 0.733905732632 -0.081000246108 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.934627115726 0.023425996304 -0.354856818914 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn 0.348094910383 0.829414248466 -0.436923295259 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn 0.537178814411 0.185756832361 -0.822759568691 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn -0.048428762704 0.890414535999 -0.452566653490 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.005166693125 0.263290047646 -0.964702904224 -vn -0.635505199432 0.110047593713 -0.764213740826 -vn -0.518715977669 0.722569584846 -0.456975817680 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.829682111740 -0.395381569862 -0.394082486629 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.896774768829 -0.440434336662 0.042574360967 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.821440160275 -0.447597593069 -0.353401303291 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.847441673279 -0.448818117380 -0.283557623625 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.879417061806 -0.475138366222 0.029482273385 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.645010352135 -0.400364696980 0.650899171829 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn -0.504025876522 -0.301672607660 -0.809290766716 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.059312444180 -0.544704258442 -0.836528122425 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.069433189929 -0.577286839485 0.813584029675 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.883949697018 -0.165927350521 -0.437151044607 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.965354561806 -0.258063018322 0.038652259856 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.872142016888 -0.268645823002 -0.408898174763 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.819668352604 0.424242556095 0.384918212891 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.927781820297 -0.247336685658 -0.279366135597 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.708797097206 0.001518160105 0.705410778522 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.963938236237 -0.265642106533 0.016040276736 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.708797097206 0.001518160105 0.705410778522 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.813350260258 0.528666734695 0.242843255401 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn -0.560952782631 -0.203689426184 -0.802398025990 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.166494444013 -0.262386292219 -0.950490951538 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.025587152690 -0.188668310642 0.981707453728 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.010253517888 0.434012025595 0.900848746300 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.407970279455 0.717792689800 0.564210891724 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.010253517888 0.434012025595 0.900848746300 -vn -0.605787634850 0.494257092476 0.623483181000 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.605787634850 0.494257092476 0.623483181000 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.887520253658 0.064618252218 -0.456215173006 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.999695837498 -0.003873218782 0.024357249960 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.969513058662 0.062274549156 0.236994311213 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.887326896191 -0.078793831170 -0.454359501600 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.198920249939 0.084711700678 -0.976347625256 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.584151804447 0.006681963336 -0.811616897583 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.973477184772 -0.045333888382 -0.224247634411 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.037328623235 0.984341025352 0.172276824713 -vn -0.059391405433 0.995314598083 0.076298937201 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.030940596014 0.946716606617 0.320578128099 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.417391598225 0.758342742920 0.500700056553 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.401526331902 0.782190501690 0.476397514343 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.455726176500 0.851219177246 0.260268300772 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.839084565639 0.100407406688 -0.534654557705 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.998415172100 0.038624547422 -0.040929865092 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.875011146069 -0.052693475038 -0.481226444244 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn 0.171029835939 0.100886046886 -0.980087161064 -vn -0.520150959492 0.017325222492 -0.853898584843 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.995632350445 -0.006020219531 0.093166664243 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.972541630268 0.205112487078 0.109961979091 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.996427416801 0.009055949748 -0.083966597915 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.191165298223 0.042684063315 0.980629324913 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.609602272511 -0.248254984617 0.752830982208 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.794788122177 -0.514725565910 0.321511179209 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.842492818832 -0.518067896366 0.147687375546 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.648548364639 -0.114402368665 0.752527177334 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.894344449043 -0.227003604174 0.385509222746 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.972984254360 -0.096121504903 0.209910243750 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.813350260258 0.528666734695 0.242843255401 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.572210907936 0.744452595711 0.344042211771 -vn 0.598563194275 0.346359431744 0.722327709198 -vn 0.819668352604 0.424242556095 0.384918212891 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.598563194275 0.346359431744 0.722327709198 -vn -0.036019083112 0.815896332264 0.577075183392 -vn 0.407970279455 0.717792689800 0.564210891724 -vn 0.449902802706 0.833744525909 0.320089966059 -vn 0.449902802706 0.833744525909 0.320089966059 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.036019083112 0.815896332264 0.577075183392 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.455726176500 0.851219177246 0.260268300772 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.030940596014 0.946716606617 0.320578128099 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.572210907936 0.744452595711 0.344042211771 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.811857640743 0.316165834665 0.490842521191 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.069371618330 0.841719925404 0.535439193249 -vn -0.069371618330 0.841719925404 0.535439193249 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.417391598225 0.758342742920 0.500700056553 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.842946350574 0.536730229855 0.036906283349 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.972729504108 0.229226604104 -0.035391129553 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn -0.985983729362 -0.146261081100 -0.080273129046 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.949543714523 -0.179056674242 -0.257498413324 -vn -0.876788675785 -0.431774467230 -0.211689546704 -vn -0.850716531277 -0.518900275230 -0.083808444440 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.785471856594 -0.612062454224 0.091725103557 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.814705491066 -0.579487860203 -0.021184906363 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.971690714359 -0.233434706926 -0.036406382918 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.972541630268 0.205112487078 0.109961979091 -vn 0.878596842289 0.430425614119 0.206884905696 -vn 0.971849977970 -0.209810242057 0.107178568840 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.505996525288 0.084093302488 0.858426392078 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.173762992024 0.444730252028 0.878647506237 -vn -0.191165298223 0.042684063315 0.980629324913 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.811857640743 0.316165834665 0.490842521191 -vn -0.173762992024 0.444730252028 0.878647506237 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.773993730545 -0.031222863123 -0.632422983646 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.994028806686 -0.075991086662 -0.078307822347 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.872911095619 -0.077577248216 -0.481672078371 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn 0.120794489980 -0.012212047353 -0.992602407932 -vn -0.519446194172 -0.050545126200 -0.853006899357 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.995949149132 -0.049522735178 0.075052306056 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.741294920444 0.053056657314 0.669079065323 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn 0.616871714592 0.388114273548 0.684716403484 -vn 0.969513058662 0.062274549156 0.236994311213 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.916820347309 -0.011684142984 0.399129003286 -vn 0.505996525288 0.084093302488 0.858426392078 -vn 0.616871714592 0.388114273548 0.684716403484 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.059391405433 0.995314598083 0.076298937201 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.044663131237 0.745588660240 0.664908111095 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.966818511486 0.224690467119 -0.121557444334 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.522335886955 0.850371062756 -0.063516058028 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.882667124271 0.166973158717 0.439338982105 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.521055519581 0.802924513817 0.289505362511 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.556349575520 0.162882700562 0.814827799797 -vn -0.099295251071 0.116247646511 0.988244354725 -vn 0.556349575520 0.162882700562 0.814827799797 -vn 0.372912973166 0.711369335651 0.595726132393 -vn 0.372912973166 0.711369335651 0.595726132393 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.099295251071 0.116247646511 0.988244354725 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.044663131237 0.745588660240 0.664908111095 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.732730984688 0.177388116717 0.656992197037 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.647355437279 0.397109150887 0.650565385818 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.958392262459 0.126938298345 0.255677402020 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.616252362728 0.723567962646 0.310938030481 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.923233270645 0.139920517802 -0.357858330011 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.588900148869 0.785738825798 -0.189238250256 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn -0.505702018738 0.255946218967 -0.823867142200 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn -0.197339877486 0.930521845818 -0.308522373438 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.121527731419 0.339896291494 -0.932577908039 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.134792685509 0.935151696205 -0.327600717545 -vn 0.353185534477 0.857257008553 -0.374660313129 -vn 0.661811292171 0.282459527254 -0.694422364235 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.165890663862 -0.080262839794 0.982872426510 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.861182153225 -0.498627454042 0.098670788109 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn -0.078196831048 -0.519988059998 -0.850586652756 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.607277333736 -0.348896950483 0.713782250881 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn 0.673874497414 -0.215907782316 0.706595361233 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.794679522514 -0.204883232713 0.571408152580 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.075495623052 0.638999342918 0.765493452549 -vn -0.111832089722 0.738575160503 0.664831042290 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.128649204969 -0.137737974524 0.982078194618 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.257161408663 0.242241248488 0.935514390469 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.904853343964 -0.389152079821 0.172629922628 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.237984761596 0.763823807240 0.599947035313 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.171342536807 0.505555272102 0.845609605312 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.171342536807 0.505555272102 0.845609605312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.492926061153 0.859100401402 0.137733176351 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.282441049814 0.953399002552 0.106100834906 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.237984761596 0.763823807240 0.599947035313 -vn 0.251620978117 0.921132147312 0.296989083290 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.593964874744 0.762796759605 0.255630224943 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.506997168064 0.607864022255 0.611109852791 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.257161408663 0.242241248488 0.935514390469 -vn 0.387058705091 0.203184276819 0.899389624596 -vn 0.633399128914 0.460792303085 0.621671974659 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.212242841721 0.213236674666 0.953668236732 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.643045067787 0.415603846312 0.643246829510 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.349010735750 0.216333240271 0.911806702614 -vn 0.212242841721 0.213236674666 0.953668236732 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.349010735750 0.216333240271 0.911806702614 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.059541396797 -0.167730659246 0.984033167362 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn 0.156115815043 -0.433304518461 0.887623250484 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.284749358892 -0.108630344272 0.952427029610 -vn -0.087970539927 -0.399062961340 0.912693798542 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.699491322041 -0.402707010508 0.590371906757 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.772367894650 -0.622275471687 0.127362146974 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.498844444752 -0.762858331203 -0.411340981722 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.616724967957 -0.723277747631 -0.310676127672 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.011610183865 -0.692953765392 -0.720888495445 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.552886605263 -0.401466637850 -0.730165004730 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.816603302956 -0.058255102485 -0.574252009392 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.763571262360 0.082273617387 -0.640460789204 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.695236504078 0.614502906799 -0.372870475054 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.779175877571 0.625292360783 0.043525107205 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.666696548462 0.741401612759 0.076415598392 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.784898281097 0.530796229839 0.319671779871 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.669892311096 0.461255759001 0.581796705723 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.690741717815 0.620739996433 0.370887815952 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn -0.028153385967 0.120939411223 0.992260575294 -vn -0.028153385967 0.120939411223 0.992260575294 -vn 0.129821896553 0.431758940220 0.892597615719 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.711518228054 0.412141650915 0.569105505943 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.488295584917 0.005115387030 0.872663319111 -vn 0.341495156288 -0.114650800824 0.932864546776 -vn 0.483176141977 0.413156896830 0.771908164024 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.915098607540 0.254363477230 -0.312879711390 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.814443290234 0.428261250257 -0.391502827406 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.719430983067 0.689766764641 0.081491425633 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.519054591656 0.696090579033 0.496024429798 -vn 0.509533464909 0.721226334572 0.469263523817 -vn 0.804123282433 0.590738654137 0.066434659064 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.707261800766 0.620109856129 -0.339476883411 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.743355274200 0.583543002605 -0.326956421137 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.601811349392 0.482836604118 -0.636153995991 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn 0.578398287296 0.384770780802 -0.719309985638 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.613577902317 0.418933212757 -0.669340789318 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.332224786282 0.123063504696 -0.935137450695 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.279016286135 0.135762885213 -0.950641036034 -vn -0.090083517134 -0.213283732533 -0.972828328609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.587422788143 -0.400375455618 -0.703302204609 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.486695349216 -0.541777074337 -0.685277462006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn -0.696502983570 -0.649435698986 -0.305150657892 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.746161580086 -0.604792654514 -0.278332084417 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn -0.091559745371 -0.086368091404 -0.992047071457 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.266986012459 0.223067820072 -0.937528252602 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.568451166153 0.425904035568 -0.703895568848 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.460776060820 0.492168724537 -0.738549530506 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.722028672695 0.518228352070 -0.458381891251 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.283960044384 0.958195984364 0.035031434149 -vn 0.609941601753 0.791307687759 -0.042465876788 -vn 0.591527760029 0.703443408012 -0.394033312798 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.257461100817 0.166636288166 -0.951812028885 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.121597990394 0.379167228937 -0.917303740978 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.239243164659 -0.068095922470 -0.968568861485 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.237777918577 0.189985200763 -0.952558279037 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.321765869856 0.031786296517 -0.946285545826 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.499776810408 -0.188684627414 -0.845352709293 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.668428599834 -0.167659357190 -0.724633395672 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.925868690014 -0.143659874797 -0.349469542503 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.994119644165 -0.024308571592 0.105523765087 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.342720925808 -0.695488154888 0.631536722183 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.967731595039 0.089420117438 0.235583648086 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.975846707821 0.090819150209 0.198683232069 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn -0.030241664499 -0.188028365374 0.981697916985 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.300667345524 -0.639052808285 0.707962334156 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn 0.518350839615 -0.279829472303 0.808089017868 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.968691527843 0.096191249788 0.228875383735 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.672764062881 -0.122789070010 0.729596734047 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.852591931820 0.267648220062 0.448833376169 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.411579012871 0.213397726417 0.886038422585 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.003467992181 0.502313077450 0.864678859711 -vn 0.075495623052 0.638999342918 0.765493452549 -vn 0.450228840113 0.505723893642 0.735892176628 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.405834138393 0.527080059052 0.746649324894 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.046318404377 0.483514308929 0.874110102654 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.076707385480 0.563243448734 0.822722792625 -vn 0.174220189452 0.662042379379 0.728935658932 -vn 0.033342286944 0.775118052959 0.630936086178 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.076707385480 0.563243448734 0.822722792625 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.001853432041 0.702297449112 0.711881220341 -vn 0.033342286944 0.775118052959 0.630936086178 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.077421911061 0.794761300087 0.601963758469 -vn -0.107103355229 0.802144825459 0.587445795536 -vn -0.001853432041 0.702297449112 0.711881220341 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.135683953762 0.754256904125 0.642406702042 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.122877381742 0.615804612637 0.778258204460 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.221242532134 0.675346255302 0.703533351421 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.300841867924 0.528104782104 0.794102966785 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.046318404377 0.483514308929 0.874110102654 -vn -0.277309715748 0.398924142122 0.874047398567 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.237557619810 0.219554141164 0.946235895157 -vn -0.146622955799 -0.094849973917 0.984634518623 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.046239048243 0.326019555330 0.944231569767 -vn -0.237557619810 0.219554141164 0.946235895157 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.221997469664 0.427836626768 0.876169443130 -vn 0.046239048243 0.326019555330 0.944231569767 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.254596322775 -0.007401073817 0.967019081116 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.739345252514 0.255324393511 0.623039305210 -vn 0.548855543137 0.135462462902 0.824868202209 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.772374272346 -0.180488973856 0.608984172344 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.930129706860 0.026116527617 0.366301268339 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.841595470905 -0.201776951551 0.501002132893 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.963214516640 -0.029732352123 0.267083823681 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.974512875080 -0.025255583227 0.222905322909 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.957786798477 -0.129983693361 0.256414979696 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.979428172112 -0.143875330687 0.141493156552 -vn 0.964216649532 -0.242792561650 0.106480389833 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.913284003735 -0.340560376644 -0.223452240229 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.935110151768 -0.206819996238 -0.287740230560 -vn 0.898189663887 -0.392043143511 -0.198890775442 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.685206770897 -0.246739089489 -0.685282051563 -vn 0.682528674603 -0.394196480513 -0.615437865257 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.751338779926 -0.380058526993 -0.539486408234 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.448662787676 -0.365269780159 -0.815646827221 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.367560327053 -0.375832140446 -0.850676000118 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.058334883302 -0.343567430973 -0.937314510345 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.077338591218 0.131009072065 -0.988359928131 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.103644236922 0.293572992086 -0.950301408768 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.097468562424 0.453337430954 -0.885993838310 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.034318841994 -0.066007785499 -0.997228741646 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.378137439489 -0.097102984786 -0.920642733574 -vn 0.382293641567 -0.255345821381 -0.888059735298 -vn 0.018272232264 -0.243482127786 -0.969733238220 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.144967123866 -0.303422033787 -0.941764116287 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.314027190208 -0.224331513047 -0.922530353069 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.560364544392 -0.248785302043 -0.789998352528 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.551769614220 -0.158883363008 -0.818722426891 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.784293711185 -0.208406299353 -0.584337353706 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.812738358974 -0.068893551826 -0.578541278839 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.964142441750 -0.114445134997 -0.239440232515 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.985361099243 -0.003984482028 -0.170433565974 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.594317197800 -0.286981523037 0.751284718513 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.392399847507 -0.357331961393 0.847547173500 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.433231920004 -0.378289788961 0.818050682545 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn 0.050828304142 -0.260675102472 0.964087665081 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.374007642269 -0.798582255840 0.471576750278 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.382115125656 -0.919592499733 0.091310665011 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.444822311401 -0.877944648266 0.177049025893 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn -0.175218105316 -0.657200574875 -0.733066201210 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.329441517591 -0.413433134556 -0.848847091198 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.754504084587 -0.130536347628 -0.643182575703 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.970057964325 0.115720912814 -0.213532686234 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.931108534336 0.223939180374 0.287903070450 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.209134399891 0.041847482324 0.976991117001 -vn 0.441210776567 0.220206886530 0.869966685772 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.261542350054 -0.173252478242 0.949515223503 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.209134399891 0.041847482324 0.976991117001 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.728682994843 -0.144246354699 0.669487893581 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.978950858116 -0.052735656500 -0.197165250778 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn -0.656407594681 0.145513758063 -0.740239739418 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.021359665319 0.267187446356 -0.963407814503 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.596999526024 0.318955272436 -0.736110806465 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.922186851501 -0.285774916410 -0.260584205389 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.961917400360 -0.257273793221 0.092331200838 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.965425789356 -0.103984490037 0.239040255547 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.877248644829 -0.199683353305 0.436533331871 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.761923372746 -0.109514206648 0.638341128826 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn 0.262398809195 -0.280063599348 0.923423647881 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.050410073251 -0.219276145101 0.974359691143 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.581942975521 -0.282826542854 0.762464106083 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.861634016037 -0.294701397419 0.413204461336 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.944620668888 -0.320841640234 -0.068938180804 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.610765278339 -0.297193735838 -0.733922123909 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.566875457764 -0.316759556532 -0.760470628738 -vn -0.012012279592 -0.263556957245 -0.964569032192 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.278343588114 -0.634537100792 0.721032261848 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.263197481632 0.913265168667 -0.310924112797 -vn 0.148090556264 0.691439032555 -0.707093536854 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn 0.784938931465 0.612792372704 -0.091413095593 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.759271144867 0.607571125031 0.233162388206 -vn 0.807897269726 0.516708374023 0.283397972584 -vn 0.819642543793 0.571151673794 -0.044405825436 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.788973271847 -0.602539002895 -0.120282799006 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.453124940395 -0.533907651901 0.713877022266 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.209175691009 0.608960092068 0.765122950077 -vn 0.056181445718 0.741137385368 0.668998479843 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.895822942257 -0.438793927431 -0.070435158908 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.114055275917 -0.985913276672 0.122337311506 -vn 0.077598378062 -0.729124426842 -0.679967701435 -vn -0.804523825645 -0.541744470596 -0.243422150612 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn 0.189562767744 -0.437566787004 -0.878977417946 -vn -0.248833328485 -0.838818490505 -0.484216392040 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.030380034819 0.719979643822 0.693329930305 -vn 0.038794174790 0.877033114433 0.478861063719 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.181931316853 0.702624380589 0.687909841537 -vn 0.209175691009 0.608960092068 0.765122950077 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.111832089722 0.738575160503 0.664831042290 -vn -0.128300026059 0.747947514057 0.651240050793 -vn -0.128300026059 0.747947514057 0.651240050793 -vn 0.038794174790 0.877033114433 0.478861063719 -vn -0.030380034819 0.719979643822 0.693329930305 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.838057279587 -0.542088925838 0.061640992761 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.708151936531 -0.630512416363 0.317765504122 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.313671469688 -0.051237426698 0.948148190975 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.350755721331 -0.247280761600 0.903228998184 -vn -0.775184810162 -0.412616372108 0.478368282318 -vn -0.712314128876 -0.334099650383 0.617240667343 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.427448153496 -0.568507194519 -0.702913641930 -vn -0.050258129835 -0.230293035507 -0.971822619438 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.345611095428 0.052760053426 -0.936893463135 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn 0.472444206476 -0.356785893440 -0.805915832520 -vn -0.149990439415 -0.628571093082 -0.763152182102 -vn -0.063608899713 -0.294556140900 -0.953514873981 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn 0.437060922384 -0.336361557245 0.834169447422 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.003682370530 -0.286790549755 0.957986235619 -vn 0.141802325845 -0.285771101713 0.947748363018 -vn 0.554837346077 -0.267414331436 0.787810325623 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.525639712811 -0.737791001797 0.423517793417 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.226015701890 -0.698085904121 0.679406344891 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.496036052704 -0.635917305946 0.591233789921 -vn -0.449271619320 -0.796677172184 0.404302537441 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn -0.702819705009 -0.693241298199 0.159565150738 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.526743113995 -0.821171522141 0.219588309526 -vn -0.644651114941 -0.755516409874 0.116704128683 -vn -0.689048826694 -0.722033262253 -0.062287207693 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn 0.273087769747 0.699498236179 -0.660397827625 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.465314835310 0.811250209808 -0.354055315256 -vn 0.273829400539 0.924696326256 -0.264488548040 -vn 0.183432310820 0.690850257874 -0.699341475964 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.908309876919 0.015843641013 0.417997717857 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.448863714933 0.183967590332 0.874458312988 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.819909214973 0.467708528042 0.330147922039 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.972455918789 0.091722354293 0.214281424880 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.707751631737 0.511009931564 0.487807840109 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.648009002209 0.425326675177 0.631808161736 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.716207981110 0.499084711075 0.487812042236 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.716207981110 0.499084711075 0.487812042236 -vn -0.825679838657 0.400832891464 0.396970719099 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn -0.340450763702 -0.576976120472 -0.742422938347 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.962301254272 -0.039169192314 -0.269150674343 -vn -0.953632593155 -0.027220398188 -0.299739748240 -vn -0.446626484394 -0.477167993784 -0.756858944893 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.979201793671 0.043794684112 0.198105692863 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.707751631737 0.511009931564 0.487807840109 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.880204081535 0.234645605087 -0.412531435490 -vn -0.280455946922 -0.412052839994 -0.866923809052 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.629050672054 0.575037002563 0.523094296455 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.629050672054 0.575037002563 0.523094296455 -vn -0.739546954632 0.515352368355 0.432992160320 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn -0.263094604015 -0.543884932995 -0.796850323677 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.946830511093 0.063935965300 -0.315315932035 -vn -0.849882602692 0.271090626717 -0.451895385981 -vn -0.321785986423 -0.349392801523 -0.879987776279 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.981580853462 0.085098065436 0.171047657728 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.962681233883 0.257090866566 -0.084552332759 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.565301001072 0.742878913879 0.358560562134 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.496823996305 0.472443997860 0.727985262871 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.496823996305 0.472443997860 0.727985262871 -vn -0.266624689102 0.593041419983 0.759745419025 -vn -0.266624689102 0.593041419983 0.759745419025 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.616365551949 0.101494207978 0.780892074108 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.192745268345 0.492540299892 0.848677396774 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.895483732224 -0.159650802612 0.415476232767 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.913564145565 -0.070332199335 0.400566965342 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.856193542480 -0.515455365181 -0.035190675408 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.620249688625 -0.654477775097 -0.432376146317 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.833615779877 -0.411711692810 -0.368209511042 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.254390329123 -0.599514067173 -0.758859992027 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.844129383564 0.021499739960 -0.535708248615 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.901966691017 0.388665527105 -0.188136070967 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.935332417488 0.343503236771 -0.084609612823 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.575632691383 0.763012647629 0.294038593769 -vn 0.171868190169 0.732080280781 0.659181177616 -vn 0.171868190169 0.732080280781 0.659181177616 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.521306455135 0.467230886221 0.714097201824 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.521306455135 0.467230886221 0.714097201824 -vn -0.180061206222 0.563334167004 0.806370019913 -vn -0.180061206222 0.563334167004 0.806370019913 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.535567224026 -0.012940082699 0.844393432140 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.184908628464 0.381606191397 0.905640959740 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.843786776066 -0.245984554291 0.476985782385 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.793580412865 -0.300677359104 0.528983235359 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.784687519073 -0.618691146374 -0.038558837026 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.570066154003 -0.723200023174 -0.389879912138 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn 0.830022990704 -0.359803080559 -0.426149666309 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.330498814583 -0.562601387501 -0.757793009281 -vn 0.551274299622 -0.377769410610 -0.743899822235 -vn 0.770441830158 0.124682173133 -0.625198960304 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.648009002209 0.425326675177 0.631808161736 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.649962127209 -0.032834753394 0.759256958961 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn -0.269836694002 -0.648911595345 -0.711408436298 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.361486613750 -0.871635258198 -0.331027746201 -vn -0.755871891975 -0.587243855000 0.289486378431 -vn -0.976216316223 -0.161507442594 -0.144627094269 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.092150472105 -0.960336923599 -0.263175487518 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.548589885235 -0.620292305946 -0.560612738132 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.956916511059 -0.095712594688 0.274134784937 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.129396855831 0.545063197613 0.828349292278 -vn 0.129396855831 0.545063197613 0.828349292278 -vn -0.290875703096 0.016440996900 0.956619560719 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.290875703096 0.016440996900 0.956619560719 -vn -0.252987205982 -0.770890474319 0.584572792053 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.782792508602 -0.622060239315 0.016640689224 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.374225527048 -0.918710529804 -0.126199200749 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.978597700596 -0.203487649560 -0.030648948625 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.873680889606 -0.254217475653 -0.414795339108 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.976393342018 -0.034493237734 0.213228285313 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.996993303299 0.043252151459 0.064293101430 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.823331177235 0.180604666471 0.538059234619 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.522149622440 0.581013023853 0.624326586723 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.483783185482 -0.188346296549 0.854680955410 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.042617920786 -0.077262252569 0.996099531651 -vn 0.121004454792 -0.743254899979 0.657974183559 -vn 0.702570617199 -0.417962342501 0.575935781002 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.743372976780 -0.626676201820 0.233823701739 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.411944001913 0.393821209669 0.821709811687 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.787957370281 0.477610796690 0.388601541519 -vn 0.076644353569 0.755293190479 0.650890052319 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.787957370281 0.477610796690 0.388601541519 -vn -0.448863714933 0.183967590332 0.874458312988 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn -0.918951630592 -0.393101125956 0.031612586230 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.107680648565 -0.894641518593 -0.433614403009 -vn -0.333550721407 -0.596247136593 -0.730228245258 -vn -0.959001660347 -0.101881392300 -0.264454126358 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.563659667969 -0.461650341749 -0.684957504272 -vn 0.755673527718 -0.580640435219 -0.303008645773 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.972455918789 0.091722354293 0.214281424880 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.411944001913 0.393821209669 0.821709811687 -vn 0.076644353569 0.755293190479 0.650890052319 -vn 0.952149391174 0.305112123489 -0.017836395651 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.518603384495 0.300804406404 0.800354421139 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.504803478718 -0.691964030266 0.516099989414 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.836774110794 -0.481221765280 0.261217683554 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.997338175774 0.072519011796 0.007588622160 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.700886607170 0.338039726019 0.628082096577 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.571633458138 0.247708499432 0.782224833965 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.674985289574 0.334197402000 0.657804667950 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.674985289574 0.334197402000 0.657804667950 -vn -0.727050065994 0.229038923979 0.647255241871 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn -0.425885379314 -0.623170614243 -0.655957341194 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.975743651390 -0.217743486166 -0.022630447522 -vn -0.956104636192 -0.292931735516 -0.007408959325 -vn -0.553487002850 -0.562953591347 -0.613787710667 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.964841306210 0.247465044260 0.088557027280 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.700886607170 0.338039726019 0.628082096577 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.963580250740 -0.267051726580 0.014016546309 -vn -0.333052396774 -0.693272292614 -0.639100670815 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.655655622482 0.397478044033 0.641971111298 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.655655622482 0.397478044033 0.641971111298 -vn -0.725499093533 0.294759482145 0.621906638145 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn -0.313091188669 -0.700623571873 -0.641171157360 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.960929155350 -0.276273429394 0.016975795850 -vn -0.971467733383 -0.236483171582 -0.018060231581 -vn -0.470730185509 -0.604085922241 -0.643034458160 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.935157954693 0.353377223015 -0.024578729644 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.856117010117 0.482730776072 -0.184484988451 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.540606260300 0.807461678982 0.236115515232 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.605633556843 0.573746502399 0.551382780075 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.605633556843 0.573746502399 0.551382780075 -vn -0.059534739703 0.594721972942 0.801724016666 -vn -0.059534739703 0.594721972942 0.801724016666 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.771579861641 0.202758759260 0.602953910828 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.322712332010 0.518643856049 0.791748225689 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.961140692234 0.050061751157 0.271481752396 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.970984339714 0.123645357788 0.204697906971 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.952282905579 -0.284368395805 -0.110868863761 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.685568511486 -0.533490240574 -0.495362460613 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.874183952808 -0.164703086019 -0.456809937954 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.214254140854 -0.526274204254 -0.822879493237 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.695948600769 0.300683468580 -0.652108132839 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.775852501392 0.567831695080 -0.274991095066 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.832989275455 0.504606544971 -0.226938515902 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.460896521807 0.879790425301 0.116375401616 -vn 0.118212953210 0.816253483295 0.565469682217 -vn 0.118212953210 0.816253483295 0.565469682217 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.578698873520 0.646696209908 0.496881872416 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.578698873520 0.646696209908 0.496881872416 -vn -0.094312846661 0.586990058422 0.804081916809 -vn -0.094312846661 0.586990058422 0.804081916809 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.767063081264 0.215842425823 0.604174017906 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.321015238762 0.514520943165 0.795121014118 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.973615527153 0.120421126485 0.193833947182 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.966279029846 0.053210075945 0.251939415932 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.952031672001 -0.265573054552 -0.152008801699 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.723640680313 -0.512672543526 -0.462072551250 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn 0.849038064480 -0.124876268208 -0.513361752033 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.313650816679 -0.538114547729 -0.782340049744 -vn 0.549481987953 -0.322085440159 -0.770928323269 -vn 0.629623532295 0.333947807550 -0.701464951038 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.180510208011 0.646930694580 0.740875661373 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.571633458138 0.247708499432 0.782224833965 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.322253704071 -0.189766019583 0.927438080311 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn -0.196830675006 -0.838620603085 -0.507910609245 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.068582832813 -0.993876457214 -0.086637146771 -vn -0.326727688313 -0.762412965298 0.558547675610 -vn -0.845117628574 -0.490876168013 0.211699649692 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.433536440134 -0.874591886997 -0.217106372118 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.634616017342 -0.463246196508 -0.618599593639 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.955628812313 0.291310042143 -0.043726418167 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.180510208011 0.646930694580 0.740875661373 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.088888555765 0.015037650242 0.995928049088 -vn 0.310724049807 -0.698983669281 0.644105851650 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.943425536156 -0.203005120158 -0.262177675962 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.717304289341 -0.660168945789 -0.222826108336 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.891302168369 0.238586738706 -0.385560452938 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.758884966373 0.092251464725 -0.644657492638 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.930916905403 0.332600742579 -0.150898694992 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.877895355225 0.405764371157 -0.254273504019 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.823468267918 0.544366657734 0.159890517592 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.448758721352 0.815742969513 0.364937067032 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn 0.803170442581 0.076972313225 0.590755879879 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.461701482534 0.051164239645 0.885558545589 -vn 0.641450524330 -0.522252142429 0.561955392361 -vn 0.964601278305 -0.034498769790 0.261446416378 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.508389532566 0.448634028435 0.735028982162 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.734525084496 0.400696694851 0.547644972801 -vn 0.149192854762 0.818112552166 0.555367708206 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.734525084496 0.400696694851 0.547644972801 -vn -0.518603384495 0.300804406404 0.800354421139 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn -0.943273961544 -0.317976415157 0.095526158810 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.181024864316 -0.898927867413 -0.398947030306 -vn -0.368347316980 -0.700353562832 -0.611412405968 -vn -0.957798421383 -0.287328153849 0.008044288494 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.515817642212 -0.344284206629 -0.784474670887 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.508389532566 0.448634028435 0.735028982162 -vn 0.149192854762 0.818112552166 0.555367708206 -vn 0.900408267975 0.406306445599 -0.155499354005 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.443338632584 -0.801661252975 0.400986373425 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.655084729195 -0.755481123924 0.010595246218 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.247283771634 -0.719329714775 -0.649165272713 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.519214332104 0.253620952368 0.816145122051 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.505004465580 0.475358963013 0.720419526100 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.520211935043 0.559058606625 0.645626068115 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.508684575558 0.100909605622 0.855018854141 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.482553303242 0.293915122747 0.825079500675 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.143501415849 0.469171375036 0.871369957924 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.482553303242 0.293915122747 0.825079500675 -vn -0.508684575558 0.100909605622 0.855018854141 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn -0.346198737621 -0.711642503738 -0.611319363117 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.869434535503 -0.445658445358 0.213242009282 -vn -0.828451156616 -0.499392956495 0.253525912762 -vn -0.473281711340 -0.666536271572 -0.575963377953 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.910344779491 0.372827082872 -0.179644897580 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.532382369041 0.165311589837 0.830205440521 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.265235602856 0.751007497311 0.604679942131 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.519214332104 0.253620952368 0.816145122051 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.838412821293 -0.511487185955 0.188267946243 -vn -0.325170487165 -0.671815574169 -0.665528357029 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.438396394253 0.250405520201 0.863195061684 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.184828087687 0.570850193501 0.799980401993 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.438396394253 0.250405520201 0.863195061684 -vn -0.532382369041 0.165311589837 0.830205440521 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn -0.371108859777 -0.615805447102 -0.695026516914 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.861999690533 -0.480082362890 0.162718862295 -vn -0.883482158184 -0.442702859640 0.153210327029 -vn -0.472557634115 -0.605245292187 -0.640599250793 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.831110119820 0.524186849594 -0.185698986053 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.674065530300 0.659879446030 -0.331956028938 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.463716655970 0.855164170265 0.231648653746 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.686772048473 0.587655961514 0.427790343761 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.143501415849 0.469171375036 0.871369957924 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.901354968548 0.173700019717 0.396721005440 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.505004465580 0.475358963013 0.720419526100 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.986742973328 0.148276701570 -0.065972454846 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.980657398701 0.183535054326 -0.068014398217 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.863255441189 -0.137341469526 -0.485723584890 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.544145107269 -0.351761192083 -0.761689007282 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.687293410301 -0.005807823967 -0.726356685162 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.128968864679 -0.386283367872 -0.913319349289 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.391208052635 0.468177586794 -0.792316854000 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.623391151428 0.703280031681 -0.341731846333 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.739776730537 0.600438773632 -0.303650617599 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.388378977776 0.908979058266 0.151389509439 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.265235602856 0.751007497311 0.604679942131 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.630653321743 0.678292334080 0.377088755369 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.184828087687 0.570850193501 0.799980401993 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.874575555325 0.318329840899 0.365764498711 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.520211935043 0.559058606625 0.645626068115 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.937908053398 0.346375674009 -0.018771579489 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.918112099171 0.388273864985 -0.079458087683 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.876418769360 0.027477806434 -0.480765074492 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.560012459755 -0.217515259981 -0.799420535564 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.664896368980 0.172920316458 -0.726643919945 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.129326030612 -0.292879104614 -0.947362959385 -vn 0.389072328806 -0.095891259611 -0.916202783585 -vn 0.406478911638 0.543811917305 -0.734195768833 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.339759290218 0.652270197868 0.677574515343 -vn -0.228174239397 0.046188309789 0.972524106503 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.228174239397 0.046188309789 0.972524106503 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn 0.170270666480 -0.406844973564 0.897488176823 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn -0.235076472163 -0.728490591049 -0.643459796906 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.082195654511 -0.937620520592 -0.337804198265 -vn 0.088449247181 -0.925405740738 0.368511795998 -vn -0.619149923325 -0.738844692707 0.266010940075 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.476972043514 -0.707461297512 -0.521532535553 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.355099231005 -0.208450347185 -0.911291956902 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.687901079655 0.645506918430 -0.331832736731 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.339759290218 0.652270197868 0.677574515343 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.513085484505 0.034213557839 0.857655346394 -vn 0.684322059155 -0.660563945770 0.308801889420 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.904637575150 0.042771328241 -0.424029976130 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.753184616566 -0.437666743994 -0.491081178188 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.821415543556 0.418836295605 -0.387108117342 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.494041234255 0.320056259632 -0.808385610580 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.869845926762 0.474592566490 -0.134647488594 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.675994634628 0.653667986393 -0.340219646692 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.809969186783 0.585213720798 0.038403198123 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.442176759243 0.858698606491 0.259068340063 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.975914239883 0.216983765364 0.022570852190 -vn 0.902213692665 0.365601032972 0.228793248534 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.775210857391 0.244860023260 0.582315802574 -vn 0.927561044693 -0.318227767944 0.195861279964 -vn 0.975914239883 0.216983765364 0.022570852190 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.501678824425 0.396977752447 0.768587708473 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.437682479620 0.131488755345 0.889463186264 -vn 0.227183014154 0.711364388466 0.665092885494 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.437682479620 0.131488755345 0.889463186264 -vn -0.234297513962 -0.089574843645 0.968029439449 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn -0.734225749969 -0.640220344067 0.225899294019 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.405751198530 -0.675861299038 -0.615286529064 -vn -0.354655981064 -0.667066633701 -0.655165076256 -vn -0.765435516834 -0.599227905273 0.234594091773 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.280589044094 -0.079728811979 -0.956510901451 -vn 0.431223034859 -0.245175361633 -0.868294715881 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.913566887379 0.292726159096 -0.282324224710 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.501678824425 0.396977752447 0.768587708473 -vn 0.227183014154 0.711364388466 0.665092885494 -vn 0.610397398472 0.699176430702 -0.372246384621 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.110006704926 0.644826173782 0.756371438503 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.693001866341 0.498886138201 0.520443081856 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.616370320320 0.433791041374 0.657200813293 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.901949763298 -0.291285008192 0.318809688091 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.359303474426 -0.736660242081 0.572916030884 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.890769839287 0.184809222817 0.415180265903 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.616071522236 0.741670787334 0.265292972326 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.983508825302 0.178707674146 0.027819553390 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.657146453857 0.579351842403 0.482192873955 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.677771806717 0.617188751698 0.399629086256 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.677771806717 0.617188751698 0.399629086256 -vn -0.768773972988 0.435160547495 0.468638271093 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn -0.316729605198 -0.591466248035 -0.741518735886 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.926304101944 0.045903865248 -0.373969972134 -vn -0.975134015083 -0.114833161235 -0.189544335008 -vn -0.430359631777 -0.595827996731 -0.678070485592 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.970880985260 -0.015337765217 0.239070773125 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.616071522236 0.741670787334 0.265292972326 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.833082377911 0.170161336660 -0.526325821877 -vn -0.199534490705 -0.497407346964 -0.844258189201 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.610949575901 0.705598056316 0.358987480402 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.610949575901 0.705598056316 0.358987480402 -vn -0.668119966984 0.705169081688 0.237386316061 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn -0.208768904209 -0.573515474796 -0.792146205902 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.850158751011 0.180513113737 -0.494616091251 -vn -0.799643516541 0.236606702209 -0.551894485950 -vn -0.254326343536 -0.407145589590 -0.877240300179 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.868796169758 -0.152697831392 0.471037775278 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.981905460358 0.179060816765 -0.061635598540 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.585843265057 0.739259600639 0.332088679075 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.518502652645 0.501994550228 0.692211270332 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.518502652645 0.501994550228 0.692211270332 -vn -0.206256195903 0.641347289085 0.739007472992 -vn -0.206256195903 0.641347289085 0.739007472992 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.554780423641 0.107210293412 0.825060427189 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.157286047935 0.538553655148 0.827780783176 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.880316972733 -0.152910739183 0.449066013098 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.889279901981 -0.100665405393 0.446147680283 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.815516710281 -0.578331232071 0.021573621780 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.567068278790 -0.731413245201 -0.378772050142 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.797515034676 -0.488100707531 -0.354580610991 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.196752786636 -0.678127408028 -0.708118319511 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.804508805275 -0.077632702887 -0.588845252991 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.987893760204 0.129381850362 0.085593491793 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.983508825302 0.178707674146 0.027819553390 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.651536583900 0.604201257229 0.458738386631 -vn 0.222944125533 0.750830531120 0.621730983257 -vn 0.222944125533 0.750830531120 0.621730983257 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.461553364992 0.375474810600 0.803733229637 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.461553364992 0.375474810600 0.803733229637 -vn -0.139188796282 0.683903872967 0.716171741486 -vn -0.139188796282 0.683903872967 0.716171741486 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.396851718426 -0.018567655236 0.917694926262 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.104782521725 0.411863684654 0.905201017857 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.646806478500 -0.355502337217 0.674729228020 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.632826983929 -0.368218600750 0.681135118008 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.626226544380 -0.741151809692 0.241938635707 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.506012320518 -0.837805211544 -0.205021828413 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn 0.793541431427 -0.589811086655 -0.149715930223 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.339195787907 -0.687699139118 -0.641884803772 -vn 0.614367485046 -0.528622925282 -0.585756242275 -vn 0.908918678761 -0.099282518029 -0.404981225729 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.657146453857 0.579351842403 0.482192873955 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.734268069267 0.103339523077 0.670948088169 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn -0.233318984509 -0.666360259056 -0.708185136318 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.399920433760 -0.850315570831 -0.342092126608 -vn -0.848475039005 -0.487641692162 0.205659151077 -vn -0.952475607395 -0.035068064928 -0.302589625120 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.043543953449 -0.980369687080 -0.192299902439 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.558148503304 -0.735797524452 -0.383499979973 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.871987402439 -0.213342875242 0.440593689680 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.113310351968 0.573081195354 0.811627209187 -vn 0.113310351968 0.573081195354 0.811627209187 -vn -0.357588768005 0.118223853409 0.926365673542 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.357588768005 0.118223853409 0.926365673542 -vn -0.383437961340 -0.706359207630 0.595005929470 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.748748421669 -0.647354602814 0.142505466938 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.360437154770 -0.932430565357 -0.025656782091 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.959618747234 -0.261538088322 0.103584453464 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.903939485550 -0.364983111620 -0.222891658545 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.945667684078 -0.079083986580 0.315370142460 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.939626336098 -0.190783411264 0.284084558487 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.892274856567 0.088678508997 0.442698240280 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.598061859608 0.474797159433 0.645669937134 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn 0.501735031605 -0.120247341692 0.856622755527 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.000675067538 -0.005126592703 0.999986648560 -vn 0.021822169423 -0.700111567974 0.713699936867 -vn 0.660671710968 -0.416826665401 0.624314367771 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.149933636189 0.697240829468 0.700981557369 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.731816112995 0.506709039211 0.455731421709 -vn 0.096828460693 0.822797715664 0.560025155544 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.731816112995 0.506709039211 0.455731421709 -vn -0.693001866341 0.498886138201 0.520443081856 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn -0.980364203453 -0.180218189955 -0.080046124756 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.342308551073 -0.898793816566 -0.273851275444 -vn -0.389741688967 -0.670392096043 -0.631407797337 -vn -0.980241477489 -0.154460281134 -0.123566515744 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.475301384926 -0.572428107262 -0.668142676353 -vn 0.668267428875 -0.714787065983 -0.206150755286 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.890769839287 0.184809222817 0.415180265903 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.149933636189 0.697240829468 0.700981557369 -vn 0.096828460693 0.822797715664 0.560025155544 -vn 0.960634171963 0.272636055946 -0.053400605917 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.989734828472 0.125559329987 -0.068262815475 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.921148419380 0.385149210691 -0.056086633354 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.672626733780 0.736264288425 0.074082300067 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.257287919521 0.884805023670 0.388488024473 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.257287919521 0.884805023670 0.388488024473 -vn -0.063488200307 0.792590856552 0.606439590454 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.495524138212 0.582533538342 0.644290685654 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.110006704926 0.644826173782 0.756371438503 -vn 0.817651689053 0.281194716692 0.502369642258 -vn 0.819909214973 0.467708528042 0.330147922039 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.996836364269 -0.078574545681 0.011971659027 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.992345750332 0.105561174452 -0.064083777368 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.933551311493 0.355292409658 0.047425679862 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.865989685059 0.453615128994 0.210464164615 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.882028698921 0.317493706942 0.348171114922 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.908309876919 0.015843641013 0.417997717857 -vn 0.972412407398 0.062441378832 0.224755913019 -vn 0.974218785763 0.136953219771 0.179280668497 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.999813377857 -0.018315166235 -0.006142910570 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.991819202900 -0.034799017012 -0.122815772891 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.977511823177 -0.022532563657 -0.209673374891 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.987035095692 0.088362626731 -0.133991599083 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.983536243439 0.177552938461 0.033636920154 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.967617809772 -0.103586673737 0.230186060071 -vn 0.981092154980 0.054133977741 0.185816302896 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.795029461384 -0.241429388523 -0.556453049183 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.487139850855 -0.463946342468 -0.739897668362 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.647841155529 -0.025598770007 -0.761345207691 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.859054207802 0.164472088218 -0.484741955996 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.946094691753 0.247164011002 -0.209319770336 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.990318894386 0.134526759386 0.034220863134 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.969940900803 -0.016906807199 -0.242752596736 -vn 0.969082534313 0.013526707888 -0.246365621686 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn 0.991130888462 -0.068684190512 0.113763011992 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.999113142490 0.000560889952 0.042102612555 -vn 0.997338175774 0.072519011796 0.007588622160 -vn 0.724958002567 -0.519052088261 -0.452792286873 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.754400372505 -0.617815971375 0.221773415804 -vn -0.676493585110 -0.725261986256 0.127872824669 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.851959705353 0.511508643627 0.111908867955 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.310053557158 0.172868609428 0.934870719910 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.065754547715 -0.648359239101 0.758489727974 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.398574531078 -0.913124322891 0.085687346756 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn 0.262353718281 -0.850628614426 0.455633014441 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.809110283852 -0.140281960368 0.570667624474 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.454158663750 0.889905989170 -0.042511224747 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.487139791250 -0.811088681221 -0.323774576187 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.450961977243 -0.891635656357 -0.040238905698 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.488797932863 0.870124578476 -0.062927119434 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834133267403 0.451350212097 -0.317024648190 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.891583979130 0.427818477154 -0.148490324616 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.920045375824 -0.349020928144 -0.178047493100 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.834865987301 0.549538910389 0.031714677811 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.941915929317 0.115449301898 -0.315382063389 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.076232120395 0.892228424549 0.445103466511 -vn -0.539173722267 0.833431780338 0.121174119413 -vn -0.531211972237 0.828068792820 0.179209098220 -vn -0.531211972237 0.828068792820 0.179209098220 -vn 0.316012024879 0.686757266521 0.654599726200 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.076232120395 0.892228424549 0.445103466511 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.316012024879 0.686757266521 0.654599726200 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.092993848026 0.951101779938 0.294546306133 -vn -0.162509486079 0.963348150253 0.213426902890 -vn 0.092993848026 0.951101779938 0.294546306133 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162509486079 0.963348150253 0.213426902890 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.039080802351 -0.837885558605 0.544445097446 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.523957431316 -0.527176558971 0.668994367123 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.644062459469 -0.736073076725 0.208278611302 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.459524750710 -0.881456553936 -0.108955472708 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.931347429752 -0.191739603877 0.309560865164 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.296533823013 0.937092840672 0.184186592698 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.399717628956 -0.800060749054 -0.447357386351 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.221573963761 -0.975115537643 0.007395572029 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn 0.323385655880 -0.909398913383 -0.261563360691 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.792649924755 -0.450770765543 0.410501927137 -vn 0.908204495907 -0.398815929890 0.126926913857 -vn 0.879008293152 0.327037870884 0.346973568201 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.296533823013 0.937092840672 0.184186592698 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.584438264370 -0.750773370266 -0.307849317789 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.463834911585 -0.781955063343 -0.416417390108 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.656715273857 0.671186864376 0.343850612640 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.162260547280 0.985521793365 -0.049175888300 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.278513342142 0.959875881672 -0.032689496875 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.552404344082 0.714155137539 -0.429920792580 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.807621896267 0.130036145449 -0.575184762478 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.770505726337 0.605568349361 -0.199017360806 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.874981164932 -0.187535449862 -0.446361333132 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.765422403812 0.624349057674 0.155938431621 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.386452257633 0.830117344856 0.401945084333 -vn 0.018751272932 0.761757254601 0.647591114044 -vn -0.386452257633 0.830117344856 0.401945084333 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.018751272932 0.761757254601 0.647591114044 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.301279544830 0.869882464409 0.390557467937 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.879008293152 0.327037870884 0.346973568201 -vn 0.656715273857 0.671186864376 0.343850612640 -vn 0.256493657827 0.966490387917 0.010358544998 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.472992837429 -0.007466317620 0.881034612656 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.620225965977 0.440775215626 0.648873627186 -vn 0.620225965977 0.440775215626 0.648873627186 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.321225166321 0.935288310051 0.148492872715 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.977639138699 0.079577423632 -0.194651469588 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.886710703373 -0.365493357182 0.283123165369 -vn -0.299715340137 -0.398805558681 0.866674602032 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.418872237206 0.170925334096 0.891813099384 -vn 0.257990837097 0.399163067341 0.879834949970 -vn -0.073301777244 0.768137931824 0.636074662209 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.073301777244 0.768137931824 0.636074662209 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.257990837097 0.399163067341 0.879834949970 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.106712952256 0.917102098465 0.384104311466 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.106712952256 0.917102098465 0.384104311466 -vn 0.350384771824 0.861267209053 0.368034303188 -vn 0.350384771824 0.861267209053 0.368034303188 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.287710011005 0.868447899818 0.403758883476 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.169324740767 0.985013782978 -0.032816808671 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.506764352322 0.822178900242 0.259252250195 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.777136385441 0.616913676262 -0.124404892325 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.626703619957 0.600684523582 0.496407806873 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.902384638786 0.115731023252 0.415100276470 -vn -0.418872237206 0.170925334096 0.891813099384 -vn -0.379872918129 0.728305935860 0.570321917534 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.794405698776 -0.012495234609 -0.607258975506 -vn 0.392160177231 -0.396549701691 -0.830035388470 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.955716431141 0.190873801708 -0.223993942142 -vn 0.949413836002 0.132040485740 -0.284918785095 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.482846260071 0.869433462620 0.104618154466 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.746451914310 0.651406109333 0.135939553380 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.895273745060 0.445466607809 0.006669424009 -vn 0.971128344536 0.229403585196 -0.065450385213 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.646575033665 0.757143557072 0.093136429787 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.840204894543 0.542268991470 -0.000119482458 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.695233106613 -0.308236718178 0.649338960648 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.509524762630 0.326571792364 0.796074986458 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn -0.063488200307 0.792590856552 0.606439590454 -vn 0.532998859882 0.815917551517 0.224032908678 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.510312438011 0.841042578220 0.179523259401 -vn 0.510312438011 0.841042578220 0.179523259401 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.041679881513 0.924551546574 0.378770738840 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.714573740959 0.695854723454 -0.071906782687 -vn -0.808967173100 0.572136342525 -0.135026350617 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.941590726376 0.033662363887 -0.335072696209 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.881481885910 -0.453425347805 -0.131890684366 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.595355689526 -0.790148377419 0.145661026239 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.527738094330 -0.663481891155 0.530362427235 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.087274819613 0.444357991219 0.891587972641 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.383311569691 0.245430797338 0.890413403511 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.087274819613 0.444357991219 0.891587972641 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.050192341208 0.664369225502 0.745717287064 -vn 0.541074633598 0.742484569550 0.394911348820 -vn 0.368794947863 0.655544221401 0.658978044987 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.366472154856 0.870783627033 0.327771276236 -vn -0.162673503160 0.963678956032 0.211802154779 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn -0.453713983297 -0.402141332626 0.795252144337 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.523102521896 -0.394829660654 0.755296826363 -vn -0.383311569691 0.245430797338 0.890413403511 -vn -0.217805311084 -0.017195902765 0.975840747356 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.368794947863 0.655544221401 0.658978044987 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.366472154856 0.870783627033 0.327771276236 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.432463288307 0.539263606071 0.722613453865 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.432463288307 0.539263606071 0.722613453865 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn -0.656450152397 -0.729013919830 -0.193937793374 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.168870478868 -0.724403142929 -0.668373286724 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn 0.312904179096 -0.418887764215 -0.852422416210 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.165293544531 -0.684560775757 -0.709968030453 -vn -0.561405301094 -0.783839344978 -0.265367656946 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.636142671108 -0.726978540421 0.258504658937 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.592031836510 -0.689757585526 0.416812658310 -vn -0.445946663618 -0.807002365589 0.387141823769 -vn -0.491080105305 -0.837426304817 0.239911466837 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.653411686420 -0.700181365013 0.287748575211 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.750844120979 -0.583663046360 0.309144854546 -vn -0.671968698502 -0.667977213860 0.319788247347 -vn -0.584727287292 -0.760881543159 0.281341969967 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.874737322330 -0.461276412010 -0.148521482944 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.618247926235 -0.775683164597 0.126827254891 -vn -0.582560062408 -0.809202492237 0.076257012784 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.126566886902 -0.326682716608 -0.936621189117 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn 0.137934416533 -0.403524935246 -0.904511868954 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.437444090843 -0.449006646872 -0.779124975204 -vn -0.246353954077 -0.609194815159 -0.753784716129 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.691448807716 -0.499428868294 -0.521985948086 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.538350522518 -0.738366723061 -0.406193703413 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.788505494595 -0.575718581676 -0.216349691153 -vn -0.639232695103 -0.769012033939 0.001446417999 -vn -0.664937376976 -0.730501115322 0.155648365617 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.832284808159 -0.533833265305 -0.149412333965 -vn -0.830348789692 -0.545909702778 -0.111818790436 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.484131455421 -0.316163808107 -0.815878152847 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.795067191124 -0.386380672455 -0.467523425817 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.898375689983 -0.393273085356 -0.195594832301 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.966934204102 -0.186706066132 -0.173721387982 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.900562524796 0.426854074001 0.082357078791 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.086542211473 0.967878103256 0.236056029797 -vn -0.086542211473 0.967878103256 0.236056029797 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.482846260071 0.869433462620 0.104618154466 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.664757490158 0.741586744785 -0.090258158743 -vn 0.758434236050 0.649761736393 -0.050863955170 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.349582046270 -0.311735272408 -0.883523344994 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.704096138477 -0.441944241524 -0.555818200111 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.832196235657 -0.529535293579 -0.164443820715 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.915586531162 -0.333801418543 0.224227353930 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.820469796658 0.119803763926 0.558995842934 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.362487792969 0.694832563400 0.621136307716 -vn -0.362487792969 0.694832563400 0.621136307716 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.367153495550 0.875142931938 0.315155804157 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.683762192726 0.728296756744 -0.045311164111 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn -0.519133925438 -0.761686325073 0.387729167938 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.973435103893 -0.116879180074 -0.196884244680 -vn -0.880192518234 -0.458102107048 0.124111056328 -vn -0.675654530525 -0.652904331684 0.342354983091 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.540591895580 -0.128417894244 0.831426024437 -vn 0.310053557158 0.172868609428 0.934870719910 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.488122433424 0.411598801613 0.769625186920 -vn 0.412324339151 0.719989717007 0.558214545250 -vn 0.412324339151 0.719989717007 0.558214545250 -vn -0.041679881513 0.924551546574 0.378770738840 -vn 0.414537787437 0.577000021935 0.703725337982 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.493106514215 -0.556070029736 -0.669053137302 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.152241155505 -0.867611408234 -0.473363518715 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.847137212753 0.013076731004 -0.531213283539 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.682675063610 -0.077603086829 -0.726589620113 -vn 0.519804894924 -0.123855583370 -0.845258951187 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.858815073967 0.119769096375 -0.498088389635 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.907647013664 0.391346275806 -0.151739954948 -vn 0.916165411472 0.250511020422 -0.312866061926 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.761525034904 0.090172626078 -0.641832113266 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.096408627927 -0.179964497685 -0.978937268257 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.147158190608 0.045159835368 -0.988081514835 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.605928599834 0.056156951934 -0.793534457684 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.447385460138 0.231602251530 -0.863832533360 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.524165391922 0.471699982882 -0.709048509598 -vn 0.711000323296 0.521369159222 -0.471860915422 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.762283980846 0.367579370737 -0.532736837864 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.720319032669 0.613522648811 -0.323620855808 -vn 0.833127021790 0.499868392944 -0.236708581448 -vn 0.846919417381 0.311212152243 -0.431131660938 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.196437984705 0.667735934258 0.718011736870 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.706075668335 0.665737152100 0.241352871060 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.476979732513 0.530355632305 0.700866043568 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.200900077820 0.779989659786 0.592667937279 -vn 0.196437984705 0.667735934258 0.718011736870 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.476979732513 0.530355632305 0.700866043568 -vn -0.460308641195 0.432748824358 0.775141537189 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.796163260937 0.020412357524 0.604737460613 -vn -0.792952120304 -0.015133478679 0.609095990658 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.472495853901 -0.873955726624 0.113794088364 -vn -0.250959426165 -0.952669680119 -0.171580299735 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn -0.430559724569 -0.708580851555 -0.559045195580 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn -0.078519783914 -0.830581963062 -0.551333189011 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.094399817288 -0.468443334103 -0.878435850143 -vn 0.399592339993 -0.540018141270 -0.740747153759 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.699251949787 -0.040834713727 -0.713708102703 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.842043936253 -0.014386636205 -0.539217054844 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.915375590324 0.387467741966 -0.109344631433 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn 0.900250494480 0.354679793119 -0.252490162849 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.851737022400 0.522776246071 0.035341292620 -vn 0.723317623138 0.619894027710 0.304208874702 -vn 0.906766295433 0.409387618303 -0.100879304111 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn -0.616665720940 -0.782339334488 -0.087570220232 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.788612246513 -0.502828478813 0.353912740946 -vn -0.685466885567 -0.650259494781 0.327563315630 -vn -0.424148023129 -0.902120292187 -0.079230606556 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.911147356033 -0.255800306797 0.323073804379 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.826433897018 -0.245585113764 0.506650686264 -vn 0.949352085590 -0.135964304209 0.283274352551 -vn 0.957214355469 -0.286995112896 0.037074200809 -vn 0.388409644365 0.097376465797 0.916327297688 -vn 0.886226296425 0.257387071848 0.385168552399 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.388409644365 0.097376465797 0.916327297688 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.716518461704 -0.298295706511 0.630571901798 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.728796660900 -0.660439372063 -0.180763065815 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.860012650490 -0.378439724445 0.342288851738 -vn -0.658858060837 -0.689020693302 0.301921337843 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.631677627563 -0.756497323513 -0.169396430254 -vn -0.480001002550 -0.817916572094 -0.317193210125 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn -0.074344001710 -0.674611508846 -0.734419703484 -vn -0.066533669829 -0.595843851566 -0.800339519978 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.407755017281 -0.386306762695 -0.827346920967 -vn 0.481644779444 -0.286784321070 -0.828114151955 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.785199224949 -0.046839069575 -0.617469251156 -vn 0.803414165974 0.005024130922 -0.595399379730 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.849230527878 0.245510101318 0.467474341393 -vn 0.971741199493 0.187253728509 -0.143718585372 -vn 0.984765470028 0.141468495131 -0.101112186909 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.347463965416 -0.779532015324 0.521151185036 -vn -0.462024897337 -0.668333053589 0.582978487015 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.121289253235 -0.574827611446 0.809235513210 -vn -0.122824735940 -0.428479611874 0.895164430141 -vn 0.402302742004 -0.049480821937 0.914168536663 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.799090266228 0.180629134178 0.573435127735 -vn 0.890469372272 0.030705736950 0.454006016254 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.983807981014 0.074132882059 0.163175269961 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.614874482155 0.042262133211 0.787491738796 -vn 0.614874482155 0.042262133211 0.787491738796 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.096592143178 -0.040983092040 0.994479954243 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.637993156910 -0.174105063081 0.750101447105 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.933749496937 -0.230891004205 0.273498028517 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.903826475143 -0.356221497059 0.237073644996 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.930003046989 -0.311220437288 0.195540815592 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.886968255043 -0.360542476177 -0.288611203432 -vn -0.753570079803 -0.612610638142 -0.238412141800 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn -0.532093167305 -0.256158202887 -0.807006716728 -vn -0.325670957565 -0.585272669792 -0.742559313774 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.135324358940 -0.097970917821 -0.985945761204 -vn 0.246417284012 -0.373370826244 -0.894356071949 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn 0.952648162842 0.045603808016 -0.300635546446 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.920179307461 0.077894940972 -0.383669644594 -vn 0.660331547260 0.014505122788 -0.750834107399 -vn 0.720516026020 -0.153431087732 -0.676251113415 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.668597519398 -0.234984099865 0.705520927906 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.883964776993 -0.243255555630 0.399290591478 -vn -0.922570586205 -0.144029989839 0.357936978340 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.947189986706 -0.247276708484 -0.204170018435 -vn -0.987068951130 -0.001342023723 -0.160290583968 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.519403219223 -0.215743064880 -0.826846539974 -vn -0.609359264374 0.086500100791 -0.788161814213 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn -0.041514541954 -0.171664625406 -0.984280347824 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn -0.023929292336 0.121215716004 -0.992337703705 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.427678495646 -0.126462370157 -0.895040988922 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.495944917202 0.221249133348 -0.839694857597 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.915072023869 -0.104790523648 -0.389438182116 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.908574581146 0.206608444452 -0.363049775362 -vn 0.924159824848 0.201810598373 -0.324347227812 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.980115532875 0.048620678484 0.192378610373 -vn 0.988765597343 -0.019402373582 0.148209601641 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.799184441566 -0.119045473635 0.589179396629 -vn 0.794139862061 -0.172562643886 0.582721173763 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn 0.166234999895 -0.225214079022 0.960023224354 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.575514614582 -0.278533190489 0.768896758556 -vn -0.670065939426 -0.258720010519 0.695755422115 -vn 0.127896860242 -0.234220936894 0.963733851910 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.401186734438 -0.166196405888 0.900792956352 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.207664504647 -0.740456640720 0.639217793941 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.622594892979 -0.589945852757 -0.514139533043 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.803143441677 -0.424439013004 0.418105423450 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.870798230171 -0.274165362120 0.408097743988 -vn -0.929131925106 -0.287983894348 0.231903240085 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.674554347992 -0.159368902445 0.720817565918 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.606201291084 0.206537902355 0.768024802208 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.350814163685 -0.622514247894 0.699575185776 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.481114804745 0.476588666439 0.735793292522 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.696642994881 0.705350995064 -0.131028831005 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.466922909021 0.878792583942 -0.098521873355 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.441691637039 0.769754469395 0.460854202509 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.380355626345 0.915188968182 0.133262023330 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.531039237976 0.846361756325 -0.040854826570 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.754615128040 0.229811772704 0.614607691765 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.606201291084 0.206537902355 0.768024802208 -vn -0.661760091782 0.656048417091 0.362869143486 -vn -0.785454511642 0.548647284508 0.286439210176 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.849245250225 0.459349334240 0.260347217321 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.675730884075 0.170890003443 0.717066466808 -vn -0.831401288509 0.182725146413 0.524769842625 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn -0.628898859024 -0.167266234756 0.759281396866 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.820158123970 -0.257162839174 0.511085033417 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.717795908451 -0.106868870556 0.688002943993 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.014599231072 -0.289826303720 0.956967890263 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.213539779186 -0.735609531403 0.642868101597 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.313859432936 -0.946901202202 0.069788210094 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.148168861866 -0.965607345104 0.213654994965 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.000251441961 -0.942464411259 -0.334306448698 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.133523687720 -0.654319226742 -0.744337141514 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.178969815373 -0.036877691746 -0.983163177967 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.130780518055 0.699840128422 -0.702225208282 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.647320389748 0.685716152191 -0.332820743322 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.432985514402 0.861952602863 -0.263744652271 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.893545091152 0.419377058744 0.160312488675 -vn -0.835198342800 0.538639068604 -0.110958099365 -vn -0.734826862812 0.676068246365 -0.054416924715 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.854047775269 0.194880262017 0.482311189175 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.934815168381 0.101666234434 0.340271264315 -vn -0.899725437164 0.424019932747 0.103446580470 -vn -0.724321365356 0.630072712898 0.279940962791 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.491222590208 0.725237250328 0.482422292233 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.344457119703 0.228259548545 0.910629928112 -vn -0.442502230406 0.477027654648 0.759365797043 -vn -0.259154200554 0.634195923805 0.728446722031 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.105894960463 0.457142889500 0.883066594601 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn -0.066208049655 0.065464153886 0.995656013489 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.025139117613 -0.589855730534 0.807117223740 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.042927689850 -0.924748063087 0.378151118755 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.150387302041 -0.987316966057 -0.050880618393 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.331084758043 -0.787115514278 -0.520415246487 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.277171522379 -0.333621501923 -0.901039779186 -vn -0.422015488148 -0.481336265802 -0.768256664276 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.524348676205 -0.128817796707 -0.841703295708 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.121618598700 0.471150964499 -0.873627901077 -vn -0.492768824100 0.139666393399 -0.858878433704 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.486196488142 0.873833239079 -0.005337357987 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.513394534588 0.856354117393 0.055530793965 -vn -0.330983459949 0.883402228355 -0.331738591194 -vn -0.546669006348 0.650373995304 -0.527415037155 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.587025642395 0.370276719332 -0.719927787781 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.431260585785 0.846675992012 0.311695545912 -vn -0.605038166046 0.783646821976 -0.140806540847 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.352230370045 0.729819893837 -0.585915267467 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.363752692938 0.687420129776 -0.628599703312 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn -0.057436451316 0.584186136723 -0.809584856033 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.070003993809 0.410762041807 -0.909051120281 -vn -0.024612516165 0.484930634499 -0.874206185341 -vn 0.203552156687 0.187401816249 -0.960961520672 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.200884222984 0.281286299229 -0.938362181187 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.508846163750 -0.197130560875 -0.837982773781 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.789647102356 -0.514648020267 -0.334058165550 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.642632007599 -0.639336526394 -0.422223776579 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.449879735708 -0.892520606518 -0.031862419099 -vn 0.616720378399 -0.787130177021 -0.009059753269 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.691674530506 -0.071475937963 -0.718663692474 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.380637049675 0.233202338219 -0.894836366177 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.015120597556 0.448562145233 -0.893623709679 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.008417923935 0.505917787552 -0.862540602684 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.305590540171 0.615349054337 -0.726608574390 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn -0.443666130304 0.852729022503 -0.275705635548 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.332030713558 0.934520363808 -0.128168955445 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.269882589579 0.768469750881 -0.580187559128 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.291657984257 0.089169785380 -0.952357292175 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.283972531557 0.357400029898 -0.889733016491 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.369570851326 -0.178360313177 -0.911923766136 -vn 0.195117399096 0.110545657575 -0.974530041218 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn 0.123270623386 -0.089006535709 -0.988373517990 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn 0.057102527469 -0.408684372902 -0.910887718201 -vn -0.248657748103 -0.389411330223 -0.886864244938 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.631206750870 -0.460801810026 -0.623890817165 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.918274998665 -0.334325522184 -0.212126120925 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.656991720200 -0.618542015553 0.431007683277 -vn -0.985950827599 -0.157788723707 -0.054805383086 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.972732365131 -0.190843746066 -0.131796970963 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.434074252844 -0.268963068724 0.859789729118 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.656465947628 -0.623428642750 0.424722492695 -vn -0.749023437500 -0.459609448910 0.477203339338 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.960145235062 -0.235651865602 -0.150297492743 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.866114735603 -0.318803369999 0.384980142117 -vn -0.994470536709 -0.003524448955 0.104957044125 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.521253764629 0.558969914913 0.644862115383 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.398872137070 0.415788918734 0.817325294018 -vn -0.732338190079 0.066023983061 0.677732706070 -vn -0.778450906277 0.365307867527 0.510455012321 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.757318496704 0.415668547153 0.503674864769 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.598532140255 0.585088372231 0.547202765942 -vn -0.525861024857 0.510891556740 0.680044114590 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.319124907255 0.778944134712 0.539819717407 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.372199684381 0.758454144001 0.534990429878 -vn -0.470349341631 0.716976583004 0.514505684376 -vn -0.444885224104 0.657462239265 0.608128726482 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.294267475605 0.736320257187 0.609293937683 -vn -0.329087138176 0.596190571785 0.732296705246 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.220259353518 0.493042349815 0.841662108898 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.217704832554 0.616207301617 0.756897091866 -vn -0.210031285882 0.676729142666 0.705637693405 -vn -0.141039162874 0.546767175198 0.825320303440 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.217961534858 0.368339926004 0.903780102730 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.192643001676 -0.043187834322 0.980318069458 -vn -0.208762139082 0.173094764352 0.962526142597 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.162622109056 0.413673579693 0.895783603191 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.401722431183 0.450534582138 0.797268867493 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.209707826376 -0.115715160966 0.970892667770 -vn -0.181194424629 0.227098539472 0.956867218018 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.628319561481 0.359209179878 0.690060377121 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.464984834194 0.282209694386 0.839134573936 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.587958753109 -0.088701777160 0.804012775421 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.944666683674 0.069445535541 0.320596575737 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.829526960850 0.006343629677 0.558430612087 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.886774122715 -0.348562031984 0.303539305925 -vn -0.978150129318 -0.207043349743 0.018851371482 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.928429484367 -0.330303490162 0.170053705573 -vn -0.972717821598 -0.214486360550 -0.088405892253 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.972956180573 -0.193811461329 -0.125671654940 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.959261178970 -0.266427934170 -0.093989863992 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.914136767387 -0.355888932943 -0.194157153368 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.882259726524 -0.411326795816 -0.228971764445 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.714386403561 -0.455613791943 -0.531100869179 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.661482095718 -0.585137486458 -0.469100773335 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.695248961449 -0.433017820120 -0.573693692684 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.290984004736 -0.442904204130 -0.848035514355 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn -0.326375365257 -0.544217050076 -0.772856354713 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.461035043001 -0.472170799971 -0.751333117485 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn -0.092966847122 -0.408933341503 -0.907816410065 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.029672866687 -0.456797748804 -0.889075577259 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.186271145940 -0.284139335155 -0.940514683723 -vn 0.333242952824 -0.351648002863 -0.874810159206 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.206165060401 -0.231415942311 -0.950758993626 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.227766945958 -0.113212391734 -0.967111766338 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.348777472973 0.110478848219 -0.930671095848 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.232259064913 0.042165666819 -0.971739590168 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.291348487139 0.287645339966 -0.912346541882 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.205909222364 0.252331405878 -0.945478856564 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.213274046779 0.473949223757 -0.854333817959 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn 0.150941848755 0.451750874519 -0.879282474518 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.053181022406 -0.359932571650 -0.931461393833 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.063421443105 -0.214829355478 -0.974590182304 -vn 0.393268018961 -0.069132164121 -0.916821122169 -vn 0.404777139425 -0.242898955941 -0.881564259529 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.220781981945 -0.310104668140 -0.924710988998 -vn 0.183340653777 -0.273737013340 -0.944168567657 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.179423063993 -0.188055112958 -0.965630710125 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn 0.057057879865 -0.261248350143 -0.963583767414 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.212149545550 -0.267020434141 -0.940049290657 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.123162224889 -0.212614715099 -0.969343125820 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.502373993397 -0.221697002649 -0.835745632648 -vn -0.530079066753 -0.134988084435 -0.837134659290 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.789869427681 -0.142434820533 -0.596505343914 -vn -0.840851187706 -0.088725514710 -0.533944845200 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.805913925171 -0.393099069595 0.442691624165 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.755450785160 -0.244421571493 0.607908070087 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.682558894157 -0.447725176811 0.577629208565 -vn -0.649566590786 -0.465607345104 0.601059973240 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.196055978537 -0.171053454280 0.965558290482 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.417664378881 -0.297151625156 0.858636915684 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.507497727871 -0.236813455820 0.828471779823 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.216913148761 -0.139054685831 0.966236233711 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.283693671227 -0.203705921769 0.937028169632 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.359831422567 -0.413703173399 0.836284041405 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.338521063328 -0.652876555920 0.677610278130 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.228975534439 -0.966663718224 0.114592753351 -vn -0.286758840084 -0.825533211231 0.486070215702 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn -0.060088019818 -0.817149162292 0.573285877705 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.080994680524 -0.984151780605 0.157750397921 -vn 0.422937929630 -0.871309041977 0.248885691166 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.437271595001 -0.449537754059 -0.778915524483 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.115275420249 -0.405100435019 -0.906975865364 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.608339726925 -0.334035158157 -0.719960570335 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.909568905830 -0.262379735708 -0.322244167328 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.968926668167 -0.157936230302 0.190361022949 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.565466403961 -0.060642685741 0.822538852692 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.149793371558 -0.171276986599 0.973769009113 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.100404962897 -0.010206341743 0.994894325733 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.696138083935 0.027712017298 0.717372834682 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.971542954445 0.190712869167 -0.140473663807 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.667801558971 0.397239923477 -0.629477202892 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn 0.020017268136 0.422390818596 -0.906192779541 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.607101559639 0.302661061287 -0.734727144241 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.903522908688 -0.324223697186 -0.280223727226 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.939108490944 -0.334201961756 0.079902052879 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.948065698147 -0.258092373610 0.185902506113 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.879063725471 -0.294311136007 0.375003933907 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.772708237171 -0.313344955444 0.552029848099 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.350002974272 -0.353424876928 0.867518723011 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn -0.108156479895 -0.424431473017 0.898977220058 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.522046148777 -0.307964920998 0.795377552509 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.855423569679 -0.287269592285 0.430960148573 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.965904176235 -0.249124884605 -0.070468947291 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.707191705704 -0.151784554124 -0.690536975861 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.514643490314 -0.262845516205 -0.816121518612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.155663013458 -0.127083465457 -0.979601383209 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.250461757183 -0.593217015266 0.765089869499 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn -0.521389782429 -0.343838661909 0.780978679657 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.715763926506 -0.212930619717 0.665088415146 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.465007245541 -0.425382465124 0.776413559914 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.145126968622 0.899781525135 -0.411498963833 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.134684994817 0.684974730015 -0.716009497643 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn -0.775885522366 0.616467952728 -0.134048074484 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.633557975292 0.763627767563 -0.124406084418 -vn -0.516845405102 0.745677411556 -0.420518726110 -vn -0.596450567245 0.676830708981 -0.431447476149 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.522606372833 -0.813196480274 0.256113231182 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.230195984244 -0.579904317856 0.781486272812 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.513534486294 0.648863255978 0.561479091644 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.513534486294 0.648863255978 0.561479091644 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn 0.137720257044 -0.872675478458 -0.468476980925 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn -0.555393755436 -0.827782988548 0.079454943538 -vn 0.323501050472 -0.885855317116 0.332576870918 -vn 0.652669608593 -0.757597029209 0.008313104510 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn 0.280668675900 -0.841036975384 -0.462473720312 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.123121000826 -0.448742777109 -0.885139048100 -vn 0.092088714242 -0.480216324329 -0.872302651405 -vn -0.043687757105 -0.877011001110 -0.478479951620 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.660521805286 0.480035573244 0.577301323414 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.632141351700 0.593008518219 0.498736590147 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.426534503698 0.658479154110 0.620059251785 -vn -0.405317097902 0.826308548450 0.391065508127 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.253316640854 0.715313494205 0.651273608208 -vn -0.354340136051 0.692856073380 0.628007590771 -vn -0.426534503698 0.658479154110 0.620059251785 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn 0.439630091190 -0.721156895161 0.535404622555 -vn 0.153458490968 -0.724150478840 0.672351539135 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn 0.052944108844 -0.525575459003 0.849097967148 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.194386199117 -0.316394358873 0.928498029709 -vn -0.327875584364 -0.123132228851 0.936662197113 -vn 0.005380727351 -0.466115295887 0.884707629681 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.183084383607 -0.301576018333 0.935698688030 -vn -0.183688417077 -0.212271973491 0.959791243076 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.442722022533 -0.331521779299 -0.833120942116 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.531822919846 -0.763270735741 -0.366854429245 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn 0.157262817025 -0.804923295975 -0.572159826756 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn -0.114131063223 -0.495763331652 -0.860925555229 -vn 0.238099992275 -0.110498450696 -0.964934468269 -vn 0.452441990376 -0.493693500757 -0.742672860622 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn -0.474601060152 -0.314127713442 0.822239398956 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.310935705900 -0.333749651909 0.889904558659 -vn -0.645000696182 -0.448348075151 0.618836104870 -vn -0.776939868927 -0.339007973671 0.530507385731 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.097222670913 -0.772586345673 0.627421736717 -vn -0.441064447165 -0.647433578968 0.621523916721 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.278138488531 -0.797384798527 0.535552501678 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn -0.282175540924 -0.623341798782 0.729261279106 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.148190066218 -0.888485610485 0.434319049120 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn -0.163589537144 -0.883762001991 0.438409894705 -vn 0.091035820544 -0.847606122494 0.522758364677 -vn 0.277552098036 -0.928275525570 0.247526556253 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn 0.080240480602 0.638880431652 -0.765109956264 -vn 0.103091351688 0.587236762047 -0.802823245525 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn -0.315204828978 0.861297667027 -0.398512542248 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.474705159664 0.698050916195 -0.536078274250 -vn -0.147046521306 0.661145508289 -0.735706388950 -vn -0.021746918559 0.684855461121 -0.728354394436 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.449752897024 0.215031251311 0.866881728172 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.220938414335 0.246594354510 0.943598151207 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.525134205818 0.469024330378 0.710105836391 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.518878757954 0.427382588387 0.740343809128 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.418460667133 0.901152551174 0.113202057779 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.331191927195 0.887251555920 -0.321086555719 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.199163094163 0.857034504414 -0.475211501122 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn 0.901155054569 0.207435190678 -0.380644440651 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.767984747887 -0.000124268874 -0.640468120575 -vn 0.632791161537 -0.770698904991 -0.074823580682 -vn 0.755004882813 -0.648362755775 -0.097945638001 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.887100934982 -0.301324844360 0.349650204182 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.094880104065 0.767824649811 -0.633595347404 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn 0.584740519524 -0.076099924743 -0.807643055916 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.512204766273 -0.850021958351 -0.122918345034 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.898592233658 0.382915318012 0.214261218905 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.070625789464 0.688678205013 -0.721619248390 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn -0.057959515601 0.724743604660 -0.686576604843 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn 0.469996184111 -0.136217668653 -0.872094213963 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.575490474701 -0.073232166469 -0.814523041248 -vn 0.609682977200 -0.792106568813 -0.029220450670 -vn 0.525191307068 -0.828523874283 -0.194222226739 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.571492850780 -0.022711342201 0.820292711258 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.853799223900 -0.515887677670 -0.069905407727 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.923558056355 0.181594893336 -0.337733328342 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.356608331203 0.911232411861 -0.206121206284 -vn -0.882203221321 0.466355353594 0.065039306879 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.526116251945 0.837725043297 0.146350353956 -vn -0.669882655144 0.495309412479 0.553105592728 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.690679788589 -0.000778474496 0.723160266876 -vn -0.716297686100 -0.048545919359 0.696104109287 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.008410177194 -0.786310911179 0.617773711681 -vn -0.356729805470 -0.570918679237 0.739456355572 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn 0.281914830208 -0.912322878838 0.296969711781 -vn -0.359494030476 -0.823143482208 0.439543902874 -vn -0.452860146761 -0.891462624073 -0.014562929980 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.840265870094 -0.241866633296 0.485235869884 -vn -0.784745812416 -0.252164989710 0.566203892231 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.686430990696 0.720295071602 -0.099937297404 -vn -0.898592233658 0.382915318012 0.214261218905 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.342781454325 0.907233953476 -0.243777379394 -vn -0.650007605553 0.666634500027 0.364813089371 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.418460667133 0.901152551174 0.113202057779 -vn -0.313529968262 0.702443897724 0.638961255550 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.300787478685 0.223077714443 0.927234172821 -vn -0.291609972715 0.196503594518 0.936135649681 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.193445131183 -0.664700031281 0.721632063389 -vn 0.027322886512 -0.366461753845 0.930031836033 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn -0.071583420038 -0.882299423218 0.465213447809 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn 0.251126438379 -0.872303128242 0.419550597668 -vn -0.134772136807 -0.627485811710 0.766875505447 -vn -0.489775359631 -0.690809249878 0.531885921955 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.059762805700 0.789890289307 -0.610329151154 -vn 0.442690938711 0.830069482327 -0.339130282402 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn 0.939903497696 0.263156682253 -0.217554569244 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.872482240200 -0.471308529377 0.129007905722 -vn 0.654265940189 -0.755983114243 0.020631497726 -vn 0.717394471169 0.009258572012 -0.696605682373 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.671369910240 -0.501542747021 0.545634746552 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.582837760448 0.017110457644 0.812408387661 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn 0.086628310382 -0.763483464718 0.639991044998 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.582837760448 0.017110457644 0.812408387661 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.519856750965 0.852639913559 -0.052479960024 -vn -0.750201165676 0.627852976322 0.207361668348 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.831779718399 0.422522366047 0.360024124384 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.211761444807 0.976250410080 -0.045741431415 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.563470244408 0.434554904699 0.702611804008 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn 0.477946668863 -0.420341253281 0.771284759045 -vn -0.007830149494 -0.295004695654 0.955463707447 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.347150862217 -0.614471793175 0.708456575871 -vn -0.434476226568 -0.280854701996 0.855775117874 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.686755061150 -0.134028151631 0.714425623417 -vn -0.577457189560 -0.013896662742 0.816302657127 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.750201165676 0.627852976322 0.207361668348 -vn -0.630089104176 0.398744553328 0.666326105595 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn 0.563470244408 0.434554904699 0.702611804008 -vn 0.072813071311 0.950119674206 0.303266942501 -vn 0.072813071311 0.950119674206 0.303266942501 -vn -0.131474196911 0.695336520672 0.706556200981 -vn -0.083546750247 0.307561278343 0.947853386402 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.595785379410 0.316492557526 0.738154590130 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.125691637397 0.965929806232 0.226232767105 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.103229515254 0.978088200092 0.180795833468 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.234835863113 0.898671209812 -0.370462059975 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.864156365395 0.421443611383 0.274989217520 -vn -0.103229515254 0.978088200092 0.180795833468 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn 0.795773029327 -0.568661808968 0.208252415061 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.560475468636 -0.384606152773 0.733447611332 -vn 0.864156365395 0.421443611383 0.274989217520 -vn 0.935081541538 0.343843042850 -0.085991114378 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.012428311631 -0.972527623177 0.232455551624 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.273491442204 -0.824210345745 0.495862573385 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.654169857502 0.611067593098 -0.445710867643 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.825740158558 0.557865142822 -0.083304390311 -vn -0.924543797970 -0.378240644932 0.046398065984 -vn -0.859294295311 -0.489033728838 -0.149864375591 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.188257768750 0.392298519611 0.900367081165 -vn 0.188257768750 0.392298519611 0.900367081165 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.544627487659 0.529230535030 0.650611937046 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.716074943542 0.144961029291 0.682805240154 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.429535895586 0.902928054333 0.014827483334 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.925961256027 0.377290695906 0.015729881823 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.314878374338 0.648127079010 -0.693385124207 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.183795481920 0.739516615868 -0.647560358047 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn 0.801216185093 -0.015416327864 -0.598176360130 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.800073266029 0.021300172433 -0.599524021149 -vn 0.750594854355 -0.659069657326 -0.047271598130 -vn 0.760725796223 -0.609730362892 -0.222542375326 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.779098629951 0.083139143884 0.621363997459 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.137644410133 0.679225027561 -0.720907330513 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn 0.779980123043 -0.012368889526 -0.625682055950 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.718797862530 -0.691185951233 0.074776910245 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.934488713741 0.355977147818 0.003339467803 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.157137870789 0.549231410027 -0.820763409138 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn -0.079140819609 0.539121925831 -0.838501214981 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn 0.555945277214 -0.210566222668 -0.804106175900 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.413201630116 -0.293350487947 -0.862096250057 -vn 0.575929820538 -0.817486464977 0.004545534495 -vn 0.615144014359 -0.778381824493 -0.125377655029 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.722877025604 0.172329545021 0.669142186642 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.929514527321 -0.149202257395 0.337255775928 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.925961256027 0.377290695906 0.015729881823 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.372731298208 0.847431004047 -0.378063619137 -vn -0.768828213215 0.621080696583 0.152190640569 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.584914922714 0.809603810310 -0.049154900014 -vn -0.600362479687 0.620171487331 0.504927933216 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.716074943542 0.144961029291 0.682805240154 -vn -0.614867448807 0.221208631992 0.756970763206 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn 0.050791967660 -0.655888438225 0.753147065639 -vn -0.303740888834 -0.252504259348 0.918685495853 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn 0.293518781662 -0.907126367092 0.301609754562 -vn -0.381968259811 -0.541032910347 0.749255359173 -vn -0.696559727192 -0.627136945724 0.348573863506 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.935787856579 -0.153255134821 0.317512065172 -vn -0.930642664433 -0.119538858533 0.345853626728 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.714753448963 0.639174342155 -0.283872634172 -vn -0.934488713741 0.355977147818 0.003339467803 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.337008565664 0.844721615314 -0.415777087212 -vn -0.714815974236 0.677176654339 0.174556314945 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.429535895586 0.902928054333 0.014827483334 -vn -0.356412112713 0.766799211502 0.533843994141 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.274307638407 0.453335881233 0.848081290722 -vn -0.396692723036 0.409319311380 0.821640193462 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn 0.217625066638 -0.362255036831 0.906317055225 -vn -0.104366108775 -0.074760586023 0.991725027561 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn -0.158099621534 -0.848514199257 0.505003094673 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn 0.242346301675 -0.785019755363 0.570098459721 -vn -0.339470773935 -0.405748128891 0.848603606224 -vn -0.702686250210 -0.592057228088 0.394588679075 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.053827662021 0.628712534904 -0.775772631168 -vn 0.483346670866 0.702270805836 -0.522677481174 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn 0.917047142982 0.207954093814 -0.340264052153 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.917628645897 -0.383898764849 0.102856516838 -vn 0.673219799995 -0.736139237881 0.069814592600 -vn 0.606436192989 -0.167024254799 -0.777391850948 -vn -0.364090979099 0.029598439112 0.930892944336 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.030472742394 0.502272367477 0.864172399044 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.048600327224 0.791139721870 0.609701573849 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.411388903856 0.236352607608 0.880282104015 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.720661699772 -0.320666521788 0.614670395851 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.441782504320 0.297333627939 0.846416532993 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn 0.181036546826 -0.475809484720 0.860715448856 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.441782504320 0.297333627939 0.846416532993 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.468466967344 0.873695731163 -0.131127700210 -vn -0.667333602905 0.709663510323 0.225928291678 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.845024704933 0.479537010193 0.236595571041 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.275201112032 0.942345619202 -0.190391898155 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.488979995251 -0.171528041363 0.855264127254 -vn 0.024463318288 -0.011137106456 0.999638676643 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.317777812481 -0.270505011082 0.908759772778 -vn -0.364090979099 0.029598439112 0.930892944336 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.505450129509 0.167936429381 0.846355438232 -vn -0.411388903856 0.236352607608 0.880282104015 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.184340089560 0.964558541775 0.188800379634 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.667333602905 0.709663510323 0.225928291678 -vn -0.491668075323 0.542922973633 0.680806279182 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.620835781097 0.549651503563 0.558968842030 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.184340089560 0.964558541775 0.188800379634 -vn 0.048600327224 0.791139721870 0.609701573849 -vn 0.030472742394 0.502272367477 0.864172399044 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.082621961832 0.478565484285 -0.874155998230 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn -0.143158808351 0.976085782051 -0.163591206074 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn 0.744623959064 -0.667047798634 -0.024132670835 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.552064001560 -0.510690867901 0.659105539322 -vn 0.845170021057 0.302865654230 -0.440408945084 -vn 0.633280694485 -0.109367601573 -0.766155540943 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.165316551924 -0.941744863987 0.292894333601 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn -0.732530832291 0.579060792923 -0.357892721891 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.869091689587 0.493450880051 -0.034437030554 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.948099553585 -0.283545225859 0.143907278776 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.221887230873 0.512353301048 0.829614460468 -vn 0.221887230873 0.512353301048 0.829614460468 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.675440192223 -0.458956182003 0.577182590961 -vn 0.706088304520 0.278354465961 0.651120662689 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn -0.084731951356 0.879110991955 -0.469024926424 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn -0.275824129581 0.797233998775 -0.536972105503 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn 0.678748965263 0.523606896400 -0.514913320541 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.665448784828 0.485600709915 -0.566894888878 -vn 0.937493324280 -0.345414757729 -0.042365852743 -vn 0.946458578110 -0.312835901976 -0.079685956240 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.746901273727 -0.482674479485 0.457344383001 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.964621126652 0.160373017192 0.209252431989 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn -0.335760802031 0.784725189209 -0.521028876305 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn 0.640085756779 0.425537496805 -0.639693737030 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.884581148624 -0.462744623423 -0.058168973774 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.945016801357 0.013837653212 0.326728969812 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn -0.229058310390 0.760169625282 -0.608008563519 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn -0.317595332861 0.768381953239 -0.555627942085 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn 0.490750640631 0.181577041745 -0.852169930935 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.499564975500 0.111929893494 -0.859014868736 -vn 0.793244004250 -0.584889531136 -0.169316813350 -vn 0.806491255760 -0.528655171394 -0.264755606651 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.551944792271 -0.293012142181 0.780705332756 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.713030219078 -0.700323402882 -0.033689942211 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.968837380409 -0.045421116054 -0.243497610092 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.685728549957 0.718560576439 -0.115961268544 -vn -0.964621126652 0.160373017192 0.209252431989 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.830990672112 0.493389964104 0.256945282221 -vn -0.788937568665 0.168626442552 0.590882897377 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.579639554024 -0.263481736183 0.771100103855 -vn -0.625793576241 -0.278895854950 0.728422582150 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn 0.247374296188 -0.749275922775 0.614322006702 -vn -0.162624269724 -0.590079188347 0.790796995163 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn 0.508111000061 -0.792860507965 0.336445242167 -vn -0.156016990542 -0.835193991661 0.527361035347 -vn -0.238086134195 -0.970914840698 -0.025286355987 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.698240220547 -0.517006635666 0.495141148567 -vn -0.674922764301 -0.523977279663 0.519545078278 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.926037192345 0.371895700693 0.064410530031 -vn -0.945016801357 0.013837653212 0.326728969812 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.732761621475 0.679454922676 0.037435822189 -vn -0.832083702087 0.208347573876 0.514031112194 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.683753192425 0.643162727356 0.344707518816 -vn -0.483903706074 0.389737546444 0.783544421196 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.438034206629 -0.038588356227 0.898129701614 -vn -0.407987475395 -0.052795879543 0.911459743977 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn 0.339785724878 -0.630825996399 0.697570264339 -vn -0.007603065576 -0.428264111280 0.903621613979 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.191624388099 -0.923793375492 0.331490367651 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn 0.465707689524 -0.822708785534 0.325985670090 -vn -0.092611193657 -0.674204349518 0.732715308666 -vn -0.364021629095 -0.856148600578 0.366739392281 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.067432902753 0.981908500195 0.176942050457 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn -0.757342994213 0.639263868332 0.133316561580 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.137136697769 0.888346493244 -0.438216865063 -vn 0.305667221546 0.945262253284 -0.114222683012 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn 0.873983740807 0.479939311743 -0.076227970421 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.971413433552 -0.198218494654 0.130634292960 -vn 0.840784430504 -0.537654459476 -0.063318446279 -vn 0.716986238956 0.239118993282 -0.654792249203 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.178718537092 0.188127040863 0.965747356415 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.689539670944 0.551088571548 0.469932347536 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.785614967346 -0.286049783230 0.548620700836 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn 0.307455629110 -0.716057658195 0.626683712006 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.601199984550 -0.264719158411 0.753977715969 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.757342994213 0.639263868332 0.133316561580 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.689539670944 0.551088571548 0.469932347536 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.067432902753 0.981908500195 0.176942050457 -vn -0.262828111649 0.784388482571 0.561832785606 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.376014262438 0.462822437286 0.802750706673 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.519195377827 -0.233764812350 0.822064578533 -vn 0.025394085795 -0.229523256421 0.972971856594 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.203189909458 -0.671831786633 0.712289214134 -vn -0.339134454727 -0.273717045784 0.900037109852 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.580693304539 -0.239784106612 0.778009533882 -vn -0.447011172771 -0.045240279287 0.893383622169 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.870019555092 0.264733344316 0.415911346674 -vn -0.581079006195 0.111400045455 0.806186854839 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.376014262438 0.462822437286 0.802750706673 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.262828111649 0.784388482571 0.561832785606 -vn -0.348185300827 0.396597862244 0.849398136139 -vn -0.178718537092 0.188127040863 0.965747356415 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.243232712150 0.967023551464 0.075520321727 -vn -0.115772135556 0.916144967079 -0.383764445782 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.842137992382 0.517580270767 0.151374444366 -vn -0.243232712150 0.967023551464 0.075520321727 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.847369909286 -0.431685984135 0.309211075306 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.818376600742 -0.401787668467 0.410884916782 -vn 0.842137992382 0.517580270767 0.151374444366 -vn 0.857951998711 0.502564668655 -0.106523200870 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn 0.210670322180 -0.966682791710 0.145404189825 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn 0.111688241363 -0.954437494278 0.276721477509 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.817223966122 0.438406974077 -0.374091386795 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.886659443378 0.442658960819 -0.133746445179 -vn -0.726776778698 -0.684764206409 -0.053791709244 -vn -0.639753162861 -0.691484153271 -0.335507929325 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.228585809469 0.971321880817 -0.065439939499 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.155846312642 0.291441172361 0.943808257580 -vn 0.525134205818 0.469024330378 0.710105836391 -vn 0.934458494186 0.322290331125 0.151381283998 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.547749757767 0.077166840434 0.833075940609 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.170828253031 0.950032889843 0.261256903410 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.338147550821 0.829213023186 -0.445041537285 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.098854996264 0.784844338894 -0.611757338047 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn 0.920910716057 0.206858113408 -0.330353140831 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.688472807407 0.029249710962 -0.724672079086 -vn 0.646868646145 -0.754471123219 -0.111059591174 -vn 0.785724759102 -0.618380904198 -0.015544304624 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.795008242130 -0.004372249823 0.606582820415 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn -0.047386102378 0.731830000877 -0.679837763309 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn 0.473639577627 -0.082474462688 -0.876848638058 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.421069711447 -0.883927404881 -0.203402578831 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.777829766273 0.488033413887 0.395985156298 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.001963527407 0.702904462814 -0.711281538010 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn -0.025579690933 0.776846170425 -0.629170656204 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn 0.276719152927 -0.113191716373 -0.954261064529 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.322021692991 -0.110789388418 -0.940227508545 -vn 0.412459701300 -0.882799863815 -0.224814176559 -vn 0.308892786503 -0.861497938633 -0.402996987104 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.326971471310 0.053588666022 0.943513572216 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.326971471310 0.053588666022 0.943513572216 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.035827055573 0.207518517971 0.977574825287 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.960114955902 -0.244047343731 0.136455714703 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.910519480705 0.385565638542 -0.149309948087 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.275407165289 0.928095698357 -0.250577956438 -vn -0.745011448860 0.632212758064 0.212755620480 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.470382779837 0.875310480595 0.112123101950 -vn -0.485284209251 0.621354460716 0.615156769753 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.547749757767 0.077166840434 0.833075940609 -vn -0.536564469337 0.119927458465 0.835293948650 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn 0.102821968496 -0.748076140881 0.655598759651 -vn -0.198560431600 -0.441530883312 0.874999582767 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn 0.306575775146 -0.907850980759 0.286038279533 -vn -0.384179323912 -0.683712661266 0.620437920094 -vn -0.647293269634 -0.752994298935 -0.118367962539 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.773331344128 -0.181563839316 0.607448101044 -vn -0.665392875671 -0.152734041214 0.730701446533 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.653835475445 0.756583929062 0.008939243853 -vn -0.777829766273 0.488033413887 0.395985156298 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.253899276257 0.958160519600 -0.132149979472 -vn -0.436078906059 0.732999444008 0.522060334682 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.001197829144 0.204163551331 0.978936076164 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.170828253031 0.950032889843 0.261256903410 -vn -0.050434809178 0.689648866653 0.722385466099 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.001197829144 0.204163551331 0.978936076164 -vn 0.035827055573 0.207518517971 0.977574825287 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.178257793188 -0.751887738705 0.634735345840 -vn 0.251319766045 -0.339376091957 0.906455874443 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn -0.068334780633 -0.860537767410 0.504782259464 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn 0.192031323910 -0.934470832348 0.299813717604 -vn -0.034413214773 -0.623692095280 0.780912220478 -vn -0.449355930090 -0.622634947300 0.640628576279 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn -0.337525874376 0.930810749531 0.140241369605 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.125956013799 0.815335929394 -0.565121591091 -vn 0.615988314152 0.720898389816 -0.317590743303 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn 0.924420893192 0.053604725748 -0.377587854862 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.760992348194 -0.645550906658 -0.064457304776 -vn 0.461613714695 -0.874826371670 -0.146940901875 -vn 0.556747496128 -0.079760462046 -0.826843678951 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.067655861378 0.094781979918 0.993196368217 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.004601359833 0.522861719131 0.852405130863 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.623558640480 -0.671979129314 0.399523109198 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.429289430380 0.010662646964 0.903104007244 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn 0.022328991443 -0.807272195816 0.589756786823 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.429289430380 0.010662646964 0.903104007244 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.423879355192 0.904768526554 0.041475951672 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.337525874376 0.930810749531 0.140241369605 -vn -0.590204536915 0.644762694836 0.485736191273 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.959200203419 0.162117242813 0.231631040573 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.423879355192 0.904768526554 0.041475951672 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.437515467405 -0.595975279808 0.673345148563 -vn 0.030373126268 -0.405382573605 0.913642406464 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.406600266695 -0.599074244499 0.689772665501 -vn -0.425275236368 -0.307458400726 0.851240456104 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.519624173641 -0.096402786672 0.848938882351 -vn -0.498360216618 -0.011345745064 0.866895854473 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.313855469227 0.815999209881 0.485427707434 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.590204536915 0.644762694836 0.485736191273 -vn -0.538786590099 0.230709373951 0.810235857964 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.736156404018 0.144710719585 0.661159992218 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.313855469227 0.815999209881 0.485427707434 -vn 0.004601359833 0.522861719131 0.852405130863 -vn 0.067655861378 0.094781979918 0.993196368217 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.285551220179 0.869218170643 -0.403633773327 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.274834781885 0.908923387527 -0.313566774130 -vn 0.952248871326 0.304680645466 0.019794657826 -vn 0.807383418083 -0.537694036961 0.242934510112 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.757777929306 -0.368886232376 0.538233757019 -vn 0.934458494186 0.322290331125 0.151381283998 -vn 0.952248871326 0.304680645466 0.019794657826 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.061535436660 -0.933928251266 0.352124094963 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.253473311663 -0.772156655788 0.582688093185 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.623009026051 0.664530754089 -0.412624120712 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.581666529179 0.743011713028 -0.331055343151 -vn -0.996103525162 -0.017238132656 0.086490817368 -vn -0.945911884308 -0.323958635330 -0.017364645377 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.807789504528 -0.443095922470 -0.388770043850 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.728950142860 -0.327087074518 -0.601369857788 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.618258059025 0.073811292648 -0.782501697540 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.458354860544 0.598978698254 -0.656608939171 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.979369640350 0.134773358703 -0.150569871068 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.495899587870 0.820320844650 -0.284881204367 -vn -0.776327371597 0.532938063145 -0.336589962244 -vn -0.890372574329 0.080532528460 -0.448052674532 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.711501002312 -0.684330821037 -0.159554719925 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.706272184849 -0.603011190891 -0.370887011290 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.723380565643 -0.383380830288 -0.574229657650 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.775762677193 -0.188441053033 -0.602231025696 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.906276762486 -0.404754072428 -0.121805310249 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.984793066978 -0.172015860677 -0.024353824556 -vn -0.909171402454 -0.153872847557 -0.386950284243 -vn -0.845550715923 -0.427685022354 -0.319577127695 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.796449840069 -0.575604200363 -0.185330703855 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.701268851757 -0.693833172321 -0.163760513067 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.670601308346 -0.706431031227 -0.226382493973 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.706466317177 -0.613281667233 -0.353257507086 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.893056094646 -0.445511609316 0.063009694219 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.788561046124 -0.477070689201 -0.388040006161 -vn -0.888054728508 -0.403473645449 -0.220381125808 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn 0.103919081390 -0.905755519867 0.410862177610 -vn -0.228597149253 -0.963452041149 0.139655098319 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.064416959882 -0.989249408245 -0.131286263466 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.400125116110 -0.844774186611 -0.355325788260 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.656732261181 -0.623147845268 -0.424722850323 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.667753398418 -0.732233583927 0.133938133717 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.846791744232 -0.483428299427 -0.221902847290 -vn -0.638963222504 -0.764738500118 -0.083072558045 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn -0.899286210537 -0.416854232550 0.132351279259 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.858372688293 -0.511320352554 -0.041807256639 -vn -0.884231448174 -0.461644798517 0.070843711495 -vn -0.298239111900 -0.830386161804 0.470650851727 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.343221575022 0.333233237267 0.878154039383 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.449752897024 0.215031251311 0.866881728172 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.518878757954 0.427382588387 0.740343809128 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.714198350906 -0.144104629755 -0.684948563576 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.765450656414 0.598935127258 0.235291317105 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.720277249813 0.069460451603 0.690199911594 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.554942369461 0.176653087139 0.812916159630 -vn -0.554942369461 0.176653087139 0.812916159630 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.301544338465 0.953448176384 0.002751463326 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn -0.476167112589 -0.808386087418 0.346087813377 -vn -0.621210396290 -0.516742289066 0.589130699635 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.998421430588 -0.004686263390 0.055970139802 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.509444832802 0.780633270741 -0.362046450377 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.504871308804 -0.590458869934 0.629653275013 -vn 0.162469699979 -0.467619746923 0.868870139122 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.613426685333 0.657508313656 -0.437481969595 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.896798372269 0.441279530525 -0.032017208636 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.720277249813 0.069460451603 0.690199911594 -vn 0.807750463486 0.575951337814 0.125774711370 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.826578557491 0.386441767216 0.409182965755 -vn 0.581056177616 0.793762326241 0.179764077067 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.301544338465 0.953448176384 0.002751463326 -vn 0.369211822748 0.922699332237 -0.110943920910 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.646847009659 0.741001725197 -0.180292502046 -vn -0.184017047286 0.939944207668 -0.287476360798 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.099195800722 0.803823649883 -0.586538732052 -vn 0.254744201899 0.720660746098 -0.644789516926 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.573264300823 -0.621842443943 0.533554136753 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852300584316 -0.522522985935 -0.023525990546 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn -0.002327257767 -0.462118774652 0.886815011501 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.793979823589 0.261099308729 0.549020230770 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.340674638748 -0.929889678955 0.138729795814 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.937267899513 -0.270961970091 -0.219336494803 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.513688981533 -0.684592545033 0.517162144184 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn -0.363146990538 -0.909030199051 0.204422011971 -vn -0.272706478834 -0.959422051907 0.071697592735 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.825297355652 -0.437561929226 -0.356964796782 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.852417647839 -0.424412041903 -0.305382728577 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn 0.229095175862 0.971845209599 0.055066000670 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.298334419727 0.949311316013 0.099018156528 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.229095175862 0.971845209599 0.055066000670 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.388242930174 -0.640620768070 0.662474453449 -vn 0.441654533148 -0.722736120224 0.531595468521 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.444323122501 0.850608170033 -0.281145304441 -vn 0.434042304754 0.843485772610 -0.316447526217 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.933602452278 0.183274835348 0.307890951633 -vn 0.816090106964 0.577879071236 -0.007257726509 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.855770230293 -0.002302488778 0.517350971699 -vn 0.668103694916 0.661955296993 0.339783221483 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.510277152061 0.789386153221 0.341301500797 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.038500741124 0.970658123493 0.237361595035 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.298334419727 0.949311316013 0.099018156528 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.593913555145 0.612360298634 -0.521806061268 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.806880056858 0.269844979048 -0.525479078293 -vn -0.333856552839 0.903271317482 -0.269519507885 -vn 0.002065459266 0.795183241367 -0.606365740299 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.984832644463 0.126232400537 -0.119038090110 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.195449680090 0.978367269039 0.067800879478 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.740837633610 0.595236599445 -0.311212152243 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.195449680090 0.978367269039 0.067800879478 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.793979823589 0.261099308729 0.549020230770 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.735706865788 -0.054184451699 0.675129234791 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.152383819222 -0.058323230594 0.986598968506 -vn 0.117484591901 0.535072982311 0.836596846581 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.580564439297 0.618157505989 0.529930353165 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.702350616455 0.688323199749 -0.181424275041 -vn -0.101965256035 0.950193762779 -0.294507831335 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn -0.273582547903 0.913477420807 -0.301183640957 -vn 0.032985683531 0.980769813061 -0.192360520363 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.309013634920 0.944480478764 -0.111656844616 -vn 0.167077019811 0.982238590717 -0.085397034883 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.646426260471 0.607408761978 0.461722522974 -vn 0.360706925392 0.930654346943 -0.061424735934 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn -0.580564439297 0.618157505989 0.529930353165 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.117484591901 0.535072982311 0.836596846581 -vn 0.187485709786 0.938560783863 0.289746075869 -vn -0.005631436128 0.999072909355 0.042680554092 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.222899302840 -0.961414158344 0.161241352558 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.278032571077 -0.915405213833 -0.291086286306 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.605843842030 -0.687134027481 -0.400998830795 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.631184875965 -0.605723857880 -0.484462857246 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.644962370396 0.058819733560 -0.761947333813 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.717515647411 -0.506692528725 -0.477947682142 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.685438394547 -0.309446930885 -0.659103035927 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.529830276966 0.180707767606 -0.828628122807 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.659071147442 -0.200914278626 -0.724747300148 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.101169690490 0.512140154839 0.852922737598 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn 0.125691637397 0.965929806232 0.226232767105 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn -0.179032042623 0.870336353779 -0.458761513233 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.496197491884 0.338221609592 -0.799621284008 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.408649384975 0.500134229660 -0.763460159302 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.674920856953 0.632537782192 -0.379970818758 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.707616925240 0.585469484329 -0.395605623722 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.939780056477 0.338753521442 0.045381970704 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.857936024666 -0.122563391924 0.498922824860 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.371329933405 -0.353956162930 0.858387529850 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn 0.075631655753 -0.076423481107 0.994202852249 -vn -0.078894823790 0.316832482815 0.945194602013 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn 0.071874260902 0.922927081585 0.378205835819 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.581009745598 0.524481356144 -0.622372090816 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.284967243671 0.950918138027 -0.120616540313 -vn -0.383206188679 0.894132435322 0.231689810753 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn 0.192059397697 0.733371317387 -0.652134716511 -vn -0.148294940591 0.763890028000 0.628076970577 -vn 0.071874260902 0.922927081585 0.378205835819 -vn 0.105647958815 0.477384954691 0.872319936752 -vn 0.105647958815 0.477384954691 0.872319936752 -vn -0.078894823790 0.316832482815 0.945194602013 -vn -0.148294940591 0.763890028000 0.628076970577 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.299237340689 0.679699480534 -0.669675767422 -vn -0.577740788460 0.755005121231 -0.310133606195 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.716520488262 0.652290821075 -0.247214660048 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.668927371502 0.054616473615 0.741318523884 -vn 0.575854957104 -0.556808650494 0.598627746105 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.259312212467 -0.961311340332 0.092938996851 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.586589038372 -0.130760043859 0.799259126186 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.542366027832 -0.667315959930 0.510419964790 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.067944653332 -0.146262273192 0.986909747124 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.220938414335 0.246594354510 0.943598151207 -vn 0.371117204428 0.216821014881 0.902917861938 -vn 0.235978275537 -0.027912126854 0.971357405186 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.381070137024 0.377225160599 0.844089269638 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.447196930647 0.457334220409 0.768674373627 -vn 0.343221575022 0.333233237267 0.878154039383 -vn 0.298508673906 0.235164701939 0.924981176853 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.386256456375 0.060981024057 0.920373439789 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.792960882187 -0.082992456853 0.603593647480 -vn 0.389172941446 -0.187152817845 0.901952445507 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.406082540751 -0.913307428360 0.031089453027 -vn 0.616677582264 -0.787093162537 0.013895100914 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.636817932129 -0.665135920048 0.389945089817 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.764927029610 -0.576102018356 0.288085192442 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.651197373867 -0.295929104090 0.698833286762 -vn 0.819841921329 -0.267875581980 0.506065070629 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.484686046839 0.057347863913 0.872806191444 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.722315967083 0.014853472821 0.691403687000 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.412116557360 0.192709788680 0.890518307686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.685664176941 0.024288894609 0.727512657642 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.709150254726 0.064871802926 0.702066600323 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.749943137169 -0.607590794563 0.261569708586 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.833654463291 -0.165826693177 0.526803314686 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.777859270573 0.059331193566 0.625631511211 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.856723487377 0.313828945160 0.409311980009 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.565619111061 0.815543174744 -0.122328855097 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn -0.000058030513 0.758348703384 -0.651849091053 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.334304481745 0.357836514711 -0.871890783310 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.556180357933 -0.108734130859 -0.823917686939 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.412349730730 -0.020164160058 -0.910802423954 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.541802704334 -0.795597314835 0.271062254906 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.684188246727 -0.314334392548 0.658088386059 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.612721860409 0.027013452724 0.789836823940 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.523797929287 0.432407170534 0.733934402466 -vn 0.260491907597 0.307280063629 0.915272057056 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.330873250961 0.872498035431 0.359541505575 -vn 0.162017181516 0.796604990959 0.582383811474 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn 0.014589162543 0.951842546463 -0.306240051985 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.328589290380 0.516683042049 -0.790612220764 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394009530544 -0.007915191352 -0.919072270393 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn 0.710684239864 -0.017598621547 0.703290998936 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.868372321129 0.207240670919 0.450533896685 -vn 0.067035764456 -0.147402390838 0.986802279949 -vn 0.283248275518 -0.164805412292 0.944780170918 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.941432178020 0.205026820302 0.267711549997 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.765450656414 0.598935127258 0.235291317105 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.044693116099 0.737179398537 -0.674217343330 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.462693333626 0.681148767471 -0.567407488823 -vn -0.791678369045 0.572285056114 -0.213857769966 -vn -0.653196692467 0.687323570251 -0.317679673433 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.000500970287 0.150257885456 0.988646686077 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.094890594482 0.167634546757 0.981271862984 -vn -0.000500970287 0.150257885456 0.988646686077 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.020890446380 0.525199234486 0.850722849369 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.203145816922 0.789853513241 0.578673660755 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.494061529636 0.865195631981 0.085671991110 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.718650877476 0.596940636635 -0.356655031443 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.131719857454 -0.939497470856 -0.316218942404 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn 0.054139081389 -0.946674823761 -0.317609339952 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.417767822742 -0.763937056065 -0.491803050041 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.633862555027 -0.426885992289 -0.644970238209 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.564986348152 -0.593238472939 -0.573461830616 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.260545551777 -0.813256382942 -0.520317316055 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn 0.388792097569 -0.902842164040 -0.183621153235 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn 0.194966942072 -0.890786707401 -0.410471647978 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn 0.042187642306 -0.766220450401 -0.641191422939 -vn -0.072411671281 -0.856675744057 -0.510747730732 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.236149817705 -0.424875795841 -0.873907208443 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.074641257524 -0.569141447544 -0.818844735622 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.530624270439 -0.375058025122 -0.760111391544 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.357876986265 -0.306289374828 -0.882105946541 -vn -0.314885556698 -0.595676243305 -0.738929569721 -vn -0.444026708603 -0.606746494770 -0.659317076206 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.495413959026 0.088413864374 -0.864145815372 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.518924534321 0.789362072945 -0.328062266111 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.403777748346 0.675936877728 -0.616500496864 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.212111368775 0.931484699249 0.295541882515 -vn 0.033992055804 0.651784360409 0.757642209530 -vn -0.212111368775 0.931484699249 0.295541882515 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn -0.057846810669 0.996845066547 -0.054347090423 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.033992055804 0.651784360409 0.757642209530 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.162017181516 0.796604990959 0.582383811474 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.217132925987 -0.699617862701 0.680726230145 -vn 0.345870345831 -0.507937014103 0.788906633854 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn 0.194033831358 -0.975260198116 0.105917148292 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn 0.148078888655 -0.966142833233 0.211283400655 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.161389231682 -0.826426625252 -0.539418697357 -vn -0.095659404993 -0.891003251076 -0.443804621696 -vn -0.394770026207 -0.408056885004 -0.823192656040 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.722775518894 0.127099156380 -0.679294764996 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.558745026588 -0.260360956192 -0.787411093712 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.322938174009 -0.703057765961 -0.633577704430 -vn -0.371036648750 -0.578186392784 -0.726658284664 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.135474219918 -0.988358557224 -0.069239638746 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.166938528419 -0.919655323029 -0.355479389429 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.211538925767 -0.861231863499 0.462094068527 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.106166861951 -0.985075116158 0.135482907295 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn 0.020051987842 -0.112118013203 0.993492543697 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn 0.079771168530 -0.496181964874 0.864546120167 -vn -0.042744558305 -0.808862030506 0.586442768574 -vn 0.043110653758 -0.307953089476 0.950424313545 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn -0.638447046280 0.245981469750 -0.729299962521 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.649896085262 -0.004399633035 -0.760010361671 -vn -0.535104215145 -0.309753090143 -0.785949409008 -vn -0.451521098614 -0.345670461655 -0.822581708431 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn 0.094890594482 0.167634546757 0.981271862984 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.260491907597 0.307280063629 0.915272057056 -vn 0.289737731218 -0.101735204458 0.951683759689 -vn 0.129637911916 -0.209326177835 0.969214379787 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.977375864983 -0.182302713394 -0.107247889042 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.932448983192 -0.323441475630 0.161010980606 -vn -0.933986306190 -0.356039702892 -0.030087741092 -vn -0.863622725010 -0.395356804132 -0.312807887793 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.953337550163 -0.167185232043 0.251389354467 -vn -0.551249742508 -0.140232846141 0.822470963001 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.707793414593 -0.092283651233 0.700365781784 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.771496355534 -0.520169913769 0.366355866194 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.921395957470 -0.096049144864 0.376568794250 -vn 0.915147721767 -0.341821610928 -0.213688179851 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.843312978745 -0.508717417717 -0.173291251063 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.635089933872 -0.717878699303 -0.285150736570 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn 0.376745164394 -0.480174839497 -0.792145967484 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn 0.338396072388 -0.505504190922 -0.793696165085 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.128155156970 -0.402803808451 -0.906270027161 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.141834318638 -0.356789201498 -0.923355042934 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.617432177067 -0.286321341991 -0.732664763927 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.587534666061 -0.195610851049 -0.785200238228 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.925773084164 -0.217750370502 -0.309077620506 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.942502677441 -0.131082609296 0.307418376207 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.916307866573 -0.152069538832 -0.370479047298 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn 0.478567808867 -0.553991734982 0.681223928928 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn 0.200163364410 -0.734465181828 0.648456275463 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.019374400377 -0.340837627649 0.939922511578 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.175170764327 -0.422769248486 0.889146447182 -vn -0.563060462475 -0.168180093169 0.809121966362 -vn -0.551818788052 -0.097078174353 0.828294575214 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.922188758850 -0.076360240579 0.379126608372 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.790964484215 -0.047528445721 0.610013246536 -vn -0.809697628021 -0.208559572697 0.548536777496 -vn -0.989886045456 -0.102725066245 0.097842380404 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.969465434551 -0.233353525400 0.075384795666 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.657921433449 -0.251068294048 0.710002899170 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn 0.022503187880 -0.168173655868 0.985500514507 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.626895606518 -0.109646342695 0.771349191666 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.955945372581 -0.075195699930 0.283750057220 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.965460717678 -0.065064646304 0.252293825150 -vn 0.976103127003 -0.056135118008 0.209932267666 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.959917187691 -0.043896026909 -0.276825070381 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.916344642639 -0.289950251579 -0.276118308306 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn 0.639318466187 0.016674445942 -0.768761277199 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn 0.527624547482 -0.341483384371 -0.777818381786 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.015542259440 -0.012424598448 -0.999801993370 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.065956912935 -0.328755855560 -0.942108929157 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn -0.593472301960 -0.092204272747 -0.799555480480 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.886553704739 -0.150430575013 -0.437485098839 -vn -0.891806840897 -0.253316342831 -0.374848484993 -vn -0.597554683685 -0.308073014021 -0.740283310413 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.603337705135 -0.321985483170 0.729595065117 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.918845653534 -0.108316130936 0.379460453987 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.863250315189 -0.240368023515 0.443871766329 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.980078399181 0.178462892771 -0.087162509561 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.981968581676 -0.106181085110 -0.156407564878 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.636526405811 0.364853173494 -0.679497122765 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.628715753555 0.022276135162 -0.777316093445 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.084422126412 0.381982415915 -0.920305550098 -vn 0.163179978728 0.071530185640 -0.983999848366 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.477106243372 0.354926079512 -0.803988277912 -vn -0.362230628729 0.031117305160 -0.931568920612 -vn -0.891922414303 -0.121970690787 -0.435428053141 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.924370706081 0.140413299203 -0.354715228081 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.938400447369 0.027688471600 -0.344438642263 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.971519231796 -0.181915670633 0.151845633984 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.956004738808 -0.284389942884 0.071953646839 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.779256761074 -0.415031522512 0.469582498074 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.763228416443 -0.461620450020 0.452093988657 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.652728021145 -0.370803534985 0.660644292831 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn 0.580956161022 -0.315899401903 0.750131666660 -vn -0.181248873472 -0.456907838583 0.870852470398 -vn -0.141817405820 -0.538776338100 0.830426335335 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.608893454075 0.235913068056 0.757359743118 -vn 0.593855559826 0.019980316982 0.804323554039 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn 0.113157883286 -0.147927060723 0.982503354549 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.466343373060 -0.015833530575 0.884462058544 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn 0.300583481789 -0.145427584648 0.942602992058 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.376915872097 0.132242649794 0.916758596897 -vn 0.066894985735 -0.120529606938 0.990453243256 -vn -0.088382758200 -0.339686036110 0.936376988888 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.656117200851 -0.752742469311 0.053749088198 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.321534842253 -0.887416303158 0.330314517021 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.965605020523 0.107465490699 0.236765861511 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.068652406335 0.974390566349 0.214125752449 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.961623728275 0.054777454585 0.268847882748 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.400886356831 0.901594340801 0.162535563111 -vn 0.442601650953 0.886409521103 0.135580167174 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.979799330235 0.116351984441 -0.162651434541 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.068652406335 0.974390566349 0.214125752449 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.147310256958 0.958264529705 0.245007723570 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.932176113129 -0.021262366325 -0.361380100250 -vn -0.938433587551 -0.109255589545 -0.327727943659 -vn -0.716325759888 0.585582971573 0.379433780909 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.680016100407 0.152828097343 0.717092514038 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717058062553 0.043724697083 0.695640623569 -vn 0.717947840691 -0.072925940156 0.692266345024 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.264956355095 -0.115032657981 0.957374334335 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn 0.296417653561 -0.129989758134 0.946170806885 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.965605020523 0.107465490699 0.236765861511 -vn 0.966316044331 0.170746937394 0.192558467388 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.951884567738 0.018304115161 -0.305909752846 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.611862540245 -0.209730833769 -0.762651443481 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.925466060638 -0.019112786278 -0.378348082304 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.463319748640 -0.284106910229 -0.839415311813 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.873224854469 0.040406849235 -0.485639452934 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.930489718914 -0.261996328831 -0.256021112204 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.933810532093 -0.240890204906 -0.264518111944 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.217509955168 -0.925485610962 0.310106158257 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.421064645052 -0.893715202808 0.154847532511 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.967172682285 0.241761222482 0.078284777701 -vn 0.634496629238 0.241281628609 0.734300494194 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.967172682285 0.241761222482 0.078284777701 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn -0.344990402460 -0.115646079183 -0.931454539299 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.279096722603 -0.206124126911 -0.937879443169 -vn -0.255546450615 -0.236742943525 -0.937362670898 -vn -0.333036005497 -0.132622703910 -0.933540701866 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn 0.385443925858 0.300371497869 -0.872473478317 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.316477656364 0.365814924240 -0.875226438046 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999865949154 -0.007872974500 -0.014355270192 -vn -0.999982237816 -0.005035636947 0.003187689232 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.817613303661 0.347829401493 0.458828032017 -vn -0.836668133736 0.327173054218 0.439254164696 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.817613303661 0.347829401493 0.458828032017 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.208270162344 -0.874368071556 0.438296735287 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.201453700662 -0.832577824593 0.515975356102 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn -0.143444925547 -0.679574370384 -0.719445765018 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.399136632681 -0.109241187572 -0.910360515118 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.238736808300 0.966642439365 -0.092774368823 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.191518172622 0.977899730206 0.083862185478 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.221692368388 0.969382524490 -0.105593815446 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.825137555599 -0.039393767715 -0.563556671143 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.800368309021 -0.110980175436 -0.589146792889 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.368902295828 -0.176557660103 -0.912545084953 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.036762826145 -0.407817989588 -0.912322878838 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn -0.018286168575 -0.241975441575 -0.970110058784 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn -0.066875919700 -0.211223438382 -0.975147306919 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.143724322319 -0.430487692356 -0.891080081463 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.233708530664 -0.381010770798 -0.894545197487 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.162009149790 -0.252556264400 -0.953922629356 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.158448517323 -0.275207310915 -0.948237836361 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.131967604160 0.986462950706 -0.097341716290 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.049535784870 0.983003556728 -0.176777198911 -vn 0.078429423273 0.979791224003 -0.184005334973 -vn -0.131907835603 0.985628366470 -0.105532377958 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.057303033769 -0.768139362335 -0.637713313103 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn 0.624225676060 -0.733383476734 -0.269241482019 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.683579862118 -0.686875283718 -0.246821716428 -vn 0.913559436798 -0.390938848257 -0.112142503262 -vn 0.882891595364 -0.448917657137 -0.137750983238 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.426549911499 0.661332190037 -0.617004811764 -vn -0.434841871262 0.650471568108 -0.622735321522 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.299304544926 0.655579268932 -0.693276703358 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.203423932195 0.523596465588 -0.827324271202 -vn -0.206277325749 0.496593266726 -0.843116104603 -vn -0.299391537905 0.646304905415 -0.701893627644 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.735097944736 -0.411521434784 -0.538777410984 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.167258366942 -0.947917759418 0.271065652370 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn 0.015772189945 -0.661784946918 0.749527812004 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.919971227646 -0.315933138132 -0.232032716274 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.275574177504 0.178359404206 0.944588184357 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.309776514769 0.123586989939 0.942743241787 -vn -0.318132579327 0.109800979495 0.941666305065 -vn -0.283012300730 0.166665807366 0.944524526596 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.864802479744 0.500968754292 0.033867362887 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.670427143574 0.731589615345 0.123709522188 -vn -0.609832704067 0.779186606407 0.144818082452 -vn -0.820068120956 0.569231271744 0.058856066316 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.711521089077 -0.668513596058 0.216396108270 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.133838012815 -0.990629673004 0.027208203450 -vn -0.441047191620 -0.897233605385 0.021195763722 -vn 0.676929712296 0.735970973969 0.010624704883 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.730528593063 0.682668983936 0.017058826983 -vn 0.676929712296 0.735970973969 0.010624704883 -vn -0.394177705050 0.541026473045 0.742909312248 -vn -0.393941193819 0.551313161850 0.735434651375 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.066927298903 0.552506208420 0.830817461014 -vn -0.067695811391 0.526292204857 0.847604751587 -vn -0.394177705050 0.541026473045 0.742909312248 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn 0.265394568443 0.762436449528 -0.590132534504 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.258136868477 0.673559129238 -0.692591845989 -vn 0.498349219561 0.832625806332 -0.241624265909 -vn 0.462099343538 0.855638921261 -0.233122825623 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.652370274067 -0.700718224049 -0.288802653551 -vn 0.452018469572 -0.883442044258 -0.123326830566 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.222474575043 -0.822602808475 0.523287415504 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn 0.030194981024 -0.298345863819 0.953980088234 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn 0.146515324712 -0.276555955410 0.949763178825 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.334040522575 -0.736586928368 0.588095724583 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.202640861273 -0.541228234768 0.816093564034 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.281598299742 -0.578111886978 0.765825748444 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.052583612502 0.985693454742 0.160135433078 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.026022652164 0.988108336926 0.151541069150 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn 0.262357443571 0.201877102256 -0.943617641926 -vn 0.265916287899 0.192993134260 -0.944479823112 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.041227888316 0.133673071861 -0.990167558193 -vn -0.020402621478 0.125429570675 -0.991892695427 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn -0.333152711391 0.173149183393 -0.926837980747 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.684160232544 -0.015572587028 -0.729165434837 -vn -0.655080139637 -0.018082045019 -0.755343019962 -vn -0.336778044701 0.156496420503 -0.928487718105 -vn 0.116307489574 0.990462958813 0.073862694204 -vn -0.048381622881 0.989867806435 0.133495286107 -vn -0.040402501822 0.989431560040 0.139258161187 -vn -0.040402501822 0.989431560040 0.139258161187 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.116307489574 0.990462958813 0.073862694204 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.147966638207 0.985058844090 0.088119089603 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.233582735062 0.960899651051 0.148697659373 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.228807210922 0.964297473431 0.133332878351 -vn 0.134896829724 0.973662376404 0.183805242181 -vn 0.052583612502 0.985693454742 0.160135433078 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.043970555067 0.986248075962 0.159315317869 -vn 0.133777290583 0.972870230675 0.188751518726 -vn 0.134896829724 0.973662376404 0.183805242181 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.067382998765 -0.241788670421 0.967986464500 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.110075645149 -0.299240350723 0.947807252407 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn -0.327422112226 -0.238218516111 0.914355874062 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.506272614002 -0.212398335338 0.835807979107 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.302206009626 -0.319333881140 0.898163378239 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.499433219433 0.162840068340 -0.850911021233 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.493813991547 0.168256774545 -0.853133857250 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn -0.018820434809 0.989357590675 0.144282087684 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.011763782240 0.995036125183 0.098816752434 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.026022652164 0.988108336926 0.151541069150 -vn -0.018820434809 0.989357590675 0.144282087684 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.003519654274 0.995996475220 0.089323498309 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.011763782240 0.995036125183 0.098816752434 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.700267732143 -0.161503911018 0.695371508598 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.996581256390 -0.016104307026 -0.081033818424 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.904178857803 -0.087611623108 0.418072730303 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.893042266369 -0.102554738522 0.438130140305 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.995280504227 -0.048975117505 -0.083774343133 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.844687044621 -0.055362772197 0.532389700413 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.470668077469 -0.288607269526 0.833773016930 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.667668998241 -0.190084442496 0.719781875610 -vn -0.518660068512 -0.250207871199 0.817549884319 -vn -0.393412828445 -0.499320507050 0.771949112415 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.150311067700 0.982064425945 0.113824792206 -vn 0.098272599280 0.988767683506 0.112609624863 -vn 0.098272599280 0.988767683506 0.112609624863 -vn -0.226836472750 0.971370637417 0.070599377155 -vn -0.191518172622 0.977899730206 0.083862185478 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.828021049500 -0.105283483863 0.550723612309 -vn 0.849974095821 -0.094851419330 0.518215477467 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.478259414434 -0.153687790036 0.864666402340 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.516509771347 -0.172434687614 0.838739454746 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.997999727726 0.053960263729 0.032937355340 -vn 0.994555354118 0.050949502736 0.090905636549 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.691769719124 0.281607925892 -0.664944827557 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.902975142002 0.113141357899 -0.414529800415 -vn 0.909626424313 0.109246626496 -0.400805354118 -vn 0.699930727482 0.270119965076 -0.661159753799 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.698699057102 -0.088728033006 -0.709892213345 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.675778031349 -0.159016281366 -0.719748497009 -vn 0.348523497581 -0.248401150107 -0.903785526752 -vn 0.372713238001 -0.219777032733 -0.901544749737 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.215006738901 0.976588487625 -0.006861140486 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.680514693260 0.732540011406 -0.016878856346 -vn 0.529358327389 0.845940232277 -0.064536072314 -vn 0.233587369323 0.971875846386 -0.029904913157 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn 0.194978520274 -0.578596770763 -0.791965365410 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn -0.151900768280 -0.824738562107 0.544731557369 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.292715787888 -0.318961352110 -0.901432812214 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.111708708107 -0.268920898438 -0.956662297249 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.992322683334 -0.093264035881 -0.081225268543 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.759035468102 -0.198567867279 -0.620029032230 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.746579527855 -0.245642706752 -0.618286848068 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.914270520210 -0.374885022640 -0.153527349234 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.932675123215 -0.328857719898 -0.148221790791 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.992116570473 -0.075684450567 0.099882952869 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.978691160679 -0.038977265358 0.201604634523 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn 0.757674992085 0.067285761237 0.649154245853 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.682809650898 0.058452133089 0.728254318237 -vn 0.469311714172 -0.101307049394 0.877202033997 -vn 0.467002600431 -0.069905437529 0.881488382816 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.101197555661 -0.910763978958 0.400334864855 -vn 0.220449462533 -0.944154858589 0.244895160198 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn 0.465971797705 0.054153501987 -0.883140802383 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.452682107687 0.112095654011 -0.884597897530 -vn 0.448319792747 0.129651442170 -0.884420633316 -vn 0.461291611195 0.075415410101 -0.884037673473 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn 0.232225567102 -0.911761343479 -0.338766276836 -vn -0.194162026048 -0.710348606110 -0.676539719105 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.971844494343 -0.232869014144 -0.035921055824 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.213583230972 -0.152138248086 0.965005755424 -vn -0.790865480900 -0.036794260144 0.610882937908 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.167976438999 0.232479542494 0.957985997200 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.112317882478 -0.462118685246 0.879676640034 -vn 0.144089296460 -0.504522621632 0.851290345192 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.167976438999 0.232479542494 0.957985997200 -vn -0.168900057673 0.193152844906 0.966521978378 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.362826079130 0.288003414869 0.886234343052 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.361879914999 0.274064928293 0.891028225422 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.616649746895 0.675030350685 0.405064314604 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.716325759888 0.585582971573 0.379433780909 -vn -0.720118165016 0.286492228508 0.631943047047 -vn -0.701582729816 0.307782292366 0.642691016197 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.004341814201 -0.943970918655 0.330000013113 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.619513154030 -0.784907817841 -0.011097250506 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn 0.079071938992 -0.791167795658 0.606466054916 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.482992053032 -0.863088667393 -0.147636696696 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn 0.180200353265 -0.741592764854 -0.646194994450 -vn -0.116688124835 -0.992550909519 -0.035022944212 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.142431572080 -0.628738820553 -0.764461100101 -vn -0.176847338676 -0.984200179577 0.008661456406 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.271172046661 -0.956903278828 0.103931777179 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.680348038673 -0.605094075203 -0.413506597281 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.798590898514 -0.600576460361 0.039503142238 -vn -0.184958517551 -0.968991398811 0.163847535849 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.260384202003 -0.547934710979 0.794963896275 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.768781661987 -0.413898468018 0.487506747246 -vn -0.231335133314 -0.954641819000 0.187464684248 -vn -0.226429939270 -0.972733318806 -0.050193894655 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn -0.327985137701 -0.938536167145 0.107590034604 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.238442823291 -0.955045223236 0.176163703203 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn -0.197733581066 -0.828324854374 -0.524194002151 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.027907121927 -0.999519944191 -0.013458410278 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.351804703474 -0.934922873974 0.046397421509 -vn 0.455730617046 -0.609691083431 -0.648526310921 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.562027513981 -0.816579937935 0.131614059210 -vn 0.873089492321 -0.323864191771 -0.364453941584 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.983599066734 -0.120129249990 0.134542852640 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.641216576099 -0.727358162403 0.244522735476 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn 0.772990465164 0.063075460494 0.631274282932 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.740041375160 -0.561373829842 0.370402753353 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.446306288242 -0.891758263111 0.074685193598 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.479405224323 -0.803639292717 0.352610945702 -vn 0.251268237829 -0.424266308546 0.869978368282 -vn -0.087695412338 -0.850844204426 0.518047869205 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.301698088646 0.951182126999 0.065044857562 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.171455085278 0.914633154869 0.366127461195 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn 0.124457292259 -0.991895079613 -0.025584608316 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.215676337481 0.968818902969 0.121957629919 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.117949590087 0.849612355232 0.514049351215 -vn 0.301698088646 0.951182126999 0.065044857562 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.135806068778 0.653280317783 0.744836568832 -vn 0.215676337481 0.968818902969 0.121957629919 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.174129217863 -0.981105268002 -0.084329314530 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.180662691593 -0.977567434311 -0.108272127807 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.174272745848 0.962094068527 0.209771290421 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.473818302155 0.648060023785 0.596250295639 -vn 0.116785392165 0.979833245277 0.162135779858 -vn 0.116785392165 0.979833245277 0.162135779858 -vn -0.093426696956 0.949718952179 0.298839986324 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.003870419692 -0.997206032276 0.074600264430 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.079968959093 -0.996480226517 0.025141783059 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn -0.059656828642 -0.984534978867 0.164717689157 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.050876371562 -0.998084306717 0.035204216838 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.687957525253 -0.724567592144 -0.041426882148 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.509252071381 -0.849297642708 0.139125302434 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.248102903366 0.886689305305 0.390162765980 -vn -0.042816758156 0.962022185326 0.269592463970 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.062132738531 0.996134936810 0.062086712569 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.200634062290 0.979664087296 -0.002052781638 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.210182353854 0.975235521793 0.068840667605 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.247134611011 0.967952191830 0.044642847031 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn 0.102859064937 -0.983786880970 -0.146912872791 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.122811011970 -0.957747161388 -0.260072857141 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.169295936823 -0.937194883823 -0.304966658354 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.235094085336 -0.934384286404 -0.267687737942 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.246383532882 -0.967374920845 -0.058999452740 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.297367244959 -0.937489330769 0.180794060230 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn 0.197106972337 -0.920975387096 0.336084991693 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.029394404963 -0.956659615040 0.289721101522 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.263758838177 0.662336528301 -0.701242864132 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.241378128529 0.940966784954 -0.237314462662 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.248370751739 0.904884219170 -0.345682770014 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.253509610891 -0.900861382484 0.352394223213 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.423191249371 -0.904291272163 0.056271243840 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn -0.280886679888 -0.956602573395 -0.077551461756 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.312394291162 0.933531820774 -0.175863862038 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.524871349335 0.551161825657 -0.648637592793 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.186048939824 0.976999819279 0.104197762907 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.246464684606 0.969103455544 -0.009678545408 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.193100318313 0.461876630783 -0.865668654442 -vn -0.189719647169 0.908340811729 -0.372724354267 -vn 0.097601912916 0.930599808693 -0.352785885334 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.310470491648 0.939930260181 -0.141912579536 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.436779737473 0.895123004913 -0.089321024716 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.423305630684 0.886720836163 0.185845404863 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.405214011669 0.855926692486 0.321233749390 -vn 0.162324577570 0.904733717442 0.393837094307 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.803628146648 0.587178885937 -0.096968024969 -vn 0.753271698952 0.627935349941 0.195650026202 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.090818278491 -0.972123861313 -0.216164782643 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn -0.260627955198 -0.963619589806 0.059247847646 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn -0.009665114805 0.432859390974 0.901409626007 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.135806068778 0.653280317783 0.744836568832 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.212095111609 0.293082028627 0.932265281677 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.410863459110 -0.055618740618 0.909998774529 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.644459664822 0.624916911125 0.440625160933 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.705824911594 -0.080311007798 0.703819155693 -vn -0.473818302155 0.648060023785 0.596250295639 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.902148842812 -0.074126504362 0.425009071827 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.745227813721 0.633083999157 0.209380432963 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.983445346355 -0.041850395501 0.176306024194 -vn -0.745227813721 0.633083999157 0.209380432963 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.117949590087 0.849612355232 0.514049351215 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.212095111609 0.293082028627 0.932265281677 -vn -0.009665114805 0.432859390974 0.901409626007 -vn 0.171455085278 0.914633154869 0.366127461195 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.151055559516 0.962752103806 0.224255621433 -vn 0.390230685472 0.623500227928 0.677471399307 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.512415468693 0.772289216518 0.375499367714 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.248102903366 0.886689305305 0.390162765980 -vn 0.686944067478 0.473488986492 0.551285803318 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.930573165417 0.310774356127 0.193527519703 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.256829530001 0.900792479515 0.350159198046 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.201083213091 0.576883137226 0.791688919067 -vn 0.385481506586 0.480627328157 0.787655591965 -vn 0.253791481256 0.930407822132 0.264444947243 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.176589697599 0.143177881837 -0.973815262318 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.227506399155 0.605743527412 -0.762440562248 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.283158630133 0.632815361023 -0.720670461655 -vn 0.281906336546 0.138081952929 -0.949453651905 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.468284696341 0.617177546024 -0.632298469543 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.697048187256 0.565060555935 -0.441395968199 -vn 0.728800296783 0.028480309993 -0.684133768082 -vn 0.412756860256 0.060444112867 -0.908833444118 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn 0.184735700488 -0.032027877867 -0.982266247272 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.196467101574 -0.223334953189 -0.954736709595 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.555135130882 -0.143407806754 -0.819304108620 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn -0.727473437786 0.553508579731 -0.405475795269 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.847794950008 -0.123858034611 -0.515657722950 -vn -0.985829532146 0.026642497629 -0.165621146560 -vn -0.704271733761 0.708031654358 -0.051889482886 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.956620991230 0.038980554789 -0.288715720177 -vn 0.990990340710 0.130139961839 -0.031650196761 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.082572974265 -0.055582214147 0.995033800602 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.090538904071 -0.721768438816 0.686187326908 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.355197250843 -0.292997479439 0.887686550617 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.097998321056 -0.885099232197 0.454967737198 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.156766593456 -0.905144870281 0.395141780376 -vn -0.486689150333 -0.374447375536 0.789254605770 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.285608649254 -0.925775051117 0.247726097703 -vn -0.675995051861 -0.429347306490 0.598908662796 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.307565927505 -0.950393795967 0.046419605613 -vn -0.818308353424 -0.492649257183 0.296088099480 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.459652185440 -0.883022904396 -0.094818055630 -vn -0.929030179977 -0.362915277481 0.072079576552 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.146504536271 -0.042443491518 0.988299012184 -vn 0.065914735198 -0.785547375679 0.615280866623 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.297726511955 -0.357162386179 0.885321378708 -vn 0.098932050169 -0.899504899979 0.425562411547 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.455326050520 -0.212368279696 0.864625871181 -vn 0.319514423609 -0.863103568554 0.391104489565 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.699083209038 -0.651106238365 0.295539051294 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.844169318676 -0.142716273665 0.516730368137 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.927620470524 -0.368441313505 0.061410423368 -vn 0.696924626827 -0.715875566006 -0.042640652508 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.926520526409 -0.330959945917 -0.178956046700 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.436327308416 -0.827338337898 -0.353736788034 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.693109035492 -0.481128364801 -0.536763787270 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.125757485628 -0.893814086914 -0.430443346500 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn -0.429687142372 -0.462241262197 -0.775694489479 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.087170556188 -0.883316695690 -0.460600584745 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn -0.131213530898 -0.471373289824 -0.872118234634 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.089234955609 -0.909940361977 -0.405025571585 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn 0.039728019387 -0.366211801767 -0.929683089256 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.060197409242 -0.886249661446 -0.459279716015 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.177547097206 -0.158900201321 -0.971199154854 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.001846735133 -0.877386391163 -0.479780942202 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn -0.071178838611 -0.914667427540 -0.397890716791 -vn 0.193469092250 -0.202935039997 -0.959889113903 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.364927858114 -0.230931147933 -0.901941478252 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn -0.060941711068 -0.833909392357 -0.548526406288 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.588752269745 -0.330777943134 -0.737534224987 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.116796404123 -0.867212474346 -0.484046578407 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.419476836920 -0.896206259727 -0.144407406449 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.262821823359 -0.951250076294 -0.161393716931 -vn 0.819989025593 -0.434048742056 -0.373121529818 -vn 0.899102628231 -0.414789378643 -0.139872014523 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.812033295631 0.514916896820 0.274704486132 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.237624734640 0.624630987644 0.743888854980 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.325573593378 0.324940294027 0.887927711010 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.325573593378 0.324940294027 0.887927711010 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.538130819798 -0.140533074737 0.831062972546 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.522908329964 -0.718644380569 0.458385378122 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn -0.118096649647 -0.989603102207 -0.082090765238 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.365978002548 -0.816699564457 -0.446163564920 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.735541522503 -0.420057326555 -0.531536042690 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.957898378372 0.116688869894 -0.262324929237 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.812033295631 0.514916896820 0.274704486132 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.237624734640 0.624630987644 0.743888854980 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.599148094654 -0.349108159542 0.720517218113 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn 0.445603191853 -0.384337395430 0.808531105518 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn 0.353177726269 -0.489298284054 0.797403693199 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.349057108164 -0.704609453678 0.617806315422 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.497694343328 -0.736805498600 0.457622140646 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.627989470959 -0.668266415596 0.398809760809 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.663220942020 -0.615163028240 0.426277458668 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.765411973000 -0.281774252653 0.578573942184 -vn 0.695339739323 -0.572090268135 0.434988915920 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.718194782734 0.602012097836 -0.348966598511 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.725587606430 0.503578245640 -0.468968629837 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.789350450039 0.503757894039 -0.350932806730 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.850929498672 0.302877247334 -0.429167002439 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.628575026989 0.261088401079 -0.732616007328 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.228433817625 0.366642951965 -0.901881873608 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.369103759527 0.776214718819 -0.511129260063 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.483243614435 0.776178956032 -0.404996097088 -vn -0.576867401600 0.757517874241 -0.305598944426 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.454803496599 0.485992193222 0.746301114559 -vn 0.033919174224 0.761711001396 0.647028446198 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.716205894947 0.675131976604 0.176765188575 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.454803496599 0.485992193222 0.746301114559 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.931238234043 0.267171919346 0.247819513083 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.653353095055 -0.045459389687 0.755687236786 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.994130134583 -0.099492669106 -0.042502265424 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.702828645706 -0.631237745285 0.327979892492 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn -0.820460438728 -0.286714076996 -0.494610667229 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.384284645319 -0.881262183189 -0.275140374899 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn -0.280365377665 -0.237007901073 -0.930173397064 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.265687763691 -0.705258131027 -0.657283067703 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.198456883430 0.134244099259 -0.970872461796 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.664483129978 -0.179814308882 -0.725347459316 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.296048760414 0.717162728310 -0.630898356438 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.867754399776 0.307647943497 -0.390326917171 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.158363074064 0.985768735409 -0.056401804090 -vn -0.305796295404 0.933188319206 0.188807144761 -vn -0.305796295404 0.933188319206 0.188807144761 -vn 0.033919174224 0.761711001396 0.647028446198 -vn 0.729900121689 0.651386141777 0.207224413753 -vn 0.348348826170 0.555683076382 0.754896938801 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.523129105568 0.167803466320 0.835570394993 -vn 0.348348826170 0.555683076382 0.754896938801 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn 0.047754000872 -0.065999239683 0.996676325798 -vn -0.258473217487 0.240610465407 0.935573697090 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.070202268660 -0.434225112200 0.898064672947 -vn -0.483811736107 -0.291279852390 0.825277090073 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.105502836406 -0.773460447788 0.625002443790 -vn -0.419215917587 -0.771656930447 0.478334188461 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn 0.191903352737 -0.952242434025 0.237502530217 -vn -0.069711819291 -0.997551083565 0.005667928606 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.493556946516 -0.869650483131 -0.010467589833 -vn 0.338439792395 -0.873332142830 -0.350356280804 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.712524473667 -0.673489809036 -0.196774929762 -vn 0.664489090443 -0.542217135429 -0.514251768589 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn 0.883103847504 0.135465055704 0.449195712805 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.935779094696 -0.302246212959 0.181561961770 -vn 0.988916158676 0.017871269956 -0.147395417094 -vn 0.848077535629 0.469010263681 0.246564060450 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.069645345211 0.862430155277 0.501361846924 -vn 0.056397389621 0.973752439022 0.220511928201 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.625884294510 0.621010959148 0.471820145845 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.382084578276 0.771323442459 0.508990705013 -vn -0.506518363953 0.725894212723 0.465313613415 -vn -0.392548322678 0.780418395996 0.486675381660 -vn -0.382084578276 0.771323442459 0.508990705013 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.392548322678 0.780418395996 0.486675381660 -vn 0.002175812144 0.997610270977 0.069057755172 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.359837502241 0.773664951324 0.521497368813 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.291743457317 0.775886118412 0.559362590313 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.202851682901 0.784742534161 0.585687935352 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.092519551516 0.986486911774 -0.135217294097 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.055783562362 0.991671502590 -0.116085425019 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn -0.064116746187 0.995342969894 -0.071981780231 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.002175812144 0.997610270977 0.069057755172 -vn 0.093329630792 0.941157698631 0.324825823307 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn 0.145412996411 0.775520384312 -0.614347755909 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.435292720795 -0.036885086447 -0.899533033371 -vn -0.212444365025 0.441597640514 -0.871698856354 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.000561077497 0.892739951611 -0.450571924448 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn 0.093329630792 0.941157698631 0.324825823307 -vn -0.015082026832 0.898052096367 0.439630508423 -vn -0.015082026832 0.898052096367 0.439630508423 -vn 0.056397389621 0.973752439022 0.220511928201 -vn 0.164719715714 0.961630463600 -0.219395115972 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.756435573101 0.570307672024 0.320241183043 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.110619284213 0.821678519249 0.559113383293 -vn -0.218308880925 0.796049535275 0.564487636089 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.069645345211 0.862430155277 0.501361846924 -vn -0.110619284213 0.821678519249 0.559113383293 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.164405122399 0.635002374649 0.754813194275 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.218308880925 0.796049535275 0.564487636089 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.750251233578 0.270256996155 0.603393971920 -vn -0.353946268559 0.734738647938 0.578689157963 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.935766935349 -0.242188498378 0.256290793419 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.750251233578 0.270256996155 0.603393971920 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn 0.164405122399 0.635002374649 0.754813194275 -vn 0.356486141682 -0.270039647818 0.894425094128 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.147346720099 0.889737486839 0.432037174702 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.534322023392 0.359675824642 0.764940083027 -vn -0.671294987202 -0.260830819607 0.693779766560 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.910371243954 -0.268473833799 0.314874649048 -vn 0.703342258930 0.225412517786 0.674165308475 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.703342258930 0.225412517786 0.674165308475 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.598508119583 0.249849140644 0.761159241199 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.429617762566 0.848202347755 0.309808552265 -vn -0.791654765606 0.576650857925 -0.201882332563 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.429617762566 0.848202347755 0.309808552265 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.598508119583 0.249849140644 0.761159241199 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.811512649059 -0.327733904123 0.483774423599 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn 0.313882619143 0.163946226239 0.935200154781 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.607785642147 -0.416889160872 0.675869822502 -vn -0.457538694143 0.750161647797 0.477405369282 -vn -0.353946268559 0.734738647938 0.578689157963 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.833009958267 0.535604238510 0.138645425439 -vn -0.842326104641 0.537471950054 -0.040131911635 -vn -0.457538694143 0.750161647797 0.477405369282 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.384632349014 -0.290035128593 0.876320481300 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn 0.314843177795 -0.462489783764 0.828840732574 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn 0.100030563772 -0.661799669266 0.742977142334 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.019895311445 -0.792612075806 0.609401524067 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.178587734699 -0.922734260559 0.341566920280 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.408398300409 0.460756182671 -0.787981331348 -vn -0.688532412052 0.659234106541 -0.302214354277 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.537448406219 -0.838045239449 0.093964748085 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.640428006649 -0.731053292751 -0.235399663448 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.941314995289 -0.067905850708 -0.330627977848 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019885519519 0.156374439597 0.987497627735 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.181642502546 0.885934293270 0.426762789488 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.181642502546 0.885934293270 0.426762789488 -vn 0.170826375484 0.283379584551 0.943670690060 -vn 0.170826375484 0.283379584551 0.943670690060 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.424639850855 0.811399281025 0.401636928320 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.546915650368 0.810093104839 -0.211263924837 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.389531940222 0.909839093685 -0.143030583858 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.310567855835 -0.005853740964 0.950533211231 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.019885519519 0.156374439597 0.987497627735 -vn -0.383504658937 0.857913494110 0.341919034719 -vn -0.606193363667 0.768687665462 0.204080417752 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.815810859203 0.574943482876 0.062391024083 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.968362867832 -0.224615901709 0.108724497259 -vn -0.859864592552 -0.161788597703 0.484207957983 -vn -0.612901210785 -0.171269357204 0.771374642849 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.577897906303 -0.355524659157 0.734599351883 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.914714396000 -0.397285848856 -0.073902077973 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887782454491 -0.459931015968 -0.017485428602 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.077389903367 0.914463222027 0.397199958563 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.669492661953 0.064479798079 0.740014791489 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.545027732849 0.737514972687 0.398768693209 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.743179678917 0.068944804370 0.665530264378 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.646443426609 0.759647488594 0.071039631963 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn 0.553945541382 0.699680268764 0.451211482286 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.058358471841 0.816487491131 0.574406206608 -vn 0.630036652088 0.727832496166 0.270765095949 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.553945541382 0.699680268764 0.451211482286 -vn 0.436596006155 0.685988366604 0.582068622112 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.436596006155 0.685988366604 0.582068622112 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.298728913069 0.741523385048 0.600752949715 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.936779797077 0.026538468897 0.348911702633 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.097729347646 0.768430531025 0.632426679134 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.962532341480 0.106497831643 0.249378725886 -vn -0.097729347646 0.768430531025 0.632426679134 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.058358471841 0.816487491131 0.574406206608 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.936779797077 0.026538468897 0.348911702633 -vn -0.887424767017 0.078465610743 0.454225122929 -vn 0.077389903367 0.914463222027 0.397199958563 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn 0.568133234978 0.821251451969 -0.052637834102 -vn 0.081868670881 0.901294291019 0.425401180983 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.103438951075 0.980265319347 -0.168464601040 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.545027732849 0.737514972687 0.398768693209 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.399299442768 -0.641792595387 0.654722988605 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.509258329868 -0.100890107453 0.854679524899 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.030449874699 -0.613143086433 -0.789384782314 -vn -0.030449874699 -0.613143146038 -0.789384782314 -vn -0.030449876562 -0.613143146038 -0.789384782314 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295697689 -0.699427545071 -vn 0.454834192991 -0.551295757294 -0.699427545071 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.084855884314 0.981540918350 -0.171397000551 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.266018509865 0.937779486179 -0.223167747259 -vn -0.494124293327 0.813777327538 0.305953741074 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.743179678917 0.068944804370 0.665530264378 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.701685905457 -0.509247004986 0.498301476240 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.669492661953 0.064479798079 0.740014791489 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.887424767017 0.078465610743 0.454225122929 -vn -0.834079504013 -0.535284638405 0.133348211646 -vn -0.714156806469 -0.585525572300 0.383588165045 -vn -0.254605710506 0.744727969170 0.616892397404 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.622664332390 0.454117029905 0.637233734131 -vn -0.254605710506 0.744727969170 0.616892397404 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.373588293791 0.906539082527 0.196516364813 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.388561308384 0.831142783165 0.397771000862 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.008125438355 0.822232007980 0.569094419479 -vn 0.008125438355 0.822232007980 0.569094419479 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn 0.298728913069 0.741523385048 0.600752949715 -vn 0.114516958594 0.788044095039 0.604873836040 -vn 0.114516958594 0.788044095039 0.604873836040 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.424639850855 0.811399281025 0.401636928320 -vn -0.316964924335 0.809910416603 0.493536621332 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.388561308384 0.831142783165 0.397771000862 -vn -0.373588293791 0.906539082527 0.196516364813 -vn -0.013701758347 0.829518616199 0.558310985565 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.013701758347 0.829518616199 0.558310985565 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.242492765188 0.969967246056 -0.018994800746 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.034370608628 0.694903075695 -0.718281567097 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.483079075813 0.188845366240 -0.854969024658 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.308176785707 -0.444958806038 -0.840855956078 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.095979750156 0.237653985620 -0.966596305370 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.108198247850 0.059869885445 -0.992324888706 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.188442409039 -0.595347464085 -0.781057536602 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.223764970899 -0.611924827099 -0.758602142334 -vn 0.186325952411 0.041206322610 -0.981623470783 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn 0.280480980873 0.072654128075 -0.957105934620 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.270638674498 -0.588777959347 -0.761639833450 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.112290486693 0.984839260578 -0.132221266627 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.164916515350 0.980066657066 -0.110778510571 -vn -0.040053065866 0.814612388611 0.578621149063 -vn -0.115149334073 0.801315605640 0.587055325508 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.181109443307 0.982749462128 -0.037454269826 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.432357877493 0.900786101818 0.040632791817 -vn -0.374014973640 0.886462867260 -0.272573590279 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn -0.019123541191 0.906814336777 -0.421096295118 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.071902558208 0.827343285084 -0.557075500488 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn -0.243032351136 0.654210090637 -0.716201424599 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.759460985661 -0.164043009281 -0.629530727863 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.574291229248 0.222163870931 -0.787929475307 -vn 0.501307368279 0.477822452784 -0.721371352673 -vn 0.821521222591 0.078862875700 -0.564697682858 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.369810193777 -0.044239182025 -0.928053498268 -vn 0.552213788033 -0.386443734169 -0.738729417324 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.161430969834 -0.167638167739 -0.972541749477 -vn 0.368465006351 -0.612099230289 -0.699691414833 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn -0.422474920750 -0.667798876762 -0.612829148769 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.627340018749 -0.085048124194 -0.774087429047 -vn -0.224376007915 -0.046368073672 -0.973398864269 -vn 0.045121468604 -0.817973375320 -0.573483705521 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn -0.149325296283 0.191209688783 -0.970124125481 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.271971881390 -0.439561158419 -0.856047511101 -vn 0.304755032063 0.162415653467 -0.938480436802 -vn 0.158929482102 0.658865928650 -0.735280275345 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.018299452960 0.998276531696 0.055759474635 -vn 0.018299452960 0.998276531696 0.055759474635 -vn -0.147346720099 0.889737486839 0.432037174702 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.227914363146 0.973679065704 -0.002040540567 -vn 0.050975821912 0.871190190315 0.488292098045 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.050975821912 0.871190190315 0.488292098045 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.415789157152 0.681671321392 0.602032840252 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.090699143708 0.010228182189 0.995825827122 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn -0.245555266738 -0.736587166786 0.630191981792 -vn 0.163989365101 -0.143401250243 0.975983381271 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn -0.578328967094 -0.319814234972 0.750502765179 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.378451079130 -0.561920762062 0.735540509224 -vn -0.090699143708 0.010228182189 0.995825827122 -vn -0.357310593128 0.236652135849 0.903506994247 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.535596609116 -0.080347500741 0.840642929077 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn -0.084090135992 -0.870717883110 0.484540194273 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.303251296282 -0.837280929089 0.454971790314 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.704818487167 -0.360784024000 0.610791087151 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.934182822704 -0.324974685907 0.147288635373 -vn 0.590286970139 -0.797087967396 0.127326473594 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.502711594105 0.493176937103 -0.709970116615 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.712965011597 0.308273494244 -0.629800260067 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn -0.285020858049 -0.719945371151 -0.632804691792 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.108074806631 -0.244027063251 -0.963727474213 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.913268625736 0.406597167253 -0.024883907288 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.644251585007 0.759489834309 -0.090083837509 -vn 0.415789157152 0.681671321392 0.602032840252 -vn 0.715015947819 0.376954406500 0.588776290417 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.143064171076 0.886963069439 0.439123153687 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.182695105672 0.915379524231 0.358751714230 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.203395426273 0.839035332203 0.504628598690 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.313882619143 0.163946226239 0.935200154781 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.145488426089 0.976211905479 -0.160759046674 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.143064171076 0.886963069439 0.439123153687 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.429713785648 0.846449017525 0.314436256886 -vn -0.667831838131 0.682248771191 -0.297552168369 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn -0.046772319824 0.986538410187 -0.156698241830 -vn 0.203395426273 0.839035332203 0.504628598690 -vn -0.429713785648 0.846449017525 0.314436256886 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.516368031502 -0.345768600702 0.783459067345 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.433476418257 0.101598486304 0.895419418812 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn 0.286178618670 -0.536495864391 0.793897986412 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn 0.179807379842 -0.031763926148 0.983188867569 -vn -0.178978517652 -0.082300312817 0.980404675007 -vn -0.083396285772 -0.628017544746 0.773717641830 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.149947926402 0.168516919017 -0.974226713181 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn 0.029971798882 -0.099999859929 -0.994535923004 -vn -0.264134556055 -0.500071525574 -0.824718952179 -vn -0.374504595995 -0.259615004063 -0.890138387680 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.433138728142 -0.448282390833 -0.781942307949 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.835667192936 -0.353619337082 -0.420254290104 -vn 0.538265943527 -0.756090760231 -0.372285634279 -vn -0.007061770186 -0.825218200684 -0.564769864082 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.893253266811 -0.289331018925 0.344072848558 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn 0.775661766529 -0.398030877113 -0.489816576242 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.330751955509 -0.411549597979 0.849252641201 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.172960251570 -0.975686252117 -0.134614691138 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.829526424408 0.541623890400 0.136123031378 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.945044875145 -0.011528831907 0.326737374067 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.647236943245 -0.611986935139 0.454484701157 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.564102113247 0.009641343728 0.825648725033 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn 0.227151930332 0.082373514771 0.970369338989 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.236986622214 0.101993352175 0.966144263744 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn 0.120366461575 -0.507115423679 -0.853431820869 -vn -0.402320235968 0.064717441797 -0.913208663464 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.078055009246 -0.974436163902 -0.210669353604 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn 0.010250043124 -0.738894104958 0.673743546009 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.496666043997 -0.462730199099 0.734304845333 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.544135689735 -0.377859950066 0.749091565609 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.037874251604 -0.391661256552 -0.919329643250 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn 0.309158563614 -0.309895396233 0.899102807045 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.457300573587 -0.591948747635 -0.663681268692 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.203997373581 0.026348058134 0.978616833687 -vn 0.239223495126 -0.067995756865 0.968580782413 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn 0.206780195236 -0.288152217865 0.934992134571 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.583397090435 -0.665412664413 0.465697109699 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.649454832077 -0.730109870434 0.212480604649 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.203997373581 0.026348058134 0.978616833687 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.631104588509 0.755875229836 -0.174240186810 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.297869771719 -0.792901396751 0.531583428383 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.407826662064 -0.263833075762 0.874110698700 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.499737411737 -0.027546295896 -0.865738809109 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.826180279255 0.350576817989 0.441046565771 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.659432172775 0.712318539619 0.240315511823 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.132363051176 0.588919281960 0.797279179096 -vn 0.370204120874 0.758121490479 0.536843240261 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.052568800747 -0.785489320755 -0.616638481617 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.841082036495 -0.539783477783 0.034854743630 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.482255339622 -0.870516359806 0.098138004541 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.475282013416 -0.870118498802 0.130387231708 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.153536304832 -0.769525945187 -0.619884192944 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.413747638464 -0.638228178024 -0.649213135242 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.178848639131 -0.936645090580 -0.301179677248 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.483235120773 -0.712880373001 -0.508217871189 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.321229845285 -0.869021952152 -0.376313954592 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.556770026684 -0.623259902000 -0.549139559269 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.474162250757 -0.571830630302 -0.669462382793 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.658861577511 -0.512930274010 -0.550276279449 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.667836844921 -0.152970269322 -0.728418886662 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.925836741924 -0.160533234477 -0.342133611441 -vn -0.899324655533 0.257733941078 -0.353253960609 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.932423293591 -0.356068879366 -0.061658397317 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.995549976826 0.022097477689 -0.091607637703 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.976822197437 -0.125868663192 0.173134148121 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.443778961897 -0.582111120224 0.681327283382 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.869244992733 0.157309949398 0.468686133623 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.855051636696 -0.223598405719 0.467857301235 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.739987790585 -0.562143504620 0.369341015816 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.888698339462 -0.439484417439 0.130647391081 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.632312119007 -0.679946780205 0.371286600828 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.862132310867 -0.493066251278 0.116677321494 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.918786525726 -0.386189073324 0.081788085401 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.772156238556 -0.451216131449 0.447413414717 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.321332365274 -0.686707675457 0.652056813240 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn 0.099003560841 -0.460517406464 0.882112264633 -vn -0.107284501195 -0.382235765457 0.917815804482 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.245721325278 -0.497057318687 0.832198917866 -vn -0.428062021732 -0.867399811745 0.253733038902 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.644596397877 -0.704937696457 0.295902520418 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.813467323780 -0.562431871891 -0.148126035929 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.801894485950 -0.583262145519 -0.129501029849 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.415000826120 -0.651071131229 -0.635516107082 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.216722741723 -0.871117889881 -0.440664112568 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.013535787351 -0.880698323250 -0.473484188318 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.465112328529 -0.877144038677 -0.119536064565 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.209421366453 -0.651745200157 0.728951931000 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.314107537270 -0.661226451397 0.681260585785 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.087140031159 -0.994907796383 -0.050647247583 -vn 0.010299650952 -0.900448083878 0.434841483831 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.805738449097 -0.547442436218 0.226036131382 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.519221127033 -0.425794452429 0.741018593311 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.640411615372 -0.260996520519 0.722325265408 -vn -0.829879522324 -0.541816174984 0.133173540235 -vn -0.845744073391 -0.529137194157 0.068780913949 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.487767368555 -0.313111811876 0.814888954163 -vn -0.574658870697 -0.143289893866 0.805751323700 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.559565782547 0.120767101645 0.819939911366 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.853377461433 -0.132773742080 0.504101276398 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.837346494198 -0.286848008633 0.465369820595 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.747882008553 -0.238024860620 0.619690835476 -vn -0.693059682846 -0.333859682083 0.638909995556 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn -0.458640992641 -0.736003398895 0.497943222523 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn -0.286890745163 -0.891448795795 0.350731760263 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.173197016120 -0.846449792385 0.503513157368 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.036074623466 -0.999024033546 0.025488309562 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.296743154526 -0.755670011044 0.583871841431 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.617912590504 -0.773055791855 -0.143418341875 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.684597432613 -0.679221808910 -0.264545053244 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.679967224598 -0.681577086449 0.270365059376 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.593118011951 -0.667791306973 -0.449739724398 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.652128934860 -0.607643485069 -0.453317999840 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn -0.018079442903 -0.557789921761 -0.829785227776 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn -0.016730729491 -0.462477594614 -0.886473119259 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.757288575172 0.167512565851 -0.631231725216 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.782802700996 0.142475947738 -0.605739653111 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.832457840443 0.231845602393 -0.503251016140 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.829526424408 0.541623890400 0.136123031378 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.052795063704 -0.326312363148 0.943786501884 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.529069483280 -0.659794330597 0.533626258373 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.868813395500 0.343230307102 -0.356869995594 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.652744770050 0.294556379318 -0.697969019413 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.167408272624 0.019269237295 -0.985699355602 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.403329372406 0.107619918883 -0.908704221249 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.937725424767 0.113176889718 -0.328423529863 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.665814876556 0.035237163305 -0.745284438133 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.953373312950 -0.099214516580 -0.285018980503 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn 0.589868128300 -0.175914064050 -0.788105249405 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.236893758178 -0.226129606366 -0.944852769375 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.867434203625 -0.060777686536 -0.493825823069 -vn 0.997439682484 -0.069704242051 0.015980891883 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.471449375153 -0.100497379899 -0.876148223877 -vn 0.900293529034 0.234960332513 -0.366422206163 -vn 0.847567141056 0.260671019554 -0.462255924940 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.249982208014 -0.445761620998 -0.859537959099 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn -0.681225955486 -0.643803775311 -0.348493665457 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.948226809502 0.311464130878 0.062097102404 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.951063156128 0.070982269943 0.300733000040 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.679351329803 -0.176735669374 0.712212264538 -vn 0.365372657776 -0.213905602694 0.905951023102 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.846369147301 0.254753082991 0.467718034983 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.601849079132 0.160555899143 0.782303988934 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.628393650055 0.178586021066 0.757118523121 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.877089083195 0.223065018654 0.425390124321 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.348919451237 0.080806083977 0.933662474155 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.368893653154 0.027525994927 0.929063916206 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.194185197353 -0.183894842863 0.963573992252 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.256139546633 0.005911893677 0.966621756554 -vn 0.227151930332 0.082373514771 0.970369338989 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.836737871170 -0.128324687481 0.532355606556 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.963498711586 0.237371236086 0.123794898391 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.319046318531 0.589759051800 0.741885244846 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.744825839996 0.492822498083 0.449844926596 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.760400354862 0.647973775864 0.043833035976 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.405096322298 0.863581359386 0.300206899643 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.379973024130 0.906289756298 -0.185092836618 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.682067394257 0.691617667675 -0.237590149045 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.709767401218 0.168196678162 0.684061467648 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.348638504744 -0.498758524656 0.793530762196 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.352969527245 -0.536707878113 0.766392350197 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.167523771524 -0.257773190737 0.951571762562 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.295748770237 -0.295451253653 0.908427894115 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.555238842964 -0.456454634666 0.695240259171 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.862534463406 -0.244094222784 0.443229347467 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn 0.487581610680 -0.775879859924 0.400343090296 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.343629240990 -0.755872249603 0.557293534279 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn 0.103528626263 -0.504750728607 0.857034742832 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.067010790110 0.193234190345 0.978861629963 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.469787657261 0.093729905784 0.877789437771 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.946406006813 0.125533640385 0.297585338354 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.948614597321 -0.097721196711 0.300966590643 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.580778717995 -0.219648644328 0.783868968487 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.448288679123 0.297675549984 0.842868030071 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.371716529131 -0.655101001263 0.657776176929 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.524495065212 -0.158350035548 0.836558520794 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.492483049631 -0.606667697430 -0.624031007290 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.177026122808 -0.302125543356 -0.936686635017 -vn 0.057427704334 -0.414175599813 -0.908383548260 -vn -0.626207888126 -0.615593433380 -0.478443711996 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.574005007744 -0.568478524685 -0.589364349842 -vn -0.636359751225 -0.637431919575 -0.434427082539 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.705403685570 -0.708261907101 0.027761107311 -vn -0.704343855381 -0.707138836384 -0.062083810568 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn 0.358009755611 -0.281399130821 0.890305280685 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.134670898318 -0.693116486073 0.708133637905 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.430385142565 -0.512250244617 0.743214845657 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.831635236740 -0.554599404335 -0.028325177729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.826602876186 -0.557232499123 -0.078864529729 -vn -0.201462924480 -0.979488193989 -0.003945601173 -vn -0.165003806353 -0.884678483009 0.436024934053 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn -0.649726748466 -0.700721383095 -0.294694274664 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.284909248352 -0.955779790878 0.072881773114 -vn -0.102928921580 -0.779785394669 0.617527663708 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.375210881233 -0.925834357738 -0.045249074697 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.268584340811 -0.695054829121 0.666904211044 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.424531817436 -0.905397713184 0.005259912461 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.706194460392 -0.044653762132 0.706608414650 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.726206362247 -0.341912865639 0.596422553062 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.974349737167 0.170101836324 0.147336244583 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.985877811909 0.130831107497 -0.104537896812 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.923730432987 -0.023954166099 -0.382293522358 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.478329122066 -0.718357503414 -0.505137383938 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.613461971283 -0.711588799953 -0.342499285936 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.407492965460 -0.781558632851 -0.472351163626 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.702270984650 -0.386405408382 -0.597918331623 -vn -0.618783295155 -0.420402556658 -0.663603007793 -vn -0.477094113827 -0.544931411743 -0.689515054226 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.932627201080 -0.223822146654 -0.283037424088 -vn -0.468870520592 -0.880146622658 0.074178211391 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.964247941971 -0.187405601144 0.187363326550 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.981363117695 -0.161664009094 -0.103880442679 -vn -0.448362886906 -0.891751825809 0.061232645065 -vn -0.444202423096 -0.895280957222 0.034002799541 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.807064890862 -0.552481949329 -0.208350643516 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.868382692337 -0.492589503527 -0.057158134878 -vn -0.813132524490 -0.578888535500 -0.060856662691 -vn -0.807450592518 -0.554794609547 -0.200565382838 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.388772368431 0.459267735481 0.798704683781 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.549822390079 -0.063416108489 0.832870781422 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.477920562029 0.410443186760 0.776613354683 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.560062587261 -0.186729982495 0.807131826878 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.699011743069 -0.205537945032 0.684935569763 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.587647318840 0.285558760166 0.757051348686 -vn -0.718367397785 0.331862986088 0.611404359341 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.227597177029 0.752148985863 0.618442714214 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.369171798229 0.707622945309 0.602479815483 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.015306836925 0.932955980301 0.359664946795 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.087493650615 0.818190336227 0.568251192570 -vn -0.087493650615 0.818190336227 0.568251192570 -vn 0.224660709500 0.880128324032 0.418212532997 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn -0.015306836925 0.932955980301 0.359664946795 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.224660709500 0.880128324032 0.418212532997 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.569128751755 0.821337521076 0.038692541420 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.337324202061 0.937716066837 -0.083071991801 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.535955786705 0.643807947636 -0.546134352684 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.021702494472 0.953724086285 -0.299898922443 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn 0.153611332178 0.712468445301 -0.684684097767 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.264695346355 0.355452001095 -0.896431982517 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.121029257774 -0.027293033898 -0.992273628712 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.048779781908 -0.453738659620 -0.889798700809 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.206205829978 -0.702378511429 -0.681280851364 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.182425379753 -0.612416327000 -0.769199073315 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.211010664701 -0.782586097717 -0.585690617561 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.351192057133 -0.756816744804 -0.551264524460 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.485435694456 -0.860150992870 -0.156500682235 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.487536758184 -0.706500649452 0.512995839119 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.410868376493 -0.855570673943 -0.314938157797 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.408026278019 -0.912963032722 -0.003611285938 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.514525294304 -0.731623828411 0.447202742100 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.101952873170 -0.909801363945 -0.402327060699 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.184225216508 -0.972478866577 -0.142639294267 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.674101769924 -0.578337550163 0.459469795227 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.585420906544 -0.788699448109 0.187711238861 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.719724059105 -0.685022294521 0.112879239023 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.858911693096 -0.182994604111 0.478313356638 -vn -0.807156682014 -0.517316579819 0.284396976233 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.916460096836 0.020301461220 0.399610698223 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.655620634556 0.408538043499 0.635026156902 -vn -0.671189248562 0.679710924625 0.295800745487 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.133595734835 0.780554592609 0.610644459724 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.227597177029 0.752148985863 0.618442714214 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.133595734835 0.780554592609 0.610644459724 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.383149057627 0.722431600094 0.575577437878 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.639663100243 0.702030539513 0.313024312258 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.731158316135 0.601349055767 -0.322159647942 -vn 0.831336021423 0.522877693176 -0.188359692693 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.099108003080 -0.402736932039 -0.909934401512 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.708833932877 0.250561743975 -0.659373402596 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.492782562971 -0.063800342381 -0.867810368538 -vn 0.428585141897 -0.040443520993 -0.902595758438 -vn 0.535544693470 0.275787591934 -0.798206150532 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn 0.226864755154 -0.286887109280 -0.930713772774 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.194933831692 -0.583831667900 -0.788125216961 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.672055184841 -0.725156843662 -0.149964749813 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.511326909065 -0.718953311443 -0.470798164606 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.892944872379 -0.385881245136 -0.231829911470 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.938371777534 -0.282592266798 -0.198997437954 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.815596401691 0.281203985214 -0.505694448948 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.949289202690 -0.309554010630 0.055011600256 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.663576424122 0.494282841682 -0.561561048031 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.821825385094 0.395930439234 -0.409685432911 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.671606421471 0.450448870659 -0.588252186775 -vn -0.869419932365 0.084259010851 -0.486836105585 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.637821733952 0.488461166620 -0.595473885536 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.490629106760 0.237269863486 -0.838442683220 -vn -0.721844017506 0.195682883263 -0.663814306259 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.545747458935 0.283221065998 -0.788635253906 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.686485171318 0.092494286597 -0.721237063408 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.183073207736 -0.386103332043 -0.904106438160 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.478759437799 -0.663799166679 -0.574595510960 -vn 0.449785411358 -0.576989471912 -0.681744992733 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.329149395227 -0.467716008425 -0.820306301117 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.673811018467 -0.258386611938 -0.692253589630 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.502841472626 0.152358904481 -0.850844979286 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.083382159472 -0.056732505560 -0.994901418686 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.009588683955 0.158294707537 -0.987345337868 -vn -0.245750382543 0.123391754925 -0.961447477341 -vn -0.264142423868 -0.036704715341 -0.963784992695 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn -0.025633789599 0.161498978734 -0.986539900303 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.082963459194 0.056872200221 -0.994928419590 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.225545078516 -0.033045161515 -0.973672151566 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.489780098200 -0.209073856473 -0.846406280994 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.590395748615 -0.458811551332 -0.664021730423 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.892143607140 -0.373993068933 -0.253394812346 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.545812249184 -0.730485975742 -0.410462200642 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.596728801727 -0.251290261745 -0.762081325054 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.527154386044 -0.303020209074 -0.793906211853 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.639553129673 0.242772787809 -0.729405999184 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.419903606176 0.134679481387 -0.897520124912 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.714447438717 0.682991147041 -0.151947423816 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.739929258823 0.304891109467 -0.599621653557 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.673065066338 0.472372084856 -0.569076478481 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.341846585274 0.284227907658 -0.895742952824 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.467311531305 0.620484113693 -0.629777252674 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.259521037340 0.371823370457 -0.891289055347 -vn 0.325470060110 0.351604342461 -0.877749204636 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.392812073231 0.735419094563 -0.552138984203 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.640389323235 0.549518227577 -0.536592245102 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.941307663918 0.022298494354 -0.336812436581 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.965461432934 0.242496728897 0.095286831260 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.741731941700 0.501786887646 0.445020914078 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.293927401304 0.907257616520 0.300816118717 -vn 0.360126763582 0.767400383949 0.530476570129 -vn 0.179308205843 0.861584722996 0.474889785051 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.273158043623 0.934740722179 -0.227254107594 -vn 0.080189734697 0.994042217731 0.073822200298 -vn 0.012269859202 0.997172594070 0.074136719108 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.012269859202 0.997172594070 0.074136719108 -vn 0.132539749146 0.945317745209 0.298005938530 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn 0.033008869737 0.924311041832 -0.380209892988 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.330062657595 0.835152924061 -0.439975202084 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.768199086189 0.245171323419 -0.591406106949 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.677218377590 0.363926440477 -0.639478564262 -vn -0.893771290779 0.433860689402 0.113744199276 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.678252398968 -0.455122470856 -0.576920449734 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.984319269657 -0.152193680406 0.089177437127 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.763610422611 -0.477208584547 0.434937983751 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.594703376293 -0.397734880447 0.698666512966 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.263727605343 0.610503315926 0.746815502644 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.020327450708 0.685757458210 0.727546215057 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.263727605343 0.610503315926 0.746815502644 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.370204120874 0.758121490479 0.536843240261 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.542481601238 0.822646200657 0.170196890831 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.047376774251 0.985158741474 0.164977937937 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn 0.267536640167 0.962516665459 -0.044562082738 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.286273032427 0.950327754021 -0.122167788446 -vn 0.536262750626 0.829411447048 0.156521141529 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.193438187242 0.920349657536 -0.339909076691 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.518993139267 0.853364884853 -0.049137547612 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.277653843164 0.886079668999 -0.371175289154 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.679521858692 0.707831799984 -0.192935630679 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.872674405575 0.488287925720 -0.003779047867 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.580039501190 0.810850262642 -0.077948980033 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.538406550884 0.777243494987 0.325593203306 -vn 0.271541535854 0.878055930138 0.394059598446 -vn 0.318014234304 0.945945560932 -0.063670635223 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.219829887152 0.614850819111 0.757385849953 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.437919378281 0.522179126740 0.731816649437 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.050312381238 0.219402447343 0.974336326122 -vn 0.075094878674 0.432029217482 0.898727715015 -vn 0.169710069895 0.354005783796 0.919716477394 -vn 0.169710069895 0.354005783796 0.919716477394 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn -0.085905134678 0.072124846280 0.993689239025 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.112385883927 -0.013062778860 0.993578791618 -vn -0.004842369352 -0.090278387070 0.995904803276 -vn 0.058739125729 0.414347767830 0.908221125603 -vn 0.075094878674 0.432029217482 0.898727715015 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.050312381238 0.219402447343 0.974336326122 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.035715855658 0.282992452383 0.958456933498 -vn -0.035715855658 0.282992452383 0.958456933498 -vn 0.029441878200 0.010064356960 0.999515831470 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.263161271811 0.103435955942 0.959190905094 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.029441878200 0.010064356960 0.999515831470 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.518912613392 -0.007385498378 0.854795396328 -vn 0.831018924713 0.197237804532 0.520100772381 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.600048422813 -0.203632548451 0.773612141609 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.864150702953 0.126768007874 0.487004548311 -vn 0.818057775497 0.564850091934 0.108286269009 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.455256909132 0.154836475849 0.876793503761 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.453169703484 0.481266558170 0.750346422195 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn 0.135830074549 -0.343074232340 0.929435431957 -vn 0.208336263895 -0.278127074242 0.937678694725 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.265029519796 -0.254425883293 0.930068194866 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.755936682224 -0.078634925187 0.649904847145 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.823928177357 -0.558669090271 0.095032870770 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.600404083729 -0.799385666847 0.022305326536 -vn -0.528669953346 -0.833349883556 0.161356776953 -vn -0.569882392883 -0.781691014767 -0.253363668919 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.673517167568 -0.634575307369 0.379063099623 -vn -0.210569992661 -0.581241369247 0.786014497280 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.498376756907 -0.793012082577 0.350360482931 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.887668788433 0.052449654788 0.457485646009 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.944252073765 0.136449009180 0.299615949392 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.697707474232 0.421750694513 0.579077363014 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.727394163609 0.509469330311 0.459715932608 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.724714219570 0.435234844685 0.534190952778 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.768063783646 0.480185359716 0.423674464226 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.778490006924 0.600795805454 0.181652903557 -vn -0.659432172775 0.712318539619 0.240315511823 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.809710144997 0.519156396389 -0.273580133915 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.675162792206 0.732949554920 -0.083307720721 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.670200228691 0.606968700886 -0.427107304335 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.649198472500 0.702223300934 -0.292273372412 -vn -0.859216272831 0.509000778198 -0.051629338413 -vn -0.942147135735 0.238965108991 -0.235062733293 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.785289108753 0.476154029369 -0.395725131035 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.347453445196 0.917836844921 -0.191967740655 -vn -0.839950859547 0.531240165234 0.110753878951 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn -0.952616810799 -0.174849286675 -0.248895525932 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.859815657139 -0.502162754536 -0.092464320362 -vn -0.662463724613 -0.694501161575 -0.280731111765 -vn -0.788645088673 -0.409951418638 -0.458234369755 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn -0.178030878305 -0.583501636982 0.792357742786 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.158309683204 -0.178065404296 0.971200704575 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.184182494879 -0.197999864817 0.962742388248 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.441284209490 0.209403678775 0.872592866421 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.505942106247 0.540051519871 0.672582268715 -vn 0.660578846931 0.637442171574 0.396614521742 -vn 0.453169703484 0.481266558170 0.750346422195 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.512911856174 0.478652119637 0.712610423565 -vn 0.608070433140 0.728028059006 0.316584140062 -vn 0.660578846931 0.637442171574 0.396614521742 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.211216762662 -0.001241557067 0.977438449860 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.621104836464 -0.359912663698 0.696197986603 -vn -0.399748653173 -0.843661308289 0.358380526304 -vn -0.019606690854 -0.578665554523 0.815329253674 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.204309478402 0.943660676479 0.260311752558 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.132539749146 0.945317745209 0.298005938530 -vn 0.179308205843 0.861584722996 0.474889785051 -vn -0.220427542925 0.888312995434 0.402879327536 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn 0.925407707691 -0.005031303037 -0.378939688206 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.681297540665 -0.322972238064 -0.656903803349 -vn 0.652328729630 -0.167368456721 -0.739225983620 -vn 0.804847180843 0.152762740850 -0.573484599590 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.122597619891 -0.747514247894 -0.652834057808 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.046912796795 -0.729911625385 -0.681929767132 -vn -0.620779097080 -0.438473641872 -0.649903237820 -vn -0.633255422115 -0.627966761589 -0.452377378941 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.671189248562 0.679710924625 0.295800745487 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.220427542925 0.888312995434 0.402879327536 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.390028774738 0.674186646938 0.627176105976 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.253249228001 0.791888356209 0.555677652359 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.340392619371 0.609669387341 0.715846419334 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.573439121246 0.774328887463 0.267548710108 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.408763051033 0.858367443085 0.310029268265 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.387950241566 0.306505471468 0.869223237038 -vn 0.112411670387 0.934677660465 0.337255597115 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.880949735641 0.343913435936 0.325040131807 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.904745161533 0.424362540245 0.036777820438 -vn -0.971087098122 0.209993973374 -0.113544560969 -vn -0.949271559715 0.198618978262 0.243790954351 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.678752899170 0.244429960847 0.692494392395 -vn -0.576891720295 -0.135861605406 0.805442452431 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.193375051022 0.128279089928 0.972702741623 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.263161271811 0.103435955942 0.959190905094 -vn -0.577125847340 0.201278433204 0.791462421417 -vn -0.355250090361 -0.150804743171 0.922526597977 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn -0.441548943520 -0.284639060497 -0.850890815258 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.423912823200 -0.341173976660 -0.838986456394 -vn -0.240199193358 -0.029700530693 -0.970269143581 -vn -0.157724842429 -0.135115936399 -0.978195548058 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn -0.015824938193 -0.742880165577 0.669237315655 -vn 0.059519782662 -0.753729641438 0.654483735561 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.281399369240 -0.574816942215 0.768374800682 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.261888325214 -0.752726018429 0.604001641273 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.439621299505 -0.798366189003 0.411514908075 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.180149838328 -0.906361877918 0.382170349360 -vn -0.062123641372 -0.885799050331 0.459892094135 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn -0.159160330892 -0.964936077595 0.208725690842 -vn 0.051451597363 -0.920796453953 0.386635005474 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.333943217993 -0.910978615284 0.242074161768 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.435610353947 -0.881730079651 0.181095689535 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.189692094922 -0.955165922642 0.227321282029 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.218373641372 -0.969438731670 0.111810170114 -vn -0.048545453697 -0.967491388321 0.248201131821 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.006470040418 -0.977761268616 0.209621205926 -vn -0.140495687723 -0.969917178154 0.198800444603 -vn 0.088904842734 -0.968297600746 0.233443140984 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn -0.066201880574 -0.954533576965 0.290659606457 -vn 0.244941085577 -0.836532413960 0.490119814873 -vn 0.308790862560 -0.745268821716 0.590950608253 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.135852813721 -0.058212291449 0.989017367363 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.204170882702 0.248477354646 0.946875512600 -vn 0.058739125729 0.414347767830 0.908221125603 -vn -0.085905134678 0.072124846280 0.993689239025 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.027110569179 -0.011936810799 -0.999561190605 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.019503040239 -0.172679528594 -0.984784960747 -vn 0.269662439823 -0.263775676489 -0.926123380661 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.583311021328 0.040439106524 0.811241567135 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.470662862062 -0.460005283356 0.752908766270 -vn -0.489858627319 -0.656127095222 0.574052095413 -vn -0.768608272076 -0.485239326954 0.416874170303 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn -0.347360849380 -0.510150015354 0.786821067333 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.135091811419 -0.937327325344 0.321197301149 -vn -0.028921009973 -0.899534881115 0.435890555382 -vn -0.075540587306 -0.408239841461 0.909743845463 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.125578880310 -0.818379342556 -0.560789823532 -vn 0.310442298651 -0.483567774296 -0.818405628204 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.057479105890 -0.991644442081 0.115487813950 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn 0.000114159702 -0.916326463223 -0.400432020426 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.334424287081 -0.422505348921 -0.842407047749 -vn -0.136971995234 -0.962700605392 -0.233337238431 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.239525496960 -0.963812053204 -0.117020592093 -vn 0.252535343170 -0.921323895454 -0.295614898205 -vn 0.422853231430 -0.774249792099 -0.470884710550 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn 0.173997506499 -0.880611777306 -0.440735518932 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.339754194021 -0.900075256824 -0.272821515799 -vn 0.544952988625 -0.759176731110 -0.355916976929 -vn 0.451726198196 -0.783965706825 -0.425841778517 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.315271288157 -0.518904209137 0.794570624828 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.054175578058 -0.901394307613 0.429596632719 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.260502964258 -0.838142514229 0.479223728180 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.572803854942 -0.352588474751 0.739984512329 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.236986622214 0.101993352175 0.966144263744 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.147857800126 -0.099749833345 0.983965456486 -vn -0.107788465917 -0.386987119913 0.915763437748 -vn -0.034547798336 -0.278813153505 0.959723770618 -vn -0.735418856144 0.087225042284 0.671975374222 -vn -0.303747743368 -0.019316455349 0.952556669712 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.271746575832 -0.111890241504 0.955842256546 -vn -0.523545145988 0.010065250099 0.851938486099 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.196217641234 0.079919569194 0.977298080921 -vn 0.154252499342 -0.124288119376 0.980182945728 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn -0.029381169006 -0.030018234625 0.999117434025 -vn 0.067010790110 0.193234190345 0.978861629963 -vn 0.196217641234 0.079919569194 0.977298080921 -vn -0.339029431343 0.284355103970 0.896772682667 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.827181220055 -0.138448268175 0.544613003731 -vn -0.564102113247 0.009641343728 0.825648725033 -vn -0.339029431343 0.284355103970 0.896772682667 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.285008758307 -0.406475007534 -0.868071496487 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.267445057631 -0.192847266793 -0.944077908993 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.516787350178 -0.512377858162 -0.685856938362 -vn 0.846682190895 0.200712263584 -0.492791861296 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn 0.759303212166 0.159380048513 -0.630917251110 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.484712213278 -0.006896703970 -0.874646484852 -vn 0.330834299326 -0.371046543121 -0.867682635784 -vn 0.816680550575 -0.101389199495 -0.568113625050 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn -0.806820988655 -0.332564800978 0.488303750753 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.406228005886 -0.041485197842 0.912829577923 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.209566771984 0.133428663015 -0.968647778034 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.538782417774 -0.202660694718 -0.817705392838 -vn -0.069656006992 0.129356831312 -0.989148557186 -vn -0.631666839123 0.276833325624 -0.724127292633 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.060981951654 -0.674715280533 0.735554575920 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.427608430386 -0.371340870857 0.824170470238 -vn 0.176717445254 -0.092994883657 0.979858636856 -vn -0.167441368103 -0.416238933802 0.893704950809 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.578013658524 0.042303718626 0.814929783344 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn 0.251756250858 -0.084170669317 0.964123487473 -vn -0.090002775192 -0.362050384283 0.927803337574 -vn 0.604858994484 -0.045539114624 0.795029461384 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn -0.447785437107 -0.638254702091 0.626194119453 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.713085711002 -0.687005877495 0.139755845070 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.800140321255 0.517762780190 0.302815377712 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.869676053524 0.481602787971 0.108269944787 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.008688014932 -0.035473790020 0.999332845211 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.367894500494 -0.700198650360 -0.611862301826 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.476563870907 -0.524323523045 -0.705671131611 -vn 0.421691358089 -0.146094635129 -0.894892573357 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.414077520370 -0.196655467153 -0.888744294643 -vn 0.105665363371 -0.365992993116 -0.924599349499 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.384889483452 -0.623771905899 -0.680271029472 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn 0.316687047482 -0.489543884993 -0.812438368797 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn 0.028203584254 -0.615325748920 -0.787768244743 -vn -0.261296123266 -0.475798040628 -0.839845538139 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.087292499840 0.331456899643 0.939423382282 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.411596596241 0.156486570835 0.897830843925 -vn 0.505942106247 0.540051519871 0.672582268715 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.016478214413 0.889357864857 -0.456914693117 -vn -0.437514305115 0.716767847538 -0.542977988720 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.408763051033 0.858367443085 0.310029268265 -vn -0.047376774251 0.985158741474 0.164977937937 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.843002557755 0.537570774555 -0.019088163972 -vn -0.411975830793 0.620765864849 0.667027473450 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.318106293678 0.808898806572 0.494460374117 -vn -0.139534607530 0.974310278893 0.176775634289 -vn -0.534430682659 0.838877797127 0.103285685182 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn -0.320949465036 0.043232060969 -0.946109116077 -vn 0.145574510098 0.222784399986 -0.963937342167 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.232292786241 0.148990094662 0.961167037487 -vn -0.087292499840 0.331456899643 0.939423382282 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.059995397925 0.889339148998 -0.453295111656 -vn -0.356496870518 0.789703249931 -0.499278217554 -vn -0.086963027716 0.905135571957 -0.416133403778 -vn -0.534430682659 0.838877797127 0.103285685182 -vn -0.787490665913 0.559860408306 -0.257710725069 -vn -0.369516134262 0.895232856274 0.249030083418 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.560695827007 0.078877851367 0.824256300926 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.070092804730 0.916692733765 -0.393397301435 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.375852286816 -0.924159824848 0.068291187286 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.394036650658 -0.827092707157 -0.400815129280 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.387950241566 0.306505471468 0.869223237038 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.447341591120 0.339131593704 0.827571868896 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.417517900467 -0.904517471790 -0.086757712066 -vn -0.323057621717 -0.945225358009 -0.046719886363 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.308101117611 -0.933596551418 -0.182951375842 -vn -0.186435729265 -0.727443575859 -0.660354137421 -vn -0.354307264090 -0.814609885216 -0.459213525057 -vn -0.052991427481 0.783603668213 -0.618996977806 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.698746025562 -0.547520458698 -0.460407793522 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.825821697712 -0.556694149971 -0.090056210756 -vn -0.939724683762 -0.015627166256 0.341574728489 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.913984477520 0.205607891083 -0.349796772003 -vn 0.847370386124 0.434056639671 -0.305872917175 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.925316154957 0.358393728733 -0.123870611191 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.957574665546 0.276369482279 -0.081673927605 -vn 0.882223665714 0.299788743258 -0.363053917885 -vn 0.854635655880 0.431288868189 -0.289115548134 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.434012651443 -0.235733553767 0.869518637657 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.166393876076 -0.774949491024 0.609726488590 -vn 0.952093958855 -0.222135722637 0.210173279047 -vn 0.894741058350 0.330808013678 0.300007522106 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.950541198254 -0.306927442551 0.047613322735 -vn 0.843217432499 -0.417677789927 -0.338422268629 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.902191579342 0.340740293264 -0.264473766088 -vn 0.881415486336 0.472221165895 0.010672469623 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.975543797016 -0.094598576427 0.198407247663 -vn 0.992158353329 0.027582362294 -0.121905915439 -vn 0.964519500732 0.260759145021 0.041313480586 -vn 0.339722335339 -0.772119879723 0.537047088146 -vn 0.606853306293 -0.574624598026 0.549122631550 -vn 0.472912132740 -0.407679647207 0.781121909618 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.516383767128 0.829848945141 -0.211420193315 -vn 0.910326242447 0.412144482136 0.037987414747 -vn 0.614409804344 0.747312724590 0.253030240536 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn 0.408882349730 0.910067975521 -0.067760296166 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.452918559313 0.890388429165 -0.045532457530 -vn 0.326792329550 0.941127479076 0.086521036923 -vn 0.366194635630 0.921540796757 -0.129089444876 -vn -0.253069043159 0.614814400673 0.746966719627 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.647573769093 0.433242529631 0.626856565475 -vn -0.020327450708 0.685757458210 0.727546215057 -vn -0.253069043159 0.614814400673 0.746966719627 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.503477275372 0.329060941935 0.798892676830 -vn -0.461934238672 0.250010490417 0.850947439671 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.271056413651 0.279122084379 0.921205341816 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.370860576630 0.350416839123 0.860040962696 -vn -0.411217749119 0.406187385321 0.816034138203 -vn -0.283286154270 0.279502421618 0.917402505875 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.502772688866 0.431714475155 0.748894035816 -vn -0.457814812660 0.521315336227 0.720163822174 -vn -0.457814812660 0.521315336227 0.720163822174 -vn 0.132363051176 0.588919281960 0.797279179096 -vn -0.560695827007 0.078877851367 0.824256300926 -vn -0.736113429070 0.674601316452 -0.055227596313 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.582481026649 0.595602929592 -0.553148269653 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.421104758978 0.313611149788 -0.851069211960 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.907230198383 0.196332752705 -0.372003853321 -vn -0.349258631468 0.184622913599 -0.918658137321 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.498195052147 -0.115418910980 -0.859348714352 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.866396248341 0.034091062844 -0.498192071915 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.811541140079 0.126786649227 -0.570373654366 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.900458395481 0.141342937946 -0.411335438490 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.774951875210 0.023437473923 -0.631585538387 -vn -0.889064431190 0.043844252825 -0.455677688122 -vn -0.616255939007 -0.460302233696 -0.639023005962 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.204309478402 0.943660676479 0.260311752558 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.508762955666 0.860877335072 -0.007104512304 -vn -0.446603745222 0.894501268864 0.020310429856 -vn -0.239098101854 0.963960468769 -0.116671897471 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn -0.680015206337 -0.641033887863 -0.355885982513 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.749990403652 -0.660737752914 -0.030658992007 -vn -0.209138780832 -0.976161360741 0.058051183820 -vn -0.731709063053 -0.655248463154 -0.187753319740 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.903819084167 -0.127298012376 -0.408541679382 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.922906994820 -0.375173211098 -0.086531668901 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.355505973101 -0.143865868449 -0.923535645008 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.326625823975 -0.538841307163 -0.776508629322 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.529980838299 -0.488053917885 -0.693486630917 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.226000085473 -0.775390207767 -0.589655816555 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.601899981499 -0.650427222252 -0.463315069675 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.705796301365 -0.553804755211 -0.441759973764 -vn 0.573986172676 -0.693480610847 -0.435458958149 -vn 0.451178431511 -0.619352042675 -0.642527103424 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.389436155558 -0.407782554626 0.825864911079 -vn 0.169235989451 -0.360193341970 0.917398452759 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.539327800274 -0.415947258472 0.732197642326 -vn 0.274402290583 -0.560791194439 0.781163632870 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.830068528652 -0.119470968843 0.544713616371 -vn 0.160938441753 -0.757669389248 0.632483959198 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn -0.098821595311 -0.750114619732 0.653882503510 -vn -0.051150433719 -0.430328905582 0.901221752167 -vn -0.276620745659 -0.374111890793 0.885167360306 -vn -0.590411484241 0.405412644148 0.697893142700 -vn -0.650010585785 0.251060932875 0.717254936695 -vn -0.735418856144 0.087225042284 0.671975374222 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.924569845200 0.120250284672 0.361538976431 -vn 0.273815929890 -0.854739964008 0.440958529711 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.675949811935 -0.481971591711 0.557490110397 -vn 0.867050588131 -0.340229004622 0.363960862160 -vn 0.970553517342 -0.047824073583 0.236090585589 -vn 0.879921913147 0.474158734083 -0.030182171613 -vn 0.904111444950 -0.175178438425 0.389737099409 -vn 0.881415486336 0.472221165895 0.010672469623 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.248923435807 -0.588823974133 0.768975555897 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.242862716317 -0.841675460339 0.482286363840 -vn -0.621428489685 -0.689511239529 0.372022658587 -vn -0.267561286688 -0.597799122334 0.755676627159 -vn 0.223833784461 -0.794061601162 -0.565123498440 -vn -0.240883529186 -0.697934210300 -0.674435257912 -vn -0.098200760782 -0.989465296268 -0.106372416019 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn 0.031475782394 -0.144916534424 -0.988943099976 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn 0.094840519130 -0.561432182789 -0.822070062160 -vn 0.065739303827 -0.746938109398 -0.661635696888 -vn 0.147203862667 -0.777868270874 -0.610943555832 -vn 0.075115866959 -0.905055582523 -0.418607264757 -vn -0.534120261669 -0.186229407787 -0.824641823769 -vn -0.307740598917 -0.471744924784 -0.826288342476 -vn -0.631180763245 -0.548184394836 -0.548730134964 -vn 0.938025355339 0.000610377872 0.346566140652 -vn 0.546886205673 -0.028232229874 0.836730778217 -vn 0.939568758011 0.305846303701 0.153846189380 -vn 0.950614035130 -0.258485972881 -0.171807885170 -vn 0.964954078197 -0.247261434793 -0.087894394994 -vn 0.990055978298 0.139069169760 -0.021188542247 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.321418374777 0.367474496365 0.872727155685 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.074762940407 0.203222677112 0.976274073124 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.485629320145 0.230432748795 0.843246638775 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.283379137516 0.492464959621 0.822906136513 -vn -0.074762940407 0.203222677112 0.976274073124 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.131599500775 0.737507283688 0.662393093109 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.131599500775 0.737507283688 0.662393093109 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.448826909065 0.613783061504 0.649480342865 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.204573646188 -0.914748191833 0.348404049873 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.880636394024 0.473645627499 0.011806108057 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.878691315651 0.477109283209 -0.016380488873 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.119672834873 0.101008400321 0.987661719322 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.188408941031 0.017793446779 0.981929481030 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.354700446129 0.034820698202 0.934331357479 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.188408941031 0.017793446779 0.981929481030 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.314111679792 0.058616135269 0.947574794292 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.314111679792 0.058616135269 0.947574794292 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.027125038207 0.236739024520 0.971194565296 -vn -0.206207558513 0.036233242601 0.977837204933 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.206207558513 0.036233242601 0.977837204933 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.911755323410 -0.257045537233 0.320358961821 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.636651694775 -0.563084363937 0.526887714863 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.701901853085 0.564634799957 0.434190422297 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn 0.713554799557 -0.435151606798 0.549074351788 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn -0.192956984043 -0.339222282171 0.920704007149 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.369695425034 0.844070196152 -0.388420820236 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.334633797407 0.108778014779 0.936048924923 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.619381129742 -0.464946269989 0.632607281208 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.202524766326 -0.771763801575 0.602797091007 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.786651909351 -0.153091132641 0.598115265369 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.227208584547 -0.580720245838 0.781754612923 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.987220883369 0.152396500111 0.046585436910 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.506033003330 0.457370489836 0.731261134148 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.290093451738 0.940565109253 0.176587253809 -vn 0.303327411413 0.940892398357 0.150711387396 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.631274282932 0.601515531540 -0.489562898874 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.524528563023 -0.200460836291 -0.827457070351 -vn 0.197829738259 -0.940914392471 -0.274851888418 -vn -0.769450485706 -0.472503662109 -0.429751396179 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.178706854582 -0.840725898743 -0.511120200157 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.672420799732 0.229601070285 0.703657329082 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.645085215569 0.203440889716 0.736530244350 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn -0.971202492714 0.043587461114 -0.234234675765 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.378839254379 -0.581993818283 -0.719558179379 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.583150744438 0.262040317059 -0.768940865993 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.463207036257 -0.877379715443 -0.125076130033 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.244689688087 -0.624031841755 -0.742099225521 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.555992066860 -0.656022727489 -0.510398864746 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.096150808036 0.063654631376 0.993329286575 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.254643589258 0.460702836514 0.850240886211 -vn -0.096150808036 0.063654631376 0.993329286575 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.254643589258 0.460702836514 0.850240886211 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn 0.317261904478 0.790387809277 0.524053394794 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.363941878080 0.109785512090 0.924928903580 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.317261904478 0.790387809277 0.524053394794 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.516634881496 0.036752458662 0.855416655540 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.516634881496 0.036752458662 0.855416655540 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.925209879875 -0.269885331392 0.266736835241 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.153454333544 -0.469212532043 0.869650125504 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.792448759079 0.608949303627 0.034723557532 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.172254130244 -0.362085193396 -0.916091084480 -vn 0.291244596243 -0.020018570125 -0.956439137459 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.838846743107 -0.329071611166 -0.433645069599 -vn 0.466906398535 -0.236898526549 -0.851984441280 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.919350385666 0.165112033486 -0.357117384672 -vn 0.592370748520 0.167298868299 -0.788103997707 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.688086986542 0.005382491741 -0.725608229637 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.730803132057 -0.124241836369 -0.671186089516 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.894795954227 -0.208162710071 -0.394979119301 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.778905391693 -0.485527932644 -0.396949648857 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.582459867001 -0.756581723690 -0.297194570303 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.398407310247 -0.854170084000 0.334163308144 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.487584769726 0.575793743134 0.656294643879 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.288535594940 0.014455531724 0.957360029221 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.232914984226 0.237921655178 0.942944288254 -vn -0.035672992468 0.077534280717 0.996351301670 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.410304158926 -0.774405479431 0.481608390808 -vn 0.069301426411 -0.423665106297 0.903163969517 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn -0.175124287605 -0.611406266689 0.771695435047 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.283917009830 -0.872002422810 0.398751676083 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.275815635920 -0.256258785725 0.926421701908 -vn 0.552535414696 -0.620800912380 0.556157231331 -vn 0.528594553471 -0.735937774181 0.423064291477 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.232914984226 0.237921655178 0.942944288254 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.459898144007 -0.231092125177 0.857373952866 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.487584769726 0.575793743134 0.656294643879 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.834144592285 -0.284741282463 0.472361266613 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.319824814796 -0.932368159294 0.168527901173 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.748732030392 -0.637023806572 -0.183305755258 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.570902347565 -0.647958517075 -0.504202604294 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.663026869297 -0.326852053404 -0.673470914364 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.810734689236 -0.513062596321 -0.281915038824 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.685769379139 -0.187744989991 -0.703187167645 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.624556243420 -0.611509680748 -0.485783308744 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.455409258604 -0.854054450989 0.251383066177 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.866467535496 -0.497229367495 0.044686846435 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.426863461733 -0.857933163643 -0.285898983479 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.266588270664 -0.862479686737 -0.430185347795 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.523924887180 0.036490101367 -0.850982487202 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.686465680599 0.170581594110 -0.706871092319 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.950546622276 0.019457427785 -0.309971868992 -vn 0.912563502789 -0.373714834452 0.166027501225 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.587922394276 -0.743195712566 0.319385975599 -vn 0.956435620785 -0.162598088384 0.242472261190 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.694850206375 -0.184983968735 0.694956183434 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.465447813272 -0.842818975449 0.270211994648 -vn 0.453915089369 -0.848896443844 0.270806014538 -vn 0.867994189262 -0.239089637995 0.435226678848 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.980162084103 -0.166142880917 -0.108068868518 -vn 0.643816113472 -0.739150702953 0.197881504893 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.864660620689 -0.347837835550 -0.362451195717 -vn 0.560174226761 -0.823622524738 0.088604912162 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.590715467930 -0.806350469589 -0.029225697741 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.694869339466 -0.418429195881 -0.584870636463 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.274543195963 -0.224540710449 -0.934990644455 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.042917381972 -0.468026548624 -0.882671654224 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.063990190625 -0.437220007181 -0.897075176239 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.409019470215 -0.695324003696 -0.590954840183 -vn 0.188240170479 -0.569500625134 -0.800146639347 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.193443819880 -0.738571822643 -0.645825982094 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.427592217922 -0.637055397034 -0.641346454620 -vn 0.520828485489 -0.852863729000 -0.036893356591 -vn 0.394156038761 -0.893297255039 -0.216011554003 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.499595552683 -0.467188239098 -0.729478895664 -vn 0.749511778355 -0.659742295742 0.054518498480 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.486455798149 -0.718520760536 0.497080177069 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.861029863358 -0.429624319077 -0.272122204304 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.768759310246 -0.630120694637 -0.109348192811 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.539959251881 -0.597649097443 -0.592671513557 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn -0.161456078291 -0.961875319481 -0.220743775368 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.290766537189 -0.504648089409 -0.812886893749 -vn -0.079212263227 -0.595626950264 -0.799345970154 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.254020094872 -0.811730861664 -0.525896191597 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.416124105453 -0.908334791660 -0.042054574937 -vn -0.393807053566 -0.888457477093 0.235710248351 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.327255338430 -0.944576919079 0.026045057923 -vn -0.366184175014 -0.881492078304 0.298128902912 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.729899942875 -0.569648981094 0.377817600965 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.628532528877 -0.762571930885 0.153071716428 -vn -0.471601903439 -0.794673979282 0.382210522890 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.519463300705 -0.846371293068 -0.117530994117 -vn -0.291796803474 -0.953618049622 0.073941029608 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.160140171647 -0.822294294834 -0.546065270901 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.192814096808 -0.594672739506 -0.780504345894 -vn -0.375377774239 -0.755562245846 -0.536858677864 -vn -0.070841103792 -0.960352778435 -0.269636899233 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.397055238485 -0.917237818241 0.031967546791 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.242176041007 -0.913083732128 0.328068315983 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.156231343746 -0.785838067532 0.598372995853 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.513081073761 -0.750334918499 0.416827619076 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.441990941763 -0.709040522575 0.549459338188 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.417561560869 -0.689145386219 0.592216968536 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.209151834249 -0.533267676830 0.819683551788 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.443723082542 0.653885424137 -0.612816214561 -vn -0.840556323528 0.541296303272 0.021526474506 -vn -0.842809736729 0.524093627930 0.122464656830 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.926395535469 0.212197542191 0.311068296432 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn -0.275668442249 0.308932840824 -0.910256803036 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.117609016597 -0.507979869843 -0.853302180767 -vn 0.330104917288 -0.361622065306 -0.871929049492 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.595358073711 -0.784905374050 -0.171674996614 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.651124894619 -0.758814871311 0.015374669805 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.239769145846 -0.773571789265 0.586598157883 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.596639752388 -0.721411108971 0.351549416780 -vn 0.679681301117 -0.729310512543 0.078354842961 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.585008740425 -0.782305777073 0.213921636343 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.641663014889 -0.747617542744 0.171279326081 -vn 0.698903441429 -0.711515784264 0.072658590972 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.711502373219 -0.696542620659 -0.092697240412 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.591400563717 -0.780224919319 -0.203701823950 -vn 0.701678097248 -0.711883068085 0.029501596466 -vn 0.750673115253 -0.641616702080 -0.157536834478 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.257752180099 -0.654427826405 -0.710836112499 -vn 0.665769279003 -0.679318904877 -0.308669835329 -vn 0.500242888927 -0.405992329121 -0.764805376530 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.174743488431 0.009917460382 -0.984564065933 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn 0.662599146366 -0.519838631153 -0.539193987846 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.161422282457 -0.139288842678 -0.977006375790 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.531068980694 0.293644726276 -0.794819831848 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.871813118458 -0.005059626419 -0.489812523127 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.527581334114 0.393371969461 -0.752938508987 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.643263280392 -0.636784613132 -0.425109058619 -vn 0.155823215842 -0.064390845597 -0.985683977604 -vn -0.301210343838 0.243355542421 -0.921981811523 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn 0.674390673637 -0.636433362961 -0.374365925789 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.717560648918 -0.694060981274 -0.058189537376 -vn 0.514324247837 -0.516093671322 -0.684921801090 -vn 0.294105798006 -0.266938149929 -0.917739510536 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.903762876987 0.246395617723 0.350002735853 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.147812932730 -0.499316662550 0.853717863560 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.936993002892 0.101482637227 0.334283322096 -vn -0.046108797193 -0.511099517345 0.858283877373 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.987220883369 0.152396500111 0.046585436910 -vn -0.936993002892 0.101482637227 0.334283322096 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.426190882921 -0.692445337772 0.582134664059 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn -0.494620203972 -0.327400892973 0.805083572865 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn -0.716524899006 -0.209137350321 0.665472507477 -vn 0.216387555003 -0.792263209820 0.570522069931 -vn 0.356181681156 -0.751746535301 0.554988086224 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.581949949265 -0.764983475208 0.275924861431 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn 0.595780968666 -0.744827687740 0.300460904837 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.623058736324 -0.720617711544 0.304151177406 -vn 0.508039653301 -0.692776381969 0.511816978455 -vn 0.528803288937 -0.717596948147 0.453234672546 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.731317400932 -0.539573132992 0.417175889015 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.248956441879 -0.794233560562 0.554268658161 -vn -0.453740745783 -0.766918957233 0.453822225332 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.530688881874 -0.768034517765 0.358458191156 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn 0.533105850220 -0.792724728584 0.295610725880 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.300278335810 -0.889515042305 0.344377607107 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn 0.135520935059 -0.885927915573 0.443582922220 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.180990353227 -0.796912014484 0.576345145702 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.284306257963 -0.792260944843 0.539900481701 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.355224251747 -0.699728786945 0.619834899902 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.546890854836 -0.178878933191 0.817870855331 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.287652492523 -0.039519365877 0.956919133663 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.035672992468 0.077534280717 0.996351301670 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.092231564224 -0.556987345219 0.825383841991 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.499062180519 -0.256094902754 0.827860116959 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn -0.293638288975 -0.111764669418 0.949360430241 -vn -0.004625395872 0.025178126991 0.999672293663 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.017673462629 -0.461896091700 0.886757969856 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.234883025289 0.208845853806 0.949322581291 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.071927569807 -0.503380060196 0.861066162586 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112957909703 -0.620997428894 0.775630533695 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn -0.024860668927 -0.316736102104 0.948187828064 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.543487012386 -0.280511081219 0.791160821915 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.112448878586 -0.172594755888 0.978553175926 -vn 0.119672834873 0.101008400321 0.987661719322 -vn 0.694415569305 -0.021816432476 0.719243407249 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.058332707733 -0.020505351946 0.998086571693 -vn 0.234883025289 0.208845853806 0.949322581291 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.027125038207 0.236739024520 0.971194565296 -vn 0.221945360303 0.419836610556 0.880044043064 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.166294232011 0.550812959671 0.817894458771 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn 0.175731316209 -0.003851976711 0.984430611134 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.129663527012 -0.192400217056 0.972712457180 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.683165788651 -0.057890441269 0.727965116501 -vn -0.911608457565 0.391552716494 0.125126004219 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.606130063534 0.280255675316 0.744354128838 -vn -0.578004896641 0.259107351303 0.773804724216 -vn -0.789368987083 0.531028747559 0.308066695929 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.677267670631 0.631871998310 0.376890242100 -vn -0.615168273449 0.781630039215 0.103065654635 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.713334560394 0.697373151779 -0.069458454847 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.784244716167 0.604237020016 0.140917971730 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.721555650234 0.631091058254 -0.284748166800 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.945204854012 0.321921139956 -0.054355837405 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.945134520531 0.274897247553 0.176500037313 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.819403469563 0.542005181313 -0.186569884419 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.810429036617 0.581710219383 -0.069411993027 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.717592597008 0.544949829578 -0.433694094419 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.424883872271 0.424551874399 -0.799518227577 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn 0.481452792883 -0.399535596371 -0.780111849308 -vn -0.010878787376 0.047278579324 -0.998822510242 -vn -0.040102791041 0.157673552632 -0.986676633358 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn -0.027139838785 0.297324597836 -0.954390645027 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.242206633091 -0.299529105425 -0.922831654549 -vn 0.240511506796 0.018549861386 -0.970468997955 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.108458139002 -0.328526467085 -0.938246846199 -vn 0.236112982035 -0.001613639994 -0.971724271774 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.277681350708 -0.025956066325 -0.960322499275 -vn 0.102752819657 0.184994399548 -0.977353036404 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn -0.003276867792 -0.080719538033 -0.996731460094 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn 0.201174870133 -0.087589986622 -0.975631415844 -vn 0.316024690866 -0.094793908298 -0.944003462791 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn 0.101619660854 -0.255653083324 -0.961413025856 -vn -0.036979392171 -0.187850594521 -0.981501221657 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.229903444648 -0.600790917873 -0.765633523464 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn -0.026375874877 -0.660482764244 -0.750377774239 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.201480373740 -0.832634091377 -0.515874087811 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn -0.153387278318 -0.832074820995 -0.533032655716 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.227712795138 -0.968599319458 0.099810823798 -vn 0.027616413310 -0.965272784233 -0.259780257940 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.056213788688 -0.686007142067 -0.725420057774 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.065242014825 -0.397843718529 -0.915130496025 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.297565698624 -0.840286493301 -0.453181296587 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.144834354520 -0.934874594212 -0.324087142944 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.343803733587 -0.740231871605 -0.577802479267 -vn 0.000912307180 -0.956513702869 -0.291685968637 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.358295381069 -0.487439304590 -0.796258330345 -vn -0.425949454308 -0.498663961887 -0.754918098450 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.211206659675 -0.288128644228 -0.934009432793 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.382034838200 -0.694504439831 -0.609682679176 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.316609293222 -0.120613738894 -0.940856456757 -vn -0.019057372585 -0.177110031247 -0.984006524086 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn -0.141708299518 -0.329541563988 -0.933445811272 -vn 0.090835489333 -0.963552772999 -0.251624643803 -vn 0.241303235292 -0.614637672901 -0.750994861126 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.347830146551 0.660270571709 -0.665625214577 -vn -0.350479990244 0.437364995480 -0.828176081181 -vn -0.361618489027 0.031844489276 -0.931782186031 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.078917674720 0.331730693579 -0.940067410469 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.448264569044 0.485658913851 -0.750462710857 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.210705280304 0.061815194786 -0.975593209267 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.712247908115 0.508445441723 -0.483927845955 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.452509254217 0.396822035313 -0.798603534698 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.493341773748 0.344065487385 -0.798894762993 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.692287385464 0.521458029747 -0.498818278313 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.871990084648 0.489088982344 -0.020622229204 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.850674211979 0.522735774517 -0.055684074759 -vn -0.880456626415 0.472398698330 -0.040442653000 -vn -0.854712486267 0.359191447496 0.374764025211 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.841622591019 0.437275558710 0.316956669092 -vn -0.846006751060 0.409653961658 0.341256827116 -vn -0.702346086502 0.236375972629 0.671443521976 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.877859234810 -0.107805848122 0.466627299786 -vn -0.785008013248 0.203743636608 0.585022211075 -vn -0.619045197964 0.074977569282 0.781768143177 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.334633797407 0.108778014779 0.936048924923 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.202762871981 0.044235628098 0.978228211403 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.488049238920 0.155030697584 0.858937382698 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.646497070789 0.081178493798 0.758585274220 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.557461321354 0.174925819039 0.811565041542 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.173753112555 -0.033539067954 0.984217941761 -vn -0.330435961485 0.111589379609 0.937208533287 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.458910495043 -0.049582216889 0.887097954750 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.501991808414 -0.171072304249 0.847784459591 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.721782505512 -0.005383551121 0.692098975182 -vn -0.653137028217 0.147144690156 0.742805838585 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.654840648174 0.184742674232 0.732839584351 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.647204220295 -0.005476547871 0.762296974659 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.657491862774 -0.150105699897 0.738358139992 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.873160123825 0.306886225939 0.378698021173 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.916443407536 0.266949117184 0.298110216856 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.642937421799 -0.054738871753 0.763960123062 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.678899943829 0.618567526340 -0.395561784506 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.676860630512 0.594577789307 -0.433978050947 -vn -0.587254881859 0.526393055916 -0.614851236343 -vn -0.470546931028 0.462075620890 -0.751712501049 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.469751149416 0.765853762627 -0.439092069864 -vn -0.473276704550 0.816994488239 -0.329437643290 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.277536809444 0.877475261688 -0.391165494919 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.244834110141 0.793942570686 -0.556517302990 -vn -0.387393981218 0.713189482689 -0.584197461605 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn -0.117384985089 0.660975337029 -0.741169571877 -vn -0.281692802906 0.468684077263 -0.837248146534 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.100804962218 0.148268595338 -0.983796119690 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.446126013994 -0.152536511421 -0.881875395775 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.699311733246 -0.076596602798 -0.710701107979 -vn 0.676580607891 -0.353477507830 -0.645981729031 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.855498135090 -0.216838672757 -0.470216870308 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.835438132286 0.233318656683 -0.497599750757 -vn 0.945405006409 -0.279130101204 -0.168213531375 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.788167059422 0.469254255295 -0.398237556219 -vn 0.989614725113 0.143259719014 -0.011802316643 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.683103263378 -0.540835082531 0.490782380104 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.439381361008 -0.207031399012 0.874117851257 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.094372428954 0.461883842945 0.881905436516 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.256296396255 0.374693721533 0.891020059586 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.125300318003 0.134481579065 0.982962131500 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.092569380999 0.481423765421 0.871585965157 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.090679392219 0.816002249718 0.570891857147 -vn 0.006276889239 0.523106515408 0.852244198322 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.121771819890 0.907417356968 0.402200639248 -vn 0.094372428954 0.461883842945 0.881905436516 -vn 0.006276889239 0.523106515408 0.852244198322 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.121771819890 0.907417356968 0.402200639248 -vn -0.090679392219 0.816002249718 0.570891857147 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.065149024129 0.968082070351 0.242018088698 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.149969920516 0.969446182251 0.194121301174 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.246833741665 0.934036254883 0.258165508509 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.357779502869 0.923080861568 -0.141122400761 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.673667073250 0.396585196257 -0.623612761497 -vn -0.608903050423 0.524954736233 -0.594692826271 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.408774822950 0.130344390869 -0.903279304504 -vn -0.366888701916 0.236831426620 -0.899613022804 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn -0.036002598703 -0.139449045062 -0.989574551582 -vn -0.052284561098 -0.164256900549 -0.985030949116 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.311450004578 -0.462049156427 -0.830367088318 -vn 0.236821636558 -0.530136287212 -0.814168930054 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.704556524754 -0.690262138844 -0.164736986160 -vn 0.523449182510 -0.696044564247 -0.491449832916 -vn 0.476768404245 -0.740061700344 -0.474342286587 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.653732180595 -0.718960464001 0.236072242260 -vn 0.620975375175 -0.783508956432 -0.022433303297 -vn 0.518730282784 -0.854915916920 0.006139353849 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.497199982405 -0.602465748787 0.624361455441 -vn 0.504551768303 -0.829032003880 0.241108819842 -vn 0.382935672998 -0.885049641132 0.264664679766 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.354534059763 -0.750870287418 0.557224750519 -vn 0.119527801871 -0.816052436829 0.565483450890 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.038040585816 0.040302138776 0.998463153839 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.125300318003 0.134481579065 0.982962131500 -vn 0.270803511143 -0.386747300625 0.881528198719 -vn 0.045098394156 -0.479812443256 0.876211225986 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.038040585816 0.040302138776 0.998463153839 -vn -0.234272703528 -0.042228519917 0.971253335476 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.092569380999 0.481423765421 0.871585965157 -vn -0.209088429809 0.424714595079 0.880851626396 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.113789513707 0.780125617981 0.615187764168 -vn -0.128022998571 0.758390307426 0.639104306698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.046635005623 0.905606448650 0.421547323465 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn -0.004725415260 0.954034984112 0.299657970667 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn -0.065149024129 0.968082070351 0.242018088698 -vn -0.004725415260 0.954034984112 0.299657970667 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.297269523144 0.952216386795 0.070105269551 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.156814858317 0.983114242554 -0.094316169620 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn -0.095253936946 0.959836602211 -0.263894736767 -vn 0.053862564266 0.980405032635 -0.189485639334 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.187974944711 0.813540935516 -0.550287723541 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn -0.317155778408 0.702843785286 -0.636728227139 -vn 0.002242129063 0.749514043331 -0.661984682083 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn -0.155637040734 0.360485523939 -0.919688701630 -vn 0.129199773073 0.375185638666 -0.917901515961 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.060935895890 -0.076402917504 -0.995213270187 -vn 0.269014984369 -0.078607410192 -0.959922790527 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.467446297407 -0.797998487949 -0.380384445190 -vn 0.289471894503 -0.512713968754 -0.808288574219 -vn 0.382335335016 -0.497620224953 -0.778584480286 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.409876346588 -0.911997258663 -0.016198895872 -vn 0.432791292667 -0.800442516804 -0.414708852768 -vn 0.365264266729 -0.818917512894 -0.442669272423 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.174779847264 -0.957992732525 0.227380603552 -vn 0.259054720402 -0.960606396198 -0.100628063083 -vn 0.115236766636 -0.977209568024 -0.178274780512 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.102916389704 -0.977832078934 -0.182353064418 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.038977205753 -0.981028497219 0.189904913306 -vn -0.168345868587 -0.983503580093 0.066184416413 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.325221389532 -0.836283624172 0.441430330276 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.200875982642 -0.531464934349 0.822917878628 -vn -0.133754879236 -0.847533881664 0.513610720634 -vn -0.341652840376 -0.826769411564 0.446906805038 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.411269128323 -0.523518621922 0.746180891991 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.423713356256 -0.109792359173 0.899117708206 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.214608341455 0.516929745674 0.828689873219 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.336109995842 0.348441511393 0.874996364117 -vn -0.175727561116 0.689686655998 0.702461481094 -vn -0.214608341455 0.516929745674 0.828689873219 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.054755549878 0.784012436867 0.618325412273 -vn 0.046635005623 0.905606448650 0.421547323465 -vn -0.175727561116 0.689686655998 0.702461481094 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.081253156066 -0.948016583920 -0.307672768831 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.268750041723 -0.944639980793 0.188225045800 -vn 0.231874272227 -0.820132136345 -0.523084700108 -vn 0.584060728550 -0.472724586725 -0.659851908684 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.999197006226 -0.013656531461 0.037667006254 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn -0.141119390726 -0.374258041382 0.916523993015 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.798023343086 -0.602499783039 -0.012357043102 -vn 0.935255706310 -0.353455752134 0.019125895575 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.736387848854 -0.150494113564 -0.659609317780 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.800038218498 0.208430096507 -0.562579572201 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.356513082981 -0.697556674480 -0.621540963650 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.304330408573 -0.793034672737 -0.527711093426 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.560852169991 -0.336584091187 -0.756409943104 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.322998225689 0.476452618837 -0.817719399929 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.661050438881 0.078701704741 -0.746202647686 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.455111831427 -0.433408737183 -0.777836799622 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.433478921652 -0.505406737328 -0.746096551418 -vn 0.425416529179 -0.038051687181 -0.904197335243 -vn 0.522343158722 0.054986000061 -0.850960731506 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.534159302711 0.839426577091 0.100184306502 -vn 0.757121384144 0.595956921577 -0.267586499453 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn 0.468820512295 0.504855453968 -0.724795341492 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.330816537142 0.821879863739 -0.463760614395 -vn 0.503617525101 0.812182068825 -0.294499009848 -vn 0.638090133667 0.488221794367 -0.595382630825 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.695233583450 0.684673905373 -0.218796551228 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.290093451738 0.940565109253 0.176587253809 -vn -0.473572015762 0.867844879627 0.150249123573 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.658086836338 0.691037118435 -0.298980653286 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.273009449244 0.860975801945 -0.429169535637 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.394390285015 0.915188133717 -0.082987517118 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn -0.205601692200 0.946526050568 -0.248628988862 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.345520466566 0.916609048843 -0.201105564833 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.319511979818 0.905989944935 -0.277658611536 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.672298371792 0.739992916584 -0.020625833422 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.082643136382 0.941257119179 -0.327421933413 -vn -0.414547055960 0.883300960064 -0.218929663301 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.690027296543 0.696177899837 -0.197986468673 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.411774367094 0.846359968185 -0.337811619043 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn -0.141386777163 0.929110169411 -0.341707617044 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.410014301538 0.809555232525 -0.420129299164 -vn 0.223141282797 0.610668420792 -0.759797394276 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.614214539528 0.333024352789 -0.715426623821 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.879203557968 0.280645579100 -0.385018318892 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.657837927341 0.378287076950 -0.651266574860 -vn 0.233906283975 0.632930636406 -0.738028883934 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.506191194057 0.784512937069 -0.358203768730 -vn 0.236852481961 0.874147355556 -0.423989772797 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.344998806715 0.866717040539 -0.360246300697 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.714554429054 0.667727410793 0.208691373467 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.348152428865 0.870052337646 -0.348996847868 -vn 0.376080244780 0.926337480545 -0.021506395191 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.836690306664 0.270335048437 -0.476306915283 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.607457041740 0.710641443729 -0.354943275452 -vn 0.604264497757 0.669568955898 -0.431904941797 -vn 0.083596318960 0.705422341824 0.703840136528 -vn -0.141477271914 0.989577353001 0.026847619563 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.083596318960 0.705422341824 0.703840136528 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.242646485567 0.968250751495 0.060110073537 -vn 0.037707228214 0.982987165451 -0.179762169719 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.242646485567 0.968250751495 0.060110073537 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.146492078900 0.927200198174 -0.344731599092 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.342749416828 0.924339294434 -0.167689189315 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.655902504921 0.742715775967 -0.134778127074 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.871123313904 0.373719185591 -0.318556308746 -vn -0.938181340694 0.340947598219 -0.059753816575 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.872809171677 -0.341396838427 0.348786950111 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.981501281261 -0.186295166612 -0.044151421636 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.545271813869 -0.699797272682 0.461478531361 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn -0.268343746662 -0.638682842255 0.721162855625 -vn 0.291242122650 -0.640502154827 0.710587799549 -vn 0.150246888399 -0.894174337387 0.421756029129 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.673261463642 0.576191544533 -0.463381379843 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.713754475117 0.560689210892 -0.419740587473 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.453665226698 0.661064624786 -0.597646594048 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.176629319787 0.697645485401 -0.694329082966 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.668538451195 -0.460031986237 0.584317445755 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.797018706799 0.597555816174 -0.087682552636 -vn -0.948703587055 0.192561715841 0.250761777163 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.631175696850 0.324559658766 0.704470157623 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.740443646908 0.314420253038 0.594039678574 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.182598531246 0.715381562710 0.674453139305 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.431219965219 0.861944854259 0.266646653414 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.524120569229 0.848639190197 0.071478672326 -vn -0.668778121471 0.668187499046 0.325977385044 -vn -0.576677322388 0.648915290833 0.496338844299 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.604831039906 0.008647575043 0.796306848526 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.492510139942 -0.097670763731 0.864808738232 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn -0.571737766266 0.732720911503 -0.369101554155 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.100757867098 0.856254220009 -0.506632566452 -vn -0.217604145408 0.731005907059 -0.646744787693 -vn -0.425220996141 0.709233522415 -0.562294363976 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.584861516953 -0.029748234898 0.810587465763 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.251433730125 0.644871890545 0.721748828888 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.535930573940 0.770952641964 0.344108164310 -vn 0.381881237030 0.563686668873 0.732409715652 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.514674782753 0.424443304539 0.744954884052 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.608824074268 -0.275057256222 0.744094610214 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.229931414127 -0.389015793800 0.892075240612 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.908035099506 -0.210515215993 0.362154066563 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.511419832706 -0.781244933605 0.357919096947 -vn 0.634775996208 -0.760179579258 0.138515204191 -vn 0.991328895092 -0.113044984639 -0.066991284490 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.656224668026 -0.205502897501 0.726042509079 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.338420450687 -0.825779497623 0.451176017523 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.232008248568 -0.536629438400 0.811295926571 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn 0.071474067867 -0.435570329428 0.897312641144 -vn -0.004625395872 0.025178126991 0.999672293663 -vn 0.288535594940 0.014455531724 0.957360029221 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn 0.811073362827 -0.208045750856 -0.546696424484 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.734331071377 -0.294317692518 -0.611665785313 -vn 0.788941442966 -0.018234614283 -0.614197731018 -vn 0.801559090614 0.223377063870 -0.554622173309 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.684462308884 -0.341979593039 0.643864393234 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.610466539860 -0.416379898787 0.673764348030 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.726929843426 -0.403456211090 0.555694282055 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.726210057735 -0.395518779755 0.562302231789 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.202762871981 0.044235628098 0.978228211403 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.560032069683 -0.786853432655 0.259279340506 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.554771304131 -0.800131857395 0.228074103594 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn -0.071950569749 -0.950316131115 0.302857011557 -vn 0.591515541077 -0.752557575703 0.289424389601 -vn 0.590239226818 -0.761261343956 0.268512219191 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.526070177555 -0.834664642811 0.163049384952 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.104877673090 -0.737829804420 0.666789233685 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.563823878765 -0.815900862217 0.128095164895 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.653912723064 -0.623547196388 0.428470611572 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.639154016972 -0.695473492146 0.328327208757 -vn 0.363275855780 -0.318919390440 0.875397682190 -vn 0.261660903692 -0.444394350052 0.856765568256 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.536898553371 -0.759433269501 0.367424845695 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.627686858177 -0.765295922756 0.142588213086 -vn 0.554613232613 -0.706817686558 0.439104676247 -vn 0.539303719997 -0.757244586945 0.368418484926 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.119740322232 -0.991864562035 0.043207794428 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn -0.048961449414 -0.929446697235 -0.365693271160 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.279040306807 -0.729090750217 -0.624950528145 -vn 0.564531207085 -0.810247540474 0.157491043210 -vn 0.476696014404 -0.850157141685 0.223592743278 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.140470072627 0.209249109030 -0.967720508575 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.514849841595 0.027653733268 -0.856834232807 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.729452431202 -0.625799298286 0.276178151369 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.624742865562 -0.651130437851 0.430958807468 -vn 0.352315664291 -0.931752741337 0.087809689343 -vn 0.525851249695 -0.848270535469 -0.062589950860 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.176694035530 0.500781595707 -0.847347021103 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.521646261215 0.109020903707 -0.846167623997 -vn 0.568980515003 0.064607515931 -0.819809138775 -vn 0.171955436468 0.529781341553 -0.830519735813 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.363941878080 0.109785512090 0.924928903580 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.324504107237 -0.427837014198 0.843595027924 -vn 0.340282380581 -0.382701039314 0.858922481537 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.364101141691 -0.929735064507 0.054982718080 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.752022862434 -0.514463245869 -0.412054896355 -vn 0.559680283070 -0.749737679958 -0.353060066700 -vn 0.240792527795 -0.970571935177 -0.003004235681 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn -0.074265211821 -0.373613417149 -0.924606800079 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.163060486317 -0.384637802839 -0.908551037312 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.403615891933 -0.100003473461 -0.909446835518 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.827641427517 -0.113630585372 -0.549634158611 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.079553619027 -0.875217258930 -0.477143585682 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn -0.057935588062 -0.779576897621 -0.623621106148 -vn 0.223080739379 -0.690481960773 -0.688091278076 -vn 0.363940000534 -0.870755136013 -0.330655604601 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.837370514870 -0.543764710426 -0.055951450020 -vn 0.668449163437 -0.649779140949 -0.361887782812 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.903918921947 0.398155480623 -0.156213954091 -vn -0.760393679142 0.343544006348 -0.551161468029 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.892418026924 -0.216831088066 -0.395694732666 -vn -0.878178358078 -0.175636082888 -0.444921076298 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn 0.222291097045 -0.811474919319 0.540458202362 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.426152616739 -0.798374474049 0.425431698561 -vn -0.242103204131 -0.685089111328 -0.687050879002 -vn 0.472686260939 -0.862592041492 -0.180284857750 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.645085215569 0.203440889716 0.736530244350 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.628692030907 0.732832312584 -0.260198384523 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.079247862101 0.969927549362 -0.230131030083 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn -0.132732585073 0.987605988979 -0.083764702082 -vn 0.327142566442 0.847049534321 0.418909132481 -vn 0.203795030713 0.978946566582 -0.011453438550 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.327142566442 0.847049534321 0.418909132481 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.555045068264 -0.208258599043 0.805328071117 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.625582337379 -0.136659100652 0.768095731735 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.727658629417 -0.171462669969 0.664163768291 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.657310307026 -0.511882245541 0.553100109100 -vn -0.385458141565 -0.653668999672 0.651259422302 -vn -0.640274345875 -0.423490315676 0.640862464905 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.473156034946 -0.648721933365 0.596056401730 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn -0.306055247784 -0.144851490855 0.940929472446 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.354700446129 0.034820698202 0.934331357479 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.374189198017 -0.555483102798 0.742577254772 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.742680370808 -0.634518027306 0.214039161801 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn 0.714853286743 -0.650683462620 0.256116777658 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.659638285637 -0.392307132483 0.641071319580 -vn 0.303534507751 -0.735307157040 0.605962216854 -vn 0.213522091508 -0.907311439514 0.362207502127 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.320037037134 -0.884738564491 0.338842153549 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.349309086800 -0.879998743534 0.321846753359 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.661074161530 -0.704808950424 0.257342725992 -vn -0.573730945587 -0.763768911362 0.295786827803 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.814631104469 -0.517790317535 0.261284053326 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.351726382971 -0.147820845246 0.924357891083 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.418743818998 -0.453809380531 0.786581635475 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.725175499916 -0.509295403957 0.463399112225 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.518619835377 -0.150040104985 0.841737151146 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.677911162376 -0.171685174108 0.714815080166 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.608457267284 0.157792612910 0.777741134167 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.234294578433 -0.665710151196 0.708474457264 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.459269702435 -0.773269057274 0.437179893255 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.856631577015 0.492435991764 0.153912588954 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.914469540119 -0.242004066706 0.324313849211 -vn -0.358048766851 -0.624385535717 0.694221735001 -vn -0.906540632248 -0.160127803683 0.390567809343 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.684804737568 -0.664337873459 0.299495548010 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.798626184464 -0.023845696822 0.601354777813 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.746172189713 0.359903126955 0.560086369514 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.860423803329 -0.202527076006 0.467604160309 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.809427082539 -0.343396574259 0.476347148418 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.591782271862 -0.301380485296 0.747638642788 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.492519497871 -0.088171571493 0.865823507309 -vn -0.461953103542 0.098662018776 0.881399512291 -vn -0.616403996944 -0.046978741884 0.786027431488 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.819547474384 -0.149944037199 0.553044915199 -vn -0.878214716911 -0.449576526880 0.163155734539 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn -0.550928473473 -0.090877428651 0.829589724541 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.577446520329 -0.303569018841 0.757892727852 -vn -0.675307810307 -0.183331325650 0.714387118816 -vn -0.636181175709 -0.112482629716 0.763296246529 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.748724162579 0.597042918205 -0.288013637066 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.307974070311 0.947956979275 -0.080805882812 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn 0.182218909264 -0.496878981590 0.848473668098 -vn 0.392328858376 -0.721172392368 0.570953965187 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.541634559631 -0.827475488186 0.148041695356 -vn 0.679533302784 -0.730276048183 0.070223495364 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.858834862709 -0.343651831150 -0.379876434803 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.447879314423 -0.893079757690 0.042575549334 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.643597602844 -0.741183161736 -0.190865457058 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.943861186504 -0.260932624340 -0.202583923936 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.767445862293 -0.639363825321 -0.047336645424 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.275597184896 -0.961144804955 0.015710320324 -vn 0.491151094437 -0.666431069374 0.560927987099 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.373320966959 0.424053817987 0.825111985207 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.764400541782 -0.041232846677 0.643421828747 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.816324055195 0.200977146626 0.541500926018 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.378446906805 0.448631554842 0.809634268284 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.087227329612 -0.761248648167 0.642566621304 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.279852241278 -0.486823260784 0.827457427979 -vn -0.328510224819 -0.452966272831 0.828795850277 -vn -0.149849325418 -0.801799178123 0.578500866890 -vn -0.109330229461 0.941514909267 0.318742185831 -vn -0.182598531246 0.715381562710 0.674453139305 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.421047270298 0.334669202566 0.843039572239 -vn -0.109330229461 0.941514909267 0.318742185831 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.485629320145 0.230432748795 0.843246638775 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.421047270298 0.334669202566 0.843039572239 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.453291714191 -0.478627860546 0.751958787441 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.371392548084 -0.273312330246 0.887337565422 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.337292581797 -0.545221269131 0.767442166805 -vn -0.162412509322 -0.601992547512 0.781810164452 -vn -0.086682282388 -0.655554294586 0.750156462193 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn -0.332097560167 0.081697568297 0.939700365067 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.400463789701 -0.304052025080 0.864396393299 -vn -0.225902393460 -0.420675784349 0.878635287285 -vn -0.039725661278 -0.290360718966 0.956092298031 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.724548757076 0.585632026196 -0.363406389952 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.757091164589 -0.360904663801 0.544573962688 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.053172789514 -0.616151213646 0.785830974579 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.464463710785 -0.464943259954 0.753724873066 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn -0.601008892059 -0.672716557980 0.431556135416 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.709319472313 -0.529251933098 0.465573132038 -vn -0.816449046135 -0.409892588854 0.406692773104 -vn -0.249192371964 -0.776740670204 0.578426361084 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.855401635170 -0.481659621000 -0.190504774451 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.754061222076 0.027538735420 -0.656226575375 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn 0.407061606646 0.429488331079 -0.806126892567 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.054847415537 -0.026922827587 -0.998131692410 -vn 0.308949559927 0.079883605242 -0.947717666626 -vn 0.730692684650 -0.553247034550 -0.400007367134 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn -0.022242724895 -0.434845775366 0.900230228901 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.346841216087 -0.535551905632 0.769990444183 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.473556876183 -0.396522194147 0.786456644535 -vn -0.392607510090 -0.288638532162 0.873239457607 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn -0.504324793816 -0.689210057259 0.520236492157 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn -0.081477582455 -0.860848963261 0.502295136452 -vn 0.056576341391 -0.826324164867 0.560345888138 -vn -0.336106806993 -0.668615162373 0.663314402103 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.196567177773 -0.151929289103 0.968647956848 -vn 0.281917303801 -0.331665396690 0.900289237499 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn 0.078508637846 -0.052543114871 0.995527803898 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.436046063900 -0.577629566193 0.690078198910 -vn 0.322791486979 -0.675322711468 0.663132667542 -vn 0.032026510686 -0.155209660530 0.987362265587 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.222196698189 -0.942532956600 0.249520063400 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn 0.011259951629 -0.915645122528 0.401829808950 -vn -0.364636987448 -0.726501166821 0.582439601421 -vn -0.034457810223 -0.800295412540 0.598614990711 -vn 0.893638670444 0.390344947577 -0.221451431513 -vn 0.737706422806 0.663348376751 -0.125531315804 -vn 0.789966821671 0.530356287956 0.307692408562 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.303327411413 0.940892398357 0.150711387396 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.878466308117 0.353272229433 0.321707457304 -vn 0.564451873302 -0.211039349437 0.798032879829 -vn 0.506033003330 0.457370489836 0.731261134148 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.283379137516 0.492464959621 0.822906136513 -vn 0.373320966959 0.424053817987 0.825111985207 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.820009887218 0.179416894913 0.543501019478 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.573140323162 0.155218109488 0.804622590542 -vn 0.391355395317 0.211594060063 0.895582973957 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.395421296358 0.146563902497 0.906730949879 -vn 0.509310722351 0.129563525319 0.850773692131 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.640595257282 0.556611776352 0.528981089592 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.305486649275 0.190570458770 0.932931303978 -vn 0.378446906805 0.448631554842 0.809634268284 -vn 0.535769343376 0.346915453672 0.769805729389 -vn 0.737881243229 0.138341784477 0.660600364208 -vn 0.600012421608 0.673197388649 0.432192444801 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.875085175037 0.284960567951 -0.391182065010 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.894703328609 -0.337323635817 -0.292777568102 -vn 0.987493872643 -0.002295108046 -0.157640531659 -vn 0.882139682770 0.021659230813 -0.470489531755 -vn 0.030576495454 -0.849807500839 0.526205539703 -vn 0.246345400810 -0.477399200201 0.843447685242 -vn -0.100082904100 -0.121986940503 0.987472832203 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.765195369720 -0.226806268096 -0.602523803711 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.626230418682 -0.102859854698 -0.772822916508 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.512817382813 -0.279925793409 -0.811578631401 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.008919883519 -0.227142065763 -0.973820805550 -vn 0.195846781135 -0.780589878559 -0.593568444252 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.544381499290 -0.683503627777 -0.486283451319 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.074802413583 -0.821258544922 -0.565631449223 -vn -0.433612197638 -0.211576133966 -0.875908672810 -vn -0.272886395454 -0.223364964128 -0.935756981373 -vn -0.114821292460 -0.062603108585 -0.991411566734 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.540508806705 -0.812121748924 0.219791963696 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.480690151453 -0.740491211414 0.469691097736 -vn -0.562911212444 -0.417130827904 0.713535487652 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.585892200470 -0.686456024647 0.430706888437 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.767110168934 -0.116551913321 0.630838811398 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.878785669804 -0.475048571825 0.045437283814 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.985003590584 -0.159312814474 0.066237233579 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.894161939621 -0.087291687727 0.439152121544 -vn -0.892477273941 -0.404392063618 0.199878498912 -vn -0.987259328365 -0.150906518102 0.050460640341 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.253314435482 -0.451992571354 0.855297923088 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.534343063831 -0.704809904099 0.466605246067 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.557868421078 -0.657093167305 0.506962835789 -vn -0.262534588575 -0.765424966812 0.587537407875 -vn -0.328291893005 -0.713074207306 0.619475305080 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.738621592522 -0.423740774393 -0.524291872978 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.900035083294 -0.384015738964 -0.206079438329 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.988403439522 -0.062521792948 -0.138382419944 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.871245801449 0.175334334373 -0.458463281393 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.819572389126 0.387809962034 -0.421787351370 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.817677199841 0.405813783407 -0.408312559128 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.750016629696 0.569118261337 -0.337015509605 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.745622813702 0.555361211300 -0.368266910315 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.883379578590 0.453356623650 0.118778400123 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.672420799732 0.229601070285 0.703657329082 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.883379578590 0.453356623650 0.118778400123 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.374333351851 0.575284957886 -0.727270066738 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.745987057686 0.581899583340 -0.323876738548 -vn -0.666667342186 0.591724395752 -0.453229427338 -vn -0.609977424145 0.596584975719 -0.521549582481 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.052916388959 -0.905325412750 0.421409189701 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.308463364840 -0.924584686756 -0.223592355847 -vn -0.529323875904 0.631218016148 -0.566903889179 -vn -0.941008746624 -0.008539366536 -0.338274419308 -vn 0.608978867531 -0.271527022123 -0.745263576508 -vn 0.907390177250 -0.009350413457 -0.420185178518 -vn 0.630308449268 -0.241095229983 -0.737959623337 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.529933810234 0.358376175165 0.768593966961 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.680543184280 0.249560609460 0.688898026943 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.482880949974 0.671260416508 0.562348186970 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.614093124866 0.430214881897 0.661668241024 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.654366791248 0.047013234347 0.754714429379 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.334695070982 0.126260608435 0.933829486370 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.364242702723 -0.054625615478 0.929700672626 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.637862801552 -0.223076045513 0.737135112286 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.001566139865 -0.462129712105 0.886810958385 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.638392686844 -0.365504652262 0.677392899990 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.587673306465 -0.199469223619 0.784125089645 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.246305704117 -0.082893215120 0.965640842915 -vn -0.004930214491 -0.283830404282 0.958861827850 -vn 0.054863095284 0.347303807735 0.936146438122 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.344563275576 0.644585311413 0.682485103607 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.372962445021 0.479036808014 0.794621169567 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.549920439720 0.485596776009 0.679546356201 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.686435878277 0.364511430264 0.629235386848 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.779409170151 0.133687332273 0.612085759640 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.847423136234 -0.037507932633 0.529591500759 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.886623203754 -0.054525546730 0.459267079830 -vn -0.748294830322 0.242019072175 0.617641985416 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.748294830322 0.242019072175 0.617641985416 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.291076213121 0.481702655554 0.826581597328 -vn -0.291076213121 0.481702655554 0.826581597328 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.054863095284 0.347303807735 0.936146438122 -vn 0.148399889469 0.002237849403 0.988924920559 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.148399889469 0.002237849403 0.988924920559 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.334695070982 0.126260608435 0.933829486370 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.521575689316 0.572148561478 0.632933557034 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.386426508427 0.578002810478 0.718740105629 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.403516948223 0.547950804234 0.732750952244 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.427337408066 0.314811915159 0.847511768341 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.854340553284 0.087816275656 0.512240648270 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.190369337797 0.409592747688 0.892184555531 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.137372553349 0.403856068850 0.904449582100 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.270152628422 0.623499035835 0.733666479588 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.270152628422 0.623499035835 0.733666479588 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.023788293824 0.573797225952 0.818651854992 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.023788293824 0.573797225952 0.818651854992 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.190369337797 0.409592747688 0.892184555531 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.882100045681 0.079713657498 0.464268475771 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.762780547142 0.400260478258 0.507895052433 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.916964530945 0.114480897784 0.382191210985 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.863167405128 0.192745745182 0.466681003571 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.193748310208 0.389752209187 0.900308191776 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.080102473497 0.828760683537 0.553840458393 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.217033192515 0.376930564642 0.900455415249 -vn -0.217033192515 0.376930564642 0.900455415249 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.469709098339 0.664078414440 0.581698536873 -vn -0.469709098339 0.664078414440 0.581698536873 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.808123826981 0.439913094044 0.391678839922 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.694979846478 0.558244287968 0.453173667192 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.771863758564 0.521848499775 0.363181054592 -vn 0.057261314243 0.891568779945 0.449250817299 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.411870986223 0.780674993992 0.470009416342 -vn -0.411870986223 0.780674993992 0.470009416342 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.390541195869 0.766919553280 0.509226858616 -vn -0.390541195869 0.766919553280 0.509226858616 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn -0.068840779364 0.560529172421 0.825268447399 -vn -0.068840779364 0.560529172421 0.825268447399 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.143529653549 0.440658539534 0.886125981808 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.011909886263 0.610265195370 0.792107701302 -vn 0.162006527185 0.616976797581 0.770125627518 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.011909886263 0.610265195370 0.792107701302 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.299964487553 0.683094441891 0.665885329247 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.752513349056 0.427093178034 0.501313328743 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.893567860126 0.130850359797 0.429435312748 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.885882377625 0.112097278237 0.450162917376 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.795666098595 0.317581713200 0.515807449818 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.359927237034 0.401224017143 0.842301428318 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.623659551144 0.380152404308 0.683032155037 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.893415629864 0.151184454560 0.423026919365 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.907577753067 0.131067544222 0.398903340101 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.763386487961 0.156498655677 0.626697123051 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.439757525921 0.140757396817 0.887017846107 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.332337766886 0.311493158340 0.890237987041 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.694828391075 0.219617471099 0.684822380543 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.625334560871 -0.238754346967 0.742935419083 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.756767809391 -0.052385684103 0.651581287384 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.727002084255 0.154723718762 0.668975770473 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.305853247643 -0.242935404181 0.920562982559 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.527027726173 -0.021860340610 0.849566876888 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.489686667919 0.504504680634 0.711113214493 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.314739197493 -0.737429022789 0.597609996796 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn -0.028332799673 -0.666234850883 0.745203554630 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.463801503181 -0.757760345936 0.459007054567 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.249539628625 -0.831801772118 0.495818287134 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.343408226967 -0.915781915188 0.208361029625 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.154837504029 -0.986933887005 -0.044574052095 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.127255231142 -0.188344046474 0.973823726177 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.530067265034 0.182262152433 0.828135967255 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.312652051449 -0.927255630493 0.206023424864 -vn 0.494197249413 -0.754905045033 0.431146651506 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn 0.237130910158 -0.530649483204 0.813744485378 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn 0.176475107670 -0.932356715202 0.315543144941 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.393963932991 -0.907506763935 0.145684033632 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.535760462284 -0.485617697239 0.690750479698 -vn -0.804074645042 -0.480982899666 0.349455922842 -vn -0.658694267273 -0.752078175545 0.022367335856 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.315292984247 0.356447100639 0.879508852959 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.307988971472 0.256761282682 0.916087567806 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.265762388706 0.341355532408 0.901580154896 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.266749024391 0.631645679474 0.727920830250 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.420182943344 0.649817228317 0.633390784264 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.526362180710 0.591725170612 0.610576927662 -vn -0.465997457504 0.474939972162 0.746510803699 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.465997457504 0.474939972162 0.746510803699 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.104101993144 0.368369311094 0.923832714558 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.174813181162 0.397422939539 0.900830388069 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.625428259373 0.495156258345 0.603042125702 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.535713851452 0.407568365335 0.739525973797 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.552081704140 0.668588280678 0.498192220926 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.326112389565 0.647804796696 0.688476324081 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.253103345633 0.215464681387 0.943140327930 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.372200131416 0.254434913397 0.892597317696 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.476249128580 0.384410738945 0.790831923485 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.383693754673 0.415092200041 0.824910640717 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.489686667919 0.504504680634 0.711113214493 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.256318479776 0.039006829262 0.965804994106 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.129079088569 0.182803943753 0.974639058113 -vn -0.023426074535 0.341141790152 0.939719915390 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.588860034943 0.466583490372 0.659957349300 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.682675838470 0.530749320984 0.502253770828 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.641178429127 0.678829967976 0.357882797718 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.413006156683 0.495547741652 0.764106214046 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.198482468724 0.114406384528 0.973404288292 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.360481590033 0.133366003633 0.923182845116 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.451417952776 0.277944266796 0.847920298576 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.433118402958 0.408091127872 0.803660452366 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.358566522598 0.428788691759 0.829198598862 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.023426074535 0.341141790152 0.939719915390 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.076032698154 0.722265958786 0.687423348427 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.212365403771 0.248311832547 0.945114910603 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.388789445162 0.349601566792 0.852420985699 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.258582144976 0.059639494866 0.964146435261 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.499279707670 0.194446042180 0.844340264797 -vn -0.647559285164 0.548586845398 0.528885126114 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.591052055359 0.431705445051 0.681386709213 -vn -0.679444611073 0.610277473927 0.407328456640 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.551266074181 0.579253494740 0.600475728512 -vn -0.623957276344 0.639919638634 0.448531210423 -vn -0.485179066658 0.696842193604 0.528216063976 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.068228773773 0.298730581999 0.951895415783 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.189450860023 0.359886229038 0.913559138775 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.312441259623 0.395822644234 0.863542079926 -vn -0.104101993144 0.368369311094 0.923832714558 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.404190242290 0.454529225826 0.793746471405 -vn -0.359362721443 0.378377079964 0.853047013283 -vn -0.125801399350 0.381812900305 0.915637969971 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.148606613278 0.474946022034 0.867376685143 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.012771333568 0.858014822006 0.513466119766 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.485179066658 0.696842193604 0.528216063976 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.429581940174 0.658338308334 0.618101954460 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.076032698154 0.722265958786 0.687423348427 -vn -0.253973126411 0.785078167915 0.564933538437 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.538188695908 0.264146775007 0.800362050533 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.836813807487 0.186702415347 0.514669656754 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.878834486008 0.176552668214 0.443259596825 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.543800532818 0.442923873663 0.712810933590 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.466357082129 0.552756190300 0.690631389618 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.435317426920 0.573959171772 0.693591833115 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.456825613976 0.516326904297 0.724373459816 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.391398638487 0.397019624710 0.830170154572 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267233550549 0.334511578083 0.903708040714 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.067125074565 0.157456219196 0.985242009163 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn -0.068228773773 0.298730581999 0.951895415783 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.761066019535 0.470063358545 0.447011142969 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.734925448895 0.490863144398 0.467908084393 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.698878407478 0.347065120935 0.625391721725 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.591195464134 0.235663145781 0.771330535412 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.434332191944 0.195762410760 0.879222750664 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.267134964466 0.181432187557 0.946425497532 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.202230855823 0.135011807084 0.969986855984 -vn -0.067125074565 0.157456219196 0.985242009163 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.872427821159 0.346370130777 0.344814985991 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.869322419167 0.077864855528 0.488073319197 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.747900903225 -0.163354054093 0.643397033215 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.567458391190 -0.253882825375 0.783284425735 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.351191669703 -0.261454999447 0.899058222771 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn -0.079490303993 -0.281491726637 0.956265509129 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.855607628822 0.333090543747 0.396214872599 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.896722614765 0.179688841105 0.404475569725 -vn -0.891332924366 0.137296840549 0.432059258223 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.901383638382 0.126723989844 0.414063543081 -vn -0.894213795662 0.123666495085 0.430218875408 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.895166754723 0.229004427791 0.382404863834 -vn -0.896939873695 0.210649311543 0.388748884201 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.804847061634 0.546090245247 0.232393324375 -vn -0.753519773483 0.571189284325 0.325500786304 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.423992425203 0.897252678871 0.123158536851 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.371073067188 0.842229127884 0.391094416380 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn 0.066447027028 0.874545276165 0.480370044708 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.160930529237 0.977088928223 0.139278993011 -vn -0.105991713703 0.867368280888 0.486248910427 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.324463427067 -0.758725166321 0.564853608608 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.532799720764 -0.676156878471 0.508857905865 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.744308650494 -0.519166171551 0.420084595680 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.940527975559 -0.179164126515 0.288630217314 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.957346260548 0.170727133751 0.233110263944 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.919281125069 0.197047114372 0.340726643801 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.910739362240 0.261341512203 0.319772452116 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.951893627644 0.165721222758 0.257749825716 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.946807622910 0.193610027432 0.257041752338 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.982647716999 0.016579046845 0.184739291668 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.920943319798 -0.369556844234 0.123657345772 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.666060030460 -0.719265341759 0.197538405657 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.465739727020 -0.826660633087 0.315782696009 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.223995730281 -0.905615508556 0.360120028257 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.992123544216 0.107160180807 0.064866028726 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.900042414665 -0.367482185364 0.234265789390 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.722536802292 -0.635164976120 0.272957891226 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.590967774391 -0.706974327564 0.388515591621 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.370591431856 -0.795985579491 0.478611499071 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.132983490825 -0.834781706333 0.534279823303 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.399518489838 -0.542610168457 0.738890528679 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.533770442009 -0.580261945724 0.615130186081 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.643752753735 -0.493780285120 0.584605395794 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.725106775761 -0.420382618904 0.545434296131 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.867924034595 -0.260958462954 0.422621041536 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.940244019032 -0.092775426805 0.327618628740 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.982467770576 0.013177152723 0.185966104269 -vn -0.977001428604 0.139837592840 0.160977154970 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.999725461006 0.019930899143 0.012318536639 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.994666993618 -0.069035917521 0.076626136899 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.931911706924 -0.215440362692 0.291763722897 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.759057343006 -0.301369190216 0.577068984509 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.602344691753 -0.280756384134 0.747232735157 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.455631524324 -0.168883621693 0.874001264572 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.217910498381 0.339262723923 0.915104269981 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.375407576561 0.093609236181 0.922120630741 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.191797509789 0.434196591377 0.880163073540 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.395720273256 0.369814962149 0.840620219707 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.659957766533 -0.041379831731 0.750162303448 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.837945520878 -0.316482156515 0.444619327784 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.915060877800 -0.357950210571 0.185836642981 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.964661836624 -0.263473212719 -0.003073681612 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.987796187401 -0.113843455911 -0.106294021010 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.989076316357 -0.038925040513 -0.142172202468 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.994616329670 0.103621371090 0.001013222034 -vn -0.964359700680 0.172863632441 -0.200321212411 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.915636658669 0.071842692792 -0.395535230637 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.971966803074 0.001679895911 -0.235112071037 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.746083080769 0.133082449436 -0.652417898178 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.492909461260 -0.012797347270 -0.869986474514 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.427307009697 0.517403364182 0.741419196129 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.535577595234 0.507573664188 0.674926340580 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.773666918278 0.195886433125 0.602551281452 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.898037970066 -0.009601750411 0.439813166857 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.963670790195 -0.085356377065 0.253086805344 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.984421253204 -0.134353876114 0.113419070840 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.997844159603 -0.060008797795 0.026569990441 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.996333360672 0.068236447871 -0.051610436291 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.953527510166 0.177026733756 -0.243817120790 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.760778129101 0.260384917259 -0.594488263130 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.406314909458 0.302539587021 -0.862193703651 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.329013854265 0.770135164261 0.546481192112 -vn -0.452492952347 0.644353330135 0.616489171982 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.398361533880 0.768928885460 0.500056445599 -vn -0.583555281162 0.562829434872 0.585394084454 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.561793684959 0.644772768021 0.518320322037 -vn -0.727042436600 0.392065703869 0.563643276691 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.698581337929 0.486032783985 0.525124967098 -vn -0.818493127823 0.307605028152 0.485230028629 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.762003898621 0.412130415440 0.499498367310 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.876592457294 0.223390161991 0.426242262125 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.839617133141 0.349256485701 0.416008383036 -vn -0.916528403759 0.191852614284 0.350953310728 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.866007030010 0.441917747259 0.233966961503 -vn -0.928365826607 0.321700394154 0.186133533716 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.776705801487 0.629756927490 0.011586484499 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.855468750000 0.511627614498 -0.080065056682 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.523762464523 0.784509122372 -0.331991434097 -vn -0.624914050102 0.641845524311 -0.444428503513 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn -0.206527620554 0.787486314774 -0.580699265003 -vn -0.282768219709 0.664981305599 -0.691261172295 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.016504848376 -0.369534045458 0.929070591927 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn 0.078862175345 -0.381660461426 0.920932173729 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.153125435114 -0.193988814950 0.968979299068 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.410691499710 0.290064156055 0.864404559135 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.140696853399 0.584784626961 0.798893809319 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.027015432715 0.338717550039 0.940500199795 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.027015432715 0.338717550039 0.940500199795 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.279472678900 0.108999013901 0.953946650028 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.553700327873 0.070910565555 0.829691290855 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.769504010677 0.079040892422 0.633731842041 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.677909493446 0.067609973252 0.732029795647 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.606147646904 -0.230062335730 0.761351704597 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.599996566772 -0.402166903019 0.691567718983 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.126013457775 -0.373803198338 0.918907940388 -vn -0.428883343935 -0.397854208946 0.811030864716 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn 0.013011713512 -0.459181368351 0.888247251511 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.084034346044 -0.807875812054 0.583330869675 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn 0.080218009651 -0.410371363163 0.908383429050 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.109498061240 -0.629230618477 0.769466698170 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.063901998103 -0.398544043303 0.914920330048 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.221097260714 -0.580378770828 0.783757925034 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.249645799398 0.220579460263 0.942879438400 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.685548245907 0.317658185959 0.655070185661 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.105937428772 0.694840073586 0.711318850517 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.105937428772 0.694840073586 0.711318850517 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.600660264492 0.792620480061 0.104690179229 -vn -0.069257460535 0.874967575073 0.479202568531 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.266394942999 0.146734341979 0.952629387379 -vn 0.009658423252 0.446354955435 0.894803881645 -vn 0.009658423252 0.446354955435 0.894803881645 -vn -0.069257460535 0.874967575073 0.479202568531 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.266394942999 0.146734341979 0.952629387379 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.265599220991 0.522465229034 0.810238957405 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.537447929382 0.114899255335 0.835432767868 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.446344643831 0.362028479576 0.818359255791 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.685811817646 0.249726369977 0.683592677116 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.504875242710 0.559537291527 0.657281517982 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.710882127285 0.139447763562 0.689348161221 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.336613386869 0.544670164585 0.768131375313 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.630098760128 -0.243901118636 0.737216234207 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.102486148477 -0.211847081780 0.971914291382 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.503107845783 -0.454628795385 0.734979689121 -vn -0.255514144897 -0.578030169010 0.774979770184 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.102777846158 -0.450431048870 0.886875748634 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn -0.273829430342 -0.547039330006 0.791053354740 -vn 0.011388301849 -0.758041679859 0.652106702328 -vn 0.036760635674 -0.803918957710 0.593601703644 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.596428692341 0.562675476074 0.572423934937 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.741860687733 0.398763775826 0.539101243019 -vn -0.745369732380 0.574101984501 0.338866978884 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.719880223274 0.496003329754 0.485544234514 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.774322211742 0.506421625614 0.379423618317 -vn -0.604330658913 0.579120814800 0.547177731991 -vn -0.647695779800 0.510680079460 0.565416753292 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn -0.451884835958 -0.352392107248 0.819524168968 -vn -0.129079088569 0.182803943753 0.974639058113 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.143435344100 0.498812109232 0.854758918285 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.148606613278 0.474946022034 0.867376685143 -vn -0.125801399350 0.381812900305 0.915637969971 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.112893626094 -0.793193936348 0.598413288593 -vn -0.042874984443 -0.941498875618 0.334277719259 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.868730366230 0.328395128250 0.370761603117 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.913611531258 0.350178182125 0.206613779068 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.460474193096 0.810446918011 0.362131565809 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.763267517090 0.574969351292 0.294674217701 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.932681202888 0.163048297167 0.321746885777 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.751718580723 0.003752671881 0.659473359585 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.946365475655 -0.125464737415 0.297743052244 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.391488641500 -0.397782742977 0.829762339592 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.949858725071 -0.240486517549 0.199836567044 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.938949048519 -0.058859646320 0.338984102011 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.437488079071 -0.155996456742 0.885589778423 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.705798804760 0.015210544690 0.708248972893 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.715422451496 0.350363373756 0.604496717453 -vn 0.502289772034 0.579192757607 0.642059743404 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.815317630768 0.471812427044 0.335633963346 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.880656659603 0.431369334459 0.195868119597 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.959631383419 0.240150228143 0.146408542991 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.995585680008 0.084991008043 0.039821058512 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.996004641056 0.086562149227 -0.021949866787 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.921359837055 0.324258625507 0.214364975691 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.637871384621 0.505046308041 0.581419229507 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.382308036089 0.393014520407 0.836289525032 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.332400560379 0.032188046724 0.942588865757 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.723643064499 0.199117779732 0.660827338696 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.646447479725 0.689189255238 0.327297866344 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.712246954441 0.480327963829 0.511848926544 -vn 0.617744982243 0.553522169590 0.558573484421 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.766100347042 0.358995050192 0.533116102219 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.978415131569 0.206477284431 0.008421845734 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.513990104198 0.448301106691 0.731327772141 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.561893999577 0.628997325897 0.537249922752 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.227718770504 0.409422904253 0.883468747139 -vn 0.337808459997 0.583175957203 0.738776862621 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.978925883770 0.200375735760 -0.039417244494 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.870324015617 0.476587593555 0.124098449945 -vn 0.963288187981 0.245665282011 -0.108279429376 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.955230534077 0.294983744621 -0.022786777467 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.193748310208 0.389752209187 0.900308191776 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.573244988918 0.426280379295 0.699767947197 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.080102473497 0.828760683537 0.553840458393 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.581106901169 0.752690315247 0.309470504522 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.693223118782 0.698026776314 0.179444551468 -vn 0.802966713905 0.595613062382 0.022125337273 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.726919829845 0.686512351036 0.016981491819 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.065837807953 0.882237017155 0.466179400682 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.470912784338 0.849372148514 0.238344386220 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.057261314243 0.891568779945 0.449250817299 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.484451025724 0.828598141670 0.280592858791 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.150822833180 0.635599315166 0.757143259048 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.391466438770 0.592203080654 0.704307854176 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.198422238231 0.451261907816 0.870052456856 -vn 0.254763633013 0.450295269489 0.855762600899 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.162006527185 0.616976797581 0.770125627518 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.323617666960 0.631942093372 0.704216420650 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.513759911060 0.724395990372 0.459675103426 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.844890832901 0.527608036995 0.088256470859 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.962731480598 0.260328829288 -0.073327668011 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.971856832504 0.228067263961 -0.058987963945 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.911189258099 0.404794245958 0.076653681695 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.843756496906 0.439300507307 0.308366686106 -vn 0.694763541222 0.453988581896 0.557851195335 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.964206695557 0.249121606350 -0.090795695782 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.970545232296 0.217519640923 -0.103571861982 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.954509973526 0.227643296123 0.192585557699 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.808572351933 0.230919525027 0.541190326214 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.695473253727 0.390722751617 0.603036224842 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.927650451660 0.292795777321 0.231808677316 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.941774845123 -0.162280142307 0.294491648674 -vn 0.976824223995 0.065190963447 0.203873768449 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.932209432125 0.252634704113 0.259155035019 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.750695765018 -0.204045504332 0.628348052502 -vn 0.274623602629 -0.340901017189 0.899093091488 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.881306648254 -0.029563881457 0.471619129181 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.199788928032 -0.930502891541 0.306999534369 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.239685952663 -0.807179331779 0.539455413818 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.530258059502 -0.658419847488 0.534143865108 -vn 0.687712013721 -0.691433250904 0.221296757460 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.721093952656 -0.689267814159 0.070238180459 -vn 0.597214460373 -0.764811575413 0.241656988859 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.569580495358 -0.820051550865 -0.055619228631 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.304680794477 -0.922051012516 -0.238728925586 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.830080926418 0.300810962915 0.469551295042 -vn 0.438327252865 -0.163195595145 0.883875787258 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.060541231185 -0.987986981869 0.142184779048 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn -0.015889639035 -0.856240689754 0.516332685947 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.362986683846 -0.543438851833 0.756911396980 -vn 0.256147146225 -0.944341897964 0.206414595246 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.932668745518 -0.338243275881 -0.125381320715 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.894300460815 -0.354748576880 0.272727280855 -vn 0.595596849918 -0.783921420574 -0.175304144621 -vn 0.705144464970 -0.621076881886 -0.342103481293 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.669635236263 0.465004295111 0.579102456570 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.687887787819 0.334090083838 0.644355654716 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.653526067734 0.407454669476 0.637874901295 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.634473979473 0.589673757553 0.499727547169 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.698470294476 0.581860423088 0.416626513004 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.746993243694 0.532737910748 0.397732883692 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.730922043324 0.457406550646 0.506490111351 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.810685992241 0.490832895041 0.319172859192 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.785306930542 0.420944809914 0.453980714083 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.712920784950 0.650831878185 0.261078268290 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.631312608719 0.613184511662 0.474814802408 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.668137073517 0.285563141108 0.687056422234 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.740139663219 0.363552957773 0.565705299377 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.748942732811 0.480127364397 0.456686407328 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.647795736790 0.509497582912 0.566368162632 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.660879850388 0.615431725979 0.429513245821 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.751814782619 0.542736291885 0.374448657036 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.754177689552 0.626339972019 0.197266981006 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.643801271915 0.761630415916 0.073749937117 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.690789639950 0.523333430290 0.498930633068 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.656909048557 0.151666134596 0.738557994366 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.775538980961 0.183304697275 0.604101538658 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.769935011864 0.395327806473 0.500915110111 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.674992680550 0.544619321823 0.497769713402 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.613109469414 0.536489784718 0.579892635345 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.401266843081 0.378328412771 0.834177792072 -vn 0.212365403771 0.248311832547 0.945114910603 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.721213638783 0.367009401321 0.587498903275 -vn 0.705344974995 0.077326208353 0.704634010792 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.733649730682 0.647041141987 0.207595452666 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.835132360458 0.253148376942 0.488333761692 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.648433148861 0.753310024738 0.109811037779 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.752818822861 0.565508663654 0.336843818426 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.590059459209 0.781824648380 0.201444983482 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.581709802151 0.746405720711 0.323252558708 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.189450860023 0.359886229038 0.913559138775 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.637228786945 0.390339761972 0.664510607719 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.463531196117 0.361015528440 0.809201240540 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.669019818306 0.397284835577 0.628153860569 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.638848066330 0.514054417610 0.572382032871 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.246009349823 0.853070199490 0.460163712502 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.472574830055 0.812009453773 0.342510819435 -vn 0.441359281540 0.799569964409 0.407295793295 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.156517177820 0.758275330067 0.632867217064 -vn 0.055986881256 0.728759109974 0.682477593422 -vn 0.055986881256 0.728759109974 0.682477593422 -vn -0.012771333568 0.858014822006 0.513466119766 -vn 0.246009349823 0.853070199490 0.460163712502 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.818397223949 0.368209451437 0.441189020872 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.959213256836 0.278156578541 0.050387240946 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.966507077217 0.248770341277 -0.063066102564 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.796820223331 0.531731307507 0.286948263645 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.753260552883 0.553977191448 0.354552984238 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.718876957893 0.542798221111 0.434264868498 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.724643111229 0.485672384501 0.488891303539 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.704077363014 0.383839637041 0.597446382046 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.617557048798 0.317419141531 0.719630718231 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.452783286572 0.288476914167 0.843663632870 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.200406655669 0.284720838070 0.937427997589 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.847496092319 0.530518829823 -0.017324548215 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.862550377846 0.504348695278 0.040488097817 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.906684279442 0.350142270327 0.235210523009 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.869828820229 0.229744896293 0.436594873667 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.763165831566 0.176690846682 0.621577203274 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.629935562611 0.152864024043 0.761454999447 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.202230855823 0.135011807084 0.969986855984 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.457086682320 0.133212804794 0.879389643669 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.924294352531 0.355563312769 -0.138761267066 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.998203098774 0.057374663651 0.017284091562 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.950728535652 -0.205100849271 0.232484206557 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.833590924740 -0.306202918291 0.459745496511 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.678838312626 -0.308879584074 0.666162133217 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.464666336775 -0.298411458731 0.833688080311 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.199260234833 -0.289389193058 0.936242103577 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.918455123901 0.385997414589 -0.086291559041 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.959071338177 0.263900458813 -0.102658011019 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.969372093678 0.230969890952 -0.083490356803 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.965679407120 0.234967827797 -0.110695056617 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.968204200268 0.234657734632 -0.086697340012 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.927285432816 0.353592813015 -0.122938469052 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.935479402542 0.335015088320 -0.112441688776 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.731829226017 0.655255794525 -0.187258720398 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.736853659153 0.671932935715 -0.074516959488 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.407246440649 0.894191622734 0.185934543610 -vn 0.311583012342 0.947266399860 -0.074849106371 -vn 0.084336921573 0.993597984314 0.075168356299 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.084336921573 0.993597984314 0.075168356299 -vn -0.025935206562 0.987000048161 0.158613726497 -vn -0.025935206562 0.987000048161 0.158613726497 -vn 0.066447027028 0.874545276165 0.480370044708 -vn 0.220619097352 0.888912618160 0.401449382305 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.518842935562 -0.785850405693 0.336513310671 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.662475109100 -0.725363969803 0.187012910843 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.805370748043 -0.592758417130 -0.003930583131 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.929175615311 -0.269463419914 -0.253026038408 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.939284741879 0.113941721618 -0.323668777943 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.950457096100 0.270852208138 -0.152546450496 -vn 0.934725701809 0.310489326715 -0.172870650887 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.948978900909 0.234526768327 -0.210799112916 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.946819961071 0.235502317548 -0.219250187278 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.895631790161 -0.129716515541 -0.425461292267 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.696239709854 -0.526411354542 -0.487997263670 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.564199924469 -0.795334279537 -0.221634536982 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.489956259727 -0.871741354465 0.003144107526 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.353234022856 -0.919000506401 0.175110846758 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.927901625633 0.165795251727 -0.333931833506 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.672931492329 -0.577748060226 -0.461920291185 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.602797508240 -0.769893229008 -0.209522381425 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.599060893059 -0.799365341663 0.046272549778 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.470746397972 -0.837257504463 0.278204500675 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.295373827219 -0.848388731480 0.439307302237 -vn 0.099432311952 -0.850939333439 0.515766859055 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn -0.011365610175 -0.569823741913 0.821688354015 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.388656109571 -0.596401989460 0.702318370342 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.571297943592 -0.634666800499 0.520400583744 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.693751633167 -0.554435610771 0.459684520960 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.810669839382 -0.437342017889 0.389289557934 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.920904278755 -0.372545152903 0.114653512836 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.969618976116 0.014173090458 0.244209289551 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.888312399387 -0.198640093207 -0.414056956768 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.956887304783 0.187676936388 -0.221684709191 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.935869395733 -0.058511238545 -0.347454905510 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.920701980591 -0.219541355968 -0.322659939528 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.946366429329 -0.292681604624 0.136850625277 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.714061379433 -0.126653254032 0.688531279564 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.496513873339 -0.209683701396 0.842322230339 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.269091695547 -0.158653467894 0.949957251549 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.211031064391 0.334258556366 0.918551623821 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.193377628922 -0.020433094352 0.980911612511 -vn -0.212129950523 0.227813541889 0.950316727161 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.009567377158 0.062936350703 0.997971653938 -vn 0.009567377158 0.062936350703 0.997971653938 -vn -0.211031064391 0.334258556366 0.918551623821 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.252683490515 0.431100577116 0.866200506687 -vn -0.005775345955 0.566921889782 0.823751330376 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.307430177927 0.101323992014 0.946160733700 -vn -0.043281786144 0.417985618114 0.907422006130 -vn -0.043281786144 0.417985618114 0.907422006130 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.307430177927 0.101323992014 0.946160733700 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.681450366974 -0.170108318329 0.711820542812 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.887927532196 -0.283699363470 0.362076491117 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.951872944832 -0.304682195187 -0.033267050982 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.957415223122 -0.181213185191 -0.224761724472 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.969675958157 -0.006265759468 -0.244313865900 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.949974477291 0.187011525035 -0.250150322914 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.826718986034 0.240371182561 -0.508682072163 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.861497342587 0.166910842061 -0.479544728994 -vn 0.942599773407 0.121348172426 -0.311095267534 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.597053110600 0.192763477564 -0.778697490692 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn -0.091410763562 -0.033696297556 -0.995243012905 -vn 0.340949475765 0.080066934228 -0.936665773392 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.118042111397 0.582126080990 0.804484486580 -vn -0.005775345955 0.566921889782 0.823751330376 -vn -0.087644666433 0.797944962978 0.596323907375 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.118042111397 0.582126080990 0.804484486580 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.022682305425 0.700176298618 0.713609576225 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.421086013317 0.331745862961 0.844174861908 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.655123889446 0.148886278272 0.740706145763 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.835974216461 0.060734994709 0.545397460461 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.931944012642 -0.003060617950 0.362589240074 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.956516206264 0.125038489699 0.263518750668 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.927957713604 0.333342611790 0.166664868593 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.898776412010 0.424006968737 -0.111440964043 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.699897587299 0.400653809309 -0.591286659241 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn -0.028911255300 0.248572260141 -0.968181788921 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.365882277489 0.343775957823 -0.864840030670 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.022682305425 0.700176298618 0.713609576225 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.087644666433 0.797944962978 0.596323907375 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.158913969994 0.649801671505 0.743306219578 -vn -0.021405575797 0.810315549374 0.585602700710 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.158913969994 0.649801671505 0.743306219578 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.135182872415 0.733623564243 0.665974557400 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.326081156731 0.529603064060 0.783065557480 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.297315388918 0.622704029083 0.723770201206 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.470974206924 0.477889269590 0.741488456726 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.573665559292 0.416753500700 0.705141365528 -vn 0.389200001955 0.573539316654 0.720816195011 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.639803349972 0.412074059248 0.648726940155 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.507545232773 0.531004428864 0.678551495075 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.580223083496 0.617204606533 0.531412839890 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.654379069805 0.572576820850 0.493906706572 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.628654718399 0.752240359783 0.197300985456 -vn 0.527233898640 0.796128153801 0.296992242336 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.416550189257 0.902303695679 -0.111058652401 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.553518593311 0.789642274380 -0.264730513096 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.250042259693 0.829527139664 -0.499363213778 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.031884565949 0.757848381996 -0.651651144028 -vn 0.011481816880 0.636885046959 -0.770873308182 -vn 0.304938465357 0.703848004341 -0.641568779945 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.377220094204 -0.226272672415 0.898056626320 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.274269640446 -0.322407662868 0.905996382236 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.564134895802 -0.143683999777 0.813084661961 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.646276831627 0.492995202541 0.582479178905 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.184095010161 0.707548022270 0.682264506817 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.297506958246 0.235928297043 0.925109446049 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.693422079086 0.040879141539 0.719371080399 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.916819691658 0.095807664096 0.387637108564 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.978968083858 0.184593155980 0.086872689426 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.945089697838 0.192533746362 0.264076173306 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.932904720306 -0.147877126932 0.328361213207 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.940850913525 -0.294875055552 0.166878074408 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.639572858810 -0.175081178546 0.748527288437 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.898053467274 -0.229784309864 0.375098794699 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.348717659712 -0.799128830433 0.489682704210 -vn 0.378185003996 -0.403165251017 0.833326995373 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.340711802244 -0.641201555729 0.687587082386 -vn 0.229054272175 -0.404233902693 0.885510623455 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.487048745155 -0.694580614567 0.529472649097 -vn 0.420370161533 -0.418006032705 0.805332183838 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.744322121143 0.657111704350 0.119116656482 -vn 0.490524053574 0.461309880018 0.739310026169 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.141101598740 0.945256769657 -0.294244796038 -vn 0.027354190126 0.848339557648 0.528745472431 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.425227582455 0.791610717773 0.438786923885 -vn -0.089801914990 0.986447930336 0.137317344546 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.217779934406 0.618968546391 0.754619002342 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.425227582455 0.791610717773 0.438786923885 -vn 0.648735523224 0.337128430605 0.682265818119 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.706862568855 0.568781375885 0.420515179634 -vn 0.868949472904 0.298117607832 0.395035088062 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.647108733654 0.750588536263 0.133668154478 -vn 0.882189989090 0.458903372288 0.105586610734 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.330178469419 0.915636241436 0.229330360889 -vn 0.903099119663 0.412203252316 0.120418034494 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.677508771420 -0.232246801257 0.697884857655 -vn 0.961342573166 -0.171136543155 0.215714603662 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.647285282612 -0.671119987965 0.361413508654 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.865472078323 -0.445646405220 0.228817224503 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.388192862272 -0.845675826073 0.366249561310 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.758167684078 -0.502615153790 0.415403187275 -vn 0.602071702480 -0.417796939611 0.680408239365 -vn 0.336075752974 -0.870628416538 0.359248220921 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.666646242142 0.745317161083 -0.009225846268 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.839728236198 0.539731502533 0.059551939368 -vn 0.708084583282 0.692552626133 0.137793600559 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.713051259518 0.673798978329 0.193785592914 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.753422796726 0.657339215279 -0.016101408750 -vn 0.733347594738 0.675600945950 0.075925514102 -vn 0.750932097435 0.635434091091 0.179790079594 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.854356050491 -0.257476896048 0.451421499252 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.284206509590 -0.519967913628 0.805518448353 -vn 0.256318479776 0.039006829262 0.965804994106 -vn 0.561187684536 0.239976942539 0.792136013508 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.464831054211 0.394190609455 0.792808830738 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.421305626631 0.513768494129 0.747357726097 -vn 0.143435344100 0.498812109232 0.854758918285 -vn 0.174813181162 0.397422939539 0.900830388069 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.247673124075 -0.940627634525 0.232115536928 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.375306636095 -0.805032193661 0.459421426058 -vn 0.138890832663 -0.801826655865 0.581191301346 -vn 0.116708174348 -0.953639626503 0.277399748564 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.316775918007 -0.082177042961 -0.944933831692 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.936159014702 -0.063873127103 -0.345726042986 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.821858465672 0.073336854577 0.564951658249 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.909234404564 -0.117803066969 0.399268388748 -vn -0.905587971210 0.151429876685 0.396206259727 -vn -0.791023254395 0.166800767183 0.588608264923 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.905587971210 0.151429876685 0.396206259727 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.042918991297 -0.159098654985 -0.986329317093 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.398862630129 -0.116559632123 -0.909572660923 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.577902257442 -0.002421748824 -0.816102385521 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.647427976131 0.019929872826 -0.761865973473 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.761567533016 -0.045328486711 -0.646498441696 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.949094235897 0.007942831144 -0.314892143011 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.963914513588 0.155681833625 0.215944394469 -vn 0.997646987438 0.040396459401 -0.055394966155 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.933379650116 0.281861096621 0.222163870931 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.940660119057 0.304994046688 0.148785516620 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.945739746094 0.324362844229 -0.019108049572 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.937179505825 0.337875336409 -0.086803659797 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.891787886620 0.452209621668 -0.014860952273 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.781435728073 0.546684145927 0.300823241472 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.506390750408 0.538258075714 0.673681437969 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.506390750408 0.538258075714 0.673681437969 -vn -0.299555271864 0.546643376350 0.781951189041 -vn 0.159534424543 0.524704039097 0.836202383041 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.073365107179 0.805665493011 0.587810039520 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.889801084995 0.299412399530 0.344392567873 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.808350086212 0.203630700707 0.552362799644 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.874613881111 0.251075208187 0.414743065834 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.899425983429 0.198404535651 0.389446407557 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900945067406 0.305853515863 0.307817548513 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.950938582420 0.160574719310 -0.264445781708 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.882616877556 0.102173909545 -0.458855003119 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.643136858940 0.096314810216 -0.759669959545 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.320609718561 0.092053167522 -0.942727744579 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.935305595398 0.353835970163 0.001867453801 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.971110105515 0.234779074788 -0.042708016932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.690404534340 0.159054651856 -0.705721735954 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.649252891541 0.146428629756 -0.746343970299 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.458819925785 0.122962743044 -0.879979789257 -vn 0.051589123905 0.106985323131 -0.992921292782 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.894793391228 0.437213540077 -0.090493924916 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.682536661625 0.380229771137 -0.624154686928 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.468114078045 0.390638738871 -0.792635202408 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.082577347755 0.397961974144 -0.913677871227 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.300105422735 0.398083269596 -0.866871654987 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.618252098560 0.372385114431 -0.692165970802 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.870385944843 0.337260872126 -0.358724743128 -vn -0.954860091209 0.286923676729 -0.076921768486 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.900584936142 0.356063216925 0.249330729246 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.911430358887 0.392372965813 0.123847253621 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.879127502441 0.464078336954 0.108471810818 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.851247549057 0.477446943521 0.217765927315 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.073365107179 0.805665493011 0.587810039520 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.384399235249 0.833342432976 0.397212386131 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.583706438541 0.802595734596 0.122991107404 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.709767103195 0.697536826134 -0.098351791501 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.824468553066 0.518499433994 -0.226737543941 -vn 0.749483346939 0.541744291782 -0.380509972572 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.509359657764 0.645855545998 -0.568703174591 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.113862566650 0.711150884628 -0.693757712841 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.233893856406 0.712710499763 -0.661314904690 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.524419128895 0.664470672607 -0.532412707806 -vn -0.801686048508 0.561523139477 -0.204917788506 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.761753618717 0.646870017052 -0.035924945027 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.473680764437 0.825297594070 -0.307425469160 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.166509822011 0.881523549557 -0.441803902388 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.261811822653 0.863229155540 -0.431613206863 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.646529257298 0.697131037712 -0.309851974249 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.598942220211 0.781105816364 -0.176470771432 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.530289411545 0.847510576248 -0.022779457271 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.320996463299 0.929820060730 0.179988548160 -vn 0.203431159258 0.979057490826 0.007884264924 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.288760930300 0.908043682575 0.303436666727 -vn 0.022177392617 0.949803769588 0.312059193850 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.288760930300 0.908043682575 0.303436666727 -vn -0.707089662552 0.699392676353 0.104278922081 -vn -0.584631860256 0.788804054260 0.189720153809 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.707089662552 0.699392676353 0.104278922081 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.009512823075 0.999211311340 0.038552604616 -vn 0.203431159258 0.979057490826 0.007884264924 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.250993162394 0.964091360569 0.086776979268 -vn -0.009512823075 0.999211311340 0.038552604616 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn 0.271936625242 0.949670791626 -0.155485764146 -vn 0.281529068947 0.918153464794 -0.278811126947 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.121225893497 0.952505052090 -0.279353648424 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.440613836050 0.886203765869 -0.143186286092 -vn -0.406076490879 0.913435757160 -0.027146851644 -vn -0.078651353717 0.986206769943 -0.145637229085 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.231967061758 -0.233555212617 0.944268643856 -vn 0.221423864365 -0.754890739918 0.617342233658 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.546610355377 -0.258020311594 0.796644628048 -vn 0.349241763353 -0.781512439251 0.516980171204 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.830623030663 -0.231687158346 0.506346166134 -vn 0.408381432295 -0.796557366848 0.445781260729 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.427210748196 -0.706106841564 0.564715921879 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.918158710003 -0.240577429533 0.314812809229 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.428907752037 -0.443769127131 0.786833584309 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.873789131641 -0.168129771948 0.456316709518 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.417140841484 -0.120375834405 0.900834739208 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.813842773438 0.072670906782 0.576523065567 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.424012660980 0.031315691769 0.905114650726 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.769383728504 0.143628954887 0.622430264950 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.395210921764 0.116690479219 0.911148548126 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.705974459648 0.211807489395 0.675823688507 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn 0.655949294567 -0.360590577126 0.663102567196 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.683387815952 -0.673397064209 0.281988471746 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn 0.633489966393 -0.757112979889 -0.159594580531 -vn -0.017104798928 -0.994401037693 0.104278236628 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn 0.408531010151 -0.740816414356 -0.533191740513 -vn -0.089078962803 -0.979717195034 -0.179496884346 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn -0.141694068909 -0.964558184147 -0.222599074244 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.352352052927 -0.675574064255 -0.647647798061 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn -0.164628922939 -0.971865355968 -0.168449014425 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.264879673719 -0.680946111679 -0.682752609253 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn -0.106762722135 -0.991933047771 -0.068341821432 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.212482243776 -0.757902085781 -0.616794705391 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.079081669450 -0.841114282608 -0.535044729710 -vn 0.032250907272 -0.990156650543 0.136197254062 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn 0.086438052356 -0.988402068615 0.124859288335 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.155002683401 -0.764973640442 -0.625131547451 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn 0.156755745411 -0.987137198448 0.031429961324 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn 0.171683400869 -0.948143720627 -0.267485111952 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.494367212057 -0.821183621883 -0.285058826208 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn 0.200182467699 -0.979581654072 -0.018621146679 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.462283223867 -0.884084403515 0.068476572633 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.353442579508 -0.812535405159 0.463534832001 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.105939380825 0.093255937099 0.989989995956 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.279677391052 -0.181245908141 0.942831099033 -vn -0.304022520781 0.155782133341 0.939841628075 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.304022520781 0.155782133341 0.939841628075 -vn -0.365280956030 0.082129344344 0.927267253399 -vn 0.091720648110 -0.006141365506 0.995765864849 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.365280956030 0.082129344344 0.927267253399 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn 0.074245169759 -0.239324852824 0.968096733093 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.442798525095 -0.048629581928 0.895301401615 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.011659302749 -0.585357308388 0.810691654682 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.602641165257 -0.246796503663 0.758890688419 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn -0.097086712718 -0.792906105518 0.601559698582 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.014092958532 -0.790904879570 0.611776828766 -vn -0.182521164417 -0.203338980675 0.961945593357 -vn -0.532182991505 -0.286137044430 0.796810448170 -vn 0.105939380825 0.093255937099 0.989989995956 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn -0.004304377362 -0.913099169731 0.407714813948 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn -0.924340128899 0.360457271338 0.125163570046 -vn -0.960693836212 0.275875806808 -0.030982023105 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.924340128899 0.360457271338 0.125163570046 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.906805396080 0.355602860451 -0.226385816932 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.943933427334 0.166785299778 -0.284907698631 -vn 0.817821025848 0.123250223696 -0.562119364738 -vn 0.783317208290 0.248922675848 -0.569606602192 -vn 0.791172683239 0.410195678473 -0.453635632992 -vn 0.746720135212 0.375254184008 -0.549175143242 -vn 0.830051660538 0.501415014267 -0.244125440717 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.975682437420 0.182560175657 -0.121307574213 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.984978437424 -0.148210123181 -0.088606998324 -vn -0.977963626385 -0.174421295524 0.114736154675 -vn -0.974032580853 0.165303468704 0.154710352421 -vn -0.339267462492 0.787710845470 0.514207422733 -vn -0.665048420429 0.670540630817 0.328764200211 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.705455362797 0.442646503448 0.553531229496 -vn -0.299555271864 0.546643376350 0.781951189041 -vn -0.339267462492 0.787710845470 0.514207422733 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.479634582996 -0.732783257961 -0.482679367065 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn 0.129998713732 -0.981209576130 -0.142576515675 -vn 0.160609349608 -0.944374680519 -0.286986321211 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn -0.284915238619 -0.800749540329 -0.526899874210 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.436591178179 -0.710123062134 -0.552370667458 -vn -0.815816044807 -0.033233188093 -0.577355861664 -vn -0.587253093719 -0.116071887314 -0.801037490368 -vn 0.236537411809 -0.417193204165 0.877496361732 -vn 0.395210921764 0.116690479219 0.911148548126 -vn -0.016325036064 -0.353321343660 0.935359537601 -vn 0.324508875608 -0.535487234592 0.779709815979 -vn 0.365930229425 -0.888301491737 0.277516782284 -vn 0.344442546368 -0.215144351125 0.913822889328 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.215249896049 0.259879410267 0.941344857216 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.676891267300 0.478440582752 0.559386134148 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.277345180511 0.887103021145 -0.368955165148 -vn -0.347879409790 0.817592084408 0.458827942610 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.254123061895 0.426116853952 0.868242979050 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.384487777948 0.887601256371 0.253639906645 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.347879409790 0.817592084408 0.458827942610 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.923225998878 0.380098938942 0.056378662586 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718087673187 0.217695534229 -0.661028504372 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.056213334203 0.268312811852 -0.961690306664 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.530799150467 0.680233538151 -0.505504250526 -vn 0.384487777948 0.887601256371 0.253639906645 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.201308771968 0.240931555629 0.949434995651 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.685477375984 0.462024539709 0.562720298767 -vn -0.240289658308 0.320749431849 0.916177213192 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.653510272503 0.565980076790 0.502584218979 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.680037975311 0.480506420135 0.553770661354 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.219177588820 0.295268416405 0.929934263229 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.225854665041 0.275281429291 0.934456944466 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.680287778378 0.480499923229 0.553469419479 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.254123061895 0.426116853952 0.868242979050 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.240289658308 0.320749431849 0.916177213192 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.225854665041 0.275281429291 0.934456944466 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.949123442173 -0.061713241041 0.308797955513 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.921951174736 -0.151050478220 0.356636703014 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.907250344753 -0.188964352012 0.375751674175 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn -0.718620479107 -0.362539023161 -0.593422293663 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn -0.688484191895 -0.460392743349 -0.560382068157 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn -0.695992946625 -0.460888862610 -0.550613582134 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.226011291146 -0.206536710262 -0.951977670193 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.236712202430 -0.296670228243 -0.925177872181 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.224680751562 -0.257442176342 -0.939809620380 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.881881117821 0.258271634579 -0.394438207150 -vn 0.653510272503 0.565980076790 0.502584218979 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.916761815548 0.175430729985 -0.358847975731 -vn 0.680037975311 0.480506420135 0.553770661354 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.904699862003 0.220005586743 -0.364850312471 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.676891267300 0.478440582752 0.559386134148 -vn 0.658345997334 0.509523391724 0.554045557976 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.211771011353 0.234253704548 0.948829948902 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.213284403086 0.286679387093 0.933983266354 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.750280976295 0.265666365623 0.605392277241 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.520998537540 -0.756937682629 0.394469082355 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.523602247238 -0.757869243622 0.389197736979 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.585367500782 -0.787940621376 0.191035225987 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.588895976543 -0.784702122211 0.193504810333 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.428356975317 -0.900839090347 0.070705041289 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.425227791071 -0.902204632759 0.072167634964 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.244827017188 -0.958182632923 0.148140966892 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.247534096241 -0.957624971867 0.147245749831 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn 0.238857537508 -0.902638971806 0.358036190271 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.239870905876 -0.901330232620 0.360646307468 -vn 0.333805084229 -0.795262694359 0.506094276905 -vn 0.340784788132 -0.793341636658 0.504454910755 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.351152896881 0.896278381348 -0.270881265402 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.349539011717 0.894979357719 -0.277190327644 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.315098047256 0.909006059170 -0.272802501917 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.314274698496 0.905051290989 -0.286554604769 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.324795067310 0.917077064514 -0.231252595782 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.327561646700 0.916575074196 -0.229332759976 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.376637071371 0.902566313744 -0.208610922098 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.376510679722 0.902412891388 -0.209500908852 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn -0.409135401249 0.882911443710 -0.230381488800 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.404935628176 0.884113430977 -0.233175009489 -vn -0.380583465099 0.884880721569 -0.268593341112 -vn -0.389907628298 0.882185220718 -0.264047831297 -vn 0.570412695408 0.657898664474 0.491730272770 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.227320805192 0.221673280001 0.948254287243 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.699121236801 0.428781896830 0.572167456150 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.892048120499 0.221571207047 -0.393898874521 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn 0.232417941093 -0.321322321892 -0.918005347252 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.622993707657 -0.581864595413 -0.522792935371 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.857758522034 -0.317021489143 0.404657512903 -vn -0.227320805192 0.221673280001 0.948254287243 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.153622061014 0.138630852103 0.978356659412 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.551810741425 0.698545396328 0.455564767122 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.257132411003 0.416455388069 0.872036576271 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.917856097221 -0.143156483769 0.370197772980 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn -0.723487615585 -0.324982106686 -0.609058499336 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.159523501992 -0.123263031244 -0.979468464851 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.838533520699 0.315829396248 -0.443974435329 -vn 0.551810741425 0.698545396328 0.455564767122 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.543161213398 0.695157170296 0.470884680748 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.263800501823 0.365938633680 0.892467498779 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.570412695408 0.657898664474 0.491730272770 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.760976850986 0.469329386950 -0.447933167219 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn 0.106153875589 -0.007835450582 -0.994318842888 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.749192118645 -0.260680377483 -0.608898103237 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.945832312107 -0.043938733637 0.321668446064 -vn -0.263800501823 0.365938633680 0.892467498779 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.117148451507 0.034600071609 0.992511510849 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.706371426582 0.398818373680 0.584793448448 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.117148451507 0.034600071609 0.992511510849 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.153622061014 0.138630852103 0.978356659412 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.773168981075 -0.442755550146 0.454067409039 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.809115707874 -0.377030491829 0.450754731894 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn -0.578914999962 -0.647734820843 -0.495274722576 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn -0.639346003532 -0.562029004097 -0.524747669697 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.266819119453 -0.410633623600 -0.871887385845 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.238241240382 -0.329128980637 -0.913736939430 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.933817505836 0.069771841168 -0.350879937410 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.923433840275 0.129846125841 -0.361123204231 -vn 0.706371426582 0.398818373680 0.584793448448 -vn 0.750280976295 0.265666365623 0.605392277241 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.332089483738 -0.877025306225 0.347193360329 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn 0.193432345986 -0.589852690697 0.784001111984 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.295678406954 -0.832099795341 0.469237923622 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn -0.115704677999 -0.992193222046 -0.046530377120 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.416424691677 -0.838034331799 -0.352546423674 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.812869012356 -0.581592381001 0.031531836838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.690424919128 -0.371962577105 0.620449244976 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.168904587626 0.153192564845 0.973654627800 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.696267127991 0.416324853897 0.584709942341 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.163892567158 0.169382914901 0.971827507019 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.869695901871 -0.274154037237 0.410449296236 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.680004060268 -0.465699821711 -0.566319882870 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.207809269428 -0.215856730938 -0.954055130482 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn 0.696267127991 0.416324853897 0.584709942341 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.899366557598 0.232333302498 -0.370352536440 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.804239809513 -0.440206110477 0.399270415306 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473620533943 -0.329276412725 -0.816860198975 -vn -0.473841011524 -0.329637020826 -0.816586852074 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.526769578457 0.236967489123 -0.816308915615 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.847266793251 0.458697319031 -0.267835289240 -vn 0.838858008385 0.494629532099 0.227285787463 -vn 0.804961979389 0.551999032497 0.217562019825 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.069586545229 0.022697513923 0.997317671776 -vn -0.499279826880 -0.238045200706 0.833099126816 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn -0.662377238274 -0.626874268055 0.410225600004 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.512087404728 -0.264961868525 -0.817044496536 -vn -0.522163152695 -0.246549248695 -0.816430747509 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.382704496384 0.445656538010 -0.809275925159 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.730786740780 0.610652327538 -0.305048257113 -vn 0.804961979389 0.551999032497 0.217562019825 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn 0.048752576113 -0.154843926430 0.986735284328 -vn -0.382990270853 -0.432740062475 0.816121637821 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn -0.342832326889 -0.903053998947 0.258765399456 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.644643008709 -0.127199381590 -0.753827393055 -vn -0.654632925987 -0.115691319108 -0.747041642666 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn -0.013651727699 0.782738447189 -0.622201085091 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.435036271811 0.891461074352 -0.126651614904 -vn 0.662259042263 0.684042572975 0.305775582790 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.393361032009 -0.415148884058 0.820316076279 -vn 0.010212839581 -0.767236471176 0.641283035278 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.048680081964 -0.994659066200 -0.091014303267 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.801242232323 -0.099859014153 -0.589948415756 -vn -0.803988158703 -0.094470322132 -0.587093174458 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn -0.451572537422 0.873713314533 -0.180851474404 -vn 0.089037470520 0.972759723663 0.214034825563 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.089037470520 0.972759723663 0.214034825563 -vn 0.490652501583 0.740379989147 0.459453642368 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.712795853615 -0.526864945889 0.462963700294 -vn 0.435790151358 -0.874335944653 0.213596761227 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.251401871443 -0.758408725262 -0.601342916489 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.885544598103 -0.229386016726 -0.403971284628 -vn -0.893262147903 -0.230714723468 -0.385815322399 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.715602040291 0.563986122608 0.412108510733 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.038355976343 0.223484531045 0.973952531815 -vn -0.079347580671 0.714547991753 0.695071995258 -vn -0.079347580671 0.714547991753 0.695071995258 -vn 0.405009925365 0.626119792461 0.666288971901 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.959425985813 -0.281454920769 -0.016879195347 -vn 0.702698290348 -0.607031822205 -0.371116548777 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.135830551386 -0.277985215187 -0.950933396816 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846942424774 -0.425363630056 -0.318989604712 -vn -0.846260547638 -0.440019220114 -0.300376683474 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn -0.579691588879 -0.009793659672 0.814777135849 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.038355976343 0.223484531045 0.973952531815 -vn 0.449782669544 0.419279068708 0.788606762886 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.915183722973 0.209073305130 -0.344568014145 -vn 0.622677326202 -0.050570812076 -0.780842840672 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.197052255273 0.120570488274 -0.972950756550 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.756549417973 -0.568829655647 -0.322592258453 -vn -0.748504459858 -0.580423593521 -0.320701569319 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn -0.239331066608 -0.482139617205 0.842770457268 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.298763692379 -0.113984473050 0.947495520115 -vn 0.573455870152 0.261886984110 0.776249706745 -vn 0.675563931465 0.163798823953 0.718876481056 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.657979726791 0.678265154362 -0.327137589455 -vn 0.307854622602 0.464908808470 -0.830111622810 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.438953995705 0.307949036360 -0.844089329243 -vn -0.514398455620 0.378968864679 -0.769270300865 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn -0.600282192230 -0.662484288216 -0.448080182076 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.631202220917 -0.677794516087 -0.377065479755 -vn -0.577075004578 -0.720137119293 -0.385210335255 -vn -0.556825041771 -0.704007327557 -0.440816938877 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.223079264164 -0.842810750008 0.489801704884 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.107150927186 -0.772752523422 0.625597476959 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.769818246365 0.161918729544 0.617383360863 -vn 0.684020638466 -0.337137818336 0.646880090237 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.518678426743 -0.327887445688 0.789596378803 -vn 0.675563931465 0.163798823953 0.718876481056 -vn 0.769818246365 0.161918729544 0.617383360863 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn 0.298304438591 0.947766005993 -0.112933620811 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn 0.393360197544 0.904708862305 -0.163614228368 -vn -0.015659844503 0.758790850639 -0.651146113873 -vn -0.137769415975 0.828296601772 -0.543087780476 -vn -0.218723073602 0.307124495506 0.926193714142 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.676530897617 0.479380965233 0.559016883373 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.218723073602 0.307124495506 0.926193714142 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.221647694707 0.312501966953 0.923696279526 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.917439937592 -0.170511052012 0.359485685825 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.919012665749 -0.163916215301 0.358534842730 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn -0.670401155949 -0.457893431187 -0.583862960339 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn -0.681730031967 -0.466094911098 -0.563914597034 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.232400774956 -0.280038267374 -0.931433558464 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.231879636645 -0.296164631844 -0.926562666893 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.682748973370 0.479876726866 0.550973832607 -vn 0.908105671406 0.180472493172 -0.377854198217 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.917508840561 0.192104980350 -0.348242968321 -vn 0.676530897617 0.479380965233 0.559016883373 -vn 0.682748973370 0.479876726866 0.550973832607 -vn -0.231893524528 0.286410689354 0.929620504379 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.681994259357 0.479156374931 0.552533268929 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.231893524528 0.286410689354 0.929620504379 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.219177588820 0.295268416405 0.929934263229 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.909621715546 -0.186995491385 0.370973020792 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.909907639027 -0.179549068213 0.373938739300 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn -0.691403150558 -0.464157193899 -0.553642272949 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn -0.683602571487 -0.461759626865 -0.565212845802 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.232408687472 -0.262927412987 -0.936405539513 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.236520305276 -0.263811916113 -0.935126423836 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.907337546349 0.210294201970 -0.364025950432 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.908501267433 0.201881110668 -0.365881800652 -vn 0.681994259357 0.479156374931 0.552533268929 -vn 0.680287778378 0.480499923229 0.553469419479 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.206624403596 0.240915045142 0.948296546936 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.673861861229 0.474872797728 0.566044211388 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.206624403596 0.240915045142 0.948296546936 -vn -0.215249896049 0.259879410267 0.941344857216 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.895451784134 -0.211260989308 0.391835272312 -vn -0.900530099869 -0.196758732200 0.387726187706 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn -0.692713320255 -0.448291033506 -0.564963161945 -vn -0.691453754902 -0.450606733561 -0.564663827419 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.203994378448 -0.226881235838 -0.952318847179 -vn 0.218465223908 -0.238150179386 -0.946338951588 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.673861861229 0.474872797728 0.566044211388 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.685477375984 0.462024539709 0.562720298767 -vn 0.892602801323 0.230994895101 -0.387171238661 -vn 0.898511350155 0.228213340044 -0.374961405993 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.206473186612 0.250022917986 0.945968985558 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.682193696499 0.466817051172 0.562755405903 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.206473186612 0.250022917986 0.945968985558 -vn -0.201308771968 0.240931555629 0.949434995651 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.892609059811 -0.207406908274 0.400289177895 -vn -0.892966151237 -0.215754017234 0.395046353340 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn -0.697274863720 -0.451277852058 -0.556916594505 -vn -0.690826892853 -0.451026529074 -0.565095782280 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.194074183702 -0.230058833957 -0.953628957272 -vn 0.197611436248 -0.226847842336 -0.953671753407 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.682193696499 0.466817051172 0.562755405903 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.672250747681 0.474375575781 0.568372070789 -vn 0.889703333378 0.238144084811 -0.389506608248 -vn 0.888792514801 0.234837070107 -0.393572568893 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.226969450712 0.276726186275 0.933759868145 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.665205776691 0.510107040405 0.545244932175 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.226969450712 0.276726186275 0.933759868145 -vn -0.213284403086 0.286679387093 0.933983266354 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.892012178898 -0.212036281824 0.399192839861 -vn -0.895926833153 -0.207023650408 0.393009245396 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn -0.682163417339 -0.476584762335 -0.554544925690 -vn -0.678995072842 -0.478009134531 -0.557201027870 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.213831633329 -0.244800299406 -0.945700168610 -vn 0.207553997636 -0.256860315800 -0.943898379803 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.665205776691 0.510107040405 0.545244932175 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.658345997334 0.509523391724 0.554045557976 -vn 0.887191772461 0.243261545897 -0.392064481974 -vn 0.884813129902 0.235721811652 -0.401921570301 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.272610336542 0.367797374725 0.889049291611 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.670803904533 0.475809752941 0.568882465363 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.272610336542 0.367797374725 0.889049291611 -vn -0.211771011353 0.234253704548 0.948829948902 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.960054516792 0.049479231238 0.275403499603 -vn -0.885972619057 -0.237013354897 0.398594051600 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn -0.770698904991 -0.121819429100 -0.625446438789 -vn -0.680139005184 -0.469099432230 -0.563344180584 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.055108718574 0.101982802153 -0.993258535862 -vn 0.217604622245 -0.205104112625 -0.954243421555 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.670803904533 0.475809752941 0.568882465363 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.543161213398 0.695157170296 0.470884680748 -vn 0.722058236599 0.512534260750 -0.464693993330 -vn 0.886675596237 0.257487684488 -0.384065717459 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.700519919395 0.417314112186 0.578896164894 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.056536089629 -0.104562290013 0.992910087109 -vn -0.168904587626 0.153192564845 0.973654627800 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.720583796501 -0.519040763378 0.459734320641 -vn -0.857704401016 -0.305203676224 0.413755863905 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn -0.532744526863 -0.732410252094 -0.423979341984 -vn -0.669463574886 -0.488497883081 -0.559632301331 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.325455516577 -0.477934837341 -0.815878033638 -vn 0.219654008746 -0.233781188726 -0.947152853012 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.700519919395 0.417314112186 0.578896164894 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.764939725399 0.154692605138 0.625249862671 -vn 0.955836892128 -0.063799977303 -0.286889135838 -vn 0.905991435051 0.192221090198 -0.377134740353 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.874474585056 -0.312890410423 -0.370666712523 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.825260698795 -0.564096808434 -0.027195354924 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.043186146766 -0.834612667561 -0.549141705036 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.289707869291 -0.616199791431 -0.732370913029 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.802102267742 -0.378115504980 -0.462234377861 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.038995340466 -0.702562272549 -0.710553050041 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn 0.335055351257 -0.725507557392 -0.601146161556 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.839455544949 0.190680772066 0.508876383305 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.686181128025 0.609030485153 0.397790521383 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.803459405899 0.538893818855 0.253074049950 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.800493359566 0.529156804085 0.281431138515 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.658253967762 0.476895362139 0.582471072674 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.936452150345 0.213357940316 0.278452545404 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.985347628593 -0.062460951507 0.158709406853 -vn 0.949053943157 0.121953181922 0.290558248758 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.616893053055 0.346695452929 0.706572890282 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.603666186333 0.348124086857 0.717214584351 -vn 0.626911520958 0.404290556908 0.665981292725 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.582295238972 0.388309806585 0.714246273041 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.605078577995 0.364442020655 0.707857310772 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.581736147404 0.413781523705 0.700262784958 -vn 0.596132755280 0.419728368521 0.684436857700 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.573984384537 0.438848376274 0.691342175007 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.622975468636 0.450315475464 0.639622926712 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.566616058350 0.477363884449 0.671617388725 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.598666012287 0.478592902422 0.642298877239 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.554501175880 0.500465869904 0.664877712727 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.660991668701 0.493317723274 0.565444648266 -vn 0.541685938835 0.558042049408 0.628621816635 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.370886951685 0.612930238247 0.697681427002 -vn 0.491780072451 0.556345999241 0.669799625874 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.696129977703 0.598392426968 0.396647810936 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.383700132370 0.539854407310 0.749220550060 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn 0.229398831725 0.792460381985 -0.565139591694 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.225670069456 0.764190435410 -0.604223489761 -vn 0.221627816558 0.735603809357 -0.640131354332 -vn 0.227120384574 0.774927020073 -0.589834272861 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn 0.199336946011 0.966365575790 -0.162488013506 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.063228040934 0.967862427235 -0.243401989341 -vn -0.526178479195 0.778710901737 -0.341680556536 -vn -0.416140437126 0.849503874779 -0.324299782515 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.005032873247 -0.546992003918 0.837122738361 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.018200494349 -0.594198882580 0.804112195969 -vn -0.058633551002 -0.727339625359 0.683768332005 -vn -0.037351265550 -0.659526169300 0.750753045082 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.601092875004 -0.198408842087 0.774158477783 -vn -0.597158789635 -0.182681038976 0.781043529510 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.286670923233 0.777926385403 -0.559151470661 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.306549847126 0.864508807659 -0.398311138153 -vn -0.316740483046 0.940792977810 -0.120764441788 -vn -0.310718089342 0.886000812054 -0.344175636768 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.766251981258 0.386263102293 0.513477087021 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.688824176788 0.425401031971 0.586988270283 -vn -0.679944336414 0.429292380810 0.594460844994 -vn -0.758818030357 0.390478551388 0.521269321442 -vn -0.714168488979 0.133881628513 0.687050998211 -vn -0.709266424179 0.149740710855 0.688853323460 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755035281181 0.451850354671 0.475134670734 -vn -0.755384206772 0.451619952917 0.474799036980 -vn -0.714168488979 0.133881628513 0.687050998211 -vn 0.004882045556 0.808167695999 0.588932156563 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.696129977703 0.598392426968 0.396647810936 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.062585294247 0.512094378471 0.856646001339 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.062585294247 0.512094378471 0.856646001339 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn 0.004882045556 0.808167695999 0.588932156563 -vn -0.067740865052 0.924975275993 0.373941093683 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.067740865052 0.924975275993 0.373941093683 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn 0.260936617851 0.964896023273 -0.029794689268 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.218742683530 -0.747778773308 0.626880049706 -vn -0.207069844007 -0.739300668240 0.640746891499 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.336433708668 -0.580547392368 0.741469502449 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.329182595015 -0.575041651726 0.748976588249 -vn -0.082584783435 -0.501806735992 0.861028313637 -vn -0.082042597234 -0.496342778206 0.864241182804 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.723464310169 -0.577978670597 -0.377544850111 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.292118996382 -0.289201915264 0.911607801914 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.290420413017 -0.288244158030 0.912453472614 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.331636220217 -0.201299607754 0.921680986881 -vn -0.343499422073 -0.192366912961 0.919240534306 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.531560599804 -0.106481343508 0.840300559998 -vn -0.530348896980 -0.108248136938 0.840840280056 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.676289498806 0.234662115574 0.698259413242 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.715247035027 0.057760063559 0.696480751038 -vn -0.711355686188 0.047995567322 0.701191484928 -vn -0.678254187107 0.233527660370 0.696732461452 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.807819128036 -0.426007598639 -0.407364487648 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.822031438351 -0.366936504841 -0.435455977917 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.807143092155 -0.382068574429 -0.450048476458 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.833994865417 -0.328578948975 -0.443270176649 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.813188791275 -0.351887822151 -0.463571965694 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.934351325035 0.180582076311 0.307209491730 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.944160640240 0.323921054602 -0.060297612101 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.886515855789 0.312364012003 -0.341347783804 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.188115775585 0.482156515121 -0.855650365353 -vn 0.779463052750 0.515830814838 -0.355465710163 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.745901107788 0.408829033375 -0.525823473930 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.159677147865 -0.149930417538 -0.975717186928 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.923839390278 -0.340887963772 -0.174115538597 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.799885809422 -0.375754773617 -0.467964798212 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.787681639194 -0.419256091118 -0.451422154903 -vn -0.755526661873 -0.421179801226 -0.501783847809 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.771373629570 -0.445649206638 -0.454290151596 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.763828694820 -0.489515036345 -0.420643240213 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.667977154255 -0.468124926090 -0.578502893448 -vn -0.730110049248 -0.523954749107 -0.438646525145 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn 0.605304896832 -0.786918938160 0.119852282107 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.620291948318 -0.767025291920 0.164042875171 -vn 0.644578337669 -0.723311424255 0.247667729855 -vn 0.631962656975 -0.748235523701 0.201907843351 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.576117694378 0.644429028034 0.502791821957 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.603480875492 0.624114632607 0.496277928352 -vn -0.706421017647 0.534547507763 0.463927060366 -vn -0.663433015347 0.574735462666 0.479098916054 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.792546272278 -0.441156685352 -0.421012073755 -vn -0.818468391895 -0.371596157551 -0.438207447529 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.751621365547 -0.450838387012 -0.481466561556 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.740067958832 -0.484423100948 -0.466512233019 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.744350910187 -0.521077871323 -0.417635709047 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.726788640022 -0.502398431301 -0.468373894691 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.621027767658 -0.595708489418 -0.509368121624 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.417442232370 -0.590895056725 -0.690351366997 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.674613356590 0.471521556377 -0.567947328091 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.254311680794 -0.167461365461 -0.952513635159 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn 0.463969379663 0.813530683517 -0.350571364164 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.373882293701 0.310287743807 -0.874032914639 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.612864077091 -0.559671700001 -0.557821869850 -vn -0.713246285915 -0.308358550072 -0.629440069199 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.495753198862 0.131482884288 0.858452677727 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.256251752377 0.170163363218 0.951514303684 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.603593230247 0.192291274667 0.773756623268 -vn 0.229584172368 0.852379977703 0.469829171896 -vn 0.041993357241 0.797598063946 0.601725757122 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn 0.229584172368 0.852379977703 0.469829171896 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.041993357241 0.797598063946 0.601725757122 -vn 0.426158398390 0.826792299747 0.367155998945 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn 0.426158398390 0.826792299747 0.367155998945 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.922598123550 0.068173386157 0.379690796137 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn 0.645867347717 0.759562194347 -0.076946094632 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.995269954205 -0.094131454825 0.024020485580 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn 0.684990108013 0.674838602543 -0.274556785822 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.938056409359 0.055331554264 -0.342035889626 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.981343269348 -0.031429406255 -0.189677640796 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.764200329781 -0.186552703381 -0.617410659790 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.349761039019 -0.113213412464 -0.929973065853 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.566509664059 -0.823908209801 -0.015559613705 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.804719209671 -0.591550230980 0.049952868372 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn -0.570844233036 -0.740347564220 -0.354996263981 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.098033927381 -0.756649672985 -0.646429121494 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn 0.518000125885 -0.625398337841 0.583568990231 -vn 0.150375440717 -0.956338346004 0.250607728958 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.417796224356 -0.550401687622 0.722844600677 -vn -0.135790631175 -0.961399912834 0.239313766360 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn 0.553593516350 -0.527526497841 0.644398927689 -vn -0.072136357427 -0.994475126266 0.076259985566 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.671063661575 -0.589654684067 0.449422925711 -vn 0.191048607230 -0.981342017651 -0.021640488878 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.640465438366 -0.704728960991 0.305223017931 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.422723919153 0.738064825535 -0.525894224644 -vn -0.118776917458 0.966788709164 -0.226299867034 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.662224650383 0.613074541092 -0.430810958147 -vn -0.161380723119 0.978026390076 -0.131987363100 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.576915979385 0.514074325562 -0.634740591049 -vn -0.054437931627 0.979436457157 -0.194269850850 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.372853875160 0.596242547035 -0.710967540741 -vn -0.033968716860 0.937177479267 -0.347195148468 -vn -0.059337425977 0.911660373211 -0.406638026237 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.429046809673 -0.796191692352 0.426611751318 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn 0.126075819135 -0.991391956806 -0.035311166197 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.313647478819 -0.631883203983 -0.708765745163 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.507797300816 -0.014627303928 -0.861352384090 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.884976446629 -0.250451683998 0.392543762922 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn 0.378463476896 0.783811092377 0.492346972227 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn 0.422761082649 0.905447840691 -0.037911430001 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.355150580406 0.699059724808 -0.620631575584 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.120943859220 0.924671351910 -0.361047744751 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.411167144775 0.906487345695 0.096032403409 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.334084272385 0.786465167999 0.519480764866 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.790524423122 0.521289408207 -0.321447402239 -vn -0.411167144775 0.906487345695 0.096032403409 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.740822911263 0.609460711479 0.282381057739 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn -0.334084272385 0.786465167999 0.519480764866 -vn 0.388690173626 0.732356131077 0.559083580971 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.740822911263 0.609460711479 0.282381057739 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.003442640649 0.996815025806 -0.079673819244 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.388690173626 0.732356131077 0.559083580971 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.718595862389 0.547037959099 0.429382652044 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.817769885063 0.481556564569 0.315207391977 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.749369800091 0.489035457373 0.446418195963 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.812969028950 0.469094514847 0.345009744167 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.767436444759 0.463645577431 0.442802578211 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.806812405586 0.465968638659 0.363217532635 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.757159888744 0.476233154535 0.447113960981 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.666716694832 0.479019969702 0.570989251137 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.378463476896 0.783811092377 0.492346972227 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.681036770344 0.469771593809 0.561697006226 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.665310978889 0.292275011539 0.686976432800 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.540240406990 0.256953597069 0.801320850849 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn 0.330415427685 -0.368209093809 0.869049906731 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.007833177224 -0.254301071167 0.967093408108 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.785756528378 -0.244205147028 -0.568287372589 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.681711435318 -0.464849233627 -0.564964354038 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.662668108940 0.436805695295 -0.608335196972 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.949991941452 0.066238164902 -0.305168509483 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.621671855450 -0.395317047834 -0.676201522350 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn -0.289297044277 0.126304164529 -0.948870122433 -vn 0.543234527111 0.750437855721 -0.376482844353 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn 0.682607948780 0.602593600750 -0.413433611393 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn 0.568385779858 0.633698344231 -0.524751365185 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.304266571999 -0.081515416503 -0.949092745781 -vn -0.152807876468 0.003922926262 -0.988248109818 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn 0.581513226032 0.206123635173 -0.786991357803 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.571283638477 0.195726588368 -0.797073483467 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.595149517059 -0.417273491621 -0.686789572239 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn -0.537571310997 0.772639870644 -0.337705105543 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.534661054611 0.774923622608 -0.337091892958 -vn -0.495952785015 0.803755402565 -0.328645855188 -vn -0.509972751141 0.793636679649 -0.331765860319 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.629080116749 -0.764525115490 0.140568733215 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627358913422 -0.766035020351 0.140039905906 -vn 0.627170860767 -0.766199529171 0.139982149005 -vn 0.628486037254 -0.765047073364 0.140386179090 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.559709072113 0.020506501198 -0.828435420990 -vn 0.531929790974 0.057460013777 -0.844836711884 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.577492237091 -0.461448967457 -0.673474252224 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.618541955948 -0.147163629532 -0.771847546101 -vn 0.601446866989 -0.122731477022 -0.789429366589 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.526679396629 -0.509270489216 -0.680626451969 -vn -0.624906539917 -0.432199299335 -0.650150477886 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.603490769863 -0.486868530512 -0.631472826004 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn 0.734982609749 -0.236774384975 -0.635404169559 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.604554712772 -0.406347364187 -0.685124337673 -vn 0.599086761475 -0.409433424473 -0.688083827496 -vn 0.734118044376 -0.247591629624 -0.632272958755 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.700512945652 -0.458336979151 -0.546999812126 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.506287515163 -0.536978483200 -0.674779236317 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.566157758236 -0.520466208458 -0.639202833176 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.666281819344 -0.495860993862 -0.556947410107 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.669272661209 -0.586196959019 -0.456560224295 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.726016998291 -0.656698286533 -0.204075306654 -vn -0.538350999355 -0.654604792595 0.530726671219 -vn -0.486205756664 -0.848186790943 0.210197895765 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.597590386868 -0.566873550415 -0.567045092583 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.672040104866 -0.656086146832 -0.343384683132 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.577021539211 -0.631674647331 0.517719328403 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.572836101055 0.156684830785 0.804554939270 -vn -0.056767333299 -0.310560673475 0.948856949806 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn 0.354127824306 -0.701984345913 0.617908954620 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.354813098907 -0.700787842274 0.618873238564 -vn 0.356339871883 -0.698108613491 0.621020376682 -vn 0.355971693993 -0.698756396770 0.620502710342 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn -0.045421313494 -0.364519536495 -0.930087327957 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.208624199033 -0.309199512005 -0.927831649780 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.896686136723 0.435548067093 -0.079068511724 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.949957668781 0.131756618619 -0.283232480288 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.271968334913 -0.475931823254 -0.836374402046 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.385559916496 -0.831905722618 -0.399094432592 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.977639138699 -0.121614255011 0.171556651592 -vn 0.737763464451 0.411261945963 0.535321116447 -vn 0.572836101055 0.156684830785 0.804554939270 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn 0.826030433178 -0.454960823059 0.332692533731 -vn 0.585414111614 -0.286889463663 0.758277475834 -vn 0.023477902636 -0.918665289879 -0.394338548183 -vn -0.098564960063 -0.946164667606 0.308313846588 -vn -0.755449414253 -0.654008865356 -0.039605412632 -vn 0.558988094330 0.524203598499 0.642450690269 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.553849399090 0.540512084961 0.633322656155 -vn 0.598153293133 0.517687678337 0.611728787422 -vn 0.383700132370 0.539854407310 0.749220550060 -vn 0.830982983112 0.368793278933 0.416483879089 -vn 0.820294380188 0.412772327662 0.395899116993 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.772460281849 0.431776523590 0.465697467327 -vn 0.915219843388 0.365772277117 0.169065743685 -vn 0.830982983112 0.368793278933 0.416483879089 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.690469682217 -0.475103706121 -0.545461297035 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.626620769501 -0.425015181303 -0.653229296207 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.674324989319 -0.420667380095 -0.606897652149 -vn -0.699129939079 -0.454820096493 -0.551684677601 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn -0.689756512642 -0.386467009783 -0.612273812294 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.116164192557 -0.129425451159 -0.984761357307 -vn -0.690721869469 -0.425349652767 -0.584791421890 -vn -0.742867887020 -0.401135712862 -0.535945415497 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.221020415425 0.617830932140 0.754609107971 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.022359715775 0.783848524094 0.620549440384 -vn 0.225397258997 0.847410619259 0.480719625950 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.022359715775 0.783848524094 0.620549440384 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.221020415425 0.617830932140 0.754609107971 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.340275913477 0.374614924192 0.862482428551 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.361942619085 0.091239318252 0.927724599838 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.282722592354 -0.189093366265 0.940378427505 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.114699073136 -0.423665881157 0.898527324200 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.116556644440 -0.576752722263 0.808560967445 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.375719875097 -0.625069260597 0.684195160866 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.623359560966 -0.561303257942 0.544390976429 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.821807086468 -0.395209699869 0.410417407751 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.940890491009 -0.152064502239 0.302657306194 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.962504327297 0.131084352732 0.237491607666 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.883385002613 0.411203354597 0.224817082286 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.715548932552 0.645697057247 0.266580253839 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.225397258997 0.847410619259 0.480719625950 -vn 0.484497249126 0.798884570599 0.356435000896 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.235830068588 0.898830175400 0.369443446398 -vn 0.072499595582 0.978071272373 0.195244491100 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.235830068588 0.898830175400 0.369443446398 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.482984036207 0.692101240158 0.536397576332 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.631313920021 0.389362454414 0.670700788498 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.658245265484 0.036702454090 0.751908302307 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.559685468674 -0.312195211649 0.767649888992 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.350638359785 -0.604206144810 0.715533137321 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn -0.062918022275 -0.794889926910 0.603482663631 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.259666293859 -0.855197250843 0.448565602303 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.567983329296 -0.775958120823 0.274379104376 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.815125644207 -0.569236397743 0.107424795628 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.963462889194 -0.266489982605 -0.026876050979 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.990399360657 0.086185812950 -0.108078926802 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.891834855080 0.435085475445 -0.123819284141 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.682788848877 0.727087855339 -0.071712374687 -vn 0.395072251558 0.917763888836 0.040340516716 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.072499595582 0.978071272373 0.195244491100 -vn 0.395072251558 0.917763888836 0.040340516716 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.510389328003 0.851969182491 -0.116838611662 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.432139426470 0.900357484818 0.051106605679 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.771237671375 0.633772552013 0.059369832277 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.697865962982 0.678082287312 0.230624243617 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.927791595459 0.314238816500 0.201138496399 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.857345402241 0.352580279112 0.375027984381 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.956224083900 -0.057976730168 0.286834865808 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.886307537556 -0.026594040915 0.462332934141 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.852196872234 -0.426232755184 0.303456902504 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.780336201191 -0.401725471020 0.479261994362 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.631541669369 -0.734460175037 0.248441949487 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.555568754673 -0.715700089931 0.423221856356 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn -0.327866882086 -0.935713112354 0.130170091987 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn -0.246219098568 -0.920718669891 0.302742958069 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.012606930919 -0.999365031719 -0.033325370401 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.100627504289 -0.985559940338 0.136182814837 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.338061541319 -0.915723919868 -0.217173010111 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.432129591703 -0.900362253189 -0.051105588675 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.598875761032 -0.697550654411 -0.393409401178 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.697853982449 -0.678096115589 -0.230619743466 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.755454063416 -0.378001183271 -0.535167455673 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.857345044613 -0.352587401867 -0.375022053719 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.783883988857 -0.005762599874 -0.620880603790 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.886305391788 0.026597272605 -0.462336778641 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.679845094681 0.362510502338 -0.637492597103 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.780332505703 0.401737719774 -0.479257732630 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.459209173918 0.670695543289 -0.582489907742 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.555568575859 0.715697705746 -0.423226147890 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.155552893877 0.871945738792 -0.464234739542 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.184946745634 0.935617744923 -0.300689518452 -vn -0.100619047880 0.985560953617 -0.136181518435 -vn 0.246223002672 0.920717000961 -0.302744895220 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.440409421921 0.166868761182 0.882153272629 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.451448649168 0.167209327221 0.876490235329 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.452018499374 0.167220517993 0.876194357872 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.452623456717 0.167246818542 0.875876963139 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.463660359383 0.167292177677 0.870076119900 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.363943278790 0.341866672039 0.866413593292 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.176284044981 0.601203441620 0.779408991337 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.283881247044 0.325743108988 0.901833057404 -vn 0.016968332231 0.508910477161 0.860652208328 -vn 0.016968332231 0.508910477161 0.860652208328 -vn -0.107152707875 0.334624469280 0.936239659786 -vn 0.169255286455 0.259556770325 0.950780153275 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.169255286455 0.259556770325 0.950780153275 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.107152707875 0.334624469280 0.936239659786 -vn -0.115241959691 0.127359017730 0.985139071941 -vn 0.194399654865 0.158964470029 0.967956125736 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.194399654865 0.158964470029 0.967956125736 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.115241959691 0.127359017730 0.985139071941 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.197535604239 0.024697216228 0.979984581470 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.197535604239 0.024697216228 0.979984581470 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn -0.057254210114 -0.091495782137 0.994158148766 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.305516988039 -0.015322029591 0.952063322067 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.100197784603 -0.239033892751 0.965827703476 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.394724458456 -0.022512111813 0.918523728848 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.271152794361 -0.318406075239 0.908346712589 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.460756331682 -0.017682855949 0.887350499630 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.441843092442 -0.342358052731 0.829195797443 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.521523356438 -0.012042840943 0.853152036667 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.604076445103 -0.310684293509 0.733871161938 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.591680169106 0.003373243380 0.806165754795 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.747208595276 -0.221942380071 0.626435041428 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.684162914753 0.063145652413 0.726590454578 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.851525843143 -0.053865674883 0.521538317204 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.667653024197 0.162887707353 0.726434469223 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.863084256649 0.151679724455 0.481745600700 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.656706690788 0.291235148907 0.695642411709 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.804317176342 0.366487383842 0.467718809843 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.567347586155 0.336215704679 0.751715183258 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.669112265110 0.520763397217 0.530183255672 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.427116841078 0.346271544695 0.835264742374 -vn 0.489619523287 0.348137021065 0.799420595169 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.511473476887 0.606199979782 0.609029054642 -vn 0.344095647335 0.632951617241 0.693520307541 -vn 0.427116841078 0.346271544695 0.835264742374 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.226580724120 0.800231337547 0.555239558220 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.035729635507 0.607942640781 0.793176591396 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.274038642645 0.932397603989 0.235664024949 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.063553564250 0.828384757042 0.556542575359 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.226580724120 0.800231337547 0.555239558220 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.484057068825 0.664243340492 0.569622218609 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.669634461403 0.441104024649 0.597508907318 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.755023717880 0.164784476161 0.634653627872 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.727189660072 -0.122606091201 0.675398409367 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.590394258499 -0.377241045237 0.713529169559 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.365469276905 -0.560368835926 0.743248939514 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.086761683226 -0.644093751907 0.760010302067 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.203307241201 -0.615718901157 0.761286020279 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.460575342178 -0.479621708393 0.746882438660 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.645931184292 -0.256549030542 0.718996167183 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.731200158596 0.019573226571 0.681882083416 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.703438580036 0.306727319956 0.641164958477 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.566846191883 0.561266124249 0.603047072887 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.063553564250 0.828384757042 0.556542575359 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.342163980007 0.744452655315 0.573335886002 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.087142288685 0.967561662197 0.237130120397 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.274038642645 0.932397603989 0.235664024949 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.594477415085 0.763044595718 0.253691971302 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.825399279594 0.485264062881 0.288504391909 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.931638896465 0.141375392675 0.334756553173 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.897019803524 -0.216296717525 0.385449409485 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.726828277111 -0.533273994923 0.432827323675 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.446954131126 -0.761327028275 0.469694793224 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.100011304021 -0.865711152554 0.490450710058 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.261155962944 -0.830548822880 0.491920948029 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.581612646580 -0.661173880100 0.473894327879 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.812520205975 -0.383413404226 0.439095735550 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.918760716915 -0.039528399706 0.392831087112 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.884145736694 0.318151026964 0.342149436474 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.713946640491 0.635133862495 0.294762849808 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.087142288685 0.967561662197 0.237130120397 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.434065520763 0.863180398941 0.257888972759 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.279109090567 0.903948545456 -0.323998630047 -vn 0.287722229958 0.947753131390 -0.137767583132 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.617344737053 0.725185930729 -0.304944008589 -vn 0.632264733315 0.765655398369 -0.118377074599 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.861044466496 0.432026088238 -0.268245995045 -vn 0.880540430546 0.467004269361 -0.080966107547 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.973190963268 0.069042496383 -0.219391137362 -vn 0.994772076607 0.097234629095 -0.031207935885 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.936656296253 -0.308471262455 -0.165892928839 -vn 0.957554459572 -0.287310987711 0.023277990520 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.757012963295 -0.643040478230 -0.115889355540 -vn 0.774556040764 -0.628134548664 0.074228972197 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.461620241404 -0.883733093739 -0.076957985759 -vn 0.473634302616 -0.873328685760 0.113875091076 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn 0.095433920622 -0.993913292885 -0.055033963174 -vn 0.100609168410 -0.985559642315 0.136198222637 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.285777777433 -0.956801950932 -0.053489483893 -vn -0.287719607353 -0.947753310204 0.137771964073 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.624005198479 -0.778046429157 -0.072535090148 -vn -0.632260084152 -0.765659391880 0.118376106024 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.867740154266 -0.484856963158 -0.109273917973 -vn -0.880548179150 -0.466990053654 0.080964274704 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.979872226715 -0.121874794364 -0.158104330301 -vn -0.994770646095 -0.097247369587 0.031213214621 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.943332910538 0.255631208420 -0.211602717638 -vn -0.957554757595 0.287309199572 -0.023287288845 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.763698756695 0.590180635452 -0.261631429195 -vn -0.774568021297 0.628118455410 -0.074239954352 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.100611813366 0.985561251640 -0.136184900999 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.102105967700 0.941065251827 -0.322444617748 -vn -0.468307971954 0.830874264240 -0.300558716059 -vn -0.473643004894 0.873323142529 -0.113881506026 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.241403773427 0.103066213429 0.964936017990 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.067393772304 0.322359681129 0.944215178490 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.074658878148 0.311024487019 0.947464942932 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.163651511073 0.288096219301 0.943514049053 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.030540788546 0.139876529574 0.989697813988 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.018172575161 0.138676419854 0.990171015263 -vn 0.017514187843 0.138613402843 0.990191698074 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.017514187843 0.138613402843 0.990191698074 -vn 0.016861176118 0.138552471995 0.990211546421 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.016861176118 0.138552471995 0.990211546421 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn 0.004517787136 0.137057393789 0.990552783012 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155109524727 0.599816203117 0.784959554672 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.002960407641 0.317960262299 0.948099434376 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.155109524727 0.599816203117 0.784959554672 -vn 0.067393772304 0.322359681129 0.944215178490 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.343748748302 0.530425429344 0.774910092354 -vn 0.155877947807 0.317323088646 0.935418665409 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.509252369404 0.375231623650 0.774508416653 -vn 0.286905646324 0.267333179712 0.919901132584 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.565602898598 0.172177463770 0.806503772736 -vn 0.285920530558 0.164982482791 0.943943977356 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.546779811382 -0.051727127284 0.835677087307 -vn 0.305570989847 0.031798329204 0.951638162136 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.415045827627 -0.218302249908 0.883221983910 -vn 0.203566029668 -0.022038534284 0.978813171387 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.249044612050 -0.319868445396 0.914144933224 -vn 0.111007757485 -0.041198842227 0.992965221405 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.065878793597 -0.367101311684 0.927845120430 -vn 0.038118865341 -0.045521553606 0.998235821724 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.124714381993 -0.358643174171 0.925106167793 -vn -0.031741838902 -0.048425141722 0.998322308064 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.311798155308 -0.291660279036 0.904276609421 -vn -0.117219403386 -0.043315853924 0.992160975933 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.473762780428 -0.141139611602 0.869268894196 -vn -0.243293151259 0.002079511527 0.969950556755 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.528437733650 0.060071583837 0.846844136715 -vn -0.241403773427 0.103066213429 0.964936017990 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.510871827602 0.279885828495 0.812818467617 -vn -0.262741386890 0.230674043298 0.936886548996 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.382493257523 0.451562076807 0.806095898151 -vn -0.163651511073 0.288096219301 0.943514049053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.035729635507 0.607942640781 0.793176591396 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.218273103237 0.558162093163 0.800507307053 -vn -0.074658878148 0.311024487019 0.947464942932 -vn -0.002960407641 0.317960262299 0.948099434376 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.517724156380 0.205077111721 -0.830605268478 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.397452175617 0.135070383549 -0.907627522945 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.437227338552 0.155448332429 -0.885814905167 -vn -0.206340491772 0.165451377630 -0.964390695095 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.382902115583 0.072942674160 -0.920904636383 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.006594384555 0.126419976354 -0.991954863071 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.191130816936 0.078426040709 -0.978426456451 -vn 0.185881495476 0.003713119309 -0.982565164566 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.053378995508 0.007072980981 -0.998549282551 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.171981990337 0.040181573480 -0.984280288219 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.372208535671 0.083363167942 -0.924397826195 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.590301692486 0.097231328487 -0.801305174828 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.353503555059 0.035152658820 -0.934772431850 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.615159690380 0.029194956645 -0.787861764431 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.826513767242 0.040492236614 -0.561458230019 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.229980155826 0.074654586613 -0.970327675343 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.261003404856 0.108527362347 -0.959217905998 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.800375282764 0.018794151023 -0.599204599857 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.271599829197 0.028476212174 -0.961988866329 -vn -0.164049550891 -0.028682840988 -0.986034989357 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.255096316338 0.111758060753 -0.960435330868 -vn -0.121076330543 0.077568016946 -0.989607870579 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.041888136417 -0.060322493315 -0.997299671173 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.087437242270 0.002138112905 -0.996167719364 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.288816571236 -0.039053402841 -0.956587612629 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.204631596804 0.028210701421 -0.978432476521 -vn 0.136239171028 -0.017071370035 -0.990528881550 -vn 0.137395173311 -0.069602020085 -0.988067865372 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.597115218639 0.003556745360 -0.802147567272 -vn 0.773272275925 0.060861453414 -0.631146490574 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.491304695606 0.135842129588 -0.860329389572 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.715357065201 0.252833127975 -0.651413619518 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.505375087261 -0.195974618196 0.840351104736 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.383719682693 -0.125125527382 0.914933204651 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.209405109286 -0.154618844390 0.965527057648 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.439777612686 -0.138827741146 0.887311935425 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.381064385176 -0.062698408961 0.922420084476 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn -0.179953932762 -0.003242430044 0.983669698238 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.186582252383 -0.074930444360 0.979577720165 -vn -0.004214687273 -0.117233298719 0.993095457554 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn 0.179345592856 0.032156031579 0.983260452747 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.046806681901 -0.005556719378 0.998888492584 -vn 0.180568888783 -0.032149348408 0.983036756516 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.592707335949 -0.091434136033 0.800211071968 -vn -0.371242731810 -0.081995286047 0.924908459187 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.357168287039 -0.031741797924 0.933500528336 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.620553731918 -0.019484132528 0.783921837807 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.819650113583 -0.032982375473 0.571914196014 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.248948097229 -0.072537310421 0.965796649456 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn 0.266313046217 -0.114633738995 0.957045674324 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.796980798244 -0.012833101675 0.603868305683 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.030801737681 0.058983106166 0.997783660889 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.179345592856 0.032156031579 0.983260452747 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.280457735062 -0.025431802496 0.959529399872 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.127938747406 -0.089620761573 0.987724542618 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.257878810167 -0.124472789466 0.958125770092 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.030801737681 0.058983106166 0.997783660889 -vn -0.074074417353 -0.006822756957 0.997229397297 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.141732782125 0.018439134583 0.989733219147 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.201434418559 -0.024834183976 0.979187130928 -vn -0.296823740005 0.040104743093 0.954089760780 -vn -0.135255068541 0.071016401052 0.988262474537 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.608369290829 -0.007743894123 0.793616294861 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.786969006062 -0.049346722662 0.615015983582 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.498839020729 -0.132146120071 0.856561183929 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.746446251869 -0.239098697901 0.621007084846 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.956761240959 0.176445245743 0.231246590614 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.909739613533 0.046079874039 0.412614196539 -vn -0.990912795067 0.127940833569 0.041508488357 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.171049833298 0.970419943333 0.170373469591 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.086038894951 0.984414279461 0.153381422162 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.091391056776 0.983691334724 0.154916256666 -vn -0.086038894951 0.984414279461 0.153381422162 -vn 0.083577327430 0.994467854500 0.063627921045 -vn -0.020135141909 0.994862496853 0.099212974310 -vn -0.023173412308 0.995078146458 0.096345901489 -vn -0.023173412308 0.995078146458 0.096345901489 -vn 0.080522112548 0.994727730751 0.063505046070 -vn 0.083577327430 0.994467854500 0.063627921045 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.171049833298 0.970419943333 0.170373469591 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.173171848059 0.969543695450 0.173195227981 -vn 0.170091286302 0.973490953445 0.152919292450 -vn 0.173439845443 0.973078310490 0.151780202985 -vn 0.063926614821 0.963856279850 0.258639603853 -vn -0.375237524509 0.793154478073 0.479690253735 -vn -0.350450277328 0.809412717819 0.471206605434 -vn -0.350450277328 0.809412717819 0.471206605434 -vn 0.078747101128 0.966759562492 0.243258908391 -vn 0.063926614821 0.963856279850 0.258639603853 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.577268898487 0.306803852320 0.756724536419 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.268814533949 0.206545710564 0.940785646439 -vn -0.185570269823 0.171825677156 0.967491388321 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.500203728676 0.010609781370 0.865842759609 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.669060587883 -0.077813722193 0.739123106003 -vn -0.866238534451 -0.039508130401 0.498066157103 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.002355504315 -0.820036292076 0.572306632996 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.789331555367 0.258876562119 0.556721329689 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.185570269823 0.171825677156 0.967491388321 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.487122595310 0.042172510177 0.872314751148 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.613033175468 -0.080646120012 0.785930335522 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.322813808918 -0.785219132900 0.528414785862 -vn 0.219091191888 -0.684044837952 0.695759832859 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.054789707065 -0.708841145039 0.703236997128 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.253998637199 -0.812512278557 0.524698436260 -vn -0.249018087983 -0.770230114460 0.587141871452 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn -0.359748840332 -0.730751514435 0.580157697201 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn -0.369146257639 -0.922445654869 0.113248042762 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn -0.431353598833 -0.487713992596 0.758992195129 -vn 0.129810020328 -0.933628261089 0.333897590637 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.980981588364 0.145293399692 0.128704696894 -vn -0.972946465015 0.230288386345 0.018504710868 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.990912795067 0.127940833569 0.041508488357 -vn -0.937579154968 0.180314436555 -0.297375231981 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.951725065708 0.081832073629 0.295842707157 -vn -0.896948277950 0.114084340632 -0.427163422108 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.431490808725 -0.866988837719 -0.249291151762 -vn -0.509320318699 -0.404863327742 -0.759393453598 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn -0.885119140148 -0.056781947613 0.461887329817 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.999801933765 0.008688983507 0.017906675115 -vn -0.880329668522 0.056018378586 -0.471043139696 -vn -0.995611131191 -0.009796535596 -0.093072362244 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.789331555367 0.258876562119 0.556721329689 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.970258474350 0.158947870135 -0.182576209307 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.487122595310 0.042172510177 0.872314751148 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.967192232609 0.137083888054 -0.213885977864 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.228643909097 -0.830196857452 -0.508424222469 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.088624604046 -0.961325287819 -0.260766953230 -vn -0.316408157349 -0.306027173996 -0.897904932499 -vn 0.011043122970 -0.237970724702 -0.971209526062 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.112375475466 -0.893029689789 -0.435740411282 -vn 0.126697152853 -0.260049194098 -0.957247197628 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn -0.238835632801 -0.915335536003 -0.324219733477 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn -0.146188363433 -0.808538675308 -0.569994866848 -vn 0.031643856317 -0.253338366747 -0.966860055923 -vn -0.078926093876 -0.439550966024 -0.894743323326 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn -0.253018796444 -0.949872851372 -0.183638378978 -vn 0.119680173695 -0.356093317270 -0.926754653454 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.622324407101 -0.358227372169 0.695978045464 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.969258189201 0.132872030139 -0.207083404064 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn 0.735630095005 -0.650957882404 -0.187355905771 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.068400837481 -0.871033847332 -0.486437410116 -vn 0.490402966738 -0.257621675730 -0.832547903061 -vn 0.852056205273 0.085932567716 -0.516348540783 -vn -0.268814533949 0.206545710564 0.940785646439 -vn 0.577268898487 0.306803852320 0.756724536419 -vn 0.984173178673 0.160306110978 -0.075532399118 -vn -0.194942057133 0.976504385471 0.091851882637 -vn -0.191570550203 0.977551102638 0.087718985975 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.181678786874 0.971370339394 0.153076708317 -vn -0.180396959186 0.971246838570 0.155359238386 -vn -0.194942057133 0.976504385471 0.091851882637 -# 32013 vertex normals - -vt 0.377155363560 0.858360707760 0.000000000000 -vt 0.377155363560 0.848666846752 0.000000000000 -vt 0.387879788876 0.848666846752 0.000000000000 -vt 0.387879788876 0.858360707760 0.000000000000 -vt 0.377155363560 0.838978648186 0.000000000000 -vt 0.387879788876 0.838978648186 0.000000000000 -vt 0.377155363560 0.829283058643 0.000000000000 -vt 0.387879788876 0.829283058643 0.000000000000 -vt 0.377155363560 0.984480679035 0.000000000000 -vt 0.377155363560 0.974780797958 0.000000000000 -vt 0.387879788876 0.974780797958 0.000000000000 -vt 0.387879788876 0.984480679035 0.000000000000 -vt 0.377155363560 0.965079963207 0.000000000000 -vt 0.387879788876 0.965079963207 0.000000000000 -vt 0.377155363560 0.955380022526 0.000000000000 -vt 0.387879788876 0.955380022526 0.000000000000 -vt 0.377155363560 0.945681273937 0.000000000000 -vt 0.387879788876 0.945681273937 0.000000000000 -vt 0.377155363560 0.935981333256 0.000000000000 -vt 0.387879788876 0.935981333256 0.000000000000 -vt 0.377155363560 0.926279187202 0.000000000000 -vt 0.387879788876 0.926279187202 0.000000000000 -vt 0.377155363560 0.916576147079 0.000000000000 -vt 0.387879788876 0.916576147079 0.000000000000 -vt 0.377155363560 0.906873524189 0.000000000000 -vt 0.387879788876 0.906873524189 0.000000000000 -vt 0.377155363560 0.897172033787 0.000000000000 -vt 0.387879788876 0.897172033787 0.000000000000 -vt 0.377155363560 0.887470304966 0.000000000000 -vt 0.387879788876 0.887470304966 0.000000000000 -vt 0.377155363560 0.877766370773 0.000000000000 -vt 0.387879788876 0.877766370773 0.000000000000 -vt 0.377155363560 0.868061482906 0.000000000000 -vt 0.387879788876 0.868061482906 0.000000000000 -vt 0.389967858791 0.848666846752 0.000000000000 -vt 0.389967858791 0.858360707760 0.000000000000 -vt 0.389223754406 0.858360707760 0.000000000000 -vt 0.389223754406 0.848666846752 0.000000000000 -vt 0.389967858791 0.838978648186 0.000000000000 -vt 0.389223754406 0.838978648186 0.000000000000 -vt 0.389967858791 0.829283058643 0.000000000000 -vt 0.389223754406 0.829283058643 0.000000000000 -vt 0.389967858791 0.974780797958 0.000000000000 -vt 0.389967858791 0.984480679035 0.000000000000 -vt 0.389223754406 0.984480679035 0.000000000000 -vt 0.389223754406 0.974780797958 0.000000000000 -vt 0.389967858791 0.965079963207 0.000000000000 -vt 0.389223754406 0.965079963207 0.000000000000 -vt 0.389967858791 0.955380022526 0.000000000000 -vt 0.389223754406 0.955380022526 0.000000000000 -vt 0.389967858791 0.945681273937 0.000000000000 -vt 0.389223754406 0.945681273937 0.000000000000 -vt 0.389967858791 0.935981333256 0.000000000000 -vt 0.389223754406 0.935981333256 0.000000000000 -vt 0.389967858791 0.926279187202 0.000000000000 -vt 0.389223754406 0.926279187202 0.000000000000 -vt 0.389967858791 0.916576147079 0.000000000000 -vt 0.389223754406 0.916576147079 0.000000000000 -vt 0.389967858791 0.906873524189 0.000000000000 -vt 0.389223754406 0.906873524189 0.000000000000 -vt 0.389967858791 0.897172033787 0.000000000000 -vt 0.389223754406 0.897172033787 0.000000000000 -vt 0.389967858791 0.887470304966 0.000000000000 -vt 0.389223754406 0.887470304966 0.000000000000 -vt 0.389967858791 0.877766370773 0.000000000000 -vt 0.389223754406 0.877766370773 0.000000000000 -vt 0.389967858791 0.868061482906 0.000000000000 -vt 0.389223754406 0.868061482906 0.000000000000 -vt 0.391293346882 0.858360707760 0.000000000000 -vt 0.391293346882 0.848666846752 0.000000000000 -vt 0.396203100681 0.848666846752 0.000000000000 -vt 0.396203100681 0.858360707760 0.000000000000 -vt 0.391293346882 0.838978648186 0.000000000000 -vt 0.396203100681 0.838978648186 0.000000000000 -vt 0.391293346882 0.829283058643 0.000000000000 -vt 0.396203100681 0.829283058643 0.000000000000 -vt 0.391293346882 0.984480679035 0.000000000000 -vt 0.391293346882 0.974780797958 0.000000000000 -vt 0.396203100681 0.974780797958 0.000000000000 -vt 0.396203100681 0.984480679035 0.000000000000 -vt 0.391293346882 0.965079963207 0.000000000000 -vt 0.396203100681 0.965079963207 0.000000000000 -vt 0.391293346882 0.955380022526 0.000000000000 -vt 0.396203100681 0.955380022526 0.000000000000 -vt 0.391293346882 0.945681273937 0.000000000000 -vt 0.396203100681 0.945681273937 0.000000000000 -vt 0.391293346882 0.935981333256 0.000000000000 -vt 0.396203100681 0.935981333256 0.000000000000 -vt 0.391293346882 0.926279187202 0.000000000000 -vt 0.396203100681 0.926279187202 0.000000000000 -vt 0.391293346882 0.916576147079 0.000000000000 -vt 0.396203100681 0.916576147079 0.000000000000 -vt 0.391293346882 0.906873524189 0.000000000000 -vt 0.396203100681 0.906873524189 0.000000000000 -vt 0.391293346882 0.897172033787 0.000000000000 -vt 0.396203100681 0.897172033787 0.000000000000 -vt 0.391293346882 0.887470304966 0.000000000000 -vt 0.396203100681 0.887470304966 0.000000000000 -vt 0.391293346882 0.877766370773 0.000000000000 -vt 0.396203100681 0.877766370773 0.000000000000 -vt 0.391293346882 0.868061482906 0.000000000000 -vt 0.396203100681 0.868061482906 0.000000000000 -vt 0.409175425768 0.672242879868 0.000000000000 -vt 0.452760726213 0.666515350342 0.000000000000 -vt 0.431881427765 0.692003369331 0.000000000000 -vt 0.481934756041 0.680083930492 0.000000000000 -vt 0.508225858212 0.789766192436 0.000000000000 -vt 0.553140699863 0.792127192020 0.000000000000 -vt 0.543430626392 0.810674130917 0.000000000000 -vt 0.493056267500 0.761313557625 0.000000000000 -vt 0.498380273581 0.738467097282 0.000000000000 -vt 0.515042841434 0.755405724049 0.000000000000 -vt 0.550852000713 0.845992863178 0.000000000000 -vt 0.577347338200 0.824143350124 0.000000000000 -vt 0.609382450581 0.854941427708 0.000000000000 -vt 0.665927231312 0.810042083263 0.000000000000 -vt 0.669713199139 0.747112154961 0.000000000000 -vt 0.691940128803 0.688431560993 0.000000000000 -vt 0.480293363333 0.580234348774 0.000000000000 -vt 0.515759050846 0.550068080425 0.000000000000 -vt 0.567890584469 0.594532608986 0.000000000000 -vt 0.623778641224 0.602010011673 0.000000000000 -vt 0.572804629803 0.544676065445 0.000000000000 -vt 0.631756961346 0.573595166206 0.000000000000 -vt 0.610680639744 0.688212931156 0.000000000000 -vt 0.650606334209 0.643516659737 0.000000000000 -vt 0.631374895573 0.713805377483 0.000000000000 -vt 0.451538383961 0.699487090111 0.000000000000 -vt 0.488095849752 0.712747395039 0.000000000000 -vt 0.505906522274 0.654317796230 0.000000000000 -vt 0.514503896236 0.621594429016 0.000000000000 -vt 0.546522319317 0.636798501015 0.000000000000 -vt 0.620644509792 0.650109648705 0.000000000000 -vt 0.536644995213 0.674807369709 0.000000000000 -vt 0.559180438519 0.677152156830 0.000000000000 -vt 0.546803295612 0.700395822525 0.000000000000 -vt 0.580495297909 0.670894205570 0.000000000000 -vt 0.560229241848 0.708388805389 0.000000000000 -vt 0.583466589451 0.746397972107 0.000000000000 -vt 0.590534269810 0.714147150517 0.000000000000 -vt 0.632254183292 0.742581784725 0.000000000000 -vt 0.392473429441 0.735891520977 0.000000000000 -vt 0.401782691479 0.699883401394 0.000000000000 -vt 0.437636852264 0.750069797039 0.000000000000 -vt 0.443033576012 0.728961050510 0.000000000000 -vt 0.467387497425 0.731456875801 0.000000000000 -vt 0.397550672293 0.599925756454 0.000000000000 -vt 0.443568110466 0.613210141659 0.000000000000 -vt 0.366362631321 0.656876027584 0.000000000000 -vt 0.447481751442 0.559440612793 0.000000000000 -vt 0.601355612278 0.819214940071 0.000000000000 -vt 0.636718928814 0.797729492188 0.000000000000 -vt 0.619128763676 0.819936096668 0.000000000000 -vt 0.559825360775 0.776961624622 0.000000000000 -vt 0.572190821171 0.759399116039 0.000000000000 -vt 0.604671776295 0.773796379566 0.000000000000 -vt 0.554654181004 0.617363810539 0.000000000000 -vt 0.567634403706 0.651618182659 0.000000000000 -vt 0.590938866138 0.618936240673 0.000000000000 -vt 0.596868813038 0.647921144962 0.000000000000 -vt 0.651719510555 0.782778739929 0.000000000000 -vt 0.614525854588 0.755118906498 0.000000000000 -vt 0.455462366343 0.816022455692 0.000000000000 -vt 0.450997769833 0.780333817005 0.000000000000 -vt 0.483516186476 0.802494883537 0.000000000000 -vt 0.485845893621 0.853235423565 0.000000000000 -vt 0.417244762182 0.840927124023 0.000000000000 -vt 0.433641225100 0.829533994198 0.000000000000 -vt 0.477579563856 0.870459556580 0.000000000000 -vt 0.530758202076 0.857129693031 0.000000000000 -vt 0.544338524342 0.876446247101 0.000000000000 -vt 0.532405674458 0.712911307812 0.000000000000 -vt 0.526134669781 0.742851078510 0.000000000000 -vt 0.547361195087 0.739448964596 0.000000000000 -vt 0.567548215389 0.558903396130 0.000000000000 -vt 0.397433131933 0.817093312740 0.000000000000 -vt 0.514106690884 0.777620911598 0.000000000000 -vt 0.462766647339 0.752251565456 0.000000000000 -vt 0.460485816002 0.643762111664 0.000000000000 -vt 0.485318392515 0.636485338211 0.000000000000 -vt 0.480034440756 0.664412677288 0.000000000000 -vt 0.630446612835 0.777688920498 0.000000000000 -vt 0.600008070469 0.799526214600 0.000000000000 -vt 0.476415723562 0.779506325722 0.000000000000 -vt 0.473682790995 0.610604822636 0.000000000000 -vt 0.675627768040 0.625576317310 0.000000000000 -vt 0.565741121769 0.800483822823 0.000000000000 -vt 0.356244146824 0.722902357578 0.000000000000 -vt 0.588402211666 0.811188578606 0.000000000000 -vt 0.518669903278 0.699171006680 0.000000000000 -vt 0.535777628422 0.658217966557 0.000000000000 -vt 0.508222043514 0.539263308048 0.000000000000 -vt 0.648145139217 0.728081822395 0.000000000000 -vt 0.514887988567 0.819228231907 0.000000000000 -vt 0.480209141970 0.748140454292 0.000000000000 -vt 0.594826638699 0.678737699986 0.000000000000 -vt 0.609615743160 0.711115896702 0.000000000000 -vt 0.374209046364 0.788166940212 0.000000000000 -vt 0.696136057377 0.841438889503 0.000000000000 -vt 0.697102844715 0.847001552582 0.000000000000 -vt 0.687970817089 0.838945984840 0.000000000000 -vt 0.676894485950 0.837039768696 0.000000000000 -vt 0.668740808964 0.834839344025 0.000000000000 -vt 0.658680617809 0.855564236641 0.000000000000 -vt 0.651980459690 0.853254318237 0.000000000000 -vt 0.694596707821 0.852629542351 0.000000000000 -vt 0.685916483402 0.854809284210 0.000000000000 -vt 0.674534022808 0.855843186378 0.000000000000 -vt 0.665389955044 0.856125533581 0.000000000000 -vt 0.650012195110 0.834412455559 0.000000000000 -vt 0.656730353832 0.833129286766 0.000000000000 -vt 0.646296203136 0.841373562813 0.000000000000 -vt 0.688886702061 0.834426641464 0.000000000000 -vt 0.699207842350 0.838674664497 0.000000000000 -vt 0.697359144688 0.855724990368 0.000000000000 -vt 0.686487972736 0.859591126442 0.000000000000 -vt 0.702463567257 0.847452104092 0.000000000000 -vt 0.677858173847 0.832566380501 0.000000000000 -vt 0.674788177013 0.860633373260 0.000000000000 -vt 0.656709134579 0.828647792339 0.000000000000 -vt 0.663522779942 0.828503489494 0.000000000000 -vt 0.663026511669 0.833329021931 0.000000000000 -vt 0.665229976177 0.860744595528 0.000000000000 -vt 0.646054327488 0.849184870720 0.000000000000 -vt 0.944440543652 0.577088952065 0.000000000000 -vt 0.934413731098 0.578397750854 0.000000000000 -vt 0.933311760426 0.570732593536 0.000000000000 -vt 0.942559897900 0.569070458412 0.000000000000 -vt 0.878645479679 0.586926877499 0.000000000000 -vt 0.868258655071 0.588900566101 0.000000000000 -vt 0.867458641529 0.580585360527 0.000000000000 -vt 0.877176105976 0.579317748547 0.000000000000 -vt 0.952389657497 0.575497746468 0.000000000000 -vt 0.950832903385 0.567034423351 0.000000000000 -vt 0.923831403255 0.579496085644 0.000000000000 -vt 0.923619329929 0.572405040264 0.000000000000 -vt 0.628452599049 0.873331427574 0.000000000000 -vt 0.632204830647 0.876753568649 0.000000000000 -vt 0.628753483295 0.881655633450 0.000000000000 -vt 0.623970210552 0.878167748451 0.000000000000 -vt 0.646685302258 0.866765677929 0.000000000000 -vt 0.656351864338 0.871634185314 0.000000000000 -vt 0.653122007847 0.874798536301 0.000000000000 -vt 0.645847260952 0.871063649654 0.000000000000 -vt 0.726799309254 0.837845385075 0.000000000000 -vt 0.661485850811 0.880055904388 0.000000000000 -vt 0.656600654125 0.882020831108 0.000000000000 -vt 0.636110603809 0.868256449699 0.000000000000 -vt 0.637845695019 0.872147083282 0.000000000000 -vt 0.649987399578 0.877419590950 0.000000000000 -vt 0.644934833050 0.875803411007 0.000000000000 -vt 0.639724314213 0.875453293324 0.000000000000 -vt 0.650543510914 0.882872819901 0.000000000000 -vt 0.637335002422 0.879814982414 0.000000000000 -vt 0.635132730007 0.885670363903 0.000000000000 -vt 0.643860280514 0.881775856018 0.000000000000 -vt 0.642733037472 0.850792288780 0.000000000000 -vt 0.641889035702 0.840179145336 0.000000000000 -vt 0.669664084911 0.830182671547 0.000000000000 -vt 0.650239527225 0.857445180416 0.000000000000 -vt 0.648015201092 0.831698417664 0.000000000000 -vt 0.642690360546 0.888261675835 0.000000000000 -vt 0.663629949093 0.887337207794 0.000000000000 -vt 0.657781779766 0.889087080956 0.000000000000 -vt 0.889635980129 0.584733188152 0.000000000000 -vt 0.887632310390 0.577965676785 0.000000000000 -vt 0.898609101772 0.583011865616 0.000000000000 -vt 0.896672070026 0.576863348484 0.000000000000 -vt 0.915674507618 0.580389678478 0.000000000000 -vt 0.915229618549 0.574002265930 0.000000000000 -vt 0.657724201679 0.860278069973 0.000000000000 -vt 0.930922925472 0.558675527573 0.000000000000 -vt 0.650379359722 0.889898777008 0.000000000000 -vt 0.939678132534 0.556469440460 0.000000000000 -vt 0.867106497288 0.567602217197 0.000000000000 -vt 0.875806748867 0.567502915859 0.000000000000 -vt 0.947033226490 0.554314255714 0.000000000000 -vt 0.922403037548 0.561220228672 0.000000000000 -vt 0.885274112225 0.567466676235 0.000000000000 -vt 0.658997356892 0.896231293678 0.000000000000 -vt 0.649604141712 0.899704515934 0.000000000000 -vt 0.895252883434 0.566620349884 0.000000000000 -vt 0.719376146793 0.837280273438 0.000000000000 -vt 0.918815433979 0.545299708843 0.000000000000 -vt 0.910051763058 0.547324061394 0.000000000000 -vt 0.907046377659 0.529140114784 0.000000000000 -vt 0.916585505009 0.527373969555 0.000000000000 -vt 0.899707138538 0.530310690403 0.000000000000 -vt 0.641025960445 0.896537065506 0.000000000000 -vt 0.901793301105 0.548481404781 0.000000000000 -vt 0.927321612835 0.542573332787 0.000000000000 -vt 0.632426559925 0.894321084023 0.000000000000 -vt 0.625132262707 0.886998593807 0.000000000000 -vt 0.717746436596 0.831090271473 0.000000000000 -vt 0.725946605206 0.830549895763 0.000000000000 -vt 0.735287845135 0.838093996048 0.000000000000 -vt 0.734414517879 0.830852091312 0.000000000000 -vt 0.717679798603 0.825329720974 0.000000000000 -vt 0.723944962025 0.823542177677 0.000000000000 -vt 0.732950508595 0.823792576790 0.000000000000 -vt 0.739792287350 0.825830638409 0.000000000000 -vt 0.741621911526 0.831147015095 0.000000000000 -vt 0.741378247738 0.836689889431 0.000000000000 -vt 0.665112435818 0.894209623337 0.000000000000 -vt 0.620138943195 0.882827579975 0.000000000000 -vt 0.936108648777 0.539952039719 0.000000000000 -vt 0.867212593555 0.550016939640 0.000000000000 -vt 0.875978291035 0.550476253033 0.000000000000 -vt 0.943726122379 0.537669897079 0.000000000000 -vt 0.884841740131 0.551008760929 0.000000000000 -vt 0.913087069988 0.563861310482 0.000000000000 -vt 0.893644869328 0.550148010254 0.000000000000 -vt 0.892628490925 0.531013190746 0.000000000000 -vt 0.904061496258 0.562744498253 0.000000000000 -vt 0.926213800907 0.525771796703 0.000000000000 -vt 0.934501111507 0.523906171322 0.000000000000 -vt 0.865935027599 0.533409059048 0.000000000000 -vt 0.875216186047 0.532836914063 0.000000000000 -vt 0.942422688007 0.521042168140 0.000000000000 -vt 0.884195983410 0.531999826431 0.000000000000 -vt 0.924653232098 0.517368316650 0.000000000000 -vt 0.932635247707 0.517127633095 0.000000000000 -vt 0.914257109165 0.519580006599 0.000000000000 -vt 0.906176626682 0.522352159023 0.000000000000 -vt 0.899168789387 0.522687613964 0.000000000000 -vt 0.892163813114 0.523706674576 0.000000000000 -vt 0.884188354015 0.523065209389 0.000000000000 -vt 0.873883426189 0.524219810963 0.000000000000 -vt 0.865347802639 0.526163995266 0.000000000000 -vt 0.858433783054 0.526082932949 0.000000000000 -vt 0.859899699688 0.590485215187 0.000000000000 -vt 0.858855664730 0.581898033619 0.000000000000 -vt 0.859369337559 0.568410336971 0.000000000000 -vt 0.859169065952 0.551045894623 0.000000000000 -vt 0.856827557087 0.534337580204 0.000000000000 -vt 0.937964379787 0.513839006424 0.000000000000 -vt 0.693465530872 0.814677596092 0.000000000000 -vt 0.700085699558 0.824197411537 0.000000000000 -vt 0.694888770580 0.822570204735 0.000000000000 -vt 0.692891776562 0.803992629051 0.000000000000 -vt 0.691710650921 0.795865237713 0.000000000000 -vt 0.711294472218 0.782084345818 0.000000000000 -vt 0.712714016438 0.788840830326 0.000000000000 -vt 0.708831012249 0.814877569675 0.000000000000 -vt 0.705738484859 0.822653293610 0.000000000000 -vt 0.711153686047 0.804187417030 0.000000000000 -vt 0.712479650974 0.795391499996 0.000000000000 -vt 0.700650393963 0.775034308434 0.000000000000 -vt 0.691504657269 0.783996403217 0.000000000000 -vt 0.693565666676 0.777675151825 0.000000000000 -vt 0.691854059696 0.825260579586 0.000000000000 -vt 0.688908874989 0.815112352371 0.000000000000 -vt 0.713424861431 0.816177845001 0.000000000000 -vt 0.708342850208 0.825807273388 0.000000000000 -vt 0.699830830097 0.829423010349 0.000000000000 -vt 0.688347995281 0.804415702820 0.000000000000 -vt 0.715837776661 0.805065751076 0.000000000000 -vt 0.690926015377 0.790131390095 0.000000000000 -vt 0.686091244221 0.790077388287 0.000000000000 -vt 0.687085330486 0.783463239670 0.000000000000 -vt 0.717056095600 0.795820415020 0.000000000000 -vt 0.700017035007 0.770576894283 0.000000000000 -vt 0.914225161076 0.695051312447 0.000000000000 -vt 0.916345059872 0.684997260571 0.000000000000 -vt 0.924999296665 0.686340272427 0.000000000000 -vt 0.923253715038 0.697034716606 0.000000000000 -vt 0.917016923428 0.620534837246 0.000000000000 -vt 0.915503799915 0.609951913357 0.000000000000 -vt 0.924802958965 0.608696460724 0.000000000000 -vt 0.925778567791 0.619882166386 0.000000000000 -vt 0.912027418613 0.704157292843 0.000000000000 -vt 0.921499311924 0.705678403378 0.000000000000 -vt 0.918580591679 0.674305975437 0.000000000000 -vt 0.926661670208 0.674895882607 0.000000000000 -vt 0.718583166599 0.876050651073 0.000000000000 -vt 0.713863432407 0.879810035229 0.000000000000 -vt 0.710420310497 0.875060856342 0.000000000000 -vt 0.714020431042 0.871412634850 0.000000000000 -vt 0.697144329548 0.869657814503 0.000000000000 -vt 0.690142214298 0.873365402222 0.000000000000 -vt 0.686877906322 0.870136678219 0.000000000000 -vt 0.696207225323 0.865324914455 0.000000000000 -vt 0.723377764225 0.855088472366 0.000000000000 -vt 0.686818659306 0.880428075790 0.000000000000 -vt 0.681876957417 0.878385961056 0.000000000000 -vt 0.704877674580 0.870628654957 0.000000000000 -vt 0.706442534924 0.866614162922 0.000000000000 -vt 0.698146879673 0.874422729015 0.000000000000 -vt 0.693293511868 0.876017093658 0.000000000000 -vt 0.703139483929 0.874020636082 0.000000000000 -vt 0.692841827869 0.881317675114 0.000000000000 -vt 0.707678377628 0.883993208408 0.000000000000 -vt 0.705496728420 0.878273785114 0.000000000000 -vt 0.700505435467 0.886600732803 0.000000000000 -vt 0.710137546062 0.772817432880 0.000000000000 -vt 0.708110511303 0.775850474834 0.000000000000 -vt 0.686994135380 0.796237647533 0.000000000000 -vt 0.715639293194 0.780954062939 0.000000000000 -vt 0.691104710102 0.775407373905 0.000000000000 -vt 0.699277937412 0.880255401134 0.000000000000 -vt 0.685730040073 0.887317180634 0.000000000000 -vt 0.679790914059 0.885531485081 0.000000000000 -vt 0.918968498707 0.632217705250 0.000000000000 -vt 0.927030384541 0.632067978382 0.000000000000 -vt 0.920924723148 0.642282843590 0.000000000000 -vt 0.928346455097 0.642091691494 0.000000000000 -vt 0.920858919621 0.665029823780 0.000000000000 -vt 0.928194463253 0.665964901447 0.000000000000 -vt 0.717470824718 0.788531899452 0.000000000000 -vt 0.900251805782 0.692512214184 0.000000000000 -vt 0.693121254444 0.888164877892 0.000000000000 -vt 0.902859151363 0.682655394077 0.000000000000 -vt 0.903970539570 0.621789634228 0.000000000000 -vt 0.901585161686 0.612310171127 0.000000000000 -vt 0.898017823696 0.700807869434 0.000000000000 -vt 0.905948698521 0.673050761223 0.000000000000 -vt 0.906874597073 0.632321536541 0.000000000000 -vt 0.693904578686 0.898468434811 0.000000000000 -vt 0.684614479542 0.894367456436 0.000000000000 -vt 0.909317672253 0.643546879292 0.000000000000 -vt 0.731463849545 0.855961382389 0.000000000000 -vt 0.869329869747 0.669516265392 0.000000000000 -vt 0.870946586132 0.660611331463 0.000000000000 -vt 0.890423119068 0.661864340305 0.000000000000 -vt 0.888348281384 0.670855045319 0.000000000000 -vt 0.890978634357 0.652710914612 0.000000000000 -vt 0.702305495739 0.895358145237 0.000000000000 -vt 0.871763646603 0.652749598026 0.000000000000 -vt 0.882360517979 0.689871191978 0.000000000000 -vt 0.710604488850 0.892980515957 0.000000000000 -vt 0.717464387417 0.885056376457 0.000000000000 -vt 0.730221688747 0.863188624382 0.000000000000 -vt 0.722860634327 0.863828301430 0.000000000000 -vt 0.714506924152 0.854860365391 0.000000000000 -vt 0.713789999485 0.863633096218 0.000000000000 -vt 0.724120557308 0.846761763096 0.000000000000 -vt 0.730854570866 0.849116206169 0.000000000000 -vt 0.714706599712 0.846446990967 0.000000000000 -vt 0.706338703632 0.855344653130 0.000000000000 -vt 0.707510411739 0.848723769188 0.000000000000 -vt 0.707069814205 0.861884772778 0.000000000000 -vt 0.678365886211 0.892260015011 0.000000000000 -vt 0.722407639027 0.880594253540 0.000000000000 -vt 0.885312139988 0.679928541183 0.000000000000 -vt 0.886436760426 0.624270200729 0.000000000000 -vt 0.883410274982 0.615363061428 0.000000000000 -vt 0.879997313023 0.698587834835 0.000000000000 -vt 0.889629900455 0.633672416210 0.000000000000 -vt 0.909305155277 0.662700593472 0.000000000000 -vt 0.891184151173 0.643255293369 0.000000000000 -vt 0.871766149998 0.644696950912 0.000000000000 -vt 0.907031238079 0.653394460678 0.000000000000 -vt 0.865283668041 0.687783956528 0.000000000000 -vt 0.867546260357 0.678728938103 0.000000000000 -vt 0.868419826031 0.627362251282 0.000000000000 -vt 0.866138994694 0.618586599827 0.000000000000 -vt 0.862232387066 0.696758449078 0.000000000000 -vt 0.870358645916 0.636041104794 0.000000000000 -vt 0.858235895634 0.685826241970 0.000000000000 -vt 0.858604013920 0.677683055401 0.000000000000 -vt 0.860833942890 0.667493700981 0.000000000000 -vt 0.863862931728 0.659794270992 0.000000000000 -vt 0.864249050617 0.652788579464 0.000000000000 -vt 0.864739954472 0.645918428898 0.000000000000 -vt 0.861379206181 0.638689100742 0.000000000000 -vt 0.859226524830 0.628483951092 0.000000000000 -vt 0.858618676662 0.620088815689 0.000000000000 -vt 0.856225430965 0.613054513931 0.000000000000 -vt 0.914761722088 0.600589513779 0.000000000000 -vt 0.924306929111 0.599584639072 0.000000000000 -vt 0.900618851185 0.603945910931 0.000000000000 -vt 0.882335126400 0.606884181499 0.000000000000 -vt 0.864254891872 0.609210252762 0.000000000000 -vt 0.854927241802 0.691868305206 0.000000000000 -vt 0.837422072887 0.841993212700 0.000000000000 -vt 0.887628972530 0.127281382680 0.000000000000 -vt 0.891492426395 0.109981805086 0.000000000000 -vt 0.853538930416 0.841780006886 0.000000000000 -vt 0.446142524481 0.173150673509 0.000000000000 -vt 0.852221906185 0.869813799858 0.000000000000 -vt 0.834832131863 0.866848766804 0.000000000000 -vt 0.827377617359 0.891240715981 0.000000000000 -vt 0.844508349895 0.896685421467 0.000000000000 -vt 0.876590073109 0.913664817810 0.000000000000 -vt 0.631155192852 0.291285961866 0.000000000000 -vt 0.626378953457 0.296571254730 0.000000000000 -vt 0.619356811047 0.293236494064 0.000000000000 -vt 0.617115795612 0.281405717134 0.000000000000 -vt 0.627076447010 0.304564028978 0.000000000000 -vt 0.612752139568 0.299342244864 0.000000000000 -vt 0.603455007076 0.284176468849 0.000000000000 -vt 0.551565110683 0.292362421751 0.000000000000 -vt 0.563377797604 0.287606924772 0.000000000000 -vt 0.575475394726 0.299903571606 0.000000000000 -vt 0.558976709843 0.303807973862 0.000000000000 -vt 0.562288582325 0.307399660349 0.000000000000 -vt 0.579733312130 0.307971090078 0.000000000000 -vt 0.596043288708 0.307672083378 0.000000000000 -vt 0.594420373440 0.298339635134 0.000000000000 -vt 0.590357482433 0.287719279528 0.000000000000 -vt 0.579626619816 0.290383100510 0.000000000000 -vt 0.573159515858 0.282042890787 0.000000000000 -vt 0.578718960285 0.044730942696 0.000000000000 -vt 0.566518962383 0.050097059458 0.000000000000 -vt 0.561770737171 0.022569365799 0.000000000000 -vt 0.579452574253 0.019849490374 0.000000000000 -vt 0.557008445263 0.060779999942 0.000000000000 -vt 0.548213899136 0.048078324646 0.000000000000 -vt 0.693731248379 0.210530251265 0.000000000000 -vt 0.693874895573 0.194242313504 0.000000000000 -vt 0.701992332935 0.200576603413 0.000000000000 -vt 0.711977064610 0.218270197511 0.000000000000 -vt 0.698697388172 0.178742393851 0.000000000000 -vt 0.704717457294 0.185912460089 0.000000000000 -vt 0.903121650219 0.125584170222 0.000000000000 -vt 0.867082893848 0.928871572018 0.000000000000 -vt 0.847567975521 0.932113111019 0.000000000000 -vt 0.861807763577 0.903646290302 0.000000000000 -vt 0.874533474445 0.941229879856 0.000000000000 -vt 0.854254424572 0.953694105148 0.000000000000 -vt 0.828710377216 0.919355154037 0.000000000000 -vt 0.886985480785 0.898062467575 0.000000000000 -vt 0.872782289982 0.875068247318 0.000000000000 -vt 0.906435072422 0.912213265896 0.000000000000 -vt 0.907167255878 0.936152637005 0.000000000000 -vt 0.888857185841 0.925772547722 0.000000000000 -vt 0.894924700260 0.912269532681 0.000000000000 -vt 0.909523308277 0.137212976813 0.000000000000 -vt 0.900375425816 0.890851438046 0.000000000000 -vt 0.647988855839 0.030116569251 0.000000000000 -vt 0.663214385509 0.030034158379 0.000000000000 -vt 0.655444204807 0.048680160195 0.000000000000 -vt 0.633447468281 0.039773471653 0.000000000000 -vt 0.639170706272 0.061737354845 0.000000000000 -vt 0.625266969204 0.055919121951 0.000000000000 -vt 0.724736869335 0.892238378525 0.000000000000 -vt 0.741851985455 0.899839401245 0.000000000000 -vt 0.725909292698 0.912707686424 0.000000000000 -vt 0.713663756847 0.901688575745 0.000000000000 -vt 0.650711238384 0.327391177416 0.000000000000 -vt 0.634856283665 0.320250153542 0.000000000000 -vt 0.740120351315 0.933756113052 0.000000000000 -vt 0.722898066044 0.930224955082 0.000000000000 -vt 0.640473186970 0.306113332510 0.000000000000 -vt 0.652059733868 0.314922749996 0.000000000000 -vt 0.621949970722 0.313803285360 0.000000000000 -vt 0.583925902843 0.276038467884 0.000000000000 -vt 0.669873058796 0.330044180155 0.000000000000 -vt 0.663455307484 0.311076432467 0.000000000000 -vt 0.653194963932 0.296154946089 0.000000000000 -vt 0.537551581860 0.063254460692 0.000000000000 -vt 0.855031669140 0.035574551672 0.000000000000 -vt 0.837493717670 0.022007379681 0.000000000000 -vt 0.709798753262 0.290995299816 0.000000000000 -vt 0.720909416676 0.320390880108 0.000000000000 -vt 0.708561480045 0.322530746460 0.000000000000 -vt 0.747772991657 0.921521842480 0.000000000000 -vt 0.695623576641 0.297934114933 0.000000000000 -vt 0.680082261562 0.305459260941 0.000000000000 -vt 0.693427860737 0.329764753580 0.000000000000 -vt 0.681907594204 0.278335958719 0.000000000000 -vt 0.667823493481 0.287369400263 0.000000000000 -vt 0.667146265507 0.261673122644 0.000000000000 -vt 0.654371798038 0.271894037724 0.000000000000 -vt 0.641373217106 0.281966120005 0.000000000000 -vt 0.639975368977 0.258212238550 0.000000000000 -vt 0.628611147404 0.269090384245 0.000000000000 -vt 0.626621663570 0.244766697288 0.000000000000 -vt 0.616053998470 0.255464911461 0.000000000000 -vt 0.605184614658 0.264766514301 0.000000000000 -vt 0.605853140354 0.242097690701 0.000000000000 -vt 0.595517814159 0.250885695219 0.000000000000 -vt 0.585814058781 0.256739497185 0.000000000000 -vt 0.595492184162 0.270403504372 0.000000000000 -vt 0.574711024761 0.264054805040 0.000000000000 -vt 0.585790932178 0.239443764091 0.000000000000 -vt 0.572891771793 0.246539995074 0.000000000000 -vt 0.559696972370 0.254923403263 0.000000000000 -vt 0.577001988888 0.228986665606 0.000000000000 -vt 0.564495980740 0.234662607312 0.000000000000 -vt 0.551713407040 0.238481923938 0.000000000000 -vt 0.545511305332 0.261512130499 0.000000000000 -vt 0.538646757603 0.241494938731 0.000000000000 -vt 0.661286294460 0.149169623852 0.000000000000 -vt 0.643085420132 0.133995741606 0.000000000000 -vt 0.684797942638 0.147779509425 0.000000000000 -vt 0.676565825939 0.159141749144 0.000000000000 -vt 0.630804598331 0.144728660583 0.000000000000 -vt 0.649197280407 0.162055477500 0.000000000000 -vt 0.669700562954 0.172124639153 0.000000000000 -vt 0.633624017239 0.171124503016 0.000000000000 -vt 0.617616355419 0.157551243901 0.000000000000 -vt 0.624203979969 0.183554634452 0.000000000000 -vt 0.607319533825 0.173306703568 0.000000000000 -vt 0.645736873150 0.185071289539 0.000000000000 -vt 0.638931095600 0.196221649647 0.000000000000 -vt 0.601086556911 0.187993124127 0.000000000000 -vt 0.617492735386 0.196533486247 0.000000000000 -vt 0.632214725018 0.207936018705 0.000000000000 -vt 0.654465734959 0.209547683597 0.000000000000 -vt 0.646386682987 0.221093416214 0.000000000000 -vt 0.611703574657 0.208597302437 0.000000000000 -vt 0.624510347843 0.219911128283 0.000000000000 -vt 0.636621057987 0.233212843537 0.000000000000 -vt 0.661210715771 0.235190823674 0.000000000000 -vt 0.651021778584 0.247041419148 0.000000000000 -vt 0.615979254246 0.231477782130 0.000000000000 -vt 0.605249464512 0.220229938626 0.000000000000 -vt 0.596773326397 0.230893954635 0.000000000000 -vt 0.592077195644 0.211689129472 0.000000000000 -vt 0.586139500141 0.221562415361 0.000000000000 -vt 0.596748054028 0.200712144375 0.000000000000 -vt 0.686020314693 0.238807246089 0.000000000000 -vt 0.677805483341 0.250549525023 0.000000000000 -vt 0.669185936451 0.222903206944 0.000000000000 -vt 0.691701591015 0.226273551583 0.000000000000 -vt 0.675190150738 0.210060581565 0.000000000000 -vt 0.660946547985 0.197643056512 0.000000000000 -vt 0.679371058941 0.196919396520 0.000000000000 -vt 0.665786325932 0.185841768980 0.000000000000 -vt 0.653169095516 0.177967861295 0.000000000000 -vt 0.682948529720 0.183452650905 0.000000000000 -vt 0.688856303692 0.169335424900 0.000000000000 -vt 0.712051331997 0.240907743573 0.000000000000 -vt 0.705046594143 0.257047295570 0.000000000000 -vt 0.693947613239 0.268588751554 0.000000000000 -vt 0.846441566944 0.016312304884 0.000000000000 -vt 0.725233733654 0.280963063240 0.000000000000 -vt 0.864230215549 0.027330722660 0.000000000000 -vt 0.867542684078 0.077758729458 0.000000000000 -vt 0.873992264271 0.059032347053 0.000000000000 -vt 0.900698363781 0.073607310653 0.000000000000 -vt 0.893409788609 0.088153243065 0.000000000000 -vt 0.837527215481 0.094833135605 0.000000000000 -vt 0.838087618351 0.073169842362 0.000000000000 -vt 0.864491522312 0.098964735866 0.000000000000 -vt 0.839568436146 0.049210395664 0.000000000000 -vt 0.838048279285 0.117027804255 0.000000000000 -vt 0.862743914127 0.119909122586 0.000000000000 -vt 0.839784204960 0.140174224973 0.000000000000 -vt 0.862825214863 0.142299681902 0.000000000000 -vt 0.887471616268 0.147722780704 0.000000000000 -vt 0.864518344402 0.167147815228 0.000000000000 -vt 0.760909855366 0.908550620079 0.000000000000 -vt 0.702537238598 0.924268066883 0.000000000000 -vt 0.688291251659 0.928146779537 0.000000000000 -vt 0.681064426899 0.908967435360 0.000000000000 -vt 0.690809547901 0.908960223198 0.000000000000 -vt 0.831720411777 0.965238690376 0.000000000000 -vt 0.609436690807 0.309842139482 0.000000000000 -vt 0.841262519360 0.982780098915 0.000000000000 -vt 0.824164688587 0.990950345993 0.000000000000 -vt 0.813748776913 0.974472284317 0.000000000000 -vt 0.803931534290 0.981341362000 0.000000000000 -vt 0.813704669476 0.995644569397 0.000000000000 -vt 0.821433365345 0.949445426464 0.000000000000 -vt 0.802491247654 0.961359918118 0.000000000000 -vt 0.792442619801 0.969731867313 0.000000000000 -vt 0.808618605137 0.936246752739 0.000000000000 -vt 0.791009962559 0.950495541096 0.000000000000 -vt 0.780412495136 0.960320413113 0.000000000000 -vt 0.779733002186 0.938618302345 0.000000000000 -vt 0.769098222256 0.949621915817 0.000000000000 -vt 0.795302093029 0.925809264183 0.000000000000 -vt 0.779587566853 0.917365670204 0.000000000000 -vt 0.765330970287 0.930258750916 0.000000000000 -vt 0.755919754505 0.940638661385 0.000000000000 -vt 0.888226568699 0.171349883080 0.000000000000 -vt 0.910776436329 0.175429016352 0.000000000000 -vt 0.910029232502 0.154122352600 0.000000000000 -vt 0.931366503239 0.177302077413 0.000000000000 -vt 0.929215371609 0.158224686980 0.000000000000 -vt 0.927563607693 0.146612986922 0.000000000000 -vt 0.907406389713 0.225816711783 0.000000000000 -vt 0.909843504429 0.199414119124 0.000000000000 -vt 0.930679738522 0.201603308320 0.000000000000 -vt 0.928200304508 0.226828783751 0.000000000000 -vt 0.887493193150 0.252168864012 0.000000000000 -vt 0.887319624424 0.224217891693 0.000000000000 -vt 0.907594621181 0.252231895924 0.000000000000 -vt 0.932080924511 0.253668844700 0.000000000000 -vt 0.888279378414 0.197011262178 0.000000000000 -vt 0.868254363537 0.222412139177 0.000000000000 -vt 0.866531431675 0.193962886930 0.000000000000 -vt 0.850991070271 0.254400819540 0.000000000000 -vt 0.425416767597 0.169557422400 0.000000000000 -vt 0.527126252651 0.054304089397 0.000000000000 -vt 0.537031948566 0.037999924272 0.000000000000 -vt 0.594819605350 0.021248605102 0.000000000000 -vt 0.593616664410 0.041817199439 0.000000000000 -vt 0.611463606358 0.039550118148 0.000000000000 -vt 0.612102329731 0.021802034229 0.000000000000 -vt 0.629308164120 0.021318852901 0.000000000000 -vt 0.684654057026 0.026047337800 0.000000000000 -vt 0.686814010143 0.010275442153 0.000000000000 -vt 0.813150346279 0.910948097706 0.000000000000 -vt 0.795561254025 0.902303934097 0.000000000000 -vt 0.708547055721 0.008438628167 0.000000000000 -vt 0.706763446331 0.024136669934 0.000000000000 -vt 0.681121885777 0.042657937855 0.000000000000 -vt 0.703326165676 0.040577050298 0.000000000000 -vt 0.679071128368 0.059330899268 0.000000000000 -vt 0.697736203671 0.057211738080 0.000000000000 -vt 0.679068386555 0.075802132487 0.000000000000 -vt 0.694422185421 0.074145883322 0.000000000000 -vt 0.660856544971 0.065091490746 0.000000000000 -vt 0.664182245731 0.079712390900 0.000000000000 -vt 0.667562067509 0.093277320266 0.000000000000 -vt 0.658718883991 0.094275429845 0.000000000000 -vt 0.653593957424 0.083498373628 0.000000000000 -vt 0.562429010868 0.070872798562 0.000000000000 -vt 0.561431109905 0.091275691986 0.000000000000 -vt 0.651631176472 0.096843779087 0.000000000000 -vt 0.566199004650 0.079591929913 0.000000000000 -vt 0.568919837475 0.088470026851 0.000000000000 -vt 0.576352179050 0.086408510804 0.000000000000 -vt 0.573891699314 0.075738176703 0.000000000000 -vt 0.570575177670 0.065078660846 0.000000000000 -vt 0.584147036076 0.084593981504 0.000000000000 -vt 0.582864105701 0.072689130902 0.000000000000 -vt 0.580894887447 0.060486171395 0.000000000000 -vt 0.593160688877 0.083160415292 0.000000000000 -vt 0.593804895878 0.070337161422 0.000000000000 -vt 0.593818604946 0.057107713073 0.000000000000 -vt 0.603601753712 0.082686245441 0.000000000000 -vt 0.606147468090 0.069071784616 0.000000000000 -vt 0.609074890614 0.054980006069 0.000000000000 -vt 0.614769279957 0.083682104945 0.000000000000 -vt 0.619084775448 0.069891348481 0.000000000000 -vt 0.610922992229 0.095825180411 0.000000000000 -vt 0.601321876049 0.094617664814 0.000000000000 -vt 0.622694909573 0.086109951138 0.000000000000 -vt 0.617340266705 0.097710400820 0.000000000000 -vt 0.629761517048 0.073689267039 0.000000000000 -vt 0.629895031452 0.090603604913 0.000000000000 -vt 0.623498737812 0.100945651531 0.000000000000 -vt 0.638310372829 0.080408573151 0.000000000000 -vt 0.638113796711 0.097320660949 0.000000000000 -vt 0.645590126514 0.088923722506 0.000000000000 -vt 0.647677242756 0.071726813912 0.000000000000 -vt 0.631511867046 0.105762854218 0.000000000000 -vt 0.638789474964 0.110335975885 0.000000000000 -vt 0.562276422977 0.105178341269 0.000000000000 -vt 0.630611360073 0.128678917885 0.000000000000 -vt 0.623610913754 0.125340327621 0.000000000000 -vt 0.626384556293 0.114658728242 0.000000000000 -vt 0.569847881794 0.105211660266 0.000000000000 -vt 0.570068538189 0.114621803164 0.000000000000 -vt 0.570002615452 0.097111940384 0.000000000000 -vt 0.577380478382 0.104798287153 0.000000000000 -vt 0.576979458332 0.114249393344 0.000000000000 -vt 0.577486932278 0.096096485853 0.000000000000 -vt 0.584565103054 0.104308113456 0.000000000000 -vt 0.583777844906 0.114008486271 0.000000000000 -vt 0.584677040577 0.095082387328 0.000000000000 -vt 0.591241061687 0.104193970561 0.000000000000 -vt 0.589022576809 0.114581719041 0.000000000000 -vt 0.592356622219 0.094391390681 0.000000000000 -vt 0.598587095737 0.105026379228 0.000000000000 -vt 0.594260156155 0.115820080042 0.000000000000 -vt 0.586750924587 0.143253445625 0.000000000000 -vt 0.588111102581 0.125869661570 0.000000000000 -vt 0.593005359173 0.127749264240 0.000000000000 -vt 0.591630995274 0.144661337137 0.000000000000 -vt 0.596110045910 0.146092429757 0.000000000000 -vt 0.598921716213 0.130493223667 0.000000000000 -vt 0.601200044155 0.117737725377 0.000000000000 -vt 0.600308954716 0.147598937154 0.000000000000 -vt 0.605599582195 0.133385121822 0.000000000000 -vt 0.608710825443 0.120034545660 0.000000000000 -vt 0.604579865932 0.149645149708 0.000000000000 -vt 0.611486494541 0.135846063495 0.000000000000 -vt 0.615960538387 0.122533097863 0.000000000000 -vt 0.608992874622 0.150967940688 0.000000000000 -vt 0.617690265179 0.137778565288 0.000000000000 -vt 0.624459326267 0.140183672309 0.000000000000 -vt 0.613782465458 0.152489989996 0.000000000000 -vt 0.570089280605 0.125959947705 0.000000000000 -vt 0.557442963123 0.275540649891 0.000000000000 -vt 0.566006243229 0.270970880985 0.000000000000 -vt 0.775371730328 0.893757700920 0.000000000000 -vt 0.808763206005 0.883916676044 0.000000000000 -vt 0.559562146664 0.264112442732 0.000000000000 -vt 0.554663598537 0.266600191593 0.000000000000 -vt 0.848581612110 0.221785306931 0.000000000000 -vt 0.393582761288 0.484183341265 0.000000000000 -vt 0.396767795086 0.480453461409 0.000000000000 -vt 0.400794714689 0.480809420347 0.000000000000 -vt 0.399765521288 0.485055834055 0.000000000000 -vt 0.439470499754 0.511713802814 0.000000000000 -vt 0.440386444330 0.513542473316 0.000000000000 -vt 0.437012046576 0.514041662216 0.000000000000 -vt 0.437573134899 0.511677742004 0.000000000000 -vt 0.422013103962 0.460037946701 0.000000000000 -vt 0.418047666550 0.470334529877 0.000000000000 -vt 0.412509530783 0.468371391296 0.000000000000 -vt 0.414865106344 0.458373844624 0.000000000000 -vt 0.429023534060 0.476388931274 0.000000000000 -vt 0.423462659121 0.473014324903 0.000000000000 -vt 0.429314196110 0.462833255529 0.000000000000 -vt 0.436214298010 0.467371255159 0.000000000000 -vt 0.406041711569 0.475491911173 0.000000000000 -vt 0.406945496798 0.467524141073 0.000000000000 -vt 0.410694092512 0.476356506348 0.000000000000 -vt 0.435092151165 0.452288359404 0.000000000000 -vt 0.438309162855 0.447881609201 0.000000000000 -vt 0.359971135855 0.090370342135 0.000000000000 -vt 0.368420302868 0.099629849195 0.000000000000 -vt 0.362833082676 0.104876860976 0.000000000000 -vt 0.354921132326 0.096900969744 0.000000000000 -vt 0.352515369654 0.130700588226 0.000000000000 -vt 0.345492541790 0.124132826924 0.000000000000 -vt 0.349532276392 0.119571164250 0.000000000000 -vt 0.358871489763 0.128728002310 0.000000000000 -vt 0.438525289297 0.449985921383 0.000000000000 -vt 0.439274400473 0.451704740524 0.000000000000 -vt 0.449622303247 0.464140743017 0.000000000000 -vt 0.448981046677 0.460056871176 0.000000000000 -vt 0.450336039066 0.460677176714 0.000000000000 -vt 0.452015697956 0.460444808006 0.000000000000 -vt 0.425263881683 0.450979530811 0.000000000000 -vt 0.453179091215 0.473780065775 0.000000000000 -vt 0.449453443289 0.477478682995 0.000000000000 -vt 0.442929327488 0.472293376923 0.000000000000 -vt 0.441622525454 0.459930330515 0.000000000000 -vt 0.444129645824 0.456388652325 0.000000000000 -vt 0.373616009951 0.118581384420 0.000000000000 -vt 0.375112146139 0.115701422095 0.000000000000 -vt 0.377992779016 0.117945536971 0.000000000000 -vt 0.375868886709 0.120479449630 0.000000000000 -vt 0.382243275642 0.107223436236 0.000000000000 -vt 0.383732229471 0.103787556291 0.000000000000 -vt 0.386310935020 0.106139764190 0.000000000000 -vt 0.384451150894 0.109020173550 0.000000000000 -vt 0.409286201000 0.450759083033 0.000000000000 -vt 0.408566385508 0.458585023880 0.000000000000 -vt 0.376690715551 0.126454398036 0.000000000000 -vt 0.381214976311 0.120371833444 0.000000000000 -vt 0.403114914894 0.459155589342 0.000000000000 -vt 0.403876841068 0.452309519053 0.000000000000 -vt 0.454835981131 0.482029527426 0.000000000000 -vt 0.457485169172 0.479463666677 0.000000000000 -vt 0.384555608034 0.122786611319 0.000000000000 -vt 0.382433533669 0.128221631050 0.000000000000 -vt 0.385892122984 0.114606484771 0.000000000000 -vt 0.389199435711 0.119001969695 0.000000000000 -vt 0.416368693113 0.447328180075 0.000000000000 -vt 0.461556434631 0.440214395523 0.000000000000 -vt 0.354810804129 0.135790005326 0.000000000000 -vt 0.356487303972 0.133928865194 0.000000000000 -vt 0.459117084742 0.440935134888 0.000000000000 -vt 0.359035402536 0.136161059141 0.000000000000 -vt 0.356604158878 0.137259811163 0.000000000000 -vt 0.456829965115 0.439723789692 0.000000000000 -vt 0.458451539278 0.437272518873 0.000000000000 -vt 0.454769343138 0.438526421785 0.000000000000 -vt 0.454550951719 0.435967743397 0.000000000000 -vt 0.441826075315 0.444921255112 0.000000000000 -vt 0.443551659584 0.442011803389 0.000000000000 -vt 0.448256731033 0.443818241358 0.000000000000 -vt 0.446299463511 0.446265220642 0.000000000000 -vt 0.455544114113 0.449857115746 0.000000000000 -vt 0.458855003119 0.454671829939 0.000000000000 -vt 0.455724000931 0.457280248404 0.000000000000 -vt 0.453310787678 0.452473431826 0.000000000000 -vt 0.450308114290 0.448847740889 0.000000000000 -vt 0.386408418417 0.101448193192 0.000000000000 -vt 0.387978881598 0.103007167578 0.000000000000 -vt 0.452250301838 0.446324646473 0.000000000000 -vt 0.447152793407 0.437671035528 0.000000000000 -vt 0.450194656849 0.436007380486 0.000000000000 -vt 0.452898085117 0.439646780491 0.000000000000 -vt 0.450881361961 0.441238403320 0.000000000000 -vt 0.458574026823 0.443444490433 0.000000000000 -vt 0.463303625584 0.444895386696 0.000000000000 -vt 0.462563782930 0.448778629303 0.000000000000 -vt 0.457480877638 0.446133941412 0.000000000000 -vt 0.454026341438 0.443802684546 0.000000000000 -vt 0.359097301960 0.132905989885 0.000000000000 -vt 0.361074864864 0.134876102209 0.000000000000 -vt 0.455461025238 0.441745221615 0.000000000000 -vt 0.444298267365 0.448686748743 0.000000000000 -vt 0.442074418068 0.450537770987 0.000000000000 -vt 0.439655810595 0.449115246534 0.000000000000 -vt 0.441199243069 0.447540730238 0.000000000000 -vt 0.451972931623 0.458101630211 0.000000000000 -vt 0.450596332550 0.459385693073 0.000000000000 -vt 0.449565351009 0.457458138466 0.000000000000 -vt 0.450939685106 0.454803764820 0.000000000000 -vt 0.446267724037 0.453737437725 0.000000000000 -vt 0.397592544556 0.132566675544 0.000000000000 -vt 0.395102560520 0.138213351369 0.000000000000 -vt 0.392103701830 0.135889068246 0.000000000000 -vt 0.395304739475 0.130839735270 0.000000000000 -vt 0.399295836687 0.125662967563 0.000000000000 -vt 0.402231425047 0.128127291799 0.000000000000 -vt 0.404049992561 0.137433633208 0.000000000000 -vt 0.405965834856 0.138806402683 0.000000000000 -vt 0.404163688421 0.144568577409 0.000000000000 -vt 0.448208779097 0.451402574778 0.000000000000 -vt 0.449387699366 0.442756623030 0.000000000000 -vt 0.445775300264 0.440066248178 0.000000000000 -vt 0.459970653057 0.451159417629 0.000000000000 -vt 0.456270694733 0.448136717081 0.000000000000 -vt 0.400764316320 0.142388850451 0.000000000000 -vt 0.410871744156 0.135244905949 0.000000000000 -vt 0.407858490944 0.132529079914 0.000000000000 -vt 0.389080792665 0.131361424923 0.000000000000 -vt 0.387762486935 0.129610389471 0.000000000000 -vt 0.389104187489 0.126333042979 0.000000000000 -vt 0.390812218189 0.127695217729 0.000000000000 -vt 0.391797959805 0.123638600111 0.000000000000 -vt 0.393867135048 0.124303475022 0.000000000000 -vt 0.390969157219 0.132123574615 0.000000000000 -vt 0.392821729183 0.129185527563 0.000000000000 -vt 0.395075976849 0.126136258245 0.000000000000 -vt 0.398736566305 0.138166293502 0.000000000000 -vt 0.397700846195 0.136793285608 0.000000000000 -vt 0.399035334587 0.133746489882 0.000000000000 -vt 0.400510340929 0.134889379144 0.000000000000 -vt 0.401520818472 0.131361871958 0.000000000000 -vt 0.403166472912 0.131912827492 0.000000000000 -vt 0.400330662727 0.138775110245 0.000000000000 -vt 0.402200579643 0.136118054390 0.000000000000 -vt 0.404188245535 0.133363723755 0.000000000000 -vt 0.385480999947 0.131040126085 0.000000000000 -vt 0.387488692999 0.124964997172 0.000000000000 -vt 0.392740219831 0.120471790433 0.000000000000 -vt 0.397779881954 0.121211871505 0.000000000000 -vt 0.388019412756 0.135536253452 0.000000000000 -vt 0.406621724367 0.128388255835 0.000000000000 -vt 0.396779060364 0.141935378313 0.000000000000 -vt 0.409657478333 0.141405150294 0.000000000000 -vt 0.408238559961 0.143032342196 0.000000000000 -vt 0.452826261520 0.445473134518 0.000000000000 -vt 0.398223191500 0.453096210957 0.000000000000 -vt 0.397748589516 0.459203541279 0.000000000000 -vt 0.461537957191 0.483292669058 0.000000000000 -vt 0.458966463804 0.486215561628 0.000000000000 -vt 0.417104929686 0.441364258528 0.000000000000 -vt 0.418126702309 0.442871898413 0.000000000000 -vt 0.420422822237 0.444641411304 0.000000000000 -vt 0.433500528336 0.448079735041 0.000000000000 -vt 0.436020672321 0.448221594095 0.000000000000 -vt 0.427099138498 0.446181684732 0.000000000000 -vt 0.438960522413 0.423234313726 0.000000000000 -vt 0.436720907688 0.424649864435 0.000000000000 -vt 0.407253503799 0.142381638288 0.000000000000 -vt 0.408249586821 0.140351876616 0.000000000000 -vt 0.434051692486 0.423569798470 0.000000000000 -vt 0.434879601002 0.420804440975 0.000000000000 -vt 0.431214749813 0.423123985529 0.000000000000 -vt 0.430086702108 0.420641422272 0.000000000000 -vt 0.419274091721 0.434574037790 0.000000000000 -vt 0.420379161835 0.430852890015 0.000000000000 -vt 0.426141530275 0.431651085615 0.000000000000 -vt 0.424853444099 0.434927970171 0.000000000000 -vt 0.436181217432 0.434532612562 0.000000000000 -vt 0.441298097372 0.437351107597 0.000000000000 -vt 0.439914047718 0.441069751978 0.000000000000 -vt 0.435192108154 0.437948435545 0.000000000000 -vt 0.430372446775 0.435908526182 0.000000000000 -vt 0.410810738802 0.139599621296 0.000000000000 -vt 0.409828603268 0.138812705874 0.000000000000 -vt 0.431275308132 0.432643771172 0.000000000000 -vt 0.423234343529 0.424417972565 0.000000000000 -vt 0.425667136908 0.422001600266 0.000000000000 -vt 0.429718136787 0.424738824368 0.000000000000 -vt 0.428410202265 0.426783442497 0.000000000000 -vt 0.437025994062 0.426789969206 0.000000000000 -vt 0.441838681698 0.426870137453 0.000000000000 -vt 0.442383557558 0.430333465338 0.000000000000 -vt 0.436957329512 0.429274797440 0.000000000000 -vt 0.432621270418 0.428078770638 0.000000000000 -vt 0.414452850819 0.144986689091 0.000000000000 -vt 0.409147053957 0.147766679525 0.000000000000 -vt 0.433331876993 0.425908029079 0.000000000000 -vt 0.423957765102 0.438147932291 0.000000000000 -vt 0.422544687986 0.441486746073 0.000000000000 -vt 0.418296456337 0.441183239222 0.000000000000 -vt 0.419304251671 0.438087821007 0.000000000000 -vt 0.437636613846 0.443893879652 0.000000000000 -vt 0.436708301306 0.446964770555 0.000000000000 -vt 0.433489710093 0.444419175386 0.000000000000 -vt 0.434133440256 0.441165685654 0.000000000000 -vt 0.428444206715 0.442456930876 0.000000000000 -vt 0.408575177193 0.144754558802 0.000000000000 -vt 0.411639750004 0.142881035805 0.000000000000 -vt 0.406258314848 0.142990231514 0.000000000000 -vt 0.407059431076 0.139547616243 0.000000000000 -vt 0.410056680441 0.137724533677 0.000000000000 -vt 0.415505886078 0.139094606042 0.000000000000 -vt 0.412565827370 0.139450341463 0.000000000000 -vt 0.364202499390 0.128939658403 0.000000000000 -vt 0.366093575954 0.126167103648 0.000000000000 -vt 0.429390072823 0.439258158207 0.000000000000 -vt 0.427526712418 0.428991526365 0.000000000000 -vt 0.422490209341 0.427620559931 0.000000000000 -vt 0.441317677498 0.433453887701 0.000000000000 -vt 0.436557680368 0.431637555361 0.000000000000 -vt 0.368825376034 0.128782272339 0.000000000000 -vt 0.366221219301 0.131002977490 0.000000000000 -vt 0.377708643675 0.113558173180 0.000000000000 -vt 0.379947811365 0.115249529481 0.000000000000 -vt 0.368792057037 0.124293580651 0.000000000000 -vt 0.370973348618 0.126337096095 0.000000000000 -vt 0.379835903645 0.132157340646 0.000000000000 -vt 0.374702155590 0.134804278612 0.000000000000 -vt 0.371608525515 0.131661787629 0.000000000000 -vt 0.385006606579 0.145867496729 0.000000000000 -vt 0.380806565285 0.150551855564 0.000000000000 -vt 0.378436356783 0.147939816117 0.000000000000 -vt 0.383413165808 0.143897384405 0.000000000000 -vt 0.388382792473 0.140254378319 0.000000000000 -vt 0.390580326319 0.142940923572 0.000000000000 -vt 0.389787077904 0.151387169957 0.000000000000 -vt 0.391084223986 0.152869373560 0.000000000000 -vt 0.387653529644 0.157836511731 0.000000000000 -vt 0.385402202606 0.155462026596 0.000000000000 -vt 0.396483421326 0.150470122695 0.000000000000 -vt 0.394613981247 0.147955358028 0.000000000000 -vt 0.377133131027 0.143021076918 0.000000000000 -vt 0.431962937117 0.430194556713 0.000000000000 -vt 0.398509591818 0.449473470449 0.000000000000 -vt 0.403451532125 0.447545230389 0.000000000000 -vt 0.412772059441 0.443381220102 0.000000000000 -vt 0.415262728930 0.442666351795 0.000000000000 -vt 0.408193081617 0.445362567902 0.000000000000 -vt 0.402572304010 0.417491078377 0.000000000000 -vt 0.401636779308 0.420146107674 0.000000000000 -vt 0.376334518194 0.141268029809 0.000000000000 -vt 0.378864586353 0.138637766242 0.000000000000 -vt 0.398579388857 0.420967459679 0.000000000000 -vt 0.397203922272 0.418318748474 0.000000000000 -vt 0.395930439234 0.422812163830 0.000000000000 -vt 0.393101811409 0.421740859747 0.000000000000 -vt 0.393963277340 0.440714478493 0.000000000000 -vt 0.392591178417 0.436948060989 0.000000000000 -vt 0.397990405560 0.434073746204 0.000000000000 -vt 0.399504780769 0.437697380781 0.000000000000 -vt 0.408009588718 0.428790479898 0.000000000000 -vt 0.414924532175 0.428841352463 0.000000000000 -vt 0.416294604540 0.432789921761 0.000000000000 -vt 0.409434139729 0.432349741459 0.000000000000 -vt 0.404077023268 0.434443891048 0.000000000000 -vt 0.380261212587 0.140083029866 0.000000000000 -vt 0.382164925337 0.137022957206 0.000000000000 -vt 0.402819514275 0.430790752172 0.000000000000 -vt 0.390489786863 0.430026113987 0.000000000000 -vt 0.390550136566 0.426381319761 0.000000000000 -vt 0.395857959986 0.425411134958 0.000000000000 -vt 0.396276742220 0.428331613541 0.000000000000 -vt 0.403288513422 0.421578973532 0.000000000000 -vt 0.408246427774 0.418946474791 0.000000000000 -vt 0.411142379045 0.421542286873 0.000000000000 -vt 0.405009150505 0.423732370138 0.000000000000 -vt 0.400750786066 0.425774753094 0.000000000000 -vt 0.383944779634 0.138014540076 0.000000000000 -vt 0.378778368235 0.144098669291 0.000000000000 -vt 0.399727702141 0.423417359591 0.000000000000 -vt 0.400881379843 0.440771222115 0.000000000000 -vt 0.401966422796 0.443919539452 0.000000000000 -vt 0.396847724915 0.446899026632 0.000000000000 -vt 0.396342486143 0.443651407957 0.000000000000 -vt 0.415956437588 0.436509907246 0.000000000000 -vt 0.416573584080 0.440072774887 0.000000000000 -vt 0.411374956369 0.439379304647 0.000000000000 -vt 0.410169273615 0.436066806316 0.000000000000 -vt 0.406326770782 0.441095888615 0.000000000000 -vt 0.381734192371 0.141807720065 0.000000000000 -vt 0.384717941284 0.139707922935 0.000000000000 -vt 0.384294420481 0.151226192713 0.000000000000 -vt 0.383655220270 0.149787440896 0.000000000000 -vt 0.386135309935 0.147063747048 0.000000000000 -vt 0.387247562408 0.148301199079 0.000000000000 -vt 0.389312237501 0.145468518138 0.000000000000 -vt 0.390688598156 0.146293267608 0.000000000000 -vt 0.385713368654 0.152030900121 0.000000000000 -vt 0.405239045620 0.437882453203 0.000000000000 -vt 0.396997690201 0.430689215660 0.000000000000 -vt 0.392160445452 0.433128327131 0.000000000000 -vt 0.412164151669 0.424938082695 0.000000000000 -vt 0.406307399273 0.426028043032 0.000000000000 -vt 0.388458669186 0.149755924940 0.000000000000 -vt 0.391224920750 0.147718727589 0.000000000000 -vt 0.373405694962 0.142156943679 0.000000000000 -vt 0.377377659082 0.137248560786 0.000000000000 -vt 0.383390426636 0.134469017386 0.000000000000 -vt 0.387974828482 0.136217564344 0.000000000000 -vt 0.374564796686 0.146659821272 0.000000000000 -vt 0.394345581532 0.144419968128 0.000000000000 -vt 0.381775170565 0.154543623328 0.000000000000 -vt 0.393369078636 0.155557274818 0.000000000000 -vt 0.391563802958 0.156876459718 0.000000000000 -vt 0.390937179327 0.156117007136 0.000000000000 -vt 0.392488509417 0.154420018196 0.000000000000 -vt 0.395006179810 0.154078006744 0.000000000000 -vt 0.394348293543 0.153221741319 0.000000000000 -vt 0.396971106529 0.159922137856 0.000000000000 -vt 0.391263425350 0.161551579833 0.000000000000 -vt 0.391377806664 0.158593714237 0.000000000000 -vt 0.394818872213 0.157320469618 0.000000000000 -vt 0.389807134867 0.156631037593 0.000000000000 -vt 0.391787588596 0.153602257371 0.000000000000 -vt 0.395006865263 0.152312338352 0.000000000000 -vt 0.401779532433 0.428116351366 0.000000000000 -vt 0.452458798885 0.462447345257 0.000000000000 -vt 0.452626556158 0.465537369251 0.000000000000 -vt 0.459379166365 0.476943254471 0.000000000000 -vt 0.462601810694 0.480663985014 0.000000000000 -vt 0.455803722143 0.471922338009 0.000000000000 -vt 0.479603260756 0.461800038815 0.000000000000 -vt 0.477074772120 0.461461395025 0.000000000000 -vt 0.399524837732 0.154673993587 0.000000000000 -vt 0.396705895662 0.154279291630 0.000000000000 -vt 0.475300759077 0.459207594395 0.000000000000 -vt 0.477906495333 0.457540988922 0.000000000000 -vt 0.473629444838 0.457062989473 0.000000000000 -vt 0.474505990744 0.454424381256 0.000000000000 -vt 0.457420319319 0.456922262907 0.000000000000 -vt 0.460104405880 0.454761892557 0.000000000000 -vt 0.463730514050 0.459742784500 0.000000000000 -vt 0.461280167103 0.461182653904 0.000000000000 -vt 0.469485044479 0.469264149666 0.000000000000 -vt 0.472566455603 0.474419951439 0.000000000000 -vt 0.469833135605 0.475842684507 0.000000000000 -vt 0.467271775007 0.470811873674 0.000000000000 -vt 0.464453041553 0.465783476830 0.000000000000 -vt 0.371207743883 0.139285087585 0.000000000000 -vt 0.356069415808 0.140628591180 0.000000000000 -vt 0.466606199741 0.464368134737 0.000000000000 -vt 0.466347038746 0.452607154846 0.000000000000 -vt 0.470105797052 0.452469378710 0.000000000000 -vt 0.471197992563 0.457316517830 0.000000000000 -vt 0.468378633261 0.458023726940 0.000000000000 -vt 0.475411504507 0.463598579168 0.000000000000 -vt 0.478970795870 0.466784060001 0.000000000000 -vt 0.476854532957 0.469994544983 0.000000000000 -vt 0.473139971495 0.465840876102 0.000000000000 -vt 0.470534920692 0.462002217770 0.000000000000 -vt 0.361092180014 0.138868093491 0.000000000000 -vt 0.362757891417 0.141520425677 0.000000000000 -vt 0.473011165857 0.460577666759 0.000000000000 -vt 0.458834081888 0.463209271431 0.000000000000 -vt 0.456127494574 0.464871376753 0.000000000000 -vt 0.453364372253 0.461712449789 0.000000000000 -vt 0.455975264311 0.460149645805 0.000000000000 -vt 0.466653943062 0.476451963186 0.000000000000 -vt 0.464873641729 0.479033142328 0.000000000000 -vt 0.462096124887 0.474372893572 0.000000000000 -vt 0.464624851942 0.472282111645 0.000000000000 -vt 0.459239572287 0.469601660967 0.000000000000 -vt 0.358396410942 0.143731668591 0.000000000000 -vt 0.366143107414 0.136179968715 0.000000000000 -vt 0.367462068796 0.140748366714 0.000000000000 -vt 0.367624849081 0.152154952288 0.000000000000 -vt 0.363851904869 0.154144421220 0.000000000000 -vt 0.362488389015 0.151757776737 0.000000000000 -vt 0.366743355989 0.150309801102 0.000000000000 -vt 0.370945870876 0.149034306407 0.000000000000 -vt 0.371946483850 0.151283830404 0.000000000000 -vt 0.461986482143 0.467537879944 0.000000000000 -vt 0.466021031141 0.459026336670 0.000000000000 -vt 0.463648796082 0.454296290874 0.000000000000 -vt 0.474090546370 0.471629172564 0.000000000000 -vt 0.471038132906 0.467538326979 0.000000000000 -vt 0.369695812464 0.157271832228 0.000000000000 -vt 0.370106279850 0.158484742045 0.000000000000 -vt 0.366340100765 0.161045432091 0.000000000000 -vt 0.365696161985 0.158691659570 0.000000000000 -vt 0.374921888113 0.158001109958 0.000000000000 -vt 0.373830109835 0.155684486032 0.000000000000 -vt 0.362566053867 0.147848188877 0.000000000000 -vt 0.362277865410 0.146466180682 0.000000000000 -vt 0.364509135485 0.145325541496 0.000000000000 -vt 0.365181237459 0.146691560745 0.000000000000 -vt 0.366957485676 0.145109176636 0.000000000000 -vt 0.367903143167 0.146292820573 0.000000000000 -vt 0.363559901714 0.149057939649 0.000000000000 -vt 0.365885078907 0.148352980614 0.000000000000 -vt 0.368204176426 0.147704318166 0.000000000000 -vt 0.366324573755 0.155576184392 0.000000000000 -vt 0.366173952818 0.154380381107 0.000000000000 -vt 0.368186831474 0.153372362256 0.000000000000 -vt 0.368705600500 0.154601037502 0.000000000000 -vt 0.370330303907 0.152888730168 0.000000000000 -vt 0.371147632599 0.153870403767 0.000000000000 -vt 0.367092341185 0.156595915556 0.000000000000 -vt 0.369238078594 0.155905812979 0.000000000000 -vt 0.371273934841 0.155043467879 0.000000000000 -vt 0.359594911337 0.146293044090 0.000000000000 -vt 0.363820612431 0.143866091967 0.000000000000 -vt 0.368623167276 0.143500894308 0.000000000000 -vt 0.468312889338 0.463350683451 0.000000000000 -vt 0.396901309490 0.467744559050 0.000000000000 -vt 0.401809483767 0.467451632023 0.000000000000 -vt 0.371416240931 0.146074414253 0.000000000000 -vt 0.359569907188 0.149919614196 0.000000000000 -vt 0.374465495348 0.153269469738 0.000000000000 -vt 0.414790123701 0.478396862745 0.000000000000 -vt 0.447205245495 0.489582329988 0.000000000000 -vt 0.452684849501 0.491852372885 0.000000000000 -vt 0.449784398079 0.494581252337 0.000000000000 -vt 0.442751228809 0.493985742331 0.000000000000 -vt 0.434156626463 0.494034796953 0.000000000000 -vt 0.440118283033 0.488046973944 0.000000000000 -vt 0.434461027384 0.500024855137 0.000000000000 -vt 0.430395841599 0.501698195934 0.000000000000 -vt 0.425874501467 0.499181836843 0.000000000000 -vt 0.446397393942 0.499464601278 0.000000000000 -vt 0.440220713615 0.499364227057 0.000000000000 -vt 0.434654891491 0.512679457664 0.000000000000 -vt 0.435968428850 0.511407136917 0.000000000000 -vt 0.443066686392 0.505874812603 0.000000000000 -vt 0.438906043768 0.505390286446 0.000000000000 -vt 0.439353436232 0.502900302410 0.000000000000 -vt 0.444775164127 0.503243684769 0.000000000000 -vt 0.435113310814 0.505446374416 0.000000000000 -vt 0.434737980366 0.503206968307 0.000000000000 -vt 0.447127133608 0.507210433483 0.000000000000 -vt 0.449805349112 0.505035459995 0.000000000000 -vt 0.363566637039 0.157027080655 0.000000000000 -vt 0.371184110641 0.161255732179 0.000000000000 -vt 0.431567996740 0.505946636200 0.000000000000 -vt 0.430854707956 0.504090666771 0.000000000000 -vt 0.369521766901 0.161624297500 0.000000000000 -vt 0.369182020426 0.160728856921 0.000000000000 -vt 0.370721399784 0.159941717982 0.000000000000 -vt 0.372713804245 0.160549417138 0.000000000000 -vt 0.372284442186 0.159536883235 0.000000000000 -vt 0.372968226671 0.165679350495 0.000000000000 -vt 0.452052175999 0.500936031342 0.000000000000 -vt 0.368058949709 0.165135830641 0.000000000000 -vt 0.368970602751 0.162820771337 0.000000000000 -vt 0.371845602989 0.162883594632 0.000000000000 -vt 0.368251889944 0.160784929991 0.000000000000 -vt 0.370353937149 0.159135669470 0.000000000000 -vt 0.440568357706 0.509817063808 0.000000000000 -vt 0.437990337610 0.509382963181 0.000000000000 -vt 0.435604155064 0.509494423866 0.000000000000 -vt 0.443635433912 0.511720776558 0.000000000000 -vt 0.373006284237 0.158982783556 0.000000000000 -vt 0.376509696245 0.162375643849 0.000000000000 -vt 0.374031394720 0.161057814956 0.000000000000 -vt 0.389625668526 0.108183041215 0.000000000000 -vt 0.393046200275 0.109792903066 0.000000000000 -vt 0.392523407936 0.116342663765 0.000000000000 -vt 0.432401984930 0.510016977787 0.000000000000 -vt 0.438322216272 0.506984829903 0.000000000000 -vt 0.441790044308 0.507623851299 0.000000000000 -vt 0.435307621956 0.507277548313 0.000000000000 -vt 0.444958448410 0.509229838848 0.000000000000 -vt 0.392005532980 0.101636424661 0.000000000000 -vt 0.395671516657 0.103756263852 0.000000000000 -vt 0.407296061516 0.115123912692 0.000000000000 -vt 0.406397461891 0.121328055859 0.000000000000 -vt 0.403196871281 0.120348632336 0.000000000000 -vt 0.404978096485 0.114345774055 0.000000000000 -vt 0.432492733002 0.507707357407 0.000000000000 -vt 0.406864881516 0.108425304294 0.000000000000 -vt 0.409913033247 0.109619542956 0.000000000000 -vt 0.414692848921 0.117440745234 0.000000000000 -vt 0.416797161102 0.118163943291 0.000000000000 -vt 0.416874825954 0.124142721295 0.000000000000 -vt 0.413157969713 0.123205170035 0.000000000000 -vt 0.420296519995 0.113394036889 0.000000000000 -vt 0.416648089886 0.111873343587 0.000000000000 -vt 0.399549156427 0.117066100240 0.000000000000 -vt 0.397761642933 0.115746006370 0.000000000000 -vt 0.444640964270 0.482646912336 0.000000000000 -vt 0.435251086950 0.480776757002 0.000000000000 -vt 0.412997663021 0.489607781172 0.000000000000 -vt 0.415611475706 0.485968559980 0.000000000000 -vt 0.419600337744 0.489331930876 0.000000000000 -vt 0.418021112680 0.495383232832 0.000000000000 -vt 0.418760269880 0.480955928564 0.000000000000 -vt 0.451327174902 0.485552281141 0.000000000000 -vt 0.397986561060 0.111830547452 0.000000000000 -vt 0.400141090155 0.112691327929 0.000000000000 -vt 0.399654954672 0.108637854457 0.000000000000 -vt 0.401813089848 0.108847483993 0.000000000000 -vt 0.401618987322 0.117125526071 0.000000000000 -vt 0.402521193027 0.113518998027 0.000000000000 -vt 0.403585493565 0.110106542706 0.000000000000 -vt 0.409883081913 0.119960919023 0.000000000000 -vt 0.455791562796 0.489336222410 0.000000000000 -vt 0.422770082951 0.483635991812 0.000000000000 -vt 0.423145622015 0.491761177778 0.000000000000 -vt 0.408528327942 0.119000181556 0.000000000000 -vt 0.408956587315 0.115644469857 0.000000000000 -vt 0.410606950521 0.116135522723 0.000000000000 -vt 0.410386979580 0.112677589059 0.000000000000 -vt 0.421489149332 0.498041182756 0.000000000000 -vt 0.426815658808 0.486486226320 0.000000000000 -vt 0.430106759071 0.489818543196 0.000000000000 -vt 0.434814959764 0.486344844103 0.000000000000 -vt 0.426011174917 0.493239969015 0.000000000000 -vt 0.405869930983 0.480812519789 0.000000000000 -vt 0.412047952414 0.112628281116 0.000000000000 -vt 0.406924337149 0.485618025064 0.000000000000 -vt 0.401090562344 0.475320100784 0.000000000000 -vt 0.396311402321 0.475648850203 0.000000000000 -vt 0.411765158176 0.482897728682 0.000000000000 -vt 0.409521043301 0.480445533991 0.000000000000 -vt 0.453219145536 0.496879428625 0.000000000000 -vt 0.411550819874 0.119953945279 0.000000000000 -vt 0.412490606308 0.116729035974 0.000000000000 -vt 0.413484215736 0.113597795367 0.000000000000 -vt 0.395627617836 0.118285313249 0.000000000000 -vt 0.396080166101 0.111090466380 0.000000000000 -vt 0.399283915758 0.105090305209 0.000000000000 -vt 0.404269516468 0.104768797755 0.000000000000 -vt 0.398505777121 0.120832040906 0.000000000000 -vt 0.413978666067 0.108735352755 0.000000000000 -vt 0.409310519695 0.124303475022 0.000000000000 -vt 0.420999675989 0.119554504752 0.000000000000 -vt 0.420234143734 0.121525302529 0.000000000000 -vt 0.419045567513 0.121159419417 0.000000000000 -vt 0.419289410114 0.118994310498 0.000000000000 -vt 0.421489626169 0.117538690567 0.000000000000 -vt 0.420303285122 0.117139488459 0.000000000000 -vt 0.426694989204 0.121457740664 0.000000000000 -vt 0.422340482473 0.125688865781 0.000000000000 -vt 0.420924037695 0.122998699546 0.000000000000 -vt 0.423304349184 0.120309680700 0.000000000000 -vt 0.418264955282 0.122074902058 0.000000000000 -vt 0.417998820543 0.118570342660 0.000000000000 -vt 0.420178323984 0.115989848971 0.000000000000 -vt 0.425800204277 0.115537062287 0.000000000000 -vt 0.423050165176 0.116810753942 0.000000000000 -vt 0.377677112818 0.108308449388 0.000000000000 -vt 0.380777746439 0.100671857595 0.000000000000 -vt 0.387641370296 0.097277656198 0.000000000000 -vt 0.368460386992 0.119178041816 0.000000000000 -vt 0.370848834515 0.112134292722 0.000000000000 -vt 0.361701697111 0.122205942869 0.000000000000 -vt 0.350305467844 0.135973051190 0.000000000000 -vt 0.358212679625 0.109973028302 0.000000000000 -vt 0.353615224361 0.114691153169 0.000000000000 -vt 0.374976605177 0.093655571342 0.000000000000 -vt 0.389860272408 0.064062759280 0.000000000000 -vt 0.392403393984 0.070562094450 0.000000000000 -vt 0.387591153383 0.070836335421 0.000000000000 -vt 0.386600703001 0.064674735069 0.000000000000 -vt 0.390128880739 0.057090383023 0.000000000000 -vt 0.385809719563 0.057704154402 0.000000000000 -vt 0.381569832563 0.070360124111 0.000000000000 -vt 0.378056943417 0.070291683078 0.000000000000 -vt 0.376780331135 0.065116941929 0.000000000000 -vt 0.571491539478 0.142689660192 0.000000000000 -vt 0.576072752476 0.124807611108 0.000000000000 -vt 0.575986921787 0.141870543361 0.000000000000 -vt 0.787393748760 0.876816630363 0.000000000000 -vt 0.764766037464 0.871043145657 0.000000000000 -vt 0.754721701145 0.886201500893 0.000000000000 -vt 0.742770016193 0.866340160370 0.000000000000 -vt 0.734950125217 0.879857540131 0.000000000000 -vt 0.639134943485 0.405957043171 0.000000000000 -vt 0.626996815205 0.399863898754 0.000000000000 -vt 0.634920418262 0.394428640604 0.000000000000 -vt 0.639219582081 0.397930711508 0.000000000000 -vt 0.634795248508 0.383935958147 0.000000000000 -vt 0.643223226070 0.392979323864 0.000000000000 -vt 0.621101796627 0.387013614178 0.000000000000 -vt 0.588396847248 0.330318629742 0.000000000000 -vt 0.604378163815 0.331369876862 0.000000000000 -vt 0.613536059856 0.349697083235 0.000000000000 -vt 0.593470990658 0.343456894159 0.000000000000 -vt 0.615174353123 0.332106143236 0.000000000000 -vt 0.627085506916 0.345775991678 0.000000000000 -vt 0.635642707348 0.359163492918 0.000000000000 -vt 0.624931395054 0.369269371033 0.000000000000 -vt 0.614598810673 0.373340398073 0.000000000000 -vt 0.608756959438 0.360698610544 0.000000000000 -vt 0.595678865910 0.357187539339 0.000000000000 -vt 0.436208903790 0.152205392718 0.000000000000 -vt 0.456390678883 0.160455301404 0.000000000000 -vt 0.470007836819 0.150451436639 0.000000000000 -vt 0.463308125734 0.141743332148 0.000000000000 -vt 0.426335632801 0.240489169955 0.000000000000 -vt 0.436077862978 0.227415770292 0.000000000000 -vt 0.568314850330 0.508301794529 0.000000000000 -vt 0.585736811161 0.522079706192 0.000000000000 -vt 0.563862621784 0.526518404484 0.000000000000 -vt 0.552698671818 0.519208967686 0.000000000000 -vt 0.611942946911 0.313467800617 0.000000000000 -vt 0.543040931225 0.535523951054 0.000000000000 -vt 0.869499862194 0.252641230822 0.000000000000 -vt 0.794922888279 0.858771979809 0.000000000000 -vt 0.771254837513 0.855260670185 0.000000000000 -vt 0.747811377048 0.852186858654 0.000000000000 -vt 0.797975599766 0.840329766273 0.000000000000 -vt 0.773927867413 0.839067518711 0.000000000000 -vt 0.750024020672 0.837795853615 0.000000000000 -vt 0.816554009914 0.862926125526 0.000000000000 -vt 0.819631397724 0.841430306435 0.000000000000 -vt 0.863419592381 0.971586704254 0.000000000000 -vt 0.886208474636 0.956715881824 0.000000000000 -vt 0.845495879650 0.192380949855 0.000000000000 -vt 0.921158373356 0.909126162529 0.000000000000 -vt 0.928987085819 0.927418887615 0.000000000000 -vt 0.914810121059 0.888543367386 0.000000000000 -vt 0.449255734682 0.250441461802 0.000000000000 -vt 0.429135203362 0.255882352591 0.000000000000 -vt 0.454719811678 0.222426101565 0.000000000000 -vt 0.463549941778 0.236386403441 0.000000000000 -vt 0.480748862028 0.132810741663 0.000000000000 -vt 0.460707813501 0.129074752331 0.000000000000 -vt 0.890980184078 0.866303682327 0.000000000000 -vt 0.906893670559 0.863792300224 0.000000000000 -vt 0.901800453663 0.838266909122 0.000000000000 -vt 0.885961711407 0.839472353458 0.000000000000 -vt 0.672634780407 0.403682291508 0.000000000000 -vt 0.870305716991 0.840758919716 0.000000000000 -vt 0.709015905857 0.913828730583 0.000000000000 -vt 0.702005445957 0.906553089619 0.000000000000 -vt 0.664313495159 0.411870300770 0.000000000000 -vt 0.651246488094 0.405295312405 0.000000000000 -vt 0.658828794956 0.392099201679 0.000000000000 -vt 0.648704469204 0.380986869335 0.000000000000 -vt 0.598465621471 0.371364206076 0.000000000000 -vt 0.649795591831 0.422901540995 0.000000000000 -vt 0.666176021099 0.425574362278 0.000000000000 -vt 0.478667050600 0.121633604169 0.000000000000 -vt 0.439155727625 0.188678041101 0.000000000000 -vt 0.419110178947 0.186491340399 0.000000000000 -vt 0.828646361828 0.222074419260 0.000000000000 -vt 0.825475156307 0.193224608898 0.000000000000 -vt 0.842488110065 0.165252909064 0.000000000000 -vt 0.821768820286 0.166762799025 0.000000000000 -vt 0.836636006832 0.816951870918 0.000000000000 -vt 0.852425515652 0.813404560089 0.000000000000 -vt 0.638719737530 0.461908787489 0.000000000000 -vt 0.645538747311 0.442247092724 0.000000000000 -vt 0.666097700596 0.445383280516 0.000000000000 -vt 0.662395417690 0.464661508799 0.000000000000 -vt 0.617127835751 0.458045125008 0.000000000000 -vt 0.627697288990 0.440409153700 0.000000000000 -vt 0.635399162769 0.421377927065 0.000000000000 -vt 0.609715163708 0.435786485672 0.000000000000 -vt 0.619829595089 0.417641699314 0.000000000000 -vt 0.590706527233 0.430238008499 0.000000000000 -vt 0.600633800030 0.414015561342 0.000000000000 -vt 0.605100929737 0.397916287184 0.000000000000 -vt 0.580789983273 0.413832962513 0.000000000000 -vt 0.585207521915 0.396601408720 0.000000000000 -vt 0.583855688572 0.381996691227 0.000000000000 -vt 0.602939188480 0.384962439537 0.000000000000 -vt 0.583396375179 0.371497720480 0.000000000000 -vt 0.567030251026 0.398448109627 0.000000000000 -vt 0.565822064877 0.380739450455 0.000000000000 -vt 0.565940558910 0.366790413857 0.000000000000 -vt 0.546947419643 0.397279322147 0.000000000000 -vt 0.547453343868 0.381623625755 0.000000000000 -vt 0.546291291714 0.366621524096 0.000000000000 -vt 0.529646694660 0.384682595730 0.000000000000 -vt 0.528711616993 0.373113870621 0.000000000000 -vt 0.526230156422 0.363655120134 0.000000000000 -vt 0.543110311031 0.353565901518 0.000000000000 -vt 0.560514271259 0.346006095409 0.000000000000 -vt 0.521848142147 0.354256451130 0.000000000000 -vt 0.537153065205 0.340497672558 0.000000000000 -vt 0.550614297390 0.329262435436 0.000000000000 -vt 0.573693096638 0.334259301424 0.000000000000 -vt 0.565188109875 0.321530610323 0.000000000000 -vt 0.481604665518 0.473584860563 0.000000000000 -vt 0.503952205181 0.484111279249 0.000000000000 -vt 0.523758590221 0.503893256187 0.000000000000 -vt 0.516087591648 0.344791620970 0.000000000000 -vt 0.508227407932 0.335609555244 0.000000000000 -vt 0.518797814846 0.319672405720 0.000000000000 -vt 0.510983765125 0.468507856131 0.000000000000 -vt 0.490077227354 0.435670107603 0.000000000000 -vt 0.502925693989 0.448421299458 0.000000000000 -vt 0.522674977779 0.457363337278 0.000000000000 -vt 0.530655562878 0.477804929018 0.000000000000 -vt 0.538420259953 0.463601946831 0.000000000000 -vt 0.515796720982 0.440703213215 0.000000000000 -vt 0.534934461117 0.448625057936 0.000000000000 -vt 0.549823939800 0.452839523554 0.000000000000 -vt 0.557107031345 0.466927945614 0.000000000000 -vt 0.568541586399 0.456593096256 0.000000000000 -vt 0.547232806683 0.441114574671 0.000000000000 -vt 0.561775863171 0.442336261272 0.000000000000 -vt 0.578855931759 0.444288581610 0.000000000000 -vt 0.586479246616 0.463815152645 0.000000000000 -vt 0.597201764584 0.451105147600 0.000000000000 -vt 0.571721136570 0.429578959942 0.000000000000 -vt 0.557132422924 0.430043905973 0.000000000000 -vt 0.564029395580 0.415538519621 0.000000000000 -vt 0.537347137928 0.424302697182 0.000000000000 -vt 0.544077932835 0.411527603865 0.000000000000 -vt 0.518473088741 0.418114066124 0.000000000000 -vt 0.524959385395 0.408595174551 0.000000000000 -vt 0.528635084629 0.397043138742 0.000000000000 -vt 0.509449779987 0.404620736837 0.000000000000 -vt 0.513173401356 0.395612955093 0.000000000000 -vt 0.514248788357 0.385702759027 0.000000000000 -vt 0.513777077198 0.377086073160 0.000000000000 -vt 0.512884557247 0.370190680027 0.000000000000 -vt 0.510034501553 0.363916963339 0.000000000000 -vt 0.505580484867 0.356326758862 0.000000000000 -vt 0.500341594219 0.348006844521 0.000000000000 -vt 0.481183856726 0.423593431711 0.000000000000 -vt 0.500625789165 0.430742353201 0.000000000000 -vt 0.490146607161 0.420840919018 0.000000000000 -vt 0.498169153929 0.417084664106 0.000000000000 -vt 0.510002553463 0.425448060036 0.000000000000 -vt 0.527178347111 0.433869749308 0.000000000000 -vt 0.503946959972 0.411769419909 0.000000000000 -vt 0.596737325191 0.484501451254 0.000000000000 -vt 0.576489269733 0.474731117487 0.000000000000 -vt 0.606985628605 0.472689867020 0.000000000000 -vt 0.584141671658 0.495642870665 0.000000000000 -vt 0.563076555729 0.485377997160 0.000000000000 -vt 0.546334922314 0.479332834482 0.000000000000 -vt 0.550337493420 0.497008413076 0.000000000000 -vt 0.537908732891 0.494894415140 0.000000000000 -vt 0.526974737644 0.490041226149 0.000000000000 -vt 0.537790954113 0.509640336037 0.000000000000 -vt 0.527427136898 0.525675892830 0.000000000000 -vt 0.605959832668 0.507260859013 0.000000000000 -vt 0.620633423328 0.493587821722 0.000000000000 -vt 0.631438195705 0.478594750166 0.000000000000 -vt 0.817847788334 0.142355754972 0.000000000000 -vt 0.814487040043 0.119411304593 0.000000000000 -vt 0.658278763294 0.481082051992 0.000000000000 -vt 0.811750113964 0.097056999803 0.000000000000 -vt 0.809368431568 0.075157731771 0.000000000000 -vt 0.807133018970 0.053564000875 0.000000000000 -vt 0.831686437130 0.254841685295 0.000000000000 -vt 0.856208741665 0.293983995914 0.000000000000 -vt 0.835455358028 0.290136784315 0.000000000000 -vt 0.873124063015 0.283648252487 0.000000000000 -vt 0.889739573002 0.279546380043 0.000000000000 -vt 0.909207642078 0.276814579964 0.000000000000 -vt 0.929072201252 0.276617109776 0.000000000000 -vt 0.884098351002 0.044427882880 0.000000000000 -vt 0.824312150478 0.028333339840 0.000000000000 -vt 0.804996788502 0.032941136509 0.000000000000 -vt 0.745384037495 0.153986141086 0.000000000000 -vt 0.727315604687 0.170344561338 0.000000000000 -vt 0.831523954868 0.792076110840 0.000000000000 -vt 0.846453726292 0.786361873150 0.000000000000 -vt 0.871971428394 0.766853511333 0.000000000000 -vt 0.860507428646 0.778107702732 0.000000000000 -vt 0.849813520908 0.750272214413 0.000000000000 -vt 0.864782273769 0.752571046352 0.000000000000 -vt 0.641757309437 0.369858145714 0.000000000000 -vt 0.871010005474 0.740061163902 0.000000000000 -vt 0.856036365032 0.728532135487 0.000000000000 -vt 0.833810746670 0.763259589672 0.000000000000 -vt 0.880542218685 0.781249523163 0.000000000000 -vt 0.870216548443 0.805862307549 0.000000000000 -vt 0.895947515965 0.765040814877 0.000000000000 -vt 0.886363804340 0.766362249851 0.000000000000 -vt 0.881665766239 0.753908455372 0.000000000000 -vt 0.896844565868 0.741948008537 0.000000000000 -vt 0.892329037189 0.786806523800 0.000000000000 -vt 0.730150520802 0.779693901539 0.000000000000 -vt 0.720385253429 0.768897235394 0.000000000000 -vt 0.732248246670 0.757981956005 0.000000000000 -vt 0.746850073338 0.773370444775 0.000000000000 -vt 0.746807038784 0.737674295902 0.000000000000 -vt 0.754076421261 0.750202596188 0.000000000000 -vt 0.729847013950 0.741506457329 0.000000000000 -vt 0.766269385815 0.766434729099 0.000000000000 -vt 0.732167899609 0.725132286549 0.000000000000 -vt 0.744101583958 0.727173089981 0.000000000000 -vt 0.726897180080 0.154936745763 0.000000000000 -vt 0.736608207226 0.138647675514 0.000000000000 -vt 0.757733404636 0.048427533358 0.000000000000 -vt 0.748305857182 0.039854753762 0.000000000000 -vt 0.762275159359 0.025697443634 0.000000000000 -vt 0.771673381329 0.029945448041 0.000000000000 -vt 0.737863123417 0.066377580166 0.000000000000 -vt 0.730143487453 0.052494283766 0.000000000000 -vt 0.754568159580 0.099855229259 0.000000000000 -vt 0.731352865696 0.116734221578 0.000000000000 -vt 0.725217759609 0.099748730659 0.000000000000 -vt 0.746904551983 0.081010863185 0.000000000000 -vt 0.718968212605 0.084019616246 0.000000000000 -vt 0.786774814129 0.105366572738 0.000000000000 -vt 0.761492788792 0.119630172849 0.000000000000 -vt 0.781676113605 0.084223598242 0.000000000000 -vt 0.775007426739 0.059413980693 0.000000000000 -vt 0.791212141514 0.126294299960 0.000000000000 -vt 0.767748415470 0.138232484460 0.000000000000 -vt 0.435300618410 0.206924617290 0.000000000000 -vt 0.415769994259 0.205245867372 0.000000000000 -vt 0.415477305651 0.223549634218 0.000000000000 -vt 0.415708750486 0.260153979063 0.000000000000 -vt 0.415216326714 0.241337999701 0.000000000000 -vt 0.431532442570 0.277840822935 0.000000000000 -vt 0.416861325502 0.282650142908 0.000000000000 -vt 0.437933146954 0.297910034657 0.000000000000 -vt 0.422700941563 0.304020076990 0.000000000000 -vt 0.710437953472 0.745294928551 0.000000000000 -vt 0.448528498411 0.274154812098 0.000000000000 -vt 0.453730016947 0.292313814163 0.000000000000 -vt 0.466458499432 0.272584140301 0.000000000000 -vt 0.470066845417 0.288187146187 0.000000000000 -vt 0.483627885580 0.271198511124 0.000000000000 -vt 0.486174434423 0.284226238728 0.000000000000 -vt 0.468398451805 0.256950020790 0.000000000000 -vt 0.484410136938 0.259565204382 0.000000000000 -vt 0.499547928572 0.260835975409 0.000000000000 -vt 0.488594621420 0.251296162605 0.000000000000 -vt 0.500861465931 0.255602240562 0.000000000000 -vt 0.476949125528 0.155961647630 0.000000000000 -vt 0.496368080378 0.154256105423 0.000000000000 -vt 0.493585199118 0.162589550018 0.000000000000 -vt 0.484565943480 0.159969419241 0.000000000000 -vt 0.504522025585 0.250607877970 0.000000000000 -vt 0.490841835737 0.170824587345 0.000000000000 -vt 0.479497641325 0.168406203389 0.000000000000 -vt 0.468820154667 0.165049582720 0.000000000000 -vt 0.487937420607 0.179314747453 0.000000000000 -vt 0.474618524313 0.178034290671 0.000000000000 -vt 0.461312592030 0.176021173596 0.000000000000 -vt 0.485546678305 0.188977956772 0.000000000000 -vt 0.470588952303 0.189741462469 0.000000000000 -vt 0.455546349287 0.189690113068 0.000000000000 -vt 0.484867841005 0.200385212898 0.000000000000 -vt 0.468716144562 0.203217670321 0.000000000000 -vt 0.452557861805 0.205941826105 0.000000000000 -vt 0.486695379019 0.212983325124 0.000000000000 -vt 0.470563501120 0.217475160956 0.000000000000 -vt 0.498891204596 0.197758778930 0.000000000000 -vt 0.500793755054 0.208588525653 0.000000000000 -vt 0.503768861294 0.215860128403 0.000000000000 -vt 0.490694373846 0.221827194095 0.000000000000 -vt 0.476610749960 0.228770300746 0.000000000000 -vt 0.508271515369 0.222307890654 0.000000000000 -vt 0.496900588274 0.229248985648 0.000000000000 -vt 0.485334604979 0.237566873431 0.000000000000 -vt 0.505223691463 0.237320348620 0.000000000000 -vt 0.495418399572 0.244713291526 0.000000000000 -vt 0.475383609533 0.245258644223 0.000000000000 -vt 0.514443337917 0.230237171054 0.000000000000 -vt 0.519902884960 0.237665936351 0.000000000000 -vt 0.511179625988 0.154767423868 0.000000000000 -vt 0.523703515530 0.224226221442 0.000000000000 -vt 0.534955561161 0.219976648688 0.000000000000 -vt 0.539630472660 0.226309135556 0.000000000000 -vt 0.522125780582 0.163012161851 0.000000000000 -vt 0.511400759220 0.162948891521 0.000000000000 -vt 0.502651274204 0.163395151496 0.000000000000 -vt 0.521724998951 0.170782491565 0.000000000000 -vt 0.510841667652 0.171353936195 0.000000000000 -vt 0.501311361790 0.171751782298 0.000000000000 -vt 0.521135985851 0.178479418159 0.000000000000 -vt 0.510029613972 0.179412469268 0.000000000000 -vt 0.499761670828 0.179692775011 0.000000000000 -vt 0.521464765072 0.184219524264 0.000000000000 -vt 0.509710252285 0.186720550060 0.000000000000 -vt 0.498645514250 0.187971740961 0.000000000000 -vt 0.522567331791 0.189815983176 0.000000000000 -vt 0.510646045208 0.194714680314 0.000000000000 -vt 0.552625119686 0.181308269501 0.000000000000 -vt 0.553095877171 0.186058148742 0.000000000000 -vt 0.535693705082 0.186998158693 0.000000000000 -vt 0.534666717052 0.182170838118 0.000000000000 -vt 0.553785145283 0.190441906452 0.000000000000 -vt 0.537737786770 0.193066775799 0.000000000000 -vt 0.524687230587 0.197172924876 0.000000000000 -vt 0.554820120335 0.194571927190 0.000000000000 -vt 0.540497124195 0.200262054801 0.000000000000 -vt 0.527609050274 0.205128788948 0.000000000000 -vt 0.556690990925 0.198639363050 0.000000000000 -vt 0.543533384800 0.206711396575 0.000000000000 -vt 0.531002581120 0.212646707892 0.000000000000 -vt 0.558761537075 0.202166423202 0.000000000000 -vt 0.546805322170 0.212670803070 0.000000000000 -vt 0.550771892071 0.218399211764 0.000000000000 -vt 0.561493337154 0.206085249782 0.000000000000 -vt 0.535221517086 0.163484767079 0.000000000000 -vt 0.552473127842 0.164653763175 0.000000000000 -vt 0.534547865391 0.169898986816 0.000000000000 -vt 0.552217543125 0.170028448105 0.000000000000 -vt 0.534365713596 0.176693260670 0.000000000000 -vt 0.552374064922 0.175845101476 0.000000000000 -vt 0.432602375746 0.133366212249 0.000000000000 -vt 0.579707443714 0.344648867846 0.000000000000 -vt 0.582962691784 0.359227657318 0.000000000000 -vt 0.699510276318 0.760418593884 0.000000000000 -vt 0.690002620220 0.760535240173 0.000000000000 -vt 0.573572456837 0.358697652817 0.000000000000 -vt 0.571034729481 0.348925471306 0.000000000000 -vt 0.795890152454 0.148126482964 0.000000000000 -vt 0.773672997952 0.158082619309 0.000000000000 -vt 0.761886537075 0.368884116411 0.000000000000 -vt 0.756864488125 0.374716073275 0.000000000000 -vt 0.752732694149 0.371530354023 0.000000000000 -vt 0.756020605564 0.368056684732 0.000000000000 -vt 0.745198905468 0.426691144705 0.000000000000 -vt 0.748513877392 0.424927502871 0.000000000000 -vt 0.751336514950 0.428736001253 0.000000000000 -vt 0.745641887188 0.430311173201 0.000000000000 -vt 0.718655884266 0.367600291967 0.000000000000 -vt 0.723707854748 0.362223118544 0.000000000000 -vt 0.731543242931 0.368654459715 0.000000000000 -vt 0.727982223034 0.373404115438 0.000000000000 -vt 0.723776161671 0.384299814701 0.000000000000 -vt 0.712015807629 0.382623314857 0.000000000000 -vt 0.714580357075 0.374560505152 0.000000000000 -vt 0.725447237492 0.378716200590 0.000000000000 -vt 0.743162930012 0.370530217886 0.000000000000 -vt 0.739214956760 0.374083191156 0.000000000000 -vt 0.736095726490 0.364764451981 0.000000000000 -vt 0.470379114151 0.072487622499 0.000000000000 -vt 0.476932018995 0.067091092467 0.000000000000 -vt 0.483967453241 0.075338751078 0.000000000000 -vt 0.477926939726 0.080794483423 0.000000000000 -vt 0.511079013348 0.066174268723 0.000000000000 -vt 0.508617579937 0.072203919291 0.000000000000 -vt 0.499857753515 0.062445472926 0.000000000000 -vt 0.504508316517 0.058762382716 0.000000000000 -vt 0.705864846706 0.371028959751 0.000000000000 -vt 0.701381266117 0.375573486090 0.000000000000 -vt 0.698225557804 0.370354384184 0.000000000000 -vt 0.697068870068 0.367405295372 0.000000000000 -vt 0.701902329922 0.391683101654 0.000000000000 -vt 0.691578447819 0.393901556730 0.000000000000 -vt 0.693959891796 0.392793804407 0.000000000000 -vt 0.699081957340 0.388415664434 0.000000000000 -vt 0.712482511997 0.363048106432 0.000000000000 -vt 0.706260859966 0.399656295776 0.000000000000 -vt 0.710350573063 0.390655279160 0.000000000000 -vt 0.709410727024 0.398413658142 0.000000000000 -vt 0.497506469488 0.086208790541 0.000000000000 -vt 0.499487847090 0.088523834944 0.000000000000 -vt 0.496975511312 0.090857118368 0.000000000000 -vt 0.494485110044 0.087826982141 0.000000000000 -vt 0.485454589128 0.095807611942 0.000000000000 -vt 0.487140089273 0.098796099424 0.000000000000 -vt 0.483731955290 0.100186884403 0.000000000000 -vt 0.481757134199 0.096767678857 0.000000000000 -vt 0.701098263264 0.382279485464 0.000000000000 -vt 0.704454600811 0.381990849972 0.000000000000 -vt 0.505547583103 0.089302882552 0.000000000000 -vt 0.507946908474 0.095191136003 0.000000000000 -vt 0.725627362728 0.354063272476 0.000000000000 -vt 0.730535089970 0.352071553469 0.000000000000 -vt 0.733845055103 0.356517255306 0.000000000000 -vt 0.729133427143 0.358981132507 0.000000000000 -vt 0.502358973026 0.098305702209 0.000000000000 -vt 0.499749034643 0.094421327114 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.499274820089 0.102383270860 0.000000000000 -vt 0.709335625172 0.404707193375 0.000000000000 -vt 0.707483947277 0.405635058880 0.000000000000 -vt 0.516392290592 0.069226473570 0.000000000000 -vt 0.518077909946 0.071355760098 0.000000000000 -vt 0.718284785748 0.355620443821 0.000000000000 -vt 0.516956746578 0.073715612292 0.000000000000 -vt 0.514483392239 0.070643588901 0.000000000000 -vt 0.668390452862 0.386624544859 0.000000000000 -vt 0.667060911655 0.380806088448 0.000000000000 -vt 0.671376407146 0.380861908197 0.000000000000 -vt 0.671312749386 0.384570688009 0.000000000000 -vt 0.669187486172 0.375094115734 0.000000000000 -vt 0.671998560429 0.377249538898 0.000000000000 -vt 0.691448748112 0.370133042336 0.000000000000 -vt 0.690848052502 0.375890284777 0.000000000000 -vt 0.686910808086 0.375525057316 0.000000000000 -vt 0.687306106091 0.369519740343 0.000000000000 -vt 0.686368644238 0.386486738920 0.000000000000 -vt 0.689943373203 0.386325776577 0.000000000000 -vt 0.688951313496 0.392648577690 0.000000000000 -vt 0.685665905476 0.393045514822 0.000000000000 -vt 0.690709650517 0.381118148565 0.000000000000 -vt 0.686853349209 0.380862385035 0.000000000000 -vt 0.480086654425 0.100869327784 0.000000000000 -vt 0.478839308023 0.098695233464 0.000000000000 -vt 0.678826630116 0.369220048189 0.000000000000 -vt 0.679812729359 0.375340670347 0.000000000000 -vt 0.675520837307 0.375914126635 0.000000000000 -vt 0.673433959484 0.370380729437 0.000000000000 -vt 0.674808919430 0.385995447636 0.000000000000 -vt 0.679343521595 0.386584460735 0.000000000000 -vt 0.678030192852 0.392984062433 0.000000000000 -vt 0.672598540783 0.391514003277 0.000000000000 -vt 0.680286943913 0.380828380585 0.000000000000 -vt 0.675836026669 0.380848854780 0.000000000000 -vt 0.515295088291 0.075423642993 0.000000000000 -vt 0.513281047344 0.073069870472 0.000000000000 -vt 0.693681657314 0.376642733812 0.000000000000 -vt 0.693711340427 0.371875762939 0.000000000000 -vt 0.696114480495 0.370918631554 0.000000000000 -vt 0.696933090687 0.376871287823 0.000000000000 -vt 0.691533505917 0.391513794661 0.000000000000 -vt 0.692914068699 0.386218369007 0.000000000000 -vt 0.695932805538 0.386784404516 0.000000000000 -vt 0.693213999271 0.392598807812 0.000000000000 -vt 0.693558990955 0.381606072187 0.000000000000 -vt 0.696726262569 0.381991982460 0.000000000000 -vt 0.512632310390 0.113346979022 0.000000000000 -vt 0.510703504086 0.110827267170 0.000000000000 -vt 0.515379965305 0.107007056475 0.000000000000 -vt 0.518175065517 0.110701844096 0.000000000000 -vt 0.505509078503 0.114236339927 0.000000000000 -vt 0.508307397366 0.117514595389 0.000000000000 -vt 0.518149077892 0.121353730559 0.000000000000 -vt 0.522928655148 0.117672875524 0.000000000000 -vt 0.525190651417 0.121514260769 0.000000000000 -vt 0.683571517467 0.375538796186 0.000000000000 -vt 0.683092653751 0.370623677969 0.000000000000 -vt 0.682278931141 0.392029613256 0.000000000000 -vt 0.683356225491 0.386358857155 0.000000000000 -vt 0.684057652950 0.380769610405 0.000000000000 -vt 0.519570291042 0.123483464122 0.000000000000 -vt 0.516307771206 0.128428325057 0.000000000000 -vt 0.513406455517 0.124672070146 0.000000000000 -vt 0.511565864086 0.103494629264 0.000000000000 -vt 0.507416427135 0.106189742684 0.000000000000 -vt 0.506013691425 0.103982776403 0.000000000000 -vt 0.509203732014 0.102665841579 0.000000000000 -vt 0.504296243191 0.108756288886 0.000000000000 -vt 0.503382742405 0.106384947896 0.000000000000 -vt 0.511651098728 0.106469616294 0.000000000000 -vt 0.509026229382 0.108525276184 0.000000000000 -vt 0.506196796894 0.110484585166 0.000000000000 -vt 0.518708407879 0.115314379334 0.000000000000 -vt 0.515459358692 0.117382884026 0.000000000000 -vt 0.514127433300 0.115409389138 0.000000000000 -vt 0.518203437328 0.112691774964 0.000000000000 -vt 0.512567102909 0.119688019156 0.000000000000 -vt 0.511780798435 0.117559626698 0.000000000000 -vt 0.519389688969 0.117316469550 0.000000000000 -vt 0.516777694225 0.119350507855 0.000000000000 -vt 0.514133274555 0.121143206954 0.000000000000 -vt 0.510631144047 0.099778667092 0.000000000000 -vt 0.504632174969 0.101817682385 0.000000000000 -vt 0.499871104956 0.106421664357 0.000000000000 -vt 0.500889837742 0.111934348941 0.000000000000 -vt 0.514839589596 0.101724907756 0.000000000000 -vt 0.509192049503 0.122385606170 0.000000000000 -vt 0.522657573223 0.113145455718 0.000000000000 -vt 0.522569835186 0.127797886729 0.000000000000 -vt 0.521396934986 0.126231938601 0.000000000000 -vt 0.735525667667 0.349380731583 0.000000000000 -vt 0.738029062748 0.353152751923 0.000000000000 -vt 0.709487140179 0.411515235901 0.000000000000 -vt 0.706850707531 0.412472575903 0.000000000000 -vt 0.713795721531 0.355628103018 0.000000000000 -vt 0.714886367321 0.349705845118 0.000000000000 -vt 0.715047299862 0.346170902252 0.000000000000 -vt 0.700704872608 0.366192162037 0.000000000000 -vt 0.705918371677 0.365258455276 0.000000000000 -vt 0.710480749607 0.361039042473 0.000000000000 -vt 0.523268878460 0.125216260552 0.000000000000 -vt 0.523997724056 0.126300171018 0.000000000000 -vt 0.687866628170 0.342219889164 0.000000000000 -vt 0.691187441349 0.337702393532 0.000000000000 -vt 0.693574011326 0.340425401926 0.000000000000 -vt 0.690801203251 0.342919677496 0.000000000000 -vt 0.696296155453 0.334926456213 0.000000000000 -vt 0.696642935276 0.338050007820 0.000000000000 -vt 0.711912453175 0.345587313175 0.000000000000 -vt 0.707153379917 0.348584800959 0.000000000000 -vt 0.704814493656 0.344684004784 0.000000000000 -vt 0.710185706615 0.341764390469 0.000000000000 -vt 0.695865690708 0.351892799139 0.000000000000 -vt 0.699073016644 0.355076700449 0.000000000000 -vt 0.695596873760 0.359068036079 0.000000000000 -vt 0.692301213741 0.356082707644 0.000000000000 -vt 0.702675044537 0.351823449135 0.000000000000 -vt 0.699874341488 0.348093301058 0.000000000000 -vt 0.520938813686 0.128895744681 0.000000000000 -vt 0.520082056522 0.127839773893 0.000000000000 -vt 0.705446422100 0.335541337729 0.000000000000 -vt 0.701623976231 0.340389162302 0.000000000000 -vt 0.699281990528 0.338887810707 0.000000000000 -vt 0.701398193836 0.333822280169 0.000000000000 -vt 0.691363513470 0.345513224602 0.000000000000 -vt 0.692718684673 0.347970575094 0.000000000000 -vt 0.688071906567 0.350903898478 0.000000000000 -vt 0.686495840549 0.347062766552 0.000000000000 -vt 0.697414934635 0.344720244408 0.000000000000 -vt 0.695644319057 0.342764317989 0.000000000000 -vt 0.526300132275 0.132303252816 0.000000000000 -vt 0.524093449116 0.129697531462 0.000000000000 -vt 0.709353864193 0.352346479893 0.000000000000 -vt 0.712929904461 0.348732739687 0.000000000000 -vt 0.714268267155 0.349192053080 0.000000000000 -vt 0.711979806423 0.354660391808 0.000000000000 -vt 0.699490010738 0.361016511917 0.000000000000 -vt 0.702696144581 0.358416646719 0.000000000000 -vt 0.704991638660 0.361978620291 0.000000000000 -vt 0.700050175190 0.364112406969 0.000000000000 -vt 0.705978453159 0.355808466673 0.000000000000 -vt 0.708694994450 0.358966708183 0.000000000000 -vt 0.525715887547 0.126499876380 0.000000000000 -vt 0.528771936893 0.126690357924 0.000000000000 -vt 0.523779094219 0.124067738652 0.000000000000 -vt 0.520451605320 0.124855801463 0.000000000000 -vt 0.518978536129 0.127953931689 0.000000000000 -vt 0.520814955235 0.130581036210 0.000000000000 -vt 0.520374357700 0.133407860994 0.000000000000 -vt 0.508442223072 0.077186152339 0.000000000000 -vt 0.510329902172 0.079375565052 0.000000000000 -vt 0.703039348125 0.342263132334 0.000000000000 -vt 0.707691013813 0.338801592588 0.000000000000 -vt 0.691107928753 0.352693885565 0.000000000000 -vt 0.694404184818 0.349684000015 0.000000000000 -vt 0.698663651943 0.346254229546 0.000000000000 -vt 0.508014619350 0.081564977765 0.000000000000 -vt 0.505533874035 0.078727111220 0.000000000000 -vt 0.494260638952 0.093220800161 0.000000000000 -vt 0.492302030325 0.090663939714 0.000000000000 -vt 0.505529224873 0.083532154560 0.000000000000 -vt 0.503514945507 0.081306725740 0.000000000000 -vt 0.510711610317 0.084656804800 0.000000000000 -vt 0.514165699482 0.088350698352 0.000000000000 -vt 0.511911690235 0.093188375235 0.000000000000 -vt 0.527652680874 0.098926231265 0.000000000000 -vt 0.525356113911 0.097472637892 0.000000000000 -vt 0.528094470501 0.091692224145 0.000000000000 -vt 0.531258046627 0.093997821212 0.000000000000 -vt 0.521796643734 0.102959886193 0.000000000000 -vt 0.525596559048 0.105276063085 0.000000000000 -vt 0.534857928753 0.104219183326 0.000000000000 -vt 0.537856757641 0.099045574665 0.000000000000 -vt 0.540888249874 0.101543441415 0.000000000000 -vt 0.536647617817 0.105644643307 0.000000000000 -vt 0.534925162792 0.111184135079 0.000000000000 -vt 0.531729161739 0.109336286783 0.000000000000 -vt 0.523591578007 0.091089487076 0.000000000000 -vt 0.730021059513 0.349459081888 0.000000000000 -vt 0.735328376293 0.349237293005 0.000000000000 -vt 0.715811312199 0.346691012383 0.000000000000 -vt 0.720742166042 0.350149869919 0.000000000000 -vt 0.725372970104 0.349892735481 0.000000000000 -vt 0.521666467190 0.094739928842 0.000000000000 -vt 0.520136296749 0.093459248543 0.000000000000 -vt 0.731795966625 0.325470387936 0.000000000000 -vt 0.736351430416 0.326853275299 0.000000000000 -vt 0.734878718853 0.329794704914 0.000000000000 -vt 0.732054173946 0.328241348267 0.000000000000 -vt 0.739810764790 0.330046653748 0.000000000000 -vt 0.737516939640 0.331477284431 0.000000000000 -vt 0.737019240856 0.345520436764 0.000000000000 -vt 0.732173502445 0.343047350645 0.000000000000 -vt 0.734046399593 0.340439140797 0.000000000000 -vt 0.738021910191 0.343094855547 0.000000000000 -vt 0.725114047527 0.336557924747 0.000000000000 -vt 0.723978340626 0.339484244585 0.000000000000 -vt 0.718742549419 0.338676393032 0.000000000000 -vt 0.720449268818 0.335456222296 0.000000000000 -vt 0.728333771229 0.341184616089 0.000000000000 -vt 0.729620277882 0.338552564383 0.000000000000 -vt 0.521848857403 0.090589866042 0.000000000000 -vt 0.519341766834 0.098529517651 0.000000000000 -vt 0.741242706776 0.337124168873 0.000000000000 -vt 0.736575305462 0.336675226688 0.000000000000 -vt 0.737431108952 0.333985060453 0.000000000000 -vt 0.741768896580 0.333650708199 0.000000000000 -vt 0.730156362057 0.329479277134 0.000000000000 -vt 0.728279173374 0.331620484591 0.000000000000 -vt 0.724462211132 0.328425318003 0.000000000000 -vt 0.727317392826 0.325960755348 0.000000000000 -vt 0.732129871845 0.334760516882 0.000000000000 -vt 0.733519494534 0.332428127527 0.000000000000 -vt 0.518350422382 0.096643164754 0.000000000000 -vt 0.524855554104 0.092653632164 0.000000000000 -vt 0.731151521206 0.345263779163 0.000000000000 -vt 0.735784590244 0.347043156624 0.000000000000 -vt 0.736424624920 0.348627597094 0.000000000000 -vt 0.730661809444 0.347184121609 0.000000000000 -vt 0.718040287495 0.341615349054 0.000000000000 -vt 0.723183095455 0.342720180750 0.000000000000 -vt 0.721934854984 0.345855712891 0.000000000000 -vt 0.715493619442 0.344276010990 0.000000000000 -vt 0.727172791958 0.344054907560 0.000000000000 -vt 0.726349413395 0.346510440111 0.000000000000 -vt 0.523354947567 0.096010923386 0.000000000000 -vt 0.521311223507 0.099254280329 0.000000000000 -vt 0.533330857754 0.097978785634 0.000000000000 -vt 0.531335532665 0.101454958320 0.000000000000 -vt 0.529585421085 0.100170671940 0.000000000000 -vt 0.531549036503 0.097181737423 0.000000000000 -vt 0.529571712017 0.105359822512 0.000000000000 -vt 0.528426826000 0.103743880987 0.000000000000 -vt 0.534639537334 0.099621966481 0.000000000000 -vt 0.735392153263 0.338480740786 0.000000000000 -vt 0.739044845104 0.340150952339 0.000000000000 -vt 0.723158061504 0.331868380308 0.000000000000 -vt 0.726885974407 0.334070175886 0.000000000000 -vt 0.730814039707 0.336822479963 0.000000000000 -vt 0.533084571362 0.102829977870 0.000000000000 -vt 0.531313717365 0.105897054076 0.000000000000 -vt 0.521283328533 0.087026789784 0.000000000000 -vt 0.517856895924 0.091663181782 0.000000000000 -vt 0.514960706234 0.097525775433 0.000000000000 -vt 0.517828285694 0.100980103016 0.000000000000 -vt 0.526034533978 0.087389066815 0.000000000000 -vt 0.527589142323 0.109247803688 0.000000000000 -vt 0.535756528378 0.095117062330 0.000000000000 -vt 0.539837419987 0.107863321900 0.000000000000 -vt 0.538558781147 0.107128873467 0.000000000000 -vt 0.539949953556 0.105316147208 0.000000000000 -vt 0.540825903416 0.105864629149 0.000000000000 -vt 0.538582384586 0.109620437026 0.000000000000 -vt 0.537616670132 0.109082773328 0.000000000000 -vt 0.544267117977 0.110548302531 0.000000000000 -vt 0.541652381420 0.108950823545 0.000000000000 -vt 0.542387545109 0.105380535126 0.000000000000 -vt 0.545064866543 0.104814276099 0.000000000000 -vt 0.540196716785 0.104028716683 0.000000000000 -vt 0.537597596645 0.106465324759 0.000000000000 -vt 0.536735951900 0.109748318791 0.000000000000 -vt 0.701508939266 0.396991372108 0.000000000000 -vt 0.695306599140 0.396085560322 0.000000000000 -vt 0.705828607082 0.412745684385 0.000000000000 -vt 0.705876052380 0.406576901674 0.000000000000 -vt 0.704530298710 0.401503235102 0.000000000000 -vt 0.538923561573 0.111143380404 0.000000000000 -vt 0.539531409740 0.113621219993 0.000000000000 -vt 0.688302695751 0.427976310253 0.000000000000 -vt 0.683832943439 0.424098700285 0.000000000000 -vt 0.687000572681 0.421046495438 0.000000000000 -vt 0.689052641392 0.424283087254 0.000000000000 -vt 0.681496918201 0.418339222670 0.000000000000 -vt 0.684903800488 0.417768895626 0.000000000000 -vt 0.690302073956 0.401867091656 0.000000000000 -vt 0.694480240345 0.405638903379 0.000000000000 -vt 0.692191779613 0.407944500446 0.000000000000 -vt 0.687600672245 0.404441058636 0.000000000000 -vt 0.699370443821 0.415826499462 0.000000000000 -vt 0.700973808765 0.413097828627 0.000000000000 -vt 0.704431712627 0.417759448290 0.000000000000 -vt 0.703326642513 0.420762330294 0.000000000000 -vt 0.697867929935 0.408945530653 0.000000000000 -vt 0.695929110050 0.411309421062 0.000000000000 -vt 0.517626106739 0.084983274341 0.000000000000 -vt 0.521136224270 0.070760220289 0.000000000000 -vt 0.683233559132 0.409444689751 0.000000000000 -vt 0.688319623470 0.412122905254 0.000000000000 -vt 0.686133563519 0.414829730988 0.000000000000 -vt 0.680900275707 0.412907809019 0.000000000000 -vt 0.692204892635 0.422975838184 0.000000000000 -vt 0.695665299892 0.420329362154 0.000000000000 -vt 0.698658287525 0.425916135311 0.000000000000 -vt 0.694272696972 0.428446441889 0.000000000000 -vt 0.692554771900 0.415226012468 0.000000000000 -vt 0.689908921719 0.417935758829 0.000000000000 -vt 0.523216187954 0.072577908635 0.000000000000 -vt 0.520890176296 0.077228039503 0.000000000000 -vt 0.697199761868 0.403361231089 0.000000000000 -vt 0.693439781666 0.400654852390 0.000000000000 -vt 0.693814694881 0.397902786732 0.000000000000 -vt 0.699269115925 0.401036739349 0.000000000000 -vt 0.704553306103 0.414974272251 0.000000000000 -vt 0.702452123165 0.410426139832 0.000000000000 -vt 0.703826010227 0.408506244421 0.000000000000 -vt 0.705401599407 0.414679765701 0.000000000000 -vt 0.700053751469 0.406474679708 0.000000000000 -vt 0.701919615269 0.404333680868 0.000000000000 -vt 0.519232571125 0.075901642442 0.000000000000 -vt 0.515266001225 0.080151677132 0.000000000000 -vt 0.519640505314 0.081991866231 0.000000000000 -vt 0.533958613873 0.080200076103 0.000000000000 -vt 0.531604349613 0.079964339733 0.000000000000 -vt 0.532588779926 0.075347989798 0.000000000000 -vt 0.535456359386 0.075775325298 0.000000000000 -vt 0.531062185764 0.084430292249 0.000000000000 -vt 0.534919083118 0.084616497159 0.000000000000 -vt 0.690639078617 0.410164058208 0.000000000000 -vt 0.686743676662 0.408009111881 0.000000000000 -vt 0.700886189938 0.422482520342 0.000000000000 -vt 0.697773873806 0.417764842510 0.000000000000 -vt 0.694584786892 0.413028031588 0.000000000000 -vt 0.543268382549 0.081021666527 0.000000000000 -vt 0.542410075665 0.076548516750 0.000000000000 -vt 0.545253694057 0.076710179448 0.000000000000 -vt 0.544744908810 0.081107899547 0.000000000000 -vt 0.545586764812 0.085359513760 0.000000000000 -vt 0.542715609074 0.085166096687 0.000000000000 -vt 0.528137505054 0.076546490192 0.000000000000 -vt 0.526995480061 0.079263880849 0.000000000000 -vt 0.524926722050 0.078719690442 0.000000000000 -vt 0.526245653629 0.076403737068 0.000000000000 -vt 0.526619493961 0.081934899092 0.000000000000 -vt 0.524678170681 0.081073686481 0.000000000000 -vt 0.529789626598 0.077268108726 0.000000000000 -vt 0.529239356518 0.079652726650 0.000000000000 -vt 0.528736531734 0.081992313266 0.000000000000 -vt 0.539014041424 0.077833026648 0.000000000000 -vt 0.539221823215 0.080529257655 0.000000000000 -vt 0.536268293858 0.080332249403 0.000000000000 -vt 0.536676228046 0.078035444021 0.000000000000 -vt 0.539300858974 0.083174824715 0.000000000000 -vt 0.536652386189 0.082537859678 0.000000000000 -vt 0.541114032269 0.078451976180 0.000000000000 -vt 0.541567981243 0.080870822072 0.000000000000 -vt 0.541349947453 0.083064511418 0.000000000000 -vt 0.525810420513 0.073440477252 0.000000000000 -vt 0.522990167141 0.078078895807 0.000000000000 -vt 0.522753298283 0.083092421293 0.000000000000 -vt 0.744985520840 0.358051896095 0.000000000000 -vt 0.740702569485 0.361511409283 0.000000000000 -vt 0.737015068531 0.377986699343 0.000000000000 -vt 0.527110517025 0.085661664605 0.000000000000 -vt 0.529920637608 0.072953239083 0.000000000000 -vt 0.539422690868 0.086372941732 0.000000000000 -vt 0.720288455486 0.404917716980 0.000000000000 -vt 0.725336492062 0.406646698713 0.000000000000 -vt 0.719956338406 0.413258612156 0.000000000000 -vt 0.717335283756 0.410958647728 0.000000000000 -vt 0.723915517330 0.398037433624 0.000000000000 -vt 0.731581389904 0.399601578712 0.000000000000 -vt 0.741063773632 0.398945480585 0.000000000000 -vt 0.741147696972 0.402583092451 0.000000000000 -vt 0.735348403454 0.405078500509 0.000000000000 -vt 0.724570930004 0.415234774351 0.000000000000 -vt 0.730074822903 0.409371733665 0.000000000000 -vt 0.755069792271 0.423953682184 0.000000000000 -vt 0.751188337803 0.423076480627 0.000000000000 -vt 0.732347548008 0.419561594725 0.000000000000 -vt 0.728611052036 0.417487025261 0.000000000000 -vt 0.734247624874 0.412292242050 0.000000000000 -vt 0.737663686275 0.415086418390 0.000000000000 -vt 0.739005625248 0.408245295286 0.000000000000 -vt 0.742154181004 0.411730021238 0.000000000000 -vt 0.728346526623 0.424829334021 0.000000000000 -vt 0.724365770817 0.423212945461 0.000000000000 -vt 0.539046466351 0.074854224920 0.000000000000 -vt 0.547604382038 0.081218689680 0.000000000000 -vt 0.744521200657 0.403573781252 0.000000000000 -vt 0.746637046337 0.406587243080 0.000000000000 -vt 0.546402513981 0.081313252449 0.000000000000 -vt 0.546436250210 0.079620987177 0.000000000000 -vt 0.547303736210 0.079606115818 0.000000000000 -vt 0.547511637211 0.082779005170 0.000000000000 -vt 0.546545684338 0.082813456655 0.000000000000 -vt 0.551446378231 0.080884099007 0.000000000000 -vt 0.719365775585 0.420285463333 0.000000000000 -vt 0.548926889896 0.081119611859 0.000000000000 -vt 0.547964394093 0.078651010990 0.000000000000 -vt 0.549326121807 0.076903134584 0.000000000000 -vt 0.546006023884 0.078606888652 0.000000000000 -vt 0.545527517796 0.081211924553 0.000000000000 -vt 0.740861833096 0.424791932106 0.000000000000 -vt 0.744636476040 0.421375900507 0.000000000000 -vt 0.748865187168 0.419236689806 0.000000000000 -vt 0.738058149815 0.430005639791 0.000000000000 -vt 0.546189963818 0.083545655012 0.000000000000 -vt 0.548156440258 0.083578765392 0.000000000000 -vt 0.549798786640 0.085083246231 0.000000000000 -vt 0.493128985167 0.107532128692 0.000000000000 -vt 0.487130194902 0.108177408576 0.000000000000 -vt 0.484787672758 0.104095578194 0.000000000000 -vt 0.754294574261 0.415865898132 0.000000000000 -vt 0.741011559963 0.418052166700 0.000000000000 -vt 0.736329138279 0.422021627426 0.000000000000 -vt 0.745218575001 0.415226459503 0.000000000000 -vt 0.732700407505 0.426749676466 0.000000000000 -vt 0.477795451880 0.104249805212 0.000000000000 -vt 0.480690747499 0.109506055713 0.000000000000 -vt 0.493065744638 0.123880639672 0.000000000000 -vt 0.492350906134 0.121099308133 0.000000000000 -vt 0.498245447874 0.118749126792 0.000000000000 -vt 0.499274820089 0.122994199395 0.000000000000 -vt 0.749212324619 0.411244809628 0.000000000000 -vt 0.486499279737 0.122255474329 0.000000000000 -vt 0.487754553556 0.125899389386 0.000000000000 -vt 0.495414823294 0.131725952029 0.000000000000 -vt 0.501138865948 0.129815727472 0.000000000000 -vt 0.501795589924 0.132985696197 0.000000000000 -vt 0.496015042067 0.133395478129 0.000000000000 -vt 0.491779893637 0.137110754848 0.000000000000 -vt 0.490246385336 0.133341893554 0.000000000000 -vt 0.493753403425 0.114416465163 0.000000000000 -vt 0.490512460470 0.116016864777 0.000000000000 -vt 0.716776549816 0.397952318192 0.000000000000 -vt 0.722395479679 0.390428304672 0.000000000000 -vt 0.748906552792 0.386245161295 0.000000000000 -vt 0.748211801052 0.394017070532 0.000000000000 -vt 0.743617475033 0.387832283974 0.000000000000 -vt 0.743471086025 0.384143799543 0.000000000000 -vt 0.735934555531 0.381866127253 0.000000000000 -vt 0.489763349295 0.113667383790 0.000000000000 -vt 0.714425027370 0.404076099396 0.000000000000 -vt 0.492669016123 0.112787023187 0.000000000000 -vt 0.487121194601 0.117388963699 0.000000000000 -vt 0.486971467733 0.115077972412 0.000000000000 -vt 0.494484215975 0.116980090737 0.000000000000 -vt 0.491517156363 0.118607267737 0.000000000000 -vt 0.488306194544 0.119425490499 0.000000000000 -vt 0.498060315847 0.127201452851 0.000000000000 -vt 0.713693201542 0.410189747810 0.000000000000 -vt 0.735486447811 0.385052949190 0.000000000000 -vt 0.746610701084 0.396617144346 0.000000000000 -vt 0.494058936834 0.127958431840 0.000000000000 -vt 0.493515819311 0.126024797559 0.000000000000 -vt 0.496876925230 0.125608488917 0.000000000000 -vt 0.490766674280 0.128856346011 0.000000000000 -vt 0.743014752865 0.389892905951 0.000000000000 -vt 0.735056340694 0.387602627277 0.000000000000 -vt 0.727178633213 0.392949610949 0.000000000000 -vt 0.733748018742 0.392339646816 0.000000000000 -vt 0.739848792553 0.392785251141 0.000000000000 -vt 0.747750461102 0.374964654446 0.000000000000 -vt 0.490720719099 0.127026960254 0.000000000000 -vt 0.750498473644 0.379568845034 0.000000000000 -vt 0.752317011356 0.363459676504 0.000000000000 -vt 0.747864067554 0.366984248161 0.000000000000 -vt 0.743768513203 0.380047321320 0.000000000000 -vt 0.743770778179 0.376911133528 0.000000000000 -vt 0.716933429241 0.416927278042 0.000000000000 -vt 0.497924119234 0.128914669156 0.000000000000 -vt 0.494692295790 0.129884406924 0.000000000000 -vt 0.491763919592 0.130519121885 0.000000000000 -vt 0.495831340551 0.110157430172 0.000000000000 -vt 0.489241451025 0.111455008388 0.000000000000 -vt 0.483312696218 0.114056900144 0.000000000000 -vt 0.482924073935 0.118979677558 0.000000000000 -vt 0.499466627836 0.113667383790 0.000000000000 -vt 0.487026840448 0.130218312144 0.000000000000 -vt 0.502736389637 0.126097753644 0.000000000000 -vt 0.497383981943 0.137650460005 0.000000000000 -vt 0.496828526258 0.135942205787 0.000000000000 -vt 0.498790949583 0.135475009680 0.000000000000 -vt 0.489594787359 0.354463160038 0.000000000000 -vt 0.493529766798 0.348664730787 0.000000000000 -vt 0.466066062450 0.416784971952 0.000000000000 -vt 0.492370694876 0.361383527517 0.000000000000 -vt 0.500243246555 0.364317297935 0.000000000000 -vt 0.494832962751 0.368273258209 0.000000000000 -vt 0.503132641315 0.370268374681 0.000000000000 -vt 0.497408539057 0.374473363161 0.000000000000 -vt 0.505711734295 0.374342322350 0.000000000000 -vt 0.501966536045 0.380494236946 0.000000000000 -vt 0.502037703991 0.387555330992 0.000000000000 -vt 0.500600278378 0.394303470850 0.000000000000 -vt 0.497024863958 0.400832056999 0.000000000000 -vt 0.490292042494 0.406675279140 0.000000000000 -vt 0.490373104811 0.412000209093 0.000000000000 -vt 0.478659600019 0.408653289080 0.000000000000 -vt 0.483080357313 0.413705527782 0.000000000000 -vt 0.483867734671 0.400707095861 0.000000000000 -vt 0.475096553564 0.403399050236 0.000000000000 -vt 0.490063995123 0.397259533405 0.000000000000 -vt 0.493380278349 0.393484354019 0.000000000000 -vt 0.495144337416 0.389038652182 0.000000000000 -vt 0.495407789946 0.384074211121 0.000000000000 -vt 0.493809431791 0.377649396658 0.000000000000 -vt 0.491057127714 0.371400237083 0.000000000000 -vt 0.488305300474 0.365160942078 0.000000000000 -vt 0.485417455435 0.358706206083 0.000000000000 -vt 0.499160021544 0.136612713337 0.000000000000 -vt 0.495681852102 0.138441428542 0.000000000000 -vt 0.495292752981 0.137186184525 0.000000000000 -vt 0.499904841185 0.142935067415 0.000000000000 -vt 0.512892186642 0.203441917896 0.000000000000 -vt 0.515536010265 0.210260972381 0.000000000000 -vt 0.519058048725 0.216575443745 0.000000000000 -vt 0.498339504004 0.139838293195 0.000000000000 -vt 0.500721871853 0.137117296457 0.000000000000 -vt 0.503684222698 0.138030976057 0.000000000000 -vt 0.499697417021 0.134602531791 0.000000000000 -vt 0.496406823397 0.134647563100 0.000000000000 -vt 0.494290322065 0.137108504772 0.000000000000 -vt 0.495159000158 0.139991164207 0.000000000000 -vt 0.493990033865 0.142434999347 0.000000000000 -vt 0.486728996038 0.090575456619 0.000000000000 -vt 0.478315383196 0.092991143465 0.000000000000 -vt 0.474077731371 0.098476827145 0.000000000000 -vt 0.498264402151 0.081063106656 0.000000000000 -vt 0.490895956755 0.083478346467 0.000000000000 -vt 0.501754701138 0.074368119240 0.000000000000 -vt 0.516297876835 0.064490333200 0.000000000000 -vt 0.489585071802 0.070763155818 0.000000000000 -vt 0.494673103094 0.066240236163 0.000000000000 -vt 0.470336109400 0.086715623736 0.000000000000 -vt 0.436086863279 0.092820927501 0.000000000000 -vt 0.438066899776 0.090013250709 0.000000000000 -vt 0.444520950317 0.092675030231 0.000000000000 -vt 0.441438585520 0.096161559224 0.000000000000 -vt 0.428543061018 0.092088505626 0.000000000000 -vt 0.430847972631 0.087048172951 0.000000000000 -vt 0.445708662271 0.087137565017 0.000000000000 -vt 0.440775513649 0.085114762187 0.000000000000 -vt 0.441083967686 0.081669896841 0.000000000000 -vt 0.445867836475 0.084105402231 0.000000000000 -vt 0.434993296862 0.082800179720 0.000000000000 -vt 0.435679793358 0.079566493630 0.000000000000 -vt 0.443775683641 0.089068949223 0.000000000000 -vt 0.439778298140 0.087716892362 0.000000000000 -vt 0.435482561588 0.085728764534 0.000000000000 -vt 0.449968576431 0.082234129310 0.000000000000 -vt 0.441662847996 0.076967298985 0.000000000000 -vt 0.431835711002 0.073218241334 0.000000000000 -vt 0.428974449635 0.081223636866 0.000000000000 -vt 0.450840383768 0.089633405209 0.000000000000 -vt 0.429250478745 0.110776379704 0.000000000000 -vt 0.428867727518 0.107335552573 0.000000000000 -vt 0.431848555803 0.108271300793 0.000000000000 -vt 0.431623846292 0.110644668341 0.000000000000 -vt 0.427443832159 0.110487952828 0.000000000000 -vt 0.426816552877 0.108107388020 0.000000000000 -vt 0.437157928944 0.099945515394 0.000000000000 -vt 0.433482289314 0.098722696304 0.000000000000 -vt 0.434810459614 0.095693901181 0.000000000000 -vt 0.437838792801 0.097269997001 0.000000000000 -vt 0.429327040911 0.097964599729 0.000000000000 -vt 0.431027412415 0.095057398081 0.000000000000 -vt 0.435632973909 0.102705463767 0.000000000000 -vt 0.431967437267 0.102064222097 0.000000000000 -vt 0.428185939789 0.101327285171 0.000000000000 -vt 0.424739956856 0.097438409925 0.000000000000 -vt 0.424326807261 0.104374542832 0.000000000000 -vt 0.430121839046 0.103951931000 0.000000000000 -vt 0.436985909939 0.106490775943 0.000000000000 -vt 0.440761536360 0.101641386747 0.000000000000 -vt 0.429635047913 0.115833595395 0.000000000000 -vt 0.429685264826 0.112943276763 0.000000000000 -vt 0.432830691338 0.111719325185 0.000000000000 -vt 0.435101598501 0.113605901599 0.000000000000 -vt 0.434298694134 0.107984006405 0.000000000000 -vt 0.429523140192 0.105171591043 0.000000000000 -vt 0.425729721785 0.106971934438 0.000000000000 -vt 0.426668196917 0.111298739910 0.000000000000 -vt 0.424650788307 0.112406730652 0.000000000000 -vt 0.509388387203 0.055841218680 0.000000000000 -vt 0.498403996229 0.043372806162 0.000000000000 -vt 0.502433478832 0.048159595579 0.000000000000 -vt 0.497449725866 0.051044743508 0.000000000000 -vt 0.492421835661 0.043788667768 0.000000000000 -vt 0.463615030050 0.077348947525 0.000000000000 -vt 0.455456525087 0.070783421397 0.000000000000 -vt 0.464122295380 0.066180795431 0.000000000000 -vt 0.462868630886 0.093436956406 0.000000000000 -vt 0.458721280098 0.092571005225 0.000000000000 -vt 0.459522604942 0.087591469288 0.000000000000 -vt 0.462670952082 0.086979731917 0.000000000000 -vt 0.471514105797 0.060662243515 0.000000000000 -vt 0.482812136412 0.062291014940 0.000000000000 -vt 0.467946112156 0.095136195421 0.000000000000 -vt 0.458524495363 0.080985873938 0.000000000000 -vt 0.452050387859 0.076159223914 0.000000000000 -vt 0.443986207247 0.071658372879 0.000000000000 -vt 0.445354491472 0.066013723612 0.000000000000 -vt 0.436717092991 0.065082713962 0.000000000000 -vt 0.437832713127 0.058958042413 0.000000000000 -vt 0.456312119961 0.084696203470 0.000000000000 -vt 0.455533295870 0.088533744216 0.000000000000 -vt 0.442759126425 0.026406910270 0.000000000000 -vt 0.439107567072 0.033566392958 0.000000000000 -vt 0.433614879847 0.033746067435 0.000000000000 -vt 0.436550229788 0.040571421385 0.000000000000 -vt 0.431009620428 0.041979093105 0.000000000000 -vt 0.436738461256 0.048520524055 0.000000000000 -vt 0.433239340782 0.050523724407 0.000000000000 -vt 0.439432889223 0.056393977255 0.000000000000 -vt 0.444673389196 0.062197577208 0.000000000000 -vt 0.452080547810 0.064230725169 0.000000000000 -vt 0.459633141756 0.061068650335 0.000000000000 -vt 0.466834276915 0.054884534329 0.000000000000 -vt 0.476173490286 0.048398043960 0.000000000000 -vt 0.478311985731 0.055618535727 0.000000000000 -vt 0.487611383200 0.048637155443 0.000000000000 -vt 0.492559403181 0.054551754147 0.000000000000 -vt 0.450314640999 0.028678275645 0.000000000000 -vt 0.445344805717 0.034261446446 0.000000000000 -vt 0.441385686398 0.039831560105 0.000000000000 -vt 0.440092831850 0.046508762985 0.000000000000 -vt 0.441298097372 0.053300123662 0.000000000000 -vt 0.444251447916 0.058152657002 0.000000000000 -vt 0.449525713921 0.059440102428 0.000000000000 -vt 0.455304324627 0.055676858872 0.000000000000 -vt 0.461506903172 0.049404706806 0.000000000000 -vt 0.469306051731 0.042024347931 0.000000000000 -vt 0.487811952829 0.058225836605 0.000000000000 -vt 0.483524292707 0.052073474973 0.000000000000 -vt 0.484311491251 0.046199399978 0.000000000000 -vt 0.481747001410 0.048475492746 0.000000000000 -vt 0.380680233240 0.065514564514 0.000000000000 -vt 0.376588284969 0.059708710760 0.000000000000 -vt 0.380253583193 0.059918548912 0.000000000000 -vt 0.384085476398 0.069081693888 0.000000000000 -vt 0.495234221220 0.099533021450 0.000000000000 -vt 0.383714437485 0.065352901816 0.000000000000 -vt 0.383114397526 0.061096791178 0.000000000000 -vt 0.374451309443 0.073164209723 0.000000000000 -vt 0.372015357018 0.063677519560 0.000000000000 -vt 0.374059766531 0.053939338773 0.000000000000 -vt 0.381692320108 0.054332684726 0.000000000000 -vt 0.383103370667 0.075196906924 0.000000000000 -vt 0.405146718025 0.062567278743 0.000000000000 -vt 0.405029207468 0.064906865358 0.000000000000 -vt 0.403085887432 0.065327689052 0.000000000000 -vt 0.402291089296 0.062788158655 0.000000000000 -vt 0.404567837715 0.060321133584 0.000000000000 -vt 0.402513980865 0.060236703604 0.000000000000 -vt 0.396065324545 0.068468824029 0.000000000000 -vt 0.393785178661 0.067805290222 0.000000000000 -vt 0.392409473658 0.063877239823 0.000000000000 -vt 0.394892245531 0.063695982099 0.000000000000 -vt 0.392374575138 0.059808004647 0.000000000000 -vt 0.394494861364 0.058848392218 0.000000000000 -vt 0.398127049208 0.067958623171 0.000000000000 -vt 0.397333174944 0.063290476799 0.000000000000 -vt 0.396797299385 0.058876764029 0.000000000000 -vt 0.394452542067 0.054397072643 0.000000000000 -vt 0.399751543999 0.055975642055 0.000000000000 -vt 0.399062365294 0.062898263335 0.000000000000 -vt 0.401548743248 0.070496574044 0.000000000000 -vt 0.397002875805 0.072747439146 0.000000000000 -vt 0.410708278418 0.061957109720 0.000000000000 -vt 0.408443450928 0.068036526442 0.000000000000 -vt 0.406104087830 0.065834060311 0.000000000000 -vt 0.407416969538 0.062223013490 0.000000000000 -vt 0.402603596449 0.067001029849 0.000000000000 -vt 0.400384694338 0.062776446342 0.000000000000 -vt 0.401618093252 0.058767784387 0.000000000000 -vt 0.407653838396 0.056897196919 0.000000000000 -vt 0.405660539865 0.059153925627 0.000000000000 -vt 0.342144489288 0.129252389073 0.000000000000 -vt 0.330034285784 0.118232384324 0.000000000000 -vt 0.331073820591 0.111910715699 0.000000000000 -vt 0.337948709726 0.117126211524 0.000000000000 -vt 0.334675848484 0.122342392802 0.000000000000 -vt 0.364498108625 0.084034025669 0.000000000000 -vt 0.353841513395 0.081475362182 0.000000000000 -vt 0.359023243189 0.072227567434 0.000000000000 -vt 0.383939355612 0.087411120534 0.000000000000 -vt 0.376194030046 0.086917132139 0.000000000000 -vt 0.378380954266 0.083674445748 0.000000000000 -vt 0.385140568018 0.082588523626 0.000000000000 -vt 0.348989427090 0.090118840337 0.000000000000 -vt 0.349848628044 0.102441802621 0.000000000000 -vt 0.384516656399 0.092244535685 0.000000000000 -vt 0.368901699781 0.080153703690 0.000000000000 -vt 0.366300255060 0.072573855519 0.000000000000 -vt 0.362025469542 0.061230536550 0.000000000000 -vt 0.366504251957 0.062840163708 0.000000000000 -vt 0.364860385656 0.049893748015 0.000000000000 -vt 0.368391275406 0.052941676229 0.000000000000 -vt 0.375058352947 0.079524159431 0.000000000000 -vt 0.381066381931 0.079621434212 0.000000000000 -vt 0.369406282902 0.023787003011 0.000000000000 -vt 0.363827377558 0.021882418543 0.000000000000 -vt 0.362167745829 0.013727746904 0.000000000000 -vt 0.369875043631 0.032330740243 0.000000000000 -vt 0.363867014647 0.030249182135 0.000000000000 -vt 0.367265045643 0.040660582483 0.000000000000 -vt 0.362684249878 0.039418853819 0.000000000000 -vt 0.360803991556 0.049217607826 0.000000000000 -vt 0.358212471008 0.058879461139 0.000000000000 -vt 0.354023665190 0.067041784525 0.000000000000 -vt 0.349367916584 0.074845895171 0.000000000000 -vt 0.344372838736 0.084569439292 0.000000000000 -vt 0.343579858541 0.097275629640 0.000000000000 -vt 0.337548166513 0.094781354070 0.000000000000 -vt 0.336168199778 0.107096001506 0.000000000000 -vt 0.341732889414 0.112160399556 0.000000000000 -vt 0.358703076839 0.019574124366 0.000000000000 -vt 0.356585264206 0.011583819985 0.000000000000 -vt 0.359179943800 0.028422724456 0.000000000000 -vt 0.358128011227 0.037861227989 0.000000000000 -vt 0.355775833130 0.047059264034 0.000000000000 -vt 0.352667778730 0.055755432695 0.000000000000 -vt 0.348802536726 0.062798514962 0.000000000000 -vt 0.344516932964 0.069515347481 0.000000000000 -vt 0.339693903923 0.078744009137 0.000000000000 -vt 0.334405004978 0.088547706604 0.000000000000 -vt 0.351488649845 0.008813511580 0.000000000000 -vt 0.353146910667 0.017157759517 0.000000000000 -vt 0.344804912806 0.016256015748 0.000000000000 -vt 0.343273401260 0.007860429585 0.000000000000 -vt 0.353605329990 0.026377867907 0.000000000000 -vt 0.345076918602 0.024861443788 0.000000000000 -vt 0.351858347654 0.035421445966 0.000000000000 -vt 0.343469291925 0.032606557012 0.000000000000 -vt 0.329398661852 0.083495229483 0.000000000000 -vt 0.321584880352 0.080222144723 0.000000000000 -vt 0.345637321472 0.107405588031 0.000000000000 -vt 0.339709669352 0.102807238698 0.000000000000 -vt 0.334294229746 0.103572994471 0.000000000000 -vt 0.336519658566 0.100833073258 0.000000000000 -vt 0.331020236015 0.072261109948 0.000000000000 -vt 0.336660385132 0.064951002598 0.000000000000 -vt 0.434932053089 0.026294331998 0.000000000000 -vt 0.340934514999 0.059087056667 0.000000000000 -vt 0.343839913607 0.051737319678 0.000000000000 -vt 0.346170932055 0.042951311916 0.000000000000 -vt 0.340638875961 0.037561997771 0.000000000000 -vt 0.323255330324 0.073237612844 0.000000000000 -vt 0.695959985256 0.741854548454 0.000000000000 -vt 0.714866340160 0.723106801510 0.000000000000 -vt 0.697431623936 0.719995796680 0.000000000000 -vt 0.483988851309 0.041881825775 0.000000000000 -vt 0.839606106281 0.716192245483 0.000000000000 -vt 0.824899375439 0.704895555973 0.000000000000 -vt 0.836511552334 0.689590156078 0.000000000000 -vt 0.848930418491 0.699052095413 0.000000000000 -vt 0.814055740833 0.694797575474 0.000000000000 -vt 0.477539271116 0.036895312369 0.000000000000 -vt 0.826638519764 0.681990265846 0.000000000000 -vt 0.829895794392 0.731659770012 0.000000000000 -vt 0.813143789768 0.716623902321 0.000000000000 -vt 0.801700055599 0.705101132393 0.000000000000 -vt 0.817305624485 0.743863582611 0.000000000000 -vt 0.801387965679 0.725039482117 0.000000000000 -vt 0.789851725101 0.712394773960 0.000000000000 -vt 0.788582026958 0.734670758247 0.000000000000 -vt 0.777517497540 0.721166849136 0.000000000000 -vt 0.803215801716 0.752814412117 0.000000000000 -vt 0.786242902279 0.759428799152 0.000000000000 -vt 0.773034870625 0.741466820240 0.000000000000 -vt 0.763387620449 0.729409098625 0.000000000000 -vt 0.819508969784 0.771108031273 0.000000000000 -vt 0.801594197750 0.778130888939 0.000000000000 -vt 0.780358016491 0.784393787384 0.000000000000 -vt 0.813161194324 0.798096477985 0.000000000000 -vt 0.791216671467 0.802965700626 0.000000000000 -vt 0.768060982227 0.806276857853 0.000000000000 -vt 0.758998692036 0.789613127708 0.000000000000 -vt 0.745742022991 0.808515787125 0.000000000000 -vt 0.739104449749 0.793780505657 0.000000000000 -vt 0.796912372112 0.821695029736 0.000000000000 -vt 0.772977530956 0.822699189186 0.000000000000 -vt 0.749330580235 0.823236882687 0.000000000000 -vt 0.818778097630 0.819741129875 0.000000000000 -vt 0.864375889301 0.710809707642 0.000000000000 -vt 0.880953133106 0.724374651909 0.000000000000 -vt 0.915635168552 0.748171925545 0.000000000000 -vt 0.908841907978 0.766230940819 0.000000000000 -vt 0.905186593533 0.787342846394 0.000000000000 -vt 0.887137472630 0.812209010124 0.000000000000 -vt 0.901950418949 0.812799155712 0.000000000000 -vt 0.716777384281 0.755539953709 0.000000000000 -vt 0.709918677807 0.762999296188 0.000000000000 -vt 0.751775801182 0.171791642904 0.000000000000 -vt 0.779532253742 0.179935947061 0.000000000000 -vt 0.757754266262 0.191265076399 0.000000000000 -vt 0.738353550434 0.202746644616 0.000000000000 -vt 0.733651459217 0.186159908772 0.000000000000 -vt 0.720768034458 0.212536171079 0.000000000000 -vt 0.718448698521 0.197526648641 0.000000000000 -vt 0.715862095356 0.185371875763 0.000000000000 -vt 0.749988734722 0.241413876414 0.000000000000 -vt 0.731017768383 0.248716101050 0.000000000000 -vt 0.725487768650 0.230310603976 0.000000000000 -vt 0.743789970875 0.221092060208 0.000000000000 -vt 0.774173557758 0.257214367390 0.000000000000 -vt 0.754297435284 0.261839717627 0.000000000000 -vt 0.769551694393 0.234550252557 0.000000000000 -vt 0.731539070606 0.269993722439 0.000000000000 -vt 0.763681709766 0.212278813124 0.000000000000 -vt 0.789024770260 0.228903159499 0.000000000000 -vt 0.784669578075 0.203588500619 0.000000000000 -vt 0.812417447567 0.255994260311 0.000000000000 -vt 0.793350636959 0.255872875452 0.000000000000 -vt 0.808808386326 0.224819734693 0.000000000000 -vt 0.805518686771 0.196942374110 0.000000000000 -vt 0.801068723202 0.171566486359 0.000000000000 -vt 0.816036999226 0.293190568686 0.000000000000 -vt 0.796044886112 0.283715814352 0.000000000000 -vt 0.777438461781 0.280535697937 0.000000000000 -vt 0.757886707783 0.282600164413 0.000000000000 -vt 0.739174664021 0.287719726563 0.000000000000 -vt 0.785341441631 0.033302962780 0.000000000000 -vt 0.582609474659 0.124908477068 0.000000000000 -vt 0.581306993961 0.142187565565 0.000000000000 -vt 0.545368969440 0.011624570936 0.000000000000 -vt 0.646641552448 0.018267553300 0.000000000000 -vt 0.606483757496 0.106701299548 0.000000000000 -vt 0.612616598606 0.108521446586 0.000000000000 -vt 0.618627488613 0.111129656434 0.000000000000 -vt 0.665071904659 0.014743648469 0.000000000000 -vt 0.370113700628 0.016160547733 0.000000000000 -vt 0.331191360950 0.103096559644 0.000000000000 -vt 0.330383718014 0.097089871764 0.000000000000 -vt 0.327046245337 0.092111021280 0.000000000000 -vt 0.319549947977 0.088000133634 0.000000000000 -vt 0.491939753294 0.100965470076 0.000000000000 -vt 0.696907937527 0.156802833080 0.000000000000 -vt 0.707364618778 0.164915174246 0.000000000000 -vt 0.711468279362 0.167301818728 0.000000000000 -vt 0.672648847103 0.136169388890 0.000000000000 -vt 0.654392778873 0.123681157827 0.000000000000 -vt 0.546281397343 0.277987629175 0.000000000000 -vt 0.555889427662 0.542913317680 0.000000000000 -vt 0.598048627377 0.315594613552 0.000000000000 -vt 0.474871605635 0.487518340349 0.000000000000 -vt 0.493717104197 0.499704867601 0.000000000000 -vt 0.510663211346 0.513657331467 0.000000000000 -vt 0.529695570469 0.328777670860 0.000000000000 -vt 0.478573888540 0.439885228872 0.000000000000 -vt 0.489638179541 0.458603054285 0.000000000000 -vt 0.472153753042 0.424974769354 0.000000000000 -vt 0.581608593464 0.316328614950 0.000000000000 -vt 0.469933092594 0.410422533751 0.000000000000 -vt 0.474573940039 0.415574103594 0.000000000000 -vt 0.496727436781 0.356613397598 0.000000000000 -vt 0.467020928860 0.405297100544 0.000000000000 -vt 0.680720627308 0.091846004128 0.000000000000 -vt 0.694580972195 0.090741172433 0.000000000000 -vt 0.547491371632 0.071579337120 0.000000000000 -vt 0.553497970104 0.078128427267 0.000000000000 -vt 0.645280063152 0.102942556143 0.000000000000 -vt 0.557917654514 0.084493562579 0.000000000000 -vt 0.562383949757 0.098196953535 0.000000000000 -vt 0.633653700352 0.118626862764 0.000000000000 -vt 0.562888324261 0.114720419049 0.000000000000 -vt 0.563672840595 0.128326103091 0.000000000000 -vt 0.567211091518 0.144699171185 0.000000000000 -vt 0.500136196613 0.268927842379 0.000000000000 -vt 0.502436935902 0.280043512583 0.000000000000 -vt 0.482790559530 0.140759631991 0.000000000000 -vt 0.485283464193 0.145932793617 0.000000000000 -vt 0.511669576168 0.244729980826 0.000000000000 -vt 0.489596575499 0.150636732578 0.000000000000 -vt 0.503686726093 0.155002936721 0.000000000000 -vt 0.528804123402 0.231279209256 0.000000000000 -vt 0.521844804287 0.155472621322 0.000000000000 -vt 0.536552846432 0.156950756907 0.000000000000 -vt 0.553597509861 0.159783437848 0.000000000000 -vt 0.307654768229 0.609554529190 0.000000000000 -vt 0.290467321873 0.613707244396 0.000000000000 -vt 0.204575508833 0.719810605049 0.000000000000 -vt 0.210707157850 0.703682720661 0.000000000000 -vt 0.284538298845 0.585472345352 0.000000000000 -vt 0.223060980439 0.709351420403 0.000000000000 -vt 0.213785484433 0.729282855988 0.000000000000 -vt 0.294191390276 0.583933651447 0.000000000000 -vt 0.193332836032 0.738901257515 0.000000000000 -vt 0.188829287887 0.728674709797 0.000000000000 -vt 0.197825804353 0.749223530293 0.000000000000 -vt 0.225497603416 0.740132212639 0.000000000000 -vt 0.172644689679 0.756999909878 0.000000000000 -vt 0.173354595900 0.748063921928 0.000000000000 -vt 0.153877779841 0.774228334427 0.000000000000 -vt 0.153797164559 0.760271430016 0.000000000000 -vt 0.173445329070 0.773155450821 0.000000000000 -vt 0.149432986975 0.820051431656 0.000000000000 -vt 0.173765048385 0.821435034275 0.000000000000 -vt 0.175114631653 0.829998791218 0.000000000000 -vt 0.154235765338 0.830059587955 0.000000000000 -vt 0.154094830155 0.792689681053 0.000000000000 -vt 0.177844420075 0.795601427555 0.000000000000 -vt 0.212241590023 0.836606919765 0.000000000000 -vt 0.307616710663 0.586260378361 0.000000000000 -vt 0.319666564465 0.604332268238 0.000000000000 -vt 0.206351310015 0.841337859631 0.000000000000 -vt 0.357945650816 0.653928995132 0.000000000000 -vt 0.205141782761 0.802912175655 0.000000000000 -vt 0.181257992983 0.838490307331 0.000000000000 -vt 0.150479733944 0.836383342743 0.000000000000 -vt 0.202541679144 0.774786055088 0.000000000000 -vt 0.230581372976 0.776787877083 0.000000000000 -vt 0.232835412025 0.808410942554 0.000000000000 -vt 0.153742238879 0.753254890442 0.000000000000 -vt 0.354879945517 0.670894861221 0.000000000000 -vt 0.156122118235 0.742229044437 0.000000000000 -vt 0.325383484364 0.664160490036 0.000000000000 -vt 0.172345682979 0.736270546913 0.000000000000 -vt 0.329998701811 0.649386703968 0.000000000000 -vt 0.344495564699 0.695504546165 0.000000000000 -vt 0.319999575615 0.685368955135 0.000000000000 -vt 0.340014070272 0.705360293388 0.000000000000 -vt 0.316662311554 0.697957396507 0.000000000000 -vt 0.335703253746 0.712217569351 0.000000000000 -vt 0.314472913742 0.703338801861 0.000000000000 -vt 0.298693358898 0.660711348057 0.000000000000 -vt 0.305291980505 0.643745899200 0.000000000000 -vt 0.335656195879 0.638233840466 0.000000000000 -vt 0.170275822282 0.731788814068 0.000000000000 -vt 0.154652982950 0.738835036755 0.000000000000 -vt 0.186667352915 0.724648237228 0.000000000000 -vt 0.232443422079 0.711409807205 0.000000000000 -vt 0.252836883068 0.745151817799 0.000000000000 -vt 0.251037418842 0.715631723404 0.000000000000 -vt 0.257062584162 0.778479039669 0.000000000000 -vt 0.286519646645 0.808762609959 0.000000000000 -vt 0.259915977716 0.810499906540 0.000000000000 -vt 0.282630771399 0.777449607849 0.000000000000 -vt 0.312265455723 0.804308831692 0.000000000000 -vt 0.315088212490 0.835467398167 0.000000000000 -vt 0.288638800383 0.843417167664 0.000000000000 -vt 0.337379038334 0.797992110252 0.000000000000 -vt 0.342023313046 0.826052308083 0.000000000000 -vt 0.314613372087 0.842931270599 0.000000000000 -vt 0.360430896282 0.641259968281 0.000000000000 -vt 0.314939886332 0.630025804043 0.000000000000 -vt 0.289557874203 0.850114881992 0.000000000000 -vt 0.294469684362 0.682716429234 0.000000000000 -vt 0.273877441883 0.659004628658 0.000000000000 -vt 0.280411213636 0.635718882084 0.000000000000 -vt 0.270008593798 0.684478938580 0.000000000000 -vt 0.359717398882 0.625162005424 0.000000000000 -vt 0.343318879604 0.624738991261 0.000000000000 -vt 0.344458639622 0.621523499489 0.000000000000 -vt 0.360369205475 0.621685206890 0.000000000000 -vt 0.360682636499 0.635098338127 0.000000000000 -vt 0.339501827955 0.634016931057 0.000000000000 -vt 0.340652346611 0.835465610027 0.000000000000 -vt 0.309305101633 0.776968240738 0.000000000000 -vt 0.334473401308 0.773887217045 0.000000000000 -vt 0.363107293844 0.791482627392 0.000000000000 -vt 0.368501096964 0.820234537125 0.000000000000 -vt 0.358934253454 0.769033312798 0.000000000000 -vt 0.275969982147 0.743224263191 0.000000000000 -vt 0.305437386036 0.756031274796 0.000000000000 -vt 0.260169744492 0.846379280090 0.000000000000 -vt 0.235436409712 0.844436645508 0.000000000000 -vt 0.262015789747 0.854236066341 0.000000000000 -vt 0.234238356352 0.851540505886 0.000000000000 -vt 0.263981163502 0.715166091919 0.000000000000 -vt 0.267965942621 0.713351130486 0.000000000000 -vt 0.281729459763 0.734891474247 0.000000000000 -vt 0.288172066212 0.722100436687 0.000000000000 -vt 0.277648299932 0.707795619965 0.000000000000 -vt 0.291222691536 0.716961920261 0.000000000000 -vt 0.308623343706 0.723172843456 0.000000000000 -vt 0.307381391525 0.728834807873 0.000000000000 -vt 0.281491696835 0.703531861305 0.000000000000 -vt 0.305040448904 0.743083953857 0.000000000000 -vt 0.201677769423 0.717027664185 0.000000000000 -vt 0.205799683928 0.700485944748 0.000000000000 -vt 0.367262303829 0.829703629017 0.000000000000 -vt 0.341758757830 0.839105904102 0.000000000000 -vt 0.368334710598 0.833229362965 0.000000000000 -vt 0.316586196423 0.847852051258 0.000000000000 -vt 0.290764272213 0.854788422585 0.000000000000 -vt 0.327047795057 0.738471865654 0.000000000000 -vt 0.326124876738 0.730000674725 0.000000000000 -vt 0.330911010504 0.754280507565 0.000000000000 -vt 0.355491876602 0.749867677689 0.000000000000 -vt 0.351486146450 0.739300012589 0.000000000000 -vt 0.326873511076 0.724973142147 0.000000000000 -vt 0.344539195299 0.722123146057 0.000000000000 -vt 0.344190418720 0.726383745670 0.000000000000 -vt 0.261989206076 0.857144653797 0.000000000000 -vt 0.233581811190 0.854094266891 0.000000000000 -vt 0.204417899251 0.849156141281 0.000000000000 -vt 0.326887309551 0.621081113815 0.000000000000 -vt 0.252677500248 0.583962917328 0.000000000000 -vt 0.265231251717 0.586087048054 0.000000000000 -vt 0.256276845932 0.613264143467 0.000000000000 -vt 0.236884176731 0.612185239792 0.000000000000 -vt 0.225397676229 0.592031359673 0.000000000000 -vt 0.240359246731 0.578182041645 0.000000000000 -vt 0.249482765794 0.581659138203 0.000000000000 -vt 0.230406701565 0.604802131653 0.000000000000 -vt 0.221547290683 0.586520910263 0.000000000000 -vt 0.237664133310 0.573132932186 0.000000000000 -vt 0.211196690798 0.601164758205 0.000000000000 -vt 0.209809958935 0.594907939434 0.000000000000 -vt 0.213919267058 0.613228797913 0.000000000000 -vt 0.215259835124 0.621791481972 0.000000000000 -vt 0.233155399561 0.635776519775 0.000000000000 -vt 0.212040349841 0.638687551022 0.000000000000 -vt 0.329966962337 0.616993844509 0.000000000000 -vt 0.252798855305 0.635614156723 0.000000000000 -vt 0.333201110363 0.612495720387 0.000000000000 -vt 0.324382007122 0.598686695099 0.000000000000 -vt 0.311093568802 0.581733644009 0.000000000000 -vt 0.250871539116 0.659518659115 0.000000000000 -vt 0.246007040143 0.695468783379 0.000000000000 -vt 0.267591327429 0.695985734463 0.000000000000 -vt 0.229620695114 0.658928096294 0.000000000000 -vt 0.224895358086 0.685685992241 0.000000000000 -vt 0.202963665128 0.683032333851 0.000000000000 -vt 0.206480368972 0.658463180065 0.000000000000 -vt 0.225187152624 0.694258570671 0.000000000000 -vt 0.267994135618 0.700619399548 0.000000000000 -vt 0.246059074998 0.698300302029 0.000000000000 -vt 0.202539697289 0.691807746887 0.000000000000 -vt 0.292167007923 0.695293128490 0.000000000000 -vt 0.291803628206 0.699824810028 0.000000000000 -vt 0.246173635125 0.686428308487 0.000000000000 -vt 0.225166440010 0.697112381458 0.000000000000 -vt 0.202534750104 0.694576680660 0.000000000000 -vt 0.179447337985 0.689694881439 0.000000000000 -vt 0.179994687438 0.681011319160 0.000000000000 -vt 0.156249374151 0.689290702343 0.000000000000 -vt 0.153237923980 0.680606484413 0.000000000000 -vt 0.181782424450 0.657110214233 0.000000000000 -vt 0.156527668238 0.653305292130 0.000000000000 -vt 0.186954230070 0.638771533966 0.000000000000 -vt 0.162625998259 0.633767902851 0.000000000000 -vt 0.191838979721 0.622671365738 0.000000000000 -vt 0.169981136918 0.618435740471 0.000000000000 -vt 0.179694786668 0.692102015018 0.000000000000 -vt 0.157019853592 0.692945420742 0.000000000000 -vt 0.174810484052 0.610164642334 0.000000000000 -vt 0.181283250451 0.599177777767 0.000000000000 -vt 0.196757718921 0.604870617390 0.000000000000 -vt 0.192525476217 0.616066217422 0.000000000000 -vt 0.183410972357 0.595816195011 0.000000000000 -vt 0.198278859258 0.601250529289 0.000000000000 -vt 0.244824290276 0.579442679882 0.000000000000 -vt 0.273151040077 0.710567533970 0.000000000000 -vt 0.285232663155 0.728684842587 0.000000000000 -vt 0.227200508118 0.598817527294 0.000000000000 -vt 0.212605252862 0.606770217419 0.000000000000 -vt 0.305614590645 0.736904382706 0.000000000000 -vt 0.328240215778 0.744696319103 0.000000000000 -vt 0.178053170443 0.604644119740 0.000000000000 -vt 0.348152697086 0.732621014118 0.000000000000 -vt 0.194131508470 0.610380828381 0.000000000000 -vt 0.313762992620 0.607308149338 0.000000000000 -vt 0.300771087408 0.584314823151 0.000000000000 -vt 0.216887891293 0.707050144672 0.000000000000 -vt 0.208923026919 0.724448800087 0.000000000000 -vt 0.190924808383 0.733412683010 0.000000000000 -vt 0.173134177923 0.741575896740 0.000000000000 -vt 0.154957845807 0.745678186417 0.000000000000 -vt 0.360251009464 0.628313779831 0.000000000000 -vt 0.342385172844 0.628576755524 0.000000000000 -vt 0.322390943766 0.625243067741 0.000000000000 -vt 0.255816608667 0.538961172104 0.000000000000 -vt 0.255609929562 0.531903445721 0.000000000000 -vt 0.276532471180 0.523902297020 0.000000000000 -vt 0.276766628027 0.530665338039 0.000000000000 -vt 0.258155763149 0.542869150639 0.000000000000 -vt 0.239253938198 0.549565970898 0.000000000000 -vt 0.237569808960 0.546314954758 0.000000000000 -vt 0.259632319212 0.557646989822 0.000000000000 -vt 0.278000265360 0.557606041431 0.000000000000 -vt 0.280406028032 0.561680853367 0.000000000000 -vt 0.259857028723 0.562739551067 0.000000000000 -vt 0.301217794418 0.558059513569 0.000000000000 -vt 0.301868736744 0.561496496201 0.000000000000 -vt 0.280528068542 0.552090644836 0.000000000000 -vt 0.277729153633 0.535347640514 0.000000000000 -vt 0.297178983688 0.528205513954 0.000000000000 -vt 0.301819860935 0.553178787231 0.000000000000 -vt 0.296229928732 0.518692255020 0.000000000000 -vt 0.297345817089 0.522403001785 0.000000000000 -vt 0.317796647549 0.513919591904 0.000000000000 -vt 0.319642692804 0.516018092632 0.000000000000 -vt 0.318866372108 0.522611498833 0.000000000000 -vt 0.323723644018 0.553826808929 0.000000000000 -vt 0.342375040054 0.518720626831 0.000000000000 -vt 0.345081865788 0.553842306137 0.000000000000 -vt 0.325454175472 0.558225631714 0.000000000000 -vt 0.324885904789 0.562544107437 0.000000000000 -vt 0.344201058149 0.558419764042 0.000000000000 -vt 0.346064895391 0.561874091625 0.000000000000 -vt 0.367183536291 0.508728206158 0.000000000000 -vt 0.365877866745 0.516082882881 0.000000000000 -vt 0.342823565006 0.511460900307 0.000000000000 -vt 0.365199923515 0.505763173103 0.000000000000 -vt 0.387129127979 0.502111792564 0.000000000000 -vt 0.389222174883 0.506725013256 0.000000000000 -vt 0.341677963734 0.508929491043 0.000000000000 -vt 0.382050991058 0.547588169575 0.000000000000 -vt 0.364945054054 0.550378084183 0.000000000000 -vt 0.388924062252 0.514224946499 0.000000000000 -vt 0.256348222494 0.552059113979 0.000000000000 -vt 0.239861428738 0.565382003784 0.000000000000 -vt 0.239956676960 0.562402725220 0.000000000000 -vt 0.220832422376 0.568670809269 0.000000000000 -vt 0.219239458442 0.567124247551 0.000000000000 -vt 0.203210204840 0.570883214474 0.000000000000 -vt 0.201898008585 0.568920969963 0.000000000000 -vt 0.182944670320 0.570823550224 0.000000000000 -vt 0.183698490262 0.567600429058 0.000000000000 -vt 0.203983396292 0.564405024052 0.000000000000 -vt 0.204041033983 0.557649910450 0.000000000000 -vt 0.220529600978 0.554902791977 0.000000000000 -vt 0.220537245274 0.562811851501 0.000000000000 -vt 0.183808818460 0.564445316792 0.000000000000 -vt 0.182822406292 0.557343244553 0.000000000000 -vt 0.156297102571 0.564277827740 0.000000000000 -vt 0.153392598033 0.552050530910 0.000000000000 -vt 0.137154191732 0.566353738308 0.000000000000 -vt 0.156789526343 0.566984176636 0.000000000000 -vt 0.156581923366 0.569497346878 0.000000000000 -vt 0.138306304812 0.569090723991 0.000000000000 -vt 0.154402419925 0.548665106297 0.000000000000 -vt 0.132301419973 0.547170519829 0.000000000000 -vt 0.131927892566 0.543763041496 0.000000000000 -vt 0.183378085494 0.554381549358 0.000000000000 -vt 0.155377343297 0.546469151974 0.000000000000 -vt 0.182058230042 0.549026727676 0.000000000000 -vt 0.203520476818 0.547020137310 0.000000000000 -vt 0.203194230795 0.553471744061 0.000000000000 -vt 0.219951391220 0.551127851009 0.000000000000 -vt 0.219577863812 0.544329047203 0.000000000000 -vt 0.236548244953 0.540101110935 0.000000000000 -vt 0.239640295506 0.557557404041 0.000000000000 -vt 0.364015817642 0.556429386139 0.000000000000 -vt 0.364667207003 0.559019565582 0.000000000000 -vt 0.385533690453 0.553289771080 0.000000000000 -vt 0.382902741432 0.557026267052 0.000000000000 -vt 0.154217123985 0.713813722134 0.000000000000 -vt 0.157158553600 0.710084676743 0.000000000000 -vt 0.139992043376 0.697338879108 0.000000000000 -vt 0.145032361150 0.694776415825 0.000000000000 -vt 0.129598200321 0.676885545254 0.000000000000 -vt 0.133522659540 0.676785171032 0.000000000000 -vt 0.121781267226 0.655710399151 0.000000000000 -vt 0.125936508179 0.658108294010 0.000000000000 -vt 0.117115393281 0.636653959751 0.000000000000 -vt 0.121172465384 0.637733101845 0.000000000000 -vt 0.116183921695 0.616349458694 0.000000000000 -vt 0.120485514402 0.618173420429 0.000000000000 -vt 0.084196135402 0.636717438698 0.000000000000 -vt 0.084505945444 0.617743194103 0.000000000000 -vt 0.089589498937 0.618903636932 0.000000000000 -vt 0.089312784374 0.636993050575 0.000000000000 -vt 0.080862037838 0.637916862965 0.000000000000 -vt 0.081022799015 0.618841469288 0.000000000000 -vt 0.085008040071 0.598570287228 0.000000000000 -vt 0.090116359293 0.599607348442 0.000000000000 -vt 0.081807009876 0.598996996880 0.000000000000 -vt 0.086025521159 0.666380286217 0.000000000000 -vt 0.083288080990 0.667724907398 0.000000000000 -vt 0.115721911192 0.657637059689 0.000000000000 -vt 0.091839924455 0.665398180485 0.000000000000 -vt 0.112071022391 0.636431932449 0.000000000000 -vt 0.116621181369 0.598775207996 0.000000000000 -vt 0.122074656188 0.598256886005 0.000000000000 -vt 0.117822155356 0.580991744995 0.000000000000 -vt 0.122807092965 0.579663336277 0.000000000000 -vt 0.118204921484 0.561226546764 0.000000000000 -vt 0.122930236161 0.561480045319 0.000000000000 -vt 0.086409181356 0.580696821213 0.000000000000 -vt 0.088303416967 0.563481450081 0.000000000000 -vt 0.092769816518 0.562017738819 0.000000000000 -vt 0.090972624719 0.580980956554 0.000000000000 -vt 0.112636163831 0.581119179726 0.000000000000 -vt 0.110782906413 0.597800493240 0.000000000000 -vt 0.092613331974 0.689584314823 0.000000000000 -vt 0.099071905017 0.688045859337 0.000000000000 -vt 0.108099728823 0.710213482380 0.000000000000 -vt 0.102641746402 0.710727512836 0.000000000000 -vt 0.099205419421 0.711480677128 0.000000000000 -vt 0.090210475028 0.691667914391 0.000000000000 -vt 0.112440273166 0.725039958954 0.000000000000 -vt 0.109685271978 0.733518600464 0.000000000000 -vt 0.120316430926 0.724148333073 0.000000000000 -vt 0.149469718337 0.716144502163 0.000000000000 -vt 0.083509407938 0.581079363823 0.000000000000 -vt 0.085539408028 0.563082933426 0.000000000000 -vt 0.091403126717 0.541651070118 0.000000000000 -vt 0.135661408305 0.562481999397 0.000000000000 -vt 0.112166255713 0.617554724216 0.000000000000 -vt 0.115233764052 0.561244547367 0.000000000000 -vt 0.124406136572 0.679192543030 0.000000000000 -vt 0.135345742106 0.699786543846 0.000000000000 -vt 0.124257989228 0.753876924515 0.000000000000 -vt 0.128552585840 0.751157760620 0.000000000000 -vt 0.165847733617 0.731854498386 0.000000000000 -vt 0.135802805424 0.748261570930 0.000000000000 -vt 0.166685536504 0.724866151810 0.000000000000 -vt 0.170482099056 0.722631275654 0.000000000000 -vt 0.118092343211 0.538387894630 0.000000000000 -vt 0.120958782732 0.537692189217 0.000000000000 -vt 0.098085269332 0.540873169899 0.000000000000 -vt 0.094365492463 0.541822671890 0.000000000000 -vt 0.132603570819 0.540962100029 0.000000000000 -vt 0.113834425807 0.538623392582 0.000000000000 -vt 0.319482028484 0.899047315121 0.000000000000 -vt 0.309817373753 0.903006970882 0.000000000000 -vt 0.303308844566 0.883904874325 0.000000000000 -vt 0.314649820328 0.880987823009 0.000000000000 -vt 0.328109025955 0.880558192730 0.000000000000 -vt 0.328658103943 0.897744834423 0.000000000000 -vt 0.341684728861 0.882348120213 0.000000000000 -vt 0.338721781969 0.899649322033 0.000000000000 -vt 0.355538994074 0.885123133659 0.000000000000 -vt 0.346919715405 0.902684092522 0.000000000000 -vt 0.264496624470 0.923883795738 0.000000000000 -vt 0.285223543644 0.930731534958 0.000000000000 -vt 0.267435461283 0.909074544907 0.000000000000 -vt 0.288075894117 0.921931266785 0.000000000000 -vt 0.274401426315 0.897557139397 0.000000000000 -vt 0.292297661304 0.914312303066 0.000000000000 -vt 0.287088751793 0.890229046345 0.000000000000 -vt 0.300147175789 0.908530831337 0.000000000000 -vt 0.310877472162 0.867308914661 0.000000000000 -vt 0.326778471470 0.865757822990 0.000000000000 -vt 0.343281567097 0.865718007088 0.000000000000 -vt 0.361255347729 0.866305887699 0.000000000000 -vt 0.245798677206 0.914549648762 0.000000000000 -vt 0.250797957182 0.897025287151 0.000000000000 -vt 0.263053983450 0.883340418339 0.000000000000 -vt 0.278658270836 0.875975549221 0.000000000000 -vt 0.297883272171 0.872081577778 0.000000000000 -vt 0.321375846863 0.908167660236 0.000000000000 -vt 0.313384771347 0.911024928093 0.000000000000 -vt 0.312286227942 0.907532513142 0.000000000000 -vt 0.320597171783 0.903883635998 0.000000000000 -vt 0.329484283924 0.906974732876 0.000000000000 -vt 0.329025387764 0.902560055256 0.000000000000 -vt 0.335602283478 0.907388985157 0.000000000000 -vt 0.336900919676 0.903732657433 0.000000000000 -vt 0.340975165367 0.909342050552 0.000000000000 -vt 0.344243913889 0.905984163284 0.000000000000 -vt 0.292275160551 0.931756854057 0.000000000000 -vt 0.288374781609 0.931339025497 0.000000000000 -vt 0.294533699751 0.926007986069 0.000000000000 -vt 0.291681826115 0.923927128315 0.000000000000 -vt 0.298611998558 0.919755756855 0.000000000000 -vt 0.295432448387 0.917401850224 0.000000000000 -vt 0.304809689522 0.915081322193 0.000000000000 -vt 0.302478045225 0.912388324738 0.000000000000 -vt 0.309649169445 0.859347939491 0.000000000000 -vt 0.325541138649 0.857225894928 0.000000000000 -vt 0.326330006123 0.861102938652 0.000000000000 -vt 0.309487581253 0.863262355328 0.000000000000 -vt 0.341508537531 0.857451260090 0.000000000000 -vt 0.343136012554 0.863369047642 0.000000000000 -vt 0.356366693974 0.855853736401 0.000000000000 -vt 0.360483229160 0.861095964909 0.000000000000 -vt 0.237906411290 0.910131931305 0.000000000000 -vt 0.242411300540 0.912403225899 0.000000000000 -vt 0.243345454335 0.892147541046 0.000000000000 -vt 0.247076600790 0.894490242004 0.000000000000 -vt 0.255101680756 0.878566741943 0.000000000000 -vt 0.258435934782 0.881105363369 0.000000000000 -vt 0.274271398783 0.868584036827 0.000000000000 -vt 0.276469051838 0.872065901756 0.000000000000 -vt 0.295189887285 0.862639725208 0.000000000000 -vt 0.297131747007 0.866627097130 0.000000000000 -vt 0.264509558678 0.939163446426 0.000000000000 -vt 0.284231007099 0.939391553402 0.000000000000 -vt 0.245086982846 0.933630704880 0.000000000000 -vt 0.292607039213 0.937922894955 0.000000000000 -vt 0.288247227669 0.939458549023 0.000000000000 -vt 0.234031543136 0.927958786488 0.000000000000 -vt 0.239948898554 0.931120336056 0.000000000000 -vt 0.303108215332 0.259901374578 0.000000000000 -vt 0.299691259861 0.272608458996 0.000000000000 -vt 0.227741092443 0.179622754455 0.000000000000 -vt 0.241408705711 0.177819043398 0.000000000000 -vt 0.288645803928 0.272444993258 0.000000000000 -vt 0.249047771096 0.186873659492 0.000000000000 -vt 0.294585645199 0.259171187878 0.000000000000 -vt 0.304501682520 0.254701167345 0.000000000000 -vt 0.313444852829 0.253634393215 0.000000000000 -vt 0.312482535839 0.259582310915 0.000000000000 -vt 0.296862632036 0.254683613777 0.000000000000 -vt 0.286406427622 0.256932258606 0.000000000000 -vt 0.289906680584 0.252584934235 0.000000000000 -vt 0.279214531183 0.252052009106 0.000000000000 -vt 0.283777058125 0.248220309615 0.000000000000 -vt 0.278458207846 0.270513832569 0.000000000000 -vt 0.212318181992 0.149050965905 0.000000000000 -vt 0.220562011003 0.146735697985 0.000000000000 -vt 0.222703933716 0.152291625738 0.000000000000 -vt 0.213263839483 0.154687494040 0.000000000000 -vt 0.203408792615 0.155836462975 0.000000000000 -vt 0.203189268708 0.150103569031 0.000000000000 -vt 0.193548575044 0.156050369143 0.000000000000 -vt 0.193696498871 0.150199025869 0.000000000000 -vt 0.183689251542 0.155369937420 0.000000000000 -vt 0.184210494161 0.149640426040 0.000000000000 -vt 0.193191483617 0.169719755650 0.000000000000 -vt 0.182228907943 0.169336318970 0.000000000000 -vt 0.268187999725 0.265260279179 0.000000000000 -vt 0.324253201485 0.252125859261 0.000000000000 -vt 0.231818437576 0.195312470198 0.000000000000 -vt 0.212309181690 0.181552782655 0.000000000000 -vt 0.213149681687 0.200687378645 0.000000000000 -vt 0.197734892368 0.182133242488 0.000000000000 -vt 0.196059510112 0.201420485973 0.000000000000 -vt 0.178108111024 0.197619631886 0.000000000000 -vt 0.184773385525 0.179257780313 0.000000000000 -vt 0.193671286106 0.220274075866 0.000000000000 -vt 0.204073458910 0.169701069593 0.000000000000 -vt 0.171984791756 0.217511638999 0.000000000000 -vt 0.196902945638 0.242536947131 0.000000000000 -vt 0.323984831572 0.258038192987 0.000000000000 -vt 0.310539454222 0.271224856377 0.000000000000 -vt 0.324096947908 0.268115252256 0.000000000000 -vt 0.339193135500 0.265587210655 0.000000000000 -vt 0.336792320013 0.254855424166 0.000000000000 -vt 0.340972989798 0.271843373775 0.000000000000 -vt 0.325516790152 0.274833887815 0.000000000000 -vt 0.313507229090 0.275261014700 0.000000000000 -vt 0.171768411994 0.240901872516 0.000000000000 -vt 0.215576186776 0.241010859609 0.000000000000 -vt 0.215113937855 0.219385609031 0.000000000000 -vt 0.179179176688 0.179597318172 0.000000000000 -vt 0.354237109423 0.261272788048 0.000000000000 -vt 0.356365293264 0.266201436520 0.000000000000 -vt 0.348684787750 0.251001656055 0.000000000000 -vt 0.335720360279 0.249260529876 0.000000000000 -vt 0.346057444811 0.245707139373 0.000000000000 -vt 0.367124110460 0.254228800535 0.000000000000 -vt 0.359250634909 0.246444091201 0.000000000000 -vt 0.355434030294 0.241601213813 0.000000000000 -vt 0.369936972857 0.258326172829 0.000000000000 -vt 0.169737070799 0.113030180335 0.000000000000 -vt 0.170575097203 0.120991900563 0.000000000000 -vt 0.297219276428 0.135332033038 0.000000000000 -vt 0.283211469650 0.234442397952 0.000000000000 -vt 0.292599529028 0.237945362926 0.000000000000 -vt 0.298478573561 0.140298739076 0.000000000000 -vt 0.290076673031 0.243708446622 0.000000000000 -vt 0.282434672117 0.239781066775 0.000000000000 -vt 0.305352568626 0.241858348250 0.000000000000 -vt 0.303028285503 0.248206838965 0.000000000000 -vt 0.324729174376 0.241821423173 0.000000000000 -vt 0.321562141180 0.249174103141 0.000000000000 -vt 0.347120851278 0.237402305007 0.000000000000 -vt 0.343635231256 0.232021078467 0.000000000000 -vt 0.357544183731 0.220489770174 0.000000000000 -vt 0.362244993448 0.226528212428 0.000000000000 -vt 0.363515973091 0.202669411898 0.000000000000 -vt 0.368934571743 0.200474381447 0.000000000000 -vt 0.344842731953 0.210690349340 0.000000000000 -vt 0.342417836189 0.185361966491 0.000000000000 -vt 0.364349514246 0.181216180325 0.000000000000 -vt 0.324543416500 0.218253985047 0.000000000000 -vt 0.321842014790 0.191119849682 0.000000000000 -vt 0.337232500315 0.165248394012 0.000000000000 -vt 0.356791496277 0.164284512401 0.000000000000 -vt 0.332506477833 0.147537469864 0.000000000000 -vt 0.347481101751 0.153085976839 0.000000000000 -vt 0.318637371063 0.169776722789 0.000000000000 -vt 0.312718063593 0.146633028984 0.000000000000 -vt 0.370308697224 0.181861028075 0.000000000000 -vt 0.360243141651 0.161985456944 0.000000000000 -vt 0.304652988911 0.221441268921 0.000000000000 -vt 0.303939700127 0.197721183300 0.000000000000 -vt 0.289470791817 0.148055776954 0.000000000000 -vt 0.285560518503 0.142270863056 0.000000000000 -vt 0.291176348925 0.221764370799 0.000000000000 -vt 0.288291871548 0.203909799457 0.000000000000 -vt 0.276085317135 0.156505629420 0.000000000000 -vt 0.272780030966 0.150750204921 0.000000000000 -vt 0.258125126362 0.158074513078 0.000000000000 -vt 0.260224252939 0.163233041763 0.000000000000 -vt 0.243465483189 0.162214890122 0.000000000000 -vt 0.243714034557 0.151190385222 0.000000000000 -vt 0.254636585712 0.146920993924 0.000000000000 -vt 0.229478836060 0.163604542613 0.000000000000 -vt 0.233701616526 0.153107583523 0.000000000000 -vt 0.167218700051 0.121271774173 0.000000000000 -vt 0.166369423270 0.112692907453 0.000000000000 -vt 0.243073940277 0.145069316030 0.000000000000 -vt 0.252761274576 0.141263067722 0.000000000000 -vt 0.263089358807 0.136896863580 0.000000000000 -vt 0.266313344240 0.141587063670 0.000000000000 -vt 0.277861565351 0.135119035840 0.000000000000 -vt 0.273413181305 0.131129965186 0.000000000000 -vt 0.282169669867 0.124930545688 0.000000000000 -vt 0.287077844143 0.128512978554 0.000000000000 -vt 0.289280533791 0.119594141841 0.000000000000 -vt 0.293950706720 0.122467115521 0.000000000000 -vt 0.168387711048 0.136361449957 0.000000000000 -vt 0.172123029828 0.133879333735 0.000000000000 -vt 0.159614548087 0.137594163418 0.000000000000 -vt 0.170139640570 0.142349898815 0.000000000000 -vt 0.159916698933 0.145990878344 0.000000000000 -vt 0.175263956189 0.137986391783 0.000000000000 -vt 0.158946737647 0.121140733361 0.000000000000 -vt 0.158538520336 0.111063912511 0.000000000000 -vt 0.150848120451 0.113286182284 0.000000000000 -vt 0.147537663579 0.113875642419 0.000000000000 -vt 0.150810301304 0.122010722756 0.000000000000 -vt 0.150818631053 0.137049511075 0.000000000000 -vt 0.146893724799 0.134909197688 0.000000000000 -vt 0.234794318676 0.147171825171 0.000000000000 -vt 0.280413031578 0.223018944263 0.000000000000 -vt 0.244322419167 0.167136326432 0.000000000000 -vt 0.215430051088 0.169227793813 0.000000000000 -vt 0.276956439018 0.210102006793 0.000000000000 -vt 0.230842590332 0.168110579252 0.000000000000 -vt 0.304748684168 0.128483712673 0.000000000000 -vt 0.319317579269 0.112706646323 0.000000000000 -vt 0.304126799107 0.108920201659 0.000000000000 -vt 0.306201845407 0.100410684943 0.000000000000 -vt 0.324304103851 0.102940306067 0.000000000000 -vt 0.298506706953 0.108017548919 0.000000000000 -vt 0.227834999561 0.168783783913 0.000000000000 -vt 0.173827692866 0.153802856803 0.000000000000 -vt 0.164431959391 0.150985270739 0.000000000000 -vt 0.166879624128 0.145447134972 0.000000000000 -vt 0.175091713667 0.148140892386 0.000000000000 -vt 0.170737877488 0.168616726995 0.000000000000 -vt 0.158358171582 0.168257147074 0.000000000000 -vt 0.171079888940 0.173917546868 0.000000000000 -vt 0.298551976681 0.176225617528 0.000000000000 -vt 0.284409761429 0.187349408865 0.000000000000 -vt 0.278388887644 0.172707334161 0.000000000000 -vt 0.265587240458 0.188653051853 0.000000000000 -vt 0.263487190008 0.183533251286 0.000000000000 -vt 0.172304287553 0.195576354861 0.000000000000 -vt 0.166341051459 0.215843468904 0.000000000000 -vt 0.246410295367 0.175310358405 0.000000000000 -vt 0.253420293331 0.181435257196 0.000000000000 -vt 0.258993119001 0.199986010790 0.000000000000 -vt 0.238587737083 0.209960162640 0.000000000000 -vt 0.263290882111 0.194039210677 0.000000000000 -vt 0.244794785976 0.230162426829 0.000000000000 -vt 0.267062664032 0.219509899616 0.000000000000 -vt 0.265724569559 0.241132006049 0.000000000000 -vt 0.247063919902 0.252580881119 0.000000000000 -vt 0.260249704123 0.258537381887 0.000000000000 -vt 0.247949019074 0.272692441940 0.000000000000 -vt 0.271840006113 0.241458699107 0.000000000000 -vt 0.267441391945 0.259758830070 0.000000000000 -vt 0.274886131287 0.221160054207 0.000000000000 -vt 0.248786136508 0.278353273869 0.000000000000 -vt 0.233543574810 0.288995474577 0.000000000000 -vt 0.228813290596 0.284420073032 0.000000000000 -vt 0.222581654787 0.263455659151 0.000000000000 -vt 0.201069429517 0.264848470688 0.000000000000 -vt 0.147332772613 0.121980324388 0.000000000000 -vt 0.149485930800 0.143096730113 0.000000000000 -vt 0.144085362554 0.139203354716 0.000000000000 -vt 0.274613022804 0.168164387345 0.000000000000 -vt 0.272586405277 0.198066562414 0.000000000000 -vt 0.292887955904 0.156603798270 0.000000000000 -vt 0.289811223745 0.151691362262 0.000000000000 -vt 0.308121502399 0.141383305192 0.000000000000 -vt 0.331666439772 0.141558468342 0.000000000000 -vt 0.346801817417 0.147019162774 0.000000000000 -vt 0.208444163203 0.284849673510 0.000000000000 -vt 0.207779288292 0.289209812880 0.000000000000 -vt 0.329524755478 0.248061582446 0.000000000000 -vt 0.180802538991 0.263033509254 0.000000000000 -vt 0.364997059107 0.218376457691 0.000000000000 -vt 0.185599476099 0.280001878738 0.000000000000 -vt 0.174449339509 0.263261795044 0.000000000000 -vt 0.192701548338 0.278811007738 0.000000000000 -vt 0.367429643869 0.175568386912 0.000000000000 -vt 0.166094049811 0.244550302625 0.000000000000 -vt 0.159377232194 0.173221364617 0.000000000000 -vt 0.182153701782 0.175170764327 0.000000000000 -vt 0.193075969815 0.175665423274 0.000000000000 -vt 0.313833713531 0.139958515763 0.000000000000 -vt 0.352484732866 0.149898454547 0.000000000000 -vt 0.203923046589 0.175497695804 0.000000000000 -vt 0.214893281460 0.174428433180 0.000000000000 -vt 0.226242244244 0.173432335258 0.000000000000 -vt 0.378087341785 0.245563969016 0.000000000000 -vt 0.380262136459 0.249743267894 0.000000000000 -vt 0.367841005325 0.240881398320 0.000000000000 -vt 0.362897038460 0.237351402640 0.000000000000 -vt 0.300132334232 0.100594177842 0.000000000000 -vt 0.299615830183 0.116130575538 0.000000000000 -vt 0.294845253229 0.114346668124 0.000000000000 -vt 0.312476694584 0.120818093419 0.000000000000 -vt 0.262099564075 0.265859633684 0.000000000000 -vt 0.271560132504 0.212059065700 0.000000000000 -vt 0.224148511887 0.289957106113 0.000000000000 -vt 0.191555723548 0.285657763481 0.000000000000 -vt 0.165448531508 0.236725702882 0.000000000000 -vt 0.048055123538 0.175203412771 0.000000000000 -vt 0.048704918474 0.175287619233 0.000000000000 -vt 0.049519758672 0.175945073366 0.000000000000 -vt 0.048962052912 0.176530927420 0.000000000000 -vt 0.048142258078 0.174550458789 0.000000000000 -vt 0.048840459436 0.174907326698 0.000000000000 -vt 0.048184361309 0.177168339491 0.000000000000 -vt 0.047785613686 0.175479233265 0.000000000000 -vt 0.050077687949 0.175508722663 0.000000000000 -vt 0.049611847848 0.173526674509 0.000000000000 -vt 0.050155591220 0.174321472645 0.000000000000 -vt 0.050484325737 0.174935474992 0.000000000000 -vt 0.049262631685 0.178634554148 0.000000000000 -vt 0.050630893558 0.177782341838 0.000000000000 -vt 0.053486991674 0.179326459765 0.000000000000 -vt 0.051250975579 0.172665014863 0.000000000000 -vt 0.052335549146 0.174432024360 0.000000000000 -vt 0.052290286869 0.172393932939 0.000000000000 -vt 0.060022119433 0.196368679404 0.000000000000 -vt 0.059825789183 0.195150136948 0.000000000000 -vt 0.062848724425 0.193425223231 0.000000000000 -vt 0.063640370965 0.194470614195 0.000000000000 -vt 0.057444769889 0.198157310486 0.000000000000 -vt 0.061123806983 0.204831123352 0.000000000000 -vt 0.054434444755 0.202152684331 0.000000000000 -vt 0.052125032991 0.196384206414 0.000000000000 -vt 0.065405808389 0.200892046094 0.000000000000 -vt 0.053650680929 0.194501906633 0.000000000000 -vt 0.071322210133 0.182865217328 0.000000000000 -vt 0.069051973522 0.180266022682 0.000000000000 -vt 0.072467572987 0.177512601018 0.000000000000 -vt 0.073771677911 0.182455211878 0.000000000000 -vt 0.046373885125 0.201640009880 0.000000000000 -vt 0.047620352358 0.205844104290 0.000000000000 -vt 0.044672172517 0.207344532013 0.000000000000 -vt 0.043322812766 0.201532378793 0.000000000000 -vt 0.048094075173 0.197172701359 0.000000000000 -vt 0.050799090415 0.203515991569 0.000000000000 -vt 0.043212261051 0.193465515971 0.000000000000 -vt 0.038478370756 0.209311038256 0.000000000000 -vt 0.037481162697 0.210909873247 0.000000000000 -vt 0.035782586783 0.208673626184 0.000000000000 -vt 0.036327917129 0.206941053271 0.000000000000 -vt 0.038885008544 0.211182534695 0.000000000000 -vt 0.037817772478 0.205236405134 0.000000000000 -vt 0.037915710360 0.216193586588 0.000000000000 -vt 0.036525826901 0.213128775358 0.000000000000 -vt 0.033292595297 0.211684182286 0.000000000000 -vt 0.032988864928 0.209396824241 0.000000000000 -vt 0.044357400388 0.213697507977 0.000000000000 -vt 0.040415156633 0.211841553450 0.000000000000 -vt 0.041487347335 0.208158016205 0.000000000000 -vt 0.042062167078 0.222331538796 0.000000000000 -vt 0.039700064808 0.219182297587 0.000000000000 -vt 0.046859998256 0.219299152493 0.000000000000 -vt 0.039277669042 0.216008275747 0.000000000000 -vt 0.090955741704 0.182833924890 0.000000000000 -vt 0.095942027867 0.185236781836 0.000000000000 -vt 0.091125510633 0.186936691403 0.000000000000 -vt 0.090062774718 0.185735270381 0.000000000000 -vt 0.091737933457 0.190855517983 0.000000000000 -vt 0.087909393013 0.188273668289 0.000000000000 -vt 0.096602633595 0.188918739557 0.000000000000 -vt 0.094589523971 0.190106213093 0.000000000000 -vt 0.088805288076 0.195824697614 0.000000000000 -vt 0.085034608841 0.192018002272 0.000000000000 -vt 0.037808310241 0.218160092831 0.000000000000 -vt 0.101674705744 0.180272325873 0.000000000000 -vt 0.108147457242 0.181930154562 0.000000000000 -vt 0.084888033569 0.212164208293 0.000000000000 -vt 0.086827971041 0.209401324391 0.000000000000 -vt 0.092867530882 0.213331192732 0.000000000000 -vt 0.090507008135 0.217772141099 0.000000000000 -vt 0.078402668238 0.211174651980 0.000000000000 -vt 0.081946156919 0.206284955144 0.000000000000 -vt 0.064126476645 0.226784884930 0.000000000000 -vt 0.059163603932 0.221614643931 0.000000000000 -vt 0.063531167805 0.218933045864 0.000000000000 -vt 0.066850177944 0.224536255002 0.000000000000 -vt 0.058718021959 0.224759161472 0.000000000000 -vt 0.052740599960 0.222449973226 0.000000000000 -vt 0.051313344389 0.218079030514 0.000000000000 -vt 0.056304361671 0.215266615152 0.000000000000 -vt 0.052650313824 0.225943475962 0.000000000000 -vt 0.101671561599 0.191067621112 0.000000000000 -vt 0.102857217193 0.187916800380 0.000000000000 -vt 0.090246729553 0.206087037921 0.000000000000 -vt 0.085568904877 0.202257156372 0.000000000000 -vt 0.091549478471 0.199667423964 0.000000000000 -vt 0.092842765152 0.201647892594 0.000000000000 -vt 0.092551417649 0.205803573132 0.000000000000 -vt 0.094774819911 0.209103897214 0.000000000000 -vt 0.094059728086 0.210680663586 0.000000000000 -vt 0.095144078135 0.195538073778 0.000000000000 -vt 0.099691078067 0.194344520569 0.000000000000 -vt 0.099405810237 0.196164458990 0.000000000000 -vt 0.099158152938 0.198102816939 0.000000000000 -vt 0.095910727978 0.198648139834 0.000000000000 -vt 0.040310692042 0.223760381341 0.000000000000 -vt 0.038051482290 0.225095763803 0.000000000000 -vt 0.039297934622 0.221828088164 0.000000000000 -vt 0.048715729266 0.226211413741 0.000000000000 -vt 0.048271726817 0.223471954465 0.000000000000 -vt 0.054012056440 0.227152556181 0.000000000000 -vt 0.051328878850 0.229439899325 0.000000000000 -vt 0.050317708403 0.229129895568 0.000000000000 -vt 0.048270147294 0.228640601039 0.000000000000 -vt 0.040398042649 0.225845307112 0.000000000000 -vt 0.043110940605 0.225429221988 0.000000000000 -vt 0.043746557087 0.226806730032 0.000000000000 -vt 0.041524719447 0.227182060480 0.000000000000 -vt 0.039583209902 0.227637097239 0.000000000000 -vt 0.037672769278 0.226903319359 0.000000000000 -vt 0.033523153514 0.225719004869 0.000000000000 -vt 0.036088127643 0.224684417248 0.000000000000 -vt 0.036136310548 0.226817533374 0.000000000000 -vt 0.034433234483 0.227448642254 0.000000000000 -vt 0.027782825753 0.229924663901 0.000000000000 -vt 0.030765233561 0.223758801818 0.000000000000 -vt 0.030333613977 0.231470361352 0.000000000000 -vt 0.110832214355 0.191612944007 0.000000000000 -vt 0.111078530550 0.184968620539 0.000000000000 -vt 0.106155976653 0.192477762699 0.000000000000 -vt 0.041945312172 0.228952214122 0.000000000000 -vt 0.038930263370 0.230628952384 0.000000000000 -vt 0.041834760457 0.232057794929 0.000000000000 -vt 0.044282648712 0.228836938739 0.000000000000 -vt 0.044818740338 0.232165411115 0.000000000000 -vt 0.039072107524 0.234580442309 0.000000000000 -vt 0.036424513906 0.232783898711 0.000000000000 -vt 0.106855750084 0.201680526137 0.000000000000 -vt 0.103606760502 0.198020190001 0.000000000000 -vt 0.104195758700 0.196577385068 0.000000000000 -vt 0.107200011611 0.198694974184 0.000000000000 -vt 0.109750792384 0.200388818979 0.000000000000 -vt 0.109513923526 0.203364923596 0.000000000000 -vt 0.105775907636 0.203093826771 0.000000000000 -vt 0.102690592408 0.199908792973 0.000000000000 -vt 0.050538811833 0.243682101369 0.000000000000 -vt 0.048396233469 0.240920796990 0.000000000000 -vt 0.048424374312 0.237581744790 0.000000000000 -vt 0.051719974726 0.241248175502 0.000000000000 -vt 0.046845819801 0.239993855357 0.000000000000 -vt 0.108550950885 0.195103302598 0.000000000000 -vt 0.107877954841 0.196638181806 0.000000000000 -vt 0.104663178325 0.194704324007 0.000000000000 -vt 0.111446216702 0.196098938584 0.000000000000 -vt 0.110371097922 0.198414430022 0.000000000000 -vt 0.033939246088 0.229781255126 0.000000000000 -vt 0.032943610102 0.235806867480 0.000000000000 -vt 0.036778222769 0.228347703815 0.000000000000 -vt 0.026748239994 0.237935468554 0.000000000000 -vt 0.029005868360 0.239583835006 0.000000000000 -vt 0.024600934237 0.235979780555 0.000000000000 -vt 0.036203410476 0.237542793155 0.000000000000 -vt 0.047933544964 0.242292001843 0.000000000000 -vt 0.048371467739 0.243713185191 0.000000000000 -vt 0.047026615590 0.242233023047 0.000000000000 -vt 0.047408472747 0.243272319436 0.000000000000 -vt 0.112042874098 0.199774816632 0.000000000000 -vt 0.112708196044 0.198945805430 0.000000000000 -vt 0.112421587110 0.201317355037 0.000000000000 -vt 0.115999296308 0.201012045145 0.000000000000 -vt 0.047676410526 0.245324388146 0.000000000000 -vt 0.046835009009 0.243697628379 0.000000000000 -vt 0.046366009861 0.242653593421 0.000000000000 -vt 0.116282775998 0.196683213115 0.000000000000 -vt 0.054629202932 0.245314940810 0.000000000000 -vt 0.055006336421 0.243421837687 0.000000000000 -vt 0.054401572794 0.246826633811 0.000000000000 -vt 0.049971643835 0.245547279716 0.000000000000 -vt 0.045614894480 0.244002953172 0.000000000000 -vt 0.046210203320 0.243990585208 0.000000000000 -vt 0.046083893627 0.245279118419 0.000000000000 -vt 0.044977705926 0.244760379195 0.000000000000 -vt 0.044843737036 0.243163123727 0.000000000000 -vt 0.045724090189 0.242940440774 0.000000000000 -vt 0.044279497117 0.243847146630 0.000000000000 -vt 0.042543780059 0.243463918567 0.000000000000 -vt 0.042998816818 0.241575345397 0.000000000000 -vt 0.043060954660 0.245589390397 0.000000000000 -vt 0.050320636481 0.250064343214 0.000000000000 -vt 0.046863149852 0.247579082847 0.000000000000 -vt 0.044486861676 0.247248783708 0.000000000000 -vt 0.115950897336 0.205869093537 0.000000000000 -vt 0.111902818084 0.203687563539 0.000000000000 -vt 0.067590266466 0.245651528239 0.000000000000 -vt 0.060156088322 0.247964099050 0.000000000000 -vt 0.059522051364 0.246006831527 0.000000000000 -vt 0.064255714417 0.241894826293 0.000000000000 -vt 0.075842648745 0.243643149734 0.000000000000 -vt 0.076406665146 0.251217573881 0.000000000000 -vt 0.068737201393 0.251990318298 0.000000000000 -vt 0.061447802931 0.252729058266 0.000000000000 -vt 0.101252302527 0.229214087129 0.000000000000 -vt 0.107055231929 0.225204750896 0.000000000000 -vt 0.110550090671 0.228503510356 0.000000000000 -vt 0.103125378489 0.234605416656 0.000000000000 -vt 0.093981824815 0.227124422789 0.000000000000 -vt 0.102826148272 0.221592798829 0.000000000000 -vt 0.093353867531 0.237001970410 0.000000000000 -vt 0.031605061144 0.248132273555 0.000000000000 -vt 0.033780287951 0.241846427321 0.000000000000 -vt 0.038934987038 0.242647275329 0.000000000000 -vt 0.038883429021 0.246692433953 0.000000000000 -vt 0.040764149278 0.250432223082 0.000000000000 -vt 0.034480068833 0.253740221262 0.000000000000 -vt 0.026098441333 0.256615221500 0.000000000000 -vt 0.024784889072 0.253078043461 0.000000000000 -vt 0.027103310451 0.246195510030 0.000000000000 -vt 0.022952351719 0.252045035362 0.000000000000 -vt 0.043932076544 0.254584789276 0.000000000000 -vt 0.049854788929 0.255521208048 0.000000000000 -vt 0.035871531814 0.256568402052 0.000000000000 -vt 0.127526775002 0.205384328961 0.000000000000 -vt 0.129298523068 0.208109617233 0.000000000000 -vt 0.124919943511 0.212541341782 0.000000000000 -vt 0.122282020748 0.208313822746 0.000000000000 -vt 0.130605995655 0.199026852846 0.000000000000 -vt 0.134021386504 0.202176094055 0.000000000000 -vt 0.123184211552 0.201524719596 0.000000000000 -vt 0.043590750545 0.262480288744 0.000000000000 -vt 0.045658569783 0.265317708254 0.000000000000 -vt 0.042624827474 0.268781721592 0.000000000000 -vt 0.040003802627 0.268262714148 0.000000000000 -vt 0.049783188850 0.260548025370 0.000000000000 -vt 0.050202202052 0.262952446938 0.000000000000 -vt 0.035101722926 0.267388671637 0.000000000000 -vt 0.036307651550 0.262090772390 0.000000000000 -vt 0.158384069800 0.177545472980 0.000000000000 -vt 0.163128763437 0.177713662386 0.000000000000 -vt 0.161081433296 0.184286177158 0.000000000000 -vt 0.155855119228 0.182891562581 0.000000000000 -vt 0.030163845047 0.266456753016 0.000000000000 -vt 0.028748972341 0.262917995453 0.000000000000 -vt 0.152635857463 0.180741325021 0.000000000000 -vt 0.156146481633 0.174547314644 0.000000000000 -vt 0.108293592930 0.175105020404 0.000000000000 -vt 0.103180319071 0.172587782145 0.000000000000 -vt 0.102925881743 0.166502520442 0.000000000000 -vt 0.107659325004 0.167699888349 0.000000000000 -vt 0.091472923756 0.255974650383 0.000000000000 -vt 0.083825305104 0.257546931505 0.000000000000 -vt 0.084012404084 0.249293193221 0.000000000000 -vt 0.091871894896 0.246349737048 0.000000000000 -vt 0.112725540996 0.167742446065 0.000000000000 -vt 0.113225832582 0.171109184623 0.000000000000 -vt 0.035772006959 0.183283552527 0.000000000000 -vt 0.035782817751 0.183923900127 0.000000000000 -vt 0.033255446702 0.184070467949 0.000000000000 -vt 0.033405173570 0.183254063129 0.000000000000 -vt 0.038481753320 0.182127386332 0.000000000000 -vt 0.038974162191 0.182417154312 0.000000000000 -vt 0.034431885928 0.181669190526 0.000000000000 -vt 0.036685016006 0.180374324322 0.000000000000 -vt 0.144137382507 0.199537962675 0.000000000000 -vt 0.139657467604 0.194585889578 0.000000000000 -vt 0.144188717008 0.186229258776 0.000000000000 -vt 0.148093581200 0.188943728805 0.000000000000 -vt 0.136400818825 0.206110462546 0.000000000000 -vt 0.153703317046 0.190900772810 0.000000000000 -vt 0.151239663363 0.198920801282 0.000000000000 -vt 0.150279834867 0.205067992210 0.000000000000 -vt 0.143856838346 0.206392586231 0.000000000000 -vt 0.163417190313 0.198642060161 0.000000000000 -vt 0.164253860712 0.202018722892 0.000000000000 -vt 0.160158962011 0.199008166790 0.000000000000 -vt 0.162906080484 0.192356184125 0.000000000000 -vt 0.165629789233 0.191846653819 0.000000000000 -vt 0.028680523857 0.176149964333 0.000000000000 -vt 0.028775541112 0.179067075253 0.000000000000 -vt 0.027133254334 0.179045230150 0.000000000000 -vt 0.026841904968 0.175766751170 0.000000000000 -vt 0.107328131795 0.163071155548 0.000000000000 -vt 0.102894365788 0.161774039268 0.000000000000 -vt 0.103162080050 0.158067077398 0.000000000000 -vt 0.107190564275 0.158765062690 0.000000000000 -vt 0.034622143954 0.168636307120 0.000000000000 -vt 0.034757684916 0.167032986879 0.000000000000 -vt 0.037417437881 0.167039290071 0.000000000000 -vt 0.036150719970 0.169255033135 0.000000000000 -vt 0.032856475562 0.170001432300 0.000000000000 -vt 0.031410526484 0.168317034841 0.000000000000 -vt 0.071371294558 0.162234246731 0.000000000000 -vt 0.072683498263 0.160097971559 0.000000000000 -vt 0.074752002954 0.160783797503 0.000000000000 -vt 0.072475455701 0.163342237473 0.000000000000 -vt 0.070219628513 0.164971008897 0.000000000000 -vt 0.067989014089 0.162172779441 0.000000000000 -vt 0.070951156318 0.158560618758 0.000000000000 -vt 0.071128129959 0.166468963027 0.000000000000 -vt 0.069623641670 0.166651114821 0.000000000000 -vt 0.052506666631 0.160904929042 0.000000000000 -vt 0.057779353112 0.165149331093 0.000000000000 -vt 0.056724499911 0.167911082506 0.000000000000 -vt 0.050493102521 0.165551453829 0.000000000000 -vt 0.060259658843 0.168007910252 0.000000000000 -vt 0.059231828898 0.159990578890 0.000000000000 -vt 0.061392862350 0.158380940557 0.000000000000 -vt 0.063771635294 0.161536499858 0.000000000000 -vt 0.063607268035 0.163274914026 0.000000000000 -vt 0.055211450905 0.155678853393 0.000000000000 -vt 0.057744000107 0.153191789985 0.000000000000 -vt 0.058993611485 0.163293376565 0.000000000000 -vt 0.053434979171 0.158556342125 0.000000000000 -vt 0.064857780933 0.162417531013 0.000000000000 -vt 0.064824908972 0.161404550076 0.000000000000 -vt 0.031159481034 0.208711221814 0.000000000000 -vt 0.030880516395 0.210443794727 0.000000000000 -vt 0.029724342749 0.204800054431 0.000000000000 -vt 0.031837198883 0.204756379128 0.000000000000 -vt 0.128212377429 0.176210075617 0.000000000000 -vt 0.128955841064 0.177864745259 0.000000000000 -vt 0.126242950559 0.177906855941 0.000000000000 -vt 0.125418648124 0.176409572363 0.000000000000 -vt 0.129953056574 0.174939975142 0.000000000000 -vt 0.130758658051 0.176998347044 0.000000000000 -vt 0.121036924422 0.175653725863 0.000000000000 -vt 0.121420361102 0.178308978677 0.000000000000 -vt 0.123617418110 0.183743998408 0.000000000000 -vt 0.117588669062 0.183899804950 0.000000000000 -vt 0.115403994918 0.191726654768 0.000000000000 -vt 0.122710488737 0.192234605551 0.000000000000 -vt 0.123056329787 0.196519747376 0.000000000000 -vt 0.128924548626 0.189431414008 0.000000000000 -vt 0.129672512412 0.193513929844 0.000000000000 -vt 0.133775278926 0.185372322798 0.000000000000 -vt 0.134995400906 0.187966778874 0.000000000000 -vt 0.136989831924 0.191276341677 0.000000000000 -vt 0.139916166663 0.181990936399 0.000000000000 -vt 0.141775041819 0.183941915631 0.000000000000 -vt 0.145468041301 0.175736352801 0.000000000000 -vt 0.147888004780 0.177232280374 0.000000000000 -vt 0.149156302214 0.178392961621 0.000000000000 -vt 0.151406511664 0.170416608453 0.000000000000 -vt 0.153140649199 0.171435669065 0.000000000000 -vt 0.026889864355 0.258701503277 0.000000000000 -vt 0.148213580251 0.169269666076 0.000000000000 -vt 0.138399973512 0.180339202285 0.000000000000 -vt 0.143568634987 0.174784168601 0.000000000000 -vt 0.146306514740 0.170045778155 0.000000000000 -vt 0.137052193284 0.178213953972 0.000000000000 -vt 0.141616314650 0.173843026161 0.000000000000 -vt 0.144707694650 0.169350728393 0.000000000000 -vt 0.021730657667 0.250446200371 0.000000000000 -vt 0.024742785841 0.244501665235 0.000000000000 -vt 0.018961701542 0.249092146754 0.000000000000 -vt 0.022073570639 0.243767663836 0.000000000000 -vt 0.023706618696 0.235825523734 0.000000000000 -vt 0.027095658705 0.229019328952 0.000000000000 -vt 0.029609059915 0.222379729152 0.000000000000 -vt 0.030542327091 0.216693878174 0.000000000000 -vt 0.033057313412 0.217472910881 0.000000000000 -vt 0.087314084172 0.175335809588 0.000000000000 -vt 0.094248183072 0.178092375398 0.000000000000 -vt 0.092181935906 0.179499372840 0.000000000000 -vt 0.085963152349 0.177274391055 0.000000000000 -vt 0.081338465214 0.174150139093 0.000000000000 -vt 0.082193829119 0.172002837062 0.000000000000 -vt 0.076521947980 0.167970299721 0.000000000000 -vt 0.077380686998 0.167476311326 0.000000000000 -vt 0.081656381488 0.178617432714 0.000000000000 -vt 0.077681265771 0.174922868609 0.000000000000 -vt 0.087579086423 0.180975034833 0.000000000000 -vt 0.074853092432 0.169260442257 0.000000000000 -vt 0.079015091062 0.179725423455 0.000000000000 -vt 0.076188489795 0.181088745594 0.000000000000 -vt 0.074826754630 0.175708204508 0.000000000000 -vt 0.082938641310 0.183109730482 0.000000000000 -vt 0.078197099268 0.184789612889 0.000000000000 -vt 0.070867173374 0.171145886183 0.000000000000 -vt 0.073829539120 0.169667065144 0.000000000000 -vt 0.031271602958 0.196384206414 0.000000000000 -vt 0.033982921392 0.194425582886 0.000000000000 -vt 0.037058766931 0.199865102768 0.000000000000 -vt 0.034688781947 0.202102705836 0.000000000000 -vt 0.033738177270 0.202948838472 0.000000000000 -vt 0.030448889360 0.197130590677 0.000000000000 -vt 0.028569748625 0.198085710406 0.000000000000 -vt 0.036571081728 0.216693878174 0.000000000000 -vt 0.033219423145 0.214136794209 0.000000000000 -vt 0.035667311400 0.220581635833 0.000000000000 -vt 0.030702864751 0.212936937809 0.000000000000 -vt 0.037512231618 0.221022486687 0.000000000000 -vt 0.039851140231 0.198102816939 0.000000000000 -vt 0.041124176234 0.203433588147 0.000000000000 -vt 0.037788044661 0.191379234195 0.000000000000 -vt 0.041217606515 0.195904180408 0.000000000000 -vt 0.067828707397 0.174960240722 0.000000000000 -vt 0.038927104324 0.189132183790 0.000000000000 -vt 0.041049417108 0.184728831053 0.000000000000 -vt 0.043036188930 0.186458468437 0.000000000000 -vt 0.065335564315 0.175491616130 0.000000000000 -vt 0.064928933978 0.179175376892 0.000000000000 -vt 0.059944216162 0.177007809281 0.000000000000 -vt 0.060216885060 0.175005495548 0.000000000000 -vt 0.055878814310 0.175014957786 0.000000000000 -vt 0.064486503601 0.180831611156 0.000000000000 -vt 0.059665244073 0.178134486079 0.000000000000 -vt 0.055603001267 0.176066651940 0.000000000000 -vt 0.059327062219 0.179134845734 0.000000000000 -vt 0.054891061038 0.176806747913 0.000000000000 -vt 0.052252914757 0.175443425775 0.000000000000 -vt 0.054579224437 0.177642062306 0.000000000000 -vt 0.051933418959 0.176275372505 0.000000000000 -vt 0.054217841476 0.178369775414 0.000000000000 -vt 0.051375713199 0.176691457629 0.000000000000 -vt 0.058970417827 0.180060461164 0.000000000000 -vt 0.058582257479 0.180961072445 0.000000000000 -vt 0.057680051774 0.181828826666 0.000000000000 -vt 0.062502883375 0.183891922235 0.000000000000 -vt 0.061697278172 0.184658572078 0.000000000000 -vt 0.050166402012 0.187552273273 0.000000000000 -vt 0.051037531346 0.187452524900 0.000000000000 -vt 0.054431293160 0.193168088794 0.000000000000 -vt 0.049586858600 0.182190433145 0.000000000000 -vt 0.049161311239 0.182690724730 0.000000000000 -vt 0.048391725868 0.182542562485 0.000000000000 -vt 0.049334455281 0.187815472484 0.000000000000 -vt 0.048377547413 0.188716322184 0.000000000000 -vt 0.047788541764 0.182509928942 0.000000000000 -vt 0.046637099236 0.188832953572 0.000000000000 -vt 0.046065207571 0.182266756892 0.000000000000 -vt 0.047180842608 0.178921401501 0.000000000000 -vt 0.047978799790 0.180811345577 0.000000000000 -vt 0.042535897344 0.180803701282 0.000000000000 -vt 0.063310064375 0.188303396106 0.000000000000 -vt 0.064299397171 0.188258126378 0.000000000000 -vt 0.065667442977 0.187005370855 0.000000000000 -vt 0.067313097417 0.191977471113 0.000000000000 -vt 0.069538079202 0.197437480092 0.000000000000 -vt 0.067683927715 0.207009509206 0.000000000000 -vt 0.063888035715 0.210395619273 0.000000000000 -vt 0.073146872222 0.203862056136 0.000000000000 -vt 0.071523271501 0.214295744896 0.000000000000 -vt 0.073026858270 0.194442689419 0.000000000000 -vt 0.077325977385 0.201174154878 0.000000000000 -vt 0.081237144768 0.196533709764 0.000000000000 -vt 0.076219789684 0.190154388547 0.000000000000 -vt 0.081086061895 0.187698617578 0.000000000000 -vt 0.069806240499 0.189532741904 0.000000000000 -vt 0.071710377932 0.187683090568 0.000000000000 -vt 0.067168101668 0.185359716415 0.000000000000 -vt 0.069611258805 0.183986946940 0.000000000000 -vt 0.063944101334 0.182054877281 0.000000000000 -vt 0.063255354762 0.183039709926 0.000000000000 -vt 0.074488565326 0.222574487329 0.000000000000 -vt 0.069771796465 0.223591953516 0.000000000000 -vt 0.067730538547 0.216421216726 0.000000000000 -vt 0.060474004596 0.213022723794 0.000000000000 -vt 0.053378012031 0.208070665598 0.000000000000 -vt 0.057214211673 0.207134246826 0.000000000000 -vt 0.049100745469 0.211366251111 0.000000000000 -vt 0.064397566020 0.232721552253 0.000000000000 -vt 0.067054398358 0.233078405261 0.000000000000 -vt 0.070033647120 0.233986899257 0.000000000000 -vt 0.075478121638 0.233488187194 0.000000000000 -vt 0.081782467663 0.220023691654 0.000000000000 -vt 0.083951614797 0.230261281133 0.000000000000 -vt 0.084691703320 0.240565523505 0.000000000000 -vt 0.062245752662 0.239568278193 0.000000000000 -vt 0.061321716756 0.238784536719 0.000000000000 -vt 0.063168220222 0.233371362090 0.000000000000 -vt 0.063390895724 0.227339446545 0.000000000000 -vt 0.058965694159 0.225806355476 0.000000000000 -vt 0.050889376551 0.232737079263 0.000000000000 -vt 0.051590736955 0.236221358180 0.000000000000 -vt 0.050666701049 0.236511155963 0.000000000000 -vt 0.049805026501 0.232663914561 0.000000000000 -vt 0.049557130784 0.236889854074 0.000000000000 -vt 0.048572305590 0.232626542449 0.000000000000 -vt 0.052862185985 0.239495113492 0.000000000000 -vt 0.052227925509 0.240581259131 0.000000000000 -vt 0.055151116103 0.242463573813 0.000000000000 -vt 0.058518532664 0.242689415812 0.000000000000 -vt 0.058837804943 0.243750557303 0.000000000000 -vt 0.027835739776 0.198754191399 0.000000000000 -vt 0.102103173733 0.178665846586 0.000000000000 -vt 0.020530804992 0.243255212903 0.000000000000 -vt 0.017403624952 0.246614530683 0.000000000000 -vt 0.142661705613 0.167488694191 0.000000000000 -vt 0.138711810112 0.171222224832 0.000000000000 -vt 0.136936917901 0.169240176678 0.000000000000 -vt 0.140343055129 0.166225120425 0.000000000000 -vt 0.133923217654 0.174637824297 0.000000000000 -vt 0.132665947080 0.181584313512 0.000000000000 -vt 0.128641068935 0.183620840311 0.000000000000 -vt 0.132804647088 0.173296123743 0.000000000000 -vt 0.065053895116 0.163422614336 0.000000000000 -vt 0.063069596887 0.163681775331 0.000000000000 -vt 0.064668200910 0.167430609465 0.000000000000 -vt 0.063209198415 0.168160781264 0.000000000000 -vt 0.063756324351 0.165098443627 0.000000000000 -vt 0.065168723464 0.164823085070 0.000000000000 -vt 0.065913312137 0.169554486871 0.000000000000 -vt 0.062940359116 0.170286476612 0.000000000000 -vt 0.061481129378 0.167505130172 0.000000000000 -vt 0.060151811689 0.170392528176 0.000000000000 -vt 0.060107905418 0.172657802701 0.000000000000 -vt 0.057210605592 0.172009363770 0.000000000000 -vt 0.057532805949 0.170253381133 0.000000000000 -vt 0.063048884273 0.172646328807 0.000000000000 -vt 0.048934575170 0.168896585703 0.000000000000 -vt 0.049731176347 0.167191714048 0.000000000000 -vt 0.042593311518 0.164057999849 0.000000000000 -vt 0.043497528881 0.162384659052 0.000000000000 -vt 0.044287156314 0.160732463002 0.000000000000 -vt 0.033884081990 0.156096965075 0.000000000000 -vt 0.034770067781 0.153932109475 0.000000000000 -vt 0.036515694112 0.150483399630 0.000000000000 -vt 0.046103026718 0.155740767717 0.000000000000 -vt 0.039584781975 0.147428721189 0.000000000000 -vt 0.047613140196 0.151688650250 0.000000000000 -vt 0.043061178178 0.143725812435 0.000000000000 -vt 0.050141181797 0.149046242237 0.000000000000 -vt 0.047894362360 0.140243798494 0.000000000000 -vt 0.053615551442 0.146738171577 0.000000000000 -vt 0.053296964616 0.138070821762 0.000000000000 -vt 0.056939747185 0.144772797823 0.000000000000 -vt 0.060318645090 0.151515960693 0.000000000000 -vt 0.060732934624 0.143554925919 0.000000000000 -vt 0.062500409782 0.150664418936 0.000000000000 -vt 0.064538739622 0.156376838684 0.000000000000 -vt 0.063412509859 0.157254040241 0.000000000000 -vt 0.065951131284 0.161686450243 0.000000000000 -vt 0.064260445535 0.149016290903 0.000000000000 -vt 0.065228387713 0.155802473426 0.000000000000 -vt 0.067762054503 0.156014785171 0.000000000000 -vt 0.067490294576 0.161968335509 0.000000000000 -vt 0.068041928113 0.150318130851 0.000000000000 -vt 0.072004206479 0.152485474944 0.000000000000 -vt 0.068994782865 0.144661113620 0.000000000000 -vt 0.072091117501 0.145224899054 0.000000000000 -vt 0.075190380216 0.145809859037 0.000000000000 -vt 0.074453443289 0.154495447874 0.000000000000 -vt 0.078592248261 0.146916940808 0.000000000000 -vt 0.077539868653 0.155462488532 0.000000000000 -vt 0.083513915539 0.149794429541 0.000000000000 -vt 0.080134786665 0.156474098563 0.000000000000 -vt 0.076403960586 0.162150710821 0.000000000000 -vt 0.082034416497 0.157592907548 0.000000000000 -vt 0.077113650739 0.164572715759 0.000000000000 -vt 0.075192175806 0.166414484382 0.000000000000 -vt 0.073551476002 0.164994657040 0.000000000000 -vt 0.072395749390 0.167818546295 0.000000000000 -vt 0.086013361812 0.151608720422 0.000000000000 -vt 0.082925580442 0.138807758689 0.000000000000 -vt 0.088270992041 0.142190933228 0.000000000000 -vt 0.092381425202 0.144706368446 0.000000000000 -vt 0.033781412989 0.159828022122 0.000000000000 -vt 0.032040510327 0.158961847425 0.000000000000 -vt 0.032221313566 0.155238896608 0.000000000000 -vt 0.033128913492 0.152995914221 0.000000000000 -vt 0.034247931093 0.149646267295 0.000000000000 -vt 0.036089029163 0.146674454212 0.000000000000 -vt 0.039337117225 0.142542183399 0.000000000000 -vt 0.044477183372 0.138003721833 0.000000000000 -vt 0.051182758063 0.134617850184 0.000000000000 -vt 0.057887878269 0.132730364799 0.000000000000 -vt 0.058954205364 0.136307403445 0.000000000000 -vt 0.065197318792 0.135614156723 0.000000000000 -vt 0.065236717463 0.143920347095 0.000000000000 -vt 0.070889234543 0.135065451264 0.000000000000 -vt 0.075503565371 0.136102512479 0.000000000000 -vt 0.079501420259 0.136758163571 0.000000000000 -vt 0.080287218094 0.135892897844 0.000000000000 -vt 0.083798281848 0.137524142861 0.000000000000 -vt 0.089716039598 0.140691623092 0.000000000000 -vt 0.143560752273 0.209685027599 0.000000000000 -vt 0.135448858142 0.212041050196 0.000000000000 -vt 0.136980593204 0.209762930870 0.000000000000 -vt 0.149614498019 0.207925885916 0.000000000000 -vt 0.093936122954 0.143564611673 0.000000000000 -vt 0.131235316396 0.212935358286 0.000000000000 -vt 0.130912885070 0.210914373398 0.000000000000 -vt 0.130802333355 0.214139938354 0.000000000000 -vt 0.126496925950 0.214841082692 0.000000000000 -vt 0.127033010125 0.216304361820 0.000000000000 -vt 0.123436622322 0.220508232713 0.000000000000 -vt 0.122662074864 0.219344407320 0.000000000000 -vt 0.127302527428 0.217270508409 0.000000000000 -vt 0.124103523791 0.221681743860 0.000000000000 -vt 0.121738053858 0.226466968656 0.000000000000 -vt 0.119399368763 0.224682837725 0.000000000000 -vt 0.071574836969 0.132907792926 0.000000000000 -vt 0.076760835946 0.134390205145 0.000000000000 -vt 0.065341189504 0.132802188396 0.000000000000 -vt 0.115896403790 0.229595944285 0.000000000000 -vt 0.113967284560 0.229628607631 0.000000000000 -vt 0.118455067277 0.224354103208 0.000000000000 -vt 0.118444040418 0.231105849147 0.000000000000 -vt 0.116246968508 0.222922116518 0.000000000000 -vt 0.121256656945 0.217508718371 0.000000000000 -vt 0.113348767161 0.220198199153 0.000000000000 -vt 0.118779063225 0.214370504022 0.000000000000 -vt 0.109506264329 0.216642320156 0.000000000000 -vt 0.113111913204 0.210065305233 0.000000000000 -vt 0.106790229678 0.213530674577 0.000000000000 -vt 0.110659286380 0.209100753069 0.000000000000 -vt 0.105615362525 0.211812064052 0.000000000000 -vt 0.108720943332 0.208151713014 0.000000000000 -vt 0.104931339622 0.210859879851 0.000000000000 -vt 0.107262387872 0.207199767232 0.000000000000 -vt 0.104268938303 0.209731861949 0.000000000000 -vt 0.106411516666 0.206867888570 0.000000000000 -vt 0.099854543805 0.210535883904 0.000000000000 -vt 0.101010948420 0.212820082903 0.000000000000 -vt 0.101252302527 0.214150756598 0.000000000000 -vt 0.100541725755 0.216653347015 0.000000000000 -vt 0.109188362956 0.234976246953 0.000000000000 -vt 0.112999781966 0.234926506877 0.000000000000 -vt 0.116525933146 0.235893979669 0.000000000000 -vt 0.113097950816 0.239953324199 0.000000000000 -vt 0.109616830945 0.240531280637 0.000000000000 -vt 0.105305328965 0.241614267230 0.000000000000 -vt 0.103323295712 0.248255476356 0.000000000000 -vt 0.107525810599 0.246296599507 0.000000000000 -vt 0.106832340360 0.251131802797 0.000000000000 -vt 0.103008523583 0.253494113684 0.000000000000 -vt 0.111104875803 0.245297834277 0.000000000000 -vt 0.110048457980 0.249654576182 0.000000000000 -vt 0.096914246678 0.264147579670 0.000000000000 -vt 0.095100626349 0.260864347219 0.000000000000 -vt 0.103348061442 0.257600039244 0.000000000000 -vt 0.106801033020 0.254496067762 0.000000000000 -vt 0.169106185436 0.192728593946 0.000000000000 -vt 0.170338675380 0.195399373770 0.000000000000 -vt 0.099874362350 0.170928612351 0.000000000000 -vt 0.097011074424 0.169942215085 0.000000000000 -vt 0.095663733780 0.165094852448 0.000000000000 -vt 0.099198222160 0.165355354548 0.000000000000 -vt 0.093683719635 0.168949723244 0.000000000000 -vt 0.092458203435 0.165013566613 0.000000000000 -vt 0.090356379747 0.159508973360 0.000000000000 -vt 0.094260796905 0.160128593445 0.000000000000 -vt 0.099197551608 0.159526988864 0.000000000000 -vt 0.033023308963 0.163863465190 0.000000000000 -vt 0.037694837898 0.165538623929 0.000000000000 -vt 0.027775174007 0.166775852442 0.000000000000 -vt 0.088919214904 0.165129065514 0.000000000000 -vt 0.087757416070 0.161358624697 0.000000000000 -vt 0.041305195540 0.168003618717 0.000000000000 -vt 0.039413448423 0.169479295611 0.000000000000 -vt 0.041364412755 0.172144010663 0.000000000000 -vt 0.039971377701 0.172480389476 0.000000000000 -vt 0.038754414767 0.172880932689 0.000000000000 -vt 0.037746172398 0.170685455203 0.000000000000 -vt 0.041679184884 0.177758023143 0.000000000000 -vt 0.040490355343 0.177621126175 0.000000000000 -vt 0.038885232061 0.177430868149 0.000000000000 -vt 0.031558681279 0.181349694729 0.000000000000 -vt 0.032375093549 0.182451382279 0.000000000000 -vt 0.031321812421 0.183208808303 0.000000000000 -vt 0.029306901619 0.181765779853 0.000000000000 -vt 0.030110931024 0.184735804796 0.000000000000 -vt 0.026748467237 0.183448821306 0.000000000000 -vt 0.025492548943 0.179579749703 0.000000000000 -vt 0.025225963444 0.184383660555 0.000000000000 -vt 0.023586835712 0.180322989821 0.000000000000 -vt 0.023586835712 0.175274342299 0.000000000000 -vt 0.025453597307 0.175285145640 0.000000000000 -vt 0.025660742074 0.170873910189 0.000000000000 -vt 0.026788990945 0.172416672111 0.000000000000 -vt 0.028133621439 0.171821355820 0.000000000000 -vt 0.117384001613 0.164725363255 0.000000000000 -vt 0.112397044897 0.164127796888 0.000000000000 -vt 0.111941114068 0.159629434347 0.000000000000 -vt 0.116640761495 0.160034939647 0.000000000000 -vt 0.117678731680 0.167584165931 0.000000000000 -vt 0.121842063963 0.165160596371 0.000000000000 -vt 0.122367806733 0.167285159230 0.000000000000 -vt 0.123244337738 0.169767260551 0.000000000000 -vt 0.118570342660 0.170628488064 0.000000000000 -vt 0.076927222311 0.256597876549 0.000000000000 -vt 0.069735996425 0.256459414959 0.000000000000 -vt 0.126834645867 0.166902616620 0.000000000000 -vt 0.127785488963 0.169480189681 0.000000000000 -vt 0.062401559204 0.256990790367 0.000000000000 -vt 0.061513323337 0.259970039129 0.000000000000 -vt 0.055246125907 0.260234832764 0.000000000000 -vt 0.055534552783 0.256361246109 0.000000000000 -vt 0.055091898888 0.251717656851 0.000000000000 -vt 0.055174525827 0.262654781342 0.000000000000 -vt 0.131237342954 0.166645258665 0.000000000000 -vt 0.126206025481 0.164752155542 0.000000000000 -vt 0.130478784442 0.164564833045 0.000000000000 -vt 0.128323823214 0.157905861735 0.000000000000 -vt 0.124372817576 0.158351898193 0.000000000000 -vt 0.120934464037 0.159285396338 0.000000000000 -vt 0.031951349229 0.187119752169 0.000000000000 -vt 0.032728809863 0.185262441635 0.000000000000 -vt 0.035856213421 0.185055300593 0.000000000000 -vt 0.035672266036 0.187161847949 0.000000000000 -vt 0.028532592580 0.186527818441 0.000000000000 -vt 0.128893464804 0.155811250210 0.000000000000 -vt 0.132322803140 0.155696868896 0.000000000000 -vt 0.132445976138 0.157863765955 0.000000000000 -vt 0.134399861097 0.164290815592 0.000000000000 -vt 0.137302115560 0.158585160971 0.000000000000 -vt 0.138255640864 0.163551405072 0.000000000000 -vt 0.141750499606 0.159247785807 0.000000000000 -vt 0.142176494002 0.162172332406 0.000000000000 -vt 0.167481020093 0.185227319598 0.000000000000 -vt 0.170263931155 0.178922742605 0.000000000000 -vt 0.172615230083 0.181126117706 0.000000000000 -vt 0.170385509729 0.185613691807 0.000000000000 -vt 0.137086644769 0.156343296170 0.000000000000 -vt 0.141829982400 0.156543448567 0.000000000000 -vt 0.084312535822 0.167729392648 0.000000000000 -vt 0.084777034819 0.164774447680 0.000000000000 -vt 0.089359387755 0.168153122067 0.000000000000 -vt 0.136736750603 0.154593154788 0.000000000000 -vt 0.141693994403 0.153399839997 0.000000000000 -vt 0.084533862770 0.161654248834 0.000000000000 -vt 0.132128268480 0.155035361648 0.000000000000 -vt 0.168764844537 0.189312979579 0.000000000000 -vt 0.165124982595 0.185052827001 0.000000000000 -vt 0.167759761214 0.178524002433 0.000000000000 -vt 0.158733054996 0.192014843225 0.000000000000 -vt 0.156409904361 0.199086070061 0.000000000000 -vt 0.155019804835 0.205063492060 0.000000000000 -vt 0.157773226500 0.205484077334 0.000000000000 -vt 0.157165527344 0.207992762327 0.000000000000 -vt 0.154318660498 0.207045525312 0.000000000000 -vt 0.039390247315 0.183007746935 0.000000000000 -vt 0.109839722514 0.252810090780 0.000000000000 -vt 0.161794945598 0.206194669008 0.000000000000 -vt 0.160380065441 0.209382638335 0.000000000000 -vt 0.030997594818 0.172260865569 0.000000000000 -vt 0.028872353956 0.171737149358 0.000000000000 -vt 0.040024068207 0.239364311099 0.000000000000 -vt 0.041931357235 0.237304374576 0.000000000000 -vt 0.044145528227 0.240434691310 0.000000000000 -vt 0.045424859971 0.239937767386 0.000000000000 -vt 0.044002104551 0.236135587096 0.000000000000 -vt 0.100529327989 0.192775428295 0.000000000000 -vt 0.086145527661 0.185369163752 0.000000000000 -vt 0.074024297297 0.186244800687 0.000000000000 -vt 0.062078233808 0.164369389415 0.000000000000 -vt 0.030012762174 0.176220208406 0.000000000000 -vt 0.112108394504 0.179039835930 0.000000000000 -vt 0.112108394504 0.176560640335 0.000000000000 -vt 0.069380022585 0.168249264359 0.000000000000 -vt 0.065014265478 0.171704053879 0.000000000000 -vt 0.048454102129 0.180325239897 0.000000000000 -vt 0.146105453372 0.080951645970 0.000000000000 -vt 0.144684508443 0.079957589507 0.000000000000 -vt 0.149933993816 0.076390907168 0.000000000000 -vt 0.151316225529 0.078695371747 0.000000000000 -vt 0.153613030910 0.080021530390 0.000000000000 -vt 0.145809382200 0.082432046533 0.000000000000 -vt 0.143933385611 0.080989018083 0.000000000000 -vt 0.154818966985 0.082354143262 0.000000000000 -vt 0.145563289523 0.085070192814 0.000000000000 -vt 0.143352255225 0.081543803215 0.000000000000 -vt 0.144436612725 0.082785755396 0.000000000000 -vt 0.143652841449 0.084858089685 0.000000000000 -vt 0.146591797471 0.088287875056 0.000000000000 -vt 0.154597863555 0.085654467344 0.000000000000 -vt 0.153173521161 0.089168235660 0.000000000000 -vt 0.152664005756 0.094450607896 0.000000000000 -vt 0.140441447496 0.090233892202 0.000000000000 -vt 0.138348862529 0.080004423857 0.000000000000 -vt 0.139517411590 0.078812226653 0.000000000000 -vt 0.140799894929 0.078904315829 0.000000000000 -vt 0.140338554978 0.079870223999 0.000000000000 -vt 0.139646649361 0.078048720956 0.000000000000 -vt 0.142411112785 0.080079168081 0.000000000000 -vt 0.142763257027 0.078845098615 0.000000000000 -vt 0.144676625729 0.071552544832 0.000000000000 -vt 0.147951960564 0.073969364166 0.000000000000 -vt 0.165310516953 0.075303182006 0.000000000000 -vt 0.162680253386 0.081052973866 0.000000000000 -vt 0.159637063742 0.079843878746 0.000000000000 -vt 0.160642147064 0.076046422124 0.000000000000 -vt 0.138225704432 0.079229891300 0.000000000000 -vt 0.137284547091 0.079804927111 0.000000000000 -vt 0.137759849429 0.078385323286 0.000000000000 -vt 0.137967005372 0.069246500731 0.000000000000 -vt 0.141144156456 0.069925799966 0.000000000000 -vt 0.135236993432 0.081436410546 0.000000000000 -vt 0.135894671082 0.079535424709 0.000000000000 -vt 0.134577959776 0.080499768257 0.000000000000 -vt 0.135107755661 0.084568321705 0.000000000000 -vt 0.134055823088 0.084435924888 0.000000000000 -vt 0.133896872401 0.080932959914 0.000000000000 -vt 0.133128866553 0.069963172078 0.000000000000 -vt 0.135289907455 0.069450497627 0.000000000000 -vt 0.163844078779 0.085923969746 0.000000000000 -vt 0.162402868271 0.094224542379 0.000000000000 -vt 0.132371440530 0.082354143262 0.000000000000 -vt 0.128753200173 0.071022763848 0.000000000000 -vt 0.105484560132 0.044374290854 0.000000000000 -vt 0.104406282306 0.042068254203 0.000000000000 -vt 0.105255573988 0.042082216591 0.000000000000 -vt 0.106301188469 0.043263372034 0.000000000000 -vt 0.105341121554 0.039797786623 0.000000000000 -vt 0.107362121344 0.040538098663 0.000000000000 -vt 0.102971151471 0.044095326215 0.000000000000 -vt 0.109018579125 0.049298208207 0.000000000000 -vt 0.103879645467 0.048260468990 0.000000000000 -vt 0.106288582087 0.055648040026 0.000000000000 -vt 0.099673971534 0.057078447193 0.000000000000 -vt 0.097955361009 0.055400144309 0.000000000000 -vt 0.110525324941 0.046463962644 0.000000000000 -vt 0.102905854583 0.041538458318 0.000000000000 -vt 0.103917017579 0.039889875799 0.000000000000 -vt 0.118358477950 0.052561160177 0.000000000000 -vt 0.113901987672 0.058519665152 0.000000000000 -vt 0.118132635951 0.047917779535 0.000000000000 -vt 0.118020296097 0.061421241611 0.000000000000 -vt 0.122165165842 0.055722784251 0.000000000000 -vt 0.126941144466 0.044675100595 0.000000000000 -vt 0.128192335367 0.048273082823 0.000000000000 -vt 0.129756718874 0.051271017641 0.000000000000 -vt 0.104457631707 0.038520034403 0.000000000000 -vt 0.106935217977 0.039335094392 0.000000000000 -vt 0.110430315137 0.041719038039 0.000000000000 -vt 0.109509423375 0.038915853947 0.000000000000 -vt 0.103522777557 0.036517728120 0.000000000000 -vt 0.097110807896 0.038964264095 0.000000000000 -vt 0.099772140384 0.040999215096 0.000000000000 -vt 0.097977206111 0.041525851935 0.000000000000 -vt 0.096010699868 0.040015961975 0.000000000000 -vt 0.098011419177 0.043816577643 0.000000000000 -vt 0.095403008163 0.041276607662 0.000000000000 -vt 0.100398525596 0.044103201479 0.000000000000 -vt 0.092719830573 0.059615265578 0.000000000000 -vt 0.090432256460 0.055584091693 0.000000000000 -vt 0.103748843074 0.062081839889 0.000000000000 -vt 0.109088838100 0.036444552243 0.000000000000 -vt 0.116189554334 0.040374409407 0.000000000000 -vt 0.117214694619 0.043208893389 0.000000000000 -vt 0.100217953324 0.036773279309 0.000000000000 -vt 0.101216748357 0.031871203333 0.000000000000 -vt 0.129965662956 0.062457408756 0.000000000000 -vt 0.134202405810 0.063657253981 0.000000000000 -vt 0.126032650471 0.071523055434 0.000000000000 -vt 0.126584276557 0.061618920416 0.000000000000 -vt 0.126425325871 0.056240197271 0.000000000000 -vt 0.131047084928 0.056420769542 0.000000000000 -vt 0.136421307921 0.063021421432 0.000000000000 -vt 0.135489389300 0.060313250870 0.000000000000 -vt 0.137195616961 0.059194456786 0.000000000000 -vt 0.136729776859 0.057686138898 0.000000000000 -vt 0.156631231308 0.049092646688 0.000000000000 -vt 0.157220244408 0.050672557205 0.000000000000 -vt 0.155348747969 0.051238145679 0.000000000000 -vt 0.152967959642 0.049707990140 0.000000000000 -vt 0.072539396584 0.024206470698 0.000000000000 -vt 0.073009975255 0.022490788251 0.000000000000 -vt 0.074167720973 0.023411672562 0.000000000000 -vt 0.075313083827 0.024346742779 0.000000000000 -vt 0.078608684242 0.024770483375 0.000000000000 -vt 0.076113961637 0.022561032325 0.000000000000 -vt 0.074407733977 0.021668069065 0.000000000000 -vt 0.085832558572 0.034895710647 0.000000000000 -vt 0.088694959879 0.030288133770 0.000000000000 -vt 0.092079266906 0.032754708081 0.000000000000 -vt 0.090345121920 0.035805787891 0.000000000000 -vt 0.080766797066 0.037424653769 0.000000000000 -vt 0.083163343370 0.031321149319 0.000000000000 -vt 0.082765944302 0.039579611272 0.000000000000 -vt 0.075439170003 0.026426948607 0.000000000000 -vt 0.079141400754 0.028394807130 0.000000000000 -vt 0.065825045109 0.019637845457 0.000000000000 -vt 0.070792645216 0.020507168025 0.000000000000 -vt 0.069720685482 0.023076642305 0.000000000000 -vt 0.066453002393 0.021015118808 0.000000000000 -vt 0.074630416930 0.020555578172 0.000000000000 -vt 0.078393660486 0.021780196577 0.000000000000 -vt 0.118059247732 0.097139850259 0.000000000000 -vt 0.114740446210 0.098579719663 0.000000000000 -vt 0.114250972867 0.095418095589 0.000000000000 -vt 0.117238104343 0.094657748938 0.000000000000 -vt 0.109638676047 0.091790616512 0.000000000000 -vt 0.115868493915 0.090512856841 0.000000000000 -vt 0.106643870473 0.097877010703 0.000000000000 -vt 0.080275960267 0.020345281810 0.000000000000 -vt 0.084542199969 0.020472947508 0.000000000000 -vt 0.082198783755 0.026802506298 0.000000000000 -vt 0.087908044457 0.024324897677 0.000000000000 -vt 0.082033514977 0.045575719327 0.000000000000 -vt 0.083040185273 0.050441998988 0.000000000000 -vt 0.079672768712 0.048204403371 0.000000000000 -vt 0.080490976572 0.044366639107 0.000000000000 -vt 0.076486371458 0.049105029553 0.000000000000 -vt 0.078130230308 0.043149676174 0.000000000000 -vt 0.081851139665 0.052377205342 0.000000000000 -vt 0.066788040102 0.023179534823 0.000000000000 -vt 0.064600206912 0.023336920887 0.000000000000 -vt 0.064584665000 0.022389467806 0.000000000000 -vt 0.066289320588 0.022115226835 0.000000000000 -vt 0.060966644436 0.023584589362 0.000000000000 -vt 0.061784636229 0.022029668093 0.000000000000 -vt 0.063617177308 0.021110359579 0.000000000000 -vt 0.091050982475 0.028800085187 0.000000000000 -vt 0.094201579690 0.030098102987 0.000000000000 -vt 0.090151712298 0.025628998876 0.000000000000 -vt 0.093743383884 0.027991328388 0.000000000000 -vt 0.066948570311 0.027383632958 0.000000000000 -vt 0.060868475586 0.030944012105 0.000000000000 -vt 0.062462348491 0.027807373554 0.000000000000 -vt 0.066029265523 0.025897156447 0.000000000000 -vt 0.059814978391 0.026431452483 0.000000000000 -vt 0.064851254225 0.024653624743 0.000000000000 -vt 0.054694723338 0.030345775187 0.000000000000 -vt 0.047921154648 0.032958924770 0.000000000000 -vt 0.043463084847 0.030261565000 0.000000000000 -vt 0.047107893974 0.029183298349 0.000000000000 -vt 0.050095032901 0.030151013285 0.000000000000 -vt 0.047431897372 0.026514083147 0.000000000000 -vt 0.050590369850 0.027707632631 0.000000000000 -vt 0.042810361832 0.027617346495 0.000000000000 -vt 0.047869820148 0.042448315769 0.000000000000 -vt 0.045954655856 0.041697423905 0.000000000000 -vt 0.046084117144 0.036520879716 0.000000000000 -vt 0.049386020750 0.038101017475 0.000000000000 -vt 0.044854771346 0.041064735502 0.000000000000 -vt 0.043885473162 0.036986950785 0.000000000000 -vt 0.051757570356 0.034210111946 0.000000000000 -vt 0.154328122735 0.043087299913 0.000000000000 -vt 0.154911056161 0.037254884839 0.000000000000 -vt 0.167563647032 0.034898862243 0.000000000000 -vt 0.161921262741 0.041362386197 0.000000000000 -vt 0.153502255678 0.030707374215 0.000000000000 -vt 0.163250565529 0.027692098171 0.000000000000 -vt 0.103868618608 0.102910131216 0.000000000000 -vt 0.111994698644 0.103447571397 0.000000000000 -vt 0.106992870569 0.109234735370 0.000000000000 -vt 0.101400464773 0.108030393720 0.000000000000 -vt 0.096481271088 0.122771069407 0.000000000000 -vt 0.089952446520 0.124826297164 0.000000000000 -vt 0.088087268174 0.119303897023 0.000000000000 -vt 0.094165779650 0.117781624198 0.000000000000 -vt 0.070482604206 0.058522816747 0.000000000000 -vt 0.077887058258 0.065487995744 0.000000000000 -vt 0.071217961609 0.071155369282 0.000000000000 -vt 0.066381409764 0.064373925328 0.000000000000 -vt 0.070337608457 0.087279632688 0.000000000000 -vt 0.063515856862 0.072370767593 0.000000000000 -vt 0.079217955470 0.082213863730 0.000000000000 -vt 0.050732221454 0.021630693227 0.000000000000 -vt 0.048374619335 0.020630329847 0.000000000000 -vt 0.048564653844 0.016099080443 0.000000000000 -vt 0.051573622972 0.018779102713 0.000000000000 -vt 0.045837800950 0.018292993307 0.000000000000 -vt 0.046268071979 0.015899594873 0.000000000000 -vt 0.051961567253 0.016921799630 0.000000000000 -vt 0.048754904419 0.013884905726 0.000000000000 -vt 0.026494264603 0.028064500540 0.000000000000 -vt 0.026460040361 0.028243724257 0.000000000000 -vt 0.026340033859 0.028218735009 0.000000000000 -vt 0.026315040886 0.028072383255 0.000000000000 -vt 0.026271361858 0.028111334890 0.000000000000 -vt 0.026316616684 0.028287407011 0.000000000000 -vt 0.026220027357 0.028083190322 0.000000000000 -vt 0.025830507278 0.027961608022 0.000000000000 -vt 0.026793498546 0.027743656188 0.000000000000 -vt 0.022305700928 0.037761259824 0.000000000000 -vt 0.020612087101 0.038116555661 0.000000000000 -vt 0.018779549748 0.032605204731 0.000000000000 -vt 0.019568044692 0.032413598150 0.000000000000 -vt 0.026293199509 0.029374904931 0.000000000000 -vt 0.026729550213 0.056939747185 0.000000000000 -vt 0.025282029063 0.059646341950 0.000000000000 -vt 0.023371588439 0.056319449097 0.000000000000 -vt 0.024051103741 0.054049205035 0.000000000000 -vt 0.023613180965 0.061910506338 0.000000000000 -vt 0.020778700709 0.056646820158 0.000000000000 -vt 0.024753816426 0.028824850917 0.000000000000 -vt 0.024046380073 0.029639910907 0.000000000000 -vt 0.021925639361 0.027996055782 0.000000000000 -vt 0.019233010709 0.029932837933 0.000000000000 -vt 0.020827110857 0.032996300608 0.000000000000 -vt 0.018511611968 0.030085492879 0.000000000000 -vt 0.018042616546 0.028514813632 0.000000000000 -vt 0.018695343286 0.028449516743 0.000000000000 -vt 0.018340270966 0.027692098171 0.000000000000 -vt 0.019049059600 0.027235481888 0.000000000000 -vt 0.018784277141 0.027503643185 0.000000000000 -vt 0.018855873495 0.026894371957 0.000000000000 -vt 0.019962288439 0.026958312839 0.000000000000 -vt 0.019748840481 0.027567584068 0.000000000000 -vt 0.160484761000 0.020033445209 0.000000000000 -vt 0.147482961416 0.021641500294 0.000000000000 -vt 0.154410749674 0.015146899968 0.000000000000 -vt 0.161012977362 0.008924962953 0.000000000000 -vt 0.166393518448 0.013308282942 0.000000000000 -vt 0.166352987289 0.025851901621 0.000000000000 -vt 0.166651993990 0.020915377885 0.000000000000 -vt 0.170089438558 0.015492964536 0.000000000000 -vt 0.019588306546 0.027807373554 0.000000000000 -vt 0.019134845585 0.027851056308 0.000000000000 -vt 0.019064817578 0.028270293027 0.000000000000 -vt 0.038729425520 0.090958446264 0.000000000000 -vt 0.036177065223 0.089736983180 0.000000000000 -vt 0.038676287979 0.085981622338 0.000000000000 -vt 0.040239315480 0.089066922665 0.000000000000 -vt 0.042406659573 0.093741580844 0.000000000000 -vt 0.040854658931 0.094687461853 0.000000000000 -vt 0.037749316543 0.094786986709 0.000000000000 -vt 0.027898332104 0.053784426302 0.000000000000 -vt 0.031369995326 0.055613588542 0.000000000000 -vt 0.030157541856 0.062759563327 0.000000000000 -vt 0.033898938447 0.060758832842 0.000000000000 -vt 0.032940682024 0.067951634526 0.000000000000 -vt 0.027729919180 0.065882235765 0.000000000000 -vt 0.093380436301 0.131579592824 0.000000000000 -vt 0.101789981127 0.126331463456 0.000000000000 -vt 0.037756975740 0.051755558699 0.000000000000 -vt 0.035693880171 0.048643913120 0.000000000000 -vt 0.039868485183 0.048481795937 0.000000000000 -vt 0.041482623667 0.049996417016 0.000000000000 -vt 0.042654555291 0.045740988106 0.000000000000 -vt 0.045040067285 0.046664800495 0.000000000000 -vt 0.036985594779 0.046448197216 0.000000000000 -vt 0.034682709724 0.086651682854 0.000000000000 -vt 0.030933646485 0.089648038149 0.000000000000 -vt 0.029764866456 0.085144937038 0.000000000000 -vt 0.031592678279 0.081364586949 0.000000000000 -vt 0.034569006413 0.082026988268 0.000000000000 -vt 0.032102201134 0.080329999328 0.000000000000 -vt 0.028744241223 0.051196273416 0.000000000000 -vt 0.030639147386 0.050709929317 0.000000000000 -vt 0.036769222468 0.056941326708 0.000000000000 -vt 0.034461375326 0.053469661623 0.000000000000 -vt 0.041688408703 0.088625833392 0.000000000000 -vt 0.044041287154 0.087036460638 0.000000000000 -vt 0.042447183281 0.080775573850 0.000000000000 -vt 0.049191255122 0.076541990042 0.000000000000 -vt 0.046822618693 0.081983312964 0.000000000000 -vt 0.044226806611 0.072259977460 0.000000000000 -vt 0.046158861369 0.086456924677 0.000000000000 -vt 0.027991769835 0.075538471341 0.000000000000 -vt 0.027059858665 0.080196022987 0.000000000000 -vt 0.025024902076 0.073586151004 0.000000000000 -vt 0.026086058468 0.070214003325 0.000000000000 -vt 0.026441354305 0.067705318332 0.000000000000 -vt 0.028167841956 0.071457535028 0.000000000000 -vt 0.028880013153 0.073195055127 0.000000000000 -vt 0.030567547306 0.076351955533 0.000000000000 -vt 0.030551789328 0.069745004177 0.000000000000 -vt 0.029026357457 0.069470763206 0.000000000000 -vt 0.030614150688 0.072523415089 0.000000000000 -vt 0.043936815113 0.092527776957 0.000000000000 -vt 0.046364661306 0.097238019109 0.000000000000 -vt 0.044538419694 0.100720718503 0.000000000000 -vt 0.042931716889 0.101345524192 0.000000000000 -vt 0.048817273229 0.100172251463 0.000000000000 -vt 0.048457246274 0.102738559246 0.000000000000 -vt 0.137558788061 0.098332047462 0.000000000000 -vt 0.139102905989 0.097345650196 0.000000000000 -vt 0.138733655214 0.098258882761 0.000000000000 -vt 0.137797236443 0.098970815539 0.000000000000 -vt 0.138197556138 0.099481925368 0.000000000000 -vt 0.139004737139 0.098487854004 0.000000000000 -vt 0.139805614948 0.097956493497 0.000000000000 -vt 0.139377146959 0.099524021149 0.000000000000 -vt 0.050679307431 0.107523784041 0.000000000000 -vt 0.054135438055 0.112569287419 0.000000000000 -vt 0.050330314785 0.114288136363 0.000000000000 -vt 0.047148425132 0.107650101185 0.000000000000 -vt 0.050964351743 0.104889020324 0.000000000000 -vt 0.053239319474 0.103625223041 0.000000000000 -vt 0.055646907538 0.107062682509 0.000000000000 -vt 0.058104019612 0.112983807921 0.000000000000 -vt 0.140801474452 0.096658468246 0.000000000000 -vt 0.138233363628 0.096205011010 0.000000000000 -vt 0.140344858170 0.095949456096 0.000000000000 -vt 0.142007410526 0.098663926125 0.000000000000 -vt 0.140017718077 0.100223585963 0.000000000000 -vt 0.141385748982 0.098199442029 0.000000000000 -vt 0.141155198216 0.097431436181 0.000000000000 -vt 0.133312597871 0.105359598994 0.000000000000 -vt 0.132514864206 0.104310825467 0.000000000000 -vt 0.134183719754 0.106383368373 0.000000000000 -vt 0.140815436840 0.100723877549 0.000000000000 -vt 0.141863986850 0.099782720208 0.000000000000 -vt 0.142421916127 0.100219070911 0.000000000000 -vt 0.142892494798 0.098935022950 0.000000000000 -vt 0.050447177142 0.103112548590 0.000000000000 -vt 0.052483703941 0.102864876390 0.000000000000 -vt 0.144728183746 0.104067876935 0.000000000000 -vt 0.144224733114 0.102514311671 0.000000000000 -vt 0.145186141133 0.101699247956 0.000000000000 -vt 0.146470203996 0.103851273656 0.000000000000 -vt 0.143584400415 0.101527899504 0.000000000000 -vt 0.144430533051 0.100561767817 0.000000000000 -vt 0.141550794244 0.101287886500 0.000000000000 -vt 0.061257999390 0.112659797072 0.000000000000 -vt 0.065134719014 0.115944370627 0.000000000000 -vt 0.061873342842 0.123118489981 0.000000000000 -vt 0.056573864073 0.121722295880 0.000000000000 -vt 0.067445486784 0.110573291779 0.000000000000 -vt 0.063640370965 0.107372716069 0.000000000000 -vt 0.069648854434 0.106004670262 0.000000000000 -vt 0.066685140133 0.100748866796 0.000000000000 -vt 0.072863399982 0.099591121078 0.000000000000 -vt 0.079629309475 0.095017760992 0.000000000000 -vt 0.063420616090 0.097499877214 0.000000000000 -vt 0.064508341253 0.086475610733 0.000000000000 -vt 0.143850758672 0.104326352477 0.000000000000 -vt 0.143411472440 0.103562861681 0.000000000000 -vt 0.056262250990 0.094160601497 0.000000000000 -vt 0.056469622999 0.096354737878 0.000000000000 -vt 0.051992859691 0.094852507114 0.000000000000 -vt 0.052877943963 0.092719376087 0.000000000000 -vt 0.057681854814 0.098607867956 0.000000000000 -vt 0.053764607757 0.098246261477 0.000000000000 -vt 0.051455195993 0.098188623786 0.000000000000 -vt 0.049526061863 0.095104902983 0.000000000000 -vt 0.050771173090 0.101749226451 0.000000000000 -vt 0.052848231047 0.102208778262 0.000000000000 -vt 0.051238592714 0.100907593966 0.000000000000 -vt 0.052483703941 0.100563332438 0.000000000000 -vt 0.057426307350 0.106243103743 0.000000000000 -vt 0.059230696410 0.102589055896 0.000000000000 -vt 0.054297324270 0.103461548686 0.000000000000 -vt 0.054697874933 0.101320534945 0.000000000000 -vt 0.052963506430 0.122161805630 0.000000000000 -vt 0.052379231900 0.131099566817 0.000000000000 -vt 0.048094075173 0.130477920175 0.000000000000 -vt 0.046760257334 0.130856394768 0.000000000000 -vt 0.050066884607 0.122128933668 0.000000000000 -vt 0.156333580613 0.006823139265 0.000000000000 -vt 0.149899765849 0.012613456696 0.000000000000 -vt 0.148388311267 0.011923130602 0.000000000000 -vt 0.154814451933 0.007212657481 0.000000000000 -vt 0.143572017550 0.018695119768 0.000000000000 -vt 0.142008990049 0.017630811781 0.000000000000 -vt 0.141720786691 0.017121285200 0.000000000000 -vt 0.147525057197 0.011396490037 0.000000000000 -vt 0.137385874987 0.025342378765 0.000000000000 -vt 0.135559633374 0.023885395378 0.000000000000 -vt 0.134478226304 0.023776423186 0.000000000000 -vt 0.129616662860 0.030687112361 0.000000000000 -vt 0.127787277102 0.029326722026 0.000000000000 -vt 0.122677840292 0.035132572055 0.000000000000 -vt 0.121847249568 0.031333755702 0.000000000000 -vt 0.121459312737 0.026788320392 0.000000000000 -vt 0.126799300313 0.025711629540 0.000000000000 -vt 0.116022720933 0.031031373888 0.000000000000 -vt 0.116498008370 0.026107456535 0.000000000000 -vt 0.109646543860 0.029707010835 0.000000000000 -vt 0.110188722610 0.025318961591 0.000000000000 -vt 0.102204486728 0.027808953077 0.000000000000 -vt 0.102347925305 0.024181474000 0.000000000000 -vt 0.120979495347 0.024089615792 0.000000000000 -vt 0.116271957755 0.023522447795 0.000000000000 -vt 0.110184207559 0.022347588092 0.000000000000 -vt 0.102416366339 0.022239964455 0.000000000000 -vt 0.133086755872 0.021283280104 0.000000000000 -vt 0.125700771809 0.022800825536 0.000000000000 -vt 0.131805852056 0.019698411226 0.000000000000 -vt 0.140229582787 0.014688935131 0.000000000000 -vt 0.145475924015 0.010294806212 0.000000000000 -vt 0.152886912227 0.006676563993 0.000000000000 -vt 0.047576893121 0.122769504786 0.000000000000 -vt 0.044946629554 0.130904808640 0.000000000000 -vt 0.047352414578 0.114989265800 0.000000000000 -vt 0.044636588544 0.108223572373 0.000000000000 -vt 0.040943596512 0.101545020938 0.000000000000 -vt 0.041778694838 0.117057085037 0.000000000000 -vt 0.038933407515 0.109159991145 0.000000000000 -vt 0.042194779962 0.125491634011 0.000000000000 -vt 0.042258728296 0.131637245417 0.000000000000 -vt 0.150459289551 0.005439335480 0.000000000000 -vt 0.147406622767 0.004468692467 0.000000000000 -vt 0.143596783280 0.008389092982 0.000000000000 -vt 0.139240026474 0.012483991683 0.000000000000 -vt 0.039006810635 0.131603017449 0.000000000000 -vt 0.039525572211 0.125474527478 0.000000000000 -vt 0.038843121380 0.117890611291 0.000000000000 -vt 0.036237854511 0.109794244170 0.000000000000 -vt 0.035265412182 0.101655572653 0.000000000000 -vt 0.032339062542 0.095125168562 0.000000000000 -vt 0.030368058011 0.090082809329 0.000000000000 -vt 0.031399492174 0.094974085689 0.000000000000 -vt 0.033498387784 0.101733475924 0.000000000000 -vt 0.028639992699 0.086095318198 0.000000000000 -vt 0.025852348655 0.081437990069 0.000000000000 -vt 0.022753085941 0.076138511300 0.000000000000 -vt 0.023653708398 0.075184747577 0.000000000000 -vt 0.020847376436 0.069434955716 0.000000000000 -vt 0.021620105952 0.067643180490 0.000000000000 -vt 0.023307643831 0.064264953136 0.000000000000 -vt 0.017721544951 0.061841826886 0.000000000000 -vt 0.020375225693 0.059083905071 0.000000000000 -vt 0.053222205490 0.012929573655 0.000000000000 -vt 0.050235074013 0.010815139860 0.000000000000 -vt 0.056510146707 0.014634449035 0.000000000000 -vt 0.054663654417 0.018612489104 0.000000000000 -vt 0.060259204358 0.016382552683 0.000000000000 -vt 0.059049900621 0.020086579025 0.000000000000 -vt 0.058030847460 0.021122742444 0.000000000000 -vt 0.054247569293 0.019831027836 0.000000000000 -vt 0.056996259838 0.023039262742 0.000000000000 -vt 0.053340639919 0.022660780698 0.000000000000 -vt 0.055484797806 0.025647688657 0.000000000000 -vt 0.052176591009 0.025117896497 0.000000000000 -vt 0.049496565014 0.024186205119 0.000000000000 -vt 0.045745935291 0.023629847914 0.000000000000 -vt 0.047365020961 0.022347588092 0.000000000000 -vt 0.044394996017 0.020589802414 0.000000000000 -vt 0.045242708176 0.019883941859 0.000000000000 -vt 0.024909622967 0.052349288017 0.000000000000 -vt 0.025043588132 0.050973366946 0.000000000000 -vt 0.027739373967 0.047426950186 0.000000000000 -vt 0.024479579180 0.048439692706 0.000000000000 -vt 0.042350593954 0.024865496904 0.000000000000 -vt 0.042051356286 0.021227214485 0.000000000000 -vt 0.036529209465 0.022210467607 0.000000000000 -vt 0.037055846304 0.026330355555 0.000000000000 -vt 0.036963980645 0.028058420867 0.000000000000 -vt 0.031510043889 0.025784809142 0.000000000000 -vt 0.031432140619 0.027294699103 0.000000000000 -vt 0.036716084927 0.029509097338 0.000000000000 -vt 0.031419757754 0.028624013066 0.000000000000 -vt 0.027148788795 0.027899462730 0.000000000000 -vt 0.027295140550 0.028648782521 0.000000000000 -vt 0.036427881569 0.031031373888 0.000000000000 -vt 0.031274754554 0.029678862542 0.000000000000 -vt 0.027111416683 0.029242511839 0.000000000000 -vt 0.030949188396 0.030895829201 0.000000000000 -vt 0.035843607038 0.032156471163 0.000000000000 -vt 0.020707104355 0.028784547001 0.000000000000 -vt 0.022812303156 0.031886737794 0.000000000000 -vt 0.020281784236 0.029052484781 0.000000000000 -vt 0.023458946496 0.031434852630 0.000000000000 -vt 0.022109370679 0.032270174474 0.000000000000 -vt 0.020171005279 0.029769152403 0.000000000000 -vt 0.021504826844 0.032532032579 0.000000000000 -vt 0.025012519211 0.036299776286 0.000000000000 -vt 0.024063490331 0.036756169051 0.000000000000 -vt 0.023340519518 0.037314102054 0.000000000000 -vt 0.027483826503 0.041390310973 0.000000000000 -vt 0.026430319995 0.041890602559 0.000000000000 -vt 0.025338094682 0.042350146919 0.000000000000 -vt 0.029316132888 0.046764533967 0.000000000000 -vt 0.022701527923 0.043102841824 0.000000000000 -vt 0.030600195751 0.046093124896 0.000000000000 -vt 0.032929647714 0.049832727760 0.000000000000 -vt 0.031767170876 0.045388620347 0.000000000000 -vt 0.029398767278 0.040288627148 0.000000000000 -vt 0.032870430499 0.044547211379 0.000000000000 -vt 0.028457617387 0.040873128921 0.000000000000 -vt 0.030336765572 0.039641980082 0.000000000000 -vt 0.033799197525 0.043578144163 0.000000000000 -vt 0.037752252072 0.045114379376 0.000000000000 -vt 0.041783425957 0.044548790902 0.000000000000 -vt 0.025857076049 0.035843163729 0.000000000000 -vt 0.026734281331 0.035361554474 0.000000000000 -vt 0.041914243251 0.032859180123 0.000000000000 -vt 0.040793869644 0.033786371350 0.000000000000 -vt 0.030941305682 0.023799840361 0.000000000000 -vt 0.057466831058 0.013119827956 0.000000000000 -vt 0.054774206132 0.010378789157 0.000000000000 -vt 0.051085937768 0.008826795965 0.000000000000 -vt 0.051754426211 0.007754832506 0.000000000000 -vt 0.088373884559 0.020429264754 0.000000000000 -vt 0.088517308235 0.019399408251 0.000000000000 -vt 0.090854644775 0.019729707390 0.000000000000 -vt 0.090842038393 0.020712960511 0.000000000000 -vt 0.094946391881 0.022414457053 0.000000000000 -vt 0.095091395080 0.020460564643 0.000000000000 -vt 0.094299748540 0.025574509054 0.000000000000 -vt 0.090377770364 0.023751430213 0.000000000000 -vt 0.109390988946 0.033906377852 0.000000000000 -vt 0.101716801524 0.030102606863 0.000000000000 -vt 0.116005614400 0.037482291460 0.000000000000 -vt 0.123491324484 0.037183284760 0.000000000000 -vt 0.125074386597 0.041345056146 0.000000000000 -vt 0.130738392472 0.031681168824 0.000000000000 -vt 0.133287593722 0.035913188010 0.000000000000 -vt 0.135103031993 0.039498783648 0.000000000000 -vt 0.140455409884 0.028768789023 0.000000000000 -vt 0.144802927971 0.035279151052 0.000000000000 -vt 0.146699190140 0.040768656880 0.000000000000 -vt 0.137726977468 0.044129770249 0.000000000000 -vt 0.147504791617 0.045349668711 0.000000000000 -vt 0.138828665018 0.047825690359 0.000000000000 -vt 0.146984457970 0.048285465688 0.000000000000 -vt 0.138644710183 0.050088282675 0.000000000000 -vt 0.129806697369 0.052833821625 0.000000000000 -vt 0.169347777963 0.087803125381 0.000000000000 -vt 0.166878044605 0.096072614193 0.000000000000 -vt 0.123137615621 0.057648766786 0.000000000000 -vt 0.120253384113 0.063675940037 0.000000000000 -vt 0.115961924195 0.067340791225 0.000000000000 -vt 0.118732467294 0.069205984473 0.000000000000 -vt 0.118006333709 0.075494781137 0.000000000000 -vt 0.115131542087 0.074644148350 0.000000000000 -vt 0.109959736466 0.072775810957 0.000000000000 -vt 0.111552253366 0.064712107182 0.000000000000 -vt 0.102553710341 0.070056840777 0.000000000000 -vt 0.109609171748 0.082248091698 0.000000000000 -vt 0.100861445069 0.081328779459 0.000000000000 -vt 0.090299867094 0.080892428756 0.000000000000 -vt 0.091694474220 0.066030398011 0.000000000000 -vt 0.079119786620 0.055774118751 0.000000000000 -vt 0.072969444096 0.053520996124 0.000000000000 -vt 0.071013972163 0.047288250178 0.000000000000 -vt 0.068132661283 0.051054421812 0.000000000000 -vt 0.065332636237 0.054049205035 0.000000000000 -vt 0.061893608421 0.046331342310 0.000000000000 -vt 0.058749314398 0.049416642636 0.000000000000 -vt 0.061658326536 0.058715995401 0.000000000000 -vt 0.055071856827 0.053793657571 0.000000000000 -vt 0.052937161177 0.044756155461 0.000000000000 -vt 0.049072828144 0.049751672894 0.000000000000 -vt 0.058147702366 0.064059153199 0.000000000000 -vt 0.052524227649 0.058092769235 0.000000000000 -vt 0.045923579484 0.053873132914 0.000000000000 -vt 0.046409692615 0.047785166651 0.000000000000 -vt 0.043375950307 0.051665265113 0.000000000000 -vt 0.050428483635 0.061640765518 0.000000000000 -vt 0.043210681528 0.056986581534 0.000000000000 -vt 0.040099035949 0.054348435253 0.000000000000 -vt 0.039909008890 0.059638466686 0.000000000000 -vt 0.047191876918 0.065960139036 0.000000000000 -vt 0.038101460785 0.065509825945 0.000000000000 -vt 0.035400953144 0.074902862310 0.000000000000 -vt 0.055581387132 0.067733466625 0.000000000000 -vt 0.052806120366 0.071872040629 0.000000000000 -vt 0.060378994793 0.075755074620 0.000000000000 -vt 0.058071371168 0.078776419163 0.000000000000 -vt 0.055618759245 0.080065205693 0.000000000000 -vt 0.052734520286 0.079525962472 0.000000000000 -vt 0.053052444011 0.081367731094 0.000000000000 -vt 0.050789859146 0.083292141557 0.000000000000 -vt 0.049432624131 0.082779452205 0.000000000000 -vt 0.049594733864 0.085844501853 0.000000000000 -vt 0.048008512706 0.086075052619 0.000000000000 -vt 0.050535883754 0.089364573359 0.000000000000 -vt 0.049192603678 0.090299412608 0.000000000000 -vt 0.047464769334 0.090754449368 0.000000000000 -vt 0.045393791050 0.091461896896 0.000000000000 -vt 0.047896388918 0.095926046371 0.000000000000 -vt 0.049828443676 0.098826035857 0.000000000000 -vt 0.057419996709 0.081000059843 0.000000000000 -vt 0.060966644436 0.087109863758 0.000000000000 -vt 0.059794712812 0.087519645691 0.000000000000 -vt 0.060287129134 0.094168484211 0.000000000000 -vt 0.059352282435 0.093295782804 0.000000000000 -vt 0.062393907458 0.086673513055 0.000000000000 -vt 0.061801750213 0.096052348614 0.000000000000 -vt 0.049892392009 0.042724128813 0.000000000000 -vt 0.052075494081 0.038878478110 0.000000000000 -vt 0.055960100144 0.041236083955 0.000000000000 -vt 0.055889848620 0.035288382322 0.000000000000 -vt 0.060157891363 0.037993393838 0.000000000000 -vt 0.065116032958 0.042724128813 0.000000000000 -vt 0.064106442034 0.032941814512 0.000000000000 -vt 0.068679787219 0.036249794066 0.000000000000 -vt 0.074156686664 0.040447585285 0.000000000000 -vt 0.073277905583 0.031112428755 0.000000000000 -vt 0.077270135283 0.034540414810 0.000000000000 -vt 0.072071976960 0.025901664048 0.000000000000 -vt 0.069379344583 0.029083553702 0.000000000000 -vt 0.069463558495 0.025113392621 0.000000000000 -vt 0.067841313779 0.024271763861 0.000000000000 -vt 0.099162861705 0.091220304370 0.000000000000 -vt 0.089000269771 0.092127218843 0.000000000000 -vt 0.097078159451 0.097934648395 0.000000000000 -vt 0.087571434677 0.099022373557 0.000000000000 -vt 0.079772509634 0.101554468274 0.000000000000 -vt 0.086257882416 0.102638825774 0.000000000000 -vt 0.079043231905 0.105086937547 0.000000000000 -vt 0.075504690409 0.108024075627 0.000000000000 -vt 0.074613302946 0.105156958103 0.000000000000 -vt 0.073125250638 0.110627785325 0.000000000000 -vt 0.071593523026 0.108968392015 0.000000000000 -vt 0.070599466562 0.114607393742 0.000000000000 -vt 0.069200120866 0.112909048796 0.000000000000 -vt 0.067964471877 0.119090452790 0.000000000000 -vt 0.066672757268 0.117705300450 0.000000000000 -vt 0.065623983741 0.124006733298 0.000000000000 -vt 0.064179614186 0.123651430011 0.000000000000 -vt 0.064288586378 0.130211338401 0.000000000000 -vt 0.062253635377 0.130234748125 0.000000000000 -vt 0.058482732624 0.130786374211 0.000000000000 -vt 0.122141756117 0.148486047983 0.000000000000 -vt 0.127875998616 0.147998362780 0.000000000000 -vt 0.127665698528 0.150818660855 0.000000000000 -vt 0.122073300183 0.151981130242 0.000000000000 -vt 0.133205190301 0.149006605148 0.000000000000 -vt 0.133069649339 0.151248708367 0.000000000000 -vt 0.172021716833 0.016547817737 0.000000000000 -vt 0.169503584504 0.022040475160 0.000000000000 -vt 0.137767508626 0.149533241987 0.000000000000 -vt 0.137985691428 0.152411177754 0.000000000000 -vt 0.168945640326 0.028130020946 0.000000000000 -vt 0.129772469401 0.142226740718 0.000000000000 -vt 0.133960813284 0.145277813077 0.000000000000 -vt 0.137136399746 0.143440544605 0.000000000000 -vt 0.135624930263 0.133524268866 0.000000000000 -vt 0.137717753649 0.134089857340 0.000000000000 -vt 0.109607592225 0.111450493336 0.000000000000 -vt 0.100973561406 0.115215316415 0.000000000000 -vt 0.100111901760 0.112997993827 0.000000000000 -vt 0.109063848853 0.109449759126 0.000000000000 -vt 0.094076842070 0.114406555891 0.000000000000 -vt 0.109662085772 0.113127216697 0.000000000000 -vt 0.101924166083 0.117096036673 0.000000000000 -vt 0.118073418736 0.107520863414 0.000000000000 -vt 0.118896141648 0.109094470739 0.000000000000 -vt 0.119979143143 0.110803857446 0.000000000000 -vt 0.109627857804 0.115891456604 0.000000000000 -vt 0.121512211859 0.112745359540 0.000000000000 -vt 0.113743022084 0.119411528111 0.000000000000 -vt 0.123366601765 0.114860013127 0.000000000000 -vt 0.116215899587 0.122188150883 0.000000000000 -vt 0.104867622256 0.130242630839 0.000000000000 -vt 0.095320373774 0.140049934387 0.000000000000 -vt 0.118313208222 0.124379143119 0.000000000000 -vt 0.107863992453 0.133408755064 0.000000000000 -vt 0.099661588669 0.143760040402 0.000000000000 -vt 0.087192721665 0.108221992850 0.000000000000 -vt 0.082525931299 0.110838308930 0.000000000000 -vt 0.110880628228 0.135783463717 0.000000000000 -vt 0.103619366884 0.146102100611 0.000000000000 -vt 0.078900031745 0.113002493978 0.000000000000 -vt 0.114026710391 0.137971296906 0.000000000000 -vt 0.107220500708 0.147809907794 0.000000000000 -vt 0.075743131340 0.114870831370 0.000000000000 -vt 0.117038622499 0.139775693417 0.000000000000 -vt 0.110938265920 0.149550363421 0.000000000000 -vt 0.072325952351 0.116807609797 0.000000000000 -vt 0.121297188103 0.140570491552 0.000000000000 -vt 0.116660133004 0.148486047983 0.000000000000 -vt 0.070322073996 0.122125789523 0.000000000000 -vt 0.125169411302 0.141371369362 0.000000000000 -vt 0.067821048200 0.126478031278 0.000000000000 -vt 0.126182377338 0.130125775933 0.000000000000 -vt 0.128910809755 0.131200894713 0.000000000000 -vt 0.132871732116 0.132607877254 0.000000000000 -vt 0.133273646235 0.122961118817 0.000000000000 -vt 0.135723099113 0.124199911952 0.000000000000 -vt 0.137808039784 0.124982103705 0.000000000000 -vt 0.138423606753 0.117220535874 0.000000000000 -vt 0.140033245087 0.117920324206 0.000000000000 -vt 0.141472890973 0.118429854512 0.000000000000 -vt 0.139520570636 0.125482171774 0.000000000000 -vt 0.124876491725 0.103963419795 0.000000000000 -vt 0.117411032319 0.105984404683 0.000000000000 -vt 0.124236144125 0.102663815022 0.000000000000 -vt 0.129794090986 0.099442973733 0.000000000000 -vt 0.130341216922 0.100725457072 0.000000000000 -vt 0.131000250578 0.101975068450 0.000000000000 -vt 0.125632330775 0.105312764645 0.000000000000 -vt 0.131731107831 0.103181213140 0.000000000000 -vt 0.126520335674 0.106766596437 0.000000000000 -vt 0.127601757646 0.108326464891 0.000000000000 -vt 0.128798455000 0.109823748469 0.000000000000 -vt 0.130024880171 0.111135736108 0.000000000000 -vt 0.125136762857 0.116662845016 0.000000000000 -vt 0.131293177605 0.112291902304 0.000000000000 -vt 0.126648217440 0.118099555373 0.000000000000 -vt 0.120172336698 0.126228556037 0.000000000000 -vt 0.128081783652 0.119333624840 0.000000000000 -vt 0.122010938823 0.127758711576 0.000000000000 -vt 0.129577711225 0.120530337095 0.000000000000 -vt 0.123975865543 0.129045933485 0.000000000000 -vt 0.131254225969 0.121706768870 0.000000000000 -vt 0.133884489536 0.114366039634 0.000000000000 -vt 0.135243296623 0.115338250995 0.000000000000 -vt 0.136775031686 0.116316780448 0.000000000000 -vt 0.138644710183 0.110085606575 0.000000000000 -vt 0.139880597591 0.110813304782 0.000000000000 -vt 0.141141012311 0.111453637481 0.000000000000 -vt 0.142396926880 0.111997395754 0.000000000000 -vt 0.143704399467 0.112458750606 0.000000000000 -vt 0.137226909399 0.097607508302 0.000000000000 -vt 0.142870649695 0.102392718196 0.000000000000 -vt 0.137440353632 0.109256580472 0.000000000000 -vt 0.142222434282 0.101855054498 0.000000000000 -vt 0.143068566918 0.100842311978 0.000000000000 -vt 0.143592044711 0.099678248167 0.000000000000 -vt 0.136274725199 0.108363851905 0.000000000000 -vt 0.135182499886 0.107386663556 0.000000000000 -vt 0.132592767477 0.113364085555 0.000000000000 -vt 0.095187984407 0.102827504277 0.000000000000 -vt 0.094770319760 0.109039977193 0.000000000000 -vt 0.115190759301 0.083002358675 0.000000000000 -vt 0.117822378874 0.083010017872 0.000000000000 -vt 0.118609294295 0.089811727405 0.000000000000 -vt 0.145974636078 0.053520996124 0.000000000000 -vt 0.146114915609 0.056235466152 0.000000000000 -vt 0.139495581388 0.056631293148 0.000000000000 -vt 0.139889821410 0.054191056639 0.000000000000 -vt 0.119352757931 0.094131112099 0.000000000000 -vt 0.136199980974 0.055359613150 0.000000000000 -vt 0.119957312942 0.096627399325 0.000000000000 -vt 0.133549451828 0.056533124298 0.000000000000 -vt 0.144910335541 0.057005267590 0.000000000000 -vt 0.139738738537 0.057558249682 0.000000000000 -vt 0.145398020744 0.061774957925 0.000000000000 -vt 0.139342918992 0.061978947371 0.000000000000 -vt 0.149662911892 0.063947036862 0.000000000000 -vt 0.153687775135 0.067230239511 0.000000000000 -vt 0.155149489641 0.059760045260 0.000000000000 -vt 0.158387213945 0.062926396728 0.000000000000 -vt 0.157279461622 0.070296630263 0.000000000000 -vt 0.163594841957 0.066641241312 0.000000000000 -vt 0.153912261128 0.057711135596 0.000000000000 -vt 0.159546762705 0.060358505696 0.000000000000 -vt 0.164818108082 0.064783707261 0.000000000000 -vt 0.165087610483 0.069813668728 0.000000000000 -vt 0.167392298579 0.069913417101 0.000000000000 -vt 0.162909239531 0.058806512505 0.000000000000 -vt 0.168085560203 0.065015837550 0.000000000000 -vt 0.170962139964 0.071387514472 0.000000000000 -vt 0.171663269401 0.079518079758 0.000000000000 -vt 0.168453454971 0.075633481145 0.000000000000 -vt 0.154616549611 0.054712962359 0.000000000000 -vt 0.160480037332 0.072431325912 0.000000000000 -vt 0.165078386664 0.102370887995 0.000000000000 -vt 0.160031303763 0.101119697094 0.000000000000 -vt 0.153291955590 0.047032695264 0.000000000000 -vt 0.081070527434 0.018897537142 0.000000000000 -vt 0.085028529167 0.019402559847 0.000000000000 -vt 0.066250368953 0.017697680742 0.000000000000 -vt 0.060628462583 0.015371378511 0.000000000000 -vt 0.066359564662 0.016670975834 0.000000000000 -vt 0.071543760598 0.016661521047 0.000000000000 -vt 0.071405068040 0.017848987132 0.000000000000 -vt 0.075989224017 0.018615640700 0.000000000000 -vt 0.076596923172 0.017573174089 0.000000000000 -vt 0.017198059708 0.064038887620 0.000000000000 -vt 0.020149167627 0.070380836725 0.000000000000 -vt 0.016810115427 0.065315067768 0.000000000000 -vt 0.158577471972 0.046223942190 0.000000000000 -vt 0.102452382445 0.038576319814 0.000000000000 -vt 0.089843250811 0.037739418447 0.000000000000 -vt 0.086650550365 0.040033075958 0.000000000000 -vt 0.086444757879 0.038370531052 0.000000000000 -vt 0.089615844190 0.039254039526 0.000000000000 -vt 0.094363689423 0.042627539486 0.000000000000 -vt 0.089279234409 0.040964987129 0.000000000000 -vt 0.096154123545 0.044999096543 0.000000000000 -vt 0.099321827292 0.047730680555 0.000000000000 -vt 0.097085818648 0.047713566571 0.000000000000 -vt 0.095434077084 0.052601691335 0.000000000000 -vt 0.094276331365 0.051693182439 0.000000000000 -vt 0.089904040098 0.052642215043 0.000000000000 -vt 0.089681141078 0.050836246461 0.000000000000 -vt 0.084422186017 0.049848269671 0.000000000000 -vt 0.086022593081 0.049033429474 0.000000000000 -vt 0.082889109850 0.045797046274 0.000000000000 -vt 0.084425337613 0.045902874321 0.000000000000 -vt 0.084310062230 0.042319070548 0.000000000000 -vt 0.085408590734 0.043013904244 0.000000000000 -vt 0.083744473755 0.041396614164 0.000000000000 -vt 0.087161652744 0.041465062648 0.000000000000 -vt 0.089801147580 0.053888674825 0.000000000000 -vt 0.096400216222 0.053726788610 0.000000000000 -vt 0.101375699043 0.047830428928 0.000000000000 -vt 0.150993570685 0.099017649889 0.000000000000 -vt 0.131135791540 0.085984766483 0.000000000000 -vt 0.137482464314 0.092382773757 0.000000000000 -vt 0.135268285871 0.088904798031 0.000000000000 -vt 0.139503464103 0.089568555355 0.000000000000 -vt 0.136636331677 0.087804690003 0.000000000000 -vt 0.139095246792 0.088097617030 0.000000000000 -vt 0.141262590885 0.086944609880 0.000000000000 -vt 0.143028035760 0.087709680200 0.000000000000 -vt 0.052647162229 0.028242152184 0.000000000000 -vt 0.091367103159 0.114521846175 0.000000000000 -vt 0.024943847209 0.029597807676 0.000000000000 -vt 0.082706280053 0.355134129524 0.000000000000 -vt 0.085947386920 0.363250732422 0.000000000000 -vt 0.082174688578 0.364220470190 0.000000000000 -vt 0.079061470926 0.357818633318 0.000000000000 -vt 0.076576210558 0.349433183670 0.000000000000 -vt 0.074389949441 0.353636831045 0.000000000000 -vt 0.070025764406 0.352275311947 0.000000000000 -vt 0.069683760405 0.347608089447 0.000000000000 -vt 0.084169343114 0.377381920815 0.000000000000 -vt 0.080777153373 0.375979661942 0.000000000000 -vt 0.082553848624 0.370932579041 0.000000000000 -vt 0.086099147797 0.371338099241 0.000000000000 -vt 0.079547807574 0.364964604378 0.000000000000 -vt 0.080153018236 0.370642364025 0.000000000000 -vt 0.076729759574 0.359675943851 0.000000000000 -vt 0.073228374124 0.356270015240 0.000000000000 -vt 0.070341885090 0.355011194944 0.000000000000 -vt 0.078728012741 0.374791979790 0.000000000000 -vt 0.078406266868 0.379009783268 0.000000000000 -vt 0.081292532384 0.382708638906 0.000000000000 -vt 0.077228710055 0.376913607121 0.000000000000 -vt 0.076079964638 0.380043476820 0.000000000000 -vt 0.075517080724 0.383981227875 0.000000000000 -vt 0.075921684504 0.377626001835 0.000000000000 -vt 0.067173950374 0.353658229113 0.000000000000 -vt 0.068672135472 0.355914741755 0.000000000000 -vt 0.064776502550 0.349804252386 0.000000000000 -vt 0.072278216481 0.378946751356 0.000000000000 -vt 0.069932326674 0.382139891386 0.000000000000 -vt 0.073346585035 0.376760721207 0.000000000000 -vt 0.065008409321 0.358051896095 0.000000000000 -vt 0.067364208400 0.359130382538 0.000000000000 -vt 0.061515796930 0.356177270412 0.000000000000 -vt 0.067828252912 0.375058323145 0.000000000000 -vt 0.064983420074 0.377222746611 0.000000000000 -vt 0.069865681231 0.373641878366 0.000000000000 -vt 0.063662886620 0.364159464836 0.000000000000 -vt 0.066595532000 0.364011079073 0.000000000000 -vt 0.059879150242 0.364149570465 0.000000000000 -vt 0.064561255276 0.369833588600 0.000000000000 -vt 0.067180253565 0.369111299515 0.000000000000 -vt 0.061178293079 0.370929658413 0.000000000000 -vt 0.087921552360 0.351186037064 0.000000000000 -vt 0.091303609312 0.361563861370 0.000000000000 -vt 0.079885534942 0.343255817890 0.000000000000 -vt 0.069204851985 0.340724855661 0.000000000000 -vt 0.060809489340 0.344233006239 0.000000000000 -vt 0.055593322963 0.353128671646 0.000000000000 -vt 0.053862329572 0.363875776529 0.000000000000 -vt 0.055507313460 0.372740805149 0.000000000000 -vt 0.060099344701 0.380897492170 0.000000000000 -vt 0.066655874252 0.386289954185 0.000000000000 -vt 0.073765367270 0.388392239809 0.000000000000 -vt 0.081145055592 0.388035595417 0.000000000000 -vt 0.088785246015 0.377678692341 0.000000000000 -vt 0.087788932025 0.382556229830 0.000000000000 -vt 0.090708971024 0.371422529221 0.000000000000 -vt 0.098516449332 0.359101116657 0.000000000000 -vt 0.095570974052 0.371151894331 0.000000000000 -vt 0.081494718790 0.391452759504 0.000000000000 -vt 0.072904601693 0.391978055239 0.000000000000 -vt 0.087930560112 0.387041747570 0.000000000000 -vt 0.089069843292 0.390307635069 0.000000000000 -vt 0.093086160719 0.377379685640 0.000000000000 -vt 0.092234395444 0.382332623005 0.000000000000 -vt 0.096012048423 0.378206431866 0.000000000000 -vt 0.095273993909 0.382441610098 0.000000000000 -vt 0.098627001047 0.372742831707 0.000000000000 -vt 0.100691899657 0.375768691301 0.000000000000 -vt 0.097777709365 0.379422277212 0.000000000000 -vt 0.096909299493 0.382944613695 0.000000000000 -vt 0.064227119088 0.390731811523 0.000000000000 -vt 0.047463636845 0.374592483044 0.000000000000 -vt 0.045266803354 0.362910062075 0.000000000000 -vt 0.053129222244 0.386380702257 0.000000000000 -vt 0.055269774050 0.337182939053 0.000000000000 -vt 0.068264156580 0.332182705402 0.000000000000 -vt 0.047308508307 0.348847329617 0.000000000000 -vt 0.083508059382 0.335973203182 0.000000000000 -vt 0.092679306865 0.386310219765 0.000000000000 -vt 0.094604156911 0.389197170734 0.000000000000 -vt 0.096809998155 0.386411547661 0.000000000000 -vt 0.095029927790 0.385251104832 0.000000000000 -vt 0.098225995898 0.388757675886 0.000000000000 -vt 0.097066685557 0.389816790819 0.000000000000 -vt 0.098929613829 0.391160309315 0.000000000000 -vt 0.097326502204 0.391429573298 0.000000000000 -vt 0.094737671316 0.391862779856 0.000000000000 -vt 0.089453734457 0.392666131258 0.000000000000 -vt 0.081771887839 0.393726825714 0.000000000000 -vt 0.072946928442 0.394806444645 0.000000000000 -vt 0.063999712467 0.395681649446 0.000000000000 -vt 0.053615327924 0.396396279335 0.000000000000 -vt 0.041419353336 0.396926730871 0.000000000000 -vt 0.039976555854 0.386726528406 0.000000000000 -vt 0.037052463740 0.374329954386 0.000000000000 -vt 0.035149227828 0.359872728586 0.000000000000 -vt 0.038212914020 0.342804163694 0.000000000000 -vt 0.049577396363 0.328440159559 0.000000000000 -vt 0.067996665835 0.322506874800 0.000000000000 -vt 0.093688450754 0.346306473017 0.000000000000 -vt 0.088374562562 0.327701002359 0.000000000000 -vt 0.100369259715 0.339963853359 0.000000000000 -vt 0.105655893683 0.350941717625 0.000000000000 -vt 0.103044107556 0.365339487791 0.000000000000 -vt 0.108533605933 0.357757389545 0.000000000000 -vt 0.105408892035 0.369979262352 0.000000000000 -vt 0.098068401217 0.383108973503 0.000000000000 -vt 0.098497763276 0.385625302792 0.000000000000 -vt 0.101734369993 0.380148172379 0.000000000000 -vt 0.098705813289 0.380785822868 0.000000000000 -vt 0.099697157741 0.387924820185 0.000000000000 -vt 0.100644618273 0.390900254250 0.000000000000 -vt 0.105129703879 0.377691507339 0.000000000000 -vt 0.105785802007 0.382571756840 0.000000000000 -vt 0.103088900447 0.383172452450 0.000000000000 -vt 0.106459483504 0.386435866356 0.000000000000 -vt 0.104129120708 0.386695683002 0.000000000000 -vt 0.104879111052 0.390249550343 0.000000000000 -vt 0.102643325925 0.390611141920 0.000000000000 -vt 0.101812496781 0.387293249369 0.000000000000 -vt 0.099612280726 0.383124738932 0.000000000000 -vt 0.100343361497 0.384889960289 0.000000000000 -vt 0.101334720850 0.382499039173 0.000000000000 -vt 0.099765837193 0.381787300110 0.000000000000 -vt 0.101950511336 0.385482788086 0.000000000000 -vt 0.102647826076 0.385179489851 0.000000000000 -vt 0.102046653628 0.383690536022 0.000000000000 -vt 0.101413294673 0.384207725525 0.000000000000 -vt 0.101018831134 0.383238196373 0.000000000000 -vt 0.111804887652 0.347057133913 0.000000000000 -vt 0.113323777914 0.353700101376 0.000000000000 -vt 0.116853311658 0.353322982788 0.000000000000 -vt 0.117552861571 0.346509546041 0.000000000000 -vt 0.123864643276 0.349401652813 0.000000000000 -vt 0.120530322194 0.355773121119 0.000000000000 -vt 0.129755362868 0.355360180140 0.000000000000 -vt 0.124298743904 0.360911160707 0.000000000000 -vt 0.134041413665 0.362597793341 0.000000000000 -vt 0.127354532480 0.367429167032 0.000000000000 -vt 0.129645943642 0.373671829700 0.000000000000 -vt 0.136888504028 0.369591563940 0.000000000000 -vt 0.138823032379 0.375629991293 0.000000000000 -vt 0.131178572774 0.379008889198 0.000000000000 -vt 0.110230609775 0.361257672310 0.000000000000 -vt 0.113775447011 0.356992095709 0.000000000000 -vt 0.115981966257 0.356578052044 0.000000000000 -vt 0.118140742183 0.358845561743 0.000000000000 -vt 0.120337590575 0.363843351603 0.000000000000 -vt 0.122301377356 0.370323300362 0.000000000000 -vt 0.123794607818 0.376463502645 0.000000000000 -vt 0.125330835581 0.385786980391 0.000000000000 -vt 0.124756477773 0.381512612104 0.000000000000 -vt 0.132145613432 0.383721172810 0.000000000000 -vt 0.117319837213 0.365754455328 0.000000000000 -vt 0.116345807910 0.360568702221 0.000000000000 -vt 0.118315473199 0.372491776943 0.000000000000 -vt 0.119095861912 0.378632873297 0.000000000000 -vt 0.115259900689 0.358279764652 0.000000000000 -vt 0.113950163126 0.358692705631 0.000000000000 -vt 0.111850589514 0.362477779388 0.000000000000 -vt 0.109477445483 0.369221389294 0.000000000000 -vt 0.108606114984 0.376295775175 0.000000000000 -vt 0.108548924327 0.381853967905 0.000000000000 -vt 0.108668252826 0.385990947485 0.000000000000 -vt 0.109056636691 0.389389663935 0.000000000000 -vt 0.106977775693 0.389831870794 0.000000000000 -vt 0.115236923099 0.380258053541 0.000000000000 -vt 0.119639605284 0.383368134499 0.000000000000 -vt 0.115580737591 0.384713888168 0.000000000000 -vt 0.114937916398 0.374172329903 0.000000000000 -vt 0.114662095904 0.367107868195 0.000000000000 -vt 0.114699468017 0.361614972353 0.000000000000 -vt 0.114764764905 0.359385490417 0.000000000000 -vt 0.114121511579 0.359670996666 0.000000000000 -vt 0.113303065300 0.362503677607 0.000000000000 -vt 0.112174823880 0.368418276310 0.000000000000 -vt 0.111594587564 0.375343382359 0.000000000000 -vt 0.111402764916 0.381200790405 0.000000000000 -vt 0.111436754465 0.385559558868 0.000000000000 -vt 0.111605182290 0.388848632574 0.000000000000 -vt 0.140208870173 0.380911469460 0.000000000000 -vt 0.120046690106 0.387208133936 0.000000000000 -vt 0.116041406989 0.388132423162 0.000000000000 -vt 0.108075186610 0.335427641869 0.000000000000 -vt 0.097032681108 0.317022114992 0.000000000000 -vt 0.068101368845 0.311556011438 0.000000000000 -vt 0.117994397879 0.334477722645 0.000000000000 -vt 0.128177925944 0.338179260492 0.000000000000 -vt 0.136790558696 0.345966488123 0.000000000000 -vt 0.142394453287 0.355307698250 0.000000000000 -vt 0.145550668240 0.364030212164 0.000000000000 -vt 0.147579327226 0.371295541525 0.000000000000 -vt 0.149121865630 0.377288043499 0.000000000000 -vt 0.117433980107 0.316912233829 0.000000000000 -vt 0.132998272777 0.322530061007 0.000000000000 -vt 0.144912809134 0.333580464125 0.000000000000 -vt 0.151742890477 0.346387058496 0.000000000000 -vt 0.155101761222 0.357449173927 0.000000000000 -vt 0.157138064504 0.366050541401 0.000000000000 -vt 0.158694103360 0.372791916132 0.000000000000 -vt 0.093021988869 0.298639088869 0.000000000000 -vt 0.116434976459 0.299687176943 0.000000000000 -vt 0.137037336826 0.306387364864 0.000000000000 -vt 0.152599602938 0.319078207016 0.000000000000 -vt 0.161577224731 0.334434717894 0.000000000000 -vt 0.165657475591 0.348677575588 0.000000000000 -vt 0.167427644134 0.359111487865 0.000000000000 -vt 0.169053271413 0.366990566254 0.000000000000 -vt 0.066684693098 0.299283713102 0.000000000000 -vt 0.044727105647 0.318464457989 0.000000000000 -vt 0.029994530603 0.333837360144 0.000000000000 -vt 0.023920066655 0.352325320244 0.000000000000 -vt 0.023143958300 0.369406253099 0.000000000000 -vt 0.024057183415 0.384051918983 0.000000000000 -vt 0.024341106415 0.396830379963 0.000000000000 -vt 0.177712291479 0.335085839033 0.000000000000 -vt 0.181121811271 0.347459256649 0.000000000000 -vt 0.170949757099 0.319616109133 0.000000000000 -vt 0.158325985074 0.304390668869 0.000000000000 -vt 0.139046162367 0.292386740446 0.000000000000 -vt 0.114894911647 0.285406500101 0.000000000000 -vt 0.089810602367 0.284732818604 0.000000000000 -vt 0.064246259630 0.287257254124 0.000000000000 -vt 0.060561817139 0.275299966335 0.000000000000 -vt 0.085912264884 0.272128403187 0.000000000000 -vt 0.112814709544 0.271828740835 0.000000000000 -vt 0.139997899532 0.280653685331 0.000000000000 -vt 0.162012219429 0.289723157883 0.000000000000 -vt 0.177664101124 0.300114750862 0.000000000000 -vt 0.190142661333 0.313898980618 0.000000000000 -vt 0.198672652245 0.327432364225 0.000000000000 -vt 0.205239757895 0.340885162354 0.000000000000 -vt 0.183992534876 0.357445776463 0.000000000000 -vt 0.069244705141 0.368339478970 0.000000000000 -vt 0.071158297360 0.372511804104 0.000000000000 -vt 0.073666974902 0.375427126884 0.000000000000 -vt 0.075608938932 0.376399338245 0.000000000000 -vt 0.076639704406 0.375857174397 0.000000000000 -vt 0.077665731311 0.373797893524 0.000000000000 -vt 0.078264869750 0.370282560587 0.000000000000 -vt 0.077448233962 0.365520745516 0.000000000000 -vt 0.075266703963 0.360965639353 0.000000000000 -vt 0.072741590440 0.357893168926 0.000000000000 -vt 0.070687949657 0.356488436460 0.000000000000 -vt 0.069615535438 0.357108056545 0.000000000000 -vt 0.068887837231 0.359731346369 0.000000000000 -vt 0.068630032241 0.363813161850 0.000000000000 -vt 0.070949353278 0.367750674486 0.000000000000 -vt 0.072260208428 0.371762514114 0.000000000000 -vt 0.074021823704 0.374623537064 0.000000000000 -vt 0.075438044965 0.375722974539 0.000000000000 -vt 0.076083339751 0.375304430723 0.000000000000 -vt 0.076256714761 0.373671144247 0.000000000000 -vt 0.077135719359 0.370294928551 0.000000000000 -vt 0.076337769628 0.365889549255 0.000000000000 -vt 0.074512436986 0.361760437489 0.000000000000 -vt 0.072514630854 0.358907490969 0.000000000000 -vt 0.070951603353 0.357409089804 0.000000000000 -vt 0.070442758501 0.357752889395 0.000000000000 -vt 0.070120111108 0.359841883183 0.000000000000 -vt 0.070317119360 0.363489836454 0.000000000000 -vt 0.095527067780 0.433499604464 0.000000000000 -vt 0.089006572962 0.431389659643 0.000000000000 -vt 0.089679561555 0.423253923655 0.000000000000 -vt 0.095813460648 0.423289269209 0.000000000000 -vt 0.090270593762 0.442476540804 0.000000000000 -vt 0.085782580078 0.438130587339 0.000000000000 -vt 0.082391515374 0.447095155716 0.000000000000 -vt 0.081284202635 0.441373258829 0.000000000000 -vt 0.088421173394 0.409246772528 0.000000000000 -vt 0.092461802065 0.414794385433 0.000000000000 -vt 0.088074430823 0.416153192520 0.000000000000 -vt 0.085401162505 0.411531209946 0.000000000000 -vt 0.085601098835 0.423056453466 0.000000000000 -vt 0.085188619792 0.417149722576 0.000000000000 -vt 0.084852233529 0.429683655500 0.000000000000 -vt 0.083113588393 0.435138046741 0.000000000000 -vt 0.080847173929 0.437920957804 0.000000000000 -vt 0.083637073636 0.413283139467 0.000000000000 -vt 0.082392193377 0.409229904413 0.000000000000 -vt 0.084188699722 0.404711484909 0.000000000000 -vt 0.081871181726 0.411629140377 0.000000000000 -vt 0.079863473773 0.408857047558 0.000000000000 -vt 0.078159049153 0.404978066683 0.000000000000 -vt 0.080601528287 0.411386430264 0.000000000000 -vt 0.077497541904 0.440609782934 0.000000000000 -vt 0.078839689493 0.437481015921 0.000000000000 -vt 0.075624249876 0.445949316025 0.000000000000 -vt 0.076512485743 0.410979568958 0.000000000000 -vt 0.072959765792 0.408222317696 0.000000000000 -vt 0.078687265515 0.412980526686 0.000000000000 -vt 0.074185512960 0.435919106007 0.000000000000 -vt 0.076881967485 0.434023529291 0.000000000000 -vt 0.070257902145 0.439116775990 0.000000000000 -vt 0.073384404182 0.416101634502 0.000000000000 -vt 0.069238848984 0.414494931698 0.000000000000 -vt 0.076494477689 0.417049527168 0.000000000000 -vt 0.072321221232 0.429132491350 0.000000000000 -vt 0.075570665300 0.428600221872 0.000000000000 -vt 0.067612551153 0.430139392614 0.000000000000 -vt 0.072135694325 0.422728389502 0.000000000000 -vt 0.075469121337 0.422917068005 0.000000000000 -vt 0.067447289824 0.422248363495 0.000000000000 -vt 0.102335080504 0.423187494278 0.000000000000 -vt 0.103228494525 0.435963690281 0.000000000000 -vt 0.096575386822 0.448499649763 0.000000000000 -vt 0.084121152759 0.455617934465 0.000000000000 -vt 0.072271011770 0.453928828239 0.000000000000 -vt 0.063513830304 0.444215625525 0.000000000000 -vt 0.059691589326 0.431783914566 0.000000000000 -vt 0.059796515852 0.421276837587 0.000000000000 -vt 0.062896229327 0.411542922258 0.000000000000 -vt 0.068578697741 0.404683113098 0.000000000000 -vt 0.075288772583 0.400957018137 0.000000000000 -vt 0.082664631307 0.399442404509 0.000000000000 -vt 0.090280279517 0.402916997671 0.000000000000 -vt 0.092445820570 0.407546848059 0.000000000000 -vt 0.097145929933 0.413269847631 0.000000000000 -vt 0.101524755359 0.411767631769 0.000000000000 -vt 0.108704730868 0.422636747360 0.000000000000 -vt 0.073573760688 0.397591859102 0.000000000000 -vt 0.082102417946 0.395999342203 0.000000000000 -vt 0.089554600418 0.398501247168 0.000000000000 -vt 0.089799568057 0.395039051771 0.000000000000 -vt 0.096459656954 0.406454414129 0.000000000000 -vt 0.094413220882 0.401787608862 0.000000000000 -vt 0.097341135144 0.400798738003 0.000000000000 -vt 0.099026650190 0.404693007469 0.000000000000 -vt 0.103435859084 0.409006088972 0.000000000000 -vt 0.100435674191 0.402943789959 0.000000000000 -vt 0.104281768203 0.405376374722 0.000000000000 -vt 0.098907768726 0.399778544903 0.000000000000 -vt 0.065163768828 0.400598347187 0.000000000000 -vt 0.049860190600 0.420209825039 0.000000000000 -vt 0.048853974789 0.434106171131 0.000000000000 -vt 0.054477673024 0.406693518162 0.000000000000 -vt 0.086032271385 0.466448366642 0.000000000000 -vt 0.067181386054 0.464296758175 0.000000000000 -vt 0.053818415850 0.451216369867 0.000000000000 -vt 0.103748381138 0.455393463373 0.000000000000 -vt 0.094275876880 0.397762984037 0.000000000000 -vt 0.095426648855 0.394399613142 0.000000000000 -vt 0.096762046218 0.398063540459 0.000000000000 -vt 0.098227351904 0.396364301443 0.000000000000 -vt 0.097545132041 0.393038094044 0.000000000000 -vt 0.098932549357 0.393664687872 0.000000000000 -vt 0.040455233306 0.407481104136 0.000000000000 -vt 0.037843432277 0.421338081360 0.000000000000 -vt 0.036472912878 0.438838243484 0.000000000000 -vt 0.042982604355 0.460524737835 0.000000000000 -vt 0.062214907259 0.477089822292 0.000000000000 -vt 0.089566305280 0.478372305632 0.000000000000 -vt 0.111008062959 0.438808530569 0.000000000000 -vt 0.113180801272 0.462344437838 0.000000000000 -vt 0.120472237468 0.442430824041 0.000000000000 -vt 0.117490500212 0.428076952696 0.000000000000 -vt 0.109111800790 0.414127260447 0.000000000000 -vt 0.115140110254 0.419330358505 0.000000000000 -vt 0.109508290887 0.408478111029 0.000000000000 -vt 0.099965557456 0.396614462137 0.000000000000 -vt 0.100016877055 0.399250566959 0.000000000000 -vt 0.101089760661 0.401380300522 0.000000000000 -vt 0.104426547885 0.401133537292 0.000000000000 -vt 0.100525066257 0.394041150808 0.000000000000 -vt 0.108131244779 0.401879489422 0.000000000000 -vt 0.105194106698 0.397765219212 0.000000000000 -vt 0.107807472348 0.397282481194 0.000000000000 -vt 0.105133533478 0.393932640553 0.000000000000 -vt 0.107335999608 0.393302202225 0.000000000000 -vt 0.102719649673 0.394079893827 0.000000000000 -vt 0.101905718446 0.396900862455 0.000000000000 -vt 0.101522728801 0.398900896311 0.000000000000 -vt 0.101974606514 0.400191038847 0.000000000000 -vt 0.103468522429 0.399126052856 0.000000000000 -vt 0.104171678424 0.395909041166 0.000000000000 -vt 0.103377550840 0.395803213120 0.000000000000 -vt 0.103972420096 0.397658735514 0.000000000000 -vt 0.103157803416 0.397318959236 0.000000000000 -vt 0.102937594056 0.398482114077 0.000000000000 -vt 0.120900921524 0.421827554703 0.000000000000 -vt 0.125391185284 0.429458737373 0.000000000000 -vt 0.124984331429 0.420799940825 0.000000000000 -vt 0.132154166698 0.427056103945 0.000000000000 -vt 0.128460273147 0.416311025620 0.000000000000 -vt 0.138081595302 0.420313149691 0.000000000000 -vt 0.142197445035 0.410675615072 0.000000000000 -vt 0.131676614285 0.408927738667 0.000000000000 -vt 0.133587732911 0.401068240404 0.000000000000 -vt 0.143351808190 0.401146143675 0.000000000000 -vt 0.133652120829 0.394226670265 0.000000000000 -vt 0.142618030310 0.392982929945 0.000000000000 -vt 0.132911369205 0.388540625572 0.000000000000 -vt 0.141394317150 0.386369884014 0.000000000000 -vt 0.114809587598 0.414815992117 0.000000000000 -vt 0.119088873267 0.418000578880 0.000000000000 -vt 0.121582247317 0.417691677809 0.000000000000 -vt 0.123152919114 0.414221823215 0.000000000000 -vt 0.124552257359 0.408110886812 0.000000000000 -vt 0.125927954912 0.401200413704 0.000000000000 -vt 0.126286625862 0.395116031170 0.000000000000 -vt 0.125815823674 0.390080004930 0.000000000000 -vt 0.120327234268 0.413139492273 0.000000000000 -vt 0.120299309492 0.407533794641 0.000000000000 -vt 0.120726875961 0.401063978672 0.000000000000 -vt 0.120826847851 0.395488440990 0.000000000000 -vt 0.119930967689 0.416081815958 0.000000000000 -vt 0.118429407477 0.416086316109 0.000000000000 -vt 0.115609556437 0.412894517183 0.000000000000 -vt 0.112695828080 0.407353222370 0.000000000000 -vt 0.111295580864 0.401569455862 0.000000000000 -vt 0.110395416617 0.396767795086 0.000000000000 -vt 0.109471604228 0.392846018076 0.000000000000 -vt 0.116785764694 0.395642906427 0.000000000000 -vt 0.116270169616 0.391529113054 0.000000000000 -vt 0.120401531458 0.391011029482 0.000000000000 -vt 0.117080941796 0.400902092457 0.000000000000 -vt 0.117325022817 0.407227128744 0.000000000000 -vt 0.118285760283 0.412657201290 0.000000000000 -vt 0.118986204267 0.415048807859 0.000000000000 -vt 0.118248149753 0.414979010820 0.000000000000 -vt 0.116768434644 0.412282764912 0.000000000000 -vt 0.114910230041 0.406959205866 0.000000000000 -vt 0.113860324025 0.401094585657 0.000000000000 -vt 0.113027706742 0.396125406027 0.000000000000 -vt 0.112157255411 0.392097175121 0.000000000000 -vt 0.130801886320 0.442939460278 0.000000000000 -vt 0.128610894084 0.468570888042 0.000000000000 -vt 0.094356708229 0.491361290216 0.000000000000 -vt 0.141893029213 0.437752097845 0.000000000000 -vt 0.150102630258 0.427333265543 0.000000000000 -vt 0.154337808490 0.414093464613 0.000000000000 -vt 0.154476270080 0.401521474123 0.000000000000 -vt 0.152643069625 0.391335010529 0.000000000000 -vt 0.150666207075 0.383463352919 0.000000000000 -vt 0.151377916336 0.454670488834 0.000000000000 -vt 0.163681745529 0.437636584044 0.000000000000 -vt 0.168372631073 0.418352723122 0.000000000000 -vt 0.166913852096 0.401432096958 0.000000000000 -vt 0.163569614291 0.388818919659 0.000000000000 -vt 0.160684034228 0.379647225142 0.000000000000 -vt 0.159950926900 0.471008867025 0.000000000000 -vt 0.132880300283 0.489435285330 0.000000000000 -vt 0.177281573415 0.447766780853 0.000000000000 -vt 0.184215664864 0.422988891602 0.000000000000 -vt 0.181977853179 0.401209205389 0.000000000000 -vt 0.176495552063 0.385539740324 0.000000000000 -vt 0.171912297606 0.374865829945 0.000000000000 -vt 0.098764792085 0.505384683609 0.000000000000 -vt 0.058615576476 0.491276592016 0.000000000000 -vt 0.294122487307 0.343028873205 0.000000000000 -vt 0.033512126654 0.473827123642 0.000000000000 -vt 0.022036869079 0.449060529470 0.000000000000 -vt 0.304196149111 0.365502059460 0.000000000000 -vt 0.294669389725 0.374178409576 0.000000000000 -vt 0.283370435238 0.353863328695 0.000000000000 -vt 0.021253105253 0.427221357822 0.000000000000 -vt 0.316540300846 0.419560700655 0.000000000000 -vt 0.308288812637 0.422085821629 0.000000000000 -vt 0.304480075836 0.396445810795 0.000000000000 -vt 0.312906295061 0.403799384832 0.000000000000 -vt 0.320418357849 0.438478231430 0.000000000000 -vt 0.309799134731 0.442829579115 0.000000000000 -vt 0.322631418705 0.453612715006 0.000000000000 -vt 0.308162033558 0.458434849977 0.000000000000 -vt 0.322842836380 0.466000735760 0.000000000000 -vt 0.304739683867 0.470083713531 0.000000000000 -vt 0.321488976479 0.476586610079 0.000000000000 -vt 0.301276564598 0.479211658239 0.000000000000 -vt 0.318110078573 0.486222833395 0.000000000000 -vt 0.298631459475 0.487806051970 0.000000000000 -vt 0.342029422522 0.477887094021 0.000000000000 -vt 0.335520654917 0.489814013243 0.000000000000 -vt 0.338924765587 0.462258905172 0.000000000000 -vt 0.335986942053 0.447854578495 0.000000000000 -vt 0.331019103527 0.432695329189 0.000000000000 -vt 0.324403166771 0.415379106998 0.000000000000 -vt 0.317968666553 0.397860914469 0.000000000000 -vt 0.311544537544 0.382980197668 0.000000000000 -vt 0.292794078588 0.320117980242 0.000000000000 -vt 0.322062432766 0.330567449331 0.000000000000 -vt 0.310178071260 0.344646602869 0.000000000000 -vt 0.321752399206 0.375562220812 0.000000000000 -vt 0.315860539675 0.358816295862 0.000000000000 -vt 0.327765852213 0.391973108053 0.000000000000 -vt 0.334508121014 0.409605920315 0.000000000000 -vt 0.341052263975 0.426227092743 0.000000000000 -vt 0.345613449812 0.441917032003 0.000000000000 -vt 0.349559307098 0.456911921501 0.000000000000 -vt 0.353330194950 0.470938861370 0.000000000000 -vt 0.352067083120 0.491384476423 0.000000000000 -vt 0.346471965313 0.498636275530 0.000000000000 -vt 0.357014626265 0.482859700918 0.000000000000 -vt 0.023049619049 0.410277992487 0.000000000000 -vt 0.188200235367 0.367613345385 0.000000000000 -vt 0.193979293108 0.380675494671 0.000000000000 -vt 0.199914619327 0.400077104568 0.000000000000 -vt 0.200497537851 0.426822185516 0.000000000000 -vt 0.188813567162 0.456079959869 0.000000000000 -vt 0.165967300534 0.483203917742 0.000000000000 -vt 0.135587558150 0.503403544426 0.000000000000 -vt 0.101455852389 0.518397510052 0.000000000000 -vt 0.136549651623 0.514204204082 0.000000000000 -vt 0.102526023984 0.530645966530 0.000000000000 -vt 0.170128390193 0.491040199995 0.000000000000 -vt 0.198282465339 0.460966050625 0.000000000000 -vt 0.217465236783 0.429308772087 0.000000000000 -vt 0.220426246524 0.397770404816 0.000000000000 -vt 0.216484680772 0.373772233725 0.000000000000 -vt 0.211094245315 0.355721533298 0.000000000000 -vt 0.078403115273 0.417854249477 0.000000000000 -vt 0.077661454678 0.423130065203 0.000000000000 -vt 0.361433088779 0.473092228174 0.000000000000 -vt 0.358897387981 0.464050680399 0.000000000000 -vt 0.356920510530 0.451468318701 0.000000000000 -vt 0.079683125019 0.414227455854 0.000000000000 -vt 0.080865636468 0.412698864937 0.000000000000 -vt 0.081717401743 0.412858963013 0.000000000000 -vt 0.082934811711 0.414582073689 0.000000000000 -vt 0.083612754941 0.417999476194 0.000000000000 -vt 0.083627842367 0.422989368439 0.000000000000 -vt 0.355338811874 0.436321228743 0.000000000000 -vt 0.352934360504 0.420035988092 0.000000000000 -vt 0.348425179720 0.402650177479 0.000000000000 -vt 0.342104852200 0.385241180658 0.000000000000 -vt 0.336092978716 0.368649065495 0.000000000000 -vt 0.083053693175 0.428555428982 0.000000000000 -vt 0.331038475037 0.351473778486 0.000000000000 -vt 0.295939028263 0.301119387150 0.000000000000 -vt 0.322564095259 0.306299775839 0.000000000000 -vt 0.297336816788 0.282364428043 0.000000000000 -vt 0.323178768158 0.284241318703 0.000000000000 -vt 0.367684066296 0.461390703917 0.000000000000 -vt 0.363470733166 0.458035647869 0.000000000000 -vt 0.364652335644 0.447590470314 0.000000000000 -vt 0.365994274616 0.432411193848 0.000000000000 -vt 0.366280674934 0.415150791407 0.000000000000 -vt 0.364420890808 0.396647334099 0.000000000000 -vt 0.360572069883 0.378713041544 0.000000000000 -vt 0.356490701437 0.362032413483 0.000000000000 -vt 0.353067219257 0.345778703690 0.000000000000 -vt 0.350522726774 0.327914893627 0.000000000000 -vt 0.348939448595 0.305953025818 0.000000000000 -vt 0.346083581448 0.277952730656 0.000000000000 -vt 0.373975127935 0.447995543480 0.000000000000 -vt 0.379207283258 0.431906849146 0.000000000000 -vt 0.382956564426 0.412491261959 0.000000000000 -vt 0.384116321802 0.392035484314 0.000000000000 -vt 0.382254749537 0.373682171106 0.000000000000 -vt 0.379626274109 0.358964234591 0.000000000000 -vt 0.377992331982 0.345823734999 0.000000000000 -vt 0.377301573753 0.329902321100 0.000000000000 -vt 0.376336544752 0.303653508425 0.000000000000 -vt 0.370527774096 0.266846507788 0.000000000000 -vt 0.216167435050 0.467717558146 0.000000000000 -vt 0.210370138288 0.459447145462 0.000000000000 -vt 0.081996142864 0.433199465275 0.000000000000 -vt 0.222096204758 0.439130961895 0.000000000000 -vt 0.226445078850 0.444121509790 0.000000000000 -vt 0.233966410160 0.386992007494 0.000000000000 -vt 0.231436342001 0.403846651316 0.000000000000 -vt 0.228788286448 0.415274649858 0.000000000000 -vt 0.231669127941 0.390098005533 0.000000000000 -vt 0.233401954174 0.365559697151 0.000000000000 -vt 0.227946877480 0.368952572346 0.000000000000 -vt 0.222369551659 0.352989733219 0.000000000000 -vt 0.231268167496 0.347663909197 0.000000000000 -vt 0.228197038174 0.333069592714 0.000000000000 -vt 0.215772062540 0.341411590576 0.000000000000 -vt 0.225630939007 0.321423888206 0.000000000000 -vt 0.210557922721 0.332115828991 0.000000000000 -vt 0.240293502808 0.310512185097 0.000000000000 -vt 0.238473564386 0.327548325062 0.000000000000 -vt 0.237924396992 0.344880312681 0.000000000000 -vt 0.237548619509 0.364148646593 0.000000000000 -vt 0.080796964467 0.435884207487 0.000000000000 -vt 0.235683202744 0.385488867760 0.000000000000 -vt 0.233118027449 0.406267970800 0.000000000000 -vt 0.231307089329 0.424209684134 0.000000000000 -vt 0.210896104574 0.489333540201 0.000000000000 -vt 0.228112816811 0.462109386921 0.000000000000 -vt 0.236405730247 0.472126305103 0.000000000000 -vt 0.236261844635 0.426290810108 0.000000000000 -vt 0.232935667038 0.445951789618 0.000000000000 -vt 0.237997591496 0.406573981047 0.000000000000 -vt 0.240250259638 0.385305374861 0.000000000000 -vt 0.242734611034 0.364867120981 0.000000000000 -vt 0.244929671288 0.346436828375 0.000000000000 -vt 0.247872665524 0.330308973789 0.000000000000 -vt 0.250990182161 0.316065877676 0.000000000000 -vt 0.249255821109 0.295715004206 0.000000000000 -vt 0.254375159740 0.304102927446 0.000000000000 -vt 0.259052336216 0.313747882843 0.000000000000 -vt 0.256746292114 0.322819858789 0.000000000000 -vt 0.255218595266 0.335408508778 0.000000000000 -vt 0.254195064306 0.350621551275 0.000000000000 -vt 0.252835571766 0.367554813623 0.000000000000 -vt 0.250323951244 0.386674314737 0.000000000000 -vt 0.247343555093 0.407099246979 0.000000000000 -vt 0.244989335537 0.426806420088 0.000000000000 -vt 0.242804884911 0.447076678276 0.000000000000 -vt 0.235569059849 0.496732383966 0.000000000000 -vt 0.210636273026 0.507261335850 0.000000000000 -vt 0.265602082014 0.325080633163 0.000000000000 -vt 0.261477023363 0.328609049320 0.000000000000 -vt 0.262952446938 0.338707923889 0.000000000000 -vt 0.264598786831 0.353362590075 0.000000000000 -vt 0.265408009291 0.370452553034 0.000000000000 -vt 0.264614790678 0.389507651329 0.000000000000 -vt 0.262594908476 0.408623784781 0.000000000000 -vt 0.260723888874 0.426476329565 0.000000000000 -vt 0.259777098894 0.444406121969 0.000000000000 -vt 0.259517729282 0.464280545712 0.000000000000 -vt 0.259723722935 0.488092929125 0.000000000000 -vt 0.272190570831 0.337464153767 0.000000000000 -vt 0.277376800776 0.352163642645 0.000000000000 -vt 0.281132608652 0.370615124702 0.000000000000 -vt 0.283069849014 0.391205787659 0.000000000000 -vt 0.282786369324 0.410528808832 0.000000000000 -vt 0.281975150108 0.425936192274 0.000000000000 -vt 0.281850397587 0.438871800900 0.000000000000 -vt 0.282650381327 0.454188883305 0.000000000000 -vt 0.285106837749 0.479603022337 0.000000000000 -vt 0.079694159329 0.435663342476 0.000000000000 -vt 0.078524023294 0.432797789574 0.000000000000 -vt 0.077620923519 0.428230971098 0.000000000000 -vt 0.079657681286 0.418213814497 0.000000000000 -vt 0.079307116568 0.423214733601 0.000000000000 -vt 0.080295994878 0.414836943150 0.000000000000 -vt 0.080963805318 0.413298457861 0.000000000000 -vt 0.081294111907 0.413456052542 0.000000000000 -vt 0.081488415599 0.414713323116 0.000000000000 -vt 0.082648865879 0.418150305748 0.000000000000 -vt 0.082757845521 0.422904253006 0.000000000000 -vt 0.082332074642 0.427900880575 0.000000000000 -vt 0.081549659371 0.432032704353 0.000000000000 -vt 0.080782778561 0.434659361839 0.000000000000 -vt 0.080355659127 0.434551537037 0.000000000000 -vt 0.079714648426 0.432231515646 0.000000000000 -vt 0.079296082258 0.428110510111 0.000000000000 -vt 0.221947401762 0.311564117670 0.000000000000 -vt 0.206676691771 0.323618710041 0.000000000000 -vt 0.234236359596 0.298808634281 0.000000000000 -vt 0.243671953678 0.288532763720 0.000000000000 -vt 0.210074737668 0.525931179523 0.000000000000 -vt 0.234980046749 0.519074082375 0.000000000000 -vt 0.258448451757 0.516759932041 0.000000000000 -vt 0.285151630640 0.516420423985 0.000000000000 -vt 0.195827364922 0.027920853347 0.000000000000 -vt 0.193216472864 0.025534208864 0.000000000000 -vt 0.208045646548 0.014590993524 0.000000000000 -vt 0.209939867258 0.017815891653 0.000000000000 -vt 0.219733223319 0.012098524719 0.000000000000 -vt 0.219577640295 0.015777334571 0.000000000000 -vt 0.231459319592 0.012075107545 0.000000000000 -vt 0.230521082878 0.016644857824 0.000000000000 -vt 0.243238985538 0.012886568904 0.000000000000 -vt 0.242090910673 0.019283901900 0.000000000000 -vt 0.254986017942 0.014112763107 0.000000000000 -vt 0.254209905863 0.020853456110 0.000000000000 -vt 0.268618255854 0.021859001368 0.000000000000 -vt 0.266599744558 0.015186753124 0.000000000000 -vt 0.278297692537 0.015581674874 0.000000000000 -vt 0.280311465263 0.022918354720 0.000000000000 -vt 0.294243395329 0.017284523696 0.000000000000 -vt 0.290962666273 0.024005178362 0.000000000000 -vt 0.296158790588 0.030226442963 0.000000000000 -vt 0.300414890051 0.029313210398 0.000000000000 -vt 0.303686618805 0.042154934257 0.000000000000 -vt 0.299199730158 0.041589122266 0.000000000000 -vt 0.303400695324 0.052850034088 0.000000000000 -vt 0.299067586660 0.051488291472 0.000000000000 -vt 0.301245510578 0.063028395176 0.000000000000 -vt 0.297050625086 0.061028119177 0.000000000000 -vt 0.188072130084 0.041658472270 0.000000000000 -vt 0.184647515416 0.040359999985 0.000000000000 -vt 0.185590237379 0.054300930351 0.000000000000 -vt 0.180999323726 0.054078709334 0.000000000000 -vt 0.186842098832 0.067733690143 0.000000000000 -vt 0.180815145373 0.066969290376 0.000000000000 -vt 0.187923297286 0.082707628608 0.000000000000 -vt 0.181074976921 0.081876814365 0.000000000000 -vt 0.187377303839 0.107746466994 0.000000000000 -vt 0.187539190054 0.120622426271 0.000000000000 -vt 0.181078135967 0.122370526195 0.000000000000 -vt 0.180750086904 0.106961801648 0.000000000000 -vt 0.181374669075 0.094601452351 0.000000000000 -vt 0.187665045261 0.095849484205 0.000000000000 -vt 0.227798283100 0.129312291741 0.000000000000 -vt 0.238564521074 0.124569609761 0.000000000000 -vt 0.243330389261 0.127270132303 0.000000000000 -vt 0.231010556221 0.133791074157 0.000000000000 -vt 0.220073655248 0.135354548693 0.000000000000 -vt 0.218523919582 0.131200432777 0.000000000000 -vt 0.206768333912 0.135661438107 0.000000000000 -vt 0.206591814756 0.131151124835 0.000000000000 -vt 0.194878339767 0.131718292832 0.000000000000 -vt 0.195264026523 0.127670004964 0.000000000000 -vt 0.297571629286 0.073909014463 0.000000000000 -vt 0.293510973454 0.071692824364 0.000000000000 -vt 0.293531447649 0.085388556123 0.000000000000 -vt 0.288804322481 0.082740962505 0.000000000000 -vt 0.284273296595 0.097582057118 0.000000000000 -vt 0.281252384186 0.094275429845 0.000000000000 -vt 0.270511358976 0.111514881253 0.000000000000 -vt 0.267813563347 0.108745023608 0.000000000000 -vt 0.253925532103 0.117747187614 0.000000000000 -vt 0.256331086159 0.121454820037 0.000000000000 -vt 0.267415255308 0.081492692232 0.000000000000 -vt 0.255906671286 0.094144165516 0.000000000000 -vt 0.244139820337 0.101001486182 0.000000000000 -vt 0.231230318546 0.105198845267 0.000000000000 -vt 0.219598352909 0.110711082816 0.000000000000 -vt 0.213647723198 0.110525771976 0.000000000000 -vt 0.198271200061 0.116921544075 0.000000000000 -vt 0.203886121511 0.110362097621 0.000000000000 -vt 0.196813777089 0.098104864359 0.000000000000 -vt 0.196252465248 0.102853164077 0.000000000000 -vt 0.272518634796 0.073012456298 0.000000000000 -vt 0.276711463928 0.062691569328 0.000000000000 -vt 0.280104994774 0.053172681481 0.000000000000 -vt 0.283575773239 0.045879449695 0.000000000000 -vt 0.283506870270 0.039421103895 0.000000000000 -vt 0.282259076834 0.030528377742 0.000000000000 -vt 0.272425651550 0.030439440161 0.000000000000 -vt 0.257659971714 0.030192218721 0.000000000000 -vt 0.247058525681 0.033215377480 0.000000000000 -vt 0.228341341019 0.025837715715 0.000000000000 -vt 0.218866378069 0.024133518338 0.000000000000 -vt 0.212634310126 0.025178913027 0.000000000000 -vt 0.200903266668 0.032452777028 0.000000000000 -vt 0.194876089692 0.044088792056 0.000000000000 -vt 0.193243041635 0.053994949907 0.000000000000 -vt 0.194931253791 0.067793801427 0.000000000000 -vt 0.198766767979 0.084062173963 0.000000000000 -vt 0.206359907985 0.094736546278 0.000000000000 -vt 0.212366148829 0.098234102130 0.000000000000 -vt 0.217166453600 0.096218973398 0.000000000000 -vt 0.205443292856 0.087112799287 0.000000000000 -vt 0.226509511471 0.090840920806 0.000000000000 -vt 0.237037748098 0.087899029255 0.000000000000 -vt 0.246875688434 0.081057921052 0.000000000000 -vt 0.256278872490 0.072482436895 0.000000000000 -vt 0.260736495256 0.057795342058 0.000000000000 -vt 0.259254723787 0.064904838800 0.000000000000 -vt 0.272691100836 0.038979575038 0.000000000000 -vt 0.262009739876 0.038989257067 0.000000000000 -vt 0.276944041252 0.045822035521 0.000000000000 -vt 0.268426418304 0.047114204615 0.000000000000 -vt 0.269619315863 0.043809827417 0.000000000000 -vt 0.253669768572 0.045147921890 0.000000000000 -vt 0.248847588897 0.056667540222 0.000000000000 -vt 0.246177032590 0.064497530460 0.000000000000 -vt 0.239239543676 0.071869567037 0.000000000000 -vt 0.232059359550 0.077080324292 0.000000000000 -vt 0.222070574760 0.079870447516 0.000000000000 -vt 0.206698760390 0.074161648750 0.000000000000 -vt 0.213897421956 0.072432681918 0.000000000000 -vt 0.205729246140 0.062620416284 0.000000000000 -vt 0.203790888190 0.054370727390 0.000000000000 -vt 0.204770088196 0.045650247484 0.000000000000 -vt 0.208388775587 0.038391694427 0.000000000000 -vt 0.216515302658 0.032267022878 0.000000000000 -vt 0.221525013447 0.031139671803 0.000000000000 -vt 0.229856431484 0.032532032579 0.000000000000 -vt 0.240117192268 0.040356174111 0.000000000000 -vt 0.238003432751 0.049525838345 0.000000000000 -vt 0.230851382017 0.062317129225 0.000000000000 -vt 0.223892956972 0.068100020289 0.000000000000 -vt 0.218158707023 0.060949768871 0.000000000000 -vt 0.224889278412 0.055608633906 0.000000000000 -vt 0.231338173151 0.044668566436 0.000000000000 -vt 0.224949836731 0.040866594762 0.000000000000 -vt 0.220517441630 0.039209909737 0.000000000000 -vt 0.215718701482 0.043925788254 0.000000000000 -vt 0.211569100618 0.049045812339 0.000000000000 -vt 0.212551221251 0.054835002869 0.000000000000 -vt 0.219418004155 0.048615094274 0.000000000000 -vt 0.177896246314 0.039324510843 0.000000000000 -vt 0.189204439521 0.020011376590 0.000000000000 -vt 0.204814672470 0.008875429630 0.000000000000 -vt 0.218808963895 0.005773015320 0.000000000000 -vt 0.232130467892 0.004795841873 0.000000000000 -vt 0.243434399366 0.006405927241 0.000000000000 -vt 0.255707651377 0.007152091712 0.000000000000 -vt 0.266037523746 0.008445382118 0.000000000000 -vt 0.276542603970 0.009638480842 0.000000000000 -vt 0.291882872581 0.013886258006 0.000000000000 -vt 0.305758953094 0.026801381260 0.000000000000 -vt 0.310110300779 0.042010162026 0.000000000000 -vt 0.309658646584 0.054701257497 0.000000000000 -vt 0.307640582323 0.066039174795 0.000000000000 -vt 0.304315268993 0.075605571270 0.000000000000 -vt 0.302689433098 0.083687961102 0.000000000000 -vt 0.289600938559 0.101637110114 0.000000000000 -vt 0.275979250669 0.114943787456 0.000000000000 -vt 0.261293739080 0.125751689076 0.000000000000 -vt 0.248583957553 0.132909372449 0.000000000000 -vt 0.218775406480 0.143254563212 0.000000000000 -vt 0.228658616543 0.143950298429 0.000000000000 -vt 0.206840604544 0.142785564065 0.000000000000 -vt 0.190907508135 0.138325244188 0.000000000000 -vt 0.181003153324 0.126772314310 0.000000000000 -vt 0.174718171358 0.105727061629 0.000000000000 -vt 0.175457358360 0.093386068940 0.000000000000 -vt 0.176170423627 0.080959752202 0.000000000000 -vt 0.175519734621 0.067012742162 0.000000000000 -vt 0.174860477448 0.054189030081 0.000000000000 -vt 0.175442948937 0.118314579129 0.000000000000 -vt 0.299658834934 0.013686995953 0.000000000000 -vt 0.297007620335 0.015501294285 0.000000000000 -vt 0.296986013651 0.094732716680 0.000000000000 -vt 0.178140535951 0.121313422918 0.000000000000 -vt 0.178094834089 0.129377126694 0.000000000000 -vt 0.290370285511 0.010927941650 0.000000000000 -vt 0.240662753582 0.138773083687 0.000000000000 -vt 0.059489179403 0.582100212574 0.000000000000 -vt 0.068415686488 0.582416296005 0.000000000000 -vt 0.067261539400 0.606926023960 0.000000000000 -vt 0.058599364012 0.606609225273 0.000000000000 -vt 0.050634499639 0.581815600395 0.000000000000 -vt 0.050033342093 0.606300354004 0.000000000000 -vt 0.041638877243 0.581597447395 0.000000000000 -vt 0.041299115866 0.606083035469 0.000000000000 -vt 0.032489020377 0.581519067287 0.000000000000 -vt 0.032466728240 0.605973839760 0.000000000000 -vt 0.023544281721 0.581574916840 0.000000000000 -vt 0.023710895330 0.605970263481 0.000000000000 -vt 0.077301658690 0.582797050476 0.000000000000 -vt 0.075893089175 0.607333362103 0.000000000000 -vt 0.035480882972 0.775563001633 0.000000000000 -vt 0.040293347090 0.776472151279 0.000000000000 -vt 0.036699648947 0.779854416847 0.000000000000 -vt 0.032038930804 0.777974605560 0.000000000000 -vt 0.044753897935 0.775144159794 0.000000000000 -vt 0.049120556563 0.776610195637 0.000000000000 -vt 0.044636141509 0.779394447803 0.000000000000 -vt 0.050690788776 0.780745148659 0.000000000000 -vt 0.054302733392 0.776831269264 0.000000000000 -vt 0.056948300451 0.779902398586 0.000000000000 -vt 0.057442288846 0.767054140568 0.000000000000 -vt 0.051350947469 0.766096353531 0.000000000000 -vt 0.045185070485 0.765643537045 0.000000000000 -vt 0.039071660489 0.765589058399 0.000000000000 -vt 0.032788928598 0.766110718250 0.000000000000 -vt 0.026467472315 0.767407417297 0.000000000000 -vt 0.063698008657 0.768436372280 0.000000000000 -vt 0.410184800625 0.205661505461 0.000000000000 -vt 0.061233457178 0.523812234402 0.000000000000 -vt 0.070765629411 0.524310529232 0.000000000000 -vt 0.069685108960 0.554912924767 0.000000000000 -vt 0.060390468687 0.554528176785 0.000000000000 -vt 0.053767081350 0.729990005493 0.000000000000 -vt 0.061261150986 0.730732798576 0.000000000000 -vt 0.054995980114 0.702194809914 0.000000000000 -vt 0.062634825706 0.702704548836 0.000000000000 -vt 0.064006246626 0.678737044334 0.000000000000 -vt 0.055990491062 0.678335130215 0.000000000000 -vt 0.056928943843 0.654432654381 0.000000000000 -vt 0.065110854805 0.654795587063 0.000000000000 -vt 0.066195428371 0.630862057209 0.000000000000 -vt 0.057763587683 0.630513489246 0.000000000000 -vt 0.051746767014 0.523659586906 0.000000000000 -vt 0.051160465926 0.554318308830 0.000000000000 -vt 0.046276170760 0.729541480541 0.000000000000 -vt 0.047176342458 0.701836824417 0.000000000000 -vt 0.047830644995 0.678016304970 0.000000000000 -vt 0.048644352704 0.654150307178 0.000000000000 -vt 0.049303833395 0.630233883858 0.000000000000 -vt 0.042389769107 0.523753523827 0.000000000000 -vt 0.041977059096 0.554233670235 0.000000000000 -vt 0.038769047707 0.729471445084 0.000000000000 -vt 0.039331037551 0.701696574688 0.000000000000 -vt 0.039704795927 0.677826702595 0.000000000000 -vt 0.040310915560 0.653930783272 0.000000000000 -vt 0.040829222649 0.630019962788 0.000000000000 -vt 0.032788697630 0.523885667324 0.000000000000 -vt 0.032603625208 0.554248988628 0.000000000000 -vt 0.031183568761 0.729752242565 0.000000000000 -vt 0.031547192484 0.701745390892 0.000000000000 -vt 0.031793061644 0.677753329277 0.000000000000 -vt 0.032022494823 0.653800427914 0.000000000000 -vt 0.032241348177 0.629892110825 0.000000000000 -vt 0.023286256939 0.523862004280 0.000000000000 -vt 0.023312594742 0.554275989532 0.000000000000 -vt 0.023615654558 0.730087935925 0.000000000000 -vt 0.023773714900 0.701748549938 0.000000000000 -vt 0.023966450244 0.677748382092 0.000000000000 -vt 0.023824151605 0.653813481331 0.000000000000 -vt 0.023755025119 0.629873633385 0.000000000000 -vt 0.080035939813 0.524939179420 0.000000000000 -vt 0.078819200397 0.555354475975 0.000000000000 -vt 0.068714916706 0.731523096561 0.000000000000 -vt 0.070204541087 0.703219473362 0.000000000000 -vt 0.071883074939 0.679210066795 0.000000000000 -vt 0.073152050376 0.655230820179 0.000000000000 -vt 0.074596188962 0.631297707558 0.000000000000 -vt 0.427655726671 0.333007007837 0.000000000000 -vt 0.440372914076 0.328327596188 0.000000000000 -vt 0.444987475872 0.344597071409 0.000000000000 -vt 0.432079792023 0.348230421543 0.000000000000 -vt 0.436833947897 0.363906830549 0.000000000000 -vt 0.449768215418 0.360880523920 0.000000000000 -vt 0.454692780972 0.378165900707 0.000000000000 -vt 0.441895663738 0.381562143564 0.000000000000 -vt 0.414691954851 0.337748318911 0.000000000000 -vt 0.419402211905 0.352767288685 0.000000000000 -vt 0.424107730389 0.368486940861 0.000000000000 -vt 0.429422736168 0.385863065720 0.000000000000 -vt 0.401303559542 0.341026574373 0.000000000000 -vt 0.406823009253 0.357325315475 0.000000000000 -vt 0.411697834730 0.372874319553 0.000000000000 -vt 0.417245209217 0.390449941158 0.000000000000 -vt 0.387970775366 0.344980746508 0.000000000000 -vt 0.393820285797 0.361572891474 0.000000000000 -vt 0.399133056402 0.377458244562 0.000000000000 -vt 0.404806077480 0.394824922085 0.000000000000 -vt 0.453473359346 0.324476778507 0.000000000000 -vt 0.466956764460 0.321778506041 0.000000000000 -vt 0.471398383379 0.338798433542 0.000000000000 -vt 0.458161979914 0.342115193605 0.000000000000 -vt 0.462697505951 0.358080714941 0.000000000000 -vt 0.475638061762 0.355021774769 0.000000000000 -vt 0.480182796717 0.372735410929 0.000000000000 -vt 0.467404156923 0.375559061766 0.000000000000 -vt 0.423334538937 0.312670528889 0.000000000000 -vt 0.433873385191 0.309838533401 0.000000000000 -vt 0.436265200377 0.312351495028 0.000000000000 -vt 0.422530740499 0.315895646811 0.000000000000 -vt 0.447797864676 0.306353360415 0.000000000000 -vt 0.450094014406 0.308744937181 0.000000000000 -vt 0.461704343557 0.302910506725 0.000000000000 -vt 0.463915377855 0.305326640606 0.000000000000 -vt 0.382604420185 0.326017051935 0.000000000000 -vt 0.392749220133 0.322181522846 0.000000000000 -vt 0.395257681608 0.324275016785 0.000000000000 -vt 0.382101863623 0.329265147448 0.000000000000 -vt 0.406064450741 0.317371100187 0.000000000000 -vt 0.408690214157 0.319537758827 0.000000000000 -vt 0.454164594412 0.389897853136 0.000000000000 -vt 0.448823004961 0.391495555639 0.000000000000 -vt 0.443516105413 0.386446684599 0.000000000000 -vt 0.456138074398 0.383067548275 0.000000000000 -vt 0.437463909388 0.395830690861 0.000000000000 -vt 0.431178033352 0.391206234694 0.000000000000 -vt 0.424428552389 0.400618851185 0.000000000000 -vt 0.419008165598 0.395644724369 0.000000000000 -vt 0.412200152874 0.404757648706 0.000000000000 -vt 0.406511843204 0.400167405605 0.000000000000 -vt 0.479276150465 0.385172754526 0.000000000000 -vt 0.473846048117 0.386270821095 0.000000000000 -vt 0.468606919050 0.380785584450 0.000000000000 -vt 0.481370300055 0.378176510334 0.000000000000 -vt 0.436999201775 0.315413832664 0.000000000000 -vt 0.423440814018 0.318899452686 0.000000000000 -vt 0.450722873211 0.311825752258 0.000000000000 -vt 0.464657485485 0.308184534311 0.000000000000 -vt 0.396297454834 0.327027112246 0.000000000000 -vt 0.382932245731 0.332121223211 0.000000000000 -vt 0.409763991833 0.322595357895 0.000000000000 -vt 0.442299365997 0.382790595293 0.000000000000 -vt 0.455049455166 0.379350900650 0.000000000000 -vt 0.429864943027 0.387207239866 0.000000000000 -vt 0.417697101831 0.391777902842 0.000000000000 -vt 0.404973804951 0.396399646997 0.000000000000 -vt 0.467713981867 0.376910001040 0.000000000000 -vt 0.480817049742 0.374158143997 0.000000000000 -vt 0.437278181314 0.316399097443 0.000000000000 -vt 0.423721343279 0.319981753826 0.000000000000 -vt 0.450930684805 0.312892526388 0.000000000000 -vt 0.464460253716 0.309410959482 0.000000000000 -vt 0.396746635437 0.328152865171 0.000000000000 -vt 0.383763283491 0.333080857992 0.000000000000 -vt 0.410141348839 0.323806256056 0.000000000000 -vt 0.371242642403 0.206788405776 0.000000000000 -vt 0.375714451075 0.200254172087 0.000000000000 -vt 0.379231601954 0.206475213170 0.000000000000 -vt 0.375783115625 0.212909027934 0.000000000000 -vt 0.383946120739 0.214252978563 0.000000000000 -vt 0.385994136333 0.206152796745 0.000000000000 -vt 0.383823841810 0.198206618428 0.000000000000 -vt 0.389040261507 0.196492955089 0.000000000000 -vt 0.391231000423 0.205955997109 0.000000000000 -vt 0.388896137476 0.215648040175 0.000000000000 -vt 0.386244505644 0.225284442306 0.000000000000 -vt 0.381366074085 0.234502539039 0.000000000000 -vt 0.377654612064 0.230434879661 0.000000000000 -vt 0.380352199078 0.177962914109 0.000000000000 -vt 0.385863542557 0.187034189701 0.000000000000 -vt 0.376735985279 0.182071089745 0.000000000000 -vt 0.400243073702 0.205795019865 0.000000000000 -vt 0.398853629827 0.194475561380 0.000000000000 -vt 0.398457139730 0.217155665159 0.000000000000 -vt 0.395268946886 0.228200212121 0.000000000000 -vt 0.391248136759 0.239007428288 0.000000000000 -vt 0.395271182060 0.183712929487 0.000000000000 -vt 0.390099167824 0.173236235976 0.000000000000 -vt 0.404895007610 0.295395046473 0.000000000000 -vt 0.401947498322 0.296175211668 0.000000000000 -vt 0.399637848139 0.292153716087 0.000000000000 -vt 0.401830643415 0.291295886040 0.000000000000 -vt 0.399310708046 0.296199768782 0.000000000000 -vt 0.397574305534 0.292755782604 0.000000000000 -vt 0.408904105425 0.288272053003 0.000000000000 -vt 0.407307982445 0.290285140276 0.000000000000 -vt 0.404559284449 0.287732571363 0.000000000000 -vt 0.406326085329 0.285840153694 0.000000000000 -vt 0.406662702560 0.292970359325 0.000000000000 -vt 0.403447926044 0.289671152830 0.000000000000 -vt 0.396660417318 0.287977755070 0.000000000000 -vt 0.398700773716 0.286984145641 0.000000000000 -vt 0.394956201315 0.288790345192 0.000000000000 -vt 0.401856094599 0.284300088882 0.000000000000 -vt 0.403861761093 0.282722651958 0.000000000000 -vt 0.400499969721 0.285655498505 0.000000000000 -vt 0.393806338310 0.283442467451 0.000000000000 -vt 0.395833194256 0.282441198826 0.000000000000 -vt 0.392093360424 0.284306377172 0.000000000000 -vt 0.399467855692 0.280218929052 0.000000000000 -vt 0.401700288057 0.278968840837 0.000000000000 -vt 0.397831201553 0.281272202730 0.000000000000 -vt 0.391297876835 0.278489261866 0.000000000000 -vt 0.393293648958 0.277554869652 0.000000000000 -vt 0.389414459467 0.279250085354 0.000000000000 -vt 0.397396445274 0.275657951832 0.000000000000 -vt 0.399793207645 0.274844229221 0.000000000000 -vt 0.395377457142 0.276584476233 0.000000000000 -vt 0.389087766409 0.272915095091 0.000000000000 -vt 0.391173362732 0.272055685520 0.000000000000 -vt 0.386810988188 0.273582458496 0.000000000000 -vt 0.395762920380 0.270275622606 0.000000000000 -vt 0.398250907660 0.270135104656 0.000000000000 -vt 0.393281280994 0.271341711283 0.000000000000 -vt 0.387520015240 0.266913384199 0.000000000000 -vt 0.389951229095 0.266276419163 0.000000000000 -vt 0.384966522455 0.267515212297 0.000000000000 -vt 0.394670933485 0.264871448278 0.000000000000 -vt 0.397267192602 0.265005409718 0.000000000000 -vt 0.392056882381 0.265746623278 0.000000000000 -vt 0.386280536652 0.262535691261 0.000000000000 -vt 0.389030128717 0.261800318956 0.000000000000 -vt 0.383825421333 0.263225555420 0.000000000000 -vt 0.394305050373 0.261209517717 0.000000000000 -vt 0.396993845701 0.261318951845 0.000000000000 -vt 0.391601622105 0.261423856020 0.000000000000 -vt 0.384926229715 0.259148895741 0.000000000000 -vt 0.388205587864 0.257940262556 0.000000000000 -vt 0.382767438889 0.261004865170 0.000000000000 -vt 0.394367873669 0.258704215288 0.000000000000 -vt 0.397562384605 0.259168028831 0.000000000000 -vt 0.391579329967 0.257740765810 0.000000000000 -vt 0.062066528946 0.497222512960 0.000000000000 -vt 0.071865737438 0.497819632292 0.000000000000 -vt 0.052253138274 0.497047573328 0.000000000000 -vt 0.042627077550 0.497259229422 0.000000000000 -vt 0.032757628709 0.497487276793 0.000000000000 -vt 0.022930733860 0.497487515211 0.000000000000 -vt 0.081421323121 0.498642355204 0.000000000000 -vt 0.408895790577 0.192783519626 0.000000000000 -vt 0.405064105988 0.180669501424 0.000000000000 -vt 0.400167405605 0.169291511178 0.000000000000 -vt 0.401480078697 0.242461070418 0.000000000000 -vt 0.405161798000 0.230870768428 0.000000000000 -vt 0.408491641283 0.218653172255 0.000000000000 -vt 0.380247503519 0.189571470022 0.000000000000 -vt 0.381086647511 0.223131284118 0.000000000000 -vt 0.420218378305 0.313499540091 0.000000000000 -vt 0.442574709654 0.393686324358 0.000000000000 -vt 0.437170535326 0.308998465538 0.000000000000 -vt 0.450992375612 0.305552929640 0.000000000000 -vt 0.395807057619 0.321048557758 0.000000000000 -vt 0.409543335438 0.316259503365 0.000000000000 -vt 0.460468471050 0.388684481382 0.000000000000 -vt 0.429571330547 0.398836284876 0.000000000000 -vt 0.417428702116 0.402817249298 0.000000000000 -vt 0.465852618217 0.387890368700 0.000000000000 -vt 0.165486067533 0.985748410225 0.000000000000 -vt 0.153918713331 0.884558439255 0.000000000000 -vt 0.153763413429 0.881860136986 0.000000000000 -vt 0.204113468528 0.982658386230 0.000000000000 -vt 0.204646229744 0.989186286926 0.000000000000 -vt 0.186044186354 0.877731442451 0.000000000000 -vt 0.185995131731 0.879323482513 0.000000000000 -vt 0.165391892195 0.991528987885 0.000000000000 -vt 0.215989306569 0.874527692795 0.000000000000 -vt 0.239299163222 0.979033589363 0.000000000000 -vt 0.216438904405 0.876245737076 0.000000000000 -vt 0.147602885962 0.884569108486 0.000000000000 -vt 0.252690643072 0.979669451714 0.000000000000 -vt 0.252580404282 0.986951112747 0.000000000000 -vt 0.149314463139 0.881703615189 0.000000000000 -vt 0.239499345422 0.986131906509 0.000000000000 -vt 0.139916136861 0.872989058495 0.000000000000 -vt 0.153603509068 0.992006182671 0.000000000000 -vt 0.153609484434 0.990444540977 0.000000000000 -vt 0.010600453243 0.824086070061 0.000000000000 -vt 0.012143557891 0.805372476578 0.000000000000 -vt 0.018072610721 0.805904865265 0.000000000000 -vt 0.018011515960 0.835803985596 0.000000000000 -vt 0.854685604572 0.394145637751 0.000000000000 -vt 0.856347262859 0.406974732876 0.000000000000 -vt 0.854803860188 0.407253265381 0.000000000000 -vt 0.852515399456 0.394508123398 0.000000000000 -vt 0.014217739925 0.786286652088 0.000000000000 -vt 0.141516894102 0.871268332005 0.000000000000 -vt 0.236085057259 0.870658397675 0.000000000000 -vt 0.235590070486 0.871755778790 0.000000000000 -vt 0.115637660027 0.902860224247 0.000000000000 -vt 0.110983915627 0.890343248844 0.000000000000 -vt 0.113721966743 0.903127968311 0.000000000000 -vt 0.108955033123 0.891542613506 0.000000000000 -vt 0.094152219594 0.932179987431 0.000000000000 -vt 0.092673666775 0.930834054947 0.000000000000 -vt 0.070010572672 0.963107407093 0.000000000000 -vt 0.068242847919 0.961778044701 0.000000000000 -vt 0.061999842525 0.971761763096 0.000000000000 -vt 0.174994021654 0.927675366402 0.000000000000 -vt 0.144831538200 0.970289051533 0.000000000000 -vt 0.200194299221 0.932316362858 0.000000000000 -vt 0.170293733478 0.964262902737 0.000000000000 -vt 0.108677349985 0.981302440166 0.000000000000 -vt 0.124079853296 0.982393920422 0.000000000000 -vt 0.078137099743 0.979704558849 0.000000000000 -vt 0.109282203019 0.983950555325 0.000000000000 -vt 0.105039052665 0.987083256245 0.000000000000 -vt 0.125474229455 0.988127648830 0.000000000000 -vt 0.111332640052 0.988403081894 0.000000000000 -vt 0.149527281523 0.983822643757 0.000000000000 -vt 0.175797849894 0.974198222160 0.000000000000 -vt 0.200493484735 0.947993755341 0.000000000000 -vt 0.202181890607 0.953875601292 0.000000000000 -vt 0.210946768522 0.941928744316 0.000000000000 -vt 0.204716980457 0.950321793556 0.000000000000 -vt 0.211182147264 0.940664827824 0.000000000000 -vt 0.221946761012 0.927524268627 0.000000000000 -vt 0.212981313467 0.939730703831 0.000000000000 -vt 0.219961285591 0.926237881184 0.000000000000 -vt 0.236418157816 0.878085970879 0.000000000000 -vt 0.009088402614 0.867007911205 0.000000000000 -vt 0.233274430037 0.900619506836 0.000000000000 -vt 0.223317831755 0.925070583820 0.000000000000 -vt 0.222155556083 0.926465988159 0.000000000000 -vt 0.221913784742 0.924954414368 0.000000000000 -vt 0.222598418593 0.927596032619 0.000000000000 -vt 0.201231330633 0.949153244495 0.000000000000 -vt 0.203538969159 0.953897118568 0.000000000000 -vt 0.818132102489 0.385249525309 0.000000000000 -vt 0.205010369420 0.951609432697 0.000000000000 -vt 0.213920146227 0.940414905548 0.000000000000 -vt 0.818589150906 0.383544415236 0.000000000000 -vt 0.780589759350 0.374358534813 0.000000000000 -vt 0.016577487811 0.868200361729 0.000000000000 -vt 0.016604727134 0.872863054276 0.000000000000 -vt 0.010927146301 0.873423874378 0.000000000000 -vt 0.781472146511 0.373139113188 0.000000000000 -vt 0.775797307491 0.355791121721 0.000000000000 -vt 0.767820060253 0.372488409281 0.000000000000 -vt 0.802661955357 0.343176126480 0.000000000000 -vt 0.212836444378 0.942034363747 0.000000000000 -vt 0.794418156147 0.332618147135 0.000000000000 -vt 0.017825072631 0.886228740215 0.000000000000 -vt 0.859027683735 0.311750322580 0.000000000000 -vt 0.856714665890 0.300876915455 0.000000000000 -vt 0.011322205886 0.886385619640 0.000000000000 -vt 0.890980184078 0.300591170788 0.000000000000 -vt 0.212094113231 0.942788124084 0.000000000000 -vt 0.234720200300 0.900862038136 0.000000000000 -vt 0.237578302622 0.878117561340 0.000000000000 -vt 0.077356182039 0.981415390968 0.000000000000 -vt 0.060611370951 0.973357379436 0.000000000000 -vt 0.105943888426 0.988982677460 0.000000000000 -vt 0.258138507605 0.974806785583 0.000000000000 -vt 0.257529258728 0.990823626518 0.000000000000 -vt 0.264203071594 0.971977353096 0.000000000000 -vt 0.263009667397 0.993429660797 0.000000000000 -vt 0.271215617657 0.974126696587 0.000000000000 -vt 0.269773542881 0.993223547935 0.000000000000 -vt 0.125471040606 0.989767909050 0.000000000000 -vt 0.110437445343 0.990312933922 0.000000000000 -vt 0.276588261127 0.979046463966 0.000000000000 -vt 0.273934006691 0.990138053894 0.000000000000 -vt 0.150033578277 0.985471129417 0.000000000000 -vt 0.176784589887 0.975747346878 0.000000000000 -vt 0.276720821857 0.986530065536 0.000000000000 -vt 0.022495752200 0.890904963017 0.000000000000 -vt 0.891464889050 0.306228846312 0.000000000000 -vt 0.904646217823 0.305932313204 0.000000000000 -vt 0.893834292889 0.301968216896 0.000000000000 -vt 0.904706299305 0.304305553436 0.000000000000 -vt 0.921183407307 0.310902148485 0.000000000000 -vt 0.906808555126 0.304849773645 0.000000000000 -vt 0.921672403812 0.309491783381 0.000000000000 -vt 0.938244044781 0.337644517422 0.000000000000 -vt 0.005772059783 0.892303645611 0.000000000000 -vt 0.024704044685 0.895432829857 0.000000000000 -vt 0.004067962989 0.897250592709 0.000000000000 -vt 0.023151105270 0.902699828148 0.000000000000 -vt 0.006364827976 0.903177917004 0.000000000000 -vt 0.019447928295 0.907367289066 0.000000000000 -vt 0.011597758159 0.909153997898 0.000000000000 -vt 0.018155282363 0.909749448299 0.000000000000 -vt 0.289794445038 0.979737758636 0.000000000000 -vt 0.289097309113 0.986868619919 0.000000000000 -vt 0.108699530363 0.986913800240 0.000000000000 -vt 0.923338353634 0.310172647238 0.000000000000 -vt 0.947028934956 0.322753190994 0.000000000000 -vt 0.017324453220 0.921973764896 0.000000000000 -vt 0.107475332916 0.990945875645 0.000000000000 -vt 0.012956982478 0.921561121941 0.000000000000 -vt 0.109573453665 0.884426295757 0.000000000000 -vt 0.020662194118 0.973094761372 0.000000000000 -vt 0.018618410453 0.972752928734 0.000000000000 -vt 0.963379323483 0.338597148657 0.000000000000 -vt 0.020546024665 0.981108963490 0.000000000000 -vt 0.018002038822 0.980931103230 0.000000000000 -vt 0.135590508580 0.867567420006 0.000000000000 -vt 0.106516152620 0.878543734550 0.000000000000 -vt 0.131759136915 0.862308800220 0.000000000000 -vt 0.101919859648 0.872579514980 0.000000000000 -vt 0.127446323633 0.855293273926 0.000000000000 -vt 0.106182672083 0.886078596115 0.000000000000 -vt 0.102917589247 0.880396783352 0.000000000000 -vt 0.099388279021 0.873800635338 0.000000000000 -vt 0.137774154544 0.865794837475 0.000000000000 -vt 0.134449630976 0.860945940018 0.000000000000 -vt 0.129994958639 0.853814363480 0.000000000000 -vt 0.098041392863 0.867455244064 0.000000000000 -vt 0.123956769705 0.849580526352 0.000000000000 -vt 0.096607387066 0.868979096413 0.000000000000 -vt 0.126601263881 0.848501205444 0.000000000000 -vt 0.095606558025 0.864713788033 0.000000000000 -vt 0.123283371329 0.847612500191 0.000000000000 -vt 0.093895524740 0.865760445595 0.000000000000 -vt 0.125174984336 0.846612274647 0.000000000000 -vt 0.090208120644 0.853443682194 0.000000000000 -vt 0.088275067508 0.855292141438 0.000000000000 -vt 0.116189479828 0.837091147900 0.000000000000 -vt 0.119325831532 0.836723268032 0.000000000000 -vt 0.133553490043 0.788949906826 0.000000000000 -vt 0.293736696243 0.986775279045 0.000000000000 -vt 0.295940577984 0.980653762817 0.000000000000 -vt 0.340545475483 0.984447240829 0.000000000000 -vt 0.340072214603 0.986525893211 0.000000000000 -vt 0.950552880764 0.345313966274 0.000000000000 -vt 0.967208921909 0.344859838486 0.000000000000 -vt 0.950094163418 0.353987187147 0.000000000000 -vt 0.933797061443 0.363659620285 0.000000000000 -vt 0.136295691133 0.788761913776 0.000000000000 -vt 0.138059511781 0.780847370625 0.000000000000 -vt 0.130408823490 0.777872502804 0.000000000000 -vt 0.131355047226 0.775953590870 0.000000000000 -vt 0.138569056988 0.778319716454 0.000000000000 -vt 0.118060231209 0.785308957100 0.000000000000 -vt 0.896019995213 0.384664356709 0.000000000000 -vt 0.115173012018 0.774169325829 0.000000000000 -vt 0.898356497288 0.351344764233 0.000000000000 -vt 0.096679173410 0.785911738873 0.000000000000 -vt 0.095730684698 0.772729396820 0.000000000000 -vt 0.104705169797 0.831313431263 0.000000000000 -vt 0.902008712292 0.319425404072 0.000000000000 -vt 0.086956694722 0.837567865849 0.000000000000 -vt 0.082478508353 0.790962874889 0.000000000000 -vt 0.833729565144 0.320394694805 0.000000000000 -vt 0.348657131195 0.984760761261 0.000000000000 -vt 0.081306569278 0.775940597057 0.000000000000 -vt 0.089978247881 0.773647964001 0.000000000000 -vt 0.829791605473 0.309479862452 0.000000000000 -vt 0.816609799862 0.333315908909 0.000000000000 -vt 0.807817518711 0.321131646633 0.000000000000 -vt 0.797316968441 0.333731085062 0.000000000000 -vt 0.795922100544 0.331054210663 0.000000000000 -vt 0.852600395679 0.366287618876 0.000000000000 -vt 0.888158023357 0.389725148678 0.000000000000 -vt 0.891561090946 0.383528649807 0.000000000000 -vt 0.892443001270 0.390044867992 0.000000000000 -vt 0.890115559101 0.403733402491 0.000000000000 -vt 0.893740594387 0.402232736349 0.000000000000 -vt 0.889661490917 0.409355312586 0.000000000000 -vt 0.859144628048 0.413082540035 0.000000000000 -vt 0.889299809933 0.416188776493 0.000000000000 -vt 0.860674321651 0.420680373907 0.000000000000 -vt 0.890587747097 0.423362225294 0.000000000000 -vt 0.861845076084 0.428339481354 0.000000000000 -vt 0.893469750881 0.431529492140 0.000000000000 -vt 0.863975346088 0.435634076595 0.000000000000 -vt 0.892712771893 0.409693717957 0.000000000000 -vt 0.893171131611 0.415372341871 0.000000000000 -vt 0.894341528416 0.422278076410 0.000000000000 -vt 0.895548760891 0.430168658495 0.000000000000 -vt 0.856991708279 0.413939237595 0.000000000000 -vt 0.858568608761 0.420849025249 0.000000000000 -vt 0.860028803349 0.428554058075 0.000000000000 -vt 0.861705243587 0.435540854931 0.000000000000 -vt 0.862937510014 0.448144823313 0.000000000000 -vt 0.865016877651 0.448156058788 0.000000000000 -vt 0.894014537334 0.443118661642 0.000000000000 -vt 0.896675527096 0.441695034504 0.000000000000 -vt 0.942015469074 0.465249389410 0.000000000000 -vt 0.938968360424 0.467184603214 0.000000000000 -vt 0.947230279446 0.471932232380 0.000000000000 -vt 0.929851353168 0.479779750109 0.000000000000 -vt 0.884821474552 0.455685496330 0.000000000000 -vt 0.911414802074 0.493092268705 0.000000000000 -vt 0.871183216572 0.461694657803 0.000000000000 -vt 0.860978066921 0.452166974545 0.000000000000 -vt 0.943686783314 0.478628307581 0.000000000000 -vt 0.933102667332 0.492131799459 0.000000000000 -vt 0.919620096684 0.505386710167 0.000000000000 -vt 0.891063272953 0.499169915915 0.000000000000 -vt 0.916852533817 0.507224857807 0.000000000000 -vt 0.908044636250 0.511230826378 0.000000000000 -vt 0.888901054859 0.516245007515 0.000000000000 -vt 0.869810879230 0.502536654472 0.000000000000 -vt 0.873295843601 0.517087996006 0.000000000000 -vt 0.852177441120 0.511175870895 0.000000000000 -vt 0.852176964283 0.514577090740 0.000000000000 -vt 0.850538194180 0.510758638382 0.000000000000 -vt 0.846698939800 0.494376987219 0.000000000000 -vt 0.847678959370 0.512833237648 0.000000000000 -vt 0.836011469364 0.506721198559 0.000000000000 -vt 0.830273568630 0.488239735365 0.000000000000 -vt 0.829936563969 0.486338347197 0.000000000000 -vt 0.858301818371 0.452152788639 0.000000000000 -vt 0.827840387821 0.498115986586 0.000000000000 -vt 0.829935252666 0.487876564264 0.000000000000 -vt 0.823986113071 0.491719275713 0.000000000000 -vt 0.069046996534 0.797405838966 0.000000000000 -vt 0.063239946961 0.785030543804 0.000000000000 -vt 0.056414369494 0.807498395443 0.000000000000 -vt 0.050693791360 0.794903695583 0.000000000000 -vt 0.038561563939 0.813347876072 0.000000000000 -vt 0.035990972072 0.810181796551 0.000000000000 -vt 0.047508850694 0.830956161022 0.000000000000 -vt 0.037681039423 0.814844489098 0.000000000000 -vt 0.029368514195 0.826868057251 0.000000000000 -vt 0.033771704882 0.815734088421 0.000000000000 -vt 0.038801524788 0.845296800137 0.000000000000 -vt 0.029519105330 0.846085309982 0.000000000000 -vt 0.027892099693 0.839723408222 0.000000000000 -vt 0.084708891809 0.852553844452 0.000000000000 -vt 0.083767443895 0.854980945587 0.000000000000 -vt 0.037650745362 0.847761273384 0.000000000000 -vt 0.114381492138 0.771946310997 0.000000000000 -vt 0.094816014171 0.771821796894 0.000000000000 -vt 0.080136142671 0.774619162083 0.000000000000 -vt 0.090211994946 0.772520661354 0.000000000000 -vt 0.095953144133 0.783221781254 0.000000000000 -vt 0.062365397811 0.784237205982 0.000000000000 -vt 0.049735300243 0.794033586979 0.000000000000 -vt 0.035117056221 0.810181081295 0.000000000000 -vt 0.028672711924 0.846871018410 0.000000000000 -vt 0.036163691431 0.812595427036 0.000000000000 -vt 0.032508853823 0.815019369125 0.000000000000 -vt 0.035413723439 0.813524901867 0.000000000000 -vt 0.028211543337 0.827950716019 0.000000000000 -vt 0.026609050110 0.839356005192 0.000000000000 -vt 0.896258294582 0.381265163422 0.000000000000 -vt 0.934112012386 0.361818969250 0.000000000000 -vt 0.059123776853 0.925175607204 0.000000000000 -vt 0.055362485349 0.926216900349 0.000000000000 -vt 0.054541967809 0.924610912800 0.000000000000 -vt 0.057503841817 0.922102153301 0.000000000000 -vt 0.059521101415 0.928506195545 0.000000000000 -vt 0.055455230176 0.928037106991 0.000000000000 -vt 0.058347843587 0.931667983532 0.000000000000 -vt 0.054807446897 0.929809391499 0.000000000000 -vt 0.056133113801 0.934393584728 0.000000000000 -vt 0.053610645235 0.931369364262 0.000000000000 -vt 0.053249321878 0.936173141003 0.000000000000 -vt 0.051895163953 0.932276666164 0.000000000000 -vt 0.049887977540 0.936500608921 0.000000000000 -vt 0.050015471876 0.932548344135 0.000000000000 -vt 0.046488307416 0.935653746128 0.000000000000 -vt 0.048176728189 0.932161509991 0.000000000000 -vt 0.043682835996 0.933717668056 0.000000000000 -vt 0.046699486673 0.931114256382 0.000000000000 -vt 0.042096994817 0.930674016476 0.000000000000 -vt 0.045871280134 0.929518997669 0.000000000000 -vt 0.041774652898 0.927204310894 0.000000000000 -vt 0.045793555677 0.927666127682 0.000000000000 -vt 0.042907558382 0.923894703388 0.000000000000 -vt 0.046437762678 0.925861775875 0.000000000000 -vt 0.045091055334 0.921195805073 0.000000000000 -vt 0.047651670873 0.924327433109 0.000000000000 -vt 0.048192583025 0.919690430164 0.000000000000 -vt 0.049426577985 0.923481881618 0.000000000000 -vt 0.051677010953 0.919228494167 0.000000000000 -vt 0.051336131990 0.923179805279 0.000000000000 -vt 0.054966412485 0.919925153255 0.000000000000 -vt 0.053134106100 0.923531472683 0.000000000000 -vt 0.063366554677 0.923810899258 0.000000000000 -vt 0.060973726213 0.919329464436 0.000000000000 -vt 0.064595483243 0.929011166096 0.000000000000 -vt 0.062306247652 0.933849632740 0.000000000000 -vt 0.059110067785 0.937792122364 0.000000000000 -vt 0.054868541658 0.941029012203 0.000000000000 -vt 0.049543462694 0.940982162952 0.000000000000 -vt 0.044648133218 0.939702689648 0.000000000000 -vt 0.040030620992 0.937077343464 0.000000000000 -vt 0.037820480764 0.932063996792 0.000000000000 -vt 0.036892317235 0.926711142063 0.000000000000 -vt 0.038925252855 0.921679198742 0.000000000000 -vt 0.042036972940 0.917214572430 0.000000000000 -vt 0.046976409853 0.915347874165 0.000000000000 -vt 0.051998518407 0.914744794369 0.000000000000 -vt 0.057310722768 0.915426671505 0.000000000000 -vt 0.067497454584 0.921644866467 0.000000000000 -vt 0.065058015287 0.917089760303 0.000000000000 -vt 0.069694779813 0.926195323467 0.000000000000 -vt 0.065975569189 0.936767637730 0.000000000000 -vt 0.062733851373 0.940771758556 0.000000000000 -vt 0.059423707426 0.944580018520 0.000000000000 -vt 0.048389576375 0.945518910885 0.000000000000 -vt 0.043406806886 0.944201171398 0.000000000000 -vt 0.038586281240 0.942701995373 0.000000000000 -vt 0.033321164548 0.933438599110 0.000000000000 -vt 0.031816206872 0.928624808788 0.000000000000 -vt 0.034770034254 0.919423639774 0.000000000000 -vt 0.037123106420 0.914970576763 0.000000000000 -vt 0.046392939985 0.910692512989 0.000000000000 -vt 0.051504157484 0.910091817379 0.000000000000 -vt 0.056533597410 0.909688174725 0.000000000000 -vt 0.071821056306 0.919187366962 0.000000000000 -vt 0.069497846067 0.914850890636 0.000000000000 -vt 0.074104093015 0.923345625401 0.000000000000 -vt 0.069763801992 0.939998447895 0.000000000000 -vt 0.066682241857 0.943804800510 0.000000000000 -vt 0.063756071031 0.947524607182 0.000000000000 -vt 0.046995721757 0.950295627117 0.000000000000 -vt 0.042247436941 0.949036777020 0.000000000000 -vt 0.037652872503 0.947865664959 0.000000000000 -vt 0.028527699411 0.934890091419 0.000000000000 -vt 0.027052603662 0.930507719517 0.000000000000 -vt 0.030363760889 0.917036354542 0.000000000000 -vt 0.032438538969 0.912907421589 0.000000000000 -vt 0.045932315290 0.905737102032 0.000000000000 -vt 0.050800107419 0.905163943768 0.000000000000 -vt 0.055495165288 0.904551923275 0.000000000000 -vt 0.050987325609 0.924352467060 0.000000000000 -vt 0.048744998872 0.925625741482 0.000000000000 -vt 0.048258863389 0.925050437450 0.000000000000 -vt 0.049704097211 0.924391329288 0.000000000000 -vt 0.054107807577 0.926788032055 0.000000000000 -vt 0.051701687276 0.929121911526 0.000000000000 -vt 0.050647579134 0.927882850170 0.000000000000 -vt 0.053451858461 0.925569355488 0.000000000000 -vt 0.052362285554 0.924720108509 0.000000000000 -vt 0.049598239362 0.926641643047 0.000000000000 -vt 0.054247222841 0.928189814091 0.000000000000 -vt 0.052564702928 0.930132806301 0.000000000000 -vt 0.053045056760 0.930693566799 0.000000000000 -vt 0.053973041475 0.929413259029 0.000000000000 -vt 0.050350688398 0.931418359280 0.000000000000 -vt 0.051625333726 0.931378662586 0.000000000000 -vt 0.048955641687 0.931039512157 0.000000000000 -vt 0.047835491598 0.930190026760 0.000000000000 -vt 0.047166489065 0.928965747356 0.000000000000 -vt 0.047026477754 0.927548825741 0.000000000000 -vt 0.047300122678 0.926310837269 0.000000000000 -vt 0.076263017952 0.889852464199 0.000000000000 -vt 0.072937078774 0.890983402729 0.000000000000 -vt 0.072223909199 0.886963069439 0.000000000000 -vt 0.073955483735 0.886285126209 0.000000000000 -vt 0.078647918999 0.887252748013 0.000000000000 -vt 0.075236566365 0.884860932827 0.000000000000 -vt 0.080082006752 0.883868515491 0.000000000000 -vt 0.075974173844 0.882985889912 0.000000000000 -vt 0.080343849957 0.880316436291 0.000000000000 -vt 0.076127000153 0.880949914455 0.000000000000 -vt 0.078979976475 0.877020061016 0.000000000000 -vt 0.075315542519 0.879069387913 0.000000000000 -vt 0.076549418271 0.874237835407 0.000000000000 -vt 0.074006743729 0.877511203289 0.000000000000 -vt 0.073425479233 0.872460305691 0.000000000000 -vt 0.072319932282 0.876525342464 0.000000000000 -vt 0.069821424782 0.872302711010 0.000000000000 -vt 0.070436544716 0.876380264759 0.000000000000 -vt 0.066397853196 0.873569548130 0.000000000000 -vt 0.068679399788 0.877089798450 0.000000000000 -vt 0.063854344189 0.876202642918 0.000000000000 -vt 0.067366369069 0.878527104855 0.000000000000 -vt 0.062428124249 0.879545271397 0.000000000000 -vt 0.066652543843 0.880400240421 0.000000000000 -vt 0.062527008355 0.883167207241 0.000000000000 -vt 0.066598244011 0.882463753223 0.000000000000 -vt 0.063823170960 0.886639058590 0.000000000000 -vt 0.067381329834 0.884392201900 0.000000000000 -vt 0.066064722836 0.889388978481 0.000000000000 -vt 0.068642385304 0.885931313038 0.000000000000 -vt 0.069291241467 0.890806376934 0.000000000000 -vt 0.070335276425 0.886830031872 0.000000000000 -vt 0.079105265439 0.894360721111 0.000000000000 -vt 0.073614127934 0.895603239536 0.000000000000 -vt 0.082558877766 0.889905154705 0.000000000000 -vt 0.084692724049 0.885016143322 0.000000000000 -vt 0.085654027760 0.879498064518 0.000000000000 -vt 0.083038873971 0.874549567699 0.000000000000 -vt 0.079515941441 0.870571315289 0.000000000000 -vt 0.074898667634 0.867442429066 0.000000000000 -vt 0.069151528180 0.867639601231 0.000000000000 -vt 0.063656993210 0.869233548641 0.000000000000 -vt 0.059899874032 0.873542368412 0.000000000000 -vt 0.057234056294 0.878605186939 0.000000000000 -vt 0.057885952294 0.884120523930 0.000000000000 -vt 0.059755094349 0.889095604420 0.000000000000 -vt 0.062920100987 0.893733680248 0.000000000000 -vt 0.068280227482 0.895384490490 0.000000000000 -vt 0.078785724938 0.900479376316 0.000000000000 -vt 0.073472566903 0.900497257710 0.000000000000 -vt 0.087039537728 0.891929209232 0.000000000000 -vt 0.089219875634 0.886968076229 0.000000000000 -vt 0.091177947819 0.882038056850 0.000000000000 -vt 0.086754925549 0.871306598186 0.000000000000 -vt 0.083158977330 0.867264211178 0.000000000000 -vt 0.079480238259 0.863445341587 0.000000000000 -vt 0.068381793797 0.862759649754 0.000000000000 -vt 0.063137896359 0.863549411297 0.000000000000 -vt 0.055807478726 0.870739161968 0.000000000000 -vt 0.052770502865 0.875079214573 0.000000000000 -vt 0.053255327046 0.885821878910 0.000000000000 -vt 0.055160112679 0.890882432461 0.000000000000 -vt 0.057204969227 0.895774066448 0.000000000000 -vt 0.068046040833 0.900283634663 0.000000000000 -vt 0.078120060265 0.905958473682 0.000000000000 -vt 0.073138959706 0.905713617802 0.000000000000 -vt 0.091880030930 0.893913924694 0.000000000000 -vt 0.093954570591 0.889196693897 0.000000000000 -vt 0.096018739045 0.884667575359 0.000000000000 -vt 0.090575344861 0.867730081081 0.000000000000 -vt 0.087147958577 0.863881051540 0.000000000000 -vt 0.083878643811 0.860125720501 0.000000000000 -vt 0.067553706467 0.857561290264 0.000000000000 -vt 0.062731571496 0.858179271221 0.000000000000 -vt 0.051463313401 0.867761790752 0.000000000000 -vt 0.048594601452 0.871683299541 0.000000000000 -vt 0.048404522240 0.887782871723 0.000000000000 -vt 0.050217278302 0.892602741718 0.000000000000 -vt 0.051908619702 0.897282183170 0.000000000000 -vt 0.067971713841 0.905510962009 0.000000000000 -vt 0.069196112454 0.884744703770 0.000000000000 -vt 0.068222053349 0.883839309216 0.000000000000 -vt 0.067552991211 0.882304251194 0.000000000000 -vt 0.068320401013 0.882175028324 0.000000000000 -vt 0.073343880475 0.884937107563 0.000000000000 -vt 0.071995504200 0.885450780392 0.000000000000 -vt 0.071372933686 0.881675302982 0.000000000000 -vt 0.073059923947 0.881411254406 0.000000000000 -vt 0.070542402565 0.885377347469 0.000000000000 -vt 0.069689460099 0.881946742535 0.000000000000 -vt 0.074404723942 0.883906543255 0.000000000000 -vt 0.074438758194 0.881199419498 0.000000000000 -vt 0.075204439461 0.881086766720 0.000000000000 -vt 0.075038559735 0.882739722729 0.000000000000 -vt 0.073512084782 0.878659069538 0.000000000000 -vt 0.074500329792 0.879579484463 0.000000000000 -vt 0.072161979973 0.877989232540 0.000000000000 -vt 0.070704765618 0.877902209759 0.000000000000 -vt 0.069342859089 0.878422200680 0.000000000000 -vt 0.068271823227 0.879460871220 0.000000000000 -vt 0.067647464573 0.880636036396 0.000000000000 -vt 0.069012485445 0.932736814022 0.000000000000 -vt 0.053315483034 0.946615636349 0.000000000000 -vt 0.034739337862 0.938278734684 0.000000000000 -vt 0.032324932516 0.923826873302 0.000000000000 -vt 0.041412316263 0.911473333836 0.000000000000 -vt 0.062483809888 0.912739932537 0.000000000000 -vt 0.072793565691 0.936362326145 0.000000000000 -vt 0.051563642919 0.951559722424 0.000000000000 -vt 0.029731415212 0.939354598522 0.000000000000 -vt 0.028038166463 0.921029269695 0.000000000000 -vt 0.041223250329 0.906235873699 0.000000000000 -vt 0.067299149930 0.910646736622 0.000000000000 -vt 0.084724672139 0.896705806255 0.000000000000 -vt 0.090130694211 0.875394165516 0.000000000000 -vt 0.073611505330 0.861880958080 0.000000000000 -vt 0.058759339154 0.866340816021 0.000000000000 -vt 0.051577635109 0.880795300007 0.000000000000 -vt 0.062752433121 0.899852573872 0.000000000000 -vt 0.089935369790 0.898496687412 0.000000000000 -vt 0.093930847943 0.871406018734 0.000000000000 -vt 0.072329230607 0.856650412083 0.000000000000 -vt 0.054085560143 0.863671362400 0.000000000000 -vt 0.046596772969 0.883146226406 0.000000000000 -vt 0.062987215817 0.905366241932 0.000000000000 -vt 0.724434196949 0.690520286560 0.000000000000 -vt 0.714673578739 0.670199394226 0.000000000000 -vt 0.738192379475 0.658733546734 0.000000000000 -vt 0.749425828457 0.679554581642 0.000000000000 -vt 0.766880452633 0.648001551628 0.000000000000 -vt 0.778476417065 0.667455196381 0.000000000000 -vt 0.658123552799 0.561918437481 0.000000000000 -vt 0.681013524532 0.545336842537 0.000000000000 -vt 0.691574394703 0.565115392208 0.000000000000 -vt 0.668605864048 0.578333139420 0.000000000000 -vt 0.678273379803 0.596119463444 0.000000000000 -vt 0.700517117977 0.582515180111 0.000000000000 -vt 0.708820402622 0.600191891193 0.000000000000 -vt 0.686416089535 0.614063024521 0.000000000000 -vt 0.693850934505 0.631938755512 0.000000000000 -vt 0.717175424099 0.619349181652 0.000000000000 -vt 0.726578891277 0.638749718666 0.000000000000 -vt 0.702835142612 0.650949716568 0.000000000000 -vt 0.727393448353 0.566789627075 0.000000000000 -vt 0.737516939640 0.584310531616 0.000000000000 -vt 0.746533215046 0.605367720127 0.000000000000 -vt 0.755558550358 0.627303957939 0.000000000000 -vt 0.717193305492 0.550311207771 0.000000000000 -vt 0.707122027874 0.527874290943 0.000000000000 -vt 0.648476541042 0.550091445446 0.000000000000 -vt 0.670800983906 0.526029586792 0.000000000000 -vt 0.796826541424 0.635315418243 0.000000000000 -vt 0.810074508190 0.653544664383 0.000000000000 -vt 0.828041613102 0.628299355507 0.000000000000 -vt 0.837326347828 0.640173137188 0.000000000000 -vt 0.784561932087 0.614920377731 0.000000000000 -vt 0.774542272091 0.593422353268 0.000000000000 -vt 0.802680790424 0.583606719971 0.000000000000 -vt 0.815609514713 0.603868663311 0.000000000000 -vt 0.744441092014 0.531438291073 0.000000000000 -vt 0.776179373264 0.512288391590 0.000000000000 -vt 0.783609092236 0.532737612724 0.000000000000 -vt 0.755129158497 0.549743592739 0.000000000000 -vt 0.697984158993 0.500902295113 0.000000000000 -vt 0.737360656261 0.508947730064 0.000000000000 -vt 0.730104506016 0.483820885420 0.000000000000 -vt 0.765154659748 0.571034491062 0.000000000000 -vt 0.792746603489 0.558559775352 0.000000000000 -vt 0.768725693226 0.492010682821 0.000000000000 -vt 0.757663547993 0.472875863314 0.000000000000 -vt 0.725043118000 0.693508327007 0.000000000000 -vt 0.750067889690 0.685739338398 0.000000000000 -vt 0.791203796864 0.399861633778 0.000000000000 -vt 0.779777586460 0.399193614721 0.000000000000 -vt 0.752974689007 0.710415661335 0.000000000000 -vt 0.804506599903 0.398513197899 0.000000000000 -vt 0.782004177570 0.452414214611 0.000000000000 -vt 0.780603945255 0.444166988134 0.000000000000 -vt 0.791876137257 0.443759024143 0.000000000000 -vt 0.793968260288 0.453128397465 0.000000000000 -vt 0.779418051243 0.435353308916 0.000000000000 -vt 0.778252422810 0.426639556885 0.000000000000 -vt 0.789694845676 0.427197962999 0.000000000000 -vt 0.790620148182 0.435532063246 0.000000000000 -vt 0.777533710003 0.418020188808 0.000000000000 -vt 0.777940571308 0.408807516098 0.000000000000 -vt 0.789442360401 0.409360051155 0.000000000000 -vt 0.789057195187 0.418372094631 0.000000000000 -vt 0.803890883923 0.427518129349 0.000000000000 -vt 0.804031312466 0.435820281506 0.000000000000 -vt 0.803060233593 0.417909622192 0.000000000000 -vt 0.802897393703 0.408120334148 0.000000000000 -vt 0.804555714130 0.443755626678 0.000000000000 -vt 0.807329356670 0.454006284475 0.000000000000 -vt 0.725099384785 0.716310918331 0.000000000000 -vt 0.779836833477 0.674231469631 0.000000000000 -vt 0.783605754375 0.697045505047 0.000000000000 -vt 0.818779408932 0.398010879755 0.000000000000 -vt 0.643724501133 0.545761525631 0.000000000000 -vt 0.628008902073 0.541231870651 0.000000000000 -vt 0.816486179829 0.407289743423 0.000000000000 -vt 0.643818080425 0.512760996819 0.000000000000 -vt 0.665438830853 0.521224975586 0.000000000000 -vt 0.815758764744 0.416817396879 0.000000000000 -vt 0.818642079830 0.444537609816 0.000000000000 -vt 0.817937195301 0.436300307512 0.000000000000 -vt 0.811494052410 0.658484101295 0.000000000000 -vt 0.816042482853 0.680989921093 0.000000000000 -vt 0.840249359608 0.645133495331 0.000000000000 -vt 0.822369277477 0.453545153141 0.000000000000 -vt 0.847676336765 0.654553532600 0.000000000000 -vt 0.848686635494 0.579840302467 0.000000000000 -vt 0.816775619984 0.426806628704 0.000000000000 -vt 0.821314275265 0.600943446159 0.000000000000 -vt 0.813257277012 0.578419387341 0.000000000000 -vt 0.838545382023 0.561789393425 0.000000000000 -vt 0.819137394428 0.502666831017 0.000000000000 -vt 0.823779404163 0.522105157375 0.000000000000 -vt 0.790229976177 0.529961049557 0.000000000000 -vt 0.781899273396 0.510464847088 0.000000000000 -vt 0.668055117130 0.483010739088 0.000000000000 -vt 0.692842900753 0.497021466494 0.000000000000 -vt 0.808572947979 0.481489390135 0.000000000000 -vt 0.704506456852 0.458266437054 0.000000000000 -vt 0.801172792912 0.554602205753 0.000000000000 -vt 0.830090582371 0.542637288570 0.000000000000 -vt 0.773884236813 0.490298360586 0.000000000000 -vt 0.726107180119 0.478320568800 0.000000000000 -vt 0.745716154575 0.441092967987 0.000000000000 -vt 0.753030359745 0.462626129389 0.000000000000 -vt 0.722523391247 0.691917836666 0.000000000000 -vt 0.749568045139 0.682414948940 0.000000000000 -vt 0.779008090496 0.670675337315 0.000000000000 -vt 0.667049825191 0.578830957413 0.000000000000 -vt 0.684892475605 0.614746153355 0.000000000000 -vt 0.676726400852 0.596634447575 0.000000000000 -vt 0.701373159885 0.652009308338 0.000000000000 -vt 0.692301928997 0.632841825485 0.000000000000 -vt 0.646996915340 0.549704909325 0.000000000000 -vt 0.667850673199 0.524221837521 0.000000000000 -vt 0.810716688633 0.655620336533 0.000000000000 -vt 0.839727461338 0.639870941639 0.000000000000 -vt 0.830280363560 0.627509713173 0.000000000000 -vt 0.818201720715 0.602329492569 0.000000000000 -vt 0.807740032673 0.580971300602 0.000000000000 -vt 0.786967098713 0.531335592270 0.000000000000 -vt 0.778827011585 0.511309623718 0.000000000000 -vt 0.695696294308 0.499585956335 0.000000000000 -vt 0.728171169758 0.480036228895 0.000000000000 -vt 0.796798646450 0.556795895100 0.000000000000 -vt 0.771090447903 0.491387873888 0.000000000000 -vt 0.755518972874 0.467876076698 0.000000000000 -vt 0.857891857624 0.600561559200 0.000000000000 -vt 0.832526981831 0.625968098640 0.000000000000 -vt 0.721892893314 0.690372586250 0.000000000000 -vt 0.713340461254 0.671590626240 0.000000000000 -vt 0.646686851978 0.550678908825 0.000000000000 -vt 0.656452476978 0.562453389168 0.000000000000 -vt 0.842236578465 0.638690054417 0.000000000000 -vt 0.764252245426 0.471054345369 0.000000000000 -vt 0.725051343441 0.691869199276 0.000000000000 -vt 0.646329224110 0.548061668873 0.000000000000 -vt 0.838410317898 0.642666935921 0.000000000000 -vt 0.759749114513 0.472487002611 0.000000000000 -# 6542 texture coords - -g Box001 -usemtl Material__283 -s 1 -f 18/3/1 17/4/2 1/1/3 -f 1/1/4 2/2/5 18/3/6 -f 19/6/7 18/3/8 2/2/9 -f 2/2/10 3/5/11 19/6/12 -f 20/8/13 19/6/14 3/5/15 -f 3/5/16 4/7/17 20/8/18 -f 21/11/19 20/12/20 4/9/21 -f 4/9/22 5/10/23 21/11/24 -f 22/14/25 21/11/26 5/10/27 -f 5/10/28 6/13/29 22/14/30 -f 23/16/31 22/14/32 6/13/33 -f 6/13/34 7/15/35 23/16/36 -f 24/18/37 23/16/38 7/15/39 -f 7/15/40 8/17/41 24/18/42 -f 25/20/43 24/18/44 8/17/45 -f 8/17/46 9/19/47 25/20/48 -f 26/22/49 25/20/50 9/19/51 -f 9/19/52 10/21/53 26/22/54 -f 27/24/55 26/22/56 10/21/57 -f 10/21/58 11/23/59 27/24/60 -f 28/26/61 27/24/62 11/23/63 -f 11/23/64 12/25/65 28/26/66 -f 29/28/67 28/26/68 12/25/69 -f 12/25/70 13/27/71 29/28/72 -f 30/30/73 29/28/74 13/27/75 -f 13/27/76 14/29/77 30/30/78 -f 31/32/79 30/30/80 14/29/81 -f 14/29/82 15/31/83 31/32/84 -f 32/34/85 31/32/86 15/31/87 -f 15/31/88 16/33/89 32/34/90 -f 17/4/91 32/34/92 16/33/93 -f 16/33/94 1/1/95 17/4/96 -f 65/37/97 67/38/98 68/35/99 -f 68/35/100 66/36/101 65/37/102 -f 67/38/103 69/40/104 70/39/105 -f 70/39/106 68/35/107 67/38/108 -f 69/40/109 71/42/110 72/41/111 -f 72/41/112 70/39/113 69/40/114 -f 71/45/115 73/46/116 74/43/117 -f 74/43/118 72/44/119 71/45/120 -f 73/46/121 75/48/122 76/47/123 -f 76/47/124 74/43/125 73/46/126 -f 75/48/127 77/50/128 78/49/129 -f 78/49/130 76/47/131 75/48/132 -f 77/50/133 79/52/134 80/51/135 -f 80/51/136 78/49/137 77/50/138 -f 79/52/139 81/54/140 82/53/141 -f 82/53/142 80/51/143 79/52/144 -f 81/54/145 83/56/146 84/55/147 -f 84/55/148 82/53/149 81/54/150 -f 83/56/151 85/58/152 86/57/153 -f 86/57/154 84/55/155 83/56/156 -f 85/58/157 87/60/158 88/59/159 -f 88/59/160 86/57/161 85/58/162 -f 87/60/163 89/62/164 90/61/165 -f 90/61/166 88/59/167 87/60/168 -f 89/62/169 91/64/170 92/63/171 -f 92/63/172 90/61/173 89/62/174 -f 91/64/175 93/66/176 94/65/177 -f 94/65/178 92/63/179 91/64/180 -f 93/66/181 95/68/182 96/67/183 -f 96/67/184 94/65/185 93/66/186 -f 95/68/187 65/37/188 66/36/189 -f 66/36/190 96/67/191 95/68/192 -f 50/71/193 49/72/194 33/69/195 -f 33/69/196 34/70/197 50/71/198 -f 51/74/199 50/71/200 34/70/201 -f 34/70/202 35/73/203 51/74/204 -f 52/76/205 51/74/206 35/73/207 -f 35/73/208 36/75/209 52/76/210 -f 53/79/211 52/80/212 36/77/213 -f 36/77/214 37/78/215 53/79/216 -f 54/82/217 53/79/218 37/78/219 -f 37/78/220 38/81/221 54/82/222 -f 55/84/223 54/82/224 38/81/225 -f 38/81/226 39/83/227 55/84/228 -f 56/86/229 55/84/230 39/83/231 -f 39/83/232 40/85/233 56/86/234 -f 57/88/235 56/86/236 40/85/237 -f 40/85/238 41/87/239 57/88/240 -f 58/90/241 57/88/242 41/87/243 -f 41/87/244 42/89/245 58/90/246 -f 59/92/247 58/90/248 42/89/249 -f 42/89/250 43/91/251 59/92/252 -f 60/94/253 59/92/254 43/91/255 -f 43/91/256 44/93/257 60/94/258 -f 61/96/259 60/94/260 44/93/261 -f 44/93/262 45/95/263 61/96/264 -f 62/98/265 61/96/266 45/95/267 -f 45/95/268 46/97/269 62/98/270 -f 63/100/271 62/98/272 46/97/273 -f 46/97/274 47/99/275 63/100/276 -f 64/102/277 63/100/278 47/99/279 -f 47/99/280 48/101/281 64/102/282 -f 49/72/283 64/102/284 48/101/285 -f 48/101/286 33/69/287 49/72/288 -f 66/36/289 68/35/290 34/70/291 -f 34/70/292 33/69/293 66/36/294 -f 67/38/295 65/37/296 17/4/297 -f 17/4/298 18/3/299 67/38/300 -f 68/35/301 70/39/302 35/73/303 -f 35/73/304 34/70/305 68/35/306 -f 69/40/307 67/38/308 18/3/309 -f 18/3/310 19/6/311 69/40/312 -f 70/39/313 72/41/314 36/75/315 -f 36/75/316 35/73/317 70/39/318 -f 71/42/319 69/40/320 19/6/321 -f 19/6/322 20/8/323 71/42/324 -f 72/44/325 74/43/326 37/78/327 -f 37/78/328 36/77/329 72/44/330 -f 73/46/331 71/45/332 20/12/333 -f 20/12/334 21/11/335 73/46/336 -f 74/43/337 76/47/338 38/81/339 -f 38/81/340 37/78/341 74/43/342 -f 75/48/343 73/46/344 21/11/345 -f 21/11/346 22/14/347 75/48/348 -f 76/47/349 78/49/350 39/83/351 -f 39/83/352 38/81/353 76/47/354 -f 77/50/355 75/48/356 22/14/357 -f 22/14/358 23/16/359 77/50/360 -f 78/49/361 80/51/362 40/85/363 -f 40/85/364 39/83/365 78/49/366 -f 79/52/367 77/50/368 23/16/369 -f 23/16/370 24/18/371 79/52/372 -f 80/51/373 82/53/374 41/87/375 -f 41/87/376 40/85/377 80/51/378 -f 81/54/379 79/52/380 24/18/381 -f 24/18/382 25/20/383 81/54/384 -f 82/53/385 84/55/386 42/89/387 -f 42/89/388 41/87/389 82/53/390 -f 83/56/391 81/54/392 25/20/393 -f 25/20/394 26/22/395 83/56/396 -f 84/55/397 86/57/398 43/91/399 -f 43/91/400 42/89/401 84/55/402 -f 85/58/403 83/56/404 26/22/405 -f 26/22/406 27/24/407 85/58/408 -f 86/57/409 88/59/410 44/93/411 -f 44/93/412 43/91/413 86/57/414 -f 87/60/415 85/58/416 27/24/417 -f 27/24/418 28/26/419 87/60/420 -f 88/59/421 90/61/422 45/95/423 -f 45/95/424 44/93/425 88/59/426 -f 89/62/427 87/60/428 28/26/429 -f 28/26/430 29/28/431 89/62/432 -f 90/61/433 92/63/434 46/97/435 -f 46/97/436 45/95/437 90/61/438 -f 91/64/439 89/62/440 29/28/441 -f 29/28/442 30/30/443 91/64/444 -f 92/63/445 94/65/446 47/99/447 -f 47/99/448 46/97/449 92/63/450 -f 93/66/451 91/64/452 30/30/453 -f 30/30/454 31/32/455 93/66/456 -f 94/65/457 96/67/458 48/101/459 -f 48/101/460 47/99/461 94/65/462 -f 95/68/463 93/66/464 31/32/465 -f 31/32/466 32/34/467 95/68/468 -f 96/67/469 66/36/470 33/69/471 -f 33/69/472 48/101/473 96/67/474 -f 65/37/475 95/68/476 32/34/477 -f 32/34/478 17/4/479 65/37/480 -f 188/103/481 158/104/482 108/105/483 -f 108/105/484 158/104/485 135/106/486 -f 99/107/487 190/108/488 114/109/489 -f 151/110/490 140/111/491 131/112/492 -f 142/113/493 133/114/494 149/115/495 -f 113/116/496 145/117/497 132/118/498 -f 109/119/499 121/120/500 181/121/501 -f 123/122/502 119/123/503 102/124/504 -f 177/125/505 130/126/506 141/127/507 -f 176/128/508 135/106/509 167/129/510 -f 138/130/511 143/131/512 111/132/513 -f 116/133/514 123/122/515 130/126/516 -f 104/134/517 150/135/518 183/136/519 -f 150/135/520 179/137/521 162/138/522 -f 120/139/523 189/140/524 153/141/525 -f 168/142/526 152/143/527 122/144/528 -f 152/143/529 161/145/530 122/144/531 -f 176/128/532 167/129/533 124/146/534 -f 192/147/535 185/148/536 97/149/537 -f 192/147/538 100/150/539 185/148/540 -f 134/151/541 163/152/542 101/153/543 -f 175/154/544 180/155/545 127/156/546 -f 143/131/547 181/121/548 184/157/549 -f 169/158/550 103/159/551 174/160/552 -f 165/161/553 145/117/554 113/116/555 -f 120/139/556 153/141/557 159/162/558 -f 142/113/559 114/109/560 133/114/561 -f 115/163/562 128/164/563 172/165/564 -f 115/163/565 172/165/566 117/166/567 -f 107/167/568 125/168/569 166/169/570 -f 177/125/571 116/133/572 130/126/573 -f 125/168/574 117/166/575 166/169/576 -f 166/169/577 182/170/578 157/171/579 -f 104/134/580 183/136/581 118/172/582 -f 131/112/583 155/173/584 106/174/585 -f 100/150/586 121/120/587 109/119/588 -f 162/138/589 189/140/590 120/139/591 -f 175/154/592 106/174/593 180/155/594 -f 121/120/595 136/175/596 181/121/597 -f 122/144/598 128/164/599 170/176/600 -f 103/159/601 123/122/602 116/133/603 -f 181/121/604 136/175/605 123/122/606 -f 99/107/607 186/177/608 190/108/609 -f 122/144/610 144/178/611 128/164/612 -f 115/163/613 117/166/614 125/168/615 -f 129/179/616 126/180/617 191/181/618 -f 109/119/619 181/121/620 143/131/621 -f 127/156/622 112/182/623 137/183/624 -f 159/162/625 153/141/626 112/182/627 -f 128/164/628 144/178/629 164/184/630 -f 128/164/631 164/184/632 172/165/633 -f 129/179/634 173/185/635 126/180/636 -f 188/103/637 185/148/638 158/104/639 -f 123/122/640 102/124/641 130/126/642 -f 141/127/643 130/126/644 156/186/645 -f 186/177/646 175/154/647 190/108/648 -f 175/154/649 127/156/650 137/183/651 -f 130/126/652 102/124/653 156/186/654 -f 110/187/655 133/114/656 114/109/657 -f 133/114/658 134/151/659 149/115/660 -f 97/149/661 185/148/662 188/103/663 -f 147/188/664 152/143/665 168/142/666 -f 190/108/667 175/154/668 137/183/669 -f 133/114/670 110/187/671 178/189/672 -f 135/106/673 154/190/674 167/129/675 -f 138/130/676 171/191/677 104/134/678 -f 136/175/679 119/123/680 123/122/681 -f 139/192/682 119/123/683 136/175/684 -f 137/183/685 112/182/686 134/151/687 -f 133/114/688 178/189/689 134/151/690 -f 138/130/691 104/134/692 135/106/693 -f 191/181/694 126/180/695 138/130/696 -f 112/182/697 163/152/698 134/151/699 -f 112/182/700 98/193/701 165/161/702 -f 139/192/703 136/175/704 121/120/705 -f 100/150/706 139/192/707 121/120/708 -f 131/112/709 140/111/710 155/173/711 -f 154/190/712 118/172/713 167/129/714 -f 141/127/715 156/186/716 98/193/717 -f 153/141/718 98/193/719 112/182/720 -f 166/169/721 117/166/722 182/170/723 -f 117/166/724 160/194/725 182/170/726 -f 126/180/727 143/131/728 138/130/729 -f 173/185/730 143/131/731 126/180/732 -f 144/178/733 146/195/734 164/184/735 -f 161/145/736 176/128/737 124/146/738 -f 98/193/739 145/117/740 165/161/741 -f 98/193/742 132/118/743 145/117/744 -f 161/145/745 124/146/746 144/178/747 -f 124/146/748 140/111/749 146/195/750 -f 97/149/751 152/143/752 147/188/753 -f 177/125/754 148/196/755 116/133/756 -f 103/159/757 116/133/758 174/160/759 -f 134/151/760 101/153/761 149/115/762 -f 169/158/763 179/137/764 150/135/765 -f 138/130/766 111/132/767 171/191/768 -f 140/111/769 151/110/770 146/195/771 -f 146/195/772 151/110/773 164/184/774 -f 152/143/775 97/149/776 188/103/777 -f 188/103/778 108/105/779 152/143/780 -f 105/197/781 141/127/782 153/141/783 -f 141/127/784 98/193/785 153/141/786 -f 135/106/787 104/134/788 154/190/789 -f 154/190/790 104/134/791 118/172/792 -f 122/144/793 161/145/794 144/178/795 -f 155/173/796 118/172/797 106/174/798 -f 167/129/799 118/172/800 155/173/801 -f 98/193/802 156/186/803 132/118/804 -f 142/113/805 149/115/806 157/171/807 -f 129/179/808 191/181/809 158/104/810 -f 158/104/811 185/148/812 129/179/813 -f 120/139/814 159/162/815 127/156/816 -f 127/156/817 159/162/818 112/182/819 -f 160/194/820 114/109/821 142/113/822 -f 99/107/823 114/109/824 160/194/825 -f 108/105/826 161/145/827 152/143/828 -f 176/128/829 108/105/830 135/106/831 -f 118/172/832 162/138/833 106/174/834 -f 106/174/835 162/138/836 120/139/837 -f 165/161/838 113/116/839 163/152/840 -f 164/184/841 186/177/842 99/107/843 -f 164/184/844 99/107/845 172/165/846 -f 112/182/847 165/161/848 163/152/849 -f 167/129/850 155/173/851 140/111/852 -f 124/146/853 167/129/854 140/111/855 -f 100/150/856 109/119/857 185/148/858 -f 109/119/859 143/131/860 173/185/861 -f 189/140/862 105/197/863 153/141/864 -f 170/176/865 125/168/866 107/167/867 -f 172/165/868 99/107/869 160/194/870 -f 172/165/871 160/194/872 117/166/873 -f 171/191/874 111/132/875 169/158/876 -f 184/157/877 103/159/878 169/158/879 -f 187/198/880 168/142/881 122/144/882 -f 147/188/883 168/142/884 187/198/885 -f 171/191/886 150/135/887 104/134/888 -f 171/191/889 169/158/890 150/135/891 -f 109/119/892 173/185/893 185/148/894 -f 185/148/895 173/185/896 129/179/897 -f 169/158/898 174/160/899 179/137/900 -f 148/196/901 174/160/902 116/133/903 -f 131/112/904 175/154/905 186/177/906 -f 131/112/907 106/174/908 175/154/909 -f 161/145/910 108/105/911 176/128/912 -f 105/197/913 177/125/914 141/127/915 -f 177/125/916 105/197/917 189/140/918 -f 178/189/919 137/183/920 134/151/921 -f 110/187/922 137/183/923 178/189/924 -f 179/137/925 174/160/926 148/196/927 -f 179/137/928 148/196/929 162/138/930 -f 180/155/931 120/139/932 127/156/933 -f 106/174/934 120/139/935 180/155/936 -f 103/159/937 181/121/938 123/122/939 -f 184/157/940 181/121/941 103/159/942 -f 182/170/943 142/113/944 157/171/945 -f 160/194/946 142/113/947 182/170/948 -f 183/136/949 150/135/950 162/138/951 -f 118/172/952 183/136/953 162/138/954 -f 111/132/955 184/157/956 169/158/957 -f 143/131/958 184/157/959 111/132/960 -f 164/184/961 151/110/962 186/177/963 -f 151/110/964 131/112/965 186/177/966 -f 149/115/967 101/153/968 163/152/969 -f 163/152/970 113/116/971 149/115/972 -f 187/198/973 122/144/974 170/176/975 -f 189/140/976 162/138/977 148/196/978 -f 189/140/979 148/196/980 177/125/981 -f 190/108/982 137/183/983 110/187/984 -f 190/108/985 110/187/986 114/109/987 -f 191/181/988 138/130/989 135/106/990 -f 158/104/991 191/181/992 135/106/993 -f 125/168/994 170/176/995 128/164/996 -f 128/164/997 115/163/998 125/168/999 -f 124/146/1000 146/195/1001 144/178/1002 -s 2 -f 207/213/1003 205/214/1004 193/199/1005 -f 193/199/1006 195/201/1007 207/213/1008 -f 206/215/1009 208/216/1010 196/207/1011 -f 196/207/1012 194/206/1013 206/215/1014 -f 205/214/1015 215/217/1016 203/200/1017 -f 203/200/1018 193/199/1019 205/214/1020 -f 209/218/1021 207/213/1022 195/201/1023 -f 195/201/1024 197/202/1025 209/218/1026 -f 208/216/1027 210/219/1028 198/208/1029 -f 198/208/1030 196/207/1031 208/216/1032 -f 213/221/1033 201/222/1034 253/211/1035 -f 253/211/1036 255/220/1037 213/221/1038 -f 266/223/1039 267/209/1040 198/208/1041 -f 198/208/1042 210/219/1043 266/223/1044 -f 212/257/1045 216/258/1046 204/212/1047 -f 204/212/1048 200/224/1049 212/257/1050 -f 209/218/1051 197/202/1052 268/203/1053 -f 268/203/1054 269/259/1055 209/218/1056 -f 212/257/1057 200/224/1058 254/205/1059 -f 254/205/1060 256/260/1061 212/257/1062 -f 215/217/1063 206/215/1064 194/206/1065 -f 194/206/1066 203/200/1067 215/217/1068 -f 216/258/1069 211/261/1070 199/210/1071 -f 199/210/1072 204/212/1073 216/258/1074 -f 219/227/1075 217/228/1076 205/225/1077 -f 205/225/1078 207/226/1079 219/227/1080 -f 218/231/1081 220/232/1082 208/229/1083 -f 208/229/1084 206/230/1085 218/231/1086 -f 217/228/1087 226/234/1088 215/233/1089 -f 215/233/1090 205/225/1091 217/228/1092 -f 221/236/1093 219/227/1094 207/226/1095 -f 207/226/1096 209/235/1097 221/236/1098 -f 220/232/1099 222/266/1100 210/265/1101 -f 210/265/1102 208/229/1103 220/232/1104 -f 225/239/1105 213/240/1106 255/237/1107 -f 255/237/1108 257/238/1109 225/239/1110 -f 222/266/1111 265/268/1112 266/267/1113 -f 266/267/1114 210/265/1115 222/266/1116 -f 224/243/1117 227/244/1118 216/241/1119 -f 216/241/1120 212/242/1121 224/243/1122 -f 270/270/1123 221/236/1124 209/235/1125 -f 209/235/1126 269/269/1127 270/270/1128 -f 224/243/1129 212/242/1130 256/246/1131 -f 256/246/1132 258/247/1133 224/243/1134 -f 226/332/1135 218/231/1136 206/230/1137 -f 206/230/1138 215/331/1139 226/332/1140 -f 227/244/1141 223/249/1142 211/248/1143 -f 211/248/1144 216/241/1145 227/244/1146 -f 228/250/1147 229/251/1148 227/244/1149 -f 227/244/1150 224/243/1151 228/250/1152 -f 229/251/1153 232/252/1154 223/249/1155 -f 223/249/1156 227/244/1157 229/251/1158 -f 258/247/1159 259/253/1160 228/250/1161 -f 228/250/1162 224/243/1163 258/247/1164 -f 260/254/1165 264/255/1166 225/239/1167 -f 225/239/1168 257/238/1169 260/254/1170 -f 244/274/1171 217/228/1172 219/227/1173 -f 219/227/1174 246/272/1175 244/274/1176 -f 247/276/1177 220/232/1178 218/231/1179 -f 218/231/1180 245/275/1181 247/276/1182 -f 250/277/1183 226/234/1184 217/228/1185 -f 217/228/1186 244/274/1187 250/277/1188 -f 246/272/1189 219/227/1190 221/236/1191 -f 221/236/1192 248/278/1193 246/272/1194 -f 249/279/1195 222/266/1196 220/232/1197 -f 220/232/1198 247/276/1199 249/279/1200 -f 245/275/1201 218/231/1202 226/332/1203 -f 226/332/1204 250/333/1205 245/275/1206 -f 231/282/1207 265/268/1208 222/266/1209 -f 222/266/1210 249/279/1211 231/282/1212 -f 252/286/1213 238/287/1214 279/284/1215 -f 279/284/1216 273/285/1217 252/286/1218 -f 273/285/1219 271/290/1220 242/288/1221 -f 242/288/1222 252/286/1223 273/285/1224 -f 291/294/1225 241/295/1226 289/245/1227 -f 289/245/1228 290/283/1229 291/294/1230 -f 241/295/1231 281/297/1232 288/296/1233 -f 288/296/1234 289/245/1235 241/295/1236 -f 283/299/1237 241/295/1238 291/294/1239 -f 291/294/1240 282/298/1241 283/299/1242 -f 281/297/1243 241/295/1244 283/299/1245 -f 283/299/1246 284/300/1247 281/297/1248 -f 263/262/1249 264/255/1250 260/254/1251 -f 260/254/1252 261/256/1253 263/262/1254 -f 261/256/1255 229/251/1256 228/250/1257 -f 228/250/1258 259/253/1259 261/256/1260 -f 275/306/1261 244/274/1262 246/272/1263 -f 246/272/1264 277/291/1265 275/306/1266 -f 247/276/1267 245/275/1268 276/307/1269 -f 276/307/1270 278/308/1271 247/276/1272 -f 280/309/1273 250/277/1274 244/274/1275 -f 244/274/1276 275/306/1277 280/309/1278 -f 246/272/1279 248/278/1280 279/284/1281 -f 279/284/1282 277/291/1283 246/272/1284 -f 274/310/1285 249/279/1286 247/276/1287 -f 247/276/1288 278/308/1289 274/310/1290 -f 245/275/1291 250/333/1292 280/334/1293 -f 280/334/1294 276/307/1295 245/275/1296 -f 233/311/1297 248/278/1298 221/236/1299 -f 221/236/1300 270/270/1301 233/311/1302 -f 272/312/1303 231/282/1304 249/279/1305 -f 249/279/1306 274/310/1307 272/312/1308 -f 272/312/1309 251/313/1310 242/288/1311 -f 242/288/1312 271/290/1313 272/312/1314 -f 255/220/1315 253/211/1316 199/210/1317 -f 199/210/1318 211/261/1319 255/220/1320 -f 256/260/1321 254/205/1322 202/204/1323 -f 202/204/1324 214/271/1325 256/260/1326 -f 257/238/1327 255/237/1328 211/248/1329 -f 211/248/1330 223/249/1331 257/238/1332 -f 258/247/1333 256/246/1334 214/263/1335 -f 214/263/1336 230/264/1337 258/247/1338 -f 259/253/1339 258/247/1340 230/264/1341 -f 230/264/1342 262/273/1343 259/253/1344 -f 232/252/1345 260/254/1346 257/238/1347 -f 257/238/1348 223/249/1349 232/252/1350 -f 261/256/1351 260/254/1352 232/252/1353 -f 232/252/1354 229/251/1355 261/256/1356 -f 263/262/1357 261/256/1358 259/253/1359 -f 259/253/1360 262/273/1361 263/262/1362 -f 231/281/1363 262/273/1364 230/264/1365 -f 230/264/1366 265/280/1367 231/281/1368 -f 243/289/1369 263/262/1370 262/273/1371 -f 262/273/1372 231/281/1373 243/289/1374 -f 264/255/1375 263/262/1376 243/289/1377 -f 243/289/1378 233/292/1379 264/255/1380 -f 270/293/1381 225/239/1382 264/255/1383 -f 264/255/1384 233/292/1385 270/293/1386 -f 266/304/1387 265/280/1388 230/264/1389 -f 230/264/1390 214/263/1391 266/304/1392 -f 267/209/1393 266/223/1394 214/271/1395 -f 214/271/1396 202/204/1397 267/209/1398 -f 269/259/1399 268/203/1400 201/222/1401 -f 201/222/1402 213/221/1403 269/259/1404 -f 225/239/1405 270/293/1406 269/305/1407 -f 269/305/1408 213/240/1409 225/239/1410 -f 243/314/1411 271/290/1412 273/285/1413 -f 273/285/1414 233/311/1415 243/314/1416 -f 231/282/1417 272/312/1418 271/290/1419 -f 271/290/1420 243/314/1421 231/282/1422 -f 234/316/1423 275/306/1424 277/291/1425 -f 277/291/1426 236/315/1427 234/316/1428 -f 278/308/1429 276/307/1430 235/317/1431 -f 235/317/1432 237/318/1433 278/308/1434 -f 240/319/1435 280/309/1436 275/306/1437 -f 275/306/1438 234/316/1439 240/319/1440 -f 277/291/1441 279/284/1442 238/287/1443 -f 238/287/1444 236/315/1445 277/291/1446 -f 239/320/1447 274/310/1448 278/308/1449 -f 278/308/1450 237/318/1451 239/320/1452 -f 276/307/1453 280/334/1454 240/335/1455 -f 240/335/1456 235/317/1457 276/307/1458 -f 251/313/1459 272/312/1460 274/310/1461 -f 274/310/1462 239/320/1463 251/313/1464 -f 273/285/1465 279/284/1466 248/278/1467 -f 248/278/1468 233/311/1469 273/285/1470 -f 281/297/1471 284/300/1472 285/301/1473 -f 285/301/1474 286/302/1475 281/297/1476 -f 287/303/1477 288/296/1478 281/297/1479 -f 281/297/1480 286/302/1481 287/303/1482 -f 283/321/1483 282/322/1484 234/316/1485 -f 234/316/1486 236/315/1487 283/321/1488 -f 284/323/1489 283/321/1490 236/315/1491 -f 236/315/1492 238/287/1493 284/323/1494 -f 285/324/1495 284/323/1496 238/287/1497 -f 238/287/1498 252/286/1499 285/324/1500 -f 286/325/1501 285/324/1502 252/286/1503 -f 252/286/1504 242/288/1505 286/325/1506 -f 287/326/1507 286/325/1508 242/288/1509 -f 242/288/1510 251/313/1511 287/326/1512 -f 288/327/1513 287/326/1514 251/313/1515 -f 251/313/1516 239/320/1517 288/327/1518 -f 289/328/1519 288/327/1520 239/320/1521 -f 239/320/1522 237/318/1523 289/328/1524 -f 290/329/1525 289/328/1526 237/318/1527 -f 237/318/1528 235/317/1529 290/329/1530 -f 291/330/1531 290/329/1532 235/317/1533 -f 235/317/1534 240/335/1535 291/330/1536 -f 282/322/1537 291/336/1538 240/319/1539 -f 240/319/1540 234/316/1541 282/322/1542 -s 1 -f 294/337/1543 292/339/1544 304/351/1545 -f 304/351/1546 306/352/1547 294/337/1548 -f 293/345/1549 295/344/1550 307/353/1551 -f 307/353/1552 305/354/1553 293/345/1554 -f 292/339/1555 302/338/1556 314/355/1557 -f 314/355/1558 304/351/1559 292/339/1560 -f 296/340/1561 294/337/1562 306/352/1563 -f 306/352/1564 308/356/1565 296/340/1566 -f 295/344/1567 297/346/1568 309/357/1569 -f 309/357/1570 307/353/1571 295/344/1572 -f 354/360/1573 352/349/1574 300/358/1575 -f 300/358/1576 312/359/1577 354/360/1578 -f 309/357/1579 297/346/1580 366/347/1581 -f 366/347/1582 365/361/1583 309/357/1584 -f 299/396/1585 303/348/1586 315/362/1587 -f 315/362/1588 311/395/1589 299/396/1590 -f 368/397/1591 367/341/1592 296/340/1593 -f 296/340/1594 308/356/1595 368/397/1596 -f 355/398/1597 353/342/1598 299/396/1599 -f 299/396/1600 311/395/1601 355/398/1602 -f 302/338/1603 293/345/1604 305/354/1605 -f 305/354/1606 314/355/1607 302/338/1608 -f 303/348/1609 298/350/1610 310/399/1611 -f 310/399/1612 315/362/1613 303/348/1614 -f 306/365/1615 304/366/1616 316/363/1617 -f 316/363/1618 318/364/1619 306/365/1620 -f 305/369/1621 307/370/1622 319/367/1623 -f 319/367/1624 317/368/1625 305/369/1626 -f 304/366/1627 314/372/1628 325/371/1629 -f 325/371/1630 316/363/1631 304/366/1632 -f 308/374/1633 306/365/1634 318/364/1635 -f 318/364/1636 320/373/1637 308/374/1638 -f 307/370/1639 309/404/1640 321/403/1641 -f 321/403/1642 319/367/1643 307/370/1644 -f 356/377/1645 354/378/1646 312/375/1647 -f 312/375/1648 324/376/1649 356/377/1650 -f 309/404/1651 365/406/1652 364/405/1653 -f 364/405/1654 321/403/1655 309/404/1656 -f 311/381/1657 315/382/1658 326/379/1659 -f 326/379/1660 323/380/1661 311/381/1662 -f 368/408/1663 308/374/1664 320/373/1665 -f 320/373/1666 369/407/1667 368/408/1668 -f 357/384/1669 355/385/1670 311/381/1671 -f 311/381/1672 323/380/1673 357/384/1674 -f 314/470/1675 305/369/1676 317/368/1677 -f 317/368/1678 325/469/1679 314/470/1680 -f 315/382/1681 310/387/1682 322/386/1683 -f 322/386/1684 326/379/1685 315/382/1686 -f 323/380/1687 326/379/1688 328/388/1689 -f 328/388/1690 327/389/1691 323/380/1692 -f 326/379/1693 322/386/1694 331/390/1695 -f 331/390/1696 328/388/1697 326/379/1698 -f 323/380/1699 327/389/1700 358/391/1701 -f 358/391/1702 357/384/1703 323/380/1704 -f 356/377/1705 324/376/1706 363/392/1707 -f 363/392/1708 359/393/1709 356/377/1710 -f 345/412/1711 318/364/1712 316/363/1713 -f 316/363/1714 343/410/1715 345/412/1716 -f 344/414/1717 317/368/1718 319/367/1719 -f 319/367/1720 346/413/1721 344/414/1722 -f 343/410/1723 316/363/1724 325/371/1725 -f 325/371/1726 349/415/1727 343/410/1728 -f 347/416/1729 320/373/1730 318/364/1731 -f 318/364/1732 345/412/1733 347/416/1734 -f 346/413/1735 319/367/1736 321/403/1737 -f 321/403/1738 348/417/1739 346/413/1740 -f 349/471/1741 325/469/1742 317/368/1743 -f 317/368/1744 344/414/1745 349/471/1746 -f 348/417/1747 321/403/1748 364/405/1749 -f 364/405/1750 330/420/1751 348/417/1752 -f 372/424/1753 378/425/1754 337/422/1755 -f 337/422/1756 351/423/1757 372/424/1758 -f 351/423/1759 341/428/1760 370/426/1761 -f 370/426/1762 372/424/1763 351/423/1764 -f 389/432/1765 388/433/1766 340/383/1767 -f 340/383/1768 390/421/1769 389/432/1770 -f 388/433/1771 387/435/1772 380/434/1773 -f 380/434/1774 340/383/1775 388/433/1776 -f 381/437/1777 390/421/1778 340/383/1779 -f 340/383/1780 382/436/1781 381/437/1782 -f 383/438/1783 382/436/1784 340/383/1785 -f 340/383/1786 380/434/1787 383/438/1788 -f 360/400/1789 359/393/1790 363/392/1791 -f 363/392/1792 362/394/1793 360/400/1794 -f 358/391/1795 327/389/1796 328/388/1797 -f 328/388/1798 360/400/1799 358/391/1800 -f 376/444/1801 345/412/1802 343/410/1803 -f 343/410/1804 374/429/1805 376/444/1806 -f 377/445/1807 375/446/1808 344/414/1809 -f 344/414/1810 346/413/1811 377/445/1812 -f 374/429/1813 343/410/1814 349/415/1815 -f 349/415/1816 379/447/1817 374/429/1818 -f 376/444/1819 378/425/1820 347/416/1821 -f 347/416/1822 345/412/1823 376/444/1824 -f 377/445/1825 346/413/1826 348/417/1827 -f 348/417/1828 373/448/1829 377/445/1830 -f 375/446/1831 379/472/1832 349/471/1833 -f 349/471/1834 344/414/1835 375/446/1836 -f 369/407/1837 320/373/1838 347/416/1839 -f 347/416/1840 332/449/1841 369/407/1842 -f 373/448/1843 348/417/1844 330/420/1845 -f 330/420/1846 371/450/1847 373/448/1848 -f 370/426/1849 341/428/1850 350/451/1851 -f 350/451/1852 371/450/1853 370/426/1854 -f 310/399/1855 298/350/1856 352/349/1857 -f 352/349/1858 354/360/1859 310/399/1860 -f 313/409/1861 301/343/1862 353/342/1863 -f 353/342/1864 355/398/1865 313/409/1866 -f 322/386/1867 310/387/1868 354/378/1869 -f 354/378/1870 356/377/1871 322/386/1872 -f 329/401/1873 313/402/1874 355/385/1875 -f 355/385/1876 357/384/1877 329/401/1878 -f 361/411/1879 329/401/1880 357/384/1881 -f 357/384/1882 358/391/1883 361/411/1884 -f 322/386/1885 356/377/1886 359/393/1887 -f 359/393/1888 331/390/1889 322/386/1890 -f 328/388/1891 331/390/1892 359/393/1893 -f 359/393/1894 360/400/1895 328/388/1896 -f 361/411/1897 358/391/1898 360/400/1899 -f 360/400/1900 362/394/1901 361/411/1902 -f 364/419/1903 329/401/1904 361/411/1905 -f 361/411/1906 330/418/1907 364/419/1908 -f 330/418/1909 361/411/1910 362/394/1911 -f 362/394/1912 342/427/1913 330/418/1914 -f 332/430/1915 342/427/1916 362/394/1917 -f 362/394/1918 363/392/1919 332/430/1920 -f 332/430/1921 363/392/1922 324/376/1923 -f 324/376/1924 369/431/1925 332/430/1926 -f 313/402/1927 329/401/1928 364/419/1929 -f 364/419/1930 365/442/1931 313/402/1932 -f 301/343/1933 313/409/1934 365/361/1935 -f 365/361/1936 366/347/1937 301/343/1938 -f 312/359/1939 300/358/1940 367/341/1941 -f 367/341/1942 368/397/1943 312/359/1944 -f 312/375/1945 368/443/1946 369/431/1947 -f 369/431/1948 324/376/1949 312/375/1950 -f 332/449/1951 372/424/1952 370/426/1953 -f 370/426/1954 342/452/1955 332/449/1956 -f 342/452/1957 370/426/1958 371/450/1959 -f 371/450/1960 330/420/1961 342/452/1962 -f 335/454/1963 376/444/1964 374/429/1965 -f 374/429/1966 333/453/1967 335/454/1968 -f 336/455/1969 334/456/1970 375/446/1971 -f 375/446/1972 377/445/1973 336/455/1974 -f 333/453/1975 374/429/1976 379/447/1977 -f 379/447/1978 339/457/1979 333/453/1980 -f 335/454/1981 337/422/1982 378/425/1983 -f 378/425/1984 376/444/1985 335/454/1986 -f 336/455/1987 377/445/1988 373/448/1989 -f 373/448/1990 338/458/1991 336/455/1992 -f 334/456/1993 339/473/1994 379/472/1995 -f 379/472/1996 375/446/1997 334/456/1998 -f 338/458/1999 373/448/2000 371/450/2001 -f 371/450/2002 350/451/2003 338/458/2004 -f 332/449/2005 347/416/2006 378/425/2007 -f 378/425/2008 372/424/2009 332/449/2010 -f 385/439/2011 384/440/2012 383/438/2013 -f 383/438/2014 380/434/2015 385/439/2016 -f 385/439/2017 380/434/2018 387/435/2019 -f 387/435/2020 386/441/2021 385/439/2022 -f 335/454/2023 333/453/2024 381/459/2025 -f 381/459/2026 382/460/2027 335/454/2028 -f 337/422/2029 335/454/2030 382/460/2031 -f 382/460/2032 383/461/2033 337/422/2034 -f 351/423/2035 337/422/2036 383/461/2037 -f 383/461/2038 384/462/2039 351/423/2040 -f 341/428/2041 351/423/2042 384/462/2043 -f 384/462/2044 385/463/2045 341/428/2046 -f 350/451/2047 341/428/2048 385/463/2049 -f 385/463/2050 386/464/2051 350/451/2052 -f 338/458/2053 350/451/2054 386/464/2055 -f 386/464/2056 387/465/2057 338/458/2058 -f 336/455/2059 338/458/2060 387/465/2061 -f 387/465/2062 388/466/2063 336/455/2064 -f 334/456/2065 336/455/2066 388/466/2067 -f 388/466/2068 389/467/2069 334/456/2070 -f 339/473/2071 334/456/2072 389/467/2073 -f 389/467/2074 390/468/2075 339/473/2076 -f 333/453/2077 339/457/2078 390/474/2079 -f 390/474/2080 381/459/2081 333/453/2082 -f 396/480/2083 398/481/2084 397/475/2085 -f 397/475/2086 1269/478/2087 396/480/2088 -f 396/480/2089 400/483/2090 399/482/2091 -f 399/482/2092 398/481/2093 396/480/2094 -f 401/487/2095 404/488/2096 403/485/2097 -f 403/485/2098 402/486/2099 401/487/2100 -f 405/490/2101 401/487/2102 402/486/2103 -f 402/486/2104 406/489/2105 405/490/2106 -f 401/487/2107 405/490/2108 407/491/2109 -f 407/491/2110 404/488/2111 401/487/2112 -f 408/494/2113 411/495/2114 410/492/2115 -f 410/492/2116 409/493/2117 408/494/2118 -f 408/494/2119 413/497/2120 412/496/2121 -f 412/496/2122 411/495/2123 408/494/2124 -f 408/494/2125 415/499/2126 414/498/2127 -f 414/498/2128 413/497/2129 408/494/2130 -f 408/494/2131 417/501/2132 416/500/2133 -f 416/500/2134 415/499/2135 408/494/2136 -f 408/494/2137 409/493/2138 418/502/2139 -f 418/502/2140 417/501/2141 408/494/2142 -f 419/505/2143 422/506/2144 421/503/2145 -f 421/503/2146 420/504/2147 419/505/2148 -f 419/505/2149 420/504/2150 424/507/2151 -f 424/507/2152 423/508/2153 419/505/2154 -f 425/511/2155 428/512/2156 427/509/2157 -f 427/509/2158 426/510/2159 425/511/2160 -f 429/514/2161 425/511/2162 426/510/2163 -f 426/510/2164 430/513/2165 429/514/2166 -f 425/515/2167 429/528/2168 431/476/2169 -f 431/476/2170 428/477/2171 425/515/2172 -f 432/517/2173 435/518/2174 434/484/2175 -f 434/484/2176 433/516/2177 432/517/2178 -f 432/517/2179 433/516/2180 437/519/2181 -f 437/519/2182 436/520/2183 432/517/2184 -f 432/517/2185 438/521/2186 400/483/2187 -f 400/483/2188 435/518/2189 432/517/2190 -f 435/518/2191 440/523/2192 439/522/2193 -f 439/522/2194 434/484/2195 435/518/2196 -f 443/526/2197 442/527/2198 441/524/2199 -f 441/524/2200 444/525/2201 443/526/2202 -f 442/527/2203 443/526/2204 434/484/2205 -f 434/484/2206 439/522/2207 442/527/2208 -f 442/527/2209 439/522/2210 445/529/2211 -f 445/529/2212 441/524/2213 442/527/2214 -f 446/532/2215 449/533/2216 448/530/2217 -f 448/530/2218 447/531/2219 446/532/2220 -f 451/534/2221 450/535/2222 449/533/2223 -f 449/533/2224 446/532/2225 451/534/2226 -f 433/516/2227 434/484/2228 443/526/2229 -f 443/526/2230 437/519/2231 433/516/2232 -f 452/538/2233 455/539/2234 454/536/2235 -f 454/536/2236 453/537/2237 452/538/2238 -f 452/538/2239 458/557/2240 457/542/2241 -f 457/542/2242 456/543/2243 452/538/2244 -f 452/538/2245 453/537/2246 459/644/2247 -f 459/644/2248 458/557/2249 452/538/2250 -f 460/544/2251 462/545/2252 457/540/2253 -f 457/540/2254 461/541/2255 460/544/2256 -f 460/544/2257 406/489/2258 402/486/2259 -f 402/486/2260 403/485/2261 460/544/2262 -f 460/544/2263 461/541/2264 463/546/2265 -f 463/546/2266 406/489/2267 460/544/2268 -f 417/501/2269 418/502/2270 464/547/2271 -f 464/547/2272 416/500/2273 417/501/2274 -f 462/545/2275 465/549/2276 456/548/2277 -f 456/548/2278 457/540/2279 462/545/2280 -f 462/545/2281 460/544/2282 466/550/2283 -f 466/550/2284 465/549/2285 462/545/2286 -f 1342/688/2287 423/508/2288 467/551/2289 -f 467/551/2290 1341/687/2291 1342/688/2292 -f 468/627/2293 471/629/2294 470/552/2295 -f 470/552/2296 469/553/2297 468/627/2298 -f 468/647/2299 473/648/2300 472/645/2301 -f 472/645/2302 471/646/2303 468/647/2304 -f 471/556/2305 475/558/2306 474/554/2307 -f 474/554/2308 470/555/2309 471/556/2310 -f 471/556/2311 472/560/2312 476/559/2313 -f 476/559/2314 475/558/2315 471/556/2316 -f 476/559/2317 478/562/2318 477/561/2319 -f 477/561/2320 475/558/2321 476/559/2322 -f 476/559/2323 465/549/2324 466/550/2325 -f 466/550/2326 478/562/2327 476/559/2328 -f 476/559/2329 472/560/2330 456/548/2331 -f 456/548/2332 465/549/2333 476/559/2334 -f 478/562/2335 480/564/2336 479/563/2337 -f 479/563/2338 477/561/2339 478/562/2340 -f 478/562/2341 466/550/2342 481/565/2343 -f 481/565/2344 480/564/2345 478/562/2346 -f 481/565/2347 483/567/2348 482/566/2349 -f 482/566/2350 480/564/2351 481/565/2352 -f 481/565/2353 403/485/2354 404/488/2355 -f 404/488/2356 483/567/2357 481/565/2358 -f 481/565/2359 466/550/2360 460/544/2361 -f 460/544/2362 403/485/2363 481/565/2364 -f 483/567/2365 485/569/2366 484/568/2367 -f 484/568/2368 482/566/2369 483/567/2370 -f 483/567/2371 404/488/2372 486/570/2373 -f 486/570/2374 485/569/2375 483/567/2376 -f 486/570/2377 488/572/2378 487/571/2379 -f 487/571/2380 485/569/2381 486/570/2382 -f 486/570/2383 490/574/2384 489/573/2385 -f 489/573/2386 488/572/2387 486/570/2388 -f 486/570/2389 404/488/2390 407/491/2391 -f 407/491/2392 490/574/2393 486/570/2394 -f 490/574/2395 464/547/2396 491/575/2397 -f 491/575/2398 489/573/2399 490/574/2400 -f 490/574/2401 407/491/2402 416/500/2403 -f 416/500/2404 464/547/2405 490/574/2406 -f 489/573/2407 493/577/2408 492/576/2409 -f 492/576/2410 488/572/2411 489/573/2412 -f 489/573/2413 491/575/2414 494/578/2415 -f 494/578/2416 493/577/2417 489/573/2418 -f 493/577/2419 496/580/2420 495/579/2421 -f 495/579/2422 492/576/2423 493/577/2424 -f 493/577/2425 494/578/2426 497/581/2427 -f 497/581/2428 496/580/2429 493/577/2430 -f 497/581/2431 494/578/2432 499/582/2433 -f 499/582/2434 498/583/2435 497/581/2436 -f 498/2584/2437 499/2583/2438 501/584/2439 -f 501/584/2440 500/585/2441 498/2584/2442 -f 501/584/2443 499/2583/2444 503/586/2445 -f 503/586/2446 502/587/2447 501/584/2448 -f 501/584/2449 505/589/2450 504/588/2451 -f 504/588/2452 500/585/2453 501/584/2454 -f 501/584/2455 502/587/2456 506/590/2457 -f 506/590/2458 505/589/2459 501/584/2460 -f 504/588/2461 505/589/2462 508/591/2463 -f 508/591/2464 507/592/2465 504/588/2466 -f 507/592/2467 508/591/2468 510/593/2469 -f 510/593/2470 509/594/2471 507/592/2472 -f 510/593/2473 508/591/2474 512/595/2475 -f 512/595/2476 511/596/2477 510/593/2478 -f 510/593/2479 514/598/2480 513/597/2481 -f 513/597/2482 509/594/2483 510/593/2484 -f 510/593/2485 511/596/2486 515/599/2487 -f 515/599/2488 514/598/2489 510/593/2490 -f 515/599/2491 511/596/2492 517/600/2493 -f 517/600/2494 516/601/2495 515/599/2496 -f 515/599/2497 519/603/2498 518/602/2499 -f 518/602/2500 514/598/2501 515/599/2502 -f 515/599/2503 516/601/2504 520/604/2505 -f 520/604/2506 519/603/2507 515/599/2508 -f 520/604/2509 516/601/2510 522/605/2511 -f 522/605/2512 521/606/2513 520/604/2514 -f 520/604/2515 484/568/2516 523/607/2517 -f 523/607/2518 519/603/2519 520/604/2520 -f 520/604/2521 521/606/2522 482/566/2523 -f 482/566/2524 484/568/2525 520/604/2526 -f 523/607/2527 524/608/2528 518/602/2529 -f 518/602/2530 519/603/2531 523/607/2532 -f 523/607/2533 487/571/2534 525/609/2535 -f 525/609/2536 524/608/2537 523/607/2538 -f 523/607/2539 484/568/2540 485/569/2541 -f 485/569/2542 487/571/2543 523/607/2544 -f 525/609/2545 527/611/2546 526/610/2547 -f 526/610/2548 524/608/2549 525/609/2550 -f 525/609/2551 492/576/2552 495/579/2553 -f 495/579/2554 527/611/2555 525/609/2556 -f 525/609/2557 487/571/2558 488/572/2559 -f 488/572/2560 492/576/2561 525/609/2562 -f 528/612/2563 513/597/2564 514/598/2565 -f 514/598/2566 518/602/2567 528/612/2568 -f 528/612/2569 518/602/2570 524/608/2571 -f 524/608/2572 526/610/2573 528/612/2574 -f 522/605/2575 531/615/2576 530/613/2577 -f 530/613/2578 529/614/2579 522/605/2580 -f 522/605/2581 516/601/2582 517/600/2583 -f 517/600/2584 531/615/2585 522/605/2586 -f 522/605/2587 529/614/2588 479/563/2589 -f 479/563/2590 521/606/2591 522/605/2592 -f 531/615/2593 533/617/2594 532/616/2595 -f 532/616/2596 530/613/2597 531/615/2598 -f 531/615/2599 517/600/2600 534/618/2601 -f 534/618/2602 533/617/2603 531/615/2604 -f 534/618/2605 536/620/2606 535/619/2607 -f 535/619/2608 533/617/2609 534/618/2610 -f 534/618/2611 512/595/2612 537/621/2613 -f 537/621/2614 536/620/2615 534/618/2616 -f 534/618/2617 517/600/2618 511/596/2619 -f 511/596/2620 512/595/2621 534/618/2622 -f 535/619/2623 538/622/2624 426/510/2625 -f 426/510/2626 427/509/2627 535/619/2628 -f 535/619/2629 536/620/2630 506/590/2631 -f 506/590/2632 538/622/2633 535/619/2634 -f 535/619/2635 427/509/2636 532/616/2637 -f 532/616/2638 533/617/2639 535/619/2640 -f 538/622/2641 539/623/2642 430/513/2643 -f 430/513/2644 426/510/2645 538/622/2646 -f 538/622/2647 506/590/2648 502/587/2649 -f 502/587/2650 539/623/2651 538/622/2652 -f 539/623/2653 410/2580/2654 411/2581/2655 -f 411/2581/2656 430/513/2657 539/623/2658 -f 539/623/2659 502/587/2660 503/586/2661 -f 503/586/2662 410/2580/2663 539/623/2664 -f 532/616/2665 427/509/2666 428/512/2667 -f 428/512/2668 540/624/2669 532/616/2670 -f 532/616/2671 540/624/2672 541/625/2673 -f 541/625/2674 530/613/2675 532/616/2676 -f 541/632/2677 540/633/2678 543/630/2679 -f 543/630/2680 542/631/2681 541/632/2682 -f 541/625/2683 544/626/2684 529/614/2685 -f 529/614/2686 530/613/2687 541/625/2688 -f 541/625/2689 542/628/2690 474/554/2691 -f 474/554/2692 544/626/2693 541/625/2694 -f 544/626/2695 477/561/2696 479/563/2697 -f 479/563/2698 529/614/2699 544/626/2700 -f 544/626/2701 474/554/2702 475/558/2703 -f 475/558/2704 477/561/2705 544/626/2706 -f 543/630/2707 547/636/2708 546/634/2709 -f 546/634/2710 545/635/2711 543/630/2712 -f 543/630/2713 540/633/2714 428/477/2715 -f 428/477/2716 547/636/2717 543/630/2718 -f 543/630/2719 545/635/2720 548/637/2721 -f 548/637/2722 542/631/2723 543/630/2724 -f 547/636/2725 550/639/2726 549/638/2727 -f 549/638/2728 546/634/2729 547/636/2730 -f 547/636/2731 428/477/2732 431/476/2733 -f 431/476/2734 550/639/2735 547/636/2736 -f 550/639/2737 552/641/2738 551/640/2739 -f 551/640/2740 549/638/2741 550/639/2742 -f 550/639/2743 431/476/2744 553/642/2745 -f 553/642/2746 552/641/2747 550/639/2748 -f 553/642/2749 555/668/2750 554/643/2751 -f 554/643/2752 552/641/2753 553/642/2754 -f 553/642/2755 557/670/2756 556/669/2757 -f 556/669/2758 555/668/2759 553/642/2760 -f 553/642/2761 431/476/2762 429/528/2763 -f 429/528/2764 557/670/2765 553/642/2766 -f 557/670/2767 559/672/2768 558/671/2769 -f 558/671/2770 556/669/2771 557/670/2772 -f 557/670/2773 429/528/2774 412/673/2775 -f 412/673/2776 559/672/2777 557/670/2778 -f 559/652/2779 561/653/2780 560/649/2781 -f 560/649/2782 558/651/2783 559/652/2784 -f 559/652/2785 412/655/2786 413/654/2787 -f 413/654/2788 561/653/2789 559/652/2790 -f 561/653/2791 563/657/2792 562/656/2793 -f 562/656/2794 560/649/2795 561/653/2796 -f 561/653/2797 413/654/2798 414/658/2799 -f 414/658/2800 563/657/2801 561/653/2802 -f 563/657/2803 565/660/2804 564/659/2805 -f 564/659/2806 562/656/2807 563/657/2808 -f 563/657/2809 414/658/2810 566/661/2811 -f 566/661/2812 565/660/2813 563/657/2814 -f 566/661/2815 463/663/2816 567/662/2817 -f 567/662/2818 565/660/2819 566/661/2820 -f 566/650/2821 405/490/2822 406/489/2823 -f 406/489/2824 463/546/2825 566/650/2826 -f 566/650/2827 414/498/2828 415/499/2829 -f 415/499/2830 405/490/2831 566/650/2832 -f 567/662/2833 568/664/2834 564/659/2835 -f 564/659/2836 565/660/2837 567/662/2838 -f 567/662/2839 570/666/2840 569/665/2841 -f 569/665/2842 568/664/2843 567/662/2844 -f 567/662/2845 463/663/2846 461/667/2847 -f 461/667/2848 570/666/2849 567/662/2850 -f 570/666/2851 458/557/2852 459/644/2853 -f 459/644/2854 569/665/2855 570/666/2856 -f 570/666/2857 461/667/2858 457/542/2859 -f 457/542/2860 458/557/2861 570/666/2862 -f 569/665/2863 572/697/2864 571/696/2865 -f 571/696/2866 568/664/2867 569/665/2868 -f 569/665/2869 459/644/2870 573/781/2871 -f 573/781/2872 572/697/2873 569/665/2874 -f 573/781/2875 575/1353/2876 574/782/2877 -f 574/782/2878 572/697/2879 573/781/2880 -f 573/781/2881 577/1355/2882 576/1354/2883 -f 576/1354/2884 575/1353/2885 573/781/2886 -f 573/781/2887 459/644/2888 453/537/2889 -f 453/537/2890 577/1355/2891 573/781/2892 -f 577/1355/2893 579/1357/2894 578/1356/2895 -f 578/1356/2896 576/1354/2897 577/1355/2898 -f 577/1355/2899 453/537/2900 454/536/2901 -f 454/536/2902 579/1357/2903 577/1355/2904 -f 576/1354/2905 581/1390/2906 580/1389/2907 -f 580/1389/2908 575/1353/2909 576/1354/2910 -f 576/1354/2911 578/1356/2912 582/1391/2913 -f 582/1391/2914 581/1390/2915 576/1354/2916 -f 581/1390/2917 1483/1393/2918 1482/1392/2919 -f 1482/1392/2920 580/1389/2921 581/1390/2922 -f 581/1390/2923 582/1391/2924 1484/1394/2925 -f 1484/1394/2926 1483/1393/2927 581/1390/2928 -f 1482/1392/2929 391/1396/2930 583/1395/2931 -f 583/1395/2932 580/1389/2933 1482/1392/2934 -f 391/1396/2935 397/475/2936 398/481/2937 -f 398/481/2938 583/1395/2939 391/1396/2940 -f 583/1395/2941 574/782/2942 575/1353/2943 -f 575/1353/2944 580/1389/2945 583/1395/2946 -f 583/1395/2947 398/481/2948 399/482/2949 -f 399/482/2950 574/782/2951 583/1395/2952 -f 574/782/2953 399/482/2954 571/696/2955 -f 571/696/2956 572/697/2957 574/782/2958 -f 571/696/2959 399/482/2960 400/483/2961 -f 400/483/2962 438/521/2963 571/696/2964 -f 571/696/2965 438/521/2966 564/659/2967 -f 564/659/2968 568/664/2969 571/696/2970 -f 564/659/2971 438/521/2972 432/517/2973 -f 432/517/2974 562/656/2975 564/659/2976 -f 562/656/2977 432/517/2978 436/520/2979 -f 436/520/2980 560/649/2981 562/656/2982 -f 560/649/2983 436/520/2984 584/1397/2985 -f 584/1397/2986 558/651/2987 560/649/2988 -f 584/676/2989 587/677/2990 586/674/2991 -f 586/674/2992 585/675/2993 584/676/2994 -f 584/1397/2995 436/520/2996 437/519/2997 -f 437/519/2998 587/1398/2999 584/1397/3000 -f 584/676/3001 585/675/3002 556/669/3003 -f 556/669/3004 558/671/3005 584/676/3006 -f 586/674/3007 590/680/3008 589/678/3009 -f 589/678/3010 588/679/3011 586/674/3012 -f 586/674/3013 587/677/3014 444/681/3015 -f 444/681/3016 590/680/3017 586/674/3018 -f 586/674/3019 588/679/3020 591/682/3021 -f 591/682/3022 585/675/3023 586/674/3024 -f 591/682/3025 588/679/3026 593/683/3027 -f 593/683/3028 592/684/3029 591/682/3030 -f 591/682/3031 555/668/3032 556/669/3033 -f 556/669/3034 585/675/3035 591/682/3036 -f 591/682/3037 592/684/3038 554/643/3039 -f 554/643/3040 555/668/3041 591/682/3042 -f 593/683/3043 596/1388/3044 595/685/3045 -f 595/685/3046 594/785/3047 593/683/3048 -f 593/683/3049 588/679/3050 589/678/3051 -f 589/678/3052 596/1388/3053 593/683/3054 -f 593/683/3055 594/785/3056 597/1399/3057 -f 597/1399/3058 592/684/3059 593/683/3060 -f 597/1399/3061 594/785/3062 1500/1427/3063 -f 1500/1427/3064 1501/1428/3065 597/1399/3066 -f 597/1399/3067 598/1429/3068 554/643/3069 -f 554/643/3070 592/684/3071 597/1399/3072 -f 597/1399/3073 1501/1428/3074 392/1430/3075 -f 392/1430/3076 598/1429/3077 597/1399/3078 -f 392/1430/3079 1503/1525/3080 551/640/3081 -f 551/640/3082 598/1429/3083 392/1430/3084 -f 1503/1525/3085 599/1526/3086 549/638/3087 -f 549/638/3088 551/640/3089 1503/1525/3090 -f 599/1526/3091 1504/1528/3092 546/634/3093 -f 546/634/3094 549/638/3095 599/1526/3096 -f 1504/1528/3097 600/1529/3098 545/635/3099 -f 545/635/3100 546/634/3101 1504/1528/3102 -f 600/1529/3103 601/1530/3104 548/637/3105 -f 548/637/3106 545/635/3107 600/1529/3108 -f 598/1429/3109 551/640/3110 552/641/3111 -f 552/641/3112 554/643/3113 598/1429/3114 -f 1500/1427/3115 594/785/3116 595/685/3117 -f 595/685/3118 393/1531/3119 1500/1427/3120 -f 393/1531/3121 595/685/3122 419/1532/3123 -f 419/1532/3124 602/1533/3125 393/1531/3126 -f 596/1388/3127 422/1534/3128 419/1532/3129 -f 419/1532/3130 595/685/3131 596/1388/3132 -f 596/1388/3133 589/678/3134 603/1535/3135 -f 603/1535/3136 422/1534/3137 596/1388/3138 -f 603/689/3139 604/690/3140 421/503/3141 -f 421/503/3142 422/506/3143 603/689/3144 -f 603/689/3145 606/692/3146 605/691/3147 -f 605/691/3148 604/690/3149 603/689/3150 -f 603/1535/3151 589/678/3152 590/680/3153 -f 590/680/3154 606/1536/3155 603/1535/3156 -f 607/693/3157 449/533/3158 605/691/3159 -f 605/691/3160 606/692/3161 607/693/3162 -f 606/1536/3163 590/680/3164 444/681/3165 -f 444/681/3166 607/1537/3167 606/1536/3168 -f 607/1401/3169 444/525/3170 441/524/3171 -f 441/524/3172 608/1400/3173 607/1401/3174 -f 608/1400/3175 441/524/3176 445/529/3177 -f 445/529/3178 609/1402/3179 608/1400/3180 -f 609/1402/3181 445/529/3182 612/1409/3183 -f 612/1409/3184 611/1410/3185 609/1402/3186 -f 612/1409/3187 445/529/3188 439/522/3189 -f 439/522/3190 440/523/3191 612/1409/3192 -f 612/1409/3193 613/1412/3194 1515/1411/3195 -f 1515/1411/3196 611/1410/3197 612/1409/3198 -f 612/1409/3199 440/523/3200 394/1414/3201 -f 394/1414/3202 613/1412/3203 612/1409/3204 -f 1515/698/3205 395/699/3206 610/694/3207 -f 610/694/3208 611/695/3209 1515/698/3210 -f 395/699/3211 1517/701/3212 614/700/3213 -f 614/700/3214 610/694/3215 395/699/3216 -f 1517/701/3217 1519/703/3218 615/702/3219 -f 615/702/3220 614/700/3221 1517/701/3222 -f 1519/703/3223 1521/705/3224 616/704/3225 -f 616/704/3226 615/702/3227 1519/703/3228 -f 1521/705/3229 1341/2601/3230 467/2600/3231 -f 467/2600/3232 616/704/3233 1521/705/3234 -f 616/704/3235 618/707/3236 617/706/3237 -f 617/706/3238 615/702/3239 616/704/3240 -f 616/704/3241 467/2600/3242 619/708/3243 -f 619/708/3244 618/707/3245 616/704/3246 -f 620/710/3247 618/707/3248 619/708/3249 -f 619/708/3250 621/709/3251 620/710/3252 -f 424/507/3253 622/711/3254 621/2603/3255 -f 621/2603/3256 619/2602/3257 424/507/3258 -f 619/2602/3259 467/551/3260 423/508/3261 -f 423/508/3262 424/507/3263 619/2602/3264 -f 623/714/3265 626/715/3266 625/712/3267 -f 625/712/3268 624/2605/3269 623/714/3270 -f 623/714/3271 628/717/3272 627/716/3273 -f 627/716/3274 626/715/3275 623/714/3276 -f 622/711/3277 629/718/3278 628/717/3279 -f 628/717/3280 623/714/3281 622/711/3282 -f 628/717/3283 631/720/3284 630/719/3285 -f 630/719/3286 627/716/3287 628/717/3288 -f 629/718/3289 632/721/3290 631/720/3291 -f 631/720/3292 628/717/3293 629/718/3294 -f 631/720/3295 634/723/3296 633/722/3297 -f 633/722/3298 630/719/3299 631/720/3300 -f 632/721/3301 635/724/3302 634/723/3303 -f 634/723/3304 631/720/3305 632/721/3306 -f 634/723/3307 637/726/3308 636/725/3309 -f 636/725/3310 633/722/3311 634/723/3312 -f 635/724/3313 638/727/3314 637/726/3315 -f 637/726/3316 634/723/3317 635/724/3318 -f 637/726/3319 640/729/3320 639/728/3321 -f 639/728/3322 636/725/3323 637/726/3324 -f 638/727/3325 450/535/3326 640/729/3327 -f 640/729/3328 637/726/3329 638/727/3330 -f 642/730/3331 641/731/3332 636/725/3333 -f 636/725/3334 639/728/3335 642/730/3336 -f 644/732/3337 643/733/3338 642/730/3339 -f 642/730/3340 639/728/3341 644/732/3342 -f 639/728/3343 640/729/3344 645/734/3345 -f 645/734/3346 644/732/3347 639/728/3348 -f 647/735/3349 646/736/3350 643/733/3351 -f 643/733/3352 644/732/3353 647/735/3354 -f 644/732/3355 645/734/3356 648/737/3357 -f 648/737/3358 647/735/3359 644/732/3360 -f 648/737/3361 650/739/3362 649/738/3363 -f 649/738/3364 647/735/3365 648/737/3366 -f 620/710/3367 650/739/3368 648/737/3369 -f 648/737/3370 651/740/3371 620/710/3372 -f 645/734/3373 451/534/3374 651/740/3375 -f 651/740/3376 648/737/3377 645/734/3378 -f 646/736/3379 647/735/3380 649/738/3381 -f 649/738/3382 652/741/3383 646/736/3384 -f 653/742/3385 652/741/3386 649/738/3387 -f 649/738/3388 625/2604/3389 653/742/3390 -f 649/738/3391 650/739/3392 624/713/3393 -f 624/713/3394 625/2604/3395 649/738/3396 -f 656/745/3397 655/746/3398 654/2607/3399 -f 654/2607/3400 657/744/3401 656/745/3402 -f 659/747/3403 658/748/3404 657/2608/3405 -f 657/2608/3406 654/743/3407 659/747/3408 -f 653/2606/3409 660/749/3410 659/747/3411 -f 659/747/3412 654/743/3413 653/2606/3414 -f 662/750/3415 661/751/3416 658/748/3417 -f 658/748/3418 659/747/3419 662/750/3420 -f 660/749/3421 663/752/3422 662/750/3423 -f 662/750/3424 659/747/3425 660/749/3426 -f 665/753/3427 664/754/3428 661/751/3429 -f 661/751/3430 662/750/3431 665/753/3432 -f 663/752/3433 666/755/3434 665/753/3435 -f 665/753/3436 662/750/3437 663/752/3438 -f 667/757/3439 664/754/3440 665/753/3441 -f 665/753/3442 668/756/3443 667/757/3444 -f 666/755/3445 669/758/3446 668/756/3447 -f 668/756/3448 665/753/3449 666/755/3450 -f 670/760/3451 667/757/3452 668/756/3453 -f 668/756/3454 671/759/3455 670/760/3456 -f 641/731/3457 671/759/3458 668/756/3459 -f 668/756/3460 669/758/3461 641/731/3462 -f 672/763/3463 675/764/3464 674/761/3465 -f 674/761/3466 673/762/3467 672/763/3468 -f 672/763/3469 677/766/3470 676/765/3471 -f 676/765/3472 675/764/3473 672/763/3474 -f 670/760/3475 678/767/3476 677/766/3477 -f 677/766/3478 672/763/3479 670/760/3480 -f 677/766/3481 680/769/3482 679/768/3483 -f 679/768/3484 676/765/3485 677/766/3486 -f 678/767/3487 681/770/3488 680/769/3489 -f 680/769/3490 677/766/3491 678/767/3492 -f 680/769/3493 683/772/3494 682/771/3495 -f 682/771/3496 679/768/3497 680/769/3498 -f 681/770/3499 684/773/3500 683/772/3501 -f 683/772/3502 680/769/3503 681/770/3504 -f 683/772/3505 686/775/3506 685/774/3507 -f 685/774/3508 682/771/3509 683/772/3510 -f 656/745/3511 686/775/3512 683/772/3513 -f 683/772/3514 684/773/3515 656/745/3516 -f 685/774/3517 686/775/3518 688/776/3519 -f 688/776/3520 687/777/3521 685/774/3522 -f 687/2610/3523 688/2609/3524 690/778/3525 -f 690/778/3526 689/1350/3527 687/2610/3528 -f 689/1350/3529 690/778/3530 692/1351/3531 -f 692/1351/3532 691/1352/3533 689/1350/3534 -f 691/1352/3535 692/1351/3536 694/2566/3537 -f 694/2566/3538 693/2567/3539 691/1352/3540 -f 693/2567/3541 694/2566/3542 673/762/3543 -f 673/762/3544 674/761/3545 693/2567/3546 -f 617/706/3547 446/532/3548 614/700/3549 -f 614/700/3550 615/702/3551 617/706/3552 -f 542/631/3553 548/637/3554 470/552/3555 -f 470/552/3556 474/1538/3557 542/631/3558 -f 521/606/3559 479/563/3560 480/564/3561 -f 480/564/3562 482/566/3563 521/606/3564 -f 503/2585/3565 695/779/3566 409/493/3567 -f 409/493/3568 410/492/3569 503/2585/3570 -f 491/575/3571 464/547/3572 418/502/3573 -f 418/502/3574 696/780/3575 491/575/3576 -f 455/539/3577 452/538/3578 698/1415/3579 -f 698/1415/3580 697/1416/3581 455/539/3582 -f 430/513/3583 411/2581/3584 412/2582/3585 -f 412/2582/3586 429/514/3587 430/513/3588 -f 1342/688/3589 602/2568/3590 419/505/3591 -f 419/505/3592 423/508/3593 1342/688/3594 -f 698/1415/3595 472/645/3596 473/648/3597 -f 473/648/3598 697/1416/3599 698/1415/3600 -f 698/1415/3601 452/538/3602 456/543/3603 -f 456/543/3604 472/645/3605 698/1415/3606 -f 418/502/3607 409/493/3608 695/779/3609 -f 695/779/3610 696/780/3611 418/502/3612 -f 416/500/3613 407/491/3614 405/490/3615 -f 405/490/3616 415/499/3617 416/500/3618 -f 1269/478/3619 394/1414/3620 440/523/3621 -f 440/523/3622 396/480/3623 1269/478/3624 -f 537/621/3625 505/589/3626 506/590/3627 -f 506/590/3628 536/620/3629 537/621/3630 -f 537/621/3631 512/595/3632 508/591/3633 -f 508/591/3634 505/589/3635 537/621/3636 -f 435/518/3637 400/483/3638 396/480/3639 -f 396/480/3640 440/523/3641 435/518/3642 -f 695/779/3643 700/784/3644 699/783/3645 -f 699/783/3646 696/780/3647 695/779/3648 -f 491/575/3649 696/780/3650 699/783/3651 -f 699/783/3652 494/578/3653 491/575/3654 -f 700/784/3655 499/582/3656 494/578/3657 -f 494/578/3658 699/783/3659 700/784/3660 -f 503/2585/3661 499/582/3662 700/784/3663 -f 700/784/3664 695/779/3665 503/2585/3666 -f 601/1530/3667 1607/1540/3668 701/1539/3669 -f 701/1539/3670 548/637/3671 601/1530/3672 -f 548/637/3673 701/1539/3674 469/553/3675 -f 469/553/3676 470/552/3677 548/637/3678 -f 703/788/3679 702/789/3680 705/786/3681 -f 705/786/3682 704/787/3683 703/788/3684 -f 1129/792/3685 707/793/3686 706/790/3687 -f 706/790/3688 708/791/3689 1129/792/3690 -f 711/796/3691 710/797/3692 709/794/3693 -f 709/794/3694 712/795/3695 711/796/3696 -f 714/800/3697 713/801/3698 716/798/3699 -f 716/798/3700 715/799/3701 714/800/3702 -f 711/796/3703 718/804/3704 717/802/3705 -f 717/802/3706 719/803/3707 711/796/3708 -f 724/809/3709 723/810/3710 726/807/3711 -f 726/807/3712 725/808/3713 724/809/3714 -f 728/813/3715 727/814/3716 730/811/3717 -f 730/811/3718 729/812/3719 728/813/3720 -f 733/815/3721 732/816/3722 731/805/3723 -f 731/805/3724 734/806/3725 733/815/3726 -f 736/819/3727 735/820/3728 738/817/3729 -f 738/817/3730 737/818/3731 736/819/3732 -f 739/821/3733 731/805/3734 714/800/3735 -f 714/800/3736 709/794/3737 739/821/3738 -f 741/824/3739 738/817/3740 740/822/3741 -f 740/822/3742 742/823/3743 741/824/3744 -f 744/829/3745 743/830/3746 746/827/3747 -f 746/827/3748 745/828/3749 744/829/3750 -f 747/833/3751 750/834/3752 749/831/3753 -f 749/831/3754 748/832/3755 747/833/3756 -f 751/826/3757 737/818/3758 738/817/3759 -f 738/817/3760 752/825/3761 751/826/3762 -f 751/826/3763 752/825/3764 731/805/3765 -f 731/805/3766 732/816/3767 751/826/3768 -f 753/843/3769 733/844/3770 734/837/3771 -f 734/837/3772 754/838/3773 753/843/3774 -f 753/843/3775 754/838/3776 735/845/3777 -f 735/845/3778 736/846/3779 753/843/3780 -f 755/839/3781 758/840/3782 757/835/3783 -f 757/835/3784 756/836/3785 755/839/3786 -f 761/852/3787 760/853/3788 759/849/3789 -f 759/849/3790 762/850/3791 761/852/3792 -f 740/822/3793 764/842/3794 763/841/3795 -f 763/841/3796 742/823/3797 740/822/3798 -f 765/867/3799 766/868/3800 747/833/3801 -f 747/833/3802 748/832/3803 765/867/3804 -f 710/797/3805 767/847/3806 739/821/3807 -f 739/821/3808 709/794/3809 710/797/3810 -f 768/879/3811 769/880/3812 761/852/3813 -f 761/852/3814 762/850/3815 768/879/3816 -f 770/854/3817 721/855/3818 722/848/3819 -f 722/848/3820 771/851/3821 770/854/3822 -f 772/856/3823 720/857/3824 721/855/3825 -f 721/855/3826 770/854/3827 772/856/3828 -f 775/860/3829 774/861/3830 773/858/3831 -f 773/858/3832 776/859/3833 775/860/3834 -f 778/864/3835 777/865/3836 780/862/3837 -f 780/862/3838 779/863/3839 778/864/3840 -f 780/862/3841 777/865/3842 781/866/3843 -f 781/866/3844 782/869/3845 780/862/3846 -f 781/866/3847 774/861/3848 775/860/3849 -f 775/860/3850 782/869/3851 781/866/3852 -f 773/893/3853 783/894/3854 784/891/3855 -f 784/891/3856 776/892/3857 773/893/3858 -f 784/891/3859 783/894/3860 778/895/3861 -f 778/895/3862 779/896/3863 784/891/3864 -f 787/872/3865 786/873/3866 785/870/3867 -f 785/870/3868 788/871/3869 787/872/3870 -f 790/876/3871 789/877/3872 792/874/3873 -f 792/874/3874 791/875/3875 790/876/3876 -f 792/874/3877 789/877/3878 793/878/3879 -f 793/878/3880 794/881/3881 792/874/3882 -f 793/878/3883 786/873/3884 787/872/3885 -f 787/872/3886 794/881/3887 793/878/3888 -f 788/899/3889 785/905/3890 795/897/3891 -f 795/897/3892 796/898/3893 788/899/3894 -f 795/897/3895 790/907/3896 791/906/3897 -f 791/906/3898 796/898/3899 795/897/3900 -f 797/884/3901 800/885/3902 799/882/3903 -f 799/882/3904 798/883/3905 797/884/3906 -f 801/888/3907 804/889/3908 803/886/3909 -f 803/886/3910 802/887/3911 801/888/3912 -f 805/890/3913 806/900/3914 804/889/3915 -f 804/889/3916 801/888/3917 805/890/3918 -f 798/883/3919 799/882/3920 806/900/3921 -f 806/900/3922 805/890/3923 798/883/3924 -f 807/910/3925 810/911/3926 809/908/3927 -f 809/908/3928 808/909/3929 807/910/3930 -f 811/912/3931 812/913/3932 810/911/3933 -f 810/911/3934 807/910/3935 811/912/3936 -f 800/885/3937 773/858/3938 774/861/3939 -f 774/861/3940 799/882/3941 800/885/3942 -f 804/889/3943 777/865/3944 778/864/3945 -f 778/864/3946 803/886/3947 804/889/3948 -f 806/900/3949 781/866/3950 777/865/3951 -f 777/865/3952 804/889/3953 806/900/3954 -f 799/882/3955 774/861/3956 781/866/3957 -f 781/866/3958 806/900/3959 799/882/3960 -f 810/911/3961 814/915/3962 813/914/3963 -f 813/914/3964 809/908/3965 810/911/3966 -f 812/913/3967 815/916/3968 814/915/3969 -f 814/915/3970 810/911/3971 812/913/3972 -f 776/859/3973 817/902/3974 816/901/3975 -f 816/901/3976 775/860/3977 776/859/3978 -f 780/862/3979 819/904/3980 818/903/3981 -f 818/903/3982 779/863/3983 780/862/3984 -f 782/869/3985 820/935/3986 819/904/3987 -f 819/904/3988 780/862/3989 782/869/3990 -f 775/860/3991 816/901/3992 820/935/3993 -f 820/935/3994 782/869/3995 775/860/3996 -f 821/919/3997 824/920/3998 823/917/3999 -f 823/917/4000 822/918/4001 821/919/4002 -f 825/921/4003 826/922/4004 824/920/4005 -f 824/920/4006 821/919/4007 825/921/4008 -f 817/902/4009 785/870/4010 786/873/4011 -f 786/873/4012 816/901/4013 817/902/4014 -f 819/904/4015 789/877/4016 790/876/4017 -f 790/876/4018 818/903/4019 819/904/4020 -f 820/935/4021 793/878/4022 789/877/4023 -f 789/877/4024 819/904/4025 820/935/4026 -f 816/901/4027 786/873/4028 793/878/4029 -f 793/878/4030 820/935/4031 816/901/4032 -f 824/920/4033 828/924/4034 827/923/4035 -f 827/923/4036 823/917/4037 824/920/4038 -f 826/922/4039 829/925/4040 828/924/4041 -f 828/924/4042 824/920/4043 826/922/4044 -f 807/910/4045 808/909/4046 797/926/4047 -f 797/926/4048 830/927/4049 807/910/4050 -f 811/912/4051 807/910/4052 830/927/4053 -f 830/927/4054 802/928/4055 811/912/4056 -f 812/913/4057 811/912/4058 802/928/4059 -f 802/928/4060 803/929/4061 812/913/4062 -f 815/916/4063 812/913/4064 803/929/4065 -f 803/929/4066 778/895/4067 815/916/4068 -f 814/915/4069 815/916/4070 778/895/4071 -f 778/895/4072 783/894/4073 814/915/4074 -f 813/914/4075 814/915/4076 783/894/4077 -f 783/894/4078 773/893/4079 813/914/4080 -f 809/908/4081 813/914/4082 773/893/4083 -f 773/893/4084 800/930/4085 809/908/4086 -f 808/909/4087 809/908/4088 800/930/4089 -f 800/930/4090 797/926/4091 808/909/4092 -f 821/919/4093 822/918/4094 776/892/4095 -f 776/892/4096 784/891/4097 821/919/4098 -f 825/921/4099 821/919/4100 784/891/4101 -f 784/891/4102 779/896/4103 825/921/4104 -f 826/922/4105 825/921/4106 779/896/4107 -f 779/896/4108 818/931/4109 826/922/4110 -f 829/925/4111 826/922/4112 818/931/4113 -f 818/931/4114 790/907/4115 829/925/4116 -f 828/924/4117 829/925/4118 790/907/4119 -f 790/907/4120 795/897/4121 828/924/4122 -f 827/923/4123 828/924/4124 795/897/4125 -f 795/897/4126 785/905/4127 827/923/4128 -f 823/917/4129 827/923/4130 785/905/4131 -f 785/905/4132 817/932/4133 823/917/4134 -f 822/918/4135 823/917/4136 817/932/4137 -f 817/932/4138 776/892/4139 822/918/4140 -f 772/856/4141 787/872/4142 788/871/4143 -f 788/871/4144 720/857/4145 772/856/4146 -f 791/875/4147 792/874/4148 771/851/4149 -f 771/851/4150 722/848/4151 791/875/4152 -f 771/851/4153 792/874/4154 794/881/4155 -f 794/881/4156 770/854/4157 771/851/4158 -f 794/881/4159 787/872/4160 772/856/4161 -f 772/856/4162 770/854/4163 794/881/4164 -f 832/948/4165 831/949/4166 834/933/4167 -f 834/933/4168 833/934/4169 832/948/4170 -f 831/949/4171 835/964/4172 836/963/4173 -f 836/963/4174 834/933/4175 831/949/4176 -f 838/987/4177 837/988/4178 721/975/4179 -f 721/975/4180 720/976/4181 838/987/4182 -f 839/989/4183 838/987/4184 720/976/4185 -f 720/976/4186 788/899/4187 839/989/4188 -f 840/990/4189 839/989/4190 788/899/4191 -f 788/899/4192 796/898/4193 840/990/4194 -f 841/991/4195 840/990/4196 796/898/4197 -f 796/898/4198 791/906/4199 841/991/4200 -f 842/993/4201 841/991/4202 791/906/4203 -f 791/906/4204 722/992/4205 842/993/4206 -f 837/988/4207 842/993/4208 722/992/4209 -f 722/992/4210 721/975/4211 837/988/4212 -f 833/934/4213 834/933/4214 837/988/4215 -f 837/988/4216 838/987/4217 833/934/4218 -f 832/948/4219 833/934/4220 838/987/4221 -f 838/987/4222 839/989/4223 832/948/4224 -f 831/949/4225 832/948/4226 839/989/4227 -f 839/989/4228 840/990/4229 831/949/4230 -f 835/964/4231 831/949/4232 840/990/4233 -f 840/990/4234 841/991/4235 835/964/4236 -f 836/963/4237 835/964/4238 841/991/4239 -f 841/991/4240 842/993/4241 836/963/4242 -f 834/933/4243 836/963/4244 842/993/4245 -f 842/993/4246 837/988/4247 834/933/4248 -f 845/1001/4249 844/1002/4250 843/994/4251 -f 843/994/4252 846/995/4253 845/1001/4254 -f 848/1003/4255 847/1004/4256 744/829/4257 -f 744/829/4258 745/828/4259 848/1003/4260 -f 850/1005/4261 849/1006/4262 845/1001/4263 -f 845/1001/4264 846/995/4265 850/1005/4266 -f 714/800/4267 731/805/4268 752/825/4269 -f 752/825/4270 713/801/4271 714/800/4272 -f 752/825/4273 738/817/4274 741/824/4275 -f 741/824/4276 713/801/4277 752/825/4278 -f 757/835/4279 767/847/4280 710/797/4281 -f 710/797/4282 756/836/4283 757/835/4284 -f 755/839/4285 851/937/4286 852/936/4287 -f 852/936/4288 758/840/4289 755/839/4290 -f 853/939/4291 763/841/4292 764/842/4293 -f 764/842/4294 854/938/4295 853/939/4296 -f 732/816/4297 733/815/4298 797/884/4299 -f 797/884/4300 798/883/4301 732/816/4302 -f 802/887/4303 736/819/4304 737/818/4305 -f 737/818/4306 801/888/4307 802/887/4308 -f 737/818/4309 751/826/4310 805/890/4311 -f 805/890/4312 801/888/4313 737/818/4314 -f 805/890/4315 751/826/4316 732/816/4317 -f 732/816/4318 798/883/4319 805/890/4320 -f 733/844/4321 753/843/4322 830/927/4323 -f 830/927/4324 797/926/4325 733/844/4326 -f 830/927/4327 753/843/4328 736/846/4329 -f 736/846/4330 802/928/4331 830/927/4332 -f 859/941/4333 858/942/4334 767/847/4335 -f 767/847/4336 860/940/4337 859/941/4338 -f 861/944/4339 734/806/4340 731/805/4341 -f 731/805/4342 862/943/4343 861/944/4344 -f 863/945/4345 862/943/4346 731/805/4347 -f 731/805/4348 739/821/4349 863/945/4350 -f 863/945/4351 739/821/4352 767/847/4353 -f 767/847/4354 858/942/4355 863/945/4356 -f 865/1008/4357 864/1009/4358 734/837/4359 -f 734/837/4360 861/1007/4361 865/1008/4362 -f 866/950/4363 856/951/4364 857/946/4365 -f 857/946/4366 867/947/4367 866/950/4368 -f 868/952/4369 855/953/4370 856/951/4371 -f 856/951/4372 866/950/4373 868/952/4374 -f 871/956/4375 870/957/4376 869/954/4377 -f 869/954/4378 872/955/4379 871/956/4380 -f 874/960/4381 873/961/4382 876/958/4383 -f 876/958/4384 875/959/4385 874/960/4386 -f 876/958/4387 873/961/4388 877/962/4389 -f 877/962/4390 878/965/4391 876/958/4392 -f 877/962/4393 870/957/4394 871/956/4395 -f 871/956/4396 878/965/4397 877/962/4398 -f 869/1012/4399 879/1013/4400 880/1010/4401 -f 880/1010/4402 872/1011/4403 869/1012/4404 -f 880/1010/4405 879/1013/4406 874/1014/4407 -f 874/1014/4408 875/1015/4409 880/1010/4410 -f 883/968/4411 882/969/4412 881/966/4413 -f 881/966/4414 884/967/4415 883/968/4416 -f 886/972/4417 885/973/4418 888/970/4419 -f 888/970/4420 887/971/4421 886/972/4422 -f 888/970/4423 885/973/4424 889/974/4425 -f 889/974/4426 890/977/4427 888/970/4428 -f 889/974/4429 882/969/4430 883/968/4431 -f 883/968/4432 890/977/4433 889/974/4434 -f 884/1018/4435 881/1019/4436 891/1016/4437 -f 891/1016/4438 892/1017/4439 884/1018/4440 -f 891/1016/4441 886/1021/4442 887/1020/4443 -f 887/1020/4444 892/1017/4445 891/1016/4446 -f 893/980/4447 896/981/4448 895/978/4449 -f 895/978/4450 894/979/4451 893/980/4452 -f 897/984/4453 900/985/4454 899/982/4455 -f 899/982/4456 898/983/4457 897/984/4458 -f 901/986/4459 902/996/4460 900/985/4461 -f 900/985/4462 897/984/4463 901/986/4464 -f 894/979/4465 895/978/4466 902/996/4467 -f 902/996/4468 901/986/4469 894/979/4470 -f 903/1032/4471 906/1046/4472 905/1022/4473 -f 905/1022/4474 904/1031/4475 903/1032/4476 -f 907/1047/4477 908/1058/4478 906/1046/4479 -f 906/1046/4480 903/1032/4481 907/1047/4482 -f 896/981/4483 869/954/4484 870/957/4485 -f 870/957/4486 895/978/4487 896/981/4488 -f 900/985/4489 873/961/4490 874/960/4491 -f 874/960/4492 899/982/4493 900/985/4494 -f 902/996/4495 877/962/4496 873/961/4497 -f 873/961/4498 900/985/4499 902/996/4500 -f 895/978/4501 870/957/4502 877/962/4503 -f 877/962/4504 902/996/4505 895/978/4506 -f 906/1046/4507 910/1070/4508 909/1059/4509 -f 909/1059/4510 905/1022/4511 906/1046/4512 -f 908/1058/4513 911/1071/4514 910/1070/4515 -f 910/1070/4516 906/1046/4517 908/1058/4518 -f 872/955/4519 913/998/4520 912/997/4521 -f 912/997/4522 871/956/4523 872/955/4524 -f 876/958/4525 915/1000/4526 914/999/4527 -f 914/999/4528 875/959/4529 876/958/4530 -f 878/965/4531 916/1023/4532 915/1000/4533 -f 915/1000/4534 876/958/4535 878/965/4536 -f 871/956/4537 912/997/4538 916/1023/4539 -f 916/1023/4540 878/965/4541 871/956/4542 -f 917/1074/4543 920/1075/4544 919/1072/4545 -f 919/1072/4546 918/1073/4547 917/1074/4548 -f 921/1076/4549 922/1077/4550 920/1075/4551 -f 920/1075/4552 917/1074/4553 921/1076/4554 -f 913/998/4555 881/966/4556 882/969/4557 -f 882/969/4558 912/997/4559 913/998/4560 -f 915/1000/4561 885/973/4562 886/972/4563 -f 886/972/4564 914/999/4565 915/1000/4566 -f 916/1023/4567 889/974/4568 885/973/4569 -f 885/973/4570 915/1000/4571 916/1023/4572 -f 912/997/4573 882/969/4574 889/974/4575 -f 889/974/4576 916/1023/4577 912/997/4578 -f 920/1075/4579 924/1084/4580 923/1078/4581 -f 923/1078/4582 919/1072/4583 920/1075/4584 -f 922/1077/4585 925/1085/4586 924/1084/4587 -f 924/1084/4588 920/1075/4589 922/1077/4590 -f 903/1032/4591 904/1031/4592 893/1086/4593 -f 893/1086/4594 926/1087/4595 903/1032/4596 -f 907/1047/4597 903/1032/4598 926/1087/4599 -f 926/1087/4600 898/1088/4601 907/1047/4602 -f 908/1058/4603 907/1047/4604 898/1088/4605 -f 898/1088/4606 899/1089/4607 908/1058/4608 -f 911/1071/4609 908/1058/4610 899/1089/4611 -f 899/1089/4612 874/1014/4613 911/1071/4614 -f 910/1070/4615 911/1071/4616 874/1014/4617 -f 874/1014/4618 879/1013/4619 910/1070/4620 -f 909/1059/4621 910/1070/4622 879/1013/4623 -f 879/1013/4624 869/1012/4625 909/1059/4626 -f 905/1022/4627 909/1059/4628 869/1012/4629 -f 869/1012/4630 896/1090/4631 905/1022/4632 -f 904/1031/4633 905/1022/4634 896/1090/4635 -f 896/1090/4636 893/1086/4637 904/1031/4638 -f 917/1074/4639 918/1073/4640 872/1011/4641 -f 872/1011/4642 880/1010/4643 917/1074/4644 -f 921/1076/4645 917/1074/4646 880/1010/4647 -f 880/1010/4648 875/1015/4649 921/1076/4650 -f 922/1077/4651 921/1076/4652 875/1015/4653 -f 875/1015/4654 914/1091/4655 922/1077/4656 -f 925/1085/4657 922/1077/4658 914/1091/4659 -f 914/1091/4660 886/1021/4661 925/1085/4662 -f 924/1084/4663 925/1085/4664 886/1021/4665 -f 886/1021/4666 891/1016/4667 924/1084/4668 -f 923/1078/4669 924/1084/4670 891/1016/4671 -f 891/1016/4672 881/1019/4673 923/1078/4674 -f 919/1072/4675 923/1078/4676 881/1019/4677 -f 881/1019/4678 913/1092/4679 919/1072/4680 -f 918/1073/4681 919/1072/4682 913/1092/4683 -f 913/1092/4684 872/1011/4685 918/1073/4686 -f 868/952/4687 883/968/4688 884/967/4689 -f 884/967/4690 855/953/4691 868/952/4692 -f 887/971/4693 888/970/4694 867/947/4695 -f 867/947/4696 857/946/4697 887/971/4698 -f 867/947/4699 888/970/4700 890/977/4701 -f 890/977/4702 866/950/4703 867/947/4704 -f 890/977/4705 883/968/4706 868/952/4707 -f 868/952/4708 866/950/4709 890/977/4710 -f 928/1095/4711 927/1096/4712 930/1093/4713 -f 930/1093/4714 929/1094/4715 928/1095/4716 -f 927/1096/4717 931/1098/4718 932/1097/4719 -f 932/1097/4720 930/1093/4721 927/1096/4722 -f 934/1101/4723 933/1102/4724 856/1099/4725 -f 856/1099/4726 855/1100/4727 934/1101/4728 -f 935/1103/4729 934/1101/4730 855/1100/4731 -f 855/1100/4732 884/1018/4733 935/1103/4734 -f 936/1104/4735 935/1103/4736 884/1018/4737 -f 884/1018/4738 892/1017/4739 936/1104/4740 -f 937/1105/4741 936/1104/4742 892/1017/4743 -f 892/1017/4744 887/1020/4745 937/1105/4746 -f 938/1115/4747 937/1105/4748 887/1020/4749 -f 887/1020/4750 857/1114/4751 938/1115/4752 -f 933/1102/4753 938/1115/4754 857/1114/4755 -f 857/1114/4756 856/1099/4757 933/1102/4758 -f 929/1094/4759 930/1093/4760 933/1102/4761 -f 933/1102/4762 934/1101/4763 929/1094/4764 -f 928/1095/4765 929/1094/4766 934/1101/4767 -f 934/1101/4768 935/1103/4769 928/1095/4770 -f 927/1096/4771 928/1095/4772 935/1103/4773 -f 935/1103/4774 936/1104/4775 927/1096/4776 -f 931/1098/4777 927/1096/4778 936/1104/4779 -f 936/1104/4780 937/1105/4781 931/1098/4782 -f 932/1097/4783 931/1098/4784 937/1105/4785 -f 937/1105/4786 938/1115/4787 932/1097/4788 -f 930/1093/4789 932/1097/4790 938/1115/4791 -f 938/1115/4792 933/1102/4793 930/1093/4794 -f 858/942/4795 859/941/4796 893/980/4797 -f 893/980/4798 894/979/4799 858/942/4800 -f 898/983/4801 861/944/4802 862/943/4803 -f 862/943/4804 897/984/4805 898/983/4806 -f 862/943/4807 863/945/4808 901/986/4809 -f 901/986/4810 897/984/4811 862/943/4812 -f 901/986/4813 863/945/4814 858/942/4815 -f 858/942/4816 894/979/4817 901/986/4818 -f 859/1129/4819 865/1008/4820 926/1087/4821 -f 926/1087/4822 893/1086/4823 859/1129/4824 -f 926/1087/4825 865/1008/4826 861/1007/4827 -f 861/1007/4828 898/1088/4829 926/1087/4830 -f 943/1024/4831 942/1025/4832 758/840/4833 -f 758/840/4834 852/936/4835 943/1024/4836 -f 944/1027/4837 860/940/4838 767/847/4839 -f 767/847/4840 945/1026/4841 944/1027/4842 -f 946/1028/4843 945/1026/4844 767/847/4845 -f 767/847/4846 757/835/4847 946/1028/4848 -f 946/1028/4849 757/835/4850 758/840/4851 -f 758/840/4852 942/1025/4853 946/1028/4854 -f 947/1142/4855 943/1153/4856 852/1130/4857 -f 852/1130/4858 948/1141/4859 947/1142/4860 -f 947/1142/4861 948/1141/4862 860/1154/4863 -f 860/1154/4864 944/1155/4865 947/1142/4866 -f 949/1033/4867 940/1034/4868 941/1029/4869 -f 941/1029/4870 950/1030/4871 949/1033/4872 -f 951/1035/4873 939/1036/4874 940/1034/4875 -f 940/1034/4876 949/1033/4877 951/1035/4878 -f 954/1039/4879 953/1040/4880 952/1037/4881 -f 952/1037/4882 955/1038/4883 954/1039/4884 -f 957/1043/4885 956/1044/4886 959/1041/4887 -f 959/1041/4888 958/1042/4889 957/1043/4890 -f 959/1041/4891 956/1044/4892 960/1045/4893 -f 960/1045/4894 961/1048/4895 959/1041/4896 -f 960/1045/4897 953/1040/4898 954/1039/4899 -f 954/1039/4900 961/1048/4901 960/1045/4902 -f 952/1158/4903 962/1159/4904 963/1156/4905 -f 963/1156/4906 955/1157/4907 952/1158/4908 -f 963/1156/4909 962/1159/4910 957/1160/4911 -f 957/1160/4912 958/1161/4913 963/1156/4914 -f 966/1051/4915 965/1052/4916 964/1049/4917 -f 964/1049/4918 967/1050/4919 966/1051/4920 -f 969/1055/4921 968/1056/4922 971/1053/4923 -f 971/1053/4924 970/1054/4925 969/1055/4926 -f 971/1053/4927 968/1056/4928 972/1057/4929 -f 972/1057/4930 973/1060/4931 971/1053/4932 -f 972/1057/4933 965/1052/4934 966/1051/4935 -f 966/1051/4936 973/1060/4937 972/1057/4938 -f 967/1169/4939 964/1170/4940 974/1167/4941 -f 974/1167/4942 975/1168/4943 967/1169/4944 -f 974/1167/4945 969/1172/4946 970/1171/4947 -f 970/1171/4948 975/1168/4949 974/1167/4950 -f 976/1063/4951 979/1064/4952 978/1061/4953 -f 978/1061/4954 977/1062/4955 976/1063/4956 -f 980/1067/4957 983/1068/4958 982/1065/4959 -f 982/1065/4960 981/1066/4961 980/1067/4962 -f 984/1069/4963 985/1079/4964 983/1068/4965 -f 983/1068/4966 980/1067/4967 984/1069/4968 -f 977/1062/4969 978/1061/4970 985/1079/4971 -f 985/1079/4972 984/1069/4973 977/1062/4974 -f 986/1175/4975 989/1176/4976 988/1173/4977 -f 988/1173/4978 987/1174/4979 986/1175/4980 -f 990/1177/4981 991/1178/4982 989/1176/4983 -f 989/1176/4984 986/1175/4985 990/1177/4986 -f 979/1064/4987 952/1037/4988 953/1040/4989 -f 953/1040/4990 978/1061/4991 979/1064/4992 -f 983/1068/4993 956/1044/4994 957/1043/4995 -f 957/1043/4996 982/1065/4997 983/1068/4998 -f 985/1079/4999 960/1045/5000 956/1044/5001 -f 956/1044/5002 983/1068/5003 985/1079/5004 -f 978/1061/5005 953/1040/5006 960/1045/5007 -f 960/1045/5008 985/1079/5009 978/1061/5010 -f 989/1176/5011 993/1180/5012 992/1179/5013 -f 992/1179/5014 988/1173/5015 989/1176/5016 -f 991/1178/5017 994/1181/5018 993/1180/5019 -f 993/1180/5020 989/1176/5021 991/1178/5022 -f 955/1038/5023 996/1081/5024 995/1080/5025 -f 995/1080/5026 954/1039/5027 955/1038/5028 -f 959/1041/5029 998/1083/5030 997/1082/5031 -f 997/1082/5032 958/1042/5033 959/1041/5034 -f 961/1048/5035 999/1106/5036 998/1083/5037 -f 998/1083/5038 959/1041/5039 961/1048/5040 -f 954/1039/5041 995/1080/5042 999/1106/5043 -f 999/1106/5044 961/1048/5045 954/1039/5046 -f 1000/1184/5047 1003/1185/5048 1002/1182/5049 -f 1002/1182/5050 1001/1183/5051 1000/1184/5052 -f 1004/1186/5053 1005/1187/5054 1003/1185/5055 -f 1003/1185/5056 1000/1184/5057 1004/1186/5058 -f 996/1081/5059 964/1049/5060 965/1052/5061 -f 965/1052/5062 995/1080/5063 996/1081/5064 -f 998/1083/5065 968/1056/5066 969/1055/5067 -f 969/1055/5068 997/1082/5069 998/1083/5070 -f 999/1106/5071 972/1057/5072 968/1056/5073 -f 968/1056/5074 998/1083/5075 999/1106/5076 -f 995/1080/5077 965/1052/5078 972/1057/5079 -f 972/1057/5080 999/1106/5081 995/1080/5082 -f 1003/1185/5083 1007/1189/5084 1006/1188/5085 -f 1006/1188/5086 1002/1182/5087 1003/1185/5088 -f 1005/1187/5089 1008/1190/5090 1007/1189/5091 -f 1007/1189/5092 1003/1185/5093 1005/1187/5094 -f 986/1175/5095 987/1174/5096 976/1191/5097 -f 976/1191/5098 1009/1192/5099 986/1175/5100 -f 990/1177/5101 986/1175/5102 1009/1192/5103 -f 1009/1192/5104 981/1193/5105 990/1177/5106 -f 991/1178/5107 990/1177/5108 981/1193/5109 -f 981/1193/5110 982/1197/5111 991/1178/5112 -f 994/1181/5113 991/1178/5114 982/1197/5115 -f 982/1197/5116 957/1160/5117 994/1181/5118 -f 993/1180/5119 994/1181/5120 957/1160/5121 -f 957/1160/5122 962/1159/5123 993/1180/5124 -f 992/1179/5125 993/1180/5126 962/1159/5127 -f 962/1159/5128 952/1158/5129 992/1179/5130 -f 988/1173/5131 992/1179/5132 952/1158/5133 -f 952/1158/5134 979/1198/5135 988/1173/5136 -f 987/1174/5137 988/1173/5138 979/1198/5139 -f 979/1198/5140 976/1191/5141 987/1174/5142 -f 1000/1184/5143 1001/1183/5144 955/1157/5145 -f 955/1157/5146 963/1156/5147 1000/1184/5148 -f 1004/1186/5149 1000/1184/5150 963/1156/5151 -f 963/1156/5152 958/1161/5153 1004/1186/5154 -f 1005/1187/5155 1004/1186/5156 958/1161/5157 -f 958/1161/5158 997/1199/5159 1005/1187/5160 -f 1008/1190/5161 1005/1187/5162 997/1199/5163 -f 997/1199/5164 969/1172/5165 1008/1190/5166 -f 1007/1189/5167 1008/1190/5168 969/1172/5169 -f 969/1172/5170 974/1167/5171 1007/1189/5172 -f 1006/1188/5173 1007/1189/5174 974/1167/5175 -f 974/1167/5176 964/1170/5177 1006/1188/5178 -f 1002/1182/5179 1006/1188/5180 964/1170/5181 -f 964/1170/5182 996/1222/5183 1002/1182/5184 -f 1001/1183/5185 1002/1182/5186 996/1222/5187 -f 996/1222/5188 955/1157/5189 1001/1183/5190 -f 951/1035/5191 966/1051/5192 967/1050/5193 -f 967/1050/5194 939/1036/5195 951/1035/5196 -f 970/1054/5197 971/1053/5198 950/1030/5199 -f 950/1030/5200 941/1029/5201 970/1054/5202 -f 950/1030/5203 971/1053/5204 973/1060/5205 -f 973/1060/5206 949/1033/5207 950/1030/5208 -f 973/1060/5209 966/1051/5210 951/1035/5211 -f 951/1035/5212 949/1033/5213 973/1060/5214 -f 1011/1227/5215 1010/1228/5216 1013/1223/5217 -f 1013/1223/5218 1012/1226/5219 1011/1227/5220 -f 1010/1228/5221 1014/1230/5222 1015/1229/5223 -f 1015/1229/5224 1013/1223/5225 1010/1228/5226 -f 1017/1234/5227 1016/1235/5228 940/1231/5229 -f 940/1231/5230 939/1233/5231 1017/1234/5232 -f 1018/1236/5233 1017/1234/5234 939/1233/5235 -f 939/1233/5236 967/1169/5237 1018/1236/5238 -f 1019/1237/5239 1018/1236/5240 967/1169/5241 -f 967/1169/5242 975/1168/5243 1019/1237/5244 -f 1020/1242/5245 1019/1237/5246 975/1168/5247 -f 975/1168/5248 970/1171/5249 1020/1242/5250 -f 1021/1244/5251 1020/1242/5252 970/1171/5253 -f 970/1171/5254 941/1243/5255 1021/1244/5256 -f 1016/1235/5257 1021/1244/5258 941/1243/5259 -f 941/1243/5260 940/1231/5261 1016/1235/5262 -f 1012/1226/5263 1013/1223/5264 1016/1235/5265 -f 1016/1235/5266 1017/1234/5267 1012/1226/5268 -f 1011/1227/5269 1012/1226/5270 1017/1234/5271 -f 1017/1234/5272 1018/1236/5273 1011/1227/5274 -f 1010/1228/5275 1011/1227/5276 1018/1236/5277 -f 1018/1236/5278 1019/1237/5279 1010/1228/5280 -f 1014/1230/5281 1010/1228/5282 1019/1237/5283 -f 1019/1237/5284 1020/1242/5285 1014/1230/5286 -f 1015/1229/5287 1014/1230/5288 1020/1242/5289 -f 1020/1242/5290 1021/1244/5291 1015/1229/5292 -f 1013/1223/5293 1015/1229/5294 1021/1244/5295 -f 1021/1244/5296 1016/1235/5297 1013/1223/5298 -f 942/1025/5299 943/1024/5300 976/1063/5301 -f 976/1063/5302 977/1062/5303 942/1025/5304 -f 981/1066/5305 944/1027/5306 945/1026/5307 -f 945/1026/5308 980/1067/5309 981/1066/5310 -f 945/1026/5311 946/1028/5312 984/1069/5313 -f 984/1069/5314 980/1067/5315 945/1026/5316 -f 984/1069/5317 946/1028/5318 942/1025/5319 -f 942/1025/5320 977/1062/5321 984/1069/5322 -f 943/1153/5323 947/1142/5324 1009/1192/5325 -f 1009/1192/5326 976/1191/5327 943/1153/5328 -f 1009/1192/5329 947/1142/5330 944/1155/5331 -f 944/1155/5332 981/1193/5333 1009/1192/5334 -f 1026/1107/5335 1025/1108/5336 738/817/5337 -f 738/817/5338 735/820/5339 1026/1107/5340 -f 1027/1110/5341 854/938/5342 764/842/5343 -f 764/842/5344 1028/1109/5345 1027/1110/5346 -f 1029/1111/5347 1028/1109/5348 764/842/5349 -f 764/842/5350 740/822/5351 1029/1111/5352 -f 1029/1111/5353 740/822/5354 738/817/5355 -f 738/817/5356 1025/1108/5357 1029/1111/5358 -f 1030/1246/5359 1026/1247/5360 735/845/5361 -f 735/845/5362 1031/1245/5363 1030/1246/5364 -f 1030/1246/5365 1031/1245/5366 854/1253/5367 -f 854/1253/5368 1027/1254/5369 1030/1246/5370 -f 1032/1116/5371 1023/1117/5372 1024/1112/5373 -f 1024/1112/5374 1033/1113/5375 1032/1116/5376 -f 1034/1118/5377 1022/1119/5378 1023/1117/5379 -f 1023/1117/5380 1032/1116/5381 1034/1118/5382 -f 1037/1122/5383 1036/1123/5384 1035/1120/5385 -f 1035/1120/5386 1038/1121/5387 1037/1122/5388 -f 1040/1126/5389 1039/1127/5390 1042/1124/5391 -f 1042/1124/5392 1041/1125/5393 1040/1126/5394 -f 1042/1124/5395 1039/1127/5396 1043/1128/5397 -f 1043/1128/5398 1044/1131/5399 1042/1124/5400 -f 1043/1128/5401 1036/1123/5402 1037/1122/5403 -f 1037/1122/5404 1044/1131/5405 1043/1128/5406 -f 1035/1257/5407 1045/1258/5408 1046/1255/5409 -f 1046/1255/5410 1038/1256/5411 1035/1257/5412 -f 1046/1255/5413 1045/1258/5414 1040/1260/5415 -f 1040/1260/5416 1041/1261/5417 1046/1255/5418 -f 1049/1134/5419 1048/1135/5420 1047/1132/5421 -f 1047/1132/5422 1050/1133/5423 1049/1134/5424 -f 1052/1138/5425 1051/1139/5426 1054/1136/5427 -f 1054/1136/5428 1053/1137/5429 1052/1138/5430 -f 1054/1136/5431 1051/1139/5432 1055/1140/5433 -f 1055/1140/5434 1056/1143/5435 1054/1136/5436 -f 1055/1140/5437 1048/1135/5438 1049/1134/5439 -f 1049/1134/5440 1056/1143/5441 1055/1140/5442 -f 1050/1264/5443 1047/1265/5444 1057/1262/5445 -f 1057/1262/5446 1058/1263/5447 1050/1264/5448 -f 1057/1262/5449 1052/1267/5450 1053/1266/5451 -f 1053/1266/5452 1058/1263/5453 1057/1262/5454 -f 1059/1146/5455 1062/1147/5456 1061/1144/5457 -f 1061/1144/5458 1060/1145/5459 1059/1146/5460 -f 1063/1150/5461 1066/1151/5462 1065/1148/5463 -f 1065/1148/5464 1064/1149/5465 1063/1150/5466 -f 1067/1152/5467 1068/1162/5468 1066/1151/5469 -f 1066/1151/5470 1063/1150/5471 1067/1152/5472 -f 1060/1145/5473 1061/1144/5474 1068/1162/5475 -f 1068/1162/5476 1067/1152/5477 1060/1145/5478 -f 1069/1278/5479 1072/1279/5480 1071/1268/5481 -f 1071/1268/5482 1070/1269/5483 1069/1278/5484 -f 1073/1280/5485 1074/1281/5486 1072/1279/5487 -f 1072/1279/5488 1069/1278/5489 1073/1280/5490 -f 1062/1147/5491 1035/1120/5492 1036/1123/5493 -f 1036/1123/5494 1061/1144/5495 1062/1147/5496 -f 1066/1151/5497 1039/1127/5498 1040/1126/5499 -f 1040/1126/5500 1065/1148/5501 1066/1151/5502 -f 1068/1162/5503 1043/1128/5504 1039/1127/5505 -f 1039/1127/5506 1066/1151/5507 1068/1162/5508 -f 1061/1144/5509 1036/1123/5510 1043/1128/5511 -f 1043/1128/5512 1068/1162/5513 1061/1144/5514 -f 1072/1279/5515 1076/1283/5516 1075/1282/5517 -f 1075/1282/5518 1071/1268/5519 1072/1279/5520 -f 1074/1281/5521 1077/1284/5522 1076/1283/5523 -f 1076/1283/5524 1072/1279/5525 1074/1281/5526 -f 1038/1121/5527 1079/1164/5528 1078/1163/5529 -f 1078/1163/5530 1037/1122/5531 1038/1121/5532 -f 1042/1124/5533 1081/1166/5534 1080/1165/5535 -f 1080/1165/5536 1041/1125/5537 1042/1124/5538 -f 1044/1131/5539 1082/1194/5540 1081/1166/5541 -f 1081/1166/5542 1042/1124/5543 1044/1131/5544 -f 1037/1122/5545 1078/1163/5546 1082/1194/5547 -f 1082/1194/5548 1044/1131/5549 1037/1122/5550 -f 1083/1290/5551 1086/1291/5552 1085/1285/5553 -f 1085/1285/5554 1084/1289/5555 1083/1290/5556 -f 1087/1292/5557 1088/1299/5558 1086/1291/5559 -f 1086/1291/5560 1083/1290/5561 1087/1292/5562 -f 1079/1164/5563 1047/1132/5564 1048/1135/5565 -f 1048/1135/5566 1078/1163/5567 1079/1164/5568 -f 1081/1166/5569 1051/1139/5570 1052/1138/5571 -f 1052/1138/5572 1080/1165/5573 1081/1166/5574 -f 1082/1194/5575 1055/1140/5576 1051/1139/5577 -f 1051/1139/5578 1081/1166/5579 1082/1194/5580 -f 1078/1163/5581 1048/1135/5582 1055/1140/5583 -f 1055/1140/5584 1082/1194/5585 1078/1163/5586 -f 1086/1291/5587 1090/1307/5588 1089/1306/5589 -f 1089/1306/5590 1085/1285/5591 1086/1291/5592 -f 1088/1299/5593 1091/1308/5594 1090/1307/5595 -f 1090/1307/5596 1086/1291/5597 1088/1299/5598 -f 1069/1278/5599 1070/1269/5600 1059/1309/5601 -f 1059/1309/5602 1092/1310/5603 1069/1278/5604 -f 1073/1280/5605 1069/1278/5606 1092/1310/5607 -f 1092/1310/5608 1064/1311/5609 1073/1280/5610 -f 1074/1281/5611 1073/1280/5612 1064/1311/5613 -f 1064/1311/5614 1065/1312/5615 1074/1281/5616 -f 1077/1284/5617 1074/1281/5618 1065/1312/5619 -f 1065/1312/5620 1040/1260/5621 1077/1284/5622 -f 1076/1283/5623 1077/1284/5624 1040/1260/5625 -f 1040/1260/5626 1045/1258/5627 1076/1283/5628 -f 1075/1282/5629 1076/1283/5630 1045/1258/5631 -f 1045/1258/5632 1035/1257/5633 1075/1282/5634 -f 1071/1268/5635 1075/1282/5636 1035/1257/5637 -f 1035/1257/5638 1062/1313/5639 1071/1268/5640 -f 1070/1269/5641 1071/1268/5642 1062/1313/5643 -f 1062/1313/5644 1059/1309/5645 1070/1269/5646 -f 1083/1290/5647 1084/1289/5648 1038/1256/5649 -f 1038/1256/5650 1046/1255/5651 1083/1290/5652 -f 1087/1292/5653 1083/1290/5654 1046/1255/5655 -f 1046/1255/5656 1041/1261/5657 1087/1292/5658 -f 1088/1299/5659 1087/1292/5660 1041/1261/5661 -f 1041/1261/5662 1080/1314/5663 1088/1299/5664 -f 1091/1308/5665 1088/1299/5666 1080/1314/5667 -f 1080/1314/5668 1052/1267/5669 1091/1308/5670 -f 1090/1307/5671 1091/1308/5672 1052/1267/5673 -f 1052/1267/5674 1057/1262/5675 1090/1307/5676 -f 1089/1306/5677 1090/1307/5678 1057/1262/5679 -f 1057/1262/5680 1047/1265/5681 1089/1306/5682 -f 1085/1285/5683 1089/1306/5684 1047/1265/5685 -f 1047/1265/5686 1079/1315/5687 1085/1285/5688 -f 1084/1289/5689 1085/1285/5690 1079/1315/5691 -f 1079/1315/5692 1038/1256/5693 1084/1289/5694 -f 1034/1118/5695 1049/1134/5696 1050/1133/5697 -f 1050/1133/5698 1022/1119/5699 1034/1118/5700 -f 1053/1137/5701 1054/1136/5702 1033/1113/5703 -f 1033/1113/5704 1024/1112/5705 1053/1137/5706 -f 1033/1113/5707 1054/1136/5708 1056/1143/5709 -f 1056/1143/5710 1032/1116/5711 1033/1113/5712 -f 1056/1143/5713 1049/1134/5714 1034/1118/5715 -f 1034/1118/5716 1032/1116/5717 1056/1143/5718 -f 1094/1318/5719 1093/1319/5720 1096/1316/5721 -f 1096/1316/5722 1095/1317/5723 1094/1318/5724 -f 1093/1319/5725 1097/1321/5726 1098/1320/5727 -f 1098/1320/5728 1096/1316/5729 1093/1319/5730 -f 1100/1324/5731 1099/1325/5732 1023/1322/5733 -f 1023/1322/5734 1022/1323/5735 1100/1324/5736 -f 1101/1326/5737 1100/1324/5738 1022/1323/5739 -f 1022/1323/5740 1050/1264/5741 1101/1326/5742 -f 1102/1327/5743 1101/1326/5744 1050/1264/5745 -f 1050/1264/5746 1058/1263/5747 1102/1327/5748 -f 1103/1328/5749 1102/1327/5750 1058/1263/5751 -f 1058/1263/5752 1053/1266/5753 1103/1328/5754 -f 1104/1330/5755 1103/1328/5756 1053/1266/5757 -f 1053/1266/5758 1024/1329/5759 1104/1330/5760 -f 1099/1325/5761 1104/1330/5762 1024/1329/5763 -f 1024/1329/5764 1023/1322/5765 1099/1325/5766 -f 1095/1317/5767 1096/1316/5768 1099/1325/5769 -f 1099/1325/5770 1100/1324/5771 1095/1317/5772 -f 1094/1318/5773 1095/1317/5774 1100/1324/5775 -f 1100/1324/5776 1101/1326/5777 1094/1318/5778 -f 1093/1319/5779 1094/1318/5780 1101/1326/5781 -f 1101/1326/5782 1102/1327/5783 1093/1319/5784 -f 1097/1321/5785 1093/1319/5786 1102/1327/5787 -f 1102/1327/5788 1103/1328/5789 1097/1321/5790 -f 1098/1320/5791 1097/1321/5792 1103/1328/5793 -f 1103/1328/5794 1104/1330/5795 1098/1320/5796 -f 1096/1316/5797 1098/1320/5798 1104/1330/5799 -f 1104/1330/5800 1099/1325/5801 1096/1316/5802 -f 1025/1108/5803 1026/1107/5804 1059/1146/5805 -f 1059/1146/5806 1060/1145/5807 1025/1108/5808 -f 1064/1149/5809 1027/1110/5810 1028/1109/5811 -f 1028/1109/5812 1063/1150/5813 1064/1149/5814 -f 1028/1109/5815 1029/1111/5816 1067/1152/5817 -f 1067/1152/5818 1063/1150/5819 1028/1109/5820 -f 1067/1152/5821 1029/1111/5822 1025/1108/5823 -f 1025/1108/5824 1060/1145/5825 1067/1152/5826 -f 1026/1247/5827 1030/1246/5828 1092/1310/5829 -f 1092/1310/5830 1059/1309/5831 1026/1247/5832 -f 1092/1310/5833 1030/1246/5834 1027/1254/5835 -f 1027/1254/5836 1064/1311/5837 1092/1310/5838 -f 750/834/5839 747/833/5840 1031/1245/5841 -f 1031/1245/5842 735/845/5843 750/834/5844 -f 749/831/5845 750/834/5846 735/845/5847 -f 735/845/5848 1105/1331/5849 749/831/5850 -f 748/832/5851 749/831/5852 1105/1331/5853 -f 1105/1331/5854 1106/1332/5855 748/832/5856 -f 765/867/5857 748/832/5858 1106/1332/5859 -f 1106/1332/5860 853/1333/5861 765/867/5862 -f 766/868/5863 765/867/5864 853/1333/5865 -f 853/1333/5866 854/1253/5867 766/868/5868 -f 747/833/5869 766/868/5870 854/1253/5871 -f 854/1253/5872 1031/1245/5873 747/833/5874 -f 743/830/5875 744/829/5876 754/838/5877 -f 754/838/5878 734/837/5879 743/830/5880 -f 746/827/5881 743/830/5882 734/837/5883 -f 734/837/5884 1107/1334/5885 746/827/5886 -f 745/828/5887 746/827/5888 1107/1334/5889 -f 1107/1334/5890 1108/1335/5891 745/828/5892 -f 848/1003/5893 745/828/5894 1108/1335/5895 -f 1108/1335/5896 1105/1331/5897 848/1003/5898 -f 847/1004/5899 848/1003/5900 1105/1331/5901 -f 1105/1331/5902 735/845/5903 847/1004/5904 -f 744/829/5905 847/1004/5906 735/845/5907 -f 735/845/5908 754/838/5909 744/829/5910 -f 845/1001/5911 849/1006/5912 734/837/5913 -f 734/837/5914 864/1009/5915 845/1001/5916 -f 844/1002/5917 845/1001/5918 864/1009/5919 -f 864/1009/5920 860/1154/5921 844/1002/5922 -f 843/994/5923 844/1002/5924 860/1154/5925 -f 860/1154/5926 727/814/5927 843/994/5928 -f 846/995/5929 843/994/5930 727/814/5931 -f 727/814/5932 1109/1336/5933 846/995/5934 -f 850/1005/5935 846/995/5936 1109/1336/5937 -f 1109/1336/5938 1107/1334/5939 850/1005/5940 -f 849/1006/5941 850/1005/5942 1107/1334/5943 -f 1107/1334/5944 734/837/5945 849/1006/5946 -f 760/853/5947 761/852/5948 948/1141/5949 -f 948/1141/5950 852/1130/5951 760/853/5952 -f 759/849/5953 760/853/5954 852/1130/5955 -f 852/1130/5956 851/1337/5957 759/849/5958 -f 762/850/5959 759/849/5960 851/1337/5961 -f 851/1337/5962 730/811/5963 762/850/5964 -f 768/879/5965 762/850/5966 730/811/5967 -f 730/811/5968 727/814/5969 768/879/5970 -f 769/880/5971 768/879/5972 727/814/5973 -f 727/814/5974 860/1154/5975 769/880/5976 -f 761/852/5977 769/880/5978 860/1154/5979 -f 860/1154/5980 948/1141/5981 761/852/5982 -f 859/1129/5983 860/1154/5984 864/1009/5985 -f 864/1009/5986 865/1008/5987 859/1129/5988 -f 755/839/5989 1111/1196/5990 1110/1195/5991 -f 1110/1195/5992 851/937/5993 755/839/5994 -f 712/795/5995 1112/1200/5996 718/804/5997 -f 718/804/5998 711/796/5999 712/795/6000 -f 1109/1336/6001 1114/1339/6002 1113/1338/6003 -f 1113/1338/6004 1107/1334/6005 1109/1336/6006 -f 719/803/6007 756/836/6008 710/797/6009 -f 710/797/6010 711/796/6011 719/803/6012 -f 725/808/6013 1115/1340/6014 1106/1332/6015 -f 1106/1332/6016 1105/1331/6017 725/808/6018 -f 1108/1335/6019 724/809/6020 725/808/6021 -f 725/808/6022 1105/1331/6023 1108/1335/6024 -f 1118/1203/6025 1117/1204/6026 1116/1201/6027 -f 1116/1201/6028 1119/1202/6029 1118/1203/6030 -f 1121/1205/6031 1120/1206/6032 1116/1201/6033 -f 1116/1201/6034 1117/1204/6035 1121/1205/6036 -f 1123/1208/6037 1122/1209/6038 1121/1205/6039 -f 1121/1205/6040 1124/1207/6041 1123/1208/6042 -f 1117/1204/6043 1118/1203/6044 1126/1210/6045 -f 1126/1210/6046 1125/1211/6047 1117/1204/6048 -f 1124/1207/6049 1121/1205/6050 1117/1204/6051 -f 1117/1204/6052 1125/1211/6053 1124/1207/6054 -f 707/793/6055 1129/792/6056 1127/1212/6057 -f 1127/1212/6058 1128/1213/6059 707/793/6060 -f 1131/1216/6061 1130/1217/6062 1133/1214/6063 -f 1133/1214/6064 1132/1215/6065 1131/1216/6066 -f 1135/1218/6067 1134/1219/6068 1131/1216/6069 -f 1131/1216/6070 1132/1215/6071 1135/1218/6072 -f 1130/1217/6073 1136/1221/6074 1137/1220/6075 -f 1137/1220/6076 1133/1214/6077 1130/1217/6078 -f 1136/1343/6079 1138/1344/6080 1139/1341/6081 -f 1139/1341/6082 1137/1342/6083 1136/1343/6084 -f 1138/1344/6085 1140/1346/6086 1141/1345/6087 -f 1141/1345/6088 1139/1341/6089 1138/1344/6090 -f 1141/1224/6091 1140/1225/6092 1134/1219/6093 -f 1134/1219/6094 1135/1218/6095 1141/1224/6096 -f 1142/1349/6097 1145/2379/6098 1144/1347/6099 -f 1144/1347/6100 1143/1348/6101 1142/1349/6102 -f 1146/2380/6103 1147/2381/6104 1145/2379/6105 -f 1145/2379/6106 1142/1349/6107 1146/2380/6108 -f 1126/1210/6109 1130/1217/6110 1131/1216/6111 -f 1131/1216/6112 1125/1211/6113 1126/1210/6114 -f 1125/1211/6115 1131/1216/6116 1134/1219/6117 -f 1134/1219/6118 1124/1207/6119 1125/1211/6120 -f 1148/1232/6121 1136/1221/6122 1130/1217/6123 -f 1130/1217/6124 1126/1210/6125 1148/1232/6126 -f 1145/2379/6127 1150/2384/6128 1149/2382/6129 -f 1149/2382/6130 1144/1347/6131 1145/2379/6132 -f 1147/2381/6133 1151/2385/6134 1150/2384/6135 -f 1150/2384/6136 1145/2379/6137 1147/2381/6138 -f 1124/1207/6139 1134/1219/6140 1140/1225/6141 -f 1140/1225/6142 1123/1208/6143 1124/1207/6144 -f 1142/1349/6145 1143/1348/6146 1152/2386/6147 -f 1152/2386/6148 1153/2387/6149 1142/1349/6150 -f 1146/2380/6151 1142/1349/6152 1153/2387/6153 -f 1153/2387/6154 1122/2388/6155 1146/2380/6156 -f 1147/2381/6157 1146/2380/6158 1122/2388/6159 -f 1122/2388/6160 1123/2389/6161 1147/2381/6162 -f 1151/2385/6163 1147/2381/6164 1123/2389/6165 -f 1123/2389/6166 1140/1346/6167 1151/2385/6168 -f 1150/2384/6169 1151/2385/6170 1140/1346/6171 -f 1140/1346/6172 1138/1344/6173 1150/2384/6174 -f 1149/2382/6175 1150/2384/6176 1138/1344/6177 -f 1138/1344/6178 1136/1343/6179 1149/2382/6180 -f 1144/1347/6181 1149/2382/6182 1136/1343/6183 -f 1136/1343/6184 1148/2390/6185 1144/1347/6186 -f 1143/1348/6187 1144/1347/6188 1148/2390/6189 -f 1148/2390/6190 1152/2386/6191 1143/1348/6192 -f 707/793/6193 1155/1239/6194 1154/1238/6195 -f 1154/1238/6196 706/790/6197 707/793/6198 -f 1128/1213/6199 1156/1240/6200 1155/1239/6201 -f 1155/1239/6202 707/793/6203 1128/1213/6204 -f 1154/1238/6205 1157/1241/6206 708/791/6207 -f 708/791/6208 706/790/6209 1154/1238/6210 -f 1159/2393/6211 1158/2394/6212 1161/2391/6213 -f 1161/2391/6214 1160/2392/6215 1159/2393/6216 -f 1158/2394/6217 1162/2396/6218 1163/2395/6219 -f 1163/2395/6220 1161/2391/6221 1158/2394/6222 -f 1164/1248/6223 1156/1240/6224 1128/1213/6225 -f 1128/1213/6226 1127/1212/6227 1164/1248/6228 -f 1133/1214/6229 1166/1250/6230 1165/1249/6231 -f 1165/1249/6232 1132/1215/6233 1133/1214/6234 -f 1132/1215/6235 1165/1249/6236 1167/1251/6237 -f 1167/1251/6238 1135/1218/6239 1132/1215/6240 -f 1137/1220/6241 1168/1252/6242 1166/1250/6243 -f 1166/1250/6244 1133/1214/6245 1137/1220/6246 -f 1169/2399/6247 1172/2400/6248 1171/2397/6249 -f 1171/2397/6250 1170/2398/6251 1169/2399/6252 -f 1173/2401/6253 1174/2402/6254 1172/2400/6255 -f 1172/2400/6256 1169/2399/6257 1173/2401/6258 -f 1135/1218/6259 1167/1251/6260 1175/1259/6261 -f 1175/1259/6262 1141/1224/6263 1135/1218/6264 -f 1166/1250/6265 1154/1238/6266 1155/1239/6267 -f 1155/1239/6268 1165/1249/6269 1166/1250/6270 -f 1165/1249/6271 1155/1239/6272 1156/1240/6273 -f 1156/1240/6274 1167/1251/6275 1165/1249/6276 -f 1168/1252/6277 1157/1241/6278 1154/1238/6279 -f 1154/1238/6280 1166/1250/6281 1168/1252/6282 -f 1172/2400/6283 1177/2404/6284 1176/2403/6285 -f 1176/2403/6286 1171/2397/6287 1172/2400/6288 -f 1174/2402/6289 1178/2405/6290 1177/2404/6291 -f 1177/2404/6292 1172/2400/6293 1174/2402/6294 -f 1167/1251/6295 1156/1240/6296 1164/1248/6297 -f 1164/1248/6298 1175/1259/6299 1167/1251/6300 -f 1169/2399/6301 1170/2398/6302 1137/1342/6303 -f 1137/1342/6304 1139/1341/6305 1169/2399/6306 -f 1173/2401/6307 1169/2399/6308 1139/1341/6309 -f 1139/1341/6310 1141/1345/6311 1173/2401/6312 -f 1174/2402/6313 1173/2401/6314 1141/1345/6315 -f 1141/1345/6316 1175/2406/6317 1174/2402/6318 -f 1178/2405/6319 1174/2402/6320 1175/2406/6321 -f 1175/2406/6322 1164/2407/6323 1178/2405/6324 -f 1177/2404/6325 1178/2405/6326 1164/2407/6327 -f 1164/2407/6328 1179/2408/6329 1177/2404/6330 -f 1176/2403/6331 1177/2404/6332 1179/2408/6333 -f 1179/2408/6334 1157/2409/6335 1176/2403/6336 -f 1171/2397/6337 1176/2403/6338 1157/2409/6339 -f 1157/2409/6340 1168/2410/6341 1171/2397/6342 -f 1170/2398/6343 1171/2397/6344 1168/2410/6345 -f 1168/2410/6346 1137/1342/6347 1170/2398/6348 -f 1181/2413/6349 1180/2414/6350 1129/2411/6351 -f 1129/2411/6352 708/2412/6353 1181/2413/6354 -f 1182/2415/6355 1181/2413/6356 708/2412/6357 -f 708/2412/6358 1157/2409/6359 1182/2415/6360 -f 1183/2416/6361 1182/2415/6362 1157/2409/6363 -f 1157/2409/6364 1179/2408/6365 1183/2416/6366 -f 1184/2417/6367 1183/2416/6368 1179/2408/6369 -f 1179/2408/6370 1164/2407/6371 1184/2417/6372 -f 1185/2419/6373 1184/2417/6374 1164/2407/6375 -f 1164/2407/6376 1127/2418/6377 1185/2419/6378 -f 1180/2414/6379 1185/2419/6380 1127/2418/6381 -f 1127/2418/6382 1129/2411/6383 1180/2414/6384 -f 1160/2392/6385 1161/2391/6386 1180/2414/6387 -f 1180/2414/6388 1181/2413/6389 1160/2392/6390 -f 1159/2393/6391 1160/2392/6392 1181/2413/6393 -f 1181/2413/6394 1182/2415/6395 1159/2393/6396 -f 1158/2394/6397 1159/2393/6398 1182/2415/6399 -f 1182/2415/6400 1183/2416/6401 1158/2394/6402 -f 1162/2396/6403 1158/2394/6404 1183/2416/6405 -f 1183/2416/6406 1184/2417/6407 1162/2396/6408 -f 1163/2395/6409 1162/2396/6410 1184/2417/6411 -f 1184/2417/6412 1185/2419/6413 1163/2395/6414 -f 1161/2391/6415 1163/2395/6416 1185/2419/6417 -f 1185/2419/6418 1180/2414/6419 1161/2391/6420 -f 741/824/6421 742/823/6422 1186/1270/6423 -f 1186/1270/6424 1187/1271/6425 741/824/6426 -f 1188/1274/6427 1191/1275/6428 1190/1272/6429 -f 1190/1272/6430 1189/1273/6431 1188/1274/6432 -f 1192/1276/6433 1112/1200/6434 712/795/6435 -f 712/795/6436 715/799/6437 1192/1276/6438 -f 1110/2420/6439 729/812/6440 730/811/6441 -f 730/811/6442 851/1337/6443 1110/2420/6444 -f 1194/2423/6445 1193/2424/6446 704/2421/6447 -f 704/2421/6448 705/2422/6449 1194/2423/6450 -f 728/813/6451 1114/1339/6452 1109/1336/6453 -f 1109/1336/6454 727/814/6455 728/813/6456 -f 1197/2426/6457 1196/2427/6458 1195/2425/6459 -f 1195/2425/6460 726/807/6461 1197/2426/6462 -f 725/808/6463 726/807/6464 1195/2425/6465 -f 1195/2425/6466 1115/1340/6467 725/808/6468 -f 1198/2430/6469 1118/2431/6470 1119/2428/6471 -f 1119/2428/6472 1199/2429/6473 1198/2430/6474 -f 1113/1338/6475 724/809/6476 1108/1335/6477 -f 1108/1335/6478 1107/1334/6479 1113/1338/6480 -f 1197/2426/6481 726/807/6482 723/810/6483 -f 723/810/6484 1200/2432/6485 1197/2426/6486 -f 1113/1338/6487 1201/2433/6488 723/810/6489 -f 723/810/6490 724/809/6491 1113/1338/6492 -f 1202/1277/6493 1186/1270/6494 742/823/6495 -f 742/823/6496 763/841/6497 1202/1277/6498 -f 853/939/6499 1203/1286/6500 1202/1277/6501 -f 1202/1277/6502 763/841/6503 853/939/6504 -f 1106/1332/6505 1115/1340/6506 1203/2434/6507 -f 1203/2434/6508 853/1333/6509 1106/1332/6510 -f 1204/1287/6511 1192/1276/6512 715/799/6513 -f 715/799/6514 716/798/6515 1204/1287/6516 -f 1205/2435/6517 1199/2429/6518 1115/1340/6519 -f 1115/1340/6520 1195/2425/6521 1205/2435/6522 -f 1206/2436/6523 1205/2435/6524 1195/2425/6525 -f 1195/2425/6526 1196/2427/6527 1206/2436/6528 -f 1207/2438/6529 1206/2436/6530 1196/2427/6531 -f 1196/2427/6532 1208/2437/6533 1207/2438/6534 -f 1209/2440/6535 1207/2438/6536 1208/2437/6537 -f 1208/2437/6538 1191/2439/6539 1209/2440/6540 -f 1210/1288/6541 1209/1293/6542 1191/1275/6543 -f 1191/1275/6544 1188/1274/6545 1210/1288/6546 -f 1187/1271/6547 1211/1294/6548 1204/1287/6549 -f 1204/1287/6550 716/798/6551 1187/1271/6552 -f 1211/1294/6553 1210/1288/6554 1188/1274/6555 -f 1188/1274/6556 1204/1287/6557 1211/1294/6558 -f 1213/1295/6559 1212/1296/6560 1120/1206/6561 -f 1120/1206/6562 1121/1205/6563 1213/1295/6564 -f 1153/2387/6565 1152/2386/6566 1206/2436/6567 -f 1206/2436/6568 1207/2438/6569 1153/2387/6570 -f 1209/2440/6571 1122/2388/6572 1153/2387/6573 -f 1153/2387/6574 1207/2438/6575 1209/2440/6576 -f 1214/1297/6577 1122/1209/6578 1209/1293/6579 -f 1209/1293/6580 1210/1288/6581 1214/1297/6582 -f 1211/1294/6583 1213/1295/6584 1214/1297/6585 -f 1214/1297/6586 1210/1288/6587 1211/1294/6588 -f 1187/1271/6589 1212/1296/6590 1213/1295/6591 -f 1213/1295/6592 1211/1294/6593 1187/1271/6594 -f 1186/1270/6595 1120/1206/6596 1212/1296/6597 -f 1212/1296/6598 1187/1271/6599 1186/1270/6600 -f 1203/1286/6601 1119/1202/6602 1116/1201/6603 -f 1116/1201/6604 1202/1277/6605 1203/1286/6606 -f 1199/2429/6607 1119/2428/6608 1203/2434/6609 -f 1203/2434/6610 1115/1340/6611 1199/2429/6612 -f 1206/2436/6613 1152/2386/6614 1215/2441/6615 -f 1215/2441/6616 1205/2435/6617 1206/2436/6618 -f 1116/1201/6619 1120/1206/6620 1186/1270/6621 -f 1186/1270/6622 1202/1277/6623 1116/1201/6624 -f 1198/2430/6625 1199/2429/6626 1205/2435/6627 -f 1205/2435/6628 1215/2441/6629 1198/2430/6630 -f 1198/2430/6631 1215/2441/6632 1216/2442/6633 -f 1216/2442/6634 1118/2431/6635 1198/2430/6636 -f 702/789/6637 703/788/6638 1217/1298/6639 -f 1217/1298/6640 1218/1300/6641 702/789/6642 -f 755/839/6643 756/836/6644 719/803/6645 -f 719/803/6646 1111/1196/6647 755/839/6648 -f 1194/2423/6649 729/812/6650 1110/2420/6651 -f 1110/2420/6652 1193/2424/6653 1194/2423/6654 -f 1219/1301/6655 1193/1302/6656 1110/1195/6657 -f 1110/1195/6658 1111/1196/6659 1219/1301/6660 -f 717/802/6661 1219/1301/6662 1111/1196/6663 -f 1111/1196/6664 719/803/6665 717/802/6666 -f 716/798/6667 713/801/6668 741/824/6669 -f 741/824/6670 1187/1271/6671 716/798/6672 -f 715/799/6673 712/795/6674 709/794/6675 -f 709/794/6676 714/800/6677 715/799/6678 -f 1112/1200/6679 1192/1276/6680 1189/1273/6681 -f 1189/1273/6682 1220/1303/6683 1112/1200/6684 -f 1204/1287/6685 1188/1274/6686 1189/1273/6687 -f 1189/1273/6688 1192/1276/6689 1204/1287/6690 -f 1217/1298/6691 1221/1304/6692 1220/1303/6693 -f 1220/1303/6694 1218/1300/6695 1217/1298/6696 -f 703/788/6697 704/787/6698 1193/1302/6699 -f 1193/1302/6700 1219/1301/6701 703/788/6702 -f 717/802/6703 1217/1298/6704 703/788/6705 -f 703/788/6706 1219/1301/6707 717/802/6708 -f 1221/1304/6709 1217/1298/6710 717/802/6711 -f 717/802/6712 718/804/6713 1221/1304/6714 -f 1112/1200/6715 1220/1303/6716 1221/1304/6717 -f 1221/1304/6718 718/804/6719 1112/1200/6720 -f 1190/1272/6721 1218/1300/6722 1220/1303/6723 -f 1220/1303/6724 1189/1273/6725 1190/1272/6726 -f 1223/2444/6727 1222/2445/6728 705/2574/6729 -f 705/2574/6730 702/2443/6731 1223/2444/6732 -f 1224/2447/6733 1223/2444/6734 702/2443/6735 -f 702/2443/6736 1218/2446/6737 1224/2447/6738 -f 1225/2449/6739 1224/2447/6740 1218/2446/6741 -f 1218/2446/6742 1190/2448/6743 1225/2449/6744 -f 1226/2450/6745 1225/2449/6746 1190/2448/6747 -f 1190/2448/6748 1191/2439/6749 1226/2450/6750 -f 1227/2451/6751 1226/2450/6752 1191/2439/6753 -f 1191/2439/6754 1208/2437/6755 1227/2451/6756 -f 1228/2452/6757 1227/2451/6758 1208/2437/6759 -f 1208/2437/6760 1196/2427/6761 1228/2452/6762 -f 1229/2453/6763 1228/2452/6764 1196/2427/6765 -f 1196/2427/6766 1197/2426/6767 1229/2453/6768 -f 1230/2454/6769 1229/2453/6770 1197/2426/6771 -f 1197/2426/6772 1200/2432/6773 1230/2454/6774 -f 1231/2456/6775 1230/2454/6776 1200/2432/6777 -f 1200/2432/6778 1232/2455/6779 1231/2456/6780 -f 1194/2423/6781 705/2422/6782 1233/2457/6783 -f 1233/2457/6784 1234/2458/6785 1194/2423/6786 -f 1201/2433/6787 1232/2455/6788 1200/2432/6789 -f 1200/2432/6790 723/810/6791 1201/2433/6792 -f 1235/2460/6793 1222/2445/6794 1223/2444/6795 -f 1223/2444/6796 1236/2459/6797 1235/2460/6798 -f 1237/2461/6799 1236/2459/6800 1223/2444/6801 -f 1223/2444/6802 1224/2447/6803 1237/2461/6804 -f 1237/2461/6805 1224/2447/6806 1225/2449/6807 -f 1225/2449/6808 1238/2462/6809 1237/2461/6810 -f 1238/2462/6811 1225/2449/6812 1226/2450/6813 -f 1226/2450/6814 1239/2463/6815 1238/2462/6816 -f 1239/2463/6817 1226/2450/6818 1227/2451/6819 -f 1227/2451/6820 1240/2464/6821 1239/2463/6822 -f 1241/2465/6823 1240/2464/6824 1227/2451/6825 -f 1227/2451/6826 1228/2452/6827 1241/2465/6828 -f 1242/2466/6829 1241/2465/6830 1228/2452/6831 -f 1228/2452/6832 1229/2453/6833 1242/2466/6834 -f 1243/2467/6835 1242/2466/6836 1229/2453/6837 -f 1229/2453/6838 1230/2454/6839 1243/2467/6840 -f 1243/2467/6841 1230/2454/6842 1231/2456/6843 -f 1231/2456/6844 1244/2468/6845 1243/2467/6846 -f 1244/2468/6847 1231/2456/6848 1222/2575/6849 -f 1222/2575/6850 1235/2576/6851 1244/2468/6852 -f 1213/1295/6853 1121/1205/6854 1122/1209/6855 -f 1122/1209/6856 1214/1297/6857 1213/1295/6858 -f 1118/1203/6859 1216/1305/6860 1148/1232/6861 -f 1148/1232/6862 1126/1210/6863 1118/1203/6864 -f 1148/2390/6865 1216/2442/6866 1215/2441/6867 -f 1215/2441/6868 1152/2386/6869 1148/2390/6870 -f 1247/2471/6871 1246/2472/6872 1245/2469/6873 -f 1245/2469/6874 1248/2470/6875 1247/2471/6876 -f 1250/2473/6877 1249/2474/6878 1247/2471/6879 -f 1247/2471/6880 1248/2470/6881 1250/2473/6882 -f 1251/2476/6883 1249/2474/6884 1250/2473/6885 -f 1250/2473/6886 1252/2475/6887 1251/2476/6888 -f 1246/2578/6889 1261/2478/6890 1260/2477/6891 -f 1260/2477/6892 1245/2577/6893 1246/2578/6894 -f 1194/2423/6895 1234/2458/6896 728/813/6897 -f 728/813/6898 729/812/6899 1194/2423/6900 -f 1262/2479/6901 1114/1339/6902 728/813/6903 -f 728/813/6904 1234/2458/6905 1262/2479/6906 -f 1114/1339/6907 1262/2479/6908 1201/2433/6909 -f 1201/2433/6910 1113/1338/6911 1114/1339/6912 -f 1263/2480/6913 1262/2479/6914 1234/2458/6915 -f 1234/2458/6916 1233/2457/6917 1263/2480/6918 -f 1264/2481/6919 1233/2457/6920 705/2422/6921 -f 705/2422/6922 1222/2575/6923 1264/2481/6924 -f 1231/2456/6925 1265/2482/6926 1264/2481/6927 -f 1264/2481/6928 1222/2575/6929 1231/2456/6930 -f 1263/2480/6931 1233/2457/6932 1264/2481/6933 -f 1264/2481/6934 1265/2482/6935 1263/2480/6936 -f 1232/2455/6937 1263/2480/6938 1265/2482/6939 -f 1265/2482/6940 1231/2456/6941 1232/2455/6942 -f 1262/2479/6943 1263/2480/6944 1232/2455/6945 -f 1232/2455/6946 1201/2433/6947 1262/2479/6948 -f 1260/2477/6949 1258/2483/6950 1243/2467/6951 -f 1243/2467/6952 1244/2468/6953 1260/2477/6954 -f 1257/2484/6955 1242/2466/6956 1243/2467/6957 -f 1243/2467/6958 1258/2483/6959 1257/2484/6960 -f 1256/2486/6961 1241/2465/6962 1242/2466/6963 -f 1242/2466/6964 1257/2484/6965 1256/2486/6966 -f 1255/2487/6967 1240/2464/6968 1241/2465/6969 -f 1241/2465/6970 1256/2486/6971 1255/2487/6972 -f 1254/2488/6973 1239/2463/6974 1240/2464/6975 -f 1240/2464/6976 1255/2487/6977 1254/2488/6978 -f 1252/2475/6979 1254/2488/6980 1253/2489/6981 -f 1253/2489/6982 1251/2476/6983 1252/2475/6984 -f 1237/2461/6985 1238/2462/6986 1252/2475/6987 -f 1252/2475/6988 1250/2473/6989 1237/2461/6990 -f 1236/2459/6991 1237/2461/6992 1250/2473/6993 -f 1250/2473/6994 1248/2470/6995 1236/2459/6996 -f 1245/2469/6997 1235/2460/6998 1236/2459/6999 -f 1236/2459/7000 1248/2470/7001 1245/2469/7002 -f 1244/2468/7003 1235/2576/7004 1245/2577/7005 -f 1245/2577/7006 1260/2477/7007 1244/2468/7008 -f 1260/2477/7009 1261/2478/7010 1259/2490/7011 -f 1259/2490/7012 1258/2483/7013 1260/2477/7014 -f 1252/2475/7015 1238/2462/7016 1239/2463/7017 -f 1239/2463/7018 1254/2488/7019 1252/2475/7020 -f 587/1398/7021 437/519/7022 443/526/7023 -f 443/526/7024 444/525/7025 587/1398/7026 -f 645/734/7027 640/729/7028 450/535/7029 -f 450/535/7030 451/534/7031 645/734/7032 -f 621/709/7033 624/713/7034 650/739/7035 -f 650/739/7036 620/710/7037 621/709/7038 -f 622/711/7039 623/714/7040 624/2605/7041 -f 624/2605/7042 621/2603/7043 622/711/7044 -f 424/507/7045 420/504/7046 629/718/7047 -f 629/718/7048 622/711/7049 424/507/7050 -f 420/504/7051 421/503/7052 632/721/7053 -f 632/721/7054 629/718/7055 420/504/7056 -f 421/503/7057 604/690/7058 635/724/7059 -f 635/724/7060 632/721/7061 421/503/7062 -f 604/690/7063 605/691/7064 638/727/7065 -f 638/727/7066 635/724/7067 604/690/7068 -f 605/691/7069 449/533/7070 450/535/7071 -f 450/535/7072 638/727/7073 605/691/7074 -f 651/740/7075 617/706/7076 618/707/7077 -f 618/707/7078 620/710/7079 651/740/7080 -f 451/534/7081 446/532/7082 617/706/7083 -f 617/706/7084 651/740/7085 451/534/7086 -f 607/693/7087 608/2569/7088 448/530/7089 -f 448/530/7090 449/533/7091 607/693/7092 -f 642/730/7093 1266/2570/7094 671/759/7095 -f 671/759/7096 641/731/7097 642/730/7098 -f 643/733/7099 1267/2571/7100 1266/2570/7101 -f 1266/2570/7102 642/730/7103 643/733/7104 -f 1268/2572/7105 1267/2571/7106 643/733/7107 -f 643/733/7108 646/736/7109 1268/2572/7110 -f 655/746/7111 1268/2572/7112 646/736/7113 -f 646/736/7114 652/741/7115 655/746/7116 -f 654/2607/7117 655/746/7118 652/741/7119 -f 652/741/7120 653/742/7121 654/2607/7122 -f 653/2606/7123 625/712/7124 626/715/7125 -f 626/715/7126 660/749/7127 653/2606/7128 -f 626/715/7129 627/716/7130 663/752/7131 -f 663/752/7132 660/749/7133 626/715/7134 -f 627/716/7135 630/719/7136 666/755/7137 -f 666/755/7138 663/752/7139 627/716/7140 -f 630/719/7141 633/722/7142 669/758/7143 -f 669/758/7144 666/755/7145 630/719/7146 -f 633/722/7147 636/725/7148 641/731/7149 -f 641/731/7150 669/758/7151 633/722/7152 -f 657/744/7153 688/776/7154 686/775/7155 -f 686/775/7156 656/745/7157 657/744/7158 -f 658/748/7159 690/778/7160 688/2609/7161 -f 688/2609/7162 657/2608/7163 658/748/7164 -f 661/751/7165 692/1351/7166 690/778/7167 -f 690/778/7168 658/748/7169 661/751/7170 -f 664/754/7171 694/2566/7172 692/1351/7173 -f 692/1351/7174 661/751/7175 664/754/7176 -f 673/762/7177 694/2566/7178 664/754/7179 -f 664/754/7180 667/757/7181 673/762/7182 -f 672/763/7183 673/762/7184 667/757/7185 -f 667/757/7186 670/760/7187 672/763/7188 -f 671/759/7189 1266/2570/7190 678/767/7191 -f 678/767/7192 670/760/7193 671/759/7194 -f 1266/2570/7195 1267/2571/7196 681/770/7197 -f 681/770/7198 678/767/7199 1266/2570/7200 -f 1267/2571/7201 1268/2572/7202 684/773/7203 -f 684/773/7204 681/770/7205 1267/2571/7206 -f 684/773/7207 1268/2572/7208 655/746/7209 -f 655/746/7210 656/745/7211 684/773/7212 -f 1270/1432/7213 1269/478/7214 397/475/7215 -f 397/475/7216 1271/1431/7217 1270/1432/7218 -f 1270/1432/7219 1271/1431/7220 1272/1543/7221 -f 1272/1543/7222 1273/1544/7223 1270/1432/7224 -f 1276/1360/7225 1275/1361/7226 1274/1358/7227 -f 1274/1358/7228 1277/1359/7229 1276/1360/7230 -f 1279/1362/7231 1278/1363/7232 1275/1361/7233 -f 1275/1361/7234 1276/1360/7235 1279/1362/7236 -f 1276/1360/7237 1277/1359/7238 1280/1364/7239 -f 1280/1364/7240 1279/1362/7241 1276/1360/7242 -f 1283/1367/7243 1282/1368/7244 1281/1365/7245 -f 1281/1365/7246 1284/1366/7247 1283/1367/7248 -f 1283/1367/7249 1284/1366/7250 1285/1369/7251 -f 1285/1369/7252 1286/1370/7253 1283/1367/7254 -f 1283/1367/7255 1286/1370/7256 1287/1371/7257 -f 1287/1371/7258 1288/1372/7259 1283/1367/7260 -f 1283/1367/7261 1288/1372/7262 1289/1373/7263 -f 1289/1373/7264 1290/1374/7265 1283/1367/7266 -f 1283/1367/7267 1290/1374/7268 1291/1375/7269 -f 1291/1375/7270 1282/1368/7271 1283/1367/7272 -f 1294/1376/7273 1293/1377/7274 1292/479/7275 -f 1292/479/7276 1295/686/7277 1294/1376/7278 -f 1294/1376/7279 1297/1379/7280 1296/1378/7281 -f 1296/1378/7282 1293/1377/7283 1294/1376/7284 -f 1300/1384/7285 1299/1385/7286 1298/1382/7287 -f 1298/1382/7288 1301/1383/7289 1300/1384/7290 -f 1303/2586/7291 1302/1387/7292 1299/1385/7293 -f 1299/1385/7294 1300/1384/7295 1303/2586/7296 -f 1300/1570/7297 1301/1571/7298 1304/1541/7299 -f 1304/1541/7300 1303/1542/7301 1300/1570/7302 -f 1307/1547/7303 1306/1548/7304 1305/1545/7305 -f 1305/1545/7306 1308/1546/7307 1307/1547/7308 -f 1307/1547/7309 1310/1551/7310 1309/1550/7311 -f 1309/1550/7312 1306/1548/7313 1307/1547/7314 -f 1307/1547/7315 1308/1546/7316 1273/1544/7317 -f 1273/1544/7318 1311/1552/7319 1307/1547/7320 -f 1308/1546/7321 1305/1545/7322 1312/1553/7323 -f 1312/1553/7324 1313/1554/7325 1308/1546/7326 -f 1316/1557/7327 1315/1558/7328 1314/1555/7329 -f 1314/1555/7330 1317/1556/7331 1316/1557/7332 -f 1317/1556/7333 1312/1553/7334 1305/1545/7335 -f 1305/1545/7336 1316/1557/7337 1317/1556/7338 -f 1317/1556/7339 1314/1555/7340 1318/1559/7341 -f 1318/1559/7342 1312/1553/7343 1317/1556/7344 -f 1321/1403/7345 1320/1404/7346 1319/1380/7347 -f 1319/1380/7348 1322/1381/7349 1321/1403/7350 -f 1323/1406/7351 1321/1403/7352 1322/1381/7353 -f 1322/1381/7354 1324/1405/7355 1323/1406/7356 -f 1306/1548/7357 1309/1550/7358 1316/1557/7359 -f 1316/1557/7360 1305/1545/7361 1306/1548/7362 -f 1327/1562/7363 1326/1563/7364 1325/1560/7365 -f 1325/1560/7366 1328/1561/7367 1327/1562/7368 -f 1327/1562/7369 1330/1566/7370 1329/1564/7371 -f 1329/1564/7372 1331/1565/7373 1327/1562/7374 -f 1327/1562/7375 1331/1565/7376 1332/1567/7377 -f 1332/1567/7378 1326/1563/7379 1327/1562/7380 -f 1334/1418/7381 1333/1419/7382 1329/1413/7383 -f 1329/1413/7384 1335/1417/7385 1334/1418/7386 -f 1334/1418/7387 1274/1358/7388 1275/1361/7389 -f 1275/1361/7390 1278/1363/7391 1334/1418/7392 -f 1334/1418/7393 1278/1363/7394 1336/1420/7395 -f 1336/1420/7396 1333/1419/7397 1334/1418/7398 -f 1290/1374/7399 1289/1373/7400 1337/1421/7401 -f 1337/1421/7402 1291/1375/7403 1290/1374/7404 -f 1335/1569/7405 1329/1564/7406 1330/1566/7407 -f 1330/1566/7408 1338/1568/7409 1335/1569/7410 -f 1335/1417/7411 1338/1423/7412 1339/1422/7413 -f 1339/1422/7414 1334/1418/7415 1335/1417/7416 -f 1342/1408/7417 1341/1424/7418 1340/1407/7419 -f 1340/1407/7420 1297/1379/7421 1342/1408/7422 -f 1345/1574/7423 1344/1575/7424 1343/1572/7425 -f 1343/1572/7426 1346/1573/7427 1345/1574/7428 -f 1345/1687/7429 1346/2491/7430 1347/1598/7431 -f 1347/1598/7432 1348/1686/7433 1345/1687/7434 -f 1346/1573/7435 1343/1572/7436 1349/1576/7437 -f 1349/1576/7438 1350/1577/7439 1346/1573/7440 -f 1346/2491/7441 1350/2493/7442 1351/2492/7443 -f 1351/2492/7444 1347/1598/7445 1346/2491/7446 -f 1351/1435/7447 1350/1436/7448 1352/1433/7449 -f 1352/1433/7450 1353/1434/7451 1351/1435/7452 -f 1351/1435/7453 1353/1434/7454 1339/1422/7455 -f 1339/1422/7456 1338/1423/7457 1351/1435/7458 -f 1351/2492/7459 1338/1568/7460 1330/1566/7461 -f 1330/1566/7462 1347/1598/7463 1351/2492/7464 -f 1353/1434/7465 1352/1433/7466 1354/1437/7467 -f 1354/1437/7468 1355/1438/7469 1353/1434/7470 -f 1353/1434/7471 1355/1438/7472 1356/1439/7473 -f 1356/1439/7474 1339/1422/7475 1353/1434/7476 -f 1356/1439/7477 1355/1438/7478 1357/1440/7479 -f 1357/1440/7480 1358/1441/7481 1356/1439/7482 -f 1356/1439/7483 1358/1441/7484 1277/1359/7485 -f 1277/1359/7486 1274/1358/7487 1356/1439/7488 -f 1356/1439/7489 1274/1358/7490 1334/1418/7491 -f 1334/1418/7492 1339/1422/7493 1356/1439/7494 -f 1358/1441/7495 1357/1440/7496 1359/1442/7497 -f 1359/1442/7498 1360/1443/7499 1358/1441/7500 -f 1358/1441/7501 1360/1443/7502 1361/1444/7503 -f 1361/1444/7504 1277/1359/7505 1358/1441/7506 -f 1361/1444/7507 1360/1443/7508 1362/1445/7509 -f 1362/1445/7510 1363/1446/7511 1361/1444/7512 -f 1361/1444/7513 1363/1446/7514 1364/1447/7515 -f 1364/1447/7516 1365/1448/7517 1361/1444/7518 -f 1361/1444/7519 1365/1448/7520 1280/1364/7521 -f 1280/1364/7522 1277/1359/7523 1361/1444/7524 -f 1365/1448/7525 1364/1447/7526 1366/1449/7527 -f 1366/1449/7528 1337/1421/7529 1365/1448/7530 -f 1365/1448/7531 1337/1421/7532 1289/1373/7533 -f 1289/1373/7534 1280/1364/7535 1365/1448/7536 -f 1364/1447/7537 1363/1446/7538 1367/1450/7539 -f 1367/1450/7540 1368/1451/7541 1364/1447/7542 -f 1364/1447/7543 1368/1451/7544 1369/1452/7545 -f 1369/1452/7546 1366/1449/7547 1364/1447/7548 -f 1368/1451/7549 1367/1450/7550 1370/1453/7551 -f 1370/1453/7552 1371/1454/7553 1368/1451/7554 -f 1368/1451/7555 1371/1454/7556 1372/1455/7557 -f 1372/1455/7558 1369/1452/7559 1368/1451/7560 -f 1372/1455/7561 1371/1454/7562 1373/1456/7563 -f 1373/1456/7564 1374/1457/7565 1372/1455/7566 -f 1372/1455/7567 1374/1457/7568 1375/1458/7569 -f 1375/1458/7570 1376/1459/7571 1372/1455/7572 -f 1372/1455/7573 1376/1459/7574 1377/1460/7575 -f 1377/1460/7576 1369/1452/7577 1372/1455/7578 -f 1376/1459/7579 1375/1458/7580 1378/1461/7581 -f 1378/1461/7582 1379/1462/7583 1376/1459/7584 -f 1376/1459/7585 1379/1462/7586 1380/1463/7587 -f 1380/1463/7588 1377/1460/7589 1376/1459/7590 -f 1380/1463/7591 1382/1465/7592 1381/1464/7593 -f 1381/1464/7594 1377/1460/7595 1380/1463/7596 -f 1380/2589/7597 1379/2588/7598 1383/1466/7599 -f 1383/1466/7600 1384/1467/7601 1380/2589/7602 -f 1380/2589/7603 1384/1467/7604 1385/1468/7605 -f 1385/1468/7606 1382/2590/7607 1380/2589/7608 -f 1383/2591/7609 1379/1462/7610 1378/1461/7611 -f 1378/1461/7612 1386/1469/7613 1383/2591/7614 -f 1383/2591/7615 1386/1469/7616 1387/1470/7617 -f 1387/1470/7618 1388/1471/7619 1383/2591/7620 -f 1383/1466/7621 1388/2593/7622 1389/1472/7623 -f 1389/1472/7624 1384/1467/7625 1383/1466/7626 -f 1388/2593/7627 1387/2592/7628 1390/1473/7629 -f 1390/1473/7630 1391/1474/7631 1388/2593/7632 -f 1388/2593/7633 1391/1474/7634 1392/1475/7635 -f 1392/1475/7636 1389/1472/7637 1388/2593/7638 -f 1392/1475/7639 1394/1477/7640 1393/1476/7641 -f 1393/1476/7642 1389/1472/7643 1392/1475/7644 -f 1392/1475/7645 1391/1474/7646 1395/1478/7647 -f 1395/1478/7648 1396/1479/7649 1392/1475/7650 -f 1392/1475/7651 1396/1479/7652 1397/1480/7653 -f 1397/1480/7654 1394/1477/7655 1392/1475/7656 -f 1397/1480/7657 1399/1482/7658 1398/1481/7659 -f 1398/1481/7660 1394/1477/7661 1397/1480/7662 -f 1397/1480/7663 1396/1479/7664 1400/1483/7665 -f 1400/1483/7666 1401/1484/7667 1397/1480/7668 -f 1397/1480/7669 1401/1484/7670 1402/1485/7671 -f 1402/1485/7672 1399/1482/7673 1397/1480/7674 -f 1402/1485/7675 1404/1487/7676 1403/1486/7677 -f 1403/1486/7678 1399/1482/7679 1402/1485/7680 -f 1402/1485/7681 1401/1484/7682 1405/1488/7683 -f 1405/1488/7684 1359/1442/7685 1402/1485/7686 -f 1402/1485/7687 1359/1442/7688 1357/1440/7689 -f 1357/1440/7690 1404/1487/7691 1402/1485/7692 -f 1405/1488/7693 1401/1484/7694 1400/1483/7695 -f 1400/1483/7696 1406/1489/7697 1405/1488/7698 -f 1405/1488/7699 1406/1489/7700 1407/1490/7701 -f 1407/1490/7702 1362/1445/7703 1405/1488/7704 -f 1405/1488/7705 1362/1445/7706 1360/1443/7707 -f 1360/1443/7708 1359/1442/7709 1405/1488/7710 -f 1407/1490/7711 1406/1489/7712 1408/1491/7713 -f 1408/1491/7714 1409/1492/7715 1407/1490/7716 -f 1407/1490/7717 1409/1492/7718 1370/1453/7719 -f 1370/1453/7720 1367/1450/7721 1407/1490/7722 -f 1407/1490/7723 1367/1450/7724 1363/1446/7725 -f 1363/1446/7726 1362/1445/7727 1407/1490/7728 -f 1409/1492/7729 1408/1491/7730 1410/1493/7731 -f 1410/1493/7732 1411/1494/7733 1409/1492/7734 -f 1409/1492/7735 1411/1494/7736 1412/1495/7737 -f 1412/1495/7738 1370/1453/7739 1409/1492/7740 -f 1412/1495/7741 1411/1494/7742 1413/1496/7743 -f 1413/1496/7744 1414/1497/7745 1412/1495/7746 -f 1412/1495/7747 1414/1497/7748 1415/1498/7749 -f 1415/1498/7750 1373/1456/7751 1412/1495/7752 -f 1412/1495/7753 1373/1456/7754 1371/1454/7755 -f 1371/1454/7756 1370/1453/7757 1412/1495/7758 -f 1415/1498/7759 1416/1499/7760 1374/1457/7761 -f 1374/1457/7762 1373/1456/7763 1415/1498/7764 -f 1416/1499/7765 1417/1500/7766 1375/1458/7767 -f 1375/1458/7768 1374/1457/7769 1416/1499/7770 -f 1417/1500/7771 1418/1501/7772 1378/1461/7773 -f 1378/1461/7774 1375/1458/7775 1417/1500/7776 -f 1418/1501/7777 1419/1502/7778 1386/1469/7779 -f 1386/1469/7780 1378/1461/7781 1418/1501/7782 -f 1419/1502/7783 1420/1503/7784 1387/1470/7785 -f 1387/1470/7786 1386/1469/7787 1419/1502/7788 -f 1420/2594/7789 1421/1504/7790 1390/1473/7791 -f 1390/1473/7792 1387/2592/7793 1420/2594/7794 -f 1421/1504/7795 1423/1506/7796 1422/1505/7797 -f 1422/1505/7798 1390/1473/7799 1421/1504/7800 -f 1422/1505/7801 1395/1478/7802 1391/1474/7803 -f 1391/1474/7804 1390/1473/7805 1422/1505/7806 -f 1422/1505/7807 1423/1506/7808 1424/1507/7809 -f 1424/1507/7810 1425/1508/7811 1422/1505/7812 -f 1422/1505/7813 1425/1508/7814 1426/1509/7815 -f 1426/1509/7816 1395/1478/7817 1422/1505/7818 -f 1426/1509/7819 1400/1483/7820 1396/1479/7821 -f 1396/1479/7822 1395/1478/7823 1426/1509/7824 -f 1426/1509/7825 1425/1508/7826 1410/1493/7827 -f 1410/1493/7828 1408/1491/7829 1426/1509/7830 -f 1426/1509/7831 1408/1491/7832 1406/1489/7833 -f 1406/1489/7834 1400/1483/7835 1426/1509/7836 -f 1425/1508/7837 1424/1507/7838 1427/1510/7839 -f 1427/1510/7840 1410/1493/7841 1425/1508/7842 -f 1427/1510/7843 1413/1496/7844 1411/1494/7845 -f 1411/1494/7846 1410/1493/7847 1427/1510/7848 -f 1403/1486/7849 1429/1513/7850 1428/1511/7851 -f 1428/1511/7852 1430/1512/7853 1403/1486/7854 -f 1403/1486/7855 1430/1512/7856 1398/1481/7857 -f 1398/1481/7858 1399/1482/7859 1403/1486/7860 -f 1403/1486/7861 1404/1487/7862 1354/1437/7863 -f 1354/1437/7864 1429/1513/7865 1403/1486/7866 -f 1430/1512/7867 1428/1511/7868 1431/1514/7869 -f 1431/1514/7870 1432/1515/7871 1430/1512/7872 -f 1430/1512/7873 1432/1515/7874 1433/1516/7875 -f 1433/1516/7876 1398/1481/7877 1430/1512/7878 -f 1433/1516/7879 1432/1515/7880 1434/1517/7881 -f 1434/1517/7882 1435/1518/7883 1433/1516/7884 -f 1433/1516/7885 1435/1518/7886 1436/1519/7887 -f 1436/1519/7888 1393/1476/7889 1433/1516/7890 -f 1433/1516/7891 1393/1476/7892 1394/1477/7893 -f 1394/1477/7894 1398/1481/7895 1433/1516/7896 -f 1434/1517/7897 1298/1382/7898 1299/1385/7899 -f 1299/1385/7900 1437/1520/7901 1434/1517/7902 -f 1434/1517/7903 1437/1520/7904 1385/1468/7905 -f 1385/1468/7906 1435/1518/7907 1434/1517/7908 -f 1434/1517/7909 1432/1515/7910 1431/1514/7911 -f 1431/1514/7912 1298/1382/7913 1434/1517/7914 -f 1437/1520/7915 1299/1385/7916 1302/1387/7917 -f 1302/1387/7918 1438/1521/7919 1437/1520/7920 -f 1437/1520/7921 1438/1521/7922 1382/2590/7923 -f 1382/2590/7924 1385/1468/7925 1437/1520/7926 -f 1438/2595/7927 1302/2587/7928 1284/1366/7929 -f 1284/1366/7930 1281/1365/7931 1438/2595/7932 -f 1438/2595/7933 1281/1365/7934 1381/1464/7935 -f 1381/1464/7936 1382/1465/7937 1438/2595/7938 -f 1431/1514/7939 1439/1522/7940 1301/1383/7941 -f 1301/1383/7942 1298/1382/7943 1431/1514/7944 -f 1431/1514/7945 1428/1511/7946 1440/1523/7947 -f 1440/1523/7948 1439/1522/7949 1431/1514/7950 -f 1440/1580/7951 1442/1581/7952 1441/1578/7953 -f 1441/1578/7954 1439/1579/7955 1440/1580/7956 -f 1440/1523/7957 1428/1511/7958 1429/1513/7959 -f 1429/1513/7960 1443/1524/7961 1440/1523/7962 -f 1440/1580/7963 1443/1582/7964 1349/1576/7965 -f 1349/1576/7966 1442/1581/7967 1440/1580/7968 -f 1443/1524/7969 1429/1513/7970 1354/1437/7971 -f 1354/1437/7972 1352/1433/7973 1443/1524/7974 -f 1443/1524/7975 1352/1433/7976 1350/1436/7977 -f 1350/1436/7978 1349/1527/7979 1443/1524/7980 -f 1441/1578/7981 1445/1585/7982 1444/1583/7983 -f 1444/1583/7984 1446/1584/7985 1441/1578/7986 -f 1441/1578/7987 1446/1584/7988 1301/1571/7989 -f 1301/1571/7990 1439/1579/7991 1441/1578/7992 -f 1441/1578/7993 1442/1581/7994 1447/1586/7995 -f 1447/1586/7996 1445/1585/7997 1441/1578/7998 -f 1446/1584/7999 1444/1583/8000 1448/1587/8001 -f 1448/1587/8002 1449/1588/8003 1446/1584/8004 -f 1446/1584/8005 1449/1588/8006 1304/1541/8007 -f 1304/1541/8008 1301/1571/8009 1446/1584/8010 -f 1449/1588/8011 1448/1587/8012 1450/1690/8013 -f 1450/1690/8014 1451/1691/8015 1449/1588/8016 -f 1449/1588/8017 1451/1691/8018 1452/2536/8019 -f 1452/2536/8020 1304/1541/8021 1449/1588/8022 -f 1452/2536/8023 1451/1691/8024 1453/2537/8025 -f 1453/2537/8026 1454/2538/8027 1452/2536/8028 -f 1452/2536/8029 1454/2538/8030 1455/2539/8031 -f 1455/2539/8032 1456/2540/8033 1452/2536/8034 -f 1452/2536/8035 1456/2540/8036 1303/1542/8037 -f 1303/1542/8038 1304/1541/8039 1452/2536/8040 -f 1456/2540/8041 1455/2539/8042 1457/2541/8043 -f 1457/2541/8044 1458/2542/8045 1456/2540/8046 -f 1456/2540/8047 1458/2542/8048 1285/2543/8049 -f 1285/2543/8050 1303/1542/8051 1456/2540/8052 -f 1458/2497/8053 1457/2498/8054 1459/2495/8055 -f 1459/2495/8056 1460/2496/8057 1458/2497/8058 -f 1458/2497/8059 1460/2496/8060 1286/2499/8061 -f 1286/2499/8062 1285/2501/8063 1458/2497/8064 -f 1460/2496/8065 1459/2495/8066 1461/2502/8067 -f 1461/2502/8068 1462/2503/8069 1460/2496/8070 -f 1460/2496/8071 1462/2503/8072 1287/2504/8073 -f 1287/2504/8074 1286/2499/8075 1460/2496/8076 -f 1462/2503/8077 1461/2502/8078 1463/2505/8079 -f 1463/2505/8080 1464/2506/8081 1462/2503/8082 -f 1462/2503/8083 1464/2506/8084 1465/2507/8085 -f 1465/2507/8086 1287/2504/8087 1462/2503/8088 -f 1465/2507/8089 1464/2506/8090 1466/2508/8091 -f 1466/2508/8092 1336/2509/8093 1465/2507/8094 -f 1465/1549/8095 1336/1420/8096 1278/1363/8097 -f 1278/1363/8098 1279/1362/8099 1465/1549/8100 -f 1465/1549/8101 1279/1362/8102 1288/1372/8103 -f 1288/1372/8104 1287/1371/8105 1465/1549/8106 -f 1466/2508/8107 1464/2506/8108 1463/2505/8109 -f 1463/2505/8110 1467/2510/8111 1466/2508/8112 -f 1466/2508/8113 1467/2510/8114 1468/2511/8115 -f 1468/2511/8116 1469/2512/8117 1466/2508/8118 -f 1466/2508/8119 1469/2512/8120 1333/2513/8121 -f 1333/2513/8122 1336/2509/8123 1466/2508/8124 -f 1469/2512/8125 1468/2511/8126 1332/1567/8127 -f 1332/1567/8128 1331/1565/8129 1469/2512/8130 -f 1469/2512/8131 1331/1565/8132 1329/1564/8133 -f 1329/1564/8134 1333/2513/8135 1469/2512/8136 -f 1468/2511/8137 1467/2510/8138 1470/2514/8139 -f 1470/2514/8140 1471/2515/8141 1468/2511/8142 -f 1468/2511/8143 1471/2515/8144 1472/2516/8145 -f 1472/2516/8146 1332/1567/8147 1468/2511/8148 -f 1472/2516/8149 1471/2515/8150 1473/2517/8151 -f 1473/2517/8152 1474/2518/8153 1472/2516/8154 -f 1472/2516/8155 1474/2518/8156 1475/2519/8157 -f 1475/2519/8158 1476/2520/8159 1472/2516/8160 -f 1472/2516/8161 1476/2520/8162 1326/1563/8163 -f 1326/1563/8164 1332/1567/8165 1472/2516/8166 -f 1476/2520/8167 1475/2519/8168 1477/2521/8169 -f 1477/2521/8170 1478/2522/8171 1476/2520/8172 -f 1476/2520/8173 1478/2522/8174 1325/1560/8175 -f 1325/1560/8176 1326/1563/8177 1476/2520/8178 -f 1475/2519/8179 1474/2518/8180 1479/2523/8181 -f 1479/2523/8182 1480/2524/8183 1475/2519/8184 -f 1475/2519/8185 1480/2524/8186 1481/2525/8187 -f 1481/2525/8188 1477/2521/8189 1475/2519/8190 -f 1480/2524/8191 1479/2523/8192 1482/1392/8193 -f 1482/1392/8194 1483/1393/8195 1480/2524/8196 -f 1480/2524/8197 1483/1393/8198 1484/1394/8199 -f 1484/1394/8200 1481/2525/8201 1480/2524/8202 -f 1482/1392/8203 1479/2523/8204 1485/2526/8205 -f 1485/2526/8206 391/1396/8207 1482/1392/8208 -f 391/1396/8209 1485/2526/8210 1271/1431/8211 -f 1271/1431/8212 397/475/8213 391/1396/8214 -f 1485/2526/8215 1479/2523/8216 1474/2518/8217 -f 1474/2518/8218 1473/2517/8219 1485/2526/8220 -f 1485/2526/8221 1473/2517/8222 1272/1543/8223 -f 1272/1543/8224 1271/1431/8225 1485/2526/8226 -f 1473/2517/8227 1471/2515/8228 1470/2514/8229 -f 1470/2514/8230 1272/1543/8231 1473/2517/8232 -f 1470/2514/8233 1311/1552/8234 1273/1544/8235 -f 1273/1544/8236 1272/1543/8237 1470/2514/8238 -f 1470/2514/8239 1467/2510/8240 1463/2505/8241 -f 1463/2505/8242 1311/1552/8243 1470/2514/8244 -f 1463/2505/8245 1461/2502/8246 1307/1547/8247 -f 1307/1547/8248 1311/1552/8249 1463/2505/8250 -f 1461/2502/8251 1459/2495/8252 1310/1551/8253 -f 1310/1551/8254 1307/1547/8255 1461/2502/8256 -f 1459/2495/8257 1457/2498/8258 1486/2527/8259 -f 1486/2527/8260 1310/1551/8261 1459/2495/8262 -f 1486/2546/8263 1488/2547/8264 1487/2544/8265 -f 1487/2544/8266 1489/2545/8267 1486/2546/8268 -f 1486/2527/8269 1489/2528/8270 1309/1550/8271 -f 1309/1550/8272 1310/1551/8273 1486/2527/8274 -f 1486/2546/8275 1457/2541/8276 1455/2539/8277 -f 1455/2539/8278 1488/2547/8279 1486/2546/8280 -f 1487/2544/8281 1491/2550/8282 1490/2548/8283 -f 1490/2548/8284 1492/2549/8285 1487/2544/8286 -f 1487/2544/8287 1492/2549/8288 1315/2551/8289 -f 1315/2551/8290 1489/2545/8291 1487/2544/8292 -f 1487/2544/8293 1488/2547/8294 1493/2552/8295 -f 1493/2552/8296 1491/2550/8297 1487/2544/8298 -f 1493/2552/8299 1495/2554/8300 1494/2553/8301 -f 1494/2553/8302 1491/2550/8303 1493/2552/8304 -f 1493/2552/8305 1488/2547/8306 1455/2539/8307 -f 1455/2539/8308 1454/2538/8309 1493/2552/8310 -f 1493/2552/8311 1454/2538/8312 1453/2537/8313 -f 1453/2537/8314 1495/2554/8315 1493/2552/8316 -f 1494/2553/8317 1497/2557/8318 1496/2555/8319 -f 1496/2555/8320 1498/2556/8321 1494/2553/8322 -f 1494/2553/8323 1498/2556/8324 1490/2548/8325 -f 1490/2548/8326 1491/2550/8327 1494/2553/8328 -f 1494/2553/8329 1495/2554/8330 1499/2558/8331 -f 1499/2558/8332 1497/2557/8333 1494/2553/8334 -f 1499/2558/8335 1501/1428/8336 1500/1427/8337 -f 1500/1427/8338 1497/2557/8339 1499/2558/8340 -f 1499/2558/8341 1495/2554/8342 1453/2537/8343 -f 1453/2537/8344 1502/2559/8345 1499/2558/8346 -f 1499/2558/8347 1502/2559/8348 392/1430/8349 -f 392/1430/8350 1501/1428/8351 1499/2558/8352 -f 392/1430/8353 1502/2559/8354 1450/1690/8355 -f 1450/1690/8356 1503/1525/8357 392/1430/8358 -f 1503/1525/8359 1450/1690/8360 1448/1587/8361 -f 1448/1587/8362 599/1526/8363 1503/1525/8364 -f 599/1526/8365 1448/1587/8366 1444/1583/8367 -f 1444/1583/8368 1504/1528/8369 599/1526/8370 -f 1504/1528/8371 1444/1583/8372 1445/1585/8373 -f 1445/1585/8374 600/1529/8375 1504/1528/8376 -f 600/1529/8377 1445/1585/8378 1447/1586/8379 -f 1447/1586/8380 601/1530/8381 600/1529/8382 -f 1502/2559/8383 1453/2537/8384 1451/1691/8385 -f 1451/1691/8386 1450/1690/8387 1502/2559/8388 -f 1500/1427/8389 393/1531/8390 1496/2555/8391 -f 1496/2555/8392 1497/2557/8393 1500/1427/8394 -f 393/1531/8395 602/1533/8396 1294/2560/8397 -f 1294/2560/8398 1496/2555/8399 393/1531/8400 -f 1498/2556/8401 1496/2555/8402 1294/2560/8403 -f 1294/2560/8404 1295/2561/8405 1498/2556/8406 -f 1498/2556/8407 1295/2561/8408 1505/2562/8409 -f 1505/2562/8410 1490/2548/8411 1498/2556/8412 -f 1505/1426/8413 1295/686/8414 1292/479/8415 -f 1292/479/8416 1506/1425/8417 1505/1426/8418 -f 1505/1426/8419 1506/1425/8420 1507/1589/8421 -f 1507/1589/8422 1508/1590/8423 1505/1426/8424 -f 1505/2562/8425 1508/2563/8426 1492/2549/8427 -f 1492/2549/8428 1490/2548/8429 1505/2562/8430 -f 1509/1591/8431 1508/1590/8432 1507/1589/8433 -f 1507/1589/8434 1322/1381/8435 1509/1591/8436 -f 1508/2563/8437 1509/2564/8438 1315/2551/8439 -f 1315/2551/8440 1492/2549/8441 1508/2563/8442 -f 1509/2529/8443 1510/2530/8444 1314/1555/8445 -f 1314/1555/8446 1315/1558/8447 1509/2529/8448 -f 1510/1593/8449 1319/1380/8450 1320/1404/8451 -f 1320/1404/8452 1511/1592/8453 1510/1593/8454 -f 1510/2530/8455 1511/2531/8456 1318/1559/8457 -f 1318/1559/8458 1314/1555/8459 1510/2530/8460 -f 1511/1592/8461 1320/1404/8462 1512/1594/8463 -f 1512/1594/8464 1513/1595/8465 1511/1592/8466 -f 1511/2531/8467 1513/2533/8468 1514/2532/8469 -f 1514/2532/8470 1318/1559/8471 1511/2531/8472 -f 1514/2532/8473 1313/1554/8474 1312/1553/8475 -f 1312/1553/8476 1318/1559/8477 1514/2532/8478 -f 1514/2532/8479 1513/2533/8480 1515/1411/8481 -f 1515/1411/8482 613/1412/8483 1514/2532/8484 -f 1514/2532/8485 613/1412/8486 394/1414/8487 -f 394/1414/8488 1313/1554/8489 1514/2532/8490 -f 1515/1597/8491 1513/1595/8492 1512/1594/8493 -f 1512/1594/8494 395/1596/8495 1515/1597/8496 -f 395/1596/8497 1512/1594/8498 1516/1599/8499 -f 1516/1599/8500 1517/1600/8501 395/1596/8502 -f 1517/1600/8503 1516/1599/8504 1518/1601/8505 -f 1518/1601/8506 1519/1602/8507 1517/1600/8508 -f 1519/1602/8509 1518/1601/8510 1520/1603/8511 -f 1520/1603/8512 1521/1604/8513 1519/1602/8514 -f 1521/1604/8515 1520/1603/8516 1340/2611/8517 -f 1340/2611/8518 1341/2612/8519 1521/1604/8520 -f 1520/1603/8521 1518/1601/8522 1522/1605/8523 -f 1522/1605/8524 1523/1606/8525 1520/1603/8526 -f 1520/1603/8527 1523/1606/8528 1524/1607/8529 -f 1524/1607/8530 1340/2611/8531 1520/1603/8532 -f 1526/1608/8533 1525/1609/8534 1524/1607/8535 -f 1524/1607/8536 1523/1606/8537 1526/1608/8538 -f 1296/1378/8539 1524/2613/8540 1525/2614/8541 -f 1525/2614/8542 1527/1610/8543 1296/1378/8544 -f 1524/2613/8545 1296/1378/8546 1297/1379/8547 -f 1297/1379/8548 1340/1407/8549 1524/2613/8550 -f 1530/1613/8551 1529/2616/8552 1528/1611/8553 -f 1528/1611/8554 1531/1612/8555 1530/1613/8556 -f 1530/1613/8557 1531/1612/8558 1532/1615/8559 -f 1532/1615/8560 1533/1616/8561 1530/1613/8562 -f 1527/1610/8563 1530/1613/8564 1533/1616/8565 -f 1533/1616/8566 1534/1617/8567 1527/1610/8568 -f 1533/1616/8569 1532/1615/8570 1535/1618/8571 -f 1535/1618/8572 1536/1619/8573 1533/1616/8574 -f 1534/1617/8575 1533/1616/8576 1536/1619/8577 -f 1536/1619/8578 1537/1620/8579 1534/1617/8580 -f 1536/1619/8581 1535/1618/8582 1538/1621/8583 -f 1538/1621/8584 1539/1622/8585 1536/1619/8586 -f 1537/1620/8587 1536/1619/8588 1539/1622/8589 -f 1539/1622/8590 1540/1623/8591 1537/1620/8592 -f 1539/1622/8593 1538/1621/8594 1541/1624/8595 -f 1541/1624/8596 1542/1625/8597 1539/1622/8598 -f 1540/1623/8599 1539/1622/8600 1542/1625/8601 -f 1542/1625/8602 1543/1626/8603 1540/1623/8604 -f 1542/1625/8605 1541/1624/8606 1544/1627/8607 -f 1544/1627/8608 1545/1628/8609 1542/1625/8610 -f 1543/1626/8611 1542/1625/8612 1545/1628/8613 -f 1545/1628/8614 1324/1405/8615 1543/1626/8616 -f 1546/1630/8617 1544/1627/8618 1541/1624/8619 -f 1541/1624/8620 1547/1629/8621 1546/1630/8622 -f 1548/1632/8623 1544/1627/8624 1546/1630/8625 -f 1546/1630/8626 1549/1631/8627 1548/1632/8628 -f 1544/1627/8629 1548/1632/8630 1550/1633/8631 -f 1550/1633/8632 1545/1628/8633 1544/1627/8634 -f 1551/1635/8635 1548/1632/8636 1549/1631/8637 -f 1549/1631/8638 1552/1634/8639 1551/1635/8640 -f 1548/1632/8641 1551/1635/8642 1553/1636/8643 -f 1553/1636/8644 1550/1633/8645 1548/1632/8646 -f 1553/1636/8647 1551/1635/8648 1554/1637/8649 -f 1554/1637/8650 1555/1638/8651 1553/1636/8652 -f 1526/1608/8653 1556/1639/8654 1553/1636/8655 -f 1553/1636/8656 1555/1638/8657 1526/1608/8658 -f 1550/1633/8659 1553/1636/8660 1556/1639/8661 -f 1556/1639/8662 1323/1406/8663 1550/1633/8664 -f 1552/1634/8665 1557/1640/8666 1554/1637/8667 -f 1554/1637/8668 1551/1635/8669 1552/1634/8670 -f 1558/1641/8671 1528/2615/8672 1554/1637/8673 -f 1554/1637/8674 1557/1640/8675 1558/1641/8676 -f 1554/1637/8677 1528/2615/8678 1529/1614/8679 -f 1529/1614/8680 1555/1638/8681 1554/1637/8682 -f 1561/1644/8683 1560/1645/8684 1559/2618/8685 -f 1559/2618/8686 1562/1643/8687 1561/1644/8688 -f 1563/1647/8689 1559/1642/8690 1560/2619/8691 -f 1560/2619/8692 1564/1646/8693 1563/1647/8694 -f 1558/2617/8695 1559/1642/8696 1563/1647/8697 -f 1563/1647/8698 1565/1648/8699 1558/2617/8700 -f 1566/1650/8701 1563/1647/8702 1564/1646/8703 -f 1564/1646/8704 1567/1649/8705 1566/1650/8706 -f 1565/1648/8707 1563/1647/8708 1566/1650/8709 -f 1566/1650/8710 1568/1651/8711 1565/1648/8712 -f 1569/1653/8713 1566/1650/8714 1567/1649/8715 -f 1567/1649/8716 1570/1652/8717 1569/1653/8718 -f 1568/1651/8719 1566/1650/8720 1569/1653/8721 -f 1569/1653/8722 1571/1654/8723 1568/1651/8724 -f 1573/1655/8725 1572/1656/8726 1569/1653/8727 -f 1569/1653/8728 1570/1652/8729 1573/1655/8730 -f 1571/1654/8731 1569/1653/8732 1572/1656/8733 -f 1572/1656/8734 1574/1657/8735 1571/1654/8736 -f 1576/1658/8737 1575/1659/8738 1572/1656/8739 -f 1572/1656/8740 1573/1655/8741 1576/1658/8742 -f 1547/1629/8743 1574/1657/8744 1572/1656/8745 -f 1572/1656/8746 1575/1659/8747 1547/1629/8748 -f 1579/1662/8749 1578/1663/8750 1577/1660/8751 -f 1577/1660/8752 1580/1661/8753 1579/1662/8754 -f 1579/1662/8755 1580/1661/8756 1581/1664/8757 -f 1581/1664/8758 1582/1665/8759 1579/1662/8760 -f 1576/1658/8761 1579/1662/8762 1582/1665/8763 -f 1582/1665/8764 1583/1666/8765 1576/1658/8766 -f 1582/1665/8767 1581/1664/8768 1584/1667/8769 -f 1584/1667/8770 1585/1668/8771 1582/1665/8772 -f 1583/1666/8773 1582/1665/8774 1585/1668/8775 -f 1585/1668/8776 1586/1669/8777 1583/1666/8778 -f 1585/1668/8779 1584/1667/8780 1587/1670/8781 -f 1587/1670/8782 1588/1671/8783 1585/1668/8784 -f 1586/1669/8785 1585/1668/8786 1588/1671/8787 -f 1588/1671/8788 1589/1672/8789 1586/1669/8790 -f 1588/1671/8791 1587/1670/8792 1590/1673/8793 -f 1590/1673/8794 1591/1674/8795 1588/1671/8796 -f 1561/1644/8797 1589/1672/8798 1588/1671/8799 -f 1588/1671/8800 1591/1674/8801 1561/1644/8802 -f 1590/1673/8803 1592/1676/8804 1593/1675/8805 -f 1593/1675/8806 1591/1674/8807 1590/1673/8808 -f 1592/2621/8809 1594/1678/8810 1595/1677/8811 -f 1595/1677/8812 1593/2620/8813 1592/2621/8814 -f 1594/1678/8815 1596/1680/8816 1597/1679/8817 -f 1597/1679/8818 1595/1677/8819 1594/1678/8820 -f 1596/1680/8821 1598/1682/8822 1599/1681/8823 -f 1599/1681/8824 1597/1679/8825 1596/1680/8826 -f 1598/1682/8827 1577/1660/8828 1578/1663/8829 -f 1578/1663/8830 1599/1681/8831 1598/1682/8832 -f 1522/1605/8833 1518/1601/8834 1516/1599/8835 -f 1516/1599/8836 1321/1403/8837 1522/1605/8838 -f 1516/1599/8839 1512/1594/8840 1320/1404/8841 -f 1320/1404/8842 1321/1403/8843 1516/1599/8844 -f 1442/1581/8845 1349/1576/8846 1343/1572/8847 -f 1343/1572/8848 1447/1586/8849 1442/1581/8850 -f 1404/1487/8851 1357/1440/8852 1355/1438/8853 -f 1355/1438/8854 1354/1437/8855 1404/1487/8856 -f 1381/1464/8857 1281/1365/8858 1282/1368/8859 -f 1282/1368/8860 1600/1684/8861 1381/1464/8862 -f 1366/1449/8863 1601/1685/8864 1291/1375/8865 -f 1291/1375/8866 1337/1421/8867 1366/1449/8868 -f 1328/1561/8869 1603/2535/8870 1602/2534/8871 -f 1602/2534/8872 1327/1562/8873 1328/1561/8874 -f 1302/2587/8875 1303/1386/8876 1285/1369/8877 -f 1285/1369/8878 1284/1366/8879 1302/2587/8880 -f 1342/1408/8881 1297/1379/8882 1294/1376/8883 -f 1294/1376/8884 602/1683/8885 1342/1408/8886 -f 1602/2534/8887 1603/2535/8888 1348/1686/8889 -f 1348/1686/8890 1347/1598/8891 1602/2534/8892 -f 1602/2534/8893 1347/1598/8894 1330/1566/8895 -f 1330/1566/8896 1327/1562/8897 1602/2534/8898 -f 1291/1375/8899 1601/1685/8900 1600/1684/8901 -f 1600/1684/8902 1282/1368/8903 1291/1375/8904 -f 1289/1373/8905 1288/1372/8906 1279/1362/8907 -f 1279/1362/8908 1280/1364/8909 1289/1373/8910 -f 1269/478/8911 1270/1432/8912 1313/1554/8913 -f 1313/1554/8914 394/1414/8915 1269/478/8916 -f 1436/1519/8917 1435/1518/8918 1385/1468/8919 -f 1385/1468/8920 1384/1467/8921 1436/1519/8922 -f 1436/1519/8923 1384/1467/8924 1389/1472/8925 -f 1389/1472/8926 1393/1476/8927 1436/1519/8928 -f 1308/1546/8929 1313/1554/8930 1270/1432/8931 -f 1270/1432/8932 1273/1544/8933 1308/1546/8934 -f 1600/1684/8935 1601/1685/8936 1604/1688/8937 -f 1604/1688/8938 1605/1689/8939 1600/1684/8940 -f 1366/1449/8941 1369/1452/8942 1604/1688/8943 -f 1604/1688/8944 1601/1685/8945 1366/1449/8946 -f 1605/1689/8947 1604/1688/8948 1369/1452/8949 -f 1369/1452/8950 1377/1460/8951 1605/1689/8952 -f 1381/1464/8953 1600/1684/8954 1605/1689/8955 -f 1605/1689/8956 1377/1460/8957 1381/1464/8958 -f 601/1530/8959 1447/1586/8960 1606/2565/8961 -f 1606/2565/8962 1607/1540/8963 601/1530/8964 -f 1447/1586/8965 1343/1572/8966 1344/1575/8967 -f 1344/1575/8968 1606/2565/8969 1447/1586/8970 -f 1610/1694/8971 1609/1695/8972 1608/1692/8973 -f 1608/1692/8974 1611/1693/8975 1610/1694/8976 -f 1614/1698/8977 1613/1699/8978 1612/1696/8979 -f 1612/1696/8980 1615/1697/8981 1614/1698/8982 -f 1618/1702/8983 1617/1703/8984 1616/1700/8985 -f 1616/1700/8986 1619/1701/8987 1618/1702/8988 -f 1622/1706/8989 1621/1707/8990 1620/1704/8991 -f 1620/1704/8992 1623/1705/8993 1622/1706/8994 -f 1618/1702/8995 1625/1710/8996 1624/1708/8997 -f 1624/1708/8998 1626/1709/8999 1618/1702/9000 -f 1629/1713/9001 1628/1714/9002 1627/1711/9003 -f 1627/1711/9004 1630/1712/9005 1629/1713/9006 -f 1633/1717/9007 1632/1718/9008 1631/1715/9009 -f 1631/1715/9010 1634/1716/9011 1633/1717/9012 -f 1637/1721/9013 1636/1722/9014 1635/1719/9015 -f 1635/1719/9016 1638/1720/9017 1637/1721/9018 -f 1641/1725/9019 1640/1726/9020 1639/1723/9021 -f 1639/1723/9022 1642/1724/9023 1641/1725/9024 -f 1643/1727/9025 1616/1700/9026 1622/1706/9027 -f 1622/1706/9028 1635/1719/9029 1643/1727/9030 -f 1646/1729/9031 1645/1730/9032 1644/1728/9033 -f 1644/1728/9034 1639/1723/9035 1646/1729/9036 -f 1649/1733/9037 1648/1734/9038 1647/1731/9039 -f 1647/1731/9040 1650/1732/9041 1649/1733/9042 -f 1653/1737/9043 1652/1738/9044 1651/1735/9045 -f 1651/1735/9046 1654/1736/9047 1653/1737/9048 -f 1656/1739/9049 1655/1740/9050 1639/1723/9051 -f 1639/1723/9052 1640/1726/9053 1656/1739/9054 -f 1656/1739/9055 1638/1720/9056 1635/1719/9057 -f 1635/1719/9058 1655/1740/9059 1656/1739/9060 -f 1658/1747/9061 1657/1748/9062 1636/1741/9063 -f 1636/1741/9064 1637/1742/9065 1658/1747/9066 -f 1658/1747/9067 1641/1750/9068 1642/2383/9069 -f 1642/2383/9070 1657/1748/9071 1658/1747/9072 -f 1661/1745/9073 1660/1746/9074 1659/1743/9075 -f 1659/1743/9076 1662/1744/9077 1661/1745/9078 -f 1665/1756/9079 1664/1757/9080 1663/1753/9081 -f 1663/1753/9082 1666/1754/9083 1665/1756/9084 -f 1644/1728/9085 1645/1730/9086 1667/1751/9087 -f 1667/1751/9088 1668/1752/9089 1644/1728/9090 -f 1669/1775/9091 1652/1738/9092 1653/1737/9093 -f 1653/1737/9094 1670/1774/9095 1669/1775/9096 -f 1619/1701/9097 1616/1700/9098 1643/1727/9099 -f 1643/1727/9100 1671/1755/9101 1619/1701/9102 -f 1672/1787/9103 1664/1757/9104 1665/1756/9105 -f 1665/1756/9106 1673/1786/9107 1672/1787/9108 -f 1676/1760/9109 1675/1761/9110 1674/1758/9111 -f 1674/1758/9112 1677/1759/9113 1676/1760/9114 -f 1678/1763/9115 1676/1760/9116 1677/1759/9117 -f 1677/1759/9118 1679/1762/9119 1678/1763/9120 -f 1682/1766/9121 1681/1767/9122 1680/1764/9123 -f 1680/1764/9124 1683/1765/9125 1682/1766/9126 -f 1686/1770/9127 1685/1771/9128 1684/1768/9129 -f 1684/1768/9130 1687/1769/9131 1686/1770/9132 -f 1684/1768/9133 1689/1773/9134 1688/1772/9135 -f 1688/1772/9136 1687/1769/9137 1684/1768/9138 -f 1688/1772/9139 1689/1773/9140 1682/1766/9141 -f 1682/1766/9142 1683/1765/9143 1688/1772/9144 -f 1680/1800/9145 1681/1801/9146 1690/1798/9147 -f 1690/1798/9148 1691/1799/9149 1680/1800/9150 -f 1690/1798/9151 1685/1803/9152 1686/1802/9153 -f 1686/1802/9154 1691/1799/9155 1690/1798/9156 -f 1694/1778/9157 1693/1779/9158 1692/1776/9159 -f 1692/1776/9160 1695/1777/9161 1694/1778/9162 -f 1698/1782/9163 1697/1783/9164 1696/1780/9165 -f 1696/1780/9166 1699/1781/9167 1698/1782/9168 -f 1696/1780/9169 1701/1785/9170 1700/1784/9171 -f 1700/1784/9172 1699/1781/9173 1696/1780/9174 -f 1700/1784/9175 1701/1785/9176 1694/1778/9177 -f 1694/1778/9178 1695/1777/9179 1700/1784/9180 -f 1693/1806/9181 1703/1812/9182 1702/1804/9183 -f 1702/1804/9184 1692/1805/9185 1693/1806/9186 -f 1702/1804/9187 1703/1812/9188 1697/1813/9189 -f 1697/1813/9190 1698/1814/9191 1702/1804/9192 -f 1706/1790/9193 1705/1791/9194 1704/1788/9195 -f 1704/1788/9196 1707/1789/9197 1706/1790/9198 -f 1710/1794/9199 1709/1795/9200 1708/1792/9201 -f 1708/1792/9202 1711/1793/9203 1710/1794/9204 -f 1712/1797/9205 1710/1794/9206 1711/1793/9207 -f 1711/1793/9208 1713/1796/9209 1712/1797/9210 -f 1705/1791/9211 1712/1797/9212 1713/1796/9213 -f 1713/1796/9214 1704/1788/9215 1705/1791/9216 -f 1716/1817/9217 1715/1818/9218 1714/1815/9219 -f 1714/1815/9220 1717/1816/9221 1716/1817/9222 -f 1718/1820/9223 1716/1817/9224 1717/1816/9225 -f 1717/1816/9226 1719/1819/9227 1718/1820/9228 -f 1707/1789/9229 1704/1788/9230 1683/1765/9231 -f 1683/1765/9232 1680/1764/9233 1707/1789/9234 -f 1711/1793/9235 1708/1792/9236 1686/1770/9237 -f 1686/1770/9238 1687/1769/9239 1711/1793/9240 -f 1713/1796/9241 1711/1793/9242 1687/1769/9243 -f 1687/1769/9244 1688/1772/9245 1713/1796/9246 -f 1704/1788/9247 1713/1796/9248 1688/1772/9249 -f 1688/1772/9250 1683/1765/9251 1704/1788/9252 -f 1717/1816/9253 1714/1815/9254 1720/1821/9255 -f 1720/1821/9256 1721/1822/9257 1717/1816/9258 -f 1719/1819/9259 1717/1816/9260 1721/1822/9261 -f 1721/1822/9262 1722/1823/9263 1719/1819/9264 -f 1681/1767/9265 1682/1766/9266 1723/1807/9267 -f 1723/1807/9268 1724/1808/9269 1681/1767/9270 -f 1684/1768/9271 1685/1771/9272 1725/1809/9273 -f 1725/1809/9274 1726/1810/9275 1684/1768/9276 -f 1689/1773/9277 1684/1768/9278 1726/1810/9279 -f 1726/1810/9280 1727/1811/9281 1689/1773/9282 -f 1682/1766/9283 1689/1773/9284 1727/1811/9285 -f 1727/1811/9286 1723/1807/9287 1682/1766/9288 -f 1730/1826/9289 1729/1827/9290 1728/1824/9291 -f 1728/1824/9292 1731/1825/9293 1730/1826/9294 -f 1732/1829/9295 1730/1826/9296 1731/1825/9297 -f 1731/1825/9298 1733/1828/9299 1732/1829/9300 -f 1724/1808/9301 1723/1807/9302 1695/1777/9303 -f 1695/1777/9304 1692/1776/9305 1724/1808/9306 -f 1726/1810/9307 1725/1809/9308 1698/1782/9309 -f 1698/1782/9310 1699/1781/9311 1726/1810/9312 -f 1727/1811/9313 1726/1810/9314 1699/1781/9315 -f 1699/1781/9316 1700/1784/9317 1727/1811/9318 -f 1723/1807/9319 1727/1811/9320 1700/1784/9321 -f 1700/1784/9322 1695/1777/9323 1723/1807/9324 -f 1731/1825/9325 1728/1824/9326 1734/1830/9327 -f 1734/1830/9328 1735/1831/9329 1731/1825/9330 -f 1733/1828/9331 1731/1825/9332 1735/1831/9333 -f 1735/1831/9334 1736/1832/9335 1733/1828/9336 -f 1716/1817/9337 1737/1834/9338 1706/1833/9339 -f 1706/1833/9340 1715/1818/9341 1716/1817/9342 -f 1718/1820/9343 1709/1835/9344 1737/1834/9345 -f 1737/1834/9346 1716/1817/9347 1718/1820/9348 -f 1719/1819/9349 1708/1836/9350 1709/1835/9351 -f 1709/1835/9352 1718/1820/9353 1719/1819/9354 -f 1722/1823/9355 1686/1802/9356 1708/1836/9357 -f 1708/1836/9358 1719/1819/9359 1722/1823/9360 -f 1721/1822/9361 1691/1799/9362 1686/1802/9363 -f 1686/1802/9364 1722/1823/9365 1721/1822/9366 -f 1720/1821/9367 1680/1800/9368 1691/1799/9369 -f 1691/1799/9370 1721/1822/9371 1720/1821/9372 -f 1714/1815/9373 1707/1837/9374 1680/1800/9375 -f 1680/1800/9376 1720/1821/9377 1714/1815/9378 -f 1715/1818/9379 1706/1833/9380 1707/1837/9381 -f 1707/1837/9382 1714/1815/9383 1715/1818/9384 -f 1730/1826/9385 1690/1798/9386 1681/1801/9387 -f 1681/1801/9388 1729/1827/9389 1730/1826/9390 -f 1732/1829/9391 1685/1803/9392 1690/1798/9393 -f 1690/1798/9394 1730/1826/9395 1732/1829/9396 -f 1733/1828/9397 1725/1838/9398 1685/1803/9399 -f 1685/1803/9400 1732/1829/9401 1733/1828/9402 -f 1736/1832/9403 1698/1814/9404 1725/1838/9405 -f 1725/1838/9406 1733/1828/9407 1736/1832/9408 -f 1735/1831/9409 1702/1804/9410 1698/1814/9411 -f 1698/1814/9412 1736/1832/9413 1735/1831/9414 -f 1734/1830/9415 1692/1805/9416 1702/1804/9417 -f 1702/1804/9418 1735/1831/9419 1734/1830/9420 -f 1728/1824/9421 1724/1839/9422 1692/1805/9423 -f 1692/1805/9424 1734/1830/9425 1728/1824/9426 -f 1729/1827/9427 1681/1801/9428 1724/1839/9429 -f 1724/1839/9430 1728/1824/9431 1729/1827/9432 -f 1678/1763/9433 1679/1762/9434 1693/1779/9435 -f 1693/1779/9436 1694/1778/9437 1678/1763/9438 -f 1697/1783/9439 1674/1758/9440 1675/1761/9441 -f 1675/1761/9442 1696/1780/9443 1697/1783/9444 -f 1675/1761/9445 1676/1760/9446 1701/1785/9447 -f 1701/1785/9448 1696/1780/9449 1675/1761/9450 -f 1701/1785/9451 1676/1760/9452 1678/1763/9453 -f 1678/1763/9454 1694/1778/9455 1701/1785/9456 -f 1740/1852/9457 1739/1853/9458 1738/1840/9459 -f 1738/1840/9460 1741/1841/9461 1740/1852/9462 -f 1741/1841/9463 1738/1840/9464 1742/1870/9465 -f 1742/1870/9466 1743/1871/9467 1741/1841/9468 -f 1744/1894/9469 1679/1895/9470 1677/1882/9471 -f 1677/1882/9472 1745/1883/9473 1744/1894/9474 -f 1746/1896/9475 1693/1806/9476 1679/1895/9477 -f 1679/1895/9478 1744/1894/9479 1746/1896/9480 -f 1747/1897/9481 1703/1812/9482 1693/1806/9483 -f 1693/1806/9484 1746/1896/9485 1747/1897/9486 -f 1748/1898/9487 1697/1813/9488 1703/1812/9489 -f 1703/1812/9490 1747/1897/9491 1748/1898/9492 -f 1749/1899/9493 1674/1900/9494 1697/1813/9495 -f 1697/1813/9496 1748/1898/9497 1749/1899/9498 -f 1745/1883/9499 1677/1882/9500 1674/1900/9501 -f 1674/1900/9502 1749/1899/9503 1745/1883/9504 -f 1739/1853/9505 1744/1894/9506 1745/1883/9507 -f 1745/1883/9508 1738/1840/9509 1739/1853/9510 -f 1740/1852/9511 1746/1896/9512 1744/1894/9513 -f 1744/1894/9514 1739/1853/9515 1740/1852/9516 -f 1741/1841/9517 1747/1897/9518 1746/1896/9519 -f 1746/1896/9520 1740/1852/9521 1741/1841/9522 -f 1743/1871/9523 1748/1898/9524 1747/1897/9525 -f 1747/1897/9526 1741/1841/9527 1743/1871/9528 -f 1742/1870/9529 1749/1899/9530 1748/1898/9531 -f 1748/1898/9532 1743/1871/9533 1742/1870/9534 -f 1738/1840/9535 1745/1883/9536 1749/1899/9537 -f 1749/1899/9538 1742/1870/9539 1738/1840/9540 -f 1752/1908/9541 1751/1909/9542 1750/1901/9543 -f 1750/1901/9544 1753/1902/9545 1752/1908/9546 -f 1754/1911/9547 1648/1734/9548 1649/1733/9549 -f 1649/1733/9550 1755/1910/9551 1754/1911/9552 -f 1756/1913/9553 1751/1909/9554 1752/1908/9555 -f 1752/1908/9556 1757/1912/9557 1756/1913/9558 -f 1622/1706/9559 1623/1705/9560 1655/1740/9561 -f 1655/1740/9562 1635/1719/9563 1622/1706/9564 -f 1655/1740/9565 1623/1705/9566 1646/1729/9567 -f 1646/1729/9568 1639/1723/9569 1655/1740/9570 -f 1659/1743/9571 1660/1746/9572 1619/1701/9573 -f 1619/1701/9574 1671/1755/9575 1659/1743/9576 -f 1661/1745/9577 1662/1744/9578 1758/1842/9579 -f 1758/1842/9580 1759/1843/9581 1661/1745/9582 -f 1761/1844/9583 1760/1845/9584 1668/1752/9585 -f 1668/1752/9586 1667/1751/9587 1761/1844/9588 -f 1638/1720/9589 1705/1791/9590 1706/1790/9591 -f 1706/1790/9592 1637/1721/9593 1638/1720/9594 -f 1709/1795/9595 1710/1794/9596 1640/1726/9597 -f 1640/1726/9598 1641/1725/9599 1709/1795/9600 -f 1640/1726/9601 1710/1794/9602 1712/1797/9603 -f 1712/1797/9604 1656/1739/9605 1640/1726/9606 -f 1712/1797/9607 1705/1791/9608 1638/1720/9609 -f 1638/1720/9610 1656/1739/9611 1712/1797/9612 -f 1637/1742/9613 1706/1833/9614 1737/1834/9615 -f 1737/1834/9616 1658/1747/9617 1637/1742/9618 -f 1737/1834/9619 1709/1835/9620 1641/1750/9621 -f 1641/1750/9622 1658/1747/9623 1737/1834/9624 -f 1763/1847/9625 1762/1848/9626 1671/1755/9627 -f 1671/1755/9628 1764/1846/9629 1763/1847/9630 -f 1766/1849/9631 1765/1850/9632 1635/1719/9633 -f 1635/1719/9634 1636/1722/9635 1766/1849/9636 -f 1767/1851/9637 1643/1727/9638 1635/1719/9639 -f 1635/1719/9640 1765/1850/9641 1767/1851/9642 -f 1767/1851/9643 1764/1846/9644 1671/1755/9645 -f 1671/1755/9646 1643/1727/9647 1767/1851/9648 -f 1768/1915/9649 1766/1916/9650 1636/1741/9651 -f 1636/1741/9652 1769/1914/9653 1768/1915/9654 -f 1772/1856/9655 1771/1857/9656 1770/1854/9657 -f 1770/1854/9658 1773/1855/9659 1772/1856/9660 -f 1774/1859/9661 1772/1856/9662 1773/1855/9663 -f 1773/1855/9664 1775/1858/9665 1774/1859/9666 -f 1778/1862/9667 1777/1863/9668 1776/1860/9669 -f 1776/1860/9670 1779/1861/9671 1778/1862/9672 -f 1782/1866/9673 1781/1867/9674 1780/1864/9675 -f 1780/1864/9676 1783/1865/9677 1782/1866/9678 -f 1780/1864/9679 1785/1869/9680 1784/1868/9681 -f 1784/1868/9682 1783/1865/9683 1780/1864/9684 -f 1784/1868/9685 1785/1869/9686 1778/1862/9687 -f 1778/1862/9688 1779/1861/9689 1784/1868/9690 -f 1776/1919/9691 1777/1920/9692 1786/1917/9693 -f 1786/1917/9694 1787/1918/9695 1776/1919/9696 -f 1786/1917/9697 1781/1922/9698 1782/1921/9699 -f 1782/1921/9700 1787/1918/9701 1786/1917/9702 -f 1790/1874/9703 1789/1875/9704 1788/1872/9705 -f 1788/1872/9706 1791/1873/9707 1790/1874/9708 -f 1794/1878/9709 1793/1879/9710 1792/1876/9711 -f 1792/1876/9712 1795/1877/9713 1794/1878/9714 -f 1792/1876/9715 1797/1881/9716 1796/1880/9717 -f 1796/1880/9718 1795/1877/9719 1792/1876/9720 -f 1796/1880/9721 1797/1881/9722 1790/1874/9723 -f 1790/1874/9724 1791/1873/9725 1796/1880/9726 -f 1789/1925/9727 1799/1926/9728 1798/1923/9729 -f 1798/1923/9730 1788/1924/9731 1789/1925/9732 -f 1798/1923/9733 1799/1926/9734 1793/1927/9735 -f 1793/1927/9736 1794/1928/9737 1798/1923/9738 -f 1802/1886/9739 1801/1887/9740 1800/1884/9741 -f 1800/1884/9742 1803/1885/9743 1802/1886/9744 -f 1806/1890/9745 1805/1891/9746 1804/1888/9747 -f 1804/1888/9748 1807/1889/9749 1806/1890/9750 -f 1808/1893/9751 1806/1890/9752 1807/1889/9753 -f 1807/1889/9754 1809/1892/9755 1808/1893/9756 -f 1801/1887/9757 1808/1893/9758 1809/1892/9759 -f 1809/1892/9760 1800/1884/9761 1801/1887/9762 -f 1812/1936/9763 1811/1953/9764 1810/1929/9765 -f 1810/1929/9766 1813/1935/9767 1812/1936/9768 -f 1814/1965/9769 1812/1936/9770 1813/1935/9771 -f 1813/1935/9772 1815/1954/9773 1814/1965/9774 -f 1803/1885/9775 1800/1884/9776 1779/1861/9777 -f 1779/1861/9778 1776/1860/9779 1803/1885/9780 -f 1807/1889/9781 1804/1888/9782 1782/1866/9783 -f 1782/1866/9784 1783/1865/9785 1807/1889/9786 -f 1809/1892/9787 1807/1889/9788 1783/1865/9789 -f 1783/1865/9790 1784/1868/9791 1809/1892/9792 -f 1800/1884/9793 1809/1892/9794 1784/1868/9795 -f 1784/1868/9796 1779/1861/9797 1800/1884/9798 -f 1813/1935/9799 1810/1929/9800 1816/1966/9801 -f 1816/1966/9802 1817/1977/9803 1813/1935/9804 -f 1815/1954/9805 1813/1935/9806 1817/1977/9807 -f 1817/1977/9808 1818/1978/9809 1815/1954/9810 -f 1777/1863/9811 1778/1862/9812 1819/1903/9813 -f 1819/1903/9814 1820/1904/9815 1777/1863/9816 -f 1780/1864/9817 1781/1867/9818 1821/1905/9819 -f 1821/1905/9820 1822/1906/9821 1780/1864/9822 -f 1785/1869/9823 1780/1864/9824 1822/1906/9825 -f 1822/1906/9826 1823/1907/9827 1785/1869/9828 -f 1778/1862/9829 1785/1869/9830 1823/1907/9831 -f 1823/1907/9832 1819/1903/9833 1778/1862/9834 -f 1826/1981/9835 1825/1982/9836 1824/1979/9837 -f 1824/1979/9838 1827/1980/9839 1826/1981/9840 -f 1828/1984/9841 1826/1981/9842 1827/1980/9843 -f 1827/1980/9844 1829/1983/9845 1828/1984/9846 -f 1820/1904/9847 1819/1903/9848 1791/1873/9849 -f 1791/1873/9850 1788/1872/9851 1820/1904/9852 -f 1822/1906/9853 1821/1905/9854 1794/1878/9855 -f 1794/1878/9856 1795/1877/9857 1822/1906/9858 -f 1823/1907/9859 1822/1906/9860 1795/1877/9861 -f 1795/1877/9862 1796/1880/9863 1823/1907/9864 -f 1819/1903/9865 1823/1907/9866 1796/1880/9867 -f 1796/1880/9868 1791/1873/9869 1819/1903/9870 -f 1827/1980/9871 1824/1979/9872 1830/1985/9873 -f 1830/1985/9874 1831/1991/9875 1827/1980/9876 -f 1829/1983/9877 1827/1980/9878 1831/1991/9879 -f 1831/1991/9880 1832/1992/9881 1829/1983/9882 -f 1812/1936/9883 1833/1994/9884 1802/1993/9885 -f 1802/1993/9886 1811/1953/9887 1812/1936/9888 -f 1814/1965/9889 1805/1995/9890 1833/1994/9891 -f 1833/1994/9892 1812/1936/9893 1814/1965/9894 -f 1815/1954/9895 1804/1996/9896 1805/1995/9897 -f 1805/1995/9898 1814/1965/9899 1815/1954/9900 -f 1818/1978/9901 1782/1921/9902 1804/1996/9903 -f 1804/1996/9904 1815/1954/9905 1818/1978/9906 -f 1817/1977/9907 1787/1918/9908 1782/1921/9909 -f 1782/1921/9910 1818/1978/9911 1817/1977/9912 -f 1816/1966/9913 1776/1919/9914 1787/1918/9915 -f 1787/1918/9916 1817/1977/9917 1816/1966/9918 -f 1810/1929/9919 1803/1997/9920 1776/1919/9921 -f 1776/1919/9922 1816/1966/9923 1810/1929/9924 -f 1811/1953/9925 1802/1993/9926 1803/1997/9927 -f 1803/1997/9928 1810/1929/9929 1811/1953/9930 -f 1826/1981/9931 1786/1917/9932 1777/1920/9933 -f 1777/1920/9934 1825/1982/9935 1826/1981/9936 -f 1828/1984/9937 1781/1922/9938 1786/1917/9939 -f 1786/1917/9940 1826/1981/9941 1828/1984/9942 -f 1829/1983/9943 1821/1998/9944 1781/1922/9945 -f 1781/1922/9946 1828/1984/9947 1829/1983/9948 -f 1832/1992/9949 1794/1928/9950 1821/1998/9951 -f 1821/1998/9952 1829/1983/9953 1832/1992/9954 -f 1831/1991/9955 1798/1923/9956 1794/1928/9957 -f 1794/1928/9958 1832/1992/9959 1831/1991/9960 -f 1830/1985/9961 1788/1924/9962 1798/1923/9963 -f 1798/1923/9964 1831/1991/9965 1830/1985/9966 -f 1824/1979/9967 1820/1999/9968 1788/1924/9969 -f 1788/1924/9970 1830/1985/9971 1824/1979/9972 -f 1825/1982/9973 1777/1920/9974 1820/1999/9975 -f 1820/1999/9976 1824/1979/9977 1825/1982/9978 -f 1774/1859/9979 1775/1858/9980 1789/1875/9981 -f 1789/1875/9982 1790/1874/9983 1774/1859/9984 -f 1793/1879/9985 1770/1854/9986 1771/1857/9987 -f 1771/1857/9988 1792/1876/9989 1793/1879/9990 -f 1771/1857/9991 1772/1856/9992 1797/1881/9993 -f 1797/1881/9994 1792/1876/9995 1771/1857/9996 -f 1797/1881/9997 1772/1856/9998 1774/1859/9999 -f 1774/1859/10000 1790/1874/10001 1797/1881/10002 -f 1836/2002/10003 1835/2003/10004 1834/2000/10005 -f 1834/2000/10006 1837/2001/10007 1836/2002/10008 -f 1837/2001/10009 1834/2000/10010 1838/2004/10011 -f 1838/2004/10012 1839/2005/10013 1837/2001/10014 -f 1840/2008/10015 1775/2009/10016 1773/2006/10017 -f 1773/2006/10018 1841/2007/10019 1840/2008/10020 -f 1842/2010/10021 1789/1925/10022 1775/2009/10023 -f 1775/2009/10024 1840/2008/10025 1842/2010/10026 -f 1843/2011/10027 1799/1926/10028 1789/1925/10029 -f 1789/1925/10030 1842/2010/10031 1843/2011/10032 -f 1844/2012/10033 1793/1927/10034 1799/1926/10035 -f 1799/1926/10036 1843/2011/10037 1844/2012/10038 -f 1845/2018/10039 1770/2019/10040 1793/1927/10041 -f 1793/1927/10042 1844/2012/10043 1845/2018/10044 -f 1841/2007/10045 1773/2006/10046 1770/2019/10047 -f 1770/2019/10048 1845/2018/10049 1841/2007/10050 -f 1835/2003/10051 1840/2008/10052 1841/2007/10053 -f 1841/2007/10054 1834/2000/10055 1835/2003/10056 -f 1836/2002/10057 1842/2010/10058 1840/2008/10059 -f 1840/2008/10060 1835/2003/10061 1836/2002/10062 -f 1837/2001/10063 1843/2011/10064 1842/2010/10065 -f 1842/2010/10066 1836/2002/10067 1837/2001/10068 -f 1839/2005/10069 1844/2012/10070 1843/2011/10071 -f 1843/2011/10072 1837/2001/10073 1839/2005/10074 -f 1838/2004/10075 1845/2018/10076 1844/2012/10077 -f 1844/2012/10078 1839/2005/10079 1838/2004/10080 -f 1834/2000/10081 1841/2007/10082 1845/2018/10083 -f 1845/2018/10084 1838/2004/10085 1834/2000/10086 -f 1764/1846/10087 1801/1887/10088 1802/1886/10089 -f 1802/1886/10090 1763/1847/10091 1764/1846/10092 -f 1805/1891/10093 1806/1890/10094 1765/1850/10095 -f 1765/1850/10096 1766/1849/10097 1805/1891/10098 -f 1765/1850/10099 1806/1890/10100 1808/1893/10101 -f 1808/1893/10102 1767/1851/10103 1765/1850/10104 -f 1808/1893/10105 1801/1887/10106 1764/1846/10107 -f 1764/1846/10108 1767/1851/10109 1808/1893/10110 -f 1763/2036/10111 1802/1993/10112 1833/1994/10113 -f 1833/1994/10114 1768/1915/10115 1763/2036/10116 -f 1833/1994/10117 1805/1995/10118 1766/1916/10119 -f 1766/1916/10120 1768/1915/10121 1833/1994/10122 -f 1846/1931/10123 1758/1842/10124 1662/1744/10125 -f 1662/1744/10126 1847/1930/10127 1846/1931/10128 -f 1849/1932/10129 1848/1933/10130 1671/1755/10131 -f 1671/1755/10132 1762/1848/10133 1849/1932/10134 -f 1850/1934/10135 1659/1743/10136 1671/1755/10137 -f 1671/1755/10138 1848/1933/10139 1850/1934/10140 -f 1850/1934/10141 1847/1930/10142 1662/1744/10143 -f 1662/1744/10144 1659/1743/10145 1850/1934/10146 -f 1852/2049/10147 1851/2060/10148 1758/2037/10149 -f 1758/2037/10150 1846/2048/10151 1852/2049/10152 -f 1852/2049/10153 1849/2062/10154 1762/2061/10155 -f 1762/2061/10156 1851/2060/10157 1852/2049/10158 -f 1855/1939/10159 1854/1940/10160 1853/1937/10161 -f 1853/1937/10162 1856/1938/10163 1855/1939/10164 -f 1857/1942/10165 1855/1939/10166 1856/1938/10167 -f 1856/1938/10168 1858/1941/10169 1857/1942/10170 -f 1861/1945/10171 1860/1946/10172 1859/1943/10173 -f 1859/1943/10174 1862/1944/10175 1861/1945/10176 -f 1865/1949/10177 1864/1950/10178 1863/1947/10179 -f 1863/1947/10180 1866/1948/10181 1865/1949/10182 -f 1863/1947/10183 1868/1952/10184 1867/1951/10185 -f 1867/1951/10186 1866/1948/10187 1863/1947/10188 -f 1867/1951/10189 1868/1952/10190 1861/1945/10191 -f 1861/1945/10192 1862/1944/10193 1867/1951/10194 -f 1859/2065/10195 1860/2066/10196 1869/2063/10197 -f 1869/2063/10198 1870/2064/10199 1859/2065/10200 -f 1869/2063/10201 1864/2068/10202 1865/2067/10203 -f 1865/2067/10204 1870/2064/10205 1869/2063/10206 -f 1873/1957/10207 1872/1958/10208 1871/1955/10209 -f 1871/1955/10210 1874/1956/10211 1873/1957/10212 -f 1877/1961/10213 1876/1962/10214 1875/1959/10215 -f 1875/1959/10216 1878/1960/10217 1877/1961/10218 -f 1875/1959/10219 1880/1964/10220 1879/1963/10221 -f 1879/1963/10222 1878/1960/10223 1875/1959/10224 -f 1879/1963/10225 1880/1964/10226 1873/1957/10227 -f 1873/1957/10228 1874/1956/10229 1879/1963/10230 -f 1872/2076/10231 1882/2077/10232 1881/2074/10233 -f 1881/2074/10234 1871/2075/10235 1872/2076/10236 -f 1881/2074/10237 1882/2077/10238 1876/2078/10239 -f 1876/2078/10240 1877/2079/10241 1881/2074/10242 -f 1885/1969/10243 1884/1970/10244 1883/1967/10245 -f 1883/1967/10246 1886/1968/10247 1885/1969/10248 -f 1889/1973/10249 1888/1974/10250 1887/1971/10251 -f 1887/1971/10252 1890/1972/10253 1889/1973/10254 -f 1891/1976/10255 1889/1973/10256 1890/1972/10257 -f 1890/1972/10258 1892/1975/10259 1891/1976/10260 -f 1884/1970/10261 1891/1976/10262 1892/1975/10263 -f 1892/1975/10264 1883/1967/10265 1884/1970/10266 -f 1895/2082/10267 1894/2083/10268 1893/2080/10269 -f 1893/2080/10270 1896/2081/10271 1895/2082/10272 -f 1897/2085/10273 1895/2082/10274 1896/2081/10275 -f 1896/2081/10276 1898/2084/10277 1897/2085/10278 -f 1886/1968/10279 1883/1967/10280 1862/1944/10281 -f 1862/1944/10282 1859/1943/10283 1886/1968/10284 -f 1890/1972/10285 1887/1971/10286 1865/1949/10287 -f 1865/1949/10288 1866/1948/10289 1890/1972/10290 -f 1892/1975/10291 1890/1972/10292 1866/1948/10293 -f 1866/1948/10294 1867/1951/10295 1892/1975/10296 -f 1883/1967/10297 1892/1975/10298 1867/1951/10299 -f 1867/1951/10300 1862/1944/10301 1883/1967/10302 -f 1896/2081/10303 1893/2080/10304 1899/2086/10305 -f 1899/2086/10306 1900/2087/10307 1896/2081/10308 -f 1898/2084/10309 1896/2081/10310 1900/2087/10311 -f 1900/2087/10312 1901/2088/10313 1898/2084/10314 -f 1860/1946/10315 1861/1945/10316 1902/1986/10317 -f 1902/1986/10318 1903/1987/10319 1860/1946/10320 -f 1863/1947/10321 1864/1950/10322 1904/1988/10323 -f 1904/1988/10324 1905/1989/10325 1863/1947/10326 -f 1868/1952/10327 1863/1947/10328 1905/1989/10329 -f 1905/1989/10330 1906/1990/10331 1868/1952/10332 -f 1861/1945/10333 1868/1952/10334 1906/1990/10335 -f 1906/1990/10336 1902/1986/10337 1861/1945/10338 -f 1909/2091/10339 1908/2092/10340 1907/2089/10341 -f 1907/2089/10342 1910/2090/10343 1909/2091/10344 -f 1911/2094/10345 1909/2091/10346 1910/2090/10347 -f 1910/2090/10348 1912/2093/10349 1911/2094/10350 -f 1903/1987/10351 1902/1986/10352 1874/1956/10353 -f 1874/1956/10354 1871/1955/10355 1903/1987/10356 -f 1905/1989/10357 1904/1988/10358 1877/1961/10359 -f 1877/1961/10360 1878/1960/10361 1905/1989/10362 -f 1906/1990/10363 1905/1989/10364 1878/1960/10365 -f 1878/1960/10366 1879/1963/10367 1906/1990/10368 -f 1902/1986/10369 1906/1990/10370 1879/1963/10371 -f 1879/1963/10372 1874/1956/10373 1902/1986/10374 -f 1910/2090/10375 1907/2089/10376 1913/2095/10377 -f 1913/2095/10378 1914/2096/10379 1910/2090/10380 -f 1912/2093/10381 1910/2090/10382 1914/2096/10383 -f 1914/2096/10384 1915/2097/10385 1912/2093/10386 -f 1895/2082/10387 1916/2099/10388 1885/2098/10389 -f 1885/2098/10390 1894/2083/10391 1895/2082/10392 -f 1897/2085/10393 1888/2100/10394 1916/2099/10395 -f 1916/2099/10396 1895/2082/10397 1897/2085/10398 -f 1898/2084/10399 1887/2104/10400 1888/2100/10401 -f 1888/2100/10402 1897/2085/10403 1898/2084/10404 -f 1901/2088/10405 1865/2067/10406 1887/2104/10407 -f 1887/2104/10408 1898/2084/10409 1901/2088/10410 -f 1900/2087/10411 1870/2064/10412 1865/2067/10413 -f 1865/2067/10414 1901/2088/10415 1900/2087/10416 -f 1899/2086/10417 1859/2065/10418 1870/2064/10419 -f 1870/2064/10420 1900/2087/10421 1899/2086/10422 -f 1893/2080/10423 1886/2105/10424 1859/2065/10425 -f 1859/2065/10426 1899/2086/10427 1893/2080/10428 -f 1894/2083/10429 1885/2098/10430 1886/2105/10431 -f 1886/2105/10432 1893/2080/10433 1894/2083/10434 -f 1909/2091/10435 1869/2063/10436 1860/2066/10437 -f 1860/2066/10438 1908/2092/10439 1909/2091/10440 -f 1911/2094/10441 1864/2068/10442 1869/2063/10443 -f 1869/2063/10444 1909/2091/10445 1911/2094/10446 -f 1912/2093/10447 1904/2106/10448 1864/2068/10449 -f 1864/2068/10450 1911/2094/10451 1912/2093/10452 -f 1915/2097/10453 1877/2079/10454 1904/2106/10455 -f 1904/2106/10456 1912/2093/10457 1915/2097/10458 -f 1914/2096/10459 1881/2074/10460 1877/2079/10461 -f 1877/2079/10462 1915/2097/10463 1914/2096/10464 -f 1913/2095/10465 1871/2075/10466 1881/2074/10467 -f 1881/2074/10468 1914/2096/10469 1913/2095/10470 -f 1907/2089/10471 1903/2128/10472 1871/2075/10473 -f 1871/2075/10474 1913/2095/10475 1907/2089/10476 -f 1908/2092/10477 1860/2066/10478 1903/2128/10479 -f 1903/2128/10480 1907/2089/10481 1908/2092/10482 -f 1857/1942/10483 1858/1941/10484 1872/1958/10485 -f 1872/1958/10486 1873/1957/10487 1857/1942/10488 -f 1876/1962/10489 1853/1937/10490 1854/1940/10491 -f 1854/1940/10492 1875/1959/10493 1876/1962/10494 -f 1854/1940/10495 1855/1939/10496 1880/1964/10497 -f 1880/1964/10498 1875/1959/10499 1854/1940/10500 -f 1880/1964/10501 1855/1939/10502 1857/1942/10503 -f 1857/1942/10504 1873/1957/10505 1880/1964/10506 -f 1919/2133/10507 1918/2134/10508 1917/2129/10509 -f 1917/2129/10510 1920/2132/10511 1919/2133/10512 -f 1920/2132/10513 1917/2129/10514 1921/2135/10515 -f 1921/2135/10516 1922/2136/10517 1920/2132/10518 -f 1923/2140/10519 1858/2141/10520 1856/2137/10521 -f 1856/2137/10522 1924/2139/10523 1923/2140/10524 -f 1925/2142/10525 1872/2076/10526 1858/2141/10527 -f 1858/2141/10528 1923/2140/10529 1925/2142/10530 -f 1926/2143/10531 1882/2077/10532 1872/2076/10533 -f 1872/2076/10534 1925/2142/10535 1926/2143/10536 -f 1927/2148/10537 1876/2078/10538 1882/2077/10539 -f 1882/2077/10540 1926/2143/10541 1927/2148/10542 -f 1928/2149/10543 1853/2150/10544 1876/2078/10545 -f 1876/2078/10546 1927/2148/10547 1928/2149/10548 -f 1924/2139/10549 1856/2137/10550 1853/2150/10551 -f 1853/2150/10552 1928/2149/10553 1924/2139/10554 -f 1918/2134/10555 1923/2140/10556 1924/2139/10557 -f 1924/2139/10558 1917/2129/10559 1918/2134/10560 -f 1919/2133/10561 1925/2142/10562 1923/2140/10563 -f 1923/2140/10564 1918/2134/10565 1919/2133/10566 -f 1920/2132/10567 1926/2143/10568 1925/2142/10569 -f 1925/2142/10570 1919/2133/10571 1920/2132/10572 -f 1922/2136/10573 1927/2148/10574 1926/2143/10575 -f 1926/2143/10576 1920/2132/10577 1922/2136/10578 -f 1921/2135/10579 1928/2149/10580 1927/2148/10581 -f 1927/2148/10582 1922/2136/10583 1921/2135/10584 -f 1917/2129/10585 1924/2139/10586 1928/2149/10587 -f 1928/2149/10588 1921/2135/10589 1917/2129/10590 -f 1847/1930/10591 1884/1970/10592 1885/1969/10593 -f 1885/1969/10594 1846/1931/10595 1847/1930/10596 -f 1888/1974/10597 1889/1973/10598 1848/1933/10599 -f 1848/1933/10600 1849/1932/10601 1888/1974/10602 -f 1848/1933/10603 1889/1973/10604 1891/1976/10605 -f 1891/1976/10606 1850/1934/10607 1848/1933/10608 -f 1891/1976/10609 1884/1970/10610 1847/1930/10611 -f 1847/1930/10612 1850/1934/10613 1891/1976/10614 -f 1846/2048/10615 1885/2098/10616 1916/2099/10617 -f 1916/2099/10618 1852/2049/10619 1846/2048/10620 -f 1916/2099/10621 1888/2100/10622 1849/2062/10623 -f 1849/2062/10624 1852/2049/10625 1916/2099/10626 -f 1929/2014/10627 1642/1724/10628 1639/1723/10629 -f 1639/1723/10630 1930/2013/10631 1929/2014/10632 -f 1932/2015/10633 1931/2016/10634 1668/1752/10635 -f 1668/1752/10636 1760/1845/10637 1932/2015/10638 -f 1933/2017/10639 1644/1728/10640 1668/1752/10641 -f 1668/1752/10642 1931/2016/10643 1933/2017/10644 -f 1933/2017/10645 1930/2013/10646 1639/1723/10647 -f 1639/1723/10648 1644/1728/10649 1933/2017/10650 -f 1935/2152/10651 1934/2153/10652 1642/1749/10653 -f 1642/1749/10654 1929/2151/10655 1935/2152/10656 -f 1935/2152/10657 1932/2160/10658 1760/2159/10659 -f 1760/2159/10660 1934/2153/10661 1935/2152/10662 -f 1938/2022/10663 1937/2023/10664 1936/2020/10665 -f 1936/2020/10666 1939/2021/10667 1938/2022/10668 -f 1940/2025/10669 1938/2022/10670 1939/2021/10671 -f 1939/2021/10672 1941/2024/10673 1940/2025/10674 -f 1944/2028/10675 1943/2029/10676 1942/2026/10677 -f 1942/2026/10678 1945/2027/10679 1944/2028/10680 -f 1948/2032/10681 1947/2033/10682 1946/2030/10683 -f 1946/2030/10684 1949/2031/10685 1948/2032/10686 -f 1946/2030/10687 1951/2035/10688 1950/2034/10689 -f 1950/2034/10690 1949/2031/10691 1946/2030/10692 -f 1950/2034/10693 1951/2035/10694 1944/2028/10695 -f 1944/2028/10696 1945/2027/10697 1950/2034/10698 -f 1942/2163/10699 1943/2164/10700 1952/2161/10701 -f 1952/2161/10702 1953/2162/10703 1942/2163/10704 -f 1952/2161/10705 1947/2167/10706 1948/2166/10707 -f 1948/2166/10708 1953/2162/10709 1952/2161/10710 -f 1956/2040/10711 1955/2041/10712 1954/2038/10713 -f 1954/2038/10714 1957/2039/10715 1956/2040/10716 -f 1960/2044/10717 1959/2045/10718 1958/2042/10719 -f 1958/2042/10720 1961/2043/10721 1960/2044/10722 -f 1958/2042/10723 1963/2047/10724 1962/2046/10725 -f 1962/2046/10726 1961/2043/10727 1958/2042/10728 -f 1962/2046/10729 1963/2047/10730 1956/2040/10731 -f 1956/2040/10732 1957/2039/10733 1962/2046/10734 -f 1955/2170/10735 1965/2171/10736 1964/2168/10737 -f 1964/2168/10738 1954/2169/10739 1955/2170/10740 -f 1964/2168/10741 1965/2171/10742 1959/2172/10743 -f 1959/2172/10744 1960/2173/10745 1964/2168/10746 -f 1968/2052/10747 1967/2053/10748 1966/2050/10749 -f 1966/2050/10750 1969/2051/10751 1968/2052/10752 -f 1972/2056/10753 1971/2057/10754 1970/2054/10755 -f 1970/2054/10756 1973/2055/10757 1972/2056/10758 -f 1974/2059/10759 1972/2056/10760 1973/2055/10761 -f 1973/2055/10762 1975/2058/10763 1974/2059/10764 -f 1967/2053/10765 1974/2059/10766 1975/2058/10767 -f 1975/2058/10768 1966/2050/10769 1967/2053/10770 -f 1978/2183/10771 1977/2185/10772 1976/2174/10773 -f 1976/2174/10774 1979/2175/10775 1978/2183/10776 -f 1980/2187/10777 1978/2183/10778 1979/2175/10779 -f 1979/2175/10780 1981/2186/10781 1980/2187/10782 -f 1969/2051/10783 1966/2050/10784 1945/2027/10785 -f 1945/2027/10786 1942/2026/10787 1969/2051/10788 -f 1973/2055/10789 1970/2054/10790 1948/2032/10791 -f 1948/2032/10792 1949/2031/10793 1973/2055/10794 -f 1975/2058/10795 1973/2055/10796 1949/2031/10797 -f 1949/2031/10798 1950/2034/10799 1975/2058/10800 -f 1966/2050/10801 1975/2058/10802 1950/2034/10803 -f 1950/2034/10804 1945/2027/10805 1966/2050/10806 -f 1979/2175/10807 1976/2174/10808 1982/2188/10809 -f 1982/2188/10810 1983/2189/10811 1979/2175/10812 -f 1981/2186/10813 1979/2175/10814 1983/2189/10815 -f 1983/2189/10816 1984/2190/10817 1981/2186/10818 -f 1943/2029/10819 1944/2028/10820 1985/2069/10821 -f 1985/2069/10822 1986/2070/10823 1943/2029/10824 -f 1946/2030/10825 1947/2033/10826 1987/2071/10827 -f 1987/2071/10828 1988/2072/10829 1946/2030/10830 -f 1951/2035/10831 1946/2030/10832 1988/2072/10833 -f 1988/2072/10834 1989/2073/10835 1951/2035/10836 -f 1944/2028/10837 1951/2035/10838 1989/2073/10839 -f 1989/2073/10840 1985/2069/10841 1944/2028/10842 -f 1992/2196/10843 1991/2197/10844 1990/2191/10845 -f 1990/2191/10846 1993/2195/10847 1992/2196/10848 -f 1994/2205/10849 1992/2196/10850 1993/2195/10851 -f 1993/2195/10852 1995/2198/10853 1994/2205/10854 -f 1986/2070/10855 1985/2069/10856 1957/2039/10857 -f 1957/2039/10858 1954/2038/10859 1986/2070/10860 -f 1988/2072/10861 1987/2071/10862 1960/2044/10863 -f 1960/2044/10864 1961/2043/10865 1988/2072/10866 -f 1989/2073/10867 1988/2072/10868 1961/2043/10869 -f 1961/2043/10870 1962/2046/10871 1989/2073/10872 -f 1985/2069/10873 1989/2073/10874 1962/2046/10875 -f 1962/2046/10876 1957/2039/10877 1985/2069/10878 -f 1993/2195/10879 1990/2191/10880 1996/2212/10881 -f 1996/2212/10882 1997/2213/10883 1993/2195/10884 -f 1995/2198/10885 1993/2195/10886 1997/2213/10887 -f 1997/2213/10888 1998/2214/10889 1995/2198/10890 -f 1978/2183/10891 1999/2216/10892 1968/2215/10893 -f 1968/2215/10894 1977/2185/10895 1978/2183/10896 -f 1980/2187/10897 1971/2217/10898 1999/2216/10899 -f 1999/2216/10900 1978/2183/10901 1980/2187/10902 -f 1981/2186/10903 1970/2218/10904 1971/2217/10905 -f 1971/2217/10906 1980/2187/10907 1981/2186/10908 -f 1984/2190/10909 1948/2166/10910 1970/2218/10911 -f 1970/2218/10912 1981/2186/10913 1984/2190/10914 -f 1983/2189/10915 1953/2162/10916 1948/2166/10917 -f 1948/2166/10918 1984/2190/10919 1983/2189/10920 -f 1982/2188/10921 1942/2163/10922 1953/2162/10923 -f 1953/2162/10924 1983/2189/10925 1982/2188/10926 -f 1976/2174/10927 1969/2219/10928 1942/2163/10929 -f 1942/2163/10930 1982/2188/10931 1976/2174/10932 -f 1977/2185/10933 1968/2215/10934 1969/2219/10935 -f 1969/2219/10936 1976/2174/10937 1977/2185/10938 -f 1992/2196/10939 1952/2161/10940 1943/2164/10941 -f 1943/2164/10942 1991/2197/10943 1992/2196/10944 -f 1994/2205/10945 1947/2167/10946 1952/2161/10947 -f 1952/2161/10948 1992/2196/10949 1994/2205/10950 -f 1995/2198/10951 1987/2220/10952 1947/2167/10953 -f 1947/2167/10954 1994/2205/10955 1995/2198/10956 -f 1998/2214/10957 1960/2173/10958 1987/2220/10959 -f 1987/2220/10960 1995/2198/10961 1998/2214/10962 -f 1997/2213/10963 1964/2168/10964 1960/2173/10965 -f 1960/2173/10966 1998/2214/10967 1997/2213/10968 -f 1996/2212/10969 1954/2169/10970 1964/2168/10971 -f 1964/2168/10972 1997/2213/10973 1996/2212/10974 -f 1990/2191/10975 1986/2221/10976 1954/2169/10977 -f 1954/2169/10978 1996/2212/10979 1990/2191/10980 -f 1991/2197/10981 1943/2164/10982 1986/2221/10983 -f 1986/2221/10984 1990/2191/10985 1991/2197/10986 -f 1940/2025/10987 1941/2024/10988 1955/2041/10989 -f 1955/2041/10990 1956/2040/10991 1940/2025/10992 -f 1959/2045/10993 1936/2020/10994 1937/2023/10995 -f 1937/2023/10996 1958/2042/10997 1959/2045/10998 -f 1937/2023/10999 1938/2022/11000 1963/2047/11001 -f 1963/2047/11002 1958/2042/11003 1937/2023/11004 -f 1963/2047/11005 1938/2022/11006 1940/2025/11007 -f 1940/2025/11008 1956/2040/11009 1963/2047/11010 -f 2002/2224/11011 2001/2252/11012 2000/2222/11013 -f 2000/2222/11014 2003/2223/11015 2002/2224/11016 -f 2003/2223/11017 2000/2222/11018 2004/2253/11019 -f 2004/2253/11020 2005/2254/11021 2003/2223/11022 -f 2006/2260/11023 1941/2261/11024 1939/2255/11025 -f 1939/2255/11026 2007/2259/11027 2006/2260/11028 -f 2008/2262/11029 1955/2170/11030 1941/2261/11031 -f 1941/2261/11032 2006/2260/11033 2008/2262/11034 -f 2009/2263/11035 1965/2171/11036 1955/2170/11037 -f 1955/2170/11038 2008/2262/11039 2009/2263/11040 -f 2010/2264/11041 1959/2172/11042 1965/2171/11043 -f 1965/2171/11044 2009/2263/11045 2010/2264/11046 -f 2011/2265/11047 1936/2266/11048 1959/2172/11049 -f 1959/2172/11050 2010/2264/11051 2011/2265/11052 -f 2007/2259/11053 1939/2255/11054 1936/2266/11055 -f 1936/2266/11056 2011/2265/11057 2007/2259/11058 -f 2001/2252/11059 2006/2260/11060 2007/2259/11061 -f 2007/2259/11062 2000/2222/11063 2001/2252/11064 -f 2002/2224/11065 2008/2262/11066 2006/2260/11067 -f 2006/2260/11068 2001/2252/11069 2002/2224/11070 -f 2003/2223/11071 2009/2263/11072 2008/2262/11073 -f 2008/2262/11074 2002/2224/11075 2003/2223/11076 -f 2005/2254/11077 2010/2264/11078 2009/2263/11079 -f 2009/2263/11080 2003/2223/11081 2005/2254/11082 -f 2004/2253/11083 2011/2265/11084 2010/2264/11085 -f 2010/2264/11086 2005/2254/11087 2004/2253/11088 -f 2000/2222/11089 2007/2259/11090 2011/2265/11091 -f 2011/2265/11092 2004/2253/11093 2000/2222/11094 -f 1930/2013/11095 1967/2053/11096 1968/2052/11097 -f 1968/2052/11098 1929/2014/11099 1930/2013/11100 -f 1971/2057/11101 1972/2056/11102 1931/2016/11103 -f 1931/2016/11104 1932/2015/11105 1971/2057/11106 -f 1931/2016/11107 1972/2056/11108 1974/2059/11109 -f 1974/2059/11110 1933/2017/11111 1931/2016/11112 -f 1974/2059/11113 1967/2053/11114 1930/2013/11115 -f 1930/2013/11116 1933/2017/11117 1974/2059/11118 -f 1929/2151/11119 1968/2215/11120 1999/2216/11121 -f 1999/2216/11122 1935/2152/11123 1929/2151/11124 -f 1999/2216/11125 1971/2217/11126 1932/2160/11127 -f 1932/2160/11128 1935/2152/11129 1999/2216/11130 -f 1654/1736/11131 1642/1749/11132 1934/2153/11133 -f 1934/2153/11134 1653/1737/11135 1654/1736/11136 -f 1651/1735/11137 2012/2267/11138 1642/2579/11139 -f 1642/2579/11140 1654/1736/11141 1651/1735/11142 -f 1652/1738/11143 2013/2268/11144 2012/2267/11145 -f 2012/2267/11146 1651/1735/11147 1652/1738/11148 -f 1669/1775/11149 1761/2269/11150 2013/2268/11151 -f 2013/2268/11152 1652/1738/11153 1669/1775/11154 -f 1670/1774/11155 1760/2159/11156 1761/2269/11157 -f 1761/2269/11158 1669/1775/11159 1670/1774/11160 -f 1653/1737/11161 1934/2153/11162 1760/2159/11163 -f 1760/2159/11164 1670/1774/11165 1653/1737/11166 -f 1650/1732/11167 1636/1741/11168 1657/1748/11169 -f 1657/1748/11170 1649/1733/11171 1650/1732/11172 -f 1647/1731/11173 2014/2270/11174 1636/1741/11175 -f 1636/1741/11176 1650/1732/11177 1647/1731/11178 -f 1648/1734/11179 2015/2271/11180 2014/2270/11181 -f 2014/2270/11182 1647/1731/11183 1648/1734/11184 -f 1754/1911/11185 2012/2267/11186 2015/2271/11187 -f 2015/2271/11188 1648/1734/11189 1754/1911/11190 -f 1755/1910/11191 1642/2579/11192 2012/2267/11193 -f 2012/2267/11194 1754/1911/11195 1755/1910/11196 -f 1649/1733/11197 1657/1748/11198 1642/2383/11199 -f 1642/2383/11200 1755/1910/11201 1649/1733/11202 -f 1752/1908/11203 1769/1914/11204 1636/1741/11205 -f 1636/1741/11206 1757/1912/11207 1752/1908/11208 -f 1753/1902/11209 1762/2061/11210 1769/1914/11211 -f 1769/1914/11212 1752/1908/11213 1753/1902/11214 -f 1750/1901/11215 1634/1716/11216 1762/2061/11217 -f 1762/2061/11218 1753/1902/11219 1750/1901/11220 -f 1751/1909/11221 2016/2272/11222 1634/1716/11223 -f 1634/1716/11224 1750/1901/11225 1751/1909/11226 -f 1756/1913/11227 2014/2270/11228 2016/2272/11229 -f 2016/2272/11230 1751/1909/11231 1756/1913/11232 -f 1757/1912/11233 1636/1741/11234 2014/2270/11235 -f 2014/2270/11236 1756/1913/11237 1757/1912/11238 -f 1666/1754/11239 1758/2037/11240 1851/2060/11241 -f 1851/2060/11242 1665/1756/11243 1666/1754/11244 -f 1663/1753/11245 1759/2273/11246 1758/2037/11247 -f 1758/2037/11248 1666/1754/11249 1663/1753/11250 -f 1664/1757/11251 1631/1715/11252 1759/2273/11253 -f 1759/2273/11254 1663/1753/11255 1664/1757/11256 -f 1672/1787/11257 1634/1716/11258 1631/1715/11259 -f 1631/1715/11260 1664/1757/11261 1672/1787/11262 -f 1673/1786/11263 1762/2061/11264 1634/1716/11265 -f 1634/1716/11266 1672/1787/11267 1673/1786/11268 -f 1665/1756/11269 1851/2060/11270 1762/2061/11271 -f 1762/2061/11272 1673/1786/11273 1665/1756/11274 -f 1763/2036/11275 1768/1915/11276 1769/1914/11277 -f 1769/1914/11278 1762/2061/11279 1763/2036/11280 -f 1661/1745/11281 1759/1843/11282 2017/2101/11283 -f 2017/2101/11284 2018/2102/11285 1661/1745/11286 -f 1617/1703/11287 1618/1702/11288 1626/1709/11289 -f 1626/1709/11290 2019/2103/11291 1617/1703/11292 -f 2016/2272/11293 2014/2270/11294 2020/2274/11295 -f 2020/2274/11296 2021/2275/11297 2016/2272/11298 -f 1625/1710/11299 1618/1702/11300 1619/1701/11301 -f 1619/1701/11302 1660/1746/11303 1625/1710/11304 -f 1628/1714/11305 2012/2267/11306 2013/2268/11307 -f 2013/2268/11308 2022/2276/11309 1628/1714/11310 -f 2015/2271/11311 2012/2267/11312 1628/1714/11313 -f 1628/1714/11314 1629/1713/11315 2015/2271/11316 -f 2025/2109/11317 2024/2110/11318 2023/2107/11319 -f 2023/2107/11320 2026/2108/11321 2025/2109/11322 -f 2027/2112/11323 2026/2108/11324 2023/2107/11325 -f 2023/2107/11326 2028/2111/11327 2027/2112/11328 -f 2030/2114/11329 2029/2115/11330 2027/2112/11331 -f 2027/2112/11332 2031/2113/11333 2030/2114/11334 -f 2026/2108/11335 2033/2117/11336 2032/2116/11337 -f 2032/2116/11338 2025/2109/11339 2026/2108/11340 -f 2029/2115/11341 2033/2117/11342 2026/2108/11343 -f 2026/2108/11344 2027/2112/11345 2029/2115/11346 -f 1615/1697/11347 2035/2119/11348 2034/2118/11349 -f 2034/2118/11350 1614/1698/11351 1615/1697/11352 -f 2038/2122/11353 2037/2123/11354 2036/2120/11355 -f 2036/2120/11356 2039/2121/11357 2038/2122/11358 -f 2040/2125/11359 2037/2123/11360 2038/2122/11361 -f 2038/2122/11362 2041/2124/11363 2040/2125/11364 -f 2039/2121/11365 2036/2120/11366 2042/2126/11367 -f 2042/2126/11368 2043/2127/11369 2039/2121/11370 -f 2043/2279/11371 2042/2280/11372 2044/2277/11373 -f 2044/2277/11374 2045/2278/11375 2043/2279/11376 -f 2045/2278/11377 2044/2277/11378 2046/2281/11379 -f 2046/2281/11380 2047/2282/11381 2045/2278/11382 -f 2046/2131/11383 2040/2125/11384 2041/2124/11385 -f 2041/2124/11386 2047/2130/11387 2046/2131/11388 -f 2050/2285/11389 2049/2286/11390 2048/2283/11391 -f 2048/2283/11392 2051/2284/11393 2050/2285/11394 -f 2052/2288/11395 2050/2285/11396 2051/2284/11397 -f 2051/2284/11398 2053/2287/11399 2052/2288/11400 -f 2032/2116/11401 2033/2117/11402 2038/2122/11403 -f 2038/2122/11404 2039/2121/11405 2032/2116/11406 -f 2033/2117/11407 2029/2115/11408 2041/2124/11409 -f 2041/2124/11410 2038/2122/11411 2033/2117/11412 -f 2054/2138/11413 2032/2116/11414 2039/2121/11415 -f 2039/2121/11416 2043/2127/11417 2054/2138/11418 -f 2051/2284/11419 2048/2283/11420 2055/2289/11421 -f 2055/2289/11422 2056/2290/11423 2051/2284/11424 -f 2053/2287/11425 2051/2284/11426 2056/2290/11427 -f 2056/2290/11428 2057/2291/11429 2053/2287/11430 -f 2029/2115/11431 2030/2114/11432 2047/2130/11433 -f 2047/2130/11434 2041/2124/11435 2029/2115/11436 -f 2050/2285/11437 2059/2293/11438 2058/2292/11439 -f 2058/2292/11440 2049/2286/11441 2050/2285/11442 -f 2052/2288/11443 2031/2294/11444 2059/2293/11445 -f 2059/2293/11446 2050/2285/11447 2052/2288/11448 -f 2053/2287/11449 2030/2295/11450 2031/2294/11451 -f 2031/2294/11452 2052/2288/11453 2053/2287/11454 -f 2057/2291/11455 2047/2282/11456 2030/2295/11457 -f 2030/2295/11458 2053/2287/11459 2057/2291/11460 -f 2056/2290/11461 2045/2278/11462 2047/2282/11463 -f 2047/2282/11464 2057/2291/11465 2056/2290/11466 -f 2055/2289/11467 2043/2279/11468 2045/2278/11469 -f 2045/2278/11470 2056/2290/11471 2055/2289/11472 -f 2048/2283/11473 2054/2296/11474 2043/2279/11475 -f 2043/2279/11476 2055/2289/11477 2048/2283/11478 -f 2049/2286/11479 2058/2292/11480 2054/2296/11481 -f 2054/2296/11482 2048/2283/11483 2049/2286/11484 -f 1615/1697/11485 1612/1696/11486 2060/2144/11487 -f 2060/2144/11488 2061/2145/11489 1615/1697/11490 -f 2035/2119/11491 1615/1697/11492 2061/2145/11493 -f 2061/2145/11494 2062/2146/11495 2035/2119/11496 -f 2060/2144/11497 1612/1696/11498 1613/1699/11499 -f 1613/1699/11500 2063/2147/11501 2060/2144/11502 -f 2066/2299/11503 2065/2300/11504 2064/2297/11505 -f 2064/2297/11506 2067/2298/11507 2066/2299/11508 -f 2067/2298/11509 2064/2297/11510 2068/2301/11511 -f 2068/2301/11512 2069/2302/11513 2067/2298/11514 -f 2070/2154/11515 2034/2118/11516 2035/2119/11517 -f 2035/2119/11518 2062/2146/11519 2070/2154/11520 -f 2036/2120/11521 2037/2123/11522 2071/2155/11523 -f 2071/2155/11524 2072/2156/11525 2036/2120/11526 -f 2037/2123/11527 2040/2125/11528 2073/2157/11529 -f 2073/2157/11530 2071/2155/11531 2037/2123/11532 -f 2042/2126/11533 2036/2120/11534 2072/2156/11535 -f 2072/2156/11536 2074/2158/11537 2042/2126/11538 -f 2077/2305/11539 2076/2306/11540 2075/2303/11541 -f 2075/2303/11542 2078/2304/11543 2077/2305/11544 -f 2079/2308/11545 2077/2305/11546 2078/2304/11547 -f 2078/2304/11548 2080/2307/11549 2079/2308/11550 -f 2040/2125/11551 2046/2131/11552 2081/2165/11553 -f 2081/2165/11554 2073/2157/11555 2040/2125/11556 -f 2072/2156/11557 2071/2155/11558 2061/2145/11559 -f 2061/2145/11560 2060/2144/11561 2072/2156/11562 -f 2071/2155/11563 2073/2157/11564 2062/2146/11565 -f 2062/2146/11566 2061/2145/11567 2071/2155/11568 -f 2074/2158/11569 2072/2156/11570 2060/2144/11571 -f 2060/2144/11572 2063/2147/11573 2074/2158/11574 -f 2078/2304/11575 2075/2303/11576 2082/2309/11577 -f 2082/2309/11578 2083/2310/11579 2078/2304/11580 -f 2080/2307/11581 2078/2304/11582 2083/2310/11583 -f 2083/2310/11584 2084/2311/11585 2080/2307/11586 -f 2073/2157/11587 2081/2165/11588 2070/2154/11589 -f 2070/2154/11590 2062/2146/11591 2073/2157/11592 -f 2077/2305/11593 2044/2277/11594 2042/2280/11595 -f 2042/2280/11596 2076/2306/11597 2077/2305/11598 -f 2079/2308/11599 2046/2281/11600 2044/2277/11601 -f 2044/2277/11602 2077/2305/11603 2079/2308/11604 -f 2080/2307/11605 2081/2312/11606 2046/2281/11607 -f 2046/2281/11608 2079/2308/11609 2080/2307/11610 -f 2084/2311/11611 2070/2313/11612 2081/2312/11613 -f 2081/2312/11614 2080/2307/11615 2084/2311/11616 -f 2083/2310/11617 2085/2314/11618 2070/2313/11619 -f 2070/2313/11620 2084/2311/11621 2083/2310/11622 -f 2082/2309/11623 2063/2315/11624 2085/2314/11625 -f 2085/2314/11626 2083/2310/11627 2082/2309/11628 -f 2075/2303/11629 2074/2316/11630 2063/2315/11631 -f 2063/2315/11632 2082/2309/11633 2075/2303/11634 -f 2076/2306/11635 2042/2280/11636 2074/2316/11637 -f 2074/2316/11638 2075/2303/11639 2076/2306/11640 -f 2086/2319/11641 1613/2320/11642 1614/2317/11643 -f 1614/2317/11644 2087/2318/11645 2086/2319/11646 -f 2088/2321/11647 2063/2315/11648 1613/2320/11649 -f 1613/2320/11650 2086/2319/11651 2088/2321/11652 -f 2089/2322/11653 2085/2314/11654 2063/2315/11655 -f 2063/2315/11656 2088/2321/11657 2089/2322/11658 -f 2090/2323/11659 2070/2313/11660 2085/2314/11661 -f 2085/2314/11662 2089/2322/11663 2090/2323/11664 -f 2091/2324/11665 2034/2325/11666 2070/2313/11667 -f 2070/2313/11668 2090/2323/11669 2091/2324/11670 -f 2087/2318/11671 1614/2317/11672 2034/2325/11673 -f 2034/2325/11674 2091/2324/11675 2087/2318/11676 -f 2065/2300/11677 2086/2319/11678 2087/2318/11679 -f 2087/2318/11680 2064/2297/11681 2065/2300/11682 -f 2066/2299/11683 2088/2321/11684 2086/2319/11685 -f 2086/2319/11686 2065/2300/11687 2066/2299/11688 -f 2067/2298/11689 2089/2322/11690 2088/2321/11691 -f 2088/2321/11692 2066/2299/11693 2067/2298/11694 -f 2069/2302/11695 2090/2323/11696 2089/2322/11697 -f 2089/2322/11698 2067/2298/11699 2069/2302/11700 -f 2068/2301/11701 2091/2324/11702 2090/2323/11703 -f 2090/2323/11704 2069/2302/11705 2068/2301/11706 -f 2064/2297/11707 2087/2318/11708 2091/2324/11709 -f 2091/2324/11710 2068/2301/11711 2064/2297/11712 -f 1646/1729/11713 2093/2177/11714 2092/2176/11715 -f 2092/2176/11716 1645/1730/11717 1646/1729/11718 -f 2096/2180/11719 2095/2181/11720 2094/2178/11721 -f 2094/2178/11722 2097/2179/11723 2096/2180/11724 -f 2098/2182/11725 1621/1707/11726 1617/1703/11727 -f 1617/1703/11728 2019/2103/11729 2098/2182/11730 -f 2017/2326/11731 1759/2273/11732 1631/1715/11733 -f 1631/1715/11734 1632/1718/11735 2017/2326/11736 -f 2099/2329/11737 1608/2330/11738 1609/2327/11739 -f 1609/2327/11740 2100/2328/11741 2099/2329/11742 -f 1633/1717/11743 1634/1716/11744 2016/2272/11745 -f 2016/2272/11746 2021/2275/11747 1633/1717/11748 -f 2102/2333/11749 1627/1711/11750 2101/2331/11751 -f 2101/2331/11752 2103/2332/11753 2102/2333/11754 -f 1628/1714/11755 2022/2276/11756 2101/2331/11757 -f 2101/2331/11758 1627/1711/11759 1628/1714/11760 -f 2105/2336/11761 2104/2337/11762 2024/2334/11763 -f 2024/2334/11764 2025/2335/11765 2105/2336/11766 -f 2020/2274/11767 2014/2270/11768 2015/2271/11769 -f 2015/2271/11770 1629/1713/11771 2020/2274/11772 -f 2102/2333/11773 2106/2338/11774 1630/1712/11775 -f 1630/1712/11776 1627/1711/11777 2102/2333/11778 -f 2020/2274/11779 1629/1713/11780 1630/1712/11781 -f 1630/1712/11782 2107/2339/11783 2020/2274/11784 -f 2108/2184/11785 1667/1751/11786 1645/1730/11787 -f 1645/1730/11788 2092/2176/11789 2108/2184/11790 -f 1761/1844/11791 1667/1751/11792 2108/2184/11793 -f 2108/2184/11794 2109/2192/11795 1761/1844/11796 -f 2013/2268/11797 1761/2269/11798 2109/2340/11799 -f 2109/2340/11800 2022/2276/11801 2013/2268/11802 -f 2110/2193/11803 1620/1704/11804 1621/1707/11805 -f 1621/1707/11806 2098/2182/11807 2110/2193/11808 -f 2111/2341/11809 2101/2331/11810 2022/2276/11811 -f 2022/2276/11812 2104/2337/11813 2111/2341/11814 -f 2112/2342/11815 2103/2332/11816 2101/2331/11817 -f 2101/2331/11818 2111/2341/11819 2112/2342/11820 -f 2114/2343/11821 2113/2344/11822 2103/2332/11823 -f 2103/2332/11824 2112/2342/11825 2114/2343/11826 -f 2115/2345/11827 2097/2346/11828 2113/2344/11829 -f 2113/2344/11830 2114/2343/11831 2115/2345/11832 -f 2116/2199/11833 2096/2180/11834 2097/2179/11835 -f 2097/2179/11836 2115/2194/11837 2116/2199/11838 -f 2093/2177/11839 1620/1704/11840 2110/2193/11841 -f 2110/2193/11842 2117/2200/11843 2093/2177/11844 -f 2117/2200/11845 2110/2193/11846 2096/2180/11847 -f 2096/2180/11848 2116/2199/11849 2117/2200/11850 -f 2118/2202/11851 2027/2112/11852 2028/2111/11853 -f 2028/2111/11854 2119/2201/11855 2118/2202/11856 -f 2059/2293/11857 2114/2343/11858 2112/2342/11859 -f 2112/2342/11860 2058/2292/11861 2059/2293/11862 -f 2115/2345/11863 2114/2343/11864 2059/2293/11865 -f 2059/2293/11866 2031/2294/11867 2115/2345/11868 -f 2120/2203/11869 2116/2199/11870 2115/2194/11871 -f 2115/2194/11872 2031/2113/11873 2120/2203/11874 -f 2117/2200/11875 2116/2199/11876 2120/2203/11877 -f 2120/2203/11878 2118/2202/11879 2117/2200/11880 -f 2093/2177/11881 2117/2200/11882 2118/2202/11883 -f 2118/2202/11884 2119/2201/11885 2093/2177/11886 -f 2092/2176/11887 2093/2177/11888 2119/2201/11889 -f 2119/2201/11890 2028/2111/11891 2092/2176/11892 -f 2109/2192/11893 2108/2184/11894 2023/2107/11895 -f 2023/2107/11896 2024/2110/11897 2109/2192/11898 -f 2104/2337/11899 2022/2276/11900 2109/2340/11901 -f 2109/2340/11902 2024/2334/11903 2104/2337/11904 -f 2112/2342/11905 2111/2341/11906 2121/2347/11907 -f 2121/2347/11908 2058/2292/11909 2112/2342/11910 -f 2023/2107/11911 2108/2184/11912 2092/2176/11913 -f 2092/2176/11914 2028/2111/11915 2023/2107/11916 -f 2105/2336/11917 2121/2347/11918 2111/2341/11919 -f 2111/2341/11920 2104/2337/11921 2105/2336/11922 -f 2105/2336/11923 2025/2335/11924 2122/2348/11925 -f 2122/2348/11926 2121/2347/11927 2105/2336/11928 -f 1611/1693/11929 2124/2206/11930 2123/2204/11931 -f 2123/2204/11932 1610/1694/11933 1611/1693/11934 -f 1661/1745/11935 2018/2102/11936 1625/1710/11937 -f 1625/1710/11938 1660/1746/11939 1661/1745/11940 -f 2099/2329/11941 2100/2328/11942 2017/2326/11943 -f 2017/2326/11944 1632/1718/11945 2099/2329/11946 -f 2125/2208/11947 2018/2102/11948 2017/2101/11949 -f 2017/2101/11950 2100/2207/11951 2125/2208/11952 -f 1624/1708/11953 1625/1710/11954 2018/2102/11955 -f 2018/2102/11956 2125/2208/11957 1624/1708/11958 -f 1620/1704/11959 2093/2177/11960 1646/1729/11961 -f 1646/1729/11962 1623/1705/11963 1620/1704/11964 -f 1621/1707/11965 1622/1706/11966 1616/1700/11967 -f 1616/1700/11968 1617/1703/11969 1621/1707/11970 -f 2019/2103/11971 2126/2209/11972 2095/2181/11973 -f 2095/2181/11974 2098/2182/11975 2019/2103/11976 -f 2110/2193/11977 2098/2182/11978 2095/2181/11979 -f 2095/2181/11980 2096/2180/11981 2110/2193/11982 -f 2123/2204/11983 2124/2206/11984 2126/2209/11985 -f 2126/2209/11986 2127/2210/11987 2123/2204/11988 -f 1610/1694/11989 2125/2208/11990 2100/2207/11991 -f 2100/2207/11992 1609/1695/11993 1610/1694/11994 -f 1624/1708/11995 2125/2208/11996 1610/1694/11997 -f 1610/1694/11998 2123/2204/11999 1624/1708/12000 -f 2127/2210/12001 1626/1709/12002 1624/1708/12003 -f 1624/1708/12004 2123/2204/12005 2127/2210/12006 -f 2019/2103/12007 1626/1709/12008 2127/2210/12009 -f 2127/2210/12010 2126/2209/12011 2019/2103/12012 -f 2094/2178/12013 2095/2181/12014 2126/2209/12015 -f 2126/2209/12016 2124/2206/12017 2094/2178/12018 -f 2128/2350/12019 1611/2351/12020 1608/2485/12021 -f 1608/2485/12022 2129/2349/12023 2128/2350/12024 -f 2130/2352/12025 2124/2353/12026 1611/2351/12027 -f 1611/2351/12028 2128/2350/12029 2130/2352/12030 -f 2131/2354/12031 2094/2355/12032 2124/2353/12033 -f 2124/2353/12034 2130/2352/12035 2131/2354/12036 -f 2132/2356/12037 2097/2346/12038 2094/2355/12039 -f 2094/2355/12040 2131/2354/12041 2132/2356/12042 -f 2133/2357/12043 2113/2344/12044 2097/2346/12045 -f 2097/2346/12046 2132/2356/12047 2133/2357/12048 -f 2134/2358/12049 2103/2332/12050 2113/2344/12051 -f 2113/2344/12052 2133/2357/12053 2134/2358/12054 -f 2135/2359/12055 2102/2333/12056 2103/2332/12057 -f 2103/2332/12058 2134/2358/12059 2135/2359/12060 -f 2136/2360/12061 2106/2338/12062 2102/2333/12063 -f 2102/2333/12064 2135/2359/12065 2136/2360/12066 -f 2138/2361/12067 2137/2362/12068 2106/2338/12069 -f 2106/2338/12070 2136/2360/12071 2138/2361/12072 -f 2099/2329/12073 2140/2364/12074 2139/2363/12075 -f 2139/2363/12076 1608/2330/12077 2099/2329/12078 -f 2107/2339/12079 1630/1712/12080 2106/2338/12081 -f 2106/2338/12082 2137/2362/12083 2107/2339/12084 -f 2142/2365/12085 2141/2366/12086 2128/2350/12087 -f 2128/2350/12088 2129/2349/12089 2142/2365/12090 -f 2143/2367/12091 2130/2352/12092 2128/2350/12093 -f 2128/2350/12094 2141/2366/12095 2143/2367/12096 -f 2143/2367/12097 2144/2368/12098 2131/2354/12099 -f 2131/2354/12100 2130/2352/12101 2143/2367/12102 -f 2144/2368/12103 2145/2369/12104 2132/2356/12105 -f 2132/2356/12106 2131/2354/12107 2144/2368/12108 -f 2145/2369/12109 2146/2370/12110 2133/2357/12111 -f 2133/2357/12112 2132/2356/12113 2145/2369/12114 -f 2147/2371/12115 2134/2358/12116 2133/2357/12117 -f 2133/2357/12118 2146/2370/12119 2147/2371/12120 -f 2148/2372/12121 2135/2359/12122 2134/2358/12123 -f 2134/2358/12124 2147/2371/12125 2148/2372/12126 -f 2149/2373/12127 2136/2360/12128 2135/2359/12129 -f 2135/2359/12130 2148/2372/12131 2149/2373/12132 -f 2149/2373/12133 2150/2374/12134 2138/2361/12135 -f 2138/2361/12136 2136/2360/12137 2149/2373/12138 -f 2150/2374/12139 2142/2500/12140 2129/2494/12141 -f 2129/2494/12142 2138/2361/12143 2150/2374/12144 -f 2118/2202/12145 2120/2203/12146 2031/2113/12147 -f 2031/2113/12148 2027/2112/12149 2118/2202/12150 -f 2025/2109/12151 2032/2116/12152 2054/2138/12153 -f 2054/2138/12154 2122/2211/12155 2025/2109/12156 -f 2054/2296/12157 2058/2292/12158 2121/2347/12159 -f 2121/2347/12160 2122/2348/12161 2054/2296/12162 -f 2153/2598/12163 2152/2228/12164 2151/2225/12165 -f 2151/2225/12166 2154/2226/12167 2153/2598/12168 -f 2155/2230/12169 2152/2228/12170 2153/2598/12171 -f 2153/2598/12172 2156/2229/12173 2155/2230/12174 -f 2158/2231/12175 2157/2232/12176 2155/2230/12177 -f 2155/2230/12178 2156/2229/12179 2158/2231/12180 -f 1416/1499/12181 2160/2234/12182 2159/2233/12183 -f 2159/2233/12184 1417/1500/12185 1416/1499/12186 -f 1415/1498/12187 2161/2235/12188 2160/2234/12189 -f 2160/2234/12190 1416/1499/12191 1415/1498/12192 -f 2162/2236/12193 2161/2235/12194 1415/1498/12195 -f 1415/1498/12196 1414/1497/12197 2162/2236/12198 -f 2163/2237/12199 2162/2236/12200 1414/1497/12201 -f 1414/1497/12202 1413/1496/12203 2163/2237/12204 -f 2164/2238/12205 2163/2237/12206 1413/1496/12207 -f 1413/1496/12208 1427/1510/12209 2164/2238/12210 -f 1427/1510/12211 1424/1507/12212 2165/2239/12213 -f 2165/2239/12214 2164/2238/12215 1427/1510/12216 -f 2154/2597/12217 2151/2596/12218 2166/2240/12219 -f 2166/2240/12220 2167/2241/12221 2154/2597/12222 -f 2099/2329/12223 1632/1718/12224 1633/1717/12225 -f 1633/1717/12226 2140/2364/12227 2099/2329/12228 -f 2168/2375/12229 2140/2364/12230 1633/1717/12231 -f 1633/1717/12232 2021/2275/12233 2168/2375/12234 -f 2021/2275/12235 2020/2274/12236 2107/2339/12237 -f 2107/2339/12238 2168/2375/12239 2021/2275/12240 -f 2169/2376/12241 2139/2363/12242 2140/2364/12243 -f 2140/2364/12244 2168/2375/12245 2169/2376/12246 -f 2170/2377/12247 2129/2494/12248 1608/2330/12249 -f 1608/2330/12250 2139/2363/12251 2170/2377/12252 -f 2138/2361/12253 2129/2494/12254 2170/2377/12255 -f 2170/2377/12256 2171/2378/12257 2138/2361/12258 -f 2169/2376/12259 2171/2378/12260 2170/2377/12261 -f 2170/2377/12262 2139/2363/12263 2169/2376/12264 -f 2137/2362/12265 2138/2361/12266 2171/2378/12267 -f 2171/2378/12268 2169/2376/12269 2137/2362/12270 -f 2168/2375/12271 2107/2339/12272 2137/2362/12273 -f 2137/2362/12274 2169/2376/12275 2168/2375/12276 -f 2166/2240/12277 2150/2243/12278 2149/2242/12279 -f 2149/2242/12280 2164/2238/12281 2166/2240/12282 -f 2163/2237/12283 2164/2238/12284 2149/2242/12285 -f 2149/2242/12286 2148/2244/12287 2163/2237/12288 -f 2162/2236/12289 2163/2237/12290 2148/2244/12291 -f 2148/2244/12292 2147/2245/12293 2162/2236/12294 -f 2161/2235/12295 2162/2236/12296 2147/2245/12297 -f 2147/2245/12298 2146/2246/12299 2161/2235/12300 -f 2160/2234/12301 2161/2235/12302 2146/2246/12303 -f 2146/2246/12304 2145/2247/12305 2160/2234/12306 -f 2157/2232/12307 2158/2231/12308 2159/2233/12309 -f 2159/2233/12310 2160/2234/12311 2157/2232/12312 -f 2143/2249/12313 2155/2230/12314 2157/2232/12315 -f 2157/2232/12316 2144/2248/12317 2143/2249/12318 -f 2141/2250/12319 2152/2228/12320 2155/2230/12321 -f 2155/2230/12322 2143/2249/12323 2141/2250/12324 -f 2151/2225/12325 2152/2228/12326 2141/2250/12327 -f 2141/2250/12328 2142/2251/12329 2151/2225/12330 -f 2150/2243/12331 2166/2240/12332 2151/2596/12333 -f 2151/2596/12334 2142/2599/12335 2150/2243/12336 -f 1423/1506/12337 2167/2241/12338 2165/2239/12339 -f 2165/2239/12340 1424/1507/12341 1423/1506/12342 -f 1421/1504/12343 2154/2597/12344 2167/2241/12345 -f 2167/2241/12346 1423/1506/12347 1421/1504/12348 -f 1420/2594/12349 2153/2227/12350 2154/2597/12351 -f 2154/2597/12352 1421/1504/12353 1420/2594/12354 -f 2156/2229/12355 2153/2598/12356 1420/1503/12357 -f 1420/1503/12358 1419/1502/12359 2156/2229/12360 -f 2158/2231/12361 2156/2229/12362 1419/1502/12363 -f 1419/1502/12364 1418/1501/12365 2158/2231/12366 -f 1417/1500/12367 2159/2233/12368 2158/2231/12369 -f 2158/2231/12370 1418/1501/12371 1417/1500/12372 -f 2166/2240/12373 2164/2238/12374 2165/2239/12375 -f 2165/2239/12376 2167/2241/12377 2166/2240/12378 -f 2157/2232/12379 2160/2234/12380 2145/2247/12381 -f 2145/2247/12382 2144/2248/12383 2157/2232/12384 -f 1489/2528/12385 1315/1558/12386 1316/1557/12387 -f 1316/1557/12388 1309/1550/12389 1489/2528/12390 -f 1550/1633/12391 1323/1406/12392 1324/1405/12393 -f 1324/1405/12394 1545/1628/12395 1550/1633/12396 -f 1525/1609/12397 1526/1608/12398 1555/1638/12399 -f 1555/1638/12400 1529/1614/12401 1525/1609/12402 -f 1527/1610/12403 1525/2614/12404 1529/2616/12405 -f 1529/2616/12406 1530/1613/12407 1527/1610/12408 -f 1296/1378/12409 1527/1610/12410 1534/1617/12411 -f 1534/1617/12412 1293/1377/12413 1296/1378/12414 -f 1293/1377/12415 1534/1617/12416 1537/1620/12417 -f 1537/1620/12418 1292/479/12419 1293/1377/12420 -f 1292/479/12421 1537/1620/12422 1540/1623/12423 -f 1540/1623/12424 1506/1425/12425 1292/479/12426 -f 1506/1425/12427 1540/1623/12428 1543/1626/12429 -f 1543/1626/12430 1507/1589/12431 1506/1425/12432 -f 1507/1589/12433 1543/1626/12434 1324/1405/12435 -f 1324/1405/12436 1322/1381/12437 1507/1589/12438 -f 1556/1639/12439 1526/1608/12440 1523/1606/12441 -f 1523/1606/12442 1522/1605/12443 1556/1639/12444 -f 1323/1406/12445 1556/1639/12446 1522/1605/12447 -f 1522/1605/12448 1321/1403/12449 1323/1406/12450 -f 1509/1591/12451 1322/1381/12452 1319/1380/12453 -f 1319/1380/12454 1510/1593/12455 1509/1591/12456 -f 1546/1630/12457 1547/1629/12458 1575/1659/12459 -f 1575/1659/12460 2172/2256/12461 1546/1630/12462 -f 1549/1631/12463 1546/1630/12464 2172/2256/12465 -f 2172/2256/12466 2173/2257/12467 1549/1631/12468 -f 2174/2258/12469 1552/1634/12470 1549/1631/12471 -f 1549/1631/12472 2173/2257/12473 2174/2258/12474 -f 1562/1643/12475 1557/1640/12476 1552/1634/12477 -f 1552/1634/12478 2174/2258/12479 1562/1643/12480 -f 1559/2618/12481 1558/1641/12482 1557/1640/12483 -f 1557/1640/12484 1562/1643/12485 1559/2618/12486 -f 1558/2617/12487 1565/1648/12488 1531/1612/12489 -f 1531/1612/12490 1528/1611/12491 1558/2617/12492 -f 1531/1612/12493 1565/1648/12494 1568/1651/12495 -f 1568/1651/12496 1532/1615/12497 1531/1612/12498 -f 1532/1615/12499 1568/1651/12500 1571/1654/12501 -f 1571/1654/12502 1535/1618/12503 1532/1615/12504 -f 1535/1618/12505 1571/1654/12506 1574/1657/12507 -f 1574/1657/12508 1538/1621/12509 1535/1618/12510 -f 1538/1621/12511 1574/1657/12512 1547/1629/12513 -f 1547/1629/12514 1541/1624/12515 1538/1621/12516 -f 1560/1645/12517 1561/1644/12518 1591/1674/12519 -f 1591/1674/12520 1593/1675/12521 1560/1645/12522 -f 1564/1646/12523 1560/2619/12524 1593/2620/12525 -f 1593/2620/12526 1595/1677/12527 1564/1646/12528 -f 1567/1649/12529 1564/1646/12530 1595/1677/12531 -f 1595/1677/12532 1597/1679/12533 1567/1649/12534 -f 1570/1652/12535 1567/1649/12536 1597/1679/12537 -f 1597/1679/12538 1599/1681/12539 1570/1652/12540 -f 1578/1663/12541 1573/1655/12542 1570/1652/12543 -f 1570/1652/12544 1599/1681/12545 1578/1663/12546 -f 1579/1662/12547 1576/1658/12548 1573/1655/12549 -f 1573/1655/12550 1578/1663/12551 1579/1662/12552 -f 1575/1659/12553 1576/1658/12554 1583/1666/12555 -f 1583/1666/12556 2172/2256/12557 1575/1659/12558 -f 2172/2256/12559 1583/1666/12560 1586/1669/12561 -f 1586/1669/12562 2173/2257/12563 2172/2256/12564 -f 2173/2257/12565 1586/1669/12566 1589/1672/12567 -f 1589/1672/12568 2174/2258/12569 2173/2257/12570 -f 1589/1672/12571 1561/1644/12572 1562/1643/12573 -f 1562/1643/12574 2174/2258/12575 1589/1672/12576 -f 608/2569/12577 609/2573/12578 447/531/12579 -f 447/531/12580 448/530/12581 608/2569/12582 -f 609/2573/12583 611/695/12584 610/694/12585 -f 610/694/12586 447/531/12587 609/2573/12588 -f 614/700/12589 446/532/12590 447/531/12591 -f 447/531/12592 610/694/12593 614/700/12594 -f 2175/2622/12595 2176/2623/12596 2177/2626/12597 -f 2177/2626/12598 2178/2629/12599 2175/2622/12600 -f 2330/2806/12601 2331/2807/12602 2179/2646/12603 -f 2179/2646/12604 2180/2647/12605 2330/2806/12606 -f 2181/2624/12607 2179/2625/12608 2331/2808/12609 -f 2331/2808/12610 2332/2809/12611 2181/2624/12612 -f 2181/2624/12613 2332/2809/12614 2333/2810/12615 -f 2333/2810/12616 2184/2631/12617 2181/2624/12618 -f 2185/2632/12619 2183/2630/12620 2182/2628/12621 -f 2182/2628/12622 2186/2633/12623 2185/2632/12624 -f 2187/2634/12625 2188/2635/12626 2183/2630/12627 -f 2183/2630/12628 2185/2632/12629 2187/2634/12630 -f 2189/2636/12631 2190/2637/12632 2187/2634/12633 -f 2187/2634/12634 2191/2638/12635 2189/2636/12636 -f 2189/2649/12637 2192/2657/12638 2193/2659/12639 -f 2193/2659/12640 2194/2661/12641 2189/2649/12642 -f 2192/2657/12643 2195/2662/12644 2196/2663/12645 -f 2196/2663/12646 2193/2659/12647 2192/2657/12648 -s 2 -f 2195/2639/12649 2197/2640/12650 2198/2641/12651 -f 2198/2641/12652 2199/2642/12653 2195/2639/12654 -s 1 -f 2192/2643/12655 2200/2644/12656 2197/2640/12657 -f 2197/2640/12658 2195/2639/12659 2192/2643/12660 -s 2 -f 2201/2645/12661 2202/2648/12662 2198/2641/12663 -f 2198/2641/12664 2197/2640/12665 2201/2645/12666 -s 1 -f 2200/2644/12667 2203/2650/12668 2201/2645/12669 -f 2201/2645/12670 2197/2640/12671 2200/2644/12672 -s 2 -f 2196/2663/12673 2195/2662/12674 2199/2664/12675 -f 2199/2664/12676 2204/2665/12677 2196/2663/12678 -s 1 -f 2205/2666/12679 2206/2667/12680 2204/2665/12681 -f 2204/2665/12682 2199/2664/12683 2205/2666/12684 -f 2198/2641/12685 2207/2651/12686 2205/2652/12687 -f 2205/2652/12688 2199/2642/12689 2198/2641/12690 -f 2194/2661/12691 2193/2659/12692 2208/2668/12693 -f 2208/2668/12694 2209/2669/12695 2194/2661/12696 -f 2194/2661/12697 2210/2670/12698 2190/2687/12699 -f 2190/2687/12700 2189/2649/12701 2194/2661/12702 -f 2209/2669/12703 2211/2688/12704 2210/2670/12705 -f 2210/2670/12706 2194/2661/12707 2209/2669/12708 -f 2212/2690/12709 2208/2668/12710 2193/2659/12711 -f 2193/2659/12712 2196/2663/12713 2212/2690/12714 -f 2213/2691/12715 2214/2692/12716 2209/2669/12717 -f 2209/2669/12718 2208/2668/12719 2213/2691/12720 -f 2213/2691/12721 2208/2668/12722 2212/2690/12723 -f 2212/2690/12724 2215/2693/12725 2213/2691/12726 -f 2189/2636/12727 2191/2638/12728 2200/2644/12729 -f 2200/2644/12730 2192/2643/12731 2189/2636/12732 -f 2191/2638/12733 2216/2653/12734 2203/2650/12735 -f 2203/2650/12736 2200/2644/12737 2191/2638/12738 -f 2216/2653/12739 2217/2654/12740 2218/2655/12741 -f 2218/2655/12742 2203/2650/12743 2216/2653/12744 -f 2217/2654/12745 2216/2653/12746 2185/2632/12747 -f 2185/2632/12748 2186/2633/12749 2217/2654/12750 -f 2185/2632/12751 2216/2653/12752 2191/2638/12753 -f 2191/2638/12754 2187/2634/12755 2185/2632/12756 -f 2219/2656/12757 2188/2635/12758 2187/2634/12759 -f 2187/2634/12760 2190/2637/12761 2219/2656/12762 -f 2335/2812/12763 2220/2658/12764 2221/2660/12765 -f 2221/2660/12766 2334/2811/12767 2335/2812/12768 -s 2 -f 2220/2694/12769 2222/2695/12770 2223/2696/12771 -f 2223/2696/12772 2224/2697/12773 2220/2694/12774 -s 1 -f 2335/2813/12775 2336/2814/12776 2222/2695/12777 -f 2222/2695/12778 2220/2694/12779 2335/2813/12780 -f 2226/2740/12781 2227/2757/12782 2222/2695/12783 -f 2222/2695/12784 2336/2814/12785 2226/2740/12786 -f 2210/2670/12787 2211/2688/12788 2337/2815/12789 -f 2337/2815/12790 2225/2699/12791 2210/2670/12792 -f 2190/2687/12793 2210/2670/12794 2225/2699/12795 -f 2225/2699/12796 2219/2698/12797 2190/2687/12798 -s 4 -f 2227/2757/12799 2228/2759/12800 2223/2696/12801 -f 2223/2696/12802 2222/2695/12803 2227/2757/12804 -s 8 -f 2228/2759/12805 2227/2757/12806 2180/2647/12807 -f 2180/2647/12808 2229/2760/12809 2228/2759/12810 -s 2 -f 2230/2671/12811 2221/2660/12812 2220/2658/12813 -f 2220/2658/12814 2224/2672/12815 2230/2671/12816 -f 2221/2660/12817 2230/2671/12818 2231/2673/12819 -f 2231/2673/12820 2184/2631/12821 2221/2660/12822 -s 1 -f 2334/2811/12823 2221/2660/12824 2184/2631/12825 -f 2184/2631/12826 2333/2810/12827 2334/2811/12828 -f 2177/2674/12829 2186/2633/12830 2182/2628/12831 -f 2182/2628/12832 2178/2627/12833 2177/2674/12834 -f 2232/2675/12835 2186/2633/12836 2177/2674/12837 -f 2177/2674/12838 2233/2676/12839 2232/2675/12840 -f 2232/2675/12841 2234/2677/12842 2217/2654/12843 -f 2217/2654/12844 2186/2633/12845 2232/2675/12846 -f 2235/2678/12847 2236/2679/12848 2234/2677/12849 -f 2234/2677/12850 2237/2680/12851 2235/2678/12852 -f 2235/2678/12853 2238/2681/12854 2239/2682/12855 -f 2239/2682/12856 2240/2683/12857 2235/2678/12858 -f 2239/2682/12859 2238/2681/12860 2241/2684/12861 -f 2241/2684/12862 2242/2685/12863 2239/2682/12864 -s 2 -f 2239/2682/12865 2243/2686/12866 2244/2689/12867 -f 2244/2689/12868 2240/2683/12869 2239/2682/12870 -f 2243/2686/12871 2239/2682/12872 2242/2685/12873 -f 2242/2685/12874 2245/2700/12875 2243/2686/12876 -s 1 -f 2238/2681/12877 2246/2701/12878 2247/2702/12879 -f 2247/2702/12880 2241/2684/12881 2238/2681/12882 -f 2241/2684/12883 2248/2703/12884 2249/2704/12885 -f 2249/2704/12886 2242/2685/12887 2241/2684/12888 -f 2247/2702/12889 2250/2705/12890 2248/2703/12891 -f 2248/2703/12892 2241/2684/12893 2247/2702/12894 -f 2237/2680/12895 2246/2701/12896 2238/2681/12897 -f 2238/2681/12898 2235/2678/12899 2237/2680/12900 -f 2251/2706/12901 2252/2707/12902 2246/2701/12903 -f 2246/2701/12904 2237/2680/12905 2251/2706/12906 -f 2234/2677/12907 2232/2675/12908 2251/2706/12909 -f 2251/2706/12910 2237/2680/12911 2234/2677/12912 -f 2236/2679/12913 2235/2678/12914 2240/2683/12915 -f 2240/2683/12916 2253/2708/12917 2236/2679/12918 -f 2217/2654/12919 2234/2677/12920 2236/2679/12921 -f 2236/2679/12922 2218/2655/12923 2217/2654/12924 -f 2236/2679/12925 2253/2708/12926 2254/2709/12927 -f 2254/2709/12928 2218/2655/12929 2236/2679/12930 -s 2 -f 2254/2709/12931 2253/2708/12932 2255/2710/12933 -f 2255/2710/12934 2256/2711/12935 2254/2709/12936 -f 2240/2683/12937 2244/2689/12938 2255/2710/12939 -f 2255/2710/12940 2253/2708/12941 2240/2683/12942 -s 1 -f 2233/2676/12943 2257/2712/12944 2251/2706/12945 -f 2251/2706/12946 2232/2675/12947 2233/2676/12948 -f 2257/2741/12949 2233/2742/12950 2258/2743/12951 -f 2258/2743/12952 2259/2744/12953 2257/2741/12954 -s 2 -f 2251/2706/12955 2257/2712/12956 2260/2713/12957 -f 2260/2713/12958 2261/2714/12959 2251/2706/12960 -s 1 -f 2262/2745/12961 2263/2746/12962 2322/2796/12963 -f 2322/2796/12964 2324/2799/12965 2262/2745/12966 -s 2 -f 2262/2745/12967 2265/2749/12968 2266/2750/12969 -f 2266/2750/12970 2263/2746/12971 2262/2745/12972 -f 2265/2749/12973 2262/2745/12974 2267/2751/12975 -f 2267/2751/12976 2268/2752/12977 2265/2749/12978 -s 1 -f 2324/2799/12979 2325/2800/12980 2267/2751/12981 -f 2267/2751/12982 2262/2745/12983 2324/2799/12984 -f 2259/2744/12985 2264/2748/12986 2260/2747/12987 -f 2260/2747/12988 2257/2741/12989 2259/2744/12990 -f 2259/2744/12991 2270/2754/12992 2269/2753/12993 -f 2269/2753/12994 2264/2748/12995 2259/2744/12996 -f 2259/2744/12997 2271/2755/12998 2272/2756/12999 -f 2272/2756/13000 2270/2754/13001 2259/2744/13002 -f 2273/2758/13003 2271/2755/13004 2259/2744/13005 -f 2259/2744/13006 2258/2743/13007 2273/2758/13008 -f 2274/2715/13009 2323/2798/13010 2322/2797/13011 -f 2322/2797/13012 2263/2716/13013 2274/2715/13014 -s 2 -f 2274/2715/13015 2275/2717/13016 2276/2718/13017 -f 2276/2718/13018 2277/2719/13019 2274/2715/13020 -s 4 -f 2275/2717/13021 2274/2715/13022 2263/2716/13023 -f 2263/2716/13024 2266/2720/13025 2275/2717/13026 -s 1 -f 2323/2798/13027 2274/2715/13028 2277/2719/13029 -f 2277/2719/13030 2326/2801/13031 2323/2798/13032 -f 2177/2626/13033 2176/2623/13034 2258/2743/13035 -f 2258/2743/13036 2233/2742/13037 2177/2626/13038 -s 8 -f 2279/2722/13039 2280/2723/13040 2179/2625/13041 -f 2179/2625/13042 2181/2624/13043 2279/2722/13044 -s 2 -f 2184/2631/13045 2231/2673/13046 2279/2722/13047 -f 2279/2722/13048 2181/2624/13049 2184/2631/13050 -s 8 -f 2280/2761/13051 2229/2760/13052 2180/2647/13053 -f 2180/2647/13054 2179/2646/13055 2280/2761/13056 -s 1 -f 2176/2623/13057 2175/2622/13058 2337/2815/13059 -f 2337/2815/13060 2211/2688/13061 2176/2623/13062 -f 2227/2757/13063 2226/2740/13064 2330/2806/13065 -f 2330/2806/13066 2180/2647/13067 2227/2757/13068 -f 2214/2692/13069 2273/2758/13070 2258/2743/13071 -f 2258/2743/13072 2176/2623/13073 2214/2692/13074 -f 2176/2623/13075 2211/2688/13076 2209/2669/13077 -f 2209/2669/13078 2214/2692/13079 2176/2623/13080 -f 2214/2692/13081 2213/2691/13082 2281/2762/13083 -f 2281/2762/13084 2273/2758/13085 2214/2692/13086 -f 2281/2762/13087 2282/2765/13088 2271/2755/13089 -f 2271/2755/13090 2273/2758/13091 2281/2762/13092 -f 2282/2765/13093 2283/2766/13094 2284/2767/13095 -f 2284/2767/13096 2285/2768/13097 2282/2765/13098 -s 2 -f 2283/2766/13099 2286/2769/13100 2287/2772/13101 -f 2287/2772/13102 2284/2767/13103 2283/2766/13104 -s 1 -f 2286/2769/13105 2288/2763/13106 2289/2771/13107 -f 2289/2771/13108 2290/2776/13109 2286/2769/13110 -f 2288/2763/13111 2291/2764/13112 2292/2770/13113 -f 2292/2770/13114 2289/2771/13115 2288/2763/13116 -f 2293/2773/13117 2294/2774/13118 2292/2770/13119 -f 2292/2770/13120 2291/2764/13121 2293/2773/13122 -f 2294/2774/13123 2293/2773/13124 2204/2665/13125 -f 2204/2665/13126 2206/2667/13127 2294/2774/13128 -s 2 -f 2212/2690/13129 2196/2663/13130 2204/2665/13131 -f 2204/2665/13132 2293/2773/13133 2212/2690/13134 -f 2215/2693/13135 2212/2690/13136 2293/2773/13137 -f 2293/2773/13138 2291/2764/13139 2215/2693/13140 -f 2215/2693/13141 2291/2764/13142 2288/2763/13143 -f 2288/2763/13144 2295/2775/13145 2215/2693/13146 -f 2288/2763/13147 2286/2769/13148 2283/2766/13149 -f 2283/2766/13150 2295/2775/13151 2288/2763/13152 -s 1 -f 2213/2691/13153 2215/2693/13154 2295/2775/13155 -f 2295/2775/13156 2281/2762/13157 2213/2691/13158 -f 2281/2762/13159 2295/2775/13160 2283/2766/13161 -f 2283/2766/13162 2282/2765/13163 2281/2762/13164 -f 2287/2772/13165 2286/2769/13166 2290/2776/13167 -f 2290/2776/13168 2296/2777/13169 2287/2772/13170 -s 2 -f 2287/2772/13171 2297/2778/13172 2298/2779/13173 -f 2298/2779/13174 2284/2767/13175 2287/2772/13176 -f 2298/2779/13177 2297/2778/13178 2299/2780/13179 -f 2299/2780/13180 2249/2781/13181 2298/2779/13182 -s 1 -f 2298/2779/13183 2300/2782/13184 2285/2768/13185 -f 2285/2768/13186 2284/2767/13187 2298/2779/13188 -f 2298/2779/13189 2249/2781/13190 2248/2783/13191 -f 2248/2783/13192 2300/2782/13193 2298/2779/13194 -f 2300/2782/13195 2301/2784/13196 2272/2756/13197 -f 2272/2756/13198 2285/2768/13199 2300/2782/13200 -f 2301/2784/13201 2300/2782/13202 2248/2783/13203 -f 2248/2783/13204 2250/2785/13205 2301/2784/13206 -f 2270/2754/13207 2272/2756/13208 2301/2784/13209 -f 2301/2784/13210 2302/2786/13211 2270/2754/13212 -f 2250/2785/13213 2303/2787/13214 2302/2786/13215 -f 2302/2786/13216 2301/2784/13217 2250/2785/13218 -f 2271/2755/13219 2282/2765/13220 2285/2768/13221 -f 2285/2768/13222 2272/2756/13223 2271/2755/13224 -s 2 -f 2242/2685/13225 2249/2704/13226 2299/2724/13227 -f 2299/2724/13228 2245/2700/13229 2242/2685/13230 -s 1 -f 2304/2725/13231 2245/2700/13232 2299/2724/13233 -f 2299/2724/13234 2305/2726/13235 2304/2725/13236 -f 2306/2727/13237 2243/2686/13238 2245/2700/13239 -f 2245/2700/13240 2304/2725/13241 2306/2727/13242 -f 2244/2689/13243 2243/2686/13244 2306/2727/13245 -f 2306/2727/13246 2307/2728/13247 2244/2689/13248 -f 2299/2780/13249 2297/2778/13250 2308/2788/13251 -f 2308/2788/13252 2305/2789/13253 2299/2780/13254 -f 2287/2772/13255 2296/2777/13256 2308/2788/13257 -f 2308/2788/13258 2297/2778/13259 2287/2772/13260 -f 2254/2709/13261 2201/2645/13262 2203/2650/13263 -f 2203/2650/13264 2218/2655/13265 2254/2709/13266 -s 2 -f 2254/2709/13267 2256/2711/13268 2202/2648/13269 -f 2202/2648/13270 2201/2645/13271 2254/2709/13272 -s 1 -f 2261/2714/13273 2278/2721/13274 2252/2707/13275 -f 2252/2707/13276 2251/2706/13277 2261/2714/13278 -f 2309/2729/13279 2326/2801/13280 2277/2719/13281 -f 2277/2719/13282 2310/2730/13283 2309/2729/13284 -f 2278/2721/13285 2327/2802/13286 2311/2731/13287 -f 2311/2731/13288 2252/2707/13289 2278/2721/13290 -f 2247/2702/13291 2246/2701/13292 2252/2707/13293 -f 2252/2707/13294 2311/2731/13295 2247/2702/13296 -f 2303/2732/13297 2250/2705/13298 2247/2702/13299 -f 2247/2702/13300 2311/2731/13301 2303/2732/13302 -f 2312/2733/13303 2303/2732/13304 2311/2731/13305 -f 2311/2731/13306 2327/2802/13307 2312/2733/13308 -f 2328/2803/13309 2313/2791/13310 2314/2792/13311 -f 2314/2792/13312 2329/2805/13313 2328/2803/13314 -s 4 -f 2316/2794/13315 2317/2795/13316 2314/2792/13317 -f 2314/2792/13318 2313/2791/13319 2316/2794/13320 -f 2318/2734/13321 2316/2735/13322 2313/2736/13323 -f 2313/2736/13324 2310/2730/13325 2318/2734/13326 -f 2276/2718/13327 2318/2734/13328 2310/2730/13329 -f 2310/2730/13330 2277/2719/13331 2276/2718/13332 -s 1 -f 2328/2804/13333 2309/2729/13334 2310/2730/13335 -f 2310/2730/13336 2313/2736/13337 2328/2804/13338 -s 8 -f 2314/2792/13339 2317/2795/13340 2268/2752/13341 -f 2268/2752/13342 2267/2751/13343 2314/2792/13344 -s 1 -f 2325/2800/13345 2329/2805/13346 2314/2792/13347 -f 2314/2792/13348 2267/2751/13349 2325/2800/13350 -f 2302/2786/13351 2303/2787/13352 2312/2790/13353 -f 2312/2790/13354 2315/2793/13355 2302/2786/13356 -f 2315/2793/13357 2269/2753/13358 2270/2754/13359 -f 2270/2754/13360 2302/2786/13361 2315/2793/13362 -f 2319/2737/13363 2255/2710/13364 2244/2689/13365 -f 2244/2689/13366 2307/2728/13367 2319/2737/13368 -f 2320/2738/13369 2256/2711/13370 2255/2710/13371 -f 2255/2710/13372 2319/2737/13373 2320/2738/13374 -f 2256/2711/13375 2320/2738/13376 2321/2739/13377 -f 2321/2739/13378 2202/2648/13379 2256/2711/13380 -f 2321/2739/13381 2207/2651/13382 2198/2641/13383 -f 2198/2641/13384 2202/2648/13385 2321/2739/13386 -f 2260/2713/13387 2322/2797/13388 2323/2798/13389 -f 2323/2798/13390 2261/2714/13391 2260/2713/13392 -f 2322/2796/13393 2260/2747/13394 2264/2748/13395 -f 2264/2748/13396 2324/2799/13397 2322/2796/13398 -f 2324/2799/13399 2264/2748/13400 2269/2753/13401 -f 2269/2753/13402 2325/2800/13403 2324/2799/13404 -f 2326/2801/13405 2278/2721/13406 2261/2714/13407 -f 2261/2714/13408 2323/2798/13409 2326/2801/13410 -f 2309/2729/13411 2327/2802/13412 2278/2721/13413 -f 2278/2721/13414 2326/2801/13415 2309/2729/13416 -f 2327/2802/13417 2309/2729/13418 2328/2804/13419 -f 2328/2804/13420 2312/2733/13421 2327/2802/13422 -f 2329/2805/13423 2315/2793/13424 2312/2790/13425 -f 2312/2790/13426 2328/2803/13427 2329/2805/13428 -f 2325/2800/13429 2269/2753/13430 2315/2793/13431 -f 2315/2793/13432 2329/2805/13433 2325/2800/13434 -f 2178/2629/13435 2331/2807/13436 2330/2806/13437 -f 2330/2806/13438 2175/2622/13439 2178/2629/13440 -f 2331/2808/13441 2178/2627/13442 2182/2628/13443 -f 2182/2628/13444 2332/2809/13445 2331/2808/13446 -f 2332/2809/13447 2182/2628/13448 2183/2630/13449 -f 2183/2630/13450 2333/2810/13451 2332/2809/13452 -f 2188/2635/13453 2334/2811/13454 2333/2810/13455 -f 2333/2810/13456 2183/2630/13457 2188/2635/13458 -f 2219/2656/13459 2335/2812/13460 2334/2811/13461 -f 2334/2811/13462 2188/2635/13463 2219/2656/13464 -f 2335/2813/13465 2219/2698/13466 2225/2699/13467 -f 2225/2699/13468 2336/2814/13469 2335/2813/13470 -f 2336/2814/13471 2225/2699/13472 2337/2815/13473 -f 2337/2815/13474 2226/2740/13475 2336/2814/13476 -f 2175/2622/13477 2330/2806/13478 2226/2740/13479 -f 2226/2740/13480 2337/2815/13481 2175/2622/13482 -f 2340/2818/13483 2341/2819/13484 2338/2816/13485 -f 2338/2816/13486 2339/2817/13487 2340/2818/13488 -f 2426/2820/13489 2427/2821/13490 2344/2822/13491 -f 2344/2822/13492 2338/2816/13493 2426/2820/13494 -f 2346/2825/13495 2347/2826/13496 2448/2823/13497 -f 2448/2823/13498 2450/2824/13499 2346/2825/13500 -f 2451/2827/13501 2349/2828/13502 2346/2825/13503 -f 2346/2825/13504 2450/2824/13505 2451/2827/13506 -f 2428/2830/13507 2429/2831/13508 2348/2832/13509 -f 2348/2832/13510 2345/2829/13511 2428/2830/13512 -f 2351/2833/13513 2350/2834/13514 2341/2819/13515 -f 2341/2819/13516 2340/2818/13517 2351/2833/13518 -f 2352/2835/13519 2353/2836/13520 2350/2834/13521 -f 2350/2834/13522 2351/2833/13523 2352/2835/13524 -f 2350/2834/13525 2353/2836/13526 2430/2837/13527 -f 2430/2837/13528 2429/2831/13529 2350/2834/13530 -f 2354/2838/13531 2430/2837/13532 2431/2839/13533 -f 2431/2839/13534 2356/2840/13535 2354/2838/13536 -f 2357/2842/13537 2349/2828/13538 2451/2827/13539 -f 2451/2827/13540 2452/2841/13541 2357/2842/13542 -f 2358/2844/13543 2357/2842/13544 2452/2841/13545 -f 2452/2841/13546 2453/2843/13547 2358/2844/13548 -f 2432/2846/13549 2431/2839/13550 2355/2847/13551 -f 2355/2847/13552 2359/2845/13553 2432/2846/13554 -f 2362/2849/13555 2363/2850/13556 2359/2845/13557 -f 2359/2845/13558 2361/2848/13559 2362/2849/13560 -f 2361/2848/13561 2359/2845/13562 2355/2847/13563 -f 2355/2847/13564 2364/2851/13565 2361/2848/13566 -f 2365/2852/13567 2360/2853/13568 2432/2846/13569 -f 2432/2846/13570 2433/2854/13571 2365/2852/13572 -f 2355/2847/13573 2353/2836/13574 2352/2835/13575 -f 2352/2835/13576 2364/2851/13577 2355/2847/13578 -f 2345/2829/13579 2342/2855/13580 2426/2820/13581 -f 2426/2820/13582 2428/2830/13583 2345/2829/13584 -f 2366/2856/13585 2343/2857/13586 2448/2823/13587 -f 2448/2823/13588 2347/2826/13589 2366/2856/13590 -f 2368/2859/13591 2343/2857/13592 2366/2856/13593 -f 2366/2856/13594 2367/2858/13595 2368/2859/13596 -f 2370/2861/13597 2368/2859/13598 2367/2858/13599 -f 2367/2858/13600 2369/2860/13601 2370/2861/13602 -f 2371/2862/13603 2372/2863/13604 2370/2861/13605 -f 2370/2861/13606 2369/2860/13607 2371/2862/13608 -f 2434/2865/13609 2435/2866/13610 2456/2867/13611 -f 2456/2867/13612 2457/2864/13613 2434/2865/13614 -f 2458/2868/13615 2436/2869/13616 2434/2865/13617 -f 2434/2865/13618 2457/2864/13619 2458/2868/13620 -f 2459/2870/13621 2437/2871/13622 2436/2869/13623 -f 2436/2869/13624 2458/2868/13625 2459/2870/13626 -f 2379/2874/13627 2380/2875/13628 2378/2872/13629 -f 2378/2872/13630 2376/2873/13631 2379/2874/13632 -f 2371/2862/13633 2379/2874/13634 2376/2873/13635 -f 2376/2873/13636 2372/2863/13637 2371/2862/13638 -f 2377/2876/13639 2437/2871/13640 2438/2877/13641 -f 2438/2877/13642 2381/2878/13643 2377/2876/13644 -f 2382/2880/13645 2383/2881/13646 2375/2879/13647 -f 2375/2879/13648 2377/2876/13649 2382/2880/13650 -f 2375/2879/13651 2383/2881/13652 2384/2882/13653 -f 2384/2882/13654 2373/2883/13655 2375/2879/13656 -f 2384/2882/13657 2385/2885/13658 2374/2884/13659 -f 2374/2884/13660 2373/2883/13661 2384/2882/13662 -f 2386/2886/13663 2344/2822/13664 2374/2884/13665 -f 2374/2884/13666 2385/2885/13667 2386/2886/13668 -f 2344/2822/13669 2386/2886/13670 2339/2817/13671 -f 2339/2817/13672 2338/2816/13673 2344/2822/13674 -f 2449/2887/13675 2456/2867/13676 2435/2866/13677 -f 2435/2866/13678 2427/2821/13679 2449/2887/13680 -f 2454/2888/13681 2387/2889/13682 2358/2844/13683 -f 2358/2844/13684 2453/2843/13685 2454/2888/13686 -f 2388/2891/13687 2387/2889/13688 2454/2888/13689 -f 2454/2888/13690 2455/2890/13691 2388/2891/13692 -f 2390/2893/13693 2388/2953/13694 2455/2952/13695 -f 2455/2952/13696 2461/2892/13697 2390/2893/13698 -f 2392/2895/13699 2390/2893/13700 2461/2892/13701 -f 2461/2892/13702 2462/2894/13703 2392/2895/13704 -f 2392/2895/13705 2462/2894/13706 2463/2896/13707 -f 2463/2896/13708 2394/2897/13709 2392/2895/13710 -f 2394/2897/13711 2463/2896/13712 2464/2898/13713 -f 2464/2898/13714 2396/2899/13715 2394/2897/13716 -f 2396/2899/13717 2464/2898/13718 2465/2900/13719 -f 2465/2900/13720 2398/2901/13721 2396/2899/13722 -f 2400/2903/13723 2398/2901/13724 2465/2900/13725 -f 2465/2900/13726 2466/2902/13727 2400/2903/13728 -f 2402/2905/13729 2439/2906/13730 2440/2907/13731 -f 2440/2907/13732 2401/2904/13733 2402/2905/13734 -f 2403/2908/13735 2404/2909/13736 2402/2905/13737 -f 2402/2905/13738 2401/2904/13739 2403/2908/13740 -f 2405/2910/13741 2441/2911/13742 2439/2906/13743 -f 2439/2906/13744 2402/2905/13745 2405/2910/13746 -f 2405/2910/13747 2402/2905/13748 2404/2909/13749 -f 2404/2909/13750 2407/2912/13751 2405/2910/13752 -f 2409/2914/13753 2403/2908/13754 2401/2904/13755 -f 2401/2904/13756 2408/2913/13757 2409/2914/13758 -f 2442/2916/13759 2440/2907/13760 2397/2917/13761 -f 2397/2917/13762 2395/2915/13763 2442/2916/13764 -f 2467/2918/13765 2410/2919/13766 2400/2903/13767 -f 2400/2903/13768 2466/2902/13769 2467/2918/13770 -f 2412/2921/13771 2410/2919/13772 2467/2918/13773 -f 2467/2918/13774 2468/2920/13775 2412/2921/13776 -f 2413/2922/13777 2414/2923/13778 2412/2921/13779 -f 2412/2921/13780 2468/2920/13781 2413/2922/13782 -f 2416/2925/13783 2443/2926/13784 2444/2927/13785 -f 2444/2927/13786 2415/2924/13787 2416/2925/13788 -f 2406/2929/13789 2441/2911/13790 2444/2927/13791 -f 2444/2927/13792 2411/2928/13793 2406/2929/13794 -f 2417/2930/13795 2408/2913/13796 2442/2916/13797 -f 2442/2916/13798 2445/2931/13799 2417/2930/13800 -f 2445/2931/13801 2446/2932/13802 2418/2933/13803 -f 2418/2933/13804 2417/2930/13805 2445/2931/13806 -f 2420/2935/13807 2417/2930/13808 2418/2933/13809 -f 2418/2933/13810 2419/2934/13811 2420/2935/13812 -f 2422/2937/13813 2419/2934/13814 2418/2933/13815 -f 2418/2933/13816 2421/2936/13817 2422/2937/13818 -f 2421/2936/13819 2418/2933/13820 2446/2932/13821 -f 2446/2932/13822 2447/2938/13823 2421/2936/13824 -f 2363/2949/13825 2362/2948/13826 2422/2937/13827 -f 2422/2937/13828 2421/2936/13829 2363/2949/13830 -f 2433/2951/13831 2447/2938/13832 2389/2939/13833 -f 2389/2939/13834 2365/2950/13835 2433/2951/13836 -f 2409/2914/13837 2408/2913/13838 2417/2930/13839 -f 2417/2930/13840 2420/2935/13841 2409/2914/13842 -f 2405/2910/13843 2407/2912/13844 2423/2940/13845 -f 2423/2940/13846 2415/2924/13847 2405/2910/13848 -f 2423/2940/13849 2424/2941/13850 2416/2925/13851 -f 2416/2925/13852 2415/2924/13853 2423/2940/13854 -f 2425/2942/13855 2381/2957/13856 2416/2925/13857 -f 2416/2925/13858 2424/2941/13859 2425/2942/13860 -f 2377/2876/13861 2381/2878/13862 2425/2958/13863 -f 2425/2958/13864 2382/2880/13865 2377/2876/13866 -f 2381/2957/13867 2438/2956/13868 2443/2926/13869 -f 2443/2926/13870 2416/2925/13871 2381/2957/13872 -f 2378/2954/13873 2380/2955/13874 2414/2923/13875 -f 2414/2923/13876 2413/2922/13877 2378/2954/13878 -f 2342/2855/13879 2449/2887/13880 2427/2821/13881 -f 2427/2821/13882 2426/2820/13883 2342/2855/13884 -f 2341/2819/13885 2350/2834/13886 2429/2831/13887 -f 2429/2831/13888 2428/2830/13889 2341/2819/13890 -f 2430/2837/13891 2354/2838/13892 2348/2832/13893 -f 2348/2832/13894 2429/2831/13895 2430/2837/13896 -f 2353/2836/13897 2355/2847/13898 2431/2839/13899 -f 2431/2839/13900 2430/2837/13901 2353/2836/13902 -f 2360/2853/13903 2356/2840/13904 2431/2839/13905 -f 2431/2839/13906 2432/2846/13907 2360/2853/13908 -f 2359/2845/13909 2363/2850/13910 2433/2854/13911 -f 2433/2854/13912 2432/2846/13913 2359/2845/13914 -f 2338/2816/13915 2341/2819/13916 2428/2830/13917 -f 2428/2830/13918 2426/2820/13919 2338/2816/13920 -f 2373/2883/13921 2374/2884/13922 2435/2866/13923 -f 2435/2866/13924 2434/2865/13925 2373/2883/13926 -f 2436/2869/13927 2375/2879/13928 2373/2883/13929 -f 2373/2883/13930 2434/2865/13931 2436/2869/13932 -f 2437/2871/13933 2377/2876/13934 2375/2879/13935 -f 2375/2879/13936 2436/2869/13937 2437/2871/13938 -f 2437/2871/13939 2459/2870/13940 2460/2943/13941 -f 2460/2943/13942 2438/2877/13943 2437/2871/13944 -f 2374/2884/13945 2344/2822/13946 2427/2821/13947 -f 2427/2821/13948 2435/2866/13949 2374/2884/13950 -f 2399/2944/13951 2397/2917/13952 2440/2907/13953 -f 2440/2907/13954 2439/2906/13955 2399/2944/13956 -f 2441/2911/13957 2406/2929/13958 2399/2944/13959 -f 2399/2944/13960 2439/2906/13961 2441/2911/13962 -f 2442/2916/13963 2408/2913/13964 2401/2904/13965 -f 2401/2904/13966 2440/2907/13967 2442/2916/13968 -f 2443/2926/13969 2469/2945/13970 2411/2928/13971 -f 2411/2928/13972 2444/2927/13973 2443/2926/13974 -f 2441/2911/13975 2405/2910/13976 2415/2924/13977 -f 2415/2924/13978 2444/2927/13979 2441/2911/13980 -f 2395/2915/13981 2393/2946/13982 2445/2931/13983 -f 2445/2931/13984 2442/2916/13985 2395/2915/13986 -f 2393/2946/13987 2391/2947/13988 2446/2932/13989 -f 2446/2932/13990 2445/2931/13991 2393/2946/13992 -f 2391/2947/13993 2389/2939/13994 2447/2938/13995 -f 2447/2938/13996 2446/2932/13997 2391/2947/13998 -f 2363/2949/13999 2421/2936/14000 2447/2938/14001 -f 2447/2938/14002 2433/2951/14003 2363/2949/14004 -f 2438/2956/14005 2460/2959/14006 2469/2945/14007 -f 2469/2945/14008 2443/2926/14009 2438/2956/14010 -f 2342/2855/14011 2448/2823/14012 2343/2857/14013 -f 2343/2857/14014 2449/2887/14015 2342/2855/14016 -f 2448/2823/14017 2342/2855/14018 2345/2829/14019 -f 2345/2829/14020 2450/2824/14021 2448/2823/14022 -f 2450/2824/14023 2345/2829/14024 2348/2832/14025 -f 2348/2832/14026 2451/2827/14027 2450/2824/14028 -f 2354/2838/14029 2452/2841/14030 2451/2827/14031 -f 2451/2827/14032 2348/2832/14033 2354/2838/14034 -f 2356/2840/14035 2453/2843/14036 2452/2841/14037 -f 2452/2841/14038 2354/2838/14039 2356/2840/14040 -f 2360/2853/14041 2454/2888/14042 2453/2843/14043 -f 2453/2843/14044 2356/2840/14045 2360/2853/14046 -f 2365/2852/14047 2455/2890/14048 2454/2888/14049 -f 2454/2888/14050 2360/2853/14051 2365/2852/14052 -f 2368/2859/14053 2456/2867/14054 2449/2887/14055 -f 2449/2887/14056 2343/2857/14057 2368/2859/14058 -f 2370/2861/14059 2457/2864/14060 2456/2867/14061 -f 2456/2867/14062 2368/2859/14063 2370/2861/14064 -f 2372/2863/14065 2458/2868/14066 2457/2864/14067 -f 2457/2864/14068 2370/2861/14069 2372/2863/14070 -f 2458/2868/14071 2372/2863/14072 2376/2873/14073 -f 2376/2873/14074 2459/2870/14075 2458/2868/14076 -f 2378/2872/14077 2460/2943/14078 2459/2870/14079 -f 2459/2870/14080 2376/2873/14081 2378/2872/14082 -f 2455/2952/14083 2365/2950/14084 2389/2939/14085 -f 2389/2939/14086 2461/2892/14087 2455/2952/14088 -f 2461/2892/14089 2389/2939/14090 2391/2947/14091 -f 2391/2947/14092 2462/2894/14093 2461/2892/14094 -f 2462/2894/14095 2391/2947/14096 2393/2946/14097 -f 2393/2946/14098 2463/2896/14099 2462/2894/14100 -f 2463/2896/14101 2393/2946/14102 2395/2915/14103 -f 2395/2915/14104 2464/2898/14105 2463/2896/14106 -f 2464/2898/14107 2395/2915/14108 2397/2917/14109 -f 2397/2917/14110 2465/2900/14111 2464/2898/14112 -f 2465/2900/14113 2397/2917/14114 2399/2944/14115 -f 2399/2944/14116 2466/2902/14117 2465/2900/14118 -f 2406/2929/14119 2467/2918/14120 2466/2902/14121 -f 2466/2902/14122 2399/2944/14123 2406/2929/14124 -f 2467/2918/14125 2406/2929/14126 2411/2928/14127 -f 2411/2928/14128 2468/2920/14129 2467/2918/14130 -f 2468/2920/14131 2411/2928/14132 2469/2945/14133 -f 2469/2945/14134 2413/2922/14135 2468/2920/14136 -f 2460/2959/14137 2378/2954/14138 2413/2922/14139 -f 2413/2922/14140 2469/2945/14141 2460/2959/14142 -f 2486/2962/14143 2487/2963/14144 2524/2960/14145 -f 2524/2960/14146 2532/2961/14147 2486/2962/14148 -f 2471/2965/14149 2524/2960/14150 2487/2963/14151 -f 2487/2963/14152 2479/2964/14153 2471/2965/14154 -f 2472/2967/14155 2471/2965/14156 2479/2964/14157 -f 2479/2964/14158 2480/2966/14159 2472/2967/14160 -f 2473/2969/14161 2472/2967/14162 2480/2966/14163 -f 2480/2966/14164 2481/2968/14165 2473/2969/14166 -f 2474/2971/14167 2473/3024/14168 2481/3023/14169 -f 2481/3023/14170 2482/2970/14171 2474/2971/14172 -f 2475/2973/14173 2474/2971/14174 2482/2970/14175 -f 2482/2970/14176 2483/2972/14177 2475/2973/14178 -f 2476/2975/14179 2475/2973/14180 2483/2972/14181 -f 2483/2972/14182 2484/2974/14183 2476/2975/14184 -f 2477/2977/14185 2476/2975/14186 2484/2974/14187 -f 2484/2974/14188 2485/2976/14189 2477/2977/14190 -f 2532/2961/14191 2477/2977/14192 2485/2976/14193 -f 2485/2976/14194 2486/2962/14195 2532/2961/14196 -f 2495/2978/14197 2494/2979/14198 2479/2964/14199 -f 2479/2964/14200 2487/2963/14201 2495/2978/14202 -f 2480/2966/14203 2479/2964/14204 2494/2979/14205 -f 2494/2979/14206 2493/2980/14207 2480/2966/14208 -f 2481/2968/14209 2480/2966/14210 2493/2980/14211 -f 2493/2980/14212 2492/2981/14213 2481/2968/14214 -f 2482/2970/14215 2481/3023/14216 2492/3025/14217 -f 2492/3025/14218 2491/2982/14219 2482/2970/14220 -f 2483/2972/14221 2482/2970/14222 2491/2982/14223 -f 2491/2982/14224 2490/2983/14225 2483/2972/14226 -f 2484/2974/14227 2483/2972/14228 2490/2983/14229 -f 2490/2983/14230 2489/2984/14231 2484/2974/14232 -f 2485/2976/14233 2484/2974/14234 2489/2984/14235 -f 2489/2984/14236 2488/2985/14237 2485/2976/14238 -f 2486/2962/14239 2485/2976/14240 2488/2985/14241 -f 2488/2985/14242 2496/2986/14243 2486/2962/14244 -f 2487/2963/14245 2486/2962/14246 2496/2986/14247 -f 2496/2986/14248 2495/2978/14249 2487/2963/14250 -f 2478/2989/14251 2470/2990/14252 2497/2987/14253 -f 2497/2987/14254 2505/2988/14255 2478/2989/14256 -f 2470/2990/14257 2525/2992/14258 2498/2991/14259 -f 2498/2991/14260 2497/2987/14261 2470/2990/14262 -f 2525/2992/14263 2526/2994/14264 2499/2993/14265 -f 2499/2993/14266 2498/2991/14267 2525/2992/14268 -f 2526/2994/14269 2527/2996/14270 2500/2995/14271 -f 2500/2995/14272 2499/2993/14273 2526/2994/14274 -f 2527/3027/14275 2528/2998/14276 2501/2997/14277 -f 2501/2997/14278 2500/3026/14279 2527/3027/14280 -f 2528/2998/14281 2529/3000/14282 2502/2999/14283 -f 2502/2999/14284 2501/2997/14285 2528/2998/14286 -f 2529/3000/14287 2530/3002/14288 2503/3001/14289 -f 2503/3001/14290 2502/2999/14291 2529/3000/14292 -f 2530/3002/14293 2531/3004/14294 2504/3003/14295 -f 2504/3003/14296 2503/3001/14297 2530/3002/14298 -f 2531/3004/14299 2478/2989/14300 2505/2988/14301 -f 2505/2988/14302 2504/3003/14303 2531/3004/14304 -f 2521/3007/14305 2522/3008/14306 2513/3005/14307 -f 2513/3005/14308 2512/3006/14309 2521/3007/14310 -f 2520/3010/14311 2521/3007/14312 2512/3006/14313 -f 2512/3006/14314 2511/3009/14315 2520/3010/14316 -f 2519/3012/14317 2520/3010/14318 2511/3009/14319 -f 2511/3009/14320 2510/3011/14321 2519/3012/14322 -f 2518/3014/14323 2519/3029/14324 2510/3028/14325 -f 2510/3028/14326 2509/3013/14327 2518/3014/14328 -f 2517/3016/14329 2518/3014/14330 2509/3013/14331 -f 2509/3013/14332 2508/3015/14333 2517/3016/14334 -f 2516/3018/14335 2517/3016/14336 2508/3015/14337 -f 2508/3015/14338 2507/3017/14339 2516/3018/14340 -f 2515/3020/14341 2516/3018/14342 2507/3017/14343 -f 2507/3017/14344 2506/3019/14345 2515/3020/14346 -f 2523/3022/14347 2515/3020/14348 2506/3019/14349 -f 2506/3019/14350 2514/3021/14351 2523/3022/14352 -f 2522/3008/14353 2523/3022/14354 2514/3021/14355 -f 2514/3021/14356 2513/3005/14357 2522/3008/14358 -f 2495/2978/14359 2522/3008/14360 2521/3007/14361 -f 2521/3007/14362 2494/2979/14363 2495/2978/14364 -f 2494/2979/14365 2521/3007/14366 2520/3010/14367 -f 2520/3010/14368 2493/2980/14369 2494/2979/14370 -f 2493/2980/14371 2520/3010/14372 2519/3012/14373 -f 2519/3012/14374 2492/2981/14375 2493/2980/14376 -f 2492/3025/14377 2519/3029/14378 2518/3014/14379 -f 2518/3014/14380 2491/2982/14381 2492/3025/14382 -f 2491/2982/14383 2518/3014/14384 2517/3016/14385 -f 2517/3016/14386 2490/2983/14387 2491/2982/14388 -f 2490/2983/14389 2517/3016/14390 2516/3018/14391 -f 2516/3018/14392 2489/2984/14393 2490/2983/14394 -f 2489/2984/14395 2516/3018/14396 2515/3020/14397 -f 2515/3020/14398 2488/2985/14399 2489/2984/14400 -f 2488/2985/14401 2515/3020/14402 2523/3022/14403 -f 2523/3022/14404 2496/2986/14405 2488/2985/14406 -f 2496/2986/14407 2523/3022/14408 2522/3008/14409 -f 2522/3008/14410 2495/2978/14411 2496/2986/14412 -f 2524/2960/14413 2470/2990/14414 2478/2989/14415 -f 2478/2989/14416 2532/2961/14417 2524/2960/14418 -f 2471/2965/14419 2525/2992/14420 2470/2990/14421 -f 2470/2990/14422 2524/2960/14423 2471/2965/14424 -f 2472/2967/14425 2526/2994/14426 2525/2992/14427 -f 2525/2992/14428 2471/2965/14429 2472/2967/14430 -f 2473/2969/14431 2527/2996/14432 2526/2994/14433 -f 2526/2994/14434 2472/2967/14435 2473/2969/14436 -f 2474/2971/14437 2528/2998/14438 2527/3027/14439 -f 2527/3027/14440 2473/3024/14441 2474/2971/14442 -f 2475/2973/14443 2529/3000/14444 2528/2998/14445 -f 2528/2998/14446 2474/2971/14447 2475/2973/14448 -f 2476/2975/14449 2530/3002/14450 2529/3000/14451 -f 2529/3000/14452 2475/2973/14453 2476/2975/14454 -f 2477/2977/14455 2531/3004/14456 2530/3002/14457 -f 2530/3002/14458 2476/2975/14459 2477/2977/14460 -f 2532/2961/14461 2478/2989/14462 2531/3004/14463 -f 2531/3004/14464 2477/2977/14465 2532/2961/14466 -f 2535/3035/14467 2536/3060/14468 2533/3032/14469 -f 2533/3032/14470 2534/3033/14471 2535/3035/14472 -f 2536/3060/14473 2538/3062/14474 2537/3061/14475 -f 2537/3061/14476 2533/3032/14477 2536/3060/14478 -f 2537/3034/14479 2540/3036/14480 2539/3030/14481 -f 2539/3030/14482 2533/3031/14483 2537/3034/14484 -f 2542/3038/14485 2543/3039/14486 2539/3030/14487 -f 2539/3030/14488 2541/3037/14489 2542/3038/14490 -f 2539/3030/14491 2540/3036/14492 2544/3040/14493 -f 2544/3040/14494 2541/3037/14495 2539/3030/14496 -f 2544/3040/14497 2540/3036/14498 2545/3041/14499 -f 2545/3041/14500 2546/3042/14501 2544/3040/14502 -f 2548/3044/14503 2546/3042/14504 2545/3041/14505 -f 2545/3041/14506 2547/3043/14507 2548/3044/14508 -f 2547/3048/14509 2550/3049/14510 2549/3046/14511 -f 2549/3046/14512 2548/3047/14513 2547/3048/14514 -f 2549/3046/14515 2550/3049/14516 2551/3050/14517 -f 2551/3050/14518 2552/3051/14519 2549/3046/14520 -f 2554/3053/14521 2552/3051/14522 2551/3050/14523 -f 2551/3050/14524 2553/3052/14525 2554/3053/14526 -f 2555/3054/14527 2556/3055/14528 2554/3053/14529 -f 2554/3053/14530 2553/3052/14531 2555/3054/14532 -f 2557/3056/14533 2558/3057/14534 2555/3054/14535 -f 2555/3054/14536 2553/3052/14537 2557/3056/14538 -f 2559/3068/14539 2557/3056/14540 2553/3052/14541 -f 2553/3052/14542 2551/3050/14543 2559/3068/14544 -f 2559/3068/14545 2551/3050/14546 2550/3049/14547 -f 2550/3049/14548 2560/3166/14549 2559/3068/14550 -f 2550/3049/14551 2547/3048/14552 2561/3175/14553 -f 2561/3175/14554 2560/3166/14555 2550/3049/14556 -f 2562/3045/14557 2561/3058/14558 2547/3043/14559 -f 2547/3043/14560 2545/3041/14561 2562/3045/14562 -f 2564/3065/14563 2561/3066/14564 2562/3063/14565 -f 2562/3063/14566 2563/3064/14567 2564/3065/14568 -f 2566/3069/14569 2564/3065/14570 2563/3064/14571 -f 2563/3064/14572 2565/3067/14573 2566/3069/14574 -f 2567/3070/14575 2568/3079/14576 2566/3069/14577 -f 2566/3069/14578 2565/3067/14579 2567/3070/14580 -f 2565/3067/14581 2570/3081/14582 2569/3080/14583 -f 2569/3080/14584 2567/3070/14585 2565/3067/14586 -f 2538/3062/14587 2570/3081/14588 2565/3067/14589 -f 2565/3067/14590 2563/3064/14591 2538/3062/14592 -f 2564/3065/14593 2572/3188/14594 2571/3082/14595 -f 2571/3082/14596 2561/3066/14597 2564/3065/14598 -f 2566/3069/14599 2573/3189/14600 2572/3188/14601 -f 2572/3188/14602 2564/3065/14603 2566/3069/14604 -f 2538/3062/14605 2563/3064/14606 2562/3063/14607 -f 2562/3063/14608 2537/3061/14609 2538/3062/14610 -f 2562/3045/14611 2545/3041/14612 2540/3036/14613 -f 2540/3036/14614 2537/3034/14615 2562/3045/14616 -f 2574/3059/14617 2575/3071/14618 2543/3039/14619 -f 2543/3039/14620 2542/3038/14621 2574/3059/14622 -f 2539/3030/14623 2543/3039/14624 2534/3072/14625 -f 2534/3072/14626 2533/3031/14627 2539/3030/14628 -f 2576/3073/14629 2534/3072/14630 2543/3039/14631 -f 2543/3039/14632 2575/3071/14633 2576/3073/14634 -f 2575/3071/14635 2578/3075/14636 2577/3074/14637 -f 2577/3074/14638 2576/3073/14639 2575/3071/14640 -f 2579/3076/14641 2580/3077/14642 2576/3073/14643 -f 2576/3073/14644 2577/3074/14645 2579/3076/14646 -f 2576/3073/14647 2580/3077/14648 2581/3078/14649 -f 2581/3078/14650 2534/3072/14651 2576/3073/14652 -f 2581/3190/14653 2582/3191/14654 2535/3035/14655 -f 2535/3035/14656 2534/3033/14657 2581/3190/14658 -f 2584/3193/14659 2536/3060/14660 2535/3035/14661 -f 2535/3035/14662 2583/3192/14663 2584/3193/14664 -f 2585/3194/14665 2583/3192/14666 2535/3035/14667 -f 2535/3035/14668 2582/3191/14669 2585/3194/14670 -f 2586/3083/14671 2587/3084/14672 2579/3076/14673 -f 2579/3076/14674 2577/3074/14675 2586/3083/14676 -f 2577/3074/14677 2578/3075/14678 2588/3085/14679 -f 2588/3085/14680 2586/3083/14681 2577/3074/14682 -f 2589/3086/14683 2590/3087/14684 2588/3085/14685 -f 2588/3085/14686 2578/3075/14687 2589/3086/14688 -f 2588/3085/14689 2592/3089/14690 2591/3088/14691 -f 2591/3088/14692 2586/3083/14693 2588/3085/14694 -f 2588/3085/14695 2590/3087/14696 2593/3090/14697 -f 2593/3090/14698 2592/3089/14699 2588/3085/14700 -f 2587/3084/14701 2586/3083/14702 2591/3088/14703 -f 2591/3088/14704 2594/3091/14705 2587/3084/14706 -f 2594/3091/14707 2591/3088/14708 2595/3237/14709 -f 2595/3237/14710 2596/3238/14711 2594/3091/14712 -f 2578/3075/14713 2575/3071/14714 2574/3059/14715 -f 2574/3059/14716 2589/3086/14717 2578/3075/14718 -f 2599/3098/14719 2600/3099/14720 2597/3095/14721 -f 2597/3095/14722 2598/3096/14723 2599/3098/14724 -f 2602/3101/14725 2599/3098/14726 2598/3096/14727 -f 2598/3096/14728 2601/3100/14729 2602/3101/14730 -f 2604/3103/14731 2602/3101/14732 2601/3100/14733 -f 2601/3100/14734 2603/3102/14735 2604/3103/14736 -f 2603/3102/14737 2606/3105/14738 2605/3104/14739 -f 2605/3104/14740 2604/3221/14741 2603/3102/14742 -f 2605/3104/14743 2606/3105/14744 2607/3106/14745 -f 2607/3106/14746 2608/3107/14747 2605/3104/14748 -f 2608/3223/14749 2607/3106/14750 2609/3108/14751 -f 2609/3108/14752 2610/3109/14753 2608/3223/14754 -f 2612/3111/14755 2613/3112/14756 2609/3108/14757 -f 2609/3108/14758 2611/3110/14759 2612/3111/14760 -f 2606/3105/14761 2603/3102/14762 2614/3113/14763 -f 2614/3113/14764 2611/3110/14765 2606/3105/14766 -f 2614/3113/14767 2615/3114/14768 2612/3111/14769 -f 2612/3111/14770 2611/3110/14771 2614/3113/14772 -f 2617/3116/14773 2613/3112/14774 2612/3111/14775 -f 2612/3111/14776 2616/3115/14777 2617/3116/14778 -f 2618/3117/14779 2619/3118/14780 2617/3116/14781 -f 2617/3116/14782 2616/3115/14783 2618/3117/14784 -f 2621/3120/14785 2618/3117/14786 2616/3115/14787 -f 2616/3115/14788 2620/3119/14789 2621/3120/14790 -f 2612/3111/14791 2615/3114/14792 2620/3119/14793 -f 2620/3119/14794 2616/3115/14795 2612/3111/14796 -f 2610/3109/14797 2609/3108/14798 2613/3112/14799 -f 2613/3112/14800 2622/3121/14801 2610/3109/14802 -f 2623/3122/14803 2622/3227/14804 2613/3112/14805 -f 2613/3112/14806 2617/3116/14807 2623/3122/14808 -f 2615/3114/14809 2614/3113/14810 2624/3123/14811 -f 2624/3123/14812 2625/3124/14813 2615/3114/14814 -f 2627/3128/14815 2625/3124/14816 2624/3123/14817 -f 2624/3123/14818 2626/3127/14819 2627/3128/14820 -f 2601/3100/14821 2598/3096/14822 2626/3127/14823 -f 2626/3127/14824 2624/3123/14825 2601/3100/14826 -f 2629/3167/14827 2627/3128/14828 2626/3127/14829 -f 2626/3127/14830 2628/3164/14831 2629/3167/14832 -f 2628/3164/14833 2626/3127/14834 2598/3096/14835 -f 2598/3096/14836 2597/3095/14837 2628/3164/14838 -f 2630/3183/14839 2620/3119/14840 2615/3114/14841 -f 2615/3114/14842 2625/3124/14843 2630/3183/14844 -f 2631/3184/14845 2630/3183/14846 2625/3124/14847 -f 2625/3124/14848 2627/3128/14849 2631/3184/14850 -f 2614/3113/14851 2603/3102/14852 2601/3100/14853 -f 2601/3100/14854 2624/3123/14855 2614/3113/14856 -f 2606/3105/14857 2611/3110/14858 2609/3108/14859 -f 2609/3108/14860 2607/3106/14861 2606/3105/14862 -f 2632/3125/14863 2633/3126/14864 2597/3094/14865 -f 2597/3094/14866 2600/3097/14867 2632/3125/14868 -f 2633/3126/14869 2632/3125/14870 2634/3129/14871 -f 2634/3129/14872 2635/3130/14873 2633/3126/14874 -f 2634/3129/14875 2637/3132/14876 2636/3131/14877 -f 2636/3131/14878 2635/3130/14879 2634/3129/14880 -f 2639/3134/14881 2640/3135/14882 2636/3131/14883 -f 2636/3131/14884 2638/3133/14885 2639/3134/14886 -f 2641/3136/14887 2642/3137/14888 2639/3134/14889 -f 2639/3134/14890 2638/3133/14891 2641/3136/14892 -f 2643/3140/14893 2644/3141/14894 2640/3135/14895 -f 2640/3135/14896 2639/3134/14897 2643/3140/14898 -f 2646/3143/14899 2640/3135/14900 2644/3141/14901 -f 2644/3141/14902 2645/3142/14903 2646/3143/14904 -f 2645/3142/14905 2648/3145/14906 2647/3144/14907 -f 2647/3144/14908 2646/3143/14909 2645/3142/14910 -f 2650/3147/14911 2647/3144/14912 2648/3145/14913 -f 2648/3145/14914 2649/3146/14915 2650/3147/14916 -f 2650/3147/14917 2649/3146/14918 2651/3148/14919 -f 2651/3148/14920 2652/3149/14921 2650/3147/14922 -f 2635/3130/14923 2646/3143/14924 2647/3144/14925 -f 2647/3144/14926 2633/3126/14927 2635/3130/14928 -f 2647/3144/14929 2650/3147/14930 2597/3094/14931 -f 2597/3094/14932 2633/3126/14933 2647/3144/14934 -f 2640/3135/14935 2646/3143/14936 2635/3130/14937 -f 2635/3130/14938 2636/3131/14939 2640/3135/14940 -f 2639/3134/14941 2642/3137/14942 2653/3163/14943 -f 2653/3163/14944 2643/3140/14945 2639/3134/14946 -f 2654/3138/14947 2655/3139/14948 2653/3092/14949 -f 2653/3092/14950 2642/3093/14951 2654/3138/14952 -f 2642/3093/14953 2641/3151/14954 2656/3150/14955 -f 2656/3150/14956 2654/3138/14957 2642/3093/14958 -f 2658/3153/14959 2659/3154/14960 2657/3152/14961 -f 2657/3152/14962 2656/3150/14963 2658/3153/14964 -f 2656/3150/14965 2641/3151/14966 2660/3155/14967 -f 2660/3155/14968 2658/3153/14969 2656/3150/14970 -f 2657/3152/14971 2661/3156/14972 2654/3138/14973 -f 2654/3138/14974 2656/3150/14975 2657/3152/14976 -s 2 -f 2662/3157/14977 2653/3092/14978 2655/3139/14979 -s 4 -f 2662/3157/14980 2663/3158/14981 2664/3159/14982 -s 1 -f 2662/3157/14983 2661/3156/14984 2665/3160/14985 -f 2665/3160/14986 2663/3158/14987 2662/3157/14988 -f 2661/3156/14989 2662/3157/14990 2655/3139/14991 -f 2655/3139/14992 2654/3138/14993 2661/3156/14994 -f 2660/3168/14995 2641/3136/14996 2638/3133/14997 -f 2638/3133/14998 2666/3165/14999 2660/3168/15000 -f 2666/3165/15001 2638/3133/15002 2636/3131/15003 -f 2636/3131/15004 2637/3132/15005 2666/3165/15006 -f 2650/3147/15007 2652/3149/15008 2628/3169/15009 -f 2628/3169/15010 2597/3094/15011 2650/3147/15012 -f 2669/3187/15013 2670/3212/15014 2667/3185/15015 -f 2667/3185/15016 2668/3186/15017 2669/3187/15018 -f 2631/3184/15019 2671/3213/15020 2668/3186/15021 -f 2668/3186/15022 2667/3185/15023 2631/3184/15024 -f 2673/3172/15025 2668/3173/15026 2671/3170/15027 -f 2671/3170/15028 2672/3171/15029 2673/3172/15030 -f 2675/3241/15031 2673/3172/15032 2672/3171/15033 -f 2672/3171/15034 2674/3174/15035 2675/3241/15036 -f 2676/3242/15037 2677/3243/15038 2674/3174/15039 -f 2674/3174/15040 2672/3171/15041 2676/3242/15042 -f 2652/3149/15043 2651/3148/15044 2677/3243/15045 -f 2677/3243/15046 2676/3242/15047 2652/3149/15048 -f 2652/3149/15049 2676/3242/15050 2629/3244/15051 -f 2629/3244/15052 2628/3169/15053 2652/3149/15054 -f 2672/3171/15055 2671/3170/15056 2629/3244/15057 -f 2629/3244/15058 2676/3242/15059 2672/3171/15060 -f 2675/3178/15061 2679/3179/15062 2678/3176/15063 -f 2678/3176/15064 2673/3177/15065 2675/3178/15066 -f 2558/3057/15067 2680/3180/15068 2678/3176/15069 -f 2678/3176/15070 2555/3054/15071 2558/3057/15072 -f 2680/3180/15073 2668/3181/15074 2673/3177/15075 -f 2673/3177/15076 2678/3176/15077 2680/3180/15078 -f 2669/3229/15079 2668/3181/15080 2680/3180/15081 -f 2680/3180/15082 2681/3182/15083 2669/3229/15084 -f 2682/3230/15085 2681/3182/15086 2680/3180/15087 -f 2680/3180/15088 2558/3057/15089 2682/3230/15090 -f 2682/3230/15091 2558/3057/15092 2557/3056/15093 -f 2557/3056/15094 2683/3231/15095 2682/3230/15096 -f 2557/3056/15097 2559/3068/15098 2684/3234/15099 -f 2684/3234/15100 2683/3231/15101 2557/3056/15102 -f 2684/3234/15103 2559/3068/15104 2560/3166/15105 -f 2560/3166/15106 2685/3235/15107 2684/3234/15108 -f 2556/3055/15109 2555/3054/15110 2678/3176/15111 -f 2678/3176/15112 2679/3179/15113 2556/3055/15114 -f 2631/3184/15115 2627/3128/15116 2629/3167/15117 -f 2629/3167/15118 2671/3213/15119 2631/3184/15120 -f 2686/3214/15121 2630/3183/15122 2631/3184/15123 -f 2631/3184/15124 2667/3185/15125 2686/3214/15126 -f 2620/3119/15127 2630/3183/15128 2686/3214/15129 -f 2686/3214/15130 2621/3120/15131 2620/3119/15132 -f 2621/3120/15133 2686/3214/15134 2687/3215/15135 -f 2687/3215/15136 2688/3216/15137 2621/3120/15138 -f 2670/3212/15139 2687/3215/15140 2686/3214/15141 -f 2686/3214/15142 2667/3185/15143 2670/3212/15144 -f 2689/3217/15145 2618/3117/15146 2621/3120/15147 -f 2621/3120/15148 2688/3232/15149 2689/3217/15150 -f 2690/3218/15151 2619/3118/15152 2618/3117/15153 -f 2618/3117/15154 2689/3217/15155 2690/3218/15156 -f 2690/3233/15157 2623/3122/15158 2617/3116/15159 -f 2617/3116/15160 2619/3118/15161 2690/3233/15162 -f 2561/3175/15163 2571/3236/15164 2685/3235/15165 -f 2685/3235/15166 2560/3166/15167 2561/3175/15168 -f 2584/3193/15169 2570/3081/15170 2538/3062/15171 -f 2538/3062/15172 2536/3060/15173 2584/3193/15174 -f 2691/3195/15175 2569/3080/15176 2570/3081/15177 -f 2570/3081/15178 2584/3193/15179 2691/3195/15180 -f 2691/3195/15181 2584/3193/15182 2583/3192/15183 -f 2583/3192/15184 2692/3196/15185 2691/3195/15186 -f 2694/3198/15187 2691/3195/15188 2692/3196/15189 -f 2692/3196/15190 2693/3197/15191 2694/3198/15192 -f 2696/3200/15193 2694/3198/15194 2693/3197/15195 -f 2693/3197/15196 2695/3199/15197 2696/3200/15198 -f 2698/3202/15199 2695/3199/15200 2693/3197/15201 -f 2693/3197/15202 2697/3201/15203 2698/3202/15204 -f 2692/3196/15205 2699/3203/15206 2697/3201/15207 -f 2697/3201/15208 2693/3197/15209 2692/3196/15210 -f 2583/3192/15211 2585/3194/15212 2699/3246/15213 -f 2699/3246/15214 2692/3196/15215 2583/3192/15216 -f 2696/3200/15217 2695/3199/15218 2698/3245/15219 -f 2698/3245/15220 2700/3204/15221 2696/3200/15222 -f 2701/3205/15223 2702/3206/15224 2696/3200/15225 -f 2696/3200/15226 2700/3204/15227 2701/3205/15228 -f 2696/3200/15229 2702/3206/15230 2703/3207/15231 -f 2703/3207/15232 2694/3198/15233 2696/3200/15234 -f 2567/3070/15235 2569/3080/15236 2703/3207/15237 -f 2703/3207/15238 2704/3208/15239 2567/3070/15240 -f 2705/3219/15241 2704/3208/15242 2703/3207/15243 -f 2703/3207/15244 2702/3206/15245 2705/3219/15246 -f 2701/3247/15247 2706/3220/15248 2705/3219/15249 -f 2705/3219/15250 2702/3206/15251 2701/3247/15252 -f 2704/3208/15253 2707/3222/15254 2568/3079/15255 -f 2568/3079/15256 2567/3070/15257 2704/3208/15258 -f 2707/3222/15259 2710/3226/15260 2708/3224/15261 -f 2708/3224/15262 2709/3225/15263 2707/3222/15264 -f 2710/3226/15265 2707/3222/15266 2704/3208/15267 -f 2704/3208/15268 2705/3219/15269 2710/3226/15270 -f 2707/3222/15271 2709/3225/15272 2711/3228/15273 -f 2711/3228/15274 2568/3079/15275 2707/3222/15276 -f 2694/3198/15277 2703/3207/15278 2569/3080/15279 -f 2569/3080/15280 2691/3195/15281 2694/3198/15282 -f 2712/3161/15283 2665/3160/15284 2661/3156/15285 -f 2661/3156/15286 2657/3152/15287 2712/3161/15288 -f 2595/3162/15289 2713/3209/15290 2665/3160/15291 -f 2665/3160/15292 2712/3161/15293 2595/3162/15294 -f 2591/3088/15295 2592/3089/15296 2713/3239/15297 -f 2713/3239/15298 2595/3237/15299 2591/3088/15300 -f 2664/3159/15301 2663/3158/15302 2665/3160/15303 -f 2665/3160/15304 2713/3209/15305 2664/3159/15306 -f 2592/3089/15307 2593/3090/15308 2664/3240/15309 -f 2664/3240/15310 2713/3239/15311 2592/3089/15312 -f 2714/3210/15313 2596/3211/15314 2595/3162/15315 -f 2595/3162/15316 2712/3161/15317 2714/3210/15318 -f 2659/3154/15319 2714/3210/15320 2712/3161/15321 -f 2712/3161/15322 2657/3152/15323 2659/3154/15324 -f 2573/3189/15325 2566/3069/15326 2568/3079/15327 -f 2568/3079/15328 2711/3249/15329 2573/3189/15330 -f 2708/3248/15331 2710/3226/15332 2705/3219/15333 -f 2705/3219/15334 2706/3220/15335 2708/3248/15336 -f 2716/3252/15337 2715/3253/15338 2718/3250/15339 -f 2718/3250/15340 2717/3251/15341 2716/3252/15342 -f 2719/3255/15343 2717/3251/15344 2718/3250/15345 -f 2718/3250/15346 2720/3254/15347 2719/3255/15348 -f 2721/3256/15349 2720/3257/15350 2718/3250/15351 -f 2718/3250/15352 2715/3253/15353 2721/3256/15354 -f 2722/3258/15355 2716/3252/15356 2717/3251/15357 -f 2717/3251/15358 2719/3255/15359 2722/3258/15360 -f 2723/3260/15361 2719/3255/15362 2720/3254/15363 -f 2720/3254/15364 2721/3259/15365 2723/3260/15366 -f 2719/3255/15367 2723/3260/15368 2724/3261/15369 -f 2724/3261/15370 2722/3258/15371 2719/3255/15372 -f 2727/3262/15373 2726/3263/15374 2725/3264/15375 -f 2723/3260/15376 2721/3259/15377 2727/3265/15378 -f 2727/3265/15379 2728/3266/15380 2723/3260/15381 -f 2727/3265/15382 2729/3267/15383 2728/3266/15384 -f 2731/3270/15385 2730/3271/15386 2733/3268/15387 -f 2733/3268/15388 2732/3269/15389 2731/3270/15390 -f 2735/3274/15391 2734/3275/15392 2737/3272/15393 -f 2737/3272/15394 2736/3273/15395 2735/3274/15396 -f 2738/3276/15397 2736/3273/15398 2737/3272/15399 -f 2737/3272/15400 2733/3268/15401 2738/3276/15402 -f 2739/3277/15403 2733/3268/15404 2737/3272/15405 -f 2737/3272/15406 2734/3275/15407 2739/3277/15408 -f 2741/3280/15409 2740/3281/15410 2743/3278/15411 -f 2743/3278/15412 2742/3279/15413 2741/3280/15414 -f 2745/3284/15415 2744/3285/15416 2747/3282/15417 -f 2747/3282/15418 2746/3283/15419 2745/3284/15420 -f 2746/3283/15421 2747/3282/15422 2749/3286/15423 -f 2749/3286/15424 2748/3287/15425 2746/3283/15426 -f 2747/3282/15427 2750/3288/15428 2749/3286/15429 -f 2752/3291/15430 2751/3292/15431 2754/3289/15432 -f 2754/3289/15433 2753/3290/15434 2752/3291/15435 -f 2754/3289/15436 2755/3293/15437 2753/3290/15438 -f 2754/3289/15439 2751/3292/15440 2756/3294/15441 -f 2753/3290/15442 2755/3293/15443 2758/3295/15444 -f 2758/3295/15445 2757/3296/15446 2753/3290/15447 -f 2752/3291/15448 2753/3290/15449 2757/3296/15450 -f 2752/3291/15451 2757/3296/15452 2760/3297/15453 -f 2760/3297/15454 2759/3298/15455 2752/3291/15456 -f 2761/3301/15457 2745/3284/15458 2763/3299/15459 -f 2763/3299/15460 2762/3300/15461 2761/3301/15462 -f 2763/3299/15463 2764/3304/15464 2766/3302/15465 -f 2766/3302/15466 2765/3303/15467 2763/3299/15468 -f 2763/3299/15469 2765/3303/15470 2767/3305/15471 -f 2767/3305/15472 2762/3300/15473 2763/3299/15474 -f 2769/3308/15475 2768/3309/15476 2771/3306/15477 -f 2771/3306/15478 2770/3307/15479 2769/3308/15480 -f 2773/3310/15481 2772/3311/15482 2768/3309/15483 -f 2768/3309/15484 2769/3308/15485 2773/3310/15486 -f 2774/3313/15487 2769/3308/15488 2770/3307/15489 -f 2770/3307/15490 2775/3312/15491 2774/3313/15492 -f 2776/3315/15493 2772/3311/15494 2773/3310/15495 -f 2773/3310/15496 2777/3314/15497 2776/3315/15498 -f 2778/3316/15499 2758/3295/15500 2767/3305/15501 -f 2767/3305/15502 2765/3303/15503 2778/3316/15504 -f 2770/3307/15505 2771/3306/15506 2780/3317/15507 -f 2780/3317/15508 2779/3318/15509 2770/3307/15510 -f 2782/3321/15511 2781/3322/15512 2784/3319/15513 -f 2784/3319/15514 2783/3320/15515 2782/3321/15516 -f 2783/3320/15517 2784/3319/15518 2786/3323/15519 -f 2786/3323/15520 2785/3324/15521 2783/3320/15522 -f 2788/3327/15523 2787/3328/15524 2790/3325/15525 -f 2790/3325/15526 2789/3326/15527 2788/3327/15528 -f 2789/3326/15529 2790/3325/15530 2791/3329/15531 -f 2793/3331/15532 2792/3332/15533 2789/3326/15534 -f 2789/3326/15535 2794/3330/15536 2793/3331/15537 -f 2795/3333/15538 2794/3330/15539 2789/3326/15540 -f 2789/3326/15541 2791/3329/15542 2795/3333/15543 -f 2770/3307/15544 2796/3335/15545 2797/3334/15546 -f 2797/3334/15547 2775/3312/15548 2770/3307/15549 -f 2777/3314/15550 2798/3338/15551 2800/3336/15552 -f 2800/3336/15553 2799/3337/15554 2777/3314/15555 -f 2802/3339/15556 2801/3340/15557 2800/3336/15558 -f 2800/3336/15559 2798/3338/15560 2802/3339/15561 -f 2804/3341/15562 2803/3342/15563 2800/3336/15564 -f 2800/3336/15565 2801/3340/15566 2804/3341/15567 -f 2777/3314/15568 2773/3310/15569 2805/3343/15570 -f 2805/3343/15571 2798/3338/15572 2777/3314/15573 -f 2805/3343/15574 2773/3310/15575 2774/3313/15576 -f 2774/3313/15577 2806/3344/15578 2805/3343/15579 -f 2805/3343/15580 2806/3344/15581 2807/3345/15582 -f 2809/3346/15583 2808/3347/15584 2805/3343/15585 -f 2805/3343/15586 2807/3345/15587 2809/3346/15588 -f 2812/3348/15589 2811/3349/15590 2810/3350/15591 -f 2813/3352/15592 2794/3330/15593 2795/3333/15594 -f 2795/3333/15595 2814/3351/15596 2813/3352/15597 -f 2816/3354/15598 2815/3355/15599 2795/3333/15600 -f 2795/3333/15601 2817/3353/15602 2816/3354/15603 -f 2818/3356/15604 2814/3351/15605 2795/3333/15606 -f 2795/3333/15607 2815/3355/15608 2818/3356/15609 -f 2820/3359/15610 2819/3360/15611 2822/3357/15612 -f 2822/3357/15613 2821/3358/15614 2820/3359/15615 -f 2766/3302/15616 2821/3358/15617 2822/3357/15618 -f 2822/3357/15619 2812/3348/15620 2766/3302/15621 -f 2819/3360/15622 2823/3361/15623 2822/3357/15624 -f 2822/3357/15625 2823/3361/15626 2824/3362/15627 -f 2822/3357/15628 2824/3362/15629 2811/3349/15630 -f 2826/3365/15631 2825/3366/15632 2828/3363/15633 -f 2828/3363/15634 2827/3364/15635 2826/3365/15636 -f 2828/3363/15637 2829/3369/15638 2831/3367/15639 -f 2831/3367/15640 2830/3368/15641 2828/3363/15642 -f 2796/3335/15643 2832/3371/15644 2833/3370/15645 -f 2833/3370/15646 2797/3334/15647 2796/3335/15648 -f 2833/3370/15649 2834/3372/15650 2797/3334/15651 -f 2770/3307/15652 2779/3318/15653 2832/3371/15654 -f 2832/3371/15655 2796/3335/15656 2770/3307/15657 -f 2836/3373/15658 2835/3374/15659 2823/3361/15660 -f 2838/3376/15661 2837/3377/15662 2839/3375/15663 -f 2839/3375/15664 2836/3373/15665 2838/3376/15666 -f 2840/3379/15667 2835/3374/15668 2839/3375/15669 -f 2839/3375/15670 2841/3378/15671 2840/3379/15672 -f 2839/3375/15673 2835/3374/15674 2836/3373/15675 -f 2843/3382/15676 2842/3383/15677 2845/3380/15678 -f 2845/3380/15679 2844/3381/15680 2843/3382/15681 -f 2847/3384/15682 2846/3385/15683 2845/3380/15684 -f 2845/3380/15685 2842/3383/15686 2847/3384/15687 -f 2848/3387/15688 2844/3381/15689 2845/3380/15690 -f 2845/3380/15691 2849/3386/15692 2848/3387/15693 -f 2851/3390/15694 2850/3391/15695 2853/3388/15696 -f 2853/3388/15697 2852/3389/15698 2851/3390/15699 -f 2852/3389/15700 2854/3392/15701 2851/3390/15702 -f 2855/3395/15703 2834/3372/15704 2857/3393/15705 -f 2857/3393/15706 2856/3394/15707 2855/3395/15708 -f 2856/3394/15709 2857/3393/15710 2859/3396/15711 -f 2859/3396/15712 2858/3397/15713 2856/3394/15714 -f 2833/3370/15715 2859/3396/15716 2857/3393/15717 -f 2857/3393/15718 2834/3372/15719 2833/3370/15720 -f 2860/3399/15721 2829/3369/15722 2861/3398/15723 -f 2861/3398/15724 2840/3379/15725 2860/3399/15726 -f 2840/3379/15727 2861/3398/15728 2862/3400/15729 -f 2862/3400/15730 2835/3374/15731 2840/3379/15732 -f 2860/3399/15733 2863/3402/15734 2864/3401/15735 -f 2864/3401/15736 2829/3369/15737 2860/3399/15738 -f 2829/3369/15739 2864/3401/15740 2865/3403/15741 -f 2865/3403/15742 2831/3367/15743 2829/3369/15744 -f 2866/3404/15745 2860/3399/15746 2840/3379/15747 -f 2840/3379/15748 2841/3378/15749 2866/3404/15750 -f 2853/3388/15751 2867/3406/15752 2868/3405/15753 -f 2868/3405/15754 2852/3389/15755 2853/3388/15756 -f 2854/3392/15757 2852/3389/15758 2868/3405/15759 -f 2868/3405/15760 2869/3407/15761 2854/3392/15762 -f 2870/3408/15763 2869/3407/15764 2868/3405/15765 -f 2868/3405/15766 2867/3406/15767 2870/3408/15768 -f 2859/3396/15769 2871/3410/15770 2872/3409/15771 -f 2872/3409/15772 2858/3397/15773 2859/3396/15774 -f 2847/3384/15775 2858/3397/15776 2872/3409/15777 -f 2872/3409/15778 2873/3411/15779 2847/3384/15780 -f 2874/3412/15781 2873/3411/15782 2872/3409/15783 -f 2872/3409/15784 2871/3410/15785 2874/3412/15786 -f 2876/3413/15787 2875/3414/15788 2870/3408/15789 -f 2870/3408/15790 2867/3406/15791 2876/3413/15792 -f 2877/3415/15793 2869/3407/15794 2870/3408/15795 -f 2870/3408/15796 2875/3414/15797 2877/3415/15798 -f 2878/3416/15799 2874/3412/15800 2871/3410/15801 -f 2871/3410/15802 2859/3396/15803 2878/3416/15804 -f 2850/3391/15805 2879/3418/15806 2880/3417/15807 -f 2880/3417/15808 2853/3388/15809 2850/3391/15810 -f 2882/3419/15811 2881/3420/15812 2853/3388/15813 -f 2853/3388/15814 2880/3417/15815 2882/3419/15816 -f 2876/3413/15817 2867/3406/15818 2853/3388/15819 -f 2853/3388/15820 2881/3420/15821 2876/3413/15822 -f 2884/3423/15823 2883/3424/15824 2886/3421/15825 -f 2886/3421/15826 2885/3422/15827 2884/3423/15828 -f 2887/3426/15829 2885/3422/15830 2886/3421/15831 -f 2886/3421/15832 2888/3425/15833 2887/3426/15834 -f 2889/3427/15835 2888/3425/15836 2886/3421/15837 -f 2886/3421/15838 2883/3424/15839 2889/3427/15840 -f 2890/3429/15841 2888/3425/15842 2889/3427/15843 -f 2889/3427/15844 2891/3428/15845 2890/3429/15846 -f 2892/3430/15847 2891/3428/15848 2889/3427/15849 -f 2889/3427/15850 2883/3424/15851 2892/3430/15852 -f 2894/3431/15853 2893/3432/15854 2876/3413/15855 -f 2876/3413/15856 2881/3420/15857 2894/3431/15858 -f 2885/3422/15859 2875/3414/15860 2876/3413/15861 -f 2876/3413/15862 2884/3423/15863 2885/3422/15864 -f 2895/3433/15865 2884/3423/15866 2876/3413/15867 -f 2876/3413/15868 2893/3432/15869 2895/3433/15870 -f 2896/3435/15871 2873/3411/15872 2874/3412/15873 -f 2874/3412/15874 2897/3434/15875 2896/3435/15876 -f 2899/3438/15877 2898/3439/15878 2901/3436/15879 -f 2901/3436/15880 2900/3437/15881 2899/3438/15882 -f 2903/3441/15883 2902/3442/15884 2901/3436/15885 -f 2901/3436/15886 2904/3440/15887 2903/3441/15888 -f 2905/3443/15889 2900/3437/15890 2901/3436/15891 -f 2901/3436/15892 2902/3442/15893 2905/3443/15894 -f 2907/3446/15895 2906/3447/15896 2909/3444/15897 -f 2909/3444/15898 2908/3445/15899 2907/3446/15900 -f 2910/3449/15901 2908/3445/15902 2909/3444/15903 -f 2909/3444/15904 2911/3448/15905 2910/3449/15906 -f 2912/3450/15907 2911/3448/15908 2909/3444/15909 -f 2909/3444/15910 2906/3447/15911 2912/3450/15912 -f 2914/3453/15913 2913/3454/15914 2916/3451/15915 -f 2916/3451/15916 2915/3452/15917 2914/3453/15918 -f 2918/3455/15919 2917/3456/15920 2916/3451/15921 -f 2916/3451/15922 2913/3454/15923 2918/3455/15924 -f 2920/3457/15925 2919/3458/15926 2916/3451/15927 -f 2916/3451/15928 2917/3456/15929 2920/3457/15930 -f 2863/3402/15931 2915/3452/15932 2916/3451/15933 -f 2916/3451/15934 2921/3459/15935 2863/3402/15936 -f 2922/3460/15937 2921/3459/15938 2916/3451/15939 -f 2916/3451/15940 2919/3458/15941 2922/3460/15942 -f 2895/3433/15943 2893/3432/15944 2923/3461/15945 -f 2923/3461/15946 2918/3455/15947 2895/3433/15948 -f 2894/3431/15949 2924/3462/15950 2923/3461/15951 -f 2923/3461/15952 2893/3432/15953 2894/3431/15954 -f 2917/3456/15955 2918/3455/15956 2923/3461/15957 -f 2923/3461/15958 2925/3463/15959 2917/3456/15960 -f 2927/3466/15961 2926/3467/15962 2929/3464/15963 -f 2929/3464/15964 2928/3465/15965 2927/3466/15966 -f 2928/3465/15967 2929/3464/15968 2931/3468/15969 -f 2931/3468/15970 2930/3469/15971 2928/3465/15972 -f 2932/3470/15973 2931/3468/15974 2929/3464/15975 -f 2929/3464/15976 2926/3467/15977 2932/3470/15978 -f 2934/3473/15979 2933/3474/15980 2936/3471/15981 -f 2936/3471/15982 2935/3472/15983 2934/3473/15984 -f 2937/3476/15985 2935/3472/15986 2936/3471/15987 -f 2936/3471/15988 2938/3475/15989 2937/3476/15990 -f 2940/3477/15991 2939/3478/15992 2936/3471/15993 -f 2936/3471/15994 2933/3474/15995 2940/3477/15996 -f 2942/3481/15997 2941/3482/15998 2943/3479/15999 -f 2943/3479/16000 2940/3480/16001 2942/3481/16002 -f 2939/3478/16003 2940/3477/16004 2943/3483/16005 -f 2943/3483/16006 2944/3484/16007 2939/3478/16008 -f 2945/3485/16009 2944/3486/16010 2943/3479/16011 -f 2943/3479/16012 2941/3482/16013 2945/3485/16014 -f 2947/3489/16015 2946/3490/16016 2949/3487/16017 -f 2949/3487/16018 2948/3488/16019 2947/3489/16020 -f 2951/3493/16021 2950/3494/16022 2949/3491/16023 -f 2949/3491/16024 2952/3492/16025 2951/3493/16026 -f 2953/3495/16027 2952/3496/16028 2949/3487/16029 -f 2949/3487/16030 2946/3490/16031 2953/3495/16032 -f 2955/3499/16033 2954/3500/16034 2957/3497/16035 -f 2957/3497/16036 2956/3498/16037 2955/3499/16038 -f 2958/3502/16039 2956/3498/16040 2957/3497/16041 -f 2957/3497/16042 2959/3501/16043 2958/3502/16044 -f 2960/3504/16045 2959/3501/16046 2957/3497/16047 -f 2957/3497/16048 2961/3503/16049 2960/3504/16050 -f 2963/3507/16051 2962/3508/16052 2965/3505/16053 -f 2965/3505/16054 2964/3506/16055 2963/3507/16056 -f 2930/3469/16057 2964/3506/16058 2965/3505/16059 -f 2965/3505/16060 2966/3509/16061 2930/3469/16062 -f 2968/3510/16063 2967/3511/16064 2965/3505/16065 -f 2965/3505/16066 2962/3508/16067 2968/3510/16068 -f 2970/3512/16069 2969/3513/16070 2965/3505/16071 -f 2965/3505/16072 2967/3511/16073 2970/3512/16074 -f 2973/3514/16075 2972/3515/16076 2971/3516/16077 -f 2975/3517/16078 2974/3518/16079 2973/3514/16080 -f 2973/3514/16081 2971/3516/16082 2975/3517/16083 -f 2977/3521/16084 2976/3522/16085 2979/3519/16086 -f 2979/3519/16087 2978/3520/16088 2977/3521/16089 -f 2981/3525/16090 2980/3526/16091 2983/3523/16092 -f 2983/3523/16093 2982/3524/16094 2981/3525/16095 -f 2946/3490/16096 2947/3489/16097 2982/3524/16098 -f 2982/3524/16099 2983/3523/16100 2946/3490/16101 -f 2985/3529/16102 2984/3530/16103 2987/3527/16104 -f 2987/3527/16105 2986/3528/16106 2985/3529/16107 -f 2988/3532/16108 2986/3528/16109 2987/3527/16110 -f 2987/3527/16111 2989/3531/16112 2988/3532/16113 -f 2991/3535/16114 2990/3536/16115 2993/3533/16116 -f 2993/3533/16117 2992/3534/16118 2991/3535/16119 -f 2995/3537/16120 2994/3538/16121 2993/3533/16122 -f 2993/3533/16123 2990/3536/16124 2995/3537/16125 -f 2996/3539/16126 2992/3534/16127 2993/3533/16128 -f 2993/3533/16129 2994/3538/16130 2996/3539/16131 -f 2998/3540/16132 2997/3541/16133 2995/3537/16134 -f 3000/3544/16135 2999/3545/16136 3002/3542/16137 -f 3002/3542/16138 3001/3543/16139 3000/3544/16140 -f 3001/3543/16141 3003/3546/16142 3000/3544/16143 -f 3005/3549/16144 3004/3550/16145 3007/3547/16146 -f 3007/3547/16147 3006/3548/16148 3005/3549/16149 -f 3008/3552/16150 3006/3548/16151 3007/3547/16152 -f 3007/3547/16153 3009/3551/16154 3008/3552/16155 -f 3010/3554/16156 3009/3551/16157 3007/3547/16158 -f 3007/3547/16159 3011/3553/16160 3010/3554/16161 -f 3013/3555/16162 3005/3549/16163 3012/3556/16164 -f 2760/3297/16165 3014/3558/16166 3015/3557/16167 -f 3015/3557/16168 2759/3298/16169 2760/3297/16170 -f 3016/3560/16171 2759/3298/16172 3015/3557/16173 -f 3015/3557/16174 3017/3559/16175 3016/3560/16176 -f 3019/3563/16177 3018/3564/16178 3021/3561/16179 -f 3021/3561/16180 3020/3562/16181 3019/3563/16182 -f 3022/3566/16183 3020/3562/16184 3021/3561/16185 -f 3021/3561/16186 3023/3565/16187 3022/3566/16188 -f 3019/3563/16189 3024/3568/16190 3025/3567/16191 -f 3025/3567/16192 3018/3564/16193 3019/3563/16194 -f 3024/3568/16195 3019/3563/16196 3027/3569/16197 -f 3027/3569/16198 3026/3570/16199 3024/3568/16200 -f 3024/3568/16201 3026/3570/16202 2832/3371/16203 -f 2832/3371/16204 2779/3318/16205 3024/3568/16206 -f 2833/3370/16207 2832/3371/16208 3026/3570/16209 -f 3026/3570/16210 3028/3571/16211 2833/3370/16212 -f 3028/3571/16213 3026/3570/16214 3027/3569/16215 -f 3027/3569/16216 3029/3572/16217 3028/3571/16218 -f 3030/3573/16219 2878/3416/16220 3028/3571/16221 -f 3028/3571/16222 3029/3572/16223 3030/3573/16224 -f 2859/3396/16225 2833/3370/16226 3028/3571/16227 -f 3028/3571/16228 2878/3416/16229 2859/3396/16230 -f 3032/3574/16231 3031/3575/16232 3030/3573/16233 -f 3030/3573/16234 3029/3572/16235 3032/3574/16236 -f 2931/3468/16237 2932/3470/16238 3030/3573/16239 -f 3030/3573/16240 3031/3575/16241 2931/3468/16242 -f 2874/3412/16243 2878/3416/16244 3030/3573/16245 -f 3030/3573/16246 2932/3470/16247 2874/3412/16248 -f 3034/3576/16249 3033/3577/16250 3031/3575/16251 -f 3031/3575/16252 3032/3574/16253 3034/3576/16254 -f 3035/3578/16255 2931/3468/16256 3031/3575/16257 -f 3031/3575/16258 3033/3577/16259 3035/3578/16260 -f 3037/3579/16261 3036/3580/16262 3035/3578/16263 -f 3035/3578/16264 3033/3577/16265 3037/3579/16266 -f 2963/3507/16267 2964/3506/16268 3035/3578/16269 -f 3035/3578/16270 3036/3580/16271 2963/3507/16272 -f 2930/3469/16273 2931/3468/16274 3035/3578/16275 -f 3035/3578/16276 2964/3506/16277 2930/3469/16278 -f 3039/3581/16279 3038/3582/16280 3036/3580/16281 -f 3036/3580/16282 3037/3579/16283 3039/3581/16284 -f 3040/3583/16285 2963/3507/16286 3036/3580/16287 -f 3036/3580/16288 3038/3582/16289 3040/3583/16290 -f 2920/3584/16291 3041/3585/16292 3040/3583/16293 -f 3040/3583/16294 3038/3582/16295 2920/3584/16296 -f 2944/3486/16297 2945/3485/16298 3040/3583/16299 -f 3040/3583/16300 3041/3585/16301 2944/3486/16302 -f 2962/3508/16303 2963/3507/16304 3040/3583/16305 -f 3040/3583/16306 2945/3485/16307 2962/3508/16308 -f 2917/3456/16309 2925/3463/16310 3041/3586/16311 -f 3041/3586/16312 2920/3457/16313 2917/3456/16314 -f 2939/3478/16315 2944/3484/16316 3041/3586/16317 -f 3041/3586/16318 2925/3463/16319 2939/3478/16320 -f 2919/3587/16321 2920/3584/16322 3038/3582/16323 -f 3038/3582/16324 3039/3581/16325 2919/3587/16326 -f 3043/3588/16327 3042/3589/16328 3039/3581/16329 -f 3039/3581/16330 3037/3579/16331 3043/3588/16332 -f 2922/3590/16333 2919/3587/16334 3039/3581/16335 -f 3039/3581/16336 3042/3589/16337 2922/3590/16338 -f 3042/3589/16339 3043/3588/16340 3045/3591/16341 -f 3045/3591/16342 3044/3592/16343 3042/3589/16344 -f 3042/3589/16345 3044/3592/16346 3046/3593/16347 -f 3046/3593/16348 2922/3590/16349 3042/3589/16350 -f 3046/3594/16351 3047/3595/16352 2921/3459/16353 -f 2921/3459/16354 2922/3460/16355 3046/3594/16356 -f 3047/3595/16357 2864/3401/16358 2863/3402/16359 -f 2863/3402/16360 2921/3459/16361 3047/3595/16362 -f 3047/3595/16363 3046/3594/16364 3049/3596/16365 -f 3049/3596/16366 3048/3597/16367 3047/3595/16368 -f 3047/3595/16369 3048/3597/16370 2865/3403/16371 -f 2865/3403/16372 2864/3401/16373 3047/3595/16374 -f 3051/3598/16375 3050/3599/16376 2831/3367/16377 -f 2831/3367/16378 2865/3403/16379 3051/3598/16380 -f 3052/3600/16381 2830/3368/16382 2831/3367/16383 -f 2831/3367/16384 3050/3599/16385 3052/3600/16386 -f 3053/3602/16387 2830/3368/16388 3052/3600/16389 -f 3052/3600/16390 3054/3601/16391 3053/3602/16392 -f 3056/3605/16393 3055/3606/16394 3058/3603/16395 -f 3058/3603/16396 3057/3604/16397 3056/3605/16398 -f 3060/3607/16399 3059/3608/16400 3058/3603/16401 -f 3058/3603/16402 3055/3606/16403 3060/3607/16404 -f 3061/3610/16405 3059/3608/16406 3060/3607/16407 -f 3060/3607/16408 3062/3609/16409 3061/3610/16410 -f 3060/3607/16411 3055/3606/16412 3064/3611/16413 -f 3064/3611/16414 3063/3612/16415 3060/3607/16416 -f 3055/3606/16417 3056/3605/16418 3065/3613/16419 -f 3065/3613/16420 3064/3611/16421 3055/3606/16422 -f 3056/3605/16423 2780/3317/16424 2771/3306/16425 -f 3063/3612/16426 3066/3614/16427 3062/3609/16428 -f 3062/3609/16429 3060/3607/16430 3063/3612/16431 -f 3067/3617/16432 3063/3612/16433 3069/3615/16434 -f 3069/3615/16435 3068/3616/16436 3067/3617/16437 -f 3070/3619/16438 3068/3616/16439 3069/3615/16440 -f 3069/3615/16441 3071/3618/16442 3070/3619/16443 -f 3073/3620/16444 3072/3621/16445 3067/3617/16446 -f 3067/3617/16447 2741/3280/16448 3073/3620/16449 -f 3066/3614/16450 3063/3612/16451 3067/3617/16452 -f 3067/3617/16453 3072/3621/16454 3066/3614/16455 -f 2740/3281/16456 2741/3280/16457 3067/3617/16458 -f 3067/3617/16459 3068/3616/16460 2740/3281/16461 -f 3075/3624/16462 3074/3625/16463 3072/3622/16464 -f 3072/3622/16465 3073/3623/16466 3075/3624/16467 -f 3076/3626/16468 3066/3627/16469 3072/3622/16470 -f 3072/3622/16471 3074/3625/16472 3076/3626/16473 -f 2751/3292/16474 2752/3291/16475 3076/3626/16476 -f 3076/3626/16477 3074/3625/16478 2751/3292/16479 -f 3076/3626/16480 2752/3291/16481 2759/3298/16482 -f 2759/3298/16483 3016/3560/16484 3076/3626/16485 -f 3076/3626/16486 3016/3560/16487 3062/3628/16488 -f 3062/3628/16489 3066/3627/16490 3076/3626/16491 -f 3078/3629/16492 3077/3630/16493 2760/3297/16494 -f 2760/3297/16495 2757/3296/16496 3078/3629/16497 -f 3077/3630/16498 3078/3629/16499 3079/3631/16500 -f 3079/3631/16501 3053/3602/16502 3077/3630/16503 -f 3054/3601/16504 3080/3632/16505 3077/3630/16506 -f 3077/3630/16507 3053/3602/16508 3054/3601/16509 -f 3014/3558/16510 2760/3297/16511 3077/3630/16512 -f 3077/3630/16513 3080/3632/16514 3014/3558/16515 -f 3079/3631/16516 2828/3363/16517 2830/3368/16518 -f 2830/3368/16519 3053/3602/16520 3079/3631/16521 -f 2778/3316/16522 3081/3633/16523 3079/3631/16524 -f 3079/3631/16525 3078/3629/16526 2778/3316/16527 -f 2827/3364/16528 2828/3363/16529 3079/3631/16530 -f 3079/3631/16531 3081/3633/16532 2827/3364/16533 -f 2765/3303/16534 2810/3350/16535 3081/3633/16536 -f 3081/3633/16537 2778/3316/16538 2765/3303/16539 -f 2811/3349/16540 2827/3364/16541 3081/3633/16542 -f 3081/3633/16543 2810/3350/16544 2811/3349/16545 -f 2758/3295/16546 2778/3316/16547 3078/3629/16548 -f 3078/3629/16549 2757/3296/16550 2758/3295/16551 -f 2756/3294/16552 2751/3292/16553 3074/3625/16554 -f 3074/3625/16555 3075/3624/16556 2756/3294/16557 -f 3082/3635/16558 2756/3294/16559 3075/3624/16560 -f 3075/3624/16561 3083/3634/16562 3082/3635/16563 -f 3084/3636/16564 3083/3634/16565 3075/3624/16566 -f 3075/3624/16567 3073/3623/16568 3084/3636/16569 -f 3084/3636/16570 3085/3637/16571 3083/3634/16572 -f 3084/3638/16573 3073/3620/16574 2741/3280/16575 -f 3082/3635/16576 3083/3634/16577 3085/3637/16578 -f 3085/3637/16579 2744/3285/16580 3082/3635/16581 -f 3086/3639/16582 2750/3288/16583 3085/3637/16584 -f 3085/3637/16585 3084/3636/16586 3086/3639/16587 -f 3087/3641/16588 2750/3288/16589 3086/3639/16590 -f 3086/3639/16591 3088/3640/16592 3087/3641/16593 -f 2742/3279/16594 3089/3643/16595 3086/3642/16596 -f 3086/3642/16597 3084/3638/16598 2742/3279/16599 -f 3090/3644/16600 3088/3645/16601 3086/3642/16602 -f 3086/3642/16603 3089/3643/16604 3090/3644/16605 -f 3090/3644/16606 3091/3646/16607 3088/3645/16608 -f 3093/3647/16609 3092/3648/16610 3090/3644/16611 -f 3090/3644/16612 3089/3643/16613 3093/3647/16614 -f 3094/3649/16615 3091/3646/16616 3090/3644/16617 -f 3090/3644/16618 3092/3648/16619 3094/3649/16620 -f 3096/3650/16621 3095/3651/16622 3094/3649/16623 -f 3094/3649/16624 3092/3648/16625 3096/3650/16626 -f 3097/3652/16627 2728/3266/16628 3094/3649/16629 -f 3094/3649/16630 3095/3651/16631 3097/3652/16632 -f 2723/3260/16633 2728/3266/16634 3097/3652/16635 -f 3097/3652/16636 2724/3261/16637 2723/3260/16638 -f 3099/3653/16639 3098/3654/16640 3097/3652/16641 -f 3097/3652/16642 3095/3651/16643 3099/3653/16644 -f 2722/3258/16645 2724/3261/16646 3097/3652/16647 -f 3097/3652/16648 3098/3654/16649 2722/3258/16650 -f 3101/3655/16651 3100/3656/16652 3098/3654/16653 -f 3098/3654/16654 3099/3653/16655 3101/3655/16656 -f 2716/3252/16657 2722/3258/16658 3098/3654/16659 -f 3098/3654/16660 3100/3656/16661 2716/3252/16662 -f 2725/3264/16663 2726/3263/16664 3100/3656/16665 -f 3100/3656/16666 3101/3655/16667 2725/3264/16668 -f 2715/3253/16669 2716/3252/16670 3100/3656/16671 -f 3100/3656/16672 2726/3263/16673 2715/3253/16674 -f 3103/3657/16675 3102/3658/16676 3101/3655/16677 -f 3101/3655/16678 3099/3653/16679 3103/3657/16680 -f 3104/3659/16681 2725/3264/16682 3101/3655/16683 -f 3101/3655/16684 3102/3658/16685 3104/3659/16686 -f 3106/3660/16687 3105/3661/16688 3104/3659/16689 -f 3104/3659/16690 3102/3658/16691 3106/3660/16692 -f 3104/3659/16693 2727/3262/16694 2725/3264/16695 -f 3107/3664/16696 2739/3277/16697 3109/3662/16698 -f 3109/3662/16699 3108/3663/16700 3107/3664/16701 -f 3109/3662/16702 3110/3666/16703 3111/3665/16704 -f 3111/3665/16705 3108/3663/16706 3109/3662/16707 -f 3109/3662/16708 3112/3668/16709 3113/3667/16710 -f 3113/3667/16711 3110/3666/16712 3109/3662/16713 -f 2734/3275/16714 3114/3669/16715 3112/3668/16716 -f 3112/3668/16717 2739/3277/16718 2734/3275/16719 -f 3114/3669/16720 3115/3670/16721 3113/3667/16722 -f 3113/3667/16723 3112/3668/16724 3114/3669/16725 -f 2749/3286/16726 3116/3671/16727 3114/3669/16728 -f 3114/3669/16729 2734/3275/16730 2749/3286/16731 -f 3116/3671/16732 3117/3672/16733 3115/3670/16734 -f 3115/3670/16735 3114/3669/16736 3116/3671/16737 -f 3118/3674/16738 3115/3670/16739 3117/3672/16740 -f 3117/3672/16741 2729/3673/16742 3118/3674/16743 -f 3116/3671/16744 3087/3641/16745 3091/3675/16746 -f 3091/3675/16747 3117/3672/16748 3116/3671/16749 -f 3116/3671/16750 2749/3286/16751 2750/3288/16752 -f 2750/3288/16753 3087/3641/16754 3116/3671/16755 -f 2733/3268/16756 2739/3277/16757 3107/3664/16758 -f 3107/3664/16759 2732/3269/16760 2733/3268/16761 -f 3106/3660/16762 3119/3677/16763 3120/3676/16764 -f 3120/3676/16765 3105/3661/16766 3106/3660/16767 -f 2730/3271/16768 2731/3270/16769 3120/3676/16770 -f 3120/3676/16771 3119/3677/16772 2730/3271/16773 -f 3122/3678/16774 3121/3679/16775 2730/3271/16776 -f 2730/3271/16777 3119/3677/16778 3122/3678/16779 -f 2738/3276/16780 2730/3271/16781 3121/3679/16782 -f 3121/3679/16783 3123/3680/16784 2738/3276/16785 -f 3124/3682/16786 2736/3273/16787 2738/3276/16788 -f 2738/3276/16789 3125/3681/16790 3124/3682/16791 -f 3126/3683/16792 3125/3681/16793 2738/3276/16794 -f 2738/3276/16795 3123/3680/16796 3126/3683/16797 -f 3127/3684/16798 3125/3681/16799 3126/3683/16800 -f 3126/3683/16801 2786/3323/16802 3127/3684/16803 -f 3129/3685/16804 3128/3686/16805 3126/3683/16806 -f 3126/3683/16807 3123/3680/16808 3129/3685/16809 -f 2785/3324/16810 2786/3323/16811 3126/3683/16812 -f 3126/3683/16813 3128/3686/16814 2785/3324/16815 -f 3129/3685/16816 3130/3688/16817 3131/3687/16818 -f 3131/3687/16819 3128/3686/16820 3129/3685/16821 -f 2799/3337/16822 2785/3324/16823 3128/3686/16824 -f 3128/3686/16825 3131/3687/16826 2799/3337/16827 -f 3132/3689/16828 2776/3315/16829 3131/3687/16830 -f 3131/3687/16831 3130/3688/16832 3132/3689/16833 -f 2776/3315/16834 2777/3314/16835 2799/3337/16836 -f 2799/3337/16837 3131/3687/16838 2776/3315/16839 -f 3121/3679/16840 3133/3690/16841 3129/3685/16842 -f 3129/3685/16843 3123/3680/16844 3121/3679/16845 -f 3133/3690/16846 3134/3691/16847 3130/3688/16848 -f 3130/3688/16849 3129/3685/16850 3133/3690/16851 -f 3122/3678/16852 3135/3692/16853 3133/3690/16854 -f 3133/3690/16855 3121/3679/16856 3122/3678/16857 -f 3135/3692/16858 3136/3693/16859 3134/3691/16860 -f 3134/3691/16861 3133/3690/16862 3135/3692/16863 -f 3137/3694/16864 3093/3647/16865 3136/3693/16866 -f 3136/3693/16867 3135/3692/16868 3137/3694/16869 -f 3138/3695/16870 3137/3694/16871 3135/3692/16872 -f 3135/3692/16873 3122/3678/16874 3138/3695/16875 -f 3096/3650/16876 3137/3694/16877 3138/3695/16878 -f 3138/3695/16879 3103/3657/16880 3096/3650/16881 -f 3119/3677/16882 3106/3660/16883 3138/3695/16884 -f 3138/3695/16885 3122/3678/16886 3119/3677/16887 -f 3102/3658/16888 3103/3657/16889 3138/3695/16890 -f 3138/3695/16891 3106/3660/16892 3102/3658/16893 -f 3092/3648/16894 3093/3647/16895 3137/3694/16896 -f 3137/3694/16897 3096/3650/16898 3092/3648/16899 -f 3140/3697/16900 3139/3698/16901 3127/3684/16902 -f 3127/3684/16903 3141/3696/16904 3140/3697/16905 -f 3124/3682/16906 3125/3681/16907 3127/3684/16908 -f 3127/3684/16909 3139/3698/16910 3124/3682/16911 -f 2787/3328/16912 2788/3327/16913 3139/3698/16914 -f 3139/3698/16915 3140/3697/16916 2787/3328/16917 -f 3142/3699/16918 3124/3682/16919 3139/3698/16920 -f 3139/3698/16921 2788/3327/16922 3142/3699/16923 -f 2789/3326/16924 2792/3332/16925 3142/3699/16926 -f 3142/3699/16927 2788/3327/16928 2789/3326/16929 -f 3144/3700/16930 3143/3701/16931 3142/3699/16932 -f 3142/3699/16933 2792/3332/16934 3144/3700/16935 -f 2736/3273/16936 3124/3682/16937 3142/3699/16938 -f 3142/3699/16939 3143/3701/16940 2736/3273/16941 -f 2748/3287/16942 2735/3274/16943 3143/3701/16944 -f 3143/3701/16945 3144/3700/16946 2748/3287/16947 -f 3143/3701/16948 2735/3274/16949 2736/3273/16950 -f 2793/3331/16951 3145/3702/16952 3144/3700/16953 -f 3144/3700/16954 2792/3332/16955 2793/3331/16956 -f 2746/3283/16957 2748/3287/16958 3144/3700/16959 -f 3144/3700/16960 3145/3702/16961 2746/3283/16962 -f 2764/3304/16963 2763/3299/16964 3145/3702/16965 -f 3145/3702/16966 2793/3331/16967 2764/3304/16968 -f 2745/3284/16969 2746/3283/16970 3145/3702/16971 -f 3145/3702/16972 2763/3299/16973 2745/3284/16974 -f 2787/3328/16975 3146/3704/16976 3147/3703/16977 -f 3147/3703/16978 2790/3325/16979 2787/3328/16980 -f 3148/3705/16981 3146/3704/16982 2787/3328/16983 -f 2787/3328/16984 3140/3697/16985 3148/3705/16986 -f 2898/3439/16987 3146/3704/16988 3148/3705/16989 -f 3148/3705/16990 2901/3436/16991 2898/3439/16992 -f 3141/3696/16993 3149/3706/16994 3148/3705/16995 -f 3148/3705/16996 3140/3697/16997 3141/3696/16998 -f 2904/3440/16999 2901/3436/17000 3148/3705/17001 -f 3148/3705/17002 3149/3706/17003 2904/3440/17004 -f 3151/3707/17005 3150/3708/17006 3149/3706/17007 -f 3149/3706/17008 3141/3696/17009 3151/3707/17010 -f 3152/3709/17011 2904/3440/17012 3149/3706/17013 -f 3149/3706/17014 3150/3708/17015 3152/3709/17016 -f 2903/3441/17017 2904/3440/17018 3152/3709/17019 -f 3152/3709/17020 2951/3493/17021 2903/3441/17022 -f 2911/3448/17023 2912/3450/17024 3152/3709/17025 -f 3152/3709/17026 3150/3708/17027 2911/3448/17028 -f 2950/3494/17029 2951/3493/17030 3152/3709/17031 -f 3152/3709/17032 2912/3450/17033 2950/3494/17034 -f 2781/3322/17035 2911/3448/17036 3150/3708/17037 -f 3150/3708/17038 3151/3707/17039 2781/3322/17040 -f 2898/3439/17041 3153/3710/17042 3147/3703/17043 -f 3147/3703/17044 3146/3704/17045 2898/3439/17046 -f 3155/3711/17047 3154/3712/17048 3147/3703/17049 -f 3147/3703/17050 3153/3710/17051 3155/3711/17052 -f 3156/3713/17053 2790/3325/17054 3147/3703/17055 -f 3147/3703/17056 3154/3712/17057 3156/3713/17058 -f 2791/3329/17059 2790/3325/17060 3156/3713/17061 -f 3156/3713/17062 3157/3714/17063 2791/3329/17064 -f 2795/3333/17065 2791/3329/17066 3157/3714/17067 -f 3157/3714/17068 2817/3353/17069 2795/3333/17070 -f 3159/3717/17071 3158/3718/17072 3161/3715/17073 -f 3161/3715/17074 3160/3716/17075 3159/3717/17076 -f 2815/3355/17077 2816/3354/17078 3161/3715/17079 -f 3161/3715/17080 3158/3718/17081 2815/3355/17082 -f 3163/3719/17083 3162/3720/17084 3158/3718/17085 -f 3158/3718/17086 3159/3717/17087 3163/3719/17088 -f 2818/3356/17089 2815/3355/17090 3158/3718/17091 -f 3158/3718/17092 3162/3720/17093 2818/3356/17094 -f 3162/3720/17095 3163/3719/17096 2851/3390/17097 -f 2851/3390/17098 2837/3377/17099 3162/3720/17100 -f 3162/3720/17101 2837/3377/17102 2838/3376/17103 -f 2838/3376/17104 2818/3356/17105 3162/3720/17106 -f 2838/3376/17107 2820/3359/17108 2814/3351/17109 -f 2814/3351/17110 2818/3356/17111 2838/3376/17112 -f 2821/3358/17113 2813/3352/17114 2814/3351/17115 -f 2814/3351/17116 2820/3359/17117 2821/3358/17118 -f 2766/3302/17119 2764/3304/17120 2813/3352/17121 -f 2813/3352/17122 2821/3358/17123 2766/3302/17124 -f 3165/3721/17125 3164/3722/17126 3159/3717/17127 -f 3159/3717/17128 3160/3716/17129 3165/3721/17130 -f 2850/3391/17131 3163/3719/17132 3159/3717/17133 -f 3159/3717/17134 3164/3722/17135 2850/3391/17136 -f 3166/3723/17137 3164/3722/17138 3165/3721/17139 -f 2879/3418/17140 2850/3391/17141 3164/3722/17142 -f 3164/3722/17143 3166/3723/17144 2879/3418/17145 -f 3168/3724/17146 3167/3725/17147 2879/3418/17148 -f 2879/3418/17149 3166/3723/17150 3168/3724/17151 -f 2879/3418/17152 3167/3725/17153 2899/3438/17154 -f 2899/3438/17155 2880/3417/17156 2879/3418/17157 -f 3153/3710/17158 2898/3439/17159 2899/3438/17160 -f 2899/3438/17161 3167/3725/17162 3153/3710/17163 -f 3155/3711/17164 3153/3710/17165 3167/3725/17166 -f 3167/3725/17167 3168/3724/17168 3155/3711/17169 -f 3095/3651/17170 3096/3650/17171 3103/3657/17172 -f 3103/3657/17173 3099/3653/17174 3095/3651/17175 -f 2742/3279/17176 3136/3693/17177 3093/3647/17178 -f 3093/3647/17179 3089/3643/17180 2742/3279/17181 -f 3087/3641/17182 3088/3640/17183 3091/3675/17184 -f 2745/3284/17185 2761/3301/17186 3082/3635/17187 -f 3082/3635/17188 2744/3285/17189 2745/3284/17190 -f 2754/3289/17191 2756/3294/17192 3082/3635/17193 -f 3082/3635/17194 2761/3301/17195 2754/3289/17196 -f 3016/3560/17197 3017/3559/17198 3061/3726/17199 -f 3061/3726/17200 3062/3628/17201 3016/3560/17202 -f 3169/3727/17203 2780/3317/17204 3056/3605/17205 -f 3056/3605/17206 3057/3604/17207 3169/3727/17208 -f 3048/3597/17209 3170/3728/17210 3051/3598/17211 -f 3051/3598/17212 2865/3403/17213 3048/3597/17214 -f 3171/3729/17215 3170/3728/17216 3048/3597/17217 -f 3048/3597/17218 3049/3596/17219 3171/3729/17220 -f 3172/3732/17221 3171/3733/17222 3049/3730/17223 -f 3049/3730/17224 3173/3731/17225 3172/3732/17226 -f 3049/3730/17227 3046/3593/17228 3044/3592/17229 -f 3044/3592/17230 3173/3731/17231 3049/3730/17232 -f 3044/3592/17233 3045/3591/17234 3174/3734/17235 -f 3174/3734/17236 3173/3731/17237 3044/3592/17238 -f 3045/3591/17239 3175/3735/17240 3022/3566/17241 -f 3022/3566/17242 3174/3734/17243 3045/3591/17244 -f 3175/3735/17245 3176/3736/17246 3020/3562/17247 -f 3020/3562/17248 3022/3566/17249 3175/3735/17250 -f 3175/3735/17251 3045/3591/17252 3043/3588/17253 -f 3043/3588/17254 3034/3576/17255 3175/3735/17256 -f 3175/3735/17257 3034/3576/17258 3032/3574/17259 -f 3032/3574/17260 3176/3736/17261 3175/3735/17262 -f 3032/3574/17263 3029/3572/17264 3027/3569/17265 -f 3027/3569/17266 3176/3736/17267 3032/3574/17268 -f 3027/3569/17269 3019/3563/17270 3020/3562/17271 -f 3020/3562/17272 3176/3736/17273 3027/3569/17274 -f 3023/3565/17275 3177/3737/17276 3174/3734/17277 -f 3174/3734/17278 3022/3566/17279 3023/3565/17280 -f 3172/3732/17281 3173/3731/17282 3174/3734/17283 -f 3174/3734/17284 3177/3737/17285 3172/3732/17286 -f 3033/3577/17287 3034/3576/17288 3043/3588/17289 -f 3043/3588/17290 3037/3579/17291 3033/3577/17292 -f 3004/3550/17293 3179/3738/17294 3178/3739/17295 -f 3182/3740/17296 3181/3741/17297 3180/3742/17298 -f 3179/3738/17299 3183/3743/17300 3180/3742/17301 -f 3180/3742/17302 3178/3739/17303 3179/3738/17304 -f 3180/3742/17305 3183/3743/17306 3182/3740/17307 -f 3185/3744/17308 3184/3745/17309 3181/3741/17310 -f 3181/3741/17311 3182/3740/17312 3185/3744/17313 -f 3181/3741/17314 3184/3745/17315 3186/3746/17316 -f 3187/3747/17317 3003/3546/17318 3186/3746/17319 -f 3186/3746/17320 3184/3745/17321 3187/3747/17322 -f 3001/3543/17323 3011/3553/17324 3186/3746/17325 -f 3186/3746/17326 3003/3546/17327 3001/3543/17328 -f 3189/3749/17329 3188/3750/17330 3187/3747/17331 -f 3187/3747/17332 3190/3748/17333 3189/3749/17334 -f 3000/3544/17335 3003/3546/17336 3187/3747/17337 -f 3187/3747/17338 3188/3750/17339 3000/3544/17340 -f 3191/3751/17341 3190/3748/17342 3187/3747/17343 -f 3187/3747/17344 3184/3745/17345 3191/3751/17346 -f 3193/3752/17347 3192/3753/17348 3188/3750/17349 -f 3188/3750/17350 3189/3749/17351 3193/3752/17352 -f 2999/3545/17353 3000/3544/17354 3188/3750/17355 -f 3188/3750/17356 3192/3753/17357 2999/3545/17358 -f 3195/3754/17359 3194/3755/17360 3192/3753/17361 -f 3192/3753/17362 3193/3752/17363 3195/3754/17364 -f 3196/3756/17365 2999/3545/17366 3192/3753/17367 -f 3192/3753/17368 3194/3755/17369 3196/3756/17370 -f 3196/3756/17371 3194/3755/17372 3198/3757/17373 -f 3198/3757/17374 3197/3758/17375 3196/3756/17376 -f 3196/3756/17377 3197/3758/17378 3200/3759/17379 -f 3200/3759/17380 3199/3760/17381 3196/3756/17382 -f 3196/3756/17383 3199/3760/17384 3002/3542/17385 -f 3002/3542/17386 2999/3545/17387 3196/3756/17388 -f 3199/3760/17389 3200/3759/17390 3202/3761/17391 -f 3202/3761/17392 3201/3762/17393 3199/3760/17394 -f 3010/3554/17395 3002/3542/17396 3199/3760/17397 -f 3199/3760/17398 3201/3762/17399 3010/3554/17400 -f 3201/3762/17401 3202/3761/17402 3204/3763/17403 -f 3204/3763/17404 3203/3764/17405 3201/3762/17406 -f 3009/3551/17407 3010/3554/17408 3201/3762/17409 -f 3201/3762/17410 3203/3764/17411 3009/3551/17412 -f 3203/3764/17413 3204/3763/17414 3206/3765/17415 -f 3206/3765/17416 3205/3766/17417 3203/3764/17418 -f 3008/3552/17419 3009/3551/17420 3203/3764/17421 -f 3203/3764/17422 3205/3766/17423 3008/3552/17424 -f 3205/3766/17425 3206/3765/17426 3208/3767/17427 -f 3208/3767/17428 3207/3768/17429 3205/3766/17430 -f 3209/3769/17431 3008/3552/17432 3205/3766/17433 -f 3205/3766/17434 3207/3768/17435 3209/3769/17436 -f 3211/3770/17437 3210/3771/17438 3209/3769/17439 -f 3209/3769/17440 3207/3768/17441 3211/3770/17442 -f 3213/3772/17443 3212/3773/17444 3209/3769/17445 -f 3209/3769/17446 3210/3771/17447 3213/3772/17448 -f 3006/3548/17449 3008/3552/17450 3209/3769/17451 -f 3209/3769/17452 3212/3773/17453 3006/3548/17454 -f 3214/3774/17455 3012/3556/17456 3212/3773/17457 -f 3212/3773/17458 3213/3772/17459 3214/3774/17460 -f 3005/3549/17461 3006/3548/17462 3212/3773/17463 -f 3212/3773/17464 3012/3556/17465 3005/3549/17466 -f 3216/3775/17467 3215/3776/17468 3213/3772/17469 -f 3213/3772/17470 3210/3771/17471 3216/3775/17472 -f 3213/3772/17473 3215/3776/17474 3214/3774/17475 -f 3218/3777/17476 3217/3778/17477 3214/3774/17478 -f 3214/3774/17479 3215/3776/17480 3218/3777/17481 -f 3216/3775/17482 3219/3779/17483 3218/3777/17484 -f 3218/3777/17485 3215/3776/17486 3216/3775/17487 -f 3220/3780/17488 2996/3539/17489 3218/3777/17490 -f 3218/3777/17491 3219/3779/17492 3220/3780/17493 -f 2994/3538/17494 3217/3778/17495 3218/3777/17496 -f 3218/3777/17497 2996/3539/17498 2994/3538/17499 -f 3222/3781/17500 3221/3782/17501 3220/3780/17502 -f 3220/3780/17503 3219/3779/17504 3222/3781/17505 -f 3224/3783/17506 3223/3784/17507 3220/3780/17508 -f 3220/3780/17509 3221/3782/17510 3224/3783/17511 -f 2992/3534/17512 2996/3539/17513 3220/3780/17514 -f 3220/3780/17515 3223/3784/17516 2992/3534/17517 -f 3226/3785/17518 3225/3786/17519 3223/3784/17520 -f 3223/3784/17521 3224/3783/17522 3226/3785/17523 -f 2991/3535/17524 2992/3534/17525 3223/3784/17526 -f 3223/3784/17527 3225/3786/17528 2991/3535/17529 -f 3228/3787/17530 3227/3788/17531 3225/3786/17532 -f 3225/3786/17533 3226/3785/17534 3228/3787/17535 -f 3229/3789/17536 2991/3535/17537 3225/3786/17538 -f 3225/3786/17539 3227/3788/17540 3229/3789/17541 -f 3193/3790/17542 3189/3791/17543 3229/3789/17544 -f 3229/3789/17545 3227/3788/17546 3193/3790/17547 -f 3190/3792/17548 3230/3793/17549 3229/3789/17550 -f 3229/3789/17551 3189/3791/17552 3190/3792/17553 -f 2990/3536/17554 2991/3535/17555 3229/3789/17556 -f 3229/3789/17557 3230/3793/17558 2990/3536/17559 -f 3191/3794/17560 2998/3540/17561 3230/3793/17562 -f 3230/3793/17563 3190/3792/17564 3191/3794/17565 -f 2995/3537/17566 2990/3536/17567 3230/3793/17568 -f 3230/3793/17569 2998/3540/17570 2995/3537/17571 -f 3195/3795/17572 3193/3790/17573 3227/3788/17574 -f 3227/3788/17575 3228/3787/17576 3195/3795/17577 -f 3228/3787/17578 3226/3785/17579 3232/3796/17580 -f 3232/3796/17581 3231/3797/17582 3228/3787/17583 -f 3228/3787/17584 3231/3797/17585 3233/3798/17586 -f 3233/3798/17587 3195/3795/17588 3228/3787/17589 -f 3233/3799/17590 3198/3757/17591 3194/3755/17592 -f 3194/3755/17593 3195/3754/17594 3233/3799/17595 -f 3235/3800/17596 3234/3801/17597 3198/3757/17598 -f 3198/3757/17599 3233/3799/17600 3235/3800/17601 -f 3236/3802/17602 3197/3758/17603 3198/3757/17604 -f 3198/3757/17605 3234/3801/17606 3236/3802/17607 -f 3236/3802/17608 3237/3803/17609 3200/3759/17610 -f 3200/3759/17611 3197/3758/17612 3236/3802/17613 -f 3238/3804/17614 3202/3761/17615 3200/3759/17616 -f 3200/3759/17617 3237/3803/17618 3238/3804/17619 -f 3239/3805/17620 3204/3763/17621 3202/3761/17622 -f 3202/3761/17623 3238/3804/17624 3239/3805/17625 -f 3240/3806/17626 3206/3765/17627 3204/3763/17628 -f 3204/3763/17629 3239/3805/17630 3240/3806/17631 -f 3241/3807/17632 3208/3767/17633 3206/3765/17634 -f 3206/3765/17635 3240/3806/17636 3241/3807/17637 -f 3243/3808/17638 3242/3809/17639 3208/3767/17640 -f 3208/3767/17641 3241/3807/17642 3243/3808/17643 -f 3208/3767/17644 3242/3809/17645 3211/3770/17646 -f 3211/3770/17647 3207/3768/17648 3208/3767/17649 -f 3245/3810/17650 3244/3811/17651 3211/3770/17652 -f 3211/3770/17653 3242/3809/17654 3245/3810/17655 -f 3244/3811/17656 3245/3810/17657 3246/3812/17658 -f 3246/3812/17659 3222/3781/17660 3244/3811/17661 -f 3219/3779/17662 3216/3775/17663 3244/3811/17664 -f 3244/3811/17665 3222/3781/17666 3219/3779/17667 -f 3210/3771/17668 3211/3770/17669 3244/3811/17670 -f 3244/3811/17671 3216/3775/17672 3210/3771/17673 -f 3246/3812/17674 3247/3813/17675 3221/3782/17676 -f 3221/3782/17677 3222/3781/17678 3246/3812/17679 -f 3248/3814/17680 3224/3783/17681 3221/3782/17682 -f 3221/3782/17683 3247/3813/17684 3248/3814/17685 -f 3232/3796/17686 3226/3785/17687 3224/3783/17688 -f 3224/3783/17689 3248/3814/17690 3232/3796/17691 -f 3250/3815/17692 3249/3816/17693 3232/3796/17694 -f 3232/3796/17695 3248/3814/17696 3250/3815/17697 -f 3251/3817/17698 3231/3797/17699 3232/3796/17700 -f 3232/3796/17701 3249/3816/17702 3251/3817/17703 -f 3252/3820/17704 2969/3513/17705 3251/3818/17706 -f 3251/3818/17707 3249/3819/17708 3252/3820/17709 -f 2970/3512/17710 3235/3821/17711 3251/3818/17712 -f 3251/3818/17713 2969/3513/17714 2970/3512/17715 -f 3233/3798/17716 3231/3797/17717 3251/3817/17718 -f 3251/3817/17719 3235/3822/17720 3233/3798/17721 -f 3253/3824/17722 2966/3509/17723 3252/3820/17724 -f 3252/3820/17725 3254/3823/17726 3253/3824/17727 -f 2965/3505/17728 2969/3513/17729 3252/3820/17730 -f 3252/3820/17731 2966/3509/17732 2965/3505/17733 -f 3250/3825/17734 3254/3823/17735 3252/3820/17736 -f 3252/3820/17737 3249/3819/17738 3250/3825/17739 -f 2927/3466/17740 2928/3465/17741 3253/3824/17742 -f 3253/3824/17743 3255/3826/17744 2927/3466/17745 -f 2930/3469/17746 2966/3509/17747 3253/3824/17748 -f 3253/3824/17749 2928/3465/17750 2930/3469/17751 -f 3256/3827/17752 3255/3826/17753 3253/3824/17754 -f 3253/3824/17755 3254/3823/17756 3256/3827/17757 -f 3257/3829/17758 3255/3826/17759 3256/3827/17760 -f 3256/3827/17761 3258/3828/17762 3257/3829/17763 -f 3250/3825/17764 3259/3830/17765 3256/3827/17766 -f 3256/3827/17767 3254/3823/17768 3250/3825/17769 -f 3260/3831/17770 3258/3828/17771 3256/3827/17772 -f 3256/3827/17773 3259/3830/17774 3260/3831/17775 -f 3261/3833/17776 3258/3828/17777 3260/3831/17778 -f 3260/3831/17779 3262/3832/17780 3261/3833/17781 -f 3247/3813/17782 3246/3812/17783 3260/3834/17784 -f 3260/3834/17785 3259/3835/17786 3247/3813/17787 -f 3245/3810/17788 3262/3836/17789 3260/3834/17790 -f 3260/3834/17791 3246/3812/17792 3245/3810/17793 -f 3264/3838/17794 3263/3839/17795 3261/3833/17796 -f 3261/3833/17797 3265/3837/17798 3264/3838/17799 -f 3257/3829/17800 3258/3828/17801 3261/3833/17802 -f 3261/3833/17803 3263/3839/17804 3257/3829/17805 -f 3243/3840/17806 3265/3837/17807 3261/3833/17808 -f 3261/3833/17809 3262/3832/17810 3243/3840/17811 -f 2907/3446/17812 3266/3841/17813 3263/3839/17814 -f 3263/3839/17815 3264/3838/17816 2907/3446/17817 -f 3267/3842/17818 3257/3829/17819 3263/3839/17820 -f 3263/3839/17821 3266/3841/17822 3267/3842/17823 -f 3269/3843/17824 3268/3844/17825 3267/3842/17826 -f 3267/3842/17827 3266/3841/17828 3269/3843/17829 -f 2926/3467/17830 2927/3466/17831 3267/3842/17832 -f 3267/3842/17833 3268/3844/17834 2926/3467/17835 -f 3255/3826/17836 3257/3829/17837 3267/3842/17838 -f 3267/3842/17839 2927/3466/17840 3255/3826/17841 -f 3271/3845/17842 3270/3846/17843 3268/3844/17844 -f 3268/3844/17845 3269/3843/17846 3271/3845/17847 -f 2897/3434/17848 2926/3467/17849 3268/3844/17850 -f 3268/3844/17851 3270/3846/17852 2897/3434/17853 -f 3273/3847/17854 3272/3848/17855 3270/3846/17856 -f 3270/3846/17857 3271/3845/17858 3273/3847/17859 -f 2896/3435/17860 2897/3434/17861 3270/3846/17862 -f 3270/3846/17863 3272/3848/17864 2896/3435/17865 -f 3275/3849/17866 3274/3850/17867 3272/3848/17868 -f 3272/3848/17869 3273/3847/17870 3275/3849/17871 -f 2846/3385/17872 2896/3435/17873 3272/3848/17874 -f 3272/3848/17875 3274/3850/17876 2846/3385/17877 -f 3277/3851/17878 3276/3852/17879 3274/3850/17880 -f 3274/3850/17881 3275/3849/17882 3277/3851/17883 -f 2845/3380/17884 2846/3385/17885 3274/3850/17886 -f 3274/3850/17887 3276/3852/17888 2845/3380/17889 -f 3279/3853/17890 3278/3854/17891 3276/3852/17892 -f 3276/3852/17893 3277/3851/17894 3279/3853/17895 -f 2849/3386/17896 2845/3380/17897 3276/3852/17898 -f 3276/3852/17899 3278/3854/17900 2849/3386/17901 -f 3277/3851/17902 3280/3856/17903 3281/3855/17904 -f 3281/3855/17905 3279/3853/17906 3277/3851/17907 -f 2803/3342/17908 2804/3341/17909 3281/3855/17910 -f 3281/3855/17911 3280/3856/17912 2803/3342/17913 -f 3275/3849/17914 3282/3857/17915 3280/3856/17916 -f 3280/3856/17917 3277/3851/17918 3275/3849/17919 -f 2782/3321/17920 2803/3342/17921 3280/3856/17922 -f 3280/3856/17923 3282/3857/17924 2782/3321/17925 -f 3273/3847/17926 3283/3858/17927 3282/3857/17928 -f 3282/3857/17929 3275/3849/17930 3273/3847/17931 -f 2781/3322/17932 2782/3321/17933 3282/3857/17934 -f 3282/3857/17935 3283/3858/17936 2781/3322/17937 -f 3271/3845/17938 2910/3449/17939 3283/3858/17940 -f 3283/3858/17941 3273/3847/17942 3271/3845/17943 -f 2910/3449/17944 2911/3448/17945 2781/3322/17946 -f 2781/3322/17947 3283/3858/17948 2910/3449/17949 -f 2908/3445/17950 2910/3449/17951 3271/3845/17952 -f 3271/3845/17953 3269/3843/17954 2908/3445/17955 -f 2907/3446/17956 2908/3445/17957 3269/3843/17958 -f 3269/3843/17959 3266/3841/17960 2907/3446/17961 -f 2906/3447/17962 2907/3446/17963 3264/3838/17964 -f 3264/3838/17965 3284/3859/17966 2906/3447/17967 -f 3285/3860/17968 3284/3859/17969 3264/3838/17970 -f 3264/3838/17971 3265/3837/17972 3285/3860/17973 -f 3243/3840/17974 3241/3861/17975 3285/3860/17976 -f 3285/3860/17977 3265/3837/17978 3243/3840/17979 -f 3240/3862/17980 3286/3863/17981 3285/3860/17982 -f 3285/3860/17983 3241/3861/17984 3240/3862/17985 -f 3288/3864/17986 3287/3865/17987 2949/3491/17988 -f 2949/3491/17989 2950/3494/17990 3288/3864/17991 -f 3288/3864/17992 2906/3447/17993 3284/3859/17994 -f 3289/3866/17995 3287/3865/17996 3288/3864/17997 -f 3288/3864/17998 3286/3863/17999 3289/3866/18000 -f 3290/3868/18001 3287/3865/18002 3289/3866/18003 -f 3289/3866/18004 3291/3867/18005 3290/3868/18006 -f 3240/3862/18007 3239/3869/18008 3289/3866/18009 -f 3289/3866/18010 3286/3863/18011 3240/3862/18012 -f 3238/3870/18013 3291/3867/18014 3289/3866/18015 -f 3289/3866/18016 3239/3869/18017 3238/3870/18018 -f 3290/3868/18019 2972/3873/18020 3292/3871/18021 -f 3292/3871/18022 2948/3872/18023 3290/3868/18024 -f 3290/3868/18025 2948/3872/18026 2949/3491/18027 -f 2949/3491/18028 3287/3865/18029 3290/3868/18030 -f 3293/3874/18031 2972/3873/18032 3290/3868/18033 -f 3290/3868/18034 3291/3867/18035 3293/3874/18036 -f 3292/3876/18037 2972/3515/18038 2973/3514/18039 -f 2973/3514/18040 3294/3875/18041 3292/3876/18042 -f 3296/3879/18043 3295/3880/18044 3292/3877/18045 -f 3292/3877/18046 3294/3878/18047 3296/3879/18048 -f 2947/3489/18049 2948/3488/18050 3292/3877/18051 -f 3292/3877/18052 3295/3880/18053 2947/3489/18054 -f 3298/3881/18055 3297/3882/18056 3296/3879/18057 -f 3296/3879/18058 3294/3878/18059 3298/3881/18060 -f 3300/3883/18061 3299/3884/18062 3296/3879/18063 -f 3296/3879/18064 3297/3882/18065 3300/3883/18066 -f 3301/3885/18067 3295/3880/18068 3296/3879/18069 -f 3296/3879/18070 3299/3884/18071 3301/3885/18072 -f 2985/3529/18073 2986/3528/18074 3299/3886/18075 -f 3299/3886/18076 3300/3887/18077 2985/3529/18078 -f 2988/3532/18079 3301/3888/18080 3299/3886/18081 -f 3299/3886/18082 2986/3528/18083 2988/3532/18084 -f 3303/3889/18085 3302/3890/18086 3300/3883/18087 -f 3300/3883/18088 3297/3882/18089 3303/3889/18090 -f 3304/3892/18091 2985/3529/18092 3300/3887/18093 -f 3300/3887/18094 3302/3891/18095 3304/3892/18096 -f 3306/3893/18097 3305/3894/18098 3304/3892/18099 -f 3304/3892/18100 3302/3891/18101 3306/3893/18102 -f 3308/3895/18103 3307/3896/18104 3304/3892/18105 -f 3304/3892/18106 3305/3894/18107 3308/3895/18108 -f 2984/3530/18109 2985/3529/18110 3304/3892/18111 -f 3304/3892/18112 3307/3896/18113 2984/3530/18114 -f 3310/3897/18115 3309/3898/18116 3305/3894/18117 -f 3305/3894/18118 3306/3893/18119 3310/3897/18120 -f 3311/3899/18121 3308/3895/18122 3305/3894/18123 -f 3305/3894/18124 3309/3898/18125 3311/3899/18126 -f 2959/3501/18127 2960/3504/18128 3311/3899/18129 -f 3311/3899/18130 3309/3898/18131 2959/3501/18132 -f 3313/3902/18133 3312/3903/18134 3315/3900/18135 -f 3315/3900/18136 3314/3901/18137 3313/3902/18138 -f 2977/3521/18139 2978/3520/18140 3315/3900/18141 -f 3315/3900/18142 3312/3903/18143 2977/3521/18144 -f 3317/3904/18145 3316/3905/18146 3312/3903/18147 -f 3312/3903/18148 3313/3902/18149 3317/3904/18150 -f 3318/3906/18151 2977/3521/18152 3312/3903/18153 -f 3312/3903/18154 3316/3905/18155 3318/3906/18156 -f 3320/3907/18157 3319/3908/18158 3318/3906/18159 -f 3318/3906/18160 3316/3905/18161 3320/3907/18162 -f 2980/3909/18163 3321/3910/18164 3318/3906/18165 -f 3318/3906/18166 3319/3908/18167 2980/3909/18168 -f 2976/3522/18169 2977/3521/18170 3318/3906/18171 -f 3318/3906/18172 3321/3910/18173 2976/3522/18174 -f 2981/3911/18175 3322/3912/18176 3321/3910/18177 -f 3321/3910/18178 2980/3909/18179 2981/3911/18180 -f 3323/3913/18181 2976/3522/18182 3321/3910/18183 -f 3321/3910/18184 3322/3912/18185 3323/3913/18186 -f 3319/3916/18187 3320/3917/18188 3325/3914/18189 -f 3325/3914/18190 3324/3915/18191 3319/3916/18192 -f 3324/3915/18193 2983/3523/18194 2980/3526/18195 -f 2980/3526/18196 3319/3916/18197 3324/3915/18198 -f 3326/3918/18199 2953/3495/18200 3324/3915/18201 -f 3324/3915/18202 3325/3914/18203 3326/3918/18204 -f 2946/3490/18205 2983/3523/18206 3324/3915/18207 -f 3324/3915/18208 2953/3495/18209 2946/3490/18210 -f 3328/3919/18211 3327/3920/18212 3326/3918/18213 -f 3326/3918/18214 3325/3914/18215 3328/3919/18216 -f 3330/3921/18217 3329/3922/18218 3326/3918/18219 -f 3326/3918/18220 3327/3920/18221 3330/3921/18222 -f 2952/3496/18223 2953/3495/18224 3326/3918/18225 -f 3326/3918/18226 3329/3922/18227 2952/3496/18228 -f 2902/3442/18229 2903/3441/18230 3329/3923/18231 -f 3329/3923/18232 3330/3924/18233 2902/3442/18234 -f 2951/3493/18235 2952/3492/18236 3329/3923/18237 -f 3329/3923/18238 2903/3441/18239 2951/3493/18240 -f 3332/3925/18241 3331/3926/18242 3330/3921/18243 -f 3330/3921/18244 3327/3920/18245 3332/3925/18246 -f 2905/3443/18247 2902/3442/18248 3330/3924/18249 -f 3330/3924/18250 3331/3927/18251 2905/3443/18252 -f 3334/3929/18253 3333/3930/18254 3331/3927/18255 -f 3331/3927/18256 3332/3928/18257 3334/3929/18258 -f 3335/3931/18259 2905/3443/18260 3331/3927/18261 -f 3331/3927/18262 3333/3930/18263 3335/3931/18264 -f 2924/3462/18265 2894/3431/18266 3335/3931/18267 -f 3335/3931/18268 3333/3930/18269 2924/3462/18270 -f 2881/3420/18271 2882/3419/18272 3335/3931/18273 -f 3335/3931/18274 2894/3431/18275 2881/3420/18276 -f 2900/3437/18277 2905/3443/18278 3335/3931/18279 -f 3335/3931/18280 2882/3419/18281 2900/3437/18282 -f 2938/3475/18283 2924/3462/18284 3333/3930/18285 -f 3333/3930/18286 3334/3929/18287 2938/3475/18288 -f 2937/3476/18289 2938/3475/18290 3334/3929/18291 -f 3334/3929/18292 3336/3932/18293 2937/3476/18294 -f 3337/3934/18295 3336/3935/18296 3334/3933/18297 -f 3334/3933/18298 3332/3925/18299 3337/3934/18300 -f 3337/3934/18301 3338/3937/18302 3339/3936/18303 -f 3339/3936/18304 3336/3935/18305 3337/3934/18306 -f 3327/3920/18307 3328/3919/18308 3337/3934/18309 -f 3337/3934/18310 3332/3925/18311 3327/3920/18312 -f 3338/3937/18313 3337/3934/18314 3328/3919/18315 -f 3328/3919/18316 3340/3938/18317 3338/3937/18318 -f 3325/3914/18319 3320/3917/18320 3340/3938/18321 -f 3340/3938/18322 3328/3919/18323 3325/3914/18324 -f 3341/3941/18325 3339/3942/18326 3338/3939/18327 -f 3338/3939/18328 3342/3940/18329 3341/3941/18330 -f 3317/3904/18331 3342/3940/18332 3338/3939/18333 -f 3338/3939/18334 3340/3943/18335 3317/3904/18336 -f 3344/3945/18337 3343/3946/18338 3339/3936/18339 -f 3339/3936/18340 3341/3944/18341 3344/3945/18342 -f 3339/3936/18343 3343/3946/18344 2937/3947/18345 -f 2937/3947/18346 3336/3935/18347 3339/3936/18348 -f 3345/3948/18349 2935/3949/18350 2937/3947/18351 -f 2937/3947/18352 3343/3946/18353 3345/3948/18354 -f 3346/3950/18355 2934/3951/18356 2935/3949/18357 -f 2935/3949/18358 3345/3948/18359 3346/3950/18360 -f 3346/3954/18361 3347/3955/18362 3348/3952/18363 -f 3348/3952/18364 2934/3953/18365 3346/3954/18366 -f 3350/3956/18367 3349/3957/18368 3346/3950/18369 -f 3346/3950/18370 3345/3948/18371 3350/3956/18372 -f 3303/3889/18373 3347/3960/18374 3346/3958/18375 -f 3346/3958/18376 3349/3959/18377 3303/3889/18378 -f 3310/3961/18379 3306/3962/18380 3349/3957/18381 -f 3349/3957/18382 3350/3956/18383 3310/3961/18384 -f 3302/3890/18385 3303/3889/18386 3349/3959/18387 -f 3349/3959/18388 3306/3963/18389 3302/3890/18390 -f 3343/3946/18391 3344/3945/18392 3350/3956/18393 -f 3350/3956/18394 3345/3948/18395 3343/3946/18396 -f 2958/3964/18397 3310/3961/18398 3350/3956/18399 -f 3350/3956/18400 3344/3945/18401 2958/3964/18402 -f 3298/3965/18403 2974/3518/18404 3348/3952/18405 -f 3348/3952/18406 3347/3955/18407 3298/3965/18408 -f 2975/3517/18409 3351/3966/18410 3348/3952/18411 -f 3348/3952/18412 2974/3518/18413 2975/3517/18414 -f 2933/3967/18415 2934/3953/18416 3348/3952/18417 -f 3348/3952/18418 3351/3966/18419 2933/3967/18420 -f 3352/3968/18421 2942/3481/18422 3351/3966/18423 -f 3351/3966/18424 2975/3517/18425 3352/3968/18426 -f 2940/3480/18427 2933/3967/18428 3351/3966/18429 -f 3351/3966/18430 2942/3481/18431 2940/3480/18432 -f 2967/3511/18433 2968/3510/18434 3352/3968/18435 -f 3352/3968/18436 3353/3969/18437 2967/3511/18438 -f 2941/3482/18439 2942/3481/18440 3352/3968/18441 -f 3352/3968/18442 2968/3510/18443 2941/3482/18444 -f 2971/3516/18445 3353/3969/18446 3352/3968/18447 -f 3352/3968/18448 2975/3517/18449 2971/3516/18450 -f 2970/3512/18451 2967/3511/18452 3353/3969/18453 -f 3353/3969/18454 3354/3970/18455 2970/3512/18456 -f 3355/3971/18457 3354/3970/18458 3353/3969/18459 -f 3353/3969/18460 2971/3516/18461 3355/3971/18462 -f 3236/3972/18463 3234/3973/18464 3354/3970/18465 -f 3354/3970/18466 3355/3971/18467 3236/3972/18468 -f 3235/3821/18469 2970/3512/18470 3354/3970/18471 -f 3354/3970/18472 3234/3973/18473 3235/3821/18474 -f 3298/3965/18475 3294/3875/18476 2973/3514/18477 -f 2973/3514/18478 2974/3518/18479 3298/3965/18480 -f 3297/3882/18481 3298/3881/18482 3347/3960/18483 -f 3347/3960/18484 3303/3889/18485 3297/3882/18486 -f 2956/3498/18487 2958/3502/18488 3344/3974/18489 -f 3344/3974/18490 3341/3941/18491 2956/3498/18492 -f 2955/3499/18493 2956/3498/18494 3341/3941/18495 -f 3341/3941/18496 3342/3940/18497 2955/3499/18498 -f 3313/3902/18499 2955/3499/18500 3342/3940/18501 -f 3342/3940/18502 3317/3904/18503 3313/3902/18504 -f 3316/3905/18505 3317/3904/18506 3340/3943/18507 -f 3340/3943/18508 3320/3907/18509 3316/3905/18510 -f 2958/3502/18511 2959/3501/18512 3309/3898/18513 -f 3309/3898/18514 3310/3897/18515 2958/3502/18516 -f 3237/3975/18517 3293/3874/18518 3291/3867/18519 -f 3291/3867/18520 3238/3870/18521 3237/3975/18522 -f 3242/3809/18523 3243/3808/18524 3262/3836/18525 -f 3262/3836/18526 3245/3810/18527 3242/3809/18528 -f 3248/3814/18529 3247/3813/18530 3259/3835/18531 -f 3259/3835/18532 3250/3815/18533 3248/3814/18534 -f 3237/3977/18535 3236/3972/18536 3355/3971/18537 -f 3355/3971/18538 3293/3976/18539 3237/3977/18540 -f 3001/3543/18541 3002/3542/18542 3010/3554/18543 -f 3010/3554/18544 3011/3553/18545 3001/3543/18546 -f 3357/3978/18547 3356/3979/18548 2988/3532/18549 -f 2988/3532/18550 2989/3531/18551 3357/3978/18552 -f 3323/3913/18553 3301/3888/18554 2988/3532/18555 -f 2988/3532/18556 3356/3979/18557 3323/3913/18558 -f 2976/3522/18559 3323/3913/18560 3356/3979/18561 -f 3356/3979/18562 2979/3519/18563 2976/3522/18564 -f 2945/3485/18565 2941/3482/18566 2968/3510/18567 -f 2968/3510/18568 2962/3508/18569 2945/3485/18570 -f 2923/3461/18571 2936/3471/18572 2939/3478/18573 -f 2939/3478/18574 2925/3463/18575 2923/3461/18576 -f 2923/3461/18577 2924/3462/18578 2938/3475/18579 -f 2938/3475/18580 2936/3471/18581 2923/3461/18582 -f 2897/3434/18583 2874/3412/18584 2932/3470/18585 -f 2932/3470/18586 2926/3467/18587 2897/3434/18588 -f 2866/3404/18589 2915/3452/18590 2863/3402/18591 -f 2863/3402/18592 2860/3399/18593 2866/3404/18594 -f 2892/3430/18595 2895/3433/18596 2918/3455/18597 -f 2918/3455/18598 2913/3454/18599 2892/3430/18600 -f 2891/3428/18601 2892/3430/18602 2913/3454/18603 -f 2913/3454/18604 2914/3453/18605 2891/3428/18606 -f 2890/3429/18607 2891/3428/18608 2914/3453/18609 -f 2914/3453/18610 3358/3980/18611 2890/3429/18612 -f 2866/3404/18613 3358/3980/18614 2914/3453/18615 -f 2914/3453/18616 2915/3452/18617 2866/3404/18618 -f 3359/3982/18619 2890/3429/18620 3358/3980/18621 -f 3358/3980/18622 3360/3981/18623 3359/3982/18624 -f 2841/3378/18625 3360/3981/18626 3358/3980/18627 -f 3358/3980/18628 2866/3404/18629 2841/3378/18630 -f 2877/3415/18631 2887/3426/18632 3359/3982/18633 -f 3359/3982/18634 3361/3983/18635 2877/3415/18636 -f 2888/3425/18637 2890/3429/18638 3359/3982/18639 -f 3359/3982/18640 2887/3426/18641 2888/3425/18642 -f 3362/3984/18643 3361/3983/18644 3359/3982/18645 -f 3359/3982/18646 3360/3981/18647 3362/3984/18648 -f 2854/3392/18649 3361/3983/18650 3362/3984/18651 -f 3362/3984/18652 2851/3390/18653 2854/3392/18654 -f 2841/3378/18655 2839/3375/18656 3362/3984/18657 -f 3362/3984/18658 3360/3981/18659 2841/3378/18660 -f 2837/3377/18661 2851/3390/18662 3362/3984/18663 -f 3362/3984/18664 2839/3375/18665 2837/3377/18666 -f 2869/3407/18667 2877/3415/18668 3361/3983/18669 -f 3361/3983/18670 2854/3392/18671 2869/3407/18672 -f 2882/3419/18673 2880/3417/18674 2899/3438/18675 -f 2899/3438/18676 2900/3437/18677 2882/3419/18678 -f 2847/3384/18679 2873/3411/18680 2896/3435/18681 -f 2896/3435/18682 2846/3385/18683 2847/3384/18684 -f 2883/3424/18685 2884/3423/18686 2895/3433/18687 -f 2895/3433/18688 2892/3430/18689 2883/3424/18690 -f 2875/3414/18691 2885/3422/18692 2887/3426/18693 -f 2887/3426/18694 2877/3415/18695 2875/3414/18696 -f 2842/3383/18697 2856/3394/18698 2858/3397/18699 -f 2858/3397/18700 2847/3384/18701 2842/3383/18702 -f 3363/3985/18703 2797/3334/18704 2834/3372/18705 -f 2834/3372/18706 2855/3395/18707 3363/3985/18708 -f 3363/3985/18709 2775/3312/18710 2797/3334/18711 -f 2843/3382/18712 2806/3344/18713 3363/3985/18714 -f 3363/3985/18715 2855/3395/18716 2843/3382/18717 -f 2806/3344/18718 2774/3313/18719 2775/3312/18720 -f 2775/3312/18721 3363/3985/18722 2806/3344/18723 -f 2842/3383/18724 2843/3382/18725 2855/3395/18726 -f 2855/3395/18727 2856/3394/18728 2842/3383/18729 -f 2826/3365/18730 2862/3400/18731 2861/3398/18732 -f 2861/3398/18733 2825/3366/18734 2826/3365/18735 -f 2807/3345/18736 2844/3381/18737 2848/3387/18738 -f 2848/3387/18739 2809/3346/18740 2807/3345/18741 -f 2807/3345/18742 2806/3344/18743 2843/3382/18744 -f 2843/3382/18745 2844/3381/18746 2807/3345/18747 -f 2819/3360/18748 2820/3359/18749 2838/3376/18750 -f 2838/3376/18751 2836/3373/18752 2819/3360/18753 -f 2836/3373/18754 2823/3361/18755 2819/3360/18756 -f 2824/3362/18757 2823/3361/18758 2862/3400/18759 -f 2862/3400/18760 2826/3365/18761 2824/3362/18762 -f 2829/3369/18763 2828/3363/18764 2825/3366/18765 -f 2825/3366/18766 2861/3398/18767 2829/3369/18768 -f 2811/3349/18769 2824/3362/18770 2826/3365/18771 -f 2826/3365/18772 2827/3364/18773 2811/3349/18774 -f 2793/3331/18775 2794/3330/18776 2813/3352/18777 -f 2813/3352/18778 2764/3304/18779 2793/3331/18780 -f 2766/3302/18781 2812/3348/18782 2810/3350/18783 -f 2810/3350/18784 2765/3303/18785 2766/3302/18786 -f 2798/3338/18787 2805/3343/18788 2808/3347/18789 -f 2808/3347/18790 2802/3339/18791 2798/3338/18792 -f 2783/3320/18793 2800/3336/18794 2803/3342/18795 -f 2803/3342/18796 2782/3321/18797 2783/3320/18798 -f 2783/3320/18799 2785/3324/18800 2799/3337/18801 -f 2799/3337/18802 2800/3336/18803 2783/3320/18804 -f 2767/3305/18805 2758/3295/18806 2755/3293/18807 -f 2755/3293/18808 2762/3300/18809 2767/3305/18810 -f 3364/3986/18811 2772/3311/18812 2776/3315/18813 -f 2776/3315/18814 3132/3689/18815 3364/3986/18816 -f 2774/3313/18817 2773/3310/18818 2769/3308/18819 -f 2755/3293/18820 2754/3289/18821 2761/3301/18822 -f 2761/3301/18823 2762/3300/18824 2755/3293/18825 -f 3132/3689/18826 3070/3619/18827 3071/3618/18828 -f 3071/3618/18829 3364/3986/18830 3132/3689/18831 -f 2734/3275/18832 2735/3274/18833 2748/3287/18834 -f 2748/3287/18835 2749/3286/18836 2734/3275/18837 -f 3113/3667/18838 3115/3670/18839 3118/3674/18840 -f 3117/3672/18841 3091/3675/18842 2729/3673/18843 -f 2721/3256/18844 2715/3253/18845 2726/3263/18846 -f 2726/3263/18847 2727/3262/18848 2721/3256/18849 -f 3070/3619/18850 3365/3987/18851 2740/3281/18852 -f 2740/3281/18853 3068/3616/18854 3070/3619/18855 -f 3130/3688/18856 3365/3987/18857 3070/3619/18858 -f 3070/3619/18859 3132/3689/18860 3130/3688/18861 -f 3136/3693/18862 3365/3987/18863 3130/3688/18864 -f 3130/3688/18865 3134/3691/18866 3136/3693/18867 -f 2743/3278/18868 2740/3281/18869 3365/3987/18870 -f 2743/3278/18871 3365/3987/18872 3136/3693/18873 -f 2743/3278/18874 3136/3693/18875 2742/3279/18876 -f 3314/3901/18877 2954/3500/18878 2955/3499/18879 -f 2955/3499/18880 3313/3902/18881 3314/3901/18882 -f 3301/3885/18883 2982/3524/18884 2947/3489/18885 -f 2947/3489/18886 3295/3880/18887 3301/3885/18888 -f 3322/3912/18889 2981/3911/18890 3301/3888/18891 -f 3301/3888/18892 3323/3913/18893 3322/3912/18894 -f 3178/3739/18895 3007/3547/18896 3004/3550/18897 -f 3180/3742/18898 3181/3741/18899 3366/3988/18900 -f 3011/3553/18901 3366/3988/18902 3181/3741/18903 -f 3181/3741/18904 3186/3746/18905 3011/3553/18906 -f 3178/3739/18907 3366/3988/18908 3011/3553/18909 -f 3011/3553/18910 3007/3547/18911 3178/3739/18912 -f 3364/3986/18913 2771/3306/18914 2768/3309/18915 -f 2768/3309/18916 2772/3311/18917 3364/3986/18918 -f 3314/3901/18919 2961/3503/18920 2957/3497/18921 -f 2957/3497/18922 2954/3500/18923 3314/3901/18924 -f 2982/3524/18925 3301/3885/18926 2981/3525/18927 -f 3178/3739/18928 3180/3742/18929 3366/3988/18930 -f 2979/3519/18931 3367/3989/18932 2978/3520/18933 -f 3004/3550/18934 3005/3549/18935 3013/3555/18936 -f 3369/3990/18937 3368/3991/18938 3025/3567/18939 -f 3025/3567/18940 3024/3568/18941 3369/3990/18942 -f 3024/3568/18943 2779/3318/18944 3369/3990/18945 -f 3367/3989/18946 2979/3519/18947 3356/3979/18948 -f 3356/3979/18949 3357/3978/18950 3367/3989/18951 -f 3369/3990/18952 2780/3317/18953 3169/3727/18954 -f 3169/3727/18955 3368/3991/18956 3369/3990/18957 -f 3369/3990/18958 2779/3318/18959 2780/3317/18960 -f 3012/3556/18961 3214/3774/18962 3013/3555/18963 -f 2997/3541/18964 2998/3540/18965 3370/3992/18966 -f 2998/3540/18967 3191/3794/18968 3370/3992/18969 -f 3185/3744/18970 3370/3993/18971 3191/3751/18972 -f 3191/3751/18973 3184/3745/18974 3185/3744/18975 -f 3151/3707/18976 2786/3323/18977 2784/3319/18978 -f 2784/3319/18979 2781/3322/18980 3151/3707/18981 -f 3151/3707/18982 3141/3696/18983 3127/3684/18984 -f 3127/3684/18985 2786/3323/18986 3151/3707/18987 -f 3371/3994/18988 3118/3674/18989 2729/3673/18990 -f 2729/3673/18991 2727/3262/18992 3371/3994/18993 -f 3371/3994/18994 2727/3262/18995 3111/3665/18996 -f 3111/3665/18997 3110/3666/18998 3371/3994/18999 -f 3110/3666/19000 3113/3667/19001 3118/3674/19002 -f 3118/3674/19003 3371/3994/19004 3110/3666/19005 -f 3111/3665/19006 3104/3659/19007 3108/3663/19008 -f 2732/3269/19009 3107/3664/19010 3120/3676/19011 -f 3120/3676/19012 2731/3270/19013 2732/3269/19014 -f 3105/3661/19015 3107/3664/19016 3108/3663/19017 -f 3108/3663/19018 3104/3659/19019 3105/3661/19020 -f 3120/3676/19021 3107/3664/19022 3105/3661/19023 -f 2851/3390/19024 3163/3719/19025 2850/3391/19026 -f 3286/3863/19027 3288/3864/19028 3284/3859/19029 -f 3284/3859/19030 3285/3860/19031 3286/3863/19032 -f 2950/3494/19033 2912/3450/19034 2906/3447/19035 -f 2906/3447/19036 3288/3864/19037 2950/3494/19038 -f 3315/3900/19039 2978/3520/19040 2960/3504/19041 -f 2960/3504/19042 2961/3503/19043 3315/3900/19044 -f 2961/3503/19045 3314/3901/19046 3315/3900/19047 -f 3367/3989/19048 3357/3978/19049 3308/3895/19050 -f 3308/3895/19051 3311/3899/19052 3367/3989/19053 -f 2989/3531/19054 3307/3896/19055 3308/3895/19056 -f 3308/3895/19057 3357/3978/19058 2989/3531/19059 -f 2989/3531/19060 2987/3527/19061 2984/3530/19062 -f 2984/3530/19063 3307/3896/19064 2989/3531/19065 -f 3367/3989/19066 3311/3899/19067 2960/3504/19068 -f 2960/3504/19069 2978/3520/19070 3367/3989/19071 -f 3004/3550/19072 3013/3555/19073 3179/3738/19074 -f 3179/3738/19075 3013/3555/19076 3214/3774/19077 -f 3214/3774/19078 3217/3778/19079 3179/3738/19080 -f 2994/3538/19081 3183/3743/19082 3179/3738/19083 -f 3179/3738/19084 3217/3778/19085 2994/3538/19086 -f 2994/3538/19087 2995/3537/19088 3183/3743/19089 -f 2997/3541/19090 3370/3992/19091 3185/3744/19092 -f 3185/3744/19093 3182/3740/19094 2997/3541/19095 -f 2995/3537/19096 2997/3541/19097 3182/3740/19098 -f 3182/3740/19099 3183/3743/19100 2995/3537/19101 -f 2972/3515/19102 3293/3976/19103 3355/3971/19104 -f 3355/3971/19105 2971/3516/19106 2972/3515/19107 -f 3091/3646/19108 3094/3649/19109 2728/3266/19110 -f 2728/3266/19111 2729/3267/19112 3091/3646/19113 -f 2848/3387/19114 2849/3386/19115 3278/3854/19116 -f 3278/3854/19117 3279/3853/19118 2848/3387/19119 -f 2801/3340/19120 2802/3339/19121 2808/3347/19122 -f 2808/3347/19123 2804/3341/19124 2801/3340/19125 -f 2804/3341/19126 2808/3347/19127 2809/3346/19128 -f 2809/3346/19129 3281/3855/19130 2804/3341/19131 -f 3281/3855/19132 2809/3346/19133 2848/3387/19134 -f 2848/3387/19135 3279/3853/19136 3281/3855/19137 -f 3157/3714/19138 3156/3713/19139 2816/3354/19140 -f 2816/3354/19141 2817/3353/19142 3157/3714/19143 -f 3154/3712/19144 3161/3715/19145 2816/3354/19146 -f 2816/3354/19147 3156/3713/19148 3154/3712/19149 -f 3155/3711/19150 3160/3716/19151 3161/3715/19152 -f 3161/3715/19153 3154/3712/19154 3155/3711/19155 -f 2835/3374/19156 2862/3400/19157 2823/3361/19158 -f 2812/3348/19159 2822/3357/19160 2811/3349/19161 -f 3168/3724/19162 3165/3721/19163 3160/3716/19164 -f 3160/3716/19165 3155/3711/19166 3168/3724/19167 -f 3168/3724/19168 3166/3723/19169 3165/3721/19170 -f 3111/3665/19171 2727/3262/19172 3104/3659/19173 -f 2747/3282/19174 2744/3285/19175 3085/3637/19176 -f 3085/3637/19177 2750/3288/19178 2747/3282/19179 -f 2741/3280/19180 2742/3279/19181 3084/3638/19182 -f 3364/3986/19183 3071/3618/19184 3065/3613/19185 -f 3065/3613/19186 2771/3306/19187 3364/3986/19188 -f 3071/3618/19189 3069/3615/19190 3064/3611/19191 -f 3064/3611/19192 3065/3613/19193 3071/3618/19194 -f 3064/3611/19195 3069/3615/19196 3063/3612/19197 -f 2771/3306/19198 3065/3613/19199 3056/3605/19200 -f 2739/3277/19201 3112/3668/19202 3109/3662/19203 -f 2733/3268/19204 2730/3271/19205 2738/3276/19206 -f 3373/3997/19207 3372/3998/19208 3375/3995/19209 -f 3375/3995/19210 3374/3996/19211 3373/3997/19212 -f 3377/3999/19213 3376/4000/19214 3375/3995/19215 -f 3375/3995/19216 3372/3998/19217 3377/3999/19218 -f 3375/3995/19219 3376/4000/19220 3378/4001/19221 -f 3378/4001/19222 3374/3996/19223 3375/3995/19224 -f 3380/4002/19225 3379/4003/19226 3376/4000/19227 -f 3376/4000/19228 3377/3999/19229 3380/4002/19230 -f 3376/4000/19231 3381/4005/19232 3382/4004/19233 -f 3382/4004/19234 3378/4001/19235 3376/4000/19236 -f 3376/4000/19237 3379/4003/19238 3383/4006/19239 -f 3383/4006/19240 3381/4005/19241 3376/4000/19242 -f 3380/4002/19243 3384/4008/19244 3385/4007/19245 -f 3385/4007/19246 3379/4003/19247 3380/4002/19248 -f 3385/4007/19249 3384/4008/19250 3386/4009/19251 -f 3385/4007/19252 3386/4009/19253 3388/4010/19254 -f 3388/4010/19255 3387/4011/19256 3385/4007/19257 -f 3390/4014/19258 3389/4015/19259 3392/4012/19260 -f 3392/4012/19261 3391/4013/19262 3390/4014/19263 -f 3391/4013/19264 3393/4016/19265 3390/4014/19266 -f 3390/4014/19267 3394/4018/19268 3395/4017/19269 -f 3395/4017/19270 3389/4015/19271 3390/4014/19272 -f 3396/4020/19273 3394/4018/19274 3390/4014/19275 -f 3390/4014/19276 3397/4019/19277 3396/4020/19278 -f 3399/4023/19279 3398/4024/19280 3401/4021/19281 -f 3401/4021/19282 3400/4022/19283 3399/4023/19284 -f 3402/4025/19285 3391/4013/19286 3392/4012/19287 -f 3403/4026/19288 3402/4025/19289 3392/4012/19290 -f 3404/4029/19291 3393/4016/19292 3406/4027/19293 -f 3406/4027/19294 3405/4028/19295 3404/4029/19296 -f 3406/4027/19297 3393/4016/19298 3391/4013/19299 -f 3391/4013/19300 3402/4025/19301 3406/4027/19302 -f 3402/4025/19303 3403/4026/19304 3406/4027/19305 -f 3406/4027/19306 3403/4026/19307 3408/4030/19308 -f 3408/4030/19309 3407/4031/19310 3406/4027/19311 -f 3409/4032/19312 3407/4031/19313 3408/4030/19314 -f 3409/4032/19315 3408/4030/19316 3411/4033/19317 -f 3411/4033/19318 3410/4034/19319 3409/4032/19320 -f 3409/4032/19321 3413/4035/19322 3412/4036/19323 -f 3414/4037/19324 3407/4031/19325 3409/4032/19326 -f 3409/4032/19327 3412/4036/19328 3414/4037/19329 -f 3415/4038/19330 3386/4009/19331 3384/4008/19332 -f 3384/4008/19333 3400/4022/19334 3415/4038/19335 -f 3415/4038/19336 3416/4039/19337 3388/4010/19338 -f 3388/4010/19339 3386/4009/19340 3415/4038/19341 -f 3413/4035/19342 3409/4032/19343 3410/4034/19344 -f 3410/4034/19345 3417/4040/19346 3413/4035/19347 -f 3418/4041/19348 3412/4036/19349 3413/4035/19350 -f 3413/4035/19351 3417/4040/19352 3418/4041/19353 -f 3420/4044/19354 3419/4045/19355 3422/4042/19356 -f 3422/4042/19357 3421/4043/19358 3420/4044/19359 -f 3423/4047/19360 3419/4045/19361 3420/4044/19362 -f 3420/4044/19363 3424/4046/19364 3423/4047/19365 -f 3426/4049/19366 3425/4050/19367 3427/4048/19368 -f 3427/4048/19369 3422/4042/19370 3426/4049/19371 -f 3428/4053/19372 3426/4049/19373 3430/4051/19374 -f 3430/4051/19375 3429/4052/19376 3428/4053/19377 -f 3426/4049/19378 3428/4053/19379 3425/4050/19380 -f 3426/4049/19381 3422/4042/19382 3419/4045/19383 -f 3419/4045/19384 3431/4054/19385 3426/4049/19386 -f 3421/4043/19387 3433/4055/19388 3432/4056/19389 -f 3420/4044/19390 3421/4043/19391 3432/4056/19392 -f 3432/4056/19393 3424/4046/19394 3420/4044/19395 -f 3435/4057/19396 3434/4058/19397 3430/4051/19398 -f 3430/4051/19399 3426/4049/19400 3435/4057/19401 -f 3435/4057/19402 3426/4049/19403 3431/4054/19404 -f 3431/4054/19405 3436/4059/19406 3435/4057/19407 -f 3435/4057/19408 3437/4061/19409 3438/4060/19410 -f 3438/4060/19411 3434/4058/19412 3435/4057/19413 -f 3435/4057/19414 3436/4059/19415 3440/4062/19416 -f 3440/4062/19417 3439/4063/19418 3435/4057/19419 -f 3435/4057/19420 3439/4063/19421 3441/4064/19422 -f 3441/4064/19423 3437/4061/19424 3435/4057/19425 -f 3442/4066/19426 3423/4047/19427 3424/4046/19428 -f 3424/4046/19429 3443/4065/19430 3442/4066/19431 -f 3442/4066/19432 3444/4068/19433 3445/4067/19434 -f 3445/4067/19435 3423/4047/19436 3442/4066/19437 -f 3442/4066/19438 3443/4065/19439 3446/4069/19440 -f 3446/4069/19441 3444/4068/19442 3442/4066/19443 -f 3448/4072/19444 3447/4073/19445 3450/4070/19446 -f 3450/4070/19447 3449/4071/19448 3448/4072/19449 -f 3452/4074/19450 3451/4075/19451 3447/4073/19452 -f 3447/4073/19453 3448/4072/19454 3452/4074/19455 -f 3448/4072/19456 3449/4071/19457 3453/4076/19458 -f 3453/4076/19459 3452/4074/19460 3448/4072/19461 -f 3455/4077/19462 3454/4078/19463 3428/4053/19464 -f 3428/4053/19465 3429/4052/19466 3455/4077/19467 -f 3429/4052/19468 3430/4051/19469 3456/4079/19470 -f 3456/4079/19471 3455/4077/19472 3429/4052/19473 -f 3458/4081/19474 3457/4082/19475 3444/4068/19476 -f 3444/4068/19477 3459/4080/19478 3458/4081/19479 -f 3444/4068/19480 3457/4082/19481 3445/4067/19482 -f 3446/4069/19483 3461/4083/19484 3460/4084/19485 -f 3444/4068/19486 3446/4069/19487 3460/4084/19488 -f 3460/4084/19489 3459/4080/19490 3444/4068/19491 -f 3463/4085/19492 3462/4086/19493 3412/4036/19494 -f 3412/4036/19495 3418/4041/19496 3463/4085/19497 -f 3463/4085/19498 3418/4041/19499 3465/4087/19500 -f 3465/4087/19501 3464/4088/19502 3463/4085/19503 -f 3467/4089/19504 3466/4090/19505 3463/4085/19506 -f 3463/4085/19507 3464/4088/19508 3467/4089/19509 -f 3469/4092/19510 3468/4093/19511 3470/4091/19512 -f 3470/4091/19513 3462/4086/19514 3469/4092/19515 -f 3469/4092/19516 3471/4094/19517 3468/4093/19518 -f 3472/4097/19519 3466/4098/19520 3474/4095/19521 -f 3474/4095/19522 3473/4096/19523 3472/4097/19524 -f 3476/4101/19525 3475/4102/19526 3478/4099/19527 -f 3478/4099/19528 3477/4100/19529 3476/4101/19530 -f 3476/4101/19531 3479/4104/19532 3480/4103/19533 -f 3480/4103/19534 3475/4102/19535 3476/4101/19536 -f 3476/4101/19537 3477/4100/19538 3481/4105/19539 -f 3481/4105/19540 3479/4104/19541 3476/4101/19542 -f 3483/4108/19543 3482/4109/19544 3485/4106/19545 -f 3485/4106/19546 3484/4107/19547 3483/4108/19548 -f 3485/4106/19549 3486/4112/19550 3488/4110/19551 -f 3488/4110/19552 3487/4111/19553 3485/4106/19554 -f 3480/4103/19555 3489/4114/19556 3490/4113/19557 -f 3490/4113/19558 3475/4102/19559 3480/4103/19560 -f 3492/4117/19561 3491/4118/19562 3494/4115/19563 -f 3494/4115/19564 3493/4116/19565 3492/4117/19566 -f 3479/4104/19567 3481/4105/19568 3496/4119/19569 -f 3496/4119/19570 3495/4120/19571 3479/4104/19572 -f 3498/4123/19573 3497/4124/19574 3474/4121/19575 -f 3474/4121/19576 3499/4122/19577 3498/4123/19578 -f 3501/4125/19579 3500/4126/19580 3497/4124/19581 -f 3497/4124/19582 3498/4123/19583 3501/4125/19584 -f 3498/4123/19585 3499/4122/19586 3502/4127/19587 -f 3502/4127/19588 3501/4125/19589 3498/4123/19590 -f 3504/4129/19591 3503/4130/19592 3495/4120/19593 -f 3495/4120/19594 3505/4128/19595 3504/4129/19596 -f 3487/4111/19597 3489/4114/19598 3480/4103/19599 -f 3480/4103/19600 3503/4130/19601 3487/4111/19602 -f 3503/4130/19603 3506/4131/19604 3487/4111/19605 -f 3508/4134/19606 3507/4135/19607 3510/4132/19608 -f 3510/4132/19609 3509/4133/19610 3508/4134/19611 -f 3512/4136/19612 3511/4137/19613 3507/4135/19614 -f 3507/4135/19615 3508/4134/19616 3512/4136/19617 -f 3508/4134/19618 3509/4133/19619 3513/4138/19620 -f 3513/4138/19621 3512/4136/19622 3508/4134/19623 -f 3515/4141/19624 3514/4142/19625 3517/4139/19626 -f 3517/4139/19627 3516/4140/19628 3515/4141/19629 -f 3515/4141/19630 3516/4140/19631 3519/4143/19632 -f 3519/4143/19633 3518/4144/19634 3515/4141/19635 -f 3515/4141/19636 3518/4144/19637 3520/4145/19638 -f 3520/4145/19639 3514/4142/19640 3515/4141/19641 -f 3483/4108/19642 3484/4107/19643 3522/4146/19644 -f 3522/4146/19645 3521/4147/19646 3483/4108/19647 -f 3523/4149/19648 3521/4147/19649 3522/4146/19650 -f 3522/4146/19651 3524/4148/19652 3523/4149/19653 -f 3526/4152/19654 3525/4153/19655 3528/4150/19656 -f 3528/4150/19657 3527/4151/19658 3526/4152/19659 -f 3530/4154/19660 3529/4155/19661 3525/4153/19662 -f 3525/4153/19663 3526/4152/19664 3530/4154/19665 -f 3526/4152/19666 3527/4151/19667 3531/4156/19668 -f 3531/4156/19669 3530/4154/19670 3526/4152/19671 -f 3533/4159/19672 3532/4160/19673 3535/4157/19674 -f 3535/4157/19675 3534/4158/19676 3533/4159/19677 -f 3537/4161/19678 3536/4162/19679 3532/4160/19680 -f 3532/4160/19681 3533/4159/19682 3537/4161/19683 -f 3533/4159/19684 3534/4158/19685 3538/4163/19686 -f 3538/4163/19687 3537/4161/19688 3533/4159/19689 -f 3540/4166/19690 3539/4167/19691 3542/4164/19692 -f 3542/4164/19693 3541/4165/19694 3540/4166/19695 -f 3540/4166/19696 3541/4165/19697 3544/4168/19698 -f 3544/4168/19699 3543/4169/19700 3540/4166/19701 -f 3540/4166/19702 3535/4157/19703 3545/4170/19704 -f 3545/4170/19705 3539/4167/19706 3540/4166/19707 -f 3547/4173/19708 3546/4174/19709 3549/4171/19710 -f 3549/4171/19711 3548/4172/19712 3547/4173/19713 -f 3547/4173/19714 3548/4172/19715 3551/4175/19716 -f 3551/4175/19717 3550/4176/19718 3547/4173/19719 -f 3547/4179/19720 3552/4180/19721 3553/4177/19722 -f 3553/4177/19723 3546/4178/19724 3547/4179/19725 -f 3547/4183/19726 3554/4184/19727 3555/4181/19728 -f 3555/4181/19729 3552/4182/19730 3547/4183/19731 -f 3557/4187/19732 3556/4188/19733 3559/4185/19734 -f 3559/4185/19735 3558/4186/19736 3557/4187/19737 -f 3561/4189/19738 3560/4190/19739 3556/4188/19740 -f 3556/4188/19741 3557/4187/19742 3561/4189/19743 -f 3557/4187/19744 3558/4186/19745 3562/4191/19746 -f 3562/4191/19747 3561/4189/19748 3557/4187/19749 -f 3564/4194/19750 3563/4195/19751 3566/4192/19752 -f 3566/4192/19753 3565/4193/19754 3564/4194/19755 -f 3564/4194/19756 3565/4193/19757 3568/4196/19758 -f 3568/4196/19759 3567/4197/19760 3564/4194/19761 -f 3564/4194/19762 3569/4199/19763 3570/4198/19764 -f 3570/4198/19765 3563/4195/19766 3564/4194/19767 -f 3573/4200/19768 3572/4201/19769 3571/4202/19770 -f 3571/4202/19771 3574/4204/19772 3575/4203/19773 -f 3575/4203/19774 3573/4200/19775 3571/4202/19776 -f 3571/4202/19777 3572/4201/19778 3576/4205/19779 -f 3575/4203/19780 3574/4204/19781 3577/4206/19782 -f 3579/4207/19783 3578/4208/19784 3575/4203/19785 -f 3575/4203/19786 3577/4206/19787 3579/4207/19788 -f 3579/4211/19789 3580/4212/19790 3582/4209/19791 -f 3582/4209/19792 3581/4210/19793 3579/4211/19794 -f 3579/4207/19795 3577/4206/19796 3576/4205/19797 -f 3576/4205/19798 3583/4213/19799 3579/4207/19800 -f 3571/4202/19801 3576/4205/19802 3577/4206/19803 -f 3577/4206/19804 3574/4204/19805 3571/4202/19806 -f 3567/4216/19807 3568/4217/19808 3585/4214/19809 -f 3585/4214/19810 3584/4215/19811 3567/4216/19812 -f 3567/4216/19813 3584/4215/19814 3586/4218/19815 -f 3586/4218/19816 3564/4219/19817 3567/4216/19818 -f 3580/4220/19819 3588/4221/19820 3587/4222/19821 -f 3580/4212/19822 3587/4225/19823 3590/4223/19824 -f 3590/4223/19825 3589/4224/19826 3580/4212/19827 -f 3591/4227/19828 3590/4223/19829 3587/4225/19830 -f 3587/4225/19831 3592/4226/19832 3591/4227/19833 -f 3591/4227/19834 3592/4226/19835 3593/4228/19836 -f 3595/4229/19837 3594/4230/19838 3593/4231/19839 -f 3595/4229/19840 3593/4231/19841 3592/4232/19842 -f 3592/4232/19843 3596/4233/19844 3595/4229/19845 -f 3598/4235/19846 3597/4236/19847 3599/4234/19848 -f 3599/4234/19849 3551/4175/19850 3598/4235/19851 -f 3601/4237/19852 3600/4238/19853 3599/4234/19854 -f 3599/4234/19855 3597/4236/19856 3601/4237/19857 -f 3599/4234/19858 3602/4240/19859 3603/4239/19860 -f 3603/4239/19861 3550/4176/19862 3599/4234/19863 -f 3599/4234/19864 3600/4238/19865 3604/4241/19866 -f 3604/4241/19867 3602/4240/19868 3599/4234/19869 -f 3595/4229/19870 3596/4233/19871 3605/4242/19872 -f 3595/4229/19873 3605/4242/19874 3606/4243/19875 -f 3606/4243/19876 3594/4230/19877 3595/4229/19878 -f 3594/4230/19879 3606/4243/19880 3607/4244/19881 -f 3609/4247/19882 3608/4248/19883 3611/4245/19884 -f 3611/4245/19885 3610/4246/19886 3609/4247/19887 -f 3611/4245/19888 3608/4248/19889 3613/4249/19890 -f 3613/4249/19891 3612/4250/19892 3611/4245/19893 -f 3614/4251/19894 3610/4246/19895 3611/4245/19896 -f 3611/4245/19897 3612/4250/19898 3614/4251/19899 -f 3615/4254/19900 3585/4214/19901 3617/4252/19902 -f 3617/4252/19903 3616/4253/19904 3615/4254/19905 -f 3615/4254/19906 3616/4253/19907 3619/4255/19908 -f 3619/4255/19909 3618/4256/19910 3615/4254/19911 -f 3615/4254/19912 3620/4257/19913 3584/4215/19914 -f 3584/4215/19915 3585/4214/19916 3615/4254/19917 -f 3555/4181/19918 3621/4259/19919 3622/4258/19920 -f 3622/4258/19921 3552/4182/19922 3555/4181/19923 -f 3624/4262/19924 3623/4263/19925 3626/4260/19926 -f 3626/4260/19927 3625/4261/19928 3624/4262/19929 -f 3628/4264/19930 3627/4265/19931 3623/4263/19932 -f 3623/4263/19933 3624/4262/19934 3628/4264/19935 -f 3624/4262/19936 3625/4261/19937 3629/4266/19938 -f 3629/4266/19939 3628/4264/19940 3624/4262/19941 -f 3631/4269/19942 3630/4270/19943 3633/4267/19944 -f 3633/4267/19945 3632/4268/19946 3631/4269/19947 -f 3633/4267/19948 3634/4271/19949 3609/4247/19950 -f 3609/4247/19951 3610/4246/19952 3633/4267/19953 -f 3633/4267/19954 3630/4270/19955 3635/4272/19956 -f 3635/4272/19957 3634/4271/19958 3633/4267/19959 -f 3616/4253/19960 3617/4252/19961 3637/4273/19962 -f 3637/4273/19963 3636/4274/19964 3616/4253/19965 -f 3616/4253/19966 3638/4276/19967 3639/4275/19968 -f 3639/4275/19969 3619/4255/19970 3616/4253/19971 -f 3609/4247/19972 3640/4277/19973 3608/4248/19974 -f 3609/4247/19975 3641/4279/19976 3642/4278/19977 -f 3642/4278/19978 3640/4277/19979 3609/4247/19980 -f 3641/4279/19981 3643/4282/19982 3645/4280/19983 -f 3645/4280/19984 3644/4281/19985 3641/4279/19986 -f 3641/4279/19987 3644/4281/19988 3646/4283/19989 -f 3646/4283/19990 3642/4278/19991 3641/4279/19992 -f 3648/4286/19993 3647/4287/19994 3650/4284/19995 -f 3650/4284/19996 3649/4285/19997 3648/4286/19998 -f 3650/4284/19999 3647/4287/20000 3652/4288/20001 -f 3652/4288/20002 3651/4289/20003 3650/4284/20004 -f 3650/4284/20005 3651/4289/20006 3654/4290/20007 -f 3654/4290/20008 3653/4291/20009 3650/4284/20010 -f 3655/4293/20011 3620/4257/20012 3615/4254/20013 -f 3615/4254/20014 3656/4292/20015 3655/4293/20016 -f 3655/4293/20017 3656/4292/20018 3654/4290/20019 -f 3654/4290/20020 3651/4289/20021 3655/4293/20022 -f 3655/4293/20023 3651/4289/20024 3652/4288/20025 -f 3652/4288/20026 3620/4257/20027 3655/4293/20028 -f 3654/4290/20029 3656/4292/20030 3657/4294/20031 -f 3657/4294/20032 3653/4291/20033 3654/4290/20034 -f 3658/4297/20035 3613/4249/20036 3660/4295/20037 -f 3660/4295/20038 3659/4296/20039 3658/4297/20040 -f 3658/4297/20041 3661/4298/20042 3612/4250/20043 -f 3612/4250/20044 3613/4249/20045 3658/4297/20046 -f 3658/4297/20047 3659/4296/20048 3663/4299/20049 -f 3663/4299/20050 3662/4300/20051 3658/4297/20052 -f 3665/4303/20053 3664/4304/20054 3667/4301/20055 -f 3667/4301/20056 3666/4302/20057 3665/4303/20058 -f 3665/4303/20059 3668/4306/20060 3669/4305/20061 -f 3669/4305/20062 3664/4304/20063 3665/4303/20064 -f 3665/4303/20065 3666/4302/20066 3670/4307/20067 -f 3670/4307/20068 3668/4306/20069 3665/4303/20070 -f 3668/4306/20071 3670/4307/20072 3671/4308/20073 -f 3671/4308/20074 3669/4305/20075 3668/4306/20076 -f 3673/4311/20077 3672/4312/20078 3675/4309/20079 -f 3675/4309/20080 3674/4310/20081 3673/4311/20082 -f 3677/4314/20083 3676/4315/20084 3675/4309/20085 -f 3675/4309/20086 3678/4313/20087 3677/4314/20088 -f 3679/4316/20089 3674/4310/20090 3675/4309/20091 -f 3675/4309/20092 3676/4315/20093 3679/4316/20094 -f 3681/4318/20095 3680/4319/20096 3682/4317/20097 -f 3682/4317/20098 3666/4302/20099 3681/4318/20100 -f 3671/4308/20101 3683/4322/20102 3685/4320/20103 -f 3685/4320/20104 3684/4321/20105 3671/4308/20106 -f 3671/4308/20107 3670/4307/20108 3686/4323/20109 -f 3686/4323/20110 3683/4322/20111 3671/4308/20112 -f 3687/4325/20113 3669/4305/20114 3671/4308/20115 -f 3671/4308/20116 3688/4324/20117 3687/4325/20118 -f 3689/4326/20119 3688/4324/20120 3671/4308/20121 -f 3671/4308/20122 3684/4321/20123 3689/4326/20124 -f 3685/4320/20125 3690/4328/20126 3691/4327/20127 -f 3691/4327/20128 3684/4321/20129 3685/4320/20130 -f 3685/4320/20131 3683/4330/20132 3692/4329/20133 -f 3692/4329/20134 3690/4328/20135 3685/4320/20136 -f 3678/4313/20137 3675/4309/20138 3662/4300/20139 -f 3662/4300/20140 3693/4331/20141 3678/4313/20142 -f 3694/4332/20143 3677/4314/20144 3678/4313/20145 -f 3678/4313/20146 3693/4331/20147 3694/4332/20148 -f 3680/4335/20149 3681/4336/20150 3696/4333/20151 -f 3696/4333/20152 3695/4334/20153 3680/4335/20154 -f 3680/4335/20155 3695/4334/20156 3697/4337/20157 -f 3697/4337/20158 3682/4338/20159 3680/4335/20160 -f 3690/4328/20161 3692/4329/20162 3698/4339/20163 -f 3698/4339/20164 3691/4327/20165 3690/4328/20166 -f 3700/4342/20167 3699/4343/20168 3702/4340/20169 -f 3702/4340/20170 3701/4341/20171 3700/4342/20172 -f 3702/4340/20173 3699/4343/20174 3679/4316/20175 -f 3702/4340/20176 3703/4345/20177 3704/4344/20178 -f 3704/4344/20179 3701/4341/20180 3702/4340/20181 -f 3561/4189/20182 3705/4348/20183 3707/4346/20184 -f 3707/4346/20185 3706/4347/20186 3561/4189/20187 -f 3561/4189/20188 3562/4191/20189 3708/4349/20190 -f 3708/4349/20191 3705/4348/20192 3561/4189/20193 -f 3561/4189/20194 3706/4347/20195 3710/4350/20196 -f 3710/4350/20197 3709/4351/20198 3561/4189/20199 -f 3712/4352/20200 3711/4353/20201 3695/4334/20202 -f 3695/4334/20203 3696/4333/20204 3712/4352/20205 -f 3714/4356/20206 3713/4357/20207 3716/4354/20208 -f 3716/4354/20209 3715/4355/20210 3714/4356/20211 -f 3714/4356/20212 3715/4355/20213 3718/4358/20214 -f 3718/4358/20215 3717/4359/20216 3714/4356/20217 -f 3714/4356/20218 3717/4359/20219 3720/4360/20220 -f 3720/4360/20221 3719/4361/20222 3714/4356/20223 -f 3693/4331/20224 3721/4362/20225 3694/4332/20226 -f 3721/4362/20227 3722/4364/20228 3723/4363/20229 -f 3723/4363/20230 3694/4332/20231 3721/4362/20232 -f 3722/4364/20233 3724/4365/20234 3723/4363/20235 -f 3725/4367/20236 3703/4345/20237 3702/4340/20238 -f 3702/4340/20239 3726/4366/20240 3725/4367/20241 -f 3725/4367/20242 3726/4366/20243 3728/4368/20244 -f 3728/4368/20245 3727/4369/20246 3725/4367/20247 -f 3725/4367/20248 3727/4369/20249 3717/4359/20250 -f 3717/4359/20251 3718/4358/20252 3725/4367/20253 -f 3727/4369/20254 3728/4368/20255 3723/4363/20256 -f 3723/4363/20257 3724/4365/20258 3727/4369/20259 -f 3727/4369/20260 3724/4365/20261 3720/4360/20262 -f 3720/4360/20263 3717/4359/20264 3727/4369/20265 -f 3728/4368/20266 3677/4314/20267 3694/4332/20268 -f 3694/4332/20269 3723/4363/20270 3728/4368/20271 -f 3728/4368/20272 3726/4366/20273 3676/4315/20274 -f 3676/4315/20275 3677/4314/20276 3728/4368/20277 -f 3676/4315/20278 3726/4366/20279 3702/4340/20280 -f 3702/4340/20281 3679/4316/20282 3676/4315/20283 -f 3729/4370/20284 3674/4310/20285 3679/4316/20286 -f 3679/4316/20287 3699/4343/20288 3729/4370/20289 -f 3729/4370/20290 3699/4343/20291 3601/4371/20292 -f 3601/4371/20293 3730/4372/20294 3729/4370/20295 -f 3731/4374/20296 3729/4370/20297 3730/4372/20298 -f 3730/4372/20299 3732/4373/20300 3731/4374/20301 -f 3597/4236/20302 3733/4376/20303 3730/4375/20304 -f 3730/4375/20305 3601/4237/20306 3597/4236/20307 -f 3734/4377/20308 3732/4378/20309 3730/4375/20310 -f 3730/4375/20311 3733/4376/20312 3734/4377/20313 -f 3734/4377/20314 3733/4376/20315 3736/4379/20316 -f 3736/4379/20317 3735/4380/20318 3734/4377/20319 -f 3737/4382/20320 3734/4377/20321 3735/4380/20322 -f 3735/4380/20323 3738/4381/20324 3737/4382/20325 -f 3740/4383/20326 3739/4384/20327 3735/4380/20328 -f 3735/4380/20329 3736/4379/20330 3740/4383/20331 -f 3741/4385/20332 3738/4381/20333 3735/4380/20334 -f 3735/4380/20335 3739/4384/20336 3741/4385/20337 -f 3741/4385/20338 3739/4384/20339 3743/4386/20340 -f 3743/4386/20341 3742/4387/20342 3741/4385/20343 -f 3745/4388/20344 3744/4389/20345 3742/4387/20346 -f 3742/4387/20347 3743/4386/20348 3745/4388/20349 -f 3747/4390/20350 3746/4391/20351 3742/4387/20352 -f 3742/4387/20353 3744/4389/20354 3747/4390/20355 -f 3747/4390/20356 3744/4389/20357 3749/4392/20358 -f 3749/4392/20359 3748/4393/20360 3747/4390/20361 -f 3748/4393/20362 3749/4392/20363 3751/4394/20364 -f 3751/4394/20365 3750/4395/20366 3748/4393/20367 -f 3753/4396/20368 3752/4397/20369 3750/4395/20370 -f 3750/4395/20371 3751/4394/20372 3753/4396/20373 -f 3748/4393/20374 3754/4399/20375 3755/4398/20376 -f 3755/4398/20377 3747/4390/20378 3748/4393/20379 -f 3748/4393/20380 3750/4395/20381 3756/4400/20382 -f 3756/4400/20383 3754/4399/20384 3748/4393/20385 -f 3756/4400/20386 3750/4395/20387 3752/4397/20388 -f 3752/4397/20389 3757/4401/20390 3756/4400/20391 -f 3759/4403/20392 3758/4404/20393 3760/4402/20394 -f 3760/4402/20395 3746/4391/20396 3759/4403/20397 -f 3759/4403/20398 3746/4391/20399 3747/4390/20400 -f 3747/4390/20401 3755/4398/20402 3759/4403/20403 -f 3741/4385/20404 3742/4387/20405 3746/4391/20406 -f 3746/4391/20407 3760/4402/20408 3741/4385/20409 -f 3741/4385/20410 3760/4402/20411 3761/4405/20412 -f 3761/4405/20413 3738/4381/20414 3741/4385/20415 -f 3738/4381/20416 3761/4405/20417 3762/4406/20418 -f 3762/4406/20419 3737/4382/20420 3738/4381/20421 -f 3732/4378/20422 3734/4377/20423 3737/4382/20424 -f 3737/4382/20425 3763/4407/20426 3732/4378/20427 -f 3732/4373/20428 3763/4409/20429 3764/4408/20430 -f 3764/4408/20431 3731/4374/20432 3732/4373/20433 -f 3765/4410/20434 3673/4311/20435 3731/4374/20436 -f 3731/4374/20437 3764/4408/20438 3765/4410/20439 -f 3674/4310/20440 3729/4370/20441 3731/4374/20442 -f 3731/4374/20443 3673/4311/20444 3674/4310/20445 -f 3766/4411/20446 3672/4312/20447 3673/4311/20448 -f 3673/4311/20449 3765/4410/20450 3766/4411/20451 -f 3767/4412/20452 3661/4298/20453 3672/4312/20454 -f 3672/4312/20455 3766/4411/20456 3767/4412/20457 -f 3658/4297/20458 3675/4309/20459 3672/4312/20460 -f 3672/4312/20461 3661/4298/20462 3658/4297/20463 -f 3658/4297/20464 3662/4300/20465 3675/4309/20466 -f 3612/4250/20467 3661/4298/20468 3767/4412/20469 -f 3767/4412/20470 3614/4251/20471 3612/4250/20472 -f 3769/4413/20473 3768/4414/20474 3766/4411/20475 -f 3766/4411/20476 3765/4410/20477 3769/4413/20478 -f 3769/4413/20479 3765/4410/20480 3764/4408/20481 -f 3764/4408/20482 3770/4415/20483 3769/4413/20484 -f 3770/4415/20485 3764/4408/20486 3763/4409/20487 -f 3763/4409/20488 3771/4416/20489 3770/4415/20490 -f 3737/4382/20491 3762/4406/20492 3771/4417/20493 -f 3771/4417/20494 3763/4407/20495 3737/4382/20496 -f 3762/4406/20497 3772/4419/20498 3773/4418/20499 -f 3773/4418/20500 3771/4417/20501 3762/4406/20502 -f 3762/4406/20503 3761/4405/20504 3774/4420/20505 -f 3774/4420/20506 3772/4419/20507 3762/4406/20508 -f 3761/4405/20509 3760/4402/20510 3758/4404/20511 -f 3758/4404/20512 3774/4420/20513 3761/4405/20514 -f 3773/4421/20515 3775/4422/20516 3770/4415/20517 -f 3770/4415/20518 3771/4416/20519 3773/4421/20520 -f 3775/4422/20521 3776/4423/20522 3769/4413/20523 -f 3769/4413/20524 3770/4415/20525 3775/4422/20526 -f 3769/4413/20527 3776/4423/20528 3777/4424/20529 -f 3777/4424/20530 3768/4414/20531 3769/4413/20532 -f 3767/4412/20533 3766/4411/20534 3768/4414/20535 -f 3768/4414/20536 3778/4425/20537 3767/4412/20538 -f 3767/4412/20539 3778/4425/20540 3779/4426/20541 -f 3779/4426/20542 3614/4251/20543 3767/4412/20544 -f 3610/4246/20545 3614/4251/20546 3779/4426/20547 -f 3779/4426/20548 3632/4268/20549 3610/4246/20550 -f 3779/4426/20551 3780/4428/20552 3781/4427/20553 -f 3781/4427/20554 3632/4268/20555 3779/4426/20556 -f 3779/4426/20557 3778/4425/20558 3782/4429/20559 -f 3782/4429/20560 3780/4428/20561 3779/4426/20562 -f 3782/4429/20563 3778/4425/20564 3768/4414/20565 -f 3768/4414/20566 3777/4424/20567 3782/4429/20568 -f 3784/4430/20569 3783/4431/20570 3649/4285/20571 -f 3649/4285/20572 3631/4269/20573 3784/4430/20574 -f 3784/4430/20575 3631/4269/20576 3632/4268/20577 -f 3632/4268/20578 3781/4427/20579 3784/4430/20580 -f 3649/4285/20581 3783/4431/20582 3786/4432/20583 -f 3786/4432/20584 3785/4433/20585 3649/4285/20586 -f 3785/4433/20587 3648/4286/20588 3649/4285/20589 -f 3630/4270/20590 3631/4269/20591 3649/4285/20592 -f 3649/4285/20593 3650/4284/20594 3630/4270/20595 -f 3648/4286/20596 3785/4433/20597 3788/4434/20598 -f 3788/4434/20599 3787/4435/20600 3648/4286/20601 -f 3789/4436/20602 3647/4287/20603 3648/4286/20604 -f 3648/4286/20605 3787/4435/20606 3789/4436/20607 -f 3789/4436/20608 3787/4435/20609 3790/4437/20610 -f 3790/4437/20611 3569/4438/20612 3789/4436/20613 -f 3789/4436/20614 3569/4438/20615 3564/4219/20616 -f 3564/4219/20617 3586/4218/20618 3789/4436/20619 -f 3789/4436/20620 3586/4218/20621 3652/4288/20622 -f 3652/4288/20623 3647/4287/20624 3789/4436/20625 -f 3569/4199/20626 3790/4440/20627 3791/4439/20628 -f 3791/4439/20629 3570/4198/20630 3569/4199/20631 -f 3570/4198/20632 3791/4439/20633 3793/4441/20634 -f 3793/4441/20635 3792/4442/20636 3570/4198/20637 -f 3795/4443/20638 3794/4444/20639 3792/4442/20640 -f 3792/4442/20641 3793/4441/20642 3795/4443/20643 -f 3792/4442/20644 3794/4444/20645 3797/4445/20646 -f 3797/4445/20647 3796/4446/20648 3792/4442/20649 -f 3792/4442/20650 3796/4446/20651 3563/4195/20652 -f 3563/4195/20653 3570/4198/20654 3792/4442/20655 -f 3796/4446/20656 3797/4445/20657 3799/4447/20658 -f 3799/4447/20659 3798/4448/20660 3796/4446/20661 -f 3796/4446/20662 3798/4448/20663 3566/4192/20664 -f 3566/4192/20665 3563/4195/20666 3796/4446/20667 -f 3798/4448/20668 3799/4447/20669 3801/4449/20670 -f 3801/4449/20671 3800/4450/20672 3798/4448/20673 -f 3798/4448/20674 3800/4450/20675 3802/4451/20676 -f 3802/4451/20677 3566/4192/20678 3798/4448/20679 -f 3802/4451/20680 3800/4450/20681 3536/4162/20682 -f 3536/4162/20683 3537/4161/20684 3802/4451/20685 -f 3802/4451/20686 3537/4161/20687 3804/4452/20688 -f 3804/4452/20689 3803/4453/20690 3802/4451/20691 -f 3802/4451/20692 3803/4453/20693 3565/4193/20694 -f 3565/4193/20695 3566/4192/20696 3802/4451/20697 -f 3803/4453/20698 3804/4452/20699 3806/4454/20700 -f 3806/4454/20701 3805/4455/20702 3803/4453/20703 -f 3803/4453/20704 3805/4455/20705 3568/4196/20706 -f 3568/4196/20707 3565/4193/20708 3803/4453/20709 -f 3805/4456/20710 3806/4457/20711 3637/4273/20712 -f 3637/4273/20713 3617/4252/20714 3805/4456/20715 -f 3805/4456/20716 3617/4252/20717 3585/4214/20718 -f 3585/4214/20719 3568/4217/20720 3805/4456/20721 -f 3806/4457/20722 3807/4459/20723 3808/4458/20724 -f 3808/4458/20725 3637/4273/20726 3806/4457/20727 -f 3806/4454/20728 3804/4452/20729 3809/4460/20730 -f 3809/4460/20731 3807/4461/20732 3806/4454/20733 -f 3809/4460/20734 3810/4463/20735 3811/4462/20736 -f 3811/4462/20737 3807/4461/20738 3809/4460/20739 -f 3809/4460/20740 3804/4452/20741 3537/4161/20742 -f 3537/4161/20743 3538/4163/20744 3809/4460/20745 -f 3809/4460/20746 3538/4163/20747 3812/4464/20748 -f 3812/4464/20749 3810/4463/20750 3809/4460/20751 -f 3812/4464/20752 3813/4466/20753 3814/4465/20754 -f 3814/4465/20755 3810/4463/20756 3812/4464/20757 -f 3812/4464/20758 3538/4163/20759 3534/4158/20760 -f 3534/4158/20761 3815/4467/20762 3812/4464/20763 -f 3812/4464/20764 3815/4467/20765 3816/4468/20766 -f 3816/4468/20767 3813/4466/20768 3812/4464/20769 -f 3816/4468/20770 3817/4470/20771 3818/4469/20772 -f 3818/4469/20773 3813/4466/20774 3816/4468/20775 -f 3816/4468/20776 3815/4467/20777 3820/4471/20778 -f 3820/4471/20779 3819/4472/20780 3816/4468/20781 -f 3816/4468/20782 3819/4472/20783 3821/4473/20784 -f 3821/4473/20785 3817/4470/20786 3816/4468/20787 -f 3821/4473/20788 3572/4201/20789 3573/4200/20790 -f 3573/4200/20791 3817/4470/20792 3821/4473/20793 -f 3821/4473/20794 3819/4472/20795 3822/4474/20796 -f 3822/4474/20797 3583/4213/20798 3821/4473/20799 -f 3821/4473/20800 3583/4213/20801 3576/4205/20802 -f 3576/4205/20803 3572/4201/20804 3821/4473/20805 -f 3822/4474/20806 3819/4472/20807 3820/4471/20808 -f 3820/4471/20809 3823/4475/20810 3822/4474/20811 -f 3824/4476/20812 3605/4242/20813 3596/4233/20814 -f 3824/4476/20815 3825/4479/20816 3827/4477/20817 -f 3827/4477/20818 3826/4478/20819 3824/4476/20820 -f 3824/4476/20821 3826/4478/20822 3606/4243/20823 -f 3606/4243/20824 3605/4242/20825 3824/4476/20826 -f 3826/4478/20827 3827/4477/20828 3829/4480/20829 -f 3829/4480/20830 3828/4481/20831 3826/4478/20832 -f 3826/4478/20833 3828/4481/20834 3607/4244/20835 -f 3607/4244/20836 3606/4243/20837 3826/4478/20838 -f 3828/4481/20839 3829/4480/20840 3830/4482/20841 -f 3830/4482/20842 3590/4223/20843 3828/4481/20844 -f 3828/4481/20845 3590/4223/20846 3591/4227/20847 -f 3591/4227/20848 3607/4244/20849 3828/4481/20850 -f 3830/4482/20851 3829/4480/20852 3832/4483/20853 -f 3832/4483/20854 3831/4484/20855 3830/4482/20856 -f 3830/4482/20857 3831/4484/20858 3833/4485/20859 -f 3833/4485/20860 3589/4224/20861 3830/4482/20862 -f 3830/4482/20863 3589/4224/20864 3590/4223/20865 -f 3833/4485/20866 3831/4484/20867 3835/4486/20868 -f 3835/4486/20869 3834/4487/20870 3833/4485/20871 -f 3833/4485/20872 3834/4487/20873 3836/4488/20874 -f 3836/4488/20875 3582/4209/20876 3833/4485/20877 -f 3833/4485/20878 3582/4209/20879 3580/4212/20880 -f 3580/4212/20881 3589/4224/20882 3833/4485/20883 -f 3836/4488/20884 3834/4487/20885 3837/4489/20886 -f 3837/4489/20887 3808/4458/20888 3836/4488/20889 -f 3836/4488/20890 3808/4458/20891 3807/4459/20892 -f 3807/4459/20893 3811/4490/20894 3836/4488/20895 -f 3836/4488/20896 3811/4490/20897 3581/4210/20898 -f 3581/4210/20899 3582/4209/20900 3836/4488/20901 -f 3837/4489/20902 3834/4487/20903 3835/4486/20904 -f 3835/4486/20905 3838/4491/20906 3837/4489/20907 -f 3837/4489/20908 3838/4491/20909 3839/4492/20910 -f 3839/4492/20911 3636/4274/20912 3837/4489/20913 -f 3837/4489/20914 3636/4274/20915 3637/4273/20916 -f 3637/4273/20917 3808/4458/20918 3837/4489/20919 -f 3839/4492/20920 3838/4491/20921 3840/4493/20922 -f 3840/4493/20923 3625/4261/20924 3839/4492/20925 -f 3839/4492/20926 3625/4261/20927 3626/4260/20928 -f 3626/4260/20929 3638/4276/20930 3839/4492/20931 -f 3839/4492/20932 3638/4276/20933 3616/4253/20934 -f 3616/4253/20935 3636/4274/20936 3839/4492/20937 -f 3840/4493/20938 3841/4496/20939 3843/4494/20940 -f 3843/4494/20941 3842/4495/20942 3840/4493/20943 -f 3840/4493/20944 3842/4495/20945 3629/4266/20946 -f 3629/4266/20947 3625/4261/20948 3840/4493/20949 -f 3840/4493/20950 3838/4491/20951 3835/4486/20952 -f 3835/4486/20953 3841/4496/20954 3840/4493/20955 -f 3842/4495/20956 3843/4494/20957 3845/4497/20958 -f 3845/4497/20959 3844/4498/20960 3842/4495/20961 -f 3842/4495/20962 3844/4498/20963 3846/4499/20964 -f 3846/4499/20965 3629/4266/20966 3842/4495/20967 -f 3846/4499/20968 3847/4500/20969 3628/4264/20970 -f 3628/4264/20971 3629/4266/20972 3846/4499/20973 -f 3845/4497/20974 3843/4494/20975 3849/4501/20976 -f 3849/4501/20977 3848/4502/20978 3845/4497/20979 -f 3849/4501/20980 3827/4477/20981 3825/4479/20982 -f 3825/4479/20983 3848/4502/20984 3849/4501/20985 -f 3849/4501/20986 3843/4494/20987 3841/4496/20988 -f 3841/4496/20989 3832/4483/20990 3849/4501/20991 -f 3849/4501/20992 3832/4483/20993 3829/4480/20994 -f 3829/4480/20995 3827/4477/20996 3849/4501/20997 -f 3841/4496/20998 3835/4486/20999 3831/4484/21000 -f 3831/4484/21001 3832/4483/21002 3841/4496/21003 -f 3850/4504/21004 3823/4475/21005 3820/4471/21006 -f 3820/4471/21007 3851/4503/21008 3850/4504/21009 -f 3850/4504/21010 3851/4503/21011 3540/4166/21012 -f 3540/4166/21013 3543/4169/21014 3850/4504/21015 -f 3851/4503/21016 3820/4471/21017 3815/4467/21018 -f 3815/4467/21019 3534/4158/21020 3851/4503/21021 -f 3851/4503/21022 3534/4158/21023 3535/4157/21024 -f 3535/4157/21025 3540/4166/21026 3851/4503/21027 -f 3818/4469/21028 3575/4203/21029 3578/4208/21030 -f 3818/4469/21031 3578/4208/21032 3814/4465/21033 -f 3814/4465/21034 3813/4466/21035 3818/4469/21036 -f 3818/4469/21037 3817/4470/21038 3573/4200/21039 -f 3573/4200/21040 3575/4203/21041 3818/4469/21042 -f 3814/4465/21043 3578/4208/21044 3579/4207/21045 -f 3579/4207/21046 3581/4505/21047 3814/4465/21048 -f 3814/4465/21049 3581/4505/21050 3811/4462/21051 -f 3811/4462/21052 3810/4463/21053 3814/4465/21054 -f 3799/4447/21055 3797/4445/21056 3518/4144/21057 -f 3518/4144/21058 3519/4143/21059 3799/4447/21060 -f 3799/4447/21061 3519/4143/21062 3530/4154/21063 -f 3530/4154/21064 3801/4449/21065 3799/4447/21066 -f 3797/4445/21067 3794/4444/21068 3520/4145/21069 -f 3520/4145/21070 3518/4144/21071 3797/4445/21072 -f 3520/4145/21073 3794/4444/21074 3494/4115/21075 -f 3494/4115/21076 3491/4118/21077 3520/4145/21078 -f 3791/4439/21079 3852/4507/21080 3853/4506/21081 -f 3853/4506/21082 3793/4441/21083 3791/4439/21084 -f 3852/4507/21085 3791/4439/21086 3855/4508/21087 -f 3855/4508/21088 3854/4509/21089 3852/4507/21090 -f 3857/4512/21091 3856/4513/21092 3859/4510/21093 -f 3859/4510/21094 3858/4511/21095 3857/4512/21096 -f 3857/4512/21097 3860/4515/21098 3861/4514/21099 -f 3861/4514/21100 3856/4513/21101 3857/4512/21102 -f 3862/4517/21103 3856/4513/21104 3861/4514/21105 -f 3861/4514/21106 3863/4516/21107 3862/4517/21108 -f 3861/4514/21109 3860/4515/21110 3757/4401/21111 -f 3757/4401/21112 3752/4397/21113 3861/4514/21114 -f 3859/4510/21115 3856/4513/21116 3862/4517/21117 -f 3862/4517/21118 3506/4131/21119 3859/4510/21120 -f 3863/4516/21121 3861/4514/21122 3752/4397/21123 -f 3752/4397/21124 3753/4396/21125 3863/4516/21126 -f 3864/4519/21127 3753/4396/21128 3751/4394/21129 -f 3751/4394/21130 3865/4518/21131 3864/4519/21132 -f 3866/4520/21133 3865/4518/21134 3751/4394/21135 -f 3751/4394/21136 3749/4392/21137 3866/4520/21138 -f 3866/4520/21139 3749/4392/21140 3744/4389/21141 -f 3744/4389/21142 3745/4388/21143 3866/4520/21144 -f 3460/4084/21145 3864/4519/21146 3865/4518/21147 -f 3865/4518/21148 3459/4080/21149 3460/4084/21150 -f 3458/4081/21151 3459/4080/21152 3865/4518/21153 -f 3865/4518/21154 3866/4520/21155 3458/4081/21156 -f 3458/4081/21157 3866/4520/21158 3745/4388/21159 -f 3745/4388/21160 3867/4521/21161 3458/4081/21162 -f 3868/4522/21163 3457/4082/21164 3458/4081/21165 -f 3458/4081/21166 3867/4521/21167 3868/4522/21168 -f 3868/4522/21169 3867/4521/21170 3870/4523/21171 -f 3870/4523/21172 3869/4524/21173 3868/4522/21174 -f 3871/4525/21175 3440/4062/21176 3868/4522/21177 -f 3868/4522/21178 3869/4524/21179 3871/4525/21180 -f 3436/4059/21181 3457/4082/21182 3868/4522/21183 -f 3868/4522/21184 3440/4062/21185 3436/4059/21186 -f 3445/4067/21187 3457/4082/21188 3436/4059/21189 -f 3436/4059/21190 3431/4054/21191 3445/4067/21192 -f 3423/4047/21193 3445/4067/21194 3431/4054/21195 -f 3431/4054/21196 3419/4045/21197 3423/4047/21198 -f 3873/4526/21199 3872/4527/21200 3871/4525/21201 -f 3871/4525/21202 3869/4524/21203 3873/4526/21204 -f 3871/4525/21205 3872/4527/21206 3875/4528/21207 -f 3875/4528/21208 3874/4529/21209 3871/4525/21210 -f 3871/4525/21211 3874/4529/21212 3439/4063/21213 -f 3439/4063/21214 3440/4062/21215 3871/4525/21216 -f 3874/4529/21217 3875/4528/21218 3877/4530/21219 -f 3877/4530/21220 3876/4531/21221 3874/4529/21222 -f 3874/4529/21223 3876/4531/21224 3441/4064/21225 -f 3441/4064/21226 3439/4063/21227 3874/4529/21228 -f 3876/4531/21229 3877/4530/21230 3467/4532/21231 -f 3467/4532/21232 3878/4533/21233 3876/4531/21234 -f 3876/4531/21235 3878/4533/21236 3879/4534/21237 -f 3879/4534/21238 3441/4064/21239 3876/4531/21240 -f 3416/4039/21241 3415/4038/21242 3879/4535/21243 -f 3879/4535/21244 3878/4536/21245 3416/4039/21246 -f 3879/4534/21247 3880/4537/21248 3437/4061/21249 -f 3437/4061/21250 3441/4064/21251 3879/4534/21252 -f 3880/4537/21253 3881/4538/21254 3438/4060/21255 -f 3438/4060/21256 3437/4061/21257 3880/4537/21258 -f 3881/4538/21259 3882/4540/21260 3883/4539/21261 -f 3883/4539/21262 3438/4060/21263 3881/4538/21264 -f 3883/4539/21265 3882/4540/21266 3885/4541/21267 -f 3885/4541/21268 3884/4542/21269 3883/4539/21270 -f 3883/4539/21271 3884/4542/21272 3887/4543/21273 -f 3887/4543/21274 3886/4544/21275 3883/4539/21276 -f 3883/4539/21277 3886/4544/21278 3434/4058/21279 -f 3434/4058/21280 3438/4060/21281 3883/4539/21282 -f 3886/4544/21283 3887/4543/21284 3888/4545/21285 -f 3888/4545/21286 3456/4079/21287 3886/4544/21288 -f 3886/4544/21289 3456/4079/21290 3430/4051/21291 -f 3430/4051/21292 3434/4058/21293 3886/4544/21294 -f 3888/4545/21295 3887/4543/21296 3890/4546/21297 -f 3890/4546/21298 3889/4547/21299 3888/4545/21300 -f 3888/4545/21301 3889/4547/21302 3892/4548/21303 -f 3892/4548/21304 3891/4549/21305 3888/4545/21306 -f 3888/4545/21307 3891/4549/21308 3455/4077/21309 -f 3455/4077/21310 3456/4079/21311 3888/4545/21312 -f 3891/4549/21313 3892/4548/21314 3562/4191/21315 -f 3562/4191/21316 3558/4186/21317 3891/4549/21318 -f 3891/4549/21319 3558/4186/21320 3893/4550/21321 -f 3893/4550/21322 3455/4077/21323 3891/4549/21324 -f 3893/4550/21325 3513/4138/21326 3454/4078/21327 -f 3454/4078/21328 3455/4077/21329 3893/4550/21330 -f 3893/4550/21331 3558/4186/21332 3559/4185/21333 -f 3559/4185/21334 3894/4551/21335 3893/4550/21336 -f 3893/4550/21337 3894/4551/21338 3512/4136/21339 -f 3512/4136/21340 3513/4138/21341 3893/4550/21342 -f 3894/4551/21343 3895/4553/21344 3896/4552/21345 -f 3896/4552/21346 3512/4136/21347 3894/4551/21348 -f 3894/4551/21349 3559/4185/21350 3897/4554/21351 -f 3897/4554/21352 3895/4553/21353 3894/4551/21354 -f 3897/4554/21355 3898/4556/21356 3899/4555/21357 -f 3899/4555/21358 3895/4553/21359 3897/4554/21360 -f 3897/4554/21361 3559/4185/21362 3556/4188/21363 -f 3556/4188/21364 3900/4557/21365 3897/4554/21366 -f 3897/4554/21367 3900/4557/21368 3901/4558/21369 -f 3901/4558/21370 3898/4556/21371 3897/4554/21372 -f 3901/4558/21373 3902/4560/21374 3903/4559/21375 -f 3903/4559/21376 3898/4556/21377 3901/4558/21378 -f 3901/4558/21379 3900/4557/21380 3905/4561/21381 -f 3905/4561/21382 3904/4562/21383 3901/4558/21384 -f 3901/4558/21385 3904/4562/21386 3906/4563/21387 -f 3906/4563/21388 3902/4560/21389 3901/4558/21390 -f 3906/4563/21391 3907/4565/21392 3908/4564/21393 -f 3908/4564/21394 3902/4560/21395 3906/4563/21396 -f 3906/4563/21397 3904/4562/21398 3910/4566/21399 -f 3910/4566/21400 3909/4567/21401 3906/4563/21402 -f 3906/4563/21403 3909/4567/21404 3911/4568/21405 -f 3911/4568/21406 3907/4565/21407 3906/4563/21408 -f 3911/4568/21409 3626/4260/21410 3623/4263/21411 -f 3623/4263/21412 3907/4565/21413 3911/4568/21414 -f 3911/4568/21415 3909/4567/21416 3912/4569/21417 -f 3912/4569/21418 3639/4275/21419 3911/4568/21420 -f 3911/4568/21421 3639/4275/21422 3638/4276/21423 -f 3638/4276/21424 3626/4260/21425 3911/4568/21426 -f 3912/4569/21427 3909/4567/21428 3910/4566/21429 -f 3910/4566/21430 3913/4570/21431 3912/4569/21432 -f 3912/4569/21433 3913/4570/21434 3643/4282/21435 -f 3643/4282/21436 3914/4571/21437 3912/4569/21438 -f 3912/4569/21439 3914/4571/21440 3619/4255/21441 -f 3619/4255/21442 3639/4275/21443 3912/4569/21444 -f 3914/4571/21445 3643/4282/21446 3641/4279/21447 -f 3641/4279/21448 3915/4572/21449 3914/4571/21450 -f 3914/4571/21451 3915/4572/21452 3618/4256/21453 -f 3618/4256/21454 3619/4255/21455 3914/4571/21456 -f 3913/4570/21457 3910/4566/21458 3917/4573/21459 -f 3917/4573/21460 3916/4574/21461 3913/4570/21462 -f 3913/4570/21463 3916/4574/21464 3645/4280/21465 -f 3645/4280/21466 3643/4282/21467 3913/4570/21468 -f 3916/4574/21469 3917/4573/21470 3919/4575/21471 -f 3919/4575/21472 3918/4576/21473 3916/4574/21474 -f 3918/4576/21475 3921/4577/21476 3920/4578/21477 -f 3916/4574/21478 3918/4576/21479 3920/4578/21480 -f 3920/4578/21481 3645/4280/21482 3916/4574/21483 -f 3920/4578/21484 3921/4577/21485 3922/4579/21486 -f 3920/4578/21487 3922/4579/21488 3924/4580/21489 -f 3924/4580/21490 3923/4581/21491 3920/4578/21492 -f 3920/4578/21493 3923/4581/21494 3644/4281/21495 -f 3644/4281/21496 3645/4280/21497 3920/4578/21498 -f 3923/4581/21499 3924/4580/21500 3926/4582/21501 -f 3926/4582/21502 3925/4583/21503 3923/4581/21504 -f 3923/4581/21505 3925/4583/21506 3646/4283/21507 -f 3646/4283/21508 3644/4281/21509 3923/4581/21510 -f 3925/4583/21511 3926/4582/21512 3928/4584/21513 -f 3928/4584/21514 3927/4585/21515 3925/4583/21516 -f 3925/4583/21517 3927/4585/21518 3929/4586/21519 -f 3929/4586/21520 3646/4283/21521 3925/4583/21522 -f 3929/4586/21523 3930/4587/21524 3642/4278/21525 -f 3642/4278/21526 3646/4283/21527 3929/4586/21528 -f 3929/4586/21529 3927/4585/21530 3714/4356/21531 -f 3714/4356/21532 3719/4361/21533 3929/4586/21534 -f 3929/4586/21535 3719/4361/21536 3931/4588/21537 -f 3931/4588/21538 3930/4587/21539 3929/4586/21540 -f 3931/4588/21541 3659/4296/21542 3660/4295/21543 -f 3660/4295/21544 3930/4587/21545 3931/4588/21546 -f 3931/4588/21547 3719/4361/21548 3720/4360/21549 -f 3720/4360/21550 3932/4589/21551 3931/4588/21552 -f 3931/4588/21553 3932/4589/21554 3663/4299/21555 -f 3663/4299/21556 3659/4296/21557 3931/4588/21558 -f 3932/4589/21559 3720/4360/21560 3724/4365/21561 -f 3724/4365/21562 3722/4364/21563 3932/4589/21564 -f 3932/4589/21565 3722/4364/21566 3721/4362/21567 -f 3721/4362/21568 3663/4299/21569 3932/4589/21570 -f 3930/4587/21571 3660/4295/21572 3640/4277/21573 -f 3640/4277/21574 3642/4278/21575 3930/4587/21576 -f 3927/4585/21577 3928/4584/21578 3713/4357/21579 -f 3713/4357/21580 3714/4356/21581 3927/4585/21582 -f 3933/4590/21583 3921/4577/21584 3918/4576/21585 -f 3933/4590/21586 3918/4576/21587 3935/4591/21588 -f 3935/4591/21589 3934/4592/21590 3933/4590/21591 -f 3934/4592/21592 3935/4591/21593 3937/4593/21594 -f 3937/4593/21595 3936/4594/21596 3934/4592/21597 -f 3937/4593/21598 3935/4591/21599 3939/4595/21600 -f 3939/4595/21601 3938/4596/21602 3937/4593/21603 -f 3937/4593/21604 3938/4596/21605 3718/4358/21606 -f 3718/4358/21607 3715/4355/21608 3937/4593/21609 -f 3937/4593/21610 3715/4355/21611 3716/4354/21612 -f 3716/4354/21613 3936/4594/21614 3937/4593/21615 -f 3938/4596/21616 3939/4595/21617 3709/4351/21618 -f 3709/4351/21619 3710/4350/21620 3938/4596/21621 -f 3938/4596/21622 3710/4350/21623 3725/4367/21624 -f 3725/4367/21625 3718/4358/21626 3938/4596/21627 -f 3939/4595/21628 3918/4576/21629 3919/4575/21630 -f 3919/4575/21631 3709/4351/21632 3939/4595/21633 -f 3939/4595/21634 3935/4591/21635 3918/4576/21636 -f 3919/4575/21637 3917/4573/21638 3905/4561/21639 -f 3905/4561/21640 3560/4190/21641 3919/4575/21642 -f 3919/4575/21643 3560/4190/21644 3561/4189/21645 -f 3561/4189/21646 3709/4351/21647 3919/4575/21648 -f 3917/4573/21649 3910/4566/21650 3904/4562/21651 -f 3904/4562/21652 3905/4561/21653 3917/4573/21654 -f 3908/4564/21655 3627/4265/21656 3542/4164/21657 -f 3542/4164/21658 3940/4597/21659 3908/4564/21660 -f 3908/4564/21661 3940/4597/21662 3903/4559/21663 -f 3903/4559/21664 3902/4560/21665 3908/4564/21666 -f 3908/4564/21667 3907/4565/21668 3623/4263/21669 -f 3623/4263/21670 3627/4265/21671 3908/4564/21672 -f 3940/4597/21673 3542/4164/21674 3539/4167/21675 -f 3539/4167/21676 3941/4598/21677 3940/4597/21678 -f 3940/4597/21679 3941/4598/21680 3942/4599/21681 -f 3942/4599/21682 3903/4559/21683 3940/4597/21684 -f 3942/4599/21685 3941/4598/21686 3944/4600/21687 -f 3944/4600/21688 3943/4601/21689 3942/4599/21690 -f 3942/4599/21691 3943/4601/21692 3945/4602/21693 -f 3945/4602/21694 3899/4555/21695 3942/4599/21696 -f 3942/4599/21697 3899/4555/21698 3898/4556/21699 -f 3898/4556/21700 3903/4559/21701 3942/4599/21702 -f 3945/4602/21703 3943/4601/21704 3947/4603/21705 -f 3947/4603/21706 3946/4604/21707 3945/4602/21708 -f 3945/4602/21709 3946/4604/21710 3948/4605/21711 -f 3948/4605/21712 3896/4552/21713 3945/4602/21714 -f 3945/4602/21715 3896/4552/21716 3895/4553/21717 -f 3895/4553/21718 3899/4555/21719 3945/4602/21720 -f 3948/4605/21721 3946/4604/21722 3950/4606/21723 -f 3950/4606/21724 3949/4607/21725 3948/4605/21726 -f 3948/4605/21727 3949/4607/21728 3488/4110/21729 -f 3488/4110/21730 3511/4137/21731 3948/4605/21732 -f 3948/4605/21733 3511/4137/21734 3512/4136/21735 -f 3512/4136/21736 3896/4552/21737 3948/4605/21738 -f 3949/4607/21739 3950/4606/21740 3490/4113/21741 -f 3490/4113/21742 3489/4114/21743 3949/4607/21744 -f 3949/4607/21745 3489/4114/21746 3487/4111/21747 -f 3487/4111/21748 3488/4110/21749 3949/4607/21750 -f 3950/4606/21751 3951/4609/21752 3952/4608/21753 -f 3952/4608/21754 3490/4113/21755 3950/4606/21756 -f 3950/4606/21757 3946/4604/21758 3947/4603/21759 -f 3947/4603/21760 3951/4609/21761 3950/4606/21762 -f 3952/4608/21763 3953/4610/21764 3492/4117/21765 -f 3492/4117/21766 3478/4099/21767 3952/4608/21768 -f 3952/4608/21769 3478/4099/21770 3475/4102/21771 -f 3475/4102/21772 3490/4113/21773 3952/4608/21774 -f 3952/4608/21775 3951/4609/21776 3528/4150/21777 -f 3528/4150/21778 3953/4610/21779 3952/4608/21780 -f 3953/4610/21781 3954/4611/21782 3491/4118/21783 -f 3491/4118/21784 3492/4117/21785 3953/4610/21786 -f 3953/4610/21787 3528/4150/21788 3525/4153/21789 -f 3525/4153/21790 3954/4611/21791 3953/4610/21792 -f 3951/4609/21793 3947/4603/21794 3527/4151/21795 -f 3527/4151/21796 3528/4150/21797 3951/4609/21798 -f 3947/4603/21799 3943/4601/21800 3944/4600/21801 -f 3944/4600/21802 3527/4151/21803 3947/4603/21804 -f 3944/4600/21805 3545/4170/21806 3531/4156/21807 -f 3531/4156/21808 3527/4151/21809 3944/4600/21810 -f 3944/4600/21811 3941/4598/21812 3539/4167/21813 -f 3539/4167/21814 3545/4170/21815 3944/4600/21816 -f 3905/4561/21817 3900/4557/21818 3556/4188/21819 -f 3556/4188/21820 3560/4190/21821 3905/4561/21822 -f 3892/4548/21823 3889/4547/21824 3956/4612/21825 -f 3956/4612/21826 3955/4613/21827 3892/4548/21828 -f 3892/4548/21829 3955/4613/21830 3708/4349/21831 -f 3708/4349/21832 3562/4191/21833 3892/4548/21834 -f 3955/4613/21835 3956/4612/21836 3958/4614/21837 -f 3958/4614/21838 3957/4615/21839 3955/4613/21840 -f 3955/4613/21841 3957/4615/21842 3959/4616/21843 -f 3959/4616/21844 3708/4349/21845 3955/4613/21846 -f 3959/4616/21847 3957/4615/21848 3961/4617/21849 -f 3961/4617/21850 3960/4618/21851 3959/4616/21852 -f 3959/4616/21853 3960/4618/21854 3963/4619/21855 -f 3963/4619/21856 3962/4620/21857 3959/4616/21858 -f 3959/4616/21859 3962/4620/21860 3705/4348/21861 -f 3705/4348/21862 3708/4349/21863 3959/4616/21864 -f 3962/4620/21865 3963/4619/21866 3965/4621/21867 -f 3965/4621/21868 3964/4622/21869 3962/4620/21870 -f 3962/4620/21871 3964/4622/21872 3707/4346/21873 -f 3707/4346/21874 3705/4348/21875 3962/4620/21876 -f 3964/4622/21877 3965/4621/21878 3967/4623/21879 -f 3967/4623/21880 3966/4624/21881 3964/4622/21882 -f 3964/4622/21883 3966/4624/21884 3704/4344/21885 -f 3704/4344/21886 3707/4346/21887 3964/4622/21888 -f 3966/4624/21889 3967/4623/21890 3969/4625/21891 -f 3969/4625/21892 3968/4626/21893 3966/4624/21894 -f 3966/4624/21895 3968/4626/21896 3701/4341/21897 -f 3701/4341/21898 3704/4344/21899 3966/4624/21900 -f 3968/4626/21901 3969/4625/21902 3971/4627/21903 -f 3971/4627/21904 3970/4628/21905 3968/4626/21906 -f 3968/4626/21907 3970/4628/21908 3700/4342/21909 -f 3700/4342/21910 3701/4341/21911 3968/4626/21912 -f 3970/4628/21913 3971/4627/21914 3972/4629/21915 -f 3972/4629/21916 3604/4630/21917 3970/4628/21918 -f 3970/4628/21919 3604/4630/21920 3600/4631/21921 -f 3600/4631/21922 3700/4342/21923 3970/4628/21924 -f 3972/4634/21925 3971/4635/21926 3974/4632/21927 -f 3974/4632/21928 3973/4633/21929 3972/4634/21930 -f 3972/4634/21931 3973/4633/21932 3976/4636/21933 -f 3976/4636/21934 3975/4637/21935 3972/4634/21936 -f 3972/4638/21937 3975/4639/21938 3602/4240/21939 -f 3602/4240/21940 3604/4241/21941 3972/4638/21942 -f 3975/4637/21943 3976/4636/21944 3978/4640/21945 -f 3978/4640/21946 3977/4641/21947 3975/4637/21948 -f 3975/4639/21949 3977/4642/21950 3603/4239/21951 -f 3603/4239/21952 3602/4240/21953 3975/4639/21954 -f 3976/4636/21955 3973/4633/21956 3980/4643/21957 -f 3980/4643/21958 3979/4644/21959 3976/4636/21960 -f 3976/4636/21961 3979/4644/21962 3981/4645/21963 -f 3981/4645/21964 3978/4640/21965 3976/4636/21966 -f 3981/4645/21967 3979/4644/21968 3983/4646/21969 -f 3983/4646/21970 3982/4647/21971 3981/4645/21972 -f 3981/4650/21973 3982/4651/21974 3985/4648/21975 -f 3985/4648/21976 3984/4649/21977 3981/4650/21978 -f 3981/4650/21979 3984/4649/21980 3554/4184/21981 -f 3554/4184/21982 3978/4652/21983 3981/4650/21984 -f 3984/4649/21985 3985/4648/21986 3987/4653/21987 -f 3987/4653/21988 3986/4654/21989 3984/4649/21990 -f 3984/4649/21991 3986/4654/21992 3555/4181/21993 -f 3555/4181/21994 3554/4184/21995 3984/4649/21996 -f 3987/4653/21997 3985/4648/21998 3989/4655/21999 -f 3989/4655/22000 3988/4656/22001 3987/4653/22002 -f 3987/4653/22003 3988/4656/22004 3991/4657/22005 -f 3991/4657/22006 3990/4658/22007 3987/4653/22008 -f 3987/4653/22009 3990/4658/22010 3555/4181/22011 -f 3555/4181/22012 3986/4654/22013 3987/4653/22014 -f 3990/4658/22015 3991/4657/22016 3993/4659/22017 -f 3993/4659/22018 3992/4660/22019 3990/4658/22020 -f 3990/4658/22021 3992/4660/22022 3621/4259/22023 -f 3621/4259/22024 3555/4181/22025 3990/4658/22026 -f 3992/4660/22027 3993/4659/22028 3995/4661/22029 -f 3995/4661/22030 3994/4662/22031 3992/4660/22032 -f 3992/4660/22033 3994/4662/22034 3996/4663/22035 -f 3996/4663/22036 3621/4259/22037 3992/4660/22038 -f 3996/4663/22039 3997/4664/22040 3622/4258/22041 -f 3622/4258/22042 3621/4259/22043 3996/4663/22044 -f 3996/4663/22045 3994/4662/22046 3999/4665/22047 -f 3999/4665/22048 3998/4666/22049 3996/4663/22050 -f 3996/4663/22051 3998/4666/22052 4000/4667/22053 -f 4000/4667/22054 3997/4664/22055 3996/4663/22056 -f 4000/4669/22057 3960/4618/22058 3961/4617/22059 -f 3961/4617/22060 3997/4668/22061 4000/4669/22062 -f 4000/4667/22063 3998/4666/22064 4002/4670/22065 -f 4002/4670/22066 4001/4671/22067 4000/4667/22068 -f 4000/4669/22069 4001/4672/22070 3963/4619/22071 -f 3963/4619/22072 3960/4618/22073 4000/4669/22074 -f 4001/4671/22075 4002/4670/22076 4004/4673/22077 -f 4004/4673/22078 4003/4674/22079 4001/4671/22080 -f 4001/4672/22081 4003/4675/22082 3965/4621/22083 -f 3965/4621/22084 3963/4619/22085 4001/4672/22086 -f 4003/4674/22087 4004/4673/22088 4006/4676/22089 -f 4006/4676/22090 4005/4677/22091 4003/4674/22092 -f 4003/4675/22093 4005/4678/22094 3967/4623/22095 -f 3967/4623/22096 3965/4621/22097 4003/4675/22098 -f 4005/4677/22099 4006/4676/22100 4008/4679/22101 -f 4008/4679/22102 4007/4680/22103 4005/4677/22104 -f 4005/4678/22105 4007/4681/22106 3969/4625/22107 -f 3969/4625/22108 3967/4623/22109 4005/4678/22110 -f 4007/4680/22111 4008/4679/22112 4009/4682/22113 -f 4009/4682/22114 3974/4632/22115 4007/4680/22116 -f 4007/4681/22117 3974/4683/22118 3971/4627/22119 -f 3971/4627/22120 3969/4625/22121 4007/4681/22122 -f 4009/4682/22123 4008/4679/22124 4011/4684/22125 -f 4011/4684/22126 4010/4685/22127 4009/4682/22128 -f 4009/4682/22129 4010/4685/22130 4012/4686/22131 -f 4012/4686/22132 3980/4643/22133 4009/4682/22134 -f 4009/4682/22135 3980/4643/22136 3973/4633/22137 -f 3973/4633/22138 3974/4632/22139 4009/4682/22140 -f 4012/4686/22141 4010/4685/22142 4014/4687/22143 -f 4014/4687/22144 4013/4688/22145 4012/4686/22146 -f 4012/4686/22147 4013/4688/22148 4015/4689/22149 -f 4015/4689/22150 3983/4646/22151 4012/4686/22152 -f 4012/4686/22153 3983/4646/22154 3979/4644/22155 -f 3979/4644/22156 3980/4643/22157 4012/4686/22158 -f 4015/4689/22159 4013/4688/22160 4017/4690/22161 -f 4017/4690/22162 4016/4691/22163 4015/4689/22164 -f 4015/4689/22165 4016/4691/22166 4019/4692/22167 -f 4019/4692/22168 4018/4693/22169 4015/4689/22170 -f 4015/4689/22171 4018/4693/22172 3982/4647/22173 -f 3982/4647/22174 3983/4646/22175 4015/4689/22176 -f 4018/4695/22177 4019/4696/22178 4020/4694/22179 -f 4020/4694/22180 3989/4655/22181 4018/4695/22182 -f 4018/4695/22183 3989/4655/22184 3985/4648/22185 -f 3985/4648/22186 3982/4651/22187 4018/4695/22188 -f 4020/4694/22189 4019/4696/22190 4022/4697/22191 -f 4022/4697/22192 4021/4698/22193 4020/4694/22194 -f 4020/4694/22195 4021/4698/22196 4024/4699/22197 -f 4024/4699/22198 4023/4700/22199 4020/4694/22200 -f 4020/4694/22201 4023/4700/22202 3988/4656/22203 -f 3988/4656/22204 3989/4655/22205 4020/4694/22206 -f 4023/4700/22207 4024/4699/22208 4026/4701/22209 -f 4026/4701/22210 4025/4702/22211 4023/4700/22212 -f 4023/4700/22213 4025/4702/22214 3991/4657/22215 -f 3991/4657/22216 3988/4656/22217 4023/4700/22218 -f 4025/4702/22219 4026/4701/22220 3687/4325/22221 -f 3687/4325/22222 4027/4703/22223 4025/4702/22224 -f 4025/4702/22225 4027/4703/22226 3993/4659/22227 -f 3993/4659/22228 3991/4657/22229 4025/4702/22230 -f 4027/4703/22231 3687/4325/22232 3688/4324/22233 -f 3688/4324/22234 4028/4704/22235 4027/4703/22236 -f 4027/4703/22237 4028/4704/22238 3995/4661/22239 -f 3995/4661/22240 3993/4659/22241 4027/4703/22242 -f 4028/4704/22243 3688/4324/22244 3689/4326/22245 -f 3689/4326/22246 4029/4705/22247 4028/4704/22248 -f 4028/4704/22249 4029/4705/22250 4030/4706/22251 -f 4030/4706/22252 3995/4661/22253 4028/4704/22254 -f 4030/4706/22255 3999/4665/22256 3994/4662/22257 -f 3994/4662/22258 3995/4661/22259 4030/4706/22260 -f 4030/4706/22261 4029/4705/22262 4032/4707/22263 -f 4032/4707/22264 4031/4708/22265 4030/4706/22266 -f 4030/4706/22267 4031/4708/22268 4033/4709/22269 -f 4033/4709/22270 3999/4665/22271 4030/4706/22272 -f 4033/4709/22273 4002/4670/22274 3998/4666/22275 -f 3998/4666/22276 3999/4665/22277 4033/4709/22278 -f 4033/4709/22279 4031/4708/22280 4035/4710/22281 -f 4035/4710/22282 4034/4711/22283 4033/4709/22284 -f 4033/4709/22285 4034/4711/22286 4004/4673/22287 -f 4004/4673/22288 4002/4670/22289 4033/4709/22290 -f 4034/4711/22291 4035/4710/22292 4037/4712/22293 -f 4037/4712/22294 4036/4713/22295 4034/4711/22296 -f 4034/4711/22297 4036/4713/22298 4006/4676/22299 -f 4006/4676/22300 4004/4673/22301 4034/4711/22302 -f 4036/4713/22303 4037/4712/22304 4038/4714/22305 -f 4038/4714/22306 4011/4684/22307 4036/4713/22308 -f 4036/4713/22309 4011/4684/22310 4008/4679/22311 -f 4008/4679/22312 4006/4676/22313 4036/4713/22314 -f 4038/4714/22315 4037/4712/22316 4040/4715/22317 -f 4040/4715/22318 4039/4716/22319 4038/4714/22320 -f 4038/4714/22321 4039/4716/22322 4041/4717/22323 -f 4041/4717/22324 4014/4687/22325 4038/4714/22326 -f 4038/4714/22327 4014/4687/22328 4010/4685/22329 -f 4010/4685/22330 4011/4684/22331 4038/4714/22332 -f 4041/4717/22333 4039/4716/22334 4043/4718/22335 -f 4043/4718/22336 4042/4719/22337 4041/4717/22338 -f 4041/4717/22339 4042/4719/22340 4044/4720/22341 -f 4044/4720/22342 4017/4690/22343 4041/4717/22344 -f 4041/4717/22345 4017/4690/22346 4013/4688/22347 -f 4013/4688/22348 4014/4687/22349 4041/4717/22350 -f 3711/4353/22351 3712/4352/22352 4044/4720/22353 -f 4044/4720/22354 4042/4719/22355 3711/4353/22356 -f 3696/4333/22357 4045/4721/22358 4044/4720/22359 -f 4044/4720/22360 3712/4352/22361 3696/4333/22362 -f 4044/4720/22363 4045/4721/22364 4016/4691/22365 -f 4016/4691/22366 4017/4690/22367 4044/4720/22368 -f 3681/4336/22369 4022/4722/22370 4045/4721/22371 -f 4045/4721/22372 3696/4333/22373 3681/4336/22374 -f 4045/4721/22375 4022/4722/22376 4019/4692/22377 -f 4019/4692/22378 4016/4691/22379 4045/4721/22380 -f 4021/4698/22381 4022/4697/22382 3681/4318/22383 -f 3681/4318/22384 4046/4723/22385 4021/4698/22386 -f 4021/4698/22387 4046/4723/22388 3667/4301/22389 -f 3667/4301/22390 4024/4699/22391 4021/4698/22392 -f 4024/4699/22393 3667/4301/22394 3664/4304/22395 -f 3664/4304/22396 4026/4701/22397 4024/4699/22398 -f 4026/4701/22399 3664/4304/22400 3669/4305/22401 -f 3669/4305/22402 3687/4325/22403 4026/4701/22404 -f 3711/4353/22405 4042/4719/22406 4043/4718/22407 -f 4043/4718/22408 4047/4724/22409 3711/4353/22410 -f 4049/4725/22411 4048/4726/22412 4047/4724/22413 -f 4047/4724/22414 4043/4718/22415 4049/4725/22416 -f 4047/4724/22417 4048/4726/22418 4050/4727/22419 -f 4050/4727/22420 3697/4337/22421 4047/4724/22422 -f 4047/4724/22423 3697/4337/22424 3695/4334/22425 -f 3695/4334/22426 3711/4353/22427 4047/4724/22428 -f 4050/4727/22429 4048/4726/22430 3698/4339/22431 -f 3698/4339/22432 3692/4329/22433 4050/4727/22434 -f 4050/4727/22435 3692/4329/22436 3683/4330/22437 -f 3683/4330/22438 3686/4728/22439 4050/4727/22440 -f 4050/4727/22441 3686/4728/22442 3682/4338/22443 -f 3682/4338/22444 3697/4337/22445 4050/4727/22446 -f 4051/4729/22447 3698/4339/22448 4048/4726/22449 -f 4048/4726/22450 4049/4725/22451 4051/4729/22452 -f 3691/4327/22453 3698/4339/22454 4051/4729/22455 -f 4051/4729/22456 4052/4730/22457 3691/4327/22458 -f 4049/4725/22459 4040/4715/22460 4053/4731/22461 -f 4053/4731/22462 4051/4729/22463 4049/4725/22464 -f 4049/4725/22465 4043/4718/22466 4039/4716/22467 -f 4039/4716/22468 4040/4715/22469 4049/4725/22470 -f 4053/4731/22471 4035/4710/22472 4031/4708/22473 -f 4031/4708/22474 4032/4707/22475 4053/4731/22476 -f 4053/4731/22477 4032/4707/22478 4052/4730/22479 -f 4052/4730/22480 4051/4729/22481 4053/4731/22482 -f 4053/4731/22483 4040/4715/22484 4037/4712/22485 -f 4037/4712/22486 4035/4710/22487 4053/4731/22488 -f 3691/4327/22489 4052/4730/22490 3689/4326/22491 -f 3689/4326/22492 3684/4321/22493 3691/4327/22494 -f 4052/4730/22495 4032/4707/22496 4029/4705/22497 -f 4029/4705/22498 3689/4326/22499 4052/4730/22500 -f 3997/4668/22501 3961/4617/22502 4054/4732/22503 -f 4054/4732/22504 3622/4733/22505 3997/4668/22506 -f 4054/4732/22507 3958/4614/22508 3502/4127/22509 -f 3502/4127/22510 3553/4177/22511 4054/4732/22512 -f 4054/4732/22513 3553/4177/22514 3552/4180/22515 -f 3552/4180/22516 3622/4733/22517 4054/4732/22518 -f 4054/4732/22519 3961/4617/22520 3957/4615/22521 -f 3957/4615/22522 3958/4614/22523 4054/4732/22524 -f 3958/4614/22525 3956/4612/22526 3501/4125/22527 -f 3501/4125/22528 3502/4127/22529 3958/4614/22530 -f 3956/4612/22531 3889/4547/22532 3890/4546/22533 -f 3890/4546/22534 3501/4125/22535 3956/4612/22536 -f 3890/4546/22537 3887/4543/22538 3884/4542/22539 -f 3884/4542/22540 4055/4734/22541 3890/4546/22542 -f 3890/4546/22543 4055/4734/22544 3500/4126/22545 -f 3500/4126/22546 3501/4125/22547 3890/4546/22548 -f 4055/4734/22549 3884/4542/22550 3885/4541/22551 -f 3885/4541/22552 4056/4735/22553 4055/4734/22554 -f 4055/4734/22555 4056/4735/22556 4057/4736/22557 -f 4057/4736/22558 3500/4126/22559 4055/4734/22560 -f 4059/4739/22561 4058/4740/22562 4057/4737/22563 -f 4057/4737/22564 4060/4738/22565 4059/4739/22566 -f 4057/4736/22567 4058/4741/22568 3497/4124/22569 -f 3497/4124/22570 3500/4126/22571 4057/4736/22572 -f 3471/4094/22573 3473/4742/22574 4058/4740/22575 -f 4058/4740/22576 4059/4739/22577 3471/4094/22578 -f 4058/4741/22579 3473/4743/22580 3474/4121/22581 -f 3474/4121/22582 3497/4124/22583 4058/4741/22584 -f 3472/4744/22585 3473/4742/22586 3471/4094/22587 -f 3471/4094/22588 3469/4092/22589 3472/4744/22590 -f 3469/4092/22591 3462/4086/22592 3472/4744/22593 -f 4059/4739/22594 4060/4738/22595 4062/4745/22596 -f 4062/4745/22597 4061/4746/22598 4059/4739/22599 -f 4059/4739/22600 4061/4746/22601 3468/4093/22602 -f 3468/4093/22603 3471/4094/22604 4059/4739/22605 -f 4061/4746/22606 4062/4745/22607 4064/4747/22608 -f 4064/4747/22609 4063/4748/22610 4061/4746/22611 -f 4061/4746/22612 4063/4748/22613 3470/4091/22614 -f 3470/4091/22615 3468/4093/22616 4061/4746/22617 -f 4063/4748/22618 4064/4747/22619 3404/4029/22620 -f 3404/4029/22621 3405/4028/22622 4063/4748/22623 -f 4063/4748/22624 3405/4028/22625 3414/4037/22626 -f 3414/4037/22627 3470/4091/22628 4063/4748/22629 -f 3406/4027/22630 3407/4031/22631 3414/4037/22632 -f 3414/4037/22633 3405/4028/22634 3406/4027/22635 -f 3414/4037/22636 3412/4036/22637 3462/4086/22638 -f 3462/4086/22639 3470/4091/22640 3414/4037/22641 -f 3390/4014/22642 3393/4016/22643 3404/4029/22644 -f 3404/4029/22645 3397/4019/22646 3390/4014/22647 -f 3404/4029/22648 4064/4747/22649 4065/4749/22650 -f 4065/4749/22651 3397/4019/22652 3404/4029/22653 -f 4065/4749/22654 4066/4750/22655 3396/4020/22656 -f 3396/4020/22657 3397/4019/22658 4065/4749/22659 -f 4065/4749/22660 4064/4747/22661 4062/4745/22662 -f 4062/4745/22663 4067/4751/22664 4065/4749/22665 -f 4065/4749/22666 4067/4751/22667 4068/4752/22668 -f 4068/4752/22669 4066/4750/22670 4065/4749/22671 -f 4068/4752/22672 4069/4754/22673 4070/4753/22674 -f 4070/4753/22675 4066/4750/22676 4068/4752/22677 -f 4068/4752/22678 4067/4751/22679 4072/4755/22680 -f 4072/4755/22681 4071/4756/22682 4068/4752/22683 -f 4068/4752/22684 4071/4756/22685 4073/4757/22686 -f 4073/4757/22687 4069/4754/22688 4068/4752/22689 -f 4073/4757/22690 4074/4759/22691 4075/4758/22692 -f 4075/4758/22693 4069/4754/22694 4073/4757/22695 -f 3885/4760/22696 3882/4761/22697 4073/4757/22698 -f 4073/4757/22699 4071/4756/22700 3885/4760/22701 -f 3881/4762/22702 4074/4759/22703 4073/4757/22704 -f 4073/4757/22705 3882/4761/22706 3881/4762/22707 -f 4076/4764/22708 4074/4759/22709 3881/4762/22710 -f 3881/4762/22711 3880/4763/22712 4076/4764/22713 -f 4076/4764/22714 3415/4038/22715 3400/4022/22716 -f 3400/4022/22717 3401/4021/22718 4076/4764/22719 -f 4076/4764/22720 3401/4021/22721 4075/4758/22722 -f 4075/4758/22723 4074/4759/22724 4076/4764/22725 -f 3415/4038/22726 4076/4764/22727 3880/4763/22728 -f 3880/4763/22729 3879/4535/22730 3415/4038/22731 -f 3885/4760/22732 4071/4756/22733 4072/4755/22734 -f 4072/4755/22735 4056/4765/22736 3885/4760/22737 -f 4057/4737/22738 4056/4765/22739 4072/4755/22740 -f 4072/4755/22741 4060/4738/22742 4057/4737/22743 -f 4075/4758/22744 3401/4021/22745 3398/4024/22746 -f 3398/4024/22747 4077/4766/22748 4075/4758/22749 -f 4075/4758/22750 4077/4766/22751 4070/4753/22752 -f 4070/4753/22753 4069/4754/22754 4075/4758/22755 -f 4077/4766/22756 3398/4024/22757 3377/3999/22758 -f 3377/3999/22759 3372/3998/22760 4077/4766/22761 -f 4077/4766/22762 3372/3998/22763 3373/3997/22764 -f 3373/3997/22765 4070/4753/22766 4077/4766/22767 -f 3396/4020/22768 3373/3997/22769 3374/3996/22770 -f 3374/3996/22771 3394/4018/22772 3396/4020/22773 -f 3373/3997/22774 3396/4020/22775 4066/4750/22776 -f 4066/4750/22777 4070/4753/22778 3373/3997/22779 -f 3377/3999/22780 3398/4024/22781 3399/4023/22782 -f 3399/4023/22783 3380/4002/22784 3377/3999/22785 -f 4072/4755/22786 4067/4751/22787 4062/4745/22788 -f 4062/4745/22789 4060/4738/22790 4072/4755/22791 -f 3416/4039/22792 3878/4536/22793 3467/4767/22794 -f 3467/4767/22795 3464/4768/22796 3416/4039/22797 -f 3877/4530/22798 3875/4528/22799 3548/4172/22800 -f 3548/4172/22801 3549/4171/22802 3877/4530/22803 -f 3877/4530/22804 3549/4171/22805 4078/4769/22806 -f 4078/4769/22807 3467/4532/22808 3877/4530/22809 -f 3875/4528/22810 3872/4527/22811 3551/4175/22812 -f 3551/4175/22813 3548/4172/22814 3875/4528/22815 -f 3551/4175/22816 3872/4527/22817 3873/4526/22818 -f 3873/4526/22819 3598/4235/22820 3551/4175/22821 -f 3740/4383/22822 3736/4379/22823 3598/4235/22824 -f 3598/4235/22825 3873/4526/22826 3740/4383/22827 -f 3740/4383/22828 3873/4526/22829 3869/4524/22830 -f 3869/4524/22831 3870/4523/22832 3740/4383/22833 -f 3597/4236/22834 3598/4235/22835 3736/4379/22836 -f 3736/4379/22837 3733/4376/22838 3597/4236/22839 -f 3743/4386/22840 3739/4384/22841 3740/4383/22842 -f 3740/4383/22843 3870/4523/22844 3743/4386/22845 -f 3743/4386/22846 3870/4523/22847 3867/4521/22848 -f 3867/4521/22849 3745/4388/22850 3743/4386/22851 -f 3600/4631/22852 3601/4371/22853 3699/4343/22854 -f 3699/4343/22855 3700/4342/22856 3600/4631/22857 -f 3523/4149/22858 3864/4519/22859 3460/4084/22860 -f 3460/4084/22861 3521/4147/22862 3523/4149/22863 -f 3863/4516/22864 3753/4396/22865 3864/4519/22866 -f 3864/4519/22867 3523/4149/22868 3863/4516/22869 -f 3863/4516/22870 3523/4149/22871 3524/4148/22872 -f 3524/4148/22873 3862/4517/22874 3863/4516/22875 -f 3485/4106/22876 3487/4111/22877 3506/4131/22878 -f 3506/4131/22879 3484/4107/22880 3485/4106/22881 -f 3504/4129/22882 3505/4128/22883 4080/4770/22884 -f 4080/4770/22885 4079/4771/22886 3504/4129/22887 -f 3504/4129/22888 4079/4771/22889 3858/4511/22890 -f 3858/4511/22891 3859/4510/22892 3504/4129/22893 -f 4082/4773/22894 4081/4774/22895 4083/4772/22896 -f 4083/4772/22897 3795/4443/22898 4082/4773/22899 -f 4082/4773/22900 3795/4443/22901 3793/4441/22902 -f 3793/4441/22903 3853/4506/22904 4082/4773/22905 -f 4083/4772/22906 4081/4774/22907 4085/4775/22908 -f 4085/4775/22909 4084/4776/22910 4083/4772/22911 -f 3493/4116/22912 3494/4115/22913 4083/4772/22914 -f 4083/4772/22915 4084/4776/22916 3493/4116/22917 -f 3493/4116/22918 4084/4776/22919 4086/4777/22920 -f 4086/4777/22921 3496/4119/22922 3493/4116/22923 -f 3496/4119/22924 4086/4777/22925 3505/4128/22926 -f 3505/4128/22927 3495/4120/22928 3496/4119/22929 -f 4086/4777/22930 4084/4776/22931 4085/4775/22932 -f 4085/4775/22933 4087/4778/22934 4086/4777/22935 -f 4086/4777/22936 4087/4778/22937 4080/4770/22938 -f 4080/4770/22939 3505/4128/22940 4086/4777/22941 -f 4088/4780/22942 3854/4781/22943 3855/4779/22944 -f 3855/4779/22945 3788/4434/22946 4088/4780/22947 -f 4088/4780/22948 3788/4434/22949 3785/4433/22950 -f 3785/4433/22951 3786/4432/22952 4088/4780/22953 -f 3855/4508/22954 3791/4439/22955 3790/4440/22956 -f 3855/4779/22957 3790/4437/22958 3787/4435/22959 -f 3787/4435/22960 3788/4434/22961 3855/4779/22962 -f 3725/4367/22963 3710/4350/22964 3706/4347/22965 -f 3706/4347/22966 3703/4345/22967 3725/4367/22968 -f 3721/4362/22969 3693/4331/22970 3662/4300/22971 -f 3662/4300/22972 3663/4299/22973 3721/4362/22974 -f 3706/4347/22975 3707/4346/22976 3704/4344/22977 -f 3704/4344/22978 3703/4345/22979 3706/4347/22980 -f 3686/4323/22981 3670/4307/22982 3666/4302/22983 -f 3666/4302/22984 3682/4317/22985 3686/4323/22986 -f 3660/4295/22987 3613/4249/22988 3608/4248/22989 -f 3608/4248/22990 3640/4277/22991 3660/4295/22992 -f 3656/4292/22993 3615/4254/22994 3618/4256/22995 -f 3618/4256/22996 3657/4294/22997 3656/4292/22998 -f 3915/4572/22999 3641/4279/23000 3609/4247/23001 -f 3609/4247/23002 3634/4271/23003 3915/4572/23004 -f 3652/4288/23005 3586/4218/23006 3584/4215/23007 -f 3584/4215/23008 3620/4257/23009 3652/4288/23010 -f 3650/4284/23011 3653/4291/23012 3635/4272/23013 -f 3635/4272/23014 3630/4270/23015 3650/4284/23016 -f 3627/4265/23017 3628/4264/23018 3541/4165/23019 -f 3541/4165/23020 3542/4164/23021 3627/4265/23022 -f 3628/4264/23023 3847/4500/23024 3544/4168/23025 -f 3544/4168/23026 3541/4165/23027 3628/4264/23028 -f 3607/4244/23029 3591/4227/23030 3593/4228/23031 -f 3593/4228/23032 3594/4230/23033 3607/4244/23034 -f 3596/4233/23035 3592/4232/23036 3587/4222/23037 -f 3587/4222/23038 3824/4476/23039 3596/4233/23040 -f 3553/4177/23041 3502/4127/23042 3499/4122/23043 -f 3499/4122/23044 3546/4178/23045 3553/4177/23046 -f 3549/4171/23047 3546/4174/23048 3499/4782/23049 -f 3499/4782/23050 4078/4769/23051 3549/4171/23052 -f 3545/4170/23053 3535/4157/23054 3532/4160/23055 -f 3532/4160/23056 3531/4156/23057 3545/4170/23058 -f 3529/4155/23059 3516/4140/23060 3517/4139/23061 -f 3529/4155/23062 3517/4139/23063 3954/4611/23064 -f 3954/4611/23065 3525/4153/23066 3529/4155/23067 -f 3529/4155/23068 3530/4154/23069 3519/4143/23070 -f 3519/4143/23071 3516/4140/23072 3529/4155/23073 -f 3450/4070/23074 3482/4109/23075 3483/4108/23076 -f 3483/4108/23077 3461/4083/23078 3450/4070/23079 -f 3450/4070/23080 3461/4083/23081 4089/4783/23082 -f 4089/4783/23083 3449/4071/23084 3450/4070/23085 -f 3449/4071/23086 4089/4783/23087 3432/4056/23088 -f 3432/4056/23089 3433/4055/23090 3449/4071/23091 -f 3433/4055/23092 3427/4048/23093 3453/4076/23094 -f 3453/4076/23095 3449/4071/23096 3433/4055/23097 -f 3433/4055/23098 3421/4043/23099 3422/4042/23100 -f 3422/4042/23101 3427/4048/23102 3433/4055/23103 -f 4089/4783/23104 3461/4083/23105 3446/4069/23106 -f 3446/4069/23107 3443/4065/23108 4089/4783/23109 -f 4089/4783/23110 3443/4065/23111 3424/4046/23112 -f 3424/4046/23113 3432/4056/23114 4089/4783/23115 -f 4090/4784/23116 3482/4109/23117 3450/4070/23118 -f 3450/4070/23119 3447/4073/23120 4090/4784/23121 -f 4090/4784/23122 4091/4787/23123 4093/4785/23124 -f 4093/4785/23125 4092/4786/23126 4090/4784/23127 -f 4090/4784/23128 4092/4786/23129 3485/4106/23130 -f 3485/4106/23131 3482/4109/23132 4090/4784/23133 -f 3451/4075/23134 4091/4787/23135 4090/4784/23136 -f 4090/4784/23137 3447/4073/23138 3451/4075/23139 -f 4094/4789/23140 4091/4787/23141 3451/4075/23142 -f 3451/4075/23143 4095/4788/23144 4094/4789/23145 -f 4095/4788/23146 3451/4075/23147 3452/4074/23148 -f 3452/4074/23149 4096/4790/23150 4095/4788/23151 -f 4096/4790/23152 3452/4074/23153 4098/4791/23154 -f 4098/4791/23155 4097/4792/23156 4096/4790/23157 -f 4100/4793/23158 4099/4794/23159 4097/4792/23160 -f 4097/4792/23161 4098/4791/23162 4100/4793/23163 -f 4099/4794/23164 4100/4793/23165 4102/4795/23166 -f 4102/4795/23167 4101/4796/23168 4099/4794/23169 -f 4101/4796/23170 4102/4795/23171 4104/4797/23172 -f 4104/4797/23173 4103/4798/23174 4101/4796/23175 -f 4103/4798/23176 4104/4797/23177 4106/4799/23178 -f 4106/4799/23179 4105/4800/23180 4103/4798/23181 -f 4107/4802/23182 4105/4800/23183 4106/4799/23184 -f 4106/4799/23185 4108/4801/23186 4107/4802/23187 -f 4106/4799/23188 4104/4797/23189 3509/4133/23190 -f 3509/4133/23191 3510/4132/23192 4106/4799/23193 -f 4106/4799/23194 3510/4132/23195 4109/4803/23196 -f 4109/4803/23197 4108/4801/23198 4106/4799/23199 -f 4109/4803/23200 3486/4112/23201 3485/4106/23202 -f 3485/4106/23203 4092/4786/23204 4109/4803/23205 -f 4109/4803/23206 4092/4786/23207 4093/4785/23208 -f 4093/4785/23209 4108/4801/23210 4109/4803/23211 -f 4109/4803/23212 3510/4132/23213 3507/4135/23214 -f 3507/4135/23215 3486/4112/23216 4109/4803/23217 -f 4108/4801/23218 4093/4785/23219 4110/4804/23220 -f 4110/4804/23221 4107/4802/23222 4108/4801/23223 -f 4104/4797/23224 4102/4795/23225 4111/4805/23226 -f 4111/4805/23227 3509/4133/23228 4104/4797/23229 -f 4111/4805/23230 4102/4795/23231 4100/4793/23232 -f 4100/4793/23233 4112/4806/23234 4111/4805/23235 -f 4111/4805/23236 4112/4806/23237 3428/4053/23238 -f 3428/4053/23239 3454/4078/23240 4111/4805/23241 -f 4111/4805/23242 3454/4078/23243 3513/4138/23244 -f 3513/4138/23245 3509/4133/23246 4111/4805/23247 -f 4113/4807/23248 4112/4806/23249 4100/4793/23250 -f 4100/4793/23251 4098/4791/23252 4113/4807/23253 -f 3428/4053/23254 4112/4806/23255 4113/4807/23256 -f 4113/4807/23257 3425/4050/23258 3428/4053/23259 -f 4113/4807/23260 4098/4791/23261 3452/4074/23262 -f 3452/4074/23263 3453/4076/23264 4113/4807/23265 -f 4113/4807/23266 3453/4076/23267 3427/4048/23268 -f 3427/4048/23269 3425/4050/23270 4113/4807/23271 -f 4094/4789/23272 4110/4804/23273 4093/4785/23274 -f 4093/4785/23275 4091/4787/23276 4094/4789/23277 -f 3511/4137/23278 3488/4110/23279 3486/4112/23280 -f 3486/4112/23281 3507/4135/23282 3511/4137/23283 -f 3499/4782/23284 3474/4095/23285 3466/4098/23286 -f 3466/4098/23287 4078/4769/23288 3499/4782/23289 -f 3481/4105/23290 3477/4100/23291 3493/4116/23292 -f 3493/4116/23293 3496/4119/23294 3481/4105/23295 -f 3464/4768/23296 3465/4808/23297 3388/4010/23298 -f 3388/4010/23299 3416/4039/23300 3464/4768/23301 -f 4114/4809/23302 3465/4087/23303 3418/4041/23304 -f 3418/4041/23305 3417/4040/23306 4114/4809/23307 -f 3387/4011/23308 3388/4010/23309 3465/4808/23310 -f 3465/4808/23311 4114/4810/23312 3387/4011/23313 -f 4114/4809/23314 3417/4040/23315 3410/4034/23316 -f 3410/4034/23317 4115/4811/23318 4114/4809/23319 -f 4114/4810/23320 4115/4811/23321 4116/4812/23322 -f 4116/4812/23323 3387/4011/23324 4114/4810/23325 -f 4116/4812/23326 4115/4811/23327 4118/4813/23328 -f 4118/4813/23329 4117/4814/23330 4116/4812/23331 -f 4116/4812/23332 4117/4814/23333 4120/4815/23334 -f 4120/4815/23335 4119/4816/23336 4116/4812/23337 -f 4116/4812/23338 4119/4816/23339 3385/4007/23340 -f 3385/4007/23341 3387/4011/23342 4116/4812/23343 -f 4120/4815/23344 3383/4006/23345 3379/4003/23346 -f 3379/4003/23347 4119/4816/23348 4120/4815/23349 -f 4118/4813/23350 4115/4811/23351 3410/4034/23352 -f 3410/4034/23353 3411/4033/23354 4118/4813/23355 -f 3400/4022/23356 3384/4008/23357 3380/4002/23358 -f 3380/4002/23359 3399/4023/23360 3400/4022/23361 -f 3394/4018/23362 3374/3996/23363 3378/4001/23364 -f 3378/4001/23365 3395/4017/23366 3394/4018/23367 -f 3395/4017/23368 3378/4001/23369 3382/4004/23370 -f 3382/4004/23371 3389/4015/23372 3395/4017/23373 -f 3480/4103/23374 3479/4104/23375 3495/4120/23376 -f 3477/4100/23377 3478/4099/23378 3492/4117/23379 -f 3492/4117/23380 3493/4116/23381 3477/4100/23382 -f 3666/4302/23383 3667/4301/23384 4046/4723/23385 -f 4046/4723/23386 3681/4318/23387 3666/4302/23388 -f 3550/4176/23389 3603/4239/23390 3977/4642/23391 -f 3977/4642/23392 3547/4173/23393 3550/4176/23394 -f 3801/4449/23395 3530/4154/23396 3531/4156/23397 -f 3531/4156/23398 4121/4817/23399 3801/4449/23400 -f 3531/4156/23401 3532/4160/23402 3536/4162/23403 -f 3536/4162/23404 4121/4817/23405 3531/4156/23406 -f 3536/4162/23407 3800/4450/23408 3801/4449/23409 -f 3801/4449/23410 4121/4817/23411 3536/4162/23412 -f 3634/4271/23413 3635/4272/23414 3653/4291/23415 -f 3653/4291/23416 3915/4572/23417 3634/4271/23418 -f 3653/4291/23419 3657/4294/23420 3618/4256/23421 -f 3618/4256/23422 3915/4572/23423 3653/4291/23424 -f 3522/4146/23425 3484/4107/23426 3506/4131/23427 -f 3506/4131/23428 3524/4148/23429 3522/4146/23430 -f 3506/4131/23431 3862/4517/23432 3524/4148/23433 -f 3494/4115/23434 3794/4444/23435 3795/4443/23436 -f 3795/4443/23437 4083/4772/23438 3494/4115/23439 -f 3503/4130/23440 3480/4103/23441 3495/4120/23442 -f 3506/4131/23443 3503/4130/23444 3504/4129/23445 -f 3504/4129/23446 3859/4510/23447 3506/4131/23448 -f 3460/4084/23449 3461/4083/23450 3483/4108/23451 -f 3483/4108/23452 3521/4147/23453 3460/4084/23454 -f 3599/4234/23455 3550/4176/23456 3551/4175/23457 -f 3554/4184/23458 3547/4183/23459 3977/4818/23460 -f 3977/4818/23461 3978/4652/23462 3554/4184/23463 -f 3383/4006/23464 4120/4815/23465 3382/4004/23466 -f 3382/4004/23467 3381/4005/23468 3383/4006/23469 -f 3411/4033/23470 3408/4030/23471 3403/4026/23472 -f 4120/4815/23473 4117/4814/23474 3389/4015/23475 -f 3389/4015/23476 3382/4004/23477 4120/4815/23478 -f 4118/4813/23479 3392/4012/23480 3389/4015/23481 -f 3389/4015/23482 4117/4814/23483 4118/4813/23484 -f 3411/4033/23485 3403/4026/23486 3392/4012/23487 -f 3392/4012/23488 4118/4813/23489 3411/4033/23490 -f 3467/4532/23491 4078/4769/23492 3466/4098/23493 -f 3472/4744/23494 3462/4086/23495 3463/4085/23496 -f 3463/4085/23497 3466/4090/23498 3472/4744/23499 -f 3385/4007/23500 4119/4816/23501 3379/4003/23502 -f 3936/4594/23503 3716/4354/23504 3713/4357/23505 -f 3713/4357/23506 3928/4584/23507 3936/4594/23508 -f 3922/4579/23509 3921/4577/23510 3933/4590/23511 -f 3933/4590/23512 3934/4592/23513 3924/4580/23514 -f 3924/4580/23515 3922/4579/23516 3933/4590/23517 -f 3934/4592/23518 3936/4594/23519 3928/4584/23520 -f 3928/4584/23521 3924/4580/23522 3934/4592/23523 -f 3928/4584/23524 3926/4582/23525 3924/4580/23526 -f 4097/4792/23527 4099/4794/23528 4101/4796/23529 -f 4107/4802/23530 4101/4796/23531 4103/4798/23532 -f 4103/4798/23533 4105/4800/23534 4107/4802/23535 -f 4101/4796/23536 4107/4802/23537 4097/4792/23538 -f 4097/4792/23539 4107/4802/23540 4110/4804/23541 -f 4110/4804/23542 4096/4790/23543 4097/4792/23544 -f 4095/4788/23545 4096/4790/23546 4110/4804/23547 -f 4110/4804/23548 4094/4789/23549 4095/4788/23550 -f 3491/4118/23551 3954/4611/23552 3517/4139/23553 -f 3517/4139/23554 3514/4142/23555 3491/4118/23556 -f 3514/4142/23557 3520/4145/23558 3491/4118/23559 -f 3543/4169/23560 3544/4168/23561 3847/4500/23562 -f 3847/4500/23563 3846/4499/23564 3543/4169/23565 -f 3543/4169/23566 3846/4499/23567 3844/4498/23568 -f 3844/4498/23569 3850/4504/23570 3543/4169/23571 -f 3850/4504/23572 3844/4498/23573 3845/4497/23574 -f 3845/4497/23575 3823/4475/23576 3850/4504/23577 -f 3822/4474/23578 3823/4475/23579 3845/4497/23580 -f 3845/4497/23581 3848/4502/23582 3822/4474/23583 -f 3848/4502/23584 4122/4819/23585 3822/4474/23586 -f 3588/4221/23587 3580/4220/23588 4122/4819/23589 -f 4122/4819/23590 3825/4479/23591 3588/4221/23592 -f 3824/4476/23593 3587/4222/23594 3588/4221/23595 -f 3588/4221/23596 3825/4479/23597 3824/4476/23598 -f 4122/4819/23599 3583/4213/23600 3822/4474/23601 -f 3848/4502/23602 3825/4479/23603 4122/4819/23604 -f 3580/4220/23605 3579/4207/23606 4122/4819/23607 -f 3579/4207/23608 3583/4213/23609 4122/4819/23610 -f 3632/4268/23611 3633/4267/23612 3610/4246/23613 -f 4288/4820/23614 4281/4821/23615 4290/4822/23616 -f 4290/4822/23617 4289/4823/23618 4288/4820/23619 -f 4344/4824/23620 4288/4820/23621 4289/4823/23622 -f 4289/4823/23623 4153/4825/23624 4344/4824/23625 -f 4153/4825/23626 4329/4826/23627 4328/4827/23628 -f 4328/4827/23629 4344/4824/23630 4153/4825/23631 -f 4293/4828/23632 4185/4829/23633 4280/4830/23634 -f 4280/4830/23635 4279/4831/23636 4293/4828/23637 -f 4166/4832/23638 4290/4822/23639 4280/4830/23640 -f 4280/4830/23641 4169/4833/23642 4166/4832/23643 -f 4146/4834/23644 4289/4823/23645 4290/4822/23646 -f 4290/4822/23647 4166/4832/23648 4146/4834/23649 -f 4154/4835/23650 4153/4825/23651 4289/4823/23652 -f 4289/4823/23653 4146/4834/23654 4154/4835/23655 -f 4155/4836/23656 4329/4826/23657 4153/4825/23658 -f 4153/4825/23659 4154/4835/23660 4155/4836/23661 -f 4280/4830/23662 4185/4829/23663 4191/4837/23664 -f 4191/4837/23665 4169/4833/23666 4280/4830/23667 -f 4186/4838/23668 4185/4829/23669 4293/4828/23670 -f 4293/4828/23671 4180/4839/23672 4186/4838/23673 -f 4192/4840/23674 4191/4837/23675 4185/4829/23676 -f 4185/4829/23677 4186/4838/23678 4192/4840/23679 -f 4200/4841/23680 4186/4838/23681 4180/4839/23682 -f 4180/4839/23683 4183/4842/23684 4200/4841/23685 -f 4193/4843/23686 4192/4840/23687 4186/4838/23688 -f 4186/4838/23689 4200/4841/23690 4193/4843/23691 -f 4330/4844/23692 4329/4826/23693 4155/4836/23694 -f 4155/4836/23695 4156/4845/23696 4330/4844/23697 -f 4331/4846/23698 4328/4827/23699 4329/4826/23700 -f 4329/4826/23701 4330/4844/23702 4331/4846/23703 -f 4181/4847/23704 4200/4841/23705 4183/4842/23706 -f 4183/4842/23707 4184/4848/23708 4181/4847/23709 -f 4182/4849/23710 4193/4843/23711 4200/4841/23712 -f 4200/4841/23713 4181/4847/23714 4182/4849/23715 -f 4149/4850/23716 4330/4844/23717 4156/4845/23718 -f 4156/4845/23719 4150/4851/23720 4149/4850/23721 -f 4327/4852/23722 4331/4846/23723 4330/4844/23724 -f 4330/4844/23725 4149/4850/23726 4327/4852/23727 -f 4136/4853/23728 4181/4847/23729 4184/4848/23730 -f 4184/4848/23731 4135/4854/23732 4136/4853/23733 -f 4137/4855/23734 4182/4849/23735 4181/4847/23736 -f 4181/4847/23737 4136/4853/23738 4137/4855/23739 -f 4141/4856/23740 4149/4850/23741 4150/4851/23742 -f 4150/4851/23743 4142/4857/23744 4141/4856/23745 -f 4139/4858/23746 4327/4852/23747 4149/4850/23748 -f 4149/4850/23749 4141/4856/23750 4139/4858/23751 -f 4133/4859/23752 4141/4856/23753 4142/4857/23754 -f 4142/4857/23755 4143/4860/23756 4133/4859/23757 -f 4134/4861/23758 4139/4858/23759 4141/4856/23760 -f 4141/4856/23761 4133/4859/23762 4134/4861/23763 -f 4136/4853/23764 4133/4859/23765 4143/4860/23766 -f 4143/4860/23767 4137/4855/23768 4136/4853/23769 -f 4135/4854/23770 4134/4861/23771 4133/4859/23772 -f 4133/4859/23773 4136/4853/23774 4135/4854/23775 -f 4279/4831/23776 4280/4830/23777 4290/4822/23778 -f 4290/4822/23779 4281/4821/23780 4279/4831/23781 -f 4288/4820/23782 4201/4862/23783 4283/4863/23784 -f 4283/4863/23785 4281/4821/23786 4288/4820/23787 -f 4332/4864/23788 4201/4862/23789 4288/4820/23790 -f 4288/4820/23791 4344/4824/23792 4332/4864/23793 -f 4333/4865/23794 4332/4864/23795 4344/4824/23796 -f 4344/4824/23797 4328/4827/23798 4333/4865/23799 -f 4315/4866/23800 4333/4865/23801 4328/4827/23802 -f 4328/4827/23803 4331/4846/23804 4315/4866/23805 -f 4331/4846/23806 4327/4852/23807 4313/4867/23808 -f 4313/4867/23809 4315/4866/23810 4331/4846/23811 -f 4327/4852/23812 4139/4858/23813 4140/4868/23814 -f 4140/4868/23815 4313/4867/23816 4327/4852/23817 -f 4139/4858/23818 4134/4861/23819 4127/4869/23820 -f 4127/4869/23821 4140/4868/23822 4139/4858/23823 -f 4172/4870/23824 4127/4869/23825 4134/4861/23826 -f 4134/4861/23827 4135/4854/23828 4172/4870/23829 -f 4173/4871/23830 4172/4870/23831 4135/4854/23832 -f 4135/4854/23833 4184/4848/23834 4173/4871/23835 -f 4184/4848/23836 4183/4842/23837 4179/4872/23838 -f 4179/4872/23839 4173/4871/23840 4184/4848/23841 -f 4183/4842/23842 4180/4839/23843 4187/4873/23844 -f 4187/4873/23845 4179/4872/23846 4183/4842/23847 -f 4293/4828/23848 4291/4874/23849 4222/4875/23850 -f 4222/4875/23851 4180/4839/23852 4293/4828/23853 -f 4293/4828/23854 4279/4831/23855 4282/4876/23856 -f 4282/4876/23857 4291/4874/23858 4293/4828/23859 -f 4282/4876/23860 4279/4831/23861 4281/4821/23862 -f 4281/4821/23863 4283/4863/23864 4282/4876/23865 -f 4283/4863/23866 4284/4877/23867 4285/4878/23868 -f 4285/4878/23869 4282/4876/23870 4283/4863/23871 -f 4187/4873/23872 4188/4879/23873 4175/4880/23874 -f 4175/4880/23875 4179/4872/23876 4187/4873/23877 -f 4126/4881/23878 4123/4882/23879 4188/4879/23880 -f 4188/4879/23881 4187/4873/23882 4126/4881/23883 -f 4282/4876/23884 4285/4878/23885 4292/4883/23886 -f 4292/4883/23887 4291/4874/23888 4282/4876/23889 -f 4223/4884/23890 4292/4883/23891 4230/4885/23892 -f 4230/4885/23893 4224/4886/23894 4223/4884/23895 -f 4292/4883/23896 4285/4878/23897 4294/4887/23898 -f 4294/4887/23899 4230/4885/23900 4292/4883/23901 -f 4294/4887/23902 4232/4888/23903 4231/4889/23904 -f 4231/4889/23905 4230/4885/23906 4294/4887/23907 -f 4231/4889/23908 4219/4890/23909 4224/4886/23910 -f 4224/4886/23911 4230/4885/23912 4231/4889/23913 -f 4177/4891/23914 4173/4871/23915 4179/4872/23916 -f 4179/4872/23917 4175/4880/23918 4177/4891/23919 -f 4128/4892/23920 4322/4893/23921 4140/4868/23922 -f 4140/4868/23923 4127/4869/23924 4128/4892/23925 -f 4128/4892/23926 4127/4869/23927 4172/4870/23928 -f 4172/4870/23929 4131/4894/23930 4128/4892/23931 -f 4131/4894/23932 4172/4870/23933 4173/4871/23934 -f 4173/4871/23935 4177/4891/23936 4131/4894/23937 -f 4333/4865/23938 4315/4866/23939 4316/4895/23940 -f 4316/4895/23941 4335/4896/23942 4333/4865/23943 -f 4316/4895/23944 4315/4866/23945 4313/4867/23946 -f 4313/4867/23947 4314/4897/23948 4316/4895/23949 -f 4313/4867/23950 4140/4868/23951 4322/4893/23952 -f 4322/4893/23953 4314/4897/23954 4313/4867/23955 -f 4333/4865/23956 4335/4896/23957 4334/4898/23958 -f 4334/4898/23959 4332/4864/23960 4333/4865/23961 -f 4218/4899/23962 4211/4900/23963 4123/4882/23964 -f 4123/4882/23965 4126/4881/23966 4218/4899/23967 -f 4219/4890/23968 4209/4901/23969 4220/4902/23970 -f 4220/4902/23971 4224/4886/23972 4219/4890/23973 -f 4218/4899/23974 4220/4902/23975 4209/4901/23976 -f 4209/4901/23977 4211/4900/23978 4218/4899/23979 -f 4209/4901/23980 4214/4903/23981 4213/4904/23982 -f 4213/4904/23983 4211/4900/23984 4209/4901/23985 -f 4213/4904/23986 4214/4903/23987 4216/4905/23988 -f 4216/4905/23989 4210/4906/23990 4213/4904/23991 -f 4212/4907/23992 4211/4900/23993 4213/4904/23994 -f 4213/4904/23995 4210/4906/23996 4212/4907/23997 -f 4124/4908/23998 4123/4882/23999 4211/4900/24000 -f 4211/4900/24001 4212/4907/24002 4124/4908/24003 -f 4223/4884/24004 4224/4886/24005 4220/4902/24006 -f 4220/4902/24007 4218/4899/24008 4223/4884/24009 -f 4218/4899/24010 4126/4881/24011 4222/4875/24012 -f 4222/4875/24013 4223/4884/24014 4218/4899/24015 -f 4125/4909/24016 4188/4879/24017 4123/4882/24018 -f 4123/4882/24019 4124/4908/24020 4125/4909/24021 -f 4174/4910/24022 4175/4880/24023 4188/4879/24024 -f 4188/4879/24025 4125/4909/24026 4174/4910/24027 -f 4178/4911/24028 4177/4891/24029 4175/4880/24030 -f 4175/4880/24031 4174/4910/24032 4178/4911/24033 -f 4177/4891/24034 4178/4911/24035 4132/4912/24036 -f 4132/4912/24037 4131/4894/24038 4177/4891/24039 -f 4132/4912/24040 4130/4913/24041 4129/4914/24042 -f 4129/4914/24043 4131/4894/24044 4132/4912/24045 -f 4131/4894/24046 4129/4914/24047 4321/4915/24048 -f 4321/4915/24049 4128/4892/24050 4131/4894/24051 -f 4320/4916/24052 4322/4893/24053 4128/4892/24054 -f 4128/4892/24055 4321/4915/24056 4320/4916/24057 -f 4312/4917/24058 4314/4897/24059 4322/4893/24060 -f 4322/4893/24061 4320/4916/24062 4312/4917/24063 -f 4312/4917/24064 4318/4918/24065 4316/4895/24066 -f 4316/4895/24067 4314/4897/24068 4312/4917/24069 -f 4339/4919/24070 4335/4896/24071 4316/4895/24072 -f 4316/4895/24073 4318/4918/24074 4339/4919/24075 -f 4202/4920/24076 4201/4862/24077 4332/4864/24078 -f 4332/4864/24079 4334/4898/24080 4202/4920/24081 -f 4284/4877/24082 4283/4863/24083 4201/4862/24084 -f 4201/4862/24085 4202/4920/24086 4284/4877/24087 -f 4335/4896/24088 4339/4919/24089 4336/4921/24090 -f 4336/4921/24091 4334/4898/24092 4335/4896/24093 -f 4206/4922/24094 4202/4920/24095 4334/4898/24096 -f 4334/4898/24097 4336/4921/24098 4206/4922/24099 -f 4296/4923/24100 4284/4877/24101 4202/4920/24102 -f 4202/4920/24103 4206/4922/24104 4296/4923/24105 -f 4285/4878/24106 4284/4877/24107 4286/4924/24108 -f 4286/4924/24109 4294/4887/24110 4285/4878/24111 -f 4284/4877/24112 4296/4923/24113 4297/4925/24114 -f 4297/4925/24115 4286/4924/24116 4284/4877/24117 -f 4287/4926/24118 4232/4888/24119 4294/4887/24120 -f 4294/4887/24121 4286/4924/24122 4287/4926/24123 -f 4219/4890/24124 4221/4927/24125 4227/4928/24126 -f 4227/4928/24127 4209/4901/24128 4219/4890/24129 -f 4232/4888/24130 4234/4929/24131 4233/4930/24132 -f 4233/4930/24133 4231/4889/24134 4232/4888/24135 -f 4219/4890/24136 4231/4889/24137 4233/4930/24138 -f 4233/4930/24139 4221/4927/24140 4219/4890/24141 -f 4214/4903/24142 4209/4901/24143 4227/4928/24144 -f 4227/4928/24145 4215/4931/24146 4214/4903/24147 -f 4216/4905/24148 4214/4903/24149 4215/4931/24150 -f 4215/4931/24151 4217/4932/24152 4216/4905/24153 -f 4287/4926/24154 4237/4933/24155 4234/4929/24156 -f 4234/4929/24157 4232/4888/24158 4287/4926/24159 -f 4237/4933/24160 4253/4934/24161 4251/4935/24162 -f 4251/4935/24163 4234/4929/24164 4237/4933/24165 -f 4253/4934/24166 4245/4936/24167 4239/4937/24168 -f 4239/4937/24169 4251/4935/24170 4253/4934/24171 -f 4247/4938/24172 4244/4939/24173 4240/4940/24174 -f 4240/4940/24175 4239/4937/24176 4247/4938/24177 -f 4217/4932/24178 4215/4931/24179 4240/4940/24180 -f 4240/4940/24181 4244/4939/24182 4217/4932/24183 -f 4221/4927/24184 4225/4941/24185 4228/4942/24186 -f 4228/4942/24187 4227/4928/24188 4221/4927/24189 -f 4234/4929/24190 4236/4943/24191 4235/4944/24192 -f 4235/4944/24193 4233/4930/24194 4234/4929/24195 -f 4225/4941/24196 4221/4927/24197 4233/4930/24198 -f 4233/4930/24199 4235/4944/24200 4225/4941/24201 -f 4215/4931/24202 4227/4928/24203 4228/4942/24204 -f 4228/4942/24205 4240/4940/24206 4215/4931/24207 -f 4240/4940/24208 4242/4945/24209 4241/4946/24210 -f 4241/4946/24211 4239/4937/24212 4240/4940/24213 -f 4251/4935/24214 4239/4937/24215 4241/4946/24216 -f 4241/4946/24217 4252/4947/24218 4251/4935/24219 -f 4228/4942/24220 4243/4948/24221 4242/4945/24222 -f 4242/4945/24223 4240/4940/24224 4228/4942/24225 -f 4228/4942/24226 4225/4941/24227 4226/4949/24228 -f 4226/4949/24229 4243/4948/24230 4228/4942/24231 -f 4236/4943/24232 4234/4929/24233 4251/4935/24234 -f 4251/4935/24235 4252/4947/24236 4236/4943/24237 -f 4235/4944/24238 4236/4943/24239 4226/4949/24240 -f 4226/4949/24241 4225/4941/24242 4235/4944/24243 -f 4226/4949/24244 4236/4943/24245 4252/4947/24246 -f 4252/4947/24247 4243/4948/24248 4226/4949/24249 -f 4242/4945/24250 4243/4948/24251 4252/4947/24252 -f 4252/4947/24253 4241/4946/24254 4242/4945/24255 -f 4296/4923/24256 4203/4950/24257 4298/4951/24258 -f 4298/4951/24259 4297/4925/24260 4296/4923/24261 -f 4310/4952/24262 4298/4951/24263 4203/4950/24264 -f 4203/4950/24265 4205/4953/24266 4310/4952/24267 -f 4205/4953/24268 4204/4954/24269 4308/4955/24270 -f 4308/4955/24271 4310/4952/24272 4205/4953/24273 -f 4551/4956/24274 4261/4957/24275 4308/4955/24276 -f 4308/4955/24277 4204/4954/24278 4551/4956/24279 -f 4551/4956/24280 4549/4958/24281 4259/4959/24282 -f 4259/4959/24283 4261/4957/24284 4551/4956/24285 -f 4268/4960/24286 4259/4959/24287 4549/4958/24288 -f 4549/4958/24289 4553/4961/24290 4268/4960/24291 -f 4268/4960/24292 4553/4961/24293 4554/4962/24294 -f 4554/4962/24295 4269/4963/24296 4268/4960/24297 -f 4286/4924/24298 4297/4925/24299 4299/4964/24300 -f 4299/4964/24301 4287/4926/24302 4286/4924/24303 -f 4297/4925/24304 4298/4951/24305 4295/4965/24306 -f 4295/4965/24307 4299/4964/24308 4297/4925/24309 -f 4298/4951/24310 4310/4952/24311 4309/4966/24312 -f 4309/4966/24313 4295/4965/24314 4298/4951/24315 -f 4310/4952/24316 4308/4955/24317 4311/4967/24318 -f 4311/4967/24319 4309/4966/24320 4310/4952/24321 -f 4308/4955/24322 4261/4957/24323 4260/4968/24324 -f 4260/4968/24325 4311/4967/24326 4308/4955/24327 -f 4261/4957/24328 4259/4959/24329 4258/4969/24330 -f 4258/4969/24331 4260/4968/24332 4261/4957/24333 -f 4259/4959/24334 4268/4960/24335 4267/4970/24336 -f 4267/4970/24337 4258/4969/24338 4259/4959/24339 -f 4272/4971/24340 4271/4972/24341 4269/4963/24342 -f 4269/4963/24343 4270/4973/24344 4272/4971/24345 -f 4260/4968/24346 4256/4974/24347 4300/4975/24348 -f 4300/4975/24349 4311/4967/24350 4260/4968/24351 -f 4260/4968/24352 4258/4969/24353 4276/4976/24354 -f 4276/4976/24355 4256/4974/24356 4260/4968/24357 -f 4258/4969/24358 4267/4970/24359 4262/4977/24360 -f 4262/4977/24361 4276/4976/24362 4258/4969/24363 -f 4301/4978/24364 4309/4966/24365 4311/4967/24366 -f 4311/4967/24367 4300/4975/24368 4301/4978/24369 -f 4295/4965/24370 4309/4966/24371 4301/4978/24372 -f 4301/4978/24373 4302/4979/24374 4295/4965/24375 -f 4302/4979/24376 4306/4980/24377 4299/4964/24378 -f 4299/4964/24379 4295/4965/24380 4302/4979/24381 -f 4254/4981/24382 4287/4926/24383 4299/4964/24384 -f 4299/4964/24385 4306/4980/24386 4254/4981/24387 -f 4238/4982/24388 4237/4933/24389 4287/4926/24390 -f 4287/4926/24391 4254/4981/24392 4238/4982/24393 -f 4238/4982/24394 4229/4983/24395 4253/4934/24396 -f 4253/4934/24397 4237/4933/24398 4238/4982/24399 -f 4246/4984/24400 4245/4936/24401 4253/4934/24402 -f 4253/4934/24403 4229/4983/24404 4246/4984/24405 -f 4249/4985/24406 4248/4986/24407 4245/4936/24408 -f 4245/4936/24409 4246/4984/24410 4249/4985/24411 -f 4274/4987/24412 4262/4977/24413 4265/4988/24414 -f 4265/4988/24415 4263/4989/24416 4274/4987/24417 -f 4273/4990/24418 4276/4976/24419 4262/4977/24420 -f 4262/4977/24421 4274/4987/24422 4273/4990/24423 -f 4257/4991/24424 4256/4974/24425 4276/4976/24426 -f 4276/4976/24427 4273/4990/24428 4257/4991/24429 -f 4257/4991/24430 4303/4992/24431 4300/4975/24432 -f 4300/4975/24433 4256/4974/24434 4257/4991/24435 -f 4301/4978/24436 4300/4975/24437 4303/4992/24438 -f 4303/4992/24439 4304/4993/24440 4301/4978/24441 -f 4302/4979/24442 4301/4978/24443 4304/4993/24444 -f 4304/4993/24445 4305/4994/24446 4302/4979/24447 -f 4306/4980/24448 4302/4979/24449 4305/4994/24450 -f 4305/4994/24451 4307/4995/24452 4306/4980/24453 -f 4255/4996/24454 4254/4981/24455 4306/4980/24456 -f 4306/4980/24457 4307/4995/24458 4255/4996/24459 -f 4277/4997/24460 4238/4982/24461 4254/4981/24462 -f 4254/4981/24463 4255/4996/24464 4277/4997/24465 -f 4275/4998/24466 4229/4983/24467 4238/4982/24468 -f 4238/4982/24469 4277/4997/24470 4275/4998/24471 -f 4278/4999/24472 4246/4984/24473 4229/4983/24474 -f 4229/4983/24475 4275/4998/24476 4278/4999/24477 -f 4249/4985/24478 4246/4984/24479 4278/4999/24480 -f 4278/4999/24481 4250/5000/24482 4249/4985/24483 -f 4305/4994/24484 4304/4993/24485 4303/4992/24486 -f 4303/4992/24487 4307/4995/24488 4305/4994/24489 -f 4257/4991/24490 4255/4996/24491 4307/4995/24492 -f 4307/4995/24493 4303/4992/24494 4257/4991/24495 -f 4273/4990/24496 4277/4997/24497 4255/4996/24498 -f 4255/4996/24499 4257/4991/24500 4273/4990/24501 -f 4274/4987/24502 4275/4998/24503 4277/4997/24504 -f 4277/4997/24505 4273/4990/24506 4274/4987/24507 -f 4270/4973/24508 4269/4963/24509 4554/4962/24510 -f 4554/4962/24511 4555/5001/24512 4270/4973/24513 -f 4269/4963/24514 4271/4972/24515 4267/4970/24516 -f 4267/4970/24517 4268/4960/24518 4269/4963/24519 -f 4271/4972/24520 4265/4988/24521 4262/4977/24522 -f 4262/4977/24523 4267/4970/24524 4271/4972/24525 -f 4263/4989/24526 4265/4988/24527 4266/5002/24528 -f 4266/5002/24529 4264/5003/24530 4263/4989/24531 -f 4275/4998/24532 4274/4987/24533 4263/4989/24534 -f 4263/4989/24535 4278/4999/24536 4275/4998/24537 -f 4263/4989/24538 4264/5003/24539 4250/5000/24540 -f 4250/5000/24541 4278/4999/24542 4263/4989/24543 -f 4296/4923/24544 4206/4922/24545 4208/5004/24546 -f 4208/5004/24547 4203/4950/24548 4296/4923/24549 -f 4206/4922/24550 4336/4921/24551 4337/5005/24552 -f 4337/5005/24553 4208/5004/24554 4206/4922/24555 -f 4336/4921/24556 4339/4919/24557 4340/5006/24558 -f 4340/5006/24559 4337/5005/24560 4336/4921/24561 -f 4207/5007/24562 4205/4953/24563 4203/4950/24564 -f 4203/4950/24565 4208/5004/24566 4207/5007/24567 -f 4547/5008/24568 4204/4954/24569 4205/4953/24570 -f 4205/4953/24571 4207/5007/24572 4547/5008/24573 -f 4545/5009/24574 4551/4956/24575 4204/4954/24576 -f 4204/4954/24577 4547/5008/24578 4545/5009/24579 -f 4552/5010/24580 4549/4958/24581 4551/4956/24582 -f 4551/4956/24583 4545/5009/24584 4552/5010/24585 -f 4550/5011/24586 4553/4961/24587 4549/4958/24588 -f 4549/4958/24589 4552/5010/24590 4550/5011/24591 -f 4556/5012/24592 4554/4962/24593 4553/4961/24594 -f 4553/4961/24595 4550/5011/24596 4556/5012/24597 -f 4556/5012/24598 4557/5013/24599 4555/5001/24600 -f 4555/5001/24601 4554/4962/24602 4556/5012/24603 -f 4338/5014/24604 4207/5007/24605 4208/5004/24606 -f 4208/5004/24607 4337/5005/24608 4338/5014/24609 -f 4547/5008/24610 4207/5007/24611 4338/5014/24612 -f 4338/5014/24613 4569/5015/24614 4547/5008/24615 -f 4548/5016/24616 4545/5009/24617 4547/5008/24618 -f 4547/5008/24619 4569/5015/24620 4548/5016/24621 -f 4545/5009/24622 4548/5016/24623 4546/5017/24624 -f 4546/5017/24625 4552/5010/24626 4545/5009/24627 -f 4558/5018/24628 4550/5011/24629 4552/5010/24630 -f 4552/5010/24631 4546/5017/24632 4558/5018/24633 -f 4559/5019/24634 4556/5012/24635 4550/5011/24636 -f 4550/5011/24637 4558/5018/24638 4559/5019/24639 -f 4556/5012/24640 4559/5019/24641 4560/5020/24642 -f 4560/5020/24643 4557/5013/24644 4556/5012/24645 -f 4337/5005/24646 4342/5021/24647 4574/5022/24648 -f 4574/5022/24649 4338/5014/24650 4337/5005/24651 -f 4570/5023/24652 4569/5015/24653 4338/5014/24654 -f 4338/5014/24655 4574/5022/24656 4570/5023/24657 -f 4571/5024/24658 4548/5016/24659 4569/5015/24660 -f 4569/5015/24661 4570/5023/24662 4571/5024/24663 -f 4561/5025/24664 4546/5017/24665 4548/5016/24666 -f 4548/5016/24667 4571/5024/24668 4561/5025/24669 -f 4563/5026/24670 4558/5018/24671 4546/5017/24672 -f 4546/5017/24673 4561/5025/24674 4563/5026/24675 -f 4565/5027/24676 4559/5019/24677 4558/5018/24678 -f 4558/5018/24679 4563/5026/24680 4565/5027/24681 -f 4565/5027/24682 4564/5028/24683 4560/5020/24684 -f 4560/5020/24685 4559/5019/24686 4565/5027/24687 -f 4337/5005/24688 4340/5006/24689 4341/5029/24690 -f 4341/5029/24691 4342/5021/24692 4337/5005/24693 -f 4339/4919/24694 4318/4918/24695 4319/5030/24696 -f 4319/5030/24697 4340/5006/24698 4339/4919/24699 -f 4318/4918/24700 4312/4917/24701 4317/5031/24702 -f 4317/5031/24703 4319/5030/24704 4318/4918/24705 -f 4312/4917/24706 4320/4916/24707 4323/5032/24708 -f 4323/5032/24709 4317/5031/24710 4312/4917/24711 -f 4320/4916/24712 4321/4915/24713 4324/5033/24714 -f 4324/5033/24715 4323/5032/24716 4320/4916/24717 -f 4325/5034/24718 4324/5033/24719 4321/4915/24720 -f 4321/4915/24721 4129/4914/24722 4325/5034/24723 -f 4129/4914/24724 4130/4913/24725 4326/5035/24726 -f 4326/5035/24727 4325/5034/24728 4129/4914/24729 -f 4563/5026/24730 4566/5036/24731 4567/5037/24732 -f 4567/5037/24733 4565/5027/24734 4563/5026/24735 -f 4563/5026/24736 4561/5025/24737 4562/5038/24738 -f 4562/5038/24739 4566/5036/24740 4563/5026/24741 -f 4571/5024/24742 4572/5039/24743 4562/5038/24744 -f 4562/5038/24745 4561/5025/24746 4571/5024/24747 -f 4579/5040/24748 4572/5039/24749 4571/5024/24750 -f 4571/5024/24751 4570/5023/24752 4579/5040/24753 -f 4579/5040/24754 4570/5023/24755 4574/5022/24756 -f 4574/5022/24757 4575/5041/24758 4579/5040/24759 -f 4574/5022/24760 4342/5021/24761 4343/5042/24762 -f 4343/5042/24763 4575/5041/24764 4574/5022/24765 -f 4342/5021/24766 4341/5029/24767 4679/5043/24768 -f 4679/5043/24769 4343/5042/24770 4342/5021/24771 -f 4679/5043/24772 4680/5044/24773 4682/5045/24774 -f 4682/5045/24775 4343/5042/24776 4679/5043/24777 -f 4682/5045/24778 4576/5046/24779 4575/5041/24780 -f 4575/5041/24781 4343/5042/24782 4682/5045/24783 -f 4575/5041/24784 4576/5046/24785 4581/5047/24786 -f 4581/5047/24787 4579/5040/24788 4575/5041/24789 -f 4579/5040/24790 4581/5047/24791 4573/5048/24792 -f 4573/5048/24793 4572/5039/24794 4579/5040/24795 -f 4562/5038/24796 4572/5039/24797 4573/5048/24798 -f 4573/5048/24799 4597/5049/24800 4562/5038/24801 -f 4598/5050/24802 4566/5036/24803 4562/5038/24804 -f 4562/5038/24805 4597/5049/24806 4598/5050/24807 -f 4604/5051/24808 4567/5037/24809 4566/5036/24810 -f 4566/5036/24811 4598/5050/24812 4604/5051/24813 -f 4605/5052/24814 4568/5053/24815 4567/5037/24816 -f 4567/5037/24817 4604/5051/24818 4605/5052/24819 -f 4681/5270/24820 4684/5273/24821 4682/5274/24822 -f 4682/5274/24823 4680/5275/24824 4681/5270/24825 -f 4582/5277/24826 4581/5278/24827 4576/5279/24828 -f 4576/5279/24829 4577/5280/24830 4582/5277/24831 -f 4583/5281/24832 4573/5282/24833 4581/5278/24834 -f 4581/5278/24835 4582/5277/24836 4583/5281/24837 -f 4573/5282/24838 4583/5281/24839 4599/5283/24840 -f 4599/5283/24841 4597/5284/24842 4573/5282/24843 -f 4601/5285/24844 4598/5286/24845 4597/5284/24846 -f 4597/5284/24847 4599/5283/24848 4601/5285/24849 -f 4607/5287/24850 4604/5288/24851 4598/5286/24852 -f 4598/5286/24853 4601/5285/24854 4607/5287/24855 -f 4606/5289/24856 4605/5290/24857 4604/5288/24858 -f 4604/5288/24859 4607/5287/24860 4606/5289/24861 -f 4607/5287/24862 4614/5291/24863 4615/5292/24864 -f 4615/5292/24865 4606/5289/24866 4607/5287/24867 -f 4607/5287/24868 4601/5285/24869 4603/5293/24870 -f 4603/5293/24871 4614/5291/24872 4607/5287/24873 -f 4601/5285/24874 4599/5283/24875 4600/5294/24876 -f 4600/5294/24877 4603/5293/24878 4601/5285/24879 -f 4584/5295/24880 4600/5294/24881 4599/5283/24882 -f 4599/5283/24883 4583/5281/24884 4584/5295/24885 -f 4582/5277/24886 4580/5296/24887 4584/5295/24888 -f 4584/5295/24889 4583/5281/24890 4582/5277/24891 -f 4578/5297/24892 4580/5296/24893 4582/5277/24894 -f 4582/5277/24895 4577/5280/24896 4578/5297/24897 -f 4577/5280/24898 4576/5279/24899 4683/5298/24900 -f 4683/5298/24901 4578/5297/24902 4577/5280/24903 -f 4682/5274/24904 4684/5273/24905 4683/5298/24906 -f 4683/5298/24907 4576/5279/24908 4682/5274/24909 -f 4678/5299/24910 4688/5300/24911 4686/5301/24912 -f 4686/5301/24913 4681/5270/24914 4678/5299/24915 -f 4711/5302/24916 4683/5298/24917 4684/5273/24918 -f 4684/5273/24919 4685/5303/24920 4711/5302/24921 -f 4712/5304/24922 4578/5297/24923 4683/5298/24924 -f 4683/5298/24925 4711/5302/24926 4712/5304/24927 -f 4586/5305/24928 4580/5296/24929 4578/5297/24930 -f 4578/5297/24931 4712/5304/24932 4586/5305/24933 -f 4585/5306/24934 4584/5295/24935 4580/5296/24936 -f 4580/5296/24937 4586/5305/24938 4585/5306/24939 -f 4590/5307/24940 4600/5294/24941 4584/5295/24942 -f 4584/5295/24943 4585/5306/24944 4590/5307/24945 -f 4602/5308/24946 4603/5293/24947 4600/5294/24948 -f 4600/5294/24949 4590/5307/24950 4602/5308/24951 -f 4609/5309/24952 4614/5291/24953 4603/5293/24954 -f 4603/5293/24955 4602/5308/24956 4609/5309/24957 -f 4612/5310/24958 4613/5311/24959 4615/5292/24960 -f 4615/5292/24961 4614/5291/24962 4612/5310/24963 -f 4611/5312/24964 4612/5310/24965 4614/5291/24966 -f 4614/5291/24967 4609/5309/24968 4611/5312/24969 -f 4610/5332/24970 4611/5312/24971 4609/5309/24972 -f 4609/5309/24973 4608/5333/24974 4610/5332/24975 -f 4592/5334/24976 4608/5333/24977 4609/5309/24978 -f 4609/5309/24979 4602/5308/24980 4592/5334/24981 -f 4591/5341/24982 4592/5334/24983 4602/5308/24984 -f 4602/5308/24985 4590/5307/24986 4591/5341/24987 -f 4593/5342/24988 4591/5341/24989 4590/5307/24990 -f 4590/5307/24991 4585/5306/24992 4593/5342/24993 -f 4716/5343/24994 4593/5342/24995 4585/5306/24996 -f 4585/5306/24997 4586/5305/24998 4716/5343/24999 -f 4586/5305/25000 4712/5304/25001 4713/5344/25002 -f 4713/5344/25003 4716/5343/25004 4586/5305/25005 -f 4714/5345/25006 4713/5344/25007 4712/5304/25008 -f 4712/5304/25009 4711/5302/25010 4714/5345/25011 -f 4711/5302/25012 4685/5303/25013 4687/5347/25014 -f 4687/5347/25015 4714/5345/25016 4711/5302/25017 -f 4681/5270/25018 4686/5301/25019 4685/5303/25020 -f 4685/5303/25021 4684/5273/25022 4681/5270/25023 -f 4685/5303/25024 4686/5301/25025 4688/5300/25026 -f 4688/5300/25027 4687/5347/25028 4685/5303/25029 -f 4678/5299/25030 4689/5348/25031 4692/5349/25032 -f 4692/5349/25033 4688/5300/25034 4678/5299/25035 -f 4689/5348/25036 4690/5350/25037 4693/5351/25038 -f 4693/5351/25039 4692/5349/25040 4689/5348/25041 -f 4588/5352/25042 4610/5332/25043 4608/5333/25044 -f 4608/5333/25045 4587/5353/25046 4588/5352/25047 -f 4592/5334/25048 4596/5354/25049 4587/5353/25050 -f 4587/5353/25051 4608/5333/25052 4592/5334/25053 -f 4592/5334/25054 4591/5341/25055 4594/5355/25056 -f 4594/5355/25057 4596/5354/25058 4592/5334/25059 -f 4593/5342/25060 4724/5356/25061 4594/5355/25062 -f 4594/5355/25063 4591/5341/25064 4593/5342/25065 -f 4593/5342/25066 4716/5343/25067 4715/5357/25068 -f 4715/5357/25069 4724/5356/25070 4593/5342/25071 -f 4716/5343/25072 4713/5344/25073 4719/5358/25074 -f 4719/5358/25075 4715/5357/25076 4716/5343/25077 -f 4713/5344/25078 4714/5345/25079 4717/5359/25080 -f 4717/5359/25081 4719/5358/25082 4713/5344/25083 -f 4714/5345/25084 4687/5347/25085 4718/5360/25086 -f 4718/5360/25087 4717/5359/25088 4714/5345/25089 -f 4687/5347/25090 4688/5300/25091 4691/5361/25092 -f 4691/5361/25093 4718/5360/25094 4687/5347/25095 -f 4688/5300/25096 4692/5349/25097 4694/5362/25098 -f 4694/5362/25099 4691/5361/25100 4688/5300/25101 -f 4695/5363/25102 4694/5362/25103 4692/5349/25104 -f 4692/5349/25105 4693/5351/25106 4695/5363/25107 -f 4596/5354/25108 4595/5364/25109 4588/5352/25110 -f 4588/5352/25111 4587/5353/25112 4596/5354/25113 -f 4596/5354/25114 4594/5355/25115 4589/5365/25116 -f 4589/5365/25117 4595/5364/25118 4596/5354/25119 -f 4594/5355/25120 4724/5356/25121 4722/5366/25122 -f 4722/5366/25123 4589/5365/25124 4594/5355/25125 -f 4724/5356/25126 4715/5357/25127 4723/5367/25128 -f 4723/5367/25129 4722/5366/25130 4724/5356/25131 -f 4721/5368/25132 4723/5367/25133 4715/5357/25134 -f 4715/5357/25135 4719/5358/25136 4721/5368/25137 -f 4717/5359/25138 4720/5369/25139 4721/5368/25140 -f 4721/5368/25141 4719/5358/25142 4717/5359/25143 -f 4717/5359/25144 4718/5360/25145 4725/5370/25146 -f 4725/5370/25147 4720/5369/25148 4717/5359/25149 -f 4726/5371/25150 4725/5370/25151 4718/5360/25152 -f 4718/5360/25153 4691/5361/25154 4726/5371/25155 -f 4691/5361/25156 4694/5362/25157 4727/5372/25158 -f 4727/5372/25159 4726/5371/25160 4691/5361/25161 -f 4694/5362/25162 4695/5363/25163 4728/5373/25164 -f 4728/5373/25165 4727/5372/25166 4694/5362/25167 -f 4143/4860/25168 4163/5054/25169 4138/5055/25170 -f 4138/5055/25171 4137/4855/25172 4143/4860/25173 -f 4189/5056/25174 4182/4849/25175 4137/4855/25176 -f 4137/4855/25177 4138/5055/25178 4189/5056/25179 -f 4193/4843/25180 4182/4849/25181 4189/5056/25182 -f 4189/5056/25183 4194/5057/25184 4193/4843/25185 -f 4192/4840/25186 4193/4843/25187 4194/5057/25188 -f 4194/5057/25189 4195/5058/25190 4192/4840/25191 -f 4191/4837/25192 4192/4840/25193 4195/5058/25194 -f 4195/5058/25195 4196/5059/25196 4191/4837/25197 -f 4169/4833/25198 4191/4837/25199 4196/5059/25200 -f 4196/5059/25201 4170/5060/25202 4169/4833/25203 -f 4166/4832/25204 4169/4833/25205 4170/5060/25206 -f 4170/5060/25207 4167/5061/25208 4166/4832/25209 -f 4147/5062/25210 4146/4834/25211 4166/4832/25212 -f 4166/4832/25213 4167/5061/25214 4147/5062/25215 -f 4154/4835/25216 4146/4834/25217 4147/5062/25218 -f 4147/5062/25219 4157/5063/25220 4154/4835/25221 -f 4155/4836/25222 4154/4835/25223 4157/5063/25224 -f 4157/5063/25225 4158/5064/25226 4155/4836/25227 -f 4156/4845/25228 4155/4836/25229 4158/5064/25230 -f 4158/5064/25231 4159/5065/25232 4156/4845/25233 -f 4150/4851/25234 4156/4845/25235 4159/5065/25236 -f 4159/5065/25237 4151/5066/25238 4150/4851/25239 -f 4142/4857/25240 4150/4851/25241 4151/5066/25242 -f 4151/5066/25243 4144/5067/25244 4142/4857/25245 -f 4142/4857/25246 4144/5067/25247 4163/5054/25248 -f 4163/5054/25249 4143/4860/25250 4142/4857/25251 -f 4163/5054/25252 4164/5068/25253 4165/5069/25254 -f 4165/5069/25255 4138/5055/25256 4163/5054/25257 -f 4189/5056/25258 4138/5055/25259 4165/5069/25260 -f 4165/5069/25261 4190/5070/25262 4189/5056/25263 -f 4194/5057/25264 4189/5056/25265 4190/5070/25266 -f 4190/5070/25267 4197/5071/25268 4194/5057/25269 -f 4195/5058/25270 4194/5057/25271 4197/5071/25272 -f 4197/5071/25273 4198/5072/25274 4195/5058/25275 -f 4196/5059/25276 4195/5058/25277 4198/5072/25278 -f 4198/5072/25279 4199/5073/25280 4196/5059/25281 -f 4170/5060/25282 4196/5059/25283 4199/5073/25284 -f 4199/5073/25285 4171/5074/25286 4170/5060/25287 -f 4168/5075/25288 4167/5061/25289 4170/5060/25290 -f 4170/5060/25291 4171/5074/25292 4168/5075/25293 -f 4147/5062/25294 4167/5061/25295 4168/5075/25296 -f 4168/5075/25297 4148/5076/25298 4147/5062/25299 -f 4157/5063/25300 4147/5062/25301 4148/5076/25302 -f 4148/5076/25303 4160/5077/25304 4157/5063/25305 -f 4158/5064/25306 4157/5063/25307 4160/5077/25308 -f 4160/5077/25309 4161/5078/25310 4158/5064/25311 -f 4159/5065/25312 4158/5064/25313 4161/5078/25314 -f 4161/5078/25315 4162/5079/25316 4159/5065/25317 -f 4151/5066/25318 4159/5065/25319 4162/5079/25320 -f 4162/5079/25321 4152/5080/25322 4151/5066/25323 -f 4145/5081/25324 4144/5067/25325 4151/5066/25326 -f 4151/5066/25327 4152/5080/25328 4145/5081/25329 -f 4164/5068/25330 4163/5054/25331 4144/5067/25332 -f 4144/5067/25333 4145/5081/25334 4164/5068/25335 -f 4222/4875/25336 4291/4874/25337 4292/4883/25338 -f 4292/4883/25339 4223/4884/25340 4222/4875/25341 -f 4180/4839/25342 4222/4875/25343 4126/4881/25344 -f 4126/4881/25345 4187/4873/25346 4180/4839/25347 -f 4245/4936/25348 4248/4986/25349 4247/4938/25350 -f 4247/4938/25351 4239/4937/25352 4245/4936/25353 -f 4272/4971/25354 4266/5002/25355 4265/4988/25356 -f 4265/4988/25357 4271/4972/25358 4272/4971/25359 -f 4568/5053/25360 4564/5028/25361 4565/5027/25362 -f 4565/5027/25363 4567/5037/25364 4568/5053/25365 -f 4487/5082/25366 4486/5083/25367 4485/5084/25368 -f 4485/5084/25369 4482/5085/25370 4487/5082/25371 -f 4532/5086/25372 4411/5087/25373 4486/5083/25374 -f 4486/5083/25375 4487/5082/25376 4532/5086/25377 -f 4411/5087/25378 4532/5086/25379 4522/5088/25380 -f 4522/5088/25381 4523/5089/25382 4411/5087/25383 -f 4474/5090/25384 4475/5091/25385 4476/5092/25386 -f 4476/5092/25387 4367/5093/25388 4474/5090/25389 -f 4394/5094/25390 4381/5095/25391 4476/5092/25392 -f 4476/5092/25393 4485/5084/25394 4394/5094/25395 -f 4397/5096/25396 4394/5094/25397 4485/5084/25398 -f 4485/5084/25399 4486/5083/25400 4397/5096/25401 -f 4412/5097/25402 4397/5096/25403 4486/5083/25404 -f 4486/5083/25405 4411/5087/25406 4412/5097/25407 -f 4413/5098/25408 4412/5097/25409 4411/5087/25410 -f 4411/5087/25411 4523/5089/25412 4413/5098/25413 -f 4476/5092/25414 4381/5095/25415 4372/5099/25416 -f 4372/5099/25417 4367/5093/25418 4476/5092/25419 -f 4361/5100/25420 4358/5101/25421 4474/5090/25422 -f 4474/5090/25423 4367/5093/25424 4361/5100/25425 -f 4373/5102/25426 4361/5100/25427 4367/5093/25428 -f 4367/5093/25429 4372/5099/25430 4373/5102/25431 -f 4368/5103/25432 4359/5104/25433 4358/5101/25434 -f 4358/5101/25435 4361/5100/25436 4368/5103/25437 -f 4374/5105/25438 4368/5103/25439 4361/5100/25440 -f 4361/5100/25441 4373/5102/25442 4374/5105/25443 -f 4524/5106/25444 4414/5107/25445 4413/5098/25446 -f 4413/5098/25447 4523/5089/25448 4524/5106/25449 -f 4525/5108/25450 4524/5106/25451 4523/5089/25452 -f 4523/5089/25453 4522/5088/25454 4525/5108/25455 -f 4362/5109/25456 4360/5110/25457 4359/5104/25458 -f 4359/5104/25459 4368/5103/25460 4362/5109/25461 -f 4363/5111/25462 4362/5109/25463 4368/5103/25464 -f 4368/5103/25465 4374/5105/25466 4363/5111/25467 -f 4409/5112/25468 4410/5113/25469 4414/5107/25470 -f 4414/5107/25471 4524/5106/25472 4409/5112/25473 -f 4521/5114/25474 4409/5112/25475 4524/5106/25476 -f 4524/5106/25477 4525/5108/25478 4521/5114/25479 -f 4364/5115/25480 4355/5116/25481 4360/5110/25482 -f 4360/5110/25483 4362/5109/25484 4364/5115/25485 -f 4365/5117/25486 4364/5115/25487 4362/5109/25488 -f 4362/5109/25489 4363/5111/25490 4365/5117/25491 -f 4408/5118/25492 4390/5119/25493 4410/5113/25494 -f 4410/5113/25495 4409/5112/25496 4408/5118/25497 -f 4386/5120/25498 4408/5118/25499 4409/5112/25500 -f 4409/5112/25501 4521/5114/25502 4386/5120/25503 -f 4384/5121/25504 4391/5122/25505 4390/5119/25506 -f 4390/5119/25507 4408/5118/25508 4384/5121/25509 -f 4385/5123/25510 4384/5121/25511 4408/5118/25512 -f 4408/5118/25513 4386/5120/25514 4385/5123/25515 -f 4364/5115/25516 4365/5117/25517 4391/5122/25518 -f 4391/5122/25519 4384/5121/25520 4364/5115/25521 -f 4355/5116/25522 4364/5115/25523 4384/5121/25524 -f 4384/5121/25525 4385/5123/25526 4355/5116/25527 -f 4475/5091/25528 4482/5085/25529 4485/5084/25530 -f 4485/5084/25531 4476/5092/25532 4475/5091/25533 -f 4487/5082/25534 4482/5085/25535 4483/5124/25536 -f 4483/5124/25537 4488/5125/25538 4487/5082/25539 -f 4533/5126/25540 4532/5086/25541 4487/5082/25542 -f 4487/5082/25543 4488/5125/25544 4533/5126/25545 -f 4534/5127/25546 4522/5088/25547 4532/5086/25548 -f 4532/5086/25549 4533/5126/25550 4534/5127/25551 -f 4527/5128/25552 4525/5108/25553 4522/5088/25554 -f 4522/5088/25555 4534/5127/25556 4527/5128/25557 -f 4525/5108/25558 4527/5128/25559 4520/5129/25560 -f 4520/5129/25561 4521/5114/25562 4525/5108/25563 -f 4521/5114/25564 4520/5129/25565 4387/5130/25566 -f 4387/5130/25567 4386/5120/25568 4521/5114/25569 -f 4386/5120/25570 4387/5130/25571 4349/5131/25572 -f 4349/5131/25573 4385/5123/25574 4386/5120/25575 -f 4354/5132/25576 4355/5116/25577 4385/5123/25578 -f 4385/5123/25579 4349/5131/25580 4354/5132/25581 -f 4353/5133/25582 4360/5110/25583 4355/5116/25584 -f 4355/5116/25585 4354/5132/25586 4353/5133/25587 -f 4360/5110/25588 4353/5133/25589 4352/5134/25590 -f 4352/5134/25591 4359/5104/25592 4360/5110/25593 -f 4359/5104/25594 4352/5134/25595 4356/5135/25596 -f 4356/5135/25597 4358/5101/25598 4359/5104/25599 -f 4474/5090/25600 4358/5101/25601 4423/5136/25602 -f 4423/5136/25603 4472/5137/25604 4474/5090/25605 -f 4474/5090/25606 4472/5137/25607 4477/5138/25608 -f 4477/5138/25609 4475/5091/25610 4474/5090/25611 -f 4477/5138/25612 4483/5124/25613 4482/5085/25614 -f 4482/5085/25615 4475/5091/25616 4477/5138/25617 -f 4483/5124/25618 4477/5138/25619 4479/5139/25620 -f 4479/5139/25621 4484/5140/25622 4483/5124/25623 -f 4356/5135/25624 4352/5134/25625 4176/5141/25626 -f 4176/5141/25627 4357/5142/25628 4356/5135/25629 -f 4346/5143/25630 4356/5135/25631 4357/5142/25632 -f 4357/5142/25633 4345/5144/25634 4346/5143/25635 -f 4477/5138/25636 4472/5137/25637 4473/5145/25638 -f 4473/5145/25639 4479/5139/25640 4477/5138/25641 -f 4427/5146/25642 4428/5147/25643 4445/5148/25644 -f 4445/5148/25645 4473/5145/25646 4427/5146/25647 -f 4473/5145/25648 4445/5148/25649 4478/5149/25650 -f 4478/5149/25651 4479/5139/25652 4473/5145/25653 -f 4478/5149/25654 4445/5148/25655 4446/5150/25656 -f 4446/5150/25657 4447/5151/25658 4478/5149/25659 -f 4446/5150/25660 4445/5148/25661 4428/5147/25662 -f 4428/5147/25663 4426/5152/25664 4446/5150/25665 -f 4351/5153/25666 4176/5141/25667 4352/5134/25668 -f 4352/5134/25669 4353/5133/25670 4351/5153/25671 -f 4350/5154/25672 4349/5131/25673 4387/5130/25674 -f 4387/5130/25675 4517/5155/25676 4350/5154/25677 -f 4350/5154/25678 4348/5156/25679 4354/5132/25680 -f 4354/5132/25681 4349/5131/25682 4350/5154/25683 -f 4348/5156/25684 4351/5153/25685 4353/5133/25686 -f 4353/5133/25687 4354/5132/25688 4348/5156/25689 -f 4534/5127/25690 4535/5157/25691 4528/5158/25692 -f 4528/5158/25693 4527/5128/25694 4534/5127/25695 -f 4528/5158/25696 4526/5159/25697 4520/5129/25698 -f 4520/5129/25699 4527/5128/25700 4528/5158/25701 -f 4520/5129/25702 4526/5159/25703 4517/5155/25704 -f 4517/5155/25705 4387/5130/25706 4520/5129/25707 -f 4534/5127/25708 4533/5126/25709 4536/5160/25710 -f 4536/5160/25711 4535/5157/25712 4534/5127/25713 -f 4420/5161/25714 4346/5143/25715 4345/5144/25716 -f 4345/5144/25717 4415/5162/25718 4420/5161/25719 -f 4426/5152/25720 4428/5147/25721 4421/5163/25722 -f 4421/5163/25723 4417/5164/25724 4426/5152/25725 -f 4420/5161/25726 4415/5162/25727 4417/5164/25728 -f 4417/5164/25729 4421/5163/25730 4420/5161/25731 -f 4417/5164/25732 4415/5162/25733 4416/5165/25734 -f 4416/5165/25735 4418/5166/25736 4417/5164/25737 -f 4416/5165/25738 4210/4906/25739 4216/4905/25740 -f 4216/4905/25741 4418/5166/25742 4416/5165/25743 -f 4212/4907/25744 4210/4906/25745 4416/5165/25746 -f 4416/5165/25747 4415/5162/25748 4212/4907/25749 -f 4124/4908/25750 4212/4907/25751 4415/5162/25752 -f 4415/5162/25753 4345/5144/25754 4124/4908/25755 -f 4427/5146/25756 4420/5161/25757 4421/5163/25758 -f 4421/5163/25759 4428/5147/25760 4427/5146/25761 -f 4420/5161/25762 4427/5146/25763 4423/5136/25764 -f 4423/5136/25765 4346/5143/25766 4420/5161/25767 -f 4125/4909/25768 4124/4908/25769 4345/5144/25770 -f 4345/5144/25771 4357/5142/25772 4125/4909/25773 -f 4174/4910/25774 4125/4909/25775 4357/5142/25776 -f 4357/5142/25777 4176/5141/25778 4174/4910/25779 -f 4178/4911/25780 4174/4910/25781 4176/5141/25782 -f 4176/5141/25783 4351/5153/25784 4178/4911/25785 -f 4351/5153/25786 4348/5156/25787 4132/4912/25788 -f 4132/4912/25789 4178/4911/25790 4351/5153/25791 -f 4132/4912/25792 4348/5156/25793 4347/5167/25794 -f 4347/5167/25795 4130/4913/25796 4132/4912/25797 -f 4348/5156/25798 4350/5154/25799 4514/5168/25800 -f 4514/5168/25801 4347/5167/25802 4348/5156/25803 -f 4516/5169/25804 4514/5168/25805 4350/5154/25806 -f 4350/5154/25807 4517/5155/25808 4516/5169/25809 -f 4519/5170/25810 4516/5169/25811 4517/5155/25812 -f 4517/5155/25813 4526/5159/25814 4519/5170/25815 -f 4519/5170/25816 4526/5159/25817 4528/5158/25818 -f 4528/5158/25819 4530/5171/25820 4519/5170/25821 -f 4540/5172/25822 4530/5171/25823 4528/5158/25824 -f 4528/5158/25825 4535/5157/25826 4540/5172/25827 -f 4489/5173/25828 4536/5160/25829 4533/5126/25830 -f 4533/5126/25831 4488/5125/25832 4489/5173/25833 -f 4484/5140/25834 4489/5173/25835 4488/5125/25836 -f 4488/5125/25837 4483/5124/25838 4484/5140/25839 -f 4535/5157/25840 4536/5160/25841 4537/5174/25842 -f 4537/5174/25843 4540/5172/25844 4535/5157/25845 -f 4510/5175/25846 4537/5174/25847 4536/5160/25848 -f 4536/5160/25849 4489/5173/25850 4510/5175/25851 -f 4502/5176/25852 4510/5175/25853 4489/5173/25854 -f 4489/5173/25855 4484/5140/25856 4502/5176/25857 -f 4479/5139/25858 4478/5149/25859 4480/5177/25860 -f 4480/5177/25861 4484/5140/25862 4479/5139/25863 -f 4484/5140/25864 4480/5177/25865 4500/5178/25866 -f 4500/5178/25867 4502/5176/25868 4484/5140/25869 -f 4481/5179/25870 4480/5177/25871 4478/5149/25872 -f 4478/5149/25873 4447/5151/25874 4481/5179/25875 -f 4426/5152/25876 4417/5164/25877 4434/5180/25878 -f 4434/5180/25879 4422/5181/25880 4426/5152/25881 -f 4447/5151/25882 4446/5150/25883 4448/5182/25884 -f 4448/5182/25885 4441/5183/25886 4447/5151/25887 -f 4426/5152/25888 4422/5181/25889 4448/5182/25890 -f 4448/5182/25891 4446/5150/25892 4426/5152/25893 -f 4418/5166/25894 4419/5184/25895 4434/5180/25896 -f 4434/5180/25897 4417/5164/25898 4418/5166/25899 -f 4216/4905/25900 4217/4932/25901 4419/5184/25902 -f 4419/5184/25903 4418/5166/25904 4216/4905/25905 -f 4481/5179/25906 4447/5151/25907 4441/5183/25908 -f 4441/5183/25909 4449/5185/25910 4481/5179/25911 -f 4449/5185/25912 4441/5183/25913 4439/5186/25914 -f 4439/5186/25915 4444/5187/25916 4449/5185/25917 -f 4444/5187/25918 4439/5186/25919 4429/5188/25920 -f 4429/5188/25921 4436/5189/25922 4444/5187/25923 -f 4247/4938/25924 4429/5188/25925 4430/5190/25926 -f 4430/5190/25927 4244/4939/25928 4247/4938/25929 -f 4217/4932/25930 4244/4939/25931 4430/5190/25932 -f 4430/5190/25933 4419/5184/25934 4217/4932/25935 -f 4422/5181/25936 4434/5180/25937 4435/5191/25938 -f 4435/5191/25939 4424/5192/25940 4422/5181/25941 -f 4441/5183/25942 4448/5182/25943 4442/5193/25944 -f 4442/5193/25945 4443/5194/25946 4441/5183/25947 -f 4424/5192/25948 4442/5193/25949 4448/5182/25950 -f 4448/5182/25951 4422/5181/25952 4424/5192/25953 -f 4419/5184/25954 4430/5190/25955 4435/5191/25956 -f 4435/5191/25957 4434/5180/25958 4419/5184/25959 -f 4430/5190/25960 4429/5188/25961 4431/5195/25962 -f 4431/5195/25963 4432/5196/25964 4430/5190/25965 -f 4439/5186/25966 4440/5197/25967 4431/5195/25968 -f 4431/5195/25969 4429/5188/25970 4439/5186/25971 -f 4435/5191/25972 4430/5190/25973 4432/5196/25974 -f 4432/5196/25975 4433/5198/25976 4435/5191/25977 -f 4435/5191/25978 4433/5198/25979 4425/5199/25980 -f 4425/5199/25981 4424/5192/25982 4435/5191/25983 -f 4443/5194/25984 4440/5197/25985 4439/5186/25986 -f 4439/5186/25987 4441/5183/25988 4443/5194/25989 -f 4442/5193/25990 4424/5192/25991 4425/5199/25992 -f 4425/5199/25993 4443/5194/25994 4442/5193/25995 -f 4425/5199/25996 4433/5198/25997 4440/5197/25998 -f 4440/5197/25999 4443/5194/26000 4425/5199/26001 -f 4432/5196/26002 4431/5195/26003 4440/5197/26004 -f 4440/5197/26005 4433/5198/26006 4432/5196/26007 -f 4502/5176/26008 4500/5178/26009 4501/5200/26010 -f 4501/5200/26011 4503/5201/26012 4502/5176/26013 -f 4507/5202/26014 4509/5203/26015 4503/5201/26016 -f 4503/5201/26017 4501/5200/26018 4507/5202/26019 -f 4509/5203/26020 4507/5202/26021 4505/5204/26022 -f 4505/5204/26023 4508/5205/26024 4509/5203/26025 -f 4621/5206/26026 4508/5205/26027 4505/5204/26028 -f 4505/5204/26029 4471/5207/26030 4621/5206/26031 -f 4621/5206/26032 4471/5207/26033 4469/5208/26034 -f 4469/5208/26035 4620/5209/26036 4621/5206/26037 -f 4457/5210/26038 4617/5211/26039 4620/5209/26040 -f 4620/5209/26041 4469/5208/26042 4457/5210/26043 -f 4457/5210/26044 4454/5212/26045 4616/5213/26046 -f 4616/5213/26047 4617/5211/26048 4457/5210/26049 -f 4480/5177/26050 4481/5179/26051 4492/5214/26052 -f 4492/5214/26053 4500/5178/26054 4480/5177/26055 -f 4500/5178/26056 4492/5214/26057 4499/5215/26058 -f 4499/5215/26059 4501/5200/26060 4500/5178/26061 -f 4501/5200/26062 4499/5215/26063 4506/5216/26064 -f 4506/5216/26065 4507/5202/26066 4501/5200/26067 -f 4507/5202/26068 4506/5216/26069 4504/5217/26070 -f 4504/5217/26071 4505/5204/26072 4507/5202/26073 -f 4505/5204/26074 4504/5217/26075 4470/5218/26076 -f 4470/5218/26077 4471/5207/26078 4505/5204/26079 -f 4471/5207/26080 4470/5218/26081 4468/5219/26082 -f 4468/5219/26083 4469/5208/26084 4471/5207/26085 -f 4469/5208/26086 4468/5219/26087 4456/5220/26088 -f 4456/5220/26089 4457/5210/26090 4469/5208/26091 -f 4272/4971/26092 4270/4973/26093 4454/5212/26094 -f 4454/5212/26095 4455/5221/26096 4272/4971/26097 -f 4470/5218/26098 4504/5217/26099 4493/5222/26100 -f 4493/5222/26101 4466/5223/26102 4470/5218/26103 -f 4470/5218/26104 4466/5223/26105 4462/5224/26106 -f 4462/5224/26107 4468/5219/26108 4470/5218/26109 -f 4468/5219/26110 4462/5224/26111 4453/5225/26112 -f 4453/5225/26113 4456/5220/26114 4468/5219/26115 -f 4494/5226/26116 4493/5222/26117 4504/5217/26118 -f 4504/5217/26119 4506/5216/26120 4494/5226/26121 -f 4499/5215/26122 4495/5227/26123 4494/5226/26124 -f 4494/5226/26125 4506/5216/26126 4499/5215/26127 -f 4495/5227/26128 4499/5215/26129 4492/5214/26130 -f 4492/5214/26131 4490/5228/26132 4495/5227/26133 -f 4464/5229/26134 4490/5228/26135 4492/5214/26136 -f 4492/5214/26137 4481/5179/26138 4464/5229/26139 -f 4450/5230/26140 4464/5229/26141 4481/5179/26142 -f 4481/5179/26143 4449/5185/26144 4450/5230/26145 -f 4450/5230/26146 4449/5185/26147 4444/5187/26148 -f 4444/5187/26149 4438/5231/26150 4450/5230/26151 -f 4437/5232/26152 4438/5231/26153 4444/5187/26154 -f 4444/5187/26155 4436/5189/26156 4437/5232/26157 -f 4249/4985/26158 4437/5232/26159 4436/5189/26160 -f 4436/5189/26161 4248/4986/26162 4249/4985/26163 -f 4459/5233/26164 4451/5234/26165 4452/5235/26166 -f 4452/5235/26167 4453/5225/26168 4459/5233/26169 -f 4461/5236/26170 4459/5233/26171 4453/5225/26172 -f 4453/5225/26173 4462/5224/26174 4461/5236/26175 -f 4467/5237/26176 4461/5236/26177 4462/5224/26178 -f 4462/5224/26179 4466/5223/26180 4467/5237/26181 -f 4467/5237/26182 4466/5223/26183 4493/5222/26184 -f 4493/5222/26185 4496/5238/26186 4467/5237/26187 -f 4494/5226/26188 4497/5239/26189 4496/5238/26190 -f 4496/5238/26191 4493/5222/26192 4494/5226/26193 -f 4495/5227/26194 4498/5240/26195 4497/5239/26196 -f 4497/5239/26197 4494/5226/26198 4495/5227/26199 -f 4490/5228/26200 4491/5241/26201 4498/5240/26202 -f 4498/5240/26203 4495/5227/26204 4490/5228/26205 -f 4465/5242/26206 4491/5241/26207 4490/5228/26208 -f 4490/5228/26209 4464/5229/26210 4465/5242/26211 -f 4463/5243/26212 4465/5242/26213 4464/5229/26214 -f 4464/5229/26215 4450/5230/26216 4463/5243/26217 -f 4460/5244/26218 4463/5243/26219 4450/5230/26220 -f 4450/5230/26221 4438/5231/26222 4460/5244/26223 -f 4458/5245/26224 4460/5244/26225 4438/5231/26226 -f 4438/5231/26227 4437/5232/26228 4458/5245/26229 -f 4249/4985/26230 4250/5000/26231 4458/5245/26232 -f 4458/5245/26233 4437/5232/26234 4249/4985/26235 -f 4498/5240/26236 4491/5241/26237 4496/5238/26238 -f 4496/5238/26239 4497/5239/26240 4498/5240/26241 -f 4467/5237/26242 4496/5238/26243 4491/5241/26244 -f 4491/5241/26245 4465/5242/26246 4467/5237/26247 -f 4461/5236/26248 4467/5237/26249 4465/5242/26250 -f 4465/5242/26251 4463/5243/26252 4461/5236/26253 -f 4459/5233/26254 4461/5236/26255 4463/5243/26256 -f 4463/5243/26257 4460/5244/26258 4459/5233/26259 -f 4270/4973/26260 4555/5001/26261 4616/5213/26262 -f 4616/5213/26263 4454/5212/26264 4270/4973/26265 -f 4454/5212/26266 4457/5210/26267 4456/5220/26268 -f 4456/5220/26269 4455/5221/26270 4454/5212/26271 -f 4455/5221/26272 4456/5220/26273 4453/5225/26274 -f 4453/5225/26275 4452/5235/26276 4455/5221/26277 -f 4451/5234/26278 4264/5003/26279 4266/5002/26280 -f 4266/5002/26281 4452/5235/26282 4451/5234/26283 -f 4460/5244/26284 4458/5245/26285 4451/5234/26286 -f 4451/5234/26287 4459/5233/26288 4460/5244/26289 -f 4451/5234/26290 4458/5245/26291 4250/5000/26292 -f 4250/5000/26293 4264/5003/26294 4451/5234/26295 -f 4502/5176/26296 4503/5201/26297 4512/5246/26298 -f 4512/5246/26299 4510/5175/26300 4502/5176/26301 -f 4510/5175/26302 4512/5246/26303 4538/5247/26304 -f 4538/5247/26305 4537/5174/26306 4510/5175/26307 -f 4537/5174/26308 4538/5247/26309 4541/5248/26310 -f 4541/5248/26311 4540/5172/26312 4537/5174/26313 -f 4511/5249/26314 4512/5246/26315 4503/5201/26316 -f 4503/5201/26317 4509/5203/26318 4511/5249/26319 -f 4629/5250/26320 4511/5249/26321 4509/5203/26322 -f 4509/5203/26323 4508/5205/26324 4629/5250/26325 -f 4628/5251/26326 4629/5250/26327 4508/5205/26328 -f 4508/5205/26329 4621/5206/26330 4628/5251/26331 -f 4622/5252/26332 4628/5251/26333 4621/5206/26334 -f 4621/5206/26335 4620/5209/26336 4622/5252/26337 -f 4619/5253/26338 4622/5252/26339 4620/5209/26340 -f 4620/5209/26341 4617/5211/26342 4619/5253/26343 -f 4618/5254/26344 4619/5253/26345 4617/5211/26346 -f 4617/5211/26347 4616/5213/26348 4618/5254/26349 -f 4618/5254/26350 4616/5213/26351 4555/5001/26352 -f 4555/5001/26353 4557/5013/26354 4618/5254/26355 -f 4539/5255/26356 4538/5247/26357 4512/5246/26358 -f 4512/5246/26359 4511/5249/26360 4539/5255/26361 -f 4629/5250/26362 4638/5256/26363 4539/5255/26364 -f 4539/5255/26365 4511/5249/26366 4629/5250/26367 -f 4630/5257/26368 4638/5256/26369 4629/5250/26370 -f 4629/5250/26371 4628/5251/26372 4630/5257/26373 -f 4628/5251/26374 4622/5252/26375 4625/5258/26376 -f 4625/5258/26377 4630/5257/26378 4628/5251/26379 -f 4624/5259/26380 4625/5258/26381 4622/5252/26382 -f 4622/5252/26383 4619/5253/26384 4624/5259/26385 -f 4623/5260/26386 4624/5259/26387 4619/5253/26388 -f 4619/5253/26389 4618/5254/26390 4623/5260/26391 -f 4618/5254/26392 4557/5013/26393 4560/5020/26394 -f 4560/5020/26395 4623/5260/26396 4618/5254/26397 -f 4538/5247/26398 4539/5255/26399 4642/5261/26400 -f 4642/5261/26401 4543/5262/26402 4538/5247/26403 -f 4639/5263/26404 4642/5261/26405 4539/5255/26406 -f 4539/5255/26407 4638/5256/26408 4639/5263/26409 -f 4640/5264/26410 4639/5263/26411 4638/5256/26412 -f 4638/5256/26413 4630/5257/26414 4640/5264/26415 -f 4626/5265/26416 4640/5264/26417 4630/5257/26418 -f 4630/5257/26419 4625/5258/26420 4626/5265/26421 -f 4632/5266/26422 4626/5265/26423 4625/5258/26424 -f 4625/5258/26425 4624/5259/26426 4632/5266/26427 -f 4631/5267/26428 4632/5266/26429 4624/5259/26430 -f 4624/5259/26431 4623/5260/26432 4631/5267/26433 -f 4631/5267/26434 4623/5260/26435 4560/5020/26436 -f 4560/5020/26437 4564/5028/26438 4631/5267/26439 -f 4538/5247/26440 4543/5262/26441 4542/5268/26442 -f 4542/5268/26443 4541/5248/26444 4538/5247/26445 -f 4540/5172/26446 4541/5248/26447 4531/5269/26448 -f 4531/5269/26449 4530/5171/26450 4540/5172/26451 -f 4530/5171/26452 4531/5269/26453 4529/5271/26454 -f 4529/5271/26455 4519/5170/26456 4530/5171/26457 -f 4519/5170/26458 4529/5271/26459 4518/5272/26460 -f 4518/5272/26461 4516/5169/26462 4519/5170/26463 -f 4516/5169/26464 4518/5272/26465 4515/5276/26466 -f 4515/5276/26467 4514/5168/26468 4516/5169/26469 -f 4513/5313/26470 4347/5167/26471 4514/5168/26472 -f 4514/5168/26473 4515/5276/26474 4513/5313/26475 -f 4347/5167/26476 4513/5313/26477 4326/5035/26478 -f 4326/5035/26479 4130/4913/26480 4347/5167/26481 -f 4632/5266/26482 4631/5267/26483 4633/5314/26484 -f 4633/5314/26485 4634/5315/26486 4632/5266/26487 -f 4632/5266/26488 4634/5315/26489 4627/5316/26490 -f 4627/5316/26491 4626/5265/26492 4632/5266/26493 -f 4640/5264/26494 4626/5265/26495 4627/5316/26496 -f 4627/5316/26497 4641/5317/26498 4640/5264/26499 -f 4649/5318/26500 4639/5263/26501 4640/5264/26502 -f 4640/5264/26503 4641/5317/26504 4649/5318/26505 -f 4649/5318/26506 4643/5319/26507 4642/5261/26508 -f 4642/5261/26509 4639/5263/26510 4649/5318/26511 -f 4642/5261/26512 4643/5319/26513 4544/5320/26514 -f 4544/5320/26515 4543/5262/26516 4642/5261/26517 -f 4543/5262/26518 4544/5320/26519 4698/5321/26520 -f 4698/5321/26521 4542/5268/26522 4543/5262/26523 -f 4698/5321/26524 4544/5320/26525 4701/5322/26526 -f 4701/5322/26527 4699/5323/26528 4698/5321/26529 -f 4701/5322/26530 4544/5320/26531 4643/5319/26532 -f 4643/5319/26533 4644/5324/26534 4701/5322/26535 -f 4643/5319/26536 4649/5318/26537 4647/5325/26538 -f 4647/5325/26539 4644/5324/26540 4643/5319/26541 -f 4649/5318/26542 4641/5317/26543 4635/5326/26544 -f 4635/5326/26545 4647/5325/26546 4649/5318/26547 -f 4627/5316/26548 4658/5327/26549 4635/5326/26550 -f 4635/5326/26551 4641/5317/26552 4627/5316/26553 -f 4654/5328/26554 4658/5327/26555 4627/5316/26556 -f 4627/5316/26557 4634/5315/26558 4654/5328/26559 -f 4653/5329/26560 4654/5328/26561 4634/5315/26562 -f 4634/5315/26563 4633/5314/26564 4653/5329/26565 -f 4605/5052/26566 4653/5329/26567 4633/5314/26568 -f 4633/5314/26569 4568/5053/26570 4605/5052/26571 -f 4700/5374/26572 4699/5375/26573 4701/5377/26574 -f 4701/5377/26575 4704/5378/26576 4700/5374/26577 -f 4648/5379/26578 4645/5380/26579 4644/5381/26580 -f 4644/5381/26581 4647/5382/26582 4648/5379/26583 -f 4636/5383/26584 4648/5379/26585 4647/5382/26586 -f 4647/5382/26587 4635/5384/26588 4636/5383/26589 -f 4635/5384/26590 4658/5385/26591 4659/5386/26592 -f 4659/5386/26593 4636/5383/26594 4635/5384/26595 -f 4655/5387/26596 4659/5386/26597 4658/5385/26598 -f 4658/5385/26599 4654/5388/26600 4655/5387/26601 -f 4656/5389/26602 4655/5387/26603 4654/5388/26604 -f 4654/5388/26605 4653/5390/26606 4656/5389/26607 -f 4606/5460/26608 4656/5389/26609 4653/5390/26610 -f 4653/5390/26611 4605/5461/26612 4606/5460/26613 -f 4656/5389/26614 4606/5460/26615 4615/5462/26616 -f 4615/5462/26617 4663/5391/26618 4656/5389/26619 -f 4656/5389/26620 4663/5391/26621 4657/5392/26622 -f 4657/5392/26623 4655/5387/26624 4656/5389/26625 -f 4655/5387/26626 4657/5392/26627 4660/5393/26628 -f 4660/5393/26629 4659/5386/26630 4655/5387/26631 -f 4637/5394/26632 4636/5383/26633 4659/5386/26634 -f 4659/5386/26635 4660/5393/26636 4637/5394/26637 -f 4648/5379/26638 4636/5383/26639 4637/5394/26640 -f 4637/5394/26641 4650/5396/26642 4648/5379/26643 -f 4646/5397/26644 4645/5380/26645 4648/5379/26646 -f 4648/5379/26647 4650/5396/26648 4646/5397/26649 -f 4645/5380/26650 4646/5397/26651 4702/5398/26652 -f 4702/5398/26653 4644/5381/26654 4645/5380/26655 -f 4701/5377/26656 4644/5381/26657 4702/5398/26658 -f 4702/5398/26659 4704/5378/26660 4701/5377/26661 -f 4696/5399/26662 4700/5374/26663 4705/5400/26664 -f 4705/5400/26665 4697/5401/26666 4696/5399/26667 -f 4729/5402/26668 4703/5403/26669 4704/5378/26670 -f 4704/5378/26671 4702/5398/26672 4729/5402/26673 -f 4730/5404/26674 4729/5402/26675 4702/5398/26676 -f 4702/5398/26677 4646/5397/26678 4730/5404/26679 -f 4652/5405/26680 4730/5404/26681 4646/5397/26682 -f 4646/5397/26683 4650/5396/26684 4652/5405/26685 -f 4651/5406/26686 4652/5405/26687 4650/5396/26688 -f 4650/5396/26689 4637/5394/26690 4651/5406/26691 -f 4670/5407/26692 4651/5406/26693 4637/5394/26694 -f 4637/5394/26695 4660/5393/26696 4670/5407/26697 -f 4661/5408/26698 4670/5407/26699 4660/5393/26700 -f 4660/5393/26701 4657/5392/26702 4661/5408/26703 -f 4665/5409/26704 4661/5408/26705 4657/5392/26706 -f 4657/5392/26707 4663/5391/26708 4665/5409/26709 -f 4662/5410/26710 4663/5391/26711 4615/5462/26712 -f 4615/5462/26713 4613/5463/26714 4662/5410/26715 -f 4664/5411/26716 4665/5409/26717 4663/5391/26718 -f 4663/5391/26719 4662/5410/26720 4664/5411/26721 -f 4669/5412/26722 4666/5413/26723 4665/5409/26724 -f 4665/5409/26725 4664/5411/26726 4669/5412/26727 -f 4671/5414/26728 4661/5408/26729 4665/5409/26730 -f 4665/5409/26731 4666/5413/26732 4671/5414/26733 -f 4672/5415/26734 4670/5407/26735 4661/5408/26736 -f 4661/5408/26737 4671/5414/26738 4672/5415/26739 -f 4673/5416/26740 4651/5406/26741 4670/5407/26742 -f 4670/5407/26743 4672/5415/26744 4673/5416/26745 -f 4733/5417/26746 4652/5405/26747 4651/5406/26748 -f 4651/5406/26749 4673/5416/26750 4733/5417/26751 -f 4652/5405/26752 4733/5417/26753 4731/5418/26754 -f 4731/5418/26755 4730/5404/26756 4652/5405/26757 -f 4732/5419/26758 4729/5402/26759 4730/5404/26760 -f 4730/5404/26761 4731/5418/26762 4732/5419/26763 -f 4729/5402/26764 4732/5419/26765 4706/5420/26766 -f 4706/5420/26767 4703/5403/26768 4729/5402/26769 -f 4700/5374/26770 4704/5378/26771 4703/5403/26772 -f 4703/5403/26773 4705/5400/26774 4700/5374/26775 -f 4703/5403/26776 4706/5420/26777 4697/5401/26778 -f 4697/5401/26779 4705/5400/26780 4703/5403/26781 -f 4696/5399/26782 4697/5401/26783 4708/5421/26784 -f 4708/5421/26785 4707/5422/26786 4696/5399/26787 -f 4707/5422/26788 4708/5421/26789 4693/5465/26790 -f 4693/5465/26791 4690/5464/26792 4707/5422/26793 -f 4668/5423/26794 4667/5424/26795 4666/5413/26796 -f 4666/5413/26797 4669/5412/26798 4668/5423/26799 -f 4671/5414/26800 4666/5413/26801 4667/5424/26802 -f 4667/5424/26803 4676/5425/26804 4671/5414/26805 -f 4671/5414/26806 4676/5425/26807 4674/5426/26808 -f 4674/5426/26809 4672/5415/26810 4671/5414/26811 -f 4673/5416/26812 4672/5415/26813 4674/5426/26814 -f 4674/5426/26815 4740/5427/26816 4673/5416/26817 -f 4673/5416/26818 4740/5427/26819 4734/5428/26820 -f 4734/5428/26821 4733/5417/26822 4673/5416/26823 -f 4733/5417/26824 4734/5428/26825 4737/5429/26826 -f 4737/5429/26827 4731/5418/26828 4733/5417/26829 -f 4731/5418/26830 4737/5429/26831 4735/5430/26832 -f 4735/5430/26833 4732/5419/26834 4731/5418/26835 -f 4732/5419/26836 4735/5430/26837 4736/5431/26838 -f 4736/5431/26839 4706/5420/26840 4732/5419/26841 -f 4706/5420/26842 4736/5431/26843 4710/5432/26844 -f 4710/5432/26845 4697/5401/26846 4706/5420/26847 -f 4697/5401/26848 4710/5432/26849 4709/5433/26850 -f 4709/5433/26851 4708/5421/26852 4697/5401/26853 -f 4695/5466/26854 4693/5465/26855 4708/5421/26856 -f 4708/5421/26857 4709/5433/26858 4695/5466/26859 -f 4676/5425/26860 4667/5424/26861 4668/5423/26862 -f 4668/5423/26863 4677/5434/26864 4676/5425/26865 -f 4676/5425/26866 4677/5434/26867 4675/5435/26868 -f 4675/5435/26869 4674/5426/26870 4676/5425/26871 -f 4674/5426/26872 4675/5435/26873 4741/5436/26874 -f 4741/5436/26875 4740/5427/26876 4674/5426/26877 -f 4740/5427/26878 4741/5436/26879 4742/5437/26880 -f 4742/5437/26881 4734/5428/26882 4740/5427/26883 -f 4739/5438/26884 4737/5429/26885 4734/5428/26886 -f 4734/5428/26887 4742/5437/26888 4739/5438/26889 -f 4735/5430/26890 4737/5429/26891 4739/5438/26892 -f 4739/5438/26893 4738/5439/26894 4735/5430/26895 -f 4735/5430/26896 4738/5439/26897 4744/5440/26898 -f 4744/5440/26899 4736/5431/26900 4735/5430/26901 -f 4745/5441/26902 4710/5432/26903 4736/5431/26904 -f 4736/5431/26905 4744/5440/26906 4745/5441/26907 -f 4710/5432/26908 4745/5441/26909 4743/5442/26910 -f 4743/5442/26911 4709/5433/26912 4710/5432/26913 -f 4709/5433/26914 4743/5442/26915 4728/5467/26916 -f 4728/5467/26917 4695/5466/26918 4709/5433/26919 -f 4391/5122/26920 4365/5117/26921 4366/5330/26922 -f 4366/5330/26923 4388/5331/26924 4391/5122/26925 -f 4369/5335/26926 4366/5330/26927 4365/5117/26928 -f 4365/5117/26929 4363/5111/26930 4369/5335/26931 -f 4374/5105/26932 4375/5336/26933 4369/5335/26934 -f 4369/5335/26935 4363/5111/26936 4374/5105/26937 -f 4373/5102/26938 4376/5337/26939 4375/5336/26940 -f 4375/5336/26941 4374/5105/26942 4373/5102/26943 -f 4372/5099/26944 4377/5338/26945 4376/5337/26946 -f 4376/5337/26947 4373/5102/26948 4372/5099/26949 -f 4381/5095/26950 4382/5339/26951 4377/5338/26952 -f 4377/5338/26953 4372/5099/26954 4381/5095/26955 -f 4394/5094/26956 4395/5340/26957 4382/5339/26958 -f 4382/5339/26959 4381/5095/26960 4394/5094/26961 -f 4398/5346/26962 4395/5340/26963 4394/5094/26964 -f 4394/5094/26965 4397/5096/26966 4398/5346/26967 -f 4412/5097/26968 4402/5376/26969 4398/5346/26970 -f 4398/5346/26971 4397/5096/26972 4412/5097/26973 -f 4413/5098/26974 4403/5395/26975 4402/5376/26976 -f 4402/5376/26977 4412/5097/26978 4413/5098/26979 -f 4414/5107/26980 4404/5443/26981 4403/5395/26982 -f 4403/5395/26983 4413/5098/26984 4414/5107/26985 -f 4410/5113/26986 4400/5444/26987 4404/5443/26988 -f 4404/5443/26989 4414/5107/26990 4410/5113/26991 -f 4390/5119/26992 4392/5445/26993 4400/5444/26994 -f 4400/5444/26995 4410/5113/26996 4390/5119/26997 -f 4390/5119/26998 4391/5122/26999 4388/5331/27000 -f 4388/5331/27001 4392/5445/27002 4390/5119/27003 -f 4388/5331/27004 4366/5330/27005 4371/5446/27006 -f 4371/5446/27007 4389/5447/27008 4388/5331/27009 -f 4369/5335/27010 4370/5448/27011 4371/5446/27012 -f 4371/5446/27013 4366/5330/27014 4369/5335/27015 -f 4375/5336/27016 4378/5449/27017 4370/5448/27018 -f 4370/5448/27019 4369/5335/27020 4375/5336/27021 -f 4376/5337/27022 4379/5450/27023 4378/5449/27024 -f 4378/5449/27025 4375/5336/27026 4376/5337/27027 -f 4377/5338/27028 4380/5451/27029 4379/5450/27030 -f 4379/5450/27031 4376/5337/27032 4377/5338/27033 -f 4382/5339/27034 4383/5452/27035 4380/5451/27036 -f 4380/5451/27037 4377/5338/27038 4382/5339/27039 -f 4396/5453/27040 4383/5452/27041 4382/5339/27042 -f 4382/5339/27043 4395/5340/27044 4396/5453/27045 -f 4398/5346/27046 4399/5454/27047 4396/5453/27048 -f 4396/5453/27049 4395/5340/27050 4398/5346/27051 -f 4402/5376/27052 4405/5455/27053 4399/5454/27054 -f 4399/5454/27055 4398/5346/27056 4402/5376/27057 -f 4403/5395/27058 4406/5456/27059 4405/5455/27060 -f 4405/5455/27061 4402/5376/27062 4403/5395/27063 -f 4404/5443/27064 4407/5457/27065 4406/5456/27066 -f 4406/5456/27067 4403/5395/27068 4404/5443/27069 -f 4400/5444/27070 4401/5458/27071 4407/5457/27072 -f 4407/5457/27073 4404/5443/27074 4400/5444/27075 -f 4393/5459/27076 4401/5458/27077 4400/5444/27078 -f 4400/5444/27079 4392/5445/27080 4393/5459/27081 -f 4389/5447/27082 4393/5459/27083 4392/5445/27084 -f 4392/5445/27085 4388/5331/27086 4389/5447/27087 -f 4423/5136/27088 4427/5146/27089 4473/5145/27090 -f 4473/5145/27091 4472/5137/27092 4423/5136/27093 -f 4358/5101/27094 4356/5135/27095 4346/5143/27096 -f 4346/5143/27097 4423/5136/27098 4358/5101/27099 -f 4436/5189/27100 4429/5188/27101 4247/4938/27102 -f 4247/4938/27103 4248/4986/27104 4436/5189/27105 -f 4272/4971/27106 4455/5221/27107 4452/5235/27108 -f 4452/5235/27109 4266/5002/27110 4272/4971/27111 -f 4568/5053/27112 4633/5314/27113 4631/5267/27114 -f 4631/5267/27115 4564/5028/27116 4568/5053/27117 -f 4770/5468/27118 4771/5469/27119 4746/5470/27120 -f 4746/5470/27121 4747/5471/27122 4770/5468/27123 -f 4749/5472/27124 4748/5473/27125 4747/5471/27126 -f 4747/5471/27127 4746/5470/27128 4749/5472/27129 -f 4750/5475/27130 4748/5473/27131 4749/5472/27132 -f 4749/5472/27133 4751/5474/27134 4750/5475/27135 -f 4752/5477/27136 4750/5475/27137 4751/5474/27138 -f 4751/5474/27139 4753/5476/27140 4752/5477/27141 -f 4753/5476/27142 4755/5478/27143 4754/5479/27144 -f 4754/5479/27145 4752/5477/27146 4753/5476/27147 -f 4757/5480/27148 4754/5479/27149 4755/5478/27150 -f 4755/5478/27151 4756/5481/27152 4757/5480/27153 -f 4758/5482/27154 4759/5483/27155 4757/5480/27156 -f 4757/5480/27157 4756/5481/27158 4758/5482/27159 -f 4761/5485/27160 4759/5483/27161 4758/5482/27162 -f 4758/5482/27163 4760/5484/27164 4761/5485/27165 -f 4761/5485/27166 4760/5484/27167 4763/5487/27168 -f 4763/5487/27169 4762/5486/27170 4761/5485/27171 -f 4763/5487/27172 4765/5488/27173 4764/5489/27174 -f 4764/5489/27175 4762/5486/27176 4763/5487/27177 -f 4765/5488/27178 4767/5490/27179 4766/5491/27180 -f 4766/5491/27181 4764/5489/27182 4765/5488/27183 -f 4768/5493/27184 4766/5491/27185 4767/5490/27186 -f 4767/5490/27187 4769/5492/27188 4768/5493/27189 -f 4773/5495/27190 4771/5469/27191 4770/5468/27192 -f 4770/5468/27193 4772/5494/27194 4773/5495/27195 -f 4773/5495/27196 4772/5494/27197 4774/5496/27198 -f 4774/5496/27199 4775/5497/27200 4773/5495/27201 -f 4777/5499/27202 4775/5497/27203 4774/5496/27204 -f 4774/5496/27205 4776/5498/27206 4777/5499/27207 -f 4777/5499/27208 4776/5498/27209 4778/5500/27210 -f 4778/5500/27211 4779/5501/27212 4777/5499/27213 -f 4784/5503/27214 4785/5504/27215 4783/5505/27216 -f 4783/5505/27217 4782/5502/27218 4784/5503/27219 -f 4782/5502/27220 4783/5505/27221 4781/5506/27222 -f 4781/5506/27223 4780/5507/27224 4782/5502/27225 -f 4780/5507/27226 4781/5506/27227 4779/5501/27228 -f 4779/5501/27229 4778/5500/27230 4780/5507/27231 -f 4794/5509/27232 4795/5510/27233 4793/5511/27234 -f 4793/5511/27235 4792/5508/27236 4794/5509/27237 -f 4792/5508/27238 4793/5511/27239 4791/5512/27240 -f 4791/5512/27241 4790/5513/27242 4792/5508/27243 -f 4790/5513/27244 4791/5512/27245 4789/5514/27246 -f 4789/5514/27247 4788/5515/27248 4790/5513/27249 -f 4788/5515/27250 4789/5514/27251 4787/5516/27252 -f 4787/5516/27253 4786/5517/27254 4788/5515/27255 -f 4787/5516/27256 4785/5504/27257 4784/5503/27258 -f 4784/5503/27259 4786/5517/27260 4787/5516/27261 -f 4804/5519/27262 4768/5493/27263 4769/5492/27264 -f 4769/5492/27265 4805/5518/27266 4804/5519/27267 -f 4803/5520/27268 4802/5521/27269 4804/5519/27270 -f 4804/5519/27271 4805/5518/27272 4803/5520/27273 -f 4801/5522/27274 4800/5523/27275 4802/5521/27276 -f 4802/5521/27277 4803/5520/27278 4801/5522/27279 -f 4799/5524/27280 4798/5525/27281 4800/5523/27282 -f 4800/5523/27283 4801/5522/27284 4799/5524/27285 -f 4796/5526/27286 4798/5525/27287 4799/5524/27288 -f 4799/5524/27289 4797/5527/27290 4796/5526/27291 -f 4806/5528/27292 4800/5523/27293 4798/5525/27294 -f 4798/5525/27295 4807/5529/27296 4806/5528/27297 -f 4808/5530/27298 4807/5529/27299 4798/5525/27300 -f 4798/5525/27301 4796/5526/27302 4808/5530/27303 -f 4796/5526/27304 4794/5509/27305 4809/5531/27306 -f 4809/5531/27307 4808/5530/27308 4796/5526/27309 -f 4794/5509/27310 4792/5508/27311 4810/5532/27312 -f 4810/5532/27313 4809/5531/27314 4794/5509/27315 -f 4792/5508/27316 4790/5513/27317 4811/5533/27318 -f 4811/5533/27319 4810/5532/27320 4792/5508/27321 -f 4786/5517/27322 4813/5534/27323 4812/5535/27324 -f 4812/5535/27325 4788/5515/27326 4786/5517/27327 -f 4780/5507/27328 4815/5536/27329 4814/5537/27330 -f 4814/5537/27331 4782/5502/27332 4780/5507/27333 -f 4786/5517/27334 4784/5503/27335 4782/5502/27336 -f 4782/5502/27337 4813/5534/27338 4786/5517/27339 -f 4813/5534/27340 4782/5502/27341 4814/5537/27342 -f 4814/5537/27343 4812/5535/27344 4813/5534/27345 -f 4816/5538/27346 4802/5521/27347 4800/5523/27348 -f 4800/5523/27349 4806/5528/27350 4816/5538/27351 -f 4817/5539/27352 4804/5519/27353 4802/5521/27354 -f 4802/5521/27355 4816/5538/27356 4817/5539/27357 -f 4804/5519/27358 4817/5539/27359 4818/5540/27360 -f 4818/5540/27361 4768/5493/27362 4804/5519/27363 -f 4907/5541/27364 4766/5491/27365 4768/5493/27366 -f 4768/5493/27367 4818/5540/27368 4907/5541/27369 -f 4842/5542/27370 4764/5489/27371 4766/5491/27372 -f 4766/5491/27373 4907/5541/27374 4842/5542/27375 -f 4819/5543/27376 4762/5486/27377 4764/5489/27378 -f 4764/5489/27379 4842/5542/27380 4819/5543/27381 -f 4819/5543/27382 4759/5483/27383 4761/5485/27384 -f 4761/5485/27385 4762/5486/27386 4819/5543/27387 -f 4820/5544/27388 4757/5480/27389 4759/5483/27390 -f 4759/5483/27391 4819/5543/27392 4820/5544/27393 -f 4757/5480/27394 4820/5544/27395 4821/5545/27396 -f 4821/5545/27397 4754/5479/27398 4757/5480/27399 -f 4754/5479/27400 4821/5545/27401 4822/5546/27402 -f 4822/5546/27403 4752/5477/27404 4754/5479/27405 -f 4823/5547/27406 4750/5475/27407 4752/5477/27408 -f 4752/5477/27409 4822/5546/27410 4823/5547/27411 -f 4824/5548/27412 4748/5473/27413 4750/5475/27414 -f 4750/5475/27415 4823/5547/27416 4824/5548/27417 -f 4825/5549/27418 4747/5471/27419 4748/5473/27420 -f 4748/5473/27421 4824/5548/27422 4825/5549/27423 -f 4747/5471/27424 4825/5549/27425 4826/5550/27426 -f 4826/5550/27427 4770/5468/27428 4747/5471/27429 -f 4772/5494/27430 4770/5468/27431 4826/5550/27432 -f 4826/5550/27433 4827/5551/27434 4772/5494/27435 -f 4828/5552/27436 4829/5553/27437 4776/5498/27438 -f 4776/5498/27439 4774/5496/27440 4828/5552/27441 -f 4778/5500/27442 4776/5498/27443 4829/5553/27444 -f 4829/5553/27445 4830/5554/27446 4778/5500/27447 -f 4815/5536/27448 4780/5507/27449 4778/5500/27450 -f 4778/5500/27451 4830/5554/27452 4815/5536/27453 -f 4815/5536/27454 4831/5555/27455 4812/5535/27456 -f 4812/5535/27457 4814/5537/27458 4815/5536/27459 -f 4832/5556/27460 4833/5557/27461 4810/5532/27462 -f 4810/5532/27463 4811/5533/27464 4832/5556/27465 -f 4834/5558/27466 4831/5555/27467 4815/5536/27468 -f 4815/5536/27469 4830/5554/27470 4834/5558/27471 -f 4810/5532/27472 4833/5557/27473 4835/5559/27474 -f 4835/5559/27475 4809/5531/27476 4810/5532/27477 -f 4809/5531/27478 4835/5559/27479 4836/5560/27480 -f 4836/5560/27481 4808/5530/27482 4809/5531/27483 -f 4808/5530/27484 4836/5560/27485 4837/5561/27486 -f 4837/5561/27487 4807/5529/27488 4808/5530/27489 -f 4845/5562/27490 4806/5528/27491 4807/5529/27492 -f 4807/5529/27493 4837/5561/27494 4845/5562/27495 -f 4839/5563/27496 4817/5539/27497 4816/5538/27498 -f 4816/5538/27499 4838/5564/27500 4839/5563/27501 -f 4841/5565/27502 4840/5566/27503 4821/5545/27504 -f 4821/5545/27505 4820/5544/27506 4841/5565/27507 -f 4841/5565/27508 4820/5544/27509 4819/5543/27510 -f 4819/5543/27511 4842/5542/27512 4841/5565/27513 -f 4818/5540/27514 4906/5567/27515 4907/5541/27516 -f 4905/5569/27517 4906/5567/27518 4818/5540/27519 -f 4818/5540/27520 4843/5568/27521 4905/5569/27522 -f 4843/5568/27523 4818/5540/27524 4817/5539/27525 -f 4817/5539/27526 4839/5563/27527 4843/5568/27528 -f 4843/5568/27529 4839/5563/27530 4844/5570/27531 -f 4844/5570/27532 4840/5566/27533 4843/5568/27534 -f 4845/5562/27535 4838/5564/27536 4816/5538/27537 -f 4816/5538/27538 4806/5528/27539 4845/5562/27540 -f 4840/5566/27541 4844/5570/27542 4822/5546/27543 -f 4822/5546/27544 4821/5545/27545 4840/5566/27546 -f 4846/5571/27547 4844/5570/27548 4839/5563/27549 -f 4839/5563/27550 4838/5564/27551 4846/5571/27552 -f 4847/5572/27553 4846/5571/27554 4838/5564/27555 -f 4838/5564/27556 4845/5562/27557 4847/5572/27558 -f 4845/5562/27559 4837/5561/27560 4848/5573/27561 -f 4848/5573/27562 4847/5572/27563 4845/5562/27564 -f 4836/5560/27565 4849/5574/27566 4848/5573/27567 -f 4848/5573/27568 4837/5561/27569 4836/5560/27570 -f 4850/5575/27571 4849/5574/27572 4836/5560/27573 -f 4836/5560/27574 4835/5559/27575 4850/5575/27576 -f 4833/5557/27577 4832/5556/27578 4831/5555/27579 -f 4831/5555/27580 4834/5558/27581 4833/5557/27582 -f 4833/5557/27583 4834/5558/27584 4850/5575/27585 -f 4850/5575/27586 4835/5559/27587 4833/5557/27588 -f 4851/5576/27589 4834/5558/27590 4830/5554/27591 -f 4830/5554/27592 4829/5553/27593 4851/5576/27594 -f 4834/5558/27595 4851/5576/27596 4852/5577/27597 -f 4852/5577/27598 4850/5575/27599 4834/5558/27600 -f 4853/5578/27601 4852/5577/27602 4851/5576/27603 -f 4851/5576/27604 4829/5553/27605 4853/5578/27606 -f 4854/5579/27607 4853/5578/27608 4829/5553/27609 -f 4829/5553/27610 4828/5552/27611 4854/5579/27612 -f 4855/5580/27613 4854/5579/27614 4828/5552/27615 -f 4828/5552/27616 4827/5551/27617 4855/5580/27618 -f 4827/5551/27619 4826/5550/27620 4856/5581/27621 -f 4856/5581/27622 4855/5580/27623 4827/5551/27624 -f 4856/5581/27625 4826/5550/27626 4825/5549/27627 -f 4825/5549/27628 4857/5582/27629 4856/5581/27630 -f 4858/5583/27631 4857/5582/27632 4825/5549/27633 -f 4825/5549/27634 4824/5548/27635 4858/5583/27636 -f 4859/5584/27637 4858/5583/27638 4824/5548/27639 -f 4824/5548/27640 4823/5547/27641 4859/5584/27642 -f 4823/5547/27643 4822/5546/27644 4860/5585/27645 -f 4860/5585/27646 4859/5584/27647 4823/5547/27648 -f 4844/5570/27649 4846/5571/27650 4860/5585/27651 -f 4860/5585/27652 4822/5546/27653 4844/5570/27654 -f 4861/5586/27655 4860/5585/27656 4846/5571/27657 -f 4846/5571/27658 4847/5572/27659 4861/5586/27660 -f 4847/5572/27661 4848/5573/27662 4862/5587/27663 -f 4862/5587/27664 4861/5586/27665 4847/5572/27666 -f 4863/5588/27667 4862/5587/27668 4848/5573/27669 -f 4848/5573/27670 4849/5574/27671 4863/5588/27672 -f 4850/5575/27673 4852/5577/27674 4863/5588/27675 -f 4863/5588/27676 4849/5574/27677 4850/5575/27678 -f 4864/5589/27679 4863/5588/27680 4852/5577/27681 -f 4852/5577/27682 4853/5578/27683 4864/5589/27684 -f 4863/5588/27685 4864/5589/27686 4865/5590/27687 -f 4865/5590/27688 4862/5587/27689 4863/5588/27690 -f 4866/5591/27691 4861/5586/27692 4862/5587/27693 -f 4862/5587/27694 4865/5590/27695 4866/5591/27696 -f 4860/5585/27697 4861/5586/27698 4866/5591/27699 -f 4866/5591/27700 4859/5584/27701 4860/5585/27702 -f 4859/5584/27703 4866/5591/27704 4867/5592/27705 -f 4867/5592/27706 4858/5583/27707 4859/5584/27708 -f 4858/5583/27709 4867/5592/27710 4868/5593/27711 -f 4868/5593/27712 4857/5582/27713 4858/5583/27714 -f 4869/5594/27715 4856/5581/27716 4857/5582/27717 -f 4857/5582/27718 4868/5593/27719 4869/5594/27720 -f 4856/5581/27721 4869/5594/27722 4870/5595/27723 -f 4870/5595/27724 4855/5580/27725 4856/5581/27726 -f 4855/5580/27727 4870/5595/27728 4871/5596/27729 -f 4871/5596/27730 4854/5579/27731 4855/5580/27732 -f 4853/5578/27733 4854/5579/27734 4871/5596/27735 -f 4871/5596/27736 4864/5589/27737 4853/5578/27738 -f 4867/5592/27739 4872/5597/27740 4869/5594/27741 -f 4869/5594/27742 4868/5593/27743 4867/5592/27744 -f 4872/5597/27745 4871/5596/27746 4870/5595/27747 -f 4870/5595/27748 4869/5594/27749 4872/5597/27750 -f 4866/5591/27751 4865/5590/27752 4872/5597/27753 -f 4872/5597/27754 4867/5592/27755 4866/5591/27756 -f 4872/5597/27757 4865/5590/27758 4864/5589/27759 -f 4864/5589/27760 4871/5596/27761 4872/5597/27762 -f 4873/5598/27763 4874/5599/27764 4771/5469/27765 -f 4771/5469/27766 4773/5495/27767 4873/5598/27768 -f 4875/5600/27769 4746/5470/27770 4771/5469/27771 -f 4771/5469/27772 4874/5599/27773 4875/5600/27774 -f 4876/5601/27775 4749/5472/27776 4746/5470/27777 -f 4746/5470/27778 4875/5600/27779 4876/5601/27780 -f 4877/5602/27781 4751/5474/27782 4749/5472/27783 -f 4749/5472/27784 4876/5601/27785 4877/5602/27786 -f 4751/5474/27787 4877/5602/27788 4878/5603/27789 -f 4878/5603/27790 4753/5476/27791 4751/5474/27792 -f 4753/5476/27793 4878/5603/27794 4879/5604/27795 -f 4879/5604/27796 4755/5478/27797 4753/5476/27798 -f 4755/5478/27799 4879/5604/27800 4880/5605/27801 -f 4880/5605/27802 4756/5481/27803 4755/5478/27804 -f 4756/5481/27805 4880/5605/27806 4881/5606/27807 -f 4881/5606/27808 4758/5482/27809 4756/5481/27810 -f 4758/5482/27811 4881/5606/27812 4882/5607/27813 -f 4882/5607/27814 4760/5484/27815 4758/5482/27816 -f 4760/5484/27817 4882/5630/27818 4883/5608/27819 -f 4883/5608/27820 4763/5487/27821 4760/5484/27822 -f 4883/5608/27823 4884/5609/27824 4765/5488/27825 -f 4765/5488/27826 4763/5487/27827 4883/5608/27828 -f 4885/5610/27829 4767/5490/27830 4765/5488/27831 -f 4765/5488/27832 4884/5609/27833 4885/5610/27834 -f 4886/5611/27835 4769/5492/27836 4767/5490/27837 -f 4767/5490/27838 4885/5610/27839 4886/5611/27840 -f 4769/5492/27841 4886/5611/27842 4887/5612/27843 -f 4887/5612/27844 4805/5518/27845 4769/5492/27846 -f 4805/5518/27847 4887/5612/27848 4888/5613/27849 -f 4888/5613/27850 4803/5520/27851 4805/5518/27852 -f 4803/5520/27853 4888/5631/27854 4889/5614/27855 -f 4889/5614/27856 4801/5522/27857 4803/5520/27858 -f 4890/5615/27859 4799/5524/27860 4801/5522/27861 -f 4801/5522/27862 4889/5614/27863 4890/5615/27864 -f 4799/5524/27865 4890/5615/27866 4891/5616/27867 -f 4891/5616/27868 4797/5527/27869 4799/5524/27870 -f 4797/5527/27871 4891/5616/27872 4892/5617/27873 -f 4892/5617/27874 4795/5510/27875 4797/5527/27876 -f 4793/5511/27877 4893/5619/27878 4894/5618/27879 -f 4894/5618/27880 4791/5512/27881 4793/5511/27882 -f 4791/5512/27883 4894/5618/27884 4895/5620/27885 -f 4895/5620/27886 4789/5514/27887 4791/5512/27888 -f 4789/5514/27889 4895/5620/27890 4896/5621/27891 -f 4896/5621/27892 4787/5516/27893 4789/5514/27894 -f 4787/5516/27895 4896/5621/27896 4897/5622/27897 -f 4897/5622/27898 4785/5504/27899 4787/5516/27900 -f 4785/5504/27901 4897/5632/27902 4898/5623/27903 -f 4898/5623/27904 4783/5505/27905 4785/5504/27906 -f 4783/5505/27907 4898/5623/27908 4899/5624/27909 -f 4899/5624/27910 4781/5506/27911 4783/5505/27912 -f 4781/5506/27913 4899/5624/27914 4900/5625/27915 -f 4900/5625/27916 4779/5501/27917 4781/5506/27918 -f 4779/5501/27919 4900/5625/27920 4901/5626/27921 -f 4901/5626/27922 4777/5499/27923 4779/5501/27924 -f 4777/5499/27925 4901/5626/27926 4902/5627/27927 -f 4902/5627/27928 4775/5497/27929 4777/5499/27930 -f 4775/5497/27931 4902/5627/27932 4873/5598/27933 -f 4873/5598/27934 4773/5495/27935 4775/5497/27936 -f 4898/5623/27937 4897/5632/27938 4903/5628/27939 -f 4883/5608/27940 4882/5630/27941 4904/5629/27942 -f 4831/5555/27943 4832/5556/27944 4811/5533/27945 -f 4811/5533/27946 4812/5535/27947 4831/5555/27948 -f 4840/5566/27949 4841/5565/27950 4905/5569/27951 -f 4841/5565/27952 4906/5567/27953 4905/5569/27954 -f 4906/5567/27955 4841/5565/27956 4842/5542/27957 -f 4842/5542/27958 4907/5541/27959 4906/5567/27960 -f 4905/5569/27961 4843/5568/27962 4840/5566/27963 -f 4812/5535/27964 4811/5533/27965 4790/5513/27966 -f 4790/5513/27967 4788/5515/27968 4812/5535/27969 -f 4827/5551/27970 4828/5552/27971 4774/5496/27972 -f 4774/5496/27973 4772/5494/27974 4827/5551/27975 -f 4893/5635/27976 4793/5511/27977 4795/5510/27978 -f 4795/5510/27979 4892/5617/27980 4893/5635/27981 -f 4796/5526/27982 4797/5527/27983 4795/5510/27984 -f 4795/5510/27985 4794/5509/27986 4796/5526/27987 -f 4882/5607/27988 4881/5606/27989 4904/5634/27990 -f 4897/5622/27991 4896/5621/27992 4903/5633/27993 -f 4929/5638/27994 4924/5639/27995 5081/5636/27996 -f 5081/5636/27997 5082/5637/27998 4929/5638/27999 -f 4924/5639/28000 4936/5641/28001 5083/5640/28002 -f 5083/5640/28003 5081/5636/28004 4924/5639/28005 -f 4936/5641/28006 4942/5643/28007 5084/5642/28008 -f 5084/5642/28009 5083/5640/28010 4936/5641/28011 -f 4942/5643/28012 4948/5645/28013 5085/5644/28014 -f 5085/5644/28015 5084/5642/28016 4942/5643/28017 -f 4948/5645/28018 4954/5647/28019 5086/5646/28020 -f 5086/5646/28021 5085/5644/28022 4948/5645/28023 -f 4954/5649/28024 4929/5638/28025 5082/5637/28026 -f 5082/5637/28027 5086/5648/28028 4954/5649/28029 -f 4914/5652/28030 4920/5653/28031 4912/5650/28032 -f 4912/5650/28033 4911/5651/28034 4914/5652/28035 -f 4914/5656/28036 4911/5651/28037 4910/5654/28038 -f 4910/5654/28039 4909/5655/28040 4914/5656/28041 -f 4915/5658/28042 4920/5659/28043 4914/5657/28044 -f 4914/5657/28045 4909/5655/28046 4915/5658/28047 -f 4909/5655/28048 4916/5661/28049 4908/5660/28050 -f 4908/5660/28051 4915/5658/28052 4909/5655/28053 -f 4910/5654/28054 4917/5662/28055 4916/5661/28056 -f 4916/5661/28057 4909/5655/28058 4910/5654/28059 -f 4911/5651/28060 4918/5663/28061 4917/5662/28062 -f 4917/5662/28063 4910/5654/28064 4911/5651/28065 -f 4912/5650/28066 4919/5664/28067 4918/5663/28068 -f 4918/5663/28069 4911/5651/28070 4912/5650/28071 -f 4920/5653/28072 4913/5665/28073 4919/5664/28074 -f 4919/5664/28075 4912/5650/28076 4920/5653/28077 -f 4915/5658/28078 4908/5660/28079 4913/5666/28080 -f 4913/5666/28081 4920/5659/28082 4915/5658/28083 -f 4928/5670/28084 4925/5671/28085 5087/5668/28086 -f 5087/5668/28087 5088/5669/28088 4928/5670/28089 -f 4921/5672/28090 4932/5673/28091 4908/5660/28092 -f 4908/5660/28093 4916/5661/28094 4921/5672/28095 -f 4922/5674/28096 4931/5675/28097 4932/5673/28098 -f 4932/5673/28099 4921/5672/28100 4922/5674/28101 -f 4923/5678/28102 4930/5679/28103 5070/5676/28104 -f 5070/5676/28105 5069/5677/28106 4923/5678/28107 -f 4924/5639/28108 4929/5638/28109 5076/5680/28110 -f 5076/5680/28111 5075/5681/28112 4924/5639/28113 -f 4925/5671/28114 4937/5683/28115 5089/5682/28116 -f 5089/5682/28117 5087/5668/28118 4925/5671/28119 -f 4933/5684/28120 4921/5672/28121 4916/5661/28122 -f 4916/5661/28123 4917/5662/28124 4933/5684/28125 -f 4934/5685/28126 4922/5674/28127 4921/5672/28128 -f 4921/5672/28129 4933/5684/28130 4934/5685/28131 -f 4935/5687/28132 4923/5678/28133 5069/5677/28134 -f 5069/5677/28135 5071/5686/28136 4935/5687/28137 -f 4936/5641/28138 4924/5639/28139 5075/5681/28140 -f 5075/5681/28141 5077/5688/28142 4936/5641/28143 -f 4937/5683/28144 4943/5690/28145 5090/5689/28146 -f 5090/5689/28147 5089/5682/28148 4937/5683/28149 -f 4939/5691/28150 4933/5684/28151 4917/5662/28152 -f 4917/5662/28153 4918/5663/28154 4939/5691/28155 -f 4940/5692/28156 4934/5685/28157 4933/5684/28158 -f 4933/5684/28159 4939/5691/28160 4940/5692/28161 -f 4941/5694/28162 4935/5687/28163 5071/5686/28164 -f 5071/5686/28165 5072/5693/28166 4941/5694/28167 -f 4942/5643/28168 4936/5641/28169 5077/5688/28170 -f 5077/5688/28171 5078/5695/28172 4942/5643/28173 -f 4943/5690/28174 4949/5697/28175 5091/5696/28176 -f 5091/5696/28177 5090/5689/28178 4943/5690/28179 -f 4945/5698/28180 4939/5691/28181 4918/5663/28182 -f 4918/5663/28183 4919/5664/28184 4945/5698/28185 -f 4946/5699/28186 4940/5692/28187 4939/5691/28188 -f 4939/5691/28189 4945/5698/28190 4946/5699/28191 -f 4947/5701/28192 4941/5694/28193 5072/5693/28194 -f 5072/5693/28195 5073/5700/28196 4947/5701/28197 -f 4948/5645/28198 4942/5643/28199 5078/5695/28200 -f 5078/5695/28201 5079/5702/28202 4948/5645/28203 -f 4949/5697/28204 4955/5704/28205 5092/5703/28206 -f 5092/5703/28207 5091/5696/28208 4949/5697/28209 -f 4951/5705/28210 4945/5698/28211 4919/5664/28212 -f 4919/5664/28213 4913/5665/28214 4951/5705/28215 -f 4952/5706/28216 4946/5699/28217 4945/5698/28218 -f 4945/5698/28219 4951/5705/28220 4952/5706/28221 -f 4953/5708/28222 4947/5701/28223 5073/5700/28224 -f 5073/5700/28225 5074/5707/28226 4953/5708/28227 -f 4954/5647/28228 4948/5645/28229 5079/5702/28230 -f 5079/5702/28231 5080/5709/28232 4954/5647/28233 -f 4955/5711/28234 4928/5670/28235 5088/5669/28236 -f 5088/5669/28237 5092/5710/28238 4955/5711/28239 -f 4908/5660/28240 4932/5673/28241 4951/5712/28242 -f 4951/5712/28243 4913/5666/28244 4908/5660/28245 -f 4931/5675/28246 4952/5713/28247 4951/5712/28248 -f 4951/5712/28249 4932/5673/28250 4931/5675/28251 -f 4930/5679/28252 4953/5715/28253 5074/5714/28254 -f 5074/5714/28255 5070/5676/28256 4930/5679/28257 -f 4929/5638/28258 4954/5649/28259 5080/5716/28260 -f 5080/5716/28261 5076/5680/28262 4929/5638/28263 -f 4958/5719/28264 4957/5720/28265 5100/5717/28266 -f 5100/5717/28267 5099/5718/28268 4958/5719/28269 -f 5003/5723/28270 5004/5724/28271 5094/5721/28272 -f 5094/5721/28273 5093/5722/28274 5003/5723/28275 -f 4957/5720/28276 4962/5726/28277 5101/5725/28278 -f 5101/5725/28279 5100/5717/28280 4957/5720/28281 -f 5004/5724/28282 5005/5728/28283 5095/5727/28284 -f 5095/5727/28285 5094/5721/28286 5004/5724/28287 -f 4962/5726/28288 4965/5730/28289 5102/5729/28290 -f 5102/5729/28291 5101/5725/28292 4962/5726/28293 -f 5005/5728/28294 5006/5732/28295 5096/5731/28296 -f 5096/5731/28297 5095/5727/28298 5005/5728/28299 -f 4965/5730/28300 4968/5734/28301 5103/5733/28302 -f 5103/5733/28303 5102/5729/28304 4965/5730/28305 -f 5006/5732/28306 5007/5736/28307 5097/5735/28308 -f 5097/5735/28309 5096/5731/28310 5006/5732/28311 -f 4968/5739/28312 4971/5740/28313 5104/5737/28314 -f 5104/5737/28315 5103/5738/28316 4968/5739/28317 -f 5007/5743/28318 5008/5744/28319 5098/5741/28320 -f 5098/5741/28321 5097/5742/28322 5007/5743/28323 -f 4971/5740/28324 4958/5719/28325 5099/5718/28326 -f 5099/5718/28327 5104/5737/28328 4971/5740/28329 -f 5008/5744/28330 5003/5723/28331 5093/5722/28332 -f 5093/5722/28333 5098/5741/28334 5008/5744/28335 -s 2 -f 4974/5747/28336 4973/5748/28337 5020/5745/28338 -f 5020/5745/28339 5021/5746/28340 4974/5747/28341 -f 4975/5750/28342 4974/5747/28343 5021/5888/28344 -f 5021/5888/28345 4970/5749/28346 4975/5750/28347 -f 4976/5752/28348 4975/5750/28349 4970/5889/28350 -f 4970/5889/28351 4967/5751/28352 4976/5752/28353 -f 4977/5755/28354 4976/5756/28355 4967/5753/28356 -f 4967/5753/28357 4964/5754/28358 4977/5755/28359 -f 4978/5758/28360 4977/5755/28361 4964/5890/28362 -f 4964/5890/28363 4961/5757/28364 4978/5758/28365 -f 4973/5748/28366 4978/5758/28367 4961/5891/28368 -f 4961/5891/28369 5020/5886/28370 4973/5748/28371 -f 4980/5761/28372 4979/5762/28373 4960/5759/28374 -f 4960/5759/28375 4959/5760/28376 4980/5761/28377 -f 4981/5764/28378 4980/5761/28379 4959/5887/28380 -f 4959/5887/28381 4963/5763/28382 4981/5764/28383 -f 4982/5766/28384 4981/5764/28385 4963/5893/28386 -f 4963/5893/28387 4966/5765/28388 4982/5766/28389 -f 4983/5768/28390 4982/5766/28391 4966/5894/28392 -f 4966/5894/28393 4969/5767/28394 4983/5768/28395 -f 4984/5771/28396 4983/5772/28397 4969/5769/28398 -f 4969/5769/28399 4972/5770/28400 4984/5771/28401 -f 4979/5762/28402 4984/5771/28403 4972/5895/28404 -f 4972/5895/28405 4960/5892/28406 4979/5762/28407 -s 1 -f 4986/5773/28408 4985/5774/28409 4973/5748/28410 -f 4973/5748/28411 4974/5747/28412 4986/5773/28413 -f 4987/5775/28414 4986/5773/28415 4974/5747/28416 -f 4974/5747/28417 4975/5750/28418 4987/5775/28419 -f 4988/5776/28420 4987/5775/28421 4975/5750/28422 -f 4975/5750/28423 4976/5752/28424 4988/5776/28425 -f 4989/5777/28426 4988/5778/28427 4976/5756/28428 -f 4976/5756/28429 4977/5755/28430 4989/5777/28431 -f 4990/5779/28432 4989/5777/28433 4977/5755/28434 -f 4977/5755/28435 4978/5758/28436 4990/5779/28437 -f 4985/5774/28438 4990/5779/28439 4978/5758/28440 -f 4978/5758/28441 4973/5748/28442 4985/5774/28443 -f 4992/5780/28444 4991/5781/28445 4979/5762/28446 -f 4979/5762/28447 4980/5761/28448 4992/5780/28449 -f 4993/5782/28450 4992/5780/28451 4980/5761/28452 -f 4980/5761/28453 4981/5764/28454 4993/5782/28455 -f 4994/5783/28456 4993/5782/28457 4981/5764/28458 -f 4981/5764/28459 4982/5766/28460 4994/5783/28461 -f 4995/5784/28462 4994/5783/28463 4982/5766/28464 -f 4982/5766/28465 4983/5768/28466 4995/5784/28467 -f 4996/5785/28468 4995/5786/28469 4983/5772/28470 -f 4983/5772/28471 4984/5771/28472 4996/5785/28473 -f 4991/5781/28474 4996/5785/28475 4984/5771/28476 -f 4984/5771/28477 4979/5762/28478 4991/5781/28479 -f 4998/5787/28480 4997/5788/28481 4985/5774/28482 -f 4985/5774/28483 4986/5773/28484 4998/5787/28485 -f 4999/5789/28486 4998/5787/28487 4986/5773/28488 -f 4986/5773/28489 4987/5775/28490 4999/5789/28491 -f 5000/5790/28492 4999/5789/28493 4987/5775/28494 -f 4987/5775/28495 4988/5776/28496 5000/5790/28497 -f 5001/5791/28498 5000/5792/28499 4988/5778/28500 -f 4988/5778/28501 4989/5777/28502 5001/5791/28503 -f 5002/5793/28504 5001/5791/28505 4989/5777/28506 -f 4989/5777/28507 4990/5779/28508 5002/5793/28509 -f 4997/5788/28510 5002/5793/28511 4990/5779/28512 -f 4990/5779/28513 4985/5774/28514 4997/5788/28515 -f 5004/5724/28516 5003/5723/28517 4991/5781/28518 -f 4991/5781/28519 4992/5780/28520 5004/5724/28521 -f 5005/5728/28522 5004/5724/28523 4992/5780/28524 -f 4992/5780/28525 4993/5782/28526 5005/5728/28527 -f 5006/5732/28528 5005/5728/28529 4993/5782/28530 -f 4993/5782/28531 4994/5783/28532 5006/5732/28533 -f 5007/5736/28534 5006/5732/28535 4994/5783/28536 -f 4994/5783/28537 4995/5784/28538 5007/5736/28539 -f 5008/5744/28540 5007/5743/28541 4995/5786/28542 -f 4995/5786/28543 4996/5785/28544 5008/5744/28545 -f 5003/5723/28546 5008/5744/28547 4996/5785/28548 -f 4996/5785/28549 4991/5781/28550 5003/5723/28551 -f 5012/5796/28552 5011/5797/28553 5010/5794/28554 -f 5010/5794/28555 5009/5795/28556 5012/5796/28557 -f 5012/5796/28558 5014/5799/28559 5013/5798/28560 -f 5013/5798/28561 5011/5797/28562 5012/5796/28563 -f 5015/5800/28564 5014/5799/28565 5012/5796/28566 -f 5012/5796/28567 5009/5795/28568 5015/5800/28569 -f 5014/5799/28570 5015/5800/28571 5016/5801/28572 -f 5016/5801/28573 5017/5802/28574 5014/5799/28575 -f 5013/5798/28576 5014/5799/28577 5017/5802/28578 -f 5017/5802/28579 5022/5803/28580 5013/5798/28581 -f 5011/5885/28582 5013/5798/28583 5022/5803/28584 -f 5022/5803/28585 5018/5804/28586 5011/5885/28587 -f 5010/5806/28588 5011/5885/28589 5018/5804/28590 -f 5018/5804/28591 5019/5805/28592 5010/5806/28593 -f 5009/5884/28594 5010/5809/28595 5019/5807/28596 -f 5019/5807/28597 5023/5808/28598 5009/5884/28599 -f 5015/5800/28600 5009/5884/28601 5023/5808/28602 -f 5023/5808/28603 5016/5801/28604 5015/5800/28605 -f 5021/5878/28606 5020/5667/28607 5105/5810/28608 -f 5105/5810/28609 5106/5811/28610 5021/5878/28611 -f 5020/5667/28612 4961/5883/28613 5107/5812/28614 -f 5107/5812/28615 5105/5810/28616 5020/5667/28617 -f 4961/5883/28618 4964/5882/28619 5108/5813/28620 -f 5108/5813/28621 5107/5812/28622 4961/5883/28623 -f 4964/5882/28624 4967/5881/28625 5109/5814/28626 -f 5109/5814/28627 5108/5813/28628 4964/5882/28629 -f 4967/5880/28630 4970/5879/28631 5110/5815/28632 -f 5110/5815/28633 5109/5816/28634 4967/5880/28635 -f 4970/5879/28636 5021/5878/28637 5106/5811/28638 -f 5106/5811/28639 5110/5815/28640 4970/5879/28641 -f 5030/5819/28642 5029/5820/28643 5024/5817/28644 -f 5024/5817/28645 5025/5818/28646 5030/5819/28647 -s 2 -f 5031/5822/28648 5030/5819/28649 5025/5818/28650 -f 5025/5818/28651 5026/5821/28652 5031/5822/28653 -s 4 -f 5032/5825/28654 5031/5826/28655 5026/5823/28656 -f 5026/5823/28657 5027/5824/28658 5032/5825/28659 -f 5033/5828/28660 5032/5825/28661 5027/5824/28662 -f 5027/5824/28663 5028/5827/28664 5033/5828/28665 -s 1 -f 5029/5820/28666 5033/5828/28667 5028/5827/28668 -f 5028/5827/28669 5024/5817/28670 5029/5820/28671 -f 5035/5829/28672 5034/5830/28673 5029/5820/28674 -f 5029/5820/28675 5030/5819/28676 5035/5829/28677 -s 2 -f 5036/5831/28678 5035/5829/28679 5030/5819/28680 -f 5030/5819/28681 5031/5822/28682 5036/5831/28683 -s 4 -f 5037/5832/28684 5036/5833/28685 5031/5826/28686 -f 5031/5826/28687 5032/5825/28688 5037/5832/28689 -f 5038/5834/28690 5037/5832/28691 5032/5825/28692 -f 5032/5825/28693 5033/5828/28694 5038/5834/28695 -s 1 -f 5034/5830/28696 5038/5834/28697 5033/5828/28698 -f 5033/5828/28699 5029/5820/28700 5034/5830/28701 -f 5040/5835/28702 5039/5836/28703 5034/5830/28704 -f 5034/5830/28705 5035/5829/28706 5040/5835/28707 -s 2 -f 5041/5837/28708 5040/5835/28709 5035/5829/28710 -f 5035/5829/28711 5036/5831/28712 5041/5837/28713 -s 4 -f 5042/5838/28714 5041/5839/28715 5036/5833/28716 -f 5036/5833/28717 5037/5832/28718 5042/5838/28719 -f 5043/5840/28720 5042/5838/28721 5037/5832/28722 -f 5037/5832/28723 5038/5834/28724 5043/5840/28725 -s 1 -f 5039/5836/28726 5043/5840/28727 5038/5834/28728 -f 5038/5834/28729 5034/5830/28730 5039/5836/28731 -f 5045/5841/28732 5044/5842/28733 5039/5836/28734 -f 5039/5836/28735 5040/5835/28736 5045/5841/28737 -s 2 -f 5046/5843/28738 5045/5841/28739 5040/5835/28740 -f 5040/5835/28741 5041/5837/28742 5046/5843/28743 -s 4 -f 5047/5844/28744 5046/5845/28745 5041/5839/28746 -f 5041/5839/28747 5042/5838/28748 5047/5844/28749 -f 5048/5846/28750 5047/5844/28751 5042/5838/28752 -f 5042/5838/28753 5043/5840/28754 5048/5846/28755 -s 1 -f 5044/5842/28756 5048/5846/28757 5043/5840/28758 -f 5043/5840/28759 5039/5836/28760 5044/5842/28761 -f 5050/5847/28762 5049/5848/28763 5044/5842/28764 -f 5044/5842/28765 5045/5841/28766 5050/5847/28767 -s 2 -f 5051/5849/28768 5050/5847/28769 5045/5841/28770 -f 5045/5841/28771 5046/5843/28772 5051/5849/28773 -s 4 -f 5052/5850/28774 5051/5851/28775 5046/5845/28776 -f 5046/5845/28777 5047/5844/28778 5052/5850/28779 -f 5053/5852/28780 5052/5850/28781 5047/5844/28782 -f 5047/5844/28783 5048/5846/28784 5053/5852/28785 -s 1 -f 5049/5848/28786 5053/5852/28787 5048/5846/28788 -f 5048/5846/28789 5044/5842/28790 5049/5848/28791 -f 5055/5853/28792 5054/5854/28793 5049/5848/28794 -f 5049/5848/28795 5050/5847/28796 5055/5853/28797 -s 2 -f 5056/5855/28798 5055/5853/28799 5050/5847/28800 -f 5050/5847/28801 5051/5849/28802 5056/5855/28803 -s 4 -f 5057/5856/28804 5056/5857/28805 5051/5851/28806 -f 5051/5851/28807 5052/5850/28808 5057/5856/28809 -f 5058/5858/28810 5057/5856/28811 5052/5850/28812 -f 5052/5850/28813 5053/5852/28814 5058/5858/28815 -s 1 -f 5054/5854/28816 5058/5858/28817 5053/5852/28818 -f 5053/5852/28819 5049/5848/28820 5054/5854/28821 -f 5060/5859/28822 5059/5860/28823 5054/5854/28824 -f 5054/5854/28825 5055/5853/28826 5060/5859/28827 -s 2 -f 5061/5861/28828 5060/5859/28829 5055/5853/28830 -f 5055/5853/28831 5056/5855/28832 5061/5861/28833 -s 4 -f 5062/5862/28834 5061/5863/28835 5056/5857/28836 -f 5056/5857/28837 5057/5856/28838 5062/5862/28839 -f 5063/5864/28840 5062/5862/28841 5057/5856/28842 -f 5057/5856/28843 5058/5858/28844 5063/5864/28845 -s 1 -f 5059/5860/28846 5063/5864/28847 5058/5858/28848 -f 5058/5858/28849 5054/5854/28850 5059/5860/28851 -f 5065/5865/28852 5064/5866/28853 5059/5860/28854 -f 5059/5860/28855 5060/5859/28856 5065/5865/28857 -s 2 -f 5066/5867/28858 5065/5865/28859 5060/5859/28860 -f 5060/5859/28861 5061/5861/28862 5066/5867/28863 -s 4 -f 5067/5868/28864 5066/5869/28865 5061/5863/28866 -f 5061/5863/28867 5062/5862/28868 5067/5868/28869 -f 5068/5870/28870 5067/5868/28871 5062/5862/28872 -f 5062/5862/28873 5063/5864/28874 5068/5870/28875 -s 1 -f 5064/5866/28876 5068/5870/28877 5063/5864/28878 -f 5063/5864/28879 5059/5860/28880 5064/5866/28881 -f 5069/5677/28882 5070/5676/28883 4931/5675/28884 -f 4931/5675/28885 4922/5674/28886 5069/5677/28887 -f 5071/5686/28888 5069/5677/28889 4922/5674/28890 -f 4922/5674/28891 4934/5685/28892 5071/5686/28893 -f 5072/5693/28894 5071/5686/28895 4934/5685/28896 -f 4934/5685/28897 4940/5692/28898 5072/5693/28899 -f 5073/5700/28900 5072/5693/28901 4940/5692/28902 -f 4940/5692/28903 4946/5699/28904 5073/5700/28905 -f 5074/5707/28906 5073/5700/28907 4946/5699/28908 -f 4946/5699/28909 4952/5706/28910 5074/5707/28911 -f 5070/5676/28912 5074/5714/28913 4952/5713/28914 -f 4952/5713/28915 4931/5675/28916 5070/5676/28917 -f 5075/5681/28918 5076/5680/28919 4930/5679/28920 -f 4930/5679/28921 4923/5678/28922 5075/5681/28923 -f 5077/5688/28924 5075/5681/28925 4923/5678/28926 -f 4923/5678/28927 4935/5687/28928 5077/5688/28929 -f 5078/5695/28930 5077/5688/28931 4935/5687/28932 -f 4935/5687/28933 4941/5694/28934 5078/5695/28935 -f 5079/5702/28936 5078/5695/28937 4941/5694/28938 -f 4941/5694/28939 4947/5701/28940 5079/5702/28941 -f 5080/5709/28942 5079/5702/28943 4947/5701/28944 -f 4947/5701/28945 4953/5708/28946 5080/5709/28947 -f 5076/5680/28948 5080/5716/28949 4953/5715/28950 -f 4953/5715/28951 4930/5679/28952 5076/5680/28953 -f 5082/5637/28954 5081/5636/28955 4925/5671/28956 -f 4925/5671/28957 4928/5670/28958 5082/5637/28959 -f 5081/5636/28960 5083/5640/28961 4937/5683/28962 -f 4937/5683/28963 4925/5671/28964 5081/5636/28965 -f 5083/5640/28966 5084/5642/28967 4943/5690/28968 -f 4943/5690/28969 4937/5683/28970 5083/5640/28971 -f 5084/5642/28972 5085/5644/28973 4949/5697/28974 -f 4949/5697/28975 4943/5690/28976 5084/5642/28977 -f 5085/5644/28978 5086/5646/28979 4955/5704/28980 -f 4955/5704/28981 4949/5697/28982 5085/5644/28983 -f 5086/5648/28984 5082/5637/28985 4928/5670/28986 -f 4928/5670/28987 4955/5711/28988 5086/5648/28989 -f 5088/5669/28990 5087/5668/28991 4926/5871/28992 -f 4926/5871/28993 4927/5872/28994 5088/5669/28995 -f 5087/5668/28996 5089/5682/28997 4938/5873/28998 -f 4938/5873/28999 4926/5871/29000 5087/5668/29001 -f 5089/5682/29002 5090/5689/29003 4944/5874/29004 -f 4944/5874/29005 4938/5873/29006 5089/5682/29007 -f 5090/5689/29008 5091/5696/29009 4950/5875/29010 -f 4950/5875/29011 4944/5874/29012 5090/5689/29013 -f 5091/5696/29014 5092/5703/29015 4956/5876/29016 -f 4956/5876/29017 4950/5875/29018 5091/5696/29019 -f 5092/5710/29020 5088/5669/29021 4927/5872/29022 -f 4927/5872/29023 4956/5877/29024 5092/5710/29025 -f 5093/5722/29026 5094/5721/29027 4957/5720/29028 -f 4957/5720/29029 4958/5719/29030 5093/5722/29031 -f 5094/5721/29032 5095/5727/29033 4962/5726/29034 -f 4962/5726/29035 4957/5720/29036 5094/5721/29037 -f 5095/5727/29038 5096/5731/29039 4965/5730/29040 -f 4965/5730/29041 4962/5726/29042 5095/5727/29043 -f 5096/5731/29044 5097/5735/29045 4968/5734/29046 -f 4968/5734/29047 4965/5730/29048 5096/5731/29049 -f 5097/5742/29050 5098/5741/29051 4971/5740/29052 -f 4971/5740/29053 4968/5739/29054 5097/5742/29055 -f 5098/5741/29056 5093/5722/29057 4958/5719/29058 -f 4958/5719/29059 4971/5740/29060 5098/5741/29061 -f 5099/5718/29062 5100/5717/29063 4997/5788/29064 -f 4997/5788/29065 4998/5787/29066 5099/5718/29067 -f 5100/5717/29068 5101/5725/29069 5002/5793/29070 -f 5002/5793/29071 4997/5788/29072 5100/5717/29073 -f 5101/5725/29074 5102/5729/29075 5001/5791/29076 -f 5001/5791/29077 5002/5793/29078 5101/5725/29079 -f 5102/5729/29080 5103/5733/29081 5000/5792/29082 -f 5000/5792/29083 5001/5791/29084 5102/5729/29085 -f 5103/5738/29086 5104/5737/29087 4999/5789/29088 -f 4999/5789/29089 5000/5790/29090 5103/5738/29091 -f 5104/5737/29092 5099/5718/29093 4998/5787/29094 -f 4998/5787/29095 4999/5789/29096 5104/5737/29097 -f 5106/5811/29098 5105/5810/29099 5017/5802/29100 -f 5017/5802/29101 5016/5801/29102 5106/5811/29103 -f 5105/5810/29104 5107/5812/29105 5022/5803/29106 -f 5022/5803/29107 5017/5802/29108 5105/5810/29109 -f 5107/5812/29110 5108/5813/29111 5018/5804/29112 -f 5018/5804/29113 5022/5803/29114 5107/5812/29115 -f 5108/5813/29116 5109/5814/29117 5019/5805/29118 -f 5019/5805/29119 5018/5804/29120 5108/5813/29121 -f 5109/5816/29122 5110/5815/29123 5023/5808/29124 -f 5023/5808/29125 5019/5807/29126 5109/5816/29127 -f 5110/5815/29128 5106/5811/29129 5016/5801/29130 -f 5016/5801/29131 5023/5808/29132 5110/5815/29133 -f 5111/5898/29134 5114/5901/29135 5113/5902/29136 -f 5113/5902/29137 5112/5897/29138 5111/5898/29139 -f 5113/5902/29140 5114/5901/29141 5115/5904/29142 -f 5115/5904/29143 5116/5906/29144 5113/5902/29145 -f 5118/5910/29146 5111/5898/29147 5112/5897/29148 -f 5112/5897/29149 5117/5907/29150 5118/5910/29151 -f 5120/5924/29152 5118/5910/29153 5117/5907/29154 -f 5117/5907/29155 5119/5912/29156 5120/5924/29157 -f 5116/5906/29158 5115/5904/29159 5173/5925/29160 -f 5173/5925/29161 5172/5926/29162 5116/5906/29163 -f 5121/5927/29164 5122/5928/29165 5119/5912/29166 -f 5119/5912/29167 5117/5907/29168 5121/5927/29169 -f 5123/5929/29170 5124/5930/29171 5122/5928/29172 -f 5122/5928/29173 5121/5927/29174 5123/5929/29175 -f 5126/5932/29176 5123/5929/29177 5121/5927/29178 -f 5121/5927/29179 5125/5931/29180 5126/5932/29181 -f 5128/5934/29182 5126/5932/29183 5125/5931/29184 -f 5125/5931/29185 5127/5933/29186 5128/5934/29187 -f 5129/5935/29188 5128/5934/29189 5127/5933/29190 -f 5131/5899/29191 5126/5900/29192 5128/5903/29193 -f 5128/5903/29194 5130/5896/29195 5131/5899/29196 -f 5132/5905/29197 5133/5908/29198 5124/5909/29199 -f 5124/5909/29200 5123/5911/29201 5132/5905/29202 -f 5123/5911/29203 5126/5900/29204 5131/5899/29205 -f 5131/5899/29206 5132/5905/29207 5123/5911/29208 -f 5133/5921/29209 5132/5922/29210 5134/5919/29211 -f 5134/5919/29212 5135/5920/29213 5133/5921/29214 -f 5132/5922/29215 5131/5966/29216 5136/5969/29217 -f 5136/5969/29218 5134/5919/29219 5132/5922/29220 -f 5136/5969/29221 5131/5966/29222 5130/5970/29223 -f 5130/5970/29224 5137/5974/29225 5136/5969/29226 -f 5128/5903/29227 5129/5913/29228 5138/5914/29229 -f 5138/5914/29230 5130/5896/29231 5128/5903/29232 -f 5137/5974/29233 5130/5970/29234 5138/5976/29235 -f 5138/5976/29236 5139/5975/29237 5137/5974/29238 -f 5142/5937/29239 5125/5931/29240 5121/5927/29241 -f 5121/5927/29242 5140/5936/29243 5142/5937/29244 -f 5140/5936/29245 5121/5927/29246 5117/5907/29247 -f 5117/5907/29248 5112/5897/29249 5140/5936/29250 -f 5112/5897/29251 5113/5902/29252 5140/5936/29253 -f 5141/5938/29254 5140/5936/29255 5113/5902/29256 -f 5113/5902/29257 5116/5906/29258 5141/5938/29259 -f 5143/5939/29260 5142/5937/29261 5140/5936/29262 -f 5140/5936/29263 5141/5938/29264 5143/5939/29265 -f 5125/5931/29266 5142/5937/29267 5144/5940/29268 -f 5144/5940/29269 5127/5933/29270 5125/5931/29271 -f 5144/5940/29272 5142/5937/29273 5145/5941/29274 -f 5127/5933/29275 5144/5940/29276 5146/5942/29277 -f 5146/5942/29278 5129/5935/29279 5127/5933/29280 -f 5145/5941/29281 5148/5943/29282 5144/5940/29283 -f 5147/5944/29284 5146/5942/29285 5144/5940/29286 -f 5148/5943/29287 5147/5944/29288 5144/5940/29289 -f 5149/5945/29290 5150/5946/29291 5148/5943/29292 -f 5148/5943/29293 5145/5941/29294 5149/5945/29295 -f 5145/5941/29296 5142/5937/29297 5151/5947/29298 -f 5151/5947/29299 5149/5945/29300 5145/5941/29301 -f 5152/5948/29302 5151/5947/29303 5142/5937/29304 -f 5142/5937/29305 5143/5939/29306 5152/5948/29307 -f 5143/5939/29308 5141/5938/29309 5154/5949/29310 -f 5153/5950/29311 5152/5948/29312 5143/5939/29313 -f 5143/5939/29314 5154/5949/29315 5153/5950/29316 -f 5156/5952/29317 5154/5949/29318 5157/5953/29319 -f 5157/5953/29320 5155/5951/29321 5156/5952/29322 -f 5159/5955/29323 5157/5953/29324 5161/5956/29325 -f 5161/5956/29326 5158/5954/29327 5159/5955/29328 -f 5141/5938/29329 5116/5906/29330 5161/5956/29331 -f 5160/5957/29332 5169/5959/29333 5116/5906/29334 -f 5116/5906/29335 5172/5926/29336 5160/5957/29337 -f 5161/5956/29338 5162/5962/29339 5163/5960/29340 -f 5163/5960/29341 5183/5961/29342 5161/5956/29343 -s 2 -f 5161/5956/29344 5183/5961/29345 5164/5963/29346 -f 5164/5963/29347 5158/5954/29348 5161/5956/29349 -f 5165/5964/29350 5180/5965/29351 5153/5950/29352 -f 5153/5950/29353 5154/5949/29354 5165/5964/29355 -s 4 -f 5166/5967/29356 5165/5964/29357 5154/5949/29358 -f 5154/5949/29359 5156/5952/29360 5166/5967/29361 -f 5157/5953/29362 5159/5955/29363 5167/5968/29364 -f 5167/5968/29365 5182/5978/29366 5157/5953/29367 -s 2 -f 5157/5953/29368 5182/5978/29369 5168/5985/29370 -f 5168/5985/29371 5155/5951/29372 5157/5953/29373 -s 8 -f 5166/5967/29374 5156/5952/29375 5155/5951/29376 -f 5155/5951/29377 5168/5985/29378 5166/5967/29379 -s 4 -f 5167/5968/29380 5159/5955/29381 5158/5954/29382 -f 5158/5954/29383 5164/5963/29384 5167/5968/29385 -s 1 -f 5169/5959/29386 5161/5956/29387 5116/5906/29388 -f 5162/5962/29389 5161/5956/29390 5169/5959/29391 -f 5162/5962/29392 5169/5959/29393 5170/5986/29394 -f 5170/5986/29395 5163/5960/29396 5162/5962/29397 -f 5160/5957/29398 5171/5987/29399 5170/5986/29400 -f 5170/5986/29401 5169/5959/29402 5160/5957/29403 -f 5171/5987/29404 5160/5957/29405 5172/5926/29406 -f 5172/5926/29407 5173/5925/29408 5171/5987/29409 -s 2 -f 5129/5935/29410 5146/5942/29411 5139/5988/29412 -f 5139/5988/29413 5138/5989/29414 5129/5935/29415 -f 5146/5942/29416 5147/5944/29417 5174/5990/29418 -f 5174/5990/29419 5139/5988/29420 5146/5942/29421 -s 1 -f 5139/5975/29422 5174/5979/29423 5175/5977/29424 -f 5175/5977/29425 5137/5974/29426 5139/5975/29427 -s 4 -f 5177/5998/29428 5150/5946/29429 5149/5945/29430 -f 5149/5945/29431 5176/5997/29432 5177/5998/29433 -f 5149/5945/29434 5151/5947/29435 5178/6001/29436 -f 5178/6001/29437 5176/5997/29438 5149/5945/29439 -f 5152/5948/29440 5179/6002/29441 5178/6001/29442 -f 5178/6001/29443 5151/5947/29444 5152/5948/29445 -f 5153/5950/29446 5180/5965/29447 5179/6002/29448 -f 5179/6002/29449 5152/5948/29450 5153/5950/29451 -s 1 -f 5180/5984/29452 5165/6005/29453 5181/5981/29454 -f 5181/5981/29455 5179/5982/29456 5180/5984/29457 -f 5166/6007/29458 5168/6008/29459 5182/6006/29460 -f 5182/6006/29461 5165/6005/29462 5166/6007/29463 -f 5167/6010/29464 5164/6011/29465 5183/6009/29466 -f 5183/6009/29467 5182/6006/29468 5167/6010/29469 -f 5163/6024/29470 5170/6025/29471 5184/6012/29472 -f 5184/6012/29473 5183/6009/29474 5163/6024/29475 -f 5184/6012/29476 5170/6025/29477 5171/6032/29478 -f 5171/6032/29479 5185/6063/29480 5184/6012/29481 -f 5186/6065/29482 5185/6063/29483 5171/6032/29484 -f 5171/6032/29485 5173/6064/29486 5186/6065/29487 -f 5188/6066/29488 5303/6177/29489 5186/6065/29490 -f 5188/5915/29491 5186/5916/29492 5115/5917/29493 -f 5115/5917/29494 5114/5918/29495 5188/5915/29496 -f 5186/5916/29497 5173/5923/29498 5115/5917/29499 -f 5187/5958/29500 5188/5915/29501 5114/5918/29502 -f 5114/5918/29503 5111/5971/29504 5187/5958/29505 -f 5188/6066/29506 5187/6073/29507 5302/6176/29508 -f 5302/6176/29509 5303/6177/29510 5188/6066/29511 -f 5184/6012/29512 5189/6075/29513 5190/6079/29514 -f 5190/6079/29515 5183/6009/29516 5184/6012/29517 -f 5182/6006/29518 5183/6009/29519 5190/6079/29520 -f 5165/6005/29521 5182/6006/29522 5190/6079/29523 -f 5190/6079/29524 5189/6075/29525 5181/5981/29526 -f 5181/5981/29527 5165/6005/29528 5190/6079/29529 -f 5191/6082/29530 5178/6086/29531 5179/5982/29532 -f 5179/5982/29533 5181/5981/29534 5191/6082/29535 -f 5192/6087/29536 5176/6088/29537 5178/6086/29538 -f 5178/6086/29539 5191/6082/29540 5192/6087/29541 -f 5176/6088/29542 5192/6087/29543 5193/6089/29544 -f 5193/6089/29545 5177/6090/29546 5176/6088/29547 -s 2 -f 5148/5943/29548 5150/5946/29549 5177/5998/29550 -f 5177/5998/29551 5193/6023/29552 5148/5943/29553 -s 4 -f 5147/5944/29554 5148/5943/29555 5193/6023/29556 -f 5193/6023/29557 5174/5990/29558 5147/5944/29559 -s 1 -f 5193/6023/29560 5175/6027/29561 5174/5990/29562 -f 5193/6089/29563 5192/6087/29564 5175/5977/29565 -f 5189/6075/29566 5194/6091/29567 5191/6082/29568 -f 5191/6082/29569 5181/5981/29570 5189/6075/29571 -f 5194/6091/29572 5192/6087/29573 5191/6082/29574 -f 5137/5974/29575 5175/5977/29576 5192/6087/29577 -f 5192/6087/29578 5194/6091/29579 5137/5974/29580 -f 5136/5969/29581 5137/5974/29582 5194/6091/29583 -f 5134/5919/29584 5136/5969/29585 5194/6091/29586 -f 5195/5973/29587 5187/5958/29588 5111/5971/29589 -f 5111/5971/29590 5118/5972/29591 5195/5973/29592 -f 5197/6093/29593 5187/6073/29594 5195/6094/29595 -f 5195/6094/29596 5196/6092/29597 5197/6093/29598 -f 5197/6093/29599 5302/6176/29600 5187/6073/29601 -f 5134/5919/29602 5194/6091/29603 5197/6093/29604 -f 5197/6093/29605 5196/6092/29606 5134/5919/29607 -f 5118/5972/29608 5120/5980/29609 5198/5983/29610 -f 5198/5983/29611 5195/5973/29612 5118/5972/29613 -f 5195/6094/29614 5198/6096/29615 5199/6095/29616 -f 5199/6095/29617 5196/6092/29618 5195/6094/29619 -f 5196/6092/29620 5199/6095/29621 5135/5920/29622 -f 5135/5920/29623 5134/5919/29624 5196/6092/29625 -f 5200/6029/29626 5201/6035/29627 5119/5912/29628 -f 5119/5912/29629 5122/5928/29630 5200/6029/29631 -f 5201/6035/29632 5200/6029/29633 5202/6036/29634 -f 5202/6036/29635 5203/6037/29636 5201/6035/29637 -f 5203/6037/29638 5202/6036/29639 5204/6038/29640 -f 5204/6038/29641 5205/6039/29642 5203/6037/29643 -f 5206/6040/29644 5200/6029/29645 5122/5928/29646 -f 5122/5928/29647 5124/5930/29648 5206/6040/29649 -f 5200/6029/29650 5206/6040/29651 5207/6041/29652 -f 5207/6041/29653 5202/6036/29654 5200/6029/29655 -f 5202/6036/29656 5207/6041/29657 5208/6042/29658 -f 5208/6042/29659 5204/6038/29660 5202/6036/29661 -f 5119/5912/29662 5201/6035/29663 5209/6043/29664 -f 5209/6043/29665 5120/5924/29666 5119/5912/29667 -f 5210/6044/29668 5209/6043/29669 5201/6035/29670 -f 5201/6035/29671 5203/6037/29672 5210/6044/29673 -f 5203/6037/29674 5205/6039/29675 5211/6045/29676 -f 5211/6045/29677 5210/6044/29678 5203/6037/29679 -f 5213/6047/29680 5205/6039/29681 5204/6038/29682 -f 5204/6038/29683 5212/6046/29684 5213/6047/29685 -f 5208/6042/29686 5214/6048/29687 5212/6046/29688 -f 5212/6046/29689 5204/6038/29690 5208/6042/29691 -f 5205/6039/29692 5213/6047/29693 5215/6049/29694 -f 5215/6049/29695 5211/6045/29696 5205/6039/29697 -f 5216/6050/29698 5217/6051/29699 5213/6047/29700 -f 5213/6047/29701 5212/6046/29702 5216/6050/29703 -f 5218/6052/29704 5216/6050/29705 5212/6046/29706 -f 5212/6046/29707 5214/6048/29708 5218/6052/29709 -f 5213/6047/29710 5217/6051/29711 5219/6053/29712 -f 5219/6053/29713 5215/6049/29714 5213/6047/29715 -f 5221/6098/29716 5135/5920/29717 5199/6095/29718 -f 5199/6095/29719 5220/6097/29720 5221/6098/29721 -f 5223/6100/29722 5221/6098/29723 5220/6097/29724 -f 5220/6097/29725 5222/6099/29726 5223/6100/29727 -f 5225/6102/29728 5223/6100/29729 5222/6099/29730 -f 5222/6099/29731 5224/6101/29732 5225/6102/29733 -f 5225/6102/29734 5224/6101/29735 5226/6103/29736 -f 5226/6103/29737 5227/6104/29738 5225/6102/29739 -f 5228/6105/29740 5220/6097/29741 5199/6095/29742 -f 5199/6095/29743 5198/6096/29744 5228/6105/29745 -f 5220/6097/29746 5228/6105/29747 5229/6106/29748 -f 5229/6106/29749 5222/6099/29750 5220/6097/29751 -f 5230/6107/29752 5224/6101/29753 5222/6099/29754 -f 5222/6099/29755 5229/6106/29756 5230/6107/29757 -f 5231/6108/29758 5226/6103/29759 5224/6101/29760 -f 5224/6101/29761 5230/6107/29762 5231/6108/29763 -f 5135/5920/29764 5221/6098/29765 5232/6109/29766 -f 5232/6109/29767 5133/5921/29768 5135/5920/29769 -f 5221/6098/29770 5223/6100/29771 5233/6110/29772 -f 5233/6110/29773 5232/6109/29774 5221/6098/29775 -f 5223/6100/29776 5225/6102/29777 5234/6111/29778 -f 5234/6111/29779 5233/6110/29780 5223/6100/29781 -f 5235/6112/29782 5234/6111/29783 5225/6102/29784 -f 5225/6102/29785 5227/6104/29786 5235/6112/29787 -f 5133/5908/29788 5232/5991/29789 5206/5992/29790 -f 5206/5992/29791 5124/5909/29792 5133/5908/29793 -f 5232/5991/29794 5233/5993/29795 5207/5994/29796 -f 5207/5994/29797 5206/5992/29798 5232/5991/29799 -f 5234/5995/29800 5208/5996/29801 5207/5994/29802 -f 5207/5994/29803 5233/5993/29804 5234/5995/29805 -f 5235/5999/29806 5214/6000/29807 5208/5996/29808 -f 5208/5996/29809 5234/5995/29810 5235/5999/29811 -f 5235/5999/29812 5218/6003/29813 5214/6000/29814 -f 5209/6004/29815 5228/6013/29816 5198/5983/29817 -f 5198/5983/29818 5120/5980/29819 5209/6004/29820 -f 5210/6014/29821 5229/6015/29822 5228/6013/29823 -f 5228/6013/29824 5209/6004/29825 5210/6014/29826 -f 5211/6016/29827 5230/6017/29828 5229/6015/29829 -f 5229/6015/29830 5210/6014/29831 5211/6016/29832 -f 5211/6016/29833 5215/6018/29834 5231/6019/29835 -f 5231/6019/29836 5230/6017/29837 5211/6016/29838 -f 5215/6018/29839 5219/6020/29840 5231/6019/29841 -f 5236/6021/29842 5237/6022/29843 5218/6003/29844 -f 5218/6003/29845 5235/5999/29846 5236/6021/29847 -f 5218/6052/29848 5237/6055/29849 5238/6054/29850 -f 5238/6054/29851 5216/6050/29852 5218/6052/29853 -f 5239/6114/29854 5236/6113/29855 5235/6112/29856 -f 5235/6112/29857 5227/6104/29858 5239/6114/29859 -f 5226/6103/29860 5240/6115/29861 5239/6114/29862 -f 5239/6114/29863 5227/6104/29864 5226/6103/29865 -f 5241/6116/29866 5240/6115/29867 5226/6103/29868 -f 5226/6103/29869 5231/6108/29870 5241/6116/29871 -f 5216/6050/29872 5238/6054/29873 5242/6056/29874 -f 5242/6056/29875 5217/6051/29876 5216/6050/29877 -f 5217/6051/29878 5242/6056/29879 5243/6057/29880 -f 5243/6057/29881 5219/6053/29882 5217/6051/29883 -f 5241/6028/29884 5231/6019/29885 5219/6020/29886 -f 5219/6020/29887 5243/6026/29888 5241/6028/29889 -f 5244/6058/29890 5245/6067/29891 5243/6057/29892 -f 5243/6057/29893 5242/6056/29894 5244/6058/29895 -f 5246/6117/29896 5247/6118/29897 5240/6115/29898 -f 5240/6115/29899 5241/6116/29900 5246/6117/29901 -f 5243/6026/29902 5245/6030/29903 5246/6031/29904 -f 5246/6031/29905 5241/6028/29906 5243/6026/29907 -f 5246/6031/29908 5245/6030/29909 5248/6033/29910 -f 5248/6033/29911 5249/6034/29912 5246/6031/29913 -f 5248/6068/29914 5245/6067/29915 5244/6058/29916 -f 5249/6119/29917 5247/6118/29918 5246/6117/29919 -f 5249/6071/29920 5248/6068/29921 5250/6069/29922 -f 5250/6069/29923 5251/6070/29924 5249/6071/29925 -f 5250/6069/29926 5248/6068/29927 5244/6058/29928 -f 5252/6072/29929 5253/6074/29930 5250/6069/29931 -f 5250/6069/29932 5244/6058/29933 5252/6072/29934 -f 5254/6076/29935 5255/6077/29936 5253/6074/29937 -f 5253/6074/29938 5252/6072/29939 5254/6076/29940 -f 5256/6078/29941 5252/6072/29942 5244/6058/29943 -f 5244/6058/29944 5242/6056/29945 5256/6078/29946 -f 5256/6078/29947 5254/6076/29948 5252/6072/29949 -f 5257/6080/29950 5258/6081/29951 5254/6076/29952 -f 5254/6076/29953 5256/6078/29954 5257/6080/29955 -f 5259/6084/29956 5260/6085/29957 5254/6076/29958 -f 5254/6076/29959 5258/6081/29960 5259/6084/29961 -f 5262/6147/29962 5259/6084/29963 5258/6081/29964 -f 5258/6081/29965 5261/6146/29966 5262/6147/29967 -f 5261/6146/29968 5258/6081/29969 5257/6080/29970 -f 5264/6149/29971 5262/6147/29972 5261/6146/29973 -f 5261/6146/29974 5263/6148/29975 5264/6149/29976 -f 5265/6150/29977 5263/6148/29978 5267/6152/29979 -f 5267/6152/29980 5268/6153/29981 5265/6150/29982 -f 5270/6155/29983 5268/6153/29984 5267/6152/29985 -f 5267/6152/29986 5269/6154/29987 5270/6155/29988 -f 5261/6146/29989 5257/6080/29990 5267/6152/29991 -f 5267/6152/29992 5263/6148/29993 5261/6146/29994 -f 5271/6156/29995 5272/6157/29996 5299/6158/29997 -f 5273/6159/29998 5271/6156/29999 5267/6152/30000 -f 5267/6152/30001 5257/6080/30002 5273/6159/30003 -f 5257/6080/30004 5256/6078/30005 5242/6056/30006 -f 5242/6056/30007 5238/6054/30008 5257/6080/30009 -f 5273/6159/30010 5257/6080/30011 5238/6054/30012 -f 5274/6160/30013 5273/6159/30014 5238/6054/30015 -f 5238/6054/30016 5237/6055/30017 5274/6160/30018 -f 5275/6161/30019 5271/6156/30020 5273/6159/30021 -f 5273/6159/30022 5274/6160/30023 5275/6161/30024 -f 5276/6060/30025 5274/6059/30026 5237/6022/30027 -f 5237/6022/30028 5236/6021/30029 5276/6060/30030 -f 5274/6059/30031 5276/6060/30032 5277/6061/30033 -f 5277/6061/30034 5275/6062/30035 5274/6059/30036 -f 5278/6120/30037 5279/6121/30038 5240/6115/30039 -f 5240/6115/30040 5247/6118/30041 5278/6120/30042 -f 5286/6122/30043 5280/6123/30044 5279/6121/30045 -f 5279/6121/30046 5278/6120/30047 5286/6122/30048 -f 5239/6114/30049 5240/6115/30050 5279/6121/30051 -f 5279/6121/30052 5280/6123/30053 5239/6114/30054 -f 5281/6124/30055 5239/6114/30056 5280/6123/30057 -f 5247/6118/30058 5249/6119/30059 5251/6125/30060 -f 5251/6125/30061 5278/6120/30062 5247/6118/30063 -f 5278/6120/30064 5251/6125/30065 5282/6126/30066 -f 5282/6126/30067 5286/6122/30068 5278/6120/30069 -f 5253/6074/30070 5282/6162/30071 5251/6070/30072 -f 5251/6070/30073 5250/6069/30074 5253/6074/30075 -f 5253/6074/30076 5255/6077/30077 5283/6163/30078 -f 5283/6163/30079 5282/6162/30080 5253/6074/30081 -f 5286/6122/30082 5282/6126/30083 5283/6127/30084 -s 2 -f 5285/6165/30085 5260/6085/30086 5259/6084/30087 -f 5259/6084/30088 5284/6164/30089 5285/6165/30090 -s 1 -f 5286/6122/30091 5285/6129/30092 5284/6130/30093 -f 5284/6130/30094 5288/6128/30095 5286/6122/30096 -s 4 -f 5285/6165/30097 5286/6166/30098 5254/6076/30099 -f 5254/6076/30100 5260/6085/30101 5285/6165/30102 -s 2 -f 5283/6163/30103 5255/6077/30104 5254/6076/30105 -f 5254/6076/30106 5286/6166/30107 5283/6163/30108 -f 5259/6084/30109 5262/6147/30110 5287/6167/30111 -f 5287/6167/30112 5284/6164/30113 5259/6084/30114 -s 1 -f 5288/6128/30115 5284/6130/30116 5287/6131/30117 -s 2 -f 5262/6147/30118 5264/6149/30119 5289/6168/30120 -f 5289/6168/30121 5287/6167/30122 5262/6147/30123 -s 1 -f 5287/6131/30124 5289/6133/30125 5290/6132/30126 -f 5290/6132/30127 5288/6128/30128 5287/6131/30129 -f 5286/6122/30130 5288/6128/30131 5280/6123/30132 -f 5280/6123/30133 5288/6128/30134 5290/6132/30135 -s 2 -f 5289/6168/30136 5264/6149/30137 5266/6151/30138 -f 5266/6151/30139 5291/6169/30140 5289/6168/30141 -s 1 -f 5289/6133/30142 5291/6135/30143 5292/6134/30144 -f 5292/6134/30145 5290/6132/30146 5289/6133/30147 -f 5293/6136/30148 5294/6137/30149 5290/6132/30150 -f 5290/6132/30151 5292/6134/30152 5293/6136/30153 -f 5280/6123/30154 5290/6132/30155 5294/6137/30156 -f 5294/6137/30157 5293/6136/30158 5295/6138/30159 -f 5295/6138/30160 5296/6139/30161 5294/6137/30162 -f 5280/6123/30163 5294/6137/30164 5297/6140/30165 -f 5297/6140/30166 5281/6124/30167 5280/6123/30168 -f 5297/6140/30169 5277/6141/30170 5276/6142/30171 -f 5276/6142/30172 5281/6124/30173 5297/6140/30174 -f 5236/6113/30175 5239/6114/30176 5281/6124/30177 -f 5281/6124/30178 5276/6142/30179 5236/6113/30180 -f 5294/6137/30181 5296/6139/30182 5300/6143/30183 -f 5297/6140/30184 5294/6137/30185 5300/6143/30186 -f 5297/6140/30187 5300/6143/30188 5301/6144/30189 -f 5301/6144/30190 5298/6145/30191 5277/6141/30192 -f 5277/6141/30193 5297/6140/30194 5301/6144/30195 -f 5275/6062/30196 5277/6061/30197 5298/6083/30198 -f 5275/6161/30199 5298/6170/30200 5272/6157/30201 -f 5272/6157/30202 5271/6156/30203 5275/6161/30204 -s 4 -f 5292/6171/30205 5291/6169/30206 5266/6151/30207 -f 5266/6151/30208 5265/6150/30209 5292/6171/30210 -s 1 -f 5293/6173/30211 5268/6153/30212 5270/6155/30213 -f 5270/6155/30214 5295/6172/30215 5293/6173/30216 -f 5268/6153/30217 5293/6173/30218 5292/6171/30219 -f 5292/6171/30220 5265/6150/30221 5268/6153/30222 -f 5295/6172/30223 5270/6155/30224 5269/6154/30225 -f 5269/6154/30226 5296/6174/30227 5295/6172/30228 -f 5296/6174/30229 5269/6154/30230 5299/6158/30231 -f 5299/6158/30232 5300/6175/30233 5296/6174/30234 -f 5271/6156/30235 5299/6158/30236 5269/6154/30237 -f 5269/6154/30238 5267/6152/30239 5271/6156/30240 -f 5272/6157/30241 5298/6170/30242 5300/6175/30243 -f 5300/6175/30244 5299/6158/30245 5272/6157/30246 -f 5300/6143/30247 5298/6145/30248 5301/6144/30249 -f 5154/5949/30250 5141/5938/30251 5157/5953/30252 -f 5157/5953/30253 5141/5938/30254 5161/5956/30255 -f 5266/6151/30256 5264/6149/30257 5263/6148/30258 -f 5263/6148/30259 5265/6150/30260 5266/6151/30261 -f 5197/6093/30262 5194/6091/30263 5189/6075/30264 -f 5189/6075/30265 5302/6176/30266 5197/6093/30267 -f 5189/6075/30268 5184/6012/30269 5303/6177/30270 -f 5303/6177/30271 5302/6176/30272 5189/6075/30273 -f 5184/6012/30274 5185/6063/30275 5186/6065/30276 -f 5186/6065/30277 5303/6177/30278 5184/6012/30279 -f 5304/6180/30280 5320/6181/30281 5321/6178/30282 -f 5321/6178/30283 5305/6179/30284 5304/6180/30285 -f 5305/6179/30286 5321/6178/30287 5322/6182/30288 -f 5322/6182/30289 5306/6183/30290 5305/6179/30291 -f 5306/6183/30292 5322/6182/30293 5323/6184/30294 -f 5323/6184/30295 5307/6185/30296 5306/6183/30297 -f 5307/6185/30298 5323/6184/30299 5324/6186/30300 -f 5324/6186/30301 5308/6187/30302 5307/6185/30303 -f 5308/6187/30304 5324/6186/30305 5325/6188/30306 -f 5325/6188/30307 5309/6189/30308 5308/6187/30309 -f 5309/6189/30310 5325/6188/30311 5326/6190/30312 -f 5326/6190/30313 5310/6191/30314 5309/6189/30315 -f 5310/6191/30316 5326/6190/30317 5327/6192/30318 -f 5327/6192/30319 5311/6193/30320 5310/6191/30321 -f 5311/6193/30322 5327/6192/30323 5328/6194/30324 -f 5328/6194/30325 5312/6195/30326 5311/6193/30327 -f 5312/6195/30328 5328/6194/30329 5329/6196/30330 -f 5329/6196/30331 5313/6197/30332 5312/6195/30333 -f 5313/6197/30334 5329/6196/30335 5330/6198/30336 -f 5330/6198/30337 5314/6199/30338 5313/6197/30339 -f 5314/6199/30340 5330/6198/30341 5331/6200/30342 -f 5331/6200/30343 5315/6201/30344 5314/6199/30345 -f 5315/6201/30346 5331/6200/30347 5332/6202/30348 -f 5332/6202/30349 5316/6203/30350 5315/6201/30351 -f 5316/6203/30352 5332/6202/30353 5333/6204/30354 -f 5333/6204/30355 5317/6205/30356 5316/6203/30357 -f 5317/6205/30358 5333/6204/30359 5334/6206/30360 -f 5334/6206/30361 5318/6207/30362 5317/6205/30363 -f 5318/6207/30364 5334/6206/30365 5335/6208/30366 -f 5335/6208/30367 5319/6209/30368 5318/6207/30369 -f 5319/6209/30370 5335/6208/30371 5320/6181/30372 -f 5320/6181/30373 5304/6180/30374 5319/6209/30375 -f 5320/6181/30376 5336/6211/30377 5337/6210/30378 -f 5337/6210/30379 5321/6178/30380 5320/6181/30381 -f 5321/6178/30382 5337/6210/30383 5338/6212/30384 -f 5338/6212/30385 5322/6182/30386 5321/6178/30387 -f 5322/6182/30388 5338/6212/30389 5339/6213/30390 -f 5339/6213/30391 5323/6184/30392 5322/6182/30393 -f 5323/6184/30394 5339/6213/30395 5340/6214/30396 -f 5340/6214/30397 5324/6186/30398 5323/6184/30399 -f 5324/6186/30400 5340/6214/30401 5341/6215/30402 -f 5341/6215/30403 5325/6188/30404 5324/6186/30405 -f 5325/6188/30406 5341/6215/30407 5342/6216/30408 -f 5342/6216/30409 5326/6190/30410 5325/6188/30411 -f 5326/6190/30412 5342/6216/30413 5343/6217/30414 -f 5343/6217/30415 5327/6192/30416 5326/6190/30417 -f 5327/6192/30418 5343/6217/30419 5344/6218/30420 -f 5344/6218/30421 5328/6194/30422 5327/6192/30423 -f 5328/6194/30424 5344/6218/30425 5345/6219/30426 -f 5345/6219/30427 5329/6196/30428 5328/6194/30429 -f 5329/6196/30430 5345/6219/30431 5346/6220/30432 -f 5346/6220/30433 5330/6198/30434 5329/6196/30435 -f 5330/6198/30436 5346/6220/30437 5347/6221/30438 -f 5347/6221/30439 5331/6200/30440 5330/6198/30441 -f 5331/6200/30442 5347/6221/30443 5348/6222/30444 -f 5348/6222/30445 5332/6202/30446 5331/6200/30447 -f 5332/6202/30448 5348/6222/30449 5349/6223/30450 -f 5349/6223/30451 5333/6204/30452 5332/6202/30453 -f 5333/6204/30454 5349/6223/30455 5350/6224/30456 -f 5350/6224/30457 5334/6206/30458 5333/6204/30459 -f 5334/6206/30460 5350/6224/30461 5351/6225/30462 -f 5351/6225/30463 5335/6208/30464 5334/6206/30465 -f 5335/6208/30466 5351/6225/30467 5336/6211/30468 -f 5336/6211/30469 5320/6181/30470 5335/6208/30471 -f 5336/6211/30472 5352/6227/30473 5353/6226/30474 -f 5353/6226/30475 5337/6210/30476 5336/6211/30477 -f 5337/6210/30478 5353/6226/30479 5354/6228/30480 -f 5354/6228/30481 5338/6212/30482 5337/6210/30483 -f 5338/6212/30484 5354/6380/30485 5355/6229/30486 -f 5355/6229/30487 5339/6213/30488 5338/6212/30489 -f 5339/6213/30490 5355/6229/30491 5356/6230/30492 -f 5356/6230/30493 5340/6214/30494 5339/6213/30495 -f 5340/6214/30496 5356/6230/30497 5357/6231/30498 -f 5357/6231/30499 5341/6215/30500 5340/6214/30501 -f 5341/6215/30502 5357/6381/30503 5358/6232/30504 -f 5358/6232/30505 5342/6216/30506 5341/6215/30507 -f 5342/6216/30508 5358/6232/30509 5359/6233/30510 -f 5359/6233/30511 5343/6217/30512 5342/6216/30513 -f 5343/6217/30514 5359/6233/30515 5360/6234/30516 -f 5360/6234/30517 5344/6218/30518 5343/6217/30519 -f 5344/6218/30520 5360/6382/30521 5361/6235/30522 -f 5361/6235/30523 5345/6219/30524 5344/6218/30525 -f 5345/6219/30526 5361/6235/30527 5362/6236/30528 -f 5362/6236/30529 5346/6220/30530 5345/6219/30531 -f 5346/6220/30532 5362/6383/30533 5363/6237/30534 -f 5363/6237/30535 5347/6221/30536 5346/6220/30537 -f 5347/6221/30538 5363/6237/30539 5364/6238/30540 -f 5364/6238/30541 5348/6222/30542 5347/6221/30543 -f 5348/6222/30544 5364/6384/30545 5365/6239/30546 -f 5365/6239/30547 5349/6223/30548 5348/6222/30549 -f 5349/6223/30550 5365/6239/30551 5366/6240/30552 -f 5366/6240/30553 5350/6224/30554 5349/6223/30555 -f 5350/6224/30556 5366/6240/30557 5367/6241/30558 -f 5367/6241/30559 5351/6225/30560 5350/6224/30561 -f 5351/6225/30562 5367/6385/30563 5352/6227/30564 -f 5352/6227/30565 5336/6211/30566 5351/6225/30567 -f 5352/6227/30568 5368/6243/30569 5369/6242/30570 -f 5369/6242/30571 5353/6226/30572 5352/6227/30573 -f 5353/6226/30574 5369/6242/30575 5370/6244/30576 -f 5370/6244/30577 5354/6228/30578 5353/6226/30579 -f 5354/6380/30580 5370/6386/30581 5371/6245/30582 -f 5371/6245/30583 5355/6229/30584 5354/6380/30585 -f 5355/6229/30586 5371/6245/30587 5372/6246/30588 -f 5372/6246/30589 5356/6230/30590 5355/6229/30591 -f 5356/6230/30592 5372/6246/30593 5373/6247/30594 -f 5373/6247/30595 5357/6231/30596 5356/6230/30597 -f 5357/6381/30598 5373/6387/30599 5374/6248/30600 -f 5374/6248/30601 5358/6232/30602 5357/6381/30603 -f 5358/6232/30604 5374/6248/30605 5375/6249/30606 -f 5375/6249/30607 5359/6233/30608 5358/6232/30609 -f 5359/6233/30610 5375/6249/30611 5376/6250/30612 -f 5376/6250/30613 5360/6234/30614 5359/6233/30615 -f 5360/6382/30616 5376/6388/30617 5377/6251/30618 -f 5377/6251/30619 5361/6235/30620 5360/6382/30621 -f 5361/6235/30622 5377/6251/30623 5378/6252/30624 -f 5378/6252/30625 5362/6236/30626 5361/6235/30627 -f 5362/6383/30628 5378/6389/30629 5379/6253/30630 -f 5379/6253/30631 5363/6237/30632 5362/6383/30633 -f 5363/6237/30634 5379/6253/30635 5380/6254/30636 -f 5380/6254/30637 5364/6238/30638 5363/6237/30639 -f 5364/6384/30640 5380/6390/30641 5381/6255/30642 -f 5381/6255/30643 5365/6239/30644 5364/6384/30645 -f 5365/6239/30646 5381/6255/30647 5382/6256/30648 -f 5382/6256/30649 5366/6240/30650 5365/6239/30651 -f 5366/6240/30652 5382/6256/30653 5383/6257/30654 -f 5383/6257/30655 5367/6241/30656 5366/6240/30657 -f 5367/6385/30658 5383/6391/30659 5368/6243/30660 -f 5368/6243/30661 5352/6227/30662 5367/6385/30663 -f 5401/6260/30664 5402/6261/30665 5403/6258/30666 -f 5403/6258/30667 5388/6259/30668 5401/6260/30669 -f 5386/6264/30670 5389/6265/30671 5390/6262/30672 -f 5390/6262/30673 5385/6263/30674 5386/6264/30675 -f 5386/6264/30676 5387/6267/30677 5404/6266/30678 -f 5404/6266/30679 5389/6265/30680 5386/6264/30681 -f 5387/6267/30682 5388/6259/30683 5403/6258/30684 -f 5403/6258/30685 5404/6266/30686 5387/6267/30687 -f 5385/6263/30688 5390/6262/30689 5391/6268/30690 -f 5391/6268/30691 5384/6269/30692 5385/6263/30693 -f 5391/6268/30694 5392/6271/30695 5393/6270/30696 -f 5393/6270/30697 5384/6269/30698 5391/6268/30699 -f 5393/6270/30700 5394/6273/30701 5395/6272/30702 -f 5395/6272/30703 5384/6269/30704 5393/6270/30705 -f 5385/6263/30706 5384/6269/30707 5395/6272/30708 -f 5395/6272/30709 5396/6274/30710 5385/6263/30711 -f 5386/6264/30712 5385/6263/30713 5396/6274/30714 -f 5396/6274/30715 5397/6275/30716 5386/6264/30717 -f 5398/6276/30718 5387/6267/30719 5386/6264/30720 -f 5386/6264/30721 5397/6275/30722 5398/6276/30723 -f 5399/6277/30724 5388/6259/30725 5387/6267/30726 -f 5387/6267/30727 5398/6276/30728 5399/6277/30729 -f 5388/6259/30730 5399/6277/30731 5400/6278/30732 -f 5400/6278/30733 5401/6260/30734 5388/6259/30735 -f 5390/6262/30736 5389/6265/30737 5304/6180/30738 -f 5304/6180/30739 5305/6179/30740 5390/6262/30741 -f 5391/6268/30742 5390/6262/30743 5305/6179/30744 -f 5305/6179/30745 5306/6183/30746 5391/6268/30747 -f 5392/6271/30748 5391/6268/30749 5306/6183/30750 -f 5306/6183/30751 5307/6185/30752 5392/6271/30753 -f 5393/6270/30754 5392/6271/30755 5307/6185/30756 -f 5307/6185/30757 5308/6187/30758 5393/6270/30759 -f 5394/6273/30760 5393/6270/30761 5308/6187/30762 -f 5308/6187/30763 5309/6189/30764 5394/6273/30765 -f 5395/6272/30766 5394/6273/30767 5309/6189/30768 -f 5309/6189/30769 5310/6191/30770 5395/6272/30771 -f 5396/6274/30772 5395/6272/30773 5310/6191/30774 -f 5310/6191/30775 5311/6193/30776 5396/6274/30777 -f 5397/6275/30778 5396/6274/30779 5311/6193/30780 -f 5311/6193/30781 5312/6195/30782 5397/6275/30783 -f 5398/6276/30784 5397/6275/30785 5312/6195/30786 -f 5312/6195/30787 5313/6197/30788 5398/6276/30789 -f 5399/6277/30790 5398/6276/30791 5313/6197/30792 -f 5313/6197/30793 5314/6199/30794 5399/6277/30795 -f 5400/6278/30796 5399/6277/30797 5314/6199/30798 -f 5314/6199/30799 5315/6201/30800 5400/6278/30801 -f 5401/6260/30802 5400/6278/30803 5315/6201/30804 -f 5315/6201/30805 5316/6203/30806 5401/6260/30807 -f 5402/6261/30808 5401/6260/30809 5316/6203/30810 -f 5316/6203/30811 5317/6205/30812 5402/6261/30813 -f 5403/6258/30814 5402/6261/30815 5317/6205/30816 -f 5317/6205/30817 5318/6207/30818 5403/6258/30819 -f 5404/6266/30820 5403/6258/30821 5318/6207/30822 -f 5318/6207/30823 5319/6209/30824 5404/6266/30825 -f 5389/6265/30826 5404/6266/30827 5319/6209/30828 -f 5319/6209/30829 5304/6180/30830 5389/6265/30831 -f 5405/6281/30832 5408/6282/30833 5407/6279/30834 -f 5407/6279/30835 5406/6280/30836 5405/6281/30837 -f 5408/6282/30838 5410/6284/30839 5409/6283/30840 -f 5409/6283/30841 5407/6279/30842 5408/6282/30843 -f 5410/6284/30844 5412/6286/30845 5411/6285/30846 -f 5411/6285/30847 5409/6283/30848 5410/6284/30849 -f 5412/6286/30850 5414/6288/30851 5413/6287/30852 -f 5413/6287/30853 5411/6285/30854 5412/6286/30855 -f 5414/6288/30856 5416/6290/30857 5415/6289/30858 -f 5415/6289/30859 5413/6287/30860 5414/6288/30861 -f 5416/6290/30862 5418/6292/30863 5417/6291/30864 -f 5417/6291/30865 5415/6289/30866 5416/6290/30867 -f 5418/6292/30868 5420/6294/30869 5419/6293/30870 -f 5419/6293/30871 5417/6291/30872 5418/6292/30873 -f 5420/6294/30874 5422/6296/30875 5421/6295/30876 -f 5421/6295/30877 5419/6293/30878 5420/6294/30879 -f 5422/6296/30880 5424/6298/30881 5423/6297/30882 -f 5423/6297/30883 5421/6295/30884 5422/6296/30885 -f 5424/6298/30886 5426/6300/30887 5425/6299/30888 -f 5425/6299/30889 5423/6297/30890 5424/6298/30891 -f 5426/6300/30892 5428/6302/30893 5427/6301/30894 -f 5427/6301/30895 5425/6299/30896 5426/6300/30897 -f 5428/6302/30898 5430/6304/30899 5429/6303/30900 -f 5429/6303/30901 5427/6301/30902 5428/6302/30903 -f 5430/6304/30904 5432/6306/30905 5431/6305/30906 -f 5431/6305/30907 5429/6303/30908 5430/6304/30909 -f 5432/6306/30910 5434/6308/30911 5433/6307/30912 -f 5433/6307/30913 5431/6305/30914 5432/6306/30915 -f 5434/6308/30916 5436/6310/30917 5435/6309/30918 -f 5435/6309/30919 5433/6307/30920 5434/6308/30921 -f 5436/6310/30922 5405/6281/30923 5406/6280/30924 -f 5406/6280/30925 5435/6309/30926 5436/6310/30927 -f 5406/6280/30928 5407/6279/30929 5438/6311/30930 -f 5438/6311/30931 5437/6312/30932 5406/6280/30933 -f 5407/6279/30934 5409/6283/30935 5439/6313/30936 -f 5439/6313/30937 5438/6311/30938 5407/6279/30939 -f 5409/6283/30940 5411/6285/30941 5440/6314/30942 -f 5440/6314/30943 5439/6313/30944 5409/6283/30945 -f 5411/6285/30946 5413/6287/30947 5441/6315/30948 -f 5441/6315/30949 5440/6314/30950 5411/6285/30951 -f 5413/6287/30952 5415/6289/30953 5442/6316/30954 -f 5442/6316/30955 5441/6315/30956 5413/6287/30957 -f 5415/6289/30958 5417/6291/30959 5443/6317/30960 -f 5443/6317/30961 5442/6316/30962 5415/6289/30963 -f 5417/6291/30964 5419/6293/30965 5444/6318/30966 -f 5444/6318/30967 5443/6317/30968 5417/6291/30969 -f 5419/6293/30970 5421/6295/30971 5445/6319/30972 -f 5445/6319/30973 5444/6318/30974 5419/6293/30975 -f 5421/6295/30976 5423/6297/30977 5446/6320/30978 -f 5446/6320/30979 5445/6319/30980 5421/6295/30981 -f 5423/6297/30982 5425/6299/30983 5447/6321/30984 -f 5447/6321/30985 5446/6320/30986 5423/6297/30987 -f 5425/6299/30988 5427/6301/30989 5448/6322/30990 -f 5448/6322/30991 5447/6321/30992 5425/6299/30993 -f 5427/6301/30994 5429/6303/30995 5449/6323/30996 -f 5449/6323/30997 5448/6322/30998 5427/6301/30999 -f 5429/6303/31000 5431/6305/31001 5450/6324/31002 -f 5450/6324/31003 5449/6323/31004 5429/6303/31005 -f 5431/6305/31006 5433/6307/31007 5451/6325/31008 -f 5451/6325/31009 5450/6324/31010 5431/6305/31011 -f 5433/6307/31012 5435/6309/31013 5452/6326/31014 -f 5452/6326/31015 5451/6325/31016 5433/6307/31017 -f 5435/6309/31018 5406/6280/31019 5437/6312/31020 -f 5437/6312/31021 5452/6326/31022 5435/6309/31023 -f 5437/6312/31024 5438/6311/31025 5454/6327/31026 -f 5454/6327/31027 5453/6328/31028 5437/6312/31029 -f 5438/6311/31030 5439/6313/31031 5455/6329/31032 -f 5455/6329/31033 5454/6392/31034 5438/6311/31035 -f 5439/6313/31036 5440/6314/31037 5456/6330/31038 -f 5456/6330/31039 5455/6329/31040 5439/6313/31041 -f 5440/6314/31042 5441/6315/31043 5457/6331/31044 -f 5457/6331/31045 5456/6330/31046 5440/6314/31047 -f 5441/6315/31048 5442/6316/31049 5458/6332/31050 -f 5458/6332/31051 5457/6393/31052 5441/6315/31053 -f 5442/6316/31054 5443/6317/31055 5459/6333/31056 -f 5459/6333/31057 5458/6332/31058 5442/6316/31059 -f 5443/6317/31060 5444/6318/31061 5460/6334/31062 -f 5460/6334/31063 5459/6333/31064 5443/6317/31065 -f 5444/6318/31066 5445/6319/31067 5461/6335/31068 -f 5461/6335/31069 5460/6394/31070 5444/6318/31071 -f 5445/6319/31072 5446/6320/31073 5462/6336/31074 -f 5462/6336/31075 5461/6335/31076 5445/6319/31077 -f 5446/6320/31078 5447/6321/31079 5463/6337/31080 -f 5463/6337/31081 5462/6395/31082 5446/6320/31083 -f 5447/6321/31084 5448/6322/31085 5464/6338/31086 -f 5464/6338/31087 5463/6337/31088 5447/6321/31089 -f 5448/6322/31090 5449/6323/31091 5465/6339/31092 -f 5465/6339/31093 5464/6396/31094 5448/6322/31095 -f 5449/6323/31096 5450/6324/31097 5466/6340/31098 -f 5466/6340/31099 5465/6339/31100 5449/6323/31101 -f 5450/6324/31102 5451/6325/31103 5467/6341/31104 -f 5467/6341/31105 5466/6340/31106 5450/6324/31107 -f 5451/6325/31108 5452/6326/31109 5468/6342/31110 -f 5468/6342/31111 5467/6397/31112 5451/6325/31113 -f 5452/6326/31114 5437/6312/31115 5453/6328/31116 -f 5453/6328/31117 5468/6342/31118 5452/6326/31119 -f 5453/6328/31120 5454/6327/31121 5470/6343/31122 -f 5470/6343/31123 5469/6344/31124 5453/6328/31125 -f 5454/6392/31126 5455/6329/31127 5471/6345/31128 -f 5471/6345/31129 5470/6398/31130 5454/6392/31131 -f 5455/6329/31132 5456/6330/31133 5472/6346/31134 -f 5472/6346/31135 5471/6345/31136 5455/6329/31137 -f 5456/6330/31138 5457/6331/31139 5473/6347/31140 -f 5473/6347/31141 5472/6346/31142 5456/6330/31143 -f 5457/6393/31144 5458/6332/31145 5474/6348/31146 -f 5474/6348/31147 5473/6399/31148 5457/6393/31149 -f 5458/6332/31150 5459/6333/31151 5475/6349/31152 -f 5475/6349/31153 5474/6348/31154 5458/6332/31155 -f 5459/6333/31156 5460/6334/31157 5476/6350/31158 -f 5476/6350/31159 5475/6349/31160 5459/6333/31161 -f 5460/6394/31162 5461/6335/31163 5477/6351/31164 -f 5477/6351/31165 5476/6400/31166 5460/6394/31167 -f 5461/6335/31168 5462/6336/31169 5478/6352/31170 -f 5478/6352/31171 5477/6351/31172 5461/6335/31173 -f 5462/6395/31174 5463/6337/31175 5479/6353/31176 -f 5479/6353/31177 5478/6401/31178 5462/6395/31179 -f 5463/6337/31180 5464/6338/31181 5480/6354/31182 -f 5480/6354/31183 5479/6353/31184 5463/6337/31185 -f 5464/6396/31186 5465/6339/31187 5481/6355/31188 -f 5481/6355/31189 5480/6402/31190 5464/6396/31191 -f 5465/6339/31192 5466/6340/31193 5482/6356/31194 -f 5482/6356/31195 5481/6355/31196 5465/6339/31197 -f 5466/6340/31198 5467/6341/31199 5483/6357/31200 -f 5483/6357/31201 5482/6356/31202 5466/6340/31203 -f 5467/6397/31204 5468/6342/31205 5484/6358/31206 -f 5484/6358/31207 5483/6403/31208 5467/6397/31209 -f 5468/6342/31210 5453/6328/31211 5469/6344/31212 -f 5469/6344/31213 5484/6358/31214 5468/6342/31215 -f 5485/6361/31216 5488/6362/31217 5487/6359/31218 -f 5487/6359/31219 5486/6360/31220 5485/6361/31221 -f 5492/6365/31222 5491/6366/31223 5490/6363/31224 -f 5490/6363/31225 5489/6364/31226 5492/6365/31227 -f 5492/6365/31228 5489/6364/31229 5493/6367/31230 -f 5493/6367/31231 5494/6368/31232 5492/6365/31233 -f 5494/6368/31234 5493/6367/31235 5487/6359/31236 -f 5487/6359/31237 5488/6362/31238 5494/6368/31239 -f 5491/6366/31240 5496/6370/31241 5495/6369/31242 -f 5495/6369/31243 5490/6363/31244 5491/6366/31245 -f 5495/6369/31246 5496/6370/31247 5498/6371/31248 -f 5498/6371/31249 5497/6372/31250 5495/6369/31251 -f 5498/6371/31252 5496/6370/31253 5500/6373/31254 -f 5500/6373/31255 5499/6374/31256 5498/6371/31257 -f 5491/6366/31258 5501/6375/31259 5500/6373/31260 -f 5500/6373/31261 5496/6370/31262 5491/6366/31263 -f 5492/6365/31264 5502/6376/31265 5501/6375/31266 -f 5501/6375/31267 5491/6366/31268 5492/6365/31269 -f 5503/6377/31270 5502/6376/31271 5492/6365/31272 -f 5492/6365/31273 5494/6368/31274 5503/6377/31275 -f 5504/6378/31276 5503/6377/31277 5494/6368/31278 -f 5494/6368/31279 5488/6362/31280 5504/6378/31281 -f 5488/6362/31282 5485/6361/31283 5505/6379/31284 -f 5505/6379/31285 5504/6378/31286 5488/6362/31287 -f 5490/6363/31288 5408/6282/31289 5405/6281/31290 -f 5405/6281/31291 5489/6364/31292 5490/6363/31293 -f 5495/6369/31294 5410/6284/31295 5408/6282/31296 -f 5408/6282/31297 5490/6363/31298 5495/6369/31299 -f 5497/6372/31300 5412/6286/31301 5410/6284/31302 -f 5410/6284/31303 5495/6369/31304 5497/6372/31305 -f 5498/6371/31306 5414/6288/31307 5412/6286/31308 -f 5412/6286/31309 5497/6372/31310 5498/6371/31311 -f 5499/6374/31312 5416/6290/31313 5414/6288/31314 -f 5414/6288/31315 5498/6371/31316 5499/6374/31317 -f 5500/6373/31318 5418/6292/31319 5416/6290/31320 -f 5416/6290/31321 5499/6374/31322 5500/6373/31323 -f 5501/6375/31324 5420/6294/31325 5418/6292/31326 -f 5418/6292/31327 5500/6373/31328 5501/6375/31329 -f 5502/6376/31330 5422/6296/31331 5420/6294/31332 -f 5420/6294/31333 5501/6375/31334 5502/6376/31335 -f 5503/6377/31336 5424/6298/31337 5422/6296/31338 -f 5422/6296/31339 5502/6376/31340 5503/6377/31341 -f 5504/6378/31342 5426/6300/31343 5424/6298/31344 -f 5424/6298/31345 5503/6377/31346 5504/6378/31347 -f 5505/6379/31348 5428/6302/31349 5426/6300/31350 -f 5426/6300/31351 5504/6378/31352 5505/6379/31353 -f 5485/6361/31354 5430/6304/31355 5428/6302/31356 -f 5428/6302/31357 5505/6379/31358 5485/6361/31359 -f 5486/6360/31360 5432/6306/31361 5430/6304/31362 -f 5430/6304/31363 5485/6361/31364 5486/6360/31365 -f 5487/6359/31366 5434/6308/31367 5432/6306/31368 -f 5432/6306/31369 5486/6360/31370 5487/6359/31371 -f 5493/6367/31372 5436/6310/31373 5434/6308/31374 -f 5434/6308/31375 5487/6359/31376 5493/6367/31377 -f 5489/6364/31378 5405/6281/31379 5436/6310/31380 -f 5436/6310/31381 5493/6367/31382 5489/6364/31383 -f 5520/6406/31384 5507/6407/31385 5596/6404/31386 -f 5596/6404/31387 5521/6405/31388 5520/6406/31389 -f 5522/6408/31390 5510/6409/31391 5507/6407/31392 -f 5507/6407/31393 5520/6406/31394 5522/6408/31395 -f 5515/6412/31396 5516/6413/31397 5531/6410/31398 -f 5531/6410/31399 5529/6411/31400 5515/6412/31401 -f 5519/6416/31402 5518/6417/31403 5528/6414/31404 -f 5528/6414/31405 5527/6415/31406 5519/6416/31407 -f 5508/6420/31408 5509/6421/31409 5524/6418/31410 -f 5524/6418/31411 5523/6419/31412 5508/6420/31413 -f 5526/6422/31414 5513/6423/31415 5519/6416/31416 -f 5519/6416/31417 5527/6415/31418 5526/6422/31419 -f 5519/6416/31420 5513/6423/31421 5525/6424/31422 -f 5525/6424/31423 5523/6419/31424 5519/6416/31425 -f 5508/6420/31426 5520/6406/31427 5521/6405/31428 -f 5521/6405/31429 5509/6421/31430 5508/6420/31431 -f 5511/6425/31432 5522/6408/31433 5520/6406/31434 -f 5520/6406/31435 5508/6420/31436 5511/6425/31437 -f 5523/6419/31438 5524/6418/31439 5518/6417/31440 -f 5518/6417/31441 5519/6416/31442 5523/6419/31443 -f 5508/6420/31444 5523/6419/31445 5525/6424/31446 -f 5525/6424/31447 5511/6425/31448 5508/6420/31449 -f 5527/6415/31450 5528/6414/31451 5516/6413/31452 -f 5516/6413/31453 5515/6412/31454 5527/6415/31455 -f 5512/6426/31456 5526/6422/31457 5527/6415/31458 -f 5527/6415/31459 5515/6412/31460 5512/6426/31461 -f 5529/6411/31462 5530/6427/31463 5512/6426/31464 -f 5512/6426/31465 5515/6412/31466 5529/6411/31467 -f 5529/6411/31468 5531/6410/31469 5517/6428/31470 -f 5517/6428/31471 5599/6429/31472 5529/6411/31473 -f 5542/6430/31474 5532/6431/31475 5510/6409/31476 -f 5510/6409/31477 5522/6408/31478 5542/6430/31479 -f 5543/6432/31480 5534/6433/31481 5532/6431/31482 -f 5532/6431/31483 5542/6430/31484 5543/6432/31485 -f 5544/6436/31486 5535/6437/31487 5533/6434/31488 -f 5533/6434/31489 5545/6435/31490 5544/6436/31491 -f 5547/6440/31492 5546/6441/31493 5538/6438/31494 -f 5538/6438/31495 5539/6439/31496 5547/6440/31497 -f 5526/6422/31498 5512/6426/31499 5538/6438/31500 -f 5538/6438/31501 5546/6441/31502 5526/6422/31503 -f 5530/6427/31504 5529/6411/31505 5599/6429/31506 -f 5599/6429/31507 5606/6442/31508 5530/6427/31509 -f 5606/6442/31510 5607/6444/31511 5548/6443/31512 -f 5548/6443/31513 5530/6427/31514 5606/6442/31515 -f 5533/6434/31516 5511/6425/31517 5525/6424/31518 -f 5525/6424/31519 5545/6435/31520 5533/6434/31521 -f 5533/6434/31522 5542/6430/31523 5522/6408/31524 -f 5522/6408/31525 5511/6425/31526 5533/6434/31527 -f 5535/6437/31528 5543/6432/31529 5542/6430/31530 -f 5542/6430/31531 5533/6434/31532 5535/6437/31533 -f 5536/6446/31534 5544/6436/31535 5545/6435/31536 -f 5545/6435/31537 5537/6445/31538 5536/6446/31539 -f 5545/6435/31540 5525/6424/31541 5513/6423/31542 -f 5513/6423/31543 5537/6445/31544 5545/6435/31545 -f 5546/6441/31546 5547/6440/31547 5536/6446/31548 -f 5536/6446/31549 5537/6445/31550 5546/6441/31551 -f 5513/6423/31552 5526/6422/31553 5546/6441/31554 -f 5546/6441/31555 5537/6445/31556 5513/6423/31557 -f 5530/6427/31558 5548/6443/31559 5538/6438/31560 -f 5538/6438/31561 5512/6426/31562 5530/6427/31563 -f 5548/6443/31564 5549/6447/31565 5539/6439/31566 -f 5539/6439/31567 5538/6438/31568 5548/6443/31569 -f 5607/6444/31570 5612/6448/31571 5549/6447/31572 -f 5549/6447/31573 5548/6443/31574 5607/6444/31575 -f 5565/6453/31576 5566/6473/31577 5551/6449/31578 -f 5551/6449/31579 5552/6450/31580 5565/6453/31581 -f 5567/6475/31582 5565/6453/31583 5552/6450/31584 -f 5552/6450/31585 5555/6474/31586 5567/6475/31587 -f 5560/6457/31588 5574/6458/31589 5576/6455/31590 -f 5576/6455/31591 5561/6456/31592 5560/6457/31593 -f 5564/6461/31594 5572/6462/31595 5573/6459/31596 -f 5573/6459/31597 5563/6460/31598 5564/6461/31599 -f 5553/6465/31600 5568/6466/31601 5569/6463/31602 -f 5569/6463/31603 5554/6464/31604 5553/6465/31605 -f 5571/6468/31606 5572/6462/31607 5564/6461/31608 -f 5564/6461/31609 5558/6467/31610 5571/6468/31611 -f 5564/6461/31612 5568/6466/31613 5570/6469/31614 -f 5570/6469/31615 5558/6467/31616 5564/6461/31617 -f 5553/6465/31618 5554/6464/31619 5566/6452/31620 -f 5566/6452/31621 5565/6451/31622 5553/6465/31623 -f 5556/6470/31624 5553/6465/31625 5565/6451/31626 -f 5565/6451/31627 5567/6454/31628 5556/6470/31629 -f 5568/6466/31630 5564/6461/31631 5563/6460/31632 -f 5563/6460/31633 5569/6463/31634 5568/6466/31635 -f 5553/6465/31636 5556/6470/31637 5570/6469/31638 -f 5570/6469/31639 5568/6466/31640 5553/6465/31641 -f 5572/6462/31642 5560/6457/31643 5561/6456/31644 -f 5561/6456/31645 5573/6459/31646 5572/6462/31647 -f 5557/6471/31648 5560/6457/31649 5572/6462/31650 -f 5572/6462/31651 5571/6468/31652 5557/6471/31653 -f 5574/6458/31654 5560/6457/31655 5557/6471/31656 -f 5557/6471/31657 5575/6472/31658 5574/6458/31659 -f 5574/6480/31660 5559/6481/31661 5562/6477/31662 -f 5562/6477/31663 5576/6478/31664 5574/6480/31665 -f 5587/6486/31666 5567/6475/31667 5555/6474/31668 -f 5555/6474/31669 5577/6485/31670 5587/6486/31671 -f 5588/6489/31672 5587/6486/31673 5577/6485/31674 -f 5577/6485/31675 5579/6487/31676 5588/6489/31677 -f 5589/6493/31678 5590/6494/31679 5578/6490/31680 -f 5578/6490/31681 5580/6492/31682 5589/6493/31683 -f 5592/6497/31684 5584/6498/31685 5583/6495/31686 -f 5583/6495/31687 5591/6496/31688 5592/6497/31689 -f 5571/6468/31690 5591/6484/31691 5583/6483/31692 -f 5583/6483/31693 5557/6471/31694 5571/6468/31695 -f 5575/6499/31696 5585/6500/31697 5559/6481/31698 -f 5559/6481/31699 5574/6480/31700 5575/6499/31701 -f 5585/6500/31702 5575/6499/31703 5593/6502/31704 -f 5593/6502/31705 5586/6506/31706 5585/6500/31707 -f 5578/6479/31708 5590/6482/31709 5570/6469/31710 -f 5570/6469/31711 5556/6470/31712 5578/6479/31713 -f 5578/6479/31714 5556/6470/31715 5567/6454/31716 -f 5567/6454/31717 5587/6476/31718 5578/6479/31719 -f 5580/6492/31720 5578/6490/31721 5587/6531/31722 -f 5587/6531/31723 5588/6532/31724 5580/6492/31725 -f 5581/6503/31726 5582/6504/31727 5590/6494/31728 -f 5590/6494/31729 5589/6493/31730 5581/6503/31731 -f 5590/6482/31732 5582/6491/31733 5558/6467/31734 -f 5558/6467/31735 5570/6469/31736 5590/6482/31737 -f 5591/6496/31738 5582/6504/31739 5581/6503/31740 -f 5581/6503/31741 5592/6497/31742 5591/6496/31743 -f 5558/6467/31744 5582/6491/31745 5591/6484/31746 -f 5591/6484/31747 5571/6468/31748 5558/6467/31749 -f 5575/6472/31750 5557/6471/31751 5583/6483/31752 -f 5583/6483/31753 5593/6488/31754 5575/6472/31755 -f 5593/6501/31756 5583/6495/31757 5584/6498/31758 -f 5584/6498/31759 5594/6505/31760 5593/6501/31761 -f 5586/6506/31762 5593/6502/31763 5594/6507/31764 -f 5594/6507/31765 5595/6508/31766 5586/6506/31767 -s 2 -f 5506/6539/31768 5597/6510/31769 5552/6450/31770 -f 5552/6450/31771 5551/6449/31772 5506/6539/31773 -f 5551/6533/31774 5596/6404/31775 5506/6509/31776 -f 5597/6510/31777 5598/6511/31778 5555/6474/31779 -f 5555/6474/31780 5552/6450/31781 5597/6510/31782 -s 4 -f 5531/6410/31783 5516/6413/31784 5561/6512/31785 -f 5561/6512/31786 5576/6536/31787 5531/6410/31788 -f 5528/6414/31789 5518/6417/31790 5563/6513/31791 -f 5563/6513/31792 5573/6514/31793 5528/6414/31794 -f 5524/6418/31795 5509/6421/31796 5554/6515/31797 -f 5554/6515/31798 5569/6516/31799 5524/6418/31800 -f 5509/6421/31801 5521/6405/31802 5566/6534/31803 -f 5566/6534/31804 5554/6515/31805 5509/6421/31806 -f 5518/6417/31807 5524/6418/31808 5569/6516/31809 -f 5569/6516/31810 5563/6513/31811 5518/6417/31812 -f 5516/6413/31813 5528/6414/31814 5573/6514/31815 -f 5573/6514/31816 5561/6512/31817 5516/6413/31818 -f 5576/6536/31819 5562/6535/31820 5517/6428/31821 -f 5517/6428/31822 5531/6410/31823 5576/6536/31824 -s 1 -f 5514/6518/31825 5600/6540/31826 5562/6477/31827 -f 5562/6477/31828 5559/6481/31829 5514/6518/31830 -s 2 -f 5598/6511/31831 5601/6519/31832 5577/6485/31833 -f 5577/6485/31834 5555/6474/31835 5598/6511/31836 -f 5601/6519/31837 5602/6541/31838 5579/6487/31839 -f 5579/6487/31840 5577/6485/31841 5601/6519/31842 -s 1 -f 5602/6520/31843 5608/6521/31844 5588/6532/31845 -f 5588/6532/31846 5579/6537/31847 5602/6520/31848 -f 5603/6522/31849 5609/6523/31850 5589/6493/31851 -f 5589/6493/31852 5580/6492/31853 5603/6522/31854 -f 5610/6524/31855 5605/6525/31856 5584/6498/31857 -f 5584/6498/31858 5592/6497/31859 5610/6524/31860 -f 5540/6526/31861 5514/6518/31862 5559/6481/31863 -f 5559/6481/31864 5585/6500/31865 5540/6526/31866 -f 5541/6527/31867 5540/6526/31868 5585/6500/31869 -f 5585/6500/31870 5586/6506/31871 5541/6527/31872 -f 5608/6521/31873 5603/6522/31874 5580/6492/31875 -f 5580/6492/31876 5588/6532/31877 5608/6521/31878 -f 5609/6523/31879 5604/6528/31880 5581/6503/31881 -f 5581/6503/31882 5589/6493/31883 5609/6523/31884 -f 5604/6528/31885 5610/6524/31886 5592/6497/31887 -f 5592/6497/31888 5581/6503/31889 5604/6528/31890 -f 5605/6525/31891 5611/6529/31892 5594/6505/31893 -f 5594/6505/31894 5584/6498/31895 5605/6525/31896 -f 5611/6529/31897 5550/6542/31898 5595/6538/31899 -f 5595/6538/31900 5594/6505/31901 5611/6529/31902 -f 5550/6530/31903 5541/6527/31904 5586/6506/31905 -f 5586/6506/31906 5595/6508/31907 5550/6530/31908 -s 2 -f 5507/6407/31909 5597/6510/31910 5506/6539/31911 -f 5506/6539/31912 5596/6404/31913 5507/6407/31914 -f 5510/6409/31915 5598/6511/31916 5597/6510/31917 -f 5597/6510/31918 5507/6407/31919 5510/6409/31920 -s 1 -f 5517/6428/31921 5600/6540/31922 5514/6518/31923 -f 5514/6518/31924 5599/6429/31925 5517/6428/31926 -s 2 -f 5532/6431/31927 5601/6519/31928 5598/6511/31929 -f 5598/6511/31930 5510/6409/31931 5532/6431/31932 -s 1 -f 5543/6432/31933 5608/6521/31934 5602/6520/31935 -f 5602/6520/31936 5534/6433/31937 5543/6432/31938 -s 2 -f 5534/6433/31939 5602/6541/31940 5601/6519/31941 -f 5601/6519/31942 5532/6431/31943 5534/6433/31944 -s 1 -f 5544/6436/31945 5609/6523/31946 5603/6522/31947 -f 5603/6522/31948 5535/6437/31949 5544/6436/31950 -f 5539/6439/31951 5605/6525/31952 5610/6524/31953 -f 5610/6524/31954 5547/6440/31955 5539/6439/31956 -f 5599/6429/31957 5514/6518/31958 5540/6526/31959 -f 5540/6526/31960 5606/6442/31961 5599/6429/31962 -f 5606/6442/31963 5540/6526/31964 5541/6527/31965 -f 5541/6527/31966 5607/6444/31967 5606/6442/31968 -f 5535/6437/31969 5603/6522/31970 5608/6521/31971 -f 5608/6521/31972 5543/6432/31973 5535/6437/31974 -f 5536/6446/31975 5604/6528/31976 5609/6523/31977 -f 5609/6523/31978 5544/6436/31979 5536/6446/31980 -f 5547/6440/31981 5610/6524/31982 5604/6528/31983 -f 5604/6528/31984 5536/6446/31985 5547/6440/31986 -f 5549/6447/31987 5611/6529/31988 5605/6525/31989 -f 5605/6525/31990 5539/6439/31991 5549/6447/31992 -f 5607/6444/31993 5541/6527/31994 5550/6530/31995 -f 5550/6530/31996 5612/6448/31997 5607/6444/31998 -f 5612/6448/31999 5550/6542/32000 5611/6529/32001 -f 5611/6529/32002 5549/6447/32003 5612/6448/32004 -f 5562/6535/32005 5600/6517/32006 5517/6428/32007 -s 4 -f 5566/6534/32008 5521/6405/32009 5596/6404/32010 -f 5596/6404/32011 5551/6533/32012 5566/6534/32013 -# 10671 faces - diff --git a/examples/shaders/postprocessing/dwarf_diffuse.png b/examples/shaders/postprocessing/dwarf_diffuse.png deleted file mode 100644 index 15dee61..0000000 Binary files a/examples/shaders/postprocessing/dwarf_diffuse.png and /dev/null differ diff --git a/examples/shaders/postprocessing/glsl330/bloom.fs b/examples/shaders/postprocessing/glsl330/bloom.fs index 333d5b0..549cde8 100644 --- a/examples/shaders/postprocessing/glsl330/bloom.fs +++ b/examples/shaders/postprocessing/glsl330/bloom.fs @@ -15,7 +15,7 @@ out vec4 finalColor; const vec2 size = vec2(800, 450); // render size const float samples = 5.0; // pixels per axis; higher = bigger glow, worse performance -const float quality = 2.5; // lower = smaller glow, better quality +const float quality = 2.5; // lower = smaller glow, better quality void main() { diff --git a/examples/shaders/postprocessing/glsl330/dream_vision.fs b/examples/shaders/postprocessing/glsl330/dream_vision.fs index 0311586..31d3fd2 100644 --- a/examples/shaders/postprocessing/glsl330/dream_vision.fs +++ b/examples/shaders/postprocessing/glsl330/dream_vision.fs @@ -31,4 +31,4 @@ void main() color = color/9.5; fragColor = color; -} \ No newline at end of file +} \ No newline at end of file diff --git a/examples/shaders/postprocessing/glsl330/sobel.fs b/examples/shaders/postprocessing/glsl330/sobel.fs index a1430cd..cb335c0 100644 --- a/examples/shaders/postprocessing/glsl330/sobel.fs +++ b/examples/shaders/postprocessing/glsl330/sobel.fs @@ -16,26 +16,26 @@ uniform vec2 resolution = vec2(800, 450); void main() { - float x = 1.0/resolution.x; - float y = 1.0/resolution.y; + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; - vec4 horizEdge = vec4(0.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 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; - vec4 vertEdge = vec4(0.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; + 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; - vec3 edge = sqrt((horizEdge.rgb*horizEdge.rgb) + (vertEdge.rgb*vertEdge.rgb)); - - finalColor = vec4(edge, texture2D(texture0, fragTexCoord).a); + vec3 edge = sqrt((horizEdge.rgb*horizEdge.rgb) + (vertEdge.rgb*vertEdge.rgb)); + + finalColor = vec4(edge, texture(texture0, fragTexCoord).a); } \ No newline at end of file diff --git a/examples/shaders/postprocessing/main.go b/examples/shaders/postprocessing/main.go index e1ce2ad..6377e36 100644 --- a/examples/shaders/postprocessing/main.go +++ b/examples/shaders/postprocessing/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const MaxPostproShaders = 12 @@ -40,53 +40,51 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.SetConfigFlags(raylib.FlagMsaa4xHint | raylib.FlagVsyncHint) // Enable Multi Sampling Anti Aliasing 4x (if available) + rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing shader") + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing shader") - camera := raylib.Camera{} - camera.Position = raylib.NewVector3(3.0, 3.0, 3.0) - camera.Target = raylib.NewVector3(0.0, 1.5, 0.0) - camera.Up = raylib.NewVector3(0.0, 1.0, 0.0) + camera := rl.Camera{} + camera.Position = rl.NewVector3(2.0, 3.0, 2.0) + camera.Target = rl.NewVector3(0.0, 1.0, 0.0) + camera.Up = rl.NewVector3(0.0, 1.0, 0.0) camera.Fovy = 45.0 - dwarf := raylib.LoadModel("dwarf.obj") // Load OBJ model - texture := raylib.LoadTexture("dwarf_diffuse.png") // Load model texture - dwarf.Material.Maps[raylib.MapDiffuse].Texture = texture // Set dwarf model diffuse texture + obj := rl.LoadModel("church.obj") // Load OBJ model + texture := rl.LoadTexture("church_diffuse.png") // Load model texture + rl.SetMaterialTexture(obj.Materials, rl.MapDiffuse, texture) // Set obj model diffuse texture - position := raylib.NewVector3(0.0, 0.0, 0.0) // Set model position + position := rl.NewVector3(0.0, 0.0, 0.0) // Set model position // Load all postpro shaders // NOTE 1: All postpro shader use the base vertex shader (DEFAULT_VERTEX_SHADER) - shaders := make([]raylib.Shader, MaxPostproShaders) - shaders[FxGrayscale] = raylib.LoadShader("", "glsl330/grayscale.fs") - shaders[FxPosterization] = raylib.LoadShader("", "glsl330/posterization.fs") - shaders[FxDreamVision] = raylib.LoadShader("", "glsl330/dream_vision.fs") - shaders[FxPixelizer] = raylib.LoadShader("", "glsl330/pixelizer.fs") - shaders[FxCrossHatching] = raylib.LoadShader("", "glsl330/cross_hatching.fs") - shaders[FxCrossStitching] = raylib.LoadShader("", "glsl330/cross_stitching.fs") - shaders[FxPredatorView] = raylib.LoadShader("", "glsl330/predator.fs") - shaders[FxScanlines] = raylib.LoadShader("", "glsl330/scanlines.fs") - shaders[FxFisheye] = raylib.LoadShader("", "glsl330/fisheye.fs") - shaders[FxSobel] = raylib.LoadShader("", "glsl330/sobel.fs") - shaders[FxBlur] = raylib.LoadShader("", "glsl330/blur.fs") - shaders[FxBloom] = raylib.LoadShader("", "glsl330/bloom.fs") + shaders := make([]rl.Shader, MaxPostproShaders) + shaders[FxGrayscale] = rl.LoadShader("", "glsl330/grayscale.fs") + shaders[FxPosterization] = rl.LoadShader("", "glsl330/posterization.fs") + shaders[FxDreamVision] = rl.LoadShader("", "glsl330/dream_vision.fs") + shaders[FxPixelizer] = rl.LoadShader("", "glsl330/pixelizer.fs") + shaders[FxCrossHatching] = rl.LoadShader("", "glsl330/cross_hatching.fs") + shaders[FxCrossStitching] = rl.LoadShader("", "glsl330/cross_stitching.fs") + shaders[FxPredatorView] = rl.LoadShader("", "glsl330/predator.fs") + shaders[FxScanlines] = rl.LoadShader("", "glsl330/scanlines.fs") + shaders[FxFisheye] = rl.LoadShader("", "glsl330/fisheye.fs") + shaders[FxSobel] = rl.LoadShader("", "glsl330/sobel.fs") + shaders[FxBlur] = rl.LoadShader("", "glsl330/blur.fs") + shaders[FxBloom] = rl.LoadShader("", "glsl330/bloom.fs") currentShader := FxGrayscale // Create a RenderTexture2D to be used for render to texture - target := raylib.LoadRenderTexture(screenWidth, screenHeight) + target := rl.LoadRenderTexture(screenWidth, screenHeight) - raylib.SetCameraMode(camera, raylib.CameraOrbital) // Set free camera mode + rl.SetTargetFPS(60) - raylib.SetTargetFPS(60) + for !rl.WindowShouldClose() { + rl.UpdateCamera(&camera, rl.CameraOrbital) // Update camera with orbital camera mode - for !raylib.WindowShouldClose() { - raylib.UpdateCamera(&camera) // Update camera - - if raylib.IsKeyPressed(raylib.KeyRight) { + if rl.IsKeyPressed(rl.KeyRight) { currentShader++ - } else if raylib.IsKeyPressed(raylib.KeyLeft) { + } else if rl.IsKeyPressed(rl.KeyLeft) { currentShader-- } @@ -96,51 +94,53 @@ func main() { currentShader = MaxPostproShaders - 1 } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.BeginTextureMode(target) // Enable drawing to texture + rl.BeginTextureMode(target) // Enable drawing to texture - raylib.BeginMode3D(camera) + rl.ClearBackground(rl.RayWhite) - raylib.DrawModel(dwarf, position, 2.0, raylib.White) // Draw 3d model with texture + rl.BeginMode3D(camera) - raylib.DrawGrid(10, 1.0) // Draw a grid + rl.DrawModel(obj, position, 0.1, rl.White) // Draw 3d model with texture - raylib.EndMode3D() + rl.DrawGrid(10, 1.0) // Draw a grid - raylib.EndTextureMode() // End drawing to texture (now we have a texture available for next passes) + rl.EndMode3D() + + rl.EndTextureMode() // End drawing to texture (now we have a texture available for next passes) // Render previously generated texture using selected postpro shader - raylib.BeginShaderMode(shaders[currentShader]) + rl.BeginShaderMode(shaders[currentShader]) // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) - raylib.DrawTextureRec(target.Texture, raylib.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), raylib.NewVector2(0, 0), raylib.White) + rl.DrawTextureRec(target.Texture, rl.NewRectangle(0, 0, float32(target.Texture.Width), float32(-target.Texture.Height)), rl.NewVector2(0, 0), rl.White) - raylib.EndShaderMode() + rl.EndShaderMode() - raylib.DrawRectangle(0, 9, 580, 30, raylib.Fade(raylib.LightGray, 0.7)) + rl.DrawRectangle(0, 9, 580, 30, rl.Fade(rl.LightGray, 0.7)) - raylib.DrawText("(c) Dwarf 3D model by David Moreno", screenWidth-200, screenHeight-20, 10, raylib.DarkGray) + rl.DrawText("(c) Church 3D model by Alberto Cano", screenWidth-200, screenHeight-20, 10, rl.DarkGray) - raylib.DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, raylib.Black) - raylib.DrawText(postproShaderText[currentShader], 330, 15, 20, raylib.Red) - raylib.DrawText("< >", 540, 10, 30, raylib.DarkBlue) + rl.DrawText("CURRENT POSTPRO SHADER:", 10, 15, 20, rl.Black) + rl.DrawText(postproShaderText[currentShader], 330, 15, 20, rl.Red) + rl.DrawText("< >", 540, 10, 30, rl.DarkBlue) - raylib.DrawFPS(700, 15) + rl.DrawFPS(700, 15) - raylib.EndDrawing() + rl.EndDrawing() } // Unload all postpro shaders for i := 0; i < MaxPostproShaders; i++ { - raylib.UnloadShader(shaders[i]) + rl.UnloadShader(shaders[i]) } - raylib.UnloadTexture(texture) // Unload texture - raylib.UnloadModel(dwarf) // Unload model - raylib.UnloadRenderTexture(target) // Unload render texture + rl.UnloadTexture(texture) // Unload texture + rl.UnloadModel(obj) // Unload model + rl.UnloadRenderTexture(target) // Unload render texture - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shaders/raymarching/main.go b/examples/shaders/raymarching/main.go new file mode 100644 index 0000000..23684f0 --- /dev/null +++ b/examples/shaders/raymarching/main.go @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..6a9eb45 --- /dev/null +++ b/examples/shaders/raymarching/raymarching.fs @@ -0,0 +1,430 @@ +#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 7cc319f..e374af2 100644 --- a/examples/shaders/shapes_textures/main.go +++ b/examples/shaders/shapes_textures/main.go @@ -1,74 +1,70 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes and texture shaders") + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shapes and texture shaders") - fudesumi := raylib.LoadTexture("fudesumi.png") + fudesumi := rl.LoadTexture("fudesumi.png") // NOTE: Using GLSL 330 shader version, on OpenGL ES 2.0 use GLSL 100 shader version - shader := raylib.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs") + shader := rl.LoadShader("glsl330/base.vs", "glsl330/grayscale.fs") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) // Start drawing with default shader - raylib.DrawText("USING DEFAULT SHADER", 20, 40, 10, raylib.Red) + rl.DrawText("USING DEFAULT SHADER", 20, 40, 10, rl.Red) - raylib.DrawCircle(80, 120, 35, raylib.DarkBlue) - raylib.DrawCircleGradient(80, 220, 60, raylib.Green, raylib.SkyBlue) - raylib.DrawCircleLines(80, 340, 80, raylib.DarkBlue) + rl.DrawCircle(80, 120, 35, rl.DarkBlue) + rl.DrawCircleGradient(80, 220, 60, rl.Green, rl.SkyBlue) + rl.DrawCircleLines(80, 340, 80, rl.DarkBlue) // Activate our custom shader to be applied on next shapes/textures drawings - raylib.BeginShaderMode(shader) + rl.BeginShaderMode(shader) - raylib.DrawText("USING CUSTOM SHADER", 190, 40, 10, raylib.Red) + rl.DrawText("USING CUSTOM SHADER", 190, 40, 10, rl.Red) - raylib.DrawRectangle(250-60, 90, 120, 60, raylib.Red) - raylib.DrawRectangleGradientH(250-90, 170, 180, 130, raylib.Maroon, raylib.Gold) - raylib.DrawRectangleLines(250-40, 320, 80, 60, raylib.Orange) + rl.DrawRectangle(250-60, 90, 120, 60, rl.Red) + rl.DrawRectangleGradientH(250-90, 170, 180, 130, rl.Maroon, rl.Gold) + rl.DrawRectangleLines(250-40, 320, 80, 60, rl.Orange) // Activate our default shader for next drawings - raylib.EndShaderMode() + rl.EndShaderMode() - raylib.DrawText("USING DEFAULT SHADER", 370, 40, 10, raylib.Red) + rl.DrawText("USING DEFAULT SHADER", 370, 40, 10, rl.Red) - raylib.DrawTriangle(raylib.NewVector2(430, 80), - raylib.NewVector2(430-60, 150), - raylib.NewVector2(430+60, 150), raylib.Violet) + rl.DrawTriangle(rl.NewVector2(430, 80), + rl.NewVector2(430-60, 150), + rl.NewVector2(430+60, 150), rl.Violet) - raylib.DrawTriangleLines(raylib.NewVector2(430, 160), - raylib.NewVector2(430-20, 230), - raylib.NewVector2(430+20, 230), raylib.DarkBlue) + rl.DrawTriangleLines(rl.NewVector2(430, 160), + rl.NewVector2(430-20, 230), + rl.NewVector2(430+20, 230), rl.DarkBlue) - raylib.DrawPoly(raylib.NewVector2(430, 320), 6, 80, 0, raylib.Brown) + rl.DrawPoly(rl.NewVector2(430, 320), 6, 80, 0, rl.Brown) // Activate our custom shader to be applied on next shapes/textures drawings - raylib.BeginShaderMode(shader) + rl.BeginShaderMode(shader) - raylib.DrawTexture(fudesumi, 500, -30, raylib.White) // Using custom shader + rl.DrawTexture(fudesumi, 500, -30, rl.White) // Using custom shader // Activate our default shader for next drawings - raylib.EndShaderMode() + rl.EndShaderMode() - raylib.DrawText("(c) Fudesumi sprite by Eiden Marsal", 380, screenHeight-20, 10, raylib.Gray) + rl.DrawText("(c) Fudesumi sprite by Eiden Marsal", 380, screenHeight-20, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadShader(shader) // Unload shader - raylib.UnloadTexture(fudesumi) // Unload texture + rl.UnloadShader(shader) // Unload shader + rl.UnloadTexture(fudesumi) // Unload texture - raylib.CloseWindow() // Close window and OpenGL context + rl.CloseWindow() // Close window and OpenGL context } diff --git a/examples/shaders/texture_drawing/cubes_panning.fs b/examples/shaders/texture_drawing/cubes_panning.fs new file mode 100644 index 0000000..1d75e4e --- /dev/null +++ b/examples/shaders/texture_drawing/cubes_panning.fs @@ -0,0 +1,61 @@ +#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 new file mode 100644 index 0000000..3f7136b --- /dev/null +++ b/examples/shaders/texture_drawing/main.go @@ -0,0 +1,49 @@ +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 new file mode 100644 index 0000000..8347cee Binary files /dev/null and b/examples/shaders/texture_outline/gopher.png differ diff --git a/examples/shaders/texture_outline/main.go b/examples/shaders/texture_outline/main.go new file mode 100644 index 0000000..50b2257 --- /dev/null +++ b/examples/shaders/texture_outline/main.go @@ -0,0 +1,65 @@ +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 new file mode 100644 index 0000000..2584a21 --- /dev/null +++ b/examples/shaders/texture_outline/outline.fs @@ -0,0 +1,35 @@ +#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 new file mode 100644 index 0000000..9fc404a Binary files /dev/null and b/examples/shaders/texture_tiling/cubicmap_atlas.png differ diff --git a/examples/shaders/texture_tiling/main.go b/examples/shaders/texture_tiling/main.go new file mode 100644 index 0000000..2af0f8a --- /dev/null +++ b/examples/shaders/texture_tiling/main.go @@ -0,0 +1,65 @@ +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 new file mode 100644 index 0000000..6e7f524 --- /dev/null +++ b/examples/shaders/texture_tiling/tiling.fs @@ -0,0 +1,14 @@ +#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 new file mode 100644 index 0000000..ce32710 --- /dev/null +++ b/examples/shaders/texture_waves/main.go @@ -0,0 +1,67 @@ +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 new file mode 100644 index 0000000..5d016e4 Binary files /dev/null and b/examples/shaders/texture_waves/space.png differ diff --git a/examples/shaders/texture_waves/wave.fs b/examples/shaders/texture_waves/wave.fs new file mode 100644 index 0000000..1f22bee --- /dev/null +++ b/examples/shaders/texture_waves/wave.fs @@ -0,0 +1,37 @@ +#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 new file mode 100644 index 0000000..0a99e18 --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs @@ -0,0 +1,18 @@ +#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 new file mode 100644 index 0000000..ef79097 --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs @@ -0,0 +1,48 @@ +#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 new file mode 100644 index 0000000..b80b76e --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs @@ -0,0 +1,16 @@ +#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 new file mode 100644 index 0000000..c6526db --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs @@ -0,0 +1,46 @@ +#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 new file mode 100644 index 0000000..d7c0677 --- /dev/null +++ b/examples/shaders/vertex_displacement/main.go @@ -0,0 +1,143 @@ +/******************************************************************************************* +* +* 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 18517a4..560ce56 100644 --- a/examples/shapes/basic_shapes/main.go +++ b/examples/shapes/basic_shapes/main.go @@ -1,45 +1,45 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - basic shapes drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - basic shapes drawing") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + for !rl.WindowShouldClose() { + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("some basic shapes available on raylib", 20, 20, 20, raylib.DarkGray) + rl.DrawText("some basic shapes available on raylib", 20, 20, 20, rl.DarkGray) - raylib.DrawLine(18, 42, screenWidth-18, 42, raylib.Black) + rl.DrawLine(18, 42, screenWidth-18, 42, rl.Black) - raylib.DrawCircle(screenWidth/4, 120, 35, raylib.DarkBlue) - raylib.DrawCircleGradient(screenWidth/4, 220, 60, raylib.Green, raylib.SkyBlue) - raylib.DrawCircleLines(screenWidth/4, 340, 80, raylib.DarkBlue) + rl.DrawCircle(screenWidth/4, 120, 35, rl.DarkBlue) + rl.DrawCircleGradient(screenWidth/4, 220, 60, rl.Green, rl.SkyBlue) + rl.DrawCircleLines(screenWidth/4, 340, 80, rl.DarkBlue) - raylib.DrawRectangle(screenWidth/4*2-60, 100, 120, 60, raylib.Red) - raylib.DrawRectangleGradientH(screenWidth/4*2-90, 170, 180, 130, raylib.Maroon, raylib.Gold) - raylib.DrawRectangleLines(screenWidth/4*2-40, 320, 80, 60, raylib.Orange) + rl.DrawRectangle(screenWidth/4*2-60, 100, 120, 60, rl.Red) + rl.DrawRectangleGradientH(screenWidth/4*2-90, 170, 180, 130, rl.Maroon, rl.Gold) + rl.DrawRectangleLines(screenWidth/4*2-40, 320, 80, 60, rl.Orange) - raylib.DrawTriangle(raylib.NewVector2(float32(screenWidth)/4*3, 80), - raylib.NewVector2(float32(screenWidth)/4*3-60, 150), - raylib.NewVector2(float32(screenWidth)/4*3+60, 150), raylib.Violet) + rl.DrawTriangle(rl.NewVector2(float32(screenWidth)/4*3, 80), + rl.NewVector2(float32(screenWidth)/4*3-60, 150), + rl.NewVector2(float32(screenWidth)/4*3+60, 150), rl.Violet) - raylib.DrawTriangleLines(raylib.NewVector2(float32(screenWidth)/4*3, 160), - raylib.NewVector2(float32(screenWidth)/4*3-20, 230), - raylib.NewVector2(float32(screenWidth)/4*3+20, 230), raylib.DarkBlue) + rl.DrawTriangleLines(rl.NewVector2(float32(screenWidth)/4*3, 160), + rl.NewVector2(float32(screenWidth)/4*3-20, 230), + rl.NewVector2(float32(screenWidth)/4*3+20, 230), rl.DarkBlue) - raylib.DrawPoly(raylib.NewVector2(float32(screenWidth)/4*3, 320), 6, 80, 0, raylib.Brown) + rl.DrawPoly(rl.NewVector2(float32(screenWidth)/4*3, 320), 6, 80, 0, rl.Brown) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shapes/bouncing_ball/main.go b/examples/shapes/bouncing_ball/main.go new file mode 100644 index 0000000..f5a47d3 --- /dev/null +++ b/examples/shapes/bouncing_ball/main.go @@ -0,0 +1,63 @@ +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 new file mode 100644 index 0000000..225ec09 --- /dev/null +++ b/examples/shapes/collision_area/main.go @@ -0,0 +1,88 @@ +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 ccba781..f4189ae 100644 --- a/examples/shapes/colors_pallete/main.go +++ b/examples/shapes/colors_pallete/main.go @@ -1,66 +1,66 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { - raylib.InitWindow(800, 450, "raylib [shapes] example - raylib color palette") - raylib.SetTargetFPS(60) + rl.InitWindow(800, 450, "raylib [shapes] example - raylib color palette") + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("raylib color palette", 28, 42, 20, raylib.Black) + rl.DrawText("raylib color palette", 28, 42, 20, rl.Black) - raylib.DrawRectangle(26, 80, 100, 100, raylib.DarkGray) - raylib.DrawRectangle(26, 188, 100, 100, raylib.Gray) - raylib.DrawRectangle(26, 296, 100, 100, raylib.LightGray) - raylib.DrawRectangle(134, 80, 100, 100, raylib.Maroon) - raylib.DrawRectangle(134, 188, 100, 100, raylib.Red) - raylib.DrawRectangle(134, 296, 100, 100, raylib.Pink) - raylib.DrawRectangle(242, 80, 100, 100, raylib.Orange) - raylib.DrawRectangle(242, 188, 100, 100, raylib.Gold) - raylib.DrawRectangle(242, 296, 100, 100, raylib.Yellow) - raylib.DrawRectangle(350, 80, 100, 100, raylib.DarkGreen) - raylib.DrawRectangle(350, 188, 100, 100, raylib.Lime) - raylib.DrawRectangle(350, 296, 100, 100, raylib.Green) - raylib.DrawRectangle(458, 80, 100, 100, raylib.DarkBlue) - raylib.DrawRectangle(458, 188, 100, 100, raylib.Blue) - raylib.DrawRectangle(458, 296, 100, 100, raylib.SkyBlue) - raylib.DrawRectangle(566, 80, 100, 100, raylib.DarkPurple) - raylib.DrawRectangle(566, 188, 100, 100, raylib.Violet) - raylib.DrawRectangle(566, 296, 100, 100, raylib.Purple) - raylib.DrawRectangle(674, 80, 100, 100, raylib.DarkBrown) - raylib.DrawRectangle(674, 188, 100, 100, raylib.Brown) - raylib.DrawRectangle(674, 296, 100, 100, raylib.Beige) + rl.DrawRectangle(26, 80, 100, 100, rl.DarkGray) + rl.DrawRectangle(26, 188, 100, 100, rl.Gray) + rl.DrawRectangle(26, 296, 100, 100, rl.LightGray) + rl.DrawRectangle(134, 80, 100, 100, rl.Maroon) + rl.DrawRectangle(134, 188, 100, 100, rl.Red) + rl.DrawRectangle(134, 296, 100, 100, rl.Pink) + rl.DrawRectangle(242, 80, 100, 100, rl.Orange) + rl.DrawRectangle(242, 188, 100, 100, rl.Gold) + rl.DrawRectangle(242, 296, 100, 100, rl.Yellow) + rl.DrawRectangle(350, 80, 100, 100, rl.DarkGreen) + rl.DrawRectangle(350, 188, 100, 100, rl.Lime) + rl.DrawRectangle(350, 296, 100, 100, rl.Green) + rl.DrawRectangle(458, 80, 100, 100, rl.DarkBlue) + rl.DrawRectangle(458, 188, 100, 100, rl.Blue) + rl.DrawRectangle(458, 296, 100, 100, rl.SkyBlue) + rl.DrawRectangle(566, 80, 100, 100, rl.DarkPurple) + rl.DrawRectangle(566, 188, 100, 100, rl.Violet) + rl.DrawRectangle(566, 296, 100, 100, rl.Purple) + rl.DrawRectangle(674, 80, 100, 100, rl.DarkBrown) + rl.DrawRectangle(674, 188, 100, 100, rl.Brown) + rl.DrawRectangle(674, 296, 100, 100, rl.Beige) - raylib.DrawText("DARKGRAY", 65, 166, 10, raylib.Black) - raylib.DrawText("GRAY", 93, 274, 10, raylib.Black) - raylib.DrawText("LIGHTGRAY", 61, 382, 10, raylib.Black) - raylib.DrawText("MAROON", 186, 166, 10, raylib.Black) - raylib.DrawText("RED", 208, 274, 10, raylib.Black) - raylib.DrawText("PINK", 204, 382, 10, raylib.Black) - raylib.DrawText("ORANGE", 295, 166, 10, raylib.Black) - raylib.DrawText("GOLD", 310, 274, 10, raylib.Black) - raylib.DrawText("YELLOW", 300, 382, 10, raylib.Black) - raylib.DrawText("DARKGREEN", 382, 166, 10, raylib.Black) - raylib.DrawText("LIME", 420, 274, 10, raylib.Black) - raylib.DrawText("GREEN", 410, 382, 10, raylib.Black) - raylib.DrawText("DARKBLUE", 498, 166, 10, raylib.Black) - raylib.DrawText("BLUE", 526, 274, 10, raylib.Black) - raylib.DrawText("SKYBLUE", 505, 382, 10, raylib.Black) - raylib.DrawText("DARKPURPLE", 592, 166, 10, raylib.Black) - raylib.DrawText("VIOLET", 621, 274, 10, raylib.Black) - raylib.DrawText("PURPLE", 620, 382, 10, raylib.Black) - raylib.DrawText("DARKBROWN", 705, 166, 10, raylib.Black) - raylib.DrawText("BROWN", 733, 274, 10, raylib.Black) - raylib.DrawText("BEIGE", 737, 382, 10, raylib.Black) + rl.DrawText("DARKGRAY", 65, 166, 10, rl.Black) + rl.DrawText("GRAY", 93, 274, 10, rl.Black) + rl.DrawText("LIGHTGRAY", 61, 382, 10, rl.Black) + rl.DrawText("MAROON", 186, 166, 10, rl.Black) + rl.DrawText("RED", 208, 274, 10, rl.Black) + rl.DrawText("PINK", 204, 382, 10, rl.Black) + rl.DrawText("ORANGE", 295, 166, 10, rl.Black) + rl.DrawText("GOLD", 310, 274, 10, rl.Black) + rl.DrawText("YELLOW", 300, 382, 10, rl.Black) + rl.DrawText("DARKGREEN", 382, 166, 10, rl.Black) + rl.DrawText("LIME", 420, 274, 10, rl.Black) + rl.DrawText("GREEN", 410, 382, 10, rl.Black) + rl.DrawText("DARKBLUE", 498, 166, 10, rl.Black) + rl.DrawText("BLUE", 526, 274, 10, rl.Black) + rl.DrawText("SKYBLUE", 505, 382, 10, rl.Black) + rl.DrawText("DARKPURPLE", 592, 166, 10, rl.Black) + rl.DrawText("VIOLET", 621, 274, 10, rl.Black) + rl.DrawText("PURPLE", 620, 382, 10, rl.Black) + rl.DrawText("DARKBROWN", 705, 166, 10, rl.Black) + rl.DrawText("BROWN", 733, 274, 10, rl.Black) + rl.DrawText("BEIGE", 737, 382, 10, rl.Black) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shapes/draw_circle_sector/main.go b/examples/shapes/draw_circle_sector/main.go new file mode 100644 index 0000000..e754294 --- /dev/null +++ b/examples/shapes/draw_circle_sector/main.go @@ -0,0 +1,88 @@ +/******************************************************************************************* + * + * 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 new file mode 100644 index 0000000..ace9aee --- /dev/null +++ b/examples/shapes/draw_ring/main.go @@ -0,0 +1,121 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..7927b8e --- /dev/null +++ b/examples/shapes/easings_ball_anim/main.go @@ -0,0 +1,86 @@ +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 new file mode 100644 index 0000000..9a65db5 --- /dev/null +++ b/examples/shapes/easings_box_anim/main.go @@ -0,0 +1,99 @@ +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 new file mode 100644 index 0000000..287cf75 --- /dev/null +++ b/examples/shapes/easings_rectangle_array/main.go @@ -0,0 +1,92 @@ +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 new file mode 100644 index 0000000..a52a318 --- /dev/null +++ b/examples/shapes/following_eyes/main.go @@ -0,0 +1,84 @@ +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 7ca9377..f1eeb10 100644 --- a/examples/shapes/lines_bezier/main.go +++ b/examples/shapes/lines_bezier/main.go @@ -1,36 +1,32 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - cubic-bezier lines") + rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - cubic-bezier lines") - start := raylib.NewVector2(0, 0) - end := raylib.NewVector2(float32(screenWidth), float32(screenHeight)) + start := rl.NewVector2(0, 0) + end := rl.NewVector2(float32(screenWidth), float32(screenHeight)) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - start = raylib.GetMousePosition() - } else if raylib.IsMouseButtonDown(raylib.MouseRightButton) { - end = raylib.GetMousePosition() + for !rl.WindowShouldClose() { + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + start = rl.GetMousePosition() + } else if rl.IsMouseButtonDown(rl.MouseRightButton) { + end = rl.GetMousePosition() } - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("USE MOUSE LEFT-RIGHT CLICK to DEFINE LINE START and END POINTS", 15, 20, 20, raylib.Gray) + rl.DrawText("USE MOUSE LEFT-RIGHT CLICK to DEFINE LINE START and END POINTS", 15, 20, 20, rl.Gray) - raylib.DrawLineBezier(start, end, 2.0, raylib.Red) + rl.DrawLineBezier(start, end, 2.0, rl.Red) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shapes/logo_raylib/main.go b/examples/shapes/logo_raylib/main.go index cbe98f9..4e300ef 100644 --- a/examples/shapes/logo_raylib/main.go +++ b/examples/shapes/logo_raylib/main.go @@ -1,29 +1,29 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo using shapes") + rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo using shapes") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + for !rl.WindowShouldClose() { + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) - raylib.DrawRectangle(screenWidth/2-128, screenHeight/2-128, 256, 256, raylib.Black) - raylib.DrawRectangle(screenWidth/2-112, screenHeight/2-112, 224, 224, raylib.RayWhite) - raylib.DrawText("raylib", screenWidth/2-44, screenHeight/2+48, 50, raylib.Black) + rl.DrawRectangle(screenWidth/2-128, screenHeight/2-128, 256, 256, rl.Black) + rl.DrawRectangle(screenWidth/2-112, screenHeight/2-112, 224, 224, rl.RayWhite) + rl.DrawText("raylib", screenWidth/2-44, screenHeight/2+48, 50, rl.Black) - raylib.DrawText("this is NOT a texture!", 350, 370, 10, raylib.Gray) + rl.DrawText("this is NOT a texture!", 350, 370, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shapes/logo_raylib_anim/main.go b/examples/shapes/logo_raylib_anim/main.go index fbc2f4a..1e4e2c6 100644 --- a/examples/shapes/logo_raylib_anim/main.go +++ b/examples/shapes/logo_raylib_anim/main.go @@ -1,14 +1,14 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo animation") + rl.InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo animation") logoPositionX := screenWidth/2 - 128 logoPositionY := screenHeight/2 - 128 @@ -25,9 +25,9 @@ func main() { state := 0 // Tracking animation states (State Machine) alpha := float32(1.0) // Useful for fading - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { if state == 0 { // State 0: Small box blinking framesCounter++ @@ -66,7 +66,7 @@ func main() { } } } else if state == 4 { // State 4: Reset and Replay - if raylib.IsKeyPressed(raylib.KeyR) { + if rl.IsKeyPressed(rl.KeyR) { framesCounter = 0 lettersCount = 0 @@ -81,30 +81,30 @@ func main() { } } - raylib.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.BeginDrawing() + rl.ClearBackground(rl.RayWhite) if state == 0 { if (framesCounter/15)%2 == 0 { - raylib.DrawRectangle(logoPositionX, logoPositionY, 16, 16, raylib.Black) + rl.DrawRectangle(logoPositionX, logoPositionY, 16, 16, rl.Black) } } else if state == 1 { - raylib.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, raylib.Black) - raylib.DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, raylib.Black) + rl.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, rl.Black) + rl.DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, rl.Black) } else if state == 2 { - raylib.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, raylib.Black) - raylib.DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, raylib.Black) + rl.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, rl.Black) + rl.DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, rl.Black) - raylib.DrawRectangle(logoPositionX+240, logoPositionY, 16, rightSideRecHeight, raylib.Black) - raylib.DrawRectangle(logoPositionX, logoPositionY+240, bottomSideRecWidth, 16, raylib.Black) + rl.DrawRectangle(logoPositionX+240, logoPositionY, 16, rightSideRecHeight, rl.Black) + rl.DrawRectangle(logoPositionX, logoPositionY+240, bottomSideRecWidth, 16, rl.Black) } else if state == 3 { - raylib.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, raylib.Fade(raylib.Black, alpha)) - raylib.DrawRectangle(logoPositionX, logoPositionY+16, 16, leftSideRecHeight-32, raylib.Fade(raylib.Black, alpha)) + rl.DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, rl.Fade(rl.Black, alpha)) + rl.DrawRectangle(logoPositionX, logoPositionY+16, 16, leftSideRecHeight-32, rl.Fade(rl.Black, alpha)) - raylib.DrawRectangle(logoPositionX+240, logoPositionY+16, 16, rightSideRecHeight-32, raylib.Fade(raylib.Black, alpha)) - raylib.DrawRectangle(logoPositionX, logoPositionY+240, bottomSideRecWidth, 16, raylib.Fade(raylib.Black, alpha)) + rl.DrawRectangle(logoPositionX+240, logoPositionY+16, 16, rightSideRecHeight-32, rl.Fade(rl.Black, alpha)) + rl.DrawRectangle(logoPositionX, logoPositionY+240, bottomSideRecWidth, 16, rl.Fade(rl.Black, alpha)) - raylib.DrawRectangle(screenWidth/2-112, screenHeight/2-112, 224, 224, raylib.Fade(raylib.RayWhite, alpha)) + rl.DrawRectangle(screenWidth/2-112, screenHeight/2-112, 224, 224, rl.Fade(rl.RayWhite, alpha)) text := "raylib" length := int32(len(text)) @@ -112,13 +112,13 @@ func main() { lettersCount = length } - raylib.DrawText(text[0:lettersCount], screenWidth/2-44, screenHeight/2+48, 50, raylib.Fade(raylib.Black, alpha)) + rl.DrawText(text[0:lettersCount], screenWidth/2-44, screenHeight/2+48, 50, rl.Fade(rl.Black, alpha)) } else if state == 4 { - raylib.DrawText("[R] REPLAY", 340, 200, 20, raylib.Gray) + rl.DrawText("[R] REPLAY", 340, 200, 20, rl.Gray) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/shapes/rectangle_scaling/main.go b/examples/shapes/rectangle_scaling/main.go new file mode 100644 index 0000000..029fef5 --- /dev/null +++ b/examples/shapes/rectangle_scaling/main.go @@ -0,0 +1,78 @@ +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 ee6fb87..a1724dd 100644 --- a/examples/text/bmfont_ttf/main.go +++ b/examples/text/bmfont_ttf/main.go @@ -1,42 +1,38 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont and ttf sprite fonts loading") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont and ttf sprite fonts loading") msgBm := "THIS IS AN AngelCode SPRITE FONT" msgTtf := "THIS SPRITE FONT has been GENERATED from a TTF" // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - fontBm := raylib.LoadFont("fonts/bmfont.fnt") // BMFont (AngelCode) - fontTtf := raylib.LoadFont("fonts/pixantiqua.ttf") // TTF font + fontBm := rl.LoadFont("fonts/bmfont.fnt") // BMFont (AngelCode) + fontTtf := rl.LoadFont("fonts/pixantiqua.ttf") // TTF font - fontPosition := raylib.Vector2{} + fontPosition := rl.Vector2{} - fontPosition.X = float32(screenWidth)/2 - raylib.MeasureTextEx(fontBm, msgBm, float32(fontBm.BaseSize), 0).X/2 + fontPosition.X = float32(screenWidth)/2 - rl.MeasureTextEx(fontBm, msgBm, float32(fontBm.BaseSize), 0).X/2 fontPosition.Y = float32(screenHeight)/2 - float32(fontBm.BaseSize)/2 - 80 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.BaseSize), 0, raylib.Maroon) - raylib.DrawTextEx(fontTtf, msgTtf, raylib.NewVector2(75.0, 240.0), float32(fontTtf.BaseSize)*0.8, 2, raylib.Lime) + rl.DrawTextEx(fontBm, msgBm, fontPosition, float32(fontBm.BaseSize), 0, rl.Maroon) + rl.DrawTextEx(fontTtf, msgTtf, rl.NewVector2(75.0, 240.0), float32(fontTtf.BaseSize)*0.8, 2, rl.Lime) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadFont(fontBm) // AngelCode Font unloading - raylib.UnloadFont(fontTtf) // TTF Font unloading + rl.UnloadFont(fontBm) // AngelCode Font unloading + rl.UnloadFont(fontTtf) // TTF Font unloading - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/bmfont_unordered/main.go b/examples/text/bmfont_unordered/main.go index a3238e3..f67f0b4 100644 --- a/examples/text/bmfont_unordered/main.go +++ b/examples/text/bmfont_unordered/main.go @@ -3,39 +3,39 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont unordered loading and drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - bmfont unordered loading and drawing") // NOTE: Using chars outside the [32..127] limits! // NOTE: If a character is not found in the font, it just renders a space msg := "ASCII extended characters:\n¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆ\nÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæ\nçèéêëìíîïðñòóôõö÷øùúûüýþÿ" // NOTE: Loaded font has an unordered list of characters (chars in the range 32..255) - font := raylib.LoadFont("fonts/pixantiqua.fnt") // BMFont (AngelCode) + font := rl.LoadFont("fonts/pixantiqua.fnt") // BMFont (AngelCode) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("Font name: PixAntiqua", 40, 50, 20, raylib.Gray) - raylib.DrawText(fmt.Sprintf("Font base size: %d", font.BaseSize), 40, 80, 20, raylib.Gray) - raylib.DrawText(fmt.Sprintf("Font chars number: %d", font.CharsCount), 40, 110, 20, raylib.Gray) + rl.DrawText("Font name: PixAntiqua", 40, 50, 20, rl.Gray) + rl.DrawText(fmt.Sprintf("Font base size: %d", font.BaseSize), 40, 80, 20, rl.Gray) + rl.DrawText(fmt.Sprintf("Font chars number: %d", font.CharsCount), 40, 110, 20, rl.Gray) - raylib.DrawTextEx(font, msg, raylib.NewVector2(40, 180), float32(font.BaseSize), 0, raylib.Maroon) + rl.DrawTextEx(font, msg, rl.NewVector2(40, 180), float32(font.BaseSize), 0, rl.Maroon) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadFont(font) // AngelCode Font unloading + rl.UnloadFont(font) // AngelCode Font unloading - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/codepoints_loading/DotGothic16-Regular.ttf b/examples/text/codepoints_loading/DotGothic16-Regular.ttf new file mode 100644 index 0000000..18b0c1e Binary files /dev/null and b/examples/text/codepoints_loading/DotGothic16-Regular.ttf differ diff --git a/examples/text/codepoints_loading/main.go b/examples/text/codepoints_loading/main.go new file mode 100644 index 0000000..d8793a1 --- /dev/null +++ b/examples/text/codepoints_loading/main.go @@ -0,0 +1,95 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..d2134a6 --- /dev/null +++ b/examples/text/draw_3d/alpha_discard.fs @@ -0,0 +1,19 @@ +#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 new file mode 100644 index 0000000..e534924 --- /dev/null +++ b/examples/text/draw_3d/main.go @@ -0,0 +1,822 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..04478b2 Binary files /dev/null and b/examples/text/font_filters/KAISG.ttf differ diff --git a/examples/text/font_filters/main.go b/examples/text/font_filters/main.go new file mode 100644 index 0000000..7c181de --- /dev/null +++ b/examples/text/font_filters/main.go @@ -0,0 +1,125 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..db1b49d --- /dev/null +++ b/examples/text/font_loading/main.go @@ -0,0 +1,79 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..fd9f9db --- /dev/null +++ b/examples/text/font_loading/pixantiqua.fnt @@ -0,0 +1,188 @@ +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 new file mode 100644 index 0000000..2aa2870 Binary files /dev/null and b/examples/text/font_loading/pixantiqua.png differ diff --git a/examples/text/font_loading/pixantiqua.ttf b/examples/text/font_loading/pixantiqua.ttf new file mode 100644 index 0000000..e012875 Binary files /dev/null and b/examples/text/font_loading/pixantiqua.ttf differ diff --git a/examples/text/font_sdf/AnonymousPro-Bold.ttf b/examples/text/font_sdf/AnonymousPro-Bold.ttf new file mode 100644 index 0000000..f14c18c Binary files /dev/null and b/examples/text/font_sdf/AnonymousPro-Bold.ttf differ diff --git a/examples/text/font_sdf/OFL.txt b/examples/text/font_sdf/OFL.txt new file mode 100644 index 0000000..45b11f5 --- /dev/null +++ b/examples/text/font_sdf/OFL.txt @@ -0,0 +1,94 @@ +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 new file mode 100644 index 0000000..915048d --- /dev/null +++ b/examples/text/font_sdf/main.go @@ -0,0 +1,106 @@ +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 new file mode 100644 index 0000000..545f450 --- /dev/null +++ b/examples/text/font_sdf/sdf.fs @@ -0,0 +1,26 @@ +#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 f741f33..4320b5c 100644 --- a/examples/text/format_text/main.go +++ b/examples/text/format_text/main.go @@ -3,36 +3,36 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - text formatting") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - text formatting") score := 100020 hiscore := 200450 lives := 5 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText(fmt.Sprintf("Score: %08d", score), 200, 80, 20, raylib.Red) + rl.DrawText(fmt.Sprintf("Score: %08d", score), 200, 80, 20, rl.Red) - raylib.DrawText(fmt.Sprintf("HiScore: %08d", hiscore), 200, 120, 20, raylib.Green) + rl.DrawText(fmt.Sprintf("HiScore: %08d", hiscore), 200, 120, 20, rl.Green) - raylib.DrawText(fmt.Sprintf("Lives: %02d", lives), 200, 160, 40, raylib.Blue) + rl.DrawText(fmt.Sprintf("Lives: %02d", lives), 200, 160, 40, rl.Blue) - raylib.DrawText(fmt.Sprintf("Elapsed Time: %02.02f ms", raylib.GetFrameTime()*1000), 200, 220, 20, raylib.Black) + rl.DrawText(fmt.Sprintf("Elapsed Time: %02.02f ms", rl.GetFrameTime()*1000), 200, 220, 20, rl.Black) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/input_box/main.go b/examples/text/input_box/main.go new file mode 100644 index 0000000..b1e3e18 --- /dev/null +++ b/examples/text/input_box/main.go @@ -0,0 +1,122 @@ +/******************************************************************************************* + * + * 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 8576528..c5257ef 100644 --- a/examples/text/raylib_fonts/main.go +++ b/examples/text/raylib_fonts/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) const maxFonts = 8 @@ -10,17 +10,17 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - raylib fonts") - fonts := make([]raylib.Font, maxFonts) - fonts[0] = raylib.LoadFont("fonts/alagard.png") - fonts[1] = raylib.LoadFont("fonts/pixelplay.png") - fonts[2] = raylib.LoadFont("fonts/mecha.png") - fonts[3] = raylib.LoadFont("fonts/setback.png") - fonts[4] = raylib.LoadFont("fonts/romulus.png") - fonts[5] = raylib.LoadFont("fonts/pixantiqua.png") - fonts[6] = raylib.LoadFont("fonts/alpha_beta.png") - fonts[7] = raylib.LoadFont("fonts/jupiter_crash.png") + fonts := make([]rl.Font, maxFonts) + fonts[0] = rl.LoadFont("fonts/alagard.png") + fonts[1] = rl.LoadFont("fonts/pixelplay.png") + fonts[2] = rl.LoadFont("fonts/mecha.png") + fonts[3] = rl.LoadFont("fonts/setback.png") + fonts[4] = rl.LoadFont("fonts/romulus.png") + fonts[5] = rl.LoadFont("fonts/pixantiqua.png") + fonts[6] = rl.LoadFont("fonts/alpha_beta.png") + fonts[7] = rl.LoadFont("fonts/jupiter_crash.png") messages := []string{ "ALAGARD FONT designed by Hewett Tsoi", @@ -34,13 +34,13 @@ func main() { } spacings := []float32{2, 4, 8, 4, 3, 4, 4, 1} - positions := make([]raylib.Vector2, maxFonts) + positions := make([]rl.Vector2, maxFonts) var i int32 for i = 0; i < maxFonts; i++ { - x := screenWidth/2 - int32(raylib.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2) + x := screenWidth/2 - int32(rl.MeasureTextEx(fonts[i], messages[i], float32(fonts[i].BaseSize*2), spacings[i]).X/2) y := 60 + fonts[i].BaseSize + 45*i - positions[i] = raylib.NewVector2(float32(x), float32(y)) + positions[i] = rl.NewVector2(float32(x), float32(y)) } // Small Y position corrections @@ -48,27 +48,27 @@ func main() { positions[4].Y += 2 positions[7].Y -= 8 - colors := []raylib.Color{raylib.Maroon, raylib.Orange, raylib.DarkGreen, raylib.DarkBlue, raylib.DarkPurple, raylib.Lime, raylib.Gold, raylib.DarkBrown} + colors := []rl.Color{rl.Maroon, rl.Orange, rl.DarkGreen, rl.DarkBlue, rl.DarkPurple, rl.Lime, rl.Gold, rl.DarkBrown} - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) - raylib.DrawText("free fonts included with raylib", 250, 20, 20, raylib.DarkGray) - raylib.DrawLine(220, 50, 590, 50, raylib.DarkGray) + rl.ClearBackground(rl.RayWhite) + rl.DrawText("free fonts included with raylib", 250, 20, 20, rl.DarkGray) + rl.DrawLine(220, 50, 590, 50, rl.DarkGray) for i = 0; i < maxFonts; i++ { - raylib.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].BaseSize*2), spacings[i], colors[i]) + rl.DrawTextEx(fonts[i], messages[i], positions[i], float32(fonts[i].BaseSize*2), spacings[i], colors[i]) } - raylib.EndDrawing() + rl.EndDrawing() } for i = 0; i < maxFonts; i++ { - raylib.UnloadFont(fonts[i]) + rl.UnloadFont(fonts[i]) } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/rectangle_bounds/main.go b/examples/text/rectangle_bounds/main.go new file mode 100644 index 0000000..b0d4172 --- /dev/null +++ b/examples/text/rectangle_bounds/main.go @@ -0,0 +1,308 @@ +/******************************************************************************************* +* +* 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 b49bde8..d388b62 100644 --- a/examples/text/sprite_fonts/main.go +++ b/examples/text/sprite_fonts/main.go @@ -1,52 +1,52 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - sprite fonts usage") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - sprite fonts usage") msg1 := "THIS IS A custom SPRITE FONT..." msg2 := "...and this is ANOTHER CUSTOM font..." msg3 := "...and a THIRD one! GREAT! :D" // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - font1 := raylib.LoadFont("fonts/custom_mecha.png") // Font loading - font2 := raylib.LoadFont("fonts/custom_alagard.png") // Font loading - font3 := raylib.LoadFont("fonts/custom_jupiter_crash.png") // Font loading + font1 := rl.LoadFont("fonts/custom_mecha.png") // Font loading + font2 := rl.LoadFont("fonts/custom_alagard.png") // Font loading + font3 := rl.LoadFont("fonts/custom_jupiter_crash.png") // Font loading - var fontPosition1, fontPosition2, fontPosition3 raylib.Vector2 + var fontPosition1, fontPosition2, fontPosition3 rl.Vector2 - fontPosition1.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font1, msg1, float32(font1.BaseSize), -3).X/2 + fontPosition1.X = float32(screenWidth)/2 - rl.MeasureTextEx(font1, msg1, float32(font1.BaseSize), -3).X/2 fontPosition1.Y = float32(screenHeight)/2 - float32(font1.BaseSize)/2 - 80 - fontPosition2.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font2, msg2, float32(font2.BaseSize), -2).X/2 + fontPosition2.X = float32(screenWidth)/2 - rl.MeasureTextEx(font2, msg2, float32(font2.BaseSize), -2).X/2 fontPosition2.Y = float32(screenHeight)/2 - float32(font2.BaseSize)/2 - 10 - fontPosition3.X = float32(screenWidth)/2 - raylib.MeasureTextEx(font3, msg3, float32(font3.BaseSize), 2).X/2 + fontPosition3.X = float32(screenWidth)/2 - rl.MeasureTextEx(font3, msg3, float32(font3.BaseSize), 2).X/2 fontPosition3.Y = float32(screenHeight)/2 - float32(font3.BaseSize)/2 + 50 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTextEx(font1, msg1, fontPosition1, float32(font1.BaseSize), -3, raylib.White) - raylib.DrawTextEx(font2, msg2, fontPosition2, float32(font2.BaseSize), -2, raylib.White) - raylib.DrawTextEx(font3, msg3, fontPosition3, float32(font3.BaseSize), 2, raylib.White) + rl.DrawTextEx(font1, msg1, fontPosition1, float32(font1.BaseSize), -3, rl.White) + rl.DrawTextEx(font2, msg2, fontPosition2, float32(font2.BaseSize), -2, rl.White) + rl.DrawTextEx(font3, msg3, fontPosition3, float32(font3.BaseSize), 2, rl.White) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadFont(font1) // Font unloading - raylib.UnloadFont(font2) // Font unloading - raylib.UnloadFont(font3) // Font unloading + rl.UnloadFont(font1) // Font unloading + rl.UnloadFont(font2) // Font unloading + rl.UnloadFont(font3) // Font unloading - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/ttf_loading/main.go b/examples/text/ttf_loading/main.go index f03e40d..d3dae4a 100644 --- a/examples/text/ttf_loading/main.go +++ b/examples/text/ttf_loading/main.go @@ -3,110 +3,109 @@ package main import ( "fmt" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - ttf loading") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - ttf loading") msg := "TTF Font" // NOTE: Textures/Fonts MUST be loaded after Window initialization (OpenGL context is required) - fontChars := int32(0) - // TTF Font loading with custom generation parameters - font := raylib.LoadFontEx("fonts/KAISG.ttf", 96, 0, &fontChars) + font := rl.LoadFontEx("fonts/KAISG.ttf", 96, nil) // Generate mipmap levels to use trilinear filtering // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR - raylib.GenTextureMipmaps(&font.Texture) + rl.GenTextureMipmaps(&font.Texture) fontSize := font.BaseSize - fontPosition := raylib.NewVector2(40, float32(screenHeight)/2+50) - textSize := raylib.Vector2{} + fontPosition := rl.NewVector2(40, float32(screenHeight)/2+50) + textSize := rl.Vector2{} - raylib.SetTextureFilter(font.Texture, raylib.FilterPoint) + rl.SetTextureFilter(font.Texture, rl.FilterPoint) currentFontFilter := 0 // FilterPoint - count := int32(0) + count := 0 droppedFiles := make([]string, 0) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update //---------------------------------------------------------------------------------- - fontSize += raylib.GetMouseWheelMove() * 4.0 + fontSize += int32(rl.GetMouseWheelMove() * 4.0) // Choose font texture filter method - if raylib.IsKeyPressed(raylib.KeyOne) { - raylib.SetTextureFilter(font.Texture, raylib.FilterPoint) + if rl.IsKeyPressed(rl.KeyOne) { + rl.SetTextureFilter(font.Texture, rl.FilterPoint) currentFontFilter = 0 - } else if raylib.IsKeyPressed(raylib.KeyTwo) { - raylib.SetTextureFilter(font.Texture, raylib.FilterBilinear) + } else if rl.IsKeyPressed(rl.KeyTwo) { + rl.SetTextureFilter(font.Texture, rl.FilterBilinear) currentFontFilter = 1 - } else if raylib.IsKeyPressed(raylib.KeyThree) { + } else if rl.IsKeyPressed(rl.KeyThree) { // NOTE: Trilinear filter won't be noticed on 2D drawing - raylib.SetTextureFilter(font.Texture, raylib.FilterTrilinear) + rl.SetTextureFilter(font.Texture, rl.FilterTrilinear) currentFontFilter = 2 } - textSize = raylib.MeasureTextEx(font, msg, float32(fontSize), 0) + textSize = rl.MeasureTextEx(font, msg, float32(fontSize), 0) - if raylib.IsKeyDown(raylib.KeyLeft) { + if rl.IsKeyDown(rl.KeyLeft) { fontPosition.X -= 10 - } else if raylib.IsKeyDown(raylib.KeyRight) { + } else if rl.IsKeyDown(rl.KeyRight) { fontPosition.X += 10 } // Load a dropped TTF file dynamically (at current fontSize) - if raylib.IsFileDropped() { - droppedFiles = raylib.GetDroppedFiles(&count) + if rl.IsFileDropped() { + droppedFiles = rl.LoadDroppedFiles() + count = len(droppedFiles) if count == 1 { // Only support one ttf file dropped - raylib.UnloadFont(font) - font = raylib.LoadFontEx(droppedFiles[0], fontSize, 0, &fontChars) - raylib.ClearDroppedFiles() + rl.UnloadFont(font) + font = rl.LoadFontEx(droppedFiles[0], fontSize, nil) + rl.UnloadDroppedFiles() } } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("Use mouse wheel to change font size", 20, 20, 10, raylib.Gray) - raylib.DrawText("Use KEY_RIGHT and KEY_LEFT to move text", 20, 40, 10, raylib.Gray) - raylib.DrawText("Use 1, 2, 3 to change texture filter", 20, 60, 10, raylib.Gray) - raylib.DrawText("Drop a new TTF font for dynamic loading", 20, 80, 10, raylib.DarkGray) + 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) - raylib.DrawTextEx(font, msg, fontPosition, float32(fontSize), 0, raylib.Black) + rl.DrawTextEx(font, msg, fontPosition, float32(fontSize), 0, rl.Black) // TODO: It seems texSize measurement is not accurate due to chars offsets... - //raylib.DrawRectangleLines(int32(fontPosition.X), int32(fontPosition.Y), int32(textSize.X), int32(textSize.Y), raylib.Red) + //rl.DrawRectangleLines(int32(fontPosition.X), int32(fontPosition.Y), int32(textSize.X), int32(textSize.Y), rl.Red) - raylib.DrawRectangle(0, screenHeight-80, screenWidth, 80, raylib.LightGray) - raylib.DrawText(fmt.Sprintf("Font size: %02.02f", float32(fontSize)), 20, screenHeight-50, 10, raylib.DarkGray) - raylib.DrawText(fmt.Sprintf("Text size: [%02.02f, %02.02f]", textSize.X, textSize.Y), 20, screenHeight-30, 10, raylib.DarkGray) - raylib.DrawText("CURRENT TEXTURE FILTER:", 250, 400, 20, raylib.Gray) + rl.DrawRectangle(0, screenHeight-80, screenWidth, 80, rl.LightGray) + rl.DrawText(fmt.Sprintf("Font size: %02.02f", float32(fontSize)), 20, screenHeight-50, 10, rl.DarkGray) + rl.DrawText(fmt.Sprintf("Text size: [%02.02f, %02.02f]", textSize.X, textSize.Y), 20, screenHeight-30, 10, rl.DarkGray) + rl.DrawText("CURRENT TEXTURE FILTER:", 250, 400, 20, rl.Gray) if currentFontFilter == 0 { - raylib.DrawText("POINT", 570, 400, 20, raylib.Black) + rl.DrawText("POINT", 570, 400, 20, rl.Black) } else if currentFontFilter == 1 { - raylib.DrawText("BILINEAR", 570, 400, 20, raylib.Black) + rl.DrawText("BILINEAR", 570, 400, 20, rl.Black) } else if currentFontFilter == 2 { - raylib.DrawText("TRILINEAR", 570, 400, 20, raylib.Black) + rl.DrawText("TRILINEAR", 570, 400, 20, rl.Black) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadFont(font) // Font unloading + rl.UnloadFont(font) // Font unloading - raylib.ClearDroppedFiles() // Clear internal buffers + rl.UnloadDroppedFiles() // Clear internal buffers - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/text/unicode/main.go b/examples/text/unicode/main.go new file mode 100644 index 0000000..42f1897 --- /dev/null +++ b/examples/text/unicode/main.go @@ -0,0 +1,396 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..6503b35 --- /dev/null +++ b/examples/text/unicode/resources/dejavu.fnt @@ -0,0 +1,1115 @@ +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 new file mode 100644 index 0000000..77fe4b3 Binary files /dev/null and b/examples/text/unicode/resources/dejavu.png differ diff --git a/examples/text/unicode/resources/noto_cjk.fnt b/examples/text/unicode/resources/noto_cjk.fnt new file mode 100644 index 0000000..f112ef8 --- /dev/null +++ b/examples/text/unicode/resources/noto_cjk.fnt @@ -0,0 +1,580 @@ +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 new file mode 100644 index 0000000..d3f7b6f Binary files /dev/null and b/examples/text/unicode/resources/noto_cjk.png differ diff --git a/examples/text/unicode/resources/symbola.fnt b/examples/text/unicode/resources/symbola.fnt new file mode 100644 index 0000000..5a39fcd --- /dev/null +++ b/examples/text/unicode/resources/symbola.fnt @@ -0,0 +1,191 @@ +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 new file mode 100644 index 0000000..e942606 Binary files /dev/null and b/examples/text/unicode/resources/symbola.png differ diff --git a/examples/text/unicode/unicode.go b/examples/text/unicode/unicode.go new file mode 100644 index 0000000..a6d51e9 --- /dev/null +++ b/examples/text/unicode/unicode.go @@ -0,0 +1,298 @@ +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 78fddbb..a6671a0 100644 --- a/examples/text/writing_anim/main.go +++ b/examples/text/writing_anim/main.go @@ -1,31 +1,31 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [text] example - text writing anim") + rl.InitWindow(screenWidth, screenHeight, "raylib [text] example - text writing anim") message := "This sample illustrates a text writing\nanimation effect! Check it out! ;)" length := len(message) framesCounter := 0 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update - if raylib.IsKeyDown(raylib.KeySpace) { + if rl.IsKeyDown(rl.KeySpace) { framesCounter += 8 } else { framesCounter++ } - if raylib.IsKeyPressed(raylib.KeyEnter) { + if rl.IsKeyPressed(rl.KeyEnter) { framesCounter = 0 } @@ -34,17 +34,17 @@ func main() { } // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText(message[0:framesCounter/10], 210, 160, 20, raylib.Maroon) + rl.DrawText(message[0:framesCounter/10], 210, 160, 20, rl.Maroon) - raylib.DrawText("PRESS [ENTER] to RESTART!", 240, 260, 20, raylib.LightGray) - raylib.DrawText("PRESS [SPACE] to SPEED UP!", 239, 300, 20, raylib.LightGray) + rl.DrawText("PRESS [ENTER] to RESTART!", 240, 260, 20, rl.LightGray) + rl.DrawText("PRESS [SPACE] to SPEED UP!", 239, 300, 20, rl.LightGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/background_scrolling/cyberpunk_street_background.png b/examples/textures/background_scrolling/cyberpunk_street_background.png new file mode 100644 index 0000000..838d08a Binary files /dev/null and b/examples/textures/background_scrolling/cyberpunk_street_background.png differ diff --git a/examples/textures/background_scrolling/cyberpunk_street_foreground.png b/examples/textures/background_scrolling/cyberpunk_street_foreground.png new file mode 100644 index 0000000..528b4ae Binary files /dev/null and b/examples/textures/background_scrolling/cyberpunk_street_foreground.png differ diff --git a/examples/textures/background_scrolling/cyberpunk_street_midground.png b/examples/textures/background_scrolling/cyberpunk_street_midground.png new file mode 100644 index 0000000..73f24fe Binary files /dev/null and b/examples/textures/background_scrolling/cyberpunk_street_midground.png differ diff --git a/examples/textures/background_scrolling/main.go b/examples/textures/background_scrolling/main.go new file mode 100644 index 0000000..ef36116 --- /dev/null +++ b/examples/textures/background_scrolling/main.go @@ -0,0 +1,67 @@ +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 new file mode 100644 index 0000000..838d08a Binary files /dev/null and b/examples/textures/blend_modes/cyberpunk_street_background.png differ diff --git a/examples/textures/blend_modes/cyberpunk_street_foreground.png b/examples/textures/blend_modes/cyberpunk_street_foreground.png new file mode 100644 index 0000000..528b4ae Binary files /dev/null and b/examples/textures/blend_modes/cyberpunk_street_foreground.png differ diff --git a/examples/textures/blend_modes/main.go b/examples/textures/blend_modes/main.go new file mode 100644 index 0000000..0c857c6 --- /dev/null +++ b/examples/textures/blend_modes/main.go @@ -0,0 +1,81 @@ +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 new file mode 100644 index 0000000..2a4ca93 --- /dev/null +++ b/examples/textures/draw_tiled/main.go @@ -0,0 +1,302 @@ +/******************************************************************************************* + * + * 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 new file mode 100644 index 0000000..58b3c37 Binary files /dev/null and b/examples/textures/draw_tiled/patterns.png differ diff --git a/examples/textures/image_drawing/main.go b/examples/textures/image_drawing/main.go index 230ce99..c4f76e1 100644 --- a/examples/textures/image_drawing/main.go +++ b/examples/textures/image_drawing/main.go @@ -1,49 +1,45 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - cat := raylib.LoadImage("cat.png") // Load image in CPU memory (RAM) - raylib.ImageCrop(cat, raylib.NewRectangle(100, 10, 280, 380)) // Crop an image piece - raylib.ImageFlipHorizontal(cat) // Flip cropped image horizontally - raylib.ImageResize(cat, 150, 200) // Resize flipped-cropped image + cat := rl.LoadImage("cat.png") // Load image in CPU memory (RAM) + rl.ImageCrop(cat, rl.NewRectangle(100, 10, 280, 380)) // Crop an image piece + rl.ImageFlipHorizontal(cat) // Flip cropped image horizontally + rl.ImageResize(cat, 150, 200) // Resize flipped-cropped image - parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM) + parrots := rl.LoadImage("parrots.png") // Load image in CPU memory (RAM) // Draw one image over the other with a scaling of 1.5f - raylib.ImageDraw(parrots, cat, raylib.NewRectangle(0, 0, float32(cat.Width), float32(cat.Height)), raylib.NewRectangle(30, 40, float32(cat.Width)*1.5, float32(cat.Height)*1.5)) - raylib.ImageCrop(parrots, raylib.NewRectangle(0, 50, float32(parrots.Width), float32(parrots.Height-100))) // Crop resulting image + rl.ImageDraw(parrots, cat, rl.NewRectangle(0, 0, float32(cat.Width), float32(cat.Height)), rl.NewRectangle(30, 40, float32(cat.Width)*1.5, float32(cat.Height)*1.5), rl.White) + rl.ImageCrop(parrots, rl.NewRectangle(0, 50, float32(parrots.Width), float32(parrots.Height-100))) // Crop resulting image - raylib.UnloadImage(cat) // Unload image from RAM + rl.UnloadImage(cat) // Unload image from RAM - texture := raylib.LoadTextureFromImage(parrots) // Image converted to texture, uploaded to GPU memory (VRAM) - raylib.UnloadImage(parrots) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM + texture := rl.LoadTextureFromImage(parrots) // Image converted to texture, uploaded to GPU memory (VRAM) + rl.UnloadImage(parrots) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2-40, raylib.White) - raylib.DrawRectangleLines(screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2-40, texture.Width, texture.Height, raylib.DarkGray) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2-40, rl.White) + rl.DrawRectangleLines(screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2-40, texture.Width, texture.Height, rl.DarkGray) - raylib.DrawText("We are drawing only one texture from various images composed!", 240, 350, 10, raylib.DarkGray) - raylib.DrawText("Source images have been cropped, scaled, flipped and copied one over the other.", 190, 370, 10, raylib.DarkGray) + rl.DrawText("We are drawing only one texture from various images composed!", 240, 350, 10, rl.DarkGray) + rl.DrawText("Source images have been cropped, scaled, flipped and copied one over the other.", 190, 370, 10, rl.DarkGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/image_generation/main.go b/examples/textures/image_generation/main.go index 7e963e8..16f78fd 100644 --- a/examples/textures/image_generation/main.go +++ b/examples/textures/image_generation/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const numTextures = 7 @@ -10,85 +10,79 @@ func main() { screenWidth := 800 screenHeight := 450 - raylib.InitWindow(int32(screenWidth), int32(screenHeight), "raylib [textures] example - procedural images generation") + rl.InitWindow(int32(screenWidth), int32(screenHeight), "raylib [textures] example - procedural images generation") - verticalGradient := raylib.GenImageGradientV(screenWidth, screenHeight, raylib.Red, raylib.Blue) - horizontalGradient := raylib.GenImageGradientH(screenWidth, screenHeight, raylib.Red, raylib.Blue) - radialGradient := raylib.GenImageGradientRadial(screenWidth, screenHeight, 0, raylib.White, raylib.Black) - checked := raylib.GenImageChecked(screenWidth, screenHeight, 32, 32, raylib.Red, raylib.Blue) - whiteNoise := raylib.GenImageWhiteNoise(screenWidth, screenHeight, 0.5) - perlinNoise := raylib.GenImagePerlinNoise(screenWidth, screenHeight, 50, 50, 4.0) - cellular := raylib.GenImageCellular(screenWidth, screenHeight, 32) + verticalGradient := rl.GenImageGradientLinear(screenWidth, screenHeight, 0, rl.Red, rl.Blue) + horizontalGradient := rl.GenImageGradientLinear(screenWidth, screenHeight, 90, 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) + cellular := rl.GenImageCellular(screenWidth, screenHeight, 32) - textures := make([]raylib.Texture2D, numTextures) - textures[0] = raylib.LoadTextureFromImage(verticalGradient) - textures[1] = raylib.LoadTextureFromImage(horizontalGradient) - textures[2] = raylib.LoadTextureFromImage(radialGradient) - textures[3] = raylib.LoadTextureFromImage(checked) - textures[4] = raylib.LoadTextureFromImage(whiteNoise) - textures[5] = raylib.LoadTextureFromImage(perlinNoise) - textures[6] = raylib.LoadTextureFromImage(cellular) + textures := make([]rl.Texture2D, numTextures) + textures[0] = rl.LoadTextureFromImage(verticalGradient) + textures[1] = rl.LoadTextureFromImage(horizontalGradient) + textures[2] = rl.LoadTextureFromImage(radialGradient) + textures[3] = rl.LoadTextureFromImage(checked) + textures[4] = rl.LoadTextureFromImage(whiteNoise) + textures[5] = rl.LoadTextureFromImage(cellular) // Unload image data (CPU RAM) - raylib.UnloadImage(verticalGradient) - raylib.UnloadImage(horizontalGradient) - raylib.UnloadImage(radialGradient) - raylib.UnloadImage(checked) - raylib.UnloadImage(whiteNoise) - raylib.UnloadImage(perlinNoise) - raylib.UnloadImage(cellular) + rl.UnloadImage(verticalGradient) + rl.UnloadImage(horizontalGradient) + rl.UnloadImage(radialGradient) + rl.UnloadImage(checked) + rl.UnloadImage(whiteNoise) + rl.UnloadImage(cellular) currentTexture := 0 - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { + for !rl.WindowShouldClose() { + if rl.IsMouseButtonPressed(rl.MouseLeftButton) { currentTexture = (currentTexture + 1) % numTextures // Cycle between the textures } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTexture(textures[currentTexture], 0, 0, raylib.White) + rl.DrawTexture(textures[currentTexture], 0, 0, rl.White) - raylib.DrawRectangle(30, 400, 325, 30, raylib.Fade(raylib.SkyBlue, 0.5)) - raylib.DrawRectangleLines(30, 400, 325, 30, raylib.Fade(raylib.White, 0.5)) - raylib.DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL TEXTURES", 40, 410, 10, raylib.White) + rl.DrawRectangle(30, 400, 325, 30, rl.Fade(rl.SkyBlue, 0.5)) + rl.DrawRectangleLines(30, 400, 325, 30, rl.Fade(rl.White, 0.5)) + rl.DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL TEXTURES", 40, 410, 10, rl.White) switch currentTexture { case 0: - raylib.DrawText("VERTICAL GRADIENT", 560, 10, 20, raylib.RayWhite) + rl.DrawText("VERTICAL GRADIENT", 560, 10, 20, rl.RayWhite) break case 1: - raylib.DrawText("HORIZONTAL GRADIENT", 540, 10, 20, raylib.RayWhite) + rl.DrawText("HORIZONTAL GRADIENT", 540, 10, 20, rl.RayWhite) break case 2: - raylib.DrawText("RADIAL GRADIENT", 580, 10, 20, raylib.LightGray) + rl.DrawText("RADIAL GRADIENT", 580, 10, 20, rl.LightGray) break case 3: - raylib.DrawText("CHECKED", 680, 10, 20, raylib.RayWhite) + rl.DrawText("CHECKED", 680, 10, 20, rl.RayWhite) break case 4: - raylib.DrawText("WHITE NOISE", 640, 10, 20, raylib.Red) + rl.DrawText("WHITE NOISE", 640, 10, 20, rl.Red) break case 5: - raylib.DrawText("PERLIN NOISE", 630, 10, 20, raylib.RayWhite) - break - case 6: - raylib.DrawText("CELLULAR", 670, 10, 20, raylib.RayWhite) + rl.DrawText("CELLULAR", 670, 10, 20, rl.RayWhite) break default: break } - raylib.EndDrawing() + rl.EndDrawing() } for _, t := range textures { - raylib.UnloadTexture(t) + rl.UnloadTexture(t) } - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/image_image/main.go b/examples/textures/image_image/main.go index 82d3e5a..8de80bb 100644 --- a/examples/textures/image_image/main.go +++ b/examples/textures/image_image/main.go @@ -4,64 +4,64 @@ import ( "image/png" "os" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture from image.Image") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture from image.Image") r, err := os.Open("raylib_logo.png") if err != nil { - raylib.TraceLog(raylib.LogError, err.Error()) + rl.TraceLog(rl.LogError, err.Error()) } defer r.Close() img, err := png.Decode(r) if err != nil { - raylib.TraceLog(raylib.LogError, err.Error()) + rl.TraceLog(rl.LogError, err.Error()) } - // Create raylib.Image from Go image.Image and create texture - im := raylib.NewImageFromImage(img) - texture := raylib.LoadTextureFromImage(im) + // Create rl.Image from Go image.Image and create texture + im := rl.NewImageFromImage(img) + texture := rl.LoadTextureFromImage(im) // Unload CPU (RAM) image data - raylib.UnloadImage(im) + rl.UnloadImage(im) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyPressed(raylib.KeyS) { - rimg := raylib.GetTextureData(texture) + for !rl.WindowShouldClose() { + if rl.IsKeyPressed(rl.KeyS) { + rimg := rl.LoadImageFromTexture(texture) f, err := os.Create("image_saved.png") if err != nil { - raylib.TraceLog(raylib.LogError, err.Error()) + rl.TraceLog(rl.LogError, err.Error()) } err = png.Encode(f, rimg.ToImage()) if err != nil { - raylib.TraceLog(raylib.LogError, err.Error()) + rl.TraceLog(rl.LogError, err.Error()) } f.Close() } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("PRESS S TO SAVE IMAGE FROM TEXTURE", 20, 20, 12, raylib.LightGray) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, raylib.White) - raylib.DrawText("this IS a texture loaded from an image.Image!", 285, 370, 10, raylib.Gray) + rl.DrawText("PRESS S TO SAVE IMAGE FROM TEXTURE", 20, 20, 12, rl.LightGray) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, rl.White) + rl.DrawText("this IS a texture loaded from an image.Image!", 285, 370, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/image_loading/main.go b/examples/textures/image_loading/main.go index bbaba11..e97eb9b 100644 --- a/examples/textures/image_loading/main.go +++ b/examples/textures/image_loading/main.go @@ -1,37 +1,33 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image loading") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image loading") // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - image := raylib.LoadImage("raylib_logo.png") // Loaded in CPU memory (RAM) - texture := raylib.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) + image := rl.LoadImage("raylib_logo.png") // Loaded in CPU memory (RAM) + texture := rl.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) - raylib.UnloadImage(image) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM + rl.UnloadImage(image) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, raylib.White) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, rl.White) - raylib.DrawText("this IS a texture loaded from an image!", 300, 370, 10, raylib.Gray) + rl.DrawText("this IS a texture loaded from an image!", 300, 370, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/image_processing/main.go b/examples/textures/image_processing/main.go index b9d532b..5dfdc87 100644 --- a/examples/textures/image_processing/main.go +++ b/examples/textures/image_processing/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) const numProcesses = 8 @@ -33,31 +33,31 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image processing") - image := raylib.LoadImage("parrots.png") // Loaded in CPU memory (RAM) - raylib.ImageFormat(image, raylib.UncompressedR8g8b8a8) // Format image to RGBA 32bit (required for texture update) - texture := raylib.LoadTextureFromImage(image) // Image converted to texture, GPU memory (VRAM) + 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) currentProcess := None textureReload := false - selectRecs := make([]raylib.Rectangle, numProcesses) + selectRecs := make([]rl.Rectangle, numProcesses) for i := 0; i < numProcesses; i++ { - selectRecs[i] = raylib.NewRectangle(40, 50+32*float32(i), 150, 30) + selectRecs[i] = rl.NewRectangle(40, 50+32*float32(i), 150, 30) } - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyPressed(raylib.KeyDown) { + for !rl.WindowShouldClose() { + if rl.IsKeyPressed(rl.KeyDown) { currentProcess++ if currentProcess > 7 { currentProcess = 0 } textureReload = true - } else if raylib.IsKeyPressed(raylib.KeyUp) { + } else if rl.IsKeyPressed(rl.KeyUp) { currentProcess-- if currentProcess < 0 { currentProcess = 7 @@ -66,70 +66,70 @@ func main() { } if textureReload { - raylib.UnloadImage(image) // Unload current image data - image = raylib.LoadImage("parrots.png") // Re-load image data + rl.UnloadImage(image) // Unload current image data + image = rl.LoadImage("parrots.png") // Re-load image data // NOTE: Image processing is a costly CPU process to be done every frame, // If image processing is required in a frame-basis, it should be done // with a texture and by shaders switch currentProcess { case ColorGrayscale: - raylib.ImageColorGrayscale(image) + rl.ImageColorGrayscale(image) break case ColorTint: - raylib.ImageColorTint(image, raylib.Green) + rl.ImageColorTint(image, rl.Green) break case ColorInvert: - raylib.ImageColorInvert(image) + rl.ImageColorInvert(image) break case ColorContrast: - raylib.ImageColorContrast(image, -40) + rl.ImageColorContrast(image, -40) break case ColorBrightness: - raylib.ImageColorBrightness(image, -80) + rl.ImageColorBrightness(image, -80) break case FlipVertical: - raylib.ImageFlipVertical(image) + rl.ImageFlipVertical(image) break case FlipHorizontal: - raylib.ImageFlipHorizontal(image) + rl.ImageFlipHorizontal(image) break default: break } - pixels := raylib.GetImageData(image) // Get pixel data from image (RGBA 32bit) - raylib.UpdateTexture(texture, pixels) // Update texture with new image data + pixels := rl.LoadImageColors(image) // Get pixel data from image (RGBA 32bit) + rl.UpdateTexture(texture, pixels) // Update texture with new image data textureReload = false } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawText("IMAGE PROCESSING:", 40, 30, 10, raylib.DarkGray) + rl.DrawText("IMAGE PROCESSING:", 40, 30, 10, rl.DarkGray) // Draw rectangles for i := 0; i < numProcesses; i++ { if i == currentProcess { - raylib.DrawRectangleRec(selectRecs[i], raylib.SkyBlue) - raylib.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), raylib.Blue) - raylib.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-raylib.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, raylib.DarkBlue) + rl.DrawRectangleRec(selectRecs[i], rl.SkyBlue) + rl.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), rl.Blue) + rl.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-rl.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, rl.DarkBlue) } else { - raylib.DrawRectangleRec(selectRecs[i], raylib.LightGray) - raylib.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), raylib.Gray) - raylib.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-raylib.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, raylib.DarkGray) + rl.DrawRectangleRec(selectRecs[i], rl.LightGray) + rl.DrawRectangleLines(int32(selectRecs[i].X), int32(selectRecs[i].Y), int32(selectRecs[i].Width), int32(selectRecs[i].Height), rl.Gray) + rl.DrawText(processText[i], int32(selectRecs[i].X+selectRecs[i].Width/2)-rl.MeasureText(processText[i], 10)/2, int32(selectRecs[i].Y)+11, 10, rl.DarkGray) } } - raylib.DrawTexture(texture, screenWidth-texture.Width-60, screenHeight/2-texture.Height/2, raylib.White) - raylib.DrawRectangleLines(screenWidth-texture.Width-60, screenHeight/2-texture.Height/2, texture.Width, texture.Height, raylib.Black) + rl.DrawTexture(texture, screenWidth-texture.Width-60, screenHeight/2-texture.Height/2, rl.White) + rl.DrawRectangleLines(screenWidth-texture.Width-60, screenHeight/2-texture.Height/2, texture.Width, texture.Height, rl.Black) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/image_text/main.go b/examples/textures/image_text/main.go index d5c1cab..2b93857 100644 --- a/examples/textures/image_text/main.go +++ b/examples/textures/image_text/main.go @@ -1,62 +1,61 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image text drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - image text drawing") // TTF Font loading with custom generation parameters - var fontChars int32 - font := raylib.LoadFontEx("fonts/KAISG.ttf", 64, 0, &fontChars) + font := rl.LoadFontEx("fonts/KAISG.ttf", 64, nil) - parrots := raylib.LoadImage("parrots.png") // Load image in CPU memory (RAM) + parrots := rl.LoadImage("parrots.png") // Load image in CPU memory (RAM) // Draw over image using custom font - raylib.ImageDrawTextEx(parrots, raylib.NewVector2(20, 20), font, "[Parrots font drawing]", float32(font.BaseSize), 0, raylib.White) + rl.ImageDrawTextEx(parrots, rl.NewVector2(20, 20), font, "[Parrots font drawing]", float32(font.BaseSize), 0, rl.White) - texture := raylib.LoadTextureFromImage(parrots) // Image converted to texture, uploaded to GPU memory (VRAM) + texture := rl.LoadTextureFromImage(parrots) // Image converted to texture, uploaded to GPU memory (VRAM) - raylib.UnloadImage(parrots) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM + rl.UnloadImage(parrots) // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM - position := raylib.NewVector2(float32(screenWidth)/2-float32(texture.Width)/2, float32(screenHeight)/2-float32(texture.Height)/2-20) + position := rl.NewVector2(float32(screenWidth)/2-float32(texture.Width)/2, float32(screenHeight)/2-float32(texture.Height)/2-20) showFont := false - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - if raylib.IsKeyDown(raylib.KeySpace) { + for !rl.WindowShouldClose() { + if rl.IsKeyDown(rl.KeySpace) { showFont = true } else { showFont = false } - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) if !showFont { // Draw texture with text already drawn inside - raylib.DrawTextureV(texture, position, raylib.White) + rl.DrawTextureV(texture, position, rl.White) // Draw text directly using sprite font - raylib.DrawTextEx(font, "[Parrots font drawing]", raylib.NewVector2(position.X+20, position.Y+20+280), float32(font.BaseSize), 0, raylib.White) + rl.DrawTextEx(font, "[Parrots font drawing]", rl.NewVector2(position.X+20, position.Y+20+280), float32(font.BaseSize), 0, rl.White) } else { - raylib.DrawTexture(font.Texture, screenWidth/2-font.Texture.Width/2, 50, raylib.Black) + rl.DrawTexture(font.Texture, screenWidth/2-font.Texture.Width/2, 50, rl.Black) } - raylib.DrawText("PRESS SPACE to SEE USED SPRITEFONT ", 290, 420, 10, raylib.DarkGray) + rl.DrawText("PRESS SPACE to SEE USED SPRITEFONT ", 290, 420, 10, rl.DarkGray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) - raylib.UnloadFont(font) + rl.UnloadTexture(texture) + rl.UnloadFont(font) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/logo_raylib/main.go b/examples/textures/logo_raylib/main.go index 473e171..86d8d55 100644 --- a/examples/textures/logo_raylib/main.go +++ b/examples/textures/logo_raylib/main.go @@ -1,31 +1,31 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - texture := raylib.LoadTexture("raylib_logo.png") + texture := rl.LoadTexture("raylib_logo.png") - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, raylib.White) - raylib.DrawText("this IS a texture!", 360, 370, 10, raylib.Gray) + rl.ClearBackground(rl.RayWhite) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, rl.White) + rl.DrawText("this IS a texture!", 360, 370, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/mouse_painting/main.go b/examples/textures/mouse_painting/main.go new file mode 100644 index 0000000..6b61854 --- /dev/null +++ b/examples/textures/mouse_painting/main.go @@ -0,0 +1,188 @@ +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 new file mode 100644 index 0000000..43bfe6b --- /dev/null +++ b/examples/textures/npatch_drawing/main.go @@ -0,0 +1,134 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..f10037a Binary files /dev/null and b/examples/textures/npatch_drawing/ninepatch_button.png differ diff --git a/examples/textures/particles_blending/main.go b/examples/textures/particles_blending/main.go index 3cd7cd3..8b4b7ca 100644 --- a/examples/textures/particles_blending/main.go +++ b/examples/textures/particles_blending/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) const ( @@ -9,8 +9,8 @@ const ( ) type particle struct { - Position raylib.Vector2 - Color raylib.Color + Position rl.Vector2 + Color rl.Color Alpha float32 Size float32 Rotation float32 @@ -21,31 +21,31 @@ func main() { screenWidth := int32(800) screenHeight := int32(450) - //raylib.SetConfigFlags(raylib.FlagVsyncHint) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - particles blending") + //rl.SetConfigFlags(rl.FlagVsyncHint) + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - particles blending") // Particles pool, reuse them! mouseTail := make([]particle, maxParticles) // Initialize particles for i := 0; i < maxParticles; i++ { - mouseTail[i].Position = raylib.NewVector2(0, 0) - mouseTail[i].Color = raylib.NewColor(byte(raylib.GetRandomValue(0, 255)), byte(raylib.GetRandomValue(0, 255)), byte(raylib.GetRandomValue(0, 255)), 255) + mouseTail[i].Position = rl.NewVector2(0, 0) + mouseTail[i].Color = rl.NewColor(byte(rl.GetRandomValue(0, 255)), byte(rl.GetRandomValue(0, 255)), byte(rl.GetRandomValue(0, 255)), 255) mouseTail[i].Alpha = 1.0 - mouseTail[i].Size = float32(raylib.GetRandomValue(1, 30)) / 20.0 - mouseTail[i].Rotation = float32(raylib.GetRandomValue(0, 360)) + mouseTail[i].Size = float32(rl.GetRandomValue(1, 30)) / 20.0 + mouseTail[i].Rotation = float32(rl.GetRandomValue(0, 360)) mouseTail[i].Active = false } gravity := float32(3.0) - smoke := raylib.LoadTexture("smoke.png") + smoke := rl.LoadTexture("smoke.png") - blending := raylib.BlendAlpha + blending := rl.BlendAlpha - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update // Activate one particle every frame and Update active particles @@ -56,7 +56,7 @@ func main() { if !mouseTail[i].Active { mouseTail[i].Active = true mouseTail[i].Alpha = 1.0 - mouseTail[i].Position = raylib.GetMousePosition() + mouseTail[i].Position = rl.GetMousePosition() i = maxParticles } } @@ -74,50 +74,50 @@ func main() { } } - if raylib.IsKeyPressed(raylib.KeySpace) { - if blending == raylib.BlendAlpha { - blending = raylib.BlendAdditive + if rl.IsKeyPressed(rl.KeySpace) { + if blending == rl.BlendAlpha { + blending = rl.BlendAdditive } else { - blending = raylib.BlendAlpha + blending = rl.BlendAlpha } } // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.DarkGray) + rl.ClearBackground(rl.DarkGray) - raylib.BeginBlendMode(blending) + rl.BeginBlendMode(blending) // Draw active particles for i := 0; i < maxParticles; i++ { if mouseTail[i].Active { - raylib.DrawTexturePro( + rl.DrawTexturePro( smoke, - raylib.NewRectangle(0, 0, float32(smoke.Width), float32(smoke.Height)), - raylib.NewRectangle(mouseTail[i].Position.X, mouseTail[i].Position.Y, float32(smoke.Width)*mouseTail[i].Size, float32(smoke.Height)*mouseTail[i].Size), - raylib.NewVector2(float32(smoke.Width)*mouseTail[i].Size/2, float32(smoke.Height)*mouseTail[i].Size/2), + rl.NewRectangle(0, 0, float32(smoke.Width), float32(smoke.Height)), + rl.NewRectangle(mouseTail[i].Position.X, mouseTail[i].Position.Y, float32(smoke.Width)*mouseTail[i].Size, float32(smoke.Height)*mouseTail[i].Size), + rl.NewVector2(float32(smoke.Width)*mouseTail[i].Size/2, float32(smoke.Height)*mouseTail[i].Size/2), mouseTail[i].Rotation, - raylib.Fade(mouseTail[i].Color, mouseTail[i].Alpha), + rl.Fade(mouseTail[i].Color, mouseTail[i].Alpha), ) } } - raylib.EndBlendMode() + rl.EndBlendMode() - raylib.DrawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, raylib.Black) + rl.DrawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, rl.Black) - if blending == raylib.BlendAlpha { - raylib.DrawText("ALPHA BLENDING", 290, screenHeight-40, 20, raylib.Black) + if blending == rl.BlendAlpha { + rl.DrawText("ALPHA BLENDING", 290, screenHeight-40, 20, rl.Black) } else { - raylib.DrawText("ADDITIVE BLENDING", 280, screenHeight-40, 20, raylib.RayWhite) + rl.DrawText("ADDITIVE BLENDING", 280, screenHeight-40, 20, rl.RayWhite) } - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(smoke) + rl.UnloadTexture(smoke) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/raw_data/main.go b/examples/textures/raw_data/main.go index c0f5203..c950d51 100644 --- a/examples/textures/raw_data/main.go +++ b/examples/textures/raw_data/main.go @@ -1,63 +1,64 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture from raw data") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture from raw data") // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) // Load RAW image data (384x512, 32bit RGBA, no file header) - fudesumiRaw := raylib.LoadImageRaw("texture_formats/fudesumi.raw", 384, 512, raylib.UncompressedR8g8b8a8, 0) - fudesumi := raylib.LoadTextureFromImage(fudesumiRaw) // Upload CPU (RAM) image to GPU (VRAM) - raylib.UnloadImage(fudesumiRaw) // Unload CPU (RAM) image data + fudesumiRaw := rl.LoadImageRaw("texture_formats/fudesumi.raw", 384, 512, rl.UncompressedR8g8b8a8, 0) + fudesumi := rl.LoadTextureFromImage(fudesumiRaw) // Upload CPU (RAM) image to GPU (VRAM) + rl.UnloadImage(fudesumiRaw) // Unload CPU (RAM) image data // Generate a checked texture by code (1024x1024 pixels) width := 1024 height := 1024 // Dynamic memory allocation to store pixels data (Color type) - pixels := make([]raylib.Color, width*height) + pixels := make([]rl.Color, width*height) for y := 0; y < height; y++ { for x := 0; x < width; x++ { if ((x/32+y/32)/1)%2 == 0 { - pixels[y*height+x] = raylib.Orange + pixels[y*height+x] = rl.Orange } else { - pixels[y*height+x] = raylib.Gold + pixels[y*height+x] = rl.Gold } } } + // LoadImageEx was removed from raylib // Load pixels data into an image structure and create texture - checkedIm := raylib.LoadImageEx(pixels, int32(width), int32(height)) - checked := raylib.LoadTextureFromImage(checkedIm) - raylib.UnloadImage(checkedIm) // Unload CPU (RAM) image data + // checkedIm := rl.LoadImageEx(pixels, int32(width), int32(height)) + // checked := rl.LoadTextureFromImage(checkedIm) + // rl.UnloadImage(checkedIm) // Unload CPU (RAM) image data - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTexture(checked, screenWidth/2-checked.Width/2, screenHeight/2-checked.Height/2, raylib.Fade(raylib.White, 0.5)) - raylib.DrawTexture(fudesumi, 430, -30, raylib.White) + //rl.DrawTexture(checked, screenWidth/2-checked.Width/2, screenHeight/2-checked.Height/2, rl.Fade(rl.White, 0.5)) + rl.DrawTexture(fudesumi, 430, -30, rl.White) - raylib.DrawText("CHECKED TEXTURE ", 84, 100, 30, raylib.Brown) - raylib.DrawText("GENERATED by CODE", 72, 164, 30, raylib.Brown) - raylib.DrawText("and RAW IMAGE LOADING", 46, 226, 30, raylib.Brown) + rl.DrawText("CHECKED TEXTURE ", 84, 100, 30, rl.Brown) + rl.DrawText("GENERATED by CODE", 72, 164, 30, rl.Brown) + rl.DrawText("and RAW IMAGE LOADING", 46, 226, 30, rl.Brown) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(fudesumi) // Texture unloading - raylib.UnloadTexture(checked) // Texture unloading + rl.UnloadTexture(fudesumi) // Texture unloading + //rl.UnloadTexture(checked) // Texture unloading - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/rectangle/main.go b/examples/textures/rectangle/main.go deleted file mode 100644 index 158f178..0000000 --- a/examples/textures/rectangle/main.go +++ /dev/null @@ -1,87 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/gen2brain/raylib-go/raylib" -) - -const ( - maxFrameSpeed = 15 - minFrameSpeed = 1 -) - -func main() { - screenWidth := int32(800) - screenHeight := int32(450) - - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") - - // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - scarfy := raylib.LoadTexture("scarfy.png") // Texture loading - - position := raylib.NewVector2(350.0, 280.0) - frameRec := raylib.NewRectangle(0, 0, float32(scarfy.Width/6), float32(scarfy.Height)) - currentFrame := float32(0) - - framesCounter := 0 - framesSpeed := 8 // Number of spritesheet frames shown by second - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - framesCounter++ - - if framesCounter >= (60 / framesSpeed) { - framesCounter = 0 - currentFrame++ - - if currentFrame > 5 { - currentFrame = 0 - } - - frameRec.X = currentFrame * float32(scarfy.Width) / 6 - } - - if raylib.IsKeyPressed(raylib.KeyRight) { - framesSpeed++ - } else if raylib.IsKeyPressed(raylib.KeyLeft) { - framesSpeed-- - } - - if framesSpeed > maxFrameSpeed { - framesSpeed = maxFrameSpeed - } else if framesSpeed < minFrameSpeed { - framesSpeed = minFrameSpeed - } - - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.DrawTexture(scarfy, 15, 40, raylib.White) - raylib.DrawRectangleLines(15, 40, scarfy.Width, scarfy.Height, raylib.Lime) - raylib.DrawRectangleLines(15+int32(frameRec.X), 40+int32(frameRec.Y), int32(frameRec.Width), int32(frameRec.Height), raylib.Red) - - raylib.DrawText("FRAME SPEED: ", 165, 210, 10, raylib.DarkGray) - raylib.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, raylib.DarkGray) - raylib.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, raylib.DarkGray) - - for i := 0; i < maxFrameSpeed; i++ { - if i < framesSpeed { - raylib.DrawRectangle(int32(250+21*i), 205, 20, 20, raylib.Red) - } - raylib.DrawRectangleLines(int32(250+21*i), 205, 20, 20, raylib.Maroon) - } - - raylib.DrawTextureRec(scarfy, frameRec, position, raylib.White) // Draw part of the texture - - raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray) - - raylib.EndDrawing() - } - - raylib.UnloadTexture(scarfy) - - raylib.CloseWindow() -} diff --git a/examples/textures/sprite_button/button.png b/examples/textures/sprite_button/button.png new file mode 100644 index 0000000..99a383b Binary files /dev/null and b/examples/textures/sprite_button/button.png differ diff --git a/examples/textures/sprite_button/buttonfx.wav b/examples/textures/sprite_button/buttonfx.wav new file mode 100644 index 0000000..b93b0ca Binary files /dev/null and b/examples/textures/sprite_button/buttonfx.wav differ diff --git a/examples/textures/sprite_button/main.go b/examples/textures/sprite_button/main.go new file mode 100644 index 0000000..dc685e8 --- /dev/null +++ b/examples/textures/sprite_button/main.go @@ -0,0 +1,94 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..fd18137 Binary files /dev/null and b/examples/textures/sprite_explosion/boom.wav differ diff --git a/examples/textures/sprite_explosion/explosion.png b/examples/textures/sprite_explosion/explosion.png new file mode 100644 index 0000000..6df1cf3 Binary files /dev/null and b/examples/textures/sprite_explosion/explosion.png differ diff --git a/examples/textures/sprite_explosion/main.go b/examples/textures/sprite_explosion/main.go new file mode 100644 index 0000000..8cd487f --- /dev/null +++ b/examples/textures/sprite_explosion/main.go @@ -0,0 +1,82 @@ +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 92ab73b..c51181a 100644 --- a/examples/textures/srcrec_dstrec/main.go +++ b/examples/textures/srcrec_dstrec/main.go @@ -1,59 +1,55 @@ package main -import ( - "github.com/gen2brain/raylib-go/raylib" -) - func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] examples - texture source and destination rectangles") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] examples - texture source and destination rectangles") // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) - scarfy := raylib.LoadTexture("scarfy.png") // Texture loading + scarfy := rl.LoadTexture("scarfy.png") // Texture loading frameWidth := float32(scarfy.Width) / 7 frameHeight := float32(scarfy.Height) // NOTE: Source rectangle (part of the texture to use for drawing) - sourceRec := raylib.NewRectangle(0, 0, frameWidth, frameHeight) + sourceRec := rl.NewRectangle(0, 0, frameWidth, frameHeight) // NOTE: Destination rectangle (screen rectangle where drawing part of texture) - destRec := raylib.NewRectangle(float32(screenWidth)/2, float32(screenHeight)/2, frameWidth*2, frameHeight*2) + destRec := rl.NewRectangle(float32(screenWidth)/2, float32(screenHeight)/2, frameWidth*2, frameHeight*2) // NOTE: Origin of the texture (rotation/scale point), it's relative to destination rectangle size - origin := raylib.NewVector2(float32(frameWidth), float32(frameHeight)) + origin := rl.NewVector2(float32(frameWidth), float32(frameHeight)) rotation := float32(0) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { + for !rl.WindowShouldClose() { // Update rotation++ // Draw - raylib.BeginDrawing() + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) // NOTE: Using DrawTexturePro() we can easily rotate and scale the part of the texture we draw // sourceRec defines the part of the texture we use for drawing // destRec defines the rectangle where our texture part will fit (scaling it to fit) // origin defines the point of the texture used as reference for rotation and scaling // rotation defines the texture rotation (using origin as rotation point) - raylib.DrawTexturePro(scarfy, sourceRec, destRec, origin, rotation, raylib.White) + rl.DrawTexturePro(scarfy, sourceRec, destRec, origin, rotation, rl.White) - raylib.DrawLine(int32(destRec.X), 0, int32(destRec.X), screenHeight, raylib.Gray) - raylib.DrawLine(0, int32(destRec.Y), screenWidth, int32(destRec.Y), raylib.Gray) + rl.DrawLine(int32(destRec.X), 0, int32(destRec.X), screenHeight, rl.Gray) + rl.DrawLine(0, int32(destRec.Y), screenWidth, int32(destRec.Y), rl.Gray) - raylib.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, raylib.Gray) + rl.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(scarfy) + rl.UnloadTexture(scarfy) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/examples/textures/textured_curve/main.go b/examples/textures/textured_curve/main.go new file mode 100644 index 0000000..67f0914 --- /dev/null +++ b/examples/textures/textured_curve/main.go @@ -0,0 +1,201 @@ +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 new file mode 100644 index 0000000..082f4cd Binary files /dev/null and b/examples/textures/textured_curve/road.png differ diff --git a/examples/textures/textures_gif_player/main.go b/examples/textures/textures_gif_player/main.go new file mode 100644 index 0000000..51d1275 --- /dev/null +++ b/examples/textures/textures_gif_player/main.go @@ -0,0 +1,113 @@ +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 new file mode 100644 index 0000000..f0f712c Binary files /dev/null and b/examples/textures/textures_gif_player/scarfy_run.gif differ diff --git a/examples/textures/textures_sprite_anim/main.go b/examples/textures/textures_sprite_anim/main.go new file mode 100644 index 0000000..dfa715d --- /dev/null +++ b/examples/textures/textures_sprite_anim/main.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + + "git.terah.dev/UnrealXR/raylib-go/raylib" +) + +const ( + maxFrameSpeed = 15 + minFrameSpeed = 1 +) + +func main() { + screenWidth := int32(800) + screenHeight := int32(450) + + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture loading and drawing") + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required) + scarfy := rl.LoadTexture("scarfy.png") // Texture loading + + position := rl.NewVector2(350.0, 280.0) + frameRec := rl.NewRectangle(0, 0, float32(scarfy.Width/6), float32(scarfy.Height)) + currentFrame := float32(0) + + framesCounter := 0 + framesSpeed := 8 // Number of spritesheet frames shown by second + + rl.SetTargetFPS(60) + + for !rl.WindowShouldClose() { + framesCounter++ + + if framesCounter >= (60 / framesSpeed) { + framesCounter = 0 + currentFrame++ + + if currentFrame > 5 { + currentFrame = 0 + } + + frameRec.X = currentFrame * float32(scarfy.Width) / 6 + } + + if rl.IsKeyPressed(rl.KeyRight) { + framesSpeed++ + } else if rl.IsKeyPressed(rl.KeyLeft) { + framesSpeed-- + } + + if framesSpeed > maxFrameSpeed { + framesSpeed = maxFrameSpeed + } else if framesSpeed < minFrameSpeed { + framesSpeed = minFrameSpeed + } + + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.DrawTexture(scarfy, 15, 40, rl.White) + rl.DrawRectangleLines(15, 40, scarfy.Width, scarfy.Height, rl.Lime) + rl.DrawRectangleLines(15+int32(frameRec.X), 40+int32(frameRec.Y), int32(frameRec.Width), int32(frameRec.Height), rl.Red) + + rl.DrawText("FRAME SPEED: ", 165, 210, 10, rl.DarkGray) + rl.DrawText(fmt.Sprintf("%02d FPS", framesSpeed), 575, 210, 10, rl.DarkGray) + rl.DrawText("PRESS RIGHT/LEFT KEYS to CHANGE SPEED!", 290, 240, 10, rl.DarkGray) + + for i := 0; i < maxFrameSpeed; i++ { + if i < framesSpeed { + rl.DrawRectangle(int32(250+21*i), 205, 20, 20, rl.Red) + } + rl.DrawRectangleLines(int32(250+21*i), 205, 20, 20, rl.Maroon) + } + + rl.DrawTextureRec(scarfy, frameRec, position, rl.White) // Draw part of the texture + + rl.DrawText("(c) Scarfy sprite by Eiden Marsal", screenWidth-200, screenHeight-20, 10, rl.Gray) + + rl.EndDrawing() + } + + rl.UnloadTexture(scarfy) + + rl.CloseWindow() +} diff --git a/examples/textures/rectangle/scarfy.png b/examples/textures/textures_sprite_anim/scarfy.png similarity index 100% rename from examples/textures/rectangle/scarfy.png rename to examples/textures/textures_sprite_anim/scarfy.png diff --git a/examples/textures/to_image/main.go b/examples/textures/to_image/main.go index 56ef9da..a65d4d1 100644 --- a/examples/textures/to_image/main.go +++ b/examples/textures/to_image/main.go @@ -1,39 +1,39 @@ package main import ( - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) func main() { screenWidth := int32(800) screenHeight := int32(450) - raylib.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture to image") + rl.InitWindow(screenWidth, screenHeight, "raylib [textures] example - texture to image") - image := raylib.LoadImage("raylib_logo.png") // Load image data into CPU memory (RAM) - texture := raylib.LoadTextureFromImage(image) // Image converted to texture, GPU memory (RAM -> VRAM) - raylib.UnloadImage(image) // Unload image data from CPU memory (RAM) + image := rl.LoadImage("raylib_logo.png") // Load image data into CPU memory (RAM) + texture := rl.LoadTextureFromImage(image) // Image converted to texture, GPU memory (RAM -> VRAM) + rl.UnloadImage(image) // Unload image data from CPU memory (RAM) - image = raylib.GetTextureData(texture) // Retrieve image data from GPU memory (VRAM -> RAM) - raylib.UnloadTexture(texture) // Unload texture from GPU memory (VRAM) + image = rl.LoadImageFromTexture(texture) // Retrieve image data from GPU memory (VRAM -> RAM) + rl.UnloadTexture(texture) // Unload texture from GPU memory (VRAM) - texture = raylib.LoadTextureFromImage(image) // Recreate texture from retrieved image data (RAM -> VRAM) - raylib.UnloadImage(image) // Unload retrieved image data from CPU memory (RAM) + texture = rl.LoadTextureFromImage(image) // Recreate texture from retrieved image data (RAM -> VRAM) + rl.UnloadImage(image) // Unload retrieved image data from CPU memory (RAM) - raylib.SetTargetFPS(60) + rl.SetTargetFPS(60) - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() + for !rl.WindowShouldClose() { + rl.BeginDrawing() - raylib.ClearBackground(raylib.RayWhite) + rl.ClearBackground(rl.RayWhite) - raylib.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, raylib.White) - raylib.DrawText("this IS a texture loaded from an image!", 300, 370, 10, raylib.Gray) + rl.DrawTexture(texture, screenWidth/2-texture.Width/2, screenHeight/2-texture.Height/2, rl.White) + rl.DrawText("this IS a texture loaded from an image!", 300, 370, 10, rl.Gray) - raylib.EndDrawing() + rl.EndDrawing() } - raylib.UnloadTexture(texture) + rl.UnloadTexture(texture) - raylib.CloseWindow() + rl.CloseWindow() } diff --git a/physics/README.md b/physics/README.md index b86c883..851f199 100644 --- a/physics/README.md +++ b/physics/README.md @@ -1,5 +1,5 @@ -## physics [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/physics?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/physics) +## physics [![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/physics?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/raylib-go/physics) 2D Physics library for videogames. -A port of Victor Fisac's [physac engine](https://github.com/raysan5/raylib/blob/master/src/physac.h). +A port of Victor Fisac's [physac engine](https://github.com/raysan5/physac/blob/master/src/physac.h). diff --git a/physics/go.mod b/physics/go.mod new file mode 100644 index 0000000..67b71a1 --- /dev/null +++ b/physics/go.mod @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..62eb5f5 --- /dev/null +++ b/physics/go.sum @@ -0,0 +1,8 @@ +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 2d80f7a..0e57c95 100644 --- a/physics/physics.go +++ b/physics/physics.go @@ -5,9 +5,10 @@ package physics import ( "math" + "math/rand" + "time" - "github.com/gen2brain/raylib-go/raylib" - "github.com/gen2brain/raylib-go/raymath" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) // ShapeType type @@ -26,11 +27,9 @@ type Polygon struct { // Current used vertex and normals count VertexCount int // Polygon vertex positions vectors - Vertices [maxVertices]raylib.Vector2 + Positions [maxVertices]rl.Vector2 // Polygon vertex normals vectors - Normals [maxVertices]raylib.Vector2 - // Vertices transform matrix 2x2 - Transform raylib.Mat2 + Normals [maxVertices]rl.Vector2 } // Shape type @@ -41,20 +40,24 @@ 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 - Position raylib.Vector2 + Position rl.Vector2 // Current linear velocity applied to position - Velocity raylib.Vector2 + Velocity rl.Vector2 // Current linear force (reset to 0 every step) - Force raylib.Vector2 + Force rl.Vector2 // Current angular velocity applied to orient AngularVelocity float32 // Current angular force (reset to 0 every step) @@ -85,8 +88,10 @@ type Body struct { Shape Shape } -// manifold type -type manifold struct { +// Manifold type +type Manifold struct { + // Reference unique identifier + ID int // Manifold first physics body reference BodyA *Body // Manifold second physics body reference @@ -94,9 +99,9 @@ type manifold struct { // Depth of penetration from collision Penetration float32 // Normal direction vector from 'a' to 'b' - Normal raylib.Vector2 + Normal rl.Vector2 // Points of contact during collision - Contacts [2]raylib.Vector2 + Contacts [2]rl.Vector2 // Current collision number of contacts ContactsCount int // Mixed restitution during collision @@ -109,9 +114,8 @@ type manifold struct { // Constants const ( - maxBodies = 64 - maxManifolds = 4096 - + maxBodies = 64 + maxManifolds = 4096 maxVertices = 24 circleVertices = 24 @@ -119,31 +123,51 @@ const ( penetrationAllowance = 0.05 penetrationCorrection = 0.4 - fltMax = 3.402823466 + 38 - epsilon = 0.000001 + degToRad = math.Pi / 180 + epsilon = 0.000001 + physacK = 1.0 / 3.0 ) // Globals var ( - // Physics bodies pointers - bodies []*Body + // Offset time for MONOTONIC clock + baseTime = time.Now() - // Physics manifolds pointers - manifolds []*manifold + // 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 world gravity force - gravityForce raylib.Vector2 + gravityForce = rl.NewVector2(0, 9.81) - // Delta time used for physics steps - deltaTime float32 + // 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 ) -// Init - initializes physics values +// Init - Initializes physics values, pointers and creates physics loop thread func Init() { - gravityForce = raylib.NewVector2(0, 9.81/1000) - - bodies = make([]*Body, 0, maxBodies) - manifolds = make([]*manifold, 0, maxManifolds) + initTimer() + accumulator = 0 } // SetGravity - Sets physics global gravity force @@ -153,135 +177,103 @@ func SetGravity(x, y float32) { } // NewBodyCircle - Creates a new circle physics body with generic parameters -func NewBodyCircle(pos raylib.Vector2, radius, density float32) *Body { - return NewBodyPolygon(pos, radius, circleVertices, density) +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 } // NewBodyRectangle - Creates a new rectangle physics body with generic parameters -func NewBodyRectangle(pos raylib.Vector2, width, height, density float32) *Body { - newBody := &Body{} +func NewBodyRectangle(pos rl.Vector2, width, height, density float32) *Body { + newID := findAvailableBodyIndex() + if newID < 0 { + return nil + } // Initialize new body with generic values - newBody.Enabled = true - newBody.Position = pos - newBody.Velocity = raylib.Vector2{} - newBody.Force = raylib.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, raylib.NewVector2(width, height)) + 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, + } // Calculate centroid and moment of inertia - center := raylib.Vector2{} + newBody.Shape.Body = newBody + var 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) - p1 := newBody.Shape.VertexData.Vertices[i] - nextIndex := 0 - if i+1 < newBody.Shape.VertexData.VertexCount { - nextIndex = i + 1 - } - p2 := newBody.Shape.VertexData.Vertices[nextIndex] + nextIndex := getNextIndex(i, newBody.Shape.VertexData.VertexCount) + p1 := newBody.Shape.VertexData.Positions[i] + p2 := newBody.Shape.VertexData.Positions[nextIndex] - D := raymath.Vector2CrossProduct(p1, p2) + 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) + 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 * 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 - for i := 0; i < newBody.Shape.VertexData.VertexCount; i++ { - newBody.Shape.VertexData.Vertices[i].X -= center.X - newBody.Shape.VertexData.Vertices[i].Y -= center.Y - } - - newBody.Mass = density * area - newBody.Inertia = density * 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) - - return newBody -} - -// NewBodyPolygon - Creates a new polygon physics body with generic parameters -func NewBodyPolygon(pos raylib.Vector2, radius float32, sides int, density float32) *Body { - newBody := &Body{} - - // Initialize new body with generic values - newBody.Enabled = true - newBody.Position = pos - newBody.Velocity = raylib.Vector2{} - newBody.Force = raylib.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 - center := raylib.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) - 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 := raymath.Vector2CrossProduct(position1, position2) - triangleArea := cross / 2 - - area += triangleArea - - // Use area to weight the centroid average, not just vertex position - 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 * alpha * cross) * (intx2 + inty2) + 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) } center.X *= 1.0 / area @@ -290,247 +282,140 @@ func NewBodyPolygon(pos raylib.Vector2, radius float32, sides int, density float // 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.Vertices[i].X -= center.X - newBody.Shape.VertexData.Vertices[i].Y -= center.Y + newBody.Shape.VertexData.Positions[i].X -= center.X + newBody.Shape.VertexData.Positions[i].Y -= center.Y } newBody.Mass = density * area + newBody.InverseMass = safeDiv(1.0, newBody.Mass) newBody.Inertia = density * 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) + newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) + // 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 { - raylib.TraceLog(raylib.LogDebug, "[PHYSAC] physics body index is out of bounds") +// 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 } - 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 { - raylib.TraceLog(raylib.LogDebug, "[PHYSAC] physics body index is out of bounds") + // 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, } - return result -} + newBody.Shape.Body = newBody -// GetShapeVerticesCount - Returns the amount of vertices of a physics body shape -func GetShapeVerticesCount(index int) int { - result := 0 + // Calculate centroid and moment of inertia + var center rl.Vector2 + area := float32(0.0) + inertia := float32(0.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 { - raylib.TraceLog(raylib.LogDebug, "[PHYSAC] physics body index is out of bounds") + 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] + + cross := rl.Vector2CrossProduct(position1, position2) + triangleArea := cross / 2 + + 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) + + 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) } - return result -} + center.X *= 1.0 / area + center.Y *= 1.0 / area -// 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 - } + // 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 } - return false -} + newBody.Mass = density * area + newBody.InverseMass = safeDiv(1.0, newBody.Mass) + newBody.Inertia = density * inertia + newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) -// Update - Physics steps calculations (dynamics, collisions and position corrections) -func Update() { - deltaTime = raylib.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 = raylib.Vector2{} - b.Torque = 0 - } + // Add new body to bodies pointers array and update bodies count + bodies[bodiesCount] = newBody + bodiesCount++ + return newBody } // Reset - Destroys created physics bodies and manifolds func Reset() { - 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) - } + Close() } // AddForce - Adds a force to a physics body -func (b *Body) AddForce(force raylib.Vector2) { - b.Force = raymath.Vector2Add(b.Force, force) +func AddForce(body *Body, force rl.Vector2) { + if body != nil { + body.Force = rl.Vector2Add(body.Force, force) + } } // AddTorque - Adds an angular force to a physics body -func (b *Body) AddTorque(amount float32) { - b.Torque += amount +func AddTorque(body *Body, amount float32) { + if body != nil { + body.Torque += amount + } } // Shatter - Shatters a polygon shape physics body to little physics bodies with explosion force -func (b *Body) Shatter(position raylib.Vector2, force float32) { - if b.Shape.Type != PolygonShape { +func Shatter(body *Body, position rl.Vector2, force float32) { + if body == nil || body.Shape.Type != PolygonShape { return } - vertexData := b.Shape.VertexData + vertexData := body.Shape.VertexData collision := false for i := 0; i < vertexData.VertexCount; i++ { - positionA := b.Position - positionB := raymath.Mat2MultiplyVector2(vertexData.Transform, raymath.Vector2Add(b.Position, vertexData.Vertices[i])) - - nextIndex := 0 - if i+1 < vertexData.VertexCount { - nextIndex = i + 1 - } - - positionC := raymath.Mat2MultiplyVector2(vertexData.Transform, raymath.Vector2Add(b.Position, vertexData.Vertices[nextIndex])) + 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])) // Check collision between each triangle - 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)) - + 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)) gamma := 1.0 - alpha - beta if alpha > 0 && beta > 0 && gamma > 0 { @@ -539,361 +424,594 @@ func (b *Body) Shatter(position raylib.Vector2, force float32) { } } - if collision { - count := vertexData.VertexCount - bodyPos := b.Position + if !collision { + return + } - vertices := make([]raylib.Vector2, count) - trans := vertexData.Transform - for i := 0; i < count; i++ { - vertices[i] = vertexData.Vertices[i] + 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]) } - // Destroy shattered physics body - DestroyBody(b) + // Apply computed vertex data to new physics body shape + newBody.Shape.VertexData = newData + newBody.Shape.Transform = trans - for i := 0; i < count; i++ { - nextIndex := 0 - if i+1 < count { - nextIndex = i + 1 - } + // Calculate centroid and moment of inertia + center = rl.Vector2{} + area := float32(0.0) + inertia := float32(0.0) - center := triangleBarycenter(vertices[i], vertices[nextIndex], raylib.NewVector2(0, 0)) - center = raymath.Vector2Add(bodyPos, center) - offset := raymath.Vector2Subtract(center, bodyPos) + 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] - newBody := NewBodyPolygon(center, 10, 3, 10) // Create polygon physics body with relevant values + D := rl.Vector2CrossProduct(p1, p2) + triangleArea := D / 2 - newData := Polygon{} - newData.VertexCount = 3 - newData.Transform = trans + area += triangleArea - newData.Vertices[0] = raymath.Vector2Subtract(vertices[i], offset) - newData.Vertices[1] = raymath.Vector2Subtract(vertices[nextIndex], offset) - newData.Vertices[2] = raymath.Vector2Subtract(position, center) + // 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) - // 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 + 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 + } - // Calculate polygon faces normals - for j := 0; j < newData.VertexCount; j++ { - nextVertex := 0 - if j+1 < newData.VertexCount { - nextVertex = j + 1 - } + center.X *= 1.0 / area + center.Y *= 1.0 / area - face := raymath.Vector2Subtract(newData.Vertices[nextVertex], newData.Vertices[j]) + newBody.Mass = area + newBody.InverseMass = safeDiv(1.0, newBody.Mass) + newBody.Inertia = inertia + newBody.InverseInertia = safeDiv(1.0, newBody.Inertia) - newData.Normals[j] = raylib.NewVector2(face.Y, -face.X) - normalize(&newData.Normals[j]) - } + // 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 computed vertex data to new physics body shape - newBody.Shape.VertexData = newData + // Apply force to new physics body + AddForce(newBody, forceDirection) + } +} - // Calculate centroid and moment of inertia - center = raylib.NewVector2(0, 0) - area := float32(0.0) - inertia := float32(0.0) - k := float32(1.0) / 3.0 +// GetBodies - Returns the slice of created physics bodies +func GetBodies() []*Body { + return bodies[:bodiesCount] +} - 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] +// GetBodiesCount - Returns the current amount of created physics bodies +func GetBodiesCount() int { + return bodiesCount +} - D := raymath.Vector2CrossProduct(p1, p2) - triangleArea := D / 2 +// GetBody - Returns a physics body of the bodies pool at a specific index +func GetBody(index int) *Body { + return bodies[index] +} - 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 := raymath.Vector2Subtract(newData.Vertices[1], newData.Vertices[0]) - pointB.X /= 2 - pointB.Y /= 2 - forceDirection := raymath.Vector2Subtract(raymath.Vector2Add(pointA, raymath.Vector2Add(newData.Vertices[0], pointB)), newBody.Position) - normalize(&forceDirection) - forceDirection.X *= force - forceDirection.Y *= force - - // Apply force to new physics body - newBody.AddForce(forceDirection) +// 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: + } + } + } + return result } // GetShapeVertex - Returns transformed position of a body shape (body position + vertex transformed position) -func (b *Body) GetShapeVertex(vertex int) raylib.Vector2 { - position := raylib.Vector2{} +func (b *Body) GetShapeVertex(vertex int) rl.Vector2 { + var position rl.Vector2 switch b.Shape.Type { case CircleShape: - position.X = b.Position.X + float32(math.Cos(360/float64(circleVertices)*float64(vertex)*raylib.Deg2rad))*b.Shape.Radius - position.Y = b.Position.Y + float32(math.Sin(360/float64(circleVertices)*float64(vertex)*raylib.Deg2rad))*b.Shape.Radius - break + 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 case PolygonShape: - position = raymath.Vector2Add(b.Position, raymath.Mat2MultiplyVector2(b.Shape.VertexData.Transform, b.Shape.VertexData.Vertices[vertex])) - break + position = rl.Vector2Add( + b.Position, + rl.Mat2MultiplyVector2(b.Shape.Transform, b.Shape.VertexData.Positions[vertex]), + ) } - return position } -// SetRotation - Sets physics body shape transform based on radians parameter +// SetBodyRotation - 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.VertexData.Transform = raymath.Mat2Radians(radians) + b.Shape.Transform = rl.Mat2Radians(radians) } } -// integrateVelocity - Integrates physics velocity into position and forces -func (b *Body) integrateVelocity() { - if !b.Enabled { +// 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 { return } - b.Position.X += b.Velocity.X * deltaTime - b.Position.Y += b.Velocity.Y * deltaTime + bodies[index] = nil - if !b.FreezeOrient { - b.Orient += b.AngularVelocity * deltaTime + // Reorder physics bodies pointers array and its catched index + for i := index; i+1 < bodiesCount; i++ { + bodies[i] = bodies[i+1] } - raymath.Mat2Set(&b.Shape.VertexData.Transform, b.Orient) - - b.integrateForces() + // Update physics bodies count + bodiesCount-- } -// integrateForces - Integrates physics forces into velocity -func (b *Body) integrateForces() { - if b.InverseMass == 0 || !b.Enabled { - return +// Close - Unitializes physics pointers +func Close() { + // Unitialize physics manifolds dynamic memory allocations + for i := manifoldsCount - 1; i >= 0; i-- { + destroyManifold(manifolds[i]) } - 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 / 2) - b.Velocity.Y += gravityForce.Y * (deltaTime / 2) - } - - if !b.FreezeOrient { - b.AngularVelocity += b.Torque * b.InverseInertia * (deltaTime / 2) + // Unitialize physics bodies dynamic memory allocations + for i := bodiesCount - 1; i >= 0; i-- { + bodies[i].Destroy() } } -// newRandomPolygon - Creates a random polygon shape with max vertex distance from polygon pivot -func newRandomPolygon(radius float32, sides int) Polygon { - data := Polygon{} +// 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{} data.VertexCount = sides - orient := raylib.GetRandomValue(0, 360) - data.Transform = raymath.Mat2Radians(float32(orient) * raylib.Deg2rad) - // Calculate polygon vertices positions for i := 0; i < data.VertexCount; i++ { - data.Vertices[i].X = float32(math.Cos(360/float64(sides)*float64(i)*raylib.Deg2rad)) * radius - data.Vertices[i].Y = float32(math.Sin(360/float64(sides)*float64(i)*raylib.Deg2rad)) * radius + 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 } // Calculate polygon faces normals for i := 0; i < data.VertexCount; i++ { - nextIndex := 0 - if i+1 < sides { - nextIndex = i + 1 - } + nextIndex := getNextIndex(i, sides) + face := rl.Vector2Subtract(data.Positions[nextIndex], data.Positions[i]) - face := raymath.Vector2Subtract(data.Vertices[nextIndex], data.Vertices[i]) - - data.Normals[i] = raylib.NewVector2(face.Y, -face.X) + data.Normals[i] = rl.NewVector2(face.Y, -face.X) normalize(&data.Normals[i]) } return data } -// newRectanglePolygon - Creates a rectangle polygon shape based on a min and max positions -func newRectanglePolygon(pos, size raylib.Vector2) Polygon { - data := Polygon{} - +// 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{} data.VertexCount = 4 - data.Transform = raymath.Mat2Radians(0) // Calculate polygon vertices positions - data.Vertices[0] = raylib.NewVector2(pos.X+size.X/2, pos.Y-size.Y/2) - data.Vertices[1] = raylib.NewVector2(pos.X+size.X/2, pos.Y+size.Y/2) - data.Vertices[2] = raylib.NewVector2(pos.X-size.X/2, pos.Y+size.Y/2) - data.Vertices[3] = raylib.NewVector2(pos.X-size.X/2, pos.Y-size.Y/2) + 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) // Calculate polygon faces normals for i := 0; i < data.VertexCount; i++ { - nextIndex := 0 - if i+1 < data.VertexCount { - nextIndex = i + 1 - } - face := raymath.Vector2Subtract(data.Vertices[nextIndex], data.Vertices[i]) + nextIndex := getNextIndex(i, data.VertexCount) + face := rl.Vector2Subtract(data.Positions[nextIndex], data.Positions[i]) - data.Normals[i] = raylib.NewVector2(face.Y, -face.X) + data.Normals[i] = rl.NewVector2(face.Y, -face.X) normalize(&data.Normals[i]) } return data } -// newManifold - Creates a new physics manifold to solve collision -func newManifold(a, b *Body) *manifold { - newManifold := &manifold{} +// 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 + } // Initialize new manifold with generic values - newManifold.BodyA = a - newManifold.BodyB = b - newManifold.Penetration = 0 - newManifold.Normal = raylib.Vector2{} - newManifold.Contacts[0] = raylib.Vector2{} - newManifold.Contacts[1] = raylib.Vector2{} - newManifold.ContactsCount = 0 - newManifold.Restitution = 0 - newManifold.DynamicFriction = 0 - newManifold.StaticFriction = 0 + 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, + } - // Add new manifold to manifolds pointers - manifolds = append(manifolds, newManifold) + // Add new contact to conctas pointers array and update contacts count + manifolds[manifoldsCount] = newManifold + manifoldsCount++ return newManifold } // destroyManifold - Unitializes and destroys a physics manifold -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 +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] } } - return false + // Update physics manifolds count + manifoldsCount-- } // solveManifold - Solves a created physics manifold between two physics bodies -func (m *manifold) solveManifold() { - switch m.BodyA.Shape.Type { +func solveManifold(manifold *Manifold) { + switch manifold.BodyA.Shape.Type { case CircleShape: - switch m.BodyB.Shape.Type { + switch manifold.BodyB.Shape.Type { case CircleShape: - m.solveCircleToCircle() - break + solveCircleToCircle(manifold) case PolygonShape: - m.solveCircleToPolygon() - break + solveCircleToPolygon(manifold) } case PolygonShape: - switch m.BodyB.Shape.Type { + switch manifold.BodyB.Shape.Type { case CircleShape: - m.solvePolygonToCircle() - break + solvePolygonToCircle(manifold) case PolygonShape: - m.solvePolygonToPolygon() - break + solvePolygonToPolygon(manifold) } } - // 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) + // 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 } } // solveCircleToCircle - Solves collision between two circle shape physics bodies -func (m *manifold) solveCircleToCircle() { - bodyA := m.BodyA - bodyB := m.BodyB +func solveCircleToCircle(manifold *Manifold) { + bodyA, bodyB := manifold.BodyA, manifold.BodyB + if bodyA == nil || bodyB == nil { + return + } // Calculate translational vector, which is normal - normal := raymath.Vector2Subtract(bodyB.Position, bodyA.Position) + var normal rl.Vector2 = rl.Vector2Subtract(bodyB.Position, bodyA.Position) - distSqr := raymath.Vector2LenSqr(normal) + distSqr := rl.Vector2LenSqr(normal) radius := bodyA.Shape.Radius + bodyB.Shape.Radius // Check if circles are not in contact if distSqr >= radius*radius { - m.ContactsCount = 0 + manifold.ContactsCount = 0 return } distance := float32(math.Sqrt(float64(distSqr))) - m.ContactsCount = 1 - + manifold.ContactsCount = 1 if distance == 0 { - m.Penetration = bodyA.Shape.Radius - m.Normal = raylib.NewVector2(1, 0) - m.Contacts[0] = bodyA.Position + manifold.Penetration = bodyA.Shape.Radius + manifold.Normal = rl.NewVector2(1, 0) + manifold.Contacts[0] = bodyA.Position } else { - m.Penetration = radius - distance - m.Normal = raylib.NewVector2(normal.X/distance, normal.Y/distance) // Faster than using normalize() due to sqrt is already performed - m.Contacts[0] = raylib.NewVector2(m.Normal.X*bodyA.Shape.Radius+bodyA.Position.X, m.Normal.Y*bodyA.Shape.Radius+bodyA.Position.Y) + 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, + ) } // Update physics body grounded state if normal direction is down if !bodyA.IsGrounded { - bodyA.IsGrounded = (m.Normal.Y < 0) + bodyA.IsGrounded = manifold.Normal.Y < 0 } } // solveCircleToPolygon - Solves collision between a circle to a polygon shape physics bodies -func (m *manifold) solveCircleToPolygon() { - m.ContactsCount = 0 +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 // Transform circle center to polygon transform space - center := m.BodyA.Position - center = raymath.Mat2MultiplyVector2(raymath.Mat2Transpose(m.BodyB.Shape.VertexData.Transform), raymath.Vector2Subtract(center, m.BodyB.Position)) + center := rl.Mat2MultiplyVector2( + rl.Mat2Transpose(bodyB.Shape.Transform), + rl.Vector2Subtract(bodyA.Position, bodyB.Position), + ) // Find edge with minimum penetration - // It is the same concept as using support points in solvePolygonToPolygon - separation := float32(-fltMax) + // It is the same concept as using support points in SolvePolygonToPolygon + separation := float32(-math.MaxFloat32) faceNormal := 0 - vertexData := m.BodyB.Shape.VertexData + vertexData := bodyB.Shape.VertexData for i := 0; i < vertexData.VertexCount; i++ { - currentSeparation := raymath.Vector2DotProduct(vertexData.Normals[i], raymath.Vector2Subtract(center, vertexData.Vertices[i])) + currentSeparation := rl.Vector2DotProduct( + vertexData.Normals[i], + rl.Vector2Subtract(center, vertexData.Positions[i]), + ) - if currentSeparation > m.BodyA.Shape.Radius { + if currentSeparation > bodyA.Shape.Radius { return } @@ -904,96 +1022,92 @@ func (m *manifold) solveCircleToPolygon() { } // Grab face's vertices - v1 := vertexData.Vertices[faceNormal] - nextIndex := 0 - if faceNormal+1 < vertexData.VertexCount { - nextIndex = faceNormal + 1 - } - v2 := vertexData.Vertices[nextIndex] + nextIndex := getNextIndex(faceNormal, vertexData.VertexCount) + v1 := vertexData.Positions[faceNormal] + v2 := vertexData.Positions[nextIndex] // Check to see if center is within polygon if separation < epsilon { - m.ContactsCount = 1 - normal := raymath.Mat2MultiplyVector2(vertexData.Transform, vertexData.Normals[faceNormal]) - m.Normal = raylib.NewVector2(-normal.X, -normal.Y) - m.Contacts[0] = raylib.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 + 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 return } // Determine which voronoi region of the edge center of circle lies within - dot1 := raymath.Vector2DotProduct(raymath.Vector2Subtract(center, v1), raymath.Vector2Subtract(v2, v1)) - dot2 := raymath.Vector2DotProduct(raymath.Vector2Subtract(center, v2), raymath.Vector2Subtract(v1, v2)) - m.Penetration = m.BodyA.Shape.Radius - separation + 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 - if dot1 <= 0 { // Closest to v1 - if raymath.Vector2Distance(center, v1) > m.BodyA.Shape.Radius*m.BodyA.Shape.Radius { + switch { + case dot1 <= 0: // Closest to v1 + if rl.Vector2Distance(center, v1) > bodyA.Shape.Radius*bodyA.Shape.Radius { return } - m.ContactsCount = 1 - normal := raymath.Vector2Subtract(v1, center) - normal = raymath.Mat2MultiplyVector2(vertexData.Transform, normal) + manifold.ContactsCount = 1 + var normal rl.Vector2 = rl.Vector2Subtract(v1, center) + normal = rl.Mat2MultiplyVector2(bodyB.Shape.Transform, normal) normalize(&normal) - m.Normal = normal - v1 = raymath.Mat2MultiplyVector2(vertexData.Transform, v1) - v1 = raymath.Vector2Add(v1, m.BodyB.Position) - m.Contacts[0] = v1 - } else if dot2 <= 0 { // Closest to v2 - if raymath.Vector2Distance(center, v2) > m.BodyA.Shape.Radius*m.BodyA.Shape.Radius { + 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 { return } - m.ContactsCount = 1 - normal := raymath.Vector2Subtract(v2, center) - v2 = raymath.Mat2MultiplyVector2(vertexData.Transform, v2) - v2 = raymath.Vector2Add(v2, m.BodyB.Position) - m.Contacts[0] = v2 - normal = raymath.Mat2MultiplyVector2(vertexData.Transform, normal) + 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) normalize(&normal) - m.Normal = normal - } else { // Closest to face - normal := vertexData.Normals[faceNormal] + manifold.Normal = normal - if raymath.Vector2DotProduct(raymath.Vector2Subtract(center, v1), normal) > m.BodyA.Shape.Radius { + default: // Closest to face + var normal rl.Vector2 = vertexData.Normals[faceNormal] + + if rl.Vector2DotProduct(rl.Vector2Subtract(center, v1), normal) > bodyA.Shape.Radius { return } - normal = raymath.Mat2MultiplyVector2(vertexData.Transform, normal) - m.Normal = raylib.NewVector2(-normal.X, -normal.Y) - m.Contacts[0] = raylib.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 + 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 } } -// solvePolygonToCircle - Solves collision between a polygon to a circle shape physics bodies -func (m *manifold) solvePolygonToCircle() { - bodyA := m.BodyA - bodyB := m.BodyB - - 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 +func solvePolygonToPolygon(manifold *Manifold) { + bodyA, bodyB := manifold.BodyA, manifold.BodyB + if bodyA == nil || bodyB == nil { + return + } + + shapeA, shapeB := bodyA.Shape, bodyB.Shape + manifold.ContactsCount = 0 // Check for separating axis with A shape's face planes - faceA, penetrationA := findAxisLeastPenetration(bodyA, bodyB) + faceA, penetrationA := findAxisLeastPenetration(shapeA, shapeB) if penetrationA >= 0 { return } // Check for separating axis with B shape's face planes - faceB, penetrationB := findAxisLeastPenetration(bodyB, bodyA) + faceB, penetrationB := findAxisLeastPenetration(shapeB, shapeA) if penetrationB >= 0 { return } @@ -1001,192 +1115,230 @@ func (m *manifold) solvePolygonToPolygon() { referenceIndex := 0 flip := false // Always point from A shape to B shape - refPoly := Shape{} // Reference - incPoly := Shape{} // Incident + var refPoly Shape // Reference + var incPoly Shape // Incident // Determine which shape contains reference face if biasGreaterThan(penetrationA, penetrationB) { - refPoly = bodyA - incPoly = bodyB + refPoly = shapeA + incPoly = shapeB referenceIndex = faceA } else { - refPoly = bodyB - incPoly = bodyA + refPoly = shapeB + incPoly = shapeA referenceIndex = faceB flip = true } // World space incident face - incidentFace0 := raylib.Vector2{} - incidentFace1 := raylib.Vector2{} - findIncidentFace(&incidentFace0, &incidentFace1, refPoly, incPoly, referenceIndex) + var incidentFace [2]rl.Vector2 + findIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex) // Setup reference face vertices refData := refPoly.VertexData - v1 := refData.Vertices[referenceIndex] - if referenceIndex+1 < refData.VertexCount { - referenceIndex = referenceIndex + 1 - } else { - referenceIndex = 0 - } - v2 := refData.Vertices[referenceIndex] + v1 := refData.Positions[referenceIndex] + referenceIndex = getNextIndex(referenceIndex, refData.VertexCount) + v2 := refData.Positions[referenceIndex] // Transform vertices to world space - v1 = raymath.Mat2MultiplyVector2(refData.Transform, v1) - v1 = raymath.Vector2Add(v1, refPoly.Body.Position) - v2 = raymath.Mat2MultiplyVector2(refData.Transform, v2) - v2 = raymath.Vector2Add(v2, refPoly.Body.Position) + v1 = rl.Mat2MultiplyVector2(refPoly.Transform, v1) + v1 = rl.Vector2Add(v1, refPoly.Body.Position) + v2 = rl.Mat2MultiplyVector2(refPoly.Transform, v2) + v2 = rl.Vector2Add(v2, refPoly.Body.Position) // Calculate reference face side normal in world space - sidePlaneNormal := raymath.Vector2Subtract(v2, v1) + sidePlaneNormal := rl.Vector2Subtract(v2, v1) normalize(&sidePlaneNormal) // Orthogonalize - refFaceNormal := raylib.NewVector2(sidePlaneNormal.Y, -sidePlaneNormal.X) - refC := raymath.Vector2DotProduct(refFaceNormal, v1) - negSide := raymath.Vector2DotProduct(sidePlaneNormal, v1) * -1 - posSide := raymath.Vector2DotProduct(sidePlaneNormal, v2) + refFaceNormal := rl.NewVector2(sidePlaneNormal.Y, -sidePlaneNormal.X) + refC := rl.Vector2DotProduct(refFaceNormal, v1) + negSide := rl.Vector2DotProduct(sidePlaneNormal, v1) * float32(-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(raylib.NewVector2(-sidePlaneNormal.X, -sidePlaneNormal.Y), negSide, &incidentFace0, &incidentFace1) < 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, &incidentFace[0], &incidentFace[1]) < 2 { return } - if clip(sidePlaneNormal, posSide, &incidentFace0, &incidentFace1) < 2 { + + if clip(sidePlaneNormal, posSide, &incidentFace[0], &incidentFace[1]) < 2 { return } // Flip normal if required if flip { - m.Normal = raylib.NewVector2(-refFaceNormal.X, -refFaceNormal.Y) + manifold.Normal = rl.NewVector2(-refFaceNormal.X, -refFaceNormal.Y) } else { - m.Normal = refFaceNormal + manifold.Normal = refFaceNormal } // Keep points behind reference face - currentPoint := 0 // clipped points behind reference face - separation := raymath.Vector2DotProduct(refFaceNormal, incidentFace0) - refC + currentPoint := 0 // Clipped points behind reference face + separation := rl.Vector2DotProduct(refFaceNormal, incidentFace[0]) - refC + if separation <= 0 { - m.Contacts[currentPoint] = incidentFace0 - m.Penetration = -separation + manifold.Contacts[currentPoint] = incidentFace[0] + manifold.Penetration = -separation currentPoint++ } else { - m.Penetration = 0 + manifold.Penetration = 0 } - separation = raymath.Vector2DotProduct(refFaceNormal, incidentFace1) - refC + separation = rl.Vector2DotProduct(refFaceNormal, incidentFace[1]) - refC if separation <= 0 { - m.Contacts[currentPoint] = incidentFace1 - m.Penetration += -separation + manifold.Contacts[currentPoint] = incidentFace[1] + manifold.Penetration += -separation currentPoint++ // Calculate total penetration average - m.Penetration /= float32(currentPoint) + manifold.Penetration /= float32(currentPoint) } - m.ContactsCount = 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) + } } // initializeManifolds - Initializes physics manifolds to solve collisions -func (m *manifold) initializeManifolds() { - bodyA := m.BodyA - bodyB := m.BodyB +func initializeManifolds(manifold *Manifold) { + bodyA, bodyB := manifold.BodyA, manifold.BodyB - // 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))) + if bodyA == nil || bodyB == nil { + return + } - for i := 0; i < 2; i++ { + // // 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++ { // Caculate radius from center of mass to contact - radiusA := raymath.Vector2Subtract(m.Contacts[i], bodyA.Position) - radiusB := raymath.Vector2Subtract(m.Contacts[i], bodyB.Position) + radiusA := rl.Vector2Subtract(manifold.Contacts[i], bodyA.Position) + radiusB := rl.Vector2Subtract(manifold.Contacts[i], bodyB.Position) - crossA := raymath.Vector2Cross(bodyA.AngularVelocity, radiusA) - crossB := raymath.Vector2Cross(bodyB.AngularVelocity, radiusB) - - radiusV := raylib.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 + 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, + ) // 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 - if raymath.Vector2LenSqr(radiusV) < (raymath.Vector2LenSqr(raylib.NewVector2(gravityForce.X*deltaTime, gravityForce.Y*deltaTime)) + epsilon) { - m.Restitution = 0 + // 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 } } } // integrateImpulses - Integrates physics collisions impulses to solve collisions -func (m *manifold) integrateImpulses() { - bodyA := m.BodyA - bodyB := m.BodyB +func integrateImpulses(manifold *Manifold) { + bodyA, bodyB := manifold.BodyA, manifold.BodyB - // Early out and positional correct if both objects have infinite mass - if math.Abs(float64(bodyA.InverseMass+bodyB.InverseMass)) <= epsilon { - bodyA.Velocity = raylib.Vector2{} - bodyB.Velocity = raylib.Vector2{} + if bodyA == nil || bodyB == nil { return } - for i := 0; i < m.ContactsCount; i++ { + // Early out and positional correct if both objects have infinite mass + if math.Abs(float64(bodyA.InverseMass+bodyB.InverseMass)) <= epsilon { + bodyA.Velocity = rl.Vector2{} + bodyB.Velocity = rl.Vector2{} + return + } + + for i := 0; i < manifold.ContactsCount; i++ { // Calculate radius from center of mass to contact - radiusA := raymath.Vector2Subtract(m.Contacts[i], bodyA.Position) - radiusB := raymath.Vector2Subtract(m.Contacts[i], bodyB.Position) + radiusA := rl.Vector2Subtract(manifold.Contacts[i], bodyA.Position) + radiusB := rl.Vector2Subtract(manifold.Contacts[i], bodyB.Position) // Calculate relative velocity - radiusV := raylib.Vector2{} - radiusV.X = bodyB.Velocity.X + raymath.Vector2Cross(bodyB.AngularVelocity, radiusB).X - bodyA.Velocity.X - raymath.Vector2Cross(bodyA.AngularVelocity, radiusA).X - radiusV.Y = bodyB.Velocity.Y + raymath.Vector2Cross(bodyB.AngularVelocity, radiusB).Y - bodyA.Velocity.Y - raymath.Vector2Cross(bodyA.AngularVelocity, radiusA).Y + 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, + ) // Relative velocity along the normal - contactVelocity := raymath.Vector2DotProduct(radiusV, m.Normal) + contactVelocity := rl.Vector2DotProduct(radiusV, manifold.Normal) // Do not resolve if velocities are separating if contactVelocity > 0 { return } - raCrossN := raymath.Vector2CrossProduct(radiusA, m.Normal) - rbCrossN := raymath.Vector2CrossProduct(radiusB, m.Normal) + raCrossN := rl.Vector2CrossProduct(radiusA, manifold.Normal) + rbCrossN := rl.Vector2CrossProduct(radiusB, manifold.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 := -(1.0 + m.Restitution) * contactVelocity + impulse := -(manifold.Restitution + 1.0) * contactVelocity impulse /= inverseMassSum - impulse /= float32(m.ContactsCount) + impulse /= float32(manifold.ContactsCount) // Apply impulse to each physics body - impulseV := raylib.NewVector2(m.Normal.X*impulse, m.Normal.Y*impulse) + impulseV := rl.NewVector2(manifold.Normal.X*impulse, manifold.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 * raymath.Vector2CrossProduct(radiusA, raylib.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 * raymath.Vector2CrossProduct(radiusB, impulseV) + bodyB.AngularVelocity += bodyB.InverseInertia * rl.Vector2CrossProduct(radiusB, impulseV) } } // Apply friction impulse to each physics body - radiusV.X = bodyB.Velocity.X + raymath.Vector2Cross(bodyB.AngularVelocity, radiusB).X - bodyA.Velocity.X - raymath.Vector2Cross(bodyA.AngularVelocity, radiusA).X - radiusV.Y = bodyB.Velocity.Y + raymath.Vector2Cross(bodyB.AngularVelocity, radiusB).Y - bodyA.Velocity.Y - raymath.Vector2Cross(bodyA.AngularVelocity, radiusA).Y + 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 - tangent := raylib.NewVector2(radiusV.X-(m.Normal.X*raymath.Vector2DotProduct(radiusV, m.Normal)), radiusV.Y-(m.Normal.Y*raymath.Vector2DotProduct(radiusV, m.Normal))) + tangent := rl.NewVector2( + radiusV.X-manifold.Normal.X*rl.Vector2DotProduct(radiusV, manifold.Normal), + radiusV.Y-manifold.Normal.Y*rl.Vector2DotProduct(radiusV, manifold.Normal), + ) normalize(&tangent) // Calculate impulse tangent magnitude - impulseTangent := -(raymath.Vector2DotProduct(radiusV, tangent)) + impulseTangent := -rl.Vector2DotProduct(radiusV, tangent) impulseTangent /= inverseMassSum - impulseTangent /= float32(m.ContactsCount) + impulseTangent /= float32(manifold.ContactsCount) absImpulseTangent := float32(math.Abs(float64(impulseTangent))) @@ -1196,11 +1348,14 @@ func (m *manifold) integrateImpulses() { } // Apply coulumb's law - tangentImpulse := raylib.Vector2{} - if absImpulseTangent < impulse*m.StaticFriction { - tangentImpulse = raylib.NewVector2(tangent.X*impulseTangent, tangent.Y*impulseTangent) + var tangentImpulse rl.Vector2 + if absImpulseTangent < impulse*manifold.StaticFriction { + tangentImpulse = rl.NewVector2(tangent.X*impulseTangent, tangent.Y*impulseTangent) } else { - tangentImpulse = raylib.NewVector2(tangent.X*-impulse*m.DynamicFriction, tangent.Y*-impulse*m.DynamicFriction) + tangentImpulse = rl.NewVector2( + tangent.X*(-impulse)*manifold.DynamicFriction, + tangent.Y*(-impulse)*manifold.DynamicFriction, + ) } // Apply friction impulse @@ -1209,29 +1364,50 @@ func (m *manifold) integrateImpulses() { bodyA.Velocity.Y += bodyA.InverseMass * (-tangentImpulse.Y) if !bodyA.FreezeOrient { - bodyA.AngularVelocity += bodyA.InverseInertia * raymath.Vector2CrossProduct(radiusA, raylib.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 * raymath.Vector2CrossProduct(radiusB, tangentImpulse) + bodyB.AngularVelocity += bodyB.InverseInertia * rl.Vector2CrossProduct(radiusB, tangentImpulse) } } } } -// correctPositions - Corrects physics bodies positions based on manifolds collision information -func (m *manifold) correctPositions() { - bodyA := m.BodyA - bodyB := m.BodyB +// integrateVelocity - Integrates physics velocity into position and forces +func integrateVelocity(body *Body) { + if body == nil || !body.Enabled { + return + } - correction := raylib.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 + 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 + } + + 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) if bodyA.Enabled { bodyA.Position.X -= correction.X * bodyA.InverseMass @@ -1245,13 +1421,13 @@ func (m *manifold) correctPositions() { } // getSupport - Returns the extreme point along a direction within a polygon -func getSupport(shape Shape, dir raylib.Vector2) raylib.Vector2 { - bestProjection := float32(-fltMax) - bestVertex := raylib.Vector2{} +func getSupport(shape Shape, dir rl.Vector2) rl.Vector2 { + bestProjection := float32(-math.MaxFloat32) + bestVertex := rl.Vector2{} for i := 0; i < shape.VertexData.VertexCount; i++ { - vertex := shape.VertexData.Vertices[i] - projection := raymath.Vector2DotProduct(vertex, dir) + vertex := shape.VertexData.Positions[i] + projection := rl.Vector2DotProduct(vertex, dir) if projection > bestProjection { bestVertex = vertex @@ -1263,34 +1439,33 @@ func getSupport(shape Shape, dir raylib.Vector2) raylib.Vector2 { } // findAxisLeastPenetration - Finds polygon shapes axis least penetration -func findAxisLeastPenetration(shapeA, shapeB Shape) (int, float32) { +func findAxisLeastPenetration(shapeA Shape, shapeB Shape) (int, float32) { bestIndex := 0 - bestDistance := float32(-fltMax) + bestDistance := float32(-math.MaxFloat32) 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 := raymath.Mat2MultiplyVector2(dataA.Transform, normal) + transNormal := rl.Mat2MultiplyVector2(shapeA.Transform, normal) // Transform face normal into B shape's model space - buT := raymath.Mat2Transpose(dataB.Transform) - normal = raymath.Mat2MultiplyVector2(buT, transNormal) - - // Retrieve support point from B shape along -n - support := getSupport(shapeB, raylib.NewVector2(-normal.X, -normal.Y)) + buT := rl.Mat2Transpose(shapeB.Transform) + normal = rl.Mat2MultiplyVector2(buT, transNormal) // Retrieve vertex on face from A shape, transform into B shape's model space - vertex := dataA.Vertices[i] - vertex = raymath.Mat2MultiplyVector2(dataA.Transform, vertex) - vertex = raymath.Vector2Add(vertex, shapeA.Body.Position) - vertex = raymath.Vector2Subtract(vertex, shapeB.Body.Position) - vertex = raymath.Mat2MultiplyVector2(buT, vertex) + 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 = rl.Vector2Add(vertex, shapeA.Body.Position) + vertex = rl.Vector2Subtract(vertex, shapeB.Body.Position) + vertex = rl.Mat2MultiplyVector2(buT, vertex) // Compute penetration distance in B shape's model space - distance := raymath.Vector2DotProduct(normal, raymath.Vector2Subtract(support, vertex)) + distance := rl.Vector2DotProduct(normal, rl.Vector2Subtract(support, vertex)) // Store greatest distance if distance > bestDistance { @@ -1299,27 +1474,25 @@ func findAxisLeastPenetration(shapeA, shapeB Shape) (int, float32) { } } - return bestIndex, bestDistance + return bestIndex, float32(bestDistance) } // findIncidentFace - Finds two polygon shapes incident face -func findIncidentFace(v0, v1 *raylib.Vector2, ref, inc Shape, index int) { +func findIncidentFace(v0 *rl.Vector2, v1 *rl.Vector2, ref Shape, inc Shape, index int) { refData := ref.VertexData incData := inc.VertexData - referenceNormal := refData.Normals[index] + refNormal := refData.Normals[index] // Calculate normal in incident's frame of reference - referenceNormal = raymath.Mat2MultiplyVector2(refData.Transform, referenceNormal) // To world space - referenceNormal = raymath.Mat2MultiplyVector2(raymath.Mat2Transpose(incData.Transform), referenceNormal) // To incident's model space + refNormal = rl.Mat2MultiplyVector2(ref.Transform, refNormal) // To world space + refNormal = rl.Mat2MultiplyVector2(rl.Mat2Transpose(inc.Transform), refNormal) // To incident's model space // Find most anti-normal face on polygon incidentFace := 0 - minDot := float32(fltMax) - + minDot := float32(math.MaxFloat32) for i := 0; i < incData.VertexCount; i++ { - dot := raymath.Vector2DotProduct(referenceNormal, incData.Normals[i]) - + dot := rl.Vector2DotProduct(refNormal, incData.Normals[i]) if dot < minDot { minDot = dot incidentFace = i @@ -1327,39 +1500,31 @@ func findIncidentFace(v0, v1 *raylib.Vector2, ref, inc Shape, index int) { } // Assign face vertices for incident face - *v0 = raymath.Mat2MultiplyVector2(incData.Transform, incData.Vertices[incidentFace]) - *v0 = raymath.Vector2Add(*v0, inc.Body.Position) - - if incidentFace+1 < incData.VertexCount { - incidentFace = incidentFace + 1 - } else { - incidentFace = 0 - } - - *v1 = raymath.Mat2MultiplyVector2(incData.Transform, incData.Vertices[incidentFace]) - *v1 = raymath.Vector2Add(*v1, inc.Body.Position) + *v0 = rl.Mat2MultiplyVector2(inc.Transform, incData.Positions[incidentFace]) + *v0 = rl.Vector2Add(*v0, inc.Body.Position) + incidentFace = getNextIndex(incidentFace, incData.VertexCount) + *v1 = rl.Mat2MultiplyVector2(inc.Transform, incData.Positions[incidentFace]) + *v1 = rl.Vector2Add(*v1, inc.Body.Position) } // clip - Calculates clipping based on a normal and two faces -func clip(normal raylib.Vector2, clip float32, faceA, faceB *raylib.Vector2) int { +func clip(normal rl.Vector2, clip float32, faceA *rl.Vector2, faceB *rl.Vector2) int { sp := 0 - - out := make([]raylib.Vector2, 2) - out[0] = *faceA - out[1] = *faceB + out := [2]rl.Vector2{*faceA, *faceB} // Retrieve distances from each endpoint to the line - distanceA := raymath.Vector2DotProduct(normal, *faceA) - clip - distanceB := raymath.Vector2DotProduct(normal, *faceB) - clip + distanceA := rl.Vector2DotProduct(normal, *faceA) - clip + distanceB := rl.Vector2DotProduct(normal, *faceB) - clip // If negative (behind plane) if distanceA <= 0 { out[sp] = *faceA - sp += 1 + sp++ } + if distanceB <= 0 { out[sp] = *faceB - sp += 1 + sp++ } // If the points are on different sides of the plane @@ -1367,48 +1532,71 @@ func clip(normal raylib.Vector2, clip float32, faceA, faceB *raylib.Vector2) int // Push intersection point alpha := distanceA / (distanceA - distanceB) out[sp] = *faceA - delta := raymath.Vector2Subtract(*faceB, *faceA) + delta := rl.Vector2Subtract(*faceB, *faceA) delta.X *= alpha delta.Y *= alpha - out[sp] = raymath.Vector2Add(out[sp], delta) + out[sp] = rl.Vector2Add(out[sp], delta) sp++ } // Assign the new converted values *faceA = out[0] *faceB = out[1] - return sp } -// biasGreaterThan - Check if values are between bias range -func biasGreaterThan(valueA, valueB float32) bool { +// biasGreaterThan - Checks if values are between bias range +func biasGreaterThan(valueA float32, 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, v2, v3 raylib.Vector2) raylib.Vector2 { - result := raylib.Vector2{} - - result.X = (v1.X + v2.X + v3.X) / 3 - result.Y = (v1.Y + v2.Y + v3.Y) / 3 - - return result +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, + ) } -// normalize - Normalize provided vector -func normalize(v *raylib.Vector2) { - var length, ilength float32 +// initTimer - Initializes hi-resolution MONOTONIC timer +func initTimer() { + rand.Seed(getTimeCount()) + frequency = 1000000000 + startTime = getCurrentTime() // Get current time +} - aux := *v - length = float32(math.Sqrt(float64(aux.X*aux.X + aux.Y*aux.Y))) +// getTimeCount - Gets hi-res MONOTONIC time measure in nanoseconds +func getTimeCount() int64 { + return time.Since(baseTime).Nanoseconds() +} +// 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 - - v.X *= ilength - v.Y *= ilength + 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 +} + +func safeDiv(a, b float32) float32 { + if b == 0 { + return 0 + } + return a / b } diff --git a/raygui/README.md b/raygui/README.md index bcbaaff..85ffb99 100644 --- a/raygui/README.md +++ b/raygui/README.md @@ -1,5 +1,13 @@ -## raygui [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raygui?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/raygui) +## 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 is simple and easy-to-use IMGUI (immediate mode GUI API) library. -![screenshot](https://goo.gl/ieeaLj) + +### controls_test_suite + +![Demo](../examples/gui/controls_test_suite/controls_test_suite.png) + + +### scroll_panel + +![Demo](../examples/gui/scroll_panel/scroll_panel.png) diff --git a/raygui/cgo.go b/raygui/cgo.go new file mode 100644 index 0000000..4198945 --- /dev/null +++ b/raygui/cgo.go @@ -0,0 +1,6 @@ +package raygui + +/* +#cgo CFLAGS: -std=gnu99 -Wno-unused-result +*/ +import "C" diff --git a/raygui/cstring.go b/raygui/cstring.go new file mode 100644 index 0000000..023bfd4 --- /dev/null +++ b/raygui/cstring.go @@ -0,0 +1,102 @@ +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 new file mode 100644 index 0000000..e9096e0 --- /dev/null +++ b/raygui/go.mod @@ -0,0 +1,11 @@ +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 new file mode 100644 index 0000000..62eb5f5 --- /dev/null +++ b/raygui/go.sum @@ -0,0 +1,8 @@ +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/raygui.go b/raygui/raygui.go index bc0bb35..e41a749 100644 --- a/raygui/raygui.go +++ b/raygui/raygui.go @@ -1,1090 +1,1395 @@ -// 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 ( - "bufio" - "fmt" - "io/ioutil" - "strconv" + "image/color" "strings" + "unsafe" - "github.com/gen2brain/raylib-go/raylib" + rl "git.terah.dev/UnrealXR/raylib-go/raylib" ) -// 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 + SCROLLBAR_LEFT_SIDE = 0 + SCROLLBAR_RIGHT_SIDE = 1 ) -// GUI controls states +// GuiStyleProp - Style property +type GuiStyleProp struct { + controlId uint16 + propertyId uint16 + propertyValue uint32 +} + +// Gui control state const ( - Disabled = iota - Normal - Focused - Pressed + STATE_NORMAL int32 = 0 + STATE_FOCUSED = 1 + STATE_PRESSED = 2 + STATE_DISABLED = 3 ) -// Current GUI style (default light) -var style = []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 -} +// GuiState . +type GuiState = int32 -// GUI property names (to read/write style text files) -var propertyName = []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", -} - -// For spinner -var ( - framesCounter int - framesCounter2 int - valueSpeed bool +// Gui control text alignment +const ( + TEXT_ALIGN_LEFT int32 = 0 + TEXT_ALIGN_CENTER = 1 + TEXT_ALIGN_RIGHT = 2 ) -// BackgroundColor - Get background color -func BackgroundColor() raylib.Color { - return raylib.GetColor(int32(style[GlobalBackgroundColor])) +// 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() } -// LinesColor - Get lines color -func LinesColor() raylib.Color { - return raylib.GetColor(int32(style[GlobalLinesColor])) +// GuiDisable - Disable gui controls (global state) +func Disable() { + C.GuiDisable() } -// TextColor - Get text color for normal state -func TextColor() raylib.Color { - return raylib.GetColor(int32(style[GlobalTextColor])) +// GuiLock - Lock gui controls (global state) +func Lock() { + C.GuiLock() } -// Label - Label element, show text -func Label(bounds raylib.Rectangle, text string) { - LabelEx(bounds, text, raylib.GetColor(int32(style[LabelTextColor])), raylib.NewColor(0, 0, 0, 0), raylib.NewColor(0, 0, 0, 0)) +// GuiUnlock - Unlock gui controls (global state) +func Unlock() { + C.GuiUnlock() } -// LabelEx - Label element extended, configurable colors -func LabelEx(bounds raylib.Rectangle, text string, textColor, border, inner raylib.Color) { - b := bounds.ToInt32() - // Update control - textWidth := raylib.MeasureText(text, int32(style[GlobalTextFontsize])) - textHeight := int32(style[GlobalTextFontsize]) - - if b.Width < textWidth { - b.Width = textWidth + int32(style[LabelTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[LabelTextPadding])/2 - } - - // Draw control - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, border) - raylib.DrawRectangle(b.X+int32(style[LabelBorderWidth]), b.Y+int32(style[LabelBorderWidth]), b.Width-(2*int32(style[LabelBorderWidth])), b.Height-(2*int32(style[LabelBorderWidth])), inner) - raylib.DrawText(text, b.X+((b.Width/2)-(textWidth/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), textColor) +// GuiIsLocked - Check if gui is locked (global state) +func IsLocked() bool { + return bool(C.GuiIsLocked()) } -// Button - Button element, returns true when clicked -func Button(bounds raylib.Rectangle, text string) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := raylib.GetMousePosition() - clicked := false - - textWidth := raylib.MeasureText(text, int32(style[GlobalTextFontsize])) - textHeight := int32(style[GlobalTextFontsize]) - - // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ButtonTextPadding]) - } - - if b.Height < textHeight { - b.Height = textHeight + int32(style[ButtonTextPadding])/2 - } - - if raylib.CheckCollisionPointRec(mousePoint, bounds) { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - state = Pressed - } else if raylib.IsMouseButtonReleased(raylib.MouseLeftButton) || raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - clicked = true - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonDefaultBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonDefaultInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonDefaultTextColor]))) - break - - case Focused: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonHoverBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonHoverInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonHoverTextColor]))) - break - - case Pressed: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ButtonPressedBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ButtonBorderWidth]), b.Y+int32(style[ButtonBorderWidth]), b.Width-(2*int32(style[ButtonBorderWidth])), b.Height-(2*int32(style[ButtonBorderWidth])), raylib.GetColor(int32(style[ButtonPressedInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ButtonPressedTextColor]))) - break - - default: - break - } - - if clicked { - return true - } - - return false +// 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) } -// ToggleButton - Toggle Button element, returns true when active -func ToggleButton(bounds raylib.Rectangle, text string, active bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := raylib.GetMousePosition() - - textWidth := raylib.MeasureText(text, int32(style[GlobalTextFontsize])) - textHeight := int32(style[GlobalTextFontsize]) - - // Update control - if b.Width < textWidth { - b.Width = textWidth + int32(style[ToggleTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[ToggleTextPadding])/2 - } - - if raylib.CheckCollisionPointRec(mousePoint, bounds) { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - state = Pressed - } else if raylib.IsMouseButtonReleased(raylib.MouseLeftButton) || raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - state = Normal - active = !active - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - if active { - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleActiveInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor]))) - } else { - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleDefaultBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleDefaultInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleDefaultTextColor]))) - } - break - case Focused: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleHoverBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[ToggleHoverInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ToggleHoverTextColor]))) - break - case Pressed: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[TogglePressedBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[TogglePressedInsideColor]))) - raylib.DrawText(text, b.X+((b.Width/2)-(raylib.MeasureText(text, int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[TogglePressedTextColor]))) - break - default: - break - } - - return active +// GuiSetState - Set gui state (global state) +func SetState(state int32) { + cstate := C.int(state) + C.GuiSetState(cstate) } -// ToggleGroup - Toggle Group element, returns toggled button index -func ToggleGroup(bounds raylib.Rectangle, toggleText []string, active int) int { - for i := 0; i < len(toggleText); i++ { - if i == active { - ToggleButton(raylib.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], true) - } else if ToggleButton(raylib.NewRectangle(bounds.X+float32(i)*(bounds.Width+float32(style[TogglegroupPadding])), bounds.Y, bounds.Width, bounds.Height), toggleText[i], false) { - active = i - } - } - - return active +// GuiGetState - Get gui state (global state) +func GetState() int32 { + return int32(C.GuiGetState()) } -// ComboBox - Combo Box element, returns selected item index -func ComboBox(bounds raylib.Rectangle, comboText []string, active int) int { - b := bounds.ToInt32() - state := Normal - - clicked := false - click := raylib.NewRectangle(bounds.X+bounds.Width+float32(style[ComboboxPadding]), bounds.Y, float32(style[boundsWidth]), float32(style[boundsHeight])) - c := click.ToInt32() - - mousePoint := raylib.GetMousePosition() - - textWidth := int32(0) - textHeight := int32(style[GlobalTextFontsize]) - - comboCount := len(comboText) - - for i := 0; i < comboCount; i++ { - if i == active { - // Update control - textWidth = raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize])) - - if b.Width < textWidth { - b.Width = textWidth + int32(style[ToggleTextPadding]) - } - if b.Height < textHeight { - b.Height = textHeight + int32(style[ToggleTextPadding])/2 - } - - if raylib.CheckCollisionPointRec(mousePoint, bounds) || raylib.CheckCollisionPointRec(mousePoint, click) { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - state = Pressed - } else if raylib.IsMouseButtonReleased(raylib.MouseLeftButton) || raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - clicked = true - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor]))) - - raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxDefaultBorderColor]))) - raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxDefaultInsideColor]))) - raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultListTextColor]))) - raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxDefaultTextColor]))) - break - case Focused: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor]))) - - raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxHoverBorderColor]))) - raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxHoverInsideColor]))) - raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverListTextColor]))) - raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxHoverTextColor]))) - break - case Pressed: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor]))) - - raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor]))) - raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor]))) - raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor]))) - raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor]))) - break - default: - break - } - - if clicked { - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ComboboxPressedBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ComboboxBorderWidth]), b.Y+int32(style[ComboboxBorderWidth]), b.Width-(2*int32(style[ComboboxBorderWidth])), b.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedInsideColor]))) - - raylib.DrawRectangle(c.X, c.Y, c.Width, c.Height, raylib.GetColor(int32(style[ComboboxPressedListBorderColor]))) - raylib.DrawRectangle(c.X+int32(style[ComboboxBorderWidth]), c.Y+int32(style[ComboboxBorderWidth]), c.Width-(2*int32(style[ComboboxBorderWidth])), c.Height-(2*int32(style[ComboboxBorderWidth])), raylib.GetColor(int32(style[ComboboxPressedListInsideColor]))) - raylib.DrawText(fmt.Sprintf("%d/%d", active+1, comboCount), c.X+((c.Width/2)-(raylib.MeasureText(fmt.Sprintf("%d/%d", active+1, comboCount), int32(style[GlobalTextFontsize]))/2)), c.Y+((c.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedListTextColor]))) - raylib.DrawText(comboText[i], b.X+((b.Width/2)-(raylib.MeasureText(comboText[i], int32(style[GlobalTextFontsize]))/2)), b.Y+((b.Height/2)-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[ComboboxPressedTextColor]))) - } - - } - } - - if raylib.CheckCollisionPointRec(mousePoint, bounds) || raylib.CheckCollisionPointRec(mousePoint, click) { - if raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - active++ - if active >= comboCount { - active = 0 - } - } - } - - return active +// 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) } -// CheckBox - Check Box element, returns true when active -func CheckBox(bounds raylib.Rectangle, checked bool) bool { - b := bounds.ToInt32() - state := Normal - mousePoint := raylib.GetMousePosition() - - // Update control - if raylib.CheckCollisionPointRec(mousePoint, bounds) { - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - state = Pressed - } else if raylib.IsMouseButtonReleased(raylib.MouseLeftButton) || raylib.IsMouseButtonPressed(raylib.MouseLeftButton) { - state = Normal - checked = !checked - } else { - state = Focused - } - } - - // Draw control - switch state { - case Normal: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxDefaultBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxDefaultInsideColor]))) - break - case Focused: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxHoverBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxHoverInsideColor]))) - break - case Pressed: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[CheckboxClickBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[ToggleBorderWidth]), b.Y+int32(style[ToggleBorderWidth]), b.Width-(2*int32(style[ToggleBorderWidth])), b.Height-(2*int32(style[ToggleBorderWidth])), raylib.GetColor(int32(style[CheckboxClickInsideColor]))) - break - default: - break - } - - if checked { - raylib.DrawRectangle(b.X+int32(style[CheckboxInsideWidth]), b.Y+int32(style[CheckboxInsideWidth]), b.Width-(2*int32(style[CheckboxInsideWidth])), b.Height-(2*int32(style[CheckboxInsideWidth])), raylib.GetColor(int32(style[CheckboxDefaultActiveColor]))) - } - - return checked +// 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)) } -// Slider - Slider element, returns selected value -func Slider(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 { - b := bounds.ToInt32() - sliderPos := float32(0) - state := Normal - - buttonTravelDistance := float32(0) - mousePoint := raylib.GetMousePosition() - - // Update control - if value < minValue { - value = minValue - } else if value >= maxValue { - value = maxValue +// 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)) } - - sliderPos = (value - minValue) / (maxValue - minValue) - - sliderButton := raylib.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 raylib.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused - - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - state = Pressed - } - - if state == Pressed && raylib.IsMouseButtonDown(raylib.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 - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[SliderBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderInsideColor]))) - - switch state { - case Normal: - raylib.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, raylib.GetColor(int32(style[SliderDefaultColor]))) - break - case Focused: - raylib.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, raylib.GetColor(int32(style[SliderHoverColor]))) - break - case Pressed: - raylib.DrawRectangle(sliderButton.X, sliderButton.Y, sliderButton.Width, sliderButton.Height, raylib.GetColor(int32(style[SliderActiveColor]))) - break - default: - break - } - - return minValue + (maxValue-minValue)*sliderPos + return C.GuiWindowBox(cbounds, ctitle) != 0 } -// SliderBar - Slider Bar element, returns selected value -func SliderBar(bounds raylib.Rectangle, value, minValue, maxValue float32) float32 { - b := bounds.ToInt32() - state := Normal - - mousePoint := raylib.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 +// 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)) } - - sliderBar := raylib.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 raylib.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused - - if raylib.IsMouseButtonDown(raylib.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 - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[SliderbarBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[SliderBorderWidth]), b.Y+int32(style[SliderBorderWidth]), b.Width-(2*int32(style[SliderBorderWidth])), b.Height-(2*int32(style[SliderBorderWidth])), raylib.GetColor(int32(style[SliderbarInsideColor]))) - - switch state { - case Normal: - raylib.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, raylib.GetColor(int32(style[SliderbarDefaultColor]))) - break - case Focused: - raylib.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, raylib.GetColor(int32(style[SliderbarHoverColor]))) - break - case Pressed: - raylib.DrawRectangle(sliderBar.X, sliderBar.Y, sliderBar.Width, sliderBar.Height, raylib.GetColor(int32(style[SliderbarActiveColor]))) - break - default: - break - } - - if minValue < 0 && maxValue > 0 { - raylib.DrawRectangle((b.X+int32(style[SliderBorderWidth]))-int32(minValue*(float32(b.Width-(int32(style[SliderBorderWidth])*2))/maxValue)), sliderBar.Y, 1, sliderBar.Height, raylib.GetColor(int32(style[SliderbarZeroLineColor]))) - } - - return fixedValue + minValue + C.GuiGroupBox(cbounds, ctext) } -// ProgressBar - Progress Bar element, shows current progress value -func ProgressBar(bounds raylib.Rectangle, value float32) { - b := bounds.ToInt32() - if value > 1.0 { - value = 1.0 - } else if value < 0.0 { - value = 0.0 +// 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)) } - - progressBar := raylib.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), b.Width - (int32(style[ProgressbarBorderWidth]) * 2), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} - progressValue := raylib.RectangleInt32{b.X + int32(style[ProgressbarBorderWidth]), b.Y + int32(style[ProgressbarBorderWidth]), int32(value * float32(b.Width-int32(style[ProgressbarBorderWidth])*2)), b.Height - (int32(style[ProgressbarBorderWidth]) * 2)} - - // Draw control - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ProgressbarBorderColor]))) - raylib.DrawRectangle(progressBar.X, progressBar.Y, progressBar.Width, progressBar.Height, raylib.GetColor(int32(style[ProgressbarInsideColor]))) - raylib.DrawRectangle(progressValue.X, progressValue.Y, progressValue.Width, progressValue.Height, raylib.GetColor(int32(style[ProgressbarProgressColor]))) + C.GuiLine(cbounds, ctext) } -// Spinner - Spinner element, returns selected value -func Spinner(bounds raylib.Rectangle, value, minValue, maxValue int) int { - b := bounds.ToInt32() - state := Normal - - mousePoint := raylib.GetMousePosition() - labelBoxBound := raylib.RectangleInt32{b.X + b.Width/4 + 1, b.Y, b.Width / 2, b.Height} - leftButtonBound := raylib.RectangleInt32{b.X, b.Y, b.Width / 4, b.Height} - rightButtonBound := raylib.RectangleInt32{b.X + b.Width - b.Width/4 + 1, b.Y, b.Width / 4, b.Height} - - textWidth := raylib.MeasureText(fmt.Sprintf("%d", value), int32(style[GlobalTextFontsize])) - - buttonSide := 0 - - // Update control - if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) || raylib.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) || raylib.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { - if raylib.IsKeyDown(raylib.KeyLeft) { - state = Pressed - buttonSide = 1 - - if value > minValue { - value-- - } - } else if raylib.IsKeyDown(raylib.KeyRight) { - state = Pressed - buttonSide = 2 - - if value < maxValue { - value++ - } - } +// 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)) } - - if raylib.CheckCollisionPointRec(mousePoint, leftButtonBound.ToFloat32()) { - buttonSide = 1 - state = Focused - - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - if !valueSpeed { - if value > minValue { - value-- - } - valueSpeed = true - } else { - framesCounter++ - } - - state = Pressed - - if value > minValue { - if framesCounter >= 30 { - value-- - } - } - } - } else if raylib.CheckCollisionPointRec(mousePoint, rightButtonBound.ToFloat32()) { - buttonSide = 2 - state = Focused - - if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { - if !valueSpeed { - if value < maxValue { - value++ - } - valueSpeed = true - } else { - framesCounter++ - } - - state = Pressed - - if value < maxValue { - if framesCounter >= 30 { - value++ - } - } - } - } else if !raylib.CheckCollisionPointRec(mousePoint, labelBoxBound.ToFloat32()) { - buttonSide = 0 - } - - if raylib.IsMouseButtonUp(raylib.MouseLeftButton) { - valueSpeed = false - framesCounter = 0 - } - - // Draw control - switch state { - case Normal: - raylib.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(raylib.MeasureText("+", int32(style[GlobalTextFontsize])))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - raylib.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(raylib.MeasureText("-", int32(style[GlobalTextFontsize])))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - - raylib.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, raylib.GetColor(int32(style[SpinnerLabelBorderColor]))) - raylib.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, raylib.GetColor(int32(style[SpinnerLabelInsideColor]))) - - raylib.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultTextColor]))) - break - case Focused: - if buttonSide == 1 { - raylib.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, raylib.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) - raylib.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) - - raylib.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(raylib.MeasureText("+", int32(style[GlobalTextFontsize])))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerHoverSymbolColor]))) - raylib.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(raylib.MeasureText("-", int32(style[GlobalTextFontsize])))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - } else if buttonSide == 2 { - raylib.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, raylib.GetColor(int32(style[SpinnerHoverButtonBorderColor]))) - raylib.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerHoverButtonInsideColor]))) - - raylib.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(raylib.MeasureText("+", int32(style[GlobalTextFontsize])))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - raylib.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(raylib.MeasureText("-", int32(style[GlobalTextFontsize])))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerHoverSymbolColor]))) - } - - raylib.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, raylib.GetColor(int32(style[SpinnerLabelBorderColor]))) - raylib.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, raylib.GetColor(int32(style[SpinnerLabelInsideColor]))) - - raylib.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerHoverTextColor]))) - break - case Pressed: - if buttonSide == 1 { - raylib.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, raylib.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) - raylib.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) - - raylib.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(raylib.MeasureText("+", int32(style[GlobalTextFontsize])))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerPressedSymbolColor]))) - raylib.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(raylib.MeasureText("-", int32(style[GlobalTextFontsize])))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - } else if buttonSide == 2 { - raylib.DrawRectangle(leftButtonBound.X, leftButtonBound.Y, leftButtonBound.Width, leftButtonBound.Height, raylib.GetColor(int32(style[SpinnerDefaultButtonBorderColor]))) - raylib.DrawRectangle(leftButtonBound.X+2, leftButtonBound.Y+2, leftButtonBound.Width-4, leftButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerDefaultButtonInsideColor]))) - - raylib.DrawRectangle(rightButtonBound.X, rightButtonBound.Y, rightButtonBound.Width, rightButtonBound.Height, raylib.GetColor(int32(style[SpinnerPressedButtonBorderColor]))) - raylib.DrawRectangle(rightButtonBound.X+2, rightButtonBound.Y+2, rightButtonBound.Width-4, rightButtonBound.Height-4, raylib.GetColor(int32(style[SpinnerPressedButtonInsideColor]))) - - raylib.DrawText("-", leftButtonBound.X+(leftButtonBound.Width/2-(raylib.MeasureText("+", int32(style[GlobalTextFontsize])))/2), leftButtonBound.Y+(leftButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerDefaultSymbolColor]))) - raylib.DrawText("+", rightButtonBound.X+(rightButtonBound.Width/2-(raylib.MeasureText("-", int32(style[GlobalTextFontsize])))/2), rightButtonBound.Y+(rightButtonBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerPressedSymbolColor]))) - } - - raylib.DrawRectangle(labelBoxBound.X, labelBoxBound.Y, labelBoxBound.Width, labelBoxBound.Height, raylib.GetColor(int32(style[SpinnerLabelBorderColor]))) - raylib.DrawRectangle(labelBoxBound.X+1, labelBoxBound.Y+1, labelBoxBound.Width-2, labelBoxBound.Height-2, raylib.GetColor(int32(style[SpinnerLabelInsideColor]))) - - raylib.DrawText(fmt.Sprintf("%d", value), labelBoxBound.X+(labelBoxBound.Width/2-textWidth/2), labelBoxBound.Y+(labelBoxBound.Height/2-(int32(style[GlobalTextFontsize])/2)), int32(style[GlobalTextFontsize]), raylib.GetColor(int32(style[SpinnerPressedTextColor]))) - break - default: - break - } - - return value + C.GuiPanel(cbounds, ctext) } -// TextBox - Text Box element, updates input text -func TextBox(bounds raylib.Rectangle, text string) string { - b := bounds.ToInt32() - state := Normal - - keyBackspaceText := int32(259) // GLFW BACKSPACE: 3 + 256 - - mousePoint := raylib.GetMousePosition() - letter := int32(-1) - - // Update control - if raylib.CheckCollisionPointRec(mousePoint, bounds) { - state = Focused // NOTE: PRESSED state is not used on this control - - framesCounter2++ - - letter = raylib.GetKeyPressed() - - if letter != -1 { - if letter == keyBackspaceText { - if len(text) > 0 { - text = text[:len(text)-1] - } - } else { - if letter >= 32 && letter < 127 { - text = fmt.Sprintf("%s%c", text, letter) - } - } - } +// 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) + }() - // Draw control - switch state { - case Normal: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[TextboxBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor]))) - raylib.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor]))) - break - case Focused: - raylib.DrawRectangle(b.X, b.Y, b.Width, b.Height, raylib.GetColor(int32(style[ToggleActiveBorderColor]))) - raylib.DrawRectangle(b.X+int32(style[TextboxBorderWidth]), b.Y+int32(style[TextboxBorderWidth]), b.Width-(int32(style[TextboxBorderWidth])*2), b.Height-(int32(style[TextboxBorderWidth])*2), raylib.GetColor(int32(style[TextboxInsideColor]))) - raylib.DrawText(text, b.X+2, b.Y+int32(style[TextboxBorderWidth])+b.Height/2-int32(style[TextboxTextFontsize])/2, int32(style[TextboxTextFontsize]), raylib.GetColor(int32(style[TextboxTextColor]))) + res := C.GuiScrollPanel(cbounds, ctext, ccontent, &cscroll, &cview) - if (framesCounter2/20)%2 == 0 && raylib.CheckCollisionPointRec(mousePoint, bounds) { - raylib.DrawRectangle(b.X+4+raylib.MeasureText(text, int32(style[GlobalTextFontsize])), b.Y+2, 1, b.Height-4, raylib.GetColor(int32(style[TextboxLineColor]))) - } - break - case Pressed: - break - default: - break - } - - return text + return int32(res) } -// SaveGuiStyle - Save GUI style file -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))) - } +// 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) - ioutil.WriteFile(fileName, []byte(styleFile), 0644) + cvalue := C.int(value) + cminValue := C.int(minValue) + cmaxValue := C.int(maxValue) + + return int32(C.GuiScrollBar(cbounds, cvalue, cminValue, cmaxValue)) } -// LoadGuiStyle - Load GUI style file -func LoadGuiStyle(fileName string) { - file, err := raylib.OpenAsset(fileName) - if err != nil { - raylib.TraceLog(raylib.LogWarning, "[%s] GUI style file could not be opened", fileName) - 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) - } - } - } +// 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) } -// SetStyleProperty - Set one style property -func SetStyleProperty(guiProperty Property, value int64) { - style[guiProperty] = value +// 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 } -// GetStyleProperty - Get one style property -func GetStyleProperty(guiProperty Property) int64 { - return style[int(guiProperty)] +// 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))) } diff --git a/raygui/raygui.h b/raygui/raygui.h new file mode 100644 index 0000000..9127710 --- /dev/null +++ b/raygui/raygui.h @@ -0,0 +1,5523 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..1c4c4a0 --- /dev/null +++ b/raygui/raylib.h @@ -0,0 +1,1662 @@ +/********************************************************************************************** +* +* 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/raylib/audio.c b/raylib/audio.c deleted file mode 100644 index 980d3cc..0000000 --- a/raylib/audio.c +++ /dev/null @@ -1,2280 +0,0 @@ -// +build !noaudio - -/********************************************************************************************** -* -* raylib.audio - Basic funtionality to work with audio -* -* 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 -* -* CONFIGURATION: -* -* #define AUDIO_STANDALONE -* Define to use the module as standalone library (independently of raylib). -* Required types and functions are defined in the same module. -* -* #define USE_OPENAL_BACKEND -* Use OpenAL Soft audio backend usage -* -* #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 -* -* LIMITATIONS (only OpenAL Soft): -* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) -* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) -* -* DEPENDENCIES: -* mini_al - Audio device/context management (https://github.com/dr-soft/mini_al) -* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) -* jar_xm - XM module file loading -* jar_mod - MOD audio file loading -* dr_flac - FLAC audio file loading -* -* *OpenAL Soft - Audio device management, still used on HTML5 and OSX platforms -* -* CONTRIBUTORS: -* David Reid (github: @mackron) (Nov. 2017): -* - Complete port to mini_al 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-2018 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 "config.h" - -#if !defined(USE_OPENAL_BACKEND) - #define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL. -#endif - -#if defined(AUDIO_STANDALONE) - #include "audio.h" - #include // Required for: va_list, va_start(), vfprintf(), va_end() -#else - #include "raylib.h" - #include "utils.h" // Required for: fopen() Android mapping -#endif - -#include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc. - -#if !defined(USE_MINI_AL) || (USE_MINI_AL == 0) - #if defined(__APPLE__) - #include "OpenAL/al.h" // OpenAL basic header - #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) - #else - #include "AL/al.h" // OpenAL basic header - #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) - //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS - #endif - - // OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples - // OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) -#endif - -#include // Required for: malloc(), free() -#include // Required for: strcmp(), strncmp() -#include // Required for: FILE, fopen(), fclose(), fread() - -#if defined(SUPPORT_FILEFORMAT_OGG) - //#define STB_VORBIS_HEADER_ONLY - #include "external/stb_vorbis.h" // OGG loading functions -#endif - -#if defined(SUPPORT_FILEFORMAT_XM) - #define JAR_XM_IMPLEMENTATION - #include "external/jar_xm.h" // XM loading functions -#endif - -#if defined(SUPPORT_FILEFORMAT_MOD) - #define JAR_MOD_IMPLEMENTATION - #include "external/jar_mod.h" // MOD loading functions -#endif - -#if defined(SUPPORT_FILEFORMAT_FLAC) - #define DR_FLAC_IMPLEMENTATION - #define DR_FLAC_NO_WIN32_IO - #include "external/dr_flac.h" // FLAC loading functions -#endif - -#if defined(SUPPORT_FILEFORMAT_MP3) - #define DR_MP3_IMPLEMENTATION - #include "external/dr_mp3.h" // MP3 loading functions -#endif - -#ifdef _MSC_VER - #undef bool -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define MAX_STREAM_BUFFERS 2 // Number of buffers for each audio stream - -// NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number -// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds -// and double-buffering system, I concluded that a 4096 samples buffer should be enough -// In case of music-stalls, just increase this number -#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb) - -// Support uncompressed PCM data in 32-bit float IEEE format -// NOTE: This definition is included in "AL/alext.h", but some OpenAL implementations -// could not provide the extensions header (Android), so its defined here -#if !defined(AL_EXT_float32) - #define AL_EXT_float32 1 - #define AL_FORMAT_MONO_FLOAT32 0x10010 - #define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -typedef enum { - MUSIC_AUDIO_OGG = 0, - MUSIC_AUDIO_FLAC, - MUSIC_MODULE_XM, - MUSIC_MODULE_MOD -} MusicContextType; - -// Music type (file streaming from memory) -typedef struct MusicData { - MusicContextType ctxType; // Type of music context (OGG, XM, MOD) -#if defined(SUPPORT_FILEFORMAT_OGG) - stb_vorbis *ctxOgg; // OGG audio context -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - drflac *ctxFlac; // FLAC audio context -#endif -#if defined(SUPPORT_FILEFORMAT_XM) - jar_xm_context_t *ctxXm; // XM chiptune context -#endif -#if defined(SUPPORT_FILEFORMAT_MOD) - jar_mod_context_t ctxMod; // MOD chiptune context -#endif - - AudioStream stream; // Audio stream (double buffering) - - int loopCount; // Loops count (times music repeats), -1 means infinite loop - unsigned int totalSamples; // Total number of samples - unsigned int samplesLeft; // Number of samples left to end -} MusicData; - -#if defined(AUDIO_STANDALONE) -typedef enum { - LOG_INFO = 0, - LOG_ERROR, - LOG_WARNING, - LOG_DEBUG, - LOG_OTHER -} TraceLogType; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_WAV) -static Wave LoadWAV(const char *fileName); // Load WAV file -#endif -#if defined(SUPPORT_FILEFORMAT_OGG) -static Wave LoadOGG(const char *fileName); // Load OGG file -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) -static Wave LoadFLAC(const char *fileName); // Load FLAC file -#endif - -#if defined(AUDIO_STANDALONE) -bool IsFileExtension(const char *fileName, const char *ext); // Check file extension -void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -#endif - -//---------------------------------------------------------------------------------- -// mini_al AudioBuffer Functionality -//---------------------------------------------------------------------------------- -#if USE_MINI_AL - -#define DEVICE_FORMAT mal_format_f32 -#define DEVICE_CHANNELS 2 -#define DEVICE_SAMPLE_RATE 44100 - -typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; - -// Audio buffer structure -// NOTE: Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed -typedef struct AudioBuffer AudioBuffer; -struct AudioBuffer { - mal_dsp dsp; // Required for format conversion - float volume; - float pitch; - bool playing; - bool paused; - bool looping; // Always true for AudioStreams - int usage; // AudioBufferUsage type - bool isSubBufferProcessed[2]; - unsigned int frameCursorPos; - unsigned int bufferSizeInFrames; - AudioBuffer *next; - AudioBuffer *prev; - unsigned char buffer[1]; -}; - -// mini_al global variables -static mal_context context; -static mal_device device; -static mal_mutex audioLock; -static bool isAudioInitialized = MAL_FALSE; -static float masterVolume = 1.0f; - -// Audio buffers are tracked in a linked list -static AudioBuffer *firstAudioBuffer = NULL; -static AudioBuffer *lastAudioBuffer = NULL; - -// mini_al functions declaration -static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message); -static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut); -static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, void *pFramesOut, void *pUserData); -static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 frameCount, float localVolume); - -// AudioBuffer management functions declaration -// NOTE: Those functions are not exposed by raylib... for the moment -AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage); -void DeleteAudioBuffer(AudioBuffer *audioBuffer); -bool IsAudioBufferPlaying(AudioBuffer *audioBuffer); -void PlayAudioBuffer(AudioBuffer *audioBuffer); -void StopAudioBuffer(AudioBuffer *audioBuffer); -void PauseAudioBuffer(AudioBuffer *audioBuffer); -void ResumeAudioBuffer(AudioBuffer *audioBuffer); -void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume); -void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch); -void TrackAudioBuffer(AudioBuffer *audioBuffer); -void UntrackAudioBuffer(AudioBuffer *audioBuffer); - - -// Log callback function -static void OnLog(mal_context *pContext, mal_device *pDevice, const char *message) -{ - (void)pContext; - (void)pDevice; - - TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors -} - -// Sending audio data to device callback function -static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameCount, void *pFramesOut) -{ - // This is where all of the mixing takes place. - (void)pDevice; - - // Mixing is basically just an accumulation. We need to initialize the output buffer to 0. - memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_sample_size_in_bytes(pDevice->format)); - - // Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may - // want to consider how you might want to avoid this. - mal_mutex_lock(&audioLock); - { - for (AudioBuffer *audioBuffer = firstAudioBuffer; audioBuffer != NULL; audioBuffer = audioBuffer->next) - { - // Ignore stopped or paused sounds. - if (!audioBuffer->playing || audioBuffer->paused) continue; - - mal_uint32 framesRead = 0; - for (;;) - { - if (framesRead > frameCount) - { - TraceLog(LOG_DEBUG, "Mixed too many frames from audio buffer"); - break; - } - - if (framesRead == frameCount) break; - - // Just read as much data as we can from the stream. - mal_uint32 framesToRead = (frameCount - framesRead); - while (framesToRead > 0) - { - float tempBuffer[1024]; // 512 frames for stereo. - - mal_uint32 framesToReadRightNow = framesToRead; - if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS) - { - framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS; - } - - // If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the - // last few samples. - bool flushDSP = !audioBuffer->looping; - - mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP); - if (framesJustRead > 0) - { - float *framesOut = (float *)pFramesOut + (framesRead*device.channels); - float *framesIn = tempBuffer; - MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer->volume); - - framesToRead -= framesJustRead; - framesRead += framesJustRead; - } - - // If we weren't able to read all the frames we requested, break. - if (framesJustRead < framesToReadRightNow) - { - if (!audioBuffer->looping) - { - StopAudioBuffer(audioBuffer); - break; - } - else - { - // Should never get here, but just for safety, - // move the cursor position back to the start and continue the loop. - audioBuffer->frameCursorPos = 0; - continue; - } - } - } - - // If for some reason we weren't able to read every frame we'll need to break from the loop. - // Not doing this could theoretically put us into an infinite loop. - if (framesToRead > 0) break; - } - } - } - - mal_mutex_unlock(&audioLock); - - return frameCount; // We always output the same number of frames that were originally requested. -} - -// DSP read from audio buffer callback function -static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, void *pFramesOut, void *pUserData) -{ - AudioBuffer *audioBuffer = (AudioBuffer *)pUserData; - - mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; - mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; - - if (currentSubBufferIndex > 1) - { - TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); - return 0; - } - - // 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]; - isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; - isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; - - mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn; - - // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0. - mal_uint32 framesRead = 0; - for (;;) - { - // 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 the halves of the buffer that are processed. Unprocessed halves must keep their audio data in-tact. - if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) - { - if (framesRead >= frameCount) break; - } - else - { - if (isSubBufferProcessed[currentSubBufferIndex]) break; - } - - mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining == 0) break; - - mal_uint32 framesRemainingInOutputBuffer; - if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) - { - framesRemainingInOutputBuffer = audioBuffer->bufferSizeInFrames - audioBuffer->frameCursorPos; - } - else - { - mal_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames * currentSubBufferIndex; - framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer); - } - - mal_uint32 framesToRead = totalFramesRemaining; - if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer; - - memcpy((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), audioBuffer->buffer + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); - audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead) % audioBuffer->bufferSizeInFrames; - framesRead += framesToRead; - - // If we've read to the end of the buffer, mark it as processed. - if (framesToRead == framesRemainingInOutputBuffer) - { - audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true; - isSubBufferProcessed[currentSubBufferIndex] = true; - - currentSubBufferIndex = (currentSubBufferIndex + 1)%2; - - // We need to break from this loop if we're not looping. - if (!audioBuffer->looping) - { - StopAudioBuffer(audioBuffer); - break; - } - } - } - - // Zero-fill excess. - mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining > 0) - { - memset((unsigned char*)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); - - // 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 or not a non-looping sound has finished playback. - if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining; - } - - return framesRead; -} - -// 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, mal_uint32 frameCount, float localVolume) -{ - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) - { - for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) - { - float *frameOut = framesOut + (iFrame*device.channels); - const float *frameIn = framesIn + (iFrame*device.channels); - - frameOut[iChannel] += frameIn[iChannel]*masterVolume*localVolume; - } - } -} -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Audio Device initialization and Closing -//---------------------------------------------------------------------------------- -// Initialize audio device -void InitAudioDevice(void) -{ -#if USE_MINI_AL - // Context. - mal_context_config contextConfig = mal_context_config_init(OnLog); - mal_result result = mal_context_init(NULL, 0, &contextConfig, &context); - if (result != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "Failed to initialize audio context"); - return; - } - - // Device. Using the default device. Format is floating point because it simplifies mixing. - mal_device_config deviceConfig = mal_device_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, OnSendAudioDataToDevice); - - result = mal_device_init(&context, mal_device_type_playback, NULL, &deviceConfig, NULL, &device); - if (result != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "Failed to initialize audio playback device"); - mal_context_uninit(&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. - result = mal_device_start(&device); - if (result != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "Failed to start audio playback device"); - mal_device_uninit(&device); - mal_context_uninit(&context); - 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 (mal_mutex_init(&context, &audioLock) != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "Failed to create mutex for audio mixing"); - mal_device_uninit(&device); - mal_context_uninit(&context); - return; - } - - TraceLog(LOG_INFO, "Audio device initialized successfully: %s", device.name); - TraceLog(LOG_INFO, "Audio backend: mini_al / %s", mal_get_backend_name(context.backend)); - TraceLog(LOG_INFO, "Audio format: %s -> %s", mal_get_format_name(device.format), mal_get_format_name(device.internalFormat)); - TraceLog(LOG_INFO, "Audio channels: %d -> %d", device.channels, device.internalChannels); - TraceLog(LOG_INFO, "Audio sample rate: %d -> %d", device.sampleRate, device.internalSampleRate); - TraceLog(LOG_INFO, "Audio buffer size: %d", device.bufferSizeInFrames); - - isAudioInitialized = MAL_TRUE; -#else - // Open and initialize a device with default settings - ALCdevice *device = alcOpenDevice(NULL); - - if (!device) TraceLog(LOG_ERROR, "Audio device could not be opened"); - else - { - ALCcontext *context = alcCreateContext(device, NULL); - - if ((context == NULL) || (alcMakeContextCurrent(context) == ALC_FALSE)) - { - if (context != NULL) alcDestroyContext(context); - - alcCloseDevice(device); - - TraceLog(LOG_ERROR, "Could not initialize audio context"); - } - else - { - TraceLog(LOG_INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); - - // Listener definition (just for 2D) - alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); - alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f); - - alListenerf(AL_GAIN, 1.0f); - - if (alIsExtensionPresent("AL_EXT_float32")) TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 supported"); - else TraceLog(LOG_INFO, "[EXTENSION] AL_EXT_float32 not supported"); - } - } -#endif -} - -// Close the audio device for all contexts -void CloseAudioDevice(void) -{ -#if USE_MINI_AL - if (!isAudioInitialized) - { - TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); - return; - } - - mal_mutex_uninit(&audioLock); - mal_device_uninit(&device); - mal_context_uninit(&context); -#else - ALCdevice *device; - ALCcontext *context = alcGetCurrentContext(); - - if (context == NULL) TraceLog(LOG_WARNING, "Could not get current audio context for closing"); - - device = alcGetContextsDevice(context); - - alcMakeContextCurrent(NULL); - alcDestroyContext(context); - alcCloseDevice(device); -#endif - - TraceLog(LOG_INFO, "Audio device closed successfully"); -} - -// Check if device has been initialized successfully -bool IsAudioDeviceReady(void) -{ -#if USE_MINI_AL - return isAudioInitialized; -#else - ALCcontext *context = alcGetCurrentContext(); - - if (context == NULL) return false; - else - { - ALCdevice *device = alcGetContextsDevice(context); - - if (device == NULL) return false; - else return true; - } -#endif -} - -// Set master volume (listener) -void SetMasterVolume(float volume) -{ - if (volume < 0.0f) volume = 0.0f; - else if (volume > 1.0f) volume = 1.0f; - -#if USE_MINI_AL - masterVolume = volume; -#else - alListenerf(AL_GAIN, volume); -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Audio Buffer management -//---------------------------------------------------------------------------------- -#if USE_MINI_AL -// Create a new audio buffer. Initially filled with silence -AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage) -{ - AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1); - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer"); - return NULL; - } - - // We run audio data through a format converter. - mal_dsp_config dspConfig; - memset(&dspConfig, 0, sizeof(dspConfig)); - dspConfig.formatIn = format; - dspConfig.formatOut = DEVICE_FORMAT; - dspConfig.channelsIn = channels; - dspConfig.channelsOut = DEVICE_CHANNELS; - dspConfig.sampleRateIn = sampleRate; - dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE; - mal_result resultMAL = mal_dsp_init(&dspConfig, OnAudioBufferDSPRead, audioBuffer, &audioBuffer->dsp); - if (resultMAL != MAL_SUCCESS) - { - TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline"); - free(audioBuffer); - return NULL; - } - - audioBuffer->volume = 1; - audioBuffer->pitch = 1; - audioBuffer->playing = 0; - audioBuffer->paused = 0; - audioBuffer->looping = 0; - audioBuffer->usage = usage; - audioBuffer->bufferSizeInFrames = bufferSizeInFrames; - audioBuffer->frameCursorPos = 0; - - // Buffers should be marked as processed by default so that a call to UpdateAudioStream() immediately after initialization works correctly. - audioBuffer->isSubBufferProcessed[0] = true; - audioBuffer->isSubBufferProcessed[1] = true; - - TrackAudioBuffer(audioBuffer); - - return audioBuffer; -} - -// Delete an audio buffer -void DeleteAudioBuffer(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - UntrackAudioBuffer(audioBuffer); - free(audioBuffer); -} - -// Check if an audio buffer is playing -bool IsAudioBufferPlaying(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return false; - } - - return audioBuffer->playing && !audioBuffer->paused; -} - -// Play an audio buffer -// NOTE: Buffer is restarted to the start. -// Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained. -void PlayAudioBuffer(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - audioBuffer->playing = true; - audioBuffer->paused = false; - audioBuffer->frameCursorPos = 0; -} - -// Stop an audio buffer -void StopAudioBuffer(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - // Don't do anything if the audio buffer is already stopped. - if (!IsAudioBufferPlaying(audioBuffer)) return; - - audioBuffer->playing = false; - audioBuffer->paused = false; - audioBuffer->frameCursorPos = 0; - audioBuffer->isSubBufferProcessed[0] = true; - audioBuffer->isSubBufferProcessed[1] = true; -} - -// Pause an audio buffer -void PauseAudioBuffer(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - audioBuffer->paused = true; -} - -// Resume an audio buffer -void ResumeAudioBuffer(AudioBuffer *audioBuffer) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - audioBuffer->paused = false; -} - -// Set volume for an audio buffer -void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - audioBuffer->volume = volume; -} - -// Set pitch for an audio buffer -void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch) -{ - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer"); - return; - } - - audioBuffer->pitch = pitch; - - // 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. - mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn); - mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); -} - -// Track audio buffer to linked list next position -void TrackAudioBuffer(AudioBuffer *audioBuffer) -{ - mal_mutex_lock(&audioLock); - - { - if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer; - else - { - lastAudioBuffer->next = audioBuffer; - audioBuffer->prev = lastAudioBuffer; - } - - lastAudioBuffer = audioBuffer; - } - - mal_mutex_unlock(&audioLock); -} - -// Untrack audio buffer from linked list -void UntrackAudioBuffer(AudioBuffer *audioBuffer) -{ - mal_mutex_lock(&audioLock); - - { - if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next; - else audioBuffer->prev->next = audioBuffer->next; - - if (audioBuffer->next == NULL) lastAudioBuffer = audioBuffer->prev; - else audioBuffer->next->prev = audioBuffer->prev; - - audioBuffer->prev = NULL; - audioBuffer->next = NULL; - } - - mal_mutex_unlock(&audioLock); -} -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Sounds loading and playing (.WAV) -//---------------------------------------------------------------------------------- - -// Load wave data from file -Wave LoadWave(const char *fileName) -{ - Wave wave = { 0 }; - - if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName); -#if defined(SUPPORT_FILEFORMAT_OGG) - else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (IsFileExtension(fileName, ".flac")) wave = LoadFLAC(fileName); -#endif - else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName); - - return wave; -} - -// Load wave data from raw array data -Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels) -{ - Wave wave; - - wave.data = data; - wave.sampleCount = sampleCount; - wave.sampleRate = sampleRate; - wave.sampleSize = sampleSize; - wave.channels = channels; - - // NOTE: Copy wave data to work with, user is responsible of input data to free - Wave cwave = WaveCopy(wave); - - WaveFormat(&cwave, sampleRate, sampleSize, channels); - - return cwave; -} - -// Load sound from file -// NOTE: The entire file is loaded to memory to be played (no-streaming) -Sound LoadSound(const char *fileName) -{ - Wave wave = LoadWave(fileName); - - Sound sound = LoadSoundFromWave(wave); - - UnloadWave(wave); // Sound is loaded, we can unload wave - - return sound; -} - -// Load sound from wave data -// NOTE: Wave data must be unallocated manually -Sound LoadSoundFromWave(Wave wave) -{ - Sound sound = { 0 }; - - if (wave.data != NULL) - { -#if USE_MINI_AL - // When using mini_al 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 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. - // - // I have decided on the first option because it offloads work required for the format conversion to the to the loading stage. The - // downside to this is that it uses more memory if the original sound is u8 or s16. - mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. - - mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); - if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to get frame count for format conversion"); - - AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC); - if (audioBuffer == NULL) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer"); - - frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn); - if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed"); - - sound.audioBuffer = audioBuffer; -#else - ALenum format = 0; - - // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample) - if (wave.channels == 1) - { - switch (wave.sampleSize) - { - case 8: format = AL_FORMAT_MONO8; break; - case 16: format = AL_FORMAT_MONO16; break; - case 32: format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; - } - } - else if (wave.channels == 2) - { - switch (wave.sampleSize) - { - case 8: format = AL_FORMAT_STEREO8; break; - case 16: format = AL_FORMAT_STEREO16; break; - case 32: format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; - } - } - else TraceLog(LOG_WARNING, "Wave number of channels not supported: %i", wave.channels); - - // Create an audio source - ALuint source; - alGenSources(1, &source); // Generate pointer to audio source - - alSourcef(source, AL_PITCH, 1.0f); - alSourcef(source, AL_GAIN, 1.0f); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alSourcei(source, AL_LOOPING, AL_FALSE); - - // Convert loaded data to OpenAL buffer - //---------------------------------------- - ALuint buffer; - alGenBuffers(1, &buffer); // Generate pointer to buffer - - unsigned int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; // Size in bytes - - // Upload sound data to buffer - alBufferData(buffer, format, wave.data, dataSize, wave.sampleRate); - - // Attach sound buffer to source - alSourcei(source, AL_BUFFER, buffer); - - TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (%i Hz, %i bit, %s)", source, buffer, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - - sound.source = source; - sound.buffer = buffer; - sound.format = format; -#endif - } - - return sound; -} - -// Unload wave data -void UnloadWave(Wave wave) -{ - if (wave.data != NULL) free(wave.data); - - TraceLog(LOG_INFO, "Unloaded wave data from RAM"); -} - -// Unload sound -void UnloadSound(Sound sound) -{ -#if USE_MINI_AL - DeleteAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourceStop(sound.source); - - alDeleteSources(1, &sound.source); - alDeleteBuffers(1, &sound.buffer); -#endif - - TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); -} - -// Update sound buffer with new data -// NOTE: data must match sound.format -void UpdateSound(Sound sound, const void *data, int samplesCount) -{ -#if USE_MINI_AL - AudioBuffer *audioBuffer = (AudioBuffer *)sound.audioBuffer; - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); - return; - } - - StopAudioBuffer(audioBuffer); - - // TODO: May want to lock/unlock this since this data buffer is read at mixing time. - memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.config.channelsIn*mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)); -#else - ALint sampleRate, sampleSize, channels; - alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); - alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format - alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format - - TraceLog(LOG_DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate); - TraceLog(LOG_DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize); - TraceLog(LOG_DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels); - - unsigned int dataSize = samplesCount*channels*sampleSize/8; // Size of data in bytes - - alSourceStop(sound.source); // Stop sound - alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update - //alDeleteBuffers(1, &sound.buffer); // Delete current buffer data - //alGenBuffers(1, &sound.buffer); // Generate new buffer - - // Upload new data to sound buffer - alBufferData(sound.buffer, sound.format, data, dataSize, sampleRate); - - // Attach sound buffer to source again - alSourcei(sound.source, AL_BUFFER, sound.buffer); -#endif -} - -// Play a sound -void PlaySound(Sound sound) -{ -#if USE_MINI_AL - PlayAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourcePlay(sound.source); // Play the sound -#endif - - //TraceLog(LOG_INFO, "Playing sound"); - - // Find the current position of the sound being played - // NOTE: Only work when the entire file is in a single buffer - //int byteOffset; - //alGetSourcei(sound.source, AL_BYTE_OFFSET, &byteOffset); - // - //int sampleRate; - //alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); // AL_CHANNELS, AL_BITS (bps) - - //float seconds = (float)byteOffset/sampleRate; // Number of seconds since the beginning of the sound - //or - //float result; - //alGetSourcef(sound.source, AL_SEC_OFFSET, &result); // AL_SAMPLE_OFFSET -} - -// Pause a sound -void PauseSound(Sound sound) -{ -#if USE_MINI_AL - PauseAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourcePause(sound.source); -#endif -} - -// Resume a paused sound -void ResumeSound(Sound sound) -{ -#if USE_MINI_AL - ResumeAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - ALenum state; - - alGetSourcei(sound.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) alSourcePlay(sound.source); -#endif -} - -// Stop reproducing a sound -void StopSound(Sound sound) -{ -#if USE_MINI_AL - StopAudioBuffer((AudioBuffer *)sound.audioBuffer); -#else - alSourceStop(sound.source); -#endif -} - -// Check if a sound is playing -bool IsSoundPlaying(Sound sound) -{ -#if USE_MINI_AL - return IsAudioBufferPlaying((AudioBuffer *)sound.audioBuffer); -#else - bool playing = false; - ALint state; - - alGetSourcei(sound.source, AL_SOURCE_STATE, &state); - if (state == AL_PLAYING) playing = true; - - return playing; -#endif -} - -// Set volume for a sound -void SetSoundVolume(Sound sound, float volume) -{ -#if USE_MINI_AL - SetAudioBufferVolume((AudioBuffer *)sound.audioBuffer, volume); -#else - alSourcef(sound.source, AL_GAIN, volume); -#endif -} - -// Set pitch for a sound -void SetSoundPitch(Sound sound, float pitch) -{ -#if USE_MINI_AL - SetAudioBufferPitch((AudioBuffer *)sound.audioBuffer, pitch); -#else - alSourcef(sound.source, AL_PITCH, pitch); -#endif -} - -// Convert wave data to desired format -void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) -{ -#if USE_MINI_AL - mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - - mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. - - mal_uint32 frameCount = mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn); - if (frameCount == 0) - { - TraceLog(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion."); - return; - } - - void *data = malloc(frameCount*channels*(sampleSize/8)); - - frameCount = mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn); - if (frameCount == 0) - { - TraceLog(LOG_ERROR, "WaveFormat() : Format conversion failed."); - return; - } - - wave->sampleCount = frameCount; - wave->sampleSize = sampleSize; - wave->sampleRate = sampleRate; - wave->channels = channels; - free(wave->data); - wave->data = data; - -#else - // Format sample rate - // NOTE: Only supported 22050 <--> 44100 - if (wave->sampleRate != sampleRate) - { - // TODO: Resample wave data (upsampling or downsampling) - // NOTE 1: To downsample, you have to drop samples or average them. - // NOTE 2: To upsample, you have to interpolate new samples. - - wave->sampleRate = sampleRate; - } - - // Format sample size - // NOTE: Only supported 8 bit <--> 16 bit <--> 32 bit - if (wave->sampleSize != sampleSize) - { - void *data = malloc(wave->sampleCount*wave->channels*sampleSize/8); - - for (int i = 0; i < wave->sampleCount; i++) - { - for (int j = 0; j < wave->channels; j++) - { - if (sampleSize == 8) - { - if (wave->sampleSize == 16) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float)(((short *)wave->data)[wave->channels*i + j])/32767.0f)*256); - else if (wave->sampleSize == 32) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float *)wave->data)[wave->channels*i + j]*127.0f + 127); - } - else if (sampleSize == 16) - { - if (wave->sampleSize == 8) ((short *)data)[wave->channels*i + j] = (short)(((float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f)*32767); - else if (wave->sampleSize == 32) ((short *)data)[wave->channels*i + j] = (short)((((float *)wave->data)[wave->channels*i + j])*32767); - } - else if (sampleSize == 32) - { - if (wave->sampleSize == 8) ((float *)data)[wave->channels*i + j] = (float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f; - else if (wave->sampleSize == 16) ((float *)data)[wave->channels*i + j] = (float)(((short *)wave->data)[wave->channels*i + j])/32767.0f; - } - } - } - - wave->sampleSize = sampleSize; - free(wave->data); - wave->data = data; - } - - // Format channels (interlaced mode) - // NOTE: Only supported mono <--> stereo - if (wave->channels != channels) - { - void *data = malloc(wave->sampleCount*wave->sampleSize/8*channels); - - if ((wave->channels == 1) && (channels == 2)) // mono ---> stereo (duplicate mono information) - { - for (int i = 0; i < wave->sampleCount; i++) - { - for (int j = 0; j < channels; j++) - { - if (wave->sampleSize == 8) ((unsigned char *)data)[channels*i + j] = ((unsigned char *)wave->data)[i]; - else if (wave->sampleSize == 16) ((short *)data)[channels*i + j] = ((short *)wave->data)[i]; - else if (wave->sampleSize == 32) ((float *)data)[channels*i + j] = ((float *)wave->data)[i]; - } - } - } - else if ((wave->channels == 2) && (channels == 1)) // stereo ---> mono (mix stereo channels) - { - for (int i = 0, j = 0; i < wave->sampleCount; i++, j += 2) - { - if (wave->sampleSize == 8) ((unsigned char *)data)[i] = (((unsigned char *)wave->data)[j] + ((unsigned char *)wave->data)[j + 1])/2; - else if (wave->sampleSize == 16) ((short *)data)[i] = (((short *)wave->data)[j] + ((short *)wave->data)[j + 1])/2; - else if (wave->sampleSize == 32) ((float *)data)[i] = (((float *)wave->data)[j] + ((float *)wave->data)[j + 1])/2.0f; - } - } - - // TODO: Add/remove additional interlaced channels - - wave->channels = channels; - free(wave->data); - wave->data = data; - } -#endif -} - -// Copy a wave to a new wave -Wave WaveCopy(Wave wave) -{ - Wave newWave = { 0 }; - - newWave.data = malloc(wave.sampleCount*wave.sampleSize/8*wave.channels); - - if (newWave.data != NULL) - { - // NOTE: Size must be provided in bytes - memcpy(newWave.data, wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8); - - newWave.sampleCount = wave.sampleCount; - newWave.sampleRate = wave.sampleRate; - newWave.sampleSize = wave.sampleSize; - newWave.channels = wave.channels; - } - - return newWave; -} - -// Crop a wave to defined samples range -// NOTE: Security check in case of out-of-range -void WaveCrop(Wave *wave, int initSample, int finalSample) -{ - if ((initSample >= 0) && (initSample < finalSample) && - (finalSample > 0) && (finalSample < wave->sampleCount)) - { - int sampleCount = finalSample - initSample; - - void *data = malloc(sampleCount*wave->sampleSize/8*wave->channels); - - memcpy(data, (unsigned char*)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8); - - free(wave->data); - wave->data = data; - } - else TraceLog(LOG_WARNING, "Wave crop range out of bounds"); -} - -// Get samples data from wave as a floats array -// NOTE: Returned sample values are normalized to range [-1..1] -float *GetWaveData(Wave wave) -{ - float *samples = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float)); - - for (int i = 0; i < wave.sampleCount; i++) - { - for (int j = 0; j < wave.channels; j++) - { - if (wave.sampleSize == 8) samples[wave.channels*i + j] = (float)(((unsigned char *)wave.data)[wave.channels*i + j] - 127)/256.0f; - else if (wave.sampleSize == 16) samples[wave.channels*i + j] = (float)((short *)wave.data)[wave.channels*i + j]/32767.0f; - else if (wave.sampleSize == 32) samples[wave.channels*i + j] = ((float *)wave.data)[wave.channels*i + j]; - } - } - - return samples; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Music loading and stream playing (.OGG) -//---------------------------------------------------------------------------------- - -// Load music stream from file -Music LoadMusicStream(const char *fileName) -{ - Music music = (MusicData *)malloc(sizeof(MusicData)); - - if (IsFileExtension(fileName, ".ogg")) - { - // Open ogg audio stream - music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL); - - if (music->ctxOgg == NULL) TraceLog(LOG_WARNING, "[%s] OGG audio file could not be opened", fileName); - else - { - stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // 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); - music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg); // Independent by channel - music->samplesLeft = music->totalSamples; - music->ctxType = MUSIC_AUDIO_OGG; - music->loopCount = -1; // Infinite loop by default - - TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); - TraceLog(LOG_DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); - TraceLog(LOG_DEBUG, "[%s] OGG channels: %i", fileName, info.channels); - TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); - } - } -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (IsFileExtension(fileName, ".flac")) - { - music->ctxFlac = drflac_open_file(fileName); - - if (music->ctxFlac == NULL) TraceLog(LOG_WARNING, "[%s] FLAC audio file could not be opened", fileName); - else - { - music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels); - music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels; - music->samplesLeft = music->totalSamples; - music->ctxType = MUSIC_AUDIO_FLAC; - music->loopCount = -1; // Infinite loop by default - - TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); - TraceLog(LOG_DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate); - TraceLog(LOG_DEBUG, "[%s] FLAC bits per sample: %i", fileName, music->ctxFlac->bitsPerSample); - TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels); - } - } -#endif -#if defined(SUPPORT_FILEFORMAT_XM) - else if (IsFileExtension(fileName, ".xm")) - { - int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName); - - if (!result) // XM context created successfully - { - jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops - - // NOTE: Only stereo is supported for XM - music->stream = InitAudioStream(48000, 16, 2); - music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); - music->samplesLeft = music->totalSamples; - music->ctxType = MUSIC_MODULE_XM; - music->loopCount = -1; // Infinite loop by default - - TraceLog(LOG_DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples); - TraceLog(LOG_DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); - } - else TraceLog(LOG_WARNING, "[%s] XM file could not be opened", fileName); - } -#endif -#if defined(SUPPORT_FILEFORMAT_MOD) - else if (IsFileExtension(fileName, ".mod")) - { - jar_mod_init(&music->ctxMod); - - if (jar_mod_load_file(&music->ctxMod, fileName)) - { - music->stream = InitAudioStream(48000, 16, 2); - music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod); - music->samplesLeft = music->totalSamples; - music->ctxType = MUSIC_MODULE_MOD; - music->loopCount = -1; // Infinite loop by default - - TraceLog(LOG_DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft); - TraceLog(LOG_DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); - } - else TraceLog(LOG_WARNING, "[%s] MOD file could not be opened", fileName); - } -#endif - else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName); - - return music; -} - -// Unload music stream -void UnloadMusicStream(Music music) -{ - CloseAudioStream(music->stream); - - if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); -#if defined(SUPPORT_FILEFORMAT_FLAC) - else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); -#endif -#if defined(SUPPORT_FILEFORMAT_XM) - else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm); -#endif -#if defined(SUPPORT_FILEFORMAT_MOD) - else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); -#endif - - free(music); -} - -// Start music playing (open stream) -void PlayMusicStream(Music music) -{ -#if USE_MINI_AL - AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer; - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); - return; - } - - // For music streams, we need to make sure we maintain the frame cursor position. This is 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 (IsMusicPlaying(music)) PlayMusicStream(music); - mal_uint32 frameCursorPos = audioBuffer->frameCursorPos; - - PlayAudioStream(music->stream); // <-- This resets the cursor position. - - audioBuffer->frameCursorPos = frameCursorPos; -#else - alSourcePlay(music->stream.source); -#endif -} - -// Pause music playing -void PauseMusicStream(Music music) -{ -#if USE_MINI_AL - PauseAudioStream(music->stream); -#else - alSourcePause(music->stream.source); -#endif -} - -// Resume music playing -void ResumeMusicStream(Music music) -{ -#if USE_MINI_AL - ResumeAudioStream(music->stream); -#else - ALenum state; - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) - { - TraceLog(LOG_INFO, "[AUD ID %i] Resume music stream playing", music->stream.source); - alSourcePlay(music->stream.source); - } -#endif -} - -// Stop music playing (close stream) -// TODO: To clear a buffer, make sure they have been already processed! -void StopMusicStream(Music music) -{ -#if USE_MINI_AL - StopAudioStream(music->stream); -#else - alSourceStop(music->stream.source); - - /* - // Clear stream buffers - // WARNING: Queued buffers must have been processed before unqueueing and reloaded with data!!! - void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); - - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) - { - //UpdateAudioStream(music->stream, pcm, AUDIO_BUFFER_SIZE); // Update one buffer at a time - alBufferData(music->stream.buffers[i], music->stream.format, pcm, AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, music->stream.sampleRate); - } - - free(pcm); - */ -#endif - - // Restart music context - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break; -#if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_MODULE_FLAC: /* TODO: Restart FLAC context */ break; -#endif -#if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: /* TODO: Restart XM context */ break; -#endif -#if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: jar_mod_seek_start(&music->ctxMod); break; -#endif - default: break; - } - - music->samplesLeft = music->totalSamples; -} - -// Update (re-fill) music buffers if data already processed -// TODO: Make sure buffers are ready for update... check music state -void UpdateMusicStream(Music music) -{ -#if USE_MINI_AL - bool streamEnding = false; - - unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; - - // NOTE: Using dynamic allocation because it could require more than 16KB - void *pcm = calloc(subBufferSizeInFrames*music->stream.sampleSize/8*music->stream.channels, 1); - - int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts - - while (IsAudioBufferProcessed(music->stream)) - { - if (music->samplesLeft >= subBufferSizeInFrames) samplesCount = subBufferSizeInFrames; - else samplesCount = music->samplesLeft; - - // TODO: Really don't like ctxType thingy... - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: - { - // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) - stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); - - } break; - #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: - { - // NOTE: Returns the number of samples to process - unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); - - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; - #endif - #if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; - #endif - default: break; - } - - UpdateAudioStream(music->stream, pcm, samplesCount); - music->samplesLeft -= samplesCount; - - if (music->samplesLeft <= 0) - { - streamEnding = true; - break; - } - } - - // Free allocated pcm data - free(pcm); - - // Reset audio stream for looping - if (streamEnding) - { - StopMusicStream(music); // Stop music (and reset) - - // Decrease loopCount to stop when required - if (music->loopCount > 0) - { - music->loopCount--; // Decrease loop count - PlayMusicStream(music); // Play again - } - else - { - if (music->loopCount == -1) PlayMusicStream(music); - } - } - else - { - // NOTE: In case window is minimized, music stream is stopped, - // just make sure to play again on window restore - if (IsMusicPlaying(music)) PlayMusicStream(music); - } -#else - ALenum state; - ALint processed = 0; - - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); // Get music stream state - alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); // Get processed buffers - - if (processed > 0) - { - bool streamEnding = false; - - // NOTE: Using dynamic allocation because it could require more than 16KB - void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1); - - int numBuffersToProcess = processed; - int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, - // individual L or R for ogg shorts - - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE; - else samplesCount = music->samplesLeft; - - // TODO: Really don't like ctxType thingy... - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: - { - // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) - int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); - - } break; - #if defined(SUPPORT_FILEFORMAT_FLAC) - case MUSIC_AUDIO_FLAC: - { - // NOTE: Returns the number of samples to process - unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); - - } break; - #endif - #if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; - #endif - #if defined(SUPPORT_FILEFORMAT_MOD) - case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; - #endif - default: break; - } - - UpdateAudioStream(music->stream, pcm, samplesCount); - music->samplesLeft -= samplesCount; - - if (music->samplesLeft <= 0) - { - streamEnding = true; - break; - } - } - - // Free allocated pcm data - free(pcm); - - // Reset audio stream for looping - if (streamEnding) - { - StopMusicStream(music); // Stop music (and reset) - - // Decrease loopCount to stop when required - if (music->loopCount > 0) - { - music->loopCount--; // Decrease loop count - PlayMusicStream(music); // Play again - } - else - { - if (music->loopCount == -1) - { - PlayMusicStream(music); - } - } - } - else - { - // NOTE: In case window is minimized, music stream is stopped, - // just make sure to play again on window restore - if (state != AL_PLAYING) PlayMusicStream(music); - } - } -#endif -} - -// Check if any music is playing -bool IsMusicPlaying(Music music) -{ -#if USE_MINI_AL - return IsAudioStreamPlaying(music->stream); -#else - bool playing = false; - ALint state; - - alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PLAYING) playing = true; - - return playing; -#endif -} - -// Set volume for music -void SetMusicVolume(Music music, float volume) -{ -#if USE_MINI_AL - SetAudioStreamVolume(music->stream, volume); -#else - alSourcef(music->stream.source, AL_GAIN, volume); -#endif -} - -// Set pitch for music -void SetMusicPitch(Music music, float pitch) -{ -#if USE_MINI_AL - SetAudioStreamPitch(music->stream, pitch); -#else - alSourcef(music->stream.source, AL_PITCH, pitch); -#endif -} - -// Set music loop count (loop repeats) -// NOTE: If set to -1, means infinite loop -void SetMusicLoopCount(Music music, int count) -{ - music->loopCount = count; -} - -// Get music time length (in seconds) -float GetMusicTimeLength(Music music) -{ - float totalSeconds = (float)music->totalSamples/music->stream.sampleRate; - - return totalSeconds; -} - -// Get current music time played (in seconds) -float GetMusicTimePlayed(Music music) -{ - float secondsPlayed = 0.0f; - - unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; - secondsPlayed = (float)samplesPlayed/music->stream.sampleRate; - - return secondsPlayed; -} - - -// Init audio stream (to stream audio pcm data) -AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) -{ - AudioStream stream = { 0 }; - - stream.sampleRate = sampleRate; - stream.sampleSize = sampleSize; - - // Only mono and stereo channels are supported, more channels require AL_EXT_MCFORMATS extension - if ((channels > 0) && (channels < 3)) stream.channels = channels; - else - { - TraceLog(LOG_WARNING, "Init audio stream: Number of channels not supported: %i", channels); - stream.channels = 1; // Fallback to mono channel - } - - -#if USE_MINI_AL - mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); - - // The size of a streaming buffer must be at least double the size of a period. - unsigned int periodSize = device.bufferSizeInFrames / device.periods; - unsigned int subBufferSize = AUDIO_BUFFER_SIZE; - if (subBufferSize < periodSize) subBufferSize = periodSize; - - AudioBuffer *audioBuffer = CreateAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "InitAudioStream() : Failed to create audio buffer"); - return stream; - } - - audioBuffer->looping = true; // Always loop for streaming buffers. - stream.audioBuffer = audioBuffer; -#else - // Setup OpenAL format - if (stream.channels == 1) - { - switch (sampleSize) - { - case 8: stream.format = AL_FORMAT_MONO8; break; - case 16: stream.format = AL_FORMAT_MONO16; break; - case 32: stream.format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; - } - } - else if (stream.channels == 2) - { - switch (sampleSize) - { - case 8: stream.format = AL_FORMAT_STEREO8; break; - case 16: stream.format = AL_FORMAT_STEREO16; break; - case 32: stream.format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32 - default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; - } - } - - // Create an audio source - alGenSources(1, &stream.source); - alSourcef(stream.source, AL_PITCH, 1.0f); - alSourcef(stream.source, AL_GAIN, 1.0f); - alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - // Create Buffers (double buffering) - alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); - - // Initialize buffer with zeros by default - // NOTE: Using dynamic allocation because it requires more than 16KB - void *pcm = calloc(AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, 1); - - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) - { - alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, stream.sampleRate); - } - - free(pcm); - - alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); -#endif - - TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); - - return stream; -} - -// Close audio stream and free memory -void CloseAudioStream(AudioStream stream) -{ -#if USE_MINI_AL - DeleteAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - // Stop playing channel - alSourceStop(stream.source); - - // Flush out all queued buffers - int queued = 0; - alGetSourcei(stream.source, AL_BUFFERS_QUEUED, &queued); - - ALuint buffer = 0; - - while (queued > 0) - { - alSourceUnqueueBuffers(stream.source, 1, &buffer); - queued--; - } - - // Delete source and buffers - alDeleteSources(1, &stream.source); - alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers); -#endif - - TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); -} - -// Update audio stream buffers with data -// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue -// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioBufferProcessed() -void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) -{ -#if USE_MINI_AL - AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer; - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "UpdateAudioStream() : No audio buffer"); - return; - } - - if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) - { - mal_uint32 subBufferToUpdate; - if (audioBuffer->isSubBufferProcessed[0] && audioBuffer->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; - audioBuffer->frameCursorPos = 0; - } - else - { - // Just update whichever sub-buffer is processed. - subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0]) ? 0 : 1; - } - - mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; - unsigned char *subBuffer = audioBuffer->buffer + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate); - - // 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 >= (mal_uint32)samplesCount) - { - mal_uint32 framesToWrite = subBufferSizeInFrames; - if (framesToWrite > (mal_uint32)samplesCount) framesToWrite = (mal_uint32)samplesCount; - - mal_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); - memcpy(subBuffer, data, bytesToWrite); - - // Any leftover frames should be filled with zeros. - mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - if (leftoverFrameCount > 0) - { - memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); - } - - audioBuffer->isSubBufferProcessed[subBufferToUpdate] = false; - } - else - { - TraceLog(LOG_ERROR, "UpdateAudioStream() : Attempting to write too many frames to buffer"); - return; - } - } - else - { - TraceLog(LOG_ERROR, "Audio buffer not available for updating"); - return; - } -#else - ALuint buffer = 0; - alSourceUnqueueBuffers(stream.source, 1, &buffer); - - // Check if any buffer was available for unqueue - if (alGetError() != AL_INVALID_VALUE) - { - alBufferData(buffer, stream.format, data, samplesCount*stream.sampleSize/8*stream.channels, stream.sampleRate); - alSourceQueueBuffers(stream.source, 1, &buffer); - } - else TraceLog(LOG_WARNING, "[AUD ID %i] Audio buffer not available for unqueuing", stream.source); -#endif -} - -// Check if any audio stream buffers requires refill -bool IsAudioBufferProcessed(AudioStream stream) -{ -#if USE_MINI_AL - AudioBuffer *audioBuffer = (AudioBuffer *)stream.audioBuffer; - if (audioBuffer == NULL) - { - TraceLog(LOG_ERROR, "IsAudioBufferProcessed() : No audio buffer"); - return false; - } - - return audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]; -#else - ALint processed = 0; - - // Determine if music stream is ready to be written - alGetSourcei(stream.source, AL_BUFFERS_PROCESSED, &processed); - - return (processed > 0); -#endif -} - -// Play audio stream -void PlayAudioStream(AudioStream stream) -{ -#if USE_MINI_AL - PlayAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourcePlay(stream.source); -#endif -} - -// Play audio stream -void PauseAudioStream(AudioStream stream) -{ -#if USE_MINI_AL - PauseAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourcePause(stream.source); -#endif -} - -// Resume audio stream playing -void ResumeAudioStream(AudioStream stream) -{ -#if USE_MINI_AL - ResumeAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - ALenum state; - alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) alSourcePlay(stream.source); -#endif -} - -// Check if audio stream is playing. -bool IsAudioStreamPlaying(AudioStream stream) -{ -#if USE_MINI_AL - return IsAudioBufferPlaying((AudioBuffer *)stream.audioBuffer); -#else - bool playing = false; - ALint state; - - alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - - if (state == AL_PLAYING) playing = true; - - return playing; -#endif -} - -// Stop audio stream -void StopAudioStream(AudioStream stream) -{ -#if USE_MINI_AL - StopAudioBuffer((AudioBuffer *)stream.audioBuffer); -#else - alSourceStop(stream.source); -#endif -} - -void SetAudioStreamVolume(AudioStream stream, float volume) -{ -#if USE_MINI_AL - SetAudioBufferVolume((AudioBuffer *)stream.audioBuffer, volume); -#else - alSourcef(stream.source, AL_GAIN, volume); -#endif -} - -void SetAudioStreamPitch(AudioStream stream, float pitch) -{ -#if USE_MINI_AL - SetAudioBufferPitch((AudioBuffer *)stream.audioBuffer, pitch); -#else - alSourcef(stream.source, AL_PITCH, pitch); -#endif -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(SUPPORT_FILEFORMAT_WAV) -// Load WAV file into Wave structure -static Wave LoadWAV(const char *fileName) -{ - // Basic WAV headers structs - typedef struct { - char chunkID[4]; - int chunkSize; - char format[4]; - } WAVRiffHeader; - - typedef struct { - char subChunkID[4]; - int subChunkSize; - short audioFormat; - short numChannels; - int sampleRate; - int byteRate; - short blockAlign; - short bitsPerSample; - } WAVFormat; - - typedef struct { - char subChunkID[4]; - int subChunkSize; - } WAVData; - - WAVRiffHeader wavRiffHeader; - WAVFormat wavFormat; - WAVData wavData; - - Wave wave = { 0 }; - FILE *wavFile; - - wavFile = fopen(fileName, "rb"); - - if (wavFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] WAV file could not be opened", fileName); - wave.data = NULL; - } - else - { - // Read in the first chunk into the struct - fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile); - - // Check for RIFF and WAVE tags - if (strncmp(wavRiffHeader.chunkID, "RIFF", 4) || - strncmp(wavRiffHeader.format, "WAVE", 4)) - { - TraceLog(LOG_WARNING, "[%s] Invalid RIFF or WAVE Header", fileName); - } - else - { - // Read in the 2nd chunk for the wave info - fread(&wavFormat, sizeof(WAVFormat), 1, wavFile); - - // Check for fmt tag - if ((wavFormat.subChunkID[0] != 'f') || (wavFormat.subChunkID[1] != 'm') || - (wavFormat.subChunkID[2] != 't') || (wavFormat.subChunkID[3] != ' ')) - { - TraceLog(LOG_WARNING, "[%s] Invalid Wave format", fileName); - } - else - { - // Check for extra parameters; - if (wavFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR); - - // Read in the the last byte of data before the sound file - fread(&wavData, sizeof(WAVData), 1, wavFile); - - // Check for data tag - if ((wavData.subChunkID[0] != 'd') || (wavData.subChunkID[1] != 'a') || - (wavData.subChunkID[2] != 't') || (wavData.subChunkID[3] != 'a')) - { - TraceLog(LOG_WARNING, "[%s] Invalid data header", fileName); - } - else - { - // Allocate memory for data - wave.data = malloc(wavData.subChunkSize); - - // Read in the sound data into the soundData variable - fread(wave.data, wavData.subChunkSize, 1, wavFile); - - // Store wave parameters - wave.sampleRate = wavFormat.sampleRate; - wave.sampleSize = wavFormat.bitsPerSample; - wave.channels = wavFormat.numChannels; - - // NOTE: Only support 8 bit, 16 bit and 32 bit sample sizes - if ((wave.sampleSize != 8) && (wave.sampleSize != 16) && (wave.sampleSize != 32)) - { - TraceLog(LOG_WARNING, "[%s] WAV sample size (%ibit) not supported, converted to 16bit", fileName, wave.sampleSize); - WaveFormat(&wave, wave.sampleRate, 16, wave.channels); - } - - // NOTE: Only support up to 2 channels (mono, stereo) - if (wave.channels > 2) - { - WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2); - TraceLog(LOG_WARNING, "[%s] WAV channels number (%i) not supported, converted to 2 channels", fileName, wave.channels); - } - - // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples - wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels; - - TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - } - } - } - - fclose(wavFile); - } - - return wave; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_OGG) -// Load OGG file into Wave structure -// NOTE: Using stb_vorbis library -static Wave LoadOGG(const char *fileName) -{ - Wave wave = { 0 }; - - stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL); - - if (oggFile == NULL) TraceLog(LOG_WARNING, "[%s] OGG file could not be opened", fileName); - else - { - stb_vorbis_info info = stb_vorbis_get_info(oggFile); - - wave.sampleRate = info.sample_rate; - wave.sampleSize = 16; // 16 bit per sample (short) - wave.channels = info.channels; - wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile); // Independent by channel - - float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); - if (totalSeconds > 10) TraceLog(LOG_WARNING, "[%s] Ogg audio length is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); - - wave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short)); - - // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) - int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels); - - TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg); - - TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - - stb_vorbis_close(oggFile); - } - - return wave; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_FLAC) -// Load FLAC file into Wave structure -// NOTE: Using dr_flac library -static Wave LoadFLAC(const char *fileName) -{ - Wave wave; - - // Decode an entire FLAC file in one go - uint64_t totalSampleCount; - wave.data = drflac_open_and_decode_file_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount); - - wave.sampleCount = (int)totalSampleCount/wave.channels; - wave.sampleSize = 16; - - // NOTE: Only support up to 2 channels (mono, stereo) - if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels); - - if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName); - else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - - return wave; -} -#endif - -// Some required functions for audio standalone module version -#if defined(AUDIO_STANDALONE) -// Check file extension -bool IsFileExtension(const char *fileName, const char *ext) -{ - bool result = false; - const char *fileExt; - - if ((fileExt = strrchr(fileName, '.')) != NULL) - { - if (strcmp(fileExt, ext) == 0) result = true; - } - - return result; -} - -// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -void TraceLog(int msgType, const char *text, ...) -{ - va_list args; - va_start(args, text); - - switch (msgType) - { - case LOG_INFO: fprintf(stdout, "INFO: "); break; - case LOG_ERROR: fprintf(stdout, "ERROR: "); break; - case LOG_WARNING: fprintf(stdout, "WARNING: "); break; - case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break; - default: break; - } - - vfprintf(stdout, text, args); - fprintf(stdout, "\n"); - - va_end(args); - - if (msgType == LOG_ERROR) exit(1); -} -#endif diff --git a/raylib/audio.go b/raylib/audio.go deleted file mode 100644 index 1068816..0000000 --- a/raylib/audio.go +++ /dev/null @@ -1,340 +0,0 @@ -// +build !noaudio - -package raylib - -/* -#include "external/stb_vorbis.c" - -#include "raylib.h" -#include -*/ -import "C" -import "unsafe" -import "reflect" - -// cptr returns C pointer -func (w *Wave) cptr() *C.Wave { - return (*C.Wave)(unsafe.Pointer(w)) -} - -func (s *Sound) cptr() *C.Sound { - return (*C.Sound)(unsafe.Pointer(s)) -} - -// cptr returns C pointer -func (a *AudioStream) cptr() *C.AudioStream { - return (*C.AudioStream)(unsafe.Pointer(a)) -} - -// InitAudioDevice - Initialize audio device and context -func InitAudioDevice() { - C.InitAudioDevice() -} - -// CloseAudioDevice - Close the audio device and context -func CloseAudioDevice() { - C.CloseAudioDevice() -} - -// IsAudioDeviceReady - Check if audio device has been initialized successfully -func IsAudioDeviceReady() bool { - ret := C.IsAudioDeviceReady() - v := bool(int(ret) == 1) - return v -} - -// SetMasterVolume - Set master volume (listener) -func SetMasterVolume(volume float32) { - cvolume := (C.float)(volume) - C.SetMasterVolume(cvolume) -} - -// LoadWave - Load wave data from file into RAM -func LoadWave(fileName string) Wave { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadWave(cfileName) - v := newWaveFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadWaveEx - Load wave data from float array data (32bit) -func LoadWaveEx(data []byte, sampleCount int32, sampleRate int32, sampleSize int32, channels int32) Wave { - cdata := unsafe.Pointer(&data[0]) - csampleCount := (C.int)(sampleCount) - csampleRate := (C.int)(sampleRate) - csampleSize := (C.int)(sampleSize) - cchannels := (C.int)(channels) - ret := C.LoadWaveEx(cdata, csampleCount, csampleRate, csampleSize, cchannels) - v := newWaveFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadSound - Load sound to memory -func LoadSound(fileName string) Sound { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadSound(cfileName) - v := newSoundFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadSoundFromWave - Load sound to memory from wave data -func LoadSoundFromWave(wave Wave) Sound { - cwave := wave.cptr() - ret := C.LoadSoundFromWave(*cwave) - v := newSoundFromPointer(unsafe.Pointer(&ret)) - return v -} - -// UpdateSound - Update sound buffer with new data -func UpdateSound(sound Sound, data []byte, samplesCount int32) { - csound := sound.cptr() - cdata := unsafe.Pointer(&data[0]) - csamplesCount := (C.int)(samplesCount) - C.UpdateSound(*csound, cdata, csamplesCount) -} - -// UnloadWave - Unload wave data -func UnloadWave(wave Wave) { - cwave := wave.cptr() - C.UnloadWave(*cwave) -} - -// UnloadSound - Unload sound -func UnloadSound(sound Sound) { - csound := sound.cptr() - C.UnloadSound(*csound) -} - -// PlaySound - Play a sound -func PlaySound(sound Sound) { - csound := sound.cptr() - C.PlaySound(*csound) -} - -// PauseSound - Pause a sound -func PauseSound(sound Sound) { - csound := sound.cptr() - C.PauseSound(*csound) -} - -// ResumeSound - Resume a paused sound -func ResumeSound(sound Sound) { - csound := sound.cptr() - 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() - ret := C.IsSoundPlaying(*csound) - v := bool(int(ret) == 1) - return v -} - -// SetSoundVolume - Set volume for a sound (1.0 is max level) -func SetSoundVolume(sound Sound, volume float32) { - csound := sound.cptr() - cvolume := (C.float)(volume) - C.SetSoundVolume(*csound, cvolume) -} - -// SetSoundPitch - Set pitch for a sound (1.0 is base level) -func SetSoundPitch(sound Sound, pitch float32) { - csound := sound.cptr() - cpitch := (C.float)(pitch) - C.SetSoundPitch(*csound, cpitch) -} - -// WaveFormat - Convert wave data to desired format -func WaveFormat(wave Wave, sampleRate int32, sampleSize int32, channels int32) { - cwave := wave.cptr() - csampleRate := (C.int)(sampleRate) - csampleSize := (C.int)(sampleSize) - cchannels := (C.int)(channels) - C.WaveFormat(cwave, csampleRate, csampleSize, cchannels) -} - -// WaveCopy - Copy a wave to a new wave -func WaveCopy(wave Wave) Wave { - cwave := wave.cptr() - ret := C.WaveCopy(*cwave) - v := newWaveFromPointer(unsafe.Pointer(&ret)) - return v -} - -// WaveCrop - Crop a wave to defined samples range -func WaveCrop(wave Wave, initSample int32, finalSample int32) { - cwave := wave.cptr() - cinitSample := (C.int)(initSample) - cfinalSample := (C.int)(finalSample) - C.WaveCrop(cwave, cinitSample, cfinalSample) -} - -// GetWaveData - Get samples data from wave as a floats array -func GetWaveData(wave Wave) []float32 { - var data []float32 - cwave := wave.cptr() - ret := C.GetWaveData(*cwave) - - 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 -func LoadMusicStream(fileName string) Music { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadMusicStream(cfileName) - v := *(*Music)(unsafe.Pointer(&ret)) - return v -} - -// UnloadMusicStream - Unload music stream -func UnloadMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.UnloadMusicStream(cmusic) -} - -// PlayMusicStream - Start music playing -func PlayMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.PlayMusicStream(cmusic) -} - -// UpdateMusicStream - Updates buffers for music streaming -func UpdateMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.UpdateMusicStream(cmusic) -} - -// StopMusicStream - Stop music playing -func StopMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.StopMusicStream(cmusic) -} - -// PauseMusicStream - Pause music playing -func PauseMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.PauseMusicStream(cmusic) -} - -// ResumeMusicStream - Resume playing paused music -func ResumeMusicStream(music Music) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - C.ResumeMusicStream(cmusic) -} - -// IsMusicPlaying - Check if music is playing -func IsMusicPlaying(music Music) bool { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ret := C.IsMusicPlaying(cmusic) - v := bool(int(ret) == 1) - return v -} - -// SetMusicVolume - Set volume for music (1.0 is max level) -func SetMusicVolume(music Music, volume float32) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - cvolume := (C.float)(volume) - C.SetMusicVolume(cmusic, cvolume) -} - -// SetMusicPitch - Set pitch for a music (1.0 is base level) -func SetMusicPitch(music Music, pitch float32) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - cpitch := (C.float)(pitch) - C.SetMusicPitch(cmusic, cpitch) -} - -// SetMusicLoopCount - Set music loop count (loop repeats) -// NOTE: If set to -1, means infinite loop -func SetMusicLoopCount(music Music, count int32) { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ccount := (C.int)(count) - C.SetMusicLoopCount(cmusic, ccount) -} - -// GetMusicTimeLength - Get music time length (in seconds) -func GetMusicTimeLength(music Music) float32 { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ret := C.GetMusicTimeLength(cmusic) - v := (float32)(ret) - return v -} - -// GetMusicTimePlayed - Get current music time played (in seconds) -func GetMusicTimePlayed(music Music) float32 { - cmusic := *(*C.Music)(unsafe.Pointer(&music)) - ret := C.GetMusicTimePlayed(cmusic) - v := (float32)(ret) - return v -} - -// 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.InitAudioStream(csampleRate, csampleSize, cchannels) - v := newAudioStreamFromPointer(unsafe.Pointer(&ret)) - return v -} - -// UpdateAudioStream - Update audio stream buffers with data -func UpdateAudioStream(stream AudioStream, data []float32, samplesCount int32) { - cstream := stream.cptr() - cdata := unsafe.Pointer(&data[0]) - 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) -} - -// IsAudioBufferProcessed - Check if any audio stream buffers requires refill -func IsAudioBufferProcessed(stream AudioStream) bool { - cstream := stream.cptr() - ret := C.IsAudioBufferProcessed(*cstream) - v := bool(int(ret) == 1) - return v -} - -// PlayAudioStream - Play audio stream -func PlayAudioStream(stream AudioStream) { - cstream := stream.cptr() - C.PlayAudioStream(*cstream) -} - -// PauseAudioStream - Pause audio stream -func PauseAudioStream(stream AudioStream) { - cstream := stream.cptr() - C.PauseAudioStream(*cstream) -} - -// ResumeAudioStream - Resume audio stream -func ResumeAudioStream(stream AudioStream) { - cstream := stream.cptr() - C.ResumeAudioStream(*cstream) -} - -// StopAudioStream - Stop audio stream -func StopAudioStream(stream AudioStream) { - cstream := stream.cptr() - C.StopAudioStream(*cstream) -} diff --git a/raylib/audio.h b/raylib/audio.h deleted file mode 100644 index 01c9374..0000000 --- a/raylib/audio.h +++ /dev/null @@ -1,182 +0,0 @@ -/********************************************************************************************** -* -* raylib.audio - Basic funtionality to work with audio -* -* 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 -* -* LIMITATIONS (only OpenAL Soft): -* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) -* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) -* -* DEPENDENCIES: -* mini_al - Audio device/context management (https://github.com/dr-soft/mini_al) -* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) -* jar_xm - XM module file loading -* jar_mod - MOD audio file loading -* dr_flac - FLAC audio file loading -* -* *OpenAL Soft - Audio device management, still used on HTML5 and OSX platforms -* -* CONTRIBUTORS: -* David Reid (github: @mackron) (Nov. 2017): -* - Complete port to mini_al 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-2018 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 AUDIO_H -#define AUDIO_H - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for CAMERA_STANDALONE usage -//---------------------------------------------------------------------------------- -#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; // 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; - -// Sound source type -typedef struct Sound { - void *audioBuffer; // Pointer to internal data used by the audio system - - unsigned int source; // Audio source id - unsigned int buffer; // Audio buffer id - int format; // Audio format specifier -} Sound; - -// Music type (file streaming from memory) -// NOTE: Anything longer than ~10 seconds should be streamed -typedef struct MusicData *Music; - -// 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) - - void *audioBuffer; // Pointer to internal data used by the audio system. - - int format; // Audio format specifier - unsigned int source; // Audio source id - unsigned int buffers[2]; // Audio buffers (double buffering) -} AudioStream; - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -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 LoadWave(const char *fileName); // Load wave data from file -Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data -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 -void PlaySound(Sound sound); // Play a sound -void PauseSound(Sound sound); // Pause a sound -void ResumeSound(Sound sound); // Resume a paused sound -void StopSound(Sound sound); // Stop playing a sound -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 *GetWaveData(Wave wave); // Get samples data from wave as a floats array -Music LoadMusicStream(const char *fileName); // Load music stream from file -void UnloadMusicStream(Music music); // Unload music stream -void PlayMusicStream(Music music); // Start music 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 -bool IsMusicPlaying(Music music); // Check if music is playing -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) -void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats) -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 IsAudioBufferProcessed(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) - -#ifdef __cplusplus -} -#endif - -#endif // AUDIO_H \ No newline at end of file diff --git a/raylib/camera.go b/raylib/camera.go deleted file mode 100644 index 960cf7b..0000000 --- a/raylib/camera.go +++ /dev/null @@ -1,50 +0,0 @@ -// +build !android - -package raylib - -/* -#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 deleted file mode 100644 index 8067e7b..0000000 --- a/raylib/camera.h +++ /dev/null @@ -1,498 +0,0 @@ -/******************************************************************************************* -* -* 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: -* Marc Palau: Initial implementation (2014) -* Ramon Santamaria: Supervision, review, update and maintenance -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2015-2017 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) - // Camera modes - typedef enum { - CAMERA_CUSTOM = 0, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON - } CameraMode; - - // 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 Camera { - Vector3 position; - Vector3 target; - Vector3 up; - float fovy; - } Camera; -#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 panKey); // Set camera pan key to combine with mouse movement (free camera) -void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) -void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int frontKey, int backKey, - int rightKey, int leftKey, - int upKey, int downKey); // 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: sqrt(), sin(), cos() - -#ifndef PI - #define PI 3.14159265358979323846 -#endif - -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif - -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// 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 85.0f -#define CAMERA_FIRST_PERSON_MAX_CLAMP -85.0f - -#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.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; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static Vector2 cameraAngle = { 0.0f, 0.0f }; // TODO: Remove! Compute it in UpdateCamera() -static float cameraTargetDistance = 0.0f; // TODO: Remove! Compute it in UpdateCamera() -static float playerEyesPosition = 1.85f; // Default player eyes position from ground (in meters) - -static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' }; -static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON -static int cameraAltControlKey = 342; // raylib: KEY_LEFT_ALT -static int cameraSmoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL - -static int cameraMode = CAMERA_CUSTOM; // Current camera mode - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) -// NOTE: Camera controls depend on some raylib input functions -// TODO: Set your own input functions (used in UpdateCamera()) -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 int GetMouseWheelMove() { return 0; } -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) -{ - // TODO: cameraTargetDistance and cameraAngle should be - // calculated using camera parameters on UpdateCamera() - - 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; - - cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz); - - Vector2 distance = { 0.0f, 0.0f }; - distance.x = sqrtf(dx*dx + dz*dz); - distance.y = sqrtf(dx*dx + dy*dy); - - // Camera angle calculation - cameraAngle.x = asinf(fabsf(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - cameraAngle.y = -asinf(fabsf(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW) - - // NOTE: Just testing what cameraAngle means - //cameraAngle.x = 0.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - //cameraAngle.y = -60.0f*DEG2RAD; // Camera angle in plane XY (0 aligned with X, move positive CW) - - playerEyesPosition = camera.position.y; - - // Lock cursor for first person and third person cameras - if ((mode == CAMERA_FIRST_PERSON) || - (mode == CAMERA_THIRD_PERSON)) DisableCursor(); - else EnableCursor(); - - cameraMode = 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 cameraTargetDistance and cameraAngle here - - // Mouse movement detection - Vector2 mousePositionDelta = { 0.0f, 0.0f }; - Vector2 mousePosition = GetMousePosition(); - int mouseWheelMove = GetMouseWheelMove(); - - // Keys input detection - bool panKey = IsMouseButtonDown(cameraPanControlKey); - bool altKey = IsKeyDown(cameraAltControlKey); - bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey); - - bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]), - IsKeyDown(cameraMoveControl[MOVE_BACK]), - IsKeyDown(cameraMoveControl[MOVE_RIGHT]), - IsKeyDown(cameraMoveControl[MOVE_LEFT]), - IsKeyDown(cameraMoveControl[MOVE_UP]), - IsKeyDown(cameraMoveControl[MOVE_DOWN]) }; - - // TODO: Consider touch inputs for camera - - if (cameraMode != CAMERA_CUSTOM) - { - mousePositionDelta.x = mousePosition.x - previousMousePosition.x; - mousePositionDelta.y = mousePosition.y - previousMousePosition.y; - - previousMousePosition = mousePosition; - } - - // Support for multiple automatic camera modes - switch (cameraMode) - { - case CAMERA_FREE: - { - // Camera zoom - if ((cameraTargetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - if (cameraTargetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; - } - // Camera looking down - // TODO: Review, weird comparisson of cameraTargetDistance == 120.0f? - else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - } - 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/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - - // if (camera->target.y < 0) camera->target.y = -0.001; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) - { - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - // Camera looking up - // TODO: Review, weird comparisson of cameraTargetDistance == 120.0f? - else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - } - 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/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; - - // if (camera->target.y > 0) camera->target.y = 0.001; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) - { - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - - // Input keys checks - if (panKey) - { - if (altKey) // Alternative key behaviour - { - if (szoomKey) - { - // Camera smooth zoom - cameraTargetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); - } - else - { - // Camera rotation - cameraAngle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - cameraAngle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; - - // Angle clamp - if (cameraAngle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; - else if (cameraAngle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; - } - } - else - { - // Camera panning - camera->target.x += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); - } - } - - } break; - case CAMERA_ORBITAL: - { - cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom - - // Camera distance clamp - if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - } break; - case CAMERA_FIRST_PERSON: - case CAMERA_THIRD_PERSON: - { - camera->position.x += (sinf(cameraAngle.x)*direction[MOVE_BACK] - - sinf(cameraAngle.x)*direction[MOVE_FRONT] - - cosf(cameraAngle.x)*direction[MOVE_LEFT] + - cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] - - sinf(cameraAngle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] - - cosf(cameraAngle.x)*direction[MOVE_FRONT] + - sinf(cameraAngle.x)*direction[MOVE_LEFT] - - sinf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - bool isMoving = false; // Required for swinging - - for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; } - - // Camera orientation calculation - cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - if (cameraMode == CAMERA_THIRD_PERSON) - { - // Angle clamp - if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; - else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera zoom - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - // Camera distance clamp - if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Camera is always looking at player - camera->target.x = camera->position.x + CAMERA_THIRD_PERSON_OFFSET.x*cosf(cameraAngle.x) + CAMERA_THIRD_PERSON_OFFSET.z*sinf(cameraAngle.x); - camera->target.y = camera->position.y + CAMERA_THIRD_PERSON_OFFSET.y; - camera->target.z = camera->position.z + CAMERA_THIRD_PERSON_OFFSET.z*sinf(cameraAngle.x) - CAMERA_THIRD_PERSON_OFFSET.x*sinf(cameraAngle.x); - } - else // CAMERA_FIRST_PERSON - { - // Angle clamp - if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; - else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera is always looking at player - camera->target.x = camera->position.x - sinf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; - camera->target.y = camera->position.y + sinf(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; - camera->target.z = camera->position.z - cosf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; - - if (isMoving) swingCounter++; - - // Camera position update - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = 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; - default: break; - } - - // Update camera position with changes - if ((cameraMode == CAMERA_FREE) || - (cameraMode == CAMERA_ORBITAL) || - (cameraMode == CAMERA_THIRD_PERSON)) - { - // 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(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y; - else camera->position.y = -sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y; - camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z; - } -} - -// Set camera pan key to combine with mouse movement (free camera) -void SetCameraPanControl(int panKey) { cameraPanControlKey = panKey; } - -// Set camera alt key to combine with mouse movement (free camera) -void SetCameraAltControl(int altKey) { cameraAltControlKey = altKey; } - -// Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraSmoothZoomControl(int szKey) { cameraSmoothZoomControlKey = szKey; } - -// Set camera move controls (1st person and 3rd person cameras) -void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey) -{ - cameraMoveControl[MOVE_FRONT] = frontKey; - cameraMoveControl[MOVE_BACK] = backKey; - cameraMoveControl[MOVE_RIGHT] = rightKey; - cameraMoveControl[MOVE_LEFT] = leftKey; - cameraMoveControl[MOVE_UP] = upKey; - cameraMoveControl[MOVE_DOWN] = downKey; -} - -#endif // CAMERA_IMPLEMENTATION diff --git a/raylib/cgo.go b/raylib/cgo.go index 4d85a97..88562e0 100644 --- a/raylib/cgo.go +++ b/raylib/cgo.go @@ -1,6 +1,6 @@ -package raylib +package rl /* -#cgo CFLAGS: -std=gnu99 -Wno-missing-braces -Wno-unused-result +#cgo CFLAGS: -std=gnu99 -Wno-missing-braces -Wno-unused-result -Wno-implicit-function-declaration -Wno-int-to-pointer-cast */ import "C" diff --git a/raylib/cgo_android.go b/raylib/cgo_android.go index 161695d..11714e9 100644 --- a/raylib/cgo_android.go +++ b/raylib/cgo_android.go @@ -1,11 +1,14 @@ +//go:build android // +build android -package raylib +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 -DMAL_NO_SDL -Iexternal -Iexternal/android/native_app_glue +#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 */ import "C" diff --git a/raylib/cgo_darwin.go b/raylib/cgo_darwin.go index 8b7bf07..575fb88 100644 --- a/raylib/cgo_darwin.go +++ b/raylib/cgo_darwin.go @@ -1,12 +1,14 @@ -// +build darwin +//go:build darwin && !rgfw && !sdl && !sdl3 +// +build darwin,!rgfw,!sdl,!sdl3 -package raylib +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" @@ -15,16 +17,26 @@ package raylib #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" -#cgo darwin LDFLAGS: -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework CoreFoundation -#cgo darwin CFLAGS: -x objective-c -Iexternal -Iexternal/glfw/include -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA -Wno-deprecated-declarations -DPLATFORM_DESKTOP -DMAL_NO_COREAUDIO +GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { + return GLFW_TRUE; +} -#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 +#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 */ import "C" diff --git a/raylib/cgo_darwin_rgfw.go b/raylib/cgo_darwin_rgfw.go new file mode 100644 index 0000000..3006c24 --- /dev/null +++ b/raylib/cgo_darwin_rgfw.go @@ -0,0 +1,20 @@ +//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 new file mode 100644 index 0000000..a5d3a08 --- /dev/null +++ b/raylib/cgo_darwin_sdl.go @@ -0,0 +1,25 @@ +//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 new file mode 100644 index 0000000..c29c731 --- /dev/null +++ b/raylib/cgo_freebsd.go @@ -0,0 +1,45 @@ +//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 new file mode 100644 index 0000000..6df34b8 --- /dev/null +++ b/raylib/cgo_freebsd_rgfw.go @@ -0,0 +1,19 @@ +//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 new file mode 100644 index 0000000..cc56b7e --- /dev/null +++ b/raylib/cgo_freebsd_sdl.go @@ -0,0 +1,29 @@ +//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 393de85..453d563 100644 --- a/raylib/cgo_linux.go +++ b/raylib/cgo_linux.go @@ -1,24 +1,24 @@ -// +build linux,!arm,!arm64 +//go:build linux && !rgfw && !drm && !sdl && !sdl3 && !android +// +build linux,!rgfw,!drm,!sdl,!sdl3,!android -package raylib +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" -#ifdef _GLFW_WAYLAND +#if defined _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" #endif -#ifdef _GLFW_X11 + +#if defined _GLFW_X11 #include "external/glfw/src/x11_init.c" #include "external/glfw/src/x11_monitor.c" #include "external/glfw/src/x11_window.c" @@ -26,22 +26,33 @@ package raylib #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" -#cgo linux CFLAGS: -Iexternal -Iexternal/glfw/include -DPLATFORM_DESKTOP +GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { + return GLFW_TRUE; +} -#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 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,!wayland CFLAGS: -D_GLFW_X11 +#cgo linux,x11 CFLAGS: -D_GLFW_X11 #cgo linux,wayland CFLAGS: -D_GLFW_WAYLAND +#cgo linux,!x11,!wayland CFLAGS: -D_GLFW_X11 -D_GLFW_WAYLAND -#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 +#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 */ import "C" diff --git a/raylib/cgo_linux_arm.go b/raylib/cgo_linux_arm.go deleted file mode 100644 index 1b5f4ee..0000000 --- a/raylib/cgo_linux_arm.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build linux,arm,!android - -package raylib - -/* -#cgo linux,arm LDFLAGS: -L/opt/vc/lib -L/opt/vc/lib64 -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -lvcos -lvchiq_arm -ldl -#cgo linux,arm CFLAGS: -DPLATFORM_RPI -DGRAPHICS_API_OPENGL_ES2 -Iexternal -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_drm.go b/raylib/cgo_linux_drm.go new file mode 100644 index 0000000..66d07e4 --- /dev/null +++ b/raylib/cgo_linux_drm.go @@ -0,0 +1,11 @@ +//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 +#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 +*/ +import "C" diff --git a/raylib/cgo_linux_drm_leasing.go b/raylib/cgo_linux_drm_leasing.go new file mode 100644 index 0000000..b56afc0 --- /dev/null +++ b/raylib/cgo_linux_drm_leasing.go @@ -0,0 +1,11 @@ +//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 new file mode 100644 index 0000000..bd04a7f --- /dev/null +++ b/raylib/cgo_linux_drm_leasing_no_keyboard.go @@ -0,0 +1,11 @@ +//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 new file mode 100644 index 0000000..12c329d --- /dev/null +++ b/raylib/cgo_linux_drm_no_keyboard.go @@ -0,0 +1,11 @@ +//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 new file mode 100644 index 0000000..7585836 --- /dev/null +++ b/raylib/cgo_linux_rgfw.go @@ -0,0 +1,20 @@ +//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_sdl.go b/raylib/cgo_linux_sdl.go new file mode 100644 index 0000000..cde87da --- /dev/null +++ b/raylib/cgo_linux_sdl.go @@ -0,0 +1,27 @@ +//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 new file mode 100644 index 0000000..a40ee1c --- /dev/null +++ b/raylib/cgo_openbsd.go @@ -0,0 +1,45 @@ +//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 new file mode 100644 index 0000000..11441dc --- /dev/null +++ b/raylib/cgo_openbsd_rgfw.go @@ -0,0 +1,19 @@ +//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 new file mode 100644 index 0000000..4fe5e5a --- /dev/null +++ b/raylib/cgo_openbsd_sdl.go @@ -0,0 +1,29 @@ +//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 new file mode 100644 index 0000000..87308cb --- /dev/null +++ b/raylib/cgo_vendor.go @@ -0,0 +1,12 @@ +//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 6615cc2..c2cd044 100644 --- a/raylib/cgo_windows.go +++ b/raylib/cgo_windows.go @@ -1,17 +1,20 @@ -// +build windows +//go:build windows && !rgfw && !sdl && !sdl3 +// +build windows,!rgfw,!sdl,!sdl3 -package raylib +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/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" @@ -20,11 +23,20 @@ package raylib #include "external/glfw/src/egl_context.c" #include "external/glfw/src/osmesa_context.c" -#cgo windows LDFLAGS: -lopengl32 -lgdi32 -lwinmm -lole32 -#cgo windows CFLAGS: -D_GLFW_WIN32 -Iexternal -Iexternal/glfw/include -Iexternal/glfw/deps/mingw -DPLATFORM_DESKTOP +GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { + return GLFW_TRUE; +} -#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 +#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 */ import "C" diff --git a/raylib/cgo_windows_rgfw.go b/raylib/cgo_windows_rgfw.go new file mode 100644 index 0000000..eea463d --- /dev/null +++ b/raylib/cgo_windows_rgfw.go @@ -0,0 +1,19 @@ +//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 new file mode 100644 index 0000000..58d53a4 --- /dev/null +++ b/raylib/cgo_windows_sdl.go @@ -0,0 +1,25 @@ +//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 new file mode 100644 index 0000000..3cd0337 --- /dev/null +++ b/raylib/compat.go @@ -0,0 +1,98 @@ +//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 new file mode 100644 index 0000000..1c362fb --- /dev/null +++ b/raylib/compat_compat.go @@ -0,0 +1,69 @@ +//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 8e6f74c..c0d50cd 100644 --- a/raylib/config.h +++ b/raylib/config.h @@ -6,7 +6,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2018 Ahmad Fatoum & Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2025 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,118 +25,278 @@ * **********************************************************************************************/ -#define RAYLIB_VERSION "2.0-dev" - -// Edit to control what features Makefile'd raylib is compiled with -#if defined(RAYLIB_CMAKE) - // Edit CMakeOptions.txt for CMake instead - #include "cmake/config.h" -#else +#ifndef CONFIG_H +#define CONFIG_H //------------------------------------------------------------------------------------ -// Module: core - Configuration Flags +// Module selection - Some modules could be avoided +// Mandatory modules: rcore, rlgl, utils //------------------------------------------------------------------------------------ -// 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 +#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 // Mouse gestures are directly mapped like touches and processed by gestures system -#define SUPPORT_MOUSE_GESTURES 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 +#define SUPPORT_MOUSE_GESTURES 1 +// Reconfigure standard input to receive key inputs, works with SSH connection. +//#define SUPPORT_SSH_KEYBOARD_RPI 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 +// 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 // 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 + +// 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 +#endif + + +// 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 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_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 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 +#endif +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9 + + +// 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) //------------------------------------------------------------------------------------ -// Module: rlgl - Configuration Flags +// Module: rshapes - Configuration Flags //------------------------------------------------------------------------------------ -// Support VR simulation functionality (stereo rendering) -#define SUPPORT_VR_SIMULATOR 1 -// Include stereo rendering distortion shader (shader_distortion.h) -#define SUPPORT_DISTORTION_SHADER 1 - - -//------------------------------------------------------------------------------------ -// Module: shapes - Configuration Flags -//------------------------------------------------------------------------------------ -// Draw rectangle shapes using font texture white character instead of default white texture -// Allows drawing rectangles and text with a single draw call, very useful for GUI systems! -#define SUPPORT_FONT_TEXTURE // Use QUADS instead of TRIANGLES for drawing when possible // Some lines-based shapes could still use lines -#define SUPPORT_QUADS_DRAW_MODE +#define SUPPORT_QUADS_DRAW_MODE 1 + +// rshapes: Configuration values +//------------------------------------------------------------------------------------ +#define SPLINE_SEGMENT_DIVISIONS 24 // Spline segments subdivisions + //------------------------------------------------------------------------------------ -// Module: textures - Configuration Flags +// Module: rtextures - 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_TGA 1 -//#define SUPPORT_FILEFORMAT_JPG 1 -//#define SUPPORT_FILEFORMAT_GIF 1 -//#define SUPPORT_FILEFORMAT_PSD 1 +#define SUPPORT_FILEFORMAT_BMP 1 +//#define SUPPORT_FILEFORMAT_TGA 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_KTX 1 -#define SUPPORT_FILEFORMAT_ASTC 1 -//#define SUPPORT_FILEFORMAT_PKM 1 -//#define SUPPORT_FILEFORMAT_PVR 1 +//#define SUPPORT_FILEFORMAT_HDR 1 +//#define SUPPORT_FILEFORMAT_PIC 1 +//#define SUPPORT_FILEFORMAT_KTX 1 +//#define SUPPORT_FILEFORMAT_ASTC 1 +//#define SUPPORT_FILEFORMAT_PKM 1 +//#define SUPPORT_FILEFORMAT_PVR 1 -// 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_MANIPULATION 1 -// Support proedural image generation functionality (gradient, spot, perlin-noise, cellular) -#define SUPPORT_IMAGE_GENERATION 1 +// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) +#define SUPPORT_IMAGE_EXPORT 1 +// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) +#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 //------------------------------------------------------------------------------------ -// Module: text - Configuration Flags +// Module: rtext - 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_FNT 1 -#define SUPPORT_FILEFORMAT_TTF 1 +#define SUPPORT_FILEFORMAT_TTF 1 +#define SUPPORT_FILEFORMAT_FNT 1 +#define SUPPORT_FILEFORMAT_BDF 1 + +// Support text management functions +// If not defined, still some functions are supported: TextLength(), TextFormat() +#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 +//------------------------------------------------------------------------------------ +#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() //------------------------------------------------------------------------------------ -// Module: models - Configuration Flags +// Module: rmodels - Configuration Flags //------------------------------------------------------------------------------------ // Selected desired model fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_OBJ 1 -#define SUPPORT_FILEFORMAT_MTL 1 +#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 // 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: audio - Configuration Flags +// Module: raudio - Configuration Flags //------------------------------------------------------------------------------------ // Desired audio fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_WAV 1 -#define SUPPORT_FILEFORMAT_OGG 1 -#define SUPPORT_FILEFORMAT_XM 1 -#define SUPPORT_FILEFORMAT_MOD 1 -//#define SUPPORT_FILEFORMAT_FLAC 1 -//#define SUPPORT_FILEFORMAT_MP3 1 +#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 +// raudio: Configuration values +//------------------------------------------------------------------------------------ +#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit) +#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo +#define AUDIO_DEVICE_SAMPLE_RATE 0 // Device sample rate (device default) + +#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels //------------------------------------------------------------------------------------ // Module: utils - Configuration Flags //------------------------------------------------------------------------------------ -// Show TraceLog() output messages +// Standard file io library (stdio.h) included +#define SUPPORT_STANDARD_FILEIO 1 +// Show TRACELOG() output messages // NOTE: By default LOG_DEBUG traces not shown -#define SUPPORT_TRACELOG 1 -// Support saving image data fileformats -// NOTE: Requires stb_image_write library -#define SUPPORT_SAVE_PNG 1 -//#define SUPPORT_SAVE_BMP 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 //defined(RAYLIB_CMAKE) +#endif // CONFIG_H diff --git a/raylib/core.c b/raylib/core.c deleted file mode 100644 index 91ff1a9..0000000 --- a/raylib/core.c +++ /dev/null @@ -1,3871 +0,0 @@ -/********************************************************************************************** -* -* 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 (X11 desktop) -* - PLATFORM_DESKTOP: OSX/macOS -* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64) -* - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian) -* - 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 -* 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_BUSY_WAIT_LOOP -* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used -* -* #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() -* -* DEPENDENCIES: -* rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD) -* 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) 2014-2018 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 "config.h" // Defines module configuration flags -#include "raylib.h" // Declares module functions - -#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 - -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 -#include "utils.h" // Required for: fopen() Android mapping - -#if defined(SUPPORT_GESTURES_SYSTEM) - #define GESTURES_IMPLEMENTATION - #include "gestures.h" // Gestures detection functionality -#endif - -#if defined(SUPPORT_CAMERA_SYSTEM) && !defined(PLATFORM_ANDROID) - #define CAMERA_IMPLEMENTATION - #include "camera.h" // Camera system functionality -#endif - -#if defined(SUPPORT_GIF_RECORDING) - #define RGIF_IMPLEMENTATION - #include "external/rgif.h" // Support GIF recording -#endif - -#include // Standard input / output lib -#include // Required for: malloc(), free(), rand(), atexit() -#include // Required for: typedef unsigned long long int uint64_t, used by hi-res timer -#include // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!) -#include // Required for: tan() [Used in BeginMode3D() to set perspective] -#include // Required for: strrchr(), strcmp() -//#include // Macros for reporting and retrieving error conditions through error codes -#include // Required for: tolower() [Used in IsFileExtension()] - -#if defined(_WIN32) - #include // Required for: _getch(), _chdir() - #define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir() - #define CHDIR _chdir -#else - #include "unistd.h" // Required for: getch(), chdir() (POSIX) - #define GETCWD getcwd - #define CHDIR chdir -#endif - -#if defined(__linux__) || defined(PLATFORM_WEB) - #include // Required for: timespec, nanosleep(), select() - POSIX -#elif defined(__APPLE__) - #include // Required for: usleep() -#endif - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 - #include // GLFW3 library: Windows, OpenGL context and Input management - // NOTE: GLFW3 already includes gl.h (OpenGL) headers - - #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - // 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(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 // Khronos EGL library - Native platform display device control functions - #include // Khronos OpenGL ES 2.0 library -#endif - -#if defined(PLATFORM_RPI) - #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 (mouse input) - - #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 - - #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions - - #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions - #include "EGL/eglext.h" // Khronos EGL library - Extensions - #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library -#endif - -#if defined(PLATFORM_UWP) - #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions - #include "EGL/eglext.h" // Khronos EGL library - Extensions - #include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library -#endif - -#if defined(PLATFORM_WEB) - #include - #include -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#if defined(PLATFORM_RPI) - // Old device inputs system - #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input - #define DEFAULT_MOUSE_DEV "/dev/input/mouse0" // Mouse input - #define DEFAULT_TOUCH_DEV "/dev/input/event4" // Touch input virtual device (created by ts_uinput) - #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) - - // New device input events (evdev) (must be detected) - //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" - //#define DEFAULT_MOUSE_DEV "/dev/input/eventN" - //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN" - - #define MOUSE_SENSITIVITY 0.8f -#endif - -#define MAX_GAMEPADS 4 // Max number of gamepads supported -#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) -#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) - -#define STORAGE_FILENAME "storage.data" - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) -static GLFWwindow *window; // Native window (graphic device) -#endif - -static bool windowReady = false; // Check if window has been initialized successfully -static bool windowMinimized = false; // Check if window has been minimized -static const char *windowTitle = NULL; // Window text title... - -#if defined(PLATFORM_ANDROID) -static struct android_app *androidApp; // Android activity -static struct android_poll_source *source; // Android events polling source -static int ident, events; // Android ALooper_pollAll() variables -static const char *internalDataPath; // Android internal data path to write data (/data/data//files) - -static bool appEnabled = true; // Used to detec if app is active -static bool contextRebindRequired = false; // Used to know context rebind required -#endif - -#if defined(PLATFORM_RPI) -static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device) - -// Keyboard input variables -// NOTE: For keyboard we will use the standard input (but reconfigured...) -static struct termios defaultKeyboardSettings; // Used to store default keyboard settings -static int defaultKeyboardMode; // Used to store default keyboard mode - -// Mouse input variables -static int mouseStream = -1; // Mouse device file descriptor -static bool mouseReady = false; // Flag to know if mouse is ready -static pthread_t mouseThreadId; // Mouse reading thread id - -// Touch input variables -static int touchStream = -1; // Touch device file descriptor -static bool touchReady = false; // Flag to know if touch interface is ready -static pthread_t touchThreadId; // Touch reading thread id - -// Gamepad input variables -static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor -static pthread_t gamepadThreadId; // Gamepad reading thread id -static char gamepadName[64]; // Gamepad name holder -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) -static EGLDisplay display; // Native display device (physical screen connection) -static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) -static EGLContext context; // Graphic context, mode in which drawing can be done -static EGLConfig config; // Graphic config -static uint64_t baseTime; // Base time measure for hi-res timer -static bool windowShouldClose = false; // Flag to set window for closing -#endif - -#if defined(PLATFORM_UWP) -extern EGLNativeWindowType uwpWindow; // Native EGL window handler for UWP (external, defined in UWP App) -#endif - -// Screen related variables -static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) -static int screenWidth, screenHeight; // Screen width and height (used render area) -static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required) -static int renderOffsetX = 0; // Offset X from render area (must be divided by 2) -static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2) -static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) -static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) - -static bool cursorHidden = false; // Track if cursor is hidden -static bool cursorOnScreen = false; // Tracks if cursor is inside client area - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) -// Register mouse states -static char previousMouseState[3] = { 0 }; // Registers previous mouse button state -static char currentMouseState[3] = { 0 }; // Registers current mouse button state -static int previousMouseWheelY = 0; // Registers previous mouse wheel variation -static int currentMouseWheelY = 0; // Registers current mouse wheel variation - -// Register gamepads states -static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready -static float gamepadAxisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state -static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state -static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state - -// Keyboard configuration -static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -#endif - -// Register keyboard states -static char previousKeyState[512] = { 0 }; // Registers previous frame key state -static char currentKeyState[512] = { 0 }; // Registers current frame key state - -static int lastKeyPressed = -1; // Register last key pressed -static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed -static int gamepadAxisCount = 0; // Register number of available gamepad axis - -static Vector2 mousePosition; // Mouse position on screen -static float mouseScale = 1.0f; // Mouse default scale - -#if defined(PLATFORM_WEB) -static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click -#endif - -static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen - -#if defined(PLATFORM_DESKTOP) -static char **dropFilesPath; // Store dropped files paths as strings -static int dropFilesCount = 0; // Count stored strings -#endif - -static double currentTime = 0.0; // Current time measure -static double previousTime = 0.0; // Previous time measure -static double updateTime = 0.0; // Time measure for frame update -static double drawTime = 0.0; // Time measure for frame draw -static double frameTime = 0.0; // Time measure for one frame -static double targetTime = 0.0; // Desired time for one frame, if 0 not applied - -static unsigned char configFlags = 0; // Configuration flags (bit based) -static bool showLogo = false; // Track if showing logo at init is enabled - -#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 -#endif - -//---------------------------------------------------------------------------------- -// Other Modules Functions Declaration (required by core) -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_DEFAULT_FONT) -extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow() -extern void UnloadDefaultFont(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 SetupFramebufferSize(int displayWidth, int displayHeight); -static void InitTimer(void); // Initialize timer -static void Wait(float ms); // Wait for some milliseconds (stop program execution) -static bool GetKeyStatus(int key); // Returns if a key has been pressed -static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed -static void PollInputEvents(void); // Register user events -static void SwapBuffers(void); // Copy back buffer to front buffers -static void LogoAnimation(void); // Plays raylib logo appearing animation -static void SetupViewport(void); // Set viewport parameters - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) -static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed -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 CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value) -static void ScrollCallback(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 -static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized -static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored -#endif - -#if defined(PLATFORM_DESKTOP) -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window -#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 EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData); -static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); -static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); -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) -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 -static void InitMouse(void); // Mouse initialization (including mouse thread) -static void *MouseThread(void *arg); // Mouse reading thread -static void InitTouch(void); // Touch device initialization (including touch thread) -static void *TouchThread(void *arg); // Touch device reading thread -static void InitGamepad(void); // Init raw gamepad input -static void *GamepadThread(void *arg); // Mouse reading thread -#endif - -#if defined(PLATFORM_UWP) -// TODO: Define functions required to manage inputs -#endif - -#if defined(_WIN32) - // NOTE: We include Sleep() function signature here to avoid windows.h inclusion - 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 - androidApp = 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 androidApp; -} -#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) -{ - TraceLog(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION); - - windowTitle = title; -#if defined(PLATFORM_ANDROID) - screenWidth = width; - screenHeight = height; - - // Input data is android app pointer - internalDataPath = androidApp->activity->internalDataPath; - - // Set desired windows flags before initializing anything - ANativeActivity_setWindowFlags(androidApp->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER - //ANativeActivity_setWindowFlags(androidApp->activity, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN, AWINDOW_FLAG_FULLSCREEN); - - int orientation = AConfiguration_getOrientation(androidApp->config); - - if (orientation == ACONFIGURATION_ORIENTATION_PORT) TraceLog(LOG_INFO, "PORTRAIT window orientation"); - else if (orientation == ACONFIGURATION_ORIENTATION_LAND) TraceLog(LOG_INFO, "LANDSCAPE window orientation"); - - // TODO: Automatic orientation doesn't seem to work - if (width <= height) - { - AConfiguration_setOrientation(androidApp->config, ACONFIGURATION_ORIENTATION_PORT); - TraceLog(LOG_WARNING, "Window set to portraid mode"); - } - else - { - AConfiguration_setOrientation(androidApp->config, ACONFIGURATION_ORIENTATION_LAND); - TraceLog(LOG_WARNING, "Window set to landscape mode"); - } - - //AConfiguration_getDensity(androidApp->config); - //AConfiguration_getKeyboard(androidApp->config); - //AConfiguration_getScreenSize(androidApp->config); - //AConfiguration_getScreenLong(androidApp->config); - - androidApp->onAppCmd = AndroidCommandCallback; - androidApp->onInputEvent = AndroidInputCallback; - - InitAssetManager(androidApp->activity->assetManager); - - TraceLog(LOG_INFO, "Android app initialized successfully"); - - // Wait for window to be initialized (display and context) - while (!windowReady) - { - // Process events loop - while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) - { - // Process this event - if (source != NULL) source->process(androidApp, source); - - // NOTE: Never close window, native activity is controlled by the system! - //if (androidApp->destroyRequested != 0) windowShouldClose = true; - } - } -#else - // Init graphics device (display device and OpenGL context) - // NOTE: returns true if window and graphic device has been initialized successfully - windowReady = InitGraphicsDevice(width, height); - if (!windowReady) return; - - // Init hi-res timer - InitTimer(); - -#if defined(SUPPORT_DEFAULT_FONT) - // Load default font - // NOTE: External function (defined in module: text) - LoadDefaultFont(); -#endif - -#if defined(PLATFORM_RPI) - // Init raw input system - InitMouse(); // Mouse init - InitTouch(); // Touch init - InitKeyboard(); // Keyboard init - InitGamepad(); // Gamepad init -#endif - -#if defined(PLATFORM_WEB) - emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); - - // Support keyboard events - emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); - - // Support mouse events - emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback); - - // 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); - //emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch); - //emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); - - // Support gamepad events (not provided by GLFW3 on emscripten) - emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback); - emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); -#endif - - mousePosition.x = (float)screenWidth/2.0f; - mousePosition.y = (float)screenHeight/2.0f; - - // raylib logo appearing animation (if enabled) - if (showLogo) - { - SetTargetFPS(60); - LogoAnimation(); - } -#endif // defined(PLATFORM_ANDROID) -} - -// Close window and unload OpenGL context -void CloseWindow(void) -{ -#if defined(SUPPORT_GIF_RECORDING) - if (gifRecording) - { - GifEnd(); - gifRecording = false; - } -#endif - -#if defined(SUPPORT_DEFAULT_FONT) - UnloadDefaultFont(); -#endif - - rlglClose(); // De-init rlgl - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwDestroyWindow(window); - glfwTerminate(); -#endif - -#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - timeEndPeriod(1); // Restore time period -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - // Close surface, context and display - if (display != EGL_NO_DISPLAY) - { - eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (surface != EGL_NO_SURFACE) - { - eglDestroySurface(display, surface); - surface = EGL_NO_SURFACE; - } - - if (context != EGL_NO_CONTEXT) - { - eglDestroyContext(display, context); - context = EGL_NO_CONTEXT; - } - - eglTerminate(display); - display = EGL_NO_DISPLAY; - } -#endif - -#if defined(PLATFORM_RPI) - // 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 windowShouldClose variable - - windowShouldClose = true; // Added to force threads to exit when the close window is called - - pthread_join(mouseThreadId, NULL); - pthread_join(touchThreadId, NULL); - pthread_join(gamepadThreadId, NULL); -#endif - - TraceLog(LOG_INFO, "Window closed successfully"); -} - -// Check if window has been initialized successfully -bool IsWindowReady(void) -{ - return windowReady; -} - -// Check if KEY_ESCAPE pressed or Close icon pressed -bool WindowShouldClose(void) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - if (windowReady) - { - // While window minimized, stop loop execution - while (windowMinimized) glfwWaitEvents(); - - return (glfwWindowShouldClose(window)); - } - else return true; -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - if (windowReady) return windowShouldClose; - else return true; -#endif -} - -// Check if window has been minimized (or lost focus) -bool IsWindowMinimized(void) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) - return windowMinimized; -#else - return false; -#endif -} - -// Toggle fullscreen mode (only PLATFORM_DESKTOP) -void ToggleFullscreen(void) -{ -#if defined(PLATFORM_DESKTOP) - fullscreen = !fullscreen; // Toggle fullscreen flag - - // NOTE: glfwSetWindowMonitor() doesn't work properly (bugs) - if (fullscreen) glfwSetWindowMonitor(window, glfwGetPrimaryMonitor(), 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); - else glfwSetWindowMonitor(window, NULL, 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) - TraceLog(LOG_WARNING, "Could not toggle to windowed mode"); -#endif -} - -// Set icon for window (only PLATFORM_DESKTOP) -void SetWindowIcon(Image image) -{ -#if defined(PLATFORM_DESKTOP) - ImageFormat(&image, UNCOMPRESSED_R8G8B8A8); - - GLFWimage icon[1]; - - icon[0].width = image.width; - icon[0].height = image.height; - icon[0].pixels = (unsigned char *)image.data; - - // NOTE: We only support one image icon - glfwSetWindowIcon(window, 1, icon); - - // TODO: Support multi-image icons --> image.mipmaps -#endif -} - -// Set title for window (only PLATFORM_DESKTOP) -void SetWindowTitle(const char *title) -{ -#if defined(PLATFORM_DESKTOP) - glfwSetWindowTitle(window, title); -#endif -} - -// Set window position on screen (windowed mode) -void SetWindowPosition(int x, int y) -{ -#if defined(PLATFORM_DESKTOP) - glfwSetWindowPos(window, x, y); -#endif -} - -// Set monitor for the current window (fullscreen mode) -void SetWindowMonitor(int monitor) -{ -#if defined(PLATFORM_DESKTOP) - int monitorCount; - GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) - { - //glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); - TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); - } - else TraceLog(LOG_WARNING, "Selected monitor not found"); -#endif -} - -// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) -void SetWindowMinSize(int width, int height) -{ -#if defined(PLATFORM_DESKTOP) - const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - glfwSetWindowSizeLimits(window, width, height, mode->width, mode->height); -#endif -} - -// Set window dimensions -void SetWindowSize(int width, int height) -{ -#if defined(PLATFORM_DESKTOP) - glfwSetWindowSize(window, width, height); -#endif -} - -// Get current screen width -int GetScreenWidth(void) -{ - return screenWidth; -} - -// Get current screen height -int GetScreenHeight(void) -{ - return screenHeight; -} - -// Show mouse cursor -void ShowCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif - cursorHidden = false; -} - -// Hides mouse cursor -void HideCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#endif - cursorHidden = true; -} - -// Check if cursor is not visible -bool IsCursorHidden() -{ - return cursorHidden; -} - -// Enables cursor (unlock cursor) -void EnableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif -#if defined(PLATFORM_WEB) - toggleCursorLock = true; -#endif - cursorHidden = false; -} - -// Disables cursor (lock cursor) -void DisableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif -#if defined(PLATFORM_WEB) - toggleCursorLock = true; -#endif - cursorHidden = true; -} - -// 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) -{ - currentTime = GetTime(); // Number of elapsed seconds since InitTimer() - updateTime = currentTime - previousTime; - previousTime = currentTime; - - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here - - //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) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - -#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 very slow... :( - unsigned char *screenData = rlReadScreenPixels(screenWidth, screenHeight); - GifWriteFrame(screenData, screenWidth, screenHeight, 10, 8, false); - - free(screenData); // Free image data - } - - if (((gifFramesCounter/15)%2) == 1) - { - DrawCircle(30, screenHeight - 20, 10, RED); - DrawText("RECORDING", 50, screenHeight - 25, 10, MAROON); - } - - rlglDraw(); // Draw RECORDING message - } -#endif - - SwapBuffers(); // Copy back buffer to front buffer - PollInputEvents(); // Poll user events - - // Frame time control system - currentTime = GetTime(); - drawTime = currentTime - previousTime; - previousTime = currentTime; - - frameTime = updateTime + drawTime; - - // Wait for some milliseconds... - if (frameTime < targetTime) - { - Wait((targetTime - frameTime)*1000.0f); - - currentTime = GetTime(); - double extraTime = currentTime - previousTime; - previousTime = currentTime; - - frameTime += extraTime; - } -} - -// Initialize 2D mode with custom camera (2D) -void BeginMode2D(Camera2D camera) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - - // Camera rotation and scaling is always relative to 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.target.x, camera.offset.y + camera.target.y, 0.0f); - - Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); - - rlMultMatrixf(MatrixToFloat(matTransform)); -} - -// Ends 2D mode with custom camera -void EndMode2D(void) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - rlLoadIdentity(); // Reset current matrix (MODELVIEW) -} - -// Initializes 3D mode with custom camera (3D) -void BeginMode3D(Camera3D camera) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - 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)screenWidth/(float)screenHeight; - - if (camera.type == CAMERA_PERSPECTIVE) - { - // Setup perspective projection - double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); - double right = top*aspect; - - rlFrustum(-right, right, -top, top, 0.01, 1000.0); - } - else if (camera.type == CAMERA_ORTHOGRAPHIC) - { - // Setup orthographic projection - double top = camera.fovy/2.0; - double right = top*aspect; - - rlOrtho(-right,right,-top,top, 0.01, 1000.0); - } - - // NOTE: zNear and zFar values are important when computing depth buffer values - - 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) -{ - rlglDraw(); // Process internal buffers (update + draw) - - rlMatrixMode(RL_PROJECTION); // Switch to projection matrix - rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack - - rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - - rlDisableDepthTest(); // Disable DEPTH_TEST for 2D -} - -// Initializes render texture for drawing -void BeginTextureMode(RenderTexture2D target) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - rlEnableRenderTexture(target.id); // Enable render target - - rlClearScreenBuffers(); // Clear render texture buffers - - // 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 (?) -} - -// Ends drawing to render texture -void EndTextureMode(void) -{ - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - rlDisableRenderTexture(); // Disable render target - - // Set viewport to default framebuffer size (screen size) - SetupViewport(); - - 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, GetScreenWidth(), GetScreenHeight(), 0, 0.0f, 1.0f); - - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) -} - -// Returns a ray trace from mouse position -Ray GetMouseRay(Vector2 mousePosition, Camera camera) -{ - Ray ray; - - // Calculate normalized device coordinates - // NOTE: y value is negative - float x = (2.0f*mousePosition.x)/(float)GetScreenWidth() - 1.0f; - float y = 1.0f - (2.0f*mousePosition.y)/(float)GetScreenHeight(); - float z = 1.0f; - - // Store values in a vector - Vector3 deviceCoords = { x, y, z }; - - TraceLog(LOG_DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); - - // Calculate view matrix from camera look at - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - - Matrix matProj; - - if (camera.type == CAMERA_PERSPECTIVE) - { - // Calculate projection matrix from perspective - matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); - } - else if (camera.type == CAMERA_ORTHOGRAPHIC) - { - float aspect = (float)screenWidth/(float)screenHeight; - 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 = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); - Vector3 farPoint = rlUnproject((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 = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); - - // Calculate normalized direction vector - Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint)); - - if (camera.type == CAMERA_PERSPECTIVE) ray.position = camera.position; - else if (camera.type == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos; - - // Apply calculated vectors to ray - ray.direction = direction; - - return ray; -} - -// Returns the screen space position from a 3d world space position -Vector2 GetWorldToScreen(Vector3 position, Camera camera) -{ - // Calculate projection matrix (from perspective instead of frustum - Matrix matProj; - - if(camera.type == CAMERA_PERSPECTIVE) - { - // Calculate projection matrix from perspective - matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); - } - else if(camera.type == CAMERA_ORTHOGRAPHIC) - { - float aspect = (float)screenWidth/(float)screenHeight; - 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); - } - - // 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)GetScreenWidth(), (ndcPos.y + 1.0f)/2.0f*(float)GetScreenHeight() }; - - return screenPosition; -} - -// Get transform matrix for camera -Matrix GetCameraMatrix(Camera camera) -{ - return MatrixLookAt(camera.position, camera.target, camera.up); -} - -// Set target FPS (maximum) -void SetTargetFPS(int fps) -{ - if (fps < 1) targetTime = 0.0; - else targetTime = 1.0/(double)fps; - - TraceLog(LOG_INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000); -} - -// Returns current FPS -int GetFPS(void) -{ - return (int)(1.0f/GetFrameTime()); -} - -// Returns time in seconds for last frame drawn -float GetFrameTime(void) -{ - // NOTE: We round value to milliseconds - return (float)frameTime; -} - -// 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) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t time = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec; - - return (double)(time - baseTime)*1e-9; // Elapsed time since InitTimer() -#endif -} - -// Returns hexadecimal value for a Color -int ColorToInt(Color color) -{ - return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); -} - -// Returns color normalized as float [0..1] -Vector4 ColorNormalize(Color color) -{ - Vector4 result; - - result.x = (float)color.r/255.0f; - result.y = (float)color.g/255.0f; - result.z = (float)color.b/255.0f; - result.w = (float)color.a/255.0f; - - return result; -} - -// Returns HSV values for a Color -// NOTE: Hue is returned as degrees [0..360] -Vector3 ColorToHSV(Color color) -{ - Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - Vector3 hsv = { 0.0f, 0.0f, 0.0f }; - float min, max, delta; - - 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 = NAN; // Undefined - 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; -} - -// 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; - - return color; -} - - - -// 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); -} - -// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -Color Fade(Color color, float alpha) -{ - if (alpha < 0.0f) alpha = 0.0f; - else if (alpha > 1.0f) alpha = 1.0f; - - return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)}; -} - -// Activate raylib logo at startup (can be done with flags) -void ShowLogo(void) -{ - showLogo = true; -} - -// Setup window configuration flags (view FLAGS) -void SetConfigFlags(unsigned char flags) -{ - configFlags = flags; - - if (configFlags & FLAG_SHOW_LOGO) showLogo = true; - if (configFlags & FLAG_FULLSCREEN_MODE) fullscreen = true; -} - -// NOTE TraceLog() function is located in [utils.h] - -// Takes a screenshot of current screen (saved a .png) -void TakeScreenshot(const char *fileName) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) - unsigned char *imgData = rlReadScreenPixels(renderWidth, renderHeight); - SavePNG(fileName, imgData, renderWidth, renderHeight, 4); // Save image as PNG - free(imgData); - - TraceLog(LOG_INFO, "Screenshot taken: %s", fileName); -#endif -} - -// Check file extension -bool IsFileExtension(const char *fileName, const char *ext) -{ - bool result = false; - const char *fileExt; - - if ((fileExt = strrchr(fileName, '.')) != NULL) - { - #if defined(_WIN32) - result = true; - int extLen = strlen(ext); - - if (strlen(fileExt) == extLen) - { - for (int i = 0; i < extLen; i++) - { - if (tolower(fileExt[i]) != tolower(ext[i])) - { - result = false; - break; - } - } - } - #else - if (strcmp(fileExt, ext) == 0) result = true; - #endif - } - - return result; -} - -// Get pointer to extension for a filename string -const char *GetExtension(const char *fileName) -{ - const char *dot = strrchr(fileName, '.'); - - if (!dot || dot == fileName) return NULL; - - return (dot + 1); -} - -// Get pointer to filename for a path string -const char *GetFileName(const char *filePath) -{ - const char *fileName = strrchr(filePath, '\\'); - - if (!fileName || fileName == filePath) return filePath; - - return fileName + 1; -} - - -// Get directory for a given fileName (with path) -const char *GetDirectoryPath(const char *fileName) -{ - char *lastSlash = NULL; - static char filePath[256]; // MAX_DIRECTORY_PATH_SIZE = 256 - memset(filePath, 0, 256); - - lastSlash = strrchr(fileName, '\\'); - strncpy(filePath, fileName, strlen(fileName) - (strlen(lastSlash) - 1)); - filePath[strlen(fileName) - strlen(lastSlash)] = '\0'; - - return filePath; -} - -// Get current working directory -const char *GetWorkingDirectory(void) -{ - static char currentDir[256]; // MAX_DIRECTORY_PATH_SIZE = 256 - memset(currentDir, 0, 256); - - GETCWD(currentDir, 256 - 1); - - return currentDir; -} - -// Change working directory, returns true if success -bool ChangeDirectory(const char *dir) -{ - return (CHDIR(dir) == 0); -} - -// Check if a file has been dropped into window -bool IsFileDropped(void) -{ -#if defined(PLATFORM_DESKTOP) - if (dropFilesCount > 0) return true; - else return false; -#else - return false; -#endif -} - -// Get dropped files names -char **GetDroppedFiles(int *count) -{ -#if defined(PLATFORM_DESKTOP) - *count = dropFilesCount; - return dropFilesPath; -#else - return NULL; -#endif -} - -// Clear dropped files paths buffer -void ClearDroppedFiles(void) -{ -#if defined(PLATFORM_DESKTOP) - if (dropFilesCount > 0) - { - for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]); - - free(dropFilesPath); - - dropFilesCount = 0; - } -#endif -} - -// Save integer value to storage file (to defined position) -// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer) -void StorageSaveValue(int position, int value) -{ - FILE *storageFile = NULL; - - char path[128]; -#if defined(PLATFORM_ANDROID) - strcpy(path, internalDataPath); - strcat(path, "/"); - strcat(path, STORAGE_FILENAME); -#else - strcpy(path, STORAGE_FILENAME); -#endif - - // Try open existing file to append data - storageFile = fopen(path, "rb+"); - - // If file doesn't exist, create a new storage data file - if (!storageFile) storageFile = fopen(path, "wb"); - - if (!storageFile) TraceLog(LOG_WARNING, "Storage data file could not be created"); - else - { - // Get file size - fseek(storageFile, 0, SEEK_END); - int fileSize = ftell(storageFile); // Size in bytes - fseek(storageFile, 0, SEEK_SET); - - if (fileSize < (position*4)) TraceLog(LOG_WARNING, "Storage position could not be found"); - else - { - fseek(storageFile, (position*4), SEEK_SET); - fwrite(&value, 1, 4, storageFile); - } - - fclose(storageFile); - } -} - -// Load integer value from storage file (from defined position) -// NOTE: If requested position could not be found, value 0 is returned -int StorageLoadValue(int position) -{ - int value = 0; - - char path[128]; -#if defined(PLATFORM_ANDROID) - strcpy(path, internalDataPath); - strcat(path, "/"); - strcat(path, STORAGE_FILENAME); -#else - strcpy(path, STORAGE_FILENAME); -#endif - - // Try open existing file to append data - FILE *storageFile = fopen(path, "rb"); - - if (!storageFile) TraceLog(LOG_WARNING, "Storage data file could not be found"); - else - { - // Get file size - fseek(storageFile, 0, SEEK_END); - int fileSize = ftell(storageFile); // Size in bytes - rewind(storageFile); - - if (fileSize < (position*4)) TraceLog(LOG_WARNING, "Storage position could not be found"); - else - { - fseek(storageFile, (position*4), SEEK_SET); - fread(&value, 4, 1, storageFile); // Read 1 element of 4 bytes size - } - - fclose(storageFile); - } - - return value; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions -//---------------------------------------------------------------------------------- -// Detect if a key has been pressed once -bool IsKeyPressed(int key) -{ - bool pressed = false; - - if ((currentKeyState[key] != previousKeyState[key]) && (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 (GetKeyStatus(key) == 1) return true; - else return false; -} - -// Detect if a key has been released once -bool IsKeyReleased(int key) -{ - bool released = false; - - if ((currentKeyState[key] != previousKeyState[key]) && (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 (GetKeyStatus(key) == 0) return true; - else return false; -} - -// Get the last key pressed -int GetKeyPressed(void) -{ - return lastKeyPressed; -} - -// Set a custom key to exit program -// NOTE: default exitKey is ESCAPE -void SetExitKey(int key) -{ -#if !defined(PLATFORM_ANDROID) - 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 !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; -#endif - - return result; -} - -// Check gamepad name (if available) -bool IsGamepadName(int gamepad, const char *name) -{ - bool result = false; - -#if !defined(PLATFORM_ANDROID) - const char *gamepadName = NULL; - - if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad); - if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0); -#endif - - return result; -} - -// Return gamepad internal name id -const char *GetGamepadName(int gamepad) -{ -#if defined(PLATFORM_DESKTOP) - if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); - else return NULL; -#elif defined(PLATFORM_RPI) - if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); - - return gamepadName; -#else - return NULL; -#endif -} - -// Return gamepad axis count -int GetGamepadAxisCount(int gamepad) -{ -#if defined(PLATFORM_RPI) - int axisCount = 0; - if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGAXES, &axisCount); - gamepadAxisCount = axisCount; -#endif - return gamepadAxisCount; -} - -// Return axis movement vector for a gamepad -float GetGamepadAxisMovement(int gamepad, int axis) -{ - float value = 0; - -#if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = gamepadAxisState[gamepad][axis]; -#endif - - return value; -} - -// Detect if a gamepad button has been pressed once -bool IsGamepadButtonPressed(int gamepad, int button) -{ - bool pressed = false; - -#if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && - (currentGamepadState[gamepad][button] == 1)) pressed = true; -#endif - - return pressed; -} - -// Detect if a gamepad button is being pressed -bool IsGamepadButtonDown(int gamepad, int button) -{ - bool result = false; - -#if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] == 1)) result = true; -#endif - - return result; -} - -// Detect if a gamepad button has NOT been pressed once -bool IsGamepadButtonReleased(int gamepad, int button) -{ - bool released = false; - -#if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && - (currentGamepadState[gamepad][button] == 0)) released = true; -#endif - - return released; -} - -// Detect if a mouse button is NOT being pressed -bool IsGamepadButtonUp(int gamepad, int button) -{ - bool result = false; - -#if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] == 0)) result = true; -#endif - - return result; -} - -// Get the last gamepad button pressed -int GetGamepadButtonPressed(void) -{ - return lastGamepadButtonPressed; -} - -// Detect if a mouse button has been pressed once -bool IsMouseButtonPressed(int button) -{ - bool pressed = false; - -// TODO: Review, gestures could be not supported despite being on Android platform! -#if defined(PLATFORM_ANDROID) - if (IsGestureDetected(GESTURE_TAP)) pressed = true; -#else - if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; -#endif - - return pressed; -} - -// Detect if a mouse button is being pressed -bool IsMouseButtonDown(int button) -{ - bool down = false; - -#if defined(PLATFORM_ANDROID) - if (IsGestureDetected(GESTURE_HOLD)) down = true; -#else - if (GetMouseButtonStatus(button) == 1) down = true; -#endif - - return down; -} - -// Detect if a mouse button has been released once -bool IsMouseButtonReleased(int button) -{ - bool released = false; - -#if !defined(PLATFORM_ANDROID) - if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true; -#endif - - return released; -} - -// Detect if a mouse button is NOT being pressed -bool IsMouseButtonUp(int button) -{ - bool up = false; - -#if !defined(PLATFORM_ANDROID) - if (GetMouseButtonStatus(button) == 0) up = true; -#endif - - return up; -} - -// Returns mouse position X -int GetMouseX(void) -{ -#if defined(PLATFORM_ANDROID) - return (int)touchPosition[0].x; -#else - return (int)(mousePosition.x*mouseScale); -#endif -} - -// Returns mouse position Y -int GetMouseY(void) -{ -#if defined(PLATFORM_ANDROID) - return (int)touchPosition[0].x; -#else - return (int)(mousePosition.y*mouseScale); -#endif -} - -// Returns mouse position XY -Vector2 GetMousePosition(void) -{ -#if defined(PLATFORM_ANDROID) - return GetTouchPosition(0); -#else - return (Vector2){ mousePosition.x*mouseScale, mousePosition.y*mouseScale }; -#endif -} - -// Set mouse position XY -void SetMousePosition(Vector2 position) -{ - mousePosition = position; -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - // NOTE: emscripten not implemented - glfwSetCursorPos(window, position.x, position.y); -#endif -} - -// Set mouse scaling -// NOTE: Useful when rendering to different size targets -void SetMouseScale(float scale) -{ -#if !defined(PLATFORM_ANDROID) - mouseScale = scale; -#endif -} - -// Returns mouse wheel movement Y -int GetMouseWheelMove(void) -{ -#if defined(PLATFORM_ANDROID) - return 0; -#elif defined(PLATFORM_WEB) - return previousMouseWheelY/100; -#else - return previousMouseWheelY; -#endif -} - -// Returns touch position X for touch point 0 (relative to screen size) -int GetTouchX(void) -{ -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - return (int)touchPosition[0].x; -#else // PLATFORM_DESKTOP, PLATFORM_RPI - 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) - return (int)touchPosition[0].y; -#else // PLATFORM_DESKTOP, PLATFORM_RPI - 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_ANDROID) || defined(PLATFORM_WEB) - if (index < MAX_TOUCH_POINTS) position = touchPosition[index]; - else TraceLog(LOG_WARNING, "Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); - - if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) - { - // TODO: Review touch position scaling for screenSize vs displaySize - position.x = position.x*((float)screenWidth/(float)(displayWidth - renderOffsetX)) - renderOffsetX/2; - position.y = position.y*((float)screenHeight/(float)(displayHeight - renderOffsetY)) - renderOffsetY/2; - } - else - { - position.x = position.x*((float)renderWidth/(float)displayWidth) - renderOffsetX/2; - position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2; - } -#else // PLATFORM_DESKTOP, PLATFORM_RPI - if (index == 0) position = GetMousePosition(); -#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) -{ - screenWidth = width; // User desired width - screenHeight = height; // User desired height - - // NOTE: Framebuffer (render area - renderWidth, renderHeight) could include black bars... - // ...in top-down or left-right to match display aspect ratio (no weird scalings) - - // Downscale matrix is required in case desired screen area is bigger than display area - downscaleView = MatrixIdentity(); - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwSetErrorCallback(ErrorCallback); - - if (!glfwInit()) - { - TraceLog(LOG_WARNING, "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, "Failed to get monitor"); - return false; - } - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - displayWidth = mode->width; - displayHeight = mode->height; - - // Screen size security check - if (screenWidth <= 0) screenWidth = displayWidth; - if (screenHeight <= 0) screenHeight = displayHeight; -#endif // defined(PLATFORM_DESKTOP) - -#if defined(PLATFORM_WEB) - displayWidth = screenWidth; - displayHeight = screenHeight; -#endif // defined(PLATFORM_WEB) - - glfwDefaultWindowHints(); // Set default windows hints - - // Check some Window creation flags - if (configFlags & FLAG_WINDOW_RESIZABLE) glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window - else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable - - if (configFlags & FLAG_WINDOW_DECORATED) glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window - - if (configFlags & FLAG_WINDOW_TRANSPARENT) - { - // TODO: Enable transparent window (not ready yet on GLFW 3.2) - } - - if (configFlags & FLAG_MSAA_4X_HINT) - { - glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 - TraceLog(LOG_INFO, "Trying to enable MSAA x4"); - } - - //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits - //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default) - //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window - //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // Default OpenGL API to use. Alternative: GLFW_OPENGL_ES_API - //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers - - // 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! - // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE -#if defined(__APPLE__) - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires -#else - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above! -#endif - //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); - } - - if (fullscreen) - { - // Obtain recommended displayWidth/displayHeight from a valid videomode for the monitor - int count; - const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); - - // Get closest videomode to desired screenWidth/screenHeight - for (int i = 0; i < count; i++) - { - if (modes[i].width >= screenWidth) - { - if (modes[i].height >= screenHeight) - { - displayWidth = modes[i].width; - displayHeight = modes[i].height; - break; - } - } - } - - TraceLog(LOG_WARNING, "Closest fullscreen videomode: %i x %i", displayWidth, displayHeight); - - // 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... - - // At this point we need to manage render size vs screen size - // NOTE: This function uses and modifies global module variables: - // screenWidth/screenHeight - renderWidth/renderHeight - downscaleView - SetupFramebufferSize(displayWidth, displayHeight); - - window = glfwCreateWindow(displayWidth, displayHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); - - // NOTE: Full-screen change, not working properly... - //glfwSetWindowMonitor(window, glfwGetPrimaryMonitor(), 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); - } - else - { - // No-fullscreen window creation - window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL); - - if (window) - { -#if defined(PLATFORM_DESKTOP) - // Center window on screen - int windowPosX = displayWidth/2 - screenWidth/2; - int windowPosY = displayHeight/2 - screenHeight/2; - - if (windowPosX < 0) windowPosX = 0; - if (windowPosY < 0) windowPosY = 0; - - glfwSetWindowPos(window, windowPosX, windowPosY); -#endif - renderWidth = screenWidth; - renderHeight = screenHeight; - } - } - - if (!window) - { - 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", displayWidth, displayHeight); -#endif - TraceLog(LOG_INFO, "Render size: %i x %i", renderWidth, renderHeight); - TraceLog(LOG_INFO, "Screen size: %i x %i", screenWidth, screenHeight); - TraceLog(LOG_INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY); - } - - glfwSetWindowSizeCallback(window, WindowSizeCallback); // NOTE: Resizing not allowed by default! - glfwSetCursorEnterCallback(window, CursorEnterCallback); - glfwSetKeyCallback(window, KeyCallback); - glfwSetMouseButtonCallback(window, MouseButtonCallback); - glfwSetCursorPosCallback(window, MouseCursorPosCallback); // Track mouse position changes - glfwSetCharCallback(window, CharCallback); - glfwSetScrollCallback(window, ScrollCallback); - glfwSetWindowIconifyCallback(window, WindowIconifyCallback); -#if defined(PLATFORM_DESKTOP) - glfwSetDropCallback(window, WindowDropCallback); -#endif - - glfwMakeContextCurrent(window); - - // Try to disable GPU V-Sync by default, set framerate using SetTargetFPS() - // NOTE: V-Sync can be enabled by graphic driver configuration - glfwSwapInterval(0); - -#if defined(PLATFORM_DESKTOP) - // Load OpenGL 3.3 extensions - // NOTE: GLFW loader function is passed as parameter - rlLoadExtensions(glfwGetProcAddress); -#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 (configFlags & FLAG_VSYNC_HINT) - { - glfwSwapInterval(1); - TraceLog(LOG_INFO, "Trying to enable VSYNC"); - } -#endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - fullscreen = true; - - // Screen size security check - if (screenWidth <= 0) screenWidth = displayWidth; - if (screenHeight <= 0) screenHeight = displayHeight; - -#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 - - EGLint samples = 0; - EGLint sampleBuffer = 0; - if (configFlags & FLAG_MSAA_4X_HINT) - { - samples = 4; - sampleBuffer = 1; - TraceLog(LOG_INFO, "Trying to enable MSAA x4"); - } - - const EGLint framebufferAttribs[] = - { - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI? - //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 - }; - -#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, - }; - - EGLConfig config = NULL; - - // 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, "Failed to get function 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. - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); - if (display == EGL_NO_DISPLAY) - { - TraceLog(LOG_WARNING, "Failed to initialize EGL display"); - return false; - } - - if (eglInitialize(display, 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). - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); - if (display == EGL_NO_DISPLAY) - { - TraceLog(LOG_WARNING, "Failed to initialize EGL display"); - return false; - } - - if (eglInitialize(display, NULL, NULL) == EGL_FALSE) - { - // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. - display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); - if (display == EGL_NO_DISPLAY) - { - TraceLog(LOG_WARNING, "Failed to initialize EGL display"); - return false; - } - - if (eglInitialize(display, NULL, NULL) == EGL_FALSE) - { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - TraceLog(LOG_WARNING, "Failed to initialize EGL"); - return false; - } - } - } - - //SetupFramebufferSize(displayWidth, displayHeight); - - EGLint numConfigs = 0; - if ((eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0)) - { - TraceLog(LOG_WARNING, "Failed to choose first EGLConfig"); - 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 - - //surface = eglCreateWindowSurface(display, config, reinterpret_cast(surfaceCreationProperties), surfaceAttributes); - surface = eglCreateWindowSurface(display, config, uwpWindow, surfaceAttributes); - if (surface == EGL_NO_SURFACE) - { - TraceLog(LOG_WARNING, "Failed to create EGL fullscreen surface"); - return false; - } - - context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); - if (context == EGL_NO_CONTEXT) - { - TraceLog(LOG_WARNING, "Failed to create EGL context"); - return false; - } - - // Get EGL display window size - eglQuerySurface(display, surface, EGL_WIDTH, &screenWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &screenHeight); - -#else // PLATFORM_ANDROID, PLATFORM_RPI - EGLint numConfigs; - - // Get an EGL display connection - display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) - { - TraceLog(LOG_WARNING, "Failed to initialize EGL display"); - return false; - } - - // Initialize the EGL display connection - if (eglInitialize(display, NULL, NULL) == EGL_FALSE) - { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - TraceLog(LOG_WARNING, "Failed to initialize EGL"); - return false; - } - - // Get an appropriate EGL framebuffer configuration - eglChooseConfig(display, framebufferAttribs, &config, 1, &numConfigs); - - // Set rendering API - eglBindAPI(EGL_OPENGL_ES_API); - - // Create an EGL rendering context - context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); - if (context == EGL_NO_CONTEXT) - { - TraceLog(LOG_WARNING, "Failed to create EGL context"); - return false; - } -#endif - - // Create an EGL window surface - //--------------------------------------------------------------------------------- -#if defined(PLATFORM_ANDROID) - EGLint displayFormat; - - displayWidth = ANativeWindow_getWidth(androidApp->window); - displayHeight = ANativeWindow_getHeight(androidApp->window); - - // 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(display, 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: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView - SetupFramebufferSize(displayWidth, displayHeight); - - ANativeWindow_setBuffersGeometry(androidApp->window, renderWidth, renderHeight, displayFormat); - //ANativeWindow_setBuffersGeometry(androidApp->window, 0, 0, displayFormat); // Force use of native display size - - surface = eglCreateWindowSurface(display, config, androidApp->window, NULL); -#endif // defined(PLATFORM_ANDROID) - -#if defined(PLATFORM_RPI) - graphics_get_display_size(0, &displayWidth, &displayHeight); - - // At this point we need to manage render size vs screen size - // NOTE: This function use and modify global module variables: screenWidth/screenHeight and renderWidth/renderHeight and downscaleView - SetupFramebufferSize(displayWidth, displayHeight); - - dstRect.x = 0; - dstRect.y = 0; - dstRect.width = displayWidth; - dstRect.height = displayHeight; - - srcRect.x = 0; - srcRect.y = 0; - srcRect.width = renderWidth << 16; - srcRect.height = renderHeight << 16; - - // NOTE: RPI dispmanx windowing system takes care of srcRec scaling to dstRec 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.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); - - nativeWindow.element = dispmanElement; - nativeWindow.width = renderWidth; - nativeWindow.height = renderHeight; - vc_dispmanx_update_submit_sync(dispmanUpdate); - - surface = eglCreateWindowSurface(display, config, &nativeWindow, NULL); - //--------------------------------------------------------------------------------- -#endif // defined(PLATFORM_RPI) - // There must be at least one frame displayed before the buffers are swapped - //eglSwapInterval(display, 1); - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) - { - TraceLog(LOG_WARNING, "Unable to attach EGL rendering context to EGL surface"); - return false; - } - else - { - // Grab the width and height of the surface - //eglQuerySurface(display, surface, EGL_WIDTH, &renderWidth); - //eglQuerySurface(display, surface, EGL_HEIGHT, &renderHeight); - - TraceLog(LOG_INFO, "Display device initialized successfully"); - TraceLog(LOG_INFO, "Display size: %i x %i", displayWidth, displayHeight); - TraceLog(LOG_INFO, "Render size: %i x %i", renderWidth, renderHeight); - TraceLog(LOG_INFO, "Screen size: %i x %i", screenWidth, screenHeight); - TraceLog(LOG_INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY); - } -#endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) - - renderWidth = screenWidth; - renderHeight = screenHeight; - - // Initialize OpenGL context (states and resources) - // NOTE: screenWidth and screenHeight not used, just stored as globals - rlglInit(screenWidth, screenHeight); - - // Setup default viewport - SetupViewport(); - - // Initialize internal projection and modelview matrices - // NOTE: Default to orthographic projection mode with top-left corner at (0,0) - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - rlOrtho(0, renderWidth - renderOffsetX, renderHeight - renderOffsetY, 0, 0.0f, 1.0f); - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - - ClearBackground(RAYWHITE); // Default background color for raylib games :P - -#if defined(PLATFORM_ANDROID) - windowReady = true; // IMPORTANT! -#endif - return true; -} - -// Set viewport parameters -static void SetupViewport(void) -{ -#if defined(__APPLE__) - // Get framebuffer size of current window - // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer - // is automatically reasized to adapt to new DPI. - // When OS does that, it can be detected using GLFW3 callback: glfwSetFramebufferSizeCallback() - int fbWidth, fbHeight; - glfwGetFramebufferSize(window, &fbWidth, &fbHeight); - rlViewport(renderOffsetX/2, renderOffsetY/2, fbWidth - renderOffsetX, fbHeight - renderOffsetY); -#else - // Initialize screen viewport (area of the screen that you will actually draw to) - // NOTE: Viewport must be recalculated if screen is resized - rlViewport(renderOffsetX/2, renderOffsetY/2, renderWidth - renderOffsetX, renderHeight - renderOffsetY); -#endif -} - -// Compute framebuffer size relative to screen size and display size -// NOTE: Global variables renderWidth/renderHeight and renderOffsetX/renderOffsetY can be modified -static void SetupFramebufferSize(int displayWidth, int displayHeight) -{ - // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var) - if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) - { - TraceLog(LOG_WARNING, "DOWNSCALING: Required screen size (%ix%i) is bigger than display size (%ix%i)", screenWidth, screenHeight, displayWidth, displayHeight); - - // Downscaling to fit display with border-bars - float widthRatio = (float)displayWidth/(float)screenWidth; - float heightRatio = (float)displayHeight/(float)screenHeight; - - if (widthRatio <= heightRatio) - { - renderWidth = displayWidth; - renderHeight = (int)round((float)screenHeight*widthRatio); - renderOffsetX = 0; - renderOffsetY = (displayHeight - renderHeight); - } - else - { - renderWidth = (int)round((float)screenWidth*heightRatio); - renderHeight = displayHeight; - renderOffsetX = (displayWidth - renderWidth); - renderOffsetY = 0; - } - - // NOTE: downscale matrix required! - float scaleRatio = (float)renderWidth/(float)screenWidth; - - downscaleView = MatrixScale(scaleRatio, scaleRatio, scaleRatio); - - // NOTE: We render to full display resolution! - // We just need to calculate above parameters for downscale matrix and offsets - renderWidth = displayWidth; - renderHeight = displayHeight; - - TraceLog(LOG_WARNING, "Downscale matrix generated, content will be rendered at: %i x %i", renderWidth, renderHeight); - } - else if ((screenWidth < displayWidth) || (screenHeight < displayHeight)) - { - // Required screen size is smaller than display size - TraceLog(LOG_INFO, "UPSCALING: Required screen size: %i x %i -> Display size: %i x %i", screenWidth, screenHeight, displayWidth, displayHeight); - - // Upscaling to fit display with border-bars - float displayRatio = (float)displayWidth/(float)displayHeight; - float screenRatio = (float)screenWidth/(float)screenHeight; - - if (displayRatio <= screenRatio) - { - renderWidth = screenWidth; - renderHeight = (int)round((float)screenWidth/displayRatio); - renderOffsetX = 0; - renderOffsetY = (renderHeight - screenHeight); - } - else - { - renderWidth = (int)round((float)screenHeight*displayRatio); - renderHeight = screenHeight; - renderOffsetX = (renderWidth - screenWidth); - renderOffsetY = 0; - } - } - else // screen == display - { - renderWidth = screenWidth; - renderHeight = screenHeight; - renderOffsetX = 0; - renderOffsetY = 0; - } -} - -// Initialize hi-resolution timer -static void InitTimer(void) -{ - srand(time(NULL)); // Initialize random seed - -#if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) - timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) - struct timespec now; - - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success - { - baseTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; - } - else TraceLog(LOG_WARNING, "No hi-resolution timer available"); -#endif - - previousTime = 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 -// http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected -static void Wait(float ms) -{ -#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(_WIN32) - Sleep((unsigned int)ms); - #elif defined(__linux__) || defined(PLATFORM_WEB) - 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; - #elif defined(__APPLE__) - usleep(ms*1000.0f); - #endif -#endif -} - -// Get one key state -static bool GetKeyStatus(int key) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetKey(window, key); -#elif defined(PLATFORM_ANDROID) - // NOTE: Android supports up to 260 keys - if (key < 0 || key > 260) return false; - else return currentKeyState[key]; -#elif defined(PLATFORM_RPI) - // NOTE: Keys states are filled in PollInputEvents() - if (key < 0 || key > 511) return false; - else return currentKeyState[key]; -#endif -} - -// Get one mouse button state -static bool GetMouseButtonStatus(int button) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetMouseButton(window, button); -#elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual mouse? - return false; -#elif defined(PLATFORM_RPI) - // NOTE: Mouse buttons states are filled in PollInputEvents() - return currentMouseState[button]; -#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 last key pressed registered - lastKeyPressed = -1; - -#if !defined(PLATFORM_RPI) - // Reset last gamepad button/axis registered state - lastGamepadButtonPressed = -1; - gamepadAxisCount = 0; -#endif - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - // Mouse input polling - double mouseX; - double mouseY; - - glfwGetCursorPos(window, &mouseX, &mouseY); - - mousePosition.x = (float)mouseX; - mousePosition.y = (float)mouseY; - - // Keyboard input polling (automatically managed by GLFW3 through callback) - - // Register previous keys states - for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; - - // Register previous mouse states - for (int i = 0; i < 3; i++) previousMouseState[i] = currentMouseState[i]; - - previousMouseWheelY = currentMouseWheelY; - currentMouseWheelY = 0; -#endif - -#if defined(PLATFORM_DESKTOP) - // Check if gamepads are ready - // NOTE: We do it here in case of disconection - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (glfwJoystickPresent(i)) gamepadReady[i] = true; - else gamepadReady[i] = false; - } - - // Register gamepads buttons events - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (gamepadReady[i]) // Check if gamepad is available - { - // Register previous gamepad states - for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; - - // Get current gamepad state - // NOTE: There is no callback available, so we get it manually - const unsigned char *buttons; - int buttonsCount; - - buttons = glfwGetJoystickButtons(i, &buttonsCount); - - for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) - { - if (buttons[k] == GLFW_PRESS) - { - currentGamepadState[i][k] = 1; - lastGamepadButtonPressed = k; - } - else currentGamepadState[i][k] = 0; - } - - // Get current axis state - const float *axes; - int axisCount = 0; - - axes = glfwGetJoystickAxes(i, &axisCount); - - for (int k = 0; (axes != NULL) && (k < axisCount) && (k < MAX_GAMEPAD_AXIS); k++) - { - gamepadAxisState[i][k] = axes[k]; - } - - gamepadAxisCount = axisCount; - } - } - - glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! -#endif - -// Gamepad support using emscripten API -// NOTE: GLFW3 joystick functionality not available in web -#if defined(PLATFORM_WEB) - // Get number of gamepads connected - int 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++) previousGamepadState[i][k] = currentGamepadState[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++) - { - if (gamepadState.digitalButton[j] == 1) - { - currentGamepadState[i][j] = 1; - lastGamepadButtonPressed = j; - } - else currentGamepadState[i][j] = 0; - - //printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", 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++) - { - gamepadAxisState[i][j] = gamepadState.axis[j]; - } - - gamepadAxisCount = 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++) previousKeyState[i] = currentKeyState[i]; - - // Poll Events (registered events) - // NOTE: Activity is paused if not enabled (appEnabled) - while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) - { - // Process this event - if (source != NULL) source->process(androidApp, source); - - // NOTE: Never close window, native activity is controlled by the system! - if (androidApp->destroyRequested != 0) - { - //TraceLog(LOG_INFO, "Closing Window..."); - //windowShouldClose = true; - //ANativeActivity_finish(androidApp->activity); - } - } -#endif - -#if defined(PLATFORM_RPI) - // NOTE: Mouse input events polling is done asynchonously in another pthread - MouseThread() - - // NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin, - // we use method 2 (stdin) but maybe in a future we should change to method 1... - ProcessKeyboard(); - - // 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(window); -#endif - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - eglSwapBuffers(display, surface); -#endif -} - -#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, "[GLFW3 Error] Code: %i Decription: %s", error, description); -} - -// GLFW3 Srolling Callback, runs on mouse wheel -static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset) -{ - currentMouseWheelY = (int)yoffset; -} - -// GLFW3 Keyboard Callback, runs on key pressed -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -{ - if (key == exitKey && action == GLFW_PRESS) - { - glfwSetWindowShouldClose(window, GL_TRUE); - - // NOTE: Before closing window, while loop must be left! - } -#if defined(PLATFORM_DESKTOP) - else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) - { - #if defined(SUPPORT_GIF_RECORDING) - if (mods == GLFW_MOD_CONTROL) - { - if (gifRecording) - { - GifEnd(); - gifRecording = false; - - TraceLog(LOG_INFO, "End animated GIF recording"); - } - else - { - gifRecording = true; - gifFramesCounter = 0; - - // NOTE: delay represents the time between frames in the gif, if we capture a gif frame every - // 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10. - GifBegin(FormatText("screenrec%03i.gif", screenshotCounter), screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false); - screenshotCounter++; - - TraceLog(LOG_INFO, "Begin animated GIF recording: %s", FormatText("screenrec%03i.gif", screenshotCounter)); - } - } - else - #endif // SUPPORT_GIF_RECORDING - #if defined(SUPPORT_SCREEN_CAPTURE) - { - TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } - #endif // SUPPORT_SCREEN_CAPTURE - } -#endif // PLATFORM_DESKTOP - else - { - currentKeyState[key] = action; - - // NOTE: lastKeyPressed already registered on CharCallback() - //if (action == GLFW_PRESS) lastKeyPressed = key; - } -} - -// GLFW3 Mouse Button Callback, runs on mouse button pressed -static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) -{ - currentMouseState[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; - - // Register touch actions - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) 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 screenWidth and screenHeight - 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) -{ -#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent; - - 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] = (Vector2){ (float)x, (float)y }; - - touchPosition[0] = gestureEvent.position[0]; - - // Normalize gestureEvent.position[0] for screenWidth and screenHeight - 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 Char Key Callback, runs on key down (get unicode char value) -static void CharCallback(GLFWwindow *window, unsigned int key) -{ - // NOTE: Registers any key down considering OS keyboard layout but - // do not detects action events, those should be managed by user... - // https://github.com/glfw/glfw/issues/668#issuecomment-166794907 - // http://www.glfw.org/docs/latest/input_guide.html#input_char - - lastKeyPressed = key; -} - -// GLFW3 CursorEnter Callback, when cursor enters the window -static void CursorEnterCallback(GLFWwindow *window, int enter) -{ - if (enter == true) cursorOnScreen = true; - else cursorOnScreen = false; -} - -// GLFW3 WindowSize Callback, runs when window is resized -// NOTE: Window resizing not allowed by default -static void WindowSizeCallback(GLFWwindow *window, int width, int height) -{ - // If window is resized, viewport and projection matrix needs to be re-calculated - rlViewport(0, 0, width, height); // Set viewport width and height - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - rlOrtho(0, width, height, 0, 0.0f, 1.0f); // Orthographic projection mode with top-left corner at (0,0) - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - rlClearScreenBuffers(); // Clear screen buffers (color and depth) - - // Window size must be updated to be used on 3D mode to get new aspect ratio (BeginMode3D()) - // NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor, - // for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported) - screenWidth = width; - screenHeight = height; - renderWidth = width; - renderHeight = 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) windowMinimized = true; // The window was iconified - else windowMinimized = false; // The window was restored -} -#endif - -#if defined(PLATFORM_DESKTOP) -// GLFW3 Window Drop Callback, runs when drop files into window -// NOTE: Paths are stored in dinamic memory for further retrieval -// Everytime new files are dropped, old ones are discarded -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) -{ - ClearDroppedFiles(); - - dropFilesPath = (char **)malloc(sizeof(char *)*count); - - for (int i = 0; i < count; i++) - { - dropFilesPath[i] = (char *)malloc(sizeof(char)*256); // Max path length set to 256 char - strcpy(dropFilesPath[i], paths[i]); - } - - 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; - TraceLog(LOG_INFO, "APP_CMD_START"); - } break; - case APP_CMD_RESUME: - { - TraceLog(LOG_INFO, "APP_CMD_RESUME"); - } break; - case APP_CMD_INIT_WINDOW: - { - TraceLog(LOG_INFO, "APP_CMD_INIT_WINDOW"); - - if (app->window != NULL) - { - if (contextRebindRequired) - { - // Reset screen scaling to full display size - EGLint displayFormat; - eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &displayFormat); - ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat); - - // Recreate display surface and re-attach OpenGL context - surface = eglCreateWindowSurface(display, config, app->window, NULL); - eglMakeCurrent(display, surface, surface, context); - - contextRebindRequired = false; - } - else - { - // Init graphics device (display device and OpenGL context) - InitGraphicsDevice(screenWidth, screenHeight); - - // Init hi-res timer - InitTimer(); - - #if defined(SUPPORT_DEFAULT_FONT) - // Load default font - // NOTE: External function (defined in module: text) - LoadDefaultFont(); - #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]); - } - } - */ - - // raylib logo appearing animation (if enabled) - if (showLogo) - { - SetTargetFPS(60); // Not required on Android - LogoAnimation(); - } - } - } - } break; - case APP_CMD_GAINED_FOCUS: - { - TraceLog(LOG_INFO, "APP_CMD_GAINED_FOCUS"); - appEnabled = true; - //ResumeMusicStream(); - } break; - case APP_CMD_PAUSE: - { - TraceLog(LOG_INFO, "APP_CMD_PAUSE"); - } break; - case APP_CMD_LOST_FOCUS: - { - //DrawFrame(); - TraceLog(LOG_INFO, "APP_CMD_LOST_FOCUS"); - 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(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(display, surface); - - contextRebindRequired = true; - - TraceLog(LOG_INFO, "APP_CMD_TERM_WINDOW"); - } break; - case APP_CMD_SAVE_STATE: - { - TraceLog(LOG_INFO, "APP_CMD_SAVE_STATE"); - } break; - case APP_CMD_STOP: - { - TraceLog(LOG_INFO, "APP_CMD_STOP"); - } break; - case APP_CMD_DESTROY: - { - // TODO: Finish activity? - //ANativeActivity_finish(androidApp->activity); - - TraceLog(LOG_INFO, "APP_CMD_DESTROY"); - } break; - case APP_CMD_CONFIG_CHANGED: - { - //AConfiguration_fromAssetManager(androidApp->config, androidApp->activity->assetManager); - //print_cur_config(androidApp); - - // Check screen orientation here! - - TraceLog(LOG_INFO, "APP_CMD_CONFIG_CHANGED"); - } break; - default: break; - } -} - -// Android: Get input events -static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) -{ - //http://developer.android.com/ndk/reference/index.html - - int type = AInputEvent_getType(event); - - if (type == AINPUT_EVENT_TYPE_MOTION) - { - // Get first touch position - touchPosition[0].x = AMotionEvent_getX(event, 0); - touchPosition[0].y = AMotionEvent_getY(event, 0); - - // Get second touch position - touchPosition[1].x = AMotionEvent_getX(event, 1); - touchPosition[1].y = AMotionEvent_getY(event, 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) == 0) - { - currentKeyState[keycode] = 1; // Key down - lastKeyPressed = keycode; - } - else 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; - } - } - - int32_t action = AMotionEvent_getAction(event); - unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; - -#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 - gestureEvent.pointCount = AMotionEvent_getPointerCount(event); - - // Register touch points id - gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0); - gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1); - - // Register touch points position - // NOTE: Only two points registered - 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); -#else - - // Support only simple touch position - if (flags == AMOTION_EVENT_ACTION_DOWN) - { - // Get first touch position - touchPosition[0].x = AMotionEvent_getX(event, 0); - touchPosition[0].y = AMotionEvent_getY(event, 0); - - touchPosition[0].x /= (float)GetScreenWidth(); - touchPosition[0].y /= (float)GetScreenHeight(); - } -#endif - - return 0; -} -#endif - -#if defined(PLATFORM_WEB) - -// Register fullscreen change events -static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData) -{ - //isFullscreen: int e->isFullscreen - //fullscreenEnabled: int e->fullscreenEnabled - //fs element nodeName: (char *) e->nodeName - //fs element id: (char *) e->id - //Current element size: (int) e->elementWidth, (int) e->elementHeight - //Screen size:(int) e->screenWidth, (int) e->screenHeight - - if (e->isFullscreen) - { - TraceLog(LOG_INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); - } - else - { - TraceLog(LOG_INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); - } - - // TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input - - return 0; -} - -// Register keyboard input events -static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) -{ - if ((eventType == EMSCRIPTEN_EVENT_KEYPRESS) && (strcmp(keyEvent->code, "Escape") == 0)) - { - emscripten_exit_pointerlock(); - } - - return 0; -} - -// Register mouse input events -static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) -{ - // Lock mouse pointer when click on screen - if ((eventType == EMSCRIPTEN_EVENT_CLICK) && toggleCursorLock) - { - EmscriptenPointerlockChangeEvent plce; - emscripten_get_pointerlock_status(&plce); - - if (!plce.isActive) emscripten_request_pointerlock(0, 1); - else - { - emscripten_exit_pointerlock(); - emscripten_get_pointerlock_status(&plce); - //if (plce.isActive) TraceLog(LOG_WARNING, "Pointer lock exit did not work!"); - } - - toggleCursorLock = false; - } - - return 0; -} - -// Register touch input events -static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) -{ - /* - for (int i = 0; i < touchEvent->numTouches; i++) - { - long x, y, id; - - if (!touchEvent->touches[i].isChanged) continue; - - id = touchEvent->touches[i].identifier; - x = touchEvent->touches[i].canvasX; - y = touchEvent->touches[i].canvasY; - } - - printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, - event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : ""); - - for (int i = 0; i < event->numTouches; ++i) - { - const EmscriptenTouchPoint *t = &event->touches[i]; - - printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", - t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); - } - */ - - GestureEvent gestureEvent; - - // 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 - // TODO: Touch data should be scaled accordingly! - //gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].canvasX, touchEvent->touches[0].canvasY }; - //gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].canvasX, touchEvent->touches[1].canvasY }; - gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; - gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; - - touchPosition[0] = gestureEvent.position[0]; - touchPosition[1] = gestureEvent.position[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); - - return 1; -} - -// Register connected/disconnected gamepads events -static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) -{ - /* - printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", - 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) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]); - for(int i = 0; i < gamepadEvent->numButtons; ++i) printf("Button %d: Digital: %d, Analog: %g\n", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); - */ - - if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true; - else gamepadReady[gamepadEvent->index] = false; - - // TODO: Test gamepadEvent->index - - return 0; -} -#endif - -#if defined(PLATFORM_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, &defaultKeyboardSettings); // Get current keyboard settings - keyboardNewSettings = defaultKeyboardSettings; - - // 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, we change that! -> WHY??? - - // Save old keyboard mode to restore it at the end - if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0) - { - // NOTE: It could mean we are using a remote keyboard through ssh! - TraceLog(LOG_WARNING, "Could not 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 - - // Reset pressed keys array - for (int i = 0; i < 512; i++) currentKeyState[i] = 0; - - // Read availables keycodes from stdin - bufferByteCount = read(STDIN_FILENO, keysBuffer, MAX_KEYBUFFER_SIZE); // POSIX system call - - // Fill all read bytes (looking for keys) - for (int i = 0; i < bufferByteCount; i++) - { - TraceLog(LOG_DEBUG, "Bytes on keysBuffer: %i", bufferByteCount); - - //printf("Key(s) bytes: "); - //for (int i = 0; i < bufferByteCount; i++) printf("0x%02x ", keysBuffer[i]); - //printf("\n"); - - // 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) currentKeyState[256] = 1; // raylib key: KEY_ESCAPE - 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: currentKeyState[290] = 1; break; // raylib KEY_F1 - case 0x42: currentKeyState[291] = 1; break; // raylib KEY_F2 - case 0x43: currentKeyState[292] = 1; break; // raylib KEY_F3 - case 0x44: currentKeyState[293] = 1; break; // raylib KEY_F4 - case 0x45: currentKeyState[294] = 1; break; // raylib KEY_F5 - case 0x37: currentKeyState[295] = 1; break; // raylib KEY_F6 - case 0x38: currentKeyState[296] = 1; break; // raylib KEY_F7 - case 0x39: currentKeyState[297] = 1; break; // raylib KEY_F8 - case 0x30: currentKeyState[298] = 1; break; // raylib KEY_F9 - case 0x31: currentKeyState[299] = 1; break; // raylib KEY_F10 - case 0x33: currentKeyState[300] = 1; break; // raylib KEY_F11 - case 0x34: 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: currentKeyState[265] = 1; break; // raylib KEY_UP - case 0x42: currentKeyState[264] = 1; break; // raylib KEY_DOWN - case 0x43: currentKeyState[262] = 1; break; // raylib KEY_RIGHT - case 0x44: 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) currentKeyState[257] = 1; // raylib KEY_ENTER (don't mix with KEY_*) - else if (keysBuffer[i] == 0x7f) currentKeyState[259] = 1; // raylib KEY_BACKSPACE - else - { - TraceLog(LOG_DEBUG, "Pressed key (ASCII): 0x%02x", keysBuffer[i]); - - // Translate lowercase a-z letters to A-Z - if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122)) - { - currentKeyState[(int)keysBuffer[i] - 32] = 1; - } - else currentKeyState[(int)keysBuffer[i]] = 1; - } - } - - // Check exit key (same functionality as GLFW3 KeyCallback()) - if (currentKeyState[exitKey] == 1) windowShouldClose = true; - -#if defined(SUPPORT_SCREEN_CAPTURE) - // Check screen capture key (raylib key: KEY_F12) - if (currentKeyState[301] == 1) - { - TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } -#endif -} - -// Restore default keyboard input -static void RestoreKeyboard(void) -{ - // Reset to default keyboard settings - tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings); - - // Reconfigure keyboard to default mode - ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode); -} - -// Mouse initialization (including mouse thread) -static void InitMouse(void) -{ - // NOTE: We can use /dev/input/mice to read from all available mice - if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0) - { - TraceLog(LOG_WARNING, "Mouse device could not be opened, no mouse available"); - } - else - { - mouseReady = true; - - int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL); - - if (error != 0) TraceLog(LOG_WARNING, "Error creating mouse input event thread"); - else TraceLog(LOG_INFO, "Mouse device initialized successfully"); - } -} - -// Mouse reading thread -// NOTE: We need a separate thread to avoid loosing mouse events, -// if too much time passes between reads, queue gets full and new events override older ones... -static void *MouseThread(void *arg) -{ - const unsigned char XSIGN = (1 << 4); - const unsigned char YSIGN = (1 << 5); - - typedef struct { - char buttons; - char dx, dy; - } MouseEvent; - - MouseEvent mouse; - - int mouseRelX = 0; - int mouseRelY = 0; - - while (!windowShouldClose) - { - if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent)) - { - if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set - - // Check Left button pressed - if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1; - else currentMouseState[0] = 0; - - // Check Right button pressed - if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1; - else currentMouseState[1] = 0; - - // Check Middle button pressed - if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1; - else currentMouseState[2] = 0; - - mouseRelX = (int)mouse.dx; - mouseRelY = (int)mouse.dy; - - if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX); - if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY); - - // NOTE: Mouse movement is normalized to not be screen resolution dependant - // We suppose 2*255 (max relative movement) is equivalent to screenWidth (max pixels width) - // Result after normalization is multiplied by MOUSE_SENSITIVITY factor - - mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY; - mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY; - - if (mousePosition.x < 0) mousePosition.x = 0; - if (mousePosition.y < 0) mousePosition.y = 0; - - if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; - if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; - } - //else read(mouseStream, &mouse, 1); // Try to sync up again - } - - return NULL; -} - -// Touch initialization (including touch thread) -static void InitTouch(void) -{ - if ((touchStream = open(DEFAULT_TOUCH_DEV, O_RDONLY|O_NONBLOCK)) < 0) - { - TraceLog(LOG_WARNING, "Touch device could not be opened, no touchscreen available"); - } - else - { - touchReady = true; - - int error = pthread_create(&touchThreadId, NULL, &TouchThread, NULL); - - if (error != 0) TraceLog(LOG_WARNING, "Error creating touch input event thread"); - else TraceLog(LOG_INFO, "Touch device initialized successfully"); - } -} - -// Touch reading thread. -// This reads from a Virtual Input Event /dev/input/event4 which is -// created by the ts_uinput daemon. This takes, filters and scales -// raw input from the Touchscreen (which appears in /dev/input/event3) -// based on the Calibration data referenced by tslib. -static void *TouchThread(void *arg) -{ - struct input_event ev; - GestureEvent gestureEvent; - - while (!windowShouldClose) - { - if (read(touchStream, &ev, sizeof(ev)) == (int)sizeof(ev)) - { - // if pressure > 0 then simulate left mouse button click - if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1) - { - currentMouseState[0] = 0; - gestureEvent.touchAction = TOUCH_UP; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); - } - if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0) - { - currentMouseState[0] = 1; - gestureEvent.touchAction = TOUCH_DOWN; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); - } - // x & y values supplied by event4 have been scaled & de-jittered using tslib calibration data - if (ev.type == EV_ABS && ev.code == 0) - { - mousePosition.x = ev.value; - if (mousePosition.x < 0) mousePosition.x = 0; - if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; - gestureEvent.touchAction = TOUCH_MOVE; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); - } - if (ev.type == EV_ABS && ev.code == 1) - { - mousePosition.y = ev.value; - if (mousePosition.y < 0) mousePosition.y = 0; - if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; - gestureEvent.touchAction = TOUCH_MOVE; - gestureEvent.pointCount = 1; - gestureEvent.pointerId[0] = 0; - gestureEvent.pointerId[1] = 1; - gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y }; - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - gestureEvent.position[1].x /= (float)GetScreenWidth(); - gestureEvent.position[1].y /= (float)GetScreenHeight(); - ProcessGestureEvent(gestureEvent); - } - - } - } - 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 ((gamepadStream[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0) - { - // NOTE: Only show message for first gamepad - if (i == 0) TraceLog(LOG_WARNING, "Gamepad device could not be opened, no gamepad available"); - } - else - { - gamepadReady[i] = true; - - // NOTE: Only create one thread - if (i == 0) - { - int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL); - - if (error != 0) TraceLog(LOG_WARNING, "Error creating gamepad input event thread"); - else TraceLog(LOG_INFO, "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 (!windowShouldClose) - { - for (int i = 0; i < MAX_GAMEPADS; i++) - { - if (read(gamepadStream[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_DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); - - if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) - { - // 1 - button pressed, 0 - button released - currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; - - if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; - else lastGamepadButtonPressed = -1; - } - } - else if (gamepadEvent.type == JS_EVENT_AXIS) - { - TraceLog(LOG_DEBUG, "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 - gamepadAxisState[i][gamepadEvent.number] = (float)gamepadEvent.value/32768; - } - } - } - } - } - - return NULL; -} -#endif // PLATFORM_RPI - -// Plays raylib logo appearing animation -static void LogoAnimation(void) -{ -#if !defined(PLATFORM_WEB) - int logoPositionX = screenWidth/2 - 128; - int logoPositionY = screenHeight/2 - 128; - - int framesCounter = 0; - int lettersCount = 0; - - int topSideRecWidth = 16; - int leftSideRecHeight = 16; - - int bottomSideRecWidth = 16; - int rightSideRecHeight = 16; - - int state = 0; // Tracking animation states (State Machine) - float alpha = 1.0f; // Useful for fading - - while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - if (state == 0) // State 0: Small box blinking - { - framesCounter++; - - if (framesCounter == 84) - { - state = 1; - framesCounter = 0; // Reset counter... will be used later... - } - } - else if (state == 1) // State 1: Top and left bars growing - { - topSideRecWidth += 4; - leftSideRecHeight += 4; - - if (topSideRecWidth == 256) state = 2; - } - else if (state == 2) // State 2: Bottom and right bars growing - { - bottomSideRecWidth += 4; - rightSideRecHeight += 4; - - if (bottomSideRecWidth == 256) state = 3; - } - else if (state == 3) // State 3: Letters appearing (one by one) - { - framesCounter++; - - if (framesCounter/12) // Every 12 frames, one more letter! - { - lettersCount++; - framesCounter = 0; - } - - if (lettersCount >= 10) // When all letters have appeared, just fade out everything - { - alpha -= 0.02f; - - if (alpha <= 0.0f) - { - alpha = 0.0f; - state = 4; - } - } - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - if (state == 0) - { - if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); - } - else if (state == 1) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); - DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); - } - else if (state == 2) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); - DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); - - DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); - DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); - } - else if (state == 3) - { - DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); - DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); - - DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); - DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); - - DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); - - DrawText(SubText("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha)); - } - - EndDrawing(); - //---------------------------------------------------------------------------------- - } -#endif - - showLogo = false; // Prevent for repeating when reloading window (Android) -} diff --git a/raylib/core.go b/raylib/core.go deleted file mode 100644 index 4abe442..0000000 --- a/raylib/core.go +++ /dev/null @@ -1,584 +0,0 @@ -package raylib - -/* -#include "raylib.h" -#include -*/ -import "C" - -import ( - "unsafe" -) - -// cptr returns C pointer -func (v *Vector2) cptr() *C.Vector2 { - return (*C.Vector2)(unsafe.Pointer(v)) -} - -// cptr returns C pointer -func (v *Vector3) cptr() *C.Vector3 { - return (*C.Vector3)(unsafe.Pointer(v)) -} - -// cptr returns C pointer -func (m *Matrix) cptr() *C.Matrix { - return (*C.Matrix)(unsafe.Pointer(m)) -} - -// cptr returns C pointer -func (color *Color) cptr() *C.Color { - return (*C.Color)(unsafe.Pointer(color)) -} - -// cptr returns C pointer -func (r *Rectangle) cptr() *C.Rectangle { - return (*C.Rectangle)(unsafe.Pointer(r)) -} - -// cptr returns C pointer -func (c *Camera) cptr() *C.Camera { - return (*C.Camera)(unsafe.Pointer(c)) -} - -// cptr returns C pointer -func (c *Camera2D) cptr() *C.Camera2D { - return (*C.Camera2D)(unsafe.Pointer(c)) -} - -// cptr returns C pointer -func (b *BoundingBox) cptr() *C.BoundingBox { - return (*C.BoundingBox)(unsafe.Pointer(b)) -} - -// CloseWindow - Close Window and Terminate Context -func CloseWindow() { - C.CloseWindow() -} - -// IsWindowReady - Check if window has been initialized successfully -func IsWindowReady() bool { - ret := C.IsWindowReady() - v := bool(int(ret) == 1) - return v -} - -// WindowShouldClose - Detect if KEY_ESCAPE pressed or Close icon pressed -func WindowShouldClose() bool { - ret := C.WindowShouldClose() - v := bool(int(ret) == 1) - return v -} - -// IsWindowMinimized - Detect if window has been minimized (or lost focus) -func IsWindowMinimized() bool { - ret := C.IsWindowMinimized() - v := bool(int(ret) == 1) - return v -} - -// ToggleFullscreen - Fullscreen toggle (only PLATFORM_DESKTOP) -func ToggleFullscreen() { - C.ToggleFullscreen() -} - -// SetWindowIcon - Set icon for window (only PLATFORM_DESKTOP) -func SetWindowIcon(image Image) { - cimage := image.cptr() - C.SetWindowIcon(*cimage) -} - -// SetWindowTitle - Set title for window (only PLATFORM_DESKTOP) -func SetWindowTitle(title string) { - ctitle := C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) - C.SetWindowTitle(ctitle) -} - -// SetWindowPosition - Set window position on screen (only PLATFORM_DESKTOP) -func SetWindowPosition(x, y int32) { - cx := (C.int)(x) - cy := (C.int)(y) - C.SetWindowPosition(cx, cy) -} - -// SetWindowMonitor - Set monitor for the current window (fullscreen mode) -func SetWindowMonitor(monitor int32) { - cmonitor := (C.int)(monitor) - C.SetWindowMonitor(cmonitor) -} - -// SetWindowMinSize - Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) -func SetWindowMinSize(w, h int32) { - cw := (C.int)(w) - ch := (C.int)(h) - C.SetWindowMinSize(cw, ch) -} - -// SetWindowSize - Set window dimensions -func SetWindowSize(w, h int32) { - cw := (C.int)(w) - ch := (C.int)(h) - C.SetWindowSize(cw, ch) -} - -// GetScreenWidth - Get current screen width -func GetScreenWidth() int32 { - ret := C.GetScreenWidth() - v := (int32)(ret) - return v -} - -// GetScreenHeight - Get current screen height -func GetScreenHeight() int32 { - ret := C.GetScreenHeight() - v := (int32)(ret) - return v -} - -// ClearBackground - Sets Background Color -func ClearBackground(color Color) { - ccolor := color.cptr() - C.ClearBackground(*ccolor) -} - -// BeginDrawing - Setup drawing canvas to start drawing -func BeginDrawing() { - C.BeginDrawing() -} - -// EndDrawing - End canvas drawing and Swap Buffers (Double Buffering) -func EndDrawing() { - C.EndDrawing() -} - -// BeginMode2D - Initialize 2D mode with custom camera -func BeginMode2D(camera Camera2D) { - ccamera := camera.cptr() - C.BeginMode2D(*ccamera) -} - -// EndMode2D - Ends 2D mode custom camera usage -func EndMode2D() { - C.EndMode2D() -} - -// BeginMode3D - Initializes 3D mode for drawing (Camera setup) -func BeginMode3D(camera Camera) { - ccamera := camera.cptr() - C.BeginMode3D(*ccamera) -} - -// EndMode3D - Ends 3D mode and returns to default 2D orthographic mode -func EndMode3D() { - C.EndMode3D() -} - -// BeginTextureMode - Initializes render texture for drawing -func BeginTextureMode(target RenderTexture2D) { - ctarget := target.cptr() - C.BeginTextureMode(*ctarget) -} - -// EndTextureMode - Ends drawing to render texture -func EndTextureMode() { - C.EndTextureMode() -} - -// GetMouseRay - Returns a ray trace from mouse position -func GetMouseRay(mousePosition Vector2, camera Camera) Ray { - cmousePosition := mousePosition.cptr() - ccamera := camera.cptr() - ret := C.GetMouseRay(*cmousePosition, *ccamera) - v := newRayFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetWorldToScreen - Returns the screen space position from a 3d world space position -func GetWorldToScreen(position Vector3, camera Camera) Vector2 { - cposition := position.cptr() - ccamera := camera.cptr() - ret := C.GetWorldToScreen(*cposition, *ccamera) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetCameraMatrix - Returns camera transform matrix (view matrix) -func GetCameraMatrix(camera Camera) Matrix { - ccamera := camera.cptr() - ret := C.GetCameraMatrix(*ccamera) - v := newMatrixFromPointer(unsafe.Pointer(&ret)) - return v -} - -// SetTargetFPS - Set target FPS (maximum) -func SetTargetFPS(fps int32) { - cfps := (C.int)(fps) - C.SetTargetFPS(cfps) -} - -// GetFPS - Returns current FPS -func GetFPS() float32 { - ret := C.GetFPS() - v := (float32)(ret) - return v -} - -// GetFrameTime - Returns time in seconds for one frame -func GetFrameTime() float32 { - ret := C.GetFrameTime() - v := (float32)(ret) - return v -} - -// GetTime - Return time in seconds -func GetTime() float32 { - ret := C.GetTime() - v := (float32)(ret) - return v -} - -// GetColor - Returns a Color struct from hexadecimal value -func GetColor(hexValue int32) Color { - chexValue := (C.int)(hexValue) - ret := C.GetColor(chexValue) - v := newColorFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ColorToInt - Returns hexadecimal value for a Color -func ColorToInt(color Color) int32 { - ccolor := color.cptr() - ret := C.ColorToInt(*ccolor) - v := (int32)(ret) - return v -} - -// ColorToHSV - Returns HSV values for a Color -// NOTE: Hue is returned as degrees [0..360] -func ColorToHSV(color Color) Vector3 { - ccolor := color.cptr() - ret := C.ColorToHSV(*ccolor) - v := newVector3FromPointer(unsafe.Pointer(&ret)) - return v -} - -// ColorNormalize - Returns color normalized as float [0..1] -func ColorNormalize(color Color) Vector4 { - result := Vector4{} - 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 -} - -// Vector3ToFloat - Converts Vector3 to float32 slice -func Vector3ToFloat(vec Vector3) []float32 { - data := make([]float32, 0) - data[0] = vec.X - data[1] = vec.Y - data[2] = vec.Z - - 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) - cmax := (C.int)(max) - ret := C.GetRandomValue(cmin, cmax) - v := (int32)(ret) - return v -} - -// Fade - Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -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 -} - -// ShowLogo - Activates raylib logo at startup (can be done with flags) -func ShowLogo() { - C.ShowLogo() -} - -// SetConfigFlags - Setup some window configuration flags -func SetConfigFlags(flags byte) { - cflags := (C.uchar)(flags) - C.SetConfigFlags(cflags) -} - -// TakeScreenshot - Takes a screenshot of current screen (saved a .png) -func TakeScreenshot(name string) { - cname := C.CString(name) - defer C.free(unsafe.Pointer(cname)) - C.TakeScreenshot(cname) -} - -// StorageSaveValue - Storage save integer value (to defined position) -func StorageSaveValue(position, value int32) { - cposition := (C.int)(position) - cvalue := (C.int)(value) - C.StorageSaveValue(cposition, cvalue) -} - -// StorageLoadValue - Storage load integer value (from defined position) -func StorageLoadValue(position int32) int32 { - cposition := (C.int)(position) - ret := C.StorageLoadValue(cposition) - v := (int32)(ret) - return v -} - -// IsKeyPressed - Detect if a key has been pressed once -func IsKeyPressed(key int32) bool { - ckey := (C.int)(key) - ret := C.IsKeyPressed(ckey) - v := bool(int(ret) == 1) - return v -} - -// IsKeyDown - Detect if a key is being pressed -func IsKeyDown(key int32) bool { - ckey := (C.int)(key) - ret := C.IsKeyDown(ckey) - v := bool(int(ret) == 1) - return v -} - -// IsKeyReleased - Detect if a key has been released once -func IsKeyReleased(key int32) bool { - ckey := (C.int)(key) - ret := C.IsKeyReleased(ckey) - v := bool(int(ret) == 1) - return v -} - -// IsKeyUp - Detect if a key is NOT being pressed -func IsKeyUp(key int32) bool { - ckey := (C.int)(key) - ret := C.IsKeyUp(ckey) - v := bool(int(ret) == 1) - return v -} - -// GetKeyPressed - Get latest key pressed -func GetKeyPressed() int32 { - ret := C.GetKeyPressed() - v := (int32)(ret) - return v -} - -// SetExitKey - Set a custom key to exit program (default is ESC) -func SetExitKey(key int32) { - ckey := (C.int)(key) - C.SetExitKey(ckey) -} - -// IsGamepadAvailable - Detect if a gamepad is available -func IsGamepadAvailable(gamepad int32) bool { - cgamepad := (C.int)(gamepad) - ret := C.IsGamepadAvailable(cgamepad) - v := bool(int(ret) == 1) - 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(int(ret) == 1) - return v -} - -// GetGamepadName - Return gamepad internal name id -func GetGamepadName(gamepad int32) string { - cgamepad := (C.int)(gamepad) - ret := C.GetGamepadName(cgamepad) - v := C.GoString(ret) - return v -} - -// IsGamepadButtonPressed - Detect if a gamepad button has been pressed once -func IsGamepadButtonPressed(gamepad, button int32) bool { - cgamepad := (C.int)(gamepad) - cbutton := (C.int)(button) - ret := C.IsGamepadButtonPressed(cgamepad, cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsGamepadButtonDown - Detect if a gamepad button is being pressed -func IsGamepadButtonDown(gamepad, button int32) bool { - cgamepad := (C.int)(gamepad) - cbutton := (C.int)(button) - ret := C.IsGamepadButtonDown(cgamepad, cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsGamepadButtonReleased - Detect if a gamepad button has been released once -func IsGamepadButtonReleased(gamepad, button int32) bool { - cgamepad := (C.int)(gamepad) - cbutton := (C.int)(button) - ret := C.IsGamepadButtonReleased(cgamepad, cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsGamepadButtonUp - Detect if a gamepad button is NOT being pressed -func IsGamepadButtonUp(gamepad, button int32) bool { - cgamepad := (C.int)(gamepad) - cbutton := (C.int)(button) - ret := C.IsGamepadButtonUp(cgamepad, cbutton) - v := bool(int(ret) == 1) - return v -} - -// GetGamepadButtonPressed - Get the last gamepad button pressed -func GetGamepadButtonPressed() int32 { - ret := C.GetGamepadButtonPressed() - v := (int32)(ret) - return v -} - -// GetGamepadAxisCount - Return gamepad axis count for a gamepad -func GetGamepadAxisCount(gamepad int32) int32 { - cgamepad := (C.int)(gamepad) - ret := C.GetGamepadAxisCount(cgamepad) - v := (int32)(ret) - return v -} - -// GetGamepadAxisMovement - Return axis movement value for a gamepad axis -func GetGamepadAxisMovement(gamepad, axis int32) float32 { - cgamepad := (C.int)(gamepad) - caxis := (C.int)(axis) - ret := C.GetGamepadAxisMovement(cgamepad, caxis) - v := (float32)(ret) - return v -} - -// IsMouseButtonPressed - Detect if a mouse button has been pressed once -func IsMouseButtonPressed(button int32) bool { - cbutton := (C.int)(button) - ret := C.IsMouseButtonPressed(cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsMouseButtonDown - Detect if a mouse button is being pressed -func IsMouseButtonDown(button int32) bool { - cbutton := (C.int)(button) - ret := C.IsMouseButtonDown(cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsMouseButtonReleased - Detect if a mouse button has been released once -func IsMouseButtonReleased(button int32) bool { - cbutton := (C.int)(button) - ret := C.IsMouseButtonReleased(cbutton) - v := bool(int(ret) == 1) - return v -} - -// IsMouseButtonUp - Detect if a mouse button is NOT being pressed -func IsMouseButtonUp(button int32) bool { - cbutton := (C.int)(button) - ret := C.IsMouseButtonUp(cbutton) - v := bool(int(ret) == 1) - return v -} - -// GetMouseX - Returns mouse position X -func GetMouseX() int32 { - ret := C.GetMouseX() - v := (int32)(ret) - return v -} - -// GetMouseY - Returns mouse position Y -func GetMouseY() int32 { - ret := C.GetMouseY() - v := (int32)(ret) - return v -} - -// GetMousePosition - Returns mouse position XY -func GetMousePosition() Vector2 { - ret := C.GetMousePosition() - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} - -// SetMousePosition - Set mouse position XY -func SetMousePosition(position Vector2) { - cposition := position.cptr() - C.SetMousePosition(*cposition) -} - -// SetMouseScale - Set mouse scaling -func SetMouseScale(scale float32) { - cscale := (C.float)(scale) - C.SetMouseScale(cscale) -} - -// GetMouseWheelMove - Returns mouse wheel movement Y -func GetMouseWheelMove() int32 { - ret := C.GetMouseWheelMove() - v := (int32)(ret) - return v -} - -// GetTouchX - Returns touch position X for touch point 0 (relative to screen size) -func GetTouchX() int32 { - ret := C.GetTouchX() - v := (int32)(ret) - return v -} - -// GetTouchY - Returns touch position Y for touch point 0 (relative to screen size) -func GetTouchY() int32 { - ret := C.GetTouchY() - v := (int32)(ret) - return v -} - -// GetTouchPosition - Returns touch position XY for a touch point index (relative to screen size) -func GetTouchPosition(index int32) Vector2 { - cindex := (C.int)(index) - ret := C.GetTouchPosition(cindex) - v := newVector2FromPointer(unsafe.Pointer(&ret)) - return v -} diff --git a/raylib/external/RGFW.h b/raylib/external/RGFW.h new file mode 100644 index 0000000..1582fbf --- /dev/null +++ b/raylib/external/RGFW.h @@ -0,0 +1,10837 @@ +/* +* +* 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/alsa/alisp.h b/raylib/external/alsa/alisp.h deleted file mode 100644 index 407ed64..0000000 --- a/raylib/external/alsa/alisp.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ALSA lisp implementation - * Copyright (c) 2003 by Jaroslav Kysela - * - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -struct alisp_cfg { - int verbose: 1, - warning: 1, - debug: 1; - snd_input_t *in; /* program code */ - snd_output_t *out; /* program output */ - snd_output_t *eout; /* error output */ - snd_output_t *vout; /* verbose output */ - snd_output_t *wout; /* warning output */ - snd_output_t *dout; /* debug output */ -}; - -struct alisp_instance; -struct alisp_object; -struct alisp_seq_iterator; - -struct alisp_cfg *alsa_lisp_default_cfg(snd_input_t *input); -void alsa_lisp_default_cfg_free(struct alisp_cfg *cfg); -int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **instance); -void alsa_lisp_free(struct alisp_instance *instance); -int alsa_lisp_function(struct alisp_instance *instance, struct alisp_seq_iterator **result, - const char *id, const char *args, ...) -#ifndef DOC_HIDDEN - __attribute__ ((format (printf, 4, 5))) -#endif - ; -void alsa_lisp_result_free(struct alisp_instance *instance, - struct alisp_seq_iterator *result); -int alsa_lisp_seq_first(struct alisp_instance *instance, const char *id, - struct alisp_seq_iterator **seq); -int alsa_lisp_seq_next(struct alisp_seq_iterator **seq); -int alsa_lisp_seq_count(struct alisp_seq_iterator *seq); -int alsa_lisp_seq_integer(struct alisp_seq_iterator *seq, long *val); -int alsa_lisp_seq_pointer(struct alisp_seq_iterator *seq, const char *ptr_id, void **ptr); diff --git a/raylib/external/alsa/asoundef.h b/raylib/external/alsa/asoundef.h deleted file mode 100644 index c6c4eec..0000000 --- a/raylib/external/alsa/asoundef.h +++ /dev/null @@ -1,310 +0,0 @@ -/** - * \file include/asoundef.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Definitions of constants for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_ASOUNDEF_H -#define __ALSA_ASOUNDEF_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Digital_Audio_Interface Constants for Digital Audio Interfaces - * AES/IEC958 channel status bits. - * \{ - */ - -#define IEC958_AES0_PROFESSIONAL (1<<0) /**< 0 = consumer, 1 = professional */ -#define IEC958_AES0_NONAUDIO (1<<1) /**< 0 = audio, 1 = non-audio */ -#define IEC958_AES0_PRO_EMPHASIS (7<<2) /**< mask - emphasis */ -#define IEC958_AES0_PRO_EMPHASIS_NOTID (0<<2) /**< emphasis not indicated */ -#define IEC958_AES0_PRO_EMPHASIS_NONE (1<<2) /**< no emphasis */ -#define IEC958_AES0_PRO_EMPHASIS_5015 (3<<2) /**< 50/15us emphasis */ -#define IEC958_AES0_PRO_EMPHASIS_CCITT (7<<2) /**< CCITT J.17 emphasis */ -#define IEC958_AES0_PRO_FREQ_UNLOCKED (1<<5) /**< source sample frequency: 0 = locked, 1 = unlocked */ -#define IEC958_AES0_PRO_FS (3<<6) /**< mask - sample frequency */ -#define IEC958_AES0_PRO_FS_NOTID (0<<6) /**< fs not indicated */ -#define IEC958_AES0_PRO_FS_44100 (1<<6) /**< 44.1kHz */ -#define IEC958_AES0_PRO_FS_48000 (2<<6) /**< 48kHz */ -#define IEC958_AES0_PRO_FS_32000 (3<<6) /**< 32kHz */ -#define IEC958_AES0_CON_NOT_COPYRIGHT (1<<2) /**< 0 = copyright, 1 = not copyright */ -#define IEC958_AES0_CON_EMPHASIS (7<<3) /**< mask - emphasis */ -#define IEC958_AES0_CON_EMPHASIS_NONE (0<<3) /**< no emphasis */ -#define IEC958_AES0_CON_EMPHASIS_5015 (1<<3) /**< 50/15us emphasis */ -#define IEC958_AES0_CON_MODE (3<<6) /**< mask - mode */ -#define IEC958_AES1_PRO_MODE (15<<0) /**< mask - channel mode */ -#define IEC958_AES1_PRO_MODE_NOTID (0<<0) /**< mode not indicated */ -#define IEC958_AES1_PRO_MODE_STEREOPHONIC (2<<0) /**< stereophonic - ch A is left */ -#define IEC958_AES1_PRO_MODE_SINGLE (4<<0) /**< single channel */ -#define IEC958_AES1_PRO_MODE_TWO (8<<0) /**< two channels */ -#define IEC958_AES1_PRO_MODE_PRIMARY (12<<0) /**< primary/secondary */ -#define IEC958_AES1_PRO_MODE_BYTE3 (15<<0) /**< vector to byte 3 */ -#define IEC958_AES1_PRO_USERBITS (15<<4) /**< mask - user bits */ -#define IEC958_AES1_PRO_USERBITS_NOTID (0<<4) /**< user bits not indicated */ -#define IEC958_AES1_PRO_USERBITS_192 (8<<4) /**< 192-bit structure */ -#define IEC958_AES1_PRO_USERBITS_UDEF (12<<4) /**< user defined application */ -#define IEC958_AES1_CON_CATEGORY 0x7f /**< consumer category */ -#define IEC958_AES1_CON_GENERAL 0x00 /**< general category */ -#define IEC958_AES1_CON_LASEROPT_MASK 0x07 /**< Laser-optical mask */ -#define IEC958_AES1_CON_LASEROPT_ID 0x01 /**< Laser-optical ID */ -#define IEC958_AES1_CON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x00) /**< IEC958 CD compatible device */ -#define IEC958_AES1_CON_NON_IEC908_CD (IEC958_AES1_CON_LASEROPT_ID|0x08) /**< non-IEC958 CD compatible device */ -#define IEC958_AES1_CON_MINI_DISC (IEC958_AES1_CON_LASEROPT_ID|0x48) /**< Mini-Disc device */ -#define IEC958_AES1_CON_DVD (IEC958_AES1_CON_LASEROPT_ID|0x18) /**< DVD device */ -#define IEC958_AES1_CON_LASTEROPT_OTHER (IEC958_AES1_CON_LASEROPT_ID|0x78) /**< Other laser-optical product */ -#define IEC958_AES1_CON_DIGDIGCONV_MASK 0x07 /**< digital<->digital converter mask */ -#define IEC958_AES1_CON_DIGDIGCONV_ID 0x02 /**< digital<->digital converter id */ -#define IEC958_AES1_CON_PCM_CODER (IEC958_AES1_CON_DIGDIGCONV_ID|0x00) /**< PCM coder */ -#define IEC958_AES1_CON_MIXER (IEC958_AES1_CON_DIGDIGCONV_ID|0x10) /**< Digital signal mixer */ -#define IEC958_AES1_CON_RATE_CONVERTER (IEC958_AES1_CON_DIGDIGCONV_ID|0x18) /**< Rate converter */ -#define IEC958_AES1_CON_SAMPLER (IEC958_AES1_CON_DIGDIGCONV_ID|0x20) /**< PCM sampler */ -#define IEC958_AES1_CON_DSP (IEC958_AES1_CON_DIGDIGCONV_ID|0x28) /**< Digital sound processor */ -#define IEC958_AES1_CON_DIGDIGCONV_OTHER (IEC958_AES1_CON_DIGDIGCONV_ID|0x78) /**< Other digital<->digital product */ -#define IEC958_AES1_CON_MAGNETIC_MASK 0x07 /**< Magnetic device mask */ -#define IEC958_AES1_CON_MAGNETIC_ID 0x03 /**< Magnetic device ID */ -#define IEC958_AES1_CON_DAT (IEC958_AES1_CON_MAGNETIC_ID|0x00) /**< Digital Audio Tape */ -#define IEC958_AES1_CON_VCR (IEC958_AES1_CON_MAGNETIC_ID|0x08) /**< Video recorder */ -#define IEC958_AES1_CON_DCC (IEC958_AES1_CON_MAGNETIC_ID|0x40) /**< Digital compact cassette */ -#define IEC958_AES1_CON_MAGNETIC_DISC (IEC958_AES1_CON_MAGNETIC_ID|0x18) /**< Magnetic disc digital audio device */ -#define IEC958_AES1_CON_MAGNETIC_OTHER (IEC958_AES1_CON_MAGNETIC_ID|0x78) /**< Other magnetic device */ -#define IEC958_AES1_CON_BROADCAST1_MASK 0x07 /**< Broadcast mask */ -#define IEC958_AES1_CON_BROADCAST1_ID 0x04 /**< Broadcast ID */ -#define IEC958_AES1_CON_DAB_JAPAN (IEC958_AES1_CON_BROADCAST1_ID|0x00) /**< Digital audio broadcast (Japan) */ -#define IEC958_AES1_CON_DAB_EUROPE (IEC958_AES1_CON_BROADCAST1_ID|0x08) /**< Digital audio broadcast (Europe) */ -#define IEC958_AES1_CON_DAB_USA (IEC958_AES1_CON_BROADCAST1_ID|0x60) /**< Digital audio broadcast (USA) */ -#define IEC958_AES1_CON_SOFTWARE (IEC958_AES1_CON_BROADCAST1_ID|0x40) /**< Electronic software delivery */ -#define IEC958_AES1_CON_IEC62105 (IEC958_AES1_CON_BROADCAST1_ID|0x20) /**< Used by another standard (IEC 62105) */ -#define IEC958_AES1_CON_BROADCAST1_OTHER (IEC958_AES1_CON_BROADCAST1_ID|0x78) /**< Other broadcast product */ -#define IEC958_AES1_CON_BROADCAST2_MASK 0x0f /**< Broadcast alternative mask */ -#define IEC958_AES1_CON_BROADCAST2_ID 0x0e /**< Broadcast alternative ID */ -#define IEC958_AES1_CON_MUSICAL_MASK 0x07 /**< Musical device mask */ -#define IEC958_AES1_CON_MUSICAL_ID 0x05 /**< Musical device ID */ -#define IEC958_AES1_CON_SYNTHESIZER (IEC958_AES1_CON_MUSICAL_ID|0x00) /**< Synthesizer */ -#define IEC958_AES1_CON_MICROPHONE (IEC958_AES1_CON_MUSICAL_ID|0x08) /**< Microphone */ -#define IEC958_AES1_CON_MUSICAL_OTHER (IEC958_AES1_CON_MUSICAL_ID|0x78) /**< Other musical device */ -#define IEC958_AES1_CON_ADC_MASK 0x1f /**< ADC Mask */ -#define IEC958_AES1_CON_ADC_ID 0x06 /**< ADC ID */ -#define IEC958_AES1_CON_ADC (IEC958_AES1_CON_ADC_ID|0x00) /**< ADC without copyright information */ -#define IEC958_AES1_CON_ADC_OTHER (IEC958_AES1_CON_ADC_ID|0x60) /**< Other ADC product (with no copyright information) */ -#define IEC958_AES1_CON_ADC_COPYRIGHT_MASK 0x1f /**< ADC Copyright mask */ -#define IEC958_AES1_CON_ADC_COPYRIGHT_ID 0x16 /**< ADC Copyright ID */ -#define IEC958_AES1_CON_ADC_COPYRIGHT (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x00) /**< ADC with copyright information */ -#define IEC958_AES1_CON_ADC_COPYRIGHT_OTHER (IEC958_AES1_CON_ADC_COPYRIGHT_ID|0x60) /**< Other ADC with copyright information product */ -#define IEC958_AES1_CON_SOLIDMEM_MASK 0x0f /**< Solid memory based products mask */ -#define IEC958_AES1_CON_SOLIDMEM_ID 0x08 /**< Solid memory based products ID */ -#define IEC958_AES1_CON_SOLIDMEM_DIGITAL_RECORDER_PLAYER (IEC958_AES1_CON_SOLIDMEM_ID|0x00) /**< Digital audio recorder and player using solid state memory */ -#define IEC958_AES1_CON_SOLIDMEM_OTHER (IEC958_AES1_CON_SOLIDMEM_ID|0x70) /**< Other solid state memory based product */ -#define IEC958_AES1_CON_EXPERIMENTAL 0x40 /**< experimental category */ -#define IEC958_AES1_CON_ORIGINAL (1<<7) /**< this bits depends on the category code */ -#define IEC958_AES2_PRO_SBITS (7<<0) /**< mask - sample bits */ -#define IEC958_AES2_PRO_SBITS_20 (2<<0) /**< 20-bit - coordination */ -#define IEC958_AES2_PRO_SBITS_24 (4<<0) /**< 24-bit - main audio */ -#define IEC958_AES2_PRO_SBITS_UDEF (6<<0) /**< user defined application */ -#define IEC958_AES2_PRO_WORDLEN (7<<3) /**< mask - source word length */ -#define IEC958_AES2_PRO_WORDLEN_NOTID (0<<3) /**< source word length not indicated */ -#define IEC958_AES2_PRO_WORDLEN_22_18 (2<<3) /**< 22-bit or 18-bit */ -#define IEC958_AES2_PRO_WORDLEN_23_19 (4<<3) /**< 23-bit or 19-bit */ -#define IEC958_AES2_PRO_WORDLEN_24_20 (5<<3) /**< 24-bit or 20-bit */ -#define IEC958_AES2_PRO_WORDLEN_20_16 (6<<3) /**< 20-bit or 16-bit */ -#define IEC958_AES2_CON_SOURCE (15<<0) /**< mask - source number */ -#define IEC958_AES2_CON_SOURCE_UNSPEC (0<<0) /**< source number unspecified */ -#define IEC958_AES2_CON_CHANNEL (15<<4) /**< mask - channel number */ -#define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4) /**< channel number unspecified */ -#define IEC958_AES3_CON_FS (15<<0) /**< mask - sample frequency */ -#define IEC958_AES3_CON_FS_44100 (0<<0) /**< 44.1kHz */ -#define IEC958_AES3_CON_FS_NOTID (1<<0) /**< sample frequency non indicated */ -#define IEC958_AES3_CON_FS_48000 (2<<0) /**< 48kHz */ -#define IEC958_AES3_CON_FS_32000 (3<<0) /**< 32kHz */ -#define IEC958_AES3_CON_FS_22050 (4<<0) /**< 22.05kHz */ -#define IEC958_AES3_CON_FS_24000 (6<<0) /**< 24kHz */ -#define IEC958_AES3_CON_FS_88200 (8<<0) /**< 88.2kHz */ -#define IEC958_AES3_CON_FS_768000 (9<<0) /**< 768kHz */ -#define IEC958_AES3_CON_FS_96000 (10<<0) /**< 96kHz */ -#define IEC958_AES3_CON_FS_176400 (12<<0) /**< 176.4kHz */ -#define IEC958_AES3_CON_FS_192000 (14<<0) /**< 192kHz */ -#define IEC958_AES3_CON_CLOCK (3<<4) /**< mask - clock accuracy */ -#define IEC958_AES3_CON_CLOCK_1000PPM (0<<4) /**< 1000 ppm */ -#define IEC958_AES3_CON_CLOCK_50PPM (1<<4) /**< 50 ppm */ -#define IEC958_AES3_CON_CLOCK_VARIABLE (2<<4) /**< variable pitch */ -#define IEC958_AES4_CON_MAX_WORDLEN_24 (1<<0) /**< 0 = 20-bit, 1 = 24-bit */ -#define IEC958_AES4_CON_WORDLEN (7<<1) /**< mask - sample word length */ -#define IEC958_AES4_CON_WORDLEN_NOTID (0<<1) /**< not indicated */ -#define IEC958_AES4_CON_WORDLEN_20_16 (1<<1) /**< 20-bit or 16-bit */ -#define IEC958_AES4_CON_WORDLEN_22_18 (2<<1) /**< 22-bit or 18-bit */ -#define IEC958_AES4_CON_WORDLEN_23_19 (4<<1) /**< 23-bit or 19-bit */ -#define IEC958_AES4_CON_WORDLEN_24_20 (5<<1) /**< 24-bit or 20-bit */ -#define IEC958_AES4_CON_WORDLEN_21_17 (6<<1) /**< 21-bit or 17-bit */ -#define IEC958_AES4_CON_ORIGFS (15<<4) /**< mask - original sample frequency */ -#define IEC958_AES4_CON_ORIGFS_NOTID (0<<4) /**< original sample frequency not indicated */ -#define IEC958_AES4_CON_ORIGFS_192000 (1<<4) /**< 192kHz */ -#define IEC958_AES4_CON_ORIGFS_12000 (2<<4) /**< 12kHz */ -#define IEC958_AES4_CON_ORIGFS_176400 (3<<4) /**< 176.4kHz */ -#define IEC958_AES4_CON_ORIGFS_96000 (5<<4) /**< 96kHz */ -#define IEC958_AES4_CON_ORIGFS_8000 (6<<4) /**< 8kHz */ -#define IEC958_AES4_CON_ORIGFS_88200 (7<<4) /**< 88.2kHz */ -#define IEC958_AES4_CON_ORIGFS_16000 (8<<4) /**< 16kHz */ -#define IEC958_AES4_CON_ORIGFS_24000 (9<<4) /**< 24kHz */ -#define IEC958_AES4_CON_ORIGFS_11025 (10<<4) /**< 11.025kHz */ -#define IEC958_AES4_CON_ORIGFS_22050 (11<<4) /**< 22.05kHz */ -#define IEC958_AES4_CON_ORIGFS_32000 (12<<4) /**< 32kHz */ -#define IEC958_AES4_CON_ORIGFS_48000 (13<<4) /**< 48kHz */ -#define IEC958_AES4_CON_ORIGFS_44100 (15<<4) /**< 44.1kHz */ -#define IEC958_AES5_CON_CGMSA (3<<0) /**< mask - CGMS-A */ -#define IEC958_AES5_CON_CGMSA_COPYFREELY (0<<0) /**< copying is permitted without restriction */ -#define IEC958_AES5_CON_CGMSA_COPYONCE (1<<0) /**< one generation of copies may be made */ -#define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0) /**< condition not be used */ -#define IEC958_AES5_CON_CGMSA_COPYNEVER (3<<0) /**< no copying is permitted */ - -/** \} */ - -/** - * \defgroup MIDI_Interface Constants for MIDI v1.0 - * Constants for MIDI v1.0. - * \{ - */ - -#define MIDI_CHANNELS 16 /**< Number of channels per port/cable. */ -#define MIDI_GM_DRUM_CHANNEL (10-1) /**< Channel number for GM drums. */ - -/** - * \defgroup MIDI_Commands MIDI Commands - * MIDI command codes. - * \{ - */ - -#define MIDI_CMD_NOTE_OFF 0x80 /**< note off */ -#define MIDI_CMD_NOTE_ON 0x90 /**< note on */ -#define MIDI_CMD_NOTE_PRESSURE 0xa0 /**< key pressure */ -#define MIDI_CMD_CONTROL 0xb0 /**< control change */ -#define MIDI_CMD_PGM_CHANGE 0xc0 /**< program change */ -#define MIDI_CMD_CHANNEL_PRESSURE 0xd0 /**< channel pressure */ -#define MIDI_CMD_BENDER 0xe0 /**< pitch bender */ - -#define MIDI_CMD_COMMON_SYSEX 0xf0 /**< sysex (system exclusive) begin */ -#define MIDI_CMD_COMMON_MTC_QUARTER 0xf1 /**< MTC quarter frame */ -#define MIDI_CMD_COMMON_SONG_POS 0xf2 /**< song position */ -#define MIDI_CMD_COMMON_SONG_SELECT 0xf3 /**< song select */ -#define MIDI_CMD_COMMON_TUNE_REQUEST 0xf6 /**< tune request */ -#define MIDI_CMD_COMMON_SYSEX_END 0xf7 /**< end of sysex */ -#define MIDI_CMD_COMMON_CLOCK 0xf8 /**< clock */ -#define MIDI_CMD_COMMON_START 0xfa /**< start */ -#define MIDI_CMD_COMMON_CONTINUE 0xfb /**< continue */ -#define MIDI_CMD_COMMON_STOP 0xfc /**< stop */ -#define MIDI_CMD_COMMON_SENSING 0xfe /**< active sensing */ -#define MIDI_CMD_COMMON_RESET 0xff /**< reset */ - -/** \} */ - -/** - * \defgroup MIDI_Controllers MIDI Controllers - * MIDI controller numbers. - * \{ - */ - -#define MIDI_CTL_MSB_BANK 0x00 /**< Bank selection */ -#define MIDI_CTL_MSB_MODWHEEL 0x01 /**< Modulation */ -#define MIDI_CTL_MSB_BREATH 0x02 /**< Breath */ -#define MIDI_CTL_MSB_FOOT 0x04 /**< Foot */ -#define MIDI_CTL_MSB_PORTAMENTO_TIME 0x05 /**< Portamento time */ -#define MIDI_CTL_MSB_DATA_ENTRY 0x06 /**< Data entry */ -#define MIDI_CTL_MSB_MAIN_VOLUME 0x07 /**< Main volume */ -#define MIDI_CTL_MSB_BALANCE 0x08 /**< Balance */ -#define MIDI_CTL_MSB_PAN 0x0a /**< Panpot */ -#define MIDI_CTL_MSB_EXPRESSION 0x0b /**< Expression */ -#define MIDI_CTL_MSB_EFFECT1 0x0c /**< Effect1 */ -#define MIDI_CTL_MSB_EFFECT2 0x0d /**< Effect2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE1 0x10 /**< General purpose 1 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE2 0x11 /**< General purpose 2 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE3 0x12 /**< General purpose 3 */ -#define MIDI_CTL_MSB_GENERAL_PURPOSE4 0x13 /**< General purpose 4 */ -#define MIDI_CTL_LSB_BANK 0x20 /**< Bank selection */ -#define MIDI_CTL_LSB_MODWHEEL 0x21 /**< Modulation */ -#define MIDI_CTL_LSB_BREATH 0x22 /**< Breath */ -#define MIDI_CTL_LSB_FOOT 0x24 /**< Foot */ -#define MIDI_CTL_LSB_PORTAMENTO_TIME 0x25 /**< Portamento time */ -#define MIDI_CTL_LSB_DATA_ENTRY 0x26 /**< Data entry */ -#define MIDI_CTL_LSB_MAIN_VOLUME 0x27 /**< Main volume */ -#define MIDI_CTL_LSB_BALANCE 0x28 /**< Balance */ -#define MIDI_CTL_LSB_PAN 0x2a /**< Panpot */ -#define MIDI_CTL_LSB_EXPRESSION 0x2b /**< Expression */ -#define MIDI_CTL_LSB_EFFECT1 0x2c /**< Effect1 */ -#define MIDI_CTL_LSB_EFFECT2 0x2d /**< Effect2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE1 0x30 /**< General purpose 1 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE2 0x31 /**< General purpose 2 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE3 0x32 /**< General purpose 3 */ -#define MIDI_CTL_LSB_GENERAL_PURPOSE4 0x33 /**< General purpose 4 */ -#define MIDI_CTL_SUSTAIN 0x40 /**< Sustain pedal */ -#define MIDI_CTL_PORTAMENTO 0x41 /**< Portamento */ -#define MIDI_CTL_SOSTENUTO 0x42 /**< Sostenuto */ -#define MIDI_CTL_SUSTENUTO 0x42 /**< Sostenuto (a typo in the older version) */ -#define MIDI_CTL_SOFT_PEDAL 0x43 /**< Soft pedal */ -#define MIDI_CTL_LEGATO_FOOTSWITCH 0x44 /**< Legato foot switch */ -#define MIDI_CTL_HOLD2 0x45 /**< Hold2 */ -#define MIDI_CTL_SC1_SOUND_VARIATION 0x46 /**< SC1 Sound Variation */ -#define MIDI_CTL_SC2_TIMBRE 0x47 /**< SC2 Timbre */ -#define MIDI_CTL_SC3_RELEASE_TIME 0x48 /**< SC3 Release Time */ -#define MIDI_CTL_SC4_ATTACK_TIME 0x49 /**< SC4 Attack Time */ -#define MIDI_CTL_SC5_BRIGHTNESS 0x4a /**< SC5 Brightness */ -#define MIDI_CTL_SC6 0x4b /**< SC6 */ -#define MIDI_CTL_SC7 0x4c /**< SC7 */ -#define MIDI_CTL_SC8 0x4d /**< SC8 */ -#define MIDI_CTL_SC9 0x4e /**< SC9 */ -#define MIDI_CTL_SC10 0x4f /**< SC10 */ -#define MIDI_CTL_GENERAL_PURPOSE5 0x50 /**< General purpose 5 */ -#define MIDI_CTL_GENERAL_PURPOSE6 0x51 /**< General purpose 6 */ -#define MIDI_CTL_GENERAL_PURPOSE7 0x52 /**< General purpose 7 */ -#define MIDI_CTL_GENERAL_PURPOSE8 0x53 /**< General purpose 8 */ -#define MIDI_CTL_PORTAMENTO_CONTROL 0x54 /**< Portamento control */ -#define MIDI_CTL_E1_REVERB_DEPTH 0x5b /**< E1 Reverb Depth */ -#define MIDI_CTL_E2_TREMOLO_DEPTH 0x5c /**< E2 Tremolo Depth */ -#define MIDI_CTL_E3_CHORUS_DEPTH 0x5d /**< E3 Chorus Depth */ -#define MIDI_CTL_E4_DETUNE_DEPTH 0x5e /**< E4 Detune Depth */ -#define MIDI_CTL_E5_PHASER_DEPTH 0x5f /**< E5 Phaser Depth */ -#define MIDI_CTL_DATA_INCREMENT 0x60 /**< Data Increment */ -#define MIDI_CTL_DATA_DECREMENT 0x61 /**< Data Decrement */ -#define MIDI_CTL_NONREG_PARM_NUM_LSB 0x62 /**< Non-registered parameter number */ -#define MIDI_CTL_NONREG_PARM_NUM_MSB 0x63 /**< Non-registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_LSB 0x64 /**< Registered parameter number */ -#define MIDI_CTL_REGIST_PARM_NUM_MSB 0x65 /**< Registered parameter number */ -#define MIDI_CTL_ALL_SOUNDS_OFF 0x78 /**< All sounds off */ -#define MIDI_CTL_RESET_CONTROLLERS 0x79 /**< Reset Controllers */ -#define MIDI_CTL_LOCAL_CONTROL_SWITCH 0x7a /**< Local control switch */ -#define MIDI_CTL_ALL_NOTES_OFF 0x7b /**< All notes off */ -#define MIDI_CTL_OMNI_OFF 0x7c /**< Omni off */ -#define MIDI_CTL_OMNI_ON 0x7d /**< Omni on */ -#define MIDI_CTL_MONO1 0x7e /**< Mono1 */ -#define MIDI_CTL_MONO2 0x7f /**< Mono2 */ - -/** \} */ - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_ASOUNDEF_H */ diff --git a/raylib/external/alsa/asoundlib.h b/raylib/external/alsa/asoundlib.h deleted file mode 100644 index a546194..0000000 --- a/raylib/external/alsa/asoundlib.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * \file include/asoundlib.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ASOUNDLIB_H -#define __ASOUNDLIB_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __GNUC__ -#define __inline__ inline -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* __ASOUNDLIB_H */ diff --git a/raylib/external/alsa/conf.h b/raylib/external/alsa/conf.h deleted file mode 100644 index efb1176..0000000 --- a/raylib/external/alsa/conf.h +++ /dev/null @@ -1,214 +0,0 @@ -/** - * \file include/conf.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_CONF_H -#define __ALSA_CONF_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Config Configuration Interface - * The configuration functions and types allow you to read, enumerate, - * modify and write the contents of ALSA configuration files. - * \{ - */ - -/** \brief \c dlsym version for the config evaluate callback. */ -#define SND_CONFIG_DLSYM_VERSION_EVALUATE _dlsym_config_evaluate_001 -/** \brief \c dlsym version for the config hook callback. */ -#define SND_CONFIG_DLSYM_VERSION_HOOK _dlsym_config_hook_001 - -/** \brief Configuration node type. */ -typedef enum _snd_config_type { - /** Integer number. */ - SND_CONFIG_TYPE_INTEGER, - /** 64-bit integer number. */ - SND_CONFIG_TYPE_INTEGER64, - /** Real number. */ - SND_CONFIG_TYPE_REAL, - /** Character string. */ - SND_CONFIG_TYPE_STRING, - /** Pointer (runtime only, cannot be saved). */ - SND_CONFIG_TYPE_POINTER, - /** Compound node. */ - SND_CONFIG_TYPE_COMPOUND = 1024 -} snd_config_type_t; - -/** - * \brief Internal structure for a configuration node object. - * - * The ALSA library uses a pointer to this structure as a handle to a - * configuration node. Applications don't access its contents directly. - */ -typedef struct _snd_config snd_config_t; -/** - * \brief Type for a configuration compound iterator. - * - * The ALSA library uses this pointer type as a handle to a configuration - * compound iterator. Applications don't directly access the contents of - * the structure pointed to by this type. - */ -typedef struct _snd_config_iterator *snd_config_iterator_t; -/** - * \brief Internal structure for a configuration private update object. - * - * The ALSA library uses this structure to save private update information. - */ -typedef struct _snd_config_update snd_config_update_t; - -extern snd_config_t *snd_config; - -const char *snd_config_topdir(void); - -int snd_config_top(snd_config_t **config); - -int snd_config_load(snd_config_t *config, snd_input_t *in); -int snd_config_load_override(snd_config_t *config, snd_input_t *in); -int snd_config_save(snd_config_t *config, snd_output_t *out); -int snd_config_update(void); -int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const char *path); -int snd_config_update_free(snd_config_update_t *update); -int snd_config_update_free_global(void); - -int snd_config_update_ref(snd_config_t **top); -void snd_config_ref(snd_config_t *top); -void snd_config_unref(snd_config_t *top); - -int snd_config_search(snd_config_t *config, const char *key, - snd_config_t **result); -int snd_config_searchv(snd_config_t *config, - snd_config_t **result, ...); -int snd_config_search_definition(snd_config_t *config, - const char *base, const char *key, - snd_config_t **result); - -int snd_config_expand(snd_config_t *config, snd_config_t *root, - const char *args, snd_config_t *private_data, - snd_config_t **result); -int snd_config_evaluate(snd_config_t *config, snd_config_t *root, - snd_config_t *private_data, snd_config_t **result); - -int snd_config_add(snd_config_t *config, snd_config_t *leaf); -int snd_config_delete(snd_config_t *config); -int snd_config_delete_compound_members(const snd_config_t *config); -int snd_config_copy(snd_config_t **dst, snd_config_t *src); - -int snd_config_make(snd_config_t **config, const char *key, - snd_config_type_t type); -int snd_config_make_integer(snd_config_t **config, const char *key); -int snd_config_make_integer64(snd_config_t **config, const char *key); -int snd_config_make_real(snd_config_t **config, const char *key); -int snd_config_make_string(snd_config_t **config, const char *key); -int snd_config_make_pointer(snd_config_t **config, const char *key); -int snd_config_make_compound(snd_config_t **config, const char *key, int join); - -int snd_config_imake_integer(snd_config_t **config, const char *key, const long value); -int snd_config_imake_integer64(snd_config_t **config, const char *key, const long long value); -int snd_config_imake_real(snd_config_t **config, const char *key, const double value); -int snd_config_imake_string(snd_config_t **config, const char *key, const char *ascii); -int snd_config_imake_safe_string(snd_config_t **config, const char *key, const char *ascii); -int snd_config_imake_pointer(snd_config_t **config, const char *key, const void *ptr); - -snd_config_type_t snd_config_get_type(const snd_config_t *config); - -int snd_config_set_id(snd_config_t *config, const char *id); -int snd_config_set_integer(snd_config_t *config, long value); -int snd_config_set_integer64(snd_config_t *config, long long value); -int snd_config_set_real(snd_config_t *config, double value); -int snd_config_set_string(snd_config_t *config, const char *value); -int snd_config_set_ascii(snd_config_t *config, const char *ascii); -int snd_config_set_pointer(snd_config_t *config, const void *ptr); -int snd_config_get_id(const snd_config_t *config, const char **value); -int snd_config_get_integer(const snd_config_t *config, long *value); -int snd_config_get_integer64(const snd_config_t *config, long long *value); -int snd_config_get_real(const snd_config_t *config, double *value); -int snd_config_get_ireal(const snd_config_t *config, double *value); -int snd_config_get_string(const snd_config_t *config, const char **value); -int snd_config_get_ascii(const snd_config_t *config, char **value); -int snd_config_get_pointer(const snd_config_t *config, const void **value); -int snd_config_test_id(const snd_config_t *config, const char *id); - -snd_config_iterator_t snd_config_iterator_first(const snd_config_t *node); -snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator); -snd_config_iterator_t snd_config_iterator_end(const snd_config_t *node); -snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator); - -/** - * \brief Helper macro to iterate over the children of a compound node. - * \param[in,out] pos Iterator variable for the current node. - * \param[in,out] next Temporary iterator variable for the next node. - * \param[in] node Handle to the compound configuration node to iterate over. - * - * Use this macro like a \c for statement, e.g.: - * \code - * snd_config_iterator_t pos, next; - * snd_config_for_each(pos, next, node) { - * snd_config_t *entry = snd_config_iterator_entry(pos); - * ... - * } - * \endcode - * - * This macro allows deleting or removing the current node. - */ -#define snd_config_for_each(pos, next, node) \ - for (pos = snd_config_iterator_first(node), next = snd_config_iterator_next(pos); pos != snd_config_iterator_end(node); pos = next, next = snd_config_iterator_next(pos)) - -/* Misc functions */ - -int snd_config_get_bool_ascii(const char *ascii); -int snd_config_get_bool(const snd_config_t *conf); -int snd_config_get_ctl_iface_ascii(const char *ascii); -int snd_config_get_ctl_iface(const snd_config_t *conf); - -/* Names functions */ - -/** - * Device-name list element - */ -typedef struct snd_devname snd_devname_t; - -/** - * Device-name list element (definition) - */ -struct snd_devname { - char *name; /**< Device name string */ - char *comment; /**< Comments */ - snd_devname_t *next; /**< Next pointer */ -}; - -int snd_names_list(const char *iface, snd_devname_t **list); -void snd_names_list_free(snd_devname_t *list); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_CONF_H */ diff --git a/raylib/external/alsa/control.h b/raylib/external/alsa/control.h deleted file mode 100644 index 1d4bfcb..0000000 --- a/raylib/external/alsa/control.h +++ /dev/null @@ -1,622 +0,0 @@ -/** - * \file include/control.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_CONTROL_H -#define __ALSA_CONTROL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Control Control Interface - * The control interface. - * See \ref control page for more details. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_CONTROL_DLSYM_VERSION _dlsym_control_001 - -/** IEC958 structure */ -typedef struct snd_aes_iec958 { - unsigned char status[24]; /**< AES/IEC958 channel status bits */ - unsigned char subcode[147]; /**< AES/IEC958 subcode bits */ - unsigned char pad; /**< nothing */ - unsigned char dig_subframe[4]; /**< AES/IEC958 subframe bits */ -} snd_aes_iec958_t; - -/** CTL card info container */ -typedef struct _snd_ctl_card_info snd_ctl_card_info_t; - -/** CTL element identifier container */ -typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t; - -/** CTL element identifier list container */ -typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; - -/** CTL element info container */ -typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; - -/** CTL element value container */ -typedef struct _snd_ctl_elem_value snd_ctl_elem_value_t; - -/** CTL event container */ -typedef struct _snd_ctl_event snd_ctl_event_t; - -/** CTL element type */ -typedef enum _snd_ctl_elem_type { - /** Invalid type */ - SND_CTL_ELEM_TYPE_NONE = 0, - /** Boolean contents */ - SND_CTL_ELEM_TYPE_BOOLEAN, - /** Integer contents */ - SND_CTL_ELEM_TYPE_INTEGER, - /** Enumerated contents */ - SND_CTL_ELEM_TYPE_ENUMERATED, - /** Bytes contents */ - SND_CTL_ELEM_TYPE_BYTES, - /** IEC958 (S/PDIF) setting content */ - SND_CTL_ELEM_TYPE_IEC958, - /** 64-bit integer contents */ - SND_CTL_ELEM_TYPE_INTEGER64, - SND_CTL_ELEM_TYPE_LAST = SND_CTL_ELEM_TYPE_INTEGER64 -} snd_ctl_elem_type_t; - -/** CTL related interface */ -typedef enum _snd_ctl_elem_iface { - /** Card level */ - SND_CTL_ELEM_IFACE_CARD = 0, - /** Hardware dependent device */ - SND_CTL_ELEM_IFACE_HWDEP, - /** Mixer */ - SND_CTL_ELEM_IFACE_MIXER, - /** PCM */ - SND_CTL_ELEM_IFACE_PCM, - /** RawMidi */ - SND_CTL_ELEM_IFACE_RAWMIDI, - /** Timer */ - SND_CTL_ELEM_IFACE_TIMER, - /** Sequencer */ - SND_CTL_ELEM_IFACE_SEQUENCER, - SND_CTL_ELEM_IFACE_LAST = SND_CTL_ELEM_IFACE_SEQUENCER -} snd_ctl_elem_iface_t; - -/** Event class */ -typedef enum _snd_ctl_event_type { - /** Elements related event */ - SND_CTL_EVENT_ELEM = 0, - SND_CTL_EVENT_LAST = SND_CTL_EVENT_ELEM -}snd_ctl_event_type_t; - -/** Element has been removed (Warning: test this first and if set don't - * test the other masks) \hideinitializer */ -#define SND_CTL_EVENT_MASK_REMOVE (~0U) -/** Element value has been changed \hideinitializer */ -#define SND_CTL_EVENT_MASK_VALUE (1<<0) -/** Element info has been changed \hideinitializer */ -#define SND_CTL_EVENT_MASK_INFO (1<<1) -/** Element has been added \hideinitializer */ -#define SND_CTL_EVENT_MASK_ADD (1<<2) -/** Element's TLV value has been changed \hideinitializer */ -#define SND_CTL_EVENT_MASK_TLV (1<<3) - -/** CTL name helper */ -#define SND_CTL_NAME_NONE "" -/** CTL name helper */ -#define SND_CTL_NAME_PLAYBACK "Playback " -/** CTL name helper */ -#define SND_CTL_NAME_CAPTURE "Capture " - -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_NONE "" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_SWITCH "Switch" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_VOLUME "Volume" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_DEFAULT "Default" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_MASK "Mask" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_CON_MASK "Con Mask" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_PRO_MASK "Pro Mask" -/** CTL name helper */ -#define SND_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" -/** Element name for IEC958 (S/PDIF) */ -#define SND_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SND_CTL_NAME_##direction SND_CTL_NAME_IEC958_##what - -/** Mask for the major Power State identifier */ -#define SND_CTL_POWER_MASK 0xff00 -/** ACPI/PCI Power State D0 */ -#define SND_CTL_POWER_D0 0x0000 -/** ACPI/PCI Power State D1 */ -#define SND_CTL_POWER_D1 0x0100 -/** ACPI/PCI Power State D2 */ -#define SND_CTL_POWER_D2 0x0200 -/** ACPI/PCI Power State D3 */ -#define SND_CTL_POWER_D3 0x0300 -/** ACPI/PCI Power State D3hot */ -#define SND_CTL_POWER_D3hot (SND_CTL_POWER_D3|0x0000) -/** ACPI/PCI Power State D3cold */ -#define SND_CTL_POWER_D3cold (SND_CTL_POWER_D3|0x0001) - -/** TLV type - Container */ -#define SND_CTL_TLVT_CONTAINER 0x0000 -/** TLV type - basic dB scale */ -#define SND_CTL_TLVT_DB_SCALE 0x0001 -/** TLV type - linear volume */ -#define SND_CTL_TLVT_DB_LINEAR 0x0002 -/** TLV type - dB range container */ -#define SND_CTL_TLVT_DB_RANGE 0x0003 -/** TLV type - dB scale specified by min/max values */ -#define SND_CTL_TLVT_DB_MINMAX 0x0004 -/** TLV type - dB scale specified by min/max values (with mute) */ -#define SND_CTL_TLVT_DB_MINMAX_MUTE 0x0005 - -/** Mute state */ -#define SND_CTL_TLV_DB_GAIN_MUTE -9999999 - -/** TLV type - fixed channel map positions */ -#define SND_CTL_TLVT_CHMAP_FIXED 0x00101 -/** TLV type - freely swappable channel map positions */ -#define SND_CTL_TLVT_CHMAP_VAR 0x00102 -/** TLV type - pair-wise swappable channel map positions */ -#define SND_CTL_TLVT_CHMAP_PAIRED 0x00103 - -/** CTL type */ -typedef enum _snd_ctl_type { - /** Kernel level CTL */ - SND_CTL_TYPE_HW, - /** Shared memory client CTL */ - SND_CTL_TYPE_SHM, - /** INET client CTL (not yet implemented) */ - SND_CTL_TYPE_INET, - /** External control plugin */ - SND_CTL_TYPE_EXT -} snd_ctl_type_t; - -/** Non blocking mode (flag for open mode) \hideinitializer */ -#define SND_CTL_NONBLOCK 0x0001 - -/** Async notification (flag for open mode) \hideinitializer */ -#define SND_CTL_ASYNC 0x0002 - -/** Read only (flag for open mode) \hideinitializer */ -#define SND_CTL_READONLY 0x0004 - -/** CTL handle */ -typedef struct _snd_ctl snd_ctl_t; - -/** Don't destroy the ctl handle when close */ -#define SND_SCTL_NOFREE 0x0001 - -/** SCTL type */ -typedef struct _snd_sctl snd_sctl_t; - -int snd_card_load(int card); -int snd_card_next(int *card); -int snd_card_get_index(const char *name); -int snd_card_get_name(int card, char **name); -int snd_card_get_longname(int card, char **name); - -int snd_device_name_hint(int card, const char *iface, void ***hints); -int snd_device_name_free_hint(void **hints); -char *snd_device_name_get_hint(const void *hint, const char *id); - -int snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode); -int snd_ctl_open_lconf(snd_ctl_t **ctl, const char *name, int mode, snd_config_t *lconf); -int snd_ctl_open_fallback(snd_ctl_t **ctl, snd_config_t *root, const char *name, const char *orig_name, int mode); -int snd_ctl_close(snd_ctl_t *ctl); -int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock); -static __inline__ int snd_ctl_abort(snd_ctl_t *ctl) { return snd_ctl_nonblock(ctl, 2); } -int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl, - snd_async_callback_t callback, void *private_data); -snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler); -int snd_ctl_poll_descriptors_count(snd_ctl_t *ctl); -int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int space); -int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe); -int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info); -int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list); -int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info); -int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data); -int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *data); -int snd_ctl_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); -int snd_ctl_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); -int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - unsigned int *tlv, unsigned int tlv_size); -int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - const unsigned int *tlv); -int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - const unsigned int *tlv); -#ifdef __ALSA_HWDEP_H -int snd_ctl_hwdep_next_device(snd_ctl_t *ctl, int * device); -int snd_ctl_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info); -#endif -#ifdef __ALSA_PCM_H -int snd_ctl_pcm_next_device(snd_ctl_t *ctl, int *device); -int snd_ctl_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info); -int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev); -#endif -#ifdef __ALSA_RAWMIDI_H -int snd_ctl_rawmidi_next_device(snd_ctl_t *ctl, int * device); -int snd_ctl_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info); -int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev); -#endif -int snd_ctl_set_power_state(snd_ctl_t *ctl, unsigned int state); -int snd_ctl_get_power_state(snd_ctl_t *ctl, unsigned int *state); - -int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_event_t *event); -int snd_ctl_wait(snd_ctl_t *ctl, int timeout); -const char *snd_ctl_name(snd_ctl_t *ctl); -snd_ctl_type_t snd_ctl_type(snd_ctl_t *ctl); - -const char *snd_ctl_elem_type_name(snd_ctl_elem_type_t type); -const char *snd_ctl_elem_iface_name(snd_ctl_elem_iface_t iface); -const char *snd_ctl_event_type_name(snd_ctl_event_type_t type); - -unsigned int snd_ctl_event_elem_get_mask(const snd_ctl_event_t *obj); -unsigned int snd_ctl_event_elem_get_numid(const snd_ctl_event_t *obj); -void snd_ctl_event_elem_get_id(const snd_ctl_event_t *obj, snd_ctl_elem_id_t *ptr); -snd_ctl_elem_iface_t snd_ctl_event_elem_get_interface(const snd_ctl_event_t *obj); -unsigned int snd_ctl_event_elem_get_device(const snd_ctl_event_t *obj); -unsigned int snd_ctl_event_elem_get_subdevice(const snd_ctl_event_t *obj); -const char *snd_ctl_event_elem_get_name(const snd_ctl_event_t *obj); -unsigned int snd_ctl_event_elem_get_index(const snd_ctl_event_t *obj); - -int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries); -void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj); - -char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id); -int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str); -int snd_ctl_ascii_value_parse(snd_ctl_t *handle, - snd_ctl_elem_value_t *dst, - snd_ctl_elem_info_t *info, - const char *value); - -size_t snd_ctl_elem_id_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_id_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_elem_id_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_id) -int snd_ctl_elem_id_malloc(snd_ctl_elem_id_t **ptr); -void snd_ctl_elem_id_free(snd_ctl_elem_id_t *obj); -void snd_ctl_elem_id_clear(snd_ctl_elem_id_t *obj); -void snd_ctl_elem_id_copy(snd_ctl_elem_id_t *dst, const snd_ctl_elem_id_t *src); -unsigned int snd_ctl_elem_id_get_numid(const snd_ctl_elem_id_t *obj); -snd_ctl_elem_iface_t snd_ctl_elem_id_get_interface(const snd_ctl_elem_id_t *obj); -unsigned int snd_ctl_elem_id_get_device(const snd_ctl_elem_id_t *obj); -unsigned int snd_ctl_elem_id_get_subdevice(const snd_ctl_elem_id_t *obj); -const char *snd_ctl_elem_id_get_name(const snd_ctl_elem_id_t *obj); -unsigned int snd_ctl_elem_id_get_index(const snd_ctl_elem_id_t *obj); -void snd_ctl_elem_id_set_numid(snd_ctl_elem_id_t *obj, unsigned int val); -void snd_ctl_elem_id_set_interface(snd_ctl_elem_id_t *obj, snd_ctl_elem_iface_t val); -void snd_ctl_elem_id_set_device(snd_ctl_elem_id_t *obj, unsigned int val); -void snd_ctl_elem_id_set_subdevice(snd_ctl_elem_id_t *obj, unsigned int val); -void snd_ctl_elem_id_set_name(snd_ctl_elem_id_t *obj, const char *val); -void snd_ctl_elem_id_set_index(snd_ctl_elem_id_t *obj, unsigned int val); - -size_t snd_ctl_card_info_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_card_info_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_card_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_info) -int snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr); -void snd_ctl_card_info_free(snd_ctl_card_info_t *obj); -void snd_ctl_card_info_clear(snd_ctl_card_info_t *obj); -void snd_ctl_card_info_copy(snd_ctl_card_info_t *dst, const snd_ctl_card_info_t *src); -int snd_ctl_card_info_get_card(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_id(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_driver(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj); -const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj); - -size_t snd_ctl_event_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_event_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_event_alloca(ptr) __snd_alloca(ptr, snd_ctl_event) -int snd_ctl_event_malloc(snd_ctl_event_t **ptr); -void snd_ctl_event_free(snd_ctl_event_t *obj); -void snd_ctl_event_clear(snd_ctl_event_t *obj); -void snd_ctl_event_copy(snd_ctl_event_t *dst, const snd_ctl_event_t *src); -snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj); - -size_t snd_ctl_elem_list_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_list_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_elem_list_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_list) -int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); -void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj); -void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj); -void snd_ctl_elem_list_copy(snd_ctl_elem_list_t *dst, const snd_ctl_elem_list_t *src); -void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val); -unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj); -unsigned int snd_ctl_elem_list_get_count(const snd_ctl_elem_list_t *obj); -void snd_ctl_elem_list_get_id(const snd_ctl_elem_list_t *obj, unsigned int idx, snd_ctl_elem_id_t *ptr); -unsigned int snd_ctl_elem_list_get_numid(const snd_ctl_elem_list_t *obj, unsigned int idx); -snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t *obj, unsigned int idx); -unsigned int snd_ctl_elem_list_get_device(const snd_ctl_elem_list_t *obj, unsigned int idx); -unsigned int snd_ctl_elem_list_get_subdevice(const snd_ctl_elem_list_t *obj, unsigned int idx); -const char *snd_ctl_elem_list_get_name(const snd_ctl_elem_list_t *obj, unsigned int idx); -unsigned int snd_ctl_elem_list_get_index(const snd_ctl_elem_list_t *obj, unsigned int idx); - -size_t snd_ctl_elem_info_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_info_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_elem_info_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_info) -int snd_ctl_elem_info_malloc(snd_ctl_elem_info_t **ptr); -void snd_ctl_elem_info_free(snd_ctl_elem_info_t *obj); -void snd_ctl_elem_info_clear(snd_ctl_elem_info_t *obj); -void snd_ctl_elem_info_copy(snd_ctl_elem_info_t *dst, const snd_ctl_elem_info_t *src); -snd_ctl_elem_type_t snd_ctl_elem_info_get_type(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_readable(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_writable(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_volatile(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_inactive(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_locked(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_tlv_readable(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_tlv_writable(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_tlv_commandable(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_owner(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj); -pid_t snd_ctl_elem_info_get_owner(const snd_ctl_elem_info_t *obj); -unsigned int snd_ctl_elem_info_get_count(const snd_ctl_elem_info_t *obj); -long snd_ctl_elem_info_get_min(const snd_ctl_elem_info_t *obj); -long snd_ctl_elem_info_get_max(const snd_ctl_elem_info_t *obj); -long snd_ctl_elem_info_get_step(const snd_ctl_elem_info_t *obj); -long long snd_ctl_elem_info_get_min64(const snd_ctl_elem_info_t *obj); -long long snd_ctl_elem_info_get_max64(const snd_ctl_elem_info_t *obj); -long long snd_ctl_elem_info_get_step64(const snd_ctl_elem_info_t *obj); -unsigned int snd_ctl_elem_info_get_items(const snd_ctl_elem_info_t *obj); -void snd_ctl_elem_info_set_item(snd_ctl_elem_info_t *obj, unsigned int val); -const char *snd_ctl_elem_info_get_item_name(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_get_dimensions(const snd_ctl_elem_info_t *obj); -int snd_ctl_elem_info_get_dimension(const snd_ctl_elem_info_t *obj, unsigned int idx); -int snd_ctl_elem_info_set_dimension(snd_ctl_elem_info_t *info, - const int dimension[4]); -void snd_ctl_elem_info_get_id(const snd_ctl_elem_info_t *obj, snd_ctl_elem_id_t *ptr); -unsigned int snd_ctl_elem_info_get_numid(const snd_ctl_elem_info_t *obj); -snd_ctl_elem_iface_t snd_ctl_elem_info_get_interface(const snd_ctl_elem_info_t *obj); -unsigned int snd_ctl_elem_info_get_device(const snd_ctl_elem_info_t *obj); -unsigned int snd_ctl_elem_info_get_subdevice(const snd_ctl_elem_info_t *obj); -const char *snd_ctl_elem_info_get_name(const snd_ctl_elem_info_t *obj); -unsigned int snd_ctl_elem_info_get_index(const snd_ctl_elem_info_t *obj); -void snd_ctl_elem_info_set_id(snd_ctl_elem_info_t *obj, const snd_ctl_elem_id_t *ptr); -void snd_ctl_elem_info_set_numid(snd_ctl_elem_info_t *obj, unsigned int val); -void snd_ctl_elem_info_set_interface(snd_ctl_elem_info_t *obj, snd_ctl_elem_iface_t val); -void snd_ctl_elem_info_set_device(snd_ctl_elem_info_t *obj, unsigned int val); -void snd_ctl_elem_info_set_subdevice(snd_ctl_elem_info_t *obj, unsigned int val); -void snd_ctl_elem_info_set_name(snd_ctl_elem_info_t *obj, const char *val); -void snd_ctl_elem_info_set_index(snd_ctl_elem_info_t *obj, unsigned int val); - -int snd_ctl_add_integer_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, - unsigned int element_count, - unsigned int member_count, - long min, long max, long step); -int snd_ctl_add_integer64_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, - unsigned int element_count, - unsigned int member_count, - long long min, long long max, - long long step); -int snd_ctl_add_boolean_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, - unsigned int element_count, - unsigned int member_count); -int snd_ctl_add_enumerated_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, - unsigned int element_count, - unsigned int member_count, - unsigned int items, - const char *const labels[]); -int snd_ctl_add_bytes_elem_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, - unsigned int element_count, - unsigned int member_count); - -int snd_ctl_elem_add_integer(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long imin, long imax, long istep); -int snd_ctl_elem_add_integer64(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, long long imin, long long imax, long long istep); -int snd_ctl_elem_add_boolean(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count); -int snd_ctl_elem_add_enumerated(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, unsigned int count, unsigned int items, const char *const names[]); -int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); -int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); - -size_t snd_ctl_elem_value_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_ctl_elem_value_t using standard alloca - * \param ptr returned pointer - */ -#define snd_ctl_elem_value_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_value) -int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr); -void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj); -void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj); -void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, const snd_ctl_elem_value_t *src); -int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, const snd_ctl_elem_value_t *right); -void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_t *ptr); -unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj); -snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t *obj); -unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj); -unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj); -const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj); -unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj); -void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr); -void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val); -void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_iface_t val); -void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val); -void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val); -void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val); -void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val); -int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx); -long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx); -long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx); -unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx); -unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx); -void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val); -void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val); -void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val); -void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val); -void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val); -void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size); -const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj); -void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr); -void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr); - -int snd_tlv_parse_dB_info(unsigned int *tlv, unsigned int tlv_size, - unsigned int **db_tlvp); -int snd_tlv_get_dB_range(unsigned int *tlv, long rangemin, long rangemax, - long *min, long *max); -int snd_tlv_convert_to_dB(unsigned int *tlv, long rangemin, long rangemax, - long volume, long *db_gain); -int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax, - long db_gain, long *value, int xdir); -int snd_ctl_get_dB_range(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - long *min, long *max); -int snd_ctl_convert_to_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - long volume, long *db_gain); -int snd_ctl_convert_from_dB(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id, - long db_gain, long *value, int xdir); - -/** - * \defgroup HControl High level Control Interface - * \ingroup Control - * The high level control interface. - * See \ref hcontrol page for more details. - * \{ - */ - -/** HCTL element handle */ -typedef struct _snd_hctl_elem snd_hctl_elem_t; - -/** HCTL handle */ -typedef struct _snd_hctl snd_hctl_t; - -/** - * \brief Compare function for sorting HCTL elements - * \param e1 First element - * \param e2 Second element - * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 - */ -typedef int (*snd_hctl_compare_t)(const snd_hctl_elem_t *e1, - const snd_hctl_elem_t *e2); -int snd_hctl_compare_fast(const snd_hctl_elem_t *c1, - const snd_hctl_elem_t *c2); -/** - * \brief HCTL callback function - * \param hctl HCTL handle - * \param mask event mask - * \param elem related HCTL element (if any) - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_hctl_callback_t)(snd_hctl_t *hctl, - unsigned int mask, - snd_hctl_elem_t *elem); -/** - * \brief HCTL element callback function - * \param elem HCTL element - * \param mask event mask - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_hctl_elem_callback_t)(snd_hctl_elem_t *elem, - unsigned int mask); - -int snd_hctl_open(snd_hctl_t **hctl, const char *name, int mode); -int snd_hctl_open_ctl(snd_hctl_t **hctlp, snd_ctl_t *ctl); -int snd_hctl_close(snd_hctl_t *hctl); -int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock); -static __inline__ int snd_hctl_abort(snd_hctl_t *hctl) { return snd_hctl_nonblock(hctl, 2); } -int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl); -int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space); -int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -unsigned int snd_hctl_get_count(snd_hctl_t *hctl); -int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort); -snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl); -snd_hctl_elem_t *snd_hctl_last_elem(snd_hctl_t *hctl); -snd_hctl_elem_t *snd_hctl_find_elem(snd_hctl_t *hctl, const snd_ctl_elem_id_t *id); -void snd_hctl_set_callback(snd_hctl_t *hctl, snd_hctl_callback_t callback); -void snd_hctl_set_callback_private(snd_hctl_t *hctl, void *data); -void *snd_hctl_get_callback_private(snd_hctl_t *hctl); -int snd_hctl_load(snd_hctl_t *hctl); -int snd_hctl_free(snd_hctl_t *hctl); -int snd_hctl_handle_events(snd_hctl_t *hctl); -const char *snd_hctl_name(snd_hctl_t *hctl); -int snd_hctl_wait(snd_hctl_t *hctl, int timeout); -snd_ctl_t *snd_hctl_ctl(snd_hctl_t *hctl); - -snd_hctl_elem_t *snd_hctl_elem_next(snd_hctl_elem_t *elem); -snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem); -int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info); -int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); -int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value); -int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size); -int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv); -int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv); - -snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem); - -void snd_hctl_elem_get_id(const snd_hctl_elem_t *obj, snd_ctl_elem_id_t *ptr); -unsigned int snd_hctl_elem_get_numid(const snd_hctl_elem_t *obj); -snd_ctl_elem_iface_t snd_hctl_elem_get_interface(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_device(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_subdevice(const snd_hctl_elem_t *obj); -const char *snd_hctl_elem_get_name(const snd_hctl_elem_t *obj); -unsigned int snd_hctl_elem_get_index(const snd_hctl_elem_t *obj); -void snd_hctl_elem_set_callback(snd_hctl_elem_t *obj, snd_hctl_elem_callback_t val); -void * snd_hctl_elem_get_callback_private(const snd_hctl_elem_t *obj); -void snd_hctl_elem_set_callback_private(snd_hctl_elem_t *obj, void * val); - -/** \} */ - -/** \} */ - -/** - * \defgroup SControl Setup Control Interface - * \ingroup Control - * The setup control interface - set or modify control elements from a configuration file. - * \{ - */ - -int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config, - snd_config_t *private_data, int mode); -int snd_sctl_free(snd_sctl_t *handle); -int snd_sctl_install(snd_sctl_t *handle); -int snd_sctl_remove(snd_sctl_t *handle); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_CONTROL_H */ diff --git a/raylib/external/alsa/control_external.h b/raylib/external/alsa/control_external.h deleted file mode 100644 index 12958e7..0000000 --- a/raylib/external/alsa/control_external.h +++ /dev/null @@ -1,286 +0,0 @@ -/** - * \file include/control_external.h - * \brief External control plugin SDK - * \author Takashi Iwai - * \date 2005 - * - * External control plugin SDK. - */ - -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#ifndef __ALSA_CONTROL_EXTERNAL_H -#define __ALSA_CONTROL_EXTERNAL_H - -#include "control.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup CtlPlugin_SDK External Control Plugin SDK - * \{ - */ - -/** - * Define the object entry for external control plugins - */ -#define SND_CTL_PLUGIN_ENTRY(name) _snd_ctl_##name##_open - -/** - * Define the symbols of the given control plugin with versions - */ -#define SND_CTL_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_CTL_PLUGIN_ENTRY(name), SND_CONTROL_DLSYM_VERSION); - -/** - * Define the control plugin - */ -#define SND_CTL_PLUGIN_DEFINE_FUNC(plugin) \ -int SND_CTL_PLUGIN_ENTRY(plugin) (snd_ctl_t **handlep, const char *name,\ - snd_config_t *root, snd_config_t *conf, int mode) - -/** External control plugin handle */ -typedef struct snd_ctl_ext snd_ctl_ext_t; -/** Callback table of control ext */ -typedef struct snd_ctl_ext_callback snd_ctl_ext_callback_t; -/** Key to access a control pointer */ -typedef unsigned long snd_ctl_ext_key_t; -#ifdef DOC_HIDDEN -/* redefine typedef's for stupid doxygen */ -typedef snd_ctl_ext snd_ctl_ext_t; -typedef snd_ctl_ext_callback snd_ctl_ext_callback_t; -#endif -/** Callback to handle TLV commands. */ -typedef int (snd_ctl_ext_tlv_rw_t)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, unsigned int numid, - unsigned int *tlv, unsigned int tlv_size); - -/* - * Protocol version - */ -#define SND_CTL_EXT_VERSION_MAJOR 1 /**< Protocol major version */ -#define SND_CTL_EXT_VERSION_MINOR 0 /**< Protocol minor version */ -#define SND_CTL_EXT_VERSION_TINY 1 /**< Protocol tiny version */ -/** - * external plugin protocol version - */ -#define SND_CTL_EXT_VERSION ((SND_CTL_EXT_VERSION_MAJOR<<16) |\ - (SND_CTL_EXT_VERSION_MINOR<<8) |\ - (SND_CTL_EXT_VERSION_TINY)) - -/** Handle of control ext */ -struct snd_ctl_ext { - /** - * protocol version; #SND_CTL_EXT_VERSION must be filled here - * before calling #snd_ctl_ext_create() - */ - unsigned int version; - /** - * Index of this card; must be filled before calling #snd_ctl_ext_create() - */ - int card_idx; - /** - * ID string of this card; must be filled before calling #snd_ctl_ext_create() - */ - char id[16]; - /** - * Driver name of this card; must be filled before calling #snd_ctl_ext_create() - */ - char driver[16]; - /** - * short name of this card; must be filled before calling #snd_ctl_ext_create() - */ - char name[32]; - /** - * Long name of this card; must be filled before calling #snd_ctl_ext_create() - */ - char longname[80]; - /** - * Mixer name of this card; must be filled before calling #snd_ctl_ext_create() - */ - char mixername[80]; - /** - * poll descriptor - */ - int poll_fd; - - /** - * callbacks of this plugin; must be filled before calling #snd_pcm_ioplug_create() - */ - const snd_ctl_ext_callback_t *callback; - /** - * private data, which can be used freely in the driver callbacks - */ - void *private_data; - /** - * control handle filled by #snd_ctl_ext_create() - */ - snd_ctl_t *handle; - - int nonblock; /**< non-block mode; read-only */ - int subscribed; /**< events subscribed; read-only */ - - /** - * optional TLV data for the control (since protocol 1.0.1) - */ - union { - snd_ctl_ext_tlv_rw_t *c; - const unsigned int *p; - } tlv; -}; - -/** Callback table of ext. */ -struct snd_ctl_ext_callback { - /** - * close the control handle; optional - */ - void (*close)(snd_ctl_ext_t *ext); - /** - * return the total number of elements; required - */ - int (*elem_count)(snd_ctl_ext_t *ext); - /** - * return the element id of the given offset (array index); required - */ - int (*elem_list)(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id); - /** - * convert the element id to a search key; required - */ - snd_ctl_ext_key_t (*find_elem)(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id); - /** - * the destructor of the key; optional - */ - void (*free_key)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key); - /** - * get the attribute of the element; required - */ - int (*get_attribute)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, - int *type, unsigned int *acc, unsigned int *count); - /** - * get the element information of integer type - */ - int (*get_integer_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, - long *imin, long *imax, long *istep); - /** - * get the element information of integer64 type - */ - int (*get_integer64_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, - int64_t *imin, int64_t *imax, int64_t *istep); - /** - * get the element information of enumerated type - */ - int (*get_enumerated_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); - /** - * get the name of the enumerated item - */ - int (*get_enumerated_name)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int item, - char *name, size_t name_max_len); - /** - * read the current values of integer type - */ - int (*read_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); - /** - * read the current values of integer64 type - */ - int (*read_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); - /** - * read the current values of enumerated type - */ - int (*read_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); - /** - * read the current values of bytes type - */ - int (*read_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, - size_t max_bytes); - /** - * read the current values of iec958 type - */ - int (*read_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); - /** - * update the current values of integer type with the given values - */ - int (*write_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); - /** - * update the current values of integer64 type with the given values - */ - int (*write_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); - /** - * update the current values of enumerated type with the given values - */ - int (*write_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); - /** - * update the current values of bytes type with the given values - */ - int (*write_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, - size_t max_bytes); - /** - * update the current values of iec958 type with the given values - */ - int (*write_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); - /** - * subscribe/unsubscribe the event notification; optional - */ - void (*subscribe_events)(snd_ctl_ext_t *ext, int subscribe); - /** - * read a pending notification event; optional - */ - int (*read_event)(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, unsigned int *event_mask); - /** - * return the number of poll descriptors; optional - */ - int (*poll_descriptors_count)(snd_ctl_ext_t *ext); - /** - * fill the poll descriptors; optional - */ - int (*poll_descriptors)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int space); - /** - * mangle the revents of poll descriptors - */ - int (*poll_revents)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -}; - -/** - * The access type bits stored in get_attribute callback - */ -typedef enum snd_ctl_ext_access { - SND_CTL_EXT_ACCESS_READ = (1<<0), - SND_CTL_EXT_ACCESS_WRITE = (1<<1), - SND_CTL_EXT_ACCESS_READWRITE = (3<<0), - SND_CTL_EXT_ACCESS_VOLATILE = (1<<2), - SND_CTL_EXT_ACCESS_TLV_READ = (1<<4), - SND_CTL_EXT_ACCESS_TLV_WRITE = (1<<5), - SND_CTL_EXT_ACCESS_TLV_READWRITE = (3<<4), - SND_CTL_EXT_ACCESS_TLV_COMMAND = (1<<6), - SND_CTL_EXT_ACCESS_INACTIVE = (1<<8), - SND_CTL_EXT_ACCESS_TLV_CALLBACK = (1<<28), -} snd_ctl_ext_access_t; - -/** - * find_elem callback returns this if no matching control element is found - */ -#define SND_CTL_EXT_KEY_NOT_FOUND (snd_ctl_ext_key_t)(-1) - -int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode); -int snd_ctl_ext_delete(snd_ctl_ext_t *ext); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_CONTROL_EXTERNAL_H */ diff --git a/raylib/external/alsa/error.h b/raylib/external/alsa/error.h deleted file mode 100644 index 38ee070..0000000 --- a/raylib/external/alsa/error.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * \file include/error.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_ERROR_H -#define __ALSA_ERROR_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Error Error handling - * Error handling macros and functions. - * \{ - */ - -#define SND_ERROR_BEGIN 500000 /**< Lower boundary of sound error codes. */ -#define SND_ERROR_INCOMPATIBLE_VERSION (SND_ERROR_BEGIN+0) /**< Kernel/library protocols are not compatible. */ -#define SND_ERROR_ALISP_NIL (SND_ERROR_BEGIN+1) /**< Lisp encountered an error during acall. */ - -const char *snd_strerror(int errnum); - -/** - * \brief Error handler callback. - * \param file Source file name. - * \param line Line number. - * \param function Function name. - * \param err Value of \c errno, or 0 if not relevant. - * \param fmt \c printf(3) format. - * \param ... \c printf(3) arguments. - * - * A function of this type is called by the ALSA library when an error occurs. - * This function usually shows the message on the screen, and/or logs it. - */ -typedef void (*snd_lib_error_handler_t)(const char *file, int line, const char *function, int err, const char *fmt, ...) /* __attribute__ ((format (printf, 5, 6))) */; -extern snd_lib_error_handler_t snd_lib_error; -extern int snd_lib_error_set_handler(snd_lib_error_handler_t handler); - -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 95) -#define SNDERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__) /**< Shows a sound error message. */ -#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__) /**< Shows a system error message (related to \c errno). */ -#else -#define SNDERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args) /**< Shows a sound error message. */ -#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args) /**< Shows a system error message (related to \c errno). */ -#endif - -/** \} */ - -#ifdef __cplusplus -} -#endif - -/** Local error handler function type */ -typedef void (*snd_local_error_handler_t)(const char *file, int line, - const char *func, int err, - const char *fmt, va_list arg); - -snd_local_error_handler_t snd_lib_error_set_local(snd_local_error_handler_t func); - -#endif /* __ALSA_ERROR_H */ - diff --git a/raylib/external/alsa/global.h b/raylib/external/alsa/global.h deleted file mode 100644 index 16a26dc..0000000 --- a/raylib/external/alsa/global.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * \file include/global.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_GLOBAL_H_ -#define __ALSA_GLOBAL_H_ - -/* for timeval and timespec */ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Global Global defines and functions - * Global defines and functions. - * \par - * The ALSA library implementation uses these macros and functions. - * Most applications probably do not need them. - * \{ - */ - -const char *snd_asoundlib_version(void); - -#ifndef ATTRIBUTE_UNUSED -/** do not print warning (gcc) when function parameter is not used */ -#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -#ifdef PIC /* dynamic build */ - -/** \hideinitializer \brief Helper macro for #SND_DLSYM_BUILD_VERSION. */ -#define __SND_DLSYM_VERSION(name, version) _ ## name ## version -/** - * \hideinitializer - * \brief Appends the build version to the name of a versioned dynamic symbol. - */ -#define SND_DLSYM_BUILD_VERSION(name, version) char __SND_DLSYM_VERSION(name, version); - -#else /* static build */ - -struct snd_dlsym_link { - struct snd_dlsym_link *next; - const char *dlsym_name; - const void *dlsym_ptr; -}; - -extern struct snd_dlsym_link *snd_dlsym_start; - -/** \hideinitializer \brief Helper macro for #SND_DLSYM_BUILD_VERSION. */ -#define __SND_DLSYM_VERSION(prefix, name, version) _ ## prefix ## name ## version -/** - * \hideinitializer - * \brief Appends the build version to the name of a versioned dynamic symbol. - */ -#define SND_DLSYM_BUILD_VERSION(name, version) \ - static struct snd_dlsym_link __SND_DLSYM_VERSION(snd_dlsym_, name, version); \ - void __SND_DLSYM_VERSION(snd_dlsym_constructor_, name, version) (void) __attribute__ ((constructor)); \ - void __SND_DLSYM_VERSION(snd_dlsym_constructor_, name, version) (void) { \ - __SND_DLSYM_VERSION(snd_dlsym_, name, version).next = snd_dlsym_start; \ - __SND_DLSYM_VERSION(snd_dlsym_, name, version).dlsym_name = # name; \ - __SND_DLSYM_VERSION(snd_dlsym_, name, version).dlsym_ptr = (void *)&name; \ - snd_dlsym_start = &__SND_DLSYM_VERSION(snd_dlsym_, name, version); \ - } - -#endif - -#ifndef __STRING -/** \brief Return 'x' argument as string */ -#define __STRING(x) #x -#endif - -/** \brief Returns the version of a dynamic symbol as a string. */ -#define SND_DLSYM_VERSION(version) __STRING(version) - -void *snd_dlopen(const char *file, int mode); -void *snd_dlsym(void *handle, const char *name, const char *version); -int snd_dlclose(void *handle); - - -/** \brief alloca helper macro. */ -#define __snd_alloca(ptr,type) do { *ptr = (type##_t *) alloca(type##_sizeof()); memset(*ptr, 0, type##_sizeof()); } while (0) - -/** - * \brief Internal structure for an async notification client handler. - * - * The ALSA library uses a pointer to this structure as a handle to an async - * notification object. Applications don't access its contents directly. - */ -typedef struct _snd_async_handler snd_async_handler_t; - -/** - * \brief Async notification callback. - * - * See the #snd_async_add_handler function for details. - */ -typedef void (*snd_async_callback_t)(snd_async_handler_t *handler); - -int snd_async_add_handler(snd_async_handler_t **handler, int fd, - snd_async_callback_t callback, void *private_data); -int snd_async_del_handler(snd_async_handler_t *handler); -int snd_async_handler_get_fd(snd_async_handler_t *handler); -int snd_async_handler_get_signo(snd_async_handler_t *handler); -void *snd_async_handler_get_callback_private(snd_async_handler_t *handler); - -struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr); -struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area); -int snd_shm_area_destroy(struct snd_shm_area *area); - -int snd_user_file(const char *file, char **result); - -#ifdef __GLIBC__ -#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE) -struct timeval { - time_t tv_sec; /* seconds */ - long tv_usec; /* microseconds */ -}; - -struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; -#endif -#endif - -/** Timestamp */ -typedef struct timeval snd_timestamp_t; -/** Hi-res timestamp */ -typedef struct timespec snd_htimestamp_t; - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_GLOBAL_H */ diff --git a/raylib/external/alsa/hwdep.h b/raylib/external/alsa/hwdep.h deleted file mode 100644 index ac71368..0000000 --- a/raylib/external/alsa/hwdep.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * \file include/hwdep.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_HWDEP_H -#define __ALSA_HWDEP_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup HwDep Hardware Dependant Interface - * The Hardware Dependant Interface. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_HWDEP_DLSYM_VERSION _dlsym_hwdep_001 - -/** HwDep information container */ -typedef struct _snd_hwdep_info snd_hwdep_info_t; - -/** HwDep DSP status container */ -typedef struct _snd_hwdep_dsp_status snd_hwdep_dsp_status_t; - -/** HwDep DSP image container */ -typedef struct _snd_hwdep_dsp_image snd_hwdep_dsp_image_t; - -/** HwDep interface */ -typedef enum _snd_hwdep_iface { - SND_HWDEP_IFACE_OPL2 = 0, /**< OPL2 raw driver */ - SND_HWDEP_IFACE_OPL3, /**< OPL3 raw driver */ - SND_HWDEP_IFACE_OPL4, /**< OPL4 raw driver */ - SND_HWDEP_IFACE_SB16CSP, /**< SB16CSP driver */ - SND_HWDEP_IFACE_EMU10K1, /**< EMU10K1 driver */ - SND_HWDEP_IFACE_YSS225, /**< YSS225 driver */ - SND_HWDEP_IFACE_ICS2115, /**< ICS2115 driver */ - SND_HWDEP_IFACE_SSCAPE, /**< Ensoniq SoundScape ISA card (MC68EC000) */ - SND_HWDEP_IFACE_VX, /**< Digigram VX cards */ - SND_HWDEP_IFACE_MIXART, /**< Digigram miXart cards */ - SND_HWDEP_IFACE_USX2Y, /**< Tascam US122, US224 & US428 usb */ - SND_HWDEP_IFACE_EMUX_WAVETABLE, /**< EmuX wavetable */ - SND_HWDEP_IFACE_BLUETOOTH, /**< Bluetooth audio */ - SND_HWDEP_IFACE_USX2Y_PCM, /**< Tascam US122, US224 & US428 raw USB PCM */ - SND_HWDEP_IFACE_PCXHR, /**< Digigram PCXHR */ - SND_HWDEP_IFACE_SB_RC, /**< SB Extigy/Audigy2NX remote control */ - SND_HWDEP_IFACE_HDA, /**< HD-audio */ - SND_HWDEP_IFACE_USB_STREAM, /**< direct access to usb stream */ - SND_HWDEP_IFACE_FW_DICE, /**< TC DICE FireWire device */ - SND_HWDEP_IFACE_FW_FIREWORKS, /**< Echo Audio Fireworks based device */ - SND_HWDEP_IFACE_FW_BEBOB, /**< BridgeCo BeBoB based device */ - SND_HWDEP_IFACE_FW_OXFW, /**< Oxford OXFW970/971 based device */ - SND_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */ - SND_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */ - SND_HWDEP_IFACE_LINE6, /* Line6 USB processors */ - SND_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */ - SND_HWDEP_IFACE_FW_FIREFACE, /* RME Fireface series */ - - SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_FW_FIREFACE, /**< last known hwdep interface */ -} snd_hwdep_iface_t; - -/** open for reading */ -#define SND_HWDEP_OPEN_READ (O_RDONLY) -/** open for writing */ -#define SND_HWDEP_OPEN_WRITE (O_WRONLY) -/** open for reading and writing */ -#define SND_HWDEP_OPEN_DUPLEX (O_RDWR) -/** open mode flag: open in nonblock mode */ -#define SND_HWDEP_OPEN_NONBLOCK (O_NONBLOCK) - -/** HwDep handle type */ -typedef enum _snd_hwdep_type { - /** Kernel level HwDep */ - SND_HWDEP_TYPE_HW, - /** Shared memory client HwDep (not yet implemented) */ - SND_HWDEP_TYPE_SHM, - /** INET client HwDep (not yet implemented) */ - SND_HWDEP_TYPE_INET -} snd_hwdep_type_t; - -/** HwDep handle */ -typedef struct _snd_hwdep snd_hwdep_t; - -int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode); -int snd_hwdep_close(snd_hwdep_t *hwdep); -int snd_hwdep_poll_descriptors(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int space); -int snd_hwdep_poll_descriptors_count(snd_hwdep_t *hwdep); -int snd_hwdep_poll_descriptors_revents(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_hwdep_nonblock(snd_hwdep_t *hwdep, int nonblock); -int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t * info); -int snd_hwdep_dsp_status(snd_hwdep_t *hwdep, snd_hwdep_dsp_status_t *status); -int snd_hwdep_dsp_load(snd_hwdep_t *hwdep, snd_hwdep_dsp_image_t *block); -int snd_hwdep_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg); -ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size); -ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size); - -size_t snd_hwdep_info_sizeof(void); -/** allocate #snd_hwdep_info_t container on stack */ -#define snd_hwdep_info_alloca(ptr) __snd_alloca(ptr, snd_hwdep_info) -int snd_hwdep_info_malloc(snd_hwdep_info_t **ptr); -void snd_hwdep_info_free(snd_hwdep_info_t *obj); -void snd_hwdep_info_copy(snd_hwdep_info_t *dst, const snd_hwdep_info_t *src); - -unsigned int snd_hwdep_info_get_device(const snd_hwdep_info_t *obj); -int snd_hwdep_info_get_card(const snd_hwdep_info_t *obj); -const char *snd_hwdep_info_get_id(const snd_hwdep_info_t *obj); -const char *snd_hwdep_info_get_name(const snd_hwdep_info_t *obj); -snd_hwdep_iface_t snd_hwdep_info_get_iface(const snd_hwdep_info_t *obj); -void snd_hwdep_info_set_device(snd_hwdep_info_t *obj, unsigned int val); - -size_t snd_hwdep_dsp_status_sizeof(void); -/** allocate #snd_hwdep_dsp_status_t container on stack */ -#define snd_hwdep_dsp_status_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_status) -int snd_hwdep_dsp_status_malloc(snd_hwdep_dsp_status_t **ptr); -void snd_hwdep_dsp_status_free(snd_hwdep_dsp_status_t *obj); -void snd_hwdep_dsp_status_copy(snd_hwdep_dsp_status_t *dst, const snd_hwdep_dsp_status_t *src); - -unsigned int snd_hwdep_dsp_status_get_version(const snd_hwdep_dsp_status_t *obj); -const char *snd_hwdep_dsp_status_get_id(const snd_hwdep_dsp_status_t *obj); -unsigned int snd_hwdep_dsp_status_get_num_dsps(const snd_hwdep_dsp_status_t *obj); -unsigned int snd_hwdep_dsp_status_get_dsp_loaded(const snd_hwdep_dsp_status_t *obj); -unsigned int snd_hwdep_dsp_status_get_chip_ready(const snd_hwdep_dsp_status_t *obj); - -size_t snd_hwdep_dsp_image_sizeof(void); -/** allocate #snd_hwdep_dsp_image_t container on stack */ -#define snd_hwdep_dsp_image_alloca(ptr) __snd_alloca(ptr, snd_hwdep_dsp_image) -int snd_hwdep_dsp_image_malloc(snd_hwdep_dsp_image_t **ptr); -void snd_hwdep_dsp_image_free(snd_hwdep_dsp_image_t *obj); -void snd_hwdep_dsp_image_copy(snd_hwdep_dsp_image_t *dst, const snd_hwdep_dsp_image_t *src); - -unsigned int snd_hwdep_dsp_image_get_index(const snd_hwdep_dsp_image_t *obj); -const char *snd_hwdep_dsp_image_get_name(const snd_hwdep_dsp_image_t *obj); -const void *snd_hwdep_dsp_image_get_image(const snd_hwdep_dsp_image_t *obj); -size_t snd_hwdep_dsp_image_get_length(const snd_hwdep_dsp_image_t *obj); - -void snd_hwdep_dsp_image_set_index(snd_hwdep_dsp_image_t *obj, unsigned int _index); -void snd_hwdep_dsp_image_set_name(snd_hwdep_dsp_image_t *obj, const char *name); -void snd_hwdep_dsp_image_set_image(snd_hwdep_dsp_image_t *obj, void *buffer); -void snd_hwdep_dsp_image_set_length(snd_hwdep_dsp_image_t *obj, size_t length); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_HWDEP_H */ - diff --git a/raylib/external/alsa/input.h b/raylib/external/alsa/input.h deleted file mode 100644 index fc5d0e6..0000000 --- a/raylib/external/alsa/input.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file include/input.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_INPUT_H -#define __ALSA_INPUT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Input Input Interface - * - * The input functions present an interface similar to the stdio functions - * on top of different underlying input sources. - * - * The #snd_config_load function uses such an input handle to be able to - * load configurations not only from standard files but also from other - * sources, e.g. from memory buffers. - * - * \{ - */ - -/** - * \brief Internal structure for an input object. - * - * The ALSA library uses a pointer to this structure as a handle to an - * input object. Applications don't access its contents directly. - */ -typedef struct _snd_input snd_input_t; - -/** Input type. */ -typedef enum _snd_input_type { - /** Input from a stdio stream. */ - SND_INPUT_STDIO, - /** Input from a memory buffer. */ - SND_INPUT_BUFFER -} snd_input_type_t; - -int snd_input_stdio_open(snd_input_t **inputp, const char *file, const char *mode); -int snd_input_stdio_attach(snd_input_t **inputp, FILE *fp, int _close); -int snd_input_buffer_open(snd_input_t **inputp, const char *buffer, ssize_t size); -int snd_input_close(snd_input_t *input); -int snd_input_scanf(snd_input_t *input, const char *format, ...) -#ifndef DOC_HIDDEN - __attribute__ ((format (scanf, 2, 3))) -#endif - ; -char *snd_input_gets(snd_input_t *input, char *str, size_t size); -int snd_input_getc(snd_input_t *input); -int snd_input_ungetc(snd_input_t *input, int c); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_INPUT_H */ diff --git a/raylib/external/alsa/mixer.h b/raylib/external/alsa/mixer.h deleted file mode 100644 index 066d978..0000000 --- a/raylib/external/alsa/mixer.h +++ /dev/null @@ -1,317 +0,0 @@ -/** - * \file include/mixer.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_MIXER_H -#define __ALSA_MIXER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Mixer Mixer Interface - * The mixer interface. - * \{ - */ - -/** Mixer handle */ -typedef struct _snd_mixer snd_mixer_t; -/** Mixer elements class handle */ -typedef struct _snd_mixer_class snd_mixer_class_t; -/** Mixer element handle */ -typedef struct _snd_mixer_elem snd_mixer_elem_t; - -/** - * \brief Mixer callback function - * \param mixer Mixer handle - * \param mask event mask - * \param elem related mixer element (if any) - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_mixer_callback_t)(snd_mixer_t *ctl, - unsigned int mask, - snd_mixer_elem_t *elem); - -/** - * \brief Mixer element callback function - * \param elem Mixer element - * \param mask event mask - * \return 0 on success otherwise a negative error code - */ -typedef int (*snd_mixer_elem_callback_t)(snd_mixer_elem_t *elem, - unsigned int mask); - -/** - * \brief Compare function for sorting mixer elements - * \param e1 First element - * \param e2 Second element - * \return -1 if e1 < e2, 0 if e1 == e2, 1 if e1 > e2 - */ -typedef int (*snd_mixer_compare_t)(const snd_mixer_elem_t *e1, - const snd_mixer_elem_t *e2); - -/** - * \brief Event callback for the mixer class - * \param class_ Mixer class - * \param mask Event mask (SND_CTL_EVENT_*) - * \param helem HCTL element which invoked the event - * \param melem Mixer element associated to HCTL element - * \return zero if success, otherwise a negative error value - */ -typedef int (*snd_mixer_event_t)(snd_mixer_class_t *class_, unsigned int mask, - snd_hctl_elem_t *helem, snd_mixer_elem_t *melem); - - -/** Mixer element type */ -typedef enum _snd_mixer_elem_type { - /* Simple mixer elements */ - SND_MIXER_ELEM_SIMPLE, - SND_MIXER_ELEM_LAST = SND_MIXER_ELEM_SIMPLE -} snd_mixer_elem_type_t; - -int snd_mixer_open(snd_mixer_t **mixer, int mode); -int snd_mixer_close(snd_mixer_t *mixer); -snd_mixer_elem_t *snd_mixer_first_elem(snd_mixer_t *mixer); -snd_mixer_elem_t *snd_mixer_last_elem(snd_mixer_t *mixer); -int snd_mixer_handle_events(snd_mixer_t *mixer); -int snd_mixer_attach(snd_mixer_t *mixer, const char *name); -int snd_mixer_attach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); -int snd_mixer_detach(snd_mixer_t *mixer, const char *name); -int snd_mixer_detach_hctl(snd_mixer_t *mixer, snd_hctl_t *hctl); -int snd_mixer_get_hctl(snd_mixer_t *mixer, const char *name, snd_hctl_t **hctl); -int snd_mixer_poll_descriptors_count(snd_mixer_t *mixer); -int snd_mixer_poll_descriptors(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int space); -int snd_mixer_poll_descriptors_revents(snd_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_mixer_load(snd_mixer_t *mixer); -void snd_mixer_free(snd_mixer_t *mixer); -int snd_mixer_wait(snd_mixer_t *mixer, int timeout); -int snd_mixer_set_compare(snd_mixer_t *mixer, snd_mixer_compare_t msort); -void snd_mixer_set_callback(snd_mixer_t *obj, snd_mixer_callback_t val); -void * snd_mixer_get_callback_private(const snd_mixer_t *obj); -void snd_mixer_set_callback_private(snd_mixer_t *obj, void * val); -unsigned int snd_mixer_get_count(const snd_mixer_t *obj); -int snd_mixer_class_unregister(snd_mixer_class_t *clss); - -snd_mixer_elem_t *snd_mixer_elem_next(snd_mixer_elem_t *elem); -snd_mixer_elem_t *snd_mixer_elem_prev(snd_mixer_elem_t *elem); -void snd_mixer_elem_set_callback(snd_mixer_elem_t *obj, snd_mixer_elem_callback_t val); -void * snd_mixer_elem_get_callback_private(const snd_mixer_elem_t *obj); -void snd_mixer_elem_set_callback_private(snd_mixer_elem_t *obj, void * val); -snd_mixer_elem_type_t snd_mixer_elem_get_type(const snd_mixer_elem_t *obj); - -int snd_mixer_class_register(snd_mixer_class_t *class_, snd_mixer_t *mixer); -int snd_mixer_elem_new(snd_mixer_elem_t **elem, - snd_mixer_elem_type_t type, - int compare_weight, - void *private_data, - void (*private_free)(snd_mixer_elem_t *elem)); -int snd_mixer_elem_add(snd_mixer_elem_t *elem, snd_mixer_class_t *class_); -int snd_mixer_elem_remove(snd_mixer_elem_t *elem); -void snd_mixer_elem_free(snd_mixer_elem_t *elem); -int snd_mixer_elem_info(snd_mixer_elem_t *elem); -int snd_mixer_elem_value(snd_mixer_elem_t *elem); -int snd_mixer_elem_attach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); -int snd_mixer_elem_detach(snd_mixer_elem_t *melem, snd_hctl_elem_t *helem); -int snd_mixer_elem_empty(snd_mixer_elem_t *melem); -void *snd_mixer_elem_get_private(const snd_mixer_elem_t *melem); - -size_t snd_mixer_class_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_mixer_class_t using standard alloca - * \param ptr returned pointer - */ -#define snd_mixer_class_alloca(ptr) __snd_alloca(ptr, snd_mixer_class) -int snd_mixer_class_malloc(snd_mixer_class_t **ptr); -void snd_mixer_class_free(snd_mixer_class_t *obj); -void snd_mixer_class_copy(snd_mixer_class_t *dst, const snd_mixer_class_t *src); -snd_mixer_t *snd_mixer_class_get_mixer(const snd_mixer_class_t *class_); -snd_mixer_event_t snd_mixer_class_get_event(const snd_mixer_class_t *class_); -void *snd_mixer_class_get_private(const snd_mixer_class_t *class_); -snd_mixer_compare_t snd_mixer_class_get_compare(const snd_mixer_class_t *class_); -int snd_mixer_class_set_event(snd_mixer_class_t *class_, snd_mixer_event_t event); -int snd_mixer_class_set_private(snd_mixer_class_t *class_, void *private_data); -int snd_mixer_class_set_private_free(snd_mixer_class_t *class_, void (*private_free)(snd_mixer_class_t *)); -int snd_mixer_class_set_compare(snd_mixer_class_t *class_, snd_mixer_compare_t compare); - -/** - * \defgroup SimpleMixer Simple Mixer Interface - * \ingroup Mixer - * The simple mixer interface. - * \{ - */ - -/* Simple mixer elements API */ - -/** Mixer simple element channel identifier */ -typedef enum _snd_mixer_selem_channel_id { - /** Unknown */ - SND_MIXER_SCHN_UNKNOWN = -1, - /** Front left */ - SND_MIXER_SCHN_FRONT_LEFT = 0, - /** Front right */ - SND_MIXER_SCHN_FRONT_RIGHT, - /** Rear left */ - SND_MIXER_SCHN_REAR_LEFT, - /** Rear right */ - SND_MIXER_SCHN_REAR_RIGHT, - /** Front center */ - SND_MIXER_SCHN_FRONT_CENTER, - /** Woofer */ - SND_MIXER_SCHN_WOOFER, - /** Side Left */ - SND_MIXER_SCHN_SIDE_LEFT, - /** Side Right */ - SND_MIXER_SCHN_SIDE_RIGHT, - /** Rear Center */ - SND_MIXER_SCHN_REAR_CENTER, - SND_MIXER_SCHN_LAST = 31, - /** Mono (Front left alias) */ - SND_MIXER_SCHN_MONO = SND_MIXER_SCHN_FRONT_LEFT -} snd_mixer_selem_channel_id_t; - -/** Mixer simple element - register options - abstraction level */ -enum snd_mixer_selem_regopt_abstract { - /** no abstraction - try use all universal controls from driver */ - SND_MIXER_SABSTRACT_NONE = 0, - /** basic abstraction - Master,PCM,CD,Aux,Record-Gain etc. */ - SND_MIXER_SABSTRACT_BASIC, -}; - -/** Mixer simple element - register options */ -struct snd_mixer_selem_regopt { - /** structure version */ - int ver; - /** v1: abstract layer selection */ - enum snd_mixer_selem_regopt_abstract abstract; - /** v1: device name (must be NULL when playback_pcm or capture_pcm != NULL) */ - const char *device; - /** v1: playback PCM connected to mixer device (NULL == none) */ - snd_pcm_t *playback_pcm; - /** v1: capture PCM connected to mixer device (NULL == none) */ - snd_pcm_t *capture_pcm; -}; - -/** Mixer simple element identifier */ -typedef struct _snd_mixer_selem_id snd_mixer_selem_id_t; - -const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel); - -int snd_mixer_selem_register(snd_mixer_t *mixer, - struct snd_mixer_selem_regopt *options, - snd_mixer_class_t **classp); -void snd_mixer_selem_get_id(snd_mixer_elem_t *element, - snd_mixer_selem_id_t *id); -const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem); -unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem); -snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, - const snd_mixer_selem_id_t *id); - -int snd_mixer_selem_is_active(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); -int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *obj, snd_mixer_selem_channel_id_t channel); -int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem); -int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem); - -int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); -int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue); -int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); -int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value); -int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value); -int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); -int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value); -int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); -int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value); -int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); -int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir); -int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value); -int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value); -int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir); -int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir); -int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); -int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value); -int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value); -int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value); -int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, - long min, long max); -int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, - long *min, long *max); -int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, - long min, long max); - -int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem); -int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem); -int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem); -int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, unsigned int idx, size_t maxlen, char *str); -int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *idxp); -int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int idx); - -size_t snd_mixer_selem_id_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_mixer_selem_id_t using standard alloca - * \param ptr returned pointer - */ -#define snd_mixer_selem_id_alloca(ptr) __snd_alloca(ptr, snd_mixer_selem_id) -int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr); -void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj); -void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src); -const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj); -unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj); -void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val); -void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val); - -/** \} */ - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_MIXER_H */ - diff --git a/raylib/external/alsa/mixer_abst.h b/raylib/external/alsa/mixer_abst.h deleted file mode 100644 index 7844b19..0000000 --- a/raylib/external/alsa/mixer_abst.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * \file include/mixer_abst.h - * \brief Mixer abstract implementation interface library for the ALSA library - * \author Jaroslav Kysela - * \date 2005 - * - * Mixer abstact implementation interface library for the ALSA library - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_MIXER_ABST_H -#define __ALSA_MIXER_ABST_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Mixer_Abstract Mixer Abstact Module Interface - * The mixer abstact module interface. - * \{ - */ - -#define SM_PLAY 0 -#define SM_CAPT 1 - -#define SM_CAP_GVOLUME (1<<1) -#define SM_CAP_GSWITCH (1<<2) -#define SM_CAP_PVOLUME (1<<3) -#define SM_CAP_PVOLUME_JOIN (1<<4) -#define SM_CAP_PSWITCH (1<<5) -#define SM_CAP_PSWITCH_JOIN (1<<6) -#define SM_CAP_CVOLUME (1<<7) -#define SM_CAP_CVOLUME_JOIN (1<<8) -#define SM_CAP_CSWITCH (1<<9) -#define SM_CAP_CSWITCH_JOIN (1<<10) -#define SM_CAP_CSWITCH_EXCL (1<<11) -#define SM_CAP_PENUM (1<<12) -#define SM_CAP_CENUM (1<<13) -/* SM_CAP_* 24-31 => private for module use */ - -#define SM_OPS_IS_ACTIVE 0 -#define SM_OPS_IS_MONO 1 -#define SM_OPS_IS_CHANNEL 2 -#define SM_OPS_IS_ENUMERATED 3 -#define SM_OPS_IS_ENUMCNT 4 - -#define sm_selem(x) ((sm_selem_t *)((x)->private_data)) -#define sm_selem_ops(x) ((sm_selem_t *)((x)->private_data))->ops - -typedef struct _sm_selem { - snd_mixer_selem_id_t *id; - struct sm_elem_ops *ops; - unsigned int caps; - unsigned int capture_group; -} sm_selem_t; - -typedef struct _sm_class_basic { - char *device; - snd_ctl_t *ctl; - snd_hctl_t *hctl; - snd_ctl_card_info_t *info; -} sm_class_basic_t; - -struct sm_elem_ops { - int (*is)(snd_mixer_elem_t *elem, int dir, int cmd, int val); - int (*get_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); - int (*set_range)(snd_mixer_elem_t *elem, int dir, long min, long max); - int (*get_dB_range)(snd_mixer_elem_t *elem, int dir, long *min, long *max); - int (*ask_vol_dB)(snd_mixer_elem_t *elem, int dir, long value, long *dbValue); - int (*ask_dB_vol)(snd_mixer_elem_t *elem, int dir, long dbValue, long *value, int xdir); - int (*get_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); - int (*get_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long *value); - int (*set_volume)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value); - int (*set_dB)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value, int xdir); - int (*get_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int *value); - int (*set_switch)(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value); - int (*enum_item_name)(snd_mixer_elem_t *elem, unsigned int item, size_t maxlen, char *buf); - int (*get_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int *itemp); - int (*set_enum_item)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, unsigned int item); -}; - -int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2); - -int snd_mixer_sbasic_info(const snd_mixer_class_t *class, sm_class_basic_t *info); -void *snd_mixer_sbasic_get_private(const snd_mixer_class_t *class); -void snd_mixer_sbasic_set_private(const snd_mixer_class_t *class, void *private_data); -void snd_mixer_sbasic_set_private_free(const snd_mixer_class_t *class, void (*private_free)(snd_mixer_class_t *class)); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_MIXER_ABST_H */ - diff --git a/raylib/external/alsa/output.h b/raylib/external/alsa/output.h deleted file mode 100644 index 5279aa2..0000000 --- a/raylib/external/alsa/output.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * \file include/output.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_OUTPUT_H -#define __ALSA_OUTPUT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Output Output Interface - * - * The output functions present an interface similar to the stdio functions - * on top of different underlying output destinations. - * - * Many PCM debugging functions (\c snd_pcm_xxx_dump_xxx) use such an output - * handle to be able to write not only to the screen but also to other - * destinations, e.g. to files or to memory buffers. - * - * \{ - */ - -/** - * \brief Internal structure for an output object. - * - * The ALSA library uses a pointer to this structure as a handle to an - * output object. Applications don't access its contents directly. - */ -typedef struct _snd_output snd_output_t; - -/** Output type. */ -typedef enum _snd_output_type { - /** Output to a stdio stream. */ - SND_OUTPUT_STDIO, - /** Output to a memory buffer. */ - SND_OUTPUT_BUFFER -} snd_output_type_t; - -int snd_output_stdio_open(snd_output_t **outputp, const char *file, const char *mode); -int snd_output_stdio_attach(snd_output_t **outputp, FILE *fp, int _close); -int snd_output_buffer_open(snd_output_t **outputp); -size_t snd_output_buffer_string(snd_output_t *output, char **buf); -int snd_output_close(snd_output_t *output); -int snd_output_printf(snd_output_t *output, const char *format, ...) -#ifndef DOC_HIDDEN - __attribute__ ((format (printf, 2, 3))) -#endif - ; -int snd_output_vprintf(snd_output_t *output, const char *format, va_list args); -int snd_output_puts(snd_output_t *output, const char *str); -int snd_output_putc(snd_output_t *output, int c); -int snd_output_flush(snd_output_t *output); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_OUTPUT_H */ - diff --git a/raylib/external/alsa/pcm.h b/raylib/external/alsa/pcm.h deleted file mode 100644 index d44de54..0000000 --- a/raylib/external/alsa/pcm.h +++ /dev/null @@ -1,1329 +0,0 @@ -/** - * \file include/pcm.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver. - * See the \ref pcm page for more details. - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_PCM_H -#define __ALSA_PCM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * \defgroup PCM PCM Interface - * See the \ref pcm page for more details. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_PCM_DLSYM_VERSION _dlsym_pcm_001 - -/** PCM generic info container */ -typedef struct _snd_pcm_info snd_pcm_info_t; - -/** PCM hardware configuration space container - * - * snd_pcm_hw_params_t is an opaque structure which contains a set of possible - * PCM hardware configurations. For example, a given instance might include a - * range of buffer sizes, a range of period sizes, and a set of several sample - * formats. Some subset of all possible combinations these sets may be valid, - * but not necessarily any combination will be valid. - * - * When a parameter is set or restricted using a snd_pcm_hw_params_set* - * function, all of the other ranges will be updated to exclude as many - * impossible configurations as possible. Attempting to set a parameter - * outside of its acceptable range will result in the function failing - * and an error code being returned. - */ -typedef struct _snd_pcm_hw_params snd_pcm_hw_params_t; - -/** PCM software configuration container */ -typedef struct _snd_pcm_sw_params snd_pcm_sw_params_t; -/** PCM status container */ - typedef struct _snd_pcm_status snd_pcm_status_t; -/** PCM access types mask */ -typedef struct _snd_pcm_access_mask snd_pcm_access_mask_t; -/** PCM formats mask */ -typedef struct _snd_pcm_format_mask snd_pcm_format_mask_t; -/** PCM subformats mask */ -typedef struct _snd_pcm_subformat_mask snd_pcm_subformat_mask_t; - -/** PCM class */ -typedef enum _snd_pcm_class { - /** standard device */ - - SND_PCM_CLASS_GENERIC = 0, - /** multichannel device */ - SND_PCM_CLASS_MULTI, - /** software modem device */ - SND_PCM_CLASS_MODEM, - /** digitizer device */ - SND_PCM_CLASS_DIGITIZER, - SND_PCM_CLASS_LAST = SND_PCM_CLASS_DIGITIZER -} snd_pcm_class_t; - -/** PCM subclass */ -typedef enum _snd_pcm_subclass { - /** subdevices are mixed together */ - SND_PCM_SUBCLASS_GENERIC_MIX = 0, - /** multichannel subdevices are mixed together */ - SND_PCM_SUBCLASS_MULTI_MIX, - SND_PCM_SUBCLASS_LAST = SND_PCM_SUBCLASS_MULTI_MIX -} snd_pcm_subclass_t; - -/** PCM stream (direction) */ -typedef enum _snd_pcm_stream { - /** Playback stream */ - SND_PCM_STREAM_PLAYBACK = 0, - /** Capture stream */ - SND_PCM_STREAM_CAPTURE, - SND_PCM_STREAM_LAST = SND_PCM_STREAM_CAPTURE -} snd_pcm_stream_t; - -/** PCM access type */ -typedef enum _snd_pcm_access { - /** mmap access with simple interleaved channels */ - SND_PCM_ACCESS_MMAP_INTERLEAVED = 0, - /** mmap access with simple non interleaved channels */ - SND_PCM_ACCESS_MMAP_NONINTERLEAVED, - /** mmap access with complex placement */ - SND_PCM_ACCESS_MMAP_COMPLEX, - /** snd_pcm_readi/snd_pcm_writei access */ - SND_PCM_ACCESS_RW_INTERLEAVED, - /** snd_pcm_readn/snd_pcm_writen access */ - SND_PCM_ACCESS_RW_NONINTERLEAVED, - SND_PCM_ACCESS_LAST = SND_PCM_ACCESS_RW_NONINTERLEAVED -} snd_pcm_access_t; - -/** PCM sample format */ -typedef enum _snd_pcm_format { - /** Unknown */ - SND_PCM_FORMAT_UNKNOWN = -1, - /** Signed 8 bit */ - SND_PCM_FORMAT_S8 = 0, - /** Unsigned 8 bit */ - SND_PCM_FORMAT_U8, - /** Signed 16 bit Little Endian */ - SND_PCM_FORMAT_S16_LE, - /** Signed 16 bit Big Endian */ - SND_PCM_FORMAT_S16_BE, - /** Unsigned 16 bit Little Endian */ - SND_PCM_FORMAT_U16_LE, - /** Unsigned 16 bit Big Endian */ - SND_PCM_FORMAT_U16_BE, - /** Signed 24 bit Little Endian using low three bytes in 32-bit word */ - SND_PCM_FORMAT_S24_LE, - /** Signed 24 bit Big Endian using low three bytes in 32-bit word */ - SND_PCM_FORMAT_S24_BE, - /** Unsigned 24 bit Little Endian using low three bytes in 32-bit word */ - SND_PCM_FORMAT_U24_LE, - /** Unsigned 24 bit Big Endian using low three bytes in 32-bit word */ - SND_PCM_FORMAT_U24_BE, - /** Signed 32 bit Little Endian */ - SND_PCM_FORMAT_S32_LE, - /** Signed 32 bit Big Endian */ - SND_PCM_FORMAT_S32_BE, - /** Unsigned 32 bit Little Endian */ - SND_PCM_FORMAT_U32_LE, - /** Unsigned 32 bit Big Endian */ - SND_PCM_FORMAT_U32_BE, - /** Float 32 bit Little Endian, Range -1.0 to 1.0 */ - SND_PCM_FORMAT_FLOAT_LE, - /** Float 32 bit Big Endian, Range -1.0 to 1.0 */ - SND_PCM_FORMAT_FLOAT_BE, - /** Float 64 bit Little Endian, Range -1.0 to 1.0 */ - SND_PCM_FORMAT_FLOAT64_LE, - /** Float 64 bit Big Endian, Range -1.0 to 1.0 */ - SND_PCM_FORMAT_FLOAT64_BE, - /** IEC-958 Little Endian */ - SND_PCM_FORMAT_IEC958_SUBFRAME_LE, - /** IEC-958 Big Endian */ - SND_PCM_FORMAT_IEC958_SUBFRAME_BE, - /** Mu-Law */ - SND_PCM_FORMAT_MU_LAW, - /** A-Law */ - SND_PCM_FORMAT_A_LAW, - /** Ima-ADPCM */ - SND_PCM_FORMAT_IMA_ADPCM, - /** MPEG */ - SND_PCM_FORMAT_MPEG, - /** GSM */ - SND_PCM_FORMAT_GSM, - /** Special */ - SND_PCM_FORMAT_SPECIAL = 31, - /** Signed 24bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_S24_3LE = 32, - /** Signed 24bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_S24_3BE, - /** Unsigned 24bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_U24_3LE, - /** Unsigned 24bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_U24_3BE, - /** Signed 20bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_S20_3LE, - /** Signed 20bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_S20_3BE, - /** Unsigned 20bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_U20_3LE, - /** Unsigned 20bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_U20_3BE, - /** Signed 18bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_S18_3LE, - /** Signed 18bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_S18_3BE, - /** Unsigned 18bit Little Endian in 3bytes format */ - SND_PCM_FORMAT_U18_3LE, - /** Unsigned 18bit Big Endian in 3bytes format */ - SND_PCM_FORMAT_U18_3BE, - /* G.723 (ADPCM) 24 kbit/s, 8 samples in 3 bytes */ - SND_PCM_FORMAT_G723_24, - /* G.723 (ADPCM) 24 kbit/s, 1 sample in 1 byte */ - SND_PCM_FORMAT_G723_24_1B, - /* G.723 (ADPCM) 40 kbit/s, 8 samples in 3 bytes */ - SND_PCM_FORMAT_G723_40, - /* G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte */ - SND_PCM_FORMAT_G723_40_1B, - /* Direct Stream Digital (DSD) in 1-byte samples (x8) */ - SND_PCM_FORMAT_DSD_U8, - /* Direct Stream Digital (DSD) in 2-byte samples (x16) */ - SND_PCM_FORMAT_DSD_U16_LE, - /* Direct Stream Digital (DSD) in 4-byte samples (x32) */ - SND_PCM_FORMAT_DSD_U32_LE, - /* Direct Stream Digital (DSD) in 2-byte samples (x16) */ - SND_PCM_FORMAT_DSD_U16_BE, - /* Direct Stream Digital (DSD) in 4-byte samples (x32) */ - SND_PCM_FORMAT_DSD_U32_BE, - SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U32_BE, - -#if __BYTE_ORDER == __LITTLE_ENDIAN - /** Signed 16 bit CPU endian */ - SND_PCM_FORMAT_S16 = SND_PCM_FORMAT_S16_LE, - /** Unsigned 16 bit CPU endian */ - SND_PCM_FORMAT_U16 = SND_PCM_FORMAT_U16_LE, - /** Signed 24 bit CPU endian */ - SND_PCM_FORMAT_S24 = SND_PCM_FORMAT_S24_LE, - /** Unsigned 24 bit CPU endian */ - SND_PCM_FORMAT_U24 = SND_PCM_FORMAT_U24_LE, - /** Signed 32 bit CPU endian */ - SND_PCM_FORMAT_S32 = SND_PCM_FORMAT_S32_LE, - /** Unsigned 32 bit CPU endian */ - SND_PCM_FORMAT_U32 = SND_PCM_FORMAT_U32_LE, - /** Float 32 bit CPU endian */ - SND_PCM_FORMAT_FLOAT = SND_PCM_FORMAT_FLOAT_LE, - /** Float 64 bit CPU endian */ - SND_PCM_FORMAT_FLOAT64 = SND_PCM_FORMAT_FLOAT64_LE, - /** IEC-958 CPU Endian */ - SND_PCM_FORMAT_IEC958_SUBFRAME = SND_PCM_FORMAT_IEC958_SUBFRAME_LE -#elif __BYTE_ORDER == __BIG_ENDIAN - /** Signed 16 bit CPU endian */ - SND_PCM_FORMAT_S16 = SND_PCM_FORMAT_S16_BE, - /** Unsigned 16 bit CPU endian */ - SND_PCM_FORMAT_U16 = SND_PCM_FORMAT_U16_BE, - /** Signed 24 bit CPU endian */ - SND_PCM_FORMAT_S24 = SND_PCM_FORMAT_S24_BE, - /** Unsigned 24 bit CPU endian */ - SND_PCM_FORMAT_U24 = SND_PCM_FORMAT_U24_BE, - /** Signed 32 bit CPU endian */ - SND_PCM_FORMAT_S32 = SND_PCM_FORMAT_S32_BE, - /** Unsigned 32 bit CPU endian */ - SND_PCM_FORMAT_U32 = SND_PCM_FORMAT_U32_BE, - /** Float 32 bit CPU endian */ - SND_PCM_FORMAT_FLOAT = SND_PCM_FORMAT_FLOAT_BE, - /** Float 64 bit CPU endian */ - SND_PCM_FORMAT_FLOAT64 = SND_PCM_FORMAT_FLOAT64_BE, - /** IEC-958 CPU Endian */ - SND_PCM_FORMAT_IEC958_SUBFRAME = SND_PCM_FORMAT_IEC958_SUBFRAME_BE -#else -#error "Unknown endian" -#endif -} snd_pcm_format_t; - -/** PCM sample subformat */ -typedef enum _snd_pcm_subformat { - /** Standard */ - SND_PCM_SUBFORMAT_STD = 0, - SND_PCM_SUBFORMAT_LAST = SND_PCM_SUBFORMAT_STD -} snd_pcm_subformat_t; - -/** PCM state */ -typedef enum _snd_pcm_state { - /** Open */ - SND_PCM_STATE_OPEN = 0, - /** Setup installed */ - SND_PCM_STATE_SETUP, - /** Ready to start */ - SND_PCM_STATE_PREPARED, - /** Running */ - SND_PCM_STATE_RUNNING, - /** Stopped: underrun (playback) or overrun (capture) detected */ - SND_PCM_STATE_XRUN, - /** Draining: running (playback) or stopped (capture) */ - SND_PCM_STATE_DRAINING, - /** Paused */ - SND_PCM_STATE_PAUSED, - /** Hardware is suspended */ - SND_PCM_STATE_SUSPENDED, - /** Hardware is disconnected */ - SND_PCM_STATE_DISCONNECTED, - SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED -} snd_pcm_state_t; - -/** PCM start mode */ -typedef enum _snd_pcm_start { - /** Automatic start on data read/write */ - SND_PCM_START_DATA = 0, - /** Explicit start */ - SND_PCM_START_EXPLICIT, - SND_PCM_START_LAST = SND_PCM_START_EXPLICIT -} snd_pcm_start_t; - -/** PCM xrun mode */ -typedef enum _snd_pcm_xrun { - /** Xrun detection disabled */ - SND_PCM_XRUN_NONE = 0, - /** Stop on xrun detection */ - SND_PCM_XRUN_STOP, - SND_PCM_XRUN_LAST = SND_PCM_XRUN_STOP -} snd_pcm_xrun_t; - -/** PCM timestamp mode */ -typedef enum _snd_pcm_tstamp { - /** No timestamp */ - SND_PCM_TSTAMP_NONE = 0, - /** Update timestamp at every hardware position update */ - SND_PCM_TSTAMP_ENABLE, - /** Equivalent with #SND_PCM_TSTAMP_ENABLE, - * just for compatibility with older versions - */ - SND_PCM_TSTAMP_MMAP = SND_PCM_TSTAMP_ENABLE, - SND_PCM_TSTAMP_LAST = SND_PCM_TSTAMP_ENABLE -} snd_pcm_tstamp_t; - -typedef enum _snd_pcm_tstamp_type { - SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /**< gettimeofday equivalent */ - SND_PCM_TSTAMP_TYPE_MONOTONIC, /**< posix_clock_monotonic equivalent */ - SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /**< monotonic_raw (no NTP) */ - SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, -} snd_pcm_tstamp_type_t; - -typedef struct _snd_pcm_audio_tstamp_config { - /* 5 of max 16 bits used */ - unsigned int type_requested:4; - unsigned int report_delay:1; /* add total delay to A/D or D/A */ -} snd_pcm_audio_tstamp_config_t; - -typedef struct _snd_pcm_audio_tstamp_report { - /* 6 of max 16 bits used for bit-fields */ - - /* for backwards compatibility */ - unsigned int valid:1; - - /* actual type if hardware could not support requested timestamp */ - unsigned int actual_type:4; - - /* accuracy represented in ns units */ - unsigned int accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */ - unsigned int accuracy; /* up to 4.29s, will be packed in separate field */ -} snd_pcm_audio_tstamp_report_t; - -/** Unsigned frames quantity */ -typedef unsigned long snd_pcm_uframes_t; -/** Signed frames quantity */ -typedef long snd_pcm_sframes_t; - -/** Non blocking mode (flag for open mode) \hideinitializer */ -#define SND_PCM_NONBLOCK 0x00000001 -/** Async notification (flag for open mode) \hideinitializer */ -#define SND_PCM_ASYNC 0x00000002 -/** In an abort state (internal, not allowed for open) */ -#define SND_PCM_ABORT 0x00008000 -/** Disable automatic (but not forced!) rate resamplinig */ -#define SND_PCM_NO_AUTO_RESAMPLE 0x00010000 -/** Disable automatic (but not forced!) channel conversion */ -#define SND_PCM_NO_AUTO_CHANNELS 0x00020000 -/** Disable automatic (but not forced!) format conversion */ -#define SND_PCM_NO_AUTO_FORMAT 0x00040000 -/** Disable soft volume control */ -#define SND_PCM_NO_SOFTVOL 0x00080000 - -/** PCM handle */ -typedef struct _snd_pcm snd_pcm_t; - -/** PCM type */ -enum _snd_pcm_type { - /** Kernel level PCM */ - SND_PCM_TYPE_HW = 0, - /** Hooked PCM */ - SND_PCM_TYPE_HOOKS, - /** One or more linked PCM with exclusive access to selected - channels */ - SND_PCM_TYPE_MULTI, - /** File writing plugin */ - SND_PCM_TYPE_FILE, - /** Null endpoint PCM */ - SND_PCM_TYPE_NULL, - /** Shared memory client PCM */ - SND_PCM_TYPE_SHM, - /** INET client PCM (not yet implemented) */ - SND_PCM_TYPE_INET, - /** Copying plugin */ - SND_PCM_TYPE_COPY, - /** Linear format conversion PCM */ - SND_PCM_TYPE_LINEAR, - /** A-Law format conversion PCM */ - SND_PCM_TYPE_ALAW, - /** Mu-Law format conversion PCM */ - SND_PCM_TYPE_MULAW, - /** IMA-ADPCM format conversion PCM */ - SND_PCM_TYPE_ADPCM, - /** Rate conversion PCM */ - SND_PCM_TYPE_RATE, - /** Attenuated static route PCM */ - SND_PCM_TYPE_ROUTE, - /** Format adjusted PCM */ - SND_PCM_TYPE_PLUG, - /** Sharing PCM */ - SND_PCM_TYPE_SHARE, - /** Meter plugin */ - SND_PCM_TYPE_METER, - /** Mixing PCM */ - SND_PCM_TYPE_MIX, - /** Attenuated dynamic route PCM (not yet implemented) */ - SND_PCM_TYPE_DROUTE, - /** Loopback server plugin (not yet implemented) */ - SND_PCM_TYPE_LBSERVER, - /** Linear Integer <-> Linear Float format conversion PCM */ - SND_PCM_TYPE_LINEAR_FLOAT, - /** LADSPA integration plugin */ - SND_PCM_TYPE_LADSPA, - /** Direct Mixing plugin */ - SND_PCM_TYPE_DMIX, - /** Jack Audio Connection Kit plugin */ - SND_PCM_TYPE_JACK, - /** Direct Snooping plugin */ - SND_PCM_TYPE_DSNOOP, - /** Direct Sharing plugin */ - SND_PCM_TYPE_DSHARE, - /** IEC958 subframe plugin */ - SND_PCM_TYPE_IEC958, - /** Soft volume plugin */ - SND_PCM_TYPE_SOFTVOL, - /** External I/O plugin */ - SND_PCM_TYPE_IOPLUG, - /** External filter plugin */ - SND_PCM_TYPE_EXTPLUG, - /** Mmap-emulation plugin */ - SND_PCM_TYPE_MMAP_EMUL, - SND_PCM_TYPE_LAST = SND_PCM_TYPE_MMAP_EMUL -}; - -/** PCM type */ -typedef enum _snd_pcm_type snd_pcm_type_t; - -/** PCM area specification */ -typedef struct _snd_pcm_channel_area { - /** base address of channel samples */ - void *addr; - /** offset to first sample in bits */ - unsigned int first; - /** samples distance in bits */ - unsigned int step; -} snd_pcm_channel_area_t; - -/** PCM synchronization ID */ -typedef union _snd_pcm_sync_id { - /** 8-bit ID */ - unsigned char id[16]; - /** 16-bit ID */ - unsigned short id16[8]; - /** 32-bit ID */ - unsigned int id32[4]; -} snd_pcm_sync_id_t; - -/** #SND_PCM_TYPE_METER scope handle */ -typedef struct _snd_pcm_scope snd_pcm_scope_t; - -int snd_pcm_open(snd_pcm_t **pcm, const char *name, - snd_pcm_stream_t stream, int mode); -int snd_pcm_open_lconf(snd_pcm_t **pcm, const char *name, - snd_pcm_stream_t stream, int mode, - snd_config_t *lconf); -int snd_pcm_open_fallback(snd_pcm_t **pcm, snd_config_t *root, - const char *name, const char *orig_name, - snd_pcm_stream_t stream, int mode); - -int snd_pcm_close(snd_pcm_t *pcm); -const char *snd_pcm_name(snd_pcm_t *pcm); -snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm); -snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm); -int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm); -int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); -int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock); -static __inline__ int snd_pcm_abort(snd_pcm_t *pcm) { return snd_pcm_nonblock(pcm, 2); } -int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm, - snd_async_callback_t callback, void *private_data); -snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler); -int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info); -int snd_pcm_hw_params_current(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -int snd_pcm_hw_free(snd_pcm_t *pcm); -int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); -int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); -int snd_pcm_prepare(snd_pcm_t *pcm); -int snd_pcm_reset(snd_pcm_t *pcm); -int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status); -int snd_pcm_start(snd_pcm_t *pcm); -int snd_pcm_drop(snd_pcm_t *pcm); -int snd_pcm_drain(snd_pcm_t *pcm); -int snd_pcm_pause(snd_pcm_t *pcm, int enable); -snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm); -int snd_pcm_hwsync(snd_pcm_t *pcm); -int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); -int snd_pcm_resume(snd_pcm_t *pcm); -int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, snd_htimestamp_t *tstamp); -snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm); -snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm); -int snd_pcm_avail_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *availp, snd_pcm_sframes_t *delayp); -snd_pcm_sframes_t snd_pcm_rewindable(snd_pcm_t *pcm); -snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_forwardable(snd_pcm_t *pcm); -snd_pcm_sframes_t snd_pcm_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); -int snd_pcm_wait(snd_pcm_t *pcm, int timeout); - -int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2); -int snd_pcm_unlink(snd_pcm_t *pcm); - -/** channel mapping API version number */ -#define SND_CHMAP_API_VERSION ((1 << 16) | (0 << 8) | 1) - -/** channel map list type */ -enum snd_pcm_chmap_type { - SND_CHMAP_TYPE_NONE = 0,/**< unspecified channel position */ - SND_CHMAP_TYPE_FIXED, /**< fixed channel position */ - SND_CHMAP_TYPE_VAR, /**< freely swappable channel position */ - SND_CHMAP_TYPE_PAIRED, /**< pair-wise swappable channel position */ - SND_CHMAP_TYPE_LAST = SND_CHMAP_TYPE_PAIRED, /**< last entry */ -}; - -/** channel positions */ -enum snd_pcm_chmap_position { - SND_CHMAP_UNKNOWN = 0, /**< unspecified */ - SND_CHMAP_NA, /**< N/A, silent */ - SND_CHMAP_MONO, /**< mono stream */ - SND_CHMAP_FL, /**< front left */ - SND_CHMAP_FR, /**< front right */ - SND_CHMAP_RL, /**< rear left */ - SND_CHMAP_RR, /**< rear right */ - SND_CHMAP_FC, /**< front center */ - SND_CHMAP_LFE, /**< LFE */ - SND_CHMAP_SL, /**< side left */ - SND_CHMAP_SR, /**< side right */ - SND_CHMAP_RC, /**< rear center */ - SND_CHMAP_FLC, /**< front left center */ - SND_CHMAP_FRC, /**< front right center */ - SND_CHMAP_RLC, /**< rear left center */ - SND_CHMAP_RRC, /**< rear right center */ - SND_CHMAP_FLW, /**< front left wide */ - SND_CHMAP_FRW, /**< front right wide */ - SND_CHMAP_FLH, /**< front left high */ - SND_CHMAP_FCH, /**< front center high */ - SND_CHMAP_FRH, /**< front right high */ - SND_CHMAP_TC, /**< top center */ - SND_CHMAP_TFL, /**< top front left */ - SND_CHMAP_TFR, /**< top front right */ - SND_CHMAP_TFC, /**< top front center */ - SND_CHMAP_TRL, /**< top rear left */ - SND_CHMAP_TRR, /**< top rear right */ - SND_CHMAP_TRC, /**< top rear center */ - SND_CHMAP_TFLC, /**< top front left center */ - SND_CHMAP_TFRC, /**< top front right center */ - SND_CHMAP_TSL, /**< top side left */ - SND_CHMAP_TSR, /**< top side right */ - SND_CHMAP_LLFE, /**< left LFE */ - SND_CHMAP_RLFE, /**< right LFE */ - SND_CHMAP_BC, /**< bottom center */ - SND_CHMAP_BLC, /**< bottom left center */ - SND_CHMAP_BRC, /**< bottom right center */ - SND_CHMAP_LAST = SND_CHMAP_BRC, -}; - -/** bitmask for channel position */ -#define SND_CHMAP_POSITION_MASK 0xffff - -/** bit flag indicating the channel is phase inverted */ -#define SND_CHMAP_PHASE_INVERSE (0x01 << 16) -/** bit flag indicating the non-standard channel value */ -#define SND_CHMAP_DRIVER_SPEC (0x02 << 16) - -/** the channel map header */ -typedef struct snd_pcm_chmap { - unsigned int channels; /**< number of channels */ - unsigned int pos[0]; /**< channel position array */ -} snd_pcm_chmap_t; - -/** the header of array items returned from snd_pcm_query_chmaps() */ -typedef struct snd_pcm_chmap_query { - enum snd_pcm_chmap_type type; /**< channel map type */ - snd_pcm_chmap_t map; /**< available channel map */ -} snd_pcm_chmap_query_t; - - -snd_pcm_chmap_query_t **snd_pcm_query_chmaps(snd_pcm_t *pcm); -snd_pcm_chmap_query_t **snd_pcm_query_chmaps_from_hw(int card, int dev, - int subdev, - snd_pcm_stream_t stream); -void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps); -snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm); -int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); - -const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val); -const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val); -const char *snd_pcm_chmap_long_name(enum snd_pcm_chmap_position val); -int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf); -unsigned int snd_pcm_chmap_from_string(const char *str); -snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str); - -//int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem); - -/* - * application helpers - these functions are implemented on top - * of the basic API - */ - -int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent); -int snd_pcm_set_params(snd_pcm_t *pcm, - snd_pcm_format_t format, - snd_pcm_access_t access, - unsigned int channels, - unsigned int rate, - int soft_resample, - unsigned int latency); -int snd_pcm_get_params(snd_pcm_t *pcm, - snd_pcm_uframes_t *buffer_size, - snd_pcm_uframes_t *period_size); - -/** \} */ - -/** - * \defgroup PCM_Info Stream Information - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_info_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_pcm_info_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_info_alloca(ptr) __snd_alloca(ptr, snd_pcm_info) -int snd_pcm_info_malloc(snd_pcm_info_t **ptr); -void snd_pcm_info_free(snd_pcm_info_t *obj); -void snd_pcm_info_copy(snd_pcm_info_t *dst, const snd_pcm_info_t *src); -unsigned int snd_pcm_info_get_device(const snd_pcm_info_t *obj); -unsigned int snd_pcm_info_get_subdevice(const snd_pcm_info_t *obj); -snd_pcm_stream_t snd_pcm_info_get_stream(const snd_pcm_info_t *obj); -int snd_pcm_info_get_card(const snd_pcm_info_t *obj); -const char *snd_pcm_info_get_id(const snd_pcm_info_t *obj); -const char *snd_pcm_info_get_name(const snd_pcm_info_t *obj); -const char *snd_pcm_info_get_subdevice_name(const snd_pcm_info_t *obj); -snd_pcm_class_t snd_pcm_info_get_class(const snd_pcm_info_t *obj); -snd_pcm_subclass_t snd_pcm_info_get_subclass(const snd_pcm_info_t *obj); -unsigned int snd_pcm_info_get_subdevices_count(const snd_pcm_info_t *obj); -unsigned int snd_pcm_info_get_subdevices_avail(const snd_pcm_info_t *obj); -snd_pcm_sync_id_t snd_pcm_info_get_sync(const snd_pcm_info_t *obj); -void snd_pcm_info_set_device(snd_pcm_info_t *obj, unsigned int val); -void snd_pcm_info_set_subdevice(snd_pcm_info_t *obj, unsigned int val); -void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val); - -/** \} */ - -/** - * \defgroup PCM_HW_Params Hardware Parameters - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -int snd_pcm_hw_params_can_mmap_sample_resolution(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_double(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_batch(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_block_transfer(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_monotonic(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_overrange(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_resume(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params); /* deprecated, use audio_ts_type */ -int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type); -int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, - unsigned int *rate_num, - unsigned int *rate_den); -int snd_pcm_hw_params_get_sbits(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params); - -#if 0 -typedef struct _snd_pcm_hw_strategy snd_pcm_hw_strategy_t; - -/* choices need to be sorted on ascending badness */ -typedef struct _snd_pcm_hw_strategy_simple_choices_list { - unsigned int value; - unsigned int badness; -} snd_pcm_hw_strategy_simple_choices_list_t; - -int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, - const snd_pcm_hw_strategy_t *strategy, - unsigned int badness_min, - unsigned int badness_max); - -void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy); -int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp, - unsigned int badness_min, - unsigned int badness_max); -int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm, - snd_pcm_hw_params_t *fail, - snd_pcm_hw_params_t *success, - unsigned int depth, - snd_output_t *out); - -#endif - -size_t snd_pcm_hw_params_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_pcm_hw_params_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params) -int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr); -void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj); -void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src); - -#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_HW_PARAMS_API) - -int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); -int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); -int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); -int snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); -int snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); -int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); -int snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); - -int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val); -int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); -int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); -int snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); -int snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); -int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); -void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); - -int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); -int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); -int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t subformat); -int snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); -int snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t *subformat); -int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); -void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); - -int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max); -int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); - -int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_get_export_buffer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_get_period_wakeup(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); - -int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); - -int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); -int snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); -int snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); -int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); -int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); -int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir); -int snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); - -int snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max); -int snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); - -#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_HW_PARAMS_API */ - -int snd_pcm_hw_params_get_min_align(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); - -/** \} */ - -/** - * \defgroup PCM_SW_Params Software Parameters - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_sw_params_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_pcm_sw_params_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_sw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_sw_params) -int snd_pcm_sw_params_malloc(snd_pcm_sw_params_t **ptr); -void snd_pcm_sw_params_free(snd_pcm_sw_params_t *obj); -void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t *src); -int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); - -#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_SW_PARAMS_API) - -int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); -int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val); -int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val); -int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val); -int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val); -int snd_pcm_sw_params_get_period_event(const snd_pcm_sw_params_t *params, int *val); -int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *paramsm, snd_pcm_uframes_t *val); -int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); - -#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_SW_PARAMS_API */ - -/** \} */ - -/* include old API */ -#ifndef ALSA_LIBRARY_BUILD -#if defined(ALSA_PCM_OLD_HW_PARAMS_API) || defined(ALSA_PCM_OLD_SW_PARAMS_API) -#include "pcm_old.h" -#endif -#endif - -/** - * \defgroup PCM_Access Access Mask Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_access_mask_sizeof(void); -/** \hideinitializer - * \brief allocate an empty #snd_pcm_access_mask_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_access_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_access_mask) -int snd_pcm_access_mask_malloc(snd_pcm_access_mask_t **ptr); -void snd_pcm_access_mask_free(snd_pcm_access_mask_t *obj); -void snd_pcm_access_mask_copy(snd_pcm_access_mask_t *dst, const snd_pcm_access_mask_t *src); -void snd_pcm_access_mask_none(snd_pcm_access_mask_t *mask); -void snd_pcm_access_mask_any(snd_pcm_access_mask_t *mask); -int snd_pcm_access_mask_test(const snd_pcm_access_mask_t *mask, snd_pcm_access_t val); -int snd_pcm_access_mask_empty(const snd_pcm_access_mask_t *mask); -void snd_pcm_access_mask_set(snd_pcm_access_mask_t *mask, snd_pcm_access_t val); -void snd_pcm_access_mask_reset(snd_pcm_access_mask_t *mask, snd_pcm_access_t val); - -/** \} */ - -/** - * \defgroup PCM_Format Format Mask Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_format_mask_sizeof(void); -/** \hideinitializer - * \brief allocate an empty #snd_pcm_format_mask_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_format_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_format_mask) -int snd_pcm_format_mask_malloc(snd_pcm_format_mask_t **ptr); -void snd_pcm_format_mask_free(snd_pcm_format_mask_t *obj); -void snd_pcm_format_mask_copy(snd_pcm_format_mask_t *dst, const snd_pcm_format_mask_t *src); -void snd_pcm_format_mask_none(snd_pcm_format_mask_t *mask); -void snd_pcm_format_mask_any(snd_pcm_format_mask_t *mask); -int snd_pcm_format_mask_test(const snd_pcm_format_mask_t *mask, snd_pcm_format_t val); -int snd_pcm_format_mask_empty(const snd_pcm_format_mask_t *mask); -void snd_pcm_format_mask_set(snd_pcm_format_mask_t *mask, snd_pcm_format_t val); -void snd_pcm_format_mask_reset(snd_pcm_format_mask_t *mask, snd_pcm_format_t val); - -/** \} */ - -/** - * \defgroup PCM_SubFormat Subformat Mask Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_subformat_mask_sizeof(void); -/** \hideinitializer - * \brief allocate an empty #snd_pcm_subformat_mask_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_subformat_mask_alloca(ptr) __snd_alloca(ptr, snd_pcm_subformat_mask) -int snd_pcm_subformat_mask_malloc(snd_pcm_subformat_mask_t **ptr); -void snd_pcm_subformat_mask_free(snd_pcm_subformat_mask_t *obj); -void snd_pcm_subformat_mask_copy(snd_pcm_subformat_mask_t *dst, const snd_pcm_subformat_mask_t *src); -void snd_pcm_subformat_mask_none(snd_pcm_subformat_mask_t *mask); -void snd_pcm_subformat_mask_any(snd_pcm_subformat_mask_t *mask); -int snd_pcm_subformat_mask_test(const snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); -int snd_pcm_subformat_mask_empty(const snd_pcm_subformat_mask_t *mask); -void snd_pcm_subformat_mask_set(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); -void snd_pcm_subformat_mask_reset(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val); - -/** \} */ - -/** - * \defgroup PCM_Status Status Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -size_t snd_pcm_status_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_pcm_status_t using standard alloca - * \param ptr returned pointer - */ -#define snd_pcm_status_alloca(ptr) __snd_alloca(ptr, snd_pcm_status) -int snd_pcm_status_malloc(snd_pcm_status_t **ptr); -void snd_pcm_status_free(snd_pcm_status_t *obj); -void snd_pcm_status_copy(snd_pcm_status_t *dst, const snd_pcm_status_t *src); -snd_pcm_state_t snd_pcm_status_get_state(const snd_pcm_status_t *obj); -void snd_pcm_status_get_trigger_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr); -void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); -void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr); -void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); -void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); -void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr); -void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj, - snd_pcm_audio_tstamp_report_t *audio_tstamp_report); -void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj, - snd_pcm_audio_tstamp_config_t *audio_tstamp_config); - -static inline void snd_pcm_pack_audio_tstamp_config(unsigned int *data, - snd_pcm_audio_tstamp_config_t *config) -{ - *data = config->report_delay; - *data <<= 4; - *data |= config->type_requested; -} - -static inline void snd_pcm_unpack_audio_tstamp_report(unsigned int data, unsigned int accuracy, - snd_pcm_audio_tstamp_report_t *report) -{ - data >>= 16; - report->valid = data & 1; - report->actual_type = (data >> 1) & 0xF; - report->accuracy_report = (data >> 5) & 1; - report->accuracy = accuracy; -} - -snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj); -snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj); -snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj); -snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj); - -/** \} */ - -/** - * \defgroup PCM_Description Description Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -const char *snd_pcm_type_name(snd_pcm_type_t type); -const char *snd_pcm_stream_name(const snd_pcm_stream_t stream); -const char *snd_pcm_access_name(const snd_pcm_access_t _access); -const char *snd_pcm_format_name(const snd_pcm_format_t format); -const char *snd_pcm_format_description(const snd_pcm_format_t format); -const char *snd_pcm_subformat_name(const snd_pcm_subformat_t subformat); -const char *snd_pcm_subformat_description(const snd_pcm_subformat_t subformat); -snd_pcm_format_t snd_pcm_format_value(const char* name); -const char *snd_pcm_tstamp_mode_name(const snd_pcm_tstamp_t mode); -const char *snd_pcm_state_name(const snd_pcm_state_t state); - -/** \} */ - -/** - * \defgroup PCM_Dump Debug Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -int snd_pcm_dump(snd_pcm_t *pcm, snd_output_t *out); -int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, snd_output_t *out); -int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out); -int snd_pcm_dump_setup(snd_pcm_t *pcm, snd_output_t *out); -int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out); -int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out); -int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out); - -/** \} */ - -/** - * \defgroup PCM_Direct Direct Access (MMAP) Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -int snd_pcm_mmap_begin(snd_pcm_t *pcm, - const snd_pcm_channel_area_t **areas, - snd_pcm_uframes_t *offset, - snd_pcm_uframes_t *frames); -snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t frames); -snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); -snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); - -/** \} */ - -/** - * \defgroup PCM_Helpers Helper Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -int snd_pcm_format_signed(snd_pcm_format_t format); -int snd_pcm_format_unsigned(snd_pcm_format_t format); -int snd_pcm_format_linear(snd_pcm_format_t format); -int snd_pcm_format_float(snd_pcm_format_t format); -int snd_pcm_format_little_endian(snd_pcm_format_t format); -int snd_pcm_format_big_endian(snd_pcm_format_t format); -int snd_pcm_format_cpu_endian(snd_pcm_format_t format); -int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ -int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ -snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian); -ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); -uint8_t snd_pcm_format_silence(snd_pcm_format_t format); -uint16_t snd_pcm_format_silence_16(snd_pcm_format_t format); -uint32_t snd_pcm_format_silence_32(snd_pcm_format_t format); -uint64_t snd_pcm_format_silence_64(snd_pcm_format_t format); -int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int samples); - -snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes); -ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames); -long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes); -ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples); - -int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset, - unsigned int samples, snd_pcm_format_t format); -int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_channels, snd_pcm_uframes_t dst_offset, - unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format); -int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset, - const snd_pcm_channel_area_t *src_channel, snd_pcm_uframes_t src_offset, - unsigned int samples, snd_pcm_format_t format); -int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_channels, snd_pcm_uframes_t dst_offset, - const snd_pcm_channel_area_t *src_channels, snd_pcm_uframes_t src_offset, - unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format); - -/** \} */ - -/** - * \defgroup PCM_Hook Hook Extension - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -/** type of pcm hook */ -typedef enum _snd_pcm_hook_type { - SND_PCM_HOOK_TYPE_HW_PARAMS = 0, - SND_PCM_HOOK_TYPE_HW_FREE, - SND_PCM_HOOK_TYPE_CLOSE, - SND_PCM_HOOK_TYPE_LAST = SND_PCM_HOOK_TYPE_CLOSE -} snd_pcm_hook_type_t; - -/** PCM hook container */ -typedef struct _snd_pcm_hook snd_pcm_hook_t; -/** PCM hook callback function */ -typedef int (*snd_pcm_hook_func_t)(snd_pcm_hook_t *hook); -snd_pcm_t *snd_pcm_hook_get_pcm(snd_pcm_hook_t *hook); -void *snd_pcm_hook_get_private(snd_pcm_hook_t *hook); -void snd_pcm_hook_set_private(snd_pcm_hook_t *hook, void *private_data); -int snd_pcm_hook_add(snd_pcm_hook_t **hookp, snd_pcm_t *pcm, - snd_pcm_hook_type_t type, - snd_pcm_hook_func_t func, void *private_data); -int snd_pcm_hook_remove(snd_pcm_hook_t *hook); - -/** \} */ - -/** - * \defgroup PCM_Scope Scope Plugin Extension - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -/** #SND_PCM_TYPE_METER scope functions */ -typedef struct _snd_pcm_scope_ops { - /** \brief Enable and prepare it using current params - * \param scope scope handle - */ - int (*enable)(snd_pcm_scope_t *scope); - /** \brief Disable - * \param scope scope handle - */ - void (*disable)(snd_pcm_scope_t *scope); - /** \brief PCM has been started - * \param scope scope handle - */ - void (*start)(snd_pcm_scope_t *scope); - /** \brief PCM has been stopped - * \param scope scope handle - */ - void (*stop)(snd_pcm_scope_t *scope); - /** \brief New frames are present - * \param scope scope handle - */ - void (*update)(snd_pcm_scope_t *scope); - /** \brief Reset status - * \param scope scope handle - */ - void (*reset)(snd_pcm_scope_t *scope); - /** \brief PCM is closing - * \param scope scope handle - */ - void (*close)(snd_pcm_scope_t *scope); -} snd_pcm_scope_ops_t; - -snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm); -unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm); -unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm); -snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm); -snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm); -int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope); -snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name); -int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr); -void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, - const snd_pcm_scope_ops_t *val); -void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val); -const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope); -void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope); -void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val); -int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name, - snd_pcm_scope_t **scopep); -int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope, - unsigned int channel); - -/** \} */ - -/** - * \defgroup PCM_Simple Simple setup functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -/** Simple PCM latency type */ -typedef enum _snd_spcm_latency { - /** standard latency - for standard playback or capture - (estimated latency in one direction 350ms) */ - SND_SPCM_LATENCY_STANDARD = 0, - /** medium latency - software phones etc. - (estimated latency in one direction maximally 25ms */ - SND_SPCM_LATENCY_MEDIUM, - /** realtime latency - realtime applications (effect processors etc.) - (estimated latency in one direction 5ms and better) */ - SND_SPCM_LATENCY_REALTIME -} snd_spcm_latency_t; - -/** Simple PCM xrun type */ -typedef enum _snd_spcm_xrun_type { - /** driver / library will ignore all xruns, the stream runs forever */ - SND_SPCM_XRUN_IGNORE = 0, - /** driver / library stops the stream when an xrun occurs */ - SND_SPCM_XRUN_STOP -} snd_spcm_xrun_type_t; - -/** Simple PCM duplex type */ -typedef enum _snd_spcm_duplex_type { - /** liberal duplex - the buffer and period sizes might not match */ - SND_SPCM_DUPLEX_LIBERAL = 0, - /** pedantic duplex - the buffer and period sizes MUST match */ - SND_SPCM_DUPLEX_PEDANTIC -} snd_spcm_duplex_type_t; - -int snd_spcm_init(snd_pcm_t *pcm, - unsigned int rate, - unsigned int channels, - snd_pcm_format_t format, - snd_pcm_subformat_t subformat, - snd_spcm_latency_t latency, - snd_pcm_access_t _access, - snd_spcm_xrun_type_t xrun_type); - -int snd_spcm_init_duplex(snd_pcm_t *playback_pcm, - snd_pcm_t *capture_pcm, - unsigned int rate, - unsigned int channels, - snd_pcm_format_t format, - snd_pcm_subformat_t subformat, - snd_spcm_latency_t latency, - snd_pcm_access_t _access, - snd_spcm_xrun_type_t xrun_type, - snd_spcm_duplex_type_t duplex_type); - -int snd_spcm_init_get_params(snd_pcm_t *pcm, - unsigned int *rate, - snd_pcm_uframes_t *buffer_size, - snd_pcm_uframes_t *period_size); - -/** \} */ - -/** - * \defgroup PCM_Deprecated Deprecated Functions - * \ingroup PCM - * See the \ref pcm page for more details. - * \{ - */ - -/* Deprecated functions, for compatibility */ -const char *snd_pcm_start_mode_name(snd_pcm_start_t mode) __attribute__((deprecated)); -const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode) __attribute__((deprecated)); -int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val) __attribute__((deprecated)); -snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params) __attribute__((deprecated)); -int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val) __attribute__((deprecated)); -snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params) __attribute__((deprecated)); -#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_SW_PARAMS_API) -int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val) __attribute__((deprecated)); -int snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val) __attribute__((deprecated)); -int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, unsigned int val) __attribute__((deprecated)); -int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params, unsigned int *val) __attribute__((deprecated)); -#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_SW_PARAMS_API */ -#if !defined(ALSA_LIBRARY_BUILD) && !defined(ALSA_PCM_OLD_HW_PARAMS_API) -int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) __attribute__((deprecated)); -#endif /* !ALSA_LIBRARY_BUILD && !ALSA_PCM_OLD_HW_PARAMS_API */ - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_PCM_H */ diff --git a/raylib/external/alsa/pcm_external.h b/raylib/external/alsa/pcm_external.h deleted file mode 100644 index 5750418..0000000 --- a/raylib/external/alsa/pcm_external.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * \file include/pcm_external.h - * \brief External PCM plugin SDK - * \author Takashi Iwai - * \date 2005 - * - * Extern PCM plugin SDK. - */ - -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#ifndef __ALSA_PCM_EXTERNAL_H -#define __ALSA_PCM_EXTERNAL_H - -#include "pcm.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Plugin_SDK External PCM plugin SDK - * \{ - */ - -/** - * Define the object entry for external PCM plugins - */ -#define SND_PCM_PLUGIN_ENTRY(name) _snd_pcm_##name##_open - -/** - * Define the symbols of the given plugin with versions - */ -#define SND_PCM_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_PCM_PLUGIN_ENTRY(name), SND_PCM_DLSYM_VERSION); - -/** - * Define the plugin - */ -#define SND_PCM_PLUGIN_DEFINE_FUNC(plugin) \ -int SND_PCM_PLUGIN_ENTRY(plugin) (snd_pcm_t **pcmp, const char *name,\ - snd_config_t *root, snd_config_t *conf, \ - snd_pcm_stream_t stream, int mode) - -#include "pcm_ioplug.h" -#include "pcm_extplug.h" - -int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, - int *cchannelsp, int *hwctlp); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_PCM_EXTERNAL_H */ diff --git a/raylib/external/alsa/pcm_extplug.h b/raylib/external/alsa/pcm_extplug.h deleted file mode 100644 index e3b71bc..0000000 --- a/raylib/external/alsa/pcm_extplug.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * \file include/pcm_extplug.h - * \brief External Filter-Plugin SDK - * \author Takashi Iwai - * \date 2005 - * - * External Filter-Plugin SDK - */ - -/* - * ALSA external PCM plugin SDK (draft version) - * - * Copyright (c) 2005 Takashi Iwai - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_PCM_EXTPLUG_H -#define __ALSA_PCM_EXTPLUG_H - -/** - * \defgroup PCM_ExtPlug External Filter plugin SDK - * \ingroup Plugin_SDK - * See the \ref pcm page for more details. - * \{ - */ - -/** hw constraints for extplug */ -enum { - SND_PCM_EXTPLUG_HW_FORMAT, /**< format */ - SND_PCM_EXTPLUG_HW_CHANNELS, /**< channels */ - SND_PCM_EXTPLUG_HW_PARAMS /**< max number of hw constraints */ -}; - -/** Handle of external filter plugin */ -typedef struct snd_pcm_extplug snd_pcm_extplug_t; -/** Callback table of extplug */ -typedef struct snd_pcm_extplug_callback snd_pcm_extplug_callback_t; -#ifdef DOC_HIDDEN -/* redefine typedefs for stupid doxygen */ -typedef snd_pcm_extplug snd_pcm_extplug_t; -typedef snd_pcm_extplug_callback snd_pcm_extplug_callback_t; -#endif - -/* - * Protocol version - */ -#define SND_PCM_EXTPLUG_VERSION_MAJOR 1 /**< Protocol major version */ -#define SND_PCM_EXTPLUG_VERSION_MINOR 0 /**< Protocol minor version */ -#define SND_PCM_EXTPLUG_VERSION_TINY 2 /**< Protocol tiny version */ -/** - * Filter-plugin protocol version - */ -#define SND_PCM_EXTPLUG_VERSION ((SND_PCM_EXTPLUG_VERSION_MAJOR<<16) |\ - (SND_PCM_EXTPLUG_VERSION_MINOR<<8) |\ - (SND_PCM_EXTPLUG_VERSION_TINY)) - -/** Handle of extplug */ -struct snd_pcm_extplug { - /** - * protocol version; #SND_PCM_EXTPLUG_VERSION must be filled here - * before calling #snd_pcm_extplug_create() - */ - unsigned int version; - /** - * name of this plugin; must be filled before calling #snd_pcm_extplug_create() - */ - const char *name; - /** - * callbacks of this plugin; must be filled before calling #snd_pcm_extplug_create() - */ - const snd_pcm_extplug_callback_t *callback; - /** - * private data, which can be used freely in the driver callbacks - */ - void *private_data; - /** - * PCM handle filled by #snd_pcm_extplug_create() - */ - snd_pcm_t *pcm; - /** - * stream direction; read-only status - */ - snd_pcm_stream_t stream; - /** - * format hw parameter; filled after hw_params is caled - */ - snd_pcm_format_t format; - /** - * subformat hw parameter; filled after hw_params is caled - */ - snd_pcm_subformat_t subformat; - /** - * channels hw parameter; filled after hw_params is caled - */ - unsigned int channels; - /** - * rate hw parameter; filled after hw_params is caled - */ - unsigned int rate; - /** - * slave_format hw parameter; filled after hw_params is caled - */ - snd_pcm_format_t slave_format; - /** - * slave_subformat hw parameter; filled after hw_params is caled - */ - snd_pcm_subformat_t slave_subformat; - /** - * slave_channels hw parameter; filled after hw_params is caled - */ - unsigned int slave_channels; -}; - -/** Callback table of extplug */ -struct snd_pcm_extplug_callback { - /** - * transfer between source and destination; this is a required callback - */ - snd_pcm_sframes_t (*transfer)(snd_pcm_extplug_t *ext, - const snd_pcm_channel_area_t *dst_areas, - snd_pcm_uframes_t dst_offset, - const snd_pcm_channel_area_t *src_areas, - snd_pcm_uframes_t src_offset, - snd_pcm_uframes_t size); - /** - * close the PCM; optional - */ - int (*close)(snd_pcm_extplug_t *ext); - /** - * hw_params; optional - */ - int (*hw_params)(snd_pcm_extplug_t *ext, snd_pcm_hw_params_t *params); - /** - * hw_free; optional - */ - int (*hw_free)(snd_pcm_extplug_t *ext); - /** - * dump; optional - */ - void (*dump)(snd_pcm_extplug_t *ext, snd_output_t *out); - /** - * init; optional initialization called at prepare or reset - */ - int (*init)(snd_pcm_extplug_t *ext); - /** - * query the channel maps; optional; since v1.0.2 - */ - snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_extplug_t *ext); - /** - * get the channel map; optional; since v1.0.2 - */ - snd_pcm_chmap_t *(*get_chmap)(snd_pcm_extplug_t *ext); - /** - * set the channel map; optional; since v1.0.2 - */ - int (*set_chmap)(snd_pcm_extplug_t *ext, const snd_pcm_chmap_t *map); -}; - - -int snd_pcm_extplug_create(snd_pcm_extplug_t *ext, const char *name, - snd_config_t *root, snd_config_t *slave_conf, - snd_pcm_stream_t stream, int mode); -int snd_pcm_extplug_delete(snd_pcm_extplug_t *ext); - -/* clear hw_parameter setting */ -void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *ext); - -/* hw_parameter setting */ -int snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); -int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); -int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); -int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); - -/** - * set the parameter constraint with a single value - */ -static __inline__ int snd_pcm_extplug_set_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) -{ - return snd_pcm_extplug_set_param_list(extplug, type, 1, &val); -} - -/** - * set the parameter constraint for slave PCM with a single value - */ -static __inline__ int snd_pcm_extplug_set_slave_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) -{ - return snd_pcm_extplug_set_slave_param_list(extplug, type, 1, &val); -} - -/** \} */ - -#endif /* __ALSA_PCM_EXTPLUG_H */ diff --git a/raylib/external/alsa/pcm_ioplug.h b/raylib/external/alsa/pcm_ioplug.h deleted file mode 100644 index 8c25e5e..0000000 --- a/raylib/external/alsa/pcm_ioplug.h +++ /dev/null @@ -1,234 +0,0 @@ -/** - * \file include/pcm_ioplug.h - * \brief External I/O-Plugin SDK - * \author Takashi Iwai - * \date 2005 - * - * External I/O-Plugin SDK - */ - -/* - * ALSA external PCM plugin SDK - * - * Copyright (c) 2005 Takashi Iwai - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_PCM_IOPLUG_H -#define __ALSA_PCM_IOPLUG_H - -/** - * \defgroup PCM_IOPlug External I/O plugin SDK - * \ingroup Plugin_SDK - * See the \ref pcm page for more details. - * \{ - */ - -/** hw constraints for ioplug */ -enum { - SND_PCM_IOPLUG_HW_ACCESS = 0, /**< access type */ - SND_PCM_IOPLUG_HW_FORMAT, /**< format */ - SND_PCM_IOPLUG_HW_CHANNELS, /**< channels */ - SND_PCM_IOPLUG_HW_RATE, /**< rate */ - SND_PCM_IOPLUG_HW_PERIOD_BYTES, /**< period bytes */ - SND_PCM_IOPLUG_HW_BUFFER_BYTES, /**< buffer bytes */ - SND_PCM_IOPLUG_HW_PERIODS, /**< number of periods */ - SND_PCM_IOPLUG_HW_PARAMS /**< max number of hw constraints */ -}; - -/** I/O plugin handle */ -typedef struct snd_pcm_ioplug snd_pcm_ioplug_t; -/** Callback table of ioplug */ -typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; -#ifdef DOC_HIDDEN -/* redefine typedefs for stupid doxygen */ -typedef snd_pcm_ioplug snd_pcm_ioplug_t; -typedef snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; -#endif - -/* - * bit flags for additional conditions - */ -#define SND_PCM_IOPLUG_FLAG_LISTED (1<<0) /**< list up this PCM */ -#define SND_PCM_IOPLUG_FLAG_MONOTONIC (1<<1) /**< monotonic timestamps */ - -/* - * Protocol version - */ -#define SND_PCM_IOPLUG_VERSION_MAJOR 1 /**< Protocol major version */ -#define SND_PCM_IOPLUG_VERSION_MINOR 0 /**< Protocol minor version */ -#define SND_PCM_IOPLUG_VERSION_TINY 2 /**< Protocol tiny version */ -/** - * IO-plugin protocol version - */ -#define SND_PCM_IOPLUG_VERSION ((SND_PCM_IOPLUG_VERSION_MAJOR<<16) |\ - (SND_PCM_IOPLUG_VERSION_MINOR<<8) |\ - (SND_PCM_IOPLUG_VERSION_TINY)) - -/** Handle of ioplug */ -struct snd_pcm_ioplug { - /** - * protocol version; #SND_PCM_IOPLUG_VERSION must be filled here - * before calling #snd_pcm_ioplug_create() - */ - unsigned int version; - /** - * name of this plugin; must be filled before calling #snd_pcm_ioplug_create() - */ - const char *name; - unsigned int flags; /**< SND_PCM_IOPLUG_FLAG_XXX */ - int poll_fd; /**< poll file descriptor */ - unsigned int poll_events; /**< poll events */ - unsigned int mmap_rw; /**< pseudo mmap mode */ - /** - * callbacks of this plugin; must be filled before calling #snd_pcm_ioplug_create() - */ - const snd_pcm_ioplug_callback_t *callback; - /** - * private data, which can be used freely in the driver callbacks - */ - void *private_data; - /** - * PCM handle filled by #snd_pcm_extplug_create() - */ - snd_pcm_t *pcm; - - snd_pcm_stream_t stream; /**< stream direcion; read-only */ - snd_pcm_state_t state; /**< current PCM state; read-only */ - volatile snd_pcm_uframes_t appl_ptr; /**< application pointer; read-only */ - volatile snd_pcm_uframes_t hw_ptr; /**< hw pointer; read-only */ - int nonblock; /**< non-block mode; read-only */ - - snd_pcm_access_t access; /**< access type; filled after hw_params is called */ - snd_pcm_format_t format; /**< PCM format; filled after hw_params is called */ - unsigned int channels; /**< number of channels; filled after hw_params is called */ - unsigned int rate; /**< rate; filled after hw_params is called */ - snd_pcm_uframes_t period_size; /**< period size; filled after hw_params is called */ - snd_pcm_uframes_t buffer_size; /**< buffer size; filled after hw_params is called */ -}; - -/** Callback table of ioplug */ -struct snd_pcm_ioplug_callback { - /** - * start the PCM; required, called inside mutex lock - */ - int (*start)(snd_pcm_ioplug_t *io); - /** - * stop the PCM; required, called inside mutex lock - */ - int (*stop)(snd_pcm_ioplug_t *io); - /** - * get the current DMA position; required, called inside mutex lock - */ - snd_pcm_sframes_t (*pointer)(snd_pcm_ioplug_t *io); - /** - * transfer the data; optional, called inside mutex lock - */ - snd_pcm_sframes_t (*transfer)(snd_pcm_ioplug_t *io, - const snd_pcm_channel_area_t *areas, - snd_pcm_uframes_t offset, - snd_pcm_uframes_t size); - /** - * close the PCM; optional - */ - int (*close)(snd_pcm_ioplug_t *io); - /** - * hw_params; optional - */ - int (*hw_params)(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params); - /** - * hw_free; optional - */ - int (*hw_free)(snd_pcm_ioplug_t *io); - /** - * sw_params; optional - */ - int (*sw_params)(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params); - /** - * prepare; optional - */ - int (*prepare)(snd_pcm_ioplug_t *io); - /** - * drain; optional - */ - int (*drain)(snd_pcm_ioplug_t *io); - /** - * toggle pause; optional, called inside mutex lock - */ - int (*pause)(snd_pcm_ioplug_t *io, int enable); - /** - * resume; optional - */ - int (*resume)(snd_pcm_ioplug_t *io); - /** - * poll descriptors count; optional - */ - int (*poll_descriptors_count)(snd_pcm_ioplug_t *io); - /** - * poll descriptors; optional - */ - int (*poll_descriptors)(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space); - /** - * mangle poll events; optional - */ - int (*poll_revents)(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int nfds, unsigned short *revents); - /** - * dump; optional - */ - void (*dump)(snd_pcm_ioplug_t *io, snd_output_t *out); - /** - * get the delay for the running PCM; optional; since v1.0.1 - */ - int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp); - /** - * query the channel maps; optional; since v1.0.2 - */ - snd_pcm_chmap_query_t **(*query_chmaps)(snd_pcm_ioplug_t *io); - /** - * get the channel map; optional; since v1.0.2 - */ - snd_pcm_chmap_t *(*get_chmap)(snd_pcm_ioplug_t *io); - /** - * set the channel map; optional; since v1.0.2 - */ - int (*set_chmap)(snd_pcm_ioplug_t *io, const snd_pcm_chmap_t *map); -}; - - -int snd_pcm_ioplug_create(snd_pcm_ioplug_t *io, const char *name, - snd_pcm_stream_t stream, int mode); -int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *io); - -/* update poll_fd and mmap_rw */ -int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug); - -/* get a mmap area (for mmap_rw only) */ -const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug); - -/* clear hw_parameter setting */ -void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *io); - -/* hw_parameter setting */ -int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *io, int type, unsigned int min, unsigned int max); -int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *io, int type, unsigned int num_list, const unsigned int *list); - -/* change PCM status */ -int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state); - -/** \} */ - -#endif /* __ALSA_PCM_IOPLUG_H */ diff --git a/raylib/external/alsa/pcm_old.h b/raylib/external/alsa/pcm_old.h deleted file mode 100644 index e6e050f..0000000 --- a/raylib/external/alsa/pcm_old.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Old ALSA 0.9.x API - */ - -#ifdef ALSA_PCM_OLD_HW_PARAMS_API - -asm(".symver snd_pcm_hw_params_get_access,snd_pcm_hw_params_get_access@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_access_first,snd_pcm_hw_params_set_access_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_access_last,snd_pcm_hw_params_set_access_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val); -int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val); -snd_pcm_access_t snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -snd_pcm_access_t snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); -void snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask); - -asm(".symver snd_pcm_hw_params_get_format,snd_pcm_hw_params_get_format@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_format_first,snd_pcm_hw_params_set_format_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_format_last,snd_pcm_hw_params_set_format_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); -int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); -snd_pcm_format_t snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -snd_pcm_format_t snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); -void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); - -asm(".symver snd_pcm_hw_params_get_subformat,snd_pcm_hw_params_get_subformat@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_subformat_first,snd_pcm_hw_params_set_subformat_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_subformat_last,snd_pcm_hw_params_set_subformat_last@ALSA_0.9"); - -int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val); -int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val); -snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); -void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask); - -asm(".symver snd_pcm_hw_params_get_channels,snd_pcm_hw_params_get_channels@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_channels_min,snd_pcm_hw_params_get_channels_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_channels_max,snd_pcm_hw_params_get_channels_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_channels_near,snd_pcm_hw_params_set_channels_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_channels_first,snd_pcm_hw_params_set_channels_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_channels_last,snd_pcm_hw_params_set_channels_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params); -unsigned int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params); -unsigned int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max); -unsigned int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -unsigned int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -unsigned int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -asm(".symver snd_pcm_hw_params_get_rate,snd_pcm_hw_params_get_rate@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_rate_min,snd_pcm_hw_params_get_rate_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_rate_max,snd_pcm_hw_params_get_rate_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_rate_near,snd_pcm_hw_params_set_rate_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_rate_first,snd_pcm_hw_params_set_rate_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_rate_last,snd_pcm_hw_params_set_rate_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -unsigned int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); -unsigned int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_set_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -int snd_pcm_hw_params_get_rate_resample(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); - -asm(".symver snd_pcm_hw_params_get_period_time,snd_pcm_hw_params_get_period_time@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_period_time_min,snd_pcm_hw_params_get_period_time_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_period_time_max,snd_pcm_hw_params_get_period_time_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_time_near,snd_pcm_hw_params_set_period_time_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_time_first,snd_pcm_hw_params_set_period_time_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_time_last,snd_pcm_hw_params_set_period_time_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -unsigned int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); -unsigned int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); - -asm(".symver snd_pcm_hw_params_get_period_size,snd_pcm_hw_params_get_period_size@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_period_size_min,snd_pcm_hw_params_get_period_size_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_period_size_max,snd_pcm_hw_params_get_period_size_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_size_near,snd_pcm_hw_params_set_period_size_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_size_first,snd_pcm_hw_params_set_period_size_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_period_size_last,snd_pcm_hw_params_set_period_size_last@ALSA_0.9"); - -snd_pcm_sframes_t snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, int *dir); -snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, int *dir); -snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); -int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir); -int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); -int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir); -snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int *dir); -snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -asm(".symver snd_pcm_hw_params_get_periods,snd_pcm_hw_params_get_periods@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_periods_min,snd_pcm_hw_params_get_periods_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_periods_max,snd_pcm_hw_params_get_periods_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_periods_near,snd_pcm_hw_params_set_periods_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_periods_first,snd_pcm_hw_params_set_periods_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_periods_last,snd_pcm_hw_params_set_periods_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -unsigned int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); -unsigned int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -asm(".symver snd_pcm_hw_params_get_buffer_time,snd_pcm_hw_params_get_buffer_time@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_buffer_time_min,snd_pcm_hw_params_get_buffer_time_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_buffer_time_max,snd_pcm_hw_params_get_buffer_time_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_time_near,snd_pcm_hw_params_set_buffer_time_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_time_first,snd_pcm_hw_params_set_buffer_time_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_time_last,snd_pcm_hw_params_set_buffer_time_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -unsigned int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); -unsigned int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); - -asm(".symver snd_pcm_hw_params_get_buffer_size,snd_pcm_hw_params_get_buffer_size@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_buffer_size_min,snd_pcm_hw_params_get_buffer_size_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_buffer_size_max,snd_pcm_hw_params_get_buffer_size_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_size_near,snd_pcm_hw_params_set_buffer_size_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_size_first,snd_pcm_hw_params_set_buffer_size_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_buffer_size_last,snd_pcm_hw_params_set_buffer_size_last@ALSA_0.9"); - -snd_pcm_sframes_t snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params); -snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params); -snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params); -int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); -int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max); -snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); - -asm(".symver snd_pcm_hw_params_get_tick_time,snd_pcm_hw_params_get_tick_time@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_tick_time_min,snd_pcm_hw_params_get_tick_time_min@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_get_tick_time_max,snd_pcm_hw_params_get_tick_time_max@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_tick_time_near,snd_pcm_hw_params_set_tick_time_near@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_tick_time_first,snd_pcm_hw_params_set_tick_time_first@ALSA_0.9"); -asm(".symver snd_pcm_hw_params_set_tick_time_last,snd_pcm_hw_params_set_tick_time_last@ALSA_0.9"); - -int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, int *dir); -int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir); -int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir); -unsigned int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir); -unsigned int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); -unsigned int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir); - -#endif /* ALSA_PCM_OLD_HW_PARAMS_API */ - - -#ifdef ALSA_PCM_OLD_SW_PARAMS_API - -asm(".symver snd_pcm_sw_params_get_tstamp_mode,snd_pcm_sw_params_get_tstamp_mode@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_sleep_min,snd_pcm_sw_params_get_sleep_min@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_avail_min,snd_pcm_sw_params_get_avail_min@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_xfer_align,snd_pcm_sw_params_get_xfer_align@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_start_threshold,snd_pcm_sw_params_get_start_threshold@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_stop_threshold,snd_pcm_sw_params_get_stop_threshold@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_silence_threshold,snd_pcm_sw_params_get_silence_threshold@ALSA_0.9"); -asm(".symver snd_pcm_sw_params_get_silence_size,snd_pcm_sw_params_get_silence_size@ALSA_0.9"); - -int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); -snd_pcm_tstamp_t snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, unsigned int val); -unsigned int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params); -int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -snd_pcm_uframes_t snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params); - -#endif /* ALSA_PCM_OLD_SW_PARAMS_API */ diff --git a/raylib/external/alsa/pcm_plugin.h b/raylib/external/alsa/pcm_plugin.h deleted file mode 100644 index eea1d82..0000000 --- a/raylib/external/alsa/pcm_plugin.h +++ /dev/null @@ -1,202 +0,0 @@ -/** - * \file include/pcm_plugin.h - * \brief Common PCM plugin code - * \author Abramo Bagnara - * \author Jaroslav Kysela - * \date 2000-2001 - * - * Application interface library for the ALSA driver. - * See the \ref pcm_plugins page for more details. - * - * \warning Using of contents of this header file might be dangerous - * in the sense of compatibility reasons. The contents might be - * freely changed in future. - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_PCM_PLUGIN_H - -/** - * \defgroup PCM_Plugins PCM Plugins - * \ingroup PCM - * See the \ref pcm_plugins page for more details. - * \{ - */ - -#define SND_PCM_PLUGIN_RATE_MIN 4000 /**< minimal rate for the rate plugin */ -#define SND_PCM_PLUGIN_RATE_MAX 192000 /**< maximal rate for the rate plugin */ - -/* ROUTE_FLOAT should be set to 0 for machines without FP unit - like iPAQ */ -#ifdef HAVE_SOFT_FLOAT -#define SND_PCM_PLUGIN_ROUTE_FLOAT 0 /**< use integers for route plugin */ -#else -#define SND_PCM_PLUGIN_ROUTE_FLOAT 1 /**< use floats for route plugin */ -#endif - -#define SND_PCM_PLUGIN_ROUTE_RESOLUTION 16 /**< integer resolution for route plugin */ - -#if SND_PCM_PLUGIN_ROUTE_FLOAT -/** route ttable entry type */ -typedef float snd_pcm_route_ttable_entry_t; -#define SND_PCM_PLUGIN_ROUTE_HALF 0.5 /**< half value */ -#define SND_PCM_PLUGIN_ROUTE_FULL 1.0 /**< full value */ -#else -/** route ttable entry type */ -typedef int snd_pcm_route_ttable_entry_t; -#define SND_PCM_PLUGIN_ROUTE_HALF (SND_PCM_PLUGIN_ROUTE_RESOLUTION / 2) /**< half value */ -#define SND_PCM_PLUGIN_ROUTE_FULL SND_PCM_PLUGIN_ROUTE_RESOLUTION /**< full value */ -#endif - -/* - * Hardware plugin - */ -int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, - int card, int device, int subdevice, - snd_pcm_stream_t stream, int mode, - int mmap_emulation, int sync_ptr_ioctl); -int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Copy plugin - */ -int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_t *slave, int close_slave); -int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Linear conversion plugin - */ -int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, snd_pcm_t *slave, - int close_slave); -int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Linear<->Float conversion plugin - */ -int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, snd_pcm_t *slave, - int close_slave); -int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Linear<->mu-Law conversion plugin - */ -int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, snd_pcm_t *slave, - int close_slave); -int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Linear<->a-Law conversion plugin - */ -int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, snd_pcm_t *slave, - int close_slave); -int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Linear<->Ima-ADPCM conversion plugin - */ -int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, snd_pcm_t *slave, - int close_slave); -int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Route plugin for linear formats - */ -int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, - unsigned int tt_csize, unsigned int tt_ssize, - unsigned int *tt_cused, unsigned int *tt_sused, - int schannels); -int snd_pcm_route_determine_ttable(snd_config_t *tt, - unsigned int *tt_csize, - unsigned int *tt_ssize); -int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, int schannels, - snd_pcm_route_ttable_entry_t *ttable, - unsigned int tt_ssize, - unsigned int tt_cused, unsigned int tt_sused, - snd_pcm_t *slave, int close_slave); -int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Rate plugin for linear formats - */ -int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_format_t sformat, unsigned int srate, - const snd_config_t *converter, - snd_pcm_t *slave, int close_slave); -int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Hooks plugin - */ -int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, - snd_pcm_t *slave, int close_slave); -int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * LADSPA plugin - */ -int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, - const char *ladspa_path, - unsigned int channels, - snd_config_t *ladspa_pplugins, - snd_config_t *ladspa_cplugins, - snd_pcm_t *slave, int close_slave); -int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - -/* - * Jack plugin - */ -int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *playback_conf, - snd_config_t *capture_conf, - snd_pcm_stream_t stream, int mode); -int _snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *root, snd_config_t *conf, - snd_pcm_stream_t stream, int mode); - - -/** \} */ - -#endif /* __ALSA_PCM_PLUGIN_H */ diff --git a/raylib/external/alsa/pcm_rate.h b/raylib/external/alsa/pcm_rate.h deleted file mode 100644 index da278ac..0000000 --- a/raylib/external/alsa/pcm_rate.h +++ /dev/null @@ -1,156 +0,0 @@ -/** - * \file include/pcm_rate.h - * \brief External Rate-Converter-Plugin SDK - * \author Takashi Iwai - * \date 2006 - * - * External Rate-Converter-Plugin SDK - */ - -/* - * ALSA external PCM rate-converter plugin SDK (draft version) - * - * Copyright (c) 2006 Takashi Iwai - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_PCM_RATE_H -#define __ALSA_PCM_RATE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Protocol version - */ -#define SND_PCM_RATE_PLUGIN_VERSION 0x010002 - -/** hw_params information for a single side */ -typedef struct snd_pcm_rate_side_info { - snd_pcm_format_t format; - unsigned int rate; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t period_size; -} snd_pcm_rate_side_info_t; - -/** hw_params information */ -typedef struct snd_pcm_rate_info { - struct snd_pcm_rate_side_info in; - struct snd_pcm_rate_side_info out; - unsigned int channels; -} snd_pcm_rate_info_t; - -/** Callback table of rate-converter */ -typedef struct snd_pcm_rate_ops { - /** - * close the converter; optional - */ - void (*close)(void *obj); - /** - * initialize the converter, called at hw_params - */ - int (*init)(void *obj, snd_pcm_rate_info_t *info); - /** - * free the converter; optional - */ - void (*free)(void *obj); - /** - * reset the converter, called at prepare; optional - */ - void (*reset)(void *obj); - /** - * adjust the pitch, called at sw_params; optional - */ - int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); - /** - * convert the data - */ - void (*convert)(void *obj, - const snd_pcm_channel_area_t *dst_areas, - snd_pcm_uframes_t dst_offset, unsigned int dst_frames, - const snd_pcm_channel_area_t *src_areas, - snd_pcm_uframes_t src_offset, unsigned int src_frames); - /** - * convert an s16 interleaved-data array; exclusive with convert - */ - void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, - const int16_t *src, unsigned int src_frames); - /** - * compute the frame size for input - */ - snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); - /** - * compute the frame size for output - */ - snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); - /** - * the protocol version the plugin supports; - * new field since version 0x010002 - */ - unsigned int version; - /** - * return the supported min / max sample rates; - * new ops since version 0x010002 - */ - int (*get_supported_rates)(void *obj, unsigned int *rate_min, - unsigned int *rate_max); - /** - * show some status messages for verbose mode; - * new ops since version 0x010002 - */ - void (*dump)(void *obj, snd_output_t *out); -} snd_pcm_rate_ops_t; - -/** open function type */ -typedef int (*snd_pcm_rate_open_func_t)(unsigned int version, void **objp, - snd_pcm_rate_ops_t *opsp); - -typedef int (*snd_pcm_rate_open_conf_func_t)(unsigned int version, void **objp, - snd_pcm_rate_ops_t *opsp, const snd_config_t *conf); - -/** - * Define the object entry for external PCM rate-converter plugins - */ -#define SND_PCM_RATE_PLUGIN_ENTRY(name) _snd_pcm_rate_##name##_open -#define SND_PCM_RATE_PLUGIN_CONF_ENTRY(name) _snd_pcm_rate_##name##_open_conf - -#ifndef DOC_HIDDEN -/* old rate_ops for protocol version 0x010001 */ -typedef struct snd_pcm_rate_old_ops { - void (*close)(void *obj); - int (*init)(void *obj, snd_pcm_rate_info_t *info); - void (*free)(void *obj); - void (*reset)(void *obj); - int (*adjust_pitch)(void *obj, snd_pcm_rate_info_t *info); - void (*convert)(void *obj, - const snd_pcm_channel_area_t *dst_areas, - snd_pcm_uframes_t dst_offset, unsigned int dst_frames, - const snd_pcm_channel_area_t *src_areas, - snd_pcm_uframes_t src_offset, unsigned int src_frames); - void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames, - const int16_t *src, unsigned int src_frames); - snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames); - snd_pcm_uframes_t (*output_frames)(void *obj, snd_pcm_uframes_t frames); -} snd_pcm_rate_old_ops_t; -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_PCM_RATE_H */ diff --git a/raylib/external/alsa/rawmidi.h b/raylib/external/alsa/rawmidi.h deleted file mode 100644 index 1d8fd56..0000000 --- a/raylib/external/alsa/rawmidi.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * \file include/rawmidi.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_RAWMIDI_H -#define __ALSA_RAWMIDI_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup RawMidi RawMidi Interface - * The RawMidi Interface. See \ref rawmidi page for more details. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_RAWMIDI_DLSYM_VERSION _dlsym_rawmidi_001 - -/** RawMidi information container */ -typedef struct _snd_rawmidi_info snd_rawmidi_info_t; -/** RawMidi settings container */ -typedef struct _snd_rawmidi_params snd_rawmidi_params_t; -/** RawMidi status container */ -typedef struct _snd_rawmidi_status snd_rawmidi_status_t; - -/** RawMidi stream (direction) */ -typedef enum _snd_rawmidi_stream { - /** Output stream */ - SND_RAWMIDI_STREAM_OUTPUT = 0, - /** Input stream */ - SND_RAWMIDI_STREAM_INPUT, - SND_RAWMIDI_STREAM_LAST = SND_RAWMIDI_STREAM_INPUT -} snd_rawmidi_stream_t; - -/** Append (flag to open mode) \hideinitializer */ -#define SND_RAWMIDI_APPEND 0x0001 -/** Non blocking mode (flag to open mode) \hideinitializer */ -#define SND_RAWMIDI_NONBLOCK 0x0002 -/** Write sync mode (Flag to open mode) \hideinitializer */ -#define SND_RAWMIDI_SYNC 0x0004 - -/** RawMidi handle */ -typedef struct _snd_rawmidi snd_rawmidi_t; - -/** RawMidi type */ -typedef enum _snd_rawmidi_type { - /** Kernel level RawMidi */ - SND_RAWMIDI_TYPE_HW, - /** Shared memory client RawMidi (not yet implemented) */ - SND_RAWMIDI_TYPE_SHM, - /** INET client RawMidi (not yet implemented) */ - SND_RAWMIDI_TYPE_INET, - /** Virtual (sequencer) RawMidi */ - SND_RAWMIDI_TYPE_VIRTUAL -} snd_rawmidi_type_t; - -int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, - const char *name, int mode); -int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, - const char *name, int mode, snd_config_t *lconf); -int snd_rawmidi_close(snd_rawmidi_t *rmidi); -int snd_rawmidi_poll_descriptors_count(snd_rawmidi_t *rmidi); -int snd_rawmidi_poll_descriptors(snd_rawmidi_t *rmidi, struct pollfd *pfds, unsigned int space); -int snd_rawmidi_poll_descriptors_revents(snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revent); -int snd_rawmidi_nonblock(snd_rawmidi_t *rmidi, int nonblock); -size_t snd_rawmidi_info_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_rawmidi_info_t using standard alloca - * \param ptr returned pointer - */ -#define snd_rawmidi_info_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_info) -int snd_rawmidi_info_malloc(snd_rawmidi_info_t **ptr); -void snd_rawmidi_info_free(snd_rawmidi_info_t *obj); -void snd_rawmidi_info_copy(snd_rawmidi_info_t *dst, const snd_rawmidi_info_t *src); -unsigned int snd_rawmidi_info_get_device(const snd_rawmidi_info_t *obj); -unsigned int snd_rawmidi_info_get_subdevice(const snd_rawmidi_info_t *obj); -snd_rawmidi_stream_t snd_rawmidi_info_get_stream(const snd_rawmidi_info_t *obj); -int snd_rawmidi_info_get_card(const snd_rawmidi_info_t *obj); -unsigned int snd_rawmidi_info_get_flags(const snd_rawmidi_info_t *obj); -const char *snd_rawmidi_info_get_id(const snd_rawmidi_info_t *obj); -const char *snd_rawmidi_info_get_name(const snd_rawmidi_info_t *obj); -const char *snd_rawmidi_info_get_subdevice_name(const snd_rawmidi_info_t *obj); -unsigned int snd_rawmidi_info_get_subdevices_count(const snd_rawmidi_info_t *obj); -unsigned int snd_rawmidi_info_get_subdevices_avail(const snd_rawmidi_info_t *obj); -void snd_rawmidi_info_set_device(snd_rawmidi_info_t *obj, unsigned int val); -void snd_rawmidi_info_set_subdevice(snd_rawmidi_info_t *obj, unsigned int val); -void snd_rawmidi_info_set_stream(snd_rawmidi_info_t *obj, snd_rawmidi_stream_t val); -int snd_rawmidi_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info); -size_t snd_rawmidi_params_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_rawmidi_params_t using standard alloca - * \param ptr returned pointer - */ -#define snd_rawmidi_params_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_params) -int snd_rawmidi_params_malloc(snd_rawmidi_params_t **ptr); -void snd_rawmidi_params_free(snd_rawmidi_params_t *obj); -void snd_rawmidi_params_copy(snd_rawmidi_params_t *dst, const snd_rawmidi_params_t *src); -int snd_rawmidi_params_set_buffer_size(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, size_t val); -size_t snd_rawmidi_params_get_buffer_size(const snd_rawmidi_params_t *params); -int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, size_t val); -size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params); -int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, int val); -int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params); -int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params); -int snd_rawmidi_params_current(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params); -size_t snd_rawmidi_status_sizeof(void); -/** \hideinitializer - * \brief allocate an invalid #snd_rawmidi_status_t using standard alloca - * \param ptr returned pointer - */ -#define snd_rawmidi_status_alloca(ptr) __snd_alloca(ptr, snd_rawmidi_status) -int snd_rawmidi_status_malloc(snd_rawmidi_status_t **ptr); -void snd_rawmidi_status_free(snd_rawmidi_status_t *obj); -void snd_rawmidi_status_copy(snd_rawmidi_status_t *dst, const snd_rawmidi_status_t *src); -void snd_rawmidi_status_get_tstamp(const snd_rawmidi_status_t *obj, snd_htimestamp_t *ptr); -size_t snd_rawmidi_status_get_avail(const snd_rawmidi_status_t *obj); -size_t snd_rawmidi_status_get_xruns(const snd_rawmidi_status_t *obj); -int snd_rawmidi_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status); -int snd_rawmidi_drain(snd_rawmidi_t *rmidi); -int snd_rawmidi_drop(snd_rawmidi_t *rmidi); -ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size); -ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size); -const char *snd_rawmidi_name(snd_rawmidi_t *rmidi); -snd_rawmidi_type_t snd_rawmidi_type(snd_rawmidi_t *rmidi); -snd_rawmidi_stream_t snd_rawmidi_stream(snd_rawmidi_t *rawmidi); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __RAWMIDI_H */ - diff --git a/raylib/external/alsa/seq.h b/raylib/external/alsa/seq.h deleted file mode 100644 index d05940e..0000000 --- a/raylib/external/alsa/seq.h +++ /dev/null @@ -1,739 +0,0 @@ -/** - * \file include/seq.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - */ -/* - * Application interface library for the ALSA driver - * - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_SEQ_H -#define __ALSA_SEQ_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Sequencer MIDI Sequencer - * MIDI Sequencer Interface. - * See \ref seq page for more details. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_SEQ_DLSYM_VERSION _dlsym_seq_001 - -/** Sequencer handle */ -typedef struct _snd_seq snd_seq_t; - -/** - * sequencer opening stream types - */ -#define SND_SEQ_OPEN_OUTPUT 1 /**< open for output (write) */ -#define SND_SEQ_OPEN_INPUT 2 /**< open for input (read) */ -#define SND_SEQ_OPEN_DUPLEX (SND_SEQ_OPEN_OUTPUT|SND_SEQ_OPEN_INPUT) /**< open for both input and output (read/write) */ - -/** - * sequencer opening mode - */ -#define SND_SEQ_NONBLOCK 0x0001 /**< non-blocking mode (flag to open mode) */ - -/** sequencer handle type */ -typedef enum _snd_seq_type { - SND_SEQ_TYPE_HW, /**< hardware */ - SND_SEQ_TYPE_SHM, /**< shared memory (NYI) */ - SND_SEQ_TYPE_INET /**< network (NYI) */ -} snd_seq_type_t; - -/** special client (port) ids */ -#define SND_SEQ_ADDRESS_UNKNOWN 253 /**< unknown source */ -#define SND_SEQ_ADDRESS_SUBSCRIBERS 254 /**< send event to all subscribed ports */ -#define SND_SEQ_ADDRESS_BROADCAST 255 /**< send event to all queues/clients/ports/channels */ - -/** known client numbers */ -#define SND_SEQ_CLIENT_SYSTEM 0 /**< system client */ - -/* - */ -int snd_seq_open(snd_seq_t **handle, const char *name, int streams, int mode); -int snd_seq_open_lconf(snd_seq_t **handle, const char *name, int streams, int mode, snd_config_t *lconf); -const char *snd_seq_name(snd_seq_t *seq); -snd_seq_type_t snd_seq_type(snd_seq_t *seq); -int snd_seq_close(snd_seq_t *handle); -int snd_seq_poll_descriptors_count(snd_seq_t *handle, short events); -int snd_seq_poll_descriptors(snd_seq_t *handle, struct pollfd *pfds, unsigned int space, short events); -int snd_seq_poll_descriptors_revents(snd_seq_t *seq, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_seq_nonblock(snd_seq_t *handle, int nonblock); -int snd_seq_client_id(snd_seq_t *handle); - -size_t snd_seq_get_output_buffer_size(snd_seq_t *handle); -size_t snd_seq_get_input_buffer_size(snd_seq_t *handle); -int snd_seq_set_output_buffer_size(snd_seq_t *handle, size_t size); -int snd_seq_set_input_buffer_size(snd_seq_t *handle, size_t size); - -/** system information container */ -typedef struct _snd_seq_system_info snd_seq_system_info_t; - -size_t snd_seq_system_info_sizeof(void); -/** allocate a #snd_seq_system_info_t container on stack */ -#define snd_seq_system_info_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_system_info) -int snd_seq_system_info_malloc(snd_seq_system_info_t **ptr); -void snd_seq_system_info_free(snd_seq_system_info_t *ptr); -void snd_seq_system_info_copy(snd_seq_system_info_t *dst, const snd_seq_system_info_t *src); - -int snd_seq_system_info_get_queues(const snd_seq_system_info_t *info); -int snd_seq_system_info_get_clients(const snd_seq_system_info_t *info); -int snd_seq_system_info_get_ports(const snd_seq_system_info_t *info); -int snd_seq_system_info_get_channels(const snd_seq_system_info_t *info); -int snd_seq_system_info_get_cur_clients(const snd_seq_system_info_t *info); -int snd_seq_system_info_get_cur_queues(const snd_seq_system_info_t *info); - -int snd_seq_system_info(snd_seq_t *handle, snd_seq_system_info_t *info); - -/** \} */ - - -/** - * \defgroup SeqClient Sequencer Client Interface - * Sequencer Client Interface - * \ingroup Sequencer - * \{ - */ - -/** client information container */ -typedef struct _snd_seq_client_info snd_seq_client_info_t; - -/** client types */ -typedef enum snd_seq_client_type { - SND_SEQ_USER_CLIENT = 1, /**< user client */ - SND_SEQ_KERNEL_CLIENT = 2 /**< kernel client */ -} snd_seq_client_type_t; - -size_t snd_seq_client_info_sizeof(void); -/** allocate a #snd_seq_client_info_t container on stack */ -#define snd_seq_client_info_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_client_info) -int snd_seq_client_info_malloc(snd_seq_client_info_t **ptr); -void snd_seq_client_info_free(snd_seq_client_info_t *ptr); -void snd_seq_client_info_copy(snd_seq_client_info_t *dst, const snd_seq_client_info_t *src); - -int snd_seq_client_info_get_client(const snd_seq_client_info_t *info); -snd_seq_client_type_t snd_seq_client_info_get_type(const snd_seq_client_info_t *info); -const char *snd_seq_client_info_get_name(snd_seq_client_info_t *info); -int snd_seq_client_info_get_broadcast_filter(const snd_seq_client_info_t *info); -int snd_seq_client_info_get_error_bounce(const snd_seq_client_info_t *info); -int snd_seq_client_info_get_card(const snd_seq_client_info_t *info); -int snd_seq_client_info_get_pid(const snd_seq_client_info_t *info); -const unsigned char *snd_seq_client_info_get_event_filter(const snd_seq_client_info_t *info); -int snd_seq_client_info_get_num_ports(const snd_seq_client_info_t *info); -int snd_seq_client_info_get_event_lost(const snd_seq_client_info_t *info); - -void snd_seq_client_info_set_client(snd_seq_client_info_t *info, int client); -void snd_seq_client_info_set_name(snd_seq_client_info_t *info, const char *name); -void snd_seq_client_info_set_broadcast_filter(snd_seq_client_info_t *info, int val); -void snd_seq_client_info_set_error_bounce(snd_seq_client_info_t *info, int val); -void snd_seq_client_info_set_event_filter(snd_seq_client_info_t *info, unsigned char *filter); - -void snd_seq_client_info_event_filter_clear(snd_seq_client_info_t *info); -void snd_seq_client_info_event_filter_add(snd_seq_client_info_t *info, int event_type); -void snd_seq_client_info_event_filter_del(snd_seq_client_info_t *info, int event_type); -int snd_seq_client_info_event_filter_check(snd_seq_client_info_t *info, int event_type); - -int snd_seq_get_client_info(snd_seq_t *handle, snd_seq_client_info_t *info); -int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_info_t *info); -int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t *info); -int snd_seq_query_next_client(snd_seq_t *handle, snd_seq_client_info_t *info); - -/* - */ - -/** client pool information container */ -typedef struct _snd_seq_client_pool snd_seq_client_pool_t; - -size_t snd_seq_client_pool_sizeof(void); -/** allocate a #snd_seq_client_pool_t container on stack */ -#define snd_seq_client_pool_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_client_pool) -int snd_seq_client_pool_malloc(snd_seq_client_pool_t **ptr); -void snd_seq_client_pool_free(snd_seq_client_pool_t *ptr); -void snd_seq_client_pool_copy(snd_seq_client_pool_t *dst, const snd_seq_client_pool_t *src); - -int snd_seq_client_pool_get_client(const snd_seq_client_pool_t *info); -size_t snd_seq_client_pool_get_output_pool(const snd_seq_client_pool_t *info); -size_t snd_seq_client_pool_get_input_pool(const snd_seq_client_pool_t *info); -size_t snd_seq_client_pool_get_output_room(const snd_seq_client_pool_t *info); -size_t snd_seq_client_pool_get_output_free(const snd_seq_client_pool_t *info); -size_t snd_seq_client_pool_get_input_free(const snd_seq_client_pool_t *info); -void snd_seq_client_pool_set_output_pool(snd_seq_client_pool_t *info, size_t size); -void snd_seq_client_pool_set_input_pool(snd_seq_client_pool_t *info, size_t size); -void snd_seq_client_pool_set_output_room(snd_seq_client_pool_t *info, size_t size); - -int snd_seq_get_client_pool(snd_seq_t *handle, snd_seq_client_pool_t *info); -int snd_seq_set_client_pool(snd_seq_t *handle, snd_seq_client_pool_t *info); - - -/** \} */ - - -/** - * \defgroup SeqPort Sequencer Port Interface - * Sequencer Port Interface - * \ingroup Sequencer - * \{ - */ - -/** port information container */ -typedef struct _snd_seq_port_info snd_seq_port_info_t; - -/** known port numbers */ -#define SND_SEQ_PORT_SYSTEM_TIMER 0 /**< system timer port */ -#define SND_SEQ_PORT_SYSTEM_ANNOUNCE 1 /**< system announce port */ - -/** port capabilities (32 bits) */ -#define SND_SEQ_PORT_CAP_READ (1<<0) /**< readable from this port */ -#define SND_SEQ_PORT_CAP_WRITE (1<<1) /**< writable to this port */ - -#define SND_SEQ_PORT_CAP_SYNC_READ (1<<2) /**< allow read subscriptions */ -#define SND_SEQ_PORT_CAP_SYNC_WRITE (1<<3) /**< allow write subscriptions */ - -#define SND_SEQ_PORT_CAP_DUPLEX (1<<4) /**< allow read/write duplex */ - -#define SND_SEQ_PORT_CAP_SUBS_READ (1<<5) /**< allow read subscription */ -#define SND_SEQ_PORT_CAP_SUBS_WRITE (1<<6) /**< allow write subscription */ -#define SND_SEQ_PORT_CAP_NO_EXPORT (1<<7) /**< routing not allowed */ - -/* port type */ -/** Messages sent from/to this port have device-specific semantics. */ -#define SND_SEQ_PORT_TYPE_SPECIFIC (1<<0) -/** This port understands MIDI messages. */ -#define SND_SEQ_PORT_TYPE_MIDI_GENERIC (1<<1) -/** This port is compatible with the General MIDI specification. */ -#define SND_SEQ_PORT_TYPE_MIDI_GM (1<<2) -/** This port is compatible with the Roland GS standard. */ -#define SND_SEQ_PORT_TYPE_MIDI_GS (1<<3) -/** This port is compatible with the Yamaha XG specification. */ -#define SND_SEQ_PORT_TYPE_MIDI_XG (1<<4) -/** This port is compatible with the Roland MT-32. */ -#define SND_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) -/** This port is compatible with the General MIDI 2 specification. */ -#define SND_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) -/** This port understands SND_SEQ_EVENT_SAMPLE_xxx messages - (these are not MIDI messages). */ -#define SND_SEQ_PORT_TYPE_SYNTH (1<<10) -/** Instruments can be downloaded to this port - (with SND_SEQ_EVENT_INSTR_xxx messages sent directly). */ -#define SND_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) -/** Instruments can be downloaded to this port - (with SND_SEQ_EVENT_INSTR_xxx messages sent directly or through a queue). */ -#define SND_SEQ_PORT_TYPE_SAMPLE (1<<12) -/** This port is implemented in hardware. */ -#define SND_SEQ_PORT_TYPE_HARDWARE (1<<16) -/** This port is implemented in software. */ -#define SND_SEQ_PORT_TYPE_SOFTWARE (1<<17) -/** Messages sent to this port will generate sounds. */ -#define SND_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) -/** This port may connect to other devices - (whose characteristics are not known). */ -#define SND_SEQ_PORT_TYPE_PORT (1<<19) -/** This port belongs to an application, such as a sequencer or editor. */ -#define SND_SEQ_PORT_TYPE_APPLICATION (1<<20) - - -size_t snd_seq_port_info_sizeof(void); -/** allocate a #snd_seq_port_info_t container on stack */ -#define snd_seq_port_info_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_port_info) -int snd_seq_port_info_malloc(snd_seq_port_info_t **ptr); -void snd_seq_port_info_free(snd_seq_port_info_t *ptr); -void snd_seq_port_info_copy(snd_seq_port_info_t *dst, const snd_seq_port_info_t *src); - -int snd_seq_port_info_get_client(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_port(const snd_seq_port_info_t *info); -const snd_seq_addr_t *snd_seq_port_info_get_addr(const snd_seq_port_info_t *info); -const char *snd_seq_port_info_get_name(const snd_seq_port_info_t *info); -unsigned int snd_seq_port_info_get_capability(const snd_seq_port_info_t *info); -unsigned int snd_seq_port_info_get_type(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_midi_channels(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_midi_voices(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_synth_voices(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_read_use(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_write_use(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_port_specified(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_timestamping(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_timestamp_real(const snd_seq_port_info_t *info); -int snd_seq_port_info_get_timestamp_queue(const snd_seq_port_info_t *info); - -void snd_seq_port_info_set_client(snd_seq_port_info_t *info, int client); -void snd_seq_port_info_set_port(snd_seq_port_info_t *info, int port); -void snd_seq_port_info_set_addr(snd_seq_port_info_t *info, const snd_seq_addr_t *addr); -void snd_seq_port_info_set_name(snd_seq_port_info_t *info, const char *name); -void snd_seq_port_info_set_capability(snd_seq_port_info_t *info, unsigned int capability); -void snd_seq_port_info_set_type(snd_seq_port_info_t *info, unsigned int type); -void snd_seq_port_info_set_midi_channels(snd_seq_port_info_t *info, int channels); -void snd_seq_port_info_set_midi_voices(snd_seq_port_info_t *info, int voices); -void snd_seq_port_info_set_synth_voices(snd_seq_port_info_t *info, int voices); -void snd_seq_port_info_set_port_specified(snd_seq_port_info_t *info, int val); -void snd_seq_port_info_set_timestamping(snd_seq_port_info_t *info, int enable); -void snd_seq_port_info_set_timestamp_real(snd_seq_port_info_t *info, int realtime); -void snd_seq_port_info_set_timestamp_queue(snd_seq_port_info_t *info, int queue); - -int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t *info); -int snd_seq_delete_port(snd_seq_t *handle, int port); -int snd_seq_get_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t *info); -int snd_seq_get_any_port_info(snd_seq_t *handle, int client, int port, snd_seq_port_info_t *info); -int snd_seq_set_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t *info); -int snd_seq_query_next_port(snd_seq_t *handle, snd_seq_port_info_t *info); - -/** \} */ - - -/** - * \defgroup SeqSubscribe Sequencer Port Subscription - * Sequencer Port Subscription - * \ingroup Sequencer - * \{ - */ - -/** port subscription container */ -typedef struct _snd_seq_port_subscribe snd_seq_port_subscribe_t; - -size_t snd_seq_port_subscribe_sizeof(void); -/** allocate a #snd_seq_port_subscribe_t container on stack */ -#define snd_seq_port_subscribe_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_port_subscribe) -int snd_seq_port_subscribe_malloc(snd_seq_port_subscribe_t **ptr); -void snd_seq_port_subscribe_free(snd_seq_port_subscribe_t *ptr); -void snd_seq_port_subscribe_copy(snd_seq_port_subscribe_t *dst, const snd_seq_port_subscribe_t *src); - -const snd_seq_addr_t *snd_seq_port_subscribe_get_sender(const snd_seq_port_subscribe_t *info); -const snd_seq_addr_t *snd_seq_port_subscribe_get_dest(const snd_seq_port_subscribe_t *info); -int snd_seq_port_subscribe_get_queue(const snd_seq_port_subscribe_t *info); -int snd_seq_port_subscribe_get_exclusive(const snd_seq_port_subscribe_t *info); -int snd_seq_port_subscribe_get_time_update(const snd_seq_port_subscribe_t *info); -int snd_seq_port_subscribe_get_time_real(const snd_seq_port_subscribe_t *info); - -void snd_seq_port_subscribe_set_sender(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr); -void snd_seq_port_subscribe_set_dest(snd_seq_port_subscribe_t *info, const snd_seq_addr_t *addr); -void snd_seq_port_subscribe_set_queue(snd_seq_port_subscribe_t *info, int q); -void snd_seq_port_subscribe_set_exclusive(snd_seq_port_subscribe_t *info, int val); -void snd_seq_port_subscribe_set_time_update(snd_seq_port_subscribe_t *info, int val); -void snd_seq_port_subscribe_set_time_real(snd_seq_port_subscribe_t *info, int val); - -int snd_seq_get_port_subscription(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); -int snd_seq_subscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); -int snd_seq_unsubscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t *sub); - -/* - */ - -/** subscription query container */ -typedef struct _snd_seq_query_subscribe snd_seq_query_subscribe_t; - -/** type of query subscription */ -typedef enum { - SND_SEQ_QUERY_SUBS_READ, /**< query read subscriptions */ - SND_SEQ_QUERY_SUBS_WRITE /**< query write subscriptions */ -} snd_seq_query_subs_type_t; - -size_t snd_seq_query_subscribe_sizeof(void); -/** allocate a #snd_seq_query_subscribe_t container on stack */ -#define snd_seq_query_subscribe_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_query_subscribe) -int snd_seq_query_subscribe_malloc(snd_seq_query_subscribe_t **ptr); -void snd_seq_query_subscribe_free(snd_seq_query_subscribe_t *ptr); -void snd_seq_query_subscribe_copy(snd_seq_query_subscribe_t *dst, const snd_seq_query_subscribe_t *src); - -int snd_seq_query_subscribe_get_client(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_port(const snd_seq_query_subscribe_t *info); -const snd_seq_addr_t *snd_seq_query_subscribe_get_root(const snd_seq_query_subscribe_t *info); -snd_seq_query_subs_type_t snd_seq_query_subscribe_get_type(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_index(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_num_subs(const snd_seq_query_subscribe_t *info); -const snd_seq_addr_t *snd_seq_query_subscribe_get_addr(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_queue(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_exclusive(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_time_update(const snd_seq_query_subscribe_t *info); -int snd_seq_query_subscribe_get_time_real(const snd_seq_query_subscribe_t *info); - -void snd_seq_query_subscribe_set_client(snd_seq_query_subscribe_t *info, int client); -void snd_seq_query_subscribe_set_port(snd_seq_query_subscribe_t *info, int port); -void snd_seq_query_subscribe_set_root(snd_seq_query_subscribe_t *info, const snd_seq_addr_t *addr); -void snd_seq_query_subscribe_set_type(snd_seq_query_subscribe_t *info, snd_seq_query_subs_type_t type); -void snd_seq_query_subscribe_set_index(snd_seq_query_subscribe_t *info, int _index); - -int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subscribe_t * subs); - -/** \} */ - - -/** - * \defgroup SeqQueue Sequencer Queue Interface - * Sequencer Queue Interface - * \ingroup Sequencer - * \{ - */ - -/** queue information container */ -typedef struct _snd_seq_queue_info snd_seq_queue_info_t; -/** queue status container */ -typedef struct _snd_seq_queue_status snd_seq_queue_status_t; -/** queue tempo container */ -typedef struct _snd_seq_queue_tempo snd_seq_queue_tempo_t; -/** queue timer information container */ -typedef struct _snd_seq_queue_timer snd_seq_queue_timer_t; - -/** special queue ids */ -#define SND_SEQ_QUEUE_DIRECT 253 /**< direct dispatch */ - -size_t snd_seq_queue_info_sizeof(void); -/** allocate a #snd_seq_queue_info_t container on stack */ -#define snd_seq_queue_info_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_queue_info) -int snd_seq_queue_info_malloc(snd_seq_queue_info_t **ptr); -void snd_seq_queue_info_free(snd_seq_queue_info_t *ptr); -void snd_seq_queue_info_copy(snd_seq_queue_info_t *dst, const snd_seq_queue_info_t *src); - -int snd_seq_queue_info_get_queue(const snd_seq_queue_info_t *info); -const char *snd_seq_queue_info_get_name(const snd_seq_queue_info_t *info); -int snd_seq_queue_info_get_owner(const snd_seq_queue_info_t *info); -int snd_seq_queue_info_get_locked(const snd_seq_queue_info_t *info); -unsigned int snd_seq_queue_info_get_flags(const snd_seq_queue_info_t *info); - -void snd_seq_queue_info_set_name(snd_seq_queue_info_t *info, const char *name); -void snd_seq_queue_info_set_owner(snd_seq_queue_info_t *info, int owner); -void snd_seq_queue_info_set_locked(snd_seq_queue_info_t *info, int locked); -void snd_seq_queue_info_set_flags(snd_seq_queue_info_t *info, unsigned int flags); - -int snd_seq_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info); -int snd_seq_alloc_named_queue(snd_seq_t *seq, const char *name); -int snd_seq_alloc_queue(snd_seq_t *handle); -int snd_seq_free_queue(snd_seq_t *handle, int q); -int snd_seq_get_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info); -int snd_seq_set_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info); -int snd_seq_query_named_queue(snd_seq_t *seq, const char *name); - -int snd_seq_get_queue_usage(snd_seq_t *handle, int q); -int snd_seq_set_queue_usage(snd_seq_t *handle, int q, int used); - -/* - */ -size_t snd_seq_queue_status_sizeof(void); -/** allocate a #snd_seq_queue_status_t container on stack */ -#define snd_seq_queue_status_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_queue_status) -int snd_seq_queue_status_malloc(snd_seq_queue_status_t **ptr); -void snd_seq_queue_status_free(snd_seq_queue_status_t *ptr); -void snd_seq_queue_status_copy(snd_seq_queue_status_t *dst, const snd_seq_queue_status_t *src); - -int snd_seq_queue_status_get_queue(const snd_seq_queue_status_t *info); -int snd_seq_queue_status_get_events(const snd_seq_queue_status_t *info); -snd_seq_tick_time_t snd_seq_queue_status_get_tick_time(const snd_seq_queue_status_t *info); -const snd_seq_real_time_t *snd_seq_queue_status_get_real_time(const snd_seq_queue_status_t *info); -unsigned int snd_seq_queue_status_get_status(const snd_seq_queue_status_t *info); - -int snd_seq_get_queue_status(snd_seq_t *handle, int q, snd_seq_queue_status_t *status); - -/* - */ -size_t snd_seq_queue_tempo_sizeof(void); -/** allocate a #snd_seq_queue_tempo_t container on stack */ -#define snd_seq_queue_tempo_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_queue_tempo) -int snd_seq_queue_tempo_malloc(snd_seq_queue_tempo_t **ptr); -void snd_seq_queue_tempo_free(snd_seq_queue_tempo_t *ptr); -void snd_seq_queue_tempo_copy(snd_seq_queue_tempo_t *dst, const snd_seq_queue_tempo_t *src); - -int snd_seq_queue_tempo_get_queue(const snd_seq_queue_tempo_t *info); -unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info); -int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info); -unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info); -unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info); -void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo); -void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq); -void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew); -void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base); - -int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo); -int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo); - -/* - */ - -/** sequencer timer sources */ -typedef enum { - SND_SEQ_TIMER_ALSA = 0, /* ALSA timer */ - SND_SEQ_TIMER_MIDI_CLOCK = 1, /* Midi Clock (CLOCK event) */ - SND_SEQ_TIMER_MIDI_TICK = 2 /* Midi Timer Tick (TICK event */ -} snd_seq_queue_timer_type_t; - -size_t snd_seq_queue_timer_sizeof(void); -/** allocate a #snd_seq_queue_timer_t container on stack */ -#define snd_seq_queue_timer_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_queue_timer) -int snd_seq_queue_timer_malloc(snd_seq_queue_timer_t **ptr); -void snd_seq_queue_timer_free(snd_seq_queue_timer_t *ptr); -void snd_seq_queue_timer_copy(snd_seq_queue_timer_t *dst, const snd_seq_queue_timer_t *src); - -int snd_seq_queue_timer_get_queue(const snd_seq_queue_timer_t *info); -snd_seq_queue_timer_type_t snd_seq_queue_timer_get_type(const snd_seq_queue_timer_t *info); -const snd_timer_id_t *snd_seq_queue_timer_get_id(const snd_seq_queue_timer_t *info); -unsigned int snd_seq_queue_timer_get_resolution(const snd_seq_queue_timer_t *info); - -void snd_seq_queue_timer_set_type(snd_seq_queue_timer_t *info, snd_seq_queue_timer_type_t type); -void snd_seq_queue_timer_set_id(snd_seq_queue_timer_t *info, const snd_timer_id_t *id); -void snd_seq_queue_timer_set_resolution(snd_seq_queue_timer_t *info, unsigned int resolution); - -int snd_seq_get_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t *timer); -int snd_seq_set_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t *timer); - -/** \} */ - -/** - * \defgroup SeqEvent Sequencer Event API - * Sequencer Event API - * \ingroup Sequencer - * \{ - */ - -int snd_seq_free_event(snd_seq_event_t *ev); -ssize_t snd_seq_event_length(snd_seq_event_t *ev); -int snd_seq_event_output(snd_seq_t *handle, snd_seq_event_t *ev); -int snd_seq_event_output_buffer(snd_seq_t *handle, snd_seq_event_t *ev); -int snd_seq_event_output_direct(snd_seq_t *handle, snd_seq_event_t *ev); -int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev); -int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer); -int snd_seq_drain_output(snd_seq_t *handle); -int snd_seq_event_output_pending(snd_seq_t *seq); -int snd_seq_extract_output(snd_seq_t *handle, snd_seq_event_t **ev); -int snd_seq_drop_output(snd_seq_t *handle); -int snd_seq_drop_output_buffer(snd_seq_t *handle); -int snd_seq_drop_input(snd_seq_t *handle); -int snd_seq_drop_input_buffer(snd_seq_t *handle); - -/** event removal conditionals */ -typedef struct _snd_seq_remove_events snd_seq_remove_events_t; - -/** Remove conditional flags */ -#define SND_SEQ_REMOVE_INPUT (1<<0) /**< Flush input queues */ -#define SND_SEQ_REMOVE_OUTPUT (1<<1) /**< Flush output queues */ -#define SND_SEQ_REMOVE_DEST (1<<2) /**< Restrict by destination q:client:port */ -#define SND_SEQ_REMOVE_DEST_CHANNEL (1<<3) /**< Restrict by channel */ -#define SND_SEQ_REMOVE_TIME_BEFORE (1<<4) /**< Restrict to before time */ -#define SND_SEQ_REMOVE_TIME_AFTER (1<<5) /**< Restrict to time or after */ -#define SND_SEQ_REMOVE_TIME_TICK (1<<6) /**< Time is in ticks */ -#define SND_SEQ_REMOVE_EVENT_TYPE (1<<7) /**< Restrict to event type */ -#define SND_SEQ_REMOVE_IGNORE_OFF (1<<8) /**< Do not flush off events */ -#define SND_SEQ_REMOVE_TAG_MATCH (1<<9) /**< Restrict to events with given tag */ - -size_t snd_seq_remove_events_sizeof(void); -/** allocate a #snd_seq_remove_events_t container on stack */ -#define snd_seq_remove_events_alloca(ptr) \ - __snd_alloca(ptr, snd_seq_remove_events) -int snd_seq_remove_events_malloc(snd_seq_remove_events_t **ptr); -void snd_seq_remove_events_free(snd_seq_remove_events_t *ptr); -void snd_seq_remove_events_copy(snd_seq_remove_events_t *dst, const snd_seq_remove_events_t *src); - -unsigned int snd_seq_remove_events_get_condition(const snd_seq_remove_events_t *info); -int snd_seq_remove_events_get_queue(const snd_seq_remove_events_t *info); -const snd_seq_timestamp_t *snd_seq_remove_events_get_time(const snd_seq_remove_events_t *info); -const snd_seq_addr_t *snd_seq_remove_events_get_dest(const snd_seq_remove_events_t *info); -int snd_seq_remove_events_get_channel(const snd_seq_remove_events_t *info); -int snd_seq_remove_events_get_event_type(const snd_seq_remove_events_t *info); -int snd_seq_remove_events_get_tag(const snd_seq_remove_events_t *info); - -void snd_seq_remove_events_set_condition(snd_seq_remove_events_t *info, unsigned int flags); -void snd_seq_remove_events_set_queue(snd_seq_remove_events_t *info, int queue); -void snd_seq_remove_events_set_time(snd_seq_remove_events_t *info, const snd_seq_timestamp_t *time); -void snd_seq_remove_events_set_dest(snd_seq_remove_events_t *info, const snd_seq_addr_t *addr); -void snd_seq_remove_events_set_channel(snd_seq_remove_events_t *info, int channel); -void snd_seq_remove_events_set_event_type(snd_seq_remove_events_t *info, int type); -void snd_seq_remove_events_set_tag(snd_seq_remove_events_t *info, int tag); - -int snd_seq_remove_events(snd_seq_t *handle, snd_seq_remove_events_t *info); - -/** \} */ - -/** - * \defgroup SeqMisc Sequencer Miscellaneous - * Sequencer Miscellaneous - * \ingroup Sequencer - * \{ - */ - -void snd_seq_set_bit(int nr, void *array); -void snd_seq_unset_bit(int nr, void *array); -int snd_seq_change_bit(int nr, void *array); -int snd_seq_get_bit(int nr, void *array); - -/** \} */ - - -/** - * \defgroup SeqEvType Sequencer Event Type Checks - * Sequencer Event Type Checks - * \ingroup Sequencer - * \{ - */ - -/* event type macros */ -enum { - SND_SEQ_EVFLG_RESULT, - SND_SEQ_EVFLG_NOTE, - SND_SEQ_EVFLG_CONTROL, - SND_SEQ_EVFLG_QUEUE, - SND_SEQ_EVFLG_SYSTEM, - SND_SEQ_EVFLG_MESSAGE, - SND_SEQ_EVFLG_CONNECTION, - SND_SEQ_EVFLG_SAMPLE, - SND_SEQ_EVFLG_USERS, - SND_SEQ_EVFLG_INSTR, - SND_SEQ_EVFLG_QUOTE, - SND_SEQ_EVFLG_NONE, - SND_SEQ_EVFLG_RAW, - SND_SEQ_EVFLG_FIXED, - SND_SEQ_EVFLG_VARIABLE, - SND_SEQ_EVFLG_VARUSR -}; - -enum { - SND_SEQ_EVFLG_NOTE_ONEARG, - SND_SEQ_EVFLG_NOTE_TWOARG -}; - -enum { - SND_SEQ_EVFLG_QUEUE_NOARG, - SND_SEQ_EVFLG_QUEUE_TICK, - SND_SEQ_EVFLG_QUEUE_TIME, - SND_SEQ_EVFLG_QUEUE_VALUE -}; - -/** - * Exported event type table - * - * This table is referred by snd_seq_ev_is_xxx. - */ -extern const unsigned int snd_seq_event_types[]; - -#define _SND_SEQ_TYPE(x) (1<<(x)) /**< master type - 24bit */ -#define _SND_SEQ_TYPE_OPT(x) ((x)<<24) /**< optional type - 8bit */ - -/** check the event type */ -#define snd_seq_type_check(ev,x) (snd_seq_event_types[(ev)->type] & _SND_SEQ_TYPE(x)) - -/** event type check: result events */ -#define snd_seq_ev_is_result_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_RESULT) -/** event type check: note events */ -#define snd_seq_ev_is_note_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_NOTE) -/** event type check: control events */ -#define snd_seq_ev_is_control_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_CONTROL) -/** event type check: channel specific events */ -#define snd_seq_ev_is_channel_type(ev) \ - (snd_seq_event_types[(ev)->type] & (_SND_SEQ_TYPE(SND_SEQ_EVFLG_NOTE) | _SND_SEQ_TYPE(SND_SEQ_EVFLG_CONTROL))) - -/** event type check: queue control events */ -#define snd_seq_ev_is_queue_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_QUEUE) -/** event type check: system status messages */ -#define snd_seq_ev_is_message_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_MESSAGE) -/** event type check: system status messages */ -#define snd_seq_ev_is_subscribe_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_CONNECTION) -/** event type check: sample messages */ -#define snd_seq_ev_is_sample_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_SAMPLE) -/** event type check: user-defined messages */ -#define snd_seq_ev_is_user_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_USERS) -/** event type check: instrument layer events */ -#define snd_seq_ev_is_instr_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_INSTR) -/** event type check: fixed length events */ -#define snd_seq_ev_is_fixed_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_FIXED) -/** event type check: variable length events */ -#define snd_seq_ev_is_variable_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_VARIABLE) -/** event type check: user pointer events */ -#define snd_seq_ev_is_varusr_type(ev) \ - snd_seq_type_check(ev, SND_SEQ_EVFLG_VARUSR) -/** event type check: reserved for kernel */ -#define snd_seq_ev_is_reserved(ev) \ - (! snd_seq_event_types[(ev)->type]) - -/** - * macros to check event flags - */ -/** prior events */ -#define snd_seq_ev_is_prior(ev) \ - (((ev)->flags & SND_SEQ_PRIORITY_MASK) == SND_SEQ_PRIORITY_HIGH) - -/** get the data length type */ -#define snd_seq_ev_length_type(ev) \ - ((ev)->flags & SND_SEQ_EVENT_LENGTH_MASK) -/** fixed length events */ -#define snd_seq_ev_is_fixed(ev) \ - (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_FIXED) -/** variable length events */ -#define snd_seq_ev_is_variable(ev) \ - (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_VARIABLE) -/** variable length on user-space */ -#define snd_seq_ev_is_varusr(ev) \ - (snd_seq_ev_length_type(ev) == SND_SEQ_EVENT_LENGTH_VARUSR) - -/** time-stamp type */ -#define snd_seq_ev_timestamp_type(ev) \ - ((ev)->flags & SND_SEQ_TIME_STAMP_MASK) -/** event is in tick time */ -#define snd_seq_ev_is_tick(ev) \ - (snd_seq_ev_timestamp_type(ev) == SND_SEQ_TIME_STAMP_TICK) -/** event is in real-time */ -#define snd_seq_ev_is_real(ev) \ - (snd_seq_ev_timestamp_type(ev) == SND_SEQ_TIME_STAMP_REAL) - -/** time-mode type */ -#define snd_seq_ev_timemode_type(ev) \ - ((ev)->flags & SND_SEQ_TIME_MODE_MASK) -/** scheduled in absolute time */ -#define snd_seq_ev_is_abstime(ev) \ - (snd_seq_ev_timemode_type(ev) == SND_SEQ_TIME_MODE_ABS) -/** scheduled in relative time */ -#define snd_seq_ev_is_reltime(ev) \ - (snd_seq_ev_timemode_type(ev) == SND_SEQ_TIME_MODE_REL) - -/** direct dispatched events */ -#define snd_seq_ev_is_direct(ev) \ - ((ev)->queue == SND_SEQ_QUEUE_DIRECT) - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_SEQ_H */ - diff --git a/raylib/external/alsa/seq_event.h b/raylib/external/alsa/seq_event.h deleted file mode 100644 index 6bd0de3..0000000 --- a/raylib/external/alsa/seq_event.h +++ /dev/null @@ -1,325 +0,0 @@ -/** - * \file include/seq_event.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_SEQ_EVENT_H -#define __ALSA_SEQ_EVENT_H - -/** - * \defgroup SeqEvents Sequencer Event Definitions - * Sequencer Event Definitions - * \ingroup Sequencer - * \{ - */ - -/** - * Sequencer event data type - */ -typedef unsigned char snd_seq_event_type_t; - -/** Sequencer event type */ -enum snd_seq_event_type { - /** system status; event data type = #snd_seq_result_t */ - SND_SEQ_EVENT_SYSTEM = 0, - /** returned result status; event data type = #snd_seq_result_t */ - SND_SEQ_EVENT_RESULT, - - /** note on and off with duration; event data type = #snd_seq_ev_note_t */ - SND_SEQ_EVENT_NOTE = 5, - /** note on; event data type = #snd_seq_ev_note_t */ - SND_SEQ_EVENT_NOTEON, - /** note off; event data type = #snd_seq_ev_note_t */ - SND_SEQ_EVENT_NOTEOFF, - /** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */ - SND_SEQ_EVENT_KEYPRESS, - - /** controller; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_CONTROLLER = 10, - /** program change; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_PGMCHANGE, - /** channel pressure; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_CHANPRESS, - /** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */ - SND_SEQ_EVENT_PITCHBEND, - /** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_CONTROL14, - /** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_NONREGPARAM, - /** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_REGPARAM, - - /** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_SONGPOS = 20, - /** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_SONGSEL, - /** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_QFRAME, - /** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_TIMESIGN, - /** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */ - SND_SEQ_EVENT_KEYSIGN, - - /** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_START = 30, - /** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_CONTINUE, - /** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_STOP, - /** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_SETPOS_TICK, - /** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_SETPOS_TIME, - /** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_TEMPO, - /** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_CLOCK, - /** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_TICK, - /** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_QUEUE_SKEW, - /** Sync position changed; event data type = #snd_seq_ev_queue_control_t */ - SND_SEQ_EVENT_SYNC_POS, - - /** Tune request; event data type = none */ - SND_SEQ_EVENT_TUNE_REQUEST = 40, - /** Reset to power-on state; event data type = none */ - SND_SEQ_EVENT_RESET, - /** Active sensing event; event data type = none */ - SND_SEQ_EVENT_SENSING, - - /** Echo-back event; event data type = any type */ - SND_SEQ_EVENT_ECHO = 50, - /** OSS emulation raw event; event data type = any type */ - SND_SEQ_EVENT_OSS, - - /** New client has connected; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_CLIENT_START = 60, - /** Client has left the system; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_CLIENT_EXIT, - /** Client status/info has changed; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_CLIENT_CHANGE, - /** New port was created; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_PORT_START, - /** Port was deleted from system; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_PORT_EXIT, - /** Port status/info has changed; event data type = #snd_seq_addr_t */ - SND_SEQ_EVENT_PORT_CHANGE, - - /** Ports connected; event data type = #snd_seq_connect_t */ - SND_SEQ_EVENT_PORT_SUBSCRIBED, - /** Ports disconnected; event data type = #snd_seq_connect_t */ - SND_SEQ_EVENT_PORT_UNSUBSCRIBED, - - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR0 = 90, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR1, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR2, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR3, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR4, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR5, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR6, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR7, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR8, - /** user-defined event; event data type = any (fixed size) */ - SND_SEQ_EVENT_USR9, - - /** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_SYSEX = 130, - /** error event; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_BOUNCE, - /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_USR_VAR0 = 135, - /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_USR_VAR1, - /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_USR_VAR2, - /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_USR_VAR3, - /** reserved for user apps; event data type = #snd_seq_ev_ext_t */ - SND_SEQ_EVENT_USR_VAR4, - - /** NOP; ignored in any case */ - SND_SEQ_EVENT_NONE = 255 -}; - - -/** Sequencer event address */ -typedef struct snd_seq_addr { - unsigned char client; /**< Client id */ - unsigned char port; /**< Port id */ -} snd_seq_addr_t; - -/** Connection (subscription) between ports */ -typedef struct snd_seq_connect { - snd_seq_addr_t sender; /**< sender address */ - snd_seq_addr_t dest; /**< destination address */ -} snd_seq_connect_t; - - -/** Real-time data record */ -typedef struct snd_seq_real_time { - unsigned int tv_sec; /**< seconds */ - unsigned int tv_nsec; /**< nanoseconds */ -} snd_seq_real_time_t; - -/** (MIDI) Tick-time data record */ -typedef unsigned int snd_seq_tick_time_t; - -/** unioned time stamp */ -typedef union snd_seq_timestamp { - snd_seq_tick_time_t tick; /**< tick-time */ - struct snd_seq_real_time time; /**< real-time */ -} snd_seq_timestamp_t; - - -/** - * Event mode flags - * - * NOTE: only 8 bits available! - */ -#define SND_SEQ_TIME_STAMP_TICK (0<<0) /**< timestamp in clock ticks */ -#define SND_SEQ_TIME_STAMP_REAL (1<<0) /**< timestamp in real time */ -#define SND_SEQ_TIME_STAMP_MASK (1<<0) /**< mask for timestamp bits */ - -#define SND_SEQ_TIME_MODE_ABS (0<<1) /**< absolute timestamp */ -#define SND_SEQ_TIME_MODE_REL (1<<1) /**< relative to current time */ -#define SND_SEQ_TIME_MODE_MASK (1<<1) /**< mask for time mode bits */ - -#define SND_SEQ_EVENT_LENGTH_FIXED (0<<2) /**< fixed event size */ -#define SND_SEQ_EVENT_LENGTH_VARIABLE (1<<2) /**< variable event size */ -#define SND_SEQ_EVENT_LENGTH_VARUSR (2<<2) /**< variable event size - user memory space */ -#define SND_SEQ_EVENT_LENGTH_MASK (3<<2) /**< mask for event length bits */ - -#define SND_SEQ_PRIORITY_NORMAL (0<<4) /**< normal priority */ -#define SND_SEQ_PRIORITY_HIGH (1<<4) /**< event should be processed before others */ -#define SND_SEQ_PRIORITY_MASK (1<<4) /**< mask for priority bits */ - - -/** Note event */ -typedef struct snd_seq_ev_note { - unsigned char channel; /**< channel number */ - unsigned char note; /**< note */ - unsigned char velocity; /**< velocity */ - unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */ - unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */ -} snd_seq_ev_note_t; - -/** Controller event */ -typedef struct snd_seq_ev_ctrl { - unsigned char channel; /**< channel number */ - unsigned char unused[3]; /**< reserved */ - unsigned int param; /**< control parameter */ - signed int value; /**< control value */ -} snd_seq_ev_ctrl_t; - -/** generic set of bytes (12x8 bit) */ -typedef struct snd_seq_ev_raw8 { - unsigned char d[12]; /**< 8 bit value */ -} snd_seq_ev_raw8_t; - -/** generic set of integers (3x32 bit) */ -typedef struct snd_seq_ev_raw32 { - unsigned int d[3]; /**< 32 bit value */ -} snd_seq_ev_raw32_t; - -/** external stored data */ -struct snd_seq_ev_ext { - unsigned int len; /**< length of data */ - void *ptr; /**< pointer to data (note: can be 64-bit) */ -} __attribute__((packed)); -/** external stored data */ -typedef struct snd_seq_ev_ext snd_seq_ev_ext_t; -#ifdef DOC_HIDDEN -/* redefine typedef for stupid doxygen */ -typedef snd_seq_ev_ext snd_seq_ev_ext_t; -#endif - -/** Result events */ -typedef struct snd_seq_result { - int event; /**< processed event type */ - int result; /**< status */ -} snd_seq_result_t; - -/** Queue skew values */ -typedef struct snd_seq_queue_skew { - unsigned int value; /**< skew value */ - unsigned int base; /**< skew base */ -} snd_seq_queue_skew_t; - -/** queue timer control */ -typedef struct snd_seq_ev_queue_control { - unsigned char queue; /**< affected queue */ - unsigned char unused[3]; /**< reserved */ - union { - signed int value; /**< affected value (e.g. tempo) */ - snd_seq_timestamp_t time; /**< time */ - unsigned int position; /**< sync position */ - snd_seq_queue_skew_t skew; /**< queue skew */ - unsigned int d32[2]; /**< any data */ - unsigned char d8[8]; /**< any data */ - } param; /**< data value union */ -} snd_seq_ev_queue_control_t; - - -/** Sequencer event */ -typedef struct snd_seq_event { - snd_seq_event_type_t type; /**< event type */ - unsigned char flags; /**< event flags */ - unsigned char tag; /**< tag */ - - unsigned char queue; /**< schedule queue */ - snd_seq_timestamp_t time; /**< schedule time */ - - snd_seq_addr_t source; /**< source address */ - snd_seq_addr_t dest; /**< destination address */ - - union { - snd_seq_ev_note_t note; /**< note information */ - snd_seq_ev_ctrl_t control; /**< MIDI control information */ - snd_seq_ev_raw8_t raw8; /**< raw8 data */ - snd_seq_ev_raw32_t raw32; /**< raw32 data */ - snd_seq_ev_ext_t ext; /**< external data */ - snd_seq_ev_queue_control_t queue; /**< queue control */ - snd_seq_timestamp_t time; /**< timestamp */ - snd_seq_addr_t addr; /**< address */ - snd_seq_connect_t connect; /**< connect information */ - snd_seq_result_t result; /**< operation result code */ - } data; /**< event data... */ -} snd_seq_event_t; - - -/** \} */ - -#endif /* __ALSA_SEQ_EVENT_H */ - diff --git a/raylib/external/alsa/seq_midi_event.h b/raylib/external/alsa/seq_midi_event.h deleted file mode 100644 index 9b8ee59..0000000 --- a/raylib/external/alsa/seq_midi_event.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * \file include/seq_midi_event.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_SEQ_MIDI_EVENT_H -#define __ALSA_SEQ_MIDI_EVENT_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup MIDI_Event Sequencer event <-> MIDI byte stream coder - * \ingroup Sequencer - * Sequencer event <-> MIDI byte stream coder - * \{ - */ - -/** container for sequencer midi event parsers */ -typedef struct snd_midi_event snd_midi_event_t; - -int snd_midi_event_new(size_t bufsize, snd_midi_event_t **rdev); -int snd_midi_event_resize_buffer(snd_midi_event_t *dev, size_t bufsize); -void snd_midi_event_free(snd_midi_event_t *dev); -void snd_midi_event_init(snd_midi_event_t *dev); -void snd_midi_event_reset_encode(snd_midi_event_t *dev); -void snd_midi_event_reset_decode(snd_midi_event_t *dev); -void snd_midi_event_no_status(snd_midi_event_t *dev, int on); -/* encode from byte stream - return number of written bytes if success */ -long snd_midi_event_encode(snd_midi_event_t *dev, const unsigned char *buf, long count, snd_seq_event_t *ev); -int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev); -/* decode from event to bytes - return number of written bytes if success */ -long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, const snd_seq_event_t *ev); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_SEQ_MIDI_EVENT_H */ - diff --git a/raylib/external/alsa/seqmid.h b/raylib/external/alsa/seqmid.h deleted file mode 100644 index 68069b2..0000000 --- a/raylib/external/alsa/seqmid.h +++ /dev/null @@ -1,490 +0,0 @@ -/** - * \file include/seqmid.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_SEQMID_H -#define __ALSA_SEQMID_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup SeqMiddle Sequencer Middle Level Interface - * Sequencer Middle Level Interface - * \ingroup Sequencer - * \{ - */ - -/** - * \brief initialize event record - * \param ev event record pointer - * - * This macro clears the given event record pointer to the default status. - */ -#define snd_seq_ev_clear(ev) \ - memset(ev, 0, sizeof(snd_seq_event_t)) - -/** - * \brief set the tag for given event - * \param ev event record - * \param t event tag - * - * This macro sets the tag to the given event record. - */ -#define snd_seq_ev_set_tag(ev,t) \ - ((ev)->tag = (t)) - -/** - * \brief set the explicit destination - * \param ev event record - * \param c destination client id - * \param p destination port id - * - * This macro sets the client and port id numbers to the given event record. - * - * \sa snd_seq_ev_set_subs() - */ -#define snd_seq_ev_set_dest(ev,c,p) \ - ((ev)->dest.client = (c), (ev)->dest.port = (p)) - -/** - * \brief set broadcasting to subscribers - * \param ev event record - * - * This macro sets the destination as the subscribers. - * - * \sa snd_seq_ev_set_dest() - */ -#define snd_seq_ev_set_subs(ev) \ - ((ev)->dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS,\ - (ev)->dest.port = SND_SEQ_ADDRESS_UNKNOWN) - -/** - * \brief set broadcasting to all clients/ports - * \param ev event record - * - * This macro sets the destination as the broadcasting. - * - * \sa snd_seq_ev_set_dest() - */ -#define snd_seq_ev_set_broadcast(ev) \ - ((ev)->dest.client = SND_SEQ_ADDRESS_BROADCAST,\ - (ev)->dest.port = SND_SEQ_ADDRESS_BROADCAST) - -/** - * \brief set the source port - * \param ev event record - * \param p source port id - * - * This macro sets the source port id number. - */ -#define snd_seq_ev_set_source(ev,p) \ - ((ev)->source.port = (p)) - -/** - * \brief set direct passing mode (without queued) - * \param ev event instance - * - * This macro sets the event to the direct passing mode - * to be delivered immediately without queueing. - * - * \sa snd_seq_ev_schedule_tick(), snd_seq_ev_schedule_real() - */ -#define snd_seq_ev_set_direct(ev) \ - ((ev)->queue = SND_SEQ_QUEUE_DIRECT) - -/** - * \brief set tick-scheduling mode on queue - * \param ev event instance - * \param q queue id to schedule - * \param relative relative time-stamp if non-zero - * \param ttick tick time-stamp to be delivered - * - * This macro sets the scheduling of the event in the - * MIDI tick mode. - * - * \sa snd_seq_ev_schedule_real(), snd_seq_ev_set_direct() - */ -#define snd_seq_ev_schedule_tick(ev, q, relative, ttick) \ - ((ev)->flags &= ~(SND_SEQ_TIME_STAMP_MASK | SND_SEQ_TIME_MODE_MASK),\ - (ev)->flags |= SND_SEQ_TIME_STAMP_TICK,\ - (ev)->flags |= (relative) ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS,\ - (ev)->time.tick = (ttick),\ - (ev)->queue = (q)) - -/** - * \brief set real-time-scheduling mode on queue - * \param ev event instance - * \param q queue id to schedule - * \param relative relative time-stamp if non-zero - * \param rtime time-stamp to be delivered - * - * This macro sets the scheduling of the event in the - * realtime mode. - * - * \sa snd_seq_ev_schedule_tick(), snd_seq_ev_set_direct() - */ -#define snd_seq_ev_schedule_real(ev, q, relative, rtime) \ - ((ev)->flags &= ~(SND_SEQ_TIME_STAMP_MASK | SND_SEQ_TIME_MODE_MASK),\ - (ev)->flags |= SND_SEQ_TIME_STAMP_REAL,\ - (ev)->flags |= (relative) ? SND_SEQ_TIME_MODE_REL : SND_SEQ_TIME_MODE_ABS,\ - (ev)->time.time = *(rtime),\ - (ev)->queue = (q)) - -/** - * \brief set event priority - * \param ev event instance - * \param high_prior 1 for high priority mode - */ -#define snd_seq_ev_set_priority(ev, high_prior) \ - ((ev)->flags &= ~SND_SEQ_PRIORITY_MASK,\ - (ev)->flags |= (high_prior) ? SND_SEQ_PRIORITY_HIGH : SND_SEQ_PRIORITY_NORMAL) - -/** - * \brief set fixed data - * \param ev event instance - * - * Sets the event length mode as fixed size. - * - * \sa snd_seq_ev_set_variable(), snd_seq_ev_set_varusr() - */ -#define snd_seq_ev_set_fixed(ev) \ - ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ - (ev)->flags |= SND_SEQ_EVENT_LENGTH_FIXED) - -/** - * \brief set variable data - * \param ev event instance - * \param datalen length of the external data - * \param dataptr pointer of the external data - * - * Sets the event length mode as variable length and stores the data. - * - * \sa snd_seq_ev_set_fixed(), snd_seq_ev_set_varusr() - */ -#define snd_seq_ev_set_variable(ev, datalen, dataptr) \ - ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ - (ev)->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE,\ - (ev)->data.ext.len = (datalen),\ - (ev)->data.ext.ptr = (dataptr)) - -/** - * \brief set varusr data - * \param ev event instance - * \param datalen length of the external data - * \param dataptr pointer of the external data - * - * Sets the event length mode as variable user-space data and stores the data. - * - * \sa snd_seq_ev_set_fixed(), snd_seq_ev_set_variable() - */ -#define snd_seq_ev_set_varusr(ev, datalen, dataptr) \ - ((ev)->flags &= ~SND_SEQ_EVENT_LENGTH_MASK,\ - (ev)->flags |= SND_SEQ_EVENT_LENGTH_VARUSR,\ - (ev)->data.ext.len = (datalen),\ - (ev)->data.ext.ptr = (dataptr)) - -/** - * \brief set queue controls - * \param ev event record - * \param typ event type - * \param q queue id - * \param val control value - */ -#define snd_seq_ev_set_queue_control(ev, typ, q, val) \ - ((ev)->type = (typ),\ - snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ - (ev)->data.queue.queue = (q),\ - (ev)->data.queue.param.value = (val)) - -/** - * \brief set the start queue event - * \param ev event record - * \param q queue id to start - * - * \sa snd_seq_ev_set_queue_stop(), snd_seq_ev_set_queue_continue() - */ -#define snd_seq_ev_set_queue_start(ev, q) \ - snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_START, q, 0) - -/** - * \brief set the stop queue event - * \param ev event record - * \param q queue id to stop - * - * \sa snd_seq_ev_set_queue_start(), snd_seq_ev_set_queue_continue() - */ -#define snd_seq_ev_set_queue_stop(ev, q) \ - snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_STOP, q, 0) - -/** - * \brief set the stop queue event - * \param ev event record - * \param q queue id to continue - * - * \sa snd_seq_ev_set_queue_start(), snd_seq_ev_set_queue_stop() - */ -#define snd_seq_ev_set_queue_continue(ev, q) \ - snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_CONTINUE, q, 0) - -/** - * \brief set the stop queue event - * \param ev event record - * \param q queue id to change tempo - * \param val the new tempo value - */ -#define snd_seq_ev_set_queue_tempo(ev, q, val) \ - snd_seq_ev_set_queue_control(ev, SND_SEQ_EVENT_TEMPO, q, val) - -/** - * \brief set the real-time position of a queue - * \param ev event record - * \param q queue id to change tempo - * \param rtime the new real-time pointer - */ -#define snd_seq_ev_set_queue_pos_real(ev, q, rtime) \ - ((ev)->type = SND_SEQ_EVENT_SETPOS_TIME,\ - snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ - (ev)->data.queue.queue = (q),\ - (ev)->data.queue.param.time.time = *(rtime)) - -/** - * \brief set the tick-time position of a queue - * \param ev event record - * \param q queue id to change tempo - * \param ttime the new tick-time - */ -#define snd_seq_ev_set_queue_pos_tick(ev, q, ttime) \ - ((ev)->type = SND_SEQ_EVENT_SETPOS_TICK,\ - snd_seq_ev_set_dest(ev, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_TIMER),\ - (ev)->data.queue.queue = (q),\ - (ev)->data.queue.param.time.tick = (ttime)) - -/* set and send a queue control event */ -int snd_seq_control_queue(snd_seq_t *seq, int q, int type, int value, snd_seq_event_t *ev); - -/** - * \brief start the specified queue - * \param seq sequencer handle - * \param q queue id to start - * \param ev optional event record (see #snd_seq_control_queue) - */ -#define snd_seq_start_queue(seq, q, ev) \ - snd_seq_control_queue(seq, q, SND_SEQ_EVENT_START, 0, ev) - -/** - * \brief stop the specified queue - * \param seq sequencer handle - * \param q queue id to stop - * \param ev optional event record (see #snd_seq_control_queue) - */ -#define snd_seq_stop_queue(seq, q, ev) \ - snd_seq_control_queue(seq, q, SND_SEQ_EVENT_STOP, 0, ev) - -/** - * \brief continue the specified queue - * \param seq sequencer handle - * \param q queue id to continue - * \param ev optional event record (see #snd_seq_control_queue) - */ -#define snd_seq_continue_queue(seq, q, ev) \ - snd_seq_control_queue(seq, q, SND_SEQ_EVENT_CONTINUE, 0, ev) - -/** - * \brief change the tempo of the specified queue - * \param seq sequencer handle - * \param q queue id - * \param tempo the new tempo value - * \param ev optional event record (see #snd_seq_control_queue) - */ -#define snd_seq_change_queue_tempo(seq, q, tempo, ev) \ - snd_seq_control_queue(seq, q, SND_SEQ_EVENT_TEMPO, tempo, ev) - -/* create a port - simple version - return the port number */ -int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, - unsigned int caps, unsigned int type); -/* delete the port */ -int snd_seq_delete_simple_port(snd_seq_t *seq, int port); - -/* simple subscription between this port and another port - (w/o exclusive & time conversion) - */ -int snd_seq_connect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); -int snd_seq_connect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); -int snd_seq_disconnect_from(snd_seq_t *seq, int my_port, int src_client, int src_port); -int snd_seq_disconnect_to(snd_seq_t *seq, int my_port, int dest_client, int dest_port); - -/* - * set client information - */ -int snd_seq_set_client_name(snd_seq_t *seq, const char *name); -int snd_seq_set_client_event_filter(snd_seq_t *seq, int event_type); -int snd_seq_set_client_pool_output(snd_seq_t *seq, size_t size); -int snd_seq_set_client_pool_output_room(snd_seq_t *seq, size_t size); -int snd_seq_set_client_pool_input(snd_seq_t *seq, size_t size); -/* sync output queue */ -int snd_seq_sync_output_queue(snd_seq_t *seq); - -/* - * parse the given string and get the sequencer address - */ -int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *str); - -/* - * reset client input/output pool - */ -int snd_seq_reset_pool_output(snd_seq_t *seq); -int snd_seq_reset_pool_input(snd_seq_t *seq); - -/** - * \brief set note event - * \param ev event record - * \param ch channel number - * \param key note key - * \param vel velocity - * \param dur duration (in tick or msec) - */ -#define snd_seq_ev_set_note(ev, ch, key, vel, dur) \ - ((ev)->type = SND_SEQ_EVENT_NOTE,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.note.channel = (ch),\ - (ev)->data.note.note = (key),\ - (ev)->data.note.velocity = (vel),\ - (ev)->data.note.duration = (dur)) - -/** - * \brief set note-on event - * \param ev event record - * \param ch channel number - * \param key note key - * \param vel velocity - */ -#define snd_seq_ev_set_noteon(ev, ch, key, vel) \ - ((ev)->type = SND_SEQ_EVENT_NOTEON,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.note.channel = (ch),\ - (ev)->data.note.note = (key),\ - (ev)->data.note.velocity = (vel)) - -/** - * \brief set note-off event - * \param ev event record - * \param ch channel number - * \param key note key - * \param vel velocity - */ -#define snd_seq_ev_set_noteoff(ev, ch, key, vel) \ - ((ev)->type = SND_SEQ_EVENT_NOTEOFF,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.note.channel = (ch),\ - (ev)->data.note.note = (key),\ - (ev)->data.note.velocity = (vel)) - -/** - * \brief set key-pressure event - * \param ev event record - * \param ch channel number - * \param key note key - * \param vel velocity - */ -#define snd_seq_ev_set_keypress(ev,ch,key,vel) \ - ((ev)->type = SND_SEQ_EVENT_KEYPRESS,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.note.channel = (ch),\ - (ev)->data.note.note = (key),\ - (ev)->data.note.velocity = (vel)) - -/** - * \brief set MIDI controller event - * \param ev event record - * \param ch channel number - * \param cc controller number - * \param val control value - */ -#define snd_seq_ev_set_controller(ev,ch,cc,val) \ - ((ev)->type = SND_SEQ_EVENT_CONTROLLER,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.control.channel = (ch),\ - (ev)->data.control.param = (cc),\ - (ev)->data.control.value = (val)) - -/** - * \brief set program change event - * \param ev event record - * \param ch channel number - * \param val program number - */ -#define snd_seq_ev_set_pgmchange(ev,ch,val) \ - ((ev)->type = SND_SEQ_EVENT_PGMCHANGE,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.control.channel = (ch),\ - (ev)->data.control.value = (val)) - -/** - * \brief set pitch-bend event - * \param ev event record - * \param ch channel number - * \param val pitch bend; zero centered from -8192 to 8191 - */ -#define snd_seq_ev_set_pitchbend(ev,ch,val) \ - ((ev)->type = SND_SEQ_EVENT_PITCHBEND,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.control.channel = (ch),\ - (ev)->data.control.value = (val)) - -/** - * \brief set channel pressure event - * \param ev event record - * \param ch channel number - * \param val channel pressure value - */ -#define snd_seq_ev_set_chanpress(ev,ch,val) \ - ((ev)->type = SND_SEQ_EVENT_CHANPRESS,\ - snd_seq_ev_set_fixed(ev),\ - (ev)->data.control.channel = (ch),\ - (ev)->data.control.value = (val)) - -/** - * \brief set sysex event - * \param ev event record - * \param datalen length of sysex data - * \param dataptr sysex data pointer - * - * the sysex data must contain the start byte 0xf0 and the end byte 0xf7. - */ -#define snd_seq_ev_set_sysex(ev,datalen,dataptr) \ - ((ev)->type = SND_SEQ_EVENT_SYSEX,\ - snd_seq_ev_set_variable(ev, datalen, dataptr)) - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_SEQMID_H */ - diff --git a/raylib/external/alsa/sound/asoc.h b/raylib/external/alsa/sound/asoc.h deleted file mode 100644 index 0f5d9f9..0000000 --- a/raylib/external/alsa/sound/asoc.h +++ /dev/null @@ -1,551 +0,0 @@ -/* - * uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM - * - * Copyright (C) 2012 Texas Instruments Inc. - * Copyright (C) 2015 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Simple file API to load FW that includes mixers, coefficients, DAPM graphs, - * algorithms, equalisers, DAIs, widgets etc. -*/ - -#ifndef __LINUX_UAPI_SND_ASOC_H -#define __LINUX_UAPI_SND_ASOC_H - -/* - * Maximum number of channels topology kcontrol can represent. - */ -#define SND_SOC_TPLG_MAX_CHAN 8 - -/* - * Maximum number of PCM formats capability - */ -#define SND_SOC_TPLG_MAX_FORMATS 16 - -/* - * Maximum number of PCM stream configs - */ -#define SND_SOC_TPLG_STREAM_CONFIG_MAX 8 - -/* - * Maximum number of physical link's hardware configs - */ -#define SND_SOC_TPLG_HW_CONFIG_MAX 8 - -/* individual kcontrol info types - can be mixed with other types */ -#define SND_SOC_TPLG_CTL_VOLSW 1 -#define SND_SOC_TPLG_CTL_VOLSW_SX 2 -#define SND_SOC_TPLG_CTL_VOLSW_XR_SX 3 -#define SND_SOC_TPLG_CTL_ENUM 4 -#define SND_SOC_TPLG_CTL_BYTES 5 -#define SND_SOC_TPLG_CTL_ENUM_VALUE 6 -#define SND_SOC_TPLG_CTL_RANGE 7 -#define SND_SOC_TPLG_CTL_STROBE 8 - - -/* individual widget kcontrol info types - can be mixed with other types */ -#define SND_SOC_TPLG_DAPM_CTL_VOLSW 64 -#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE 65 -#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT 66 -#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE 67 -#define SND_SOC_TPLG_DAPM_CTL_PIN 68 - -/* DAPM widget types - add new items to the end */ -#define SND_SOC_TPLG_DAPM_INPUT 0 -#define SND_SOC_TPLG_DAPM_OUTPUT 1 -#define SND_SOC_TPLG_DAPM_MUX 2 -#define SND_SOC_TPLG_DAPM_MIXER 3 -#define SND_SOC_TPLG_DAPM_PGA 4 -#define SND_SOC_TPLG_DAPM_OUT_DRV 5 -#define SND_SOC_TPLG_DAPM_ADC 6 -#define SND_SOC_TPLG_DAPM_DAC 7 -#define SND_SOC_TPLG_DAPM_SWITCH 8 -#define SND_SOC_TPLG_DAPM_PRE 9 -#define SND_SOC_TPLG_DAPM_POST 10 -#define SND_SOC_TPLG_DAPM_AIF_IN 11 -#define SND_SOC_TPLG_DAPM_AIF_OUT 12 -#define SND_SOC_TPLG_DAPM_DAI_IN 13 -#define SND_SOC_TPLG_DAPM_DAI_OUT 14 -#define SND_SOC_TPLG_DAPM_DAI_LINK 15 -#define SND_SOC_TPLG_DAPM_BUFFER 16 -#define SND_SOC_TPLG_DAPM_SCHEDULER 17 -#define SND_SOC_TPLG_DAPM_EFFECT 18 -#define SND_SOC_TPLG_DAPM_SIGGEN 19 -#define SND_SOC_TPLG_DAPM_SRC 20 -#define SND_SOC_TPLG_DAPM_ASRC 21 -#define SND_SOC_TPLG_DAPM_ENCODER 22 -#define SND_SOC_TPLG_DAPM_DECODER 23 -#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DECODER - -/* Header magic number and string sizes */ -#define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */ - -/* string sizes */ -#define SND_SOC_TPLG_NUM_TEXTS 16 - -/* ABI version */ -#define SND_SOC_TPLG_ABI_VERSION 0x5 /* current version */ -#define SND_SOC_TPLG_ABI_VERSION_MIN 0x4 /* oldest version supported */ - -/* Max size of TLV data */ -#define SND_SOC_TPLG_TLV_SIZE 32 - -/* - * File and Block header data types. - * Add new generic and vendor types to end of list. - * Generic types are handled by the core whilst vendors types are passed - * to the component drivers for handling. - */ -#define SND_SOC_TPLG_TYPE_MIXER 1 -#define SND_SOC_TPLG_TYPE_BYTES 2 -#define SND_SOC_TPLG_TYPE_ENUM 3 -#define SND_SOC_TPLG_TYPE_DAPM_GRAPH 4 -#define SND_SOC_TPLG_TYPE_DAPM_WIDGET 5 -#define SND_SOC_TPLG_TYPE_DAI_LINK 6 -#define SND_SOC_TPLG_TYPE_PCM 7 -#define SND_SOC_TPLG_TYPE_MANIFEST 8 -#define SND_SOC_TPLG_TYPE_CODEC_LINK 9 -#define SND_SOC_TPLG_TYPE_BACKEND_LINK 10 -#define SND_SOC_TPLG_TYPE_PDATA 11 -#define SND_SOC_TPLG_TYPE_DAI 12 -#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_DAI - -/* vendor block IDs - please add new vendor types to end */ -#define SND_SOC_TPLG_TYPE_VENDOR_FW 1000 -#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG 1001 -#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002 -#define SND_SOC_TPLG_TYPEVENDOR_CODEC 1003 - -#define SND_SOC_TPLG_STREAM_PLAYBACK 0 -#define SND_SOC_TPLG_STREAM_CAPTURE 1 - -/* vendor tuple types */ -#define SND_SOC_TPLG_TUPLE_TYPE_UUID 0 -#define SND_SOC_TPLG_TUPLE_TYPE_STRING 1 -#define SND_SOC_TPLG_TUPLE_TYPE_BOOL 2 -#define SND_SOC_TPLG_TUPLE_TYPE_BYTE 3 -#define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 -#define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5 - -/* DAI flags */ -#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES (1 << 0) -#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) -#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) - -/* DAI physical PCM data formats. - * Add new formats to the end of the list. - */ -#define SND_SOC_DAI_FORMAT_I2S 1 /* I2S mode */ -#define SND_SOC_DAI_FORMAT_RIGHT_J 2 /* Right Justified mode */ -#define SND_SOC_DAI_FORMAT_LEFT_J 3 /* Left Justified mode */ -#define SND_SOC_DAI_FORMAT_DSP_A 4 /* L data MSB after FRM LRC */ -#define SND_SOC_DAI_FORMAT_DSP_B 5 /* L data MSB during FRM LRC */ -#define SND_SOC_DAI_FORMAT_AC97 6 /* AC97 */ -#define SND_SOC_DAI_FORMAT_PDM 7 /* Pulse density modulation */ - -/* left and right justified also known as MSB and LSB respectively */ -#define SND_SOC_DAI_FORMAT_MSB SND_SOC_DAI_FORMAT_LEFT_J -#define SND_SOC_DAI_FORMAT_LSB SND_SOC_DAI_FORMAT_RIGHT_J - -/* DAI link flags */ -#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) -#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) -#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) -#define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) - -/* - * Block Header. - * This header precedes all object and object arrays below. - */ -struct snd_soc_tplg_hdr { - __le32 magic; /* magic number */ - __le32 abi; /* ABI version */ - __le32 version; /* optional vendor specific version details */ - __le32 type; /* SND_SOC_TPLG_TYPE_ */ - __le32 size; /* size of this structure */ - __le32 vendor_type; /* optional vendor specific type info */ - __le32 payload_size; /* data bytes, excluding this header */ - __le32 index; /* identifier for block */ - __le32 count; /* number of elements in block */ -} __attribute__((packed)); - -/* vendor tuple for uuid */ -struct snd_soc_tplg_vendor_uuid_elem { - __le32 token; - char uuid[16]; -} __attribute__((packed)); - -/* vendor tuple for a bool/byte/short/word value */ -struct snd_soc_tplg_vendor_value_elem { - __le32 token; - __le32 value; -} __attribute__((packed)); - -/* vendor tuple for string */ -struct snd_soc_tplg_vendor_string_elem { - __le32 token; - char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; -} __attribute__((packed)); - -struct snd_soc_tplg_vendor_array { - __le32 size; /* size in bytes of the array, including all elements */ - __le32 type; /* SND_SOC_TPLG_TUPLE_TYPE_ */ - __le32 num_elems; /* number of elements in array */ - union { - struct snd_soc_tplg_vendor_uuid_elem uuid[0]; - struct snd_soc_tplg_vendor_value_elem value[0]; - struct snd_soc_tplg_vendor_string_elem string[0]; - }; -} __attribute__((packed)); - -/* - * Private data. - * All topology objects may have private data that can be used by the driver or - * firmware. Core will ignore this data. - */ -struct snd_soc_tplg_private { - __le32 size; /* in bytes of private data */ - union { - char data[0]; - struct snd_soc_tplg_vendor_array array[0]; - }; -} __attribute__((packed)); - -/* - * Kcontrol TLV data. - */ -struct snd_soc_tplg_tlv_dbscale { - __le32 min; - __le32 step; - __le32 mute; -} __attribute__((packed)); - -struct snd_soc_tplg_ctl_tlv { - __le32 size; /* in bytes of this structure */ - __le32 type; /* SNDRV_CTL_TLVT_*, type of TLV */ - union { - __le32 data[SND_SOC_TPLG_TLV_SIZE]; - struct snd_soc_tplg_tlv_dbscale scale; - }; -} __attribute__((packed)); - -/* - * Kcontrol channel data - */ -struct snd_soc_tplg_channel { - __le32 size; /* in bytes of this structure */ - __le32 reg; - __le32 shift; - __le32 id; /* ID maps to Left, Right, LFE etc */ -} __attribute__((packed)); - -/* - * Genericl Operations IDs, for binding Kcontrol or Bytes ext ops - * Kcontrol ops need get/put/info. - * Bytes ext ops need get/put. - */ -struct snd_soc_tplg_io_ops { - __le32 get; - __le32 put; - __le32 info; -} __attribute__((packed)); - -/* - * kcontrol header - */ -struct snd_soc_tplg_ctl_hdr { - __le32 size; /* in bytes of this structure */ - __le32 type; - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - __le32 access; - struct snd_soc_tplg_io_ops ops; - struct snd_soc_tplg_ctl_tlv tlv; -} __attribute__((packed)); - -/* - * Stream Capabilities - */ -struct snd_soc_tplg_stream_caps { - __le32 size; /* in bytes of this structure */ - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */ - __le32 rates; /* supported rates SNDRV_PCM_RATE_* */ - __le32 rate_min; /* min rate */ - __le32 rate_max; /* max rate */ - __le32 channels_min; /* min channels */ - __le32 channels_max; /* max channels */ - __le32 periods_min; /* min number of periods */ - __le32 periods_max; /* max number of periods */ - __le32 period_size_min; /* min period size bytes */ - __le32 period_size_max; /* max period size bytes */ - __le32 buffer_size_min; /* min buffer size bytes */ - __le32 buffer_size_max; /* max buffer size bytes */ - __le32 sig_bits; /* number of bits of content */ -} __attribute__((packed)); - -/* - * FE or BE Stream configuration supported by SW/FW - */ -struct snd_soc_tplg_stream { - __le32 size; /* in bytes of this structure */ - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* Name of the stream */ - __le64 format; /* SNDRV_PCM_FMTBIT_* */ - __le32 rate; /* SNDRV_PCM_RATE_* */ - __le32 period_bytes; /* size of period in bytes */ - __le32 buffer_bytes; /* size of buffer in bytes */ - __le32 channels; /* channels */ -} __attribute__((packed)); - - -/* - * Describes a physical link's runtime supported hardware config, - * i.e. hardware audio formats. - */ -struct snd_soc_tplg_hw_config { - __le32 size; /* in bytes of this structure */ - __le32 id; /* unique ID - - used to match */ - __le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */ - __u8 clock_gated; /* 1 if clock can be gated to save power */ - __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ - __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* 1 for master of BCLK, 0 for slave */ - __u8 fsync_master; /* 1 for master of FSYNC, 0 for slave */ - __u8 mclk_direction; /* 0 for input, 1 for output */ - __le16 reserved; /* for 32bit alignment */ - __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ - __le32 bclk_rate; /* BCLK freqency in Hz */ - __le32 fsync_rate; /* frame clock in Hz */ - __le32 tdm_slots; /* number of TDM slots in use */ - __le32 tdm_slot_width; /* width in bits for each slot */ - __le32 tx_slots; /* bit mask for active Tx slots */ - __le32 rx_slots; /* bit mask for active Rx slots */ - __le32 tx_channels; /* number of Tx channels */ - __le32 tx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ - __le32 rx_channels; /* number of Rx channels */ - __le32 rx_chanmap[SND_SOC_TPLG_MAX_CHAN]; /* array of slot number */ -} __attribute__((packed)); - -/* - * Manifest. List totals for each payload type. Not used in parsing, but will - * be passed to the component driver before any other objects in order for any - * global component resource allocations. - * - * File block representation for manifest :- - * +-----------------------------------+----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+----+ - * | struct snd_soc_tplg_manifest | 1 | - * +-----------------------------------+----+ - */ -struct snd_soc_tplg_manifest { - __le32 size; /* in bytes of this structure */ - __le32 control_elems; /* number of control elements */ - __le32 widget_elems; /* number of widget elements */ - __le32 graph_elems; /* number of graph elements */ - __le32 pcm_elems; /* number of PCM elements */ - __le32 dai_link_elems; /* number of DAI link elements */ - __le32 dai_elems; /* number of physical DAI elements */ - __le32 reserved[20]; /* reserved for new ABI element types */ - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - -/* - * Mixer kcontrol. - * - * File block representation for mixer kcontrol :- - * +-----------------------------------+----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+----+ - * | struct snd_soc_tplg_mixer_control | N | - * +-----------------------------------+----+ - */ -struct snd_soc_tplg_mixer_control { - struct snd_soc_tplg_ctl_hdr hdr; - __le32 size; /* in bytes of this structure */ - __le32 min; - __le32 max; - __le32 platform_max; - __le32 invert; - __le32 num_channels; - struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - -/* - * Enumerated kcontrol - * - * File block representation for enum kcontrol :- - * +-----------------------------------+----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+----+ - * | struct snd_soc_tplg_enum_control | N | - * +-----------------------------------+----+ - */ -struct snd_soc_tplg_enum_control { - struct snd_soc_tplg_ctl_hdr hdr; - __le32 size; /* in bytes of this structure */ - __le32 num_channels; - struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN]; - __le32 items; - __le32 mask; - __le32 count; - char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - __le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4]; - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - -/* - * Bytes kcontrol - * - * File block representation for bytes kcontrol :- - * +-----------------------------------+----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+----+ - * | struct snd_soc_tplg_bytes_control | N | - * +-----------------------------------+----+ - */ -struct snd_soc_tplg_bytes_control { - struct snd_soc_tplg_ctl_hdr hdr; - __le32 size; /* in bytes of this structure */ - __le32 max; - __le32 mask; - __le32 base; - __le32 num_regs; - struct snd_soc_tplg_io_ops ext_ops; - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - -/* - * DAPM Graph Element - * - * File block representation for DAPM graph elements :- - * +-------------------------------------+----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-------------------------------------+----+ - * | struct snd_soc_tplg_dapm_graph_elem | N | - * +-------------------------------------+----+ - */ -struct snd_soc_tplg_dapm_graph_elem { - char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; -} __attribute__((packed)); - -/* - * DAPM Widget. - * - * File block representation for DAPM widget :- - * +-------------------------------------+-----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-------------------------------------+-----+ - * | struct snd_soc_tplg_dapm_widget | N | - * +-------------------------------------+-----+ - * | struct snd_soc_tplg_enum_control | 0|1 | - * | struct snd_soc_tplg_mixer_control | 0|N | - * +-------------------------------------+-----+ - * - * Optional enum or mixer control can be appended to the end of each widget - * in the block. - */ -struct snd_soc_tplg_dapm_widget { - __le32 size; /* in bytes of this structure */ - __le32 id; /* SND_SOC_DAPM_CTL */ - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - - __le32 reg; /* negative reg = no direct dapm */ - __le32 shift; /* bits to shift */ - __le32 mask; /* non-shifted mask */ - __le32 subseq; /* sort within widget type */ - __le32 invert; /* invert the power bit */ - __le32 ignore_suspend; /* kept enabled over suspend */ - __le16 event_flags; - __le16 event_type; - __le32 num_kcontrols; - struct snd_soc_tplg_private priv; - /* - * kcontrols that relate to this widget - * follow here after widget private data - */ -} __attribute__((packed)); - - -/* - * Describes SW/FW specific features of PCM (FE DAI & DAI link). - * - * File block representation for PCM :- - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_pcm | N | - * +-----------------------------------+-----+ - */ -struct snd_soc_tplg_pcm { - __le32 size; /* in bytes of this structure */ - char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - __le32 pcm_id; /* unique ID - used to match with DAI link */ - __le32 dai_id; /* unique ID - used to match */ - __le32 playback; /* supports playback mode */ - __le32 capture; /* supports capture mode */ - __le32 compress; /* 1 = compressed; 0 = PCM */ - struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ - __le32 num_streams; /* number of streams */ - struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ - __le32 flag_mask; /* bitmask of flags to configure */ - __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - - -/* - * Describes the physical link runtime supported configs or params - * - * File block representation for physical link config :- - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_link_config | N | - * +-----------------------------------+-----+ - */ -struct snd_soc_tplg_link_config { - __le32 size; /* in bytes of this structure */ - __le32 id; /* unique ID - used to match */ - char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ - char stream_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* stream name - used to match */ - struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ - __le32 num_streams; /* number of streams */ - struct snd_soc_tplg_hw_config hw_config[SND_SOC_TPLG_HW_CONFIG_MAX]; /* hw configs */ - __le32 num_hw_configs; /* number of hw configs */ - __le32 default_hw_config_id; /* default hw config ID for init */ - __le32 flag_mask; /* bitmask of flags to configure */ - __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ - struct snd_soc_tplg_private priv; -} __attribute__((packed)); - -/* - * Describes SW/FW specific features of physical DAI. - * It can be used to configure backend DAIs for DPCM. - * - * File block representation for physical DAI :- - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_hdr | 1 | - * +-----------------------------------+-----+ - * | struct snd_soc_tplg_dai | N | - * +-----------------------------------+-----+ - */ -struct snd_soc_tplg_dai { - __le32 size; /* in bytes of this structure */ - char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ - __le32 dai_id; /* unique ID - used to match */ - __le32 playback; /* supports playback mode */ - __le32 capture; /* supports capture mode */ - struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ - __le32 flag_mask; /* bitmask of flags to configure */ - __le32 flags; /* SND_SOC_TPLG_DAI_FLGBIT_* */ - struct snd_soc_tplg_private priv; -} __attribute__((packed)); -#endif diff --git a/raylib/external/alsa/sound/asound_fm.h b/raylib/external/alsa/sound/asound_fm.h deleted file mode 100644 index c2a4b96..0000000 --- a/raylib/external/alsa/sound/asound_fm.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef __SOUND_ASOUND_FM_H -#define __SOUND_ASOUND_FM_H - -/* - * Advanced Linux Sound Architecture - ALSA - * - * Interface file between ALSA driver & user space - * Copyright (c) 1994-98 by Jaroslav Kysela , - * 4Front Technologies - * - * Direct FM control - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#define SNDRV_DM_FM_MODE_OPL2 0x00 -#define SNDRV_DM_FM_MODE_OPL3 0x01 - -struct snd_dm_fm_info { - unsigned char fm_mode; /* OPL mode, see SNDRV_DM_FM_MODE_XXX */ - unsigned char rhythm; /* percussion mode flag */ -}; - -/* - * Data structure composing an FM "note" or sound event. - */ - -struct snd_dm_fm_voice { - unsigned char op; /* operator cell (0 or 1) */ - unsigned char voice; /* FM voice (0 to 17) */ - - unsigned char am; /* amplitude modulation */ - unsigned char vibrato; /* vibrato effect */ - unsigned char do_sustain; /* sustain phase */ - unsigned char kbd_scale; /* keyboard scaling */ - unsigned char harmonic; /* 4 bits: harmonic and multiplier */ - unsigned char scale_level; /* 2 bits: decrease output freq rises */ - unsigned char volume; /* 6 bits: volume */ - - unsigned char attack; /* 4 bits: attack rate */ - unsigned char decay; /* 4 bits: decay rate */ - unsigned char sustain; /* 4 bits: sustain level */ - unsigned char release; /* 4 bits: release rate */ - - unsigned char feedback; /* 3 bits: feedback for op0 */ - unsigned char connection; /* 0 for serial, 1 for parallel */ - unsigned char left; /* stereo left */ - unsigned char right; /* stereo right */ - unsigned char waveform; /* 3 bits: waveform shape */ -}; - -/* - * This describes an FM note by its voice, octave, frequency number (10bit) - * and key on/off. - */ - -struct snd_dm_fm_note { - unsigned char voice; /* 0-17 voice channel */ - unsigned char octave; /* 3 bits: what octave to play */ - unsigned int fnum; /* 10 bits: frequency number */ - unsigned char key_on; /* set for active, clear for silent */ -}; - -/* - * FM parameters that apply globally to all voices, and thus are not "notes" - */ - -struct snd_dm_fm_params { - unsigned char am_depth; /* amplitude modulation depth (1=hi) */ - unsigned char vib_depth; /* vibrato depth (1=hi) */ - unsigned char kbd_split; /* keyboard split */ - unsigned char rhythm; /* percussion mode select */ - - /* This block is the percussion instrument data */ - unsigned char bass; - unsigned char snare; - unsigned char tomtom; - unsigned char cymbal; - unsigned char hihat; -}; - -/* - * FM mode ioctl settings - */ - -#define SNDRV_DM_FM_IOCTL_INFO _IOR('H', 0x20, struct snd_dm_fm_info) -#define SNDRV_DM_FM_IOCTL_RESET _IO ('H', 0x21) -#define SNDRV_DM_FM_IOCTL_PLAY_NOTE _IOW('H', 0x22, struct snd_dm_fm_note) -#define SNDRV_DM_FM_IOCTL_SET_VOICE _IOW('H', 0x23, struct snd_dm_fm_voice) -#define SNDRV_DM_FM_IOCTL_SET_PARAMS _IOW('H', 0x24, struct snd_dm_fm_params) -#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int) -/* for OPL3 only */ -#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) -/* SBI patch management */ -#define SNDRV_DM_FM_IOCTL_CLEAR_PATCHES _IO ('H', 0x40) - -#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 -#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 -#define SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 -#define SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 -#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 -#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 - -/* - * Patch Record - fixed size for write - */ - -#define FM_KEY_SBI "SBI\032" -#define FM_KEY_2OP "2OP\032" -#define FM_KEY_4OP "4OP\032" - -struct sbi_patch { - unsigned char prog; - unsigned char bank; - char key[4]; - char name[25]; - char extension[7]; - unsigned char data[32]; -}; - -#endif /* __SOUND_ASOUND_FM_H */ diff --git a/raylib/external/alsa/sound/emu10k1.h b/raylib/external/alsa/sound/emu10k1.h deleted file mode 100644 index 94018b7..0000000 --- a/raylib/external/alsa/sound/emu10k1.h +++ /dev/null @@ -1,349 +0,0 @@ -#ifndef __SOUND_EMU10K1_H -#define __SOUND_EMU10K1_H - -/* - * Copyright (c) by Jaroslav Kysela , - * Creative Labs, Inc. - * Definitions for EMU10K1 (SB Live!) chips - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include - -/* - * ---- FX8010 ---- - */ - -#define EMU10K1_CARD_CREATIVE 0x00000000 -#define EMU10K1_CARD_EMUAPS 0x00000001 - -#define EMU10K1_FX8010_PCM_COUNT 8 - -/* instruction set */ -#define iMAC0 0x00 /* R = A + (X * Y >> 31) ; saturation */ -#define iMAC1 0x01 /* R = A + (-X * Y >> 31) ; saturation */ -#define iMAC2 0x02 /* R = A + (X * Y >> 31) ; wraparound */ -#define iMAC3 0x03 /* R = A + (-X * Y >> 31) ; wraparound */ -#define iMACINT0 0x04 /* R = A + X * Y ; saturation */ -#define iMACINT1 0x05 /* R = A + X * Y ; wraparound (31-bit) */ -#define iACC3 0x06 /* R = A + X + Y ; saturation */ -#define iMACMV 0x07 /* R = A, acc += X * Y >> 31 */ -#define iANDXOR 0x08 /* R = (A & X) ^ Y */ -#define iTSTNEG 0x09 /* R = (A >= Y) ? X : ~X */ -#define iLIMITGE 0x0a /* R = (A >= Y) ? X : Y */ -#define iLIMITLT 0x0b /* R = (A < Y) ? X : Y */ -#define iLOG 0x0c /* R = linear_data, A (log_data), X (max_exp), Y (format_word) */ -#define iEXP 0x0d /* R = log_data, A (linear_data), X (max_exp), Y (format_word) */ -#define iINTERP 0x0e /* R = A + (X * (Y - A) >> 31) ; saturation */ -#define iSKIP 0x0f /* R = A (cc_reg), X (count), Y (cc_test) */ - -/* GPRs */ -#define FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x0f */ -#define EXTIN(x) (0x10 + (x)) /* x = 0x00 - 0x0f */ -#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f */ -#define C_00000000 0x40 -#define C_00000001 0x41 -#define C_00000002 0x42 -#define C_00000003 0x43 -#define C_00000004 0x44 -#define C_00000008 0x45 -#define C_00000010 0x46 -#define C_00000020 0x47 -#define C_00000100 0x48 -#define C_00010000 0x49 -#define C_00080000 0x4a -#define C_10000000 0x4b -#define C_20000000 0x4c -#define C_40000000 0x4d -#define C_80000000 0x4e -#define C_7fffffff 0x4f -#define C_ffffffff 0x50 -#define C_fffffffe 0x51 -#define C_c0000000 0x52 -#define C_4f1bbcdc 0x53 -#define C_5a7ef9db 0x54 -#define C_00100000 0x55 /* ?? */ -#define GPR_ACCU 0x56 /* ACCUM, accumulator */ -#define GPR_COND 0x57 /* CCR, condition register */ -#define GPR_NOISE0 0x58 /* noise source */ -#define GPR_NOISE1 0x59 /* noise source */ -#define GPR_IRQ 0x5a /* IRQ register */ -#define GPR_DBAC 0x5b /* TRAM Delay Base Address Counter */ -#define GPR(x) (FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */ -#define ITRAM_DATA(x) (TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ -#define ETRAM_DATA(x) (TANKMEMDATAREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ -#define ITRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */ -#define ETRAM_ADDR(x) (TANKMEMADDRREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */ - -#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f? */ -#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x1f? */ -#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f? */ -#define A_GPR(x) (A_FXGPREGBASE + (x)) - -/* cc_reg constants */ -#define CC_REG_NORMALIZED C_00000001 -#define CC_REG_BORROW C_00000002 -#define CC_REG_MINUS C_00000004 -#define CC_REG_ZERO C_00000008 -#define CC_REG_SATURATE C_00000010 -#define CC_REG_NONZERO C_00000100 - -/* FX buses */ -#define FXBUS_PCM_LEFT 0x00 -#define FXBUS_PCM_RIGHT 0x01 -#define FXBUS_PCM_LEFT_REAR 0x02 -#define FXBUS_PCM_RIGHT_REAR 0x03 -#define FXBUS_MIDI_LEFT 0x04 -#define FXBUS_MIDI_RIGHT 0x05 -#define FXBUS_PCM_CENTER 0x06 -#define FXBUS_PCM_LFE 0x07 -#define FXBUS_PCM_LEFT_FRONT 0x08 -#define FXBUS_PCM_RIGHT_FRONT 0x09 -#define FXBUS_MIDI_REVERB 0x0c -#define FXBUS_MIDI_CHORUS 0x0d -#define FXBUS_PCM_LEFT_SIDE 0x0e -#define FXBUS_PCM_RIGHT_SIDE 0x0f -#define FXBUS_PT_LEFT 0x14 -#define FXBUS_PT_RIGHT 0x15 - -/* Inputs */ -#define EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ -#define EXTIN_AC97_R 0x01 /* AC'97 capture channel - right */ -#define EXTIN_SPDIF_CD_L 0x02 /* internal S/PDIF CD - onboard - left */ -#define EXTIN_SPDIF_CD_R 0x03 /* internal S/PDIF CD - onboard - right */ -#define EXTIN_ZOOM_L 0x04 /* Zoom Video I2S - left */ -#define EXTIN_ZOOM_R 0x05 /* Zoom Video I2S - right */ -#define EXTIN_TOSLINK_L 0x06 /* LiveDrive - TOSLink Optical - left */ -#define EXTIN_TOSLINK_R 0x07 /* LiveDrive - TOSLink Optical - right */ -#define EXTIN_LINE1_L 0x08 /* LiveDrive - Line/Mic 1 - left */ -#define EXTIN_LINE1_R 0x09 /* LiveDrive - Line/Mic 1 - right */ -#define EXTIN_COAX_SPDIF_L 0x0a /* LiveDrive - Coaxial S/PDIF - left */ -#define EXTIN_COAX_SPDIF_R 0x0b /* LiveDrive - Coaxial S/PDIF - right */ -#define EXTIN_LINE2_L 0x0c /* LiveDrive - Line/Mic 2 - left */ -#define EXTIN_LINE2_R 0x0d /* LiveDrive - Line/Mic 2 - right */ - -/* Outputs */ -#define EXTOUT_AC97_L 0x00 /* AC'97 playback channel - left */ -#define EXTOUT_AC97_R 0x01 /* AC'97 playback channel - right */ -#define EXTOUT_TOSLINK_L 0x02 /* LiveDrive - TOSLink Optical - left */ -#define EXTOUT_TOSLINK_R 0x03 /* LiveDrive - TOSLink Optical - right */ -#define EXTOUT_AC97_CENTER 0x04 /* SB Live 5.1 - center */ -#define EXTOUT_AC97_LFE 0x05 /* SB Live 5.1 - LFE */ -#define EXTOUT_HEADPHONE_L 0x06 /* LiveDrive - Headphone - left */ -#define EXTOUT_HEADPHONE_R 0x07 /* LiveDrive - Headphone - right */ -#define EXTOUT_REAR_L 0x08 /* Rear channel - left */ -#define EXTOUT_REAR_R 0x09 /* Rear channel - right */ -#define EXTOUT_ADC_CAP_L 0x0a /* ADC Capture buffer - left */ -#define EXTOUT_ADC_CAP_R 0x0b /* ADC Capture buffer - right */ -#define EXTOUT_MIC_CAP 0x0c /* MIC Capture buffer */ -#define EXTOUT_AC97_REAR_L 0x0d /* SB Live 5.1 (c) 2003 - Rear Left */ -#define EXTOUT_AC97_REAR_R 0x0e /* SB Live 5.1 (c) 2003 - Rear Right */ -#define EXTOUT_ACENTER 0x11 /* Analog Center */ -#define EXTOUT_ALFE 0x12 /* Analog LFE */ - -/* Audigy Inputs */ -#define A_EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ -#define A_EXTIN_AC97_R 0x01 /* AC'97 capture channel - right */ -#define A_EXTIN_SPDIF_CD_L 0x02 /* digital CD left */ -#define A_EXTIN_SPDIF_CD_R 0x03 /* digital CD left */ -#define A_EXTIN_OPT_SPDIF_L 0x04 /* audigy drive Optical SPDIF - left */ -#define A_EXTIN_OPT_SPDIF_R 0x05 /* right */ -#define A_EXTIN_LINE2_L 0x08 /* audigy drive line2/mic2 - left */ -#define A_EXTIN_LINE2_R 0x09 /* right */ -#define A_EXTIN_ADC_L 0x0a /* Philips ADC - left */ -#define A_EXTIN_ADC_R 0x0b /* right */ -#define A_EXTIN_AUX2_L 0x0c /* audigy drive aux2 - left */ -#define A_EXTIN_AUX2_R 0x0d /* - right */ - -/* Audigiy Outputs */ -#define A_EXTOUT_FRONT_L 0x00 /* digital front left */ -#define A_EXTOUT_FRONT_R 0x01 /* right */ -#define A_EXTOUT_CENTER 0x02 /* digital front center */ -#define A_EXTOUT_LFE 0x03 /* digital front lfe */ -#define A_EXTOUT_HEADPHONE_L 0x04 /* headphone audigy drive left */ -#define A_EXTOUT_HEADPHONE_R 0x05 /* right */ -#define A_EXTOUT_REAR_L 0x06 /* digital rear left */ -#define A_EXTOUT_REAR_R 0x07 /* right */ -#define A_EXTOUT_AFRONT_L 0x08 /* analog front left */ -#define A_EXTOUT_AFRONT_R 0x09 /* right */ -#define A_EXTOUT_ACENTER 0x0a /* analog center */ -#define A_EXTOUT_ALFE 0x0b /* analog LFE */ -#define A_EXTOUT_ASIDE_L 0x0c /* analog side left - Audigy 2 ZS */ -#define A_EXTOUT_ASIDE_R 0x0d /* right - Audigy 2 ZS */ -#define A_EXTOUT_AREAR_L 0x0e /* analog rear left */ -#define A_EXTOUT_AREAR_R 0x0f /* right */ -#define A_EXTOUT_AC97_L 0x10 /* AC97 left (front) */ -#define A_EXTOUT_AC97_R 0x11 /* right */ -#define A_EXTOUT_ADC_CAP_L 0x16 /* ADC capture buffer left */ -#define A_EXTOUT_ADC_CAP_R 0x17 /* right */ -#define A_EXTOUT_MIC_CAP 0x18 /* Mic capture buffer */ - -/* Audigy constants */ -#define A_C_00000000 0xc0 -#define A_C_00000001 0xc1 -#define A_C_00000002 0xc2 -#define A_C_00000003 0xc3 -#define A_C_00000004 0xc4 -#define A_C_00000008 0xc5 -#define A_C_00000010 0xc6 -#define A_C_00000020 0xc7 -#define A_C_00000100 0xc8 -#define A_C_00010000 0xc9 -#define A_C_00000800 0xca -#define A_C_10000000 0xcb -#define A_C_20000000 0xcc -#define A_C_40000000 0xcd -#define A_C_80000000 0xce -#define A_C_7fffffff 0xcf -#define A_C_ffffffff 0xd0 -#define A_C_fffffffe 0xd1 -#define A_C_c0000000 0xd2 -#define A_C_4f1bbcdc 0xd3 -#define A_C_5a7ef9db 0xd4 -#define A_C_00100000 0xd5 -#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ -#define A_GPR_COND 0xd7 /* CCR, condition register */ -#define A_GPR_NOISE0 0xd8 /* noise source */ -#define A_GPR_NOISE1 0xd9 /* noise source */ -#define A_GPR_IRQ 0xda /* IRQ register */ -#define A_GPR_DBAC 0xdb /* TRAM Delay Base Address Counter - internal */ -#define A_GPR_DBACE 0xde /* TRAM Delay Base Address Counter - external */ - -/* definitions for debug register */ -#define EMU10K1_DBG_ZC 0x80000000 /* zero tram counter */ -#define EMU10K1_DBG_SATURATION_OCCURED 0x02000000 /* saturation control */ -#define EMU10K1_DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */ -#define EMU10K1_DBG_SINGLE_STEP 0x00008000 /* single step mode */ -#define EMU10K1_DBG_STEP 0x00004000 /* start single step */ -#define EMU10K1_DBG_CONDITION_CODE 0x00003e00 /* condition code */ -#define EMU10K1_DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */ - -/* tank memory address line */ -#ifndef __KERNEL__ -#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */ -#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */ -#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */ -#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */ -#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */ -#endif - -typedef struct { - unsigned int internal_tram_size; /* in samples */ - unsigned int external_tram_size; /* in samples */ - char fxbus_names[16][32]; /* names of FXBUSes */ - char extin_names[16][32]; /* names of external inputs */ - char extout_names[32][32]; /* names of external outputs */ - unsigned int gpr_controls; /* count of GPR controls */ -} emu10k1_fx8010_info_t; - -#define EMU10K1_GPR_TRANSLATION_NONE 0 -#define EMU10K1_GPR_TRANSLATION_TABLE100 1 -#define EMU10K1_GPR_TRANSLATION_BASS 2 -#define EMU10K1_GPR_TRANSLATION_TREBLE 3 -#define EMU10K1_GPR_TRANSLATION_ONOFF 4 - -enum emu10k1_ctl_elem_iface { - EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */ - EMU10K1_CTL_ELEM_IFACE_PCM = 3, /* PCM device */ -}; - -typedef struct { - unsigned int pad; /* don't use */ - int iface; /* interface identifier */ - unsigned int device; /* device/client number */ - unsigned int subdevice; /* subdevice (substream) number */ - unsigned char name[44]; /* ASCII name of item */ - unsigned int index; /* index of item */ -} emu10k1_ctl_elem_id_t; - -typedef struct { - emu10k1_ctl_elem_id_t id; /* full control ID definition */ - unsigned int vcount; /* visible count */ - unsigned int count; /* count of GPR (1..16) */ - unsigned short gpr[32]; /* GPR number(s) */ - unsigned int value[32]; /* initial values */ - unsigned int min; /* minimum range */ - unsigned int max; /* maximum range */ - unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ - unsigned int *tlv; -} emu10k1_fx8010_control_gpr_t; - -typedef struct { - char name[128]; - - unsigned long gpr_valid[0x200/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ - uint32_t *gpr_map; /* initializers */ - - unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */ - emu10k1_fx8010_control_gpr_t *gpr_add_controls; /* GPR controls to add/replace */ - - unsigned int gpr_del_control_count; /* count of GPR controls to remove */ - emu10k1_ctl_elem_id_t *gpr_del_controls; /* IDs of GPR controls to remove */ - - unsigned int gpr_list_control_count; /* count of GPR controls to list */ - unsigned int gpr_list_control_total; /* total count of GPR controls */ - emu10k1_fx8010_control_gpr_t *gpr_list_controls; /* listed GPR controls */ - - unsigned long tram_valid[0x100/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */ - uint32_t *tram_data_map; /* data initializers */ - uint32_t *tram_addr_map; /* map initializers */ - - unsigned long code_valid[1024/(sizeof(unsigned long)*8)]; /* bitmask of valid instructions */ - uint32_t *code; /* one instruction - 64 bits */ -} emu10k1_fx8010_code_t; - -typedef struct { - unsigned int address; /* 31.bit == 1 -> external TRAM */ - unsigned int size; /* size in samples (4 bytes) */ - unsigned int *samples; /* pointer to samples (20-bit) */ - /* NULL->clear memory */ -} emu10k1_fx8010_tram_t; - -typedef struct { - unsigned int substream; /* substream number */ - unsigned int res1; /* reserved */ - unsigned int channels; /* 16-bit channels count, zero = remove this substream */ - unsigned int tram_start; /* ring buffer position in TRAM (in samples) */ - unsigned int buffer_size; /* count of buffered samples */ - unsigned short gpr_size; /* GPR containing size of ringbuffer in samples (host) */ - unsigned short gpr_ptr; /* GPR containing current pointer in the ring buffer (host = reset, FX8010) */ - unsigned short gpr_count; /* GPR containing count of samples between two interrupts (host) */ - unsigned short gpr_tmpcount; /* GPR containing current count of samples to interrupt (host = set, FX8010) */ - unsigned short gpr_trigger; /* GPR containing trigger (activate) information (host) */ - unsigned short gpr_running; /* GPR containing info if PCM is running (FX8010) */ - unsigned char pad; /* reserved */ - unsigned char etram[32]; /* external TRAM address & data (one per channel) */ - unsigned int res2; /* reserved */ -} emu10k1_fx8010_pcm_t; - -#define SNDRV_EMU10K1_IOCTL_INFO _IOR ('H', 0x10, emu10k1_fx8010_info_t) -#define SNDRV_EMU10K1_IOCTL_CODE_POKE _IOW ('H', 0x11, emu10k1_fx8010_code_t) -#define SNDRV_EMU10K1_IOCTL_CODE_PEEK _IOWR('H', 0x12, emu10k1_fx8010_code_t) -#define SNDRV_EMU10K1_IOCTL_TRAM_SETUP _IOW ('H', 0x20, int) -#define SNDRV_EMU10K1_IOCTL_TRAM_POKE _IOW ('H', 0x21, emu10k1_fx8010_tram_t) -#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK _IOWR('H', 0x22, emu10k1_fx8010_tram_t) -#define SNDRV_EMU10K1_IOCTL_PCM_POKE _IOW ('H', 0x30, emu10k1_fx8010_pcm_t) -#define SNDRV_EMU10K1_IOCTL_PCM_PEEK _IOWR('H', 0x31, emu10k1_fx8010_pcm_t) -#define SNDRV_EMU10K1_IOCTL_PVERSION _IOR ('H', 0x40, int) -#define SNDRV_EMU10K1_IOCTL_STOP _IO ('H', 0x80) -#define SNDRV_EMU10K1_IOCTL_CONTINUE _IO ('H', 0x81) -#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82) -#define SNDRV_EMU10K1_IOCTL_SINGLE_STEP _IOW ('H', 0x83, int) -#define SNDRV_EMU10K1_IOCTL_DBG_READ _IOR ('H', 0x84, int) - -#endif /* __SOUND_EMU10K1_H */ diff --git a/raylib/external/alsa/sound/hdsp.h b/raylib/external/alsa/sound/hdsp.h deleted file mode 100644 index 5adaf7b..0000000 --- a/raylib/external/alsa/sound/hdsp.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef __SOUND_HDSP_H -#define __SOUND_HDSP_H - -/* - * Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#define HDSP_MATRIX_MIXER_SIZE 2048 - -typedef enum { - Digiface, - Multiface, - H9652, - H9632, - RPM, - Undefined, -} HDSP_IO_Type; - -typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t; - -struct _snd_hdsp_peak_rms { - uint32_t input_peaks[26]; - uint32_t playback_peaks[26]; - uint32_t output_peaks[28]; - uint64_t input_rms[26]; - uint64_t playback_rms[26]; - /* These are only used for H96xx cards */ - uint64_t output_rms[26]; -}; - -#define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t) - -typedef struct _snd_hdsp_config_info hdsp_config_info_t; - -struct _snd_hdsp_config_info { - unsigned char pref_sync_ref; - unsigned char wordclock_sync_check; - unsigned char spdif_sync_check; - unsigned char adatsync_sync_check; - unsigned char adat_sync_check[3]; - unsigned char spdif_in; - unsigned char spdif_out; - unsigned char spdif_professional; - unsigned char spdif_emphasis; - unsigned char spdif_nonaudio; - unsigned int spdif_sample_rate; - unsigned int system_sample_rate; - unsigned int autosync_sample_rate; - unsigned char system_clock_mode; - unsigned char clock_source; - unsigned char autosync_ref; - unsigned char line_out; - unsigned char passthru; - unsigned char da_gain; - unsigned char ad_gain; - unsigned char phone_gain; - unsigned char xlr_breakout_cable; - unsigned char analog_extension_board; -}; - -#define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdsp_config_info_t) - -typedef struct _snd_hdsp_firmware hdsp_firmware_t; - -struct _snd_hdsp_firmware { - void *firmware_data; /* 24413 x 4 bytes */ -}; - -#define SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE _IOW('H', 0x42, hdsp_firmware_t) - -typedef struct _snd_hdsp_version hdsp_version_t; - -struct _snd_hdsp_version { - HDSP_IO_Type io_type; - unsigned short firmware_rev; -}; - -#define SNDRV_HDSP_IOCTL_GET_VERSION _IOR('H', 0x43, hdsp_version_t) - -typedef struct _snd_hdsp_mixer hdsp_mixer_t; - -struct _snd_hdsp_mixer { - unsigned short matrix[HDSP_MATRIX_MIXER_SIZE]; -}; - -#define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, hdsp_mixer_t) - -typedef struct _snd_hdsp_9632_aeb hdsp_9632_aeb_t; - -struct _snd_hdsp_9632_aeb { - int aebi; - int aebo; -}; - -#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, hdsp_9632_aeb_t) - -#endif /* __SOUND_HDSP_H */ diff --git a/raylib/external/alsa/sound/hdspm.h b/raylib/external/alsa/sound/hdspm.h deleted file mode 100644 index fe9c5f6..0000000 --- a/raylib/external/alsa/sound/hdspm.h +++ /dev/null @@ -1,229 +0,0 @@ -#ifndef __SOUND_HDSPM_H -#define __SOUND_HDSPM_H -/* - * Copyright (C) 2003 Winfried Ritsch (IEM) - * based on hdsp.h from Thomas Charbonnel (thomas@undata.org) - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */ -#define HDSPM_MAX_CHANNELS 64 - -enum hdspm_io_type { - MADI, - MADIface, - AIO, - AES32, - RayDAT -}; - -enum hdspm_speed { - ss, - ds, - qs -}; - -/* -------------------- IOCTL Peak/RMS Meters -------------------- */ - -struct hdspm_peak_rms { - uint32_t input_peaks[64]; - uint32_t playback_peaks[64]; - uint32_t output_peaks[64]; - - uint64_t input_rms[64]; - uint64_t playback_rms[64]; - uint64_t output_rms[64]; - - uint8_t speed; /* enum {ss, ds, qs} */ - int status2; -}; - -#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS \ - _IOR('H', 0x42, struct hdspm_peak_rms) - -/* ------------ CONFIG block IOCTL ---------------------- */ - -struct hdspm_config { - unsigned char pref_sync_ref; - unsigned char wordclock_sync_check; - unsigned char madi_sync_check; - unsigned int system_sample_rate; - unsigned int autosync_sample_rate; - unsigned char system_clock_mode; - unsigned char clock_source; - unsigned char autosync_ref; - unsigned char line_out; - unsigned int passthru; - unsigned int analog_out; -}; - -#define SNDRV_HDSPM_IOCTL_GET_CONFIG \ - _IOR('H', 0x41, struct hdspm_config) - -/** - * If there's a TCO (TimeCode Option) board installed, - * there are further options and status data available. - * The hdspm_ltc structure contains the current SMPTE - * timecode and some status information and can be - * obtained via SNDRV_HDSPM_IOCTL_GET_LTC or in the - * hdspm_status struct. - **/ - -enum hdspm_ltc_format { - format_invalid, - fps_24, - fps_25, - fps_2997, - fps_30 -}; - -enum hdspm_ltc_frame { - frame_invalid, - drop_frame, - full_frame -}; - -enum hdspm_ltc_input_format { - ntsc, - pal, - no_video -}; - -struct hdspm_ltc { - unsigned int ltc; - - enum hdspm_ltc_format format; - enum hdspm_ltc_frame frame; - enum hdspm_ltc_input_format input_format; -}; - -#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc) - -/** - * The status data reflects the device's current state - * as determined by the card's configuration and - * connection status. - **/ - -enum hdspm_sync { - hdspm_sync_no_lock = 0, - hdspm_sync_lock = 1, - hdspm_sync_sync = 2 -}; - -enum hdspm_madi_input { - hdspm_input_optical = 0, - hdspm_input_coax = 1 -}; - -enum hdspm_madi_channel_format { - hdspm_format_ch_64 = 0, - hdspm_format_ch_56 = 1 -}; - -enum hdspm_madi_frame_format { - hdspm_frame_48 = 0, - hdspm_frame_96 = 1 -}; - -enum hdspm_syncsource { - syncsource_wc = 0, - syncsource_madi = 1, - syncsource_tco = 2, - syncsource_sync = 3, - syncsource_none = 4 -}; - -struct hdspm_status { - uint8_t card_type; /* enum hdspm_io_type */ - enum hdspm_syncsource autosync_source; - - uint64_t card_clock; - uint32_t master_period; - - union { - struct { - uint8_t sync_wc; /* enum hdspm_sync */ - uint8_t sync_madi; /* enum hdspm_sync */ - uint8_t sync_tco; /* enum hdspm_sync */ - uint8_t sync_in; /* enum hdspm_sync */ - uint8_t madi_input; /* enum hdspm_madi_input */ - uint8_t channel_format; /* enum hdspm_madi_channel_format */ - uint8_t frame_format; /* enum hdspm_madi_frame_format */ - } madi; - } card_specific; -}; - -#define SNDRV_HDSPM_IOCTL_GET_STATUS \ - _IOR('H', 0x47, struct hdspm_status) - -/** - * Get information about the card and its add-ons. - **/ - -#define HDSPM_ADDON_TCO 1 - -struct hdspm_version { - uint8_t card_type; /* enum hdspm_io_type */ - char cardname[20]; - unsigned int serial; - unsigned short firmware_rev; - int addons; -}; - -#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x48, struct hdspm_version) - -/* ------------- get Matrix Mixer IOCTL --------------- */ - -/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = - * 32768 Bytes - */ - -/* organisation is 64 channelfader in a continous memory block */ -/* equivalent to hardware definition, maybe for future feature of mmap of - * them - */ -/* each of 64 outputs has 64 infader and 64 outfader: - Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */ - -#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS - -struct hdspm_channelfader { - unsigned int in[HDSPM_MIXER_CHANNELS]; - unsigned int pb[HDSPM_MIXER_CHANNELS]; -}; - -struct hdspm_mixer { - struct hdspm_channelfader ch[HDSPM_MIXER_CHANNELS]; -}; - -struct hdspm_mixer_ioctl { - struct hdspm_mixer *mixer; -}; - -/* use indirect access due to the limit of ioctl bit size */ -#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdspm_mixer_ioctl) - -/* typedefs for compatibility to user-space */ -typedef struct hdspm_peak_rms hdspm_peak_rms_t; -typedef struct hdspm_config_info hdspm_config_info_t; -typedef struct hdspm_version hdspm_version_t; -typedef struct hdspm_channelfader snd_hdspm_channelfader_t; -typedef struct hdspm_mixer hdspm_mixer_t; - - -#endif diff --git a/raylib/external/alsa/sound/sb16_csp.h b/raylib/external/alsa/sound/sb16_csp.h deleted file mode 100644 index 78817b4..0000000 --- a/raylib/external/alsa/sound/sb16_csp.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef __SOUND_SB16_CSP_H -#define __SOUND_SB16_CSP_H - -/* - * Copyright (c) 1999 by Uros Bizjak - * Takashi Iwai - * - * SB16ASP/AWE32 CSP control - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* CSP modes */ -#define SNDRV_SB_CSP_MODE_NONE 0x00 -#define SNDRV_SB_CSP_MODE_DSP_READ 0x01 /* Record from DSP */ -#define SNDRV_SB_CSP_MODE_DSP_WRITE 0x02 /* Play to DSP */ -#define SNDRV_SB_CSP_MODE_QSOUND 0x04 /* QSound */ - -/* CSP load flags */ -#define SNDRV_SB_CSP_LOAD_FROMUSER 0x01 -#define SNDRV_SB_CSP_LOAD_INITBLOCK 0x02 - -/* CSP sample width */ -#define SNDRV_SB_CSP_SAMPLE_8BIT 0x01 -#define SNDRV_SB_CSP_SAMPLE_16BIT 0x02 - -/* CSP channels */ -#define SNDRV_SB_CSP_MONO 0x01 -#define SNDRV_SB_CSP_STEREO 0x02 - -/* CSP rates */ -#define SNDRV_SB_CSP_RATE_8000 0x01 -#define SNDRV_SB_CSP_RATE_11025 0x02 -#define SNDRV_SB_CSP_RATE_22050 0x04 -#define SNDRV_SB_CSP_RATE_44100 0x08 -#define SNDRV_SB_CSP_RATE_ALL 0x0f - -/* CSP running state */ -#define SNDRV_SB_CSP_ST_IDLE 0x00 -#define SNDRV_SB_CSP_ST_LOADED 0x01 -#define SNDRV_SB_CSP_ST_RUNNING 0x02 -#define SNDRV_SB_CSP_ST_PAUSED 0x04 -#define SNDRV_SB_CSP_ST_AUTO 0x08 -#define SNDRV_SB_CSP_ST_QSOUND 0x10 - -/* maximum QSound value (180 degrees right) */ -#define SNDRV_SB_CSP_QSOUND_MAX_RIGHT 0x20 - -/* maximum microcode RIFF file size */ -#define SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE 0x3000 - -/* microcode header */ -typedef struct snd_sb_csp_mc_header { - char codec_name[16]; /* id name of codec */ - unsigned short func_req; /* requested function */ -} snd_sb_csp_mc_header_t; - -/* microcode to be loaded */ -typedef struct snd_sb_csp_microcode { - snd_sb_csp_mc_header_t info; - unsigned char data[SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE]; -} snd_sb_csp_microcode_t; - -/* start CSP with sample_width in mono/stereo */ -typedef struct snd_sb_csp_start { - int sample_width; /* sample width, look above */ - int channels; /* channels, look above */ -} snd_sb_csp_start_t; - -/* CSP information */ -typedef struct snd_sb_csp_info { - char codec_name[16]; /* id name of codec */ - unsigned short func_nr; /* function number */ - unsigned int acc_format; /* accepted PCM formats */ - unsigned short acc_channels; /* accepted channels */ - unsigned short acc_width; /* accepted sample width */ - unsigned short acc_rates; /* accepted sample rates */ - unsigned short csp_mode; /* CSP mode, see above */ - unsigned short run_channels; /* current channels */ - unsigned short run_width; /* current sample width */ - unsigned short version; /* version id: 0x10 - 0x1f */ - unsigned short state; /* state bits */ -} snd_sb_csp_info_t; - -/* HWDEP controls */ -/* get CSP information */ -#define SNDRV_SB_CSP_IOCTL_INFO _IOR('H', 0x10, snd_sb_csp_info_t) -/* load microcode to CSP */ -#define SNDRV_SB_CSP_IOCTL_LOAD_CODE _IOW('H', 0x11, snd_sb_csp_microcode_t) -/* unload microcode from CSP */ -#define SNDRV_SB_CSP_IOCTL_UNLOAD_CODE _IO('H', 0x12) -/* start CSP */ -#define SNDRV_SB_CSP_IOCTL_START _IOW('H', 0x13, snd_sb_csp_start_t) -/* stop CSP */ -#define SNDRV_SB_CSP_IOCTL_STOP _IO('H', 0x14) -/* pause CSP and DMA transfer */ -#define SNDRV_SB_CSP_IOCTL_PAUSE _IO('H', 0x15) -/* restart CSP and DMA transfer */ -#define SNDRV_SB_CSP_IOCTL_RESTART _IO('H', 0x16) - - -#endif /* __SOUND_SB16_CSP */ diff --git a/raylib/external/alsa/sound/sscape_ioctl.h b/raylib/external/alsa/sound/sscape_ioctl.h deleted file mode 100644 index c6653eb..0000000 --- a/raylib/external/alsa/sound/sscape_ioctl.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SSCAPE_IOCTL_H -#define SSCAPE_IOCTL_H - - -struct sscape_bootblock -{ - unsigned char code[256]; - unsigned version; -}; - -#define SSCAPE_MICROCODE_SIZE 65536 - -struct sscape_microcode -{ - unsigned char *code; -}; - -#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) -#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode) - -#endif diff --git a/raylib/external/alsa/sound/tlv.h b/raylib/external/alsa/sound/tlv.h deleted file mode 100644 index b4df440..0000000 --- a/raylib/external/alsa/sound/tlv.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - */ - -#ifndef __UAPI_SOUND_TLV_H -#define __UAPI_SOUND_TLV_H - -#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */ -#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */ -#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */ -#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */ -#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */ -#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */ - -/* - * channel-mapping TLV items - * TLV length must match with num_channels - */ -#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */ -#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */ -#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */ - -/* - * TLV structure is right behind the struct snd_ctl_tlv: - * unsigned int type - see SNDRV_CTL_TLVT_* - * unsigned int length - * .... data aligned to sizeof(unsigned int), use - * block_length = (length + (sizeof(unsigned int) - 1)) & - * ~(sizeof(unsigned int) - 1)) .... - */ -#define SNDRV_CTL_TLVD_ITEM(type, ...) \ - (type), SNDRV_CTL_TLVD_LENGTH(__VA_ARGS__), __VA_ARGS__ -#define SNDRV_CTL_TLVD_LENGTH(...) \ - ((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ })) - -#define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__) -#define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_CONTAINER_ITEM(__VA_ARGS__) \ - } - -#define SNDRV_CTL_TLVD_DB_SCALE_MASK 0xffff -#define SNDRV_CTL_TLVD_DB_SCALE_MUTE 0x10000 -#define SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_SCALE, \ - (min), \ - ((step) & SNDRV_CTL_TLVD_DB_SCALE_MASK) | \ - ((mute) ? SNDRV_CTL_TLVD_DB_SCALE_MUTE : 0)) -#define SNDRV_CTL_TLVD_DECLARE_DB_SCALE(name, min, step, mute) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ - } - -/* dB scale specified with min/max values instead of step */ -#define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB)) -#define SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX_MUTE, (min_dB), (max_dB)) -#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(name, min_dB, max_dB) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ - } -#define SNDRV_CTL_TLVD_DECLARE_DB_MINMAX_MUTE(name, min_dB, max_dB) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ - } - -/* linear volume between min_dB and max_dB (.01dB unit) */ -#define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB)) -#define SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(name, min_dB, max_dB) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ - } - -/* dB range container: - * Items in dB range container must be ordered by their values and by their - * dB values. This implies that larger values must correspond with larger - * dB values (which is also required for all other mixer controls). - */ -/* Each item is: */ -#define SNDRV_CTL_TLVD_DB_RANGE_ITEM(...) \ - SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_RANGE, __VA_ARGS__) -#define SNDRV_CTL_TLVD_DECLARE_DB_RANGE(name, ...) \ - unsigned int name[] = { \ - SNDRV_CTL_TLVD_DB_RANGE_ITEM(__VA_ARGS__) \ - } - -#define SNDRV_CTL_TLVD_DB_GAIN_MUTE -9999999 - -#endif diff --git a/raylib/external/alsa/sound/type_compat.h b/raylib/external/alsa/sound/type_compat.h deleted file mode 100644 index e973ff3..0000000 --- a/raylib/external/alsa/sound/type_compat.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __TYPE_COMPAT_H -#define __TYPE_COMPAT_H - -#ifndef DOC_HIDDEN -#include -typedef uint8_t __u8; -typedef uint16_t __u16; -typedef uint32_t __u32; -typedef int8_t __s8; -typedef int16_t __s16; -typedef int32_t __s32; - -#include -#include -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define __cpu_to_le32(x) (x) -#define __cpu_to_be32(x) bswap_32(x) -#define __cpu_to_le16(x) (x) -#define __cpu_to_be16(x) bswap_16(x) -#else -#define __cpu_to_le32(x) bswap_32(x) -#define __cpu_to_be32(x) (x) -#define __cpu_to_le16(x) bswap_16(x) -#define __cpu_to_be16(x) (x) -#endif - -#define __le32_to_cpu __cpu_to_le32 -#define __be32_to_cpu __cpu_to_be32 -#define __le16_to_cpu __cpu_to_le16 -#define __be16_to_cpu __cpu_to_be16 - -#define __le64 __u64 -#define __le32 __u32 -#define __le16 __u16 -#define __le8 __u8 -#define __be64 __u64 -#define __be32 __u32 -#define __be16 __u16 -#define __be8 __u8 -#endif /* DOC_HIDDEN */ - -#endif /* __TYPE_COMPAT_H */ diff --git a/raylib/external/alsa/timer.h b/raylib/external/alsa/timer.h deleted file mode 100644 index 32d9b89..0000000 --- a/raylib/external/alsa/timer.h +++ /dev/null @@ -1,259 +0,0 @@ -/** - * \file include/timer.h - * \brief Application interface library for the ALSA driver - * \author Jaroslav Kysela - * \author Abramo Bagnara - * \author Takashi Iwai - * \date 1998-2001 - * - * Application interface library for the ALSA driver - */ -/* - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __ALSA_TIMER_H -#define __ALSA_TIMER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup Timer Timer Interface - * Timer Interface. See \ref timer page for more details. - * \{ - */ - -/** dlsym version for interface entry callback */ -#define SND_TIMER_DLSYM_VERSION _dlsym_timer_001 -/** dlsym version for interface entry callback */ -#define SND_TIMER_QUERY_DLSYM_VERSION _dlsym_timer_query_001 - -/** timer identification structure */ -typedef struct _snd_timer_id snd_timer_id_t; -/** timer global info structure */ -typedef struct _snd_timer_ginfo snd_timer_ginfo_t; -/** timer global params structure */ -typedef struct _snd_timer_gparams snd_timer_gparams_t; -/** timer global status structure */ -typedef struct _snd_timer_gstatus snd_timer_gstatus_t; -/** timer info structure */ -typedef struct _snd_timer_info snd_timer_info_t; -/** timer params structure */ -typedef struct _snd_timer_params snd_timer_params_t; -/** timer status structure */ -typedef struct _snd_timer_status snd_timer_status_t; -/** timer master class */ -typedef enum _snd_timer_class { - SND_TIMER_CLASS_NONE = -1, /**< invalid */ - SND_TIMER_CLASS_SLAVE = 0, /**< slave timer */ - SND_TIMER_CLASS_GLOBAL, /**< global timer */ - SND_TIMER_CLASS_CARD, /**< card timer */ - SND_TIMER_CLASS_PCM, /**< PCM timer */ - SND_TIMER_CLASS_LAST = SND_TIMER_CLASS_PCM /**< last timer */ -} snd_timer_class_t; - -/** timer slave class */ -typedef enum _snd_timer_slave_class { - SND_TIMER_SCLASS_NONE = 0, /**< none */ - SND_TIMER_SCLASS_APPLICATION, /**< for internal use */ - SND_TIMER_SCLASS_SEQUENCER, /**< sequencer timer */ - SND_TIMER_SCLASS_OSS_SEQUENCER, /**< OSS sequencer timer */ - SND_TIMER_SCLASS_LAST = SND_TIMER_SCLASS_OSS_SEQUENCER /**< last slave timer */ -} snd_timer_slave_class_t; - -/** timer read event identification */ -typedef enum _snd_timer_event { - SND_TIMER_EVENT_RESOLUTION = 0, /* val = resolution in ns */ - SND_TIMER_EVENT_TICK, /* val = ticks */ - SND_TIMER_EVENT_START, /* val = resolution in ns */ - SND_TIMER_EVENT_STOP, /* val = 0 */ - SND_TIMER_EVENT_CONTINUE, /* val = resolution in ns */ - SND_TIMER_EVENT_PAUSE, /* val = 0 */ - SND_TIMER_EVENT_EARLY, /* val = 0 */ - SND_TIMER_EVENT_SUSPEND, /* val = 0 */ - SND_TIMER_EVENT_RESUME, /* val = resolution in ns */ - /* master timer events for slave timer instances */ - SND_TIMER_EVENT_MSTART = SND_TIMER_EVENT_START + 10, - SND_TIMER_EVENT_MSTOP = SND_TIMER_EVENT_STOP + 10, - SND_TIMER_EVENT_MCONTINUE = SND_TIMER_EVENT_CONTINUE + 10, - SND_TIMER_EVENT_MPAUSE = SND_TIMER_EVENT_PAUSE + 10, - SND_TIMER_EVENT_MSUSPEND = SND_TIMER_EVENT_SUSPEND + 10, - SND_TIMER_EVENT_MRESUME = SND_TIMER_EVENT_RESUME + 10 -} snd_timer_event_t; - -/** timer read structure */ -typedef struct _snd_timer_read { - unsigned int resolution; /**< tick resolution in nanoseconds */ - unsigned int ticks; /**< count of happened ticks */ -} snd_timer_read_t; - -/** timer tstamp + event read structure */ -typedef struct _snd_timer_tread { - snd_timer_event_t event; /**< Timer event */ - snd_htimestamp_t tstamp; /**< Time stamp of each event */ - unsigned int val; /**< Event value */ -} snd_timer_tread_t; - -/** global timer - system */ -#define SND_TIMER_GLOBAL_SYSTEM 0 -/** global timer - RTC */ -#define SND_TIMER_GLOBAL_RTC 1 /* Obsoleted, due to enough legacy. */ -/** global timer - HPET */ -#define SND_TIMER_GLOBAL_HPET 2 -/** global timer - HRTIMER */ -#define SND_TIMER_GLOBAL_HRTIMER 3 - -/** timer open mode flag - non-blocking behaviour */ -#define SND_TIMER_OPEN_NONBLOCK (1<<0) -/** use timestamps and event notification - enhanced read */ -#define SND_TIMER_OPEN_TREAD (1<<1) - -/** timer handle type */ -typedef enum _snd_timer_type { - /** Kernel level HwDep */ - SND_TIMER_TYPE_HW = 0, - /** Shared memory client timer (not yet implemented) */ - SND_TIMER_TYPE_SHM, - /** INET client timer (not yet implemented) */ - SND_TIMER_TYPE_INET -} snd_timer_type_t; - -/** timer query handle */ -typedef struct _snd_timer_query snd_timer_query_t; -/** timer handle */ -typedef struct _snd_timer snd_timer_t; - - -int snd_timer_query_open(snd_timer_query_t **handle, const char *name, int mode); -int snd_timer_query_open_lconf(snd_timer_query_t **handle, const char *name, int mode, snd_config_t *lconf); -int snd_timer_query_close(snd_timer_query_t *handle); -int snd_timer_query_next_device(snd_timer_query_t *handle, snd_timer_id_t *tid); -int snd_timer_query_info(snd_timer_query_t *handle, snd_timer_ginfo_t *info); -int snd_timer_query_params(snd_timer_query_t *handle, snd_timer_gparams_t *params); -int snd_timer_query_status(snd_timer_query_t *handle, snd_timer_gstatus_t *status); - -int snd_timer_open(snd_timer_t **handle, const char *name, int mode); -int snd_timer_open_lconf(snd_timer_t **handle, const char *name, int mode, snd_config_t *lconf); -int snd_timer_close(snd_timer_t *handle); -int snd_async_add_timer_handler(snd_async_handler_t **handler, snd_timer_t *timer, - snd_async_callback_t callback, void *private_data); -snd_timer_t *snd_async_handler_get_timer(snd_async_handler_t *handler); -int snd_timer_poll_descriptors_count(snd_timer_t *handle); -int snd_timer_poll_descriptors(snd_timer_t *handle, struct pollfd *pfds, unsigned int space); -int snd_timer_poll_descriptors_revents(snd_timer_t *timer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -int snd_timer_info(snd_timer_t *handle, snd_timer_info_t *timer); -int snd_timer_params(snd_timer_t *handle, snd_timer_params_t *params); -int snd_timer_status(snd_timer_t *handle, snd_timer_status_t *status); -int snd_timer_start(snd_timer_t *handle); -int snd_timer_stop(snd_timer_t *handle); -int snd_timer_continue(snd_timer_t *handle); -ssize_t snd_timer_read(snd_timer_t *handle, void *buffer, size_t size); - -size_t snd_timer_id_sizeof(void); -/** allocate #snd_timer_id_t container on stack */ -#define snd_timer_id_alloca(ptr) __snd_alloca(ptr, snd_timer_id) -int snd_timer_id_malloc(snd_timer_id_t **ptr); -void snd_timer_id_free(snd_timer_id_t *obj); -void snd_timer_id_copy(snd_timer_id_t *dst, const snd_timer_id_t *src); - -void snd_timer_id_set_class(snd_timer_id_t *id, int dev_class); -int snd_timer_id_get_class(snd_timer_id_t *id); -void snd_timer_id_set_sclass(snd_timer_id_t *id, int dev_sclass); -int snd_timer_id_get_sclass(snd_timer_id_t *id); -void snd_timer_id_set_card(snd_timer_id_t *id, int card); -int snd_timer_id_get_card(snd_timer_id_t *id); -void snd_timer_id_set_device(snd_timer_id_t *id, int device); -int snd_timer_id_get_device(snd_timer_id_t *id); -void snd_timer_id_set_subdevice(snd_timer_id_t *id, int subdevice); -int snd_timer_id_get_subdevice(snd_timer_id_t *id); - -size_t snd_timer_ginfo_sizeof(void); -/** allocate #snd_timer_ginfo_t container on stack */ -#define snd_timer_ginfo_alloca(ptr) __snd_alloca(ptr, snd_timer_ginfo) -int snd_timer_ginfo_malloc(snd_timer_ginfo_t **ptr); -void snd_timer_ginfo_free(snd_timer_ginfo_t *obj); -void snd_timer_ginfo_copy(snd_timer_ginfo_t *dst, const snd_timer_ginfo_t *src); - -int snd_timer_ginfo_set_tid(snd_timer_ginfo_t *obj, snd_timer_id_t *tid); -snd_timer_id_t *snd_timer_ginfo_get_tid(snd_timer_ginfo_t *obj); -unsigned int snd_timer_ginfo_get_flags(snd_timer_ginfo_t *obj); -int snd_timer_ginfo_get_card(snd_timer_ginfo_t *obj); -char *snd_timer_ginfo_get_id(snd_timer_ginfo_t *obj); -char *snd_timer_ginfo_get_name(snd_timer_ginfo_t *obj); -unsigned long snd_timer_ginfo_get_resolution(snd_timer_ginfo_t *obj); -unsigned long snd_timer_ginfo_get_resolution_min(snd_timer_ginfo_t *obj); -unsigned long snd_timer_ginfo_get_resolution_max(snd_timer_ginfo_t *obj); -unsigned int snd_timer_ginfo_get_clients(snd_timer_ginfo_t *obj); - -size_t snd_timer_info_sizeof(void); -/** allocate #snd_timer_info_t container on stack */ -#define snd_timer_info_alloca(ptr) __snd_alloca(ptr, snd_timer_info) -int snd_timer_info_malloc(snd_timer_info_t **ptr); -void snd_timer_info_free(snd_timer_info_t *obj); -void snd_timer_info_copy(snd_timer_info_t *dst, const snd_timer_info_t *src); - -int snd_timer_info_is_slave(snd_timer_info_t * info); -int snd_timer_info_get_card(snd_timer_info_t * info); -const char *snd_timer_info_get_id(snd_timer_info_t * info); -const char *snd_timer_info_get_name(snd_timer_info_t * info); -long snd_timer_info_get_resolution(snd_timer_info_t * info); - -size_t snd_timer_params_sizeof(void); -/** allocate #snd_timer_params_t container on stack */ -#define snd_timer_params_alloca(ptr) __snd_alloca(ptr, snd_timer_params) -int snd_timer_params_malloc(snd_timer_params_t **ptr); -void snd_timer_params_free(snd_timer_params_t *obj); -void snd_timer_params_copy(snd_timer_params_t *dst, const snd_timer_params_t *src); - -int snd_timer_params_set_auto_start(snd_timer_params_t * params, int auto_start); -int snd_timer_params_get_auto_start(snd_timer_params_t * params); -int snd_timer_params_set_exclusive(snd_timer_params_t * params, int exclusive); -int snd_timer_params_get_exclusive(snd_timer_params_t * params); -int snd_timer_params_set_early_event(snd_timer_params_t * params, int early_event); -int snd_timer_params_get_early_event(snd_timer_params_t * params); -void snd_timer_params_set_ticks(snd_timer_params_t * params, long ticks); -long snd_timer_params_get_ticks(snd_timer_params_t * params); -void snd_timer_params_set_queue_size(snd_timer_params_t * params, long queue_size); -long snd_timer_params_get_queue_size(snd_timer_params_t * params); -void snd_timer_params_set_filter(snd_timer_params_t * params, unsigned int filter); -unsigned int snd_timer_params_get_filter(snd_timer_params_t * params); - -size_t snd_timer_status_sizeof(void); -/** allocate #snd_timer_status_t container on stack */ -#define snd_timer_status_alloca(ptr) __snd_alloca(ptr, snd_timer_status) -int snd_timer_status_malloc(snd_timer_status_t **ptr); -void snd_timer_status_free(snd_timer_status_t *obj); -void snd_timer_status_copy(snd_timer_status_t *dst, const snd_timer_status_t *src); - -snd_htimestamp_t snd_timer_status_get_timestamp(snd_timer_status_t * status); -long snd_timer_status_get_resolution(snd_timer_status_t * status); -long snd_timer_status_get_lost(snd_timer_status_t * status); -long snd_timer_status_get_overrun(snd_timer_status_t * status); -long snd_timer_status_get_queue(snd_timer_status_t * status); - -/* deprecated functions, for compatibility */ -long snd_timer_info_get_ticks(snd_timer_info_t * info); - -/** \} */ - -#ifdef __cplusplus -} -#endif - -#endif /** __ALSA_TIMER_H */ - diff --git a/raylib/external/alsa/topology.h b/raylib/external/alsa/topology.h deleted file mode 100644 index 42d2376..0000000 --- a/raylib/external/alsa/topology.h +++ /dev/null @@ -1,1115 +0,0 @@ -/* - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2015 Intel Corporation - * - */ - -#ifndef __ALSA_TOPOLOGY_H -#define __ALSA_TOPOLOGY_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup topology Topology Interface - * \{ - */ - -/*! \page topology ALSA Topology Interface - * - * The topology interface allows developers to define DSP topologies in a text - * file format and to convert the text topology to a binary topology - * representation that can be understood by the kernel. The topology core - * currently recognises the following object types :- - * - * * Controls (mixer, enumerated and byte) including TLV data. - * * PCMs (Front End DAI & DAI link) - * * DAPM widgets - * * DAPM graph elements. - * * Physical DAI & DAI links - * * Private data for each object type. - * * Manifest (containing count of each object type) - * - *

Topology File Format

- * - * The topology text format uses the standard ALSA configuration file format to - * describe each topology object type. This allows topology objects to include - * other topology objects as part of their definition. i.e. a TLV data object - * can be shared amongst many control objects that use the same TLV data. - * - * - *

Controls

- * Topology audio controls can belong to three different types :- - * * Mixer control - * * Enumerated control - * * Byte control - * - * Each control type can contain TLV data, private data, operations and also - * belong to widget objects.
- * - *
Control Operations
- * Driver Kcontrol callback info(), get() and put() operations are mapped with - * the CTL ops section in topology configuration files. The ctl ops section can - * assign operations using the standard names (listed below) for the standard - * kcontrol types or use ID numbers (>256) to map to bespoke driver controls.
- * - *
- *
- *	ops."ctl" {
- *		info "volsw"
- *		get "257"
- *		put "257"
- *	}
- *
- * 
- * - * This mapping shows info() using the standard "volsw" info callback whilst - * the get() and put() are mapped to bespoke driver callbacks.
- * - * The Standard operations names for control get(), put() and info calls - * are :- - * * volsw - * * volsw_sx - * * volsw_xr_sx - * * enum - * * bytes - * * enum_value - * * range - * * strobe - * -*
Control Access
- * Controls access can be specified using the "access" section. If no "access" - * section is defined then default RW access flags are set for normal and TLV - * controls. - * - *
- *	access [
- *		read
- *		write
- *		tlv_command
- *	]
- * 
- * - * The standard access flags are as follows :- - * * read - * * write - * * read_write - * * volatile - * * timestamp - * * tlv_read - * * tlv_write - * * tlv_read_write - * * tlv_command - * * inactive - * * lock - * * owner - * * tlv_callback - * * user - * - *
Control TLV Data
- * Controls can also use TLV data to represent dB information. This can be done - * by defining a TLV section and using the TLV section within the control. - * The TLV data for DBScale types are defined as follows :- - * - *
- *	scale {
- *		min "-9000"
- *		step "300"
- *		mute "1"
- *	}
- * 
- * - * Where the meanings and values for min, step and mute are exactly the same - * as defined in driver code. - * - *
Control Channel Mapping
- * Controls can also specify which channels they are mapped with. This is useful - * for userspace as it allows applications to determine the correct control - * channel for Left and Right etc. Channel maps are defined as follows :- - * - *
- *	channel."name" {
- *		reg "0"
- *		shift "0"
- *	}
- * 
- * - * The channel map reg is the register offset for the control, shift is the - * bit shift within the register for the channel and the section name is the - * channel name and can be one of the following :- - * - *
- *  * mono		# mono stream
- *  * fl 		# front left
- *  * fr		# front right
- *  * rl		# rear left
- *  * rr		# rear right
- *  * fc		# front center
- *  * lfe		# LFE
- *  * sl		# side left
- *  * sr		# side right
- *  * rc		# rear center
- *  * flc		# front left center
- *  * frc		# front right center
- *  * rlc		# rear left center
- *  * rrc		# rear right center
- *  * flw		# front left wide
- *  * frw		# front right wide
- *  * flh		# front left high
- *  * fch		# front center high
- *  * frh		# front right high
- *  * tc		# top center
- *  * tfl		# top front left
- *  * tfr		# top front right
- *  * tfc		# top front center
- *  * trl		# top rear left
- *  * trr		# top rear right
- *  * trc		# top rear center
- *  * tflc		# top front left center
- *  * tfrc		# top front right center
- *  * tsl		# top side left
- *  * tsr		# top side right
- *  * llfe		# left LFE
- *  * rlfe		# right LFE
- *  * bc		# bottom center
- *  * blc		# bottom left center
- *  * brc		# bottom right center
- * 
- * - *
Control Private Data
- * Controls can also have private data. This can be done by defining a private - * data section and including the section within the control. The private data - * section is defined as follows :- - * - *
- * SectionData."pdata for EQU1" {
- *	file "/path/to/file"
- *	bytes "0x12,0x34,0x56,0x78"
- *	shorts "0x1122,0x3344,0x5566,0x7788"
- *	words "0xaabbccdd,0x11223344,0x66aa77bb,0xefef1234"
- *	tuples "section id of the vendor tuples"
- * };
- * 
- * The file, bytes, shorts, words and tuples keywords are all mutually - * exclusive as the private data should only be taken from one source. - * The private data can either be read from a separate file or defined in - * the topology file using the bytes, shorts, words or tuples keywords. - * The keyword tuples is to define vendor specific tuples. Please refer to - * section Vendor Tokens and Vendor tuples. - * - * It's easy to use a vendor tuples object to define a C structure instance. - * And a data section can include multiple vendor tuples objects: - * - *
- * SectionData."data element name" {
- *	index "1"	#Index number
- *	tuples [
- *		"id of the 1st vendor tuples section"
- *		"id of the 2nd vendor tuples section"
- *		...
- *	]
- * };
- * 
- * - *
How to define an element with private data
- * An element can refer to a single data section or multiple data - * sections. - * - *
To refer to a single data section:
- *
- * Sectionxxx."element name" {
- *    ...
- *	data "name of data section"		# optional private data
- * }
- * 
- * - *
To refer to multiple data sections:
- *
- * Sectionxxx."element name" {
- *	...
- *	data [						# optional private data
- *		"name of 1st data section"
- *		"name of 2nd data section"
- *		...
- *	]
- * }
- * 
- * And data of these sections will be merged in the same order as they are - * in the list, as the element's private data for kernel. - * - * - * - *
Vendor Tokens
- * A vendor token list is defined as a new section. Each token element is - * a pair of string ID and integer value. And both the ID and value are - * vendor-specific. - * - *
- * SectionVendorTokens."id of the vendor tokens" {
- *	comment "optional comments"
- *	VENDOR_TOKEN_ID1 "1"
- *	VENDOR_TOKEN_ID2 "2"
- *	VENDOR_TOKEN_ID3 "3"
- *	...
- * }
- * 
- * - *
Vendor Tuples
- * Vendor tuples are defined as a new section. It contains a reference to - * a vendor token list and several tuple arrays. - * All arrays share a vendor token list, defined by the tokens keyword. - * Each tuple array is for a specific type, defined by the string following - * the tuples keyword. Supported types are: string, uuid, bool, byte, - * short and word. - * - *
- * SectionVendorTuples."id of the vendor tuples" {
- *	tokens "id of the vendor tokens"
- *
- *	tuples."string" {
- *		VENDOR_TOKEN_ID1 "character string"
- *		...
- *	}
- *
- *	tuples."uuid" {			# 16 characters separated by commas
- *		VENDOR_TOKEN_ID2 "0x01,0x02,...,0x0f"
- *		...
- *	}
- *
- *	tuples."bool" {
- *		VENDOR_TOKEN_ID3 "true/false"
- *		...
- *	}
- *
- *	tuples."byte" {
- *		VENDOR_TOKEN_ID4 "0x11"
- *		VENDOR_TOKEN_ID5 "0x22"
- *		...
- *	}
- *
- *	tuples."short" {
- *		VENDOR_TOKEN_ID6 "0x1122"
- *		VENDOR_TOKEN_ID7 "0x3344"
- *		...
- *	}
- *
- *	tuples."word" {
- *		VENDOR_TOKEN_ID8 "0x11223344"
- *		VENDOR_TOKEN_ID9 "0x55667788"
- *		...
- *	}
- * }
- * 
- * To define multiple vendor tuples of same type, please append some - * characters after the type string ("string", "uuid", "bool", "byte", "short" - * or "word"), to avoid ID duplication in the SectionVendorTuples.
- * The parser will check the first few characters in ID to get the tuple type. - * Here is an example: - *
- * SectionVendorTuples."id of the vendor tuples" {
- *    ...
- *	tuples."word.module0" {
- *		VENDOR_TOKEN_PARAM_ID1 "0x00112233"
- *		VENDOR_TOKEN_PARAM_ID2 "0x44556677"
- *		...
- *	}
- *
- *	tuples."word.module2" {
- *		VENDOR_TOKEN_PARAM_ID1 "0x11223344"
- *		VENDOR_TOKEN_PARAM_ID2 "0x55667788"
- *		...
- *	}
- *	...
- * }
- *
- * 
- * - *
Mixer Controls
- * A mixer control is defined as a new section that can include channel mapping, - * TLV data, callback operations and private data. The mixer section also - * includes a few other config options that are shown here :- - * - *
- * SectionControlMixer."mixer name" {
- *	comment "optional comments"
- *
- *	index "1"			# Index number
- *
- *	channel."name" {		# Channel maps
- *	   ....
- *	}
- *
- *	ops."ctl" {			# Ops callback functions
- *	   ....
- *	}
- *
- *	max "32"			# Max control value
- *	invert "0"			# Whether control values are inverted
- *
- *	tlv "tld_data"			# optional TLV data
- *
- *	data "pdata for mixer1"		# optional private data
- * }
- * 
- * - * The section name is used to define the mixer name. The index number can be - * used to identify topology objects groups(index "0" is common, fit for all - * user cases).This allows driver operations on objects with index number N and - * can be used to add/remove pipelines of objects whilst other objects are - * unaffected. - * - *
Byte Controls
- * A byte control is defined as a new section that can include channel mapping, - * TLV data, callback operations and private data. The bytes section also - * includes a few other config options that are shown here :- - * - *
- * SectionControlBytes."name" {
- *	comment "optional comments"
- *
- *	index "1"			# Index number
- *
- *	channel."name" {		# Channel maps
- *	   ....
- *	}
- *
- *	ops."ctl" {			# Ops callback functions
- *	   ....
- *	}
- *
- *	base "0"			# Register base
- *	num_regs "16"			# Number of registers
- *	mask "0xff"			# Mask
- *	max "255"			# Maximum value
- *
- *	tlv "tld_data"			# optional TLV data
- *
- *	data "pdata for mixer1"		# optional private data
- * }
- * 
- * - *
Enumerated Controls
- * A enumerated control is defined as a new section (like mixer and byte) that - * can include channel mapping, callback operations, private data and - * text strings to represent the enumerated control options.
- * - * The text strings for the enumerated controls are defined in a separate - * section as follows :- - * - *
- * SectionText."name" {
- *
- *		Values [
- *			"value1"
- *			"value2"
-			"value3"
- *		]
- * }
- * 
- * - * All the enumerated text values are listed in the values list.
- * The enumerated control is similar to the other controls and defined as - * follows :- - * - *
- * SectionControlMixer."name" {
- *	comment "optional comments"
- *
- *	index "1"			# Index number
- *
- *	texts "EQU1"			# Enumerated text items
- *
- *	channel."name" {		# Channel maps
- *	   ....
- *	}
- *
- *	ops."ctl" {			# Ops callback functions
- *	   ....
- *	}
- *
- *	data "pdata for mixer1"		# optional private data
- * }
- * 
- * - *

DAPM Graph

- * DAPM graphs can easily be defined using the topology file. The format is - * very similar to the DAPM graph kernel format. :- - * - *
- * SectionGraph."dsp" {
- *	index "1"			# Index number
- *
- *	lines [
- *		"sink1, control, source1"
- *		"sink2, , source2"
- *	]
- * }
- * 
- * - * The lines in the graph are defined as a variable size list of sinks, - * controls and sources. The control name is optional as some graph lines have - * no associated controls. The section name can be used to differentiate the - * graph with other graphs, it's not used by the kernel atm. - * - *

DAPM Widgets

- * DAPM widgets are similar to controls in that they can include many other - * objects. Widgets can contain private data, mixer controls and enum controls. - * - * The following widget types are supported and match the driver types :- - * - * * input - * * output - * * mux - * * mixer - * * pga - * * out_drv - * * adc - * * dac - * * switch - * * pre - * * post - * * aif_in - * * aif_out - * * dai_in - * * dai_out - * * dai_link - * - * Widgets are defined as follows :- - * - *
- * SectionWidget."name" {
- *
- *	index "1"			# Index number
- *
- *	type "aif_in"			# Widget type - detailed above
- *	stream_name "name"		# Stream name
- *
- *	no_pm "true"			# No PM control bit.
- *	reg "20"			# PM bit register offset
- *	shift "0"			# PM bit register shift
- *	invert "1			# PM bit is inverted
- *	subseq "8"			# subsequence number
- *
- *	event_type "1"			# DAPM widget event type
- *	event_flags "1"			# DAPM widget event flags
- *
- *	mixer "name"			# Optional Mixer Control
- *	enum "name"			# Optional Enum Control
- *
- *	data "name"			# optional private data
- * }
- * 
- * - * The section name is the widget name. The mixer and enum fields are mutually - * exclusive and used to include controls into the widget. The index and data - * fields are the same for widgets as they are for controls whilst the other - * fields map on very closely to the driver widget fields. - * - *
Widget Private Data
- * Widget can have private data. For the format of the private data, please - * refer to section Control Private Data. - * - *

PCM Capabilities

- * Topology can also define the PCM capabilities of front end or physical DAIs. - * Capabilities can be defined with the following section :- - * - *
- * SectionPCMCapabilities."name" {
- *
- *	formats "S24_LE,S16_LE"		# Supported formats
- *	rates "48000"			# Supported rates
- *	rate_min "48000"		# Max supported sample rate
- *	rate_max "48000"		# Min supported sample rate
- *	channels_min "2"		# Min number of channels
- *	channels_max "2"		# max number of channels
- * }
- * 
- * The supported formats use the same naming convention as the driver macros. - * The PCM capabilities name can be referred to and included by PCM and - * physical DAI sections. - * - *

PCM Configurations

- * PCM runtime configurations can be defined for playback and capture stream - * directions with the following section :- - * - *
- * SectionPCMConfig."name" {
- *
- *	config."playback" {		# playback config
- *		format "S16_LE"		# playback format
- *		rate "48000"		# playback sample rate
- *		channels "2"		# playback channels
- *		tdm_slot "0xf"		# playback TDM slot
- *	}
- *
- *	config."capture" {		# capture config
- *		format "S16_LE"		# capture format
- *		rate "48000"		# capture sample rate
- *		channels "2"		# capture channels
- *		tdm_slot "0xf"		# capture TDM slot
- *	}
- * }
- * 
- * - * The supported formats use the same naming convention as the driver macros. - * The PCM configuration name can be referred to and included by PCM and - * physical link sections. - * - *

PCM (Front-end DAI & DAI link)

- * PCM sections define the supported capabilities and configurations for - * supported playback and capture streams, names and flags for front end - * DAI & DAI links. Topology kernel driver will use a PCM object to create - * a pair of FE DAI & DAI links. - * - *
- * SectionPCM."name" {
- *
- *	index "1"			# Index number
- *
- *	id "0"				# used for binding to the PCM
- *
- *	dai."name of front-end DAI" {
- *		id "0"		# used for binding to the front-end DAI
- *	}
- *
- *	pcm."playback" {
- *		capabilities "capabilities1"	# capabilities for playback
- *
- *		configs [		# supported configs for playback
- *			"config1"
- *			"config2"
- *		]
- *	}
- *
- *	pcm."capture" {
- *		capabilities "capabilities2"	# capabilities for capture
- *
- *		configs [		# supported configs for capture
- *			"config1"
- *			"config2"
- *			"config3"
- *		]
- *	}
- *
- *	# Optional boolean flags
- *	symmetric_rates			"true"
- *	symmetric_channels		"true"
- *	symmetric_sample_bits		"false"
- *
- *	data "name"			# optional private data
- * }
- * 
- * - *

Physical DAI Link Configurations

- * The runtime configurations of a physical DAI link can be defined by - * SectionLink.
Backend DAI links belong to physical links, and can - * be configured by either SectionLink or SectionBE, with same syntax. - * But SectionBE is deprecated atm since the internal processing is - * actually same. - * - *
- * SectionLink."name" {
- *
- *	index "1"			# Index number
- *
- *	id "0"				# used for binding to the link
- *
- *	stream_name "name"		# used for binding to the link
- *
- *	hw_configs [	# runtime supported HW configurations, optional
- *		"config1"
- *		"config2"
- *		...
- *	]
- *
- *	default_hw_conf_id "1"		#default HW config ID for init
- *
- *	# Optional boolean flags
- *	symmetric_rates			"true"
- *	symmetric_channels		"false"
- *	symmetric_sample_bits		"true"
- *
- *	data "name"			# optional private data
- * }
- * 
- * - * A physical link can refer to multiple runtime supported hardware - * configurations, which is defined by SectionHWConfig. - * - *
- * SectionHWConfig."name" {
- *
- *	id "1"				# used for binding to the config
- *	format "I2S"			# physical audio format.
- *	bclk   "master"			# Platform is master of bit clock
- *	fsync  "slave"			# Platform is slave of fsync
- * }
- * 
- * - *

Physical DAI

- * A physical DAI (e.g. backend DAI for DPCM) is defined as a new section - * that can include a unique ID, playback and capture stream capabilities, - * optional flags, and private data.
- * Its PCM stream capablities are same as those for PCM objects, - * please refer to section 'PCM Capabilities'. - * - *
- * SectionDAI."name" {
- *
- *	index "1"			# Index number
- *
- *	id "0"				# used for binding to the Backend DAI
- *
- *	pcm."playback" {
- *		capabilities "capabilities1"	# capabilities for playback
- *	}
- *
- *	pcm."capture" {
- *		capabilities "capabilities2"	# capabilities for capture
- *	}
- *
- *	symmetric_rates "true"			# optional flags
- *	symmetric_channels "true"
- *	symmetric_sample_bits "false"
- *
- *	data "name"			# optional private data
- * }
- * 
- * - *

Manifest Private Data

- * Manfiest may have private data. Users need to define a manifest section - * and add the references to 1 or multiple data sections. Please refer to - * section 'How to define an element with private data'.
- * And the text conf file can have at most 1 manifest section.

- * - * Manifest section is defined as follows :- - * - *
- * SectionManifest"name" {
- *
- *	data "name"			# optional private data
- * }
- * 
- * - *

Include other files

- * Users may include other files in a text conf file via alsaconf syntax - * . This allows users to define common info - * in separate files (e.g. vendor tokens, tuples) and share them for - * different platforms, thus save the total size of config files.
- * Users can also specifiy additional configuraiton directories relative - * to "/usr/share/alsa/" to search the included files, via alsaconf syntax - * .

- * - * For example, file A and file B are two text conf files for platform X, - * they will be installed to /usr/share/alsa/topology/platformx. If we - * need file A to include file B, in file A we can add:
- * - *
- *

- * - * ALSA conf will search and open an included file in the following order - * of priority: - * 1. directly open the file by its name; - * 2. search for the file name in "/usr/share/alsa"; - * 3. search for the file name in user specified subdirectories under - * "/usr/share/alsa". - * - * The order of the included files need not to be same as their - * dependencies, since the topology library will load them all before - * parsing their dependencies.
- * - * The configuration directories defined by a file will only be used to search - * the files included by this file. - */ - -/** Maximum number of channels supported in one control */ -#define SND_TPLG_MAX_CHAN 8 - -/** Topology context */ -typedef struct snd_tplg snd_tplg_t; - -/** Topology object types */ -enum snd_tplg_type { - SND_TPLG_TYPE_TLV = 0, /*!< TLV Data */ - SND_TPLG_TYPE_MIXER, /*!< Mixer control*/ - SND_TPLG_TYPE_ENUM, /*!< Enumerated control */ - SND_TPLG_TYPE_TEXT, /*!< Text data */ - SND_TPLG_TYPE_DATA, /*!< Private data */ - SND_TPLG_TYPE_BYTES, /*!< Byte control */ - SND_TPLG_TYPE_STREAM_CONFIG, /*!< PCM Stream configuration */ - SND_TPLG_TYPE_STREAM_CAPS, /*!< PCM Stream capabilities */ - SND_TPLG_TYPE_PCM, /*!< PCM stream device */ - SND_TPLG_TYPE_DAPM_WIDGET, /*!< DAPM widget */ - SND_TPLG_TYPE_DAPM_GRAPH, /*!< DAPM graph elements */ - SND_TPLG_TYPE_BE, /*!< BE DAI link */ - SND_TPLG_TYPE_CC, /*!< Hostless codec <-> codec link */ - SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ - SND_TPLG_TYPE_TOKEN, /*!< Vendor tokens */ - SND_TPLG_TYPE_TUPLE, /*!< Vendor tuples */ - SND_TPLG_TYPE_LINK, /*!< Physical DAI link */ - SND_TPLG_TYPE_HW_CONFIG, /*!< Link HW config */ - SND_TPLG_TYPE_DAI, /*!< Physical DAI */ -}; - -/** Fit for all user cases */ -#define SND_TPLG_INDEX_ALL 0 - -/** - * \brief Create a new topology parser instance. - * \return New topology parser instance - */ -snd_tplg_t *snd_tplg_new(void); - -/** - * \brief Free a topology parser instance. - * \param tplg Topology parser instance - */ -void snd_tplg_free(snd_tplg_t *tplg); - -/** - * \brief Parse and build topology text file into binary file. - * \param tplg Topology instance. - * \param infile Topology text input file to be parsed - * \param outfile Binary topology output file. - * \return Zero on success, otherwise a negative error code - */ -int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile, - const char *outfile); - -/** - * \brief Enable verbose reporting of binary file output - * \param tplg Topology Instance - * \param verbose Enable verbose output level if non zero - */ -void snd_tplg_verbose(snd_tplg_t *tplg, int verbose); - -/** \struct snd_tplg_tlv_template - * \brief Template type for all TLV objects. - */ -struct snd_tplg_tlv_template { - int type; /*!< TLV type SNDRV_CTL_TLVT_ */ -}; - -/** \struct snd_tplg_tlv_dbscale_template - * \brief Template type for TLV Scale objects. - */ -struct snd_tplg_tlv_dbscale_template { - struct snd_tplg_tlv_template hdr; /*!< TLV type header */ - int min; /*!< dB minimum value in 0.1dB */ - int step; /*!< dB step size in 0.1dB */ - int mute; /*!< is min dB value mute ? */ -}; - -/** \struct snd_tplg_channel_template - * \brief Template type for single channel mapping. - */ -struct snd_tplg_channel_elem { - int size; /*!< size in bytes of this structure */ - int reg; /*!< channel control register */ - int shift; /*!< channel shift for control bits */ - int id; /*!< ID maps to Left, Right, LFE etc */ -}; - -/** \struct snd_tplg_channel_map_template - * \brief Template type for channel mapping. - */ -struct snd_tplg_channel_map_template { - int num_channels; /*!< number of channel mappings */ - struct snd_tplg_channel_elem channel[SND_TPLG_MAX_CHAN]; /*!< mapping */ -}; - -/** \struct snd_tplg_pdata_template - * \brief Template type for private data objects. - */ -struct snd_tplg_pdata_template { - unsigned int length; /*!< data length */ - const void *data; /*!< data */ -}; - -/** \struct snd_tplg_io_ops_template - * \brief Template type for object operations mapping. - */ -struct snd_tplg_io_ops_template { - int get; /*!< get callback ID */ - int put; /*!< put callback ID */ - int info; /*!< info callback ID */ -}; - -/** \struct snd_tplg_ctl_template - * \brief Template type for control objects. - */ -struct snd_tplg_ctl_template { - int type; /*!< Control type */ - const char *name; /*!< Control name */ - int access; /*!< Control access */ - struct snd_tplg_io_ops_template ops; /*!< operations */ - struct snd_tplg_tlv_template *tlv; /*!< non NULL means we have TLV data */ -}; - -/** \struct snd_tplg_mixer_template - * \brief Template type for mixer control objects. - */ -struct snd_tplg_mixer_template { - struct snd_tplg_ctl_template hdr; /*!< control type header */ - struct snd_tplg_channel_map_template *map; /*!< channel map */ - int min; /*!< min value for mixer */ - int max; /*!< max value for mixer */ - int platform_max; /*!< max value for platform control */ - int invert; /*!< whether controls bits are inverted */ - struct snd_soc_tplg_private *priv; /*!< control private data */ -}; - -/** \struct snd_tplg_enum_template - * \brief Template type for enumerated control objects. - */ -struct snd_tplg_enum_template { - struct snd_tplg_ctl_template hdr; /*!< control type header */ - struct snd_tplg_channel_map_template *map; /*!< channel map */ - int items; /*!< number of enumerated items in control */ - int mask; /*!< register mask size */ - const char **texts; /*!< control text items */ - const int **values; /*!< control value items */ - struct snd_soc_tplg_private *priv; /*!< control private data */ -}; - -/** \struct snd_tplg_bytes_template - * \brief Template type for TLV Scale objects. - */ -struct snd_tplg_bytes_template { - struct snd_tplg_ctl_template hdr; /*!< control type header */ - int max; /*!< max byte control value */ - int mask; /*!< byte control mask */ - int base; /*!< base register */ - int num_regs; /*!< number of registers */ - struct snd_tplg_io_ops_template ext_ops; /*!< ops mapping */ - struct snd_soc_tplg_private *priv; /*!< control private data */ -}; - -/** \struct snd_tplg_graph_elem - * \brief Template type for single DAPM graph element. - */ -struct snd_tplg_graph_elem { - const char *src; /*!< source widget name */ - const char *ctl; /*!< control name or NULL if no control */ - const char *sink; /*!< sink widget name */ -}; - -/** \struct snd_tplg_graph_template - * \brief Template type for array of DAPM graph elements. - */ -struct snd_tplg_graph_template { - int count; /*!< Number of graph elements */ - struct snd_tplg_graph_elem elem[0]; /*!< graph elements */ -}; - -/** \struct snd_tplg_widget_template - * \brief Template type for DAPM widget objects. - */ -struct snd_tplg_widget_template { - int id; /*!< SND_SOC_DAPM_CTL */ - const char *name; /*!< widget name */ - const char *sname; /*!< stream name (certain widgets only) */ - int reg; /*!< negative reg = no direct dapm */ - int shift; /*!< bits to shift */ - int mask; /*!< non-shifted mask */ - int subseq; /*!< sort within widget type */ - unsigned int invert; /*!< invert the power bit */ - unsigned int ignore_suspend; /*!< kept enabled over suspend */ - unsigned short event_flags; /*!< PM event sequence flags */ - unsigned short event_type; /*!< PM event sequence type */ - struct snd_soc_tplg_private *priv; /*!< widget private data */ - int num_ctls; /*!< Number of controls used by widget */ - struct snd_tplg_ctl_template *ctl[0]; /*!< array of widget controls */ -}; - -/** \struct snd_tplg_stream_template - * \brief Stream configurations. - */ -struct snd_tplg_stream_template { - const char *name; /*!< name of the stream config */ - int format; /*!< SNDRV_PCM_FMTBIT_* */ - int rate; /*!< SNDRV_PCM_RATE_* */ - int period_bytes; /*!< size of period in bytes */ - int buffer_bytes; /*!< size of buffer in bytes. */ - int channels; /*!< number of channels */ -}; - -/** \struct snd_tplg_stream_caps_template - * \brief Stream Capabilities. - */ -struct snd_tplg_stream_caps_template { - const char *name; /*!< name of the stream caps */ - uint64_t formats; /*!< supported formats SNDRV_PCM_FMTBIT_* */ - unsigned int rates; /*!< supported rates SNDRV_PCM_RATE_* */ - unsigned int rate_min; /*!< min rate */ - unsigned int rate_max; /*!< max rate */ - unsigned int channels_min; /*!< min channels */ - unsigned int channels_max; /*!< max channels */ - unsigned int periods_min; /*!< min number of periods */ - unsigned int periods_max; /*!< max number of periods */ - unsigned int period_size_min; /*!< min period size bytes */ - unsigned int period_size_max; /*!< max period size bytes */ - unsigned int buffer_size_min; /*!< min buffer size bytes */ - unsigned int buffer_size_max; /*!< max buffer size bytes */ - unsigned int sig_bits; /*!< number of bits of content */ -}; - -/** \struct snd_tplg_pcm_template - * \brief Template type for PCM (FE DAI & DAI links). - */ -struct snd_tplg_pcm_template { - const char *pcm_name; /*!< PCM stream name */ - const char *dai_name; /*!< DAI name */ - unsigned int pcm_id; /*!< unique ID - used to match */ - unsigned int dai_id; /*!< unique ID - used to match */ - unsigned int playback; /*!< supports playback mode */ - unsigned int capture; /*!< supports capture mode */ - unsigned int compress; /*!< 1 = compressed; 0 = PCM */ - struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ - unsigned int flag_mask; /*!< bitmask of flags to configure */ - unsigned int flags; /*!< flag value SND_SOC_TPLG_LNK_FLGBIT_* */ - struct snd_soc_tplg_private *priv; /*!< private data */ - int num_streams; /*!< number of supported configs */ - struct snd_tplg_stream_template stream[0]; /*!< supported configs */ -}; - - /** \struct snd_tplg_hw_config_template - * \brief Template type to describe a physical link runtime supported - * hardware config, i.e. hardware audio formats. - */ -struct snd_tplg_hw_config_template { - int id; /* unique ID - - used to match */ - unsigned int fmt; /* SND_SOC_DAI_FORMAT_ format value */ - unsigned char clock_gated; /* 1 if clock can be gated to save power */ - unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ - unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - unsigned char bclk_master; /* 1 for master of BCLK, 0 for slave */ - unsigned char fsync_master; /* 1 for master of FSYNC, 0 for slave */ - unsigned char mclk_direction; /* 0 for input, 1 for output */ - unsigned short reserved; /* for 32bit alignment */ - unsigned int mclk_rate; /* MCLK or SYSCLK freqency in Hz */ - unsigned int bclk_rate; /* BCLK freqency in Hz */ - unsigned int fsync_rate; /* frame clock in Hz */ - unsigned int tdm_slots; /* number of TDM slots in use */ - unsigned int tdm_slot_width; /* width in bits for each slot */ - unsigned int tx_slots; /* bit mask for active Tx slots */ - unsigned int rx_slots; /* bit mask for active Rx slots */ - unsigned int tx_channels; /* number of Tx channels */ - unsigned int *tx_chanmap; /* array of slot number */ - unsigned int rx_channels; /* number of Rx channels */ - unsigned int *rx_chanmap; /* array of slot number */ -}; - -/** \struct snd_tplg_dai_template - * \brief Template type for physical DAI. - * It can be used to configure backend DAIs for DPCM. - */ -struct snd_tplg_dai_template { - const char *dai_name; /*!< DAI name */ - unsigned int dai_id; /*!< unique ID - used to match */ - unsigned int playback; /*!< supports playback mode */ - unsigned int capture; /*!< supports capture mode */ - struct snd_tplg_stream_caps_template *caps[2]; /*!< playback & capture for DAI */ - unsigned int flag_mask; /*!< bitmask of flags to configure */ - unsigned int flags; /*!< SND_SOC_TPLG_DAI_FLGBIT_* */ - struct snd_soc_tplg_private *priv; /*!< private data */ - -}; - -/** \struct snd_tplg_link_template - * \brief Template type for physical DAI Links. - */ -struct snd_tplg_link_template { - const char *name; /*!< link name, used to match */ - int id; /*!< unique ID - used to match with existing physical links */ - const char *stream_name; /*!< link stream name, used to match */ - - int num_streams; /*!< number of configs */ - struct snd_tplg_stream_template *stream; /*!< supported configs */ - - struct snd_tplg_hw_config_template *hw_config; /*!< supported HW configs */ - int num_hw_configs; /* number of hw configs */ - int default_hw_config_id; /* default hw config ID for init */ - - unsigned int flag_mask; /* bitmask of flags to configure */ - unsigned int flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ - struct snd_soc_tplg_private *priv; /*!< private data */ -}; - -/** \struct snd_tplg_obj_template - * \brief Generic Template Object - */ -typedef struct snd_tplg_obj_template { - enum snd_tplg_type type; /*!< template object type */ - int index; /*!< group index for object */ - int version; /*!< optional vendor specific version details */ - int vendor_type; /*!< optional vendor specific type info */ - union { - struct snd_tplg_widget_template *widget; /*!< DAPM widget */ - struct snd_tplg_mixer_template *mixer; /*!< Mixer control */ - struct snd_tplg_bytes_template *bytes_ctl; /*!< Bytes control */ - struct snd_tplg_enum_template *enum_ctl; /*!< Enum control */ - struct snd_tplg_graph_template *graph; /*!< Graph elements */ - struct snd_tplg_pcm_template *pcm; /*!< PCM elements */ - struct snd_tplg_link_template *link; /*!< physical DAI Links */ - struct snd_tplg_dai_template *dai; /*!< Physical DAI */ - }; -} snd_tplg_obj_template_t; - -/** - * \brief Register topology template object. - * \param tplg Topology instance. - * \param t Template object. - * \return Zero on success, otherwise a negative error code - */ -int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); - -/** - * \brief Build all registered topology data into binary file. - * \param tplg Topology instance. - * \param outfile Binary topology output file. - * \return Zero on success, otherwise a negative error code - */ -int snd_tplg_build(snd_tplg_t *tplg, const char *outfile); - -/** - * \brief Attach private data to topology manifest. - * \param tplg Topology instance. - * \param data Private data. - * \param len Length of data in bytes. - * \return Zero on success, otherwise a negative error code - */ -int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len); - -/** - * \brief Set an optional vendor specific version number. - * \param tplg Topology instance. - * \param version Vendor specific version number. - * \return Zero on success, otherwise a negative error code - */ -int snd_tplg_set_version(snd_tplg_t *tplg, unsigned int version); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_TOPOLOGY_H */ diff --git a/raylib/external/alsa/use-case.h b/raylib/external/alsa/use-case.h deleted file mode 100644 index ae22bde..0000000 --- a/raylib/external/alsa/use-case.h +++ /dev/null @@ -1,433 +0,0 @@ -/** - * \file include/use-case.h - * \brief use case interface for the ALSA driver - * \author Liam Girdwood - * \author Stefan Schmidt - * \author Jaroslav Kysela - * \author Justin Xu - * \date 2008-2010 - */ -/* - * - * 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 program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2008-2010 SlimLogic Ltd - * Copyright (C) 2010 Wolfson Microelectronics PLC - * Copyright (C) 2010 Texas Instruments Inc. - * - * Support for the verb/device/modifier core logic and API, - * command line tool and file parser was kindly sponsored by - * Texas Instruments Inc. - * Support for multiple active modifiers and devices, - * transition sequences, multiple client access and user defined use - * cases was kindly sponsored by Wolfson Microelectronics PLC. - */ - -#ifndef __ALSA_USE_CASE_H -#define __ALSA_USE_CASE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup ucm Use Case Interface - * The ALSA Use Case manager interface. - * See \ref Usecase page for more details. - * \{ - */ - -/*! \page Usecase ALSA Use Case Interface - * - * The use case manager works by configuring the sound card ALSA kcontrols to - * change the hardware digital and analog audio routing to match the requested - * device use case. The use case manager kcontrol configurations are stored in - * easy to modify text files. - * - * An audio use case can be defined by a verb and device parameter. The verb - * describes the use case action i.e. a phone call, listening to music, recording - * a conversation etc. The device describes the physical audio capture and playback - * hardware i.e. headphones, phone handset, bluetooth headset, etc. - * - * It's intended clients will mostly only need to set the use case verb and - * device for each system use case change (as the verb and device parameters - * cover most audio use cases). - * - * However there are times when a use case has to be modified at runtime. e.g. - * - * + Incoming phone call when the device is playing music - * + Recording sections of a phone call - * + Playing tones during a call. - * - * In order to allow asynchronous runtime use case adaptations, we have a third - * optional modifier parameter that can be used to further configure - * the use case during live audio runtime. - * - * This interface allows clients to :- - * - * + Query the supported use case verbs, devices and modifiers for the machine. - * + Set and Get use case verbs, devices and modifiers for the machine. - * + Get the ALSA PCM playback and capture device PCMs for use case verb, - * use case device and modifier. - * + Get the TQ parameter for each use case verb, use case device and - * modifier. - * + Get the ALSA master playback and capture volume/switch kcontrols - * for each use case. - */ - - -/* - * Use Case Verb. - * - * The use case verb is the main device audio action. e.g. the "HiFi" use - * case verb will configure the audio hardware for HiFi Music playback - * and capture. - */ -#define SND_USE_CASE_VERB_INACTIVE "Inactive" /**< Inactive Verb */ -#define SND_USE_CASE_VERB_HIFI "HiFi" /**< HiFi Verb */ -#define SND_USE_CASE_VERB_HIFI_LOW_POWER "HiFi Low Power" /**< HiFi Low Power Verb */ -#define SND_USE_CASE_VERB_VOICE "Voice" /**< Voice Verb */ -#define SND_USE_CASE_VERB_VOICE_LOW_POWER "Voice Low Power" /**< Voice Low Power Verb */ -#define SND_USE_CASE_VERB_VOICECALL "Voice Call" /**< Voice Call Verb */ -#define SND_USE_CASE_VERB_IP_VOICECALL "Voice Call IP" /**< Voice Call IP Verb */ -#define SND_USE_CASE_VERB_ANALOG_RADIO "FM Analog Radio" /**< FM Analog Radio Verb */ -#define SND_USE_CASE_VERB_DIGITAL_RADIO "FM Digital Radio" /**< FM Digital Radio Verb */ -/* add new verbs to end of list */ - - -/* - * Use Case Device. - * - * Physical system devices the render and capture audio. Devices can be OR'ed - * together to support audio on simultaneous devices. - */ -#define SND_USE_CASE_DEV_NONE "None" /**< None Device */ -#define SND_USE_CASE_DEV_SPEAKER "Speaker" /**< Speaker Device */ -#define SND_USE_CASE_DEV_LINE "Line" /**< Line Device */ -#define SND_USE_CASE_DEV_HEADPHONES "Headphones" /**< Headphones Device */ -#define SND_USE_CASE_DEV_HEADSET "Headset" /**< Headset Device */ -#define SND_USE_CASE_DEV_HANDSET "Handset" /**< Handset Device */ -#define SND_USE_CASE_DEV_BLUETOOTH "Bluetooth" /**< Bluetooth Device */ -#define SND_USE_CASE_DEV_EARPIECE "Earpiece" /**< Earpiece Device */ -#define SND_USE_CASE_DEV_SPDIF "SPDIF" /**< SPDIF Device */ -#define SND_USE_CASE_DEV_HDMI "HDMI" /**< HDMI Device */ -/* add new devices to end of list */ - - -/* - * Use Case Modifiers. - * - * The use case modifier allows runtime configuration changes to deal with - * asynchronous events. - * - * e.g. to record a voice call :- - * 1. Set verb to SND_USE_CASE_VERB_VOICECALL (for voice call) - * 2. Set modifier SND_USE_CASE_MOD_CAPTURE_VOICE when capture required. - * 3. Call snd_use_case_get("CapturePCM") to get ALSA source PCM name - * with captured voice pcm data. - * - * e.g. to play a ring tone when listenin to MP3 Music :- - * 1. Set verb to SND_USE_CASE_VERB_HIFI (for MP3 playback) - * 2. Set modifier to SND_USE_CASE_MOD_PLAY_TONE when incoming call happens. - * 3. Call snd_use_case_get("PlaybackPCM") to get ALSA PCM sink name for - * ringtone pcm data. - */ -#define SND_USE_CASE_MOD_CAPTURE_VOICE "Capture Voice" /**< Capture Voice Modifier */ -#define SND_USE_CASE_MOD_CAPTURE_MUSIC "Capture Music" /**< Capture Music Modifier */ -#define SND_USE_CASE_MOD_PLAY_MUSIC "Play Music" /**< Play Music Modifier */ -#define SND_USE_CASE_MOD_PLAY_VOICE "Play Voice" /**< Play Voice Modifier */ -#define SND_USE_CASE_MOD_PLAY_TONE "Play Tone" /**< Play Tone Modifier */ -#define SND_USE_CASE_MOD_ECHO_REF "Echo Reference" /**< Echo Reference Modifier */ -/* add new modifiers to end of list */ - - -/** - * TQ - Tone Quality - * - * The interface allows clients to determine the audio TQ required for each - * use case verb and modifier. It's intended as an optional hint to the - * audio driver in order to lower power consumption. - * - */ -#define SND_USE_CASE_TQ_MUSIC "Music" /**< Music Tone Quality */ -#define SND_USE_CASE_TQ_VOICE "Voice" /**< Voice Tone Quality */ -#define SND_USE_CASE_TQ_TONES "Tones" /**< Tones Tone Quality */ - -/** use case container */ -typedef struct snd_use_case_mgr snd_use_case_mgr_t; - -/** - * \brief Create an identifier - * \param fmt Format (sprintf like) - * \param ... Optional arguments for sprintf like format - * \return Allocated string identifier or NULL on error - */ -char *snd_use_case_identifier(const char *fmt, ...); - -/** - * \brief Free a string list - * \param list The string list to free - * \param items Count of strings - * \return Zero if success, otherwise a negative error code - */ -int snd_use_case_free_list(const char *list[], int items); - -/** - * \brief Obtain a list of entries - * \param uc_mgr Use case manager (may be NULL - card list) - * \param identifier (may be NULL - card list) - * \param list Returned allocated list - * \return Number of list entries if success, otherwise a negative error code - * - * Defined identifiers: - * - NULL - get card list - * (in pair cardname+comment) - * - _verbs - get verb list - * (in pair verb+comment) - * - _devices[/{verb}] - get list of supported devices - * (in pair device+comment) - * - _modifiers[/{verb}] - get list of supported modifiers - * (in pair modifier+comment) - * - TQ[/{verb}] - get list of TQ identifiers - * - _enadevs - get list of enabled devices - * - _enamods - get list of enabled modifiers - * - * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices - * - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices - * - * Note that at most one of the supported/conflicting devs lists has - * any entries, and when neither is present, all devices are supported. - * - */ -int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **list[]); - - -/** - * \brief Get current - string - * \param uc_mgr Use case manager - * \param identifier - * \param value Value pointer - * \return Zero if success, otherwise a negative error code - * - * Note: The returned string is dynamically allocated, use free() to - * deallocate this string. (Yes, the value parameter shouldn't be marked as - * "const", but it's too late to fix it, sorry about that.) - * - * Known identifiers: - * - NULL - return current card - * - _verb - return current verb - * - _file - return configuration file loaded for current card - * - * - [=]{NAME}[/[{modifier}|{/device}][/{verb}]] - * - value identifier {NAME} - * - Search starts at given modifier or device if any, - * else at a verb - * - Search starts at given verb if any, - * else current verb - * - Searches modifier/device, then verb, then defaults - * - Specify a leading "=" to search only the exact - * device/modifier/verb specified, and not search - * through each object in turn. - * - Examples: - * - "PlaybackPCM/Play Music" - * - "CapturePCM/SPDIF" - * - From ValueDefaults only: - * "=Variable" - * - From current active verb: - * "=Variable//" - * - From verb "Verb": - * "=Variable//Verb" - * - From "Modifier" in current active verb: - * "=Variable/Modifier/" - * - From "Modifier" in "Verb": - * "=Variable/Modifier/Verb" - * - * Recommended names for values: - * - TQ - * - Tone Quality - * - PlaybackPCM - * - full PCM playback device name - * - PlaybackPCMIsDummy - * - Valid values: "yes" and "no". If set to "yes", the PCM named by the - * PlaybackPCM value is a dummy device, meaning that opening it enables - * an audio path in the hardware, but writing to the PCM device has no - * effect. - * - CapturePCM - * - full PCM capture device name - * - CapturePCMIsDummy - * - Valid values: "yes" and "no". If set to "yes", the PCM named by the - * CapturePCM value is a dummy device, meaning that opening it enables - * an audio path in the hardware, but reading from the PCM device has no - * effect. - * - PlaybackRate - * - playback device sample rate - * - PlaybackChannels - * - playback device channel count - * - PlaybackCTL - * - playback control device name - * - PlaybackVolume - * - playback control volume ID string - * - PlaybackSwitch - * - playback control switch ID string - * - CaptureRate - * - capture device sample rate - * - CaptureChannels - * - capture device channel count - * - CaptureCTL - * - capture control device name - * - CaptureVolume - * - capture control volume ID string - * - CaptureSwitch - * - capture control switch ID string - * - PlaybackMixer - * - name of playback mixer - * - PlaybackMixerID - * - mixer playback ID - * - CaptureMixer - * - name of capture mixer - * - CaptureMixerID - * - mixer capture ID - * - JackControl, JackDev, JackHWMute - * - Jack information for a device. The jack status can be reported via - * a kcontrol and/or via an input device. **JackControl** is the - * kcontrol name of the jack, and **JackDev** is the input device id of - * the jack (if the full input device path is /dev/input/by-id/foo, the - * JackDev value should be "foo"). UCM configuration files should - * contain both JackControl and JackDev when possible, because - * applications are likely to support only one or the other. - * - * If **JackHWMute** is set, it indicates that when the jack is plugged - * in, the hardware automatically mutes some other device(s). The - * JackHWMute value is a space-separated list of device names (this - * isn't compatible with device names with spaces in them, so don't use - * such device names!). Note that JackHWMute should be used only when - * the hardware enforces the automatic muting. If the hardware doesn't - * enforce any muting, it may still be tempting to set JackHWMute to - * trick upper software layers to e.g. automatically mute speakers when - * headphones are plugged in, but that's application policy - * configuration that doesn't belong to UCM configuration files. - */ -int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char **value); - -/** - * \brief Get current - integer - * \param uc_mgr Use case manager - * \param identifier - * \param value result - * \return Zero if success, otherwise a negative error code - * - * Known identifiers: - * - _devstatus/{device} - return status for given device - * - _modstatus/{modifier} - return status for given modifier - */ -int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - long *value); - -/** - * \brief Set new - * \param uc_mgr Use case manager - * \param identifier - * \param value Value - * \return Zero if success, otherwise a negative error code - * - * Known identifiers: - * - _verb - set current verb = value - * - _enadev - enable given device = value - * - _disdev - disable given device = value - * - _swdev/{old_device} - new_device = value - * - disable old_device and then enable new_device - * - if old_device is not enabled just return - * - check transmit sequence firstly - * - _enamod - enable given modifier = value - * - _dismod - disable given modifier = value - * - _swmod/{old_modifier} - new_modifier = value - * - disable old_modifier and then enable new_modifier - * - if old_modifier is not enabled just return - * - check transmit sequence firstly - */ -int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, - const char *identifier, - const char *value); - -/** - * \brief Open and initialise use case core for sound card - * \param uc_mgr Returned use case manager pointer - * \param card_name Sound card name. - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name); - - -/** - * \brief Reload and re-parse use case configuration files for sound card. - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr); - -/** - * \brief Close use case manager - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr); - -/** - * \brief Reset use case manager verb, device, modifier to deafult settings. - * \param uc_mgr Use case manager - * \return zero if success, otherwise a negative error code - */ -int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr); - -/* - * helper functions - */ - -/** - * \brief Obtain a list of cards - * \param list Returned allocated list - * \return Number of list entries if success, otherwise a negative error code - */ -static __inline__ int snd_use_case_card_list(const char **list[]) -{ - return snd_use_case_get_list(NULL, NULL, list); -} - -/** - * \brief Obtain a list of verbs - * \param uc_mgr Use case manager - * \param list Returned list of verbs - * \return Number of list entries if success, otherwise a negative error code - */ -static __inline__ int snd_use_case_verb_list(snd_use_case_mgr_t *uc_mgr, - const char **list[]) -{ - return snd_use_case_get_list(uc_mgr, "_verbs", list); -} - -/** - * \} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ALSA_USE_CASE_H */ diff --git a/raylib/external/alsa/version.h b/raylib/external/alsa/version.h deleted file mode 100644 index ad36231..0000000 --- a/raylib/external/alsa/version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * version.h - */ - -#define SND_LIB_MAJOR 1 /**< major number of library version */ -#define SND_LIB_MINOR 1 /**< minor number of library version */ -#define SND_LIB_SUBMINOR 5 /**< subminor number of library version */ -#define SND_LIB_EXTRAVER 1000000 /**< extra version number, used mainly for betas */ -/** library version */ -#define SND_LIB_VERSION ((SND_LIB_MAJOR<<16)|\ - (SND_LIB_MINOR<<8)|\ - SND_LIB_SUBMINOR) -/** library version (string) */ -#define SND_LIB_VERSION_STR "1.1.5" - diff --git a/raylib/external/android/native_app_glue/vendor.go b/raylib/external/android/native_app_glue/vendor.go new file mode 100644 index 0000000..0fb2a0f --- /dev/null +++ b/raylib/external/android/native_app_glue/vendor.go @@ -0,0 +1,4 @@ +//go:build required +// +build required + +package vendor diff --git a/raylib/external/cgltf.h b/raylib/external/cgltf.h new file mode 100644 index 0000000..36fd644 --- /dev/null +++ b/raylib/external/cgltf.h @@ -0,0 +1,7081 @@ +/** + * cgltf - a single-file glTF 2.0 parser written in C99. + * + * Version: 1.14 + * + * Website: https://github.com/jkuhlmann/cgltf + * + * Distributed under the MIT License, see notice at the end of this file. + * + * Building: + * Include this file where you need the struct and function + * declarations. Have exactly one source file where you define + * `CGLTF_IMPLEMENTATION` before including this file to get the + * function definitions. + * + * Reference: + * `cgltf_result cgltf_parse(const cgltf_options*, const void*, + * cgltf_size, cgltf_data**)` parses both glTF and GLB data. If + * this function returns `cgltf_result_success`, you have to call + * `cgltf_free()` on the created `cgltf_data*` variable. + * Note that contents of external files for buffers and images are not + * automatically loaded. You'll need to read these files yourself using + * URIs in the `cgltf_data` structure. + * + * `cgltf_options` is the struct passed to `cgltf_parse()` to control + * parts of the parsing process. You can use it to force the file type + * and provide memory allocation as well as file operation callbacks. + * Should be zero-initialized to trigger default behavior. + * + * `cgltf_data` is the struct allocated and filled by `cgltf_parse()`. + * It generally mirrors the glTF format as described by the spec (see + * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0). + * + * `void cgltf_free(cgltf_data*)` frees the allocated `cgltf_data` + * variable. + * + * `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*, + * const char* gltf_path)` can be optionally called to open and read buffer + * files using the `FILE*` APIs. The `gltf_path` argument is the path to + * the original glTF file, which allows the parser to resolve the path to + * buffer files. + * + * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, + * cgltf_size size, const char* base64, void** out_data)` decodes + * base64-encoded data content. Used internally by `cgltf_load_buffers()`. + * This is useful when decoding data URIs in images. + * + * `cgltf_result cgltf_parse_file(const cgltf_options* options, const + * char* path, cgltf_data** out_data)` can be used to open the given + * file using `FILE*` APIs and parse the data using `cgltf_parse()`. + * + * `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional + * checks to make sure the parsed glTF data is valid. + * + * `cgltf_node_transform_local` converts the translation / rotation / scale properties of a node + * into a mat4. + * + * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order + * to compute the root-to-node transformation. + * + * `cgltf_accessor_unpack_floats` reads in the data from an accessor, applies sparse data (if any), + * and converts them to floating point. Assumes that `cgltf_load_buffers` has already been called. + * 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 + * 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. + * + * `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 + * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns + * false if the passed-in element_size is too small, or if the accessor is sparse. + * + * `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 + * 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 + * 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; +typedef int cgltf_bool; + +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 +{ + cgltf_result_success, + cgltf_result_data_too_short, + cgltf_result_unknown_format, + cgltf_result_invalid_json, + cgltf_result_invalid_gltf, + cgltf_result_invalid_options, + cgltf_result_file_not_found, + 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* user_data; +} cgltf_memory_options; + +typedef struct cgltf_file_options +{ + cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data); + void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data); + void* user_data; +} cgltf_file_options; + +typedef struct cgltf_options +{ + cgltf_file_type type; /* invalid == auto detect */ + cgltf_size json_token_count; /* 0 == auto */ + cgltf_memory_options memory; + cgltf_file_options file; +} cgltf_options; + +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 +{ + cgltf_attribute_type_invalid, + cgltf_attribute_type_position, + cgltf_attribute_type_normal, + cgltf_attribute_type_tangent, + cgltf_attribute_type_texcoord, + 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 +{ + cgltf_component_type_invalid, + cgltf_component_type_r_8, /* BYTE */ + cgltf_component_type_r_8u, /* UNSIGNED_BYTE */ + cgltf_component_type_r_16, /* SHORT */ + 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 +{ + cgltf_type_invalid, + cgltf_type_scalar, + cgltf_type_vec2, + cgltf_type_vec3, + cgltf_type_vec4, + 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, + cgltf_primitive_type_line_strip, + 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 +{ + 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 { + cgltf_animation_path_type_invalid, + cgltf_animation_path_type_translation, + 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 { + cgltf_light_type_invalid, + 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_extras; + +typedef struct cgltf_extension { + char* name; + char* data; +} cgltf_extension; + +typedef struct cgltf_buffer +{ + char* name; + 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; +} cgltf_buffer; + +typedef enum cgltf_meshopt_compression_mode { + cgltf_meshopt_compression_mode_invalid, + 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 { + cgltf_meshopt_compression_filter_none, + 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 +{ + cgltf_buffer* buffer; + cgltf_size offset; + cgltf_size size; + cgltf_size stride; + cgltf_size count; + cgltf_meshopt_compression_mode mode; + cgltf_meshopt_compression_filter filter; +} cgltf_meshopt_compression; + +typedef struct cgltf_buffer_view +{ + char *name; + cgltf_buffer* buffer; + cgltf_size offset; + cgltf_size size; + cgltf_size stride; /* 0 == automatically determined by accessor */ + cgltf_buffer_view_type type; + void* data; /* overrides buffer->data if present, filled by extensions */ + cgltf_bool has_meshopt_compression; + cgltf_meshopt_compression meshopt_compression; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_buffer_view; + +typedef struct cgltf_accessor_sparse +{ + cgltf_size count; + cgltf_buffer_view* indices_buffer_view; + cgltf_size indices_byte_offset; + cgltf_component_type indices_component_type; + cgltf_buffer_view* values_buffer_view; + cgltf_size values_byte_offset; +} cgltf_accessor_sparse; + +typedef struct cgltf_accessor +{ + char* name; + cgltf_component_type component_type; + cgltf_bool normalized; + cgltf_type type; + cgltf_size offset; + cgltf_size count; + cgltf_size stride; + cgltf_buffer_view* buffer_view; + cgltf_bool has_min; + cgltf_float min[16]; + cgltf_bool has_max; + cgltf_float max[16]; + cgltf_bool is_sparse; + cgltf_accessor_sparse sparse; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_accessor; + +typedef struct cgltf_attribute +{ + char* name; + cgltf_attribute_type type; + cgltf_int index; + cgltf_accessor* data; +} cgltf_attribute; + +typedef struct cgltf_image +{ + char* name; + char* uri; + cgltf_buffer_view* buffer_view; + char* mime_type; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_image; + +typedef struct cgltf_sampler +{ + char* name; + cgltf_int mag_filter; + cgltf_int min_filter; + cgltf_int wrap_s; + cgltf_int wrap_t; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_sampler; + +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; +} cgltf_texture; + +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; + +typedef struct cgltf_texture_view +{ + cgltf_texture* texture; + cgltf_int texcoord; + cgltf_float scale; /* equivalent to strength for occlusion_texture */ + cgltf_bool has_transform; + cgltf_texture_transform transform; +} cgltf_texture_view; + +typedef struct cgltf_pbr_metallic_roughness +{ + cgltf_texture_view base_color_texture; + cgltf_texture_view metallic_roughness_texture; + + cgltf_float base_color_factor[4]; + cgltf_float metallic_factor; + cgltf_float roughness_factor; +} cgltf_pbr_metallic_roughness; + +typedef struct cgltf_pbr_specular_glossiness +{ + cgltf_texture_view diffuse_texture; + cgltf_texture_view specular_glossiness_texture; + + cgltf_float diffuse_factor[4]; + cgltf_float specular_factor[3]; + cgltf_float glossiness_factor; +} cgltf_pbr_specular_glossiness; + +typedef struct cgltf_clearcoat +{ + cgltf_texture_view clearcoat_texture; + cgltf_texture_view clearcoat_roughness_texture; + cgltf_texture_view clearcoat_normal_texture; + + cgltf_float clearcoat_factor; + cgltf_float clearcoat_roughness_factor; +} cgltf_clearcoat; + +typedef struct cgltf_transmission +{ + cgltf_texture_view transmission_texture; + cgltf_float transmission_factor; +} cgltf_transmission; + +typedef struct cgltf_ior +{ + cgltf_float ior; +} cgltf_ior; + +typedef struct cgltf_specular +{ + cgltf_texture_view specular_texture; + cgltf_texture_view specular_color_texture; + cgltf_float specular_color_factor[3]; + cgltf_float specular_factor; +} cgltf_specular; + +typedef struct cgltf_volume +{ + cgltf_texture_view thickness_texture; + cgltf_float thickness_factor; + cgltf_float attenuation_color[3]; + cgltf_float attenuation_distance; +} cgltf_volume; + +typedef struct cgltf_sheen +{ + cgltf_texture_view sheen_color_texture; + cgltf_float sheen_color_factor[3]; + cgltf_texture_view sheen_roughness_texture; + 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; + cgltf_bool has_pbr_metallic_roughness; + cgltf_bool has_pbr_specular_glossiness; + cgltf_bool has_clearcoat; + cgltf_bool has_transmission; + cgltf_bool has_volume; + 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; + cgltf_ior ior; + cgltf_specular specular; + 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; + cgltf_float emissive_factor[3]; + cgltf_alpha_mode alpha_mode; + cgltf_float alpha_cutoff; + cgltf_bool double_sided; + cgltf_bool unlit; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_material; + +typedef struct cgltf_material_mapping +{ + cgltf_size variant; + cgltf_material* material; + cgltf_extras extras; +} cgltf_material_mapping; + +typedef struct cgltf_morph_target { + cgltf_attribute* attributes; + cgltf_size attributes_count; +} cgltf_morph_target; + +typedef struct cgltf_draco_mesh_compression { + cgltf_buffer_view* buffer_view; + cgltf_attribute* attributes; + 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; + cgltf_material* material; + cgltf_attribute* attributes; + cgltf_size attributes_count; + cgltf_morph_target* targets; + cgltf_size targets_count; + cgltf_extras extras; + cgltf_bool has_draco_mesh_compression; + cgltf_draco_mesh_compression draco_mesh_compression; + cgltf_material_mapping* mappings; + cgltf_size mappings_count; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_primitive; + +typedef struct cgltf_mesh { + char* name; + cgltf_primitive* primitives; + cgltf_size primitives_count; + cgltf_float* weights; + cgltf_size weights_count; + char** target_names; + cgltf_size target_names_count; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_mesh; + +typedef struct cgltf_node cgltf_node; + +typedef struct cgltf_skin { + char* name; + cgltf_node** joints; + cgltf_size joints_count; + cgltf_node* skeleton; + cgltf_accessor* inverse_bind_matrices; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_skin; + +typedef struct cgltf_camera_perspective { + cgltf_bool has_aspect_ratio; + cgltf_float aspect_ratio; + cgltf_float yfov; + cgltf_bool has_zfar; + cgltf_float zfar; + cgltf_float znear; + cgltf_extras extras; +} cgltf_camera_perspective; + +typedef struct cgltf_camera_orthographic { + cgltf_float xmag; + cgltf_float ymag; + cgltf_float zfar; + cgltf_float znear; + cgltf_extras extras; +} cgltf_camera_orthographic; + +typedef struct cgltf_camera { + char* name; + cgltf_camera_type type; + union { + cgltf_camera_perspective perspective; + cgltf_camera_orthographic orthographic; + } data; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_camera; + +typedef struct cgltf_light { + char* name; + cgltf_float color[3]; + cgltf_float intensity; + cgltf_light_type type; + cgltf_float range; + cgltf_float spot_inner_cone_angle; + cgltf_float spot_outer_cone_angle; + cgltf_extras extras; +} cgltf_light; + +struct cgltf_node { + char* name; + cgltf_node* parent; + cgltf_node** children; + cgltf_size children_count; + cgltf_skin* skin; + cgltf_mesh* mesh; + cgltf_camera* camera; + cgltf_light* light; + cgltf_float* weights; + cgltf_size weights_count; + cgltf_bool has_translation; + cgltf_bool has_rotation; + cgltf_bool has_scale; + cgltf_bool has_matrix; + cgltf_float translation[3]; + cgltf_float rotation[4]; + 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; +}; + +typedef struct cgltf_scene { + char* name; + cgltf_node** nodes; + cgltf_size nodes_count; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_scene; + +typedef struct cgltf_animation_sampler { + cgltf_accessor* input; + cgltf_accessor* output; + cgltf_interpolation_type interpolation; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_animation_sampler; + +typedef struct cgltf_animation_channel { + cgltf_animation_sampler* sampler; + cgltf_node* target_node; + cgltf_animation_path_type target_path; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_animation_channel; + +typedef struct cgltf_animation { + char* name; + cgltf_animation_sampler* samplers; + cgltf_size samplers_count; + cgltf_animation_channel* channels; + cgltf_size channels_count; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_animation; + +typedef struct cgltf_material_variant +{ + char* name; + cgltf_extras extras; +} cgltf_material_variant; + +typedef struct cgltf_asset { + char* copyright; + char* generator; + char* version; + char* min_version; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_asset; + +typedef struct cgltf_data +{ + cgltf_file_type file_type; + void* file_data; + + cgltf_asset asset; + + cgltf_mesh* meshes; + cgltf_size meshes_count; + + cgltf_material* materials; + cgltf_size materials_count; + + cgltf_accessor* accessors; + cgltf_size accessors_count; + + cgltf_buffer_view* buffer_views; + cgltf_size buffer_views_count; + + cgltf_buffer* buffers; + cgltf_size buffers_count; + + cgltf_image* images; + cgltf_size images_count; + + cgltf_texture* textures; + cgltf_size textures_count; + + cgltf_sampler* samplers; + cgltf_size samplers_count; + + cgltf_skin* skins; + cgltf_size skins_count; + + cgltf_camera* cameras; + cgltf_size cameras_count; + + cgltf_light* lights; + cgltf_size lights_count; + + cgltf_node* nodes; + cgltf_size nodes_count; + + cgltf_scene* scenes; + cgltf_size scenes_count; + + cgltf_scene* scene; + + cgltf_animation* animations; + cgltf_size animations_count; + + cgltf_material_variant* variants; + cgltf_size variants_count; + + cgltf_extras extras; + + cgltf_size data_extensions_count; + cgltf_extension* data_extensions; + + char** extensions_used; + cgltf_size extensions_used_count; + + char** extensions_required; + cgltf_size extensions_required_count; + + const char* json; + cgltf_size json_size; + + const void* bin; + cgltf_size bin_size; + + cgltf_memory_options memory; + cgltf_file_options file; +} cgltf_data; + +cgltf_result cgltf_parse( + const cgltf_options* options, + const void* data, + cgltf_size size, + cgltf_data** out_data); + +cgltf_result cgltf_parse_file( + const cgltf_options* options, + const char* path, + cgltf_data** out_data); + +cgltf_result cgltf_load_buffers( + const cgltf_options* options, + cgltf_data* data, + const char* gltf_path); + +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); + +cgltf_result cgltf_validate(cgltf_data* data); + +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 + +#endif /* #ifndef CGLTF_H_INCLUDED__ */ + +/* + * + * Stop now, if you are only interested in the API. + * Below, you find the implementation. + * + */ + +#if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__) +/* This makes MSVC/CLion intellisense work. */ +#define CGLTF_IMPLEMENTATION +#endif + +#ifdef CGLTF_IMPLEMENTATION + +#include /* For assert */ +#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) +#include /* For malloc, free, atoi, atof */ +#endif + +/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ +#define JSMN_PARENT_LINKS + +/* JSMN_STRICT is necessary to reject invalid JSON documents */ +#define JSMN_STRICT + +/* + * -- jsmn.h start -- + * Source: https://github.com/zserge/jsmn + * License: MIT + */ +typedef enum { + JSMN_UNDEFINED = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3, + JSMN_PRIMITIVE = 4 +} jsmntype_t; +enum jsmnerr { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +}; +typedef struct { + jsmntype_t type; + ptrdiff_t start; + ptrdiff_t end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; +typedef struct { + size_t 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; +static void jsmn_init(jsmn_parser *parser); +static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens); +/* + * -- jsmn.h end -- + */ + + +#ifndef CGLTF_CONSTS +#define GlbHeaderSize 12 +#define 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) +#endif +#ifndef CGLTF_FREE +#define CGLTF_FREE(ptr) free(ptr) +#endif +#ifndef CGLTF_ATOI +#define CGLTF_ATOI(str) atoi(str) +#endif +#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 + +static void* cgltf_default_alloc(void* user, cgltf_size size) +{ + (void)user; + return CGLTF_MALLOC(size); +} + +static void cgltf_default_free(void* user, void* ptr) +{ + (void)user; + CGLTF_FREE(ptr); +} + +static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_size count) +{ + if (SIZE_MAX / element_size < count) + { + return NULL; + } + void* result = options->memory.alloc_func(options->memory.user_data, element_size * count); + if (!result) + { + return NULL; + } + memset(result, 0, element_size * count); + return result; +} + +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; + + FILE* file = fopen(path, "rb"); + if (!file) + { + return cgltf_result_file_not_found; + } + + cgltf_size file_size = size ? *size : 0; + + if (file_size == 0) + { + fseek(file, 0, SEEK_END); + +#ifdef _MSC_VER + __int64 length = _ftelli64(file); +#else + long length = ftell(file); +#endif + + if (length < 0) + { + fclose(file); + return cgltf_result_io_error; + } + + fseek(file, 0, SEEK_SET); + file_size = (cgltf_size)length; + } + + char* file_data = (char*)memory_alloc(memory_options->user_data, file_size); + if (!file_data) + { + fclose(file); + return cgltf_result_out_of_memory; + } + + cgltf_size read_size = fread(file_data, 1, file_size, file); + + fclose(file); + + if (read_size != file_size) + { + memory_free(memory_options->user_data, file_data); + return cgltf_result_io_error; + } + + if (size) + { + *size = file_size; + } + if (data) + { + *data = file_data; + } + + return cgltf_result_success; +} + +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; + memfree(memory_options->user_data, data); +} + +static cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data); + +cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data) +{ + if (size < GlbHeaderSize) + { + return cgltf_result_data_too_short; + } + + if (options == NULL) + { + return cgltf_result_invalid_options; + } + + cgltf_options fixed_options = *options; + if (fixed_options.memory.alloc_func == NULL) + { + fixed_options.memory.alloc_func = &cgltf_default_alloc; + } + if (fixed_options.memory.free_func == NULL) + { + fixed_options.memory.free_func = &cgltf_default_free; + } + + uint32_t tmp; + // Magic + memcpy(&tmp, data, 4); + if (tmp != GlbMagic) + { + if (fixed_options.type == cgltf_file_type_invalid) + { + fixed_options.type = cgltf_file_type_gltf; + } + else if (fixed_options.type == cgltf_file_type_glb) + { + return cgltf_result_unknown_format; + } + } + + if (fixed_options.type == cgltf_file_type_gltf) + { + cgltf_result json_result = cgltf_parse_json(&fixed_options, (const uint8_t*)data, size, out_data); + if (json_result != cgltf_result_success) + { + return json_result; + } + + (*out_data)->file_type = cgltf_file_type_gltf; + + return cgltf_result_success; + } + + const uint8_t* ptr = (const uint8_t*)data; + // Version + memcpy(&tmp, ptr + 4, 4); + uint32_t version = tmp; + if (version != GlbVersion) + { + return version < GlbVersion ? cgltf_result_legacy_gltf : cgltf_result_unknown_format; + } + + // Total length + memcpy(&tmp, ptr + 8, 4); + if (tmp > size) + { + return cgltf_result_data_too_short; + } + + const uint8_t* json_chunk = ptr + GlbHeaderSize; + + if (GlbHeaderSize + GlbChunkHeaderSize > size) + { + return cgltf_result_data_too_short; + } + + // JSON chunk: length + uint32_t json_length; + memcpy(&json_length, json_chunk, 4); + if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize) + { + return cgltf_result_data_too_short; + } + + // JSON chunk: magic + memcpy(&tmp, json_chunk + 4, 4); + if (tmp != GlbMagicJsonChunk) + { + return cgltf_result_unknown_format; + } + + json_chunk += GlbChunkHeaderSize; + + const void* bin = NULL; + cgltf_size bin_size = 0; + + if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length) + { + // We can read another chunk + const uint8_t* bin_chunk = json_chunk + json_length; + + // Bin chunk: length + uint32_t bin_length; + memcpy(&bin_length, bin_chunk, 4); + if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize) + { + return cgltf_result_data_too_short; + } + + // Bin chunk: magic + memcpy(&tmp, bin_chunk + 4, 4); + if (tmp != GlbMagicBinChunk) + { + return cgltf_result_unknown_format; + } + + bin_chunk += GlbChunkHeaderSize; + + bin = bin_chunk; + bin_size = bin_length; + } + + cgltf_result json_result = cgltf_parse_json(&fixed_options, json_chunk, json_length, out_data); + if (json_result != cgltf_result_success) + { + return json_result; + } + + (*out_data)->file_type = cgltf_file_type_glb; + (*out_data)->bin = bin; + (*out_data)->bin_size = bin_size; + + return cgltf_result_success; +} + +cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cgltf_data** out_data) +{ + if (options == NULL) + { + return cgltf_result_invalid_options; + } + + 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; + cgltf_result result = file_read(&options->memory, &options->file, path, &file_size, &file_data); + if (result != cgltf_result_success) + { + return result; + } + + result = cgltf_parse(options, file_data, file_size, out_data); + + if (result != cgltf_result_success) + { + file_release(&options->memory, &options->file, file_data); + return result; + } + + (*out_data)->file_data = file_data; + + return cgltf_result_success; +} + +static void cgltf_combine_paths(char* path, const char* base, const char* uri) +{ + const char* s0 = strrchr(base, '/'); + const char* s1 = strrchr(base, '\\'); + const char* slash = s0 ? (s1 && s1 > s0 ? s1 : s0) : s1; + + if (slash) + { + size_t prefix = slash - base + 1; + + strncpy(path, base, prefix); + strcpy(path + prefix, uri); + } + else + { + strcpy(path, 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; + 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); + if (!path) + { + return cgltf_result_out_of_memory; + } + + cgltf_combine_paths(path, gltf_path, uri); + + // after combining, the tail of the resulting path is a uri; decode_uri converts it into path + cgltf_decode_uri(path + strlen(path) - strlen(uri)); + + void* file_data = NULL; + cgltf_result result = file_read(&options->memory, &options->file, path, &size, &file_data); + + memory_free(options->memory.user_data, path); + + *out_data = (result == cgltf_result_success) ? file_data : NULL; + + return result; +} + +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; + + unsigned char* data = (unsigned char*)memory_alloc(options->memory.user_data, size); + if (!data) + { + return cgltf_result_out_of_memory; + } + + unsigned int buffer = 0; + unsigned int buffer_bits = 0; + + for (cgltf_size i = 0; i < size; ++i) + { + while (buffer_bits < 8) + { + char ch = *base64++; + + int index = + (unsigned)(ch - 'A') < 26 ? (ch - 'A') : + (unsigned)(ch - 'a') < 26 ? (ch - 'a') + 26 : + (unsigned)(ch - '0') < 10 ? (ch - '0') + 52 : + ch == '+' ? 62 : + ch == '/' ? 63 : + -1; + + if (index < 0) + { + memory_free(options->memory.user_data, data); + return cgltf_result_io_error; + } + + buffer = (buffer << 6) | index; + buffer_bits += 6; + } + + data[i] = (unsigned char)(buffer >> (buffer_bits - 8)); + buffer_bits -= 8; + } + + *out_data = data; + + return cgltf_result_success; +} + +static int cgltf_unhex(char ch) +{ + return + (unsigned)(ch - '0') < 10 ? (ch - '0') : + (unsigned)(ch - 'A') < 6 ? (ch - 'A') + 10 : + (unsigned)(ch - 'a') < 6 ? (ch - 'a') + 10 : + -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) +{ + char* write = uri; + char* i = uri; + + while (*i) + { + if (*i == '%') + { + int ch1 = cgltf_unhex(i[1]); + + if (ch1 >= 0) + { + int ch2 = cgltf_unhex(i[2]); + + if (ch2 >= 0) + { + *write++ = (char)(ch1 * 16 + ch2); + i += 3; + continue; + } + } + } + + *write++ = *i++; + } + + *write = 0; + return write - uri; +} + +cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path) +{ + if (options == NULL) + { + return cgltf_result_invalid_options; + } + + if (data->buffers_count && data->buffers[0].data == NULL && data->buffers[0].uri == NULL && data->bin) + { + if (data->bin_size < data->buffers[0].size) + { + return cgltf_result_data_too_short; + } + + 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) + { + if (data->buffers[i].data) + { + continue; + } + + const char* uri = data->buffers[i].uri; + + if (uri == NULL) + { + continue; + } + + if (strncmp(uri, "data:", 5) == 0) + { + const char* comma = strchr(uri, ','); + + 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) + { + return res; + } + } + else + { + return cgltf_result_unknown_format; + } + } + 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) + { + return res; + } + } + else + { + return cgltf_result_unknown_format; + } + } + + return cgltf_result_success; +} + +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; + cgltf_size bound = 0; + + switch (component_type) + { + case cgltf_component_type_r_8u: + for (size_t i = 0; i < count; ++i) + { + cgltf_size v = ((unsigned char*)data)[i]; + bound = bound > v ? bound : v; + } + break; + + case cgltf_component_type_r_16u: + for (size_t i = 0; i < count; ++i) + { + cgltf_size v = ((unsigned short*)data)[i]; + bound = bound > v ? bound : v; + } + break; + + case cgltf_component_type_r_32u: + for (size_t i = 0; i < count; ++i) + { + cgltf_size v = ((unsigned int*)data)[i]; + bound = bound > v ? bound : v; + } + break; + + default: + ; + } + + return bound; +} + +#if CGLTF_VALIDATE_ENABLE_ASSERTS +#define CGLTF_ASSERT_IF(cond, result) assert(!(cond)); if (cond) return result; +#else +#define CGLTF_ASSERT_IF(cond, result) if (cond) return result; +#endif + +cgltf_result cgltf_validate(cgltf_data* data) +{ + for (cgltf_size i = 0; i < data->accessors_count; ++i) + { + 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) + { + cgltf_size req_size = accessor->offset + accessor->stride * (accessor->count - 1) + element_size; + + CGLTF_ASSERT_IF(accessor->buffer_view->size < req_size, cgltf_result_data_too_short); + } + + if (accessor->is_sparse) + { + cgltf_accessor_sparse* sparse = &accessor->sparse; + + cgltf_size indices_component_size = cgltf_component_size(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; + + CGLTF_ASSERT_IF(sparse->indices_buffer_view->size < indices_req_size || + sparse->values_buffer_view->size < values_req_size, cgltf_result_data_too_short); + + CGLTF_ASSERT_IF(sparse->indices_component_type != cgltf_component_type_r_8u && + sparse->indices_component_type != cgltf_component_type_r_16u && + sparse->indices_component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); + + if (sparse->indices_buffer_view->buffer->data) + { + cgltf_size index_bound = cgltf_calc_index_bound(sparse->indices_buffer_view, sparse->indices_byte_offset, sparse->indices_component_type, sparse->count); + + CGLTF_ASSERT_IF(index_bound >= accessor->count, cgltf_result_data_too_short); + } + } + } + + for (cgltf_size i = 0; i < data->buffer_views_count; ++i) + { + cgltf_size req_size = data->buffer_views[i].offset + data->buffer_views[i].size; + + CGLTF_ASSERT_IF(data->buffer_views[i].buffer && data->buffer_views[i].buffer->size < req_size, cgltf_result_data_too_short); + + if (data->buffer_views[i].has_meshopt_compression) + { + cgltf_meshopt_compression* mc = &data->buffer_views[i].meshopt_compression; + + CGLTF_ASSERT_IF(mc->buffer == NULL || mc->buffer->size < mc->offset + mc->size, cgltf_result_data_too_short); + + CGLTF_ASSERT_IF(data->buffer_views[i].stride && mc->stride != data->buffer_views[i].stride, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(data->buffer_views[i].size != mc->stride * mc->count, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_invalid, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_attributes && !(mc->stride % 4 == 0 && mc->stride <= 256), cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_triangles && mc->count % 3 != 0, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->stride != 2 && mc->stride != 4, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->filter != cgltf_meshopt_compression_filter_none, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_octahedral && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf); + + CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_quaternion && mc->stride != 8, cgltf_result_invalid_gltf); + } + } + + for (cgltf_size i = 0; i < data->meshes_count; ++i) + { + if (data->meshes[i].weights) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].weights_count, cgltf_result_invalid_gltf); + } + + if (data->meshes[i].target_names) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].target_names_count, cgltf_result_invalid_gltf); + } + + 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) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); + } + + 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_accessor* indices = data->meshes[i].primitives[j].indices; + + 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_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); + + 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); + } + + 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 i = 0; i < data->nodes_count; ++i) + { + 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); + } + } + } + + for (cgltf_size i = 0; i < data->nodes_count; ++i) + { + cgltf_node* p1 = data->nodes[i].parent; + cgltf_node* p2 = p1 ? p1->parent : NULL; + + while (p1 && p2) + { + CGLTF_ASSERT_IF(p1 == p2, cgltf_result_invalid_gltf); + + p1 = p1->parent; + p2 = p2->parent ? p2->parent->parent : NULL; + } + } + + for (cgltf_size i = 0; i < data->scenes_count; ++i) + { + for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j) + { + CGLTF_ASSERT_IF(data->scenes[i].nodes[j]->parent, cgltf_result_invalid_gltf); + } + } + + for (cgltf_size i = 0; i < data->animations_count; ++i) + { + for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j) + { + cgltf_animation_channel* channel = &data->animations[i].channels[j]; + + if (!channel->target_node) + { + continue; + } + + cgltf_size components = 1; + + if (channel->target_path == cgltf_animation_path_type_weights) + { + CGLTF_ASSERT_IF(!channel->target_node->mesh || !channel->target_node->mesh->primitives_count, cgltf_result_invalid_gltf); + + components = channel->target_node->mesh->primitives[0].targets_count; + } + + 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); + } + } + + 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; +} + +cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size) +{ + cgltf_size json_size = extras->end_offset - extras->start_offset; + + if (!dest) + { + if (dest_size) + { + *dest_size = json_size + 1; + return cgltf_result_success; + } + return cgltf_result_invalid_options; + } + + if (*dest_size + 1 < json_size) + { + strncpy(dest, data->json + extras->start_offset, *dest_size - 1); + dest[*dest_size - 1] = 0; + } + else + { + strncpy(dest, data->json + extras->start_offset, json_size); + dest[json_size] = 0; + } + + 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) +{ + 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_func(data->memory.user_data, extensions); +} + +void cgltf_free(cgltf_data* data) +{ + if (!data) + { + return; + } + + 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); + + 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); + + 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); + + 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); + + 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); + + for (cgltf_size i = 0; i < data->buffers_count; ++i) + { + data->memory.free_func(data->memory.user_data, data->buffers[i].name); + + if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release) + { + 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); + + 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); + + for (cgltf_size i = 0; i < data->meshes_count; ++i) + { + data->memory.free_func(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_func(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_func(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); + + 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_func(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); + + 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); + + 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]); + } + + 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_func(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); + + 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); + + 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); + + 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); + + for (cgltf_size i = 0; i < data->textures_count; ++i) + { + data->memory.free_func(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); + + for (cgltf_size i = 0; i < data->samplers_count; ++i) + { + data->memory.free_func(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); + + 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); + + 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); + + 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); + } + + 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); + + 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_func(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); + } + + 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); + + 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); + + 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); + + for (cgltf_size i = 0; i < data->animations_count; ++i) + { + data->memory.free_func(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); + + 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); + + 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); + + 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_func(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_func(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_func(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); +} + +void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix) +{ + cgltf_float* lm = out_matrix; + + if (node->has_matrix) + { + memcpy(lm, node->matrix, sizeof(float) * 16); + } + else + { + float tx = node->translation[0]; + float ty = node->translation[1]; + float tz = node->translation[2]; + + float qx = node->rotation[0]; + float qy = node->rotation[1]; + float qz = node->rotation[2]; + float qw = node->rotation[3]; + + float sx = node->scale[0]; + float sy = node->scale[1]; + float sz = node->scale[2]; + + lm[0] = (1 - 2 * qy*qy - 2 * qz*qz) * sx; + lm[1] = (2 * qx*qy + 2 * qz*qw) * sx; + lm[2] = (2 * qx*qz - 2 * qy*qw) * sx; + lm[3] = 0.f; + + lm[4] = (2 * qx*qy - 2 * qz*qw) * sy; + lm[5] = (1 - 2 * qx*qx - 2 * qz*qz) * sy; + lm[6] = (2 * qy*qz + 2 * qx*qw) * sy; + lm[7] = 0.f; + + lm[8] = (2 * qx*qz + 2 * qy*qw) * sz; + lm[9] = (2 * qy*qz - 2 * qx*qw) * sz; + lm[10] = (1 - 2 * qx*qx - 2 * qy*qy) * sz; + lm[11] = 0.f; + + lm[12] = tx; + lm[13] = ty; + lm[14] = tz; + lm[15] = 1.f; + } +} + +void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix) +{ + cgltf_float* lm = out_matrix; + cgltf_node_transform_local(node, lm); + + const cgltf_node* parent = node->parent; + + while (parent) + { + float pm[16]; + cgltf_node_transform_local(parent, pm); + + for (int i = 0; i < 4; ++i) + { + float l0 = lm[i * 4 + 0]; + float l1 = lm[i * 4 + 1]; + float l2 = lm[i * 4 + 2]; + + float r0 = l0 * pm[0] + l1 * pm[4] + l2 * pm[8]; + float r1 = l0 * pm[1] + l1 * pm[5] + l2 * pm[9]; + float r2 = l0 * pm[2] + l1 * pm[6] + l2 * pm[10]; + + lm[i * 4 + 0] = r0; + lm[i * 4 + 1] = r1; + lm[i * 4 + 2] = r2; + } + + lm[12] += pm[12]; + lm[13] += pm[13]; + lm[14] += pm[14]; + + parent = parent->parent; + } +} + +static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_type component_type) +{ + switch (component_type) + { + case cgltf_component_type_r_16: + return *((const int16_t*) in); + 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_8: + return *((const int8_t*) in); + case cgltf_component_type_r_8u: + return *((const uint8_t*) in); + default: + return 0; + } +} + +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) + { + return *((const float*) in); + } + + if (normalized) + { + switch (component_type) + { + // note: glTF spec doesn't currently define normalized conversions for 32-bit integers + case cgltf_component_type_r_16: + return *((const int16_t*) in) / (cgltf_float)32767; + case cgltf_component_type_r_16u: + return *((const uint16_t*) in) / (cgltf_float)65535; + case cgltf_component_type_r_8: + return *((const int8_t*) in) / (cgltf_float)127; + case cgltf_component_type_r_8u: + return *((const uint8_t*) in) / (cgltf_float)255; + default: + return 0; + } + } + + return (cgltf_float)cgltf_component_read_integer(in, 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); + + if (element_size < num_components) { + return 0; + } + + // There are three special cases for component extraction, see #data-alignment in the 2.0 spec. + + cgltf_size component_size = cgltf_component_size(component_type); + + if (type == cgltf_type_mat2 && component_size == 1) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 1, component_type, normalized); + out[2] = cgltf_component_read_float(element + 4, component_type, normalized); + out[3] = cgltf_component_read_float(element + 5, component_type, normalized); + return 1; + } + + if (type == cgltf_type_mat3 && component_size == 1) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 1, component_type, normalized); + out[2] = cgltf_component_read_float(element + 2, component_type, normalized); + out[3] = cgltf_component_read_float(element + 4, component_type, normalized); + out[4] = cgltf_component_read_float(element + 5, component_type, normalized); + out[5] = cgltf_component_read_float(element + 6, component_type, normalized); + out[6] = cgltf_component_read_float(element + 8, component_type, normalized); + out[7] = cgltf_component_read_float(element + 9, component_type, normalized); + out[8] = cgltf_component_read_float(element + 10, component_type, normalized); + return 1; + } + + if (type == cgltf_type_mat3 && component_size == 2) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 2, component_type, normalized); + out[2] = cgltf_component_read_float(element + 4, component_type, normalized); + out[3] = cgltf_component_read_float(element + 8, component_type, normalized); + out[4] = cgltf_component_read_float(element + 10, component_type, normalized); + out[5] = cgltf_component_read_float(element + 12, component_type, normalized); + out[6] = cgltf_component_read_float(element + 16, component_type, normalized); + out[7] = cgltf_component_read_float(element + 18, component_type, normalized); + out[8] = cgltf_component_read_float(element + 20, component_type, normalized); + return 1; + } + + for (cgltf_size i = 0; i < num_components; ++i) + { + out[i] = cgltf_component_read_float(element + component_size * i, component_type, normalized); + } + return 1; +} + +const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view) +{ + if (view->data) + return (const uint8_t*)view->data; + + if (!view->buffer->data) + return NULL; + + const uint8_t* result = (const uint8_t*)view->buffer->data; + result += view->offset; + return result; +} + +cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size) +{ + if (accessor->is_sparse) + { + return 0; + } + if (accessor->buffer_view == NULL) + { + memset(out, 0, element_size * sizeof(cgltf_float)); + return 1; + } + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) + { + return 0; + } + element += accessor->offset + accessor->stride * index; + return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size); +} + +cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count) +{ + cgltf_size floats_per_element = cgltf_num_components(accessor->type); + cgltf_size available_floats = accessor->count * floats_per_element; + if (out == NULL) + { + return available_floats; + } + + float_count = available_floats < float_count ? available_floats : float_count; + cgltf_size element_count = float_count / floats_per_element; + + // First pass: convert each element in the base accessor. + if (accessor->buffer_view == NULL) + { + 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) + { + 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 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); + + if (index_data == NULL || reader_head == NULL) + { + return 0; + } + + index_data += sparse->indices_byte_offset; + 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) + { + 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)) + { + return 0; + } + } + } + + return element_count * floats_per_element; +} + +static cgltf_uint cgltf_component_read_uint(const void* in, cgltf_component_type component_type) +{ + switch (component_type) + { + case cgltf_component_type_r_8: + return *((const int8_t*) in); + + case cgltf_component_type_r_8u: + return *((const uint8_t*) in); + + case cgltf_component_type_r_16: + return *((const int16_t*) in); + + case cgltf_component_type_r_16u: + return *((const uint16_t*) in); + + case cgltf_component_type_r_32u: + return *((const uint32_t*) in); + + default: + return 0; + } +} + +static cgltf_bool cgltf_element_read_uint(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_uint* out, cgltf_size element_size) +{ + cgltf_size num_components = cgltf_num_components(type); + + if (element_size < num_components) + { + return 0; + } + + // Reading integer matrices is not a valid use case + if (type == cgltf_type_mat2 || type == cgltf_type_mat3 || type == cgltf_type_mat4) + { + return 0; + } + + cgltf_size component_size = cgltf_component_size(component_type); + + for (cgltf_size i = 0; i < num_components; ++i) + { + out[i] = cgltf_component_read_uint(element + component_size * i, component_type); + } + return 1; +} + +cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size) +{ + if (accessor->is_sparse) + { + return 0; + } + if (accessor->buffer_view == NULL) + { + memset(out, 0, element_size * sizeof( cgltf_uint )); + return 1; + } + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) + { + return 0; + } + element += accessor->offset + accessor->stride * index; + return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size); +} + +cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index) +{ + if (accessor->is_sparse) + { + return 0; // This is an error case, but we can't communicate the error with existing interface. + } + if (accessor->buffer_view == NULL) + { + return 0; + } + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) + { + return 0; // This is an error case, but we can't communicate the error with existing interface. + } + element += accessor->offset + accessor->stride * index; + 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) +#define CGLTF_PTRFIXUP(var, data, size) if (var) { if ((cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; } +#define CGLTF_PTRFIXUP_REQ(var, data, size) if (!var || (cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; + +static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, const char* str) +{ + CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); + size_t const str_len = strlen(str); + size_t const name_length = (size_t)(tok->end - tok->start); + return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; +} + +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); + 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); + strncpy(tmp, (const char*)json_chunk + tok->start, size); + tmp[size] = 0; + return (cgltf_float)CGLTF_ATOF(tmp); +} + +static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) +{ + int size = (int)(tok->end - tok->start); + return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; +} + +static int cgltf_skip_json(jsmntok_t const* tokens, int i) +{ + int end = i + 1; + + while (i < end) + { + switch (tokens[i].type) + { + case JSMN_OBJECT: + end += tokens[i].size * 2; + break; + + case JSMN_ARRAY: + end += tokens[i].size; + break; + + case JSMN_PRIMITIVE: + case JSMN_STRING: + break; + + default: + return -1; + } + + i++; + } + + return i; +} + +static void cgltf_fill_float_array(float* out_array, int size, float value) +{ + for (int j = 0; j < size; ++j) + { + out_array[j] = value; + } +} + +static int cgltf_parse_json_float_array(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, float* out_array, int size) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); + if (tokens[i].size != size) + { + return CGLTF_ERROR_JSON; + } + ++i; + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_array[j] = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + return i; +} + +static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char** out_string) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING); + if (*out_string) + { + 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); + if (!result) + { + return CGLTF_ERROR_NOMEM; + } + strncpy(result, (const char*)json_chunk + tokens[i].start, size); + result[size] = 0; + *out_string = result; + return i + 1; +} + +static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, size_t element_size, void** out_array, cgltf_size* out_size) +{ + (void)json_chunk; + if (tokens[i].type != JSMN_ARRAY) + { + return tokens[i].type == JSMN_OBJECT ? CGLTF_ERROR_LEGACY : CGLTF_ERROR_JSON; + } + if (*out_array) + { + return CGLTF_ERROR_JSON; + } + int size = tokens[i].size; + void* result = cgltf_calloc(options, element_size, size); + if (!result) + { + return CGLTF_ERROR_NOMEM; + } + *out_array = result; + *out_size = size; + return i + 1; +} + +static int cgltf_parse_json_string_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char*** out_array, cgltf_size* out_size) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(char*), (void**)out_array, out_size); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < *out_size; ++j) + { + i = cgltf_parse_json_string(options, tokens, i, json_chunk, j + (*out_array)); + if (i < 0) + { + return i; + } + } + return i; +} + +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); + + if (len == 8 && strncmp(name, "POSITION", 8) == 0) + { + *out_type = cgltf_attribute_type_position; + } + else if (len == 6 && strncmp(name, "NORMAL", 6) == 0) + { + *out_type = cgltf_attribute_type_normal; + } + else if (len == 7 && strncmp(name, "TANGENT", 7) == 0) + { + *out_type = cgltf_attribute_type_tangent; + } + else if (len == 8 && strncmp(name, "TEXCOORD", 8) == 0) + { + *out_type = cgltf_attribute_type_texcoord; + } + else if (len == 5 && strncmp(name, "COLOR", 5) == 0) + { + *out_type = cgltf_attribute_type_color; + } + else if (len == 6 && strncmp(name, "JOINTS", 6) == 0) + { + *out_type = cgltf_attribute_type_joints; + } + else if (len == 7 && strncmp(name, "WEIGHTS", 7) == 0) + { + *out_type = cgltf_attribute_type_weights; + } + else + { + *out_type = cgltf_attribute_type_invalid; + } + + 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; + } + } +} + +static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_attribute** out_attributes, cgltf_size* out_attributes_count) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + if (*out_attributes) + { + return CGLTF_ERROR_JSON; + } + + *out_attributes_count = tokens[i].size; + *out_attributes = (cgltf_attribute*)cgltf_calloc(options, sizeof(cgltf_attribute), *out_attributes_count); + ++i; + + if (!*out_attributes) + { + return CGLTF_ERROR_NOMEM; + } + + for (cgltf_size j = 0; j < *out_attributes_count; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + i = cgltf_parse_json_string(options, tokens, i, json_chunk, &(*out_attributes)[j].name); + if (i < 0) + { + return CGLTF_ERROR_JSON; + } + + cgltf_parse_attribute_type((*out_attributes)[j].name, &(*out_attributes)[j].type, &(*out_attributes)[j].index); + + (*out_attributes)[j].data = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + + 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) +{ + if (out_extras->data) + { + return CGLTF_ERROR_JSON; + } + + /* fill deprecated fields for now, this will be removed in the future */ + 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; +} + +static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extension* out_extension) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING); + CGLTF_CHECK_TOKTYPE(tokens[i+1], JSMN_OBJECT); + if (out_extension->name) + { + return CGLTF_ERROR_JSON; + } + + 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); + if (!out_extension->name) + { + return CGLTF_ERROR_NOMEM; + } + strncpy(out_extension->name, (const char*)json_chunk + tokens[i].start, name_length); + out_extension->name[name_length] = 0; + i++; + + 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); + if (!out_extension->data) + { + return CGLTF_ERROR_NOMEM; + } + strncpy(out_extension->data, (const char*)json_chunk + start, size); + out_extension->data[size] = '\0'; + + i = cgltf_skip_json(tokens, i); + + return i; +} + +static int cgltf_parse_json_unprocessed_extensions(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_size* out_extensions_count, cgltf_extension** out_extensions) +{ + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(*out_extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + *out_extensions_count = 0; + *out_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!*out_extensions) + { + return CGLTF_ERROR_NOMEM; + } + + ++i; + + for (int j = 0; j < extensions_size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + cgltf_size extension_index = (*out_extensions_count)++; + cgltf_extension* extension = &((*out_extensions)[extension_index]); + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, extension); + + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_draco_mesh_compression* out_draco_mesh_compression) +{ + 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_draco_mesh_compression->attributes, &out_draco_mesh_compression->attributes_count); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0) + { + ++i; + 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) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_mapping* out_mappings, cgltf_size* offset) +{ + (void)options; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); + + int size = tokens[i].size; + ++i; + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int obj_size = tokens[i].size; + ++i; + + int material = -1; + int variants_tok = -1; + int extras_tok = -1; + + for (int k = 0; k < obj_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "material") == 0) + { + ++i; + material = cgltf_json_to_int(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0) + { + variants_tok = i+1; + CGLTF_CHECK_TOKTYPE(tokens[variants_tok], JSMN_ARRAY); + + i = cgltf_skip_json(tokens, i+1); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + extras_tok = i + 1; + i = cgltf_skip_json(tokens, extras_tok); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + if (material < 0 || variants_tok < 0) + { + return CGLTF_ERROR_JSON; + } + + if (out_mappings) + { + for (int k = 0; k < tokens[variants_tok].size; ++k) + { + int variant = cgltf_json_to_int(&tokens[variants_tok + 1 + k], json_chunk); + if (variant < 0) + return variant; + + 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; + } + + (*offset)++; + } + } + else + { + (*offset) += tokens[variants_tok].size; + } + } + + return i; +} + +static int cgltf_parse_json_material_mappings(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); + + 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, "mappings") == 0) + { + if (out_prim->mappings) + { + return CGLTF_ERROR_JSON; + } + + cgltf_size mappings_offset = 0; + int k = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, NULL, &mappings_offset); + if (k < 0) + { + return k; + } + + out_prim->mappings_count = mappings_offset; + out_prim->mappings = (cgltf_material_mapping*)cgltf_calloc(options, sizeof(cgltf_material_mapping), out_prim->mappings_count); + + mappings_offset = 0; + i = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, out_prim->mappings, &mappings_offset); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + 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); + + out_prim->type = cgltf_primitive_type_triangles; + + 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, "mode") == 0) + { + ++i; + out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) + { + ++i; + out_prim->indices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "material") == 0) + { + ++i; + out_prim->material = CGLTF_PTRINDEX(cgltf_material, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "attributes") == 0) + { + i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_prim->attributes, &out_prim->attributes_count); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "targets") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_morph_target), (void**)&out_prim->targets, &out_prim->targets_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_prim->targets_count; ++k) + { + i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count); + if (i < 0) + { + return i; + } + } + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_prim->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + out_prim->extensions_count = 0; + out_prim->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!out_prim->extensions) + { + return CGLTF_ERROR_NOMEM; + } + + ++i; + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_draco_mesh_compression") == 0) + { + out_prim->has_draco_mesh_compression = 1; + i = cgltf_parse_json_draco_mesh_compression(options, tokens, i + 1, json_chunk, &out_prim->draco_mesh_compression); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0) + { + i = cgltf_parse_json_material_mappings(options, tokens, i + 1, json_chunk, out_prim); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_prim->extensions[out_prim->extensions_count++])); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh* out_mesh) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_mesh->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "primitives") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_primitive), (void**)&out_mesh->primitives, &out_mesh->primitives_count); + if (i < 0) + { + return i; + } + + for (cgltf_size prim_index = 0; prim_index < out_mesh->primitives_count; ++prim_index) + { + i = cgltf_parse_json_primitive(options, tokens, i, json_chunk, &out_mesh->primitives[prim_index]); + if (i < 0) + { + return i; + } + } + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_mesh->weights, &out_mesh->weights_count); + if (i < 0) + { + return i; + } + + i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_mesh->weights, (int)out_mesh->weights_count); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + ++i; + + out_mesh->extras.start_offset = tokens[i].start; + out_mesh->extras.end_offset = tokens[i].end; + + if (tokens[i].type == JSMN_OBJECT) + { + int extras_size = tokens[i].size; + ++i; + + for (int k = 0; k < extras_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "targetNames") == 0 && tokens[i+1].type == JSMN_ARRAY) + { + i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_mesh->target_names, &out_mesh->target_names_count); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i); + } + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_mesh->extensions_count, &out_mesh->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_meshes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_mesh), (void**)&out_data->meshes, &out_data->meshes_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->meshes_count; ++j) + { + i = cgltf_parse_json_mesh(options, tokens, i, json_chunk, &out_data->meshes[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, const uint8_t* json_chunk) +{ + int type = cgltf_json_to_int(tok, json_chunk); + + switch (type) + { + case 5120: + return cgltf_component_type_r_8; + case 5121: + return cgltf_component_type_r_8u; + case 5122: + return cgltf_component_type_r_16; + case 5123: + return cgltf_component_type_r_16u; + case 5125: + return cgltf_component_type_r_32u; + case 5126: + return cgltf_component_type_r_32f; + default: + return cgltf_component_type_invalid; + } +} + +static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) +{ + 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, "count") == 0) + { + ++i; + out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int indices_size = tokens[i].size; + ++i; + + for (int k = 0; k < indices_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0) + { + ++i; + out_sparse->indices_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + 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); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0) + { + ++i; + out_sparse->indices_component_type = cgltf_json_to_component_type(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, "values") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int values_size = tokens[i].size; + ++i; + + for (int k = 0; k < values_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0) + { + ++i; + out_sparse->values_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + 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); + ++i; + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor* out_accessor) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_accessor->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0) + { + ++i; + out_accessor->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) + { + ++i; + out_accessor->offset = + cgltf_json_to_size(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0) + { + ++i; + out_accessor->component_type = cgltf_json_to_component_type(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "normalized") == 0) + { + ++i; + out_accessor->normalized = cgltf_json_to_bool(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) + { + ++i; + out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens+i, json_chunk, "SCALAR") == 0) + { + out_accessor->type = cgltf_type_scalar; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC2") == 0) + { + out_accessor->type = cgltf_type_vec2; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC3") == 0) + { + out_accessor->type = cgltf_type_vec3; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC4") == 0) + { + out_accessor->type = cgltf_type_vec4; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT2") == 0) + { + out_accessor->type = cgltf_type_mat2; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT3") == 0) + { + out_accessor->type = cgltf_type_mat3; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT4") == 0) + { + out_accessor->type = cgltf_type_mat4; + } + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "min") == 0) + { + ++i; + out_accessor->has_min = 1; + // note: we can't parse the precise number of elements since type may not have been computed yet + int min_size = tokens[i].size > 16 ? 16 : tokens[i].size; + i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->min, min_size); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "max") == 0) + { + ++i; + out_accessor->has_max = 1; + // note: we can't parse the precise number of elements since type may not have been computed yet + int max_size = tokens[i].size > 16 ? 16 : tokens[i].size; + i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->max, max_size); + } + 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); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_accessor->extensions_count, &out_accessor->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_transform* out_texture_transform) +{ + 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, "offset") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->offset, 2); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "rotation") == 0) + { + ++i; + out_texture_transform->rotation = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->scale, 2); + } + 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; + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +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; + cgltf_fill_float_array(out_texture_view->transform.scale, 2, 1.0f); + + 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, "index") == 0) + { + ++i; + out_texture_view->texture = CGLTF_PTRINDEX(cgltf_texture, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0) + { + ++i; + out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) + { + ++i; + out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "strength") == 0) + { + ++i; + out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int extensions_size = tokens[i].size; + + ++i; + + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_texture_transform") == 0) + { + out_texture_view->has_transform = 1; + i = cgltf_parse_json_texture_transform(tokens, i + 1, json_chunk, &out_texture_view->transform); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_metallic_roughness* out_pbr) +{ + 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, "metallicFactor") == 0) + { + ++i; + out_pbr->metallic_factor = + cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) + { + ++i; + out_pbr->roughness_factor = + cgltf_json_to_float(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->base_color_factor, 4); + } + 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); + } + 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); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_pbr_specular_glossiness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_specular_glossiness* out_pbr) +{ + 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, "diffuseFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->diffuse_factor, 4); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->specular_factor, 3); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "glossinessFactor") == 0) + { + ++i; + out_pbr->glossiness_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->diffuse_texture); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularGlossinessTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->specular_glossiness_texture); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_clearcoat(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_clearcoat* out_clearcoat) +{ + 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, "clearcoatFactor") == 0) + { + ++i; + out_clearcoat->clearcoat_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessFactor") == 0) + { + ++i; + out_clearcoat->clearcoat_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_texture); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_roughness_texture); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatNormalTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_normal_texture); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_ior(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_ior* out_ior) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + // Default values + out_ior->ior = 1.5f; + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "ior") == 0) + { + ++i; + out_ior->ior = 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_specular(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_specular* out_specular) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + // Default values + out_specular->specular_factor = 1.0f; + cgltf_fill_float_array(out_specular->specular_color_factor, 3, 1.0f); + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0) + { + ++i; + out_specular->specular_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularColorFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_specular->specular_color_factor, 3); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "specularColorTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_color_texture); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_transmission(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_transmission* out_transmission) +{ + 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, "transmissionFactor") == 0) + { + ++i; + out_transmission->transmission_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "transmissionTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_transmission->transmission_texture); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_volume(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_volume* out_volume) +{ + 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, "thicknessFactor") == 0) + { + ++i; + out_volume->thickness_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "thicknessTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_volume->thickness_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationColor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_volume->attenuation_color, 3); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationDistance") == 0) + { + ++i; + out_volume->attenuation_distance = 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_sheen(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sheen* out_sheen) +{ + 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, "sheenColorFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_sheen->sheen_color_factor, 3); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenColorTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_color_texture); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessFactor") == 0) + { + ++i; + out_sheen->sheen_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_roughness_texture); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + 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); + + 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, "uri") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0) + { + ++i; + out_image->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "mimeType") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->mime_type); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->name); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_image->extensions_count, &out_image->extensions); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler) +{ + (void)options; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + out_sampler->wrap_s = 10497; + out_sampler->wrap_t = 10497; + + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_sampler->name); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "magFilter") == 0) + { + ++i; + out_sampler->mag_filter + = cgltf_json_to_int(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "minFilter") == 0) + { + ++i; + out_sampler->min_filter + = cgltf_json_to_int(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapS") == 0) + { + ++i; + out_sampler->wrap_s + = cgltf_json_to_int(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) + { + ++i; + out_sampler->wrap_t + = 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(options, tokens, i + 1, json_chunk, &out_sampler->extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture* out_texture) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_texture->name); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "sampler") == 0) + { + ++i; + 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) + { + ++i; + out_texture->image = CGLTF_PTRINDEX(cgltf_image, 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(options, 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; + } + } + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material* out_material) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + cgltf_fill_float_array(out_material->pbr_metallic_roughness.base_color_factor, 4, 1.0f); + out_material->pbr_metallic_roughness.metallic_factor = 1.0f; + out_material->pbr_metallic_roughness.roughness_factor = 1.0f; + + cgltf_fill_float_array(out_material->pbr_specular_glossiness.diffuse_factor, 4, 1.0f); + cgltf_fill_float_array(out_material->pbr_specular_glossiness.specular_factor, 3, 1.0f); + out_material->pbr_specular_glossiness.glossiness_factor = 1.0f; + + cgltf_fill_float_array(out_material->volume.attenuation_color, 3, 1.0f); + out_material->volume.attenuation_distance = FLT_MAX; + + out_material->alpha_cutoff = 0.5f; + + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_material->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "pbrMetallicRoughness") == 0) + { + out_material->has_pbr_metallic_roughness = 1; + i = cgltf_parse_json_pbr_metallic_roughness(options, tokens, i + 1, json_chunk, &out_material->pbr_metallic_roughness); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "emissiveFactor") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_material->emissive_factor, 3); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "normalTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, + &out_material->normal_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "occlusionTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, + &out_material->occlusion_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, + &out_material->emissive_texture); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaMode") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens + i, json_chunk, "OPAQUE") == 0) + { + out_material->alpha_mode = cgltf_alpha_mode_opaque; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "MASK") == 0) + { + out_material->alpha_mode = cgltf_alpha_mode_mask; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "BLEND") == 0) + { + out_material->alpha_mode = cgltf_alpha_mode_blend; + } + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaCutoff") == 0) + { + ++i; + out_material->alpha_cutoff = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "doubleSided") == 0) + { + ++i; + out_material->double_sided = + cgltf_json_to_bool(tokens + i, json_chunk); + ++i; + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_material->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + ++i; + out_material->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + out_material->extensions_count= 0; + + if (!out_material->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_materials_pbrSpecularGlossiness") == 0) + { + out_material->has_pbr_specular_glossiness = 1; + i = cgltf_parse_json_pbr_specular_glossiness(options, tokens, i + 1, json_chunk, &out_material->pbr_specular_glossiness); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_unlit") == 0) + { + out_material->unlit = 1; + i = cgltf_skip_json(tokens, i+1); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_clearcoat") == 0) + { + out_material->has_clearcoat = 1; + i = cgltf_parse_json_clearcoat(options, tokens, i + 1, json_chunk, &out_material->clearcoat); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_ior") == 0) + { + out_material->has_ior = 1; + i = cgltf_parse_json_ior(tokens, i + 1, json_chunk, &out_material->ior); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_specular") == 0) + { + out_material->has_specular = 1; + i = cgltf_parse_json_specular(options, tokens, i + 1, json_chunk, &out_material->specular); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_transmission") == 0) + { + out_material->has_transmission = 1; + i = cgltf_parse_json_transmission(options, tokens, i + 1, json_chunk, &out_material->transmission); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_volume") == 0) + { + out_material->has_volume = 1; + i = cgltf_parse_json_volume(options, tokens, i + 1, json_chunk, &out_material->volume); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_sheen") == 0) + { + 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++])); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_accessors(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_accessor), (void**)&out_data->accessors, &out_data->accessors_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->accessors_count; ++j) + { + i = cgltf_parse_json_accessor(options, tokens, i, json_chunk, &out_data->accessors[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_materials(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material), (void**)&out_data->materials, &out_data->materials_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->materials_count; ++j) + { + i = cgltf_parse_json_material(options, tokens, i, json_chunk, &out_data->materials[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_images(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_image), (void**)&out_data->images, &out_data->images_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->images_count; ++j) + { + i = cgltf_parse_json_image(options, tokens, i, json_chunk, &out_data->images[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_textures(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_texture), (void**)&out_data->textures, &out_data->textures_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->textures_count; ++j) + { + i = cgltf_parse_json_texture(options, tokens, i, json_chunk, &out_data->textures[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_samplers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_sampler), (void**)&out_data->samplers, &out_data->samplers_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->samplers_count; ++j) + { + i = cgltf_parse_json_sampler(options, tokens, i, json_chunk, &out_data->samplers[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_meshopt_compression* out_meshopt_compression) +{ + (void)options; + 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, "buffer") == 0) + { + ++i; + out_meshopt_compression->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) + { + ++i; + out_meshopt_compression->offset = cgltf_json_to_size(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); + ++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); + ++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); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens+i, json_chunk, "ATTRIBUTES") == 0) + { + out_meshopt_compression->mode = cgltf_meshopt_compression_mode_attributes; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "TRIANGLES") == 0) + { + out_meshopt_compression->mode = cgltf_meshopt_compression_mode_triangles; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "INDICES") == 0) + { + out_meshopt_compression->mode = cgltf_meshopt_compression_mode_indices; + } + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "filter") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens+i, json_chunk, "NONE") == 0) + { + out_meshopt_compression->filter = cgltf_meshopt_compression_filter_none; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "OCTAHEDRAL") == 0) + { + out_meshopt_compression->filter = cgltf_meshopt_compression_filter_octahedral; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "QUATERNION") == 0) + { + out_meshopt_compression->filter = cgltf_meshopt_compression_filter_quaternion; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "EXPONENTIAL") == 0) + { + out_meshopt_compression->filter = cgltf_meshopt_compression_filter_exponential; + } + ++i; + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer_view* out_buffer_view) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer_view->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "buffer") == 0) + { + ++i; + out_buffer_view->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0) + { + ++i; + out_buffer_view->offset = + cgltf_json_to_size(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); + ++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); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0) + { + ++i; + int type = cgltf_json_to_int(tokens+i, json_chunk); + switch (type) + { + case 34962: + type = cgltf_buffer_view_type_vertices; + break; + case 34963: + type = cgltf_buffer_view_type_indices; + break; + default: + type = cgltf_buffer_view_type_invalid; + break; + } + out_buffer_view->type = (cgltf_buffer_view_type)type; + ++i; + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_buffer_view->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + out_buffer_view->extensions_count = 0; + out_buffer_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!out_buffer_view->extensions) + { + return CGLTF_ERROR_NOMEM; + } + + ++i; + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "EXT_meshopt_compression") == 0) + { + out_buffer_view->has_meshopt_compression = 1; + i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression); + } + else + { + i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_buffer_view->extensions[out_buffer_view->extensions_count++])); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_buffer_views(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer_view), (void**)&out_data->buffer_views, &out_data->buffer_views_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->buffer_views_count; ++j) + { + i = cgltf_parse_json_buffer_view(options, tokens, i, json_chunk, &out_data->buffer_views[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer* out_buffer) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0) + { + ++i; + out_buffer->size = + cgltf_json_to_size(tokens+i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->uri); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_buffer->extensions_count, &out_buffer->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_buffers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer), (void**)&out_data->buffers, &out_data->buffers_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->buffers_count; ++j) + { + i = cgltf_parse_json_buffer(options, tokens, i, json_chunk, &out_data->buffers[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_skin* out_skin) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_skin->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "joints") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_skin->joints, &out_skin->joints_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_skin->joints_count; ++k) + { + out_skin->joints[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "skeleton") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_skin->skeleton = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "inverseBindMatrices") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_skin->inverse_bind_matrices = CGLTF_PTRINDEX(cgltf_accessor, 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(options, tokens, i + 1, json_chunk, &out_skin->extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_skin->extensions_count, &out_skin->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_skins(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_skin), (void**)&out_data->skins, &out_data->skins_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->skins_count; ++j) + { + i = cgltf_parse_json_skin(options, tokens, i, json_chunk, &out_data->skins[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_camera* out_camera) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + 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) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "aspectRatio") == 0) + { + ++i; + out_camera->data.perspective.has_aspect_ratio = 1; + out_camera->data.perspective.aspect_ratio = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "yfov") == 0) + { + ++i; + out_camera->data.perspective.yfov = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0) + { + ++i; + out_camera->data.perspective.has_zfar = 1; + out_camera->data.perspective.zfar = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0) + { + ++i; + out_camera->data.perspective.znear = 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(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "orthographic") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + 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) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "xmag") == 0) + { + ++i; + out_camera->data.orthographic.xmag = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "ymag") == 0) + { + ++i; + out_camera->data.orthographic.ymag = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0) + { + ++i; + out_camera->data.orthographic.zfar = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0) + { + ++i; + out_camera->data.orthographic.znear = 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(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_camera->extensions_count, &out_camera->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_cameras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_camera), (void**)&out_data->cameras, &out_data->cameras_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->cameras_count; ++j) + { + i = cgltf_parse_json_camera(options, tokens, i, json_chunk, &out_data->cameras[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_light* out_light) +{ + 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; + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_light->name); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "color") == 0) + { + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_light->color, 3); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "intensity") == 0) + { + ++i; + out_light->intensity = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens + i, json_chunk, "directional") == 0) + { + out_light->type = cgltf_light_type_directional; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "point") == 0) + { + out_light->type = cgltf_light_type_point; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "spot") == 0) + { + out_light->type = cgltf_light_type_spot; + } + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "range") == 0) + { + ++i; + out_light->range = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "spot") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int data_size = tokens[i].size; + ++i; + + for (int k = 0; k < data_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "innerConeAngle") == 0) + { + ++i; + out_light->spot_inner_cone_angle = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "outerConeAngle") == 0) + { + ++i; + out_light->spot_outer_cone_angle = cgltf_json_to_float(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, "extras") == 0) + { + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_lights(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_light), (void**)&out_data->lights, &out_data->lights_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->lights_count; ++j) + { + i = cgltf_parse_json_light(options, tokens, i, json_chunk, &out_data->lights[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_node* out_node) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + out_node->rotation[3] = 1.0f; + out_node->scale[0] = 1.0f; + out_node->scale[1] = 1.0f; + out_node->scale[2] = 1.0f; + out_node->matrix[0] = 1.0f; + out_node->matrix[5] = 1.0f; + out_node->matrix[10] = 1.0f; + out_node->matrix[15] = 1.0f; + + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_node->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "children") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_node->children, &out_node->children_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_node->children_count; ++k) + { + out_node->children[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "mesh") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_node->mesh = CGLTF_PTRINDEX(cgltf_mesh, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "skin") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_node->skin = CGLTF_PTRINDEX(cgltf_skin, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "camera") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_node->camera = CGLTF_PTRINDEX(cgltf_camera, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0) + { + out_node->has_translation = 1; + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->translation, 3); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0) + { + out_node->has_rotation = 1; + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->rotation, 4); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0) + { + out_node->has_scale = 1; + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->scale, 3); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "matrix") == 0) + { + out_node->has_matrix = 1; + i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->matrix, 16); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_node->weights, &out_node->weights_count); + if (i < 0) + { + return i; + } + + i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_node->weights, (int)out_node->weights_count); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_node->extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + out_node->extensions_count= 0; + out_node->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!out_node->extensions) + { + return CGLTF_ERROR_NOMEM; + } + + ++i; + + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int data_size = tokens[i].size; + ++i; + + for (int m = 0; m < data_size; ++m) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "light") == 0) + { + ++i; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE); + out_node->light = CGLTF_PTRINDEX(cgltf_light, 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_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++])); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_nodes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_node), (void**)&out_data->nodes, &out_data->nodes_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->nodes_count; ++j) + { + i = cgltf_parse_json_node(options, tokens, i, json_chunk, &out_data->nodes[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_scene* out_scene) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_scene->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "nodes") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_scene->nodes, &out_scene->nodes_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_scene->nodes_count; ++k) + { + out_scene->nodes[k] = CGLTF_PTRINDEX(cgltf_node, 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(options, tokens, i + 1, json_chunk, &out_scene->extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_scene->extensions_count, &out_scene->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_scene), (void**)&out_data->scenes, &out_data->scenes_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->scenes_count; ++j) + { + i = cgltf_parse_json_scene(options, tokens, i, json_chunk, &out_data->scenes[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_sampler* out_sampler) +{ + (void)options; + 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, "input") == 0) + { + ++i; + out_sampler->input = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "output") == 0) + { + ++i; + out_sampler->output = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "interpolation") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens + i, json_chunk, "LINEAR") == 0) + { + out_sampler->interpolation = cgltf_interpolation_type_linear; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "STEP") == 0) + { + out_sampler->interpolation = cgltf_interpolation_type_step; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "CUBICSPLINE") == 0) + { + out_sampler->interpolation = cgltf_interpolation_type_cubic_spline; + } + ++i; + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_channel* out_channel) +{ + (void)options; + 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, "sampler") == 0) + { + ++i; + out_channel->sampler = CGLTF_PTRINDEX(cgltf_animation_sampler, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int target_size = tokens[i].size; + ++i; + + for (int k = 0; k < target_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "node") == 0) + { + ++i; + out_channel->target_node = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "path") == 0) + { + ++i; + if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0) + { + out_channel->target_path = cgltf_animation_path_type_translation; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0) + { + out_channel->target_path = cgltf_animation_path_type_rotation; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0) + { + out_channel->target_path = cgltf_animation_path_type_scale; + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "weights") == 0) + { + out_channel->target_path = cgltf_animation_path_type_weights; + } + ++i; + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_channel->extensions_count, &out_channel->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation* out_animation) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_animation->name); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "samplers") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_sampler), (void**)&out_animation->samplers, &out_animation->samplers_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_animation->samplers_count; ++k) + { + i = cgltf_parse_json_animation_sampler(options, tokens, i, json_chunk, &out_animation->samplers[k]); + if (i < 0) + { + return i; + } + } + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "channels") == 0) + { + i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_channel), (void**)&out_animation->channels, &out_animation->channels_count); + if (i < 0) + { + return i; + } + + for (cgltf_size k = 0; k < out_animation->channels_count; ++k) + { + i = cgltf_parse_json_animation_channel(options, tokens, i, json_chunk, &out_animation->channels[k]); + if (i < 0) + { + return i; + } + } + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_animation->extensions_count, &out_animation->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_animations(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_animation), (void**)&out_data->animations, &out_data->animations_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->animations_count; ++j) + { + i = cgltf_parse_json_animation(options, tokens, i, json_chunk, &out_data->animations[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_variant* out_variant) +{ + 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, "name") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_variant->name); + } + 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); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_variants(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material_variant), (void**)&out_data->variants, &out_data->variants_count); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < out_data->variants_count; ++j) + { + i = cgltf_parse_json_variant(options, tokens, i, json_chunk, &out_data->variants[j]); + if (i < 0) + { + return i; + } + } + return i; +} + +static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_asset* out_asset) +{ + 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, "copyright") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->copyright); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "generator") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->generator); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "version") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->version); + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "minVersion") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->min_version); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_asset->extensions_count, &out_asset->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + if (out_asset->version && CGLTF_ATOF(out_asset->version) < 2) + { + return CGLTF_ERROR_LEGACY; + } + + return i; +} + +cgltf_size cgltf_num_components(cgltf_type type) { + switch (type) + { + case cgltf_type_vec2: + return 2; + case cgltf_type_vec3: + return 3; + case cgltf_type_vec4: + return 4; + case cgltf_type_mat2: + return 4; + case cgltf_type_mat3: + return 9; + case cgltf_type_mat4: + return 16; + case cgltf_type_invalid: + case cgltf_type_scalar: + default: + return 1; + } +} + +cgltf_size cgltf_component_size(cgltf_component_type component_type) { + switch (component_type) + { + case cgltf_component_type_r_8: + case cgltf_component_type_r_8u: + return 1; + case cgltf_component_type_r_16: + case cgltf_component_type_r_16u: + return 2; + case cgltf_component_type_r_32u: + case cgltf_component_type_r_32f: + return 4; + case cgltf_component_type_invalid: + default: + return 0; + } +} + +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) + { + return 8 * component_size; + } + else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2)) + { + return 12 * component_size; + } + return component_size * cgltf_num_components(type); +} + +static int cgltf_fixup_pointers(cgltf_data* out_data); + +static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data) +{ + 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, "asset") == 0) + { + i = cgltf_parse_json_asset(options, tokens, i + 1, json_chunk, &out_data->asset); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "meshes") == 0) + { + i = cgltf_parse_json_meshes(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "accessors") == 0) + { + i = cgltf_parse_json_accessors(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferViews") == 0) + { + i = cgltf_parse_json_buffer_views(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "buffers") == 0) + { + i = cgltf_parse_json_buffers(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "materials") == 0) + { + i = cgltf_parse_json_materials(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "images") == 0) + { + i = cgltf_parse_json_images(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "textures") == 0) + { + i = cgltf_parse_json_textures(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "samplers") == 0) + { + i = cgltf_parse_json_samplers(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "skins") == 0) + { + i = cgltf_parse_json_skins(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "cameras") == 0) + { + i = cgltf_parse_json_cameras(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "nodes") == 0) + { + i = cgltf_parse_json_nodes(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scenes") == 0) + { + i = cgltf_parse_json_scenes(options, tokens, i + 1, json_chunk, out_data); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scene") == 0) + { + ++i; + out_data->scene = CGLTF_PTRINDEX(cgltf_scene, cgltf_json_to_int(tokens + i, json_chunk)); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "animations") == 0) + { + i = cgltf_parse_json_animations(options, tokens, i + 1, json_chunk, out_data); + } + 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); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + if(out_data->data_extensions) + { + return CGLTF_ERROR_JSON; + } + + int extensions_size = tokens[i].size; + out_data->data_extensions_count = 0; + out_data->data_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); + + if (!out_data->data_extensions) + { + return CGLTF_ERROR_NOMEM; + } + + ++i; + + for (int k = 0; k < extensions_size; ++k) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int data_size = tokens[i].size; + ++i; + + for (int m = 0; m < data_size; ++m) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "lights") == 0) + { + i = cgltf_parse_json_lights(options, tokens, i + 1, json_chunk, out_data); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0) + { + ++i; + + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int data_size = tokens[i].size; + ++i; + + for (int m = 0; m < data_size; ++m) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0) + { + i = cgltf_parse_json_variants(options, tokens, i + 1, json_chunk, out_data); + } + 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_data->data_extensions[out_data->data_extensions_count++])); + } + + if (i < 0) + { + return i; + } + } + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsUsed") == 0) + { + i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_used, &out_data->extensions_used_count); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsRequired") == 0) + { + i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_required, &out_data->extensions_required_count); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data) +{ + jsmn_parser parser = { 0, 0, 0 }; + + if (options->json_token_count == 0) + { + int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, NULL, 0); + + if (token_count <= 0) + { + return cgltf_result_invalid_json; + } + + 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)); + + if (!tokens) + { + return cgltf_result_out_of_memory; + } + + jsmn_init(&parser); + + int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, tokens, options->json_token_count); + + if (token_count <= 0) + { + options->memory.free_func(options->memory.user_data, tokens); + return cgltf_result_invalid_json; + } + + // this makes sure that we always have an UNDEFINED token at the end of the stream + // 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)); + + if (!data) + { + options->memory.free_func(options->memory.user_data, tokens); + return cgltf_result_out_of_memory; + } + + memset(data, 0, sizeof(cgltf_data)); + data->memory = options->memory; + data->file = options->file; + + int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data); + + options->memory.free_func(options->memory.user_data, tokens); + + if (i < 0) + { + cgltf_free(data); + + switch (i) + { + case CGLTF_ERROR_NOMEM: return cgltf_result_out_of_memory; + case CGLTF_ERROR_LEGACY: return cgltf_result_legacy_gltf; + default: return cgltf_result_invalid_gltf; + } + } + + if (cgltf_fixup_pointers(data) < 0) + { + cgltf_free(data); + return cgltf_result_invalid_gltf; + } + + data->json = (const char*)json_chunk; + data->json_size = size; + + *out_data = data; + + return cgltf_result_success; +} + +static int cgltf_fixup_pointers(cgltf_data* data) +{ + for (cgltf_size i = 0; i < data->meshes_count; ++i) + { + for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) + { + CGLTF_PTRFIXUP(data->meshes[i].primitives[j].indices, data->accessors, data->accessors_count); + CGLTF_PTRFIXUP(data->meshes[i].primitives[j].material, data->materials, data->materials_count); + + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) + { + CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].attributes[k].data, data->accessors, data->accessors_count); + } + + 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_PTRFIXUP_REQ(data->meshes[i].primitives[j].targets[k].attributes[m].data, data->accessors, data->accessors_count); + } + } + + if (data->meshes[i].primitives[j].has_draco_mesh_compression) + { + CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.buffer_view, data->buffer_views, data->buffer_views_count); + for (cgltf_size m = 0; m < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++m) + { + CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.attributes[m].data, data->accessors, data->accessors_count); + } + } + + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) + { + CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].mappings[k].material, data->materials, data->materials_count); + } + } + } + + for (cgltf_size i = 0; i < data->accessors_count; ++i) + { + CGLTF_PTRFIXUP(data->accessors[i].buffer_view, data->buffer_views, data->buffer_views_count); + + if (data->accessors[i].is_sparse) + { + CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.indices_buffer_view, data->buffer_views, data->buffer_views_count); + CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.values_buffer_view, data->buffer_views, data->buffer_views_count); + } + + if (data->accessors[i].buffer_view) + { + data->accessors[i].stride = data->accessors[i].buffer_view->stride; + } + + if (data->accessors[i].stride == 0) + { + data->accessors[i].stride = cgltf_calc_size(data->accessors[i].type, data->accessors[i].component_type); + } + } + + 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); + } + + for (cgltf_size i = 0; i < data->images_count; ++i) + { + CGLTF_PTRFIXUP(data->images[i].buffer_view, data->buffer_views, data->buffer_views_count); + } + + for (cgltf_size i = 0; i < data->materials_count; ++i) + { + CGLTF_PTRFIXUP(data->materials[i].normal_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].emissive_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].occlusion_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.base_color_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.diffuse_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_roughness_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_normal_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].specular.specular_texture.texture, data->textures, data->textures_count); + CGLTF_PTRFIXUP(data->materials[i].specular.specular_color_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].transmission.transmission_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].volume.thickness_texture.texture, data->textures, data->textures_count); + + 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) + { + CGLTF_PTRFIXUP_REQ(data->buffer_views[i].buffer, data->buffers, data->buffers_count); + + if (data->buffer_views[i].has_meshopt_compression) + { + CGLTF_PTRFIXUP_REQ(data->buffer_views[i].meshopt_compression.buffer, data->buffers, data->buffers_count); + } + } + + for (cgltf_size i = 0; i < data->skins_count; ++i) + { + for (cgltf_size j = 0; j < data->skins[i].joints_count; ++j) + { + CGLTF_PTRFIXUP_REQ(data->skins[i].joints[j], data->nodes, data->nodes_count); + } + + CGLTF_PTRFIXUP(data->skins[i].skeleton, data->nodes, data->nodes_count); + CGLTF_PTRFIXUP(data->skins[i].inverse_bind_matrices, data->accessors, data->accessors_count); + } + + for (cgltf_size i = 0; i < data->nodes_count; ++i) + { + for (cgltf_size j = 0; j < data->nodes[i].children_count; ++j) + { + CGLTF_PTRFIXUP_REQ(data->nodes[i].children[j], data->nodes, data->nodes_count); + + if (data->nodes[i].children[j]->parent) + { + return CGLTF_ERROR_JSON; + } + + data->nodes[i].children[j]->parent = &data->nodes[i]; + } + + CGLTF_PTRFIXUP(data->nodes[i].mesh, data->meshes, data->meshes_count); + 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) + { + for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j) + { + CGLTF_PTRFIXUP_REQ(data->scenes[i].nodes[j], data->nodes, data->nodes_count); + + if (data->scenes[i].nodes[j]->parent) + { + return CGLTF_ERROR_JSON; + } + } + } + + CGLTF_PTRFIXUP(data->scene, data->scenes, data->scenes_count); + + for (cgltf_size i = 0; i < data->animations_count; ++i) + { + for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j) + { + CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].input, data->accessors, data->accessors_count); + CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].output, data->accessors, data->accessors_count); + } + + for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j) + { + CGLTF_PTRFIXUP_REQ(data->animations[i].channels[j].sampler, data->animations[i].samplers, data->animations[i].samplers_count); + CGLTF_PTRFIXUP(data->animations[i].channels[j].target_node, data->nodes, data->nodes_count); + } + } + + return 0; +} + +/* + * -- jsmn.c start -- + * Source: https://github.com/zserge/jsmn + * License: MIT + * + * Copyright (c) 2010 Serge A. Zaitsev + + * 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. + */ + +/** + * Allocates a fresh unused token from the token pull. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + ptrdiff_t start, ptrdiff_t end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +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; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t' : case '\r' : case '\n' : case ' ' : + case ',' : case ']' : case '}' : + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Fills next token with JSON string. + */ +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; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/' : case '\\' : case 'b' : + case 'f' : case 'r' : case 'n' : case 't' : + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, size_t num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = parser->toknext; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + if(token->type != type || parser->toksuper == -1) { + return JSMN_ERROR_INVAL; + } + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1' : case '2': case '3' : case '4': + case '5': case '6': case '7' : case '8': case '9': + case 't': case 'f': case 'n' : + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + if (tokens != NULL) { + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +static void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} +/* + * -- jsmn.c end -- + */ + +#endif /* #ifdef CGLTF_IMPLEMENTATION */ + +/* cgltf is distributed under MIT license: + * + * Copyright (c) 2018-2021 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 + * 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/dirent.h b/raylib/external/dirent.h new file mode 100644 index 0000000..c611376 --- /dev/null +++ b/raylib/external/dirent.h @@ -0,0 +1,183 @@ +/**************************************************************************** + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Reviewed by Ramon Santamaria for raylib on January 2020. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +****************************************************************************/ + +#ifndef DIRENT_H +#define DIRENT_H + +// Allow custom memory allocators +#ifndef DIRENT_MALLOC + #define DIRENT_MALLOC(sz) malloc(sz) +#endif +#ifndef DIRENT_FREE + #define DIRENT_FREE(p) free(p) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Fordward declaration of DIR, implementation below +typedef struct DIR DIR; + +struct dirent { + char *d_name; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------------ +// Functions Declaration +//------------------------------------------------------------------------------------ +DIR *opendir(const char *name); +int closedir(DIR *dir); +struct dirent *readdir(DIR *dir); +void rewinddir(DIR *dir); + +#ifdef __cplusplus +} +#endif + +#endif // DIRENT_H + +/**************************************************************************** + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Reviewed by Ramon Santamaria for raylib on January 2020. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +****************************************************************************/ + +#include // _findfirst and _findnext set errno iff they return -1 +#include +#include +#include + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef ptrdiff_t handle_type; // C99's intptr_t not sufficiently portable + +struct DIR { + handle_type handle; // -1 for failed rewind + struct _finddata_t info; + struct dirent result; // d_name null iff first time + char *name; // null-terminated char string +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if (name && name[0]) + { + size_t base_length = strlen(name); + + // Search pattern must end with suitable wildcard + const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if ((dir = (DIR *)DIRENT_MALLOC(sizeof *dir)) != 0 && + (dir->name = (char *)DIRENT_MALLOC(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if ((dir->handle = (handle_type) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else // rollback + { + DIRENT_FREE(dir->name); + DIRENT_FREE(dir); + dir = 0; + } + } + else // rollback + { + DIRENT_FREE(dir); + dir = 0; + errno = ENOMEM; + } + } + else errno = EINVAL; + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if (dir) + { + if (dir->handle != -1) result = _findclose(dir->handle); + + DIRENT_FREE(dir->name); + DIRENT_FREE(dir); + } + + // NOTE: All errors ampped to EBADF + if (result == -1) errno = EBADF; + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if (dir && dir->handle != -1) + { + if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else errno = EBADF; + + return result; +} + +void rewinddir(DIR *dir) +{ + if (dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type) _findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else errno = EBADF; +} diff --git a/raylib/external/dr_flac.h b/raylib/external/dr_flac.h index 60f57ec..14324cf 100644 --- a/raylib/external/dr_flac.h +++ b/raylib/external/dr_flac.h @@ -1,170 +1,362 @@ -// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_flac - v0.8d - 2017-09-22 -// -// David Reid - mackron@gmail.com +/* +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 -// USAGE -// -// dr_flac is a single-file library. To use it, do something like the following in one .c file. -// #define DR_FLAC_IMPLEMENTATION -// #include "dr_flac.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, -// do something like the following: -// -// drflac* pFlac = drflac_open_file("MySong.flac"); -// if (pFlac == NULL) { -// // Failed to open FLAC file -// } -// -// drflac_int32* pSamples = malloc(pFlac->totalSampleCount * sizeof(drflac_int32)); -// drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSamples); -// -// The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of -// channels and the bits per sample, should be directly accessible - just make sure you don't change their values. Samples are -// always output as interleaved signed 32-bit PCM. In the example above a native FLAC stream was opened, however dr_flac has -// seamless support for Ogg encapsulated FLAC streams as well. -// -// You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and -// the decoder will give you as many samples as it can, up to the amount requested. Later on when you need the next batch of -// samples, just call it again. Example: -// -// while (drflac_read_s32(pFlac, chunkSize, pChunkSamples) > 0) { -// do_something(); -// } -// -// You can seek to a specific sample with drflac_seek_to_sample(). The given sample is based on interleaving. So for example, -// if you were to seek to the sample at index 0 in a stereo stream, you'll be seeking to the first sample of the left channel. -// The sample at index 1 will be the first sample of the right channel. The sample at index 2 will be the second sample of the -// left channel, etc. -// -// -// If you just want to quickly decode an entire FLAC file in one go you can do something like this: -// -// unsigned int channels; -// unsigned int sampleRate; -// drflac_uint64 totalSampleCount; -// drflac_int32* pSampleData = drflac_open_and_decode_file_s32("MySong.flac", &channels, &sampleRate, &totalSampleCount); -// if (pSampleData == NULL) { -// // Failed to open and decode FLAC file. -// } -// -// ... -// -// drflac_free(pSampleData); -// -// -// You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs -// respectively, but note that these should be considered lossy. -// -// -// If you need access to metadata (album art, etc.), use drflac_open_with_metadata(), drflac_open_file_with_metdata() or -// drflac_open_memory_with_metadata(). The rationale for keeping these APIs separate is that they're slightly slower than the -// normal versions and also just a little bit harder to use. -// -// dr_flac reports metadata to the application through the use of a callback, and every metadata block is reported before -// drflac_open_with_metdata() returns. -// -// -// The main opening APIs (drflac_open(), etc.) will fail if the header is not present. The presents a problem in certain -// scenarios such as broadcast style streams like internet radio where the header may not be present because the user has -// started playback mid-stream. To handle this, use the relaxed APIs: drflac_open_relaxed() and drflac_open_with_metadata_relaxed(). -// -// It is not recommended to use these APIs for file based streams because a missing header would usually indicate a -// corrupted or perverse file. In addition, these APIs can take a long time to initialize because they may need to spend -// a lot of time finding the first frame. -// -// -// -// OPTIONS -// #define these options before including this file. -// -// #define DR_FLAC_NO_STDIO -// Disable drflac_open_file(). -// -// #define DR_FLAC_NO_OGG -// Disables support for Ogg/FLAC streams. -// -// #define DR_FLAC_NO_WIN32_IO -// In the Win32 build, dr_flac uses the Win32 IO APIs for drflac_open_file() by default. This setting will make it use the -// standard FILE APIs instead. Ignored when DR_FLAC_NO_STDIO is #defined. (The rationale for this configuration is that -// there's a bug in one compiler's Win32 implementation of the FILE APIs which is not present in the Win32 IO APIs.) -// -// #define DR_FLAC_BUFFER_SIZE -// Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls -// back to the client for more data. Larger values means more memory, but better performance. My tests show diminishing -// returns after about 4KB (which is the default). Consider reducing this if you have a very efficient implementation of -// onRead(), or increase it if it's very inefficient. Must be a multiple of 8. -// -// #define DR_FLAC_NO_CRC -// Disables CRC checks. This will offer a performance boost when CRC is unnecessary. -// -// #define DR_FLAC_NO_SIMD -// Disables SIMD optimizations (SSE on x86/x64 architectures). Use this if you are having compatibility issues with your -// compiler. -// -// -// -// QUICK NOTES -// - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. -// - This has not been tested on big-endian architectures. -// - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody -// knows where I can find some test files for this, let me know. -// - dr_flac is not thread-safe, but it's APIs can be called from any thread so long as you do your own synchronization. -// - When using Ogg encapsulation, a corrupted metadata block will result in drflac_open_with_metadata() and drflac_open() -// returning inconsistent samples. +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +RELEASE NOTES - v0.12.0 +======================= +Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs. + + +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 DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_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 drflac_allocation_callbacks object to drflac_open() 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); + } + + ... + + drflac_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drflac* pFlac = drflac_open_file("my_file.flac", &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_flac to use defaults which is the same as DRFLAC_MALLOC, +DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drflac object now takes this extra parameter. These include the following: + + drflac_open() + drflac_open_relaxed() + drflac_open_with_metadata() + drflac_open_with_metadata_relaxed() + drflac_open_file() + drflac_open_file_with_metadata() + drflac_open_memory() + drflac_open_memory_with_metadata() + drflac_open_and_read_pcm_frames_s32() + drflac_open_and_read_pcm_frames_s16() + drflac_open_and_read_pcm_frames_f32() + drflac_open_file_and_read_pcm_frames_s32() + drflac_open_file_and_read_pcm_frames_s16() + drflac_open_file_and_read_pcm_frames_f32() + drflac_open_memory_and_read_pcm_frames_s32() + drflac_open_memory_and_read_pcm_frames_s16() + drflac_open_memory_and_read_pcm_frames_f32() + + + +Optimizations +------------- +Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly +improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes +advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which +means it will be disabled when DR_FLAC_NO_CRC is used. + +The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in +particular. 16-bit streams should also see some improvement. + +drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32 +to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths. + +A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo +channel reconstruction which is the last part of the decoding process. + +The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when +compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at +compile time and the REV instruction requires ARM architecture version 6. + +An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling. + + +Removed APIs +------------ +The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0: + + drflac_read_s32() -> drflac_read_pcm_frames_s32() + drflac_read_s16() -> drflac_read_pcm_frames_s16() + drflac_read_f32() -> drflac_read_pcm_frames_f32() + drflac_seek_to_sample() -> drflac_seek_to_pcm_frame() + drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32() + drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16() + drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32() + drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32() + drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16() + drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32() + drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32() + drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16() + drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32() + +Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate +to the old per-sample APIs. You now need to use the "pcm_frame" versions. +*/ + + +/* +Introduction +============ +dr_flac is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_FLAC_IMPLEMENTATION + #include "dr_flac.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following: + + ```c + drflac* pFlac = drflac_open_file("MySong.flac", NULL); + if (pFlac == NULL) { + // Failed to open FLAC file + } + + drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32)); + drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples); + ``` + +The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of channels and the bits per sample, +should be directly accessible - just make sure you don't change their values. Samples are always output as interleaved signed 32-bit PCM. In the example above +a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well. + +You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and the decoder will give you as many +samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example: + + ```c + while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) { + do_something(); + } + ``` + +You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`. + +If you just want to quickly decode an entire FLAC file in one go you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drflac_uint64 totalPCMFrameCount; + drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Failed to open and decode FLAC file. + } + + ... + + drflac_free(pSampleData, NULL); + ``` + +You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these +should be considered lossy. + + +If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`. +The rationale for keeping these APIs separate is that they're slightly slower than the normal versions and also just a little bit harder to use. dr_flac +reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns. + +The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style +streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs: + + `drflac_open_relaxed()` + `drflac_open_with_metadata_relaxed()` + +It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these +APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame. + + + +Build Options +============= +#define these options before including this file. + +#define DR_FLAC_NO_STDIO + Disable `drflac_open_file()` and family. + +#define DR_FLAC_NO_OGG + Disables support for Ogg/FLAC streams. + +#define DR_FLAC_BUFFER_SIZE + Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls back to the client for more data. + Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if + you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8. + +#define DR_FLAC_NO_CRC + Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will + be used if available. Otherwise the seek will be performed using brute force. + +#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 +===== +- dr_flac does not support changing the sample rate nor channel count mid stream. +- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization. +- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due + to differences in corrupted stream recorvery logic between the two APIs. +*/ #ifndef dr_flac_h #define dr_flac_h -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -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; -typedef signed __int64 drflac_int64; -typedef unsigned __int64 drflac_uint64; -#else -#include -typedef int8_t drflac_int8; -typedef uint8_t drflac_uint8; -typedef int16_t drflac_int16; -typedef uint16_t drflac_uint16; -typedef int32_t drflac_int32; -typedef uint32_t drflac_uint32; -typedef int64_t drflac_int64; -typedef uint64_t drflac_uint64; -#endif -typedef drflac_uint8 drflac_bool8; -typedef drflac_uint32 drflac_bool32; -#define DRFLAC_TRUE 1 -#define DRFLAC_FALSE 0 - -// 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. -#ifndef DR_FLAC_BUFFER_SIZE -#define DR_FLAC_BUFFER_SIZE 4096 -#endif - #ifdef __cplusplus extern "C" { #endif -// Check if we can enable 64-bit optimizations. -#if defined(_WIN64) +#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 42 +#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 */ +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__) + 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(_M_ARM64) || 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 +/* End Sized Types */ + +/* Decorations */ +#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 +/* End Decorations */ + +#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */ + #define DRFLAC_DEPRECATED __declspec(deprecated) +#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */ + #define DRFLAC_DEPRECATED __attribute__((deprecated)) +#elif defined(__has_feature) /* Clang */ + #if __has_feature(attribute_deprecated) + #define DRFLAC_DEPRECATED __attribute__((deprecated)) + #else + #define DRFLAC_DEPRECATED + #endif +#else + #define DRFLAC_DEPRECATED +#endif + +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. +*/ +#ifndef DR_FLAC_BUFFER_SIZE +#define DR_FLAC_BUFFER_SIZE 4096 +#endif + + +/* Architecture Detection */ +#if defined(_WIN64) || defined(_LP64) || defined(__LP64__) #define DRFLAC_64BIT #endif -#if defined(__GNUC__) -#if defined(__x86_64__) || defined(__ppc64__) -#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; @@ -172,7 +364,7 @@ typedef drflac_uint64 drflac_cache_t; typedef drflac_uint32 drflac_cache_t; #endif -// The various metadata block types. +/* The various metadata block types. */ #define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0 #define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1 #define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2 @@ -182,7 +374,7 @@ typedef drflac_uint32 drflac_cache_t; #define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6 #define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127 -// The various picture types specified in the PICTURE block. +/* The various picture types specified in the PICTURE block. */ #define DRFLAC_PICTURE_TYPE_OTHER 0 #define DRFLAC_PICTURE_TYPE_FILE_ICON 1 #define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2 @@ -218,40 +410,43 @@ typedef enum drflac_seek_origin_current } drflac_seek_origin; -// Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. -#pragma pack(2) +/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */ typedef struct { - drflac_uint64 firstSample; - drflac_uint64 frameOffset; // The offset from the first byte of the header of the first frame. - drflac_uint16 sampleCount; + 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 { - drflac_uint16 minBlockSize; - drflac_uint16 maxBlockSize; - drflac_uint32 minFrameSize; - drflac_uint32 maxFrameSize; + drflac_uint16 minBlockSizeInPCMFrames; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint32 minFrameSizeInPCMFrames; + drflac_uint32 maxFrameSizeInPCMFrames; drflac_uint32 sampleRate; drflac_uint8 channels; drflac_uint8 bitsPerSample; - drflac_uint64 totalSampleCount; + drflac_uint64 totalPCMFrameCount; drflac_uint8 md5[16]; } drflac_streaminfo; typedef struct { - // The metadata type. Use this to know how to interpret the data below. + /* + The metadata type. Use this to know how to interpret the data below. Will be set to one of the + DRFLAC_METADATA_BLOCK_TYPE_* tokens. + */ drflac_uint32 type; - // A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to - // not modify the contents of this buffer. Use the structures below for more meaningful and structured - // information about the metadata. It's possible for this to be null. + /* + A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to + not modify the contents of this buffer. Use the structures below for more meaningful and structured + information about the metadata. It's possible for this to be null. + */ const void* pRawData; - // The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. + /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ drflac_uint32 rawDataSize; union @@ -281,7 +476,7 @@ typedef struct drflac_uint32 vendorLength; const char* vendor; drflac_uint32 commentCount; - const char* comments; + const void* pComments; } vorbis_comment; struct @@ -290,7 +485,7 @@ typedef struct drflac_uint64 leadInSampleCount; drflac_bool32 isCD; drflac_uint8 trackCount; - const drflac_uint8* pTrackData; + const void* pTrackData; } cuesheet; struct @@ -311,40 +506,87 @@ typedef struct } drflac_metadata; -// Callback for when data needs to be read from the client. -// -// pUserData [in] The user data that was passed to drflac_open() and family. -// pBufferOut [out] The output buffer. -// bytesToRead [in] The number of bytes to read. -// -// Returns the number of bytes actually read. -// -// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until -// either the entire bytesToRead is filled or you have reached the end of the stream. +/* +Callback for when data needs to be read from the client. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pBufferOut (out) + The output buffer. + +bytesToRead (in) + The number of bytes to read. + + +Return Value +------------ +The number of bytes actually read. + + +Remarks +------- +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or +you have reached the end of the stream. +*/ typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -// Callback for when data needs to be seeked. -// -// pUserData [in] The user data that was passed to drflac_open() and family. -// offset [in] The number of bytes to move, relative to the origin. Will never be negative. -// origin [in] The origin of the seek - the current position or the start of the stream. -// -// Returns whether or not the seek was successful. -// -// The offset will never be negative. Whether or not it is relative to the beginning or current position is determined -// by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current. +/* +Callback for when data needs to be seeked. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +offset (in) + The number of bytes to move, relative to the origin. Will never be negative. + +origin (in) + The origin of the seek - the current position or the start of the stream. + + +Return Value +------------ +Whether or not the seek was successful. + + +Remarks +------- +The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be +either drflac_seek_origin_start or drflac_seek_origin_current. + +When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected +and handled by returning DRFLAC_FALSE. +*/ typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); -// Callback for when a metadata block is read. -// -// pUserData [in] The user data that was passed to drflac_open() and family. -// pMetadata [in] A pointer to a structure containing the data of the metadata block. -// -// Use pMetadata->type to determine which metadata block is being handled and how to read the data. +/* +Callback for when a metadata block is read. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pMetadata (in) + A pointer to a structure containing the data of the metadata block. + + +Remarks +------- +Use pMetadata->type to determine which metadata block is being handled and how to read the data. This +will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens. +*/ typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); -// Structure for internal use. Only used for decoders opened with drflac_open_memory. +/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ typedef struct { const drflac_uint8* data; @@ -352,418 +594,865 @@ typedef struct size_t currentReadPos; } drflac__memory_stream; -// Structure for internal use. Used for bit streaming. +/* Structure for internal use. Used for bit streaming. */ typedef struct { - // The function to call when more data needs to be read. + /* The function to call when more data needs to be read. */ drflac_read_proc onRead; - // The function to call when the current read position needs to be moved. + /* The function to call when the current read position needs to be moved. */ drflac_seek_proc onSeek; - // The user data to pass around to onRead and onSeek. + /* The user data to pass around to onRead and onSeek. */ void* pUserData; - // The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the - // stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether - // or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t). + /* + The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the + stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether + or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t). + */ size_t unalignedByteCount; - // The content of the unaligned bytes. + /* The content of the unaligned bytes. */ drflac_cache_t unalignedCache; - // The index of the next valid cache line in the "L2" cache. + /* The index of the next valid cache line in the "L2" cache. */ drflac_uint32 nextL2Line; - // The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. + /* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */ drflac_uint32 consumedBits; - // The cached data which was most recently read from the client. There are two levels of cache. Data flows as such: - // Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions. + /* + The cached data which was most recently read from the client. There are two levels of cache. Data flows as such: + Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions. + */ drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)]; drflac_cache_t cache; - // CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this - // is reset to 0 at the beginning of each frame. + /* + CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this + is reset to 0 at the beginning of each frame. + */ drflac_uint16 crc16; - drflac_cache_t crc16Cache; // A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. - drflac_uint32 crc16CacheIgnoredBytes; // The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. + drflac_cache_t crc16Cache; /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */ + drflac_uint32 crc16CacheIgnoredBytes; /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */ } drflac_bs; typedef struct { - // The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. + /* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */ drflac_uint8 subframeType; - // The number of wasted bits per sample as specified by the sub-frame header. + /* The number of wasted bits per sample as specified by the sub-frame header. */ drflac_uint8 wastedBitsPerSample; - // The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. + /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */ drflac_uint8 lpcOrder; - // The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because - // an extra bit is required for side channels when interchannel decorrelation is being used. - drflac_uint32 bitsPerSample; - - // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. Note that - // it's a signed 32-bit integer for each value. - drflac_int32* pDecodedSamples; + /* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */ + drflac_int32* pSamplesS32; } drflac_subframe; typedef struct { - // If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will - // always be set to 0. - drflac_uint64 sampleNumber; + /* + If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will + always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits. + */ + drflac_uint64 pcmFrameNumber; - // If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. - drflac_uint32 frameNumber; + /* + If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. This + is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits. + */ + drflac_uint32 flacFrameNumber; - // The sample rate of this frame. + /* The sample rate of this frame. */ drflac_uint32 sampleRate; - // The number of samples in each sub-frame within this frame. - drflac_uint16 blockSize; + /* The number of PCM frames in each sub-frame within this frame. */ + drflac_uint16 blockSizeInPCMFrames; - // The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this - // will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE. + /* + The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this + will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE. + */ drflac_uint8 channelAssignment; - // The number of bits per sample within this frame. + /* The number of bits per sample within this frame. */ drflac_uint8 bitsPerSample; - // The frame's CRC. + /* The frame's CRC. */ drflac_uint8 crc8; } drflac_frame_header; typedef struct { - // The header. + /* The header. */ drflac_frame_header header; - // The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples - // are read, this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. - drflac_uint32 samplesRemaining; + /* + The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read, + this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. + */ + drflac_uint32 pcmFramesRemaining; - // The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. + /* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */ drflac_subframe subframes[8]; } drflac_frame; typedef struct { - // The function to call when a metadata block is read. + /* The function to call when a metadata block is read. */ drflac_meta_proc onMeta; - // The user data posted to the metadata callback function. + /* The user data posted to the metadata callback function. */ void* pUserDataMD; + /* Memory allocation callbacks. */ + drflac_allocation_callbacks allocationCallbacks; - // The sample rate. Will be set to something like 44100. + + /* The sample rate. Will be set to something like 44100. */ drflac_uint32 sampleRate; - // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the - // value specified in the STREAMINFO block. + /* + The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the + value specified in the STREAMINFO block. + */ drflac_uint8 channels; - // The bits per sample. Will be set to somthing like 16, 24, etc. + /* The bits per sample. Will be set to something like 16, 24, etc. */ drflac_uint8 bitsPerSample; - // The maximum block size, in samples. This number represents the number of samples in each channel (not combined). - drflac_uint16 maxBlockSize; + /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */ + drflac_uint16 maxBlockSizeInPCMFrames; - // The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels, - // with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a - // valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio. - drflac_uint64 totalSampleCount; + /* + The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means + the total PCM frame count is unknown. Likely the case with streams like internet radio. + */ + drflac_uint64 totalPCMFrameCount; - // The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. + /* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */ drflac_container container; - - // The position of the seektable in the file. - drflac_uint64 seektablePos; - - // The size of the seektable. - drflac_uint32 seektableSize; + /* The number of seekpoints in the seektable. */ + drflac_uint32 seekpointCount; - // Information about the frame the decoder is currently sitting on. - drflac_frame currentFrame; - - // The position of the first frame in the stream. This is only ever used for seeking. - drflac_uint64 firstFramePos; + /* Information about the frame the decoder is currently sitting on. */ + drflac_frame currentFLACFrame; - // A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). + /* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */ + drflac_uint64 currentPCMFrame; + + /* The position of the first FLAC frame in the stream. This is only ever used for seeking. */ + drflac_uint64 firstFLACFramePosInBytes; + + + /* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */ drflac__memory_stream memoryStream; - // A pointer to the decoded sample data. This is an offset of pExtraData. + /* A pointer to the decoded sample data. This is an offset of pExtraData. */ drflac_int32* pDecodedSamples; - // Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. + /* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */ + drflac_seekpoint* pSeekpoints; + + /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */ void* _oggbs; - // The bit streamer. The raw FLAC data is fed through this object. + /* Internal use only. Used for profiling and testing different seeking modes. */ + drflac_bool32 _noSeekTableSeek : 1; + drflac_bool32 _noBinarySearchSeek : 1; + drflac_bool32 _noBruteForceSeek : 1; + + /* The bit streamer. The raw FLAC data is fed through this object. */ drflac_bs bs; - // Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. + /* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */ drflac_uint8 pExtraData[1]; } drflac; -// Opens a FLAC decoder. -// -// onRead [in] The function to call when data needs to be read from the client. -// onSeek [in] The function to call when the read position of the client data needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated -// FLAC, both of which should work seamlessly without any manual intervention. Ogg encapsulation also works with -// multiplexed streams which basically means it can play FLAC encoded audio tracks in videos. -// -// This is the lowest level function for opening a FLAC stream. You can also use drflac_open_file() and drflac_open_memory() -// to open the stream from a file or from a block of memory respectively. -// -// The STREAMINFO block must be present for this to succeed. Use drflac_open_relaxed() to open a FLAC stream where -// the header may not be present. -// -// See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close() -drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData); - -// The same as drflac_open(), except attempts to open the stream even when a header block is not present. -// -// Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do -// not set this to drflac_container_unknown - that is for internal use only. -// -// Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never -// found it will continue forever. To abort, force your onRead callback to return 0, which dr_flac will use as an -// indicator that the end of the stream was found. -drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData); - -// Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). -// -// onRead [in] The function to call when data needs to be read from the client. -// onSeek [in] The function to call when the read position of the client data needs to move. -// onMeta [in] The function to call for every metadata block. -// pUserData [in, optional] A pointer to application defined data that will be passed to onRead, onSeek and onMeta. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a DRFLAC_MALLOC() -// and DRFLAC_FREE() for every metadata block except for STREAMINFO and PADDING blocks. -// -// The caller is notified of the metadata via the onMeta callback. All metadata blocks will be handled before the function -// returns. -// -// The STREAMINFO block must be present for this to succeed. Use drflac_open_with_metadata_relaxed() to open a FLAC -// stream where the header may not be present. -// -// Note that this will behave inconsistently with drflac_open() if the stream is an Ogg encapsulated stream and a metadata -// block is corrupted. This is due to the way the Ogg stream recovers from corrupted pages. When drflac_open_with_metadata() -// is being used, the open routine will try to read the contents of the metadata block, whereas drflac_open() will simply -// seek past it (for the sake of efficiency). This inconsistency can result in different samples being returned depending on -// whether or not the stream is being opened with metadata. -// -// See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close() -drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData); - -// The same as drflac_open_with_metadata(), except attemps to open the stream even when a header block is not present. -// -// See also: drflac_open_with_metadata(), drflac_open_relaxed() -drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData); - -// Closes the given FLAC decoder. -// -// pFlac [in] The decoder to close. -// -// This will destroy the decoder object. -void drflac_close(drflac* pFlac); +/* +Opens a FLAC decoder. -// Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. -// -// pFlac [in] The decoder. -// samplesToRead [in] The number of samples to read. -// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples. -// -// Returns the number of samples actually read. -// -// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples -// seeked. -drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* pBufferOut); +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. -// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. -// -// pFlac [in] The decoder. -// samplesToRead [in] The number of samples to read. -// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples. -// -// Returns the number of samples actually read. -// -// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples -// seeked. -// -// Note that this is lossy for streams where the bits per sample is larger than 16. -drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut); +onSeek (in) + The function to call when the read position of the client data needs to move. -// Same as drflac_read_s32(), except outputs samples as 32-bit floating-point PCM. -// -// pFlac [in] The decoder. -// samplesToRead [in] The number of samples to read. -// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples. -// -// Returns the number of samples actually read. -// -// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples -// seeked. -// -// Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly -// represent every possible number. -drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut); +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. -// Seeks to the sample at the given index. -// -// pFlac [in] The decoder. -// sampleIndex [in] The index of the sample to seek to. See notes below. -// -// Returns DRFLAC_TRUE if successful; DRFLAC_FALSE otherwise. -// -// The sample index is based on interleaving. In a stereo stream, for example, the sample at index 0 is the first sample -// in the left channel; the sample at index 1 is the first sample on the right channel, and so on. -// -// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with -// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels))) -drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex); +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +Returns a pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly +without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos. + +This is the lowest level function for opening a FLAC stream. You can also use `drflac_open_file()` and `drflac_open_memory()` to open the stream from a file or +from a block of memory respectively. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present. + +Use `drflac_open_with_metadata()` if you need access to metadata. + + +Seek Also +--------- +drflac_open_file() +drflac_open_memory() +drflac_open_with_metadata() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC stream with relaxed validation of the header block. + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +container (in) + Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +The same as drflac_open(), except attempts to open the stream even when a header block is not present. + +Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown` +as that is for internal use only. + +Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort, +force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found. + +Use `drflac_open_with_metadata_relaxed()` if you need access to metadata. +*/ +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +onMeta (in) + The function to call for every metadata block. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead, onSeek and onMeta. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every +metadata block except for STREAMINFO and PADDING blocks. + +The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns. This callback takes a +pointer to a `drflac_metadata` object which is a union containing the data of all relevant metadata blocks. Use the `type` member to discriminate against +the different metadata types. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present. + +Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to +the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the +metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being +returned depending on whether or not the stream is being opened with metadata. + + +Seek Also +--------- +drflac_open_file_with_metadata() +drflac_open_memory_with_metadata() +drflac_open() +drflac_close() +*/ +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); + +/* +The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present. + +See Also +-------- +drflac_open_with_metadata() +drflac_open_relaxed() +*/ +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); + +/* +Closes the given FLAC decoder. + + +Parameters +---------- +pFlac (in) + The decoder to close. + + +Remarks +------- +This will destroy the decoder object. + + +See Also +-------- +drflac_open() +drflac_open_with_metadata() +drflac_open_file() +drflac_open_file_w() +drflac_open_file_with_metadata() +drflac_open_file_with_metadata_w() +drflac_open_memory() +drflac_open_memory_with_metadata() +*/ +DRFLAC_API void drflac_close(drflac* pFlac); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this is lossy for streams where the bits per sample is larger than 16. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut); + +/* +Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut); + +/* +Seeks to the PCM frame at the given index. + + +Parameters +---------- +pFlac (in) + The decoder. + +pcmFrameIndex (in) + The index of the PCM frame to seek to. See notes below. + + +Return Value +------------- +`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise. +*/ +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex); #ifndef DR_FLAC_NO_STDIO -// Opens a FLAC decoder from the file at the given path. -// -// filename [in] The path of the file to open, either absolute or relative to the current directory. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the -// number of files a process can have open at any given time, so keep this mind if you have many decoders open at the -// same time. -// -// See also: drflac_open(), drflac_open_file_with_metadata(), drflac_close() -drflac* drflac_open_file(const char* filename); +/* +Opens a FLAC decoder from the file at the given path. -// Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) -// -// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. -drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData); + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with drflac_close(). + + +Remarks +------- +This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the number of files a process can have open +at any given time, so keep this mind if you have many decoders open at the same time. + + +See Also +-------- +drflac_open_file_with_metadata() +drflac_open() +drflac_close() +*/ +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); + +/* +Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +-------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +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 -// Opens a FLAC decoder from a pre-allocated block of memory -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the decoder. -drflac* drflac_open_memory(const void* data, size_t dataSize); +/* +Opens a FLAC decoder from a pre-allocated block of memory -// Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) -// -// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. -drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData); + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for the lifetime of the decoder. + + +See Also +-------- +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +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); -//// High Level APIs //// +/* High Level APIs */ -// Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a -// pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with DRFLAC_FREE(). -// -// Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously -// read samples into a dynamically sized buffer on the heap until no samples are left. -// -// Do not call this function on a broadcast type of stream (like internet radio streams and whatnot). -drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* +Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a +pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free(). -// Same as drflac_open_and_decode_s32(), except returns signed 16-bit integer samples. -drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which +case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. -// Same as drflac_open_and_decode_s32(), except returns 32-bit floating-point samples. -float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously +read samples into a dynamically sized buffer on the heap until no samples are left. + +Do not call this function on a broadcast type of stream (like internet radio streams and whatnot). +*/ +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); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +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); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +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 -// Same as drflac_open_and_decode_s32() except opens the decoder from a file. -drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */ +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); -// Same as drflac_open_and_decode_file_s32(), except returns signed 16-bit integer samples. -drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +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); -// Same as drflac_open_and_decode_file_f32(), except returns 32-bit floating-point samples. -float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +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 -// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory. -drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */ +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); -// Same as drflac_open_and_decode_memory_s32(), except returns signed 16-bit integer samples. -drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +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); -// Same as drflac_open_and_decode_memory_s32(), except returns 32-bit floating-point samples. -float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +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); -// Frees memory that was allocated internally by dr_flac. -void drflac_free(void* p); +/* +Frees memory that was allocated internally by dr_flac. + +Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this. +*/ +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks); -// Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. +/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */ typedef struct { drflac_uint32 countRemaining; const char* pRunningData; } drflac_vorbis_comment_iterator; -// Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT -// metadata block. -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments); +/* +Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT +metadata block. +*/ +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments); -// Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The -// returned string is NOT null terminated. -const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); +/* +Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The +returned string is NOT null terminated. +*/ +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); +/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */ +typedef struct +{ + drflac_uint32 countRemaining; + 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. */ +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 index; + drflac_uint8 reserved[3]; +} drflac_cuesheet_track_index; + +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 trackNumber; + char ISRC[12]; + drflac_bool8 isAudio; + drflac_bool8 preEmphasis; + drflac_uint8 indexCount; + const drflac_cuesheet_track_index* pIndexPoints; +} drflac_cuesheet_track; + +/* +Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata +block. +*/ +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData); + +/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */ +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); + #ifdef __cplusplus } #endif -#endif //dr_flac_h +#endif /* dr_flac_h */ -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef DR_FLAC_IMPLEMENTATION +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) +#ifndef dr_flac_c +#define dr_flac_c + +/* Disable some annoying warnings. */ +#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 + +#ifdef __linux__ + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + #ifndef __USE_BSD + #define __USE_BSD + #endif + #include +#endif + #include #include -// CPU architecture. -#if defined(__x86_64__) || defined(_M_X64) -#define DRFLAC_X64 -#elif defined(__i386) || defined(_M_IX86) -#define DRFLAC_X86 +/* Inline */ +#ifdef _MSC_VER + #define DRFLAC_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRFLAC_GNUC_INLINE_HINT __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 + #endif +#elif defined(__WATCOMC__) + #define DRFLAC_INLINE __inline +#else + #define DRFLAC_INLINE +#endif +/* End Inline */ + +/* +Intrinsics Support + +There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with + + "error: shift must be an immediate" + +Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below. +*/ +#if !defined(DR_FLAC_NO_SIMD) + #if defined(DRFLAC_X64) || defined(DRFLAC_X86) + #if defined(_MSC_VER) && !defined(__clang__) + /* MSVC. */ + #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2) /* 2005 */ + #define DRFLAC_SUPPORT_SSE2 + #endif + #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */ + #define DRFLAC_SUPPORT_SSE41 + #endif + #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) + /* Assume GNUC-style. */ + #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2) + #define DRFLAC_SUPPORT_SSE2 + #endif + #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41) + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include() + #define DRFLAC_SUPPORT_SSE2 + #endif + #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include() + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + #if defined(DRFLAC_SUPPORT_SSE41) + #include + #elif defined(DRFLAC_SUPPORT_SSE2) + #include + #endif + #endif + + #if defined(DRFLAC_ARM) + #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + #define DRFLAC_SUPPORT_NEON + #include + #endif + #endif #endif -// Compile-time CPU feature support. +/* Compile-time CPU feature support. */ #if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) - #ifdef _MSC_VER + #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER >= 1400 #include static void drflac__cpuid(int info[4], int fid) @@ -771,63 +1460,153 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr __cpuid(info, fid); } #else - #define DRFLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif #else #if defined(__GNUC__) || defined(__clang__) static void drflac__cpuid(int info[4], int fid) { - asm ( - "movl %[fid], %%eax\n\t" - "cpuid\n\t" - "movl %%eax, %[info0]\n\t" - "movl %%ebx, %[info1]\n\t" - "movl %%ecx, %[info2]\n\t" - "movl %%edx, %[info3]\n\t" - : [info0] "=rm"(info[0]), - [info1] "=rm"(info[1]), - [info2] "=rm"(info[2]), - [info3] "=rm"(info[3]) - : [fid] "rm"(fid) - : "eax", "ebx", "ecx", "edx" - ); + /* + It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the + specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for + supporting different assembly dialects. + + What's basically happening is that we're saving and restoring the ebx register manually. + */ + #if defined(DRFLAC_X86) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg{l} {%%}ebx, %k1;" + "cpuid;" + "xchg{l} {%%}ebx, %k1;" + : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #else + __asm__ __volatile__ ( + "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #endif } #else - #define DRFLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif #endif #else -#define DRFLAC_NO_CPUID + #define DRFLAC_NO_CPUID #endif - -#ifdef __linux__ -#define _BSD_SOURCE -#include +static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; /* 64-bit targets always support SSE2. */ + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[3] & (1 << 26)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ #endif +} -#if defined(_MSC_VER) && _MSC_VER >= 1500 -#define DRFLAC_HAS_LZCNT_INTRINSIC -#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) -#define DRFLAC_HAS_LZCNT_INTRINSIC -#elif defined(__clang__) - #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) +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__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[2] & (1 << 19)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE41 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + + +#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 DRFLAC_HAS_LZCNT_INTRINSIC - #endif -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1300 -#define DRFLAC_HAS_BYTESWAP_INTRINSIC -#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -#define DRFLAC_HAS_BYTESWAP_INTRINSIC #elif defined(__clang__) - #if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) - #define DRFLAC_HAS_BYTESWAP_INTRINSIC + #if defined(__has_builtin) + #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) + #define DRFLAC_HAS_LZCNT_INTRINSIC + #endif #endif #endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__) + #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 DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif +#elif defined(__WATCOMC__) && defined(__386__) + #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; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + value [eax] \ + modify nomemory; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + value [eax edx] \ + modify nomemory; +#endif -// Standard library stuff. + +/* Standard library stuff. */ #ifndef DRFLAC_ASSERT #include #define DRFLAC_ASSERT(expression) assert(expression) @@ -847,25 +1626,72 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, dr #ifndef DRFLAC_ZERO_MEMORY #define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif - -#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. - -#ifdef _MSC_VER -#define DRFLAC_INLINE __forceinline -#else -#ifdef __GNUC__ -#define DRFLAC_INLINE inline __attribute__((always_inline)) -#else -#define DRFLAC_INLINE inline -#endif +#ifndef DRFLAC_ZERO_OBJECT +#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p))) #endif +#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. +#define DRFLAC_SUCCESS 0 +#define DRFLAC_ERROR -1 /* A generic error. */ #define DRFLAC_INVALID_ARGS -2 -#define DRFLAC_END_OF_STREAM -128 -#define DRFLAC_CRC_MISMATCH -129 +#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 -100 +/* End Result Codes */ + #define DRFLAC_SUBFRAME_CONSTANT 0 #define DRFLAC_SUBFRAME_VERBATIM 1 @@ -881,37 +1707,120 @@ 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)) -#define drflac_assert DRFLAC_ASSERT -#define drflac_copy_memory DRFLAC_COPY_MEMORY -#define drflac_zero_memory DRFLAC_ZERO_MEMORY -// CPU caps. -static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; -#ifndef DRFLAC_NO_CPUID -static drflac_bool32 drflac__gIsSSE42Supported = DRFLAC_FALSE; -static void drflac__init_cpu_caps() +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision) { - int info[4] = {0}; + if (pMajor) { + *pMajor = DRFLAC_VERSION_MAJOR; + } - // LZCNT - drflac__cpuid(info, 0x80000001); - drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; + if (pMinor) { + *pMinor = DRFLAC_VERSION_MINOR; + } - // SSE4.2 - drflac__cpuid(info, 1); - drflac__gIsSSE42Supported = (info[2] & (1 << 19)) != 0; + if (pRevision) { + *pRevision = DRFLAC_VERSION_REVISION; + } +} + +DRFLAC_API const char* drflac_version_string(void) +{ + return DRFLAC_VERSION_STRING; +} + + +/* CPU caps. */ +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #else + #define DRFLAC_NO_THREAD_SANITIZE + #endif +#else + #define DRFLAC_NO_THREAD_SANITIZE +#endif + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; +#endif + +#ifndef DRFLAC_NO_CPUID +static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; +static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE; + +/* +I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does +actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of +complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore +just going to disable these warnings. This is disabled via the DRFLAC_NO_THREAD_SANITIZE attribute. +*/ +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE; + + if (!isCPUCapsInitialized) { + /* LZCNT */ +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) + int info[4] = {0}; + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; +#endif + + /* SSE2 */ + drflac__gIsSSE2Supported = drflac_has_sse2(); + + /* SSE4.1 */ + drflac__gIsSSE41Supported = drflac_has_sse41(); + + /* Initialized. */ + isCPUCapsInitialized = DRFLAC_TRUE; + } +} +#else +static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE; + +static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void) +{ +#if defined(DRFLAC_SUPPORT_NEON) + #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON) + #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */ + #else + /* TODO: Runtime check. */ + return DRFLAC_FALSE; + #endif + #else + return DRFLAC_FALSE; /* NEON is only supported on ARM architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + 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 -//// Endian Management //// -static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian() +/* Endian Management */ +static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void) { #if defined(DRFLAC_X86) || defined(DRFLAC_X64) return DRFLAC_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRFLAC_TRUE; #else int n = 1; return (*(char*)&n) == 1; @@ -920,11 +1829,13 @@ static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian() static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) { -#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC - #if defined(_MSC_VER) +#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_ushort(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -936,11 +1847,26 @@ static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) { -#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC - #if defined(_MSC_VER) +#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_ulong(n); #elif defined(__GNUC__) || defined(__clang__) - return __builtin_bswap32(n); + #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. */ + /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ + drflac_uint32 r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); #else #error "This compiler does not support the byte swap intrinsic." #endif @@ -954,78 +1880,77 @@ static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) { -#ifdef DRFLAC_HAS_BYTESWAP_INTRINSIC - #if defined(_MSC_VER) +#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) return _byteswap_uint64(n); #elif defined(__GNUC__) || defined(__clang__) return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); #else #error "This compiler does not support the byte swap intrinsic." #endif #else - return ((n & (drflac_uint64)0xFF00000000000000) >> 56) | - ((n & (drflac_uint64)0x00FF000000000000) >> 40) | - ((n & (drflac_uint64)0x0000FF0000000000) >> 24) | - ((n & (drflac_uint64)0x000000FF00000000) >> 8) | - ((n & (drflac_uint64)0x00000000FF000000) << 8) | - ((n & (drflac_uint64)0x0000000000FF0000) << 24) | - ((n & (drflac_uint64)0x000000000000FF00) << 40) | - ((n & (drflac_uint64)0x00000000000000FF) << 56); + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + 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 DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n) { -#ifdef __linux__ - return be16toh(n); -#else if (drflac__is_little_endian()) { return drflac__swap_endian_uint16(n); } return n; -#endif } static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) { -#ifdef __linux__ - return be32toh(n); -#else if (drflac__is_little_endian()) { return drflac__swap_endian_uint32(n); } return n; -#endif +} + +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) { -#ifdef __linux__ - return be64toh(n); -#else if (drflac__is_little_endian()) { return drflac__swap_endian_uint64(n); } return n; -#endif } static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) { -#ifdef __linux__ - return le32toh(n); -#else if (!drflac__is_little_endian()) { return drflac__swap_endian_uint32(n); } return n; -#endif +} + +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; } @@ -1042,7 +1967,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) -// The CRC code below is based on this document: http://zlib.net/crc_v3.txt +/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */ 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, @@ -1104,8 +2029,6 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) { - drflac_assert(count <= 32); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; @@ -1113,7 +2036,7 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 da return 0; #else #if 0 - // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */ drflac_uint8 p = 0x07; for (int i = count-1; i >= 0; --i) { drflac_uint8 bit = (data & (1 << i)) >> i; @@ -1125,20 +2048,26 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 da } return crc; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + DRFLAC_ASSERT(count <= 32); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { 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 = (crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]; + case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]); } return crc; #endif @@ -1150,6 +2079,22 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_u return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data]; } +static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data) +{ +#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 = 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 DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount) { switch (byteCount) @@ -1169,10 +2114,9 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_ return crc; } +#if 0 static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) { - drflac_assert(count <= 64); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; @@ -1180,7 +2124,7 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac return 0; #else #if 0 - // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */ drflac_uint16 p = 0x8005; for (int i = count-1; i >= 0; --i) { drflac_uint16 bit = (data & (1ULL << i)) >> i; @@ -1193,13 +2137,19 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac return crc; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: @@ -1216,32 +2166,36 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) { - drflac_assert(count <= 64); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; (void)count; return 0; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: - case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0xFF00000000000000 << leftoverBits)) >> (56 + leftoverBits))); - case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00FF000000000000 << leftoverBits)) >> (48 + leftoverBits))); - case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000FF0000000000 << leftoverBits)) >> (40 + leftoverBits))); - case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000FF00000000 << leftoverBits)) >> (32 + leftoverBits))); - case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000FF000000 << leftoverBits)) >> (24 + leftoverBits))); - case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000000000FF0000 << leftoverBits)) >> (16 + leftoverBits))); - case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000000000FF00 << leftoverBits)) >> ( 8 + leftoverBits))); - case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000000000FF << leftoverBits)) >> ( 0 + leftoverBits))); + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + 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; @@ -1257,6 +2211,7 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_ return drflac_crc16__32bit(crc, data, count); #endif } +#endif #ifdef DRFLAC_64BIT @@ -1265,27 +2220,26 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_ #define drflac__be2host__cache_line drflac__be2host_32 #endif -// BIT READING ATTEMPT #2 -// -// This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting -// on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache -// is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an -// array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data -// from onRead() is read into. -#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)) -#ifdef DRFLAC_64BIT -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint64)-1LL) >> (_bitCount))) -#else -#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((drflac_uint32)-1) >> (_bitCount))) -#endif -#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_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) +/* +BIT READING ATTEMPT #2 + +This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting +on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache +is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an +array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data +from onRead() is read into. +*/ +#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 @@ -1297,25 +2251,33 @@ static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs) static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) { - bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); - bs->crc16CacheIgnoredBytes = 0; + if (bs->crc16CacheIgnoredBytes == 0) { + bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache); + } else { + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); + bs->crc16CacheIgnoredBytes = 0; + } } static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) { - // We should never be flushing in a situation where we are not aligned on a byte boundary. - drflac_assert((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); + /* We should never be flushing in a situation where we are not aligned on a byte boundary. */ + DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); - // The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined - // by the number of bits that have been consumed. + /* + The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined + by the number of bits that have been consumed. + */ if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { drflac__update_crc16(bs); } else { - // We only accumulate the consumed bits. + /* We only accumulate the consumed bits. */ bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); - // The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated - // so we can handle that later. + /* + The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated + so we can handle that later. + */ bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; } @@ -1325,19 +2287,24 @@ static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) { - // Fast path. Try loading straight from L2. + size_t bytesRead; + size_t alignedL1LineCount; + + /* Fast path. Try loading straight from L2. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; return DRFLAC_TRUE; } - // If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's - // any left. + /* + If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's + any left. + */ if (bs->unalignedByteCount > 0) { - return DRFLAC_FALSE; // If we have any unaligned bytes it means there's no more aligned bytes left in the client. + return DRFLAC_FALSE; /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */ } - size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); bs->nextL2Line = 0; if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { @@ -1346,13 +2313,15 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs } - // If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably - // means we've just reached the end of the file. We need to move the valid data down to the end of the buffer - // and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to - // the size of the L1 so we'll need to seek backwards by any misaligned bytes. - size_t alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); + /* + If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably + means we've just reached the end of the file. We need to move the valid data down to the end of the buffer + and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to + the size of the L1 so we'll need to seek backwards by any misaligned bytes. + */ + alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); - // We need to keep track of any unaligned bytes for later use. + /* We need to keep track of any unaligned bytes for later use. */ bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); if (bs->unalignedByteCount > 0) { bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; @@ -1360,7 +2329,8 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs if (alignedL1LineCount > 0) { size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; - for (size_t i = alignedL1LineCount; i > 0; --i) { + size_t i; + for (i = alignedL1LineCount; i > 0; --i) { bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; } @@ -1368,7 +2338,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs bs->cache = bs->cacheL2[bs->nextL2Line++]; return DRFLAC_TRUE; } else { - // If we get into this branch it means we weren't able to load any L1-aligned data. + /* If we get into this branch it means we weren't able to load any L1-aligned data. */ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); return DRFLAC_FALSE; } @@ -1376,11 +2346,13 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs static drflac_bool32 drflac__reload_cache(drflac_bs* bs) { + size_t bytesRead; + #ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); #endif - // Fast path. Try just moving the next value in the L2 cache to the L1 cache. + /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */ if (drflac__reload_l1_cache_from_l2(bs)) { bs->cache = drflac__be2host__cache_line(bs->cache); bs->consumedBits = 0; @@ -1390,22 +2362,25 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) return DRFLAC_TRUE; } - // Slow path. + /* Slow path. */ - // If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last - // few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the - // data from the unaligned cache. - size_t bytesRead = bs->unalignedByteCount; + /* + If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last + few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the + data from the unaligned cache. + */ + bytesRead = bs->unalignedByteCount; if (bytesRead == 0) { + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- The stream has been exhausted, so marked the bits as consumed. */ return DRFLAC_FALSE; } - drflac_assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(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_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. - bs->unalignedByteCount = 0; // <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */ + bs->unalignedByteCount = 0; /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */ #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache >> bs->consumedBits; @@ -1416,10 +2391,10 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) static void drflac__reset_cache(drflac_bs* bs) { - bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); // <-- This clears the L2 cache. - bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- This clears the L1 cache. + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); /* <-- This clears the L2 cache. */ + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- This clears the L1 cache. */ bs->cache = 0; - bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes. + bs->unalignedByteCount = 0; /* <-- This clears the trailing unaligned bytes. */ bs->unalignedCache = 0; #ifndef DR_FLAC_NO_CRC @@ -1431,10 +2406,10 @@ static void drflac__reset_cache(drflac_bs* bs) static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut) { - drflac_assert(bs != NULL); - drflac_assert(pResultOut != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 32); + 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)) { @@ -1443,27 +2418,48 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i } if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* + If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do + a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly + more optimal solution for this. + */ +#ifdef DRFLAC_64BIT + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; +#else if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { - *pResultOut = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); bs->consumedBits += bitCount; bs->cache <<= bitCount; } else { + /* Cannot shift by 32-bits, so need to do it differently. */ *pResultOut = (drflac_uint32)bs->cache; bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; } +#endif + return DRFLAC_TRUE; } else { - // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); drflac_uint32 bitCountLo = bitCount - bitCountHi; - drflac_uint32 resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 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 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } - *pResultOut = (resultHi << bitCountLo) | DRFLAC_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 DRFLAC_TRUE; @@ -1472,34 +2468,41 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) { - drflac_assert(bs != NULL); - drflac_assert(pResult != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 32); - 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; } - drflac_uint32 signbit = ((result >> (bitCount-1)) & 0x01); - result |= (~signbit + 1) << bitCount; + /* Do not attempt to shift by 32 as it's undefined. */ + if (bitCount < 32) { + drflac_uint32 signbit; + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + } *pResult = (drflac_int32)result; return DRFLAC_TRUE; } +#ifdef DRFLAC_64BIT static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) { - drflac_assert(bitCount <= 64); - drflac_assert(bitCount > 32); - 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; } - drflac_uint32 resultLo; if (!drflac__read_uint32(bs, 32, &resultLo)) { return DRFLAC_FALSE; } @@ -1507,19 +2510,22 @@ static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, d *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo); return DRFLAC_TRUE; } +#endif -// Function below is unused, but leaving it here in case I need to quickly add it again. +/* Function below is unused, but leaving it here in case I need to quickly add it again. */ #if 0 static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) { - drflac_assert(bitCount <= 64); - drflac_uint64 result; + drflac_uint64 signbit; + + DRFLAC_ASSERT(bitCount <= 64); + if (!drflac__read_uint64(bs, bitCount, &result)) { return DRFLAC_FALSE; } - drflac_uint64 signbit = ((result >> (bitCount-1)) & 0x01); + signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; *pResultOut = (drflac_int64)result; @@ -1529,12 +2535,13 @@ static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) { - drflac_assert(bs != NULL); - drflac_assert(pResult != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 16); - 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; } @@ -1546,12 +2553,13 @@ static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, d #if 0 static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) { - drflac_assert(bs != NULL); - drflac_assert(pResult != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 16); - 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; } @@ -1563,12 +2571,13 @@ static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) { - drflac_assert(bs != NULL); - drflac_assert(pResult != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 8); - 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; } @@ -1579,12 +2588,13 @@ static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) { - drflac_assert(bs != NULL); - drflac_assert(pResult != NULL); - drflac_assert(bitCount > 0); - drflac_assert(bitCount <= 8); - 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; } @@ -1601,12 +2611,12 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) bs->cache <<= bitsToSeek; return DRFLAC_TRUE; } else { - // It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. + /* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */ bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); bs->cache = 0; - // Simple case. Seek in groups of the same number as bits that fit within a cache line. + /* Simple case. Seek in groups of the same number as bits that fit within a cache line. */ #ifdef DRFLAC_64BIT while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { drflac_uint64 bin; @@ -1625,7 +2635,7 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) } #endif - // Whole leftover bytes. + /* Whole leftover bytes. */ while (bitsToSeek >= 8) { drflac_uint8 bin; if (!drflac__read_uint8(bs, 8, &bin)) { @@ -1634,38 +2644,41 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) bitsToSeek -= 8; } - // Leftover bits. + /* Leftover bits. */ if (bitsToSeek > 0) { drflac_uint8 bin; if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) { return DRFLAC_FALSE; } - bitsToSeek = 0; // <-- Necessary for the assert below. + bitsToSeek = 0; /* <-- Necessary for the assert below. */ } - drflac_assert(bitsToSeek == 0); + DRFLAC_ASSERT(bitsToSeek == 0); return DRFLAC_TRUE; } } -// This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. +/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) { - drflac_assert(bs != NULL); + DRFLAC_ASSERT(bs != NULL); - // The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first - // thing to do is align to the next byte. + /* + The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first + thing to do is align to the next byte. + */ if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { return DRFLAC_FALSE; } for (;;) { + drflac_uint8 hi; + #ifndef DR_FLAC_NO_CRC drflac__reset_crc16(bs); #endif - drflac_uint8 hi; if (!drflac__read_uint8(bs, 8, &hi)) { return DRFLAC_FALSE; } @@ -1686,20 +2699,28 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) } } - // Should never get here. - //return DRFLAC_FALSE; + /* Should never get here. */ + /*return DRFLAC_FALSE;*/ } -#if !defined(DR_FLAC_NO_SIMD) && defined(DRFLAC_HAS_LZCNT_INTRINSIC) +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) #define DRFLAC_IMPLEMENT_CLZ_LZCNT #endif -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#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 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) { + drflac_uint32 n; static drflac_uint32 clz_table_4[] = { 0, 4, @@ -1708,13 +2729,17 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) 1, 1, 1, 1, 1, 1, 1, 1 }; - drflac_uint32 n = clz_table_4[x >> (sizeof(x)*8 - 4)]; + if (x == 0) { + return sizeof(x)*8; + } + + n = clz_table_4[x >> (sizeof(x)*8 - 4)]; if (n == 0) { #ifdef DRFLAC_64BIT - if ((x & 0xFFFFFFFF00000000ULL) == 0) { n = 32; x <<= 32; } - if ((x & 0xFFFF000000000000ULL) == 0) { n += 16; x <<= 16; } - if ((x & 0xFF00000000000000ULL) == 0) { n += 8; x <<= 8; } - if ((x & 0xF000000000000000ULL) == 0) { n += 4; x <<= 4; } + 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; } @@ -1727,19 +2752,44 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) } #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT -static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported() +static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) { - // If the compiler itself does not support the intrinsic then we'll need to return false. -#ifdef DRFLAC_HAS_LZCNT_INTRINSIC - return drflac__gIsLZCNTSupported; + /* 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 - return DRFLAC_FALSE; + /* If the compiler itself does not support the intrinsic then we'll need to return false. */ + #ifdef DRFLAC_HAS_LZCNT_INTRINSIC + return drflac__gIsLZCNTSupported; + #else + return DRFLAC_FALSE; + #endif #endif } static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) { -#ifdef _MSC_VER + /* + It's critical for competitive decoding performance that this function be highly optimal. With MSVC we can use the __lzcnt64() and __lzcnt() intrinsics + to achieve good performance, however on GCC and Clang it's a little bit more annoying. The __builtin_clzl() and __builtin_clzll() intrinsics leave + it undefined as to the return value when `x` is 0. We need this to be well defined as returning 32 or 64, depending on whether or not it's a 32- or + 64-bit build. To work around this we would need to add a conditional to check for the x = 0 case, but this creates unnecessary inefficiency. To work + around this problem I have written some inline assembly to emit the LZCNT (x86) or CLZ (ARM) instruction directly which removes the need to include + the conditional. This has worked well in the past, but for some reason Clang's MSVC compatible driver, clang-cl, does not seem to be handling this + in the same way as the normal Clang driver. It seems that `clang-cl` is just outputting the wrong results sometimes, maybe due to some register + getting clobbered? + + I'm not sure if this is a bug with dr_flac's inlined assembly (most likely), a bug in `clang-cl` or just a misunderstanding on my part with inline + assembly rules for `clang-cl`. If somebody can identify an error in dr_flac's inlined assembly I'm happy to get that fixed. + + Fortunately there is an easy workaround for this. Clang implements MSVC-specific intrinsics for compatibility. It also defines _MSC_VER for extra + compatibility. We can therefore just check for _MSC_VER and use the MSVC intrinsic which, fortunately for us, Clang supports. It would still be nice + to know how to fix the inlined assembly for correctness sake, however. + */ + +#if defined(_MSC_VER) /*&& !defined(__clang__)*/ /* <-- Intentionally wanting Clang to use the MSVC __lzcnt64/__lzcnt intrinsics due to above ^. */ #ifdef DRFLAC_64BIT return (drflac_uint32)__lzcnt64(x); #else @@ -1747,13 +2797,49 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) #endif #else #if defined(__GNUC__) || defined(__clang__) - #ifdef DRFLAC_64BIT - return (drflac_uint32)__builtin_clzll((unsigned long long)x); + #if defined(DRFLAC_X64) + { + drflac_uint64 r; + __asm__ __volatile__ ( + "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + ); + + return (drflac_uint32)r; + } + #elif defined(DRFLAC_X86) + { + drflac_uint32 r; + __asm__ __volatile__ ( + "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + ); + + 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. */ + { + unsigned int r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x) + #endif + ); + + return r; + } #else - return (drflac_uint32)__builtin_clzl((unsigned long)x); + if (x == 0) { + return sizeof(x)*8; + } + #ifdef DRFLAC_64BIT + return (drflac_uint32)__builtin_clzll((drflac_uint64)x); + #else + return (drflac_uint32)__builtin_clzl((drflac_uint32)x); + #endif #endif #else - // Unsupported compiler. + /* Unsupported compiler. */ #error "This compiler does not support the lzcnt intrinsic." #endif #endif @@ -1761,9 +2847,16 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) #endif #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#include /* For BitScanReverse(). */ + static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) { drflac_uint32 n; + + if (x == 0) { + return sizeof(x)*8; + } + #ifdef DRFLAC_64BIT _BitScanReverse64((unsigned long*)&n, x); #else @@ -1773,27 +2866,54 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) } #endif +#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" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif +#endif + static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) { - // This function assumes at least one bit is set. Checking for 0 needs to be done at a higher level, outside this function. #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT if (drflac__is_lzcnt_supported()) { return drflac__clz_lzcnt(x); } else #endif { - #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC return drflac__clz_msvc(x); - #else +#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 +#endif } } -static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) { drflac_uint32 zeroCounter = 0; + drflac_uint32 setBitOffsetPlus1; + while (bs->cache == 0) { zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); if (!drflac__reload_cache(bs)) { @@ -1801,10 +2921,24 @@ static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsign } } - drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); - zeroCounter += setBitOffsetPlus1; + 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; @@ -1816,12 +2950,14 @@ static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsign static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart) { - drflac_assert(bs != NULL); - drflac_assert(offsetFromStart > 0); + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(offsetFromStart > 0); - // Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which - // is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. - // To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + /* + Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which + is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. + To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + */ if (offsetFromStart > 0x7FFFFFFF) { drflac_uint64 bytesRemaining = offsetFromStart; if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { @@ -1847,7 +2983,7 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro } } - // The cache should be reset to force a reload of fresh data from the client. + /* The cache should be reset to force a reload of fresh data from the client. */ drflac__reset_cache(bs); return DRFLAC_TRUE; } @@ -1855,15 +2991,21 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) { - drflac_assert(bs != NULL); - drflac_assert(pNumberOut != NULL); + drflac_uint8 crc; + drflac_uint64 result; + drflac_uint8 utf8[7] = {0}; + int byteCount; + int i; - drflac_uint8 crc = *pCRCOut; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pNumberOut != NULL); + DRFLAC_ASSERT(pCRCOut != NULL); + + crc = *pCRCOut; - unsigned char utf8[7] = {0}; if (!drflac__read_uint8(bs, 8, utf8)) { *pNumberOut = 0; - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } crc = drflac_crc8(crc, utf8[0], 8); @@ -1873,7 +3015,7 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 return DRFLAC_SUCCESS; } - int byteCount = 1; + /*byteCount = 1;*/ if ((utf8[0] & 0xE0) == 0xC0) { byteCount = 2; } else if ((utf8[0] & 0xF0) == 0xE0) { @@ -1888,17 +3030,17 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 byteCount = 7; } else { *pNumberOut = 0; - return DRFLAC_CRC_MISMATCH; // Bad UTF-8 encoding. + return DRFLAC_CRC_MISMATCH; /* Bad UTF-8 encoding. */ } - // Read extra bytes. - drflac_assert(byteCount > 1); + /* Read extra bytes. */ + DRFLAC_ASSERT(byteCount > 1); - drflac_uint64 result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); - for (int i = 1; i < byteCount; ++i) { + result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + for (i = 1; i < byteCount; ++i) { if (!drflac__read_uint8(bs, 8, utf8 + i)) { *pNumberOut = 0; - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } crc = drflac_crc8(crc, utf8[i], 8); @@ -1911,21 +3053,44 @@ 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. -// -// 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. +/* +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_assert(order <= 32); - - // 32-bit version. - - // VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. drflac_int32 prediction = 0; + DRFLAC_ASSERT(order <= 32); + + /* 32-bit version. */ + + /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */ switch (order) { case 32: prediction += coefficients[31] * pDecodedSamples[-32]; @@ -1967,13 +3132,14 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - drflac_assert(order <= 32); - - // 64-bit version. - - // This method is faster on the 32-bit build when compiling with VC++. See note below. -#ifndef DRFLAC_64BIT drflac_int64 prediction; + + DRFLAC_ASSERT(order <= 32); + + /* 64-bit version. */ + + /* This method is faster on the 32-bit build when compiling with VC++. See note below. */ +#ifndef DRFLAC_64BIT if (order == 8) { prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; @@ -2090,18 +3256,21 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 } else { + int j; + prediction = 0; - for (int j = 0; j < (int)order; ++j) { + for (j = 0; j < (int)order; ++j) { prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; } } #endif - // VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some - // reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + /* + VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some + reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + */ #ifdef DRFLAC_64BIT - drflac_int64 prediction = 0; - + prediction = 0; switch (order) { case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; @@ -2142,16 +3311,20 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 return (drflac_int32)(prediction >> shift); } -#if 0 -// 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 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) -{ - drflac_assert(bs != NULL); - drflac_assert(count > 0); - drflac_assert(pSamplesOut != NULL); - for (drflac_uint32 i = 0; i < count; ++i) { +#if 0 +/* +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) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + for (i = 0; i < count; ++i) { drflac_uint32 zeroCounter = 0; for (;;) { drflac_uint8 bit; @@ -2183,10 +3356,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla } - if (bitsPerSample > 16) { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } else { - pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } @@ -2198,6 +3371,8 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { drflac_uint32 zeroCounter = 0; + drflac_uint32 decodedRice; + for (;;) { drflac_uint8 bit; if (!drflac__read_uint8(bs, 1, &bit)) { @@ -2211,7 +3386,6 @@ static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_ui } } - drflac_uint32 decodedRice; if (riceParam > 0) { if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { return DRFLAC_FALSE; @@ -2226,13 +3400,20 @@ static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_ui } #endif +#if 0 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); - drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; + drflac_cache_t riceParamMask; + drflac_uint32 zeroCounter; + drflac_uint32 setBitOffsetPlus1; + drflac_uint32 riceParamPart; + drflac_uint32 riceLength; + DRFLAC_ASSERT(riceParam > 0); /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */ - drflac_uint32 zeroCounter = 0; + riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + + zeroCounter = 0; while (bs->cache == 0) { zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); if (!drflac__reload_cache(bs)) { @@ -2240,85 +3421,323 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac } } - drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + setBitOffsetPlus1 = drflac__clz(bs->cache); zeroCounter += setBitOffsetPlus1; setBitOffsetPlus1 += 1; - - drflac_uint32 riceParamPart; - drflac_uint32 riceLength = setBitOffsetPlus1 + riceParam; + riceLength = setBitOffsetPlus1 + riceParam; if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); bs->consumedBits += riceLength; bs->cache <<= riceLength; } else { - bs->consumedBits += riceLength; - if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { - bs->cache <<= setBitOffsetPlus1; - } + drflac_uint32 bitCountLo; + drflac_cache_t resultHi; - // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. - drflac_uint32 bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); - drflac_cache_t resultHi = bs->cache & riceParamMask; // <-- This mask is OK because all bits after the first bits are always zero. + bs->consumedBits += riceLength; + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */ + + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); - #endif +#endif bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); bs->consumedBits = 0; - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache; - #endif +#endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ 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 >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); + riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); bs->consumedBits += bitCountLo; bs->cache <<= bitCountLo; } - *pZeroCounterOut = zeroCounter; - *pRiceParamPartOut = riceParamPart; + pZeroCounterOut[0] = zeroCounter; + pRiceParamPartOut[0] = riceParamPart; + + return DRFLAC_TRUE; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/ + drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + pZeroCounterOut[0] = lzcount; + + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; + + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Grab the high part of the rice parameter part. */ + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + 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; + } + + /* We should now have enough information to construct the rice parameter part. */ + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo; + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + zeroCounter += lzcount; + + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + pZeroCounterOut[0] = zeroCounter; + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + + return DRFLAC_TRUE; +} + +static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + 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; + } + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples_with_residual__rice__simple(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) +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) { - drflac_assert(bs != NULL); - drflac_assert(count > 0); - drflac_assert(pSamplesOut != NULL); + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0; + drflac_uint32 riceParamPart0; + drflac_uint32 riceParamMask; + drflac_uint32 i; - drflac_uint32 zeroCountPart; - drflac_uint32 riceParamPart; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); - drflac_uint32 i = 0; + (void)bitsPerSample; + (void)order; + (void)shift; + (void)coefficients; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + + i = 0; while (i < count) { - // Rice extraction. - if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { return DRFLAC_FALSE; } - // Rice reconstruction. - static drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; - riceParamPart |= (zeroCountPart << riceParam); - riceParamPart = (riceParamPart >> 1) ^ t[riceParamPart & 0x01]; - //riceParamPart = (riceParamPart >> 1) ^ (~(riceParamPart & 0x01) + 1); - - // Sample reconstruction. - if (bitsPerSample > 16) { - pSamplesOut[i] = riceParamPart + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); - } else { - pSamplesOut[i] = riceParamPart + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); - } + pSamplesOut[i] = riceParamPart0; i += 1; } @@ -2326,25 +3745,1117 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__simple(drflac_b return DRFLAC_TRUE; } -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) +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) { -#if 0 - return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); -#else - return drflac__decode_samples_with_residual__rice__simple(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); -#endif + 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 (lpcOrder == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + pSamplesOutEnd = pSamplesOut + (count & ~3); + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + 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 + against an array. Not sure why, but perhaps it's making more efficient use of registers? + */ + 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; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + 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 += 4; + } + } else { + while (pSamplesOut < pSamplesOutEnd) { + 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; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + 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 += 4; + } + } + + i = (count & ~3); + while (i < count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + /*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); + } else { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } + + i += 1; + pSamplesOut += 1; + } + + return DRFLAC_TRUE; } -// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b) +{ + __m128i r; + + /* Pack. */ + r = _mm_packs_epi32(a, b); + + /* a3a2 a1a0 b3b2 b1b0 -> a3a2 b3b2 a1a0 b1b0 */ + r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0)); + + /* a3a2 b3b2 a1a0 b1b0 -> a3b3 a2b2 a1b1 a0b0 */ + r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + + return r; +} +#endif + +#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 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 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 DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count) +{ + /* + To simplify this we are assuming count < 32. This restriction allows us to work on a low side and a high side. The low side + is shifted with zero bits, whereas the right side is shifted with sign bits. + */ + __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)); /* The high part needs to have the low part cleared. */ + + return _mm_or_si128(lo, hi); +} + +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; + 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; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i riceParamMask128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + + /* + 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 + 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. + */ +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + /* This causes strict-aliasing warnings with GCC. */ + switch (order) + { + 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 + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i prediction128; + __m128i zeroCountPart128; + __m128i riceParamPart128; + + 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(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); /* <-- SSE2 compatible */ + /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01)), _mm_set1_epi32(0xFFFFFFFF)));*/ /* <-- Only supported from SSE4.1 and is slower in my testing... */ + + if (order <= 4) { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + 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); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else if (order <= 8) { + 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)); + + /* Horizontal add and shift. */ + 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); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else { + for (i = 0; i < 4; i += 1) { + 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)); + + /* Horizontal add and shift. */ + 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); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +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; + 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; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i prediction128; + __m128i riceParamMask128; + + 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(); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + switch (order) + { + 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 + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i zeroCountPart128; + __m128i riceParamPart128; + + 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(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); /* Reset to 0. */ + + switch (order) + { + case 12: + case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0)))); + case 10: + case 9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2)))); + case 8: + case 7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0)))); + case 6: + case 5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2)))); + case 4: + case 3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0)))); + 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)))); + } + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi64(prediction128); + prediction128 = drflac__mm_srai_epi64(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + /* Our value should be sitting in prediction128[0]. We need to combine this with our SSE samples. */ + samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + 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) +{ + 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); + } else { + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } +} +#endif + +#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 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 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 DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x) +{ + vst1q_s16(p, vcombine_s16(x.val[0], x.val[1])); +} + +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 DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0) +{ + drflac_int32 x[4]; + x[3] = x3; + x[2] = x2; + x[1] = x1; + x[0] = x0; + return vld1q_s32(x); +} + +static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_s32(b, a, 1); +} + +static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_u32(b, a, 1); +} + +static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x) +{ + /* The sum must end up in position 0. */ + + /* Reference */ + /*return vdupq_n_s32( + vgetq_lane_s32(x, 3) + + vgetq_lane_s32(x, 2) + + vgetq_lane_s32(x, 1) + + vgetq_lane_s32(x, 0) + );*/ + + int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x)); + return vpadd_s32(r, r); +} + +static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x) +{ + return vadd_s64(vget_high_s64(x), vget_low_s64(x)); +} + +static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x) +{ + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(x, 0), + vgetq_lane_s32(x, 1), + vgetq_lane_s32(x, 2), + vgetq_lane_s32(x, 3) + );*/ + + return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x))); +} + +static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x) +{ + return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF)); +} + +static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x) +{ + return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF)); +} + +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; + 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; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int32x2_t shift64; + uint32x4_t one128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s32(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + 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 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. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + int32x4_t prediction128; + int32x2_t prediction64; + 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(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); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(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); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(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); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(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); + } + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +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; + 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; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + 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); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s64(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + 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 + 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. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + 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(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + + for (i = 0; i < 4; i += 1) { + int64x1_t prediction64; + + prediction128 = veorq_s64(prediction128, prediction128); /* Reset to 0. */ + switch (order) + { + case 12: + case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8))); + case 10: + case 9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8))); + case 8: + case 7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4))); + case 6: + case 5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4))); + case 4: + case 3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0))); + case 2: + case 1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0))); + } + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s64(prediction128); + prediction64 = vshl_s64(prediction64, shift64); + prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0))); + + /* Our value should be sitting in prediction64[0]. We need to combine this with our SSE samples. */ + 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); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + 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) +{ + 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); + } else { + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, 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) +{ +#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); + } 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); + } else +#endif + { + /* Scalar fallback. */ + #if 0 + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #else + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #endif + } +} + +/* Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. */ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam) { - drflac_assert(bs != NULL); - drflac_assert(count > 0); + drflac_uint32 i; - for (drflac_uint32 i = 0; i < count; ++i) { - drflac_uint32 zeroCountPart; - drflac_uint32 riceParamPart; - if (!drflac__read_rice_parts(bs, riceParam, &zeroCountPart, &riceParamPart)) { + DRFLAC_ASSERT(bs != NULL); + + for (i = 0; i < count; ++i) { + if (!drflac__seek_rice_parts(bs, riceParam)) { return DRFLAC_FALSE; } } @@ -2352,22 +4863,30 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ return DRFLAC_TRUE; } -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) +#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) { - drflac_assert(bs != NULL); - drflac_assert(count > 0); - drflac_assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32); - drflac_assert(pSamplesOut != NULL); + drflac_uint32 i; - for (unsigned int i = 0; i < count; ++i) { - if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { - return DRFLAC_FALSE; - } + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */ + DRFLAC_ASSERT(pSamplesOut != NULL); - if (bitsPerSample > 16) { - pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i); + for (i = 0; i < count; ++i) { + if (unencodedBitsPerSample > 0) { + if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { + return DRFLAC_FALSE; + } } else { - pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i); + pSamplesOut[i] = 0; + } + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); } } @@ -2375,107 +4894,143 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* } -// Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called -// 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 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +/* +Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called +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) { - drflac_assert(bs != NULL); - drflac_assert(blockSize != 0); - drflac_assert(pDecodedSamples != NULL); // <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? - drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + DRFLAC_ASSERT(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */ + if (!drflac__read_uint8(bs, 2, &residualMethod)) { return DRFLAC_FALSE; } if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return DRFLAC_FALSE; // Unknown or unsupported residual coding method. + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ } - // Ignore the first values. - pDecodedSamples += order; + /* Ignore the first values. */ + pDecodedSamples += lpcOrder; - - drflac_uint8 partitionOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { return DRFLAC_FALSE; } + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } - drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - drflac_uint32 partitionsRemaining = (1 << partitionOrder); + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { if (!drflac__read_uint8(bs, 4, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 16) { + if (riceParam == 15) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 32) { + if (riceParam == 31) { riceParam = 0xFF; } } if (riceParam != 0xFF) { - if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } else { - unsigned char unencodedBitsPerSample = 0; + drflac_uint8 unencodedBitsPerSample = 0; if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { return DRFLAC_FALSE; } - if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } } pDecodedSamples += samplesInPartition; - if (partitionsRemaining == 1) { break; } partitionsRemaining -= 1; - samplesInPartition = blockSize / (1 << partitionOrder); + + if (partitionOrder != 0) { + samplesInPartition = blockSize / (1 << partitionOrder); + } } return DRFLAC_TRUE; } -// Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called -// when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be set to 0. The -// and parameters are used to determine how many residual values need to be decoded. +/* +Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called +when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be set to 0. The + and parameters are used to determine how many residual values need to be decoded. +*/ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order) { - drflac_assert(bs != NULL); - drflac_assert(blockSize != 0); - 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 != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { - return DRFLAC_FALSE; // Unknown or unsupported residual coding method. + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ } - drflac_uint8 partitionOrder; if (!drflac__read_uint8(bs, 4, &partitionOrder)) { return DRFLAC_FALSE; } - drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - drflac_uint32 partitionsRemaining = (1 << partitionOrder); + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) <= order) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; @@ -2483,14 +5038,14 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 if (!drflac__read_uint8(bs, 4, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 16) { + if (riceParam == 15) { riceParam = 0xFF; } } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { if (!drflac__read_uint8(bs, 5, &riceParam)) { return DRFLAC_FALSE; } - if (riceParam == 32) { + if (riceParam == 31) { riceParam = 0xFF; } } @@ -2500,7 +5055,7 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 return DRFLAC_FALSE; } } else { - unsigned char unencodedBitsPerSample = 0; + drflac_uint8 unencodedBitsPerSample = 0; if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { return DRFLAC_FALSE; } @@ -2523,28 +5078,34 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 } -static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) { - // Only a single sample needs to be decoded here. + drflac_uint32 i; + + /* Only a single sample needs to be decoded here. */ drflac_int32 sample; - if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { return DRFLAC_FALSE; } - // We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely) - // we'll want to look at a more efficient way. - for (drflac_uint32 i = 0; i < blockSize; ++i) { + /* + We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely) + we'll want to look at a more efficient way. + */ + for (i = 0; i < blockSize; ++i) { pDecodedSamples[i] = sample; } return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) { - for (drflac_uint32 i = 0; i < blockSize; ++i) { + drflac_uint32 i; + + for (i = 0; i < blockSize; ++i) { drflac_int32 sample; - if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { return DRFLAC_FALSE; } @@ -2554,9 +5115,11 @@ static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint return DRFLAC_TRUE; } -static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) +static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { - drflac_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}, @@ -2564,18 +5127,17 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 {4, -6, 4, -1} }; - // Warm up samples and coefficients. - for (drflac_uint32 i = 0; i < lpcOrder; ++i) { + /* Warm up samples and coefficients. */ + for (i = 0; i < lpcOrder; ++i) { drflac_int32 sample; - if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { return DRFLAC_FALSE; } pDecodedSamples[i] = sample; } - - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { return DRFLAC_FALSE; } @@ -2585,8 +5147,11 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { drflac_uint8 i; + drflac_uint8 lpcPrecision; + drflac_int8 lpcShift; + drflac_int32 coefficients[32]; - // Warm up samples. + /* Warm up samples. */ for (i = 0; i < lpcOrder; ++i) { drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { @@ -2596,30 +5161,38 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl pDecodedSamples[i] = sample; } - drflac_uint8 lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DRFLAC_FALSE; // Invalid. + return DRFLAC_FALSE; /* Invalid. */ } lpcPrecision += 1; - - drflac_int8 lpcShift; if (!drflac__read_int8(bs, 5, &lpcShift)) { return DRFLAC_FALSE; } + /* + From the FLAC specification: - drflac_int32 coefficients[32]; + Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement) + + Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is + not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support. + */ + if (lpcShift < 0) { + return DRFLAC_FALSE; + } + + DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); for (i = 0; i < lpcOrder; ++i) { if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { return DRFLAC_FALSE; } } - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) { + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { return DRFLAC_FALSE; } @@ -2627,116 +5200,133 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl } -static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) +static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) { - drflac_assert(bs != NULL); - drflac_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}; // -1 = reserved. + const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; /* -1 = reserved. */ - // Keep looping until we find a valid sync code. + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(header != NULL); + + /* Keep looping until we find a valid sync code. */ for (;;) { + drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */ + 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; } - drflac_uint8 crc8 = 0xCE; // 0xCE = drflac_crc8(0, 0x3FFE, 14); - - drflac_uint8 reserved = 0; if (!drflac__read_uint8(bs, 1, &reserved)) { return DRFLAC_FALSE; } + if (reserved == 1) { + continue; + } crc8 = drflac_crc8(crc8, reserved, 1); - - drflac_uint8 blockingStrategy = 0; if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, blockingStrategy, 1); - - drflac_uint8 blockSize = 0; if (!drflac__read_uint8(bs, 4, &blockSize)) { return DRFLAC_FALSE; } + if (blockSize == 0) { + continue; + } crc8 = drflac_crc8(crc8, blockSize, 4); - - drflac_uint8 sampleRate = 0; if (!drflac__read_uint8(bs, 4, &sampleRate)) { return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, sampleRate, 4); - - drflac_uint8 channelAssignment = 0; if (!drflac__read_uint8(bs, 4, &channelAssignment)) { return DRFLAC_FALSE; } + if (channelAssignment > 10) { + continue; + } crc8 = drflac_crc8(crc8, channelAssignment, 4); - - drflac_uint8 bitsPerSample = 0; if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { return DRFLAC_FALSE; } + if (bitsPerSample == 3 || bitsPerSample == 7) { + continue; + } crc8 = drflac_crc8(crc8, bitsPerSample, 3); if (!drflac__read_uint8(bs, 1, &reserved)) { return DRFLAC_FALSE; } + if (reserved == 1) { + continue; + } crc8 = drflac_crc8(crc8, reserved, 1); - drflac_bool32 isVariableBlockSize = blockingStrategy == 1; + isVariableBlockSize = blockingStrategy == 1; if (isVariableBlockSize) { - drflac_uint64 sampleNumber; - drflac_result result = drflac__read_utf8_coded_number(bs, &sampleNumber, &crc8); + drflac_uint64 pcmFrameNumber; + drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8); if (result != DRFLAC_SUCCESS) { - if (result == DRFLAC_END_OF_STREAM) { + if (result == DRFLAC_AT_END) { return DRFLAC_FALSE; } else { continue; } } - header->frameNumber = 0; - header->sampleNumber = sampleNumber; + header->flacFrameNumber = 0; + header->pcmFrameNumber = pcmFrameNumber; } else { - drflac_uint64 frameNumber = 0; - drflac_result result = drflac__read_utf8_coded_number(bs, &frameNumber, &crc8); + drflac_uint64 flacFrameNumber = 0; + drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8); if (result != DRFLAC_SUCCESS) { - if (result == DRFLAC_END_OF_STREAM) { + if (result == DRFLAC_AT_END) { return DRFLAC_FALSE; } else { continue; } } - header->frameNumber = (drflac_uint32)frameNumber; // <-- Safe cast. - header->sampleNumber = 0; + header->flacFrameNumber = (drflac_uint32)flacFrameNumber; /* <-- Safe cast. */ + header->pcmFrameNumber = 0; } + DRFLAC_ASSERT(blockSize > 0); if (blockSize == 1) { - header->blockSize = 192; - } else if (blockSize >= 2 && blockSize <= 5) { - header->blockSize = 576 * (1 << (blockSize - 2)); + header->blockSizeInPCMFrames = 192; + } else if (blockSize <= 5) { + DRFLAC_ASSERT(blockSize >= 2); + header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2)); } else if (blockSize == 6) { - if (!drflac__read_uint16(bs, 8, &header->blockSize)) { + if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) { return DRFLAC_FALSE; } - crc8 = drflac_crc8(crc8, header->blockSize, 8); - header->blockSize += 1; + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8); + header->blockSizeInPCMFrames += 1; } else if (blockSize == 7) { - if (!drflac__read_uint16(bs, 16, &header->blockSize)) { + if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) { return DRFLAC_FALSE; } - crc8 = drflac_crc8(crc8, header->blockSize, 16); - header->blockSize += 1; + 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 { - header->blockSize = 256 * (1 << (blockSize - 8)); + DRFLAC_ASSERT(blockSize >= 8); + header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8)); } @@ -2760,7 +5350,7 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 crc8 = drflac_crc8(crc8, header->sampleRate, 16); header->sampleRate *= 10; } else { - continue; // Invalid. Assume an invalid block. + continue; /* Invalid. Assume an invalid block. */ } @@ -2771,15 +5361,20 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 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; } - #ifndef DR_FLAC_NO_CRC +#ifndef DR_FLAC_NO_CRC if (header->crc8 != crc8) { - continue; // CRC mismatch. Loop back to the top and find the next sync code. + continue; /* CRC mismatch. Loop back to the top and find the next sync code. */ } - #endif +#endif return DRFLAC_TRUE; } } @@ -2787,16 +5382,18 @@ static drflac_bool32 drflac__read_next_frame_header(drflac_bs* bs, drflac_uint8 static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) { drflac_uint8 header; + int type; + if (!drflac__read_uint8(bs, 8, &header)) { return DRFLAC_FALSE; } - // First bit should always be 0. + /* First bit should always be 0. */ if ((header & 0x80) != 0) { return DRFLAC_FALSE; } - int type = (header & 0x7E) >> 1; + type = (header & 0x7E) >> 1; if (type == 0) { pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT; } else if (type == 1) { @@ -2804,10 +5401,10 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe } else { if ((type & 0x20) != 0) { pSubframe->subframeType = DRFLAC_SUBFRAME_LPC; - pSubframe->lpcOrder = (type & 0x1F) + 1; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1; } else if ((type & 0x08) != 0) { pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED; - pSubframe->lpcOrder = (type & 0x07); + pSubframe->lpcOrder = (drflac_uint8)(type & 0x07); if (pSubframe->lpcOrder > 4) { pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; pSubframe->lpcOrder = 0; @@ -2821,14 +5418,14 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe return DRFLAC_FALSE; } - // Wasted bits per sample. + /* Wasted bits per sample. */ pSubframe->wastedBitsPerSample = 0; if ((header & 0x01) == 1) { unsigned int wastedBitsPerSample; if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { return DRFLAC_FALSE; } - pSubframe->wastedBitsPerSample = (unsigned char)wastedBitsPerSample + 1; + pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1; } return DRFLAC_TRUE; @@ -2836,46 +5433,58 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) { - drflac_assert(bs != NULL); - drflac_assert(frame != NULL); + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; - drflac_subframe* pSubframe = frame->subframes + subframeIndex; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; if (!drflac__read_subframe_header(bs, pSubframe)) { return DRFLAC_FALSE; } - // Side channels require an extra bit per sample. Took a while to figure that one out... - pSubframe->bitsPerSample = frame->header.bitsPerSample; + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { - pSubframe->bitsPerSample += 1; + subframeBitsPerSample += 1; } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { - pSubframe->bitsPerSample += 1; + subframeBitsPerSample += 1; } - // Need to handle wasted bits per sample. - pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample; - pSubframe->pDecodedSamples = pDecodedSamplesOut; + 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; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = pDecodedSamplesOut; switch (pSubframe->subframeType) { case DRFLAC_SUBFRAME_CONSTANT: { - drflac__decode_samples__constant(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples); + drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); } break; case DRFLAC_SUBFRAME_VERBATIM: { - drflac__decode_samples__verbatim(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples); + drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); } break; case DRFLAC_SUBFRAME_FIXED: { - drflac__decode_samples__fixed(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples); + drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); } break; case DRFLAC_SUBFRAME_LPC: { - drflac__decode_samples__lpc(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples); + drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); } break; default: return DRFLAC_FALSE; @@ -2886,38 +5495,45 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) { - drflac_assert(bs != NULL); - drflac_assert(frame != NULL); + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; - drflac_subframe* pSubframe = frame->subframes + subframeIndex; + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; if (!drflac__read_subframe_header(bs, pSubframe)) { return DRFLAC_FALSE; } - // Side channels require an extra bit per sample. Took a while to figure that one out... - pSubframe->bitsPerSample = frame->header.bitsPerSample; + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { - pSubframe->bitsPerSample += 1; + subframeBitsPerSample += 1; } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { - pSubframe->bitsPerSample += 1; + subframeBitsPerSample += 1; } - // Need to handle wasted bits per sample. - pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample; - pSubframe->pDecodedSamples = NULL; + /* Need to handle wasted bits per sample. */ + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return DRFLAC_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = NULL; switch (pSubframe->subframeType) { case DRFLAC_SUBFRAME_CONSTANT: { - if (!drflac__seek_bits(bs, pSubframe->bitsPerSample)) { + if (!drflac__seek_bits(bs, subframeBitsPerSample)) { return DRFLAC_FALSE; } } break; case DRFLAC_SUBFRAME_VERBATIM: { - unsigned int bitsToSeek = frame->header.blockSize * pSubframe->bitsPerSample; + unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } @@ -2925,39 +5541,40 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i case DRFLAC_SUBFRAME_FIXED: { - unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample; + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } - if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) { + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { return DRFLAC_FALSE; } } break; case DRFLAC_SUBFRAME_LPC: { - unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample; + drflac_uint8 lpcPrecision; + + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } - unsigned char lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DRFLAC_FALSE; // Invalid. + return DRFLAC_FALSE; /* Invalid. */ } lpcPrecision += 1; - bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; // +5 for shift. + bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */ if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } - if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) { + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { return DRFLAC_FALSE; } } break; @@ -2971,96 +5588,121 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) { - drflac_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 drflac_result drflac__decode_frame(drflac* pFlac) +static drflac_result drflac__decode_flac_frame(drflac* pFlac) { - // This function should be called while the stream is sitting on the first byte after the frame header. - drflac_zero_memory(pFlac->currentFrame.subframes, sizeof(pFlac->currentFrame.subframes)); + int channelCount; + int i; + drflac_uint8 paddingSizeInBits; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif - int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - for (int i = 0; i < channelCount; ++i) { - if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) { + /* This function should be called while the stream is sitting on the first byte after the frame header. */ + DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); + + /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */ + if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_ERROR; + } + + /* The number of channels in the frame must match the channel count from the STREAMINFO block. */ + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + if (channelCount != (int)pFlac->channels) { + return DRFLAC_ERROR; + } + + for (i = 0; i < channelCount; ++i) { + if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) { return DRFLAC_ERROR; } } - drflac_uint8 paddingSizeInBits = DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7; + paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7); if (paddingSizeInBits > 0) { drflac_uint8 padding = 0; if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } } #ifndef DR_FLAC_NO_CRC - drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - drflac_uint16 desiredCRC16; if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } #ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return DRFLAC_CRC_MISMATCH; // CRC mismatch. + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ } #endif - pFlac->currentFrame.samplesRemaining = pFlac->currentFrame.header.blockSize * channelCount; + pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; return DRFLAC_SUCCESS; } -static drflac_result drflac__seek_frame(drflac* pFlac) +static drflac_result drflac__seek_flac_frame(drflac* pFlac) { - int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - for (int i = 0; i < channelCount; ++i) { - if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFrame, i)) { + int channelCount; + int i; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif + + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + for (i = 0; i < channelCount; ++i) { + if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) { return DRFLAC_ERROR; } } - // Padding. + /* Padding. */ if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { return DRFLAC_ERROR; } - // CRC. + /* CRC. */ #ifndef DR_FLAC_NO_CRC - drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - drflac_uint16 desiredCRC16; if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } #ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return DRFLAC_CRC_MISMATCH; // CRC mismatch. + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ } #endif return DRFLAC_SUCCESS; } -static drflac_bool32 drflac__read_and_decode_next_frame(drflac* pFlac) +static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac) { - drflac_assert(pFlac != NULL); + DRFLAC_ASSERT(pFlac != NULL); for (;;) { - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + drflac_result result; + + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { return DRFLAC_FALSE; } - drflac_result result = drflac__decode_frame(pFlac); + result = drflac__decode_flac_frame(pFlac); if (result != DRFLAC_SUCCESS) { if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Skip to the next frame. + continue; /* CRC mismatch. Skip to the next frame. */ } else { return DRFLAC_FALSE; } @@ -3070,201 +5712,592 @@ static drflac_bool32 drflac__read_and_decode_next_frame(drflac* pFlac) } } - -static void drflac__get_current_frame_sample_range(drflac* pFlac, drflac_uint64* pFirstSampleInFrameOut, drflac_uint64* pLastSampleInFrameOut) +static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame) { - drflac_assert(pFlac != NULL); + drflac_uint64 firstPCMFrame; + drflac_uint64 lastPCMFrame; - unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + DRFLAC_ASSERT(pFlac != NULL); - drflac_uint64 firstSampleInFrame = pFlac->currentFrame.header.sampleNumber; - if (firstSampleInFrame == 0) { - firstSampleInFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize*channelCount; + firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber; + if (firstPCMFrame == 0) { + firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; } - drflac_uint64 lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount); - if (lastSampleInFrame > 0) { - lastSampleInFrame -= 1; // Needs to be zero based. + lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + if (lastPCMFrame > 0) { + lastPCMFrame -= 1; /* Needs to be zero based. */ } - if (pFirstSampleInFrameOut) *pFirstSampleInFrameOut = firstSampleInFrame; - if (pLastSampleInFrameOut) *pLastSampleInFrameOut = lastSampleInFrame; + if (pFirstPCMFrame) { + *pFirstPCMFrame = firstPCMFrame; + } + if (pLastPCMFrame) { + *pLastPCMFrame = lastPCMFrame; + } } static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) { - drflac_assert(pFlac != NULL); + drflac_bool32 result; - drflac_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos); + DRFLAC_ASSERT(pFlac != NULL); + + result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes); + + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + pFlac->currentPCMFrame = 0; - drflac_zero_memory(&pFlac->currentFrame, sizeof(pFlac->currentFrame)); return result; } -static DRFLAC_INLINE drflac_result drflac__seek_to_next_frame(drflac* pFlac) +static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac) { - // This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. - drflac_assert(pFlac != NULL); - return drflac__seek_frame(pFlac); + /* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */ + DRFLAC_ASSERT(pFlac != NULL); + return drflac__seek_flac_frame(pFlac); } -static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_uint64 sampleIndex) + +static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek) { - // We need to find the frame that contains the sample. To do this, we iterate over each frame and inspect it's header. If based on the - // header we can determine that the frame contains the sample, we do a full decode of that frame. - if (!drflac__seek_to_first_frame(pFlac)) { - return DRFLAC_FALSE; + drflac_uint64 pcmFramesRead = 0; + while (pcmFramesToSeek > 0) { + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) { + pcmFramesRead += pcmFramesToSeek; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */ + pcmFramesToSeek = 0; + } else { + pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining; + pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + } + } } - drflac_uint64 runningSampleCount = 0; - for (;;) { - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + pFlac->currentPCMFrame += pcmFramesRead; + return pcmFramesRead; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + + DRFLAC_ASSERT(pFlac != NULL); + + /* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */ + if (pcmFrameIndex >= pFlac->currentPCMFrame) { + /* Seeking forward. Need to seek from the current position. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Seeking backwards. Need to seek from the start of the file. */ + runningPCMFrameCount = 0; + + /* Move back to the start. */ + if (!drflac__seek_to_first_frame(pFlac)) { return DRFLAC_FALSE; } - drflac_uint64 firstSampleInFrame = 0; - drflac_uint64 lastSampleInFrame = 0; - drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); + /* Decode the first frame in preparation for sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; - if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend - // it never existed and keep iterating. - drflac_result result = drflac__decode_frame(pFlac); - if (result == DRFLAC_SUCCESS) { - // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. - drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. - if (samplesToDecode == 0) { - return DRFLAC_TRUE; - } - return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). - } else { - if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + /* + We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its + header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame. + */ + for (;;) { + 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)) { + /* + The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ } else { - return DRFLAC_FALSE; + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; } } else { - // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this - // frame never existed and leave the running sample count untouched. - drflac_result result = drflac__seek_to_next_frame(pFlac); - if (result == DRFLAC_SUCCESS) { - runningSampleCount += sampleCountInThisFrame; - } else { - if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; } else { - return DRFLAC_FALSE; + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; } } } -static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_uint64 sampleIndex) +#if !defined(DR_FLAC_NO_CRC) +/* +We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their +uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting +location. +*/ +#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) { - drflac_assert(pFlac != NULL); + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); + DRFLAC_ASSERT(targetByte >= rangeLo); + DRFLAC_ASSERT(targetByte <= rangeHi); - if (pFlac->seektablePos == 0) { - return DRFLAC_FALSE; - } + *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes; - if (!drflac__seek_to_byte(&pFlac->bs, pFlac->seektablePos)) { - return DRFLAC_FALSE; - } - - // The number of seek points is derived from the size of the SEEKTABLE block. - drflac_uint32 seekpointCount = pFlac->seektableSize / 18; // 18 = the size of each seek point. - if (seekpointCount == 0) { - return DRFLAC_FALSE; // Would this ever happen? - } - - - drflac_seekpoint closestSeekpoint = {0, 0, 0}; - - drflac_uint32 seekpointsRemaining = seekpointCount; - while (seekpointsRemaining > 0) { - drflac_seekpoint seekpoint; - if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.firstSample)) { - break; - } - if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.frameOffset)) { - break; - } - if (!drflac__read_uint16(&pFlac->bs, 16, &seekpoint.sampleCount)) { - break; - } - - // Note that the seekpoint sample is based on a single channel. The input sample (sampleIndex) is based on interleaving, thus - // we need to multiple the seekpoint's sample by the channel count. - if (seekpoint.firstSample*pFlac->channels > sampleIndex) { - break; - } - - closestSeekpoint = seekpoint; - seekpointsRemaining -= 1; - } - - // At this point we should have found the seekpoint closest to our sample. We need to seek to it using basically the same - // technique as we use with the brute force method. - if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos + closestSeekpoint.frameOffset)) { - return DRFLAC_FALSE; - } - - drflac_uint64 runningSampleCount = closestSeekpoint.firstSample*pFlac->channels; for (;;) { - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + /* After rangeLo == rangeHi == targetByte fails, we need to break out. */ + drflac_uint64 lastTargetByte = targetByte; + + /* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */ + if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) { + /* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */ + if (targetByte == 0) { + drflac__seek_to_first_frame(pFlac); /* Try to recover. */ + return DRFLAC_FALSE; + } + + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + /* Getting here should mean that we have seeked to an appropriate byte. */ + + /* Clear the details of the FLAC frame so we don't misreport data. */ + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + + /* + Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the + CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing + so it needs to stay this way for now. + */ +#if 1 + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#else + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#endif + } + + /* We already tried this byte and there are no more to try, break out. */ + if(targetByte == lastTargetByte) { return DRFLAC_FALSE; } + } - drflac_uint64 firstSampleInFrame = 0; - drflac_uint64 lastSampleInFrame = 0; - drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); + /* The current PCM frame needs to be updated based on the frame we just seeked to. */ + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; - if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend - // it never existed and keep iterating. - drflac_result result = drflac__decode_frame(pFlac); - if (result == DRFLAC_SUCCESS) { - // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. - drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. - if (samplesToDecode == 0) { - return DRFLAC_TRUE; + DRFLAC_ASSERT(targetByte <= rangeHi); + + *pLastSuccessfulSeekOffset = targetByte; + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset) +{ + /* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */ +#if 0 + if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) { + /* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */ + if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + } +#endif + + return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi) +{ + /* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */ + + 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 (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) { + /* We found a FLAC frame. We need to check if it contains the sample we're looking for. */ + drflac_uint64 newPCMRangeLo; + drflac_uint64 newPCMRangeHi; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi); + + /* If we selected the same frame, it means we should be pretty close. Just decode the rest. */ + if (pcmRangeLo == newPCMRangeLo) { + if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) { + break; /* Failed to seek to closest frame. */ } - return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). - } else { - if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; } else { - return DRFLAC_FALSE; + break; /* Failed to seek forward. */ + } + } + + pcmRangeLo = newPCMRangeLo; + pcmRangeHi = newPCMRangeHi; + + if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) { + /* The target PCM frame is in this FLAC frame. */ + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f); + + if (pcmRangeLo > pcmFrameIndex) { + /* We seeked too far forward. We need to move our target byte backward and try again. */ + byteRangeHi = lastSuccessfulSeekOffset; + if (byteRangeLo > byteRangeHi) { + byteRangeLo = byteRangeHi; + } + + targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2); + if (targetByte < byteRangeLo) { + targetByte = byteRangeLo; + } + } else /*if (pcmRangeHi < pcmFrameIndex)*/ { + /* We didn't seek far enough. We need to move our target byte forward and try again. */ + + /* If we're close enough we can just seek forward. */ + if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) { + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + byteRangeLo = lastSuccessfulSeekOffset; + if (byteRangeHi < byteRangeLo) { + byteRangeHi = byteRangeLo; + } + + targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + + if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) { + closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset; + } + } } } } else { - // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this - // frame never existed and leave the running sample count untouched. - drflac_result result = drflac__seek_to_next_frame(pFlac); - if (result == DRFLAC_SUCCESS) { - runningSampleCount += sampleCountInThisFrame; - } else { - if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. - } else { - return DRFLAC_FALSE; + /* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */ + break; + } + } + + drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */ + return DRFLAC_FALSE; +} + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + + /* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */ + if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + + /* If we're close enough to the start, just move to the start and seek forward. */ + if (pcmFrameIndex < seekForwardThreshold) { + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex; + } + + /* + Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures + the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it. + */ + byteRangeLo = pFlac->firstFLACFramePosInBytes; + 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 /* !DR_FLAC_NO_CRC */ + +static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + 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 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; + } + + iClosestSeekpoint = iSeekpoint; + } + + /* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_FALSE; + } + if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) { + return DRFLAC_FALSE; + } + +#if !defined(DR_FLAC_NO_CRC) + /* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */ + if (pFlac->totalPCMFrameCount > 0) { + 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 our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting + value for byteRangeHi which will clamp it appropriately. + + Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There + have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort. + */ + if (iClosestSeekpoint < pFlac->seekpointCount-1) { + drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1; + + /* Basic validation on the seekpoints to ensure they're usable. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) { + return DRFLAC_FALSE; /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */ + } + + if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */ + byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */ + } + } + + 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; } } } } +#endif /* !DR_FLAC_NO_CRC */ + + /* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */ + + /* + If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking + from the seekpoint's first sample. + */ + if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) { + /* Optimized case. Just seek forward from where we are. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */ + runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame; + + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + return DRFLAC_FALSE; + } + + /* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } + + for (;;) { + 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)) { + /* + The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; + } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } } #ifndef DR_FLAC_NO_OGG typedef struct { - drflac_uint8 capturePattern[4]; // Should be "OggS" - drflac_uint8 structureVersion; // Always 0. + drflac_uint8 capturePattern[4]; /* Should be "OggS" */ + drflac_uint8 structureVersion; /* Always 0. */ drflac_uint8 headerType; drflac_uint64 granulePosition; drflac_uint32 serialNumber; @@ -3286,13 +6319,13 @@ typedef struct drflac_uint32 sampleRate; drflac_uint8 channels; drflac_uint8 bitsPerSample; - drflac_uint64 totalSampleCount; - drflac_uint16 maxBlockSize; + drflac_uint64 totalPCMFrameCount; + drflac_uint16 maxBlockSizeInPCMFrames; drflac_uint64 runningFilePos; drflac_bool32 hasStreamInfoBlock; drflac_bool32 hasMetadataBlocks; - drflac_bs bs; // <-- A bit streamer is required for loading data during initialization. - drflac_frame_header firstFrameHeader; // <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. + drflac_bs bs; /* <-- A bit streamer is required for loading data during initialization. */ + drflac_frame_header firstFrameHeader; /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */ #ifndef DR_FLAC_NO_OGG drflac_uint32 oggSerial; @@ -3304,14 +6337,16 @@ typedef struct static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { blockHeader = drflac__be2host_32(blockHeader); - *isLastBlock = (blockHeader & (0x01 << 31)) >> 31; - *blockType = (blockHeader & (0x7F << 24)) >> 24; - *blockSize = (blockHeader & 0xFFFFFF); + *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31); + *blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24); + *blockSize = (blockHeader & 0x00FFFFFFUL); } 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) { drflac_uint32 blockHeader; + + *blockSize = 0; if (onRead(pUserData, &blockHeader, 4) != 4) { return DRFLAC_FALSE; } @@ -3320,28 +6355,29 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_r return DRFLAC_TRUE; } -drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) +static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) { - // min/max block size. drflac_uint32 blockSizes; + drflac_uint64 frameSizes = 0; + drflac_uint64 importantProps; + drflac_uint8 md5[16]; + + /* min/max block size. */ if (onRead(pUserData, &blockSizes, 4) != 4) { return DRFLAC_FALSE; } - // min/max frame size. - drflac_uint64 frameSizes = 0; + /* min/max frame size. */ if (onRead(pUserData, &frameSizes, 6) != 6) { return DRFLAC_FALSE; } - // Sample rate, channels, bits per sample and total sample count. - drflac_uint64 importantProps; + /* Sample rate, channels, bits per sample and total sample count. */ if (onRead(pUserData, &importantProps, 8) != 8) { return DRFLAC_FALSE; } - // MD5 - drflac_uint8 md5[16]; + /* MD5 */ if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { return DRFLAC_FALSE; } @@ -3350,40 +6386,119 @@ drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, frameSizes = drflac__be2host_64(frameSizes); importantProps = drflac__be2host_64(importantProps); - pStreamInfo->minBlockSize = (blockSizes & 0xFFFF0000) >> 16; - pStreamInfo->maxBlockSize = blockSizes & 0x0000FFFF; - pStreamInfo->minFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0xFFFFFF0000000000) >> 40); - pStreamInfo->maxFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0x000000FFFFFF0000) >> 16); - pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (drflac_uint64)0xFFFFF00000000000) >> 44); - pStreamInfo->channels = (drflac_uint8 )((importantProps & (drflac_uint64)0x00000E0000000000) >> 41) + 1; - pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (drflac_uint64)0x000001F000000000) >> 36) + 1; - pStreamInfo->totalSampleCount = (importantProps & (drflac_uint64)0x0000000FFFFFFFFF) * pStreamInfo->channels; - drflac_copy_memory(pStreamInfo->md5, md5, sizeof(md5)); + 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; } -drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) -{ - drflac_assert(pFlac != NULL); - // 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 - // we'll be sitting on byte 42. +static void* drflac__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_MALLOC(sz); +} + +static void* drflac__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_REALLOC(p, sz); +} + +static void drflac__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRFLAC_FREE(p); +} + + +static void* drflac__malloc_from_callbacks(size_t sz, const drflac_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* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_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) { + DRFLAC_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +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) +{ + /* + 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 + we'll be sitting on byte 42. + */ drflac_uint64 runningFilePos = 42; drflac_uint64 seektablePos = 0; drflac_uint32 seektableSize = 0; for (;;) { + drflac_metadata metadata; drflac_uint8 isLastBlock = 0; - drflac_uint8 blockType; + drflac_uint8 blockType = 0; drflac_uint32 blockSize; - if (!drflac__read_and_decode_block_header(pFlac->bs.onRead, pFlac->bs.pUserData, &isLastBlock, &blockType, &blockSize)) { + if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { return DRFLAC_FALSE; } runningFilePos += 4; - - drflac_metadata metadata; metadata.type = blockType; metadata.pRawData = NULL; metadata.rawDataSize = 0; @@ -3392,14 +6507,18 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) { case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: { - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + if (blockSize < 4) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } @@ -3408,9 +6527,9 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) 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); - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + onMeta(pUserDataMD, &metadata); - DRFLAC_FREE(pRawData); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; @@ -3419,176 +6538,355 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) seektablePos = runningFilePos; seektableSize = blockSize; - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(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); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); - 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); } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint); + metadata.data.seektable.seekpointCount = seekpointCount; metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; - // Endian swap. - for (drflac_uint32 iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { - drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; - pSeekpoint->firstSample = drflac__be2host_64(pSeekpoint->firstSample); - pSeekpoint->frameOffset = drflac__be2host_64(pSeekpoint->frameOffset); - pSeekpoint->sampleCount = drflac__be2host_16(pSeekpoint->sampleCount); - } + onMeta(pUserDataMD, &metadata); - pFlac->onMeta(pFlac->pUserDataMD, &metadata); - - DRFLAC_FREE(pRawData); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: { - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + if (blockSize < 8) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + drflac_uint32 i; + + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; - metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.vorbis_comment.comments = pRunningData; - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; - DRFLAC_FREE(pRawData); + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(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 */ + 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 = drflac__le2host_32_ptr_unaligned(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 */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.pComments = pRunningData; + + /* Check that the comments section is valid before passing it to the callback */ + for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + drflac_uint32 commentLength; + + if (pRunningDataEnd - pRunningData < 4) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + commentLength = drflac__le2host_32_ptr_unaligned(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; + } + pRunningData += commentLength; + } + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: { - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + if (blockSize < 396) { + return DRFLAC_FALSE; + } + + if (onMeta) { + 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; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - drflac_copy_memory(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; - metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(drflac_uint64*)pRunningData); pRunningData += 4; - metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259; - metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; - metadata.data.cuesheet.pTrackData = (const drflac_uint8*)pRunningData; - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; - DRFLAC_FREE(pRawData); + 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; /* Will be filled later. */ + + /* 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. */ + + 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) { + 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); + } + } + + metadata.data.cuesheet.pTrackData = pTrackData; + } + + /* 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; } } break; case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: { - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + if (blockSize < 32) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - metadata.data.picture.type = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; - metadata.data.picture.descriptionLength = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.description = pRunningData; - metadata.data.picture.width = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; - DRFLAC_FREE(pRawData); + metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(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; + + /* 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.pPictureData = (const drflac_uint8*)pRunningData; + + /* Need space for the picture after the block */ + if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; case DRFLAC_METADATA_BLOCK_TYPE_PADDING: { - if (pFlac->onMeta) { + if (onMeta) { metadata.data.padding.unused = 0; - // Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { - isLastBlock = DRFLAC_TRUE; // An error occured while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. + /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */ + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ } else { - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + onMeta(pUserDataMD, &metadata); } } } break; case DRFLAC_METADATA_BLOCK_TYPE_INVALID: { - // Invalid chunk. Just skip over this one. - if (pFlac->onMeta) { - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { - isLastBlock = DRFLAC_TRUE; // An error occured while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. + /* Invalid chunk. Just skip over this one. */ + if (onMeta) { + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ } } - } + } break; default: { - // It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we - // can at the very least report the chunk to the application and let it look at the raw data. - if (pFlac->onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + /* + It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we + can at the very least report the chunk to the application and let it look at the raw data. + */ + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); if (pRawData == NULL) { return DRFLAC_FALSE; } - if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) { - DRFLAC_FREE(pRawData); + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); return DRFLAC_FALSE; } metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - pFlac->onMeta(pFlac->pUserDataMD, &metadata); + onMeta(pUserDataMD, &metadata); - DRFLAC_FREE(pRawData); + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); } } break; } - // If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. - if (pFlac->onMeta == NULL && blockSize > 0) { - if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) { + /* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */ + if (onMeta == NULL && blockSize > 0) { + if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { isLastBlock = DRFLAC_TRUE; } } @@ -3599,51 +6897,54 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac* pFlac) } } - pFlac->seektablePos = seektablePos; - pFlac->seektableSize = seektableSize; - pFlac->firstFramePos = runningFilePos; + *pSeektablePos = seektablePos; + *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + *pFirstFramePos = runningFilePos; return DRFLAC_TRUE; } -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) +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) { - (void)onSeek; + /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */ - // Pre: The bit stream should be sitting just past the 4-byte id header. - - pInit->container = drflac_container_native; - - // The first metadata block should be the STREAMINFO block. drflac_uint8 isLastBlock; drflac_uint8 blockType; drflac_uint32 blockSize; + + (void)onSeek; + + pInit->container = drflac_container_native; + + /* The first metadata block should be the STREAMINFO block. */ if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { return DRFLAC_FALSE; } if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { if (!relaxed) { - // We're opening in strict mode and the first block is not the STREAMINFO block. Error. + /* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */ return DRFLAC_FALSE; } else { - // Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined - // for that frame. + /* + Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined + for that frame. + */ pInit->hasStreamInfoBlock = DRFLAC_FALSE; pInit->hasMetadataBlocks = DRFLAC_FALSE; - if (!drflac__read_next_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { - return DRFLAC_FALSE; // Couldn't find a frame. + if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { + return DRFLAC_FALSE; /* Couldn't find a frame. */ } if (pInit->firstFrameHeader.bitsPerSample == 0) { - return DRFLAC_FALSE; // Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. + return DRFLAC_FALSE; /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */ } - pInit->sampleRate = pInit->firstFrameHeader.sampleRate; - pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); - pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; - pInit->maxBlockSize = 65535; // <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo + pInit->sampleRate = pInit->firstFrameHeader.sampleRate; + pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; + pInit->maxBlockSizeInPCMFrames = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */ return DRFLAC_TRUE; } } else { @@ -3652,13 +6953,13 @@ drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_ return DRFLAC_FALSE; } - pInit->hasStreamInfoBlock = DRFLAC_TRUE; - pInit->sampleRate = streaminfo.sampleRate; - pInit->channels = streaminfo.channels; - pInit->bitsPerSample = streaminfo.bitsPerSample; - pInit->totalSampleCount = streaminfo.totalSampleCount; - pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation). - pInit->hasMetadataBlocks = !isLastBlock; + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */ + pInit->hasMetadataBlocks = !isLastBlock; if (onMeta) { drflac_metadata metadata; @@ -3675,7 +6976,7 @@ drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_ #ifndef DR_FLAC_NO_OGG #define DRFLAC_OGG_MAX_PAGE_SIZE 65307 -#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 // CRC-32 of "OggS". +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */ typedef enum { @@ -3683,7 +6984,7 @@ typedef enum 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, @@ -3750,6 +7051,7 @@ static drflac_uint32 drflac__crc32_table[] = { 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L }; +#endif static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) { @@ -3781,8 +7083,9 @@ static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drfl static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) { - // This can be optimized. - for (drflac_uint32 i = 0; i < dataSize; ++i) { + /* This can be optimized. */ + drflac_uint32 i; + for (i = 0; i < dataSize; ++i) { crc32 = drflac_crc32_byte(crc32, pData[i]); } return crc32; @@ -3802,45 +7105,58 @@ static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_p static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) { drflac_uint32 pageBodySize = 0; - for (int i = 0; i < pHeader->segmentCount; ++i) { + int i; + + for (i = 0; i < pHeader->segmentCount; ++i) { pageBodySize += pHeader->segmentTable[i]; } return pageBodySize; } -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) +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) { - drflac_assert(*pCRC32 == DRFLAC_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 DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } *pBytesRead += 23; + /* + It's not actually used, but set the capture pattern to 'OggS' for completeness. Not doing this will cause static analysers to complain about + us trying to access uninitialized data. We could alternatively just comment out this member of the drflac_ogg_page_header structure, but I + like to have it map to the structure of the underlying data. + */ + pHeader->capturePattern[0] = 'O'; + pHeader->capturePattern[1] = 'g'; + pHeader->capturePattern[2] = 'g'; + pHeader->capturePattern[3] = 'S'; + pHeader->structureVersion = data[0]; pHeader->headerType = data[1]; - 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); + 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]; - // Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. + /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */ data[18] = 0; data[19] = 0; data[20] = 0; data[21] = 0; - drflac_uint32 i; for (i = 0; i < 23; ++i) { *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); } if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } *pBytesRead += pHeader->segmentCount; @@ -3851,22 +7167,25 @@ drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_pro return DRFLAC_SUCCESS; } -drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_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) { + drflac_uint8 id[4]; + *pBytesRead = 0; - drflac_uint8 id[4]; if (onRead(pUserData, id, 4) != 4) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } *pBytesRead += 4; - // We need to read byte-by-byte until we find the OggS capture pattern. + /* We need to read byte-by-byte until we find the OggS capture pattern. */ for (;;) { if (drflac_ogg__is_capture_pattern(id)) { + drflac_result result; + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; - drflac_result result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); if (result == DRFLAC_SUCCESS) { return DRFLAC_SUCCESS; } else { @@ -3877,12 +7196,12 @@ drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserD } } } else { - // The first 4 bytes did not equal the capture pattern. Read the next byte and try again. + /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */ id[0] = id[1]; id[1] = id[2]; id[2] = id[3]; if (onRead(pUserData, &id[3], 1) != 1) { - return DRFLAC_END_OF_STREAM; + return DRFLAC_AT_END; } *pBytesRead += 1; } @@ -3890,25 +7209,27 @@ drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserD } -// The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works -// in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is architecured -// in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type -// dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from -// the physical Ogg bitstream are converted and delivered in native FLAC format. +/* +The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works +in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed +in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type +dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from +the physical Ogg bitstream are converted and delivered in native FLAC format. +*/ typedef struct { - drflac_read_proc onRead; // The original onRead callback from drflac_open() and family. - drflac_seek_proc onSeek; // The original onSeek callback from drflac_open() and family. - void* pUserData; // The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. - drflac_uint64 currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. - drflac_uint64 firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. - drflac_uint32 serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. - drflac_ogg_page_header bosPageHeader; // Used for seeking. + drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */ + drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */ + void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */ + drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */ + drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */ + drflac_uint32 serialNumber; /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */ + drflac_ogg_page_header bosPageHeader; /* Used for seeking. */ drflac_ogg_page_header currentPageHeader; drflac_uint32 bytesRemainingInPage; drflac_uint32 pageDataSize; drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; -} drflac_oggbs; // oggbs = Ogg Bitstream +} drflac_oggbs; /* oggbs = Ogg Bitstream */ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) { @@ -3945,7 +7266,7 @@ static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uin offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { // <-- Safe cast thanks to the loop above. + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */ return DRFLAC_FALSE; } oggbs->currentBytePos += offset; @@ -3960,18 +7281,23 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og for (;;) { drflac_uint32 crc32 = 0; drflac_uint32 bytesRead; + drflac_uint32 pageBodySize; +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32; +#endif + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { return DRFLAC_FALSE; } oggbs->currentBytePos += bytesRead; - drflac_uint32 pageBodySize = drflac_ogg__get_page_body_size(&header); + pageBodySize = drflac_ogg__get_page_body_size(&header); if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { - continue; // Invalid page size. Assume it's corrupted and just move to the next page. + continue; /* Invalid page size. Assume it's corrupted and just move to the next page. */ } if (header.serialNumber != oggbs->serialNumber) { - // It's not a FLAC page. Skip it. + /* It's not a FLAC page. Skip it. */ if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { return DRFLAC_FALSE; } @@ -3979,25 +7305,29 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og } - // We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. + /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */ if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { return DRFLAC_FALSE; } oggbs->pageDataSize = pageBodySize; #ifndef DR_FLAC_NO_CRC - drflac_uint32 actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); if (actualCRC32 != header.checksum) { if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { - continue; // CRC mismatch. Skip this page. + continue; /* CRC mismatch. Skip this page. */ } else { - // Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we - // go to the next valid page to ensure we're in a good state, but return false to let the caller know that the - // seek did not fully complete. + /* + Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we + go to the next valid page to ensure we're in a good state, but return false to let the caller know that the + seek did not fully complete. + */ drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); return DRFLAC_FALSE; } } +#else + (void)recoveryMethod; /* <-- Silence a warning. */ #endif oggbs->currentPageHeader = header; @@ -4006,7 +7336,7 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og } } -// Function below is unused at the moment, but I might be re-adding it later. +/* Function below is unused at the moment, but I might be re-adding it later. */ #if 0 static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) { @@ -4029,7 +7359,7 @@ static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) { - // The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. + /* The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. */ for (;;) { drflac_bool32 atEndOfPage = DRFLAC_FALSE; @@ -4050,24 +7380,28 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) bytesToEndOfPacketOrPage += segmentSize; } - // At this point we will have found either the packet or the end of the page. If were at the end of the page we'll - // want to load the next page and keep searching for the end of the packet. + /* + At this point we will have found either the packet or the end of the page. If were at the end of the page we'll + want to load the next page and keep searching for the end of the packet. + */ drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current); oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; if (atEndOfPage) { - // We're potentially at the next packet, but we need to check the next page first to be sure because the packet may - // straddle pages. + /* + We're potentially at the next packet, but we need to check the next page first to be sure because the packet may + straddle pages. + */ if (!drflac_oggbs__goto_next_page(oggbs)) { return DRFLAC_FALSE; } - // If it's a fresh packet it most likely means we're at the next packet. + /* If it's a fresh packet it most likely means we're at the next packet. */ if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { return DRFLAC_TRUE; } } else { - // We're at the next packet. + /* We're at the next packet. */ return DRFLAC_TRUE; } } @@ -4075,9 +7409,9 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) { - // The bitstream should be sitting on the first byte just after the header of the frame. + /* The bitstream should be sitting on the first byte just after the header of the frame. */ - // What we're actually doing here is seeking to the start of the next packet. + /* What we're actually doing here is seeking to the start of the next packet. */ return drflac_oggbs__seek_to_next_packet(oggbs); } #endif @@ -4085,33 +7419,34 @@ static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - drflac_assert(oggbs != NULL); - drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; - - // Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. size_t bytesRead = 0; + + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(pRunningBufferOut != NULL); + + /* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */ while (bytesRead < bytesToRead) { size_t bytesRemainingToRead = bytesToRead - bytesRead; if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) { - drflac_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 -= (drflac_uint32)bytesRemainingToRead; break; } - // If we get here it means some of the requested data is contained in the next pages. + /* If we get here it means some of the requested data is contained in the next pages. */ if (oggbs->bytesRemainingInPage > 0) { - drflac_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; } - drflac_assert(bytesRemainingToRead > 0); + DRFLAC_ASSERT(bytesRemainingToRead > 0); if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { - break; // Failed to go to the next page. Might have simply hit the end of the stream. + break; /* Failed to go to the next page. Might have simply hit the end of the stream. */ } } @@ -4121,10 +7456,12 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - drflac_assert(oggbs != NULL); - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + int bytesSeeked = 0; - // Seeking is always forward which makes things a lot simpler. + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + /* Seeking is always forward which makes things a lot simpler. */ if (origin == drflac_seek_origin_start) { if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) { return DRFLAC_FALSE; @@ -4137,29 +7474,28 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current); } + DRFLAC_ASSERT(origin == drflac_seek_origin_current); - drflac_assert(origin == drflac_seek_origin_current); - - int bytesSeeked = 0; while (bytesSeeked < offset) { int bytesRemainingToSeek = offset - bytesSeeked; - drflac_assert(bytesRemainingToSeek >= 0); + DRFLAC_ASSERT(bytesRemainingToSeek >= 0); if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */ oggbs->bytesRemainingInPage -= bytesRemainingToSeek; break; } - // If we get here it means some of the requested data is contained in the next pages. + /* If we get here it means some of the requested data is contained in the next pages. */ if (oggbs->bytesRemainingInPage > 0) { bytesSeeked += (int)oggbs->bytesRemainingInPage; oggbs->bytesRemainingInPage = 0; } - drflac_assert(bytesRemainingToSeek > 0); + DRFLAC_ASSERT(bytesRemainingToSeek > 0); if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { - // Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. + /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */ return DRFLAC_FALSE; } } @@ -4167,42 +7503,49 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see return DRFLAC_TRUE; } -drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) + +static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) { drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + drflac_uint64 originalBytePos; + drflac_uint64 runningGranulePosition; + drflac_uint64 runningFrameBytePos; + drflac_uint64 runningPCMFrameCount; - drflac_uint64 originalBytePos = oggbs->currentBytePos; // For recovery. + DRFLAC_ASSERT(oggbs != NULL); - // First seek to the first frame. - if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos)) { + originalBytePos = oggbs->currentBytePos; /* For recovery. Points to the OggS identifier. */ + + /* First seek to the first frame. */ + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { return DRFLAC_FALSE; } oggbs->bytesRemainingInPage = 0; - drflac_uint64 runningGranulePosition = 0; - drflac_uint64 runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier. + runningGranulePosition = 0; for (;;) { 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; // Never did find that sample... + return DRFLAC_FALSE; /* Never did find that sample... */ } runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; - if (oggbs->currentPageHeader.granulePosition*pFlac->channels >= sampleIndex) { - break; // The sample is somewhere in the previous page. + if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) { + break; /* The sample is somewhere in the previous page. */ } - - // At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we - // disregard any pages that do not begin a fresh packet. - if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { // <-- Is it a fresh page? + /* + At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we + disregard any pages that do not begin a fresh packet. + */ + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { /* <-- Is it a fresh page? */ if (oggbs->currentPageHeader.segmentTable[0] >= 2) { drflac_uint8 firstBytesInPage[2]; firstBytesInPage[0] = oggbs->pageData[0]; firstBytesInPage[1] = oggbs->pageData[1]; - if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { // <-- Does the page begin with a frame's sync code? - runningGranulePosition = oggbs->currentPageHeader.granulePosition*pFlac->channels; + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */ + runningGranulePosition = oggbs->currentPageHeader.granulePosition; } continue; @@ -4210,11 +7553,12 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde } } - - // We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the - // start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of - // a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until - // we find the one containing the target sample. + /* + We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the + start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of + a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until + we find the one containing the target sample. + */ if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) { return DRFLAC_FALSE; } @@ -4222,66 +7566,91 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde return DRFLAC_FALSE; } - - // At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep - // looping over these frames until we find the one containing the sample we're after. - drflac_uint64 runningSampleCount = runningGranulePosition; + /* + At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep + looping over these frames until we find the one containing the sample we're after. + */ + runningPCMFrameCount = runningGranulePosition; for (;;) { - // There are two ways to find the sample and seek past irrelevant frames: - // 1) Use the native FLAC decoder. - // 2) Use Ogg's framing system. - // - // Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to - // do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code - // duplication for the decoding of frame headers. - // - // Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg - // bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the - // standard drflac__*() APIs because that will read in extra data for it's own internal caching which in turn breaks - // the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read - // using the native FLAC decoding APIs, such as drflac__read_next_frame_header(), need to be re-implemented so as to - // avoid the use of the drflac_bs object. - // - // Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons: - // 1) Seeking is already partially accellerated using Ogg's paging system in the code block above. - // 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon. - // 3) Simplicity. - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { + /* + There are two ways to find the sample and seek past irrelevant frames: + 1) Use the native FLAC decoder. + 2) Use Ogg's framing system. + + Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to + do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code + duplication for the decoding of frame headers. + + Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg + bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the + standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks + the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read + using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to + avoid the use of the drflac_bs object. + + Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons: + 1) Seeking is already partially accelerated using Ogg's paging system in the code block above. + 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon. + 3) Simplicity. + */ + 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; } - drflac_uint64 firstSampleInFrame = 0; - drflac_uint64 lastSampleInFrame = 0; - drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; - if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend - // it never existed and keep iterating. - drflac_result result = drflac__decode_frame(pFlac); + pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) { + drflac_result result = drflac__decode_flac_frame(pFlac); if (result == DRFLAC_SUCCESS) { - // The frame is valid. We just need to skip over some samples to ensure it's sample-exact. - drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. - if (samplesToDecode == 0) { + pFlac->currentPCMFrame = pcmFrameIndex; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + return DRFLAC_TRUE; + } else { + return DRFLAC_FALSE; + } + } + + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) { + /* + The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */ + if (pcmFramesToDecode == 0) { return DRFLAC_TRUE; } - return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0; // <-- If this fails, something bad has happened (it should never fail). + + pFlac->currentPCMFrame = runningPCMFrameCount; + + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ } else { if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + continue; /* CRC mismatch. Pretend this frame never existed. */ } else { return DRFLAC_FALSE; } } } else { - // It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this - // frame never existed and leave the running sample count untouched. - drflac_result result = drflac__seek_to_next_frame(pFlac); + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); if (result == DRFLAC_SUCCESS) { - runningSampleCount += sampleCountInThisFrame; + runningPCMFrameCount += pcmFrameCountInThisFrame; } else { if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + continue; /* CRC mismatch. Pretend this frame never existed. */ } else { return DRFLAC_FALSE; } @@ -4291,47 +7660,51 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde } -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) + +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) { - // Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern. + drflac_ogg_page_header header; + drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + drflac_uint32 bytesRead = 0; + + /* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */ (void)relaxed; pInit->container = drflac_container_ogg; pInit->oggFirstBytePos = 0; - // We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the - // stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if - // any match the FLAC specification. Important to keep in mind that the stream may be multiplexed. - drflac_ogg_page_header header; - - drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; - drflac_uint32 bytesRead = 0; + /* + We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the + stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if + any match the FLAC specification. Important to keep in mind that the stream may be multiplexed. + */ if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { return DRFLAC_FALSE; } pInit->runningFilePos += bytesRead; for (;;) { - // Break if we're past the beginning of stream page. + int pageBodySize; + + /* Break if we're past the beginning of stream page. */ if ((header.headerType & 0x02) == 0) { return DRFLAC_FALSE; } - - // Check if it's a FLAC header. - int pageBodySize = drflac_ogg__get_page_body_size(&header); - if (pageBodySize == 51) { // 51 = the lacing value of the FLAC header packet. - // It could be a FLAC page... + /* Check if it's a FLAC header. */ + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize == 51) { /* 51 = the lacing value of the FLAC header packet. */ + /* It could be a FLAC page... */ drflac_uint32 bytesRemainingInPage = pageBodySize; - drflac_uint8 packetType; + if (onRead(pUserData, &packetType, 1) != 1) { return DRFLAC_FALSE; } bytesRemainingInPage -= 1; if (packetType == 0x7F) { - // Increasingly more likely to be a FLAC page... + /* Increasingly more likely to be a FLAC page... */ drflac_uint8 sig[4]; if (onRead(pUserData, sig, 4) != 4) { return DRFLAC_FALSE; @@ -4339,29 +7712,32 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro bytesRemainingInPage -= 4; if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { - // Almost certainly a FLAC page... + /* Almost certainly a FLAC page... */ drflac_uint8 mappingVersion[2]; if (onRead(pUserData, mappingVersion, 2) != 2) { return DRFLAC_FALSE; } if (mappingVersion[0] != 1) { - return DRFLAC_FALSE; // Only supporting version 1.x of the Ogg mapping. + return DRFLAC_FALSE; /* Only supporting version 1.x of the Ogg mapping. */ } - // The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to - // be handling it in a generic way based on the serial number and packet types. + /* + The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to + be handling it in a generic way based on the serial number and packet types. + */ if (!onSeek(pUserData, 2, drflac_seek_origin_current)) { return DRFLAC_FALSE; } - // Expecting the native FLAC signature "fLaC". + /* Expecting the native FLAC signature "fLaC". */ if (onRead(pUserData, sig, 4) != 4) { return DRFLAC_FALSE; } if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { - // The remaining data in the page should be the STREAMINFO block. + /* The remaining data in the page should be the STREAMINFO block. */ + drflac_streaminfo streaminfo; drflac_uint8 isLastBlock; drflac_uint8 blockType; drflac_uint32 blockSize; @@ -4370,19 +7746,18 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro } if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { - return DRFLAC_FALSE; // Invalid block type. First block must be the STREAMINFO block. + return DRFLAC_FALSE; /* Invalid block type. First block must be the STREAMINFO block. */ } - drflac_streaminfo streaminfo; if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { - // Success! - pInit->hasStreamInfoBlock = DRFLAC_TRUE; - pInit->sampleRate = streaminfo.sampleRate; - pInit->channels = streaminfo.channels; - pInit->bitsPerSample = streaminfo.bitsPerSample; - pInit->totalSampleCount = streaminfo.totalSampleCount; - pInit->maxBlockSize = streaminfo.maxBlockSize; - pInit->hasMetadataBlocks = !isLastBlock; + /* Success! */ + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; + pInit->hasMetadataBlocks = !isLastBlock; if (onMeta) { drflac_metadata metadata; @@ -4394,26 +7769,26 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro } pInit->runningFilePos += pageBodySize; - pInit->oggFirstBytePos = pInit->runningFilePos - 79; // Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. + pInit->oggFirstBytePos = pInit->runningFilePos - 79; /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */ pInit->oggSerial = header.serialNumber; pInit->oggBosHeader = header; break; } else { - // Failed to read STREAMINFO block. Aww, so close... + /* Failed to read STREAMINFO block. Aww, so close... */ return DRFLAC_FALSE; } } else { - // Invalid file. + /* Invalid file. */ return DRFLAC_FALSE; } } else { - // Not a FLAC header. Skip it. + /* Not a FLAC header. Skip it. */ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { return DRFLAC_FALSE; } } } else { - // Not a FLAC header. Seek past the entire page and move on to the next. + /* Not a FLAC header. Seek past the entire page and move on to the next. */ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { return DRFLAC_FALSE; } @@ -4427,29 +7802,33 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro pInit->runningFilePos += pageBodySize; - // Read the header of the next page. + /* Read the header of the next page. */ if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { return DRFLAC_FALSE; } pInit->runningFilePos += bytesRead; } - - // If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next - // packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialiation phase for Ogg is to create the - // Ogg bistream object. - pInit->hasMetadataBlocks = DRFLAC_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block. + /* + If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next + packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the + Ogg bistream object. + */ + pInit->hasMetadataBlocks = DRFLAC_TRUE; /* <-- Always have at least VORBIS_COMMENT metadata block. */ return DRFLAC_TRUE; } #endif -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) +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) { + drflac_bool32 relaxed; + drflac_uint8 id[4]; + if (pInit == NULL || onRead == NULL || onSeek == NULL) { return DRFLAC_FALSE; } - drflac_zero_memory(pInit, sizeof(*pInit)); + DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); pInit->onRead = onRead; pInit->onSeek = onSeek; pInit->onMeta = onMeta; @@ -4463,35 +7842,36 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR drflac__reset_cache(&pInit->bs); - // If the container is explicitly defined then we can try opening in relaxed mode. - drflac_bool32 relaxed = container != drflac_container_unknown; + /* If the container is explicitly defined then we can try opening in relaxed mode. */ + relaxed = container != drflac_container_unknown; - drflac_uint8 id[4]; - - // Skip over any ID3 tags. + /* Skip over any ID3 tags. */ for (;;) { if (onRead(pUserData, id, 4) != 4) { - return DRFLAC_FALSE; // Ran out of data. + return DRFLAC_FALSE; /* Ran out of data. */ } pInit->runningFilePos += 4; if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { drflac_uint8 header[6]; + drflac_uint8 flags; + drflac_uint32 headerSize; + if (onRead(pUserData, header, 6) != 6) { - return DRFLAC_FALSE; // Ran out of data. + return DRFLAC_FALSE; /* Ran out of data. */ } pInit->runningFilePos += 6; - drflac_uint8 flags = header[1]; - drflac_uint32 headerSize; - drflac_copy_memory(&headerSize, header+2, 4); + flags = header[1]; + + DRFLAC_COPY_MEMORY(&headerSize, header+2, 4); headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); if (flags & 0x10) { headerSize += 10; } if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) { - return DRFLAC_FALSE; // Failed to seek past the tag. + return DRFLAC_FALSE; /* Failed to seek past the tag. */ } pInit->runningFilePos += headerSize; } else { @@ -4508,7 +7888,7 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR } #endif - // If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. + /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */ if (relaxed) { if (container == drflac_container_native) { return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); @@ -4520,123 +7900,247 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR #endif } - // Unsupported container. + /* Unsupported container. */ return DRFLAC_FALSE; } -void drflac__init_from_info(drflac* pFlac, drflac_init_info* pInit) +static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit) { - drflac_assert(pFlac != NULL); - drflac_assert(pInit != NULL); + 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->maxBlockSize = pInit->maxBlockSize; - pFlac->sampleRate = pInit->sampleRate; - pFlac->channels = (drflac_uint8)pInit->channels; - pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; - pFlac->totalSampleCount = pInit->totalSampleCount; - pFlac->container = pInit->container; + 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 = (drflac_uint8)pInit->channels; + pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; + pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; + pFlac->container = pInit->container; } -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) -{ -#ifndef DRFLAC_NO_CPUID - // CPU support first. - drflac__init_cpu_caps(); -#endif +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) +{ drflac_init_info init; + drflac_uint32 allocationSize; + drflac_uint32 wholeSIMDVectorCountPerChannel; + drflac_uint32 decodedSamplesAllocationSize; +#ifndef DR_FLAC_NO_OGG + drflac_oggbs* pOggbs = NULL; +#endif + drflac_uint64 firstFramePos; + drflac_uint64 seektablePos; + drflac_uint32 seekpointCount; + drflac_allocation_callbacks allocationCallbacks; + drflac* pFlac; + + /* CPU support first. */ + drflac__init_cpu_caps(); + if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { return NULL; } - // The size of the allocation for the drflac object needs to be large enough to fit the following: - // 1) The main members of the drflac structure - // 2) A block of memory large enough to store the decoded samples of the largest frame in the stream - // 3) If the container is Ogg, a drflac_oggbs object - // - // The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration - // the different SIMD instruction sets. - drflac_uint32 allocationSize = sizeof(drflac); - - // The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector - // we are supporting. - drflac_uint32 wholeSIMDVectorCountPerChannel; - if ((init.maxBlockSize % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { - wholeSIMDVectorCountPerChannel = (init.maxBlockSize / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); + if (pAllocationCallbacks != NULL) { + allocationCallbacks = *pAllocationCallbacks; + if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) { + return NULL; /* Invalid allocation callbacks. */ + } } else { - wholeSIMDVectorCountPerChannel = (init.maxBlockSize / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drflac__malloc_default; + allocationCallbacks.onRealloc = drflac__realloc_default; + allocationCallbacks.onFree = drflac__free_default; } - drflac_uint32 decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + + /* + The size of the allocation for the drflac object needs to be large enough to fit the following: + 1) The main members of the drflac structure + 2) A block of memory large enough to store the decoded samples of the largest frame in the stream + 3) If the container is Ogg, a drflac_oggbs object + + The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration + the different SIMD instruction sets. + */ + allocationSize = sizeof(drflac); + + /* + The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector + we are supporting. + */ + 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 / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; + } + + decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; allocationSize += decodedSamplesAllocationSize; - allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; // Allocate extra bytes to ensure we have enough for alignment. + allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; /* Allocate extra bytes to ensure we have enough for alignment. */ #ifndef DR_FLAC_NO_OGG - // There's additional data required for Ogg streams. + /* 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; } #endif - drflac* pFlac = (drflac*)DRFLAC_MALLOC(allocationSize); + /* + This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to + 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; + if (init.hasMetadataBlocks) { + drflac_read_proc onReadOverride = onRead; + drflac_seek_proc onSeekOverride = onSeek; + void* pUserDataOverride = pUserData; + +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + onReadOverride = drflac__on_read_ogg; + onSeekOverride = drflac__on_seek_ogg; + pUserDataOverride = (void*)pOggbs; + } +#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 + return NULL; + } + + allocationSize += seekpointCount * sizeof(drflac_seekpoint); + } + + + 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; + } + drflac__init_from_info(pFlac, &init); + pFlac->allocationCallbacks = allocationCallbacks; 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* oggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); - 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; + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint))); + DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); - // The Ogg bistream needs to be layered on top of the original bitstream. + /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */ + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + pOggbs = NULL; + + /* The Ogg bistream needs to be layered on top of the original bitstream. */ pFlac->bs.onRead = drflac__on_read_ogg; pFlac->bs.onSeek = drflac__on_seek_ogg; - pFlac->bs.pUserData = (void*)oggbs; - pFlac->_oggbs = (void*)oggbs; + pFlac->bs.pUserData = (void*)pInternalOggbs; + pFlac->_oggbs = (void*)pInternalOggbs; } #endif - // Decode metadata before returning. - if (init.hasMetadataBlocks) { - if (!drflac__read_and_decode_metadata(pFlac)) { - DRFLAC_FREE(pFlac); - return NULL; + pFlac->firstFLACFramePosInBytes = firstFramePos; + + /* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */ +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) + { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + else +#endif + { + /* 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->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); + + DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); + DRFLAC_ASSERT(pFlac->bs.onRead != NULL); + + /* 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. */ + 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; + } + } + + /* We need to seek back to where we were. If this fails it's a critical error. */ + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } else { + /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } } } - // If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode - // the first frame. + + /* + If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode + the first frame. + */ if (!init.hasStreamInfoBlock) { - pFlac->currentFrame.header = init.firstFrameHeader; - do - { - drflac_result result = drflac__decode_frame(pFlac); + pFlac->currentFLACFrame.header = init.firstFrameHeader; + for (;;) { + drflac_result result = drflac__decode_flac_frame(pFlac); if (result == DRFLAC_SUCCESS) { break; } else { if (result == DRFLAC_CRC_MISMATCH) { - if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { - DRFLAC_FREE(pFlac); + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } continue; } else { - DRFLAC_FREE(pFlac); + drflac__free_from_callbacks(pFlac, &allocationCallbacks); return NULL; } } - } while (1); + } } return pFlac; @@ -4645,10 +8149,576 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p #ifndef DR_FLAC_NO_STDIO -typedef void* drflac_file; - -#if defined(DR_FLAC_NO_WIN32_IO) || !defined(_WIN32) #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) +{ + 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; + } +} +/* End Errno */ + +/* fopen */ +static drflac_result drflac_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; /* Safety. */ + } + + 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; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRFLAC_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRFLAC_HAS_WFOPEN + #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) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } + +#if defined(DRFLAC_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #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 + /* + 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; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + 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); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + 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); + } + #endif + + if (*ppFile == NULL) { + return DRFLAC_ERROR; + } +#endif + + return DRFLAC_SUCCESS; +} +#endif +/* End fopen */ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) { @@ -4657,120 +8727,104 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -static drflac_file drflac__open_file_handle(const char* filename) + +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { + drflac* pFlac; FILE* pFile; -#ifdef _MSC_VER - if (fopen_s(&pFile, filename, "rb") != 0) { - return NULL; - } -#else - pFile = fopen(filename, "rb"); - if (pFile == NULL) { - return NULL; - } -#endif - return (drflac_file)pFile; -} - -static void drflac__close_file_handle(drflac_file file) -{ - fclose((FILE*)file); -} -#else -#include - -// This doesn't seem to be defined for VC6. -#ifndef INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) -{ - drflac_assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion. - - DWORD bytesRead; - ReadFile((HANDLE)pUserData, bufferOut, (DWORD)bytesToRead, &bytesRead, NULL); - - return (size_t)bytesRead; -} - -static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) -{ - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); - - return SetFilePointer((HANDLE)pUserData, offset, NULL, (origin == drflac_seek_origin_current) ? FILE_CURRENT : FILE_BEGIN) != INVALID_SET_FILE_POINTER; -} - -static drflac_file drflac__open_file_handle(const char* filename) -{ - HANDLE hFile = CreateFileA(filename, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { return NULL; } - return (drflac_file)hFile; -} - -static void drflac__close_file_handle(drflac_file file) -{ - CloseHandle((HANDLE)file); -} -#endif - - -drflac* drflac_open_file(const char* filename) -{ - drflac_file file = drflac__open_file_handle(filename); - if (file == NULL) { - return NULL; - } - - drflac* pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)file); + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { - drflac__close_file_handle(file); + fclose(pFile); return NULL; } return pFlac; } -drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData) +#ifndef DR_FLAC_NO_WCHAR +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) { - drflac_file file = drflac__open_file_handle(filename); - if (file == NULL) { + drflac* pFlac; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { return NULL; } - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)file, pUserData); + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks); if (pFlac == NULL) { - drflac__close_file_handle(file); + fclose(pFile); + return NULL; + } + + 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) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { + return NULL; + } + + 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; } -#endif //DR_FLAC_NO_STDIO + +#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; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { + return NULL; + } + + 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; +} +#endif +#endif /* DR_FLAC_NO_STDIO */ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; - drflac_assert(memoryStream != NULL); - drflac_assert(memoryStream->dataSize >= memoryStream->currentReadPos); + size_t bytesRemaining; - size_t bytesRemaining = 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) { - drflac_copy_memory(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); + DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); memoryStream->currentReadPos += bytesToRead; } @@ -4780,40 +8834,47 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; - drflac_assert(memoryStream != NULL); - drflac_assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start)); + + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + if (offset > (drflac_int64)memoryStream->dataSize) { + return DRFLAC_FALSE; + } if (origin == drflac_seek_origin_current) { if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { memoryStream->currentReadPos += offset; } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. + return DRFLAC_FALSE; /* Trying to seek too far forward. */ } } else { if ((drflac_uint32)offset <= memoryStream->dataSize) { memoryStream->currentReadPos = offset; } else { - memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward. + return DRFLAC_FALSE; /* Trying to seek too far forward. */ } } return DRFLAC_TRUE; } -drflac* drflac_open_memory(const void* data, size_t dataSize) +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks) { drflac__memory_stream memoryStream; - memoryStream.data = (const unsigned char*)data; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drflac* pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream); + pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } pFlac->memoryStream = memoryStream; - // This is an awful hack... + /* This is an awful hack... */ #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { @@ -4829,20 +8890,22 @@ drflac* drflac_open_memory(const void* data, size_t dataSize) return pFlac; } -drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData) +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__memory_stream memoryStream; - memoryStream.data = (const unsigned char*)data; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData); + 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; - // This is an awful hack... + /* This is an awful hack... */ #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { @@ -4860,458 +8923,2840 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl -drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData) +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) { - return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData) +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 drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks); } -drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData) +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 drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); } -drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData) +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 drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData); + return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); } -void drflac_close(drflac* pFlac) +DRFLAC_API void drflac_close(drflac* pFlac) { if (pFlac == NULL) { return; } #ifndef DR_FLAC_NO_STDIO - // If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file() - // was used by looking at the callbacks. + /* + If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file() + was used by looking at the callbacks. + */ if (pFlac->bs.onRead == drflac__on_read_stdio) { - drflac__close_file_handle((drflac_file)pFlac->bs.pUserData); + fclose((FILE*)pFlac->bs.pUserData); } #ifndef DR_FLAC_NO_OGG - // Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. + /* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */ if (pFlac->container == drflac_container_ogg) { - drflac_assert(pFlac->bs.onRead == drflac__on_read_ogg); drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg); + if (oggbs->onRead == drflac__on_read_stdio) { - drflac__close_file_handle((drflac_file)oggbs->pUserData); + fclose((FILE*)oggbs->pUserData); } } #endif #endif - DRFLAC_FREE(pFlac); + drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks); } -drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) + +#if 0 +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) { - unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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; - // We should never be calling this when the number of samples to read is >= the sample count. - drflac_assert(samplesToRead < channelCount); - drflac_assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining); + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif +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) +{ + 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_uint64 samplesRead = 0; - while (samplesToRead > 0) { - drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; - drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; - drflac_uint64 channelIndex = samplesReadFromFrameSoFar % channelCount; + for (i = 0; i < frameCount4; ++i) { + 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_uint64 nextSampleInFrame = samplesReadFromFrameSoFar / channelCount; + 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; - int decodedSample = 0; - switch (pFlac->currentFrame.header.channelAssignment) - { - case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: - { - if (channelIndex == 0) { - decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame]; - } else { - int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame]; - int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame]; - decodedSample = left - side; - } - } break; + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; - case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: - { - if (channelIndex == 0) { - int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame]; - int right = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame]; - decodedSample = side + right; - } else { - decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame]; - } - } break; - - case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: - { - int mid; - int side; - if (channelIndex == 0) { - mid = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame]; - side = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame]; - - mid = (((unsigned int)mid) << 1) | (side & 0x01); - decodedSample = (mid + side) >> 1; - } else { - mid = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame]; - side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame]; - - mid = (((unsigned int)mid) << 1) | (side & 0x01); - decodedSample = (mid - side) >> 1; - } - } break; - - case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: - default: - { - decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame]; - } break; - } - - - decodedSample <<= ((32 - pFlac->bitsPerSample) + pFlac->currentFrame.subframes[channelIndex].wastedBitsPerSample); - - if (bufferOut) { - *bufferOut++ = decodedSample; - } - - samplesRead += 1; - pFlac->currentFrame.samplesRemaining -= 1; - samplesToRead -= 1; + 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; } - return samplesRead; + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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; + } } -drflac_uint64 drflac__seek_forward_by_samples(drflac* pFlac, drflac_uint64 samplesToRead) +#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) { - drflac_uint64 samplesRead = 0; - while (samplesToRead > 0) { - if (pFlac->currentFrame.samplesRemaining == 0) { - if (!drflac__read_and_decode_next_frame(pFlac)) { - break; // Couldn't read the next frame, so just break from the loop and return. - } - } else { - samplesRead += 1; - pFlac->currentFrame.samplesRemaining -= 1; - samplesToRead -= 1; + 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); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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(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) +{ + 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; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + 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); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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 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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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 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) +{ + 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) { + 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) { + 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(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) +{ + 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); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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(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) +{ + 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; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + 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); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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 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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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 (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] = (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 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) +{ + 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) { + 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 = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + 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) { + 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 = (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; } } - return samplesRead; + for (i = (frameCount4 << 2); 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] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); + } } -drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) +#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) { - // Note that is allowed to be null, in which case this will be treated as something like a seek. - if (pFlac == NULL || samplesToRead == 0) { + 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; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +#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) +{ + 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; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + uint32x4_t one4; + + 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); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + 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); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + 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)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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 (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 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) +{ + 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) { + 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] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} + +#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) +{ + 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); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +#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) +{ + 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) { + int32x4_t left; + 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)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { return 0; } - if (bufferOut == NULL) { - return drflac__seek_forward_by_samples(pFlac, samplesToRead); + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); } + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; - drflac_uint64 samplesRead = 0; - while (samplesToRead > 0) { - // If we've run out of samples in this frame, go to the next. - if (pFlac->currentFrame.samplesRemaining == 0) { - if (!drflac__read_and_decode_next_frame(pFlac)) { - break; // Couldn't read the next frame, so just break from the loop and return. + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ } } else { - // Here is where we grab the samples and interleave them. + 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; - unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; - drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; - - drflac_uint64 misalignedSampleCount = samplesReadFromFrameSoFar % channelCount; - if (misalignedSampleCount > 0) { - drflac_uint64 misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut); - samplesRead += misalignedSamplesRead; - samplesReadFromFrameSoFar += misalignedSamplesRead; - bufferOut += misalignedSamplesRead; - samplesToRead -= misalignedSamplesRead; + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; } + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; - drflac_uint64 alignedSampleCountPerChannel = samplesToRead / channelCount; - if (alignedSampleCountPerChannel > pFlac->currentFrame.samplesRemaining / channelCount) { - alignedSampleCountPerChannel = pFlac->currentFrame.samplesRemaining / channelCount; - } - - drflac_uint64 firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount; - unsigned int unusedBitsPerSample = 32 - pFlac->bitsPerSample; - - switch (pFlac->currentFrame.header.channelAssignment) - { - case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + switch (pFlac->currentFLACFrame.header.channelAssignment) { - const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - int left = pDecodedSamples0[i]; - int side = pDecodedSamples1[i]; - int right = left - side; - - bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); - } - } break; - - case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: - { - const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - int side = pDecodedSamples0[i]; - int right = pDecodedSamples1[i]; - int left = right + side; - - bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); - } - } break; - - case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: - { - const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - int side = pDecodedSamples1[i]; - int mid = (((drflac_uint32)pDecodedSamples0[i]) << 1) | (side & 0x01); - - bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); - } - } break; - - case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: - default: - { - if (pFlac->currentFrame.header.channelAssignment == 1) // 1 = Stereo + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { - // Stereo optimized inner loop unroll. - const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; - const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; + drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); - } - } - else + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { - // Generic interleaving. - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - for (unsigned int j = 0; j < channelCount; ++j) { - bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample); - } - } - } - } break; - } + drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; - drflac_uint64 alignedSamplesRead = alignedSampleCountPerChannel * channelCount; - samplesRead += alignedSamplesRead; - samplesReadFromFrameSoFar += alignedSamplesRead; - bufferOut += alignedSamplesRead; - samplesToRead -= alignedSamplesRead; - pFlac->currentFrame.samplesRemaining -= (unsigned int)alignedSamplesRead; + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; - - - // At this point we may still have some excess samples left to read. - if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0) { - drflac_uint64 excessSamplesRead = 0; - if (samplesToRead < pFlac->currentFrame.samplesRemaining) { - excessSamplesRead = drflac__read_s32__misaligned(pFlac, samplesToRead, bufferOut); - } else { - excessSamplesRead = drflac__read_s32__misaligned(pFlac, pFlac->currentFrame.samplesRemaining, bufferOut); + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + } } - - samplesRead += excessSamplesRead; - samplesReadFromFrameSoFar += excessSamplesRead; - bufferOut += excessSamplesRead; - samplesToRead -= excessSamplesRead; } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; } } - return samplesRead; + return framesRead; } -drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut) + +#if 0 +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) { - // This reads samples in 2 passes and can probably be optimized. - drflac_uint64 totalSamplesRead = 0; + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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; - while (samplesToRead > 0) { - drflac_int32 samples32[4096]; - drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); - if (samplesJustRead == 0) { - break; // Reached the end. - } + left >>= 16; + right >>= 16; - // s32 -> s16 - for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { - pBufferOut[i] = (drflac_int16)(samples32[i] >> 16); - } - - totalSamplesRead += samplesJustRead; - samplesToRead -= samplesJustRead; - pBufferOut += samplesJustRead; + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; } - - return totalSamplesRead; } +#endif -drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut) +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) { - // This reads samples in 2 passes and can probably be optimized. - drflac_uint64 totalSamplesRead = 0; + 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; - while (samplesToRead > 0) { - drflac_int32 samples32[4096]; - drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); - if (samplesJustRead == 0) { - break; // Reached the end. - } + for (i = 0; i < frameCount4; ++i) { + 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; - // s32 -> f32 - for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { - pBufferOut[i] = (float)(samples32[i] / 2147483648.0); - } + 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; - totalSamplesRead += samplesJustRead; - samplesToRead -= samplesJustRead; - pBufferOut += samplesJustRead; + 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; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + 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; } - return totalSamplesRead; + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } } -drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) +#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) +{ + 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), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#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) +{ + 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; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + 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); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +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) +{ + 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) { + 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; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + 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) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} + +#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) +{ + 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), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#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) +{ + 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; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + 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); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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 (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] = (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 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) +{ + 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) { + 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 = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + 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) { + 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 = ((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; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + 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) { + 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] = (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(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) +{ + 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; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + 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), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + 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), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +#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) +{ + 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; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + + 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) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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 (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 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) +{ + 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) { + 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; + tempL3 >>= 16; + + tempR0 >>= 16; + tempR1 >>= 16; + tempR2 >>= 16; + tempR3 >>= 16; + + 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] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} + +#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) +{ + 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); + + /* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */ + _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] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +#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) +{ + 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) { + int32x4_t left; + int32x4_t right; + + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + 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); + + 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] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + 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 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 DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + 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); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; + } + } + + return framesRead; +} + + +#if 0 +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) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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 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) +{ + 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) { + 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) { + 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(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) +{ + 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; + + 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); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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(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) +{ + 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; + + 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); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + float32x4_t leftf; + float32x4_t rightf; + + 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); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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 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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + 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 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) +{ + 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) { + 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) { + 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(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) +{ + 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; + + 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); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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(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) +{ + 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; + + 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); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + float32x4_t leftf; + float32x4_t rightf; + + 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); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + 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 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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +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 (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)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + } +} +#endif + +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) +{ + 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) { + 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 = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + 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) { + 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 = (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) { + 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] = (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(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) +{ + 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; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = 1.0f / 8388608.0f; + factor128 = _mm_set1_ps(factor); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); 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] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +#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) +{ + 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; /* Wasted Bits Per Sample */ + int32x4_t wbps1_4; /* Wasted Bits Per Sample */ + + 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); + wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + 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); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); 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] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + 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); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); 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] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +#if 0 +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 (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 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) +{ + 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) { + 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] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} + +#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) +{ + 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) { + __m128i lefti; + __m128i righti; + __m128 leftf; + __m128 rightf; + + lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +#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) +{ + 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); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + 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); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +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(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(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 + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + 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 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 DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + 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); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration; + } + } + + return framesRead; +} + + +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) { if (pFlac == NULL) { return DRFLAC_FALSE; } - // If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present - // when the decoder was opened. - if (pFlac->firstFramePos == 0) { + /* Don't do anything if we're already on the seek point. */ + if (pFlac->currentPCMFrame == pcmFrameIndex) { + return DRFLAC_TRUE; + } + + /* + If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present + when the decoder was opened. + */ + if (pFlac->firstFLACFramePosInBytes == 0) { return DRFLAC_FALSE; } - if (sampleIndex == 0) { + if (pcmFrameIndex == 0) { + pFlac->currentPCMFrame = 0; return drflac__seek_to_first_frame(pFlac); - } + } else { + drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; - // Clamp the sample to the end. - if (sampleIndex >= pFlac->totalSampleCount) { - sampleIndex = pFlac->totalSampleCount - 1; - } - - - // Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so - // we'll instead use Ogg's natural seeking facility. -#ifndef DR_FLAC_NO_OGG - if (pFlac->container == drflac_container_ogg) - { - return drflac_ogg__seek_to_sample(pFlac, sampleIndex); - } - else -#endif - { - // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. - if (!drflac__seek_to_sample__seek_table(pFlac, sampleIndex)) { - return drflac__seek_to_sample__brute_force(pFlac, sampleIndex); + /* Clamp the sample to the end. */ + if (pcmFrameIndex > pFlac->totalPCMFrameCount) { + pcmFrameIndex = pFlac->totalPCMFrameCount; } + + /* If the target sample and the current sample are in the same frame we just move the position forward. */ + if (pcmFrameIndex > pFlac->currentPCMFrame) { + /* Forward. */ + drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); + if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) { + pFlac->currentFLACFrame.pcmFramesRemaining -= offset; + pFlac->currentPCMFrame = pcmFrameIndex; + return DRFLAC_TRUE; + } + } else { + /* Backward. */ + 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 DRFLAC_TRUE; + } + } + + /* + Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so + we'll instead use Ogg's natural seeking facility. + */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); + } + else +#endif + { + /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */ + if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); + } + +#if !defined(DR_FLAC_NO_CRC) + /* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */ + if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) { + wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex); + } +#endif + + /* Fall back to brute force if all else fails. */ + if (!wasSuccessful && !pFlac->_noBruteForceSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); + } + } + + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + /* Seek failed. Try putting the decoder back to it's original state. */ + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + /* Failed to seek back to the original PCM frame. Fall back to 0. */ + drflac_seek_to_pcm_frame(pFlac, 0); + } + } + + return wasSuccessful; } - - - return DRFLAC_TRUE; } -//// High Level APIs //// +/* High Level APIs */ -// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know. -#if defined(_MSC_VER) && _MSC_VER <= 1200 -#ifdef DRFLAC_64BIT -#define SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) +/* SIZE_MAX */ +#if defined(SIZE_MAX) + #define DRFLAC_SIZE_MAX SIZE_MAX #else -#define SIZE_MAX 0xFFFFFFFF -#endif + #if defined(DRFLAC_64BIT) + #define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) + #else + #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. -#define DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(extension, type) \ -static type* drflac__full_decode_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut)\ + +/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */ +#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)\ { \ - drflac_assert(pFlac != NULL); \ - \ type* pSampleData = NULL; \ - drflac_uint64 totalSampleCount = pFlac->totalSampleCount; \ + drflac_uint64 totalPCMFrameCount; \ \ - if (totalSampleCount == 0) { \ + DRFLAC_ASSERT(pFlac != NULL); \ + \ + totalPCMFrameCount = pFlac->totalPCMFrameCount; \ + \ + if (totalPCMFrameCount == 0) { \ type buffer[4096]; \ - \ + drflac_uint64 pcmFramesRead; \ size_t sampleDataBufferSize = sizeof(buffer); \ - pSampleData = (type*)DRFLAC_MALLOC(sampleDataBufferSize); \ + \ + pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ if (pSampleData == NULL) { \ goto on_error; \ } \ \ - drflac_uint64 samplesRead; \ - while ((samplesRead = (drflac_uint64)drflac_read_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0) { \ - if (((totalSampleCount + samplesRead) * sizeof(type)) > sampleDataBufferSize) { \ - sampleDataBufferSize *= 2; \ - type* pNewSampleData = (type*)DRFLAC_REALLOC(pSampleData, sampleDataBufferSize); \ + 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*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ if (pNewSampleData == NULL) { \ - DRFLAC_FREE(pSampleData); \ + drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ goto on_error; \ } \ \ + sampleDataBufferSize = newSampleDataBufferSize; \ pSampleData = pNewSampleData; \ } \ \ - drflac_copy_memory(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(type))); \ - totalSampleCount += samplesRead; \ + DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ + totalPCMFrameCount += pcmFramesRead; \ } \ \ /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \ protect those ears from random noise! */ \ - drflac_zero_memory(pSampleData + totalSampleCount, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(type))); \ + DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ } else { \ - drflac_uint64 dataSize = totalSampleCount * sizeof(type); \ - if (dataSize > SIZE_MAX) { \ + drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ + if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \ goto on_error; /* The decoded data is too big. */ \ } \ \ - pSampleData = (type*)DRFLAC_MALLOC((size_t)dataSize); /* <-- Safe cast as per the check above. */ \ + pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); /* <-- Safe cast as per the check above. */ \ if (pSampleData == NULL) { \ goto on_error; \ } \ \ - totalSampleCount = drflac_read_##extension(pFlac, pFlac->totalSampleCount, pSampleData); \ + totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \ } \ \ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ if (channelsOut) *channelsOut = pFlac->channels; \ - if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount; \ + if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \ \ drflac_close(pFlac); \ return pSampleData; \ @@ -5321,315 +11766,771 @@ on_error: return NULL; \ } -DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(s32, drflac_int32) -DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(s16, drflac_int16) -DRFLAC_DEFINE_FULL_DECODE_AND_CLOSE(f32, float) +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_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - // Safety. - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - // Safety. - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } -float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - // Safety. - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); } #ifndef DR_FLAC_NO_STDIO -drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); } -drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); } -float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); } #endif -drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); } -drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); } -float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); if (pFlac == NULL) { return NULL; } - return drflac__full_decode_and_close_f32(pFlac, channels, sampleRate, totalSampleCount); + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); } -void drflac_free(void* pSampleDataReturnedByOpenAndDecode) + +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) { - DRFLAC_FREE(pSampleDataReturnedByOpenAndDecode); + if (pAllocationCallbacks != NULL) { + drflac__free_from_callbacks(p, pAllocationCallbacks); + } else { + drflac__free_default(p, NULL); + } } -void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const char* pComments) +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments) { if (pIter == NULL) { return; } pIter->countRemaining = commentCount; - pIter->pRunningData = pComments; + pIter->pRunningData = (const char*)pComments; } -const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) { - // Safety. - if (pCommentLengthOut) *pCommentLengthOut = 0; + drflac_int32 length; + const char* pComment; + + /* Safety. */ + if (pCommentLengthOut) { + *pCommentLengthOut = 0; + } if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { return NULL; } - drflac_uint32 length = drflac__le2host_32(*(drflac_uint32*)pIter->pRunningData); + length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); pIter->pRunningData += 4; - const char* pComment = pIter->pRunningData; + pComment = pIter->pRunningData; pIter->pRunningData += length; pIter->countRemaining -= 1; - if (pCommentLengthOut) *pCommentLengthOut = length; + if (pCommentLengthOut) { + *pCommentLengthOut = length; + } + return pComment; } -#endif //DR_FLAC_IMPLEMENTATION -// REVISION HISTORY -// -// v0.8d - 2017-09-22 -// - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. -// -// v0.8c - 2017-09-07 -// - Fix warning on non-x86/x64 architectures. -// -// v0.8b - 2017-08-19 -// - Fix build on non-x86/x64 architectures. -// -// v0.8a - 2017-08-13 -// - A small optimization for the Clang build. -// -// v0.8 - 2017-08-12 -// - API CHANGE: Rename dr_* types to drflac_*. -// - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation. -// - Add support for custom implementations of malloc(), realloc(), etc. -// - Add CRC checking to Ogg encapsulated streams. -// - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported. -// - Bug fixes. -// -// v0.7 - 2017-07-23 -// - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed(). -// -// v0.6 - 2017-07-22 -// - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they -// never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame. -// -// v0.5 - 2017-07-16 -// - Fix typos. -// - Change drflac_bool* types to unsigned. -// - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC. -// -// v0.4f - 2017-03-10 -// - Fix a couple of bugs with the bitstreaming code. -// -// v0.4e - 2017-02-17 -// - Fix some warnings. -// -// v0.4d - 2016-12-26 -// - Add support for 32-bit floating-point PCM decoding. -// - Use drflac_int*/drflac_uint* sized types to improve compiler support. -// - Minor improvements to documentation. -// -// v0.4c - 2016-12-26 -// - Add support for signed 16-bit integer PCM decoding. -// -// v0.4b - 2016-10-23 -// - A minor change to drflac_bool8 and drflac_bool32 types. -// -// v0.4a - 2016-10-11 -// - Rename drBool32 to drflac_bool32 for styling consistency. -// -// v0.4 - 2016-09-29 -// - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type. -// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32(). -// - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to -// keep it consistent with drflac_audio. -// -// v0.3f - 2016-09-21 -// - Fix a warning with GCC. -// -// v0.3e - 2016-09-18 -// - Fixed a bug where GCC 4.3+ was not getting properly identified. -// - Fixed a few typos. -// - Changed date formats to ISO 8601 (YYYY-MM-DD). -// -// v0.3d - 2016-06-11 -// - Minor clean up. -// -// v0.3c - 2016-05-28 -// - Fixed compilation error. -// -// v0.3b - 2016-05-16 -// - Fixed Linux/GCC build. -// - Updated documentation. -// -// v0.3a - 2016-05-15 -// - Minor fixes to documentation. -// -// v0.3 - 2016-05-11 -// - Optimizations. Now at about parity with the reference implementation on 32-bit builds. -// - Lots of clean up. -// -// v0.2b - 2016-05-10 -// - Bug fixes. -// -// v0.2a - 2016-05-10 -// - Made drflac_open_and_decode() more robust. -// - Removed an unused debugging variable -// -// v0.2 - 2016-05-09 -// - Added support for Ogg encapsulation. -// - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek -// should be relative to the start or the current position. Also changes the seeking rules such that -// seeking offsets will never be negative. -// - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. -// -// v0.1b - 2016-05-07 -// - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. -// - Removed a stale comment. -// -// v0.1a - 2016-05-05 -// - Minor formatting changes. -// - Fixed a warning on the GCC build. -// -// v0.1 - 2016-05-03 -// - Initial versioned release. + + +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = trackCount; + pIter->pRunningData = (const char*)pTrackData; +} + +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) +{ + drflac_cuesheet_track cuesheetTrack; + const char* pRunningData; + drflac_uint64 offsetHi; + drflac_uint64 offsetLo; + + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return DRFLAC_FALSE; + } + + pRunningData = pIter->pRunningData; + + 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; + 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 drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index); + + pIter->pRunningData = pRunningData; + pIter->countRemaining -= 1; + + if (pCuesheetTrack) { + *pCuesheetTrack = cuesheetTrack; + } + + return DRFLAC_TRUE; +} + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop +#endif +#endif /* dr_flac_c */ +#endif /* DR_FLAC_IMPLEMENTATION */ /* +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. + +v0.12.28 - 2021-02-21 + - Fix a warning due to referencing _MSC_VER when it is undefined. + +v0.12.27 - 2021-01-31 + - Fix a static analysis warning. + +v0.12.26 - 2021-01-17 + - Fix a compilation warning due to _BSD_SOURCE being deprecated. + +v0.12.25 - 2020-12-26 + - Update documentation. + +v0.12.24 - 2020-11-29 + - Fix ARM64/NEON detection when compiling with MSVC. + +v0.12.23 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.22 - 2020-11-01 + - Fix an error with the previous release. + +v0.12.21 - 2020-11-01 + - Fix a possible deadlock when seeking. + - Improve compiler support for older versions of GCC. + +v0.12.20 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.19 - 2020-08-30 + - Fix a bug due to an undefined 32-bit shift. + +v0.12.18 - 2020-08-14 + - Fix a crash when compiling with clang-cl. + +v0.12.17 - 2020-08-02 + - Simplify sized types. + +v0.12.16 - 2020-07-25 + - Fix a compilation warning. + +v0.12.15 - 2020-07-06 + - Check for negative LPC shifts and return an error. + +v0.12.14 - 2020-06-23 + - Add include guard for the implementation section. + +v0.12.13 - 2020-05-16 + - Add compile-time and run-time version querying. + - DRFLAC_VERSION_MINOR + - DRFLAC_VERSION_MAJOR + - DRFLAC_VERSION_REVISION + - DRFLAC_VERSION_STRING + - drflac_version() + - drflac_version_string() + +v0.12.12 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.11 - 2020-04-19 + - Fix some pedantic warnings. + - Fix some undefined behaviour warnings. + +v0.12.10 - 2020-04-10 + - Fix some bugs when trying to seek with an invalid seek table. + +v0.12.9 - 2020-04-05 + - Fix warnings. + +v0.12.8 - 2020-04-04 + - Add drflac_open_file_w() and drflac_open_file_with_metadata_w(). + - Fix some static analysis warnings. + - Minor documentation updates. + +v0.12.7 - 2020-03-14 + - Fix compilation errors with VC6. + +v0.12.6 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.12.5 - 2020-01-30 + - Silence some static analysis warnings. + +v0.12.4 - 2020-01-29 + - Silence some static analysis warnings. + +v0.12.3 - 2019-12-02 + - Fix some warnings when compiling with GCC and the -Og flag. + - Fix a crash in out-of-memory situations. + - Fix potential integer overflow bug. + - Fix some static analysis warnings. + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix a bug with binary search seeking where the bits per sample is not a multiple of 8. + +v0.12.2 - 2019-10-07 + - Internal code clean up. + +v0.12.1 - 2019-09-29 + - Fix some Clang Static Analyzer warnings. + - Fix an unused variable warning. + +v0.12.0 - 2019-09-23 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drflac_open() + - drflac_open_relaxed() + - drflac_open_with_metadata() + - drflac_open_with_metadata_relaxed() + - drflac_open_file() + - drflac_open_file_with_metadata() + - drflac_open_memory() + - drflac_open_memory_with_metadata() + - drflac_open_and_read_pcm_frames_s32() + - drflac_open_and_read_pcm_frames_s16() + - drflac_open_and_read_pcm_frames_f32() + - drflac_open_file_and_read_pcm_frames_s32() + - drflac_open_file_and_read_pcm_frames_s16() + - drflac_open_file_and_read_pcm_frames_f32() + - drflac_open_memory_and_read_pcm_frames_s32() + - drflac_open_memory_and_read_pcm_frames_s16() + - drflac_open_memory_and_read_pcm_frames_f32() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. + - Remove deprecated APIs: + - drflac_read_s32() + - drflac_read_s16() + - drflac_read_f32() + - drflac_seek_to_sample() + - drflac_open_and_decode_s32() + - drflac_open_and_decode_s16() + - drflac_open_and_decode_f32() + - drflac_open_and_decode_file_s32() + - drflac_open_and_decode_file_s16() + - drflac_open_and_decode_file_f32() + - drflac_open_and_decode_memory_s32() + - drflac_open_and_decode_memory_s16() + - drflac_open_and_decode_memory_f32() + - Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount + by doing pFlac->totalPCMFrameCount*pFlac->channels. + - Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames. + - Fix errors when seeking to the end of a stream. + - Optimizations to seeking. + - SSE improvements and optimizations. + - ARM NEON optimizations. + - Optimizations to drflac_read_pcm_frames_s16(). + - Optimizations to drflac_read_pcm_frames_s32(). + +v0.11.10 - 2019-06-26 + - Fix a compiler error. + +v0.11.9 - 2019-06-16 + - Silence some ThreadSanitizer warnings. + +v0.11.8 - 2019-05-21 + - Fix warnings. + +v0.11.7 - 2019-05-06 + - C89 fixes. + +v0.11.6 - 2019-05-05 + - Add support for C89. + - Fix a compiler warning when CRC is disabled. + - Change license to choice of public domain or MIT-0. + +v0.11.5 - 2019-04-19 + - Fix a compiler error with GCC. + +v0.11.4 - 2019-04-17 + - Fix some warnings with GCC when compiling with -std=c99. + +v0.11.3 - 2019-04-07 + - Silence warnings with GCC. + +v0.11.2 - 2019-03-10 + - Fix a warning. + +v0.11.1 - 2019-02-17 + - Fix a potential bug with seeking. + +v0.11.0 - 2018-12-16 + - API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with + drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take + and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by + dividing it by the channel count, and then do the same with the return value. + - API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as + the changes to drflac_read_*() apply. + - API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as + the changes to drflac_read_*() apply. + - Optimizations. + +v0.10.0 - 2018-09-11 + - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you + need to do it yourself via the callback API. + - Fix the clang build. + - Fix undefined behavior. + - Fix errors with CUESHEET metdata blocks. + - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the + Vorbis comment API. + - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams. + - Minor optimizations. + +v0.9.11 - 2018-08-29 + - Fix a bug with sample reconstruction. + +v0.9.10 - 2018-08-07 + - Improve 64-bit detection. + +v0.9.9 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.9.8 - 2018-07-24 + - Fix compilation errors. + +v0.9.7 - 2018-07-05 + - Fix a warning. + +v0.9.6 - 2018-06-29 + - Fix some typos. + +v0.9.5 - 2018-06-23 + - Fix some warnings. + +v0.9.4 - 2018-06-14 + - Optimizations to seeking. + - Clean up. + +v0.9.3 - 2018-05-22 + - Bug fix. + +v0.9.2 - 2018-05-12 + - Fix a compilation error due to a missing break statement. + +v0.9.1 - 2018-04-29 + - Fix compilation error with Clang. + +v0.9 - 2018-04-24 + - Fix Clang build. + - Start using major.minor.revision versioning. + +v0.8g - 2018-04-19 + - Fix build on non-x86/x64 architectures. + +v0.8f - 2018-02-02 + - Stop pretending to support changing rate/channels mid stream. + +v0.8e - 2018-02-01 + - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream. + - Fix a crash the the Rice partition order is invalid. + +v0.8d - 2017-09-22 + - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. + +v0.8c - 2017-09-07 + - Fix warning on non-x86/x64 architectures. + +v0.8b - 2017-08-19 + - Fix build on non-x86/x64 architectures. + +v0.8a - 2017-08-13 + - A small optimization for the Clang build. + +v0.8 - 2017-08-12 + - API CHANGE: Rename dr_* types to drflac_*. + - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add CRC checking to Ogg encapsulated streams. + - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported. + - Bug fixes. + +v0.7 - 2017-07-23 + - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed(). + +v0.6 - 2017-07-22 + - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they + never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame. + +v0.5 - 2017-07-16 + - Fix typos. + - Change drflac_bool* types to unsigned. + - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC. + +v0.4f - 2017-03-10 + - Fix a couple of bugs with the bitstreaming code. + +v0.4e - 2017-02-17 + - Fix some warnings. + +v0.4d - 2016-12-26 + - Add support for 32-bit floating-point PCM decoding. + - Use drflac_int* and drflac_uint* sized types to improve compiler support. + - Minor improvements to documentation. + +v0.4c - 2016-12-26 + - Add support for signed 16-bit integer PCM decoding. + +v0.4b - 2016-10-23 + - A minor change to drflac_bool8 and drflac_bool32 types. + +v0.4a - 2016-10-11 + - Rename drBool32 to drflac_bool32 for styling consistency. + +v0.4 - 2016-09-29 + - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type. + - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32(). + - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to + keep it consistent with drflac_audio. + +v0.3f - 2016-09-21 + - Fix a warning with GCC. + +v0.3e - 2016-09-18 + - Fixed a bug where GCC 4.3+ was not getting properly identified. + - Fixed a few typos. + - Changed date formats to ISO 8601 (YYYY-MM-DD). + +v0.3d - 2016-06-11 + - Minor clean up. + +v0.3c - 2016-05-28 + - Fixed compilation error. + +v0.3b - 2016-05-16 + - Fixed Linux/GCC build. + - Updated documentation. + +v0.3a - 2016-05-15 + - Minor fixes to documentation. + +v0.3 - 2016-05-11 + - Optimizations. Now at about parity with the reference implementation on 32-bit builds. + - Lots of clean up. + +v0.2b - 2016-05-10 + - Bug fixes. + +v0.2a - 2016-05-10 + - Made drflac_open_and_decode() more robust. + - Removed an unused debugging variable + +v0.2 - 2016-05-09 + - Added support for Ogg encapsulation. + - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek + should be relative to the start or the current position. Also changes the seeking rules such that + seeking offsets will never be negative. + - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. + +v0.1b - 2016-05-07 + - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. + - Removed a stale comment. + +v0.1a - 2016-05-05 + - Minor formatting changes. + - Fixed a warning on the GCC build. + +v0.1 - 2016-05-03 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - 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. +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. +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. +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. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2023 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 +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. + +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/dr_mp3.h b/raylib/external/dr_mp3.h index 564bf37..e1a66d9 100644 --- a/raylib/external/dr_mp3.h +++ b/raylib/external/dr_mp3.h @@ -1,62 +1,87 @@ -// MP3 audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_mp3 - v0.2.3 - 2018-04-29 -// -// David Reid - mackron@gmail.com -// -// Based off minimp3 (https://github.com/lieff/minimp3) which is where the real work was done. See the bottom of this file for -// differences between minimp3 and dr_mp3. +/* +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 -// USAGE -// ===== -// dr_mp3 is a single-file library. To use it, do something like the following in one .c file. -// #define DR_MP3_IMPLEMENTATION -// #include "dr_mp3.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, -// do something like the following: -// -// drmp3 mp3; -// if (!drmp3_init_file(&mp3, "MySong.mp3", NULL)) { -// // Failed to open file -// } -// -// ... -// -// drmp3_uint64 framesRead = drmp3_read_f32(pMP3, framesToRead, pFrames); -// -// The drmp3 object is transparent so you can get access to the channel count and sample rate like so: -// -// drmp3_uint32 channels = mp3.channels; -// drmp3_uint32 sampleRate = mp3.sampleRate; -// -// The third parameter of drmp3_init_file() in the example above allows you to control the output channel count and sample rate. It -// is a pointer to a drmp3_config object. Setting any of the variables of this object to 0 will cause dr_mp3 to use defaults. -// -// The example above initializes a decoder from a file, but you can also initialize it from a block of memory and read and seek -// callbacks with drmp3_init_memory() and drmp3_init() respectively. -// -// You do need to do any annoying memory management when reading PCM frames - this is all managed internally. You can request -// any number of PCM frames in each call to drmp3_read_f32() and it will return as many PCM frames as it can, up to the requested -// amount. -// -// You can also decode an entire file in one go with drmp3_open_and_decode_f32(), drmp3_open_and_decode_memory_f32() and -// drmp3_open_and_decode_file_f32(). -// -// -// OPTIONS -// ======= -// #define these options before including this file. -// -// #define DR_MP3_NO_STDIO -// Disable drmp3_init_file(), etc. -// -// #define DR_MP3_NO_SIMD -// Disable SIMD optimizations. -// -// -// LIMITATIONS -// =========== -// - Seeking is extremely inefficient. +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs + +Based on minimp3 (https://github.com/lieff/minimp3) which is where the real work was done. See the bottom of this file for differences between minimp3 and dr_mp3. +*/ + +/* +RELEASE NOTES - VERSION 0.6 +=========================== +Version 0.6 includes breaking changes with the configuration of decoders. The ability to customize the number of output channels and the sample rate has been +removed. You must now use the channel count and sample rate reported by the MP3 stream itself, and all channel and sample rate conversion must be done +yourself. + + +Changes to Initialization +------------------------- +Previously, `drmp3_init()`, etc. took a pointer to a `drmp3_config` object that allowed you to customize the output channels and sample rate. This has been +removed. If you need the old behaviour you will need to convert the data yourself or just not upgrade. The following APIs have changed. + + `drmp3_init()` + `drmp3_init_memory()` + `drmp3_init_file()` + + +Miscellaneous Changes +--------------------- +Support for loading a file from a `wchar_t` string has been added via the `drmp3_init_file_w()` API. +*/ + +/* +Introducation +============= +dr_mp3 is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_MP3_IMPLEMENTATION + #include "dr_mp3.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following: + + ```c + drmp3 mp3; + if (!drmp3_init_file(&mp3, "MySong.mp3", NULL)) { + // Failed to open file + } + + ... + + drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, framesToRead, pFrames); + ``` + +The drmp3 object is transparent so you can get access to the channel count and sample rate like so: + + ``` + drmp3_uint32 channels = mp3.channels; + drmp3_uint32 sampleRate = mp3.sampleRate; + ``` + +The example above initializes a decoder from a file, but you can also initialize it from a block of memory and read and seek callbacks with +`drmp3_init_memory()` and `drmp3_init()` respectively. + +You do not need to do any annoying memory management when reading PCM frames - this is all managed internally. You can request any number of PCM frames in each +call to `drmp3_read_pcm_frames_f32()` and it will return as many PCM frames as it can, up to the requested amount. + +You can also decode an entire file in one go with `drmp3_open_and_read_pcm_frames_f32()`, `drmp3_open_memory_and_read_pcm_frames_f32()` and +`drmp3_open_file_and_read_pcm_frames_f32()`. + + +Build Options +============= +#define these options before including this file. + +#define DR_MP3_NO_STDIO + Disable drmp3_init_file(), etc. + +#define DR_MP3_NO_SIMD + Disable SIMD optimizations. +*/ #ifndef dr_mp3_h #define dr_mp3_h @@ -65,165 +90,289 @@ extern "C" { #endif -#include +#define DRMP3_STRINGIFY(x) #x +#define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x) -#if defined(_MSC_VER) && _MSC_VER < 1600 -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; -typedef signed __int64 drmp3_int64; -typedef unsigned __int64 drmp3_uint64; +#define DRMP3_VERSION_MAJOR 0 +#define DRMP3_VERSION_MINOR 6 +#define DRMP3_VERSION_REVISION 39 +#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 */ +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__) + typedef signed __int64 drmp3_int64; + typedef unsigned __int64 drmp3_uint64; #else -#include -typedef int8_t drmp3_int8; -typedef uint8_t drmp3_uint8; -typedef int16_t drmp3_int16; -typedef uint16_t drmp3_uint16; -typedef int32_t drmp3_int32; -typedef uint32_t drmp3_uint32; -typedef int64_t drmp3_int64; -typedef uint64_t drmp3_uint64; + #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 -typedef drmp3_uint8 drmp3_bool8; -typedef drmp3_uint32 drmp3_bool32; -#define DRMP3_TRUE 1 -#define DRMP3_FALSE 0 +#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__) + 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 +/* End Sized Types */ -#define DRMP3_MAX_SAMPLES_PER_FRAME (1152*2) +/* Decorations */ +#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 +/* End Decorations */ + +/* Result Codes */ +typedef drmp3_int32 drmp3_result; +#define DRMP3_SUCCESS 0 +#define DRMP3_ERROR -1 /* A generic error. */ +#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 +/* 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__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRMP3_GNUC_INLINE_HINT __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 + #endif +#elif defined(__WATCOMC__) + #define DRMP3_INLINE __inline +#else + #define DRMP3_INLINE +#endif +/* End Inline */ -// Low Level Push API -// ================== +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 { - int frame_bytes; - int channels; - int hz; - int layer; - int bitrate_kbps; + 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 +================== +*/ +typedef struct +{ + int frame_bytes, channels, hz, layer, bitrate_kbps; } drmp3dec_frame_info; typedef struct { - float mdct_overlap[2][9*32]; - float qmf_state[15*2*32]; - int reserv; - int free_format_bytes; - unsigned char header[4]; - unsigned char reserv_buf[511]; + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + drmp3_uint8 header[4], reserv_buf[511]; } drmp3dec; -// Initializes a low level decoder. -void drmp3dec_init(drmp3dec *dec); +/* Initializes a low level decoder. */ +DRMP3_API void drmp3dec_init(drmp3dec *dec); -// Reads a frame from a low level decoder. -int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, short *pcm, drmp3dec_frame_info *info); +/* Reads a frame from a low level decoder. */ +DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info); + +/* Helper for converting between f32 and s16. */ +DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples); -// Main API (Pull API) -// =================== - -typedef struct drmp3_src drmp3_src; -typedef drmp3_uint64 (* drmp3_src_read_proc)(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. - -typedef enum -{ - drmp3_src_algorithm_none, - drmp3_src_algorithm_linear -} drmp3_src_algorithm; - -#define DRMP3_SRC_CACHE_SIZE_IN_FRAMES 512 -typedef struct -{ - drmp3_src* pSRC; - float pCachedFrames[2 * DRMP3_SRC_CACHE_SIZE_IN_FRAMES]; - drmp3_uint32 cachedFrameCount; - drmp3_uint32 iNextFrame; -} drmp3_src_cache; - -typedef struct -{ - drmp3_uint32 sampleRateIn; - drmp3_uint32 sampleRateOut; - drmp3_uint32 channels; - drmp3_src_algorithm algorithm; - drmp3_uint32 cacheSizeInFrames; // The number of frames to read from the client at a time. -} drmp3_src_config; - -struct drmp3_src -{ - drmp3_src_config config; - drmp3_src_read_proc onRead; - void* pUserData; - float bin[256]; - drmp3_src_cache cache; // <-- For simplifying and optimizing client -> memory reading. - union - { - struct - { - float alpha; - drmp3_bool32 isPrevFramesLoaded : 1; - drmp3_bool32 isNextFramesLoaded : 1; - } linear; - } algo; -}; +/* +Main API (Pull API) +=================== +*/ typedef enum { drmp3_seek_origin_start, drmp3_seek_origin_current } drmp3_seek_origin; -// Callback for when data is read. Return value is the number of bytes actually read. -// -// pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. -// pBufferOut [out] The output buffer. -// bytesToRead [in] The number of bytes to read. -// -// Returns the number of bytes actually read. -// -// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until -// either the entire bytesToRead is filled or you have reached the end of the stream. +typedef struct +{ + drmp3_uint64 seekPosInBytes; /* Points to the first byte of an MP3 frame. */ + drmp3_uint64 pcmFrameIndex; /* The index of the PCM frame this seek point targets. */ + drmp3_uint16 mp3FramesToDiscard; /* The number of whole MP3 frames to be discarded before pcmFramesToDiscard. */ + drmp3_uint16 pcmFramesToDiscard; /* The number of leading samples to read and discard. These are discarded after mp3FramesToDiscard. */ +} drmp3_seek_point; + +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +either the entire bytesToRead is filled or you have reached the end of the stream. +*/ typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -// Callback for when data needs to be seeked. -// -// pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. -// offset [in] The number of bytes to move, relative to the origin. Will never be negative. -// origin [in] The origin of the seek - the current position or the start of the stream. -// -// Returns whether or not the seek was successful. -// -// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which -// will be either drmp3_seek_origin_start or drmp3_seek_origin_current. +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. +offset [in] The number of bytes to move, relative to the origin. Will never be negative. +origin [in] The origin of the seek - the current position or the start of the stream. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which +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 { - drmp3_uint32 outputChannels; - drmp3_uint32 outputSampleRate; + 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_uint32 frameChannels; // The number of channels in the currently loaded MP3 frame. Internal use only. - drmp3_uint32 frameSampleRate; // The sample rate of the currently loaded MP3 frame. Internal use only. - drmp3_uint32 framesConsumed; - drmp3_uint32 framesRemaining; - drmp3_int16 frames[DRMP3_MAX_SAMPLES_PER_FRAME]; - drmp3_src src; + drmp3_allocation_callbacks allocationCallbacks; + drmp3_uint32 mp3FrameChannels; /* The number of channels in the currently loaded MP3 frame. Internal use only. */ + drmp3_uint32 mp3FrameSampleRate; /* The sample rate of the currently loaded MP3 frame. Internal use only. */ + drmp3_uint32 pcmFramesConsumedInMP3Frame; + drmp3_uint32 pcmFramesRemainingInMP3Frame; + drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; /* <-- Multipled by sizeof(float) to ensure there's enough room for DR_MP3_FLOAT_OUTPUT. */ + drmp3_uint64 currentPCMFrame; /* The current PCM frame, globally, based on the output sample rate. Mainly used for seeking. */ + drmp3_uint64 streamCursor; /* The current byte the decoder is sitting on in the raw stream. */ + drmp3_seek_point* pSeekPoints; /* NULL by default. Set with drmp3_bind_seek_table(). Memory is owned by the client. dr_mp3 will never attempt to free this pointer. */ + drmp3_uint32 seekPointCount; /* The number of items in pSeekPoints. When set to 0 assumes to no seek table. Defaults to zero. */ size_t dataSize; size_t dataCapacity; + size_t dataConsumed; drmp3_uint8* pData; drmp3_bool32 atEnd : 1; struct @@ -231,91 +380,194 @@ typedef struct const drmp3_uint8* pData; size_t dataSize; size_t currentReadPos; - } memory; // Only used for decoders that were opened against a block of memory. + } memory; /* Only used for decoders that were opened against a block of memory. */ } drmp3; -// Initializes an MP3 decoder. -// -// onRead [in] The function to call when data needs to be read from the client. -// onSeek [in] The function to call when the read position of the client data needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. -// -// Returns true if successful; false otherwise. -// -// Close the loader with drmp3_uninit(). -// -// See also: drmp3_init_file(), drmp3_init_memory(), drmp3_uninit() -drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig); +/* +Initializes an MP3 decoder. -// Initializes an MP3 decoder from a block of memory. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drmp3 object. -// -// The buffer should contain the contents of the entire MP3 file. -drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_config* pConfig); +onRead [in] The function to call when data needs to be read from the client. +onSeek [in] The function to call when the read position of the client data needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. + +Returns true if successful; false otherwise. + +Close the loader with drmp3_uninit(). + +See also: drmp3_init_file(), drmp3_init_memory(), drmp3_uninit() +*/ +DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks); + +/* +Initializes an MP3 decoder from a block of memory. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drmp3 object. + +The buffer should contain the contents of the entire MP3 file. +*/ +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 -// Initializes an MP3 decoder from a file. -// -// This holds the internal FILE object until drmp3_uninit() is called. Keep this in mind if you're caching drmp3 -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. -drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* filePath, const drmp3_config* pConfig); +/* +Initializes an MP3 decoder from a file. + +This holds the internal FILE object until drmp3_uninit() is called. Keep this in mind if you're caching drmp3 +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +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 -// Uninitializes an MP3 decoder. -void drmp3_uninit(drmp3* pMP3); +/* +Uninitializes an MP3 decoder. +*/ +DRMP3_API void drmp3_uninit(drmp3* pMP3); -// Reads PCM frames as interleaved 32-bit IEEE floating point PCM. -// -// Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. -drmp3_uint64 drmp3_read_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut); +/* +Reads PCM frames as interleaved 32-bit IEEE floating point PCM. -// Seeks to a specific frame. -// -// Note that this is _not_ an MP3 frame, but rather a PCM frame. -drmp3_bool32 drmp3_seek_to_frame(drmp3* pMP3, drmp3_uint64 frameIndex); +Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. +*/ +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut); + +/* +Reads PCM frames as interleaved signed 16-bit integer PCM. + +Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. +*/ +DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut); + +/* +Seeks to a specific frame. + +Note that this is _not_ an MP3 frame, but rather a PCM frame. +*/ +DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex); + +/* +Calculates the total number of PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. +*/ +DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3); + +/* +Calculates the total number of MP3 frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. +*/ +DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3); + +/* +Calculates the total number of MP3 and PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. + +This is equivalent to calling drmp3_get_mp3_frame_count() and drmp3_get_pcm_frame_count() except that it's more efficient. +*/ +DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount); + +/* +Calculates the seekpoints based on PCM frames. This is slow. + +pSeekpoint count is a pointer to a uint32 containing the seekpoint count. On input it contains the desired count. +On output it contains the actual count. The reason for this design is that the client may request too many +seekpoints, in which case dr_mp3 will return a corrected count. + +Note that seektable seeking is not quite sample exact when the MP3 stream contains inconsistent sample rates. +*/ +DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints); + +/* +Binds a seek table to the decoder. + +This does _not_ make a copy of pSeekPoints - it only references it. It is up to the application to ensure this +remains valid while it is bound to the decoder. + +Use drmp3_calculate_seek_points() to calculate the seek points. +*/ +DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints); -// Opens an decodes an entire MP3 stream as a single operation. -// -// pConfig is both an input and output. On input it contains what you want. On output it contains what you got. -// -// Free the returned pointer with drmp3_free(). -float* drmp3_open_and_decode_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); -float* drmp3_open_and_decode_memory_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); +/* +Opens an decodes an entire MP3 stream as a single operation. + +On output pConfig will receive the channel count and sample rate of the stream. + +Free the returned pointer with drmp3_free(). +*/ +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 -float* drmp3_open_and_decode_file_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); +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 -// Frees any memory that was allocated by a public drmp3 API. -void drmp3_free(void* p); +/* +Allocates a block of memory on the heap. +*/ +DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks); + +/* +Frees any memory that was allocated by a public drmp3 API. +*/ +DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks); #ifdef __cplusplus } #endif -#endif // dr_mp3_h +#endif /* dr_mp3_h */ -///////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -///////////////////////////////////////////////////// -#ifdef DR_MP3_IMPLEMENTATION +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION) +#ifndef dr_mp3_c +#define dr_mp3_c + #include #include -#include -#include // For INT_MAX +#include /* For INT_MAX */ -// Disable SIMD when compiling with TCC for now. +DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision) +{ + if (pMajor) { + *pMajor = DRMP3_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = DRMP3_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRMP3_VERSION_REVISION; + } +} + +DRMP3_API const char* drmp3_version_string(void) +{ + return DRMP3_VERSION_STRING; +} + +/* Disable SIMD when compiling with TCC for now. */ #if defined(__TINYC__) #define DR_MP3_NO_SIMD #endif +#define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset))) + #define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES #define DRMP3_MAX_FRAME_SYNC_MATCHES 10 +#endif #define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ @@ -339,7 +591,7 @@ void drmp3_free(void* p); #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_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) @@ -352,16 +604,16 @@ void drmp3_free(void* p); #if !defined(DR_MP3_NO_SIMD) -#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(_M_ARM64) || defined(__x86_64__) || defined(__aarch64__)) +#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) /* x64 always have SSE2, arm64 always have neon, no need for generic code */ #define DR_MP3_ONLY_SIMD #endif -#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#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) #include #endif -#include +#include #define DRMP3_HAVE_SSE 1 #define DRMP3_HAVE_SIMD 1 #define DRMP3_VSTORE _mm_storeu_ps @@ -402,7 +654,7 @@ static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], #endif } #endif -static int drmp3_have_simd() +static int drmp3_have_simd(void) { #ifdef DR_MP3_ONLY_SIMD return 1; @@ -412,10 +664,10 @@ static int drmp3_have_simd() #ifdef MINIMP3_TEST static int g_counter; if (g_counter++ > 100) - goto test_nosimd; + return 0; #endif if (g_have_simd) - return g_have_simd - 1; + goto end; drmp3_cpuid(CPUInfo, 0); if (CPUInfo[0] > 0) { @@ -423,15 +675,14 @@ static int drmp3_have_simd() g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ return g_have_simd - 1; } -#ifdef MINIMP3_TEST -test_nosimd: -#endif - g_have_simd = 1; - return 0; + +end: + return g_have_simd - 1; #endif } -#elif defined(__ARM_NEON) || defined(__aarch64__) +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) #include +#define DRMP3_HAVE_SSE 0 #define DRMP3_HAVE_SIMD 1 #define DRMP3_VSTORE vst1q_f32 #define DRMP3_VLD vld1q_f32 @@ -444,11 +695,12 @@ test_nosimd: #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() +static int drmp3_have_simd(void) { /* TODO: detect neon for !DR_MP3_ONLY_SIMD */ return 1; } #else +#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 @@ -461,47 +713,68 @@ static int drmp3_have_simd() #endif +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__) +#define DRMP3_HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a) +{ + drmp3_int32 x = 0; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} +#else +#define DRMP3_HAVE_ARMV6 0 +#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; - int pos; - int limit; + int pos, limit; } drmp3_bs; typedef struct { - drmp3_uint8 total_bands; - drmp3_uint8 stereo_bands; - drmp3_uint8 bitalloc[64]; - drmp3_uint8 scfcod[64]; float scf[3*64]; + drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; } drmp3_L12_scale_info; typedef struct { - drmp3_uint8 tab_offset; - drmp3_uint8 code_tab_width; - drmp3_uint8 band_count; + drmp3_uint8 tab_offset, code_tab_width, band_count; } drmp3_L12_subband_alloc; typedef struct { const drmp3_uint8 *sfbtab; - drmp3_uint16 part_23_length; - drmp3_uint16 big_values; - drmp3_uint16 scalefac_compress; - drmp3_uint8 global_gain; - drmp3_uint8 block_type; - drmp3_uint8 mixed_block_flag; - drmp3_uint8 n_long_sfb; - drmp3_uint8 n_short_sfb; - drmp3_uint8 table_select[3]; - drmp3_uint8 region_count[3]; - drmp3_uint8 subblock_gain[3]; - drmp3_uint8 preflag; - drmp3_uint8 scalefac_scale; - drmp3_uint8 count1_table; - drmp3_uint8 scfsi; + 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 @@ -509,10 +782,8 @@ typedef struct 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]; - float scf[40]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; drmp3_uint8 ist_pos[2][39]; - float syn[18 + 15][2*32]; } drmp3dec_scratch; static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes) @@ -653,7 +924,7 @@ static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_ui if (mask & m) { int b = drmp3_bs_get_bits(bs, 6); - s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); + s = g_deq_L12[ba*3 - 6 + b % 3]*(int)(1 << 21 >> b/3); } *scf++ = s; } @@ -746,7 +1017,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; - memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + DRMP3_COPY_MEMORY(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++) @@ -760,8 +1031,7 @@ static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr) { - static const drmp3_uint8 g_scf_long[9][23] = { - { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + 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 }, @@ -771,8 +1041,7 @@ static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drm { 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 drmp3_uint8 g_scf_short[9][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 }, + 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 }, @@ -782,8 +1051,7 @@ static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drm { 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 drmp3_uint8 g_scf_mixed[9][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 }, + 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 }, @@ -796,8 +1064,8 @@ static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drm unsigned tables, scfsi = 0; int main_data_begin, part_23_sum = 0; - int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(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)) { @@ -894,14 +1162,14 @@ static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, c int cnt = scf_count[i]; if (scfsi & 8) { - memcpy(scf, ist_pos, cnt); + DRMP3_COPY_MEMORY(scf, ist_pos, cnt); } else { int bits = scf_size[i]; if (!bits) { - memset(scf, 0, cnt); - memset(ist_pos, 0, cnt); + DRMP3_ZERO_MEMORY(scf, cnt); + DRMP3_ZERO_MEMORY(ist_pos, cnt); } else { int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; @@ -972,16 +1240,16 @@ static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *is int sh = 3 - scf_shift; for (i = 0; i < gr->n_short_sfb; i += 3) { - iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; - iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; - 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 drmp3_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; for (i = 0; i < 10; i++) { - iscf[11 + i] += g_preamp[i]; + iscf[11 + i] = (drmp3_uint8)(iscf[11 + i] + g_preamp[i]); } } @@ -993,17 +1261,19 @@ static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *is } } +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 drmp3_L3_pow_43(int x) { - static const float g_pow43[129] = { - 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 - }; float frac; int sign, mult = 256; if (x < 129) { - return g_pow43[x]; + return g_drmp3_pow43[16 + x]; } if (x < 1024) @@ -1014,34 +1284,33 @@ static float drmp3_L3_pow_43(int x) sign = 2*x & 64; frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_pow43[(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 drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit) { - static const float g_pow43_signed[32] = { 0,0,1,-1,2.519842f,-2.519842f,4.326749f,-4.326749f,6.349604f,-6.349604f,8.549880f,-8.549880f,10.902724f,-10.902724f,13.390518f,-13.390518f,16.000000f,-16.000000f,18.720754f,-18.720754f,21.544347f,-21.544347f,24.463781f,-24.463781f,27.473142f,-27.473142f,30.567351f,-30.567351f,33.741992f,-33.741992f,36.993181f,-36.993181f }; - static const drmp3_int16 tab0[32] = { 0, }; - static const drmp3_int16 tab1[] = { 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 }; - static const drmp3_int16 tab2[] = { -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 }; - static const drmp3_int16 tab3[] = { -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 }; - static const drmp3_int16 tab5[] = { -253,-318,-351,-367,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,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258 }; - static const drmp3_int16 tab6[] = { -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259 }; - static const drmp3_int16 tab7[] = { -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258 }; - static const drmp3_int16 tab8[] = { -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258 }; - static const drmp3_int16 tab9[] = { -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259 }; - static const drmp3_int16 tab10[] = { -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258 }; - static const drmp3_int16 tab11[] = { -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290 }; - static const drmp3_int16 tab12[] = { -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259 }; - static const drmp3_int16 tab13[] = { -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258 }; - static const drmp3_int16 tab15[] = { -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 }; - static const drmp3_int16 tab16[] = { -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 }; - static const drmp3_int16 tab24[] = { -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 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, + -253,-318,-351,-367,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,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -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 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 * const tabindex[2*16] = { tab0,tab1,tab2,tab3,tab0,tab5,tab6,tab7,tab8,tab9,tab10,tab11,tab12,tab13,tab0,tab15,tab16,tab16,tab16,tab16,tab16,tab16,tab16,tab16,tab24,tab24,tab24,tab24,tab24,tab24,tab24,tab24 }; + 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) @@ -1058,43 +1327,74 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g { int tab_num = gr_info->table_select[ireg]; int sfb_cnt = gr_info->region_count[ireg++]; - const short *codebook = tabindex[tab_num]; + const drmp3_int16 *codebook = tabs + tabindex[tab_num]; int linbits = g_linbits[tab_num]; - do + if (linbits) { - np = *sfb++ / 2; - pairs_to_decode = DRMP3_MIN(big_val_cnt, np); - one = *scf++; do { - int j, w = 5; - int leaf = codebook[DRMP3_PEEK_BITS(w)]; - while (leaf < 0) + np = *sfb++ / 2; + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); + one = *scf++; + do { - DRMP3_FLUSH_BITS(w); - w = leaf & 7; - leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; - } - DRMP3_FLUSH_BITS(leaf >> 8); - - for (j = 0; j < 2; j++, dst++, leaf >>= 4) - { - int lsb = leaf & 0x0F; - if (lsb == 15 && linbits) + int j, w = 5; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; + while (leaf < 0) { - lsb += DRMP3_PEEK_BITS(linbits); - DRMP3_FLUSH_BITS(linbits); - DRMP3_CHECK_BITS; - *dst = one*drmp3_L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); - } else - { - *dst = g_pow43_signed[lsb*2 + (bs_cache >> 31)]*one; + DRMP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; } - DRMP3_FLUSH_BITS(lsb ? 1 : 0); - } - DRMP3_CHECK_BITS; - } while (--pairs_to_decode); - } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + DRMP3_FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + 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_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + DRMP3_FLUSH_BITS(lsb ? 1 : 0); + } + DRMP3_CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; + while (leaf < 0) + { + DRMP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; + } + DRMP3_FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + DRMP3_FLUSH_BITS(lsb ? 1 : 0); + } + DRMP3_CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } } for (np = 1 - big_val_cnt;; dst += 4) @@ -1129,12 +1429,22 @@ 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()) for (; i < n - 3; i += 4) + if (drmp3_have_simd()) { - 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)); + 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 } #endif for (; i < n; i++) @@ -1227,7 +1537,7 @@ static void drmp3_L3_intensity_stereo(float *left, drmp3_uint8 *ist_pos, const d int prev = itop - max_blocks; ist_pos[itop] = (drmp3_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]); } - drmp3_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 drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sfb) @@ -1244,7 +1554,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf *dst++ = src[2*len]; } } - memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); + DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float)); } static void drmp3_L3_antialias(float *grbuf, int nbands) @@ -1413,8 +1723,8 @@ static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands) for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) { float tmp[18]; - memcpy(tmp, grbuf, sizeof(tmp)); - memcpy(grbuf, overlap, 6*sizeof(float)); + DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp)); + DRMP3_COPY_MEMORY(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); @@ -1458,7 +1768,7 @@ static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s) } if (remains > 0) { - memmove(h->reserv_buf, s->maindata + pos, remains); + DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains); } h->reserv = remains; } @@ -1467,8 +1777,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); - 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_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); drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); return h->reserv >= main_data_begin; } @@ -1568,7 +1878,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) { @@ -1584,7 +1894,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]); @@ -1601,7 +1911,7 @@ static void drmp3d_DCT_II(float *grbuf, int n) } else #endif #ifdef DR_MP3_ONLY_SIMD - {} + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ #else for (; k < n; k++) { @@ -1664,18 +1974,34 @@ static void drmp3d_DCT_II(float *grbuf, int n) #endif } -static short drmp3d_scale_pcm(float sample) -{ - if (sample > 32767.0) return (short) 32767; - if (sample < -32768.0) return (short)-32768; - int s = (int)(sample + .5f); - s -= (s < 0); /* away from zero, to be compliant */ - if (s > 32767) return (short) 32767; - if (s < -32768) return (short)-32768; - return (short)s; -} +#ifndef DR_MP3_FLOAT_OUTPUT +typedef drmp3_int16 drmp3d_sample_t; -static void drmp3d_synth_pair(short *pcm, int nch, const float *z) +static drmp3_int16 drmp3d_scale_pcm(float sample) +{ + drmp3_int16 s; +#if DRMP3_HAVE_ARMV6 + drmp3_int32 s32 = (drmp3_int32)(sample + .5f); + 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; + s = (drmp3_int16)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ +#endif + return s; +} +#else +typedef float drmp3d_sample_t; + +static float drmp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif + +static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z) { float a; a = (z[14*64] - z[ 0]) * 29; @@ -1700,11 +2026,11 @@ static void drmp3d_synth_pair(short *pcm, int nch, const float *z) pcm[16*nch] = drmp3d_scale_pcm(a); } -static void drmp3d_synth(float *xl, short *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); - short *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, @@ -1761,19 +2087,20 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) 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 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] = (short)_mm_extract_epi16(pcm8, 1); - dstr[(17 + i)*nch] = (short)_mm_extract_epi16(pcm8, 5); - dstl[(15 - i)*nch] = (short)_mm_extract_epi16(pcm8, 0); - dstl[(17 + i)*nch] = (short)_mm_extract_epi16(pcm8, 4); - dstr[(47 - i)*nch] = (short)_mm_extract_epi16(pcm8, 3); - dstr[(49 + i)*nch] = (short)_mm_extract_epi16(pcm8, 7); - dstl[(47 - i)*nch] = (short)_mm_extract_epi16(pcm8, 2); - dstl[(49 + i)*nch] = (short)_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 = DRMP3_VADD(a, DRMP3_VSET(0.5f)); @@ -1789,11 +2116,39 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); 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 + _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))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif +#endif /* DR_MP3_FLOAT_OUTPUT */ } } else #endif #ifdef DR_MP3_ONLY_SIMD - {} + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ #else for (i = 14; i >= 0; i--) { @@ -1826,7 +2181,7 @@ static void drmp3d_synth(float *xl, short *dstl, int nch, float *lins) #endif } -static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, short *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++) @@ -1834,7 +2189,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int drmp3d_DCT_II(grbuf + 576*i, nbands); } - memcpy(lins, qmf_state, sizeof(float)*15*64); + DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64); for (i = 0; i < nbands; i += 2) { @@ -1850,7 +2205,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int } else #endif { - memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64); } } @@ -1903,15 +2258,15 @@ static int drmp3d_find_frame(const drmp3_uint8 *mp3, int mp3_bytes, int *free_fo } } *ptr_frame_bytes = 0; - return i; + return mp3_bytes; } -void drmp3dec_init(drmp3dec *dec) +DRMP3_API void drmp3dec_init(drmp3dec *dec) { dec->header[0] = 0; } -int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, short *pcm, drmp3dec_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 drmp3_uint8 *hdr; @@ -1928,7 +2283,7 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes } if (!frame_size) { - memset(dec, 0, sizeof(drmp3dec)); + DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec)); i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); if (!frame_size || i + frame_size > mp3_bytes) { @@ -1938,7 +2293,7 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes } hdr = mp3 + i; - memcpy(dec->header, hdr, DRMP3_HDR_SIZE); + DRMP3_COPY_MEMORY(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); @@ -1960,13 +2315,13 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes return 0; } success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); - if (success) + if (success && pcm != NULL) { - for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 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)) { - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + DRMP3_ZERO_MEMORY(scratch.grbuf[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, pcm, scratch.syn[0]); + drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]); } } drmp3_L3_save_reservoir(dec, &scratch); @@ -1976,18 +2331,23 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes return 0; #else drmp3_L12_scale_info sci[1]; + + if (pcm == NULL) { + return drmp3_hdr_frame_samples(hdr); + } + drmp3_L12_read_scale_info(hdr, bs_frame, sci); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + DRMP3_ZERO_MEMORY(scratch.grbuf[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))) { 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, pcm, scratch.syn[0]); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); - pcm += 384*info->channels; + 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)); + pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels); } if (bs_frame->pos > bs_frame->limit) { @@ -1997,327 +2357,337 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes } #endif } + return success*drmp3_hdr_frame_samples(dec->header); } - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Main Public API -// -/////////////////////////////////////////////////////////////////////////////// - -// Options. -#ifndef DR_MP3_DEFAULT_CHANNELS -#define DR_MP3_DEFAULT_CHANNELS 2 +DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples) +{ + size_t i = 0; +#if DRMP3_HAVE_SIMD + size_t aligned_count = num_samples & ~7; + for(; i < aligned_count; i+=8) + { + 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 ] = (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 = 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); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); #endif -#ifndef DR_MP3_DEFAULT_SAMPLE_RATE -#define DR_MP3_DEFAULT_SAMPLE_RATE 44100 + } +#endif + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5f) + out[i] = (drmp3_int16) 32767; + else if (sample <= -32767.5f) + out[i] = (drmp3_int16)-32768; + else + { + short s = (drmp3_int16)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } +} + + + +/************************************************************************************************************************************************************ + + Main Public API + + ************************************************************************************************************************************************************/ +/* SIZE_MAX */ +#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 +/* End SIZE_MAX */ + +/* Options. */ +#ifndef DRMP3_SEEK_LEADING_MP3_FRAMES +#define DRMP3_SEEK_LEADING_MP3_FRAMES 2 +#endif + +#define DRMP3_MIN_DATA_CHUNK_SIZE 16384 + +/* 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) #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)) +#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_assert DRMP3_ASSERT -#define drmp3_copy_memory DRMP3_COPY_MEMORY -#define drmp3_zero_memory DRMP3_ZERO_MEMORY -#define drmp3_zero_object DRMP3_ZERO_OBJECT -#define drmp3_malloc DRMP3_MALLOC -#define drmp3_realloc DRMP3_REALLOC +#define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER 2 -#define drmp3_countof(x) (sizeof(x) / sizeof(x[0])) -#define drmp3_max(x, y) (((x) > (y)) ? (x) : (y)) -#define drmp3_min(x, y) (((x) < (y)) ? (x) : (y)) - -#define DRMP3_DATA_CHUNK_SIZE 16384 // The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends 16K. - -static inline float drmp3_mix_f32(float x, float y, float a) +static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; } - -static void drmp3_blend_f32(float* pOut, float* pInA, float* pInB, float factor, drmp3_uint32 channels) +static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a) { - for (drmp3_uint32 i = 0; i < channels; ++i) { - pOut[i] = drmp3_mix_f32(pInA[i], pInB[i], factor); - } + float r0 = (y - x); + float r1 = r0*a; + return x + r1; + /*return x + (y - x)*a;*/ } -void drmp3_src_cache_init(drmp3_src* pSRC, drmp3_src_cache* pCache) + +/* +Greatest common factor using Euclid's algorithm iteratively. +*/ +static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b) { - drmp3_assert(pSRC != NULL); - drmp3_assert(pCache != NULL); - - pCache->pSRC = pSRC; - pCache->cachedFrameCount = 0; - pCache->iNextFrame = 0; -} - -drmp3_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 frameCount, float* pFramesOut) -{ - drmp3_assert(pCache != NULL); - drmp3_assert(pCache->pSRC != NULL); - drmp3_assert(pCache->pSRC->onRead != NULL); - drmp3_assert(frameCount > 0); - drmp3_assert(pFramesOut != NULL); - - drmp3_uint32 channels = pCache->pSRC->config.channels; - - drmp3_uint64 totalFramesRead = 0; - while (frameCount > 0) { - // If there's anything in memory go ahead and copy that over first. - drmp3_uint64 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame; - drmp3_uint64 framesToReadFromMemory = frameCount; - if (framesToReadFromMemory > framesRemainingInMemory) { - framesToReadFromMemory = framesRemainingInMemory; - } - - drmp3_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, (drmp3_uint32)(framesToReadFromMemory * channels * sizeof(float))); - pCache->iNextFrame += (drmp3_uint32)framesToReadFromMemory; - - totalFramesRead += framesToReadFromMemory; - frameCount -= framesToReadFromMemory; - if (frameCount == 0) { - break; - } - - - // At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. - drmp3_assert(frameCount > 0); - pFramesOut += framesToReadFromMemory * channels; - - pCache->iNextFrame = 0; - pCache->cachedFrameCount = 0; - - drmp3_uint32 framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; - if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { - framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; - } - - pCache->cachedFrameCount = (drmp3_uint32)pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); - - - // Get out of this loop if nothing was able to be retrieved. - if (pCache->cachedFrameCount == 0) { + for (;;) { + if (b == 0) { break; + } else { + drmp3_uint32 t = a; + a = b; + b = t % a; } } - return totalFramesRead; + return a; } -drmp3_uint64 drmp3_src_read_frames_passthrough(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush); -drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush); - -drmp3_bool32 drmp3_src_init(const drmp3_src_config* pConfig, drmp3_src_read_proc onRead, void* pUserData, drmp3_src* pSRC) +static void* drmp3__malloc_default(size_t sz, void* pUserData) { - if (pSRC == NULL) return DRMP3_FALSE; - drmp3_zero_object(pSRC); + (void)pUserData; + return DRMP3_MALLOC(sz); +} - if (pConfig == NULL || onRead == NULL) return DRMP3_FALSE; - if (pConfig->channels == 0 || pConfig->channels > 2) return DRMP3_FALSE; +static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRMP3_REALLOC(p, sz); +} - pSRC->config = *pConfig; - pSRC->onRead = onRead; - pSRC->pUserData = pUserData; +static void drmp3__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRMP3_FREE(p); +} - if (pSRC->config.cacheSizeInFrames > DRMP3_SRC_CACHE_SIZE_IN_FRAMES || pSRC->config.cacheSizeInFrames == 0) { - pSRC->config.cacheSizeInFrames = DRMP3_SRC_CACHE_SIZE_IN_FRAMES; + +static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; } - drmp3_src_cache_init(pSRC, &pSRC->cache); - return DRMP3_TRUE; + 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; } -drmp3_bool32 drmp3_src_set_input_sample_rate(drmp3_src* pSRC, drmp3_uint32 sampleRateIn) +static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks) { - if (pSRC == NULL) return DRMP3_FALSE; + if (pAllocationCallbacks == NULL) { + return NULL; + } - // Must have a sample rate of > 0. - if (sampleRateIn == 0) { + 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) { + DRMP3_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + /* Copy. */ + return *pAllocationCallbacks; + } else { + /* Defaults. */ + drmp3_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drmp3__malloc_default; + allocationCallbacks.onRealloc = drmp3__realloc_default; + allocationCallbacks.onFree = drmp3__free_default; + return allocationCallbacks; + } +} + + + +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 drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin) +{ + DRMP3_ASSERT(offset >= 0); + + if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { return DRMP3_FALSE; } - pSRC->config.sampleRateIn = sampleRateIn; + if (origin == drmp3_seek_origin_start) { + pMP3->streamCursor = (drmp3_uint64)offset; + } else { + pMP3->streamCursor += offset; + } + return DRMP3_TRUE; } -drmp3_bool32 drmp3_src_set_output_sample_rate(drmp3_src* pSRC, drmp3_uint32 sampleRateOut) +static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin) { - if (pSRC == NULL) return DRMP3_FALSE; + if (offset <= 0x7FFFFFFF) { + return drmp3__on_seek(pMP3, (int)offset, origin); + } - // Must have a sample rate of > 0. - if (sampleRateOut == 0) { + + /* Getting here "offset" is too large for a 32-bit integer. We just keep seeking forward until we hit the offset. */ + if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) { return DRMP3_FALSE; } - pSRC->config.sampleRateOut = sampleRateOut; + offset -= 0x7FFFFFFF; + while (offset > 0) { + if (offset <= 0x7FFFFFFF) { + if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) { + return DRMP3_FALSE; + } + offset = 0; + } else { + if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) { + return DRMP3_FALSE; + } + offset -= 0x7FFFFFFF; + } + } + return DRMP3_TRUE; } -drmp3_uint64 drmp3_src_read_frames_ex(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush) + +static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { - if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; + drmp3_uint32 pcmFramesRead = 0; - drmp3_src_algorithm algorithm = pSRC->config.algorithm; - - // Always use passthrough if the sample rates are the same. - if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { - algorithm = drmp3_src_algorithm_none; - } - - // Could just use a function pointer instead of a switch for this... - switch (algorithm) - { - case drmp3_src_algorithm_none: return drmp3_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); - case drmp3_src_algorithm_linear: return drmp3_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush); - default: return 0; - } -} - -drmp3_uint64 drmp3_src_read_frames(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut) -{ - return drmp3_src_read_frames_ex(pSRC, frameCount, pFramesOut, DRMP3_FALSE); -} - -drmp3_uint64 drmp3_src_read_frames_passthrough(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush) -{ - drmp3_assert(pSRC != NULL); - drmp3_assert(frameCount > 0); - drmp3_assert(pFramesOut != NULL); - - (void)flush; // Passthrough need not care about flushing. - return pSRC->onRead(pSRC, frameCount, pFramesOut, pSRC->pUserData); -} - -drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush) -{ - drmp3_assert(pSRC != NULL); - drmp3_assert(frameCount > 0); - drmp3_assert(pFramesOut != NULL); - - // For linear SRC, the bin is only 2 frames: 1 prior, 1 future. - - // Load the bin if necessary. - if (!pSRC->algo.linear.isPrevFramesLoaded) { - drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin); - if (framesRead == 0) { - return 0; - } - pSRC->algo.linear.isPrevFramesLoaded = DRMP3_TRUE; - } - if (!pSRC->algo.linear.isNextFramesLoaded) { - drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin + pSRC->config.channels); - if (framesRead == 0) { - return 0; - } - pSRC->algo.linear.isNextFramesLoaded = DRMP3_TRUE; - } - - float factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; - - drmp3_uint64 totalFramesRead = 0; - while (frameCount > 0) { - // The bin is where the previous and next frames are located. - float* pPrevFrame = pSRC->bin; - float* pNextFrame = pSRC->bin + pSRC->config.channels; - - drmp3_blend_f32((float*)pFramesOut, pPrevFrame, pNextFrame, pSRC->algo.linear.alpha, pSRC->config.channels); - - pSRC->algo.linear.alpha += factor; - - // The new alpha value is how we determine whether or not we need to read fresh frames. - drmp3_uint32 framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha; - pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient; - - for (drmp3_uint32 i = 0; i < framesToReadFromClient; ++i) { - for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j) { - pPrevFrame[j] = pNextFrame[j]; - } - - drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); - if (framesRead == 0) { - for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j) { - pNextFrame[j] = 0; - } - - if (pSRC->algo.linear.isNextFramesLoaded) { - pSRC->algo.linear.isNextFramesLoaded = DRMP3_FALSE; - } else { - if (flush) { - pSRC->algo.linear.isPrevFramesLoaded = DRMP3_FALSE; - } - } - - break; - } - } - - pFramesOut = (drmp3_uint8*)pFramesOut + (1 * pSRC->config.channels * sizeof(float)); - frameCount -= 1; - totalFramesRead += 1; - - // If there's no frames available we need to get out of this loop. - if (!pSRC->algo.linear.isNextFramesLoaded && (!flush || !pSRC->algo.linear.isPrevFramesLoaded)) { - break; - } - } - - return totalFramesRead; -} - - - -static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3) -{ - drmp3_assert(pMP3 != NULL); - drmp3_assert(pMP3->onRead != NULL); + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onRead != NULL); if (pMP3->atEnd) { - return DRMP3_FALSE; + return 0; } - do - { - // minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. - if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE) { + for (;;) { + drmp3dec_frame_info info; + + /* minimp3 recommends doing data submission in chunks of at least 16K. If we don't have at least 16K bytes available, get more. */ + if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) { + size_t bytesRead; + + /* First we need to move the data down. */ + if (pMP3->pData != NULL) { + DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + } + + pMP3->dataConsumed = 0; + if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) { - pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE; - drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); + drmp3_uint8* pNewData; + size_t newDataCap; + + newDataCap = DRMP3_DATA_CHUNK_SIZE; + + pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks); if (pNewData == NULL) { - return DRMP3_FALSE; // Out of memory. + return 0; /* Out of memory. */ } pMP3->pData = pNewData; + pMP3->dataCapacity = newDataCap; } - size_t bytesRead = pMP3->onRead(pMP3->pUserData, 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 = DRMP3_TRUE; - return DRMP3_FALSE; // No data. + if (pMP3->dataSize == 0) { + pMP3->atEnd = DRMP3_TRUE; + return 0; /* No data. */ + } } pMP3->dataSize += bytesRead; @@ -2325,187 +2695,198 @@ static drmp3_bool32 drmp3_decode_next_frame(drmp3* pMP3) if (pMP3->dataSize > INT_MAX) { pMP3->atEnd = DRMP3_TRUE; - return DRMP3_FALSE; // File too big. + return 0; /* File too big. */ } - drmp3dec_frame_info info; - drmp3_uint32 samplesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pMP3->frames, &info); // <-- Safe size_t -> int conversion thanks to the check above. - if (samplesRead != 0) { - size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes); - for (size_t i = 0; i < leftoverDataSize; ++i) { - pMP3->pData[i] = pMP3->pData[i + (size_t)info.frame_bytes]; - } - - pMP3->dataSize = leftoverDataSize; - pMP3->framesConsumed = 0; - pMP3->framesRemaining = samplesRead; - pMP3->frameChannels = info.channels; - pMP3->frameSampleRate = info.hz; - drmp3_src_set_input_sample_rate(&pMP3->src, pMP3->frameSampleRate); + 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. */ + if (info.frame_bytes > 0) { + pMP3->dataConsumed += (size_t)info.frame_bytes; + pMP3->dataSize -= (size_t)info.frame_bytes; + } + + /* pcmFramesRead will be equal to 0 if decoding failed. If it is zero and info.frame_bytes > 0 then we have successfully decoded the frame. */ + 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 { - // Need more data. minimp3 recommends doing data submission in 16K chunks. + } else if (info.frame_bytes == 0) { + /* Need more data. minimp3 recommends doing data submission in 16K chunks. */ + size_t bytesRead; + + /* First we need to move the data down. */ + DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + pMP3->dataConsumed = 0; + if (pMP3->dataCapacity == pMP3->dataSize) { - // No room. Expand. - pMP3->dataCapacity += DRMP3_DATA_CHUNK_SIZE; - drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); + /* No room. Expand. */ + drmp3_uint8* pNewData; + size_t newDataCap; + + 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 DRMP3_FALSE; // Out of memory. + return 0; /* Out of memory. */ } pMP3->pData = pNewData; + pMP3->dataCapacity = newDataCap; } - // Fill in a chunk. - size_t bytesRead = pMP3->onRead(pMP3->pUserData, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + /* Fill in a chunk. */ + bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); if (bytesRead == 0) { pMP3->atEnd = DRMP3_TRUE; - return DRMP3_FALSE; // Error reading more data. + return 0; /* Error reading more data. */ } pMP3->dataSize += bytesRead; } - } while (DRMP3_TRUE); + }; - return DRMP3_TRUE; + return pcmFramesRead; } -static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData) +static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { - drmp3* pMP3 = (drmp3*)pUserData; - drmp3_assert(pMP3 != NULL); - drmp3_assert(pMP3->onRead != NULL); + drmp3_uint32 pcmFramesRead = 0; + drmp3dec_frame_info info; - float* pFramesOutF = (float*)pFramesOut; - drmp3_uint32 totalFramesRead = 0; + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->memory.pData != NULL); - while (frameCount > 0) { - // Read from the in-memory buffer first. - while (pMP3->framesRemaining > 0 && frameCount > 0) { - if (pMP3->frameChannels == 1) { - if (pMP3->channels == 1) { - // Mono -> Mono. - pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; - } else { - // Mono -> Stereo. - pFramesOutF[0] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; - pFramesOutF[1] = pMP3->frames[pMP3->framesConsumed] / 32768.0f; - } - } else { - if (pMP3->channels == 1) { - // Stereo -> Mono - float sample = 0; - sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; - sample += pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; - pFramesOutF[0] = sample * 0.5f; - } else { - // Stereo -> Stereo - pFramesOutF[0] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+0] / 32768.0f; - pFramesOutF[1] = pMP3->frames[(pMP3->framesConsumed*pMP3->frameChannels)+1] / 32768.0f; - } - } + if (pMP3->atEnd) { + return 0; + } - pMP3->framesConsumed += 1; - pMP3->framesRemaining -= 1; - frameCount -= 1; - totalFramesRead += 1; - pFramesOutF += pSRC->config.channels; - } - - if (frameCount == 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; - } - - drmp3_assert(pMP3->framesRemaining == 0); - - // At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed - // at this point which means we'll also need to update our sample rate conversion pipeline. - if (!drmp3_decode_next_frame(pMP3)) { + } 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; } } - return totalFramesRead; + /* Consume the data. */ + pMP3->memory.currentReadPos += (size_t)info.frame_bytes; + + return pcmFramesRead; } -drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig) +static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames) { - drmp3_assert(pMP3 != NULL); - drmp3_assert(onRead != NULL); - - // This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. - drmp3dec_init(&pMP3->decoder); - - // The config can be null in which case we use defaults. - drmp3_config config; - if (pConfig != NULL) { - config = *pConfig; + if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { + return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); } else { - drmp3_zero_object(&config); + return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + } +} + +static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3) +{ + DRMP3_ASSERT(pMP3 != NULL); + return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames); +} + +#if 0 +static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3) +{ + drmp3_uint32 pcmFrameCount; + + DRMP3_ASSERT(pMP3 != NULL); + + pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFrameCount == 0) { + return 0; } - pMP3->channels = config.outputChannels; - if (pMP3->channels == 0) { - pMP3->channels = DR_MP3_DEFAULT_CHANNELS; - } + /* We have essentially just skipped past the frame, so just set the remaining samples to 0. */ + pMP3->currentPCMFrame += pcmFrameCount; + pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount; + pMP3->pcmFramesRemainingInMP3Frame = 0; - // Cannot have more than 2 channels. - if (pMP3->channels > 2) { - pMP3->channels = 2; - } + return pcmFrameCount; +} +#endif - pMP3->sampleRate = config.outputSampleRate; - if (pMP3->sampleRate == 0) { - pMP3->sampleRate = DR_MP3_DEFAULT_SAMPLE_RATE; - } +static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(onRead != NULL); + + /* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */ + drmp3dec_init(&pMP3->decoder); pMP3->onRead = onRead; pMP3->onSeek = onSeek; pMP3->pUserData = pUserData; + pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); - // We need a sample rate converter for converting the sample rate from the MP3 frames to the requested output sample rate. - drmp3_src_config srcConfig; - drmp3_zero_object(&srcConfig); - srcConfig.sampleRateIn = DR_MP3_DEFAULT_SAMPLE_RATE; - srcConfig.sampleRateOut = pMP3->sampleRate; - srcConfig.channels = pMP3->channels; - srcConfig.algorithm = drmp3_src_algorithm_linear; - if (!drmp3_src_init(&srcConfig, drmp3_read_src, pMP3, &pMP3->src)) { - return DRMP3_FALSE; + if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { + return DRMP3_FALSE; /* Invalid allocation callbacks. */ } - - // Decode the first frame to confirm that it is indeed a valid MP3 stream. - if (!drmp3_decode_next_frame(pMP3)) { - return DRMP3_FALSE; // Not a valid MP3 stream. + + /* Decode the first frame to confirm that it is indeed a valid MP3 stream. */ + if (drmp3_decode_next_frame(pMP3) == 0) { + 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. */ } + pMP3->channels = pMP3->mp3FrameChannels; + pMP3->sampleRate = pMP3->mp3FrameSampleRate; + return DRMP3_TRUE; } -drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig) +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 DRMP3_FALSE; } - drmp3_zero_object(pMP3); - return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pConfig); + DRMP3_ZERO_OBJECT(pMP3); + return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); } static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { drmp3* pMP3 = (drmp3*)pUserData; - drmp3_assert(pMP3 != NULL); - drmp3_assert(pMP3->memory.dataSize >= pMP3->memory.currentReadPos); + size_t bytesRemaining; - size_t bytesRemaining = 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) { - drmp3_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; } @@ -2515,39 +2896,40 @@ static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t by static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin) { drmp3* pMP3 = (drmp3*)pUserData; - drmp3_assert(pMP3 != NULL); + + 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); // Trying to seek too far forward. + byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); /* Trying to seek too far forward. */ } } else { if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pMP3->memory.currentReadPos; // Trying to seek too far backwards. + byteOffset = -(int)pMP3->memory.currentReadPos; /* Trying to seek too far backwards. */ } } - // This will never underflow thanks to the clamps above. + /* This will never underflow thanks to the clamps above. */ pMP3->memory.currentReadPos += byteOffset; } else { if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) { pMP3->memory.currentReadPos = byteOffset; } else { - pMP3->memory.currentReadPos = pMP3->memory.dataSize; // Trying to seek too far forward. + pMP3->memory.currentReadPos = pMP3->memory.dataSize; /* Trying to seek too far forward. */ } } return DRMP3_TRUE; } -drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_config* pConfig) +DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks) { if (pMP3 == NULL) { return DRMP3_FALSE; } - drmp3_zero_object(pMP3); + DRMP3_ZERO_OBJECT(pMP3); if (pData == NULL || dataSize == 0) { return DRMP3_FALSE; @@ -2557,12 +2939,578 @@ drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, pMP3->memory.dataSize = dataSize; pMP3->memory.currentReadPos = 0; - return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pConfig); + return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks); } #ifndef DR_MP3_NO_STDIO #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) +{ + 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; + } +} +/* End Errno */ + +/* fopen */ +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; /* Safety. */ + } + + 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; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRMP3_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#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; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRMP3_INVALID_ARGS; + } + +#if defined(DRMP3_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #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 + /* + 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; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + 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); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + 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); + } + #endif + + if (*ppFile == NULL) { + return DRMP3_ERROR; + } +#endif + + return DRMP3_SUCCESS; +} +/* End fopen */ + static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) { @@ -2574,263 +3522,1311 @@ static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } -drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* filePath, const drmp3_config* pConfig) +DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks) { + drmp3_bool32 result; FILE* pFile; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (fopen_s(&pFile, filePath, "rb") != 0) { - return DRMP3_FALSE; - } -#else - pFile = fopen(filePath, "rb"); - if (pFile == NULL) { - return DRMP3_FALSE; - } -#endif - return drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pConfig); + if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) { + return DRMP3_FALSE; + } + + result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRMP3_TRUE) { + fclose(pFile); + return result; + } + + return DRMP3_TRUE; +} + +DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + drmp3_bool32 result; + FILE* pFile; + + if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) { + return DRMP3_FALSE; + } + + result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRMP3_TRUE) { + fclose(pFile); + return result; + } + + return DRMP3_TRUE; } #endif -void drmp3_uninit(drmp3* pMP3) +DRMP3_API void drmp3_uninit(drmp3* pMP3) { - if (pMP3 == NULL) return; + if (pMP3 == NULL) { + return; + } #ifndef DR_MP3_NO_STDIO if (pMP3->onRead == drmp3__on_read_stdio) { - fclose((FILE*)pMP3->pUserData); + FILE* pFile = (FILE*)pMP3->pUserData; + if (pFile != NULL) { + fclose(pFile); + pMP3->pUserData = NULL; /* Make sure the file handle is cleared to NULL to we don't attempt to close it a second time. */ + } } #endif - drmp3_free(pMP3->pData); + drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); } -drmp3_uint64 drmp3_read_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut) +#if defined(DR_MP3_FLOAT_OUTPUT) +static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount) { - if (pMP3 == NULL || pMP3->onRead == NULL) return 0; + drmp3_uint64 i; + drmp3_uint64 i4; + drmp3_uint64 sampleCount4; + /* Unrolled. */ + i = 0; + sampleCount4 = sampleCount >> 2; + for (i4 = 0; i4 < sampleCount4; i4 += 1) { + float x0 = src[i+0]; + float x1 = src[i+1]; + float x2 = src[i+2]; + float x3 = src[i+3]; + + x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0)); + x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1)); + x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2)); + x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3)); + + x0 = x0 * 32767.0f; + x1 = x1 * 32767.0f; + x2 = x2 * 32767.0f; + x3 = x3 * 32767.0f; + + 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; + } + + /* Leftover. */ + for (; i < sampleCount; i += 1) { + float x = src[i]; + x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ + x = x * 32767.0f; /* -1..1 to -32767..32767 */ + + dst[i] = (drmp3_int16)x; + } +} +#endif + +#if !defined(DR_MP3_FLOAT_OUTPUT) +static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount) +{ + drmp3_uint64 i; + for (i = 0; i < sampleCount; i += 1) { + float x = (float)src[i]; + x = x * 0.000030517578125f; /* -32768..32767 to -1..0.999969482421875 */ + dst[i] = x; + } +} +#endif + + +static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut) +{ drmp3_uint64 totalFramesRead = 0; - if (pBufferOut == NULL) { - float temp[4096]; - while (framesToRead > 0) { - drmp3_uint64 framesToReadRightNow = sizeof(temp)/sizeof(temp[0]) / pMP3->channels; - if (framesToReadRightNow > framesToRead) { - framesToReadRightNow = framesToRead; - } + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onRead != NULL); - drmp3_uint64 framesJustRead = drmp3_read_f32(pMP3, framesToReadRightNow, temp); - if (framesJustRead == 0) { - break; - } - - framesToRead -= framesJustRead; - totalFramesRead += framesJustRead; + while (framesToRead > 0) { + drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead); + if (pBufferOut != NULL) { + #if defined(DR_MP3_FLOAT_OUTPUT) + /* f32 */ + 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 + /* s16 */ + 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; + pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; + pMP3->pcmFramesRemainingInMP3Frame -= framesToConsume; + totalFramesRead += framesToConsume; + framesToRead -= framesToConsume; + + if (framesToRead == 0) { + break; + } + + DRMP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); + + /* + At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed + at this point which means we'll also need to update our sample rate conversion pipeline. + */ + if (drmp3_decode_next_frame(pMP3) == 0) { + break; } - } else { - totalFramesRead = drmp3_src_read_frames_ex(&pMP3->src, framesToRead, pBufferOut, DRMP3_TRUE); } return totalFramesRead; } -drmp3_bool32 drmp3_seek_to_frame(drmp3* pMP3, drmp3_uint64 frameIndex) -{ - if (pMP3 == NULL || pMP3->onSeek == NULL) return DRMP3_FALSE; - // Seek to the start of the stream to begin with. - if (!pMP3->onSeek(pMP3->pUserData, 0, drmp3_seek_origin_start)) { +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(DR_MP3_FLOAT_OUTPUT) + /* Fast path. No conversion required. */ + return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); +#else + /* Slow path. Convert from s16 to f32. */ + { + drmp3_int16 pTempS16[8192]; + drmp3_uint64 totalPCMFramesRead = 0; + + while (totalPCMFramesRead < framesToRead) { + drmp3_uint64 framesJustRead; + drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempS16) / pMP3->channels; + if (framesToReadNow > framesRemaining) { + framesToReadNow = framesRemaining; + } + + framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16); + if (framesJustRead == 0) { + break; + } + + drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels); + totalPCMFramesRead += framesJustRead; + } + + return totalPCMFramesRead; + } +#endif +} + +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(DR_MP3_FLOAT_OUTPUT) + /* Fast path. No conversion required. */ + return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut); +#else + /* Slow path. Convert from f32 to s16. */ + { + float pTempF32[4096]; + drmp3_uint64 totalPCMFramesRead = 0; + + while (totalPCMFramesRead < framesToRead) { + drmp3_uint64 framesJustRead; + drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempF32) / pMP3->channels; + if (framesToReadNow > framesRemaining) { + framesToReadNow = framesRemaining; + } + + framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32); + if (framesJustRead == 0) { + break; + } + + 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 drmp3_reset(drmp3* pMP3) +{ + DRMP3_ASSERT(pMP3 != NULL); + + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = 0; + pMP3->currentPCMFrame = 0; + pMP3->dataSize = 0; + pMP3->atEnd = DRMP3_FALSE; + drmp3dec_init(&pMP3->decoder); +} + +static drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3) +{ + DRMP3_ASSERT(pMP3 != NULL); + DRMP3_ASSERT(pMP3->onSeek != NULL); + + /* Seek to the start of the stream to begin with. */ + if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) { return DRMP3_FALSE; } - // Clear any cached data. - pMP3->framesConsumed = 0; - pMP3->framesRemaining = 0; - pMP3->dataSize = 0; - pMP3->atEnd = DRMP3_FALSE; + /* Clear any cached data. */ + drmp3_reset(pMP3); + return DRMP3_TRUE; +} - // TODO: Optimize. - // - // This is inefficient. We simply read frames from the start of the stream. - drmp3_uint64 framesRead = drmp3_read_f32(pMP3, frameIndex, NULL); - if (framesRead != frameIndex) { + +static drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset) +{ + drmp3_uint64 framesRead; + + /* + Just using a dumb read-and-discard for now. What would be nice is to parse only the header of the MP3 frame, and then skip over leading + frames without spending the time doing a full decode. I cannot see an easy way to do this in minimp3, however, so it may involve some + kind of manual processing. + */ +#if defined(DR_MP3_FLOAT_OUTPUT) + framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); +#else + framesRead = drmp3_read_pcm_frames_s16(pMP3, frameOffset, NULL); +#endif + if (framesRead != frameOffset) { return DRMP3_FALSE; } return DRMP3_TRUE; } - - -float* drmp3__full_decode_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +static drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 frameIndex) { - drmp3_assert(pMP3 != NULL); + DRMP3_ASSERT(pMP3 != NULL); + if (frameIndex == pMP3->currentPCMFrame) { + return DRMP3_TRUE; + } + + /* + If we're moving foward we just read from where we're at. Otherwise we need to move back to the start of + the stream and read from the beginning. + */ + if (frameIndex < pMP3->currentPCMFrame) { + /* Moving backward. Move to the start of the stream and then move forward. */ + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; + } + } + + DRMP3_ASSERT(frameIndex >= pMP3->currentPCMFrame); + return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame)); +} + +static drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex) +{ + drmp3_uint32 iSeekPoint; + + DRMP3_ASSERT(pSeekPointIndex != NULL); + + *pSeekPointIndex = 0; + + if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) { + return DRMP3_FALSE; + } + + /* Linear search for simplicity to begin with while I'm getting this thing working. Once it's all working change this to a binary search. */ + for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) { + if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) { + break; /* Found it. */ + } + + *pSeekPointIndex = iSeekPoint; + } + + return DRMP3_TRUE; +} + +static drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex) +{ + 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 there is no prior seekpoint it means the target PCM frame comes before the first seek point. Just assume a seekpoint at the start of the file in this case. */ + if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) { + seekPoint = pMP3->pSeekPoints[priorSeekPointIndex]; + } else { + seekPoint.seekPosInBytes = 0; + seekPoint.pcmFrameIndex = 0; + seekPoint.mp3FramesToDiscard = 0; + seekPoint.pcmFramesToDiscard = 0; + } + + /* First thing to do is seek to the first byte of the relevant MP3 frame. */ + if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) { + return DRMP3_FALSE; /* Failed to seek. */ + } + + /* Clear any cached data. */ + drmp3_reset(pMP3); + + /* Whole MP3 frames need to be discarded first. */ + for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) { + drmp3_uint32 pcmFramesRead; + drmp3d_sample_t* pPCMFrames; + + /* Pass in non-null for the last frame because we want to ensure the sample rate converter is preloaded correctly. */ + pPCMFrames = NULL; + if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { + pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames; + } + + /* We first need to decode the next frame. */ + pcmFramesRead = drmp3_decode_next_frame_ex(pMP3, pPCMFrames); + if (pcmFramesRead == 0) { + return DRMP3_FALSE; + } + } + + /* We seeked to an MP3 frame in the raw stream so we need to make sure the current PCM frame is set correctly. */ + pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard; + + /* + Now at this point we can follow the same process as the brute force technique where we just skip over unnecessary MP3 frames and then + read-and-discard at least 2 whole MP3 frames. + */ + leftoverFrames = frameIndex - pMP3->currentPCMFrame; + return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames); +} + +DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex) +{ + if (pMP3 == NULL || pMP3->onSeek == NULL) { + return DRMP3_FALSE; + } + + if (frameIndex == 0) { + return drmp3_seek_to_start_of_stream(pMP3); + } + + /* Use the seek table if we have one. */ + if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) { + return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex); + } else { + return drmp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex); + } +} + +DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount) +{ + drmp3_uint64 currentPCMFrame; + drmp3_uint64 totalPCMFrameCount; + drmp3_uint64 totalMP3FrameCount; + + if (pMP3 == NULL) { + return DRMP3_FALSE; + } + + /* + The way this works is we move back to the start of the stream, iterate over each MP3 frame and calculate the frame count based + on our output sample rate, the seek back to the PCM frame we were sitting on before calling this function. + */ + + /* The stream must support seeking for this to work. */ + if (pMP3->onSeek == NULL) { + return DRMP3_FALSE; + } + + /* We'll need to seek back to where we were, so grab the PCM frame we're currently sitting on so we can restore later. */ + currentPCMFrame = pMP3->currentPCMFrame; + + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; + } + + totalPCMFrameCount = 0; + totalMP3FrameCount = 0; + + for (;;) { + drmp3_uint32 pcmFramesInCurrentMP3Frame; + + pcmFramesInCurrentMP3Frame = drmp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFramesInCurrentMP3Frame == 0) { + break; + } + + totalPCMFrameCount += pcmFramesInCurrentMP3Frame; + totalMP3FrameCount += 1; + } + + /* Finally, we need to seek back to where we were. */ + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; + } + + if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return DRMP3_FALSE; + } + + if (pMP3FrameCount != NULL) { + *pMP3FrameCount = totalMP3FrameCount; + } + if (pPCMFrameCount != NULL) { + *pPCMFrameCount = totalPCMFrameCount; + } + + return DRMP3_TRUE; +} + +DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3) +{ + drmp3_uint64 totalPCMFrameCount; + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) { + return 0; + } + + return totalPCMFrameCount; +} + +DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3) +{ + drmp3_uint64 totalMP3FrameCount; + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) { + return 0; + } + + return totalMP3FrameCount; +} + +static void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart) +{ + float srcRatio; + float pcmFrameCountOutF; + drmp3_uint32 pcmFrameCountOut; + + srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; + DRMP3_ASSERT(srcRatio > 0); + + pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio); + pcmFrameCountOut = (drmp3_uint32)pcmFrameCountOutF; + *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut; + *pRunningPCMFrameCount += pcmFrameCountOut; +} + +typedef struct +{ + drmp3_uint64 bytePos; + drmp3_uint64 pcmFrameIndex; /* <-- After sample rate conversion. */ +} drmp3__seeking_mp3_frame_info; + +DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints) +{ + drmp3_uint32 seekPointCount; + drmp3_uint64 currentPCMFrame; + drmp3_uint64 totalMP3FrameCount; + drmp3_uint64 totalPCMFrameCount; + + if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) { + return DRMP3_FALSE; /* Invalid args. */ + } + + seekPointCount = *pSeekPointCount; + if (seekPointCount == 0) { + return DRMP3_FALSE; /* The client has requested no seek points. Consider this to be invalid arguments since the client has probably not intended this. */ + } + + /* We'll need to seek back to the current sample after calculating the seekpoints so we need to go ahead and grab the current location at the top. */ + currentPCMFrame = pMP3->currentPCMFrame; + + /* We never do more than the total number of MP3 frames and we limit it to 32-bits. */ + if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) { + return DRMP3_FALSE; + } + + /* If there's less than DRMP3_SEEK_LEADING_MP3_FRAMES+1 frames we just report 1 seek point which will be the very start of the stream. */ + 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 { + drmp3_uint64 pcmFramesBetweenSeekPoints; + drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1]; + drmp3_uint64 runningPCMFrameCount = 0; + float runningPCMFrameCountFractionalPart = 0; + drmp3_uint64 nextTargetPCMFrame; + drmp3_uint32 iMP3Frame; + drmp3_uint32 iSeekPoint; + + if (seekPointCount > totalMP3FrameCount-1) { + seekPointCount = (drmp3_uint32)totalMP3FrameCount-1; + } + + pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1); + + /* + Here is where we actually calculate the seek points. We need to start by moving the start of the stream. We then enumerate over each + MP3 frame. + */ + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; + } + + /* + We need to cache the byte positions of the previous MP3 frames. As a new MP3 frame is iterated, we cycle the byte positions in this + array. The value in the first item in this array is the byte position that will be reported in the next seek point. + */ + + /* We need to initialize the array of MP3 byte positions for the leading MP3 frames. */ + for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) { + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + + /* The byte position of the next frame will be the stream's cursor position, minus whatever is sitting in the buffer. */ + DRMP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize); + mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; + mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; + + /* We need to get information about this frame so we can know how many samples it contained. */ + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFramesInCurrentMP3FrameIn == 0) { + return DRMP3_FALSE; /* This should never happen. */ + } + + drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + } + + /* + At this point we will have extracted the byte positions of the leading MP3 frames. We can now start iterating over each seek point and + calculate them. + */ + nextTargetPCMFrame = 0; + for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) { + nextTargetPCMFrame += pcmFramesBetweenSeekPoints; + + for (;;) { + if (nextTargetPCMFrame < runningPCMFrameCount) { + /* The next seek point is in the current MP3 frame. */ + pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; + pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; + 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; + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + + /* + The next seek point is not in the current MP3 frame, so continue on to the next one. The first thing to do is cycle the cached + MP3 frame info. + */ + for (i = 0; i < DRMP3_COUNTOF(mp3FrameInfo)-1; ++i) { + mp3FrameInfo[i] = mp3FrameInfo[i+1]; + } + + /* Cache previous MP3 frame info. */ + mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; + mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; + + /* + Go to the next MP3 frame. This shouldn't ever fail, but just in case it does we just set the seek point and break. If it happens, it + should only ever do it for the last seek point. + */ + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFramesInCurrentMP3FrameIn == 0) { + pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; + pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; + pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES; + pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); + break; + } + + drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + } + } + } + + /* Finally, we need to seek back to where we were. */ + if (!drmp3_seek_to_start_of_stream(pMP3)) { + return DRMP3_FALSE; + } + if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return DRMP3_FALSE; + } + } + + *pSeekPointCount = seekPointCount; + return DRMP3_TRUE; +} + +DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints) +{ + if (pMP3 == NULL) { + return DRMP3_FALSE; + } + + if (seekPointCount == 0 || pSeekPoints == NULL) { + /* Unbinding. */ + pMP3->seekPointCount = 0; + pMP3->pSeekPoints = NULL; + } else { + /* Binding. */ + pMP3->seekPointCount = seekPointCount; + pMP3->pSeekPoints = pSeekPoints; + } + + return DRMP3_TRUE; +} + + +static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ drmp3_uint64 totalFramesRead = 0; drmp3_uint64 framesCapacity = 0; float* pFrames = NULL; - float temp[4096]; + + DRMP3_ASSERT(pMP3 != NULL); + for (;;) { - drmp3_uint64 framesToReadRightNow = drmp3_countof(temp) / pMP3->channels; - drmp3_uint64 framesJustRead = drmp3_read_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; } - // Reallocate the output buffer if there's not enough room. + /* Reallocate the output buffer if there's not enough room. */ if (framesCapacity < totalFramesRead + framesJustRead) { - framesCapacity *= 2; - if (framesCapacity < totalFramesRead + framesJustRead) { - framesCapacity = totalFramesRead + framesJustRead; + drmp3_uint64 oldFramesBufferSize; + drmp3_uint64 newFramesBufferSize; + drmp3_uint64 newFramesCap; + float* pNewFrames; + + newFramesCap = framesCapacity * 2; + if (newFramesCap < totalFramesRead + framesJustRead) { + newFramesCap = totalFramesRead + framesJustRead; } - drmp3_uint64 newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float); - if (newFramesBufferSize > SIZE_MAX) { + oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float); + newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float); + if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { break; } - float* pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize); + pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); if (pNewFrames == NULL) { - drmp3_free(pFrames); + drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); break; } pFrames = pNewFrames; + framesCapacity = newFramesCap; } - drmp3_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 the number of frames we asked for is less that what we actually read it means we've reached the end. + /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */ if (framesJustRead != framesToReadRightNow) { break; } } if (pConfig != NULL) { - pConfig->outputChannels = pMP3->channels; - pConfig->outputSampleRate = pMP3->sampleRate; + pConfig->channels = pMP3->channels; + pConfig->sampleRate = pMP3->sampleRate; } drmp3_uninit(pMP3); - if (pTotalFrameCount) *pTotalFrameCount = totalFramesRead; + if (pTotalFrameCount) { + *pTotalFrameCount = totalFramesRead; + } + return pFrames; } -float* drmp3_open_and_decode_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ + drmp3_uint64 totalFramesRead = 0; + drmp3_uint64 framesCapacity = 0; + drmp3_int16* pFrames = NULL; + drmp3_int16 temp[4096]; + + DRMP3_ASSERT(pMP3 != NULL); + + for (;;) { + drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels; + drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp); + if (framesJustRead == 0) { + break; + } + + /* Reallocate the output buffer if there's not enough room. */ + if (framesCapacity < totalFramesRead + framesJustRead) { + 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(drmp3_int16); + newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16); + if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) { + break; + } + + pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); + if (pNewFrames == NULL) { + drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks); + break; + } + + pFrames = pNewFrames; + framesCapacity = newFramesCap; + } + + DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16))); + totalFramesRead += framesJustRead; + + /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */ + if (framesJustRead != framesToReadRightNow) { + break; + } + } + + if (pConfig != NULL) { + pConfig->channels = pMP3->channels; + pConfig->sampleRate = pMP3->sampleRate; + } + + drmp3_uninit(pMP3); + + if (pTotalFrameCount) { + *pTotalFrameCount = totalFramesRead; + } + + return pFrames; +} + + +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 mp3; - if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pConfig)) { + if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return drmp3__full_decode_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } -float* drmp3_open_and_decode_memory_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +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 mp3; - if (!drmp3_init_memory(&mp3, pData, dataSize, pConfig)) { + if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return drmp3__full_decode_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); } + +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 mp3; + if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); +} + +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) +{ + drmp3 mp3; + if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); +} + + #ifndef DR_MP3_NO_STDIO -float* drmp3_open_and_decode_file_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +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 mp3; - if (!drmp3_init_file(&mp3, filePath, pConfig)) { + if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) { return NULL; } - return drmp3__full_decode_and_close_f32(&mp3, pConfig, pTotalFrameCount); + return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); +} + +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) +{ + drmp3 mp3; + if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) { + return NULL; + } + + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); } #endif -void drmp3_free(void* p) +DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks) { - DRMP3_FREE(p); + if (pAllocationCallbacks != NULL) { + return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks); + } else { + return drmp3__malloc_default(sz, NULL); + } } -#endif /*DR_MP3_IMPLEMENTATION*/ - - -// DIFFERENCES BETWEEN minimp3 AND dr_mp3 -// ====================================== -// - First, keep in mind that minimp3 (https://github.com/lieff/minimp3) is where all the real work was done. All of the -// code relating to the actual decoding remains mostly unmodified, apart from some namespacing changes. -// - dr_mp3 adds a pulling style API which allows you to deliver raw data via callbacks. So, rather than pushing data -// to the decoder, the decoder _pulls_ data from your callbacks. -// - In addition to callbacks, a decoder can be initialized from a block of memory and a file. -// - The dr_mp3 pull API reads PCM frames rather than whole MP3 frames. -// - dr_mp3 adds convenience APIs for opening and decoding entire files in one go. -// - dr_mp3 is fully namespaced, including the implementation section, which is more suitable when compiling projects -// as a single translation unit (aka unity builds). At the time of writing this, a unity build is not possible when -// using minimp3 in conjunction with stb_vorbis. dr_mp3 addresses this. - - -// REVISION HISTORY -// =============== -// -// v0.2.3 - 2018-04-29 -// - Fix TCC build. -// -// v0.2.2 - 2018-04-28 -// - Fix bug when opening a decoder from memory. -// -// v0.2.1 - 2018-04-27 -// - Efficiency improvements when the decoder reaches the end of the stream. -// -// v0.2 - 2018-04-21 -// - Bring up to date with minimp3. -// - Start using major.minor.revision versioning. -// -// v0.1d - 2018-03-30 -// - Bring up to date with minimp3. -// -// v0.1c - 2018-03-11 -// - Fix C++ build error. -// -// v0.1b - 2018-03-07 -// - Bring up to date with minimp3. -// -// v0.1a - 2018-02-28 -// - Fix compilation error on GCC/Clang. -// - Fix some warnings. -// -// v0.1 - 2018-02-xx -// - Initial versioned release. +DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drmp3__free_from_callbacks(p, pAllocationCallbacks); + } else { + drmp3__free_default(p, NULL); + } +} +#endif /* dr_mp3_c */ +#endif /*DR_MP3_IMPLEMENTATION*/ /* +DIFFERENCES BETWEEN minimp3 AND dr_mp3 +====================================== +- First, keep in mind that minimp3 (https://github.com/lieff/minimp3) is where all the real work was done. All of the + code relating to the actual decoding remains mostly unmodified, apart from some namespacing changes. +- dr_mp3 adds a pulling style API which allows you to deliver raw data via callbacks. So, rather than pushing data + to the decoder, the decoder _pulls_ data from your callbacks. +- In addition to callbacks, a decoder can be initialized from a block of memory and a file. +- The dr_mp3 pull API reads PCM frames rather than whole MP3 frames. +- dr_mp3 adds convenience APIs for opening and decoding entire files in one go. +- dr_mp3 is fully namespaced, including the implementation section, which is more suitable when compiling projects + as a single translation unit (aka unity builds). At the time of writing this, a unity build is not possible when + using minimp3 in conjunction with stb_vorbis. dr_mp3 addresses this. +*/ + +/* +RELEASE NOTES - v0.5.0 +======================= +Version 0.5.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 DRMP3_MALLOC, DRMP3_REALLOC and DRMP3_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 drmp3_allocation_callbacks object to drmp3_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); + } + + ... + + drmp3_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drmp3_init_file(&mp3, "my_file.mp3", NULL, &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_mp3 to use defaults which is the same as DRMP3_MALLOC, +DRMP3_REALLOC and DRMP3_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drmp3 object now takes this extra parameter. These include the following: + + drmp3_init() + drmp3_init_file() + drmp3_init_memory() + drmp3_open_and_read_pcm_frames_f32() + drmp3_open_and_read_pcm_frames_s16() + drmp3_open_memory_and_read_pcm_frames_f32() + drmp3_open_memory_and_read_pcm_frames_s16() + drmp3_open_file_and_read_pcm_frames_f32() + drmp3_open_file_and_read_pcm_frames_s16() + +Renamed APIs +------------ +The following APIs have been renamed for consistency with other dr_* libraries and to make it clear that they return PCM frame +counts rather than sample counts. + + drmp3_open_and_read_f32() -> drmp3_open_and_read_pcm_frames_f32() + drmp3_open_and_read_s16() -> drmp3_open_and_read_pcm_frames_s16() + drmp3_open_memory_and_read_f32() -> drmp3_open_memory_and_read_pcm_frames_f32() + drmp3_open_memory_and_read_s16() -> drmp3_open_memory_and_read_pcm_frames_s16() + drmp3_open_file_and_read_f32() -> drmp3_open_file_and_read_pcm_frames_f32() + drmp3_open_file_and_read_s16() -> drmp3_open_file_and_read_pcm_frames_s16() +*/ + +/* +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. + +v0.6.26 - 2021-01-31 + - Bring up to date with minimp3. + +v0.6.25 - 2020-12-26 + - Remove DRMP3_DEFAULT_CHANNELS and DRMP3_DEFAULT_SAMPLE_RATE which are leftovers from some removed APIs. + +v0.6.24 - 2020-12-07 + - Fix a typo in version date for 0.6.23. + +v0.6.23 - 2020-12-03 + - Fix an error where a file can be closed twice when initialization of the decoder fails. + +v0.6.22 - 2020-12-02 + - Fix an error where it's possible for a file handle to be left open when initialization of the decoder fails. + +v0.6.21 - 2020-11-28 + - Bring up to date with minimp3. + +v0.6.20 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.6.19 - 2020-11-13 + - Minor code clean up. + +v0.6.18 - 2020-11-01 + - Improve compiler support for older versions of GCC. + +v0.6.17 - 2020-09-28 + - Bring up to date with minimp3. + +v0.6.16 - 2020-08-02 + - Simplify sized types. + +v0.6.15 - 2020-07-25 + - Fix a compilation warning. + +v0.6.14 - 2020-07-23 + - Fix undefined behaviour with memmove(). + +v0.6.13 - 2020-07-06 + - Fix a bug when converting from s16 to f32 in drmp3_read_pcm_frames_f32(). + +v0.6.12 - 2020-06-23 + - Add include guard for the implementation section. + +v0.6.11 - 2020-05-26 + - Fix use of uninitialized variable error. + +v0.6.10 - 2020-05-16 + - Add compile-time and run-time version querying. + - DRMP3_VERSION_MINOR + - DRMP3_VERSION_MAJOR + - DRMP3_VERSION_REVISION + - DRMP3_VERSION_STRING + - drmp3_version() + - drmp3_version_string() + +v0.6.9 - 2020-04-30 + - Change the `pcm` parameter of drmp3dec_decode_frame() to a `const drmp3_uint8*` for consistency with internal APIs. + +v0.6.8 - 2020-04-26 + - Optimizations to decoding when initializing from memory. + +v0.6.7 - 2020-04-25 + - Fix a compilation error with DR_MP3_NO_STDIO + - Optimization to decoding by reducing some data movement. + +v0.6.6 - 2020-04-23 + - Fix a minor bug with the running PCM frame counter. + +v0.6.5 - 2020-04-19 + - Fix compilation error on ARM builds. + +v0.6.4 - 2020-04-19 + - Bring up to date with changes to minimp3. + +v0.6.3 - 2020-04-13 + - Fix some pedantic warnings. + +v0.6.2 - 2020-04-10 + - Fix a crash in drmp3_open_*_and_read_pcm_frames_*() if the output config object is NULL. + +v0.6.1 - 2020-04-05 + - Fix warnings. + +v0.6.0 - 2020-04-04 + - API CHANGE: Remove the pConfig parameter from the following APIs: + - drmp3_init() + - drmp3_init_memory() + - drmp3_init_file() + - Add drmp3_init_file_w() for opening a file from a wchar_t encoded path. + +v0.5.6 - 2020-02-12 + - Bring up to date with minimp3. + +v0.5.5 - 2020-01-29 + - Fix a memory allocation bug in high level s16 decoding APIs. + +v0.5.4 - 2019-12-02 + - Fix a possible null pointer dereference when using custom memory allocators for realloc(). + +v0.5.3 - 2019-11-14 + - Fix typos in documentation. + +v0.5.2 - 2019-11-02 + - Bring up to date with minimp3. + +v0.5.1 - 2019-10-08 + - Fix a warning with GCC. + +v0.5.0 - 2019-10-07 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drmp3_init() + - drmp3_init_file() + - drmp3_init_memory() + - drmp3_open_and_read_pcm_frames_f32() + - drmp3_open_and_read_pcm_frames_s16() + - drmp3_open_memory_and_read_pcm_frames_f32() + - drmp3_open_memory_and_read_pcm_frames_s16() + - drmp3_open_file_and_read_pcm_frames_f32() + - drmp3_open_file_and_read_pcm_frames_s16() + - API CHANGE: Renamed the following APIs: + - drmp3_open_and_read_f32() -> drmp3_open_and_read_pcm_frames_f32() + - drmp3_open_and_read_s16() -> drmp3_open_and_read_pcm_frames_s16() + - drmp3_open_memory_and_read_f32() -> drmp3_open_memory_and_read_pcm_frames_f32() + - drmp3_open_memory_and_read_s16() -> drmp3_open_memory_and_read_pcm_frames_s16() + - drmp3_open_file_and_read_f32() -> drmp3_open_file_and_read_pcm_frames_f32() + - drmp3_open_file_and_read_s16() -> drmp3_open_file_and_read_pcm_frames_s16() + +v0.4.7 - 2019-07-28 + - Fix a compiler error. + +v0.4.6 - 2019-06-14 + - Fix a compiler error. + +v0.4.5 - 2019-06-06 + - Bring up to date with minimp3. + +v0.4.4 - 2019-05-06 + - Fixes to the VC6 build. + +v0.4.3 - 2019-05-05 + - Use the channel count and/or sample rate of the first MP3 frame instead of DRMP3_DEFAULT_CHANNELS and + DRMP3_DEFAULT_SAMPLE_RATE when they are set to 0. To use the old behaviour, just set the relevant property to + DRMP3_DEFAULT_CHANNELS or DRMP3_DEFAULT_SAMPLE_RATE. + - Add s16 reading APIs + - drmp3_read_pcm_frames_s16 + - drmp3_open_memory_and_read_pcm_frames_s16 + - drmp3_open_and_read_pcm_frames_s16 + - drmp3_open_file_and_read_pcm_frames_s16 + - Add drmp3_get_mp3_and_pcm_frame_count() to the public header section. + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.4.2 - 2019-02-21 + - Fix a warning. + +v0.4.1 - 2018-12-30 + - Fix a warning. + +v0.4.0 - 2018-12-16 + - API CHANGE: Rename some APIs: + - drmp3_read_f32 -> to drmp3_read_pcm_frames_f32 + - drmp3_seek_to_frame -> drmp3_seek_to_pcm_frame + - drmp3_open_and_decode_f32 -> drmp3_open_and_read_pcm_frames_f32 + - drmp3_open_and_decode_memory_f32 -> drmp3_open_memory_and_read_pcm_frames_f32 + - drmp3_open_and_decode_file_f32 -> drmp3_open_file_and_read_pcm_frames_f32 + - Add drmp3_get_pcm_frame_count(). + - Add drmp3_get_mp3_frame_count(). + - Improve seeking performance. + +v0.3.2 - 2018-09-11 + - Fix a couple of memory leaks. + - Bring up to date with minimp3. + +v0.3.1 - 2018-08-25 + - Fix C++ build. + +v0.3.0 - 2018-08-25 + - Bring up to date with minimp3. This has a minor API change: the "pcm" parameter of drmp3dec_decode_frame() has + been changed from short* to void* because it can now output both s16 and f32 samples, depending on whether or + not the DR_MP3_FLOAT_OUTPUT option is set. + +v0.2.11 - 2018-08-08 + - Fix a bug where the last part of a file is not read. + +v0.2.10 - 2018-08-07 + - Improve 64-bit detection. + +v0.2.9 - 2018-08-05 + - Fix C++ build on older versions of GCC. + - Bring up to date with minimp3. + +v0.2.8 - 2018-08-02 + - Fix compilation errors with older versions of GCC. + +v0.2.7 - 2018-07-13 + - Bring up to date with minimp3. + +v0.2.6 - 2018-07-12 + - Bring up to date with minimp3. + +v0.2.5 - 2018-06-22 + - Bring up to date with minimp3. + +v0.2.4 - 2018-05-12 + - Bring up to date with minimp3. + +v0.2.3 - 2018-04-29 + - Fix TCC build. + +v0.2.2 - 2018-04-28 + - Fix bug when opening a decoder from memory. + +v0.2.1 - 2018-04-27 + - Efficiency improvements when the decoder reaches the end of the stream. + +v0.2 - 2018-04-21 + - Bring up to date with minimp3. + - Start using major.minor.revision versioning. + +v0.1d - 2018-03-30 + - Bring up to date with minimp3. + +v0.1c - 2018-03-11 + - Fix C++ build error. + +v0.1b - 2018-03-07 + - Bring up to date with minimp3. + +v0.1a - 2018-02-28 + - Fix compilation error on GCC/Clang. + - Fix some warnings. + +v0.1 - 2018-02-xx + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - 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. +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. +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. +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. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2023 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 +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. + +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/dr_wav.h b/raylib/external/dr_wav.h index 536df8f..a8207ab 100644 --- a/raylib/external/dr_wav.h +++ b/raylib/external/dr_wav.h @@ -1,151 +1,283 @@ -// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. -// dr_wav - v0.7a - 2017-11-17 -// -// David Reid - mackron@gmail.com +/* +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 -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_WAV_IMPLEMENTATION -// #include "dr_wav.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. Do something -// like the following to read audio data: -// -// drwav wav; -// if (!drwav_init_file(&wav, "my_song.wav")) { -// // Error opening WAV file. -// } -// -// drwav_int32* pDecodedInterleavedSamples = malloc(wav.totalSampleCount * sizeof(drwav_int32)); -// size_t numberOfSamplesActuallyDecoded = drwav_read_s32(&wav, wav.totalSampleCount, pDecodedInterleavedSamples); -// -// ... -// -// drwav_uninit(&wav); -// -// You can also use drwav_open() to allocate and initialize the loader for you: -// -// drwav* pWav = drwav_open_file("my_song.wav"); -// if (pWav == NULL) { -// // Error opening WAV file. -// } -// -// ... -// -// drwav_close(pWav); -// -// If you just want to quickly open and read the audio data in a single operation you can do something like this: -// -// unsigned int channels; -// unsigned int sampleRate; -// drwav_uint64 totalSampleCount; -// float* pSampleData = drwav_open_and_read_file_s32("my_song.wav", &channels, &sampleRate, &totalSampleCount); -// if (pSampleData == NULL) { -// // Error opening and reading WAV file. -// } -// -// ... -// -// drwav_free(pSampleData); -// -// The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in -// this case), but you can still output the audio data in it's internal format (see notes below for supported formats): -// -// size_t samplesRead = drwav_read(&wav, wav.totalSampleCount, pDecodedInterleavedSamples); -// -// You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for -// a particular data format: -// -// size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); -// -// -// dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work -// without any manual intervention. -// -// -// dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at -// drwav_open_write(), drwav_open_file_write(), etc. Use drwav_write() to write samples, or drwav_write_raw() to write -// raw data in the "data" chunk. -// -// drwav_data_format format; -// format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. -// format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. -// format.channels = 2; -// format.sampleRate = 44100; -// format.bitsPerSample = 16; -// drwav* pWav = drwav_open_file_write("data/recording.wav", &format); -// -// ... -// -// drwav_uint64 samplesWritten = drwav_write(pWav, sampleCount, pSamples); -// -// -// -// OPTIONS -// #define these options before including this file. -// -// #define DR_WAV_NO_CONVERSION_API -// Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32(). -// -// #define DR_WAV_NO_STDIO -// Disables drwav_open_file(), drwav_open_file_write(), etc. -// -// -// -// QUICK NOTES -// - Samples are always interleaved. -// - The default read function does not do any data conversion. Use drwav_read_f32() to read and convert audio data -// to IEEE 32-bit floating point samples, drwav_read_s32() to read samples as signed 32-bit PCM and drwav_read_s16() -// to read samples as signed 16-bit PCM. 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. +David Reid - mackron@gmail.com +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +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" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data: + + ```c + drwav wav; + if (!drwav_init_file(&wav, "my_song.wav", NULL)) { + // Error opening WAV file. + } + + drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); + size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + + ... + + drwav_uninit(&wav); + ``` + +If you just want to quickly open and read the audio data in a single operation you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drwav_uint64 totalPCMFrameCount; + float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Error opening and reading WAV file. + } + + ... + + drwav_free(pSampleData, NULL); + ``` + +The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the +audio data in its internal format (see notes below for supported formats): + + ```c + size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + ``` + +You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format: + + ```c + size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); + ``` + +dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`, +`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk. + + ```c + drwav_data_format format; + format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. + format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. + format.channels = 2; + format.sampleRate = 44100; + format.bitsPerSample = 16; + drwav_init_file_write(&wav, "data/recording.wav", &format, NULL); + + ... + + 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. + + +Build Options +============= +#define these options before including this file. + +#define DR_WAV_NO_CONVERSION_API + Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`. + +#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. +- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. +*/ #ifndef dr_wav_h #define dr_wav_h -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -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; -typedef signed __int64 drwav_int64; -typedef unsigned __int64 drwav_uint64; -#else -#include -typedef int8_t drwav_int8; -typedef uint8_t drwav_uint8; -typedef int16_t drwav_int16; -typedef uint16_t drwav_uint16; -typedef int32_t drwav_int32; -typedef uint32_t drwav_uint32; -typedef int64_t drwav_int64; -typedef uint64_t drwav_uint64; -#endif -typedef drwav_uint8 drwav_bool8; -typedef drwav_uint32 drwav_bool32; -#define DRWAV_TRUE 1 -#define DRWAV_FALSE 0 - #ifdef __cplusplus extern "C" { #endif -// Common data formats. +#define DRWAV_STRINGIFY(x) #x +#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_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) + +#include /* For size_t. */ + +/* 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__) + 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(_M_ARM64) || 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 +/* End Sized Types */ + +/* Decorations */ +#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 +/* End Decorations */ + +/* Result Codes */ +typedef drwav_int32 drwav_result; +#define DRWAV_SUCCESS 0 +#define DRWAV_ERROR -1 /* A generic error. */ +#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 +/* End Result Codes */ + +/* Common data formats. */ #define DR_WAVE_FORMAT_PCM 0x1 #define DR_WAVE_FORMAT_ADPCM 0x2 #define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 @@ -154,6 +286,23 @@ extern "C" { #define DR_WAVE_FORMAT_DVI_ADPCM 0x11 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE +/* 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, @@ -163,45 +312,142 @@ typedef enum typedef enum { drwav_container_riff, - drwav_container_w64 + drwav_container_rifx, + drwav_container_w64, + drwav_container_rf64, + drwav_container_aiff } drwav_container; -// Callback for when data is read. Return value is the number of bytes actually read. -// -// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. -// pBufferOut [out] The output buffer. -// bytesToRead [in] The number of bytes to read. -// -// Returns the number of bytes actually read. -// -// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until -// either the entire bytesToRead is filled or you have reached the end of the stream. +typedef struct +{ + union + { + drwav_uint8 fourcc[4]; + drwav_uint8 guid[16]; + } id; + + /* The size in bytes of the chunk. */ + drwav_uint64 sizeInBytes; + + /* + RIFF = 2 byte alignment. + W64 = 8 byte alignment. + */ + unsigned int paddingSize; +} drwav_chunk_header; + +typedef struct +{ + /* + The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications + that require support for data formats not natively supported by dr_wav. + */ + drwav_uint16 formatTag; + + /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */ + drwav_uint16 channels; + + /* The sample rate. Usually set to something like 44100. */ + drwav_uint32 sampleRate; + + /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */ + drwav_uint32 avgBytesPerSec; + + /* Block align. This is equal to the number of channels * bytes per sample. */ + drwav_uint16 blockAlign; + + /* Bits per sample. */ + drwav_uint16 bitsPerSample; + + /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */ + drwav_uint16 extendedSize; + + /* + The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, + is always rounded up to the nearest multiple of 8. This variable contains information about exactly how + many bits are valid per sample. Mainly used for informational purposes. + */ + drwav_uint16 validBitsPerSample; + + /* The channel mask. Not used at the moment. */ + drwav_uint32 channelMask; + + /* The sub-format, exactly as specified by the wave file. */ + drwav_uint8 subFormat[16]; +} drwav_fmt; + +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT); + + +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drwav_init() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +either the entire bytesToRead is filled or you have reached the end of the stream. +*/ typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -// Callback for when data is written. Returns value is the number of bytes actually written. -// -// pUserData [in] The user data that was passed to drwav_init_write(), drwav_open_write() and family. -// pData [out] A pointer to the data to write. -// bytesToWrite [in] The number of bytes to write. -// -// Returns the number of bytes actually written. -// -// If the return value differs from bytesToWrite, it indicates an error. +/* +Callback for when data is written. Returns value is the number of bytes actually written. + +pUserData [in] The user data that was passed to drwav_init_write() and family. +pData [out] A pointer to the data to write. +bytesToWrite [in] The number of bytes to write. + +Returns the number of bytes actually written. + +If the return value differs from bytesToWrite, it indicates an error. +*/ typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); -// Callback for when data needs to be seeked. -// -// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. -// offset [in] The number of bytes to move, relative to the origin. Will never be negative. -// origin [in] The origin of the seek - the current position or the start of the stream. -// -// Returns whether or not the seek was successful. -// -// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which -// will be either drwav_seek_origin_start or drwav_seek_origin_current. +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drwav_init() and family. +offset [in] The number of bytes to move, relative to the origin. Will never be negative. +origin [in] The origin of the seek - the current position or the start of the stream. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or +drwav_seek_origin_current. +*/ typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); -// Structure for internal use. Only used for loaders opened with drwav_open_memory(). +/* +Callback for when drwav_init_ex() finds a chunk. + +pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family. +onRead [in] A pointer to the function to call when reading. +onSeek [in] A pointer to the function to call when seeking. +pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family. +pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. +container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF. +pFMT [in] A pointer to the object containing the contents of the "fmt" chunk. + +Returns the number of bytes read + seeked. + +To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must +be the total number of bytes you have read _plus_ seeked. + +Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should +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. + +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); + + +/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */ typedef struct { const drwav_uint8* data; @@ -209,7 +455,7 @@ typedef struct size_t currentReadPos; } drwav__memory_stream; -// Structure for internal use. Only used for writers opened with drwav_open_memory_write(). +/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */ typedef struct { void** ppData; @@ -221,465 +467,890 @@ typedef struct typedef struct { - drwav_container container; // RIFF, W64. - drwav_uint32 format; // DR_WAVE_FORMAT_* + drwav_container container; /* RIFF, W64. */ + drwav_uint32 format; /* DR_WAVE_FORMAT_* */ drwav_uint32 channels; drwav_uint32 sampleRate; drwav_uint32 bitsPerSample; } drwav_data_format; -typedef struct +typedef enum { - // The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications - // that require support for data formats not natively supported by dr_wav. - drwav_uint16 formatTag; + drwav_metadata_type_none = 0, - // The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. - drwav_uint16 channels; + /* + 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, - // The sample rate. Usually set to something like 44100. - drwav_uint32 sampleRate; + /* 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, - // Average bytes per second. You probably don't need this, but it's left here for informational purposes. - drwav_uint32 avgBytesPerSec; + /* + 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. - // Block align. This is equal to the number of channels * bytes per sample. - drwav_uint16 blockAlign; + 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, - // Bit's per sample. - drwav_uint16 bitsPerSample; + 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, - // The size of the extended data. Only used internally for validation, but left here for informational purposes. - drwav_uint16 extendedSize; + /* 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, - // The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, - // is always rounded up to the nearest multiple of 8. This variable contains information about exactly how - // many bits a valid per sample. Mainly used for informational purposes. - drwav_uint16 validBitsPerSample; + drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label + | drwav_metadata_type_list_note + | drwav_metadata_type_list_labelled_cue_region, - // The channel mask. Not used at the moment. - drwav_uint32 channelMask; + drwav_metadata_type_all = -2, /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/ + drwav_metadata_type_all_including_unknown = -1 /*0xFFFFFFFF,*/ +} drwav_metadata_type; - // The sub-format, exactly as specified by the wave file. - drwav_uint8 subFormat[16]; -} drwav_fmt; +/* +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; typedef struct { - // A pointer to the function to call when more data is needed. + /* 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 playCount; +} drwav_smpl_loop; + +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 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_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. */ drwav_read_proc onRead; - // A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. + /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */ drwav_write_proc onWrite; - // A pointer to the function to call when the wav file needs to be seeked. + /* A pointer to the function to call when the wav file needs to be seeked. */ drwav_seek_proc onSeek; - // The user data to pass to callbacks. + /* The user data to pass to callbacks. */ void* pUserData; + /* Allocation callbacks. */ + drwav_allocation_callbacks allocationCallbacks; - // Whether or not the WAV file is formatted as a standard RIFF file or W64. + + /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */ drwav_container container; - // Structure containing format information exactly as specified by the wav file. + /* Structure containing format information exactly as specified by the wav file. */ drwav_fmt fmt; - // The sample rate. Will be set to something like 44100. + /* The sample rate. Will be set to something like 44100. */ drwav_uint32 sampleRate; - // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. + /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */ drwav_uint16 channels; - // The bits per sample. Will be set to somthing like 16, 24, etc. + /* The bits per sample. Will be set to something like 16, 24, etc. */ drwav_uint16 bitsPerSample; - // The number of bytes per sample. - drwav_uint16 bytesPerSample; - - // Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). + /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */ drwav_uint16 translatedFormatTag; - // The total number of samples making up the audio data. Use * to calculate - // the required size of a buffer to hold the entire audio data. - drwav_uint64 totalSampleCount; + /* The total number of PCM frames making up the audio data. */ + drwav_uint64 totalPCMFrameCount; - // The size in bytes of the data chunk. + /* The size in bytes of the data chunk. */ drwav_uint64 dataChunkDataSize; - - // The position in the stream of the first byte of the data chunk. This is used for seeking. + + /* 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. + /* The number of bytes remaining in the data chunk. */ drwav_uint64 bytesRemaining; + /* The current read position in PCM frames. */ + drwav_uint64 readCursorInPCMFrames; - // A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory(). + + /* + Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always + set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. + */ + drwav_uint64 dataChunkDataSizeTargetWrite; + + /* Keeps track of whether or not the wav writer was initialized in sequential mode. */ + 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; + + + /* 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 iCurrentSample; // The index of the next sample that will be read by drwav_read_*(). This is used with "totalSampleCount" to ensure we don't read excess samples at the end of the last block. - } compressed; - - // Microsoft ADPCM specific data. + + /* Microsoft ADPCM specific data. */ struct { drwav_uint32 bytesRemainingInBlock; drwav_uint16 predictor[2]; drwav_int32 delta[2]; - drwav_int32 cachedSamples[4]; // Samples are stored in this cache during decoding. - drwav_uint32 cachedSampleCount; - drwav_int32 prevSamples[2][2]; // The previous 2 samples for each channel (2 channels at most). + drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */ + drwav_uint32 cachedFrameCount; + drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */ } msadpcm; - // IMA ADPCM specific data. + /* IMA ADPCM specific data. */ struct { drwav_uint32 bytesRemainingInBlock; drwav_int32 predictor[2]; drwav_int32 stepIndex[2]; - drwav_int32 cachedSamples[16]; // Samples are stored in this cache during decoding. - drwav_uint32 cachedSampleCount; + 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; -// Initializes a pre-allocated drwav object. -// -// onRead [in] The function to call when data needs to be read from the client. -// onSeek [in] The function to call when the read position of the client data needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. -// -// Returns true if successful; false otherwise. -// -// Close the loader with drwav_uninit(). -// -// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() -// to open the stream from a file or from a block of memory respectively. -// -// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate -// a drwav object on the heap and return a pointer to it. -// -// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() -drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); +/* +Initializes a pre-allocated drwav object for reading. -// 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. -// -// Returns true if successful; false otherwise. -// -// Close the writer with drwav_uninit(). -// -// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() -// to open the stream from a file or from a block of memory respectively. -// -// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate -// a drwav object on the heap and return a pointer to it. -// -// See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() -drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); +pWav [out] A pointer to the drwav object being initialized. +onRead [in] The function to call when data needs to be read from the client. +onSeek [in] The function to call when the read position of the client data needs to move. +onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. +pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. +flags [in, optional] A set of flags for controlling how things are loaded. -// Uninitializes the given drwav object. -// -// Use this only for objects initialized with drwav_init(). -void drwav_uninit(drwav* pWav); +Returns true if successful; false otherwise. + +Close the loader with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +to open the stream from a file or from a block of memory respectively. + +Possible values for flags: + DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function + to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. + +drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". + +The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt +after the function returns. + +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. + +Returns true if successful; false otherwise. + +Close the writer with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write() +to open the stream from a file or from a block of memory respectively. + +If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform +a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. + +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); + +/* +Uninitializes the given drwav object. + +Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()). +*/ +DRWAV_API drwav_result drwav_uninit(drwav* pWav); -// Opens a wav file using the given callbacks. -// -// onRead [in] The function to call when data needs to be read from the client. -// onSeek [in] The function to call when the read position of the client data needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. -// -// Returns null on error. -// -// Close the loader with drwav_close(). -// -// This is the lowest level function for opening a WAV file. You can also use drwav_open_file() and drwav_open_memory() -// to open the stream from a file or from a block of memory respectively. -// -// This is different from drwav_init() in that it will allocate the drwav object for you via DRWAV_MALLOC() before -// initializing it. -// -// See also: drwav_open_file(), drwav_open_memory(), drwav_close() -drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); +/* +Reads raw audio data. -// Opens a wav file for writing using the given callbacks. -// -// 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 null on error. -// -// Close the loader with drwav_close(). -// -// This is the lowest level function for opening a WAV file. You can also use drwav_open_file_write() and drwav_open_memory_write() -// to open the stream from a file or from a block of memory respectively. -// -// This is different from drwav_init_write() in that it will allocate the drwav object for you via DRWAV_MALLOC() before -// initializing it. -// -// See also: drwav_open_file_write(), drwav_open_memory_write(), drwav_close() -drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); +This is the lowest level function for reading audio data. It simply reads the given number of +bytes of the raw internal sample data. -// Uninitializes and deletes the the given drwav object. -// -// Use this only for objects created with drwav_open(). -void drwav_close(drwav* pWav); +Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for +reading sample data in a consistent format. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of bytes actually read. +*/ +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); + +/* +Reads up to the specified number of PCM frames from the WAV file. + +The output data will be in the file's internal format, converted to native-endian byte order. Use +drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format. + +If the return value is less than it means the end of the file has been reached or +you have requested more PCM frames than can possibly fit in the output buffer. + +This function will only work when sample data is of a fixed size and uncompressed. If you are +using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32(). + +pBufferOut can be NULL in which case a seek will be performed. +*/ +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); + +/* +Seeks to the given PCM frame. + +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); -// Reads raw audio data. -// -// This is the lowest level function for reading audio data. It simply reads the given number of -// bytes of the raw internal sample data. -// -// Consider using drwav_read_s16(), drwav_read_s32() or drwav_read_f32() for reading sample data in -// a consistent format. -// -// Returns the number of bytes actually read. -size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); +/* +Writes raw audio data. -// Reads a chunk of audio data in the native internal format. -// -// This is typically the most efficient way to retrieve audio data, but it does not do any format -// conversions which means you'll need to convert the data manually if required. -// -// If the return value is less than it means the end of the file has been reached or -// you have requested more samples than can possibly fit in the output buffer. -// -// This function will only work when sample data is of a fixed size and uncompressed. If you are -// using a compressed format consider using drwav_read_raw() or drwav_read_s16/s32/f32/etc(). -drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut); +Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +*/ +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); -// Seeks to the given sample. -// -// Returns true if successful; false otherwise. -drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample); +/* +Writes PCM frames. +Returns the number of PCM frames written. -// Writes raw audio data. -// -// Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. -size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); +Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to +little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion. +*/ +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); -// Writes audio data based on sample counts. -// -// Returns the number of samples written. -drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData); - - - -//// Convertion Utilities //// +/* Conversion Utilities */ #ifndef DR_WAV_NO_CONVERSION_API -// Reads a chunk of audio data and converts it to signed 16-bit PCM samples. -// -// Returns the number of samples actually read. -// -// If the return value is less than it means the end of the file has been reached. -drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +/* +Reads a chunk of audio data and converts it to signed 16-bit PCM samples. -// Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. -void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +pBufferOut can be NULL in which case a seek will be performed. -// Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. -void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +Returns the number of PCM frames actually read. -// Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. -void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); +If the return value is less than it means the end of the file has been reached. +*/ +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); -// Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. -void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); +/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. -void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); +/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to signed 16-bit PCM samples. -void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to signed 16-bit PCM samples. -void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. -// -// Returns the number of samples actually read. -// -// If the return value is less than it means the end of the file has been reached. -drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut); +/* +Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. -// Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. -void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +pBufferOut can be NULL in which case a seek will be performed. -// Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. -void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); +Returns the number of PCM frames actually read. -// Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. -void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +If the return value is less than it means the end of the file has been reached. +*/ +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); -// Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. -void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); +/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. -void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); +/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to IEEE 32-bit floating point samples. -void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to IEEE 32-bit floating point samples. -void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Reads a chunk of audio data and converts it to signed 32-bit PCM samples. -// -// Returns the number of samples actually read. -// -// If the return value is less than it means the end of the file has been reached. -drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut); +/* +Reads a chunk of audio data and converts it to signed 32-bit PCM samples. -// Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. -void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +pBufferOut can be NULL in which case a seek will be performed. -// Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. -void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); +Returns the number of PCM frames actually read. -// Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. -void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +If the return value is less than it means the end of the file has been reached. +*/ +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); -// Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. -void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); +/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. -void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); +/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to signed 32-bit PCM samples. -void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to signed 32-bit PCM samples. -void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); -#endif //DR_WAV_NO_CONVERSION_API +/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +#endif /* DR_WAV_NO_CONVERSION_API */ -//// High-Level Convenience Helpers //// +/* High-Level Convenience Helpers */ #ifndef DR_WAV_NO_STDIO +/* +Helper for initializing a wave file for reading using stdio. -// Helper for initializing a wave file using stdio. -// -// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. -drwav_bool32 drwav_init_file(drwav* pWav, const char* filename); +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +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_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. -// -// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. -drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat); -// Helper for opening a wave file using stdio. -// -// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. -drwav* drwav_open_file(const char* filename); +/* +Helper for initializing a wave file for writing using stdio. -// Helper for opening a wave file for writing using stdio. -// -// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. -drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat); +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +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 /* DR_WAV_NO_STDIO */ -#endif //DR_WAV_NO_STDIO +/* +Helper for initializing a loader from a pre-allocated memory buffer. -// Helper for initializing a loader from a pre-allocated memory buffer. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drwav object. -// -// The buffer should contain the contents of the entire wave file, not just the sample data. -drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize); +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drwav object. -// Helper for initializing a writer which outputs data to a memory buffer. -// -// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). -// -// The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be -// considered valid until after drwav_uninit() has been called anyway. -drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); +The buffer should contain the contents of the entire wave file, not just the sample data. +*/ +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 opening a loader from a pre-allocated memory buffer. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drwav object. -// -// The buffer should contain the contents of the entire wave file, not just the sample data. -drwav* drwav_open_memory(const void* data, size_t dataSize); +/* +Helper for initializing a writer which outputs data to a memory buffer. -// Helper for opening a writer which outputs data to a memory buffer. -// -// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). -// -// The buffer will remain allocated even after drwav_close() is called. Indeed, the buffer should not be -// considered valid until after drwav_close() has been called anyway. -drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); +dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). + +The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid +until after drwav_uninit() has been called. +*/ +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 -// Opens and reads a wav file in a single operation. -drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +/* +Opens and reads an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +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 -// Opens an decodes a wav file in a single operation. -drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); +/* +Opens and decodes an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +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 +/* +Opens and decodes an entire wav file from a block of memory in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +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 -// Opens an decodes a wav file from a block of memory in a single operation. -drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount); -#endif +/* Frees data that was allocated internally by dr_wav. */ +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks); -// Frees data that was allocated internally by dr_wav. -void drwav_free(void* pDataReturnedByOpenAndRead); +/* Converts bytes from a wav stream to a sized type of native endian. */ +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 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]); + +/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */ +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); #ifdef __cplusplus } #endif -#endif // dr_wav_h +#endif /* dr_wav_h */ -///////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -///////////////////////////////////////////////////// +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) +#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 -#ifdef DR_WAV_IMPLEMENTATION #include -#include // For memcpy(), memset() -#include // For INT_MAX +#include +#include /* For INT_MAX */ #ifndef DR_WAV_NO_STDIO #include +#ifndef DR_WAV_NO_WCHAR +#include +#endif #endif -// Standard library stuff. +/* Standard library stuff. */ #ifndef DRWAV_ASSERT #include #define DRWAV_ASSERT(expression) assert(expression) @@ -699,119 +1370,534 @@ void drwav_free(void* pDataReturnedByOpenAndRead); #ifndef DRWAV_ZERO_MEMORY #define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif +#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_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset)) -#define drwav_assert DRWAV_ASSERT -#define drwav_copy_memory DRWAV_COPY_MEMORY -#define drwav_zero_memory DRWAV_ZERO_MEMORY +#define DRWAV_MAX_SIMD_VECTOR_SIZE 32 +/* Architecture Detection */ +#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 +/* End Architecture Detection */ -#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. - +/* Inline */ #ifdef _MSC_VER -#define DRWAV_INLINE __forceinline -#else -#ifdef __GNUC__ -#define DRWAV_INLINE inline __attribute__((always_inline)) -#else -#define DRWAV_INLINE inline -#endif -#endif - -// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know. -#if defined(_MSC_VER) && _MSC_VER <= 1200 - #if defined(_WIN64) - #define SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #define DRWAV_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRWAV_GNUC_INLINE_HINT __inline__ #else - #define SIZE_MAX 0xFFFFFFFF + #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 + #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 + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #else + #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 + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC #endif #endif -static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; // 66666972-912E-11CF-A5D6-28DB04C10000 -static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 65766177-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A -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 DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision) { - const drwav_uint32* a32 = (const drwav_uint32*)a; - const drwav_uint32* b32 = (const drwav_uint32*)b; + if (pMajor) { + *pMajor = DRWAV_VERSION_MAJOR; + } - return - a32[0] == b32[0] && - a32[1] == b32[1] && - a32[2] == b32[2] && - a32[3] == b32[3]; + if (pMinor) { + *pMinor = DRWAV_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRWAV_VERSION_REVISION; + } } -static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b) +DRWAV_API const char* drwav_version_string(void) { - return - a[0] == b[0] && - a[1] == b[1] && - a[2] == b[2] && - a[3] == b[3]; + return DRWAV_VERSION_STRING; } +/* +These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are +you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation. +*/ +#ifndef DRWAV_MAX_SAMPLE_RATE +#define DRWAV_MAX_SAMPLE_RATE 384000 +#endif +#ifndef DRWAV_MAX_CHANNELS +#define DRWAV_MAX_CHANNELS 256 +#endif +#ifndef DRWAV_MAX_BITS_PER_SAMPLE +#define DRWAV_MAX_BITS_PER_SAMPLE 64 +#endif + +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */ +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ +/*static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A */ +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 DRWAV_INLINE int drwav__is_little_endian() +static DRWAV_INLINE int drwav__is_little_endian(void) { +#if defined(DRWAV_X86) || defined(DRWAV_X64) + return DRWAV_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRWAV_TRUE; +#else int n = 1; return (*(char*)&n) == 1; +#endif } -static DRWAV_INLINE unsigned short drwav__bytes_to_u16(const unsigned char* data) -{ - if (drwav__is_little_endian()) { - return (data[0] << 0) | (data[1] << 8); - } else { - return (data[1] << 0) | (data[0] << 8); - } -} -static DRWAV_INLINE short drwav__bytes_to_s16(const unsigned char* data) +static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) { - return (short)drwav__bytes_to_u16(data); -} - -static DRWAV_INLINE unsigned int drwav__bytes_to_u32(const unsigned char* data) -{ - if (drwav__is_little_endian()) { - return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - } else { - return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); - } -} - -static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data) -{ - if (drwav__is_little_endian()) { - return - ((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); - } else { - return - ((drwav_uint64)data[7] << 0) | ((drwav_uint64)data[6] << 8) | ((drwav_uint64)data[5] << 16) | ((drwav_uint64)data[4] << 24) | - ((drwav_uint64)data[3] << 32) | ((drwav_uint64)data[2] << 40) | ((drwav_uint64)data[1] << 48) | ((drwav_uint64)data[0] << 56); - } -} - -static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid) -{ - for (int i = 0; i < 16; ++i) { + int i; + for (i = 0; i < 16; ++i) { guid[i] = data[i]; } } +static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n) +{ +#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} + +static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n) +{ +#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_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(). */ + drwav_uint32 r; + __asm__ __volatile__ ( + #if defined(DRWAV_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + +static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n) +{ +#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + 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 DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n) +{ + return (drwav_int16)drwav__bswap16((drwav_uint16)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p) +{ + drwav_uint8 t; + t = p[0]; + p[0] = p[2]; + p[2] = t; +} + +static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + drwav_uint8* pSample = pSamples + (iSample*3); + drwav__bswap_s24(pSample); + } +} + + +static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n) +{ + return (drwav_int32)drwav__bswap32((drwav_uint32)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]); + } +} + + +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 { + drwav_uint32 i; + float f; + } x; + x.f = n; + x.i = drwav__bswap32(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + switch (bytesPerSample) + { + case 1: + { + /* No-op. */ + } break; + case 2: + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + case 3: + { + drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); + } break; + case 4: + { + drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); + } break; + case 8: + { + drwav__bswap_samples_s64((drwav_int64*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + + + +DRWAV_PRIVATE DRWAV_INLINE drwav_bool32 drwav_is_container_be(drwav_container container) +{ + if (container == drwav_container_rifx || container == drwav_container_aiff) { + return DRWAV_TRUE; + } else { + return DRWAV_FALSE; + } +} + + +DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_le(const drwav_uint8* data) +{ + return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8); +} + +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); +} + +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); + } +} + + +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; + } +} + + +DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_MALLOC(sz); +} + +DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_REALLOC(p, sz); +} + +DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRWAV_FREE(p); +} + + +DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_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; +} + +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; + } + + 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) { + DRWAV_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + /* Copy. */ + return *pAllocationCallbacks; + } else { + /* Defaults. */ + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drwav__malloc_default; + allocationCallbacks.onRealloc = drwav__realloc_default; + allocationCallbacks.onFree = drwav__free_default; + return allocationCallbacks; + } +} + + static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) { return @@ -819,58 +1905,59 @@ static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 fo formatTag == DR_WAVE_FORMAT_DVI_ADPCM; } - -typedef struct +DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize) { - union - { - drwav_uint8 fourcc[4]; - drwav_uint8 guid[16]; - } id; - - // The size in bytes of the chunk. - drwav_uint64 sizeInBytes; - - // RIFF = 2 byte alignment. - // W64 = 8 byte alignment. - unsigned int paddingSize; - -} drwav__chunk_header; - -static drwav_bool32 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) { - if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { - return DRWAV_FALSE; - } - - unsigned char sizeInBytes[4]; - if (onRead(pUserData, sizeInBytes, 4) != 4) { - return DRWAV_FALSE; - } - - pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes); - pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 2); - *pRunningBytesReadOut += 8; - } else { - if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { - return DRWAV_FALSE; - } - - unsigned char sizeInBytes[8]; - if (onRead(pUserData, sizeInBytes, 8) != 8) { - return DRWAV_FALSE; - } - - pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; // <-- Subtract 24 because w64 includes the size of the header. - pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 8); - pRunningBytesReadOut += 24; - } - - return DRWAV_TRUE; + return (unsigned int)(chunkSize % 2); } -static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 8); +} + +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 == drwav_container_riff || container == drwav_container_rifx || container == drwav_container_rf64 || container == drwav_container_aiff) { + drwav_uint8 sizeInBytes[4]; + + if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 4) != 4) { + return DRWAV_INVALID_FILE; + } + + pHeaderOut->sizeInBytes = drwav_bytes_to_u32_ex(sizeInBytes, container); + pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); + + *pRunningBytesReadOut += 8; + } else if (container == drwav_container_w64) { + drwav_uint8 sizeInBytes[8]; + + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 8) != 8) { + return DRWAV_INVALID_FILE; + } + + 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; +} + +DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) { drwav_uint64 bytesRemainingToSeek = offset; while (bytesRemainingToSeek > 0) { @@ -890,637 +1977,2401 @@ static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 off return DRWAV_TRUE; } - -static 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_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) { - drwav__chunk_header header; - if (!drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header)) { + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_start); + } + + /* Larger than 32-bit seek. */ + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + + for (;;) { + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_current); + } + + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + } + + /* Should never get here. */ + /*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; + + DRWAV_ASSERT(onRead != NULL); + DRWAV_ASSERT(pCursor != NULL); + + bytesRead = onRead(pUserData, pBufferOut, bytesToRead); + *pCursor += bytesRead; + return bytesRead; +} + +#if 0 +DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor) +{ + DRWAV_ASSERT(onSeek != NULL); + DRWAV_ASSERT(pCursor != NULL); + + if (!onSeek(pUserData, offset, origin)) { return DRWAV_FALSE; } - - // Skip junk chunks. - if ((container == drwav_container_riff && drwav__fourcc_equal(header.id.fourcc, "JUNK")) || (container == drwav_container_w64 && drwav__guid_equal(header.id.guid, drwavGUID_W64_JUNK))) { - if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { - return DRWAV_FALSE; - } - *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; - - return drwav__read_fmt(onRead, onSeek, pUserData, container, pRunningBytesReadOut, fmtOut); - } - - - // Validation. - if (container == drwav_container_riff) { - if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { - return DRWAV_FALSE; - } + if (origin == drwav_seek_origin_start) { + *pCursor = offset; } else { - if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) { - return DRWAV_FALSE; - } - } - - - unsigned char fmt[16]; - 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) { - unsigned char fmt_cbSize[2]; - if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { - return DRWAV_FALSE; // Expecting more data. - } - *pRunningBytesReadOut += sizeof(fmt_cbSize); - - int 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) { - unsigned char 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; + *pCursor += offset; } return DRWAV_TRUE; } - - -#ifndef DR_WAV_NO_STDIO -static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) -{ - return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); -} - -static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) -{ - return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); -} - -static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) -{ - return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; -} - -drwav_bool32 drwav_init_file(drwav* pWav, const char* filename) -{ - FILE* pFile; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (fopen_s(&pFile, filename, "rb") != 0) { - return DRWAV_FALSE; - } -#else - pFile = fopen(filename, "rb"); - if (pFile == NULL) { - return DRWAV_FALSE; - } #endif - return drwav_init(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile); + +#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_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat) +DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align) { - FILE* pFile; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (fopen_s(&pFile, filename, "wb") != 0) { - return DRWAV_FALSE; - } -#else - pFile = fopen(filename, "wb"); - if (pFile == NULL) { - return DRWAV_FALSE; - } -#endif + drwav_uint8* pResult; - return drwav_init_write(pWav, pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); + 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* drwav_open_file(const char* filename) +DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align) { - FILE* pFile; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (fopen_s(&pFile, filename, "rb") != 0) { - return NULL; - } -#else - pFile = fopen(filename, "rb"); - if (pFile == NULL) { - return NULL; - } -#endif - - drwav* pWav = drwav_open(drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile); - if (pWav == NULL) { - fclose(pFile); - return NULL; - } - - return pWav; + size_t extra = bytes + (align ? (align - 1) : 0); + pParser->extraCapacity += extra; } -drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat) +DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks) { - FILE* pFile; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (fopen_s(&pFile, filename, "wb") != 0) { - return NULL; - } -#else - pFile = fopen(filename, "wb"); - if (pFile == NULL) { - return NULL; - } -#endif + if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) { + pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData); - drwav* pWav = drwav_open_write(pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); - if (pWav == NULL) { - fclose(pFile); - return NULL; + 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 pWav; + return DRWAV_SUCCESS; } -#endif //DR_WAV_NO_STDIO - -static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) { - drwav__memory_stream* memory = (drwav__memory_stream*)pUserData; - drwav_assert(memory != NULL); - drwav_assert(memory->dataSize >= memory->currentReadPos); + if (pCursor != NULL) { + return drwav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor); + } else { + return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead); + } +} - size_t bytesRemaining = memory->dataSize - memory->currentReadPos; +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 (bytesToRead > 0) { - DRWAV_COPY_MEMORY(pBufferOut, memory->data + memory->currentReadPos, bytesToRead); - memory->currentReadPos += bytesToRead; - } - - return bytesToRead; -} - -static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) -{ - drwav__memory_stream* memory = (drwav__memory_stream*)pUserData; - drwav_assert(memory != NULL); - - if (origin == drwav_seek_origin_current) { - if (offset > 0) { - if (memory->currentReadPos + offset > memory->dataSize) { - offset = (int)(memory->dataSize - memory->currentReadPos); // Trying to seek too far forward. - } - } else { - if (memory->currentReadPos < (size_t)-offset) { - offset = -(int)memory->currentReadPos; // Trying to seek too far backwards. - } - } - - // This will never underflow thanks to the clamps above. - memory->currentReadPos += offset; + if (pDst == NULL) { + /* Seek. */ + result = drwav_buffer_reader_seek(pReader, bytesToRead); } else { - if ((drwav_uint32)offset <= memory->dataSize) { - memory->currentReadPos = offset; - } else { - memory->currentReadPos = memory->dataSize; // Trying to seek too far forward. + /* 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); - return DRWAV_TRUE; -} + if (bytesRead == sizeof(bextData)) { + drwav_buffer_reader reader; + drwav_uint32 timeReferenceLow; + drwav_uint32 timeReferenceHigh; + size_t extraBytes; -static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) -{ - drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData; - drwav_assert(memory != NULL); - drwav_assert(memory->dataCapacity >= memory->currentWritePos); + pMetadata->type = drwav_metadata_type_bext; - size_t bytesRemaining = memory->dataCapacity - memory->currentWritePos; - if (bytesRemaining < bytesToWrite) { - // Need to reallocate. - size_t newDataCapacity = (memory->dataCapacity == 0) ? 256 : memory->dataCapacity * 2; + 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); - // If doubling wasn't enough, just make it the minimum required size to write the data. - if ((newDataCapacity - memory->currentWritePos) < bytesToWrite) { - newDataCapacity = memory->currentWritePos + bytesToWrite; - } + 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); - void* pNewData = DRWAV_REALLOC(*memory->ppData, newDataCapacity); - if (pNewData == NULL) { - return 0; - } + 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); - *memory->ppData = pNewData; - memory->dataCapacity = newDataCapacity; - } + 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_uint8* pDataOut = (drwav_uint8*)(*memory->ppData); - DRWAV_COPY_MEMORY(pDataOut + memory->currentWritePos, pDataIn, bytesToWrite); + drwav_buffer_reader_read_u32(&reader, &timeReferenceLow); + drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh); + pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow; - memory->currentWritePos += bytesToWrite; - if (memory->dataSize < memory->currentWritePos) { - memory->dataSize = memory->currentWritePos; - } + drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version); - *memory->pDataSize = memory->dataSize; + 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); - return bytesToWrite; -} + 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); -static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) -{ - drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData; - drwav_assert(memory != NULL); + DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES)); - if (origin == drwav_seek_origin_current) { - if (offset > 0) { - if (memory->currentWritePos + offset > memory->dataSize) { - offset = (int)(memory->dataSize - memory->currentWritePos); // Trying to seek too far forward. + 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 { - if (memory->currentWritePos < (size_t)-offset) { - offset = -(int)memory->currentWritePos; // Trying to seek too far backwards. - } + pMetadata->data.labelOrNote.stringLength = 0; + pMetadata->data.labelOrNote.pString = NULL; } + } - // This will never underflow thanks to the clamps above. - memory->currentWritePos += offset; + 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 { - if ((drwav_uint32)offset <= memory->dataSize) { - memory->currentWritePos = offset; + 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 { - memory->currentWritePos = memory->dataSize; // Trying to seek too far forward. + 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; + } else { + bytesPerFrame = 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) +{ + if (pFMT == NULL) { + return 0; + } + + if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) { + return pFMT->formatTag; + } else { + return drwav_bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */ + } +} + +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 DRWAV_FALSE; + } + + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onRead = onRead; + pWav->onSeek = onSeek; + pWav->pUserData = pReadSeekUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + return DRWAV_TRUE; } -drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize) +DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { - if (data == NULL || dataSize == 0) { + /* 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_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; + + 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)) { return DRWAV_FALSE; } - drwav__memory_stream memoryStream; - drwav_zero_memory(&memoryStream, sizeof(memoryStream)); - memoryStream.data = (const unsigned char*)data; - memoryStream.dataSize = dataSize; - memoryStream.currentReadPos = 0; - - if (!drwav_init(pWav, drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream)) { - return DRWAV_FALSE; - } - - pWav->memoryStream = memoryStream; - pWav->pUserData = &pWav->memoryStream; - return DRWAV_TRUE; -} - -drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat) -{ - if (ppData == NULL) { - return DRWAV_FALSE; - } - - *ppData = NULL; // Important because we're using realloc()! - *pDataSize = 0; - - drwav__memory_stream_write memoryStreamWrite; - drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); - memoryStreamWrite.ppData = ppData; - memoryStreamWrite.pDataSize = pDataSize; - memoryStreamWrite.dataSize = 0; - memoryStreamWrite.dataCapacity = 0; - memoryStreamWrite.currentWritePos = 0; - - if (!drwav_init_write(pWav, pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite)) { - return DRWAV_FALSE; - } - - pWav->memoryStreamWrite = memoryStreamWrite; - pWav->pUserData = &pWav->memoryStreamWrite; - return DRWAV_TRUE; -} - -drwav* drwav_open_memory(const void* data, size_t dataSize) -{ - if (data == NULL || dataSize == 0) { - return NULL; - } - - drwav__memory_stream memoryStream; - drwav_zero_memory(&memoryStream, sizeof(memoryStream)); - memoryStream.data = (const unsigned char*)data; - memoryStream.dataSize = dataSize; - memoryStream.currentReadPos = 0; - - drwav* pWav = drwav_open(drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream); - if (pWav == NULL) { - return NULL; - } - - pWav->memoryStream = memoryStream; - pWav->pUserData = &pWav->memoryStream; - return pWav; -} - -drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat) -{ - if (ppData == NULL) { - return NULL; - } - - *ppData = NULL; // Important because we're using realloc()! - *pDataSize = 0; - - drwav__memory_stream_write memoryStreamWrite; - drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); - memoryStreamWrite.ppData = ppData; - memoryStreamWrite.pDataSize = pDataSize; - memoryStreamWrite.dataSize = 0; - memoryStreamWrite.dataCapacity = 0; - memoryStreamWrite.currentWritePos = 0; - - drwav* pWav = drwav_open_write(pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite); - if (pWav == NULL) { - return NULL; - } - - pWav->memoryStreamWrite = memoryStreamWrite; - pWav->pUserData = &pWav->memoryStreamWrite; - return pWav; -} - - -drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData) -{ - if (onRead == NULL || onSeek == NULL) { - return DRWAV_FALSE; - } - - drwav_zero_memory(pWav, sizeof(*pWav)); - - - // The first 4 bytes should be the RIFF identifier. - unsigned char riff[4]; - if (onRead(pUserData, riff, sizeof(riff)) != sizeof(riff)) { - return DRWAV_FALSE; // Failed to read data. - } - - // The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for - // w64 it will start with "riff". - if (drwav__fourcc_equal(riff, "RIFF")) { + /* + The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for + w64 it will start with "riff". + */ + if (drwav_fourcc_equal(riff, "RIFF")) { pWav->container = drwav_container_riff; - } else if (drwav__fourcc_equal(riff, "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]; + pWav->container = drwav_container_w64; - // Check the rest of the GUID for validity. - drwav_uint8 riff2[12]; - if (onRead(pUserData, riff2, sizeof(riff2)) != sizeof(riff2)) { + /* Check the rest of the GUID for validity. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { return DRWAV_FALSE; } - for (int i = 0; i < 12; ++i) { + for (i = 0; i < 12; ++i) { if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { return DRWAV_FALSE; } } + } 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. + return DRWAV_FALSE; /* Unknown or unsupported container. */ } - if (pWav->container == drwav_container_riff) { - // RIFF/WAVE - unsigned char chunkSizeBytes[4]; - if (onRead(pUserData, chunkSizeBytes, sizeof(chunkSizeBytes)) != sizeof(chunkSizeBytes)) { + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || 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; } - unsigned int chunkSize = drwav__bytes_to_u32(chunkSizeBytes); - if (chunkSize < 36) { - return DRWAV_FALSE; // Chunk size should always be at least 36 bytes. - } - - unsigned char wave[4]; - if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) { - return DRWAV_FALSE; - } - - if (!drwav__fourcc_equal(wave, "WAVE")) { - return DRWAV_FALSE; // Expecting "WAVE". - } - - pWav->dataChunkDataPos = 4 + sizeof(chunkSizeBytes) + sizeof(wave); - } else { - // W64 - unsigned char chunkSize[8]; - if (onRead(pUserData, chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) { - return DRWAV_FALSE; - } - - if (drwav__bytes_to_u64(chunkSize) < 80) { - return DRWAV_FALSE; - } - - drwav_uint8 wave[16]; - if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) { - return DRWAV_FALSE; - } - - if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) { - return DRWAV_FALSE; - } - - pWav->dataChunkDataPos = 16 + sizeof(chunkSize) + sizeof(wave); - } - - - // The next 24 bytes should be the "fmt " chunk. - drwav_fmt fmt; - if (!drwav__read_fmt(onRead, onSeek, pUserData, pWav->container, &pWav->dataChunkDataPos, &fmt)) { - return DRWAV_FALSE; // Failed to read the "fmt " chunk. - } - - - // Translate the internal format. - unsigned short translatedFormatTag = fmt.formatTag; - if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { - translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); - } - - - drwav_uint64 sampleCountFromFactChunk = 0; - - // The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. - drwav_uint64 dataSize; - for (;;) - { - drwav__chunk_header header; - if (!drwav__read_chunk_header(onRead, pUserData, pWav->container, &pWav->dataChunkDataPos, &header)) { - return DRWAV_FALSE; - } - - dataSize = header.sizeInBytes; - if (pWav->container == drwav_container_riff) { - if (drwav__fourcc_equal(header.id.fourcc, "data")) { - break; + 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. */ } } else { - if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) { - break; + return DRWAV_FALSE; /* Should never hit this. */ + } + + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav_fourcc_equal(wave, "WAVE")) { + return DRWAV_FALSE; /* Expecting "WAVE". */ + } + } else if (pWav->container == drwav_container_w64) { + 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 (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; + } + } 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; + } + + + /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */ + if (pWav->container == drwav_container_rf64) { + drwav_uint8 sizeBytes[8]; + drwav_uint64 bytesRemainingInChunk; + drwav_chunk_header header; + 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; /* Expecting "ds64". */ + } + + bytesRemainingInChunk = header.sizeInBytes + header.paddingSize; + + /* We don't care about the size of the RIFF chunk - skip it. */ + if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + cursor += 8; + + + /* Next 8 bytes is the size of the "data" chunk. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + dataChunkSize = drwav_bytes_to_u64(sizeBytes); + + + /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes); + + + /* Skip over everything else. */ + if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { + return DRWAV_FALSE; + } + cursor += bytesRemainingInChunk; + } + + + 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; + } + + 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; + } + + + /* + 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. + */ + for (;;) { /* For each chunk... */ + drwav_chunk_header header; + drwav_uint64 chunkSize; + + result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + break; + } + + 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. + */ + if (!sequential && onChunk != NULL) { + drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); + + /* + dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before + we called the callback. + */ + if (callbackBytesRead > 0) { + if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) { + return DRWAV_FALSE; + } } } - // 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 (onRead(pUserData, &sampleCount, 4) != 4) { + + /* 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; } - pWav->dataChunkDataPos += 4; - dataSize -= 4; + cursor += (header.sizeInBytes - bytesReadSoFar); + } - // 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 (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; + } + + /* "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. */ + 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 (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { + return DRWAV_FALSE; + } + + chunkSize -= 4; + + /* + 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 = sampleCount; + sampleCountFromFactChunk = drwav_bytes_to_u32_ex(sampleCount, pWav->container); } else { sampleCountFromFactChunk = 0; } - } - } else { - if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) { - if (onRead(pUserData, &sampleCountFromFactChunk, 8) != 8) { + } else if (pWav->container == drwav_container_w64) { + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { return DRWAV_FALSE; } - pWav->dataChunkDataPos += 4; - dataSize -= 8; + + 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; + } + cursor += chunkSize; + + continue; + } + + + /* "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; + + foundChunk_fmt = DRWAV_TRUE; + + 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. */ + } + } + + 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; + } + } 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; + } + } + + /* 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. */ } } - // If we get here it means we didn't find the "data" chunk. Seek past it. - // Make sure we seek past the padding. - dataSize += header.paddingSize; - drwav__seek_forward(onSeek, dataSize, pUserData); - pWav->dataChunkDataPos += dataSize; + + /* 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) { + break; + } + cursor += chunkSize; + } + + /* 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) { + 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)) { + return DRWAV_FALSE; + } + 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; } - // At this point we should be sitting on the first byte of the raw audio data. - pWav->onRead = onRead; - pWav->onSeek = onSeek; - pWav->pUserData = pUserData; pWav->fmt = fmt; pWav->sampleRate = fmt.sampleRate; pWav->channels = fmt.channels; pWav->bitsPerSample = fmt.bitsPerSample; - pWav->bytesPerSample = (unsigned int)(fmt.blockAlign / fmt.channels); - pWav->bytesRemaining = dataSize; + pWav->bytesRemaining = dataChunkSize; pWav->translatedFormatTag = translatedFormatTag; - pWav->dataChunkDataSize = dataSize; + pWav->dataChunkDataSize = dataChunkSize; if (sampleCountFromFactChunk != 0) { - pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels; + pWav->totalPCMFrameCount = sampleCountFromFactChunk; + } else if (aiffFrameCount != 0) { + pWav->totalPCMFrameCount = aiffFrameCount; } else { - pWav->totalSampleCount = dataSize / pWav->bytesPerSample; + 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; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - drwav_uint64 blockCount = dataSize / fmt.blockAlign; - pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - drwav_uint64 blockCount = dataSize / fmt.blockAlign; - pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels); + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + + /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */ + pWav->totalPCMFrameCount += blockCount; } } - - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - pWav->bytesPerSample = 0; + + /* 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), - // it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count - // from the number of blocks, however this results in the inclusion of the extra silent samples at the end of the last block. The correct - // way to know the total sample count is to inspect the "fact" chunk which should always be present for compressed formats, and should - // always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my - // correctness tests against libsndfile and is disabled by default. + /* + I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), + it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count + from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct + way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should + always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my + correctness tests against libsndfile, and is disabled by default. + */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - drwav_uint64 blockCount = dataSize / fmt.blockAlign; - pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2; // x2 because two samples per byte. + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - drwav_uint64 blockCount = dataSize / fmt.blockAlign; - pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels); + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; } #endif return DRWAV_TRUE; } -drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) { - if (onWrite == NULL || onSeek == NULL) { + return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, 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 (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { return DRWAV_FALSE; } - // Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. + 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) +{ + if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA); +} + +DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav) +{ + drwav_metadata *result = pWav->pMetadata; + + pWav->pMetadata = NULL; + pWav->metadataCount = 0; + + return result; +} + + +DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + /* Generic write. Assumes no byte reordering required. */ + 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); + 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 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) +{ + if (pWav == NULL || onWrite == NULL) { + return DRWAV_FALSE; + } + + if (!isSequential && onSeek == NULL) { + return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */ + } + + /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */ if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { return DRWAV_FALSE; } @@ -1528,312 +4379,1548 @@ drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drw return DRWAV_FALSE; } - - drwav_zero_memory(pWav, sizeof(*pWav)); - pWav->onWrite = onWrite; - pWav->onSeek = onSeek; + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onWrite = onWrite; + pWav->onSeek = onSeek; pWav->pUserData = pUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + pWav->fmt.formatTag = (drwav_uint16)pFormat->format; pWav->fmt.channels = (drwav_uint16)pFormat->channels; pWav->fmt.sampleRate = pFormat->sampleRate; - pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) >> 3); - pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) >> 3); + 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; - - size_t runningPos = 0; - - // "RIFF" chunk. - drwav_uint64 chunkSizeRIFF = 0; - if (pFormat->container == drwav_container_riff) { - runningPos += pWav->onWrite(pUserData, "RIFF", 4); - runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 4); - runningPos += pWav->onWrite(pUserData, "WAVE", 4); - } else { - runningPos += pWav->onWrite(pUserData, drwavGUID_W64_RIFF, 16); - runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 8); - runningPos += pWav->onWrite(pUserData, drwavGUID_W64_WAVE, 16); - } - - // "fmt " chunk. - drwav_uint64 chunkSizeFMT; - if (pFormat->container == drwav_container_riff) { - chunkSizeFMT = 16; - runningPos += pWav->onWrite(pUserData, "fmt ", 4); - runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 4); - } else { - chunkSizeFMT = 40; - runningPos += pWav->onWrite(pUserData, drwavGUID_W64_FMT, 16); - runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 8); - } - - runningPos += pWav->onWrite(pUserData, &pWav->fmt.formatTag, 2); - runningPos += pWav->onWrite(pUserData, &pWav->fmt.channels, 2); - runningPos += pWav->onWrite(pUserData, &pWav->fmt.sampleRate, 4); - runningPos += pWav->onWrite(pUserData, &pWav->fmt.avgBytesPerSec, 4); - runningPos += pWav->onWrite(pUserData, &pWav->fmt.blockAlign, 2); - runningPos += pWav->onWrite(pUserData, &pWav->fmt.bitsPerSample, 2); - - pWav->dataChunkDataPos = runningPos; - pWav->dataChunkDataSize = 0; - - // "data" chunk. - drwav_uint64 chunkSizeDATA = 0; - if (pFormat->container == drwav_container_riff) { - runningPos += pWav->onWrite(pUserData, "data", 4); - runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 4); - } else { - runningPos += pWav->onWrite(pUserData, drwavGUID_W64_DATA, 16); - runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 8); - } - - - // Simple validation. - if (pFormat->container == drwav_container_riff) { - if (runningPos != 20 + chunkSizeFMT + 8) { - return DRWAV_FALSE; - } - } else { - if (runningPos != 40 + chunkSizeFMT + 24) { - return DRWAV_FALSE; - } - } - - - - // Set some properties for the client's convenience. - pWav->container = pFormat->container; - pWav->channels = (drwav_uint16)pFormat->channels; - pWav->sampleRate = pFormat->sampleRate; - pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; - pWav->bytesPerSample = (drwav_uint16)(pFormat->bitsPerSample >> 3); - pWav->translatedFormatTag = (drwav_uint16)pFormat->format; + pWav->isSequentialWrite = isSequential; return DRWAV_TRUE; } -void drwav_uninit(drwav* pWav) + +DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) { - if (pWav == NULL) { - return; - } + /* The function assumes drwav_preinit_write() was called beforehand. */ - // If the drwav object was opened in write mode we'll need to finialize a few things: - // - Make sure the "data" chunk is aligned to 16-bits - // - Set the size of the "data" chunk. - if (pWav->onWrite != NULL) { - // Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. - drwav_uint32 paddingSize = 0; - if (pWav->container == drwav_container_riff) { - paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 2); - } else { - paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 8); - } - - if (paddingSize > 0) { - drwav_uint64 paddingData = 0; - pWav->onWrite(pWav->pUserData, &paddingData, paddingSize); - } + size_t runningPos = 0; + drwav_uint64 initialDataChunkSize = 0; + drwav_uint64 chunkSizeFMT; + /* + The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In + sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- + sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. + */ + if (pWav->isSequentialWrite) { + initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; - // Chunk sizes. - if (pWav->onSeek) { - if (pWav->container == drwav_container_riff) { - // The "RIFF" chunk size. - if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { - drwav_uint32 riffChunkSize = 36; - if (pWav->dataChunkDataSize <= (0xFFFFFFFF - 36)) { - riffChunkSize = 36 + (drwav_uint32)pWav->dataChunkDataSize; - } else { - riffChunkSize = 0xFFFFFFFF; - } - - pWav->onWrite(pWav->pUserData, &riffChunkSize, 4); - } - - // the "data" chunk size. - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { - drwav_uint32 dataChunkSize = 0; - if (pWav->dataChunkDataSize <= 0xFFFFFFFF) { - dataChunkSize = (drwav_uint32)pWav->dataChunkDataSize; - } else { - dataChunkSize = 0xFFFFFFFF; - } - - pWav->onWrite(pWav->pUserData, &dataChunkSize, 4); - } - } else { - // The "RIFF" chunk size. - if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { - drwav_uint64 riffChunkSize = 80 + 24 + pWav->dataChunkDataSize; - pWav->onWrite(pWav->pUserData, &riffChunkSize, 8); - } - - // The "data" chunk size. - if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { - drwav_uint64 dataChunkSize = 24 + pWav->dataChunkDataSize; // +24 because W64 includes the size of the GUID and size fields. - pWav->onWrite(pWav->pUserData, &dataChunkSize, 8); - } + /* + The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 + so for the sake of simplicity I'm not doing any validation for that. + */ + if (pFormat->container == drwav_container_riff) { + if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { + return DRWAV_FALSE; /* Not enough room to store every sample. */ } } } + pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; + + + /* "RIFF" chunk. */ + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */ + 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; /* +24 because W64 includes the size of the GUID and size fields. */ + 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); /* 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. */ + drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */ + + runningPos += drwav__write(pWav, "ds64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */ + runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */ + } + + + /* "fmt " chunk. */ + if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) { + chunkSizeFMT = 16; + 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 += drwav__write(pWav, drwavGUID_W64_FMT, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT); + } + + 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); + + /* 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; + 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; /* +24 because W64 includes the size of the GUID and size fields. */ + 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); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */ + } + + /* Set some properties for the client's convenience. */ + pWav->container = pFormat->container; + pWav->channels = (drwav_uint16)pFormat->channels; + pWav->sampleRate = pFormat->sampleRate; + pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->translatedFormatTag = (drwav_uint16)pFormat->format; + pWav->dataChunkDataPos = runningPos; + + return DRWAV_TRUE; +} + + +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 (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */ +} + +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 (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */ +} + +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 DRWAV_FALSE; + } + + 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) +{ + 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); + drwav_uint64 riffChunkSizeBytes; + drwav_uint64 fileSizeBytes = 0; + + if (pFormat->container == drwav_container_riff) { + riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount); + 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); + fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ + } + + return fileSizeBytes; +} + + #ifndef DR_WAV_NO_STDIO - // If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() - // was used by looking at the onRead and onSeek callbacks. + +/* 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) +{ + 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; + } +} +/* End Errno */ + +/* fopen */ +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; /* Safety. */ + } + + 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; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRWAV_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRWAV_HAS_WFOPEN + #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) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } + +#if defined(DRWAV_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #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 + /* + 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; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + 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); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + 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); + } + #endif + + if (*ppFile == NULL) { + return DRWAV_ERROR; + } +#endif + + return DRWAV_SUCCESS; +} +#endif +/* End fopen */ + + +DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) +{ + return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); +} + +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) +{ + return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; +} + +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, 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) +{ + 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 = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +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 (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, 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); +} + +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 (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, 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) +{ + 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 = drwav_init_write__internal(pWav, pFormat, totalSampleCount); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +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 (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + 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; + if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* 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) +{ + return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, 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 drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, 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 DRWAV_FALSE; + } + + 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); +} + +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 drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, 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 DRWAV_FALSE; + } + + return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} +#endif +#endif /* DR_WAV_NO_STDIO */ + + +DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + 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) { + DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); + pWav->memoryStream.currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) +{ + 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 DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStream.currentReadPos < (size_t)-offset) { + return DRWAV_FALSE; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStream.currentReadPos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) { + pWav->memoryStream.currentReadPos = offset; + } else { + return DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); + + bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; + if (bytesRemaining < bytesToWrite) { + /* Need to reallocate. */ + void* pNewData; + size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2; + + /* If doubling wasn't enough, just make it the minimum required size to write the data. */ + if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) { + newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite; + } + + 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; + } + + 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; + } + + *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize; + + return bytesToWrite; +} + +DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) +{ + 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); /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { + offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStreamWrite.currentWritePos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + pWav->memoryStreamWrite.currentWritePos = offset; + } else { + pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, 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 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, 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) +{ + if (ppData == NULL || pDataSize == NULL) { + return DRWAV_FALSE; + } + + *ppData = NULL; /* Important because we're using realloc()! */ + *pDataSize = 0; + + 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 drwav_init_write__internal(pWav, pFormat, totalSampleCount); +} + +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 drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, 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 drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, 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 DRWAV_FALSE; + } + + return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} + + + +DRWAV_API drwav_result drwav_uninit(drwav* pWav) +{ + drwav_result result = DRWAV_SUCCESS; + + if (pWav == NULL) { + return DRWAV_INVALID_ARGS; + } + + /* + If the drwav object was opened in write mode we'll need to finalize a few things: + - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. + - Set the size of the "data" chunk. + */ + if (pWav->onWrite != NULL) { + drwav_uint32 paddingSize = 0; + + /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize); + } 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. */ + } + + /* + Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need + to do this when using non-sequential mode. + */ + if (pWav->onSeek && !pWav->isSequentialWrite) { + 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__write_u32ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + 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 == drwav_container_w64) { + /* The "RIFF" chunk size. */ + 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); + } + + /* The "data" chunk size. */ + 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 == drwav_container_rf64) { + /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */ + int ds64BodyPos = 12 + 8; + + /* 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__write_u64ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + 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); + } + } + } + + /* Validation for sequential mode. */ + if (pWav->isSequentialWrite) { + if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { + result = DRWAV_INVALID_FILE; + } + } + } else { + drwav_free(pWav->pMetadata, &pWav->allocationCallbacks); + } + +#ifndef DR_WAV_NO_STDIO + /* + If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() + was used by looking at the onRead and onSeek callbacks. + */ if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { fclose((FILE*)pWav->pUserData); } #endif + + return result; } -drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData) + +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { - drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav)); - if (pWav == NULL) { - return NULL; - } + size_t bytesRead; + drwav_uint32 bytesPerFrame; - if (!drwav_init(pWav, onRead, onSeek, pUserData)) { - DRWAV_FREE(pWav); - return NULL; - } - - return pWav; -} - -drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) -{ - drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav)); - if (pWav == NULL) { - return NULL; - } - - if (!drwav_init_write(pWav, pFormat, onWrite, onSeek, pUserData)) { - DRWAV_FREE(pWav); - return NULL; - } - - return pWav; -} - -void drwav_close(drwav* pWav) -{ - drwav_uninit(pWav); - DRWAV_FREE(pWav); -} - - -size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) -{ - if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) { - return 0; + if (pWav == NULL || bytesToRead == 0) { + return 0; /* Invalid args. */ } if (bytesToRead > pWav->bytesRemaining) { bytesToRead = (size_t)pWav->bytesRemaining; } - size_t bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); + 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 { + /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */ + bytesRead = 0; + while (bytesRead < bytesToRead) { + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > 0x7FFFFFFF) { + bytesToSeek = 0x7FFFFFFF; + } + + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) { + break; + } + + bytesRead += bytesToSeek; + } + + /* When we get here we may need to read-and-discard some data. */ + while (bytesRead < bytesToRead) { + drwav_uint8 buffer[4096]; + size_t bytesSeeked; + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > sizeof(buffer)) { + bytesToSeek = sizeof(buffer); + } + + bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek); + bytesRead += bytesSeeked; + + if (bytesSeeked < bytesToSeek) { + break; /* Reached the end. */ + } + } + } + + pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame; pWav->bytesRemaining -= bytesRead; return bytesRead; } -drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut) + + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { - if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + 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; } - // Cannot use this function for compressed formats. + /* Cannot use this function for compressed formats. */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. - if (samplesToRead * pWav->bytesPerSample > SIZE_MAX) { - samplesToRead = SIZE_MAX / pWav->bytesPerSample; + framesRemainingInFile = pWav->totalPCMFrameCount - pWav->readCursorInPCMFrames; + if (framesToRead > framesRemainingInFile) { + framesToRead = framesRemainingInFile; } - size_t bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * pWav->bytesPerSample), pBufferOut); - return bytesRead / pWav->bytesPerSample; + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + bytesToRead = framesToRead * bytesPerFrame; + if (bytesToRead > DRWAV_SIZE_MAX) { + bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */ + } + + /* + Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There + *could* be a time where it evaluates to 0 due to overflowing. + */ + if (bytesToRead == 0) { + return 0; + } + + return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame; } -drwav_bool32 drwav_seek_to_first_sample(drwav* pWav) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { + 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); + } + + return framesRead; +} + +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); + } else { + framesRead = 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; +} + + + +DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) +{ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; /* No seeking in write mode. */ + } + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { return DRWAV_FALSE; } if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { - pWav->compressed.iCurrentSample = 0; + /* Cached data needs to be cleared for compressed formats. */ + 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 { + 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; } -drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) { - // Seeking should be compatible with wave files > 2GB. + /* Seeking should be compatible with wave files > 2GB. */ if (pWav == NULL || pWav->onSeek == NULL) { return DRWAV_FALSE; } - // If there are no samples, just return DRWAV_TRUE without doing anything. - if (pWav->totalSampleCount == 0) { + /* No seeking in write mode. */ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; + } + + /* If there are no samples, just return DRWAV_TRUE without doing anything. */ + if (pWav->totalPCMFrameCount == 0) { return DRWAV_TRUE; } - // Make sure the sample is clamped. - if (sample >= pWav->totalSampleCount) { - sample = pWav->totalSampleCount - 1; + /* Make sure the sample is clamped. */ + if (targetFrameIndex > pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount; } - - // For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need - // to seek back to the start. + /* + For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need + to seek back to the start. + */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { - // TODO: This can be optimized. - if (sample > pWav->compressed.iCurrentSample) { - // Seeking forward - just move from the current position. - drwav_uint64 offset = sample - pWav->compressed.iCurrentSample; + /* 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 (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; + } + } + + if (targetFrameIndex > pWav->readCursorInPCMFrames) { + drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames; drwav_int16 devnull[2048]; - while (offset > 0) { - drwav_uint64 samplesToRead = sample; - if (samplesToRead > 2048) { - samplesToRead = 2048; + while (offsetInFrames > 0) { + drwav_uint64 framesRead = 0; + drwav_uint64 framesToRead = offsetInFrames; + if (framesToRead > drwav_countof(devnull)/pWav->channels) { + framesToRead = drwav_countof(devnull)/pWav->channels; } - drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); - if (samplesRead != samplesToRead) { + 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 { + 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. */ + } + + if (framesRead != framesToRead) { return DRWAV_FALSE; } - offset -= samplesRead; + offsetInFrames -= framesRead; } - } else { - // Seeking backwards. Just use the fallback. - goto fallback; } } else { - drwav_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample; - drwav_assert(totalSizeInBytes >= pWav->bytesRemaining); - - drwav_uint64 currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - drwav_uint64 targetBytePos = sample * pWav->bytesPerSample; - + drwav_uint64 totalSizeInBytes; + 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);*/ + + currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + targetBytePos = targetFrameIndex * bytesPerFrame; + if (currentBytePos < targetBytePos) { - // Offset forwards. + /* Offset forwards. */ offset = (targetBytePos - currentBytePos); } else { - // Offset backwards. - if (!drwav_seek_to_first_sample(pWav)) { + /* Offset backwards. */ + if (!drwav_seek_to_first_pcm_frame(pWav)) { return DRWAV_FALSE; } offset = targetBytePos; @@ -1845,290 +5932,281 @@ drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) return DRWAV_FALSE; } - pWav->bytesRemaining -= offset32; - offset -= offset32; + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; + pWav->bytesRemaining -= offset32; + offset -= offset32; } } - return DRWAV_TRUE; - -fallback: - // This is a generic seek implementation that just continuously reads samples into a temporary buffer. This should work for all supported - // formats, but it is not efficient. This should be used as a fall back. - if (!drwav_seek_to_first_sample(pWav)) { - return DRWAV_FALSE; - } - - drwav_int16 devnull[2048]; - while (sample > 0) { - drwav_uint64 samplesToRead = sample; - if (samplesToRead > 2048) { - samplesToRead = 2048; - } - - drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull); - if (samplesRead != samplesToRead) { - return DRWAV_FALSE; - } - - sample -= samplesRead; - } - return DRWAV_TRUE; } - -size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) +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) +{ + size_t bytesWritten; + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { return 0; } - size_t bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); pWav->dataChunkDataSize += bytesWritten; return bytesWritten; } -drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData) +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { - if (pWav == NULL || samplesToWrite == 0 || pData == NULL) { + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + const drwav_uint8* pRunningData; + + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { return 0; } - drwav_uint64 bytesToWrite = ((samplesToWrite * pWav->bitsPerSample) / 8); - if (bytesToWrite > SIZE_MAX) { + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { return 0; } - size_t bytesWritten = drwav_write_raw(pWav, (size_t)bytesToWrite, pData); - return ((drwav_uint64)bytesWritten * 8) / pWav->bitsPerSample; -} + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; + while (bytesToWrite > 0) { + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; -#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, - 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 -}; + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ -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, - 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 -}; - -static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) -{ - return (short)g_drwavAlawTable[sampleIn]; -} - -static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) -{ - return (short)g_drwavMulawTable[sampleIn]; -} - - - -static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) -{ - // Special case for 8-bit sample data because it's treated as unsigned. - if (bytesPerSample == 1) { - drwav_u8_to_s16(pOut, pIn, totalSampleCount); - return; - } - - - // Slightly more optimal implementation for common formats. - if (bytesPerSample == 2) { - for (unsigned int i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((drwav_int16*)pIn)[i]; - } - return; - } - if (bytesPerSample == 3) { - drwav_s24_to_s16(pOut, pIn, totalSampleCount); - return; - } - if (bytesPerSample == 4) { - drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); - return; - } - - - // Generic, slow converter. - for (unsigned int i = 0; i < totalSampleCount; ++i) { - unsigned short sample = 0; - unsigned short shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 2; ++j) { - sample |= (unsigned short)(pIn[j]) << shift; - shift += 8; - } - - pIn += bytesPerSample; - *pOut++ = sample; - } -} - -static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) -{ - if (bytesPerSample == 4) { - drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount); - return; - } else { - drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount); - return; - } -} - -drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) -{ - // Fast path. - if (pWav->bytesPerSample == 2) { - return drwav_read(pWav, samplesToRead, pBufferOut); - } - - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + if (bytesJustWritten == 0) { break; } - drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); - - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; } - return totalSamplesRead; + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; } -drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) { - drwav_assert(pWav != NULL); - drwav_assert(samplesToRead > 0); - drwav_assert(pBufferOut != NULL); + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + drwav_uint32 bytesPerSample; + const drwav_uint8* pRunningData; - // TODO: Lots of room for optimization here. + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } - drwav_uint64 totalSamplesRead = 0; + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { + return 0; + } - while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - // If there are no cached samples we need to load a new block. - if (pWav->msadpcm.cachedSampleCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { + bytesWritten = 0; + 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; + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; + + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ + + /* + WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need + to use an intermediary buffer for the conversion. + */ + sampleCount = sizeof(temp)/bytesPerSample; + + if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) { + bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample; + } + + DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); + drwav__bswap_samples(temp, sampleCount, bytesPerSample); + + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); + if (bytesJustWritten == 0) { + break; + } + + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; +} + +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + if (drwav__is_little_endian()) { + return drwav_write_pcm_frames_le(pWav, framesToWrite, pData); + } else { + return drwav_write_pcm_frames_be(pWav, framesToWrite, pData); + } +} + + +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead = 0; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (pWav->readCursorInPCMFrames < 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. */ + if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_uint8 header[7]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { - return totalSamplesRead; + return totalFramesRead; } pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); - pWav->msadpcm.predictor[0] = header[0]; - pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1); - pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3); - pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5); - pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][0]; - pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[0][1]; - pWav->msadpcm.cachedSampleCount = 2; + pWav->msadpcm.predictor[0] = header[0]; + 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; } else { - // Stereo. + /* Stereo. */ drwav_uint8 header[14]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { - return totalSamplesRead; + 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] = drwav__bytes_to_s16(header + 2); - pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4); - pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6); - pWav->msadpcm.prevSamples[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8); - pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10); - pWav->msadpcm.prevSamples[1][0] = (drwav_int32)drwav__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.cachedSamples[0] = pWav->msadpcm.prevSamples[0][0]; - pWav->msadpcm.cachedSamples[1] = pWav->msadpcm.prevSamples[1][0]; - pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][1]; - pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[1][1]; - pWav->msadpcm.cachedSampleCount = 4; + 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; } } - // Output anything that's cached. - while (samplesToRead > 0 && pWav->msadpcm.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - pBufferOut[0] = (drwav_int16)pWav->msadpcm.cachedSamples[drwav_countof(pWav->msadpcm.cachedSamples) - pWav->msadpcm.cachedSampleCount]; - pWav->msadpcm.cachedSampleCount -= 1; + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample = 0; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; + } - pBufferOut += 1; - samplesToRead -= 1; - totalSamplesRead += 1; - pWav->compressed.iCurrentSample += 1; + pBufferOut += pWav->channels; + } + + framesToRead -= 1; + totalFramesRead += 1; + pWav->readCursorInPCMFrames += 1; + pWav->msadpcm.cachedFrameCount -= 1; } - if (samplesToRead == 0) { - return totalSamplesRead; + if (framesToRead == 0) { + break; } - // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next - // loop iteration which will trigger the loading of a new block. - if (pWav->msadpcm.cachedSampleCount == 0) { + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->msadpcm.cachedFrameCount == 0) { if (pWav->msadpcm.bytesRemainingInBlock == 0) { continue; } else { - drwav_uint8 nibbles; - if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { - return totalSamplesRead; - } - pWav->msadpcm.bytesRemainingInBlock -= 1; - - // TODO: Optimize away these if statements. - drwav_int32 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } - drwav_int32 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } - - 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 }; + drwav_uint8 nibbles; + drwav_int32 nibble0; + drwav_int32 nibble1; + + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + + /* TODO: Optimize away these if statements. */ + nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } + nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } + if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_int32 newSample0; - newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + 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 = drwav_clamp(newSample0, -32768, 32767); @@ -2137,12 +6215,11 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.delta[0] = 16; } - pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; - pWav->msadpcm.prevSamples[0][1] = newSample0; + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; - drwav_int32 newSample1; - newSample1 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + 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 = drwav_clamp(newSample1, -32768, 32767); @@ -2151,19 +6228,20 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.delta[0] = 16; } - pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; - pWav->msadpcm.prevSamples[0][1] = newSample1; + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample1; - pWav->msadpcm.cachedSamples[2] = newSample0; - pWav->msadpcm.cachedSamples[3] = newSample1; - pWav->msadpcm.cachedSampleCount = 2; + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 2; } else { - // Stereo. - - // Left. + /* Stereo. */ drwav_int32 newSample0; - newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + drwav_int32 newSample1; + + /* Left. */ + 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 = drwav_clamp(newSample0, -32768, 32767); @@ -2172,13 +6250,12 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.delta[0] = 16; } - pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1]; - pWav->msadpcm.prevSamples[0][1] = newSample0; + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; - // Right. - drwav_int32 newSample1; - newSample1 = ((pWav->msadpcm.prevSamples[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevSamples[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; + /* Right. */ + 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 = drwav_clamp(newSample1, -32768, 32767); @@ -2187,113 +6264,139 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.delta[1] = 16; } - pWav->msadpcm.prevSamples[1][0] = pWav->msadpcm.prevSamples[1][1]; - pWav->msadpcm.prevSamples[1][1] = newSample1; + pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.prevFrames[1][1] = newSample1; - pWav->msadpcm.cachedSamples[2] = newSample0; - pWav->msadpcm.cachedSamples[3] = newSample1; - pWav->msadpcm.cachedSampleCount = 2; + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 1; } } } } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) + +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - drwav_assert(pWav != NULL); - drwav_assert(samplesToRead > 0); - drwav_assert(pBufferOut != NULL); + drwav_uint64 totalFramesRead = 0; + drwav_uint32 iChannel; - // TODO: Lots of room for optimization here. + static drwav_int32 indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; - drwav_uint64 totalSamplesRead = 0; + 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, + 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, + 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 + }; - while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - // If there are no cached samples we need to load a new block. - if (pWav->ima.cachedSampleCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (pWav->readCursorInPCMFrames < 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. */ + if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_uint8 header[4]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { - return totalSamplesRead; + return totalFramesRead; } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); - pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); - pWav->ima.stepIndex[0] = header[2]; - pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[0]; - pWav->ima.cachedSampleCount = 1; + if (header[2] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); + pWav->ima.bytesRemainingInBlock = 0; + 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.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; + pWav->ima.cachedFrameCount = 1; } else { - // Stereo. + /* Stereo. */ drwav_uint8 header[8]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { - return totalSamplesRead; + return totalFramesRead; } pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); - 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]; + 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; /* Invalid data. */ + } - pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 2] = pWav->ima.predictor[0]; - pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[1]; - pWav->ima.cachedSampleCount = 2; + 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.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.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; } } - // Output anything that's cached. - while (samplesToRead > 0 && pWav->ima.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - pBufferOut[0] = (drwav_int16)pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount]; - pWav->ima.cachedSampleCount -= 1; + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; + } + pBufferOut += pWav->channels; + } - pBufferOut += 1; - samplesToRead -= 1; - totalSamplesRead += 1; - pWav->compressed.iCurrentSample += 1; + framesToRead -= 1; + totalFramesRead += 1; + pWav->readCursorInPCMFrames += 1; + pWav->ima.cachedFrameCount -= 1; } - if (samplesToRead == 0) { - return totalSamplesRead; + if (framesToRead == 0) { + break; } - // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next - // loop iteration which will trigger the loading of a new block. - if (pWav->ima.cachedSampleCount == 0) { + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->ima.cachedFrameCount == 0) { if (pWav->ima.bytesRemainingInBlock == 0) { continue; } else { - static drwav_int32 indexTable[16] = { - -1, -1, -1, -1, 2, 4, 6, 8, - -1, -1, -1, -1, 2, 4, 6, 8 - }; - - 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, - 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, - 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 - }; - - // From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the - // left channel, 4 bytes for the right channel. - pWav->ima.cachedSampleCount = 8 * pWav->channels; - for (drwav_uint32 iChannel = 0; iChannel < pWav->channels; ++iChannel) { + /* + From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the + left channel, 4 bytes for the right channel. + */ + pWav->ima.cachedFrameCount = 8; + for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { + drwav_uint32 iByte; drwav_uint8 nibbles[4]; if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { - return totalSamplesRead; + pWav->ima.cachedFrameCount = 0; + return totalFramesRead; } pWav->ima.bytesRemainingInBlock -= 4; - for (drwav_uint32 iByte = 0; iByte < 4; ++iByte) { + for (iByte = 0; iByte < 4; ++iByte) { drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); @@ -2309,7 +6412,7 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ predictor = drwav_clamp(predictor + diff, -32768, 32767); pWav->ima.predictor[iChannel] = predictor; pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); - pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+0)*pWav->channels + iChannel] = predictor; + 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]]; @@ -2324,149 +6427,470 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ predictor = drwav_clamp(predictor + diff, -32768, 32767); pWav->ima.predictor[iChannel] = predictor; pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); - pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+1)*pWav->channels + iChannel] = predictor; + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; } } } } } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) + +#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, + 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, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + return (short)g_drwavAlawTable[sampleIn]; +} + +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavMulawTable[sampleIn]; +} + + + +DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + size_t i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); + } +} + +DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + +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_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); + if (framesRead == 0) { break; } - drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + /* 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s16__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +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_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s16__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) { - if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + if (pWav == NULL || framesToRead == 0) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. - if (samplesToRead * sizeof(drwav_int16) > SIZE_MAX) { - samplesToRead = SIZE_MAX / sizeof(drwav_int16); + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels; } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { - return drwav_read_s16__pcm(pWav, samplesToRead, pBufferOut); - } - - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_s16__msadpcm(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { - return drwav_read_s16__ieee(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { - return drwav_read_s16__alaw(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { - return drwav_read_s16__mulaw(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_s16__ima(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); } return 0; } -void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + 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; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + 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; +} + + +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { int x = pIn[i]; - r = x - 128; - r = r << 8; + r = x << 8; + r = r - 32768; pOut[i] = (short)r; } } -void drwav_s24_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) { int r; - for (size_t i = 0; i < sampleCount; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; + size_t i; + for (i = 0; i < sampleCount; ++i) { + 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; } } -void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { int x = pIn[i]; r = x >> 16; pOut[i] = (short)r; } } -void drwav_f32_to_s16(drwav_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; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { float x = pIn[i]; float c; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); @@ -2477,10 +6901,11 @@ void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) } } -void drwav_f64_to_s16(drwav_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; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { double x = pIn[i]; double c; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); @@ -2491,31 +6916,34 @@ void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) } } -void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { pOut[i] = drwav__alaw_to_s16(pIn[i]); } } -void drwav_mulaw_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) { - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { pOut[i] = drwav__mulaw_to_s16(pIn[i]); } } - -static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample) +DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) { - // Special case for 8-bit sample data because it's treated as unsigned. + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { drwav_u8_to_f32(pOut, pIn, sampleCount); return; } - // Slightly more optimal implementation for common formats. + /* Slightly more optimal implementation for common formats. */ if (bytesPerSample == 2) { drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); return; @@ -2529,304 +6957,475 @@ static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t samp return; } - // Generic, slow converter. - for (unsigned int i = 0; i < sampleCount; ++i) { - unsigned int sample = 0; + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < sampleCount; ++i) { + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { - sample |= (unsigned int)(pIn[j]) << shift; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } - pIn += bytesPerSample; - *pOut++ = (float)((int)sample / 2147483648.0); + pIn += j; + *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); } } -static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample) +DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { - for (unsigned int i = 0; i < sampleCount; ++i) { - *pOut++ = ((float*)pIn)[i]; + unsigned int i; + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((const float*)pIn)[i]; } return; + } else if (bytesPerSample == 8) { + drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); + return; } else { - drwav_f64_to_f32(pOut, (double*)pIn, sampleCount); + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); return; } } -drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { break; } - drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); - pBufferOut += samplesRead; + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + /* 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(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 totalSamplesRead = 0; + /* + 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_int16 samples16[2048]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); - if (samplesRead == 0) { + + 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); + if (framesRead == 0) { break; } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + 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 totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(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 totalSamplesRead = 0; - drwav_int16 samples16[2048]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + 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); + if (framesRead == 0) { break; } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; - } - - return totalSamplesRead; -} - -drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) -{ - // Fast path. - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bytesPerSample == 4) { - return drwav_read(pWav, samplesToRead, pBufferOut); - } - - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + /* 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, pWav->bytesPerSample); + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + pBufferOut += samplesRead; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { - if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + if (pWav == NULL || framesToRead == 0) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. - if (samplesToRead * sizeof(float) > SIZE_MAX) { - samplesToRead = SIZE_MAX / sizeof(float); + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels; } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { - return drwav_read_f32__pcm(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_f32__msadpcm(pWav, samplesToRead, 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_IEEE_FLOAT) { - return drwav_read_f32__ieee(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { - return drwav_read_f32__alaw(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { - return drwav_read_f32__mulaw(pWav, samplesToRead, pBufferOut); - } - - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_f32__ima(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); } return 0; } -void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) { + 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; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + 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; +} + + +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 DR_WAV_LIBSNDFILE_COMPAT - // It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears - // libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note - // the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated - // correctness testing. This is disabled by default. - for (size_t i = 0; i < sampleCount; ++i) { + /* + It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears + libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note + the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated + correctness testing. This is disabled by default. + */ + for (i = 0; i < sampleCount; ++i) { *pOut++ = (pIn[i] / 256.0f) * 2 - 1; } #else - for (size_t i = 0; i < sampleCount; ++i) { - *pOut++ = (pIn[i] / 255.0f) * 2 - 1; + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ + + *pOut++ = x; } #endif } -void drwav_s16_to_f32(float* pOut, const drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { - *pOut++ = pIn[i] / 32768.0f; + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] * 0.000030517578125f; } } -void drwav_s24_to_f32(float* pOut, const drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { - unsigned int s0 = pIn[i*3 + 0]; - unsigned int s1 = pIn[i*3 + 1]; - unsigned int s2 = pIn[i*3 + 2]; + for (i = 0; i < sampleCount; ++i) { + double x; + 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); - int sample32 = (int)((s0 << 8) | (s1 << 16) | (s2 << 24)); - *pOut++ = (float)(sample32 / 2147483648.0); + x = (double)((drwav_int32)(a | b | c) >> 8); + *pOut++ = (float)(x * 0.00000011920928955078125); } } -void drwav_s32_to_f32(float* pOut, const drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (float)(pIn[i] / 2147483648.0); } } -void drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (float)pIn[i]; } } -void drwav_alaw_to_f32(float* pOut, const drwav_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 (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; } } -void drwav_mulaw_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) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; } } -static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - // Special case for 8-bit sample data because it's treated as unsigned. + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { drwav_u8_to_s32(pOut, pIn, totalSampleCount); return; } - // Slightly more optimal implementation for common formats. + /* Slightly more optimal implementation for common formats. */ if (bytesPerSample == 2) { drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); return; @@ -2836,235 +7435,386 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_ return; } if (bytesPerSample == 4) { - for (unsigned int i = 0; i < totalSampleCount; ++i) { - *pOut++ = ((drwav_int32*)pIn)[i]; + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int32*)pIn)[i]; } return; } - // Generic, slow converter. - for (unsigned int i = 0; i < totalSampleCount; ++i) { - unsigned int sample = 0; + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; - for (unsigned short j = 0; j < bytesPerSample && j < 4; ++j) { - sample |= (unsigned int)(pIn[j]) << shift; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; shift += 8; } - pIn += bytesPerSample; - *pOut++ = sample; + pIn += j; + *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); } } -static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample) +DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { - drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount); + drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); return; } else { - drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount); + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); return; } } -drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - // Fast path. - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bytesPerSample == 4) { - return drwav_read(pWav, samplesToRead, pBufferOut); + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + 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); } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + 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); + if (framesRead == 0) { break; } - drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample); + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + /* 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(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 - // want to duplicate that code. - drwav_uint64 totalSamplesRead = 0; + /* + 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 = 0; drwav_int16 samples16[2048]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); - if (samplesRead == 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); + if (framesRead == 0) { break; } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + 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 totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(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 totalSamplesRead = 0; - drwav_int16 samples16[2048]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { break; } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; - } - - return totalSamplesRead; -} - -drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) -{ - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + /* 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, pWav->bytesPerSample); + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += samplesRead; + pBufferOut += samplesRead; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; - while (samplesToRead > 0) { - drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData); - if (samplesRead == 0) { + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096] = {0}; + drwav_uint32 bytesPerFrame; + drwav_uint32 bytesPerSample; + drwav_uint64 samplesRead; + + 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); + if (framesRead == 0) { + break; + } + + DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */ + + /* 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); - pBufferOut += samplesRead; - samplesToRead -= samplesRead; - totalSamplesRead += 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; + framesToRead -= framesRead; + totalFramesRead += framesRead; } - return totalSamplesRead; + return totalFramesRead; } -drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { - if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { + if (pWav == NULL || framesToRead == 0) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. - if (samplesToRead * sizeof(drwav_int32) > SIZE_MAX) { - samplesToRead = SIZE_MAX / sizeof(drwav_int32); + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); } + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels; + } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { - return drwav_read_s32__pcm(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); } - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { - return drwav_read_s32__msadpcm(pWav, samplesToRead, 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_IEEE_FLOAT) { - return drwav_read_s32__ieee(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { - return drwav_read_s32__alaw(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { - return drwav_read_s32__mulaw(pWav, samplesToRead, pBufferOut); - } - - if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { - return drwav_read_s32__ima(pWav, samplesToRead, pBufferOut); + return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); } return 0; } -void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) { + 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; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + 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; +} + + +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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = ((int)pIn[i] - 128) << 24; } } -void drwav_s16_to_s32(drwav_int32* pOut, const drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = pIn[i] << 16; } } -void drwav_s24_to_s32(drwav_int32* pOut, const drwav_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) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { unsigned int s0 = pIn[i*3 + 0]; unsigned int s1 = pIn[i*3 + 1]; unsigned int s2 = pIn[i*3 + 2]; @@ -3074,382 +7824,992 @@ void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCo } } -void drwav_f32_to_s32(drwav_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 (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0f * pIn[i]); + } +} + +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++ = (drwav_int32)(2147483648.0 * pIn[i]); } } -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) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { - *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); - } -} - -void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) -{ - if (pOut == NULL || pIn == NULL) { - return; - } - - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; } } -void drwav_mulaw_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) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i= 0; i < sampleCount; ++i) { + for (i= 0; i < sampleCount; ++i) { *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; } } -drwav_int16* drwav__read_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - drwav_assert(pWav != NULL); + drwav_uint64 sampleDataSize; + drwav_int16* pSampleData; + drwav_uint64 framesRead; - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int16); - if (sampleDataSize > SIZE_MAX) { + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16); + if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - drwav_int16* pSampleData = (drwav_int16*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData); - if (samplesRead != pWav->totalSampleCount) { - DRWAV_FREE(pSampleData); + framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + return pSampleData; } -float* drwav__read_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - drwav_assert(pWav != NULL); + drwav_uint64 sampleDataSize; + float* pSampleData; + drwav_uint64 framesRead; - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(float); - if (sampleDataSize > SIZE_MAX) { + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); + if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - float* pSampleData = (float*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData); - if (samplesRead != pWav->totalSampleCount) { - DRWAV_FREE(pSampleData); + framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + return pSampleData; } -drwav_int32* drwav__read_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) { - drwav_assert(pWav != NULL); + drwav_uint64 sampleDataSize; + drwav_int32* pSampleData; + drwav_uint64 framesRead; - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int32); - if (sampleDataSize > SIZE_MAX) { + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32); + if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - drwav_int32* pSampleData = (drwav_int32*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData); - if (samplesRead != pWav->totalSampleCount) { - DRWAV_FREE(pSampleData); + framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + return pSampleData; } -drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) -{ - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; +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 wav; - if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; - if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; - if (!drwav_init(&wav, onRead, onSeek, pUserData)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } #ifndef DR_WAV_NO_STDIO -drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; - if (!drwav_init_file(&wav, filename)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; - if (!drwav_init_file(&wav, filename)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } -drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) +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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; - if (!drwav_init_file(&wav, filename)) { + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { return NULL; } - return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); } + + +#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; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +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 wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +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) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif /* DR_WAV_NO_WCHAR */ +#endif /* DR_WAV_NO_STDIO */ + +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 wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +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 wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +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) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif /* DR_WAV_NO_CONVERSION_API */ + + +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drwav__free_from_callbacks(p, pAllocationCallbacks); + } else { + drwav__free_default(p, NULL); + } +} + +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) +{ + return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8); +} + +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) +{ + return (drwav_int16)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; +} + +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) +{ + return (drwav_int32)drwav_bytes_to_u32(data); +} + +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data) +{ + return + ((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); +} + +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data) +{ + return (drwav_int64)drwav_bytes_to_u64(data); +} + + +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 DRWAV_FALSE; + } + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) +{ + return + a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + a[3] == b[3]; +} + +#ifdef __MRC__ +/* Undo the pragma at the beginning of this file. */ +#pragma options opt reset #endif -drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) -{ - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - - drwav wav; - if (!drwav_init_memory(&wav, data, dataSize)) { - return NULL; - } - - return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount); -} - -float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) -{ - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - - drwav wav; - if (!drwav_init_memory(&wav, data, dataSize)) { - return NULL; - } - - return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount); -} - -drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) -{ - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - - drwav wav; - if (!drwav_init_memory(&wav, data, dataSize)) { - return NULL; - } - - return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount); -} -#endif //DR_WAV_NO_CONVERSION_API - - -void drwav_free(void* pDataReturnedByOpenAndRead) -{ - DRWAV_FREE(pDataReturnedByOpenAndRead); -} - -#endif //DR_WAV_IMPLEMENTATION - - -// REVISION HISTORY -// -// v0.7a - 2017-11-17 -// - Fix some GCC warnings. -// -// v0.7 - 2017-11-04 -// - Add writing APIs. -// -// v0.6 - 2017-08-16 -// - API CHANGE: Rename dr_* types to drwav_*. -// - Add support for custom implementations of malloc(), realloc(), etc. -// - Add support for Microsoft ADPCM. -// - Add support for IMA ADPCM (DVI, format code 0x11). -// - Optimizations to drwav_read_s16(). -// - Bug fixes. -// -// v0.5g - 2017-07-16 -// - Change underlying type for booleans to unsigned. -// -// v0.5f - 2017-04-04 -// - Fix a minor bug with drwav_open_and_read_s16() and family. -// -// v0.5e - 2016-12-29 -// - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. -// - Minor fixes to documentation. -// -// v0.5d - 2016-12-28 -// - Use drwav_int*/drwav_uint* sized types to improve compiler support. -// -// v0.5c - 2016-11-11 -// - Properly handle JUNK chunks that come before the FMT chunk. -// -// v0.5b - 2016-10-23 -// - A minor change to drwav_bool8 and drwav_bool32 types. -// -// v0.5a - 2016-10-11 -// - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. -// - Improve A-law and mu-law efficiency. -// -// v0.5 - 2016-09-29 -// - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to -// keep it consistent with dr_audio and drwav_flac. -// -// v0.4b - 2016-09-18 -// - Fixed a typo in documentation. -// -// v0.4a - 2016-09-18 -// - Fixed a typo. -// - Change date format to ISO 8601 (YYYY-MM-DD) -// -// v0.4 - 2016-07-13 -// - API CHANGE. Make onSeek consistent with drwav_flac. -// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with drwav_flac. -// - Added support for Sony Wave64. -// -// v0.3a - 2016-05-28 -// - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. -// - Fixed a memory leak. -// -// v0.3 - 2016-05-22 -// - Lots of API changes for consistency. -// -// v0.2a - 2016-05-16 -// - Fixed Linux/GCC build. -// -// v0.2 - 2016-05-11 -// - Added support for reading data as signed 32-bit PCM for consistency with drwav_flac. -// -// v0.1a - 2016-05-07 -// - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. -// -// v0.1 - 2016-05-04 -// - Initial versioned release. - +#endif /* dr_wav_c */ +#endif /* DR_WAV_IMPLEMENTATION */ /* +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. + +v0.12.18 - 2021-01-31 + - Clean up some static analysis warnings. + +v0.12.17 - 2021-01-17 + - Minor fix to sample code in documentation. + - Correctly qualify a private API as private rather than public. + - Code cleanup. + +v0.12.16 - 2020-12-02 + - Fix a bug when trying to read more bytes than can fit in a size_t. + +v0.12.15 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.14 - 2020-11-13 + - Minor code clean up. + +v0.12.13 - 2020-11-01 + - Improve compiler support for older versions of GCC. + +v0.12.12 - 2020-09-28 + - Add support for RF64. + - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section. + +v0.12.11 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.10 - 2020-08-24 + - Fix a bug when seeking with ADPCM formats. + +v0.12.9 - 2020-08-02 + - Simplify sized types. + +v0.12.8 - 2020-07-25 + - Fix a compilation warning. + +v0.12.7 - 2020-07-15 + - Fix some bugs on big-endian architectures. + - Fix an error in s24 to f32 conversion. + +v0.12.6 - 2020-06-23 + - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek. + - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files. + - Add include guard for the implementation section. + +v0.12.5 - 2020-05-27 + - Minor documentation fix. + +v0.12.4 - 2020-05-16 + - Replace assert() with DRWAV_ASSERT(). + - Add compile-time and run-time version querying. + - DRWAV_VERSION_MINOR + - DRWAV_VERSION_MAJOR + - DRWAV_VERSION_REVISION + - DRWAV_VERSION_STRING + - drwav_version() + - drwav_version_string() + +v0.12.3 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.2 - 2020-04-21 + - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file. + +v0.12.1 - 2020-04-13 + - Fix some pedantic warnings. + +v0.12.0 - 2020-04-04 + - API CHANGE: Add container and format parameters to the chunk callback. + - Minor documentation updates. + +v0.11.5 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.11.4 - 2020-01-29 + - Fix some static analysis warnings. + - Fix a bug when reading f32 samples from an A-law encoded stream. + +v0.11.3 - 2020-01-12 + - Minor changes to some f32 format conversion routines. + - Minor bug fix for ADPCM conversion when end of file is reached. + +v0.11.2 - 2019-12-02 + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix an integer overflow bug. + - Fix a null pointer dereference bug. + - Add limits to sample rate, channels and bits per sample to tighten up some validation. + +v0.11.1 - 2019-10-07 + - Internal code clean up. + +v0.11.0 - 2019-10-06 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - 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() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE. + - Add support for reading and writing PCM frames in an explicit endianness. New APIs: + - 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() + - Remove deprecated APIs. + - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data. + - 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() + +v0.10.1 - 2019-08-31 + - Correctly handle partial trailing ADPCM blocks. + +v0.10.0 - 2019-08-04 + - Remove deprecated APIs. + - Add wchar_t variants for file loading APIs: + drwav_init_file_w() + drwav_init_file_ex_w() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count. + - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode: + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write_sequential_pcm_frames() + - Deprecate drwav_open*() and drwav_close(): + 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() + - Minor documentation updates. + +v0.9.2 - 2019-05-21 + - Fix warnings. + +v0.9.1 - 2019-05-05 + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.9.0 - 2018-12-16 + - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and + will be removed in v0.10.0. Deprecated APIs and their replacements: + drwav_read() -> drwav_read_pcm_frames() + drwav_read_s16() -> drwav_read_pcm_frames_s16() + drwav_read_f32() -> drwav_read_pcm_frames_f32() + drwav_read_s32() -> drwav_read_pcm_frames_s32() + drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() + drwav_write() -> drwav_write_pcm_frames() + drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() + drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() + drwav::totalSampleCount -> drwav::totalPCMFrameCount + - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). + - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). + - Add built-in support for smpl chunks. + - Add support for firing a callback for each chunk in the file at initialization time. + - This is enabled through the drwav_init_ex(), etc. family of APIs. + - Handle invalid FMT chunks more robustly. + +v0.8.5 - 2018-09-11 + - Const correctness. + - Fix a potential stack overflow. + +v0.8.4 - 2018-08-07 + - Improve 64-bit detection. + +v0.8.3 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.8.2 - 2018-08-02 + - Fix some big-endian bugs. + +v0.8.1 - 2018-06-29 + - Add support for sequential writing APIs. + - Disable seeking in write mode. + - Fix bugs with Wave64. + - Fix typos. + +v0.8 - 2018-04-27 + - Bug fix. + - Start using major.minor.revision versioning. + +v0.7f - 2018-02-05 + - Restrict ADPCM formats to a maximum of 2 channels. + +v0.7e - 2018-02-02 + - Fix a crash. + +v0.7d - 2018-02-01 + - Fix a crash. + +v0.7c - 2018-02-01 + - Set drwav.bytesPerSample to 0 for all compressed formats. + - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for + all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). + - Fix some divide-by-zero errors. + +v0.7b - 2018-01-22 + - Fix errors with seeking of compressed formats. + - Fix compilation error when DR_WAV_NO_CONVERSION_API + +v0.7a - 2017-11-17 + - Fix some GCC warnings. + +v0.7 - 2017-11-04 + - Add writing APIs. + +v0.6 - 2017-08-16 + - API CHANGE: Rename dr_* types to drwav_*. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add support for Microsoft ADPCM. + - Add support for IMA ADPCM (DVI, format code 0x11). + - Optimizations to drwav_read_s16(). + - Bug fixes. + +v0.5g - 2017-07-16 + - Change underlying type for booleans to unsigned. + +v0.5f - 2017-04-04 + - Fix a minor bug with drwav_open_and_read_s16() and family. + +v0.5e - 2016-12-29 + - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. + - Minor fixes to documentation. + +v0.5d - 2016-12-28 + - Use drwav_int* and drwav_uint* sized types to improve compiler support. + +v0.5c - 2016-11-11 + - Properly handle JUNK chunks that come before the FMT chunk. + +v0.5b - 2016-10-23 + - A minor change to drwav_bool8 and drwav_bool32 types. + +v0.5a - 2016-10-11 + - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. + - Improve A-law and mu-law efficiency. + +v0.5 - 2016-09-29 + - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to + keep it consistent with dr_audio and dr_flac. + +v0.4b - 2016-09-18 + - Fixed a typo in documentation. + +v0.4a - 2016-09-18 + - Fixed a typo. + - Change date format to ISO 8601 (YYYY-MM-DD) + +v0.4 - 2016-07-13 + - API CHANGE. Make onSeek consistent with dr_flac. + - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. + - Added support for Sony Wave64. + +v0.3a - 2016-05-28 + - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. + - Fixed a memory leak. + +v0.3 - 2016-05-22 + - Lots of API changes for consistency. + +v0.2a - 2016-05-16 + - Fixed Linux/GCC build. + +v0.2 - 2016-05-11 + - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. + +v0.1a - 2016-05-07 + - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. + +v0.1 - 2016-05-04 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - 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. +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. +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. +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. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2023 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 +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. + +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/glad.h b/raylib/external/glad.h index 70dbc73..5bb79d4 100644 --- a/raylib/external/glad.h +++ b/raylib/external/glad.h @@ -1,613 +1,300 @@ -/* +/** + * 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 + * + */ - 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_ +#ifndef GLAD_GL_H_ +#define GLAD_GL_H_ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif #ifdef __gl_h_ -#error OpenGL header already included, remove this include, glad already provides it + #error OpenGL (gl.h) header already included (API: gl), remove previous include! #endif -#define __gl_h_ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 +#define __gl_h_ 1 +#ifdef __gl3_h_ + #error OpenGL (gl3.h) header already included (API: gl), remove previous include! #endif -//#include -#define APIENTRY __stdcall // RAY: Added +#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 #endif -#ifndef APIENTRY -#define APIENTRY -#endif -#ifndef APIENTRYP -#define APIENTRYP APIENTRY * -#endif +#define GLAD_GL +#define GLAD_OPTION_GL_HEADER_ONLY #ifdef __cplusplus extern "C" { #endif -struct gladGLversionStruct { - int major; - int minor; -}; +#ifndef GLAD_PLATFORM_H_ +#define GLAD_PLATFORM_H_ -typedef void* (* GLADloadproc)(const char *name); +#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 -# 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 +#define GLAPI GLAD_API_CALL #endif -GLAPI struct gladGLversionStruct GLVersion; -GLAPI int gladLoadGLLoader(GLADloadproc); +#ifndef GLAPIENTRY +#define GLAPIENTRY GLAD_API_PTR +#endif -#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 -#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_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_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_CLAMP_TO_EDGE 0x812F -#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 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_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_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 +#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_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_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_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_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 @@ -616,162 +303,29 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 -#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 0x1800 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #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 @@ -782,1536 +336,576 @@ typedef GLintptr GLvdpauSurfaceNV; #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_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#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_MAX_SAMPLES 0x8D57 -#define GL_INDEX 0x8222 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#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_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_SIGNED_R11_EAC 0x9271 +#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_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_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_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_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_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_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_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_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 @@ -2322,6 +916,7 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; #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 @@ -2332,1460 +927,7441 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; #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_FRAGMENT_SHADER_ARB 0x8B30 +#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_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 -#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#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_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 -#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D -#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_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 -#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#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_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 -#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_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_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_ALPHA16F_ARB 0x881C -#define GL_INTENSITY16F_ARB 0x881D -#define GL_LUMINANCE16F_ARB 0x881E -#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#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_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_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_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_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_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_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_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 0x8642 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 -#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 0x8B31 #define GL_VERTEX_SHADER_ARB 0x8B31 -#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 +#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 #endif -#ifndef GL_AMD_query_buffer_object -#define GL_AMD_query_buffer_object 1 -GLAPI int GLAD_GL_AMD_query_buffer_object; + +/*------------------------------------------------------------------------- + * 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 -#ifndef GL_ARB_ES2_compatibility + +/*------------------------------------------------------------------------- + * 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; #define GL_ARB_ES2_compatibility 1 -GLAPI int GLAD_GL_ARB_ES2_compatibility; -typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(); -GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; -#define glReleaseShaderCompiler glad_glReleaseShaderCompiler -typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); -GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; -#define glShaderBinary glad_glShaderBinary -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 +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 -GLAPI int GLAD_GL_ARB_ES3_compatibility; -#endif -#ifndef GL_ARB_buffer_storage +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 -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 +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 -GLAPI int GLAD_GL_ARB_compatibility; -#endif -#ifndef GL_ARB_compressed_texture_pixel_storage +GLAD_API_CALL int GLAD_GL_ARB_compatibility; #define GL_ARB_compressed_texture_pixel_storage 1 -GLAPI int GLAD_GL_ARB_compressed_texture_pixel_storage; -#endif -#ifndef GL_ARB_debug_output +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 -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 +GLAD_API_CALL int GLAD_GL_ARB_debug_output; #define GL_ARB_depth_buffer_float 1 -GLAPI int GLAD_GL_ARB_depth_buffer_float; -#endif -#ifndef GL_ARB_depth_clamp +GLAD_API_CALL int GLAD_GL_ARB_depth_buffer_float; #define GL_ARB_depth_clamp 1 -GLAPI int GLAD_GL_ARB_depth_clamp; -#endif -#ifndef GL_ARB_depth_texture +GLAD_API_CALL int GLAD_GL_ARB_depth_clamp; #define GL_ARB_depth_texture 1 -GLAPI int GLAD_GL_ARB_depth_texture; -#endif -#ifndef GL_ARB_draw_buffers +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 -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 +GLAD_API_CALL int GLAD_GL_ARB_draw_buffers; #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 +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 -GLAPI int GLAD_GL_ARB_explicit_attrib_location; -#endif -#ifndef GL_ARB_explicit_uniform_location +GLAD_API_CALL int GLAD_GL_ARB_explicit_attrib_location; #define GL_ARB_explicit_uniform_location 1 -GLAPI int GLAD_GL_ARB_explicit_uniform_location; -#endif -#ifndef GL_ARB_fragment_program +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 -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 +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 -GLAPI int GLAD_GL_ARB_fragment_shader; -#endif -#ifndef GL_ARB_framebuffer_object +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 -GLAPI int GLAD_GL_ARB_framebuffer_object; -#endif -#ifndef GL_ARB_framebuffer_sRGB +GLAD_API_CALL int GLAD_GL_ARB_framebuffer_object; #define GL_ARB_framebuffer_sRGB 1 -GLAPI int GLAD_GL_ARB_framebuffer_sRGB; -#endif -#ifndef GL_ARB_multisample +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 -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 +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 -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 +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 -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 +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 -GLAPI int GLAD_GL_ARB_texture_float; -#endif -#ifndef GL_ARB_texture_multisample +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 -GLAPI int GLAD_GL_ARB_texture_multisample; -#endif -#ifndef GL_ARB_texture_non_power_of_two +GLAD_API_CALL int GLAD_GL_ARB_texture_multisample; #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 +GLAD_API_CALL int GLAD_GL_ARB_texture_non_power_of_two; #define GL_ARB_texture_rg 1 -GLAPI int GLAD_GL_ARB_texture_rg; -#endif -#ifndef GL_ARB_texture_swizzle +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 -GLAPI int GLAD_GL_ARB_texture_swizzle; -#endif -#ifndef GL_ARB_uniform_buffer_object +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 -GLAPI int GLAD_GL_ARB_uniform_buffer_object; -#endif -#ifndef GL_ARB_vertex_array_object +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 -GLAPI int GLAD_GL_ARB_vertex_array_object; -#endif -#ifndef GL_ARB_vertex_attrib_binding +GLAD_API_CALL int GLAD_GL_ARB_vertex_array_object; #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 -typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat; -#define glVertexAttribIFormat glad_glVertexAttribIFormat -typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat; -#define glVertexAttribLFormat glad_glVertexAttribLFormat -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 -#endif -#ifndef GL_ARB_vertex_buffer_object +GLAD_API_CALL int GLAD_GL_ARB_vertex_attrib_binding; #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 +GLAD_API_CALL int GLAD_GL_ARB_vertex_buffer_object; #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 +GLAD_API_CALL int GLAD_GL_ARB_vertex_program; #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 +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 -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 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit; #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 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_multisample; #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 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_object; #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 +GLAD_API_CALL int GLAD_GL_EXT_framebuffer_sRGB; #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 +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; +#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; +#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; +#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; +#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; +#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; +#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); + + #ifdef __cplusplus } #endif - #endif -////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION SECTION -// - -#ifdef GLAD_IMPLEMENTATION - +/* Source */ +#ifdef GLAD_GL_IMPLEMENTATION #include #include #include -struct gladGLversionStruct GLVersion; +#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"); +} + + #if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) -#define _GLAD_IS_SOME_NEW_VERSION 1 +#define GLAD_GL_IS_SOME_NEW_VERSION 1 +#else +#define GLAD_GL_IS_SOME_NEW_VERSION 0 #endif -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) { +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 - exts = (const char *)glGetString(GL_EXTENSIONS); -#ifdef _GLAD_IS_SOME_NEW_VERSION - } else { - int index; - - num_exts_i = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); - if (num_exts_i > 0) { - exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i); + 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 **) GLAD_MALLOC(num_exts_i * (sizeof *exts_i)); } - if (exts_i == NULL) { return 0; } - for(index = 0; index < num_exts_i; index++) { - exts_i[index] = (const char*)glGetStringi(GL_EXTENSIONS, 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; } + + *out_num_exts_i = num_exts_i; + *out_exts_i = exts_i; } #endif return 1; } - -static void free_exts(void) { +static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) { if (exts_i != NULL) { - free((char **)exts_i); + unsigned int index; + for(index = 0; index < num_exts_i; index++) { + GLAD_FREE((void *) (exts_i[index])); + } + GLAD_FREE((void *)exts_i); exts_i = NULL; } } - -static int has_ext(const char *ext) { -#ifdef _GLAD_IS_SOME_NEW_VERSION - if(max_loaded_major < 3) { -#endif +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; @@ -3793,13 +8369,11 @@ static int has_ext(const char *ext) { 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')) { @@ -3807,1574 +8381,164 @@ static int has_ext(const char *ext) { } extensions = terminator; } -#ifdef _GLAD_IS_SOME_NEW_VERSION } else { - int index; - + unsigned 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; } -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 GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { + return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); } -static void find_coreGL(void) { +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; - /* 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_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"); + 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 }; - - version = (const char*) glGetString(GL_VERSION); - if (!version) return; - + 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) { @@ -5383,84 +8547,136 @@ static void find_coreGL(void) { } } -/* PR #18 */ -#ifdef _MSC_VER - sscanf_s(version, "%d.%d", &major, &minor); -#else - sscanf(version, "%d.%d", &major, &minor); + 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 +} #endif - 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; - } -} +#endif /* GLAD_GL_IMPLEMENTATION */ -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 new file mode 100644 index 0000000..6c753d0 --- /dev/null +++ b/raylib/external/glad_gles2.h @@ -0,0 +1,4774 @@ +/** + * 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/COPYING.txt b/raylib/external/glfw/LICENSE.md similarity index 93% rename from raylib/external/glfw/COPYING.txt rename to raylib/external/glfw/LICENSE.md index ad16462..7494a3f 100644 --- a/raylib/external/glfw/COPYING.txt +++ b/raylib/external/glfw/LICENSE.md @@ -1,5 +1,6 @@ Copyright (c) 2002-2006 Marcus Geelnard -Copyright (c) 2006-2016 Camilla Berglund + +Copyright (c) 2006-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 diff --git a/raylib/external/glfw/deps/KHR/khrplatform.h b/raylib/external/glfw/deps/KHR/khrplatform.h deleted file mode 100644 index c9e6f17..0000000 --- a/raylib/external/glfw/deps/KHR/khrplatform.h +++ /dev/null @@ -1,282 +0,0 @@ -#ifndef __khrplatform_h_ -#define __khrplatform_h_ - -/* -** Copyright (c) 2008-2009 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. - * - * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ - * - * 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 sending them to the public Khronos Bugzilla - * (http://khronos.org/bugzilla) by filing a bug against product - * "Khronos (general)" component "Registry". - * - * A predefined template which fills in some of the bug fields can be - * reached using http://tinyurl.com/khrplatform-h-bugreport, but you - * must create a Bugzilla login first. - * - * - * 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 -#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/mingw/_mingw_dxhelper.h b/raylib/external/glfw/deps/mingw/_mingw_dxhelper.h deleted file mode 100644 index 849e291..0000000 --- a/raylib/external/glfw/deps/mingw/_mingw_dxhelper.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * 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 deleted file mode 100644 index b575480..0000000 --- a/raylib/external/glfw/deps/mingw/dinput.h +++ /dev/null @@ -1,2467 +0,0 @@ -/* - * 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 deleted file mode 100644 index d3ca726..0000000 --- a/raylib/external/glfw/deps/mingw/xinput.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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 deleted file mode 100644 index d02608a..0000000 --- a/raylib/external/glfw/deps/vs2008/stdint.h +++ /dev/null @@ -1,247 +0,0 @@ -// 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/deps/vulkan/vk_platform.h b/raylib/external/glfw/deps/vulkan/vk_platform.h deleted file mode 100644 index 8e21a17..0000000 --- a/raylib/external/glfw/deps/vulkan/vk_platform.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// 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/vulkan/vulkan.h b/raylib/external/glfw/deps/vulkan/vulkan.h deleted file mode 100644 index bf35a3a..0000000 --- a/raylib/external/glfw/deps/vulkan/vulkan.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef VULKAN_H_ -#define VULKAN_H_ 1 - -/* -** Copyright (c) 2015-2018 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. -*/ - -#include "vk_platform.h" -#include "vulkan_core.h" - -#ifdef VK_USE_PLATFORM_ANDROID_KHR -#include "vulkan_android.h" -#endif - - -#ifdef VK_USE_PLATFORM_IOS_MVK -#include "vulkan_ios.h" -#endif - - -#ifdef VK_USE_PLATFORM_MACOS_MVK -#include "vulkan_macos.h" -#endif - - -#ifdef VK_USE_PLATFORM_MIR_KHR -#include -#include "vulkan_mir.h" -#endif - - -#ifdef VK_USE_PLATFORM_VI_NN -#include "vulkan_vi.h" -#endif - - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR -#include -#include "vulkan_wayland.h" -#endif - - -#ifdef VK_USE_PLATFORM_WIN32_KHR -#include -#include "vulkan_win32.h" -#endif - - -#ifdef VK_USE_PLATFORM_XCB_KHR -#include -#include "vulkan_xcb.h" -#endif - - -#ifdef VK_USE_PLATFORM_XLIB_KHR -#include -#include "vulkan_xlib.h" -#endif - - -#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT -#include -#include -#include "vulkan_xlib_xrandr.h" -#endif - -#endif // VULKAN_H_ diff --git a/raylib/external/glfw/deps/vulkan/vulkan_core.h b/raylib/external/glfw/deps/vulkan/vulkan_core.h deleted file mode 100644 index 20dccc1..0000000 --- a/raylib/external/glfw/deps/vulkan/vulkan_core.h +++ /dev/null @@ -1,7334 +0,0 @@ -#ifndef VULKAN_CORE_H_ -#define VULKAN_CORE_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** Copyright (c) 2015-2018 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. -*/ - -/* -** This header is generated from the Khronos Vulkan XML API Registry. -** -*/ - - -#define VK_VERSION_1_0 1 -#include "vk_platform.h" - -#define VK_MAKE_VERSION(major, minor, patch) \ - (((major) << 22) | ((minor) << 12) | (patch)) - -// 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 - -#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) -// Version of this file -#define VK_HEADER_VERSION 70 - - -#define VK_NULL_HANDLE 0 - - - -#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 - - - -typedef uint32_t VkFlags; -typedef uint32_t VkBool32; -typedef uint64_t VkDeviceSize; -typedef uint32_t VkSampleMask; - -VK_DEFINE_HANDLE(VkInstance) -VK_DEFINE_HANDLE(VkPhysicalDevice) -VK_DEFINE_HANDLE(VkDevice) -VK_DEFINE_HANDLE(VkQueue) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) -VK_DEFINE_HANDLE(VkCommandBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) - -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -#define VK_TRUE 1 -#define VK_FALSE 0 -#define VK_QUEUE_FAMILY_IGNORED (~0U) -#define VK_SUBPASS_EXTERNAL (~0U) -#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 -#define VK_UUID_SIZE 16 -#define VK_MAX_MEMORY_TYPES 32 -#define VK_MAX_MEMORY_HEAPS 16 -#define VK_MAX_EXTENSION_NAME_SIZE 256 -#define VK_MAX_DESCRIPTION_SIZE 256 - - -typedef enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, - VK_PIPELINE_CACHE_HEADER_VERSION_BEGIN_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_END_RANGE = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, - VK_PIPELINE_CACHE_HEADER_VERSION_RANGE_SIZE = (VK_PIPELINE_CACHE_HEADER_VERSION_ONE - VK_PIPELINE_CACHE_HEADER_VERSION_ONE + 1), - VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCacheHeaderVersion; - -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_INCOMPATIBLE_DISPLAY_KHR = -1000003001, - VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, - VK_ERROR_INVALID_SHADER_NV = -1000012000, - VK_ERROR_NOT_PERMITTED_EXT = -1000174001, - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, - VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL, - VK_RESULT_END_RANGE = VK_INCOMPLETE, - VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1), - VK_RESULT_MAX_ENUM = 0x7FFFFFFF -} VkResult; - -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_POINTER_FEATURES = 1000120000, - 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_PARAMETER_FEATURES = 1000063000, - 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_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, - VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, - VK_STRUCTURE_TYPE_DISPLAY_PRESENT_INFO_KHR = 1000003000, - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, - VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, - VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, - VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, - VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, - VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, - VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR = 1000074002, - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, - VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, - VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, - VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, - VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, - VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, - VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, - VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, - VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, - VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, - VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, - VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, - VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, - VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, - VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, - VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, - VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, - VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, - VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, - VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, - VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, - VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, - VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, - VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, - VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, - VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, - VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, - VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, - VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, - VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO, - VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1), - VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF -} 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, - VK_SYSTEM_ALLOCATION_SCOPE_BEGIN_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND, - VK_SYSTEM_ALLOCATION_SCOPE_END_RANGE = VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE, - VK_SYSTEM_ALLOCATION_SCOPE_RANGE_SIZE = (VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND + 1), - VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF -} VkSystemAllocationScope; - -typedef enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, - VK_INTERNAL_ALLOCATION_TYPE_BEGIN_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_END_RANGE = VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE, - VK_INTERNAL_ALLOCATION_TYPE_RANGE_SIZE = (VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE + 1), - VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkInternalAllocationType; - -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, - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, - VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, - VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, - VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, - VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, - VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, - VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, - VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, - VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, - VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED, - VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK, - VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1), - VK_FORMAT_MAX_ENUM = 0x7FFFFFFF -} VkFormat; - -typedef enum VkImageType { - VK_IMAGE_TYPE_1D = 0, - VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2, - VK_IMAGE_TYPE_BEGIN_RANGE = VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_END_RANGE = VK_IMAGE_TYPE_3D, - VK_IMAGE_TYPE_RANGE_SIZE = (VK_IMAGE_TYPE_3D - VK_IMAGE_TYPE_1D + 1), - VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageType; - -typedef enum VkImageTiling { - VK_IMAGE_TILING_OPTIMAL = 0, - VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, - VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), - VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF -} VkImageTiling; - -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, - VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE = VK_PHYSICAL_DEVICE_TYPE_OTHER, - VK_PHYSICAL_DEVICE_TYPE_END_RANGE = VK_PHYSICAL_DEVICE_TYPE_CPU, - VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE = (VK_PHYSICAL_DEVICE_TYPE_CPU - VK_PHYSICAL_DEVICE_TYPE_OTHER + 1), - VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkPhysicalDeviceType; - -typedef enum VkQueryType { - VK_QUERY_TYPE_OCCLUSION = 0, - VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, - VK_QUERY_TYPE_TIMESTAMP = 2, - VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, - VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, - VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), - VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkQueryType; - -typedef enum VkSharingMode { - VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1, - VK_SHARING_MODE_BEGIN_RANGE = VK_SHARING_MODE_EXCLUSIVE, - VK_SHARING_MODE_END_RANGE = VK_SHARING_MODE_CONCURRENT, - VK_SHARING_MODE_RANGE_SIZE = (VK_SHARING_MODE_CONCURRENT - VK_SHARING_MODE_EXCLUSIVE + 1), - VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSharingMode; - -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, - VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_BEGIN_RANGE = VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_END_RANGE = VK_IMAGE_LAYOUT_PREINITIALIZED, - VK_IMAGE_LAYOUT_RANGE_SIZE = (VK_IMAGE_LAYOUT_PREINITIALIZED - VK_IMAGE_LAYOUT_UNDEFINED + 1), - VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF -} VkImageLayout; - -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, - VK_IMAGE_VIEW_TYPE_BEGIN_RANGE = VK_IMAGE_VIEW_TYPE_1D, - VK_IMAGE_VIEW_TYPE_END_RANGE = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, - VK_IMAGE_VIEW_TYPE_RANGE_SIZE = (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY - VK_IMAGE_VIEW_TYPE_1D + 1), - VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkImageViewType; - -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, - VK_COMPONENT_SWIZZLE_BEGIN_RANGE = VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_END_RANGE = VK_COMPONENT_SWIZZLE_A, - VK_COMPONENT_SWIZZLE_RANGE_SIZE = (VK_COMPONENT_SWIZZLE_A - VK_COMPONENT_SWIZZLE_IDENTITY + 1), - VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF -} VkComponentSwizzle; - -typedef enum VkVertexInputRate { - VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1, - VK_VERTEX_INPUT_RATE_BEGIN_RANGE = VK_VERTEX_INPUT_RATE_VERTEX, - VK_VERTEX_INPUT_RATE_END_RANGE = VK_VERTEX_INPUT_RATE_INSTANCE, - VK_VERTEX_INPUT_RATE_RANGE_SIZE = (VK_VERTEX_INPUT_RATE_INSTANCE - VK_VERTEX_INPUT_RATE_VERTEX + 1), - VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF -} VkVertexInputRate; - -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, - VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - VK_PRIMITIVE_TOPOLOGY_END_RANGE = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, - VK_PRIMITIVE_TOPOLOGY_RANGE_SIZE = (VK_PRIMITIVE_TOPOLOGY_PATCH_LIST - VK_PRIMITIVE_TOPOLOGY_POINT_LIST + 1), - VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF -} VkPrimitiveTopology; - -typedef enum VkPolygonMode { - VK_POLYGON_MODE_FILL = 0, - VK_POLYGON_MODE_LINE = 1, - VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, - VK_POLYGON_MODE_BEGIN_RANGE = VK_POLYGON_MODE_FILL, - VK_POLYGON_MODE_END_RANGE = VK_POLYGON_MODE_POINT, - VK_POLYGON_MODE_RANGE_SIZE = (VK_POLYGON_MODE_POINT - VK_POLYGON_MODE_FILL + 1), - VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF -} VkPolygonMode; - -typedef enum VkFrontFace { - VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1, - VK_FRONT_FACE_BEGIN_RANGE = VK_FRONT_FACE_COUNTER_CLOCKWISE, - VK_FRONT_FACE_END_RANGE = VK_FRONT_FACE_CLOCKWISE, - VK_FRONT_FACE_RANGE_SIZE = (VK_FRONT_FACE_CLOCKWISE - VK_FRONT_FACE_COUNTER_CLOCKWISE + 1), - VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF -} VkFrontFace; - -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, - VK_COMPARE_OP_BEGIN_RANGE = VK_COMPARE_OP_NEVER, - VK_COMPARE_OP_END_RANGE = VK_COMPARE_OP_ALWAYS, - VK_COMPARE_OP_RANGE_SIZE = (VK_COMPARE_OP_ALWAYS - VK_COMPARE_OP_NEVER + 1), - VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF -} VkCompareOp; - -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, - VK_STENCIL_OP_BEGIN_RANGE = VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_END_RANGE = VK_STENCIL_OP_DECREMENT_AND_WRAP, - VK_STENCIL_OP_RANGE_SIZE = (VK_STENCIL_OP_DECREMENT_AND_WRAP - VK_STENCIL_OP_KEEP + 1), - VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF -} VkStencilOp; - -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, - VK_LOGIC_OP_BEGIN_RANGE = VK_LOGIC_OP_CLEAR, - VK_LOGIC_OP_END_RANGE = VK_LOGIC_OP_SET, - VK_LOGIC_OP_RANGE_SIZE = (VK_LOGIC_OP_SET - VK_LOGIC_OP_CLEAR + 1), - VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF -} VkLogicOp; - -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, - VK_BLEND_FACTOR_BEGIN_RANGE = VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_END_RANGE = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, - VK_BLEND_FACTOR_RANGE_SIZE = (VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA - VK_BLEND_FACTOR_ZERO + 1), - VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF -} 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, - VK_BLEND_OP_ZERO_EXT = 1000148000, - VK_BLEND_OP_SRC_EXT = 1000148001, - VK_BLEND_OP_DST_EXT = 1000148002, - VK_BLEND_OP_SRC_OVER_EXT = 1000148003, - VK_BLEND_OP_DST_OVER_EXT = 1000148004, - VK_BLEND_OP_SRC_IN_EXT = 1000148005, - VK_BLEND_OP_DST_IN_EXT = 1000148006, - VK_BLEND_OP_SRC_OUT_EXT = 1000148007, - VK_BLEND_OP_DST_OUT_EXT = 1000148008, - VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, - VK_BLEND_OP_DST_ATOP_EXT = 1000148010, - VK_BLEND_OP_XOR_EXT = 1000148011, - VK_BLEND_OP_MULTIPLY_EXT = 1000148012, - VK_BLEND_OP_SCREEN_EXT = 1000148013, - VK_BLEND_OP_OVERLAY_EXT = 1000148014, - VK_BLEND_OP_DARKEN_EXT = 1000148015, - VK_BLEND_OP_LIGHTEN_EXT = 1000148016, - VK_BLEND_OP_COLORDODGE_EXT = 1000148017, - VK_BLEND_OP_COLORBURN_EXT = 1000148018, - VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, - VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, - VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, - VK_BLEND_OP_EXCLUSION_EXT = 1000148022, - VK_BLEND_OP_INVERT_EXT = 1000148023, - VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, - VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, - VK_BLEND_OP_LINEARBURN_EXT = 1000148026, - VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, - VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, - VK_BLEND_OP_PINLIGHT_EXT = 1000148029, - VK_BLEND_OP_HARDMIX_EXT = 1000148030, - VK_BLEND_OP_HSL_HUE_EXT = 1000148031, - VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, - VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, - VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, - VK_BLEND_OP_PLUS_EXT = 1000148035, - VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, - VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, - VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, - VK_BLEND_OP_MINUS_EXT = 1000148039, - VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, - VK_BLEND_OP_CONTRAST_EXT = 1000148041, - VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, - VK_BLEND_OP_RED_EXT = 1000148043, - VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045, - VK_BLEND_OP_BEGIN_RANGE = VK_BLEND_OP_ADD, - VK_BLEND_OP_END_RANGE = VK_BLEND_OP_MAX, - VK_BLEND_OP_RANGE_SIZE = (VK_BLEND_OP_MAX - VK_BLEND_OP_ADD + 1), - VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF -} VkBlendOp; - -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_VIEWPORT_W_SCALING_NV = 1000087000, - VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, - VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, - VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1), - VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF -} VkDynamicState; - -typedef enum VkFilter { - VK_FILTER_NEAREST = 0, - VK_FILTER_LINEAR = 1, - VK_FILTER_CUBIC_IMG = 1000015000, - VK_FILTER_BEGIN_RANGE = VK_FILTER_NEAREST, - VK_FILTER_END_RANGE = VK_FILTER_LINEAR, - VK_FILTER_RANGE_SIZE = (VK_FILTER_LINEAR - VK_FILTER_NEAREST + 1), - VK_FILTER_MAX_ENUM = 0x7FFFFFFF -} VkFilter; - -typedef enum VkSamplerMipmapMode { - VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, - VK_SAMPLER_MIPMAP_MODE_BEGIN_RANGE = VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_END_RANGE = VK_SAMPLER_MIPMAP_MODE_LINEAR, - VK_SAMPLER_MIPMAP_MODE_RANGE_SIZE = (VK_SAMPLER_MIPMAP_MODE_LINEAR - VK_SAMPLER_MIPMAP_MODE_NEAREST + 1), - VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerMipmapMode; - -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, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_BEGIN_RANGE = VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_END_RANGE = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, - VK_SAMPLER_ADDRESS_MODE_RANGE_SIZE = (VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER - VK_SAMPLER_ADDRESS_MODE_REPEAT + 1), - VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerAddressMode; - -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, - VK_BORDER_COLOR_BEGIN_RANGE = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - VK_BORDER_COLOR_END_RANGE = VK_BORDER_COLOR_INT_OPAQUE_WHITE, - VK_BORDER_COLOR_RANGE_SIZE = (VK_BORDER_COLOR_INT_OPAQUE_WHITE - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK + 1), - VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF -} VkBorderColor; - -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, - VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, - VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), - VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorType; - -typedef enum VkAttachmentLoadOp { - VK_ATTACHMENT_LOAD_OP_LOAD = 0, - VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_BEGIN_RANGE = VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_LOAD_OP_END_RANGE = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_LOAD_OP_RANGE_SIZE = (VK_ATTACHMENT_LOAD_OP_DONT_CARE - VK_ATTACHMENT_LOAD_OP_LOAD + 1), - VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentLoadOp; - -typedef enum VkAttachmentStoreOp { - VK_ATTACHMENT_STORE_OP_STORE = 0, - VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_BEGIN_RANGE = VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_STORE_OP_END_RANGE = VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_RANGE_SIZE = (VK_ATTACHMENT_STORE_OP_DONT_CARE - VK_ATTACHMENT_STORE_OP_STORE + 1), - VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentStoreOp; - -typedef enum VkPipelineBindPoint { - VK_PIPELINE_BIND_POINT_GRAPHICS = 0, - VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, - VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, - VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), - VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF -} VkPipelineBindPoint; - -typedef enum VkCommandBufferLevel { - VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, - VK_COMMAND_BUFFER_LEVEL_BEGIN_RANGE = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - VK_COMMAND_BUFFER_LEVEL_END_RANGE = VK_COMMAND_BUFFER_LEVEL_SECONDARY, - VK_COMMAND_BUFFER_LEVEL_RANGE_SIZE = (VK_COMMAND_BUFFER_LEVEL_SECONDARY - VK_COMMAND_BUFFER_LEVEL_PRIMARY + 1), - VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferLevel; - -typedef enum VkIndexType { - VK_INDEX_TYPE_UINT16 = 0, - VK_INDEX_TYPE_UINT32 = 1, - VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, - VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, - VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), - VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkIndexType; - -typedef enum VkSubpassContents { - VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, - VK_SUBPASS_CONTENTS_BEGIN_RANGE = VK_SUBPASS_CONTENTS_INLINE, - VK_SUBPASS_CONTENTS_END_RANGE = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, - VK_SUBPASS_CONTENTS_RANGE_SIZE = (VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS - VK_SUBPASS_CONTENTS_INLINE + 1), - VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF -} VkSubpassContents; - -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_DISPLAY_KHR = 1000002000, - VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, - VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000, - VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, - VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, - VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, - VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL, - VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1), - VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkObjectType; - -typedef VkFlags VkInstanceCreateFlags; - -typedef enum VkFormatFeatureFlagBits { - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, - VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, - VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, - VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, - VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, - VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, - VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, - VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFormatFeatureFlagBits; -typedef VkFlags VkFormatFeatureFlags; - -typedef enum VkImageUsageFlagBits { - VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, - VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, - VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageUsageFlagBits; -typedef VkFlags VkImageUsageFlags; - -typedef enum VkImageCreateFlagBits { - VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, - VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, - VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, - VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, - VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, - VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, - VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, - VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, - VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageCreateFlagBits; -typedef VkFlags VkImageCreateFlags; - -typedef enum VkSampleCountFlagBits { - VK_SAMPLE_COUNT_1_BIT = 0x00000001, - VK_SAMPLE_COUNT_2_BIT = 0x00000002, - VK_SAMPLE_COUNT_4_BIT = 0x00000004, - VK_SAMPLE_COUNT_8_BIT = 0x00000008, - VK_SAMPLE_COUNT_16_BIT = 0x00000010, - VK_SAMPLE_COUNT_32_BIT = 0x00000020, - VK_SAMPLE_COUNT_64_BIT = 0x00000040, - VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSampleCountFlagBits; -typedef VkFlags VkSampleCountFlags; - -typedef enum VkQueueFlagBits { - VK_QUEUE_GRAPHICS_BIT = 0x00000001, - VK_QUEUE_COMPUTE_BIT = 0x00000002, - VK_QUEUE_TRANSFER_BIT = 0x00000004, - VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, - VK_QUEUE_PROTECTED_BIT = 0x00000010, - VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueueFlagBits; -typedef VkFlags VkQueueFlags; - -typedef enum VkMemoryPropertyFlagBits { - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, - VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, - VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, - VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryPropertyFlagBits; -typedef VkFlags VkMemoryPropertyFlags; - -typedef enum VkMemoryHeapFlagBits { - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, - VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryHeapFlagBits; -typedef VkFlags VkMemoryHeapFlags; -typedef VkFlags VkDeviceCreateFlags; - -typedef enum VkDeviceQueueCreateFlagBits { - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, - VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDeviceQueueCreateFlagBits; -typedef VkFlags VkDeviceQueueCreateFlags; - -typedef enum VkPipelineStageFlagBits { - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, - VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, - VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, - VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, - VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, - VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, - VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, - VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineStageFlagBits; -typedef VkFlags VkPipelineStageFlags; -typedef VkFlags VkMemoryMapFlags; - -typedef enum VkImageAspectFlagBits { - VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, - VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, - VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, - VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, - VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, - VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, - VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, - VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkImageAspectFlagBits; -typedef VkFlags VkImageAspectFlags; - -typedef enum VkSparseImageFormatFlagBits { - VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, - VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, - VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseImageFormatFlagBits; -typedef VkFlags VkSparseImageFormatFlags; - -typedef enum VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, - VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSparseMemoryBindFlagBits; -typedef VkFlags VkSparseMemoryBindFlags; - -typedef enum VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, - VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFenceCreateFlagBits; -typedef VkFlags VkFenceCreateFlags; -typedef VkFlags VkSemaphoreCreateFlags; -typedef VkFlags VkEventCreateFlags; -typedef VkFlags VkQueryPoolCreateFlags; - -typedef enum VkQueryPipelineStatisticFlagBits { - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, - VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryPipelineStatisticFlagBits; -typedef VkFlags VkQueryPipelineStatisticFlags; - -typedef enum VkQueryResultFlagBits { - VK_QUERY_RESULT_64_BIT = 0x00000001, - VK_QUERY_RESULT_WAIT_BIT = 0x00000002, - VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, - VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, - VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryResultFlagBits; -typedef VkFlags VkQueryResultFlags; - -typedef enum VkBufferCreateFlagBits { - VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, - VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferCreateFlagBits; -typedef VkFlags VkBufferCreateFlags; - -typedef enum VkBufferUsageFlagBits { - VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, - VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkBufferUsageFlagBits; -typedef VkFlags VkBufferUsageFlags; -typedef VkFlags VkBufferViewCreateFlags; -typedef VkFlags VkImageViewCreateFlags; -typedef VkFlags VkShaderModuleCreateFlags; -typedef VkFlags VkPipelineCacheCreateFlags; - -typedef enum VkPipelineCreateFlagBits { - VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, - VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, - VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, - VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPipelineCreateFlagBits; -typedef VkFlags VkPipelineCreateFlags; -typedef VkFlags VkPipelineShaderStageCreateFlags; - -typedef enum VkShaderStageFlagBits { - VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, - VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, - VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, - VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, - VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkShaderStageFlagBits; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; -typedef VkFlags VkPipelineTessellationStateCreateFlags; -typedef VkFlags VkPipelineViewportStateCreateFlags; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; - -typedef enum VkCullModeFlagBits { - VK_CULL_MODE_NONE = 0, - VK_CULL_MODE_FRONT_BIT = 0x00000001, - VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, - VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCullModeFlagBits; -typedef VkFlags VkCullModeFlags; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; - -typedef enum VkColorComponentFlagBits { - VK_COLOR_COMPONENT_R_BIT = 0x00000001, - VK_COLOR_COMPONENT_G_BIT = 0x00000002, - VK_COLOR_COMPONENT_B_BIT = 0x00000004, - VK_COLOR_COMPONENT_A_BIT = 0x00000008, - VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkColorComponentFlagBits; -typedef VkFlags VkColorComponentFlags; -typedef VkFlags VkPipelineDynamicStateCreateFlags; -typedef VkFlags VkPipelineLayoutCreateFlags; -typedef VkFlags VkShaderStageFlags; -typedef VkFlags VkSamplerCreateFlags; - -typedef enum VkDescriptorSetLayoutCreateFlagBits { - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorSetLayoutCreateFlagBits; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; - -typedef enum VkDescriptorPoolCreateFlagBits { - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorPoolCreateFlagBits; -typedef VkFlags VkDescriptorPoolCreateFlags; -typedef VkFlags VkDescriptorPoolResetFlags; -typedef VkFlags VkFramebufferCreateFlags; -typedef VkFlags VkRenderPassCreateFlags; - -typedef enum VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, - VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAttachmentDescriptionFlagBits; -typedef VkFlags VkAttachmentDescriptionFlags; - -typedef enum VkSubpassDescriptionFlagBits { - VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, - VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, - VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSubpassDescriptionFlagBits; -typedef VkFlags VkSubpassDescriptionFlags; - -typedef enum VkAccessFlagBits { - VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, - VK_ACCESS_INDEX_READ_BIT = 0x00000002, - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, - VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, - VK_ACCESS_SHADER_READ_BIT = 0x00000020, - VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, - VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, - VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, - VK_ACCESS_HOST_READ_BIT = 0x00002000, - VK_ACCESS_HOST_WRITE_BIT = 0x00004000, - VK_ACCESS_MEMORY_READ_BIT = 0x00008000, - VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, - VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, - VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, - VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, - VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkAccessFlagBits; -typedef VkFlags VkAccessFlags; - -typedef enum VkDependencyFlagBits { - VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, - VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, - VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkDependencyFlagBits; -typedef VkFlags VkDependencyFlags; - -typedef enum VkCommandPoolCreateFlagBits { - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, - VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolCreateFlagBits; -typedef VkFlags VkCommandPoolCreateFlags; - -typedef enum VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandPoolResetFlagBits; -typedef VkFlags VkCommandPoolResetFlags; - -typedef enum VkCommandBufferUsageFlagBits { - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, - VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, - VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferUsageFlagBits; -typedef VkFlags VkCommandBufferUsageFlags; - -typedef enum VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, - VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkQueryControlFlagBits; -typedef VkFlags VkQueryControlFlags; - -typedef enum VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkCommandBufferResetFlagBits; -typedef VkFlags VkCommandBufferResetFlags; - -typedef enum VkStencilFaceFlagBits { - VK_STENCIL_FACE_FRONT_BIT = 0x00000001, - VK_STENCIL_FACE_BACK_BIT = 0x00000002, - VK_STENCIL_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkStencilFaceFlagBits; -typedef VkFlags VkStencilFaceFlags; - -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 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 void* (VKAPI_PTR *PFN_vkAllocationFunction)( - void* pUserData, - size_t size, - size_t alignment, - 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_vkFreeFunction)( - void* pUserData, - void* pMemory); - -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 struct VkAllocationCallbacks { - void* pUserData; - PFN_vkAllocationFunction pfnAllocation; - PFN_vkReallocationFunction pfnReallocation; - PFN_vkFreeFunction pfnFree; - PFN_vkInternalAllocationNotification pfnInternalAllocation; - PFN_vkInternalFreeNotification pfnInternalFree; -} VkAllocationCallbacks; - -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 VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; - -typedef struct VkExtent3D { - uint32_t width; - uint32_t height; - uint32_t depth; -} VkExtent3D; - -typedef struct VkImageFormatProperties { - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize maxResourceSize; -} VkImageFormatProperties; - -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 VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; - -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 VkQueueFamilyProperties { - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; - -typedef struct VkMemoryType { - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; - -typedef struct VkMemoryHeap { - VkDeviceSize size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; - -typedef struct VkPhysicalDeviceMemoryProperties { - uint32_t memoryTypeCount; - VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; - uint32_t memoryHeapCount; - VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryProperties; - -typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); -typedef struct VkDeviceQueueCreateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float* pQueuePriorities; -} VkDeviceQueueCreateInfo; - -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 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 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 VkMemoryAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; - -typedef struct VkMappedMemoryRange { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkDeviceSize offset; - VkDeviceSize size; -} VkMappedMemoryRange; - -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 VkSparseMemoryBind { - VkDeviceSize resourceOffset; - VkDeviceSize size; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; - -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 VkImageSubresource { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; - -typedef struct VkOffset3D { - int32_t x; - int32_t y; - int32_t z; -} VkOffset3D; - -typedef struct VkSparseImageMemoryBind { - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; - -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 VkFenceCreateInfo { - VkStructureType sType; - const void* pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; - -typedef struct VkSemaphoreCreateInfo { - VkStructureType sType; - const void* pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; - -typedef struct VkEventCreateInfo { - VkStructureType sType; - const void* pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; - -typedef struct VkQueryPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; - -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 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 VkComponentMapping { - VkComponentSwizzle r; - VkComponentSwizzle g; - VkComponentSwizzle b; - VkComponentSwizzle a; -} VkComponentMapping; - -typedef struct VkImageSubresourceRange { - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; - -typedef struct VkImageViewCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageViewCreateFlags flags; - VkImage image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; - -typedef struct VkShaderModuleCreateInfo { - VkStructureType sType; - const void* pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t* pCode; -} VkShaderModuleCreateInfo; - -typedef struct VkPipelineCacheCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void* pInitialData; -} VkPipelineCacheCreateInfo; - -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 VkPipelineShaderStageCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule module; - const char* pName; - const VkSpecializationInfo* pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; - -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 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 VkViewport { - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; -} VkViewport; - -typedef struct VkOffset2D { - int32_t x; - int32_t y; -} VkOffset2D; - -typedef struct VkExtent2D { - uint32_t width; - uint32_t height; -} VkExtent2D; - -typedef struct VkRect2D { - VkOffset2D offset; - VkExtent2D extent; -} VkRect2D; - -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 VkStencilOpState { - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - uint32_t compareMask; - uint32_t writeMask; - uint32_t reference; -} VkStencilOpState; - -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 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 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 VkComputePipelineCreateInfo { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo stage; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; - -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 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 VkDescriptorPoolSize { - VkDescriptorType type; - uint32_t descriptorCount; -} VkDescriptorPoolSize; - -typedef struct VkDescriptorPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize* pPoolSizes; -} VkDescriptorPoolCreateInfo; - -typedef struct VkDescriptorSetAllocateInfo { - VkStructureType sType; - const void* pNext; - VkDescriptorPool descriptorPool; - uint32_t descriptorSetCount; - const VkDescriptorSetLayout* pSetLayouts; -} VkDescriptorSetAllocateInfo; - -typedef struct VkDescriptorImageInfo { - VkSampler sampler; - VkImageView imageView; - VkImageLayout imageLayout; -} VkDescriptorImageInfo; - -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 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 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 VkAttachmentDescription { - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription; - -typedef struct VkAttachmentReference { - uint32_t attachment; - VkImageLayout layout; -} VkAttachmentReference; - -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 VkCommandPoolCreateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; - -typedef struct VkCommandBufferAllocateInfo { - VkStructureType sType; - const void* pNext; - VkCommandPool commandPool; - VkCommandBufferLevel level; - uint32_t commandBufferCount; -} VkCommandBufferAllocateInfo; - -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 VkBufferCopy { - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy; - -typedef struct VkImageSubresourceLayers { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; - -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 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 VkClearAttachment { - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; - -typedef struct VkClearRect { - VkRect2D rect; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkClearRect; - -typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; - -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 VkRenderPassBeginInfo { - VkStructureType sType; - const void* pNext; - VkRenderPass renderPass; - VkFramebuffer framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue* pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkDispatchIndirectCommand { - uint32_t x; - uint32_t y; - uint32_t z; -} VkDispatchIndirectCommand; - -typedef struct VkDrawIndexedIndirectCommand { - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; -} VkDrawIndexedIndirectCommand; - -typedef struct VkDrawIndirectCommand { - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; -} VkDrawIndirectCommand; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); -typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char* pName); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); -typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); -typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice device); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo, const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMemory); -typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData); -typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); -typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges); -typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice device, VkBuffer buffer, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); -typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore); -typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent); -typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event); -typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool); -typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage); -typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView); -typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule); -typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches); -typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineLayout* pPipelineLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler); -typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorPool* pDescriptorPool); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pDescriptorSets); -typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFramebuffer* pFramebuffer); -typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass); -typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D* pGranularity); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkCommandPool* pCommandPool); -typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers); -typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); -typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo); -typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer commandBuffer); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport* pViewports); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D* pScissors); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); -typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants[4]); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); -typedef void (VKAPI_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 (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets); -typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); -typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges); -typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve* pRegions); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -typedef void (VKAPI_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 (VKAPI_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 (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); -typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); -typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( - const VkInstanceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkInstance* pInstance); - -VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( - VkInstance instance, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices( - VkInstance instance, - uint32_t* pPhysicalDeviceCount, - VkPhysicalDevice* pPhysicalDevices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkImageFormatProperties* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties* pMemoryProperties); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr( - VkInstance instance, - const char* pName); - -VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr( - VkDevice device, - const char* pName); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice( - VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDevice* pDevice); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDevice( - VkDevice device, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties( - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties( - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkLayerProperties* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue( - VkDevice device, - uint32_t queueFamilyIndex, - uint32_t queueIndex, - VkQueue* pQueue); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit( - VkQueue queue, - uint32_t submitCount, - const VkSubmitInfo* pSubmits, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle( - VkQueue queue); - -VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle( - VkDevice device); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory( - VkDevice device, - const VkMemoryAllocateInfo* pAllocateInfo, - const VkAllocationCallbacks* pAllocator, - VkDeviceMemory* pMemory); - -VKAPI_ATTR void VKAPI_CALL vkFreeMemory( - VkDevice device, - VkDeviceMemory memory, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - void** ppData); - -VKAPI_ATTR void VKAPI_CALL vkUnmapMemory( - VkDevice device, - VkDeviceMemory memory); - -VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges( - VkDevice device, - uint32_t memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize* pCommittedMemoryInBytes); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory( - VkDevice device, - VkBuffer buffer, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory( - VkDevice device, - VkImage image, - VkDeviceMemory memory, - VkDeviceSize memoryOffset); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( - VkDevice device, - VkBuffer buffer, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( - VkDevice device, - VkImage image, - VkMemoryRequirements* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements( - VkDevice device, - VkImage image, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements* pSparseMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkSampleCountFlagBits samples, - VkImageUsageFlags usage, - VkImageTiling tiling, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueueBindSparse( - VkQueue queue, - uint32_t bindInfoCount, - const VkBindSparseInfo* pBindInfo, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence( - VkDevice device, - const VkFenceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFence( - VkDevice device, - VkFence fence, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus( - VkDevice device, - VkFence fence); - -VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences( - VkDevice device, - uint32_t fenceCount, - const VkFence* pFences, - VkBool32 waitAll, - uint64_t timeout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore( - VkDevice device, - const VkSemaphoreCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSemaphore* pSemaphore); - -VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore( - VkDevice device, - VkSemaphore semaphore, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent( - VkDevice device, - const VkEventCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkEvent* pEvent); - -VKAPI_ATTR void VKAPI_CALL vkDestroyEvent( - VkDevice device, - VkEvent event, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent( - VkDevice device, - VkEvent event); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool( - VkDevice device, - const VkQueryPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkQueryPool* pQueryPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyQueryPool( - VkDevice device, - VkQueryPool queryPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults( - VkDevice device, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - size_t dataSize, - void* pData, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer( - VkDevice device, - const VkBufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBuffer* pBuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer( - VkDevice device, - VkBuffer buffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView( - VkDevice device, - const VkBufferViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBufferView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView( - VkDevice device, - VkBufferView bufferView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage( - VkDevice device, - const VkImageCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImage* pImage); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImage( - VkDevice device, - VkImage image, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout( - VkDevice device, - VkImage image, - const VkImageSubresource* pSubresource, - VkSubresourceLayout* pLayout); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView( - VkDevice device, - const VkImageViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImageView* pView); - -VKAPI_ATTR void VKAPI_CALL vkDestroyImageView( - VkDevice device, - VkImageView imageView, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule( - VkDevice device, - const VkShaderModuleCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkShaderModule* pShaderModule); - -VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule( - VkDevice device, - VkShaderModule shaderModule, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache( - VkDevice device, - const VkPipelineCacheCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineCache* pPipelineCache); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache( - VkDevice device, - VkPipelineCache pipelineCache, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData( - VkDevice device, - VkPipelineCache pipelineCache, - size_t* pDataSize, - void* pData); - -VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches( - VkDevice device, - VkPipelineCache dstCache, - uint32_t srcCacheCount, - const VkPipelineCache* pSrcCaches); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkGraphicsPipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines( - VkDevice device, - VkPipelineCache pipelineCache, - uint32_t createInfoCount, - const VkComputePipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline( - VkDevice device, - VkPipeline pipeline, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout( - VkDevice device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineLayout* pPipelineLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout( - VkDevice device, - VkPipelineLayout pipelineLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler( - VkDevice device, - const VkSamplerCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSampler* pSampler); - -VKAPI_ATTR void VKAPI_CALL vkDestroySampler( - VkDevice device, - VkSampler sampler, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorSetLayout* pSetLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout( - VkDevice device, - VkDescriptorSetLayout descriptorSetLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool( - VkDevice device, - const VkDescriptorPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorPool* pDescriptorPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - VkDescriptorPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets( - VkDevice device, - const VkDescriptorSetAllocateInfo* pAllocateInfo, - VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR VkResult VKAPI_CALL vkFreeDescriptorSets( - VkDevice device, - VkDescriptorPool descriptorPool, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets( - VkDevice device, - uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites, - uint32_t descriptorCopyCount, - const VkCopyDescriptorSet* pDescriptorCopies); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer( - VkDevice device, - const VkFramebufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFramebuffer* pFramebuffer); - -VKAPI_ATTR void VKAPI_CALL vkDestroyFramebuffer( - VkDevice device, - VkFramebuffer framebuffer, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass( - VkDevice device, - const VkRenderPassCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass); - -VKAPI_ATTR void VKAPI_CALL vkDestroyRenderPass( - VkDevice device, - VkRenderPass renderPass, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkGetRenderAreaGranularity( - VkDevice device, - VkRenderPass renderPass, - VkExtent2D* pGranularity); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool( - VkDevice device, - const VkCommandPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkCommandPool* pCommandPool); - -VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool( - VkDevice device, - VkCommandPool commandPool, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolResetFlags flags); - -VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers( - VkDevice device, - const VkCommandBufferAllocateInfo* pAllocateInfo, - VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers( - VkDevice device, - VkCommandPool commandPool, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); - -VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo* pBeginInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferResetFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewport( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetScissor( - VkCommandBuffer commandBuffer, - uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth( - VkCommandBuffer commandBuffer, - float lineWidth); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBias( - VkCommandBuffer commandBuffer, - float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants( - VkCommandBuffer commandBuffer, - const float blendConstants[4]); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds( - VkCommandBuffer commandBuffer, - float minDepthBounds, - float maxDepthBounds); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilCompareMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t compareMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilWriteMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t writeMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetStencilReference( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - uint32_t reference); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindIndexBuffer( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType); - -VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers( - VkCommandBuffer commandBuffer, - uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets); - -VKAPI_ATTR void VKAPI_CALL vkCmdDraw( - VkCommandBuffer commandBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed( - VkCommandBuffer commandBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatch( - VkCommandBuffer commandBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdBlitImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearDepthStencilImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue* pDepthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges); - -VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments( - VkCommandBuffer commandBuffer, - uint32_t attachmentCount, - const VkClearAttachment* pAttachments, - uint32_t rectCount, - const VkClearRect* pRects); - -VKAPI_ATTR void VKAPI_CALL vkCmdResolveImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask); - -VKAPI_ATTR void VKAPI_CALL 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); - -VKAPI_ATTR void VKAPI_CALL 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); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount); - -VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query); - -VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants( - VkCommandBuffer commandBuffer, - VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass( - VkCommandBuffer commandBuffer, - VkSubpassContents contents); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdExecuteCommands( - VkCommandBuffer commandBuffer, - uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers); -#endif - -#define VK_VERSION_1_1 1 -// 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 - - -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) - -#define VK_MAX_DEVICE_GROUP_SIZE 32 -#define VK_LUID_SIZE 8 -#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) - - -typedef enum VkPointClippingBehavior { - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_END_RANGE = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_RANGE_SIZE = (VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES + 1), - VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF -} VkPointClippingBehavior; - -typedef enum VkTessellationDomainOrigin { - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_BEGIN_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_END_RANGE = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_RANGE_SIZE = (VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT + 1), - VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF -} 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, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_BEGIN_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_END_RANGE = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RANGE_SIZE = (VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY + 1), - VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF -} VkSamplerYcbcrModelConversion; - -typedef enum VkSamplerYcbcrRange { - VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_BEGIN_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_END_RANGE = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_RANGE_SIZE = (VK_SAMPLER_YCBCR_RANGE_ITU_NARROW - VK_SAMPLER_YCBCR_RANGE_ITU_FULL + 1), - VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF -} VkSamplerYcbcrRange; - -typedef enum VkChromaLocation { - VK_CHROMA_LOCATION_COSITED_EVEN = 0, - VK_CHROMA_LOCATION_MIDPOINT = 1, - VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_BEGIN_RANGE = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_END_RANGE = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_RANGE_SIZE = (VK_CHROMA_LOCATION_MIDPOINT - VK_CHROMA_LOCATION_COSITED_EVEN + 1), - VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF -} VkChromaLocation; - -typedef enum VkDescriptorUpdateTemplateType { - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + 1), - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF -} VkDescriptorUpdateTemplateType; - - -typedef enum VkSubgroupFeatureFlagBits { - VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, - VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, - VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, - VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, - VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, - VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, - VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, - VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, - VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSubgroupFeatureFlagBits; -typedef VkFlags VkSubgroupFeatureFlags; - -typedef enum VkPeerMemoryFeatureFlagBits { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, - VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkPeerMemoryFeatureFlagBits; -typedef VkFlags VkPeerMemoryFeatureFlags; - -typedef enum VkMemoryAllocateFlagBits { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, - VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkMemoryAllocateFlagBits; -typedef VkFlags VkMemoryAllocateFlags; -typedef VkFlags VkCommandPoolTrimFlags; -typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; - -typedef enum VkExternalMemoryHandleTypeFlagBits { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBits; -typedef VkFlags VkExternalMemoryHandleTypeFlags; - -typedef enum VkExternalMemoryFeatureFlagBits { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBits; -typedef VkFlags VkExternalMemoryFeatureFlags; - -typedef enum VkExternalFenceHandleTypeFlagBits { - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalFenceHandleTypeFlagBits; -typedef VkFlags VkExternalFenceHandleTypeFlags; - -typedef enum VkExternalFenceFeatureFlagBits { - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalFenceFeatureFlagBits; -typedef VkFlags VkExternalFenceFeatureFlags; - -typedef enum VkFenceImportFlagBits { - VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, - VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkFenceImportFlagBits; -typedef VkFlags VkFenceImportFlags; - -typedef enum VkSemaphoreImportFlagBits { - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, - VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkSemaphoreImportFlagBits; -typedef VkFlags VkSemaphoreImportFlags; - -typedef enum VkExternalSemaphoreHandleTypeFlagBits { - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalSemaphoreHandleTypeFlagBits; -typedef VkFlags VkExternalSemaphoreHandleTypeFlags; - -typedef enum VkExternalSemaphoreFeatureFlagBits { - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VkExternalSemaphoreFeatureFlagBits; -typedef VkFlags VkExternalSemaphoreFeatureFlags; - -typedef struct VkPhysicalDeviceSubgroupProperties { - VkStructureType sType; - void* pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties; - -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 VkPhysicalDevice16BitStorageFeatures { - VkStructureType sType; - void* pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures; - -typedef struct VkMemoryDedicatedRequirements { - VkStructureType sType; - void* pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements; - -typedef struct VkMemoryDedicatedAllocateInfo { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkMemoryDedicatedAllocateInfo; - -typedef struct VkMemoryAllocateFlagsInfo { - VkStructureType sType; - const void* pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo; - -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 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 VkPhysicalDeviceGroupProperties { - VkStructureType sType; - void* pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties; - -typedef struct VkDeviceGroupDeviceCreateInfo { - VkStructureType sType; - const void* pNext; - uint32_t physicalDeviceCount; - const VkPhysicalDevice* pPhysicalDevices; -} VkDeviceGroupDeviceCreateInfo; - -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 VkMemoryRequirements2 { - VkStructureType sType; - void* pNext; - VkMemoryRequirements memoryRequirements; -} VkMemoryRequirements2; - -typedef struct VkSparseImageMemoryRequirements2 { - VkStructureType sType; - void* pNext; - VkSparseImageMemoryRequirements memoryRequirements; -} VkSparseImageMemoryRequirements2; - -typedef struct VkPhysicalDeviceFeatures2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2; - -typedef struct VkPhysicalDeviceProperties2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceProperties properties; -} VkPhysicalDeviceProperties2; - -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 VkPhysicalDeviceMemoryProperties2 { - VkStructureType sType; - void* pNext; - VkPhysicalDeviceMemoryProperties memoryProperties; -} VkPhysicalDeviceMemoryProperties2; - -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 VkPhysicalDevicePointClippingProperties { - VkStructureType sType; - void* pNext; - VkPointClippingBehavior pointClippingBehavior; -} VkPhysicalDevicePointClippingProperties; - -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 VkImageViewUsageCreateInfo { - VkStructureType sType; - const void* pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo; - -typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { - VkStructureType sType; - const void* pNext; - VkTessellationDomainOrigin domainOrigin; -} VkPipelineTessellationDomainOriginStateCreateInfo; - -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 VkPhysicalDeviceMultiviewFeatures { - VkStructureType sType; - void* pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures; - -typedef struct VkPhysicalDeviceMultiviewProperties { - VkStructureType sType; - void* pNext; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; -} VkPhysicalDeviceMultiviewProperties; - -typedef struct VkPhysicalDeviceVariablePointerFeatures { - VkStructureType sType; - void* pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointerFeatures; - -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 VkProtectedSubmitInfo { - VkStructureType sType; - const void* pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo; - -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 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 VkPhysicalDeviceSamplerYcbcrConversionFeatures { - VkStructureType sType; - void* pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures; - -typedef struct VkSamplerYcbcrConversionImageFormatProperties { - VkStructureType sType; - void* pNext; - uint32_t combinedImageSamplerDescriptorCount; -} VkSamplerYcbcrConversionImageFormatProperties; - -typedef struct VkDescriptorUpdateTemplateEntry { - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - size_t offset; - size_t stride; -} VkDescriptorUpdateTemplateEntry; - -typedef struct VkDescriptorUpdateTemplateCreateInfo { - VkStructureType sType; - void* pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo; - -typedef struct VkExternalMemoryProperties { - VkExternalMemoryFeatureFlags externalMemoryFeatures; - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlags compatibleHandleTypes; -} VkExternalMemoryProperties; - -typedef struct VkPhysicalDeviceExternalImageFormatInfo { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalImageFormatInfo; - -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 VkPhysicalDeviceExternalFenceInfo { - VkStructureType sType; - const void* pNext; - VkExternalFenceHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalFenceInfo; - -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 VkExportSemaphoreCreateInfo { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo; - -typedef struct VkPhysicalDeviceExternalSemaphoreInfo { - VkStructureType sType; - const void* pNext; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalSemaphoreInfo; - -typedef struct VkExternalSemaphoreProperties { - VkStructureType sType; - void* pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties; - -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 VkPhysicalDeviceShaderDrawParameterFeatures { - VkStructureType sType; - void* pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParameterFeatures; - - -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t* pApiVersion); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceVersion( - uint32_t* pApiVersion); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2( - VkDevice device, - uint32_t bindInfoCount, - const VkBindBufferMemoryInfo* pBindInfos); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2( - VkDevice device, - uint32_t bindInfoCount, - const VkBindImageMemoryInfo* pBindInfos); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures( - VkDevice device, - uint32_t heapIndex, - uint32_t localDeviceIndex, - uint32_t remoteDeviceIndex, - VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMask( - VkCommandBuffer commandBuffer, - uint32_t deviceMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBase( - VkCommandBuffer commandBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups( - VkInstance instance, - uint32_t* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2( - VkDevice device, - const VkImageMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2( - VkDevice device, - const VkBufferMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2* pInfo, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, - VkImageFormatProperties2* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2* pMemoryProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlags flags); - -VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2( - VkDevice device, - const VkDeviceQueueInfo2* pQueueInfo, - VkQueue* pQueue); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversion* pYcbcrConversion); - -VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversion( - VkDevice device, - VkSamplerYcbcrConversion ycbcrConversion, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplate( - VkDevice device, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplate( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const void* pData); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, - VkExternalBufferProperties* pExternalBufferProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, - VkExternalFenceProperties* pExternalFenceProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, - VkExternalSemaphoreProperties* pExternalSemaphoreProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupport* pSupport); -#endif - -#define VK_KHR_surface 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - -#define VK_KHR_SURFACE_SPEC_VERSION 25 -#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" -#define VK_COLORSPACE_SRGB_NONLINEAR_KHR VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - - -typedef enum VkColorSpaceKHR { - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, - VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, - VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, - VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, - VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1), - VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkColorSpaceKHR; - -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, - VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, - VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1), - VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF -} VkPresentModeKHR; - - -typedef enum VkSurfaceTransformFlagBitsKHR { - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, - VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSurfaceTransformFlagBitsKHR; -typedef VkFlags VkSurfaceTransformFlagsKHR; - -typedef enum VkCompositeAlphaFlagBitsKHR { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, - VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkCompositeAlphaFlagBitsKHR; -typedef VkFlags VkCompositeAlphaFlagsKHR; - -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 VkSurfaceFormatKHR { - VkFormat format; - VkColorSpaceKHR colorSpace; -} VkSurfaceFormatKHR; - - -typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( - VkInstance instance, - VkSurfaceKHR surface, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR( - VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - VkSurfaceKHR surface, - VkBool32* pSupported); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pSurfaceFormatCount, - VkSurfaceFormatKHR* pSurfaceFormats); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pPresentModeCount, - VkPresentModeKHR* pPresentModes); -#endif - -#define VK_KHR_swapchain 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) - -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 -#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" - - -typedef enum VkSwapchainCreateFlagBitsKHR { - VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, - VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, - VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkSwapchainCreateFlagBitsKHR; -typedef VkFlags VkSwapchainCreateFlagsKHR; - -typedef enum VkDeviceGroupPresentModeFlagBitsKHR { - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, - VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDeviceGroupPresentModeFlagBitsKHR; -typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; - -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 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 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 VkDeviceGroupPresentCapabilitiesKHR { - VkStructureType sType; - const void* pNext; - uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR; - -typedef struct VkDeviceGroupPresentInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const uint32_t* pDeviceMasks; - VkDeviceGroupPresentModeFlagBitsKHR mode; -} VkDeviceGroupPresentInfoKHR; - -typedef struct VkDeviceGroupSwapchainCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); -typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); -typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR( - VkDevice device, - const VkSwapchainCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchain); - -VKAPI_ATTR void VKAPI_CALL vkDestroySwapchainKHR( - VkDevice device, - VkSwapchainKHR swapchain, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainImagesKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pSwapchainImageCount, - VkImage* pSwapchainImages); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR( - VkDevice device, - VkSwapchainKHR swapchain, - uint64_t timeout, - VkSemaphore semaphore, - VkFence fence, - uint32_t* pImageIndex); - -VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( - VkQueue queue, - const VkPresentInfoKHR* pPresentInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR( - VkDevice device, - VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR( - VkDevice device, - VkSurfaceKHR surface, - VkDeviceGroupPresentModeFlagsKHR* pModes); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - uint32_t* pRectCount, - VkRect2D* pRects); - -VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR( - VkDevice device, - const VkAcquireNextImageInfoKHR* pAcquireInfo, - uint32_t* pImageIndex); -#endif - -#define VK_KHR_display 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) - -#define VK_KHR_DISPLAY_SPEC_VERSION 21 -#define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" - - -typedef enum VkDisplayPlaneAlphaFlagBitsKHR { - VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, - VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF -} VkDisplayPlaneAlphaFlagBitsKHR; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; -typedef VkFlags VkDisplayModeCreateFlagsKHR; -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; - -typedef struct VkDisplayPropertiesKHR { - VkDisplayKHR display; - const char* displayName; - VkExtent2D physicalDimensions; - VkExtent2D physicalResolution; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkBool32 planeReorderPossible; - VkBool32 persistentContent; -} VkDisplayPropertiesKHR; - -typedef struct VkDisplayModeParametersKHR { - VkExtent2D visibleRegion; - uint32_t refreshRate; -} VkDisplayModeParametersKHR; - -typedef struct VkDisplayModePropertiesKHR { - VkDisplayModeKHR displayMode; - VkDisplayModeParametersKHR parameters; -} VkDisplayModePropertiesKHR; - -typedef struct VkDisplayModeCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplayModeCreateFlagsKHR flags; - VkDisplayModeParametersKHR parameters; -} VkDisplayModeCreateInfoKHR; - -typedef struct VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha; - VkOffset2D minSrcPosition; - VkOffset2D maxSrcPosition; - VkExtent2D minSrcExtent; - VkExtent2D maxSrcExtent; - VkOffset2D minDstPosition; - VkOffset2D maxDstPosition; - VkExtent2D minDstExtent; - VkExtent2D maxDstExtent; -} VkDisplayPlaneCapabilitiesKHR; - -typedef struct VkDisplayPlanePropertiesKHR { - VkDisplayKHR currentDisplay; - uint32_t currentStackIndex; -} VkDisplayPlanePropertiesKHR; - -typedef struct VkDisplaySurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkDisplaySurfaceCreateFlagsKHR flags; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkDisplaySurfaceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDisplayModeKHR* pMode); -typedef VkResult (VKAPI_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR* pCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceDisplayPlanePropertiesKHR( - VkPhysicalDevice physicalDevice, - uint32_t* pPropertyCount, - VkDisplayPlanePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneSupportedDisplaysKHR( - VkPhysicalDevice physicalDevice, - uint32_t planeIndex, - uint32_t* pDisplayCount, - VkDisplayKHR* pDisplays); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayModePropertiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t* pPropertyCount, - VkDisplayModePropertiesKHR* pProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayModeKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - const VkDisplayModeCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDisplayModeKHR* pMode); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetDisplayPlaneCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayModeKHR mode, - uint32_t planeIndex, - VkDisplayPlaneCapabilitiesKHR* pCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR( - VkInstance instance, - const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface); -#endif - -#define VK_KHR_display_swapchain 1 -#define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 -#define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" - -typedef struct VkDisplayPresentInfoKHR { - VkStructureType sType; - const void* pNext; - VkRect2D srcRect; - VkRect2D dstRect; - VkBool32 persistent; -} VkDisplayPresentInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchains); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSharedSwapchainsKHR( - VkDevice device, - uint32_t swapchainCount, - const VkSwapchainCreateInfoKHR* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchains); -#endif - -#define VK_KHR_sampler_mirror_clamp_to_edge 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" - - -#define VK_KHR_multiview 1 -#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 -#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" - -typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; - -typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; - -typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; - - - -#define VK_KHR_get_physical_device_properties2 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" - -typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; - -typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; - -typedef VkFormatProperties2 VkFormatProperties2KHR; - -typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; - -typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; - -typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; - -typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; - -typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; - -typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2* pProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2* pFormatProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, - VkImageFormatProperties2* pImageFormatProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( - VkPhysicalDevice physicalDevice, - uint32_t* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2* pQueueFamilyProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2* pMemoryProperties); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, - uint32_t* pPropertyCount, - VkSparseImageFormatProperties2* pProperties); -#endif - -#define VK_KHR_device_group 1 -#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3 -#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" - -typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; - -typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; - -typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; - -typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; - - -typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; - -typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; - -typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; - -typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; - -typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; - -typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; - -typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR( - VkDevice device, - uint32_t heapIndex, - uint32_t localDeviceIndex, - uint32_t remoteDeviceIndex, - VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); - -VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHR( - VkCommandBuffer commandBuffer, - uint32_t deviceMask); - -VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHR( - VkCommandBuffer commandBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); -#endif - -#define VK_KHR_shader_draw_parameters 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" - - -#define VK_KHR_maintenance1 1 -#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" - -typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; - - -typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlags flags); -#endif - -#define VK_KHR_device_group_creation 1 -#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" -#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE - -typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; - -typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR( - VkInstance instance, - uint32_t* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -#endif - -#define VK_KHR_external_memory_capabilities 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" -#define VK_LUID_SIZE_KHR VK_LUID_SIZE - -typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; - -typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; - -typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; - -typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; - - -typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; - -typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; - -typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; - -typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; - -typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; - -typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, - VkExternalBufferProperties* pExternalBufferProperties); -#endif - -#define VK_KHR_external_memory 1 -#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" -#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL - -typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; - -typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; - -typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; - - - -#define VK_KHR_external_memory_fd 1 -#define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" - -typedef struct VkImportMemoryFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - int fd; -} VkImportMemoryFdInfoKHR; - -typedef struct VkMemoryFdPropertiesKHR { - VkStructureType sType; - void* pNext; - uint32_t memoryTypeBits; -} VkMemoryFdPropertiesKHR; - -typedef struct VkMemoryGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkDeviceMemory memory; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkMemoryGetFdInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR* pGetFdInfo, int* pFd); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR* pMemoryFdProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHR( - VkDevice device, - const VkMemoryGetFdInfoKHR* pGetFdInfo, - int* pFd); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR( - VkDevice device, - VkExternalMemoryHandleTypeFlagBits handleType, - int fd, - VkMemoryFdPropertiesKHR* pMemoryFdProperties); -#endif - -#define VK_KHR_external_semaphore_capabilities 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" - -typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; - -typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; - -typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; - -typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; - - -typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; - -typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, - VkExternalSemaphoreProperties* pExternalSemaphoreProperties); -#endif - -#define VK_KHR_external_semaphore 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" - -typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; - -typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; - - -typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; - - - -#define VK_KHR_external_semaphore_fd 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" - -typedef struct VkImportSemaphoreFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - int fd; -} VkImportSemaphoreFdInfoKHR; - -typedef struct VkSemaphoreGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkSemaphore semaphore; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkSemaphoreGetFdInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR* pGetFdInfo, int* pFd); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHR( - VkDevice device, - const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHR( - VkDevice device, - const VkSemaphoreGetFdInfoKHR* pGetFdInfo, - int* pFd); -#endif - -#define VK_KHR_push_descriptor 1 -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 -#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" - -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { - VkStructureType sType; - void* pNext; - uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites); -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t set, - uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites); - -VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR( - VkCommandBuffer commandBuffer, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - VkPipelineLayout layout, - uint32_t set, - const void* pData); -#endif - -#define VK_KHR_16bit_storage 1 -#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 -#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" - -typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; - - - -#define VK_KHR_incremental_present 1 -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 -#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" - -typedef struct VkRectLayerKHR { - VkOffset2D offset; - VkExtent2D extent; - uint32_t layer; -} VkRectLayerKHR; - -typedef struct VkPresentRegionKHR { - uint32_t rectangleCount; - const VkRectLayerKHR* pRectangles; -} VkPresentRegionKHR; - -typedef struct VkPresentRegionsKHR { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const VkPresentRegionKHR* pRegions; -} VkPresentRegionsKHR; - - - -#define VK_KHR_descriptor_update_template 1 -typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; - - -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" - -typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; - - -typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; - - -typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; - -typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR( - VkDevice device, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const void* pData); -#endif - -#define VK_KHR_shared_presentable_image 1 -#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 -#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" - -typedef struct VkSharedPresentSurfaceCapabilitiesKHR { - VkStructureType sType; - void* pNext; - VkImageUsageFlags sharedPresentSupportedUsageFlags; -} VkSharedPresentSurfaceCapabilitiesKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR( - VkDevice device, - VkSwapchainKHR swapchain); -#endif - -#define VK_KHR_external_fence_capabilities 1 -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" - -typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; - -typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; - -typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; - -typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; - - -typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; - -typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, - VkExternalFenceProperties* pExternalFenceProperties); -#endif - -#define VK_KHR_external_fence 1 -#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" - -typedef VkFenceImportFlags VkFenceImportFlagsKHR; - -typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; - - -typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; - - - -#define VK_KHR_external_fence_fd 1 -#define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" - -typedef struct VkImportFenceFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - int fd; -} VkImportFenceFdInfoKHR; - -typedef struct VkFenceGetFdInfoKHR { - VkStructureType sType; - const void* pNext; - VkFence fence; - VkExternalFenceHandleTypeFlagBits handleType; -} VkFenceGetFdInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR* pImportFenceFdInfo); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR* pGetFdInfo, int* pFd); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkImportFenceFdKHR( - VkDevice device, - const VkImportFenceFdInfoKHR* pImportFenceFdInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceFdKHR( - VkDevice device, - const VkFenceGetFdInfoKHR* pGetFdInfo, - int* pFd); -#endif - -#define VK_KHR_maintenance2 1 -#define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" - -typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; - -typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; - - -typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; - -typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; - -typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; - -typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; - -typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; - - - -#define VK_KHR_get_surface_capabilities2 1 -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" - -typedef struct VkPhysicalDeviceSurfaceInfo2KHR { - VkStructureType sType; - const void* pNext; - VkSurfaceKHR surface; -} VkPhysicalDeviceSurfaceInfo2KHR; - -typedef struct VkSurfaceCapabilities2KHR { - VkStructureType sType; - void* pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR; - -typedef struct VkSurfaceFormat2KHR { - VkStructureType sType; - void* pNext; - VkSurfaceFormatKHR surfaceFormat; -} VkSurfaceFormat2KHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - VkSurfaceCapabilities2KHR* pSurfaceCapabilities); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - uint32_t* pSurfaceFormatCount, - VkSurfaceFormat2KHR* pSurfaceFormats); -#endif - -#define VK_KHR_variable_pointers 1 -#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 -#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" - -typedef VkPhysicalDeviceVariablePointerFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; - - - -#define VK_KHR_dedicated_allocation 1 -#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" - -typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; - -typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; - - - -#define VK_KHR_storage_buffer_storage_class 1 -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" - - -#define VK_KHR_relaxed_block_layout 1 -#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" - - -#define VK_KHR_get_memory_requirements2 1 -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" - -typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; - -typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; - -typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; - -typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; - -typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; - - -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2KHR( - VkDevice device, - const VkImageMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2KHR( - VkDevice device, - const VkBufferMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements); - -VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2* pInfo, - uint32_t* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); -#endif - -#define VK_KHR_image_format_list 1 -#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 -#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" - -typedef struct VkImageFormatListCreateInfoKHR { - VkStructureType sType; - const void* pNext; - uint32_t viewFormatCount; - const VkFormat* pViewFormats; -} VkImageFormatListCreateInfoKHR; - - - -#define VK_KHR_sampler_ycbcr_conversion 1 -typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; - - -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1 -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" - -typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; - -typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; - -typedef VkChromaLocation VkChromaLocationKHR; - - -typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; - -typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; - -typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; - -typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; - -typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; - -typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversion* pYcbcrConversion); - -VKAPI_ATTR void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR( - VkDevice device, - VkSamplerYcbcrConversion ycbcrConversion, - const VkAllocationCallbacks* pAllocator); -#endif - -#define VK_KHR_bind_memory2 1 -#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 -#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" - -typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; - -typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; - - -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR( - VkDevice device, - uint32_t bindInfoCount, - const VkBindBufferMemoryInfo* pBindInfos); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR( - VkDevice device, - uint32_t bindInfoCount, - const VkBindImageMemoryInfo* pBindInfos); -#endif - -#define VK_KHR_maintenance3 1 -#define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" - -typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; - -typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; - - -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupport* pSupport); -#endif - -#define VK_EXT_debug_report 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) - -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 -#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT -#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT - - -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_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_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1), - VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportObjectTypeEXT; - - -typedef enum VkDebugReportFlagBitsEXT { - VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, - VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, - VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, - VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugReportFlagBitsEXT; -typedef VkFlags VkDebugReportFlagsEXT; - -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 VkDebugReportCallbackCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void* pUserData; -} VkDebugReportCallbackCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( - VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugReportCallbackEXT* pCallback); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( - VkInstance instance, - VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( - VkInstance instance, - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage); -#endif - -#define VK_NV_glsl_shader 1 -#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 -#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" - - -#define VK_EXT_depth_range_unrestricted 1 -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" - - -#define VK_IMG_filter_cubic 1 -#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 -#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" - - -#define VK_AMD_rasterization_order 1 -#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 -#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" - - -typedef enum VkRasterizationOrderAMD { - VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, - VK_RASTERIZATION_ORDER_BEGIN_RANGE_AMD = VK_RASTERIZATION_ORDER_STRICT_AMD, - VK_RASTERIZATION_ORDER_END_RANGE_AMD = VK_RASTERIZATION_ORDER_RELAXED_AMD, - VK_RASTERIZATION_ORDER_RANGE_SIZE_AMD = (VK_RASTERIZATION_ORDER_RELAXED_AMD - VK_RASTERIZATION_ORDER_STRICT_AMD + 1), - VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF -} VkRasterizationOrderAMD; - -typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { - VkStructureType sType; - const void* pNext; - VkRasterizationOrderAMD rasterizationOrder; -} VkPipelineRasterizationStateRasterizationOrderAMD; - - - -#define VK_AMD_shader_trinary_minmax 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" - - -#define VK_AMD_shader_explicit_vertex_parameter 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" - - -#define VK_EXT_debug_marker 1 -#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 -#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" - -typedef struct VkDebugMarkerObjectNameInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - const char* pObjectName; -} VkDebugMarkerObjectNameInfoEXT; - -typedef struct VkDebugMarkerObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t object; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugMarkerObjectTagInfoEXT; - -typedef struct VkDebugMarkerMarkerInfoEXT { - VkStructureType sType; - const void* pNext; - const char* pMarkerName; - float color[4]; -} VkDebugMarkerMarkerInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT* pTagInfo); -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT* pNameInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT( - VkDevice device, - const VkDebugMarkerObjectTagInfoEXT* pTagInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT( - VkDevice device, - const VkDebugMarkerObjectNameInfoEXT* pNameInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerBeginEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerEndEXT( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdDebugMarkerInsertEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo); -#endif - -#define VK_AMD_gcn_shader 1 -#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 -#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" - - -#define VK_NV_dedicated_allocation 1 -#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" - -typedef struct VkDedicatedAllocationImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; - -typedef struct VkDedicatedAllocationBufferCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; - -typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkImage image; - VkBuffer buffer; -} VkDedicatedAllocationMemoryAllocateInfoNV; - - - -#define VK_AMD_draw_indirect_count 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" - -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); - -VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - uint32_t maxDrawCount, - uint32_t stride); -#endif - -#define VK_AMD_negative_viewport_height 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" - - -#define VK_AMD_gpu_shader_half_float 1 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" - - -#define VK_AMD_shader_ballot 1 -#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 -#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" - - -#define VK_AMD_texture_gather_bias_lod 1 -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" - -typedef struct VkTextureLODGatherFormatPropertiesAMD { - VkStructureType sType; - void* pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD; - - - -#define VK_AMD_shader_info 1 -#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 -#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" - - -typedef enum VkShaderInfoTypeAMD { - VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, - VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, - VK_SHADER_INFO_TYPE_BEGIN_RANGE_AMD = VK_SHADER_INFO_TYPE_STATISTICS_AMD, - VK_SHADER_INFO_TYPE_END_RANGE_AMD = VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD, - VK_SHADER_INFO_TYPE_RANGE_SIZE_AMD = (VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD - VK_SHADER_INFO_TYPE_STATISTICS_AMD + 1), - VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF -} VkShaderInfoTypeAMD; - -typedef struct VkShaderResourceUsageAMD { - uint32_t numUsedVgprs; - uint32_t numUsedSgprs; - uint32_t ldsSizePerLocalWorkGroup; - size_t ldsUsageSizeInBytes; - size_t scratchMemUsageInBytes; -} VkShaderResourceUsageAMD; - -typedef struct VkShaderStatisticsInfoAMD { - VkShaderStageFlags shaderStageMask; - VkShaderResourceUsageAMD resourceUsage; - uint32_t numPhysicalVgprs; - uint32_t numPhysicalSgprs; - uint32_t numAvailableVgprs; - uint32_t numAvailableSgprs; - uint32_t computeWorkGroupSize[3]; -} VkShaderStatisticsInfoAMD; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t* pInfoSize, void* pInfo); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetShaderInfoAMD( - VkDevice device, - VkPipeline pipeline, - VkShaderStageFlagBits shaderStage, - VkShaderInfoTypeAMD infoType, - size_t* pInfoSize, - void* pInfo); -#endif - -#define VK_AMD_shader_image_load_store_lod 1 -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" - - -#define VK_IMG_format_pvrtc 1 -#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 -#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" - - -#define VK_NV_external_memory_capabilities 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" - - -typedef enum VkExternalMemoryHandleTypeFlagBitsNV { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryHandleTypeFlagBitsNV; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; - -typedef enum VkExternalMemoryFeatureFlagBitsNV { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF -} VkExternalMemoryFeatureFlagBitsNV; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; - -typedef struct VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties; - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; -} VkExternalImageFormatPropertiesNV; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkExternalMemoryHandleTypeFlagsNV externalHandleType, - VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties); -#endif - -#define VK_NV_external_memory 1 -#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" - -typedef struct VkExternalMemoryImageCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExternalMemoryImageCreateInfoNV; - -typedef struct VkExportMemoryAllocateInfoNV { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExportMemoryAllocateInfoNV; - - - -#define VK_EXT_validation_flags 1 -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" - - -typedef enum VkValidationCheckEXT { - VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1, - VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT, - VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_SHADERS_EXT, - VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_SHADERS_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1), - VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationCheckEXT; - -typedef struct VkValidationFlagsEXT { - VkStructureType sType; - const void* pNext; - uint32_t disabledValidationCheckCount; - VkValidationCheckEXT* pDisabledValidationChecks; -} VkValidationFlagsEXT; - - - -#define VK_EXT_shader_subgroup_ballot 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" - - -#define VK_EXT_shader_subgroup_vote 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" - - -#define VK_NVX_device_generated_commands 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX) - -#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 -#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" - - -typedef enum VkIndirectCommandsTokenTypeNVX { - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX + 1), - VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsTokenTypeNVX; - -typedef enum VkObjectEntryTypeNVX { - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0, - VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1, - VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2, - VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3, - VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4, - VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX, - VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX, - VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX + 1), - VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryTypeNVX; - - -typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX { - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkIndirectCommandsLayoutUsageFlagBitsNVX; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX; - -typedef enum VkObjectEntryUsageFlagBitsNVX { - VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, - VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, - VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkObjectEntryUsageFlagBitsNVX; -typedef VkFlags VkObjectEntryUsageFlagsNVX; - -typedef struct VkDeviceGeneratedCommandsFeaturesNVX { - VkStructureType sType; - const void* pNext; - VkBool32 computeBindingPointSupport; -} VkDeviceGeneratedCommandsFeaturesNVX; - -typedef struct VkDeviceGeneratedCommandsLimitsNVX { - VkStructureType sType; - const void* pNext; - uint32_t maxIndirectCommandsLayoutTokenCount; - uint32_t maxObjectEntryCounts; - uint32_t minSequenceCountBufferOffsetAlignment; - uint32_t minSequenceIndexBufferOffsetAlignment; - uint32_t minCommandsTokenBufferOffsetAlignment; -} VkDeviceGeneratedCommandsLimitsNVX; - -typedef struct VkIndirectCommandsTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsTokenNVX; - -typedef struct VkIndirectCommandsLayoutTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType; - uint32_t bindingUnit; - uint32_t dynamicCount; - uint32_t divisor; -} VkIndirectCommandsLayoutTokenNVX; - -typedef struct VkIndirectCommandsLayoutCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkPipelineBindPoint pipelineBindPoint; - VkIndirectCommandsLayoutUsageFlagsNVX flags; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNVX* pTokens; -} VkIndirectCommandsLayoutCreateInfoNVX; - -typedef struct VkCmdProcessCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t indirectCommandsTokenCount; - const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens; - uint32_t maxSequencesCount; - VkCommandBuffer targetCommandBuffer; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkCmdProcessCommandsInfoNVX; - -typedef struct VkCmdReserveSpaceForCommandsInfoNVX { - VkStructureType sType; - const void* pNext; - VkObjectTableNVX objectTable; - VkIndirectCommandsLayoutNVX indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkCmdReserveSpaceForCommandsInfoNVX; - -typedef struct VkObjectTableCreateInfoNVX { - VkStructureType sType; - const void* pNext; - uint32_t objectCount; - const VkObjectEntryTypeNVX* pObjectEntryTypes; - const uint32_t* pObjectEntryCounts; - const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags; - uint32_t maxUniformBuffersPerDescriptor; - uint32_t maxStorageBuffersPerDescriptor; - uint32_t maxStorageImagesPerDescriptor; - uint32_t maxSampledImagesPerDescriptor; - uint32_t maxPipelineLayouts; -} VkObjectTableCreateInfoNVX; - -typedef struct VkObjectTableEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; -} VkObjectTableEntryNVX; - -typedef struct VkObjectTablePipelineEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipeline pipeline; -} VkObjectTablePipelineEntryNVX; - -typedef struct VkObjectTableDescriptorSetEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkDescriptorSet descriptorSet; -} VkObjectTableDescriptorSetEntryNVX; - -typedef struct VkObjectTableVertexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; -} VkObjectTableVertexBufferEntryNVX; - -typedef struct VkObjectTableIndexBufferEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkBuffer buffer; - VkIndexType indexType; -} VkObjectTableIndexBufferEntryNVX; - -typedef struct VkObjectTablePushConstantEntryNVX { - VkObjectEntryTypeNVX type; - VkObjectEntryUsageFlagsNVX flags; - VkPipelineLayout pipelineLayout; - VkShaderStageFlags stageFlags; -} VkObjectTablePushConstantEntryNVX; - - -typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); -typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); -typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable); -typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices); -typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX( - VkDevice device, - const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout); - -VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX( - VkDevice device, - VkIndirectCommandsLayoutNVX indirectCommandsLayout, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX( - VkDevice device, - const VkObjectTableCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkObjectTableNVX* pObjectTable); - -VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX( - VkDevice device, - VkObjectTableNVX objectTable, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectTableEntryNVX* const* ppObjectTableEntries, - const uint32_t* pObjectIndices); - -VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - uint32_t objectCount, - const VkObjectEntryTypeNVX* pObjectEntryTypes, - const uint32_t* pObjectIndices); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( - VkPhysicalDevice physicalDevice, - VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, - VkDeviceGeneratedCommandsLimitsNVX* pLimits); -#endif - -#define VK_NV_clip_space_w_scaling 1 -#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 -#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" - -typedef struct VkViewportWScalingNV { - float xcoeff; - float ycoeff; -} VkViewportWScalingNV; - -typedef struct VkPipelineViewportWScalingStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - const VkViewportWScalingNV* pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV; - - -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV( - VkCommandBuffer commandBuffer, - uint32_t firstViewport, - uint32_t viewportCount, - const VkViewportWScalingNV* pViewportWScalings); -#endif - -#define VK_EXT_direct_mode_display 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 -#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" - -typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display); -#endif - -#define VK_EXT_display_surface_counter 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" -#define VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT - - -typedef enum VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001, - VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSurfaceCounterFlagBitsEXT; -typedef VkFlags VkSurfaceCounterFlagsEXT; - -typedef struct VkSurfaceCapabilities2EXT { - VkStructureType sType; - void* pNext; - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; - VkSurfaceCounterFlagsEXT supportedSurfaceCounters; -} VkSurfaceCapabilities2EXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilities2EXT* pSurfaceCapabilities); -#endif - -#define VK_EXT_display_control 1 -#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 -#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" - - -typedef enum VkDisplayPowerStateEXT { - VK_DISPLAY_POWER_STATE_OFF_EXT = 0, - VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2, - VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT, - VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT, - VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1), - VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayPowerStateEXT; - -typedef enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, - VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT, - VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1), - VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDeviceEventTypeEXT; - -typedef enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, - VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT, - VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1), - VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDisplayEventTypeEXT; - -typedef struct VkDisplayPowerInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayPowerStateEXT powerState; -} VkDisplayPowerInfoEXT; - -typedef struct VkDeviceEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDeviceEventTypeEXT deviceEvent; -} VkDeviceEventInfoEXT; - -typedef struct VkDisplayEventInfoEXT { - VkStructureType sType; - const void* pNext; - VkDisplayEventTypeEXT displayEvent; -} VkDisplayEventInfoEXT; - -typedef struct VkSwapchainCounterCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSurfaceCounterFlagsEXT surfaceCounters; -} VkSwapchainCounterCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayPowerInfoEXT* pDisplayPowerInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT( - VkDevice device, - const VkDeviceEventInfoEXT* pDeviceEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayEventInfoEXT* pDisplayEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT( - VkDevice device, - VkSwapchainKHR swapchain, - VkSurfaceCounterFlagBitsEXT counter, - uint64_t* pCounterValue); -#endif - -#define VK_GOOGLE_display_timing 1 -#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 -#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" - -typedef struct VkRefreshCycleDurationGOOGLE { - uint64_t refreshDuration; -} VkRefreshCycleDurationGOOGLE; - -typedef struct VkPastPresentationTimingGOOGLE { - uint32_t presentID; - uint64_t desiredPresentTime; - uint64_t actualPresentTime; - uint64_t earliestPresentTime; - uint64_t presentMargin; -} VkPastPresentationTimingGOOGLE; - -typedef struct VkPresentTimeGOOGLE { - uint32_t presentID; - uint64_t desiredPresentTime; -} VkPresentTimeGOOGLE; - -typedef struct VkPresentTimesInfoGOOGLE { - VkStructureType sType; - const void* pNext; - uint32_t swapchainCount; - const VkPresentTimeGOOGLE* pTimes; -} VkPresentTimesInfoGOOGLE; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); -typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - uint32_t* pPresentationTimingCount, - VkPastPresentationTimingGOOGLE* pPresentationTimings); -#endif - -#define VK_NV_sample_mask_override_coverage 1 -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" - - -#define VK_NV_geometry_shader_passthrough 1 -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" - - -#define VK_NV_viewport_array2 1 -#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" - - -#define VK_NVX_multiview_per_view_attributes 1 -#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 -#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" - -typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { - VkStructureType sType; - void* pNext; - VkBool32 perViewPositionAllComponents; -} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; - - - -#define VK_NV_viewport_swizzle 1 -#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" - - -typedef enum VkViewportCoordinateSwizzleNV { - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, - VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV, - VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1), - VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF -} VkViewportCoordinateSwizzleNV; - -typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; - -typedef struct VkViewportSwizzleNV { - VkViewportCoordinateSwizzleNV x; - VkViewportCoordinateSwizzleNV y; - VkViewportCoordinateSwizzleNV z; - VkViewportCoordinateSwizzleNV w; -} VkViewportSwizzleNV; - -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - const VkViewportSwizzleNV* pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV; - - - -#define VK_EXT_discard_rectangles 1 -#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 -#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" - - -typedef enum VkDiscardRectangleModeEXT { - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, - VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT, - VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1), - VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDiscardRectangleModeEXT; - -typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; - -typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxDiscardRectangles; -} VkPhysicalDeviceDiscardRectanglePropertiesEXT; - -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - const VkRect2D* pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT; - - -typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT( - VkCommandBuffer commandBuffer, - uint32_t firstDiscardRectangle, - uint32_t discardRectangleCount, - const VkRect2D* pDiscardRectangles); -#endif - -#define VK_EXT_conservative_rasterization 1 -#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 -#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" - - -typedef enum VkConservativeRasterizationModeEXT { - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, - VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, - VK_CONSERVATIVE_RASTERIZATION_MODE_BEGIN_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_END_RANGE_EXT = VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, - VK_CONSERVATIVE_RASTERIZATION_MODE_RANGE_SIZE_EXT = (VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT + 1), - VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkConservativeRasterizationModeEXT; - -typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; - -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { - VkStructureType sType; - void* pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; - -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT; - - - -#define VK_EXT_swapchain_colorspace 1 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" - - -#define VK_EXT_hdr_metadata 1 -#define VK_EXT_HDR_METADATA_SPEC_VERSION 1 -#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" - -typedef struct VkXYColorEXT { - float x; - float y; -} VkXYColorEXT; - -typedef struct VkHdrMetadataEXT { - VkStructureType sType; - const void* pNext; - VkXYColorEXT displayPrimaryRed; - VkXYColorEXT displayPrimaryGreen; - VkXYColorEXT displayPrimaryBlue; - VkXYColorEXT whitePoint; - float maxLuminance; - float minLuminance; - float maxContentLightLevel; - float maxFrameAverageLightLevel; -} VkHdrMetadataEXT; - - -typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT( - VkDevice device, - uint32_t swapchainCount, - const VkSwapchainKHR* pSwapchains, - const VkHdrMetadataEXT* pMetadata); -#endif - -#define VK_EXT_external_memory_dma_buf 1 -#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 -#define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" - - -#define VK_EXT_queue_family_foreign 1 -#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 -#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" -#define VK_QUEUE_FAMILY_FOREIGN_EXT (~0U-2) - - -#define VK_EXT_debug_utils 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) - -#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1 -#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" - -typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; - -typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugUtilsMessageSeverityFlagBitsEXT; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; - -typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, - VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF -} VkDebugUtilsMessageTypeFlagBitsEXT; -typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; - -typedef struct VkDebugUtilsObjectNameInfoEXT { - VkStructureType sType; - const void* pNext; - VkObjectType objectType; - uint64_t objectHandle; - const char* pObjectName; -} VkDebugUtilsObjectNameInfoEXT; - -typedef struct VkDebugUtilsObjectTagInfoEXT { - VkStructureType sType; - const void* pNext; - VkObjectType objectType; - uint64_t objectHandle; - uint64_t tagName; - size_t tagSize; - const void* pTag; -} VkDebugUtilsObjectTagInfoEXT; - -typedef struct VkDebugUtilsLabelEXT { - VkStructureType sType; - const void* pNext; - const char* pLabelName; - float color[4]; -} VkDebugUtilsLabelEXT; - -typedef struct VkDebugUtilsMessengerCallbackDataEXT { - VkStructureType sType; - const void* pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - const char* pMessageIdName; - int32_t messageIdNumber; - const char* pMessage; - uint32_t queueLabelCount; - VkDebugUtilsLabelEXT* pQueueLabels; - uint32_t cmdBufLabelCount; - VkDebugUtilsLabelEXT* pCmdBufLabels; - uint32_t objectCount; - VkDebugUtilsObjectNameInfoEXT* pObjects; -} VkDebugUtilsMessengerCallbackDataEXT; - -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData); - -typedef struct VkDebugUtilsMessengerCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkDebugUtilsMessengerCreateFlagsEXT flags; - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageType; - PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; - void* pUserData; -} VkDebugUtilsMessengerCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT* pNameInfo); -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT* pTagInfo); -typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); -typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT* pLabelInfo); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pMessenger); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT( - VkDevice device, - const VkDebugUtilsObjectNameInfoEXT* pNameInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT( - VkDevice device, - const VkDebugUtilsObjectTagInfoEXT* pTagInfo); - -VKAPI_ATTR void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT( - VkQueue queue); - -VKAPI_ATTR void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer); - -VKAPI_ATTR void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo); - -VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pMessenger); - -VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( - VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( - VkInstance instance, - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData); -#endif - -#define VK_EXT_sampler_filter_minmax 1 -#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1 -#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" - - -typedef enum VkSamplerReductionModeEXT { - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0, - VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2, - VK_SAMPLER_REDUCTION_MODE_BEGIN_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT, - VK_SAMPLER_REDUCTION_MODE_END_RANGE_EXT = VK_SAMPLER_REDUCTION_MODE_MAX_EXT, - VK_SAMPLER_REDUCTION_MODE_RANGE_SIZE_EXT = (VK_SAMPLER_REDUCTION_MODE_MAX_EXT - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT + 1), - VK_SAMPLER_REDUCTION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF -} VkSamplerReductionModeEXT; - -typedef struct VkSamplerReductionModeCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkSamplerReductionModeEXT reductionMode; -} VkSamplerReductionModeCreateInfoEXT; - -typedef struct VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT { - VkStructureType sType; - void* pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; - - - -#define VK_AMD_gpu_shader_int16 1 -#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1 -#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" - - -#define VK_AMD_mixed_attachment_samples 1 -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" - - -#define VK_AMD_shader_fragment_mask 1 -#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 -#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" - - -#define VK_EXT_shader_stencil_export 1 -#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 -#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" - - -#define VK_EXT_sample_locations 1 -#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 -#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" - -typedef struct VkSampleLocationEXT { - float x; - float y; -} VkSampleLocationEXT; - -typedef struct VkSampleLocationsInfoEXT { - VkStructureType sType; - const void* pNext; - VkSampleCountFlagBits sampleLocationsPerPixel; - VkExtent2D sampleLocationGridSize; - uint32_t sampleLocationsCount; - const VkSampleLocationEXT* pSampleLocations; -} VkSampleLocationsInfoEXT; - -typedef struct VkAttachmentSampleLocationsEXT { - uint32_t attachmentIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkAttachmentSampleLocationsEXT; - -typedef struct VkSubpassSampleLocationsEXT { - uint32_t subpassIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkSubpassSampleLocationsEXT; - -typedef struct VkRenderPassSampleLocationsBeginInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t attachmentInitialSampleLocationsCount; - const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; - uint32_t postSubpassSampleLocationsCount; - const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; -} VkRenderPassSampleLocationsBeginInfoEXT; - -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT; - -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { - VkStructureType sType; - void* pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange[2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT; - -typedef struct VkMultisamplePropertiesEXT { - VkStructureType sType; - void* pNext; - VkExtent2D maxSampleLocationGridSize; -} VkMultisamplePropertiesEXT; - - -typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT* pSampleLocationsInfo); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT* pMultisampleProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdSetSampleLocationsEXT( - VkCommandBuffer commandBuffer, - const VkSampleLocationsInfoEXT* pSampleLocationsInfo); - -VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT( - VkPhysicalDevice physicalDevice, - VkSampleCountFlagBits samples, - VkMultisamplePropertiesEXT* pMultisampleProperties); -#endif - -#define VK_EXT_blend_operation_advanced 1 -#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 -#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" - - -typedef enum VkBlendOverlapEXT { - VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, - VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2, - VK_BLEND_OVERLAP_BEGIN_RANGE_EXT = VK_BLEND_OVERLAP_UNCORRELATED_EXT, - VK_BLEND_OVERLAP_END_RANGE_EXT = VK_BLEND_OVERLAP_CONJOINT_EXT, - VK_BLEND_OVERLAP_RANGE_SIZE_EXT = (VK_BLEND_OVERLAP_CONJOINT_EXT - VK_BLEND_OVERLAP_UNCORRELATED_EXT + 1), - VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF -} VkBlendOverlapEXT; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { - VkStructureType sType; - void* pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; - -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT; - - - -#define VK_NV_fragment_coverage_to_color 1 -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" - -typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; - -typedef struct VkPipelineCoverageToColorStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV; - - - -#define VK_NV_framebuffer_mixed_samples 1 -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" - - -typedef enum VkCoverageModulationModeNV { - VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, - VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, - VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, - VK_COVERAGE_MODULATION_MODE_BEGIN_RANGE_NV = VK_COVERAGE_MODULATION_MODE_NONE_NV, - VK_COVERAGE_MODULATION_MODE_END_RANGE_NV = VK_COVERAGE_MODULATION_MODE_RGBA_NV, - VK_COVERAGE_MODULATION_MODE_RANGE_SIZE_NV = (VK_COVERAGE_MODULATION_MODE_RGBA_NV - VK_COVERAGE_MODULATION_MODE_NONE_NV + 1), - VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF -} VkCoverageModulationModeNV; - -typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; - -typedef struct VkPipelineCoverageModulationStateCreateInfoNV { - VkStructureType sType; - const void* pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - const float* pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV; - - - -#define VK_NV_fill_rectangle 1 -#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 -#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" - - -#define VK_EXT_post_depth_coverage 1 -#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 -#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" - - -#define VK_EXT_validation_cache 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) - -#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" -#define VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT - - -typedef enum VkValidationCacheHeaderVersionEXT { - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, - VK_VALIDATION_CACHE_HEADER_VERSION_BEGIN_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_END_RANGE_EXT = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT, - VK_VALIDATION_CACHE_HEADER_VERSION_RANGE_SIZE_EXT = (VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT + 1), - VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF -} VkValidationCacheHeaderVersionEXT; - -typedef VkFlags VkValidationCacheCreateFlagsEXT; - -typedef struct VkValidationCacheCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkValidationCacheCreateFlagsEXT flags; - size_t initialDataSize; - const void* pInitialData; -} VkValidationCacheCreateInfoEXT; - -typedef struct VkShaderModuleValidationCacheCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkValidationCacheEXT validationCache; -} VkShaderModuleValidationCacheCreateInfoEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkValidationCacheEXT* pValidationCache); -typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks* pAllocator); -typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT* pSrcCaches); -typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t* pDataSize, void* pData); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateValidationCacheEXT( - VkDevice device, - const VkValidationCacheCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkValidationCacheEXT* pValidationCache); - -VKAPI_ATTR void VKAPI_CALL vkDestroyValidationCacheEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - const VkAllocationCallbacks* pAllocator); - -VKAPI_ATTR VkResult VKAPI_CALL vkMergeValidationCachesEXT( - VkDevice device, - VkValidationCacheEXT dstCache, - uint32_t srcCacheCount, - const VkValidationCacheEXT* pSrcCaches); - -VKAPI_ATTR VkResult VKAPI_CALL vkGetValidationCacheDataEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - size_t* pDataSize, - void* pData); -#endif - -#define VK_EXT_shader_viewport_index_layer 1 -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" - - -#define VK_EXT_global_priority 1 -#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 -#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" - - -typedef enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, - VK_QUEUE_GLOBAL_PRIORITY_BEGIN_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT, - VK_QUEUE_GLOBAL_PRIORITY_END_RANGE_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT, - VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE_EXT = (VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT + 1), - VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM_EXT = 0x7FFFFFFF -} VkQueueGlobalPriorityEXT; - -typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { - VkStructureType sType; - const void* pNext; - VkQueueGlobalPriorityEXT globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoEXT; - - - -#define VK_EXT_external_memory_host 1 -#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 -#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" - -typedef struct VkImportMemoryHostPointerInfoEXT { - VkStructureType sType; - const void* pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - void* pHostPointer; -} VkImportMemoryHostPointerInfoEXT; - -typedef struct VkMemoryHostPointerPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t memoryTypeBits; -} VkMemoryHostPointerPropertiesEXT; - -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { - VkStructureType sType; - void* pNext; - VkDeviceSize minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; - - -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void* pHostPointer, VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT( - VkDevice device, - VkExternalMemoryHandleTypeFlagBits handleType, - const void* pHostPointer, - VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties); -#endif - -#define VK_AMD_buffer_marker 1 -#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 -#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" - -typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); - -#ifndef VK_NO_PROTOTYPES -VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - uint32_t marker); -#endif - -#define VK_EXT_vertex_attribute_divisor 1 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" - -typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { - VkStructureType sType; - void* pNext; - uint32_t maxVertexAttribDivisor; -} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; - -typedef struct VkVertexInputBindingDivisorDescriptionEXT { - uint32_t binding; - uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; - -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { - VkStructureType sType; - const void* pNext; - uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/raylib/external/glfw/include/GLFW/glfw3.h b/raylib/external/glfw/include/GLFW/glfw3.h index 00256d4..9c55ac9 100644 --- a/raylib/external/glfw/include/GLFW/glfw3.h +++ b/raylib/external/glfw/include/GLFW/glfw3.h @@ -1,9 +1,9 @@ /************************************************************************* - * GLFW 3.3 - www.glfw.org + * GLFW 3.4 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Löwy + * Copyright (c) 2006-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 @@ -52,7 +52,7 @@ extern "C" { * This is the reference documentation for OpenGL and OpenGL ES context related * functions. For more task-oriented information, see the @ref context_guide. */ -/*! @defgroup vulkan Vulkan reference +/*! @defgroup vulkan Vulkan support reference * @brief Functions and types related to Vulkan. * * This is the reference documentation for Vulkan related functions and types. @@ -96,11 +96,30 @@ extern "C" { #define _WIN32 #endif /* _WIN32 */ +/* Include because most Windows GLU headers need wchar_t and + * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include because it is needed by Vulkan and related functions. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +#if defined(GLFW_INCLUDE_VULKAN) + #include +#endif /* Vulkan header */ + +/* The Vulkan header may have indirectly included windows.h (because of + * VK_USE_PLATFORM_WIN32_KHR) so we offer our replacement symbols after it. + */ + /* It is customary to use APIENTRY for OpenGL function pointer declarations on * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ -#ifndef APIENTRY - #ifdef _WIN32 +#if !defined(APIENTRY) + #if defined(_WIN32) #define APIENTRY __stdcall #else #define APIENTRY @@ -122,17 +141,6 @@ extern "C" { #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ -/* Include because most Windows GLU headers need wchar_t and - * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. - * Include it unconditionally to avoid surprising side-effects. - */ -#include - -/* Include because it is needed by Vulkan and related functions. - * Include it unconditionally to avoid surprising side-effects. - */ -#include - /* Include the chosen OpenGL or OpenGL ES headers. */ #if defined(GLFW_INCLUDE_ES1) @@ -182,10 +190,44 @@ extern "C" { #else /*__APPLE__*/ #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif #endif /*__APPLE__*/ -#elif !defined(GLFW_INCLUDE_NONE) +#elif defined(GLFW_INCLUDE_GLU) + + #if defined(__APPLE__) + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #else /*__APPLE__*/ + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #endif /*__APPLE__*/ + +#elif !defined(GLFW_INCLUDE_NONE) && \ + !defined(__gl_h_) && \ + !defined(__gles1_gl_h_) && \ + !defined(__gles2_gl2_h_) && \ + !defined(__gles2_gl3_h_) && \ + !defined(__gles2_gl31_h_) && \ + !defined(__gles2_gl32_h_) && \ + !defined(__gl_glcorearb_h_) && \ + !defined(__gl2_h_) /*legacy*/ && \ + !defined(__gl3_h_) /*legacy*/ && \ + !defined(__gl31_h_) /*legacy*/ && \ + !defined(__gl32_h_) /*legacy*/ && \ + !defined(__glcorearb_h_) /*legacy*/ && \ + !defined(__GL_H__) /*non-standard*/ && \ + !defined(__gltypes_h_) /*non-standard*/ && \ + !defined(__glee_h_) /*non-standard*/ #if defined(__APPLE__) @@ -193,9 +235,6 @@ extern "C" { #define GL_GLEXT_LEGACY #endif #include - #if defined(GLFW_INCLUDE_GLU) - #include - #endif #else /*__APPLE__*/ @@ -203,18 +242,11 @@ extern "C" { #if defined(GLFW_INCLUDE_GLEXT) #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif #endif /*__APPLE__*/ #endif /* OpenGL and OpenGL ES headers */ -#if defined(GLFW_INCLUDE_VULKAN) - #include -#endif /* Vulkan header */ - #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) /* GLFW_DLL must be defined by applications that are linking against the DLL * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW @@ -230,13 +262,12 @@ extern "C" { /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) #elif defined(_WIN32) && defined(GLFW_DLL) - /* We are calling GLFW as a Win32 DLL */ + /* We are calling a GLFW Win32 DLL */ #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - /* We are building GLFW as a shared / dynamic library */ + /* We are building GLFW as a Unix shared library */ #define GLFWAPI __attribute__((visibility("default"))) #else - /* We are building or calling GLFW as a static library */ #define GLFWAPI #endif @@ -247,45 +278,47 @@ extern "C" { /*! @name GLFW version macros * @{ */ -/*! @brief The major version number of the GLFW library. +/*! @brief The major version number of the GLFW header. * - * This is incremented when the API is changed in non-compatible ways. + * The major version number of the GLFW header. 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 library. +/*! @brief The minor version number of the GLFW header. * - * This is incremented when features are added to the API but it remains - * backward-compatible. + * The minor version number of the GLFW header. This is incremented when + * features are added to the API but it remains backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 3 -/*! @brief The revision number of the GLFW library. +#define GLFW_VERSION_MINOR 4 +/*! @brief The revision number of the GLFW header. * - * This is incremented when a bug fix release is made that does not contain any - * API changes. + * The revision number of the GLFW header. This is incremented when a bug fix + * release is made that does not contain any API changes. * @ingroup init */ #define GLFW_VERSION_REVISION 0 /*! @} */ -/*! @name Boolean values - * @{ */ /*! @brief One. * - * One. Seriously. You don't _need_ to use this symbol in your code. It's - * semantic sugar for the number 1. You can also use `1` or `true` or `_True` - * or `GL_TRUE` or whatever you want. + * This is only semantic sugar for the number 1. You can instead use `1` or + * `true` or `_True` or `GL_TRUE` or `VK_TRUE` or anything else that is equal + * to one. + * + * @ingroup init */ #define GLFW_TRUE 1 /*! @brief Zero. * - * Zero. Seriously. You don't _need_ to use this symbol in your code. It's - * semantic sugar for the number 0. You can also use `0` or `false` or - * `_False` or `GL_FALSE` or whatever you want. + * This is only semantic sugar for the number 0. You can instead use `0` or + * `false` or `_False` or `GL_FALSE` or `VK_FALSE` or anything else that is + * equal to zero. + * + * @ingroup init */ #define GLFW_FALSE 0 -/*! @} */ /*! @name Key and button actions * @{ */ @@ -313,6 +346,7 @@ extern "C" { /*! @} */ /*! @defgroup hat_state Joystick hat states + * @brief Joystick hat states. * * See [joystick hat input](@ref joystick_hat) for how these are used. * @@ -327,10 +361,15 @@ 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 keys - * @brief Keyboard key IDs. +/*! @defgroup keys Keyboard key tokens + * @brief Keyboard key tokens. * * See [key input](@ref input_key) for how these are used. * @@ -340,7 +379,7 @@ extern "C" { * * The naming of the key codes follow these rules: * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * - Names of printable alphanumeric 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 @@ -353,9 +392,6 @@ extern "C" { * @{ */ -/* The unknown key */ -#define GLFW_KEY_UNKNOWN -1 - /* Printable keys */ #define GLFW_KEY_SPACE 32 #define GLFW_KEY_APOSTROPHE 39 /* ' */ @@ -685,7 +721,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 backend. + * API, or does not support it via the chosen context creation API. * Below are a few examples. * * @par @@ -751,6 +787,66 @@ extern "C" { * @analysis Application programmer error. Fix the offending call. */ #define GLFW_NO_WINDOW_CONTEXT 0x0001000A +/*! @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 + * available on the platform. + * + * @analysis Platform or system settings limitation. Pick another + * [standard cursor shape](@ref shapes) or create a + * [custom cursor](@ref cursor_custom). + */ +#define GLFW_CURSOR_UNAVAILABLE 0x0001000B +/*! @brief The requested feature is not provided by the platform. + * + * The requested feature is not provided by the platform, so GLFW is unable to + * implement it. The documentation for each function notes if it could emit + * this error. + * + * @analysis Platform or platform version limitation. The error can be ignored + * unless the feature is critical to the application. + * + * @par + * A function call that emits this error has no effect other than the error and + * updating any existing out parameters. + */ +#define GLFW_FEATURE_UNAVAILABLE 0x0001000C +/*! @brief The requested feature is not implemented for the platform. + * + * The requested feature has not yet been implemented in GLFW for this platform. + * + * @analysis An incomplete implementation of GLFW for this platform, hopefully + * fixed in a future release. The error can be ignored unless the feature is + * critical to the application. + * + * @par + * A function call that emits this error has no effect other than the error and + * 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 @@ -819,6 +915,31 @@ extern "C" { * Mouse cursor hover [window attribute](@ref GLFW_HOVERED_attrib). */ #define GLFW_HOVERED 0x0002000B +/*! @brief Input focus on calling show window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUS_ON_SHOW_hint) or + * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). + */ +#define GLFW_FOCUS_ON_SHOW 0x0002000C + +/*! @brief Mouse input transparency window hint and attribute + * + * Mouse input transparency [window hint](@ref GLFW_MOUSE_PASSTHROUGH_hint) or + * [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib). + */ +#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. * @@ -895,9 +1016,10 @@ extern "C" { * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). */ #define GLFW_REFRESH_RATE 0x0002100F -/*! @brief Framebuffer double buffering hint. +/*! @brief Framebuffer double buffering hint and attribute. * - * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). + * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER_hint) and + * [attribute](@ref GLFW_DOUBLEBUFFER_attrib). */ #define GLFW_DOUBLEBUFFER 0x00021010 @@ -909,71 +1031,110 @@ extern "C" { #define GLFW_CLIENT_API 0x00022001 /*! @brief Context client API major version hint and attribute. * - * Context client API major version [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib). */ #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 /*! @brief Context client API minor version hint and attribute. * - * Context client API minor version [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). */ #define GLFW_CONTEXT_VERSION_MINOR 0x00022003 -/*! @brief Context client API revision number hint and attribute. +/*! @brief Context client API revision number attribute. * - * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API revision number + * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). */ #define GLFW_CONTEXT_REVISION 0x00022004 /*! @brief Context robustness hint and attribute. * - * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint) + * and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib). */ #define GLFW_CONTEXT_ROBUSTNESS 0x00022005 /*! @brief OpenGL forward-compatibility hint and attribute. * - * OpenGL forward-compatibility [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) + * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). */ #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 -/*! @brief OpenGL debug context hint and attribute. +/*! @brief Debug mode context hint and attribute. * - * OpenGL debug context [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Debug mode context [hint](@ref GLFW_CONTEXT_DEBUG_hint) and + * [attribute](@ref GLFW_CONTEXT_DEBUG_attrib). */ -#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 +#define GLFW_CONTEXT_DEBUG 0x00022007 +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_OPENGL_DEBUG_CONTEXT GLFW_CONTEXT_DEBUG /*! @brief OpenGL profile hint and attribute. * - * OpenGL profile [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and + * [attribute](@ref GLFW_OPENGL_PROFILE_attrib). */ #define GLFW_OPENGL_PROFILE 0x00022008 /*! @brief Context flush-on-release hint and attribute. * - * Context flush-on-release [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and + * [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib). */ #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 /*! @brief Context error suppression hint and attribute. * - * Context error suppression [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and + * [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib). */ #define GLFW_CONTEXT_NO_ERROR 0x0002200A /*! @brief Context creation API hint and attribute. * - * Context creation API [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and + * [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib). */ #define GLFW_CONTEXT_CREATION_API 0x0002200B - +/*! @brief Window content area scaling window + * [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. + */ #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_FRAME_NAME_hint). + */ #define GLFW_COCOA_FRAME_NAME 0x00023002 +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). + */ #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 - +/*! @brief X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ #define GLFW_X11_CLASS_NAME 0x00024001 +/*! @brief X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ #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 @@ -992,10 +1153,12 @@ extern "C" { #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 #define GLFW_LOCK_KEY_MODS 0x00033004 +#define GLFW_RAW_MOUSE_MOTION 0x00033005 #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 @@ -1005,17 +1168,31 @@ extern "C" { #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 +#define GLFW_ANGLE_PLATFORM_TYPE_NONE 0x00037001 +#define GLFW_ANGLE_PLATFORM_TYPE_OPENGL 0x00037002 +#define GLFW_ANGLE_PLATFORM_TYPE_OPENGLES 0x00037003 +#define GLFW_ANGLE_PLATFORM_TYPE_D3D9 0x00037004 +#define GLFW_ANGLE_PLATFORM_TYPE_D3D11 0x00037005 +#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. * - * See [standard cursor creation](@ref cursor_standard) for how these are used. + * These are the [standard cursor shapes](@ref cursor_standard) that can be + * requested from the platform (window system). * * @ingroup input * @{ */ /*! @brief The regular arrow cursor shape. * - * The regular arrow cursor. + * The regular arrow cursor shape. */ #define GLFW_ARROW_CURSOR 0x00036001 /*! @brief The text input I-beam cursor shape. @@ -1023,26 +1200,91 @@ extern "C" { * The text input I-beam cursor shape. */ #define GLFW_IBEAM_CURSOR 0x00036002 -/*! @brief The crosshair shape. +/*! @brief The crosshair cursor shape. * - * The crosshair shape. + * The crosshair cursor shape. */ #define GLFW_CROSSHAIR_CURSOR 0x00036003 -/*! @brief The hand shape. +/*! @brief The pointing hand cursor shape. * - * The hand shape. + * The pointing hand cursor shape. */ -#define GLFW_HAND_CURSOR 0x00036004 -/*! @brief The horizontal resize arrow shape. +#define GLFW_POINTING_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize/move arrow shape. * - * The horizontal resize arrow shape. + * The horizontal resize/move arrow shape. This is usually a horizontal + * double-headed arrow. */ -#define GLFW_HRESIZE_CURSOR 0x00036005 -/*! @brief The vertical resize arrow shape. +#define GLFW_RESIZE_EW_CURSOR 0x00036005 +/*! @brief The vertical resize/move arrow shape. * - * The vertical resize arrow shape. + * The vertical resize/move shape. This is usually a vertical double-headed + * arrow. */ -#define GLFW_VRESIZE_CURSOR 0x00036006 +#define GLFW_RESIZE_NS_CURSOR 0x00036006 +/*! @brief The top-left to bottom-right diagonal resize/move arrow shape. + * + * The top-left to bottom-right diagonal resize/move shape. This is usually + * a diagonal double-headed arrow. + * + * @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. + */ +#define GLFW_RESIZE_NWSE_CURSOR 0x00036007 +/*! @brief The top-right to bottom-left diagonal resize/move arrow shape. + * + * The top-right to bottom-left diagonal resize/move shape. This is usually + * a diagonal double-headed arrow. + * + * @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. + */ +#define GLFW_RESIZE_NESW_CURSOR 0x00036008 +/*! @brief The omni-directional resize/move cursor shape. + * + * The omni-directional resize cursor/move shape. This is usually either + * a combined horizontal and vertical double-headed arrow or a grabbing hand. + */ +#define GLFW_RESIZE_ALL_CURSOR 0x00036009 +/*! @brief The operation-not-allowed shape. + * + * 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. + */ +#define GLFW_NOT_ALLOWED_CURSOR 0x0003600A +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_HRESIZE_CURSOR GLFW_RESIZE_EW_CURSOR +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_VRESIZE_CURSOR GLFW_RESIZE_NS_CURSOR +/*! @brief Legacy name for compatibility. + * + * This is an alias for compatibility with earlier versions. + */ +#define GLFW_HAND_CURSOR GLFW_POINTING_HAND_CURSOR /*! @} */ #define GLFW_CONNECTED 0x00040001 @@ -1050,10 +1292,55 @@ extern "C" { /*! @addtogroup init * @{ */ +/*! @brief Joystick hat buttons init hint. + * + * Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS). + */ #define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 - +/*! @brief ANGLE rendering backend init hint. + * + * 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). + */ #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 +/*! @brief macOS specific init hint. + * + * 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 @@ -1123,17 +1410,176 @@ typedef struct GLFWwindow GLFWwindow; * * @since Added in version 3.1. * - * @ingroup cursor + * @ingroup input */ typedef struct GLFWcursor GLFWcursor; -/*! @brief The function signature for error callbacks. +/*! @brief The function pointer type for memory allocation callbacks. * - * This is the function signature for error callback functions. + * 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 * - * @param[in] error An [error code](@ref errors). + * 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 + * function has the following signature: + * @code + * void callback_name(int error_code, const char* description) + * @endcode + * + * @param[in] error_code An [error code](@ref errors). Future releases may add + * more error codes. * @param[in] description A UTF-8 encoded string describing the error. * + * @pointer_lifetime The error description string is valid until the callback + * function returns. + * * @sa @ref error_handling * @sa @ref glfwSetErrorCallback * @@ -1141,17 +1587,21 @@ typedef struct GLFWcursor GLFWcursor; * * @ingroup init */ -typedef void (* GLFWerrorfun)(int,const char*); +typedef void (* GLFWerrorfun)(int error_code, const char* description); -/*! @brief The function signature for window position callbacks. +/*! @brief The function pointer type for window position callbacks. * - * This is the function signature for window position callback functions. + * This is the function pointer type for window position callbacks. A window + * position callback function has the following signature: + * @code + * void callback_name(GLFWwindow* window, int xpos, int ypos) + * @endcode * * @param[in] window The window that was moved. * @param[in] xpos The new x-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. + * upper-left corner of the content area of the window. * @param[in] ypos The new y-coordinate, in screen coordinates, of the - * upper-left corner of the client area of the window. + * upper-left corner of the content area of the window. * * @sa @ref window_pos * @sa @ref glfwSetWindowPosCallback @@ -1160,11 +1610,15 @@ typedef void (* GLFWerrorfun)(int,const char*); * * @ingroup window */ -typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); +typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); -/*! @brief The function signature for window resize callbacks. +/*! @brief The function pointer type for window size callbacks. * - * This is the function signature for window size callback functions. + * This is the function pointer type for window size callbacks. A window size + * callback function has the following signature: + * @code + * void callback_name(GLFWwindow* window, int width, int height) + * @endcode * * @param[in] window The window that was resized. * @param[in] width The new width, in screen coordinates, of the window. @@ -1178,11 +1632,15 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * * @ingroup window */ -typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); +typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); -/*! @brief The function signature for window close callbacks. +/*! @brief The function pointer type for window close callbacks. * - * This is the function signature for window close callback functions. + * This is the function pointer type for window close callbacks. A window + * close callback function has the following signature: + * @code + * void function_name(GLFWwindow* window) + * @endcode * * @param[in] window The window that the user attempted to close. * @@ -1194,11 +1652,15 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); * * @ingroup window */ -typedef void (* GLFWwindowclosefun)(GLFWwindow*); +typedef void (* GLFWwindowclosefun)(GLFWwindow* window); -/*! @brief The function signature for window content refresh callbacks. +/*! @brief The function pointer type for window content refresh callbacks. * - * This is the function signature for window refresh callback functions. + * This is the function pointer type for window content refresh callbacks. + * A window content refresh callback function has the following signature: + * @code + * void function_name(GLFWwindow* window); + * @endcode * * @param[in] window The window whose content needs to be refreshed. * @@ -1210,11 +1672,15 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow*); * * @ingroup window */ -typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); +typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); -/*! @brief The function signature for window focus/defocus callbacks. +/*! @brief The function pointer type for window focus callbacks. * - * This is the function signature for window focus callback functions. + * This is the function pointer type for window focus callbacks. A window + * focus callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int focused) + * @endcode * * @param[in] window The window that gained or lost input focus. * @param[in] focused `GLFW_TRUE` if the window was given input focus, or @@ -1227,12 +1693,15 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * * @ingroup window */ -typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); +typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); -/*! @brief The function signature for window iconify/restore callbacks. +/*! @brief The function pointer type for window iconify callbacks. * - * This is the function signature for window iconify/restore callback - * functions. + * This is the function pointer type for window iconify callbacks. A window + * iconify callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int iconified) + * @endcode * * @param[in] window The window that was iconified or restored. * @param[in] iconified `GLFW_TRUE` if the window was iconified, or @@ -1245,15 +1714,18 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); * * @ingroup window */ -typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); +typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); -/*! @brief The function signature for window maximize/restore callbacks. +/*! @brief The function pointer type for window maximize callbacks. * - * This is the function signature for window maximize/restore callback - * functions. + * This is the function pointer type for window maximize callbacks. A window + * maximize callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int maximized) + * @endcode * * @param[in] window The window that was maximized or restored. - * @param[in] iconified `GLFW_TRUE` if the window was maximized, or + * @param[in] maximized `GLFW_TRUE` if the window was maximized, or * `GLFW_FALSE` if it was restored. * * @sa @ref window_maximize @@ -1263,12 +1735,15 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); * * @ingroup window */ -typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); +typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); -/*! @brief The function signature for framebuffer resize callbacks. +/*! @brief The function pointer type for framebuffer size callbacks. * - * This is the function signature for framebuffer resize callback - * functions. + * This is the function pointer type for framebuffer size callbacks. + * A framebuffer size callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode * * @param[in] window The window whose framebuffer was resized. * @param[in] width The new width, in pixels, of the framebuffer. @@ -1281,12 +1756,15 @@ typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); * * @ingroup window */ -typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); +typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); -/*! @brief The function signature for window content scale callbacks. +/*! @brief The function pointer type for window content scale callbacks. * - * This is the function signature for window content scale callback - * functions. + * This is the function pointer type for window content scale callbacks. + * A window content scale callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, float xscale, float yscale) + * @endcode * * @param[in] window The window whose content scale changed. * @param[in] xscale The new x-axis content scale of the window. @@ -1299,16 +1777,21 @@ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); * * @ingroup window */ -typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float); +typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, float yscale); -/*! @brief The function signature for mouse button callbacks. +/*! @brief The function pointer type for mouse button callbacks. * - * This is the function signature for mouse button callback functions. + * This is the function pointer type for mouse button callback functions. + * A mouse button callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int button, int action, int mods) + * @endcode * * @param[in] window The window that received the event. * @param[in] button The [mouse button](@ref buttons) that was pressed or * released. - * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. + * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. Future releases + * may add more actions. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * @@ -1320,17 +1803,21 @@ typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float); * * @ingroup input */ -typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); +typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, int mods); -/*! @brief The function signature for cursor position callbacks. +/*! @brief The function pointer type for cursor position callbacks. * - * This is the function signature for cursor position callback functions. + * This is the function pointer type for cursor position callbacks. A cursor + * position callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, double xpos, double ypos); + * @endcode * * @param[in] window The window that received the event. * @param[in] xpos The new cursor x-coordinate, relative to the left edge of - * the client area. + * the content area. * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the - * client area. + * content area. * * @sa @ref cursor_pos * @sa @ref glfwSetCursorPosCallback @@ -1339,14 +1826,18 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * * @ingroup input */ -typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); +typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); -/*! @brief The function signature for cursor enter/leave callbacks. +/*! @brief The function pointer type for cursor enter/leave callbacks. * - * This is the function signature for cursor enter/leave callback functions. + * This is the function pointer type for cursor enter/leave callbacks. + * A cursor enter/leave callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int entered) + * @endcode * * @param[in] window The window that received the event. - * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's content * area, or `GLFW_FALSE` if it left it. * * @sa @ref cursor_enter @@ -1356,11 +1847,15 @@ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); * * @ingroup input */ -typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); +typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); -/*! @brief The function signature for scroll callbacks. +/*! @brief The function pointer type for scroll callbacks. * - * This is the function signature for scroll callback functions. + * This is the function pointer type for scroll callbacks. A scroll callback + * function has the following signature: + * @code + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * @endcode * * @param[in] window The window that received the event. * @param[in] xoffset The scroll offset along the x-axis. @@ -1373,16 +1868,21 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); * * @ingroup input */ -typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); +typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); -/*! @brief The function signature for keyboard key callbacks. +/*! @brief The function pointer type for keyboard key callbacks. * - * This is the function signature for keyboard key callback functions. + * This is the function pointer type for keyboard key callbacks. A keyboard + * key callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * @endcode * * @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 system-specific scancode of the key. - * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + * @param[in] scancode The platform-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 * held down. * @@ -1394,11 +1894,15 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * * @ingroup input */ -typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); +typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int action, int mods); -/*! @brief The function signature for Unicode character callbacks. +/*! @brief The function pointer type for Unicode character callbacks. * - * This is the function signature for Unicode character callback functions. + * This is the function pointer type for Unicode character callbacks. + * A Unicode character callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint) + * @endcode * * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. @@ -1411,14 +1915,18 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); * * @ingroup input */ -typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); +typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); -/*! @brief The function signature for Unicode character with modifiers +/*! @brief The function pointer type for Unicode character with modifiers * callbacks. * - * This is the function signature for Unicode character with modifiers callback - * functions. It is called for each input character, regardless of what - * modifier keys are held down. + * This is the function pointer type for Unicode character with modifiers + * callbacks. It is called for each input character, regardless of what + * modifier keys are held down. A Unicode character with modifiers callback + * function has the following signature: + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * @endcode * * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. @@ -1434,16 +1942,23 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * * @ingroup input */ -typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); +typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods); -/*! @brief The function signature for file drop callbacks. +/*! @brief The function pointer type for path drop callbacks. * - * This is the function signature for file drop callbacks. + * This is the function pointer type for path drop callbacks. A path drop + * callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * @endcode * * @param[in] window The window that received the event. - * @param[in] count The number of dropped files. + * @param[in] path_count The number of dropped paths. * @param[in] paths The UTF-8 encoded file and/or directory path names. * + * @pointer_lifetime The path array and its strings are valid until the + * callback function returns. + * * @sa @ref path_drop * @sa @ref glfwSetDropCallback * @@ -1451,15 +1966,19 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); * * @ingroup input */ -typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); +typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]); -/*! @brief The function signature for monitor configuration callbacks. +/*! @brief The function pointer type for monitor configuration callbacks. * - * This is the function signature for monitor configuration callback functions. + * This is the function pointer type for monitor configuration callbacks. + * A monitor callback function has the following signature: + * @code + * void function_name(GLFWmonitor* monitor, int event) + * @endcode * * @param[in] monitor The monitor that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Remaining - * values reserved for future use. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. * * @sa @ref monitor_event * @sa @ref glfwSetMonitorCallback @@ -1468,16 +1987,19 @@ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); * * @ingroup monitor */ -typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); +typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); -/*! @brief The function signature for joystick configuration callbacks. +/*! @brief The function pointer type for joystick configuration callbacks. * - * This is the function signature for joystick configuration callback - * functions. + * This is the function pointer type for joystick configuration callbacks. + * A joystick configuration callback function has the following signature: + * @code + * void function_name(int jid, int event) + * @endcode * * @param[in] jid The joystick that was connected or disconnected. - * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Remaining - * values reserved for future use. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. * * @sa @ref joystick_event * @sa @ref glfwSetJoystickCallback @@ -1486,7 +2008,7 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); * * @ingroup input */ -typedef void (* GLFWjoystickfun)(int,int); +typedef void (* GLFWjoystickfun)(int jid, int event); /*! @brief Video mode type. * @@ -1561,6 +2083,8 @@ typedef struct GLFWgammaramp * * @since Added in version 2.1. * @glfw3 Removed format and bytes-per-pixel members. + * + * @ingroup window */ typedef struct GLFWimage { @@ -1583,6 +2107,8 @@ typedef struct GLFWimage * @sa @ref glfwGetGamepadState * * @since Added in version 3.3. + * + * @ingroup input */ typedef struct GLFWgamepadstate { @@ -1596,6 +2122,38 @@ 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 @@ -1614,19 +2172,45 @@ typedef struct GLFWgamepadstate * 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_ERROR. + * @errors Possible errors include @ref GLFW_PLATFORM_UNAVAILABLE and @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 * bundle, if present. This can be disabled with the @ref * GLFW_COCOA_CHDIR_RESOURCES init hint. * + * @remark @macos This function will create the main menu and dock icon for the + * application. If GLFW finds a `MainMenu.nib` it is loaded and assumed to + * contain a menu bar. Otherwise a minimal menu bar is created manually with + * common commands like Hide, Quit and About. The About entry opens a minimal + * about dialog with information from the application's bundle. The menu bar + * 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. + * * @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. @@ -1647,6 +2231,8 @@ GLFWAPI int glfwInit(void); * call this function, as it is called by @ref glfwInit before it returns * failure. * + * This function has no effect if GLFW is not initialized. + * * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * * @remark This function may be called before @ref glfwInit. @@ -1699,6 +2285,85 @@ 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 @@ -1729,15 +2394,18 @@ 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, 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`. + * [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`. * * __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. @@ -1808,10 +2476,17 @@ GLFWAPI int glfwGetError(const char** description); * Once set, the error callback remains set even after the library has been * terminated. * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set. * + * @callback_signature + * @code + * void callback_name(int error_code, const char* description) + * @endcode + * For more information about the callback parameters, see the + * [callback pointer type](@ref GLFWerrorfun). + * * @errors None. * * @remark This function may be called before @ref glfwInit. @@ -1825,7 +2500,52 @@ GLFWAPI int glfwGetError(const char** description); * * @ingroup init */ -GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); +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. * @@ -1905,15 +2625,47 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); */ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); +/*! @brief Retrieves the work area of the monitor. + * + * 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 + * task bar exists then the work area is the monitor resolution in screen + * coordinates. + * + * Any or all of the position and size arguments may be `NULL`. If an error + * occurs, all non-`NULL` position and size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * @param[out] width Where to store the monitor width, or `NULL`. + * @param[out] height Where to store the monitor height, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_workarea + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); + /*! @brief Returns the physical size of the monitor. * * This function returns the size, in millimetres, of the display area of the * specified monitor. * - * 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. + * 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 * * Any or all of the size arguments may be `NULL`. If an error occurs, all * non-`NULL` size arguments will be set to zero. @@ -1926,8 +2678,8 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @remark @win32 calculates the returned physical size from the - * current resolution and system DPI instead of querying the monitor EDID data. + * @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. * * @thread_safety This function must only be called from the main thread. * @@ -1943,9 +2695,11 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* * * This function retrieves the content scale for the specified monitor. The * content scale is the ratio between the current DPI and the platform's - * default DPI. If you scale all pixel dimensions by this scale then your - * content should appear at an appropriate size. This is especially important - * for text and any UI elements. + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. * * The content scale may depend on both the monitor resolution and pixel * density and on user settings. It may be very different from the raw DPI @@ -1958,6 +2712,9 @@ 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 @@ -2051,11 +2808,18 @@ GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); * currently set callback. This is called when a monitor is connected to or * disconnected from the system. * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWmonitor* monitor, int event) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmonitorfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -2066,14 +2830,15 @@ GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); * * @ingroup monitor */ -GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun callback); /*! @brief Returns the available video modes for the specified monitor. * * 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) and then by resolution area (the - * product of width and height). + * 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. * * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned @@ -2131,9 +2896,9 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * - * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. The value must be a finite - * number greater than zero. + * This function generates an appropriately sized gamma ramp from the specified + * exponent and then calls @ref glfwSetGammaRamp with it. The value must be + * a finite number greater than zero. * * The software controlled gamma ramp is applied _in addition_ to the hardware * gamma correction, which today is usually an approximation of sRGB gamma. @@ -2146,11 +2911,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 and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE, + * @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks). * - * @remark @wayland Gamma handling is a priviledged protocol, this function - * will thus never be implemented and emits @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. * * @thread_safety This function must only be called from the main thread. * @@ -2170,11 +2935,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 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 Gamma handling is a priviledged protocol, this function - * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while * returning `NULL`. * * @pointer_lifetime The returned structure and its arrays are allocated and @@ -2209,16 +2974,16 @@ 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 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 Gamma ramp sizes other than 256 are not supported by all platforms - * or graphics hardware. + * @remark The size of the specified gamma ramp should match the size of the + * current ramp for that monitor. * * @remark @win32 The gamma ramp size must be 256. * - * @remark @wayland Gamma handling is a priviledged protocol, this function - * will thus never be implemented and emits @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. * * @pointer_lifetime The specified gamma ramp is copied before this function * returns. @@ -2361,10 +3126,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, 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. + * 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`. * * As long as at least one full screen window is not iconified, the screensaver * is prohibited from starting. @@ -2390,8 +3155,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 and @ref - * GLFW_PLATFORM_ERROR. + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. * * @remark @win32 Window creation will fail if the Microsoft GDI software * OpenGL implementation is the only one available. @@ -2404,39 +3169,43 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * @remark @win32 The context to share resources with must not be current on * any other thread. * - * @remark @macos The OS only supports forward-compatible core profile contexts - * for OpenGL versions 3.2 and later. Before creating an OpenGL context of - * version 3.2 or later you must set the - * [GLFW_OPENGL_FORWARD_COMPAT](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) and - * [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) hints accordingly. - * OpenGL 3.0 and 3.1 contexts are not supported at all on macOS. + * @remark @macos The OS only supports core profile contexts for OpenGL + * versions 3.2 and later. Before creating an OpenGL context of version 3.2 or + * later you must set the [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) + * hint accordingly. OpenGL 3.0 and 3.1 contexts are not supported at all + * on macOS. * * @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](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. + * [Bundle Programming Guide][bundle-guide] in the Mac Developer Library. * - * @remark @macos The first time a window is created the menu bar is created. - * If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu - * bar. Otherwise a minimal menu bar is created manually with common commands - * like Hide, Quit and About. The About entry opens a minimal about dialog - * with information from the application's bundle. Menu bar creation can be - * disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint. + * [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/ * * @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_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) + * [GLFW_SCALE_FRAMEBUFFER](@ref GLFW_SCALE_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](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/MacOSXBundleInfo.plist.in` in the source tree. + * [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 * * @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 overriden by previously saved values. + * 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. @@ -2449,21 +3218,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value); * @remark @x11 The class part of the `WM_CLASS` window property will by * default be set to the window title passed to this function. The instance * part will use the contents of the `RESOURCE_NAME` environment variable, if - * present and not empty, or fall back to the window title. Set the @ref - * GLFW_X11_CLASS_NAME and @ref GLFW_X11_INSTANCE_NAME window hints to override - * this. - * - * @remark @wayland The window frame is currently very simple, only allowing - * window resize or move. A compositor can still emit close, maximize or - * fullscreen events, using for example a keybind mechanism. Additionally, - * the wp_viewporter protocol is required for this feature, otherwise the - * window will not 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. + * present and not empty, or fall back to the window title. Set the + * [GLFW_X11_CLASS_NAME](@ref GLFW_X11_CLASS_NAME_hint) and + * [GLFW_X11_INSTANCE_NAME](@ref GLFW_X11_INSTANCE_NAME_hint) window hints to + * override this. * * @thread_safety This function must only be called from the main thread. * @@ -2547,6 +3305,38 @@ 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 @@ -2564,6 +3354,7 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @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. @@ -2593,21 +3384,23 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * @param[in] images The images to create the icon from. This is ignored if * count is zero. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref + * GLFW_FEATURE_UNAVAILABLE (see remarks). * * @pointer_lifetime The specified image data is copied before this function * returns. * - * @remark @macos The GLFW window has no icon, as it is not a document - * window, so this function does nothing. The dock icon will be the same as + * @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](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) - * in the Mac Developer Library. + * [Bundle Programming Guide][bundle-guide] in the Mac Developer Library. + * + * [bundle-guide]: https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/ * * @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. - * This function always emits @ref GLFW_PLATFORM_ERROR. + * This function will emit @ref GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -2619,26 +3412,26 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); */ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); -/*! @brief Retrieves the position of the client area of the specified window. +/*! @brief Retrieves the position of the content area of the specified window. * * This function retrieves the position, in screen coordinates, of the - * upper-left corner of the client area of the specified window. + * upper-left corner of the content area of the specified window. * * Any or all of the position arguments may be `NULL`. If an error occurs, all * non-`NULL` position arguments will be set to zero. * * @param[in] window The window to query. * @param[out] xpos Where to store the x-coordinate of the upper-left corner of - * the client area, or `NULL`. + * the content area, or `NULL`. * @param[out] ypos Where to store the y-coordinate of the upper-left corner of - * the client area, or `NULL`. + * the content area, or `NULL`. * - * @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 There is no way for an application to retrieve the global - * position of its windows, this function will always emit @ref - * GLFW_PLATFORM_ERROR. + * position of its windows. This function will emit @ref + * GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -2651,10 +3444,10 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i */ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); -/*! @brief Sets the position of the client area of the specified window. +/*! @brief Sets the position of the content area of the specified window. * * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the specified windowed mode window. If the + * corner of the content area of the specified windowed mode window. If the * window is a full screen window, this function does nothing. * * __Do not use this function__ to move an already visible window unless you @@ -2664,15 +3457,15 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); * cannot and should not override these limits. * * @param[in] window The window to query. - * @param[in] xpos The x-coordinate of the upper-left corner of the client area. - * @param[in] ypos The y-coordinate of the upper-left corner of the client area. + * @param[in] xpos The x-coordinate of the upper-left corner of the content area. + * @param[in] ypos The y-coordinate of the upper-left corner of the content area. * - * @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 There is no way for an application to set the global - * position of its windows, this function will always emit @ref - * GLFW_PLATFORM_ERROR. + * position of its windows. This function will emit @ref + * GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -2686,9 +3479,9 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); */ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); -/*! @brief Retrieves the size of the client area of the specified window. +/*! @brief Retrieves the size of the content area of the specified window. * - * This function retrieves the size, in screen coordinates, of the client area + * This function retrieves the size, in screen coordinates, of the content area * of the specified window. If you wish to retrieve the size of the * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. * @@ -2697,9 +3490,9 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * * @param[in] window The window whose size to retrieve. * @param[out] width Where to store the width, in screen coordinates, of the - * client area, or `NULL`. + * content area, or `NULL`. * @param[out] height Where to store the height, in screen coordinates, of the - * client area, or `NULL`. + * content area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. @@ -2718,7 +3511,7 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); /*! @brief Sets the size limits of the specified window. * - * This function sets the size limits of the client area of the specified + * This function sets the size limits of the content area of the specified * window. If the window is full screen, the size limits only take effect * once it is made windowed. If the window is not resizable, this function * does nothing. @@ -2730,14 +3523,14 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); * dimensions and all must be greater than or equal to zero. * * @param[in] window The window to set limits for. - * @param[in] minwidth The minimum width, in screen coordinates, of the client + * @param[in] minwidth The minimum width, in screen coordinates, of the content * area, or `GLFW_DONT_CARE`. * @param[in] minheight The minimum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. - * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * content area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the content * area, or `GLFW_DONT_CARE`. * @param[in] maxheight The maximum height, in screen coordinates, of the - * client area, or `GLFW_DONT_CARE`. + * content area, or `GLFW_DONT_CARE`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. @@ -2761,7 +3554,7 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe /*! @brief Sets the aspect ratio of the specified window. * - * This function sets the required aspect ratio of the client area of the + * This function sets the required aspect ratio of the content area of the * specified window. If the window is full screen, the aspect ratio only takes * effect once it is made windowed. If the window is not resizable, this * function does nothing. @@ -2802,9 +3595,9 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe */ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); -/*! @brief Sets the size of the client area of the specified window. +/*! @brief Sets the size of the content area of the specified window. * - * This function sets the size, in screen coordinates, of the client area of + * This function sets the size, in screen coordinates, of the content area of * the specified window. * * For full screen windows, this function updates the resolution of its desired @@ -2820,16 +3613,13 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * * @param[in] window The window to resize. * @param[in] width The desired width, in screen coordinates, of the window - * client area. + * content area. * @param[in] height The desired height, in screen coordinates, of the window - * client area. + * content area. * * @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 @@ -2913,11 +3703,13 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * * This function retrieves the content scale for the specified window. The * content scale is the ratio between the current DPI and the platform's - * default DPI. If you scale all pixel dimensions by this scale then your - * content should appear at an appropriate size. This is especially important - * for text and any UI elements. + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. * - * On systems where each monitors can have its own content scale, the window + * On platforms 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. * @@ -2982,8 +3774,11 @@ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); * @param[in] window The window to set the opacity for. * @param[in] opacity The desired opacity of the specified window. * - * @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 There is no way to set an opacity factor for a window. + * This function will emit @ref GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -3002,16 +3797,17 @@ 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, the original monitor - * resolution is restored until the window is restored. + * 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. * * @param[in] window The window to iconify. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland There is no concept of iconification in wl_shell, this - * function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated + * @remark @wayland Once a window is iconified, @ref glfwRestoreWindow won’t + * be able to restore it. This is a design decision of the xdg-shell * protocol. * * @thread_safety This function must only be called from the main thread. @@ -3033,8 +3829,8 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); * (minimized) or maximized. If the window is already restored, this function * does nothing. * - * If the specified window is a full screen window, the resolution chosen for - * the window is restored on the selected monitor. + * 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. * * @param[in] window The window to restore. * @@ -3085,11 +3881,21 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); * hidden. If the window is already visible or is in full screen mode, this * function does nothing. * + * By default, windowed mode windows are focused when shown + * Set the [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) window hint + * to change this behavior for all newly created windows, or change the + * behavior for an existing window with @ref glfwSetWindowAttrib. + * * @param[in] window The window to make visible. * * @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 @@ -3132,6 +3938,10 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * initially created. Set the [GLFW_FOCUSED](@ref GLFW_FOCUSED_hint) to * disable this behavior. * + * Also by default, windowed mode windows are focused when shown + * with @ref glfwShowWindow. Set the + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) to disable this behavior. + * * __Do not use this function__ to steal focus from other applications unless * you are certain that is what the user wants. Focus stealing can be * extremely disruptive. @@ -3144,8 +3954,8 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland It is not possible for an application to bring its windows - * to front, this function will always emit @ref GLFW_PLATFORM_ERROR. + * @remark @wayland The compositor will likely ignore focus requests unless + * another window created by the same application already has input focus. * * @thread_safety This function must only be called from the main thread. * @@ -3217,7 +4027,7 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); * The window position is ignored when setting a monitor. * * When the monitor is `NULL`, the position, width and height are used to - * place the window client area. The refresh rate is ignored when no monitor + * place the window content area. The refresh rate is ignored when no monitor * is specified. * * If you only wish to update the resolution of a full screen window or the @@ -3230,12 +4040,12 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); * @param[in] window The window whose monitor, size or video mode to set. * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. * @param[in] xpos The desired x-coordinate of the upper-left corner of the - * client area. + * content area. * @param[in] ypos The desired y-coordinate of the upper-left corner of the - * client area. - * @param[in] width The desired with, in screen coordinates, of the client area - * or video mode. - * @param[in] height The desired height, in screen coordinates, of the client + * content area. + * @param[in] width The desired with, in screen coordinates, of the content + * area or video mode. + * @param[in] height The desired height, in screen coordinates, of the content * area or video mode. * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, * or `GLFW_DONT_CARE`. @@ -3250,9 +4060,6 @@ 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 @@ -3288,6 +4095,9 @@ 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 @@ -3306,8 +4116,10 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), - * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and - * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib). + * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib), + * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib). + * [GLFW_MOUSE_PASSTHROUGH](@ref GLFW_MOUSE_PASSTHROUGH_attrib) * * Some of these attributes are ignored for full screen windows. The new * value will take effect if the window is later made windowed. @@ -3320,11 +4132,15 @@ 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 and @ref GLFW_PLATFORM_ERROR. + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref + * GLFW_FEATURE_UNAVAILABLE (see remarks). * * @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 @@ -3384,15 +4200,22 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * * This function sets the position callback of the specified window, which is * called when the window is moved. The callback is provided with the - * position, in screen coordinates, of the upper-left corner of the client area - * of the window. + * position, in screen coordinates, of the upper-left corner of the content + * area of the window. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int xpos, int ypos) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowposfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark @wayland This callback will never be called, as there is no way for @@ -3406,20 +4229,27 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * * @ingroup window */ -GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun callback); /*! @brief Sets the size callback for the specified window. * * This function sets the size callback of the specified window, which is * called when the window is resized. The callback is provided with the size, - * in screen coordinates, of the client area of the window. + * in screen coordinates, of the content area of the window. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowsizefun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3431,7 +4261,7 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * * @ingroup window */ -GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun callback); /*! @brief Sets the close callback for the specified window. * @@ -3445,11 +4275,18 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * The close callback is not triggered by @ref glfwDestroyWindow. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowclosefun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @remark @macos Selecting Quit from the application menu will trigger the @@ -3464,12 +4301,12 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * * @ingroup window */ -GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback); /*! @brief Sets the refresh callback for the specified window. * * This function sets the refresh callback of the specified window, which is - * called when the client area of the window needs to be redrawn, for example + * called when the content area of the window needs to be redrawn, for example * if the window has been exposed after having been covered by another window. * * On compositing window systems such as Aero, Compiz, Aqua or Wayland, where @@ -3477,11 +4314,18 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * very infrequently or never at all. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window); + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowrefreshfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3493,7 +4337,7 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * * @ingroup window */ -GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun callback); /*! @brief Sets the focus callback for the specified window. * @@ -3506,11 +4350,18 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL * and @ref glfwSetMouseButtonCallback. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int focused) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowfocusfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3521,7 +4372,7 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL * * @ingroup window */ -GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun callback); /*! @brief Sets the iconify callback for the specified window. * @@ -3529,15 +4380,19 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * is called when the window is iconified or restored. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int iconified) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowiconifyfun). * - * @remark @wayland The wl_shell protocol has no concept of iconification, - * this callback will never be called when using this deprecated protocol. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * @@ -3547,7 +4402,7 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * * @ingroup window */ -GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun callback); /*! @brief Sets the maximize callback for the specified window. * @@ -3555,11 +4410,18 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * is called when the window is maximized or restored. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int maximized) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowmaximizefun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3570,7 +4432,7 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * * @ingroup window */ -GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun cbfun); +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback); /*! @brief Sets the framebuffer resize callback for the specified window. * @@ -3578,11 +4440,18 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, * which is called when the framebuffer of the specified window is resized. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWframebuffersizefun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3593,7 +4462,7 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, * * @ingroup window */ -GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun callback); /*! @brief Sets the window content scale callback for the specified window. * @@ -3601,11 +4470,18 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * which is called when the content scale of the specified window changes. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, float xscale, float yscale) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowcontentscalefun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -3617,7 +4493,7 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * * @ingroup window */ -GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun cbfun); +GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun callback); /*! @brief Processes all pending events. * @@ -3683,10 +4559,6 @@ GLFWAPI void glfwPollEvents(void); * GLFW will pass those events on to the application callbacks before * returning. * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * * Event processing is not required for joystick input to work. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref @@ -3734,14 +4606,13 @@ GLFWAPI void glfwWaitEvents(void); * GLFW will pass those events on to the application callbacks before * returning. * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * * Event processing is not required for joystick input to work. * * @param[in] timeout The maximum amount of time, in seconds, to wait. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * * @reentrancy This function must not be called from a callback. * * @thread_safety This function must only be called from the main thread. @@ -3761,10 +4632,6 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout); * This function posts an empty event from the current thread to the event * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. * - * If no windows exist, this function returns immediately. For synchronization - * of threads in applications that do not create windows, use your threading - * library of choice. - * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * @@ -3784,11 +4651,13 @@ GLFWAPI void glfwPostEmptyEvent(void); * * This function returns the value of an input option for the specified window. * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, - * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. * * @param[in] window The window to query. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, - * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. @@ -3807,16 +4676,19 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * * This function sets an input mode option for the specified window. The mode * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, - * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. - * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the + * content area of the window but does not restrict the cursor from leaving. * - `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 @@ -3839,13 +4711,21 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. * + * If the mode is `GLFW_RAW_MOUSE_MOTION`, the value must be either `GLFW_TRUE` + * to enable raw (unscaled and unaccelerated) mouse motion when the cursor is + * disabled, or `GLFW_FALSE` to disable it. If raw motion is not supported, + * attempting to set this will emit @ref GLFW_FEATURE_UNAVAILABLE. Call @ref + * glfwRawMouseMotionSupported to check for support. + * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, - * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * GLFW_INVALID_ENUM, @ref GLFW_PLATFORM_ERROR and @ref + * GLFW_FEATURE_UNAVAILABLE (see above). * * @thread_safety This function must only be called from the main thread. * @@ -3857,6 +4737,35 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); +/*! @brief Returns whether raw mouse motion is supported. + * + * This function returns whether raw mouse motion is supported on the current + * system. This status does not change after GLFW has been initialized so you + * only need to check this once. If you attempt to enable raw motion on + * a system that does not support it, @ref GLFW_PLATFORM_ERROR will be emitted. + * + * Raw mouse motion is closer to the actual motion of the mouse across + * a surface. It is not affected by the scaling and acceleration applied to + * the motion of the desktop cursor. That processing is suitable for a cursor + * while raw motion is better for controlling for example a 3D camera. Because + * of this, raw mouse motion is only provided when the cursor is disabled. + * + * @return `GLFW_TRUE` if raw mouse motion is supported on the current machine, + * or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref raw_mouse_motion + * @sa @ref glfwSetInputMode + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwRawMouseMotionSupported(void); + /*! @brief Returns the layout-specific name of the specified printable key. * * This function returns the name of the specified printable key, encoded as @@ -3906,12 +4815,14 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * @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 and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE, @ref GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark The contents of the returned string may change when a keyboard + * layout change event is received. * * @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 - * glfwGetKeyName, or until the library is terminated. + * should not free it yourself. It is valid until the library is terminated. * * @thread_safety This function must only be called from the main thread. * @@ -3927,15 +4838,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode); * * This function returns the platform-specific scancode of the specified key. * - * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this - * method will return `-1`. + * 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. * - * @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. + * @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. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. * * @thread_safety This function may be called from any thread. * @@ -3952,8 +4866,7 @@ 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 higher-level action `GLFW_REPEAT` is only reported to - * the key callback. + * `GLFW_RELEASE`. The 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 @@ -3995,8 +4908,8 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * `GLFW_RELEASE`. * * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function - * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, - * even if that mouse button has already been released. + * returns `GLFW_PRESS` the first time you call it for a mouse button that was + * pressed, even if that mouse button has already been released. * * @param[in] window The desired window. * @param[in] button The desired [mouse button](@ref buttons). @@ -4016,11 +4929,11 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); */ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); -/*! @brief Retrieves the position of the cursor relative to the client area of +/*! @brief Retrieves the position of the cursor relative to the content area of * the window. * * This function returns the position of the cursor, in screen coordinates, - * relative to the upper-left corner of the client area of the specified + * relative to the upper-left corner of the content area of the specified * window. * * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor @@ -4036,9 +4949,9 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * * @param[in] window The desired window. * @param[out] xpos Where to store the cursor x-coordinate, relative to the - * left edge of the client area, or `NULL`. + * left edge of the content area, or `NULL`. * @param[out] ypos Where to store the cursor y-coordinate, relative to the to - * top edge of the client area, or `NULL`. + * top edge of the content area, or `NULL`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. @@ -4054,11 +4967,11 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); */ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); -/*! @brief Sets the position of the cursor, relative to the client area of the +/*! @brief Sets the position of the cursor, relative to the content area of the * window. * * This function sets the position, in screen coordinates, of the cursor - * relative to the upper-left corner of the client area of the specified + * relative to the upper-left corner of the content area of the specified * window. The window must have input focus. If the window does not have * input focus when this function is called, it fails silently. * @@ -4073,15 +4986,15 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * * @param[in] window The desired window. * @param[in] xpos The desired x-coordinate, relative to the left edge of the - * client area. + * content area. * @param[in] ypos The desired y-coordinate, relative to the top edge of the - * client area. + * content area. * - * @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 This function will only work when the cursor mode is - * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. + * `GLFW_CURSOR_DISABLED`, otherwise it will emit @ref GLFW_FEATURE_UNAVAILABLE. * * @thread_safety This function must only be called from the main thread. * @@ -4114,8 +5027,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 and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified image data is copied before this function * returns. @@ -4134,19 +5047,44 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) /*! @brief Creates a cursor with a standard shape. * - * Returns a cursor with a [standard shape](@ref shapes), that can be set for - * a window with @ref glfwSetCursor. + * Returns a cursor with a standard shape, that can be set for a window with + * @ref glfwSetCursor. The images for these cursors come from the system + * cursor theme and their exact appearance will vary between platforms. + * + * Most of these shapes are guaranteed to exist on every supported platform but + * a few may not be present. See the table below for details. + * + * Cursor shape | Windows | macOS | X11 | Wayland + * ------------------------------ | ------- | ----- | ------ | ------- + * @ref GLFW_ARROW_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_IBEAM_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_CROSSHAIR_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_POINTING_HAND_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_EW_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_NS_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_RESIZE_NWSE_CURSOR | Yes | Yes1 | Maybe2 | Maybe2 + * @ref GLFW_RESIZE_NESW_CURSOR | Yes | Yes1 | Maybe2 | Maybe2 + * @ref GLFW_RESIZE_ALL_CURSOR | Yes | Yes | Yes | Yes + * @ref GLFW_NOT_ALLOWED_CURSOR | Yes | Yes | Maybe2 | Maybe2 + * + * 1) This uses a private system API and may fail in the future. + * + * 2) This uses a newer standard that not all cursor themes support. + * + * If the requested shape is not available, this function emits a @ref + * GLFW_CURSOR_UNAVAILABLE error and returns `NULL`. * * @param[in] shape One of the [standard shapes](@ref shapes). * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref - * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * GLFW_INVALID_ENUM, @ref GLFW_CURSOR_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * * @thread_safety This function must only be called from the main thread. * - * @sa @ref cursor_object + * @sa @ref cursor_standard * @sa @ref glfwCreateCursor * * @since Added in version 3.1. @@ -4185,7 +5123,7 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); /*! @brief Sets the cursor for the window. * * This function sets the cursor image to be used when the cursor is over the - * client area of the specified window. The set cursor will only be visible + * content area of the specified window. The set cursor will only be visible * when the [cursor mode](@ref cursor_mode) of the window is * `GLFW_CURSOR_NORMAL`. * @@ -4220,9 +5158,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. 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 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 * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that @@ -4234,11 +5172,18 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * scancode may be zero. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new key callback, or `NULL` to remove the currently + * @param[in] callback The new key callback, or `NULL` to remove the currently * set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWkeyfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4250,7 +5195,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * * @ingroup input */ -GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback); /*! @brief Sets the Unicode character callback. * @@ -4267,16 +5212,21 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * The character callback behaves as system text input normally does and will * not be called if modifier keys are held down that would prevent normal text * input on that platform, for example a Super (Command) key on macOS or Alt key - * on Windows. There is a - * [character with modifiers callback](@ref glfwSetCharModsCallback) that - * receives these events. + * on Windows. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4288,7 +5238,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * * @ingroup input */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun callback); /*! @brief Sets the Unicode character with modifiers callback. * @@ -4306,11 +5256,18 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * [key callback](@ref glfwSetKeyCallback) instead. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or an * [error](@ref error_handling) occurred. * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharmodsfun). + * * @deprecated Scheduled for removal in version 4.0. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. @@ -4323,7 +5280,7 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * * @ingroup input */ -GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun callback); /*! @brief Sets the mouse button callback. * @@ -4337,11 +5294,18 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int button, int action, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmousebuttonfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4353,21 +5317,28 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * * @ingroup input */ -GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback); /*! @brief Sets the cursor position callback. * * This function sets the cursor position callback of the specified window, * which is called when the cursor is moved. The callback is provided with the * position, in screen coordinates, relative to the upper-left corner of the - * client area of the window. + * content area of the window. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double xpos, double ypos); + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorposfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4378,20 +5349,27 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * * @ingroup input */ -GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback); -/*! @brief Sets the cursor enter/exit callback. +/*! @brief Sets the cursor enter/leave callback. * * This function sets the cursor boundary crossing callback of the specified - * window, which is called when the cursor enters or leaves the client area of + * window, which is called when the cursor enters or leaves the content area of * the window. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int entered) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorenterfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4402,7 +5380,7 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * * @ingroup input */ -GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun callback); /*! @brief Sets the scroll callback. * @@ -4414,11 +5392,18 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * wheel or a touchpad scrolling area. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently - * set callback. + * @param[in] callback The new scroll callback, or `NULL` to remove the + * currently set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWscrollfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4429,12 +5414,12 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * * @ingroup input */ -GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback); -/*! @brief Sets the file drop callback. +/*! @brief Sets the path drop callback. * - * This function sets the file drop callback of the specified window, which is - * called when one or more dragged files are dropped on the window. + * This function sets the path drop callback of the specified window, which is + * called when one or more dragged paths are dropped on the window. * * Because the path array and its strings may have been generated specifically * for that event, they are not guaranteed to be valid after the callback has @@ -4442,14 +5427,19 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb * make a deep copy. * * @param[in] window The window whose callback to set. - * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * @param[in] callback The new file drop callback, or `NULL` to remove the * currently set callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWdropfun). * - * @remark @wayland File drop is currently unimplemented. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. * @@ -4459,7 +5449,7 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb * * @ingroup input */ -GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback); /*! @brief Returns whether the specified joystick is present. * @@ -4565,7 +5555,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); * Each element in the array is one of the following values: * * Name | Value - * --------------------- | -------------------------------- + * ---- | ----- * `GLFW_HAT_CENTERED` | 0 * `GLFW_HAT_UP` | 1 * `GLFW_HAT_RIGHT` | 2 @@ -4647,7 +5637,7 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); */ GLFWAPI const char* glfwGetJoystickName(int jid); -/*! @brief Returns the SDL comaptible GUID of the specified joystick. +/*! @brief Returns the SDL compatible GUID of the specified joystick. * * This function returns the SDL compatible GUID, as a UTF-8 encoded * hexadecimal string, of the specified joystick. The returned string is @@ -4778,11 +5768,18 @@ GLFWAPI int glfwJoystickIsGamepad(int jid); * called by joystick functions. The function will then return whatever it * returns if the joystick is not present. * - * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * @param[in] callback The new callback, or `NULL` to remove the currently set * callback. * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * + * @callback_signature + * @code + * void function_name(int jid, int event) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWjoystickfun). + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4793,7 +5790,7 @@ GLFWAPI int glfwJoystickIsGamepad(int jid); * * @ingroup input */ -GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback); /*! @brief Adds the specified SDL_GameControllerDB gamepad mappings. * @@ -4844,6 +5841,8 @@ 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. @@ -4861,7 +5860,7 @@ GLFWAPI const char* glfwGetGamepadName(int jid); /*! @brief Retrieves the state of the specified joystick remapped as a gamepad. * - * This function retrives the state of the specified joystick remapped to + * This function retrieves the state of the specified joystick remapped to * an Xbox-like gamepad. * * If the specified joystick is not present or does not have a gamepad mapping @@ -4885,6 +5884,8 @@ GLFWAPI const char* glfwGetGamepadName(int jid); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. * + * @thread_safety This function must only be called from the main thread. + * * @sa @ref gamepad * @sa @ref glfwUpdateGamepadMappings * @sa @ref glfwJoystickIsGamepad @@ -4906,7 +5907,10 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. * - * @remark @wayland Clipboard is currently unimplemented. + * @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. @@ -4933,10 +5937,13 @@ 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 and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_FORMAT_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * - * @remark @wayland Clipboard is currently unimplemented. + * @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 returned string is allocated and freed by GLFW. You * should not free it yourself. It is valid until the next call to @ref @@ -4954,23 +5961,26 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); -/*! @brief Returns the value of the GLFW timer. +/*! @brief Returns the GLFW time. * - * This function returns the value of the GLFW timer. Unless the timer has - * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW - * was initialized. + * This function returns the current GLFW time, in seconds. Unless the time + * has been set using @ref glfwSetTime it measures time elapsed since GLFW was + * initialized. + * + * This function and @ref glfwSetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. * * 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 supported platform. + * time source on each operating system. * - * @return The current value, in seconds, or zero if an + * @return The current time, in seconds, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be + * writing of the internal base time is not atomic, so it needs to be * externally synchronized with calls to @ref glfwSetTime. * * @sa @ref time @@ -4981,23 +5991,26 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); */ GLFWAPI double glfwGetTime(void); -/*! @brief Sets the GLFW timer. +/*! @brief Sets the GLFW time. * - * This function sets the value of the GLFW timer. It then continues to count - * up from that value. The value must be a positive finite number less than - * or equal to 18446744073.0, which is approximately 584.5 years. + * This function sets the current GLFW time, in seconds. The value must be + * a positive finite number less than or equal to 18446744073.0, which is + * approximately 584.5 years. + * + * This function and @ref glfwGetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. * * @param[in] time The new value, in seconds. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_VALUE. * - * @remark The upper limit of the timer is calculated as + * @remark The upper limit of GLFW time is calculated as * floor((264 - 1) / 109) and is due to implementations * storing nanoseconds in 64 bits. The limit may be increased in the future. * * @thread_safety This function may be called from any thread. Reading and - * writing of the internal timer offset is not atomic, so it needs to be + * writing of the internal base time is not atomic, so it needs to be * externally synchronized with calls to @ref glfwGetTime. * * @sa @ref time @@ -5054,12 +6067,15 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * 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. + * 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`. * - * When moving a context between threads, you must make it non-current on the - * old thread before making it current on the new one. + * 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. * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control @@ -5074,6 +6090,10 @@ 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. * @@ -5170,7 +6190,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 on that platform. This is done + * swap interval set to whatever is the default for that API. 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. * @@ -5274,13 +6294,11 @@ 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. - * 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. + * 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. * * @return `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` * otherwise. @@ -5301,7 +6319,7 @@ GLFWAPI int glfwVulkanSupported(void); * * This function returns an array of names of Vulkan instance extensions required * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the - * list will always contains `VK_KHR_surface`, so if you don't require any + * list will always contain `VK_KHR_surface`, so if you don't require any * additional extensions you can pass this list directly to the * `VkInstanceCreateInfo` struct. * @@ -5326,9 +6344,6 @@ 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 only supports the - * `VK_MVK_macos_surface` extension from MoltenVK. - * * @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. @@ -5410,7 +6425,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` extension does not provide + * `VK_MVK_macos_surface` and `VK_EXT_metal_surface` extensions do not provide * a `vkGetPhysicalDevice*PresentationSupport` type function. * * @thread_safety This function may be called from any thread. For @@ -5467,12 +6482,21 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should * eliminate almost all occurrences of these errors. * - * @remark @macos This function currently only supports the - * `VK_MVK_macos_surface` extension from MoltenVK. + * @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 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. * @@ -5509,6 +6533,7 @@ 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 4372cb7..92f0d32 100644 --- a/raylib/external/glfw/include/GLFW/glfw3native.h +++ b/raylib/external/glfw/include/GLFW/glfw3native.h @@ -1,9 +1,9 @@ /************************************************************************* - * GLFW 3.3 - www.glfw.org + * GLFW 3.4 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2016 Camilla Löwy + * 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 @@ -62,7 +62,6 @@ extern "C" { * * `GLFW_EXPOSE_NATIVE_COCOA` * * `GLFW_EXPOSE_NATIVE_X11` * * `GLFW_EXPOSE_NATIVE_WAYLAND` - * * `GLFW_EXPOSE_NATIVE_MIR` * * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` @@ -75,6 +74,16 @@ 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 */ @@ -82,46 +91,71 @@ extern "C" { * System headers and types *************************************************************************/ -#if defined(GLFW_EXPOSE_NATIVE_WIN32) - // 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 - #include -#elif defined(GLFW_EXPOSE_NATIVE_COCOA) - #include - #if defined(__OBJC__) - #import - #else - typedef void* id; - #endif -#elif defined(GLFW_EXPOSE_NATIVE_X11) - #include - #include -#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) - #include -#elif defined(GLFW_EXPOSE_NATIVE_MIR) - #include -#endif +#if !defined(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 + #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*/ /************************************************************************* @@ -135,6 +169,9 @@ 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. * @@ -150,6 +187,9 @@ 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. * @@ -164,6 +204,17 @@ 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. * @@ -180,6 +231,17 @@ 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. * @@ -196,6 +258,9 @@ 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. * @@ -210,6 +275,9 @@ 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. * @@ -218,6 +286,23 @@ 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) @@ -226,6 +311,9 @@ GLFWAPI id glfwGetCocoaWindow(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. * @@ -242,6 +330,9 @@ 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. * @@ -256,6 +347,9 @@ 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. * @@ -270,6 +364,9 @@ 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. * @@ -284,6 +381,9 @@ 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. * @@ -297,8 +397,8 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); * * @param[in] string A UTF-8 encoded string. * - * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. * * @pointer_lifetime The specified string is copied before this function * returns. @@ -323,8 +423,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 and @ref - * GLFW_PLATFORM_ERROR. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_PLATFORM_UNAVAILABLE 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 @@ -350,6 +450,9 @@ 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. * @@ -364,6 +467,9 @@ 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. * @@ -380,6 +486,9 @@ 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. * @@ -394,6 +503,9 @@ 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. * @@ -408,6 +520,9 @@ 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. * @@ -418,56 +533,17 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); #endif -#if defined(GLFW_EXPOSE_NATIVE_MIR) -/*! @brief Returns the `MirConnection*` used by GLFW. - * - * @return The `MirConnection*` used by GLFW, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirConnection* glfwGetMirDisplay(void); - -/*! @brief Returns the Mir output ID of the specified monitor. - * - * @return The Mir output ID of the specified monitor, or zero if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); - -/*! @brief Returns the `MirWindow*` of the specified window. - * - * @return The `MirWindow*` of the specified window, or `NULL` if an - * [error](@ref error_handling) occurred. - * - * @thread_safety This function may be called from any thread. Access is not - * synchronized. - * - * @since Added in version 3.2. - * - * @ingroup native - */ -GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* window); -#endif - #if defined(GLFW_EXPOSE_NATIVE_EGL) /*! @brief Returns the `EGLDisplay` used by GLFW. * * @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. * @@ -482,6 +558,9 @@ 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. * @@ -496,6 +575,9 @@ 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. * @@ -519,6 +601,9 @@ 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. * @@ -540,6 +625,9 @@ 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. * @@ -554,6 +642,9 @@ 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 new file mode 100644 index 0000000..0fb2a0f --- /dev/null +++ b/raylib/external/glfw/include/GLFW/vendor.go @@ -0,0 +1,4 @@ +//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 01a746b..f34d985 100644 --- a/raylib/external/glfw/src/cocoa_init.m +++ b/raylib/external/glfw/src/cocoa_init.m @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// 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 @@ -25,8 +26,13 @@ //======================================================================== #include "internal.h" + +#if defined(_GLFW_COCOA) + #include // For MAXPATHLEN +// Needed for _NSGetProgname +#include // Change to our application bundle's resources directory, if present // @@ -64,12 +70,114 @@ static void changeToResourcesDirectory(void) chdir(resourcesPath); } +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Add a nib to save us this horror. +// +static void createMenuBar(void) +{ + NSString* appName = nil; + NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; + NSString* nameKeys[] = + { + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", + }; + + // Try to figure out what the calling application is called + + for (size_t i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) + { + id name = bundleInfo[nameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![name isEqualToString:@""]) + { + appName = name; + break; + } + } + + if (!appName) + { + char** progname = _NSGetProgname(); + if (progname && *progname) + appName = @(*progname); + else + appName = @"GLFW Application"; + } + + NSMenu* bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem* appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu* servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [servicesMenu release]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem* windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + [bar release]; + NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Minimize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // TODO: Make this appear at the bottom of the menu (for consistency) + [windowMenu addItem:[NSMenuItem separatorItem]]; + [[windowMenu addItemWithTitle:@"Enter Full Screen" + action:@selector(toggleFullScreen:) + keyEquivalent:@"f"] + setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; + + // Prior to Snow Leopard, we need to use this oddly-named semi-private API + // to get the application menu working properly. + SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); + [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; +} + // Create key code translation tables // -static void createKeyTables(void) +static void createKeyTablesCocoa(void) { - int scancode; - memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); @@ -142,7 +250,7 @@ static void createKeyTables(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_F13; + _glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN; _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; @@ -188,7 +296,7 @@ static void createKeyTables(void) _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; - for (scancode = 0; scancode < 256; scancode++) + for (int scancode = 0; scancode < 256; scancode++) { // Store the reverse translation for faster key name lookup if (_glfw.ns.keycodes[scancode] >= 0) @@ -198,7 +306,7 @@ static void createKeyTables(void) // Retrieve Unicode data for the current keyboard layout // -static GLFWbool updateUnicodeDataNS(void) +static GLFWbool updateUnicodeData(void) { if (_glfw.ns.inputSource) { @@ -268,41 +376,250 @@ static GLFWbool initializeTIS(void) _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = *kPropertyUnicodeKeyLayoutData; - return updateUnicodeDataNS(); + return updateUnicodeData(); } -@interface GLFWLayoutListener : NSObject +@interface GLFWHelper : NSObject @end -@implementation GLFWLayoutListener +@implementation GLFWHelper - (void)selectedKeyboardInputSourceChanged:(NSObject* )object { - updateUnicodeDataNS(); + updateUnicodeData(); } +- (void)doNothing:(id)object +{ +} + +@end // GLFWHelper + +@interface GLFWApplicationDelegate : NSObject @end +@implementation GLFWApplicationDelegate + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + _glfwInputWindowCloseRequest(window); + + return NSTerminateCancel; +} + +- (void)applicationDidChangeScreenParameters:(NSNotification *) notification +{ + for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + { + if (window->context.client != GLFW_NO_API) + [window->context.nsgl.object update]; + } + + _glfwPollMonitorsCocoa(); +} + +- (void)applicationWillFinishLaunching:(NSNotification *)notification +{ + if (_glfw.hints.init.ns.menubar) + { + // Menu bar setup must go between sharedApplication and finishLaunching + // in order to properly emulate the behavior of NSApplicationMain + + if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) + { + [[NSBundle mainBundle] loadNibNamed:@"MainMenu" + owner:NSApp + topLevelObjects:&_glfw.ns.nibObjects]; + } + else + createMenuBar(); + } +} + +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + _glfwPostEmptyEventCocoa(); + [NSApp stop:nil]; +} + +- (void)applicationDidHide:(NSNotification *)notification +{ + for (int i = 0; i < _glfw.monitorCount; i++) + _glfwRestoreVideoModeCocoa(_glfw.monitors[i]); +} + +@end // GLFWApplicationDelegate + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void* _glfwLoadLocalVulkanLoaderCocoa(void) +{ + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return NULL; + + CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle); + if (!frameworksUrl) + 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); + + CFRelease(loaderUrl); + CFRelease(frameworksUrl); + return handle; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformInit(void) +GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) { - _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + 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) +{ + @autoreleasepool { + + _glfw.ns.helper = [[GLFWHelper alloc] init]; + + [NSThread detachNewThreadSelector:@selector(doNothing:) + toTarget:_glfw.ns.helper + withObject:nil]; + + [NSApplication sharedApplication]; + + _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; + if (_glfw.ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GLFW_FALSE; + } + + [NSApp setDelegate:_glfw.ns.delegate]; + + NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event) + { + if ([event modifierFlags] & NSEventModifierFlagCommand) + [[NSApp keyWindow] sendEvent:event]; + + return event; + }; + + _glfw.ns.keyUpMonitor = + [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp + handler:block]; if (_glfw.hints.init.ns.chdir) changeToResourcesDirectory(); - _glfw.ns.listener = [[GLFWLayoutListener alloc] init]; + // Press and Hold prevents some keys from emitting repeated characters + NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO}; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; + [[NSNotificationCenter defaultCenter] - addObserver:_glfw.ns.listener + addObserver:_glfw.ns.helper selector:@selector(selectedKeyboardInputSourceChanged:) name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; - createKeyTables(); + createKeyTablesCocoa(); _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if (!_glfw.ns.eventSource) @@ -313,15 +630,24 @@ int _glfwPlatformInit(void) if (!initializeTIS()) return GLFW_FALSE; - _glfwInitTimerNS(); - _glfwInitJoysticksNS(); + _glfwPollMonitorsCocoa(); + + 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]; - _glfwPollMonitorsNS(); return GLFW_TRUE; + + } // autoreleasepool } -void _glfwPlatformTerminate(void) +void _glfwTerminateCocoa(void) { + @autoreleasepool { + if (_glfw.ns.inputSource) { CFRelease(_glfw.ns.inputSource); @@ -342,33 +668,29 @@ void _glfwPlatformTerminate(void) _glfw.ns.delegate = nil; } - if (_glfw.ns.listener) + if (_glfw.ns.helper) { [[NSNotificationCenter defaultCenter] - removeObserver:_glfw.ns.listener + removeObserver:_glfw.ns.helper name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] - removeObserver:_glfw.ns.listener]; - [_glfw.ns.listener release]; - _glfw.ns.listener = nil; + removeObserver:_glfw.ns.helper]; + [_glfw.ns.helper release]; + _glfw.ns.helper = nil; } - free(_glfw.ns.clipboardString); + if (_glfw.ns.keyUpMonitor) + [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; + + _glfw_free(_glfw.ns.clipboardString); _glfwTerminateNSGL(); - _glfwTerminateJoysticksNS(); + _glfwTerminateEGL(); + _glfwTerminateOSMesa(); - [_glfw.ns.autoreleasePool release]; - _glfw.ns.autoreleasePool = nil; + } // autoreleasepool } -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " Cocoa NSGL" -#if defined(_GLFW_BUILD_DLL) - " dynamic" -#endif - ; -} +#endif // _GLFW_COCOA diff --git a/raylib/external/glfw/src/cocoa_joystick.h b/raylib/external/glfw/src/cocoa_joystick.h index d18d032..2f46dfc 100644 --- a/raylib/external/glfw/src/cocoa_joystick.h +++ b/raylib/external/glfw/src/cocoa_joystick.h @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 Cocoa - www.glfw.org +// GLFW 3.4 Cocoa - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -26,13 +26,10 @@ #include #include -#include #include -#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns -#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE - -#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X" +#define GLFW_COCOA_JOYSTICK_STATE _GLFWjoystickNS ns; +#define GLFW_COCOA_LIBRARY_JOYSTICK_STATE // Cocoa-specific per-joystick data // @@ -44,7 +41,9 @@ typedef struct _GLFWjoystickNS CFMutableArrayRef hats; } _GLFWjoystickNS; - -void _glfwInitJoysticksNS(void); -void _glfwTerminateJoysticksNS(void); +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 0831809..d5de479 100644 --- a/raylib/external/glfw/src/cocoa_joystick.m +++ b/raylib/external/glfw/src/cocoa_joystick.m @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 Cocoa - www.glfw.org +// GLFW 3.4 Cocoa - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// Copyright (c) 2009-2019 Camilla Löwy // Copyright (c) 2012 Torsten Walluhn // // This software is provided 'as-is', without any express or implied @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(_GLFW_COCOA) + #include #include #include @@ -94,25 +96,21 @@ static CFComparisonResult compareElements(const void* fp, // static void closeJoystick(_GLFWjoystick* js) { - int i; + _glfwInputJoystick(js, GLFW_DISCONNECTED); - if (!js->present) - return; - - for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) - free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); + for (int i = 0; i < CFArrayGetCount(js->ns.axes); i++) + _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.axes, i)); CFRelease(js->ns.axes); - for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) - free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); + for (int i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i)); CFRelease(js->ns.buttons); - for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) - free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); + for (int i = 0; i < CFArrayGetCount(js->ns.hats); i++) + _glfw_free((void*) CFArrayGetValueAtIndex(js->ns.hats, i)); CFRelease(js->ns.hats); _glfwFreeJoystick(js); - _glfwInputJoystick(js, GLFW_DISCONNECTED); } // Callback for user-initiated joystick addition @@ -125,7 +123,6 @@ 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; @@ -137,6 +134,14 @@ 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); @@ -180,10 +185,7 @@ static void matchCallback(void* context, name[8], name[9], name[10]); } - CFArrayRef elements = - IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); - - for (i = 0; i < CFArrayGetCount(elements); i++) + for (CFIndex i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef native = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i); @@ -220,14 +222,36 @@ static void matchCallback(void* context, case kHIDUsage_GD_Hatswitch: target = hats; break; + case kHIDUsage_GD_DPadUp: + case kHIDUsage_GD_DPadRight: + case kHIDUsage_GD_DPadDown: + case kHIDUsage_GD_DPadLeft: + case kHIDUsage_GD_SystemMainMenu: + case kHIDUsage_GD_Select: + case kHIDUsage_GD_Start: + target = buttons; + break; } } - else if (page == kHIDPage_Button) + else if (page == kHIDPage_Simulation) + { + switch (usage) + { + case kHIDUsage_Sim_Accelerator: + case kHIDUsage_Sim_Brake: + case kHIDUsage_Sim_Throttle: + case kHIDUsage_Sim_Rudder: + case kHIDUsage_Sim_Steering: + target = axes; + break; + } + } + else if (page == kHIDPage_Button || page == kHIDPage_Consumer) target = buttons; if (target) { - _GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS)); + _GLFWjoyelementNS* element = _glfw_calloc(1, sizeof(_GLFWjoyelementNS)); element->native = native; element->usage = usage; element->index = (int) CFArrayGetCount(target); @@ -266,13 +290,11 @@ static void removeCallback(void* context, void* sender, IOHIDDeviceRef device) { - int jid; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].ns.device == device) + if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].ns.device == device) { - closeJoystick(_glfw.joysticks + jid); + closeJoystick(&_glfw.joysticks[jid]); break; } } @@ -280,12 +302,10 @@ static void removeCallback(void* context, ////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// +////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize joystick interface -// -void _glfwInitJoysticksNS(void) +GLFWbool _glfwInitJoysticksCocoa(void) { CFMutableArrayRef matching; const long usages[] = @@ -304,10 +324,10 @@ void _glfwInitJoysticksNS(void) if (!matching) { _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array"); - return; + return GLFW_FALSE; } - for (int i = 0; i < sizeof(usages) / sizeof(long); i++) + for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++) { const long page = kHIDPage_GenericDesktop; @@ -359,33 +379,30 @@ void _glfwInitJoysticksNS(void) // Execute the run loop once in order to register any initially-attached // joysticks CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); + return GLFW_TRUE; } -// Close all opened joystick handles -// -void _glfwTerminateJoysticksNS(void) +void _glfwTerminateJoysticksCocoa(void) { - int jid; + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (_glfw.joysticks[jid].connected) + closeJoystick(&_glfw.joysticks[jid]); + } - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) - closeJoystick(_glfw.joysticks + jid); - - CFRelease(_glfw.ns.hidManager); - _glfw.ns.hidManager = NULL; + if (_glfw.ns.hidManager) + { + CFRelease(_glfw.ns.hidManager); + _glfw.ns.hidManager = NULL; + } } -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode) { if (mode & _GLFW_POLL_AXES) { - CFIndex i; - - for (i = 0; i < CFArrayGetCount(js->ns.axes); i++) + for (CFIndex i = 0; i < CFArrayGetCount(js->ns.axes); i++) { _GLFWjoyelementNS* axis = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.axes, i); @@ -397,12 +414,12 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (raw > axis->maximum) axis->maximum = raw; - const long delta = axis->maximum - axis->minimum; - if (delta == 0) + const long size = axis->maximum - axis->minimum; + if (size == 0) _glfwInputJoystickAxis(js, (int) i, 0.f); else { - const float value = (2.f * (raw - axis->minimum) / delta) - 1.f; + const float value = (2.f * (raw - axis->minimum) / size) - 1.f; _glfwInputJoystickAxis(js, (int) i, value); } } @@ -410,17 +427,16 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) if (mode & _GLFW_POLL_BUTTONS) { - CFIndex i; - - for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++) + for (CFIndex i = 0; i < CFArrayGetCount(js->ns.buttons); i++) { _GLFWjoyelementNS* button = (_GLFWjoyelementNS*) CFArrayGetValueAtIndex(js->ns.buttons, i); const char value = getElementValue(js, button) - button->minimum; - _glfwInputJoystickButton(js, (int) i, value); + const int state = (value > 0) ? GLFW_PRESS : GLFW_RELEASE; + _glfwInputJoystickButton(js, (int) i, state); } - for (i = 0; i < CFArrayGetCount(js->ns.hats); i++) + for (CFIndex i = 0; i < CFArrayGetCount(js->ns.hats); i++) { const int states[9] = { @@ -445,18 +461,25 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) } } - return js->present; + return js->connected; } -void _glfwPlatformUpdateGamepadGUID(char* guid) +const char* _glfwGetMappingNameCocoa(void) +{ + return "Mac OS X"; +} + +void _glfwUpdateGamepadGUIDCocoa(char* guid) { if ((strncmp(guid + 4, "000000000000", 12) == 0) && (strncmp(guid + 20, "000000000000", 12) == 0)) { char original[33]; - strcpy(original, guid); + strncpy(original, guid, sizeof(original) - 1); sprintf(guid, "03000000%.4s0000%.4s000000000000", original, original + 16); } } +#endif // _GLFW_COCOA + diff --git a/raylib/external/glfw/src/cocoa_monitor.m b/raylib/external/glfw/src/cocoa_monitor.m index 986d799..a2bcc2f 100644 --- a/raylib/external/glfw/src/cocoa_monitor.m +++ b/raylib/external/glfw/src/cocoa_monitor.m @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,29 +28,43 @@ #include "internal.h" +#if defined(_GLFW_COCOA) + #include #include +#include #include -#include -#include #include // Get the name of the specified display, or NULL // -static char* getDisplayName(CGDirectDisplayID displayID) +static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) { + // 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(kIOMasterPortDefault, + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("IODisplayConnect"), &it) != 0) { // This may happen if a desktop Mac is running headless - return NULL; + return _glfw_strdup("Display"); } while ((service = IOIteratorNext(it)) != 0) @@ -84,11 +99,7 @@ static char* getDisplayName(CGDirectDisplayID displayID) IOObjectRelease(it); if (!service) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to find service port for display"); - return NULL; - } + return _glfw_strdup("Display"); CFDictionaryRef names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); @@ -100,13 +111,13 @@ static char* getDisplayName(CGDirectDisplayID displayID) { // This may happen if a desktop Mac is running headless CFRelease(info); - return NULL; + return _glfw_strdup("Display"); } const CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8); - char* name = calloc(size + 1, 1); + char* name = _glfw_calloc(size + 1, 1); CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8); CFRelease(info); @@ -143,19 +154,15 @@ static GLFWbool modeIsGood(CGDisplayModeRef mode) // Convert Core Graphics display mode to GLFW video mode // static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, - CVDisplayLinkRef link) + double fallbackRefreshRate) { GLFWvidmode result; result.width = (int) CGDisplayModeGetWidth(mode); result.height = (int) CGDisplayModeGetHeight(mode); - result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode); + result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode)); if (result.refreshRate == 0) - { - const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - if (!(time.flags & kCVTimeIsIndefinite)) - result.refreshRate = (int) (time.timeScale / (double) time.timeValue); - } + result.refreshRate = (int) round(fallbackRefreshRate); #if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); @@ -212,6 +219,74 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) } } +// Returns the display refresh rate queried from the I/O registry +// +static double getFallbackRefreshRate(CGDirectDisplayID displayID) +{ + double refreshRate = 60.0; + + io_iterator_t it; + io_service_t service; + + if (IOServiceGetMatchingServices(MACH_PORT_NULL, + IOServiceMatching("IOFramebuffer"), + &it) != 0) + { + return refreshRate; + } + + while ((service = IOIteratorNext(it)) != 0) + { + const CFNumberRef indexRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFramebufferOpenGLIndex"), + kCFAllocatorDefault, + kNilOptions); + if (!indexRef) + continue; + + uint32_t index = 0; + CFNumberGetValue(indexRef, kCFNumberIntType, &index); + CFRelease(indexRef); + + if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID) + continue; + + const CFNumberRef clockRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelClock"), + kCFAllocatorDefault, + kNilOptions); + const CFNumberRef countRef = + IORegistryEntryCreateCFProperty(service, + CFSTR("IOFBCurrentPixelCount"), + kCFAllocatorDefault, + kNilOptions); + + uint32_t clock = 0, count = 0; + + if (clockRef) + { + CFNumberGetValue(clockRef, kCFNumberIntType, &clock); + CFRelease(clockRef); + } + + if (countRef) + { + CFNumberGetValue(countRef, kCFNumberIntType, &count); + CFRelease(countRef); + } + + if (clock > 0 && count > 0) + refreshRate = clock / (double) count; + + break; + } + + IOObjectRelease(it); + return refreshRate; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -219,100 +294,115 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) // Poll for changes in the set of connected monitors // -void _glfwPollMonitorsNS(void) +void _glfwPollMonitorsCocoa(void) { - uint32_t i, j, displayCount, disconnectedCount; - CGDirectDisplayID* displays; - _GLFWmonitor** disconnected = NULL; - + uint32_t displayCount; CGGetOnlineDisplayList(0, NULL, &displayCount); - displays = calloc(displayCount, sizeof(CGDirectDisplayID)); + CGDirectDisplayID* displays = _glfw_calloc(displayCount, sizeof(CGDirectDisplayID)); CGGetOnlineDisplayList(displayCount, displays, &displayCount); - for (i = 0; i < _glfw.monitorCount; i++) + for (int i = 0; i < _glfw.monitorCount; i++) _glfw.monitors[i]->ns.screen = nil; - disconnectedCount = _glfw.monitorCount; + _GLFWmonitor** disconnected = NULL; + uint32_t disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); } - for (i = 0; i < displayCount; i++) + for (uint32_t i = 0; i < displayCount; i++) { - _GLFWmonitor* monitor; - const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); - if (CGDisplayIsAsleep(displays[i])) continue; - for (j = 0; j < disconnectedCount; j++) + 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++) + { if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber) { + disconnected[j]->ns.screen = screen; disconnected[j] = NULL; break; } } - const CGSize size = CGDisplayScreenSize(displays[i]); - char* name = getDisplayName(displays[i]); - if (!name) - name = _glfw_strdup("Unknown"); + if (j < disconnectedCount) + continue; - monitor = _glfwAllocMonitor(name, size.width, size.height); + const CGSize size = CGDisplayScreenSize(displays[i]); + char* name = getMonitorName(displays[i], screen); + if (!name) + continue; + + _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber; + monitor->ns.screen = screen; - free(name); + _glfw_free(name); + + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]); + if (CGDisplayModeGetRefreshRate(mode) == 0.0) + monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]); + CGDisplayModeRelease(mode); _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } - for (i = 0; i < disconnectedCount; i++) + for (uint32_t i = 0; i < disconnectedCount; i++) { if (disconnected[i]) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - free(disconnected); - free(displays); + _glfw_free(disconnected); + _glfw_free(displays); } // Change the current video mode // -void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) +void _glfwSetVideoModeCocoa(_GLFWmonitor* monitor, const GLFWvidmode* desired) { - CFArrayRef modes; - CFIndex count, i; - CVDisplayLinkRef link; - CGDisplayModeRef native = NULL; GLFWvidmode current; - const GLFWvidmode* best; + _glfwGetVideoModeCocoa(monitor, ¤t); - best = _glfwChooseVideoMode(monitor, desired); - _glfwPlatformGetVideoMode(monitor, ¤t); + const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); if (_glfwCompareVideoModes(¤t, best) == 0) return; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + const CFIndex count = CFArrayGetCount(modes); + CGDisplayModeRef native = NULL; - modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); - count = CFArrayGetCount(modes); - - for (i = 0; i < count; i++) + for (CFIndex i = 0; i < count; i++) { CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); if (!modeIsGood(dm)) continue; - const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + const GLFWvidmode mode = + vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); if (_glfwCompareVideoModes(best, &mode) == 0) { native = dm; @@ -331,12 +421,11 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired) } CFRelease(modes); - CVDisplayLinkRelease(link); } // Restore the previously saved (original) video mode // -void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) +void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor) { if (monitor->ns.previousMode) { @@ -355,51 +444,33 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor) { } -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos) { + @autoreleasepool { + const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); if (xpos) *xpos = (int) bounds.origin.x; if (ypos) *ypos = (int) bounds.origin.y; + + } // autoreleasepool } -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, + float* xscale, float* yscale) { + @autoreleasepool { + if (!monitor->ns.screen) { - NSUInteger i; - NSArray* screens = [NSScreen screens]; - - for (i = 0; i < [screens count]; i++) - { - NSScreen* screen = [screens objectAtIndex:i]; - NSNumber* displayID = - [[screen deviceDescription] objectForKey:@"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; - break; - } - } - - if (i == [screens count]) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to find a screen for monitor"); - return; - } + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Cannot query content scale without screen"); } const NSRect points = [monitor->ns.screen frame]; @@ -409,30 +480,55 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, *xscale = (float) (pixels.size.width / points.size.width); if (yscale) *yscale = (float) (pixels.size.height / points.size.height); + + } // autoreleasepool } -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +void _glfwGetMonitorWorkareaCocoa(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { - CFArrayRef modes; - CFIndex found, i, j; - GLFWvidmode* result; - CVDisplayLinkRef link; + @autoreleasepool { + + if (!monitor->ns.screen) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Cannot query workarea without screen"); + } + + const NSRect frameRect = [monitor->ns.screen visibleFrame]; + + if (xpos) + *xpos = frameRect.origin.x; + if (ypos) + *ypos = _glfwTransformYCocoa(frameRect.origin.y + frameRect.size.height - 1); + if (width) + *width = frameRect.size.width; + if (height) + *height = frameRect.size.height; + + } // autoreleasepool +} + +GLFWvidmode* _glfwGetVideoModesCocoa(_GLFWmonitor* monitor, int* count) +{ + @autoreleasepool { *count = 0; - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + const CFIndex found = CFArrayGetCount(modes); + GLFWvidmode* result = _glfw_calloc(found, sizeof(GLFWvidmode)); - modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); - found = CFArrayGetCount(modes); - result = calloc(found, sizeof(GLFWvidmode)); - - for (i = 0; i < found; i++) + for (CFIndex i = 0; i < found; i++) { CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); if (!modeIsGood(dm)) continue; - const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + const GLFWvidmode mode = + vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate); + CFIndex j; for (j = 0; j < *count; j++) { @@ -441,7 +537,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) } // Skip duplicate modes - if (i < *count) + if (j < *count) continue; (*count)++; @@ -449,28 +545,35 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) } CFRelease(modes); - CVDisplayLinkRelease(link); return result; + + } // autoreleasepool } -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) +GLFWbool _glfwGetVideoModeCocoa(_GLFWmonitor* monitor, GLFWvidmode *mode) { - CGDisplayModeRef displayMode; - CVDisplayLinkRef link; + @autoreleasepool { - CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); + CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID); + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to query display mode"); + return GLFW_FALSE; + } - displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); - *mode = vidmodeFromCGDisplayMode(displayMode, link); - CGDisplayModeRelease(displayMode); + *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate); + CGDisplayModeRelease(native); + return GLFW_TRUE; - CVDisplayLinkRelease(link); + } // autoreleasepool } -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwGetGammaRampCocoa(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { - uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); - CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); + @autoreleasepool { + + uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID); + CGGammaValue* values = _glfw_calloc(size * 3, sizeof(CGGammaValue)); CGGetDisplayTransferByTable(monitor->ns.displayID, size, @@ -481,22 +584,26 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) _glfwAllocGammaArrays(ramp, size); - for (i = 0; i < size; i++) + for (uint32_t i = 0; i < size; i++) { ramp->red[i] = (unsigned short) (values[i] * 65535); ramp->green[i] = (unsigned short) (values[i + size] * 65535); ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); } - free(values); + _glfw_free(values); + return GLFW_TRUE; + + } // autoreleasepool } -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwSetGammaRampCocoa(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { - int i; - CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); + @autoreleasepool { - for (i = 0; i < ramp->size; i++) + CGGammaValue* values = _glfw_calloc(ramp->size * 3, sizeof(CGGammaValue)); + + for (unsigned int i = 0; i < ramp->size; i++) { values[i] = ramp->red[i] / 65535.f; values[i + ramp->size] = ramp->green[i] / 65535.f; @@ -509,7 +616,9 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) values + ramp->size, values + ramp->size * 2); - free(values); + _glfw_free(values); + + } // autoreleasepool } @@ -521,6 +630,15 @@ 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 cf6ca9f..3991455 100644 --- a/raylib/external/glfw/src/cocoa_platform.h +++ b/raylib/external/glfw/src/cocoa_platform.h @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// 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 @@ -25,18 +25,61 @@ //======================================================================== #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 #import #else -#include -#include 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 + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 + #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat + #define NSEventMaskAny NSAnyEventMask + #define NSEventMaskKeyUp NSKeyUpMask + #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask + #define NSEventModifierFlagCommand NSCommandKeyMask + #define NSEventModifierFlagControl NSControlKeyMask + #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask + #define NSEventModifierFlagOption NSAlternateKeyMask + #define NSEventModifierFlagShift NSShiftKeyMask + #define NSEventTypeApplicationDefined NSApplicationDefined + #define NSWindowStyleMaskBorderless NSBorderlessWindowMask + #define NSWindowStyleMaskClosable NSClosableWindowMask + #define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask + #define NSWindowStyleMaskResizable NSResizableWindowMask + #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; typedef struct VkMacOSSurfaceCreateInfoMVK { @@ -46,26 +89,24 @@ typedef struct VkMacOSSurfaceCreateInfoMVK const void* pView; } VkMacOSSurfaceCreateInfoMVK; +typedef struct VkMetalSurfaceCreateInfoEXT +{ + VkStructureType sType; + const void* pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const void* pLayer; +} VkMetalSurfaceCreateInfoEXT; + typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*); +typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*); -#include "posix_thread.h" -#include "cocoa_joystick.h" -#include "nsgl_context.h" -#include "egl_context.h" -#include "osmesa_context.h" +#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; -#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_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view) -#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY - -#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 +#define GLFW_NSGL_CONTEXT_STATE _GLFWcontextNSGL nsgl; +#define GLFW_NSGL_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl; // HIToolbox.framework pointer typedefs #define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData @@ -77,6 +118,22 @@ 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 @@ -87,6 +144,8 @@ typedef struct _GLFWwindowNS id layer; GLFWbool maximized; + GLFWbool occluded; + GLFWbool scaleFramebuffer; // Cached window properties to filter out duplicate events int width, height; @@ -97,7 +156,6 @@ 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 @@ -106,14 +164,15 @@ typedef struct _GLFWlibraryNS { CGEventSourceRef eventSource; id delegate; - id autoreleasePool; GLFWbool cursorHidden; TISInputSourceRef inputSource; IOHIDManagerRef hidManager; id unicodeData; - id listener; + id helper; + id keyUpMonitor; + id nibObjects; - char keyName[64]; + char keynames[GLFW_KEY_LAST + 1][17]; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; char* clipboardString; @@ -130,7 +189,6 @@ typedef struct _GLFWlibraryNS PFN_LMGetKbdType GetKbdType; CFStringRef kPropertyUnicodeKeyLayoutData; } tis; - } _GLFWlibraryNS; // Cocoa-specific per-monitor data @@ -141,7 +199,7 @@ typedef struct _GLFWmonitorNS CGDisplayModeRef previousMode; uint32_t unitNumber; id screen; - + double fallbackRefreshRate; } _GLFWmonitorNS; // Cocoa-specific per-cursor data @@ -149,21 +207,96 @@ typedef struct _GLFWmonitorNS typedef struct _GLFWcursorNS { id object; - } _GLFWcursorNS; -// Cocoa-specific global timer data -// -typedef struct _GLFWtimerNS -{ - uint64_t frequency; -} _GLFWtimerNS; +GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform); +int _glfwInitCocoa(void); +void _glfwTerminateCocoa(void); +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 _glfwInitTimerNS(void); +void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled); +GLFWbool _glfwRawMouseMotionSupportedCocoa(void); -void _glfwPollMonitorsNS(void); -void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired); -void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor); +void _glfwPollEventsCocoa(void); +void _glfwWaitEventsCocoa(void); +void _glfwWaitEventsTimeoutCocoa(double timeout); +void _glfwPostEmptyEventCocoa(void); + +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); + +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); diff --git a/raylib/external/glfw/src/cocoa_time.c b/raylib/external/glfw/src/cocoa_time.c index 3b27035..d56f145 100644 --- a/raylib/external/glfw/src/cocoa_time.c +++ b/raylib/external/glfw/src/cocoa_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2016 Camilla Löwy // @@ -26,16 +26,16 @@ #include "internal.h" +#if defined(GLFW_BUILD_COCOA_TIMER) + #include ////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// +////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -// Initialise timer -// -void _glfwInitTimerNS(void) +void _glfwPlatformInitTimer(void) { mach_timebase_info_data_t info; mach_timebase_info(&info); @@ -43,11 +43,6 @@ void _glfwInitTimerNS(void) _glfw.timer.ns.frequency = (info.denom * 1e9) / info.numer; } - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - uint64_t _glfwPlatformGetTimerValue(void) { return mach_absolute_time(); @@ -58,3 +53,5 @@ 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 new file mode 100644 index 0000000..3512e8b --- /dev/null +++ b/raylib/external/glfw/src/cocoa_time.h @@ -0,0 +1,35 @@ +//======================================================================== +// 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 7cf4a59..949cace 100644 --- a/raylib/external/glfw/src/cocoa_window.m +++ b/raylib/external/glfw/src/cocoa_window.m @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// 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 @@ -26,64 +26,18 @@ #include "internal.h" +#if defined(_GLFW_COCOA) + #include #include -// Needed for _NSGetProgname -#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) -// HACK: The 10.12 SDK adds new symbols and immediately deprecates the old ones -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 - #define NSWindowStyleMaskBorderless NSBorderlessWindowMask - #define NSWindowStyleMaskClosable NSClosableWindowMask - #define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask - #define NSWindowStyleMaskResizable NSResizableWindowMask - #define NSWindowStyleMaskTitled NSTitledWindowMask - #define NSEventModifierFlagCommand NSCommandKeyMask - #define NSEventModifierFlagControl NSControlKeyMask - #define NSEventModifierFlagOption NSAlternateKeyMask - #define NSEventModifierFlagShift NSShiftKeyMask - #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask - #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask - #define NSEventMaskAny NSAnyEventMask - #define NSEventTypeApplicationDefined NSApplicationDefined - #define NSEventTypeKeyUp NSKeyUp -#endif - - -// Returns the style mask corresponding to the window settings +// Returns whether the cursor is in the content area of the specified window // -static NSUInteger getStyleMask(_GLFWwindow* window) -{ - NSUInteger styleMask = 0; - - if (window->monitor || !window->decorated) - styleMask |= NSWindowStyleMaskBorderless; - else - { - styleMask |= NSWindowStyleMaskTitled | - NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable; - - if (window->resizable) - styleMask |= NSWindowStyleMaskResizable; - } - - return styleMask; -} - -// Center the cursor in the view of the window -// -static void centerCursor(_GLFWwindow *window) -{ - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); -} - -// Returns whether the cursor is in the client area of the specified window -// -static GLFWbool cursorInClientArea(_GLFWwindow* window) +static GLFWbool cursorInContentArea(_GLFWwindow* window) { const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; return [window->ns.view mouse:pos inRect:[window->ns.view frame]]; @@ -135,41 +89,34 @@ static void updateCursorMode(_GLFWwindow* window) if (window->cursorMode == GLFW_CURSOR_DISABLED) { _glfw.ns.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.ns.restoreCursorPosX, - &_glfw.ns.restoreCursorPosY); - centerCursor(window); + _glfwGetCursorPosCocoa(window, + &_glfw.ns.restoreCursorPosX, + &_glfw.ns.restoreCursorPosY); + _glfwCenterCursorInContentArea(window); CGAssociateMouseAndMouseCursorPosition(false); } else if (_glfw.ns.disabledCursorWindow == window) { _glfw.ns.disabledCursorWindow = NULL; - CGAssociateMouseAndMouseCursorPosition(true); - _glfwPlatformSetCursorPos(window, - _glfw.ns.restoreCursorPosX, - _glfw.ns.restoreCursorPosY); + _glfwSetCursorPosCocoa(window, + _glfw.ns.restoreCursorPosX, + _glfw.ns.restoreCursorPosY); + // NOTE: The matching CGAssociateMouseAndMouseCursorPosition call is + // made in _glfwSetCursorPosCocoa as part of a workaround } - if (cursorInClientArea(window)) + if (cursorInContentArea(window)) updateCursorImage(window); } -// Transforms the specified y-coordinate between the CG display and NS screen -// coordinate systems -// -static float transformY(float y) -{ - return CGDisplayBounds(CGMainDisplayID()).size.height - y; -} - // Make the specified window and its video mode active on its monitor // -static void acquireMonitor(_GLFWwindow* window) +static void acquireMonitorCocoa(_GLFWwindow* window) { - _glfwSetVideoModeNS(window->monitor, &window->videoMode); + _glfwSetVideoModeCocoa(window->monitor, &window->videoMode); const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID); const NSRect frame = NSMakeRect(bounds.origin.x, - transformY(bounds.origin.y + bounds.size.height), + _glfwTransformYCocoa(bounds.origin.y + bounds.size.height - 1), bounds.size.width, bounds.size.height); @@ -180,13 +127,13 @@ static void acquireMonitor(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitor(_GLFWwindow* window) +static void releaseMonitorCocoa(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfwInputMonitorWindow(window->monitor, NULL); - _glfwRestoreVideoModeNS(window->monitor); + _glfwRestoreVideoModeCocoa(window->monitor); } // Translates macOS key modifiers into GLFW ones @@ -211,7 +158,7 @@ static int translateFlags(NSUInteger flags) // Translates a macOS keycode to a GLFW keycode // -static int translateKey(unsigned int key) +static int translateKeyCocoa(unsigned int key) { if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0])) return GLFW_KEY_UNKNOWN; @@ -237,6 +184,8 @@ static NSUInteger translateKeyToModifierFlag(int key) case GLFW_KEY_LEFT_SUPER: case GLFW_KEY_RIGHT_SUPER: return NSEventModifierFlagCommand; + case GLFW_KEY_CAPS_LOCK: + return NSEventModifierFlagCapsLock; } return 0; @@ -279,11 +228,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResize:(NSNotification *)notification { - if (window->context.client != GLFW_NO_API) + if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) - centerCursor(window); + _glfwCenterCursorInContentArea(window); const int maximized = [window->ns.object isZoomed]; if (window->ns.maximized != maximized) @@ -314,21 +263,21 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidMove:(NSNotification *)notification { - if (window->context.client != GLFW_NO_API) + if (window->context.source == GLFW_NATIVE_CONTEXT_API) [window->context.nsgl.object update]; if (_glfw.ns.disabledCursorWindow == window) - centerCursor(window); + _glfwCenterCursorInContentArea(window); int x, y; - _glfwPlatformGetWindowPos(window, &x, &y); + _glfwGetWindowPosCocoa(window, &x, &y); _glfwInputWindowPos(window, x, y); } - (void)windowDidMiniaturize:(NSNotification *)notification { if (window->monitor) - releaseMonitor(window); + releaseMonitorCocoa(window); _glfwInputWindowIconify(window, GLFW_TRUE); } @@ -336,7 +285,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidDeminiaturize:(NSNotification *)notification { if (window->monitor) - acquireMonitor(window); + acquireMonitorCocoa(window); _glfwInputWindowIconify(window, GLFW_FALSE); } @@ -344,7 +293,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidBecomeKey:(NSNotification *)notification { if (_glfw.ns.disabledCursorWindow == window) - centerCursor(window); + _glfwCenterCursorInContentArea(window); _glfwInputWindowFocus(window, GLFW_TRUE); updateCursorMode(window); @@ -353,59 +302,22 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResignKey:(NSNotification *)notification { if (window->monitor && window->autoIconify) - _glfwPlatformIconifyWindow(window); + _glfwIconifyWindowCocoa(window); _glfwInputWindowFocus(window, GLFW_FALSE); } -@end - - -//------------------------------------------------------------------------ -// Delegate for application related notifications -//------------------------------------------------------------------------ - -@interface GLFWApplicationDelegate : NSObject -@end - -@implementation GLFWApplicationDelegate - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +- (void)windowDidChangeOcclusionState:(NSNotification* )notification { - _GLFWwindow* window; - - for (window = _glfw.windowListHead; window; window = window->next) - _glfwInputWindowCloseRequest(window); - - return NSTerminateCancel; -} - -- (void)applicationDidChangeScreenParameters:(NSNotification *) notification -{ - _GLFWwindow* window; - - for (window = _glfw.windowListHead; window; window = window->next) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 + if ([window->ns.object respondsToSelector:@selector(occlusionState)]) { - if (window->context.client != GLFW_NO_API) - [window->context.nsgl.object update]; + if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) + window->ns.occluded = GLFW_FALSE; + else + window->ns.occluded = GLFW_TRUE; } - - _glfwPollMonitorsNS(); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - [NSApp stop:nil]; - - _glfwPlatformPostEmptyEvent(); -} - -- (void)applicationDidHide:(NSNotification *)notification -{ - int i; - - for (i = 0; i < _glfw.monitorCount; i++) - _glfwRestoreVideoModeNS(_glfw.monitors[i]); +#endif } @end @@ -438,8 +350,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; markedText = [[NSMutableAttributedString alloc] init]; [self updateTrackingAreas]; - [self registerForDraggedTypes:[NSArray arrayWithObjects: - NSFilenamesPboardType, nil]]; + [self registerForDraggedTypes:@[NSPasteboardTypeURL]]; } return self; @@ -472,12 +383,12 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; return YES; } -- (id)makeBackingLayer +- (void)updateLayer { - if (window->ns.layer) - return window->ns.layer; + if (window->context.source == GLFW_NATIVE_CONTEXT_API) + [window->context.nsgl.object update]; - return [super makeBackingLayer]; + _glfwInputWindowDamage(window); } - (void)cursorUpdate:(NSEvent *)event @@ -485,6 +396,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; updateCursorImage(window); } +- (BOOL)acceptsFirstMouse:(NSEvent *)event +{ + return YES; +} + - (void)mouseDown:(NSEvent *)event { _glfwInputMouseClick(window, @@ -520,6 +436,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; else { const NSRect contentRect = [window->ns.view frame]; + // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [event locationInWindow]; _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); @@ -591,6 +508,18 @@ 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) @@ -599,19 +528,6 @@ 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.layer) - [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; - } } - (void)drawRect:(NSRect)rect @@ -645,12 +561,12 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)keyDown:(NSEvent *)event { - const int key = translateKey([event keyCode]); + const int key = translateKeyCocoa([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); - [self interpretKeyEvents:[NSArray arrayWithObject:event]]; + [self interpretKeyEvents:@[event]]; } - (void)flagsChanged:(NSEvent *)event @@ -658,7 +574,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; int action; const unsigned int modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; - const int key = translateKey([event keyCode]); + const int key = translateKeyCocoa([event keyCode]); const int mods = translateFlags(modifierFlags); const NSUInteger keyFlag = translateKeyToModifierFlag(key); @@ -677,17 +593,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)keyUp:(NSEvent *)event { - const int key = translateKey([event keyCode]); + const int key = translateKeyCocoa([event keyCode]); const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); } - (void)scrollWheel:(NSEvent *)event { - double deltaX, deltaY; - - deltaX = [event scrollingDeltaX]; - deltaY = [event scrollingDeltaY]; + double deltaX = [event scrollingDeltaX]; + double deltaY = [event scrollingDeltaY]; if ([event hasPreciseScrollingDeltas]) { @@ -701,57 +615,40 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (NSDragOperation)draggingEntered:(id )sender { - if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) - == NSDragOperationGeneric) - { - [self setNeedsDisplay:YES]; - return NSDragOperationGeneric; - } - - return NSDragOperationNone; -} - -- (BOOL)prepareForDragOperation:(id )sender -{ - [self setNeedsDisplay:YES]; - return YES; + // HACK: We don't know what to say here because we don't know what the + // application wants to do with the paths + return NSDragOperationGeneric; } - (BOOL)performDragOperation:(id )sender { - NSPasteboard* pasteboard = [sender draggingPasteboard]; - NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; - const NSRect contentRect = [window->ns.view frame]; - _glfwInputCursorPos(window, - [sender draggingLocation].x, - contentRect.size.height - [sender draggingLocation].y); + // NOTE: The returned location uses base 0,1 not 0,0 + const NSPoint pos = [sender draggingLocation]; + _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y); - const NSUInteger count = [files count]; + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES}; + NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]] + options:options]; + const NSUInteger count = [urls count]; if (count) { - NSEnumerator* e = [files objectEnumerator]; - char** paths = calloc(count, sizeof(char*)); - NSUInteger i; + char** paths = _glfw_calloc(count, sizeof(char*)); - for (i = 0; i < count; i++) - paths[i] = _glfw_strdup([[e nextObject] UTF8String]); + for (NSUInteger i = 0; i < count; i++) + paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]); _glfwInputDrop(window, (int) count, (const char**) paths); - for (i = 0; i < count; i++) - free(paths[i]); - free(paths); + for (NSUInteger i = 0; i < count; i++) + _glfw_free(paths[i]); + _glfw_free(paths); } return YES; } -- (void)concludeDragOperation:(id )sender -{ - [self setNeedsDisplay:YES]; -} - - (BOOL)hasMarkedText { return [markedText length] > 0; @@ -805,10 +702,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - int xpos, ypos; - _glfwPlatformGetWindowPos(window, &xpos, &ypos); - const NSRect contentRect = [window->ns.view frame]; - return NSMakeRect(xpos, transformY(ypos + contentRect.size.height), 0.0, 0.0); + const NSRect frame = [window->ns.view frame]; + return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0); } - (void)insertText:(id)string replacementRange:(NSRange)replacementRange @@ -823,15 +718,24 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; else characters = (NSString*) string; - NSUInteger i, length = [characters length]; - - for (i = 0; i < length; i++) + NSRange range = NSMakeRange(0, [characters length]); + while (range.length) { - const unichar codepoint = [characters characterAtIndex:i]; - if ((codepoint & 0xff00) == 0xf700) - continue; + uint32_t codepoint = 0; - _glfwInputChar(window, codepoint, mods, plain); + if ([characters getBytes:&codepoint + maxLength:sizeof(codepoint) + usedLength:NULL + encoding:NSUTF32StringEncoding + options:0 + range:range + remainingRange:&range]) + { + if (codepoint >= 0xf700 && codepoint <= 0xf7ff) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } } } @@ -865,210 +769,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; @end -//------------------------------------------------------------------------ -// GLFW application class -//------------------------------------------------------------------------ - -@interface GLFWApplication : NSApplication -{ - NSArray* nibObjects; -} - -@end - -@implementation GLFWApplication - -// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost -// This works around an AppKit bug, where key up events while holding -// down the command key don't get sent to the key window. -- (void)sendEvent:(NSEvent *)event -{ - if ([event type] == NSEventTypeKeyUp && - ([event modifierFlags] & NSEventModifierFlagCommand)) - { - [[self keyWindow] sendEvent:event]; - } - else - [super sendEvent:event]; -} - - -// No-op thread entry point -// -- (void)doNothing:(id)object -{ -} - -- (void)loadMainMenu -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - [[NSBundle mainBundle] loadNibNamed:@"MainMenu" - owner:NSApp - topLevelObjects:&nibObjects]; -#else - [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp]; -#endif -} -@end - -// Set up the menu bar (manually) -// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that -// could go away at any moment, lots of stuff that really should be -// localize(d|able), etc. Add a nib to save us this horror. -// -static void createMenuBar(void) -{ - size_t i; - NSString* appName = nil; - NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; - NSString* nameKeys[] = - { - @"CFBundleDisplayName", - @"CFBundleName", - @"CFBundleExecutable", - }; - - // Try to figure out what the calling application is called - - for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++) - { - id name = [bundleInfo objectForKey:nameKeys[i]]; - if (name && - [name isKindOfClass:[NSString class]] && - ![name isEqualToString:@""]) - { - appName = name; - break; - } - } - - if (!appName) - { - char** progname = _NSGetProgname(); - if (progname && *progname) - appName = [NSString stringWithUTF8String:*progname]; - else - appName = @"GLFW Application"; - } - - NSMenu* bar = [[NSMenu alloc] init]; - [NSApp setMainMenu:bar]; - - NSMenuItem* appMenuItem = - [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - NSMenu* appMenu = [[NSMenu alloc] init]; - [appMenuItem setSubmenu:appMenu]; - - [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] - action:@selector(orderFrontStandardAboutPanel:) - keyEquivalent:@""]; - [appMenu addItem:[NSMenuItem separatorItem]]; - NSMenu* servicesMenu = [[NSMenu alloc] init]; - [NSApp setServicesMenu:servicesMenu]; - [[appMenu addItemWithTitle:@"Services" - action:NULL - keyEquivalent:@""] setSubmenu:servicesMenu]; - [servicesMenu release]; - [appMenu addItem:[NSMenuItem separatorItem]]; - [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] - action:@selector(hide:) - keyEquivalent:@"h"]; - [[appMenu addItemWithTitle:@"Hide Others" - action:@selector(hideOtherApplications:) - keyEquivalent:@"h"] - setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand]; - [appMenu addItemWithTitle:@"Show All" - action:@selector(unhideAllApplications:) - keyEquivalent:@""]; - [appMenu addItem:[NSMenuItem separatorItem]]; - [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] - action:@selector(terminate:) - keyEquivalent:@"q"]; - - NSMenuItem* windowMenuItem = - [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - [bar release]; - NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - [NSApp setWindowsMenu:windowMenu]; - [windowMenuItem setSubmenu:windowMenu]; - - [windowMenu addItemWithTitle:@"Minimize" - action:@selector(performMiniaturize:) - keyEquivalent:@"m"]; - [windowMenu addItemWithTitle:@"Zoom" - action:@selector(performZoom:) - keyEquivalent:@""]; - [windowMenu addItem:[NSMenuItem separatorItem]]; - [windowMenu addItemWithTitle:@"Bring All to Front" - action:@selector(arrangeInFront:) - keyEquivalent:@""]; - - // TODO: Make this appear at the bottom of the menu (for consistency) - [windowMenu addItem:[NSMenuItem separatorItem]]; - [[windowMenu addItemWithTitle:@"Enter Full Screen" - action:@selector(toggleFullScreen:) - keyEquivalent:@"f"] - setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; - - // Prior to Snow Leopard, we need to use this oddly-named semi-private API - // to get the application menu working properly. - SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); - [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; -} - -// Initialize the Cocoa Application Kit -// -static GLFWbool initializeAppKit(void) -{ - if (NSApp) - return GLFW_TRUE; - - // Implicitly create shared NSApplication instance - [GLFWApplication sharedApplication]; - - // Make Cocoa enter multi-threaded mode - [NSThread detachNewThreadSelector:@selector(doNothing:) - toTarget:NSApp - withObject:nil]; - - 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 above and - // finishLaunching below, in order to properly emulate the behavior - // of NSApplicationMain - - if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) - [NSApp loadMainMenu]; - else - createMenuBar(); - } - - // There can only be one application delegate, but we allocate it the - // first time a window is created to keep all window code in this file - _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; - if (_glfw.ns.delegate == nil) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to create application delegate"); - return GLFW_FALSE; - } - - [NSApp setDelegate:_glfw.ns.delegate]; - [NSApp run]; - - // Press and Hold prevents some keys from emitting repeated characters - NSDictionary* defaults = - [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], - @"ApplePressAndHoldEnabled", - nil]; - [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; - - return GLFW_TRUE; -} - // Create the Cocoa window // static GLFWbool createNativeWindow(_GLFWwindow* window, @@ -1090,17 +790,41 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, GLFWvidmode mode; int xpos, ypos; - _glfwPlatformGetVideoMode(window->monitor, &mode); - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + _glfwGetVideoModeCocoa(window->monitor, &mode); + _glfwGetMonitorPosCocoa(window->monitor, &xpos, &ypos); contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); } else - contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + { + 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; + } window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect - styleMask:getStyleMask(window) + styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; @@ -1114,10 +838,14 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; else { - [window->ns.object center]; - _glfw.ns.cascadePoint = - NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: - NSPointFromCGPoint(_glfw.ns.cascadePoint)]); + 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)]); + } if (wndconfig->resizable) { @@ -1126,6 +854,12 @@ 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]; @@ -1135,44 +869,59 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, } if (strlen(wndconfig->ns.frameName)) - [window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->ns.frameName]]; + [window->ns.object setFrameAutosaveName:@(wndconfig->ns.frameName)]; window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; - - if (wndconfig->ns.retina) - [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; + window->ns.scaleFramebuffer = wndconfig->scaleFramebuffer; if (fbconfig->transparent) { [window->ns.object setOpaque:NO]; + [window->ns.object setHasShadow:NO]; [window->ns.object setBackgroundColor:[NSColor clearColor]]; } [window->ns.object setContentView:window->ns.view]; [window->ns.object makeFirstResponder:window->ns.view]; - [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; + [window->ns.object setTitle:@(wndconfig->title)]; [window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setAcceptsMouseMovedEvents:YES]; [window->ns.object setRestorable:NO]; - _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); - _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 + if ([window->ns.object respondsToSelector:@selector(setTabbingMode:)]) + [window->ns.object setTabbingMode:NSWindowTabbingModeDisallowed]; +#endif + + _glfwGetWindowSizeCocoa(window, &window->ns.width, &window->ns.height); + _glfwGetFramebufferSizeCocoa(window, &window->ns.fbWidth, &window->ns.fbHeight); return GLFW_TRUE; } +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Transforms a y-coordinate between the CG display and NS screen spaces +// +float _glfwTransformYCocoa(float y) +{ + return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformCreateWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { - if (!initializeAppKit()) - return GLFW_FALSE; + @autoreleasepool { if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; @@ -1188,6 +937,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { + // EGL implementation on macOS use CALayer* EGLNativeWindowType so we + // need to get the layer for EGL window surface creation. + [window->ns.view setWantsLayer:YES]; + window->ns.layer = [window->ns.view layer]; + if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) @@ -1200,27 +954,49 @@ int _glfwPlatformCreateWindow(_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) { - _glfwPlatformShowWindow(window); - _glfwPlatformFocusWindow(window); - acquireMonitor(window); + _glfwShowWindowCocoa(window); + _glfwFocusWindowCocoa(window); + acquireMonitorCocoa(window); + + if (wndconfig->centerCursor) + _glfwCenterCursorInContentArea(window); + } + else + { + if (wndconfig->visible) + { + _glfwShowWindowCocoa(window); + if (wndconfig->focused) + _glfwFocusWindowCocoa(window); + } } return GLFW_TRUE; + + } // autoreleasepool } -void _glfwPlatformDestroyWindow(_GLFWwindow* window) +void _glfwDestroyWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { + if (_glfw.ns.disabledCursorWindow == window) _glfw.ns.disabledCursorWindow = NULL; [window->ns.object orderOut:nil]; if (window->monitor) - releaseMonitor(window); + releaseMonitorCocoa(window); if (window->context.destroy) window->context.destroy(window); @@ -1235,69 +1011,99 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) [window->ns.object close]; window->ns.object = nil; - [_glfw.ns.autoreleasePool drain]; - _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + // HACK: Allow Cocoa to catch up before returning + _glfwPollEventsCocoa(); + + } // autoreleasepool } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) +void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title) { - NSString* string = [NSString stringWithUTF8String:title]; + @autoreleasepool { + NSString* string = @(title); [window->ns.object setTitle:string]; // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it // if the window lacks NSWindowStyleMaskTitled [window->ns.object setMiniwindowTitle:string]; + } // autoreleasepool } -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwSetWindowIconCocoa(_GLFWwindow* window, + int count, const GLFWimage* images) { - // Regular windows do not have icons + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Cocoa: Regular windows do not have icons on macOS"); } -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos) { + @autoreleasepool { + const NSRect contentRect = [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; if (xpos) *xpos = contentRect.origin.x; if (ypos) - *ypos = transformY(contentRect.origin.y + contentRect.size.height); + *ypos = _glfwTransformYCocoa(contentRect.origin.y + contentRect.size.height - 1); + + } // autoreleasepool } -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) +void _glfwSetWindowPosCocoa(_GLFWwindow* window, int x, int y) { + @autoreleasepool { + const NSRect contentRect = [window->ns.view frame]; - const NSRect dummyRect = NSMakeRect(x, transformY(y + contentRect.size.height), 0, 0); + const NSRect dummyRect = NSMakeRect(x, _glfwTransformYCocoa(y + contentRect.size.height - 1), 0, 0); const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; [window->ns.object setFrameOrigin:frameRect.origin]; + + } // autoreleasepool } -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height) { + @autoreleasepool { + const NSRect contentRect = [window->ns.view frame]; if (width) *width = contentRect.size.width; if (height) *height = contentRect.size.height; + + } // autoreleasepool } -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +void _glfwSetWindowSizeCocoa(_GLFWwindow* window, int width, int height) { + @autoreleasepool { + if (window->monitor) { if (window->monitor->window == window) - acquireMonitor(window); + acquireMonitorCocoa(window); } else - [window->ns.object setContentSize:NSMakeSize(width, height)]; + { + NSRect contentRect = + [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; + contentRect.origin.y += contentRect.size.height - height; + contentRect.size = NSMakeSize(width, height); + [window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect] + display:YES]; + } + + } // autoreleasepool } -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwSetWindowSizeLimitsCocoa(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { + @autoreleasepool { + if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) [window->ns.object setContentMinSize:NSMakeSize(0, 0)]; else @@ -1307,18 +1113,24 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)]; else [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)]; + + } // autoreleasepool } -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +void _glfwSetWindowAspectRatioCocoa(_GLFWwindow* window, int numer, int denom) { + @autoreleasepool { if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) [window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)]; else [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)]; + } // autoreleasepool } -void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetFramebufferSizeCocoa(_GLFWwindow* window, int* width, int* height) { + @autoreleasepool { + const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; @@ -1326,12 +1138,16 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh *width = (int) fbRect.size.width; if (height) *height = (int) fbRect.size.height; + + } // autoreleasepool } -void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwGetWindowFrameSizeCocoa(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { + @autoreleasepool { + const NSRect contentRect = [window->ns.view frame]; const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; @@ -1345,11 +1161,15 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, contentRect.origin.x - contentRect.size.width; if (bottom) *bottom = contentRect.origin.y - frameRect.origin.y; + + } // autoreleasepool } -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwGetWindowContentScaleCocoa(_GLFWwindow* window, + float* xscale, float* yscale) { + @autoreleasepool { + const NSRect points = [window->ns.view frame]; const NSRect pixels = [window->ns.view convertRectToBacking:points]; @@ -1357,73 +1177,91 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, *xscale = (float) (pixels.size.width / points.size.width); if (yscale) *yscale = (float) (pixels.size.height / points.size.height); + + } // autoreleasepool } -void _glfwPlatformIconifyWindow(_GLFWwindow* window) +void _glfwIconifyWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { [window->ns.object miniaturize:nil]; + } // autoreleasepool } -void _glfwPlatformRestoreWindow(_GLFWwindow* window) +void _glfwRestoreWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { if ([window->ns.object isMiniaturized]) [window->ns.object deminiaturize:nil]; else if ([window->ns.object isZoomed]) [window->ns.object zoom:nil]; + } // autoreleasepool } -void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +void _glfwMaximizeWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { if (![window->ns.object isZoomed]) [window->ns.object zoom:nil]; + } // autoreleasepool } -void _glfwPlatformShowWindow(_GLFWwindow* window) +void _glfwShowWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { [window->ns.object orderFront:nil]; + } // autoreleasepool } -void _glfwPlatformHideWindow(_GLFWwindow* window) +void _glfwHideWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { [window->ns.object orderOut:nil]; + } // autoreleasepool } -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window) { + @autoreleasepool { [NSApp requestUserAttention:NSInformationalRequest]; + } // autoreleasepool } -void _glfwPlatformFocusWindow(_GLFWwindow* window) +void _glfwFocusWindowCocoa(_GLFWwindow* window) { + @autoreleasepool { // Make us the active application - // HACK: This has been moved here from initializeAppKit to prevent - // applications using only hidden windows from being activated, but - // should probably not be done every time any window is shown + // HACK: This is here to prevent applications using only hidden windows from + // being activated, but should probably not be done every time any + // window is shown [NSApp activateIgnoringOtherApps:YES]; - [window->ns.object makeKeyAndOrderFront:nil]; + } // autoreleasepool } -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { + @autoreleasepool { + if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) - acquireMonitor(window); + acquireMonitorCocoa(window); } else { const NSRect contentRect = - NSMakeRect(xpos, transformY(ypos + height), width, height); + NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), width, height); + const NSUInteger styleMask = [window->ns.object styleMask]; const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect - styleMask:getStyleMask(window)]; + styleMask:styleMask]; [window->ns.object setFrame:frameRect display:YES]; } @@ -1432,29 +1270,49 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } if (window->monitor) - releaseMonitor(window); + releaseMonitorCocoa(window); _glfwInputWindowMonitor(window, monitor); // HACK: Allow the state cached in Cocoa to catch up to reality // TODO: Solve this in a less terrible way - _glfwPlatformPollEvents(); + _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; + } - 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]; - if (monitor) + if (window->monitor) { [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; [window->ns.object setHasShadow:NO]; - acquireMonitor(window); + acquireMonitorCocoa(window); } else { - NSRect contentRect = NSMakeRect(xpos, transformY(ypos + height), + NSRect contentRect = NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), width, height); NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect styleMask:styleMask]; @@ -1486,35 +1344,66 @@ void _glfwPlatformSetWindowMonitor(_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 [window->ns.object setTitle:[window->ns.object miniwindowTitle]]; } + + } // autoreleasepool } -int _glfwPlatformWindowFocused(_GLFWwindow* window) +GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window) { + @autoreleasepool { return [window->ns.object isKeyWindow]; + } // autoreleasepool } -int _glfwPlatformWindowIconified(_GLFWwindow* window) +GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window) { + @autoreleasepool { return [window->ns.object isMiniaturized]; + } // autoreleasepool } -int _glfwPlatformWindowVisible(_GLFWwindow* window) +GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window) { + @autoreleasepool { return [window->ns.object isVisible]; + } // autoreleasepool } -int _glfwPlatformWindowMaximized(_GLFWwindow* window) +GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window) { - return [window->ns.object isZoomed]; + @autoreleasepool { + + if (window->resizable) + return [window->ns.object isZoomed]; + else + return GLFW_FALSE; + + } // autoreleasepool } -int _glfwPlatformWindowHovered(_GLFWwindow* window) +GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window) { + @autoreleasepool { + const NSPoint point = [NSEvent mouseLocation]; if ([NSWindow windowNumberAtPoint:point belowWindowWithWindowNumber:0] != @@ -1523,48 +1412,110 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window) return GLFW_FALSE; } - return NSPointInRect(point, - [window->ns.object convertRectToScreen:[window->ns.view bounds]]); + return NSMouseInRect(point, + [window->ns.object convertRectToScreen:[window->ns.view frame]], NO); + + } // autoreleasepool } -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window) { + @autoreleasepool { return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; + } // autoreleasepool } -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled) { - [window->ns.object setStyleMask:getStyleMask(window)]; + @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]; + } + + } // autoreleasepool } -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled) { - [window->ns.object setStyleMask:getStyleMask(window)]; + @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 makeFirstResponder:window->ns.view]; + + } // autoreleasepool } -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled) { + @autoreleasepool { if (enabled) [window->ns.object setLevel:NSFloatingWindowLevel]; else [window->ns.object setLevel:NSNormalWindowLevel]; + } // autoreleasepool } -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +void _glfwSetWindowMousePassthroughCocoa(_GLFWwindow* window, GLFWbool enabled) { + @autoreleasepool { + [window->ns.object setIgnoresMouseEvents:enabled]; + } +} + +float _glfwGetWindowOpacityCocoa(_GLFWwindow* window) +{ + @autoreleasepool { return (float) [window->ns.object alphaValue]; + } // autoreleasepool } -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +void _glfwSetWindowOpacityCocoa(_GLFWwindow* window, float opacity) { + @autoreleasepool { [window->ns.object setAlphaValue:opacity]; + } // autoreleasepool } -void _glfwPlatformPollEvents(void) +void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled) { - if (!initializeAppKit()) - return; + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Cocoa: Raw mouse motion not yet implemented"); +} + +GLFWbool _glfwRawMouseMotionSupportedCocoa(void) +{ + return GLFW_FALSE; +} + +void _glfwPollEventsCocoa(void) +{ + @autoreleasepool { for (;;) { @@ -1578,12 +1529,13 @@ void _glfwPlatformPollEvents(void) [NSApp sendEvent:event]; } - [_glfw.ns.autoreleasePool drain]; - _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + } // autoreleasepool } -void _glfwPlatformWaitEvents(void) +void _glfwWaitEventsCocoa(void) { + @autoreleasepool { + // I wanted to pass NO to dequeue:, and rely on PollEvents to // dequeue and send. For reasons not at all clear to me, passing // NO to dequeue: causes this method never to return. @@ -1593,11 +1545,15 @@ void _glfwPlatformWaitEvents(void) dequeue:YES]; [NSApp sendEvent:event]; - _glfwPlatformPollEvents(); + _glfwPollEventsCocoa(); + + } // autoreleasepool } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwWaitEventsTimeoutCocoa(double timeout) { + @autoreleasepool { + NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout]; NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:date @@ -1606,12 +1562,15 @@ void _glfwPlatformWaitEventsTimeout(double timeout) if (event) [NSApp sendEvent:event]; - _glfwPlatformPollEvents(); + _glfwPollEventsCocoa(); + + } // autoreleasepool } -void _glfwPlatformPostEmptyEvent(void) +void _glfwPostEmptyEventCocoa(void) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + @autoreleasepool { + NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 @@ -1622,25 +1581,34 @@ void _glfwPlatformPostEmptyEvent(void) data1:0 data2:0]; [NSApp postEvent:event atStart:YES]; - [pool drain]; + + } // autoreleasepool } -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwGetCursorPosCocoa(_GLFWwindow* window, double* xpos, double* ypos) { + @autoreleasepool { + const NSRect contentRect = [window->ns.view frame]; + // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; if (xpos) *xpos = pos.x; if (ypos) - *ypos = contentRect.size.height - pos.y - 1; + *ypos = contentRect.size.height - pos.y; + + } // autoreleasepool } -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y) { + @autoreleasepool { + updateCursorImage(window); const NSRect contentRect = [window->ns.view frame]; + // NOTE: The returned location uses base 0,1 not 0,0 const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; window->ns.cursorWarpDeltaX += x - pos.x; @@ -1658,20 +1626,49 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) const NSPoint globalPoint = globalRect.origin; CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, - transformY(globalPoint.y))); + _glfwTransformYCocoa(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 _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode) { - if (_glfwPlatformWindowFocused(window)) + @autoreleasepool { + + if (mode == GLFW_CURSOR_CAPTURED) + { + _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, + "Cocoa: Captured cursor mode not yet implemented"); + } + + if (_glfwWindowFocusedCocoa(window)) updateCursorMode(window); + + } // autoreleasepool } -const char* _glfwPlatformGetScancodeName(int scancode) +const char* _glfwGetScancodeNameCocoa(int scancode) { + @autoreleasepool { + + if (scancode < 0 || scancode > 0xff) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); + return NULL; + } + + const int key = _glfw.ns.keycodes[scancode]; + if (key == GLFW_KEY_UNKNOWN) + return NULL; + UInt32 deadKeyState = 0; - UniChar characters[8]; + UniChar characters[4]; UniCharCount characterCount = 0; if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes], @@ -1696,29 +1693,30 @@ const char* _glfwPlatformGetScancodeName(int scancode) characterCount, kCFAllocatorNull); CFStringGetCString(string, - _glfw.ns.keyName, - sizeof(_glfw.ns.keyName), + _glfw.ns.keynames[key], + sizeof(_glfw.ns.keynames[key]), kCFStringEncodingUTF8); CFRelease(string); - return _glfw.ns.keyName; + return _glfw.ns.keynames[key]; + + } // autoreleasepool } -int _glfwPlatformGetKeyScancode(int key) +int _glfwGetKeyScancodeCocoa(int key) { return _glfw.ns.scancodes[key]; } -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { + @autoreleasepool { + NSImage* native; NSBitmapImageRep* rep; - if (!initializeAppKit()) - return GLFW_FALSE; - rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:image->width @@ -1728,7 +1726,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bitmapFormat:NSBitmapFormatAlphaNonpremultiplied bytesPerRow:image->width * 4 bitsPerPixel:32]; @@ -1750,71 +1748,123 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GLFW_FALSE; return GLFW_TRUE; + + } // autoreleasepool } -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape) { - if (!initializeAppKit()) - return GLFW_FALSE; + @autoreleasepool { - 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_HAND_CURSOR) - cursor->ns.object = [NSCursor pointingHandCursor]; - else if (shape == GLFW_HRESIZE_CURSOR) - cursor->ns.object = [NSCursor resizeLeftRightCursor]; - else if (shape == GLFW_VRESIZE_CURSOR) - cursor->ns.object = [NSCursor resizeUpDownCursor]; + 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 (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) + { + id object = [NSCursor performSelector:cursorSelector]; + if ([object isKindOfClass:[NSCursor class]]) + cursor->ns.object = object; + } if (!cursor->ns.object) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to retrieve standard cursor"); + 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 (!cursor->ns.object) + { + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "Cocoa: Standard cursor shape unavailable"); return GLFW_FALSE; } [cursor->ns.object retain]; return GLFW_TRUE; + + } // autoreleasepool } -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +void _glfwDestroyCursorCocoa(_GLFWcursor* cursor) { + @autoreleasepool { if (cursor->ns.object) [(NSCursor*) cursor->ns.object release]; + } // autoreleasepool } -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor) { - if (cursorInClientArea(window)) + @autoreleasepool { + if (cursorInContentArea(window)) updateCursorImage(window); + } // autoreleasepool } -void _glfwPlatformSetClipboardString(const char* string) +void _glfwSetClipboardStringCocoa(const char* string) { - NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; - + @autoreleasepool { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:types owner:nil]; - [pasteboard setString:[NSString stringWithUTF8String:string] - forType:NSStringPboardType]; + [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; + [pasteboard setString:@(string) forType:NSPasteboardTypeString]; + } // autoreleasepool } -const char* _glfwPlatformGetClipboardString(void) +const char* _glfwGetClipboardStringCocoa(void) { + @autoreleasepool { + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - if (![[pasteboard types] containsObject:NSStringPboardType]) + if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "Cocoa: Failed to retrieve string from pasteboard"); return NULL; } - NSString* object = [pasteboard stringForType:NSStringPboardType]; + NSString* object = [pasteboard stringForType:NSPasteboardTypeString]; if (!object) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -1822,47 +1872,84 @@ const char* _glfwPlatformGetClipboardString(void) return NULL; } - free(_glfw.ns.clipboardString); + _glfw_free(_glfw.ns.clipboardString); _glfw.ns.clipboardString = _glfw_strdup([object UTF8String]); return _glfw.ns.clipboardString; + + } // autoreleasepool } -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) { - if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface) - return; + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; - extensions[0] = "VK_KHR_surface"; - extensions[1] = "VK_MVK_macos_surface"; + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_metal) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_METAL) + type = EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE; + } + + if (type) + { + *attribs = _glfw_calloc(3, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + + return 0; } -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void) +{ + return EGL_DEFAULT_DISPLAY; +} + +EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window) +{ + return window->ns.layer; +} + +void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions) +{ + if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface) + { + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_EXT_metal_surface"; + } + else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface) + { + extensions[0] = "VK_KHR_surface"; + extensions[1] = "VK_MVK_macos_surface"; + } +} + +GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { return GLFW_TRUE; } -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { + @autoreleasepool { + #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 - VkResult err; - VkMacOSSurfaceCreateInfoMVK sci; - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; - - vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) - vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); - if (!vkCreateMacOSSurfaceMVK) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - // HACK: Dynamically load Core Animation to avoid adding an extra // dependency for the majority who don't use MoltenVK NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"]; @@ -1882,14 +1969,55 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, return VK_ERROR_EXTENSION_NOT_PRESENT; } - [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; + if (window->ns.scaleFramebuffer) + [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]]; + + [window->ns.view setLayer:window->ns.layer]; [window->ns.view setWantsLayer:YES]; - memset(&sci, 0, sizeof(sci)); - sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - sci.pView = window->ns.view; + VkResult err; + + if (_glfw.vk.EXT_metal_surface) + { + VkMetalSurfaceCreateInfoEXT sci; + + PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; + vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT) + vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT"); + if (!vkCreateMetalSurfaceEXT) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Cocoa: Vulkan instance missing VK_EXT_metal_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + sci.pLayer = window->ns.layer; + + err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface); + } + else + { + VkMacOSSurfaceCreateInfoMVK sci; + + PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; + vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) + vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); + if (!vkCreateMacOSSurfaceMVK) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension"); + return VK_ERROR_EXTENSION_NOT_PRESENT; + } + + memset(&sci, 0, sizeof(sci)); + sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + sci.pView = window->ns.view; + + err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); + } - err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface); if (err) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -1901,6 +2029,8 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, #else return VK_ERROR_EXTENSION_NOT_PRESENT; #endif + + } // autoreleasepool } @@ -1912,6 +2042,31 @@ 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 fd344cf..cc1fac4 100644 --- a/raylib/external/glfw/src/context.c +++ b/raylib/external/glfw/src/context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2016 Camilla Löwy @@ -46,16 +46,6 @@ // 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) @@ -76,6 +66,23 @@ 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) || @@ -194,12 +201,6 @@ 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; @@ -358,8 +359,10 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; - previous = _glfwPlatformGetTls(&_glfw.contextSlot);; + previous = _glfwPlatformGetTls(&_glfw.contextSlot); glfwMakeContextCurrent((GLFWwindow*) window); + if (_glfwPlatformGetTls(&_glfw.contextSlot) != window) + return GLFW_FALSE; window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv"); @@ -568,7 +571,9 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) window->context.getProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT); - window->context.swapBuffers(window); + + if (window->doublebuffer) + window->context.swapBuffers(window); } glfwMakeContextCurrent((GLFWwindow*) previous); @@ -611,10 +616,12 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot); + _GLFWwindow* previous; _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 b2d11a4..ef65dd3 100644 --- a/raylib/external/glfw/src/egl_context.c +++ b/raylib/external/glfw/src/egl_context.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 EGL - www.glfw.org +// GLFW 3.4 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -86,13 +86,30 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // Return the EGLConfig most closely matching the specified hints // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* desired, + const _GLFWfbconfig* fbconfig, EGLConfig* result) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; - int i, nativeCount, usableCount; + 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; + } eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) @@ -101,10 +118,10 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, return GLFW_FALSE; } - nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); + nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig)); eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); - usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; for (i = 0; i < nativeCount; i++) @@ -121,44 +138,33 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, continue; #if defined(_GLFW_X11) - XVisualInfo vi = {0}; - - // Only consider EGLConfigs with associated Visuals - vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); - if (!vi.visualid) - continue; - - if (desired->transparent) + if (_glfw.platform.platformID == GLFW_PLATFORM_X11) { - int count; - XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, - VisualIDMask, &vi, - &count); - if (vis) + XVisualInfo vi = {0}; + + // Only consider EGLConfigs with associated Visuals + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) + continue; + + if (fbconfig->transparent) { - u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); - XFree(vis); + int count; + XVisualInfo* vis = + XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count); + if (vis) + { + u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); + XFree(vis); + } } } #endif // _GLFW_X11 - if (ctxconfig->client == GLFW_OPENGL_ES_API) + if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit)) { - 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; + wrongApiAvailable = GLFW_TRUE; + continue; } u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); @@ -169,19 +175,63 @@ 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 = GLFW_TRUE; + u->doublebuffer = fbconfig->doublebuffer; u->handle = (uintptr_t) n; usableCount++; } - closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + closest = _glfwChooseFBConfig(fbconfig, 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"); + } + } - free(nativeConfigs); - free(usableConfigs); + _glfw_free(nativeConfigs); + _glfw_free(usableConfigs); return closest != NULL; } @@ -227,6 +277,15 @@ 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); } @@ -250,11 +309,12 @@ 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) _glfw_dlsym(window->context.egl.client, - procname); + GLFWglproc proc = (GLFWglproc) + _glfwPlatformGetModuleSymbol(window->context.egl.client, procname); if (proc) return proc; } @@ -264,15 +324,14 @@ 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 (window->context.client != GLFW_OPENGL_API) -#endif // _GLFW_X11 + if (_glfw.platform.platformID != GLFW_PLATFORM_X11 || + window->context.client != GLFW_OPENGL_API) { if (window->context.egl.client) { - _glfw_dlclose(window->context.egl.client); + _glfwPlatformFreeModule(window->context.egl.client); window->context.egl.client = NULL; } } @@ -300,6 +359,8 @@ static void destroyContextEGL(_GLFWwindow* window) GLFWbool _glfwInitEGL(void) { int i; + EGLint* attribs = NULL; + const char* extensions; const char* sonames[] = { #if defined(_GLFW_EGL_LIBRARY) @@ -311,6 +372,8 @@ GLFWbool _glfwInitEGL(void) "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so", +#elif defined(__OpenBSD__) || defined(__NetBSD__) + "libEGL.so", #else "libEGL.so.1", #endif @@ -322,7 +385,7 @@ GLFWbool _glfwInitEGL(void) for (i = 0; sonames[i]; i++) { - _glfw.egl.handle = _glfw_dlopen(sonames[i]); + _glfw.egl.handle = _glfwPlatformLoadModule(sonames[i]); if (_glfw.egl.handle) break; } @@ -336,37 +399,37 @@ GLFWbool _glfwInitEGL(void) _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib) - _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigAttrib"); _glfw.egl.GetConfigs = (PFN_eglGetConfigs) - _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigs"); _glfw.egl.GetDisplay = (PFN_eglGetDisplay) - _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetDisplay"); _glfw.egl.GetError = (PFN_eglGetError) - _glfw_dlsym(_glfw.egl.handle, "eglGetError"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetError"); _glfw.egl.Initialize = (PFN_eglInitialize) - _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglInitialize"); _glfw.egl.Terminate = (PFN_eglTerminate) - _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglTerminate"); _glfw.egl.BindAPI = (PFN_eglBindAPI) - _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglBindAPI"); _glfw.egl.CreateContext = (PFN_eglCreateContext) - _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateContext"); _glfw.egl.DestroySurface = (PFN_eglDestroySurface) - _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroySurface"); _glfw.egl.DestroyContext = (PFN_eglDestroyContext) - _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext"); _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface) - _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface"); _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent) - _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent"); _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers) - _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapBuffers"); _glfw.egl.SwapInterval = (PFN_eglSwapInterval) - _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapInterval"); _glfw.egl.QueryString = (PFN_eglQueryString) - _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString"); _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) - _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); + _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress"); if (!_glfw.egl.GetConfigAttrib || !_glfw.egl.GetConfigs || @@ -392,7 +455,51 @@ GLFWbool _glfwInitEGL(void) return GLFW_FALSE; } - _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); + extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (extensions && eglGetError() == EGL_SUCCESS) + _glfw.egl.EXT_client_extensions = GLFW_TRUE; + + if (_glfw.egl.EXT_client_extensions) + { + _glfw.egl.EXT_platform_base = + _glfwStringInExtensionString("EGL_EXT_platform_base", extensions); + _glfw.egl.EXT_platform_x11 = + _glfwStringInExtensionString("EGL_EXT_platform_x11", extensions); + _glfw.egl.EXT_platform_wayland = + _glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions); + _glfw.egl.ANGLE_platform_angle = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions); + _glfw.egl.ANGLE_platform_angle_opengl = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions); + _glfw.egl.ANGLE_platform_angle_d3d = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions); + _glfw.egl.ANGLE_platform_angle_vulkan = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions); + _glfw.egl.ANGLE_platform_angle_metal = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions); + } + + if (_glfw.egl.EXT_platform_base) + { + _glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) + eglGetProcAddress("eglGetPlatformDisplayEXT"); + _glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) + eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); + } + + _glfw.egl.platform = _glfw.platform.getEGLPlatform(&attribs); + if (_glfw.egl.platform) + { + _glfw.egl.display = + eglGetPlatformDisplayEXT(_glfw.egl.platform, + _glfw.platform.getEGLNativeDisplay(), + attribs); + } + else + _glfw.egl.display = eglGetDisplay(_glfw.platform.getEGLNativeDisplay()); + + _glfw_free(attribs); + if (_glfw.egl.display == EGL_NO_DISPLAY) { _glfwInputError(GLFW_API_UNAVAILABLE, @@ -423,6 +530,8 @@ 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; } @@ -439,14 +548,14 @@ void _glfwTerminateEGL(void) if (_glfw.egl.handle) { - _glfw_dlclose(_glfw.egl.handle); + _glfwPlatformFreeModule(_glfw.egl.handle); _glfw.egl.handle = NULL; } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ - assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } @@ -460,6 +569,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, EGLint attribs[40]; EGLConfig config; EGLContext share = NULL; + EGLNativeWindowType native; int index = 0; if (!_glfw.egl.display) @@ -472,11 +582,7 @@ 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) { @@ -521,57 +627,57 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_NO_RESET_NOTIFICATION_KHR); + SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_NO_RESET_NOTIFICATION_KHR); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, - EGL_LOSE_CONTEXT_ON_RESET_KHR); + SET_ATTRIB(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) - 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); + SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); } if (mask) - setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); if (flags) - setAttrib(EGL_CONTEXT_FLAGS_KHR, flags); + SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags); } else { if (ctxconfig->client == GLFW_OPENGL_ES_API) - setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); + SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); } if (_glfw.egl.KHR_context_flush_control) { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); + SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, - EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, + EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); } } - setAttrib(EGL_NONE, EGL_NONE); + SET_ATTRIB(EGL_NONE, EGL_NONE); window->context.egl.handle = eglCreateContext(_glfw.egl.display, config, share, attribs); @@ -585,23 +691,39 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, } // Set up attributes for surface creation + index = 0; + + if (fbconfig->sRGB) { - int index = 0; - - if (fbconfig->sRGB) - { - if (_glfw.egl.KHR_gl_colorspace) - setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); - } - - setAttrib(EGL_NONE, EGL_NONE); + if (_glfw.egl.KHR_gl_colorspace) + SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + + if (!fbconfig->doublebuffer) + SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); + + 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); + // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT + // despite reporting EGL_EXT_platform_base + if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE) + { + window->context.egl.surface = + eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs); + } + else + { + window->context.egl.surface = + eglCreateWindowSurface(_glfw.egl.display, config, native, attribs); } - window->context.egl.surface = - eglCreateWindowSurface(_glfw.egl.display, - config, - _GLFW_EGL_NATIVE_WINDOW, - attribs); if (window->context.egl.surface == EGL_NO_SURFACE) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -626,6 +748,8 @@ 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", @@ -643,6 +767,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so", +#elif defined(__OpenBSD__) || defined(__NetBSD__) + "libGLESv2.so", #else "libGLESv2.so.2", #endif @@ -654,7 +780,10 @@ 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 @@ -677,7 +806,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) continue; - window->context.egl.client = _glfw_dlopen(sonames[i]); + window->context.egl.client = _glfwPlatformLoadModule(sonames[i]); if (window->context.egl.client) break; } @@ -700,7 +829,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB // Returns the Visual and depth of the chosen EGLConfig // @@ -717,11 +846,7 @@ 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); @@ -761,7 +886,7 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); - if (window->context.client == GLFW_NO_API) + if (window->context.source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT; @@ -775,7 +900,7 @@ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); - if (window->context.client == GLFW_NO_API) + if (window->context.source != GLFW_EGL_CONTEXT_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 deleted file mode 100644 index aa339ba..0000000 --- a/raylib/external/glfw/src/egl_context.h +++ /dev/null @@ -1,219 +0,0 @@ -//======================================================================== -// GLFW 3.3 EGL - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 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_USE_EGLPLATFORM_H) - #include -#elif defined(_GLFW_WIN32) - #define EGLAPIENTRY __stdcall -typedef HDC EGLNativeDisplayType; -typedef HWND EGLNativeWindowType; -#elif defined(_GLFW_COCOA) - #define EGLAPIENTRY -typedef void* EGLNativeDisplayType; -typedef id EGLNativeWindowType; -#elif defined(_GLFW_X11) - #define EGLAPIENTRY -typedef Display* EGLNativeDisplayType; -typedef Window EGLNativeWindowType; -#elif defined(_GLFW_WAYLAND) - #define EGLAPIENTRY -typedef struct wl_display* EGLNativeDisplayType; -typedef struct wl_egl_window* EGLNativeWindowType; -#elif defined(_GLFW_MIR) - #define EGLAPIENTRY -typedef MirEGLNativeDisplayType EGLNativeDisplayType; -typedef MirEGLNativeWindowType EGLNativeWindowType; -#else - #error "No supported EGL platform selected" -#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 - -typedef int EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; -typedef void* EGLConfig; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLSurface; - -// 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 - -#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl -#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl - - -// EGL-specific per-context data -// -typedef struct _GLFWcontextEGL -{ - EGLConfig config; - EGLContext handle; - EGLSurface surface; - - void* client; - -} _GLFWcontextEGL; - -// EGL-specific global data -// -typedef struct _GLFWlibraryEGL -{ - 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; - - 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; - -} _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 new file mode 100644 index 0000000..f847c1e --- /dev/null +++ b/raylib/external/glfw/src/fractional-scale-v1-client-protocol-code.h @@ -0,0 +1,74 @@ +/* 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 new file mode 100644 index 0000000..8df7558 --- /dev/null +++ b/raylib/external/glfw/src/fractional-scale-v1-client-protocol.h @@ -0,0 +1,264 @@ +/* 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 adace82..7082682 100644 --- a/raylib/external/glfw/src/glx_context.c +++ b/raylib/external/glfw/src/glx_context.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 GLX - www.glfw.org +// GLFW 3.4 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(_GLFW_X11) + #include #include #include @@ -53,7 +55,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; - int i, nativeCount, usableCount; + int nativeCount, usableCount; const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; @@ -71,10 +73,10 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, return GLFW_FALSE; } - usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; - for (i = 0; i < nativeCount; i++) + for (int i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; @@ -90,6 +92,9 @@ 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); @@ -117,8 +122,6 @@ 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); @@ -135,7 +138,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, *result = (GLXFBConfig) closest->handle; XFree(nativeConfigs); - free(usableConfigs); + _glfw_free(usableConfigs); return closest != NULL; } @@ -187,6 +190,7 @@ static void swapBuffersGLX(_GLFWwindow* window) static void swapIntervalGLX(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); if (_glfw.glx.EXT_swap_control) { @@ -223,11 +227,12 @@ static GLFWglproc getProcAddressGLX(const char* procname) else if (_glfw.glx.GetProcAddressARB) return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); else - return _glfw_dlsym(_glfw.glx.handle, procname); + { + // NOTE: glvnd provides GLX 1.4, so this can only happen with libGL + return _glfwPlatformGetModuleSymbol(_glfw.glx.handle, procname); + } } -// Destroy the OpenGL context -// static void destroyContextGLX(_GLFWwindow* window) { if (window->context.glx.window) @@ -252,14 +257,16 @@ 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 @@ -269,9 +276,9 @@ GLFWbool _glfwInitGLX(void) if (_glfw.glx.handle) return GLFW_TRUE; - for (i = 0; sonames[i]; i++) + for (int i = 0; sonames[i]; i++) { - _glfw.glx.handle = _glfw_dlopen(sonames[i]); + _glfw.glx.handle = _glfwPlatformLoadModule(sonames[i]); if (_glfw.glx.handle) break; } @@ -282,36 +289,32 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } - _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"); + _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"); if (!_glfw.glx.GetFBConfigs || !_glfw.glx.GetFBConfigAttrib || @@ -325,8 +328,6 @@ 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, @@ -334,6 +335,12 @@ 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)) @@ -424,18 +431,18 @@ GLFWbool _glfwInitGLX(void) void _glfwTerminateGLX(void) { // NOTE: This function must not call any X11 functions, as it is called - // after XCloseDisplay (see _glfwPlatformTerminate for details) + // after XCloseDisplay (see _glfwTerminateX11 for details) if (_glfw.glx.handle) { - _glfw_dlclose(_glfw.glx.handle); + _glfwPlatformFreeModule(_glfw.glx.handle); _glfw.glx.handle = NULL; } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ - assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } @@ -521,13 +528,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_NO_RESET_NOTIFICATION_ARB); + SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_LOSE_CONTEXT_ON_RESET_ARB); + SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); } flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -540,13 +547,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -554,7 +561,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.glx.ARB_create_context_no_error) - setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + SET_ATTRIB(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -562,17 +569,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) - setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask); if (flags) - setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); + SET_ATTRIB(GLX_CONTEXT_FLAGS_ARB, flags); - setAttrib(None, None); + SET_ATTRIB(None, None); window->context.glx.handle = _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, @@ -629,7 +636,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB // Returns the Visual and depth of the chosen GLXFBConfig // @@ -673,7 +680,13 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API) + 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) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -687,7 +700,13 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - if (window->context.client == GLFW_NO_API) + 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) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None; @@ -696,3 +715,5 @@ 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 deleted file mode 100644 index f767cb1..0000000 --- a/raylib/external/glfw/src/glx_context.h +++ /dev/null @@ -1,181 +0,0 @@ -//======================================================================== -// GLFW 3.3 GLX - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 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/wayland-idle-inhibit-unstable-v1-client-protocol.c b/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h similarity index 70% rename from raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c rename to raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h index 04c32c2..0399e11 100644 --- a/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c +++ b/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol-code.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ /* * Copyright © 2015 Samsung Electronics Co., Ltd @@ -23,34 +23,45 @@ * 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 *wl_ii_types[] = { +static const struct wl_interface *idle_inhibit_unstable_v1_types[] = { &zwp_idle_inhibitor_v1_interface, &wl_surface_interface, }; static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = { - { "destroy", "", wl_ii_types + 0 }, - { "create_inhibitor", "no", wl_ii_types + 0 }, + { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, + { "create_inhibitor", "no", idle_inhibit_unstable_v1_types + 0 }, }; -WL_EXPORT const struct wl_interface zwp_idle_inhibit_manager_v1_interface = { +WL_PRIVATE 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", "", wl_ii_types + 0 }, + { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, }; -WL_EXPORT const struct wl_interface zwp_idle_inhibitor_v1_interface = { +WL_PRIVATE 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/wayland-idle-inhibit-unstable-v1-client-protocol.h b/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h similarity index 91% rename from raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h index b53d706..ef97ceb 100644 --- a/raylib/external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/idle-inhibit-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ #ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H #define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -45,6 +45,8 @@ 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 @@ -81,6 +83,9 @@ 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 @@ -117,6 +122,7 @@ 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 @@ -159,10 +165,8 @@ 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((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); + 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); } /** @@ -175,8 +179,8 @@ zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 { struct wl_proxy *id; - 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); + 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); return (struct zwp_idle_inhibitor_v1 *) id; } @@ -217,10 +221,8 @@ 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((struct wl_proxy *) zwp_idle_inhibitor_v1, - ZWP_IDLE_INHIBITOR_V1_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) 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); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/init.c b/raylib/external/glfw/src/init.c index 9e670d4..532264e 100644 --- a/raylib/external/glfw/src/init.c +++ b/raylib/external/glfw/src/init.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -26,7 +26,6 @@ //======================================================================== #include "internal.h" -#include "mappings.h" #include #include @@ -35,28 +34,61 @@ #include -// The global variables below comprise all mutable global data in GLFW -// -// Any other global variable is a bug +// NOTE: The global variables below comprise all mutable global data in GLFW +// Any other mutable global variable is a bug -// Global state shared between compilation units of GLFW +// This contains all mutable 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 +// after termination without special handling when _glfw is cleared to zero // static _GLFWerror _glfwMainThreadError; static GLFWerrorfun _glfwErrorCallback; +static GLFWallocator _glfwInitAllocator; static _GLFWinitconfig _glfwInitHints = { - GLFW_TRUE, // hat buttons + .hatButtons = GLFW_TRUE, + .angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE, + .platformID = GLFW_ANY_PLATFORM, + .vulkanLoader = NULL, + .ns = { - GLFW_TRUE, // macOS menu bar - GLFW_TRUE // macOS bundle chdir - } + .menubar = GLFW_TRUE, + .chdir = GLFW_TRUE + }, + .x11 = + { + .xcbVulkanSurface = GLFW_TRUE, + }, + .wl = + { + .libdecorMode = GLFW_WAYLAND_PREFER_LIBDECOR + }, }; +// 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) @@ -75,20 +107,21 @@ static void terminate(void) { _GLFWmonitor* monitor = _glfw.monitors[i]; if (monitor->originalRamp.size) - _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); + _glfw.platform.setGammaRamp(monitor, &monitor->originalRamp); _glfwFreeMonitor(monitor); } - free(_glfw.monitors); + _glfw_free(_glfw.monitors); _glfw.monitors = NULL; _glfw.monitorCount = 0; - free(_glfw.mappings); + _glfw_free(_glfw.mappings); _glfw.mappings = NULL; _glfw.mappingCount = 0; _glfwTerminateVulkan(); - _glfwPlatformTerminate(); + _glfw.platform.terminateJoysticks(); + _glfw.platform.terminate(); _glfw.initialized = GLFW_FALSE; @@ -96,7 +129,7 @@ static void terminate(void) { _GLFWerror* error = _glfw.errorListHead; _glfw.errorListHead = error->next; - free(error); + _glfw_free(error); } _glfwPlatformDestroyTls(&_glfw.contextSlot); @@ -111,14 +144,161 @@ 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 = calloc(length + 1, 1); + char* result = _glfw_calloc(length + 1, 1); strcpy(result, source); return result; } +int _glfw_min(int a, int 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; + } + } + else + return NULL; +} + +void* _glfw_realloc(void* block, size_t size) +{ + 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; + } + else + return _glfw_calloc(1, size); +} + +void _glfw_free(void* block) +{ + if (block) + _glfw.allocator.deallocate(block, _glfw.allocator.user); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW event API ////// @@ -163,6 +343,14 @@ void _glfwInputError(int code, const char* format, ...) strcpy(description, "The requested format is unavailable"); else if (code == GLFW_NO_WINDOW_CONTEXT) strcpy(description, "The specified window has no context"); + else if (code == GLFW_CURSOR_UNAVAILABLE) + strcpy(description, "The specified cursor shape is unavailable"); + else if (code == GLFW_FEATURE_UNAVAILABLE) + 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"); } @@ -172,7 +360,7 @@ void _glfwInputError(int code, const char* format, ...) error = _glfwPlatformGetTls(&_glfw.errorSlot); if (!error) { - error = calloc(1, sizeof(_GLFWerror)); + error = _glfw_calloc(1, sizeof(_GLFWerror)); _glfwPlatformSetTls(&_glfw.errorSlot, error); _glfwPlatformLockMutex(&_glfw.errorLock); error->next = _glfw.errorListHead; @@ -203,7 +391,18 @@ GLFWAPI int glfwInit(void) memset(&_glfw, 0, sizeof(_glfw)); _glfw.hints.init = _glfwInitHints; - if (!_glfwPlatformInit()) + _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()) { terminate(); return GLFW_FALSE; @@ -219,24 +418,14 @@ GLFWAPI int glfwInit(void) _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); - _glfw.initialized = GLFW_TRUE; + _glfwInitGamepadMappings(); + + _glfwPlatformInitTimer(); _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; } @@ -255,18 +444,48 @@ GLFWAPI void glfwInitHint(int hint, int value) case GLFW_JOYSTICK_HAT_BUTTONS: _glfwInitHints.hatButtons = value; return; + 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) @@ -277,11 +496,6 @@ 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; @@ -308,7 +522,7 @@ GLFWAPI int glfwGetError(const char** description) GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) { - _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); + _GLFW_SWAP(GLFWerrorfun, _glfwErrorCallback, cbfun); return cbfun; } diff --git a/raylib/external/glfw/src/input.c b/raylib/external/glfw/src/input.c index 4297545..7b3b340 100644 --- a/raylib/external/glfw/src/input.c +++ b/raylib/external/glfw/src/input.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -26,13 +26,13 @@ //======================================================================== #include "internal.h" +#include "mappings.h" #include #include #include #include #include -#include // Internal key state used for sticky keys #define _GLFW_STICK 3 @@ -42,6 +42,29 @@ #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()) + { + _glfw.platform.terminateJoysticks(); + return GLFW_FALSE; + } + } + + return _glfw.joysticksInitialized = GLFW_TRUE; +} + // Finds a mapping based on joystick GUID // static _GLFWmapping* findMapping(const char* guid) @@ -84,25 +107,13 @@ 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; - } } } @@ -228,8 +239,9 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) } else { - length = strlen(_GLFW_PLATFORM_MAPPING_NAME); - if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) + const char* name = _glfw.platform.getMappingName(); + length = strlen(name); + if (strncmp(c, name, length) != 0) return GLFW_FALSE; } @@ -246,7 +258,7 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) mapping->guid[i] += 'a' - 'A'; } - _glfwPlatformUpdateGamepadGUID(mapping->guid); + _glfw.platform.updateGamepadGUID(mapping->guid); return GLFW_TRUE; } @@ -259,6 +271,12 @@ 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; @@ -288,8 +306,12 @@ 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, unsigned int codepoint, int mods, GLFWbool plain) +void _glfwInputChar(_GLFWwindow* window, uint32_t 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; @@ -310,6 +332,12 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb // 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); } @@ -318,6 +346,12 @@ 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; @@ -334,10 +368,16 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) } // Notifies shared code of a cursor motion event -// The position is specified in client-area relative screen coordinates +// The position is specified in content area relative screen coordinates // 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; @@ -352,6 +392,9 @@ 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); } @@ -360,6 +403,10 @@ 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); } @@ -368,16 +415,26 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) // void _glfwInputJoystick(_GLFWjoystick* js, int event) { - const int jid = (int) (js - _glfw.joysticks); + 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; if (_glfw.callbacks.joystick) - _glfw.callbacks.joystick(jid, event); + _glfw.callbacks.joystick((int) (js - _glfw.joysticks), 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; } @@ -385,6 +442,11 @@ 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; } @@ -392,7 +454,19 @@ void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) // void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { - const int base = js->buttonCount + hat * 4; + 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; js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; @@ -407,6 +481,21 @@ 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, @@ -420,7 +509,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].present) + if (!_glfw.joysticks[jid].allocated) break; } @@ -428,16 +517,16 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, return NULL; js = _glfw.joysticks + jid; - js->present = GLFW_TRUE; - js->name = _glfw_strdup(name); - js->axes = calloc(axisCount, sizeof(float)); - js->buttons = calloc(buttonCount + hatCount * 4, 1); - js->hats = calloc(hatCount, 1); + 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->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; - strcpy(js->guid, guid); + strncpy(js->name, name, sizeof(js->name) - 1); + strncpy(js->guid, guid, sizeof(js->guid) - 1); js->mapping = findValidMapping(js); return js; @@ -447,13 +536,22 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, // void _glfwFreeJoystick(_GLFWjoystick* js) { - free(js->name); - free(js->axes); - free(js->buttons); - free(js->hats); + _glfw_free(js->axes); + _glfw_free(js->buttons); + _glfw_free(js->hats); memset(js, 0, sizeof(_GLFWjoystick)); } +// Center the cursor in the content area of the specified window +// +void _glfwCenterCursorInContentArea(_GLFWwindow* window) +{ + int width, height; + + _glfw.platform.getWindowSize(window, &width, &height); + _glfw.platform.setCursorPos(window, width / 2.0, height / 2.0); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -476,6 +574,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyMouseButtons; case GLFW_LOCK_KEY_MODS: return window->lockKeyMods; + case GLFW_RAW_MOUSE_MOTION: + return window->rawMouseMotion; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); @@ -489,72 +589,109 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) _GLFW_REQUIRE_INIT(); - if (mode == GLFW_CURSOR) + switch (mode) { - if (value != GLFW_CURSOR_NORMAL && - value != GLFW_CURSOR_HIDDEN && - value != GLFW_CURSOR_DISABLED) + case GLFW_CURSOR: { - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid cursor mode 0x%08X", - value); - return; - } - - if (window->cursorMode == value) - return; - - window->cursorMode = value; - - _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; - - if (!value) - { - int i; - - // Release all sticky keys - for (i = 0; i <= GLFW_KEY_LAST; i++) + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED && + value != GLFW_CURSOR_CAPTURED) { - if (window->keys[i] == _GLFW_STICK) - window->keys[i] = GLFW_RELEASE; + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); + return; } - } - window->stickyKeys = value; - } - else if (mode == GLFW_STICKY_MOUSE_BUTTONS) - { - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->stickyMouseButtons == value) + if (window->cursorMode == value) + return; + + window->cursorMode = value; + + _glfw.platform.getCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); + _glfw.platform.setCursorMode(window, 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; + 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; + return; + } + + case 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; + 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; + } } - else if (mode == GLFW_LOCK_KEY_MODS) - window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; - else - _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); + + _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(); } GLFWAPI const char* glfwGetKeyName(int key, int scancode) @@ -563,6 +700,12 @@ 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)) @@ -570,23 +713,23 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode) return NULL; } - scancode = _glfwPlatformGetKeyScancode(key); + scancode = _glfw.platform.getKeyScancode(key); } - return _glfwPlatformGetScancodeName(scancode); + return _glfw.platform.getScancodeName(scancode); } GLFWAPI int glfwGetKeyScancode(int key) { - _GLFW_REQUIRE_INIT_OR_RETURN(-1); + _GLFW_REQUIRE_INIT_OR_RETURN(0); if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); - return GLFW_RELEASE; + return -1; } - return _glfwPlatformGetKeyScancode(key); + return _glfw.platform.getKeyScancode(key); } GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) @@ -655,7 +798,7 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) *ypos = window->virtualCursorPosY; } else - _glfwPlatformGetCursorPos(window, xpos, ypos); + _glfw.platform.getCursorPos(window, xpos, ypos); } GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) @@ -674,7 +817,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) return; } - if (!_glfwPlatformWindowFocused(window)) + if (!_glfw.platform.windowFocused(window)) return; if (window->cursorMode == GLFW_CURSOR_DISABLED) @@ -686,7 +829,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) else { // Update system cursor position - _glfwPlatformSetCursorPos(window, xpos, ypos); + _glfw.platform.setCursorPos(window, xpos, ypos); } } @@ -695,14 +838,21 @@ 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); - cursor = calloc(1, sizeof(_GLFWcursor)); + 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->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; - if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) + if (!_glfw.platform.createCursor(cursor, image, xhot, yhot)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; @@ -720,19 +870,23 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) if (shape != GLFW_ARROW_CURSOR && shape != GLFW_IBEAM_CURSOR && shape != GLFW_CROSSHAIR_CURSOR && - shape != GLFW_HAND_CURSOR && - shape != GLFW_HRESIZE_CURSOR && - shape != GLFW_VRESIZE_CURSOR) + shape != GLFW_POINTING_HAND_CURSOR && + shape != GLFW_RESIZE_EW_CURSOR && + shape != GLFW_RESIZE_NS_CURSOR && + shape != GLFW_RESIZE_NWSE_CURSOR && + shape != GLFW_RESIZE_NESW_CURSOR && + shape != GLFW_RESIZE_ALL_CURSOR && + shape != GLFW_NOT_ALLOWED_CURSOR) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); return NULL; } - cursor = calloc(1, sizeof(_GLFWcursor)); + cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); cursor->next = _glfw.cursorListHead; _glfw.cursorListHead = cursor; - if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + if (!_glfw.platform.createStandardCursor(cursor, shape)) { glfwDestroyCursor((GLFWcursor*) cursor); return NULL; @@ -761,7 +915,7 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) } } - _glfwPlatformDestroyCursor(cursor); + _glfw.platform.destroyCursor(cursor); // Unlink cursor from global linked list { @@ -773,7 +927,7 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) *prev = cursor->next; } - free(cursor); + _glfw_free(cursor); } GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) @@ -786,7 +940,7 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) window->cursor = cursor; - _glfwPlatformSetCursor(window, cursor); + _glfw.platform.setCursor(window, cursor); } GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) @@ -795,7 +949,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); + _GLFW_SWAP(GLFWkeyfun, window->callbacks.key, cbfun); return cbfun; } @@ -805,7 +959,7 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); + _GLFW_SWAP(GLFWcharfun, window->callbacks.character, cbfun); return cbfun; } @@ -815,7 +969,7 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmods assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); + _GLFW_SWAP(GLFWcharmodsfun, window->callbacks.charmods, cbfun); return cbfun; } @@ -826,7 +980,7 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); + _GLFW_SWAP(GLFWmousebuttonfun, window->callbacks.mouseButton, cbfun); return cbfun; } @@ -837,7 +991,7 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); + _GLFW_SWAP(GLFWcursorposfun, window->callbacks.cursorPos, cbfun); return cbfun; } @@ -848,7 +1002,7 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); + _GLFW_SWAP(GLFWcursorenterfun, window->callbacks.cursorEnter, cbfun); return cbfun; } @@ -859,7 +1013,7 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); + _GLFW_SWAP(GLFWscrollfun, window->callbacks.scroll, cbfun); return cbfun; } @@ -869,7 +1023,7 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); + _GLFW_SWAP(GLFWdropfun, window->callbacks.drop, cbfun); return cbfun; } @@ -888,11 +1042,14 @@ GLFWAPI int glfwJoystickPresent(int jid) return GLFW_FALSE; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return GLFW_FALSE; - return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); + js = _glfw.joysticks + jid; + if (!js->connected) + return GLFW_FALSE; + + return _glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE); } GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) @@ -913,11 +1070,14 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_AXES)) return NULL; *count = js->axisCount; @@ -942,11 +1102,14 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; if (_glfw.hints.init.hatButtons) @@ -975,11 +1138,14 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) return NULL; *count = js->hatCount; @@ -1001,11 +1167,14 @@ GLFWAPI const char* glfwGetJoystickName(int jid) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->name; @@ -1026,11 +1195,14 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; return js->guid; @@ -1046,7 +1218,7 @@ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) _GLFW_REQUIRE_INIT(); js = _glfw.joysticks + jid; - if (!js->present) + if (!js->allocated) return; js->userPointer = pointer; @@ -1062,7 +1234,7 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); js = _glfw.joysticks + jid; - if (!js->present) + if (!js->allocated) return NULL; return js->userPointer; @@ -1071,7 +1243,11 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid) GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); + + if (!initJoysticks()) + return NULL; + + _GLFW_SWAP(GLFWjoystickfun, _glfw.callbacks.joystick, cbfun); return cbfun; } @@ -1086,7 +1262,9 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) while (*c) { - if (isxdigit(*c)) + if ((*c >= '0' && *c <= '9') || + (*c >= 'a' && *c <= 'f') || + (*c >= 'A' && *c <= 'F')) { char line[1024]; @@ -1107,8 +1285,8 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) { _glfw.mappingCount++; _glfw.mappings = - realloc(_glfw.mappings, - sizeof(_GLFWmapping) * _glfw.mappingCount); + _glfw_realloc(_glfw.mappings, + sizeof(_GLFWmapping) * _glfw.mappingCount); _glfw.mappings[_glfw.mappingCount - 1] = mapping; } } @@ -1126,7 +1304,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) js->mapping = findValidMapping(js); } @@ -1148,11 +1326,14 @@ GLFWAPI int glfwJoystickIsGamepad(int jid) return GLFW_FALSE; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return GLFW_FALSE; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + js = _glfw.joysticks + jid; + if (!js->connected) + return GLFW_FALSE; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) return GLFW_FALSE; return js->mapping != NULL; @@ -1173,11 +1354,14 @@ GLFWAPI const char* glfwGetGamepadName(int jid) return NULL; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return NULL; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) + js = _glfw.joysticks + jid; + if (!js->connected) + return NULL; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) return NULL; if (!js->mapping) @@ -1205,11 +1389,14 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) return GLFW_FALSE; } - js = _glfw.joysticks + jid; - if (!js->present) + if (!initJoysticks()) return GLFW_FALSE; - if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) + js = _glfw.joysticks + jid; + if (!js->connected) + return GLFW_FALSE; + + if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_ALL)) return GLFW_FALSE; if (!js->mapping) @@ -1221,8 +1408,18 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) if (e->type == _GLFW_JOYSTICK_AXIS) { const float value = js->axes[e->index] * e->axisScale + e->axisOffset; - if (value > 0.f) - state->buttons[i] = GLFW_PRESS; + // HACK: This should be baked into the value transform + // TODO: Bake into transform when implementing output modifiers + if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0)) + { + if (value >= 0.f) + state->buttons[i] = GLFW_PRESS; + } + else + { + if (value <= 0.f) + state->buttons[i] = GLFW_PRESS; + } } else if (e->type == _GLFW_JOYSTICK_HATBIT) { @@ -1249,9 +1446,11 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) const unsigned int bit = e->index & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; + else + state->axes[i] = -1.f; } else if (e->type == _GLFW_JOYSTICK_BUTTON) - state->axes[i] = (float) js->buttons[e->index]; + state->axes[i] = js->buttons[e->index] * 2.f - 1.f; } return GLFW_TRUE; @@ -1262,13 +1461,13 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) assert(string != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformSetClipboardString(string); + _glfw.platform.setClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetClipboardString(); + return _glfw.platform.getClipboardString(); } GLFWAPI double glfwGetTime(void) diff --git a/raylib/external/glfw/src/internal.h b/raylib/external/glfw/src/internal.h index 92bbfcc..8873359 100644 --- a/raylib/external/glfw/src/internal.h +++ b/raylib/external/glfw/src/internal.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -59,6 +59,7 @@ #define _GLFW_MESSAGE_SIZE 1024 typedef int GLFWbool; +typedef void (*GLFWproc)(void); typedef struct _GLFWerror _GLFWerror; typedef struct _GLFWinitconfig _GLFWinitconfig; @@ -67,6 +68,7 @@ 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; @@ -76,16 +78,9 @@ 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 +#define GL_NONE 0 +#define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_UNSIGNED_BYTE 0x1401 #define GL_EXTENSIONS 0x1f03 #define GL_NUM_EXTENSIONS 0x821d @@ -102,7 +97,7 @@ typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc #define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 -typedef int GLint; +typedef int GLint; typedef unsigned int GLuint; typedef unsigned int GLenum; typedef unsigned int GLbitfield; @@ -113,6 +108,159 @@ 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; @@ -126,9 +274,9 @@ typedef enum VkStructureType VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; @@ -170,38 +318,14 @@ typedef struct VkExtensionProperties typedef void (APIENTRY * PFN_vkVoidFunction)(void); -#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 +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_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_MIR) - #include "mir_platform.h" -#elif defined(_GLFW_OSMESA) - #include "null_platform.h" -#else - #error "No supported window creation API selected" -#endif +#include "platform.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) +#define GLFW_NATIVE_INCLUDE_NONE +#include "../include/GLFW/glfw3native.h" // Checks for whether the library has been initialized #define _GLFW_REQUIRE_INIT() \ @@ -218,12 +342,12 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); } // Swaps the provided pointers -#define _GLFW_SWAP_POINTERS(x, y) \ - { \ - void* t; \ - t = x; \ - x = y; \ - y = t; \ +#define _GLFW_SWAP(type, x, y) \ + { \ + type t; \ + t = x; \ + x = y; \ + y = t; \ } // Per-thread error structure @@ -242,10 +366,19 @@ struct _GLFWerror 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 @@ -256,6 +389,8 @@ struct _GLFWinitconfig // struct _GLFWwndconfig { + int xpos; + int ypos; int width; int height; const char* title; @@ -267,14 +402,24 @@ struct _GLFWwndconfig GLFWbool floating; GLFWbool maximized; GLFWbool centerCursor; + GLFWbool focusOnShow; + GLFWbool mousePassthrough; + GLFWbool scaleToMonitor; + GLFWbool scaleFramebuffer; struct { - GLFWbool retina; char frameName[256]; } ns; struct { char className[256]; char instanceName[256]; } x11; + struct { + GLFWbool keymenu; + GLFWbool showDefault; + } win32; + struct { + char appId[256]; + } wl; }; // Context configuration @@ -342,23 +487,33 @@ struct _GLFWcontext int robustness; int release; - PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv; - PFNGLGETSTRINGPROC GetString; + PFNGLGETSTRINGPROC GetString; - _GLFWmakecontextcurrentfun makeCurrent; - _GLFWswapbuffersfun swapBuffers; - _GLFWswapintervalfun swapInterval; - _GLFWextensionsupportedfun extensionSupported; - _GLFWgetprocaddressfun getProcAddress; - _GLFWdestroycontextfun destroy; + void (*makeCurrent)(_GLFWwindow*); + void (*swapBuffers)(_GLFWwindow*); + void (*swapInterval)(int); + int (*extensionSupported)(const char*); + GLFWglproc (*getProcAddress)(const char*); + void (*destroy)(_GLFWwindow*); - // This is defined in the context API's context.h - _GLFW_PLATFORM_CONTEXT_STATE; - // This is defined in egl_context.h - _GLFW_EGL_CONTEXT_STATE; - // This is defined in osmesa_context.h - _GLFW_OSMESA_CONTEXT_STATE; + 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 }; // Window and context structure @@ -372,11 +527,15 @@ struct _GLFWwindow GLFWbool decorated; GLFWbool autoIconify; GLFWbool floating; + GLFWbool focusOnShow; + GLFWbool mousePassthrough; GLFWbool shouldClose; void* userPointer; + GLFWbool doublebuffer; GLFWvidmode videoMode; _GLFWmonitor* monitor; _GLFWcursor* cursor; + char* title; int minwidth, minheight; int maxwidth, maxheight; @@ -390,38 +549,39 @@ struct _GLFWwindow char keys[GLFW_KEY_LAST + 1]; // Virtual cursor position when cursor is disabled double virtualCursorPosX, virtualCursorPosY; + GLFWbool rawMouseMotion; _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 the window API's platform.h - _GLFW_PLATFORM_WINDOW_STATE; + // This is defined in platform.h + GLFW_PLATFORM_WINDOW_STATE }; // Monitor structure // struct _GLFWmonitor { - char* name; + char name[128]; void* userPointer; // Physical dimensions in millimeters. @@ -437,8 +597,8 @@ struct _GLFWmonitor GLFWgammaramp originalRamp; GLFWgammaramp currentRamp; - // This is defined in the window API's platform.h - _GLFW_PLATFORM_MONITOR_STATE; + // This is defined in platform.h + GLFW_PLATFORM_MONITOR_STATE }; // Cursor structure @@ -446,9 +606,8 @@ struct _GLFWmonitor struct _GLFWcursor { _GLFWcursor* next; - - // This is defined in the window API's platform.h - _GLFW_PLATFORM_CURSOR_STATE; + // This is defined in platform.h + GLFW_PLATFORM_CURSOR_STATE }; // Gamepad mapping element structure @@ -475,36 +634,121 @@ struct _GLFWmapping // struct _GLFWjoystick { - GLFWbool present; + GLFWbool allocated; + GLFWbool connected; float* axes; int axisCount; unsigned char* buttons; int buttonCount; unsigned char* hats; int hatCount; - char* name; + char name[128]; void* userPointer; char guid[33]; _GLFWmapping* mapping; - // This is defined in the joystick API's joystick.h - _GLFW_PLATFORM_JOYSTICK_STATE; + // This is defined in platform.h + GLFW_PLATFORM_JOYSTICK_STATE }; // Thread local storage structure // struct _GLFWtls { - // This is defined in the platform's thread.h - _GLFW_PLATFORM_TLS_STATE; + // This is defined in platform.h + GLFW_PLATFORM_TLS_STATE }; // Mutex structure // struct _GLFWmutex { - // This is defined in the platform's thread.h - _GLFW_PLATFORM_MUTEX_STATE; + // 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*); }; // Library global data @@ -512,6 +756,9 @@ struct _GLFWmutex struct _GLFWlibrary { GLFWbool initialized; + GLFWallocator allocator; + + _GLFWplatform platform; struct { _GLFWinitconfig init; @@ -528,6 +775,7 @@ struct _GLFWlibrary _GLFWmonitor** monitors; int monitorCount; + GLFWbool joysticksInitialized; _GLFWjoystick joysticks[GLFW_JOYSTICK_LAST + 1]; _GLFWmapping* mappings; int mappingCount; @@ -538,31 +786,80 @@ struct _GLFWlibrary struct { uint64_t offset; - // This is defined in the platform's time.h - _GLFW_PLATFORM_LIBRARY_TIMER_STATE; + // This is defined in platform.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; -#elif defined(_GLFW_X11) + GLFWbool EXT_metal_surface; GLFWbool KHR_xlib_surface; GLFWbool KHR_xcb_surface; -#elif defined(_GLFW_WAYLAND) GLFWbool KHR_wayland_surface; -#elif defined(_GLFW_MIR) - GLFWbool KHR_mir_surface; -#endif } vk; struct { @@ -570,16 +867,10 @@ struct _GLFWlibrary GLFWjoystickfun joystick; } callbacks; - // 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 - _GLFW_EGL_LIBRARY_CONTEXT_STATE; - // This is defined in osmesa_context.h - _GLFW_OSMESA_LIBRARY_CONTEXT_STATE; + // These are defined in platform.h + GLFW_PLATFORM_LIBRARY_WINDOW_STATE + GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE }; // Global state shared between compilation units of GLFW @@ -591,98 +882,10 @@ extern _GLFWlibrary _glfw; ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -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); -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); -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); - -void _glfwPlatformSetClipboardString(const char* string); -const char* _glfwPlatformGetClipboardString(void); - -int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); -void _glfwPlatformUpdateGamepadGUID(char* guid); - +void _glfwPlatformInitTimer(void); 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 _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); - -void _glfwPlatformPollEvents(void); -void _glfwPlatformWaitEvents(void); -void _glfwPlatformWaitEventsTimeout(double timeout); -void _glfwPlatformPostEmptyEvent(void); - -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); @@ -693,6 +896,10 @@ 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 ////// @@ -713,7 +920,7 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window, - unsigned int codepoint, int mods, GLFWbool plain); + uint32_t 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); @@ -739,6 +946,8 @@ 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, @@ -756,16 +965,45 @@ 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, int buttonCount, int hatCount); 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); -char* _glfw_strdup(const char* source); +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); diff --git a/raylib/external/glfw/src/linux_joystick.c b/raylib/external/glfw/src/linux_joystick.c index 2777d0b..07d41d3 100644 --- a/raylib/external/glfw/src/linux_joystick.c +++ b/raylib/external/glfw/src/linux_joystick.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Linux - www.glfw.org +// GLFW 3.4 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(GLFW_BUILD_LINUX_JOYSTICK) + #include #include #include @@ -104,9 +106,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value) // static void pollAbsState(_GLFWjoystick* js) { - int code; - - for (code = 0; code < ABS_CNT; code++) + for (int code = 0; code < ABS_CNT; code++) { if (js->linjs.absMap[code] < 0) continue; @@ -126,29 +126,24 @@ static void pollAbsState(_GLFWjoystick* js) // static GLFWbool openJoystickDevice(const char* path) { - int jid, code; - char name[256] = ""; - char guid[33] = ""; - char evBits[(EV_CNT + 7) / 8] = {0}; - char keyBits[(KEY_CNT + 7) / 8] = {0}; - char absBits[(ABS_CNT + 7) / 8] = {0}; - int axisCount = 0, buttonCount = 0, hatCount = 0; - struct input_id id; - _GLFWjoystickLinux linjs = {0}; - _GLFWjoystick* js = NULL; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (!_glfw.joysticks[jid].present) + if (!_glfw.joysticks[jid].connected) continue; if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) return GLFW_FALSE; } - linjs.fd = open(path, O_RDONLY | O_NONBLOCK); + _GLFWjoystickLinux linjs = {0}; + linjs.fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); if (linjs.fd == -1) return GLFW_FALSE; + char evBits[(EV_CNT + 7) / 8] = {0}; + char keyBits[(KEY_CNT + 7) / 8] = {0}; + char absBits[(ABS_CNT + 7) / 8] = {0}; + struct input_id id; + if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 || ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 || ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 || @@ -162,15 +157,19 @@ static GLFWbool openJoystickDevice(const char* path) } // Ensure this device supports the events expected of a joystick - if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits)) + if (!isBitSet(EV_ABS, evBits)) { close(linjs.fd); return GLFW_FALSE; } + char name[256] = ""; + if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown", sizeof(name)); + char guid[33] = ""; + // Generate a joystick GUID that matches the SDL 2.0.5+ one if (id.vendor && id.product && id.version) { @@ -189,7 +188,9 @@ static GLFWbool openJoystickDevice(const char* path) name[8], name[9], name[10]); } - for (code = BTN_MISC; code < KEY_CNT; code++) + int axisCount = 0, buttonCount = 0, hatCount = 0; + + for (int code = BTN_MISC; code < KEY_CNT; code++) { if (!isBitSet(code, keyBits)) continue; @@ -198,7 +199,7 @@ static GLFWbool openJoystickDevice(const char* path) buttonCount++; } - for (code = 0; code < ABS_CNT; code++) + for (int code = 0; code < ABS_CNT; code++) { linjs.absMap[code] = -1; if (!isBitSet(code, absBits)) @@ -221,14 +222,15 @@ static GLFWbool openJoystickDevice(const char* path) } } - js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); + _GLFWjoystick* js = + _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount); if (!js) { close(linjs.fd); return GLFW_FALSE; } - strncpy(linjs.path, path, sizeof(linjs.path)); + strncpy(linjs.path, path, sizeof(linjs.path) - 1); memcpy(&js->linjs, &linjs, sizeof(linjs)); pollAbsState(js); @@ -243,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 @@ -262,12 +264,51 @@ static int compareJoysticks(const void* fp, const void* sp) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize joystick interface -// +void _glfwDetectJoystickConnectionLinux(void) +{ + if (_glfw.linjs.inotify <= 0) + return; + + ssize_t offset = 0; + char buffer[16384]; + const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + offset += sizeof(struct inotify_event) + e->len; + + if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0) + continue; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + + if (e->mask & (IN_CREATE | IN_ATTRIB)) + openJoystickDevice(path); + else if (e->mask & IN_DELETE) + { + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + { + if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) + { + closeJoystick(_glfw.joysticks + jid); + break; + } + } + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + GLFWbool _glfwInitJoysticksLinux(void) { - DIR* dir; - int count = 0; const char* dirname = "/dev/input"; _glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); @@ -283,13 +324,16 @@ GLFWbool _glfwInitJoysticksLinux(void) // Continue without device connection notifications if inotify fails - if (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) != 0) + _glfw.linjs.regexCompiled = (regcomp(&_glfw.linjs.regex, "^event[0-9]\\+$", 0) == 0); + if (!_glfw.linjs.regexCompiled) { _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); return GLFW_FALSE; } - dir = opendir(dirname); + int count = 0; + + DIR* dir = opendir(dirname); if (dir) { struct dirent* entry; @@ -318,21 +362,15 @@ GLFWbool _glfwInitJoysticksLinux(void) return GLFW_TRUE; } -// Close all opened joystick handles -// void _glfwTerminateJoysticksLinux(void) { - int jid; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) + for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + if (js->connected) closeJoystick(js); } - regfree(&_glfw.linjs.regex); - if (_glfw.linjs.inotify > 0) { if (_glfw.linjs.watch > 0) @@ -340,55 +378,12 @@ void _glfwTerminateJoysticksLinux(void) close(_glfw.linjs.inotify); } + + if (_glfw.linjs.regexCompiled) + regfree(&_glfw.linjs.regex); } -void _glfwDetectJoystickConnectionLinux(void) -{ - ssize_t offset = 0; - char buffer[16384]; - - if (_glfw.linjs.inotify <= 0) - return; - - const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer)); - - while (size > offset) - { - regmatch_t match; - const struct inotify_event* e = (struct inotify_event*) (buffer + offset); - - offset += sizeof(struct inotify_event) + e->len; - - if (regexec(&_glfw.linjs.regex, e->name, 1, &match, 0) != 0) - continue; - - char path[PATH_MAX]; - snprintf(path, sizeof(path), "/dev/input/%s", e->name); - - if (e->mask & (IN_CREATE | IN_ATTRIB)) - openJoystickDevice(path); - else if (e->mask & IN_DELETE) - { - int jid; - - for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) - { - if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0) - { - closeJoystick(_glfw.joysticks + jid); - break; - } - } - } - } -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode) { // Read all queued events (non-blocking) for (;;) @@ -425,10 +420,17 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) handleAbsEvent(js, e.code, e.value); } - return js->present; + return js->connected; } -void _glfwPlatformUpdateGamepadGUID(char* guid) +const char* _glfwGetMappingNameLinux(void) +{ + return "Linux"; +} + +void _glfwUpdateGamepadGUIDLinux(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 2eabfa1..64462b0 100644 --- a/raylib/external/glfw/src/linux_joystick.h +++ b/raylib/external/glfw/src/linux_joystick.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 Linux - www.glfw.org +// GLFW 3.4 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // @@ -28,10 +28,8 @@ #include #include -#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickLinux linjs -#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs - -#define _GLFW_PLATFORM_MAPPING_NAME "Linux" +#define GLFW_LINUX_JOYSTICK_STATE _GLFWjoystickLinux linjs; +#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs; // Linux-specific joystick data // @@ -52,11 +50,15 @@ typedef struct _GLFWlibraryLinux int inotify; int watch; regex_t regex; + GLFWbool regexCompiled; GLFWbool dropped; } _GLFWlibraryLinux; +void _glfwDetectJoystickConnectionLinux(void); GLFWbool _glfwInitJoysticksLinux(void); void _glfwTerminateJoysticksLinux(void); -void _glfwDetectJoystickConnectionLinux(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 97073db..7b0f35a 100644 --- a/raylib/external/glfw/src/mappings.h +++ b/raylib/external/glfw/src/mappings.h @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -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 GenerateMappings.cmake script. +// gamecontrollerdb.txt with the 'update_mappings' CMake target. //======================================================================== // All gamepad mappings not labeled GLFW are copied from the @@ -60,96 +60,262 @@ 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,", +"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,", "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,", +"03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,", "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,", +"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,", +"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,", -"030000008f0e00001200000000000000,Acme,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,", +"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,", +"030000006f0e00000263000000000000,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,", +"030000006f0e00001101000000000000,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,", +"030000006f0e00001401000000000000,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,", +"030000006f0e00001402000000000000,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,", +"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,", +"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,", -"030000006b1400000055000000000000,bigben ps3padstreetnew,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,", +"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,", +"03000000d62000002a79000000000000,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:Windows,", +"03000000bc2000006012000000000000,Betop 2126F,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,", +"03000000bc2000000055000000000000,Betop BFM Gamepad,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,", +"03000000bc2000006312000000000000,Betop 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:Windows,", +"03000000bc2000006321000000000000,BETOP 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:Windows,", +"03000000bc2000006412000000000000,Betop 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:Windows,", +"03000000c01100000555000000000000,Betop 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:Windows,", +"03000000c01100000655000000000000,Betop 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:Windows,", +"03000000790000000700000000000000,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,", +"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,", -"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"03000000457500000401000000000000,Cobra,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:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),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,", +"030000005e040000a102000000000000,Controller (Xbox 360 Wireless Receiver for Windows),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,", +"030000005e040000ff02000000000000,Controller (Xbox One For Windows) - Wired,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,", +"030000005e040000ea02000000000000,Controller (Xbox One For Windows) - Wireless,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,", "03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,", "03000000a306000022f6000000000000,Cyborg V.3 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:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"03000000451300000830000000000000,Defender Game Racer X7,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,", +"030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,", "03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", -"030000004f04000023b3000000000000,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:Windows,", +"03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,", +"030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,", +"030000006f0e00003001000000000000,EA SPORTS 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,", +"03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,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:b1,platform:Windows,", +"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,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:b1,platform:Windows,", +"03000000120c0000f61c000000000000,Elite,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,", +"030000008f0e00000f31000000000000,EXEQ,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:b3,y:b2,platform:Windows,", "03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,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,", +"030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,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,", +"03000000852100000201000000000000,FF-GP1,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,", "030000000d0f00008500000000000000,Fighting Commander 2016 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:Windows,", "030000000d0f00008400000000000000,Fighting Commander 5,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:a5,start:b9,x:b0,y:b3,platform:Windows,", -"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", "030000000d0f00008700000000000000,Fighting Stick mini 4,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,", +"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,", "030000000d0f00002700000000000000,FIGHTING STICK V3,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,", "78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,", -"03000000790000000600000000000000,G-Shark GS-GP702,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,", +"03000000790000002201000000000000,Game Controller for PC,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,", +"0300000066f700000100000000000000,Game VIB Joystick,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,", "03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,", +"03000000790000004618000000000000,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:Windows,", "030000008f0e00000d31000000000000,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:Windows,", "03000000280400000140000000000000,GamePad Pro USB,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:Windows,", +"03000000ac0500003d03000000000000,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,", +"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,", -"03000000451300000010000000000000,Generic USB Joystick,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,", +"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,", +"030000008305000031b0000000000000,Genius Maxfire Blaze 3,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,", +"03000000451300000010000000000000,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:Windows,", +"030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,", +"03000000300f00000b01000000000000,GGE909 Recoil Pad,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:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000f0250000c283000000000000,Gioteck,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,", +"03000000f025000021c1000000000000,Gioteck 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:Windows,", +"03000000f0250000c383000000000000,Gioteck VX2 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:Windows,", +"03000000f0250000c483000000000000,Gioteck VX2 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:Windows,", +"030000007d0400000540000000000000,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:Windows,", "03000000341a00000302000000000000,Hama Scorpad,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,", "030000000d0f00004900000000000000,Hatsune Miku Sho 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,", +"030000001008000001e1000000000000,Havit HV-G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,", "03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"03000000632500002605000000000000,HJD-X,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,", +"030000000d0f00002d00000000000000,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:Windows,", "030000000d0f00005f00000000000000,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:Windows,", "030000000d0f00005e00000000000000,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:Windows,", "030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005400000000000000,Hori Pad 3,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,", +"030000000d0f00000900000000000000,Hori Pad 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:Windows,", +"030000000d0f00004d00000000000000,Hori Pad A,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,", +"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,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:Windows,", +"030000000d0f00001600000000007803,HORI Real Arcade Pro EX-SE (Xbox 360),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,", +"030000000d0f00009c00000000000000,Hori TAC Pro,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,", +"030000000d0f0000c100000000000000,Horipad,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,", "030000000d0f00006e00000000000000,HORIPAD 4 (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:Windows,", "030000000d0f00006600000000000000,HORIPAD 4 (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:Windows,", +"030000000d0f00005500000000000000,Horipad 4 FPS,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,", "030000000d0f0000ee00000000000000,HORIPAD mini4,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:a5,start:b9,x:b0,y:b3,platform:Windows,", -"030000000d0f00004d00000000000000,HORIPAD3 A,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,", "03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,", "030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,", "03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", "03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", "03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows,", -"03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,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,", -"030000006f0e00002401000000000000,INJUSTICE FightStick for 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,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", +"03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,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,", +"030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,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,", +"03000000ac0500002c02000000000000,IPEGA,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", "03000000491900000204000000000000,Ipega PG-9023,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,", +"03000000491900000304000000000000,Ipega PG-9087 - Bluetooth Gamepad,+righty:+a5,-righty:-a4,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,start:b11,x:b3,y:b4,platform:Windows,", +"030000006e0500000a20000000000000,JC-DUX60 ELECOM MMO Gamepad,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,", +"030000006e0500000520000000000000,JC-P301U,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:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,", +"030000006e0500000320000000000000,JC-U3613M (DInput),a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,", +"030000006e0500000720000000000000,JC-W01U,a:b2,b:b3,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,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,", +"030000007e0500000620000000000000,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,", +"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,", +"03000000790000000200000000000000,King 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:a4,start:b9,x:b3,y:b0,platform:Windows,", +"030000006d040000d1ca000000000000,Logitech ChillStream,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,", +"030000006d040000d2ca000000000000,Logitech Cordless Precision,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,", "030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,", "030000006d04000016c2000000000000,Logitech Dual Action,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,", "030000006d04000018c2000000000000,Logitech F510 Gamepad,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,", "030000006d04000019c2000000000000,Logitech F710 Gamepad,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,", +"030000006d0400001ac2000000000000,Logitech Precision Gamepad,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:Windows,", +"030000006d0400000ac2000000000000,Logitech 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:Windows,", +"03000000380700006652000000000000,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700005032000000000000,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:Windows,", "03000000380700005082000000000000,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:Windows,", -"03000000380700008433000000000000,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,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", -"03000000380700008483000000000000,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:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700008433000000000000,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:Windows,", +"03000000380700008483000000000000,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:Windows,", "03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000380700006252000000000000,Mad Catz Micro 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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,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:Windows,", "03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,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:Windows,", "03000000380700008532000000000000,Madcatz Arcade 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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "03000000380700003888000000000000,Madcatz Arcade 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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", "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,", -"030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,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:a2,righty:a3,start:b9,x:b2,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,", +"03000000242f00007300000000000000,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:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", +"0300000079000000d218000000000000,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:Windows,", +"03000000d620000010a7000000000000,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:Windows,", "030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,", "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:Windows,", "03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),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,", -"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,", +"03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,", +"03000000380700006382000000000000,MLG GamePad 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,", +"03000000c62400002a89000000000000,MOGA XP5-A Plus,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:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"03000000c62400002b89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"03000000c62400001a89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"03000000c62400001b89000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"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,", +"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,", -"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,leftx:h0.6,lefty:h0.12,rightshoulder:b5,rightstick:a2,righttrigger:b7,rightx:h0.9,righty:h0.4,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,", "03000000362800000100000000000000,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:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,", "03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,", +"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,", -"030000008f0e00007530000000000000,PS (R) Gamepad,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:b1,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,", +"03000000d6200000c757000000000000,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,", +"03000000632500002306000000000000,PS Controller,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:Windows,", "03000000e30500009605000000000000,PS to USB convert cable,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,", -"03000000100800000100000000000000,PS1 USB,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,", -"03000000100800000300000000000000,PS2 USB,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000100800000100000000000000,PS1 Controller,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,", +"030000008f0e00007530000000000000,PS1 Controller,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:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,", +"03000000100800000300000000000000,PS2 Controller,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000250900008888000000000000,PS2 Controller,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,", +"03000000666600006706000000000000,PS2 Controller,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:Windows,", +"030000006b1400000303000000000000,PS2 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,", +"030000009d0d00001330000000000000,PS2 Controller,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:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,", +"03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,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:b0,y:b3,platform:Windows,", +"030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,", +"03000000632500007505000000000000,PS3 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,", "03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,", -"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:Windows,", -"03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,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:b0,y:b3,platform:Windows,", +"030000008f0e00001431000000000000,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,", +"030000003807000056a8000000000000,PS3 RF 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,", "03000000100000008200000000000000,PS360+ v1.66,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:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,", "030000004c050000a00b000000000000,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,", "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,", @@ -158,314 +324,101 @@ const char* _glfwDefaultMappings[] = "03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,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,", "03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,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:Windows,", "03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", +"03000000321500000204000000000000,Razer Panthera (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:Windows,", +"03000000321500000104000000000000,Razer Panthera (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:Windows,", +"03000000321500000507000000000000,Razer Raiju Mobile,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,", +"03000000321500000707000000000000,Razer Raiju Mobile,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,", +"03000000321500000011000000000000,Razer Raion Fightpad 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", +"03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,", "030000000d0f00001100000000000000,REAL ARCADE PRO.3,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:Windows,", -"030000000d0f00008b00000000000000,Real Arcade Pro.4,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,", -"030000000d0f00008a00000000000000,Real Arcade Pro.4,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,", -"030000000d0f00006b00000000000000,Real Arcade Pro.4,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,", "030000000d0f00006a00000000000000,Real Arcade Pro.4,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,", +"030000000d0f00006b00000000000000,Real Arcade Pro.4,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,", +"030000000d0f00008a00000000000000,Real Arcade Pro.4,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,", +"030000000d0f00008b00000000000000,Real Arcade Pro.4,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,", "030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,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:Windows,", "030000000d0f00002200000000000000,REAL ARCADE Pro.V3,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:Windows,", -"030000000d0f00005c00000000000000,Real Arcade Pro.V4,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,", "030000000d0f00005b00000000000000,Real Arcade Pro.V4,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:a5,start:b9,x:b0,y:b3,platform:Windows,", +"030000000d0f00005c00000000000000,Real Arcade Pro.V4,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,", "03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,", +"03000000bd12000013d0000000000000,Retrolink USB SEGA Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,", "0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", "0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,", "030000006b140000010d000000000000,Revolution Pro 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,", -"030000006f0e00001e01000000000000,Rock Candy Gamepad for 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:Windows,", +"030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),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,", +"030000006b140000130d000000000000,Revolution Pro Controller 3,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,", +"030000006f0e00001e01000000000000,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:Windows,", +"030000006f0e00002801000000000000,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:Windows,", +"030000006f0e00002f01000000000000,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:Windows,", "030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,", "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,", -"03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,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,", +"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,", "03000000a30600000b04000000000000,Saitek P990,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,", "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:Windows,", -"03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,", +"03000000a30600002106000000000000,Saitek PS1000,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,", +"03000000a306000020f6000000000000,Saitek PS2700,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,", +"03000000300f00001101000000000000,Saitek Rumble Pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,", +"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,", "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,", -"030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,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,", +"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,", +"03000000c01100000591000000000000,Speedlink Torid,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,", +"03000000d11800000094000000000000,Stadia 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:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,", +"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,", +"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,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:b3,y:b4,platform:Windows,", +"03000000110100003114000000000000,SteelSeries Stratus Duo,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,", +"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,", +"03000000790000001c18000000000000,STK-7024X,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,", "03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,", +"03000000d620000011a7000000000000,Switch,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,", +"03000000457500002211000000000000,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:Windows,", +"030000004f04000007d0000000000000,T Mini Wireless,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,", +"030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,", "03000000fa1900000706000000000000,Team 5,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,", "03000000b50700001203000000000000,Techmobility X6-38V,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,", -"030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,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:Windows,", +"030000004f04000015b3000000000000,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:Windows,", +"030000004f04000023b3000000000000,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:Windows,", +"030000004f0400000ed0000000000000,ThrustMaster eSwap PRO 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,", "030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,", "030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,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:Windows,", "03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,", +"03000000d62000006000000000000000,Tournament 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,", +"030000005f140000c501000000000000,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:Windows,", +"03000000b80500000210000000000000,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:Windows,", +"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,", "03000000d90400000200000000000000,TwinShock PS2,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,", -"03000000380700006652000000000000,UnKnown,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:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,", +"030000006e0500001320000000000000,U4113,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,", +"03000000101c0000171c000000000000,uRage 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:Windows,", +"03000000300f00000701000000000000,USB 4-Axis 12-Button 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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", +"03000000341a00002308000000000000,USB gamepad,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,", +"030000005509000000b4000000000000,USB gamepad,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,platform:Windows,", +"030000006b1400000203000000000000,USB gamepad,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,", +"03000000790000000a00000000000000,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:a4,start:b9,x:b3,y:b0,platform:Windows,", +"03000000f0250000c183000000000000,USB 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:Windows,", +"03000000ff1100004133000000000000,USB gamepad,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:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,", "03000000632500002305000000000000,USB Vibration Joystick (BM),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,", +"03000000790000001a18000000000000,Venom,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,", "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,", +"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,", +"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,", "03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,", "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,", -"03000000203800000900000000010000,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,", -"03000000022000000090000001000000,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,", -"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,", -"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,", -"03000000790000000600000000000000,G-Shark GP-702,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: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,", -"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,", -"030000000d0f00005f00000000000000,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,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,", -"030000000d0f00005e00000000000000,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,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,", -"030000000d0f00004d00000000000000,HORI Gem Pad 3,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,", -"030000000d0f00006e00000000010000,HORIPAD 4 (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,", -"030000000d0f00006600000000010000,HORIPAD 4 (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,", -"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", -"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,", -"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", -"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", -"030000006d04000016c2000000020000,Logitech Dual Action,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,", -"030000006d04000016c2000000030000,Logitech Dual Action,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,", -"030000006d04000016c2000014040000,Logitech Dual Action,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,", -"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),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,", -"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),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,", -"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),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,", -"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),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,", -"03000000380700005032000000010000,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:Mac OS X,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"030000004c050000cc09000000010000,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,", -"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:Mac OS X,", -"030000004c050000c405000000010000,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,", -"030000008916000000fd000000000000,Razer Onza TE,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,", -"03000000321500000010000000010000,Razer RAIJU,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,", -"0300000032150000030a000000000000,Razer Wildcat,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,", -"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"030000006b140000010d000000010000,Revolution Pro 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,", -"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,", -"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,", -"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,", -"030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,", -"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,", -"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,", -"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,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:Mac OS X,", -"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,", -"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", -"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,", -"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,", -"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,", -"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,", -"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,", -"030000005e040000e002000000000000,Xbox Wireless 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:Mac OS X,", -"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,", -"030000005e040000ea02000000000000,Xbox Wireless 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,", -"030000005e040000e002000003090000,Xbox Wireless 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:Mac OS X,", -"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,", -"05000000203800000900000000010000,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:Linux,", -"03000000022000000090000011010000,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:Linux,", -"05000000c82d00002038000000010000,8Bitdo NES30 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", -"03000000c82d00000190000011010000,8Bitdo NES30 Pro 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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", -"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", -"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,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,", -"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,", -"030000006f0e00003901000020060000,Afterglow 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,", -"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,", -"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,", -"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,", -"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,", -"03000000260900008888000000010000,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:Linux,", -"03000000a306000022f6000011010000,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:Linux,", -"03000000b40400000a01000000010000,CYPRESS 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:Linux,", -"03000000790000000600000010010000,DragonRise Inc. Generic 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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,", -"030000006f0e00003001000001010000,EA Sports 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,", -"03000000341a000005f7000010010000,GameCube {HuiJia USB box},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,", -"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:Linux,", -"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,", -"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:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", -"030000006f0e00001f01000000010000,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,", -"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,", -"03000000280400000140000000010000,Gravis GamePad Pro USB ,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,", -"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,", -"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,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:Linux,", -"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,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:Linux,", -"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,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:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", -"06000000adde0000efbe000002010000,Hidromancer 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:b2,y:b3,platform:Linux,", -"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,", -"03000000c9110000f055000011010000,HJC Game 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:Linux,", -"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,", -"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,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,", -"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,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,", -"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,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,", -"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,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,", -"030000000d0f00005f00000011010000,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:Linux,", -"030000000d0f00005e00000011010000,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:Linux,", -"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,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,", -"030000000d0f00006e00000011010000,HORIPAD 4 (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,", -"030000000d0f00006600000011010000,HORIPAD 4 (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,", -"030000000d0f00006700000001010000,HORIPAD 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,", -"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,", -"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,", -"050000006964726f69643a636f6e0000,idroid:con,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,", -"03000000b50700001503000010010000,impact,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,", -"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,", -"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,", -"03000000300f00001001000010010000,Jess Tech Dual Analog 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:Linux,", -"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,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,rightx:a3,righty:a2,start:b9,x:b3,y:b0,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,", -"030000006d04000019c2000010010000,Logitech Cordless 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,", -"030000006d04000016c2000011010000,Logitech Dual Action,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,", -"030000006d04000016c2000010010000,Logitech Dual Action,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,", -"030000006d0400001dc2000014400000,Logitech F310 Gamepad (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,", -"030000006d0400001ec2000020200000,Logitech F510 Gamepad (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,", -"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),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,", -"030000006d0400001fc2000005030000,Logitech F710 Gamepad (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,", -"030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,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,", -"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,", -"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,", -"03000000380700008034000011010000,Mad Catz fightstick (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:Linux,", -"03000000380700008084000011010000,Mad Catz fightstick (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:Linux,", -"03000000380700008433000011010000,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,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,", -"03000000380700008483000011010000,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,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", -"03000000380700001647000010040000,Mad Catz Wired 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,", -"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", -"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,", -"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,", -"03000000780000000600000010010000,Microntek USB Joystick,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,", -"030000005e0400008e02000004010000,Microsoft X-Box 360 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,", -"030000005e0400008e02000062230000,Microsoft X-Box 360 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,", -"030000005e040000d102000001010000,Microsoft X-Box One 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,", -"030000005e040000d102000003020000,Microsoft X-Box One pad v2,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,", -"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),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,", -"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),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,", -"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,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:b6,x:b2,y:b3,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,", -"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,", -"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,", -"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", -"03000000451300000830000010010000,NYKO CORE,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:a5,start:b9,x:b0,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,", -"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,", -"03000000ff1100003133000010010000,PC Game 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,", -"030000006f0e00006401000001010000,PDP Battlefield 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,", -"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,", -"030000004c0500006802000010010000,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,", -"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,", -"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,", -"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,", -"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,", -"030000004c0500006802000010810000,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,", -"030000004c0500006802000011010000,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,", -"060000004c0500006802000000010000,PS3 Controller (Bluetooth),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,", -"05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),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,", -"050000004c050000c405000000010000,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:Linux,", -"030000004c050000a00b000011010000,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:Linux,", -"050000004c050000cc09000000810000,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,", -"050000004c050000c405000000810000,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,", -"030000004c050000c405000011810000,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,", -"050000004c050000cc09000000010000,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:Linux,", -"030000004c050000cc09000011010000,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:Linux,", -"030000004c050000a00b000011810000,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,", -"030000004c050000cc09000011810000,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,", -"030000004c050000c405000011010000,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: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,", -"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,", -"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", -"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", -"03000000321500000010000011010000,Razer RAIJU,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,", -"03000000c6240000045d000025010000,Razer Sabertooth,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,", -"03000000321500000009000011010000,Razer Serval,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,", -"050000003215000000090000163a0000,Razer Serval,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,", -"0300000032150000030a000001010000,Razer Wildcat,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,", -"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", -"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", -"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", -"030000006b140000010d000011010000,Revolution Pro 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:Linux,", -"030000006f0e00001e01000011010000,Rock Candy Gamepad for 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,", -"030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,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,", -"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,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,", -"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,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,x:b0,y:b1,platform:Linux,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"03000000de280000fc11000001000000,Steam 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,", -"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,", -"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,", -"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,", -"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,", -"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,", -"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,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,", -"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless 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,", -"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", -"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,", -"03000000100800000100000010010000,Twin USB PS2 Adapter,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:Linux,", -"03000000100800000300000010010000,USB Gamepad,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:Linux,", -"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,", -"05000000ac0500003232000001000000,VR-BOX,a:b0,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:b2,y:b3,platform:Linux,", -"030000005e0400008e02000014010000,X360 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,", -"030000005e0400008e02000010010000,X360 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,", -"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", -"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", -"030000005e040000a102000007010000,X360 Wireless 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,", -"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", -"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,", -"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),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,", -"050000005e040000e002000003090000,Xbox One Wireless 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:Linux,", -"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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,", -"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,", -"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", -"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,", - +"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,", @@ -473,6 +426,577 @@ const char* _glfwDefaultMappings[] = "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 +#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,", +"03000000c82d00000650000001000000,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:Mac OS X,", +"03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,", +"03000000c82d00001590000001000000,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: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,", +"03000000c82d00006528000000010000,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: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,", +"030000003512000012ab000001000000,8BitDo NES30 Gamepad,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:Mac OS X,", +"03000000022000000090000001000000,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,", +"03000000203800000900000000010000,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,", +"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,", +"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,", +"030000000d0f00005f00000000000000,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,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,", +"030000000d0f00005e00000000000000,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,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,", +"030000000d0f00004d00000000000000,HORI Gem Pad 3,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,", +"030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,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,", +"030000000d0f00006e00000000010000,HORIPAD 4 (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,", +"030000000d0f00006600000000010000,HORIPAD 4 (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,", +"030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,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:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000000d0f0000ee00000000010000,HORIPAD mini4,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:a5,start:b9,x:b0,y:b3,platform:Mac OS X,", +"030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,", +"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", +"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,", +"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:Mac OS X,", +"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:Mac OS X,", +"03000000242f00002d00000007010000,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:Mac OS X,", +"030000006d04000016c2000000020000,Logitech Dual Action,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,", +"030000006d04000016c2000000030000,Logitech Dual Action,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,", +"030000006d04000016c2000014040000,Logitech Dual Action,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,", +"030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),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,", +"030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),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,", +"030000006d04000019c2000005030000,Logitech F710,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,", +"030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),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,", +"030000006d04000018c2000000010000,Logitech RumblePad 2 USB,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,", +"030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),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,", +"03000000380700005032000000010000,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:Mac OS X,", +"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,", +"03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Mac OS X,", +"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,", +"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,", +"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:Mac OS X,", +"030000004c050000c405000000010000,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,", +"030000004c050000cc09000000010000,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,", +"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:Mac OS X,", +"030000008916000000fd000000000000,Razer Onza TE,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,", +"03000000321500000204000000010000,Razer Panthera (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,", +"03000000321500000104000000010000,Razer Panthera (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,", +"03000000321500000010000000010000,Razer RAIJU,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,", +"03000000321500000507000001010000,Razer Raiju Mobile,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,", +"03000000321500000011000000010000,Razer Raion Fightpad 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: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,", +"03000000321500000009000000020000,Razer Serval,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,", +"030000003215000000090000163a0000,Razer Serval,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,", +"0300000032150000030a000000000000,Razer Wildcat,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,", +"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"030000006b140000010d000000010000,Revolution Pro 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,", +"030000006b140000130d000000010000,Revolution Pro Controller 3,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,", +"03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,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,", +"03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,", +"03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,", +"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,", +"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,", +"030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,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,", +"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,", +"030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,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:Mac OS X,", +"030000004f0400000ed0000000020000,ThrustMaster eSwap PRO 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,", +"030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,", +"03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,", +"03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,", +"030000006f0e00000302000025040000,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:Mac OS X,", +"030000006f0e00000702000003060000,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:Mac OS X,", +"03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,", +"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,", +"030000005e040000130b000001050000,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:Mac OS X,", +"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:Mac OS X,", +"030000005e040000e002000000000000,Xbox Wireless 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:Mac OS X,", +"030000005e040000e002000003090000,Xbox Wireless 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:Mac OS X,", +"030000005e040000ea02000000000000,Xbox Wireless 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,", +"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,", +"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,", +"03000000c82d00001590000011010000,8BitDo N30 Pro 2,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,", +"05000000c82d00006528000000010000,8BitDo N30 Pro 2,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,", +"03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,", +"05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,", +"03000000022000000090000011010000,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:Linux,", +"05000000203800000900000000010000,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:Linux,", +"05000000c82d00002038000000010000,8Bitdo NES30 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00000190000011010000,8Bitdo NES30 Pro 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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"05000000c82d00000060000000010000,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:Linux,", +"05000000c82d00000061000000010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", +"030000003512000012ab000010010000,8Bitdo SFC30 GamePad,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,", +"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", +"05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00000160000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00000160000011010000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00000161000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,", +"03000000c82d00001290000011010000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,", +"05000000c82d00000161000000010000,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:Linux,", +"05000000c82d00006228000000010000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,", +"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,", +"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,", +"030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,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,", +"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,", +"03000000260900008888000000010000,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:Linux,", +"03000000a306000022f6000011010000,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:Linux,", +"03000000b40400000a01000000010000,CYPRESS 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:Linux,", +"03000000790000000600000010010000,DragonRise Inc. Generic 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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,", +"030000004f04000004b3000010010000,Dual Power 2,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,", +"030000006f0e00003001000001010000,EA Sports 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,", +"03000000341a000005f7000010010000,GameCube {HuiJia USB box},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,", +"03000000bc2000000055000011010000,GameSir G3w,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,", +"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:Linux,", +"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,", +"03000000280400000140000000010000,Gravis GamePad Pro USB ,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,", +"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,", +"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,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:Linux,", +"0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,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:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"03000000f0250000c383000010010000,GT VX2,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,", +"06000000adde0000efbe000002010000,Hidromancer 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:b2,y:b3,platform:Linux,", +"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,", +"03000000c9110000f055000011010000,HJC Game 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:Linux,", +"03000000632500002605000010010000,HJD-X,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,", +"030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,", +"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,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,", +"030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,", +"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,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,", +"030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,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,", +"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,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,", +"030000000d0f00008500000010010000,HORI Fighting Commander,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,", +"030000000d0f00008600000002010000,Hori Fighting Commander,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,", +"030000000d0f00005f00000011010000,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:Linux,", +"030000000d0f00005e00000011010000,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:Linux,", +"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,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,", +"030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,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:Linux,", +"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,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,", +"030000000d0f0000d800000072056800,HORI Real Arcade Pro S,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:Linux,", +"030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,", +"030000000d0f00006e00000011010000,HORIPAD 4 (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,", +"030000000d0f00006600000011010000,HORIPAD 4 (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,", +"030000000d0f0000ee00000011010000,HORIPAD mini4,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:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000000d0f00006700000001010000,HORIPAD 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,", +"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,", +"03000000242e00008816000001010000,Hyperkin X91,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,", +"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,", +"050000006964726f69643a636f6e0000,idroid:con,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,", +"03000000b50700001503000010010000,impact,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,", +"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,", +"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,", +"0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,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,", +"03000000632500007505000011010000,Ipega PG-9099 - Bluetooth 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,", +"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,", +"03000000300f00001001000010010000,Jess Tech Dual Analog 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:Linux,", +"03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,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:a2,start:b9,x:b3,y:b0,platform:Linux,", +"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,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,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,", +"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:Linux,", +"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,", +"030000006d040000d1ca000000000000,Logitech ChillStream,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,", +"030000006d04000019c2000010010000,Logitech Cordless 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,", +"030000006d04000016c2000010010000,Logitech Dual Action,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,", +"030000006d04000016c2000011010000,Logitech Dual Action,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,", +"030000006d0400001dc2000014400000,Logitech F310 Gamepad (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,", +"030000006d0400001ec2000019200000,Logitech F510 Gamepad (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,", +"030000006d0400001ec2000020200000,Logitech F510 Gamepad (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,", +"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),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,", +"030000006d0400001fc2000005030000,Logitech F710 Gamepad (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,", +"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,", +"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,", +"03000000380700008034000011010000,Mad Catz fightstick (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:Linux,", +"03000000380700008084000011010000,Mad Catz fightstick (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:Linux,", +"03000000380700008433000011010000,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:Linux,", +"03000000380700008483000011010000,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:Linux,", +"03000000380700001647000010040000,Mad Catz Wired 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,", +"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,", +"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,", +"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,", +"03000000d620000010a7000011010000,Mayflash Magic NS,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,", +"0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,", +"03000000780000000600000010010000,Microntek USB Joystick,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,", +"030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,", +"030000005e0400008e02000004010000,Microsoft X-Box 360 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,", +"030000005e0400008e02000062230000,Microsoft X-Box 360 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,", +"050000005e040000050b000003090000,Microsoft X-Box One Elite 2 pad,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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:Linux,", +"030000005e040000e302000003020000,Microsoft X-Box One Elite 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,", +"030000005e040000d102000001010000,Microsoft X-Box One 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,", +"030000005e040000dd02000003020000,Microsoft X-Box One pad (Firmware 2015),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,", +"030000005e040000d102000003020000,Microsoft X-Box One pad v2,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,", +"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),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,", +"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),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,", +"030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,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,", +"030000005e040000ea02000008040000,Microsoft Xbox One S pad - Wired,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,", +"03000000c62400001a53000000010000,Mini PE,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,", +"03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,", +"05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,", +"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,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:b6,x:b2,y:b3,platform:Linux,", +"05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,", +"03000000c62400002b89000011010000,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:Linux,", +"05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,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,", +"05000000c62400001a89000000010000,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,", +"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,", +"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,", +"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,", +"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,", +"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,", +"03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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:Linux,", +"05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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:Linux,", +"03000000451300000830000010010000,NYKO CORE,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:a5,start:b9,x:b0,y:b3,platform:Linux,", +"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,", +"03000000790000001c18000011010000,PC Game 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,", +"03000000ff1100003133000010010000,PC Game 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,", +"030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One 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,", +"030000006f0e0000b802000013020000,PDP AFTERGLOW Wired Xbox One 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,", +"030000006f0e00006401000001010000,PDP Battlefield 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,", +"030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,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,", +"030000006f0e00003101000000010000,PDP EA Sports 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,", +"030000006f0e0000c802000012010000,PDP Kingdom Hearts 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,", +"030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,", +"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,", +"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,", +"030000004c0500006802000010010000,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,", +"030000004c0500006802000010810000,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,", +"030000004c0500006802000011010000,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,", +"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,", +"05000000504c415953544154494f4e00,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,", +"060000004c0500006802000000010000,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,", +"030000004c050000a00b000011010000,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:Linux,", +"030000004c050000a00b000011810000,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,", +"030000004c050000c405000011010000,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:Linux,", +"030000004c050000c405000011810000,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,", +"030000004c050000cc09000000010000,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:Linux,", +"030000004c050000cc09000011010000,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:Linux,", +"030000004c050000cc09000011810000,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,", +"03000000c01100000140000011010000,PS4 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:a5,start:b9,x:b0,y:b3,platform:Linux,", +"050000004c050000c405000000010000,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:Linux,", +"050000004c050000c405000000810000,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,", +"050000004c050000c405000001800000,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,", +"050000004c050000cc09000000010000,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:Linux,", +"050000004c050000cc09000000810000,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,", +"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,", +"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", +"030000008916000000fd000024010000,Razer Onza Tournament Edition,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,", +"03000000321500000204000011010000,Razer Panthera (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,", +"03000000321500000104000011010000,Razer Panthera (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,", +"03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,", +"03000000321500000010000011010000,Razer RAIJU,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,", +"03000000321500000507000000010000,Razer Raiju Mobile,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:Linux,", +"03000000321500000011000011010000,Razer Raion Fightpad 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,", +"030000008916000000fe000024010000,Razer Sabertooth,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,", +"03000000c6240000045d000024010000,Razer Sabertooth,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,", +"03000000c6240000045d000025010000,Razer Sabertooth,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,", +"03000000321500000009000011010000,Razer Serval,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,", +"050000003215000000090000163a0000,Razer Serval,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,", +"0300000032150000030a000001010000,Razer Wildcat,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,", +"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", +"0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,", +"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,", +"030000006b140000010d000011010000,Revolution Pro 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:Linux,", +"030000006b140000130d000011010000,Revolution Pro Controller 3,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,", +"030000006f0e00001f01000000010000,Rock Candy,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,", +"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,", +"03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,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,x:b0,y:b1,platform:Linux,", +"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,", +"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,", +"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,", +"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,", +"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,", +"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,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,", +"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,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,", +"03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,", +"030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,", +"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,", +"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,", +"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO 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:Linux,", +"03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,", +"030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,", +"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,", +"030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,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,", +"03000000c6240000025b000002020000,Thrustmaster GPX 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,", +"030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,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,", +"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless 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,", +"030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,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,", +"030000004f04000012b3000010010000,Thrustmaster vibrating gamepad,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,", +"03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,", +"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,", +"030000005e0400008e02000070050000,Torid,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,", +"03000000c01100000591000011010000,Torid,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,", +"03000000100800000100000010010000,Twin USB PS2 Adapter,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:Linux,", +"03000000100800000300000010010000,USB Gamepad,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:Linux,", +"03000000790000000600000007010000,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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,", +"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,", +"030000006f0e00000302000011010000,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:Linux,", +"030000006f0e00000702000011010000,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:Linux,", +"05000000ac0500003232000001000000,VR-BOX,a:b0,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:b2,y:b3,platform:Linux,", +"03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,", +"050000000d0f0000f600000001000000,Wireless HORIPAD 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,", +"030000005e0400008e02000010010000,X360 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,", +"030000005e0400008e02000014010000,X360 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,", +"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", +"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", +"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", +"030000005e040000a102000007010000,X360 Wireless 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,", +"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,", +"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,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,", +"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),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,", +"030000005e040000d102000002010000,Xbox One 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,", +"050000005e040000fd02000030110000,Xbox One 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,", +"050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Linux,", +"030000005e040000ea02000000000000,Xbox One Wireless 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,", +"050000005e040000e002000003090000,Xbox One Wireless 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:Linux,", +"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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,", +"030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),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,", +"030000005e040000120b000001050000,Xbox Series 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,", +"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,", +"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,", +"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 }; diff --git a/raylib/external/glfw/src/mappings.h.in b/raylib/external/glfw/src/mappings.h.in new file mode 100644 index 0000000..ed62368 --- /dev/null +++ b/raylib/external/glfw/src/mappings.h.in @@ -0,0 +1,82 @@ +//======================================================================== +// 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/mir_init.c b/raylib/external/glfw/src/mir_init.c deleted file mode 100644 index 5f9ed37..0000000 --- a/raylib/external/glfw/src/mir_init.c +++ /dev/null @@ -1,240 +0,0 @@ -//======================================================================== -// GLFW 3.3 Mir - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2014-2017 Brandon Schaefer -// -// 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 -#include - - -// Create key code translation tables -// -static void createKeyTables(void) -{ - int scancode; - - memset(_glfw.mir.keycodes, -1, sizeof(_glfw.mir.keycodes)); - memset(_glfw.mir.scancodes, -1, sizeof(_glfw.mir.scancodes)); - - _glfw.mir.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT; - _glfw.mir.keycodes[KEY_1] = GLFW_KEY_1; - _glfw.mir.keycodes[KEY_2] = GLFW_KEY_2; - _glfw.mir.keycodes[KEY_3] = GLFW_KEY_3; - _glfw.mir.keycodes[KEY_4] = GLFW_KEY_4; - _glfw.mir.keycodes[KEY_5] = GLFW_KEY_5; - _glfw.mir.keycodes[KEY_6] = GLFW_KEY_6; - _glfw.mir.keycodes[KEY_7] = GLFW_KEY_7; - _glfw.mir.keycodes[KEY_8] = GLFW_KEY_8; - _glfw.mir.keycodes[KEY_9] = GLFW_KEY_9; - _glfw.mir.keycodes[KEY_0] = GLFW_KEY_0; - _glfw.mir.keycodes[KEY_SPACE] = GLFW_KEY_SPACE; - _glfw.mir.keycodes[KEY_MINUS] = GLFW_KEY_MINUS; - _glfw.mir.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL; - _glfw.mir.keycodes[KEY_Q] = GLFW_KEY_Q; - _glfw.mir.keycodes[KEY_W] = GLFW_KEY_W; - _glfw.mir.keycodes[KEY_E] = GLFW_KEY_E; - _glfw.mir.keycodes[KEY_R] = GLFW_KEY_R; - _glfw.mir.keycodes[KEY_T] = GLFW_KEY_T; - _glfw.mir.keycodes[KEY_Y] = GLFW_KEY_Y; - _glfw.mir.keycodes[KEY_U] = GLFW_KEY_U; - _glfw.mir.keycodes[KEY_I] = GLFW_KEY_I; - _glfw.mir.keycodes[KEY_O] = GLFW_KEY_O; - _glfw.mir.keycodes[KEY_P] = GLFW_KEY_P; - _glfw.mir.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET; - _glfw.mir.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; - _glfw.mir.keycodes[KEY_A] = GLFW_KEY_A; - _glfw.mir.keycodes[KEY_S] = GLFW_KEY_S; - _glfw.mir.keycodes[KEY_D] = GLFW_KEY_D; - _glfw.mir.keycodes[KEY_F] = GLFW_KEY_F; - _glfw.mir.keycodes[KEY_G] = GLFW_KEY_G; - _glfw.mir.keycodes[KEY_H] = GLFW_KEY_H; - _glfw.mir.keycodes[KEY_J] = GLFW_KEY_J; - _glfw.mir.keycodes[KEY_K] = GLFW_KEY_K; - _glfw.mir.keycodes[KEY_L] = GLFW_KEY_L; - _glfw.mir.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON; - _glfw.mir.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; - _glfw.mir.keycodes[KEY_Z] = GLFW_KEY_Z; - _glfw.mir.keycodes[KEY_X] = GLFW_KEY_X; - _glfw.mir.keycodes[KEY_C] = GLFW_KEY_C; - _glfw.mir.keycodes[KEY_V] = GLFW_KEY_V; - _glfw.mir.keycodes[KEY_B] = GLFW_KEY_B; - _glfw.mir.keycodes[KEY_N] = GLFW_KEY_N; - _glfw.mir.keycodes[KEY_M] = GLFW_KEY_M; - _glfw.mir.keycodes[KEY_COMMA] = GLFW_KEY_COMMA; - _glfw.mir.keycodes[KEY_DOT] = GLFW_KEY_PERIOD; - _glfw.mir.keycodes[KEY_SLASH] = GLFW_KEY_SLASH; - _glfw.mir.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH; - _glfw.mir.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE; - _glfw.mir.keycodes[KEY_TAB] = GLFW_KEY_TAB; - _glfw.mir.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT; - _glfw.mir.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; - _glfw.mir.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL; - _glfw.mir.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL; - _glfw.mir.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT; - _glfw.mir.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT; - _glfw.mir.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER; - _glfw.mir.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER; - _glfw.mir.keycodes[KEY_MENU] = GLFW_KEY_MENU; - _glfw.mir.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK; - _glfw.mir.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK; - _glfw.mir.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN; - _glfw.mir.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; - _glfw.mir.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE; - _glfw.mir.keycodes[KEY_DELETE] = GLFW_KEY_DELETE; - _glfw.mir.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE; - _glfw.mir.keycodes[KEY_ENTER] = GLFW_KEY_ENTER; - _glfw.mir.keycodes[KEY_HOME] = GLFW_KEY_HOME; - _glfw.mir.keycodes[KEY_END] = GLFW_KEY_END; - _glfw.mir.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP; - _glfw.mir.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN; - _glfw.mir.keycodes[KEY_INSERT] = GLFW_KEY_INSERT; - _glfw.mir.keycodes[KEY_LEFT] = GLFW_KEY_LEFT; - _glfw.mir.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT; - _glfw.mir.keycodes[KEY_DOWN] = GLFW_KEY_DOWN; - _glfw.mir.keycodes[KEY_UP] = GLFW_KEY_UP; - _glfw.mir.keycodes[KEY_F1] = GLFW_KEY_F1; - _glfw.mir.keycodes[KEY_F2] = GLFW_KEY_F2; - _glfw.mir.keycodes[KEY_F3] = GLFW_KEY_F3; - _glfw.mir.keycodes[KEY_F4] = GLFW_KEY_F4; - _glfw.mir.keycodes[KEY_F5] = GLFW_KEY_F5; - _glfw.mir.keycodes[KEY_F6] = GLFW_KEY_F6; - _glfw.mir.keycodes[KEY_F7] = GLFW_KEY_F7; - _glfw.mir.keycodes[KEY_F8] = GLFW_KEY_F8; - _glfw.mir.keycodes[KEY_F9] = GLFW_KEY_F9; - _glfw.mir.keycodes[KEY_F10] = GLFW_KEY_F10; - _glfw.mir.keycodes[KEY_F11] = GLFW_KEY_F11; - _glfw.mir.keycodes[KEY_F12] = GLFW_KEY_F12; - _glfw.mir.keycodes[KEY_F13] = GLFW_KEY_F13; - _glfw.mir.keycodes[KEY_F14] = GLFW_KEY_F14; - _glfw.mir.keycodes[KEY_F15] = GLFW_KEY_F15; - _glfw.mir.keycodes[KEY_F16] = GLFW_KEY_F16; - _glfw.mir.keycodes[KEY_F17] = GLFW_KEY_F17; - _glfw.mir.keycodes[KEY_F18] = GLFW_KEY_F18; - _glfw.mir.keycodes[KEY_F19] = GLFW_KEY_F19; - _glfw.mir.keycodes[KEY_F20] = GLFW_KEY_F20; - _glfw.mir.keycodes[KEY_F21] = GLFW_KEY_F21; - _glfw.mir.keycodes[KEY_F22] = GLFW_KEY_F22; - _glfw.mir.keycodes[KEY_F23] = GLFW_KEY_F23; - _glfw.mir.keycodes[KEY_F24] = GLFW_KEY_F24; - _glfw.mir.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE; - _glfw.mir.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY; - _glfw.mir.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT; - _glfw.mir.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD; - _glfw.mir.keycodes[KEY_KP0] = GLFW_KEY_KP_0; - _glfw.mir.keycodes[KEY_KP1] = GLFW_KEY_KP_1; - _glfw.mir.keycodes[KEY_KP2] = GLFW_KEY_KP_2; - _glfw.mir.keycodes[KEY_KP3] = GLFW_KEY_KP_3; - _glfw.mir.keycodes[KEY_KP4] = GLFW_KEY_KP_4; - _glfw.mir.keycodes[KEY_KP5] = GLFW_KEY_KP_5; - _glfw.mir.keycodes[KEY_KP6] = GLFW_KEY_KP_6; - _glfw.mir.keycodes[KEY_KP7] = GLFW_KEY_KP_7; - _glfw.mir.keycodes[KEY_KP8] = GLFW_KEY_KP_8; - _glfw.mir.keycodes[KEY_KP9] = GLFW_KEY_KP_9; - _glfw.mir.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL; - _glfw.mir.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL; - _glfw.mir.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER; - - for (scancode = 0; scancode < 256; scancode++) - { - if (_glfw.mir.keycodes[scancode] > 0) - _glfw.mir.scancodes[_glfw.mir.keycodes[scancode]] = scancode; - } -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformInit(void) -{ - int error; - - _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); - - if (!mir_connection_is_valid(_glfw.mir.connection)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unable to connect to server: %s", - mir_connection_get_error_message(_glfw.mir.connection)); - - return GLFW_FALSE; - } - - _glfw.mir.display = - mir_connection_get_egl_native_display(_glfw.mir.connection); - - createKeyTables(); - - if (!_glfwInitJoysticksLinux()) - return GLFW_FALSE; - - _glfwInitTimerPOSIX(); - - _glfw.mir.eventQueue = calloc(1, sizeof(EventQueue)); - _glfwInitEventQueueMir(_glfw.mir.eventQueue); - - error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL); - if (error) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Failed to create event mutex: %s", - strerror(error)); - return GLFW_FALSE; - } - - _glfwPollMonitorsMir(); - return GLFW_TRUE; -} - -void _glfwPlatformTerminate(void) -{ - _glfwTerminateEGL(); - _glfwTerminateJoysticksLinux(); - - _glfwDeleteEventQueueMir(_glfw.mir.eventQueue); - - pthread_mutex_destroy(&_glfw.mir.eventMutex); - - mir_connection_release(_glfw.mir.connection); -} - -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " Mir EGL" -#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/mir_monitor.c b/raylib/external/glfw/src/mir_monitor.c deleted file mode 100644 index c340701..0000000 --- a/raylib/external/glfw/src/mir_monitor.c +++ /dev/null @@ -1,218 +0,0 @@ -//======================================================================== -// GLFW 3.3 Mir - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2014-2017 Brandon Schaefer -// -// 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 - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Poll for changes in the set of connected monitors -// -void _glfwPollMonitorsMir(void) -{ - int i; - MirDisplayConfig* displayConfig = - mir_connection_create_display_configuration(_glfw.mir.connection); - - int numOutputs = mir_display_config_get_num_outputs(displayConfig); - - for (i = 0; i < numOutputs; i++) - { - const MirOutput* output = mir_display_config_get_output(displayConfig, i); - MirOutputConnectionState state = mir_output_get_connection_state(output); - bool enabled = mir_output_is_enabled(output); - - if (enabled && state == mir_output_connection_state_connected) - { - int widthMM = mir_output_get_physical_width_mm(output); - int heightMM = mir_output_get_physical_height_mm(output); - int x = mir_output_get_position_x(output); - int y = mir_output_get_position_y(output); - int id = mir_output_get_id(output); - size_t currentMode = mir_output_get_current_mode_index(output); - const char* name = mir_output_type_name(mir_output_get_type(output)); - - _GLFWmonitor* monitor = _glfwAllocMonitor(name, - widthMM, - heightMM); - monitor->mir.x = x; - monitor->mir.y = y; - monitor->mir.outputId = id; - monitor->mir.curMode = currentMode; - monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount); - - _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); - } - } - - mir_display_config_release(displayConfig); -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) -{ -} - -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) -{ - if (xpos) - *xpos = monitor->mir.x; - if (ypos) - *ypos = monitor->mir.y; -} - -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) -{ - if (xscale) - *xscale = 1.f; - if (yscale) - *yscale = 1.f; -} - -static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) -{ - switch (pf) - { - case mir_pixel_format_rgb_565: - mode->redBits = 5; - mode->greenBits = 6; - mode->blueBits = 5; - break; - case mir_pixel_format_rgba_5551: - mode->redBits = 5; - mode->greenBits = 5; - mode->blueBits = 5; - break; - case mir_pixel_format_rgba_4444: - mode->redBits = 4; - mode->greenBits = 4; - mode->blueBits = 4; - break; - case mir_pixel_format_abgr_8888: - case mir_pixel_format_xbgr_8888: - case mir_pixel_format_argb_8888: - case mir_pixel_format_xrgb_8888: - case mir_pixel_format_bgr_888: - case mir_pixel_format_rgb_888: - default: - mode->redBits = 8; - mode->greenBits = 8; - mode->blueBits = 8; - break; - } -} - -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) -{ - int i; - GLFWvidmode* modes = NULL; - MirDisplayConfig* displayConfig = - mir_connection_create_display_configuration(_glfw.mir.connection); - - int numOutputs = mir_display_config_get_num_outputs(displayConfig); - - for (i = 0; i < numOutputs; i++) - { - const MirOutput* output = mir_display_config_get_output(displayConfig, i); - int id = mir_output_get_id(output); - - if (id != monitor->mir.outputId) - continue; - - MirOutputConnectionState state = mir_output_get_connection_state(output); - bool enabled = mir_output_is_enabled(output); - - // We must have been disconnected - if (!enabled || state != mir_output_connection_state_connected) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Monitor no longer connected"); - return NULL; - } - - int numModes = mir_output_get_num_modes(output); - modes = calloc(numModes, sizeof(GLFWvidmode)); - - for (*found = 0; *found < numModes; (*found)++) - { - const MirOutputMode* mode = mir_output_get_mode(output, *found); - int width = mir_output_mode_get_width(mode); - int height = mir_output_mode_get_height(mode); - double refreshRate = mir_output_mode_get_refresh_rate(mode); - MirPixelFormat currentFormat = mir_output_get_current_pixel_format(output); - - modes[*found].width = width; - modes[*found].height = height; - modes[*found].refreshRate = refreshRate; - - FillInRGBBitsFromPixelFormat(&modes[*found], currentFormat); - } - - break; - } - - mir_display_config_release(displayConfig); - - return modes; -} - -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) -{ - *mode = monitor->modes[monitor->mir.curMode]; -} - -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW native API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) -{ - _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(0); - return monitor->mir.outputId; -} diff --git a/raylib/external/glfw/src/mir_platform.h b/raylib/external/glfw/src/mir_platform.h deleted file mode 100644 index da00a32..0000000 --- a/raylib/external/glfw/src/mir_platform.h +++ /dev/null @@ -1,133 +0,0 @@ -//======================================================================== -// GLFW 3.3 Mir - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2014-2017 Brandon Schaefer -// -// 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 -#include -#include - -#include - -typedef VkFlags VkMirWindowCreateFlagsKHR; - -typedef struct VkMirWindowCreateInfoKHR -{ - VkStructureType sType; - const void* pNext; - VkMirWindowCreateFlagsKHR flags; - MirConnection* connection; - MirWindow* mirWindow; -} VkMirWindowCreateInfoKHR; - -typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); -typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); - -#include "posix_thread.h" -#include "posix_time.h" -#include "linux_joystick.h" -#include "xkb_unicode.h" -#include "egl_context.h" -#include "osmesa_context.h" - -#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_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.nativeWindow) -#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display) - -#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir -#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir -#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir - -#define _GLFW_PLATFORM_CONTEXT_STATE -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE - - -// Mir-specific Event Queue -// -typedef struct EventQueue -{ - TAILQ_HEAD(, EventNode) head; -} EventQueue; - -// Mir-specific per-window data -// -typedef struct _GLFWwindowMir -{ - MirWindow* window; - int width; - int height; - MirEGLNativeWindowType nativeWindow; - _GLFWcursor* currentCursor; - -} _GLFWwindowMir; - -// Mir-specific per-monitor data -// -typedef struct _GLFWmonitorMir -{ - int curMode; - int outputId; - int x; - int y; - -} _GLFWmonitorMir; - -// Mir-specific global data -// -typedef struct _GLFWlibraryMir -{ - MirConnection* connection; - MirEGLNativeDisplayType display; - EventQueue* eventQueue; - - short int keycodes[256]; - short int scancodes[GLFW_KEY_LAST + 1]; - - pthread_mutex_t eventMutex; - pthread_cond_t eventCond; - - // The window whose disabled cursor mode is active - _GLFWwindow* disabledCursorWindow; - -} _GLFWlibraryMir; - -// Mir-specific per-cursor data -// TODO: Only system cursors are implemented in Mir atm. Need to wait for support. -// -typedef struct _GLFWcursorMir -{ - MirCursorConfiguration* conf; - MirBufferStream* customCursor; - char const* cursorName; // only needed for system cursors -} _GLFWcursorMir; - - -extern void _glfwPollMonitorsMir(void); -extern void _glfwInitEventQueueMir(EventQueue* queue); -extern void _glfwDeleteEventQueueMir(EventQueue* queue); - diff --git a/raylib/external/glfw/src/mir_window.c b/raylib/external/glfw/src/mir_window.c deleted file mode 100644 index a0d17db..0000000 --- a/raylib/external/glfw/src/mir_window.c +++ /dev/null @@ -1,975 +0,0 @@ -//======================================================================== -// GLFW 3.3 Mir - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2014-2017 Brandon Schaefer -// -// 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 -#include - - -typedef struct EventNode -{ - TAILQ_ENTRY(EventNode) entries; - const MirEvent* event; - _GLFWwindow* window; -} EventNode; - -static void deleteNode(EventQueue* queue, EventNode* node) -{ - mir_event_unref(node->event); - free(node); -} - -static GLFWbool emptyEventQueue(EventQueue* queue) -{ - return queue->head.tqh_first == NULL; -} - -// TODO The mir_event_ref is not supposed to be used but ... its needed -// in this case. Need to wait until we can read from an FD set up by mir -// for single threaded event handling. -static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) -{ - EventNode* newNode = calloc(1, sizeof(EventNode)); - newNode->event = mir_event_ref(event); - newNode->window = context; - - return newNode; -} - -static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) -{ - pthread_mutex_lock(&_glfw.mir.eventMutex); - - EventNode* newNode = newEventNode(event, context); - TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries); - - pthread_cond_signal(&_glfw.mir.eventCond); - - pthread_mutex_unlock(&_glfw.mir.eventMutex); -} - -static EventNode* dequeueEvent(EventQueue* queue) -{ - EventNode* node = NULL; - - pthread_mutex_lock(&_glfw.mir.eventMutex); - - node = queue->head.tqh_first; - - if (node) - TAILQ_REMOVE(&queue->head, node, entries); - - pthread_mutex_unlock(&_glfw.mir.eventMutex); - - return node; -} - -static MirPixelFormat findValidPixelFormat(void) -{ - unsigned int i, validFormats, mirPixelFormats = 32; - MirPixelFormat formats[mir_pixel_formats]; - - mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, - mirPixelFormats, &validFormats); - - for (i = 0; i < validFormats; i++) - { - if (formats[i] == mir_pixel_format_abgr_8888 || - formats[i] == mir_pixel_format_xbgr_8888 || - formats[i] == mir_pixel_format_argb_8888 || - formats[i] == mir_pixel_format_xrgb_8888) - { - return formats[i]; - } - } - - return mir_pixel_format_invalid; -} - -static int mirModToGLFWMod(uint32_t mods) -{ - int publicMods = 0x0; - - if (mods & mir_input_event_modifier_alt) - publicMods |= GLFW_MOD_ALT; - if (mods & mir_input_event_modifier_shift) - publicMods |= GLFW_MOD_SHIFT; - if (mods & mir_input_event_modifier_ctrl) - publicMods |= GLFW_MOD_CONTROL; - if (mods & mir_input_event_modifier_meta) - publicMods |= GLFW_MOD_SUPER; - if (mods & mir_input_event_modifier_caps_lock) - publicMods |= GLFW_MOD_CAPS_LOCK; - if (mods & mir_input_event_modifier_num_lock) - publicMods |= GLFW_MOD_NUM_LOCK; - - return publicMods; -} - -static int toGLFWKeyCode(uint32_t key) -{ - if (key < sizeof(_glfw.mir.keycodes) / sizeof(_glfw.mir.keycodes[0])) - return _glfw.mir.keycodes[key]; - - return GLFW_KEY_UNKNOWN; -} - -static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window) -{ - const int action = mir_keyboard_event_action (key_event); - const int scan_code = mir_keyboard_event_scan_code(key_event); - const int key_code = mir_keyboard_event_key_code (key_event); - const int modifiers = mir_keyboard_event_modifiers(key_event); - - const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS; - const int mods = mirModToGLFWMod(modifiers); - const long text = _glfwKeySym2Unicode(key_code); - const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - - _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods); - - if (text != -1) - _glfwInputChar(window, text, mods, plain); -} - -static void handlePointerButton(_GLFWwindow* window, - int pressed, - const MirPointerEvent* pointer_event) -{ - int mods = mir_pointer_event_modifiers(pointer_event); - const int publicMods = mirModToGLFWMod(mods); - MirPointerButton button = mir_pointer_button_primary; - static uint32_t oldButtonStates = 0; - uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event); - int publicButton = GLFW_MOUSE_BUTTON_LEFT; - - // XOR our old button states our new states to figure out what was added or removed - button = newButtonStates ^ oldButtonStates; - - switch (button) - { - case mir_pointer_button_primary: - publicButton = GLFW_MOUSE_BUTTON_LEFT; - break; - case mir_pointer_button_secondary: - publicButton = GLFW_MOUSE_BUTTON_RIGHT; - break; - case mir_pointer_button_tertiary: - publicButton = GLFW_MOUSE_BUTTON_MIDDLE; - break; - case mir_pointer_button_forward: - // FIXME What is the forward button? - publicButton = GLFW_MOUSE_BUTTON_4; - break; - case mir_pointer_button_back: - // FIXME What is the back button? - publicButton = GLFW_MOUSE_BUTTON_5; - break; - default: - break; - } - - oldButtonStates = newButtonStates; - - _glfwInputMouseClick(window, publicButton, pressed, publicMods); -} - -static void handlePointerMotion(_GLFWwindow* window, - const MirPointerEvent* pointer_event) -{ - const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); - const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (_glfw.mir.disabledCursorWindow != window) - return; - - const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x); - const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y); - const int current_x = window->virtualCursorPosX; - const int current_y = window->virtualCursorPosY; - - _glfwInputCursorPos(window, dx + current_x, dy + current_y); - } - else - { - const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); - const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); - - _glfwInputCursorPos(window, x, y); - } - - if (hscroll != 0 || vscroll != 0) - _glfwInputScroll(window, hscroll, vscroll); -} - -static void handlePointerEvent(const MirPointerEvent* pointer_event, - _GLFWwindow* window) -{ - int action = mir_pointer_event_action(pointer_event); - - switch (action) - { - case mir_pointer_action_button_down: - handlePointerButton(window, GLFW_PRESS, pointer_event); - break; - case mir_pointer_action_button_up: - handlePointerButton(window, GLFW_RELEASE, pointer_event); - break; - case mir_pointer_action_motion: - handlePointerMotion(window, pointer_event); - break; - case mir_pointer_action_enter: - case mir_pointer_action_leave: - break; - default: - break; - } -} - -static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window) -{ - int type = mir_input_event_get_type(input_event); - - switch (type) - { - case mir_input_event_type_key: - handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window); - break; - case mir_input_event_type_pointer: - handlePointerEvent(mir_input_event_get_pointer_event(input_event), window); - break; - default: - break; - } -} - -static void handleEvent(const MirEvent* event, _GLFWwindow* window) -{ - int type = mir_event_get_type(event); - - switch (type) - { - case mir_event_type_input: - handleInput(mir_event_get_input_event(event), window); - break; - default: - break; - } -} - -static void addNewEvent(MirWindow* window, const MirEvent* event, void* context) -{ - enqueueEvent(event, context); -} - -static GLFWbool createWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - MirBufferUsage buffer_usage = mir_buffer_usage_hardware; - MirPixelFormat pixel_format = findValidPixelFormat(); - - if (pixel_format == mir_pixel_format_invalid) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unable to find a correct pixel format"); - return GLFW_FALSE; - } - - spec = mir_create_normal_window_spec(_glfw.mir.connection, - window->mir.width, - window->mir.height); - - mir_window_spec_set_pixel_format(spec, pixel_format); - mir_window_spec_set_buffer_usage(spec, buffer_usage); - - window->mir.window = mir_create_window_sync(spec); - mir_window_spec_release(spec); - - if (!mir_window_is_valid(window->mir.window)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unable to create window: %s", - mir_window_get_error_message(window->mir.window)); - - return GLFW_FALSE; - } - - mir_window_set_event_handler(window->mir.window, addNewEvent, window); - - return GLFW_TRUE; -} - -static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_pointer_confinement(spec, state); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwInitEventQueueMir(EventQueue* queue) -{ - TAILQ_INIT(&queue->head); -} - -void _glfwDeleteEventQueueMir(EventQueue* queue) -{ - if (queue) - { - EventNode* node, *node_next; - node = queue->head.tqh_first; - - while (node != NULL) - { - node_next = node->entries.tqe_next; - - TAILQ_REMOVE(&queue->head, node, entries); - deleteNode(queue, node); - - node = node_next; - } - - free(queue); - } -} - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformCreateWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) -{ - if (window->monitor) - { - GLFWvidmode mode; - _glfwPlatformGetVideoMode(window->monitor, &mode); - - mir_window_set_state(window->mir.window, mir_window_state_fullscreen); - - if (wndconfig->width > mode.width || wndconfig->height > mode.height) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Requested window size too large: %ix%i", - wndconfig->width, wndconfig->height); - - return GLFW_FALSE; - } - } - - window->mir.width = wndconfig->width; - window->mir.height = wndconfig->height; - window->mir.currentCursor = NULL; - - if (!createWindow(window)) - return GLFW_FALSE; - - window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window( - mir_window_get_buffer_stream(window->mir.window)); - - if (ctxconfig->client != GLFW_NO_API) - { - if (ctxconfig->source == GLFW_EGL_CONTEXT_API || - ctxconfig->source == GLFW_NATIVE_CONTEXT_API) - { - if (!_glfwInitEGL()) - return GLFW_FALSE; - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - } - else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) - { - if (!_glfwInitOSMesa()) - return GLFW_FALSE; - if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - } - } - - return GLFW_TRUE; -} - -void _glfwPlatformDestroyWindow(_GLFWwindow* window) -{ - if (_glfw.mir.disabledCursorWindow == window) - _glfw.mir.disabledCursorWindow = NULL; - - if (mir_window_is_valid(window->mir.window)) - { - mir_window_release_sync(window->mir.window); - window->mir.window= NULL; - } - - if (window->context.destroy) - window->context.destroy(window); -} - -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_name(spec, title); - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, - int count, const GLFWimage* images) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_width (spec, width); - mir_window_spec_set_height(spec, height); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_max_width (spec, maxwidth); - mir_window_spec_set_max_height(spec, maxheight); - mir_window_spec_set_min_width (spec, minwidth); - mir_window_spec_set_min_height(spec, minheight); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) -{ - if (width) - *width = window->mir.width; - if (height) - *height = window->mir.height; -} - -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) -{ - if (xscale) - *xscale = 1.f; - if (yscale) - *yscale = 1.f; -} - -void _glfwPlatformIconifyWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_state(spec, mir_window_state_minimized); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformRestoreWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_state(spec, mir_window_state_restored); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformMaximizeWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_state(spec, mir_window_state_maximized); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformHideWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_state(spec, mir_window_state_hidden); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - MirWindowSpec* spec; - - spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_state(spec, mir_window_state_restored); - - mir_window_apply_spec(window->mir.window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformFocusWindow(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -int _glfwPlatformWindowFocused(_GLFWwindow* window) -{ - return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused; -} - -int _glfwPlatformWindowIconified(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return GLFW_FALSE; -} - -int _glfwPlatformWindowVisible(_GLFWwindow* window) -{ - return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed; -} - -int _glfwPlatformWindowMaximized(_GLFWwindow* window) -{ - return mir_window_get_state(window->mir.window) == mir_window_state_maximized; -} - -int _glfwPlatformWindowHovered(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return GLFW_FALSE; -} - -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return GLFW_FALSE; -} - -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) -{ - return 1.f; -} - -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) -{ -} - -void _glfwPlatformPollEvents(void) -{ - EventNode* node = NULL; - - while ((node = dequeueEvent(_glfw.mir.eventQueue))) - { - handleEvent(node->event, node->window); - deleteNode(_glfw.mir.eventQueue, node); - } -} - -void _glfwPlatformWaitEvents(void) -{ - pthread_mutex_lock(&_glfw.mir.eventMutex); - - while (emptyEventQueue(_glfw.mir.eventQueue)) - pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex); - - pthread_mutex_unlock(&_glfw.mir.eventMutex); - - _glfwPlatformPollEvents(); -} - -void _glfwPlatformWaitEventsTimeout(double timeout) -{ - pthread_mutex_lock(&_glfw.mir.eventMutex); - - if (emptyEventQueue(_glfw.mir.eventQueue)) - { - struct timespec time; - clock_gettime(CLOCK_REALTIME, &time); - time.tv_sec += (long) timeout; - time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); - pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time); - } - - pthread_mutex_unlock(&_glfw.mir.eventMutex); - - _glfwPlatformPollEvents(); -} - -void _glfwPlatformPostEmptyEvent(void) -{ -} - -void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) -{ - if (width) - *width = window->mir.width; - if (height) - *height = window->mir.height; -} - -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) -{ - MirBufferStream* stream; - - int i_w = image->width; - int i_h = image->height; - - stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection, - i_w, i_h, - mir_pixel_format_argb_8888, - mir_buffer_usage_software); - - cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot); - - MirGraphicsRegion region; - mir_buffer_stream_get_graphics_region(stream, ®ion); - - unsigned char* pixels = image->pixels; - char* dest = region.vaddr; - int i; - - for (i = 0; i < i_w * i_h; i++, pixels += 4) - { - unsigned int alpha = pixels[3]; - *dest++ = (char)(pixels[2] * alpha / 255); - *dest++ = (char)(pixels[1] * alpha / 255); - *dest++ = (char)(pixels[0] * alpha / 255); - *dest++ = (char)alpha; - } - - mir_buffer_stream_swap_buffers_sync(stream); - cursor->mir.customCursor = stream; - - return GLFW_TRUE; -} - -static const char* getSystemCursorName(int shape) -{ - switch (shape) - { - case GLFW_ARROW_CURSOR: - return mir_arrow_cursor_name; - case GLFW_IBEAM_CURSOR: - return mir_caret_cursor_name; - case GLFW_CROSSHAIR_CURSOR: - return mir_crosshair_cursor_name; - case GLFW_HAND_CURSOR: - return mir_open_hand_cursor_name; - case GLFW_HRESIZE_CURSOR: - return mir_horizontal_resize_cursor_name; - case GLFW_VRESIZE_CURSOR: - return mir_vertical_resize_cursor_name; - } - - return NULL; -} - -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) -{ - cursor->mir.conf = NULL; - cursor->mir.customCursor = NULL; - cursor->mir.cursorName = getSystemCursorName(shape); - - return cursor->mir.cursorName != NULL; -} - -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) -{ - if (cursor->mir.conf) - mir_cursor_configuration_destroy(cursor->mir.conf); - if (cursor->mir.customCursor) - mir_buffer_stream_release_sync(cursor->mir.customCursor); -} - -static void setCursorNameForWindow(MirWindow* window, char const* name) -{ - MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection); - mir_window_spec_set_cursor_name(spec, name); - mir_window_apply_spec(window, spec); - mir_window_spec_release(spec); -} - -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) -{ - if (cursor) - { - window->mir.currentCursor = cursor; - - if (cursor->mir.cursorName) - { - setCursorNameForWindow(window->mir.window, cursor->mir.cursorName); - } - else if (cursor->mir.conf) - { - mir_window_configure_cursor(window->mir.window, cursor->mir.conf); - } - } - else - { - setCursorNameForWindow(window->mir.window, mir_default_cursor_name); - } -} - -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) -{ - if (mode == GLFW_CURSOR_DISABLED) - { - _glfw.mir.disabledCursorWindow = window; - setWindowConfinement(window, mir_pointer_confined_to_window); - setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); - } - else - { - // If we were disabled before lets undo that! - if (_glfw.mir.disabledCursorWindow == window) - { - _glfw.mir.disabledCursorWindow = NULL; - setWindowConfinement(window, mir_pointer_unconfined); - } - - if (window->cursorMode == GLFW_CURSOR_NORMAL) - { - _glfwPlatformSetCursor(window, window->mir.currentCursor); - } - else if (window->cursorMode == GLFW_CURSOR_HIDDEN) - { - setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name); - } - } -} - -const char* _glfwPlatformGetScancodeName(int scancode) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - return NULL; -} - -int _glfwPlatformGetKeyScancode(int key) -{ - return _glfw.mir.scancodes[key]; -} - -void _glfwPlatformSetClipboardString(const char* string) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); -} - -const char* _glfwPlatformGetClipboardString(void) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Unsupported function %s", __PRETTY_FUNCTION__); - - return NULL; -} - -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) -{ - if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_mir_surface) - return; - - extensions[0] = "VK_KHR_surface"; - extensions[1] = "VK_KHR_mir_surface"; -} - -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) -{ - PFN_vkGetPhysicalDeviceMirPresentationSupportKHR - vkGetPhysicalDeviceMirPresentationSupportKHR = - (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) - vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); - if (!vkGetPhysicalDeviceMirPresentationSupportKHR) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); - return GLFW_FALSE; - } - - return vkGetPhysicalDeviceMirPresentationSupportKHR(device, - queuefamily, - _glfw.mir.connection); -} - -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) -{ - VkResult err; - VkMirWindowCreateInfoKHR sci; - PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR; - - vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR) - vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR"); - if (!vkCreateMirWindowKHR) - { - _glfwInputError(GLFW_API_UNAVAILABLE, - "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - - memset(&sci, 0, sizeof(sci)); - sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; - sci.connection = _glfw.mir.connection; - sci.mirWindow = window->mir.window; - - err = vkCreateMirWindowKHR(instance, &sci, allocator, surface); - if (err) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Mir: Failed to create Vulkan surface: %s", - _glfwGetVulkanResultString(err)); - } - - return err; -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW native API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI MirConnection* glfwGetMirDisplay(void) -{ - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfw.mir.connection; -} - -GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return window->mir.window; -} - diff --git a/raylib/external/glfw/src/monitor.c b/raylib/external/glfw/src/monitor.c index f7de550..efc286d 100644 --- a/raylib/external/glfw/src/monitor.c +++ b/raylib/external/glfw/src/monitor.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -54,6 +54,10 @@ static int compareVideoModes(const void* fp, const void* sp) if (farea != sarea) return farea - sarea; + // Then sort on width + if (fm->width != sm->width) + return fm->width - sm->width; + // Lastly sort on refresh rate return fm->refreshRate - sm->refreshRate; } @@ -68,13 +72,13 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor) if (monitor->modes) return GLFW_TRUE; - modes = _glfwPlatformGetVideoModes(monitor, &modeCount); + modes = _glfw.platform.getVideoModes(monitor, &modeCount); if (!modes) return GLFW_FALSE; qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); - free(monitor->modes); + _glfw_free(monitor->modes); monitor->modes = modes; monitor->modeCount = modeCount; @@ -90,17 +94,22 @@ 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 = - realloc(_glfw.monitors, sizeof(_GLFWmonitor*) * _glfw.monitorCount); + _glfw_realloc(_glfw.monitors, + sizeof(_GLFWmonitor*) * _glfw.monitorCount); if (placement == _GLFW_INSERT_FIRST) { memmove(_glfw.monitors + 1, _glfw.monitors, - (_glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); + ((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*)); _glfw.monitors[0] = monitor; } else @@ -116,10 +125,10 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) if (window->monitor == monitor) { int width, height, xoff, yoff; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); - _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); - _glfwPlatformSetWindowPos(window, 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); } } @@ -130,7 +139,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) _glfw.monitorCount--; memmove(_glfw.monitors + i, _glfw.monitors + i + 1, - (_glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); + ((size_t) _glfw.monitorCount - i) * sizeof(_GLFWmonitor*)); break; } } @@ -148,6 +157,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) // void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) { + assert(monitor != NULL); monitor->window = window; } @@ -160,12 +170,11 @@ void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window) // _GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) { - _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); + _GLFWmonitor* monitor = _glfw_calloc(1, sizeof(_GLFWmonitor)); monitor->widthMM = widthMM; monitor->heightMM = heightMM; - if (name) - monitor->name = _glfw_strdup(name); + strncpy(monitor->name, name, sizeof(monitor->name) - 1); return monitor; } @@ -177,23 +186,22 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor) if (monitor == NULL) return; - _glfwPlatformFreeMonitor(monitor); + _glfw.platform.freeMonitor(monitor); _glfwFreeGammaArrays(&monitor->originalRamp); _glfwFreeGammaArrays(&monitor->currentRamp); - free(monitor->modes); - free(monitor->name); - free(monitor); + _glfw_free(monitor->modes); + _glfw_free(monitor); } // Allocates red, green and blue value arrays of the specified size // void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) { - ramp->red = calloc(size, sizeof(unsigned short)); - ramp->green = calloc(size, sizeof(unsigned short)); - ramp->blue = calloc(size, sizeof(unsigned short)); + 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->size = size; } @@ -201,9 +209,9 @@ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) // void _glfwFreeGammaArrays(GLFWgammaramp* ramp) { - free(ramp->red); - free(ramp->green); - free(ramp->blue); + _glfw_free(ramp->red); + _glfw_free(ramp->green); + _glfw_free(ramp->blue); memset(ramp, 0, sizeof(GLFWgammaramp)); } @@ -327,7 +335,28 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) _GLFW_REQUIRE_INIT(); - _glfwPlatformGetMonitorPos(monitor, xpos, ypos); + _glfw.platform.getMonitorPos(monitor, xpos, ypos); +} + +GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, + int* xpos, int* ypos, + int* width, int* height) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + if (width) + *width = 0; + if (height) + *height = 0; + + _GLFW_REQUIRE_INIT(); + + _glfw.platform.getMonitorWorkarea(monitor, xpos, ypos, width, height); } GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) @@ -360,7 +389,7 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* handle, *yscale = 0.f; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetMonitorContentScale(monitor, xscale, yscale); + _glfw.platform.getMonitorContentScale(monitor, xscale, yscale); } GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) @@ -393,7 +422,7 @@ GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle) GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); + _GLFW_SWAP(GLFWmonitorfun, _glfw.callbacks.monitor, cbfun); return cbfun; } @@ -421,18 +450,20 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); + if (!_glfw.platform.getVideoMode(monitor, &monitor->currentMode)) + return NULL; + return &monitor->currentMode; } GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) { - int i; - unsigned short values[256]; + unsigned int i; + unsigned short* values; GLFWgammaramp ramp; + const GLFWgammaramp* original; assert(handle != NULL); - assert(gamma == gamma); - assert(gamma >= 0.f); + assert(gamma > 0.f); assert(gamma <= FLT_MAX); _GLFW_REQUIRE_INIT(); @@ -443,18 +474,22 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) return; } - for (i = 0; i < 256; i++) + original = glfwGetGammaRamp(handle); + if (!original) + return; + + values = _glfw_calloc(original->size, sizeof(unsigned short)); + + for (i = 0; i < original->size; i++) { float value; // Calculate intensity - value = i / 255.f; + value = i / (float) (original->size - 1); // Apply gamma curve value = powf(value, 1.f / gamma) * 65535.f + 0.5f; - // Clamp to value range - if (value > 65535.f) - value = 65535.f; + value = fminf(value, 65535.f); values[i] = (unsigned short) value; } @@ -462,9 +497,10 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) ramp.red = values; ramp.green = values; ramp.blue = values; - ramp.size = 256; + ramp.size = original->size; glfwSetGammaRamp(handle, &ramp); + _glfw_free(values); } GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) @@ -475,7 +511,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _glfwFreeGammaArrays(&monitor->currentRamp); - _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); + if (!_glfw.platform.getGammaRamp(monitor, &monitor->currentRamp)) + return NULL; return &monitor->currentRamp; } @@ -490,6 +527,8 @@ 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, @@ -498,11 +537,12 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) return; } - _GLFW_REQUIRE_INIT(); - if (!monitor->originalRamp.size) - _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); + { + if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp)) + return; + } - _glfwPlatformSetGammaRamp(monitor, ramp); + _glfw.platform.setGammaRamp(monitor, ramp); } diff --git a/raylib/external/glfw/src/nsgl_context.m b/raylib/external/glfw/src/nsgl_context.m index 82af906..daa8367 100644 --- a/raylib/external/glfw/src/nsgl_context.m +++ b/raylib/external/glfw/src/nsgl_context.m @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 macOS - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// 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 @@ -26,30 +26,67 @@ #include "internal.h" +#if defined(_GLFW_COCOA) + +#include +#include static void makeContextCurrentNSGL(_GLFWwindow* window) { + @autoreleasepool { + if (window) [window->context.nsgl.object makeCurrentContext]; else [NSOpenGLContext clearCurrentContext]; _glfwPlatformSetTls(&_glfw.contextSlot, window); + + } // autoreleasepool } static void swapBuffersNSGL(_GLFWwindow* window) { - // ARP appears to be unnecessary, but this is future-proof + @autoreleasepool { + + // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to + // windows with a non-visible occlusion state + if (window->ns.occluded) + { + int interval = 0; + [window->context.nsgl.object getValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; + + if (interval > 0) + { + const double framerate = 60.0; + const uint64_t frequency = _glfwPlatformGetTimerFrequency(); + const uint64_t value = _glfwPlatformGetTimerValue(); + + const double elapsed = value / (double) frequency; + const double period = 1.0 / framerate; + const double delay = period - fmod(elapsed, period); + + usleep(floorl(delay * 1e6)); + } + } + [window->context.nsgl.object flushBuffer]; + + } // autoreleasepool } static void swapIntervalNSGL(int interval) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + @autoreleasepool { - GLint sync = interval; - [window->context.nsgl.object setValues:&sync - forParameter:NSOpenGLCPSwapInterval]; + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); + + [window->context.nsgl.object setValues:&interval + forParameter:NSOpenGLContextParameterSwapInterval]; + + } // autoreleasepool } static int extensionSupportedNSGL(const char* extension) @@ -72,15 +109,17 @@ static GLFWglproc getProcAddressNSGL(const char* procname) return symbol; } -// Destroy the OpenGL context -// static void destroyContextNSGL(_GLFWwindow* window) { + @autoreleasepool { + [window->context.nsgl.pixelFormat release]; window->context.nsgl.pixelFormat = nil; [window->context.nsgl.object release]; window->context.nsgl.object = nil; + + } // autoreleasepool } @@ -122,7 +161,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, - "NSGL: OpenGL ES is not available on macOS"); + "NSGL: OpenGL ES is not available via NSGL"); return GLFW_FALSE; } @@ -134,13 +173,13 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, "NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above"); return GLFW_FALSE; } + } - if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) - { - _glfwInputError(GLFW_VERSION_UNAVAILABLE, - "NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above"); - return GLFW_FALSE; - } + 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 @@ -155,47 +194,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 addAttrib(a) \ +#define ADD_ATTRIB(a) \ { \ assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ } -#define setAttrib(a, v) { addAttrib(a); addAttrib(v); } +#define SET_ATTRIB(a, v) { ADD_ATTRIB(a); ADD_ATTRIB(v); } NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; - addAttrib(NSOpenGLPFAAccelerated); - addAttrib(NSOpenGLPFAClosestPolicy); + ADD_ATTRIB(NSOpenGLPFAAccelerated); + ADD_ATTRIB(NSOpenGLPFAClosestPolicy); if (ctxconfig->nsgl.offline) { - addAttrib(NSOpenGLPFAAllowOfflineRenderers); + ADD_ATTRIB(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 -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); -#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching); } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 if (ctxconfig->major >= 4) { - setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); } else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ if (ctxconfig->major >= 3) { - setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); } if (ctxconfig->major <= 2) { if (fbconfig->auxBuffers != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); if (fbconfig->accumRedBits != GLFW_DONT_CARE && fbconfig->accumGreenBits != GLFW_DONT_CARE && @@ -207,7 +244,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, fbconfig->accumBlueBits + fbconfig->accumAlphaBits; - setAttrib(NSOpenGLPFAAccumSize, accumBits); + SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits); } } @@ -225,17 +262,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, else if (colorBits < 15) colorBits = 15; - setAttrib(NSOpenGLPFAColorSize, colorBits); + SET_ATTRIB(NSOpenGLPFAColorSize, colorBits); } if (fbconfig->alphaBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); if (fbconfig->depthBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); + SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits); if (fbconfig->stencilBits != GLFW_DONT_CARE) - setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits); if (fbconfig->stereo) { @@ -244,33 +281,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, "NSGL: Stereo rendering is deprecated"); return GLFW_FALSE; #else - addAttrib(NSOpenGLPFAStereo); + ADD_ATTRIB(NSOpenGLPFAStereo); #endif } if (fbconfig->doublebuffer) - addAttrib(NSOpenGLPFADoubleBuffer); + ADD_ATTRIB(NSOpenGLPFADoubleBuffer); if (fbconfig->samples != GLFW_DONT_CARE) { if (fbconfig->samples == 0) { - setAttrib(NSOpenGLPFASampleBuffers, 0); + SET_ATTRIB(NSOpenGLPFASampleBuffers, 0); } else { - setAttrib(NSOpenGLPFASampleBuffers, 1); - setAttrib(NSOpenGLPFASamples, fbconfig->samples); + SET_ATTRIB(NSOpenGLPFASampleBuffers, 1); + SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples); } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB // framebuffer, so there's no need (and no way) to request it - addAttrib(0); + ADD_ATTRIB(0); -#undef addAttrib -#undef setAttrib +#undef ADD_ATTRIB +#undef SET_ATTRIB window->context.nsgl.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; @@ -281,7 +318,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, return GLFW_FALSE; } - NSOpenGLContext* share = NULL; + NSOpenGLContext* share = nil; if (ctxconfig->share) share = ctxconfig->share->context.nsgl.object; @@ -299,9 +336,12 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, if (fbconfig->transparent) { GLint opaque = 0; - [window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; + [window->context.nsgl.object setValues:&opaque + forParameter:NSOpenGLContextParameterSurfaceOpacity]; } + [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.scaleFramebuffer]; + [window->context.nsgl.object setView:window->ns.view]; window->context.makeCurrent = makeContextCurrentNSGL; @@ -324,12 +364,21 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - if (window->context.client == GLFW_NO_API) + 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) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); - return NULL; + return nil; } 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 3414738..88940fc 100644 --- a/raylib/external/glfw/src/null_init.c +++ b/raylib/external/glfw/src/null_init.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,24 +27,238 @@ #include "internal.h" +#include +#include + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformInit(void) +GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) { - _glfwInitTimerPOSIX(); + 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; } -void _glfwPlatformTerminate(void) +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; + } + + _glfwPollMonitorsNull(); + return GLFW_TRUE; +} + +void _glfwTerminateNull(void) +{ + free(_glfw.null.clipboardString); _glfwTerminateOSMesa(); -} - -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " null OSMesa"; + _glfwTerminateEGL(); } diff --git a/raylib/external/glfw/src/null_joystick.c b/raylib/external/glfw/src/null_joystick.c index afd65e1..ec1f6b5 100644 --- a/raylib/external/glfw/src/null_joystick.c +++ b/raylib/external/glfw/src/null_joystick.c @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -31,12 +31,26 @@ ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +GLFWbool _glfwInitJoysticksNull(void) +{ + return GLFW_TRUE; +} + +void _glfwTerminateJoysticksNull(void) +{ +} + +GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode) { return GLFW_FALSE; } -void _glfwPlatformUpdateGamepadGUID(char* guid) +const char* _glfwGetMappingNameNull(void) +{ + return ""; +} + +void _glfwUpdateGamepadGUIDNull(char* guid) { } diff --git a/raylib/external/glfw/src/null_joystick.h b/raylib/external/glfw/src/null_joystick.h index 3075815..a2199c5 100644 --- a/raylib/external/glfw/src/null_joystick.h +++ b/raylib/external/glfw/src/null_joystick.h @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -24,8 +24,9 @@ // //======================================================================== -#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs -#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs - -#define _GLFW_PLATFORM_MAPPING_NAME "" +GLFWbool _glfwInitJoysticksNull(void); +void _glfwTerminateJoysticksNull(void); +GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode); +const char* _glfwGetMappingNameNull(void); +void _glfwUpdateGamepadGUIDNull(char* guid); diff --git a/raylib/external/glfw/src/null_monitor.c b/raylib/external/glfw/src/null_monitor.c index 84b41c7..d818f45 100644 --- a/raylib/external/glfw/src/null_monitor.c +++ b/raylib/external/glfw/src/null_monitor.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2016-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 @@ -27,21 +27,57 @@ #include "internal.h" +#include +#include +#include + +// The the sole (fake) video mode of our (sole) fake monitor +// +static GLFWvidmode getVideoMode(void) +{ + GLFWvidmode mode; + mode.width = 1920; + mode.height = 1080; + mode.redBits = 8; + mode.greenBits = 8; + mode.blueBits = 8; + mode.refreshRate = 60; + return mode; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPollMonitorsNull(void) +{ + const float dpi = 141.f; + const GLFWvidmode mode = getVideoMode(); + _GLFWmonitor* monitor = _glfwAllocMonitor("Null SuperNoop 0", + (int) (mode.width * 25.4f / dpi), + (int) (mode.height * 25.4f / dpi)); + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitorNull(_GLFWmonitor* monitor) { + _glfwFreeGammaArrays(&monitor->null.ramp); } -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwGetMonitorPosNull(_GLFWmonitor* monitor, int* xpos, int* ypos) { + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; } -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwGetMonitorContentScaleNull(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = 1.f; @@ -49,20 +85,76 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, *yscale = 1.f; } -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +void _glfwGetMonitorWorkareaNull(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) { - return NULL; + const GLFWvidmode mode = getVideoMode(); + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 10; + if (width) + *width = mode.width; + if (height) + *height = mode.height - 10; } -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +GLFWvidmode* _glfwGetVideoModesNull(_GLFWmonitor* monitor, int* found) { + GLFWvidmode* mode = _glfw_calloc(1, sizeof(GLFWvidmode)); + *mode = getVideoMode(); + *found = 1; + return mode; } -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwGetVideoModeNull(_GLFWmonitor* monitor, GLFWvidmode* mode) { + *mode = getVideoMode(); + return GLFW_TRUE; } -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +GLFWbool _glfwGetGammaRampNull(_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++) + { + 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); + + monitor->null.ramp.red[i] = (unsigned short) value; + monitor->null.ramp.green[i] = (unsigned short) value; + monitor->null.ramp.blue[i] = (unsigned short) value; + } + } + + _glfwAllocGammaArrays(ramp, monitor->null.ramp.size); + memcpy(ramp->red, monitor->null.ramp.red, sizeof(short) * ramp->size); + memcpy(ramp->green, monitor->null.ramp.green, sizeof(short) * ramp->size); + memcpy(ramp->blue, monitor->null.ramp.blue, sizeof(short) * ramp->size); + return GLFW_TRUE; +} + +void _glfwSetGammaRampNull(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + if (monitor->null.ramp.size != ramp->size) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Null: Gamma ramp size must match current ramp size"); + return; + } + + memcpy(monitor->null.ramp.red, ramp->red, sizeof(short) * ramp->size); + memcpy(monitor->null.ramp.green, ramp->green, sizeof(short) * ramp->size); + memcpy(monitor->null.ramp.blue, ramp->blue, sizeof(short) * ramp->size); } diff --git a/raylib/external/glfw/src/null_platform.h b/raylib/external/glfw/src/null_platform.h index 2d67c50..4843a76 100644 --- a/raylib/external/glfw/src/null_platform.h +++ b/raylib/external/glfw/src/null_platform.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -25,38 +25,247 @@ // //======================================================================== -#include +#define GLFW_NULL_WINDOW_STATE _GLFWwindowNull null; +#define GLFW_NULL_LIBRARY_WINDOW_STATE _GLFWlibraryNull null; +#define GLFW_NULL_MONITOR_STATE _GLFWmonitorNull null; -#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null +#define GLFW_NULL_CONTEXT_STATE +#define GLFW_NULL_CURSOR_STATE +#define GLFW_NULL_LIBRARY_CONTEXT_STATE -#define _GLFW_PLATFORM_CONTEXT_STATE -#define _GLFW_PLATFORM_MONITOR_STATE -#define _GLFW_PLATFORM_CURSOR_STATE -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE -#define _GLFW_EGL_CONTEXT_STATE -#define _GLFW_EGL_LIBRARY_CONTEXT_STATE - -#include "osmesa_context.h" -#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 +#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 // Null-specific per-window data // typedef struct _GLFWwindowNull { - int width; - int height; + int xpos; + int ypos; + int width; + int height; + GLFWbool visible; + GLFWbool iconified; + GLFWbool maximized; + GLFWbool resizable; + GLFWbool decorated; + GLFWbool floating; + GLFWbool transparent; + float opacity; } _GLFWwindowNull; +// Null-specific per-monitor data +// +typedef struct _GLFWmonitorNull +{ + GLFWgammaramp ramp; +} _GLFWmonitorNull; + +// Null-specific global data +// +typedef struct _GLFWlibraryNull +{ + int xcursor; + 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 6a54cfe..cd23ae0 100644 --- a/raylib/external/glfw/src/null_window.c +++ b/raylib/external/glfw/src/null_window.c @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,12 +28,80 @@ #include "internal.h" +#include + +static void applySizeLimits(_GLFWwindow* window, int* width, int* height) +{ + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) + { + const float ratio = (float) window->numer / (float) window->denom; + *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->minheight != GLFW_DONT_CARE) + *height = _glfw_min(*height, window->minheight); + else if (window->maxheight != GLFW_DONT_CARE) + *height = _glfw_max(*height, window->maxheight); +} + +static void fitToMonitor(_GLFWwindow* window) +{ + GLFWvidmode mode; + _glfwGetVideoModeNull(window->monitor, &mode); + _glfwGetMonitorPosNull(window->monitor, + &window->null.xpos, + &window->null.ypos); + window->null.width = mode.width; + window->null.height = mode.height; +} + +static void acquireMonitorNull(_GLFWwindow* window) +{ + _glfwInputMonitorWindow(window->monitor, window); +} + +static void releaseMonitorNull(_GLFWwindow* window) +{ + if (window->monitor->window != window) + return; + + _glfwInputMonitorWindow(window->monitor, NULL); +} static int createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { - window->null.width = wndconfig->width; - window->null.height = wndconfig->height; + if (window->monitor) + 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.width = wndconfig->width; + window->null.height = wndconfig->height; + } + + window->null.visible = wndconfig->visible; + window->null.decorated = wndconfig->decorated; + window->null.maximized = wndconfig->maximized; + window->null.floating = wndconfig->floating; + window->null.transparent = fbconfig->transparent; + window->null.opacity = 1.f; return GLFW_TRUE; } @@ -42,12 +111,12 @@ static int createNativeWindow(_GLFWwindow* window, ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformCreateWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { - if (!createNativeWindow(window, wndconfig)) + if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -60,48 +129,120 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } - else + else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { - _glfwInputError(GLFW_API_UNAVAILABLE, "Null: EGL not available"); + if (!_glfwInitEGL()) + return GLFW_FALSE; + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + + if (!_glfwRefreshContextAttribs(window, ctxconfig)) 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); } } return GLFW_TRUE; } -void _glfwPlatformDestroyWindow(_GLFWwindow* window) +void _glfwDestroyWindowNull(_GLFWwindow* window) { + if (window->monitor) + releaseMonitorNull(window); + + if (_glfw.null.focusedWindow == window) + _glfw.null.focusedWindow = NULL; + if (window->context.destroy) window->context.destroy(window); } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title) { } -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, - const GLFWimage* images) +void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images) { } -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwSetWindowMonitorNull(_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); + } + + return; + } + + if (window->monitor) + releaseMonitorNull(window); + + _glfwInputWindowMonitor(window, monitor); + + if (window->monitor) + { + window->null.visible = GLFW_TRUE; + acquireMonitorNull(window); + fitToMonitor(window); + } + else + { + _glfwSetWindowPosNull(window, xpos, ypos); + _glfwSetWindowSizeNull(window, width, height); + } } -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos) { + if (xpos) + *xpos = window->null.xpos; + if (ypos) + *ypos = window->null.ypos; } -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos) { + if (window->monitor) + return; + + if (window->null.xpos != xpos || window->null.ypos != ypos) + { + window->null.xpos = xpos; + window->null.ypos = ypos; + _glfwInputWindowPos(window, xpos, ypos); + } } -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; @@ -109,23 +250,40 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) *height = window->null.height; } -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height) { - window->null.width = width; - window->null.height = height; + if (window->monitor) + return; + + if (window->null.width != width || window->null.height != height) + { + window->null.width = width; + window->null.height = height; + _glfwInputFramebufferSize(window, width, height); + _glfwInputWindowDamage(window); + _glfwInputWindowSize(window, width, height); + } } -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwSetWindowSizeLimitsNull(_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); } -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) +void _glfwSetWindowAspectRatioNull(_GLFWwindow* window, int n, int d) { + int width = window->null.width; + int height = window->null.height; + applySizeLimits(window, &width, &height); + _glfwSetWindowSizeNull(window, width, height); } -void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->null.width; @@ -133,14 +291,35 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh *height = window->null.height; } -void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwGetWindowFrameSizeNull(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { + if (window->null.decorated && !window->monitor) + { + if (left) + *left = 1; + if (top) + *top = 10; + if (right) + *right = 1; + if (bottom) + *bottom = 1; + } + else + { + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + } } -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = 1.f; @@ -148,174 +327,394 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, *yscale = 1.f; } -void _glfwPlatformIconifyWindow(_GLFWwindow* window) +void _glfwIconifyWindowNull(_GLFWwindow* window) +{ + if (_glfw.null.focusedWindow == window) + { + _glfw.null.focusedWindow = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + if (!window->null.iconified) + { + window->null.iconified = GLFW_TRUE; + _glfwInputWindowIconify(window, GLFW_TRUE); + + if (window->monitor) + releaseMonitorNull(window); + } +} + +void _glfwRestoreWindowNull(_GLFWwindow* window) +{ + if (window->null.iconified) + { + window->null.iconified = GLFW_FALSE; + _glfwInputWindowIconify(window, GLFW_FALSE); + + if (window->monitor) + acquireMonitorNull(window); + } + else if (window->null.maximized) + { + window->null.maximized = GLFW_FALSE; + _glfwInputWindowMaximize(window, GLFW_FALSE); + } +} + +void _glfwMaximizeWindowNull(_GLFWwindow* window) +{ + if (!window->null.maximized) + { + window->null.maximized = GLFW_TRUE; + _glfwInputWindowMaximize(window, GLFW_TRUE); + } +} + +GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window) +{ + return window->null.maximized; +} + +GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window) +{ + return _glfw.null.xcursor >= window->null.xpos && + _glfw.null.ycursor >= window->null.ypos && + _glfw.null.xcursor <= window->null.xpos + window->null.width - 1 && + _glfw.null.ycursor <= window->null.ypos + window->null.height - 1; +} + +GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window) +{ + return window->null.transparent; +} + +void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled) +{ + window->null.resizable = enabled; +} + +void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled) +{ + window->null.decorated = enabled; +} + +void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled) +{ + window->null.floating = enabled; +} + +void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled) { } -void _glfwPlatformRestoreWindow(_GLFWwindow* window) +float _glfwGetWindowOpacityNull(_GLFWwindow* window) +{ + return window->null.opacity; +} + +void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity) +{ + window->null.opacity = opacity; +} + +void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled) { } -void _glfwPlatformMaximizeWindow(_GLFWwindow* window) -{ -} - -int _glfwPlatformWindowMaximized(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -int _glfwPlatformWindowHovered(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) -{ -} - -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) -{ -} - -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) -{ -} - -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) -{ - return 1.f; -} - -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) -{ -} - -void _glfwPlatformShowWindow(_GLFWwindow* window) -{ -} - - -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) -{ -} - -void _glfwPlatformUnhideWindow(_GLFWwindow* window) -{ -} - -void _glfwPlatformHideWindow(_GLFWwindow* window) -{ -} - -void _glfwPlatformFocusWindow(_GLFWwindow* window) -{ -} - -int _glfwPlatformWindowFocused(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -int _glfwPlatformWindowIconified(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -int _glfwPlatformWindowVisible(_GLFWwindow* window) -{ - return GLFW_FALSE; -} - -void _glfwPlatformPollEvents(void) -{ -} - -void _glfwPlatformWaitEvents(void) -{ -} - -void _glfwPlatformWaitEventsTimeout(double timeout) -{ -} - -void _glfwPlatformPostEmptyEvent(void) -{ -} - -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) -{ -} - -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) -{ -} - -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) -{ -} - -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +GLFWbool _glfwRawMouseMotionSupportedNull(void) { return GLFW_TRUE; } -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +void _glfwShowWindowNull(_GLFWwindow* window) +{ + window->null.visible = GLFW_TRUE; +} + +void _glfwRequestWindowAttentionNull(_GLFWwindow* window) +{ +} + +void _glfwHideWindowNull(_GLFWwindow* window) +{ + if (_glfw.null.focusedWindow == window) + { + _glfw.null.focusedWindow = NULL; + _glfwInputWindowFocus(window, GLFW_FALSE); + } + + window->null.visible = GLFW_FALSE; +} + +void _glfwFocusWindowNull(_GLFWwindow* window) +{ + _GLFWwindow* previous; + + if (_glfw.null.focusedWindow == window) + return; + + if (!window->null.visible) + return; + + previous = _glfw.null.focusedWindow; + _glfw.null.focusedWindow = window; + + if (previous) + { + _glfwInputWindowFocus(previous, GLFW_FALSE); + if (previous->monitor && previous->autoIconify) + _glfwIconifyWindowNull(previous); + } + + _glfwInputWindowFocus(window, GLFW_TRUE); +} + +GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window) +{ + return _glfw.null.focusedWindow == window; +} + +GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window) +{ + return window->null.iconified; +} + +GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window) +{ + return window->null.visible; +} + +void _glfwPollEventsNull(void) +{ +} + +void _glfwWaitEventsNull(void) +{ +} + +void _glfwWaitEventsTimeoutNull(double timeout) +{ +} + +void _glfwPostEmptyEventNull(void) +{ +} + +void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos) +{ + if (xpos) + *xpos = _glfw.null.xcursor - window->null.xpos; + if (ypos) + *ypos = _glfw.null.ycursor - window->null.ypos; +} + +void _glfwSetCursorPosNull(_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) +{ +} + +GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { return GLFW_TRUE; } -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape) +{ + return GLFW_TRUE; +} + +void _glfwDestroyCursorNull(_GLFWcursor* cursor) { } -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor) { } -void _glfwPlatformSetClipboardString(const char* string) +void _glfwSetClipboardStringNull(const char* string) { + char* copy = _glfw_strdup(string); + _glfw_free(_glfw.null.clipboardString); + _glfw.null.clipboardString = copy; } -const char* _glfwPlatformGetClipboardString(void) +const char* _glfwGetClipboardStringNull(void) { + return _glfw.null.clipboardString; +} + +EGLenum _glfwGetEGLPlatformNull(EGLint** attribs) +{ + 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: + return "'"; + case GLFW_NULL_SC_COMMA: + return ","; + case GLFW_NULL_SC_MINUS: + case GLFW_NULL_SC_KP_SUBTRACT: + return "-"; + case GLFW_NULL_SC_PERIOD: + case GLFW_NULL_SC_KP_DECIMAL: + return "."; + case GLFW_NULL_SC_SLASH: + case GLFW_NULL_SC_KP_DIVIDE: + return "/"; + case GLFW_NULL_SC_SEMICOLON: + return ";"; + case GLFW_NULL_SC_EQUAL: + case GLFW_NULL_SC_KP_EQUAL: + return "="; + case GLFW_NULL_SC_LEFT_BRACKET: + return "["; + case GLFW_NULL_SC_RIGHT_BRACKET: + return "]"; + case GLFW_NULL_SC_KP_MULTIPLY: + return "*"; + case GLFW_NULL_SC_KP_ADD: + return "+"; + case GLFW_NULL_SC_BACKSLASH: + case GLFW_NULL_SC_WORLD_1: + case GLFW_NULL_SC_WORLD_2: + return "\\"; + case GLFW_NULL_SC_0: + case GLFW_NULL_SC_KP_0: + return "0"; + case GLFW_NULL_SC_1: + case GLFW_NULL_SC_KP_1: + return "1"; + case GLFW_NULL_SC_2: + case GLFW_NULL_SC_KP_2: + return "2"; + case GLFW_NULL_SC_3: + case GLFW_NULL_SC_KP_3: + return "3"; + case GLFW_NULL_SC_4: + case GLFW_NULL_SC_KP_4: + return "4"; + case GLFW_NULL_SC_5: + case GLFW_NULL_SC_KP_5: + return "5"; + case GLFW_NULL_SC_6: + case GLFW_NULL_SC_KP_6: + return "6"; + case GLFW_NULL_SC_7: + case GLFW_NULL_SC_KP_7: + return "7"; + case GLFW_NULL_SC_8: + case GLFW_NULL_SC_KP_8: + return "8"; + case GLFW_NULL_SC_9: + case GLFW_NULL_SC_KP_9: + return "9"; + case GLFW_NULL_SC_A: + return "a"; + case GLFW_NULL_SC_B: + return "b"; + case GLFW_NULL_SC_C: + return "c"; + case GLFW_NULL_SC_D: + return "d"; + case GLFW_NULL_SC_E: + return "e"; + case GLFW_NULL_SC_F: + return "f"; + case GLFW_NULL_SC_G: + return "g"; + case GLFW_NULL_SC_H: + return "h"; + case GLFW_NULL_SC_I: + return "i"; + case GLFW_NULL_SC_J: + return "j"; + case GLFW_NULL_SC_K: + return "k"; + case GLFW_NULL_SC_L: + return "l"; + case GLFW_NULL_SC_M: + return "m"; + case GLFW_NULL_SC_N: + return "n"; + case GLFW_NULL_SC_O: + return "o"; + case GLFW_NULL_SC_P: + return "p"; + case GLFW_NULL_SC_Q: + return "q"; + case GLFW_NULL_SC_R: + return "r"; + case GLFW_NULL_SC_S: + return "s"; + case GLFW_NULL_SC_T: + return "t"; + case GLFW_NULL_SC_U: + return "u"; + case GLFW_NULL_SC_V: + return "v"; + case GLFW_NULL_SC_W: + return "w"; + case GLFW_NULL_SC_X: + return "x"; + case GLFW_NULL_SC_Y: + return "y"; + case GLFW_NULL_SC_Z: + return "z"; + } + return NULL; } -const char* _glfwPlatformGetScancodeName(int scancode) +int _glfwGetKeyScancodeNull(int key) { - return ""; + return _glfw.null.scancodes[key]; } -int _glfwPlatformGetKeyScancode(int key) -{ - return -1; -} - -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +void _glfwGetRequiredInstanceExtensionsNull(char** extensions) { } -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { return GLFW_FALSE; } -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { // This seems like the most appropriate error to return here - return VK_ERROR_INITIALIZATION_FAILED; + 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 a7de33f..2f12adf 100644 --- a/raylib/external/glfw/src/osmesa_context.c +++ b/raylib/external/glfw/src/osmesa_context.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 OSMesa - www.glfw.org +// GLFW 3.4 OSMesa - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -25,29 +25,28 @@ // //======================================================================== +#include "internal.h" + #include #include #include -#include "internal.h" - - static void makeContextCurrentOSMesa(_GLFWwindow* window) { if (window) { int width, height; - _glfwPlatformGetFramebufferSize(window, &width, &height); + _glfw.platform.getFramebufferSize(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)) { - free(window->context.osmesa.buffer); + _glfw_free(window->context.osmesa.buffer); // Allocate the new buffer (width * height * 8-bit RGBA) - window->context.osmesa.buffer = calloc(4, width * height); + window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height); window->context.osmesa.width = width; window->context.osmesa.height = height; } @@ -81,7 +80,7 @@ static void destroyContextOSMesa(_GLFWwindow* window) if (window->context.osmesa.buffer) { - free(window->context.osmesa.buffer); + _glfw_free(window->context.osmesa.buffer); window->context.osmesa.width = 0; window->context.osmesa.height = 0; } @@ -122,6 +121,8 @@ 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", @@ -134,7 +135,7 @@ GLFWbool _glfwInitOSMesa(void) for (i = 0; sonames[i]; i++) { - _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); + _glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]); if (_glfw.osmesa.handle) break; } @@ -146,19 +147,19 @@ GLFWbool _glfwInitOSMesa(void) } _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt"); _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs"); _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext"); _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent"); _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress) - _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); + _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress"); if (!_glfw.osmesa.CreateContextExt || !_glfw.osmesa.DestroyContext || @@ -181,14 +182,14 @@ void _glfwTerminateOSMesa(void) { if (_glfw.osmesa.handle) { - _glfw_dlclose(_glfw.osmesa.handle); + _glfwPlatformFreeModule(_glfw.osmesa.handle); _glfw.osmesa.handle = NULL; } } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ - assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } @@ -217,34 +218,34 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, { int index = 0, attribs[40]; - setAttrib(OSMESA_FORMAT, OSMESA_RGBA); - setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits); - setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits); - setAttrib(OSMESA_ACCUM_BITS, accumBits); + 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); if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) { - setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE); + SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE); } else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) { - setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); + SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE); } if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); - setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); + SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major); + SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor); } if (ctxconfig->forward) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, - "OSMesa: Foward-compatible contexts not supported"); + "OSMesa: Forward-compatible contexts not supported"); return GLFW_FALSE; } - setAttrib(0, 0); + SET_ATTRIB(0, 0); window->context.osmesa.handle = OSMesaCreateContextAttribs(attribs, share); @@ -283,7 +284,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib +#undef SET_ATTRIB ////////////////////////////////////////////////////////////////////////// @@ -300,6 +301,12 @@ 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)) @@ -333,6 +340,12 @@ 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)) @@ -359,7 +372,7 @@ GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API) + if (window->context.source != GLFW_OSMESA_CONTEXT_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 deleted file mode 100644 index 07bb469..0000000 --- a/raylib/external/glfw/src/osmesa_context.h +++ /dev/null @@ -1,94 +0,0 @@ -//======================================================================== -// GLFW 3.3 OSMesa - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2016 Google Inc. -// Copyright (c) 2006-2016 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 - -#define _GLFW_OSMESA_CONTEXT_STATE _GLFWcontextOSMesa osmesa -#define _GLFW_OSMESA_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa - - -// 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 new file mode 100644 index 0000000..c4b0a36 --- /dev/null +++ b/raylib/external/glfw/src/platform.c @@ -0,0 +1,204 @@ +//======================================================================== +// 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 new file mode 100644 index 0000000..75652dc --- /dev/null +++ b/raylib/external/glfw/src/platform.h @@ -0,0 +1,212 @@ +//======================================================================== +// 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/wayland-pointer-constraints-unstable-v1-client-protocol.c b/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h similarity index 63% rename from raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c rename to raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h index c46152e..4184538 100644 --- a/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c +++ b/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol-code.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ /* * Copyright © 2014 Jonas Ådahl @@ -24,17 +24,28 @@ * 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 *wl_pc_types[] = { +static const struct wl_interface *pointer_constraints_unstable_v1_types[] = { NULL, NULL, &zwp_locked_pointer_v1_interface, @@ -52,45 +63,45 @@ static const struct wl_interface *wl_pc_types[] = { }; static const struct wl_message zwp_pointer_constraints_v1_requests[] = { - { "destroy", "", wl_pc_types + 0 }, - { "lock_pointer", "noo?ou", wl_pc_types + 2 }, - { "confine_pointer", "noo?ou", wl_pc_types + 7 }, + { "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 }, }; -WL_EXPORT const struct wl_interface zwp_pointer_constraints_v1_interface = { +WL_PRIVATE 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", "", wl_pc_types + 0 }, - { "set_cursor_position_hint", "ff", wl_pc_types + 0 }, - { "set_region", "?o", wl_pc_types + 12 }, + { "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 }, }; static const struct wl_message zwp_locked_pointer_v1_events[] = { - { "locked", "", wl_pc_types + 0 }, - { "unlocked", "", wl_pc_types + 0 }, + { "locked", "", pointer_constraints_unstable_v1_types + 0 }, + { "unlocked", "", pointer_constraints_unstable_v1_types + 0 }, }; -WL_EXPORT const struct wl_interface zwp_locked_pointer_v1_interface = { +WL_PRIVATE 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", "", wl_pc_types + 0 }, - { "set_region", "?o", wl_pc_types + 13 }, + { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, + { "set_region", "?o", pointer_constraints_unstable_v1_types + 13 }, }; static const struct wl_message zwp_confined_pointer_v1_events[] = { - { "confined", "", wl_pc_types + 0 }, - { "unconfined", "", wl_pc_types + 0 }, + { "confined", "", pointer_constraints_unstable_v1_types + 0 }, + { "unconfined", "", pointer_constraints_unstable_v1_types + 0 }, }; -WL_EXPORT const struct wl_interface zwp_confined_pointer_v1_interface = { +WL_PRIVATE 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/wayland-pointer-constraints-unstable-v1-client-protocol.h b/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h similarity index 88% rename from raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h index 37e0c3a..dd7b871 100644 --- a/raylib/external/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/pointer-constraints-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ #ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H #define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -73,6 +73,8 @@ 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 @@ -111,6 +113,9 @@ 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 @@ -169,6 +174,9 @@ 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 @@ -213,6 +221,7 @@ 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 @@ -235,15 +244,30 @@ enum zwp_pointer_constraints_v1_error { #define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM /** * @ingroup iface_zwp_pointer_constraints_v1 - * the pointer constraint may reactivate + * constraint lifetime * - * 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. + * These values represent different lifetime semantics. They are passed + * as arguments to the factory requests to specify how the constraint + * lifetimes should be managed. */ 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 */ @@ -295,10 +319,8 @@ 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((struct wl_proxy *) zwp_pointer_constraints_v1, - ZWP_POINTER_CONSTRAINTS_V1_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) 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); } /** @@ -344,8 +366,8 @@ zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_p { struct wl_proxy *id; - 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); + 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); return (struct zwp_locked_pointer_v1 *) id; } @@ -376,8 +398,8 @@ zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zw { struct wl_proxy *id; - 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); + 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); return (struct zwp_confined_pointer_v1 *) id; } @@ -475,10 +497,8 @@ 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((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) 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); } /** @@ -492,15 +512,14 @@ 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. The new hint will only take - * effect when the associated surface gets it pending state applied. See - * wl_surface.commit for details. + * The cursor position hint is double-buffered state, see + * wl_surface.commit. */ 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((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, surface_x, 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); } /** @@ -508,17 +527,15 @@ 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. The new lock region will - * only take effect when the associated surface gets its pending state - * applied. See wl_surface.commit for details. + * The new lock region is double-buffered, see wl_surface.commit. * * 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((struct wl_proxy *) zwp_locked_pointer_v1, - ZWP_LOCKED_POINTER_V1_SET_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); } /** @@ -609,10 +626,8 @@ 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((struct wl_proxy *) zwp_confined_pointer_v1, - ZWP_CONFINED_POINTER_V1_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) 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); } /** @@ -620,9 +635,7 @@ 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. The new confine region will - * only take effect when the associated surface gets its pending state - * applied. See wl_surface.commit for details. + * The new confine region is double-buffered, see wl_surface.commit. * * 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 @@ -638,8 +651,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((struct wl_proxy *) zwp_confined_pointer_v1, - ZWP_CONFINED_POINTER_V1_SET_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); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/posix_module.c b/raylib/external/glfw/src/posix_module.c new file mode 100644 index 0000000..7d81c67 --- /dev/null +++ b/raylib/external/glfw/src/posix_module.c @@ -0,0 +1,53 @@ +//======================================================================== +// 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 new file mode 100644 index 0000000..b53e36e --- /dev/null +++ b/raylib/external/glfw/src/posix_poll.c @@ -0,0 +1,83 @@ +//======================================================================== +// 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 new file mode 100644 index 0000000..4bdd244 --- /dev/null +++ b/raylib/external/glfw/src/posix_poll.h @@ -0,0 +1,30 @@ +//======================================================================== +// 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 ce0bc39..3c355a5 100644 --- a/raylib/external/glfw/src/posix_thread.c +++ b/raylib/external/glfw/src/posix_thread.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 POSIX - www.glfw.org +// GLFW 3.4 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(GLFW_BUILD_POSIX_THREAD) + #include #include @@ -101,3 +103,5 @@ 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 bdddf41..5a5d7b7 100644 --- a/raylib/external/glfw/src/posix_thread.h +++ b/raylib/external/glfw/src/posix_thread.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 POSIX - www.glfw.org +// GLFW 3.4 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,8 +27,8 @@ #include -#define _GLFW_PLATFORM_TLS_STATE _GLFWtlsPOSIX posix -#define _GLFW_PLATFORM_MUTEX_STATE _GLFWmutexPOSIX posix +#define GLFW_POSIX_TLS_STATE _GLFWtlsPOSIX posix; +#define GLFW_POSIX_MUTEX_STATE _GLFWmutexPOSIX posix; // POSIX-specific thread local storage data @@ -37,7 +37,6 @@ typedef struct _GLFWtlsPOSIX { GLFWbool allocated; pthread_key_t key; - } _GLFWtlsPOSIX; // POSIX-specific mutex data @@ -46,6 +45,5 @@ 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 00b2831..a172408 100644 --- a/raylib/external/glfw/src/posix_time.c +++ b/raylib/external/glfw/src/posix_time.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 POSIX - www.glfw.org +// GLFW 3.4 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,55 +27,33 @@ #include "internal.h" +#if defined(GLFW_BUILD_POSIX_TIMER) + +#include #include -#include - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Initialise timer -// -void _glfwInitTimerPOSIX(void) -{ -#if defined(CLOCK_MONOTONIC) - 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) { -#if defined(CLOCK_MONOTONIC) - 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; - } + 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; } uint64_t _glfwPlatformGetTimerFrequency(void) @@ -83,3 +61,5 @@ 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 f1a69eb..94374ad 100644 --- a/raylib/external/glfw/src/posix_time.h +++ b/raylib/external/glfw/src/posix_time.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 POSIX - www.glfw.org +// GLFW 3.4 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -25,20 +25,17 @@ // //======================================================================== -#define _GLFW_PLATFORM_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix +#define GLFW_POSIX_LIBRARY_TIMER_STATE _GLFWtimerPOSIX posix; #include +#include // POSIX-specific global timer data // typedef struct _GLFWtimerPOSIX { - GLFWbool monotonic; + clockid_t clock; uint64_t frequency; - } _GLFWtimerPOSIX; - -void _glfwInitTimerPOSIX(void); - diff --git a/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c b/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h similarity index 69% rename from raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c rename to raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h index 0852c9a..605149b 100644 --- a/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c +++ b/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol-code.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ /* * Copyright © 2014 Jonas Ådahl @@ -24,14 +24,25 @@ * 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 *wl_rp_types[] = { +static const struct wl_interface *relative_pointer_unstable_v1_types[] = { NULL, NULL, NULL, @@ -43,25 +54,25 @@ static const struct wl_interface *wl_rp_types[] = { }; static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = { - { "destroy", "", wl_rp_types + 0 }, - { "get_relative_pointer", "no", wl_rp_types + 6 }, + { "destroy", "", relative_pointer_unstable_v1_types + 0 }, + { "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 }, }; -WL_EXPORT const struct wl_interface zwp_relative_pointer_manager_v1_interface = { +WL_PRIVATE 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", "", wl_rp_types + 0 }, + { "destroy", "", relative_pointer_unstable_v1_types + 0 }, }; static const struct wl_message zwp_relative_pointer_v1_events[] = { - { "relative_motion", "uuffff", wl_rp_types + 0 }, + { "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 }, }; -WL_EXPORT const struct wl_interface zwp_relative_pointer_v1_interface = { +WL_PRIVATE 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/wayland-relative-pointer-unstable-v1-client-protocol.h b/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h similarity index 92% rename from raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h rename to raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h index 7c74dbe..5c79482 100644 --- a/raylib/external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h +++ b/raylib/external/glfw/src/relative-pointer-unstable-v1-client-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.14.0 */ +/* Generated by wayland-scanner 1.23.1 */ #ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H #define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H @@ -73,6 +73,8 @@ 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 @@ -89,6 +91,9 @@ 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 @@ -109,6 +114,7 @@ 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 @@ -152,10 +158,8 @@ 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((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); + 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); } /** @@ -169,8 +173,8 @@ zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer { struct wl_proxy *id; - 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); + 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); return (struct zwp_relative_pointer_v1 *) id; } @@ -282,10 +286,8 @@ 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((struct wl_proxy *) zwp_relative_pointer_v1, - ZWP_RELATIVE_POINTER_V1_DESTROY); - - wl_proxy_destroy((struct wl_proxy *) 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); } #ifdef __cplusplus diff --git a/raylib/external/glfw/src/vendor.go b/raylib/external/glfw/src/vendor.go new file mode 100644 index 0000000..0fb2a0f --- /dev/null +++ b/raylib/external/glfw/src/vendor.go @@ -0,0 +1,4 @@ +//go:build required +// +build required + +package vendor diff --git a/raylib/external/glfw/src/viewporter-client-protocol-code.h b/raylib/external/glfw/src/viewporter-client-protocol-code.h new file mode 100644 index 0000000..d685858 --- /dev/null +++ b/raylib/external/glfw/src/viewporter-client-protocol-code.h @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2013-2016 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_surface_interface; +extern const struct wl_interface wp_viewport_interface; + +static const struct wl_interface *viewporter_types[] = { + NULL, + NULL, + NULL, + NULL, + &wp_viewport_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_viewporter_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "get_viewport", "no", viewporter_types + 4 }, +}; + +WL_PRIVATE 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 }, +}; + +WL_PRIVATE 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/viewporter-client-protocol.h new file mode 100644 index 0000000..f286095 --- /dev/null +++ b/raylib/external/glfw/src/viewporter-client-protocol.h @@ -0,0 +1,394 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef VIEWPORTER_CLIENT_PROTOCOL_H +#define VIEWPORTER_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_viewporter The viewporter protocol + * @section page_ifaces_viewporter Interfaces + * - @subpage page_iface_wp_viewporter - surface cropping and scaling + * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface + * @section page_copyright_viewporter Copyright + *
+ *
+ * Copyright © 2013-2016 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_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 + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + * @section page_iface_wp_viewporter_api API + * See @ref iface_wp_viewporter. + */ +/** + * @defgroup iface_wp_viewporter The wp_viewporter interface + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * 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 + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * 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. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + * @section page_iface_wp_viewport_api API + * See @ref iface_wp_viewport. + */ +/** + * @defgroup iface_wp_viewport The wp_viewport interface + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * 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. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * 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 +enum wp_viewporter_error { + /** + * the surface already has a viewport object associated + */ + WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0, +}; +#endif /* WP_VIEWPORTER_ERROR_ENUM */ + +#define WP_VIEWPORTER_DESTROY 0 +#define WP_VIEWPORTER_GET_VIEWPORT 1 + + +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewporter */ +static inline void +wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data); +} + +/** @ingroup iface_wp_viewporter */ +static inline void * +wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter); +} + +static inline uint32_t +wp_viewporter_get_version(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewporter); +} + +/** + * @ingroup iface_wp_viewporter + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other objects, + * wp_viewport objects included. + */ +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); +} + +/** + * @ingroup iface_wp_viewporter + * + * Instantiate an interface extension for the given wl_surface to + * crop and scale its content. If the given wl_surface already has + * a wp_viewport object associated, the viewport_exists + * protocol error is raised. + */ +static inline struct wp_viewport * +wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface) +{ + 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); + + return (struct wp_viewport *) id; +} + +#ifndef WP_VIEWPORT_ERROR_ENUM +#define WP_VIEWPORT_ERROR_ENUM +enum wp_viewport_error { + /** + * negative or zero values in width or height + */ + WP_VIEWPORT_ERROR_BAD_VALUE = 0, + /** + * destination size is not integer + */ + WP_VIEWPORT_ERROR_BAD_SIZE = 1, + /** + * source rectangle extends outside of the content area + */ + WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2, + /** + * the wl_surface was destroyed + */ + WP_VIEWPORT_ERROR_NO_SURFACE = 3, +}; +#endif /* WP_VIEWPORT_ERROR_ENUM */ + +#define WP_VIEWPORT_DESTROY 0 +#define WP_VIEWPORT_SET_SOURCE 1 +#define WP_VIEWPORT_SET_DESTINATION 2 + + +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewport */ +static inline void +wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data); +} + +/** @ingroup iface_wp_viewport */ +static inline void * +wp_viewport_get_user_data(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport); +} + +static inline uint32_t +wp_viewport_get_version(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewport); +} + +/** + * @ingroup iface_wp_viewport + * + * The associated wl_surface's crop and scale state is removed. + * The change is applied on the next wl_surface.commit. + */ +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); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the source rectangle of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If all of x, y, width and height are -1.0, the source rectangle is + * unset instead. Any other set of values where width or height are zero + * 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. + */ +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); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the destination size of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If width is -1 and height is -1, the destination size is unset + * instead. Any other pair of values for width and height that + * contains zero or negative values raises the bad_value protocol + * error. + * + * The crop and scale state is double-buffered, see 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); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/raylib/external/glfw/src/vulkan.c b/raylib/external/glfw/src/vulkan.c index debc0ef..d9fabde 100644 --- a/raylib/external/glfw/src/vulkan.c +++ b/raylib/external/glfw/src/vulkan.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -43,43 +43,52 @@ GLFWbool _glfwInitVulkan(int mode) { VkResult err; VkExtensionProperties* ep; + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; uint32_t i, count; if (_glfw.vk.available) return GLFW_TRUE; -#if !defined(_GLFW_VULKAN_STATIC) + if (_glfw.hints.init.vulkanLoader) + _glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader; + else + { #if defined(_GLFW_VULKAN_LIBRARY) - _glfw.vk.handle = _glfw_dlopen(_GLFW_VULKAN_LIBRARY); + _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY); #elif defined(_GLFW_WIN32) - _glfw.vk.handle = _glfw_dlopen("vulkan-1.dll"); + _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll"); #elif defined(_GLFW_COCOA) - _glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib"); + _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"); #else - _glfw.vk.handle = _glfw_dlopen("libvulkan.so.1"); + _glfw.vk.handle = _glfwPlatformLoadModule("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; + 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; + } } - _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) + vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties"); - if (!_glfw.vk.EnumerateInstanceExtensionProperties) + if (!vkEnumerateInstanceExtensionProperties) { _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); @@ -87,7 +96,6 @@ GLFWbool _glfwInitVulkan(int mode) _glfwTerminateVulkan(); return GLFW_FALSE; } -#endif // _GLFW_VULKAN_STATIC err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); if (err) @@ -104,7 +112,7 @@ GLFWbool _glfwInitVulkan(int mode) return GLFW_FALSE; } - ep = calloc(count, sizeof(VkExtensionProperties)); + ep = _glfw_calloc(count, sizeof(VkExtensionProperties)); err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep); if (err) @@ -113,7 +121,7 @@ GLFWbool _glfwInitVulkan(int mode) "Vulkan: Failed to query instance extensions: %s", _glfwGetVulkanResultString(err)); - free(ep); + _glfw_free(ep); _glfwTerminateVulkan(); return GLFW_FALSE; } @@ -122,41 +130,33 @@ 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; -#elif defined(_GLFW_X11) + else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0) + _glfw.vk.EXT_metal_surface = GLFW_TRUE; 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; -#elif defined(_GLFW_MIR) - else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0) - _glfw.vk.KHR_mir_surface = GLFW_TRUE; -#endif } - free(ep); + _glfw_free(ep); _glfw.vk.available = GLFW_TRUE; - _glfwPlatformGetRequiredInstanceExtensions(_glfw.vk.extensions); + _glfw.platform.getRequiredInstanceExtensions(_glfw.vk.extensions); return GLFW_TRUE; } void _glfwTerminateVulkan(void) { -#if !defined(_GLFW_VULKAN_STATIC) if (_glfw.vk.handle) - _glfw_dlclose(_glfw.vk.handle); -#endif + _glfwPlatformFreeModule(_glfw.vk.handle); } const char* _glfwGetVulkanResultString(VkResult result) @@ -254,17 +254,16 @@ 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 (strcmp(procname, "vkGetInstanceProcAddr") == 0) - return (GLFWvkproc) vkGetInstanceProcAddr; + if (_glfw.vk.handle) + proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname); } -#else - if (!proc) - proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname); -#endif return proc; } @@ -288,9 +287,9 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, return GLFW_FALSE; } - return _glfwPlatformGetPhysicalDevicePresentationSupport(instance, - device, - queuefamily); + return _glfw.platform.getPhysicalDevicePresentationSupport(instance, + device, + queuefamily); } GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, @@ -324,6 +323,6 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR; } - return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface); + return _glfw.platform.createWindowSurface(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 new file mode 100644 index 0000000..d640bb4 --- /dev/null +++ b/raylib/external/glfw/src/wayland-client-protocol-code.h @@ -0,0 +1,538 @@ +/* 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 new file mode 100644 index 0000000..fadb460 --- /dev/null +++ b/raylib/external/glfw/src/wayland-client-protocol.h @@ -0,0 +1,6522 @@ +/* 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/wgl_context.c b/raylib/external/glfw/src/wgl_context.c index beccb13..8a23ffc 100644 --- a/raylib/external/glfw/src/wgl_context.c +++ b/raylib/external/glfw/src/wgl_context.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 WGL - www.glfw.org +// GLFW 3.4 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -27,114 +27,178 @@ #include "internal.h" +#if defined(_GLFW_WIN32) + #include -#include #include - -// Returns the specified attribute of the specified pixel format +// Return the value corresponding to the specified attribute // -static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) +static int findPixelFormatAttribValueWGL(const int* attribs, + int attribCount, + const int* values, + int attrib) { - int value = 0; + int i; - assert(_glfw.wgl.ARB_pixel_format); - - if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc, - pixelFormat, - 0, 1, &attrib, &value)) + for (i = 0; i < attribCount; i++) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "WGL: Failed to retrieve pixel format attribute"); - return 0; + if (attribs[i] == attrib) + return values[i]; } - return value; + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Unknown pixel format attribute requested"); + return 0; } +#define ADD_ATTRIB(a) \ +{ \ + assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[attribCount++] = a; \ +} +#define FIND_ATTRIB_VALUE(a) \ + findPixelFormatAttribValueWGL(attribs, attribCount, values, a) + // Return a list of available and usable framebuffer configs // -static int choosePixelFormat(_GLFWwindow* window, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +static int choosePixelFormatWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; - int i, pixelFormat, nativeCount, usableCount; + int i, pixelFormat, nativeCount, usableCount = 0, attribCount = 0; + 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) { - nativeCount = getPixelFormatAttrib(window, - 1, - WGL_NUMBER_PIXEL_FORMATS_ARB); - } - else - { - nativeCount = DescribePixelFormat(window->context.wgl.dc, - 1, - sizeof(PIXELFORMATDESCRIPTOR), - NULL); + 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)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attribute"); + return 0; + } + + nativeCount = _glfw_min(nativeCount, extensionCount); } - usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); - usableCount = 0; + usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); for (i = 0; i < nativeCount; i++) { - const int n = i + 1; _GLFWfbconfig* u = usableConfigs + usableCount; + pixelFormat = i + 1; if (_glfw.wgl.ARB_pixel_format) { // Get pixel format attributes through "modern" extension - if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) || - !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB)) + if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc, + pixelFormat, 0, + attribCount, + attribs, values)) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve pixel format attributes"); + + _glfw_free(usableConfigs); + return 0; + } + + if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) || + !FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB)) { continue; } - if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) != - WGL_TYPE_RGBA_ARB) - { + if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) continue; - } - if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == - WGL_NO_ACCELERATION_ARB) - { + if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) continue; - } - u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB); - u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB); - u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB); - u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB); + if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) + continue; - u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB); - u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_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->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB); - u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB); - u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB); - u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB); + u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB); + u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB); - u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_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); - if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB)) + u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB); + + if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB)) u->stereo = GLFW_TRUE; - if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) - u->doublebuffer = GLFW_TRUE; if (_glfw.wgl.ARB_multisample) - u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); + u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB); if (ctxconfig->client == GLFW_OPENGL_API) { if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB) { - if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) u->sRGB = GLFW_TRUE; } } @@ -142,11 +206,8 @@ static int choosePixelFormat(_GLFWwindow* window, { if (_glfw.wgl.EXT_colorspace) { - if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) == - WGL_COLORSPACE_SRGB_EXT) - { + if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT) u->sRGB = GLFW_TRUE; - } } } } @@ -157,11 +218,15 @@ static int choosePixelFormat(_GLFWwindow* window, PIXELFORMATDESCRIPTOR pfd; if (!DescribePixelFormat(window->context.wgl.dc, - n, + pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { - continue; + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to describe pixel format"); + + _glfw_free(usableConfigs); + return 0; } if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || @@ -179,6 +244,9 @@ static int choosePixelFormat(_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; @@ -196,11 +264,9 @@ static int choosePixelFormat(_GLFWwindow* window, if (pfd.dwFlags & PFD_STEREO) u->stereo = GLFW_TRUE; - if (pfd.dwFlags & PFD_DOUBLEBUFFER) - u->doublebuffer = GLFW_TRUE; } - u->handle = n; + u->handle = pixelFormat; usableCount++; } @@ -209,7 +275,7 @@ static int choosePixelFormat(_GLFWwindow* window, _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: The driver does not appear to support OpenGL"); - free(usableConfigs); + _glfw_free(usableConfigs); return 0; } @@ -219,16 +285,19 @@ static int choosePixelFormat(_GLFWwindow* window, _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "WGL: Failed to find a suitable pixel format"); - free(usableConfigs); + _glfw_free(usableConfigs); return 0; } pixelFormat = (int) closest->handle; - free(usableConfigs); + _glfw_free(usableConfigs); return pixelFormat; } +#undef ADD_ATTRIB +#undef FIND_ATTRIB_VALUE + static void makeContextCurrentWGL(_GLFWwindow* window) { if (window) @@ -256,12 +325,20 @@ static void makeContextCurrentWGL(_GLFWwindow* window) static void swapBuffersWGL(_GLFWwindow* window) { - // HACK: Use DwmFlush when desktop composition is enabled - if (_glfwIsCompositionEnabledWin32() && !window->monitor) + if (!window->monitor) { - int count = abs(window->context.wgl.interval); - while (count--) - DwmFlush(); + // HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7 + if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater()) + { + BOOL enabled = FALSE; + + if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + { + int count = abs(window->context.wgl.interval); + while (count--) + DwmFlush(); + } + } } SwapBuffers(window->context.wgl.dc); @@ -270,43 +347,40 @@ static void swapBuffersWGL(_GLFWwindow* window) static void swapIntervalWGL(int interval) { _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); window->context.wgl.interval = interval; - // HACK: Disable WGL swap interval when desktop composition is enabled to - // avoid interfering with DWM vsync - if (_glfwIsCompositionEnabledWin32() && !window->monitor) - interval = 0; + 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()) + { + BOOL enabled = FALSE; + + if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + interval = 0; + } + } if (_glfw.wgl.EXT_swap_control) - _glfw.wgl.SwapIntervalEXT(interval); + wglSwapIntervalEXT(interval); } static int extensionSupportedWGL(const char* extension) { - const char* extensions; - - if (_glfw.wgl.GetExtensionsStringEXT) - { - extensions = _glfw.wgl.GetExtensionsStringEXT(); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } + const char* extensions = NULL; if (_glfw.wgl.GetExtensionsStringARB) - { - extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC()); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } + extensions = wglGetExtensionsStringARB(wglGetCurrentDC()); + else if (_glfw.wgl.GetExtensionsStringEXT) + extensions = wglGetExtensionsStringEXT(); - return GLFW_FALSE; + if (!extensions) + return GLFW_FALSE; + + return _glfwStringInExtensionString(extension, extensions); } static GLFWglproc getProcAddressWGL(const char* procname) @@ -315,11 +389,9 @@ static GLFWglproc getProcAddressWGL(const char* procname) if (proc) return proc; - return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); + return (GLFWglproc) _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, procname); } -// Destroy the OpenGL context -// static void destroyContextWGL(_GLFWwindow* window) { if (window->context.wgl.handle) @@ -329,11 +401,6 @@ static void destroyContextWGL(_GLFWwindow* window) } } - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - // Initialize WGL // GLFWbool _glfwInitWGL(void) @@ -345,7 +412,7 @@ GLFWbool _glfwInitWGL(void) if (_glfw.wgl.instance) return GLFW_TRUE; - _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); + _glfw.wgl.instance = _glfwPlatformLoadModule("opengl32.dll"); if (!_glfw.wgl.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -354,26 +421,26 @@ GLFWbool _glfwInitWGL(void) } _glfw.wgl.CreateContext = (PFN_wglCreateContext) - GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglCreateContext"); _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) - GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglDeleteContext"); _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) - GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetProcAddress"); _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) - GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentDC"); _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext) - GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentContext"); _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) - GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); + _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglMakeCurrent"); _glfw.wgl.ShareLists = (PFN_wglShareLists) - GetProcAddress(_glfw.wgl.instance, "wglShareLists"); + _glfwPlatformGetModuleSymbol(_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 // NOTE: This code will accept the Microsoft GDI ICD; accelerated context // creation failure occurs during manual pixel format enumeration - dc = GetDC(_glfw.win32.helperWindowHandle);; + dc = GetDC(_glfw.win32.helperWindowHandle); ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); @@ -459,12 +526,12 @@ GLFWbool _glfwInitWGL(void) void _glfwTerminateWGL(void) { if (_glfw.wgl.instance) - FreeLibrary(_glfw.wgl.instance); + _glfwPlatformFreeModule(_glfw.wgl.instance); } -#define setAttrib(a, v) \ +#define SET_ATTRIB(a, v) \ { \ - assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ attribs[index++] = a; \ attribs[index++] = v; \ } @@ -491,7 +558,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_FALSE; } - pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig); + pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig); if (!pixelFormat) return GLFW_FALSE; @@ -570,13 +637,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) { - setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_NO_RESET_NOTIFICATION_ARB); + SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_NO_RESET_NOTIFICATION_ARB); } else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) { - setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - WGL_LOSE_CONTEXT_ON_RESET_ARB); + SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + WGL_LOSE_CONTEXT_ON_RESET_ARB); } flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; @@ -589,13 +656,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, { if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) { - setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); } else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) { - setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, - WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); } } } @@ -603,7 +670,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, if (ctxconfig->noerror) { if (_glfw.wgl.ARB_create_context_no_error) - setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); } // NOTE: Only request an explicitly versioned context when necessary, as @@ -611,21 +678,20 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, // highest version supported by the driver if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) - setAttrib(WGL_CONTEXT_FLAGS_ARB, flags); + SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags); if (mask) - setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask); - setAttrib(0, 0); + SET_ATTRIB(0, 0); window->context.wgl.handle = - _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, - share, attribs); + wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); if (!window->context.wgl.handle) { const DWORD error = GetLastError(); @@ -705,19 +771,21 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_TRUE; } -#undef setAttrib - - -////////////////////////////////////////////////////////////////////////// -////// GLFW native API ////// -////////////////////////////////////////////////////////////////////////// +#undef SET_ATTRIB GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.client == GLFW_NO_API) + 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) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -726,3 +794,5 @@ 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 deleted file mode 100644 index c754038..0000000 --- a/raylib/external/glfw/src/wgl_context.h +++ /dev/null @@ -1,159 +0,0 @@ -//======================================================================== -// GLFW 3.3 WGL - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 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 - -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*); - -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); - -// opengl32.dll function pointer typedefs -#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_RECREATION_NOT_NEEDED 0 -#define _GLFW_RECREATION_REQUIRED 1 -#define _GLFW_RECREATION_IMPOSSIBLE 2 - -#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 a913846..d86e35e 100644 --- a/raylib/external/glfw/src/win32_init.c +++ b/raylib/external/glfw/src/win32_init.c @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,8 +28,9 @@ #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}}; @@ -37,6 +39,10 @@ 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 @@ -62,33 +68,21 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) #endif // _GLFW_BUILD_DLL -// HACK: Define versionhelpers.h functions manually as MinGW lacks the header -BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) -{ - OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; - DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; - ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); - cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); - cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - return VerifyVersionInfoW(&osvi, mask, cond); -} - // Load necessary libraries (DLLs) // static GLFWbool loadLibraries(void) { - _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll"); - if (!_glfw.win32.winmm.instance) + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (const WCHAR*) &_glfw, + (HMODULE*) &_glfw.win32.instance)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to load winmm.dll"); + "Win32: Failed to retrieve own module handle"); return GLFW_FALSE; } - _glfw.win32.winmm.GetTime = (PFN_timeGetTime) - GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); - - _glfw.win32.user32.instance = LoadLibraryA("user32.dll"); + _glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll"); if (!_glfw.win32.user32.instance) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -97,15 +91,25 @@ static GLFWbool loadLibraries(void) } _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware) - GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDPIAware"); _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx) - GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); + _glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling) + _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "EnableNonClientDpiScaling"); + _glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext) + _glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext"); + _glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow) + _glfwPlatformGetModuleSymbol(_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"); - _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll"); + _glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll"); if (_glfw.win32.dinput8.instance) { _glfw.win32.dinput8.Create = (PFN_DirectInput8Create) - GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create"); + _glfwPlatformGetModuleSymbol(_glfw.win32.dinput8.instance, "DirectInput8Create"); } { @@ -122,37 +126,46 @@ static GLFWbool loadLibraries(void) for (i = 0; names[i]; i++) { - _glfw.win32.xinput.instance = LoadLibraryA(names[i]); + _glfw.win32.xinput.instance = _glfwPlatformLoadModule(names[i]); if (_glfw.win32.xinput.instance) { _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities) - GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities"); + _glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetCapabilities"); _glfw.win32.xinput.GetState = (PFN_XInputGetState) - GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState"); + _glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetState"); break; } } } - _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll"); + _glfw.win32.dwmapi.instance = _glfwPlatformLoadModule("dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled) - GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_DwmFlush) - GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmFlush"); _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) - GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor) + _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); } - _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); + _glfw.win32.shcore.instance = _glfwPlatformLoadModule("shcore.dll"); if (_glfw.win32.shcore.instance) { _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness) - GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); + _glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "SetProcessDpiAwareness"); _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor) - GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor"); + _glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "GetDpiForMonitor"); + } + + _glfw.win32.ntdll.instance = _glfwPlatformLoadModule("ntdll.dll"); + if (_glfw.win32.ntdll.instance) + { + _glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo) + _glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); } return GLFW_TRUE; @@ -163,27 +176,27 @@ static GLFWbool loadLibraries(void) static void freeLibraries(void) { if (_glfw.win32.xinput.instance) - FreeLibrary(_glfw.win32.xinput.instance); + _glfwPlatformFreeModule(_glfw.win32.xinput.instance); if (_glfw.win32.dinput8.instance) - FreeLibrary(_glfw.win32.dinput8.instance); - - if (_glfw.win32.winmm.instance) - FreeLibrary(_glfw.win32.winmm.instance); + _glfwPlatformFreeModule(_glfw.win32.dinput8.instance); if (_glfw.win32.user32.instance) - FreeLibrary(_glfw.win32.user32.instance); + _glfwPlatformFreeModule(_glfw.win32.user32.instance); if (_glfw.win32.dwmapi.instance) - FreeLibrary(_glfw.win32.dwmapi.instance); + _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance); if (_glfw.win32.shcore.instance) - FreeLibrary(_glfw.win32.shcore.instance); + _glfwPlatformFreeModule(_glfw.win32.shcore.instance); + + if (_glfw.win32.ntdll.instance) + _glfwPlatformFreeModule(_glfw.win32.ntdll.instance); } // Create key code translation tables // -static void createKeyTables(void) +static void createKeyTablesWin32(void) { int scancode; @@ -251,7 +264,6 @@ static void createKeyTables(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; @@ -309,6 +321,7 @@ static void createKeyTables(void) _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL; _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE; _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL; _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY; _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT; @@ -319,29 +332,81 @@ static void createKeyTables(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 HWND createHelperWindow(void) +static GLFWbool createHelperWindow(void) { MSG msg; - HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, - _GLFW_WNDCLASSNAME, - L"GLFW message window", - WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0, 0, 1, 1, - NULL, NULL, - GetModuleHandleW(NULL), - NULL); - if (!window) + 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), + L"GLFW message window", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + NULL, NULL, + _glfw.win32.instance, + NULL); + + if (!_glfw.win32.helperWindowHandle) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "Win32: Failed to create helper window"); - return NULL; + return GLFW_FALSE; } - // HACK: The first call to ShowWindow is ignored if the parent process - // passed along a STARTUPINFO, so clear that flag with a no-op call - ShowWindow(window, SW_HIDE); + // HACK: The command to the first ShowWindow call is ignored if the parent + // process passed along a STARTUPINFO, so clear that with a no-op call + ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE); // Register for HID device notifications { @@ -352,7 +417,7 @@ static HWND createHelperWindow(void) dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; _glfw.win32.deviceNotificationHandle = - RegisterDeviceNotificationW(window, + RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle, (DEV_BROADCAST_HDR*) &dbi, DEVICE_NOTIFY_WINDOW_HANDLE); } @@ -363,10 +428,9 @@ static HWND createHelperWindow(void) DispatchMessageW(&msg); } - return window; + return GLFW_TRUE; } - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -386,13 +450,13 @@ WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source) return NULL; } - target = calloc(count, sizeof(WCHAR)); + target = _glfw_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"); - free(target); + _glfw_free(target); return NULL; } @@ -414,13 +478,13 @@ char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source) return NULL; } - target = calloc(size, 1); + target = _glfw_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"); - free(target); + _glfw_free(target); return NULL; } @@ -441,7 +505,7 @@ void _glfwInputErrorWin32(int error, const char* description) GetLastError() & 0xffff, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, - sizeof(buffer), + sizeof(buffer) / sizeof(WCHAR), NULL); WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL); @@ -479,7 +543,7 @@ void _glfwUpdateKeyNamesWin32(void) vk = vks[key - GLFW_KEY_KP_0]; } else - vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK); + vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK); length = ToUnicode(vk, scancode, state, chars, sizeof(chars) / sizeof(WCHAR), @@ -487,6 +551,8 @@ 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); @@ -502,86 +568,165 @@ void _glfwUpdateKeyNamesWin32(void) } } - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformInit(void) +// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the +// application having a correct embedded manifest +// +BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) { - // 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); + OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the + // latter lies unless the user knew to embed a non-default manifest + // announcing support for Windows 10 via supportedOS GUID + return RtlVerifyVersionInfo(&osvi, mask, cond) == 0; +} +// Checks whether we are on at least the specified build of Windows 10 +// +BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), 10, 0, build }; + DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER; + ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); + cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL); + // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the + // latter lies unless the user knew to embed a non-default manifest + // announcing support for Windows 10 via supportedOS GUID + 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; +} + +int _glfwInitWin32(void) +{ if (!loadLibraries()) return GLFW_FALSE; - createKeyTables(); + createKeyTablesWin32(); _glfwUpdateKeyNamesWin32(); - if (IsWindows8Point1OrGreater()) + if (_glfwIsWindows10Version1703OrGreaterWin32()) + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + else if (IsWindows8Point1OrGreater()) SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); else if (IsWindowsVistaOrGreater()) SetProcessDPIAware(); - if (!_glfwRegisterWindowClassWin32()) + if (!createHelperWindow()) return GLFW_FALSE; - _glfw.win32.helperWindowHandle = createHelperWindow(); - if (!_glfw.win32.helperWindowHandle) - return GLFW_FALSE; - - _glfwInitTimerWin32(); - _glfwInitJoysticksWin32(); - _glfwPollMonitorsWin32(); return GLFW_TRUE; } -void _glfwPlatformTerminate(void) +void _glfwTerminateWin32(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); - _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); + _glfw_free(_glfw.win32.clipboardString); + _glfw_free(_glfw.win32.rawInput); _glfwTerminateWGL(); _glfwTerminateEGL(); - - _glfwTerminateJoysticksWin32(); + _glfwTerminateOSMesa(); freeLibraries(); } -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " Win32 WGL EGL" -#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 - ; -} +#endif // _GLFW_WIN32 diff --git a/raylib/external/glfw/src/win32_joystick.c b/raylib/external/glfw/src/win32_joystick.c index d9d341f..59389a9 100644 --- a/raylib/external/glfw/src/win32_joystick.c +++ b/raylib/external/glfw/src/win32_joystick.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(_GLFW_WIN32) + #include #include @@ -197,11 +199,11 @@ static GLFWbool supportsXInput(const GUID* guid) if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0) return GLFW_FALSE; - ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); + ridl = _glfw_calloc(count, sizeof(RAWINPUTDEVICELIST)); if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1) { - free(ridl); + _glfw_free(ridl); return GLFW_FALSE; } @@ -246,7 +248,7 @@ static GLFWbool supportsXInput(const GUID* guid) } } - free(ridl); + _glfw_free(ridl); return result; } @@ -254,14 +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); _glfwFreeJoystick(js); - _glfwInputJoystick(js, GLFW_DISCONNECTED); } // DirectInput device object enumeration callback @@ -352,8 +356,8 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) + js = _glfw.joysticks + jid; + if (js->connected) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) return DIENUM_CONTINUE; @@ -412,8 +416,8 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) memset(&data, 0, sizeof(data)); data.device = device; - data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs, - sizeof(_GLFWjoyobjectWin32)); + data.objects = _glfw_calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs, + sizeof(_GLFWjoyobjectWin32)); if (FAILED(IDirectInputDevice8_EnumObjects(device, deviceObjectCallback, @@ -424,7 +428,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) "Win32: Failed to enumerate device objects"); IDirectInputDevice8_Release(device); - free(data.objects); + _glfw_free(data.objects); return DIENUM_CONTINUE; } @@ -441,7 +445,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) "Win32: Failed to convert joystick name to UTF-8"); IDirectInputDevice8_Release(device); - free(data.objects); + _glfw_free(data.objects); return DIENUM_STOP; } @@ -469,7 +473,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) if (!js) { IDirectInputDevice8_Release(device); - free(data.objects); + _glfw_free(data.objects); return DIENUM_STOP; } @@ -487,39 +491,6 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize joystick interface -// -void _glfwInitJoysticksWin32(void) -{ - if (_glfw.win32.dinput8.instance) - { - if (FAILED(DirectInput8Create(GetModuleHandle(NULL), - DIRECTINPUT_VERSION, - &IID_IDirectInput8W, - (void**) &_glfw.win32.dinput8.api, - NULL))) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to create interface"); - } - } - - _glfwDetectJoystickConnectionWin32(); -} - -// Close all opened joystick handles -// -void _glfwTerminateJoysticksWin32(void) -{ - int jid; - - for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) - closeJoystick(_glfw.joysticks + jid); - - if (_glfw.win32.dinput8.api) - IDirectInput8_Release(_glfw.win32.dinput8.api); -} - // Checks for new joysticks after DBT_DEVICEARRIVAL // void _glfwDetectJoystickConnectionWin32(void) @@ -537,7 +508,7 @@ void _glfwDetectJoystickConnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - if (_glfw.joysticks[jid].present && + if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].win32.device == NULL && _glfw.joysticks[jid].win32.index == index) { @@ -589,8 +560,8 @@ void _glfwDetectJoystickDisconnectionWin32(void) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { _GLFWjoystick* js = _glfw.joysticks + jid; - if (js->present) - _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); + if (js->connected) + _glfwPollJoystickWin32(js, _GLFW_POLL_PRESENCE); } } @@ -599,13 +570,44 @@ void _glfwDetectJoystickDisconnectionWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) +GLFWbool _glfwInitJoysticksWin32(void) +{ + if (_glfw.win32.dinput8.instance) + { + if (FAILED(DirectInput8Create(_glfw.win32.instance, + DIRECTINPUT_VERSION, + &IID_IDirectInput8W, + (void**) &_glfw.win32.dinput8.api, + NULL))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to create interface"); + return GLFW_FALSE; + } + } + + _glfwDetectJoystickConnectionWin32(); + return GLFW_TRUE; +} + +void _glfwTerminateJoysticksWin32(void) +{ + int jid; + + for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) + closeJoystick(_glfw.joysticks + jid); + + if (_glfw.win32.dinput8.api) + IDirectInput8_Release(_glfw.win32.dinput8.api); +} + +GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode) { if (js->win32.device) { int i, ai = 0, bi = 0, pi = 0; HRESULT result; - DIJOYSTATE state; + DIJOYSTATE state = {0}; IDirectInputDevice8_Poll(js->win32.device); result = IDirectInputDevice8_GetDeviceState(js->win32.device, @@ -668,11 +670,11 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) }; // Screams of horror are appropriate at this point - int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); - if (state < 0 || state > 8) - state = 8; + int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); + if (stateIndex < 0 || stateIndex > 8) + stateIndex = 8; - _glfwInputJoystickHat(js, pi, states[state]); + _glfwInputJoystickHat(js, pi, states[stateIndex]); pi++; break; } @@ -732,20 +734,34 @@ int _glfwPlatformPollJoystick(_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; } -void _glfwPlatformUpdateGamepadGUID(char* guid) +const char* _glfwGetMappingNameWin32(void) +{ + return "Windows"; +} + +void _glfwUpdateGamepadGUIDWin32(char* guid) { if (strcmp(guid + 20, "504944564944") == 0) { char original[33]; - strcpy(original, guid); + strncpy(original, guid, sizeof(original) - 1); sprintf(guid, "03000000%.4s0000%.4s000000000000", original, original + 4); } } +#endif // _GLFW_WIN32 + diff --git a/raylib/external/glfw/src/win32_joystick.h b/raylib/external/glfw/src/win32_joystick.h index 9156f6c..9ab6438 100644 --- a/raylib/external/glfw/src/win32_joystick.h +++ b/raylib/external/glfw/src/win32_joystick.h @@ -1,7 +1,7 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -24,10 +24,8 @@ // //======================================================================== -#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32 -#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy - -#define _GLFW_PLATFORM_MAPPING_NAME "Windows" +#define GLFW_WIN32_JOYSTICK_STATE _GLFWjoystickWin32 win32; +#define GLFW_WIN32_LIBRARY_JOYSTICK_STATE // Joystick element (axis, button or slider) // @@ -48,9 +46,6 @@ typedef struct _GLFWjoystickWin32 GUID guid; } _GLFWjoystickWin32; - -void _glfwInitJoysticksWin32(void); -void _glfwTerminateJoysticksWin32(void); void _glfwDetectJoystickConnectionWin32(void); void _glfwDetectJoystickDisconnectionWin32(void); diff --git a/raylib/external/glfw/src/win32_module.c b/raylib/external/glfw/src/win32_module.c new file mode 100644 index 0000000..47c8dff --- /dev/null +++ b/raylib/external/glfw/src/win32_module.c @@ -0,0 +1,51 @@ +//======================================================================== +// 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 d1d159b..87c85b9 100644 --- a/raylib/external/glfw/src/win32_monitor.c +++ b/raylib/external/glfw/src/win32_monitor.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -27,10 +27,12 @@ #include "internal.h" +#if defined(_GLFW_WIN32) + #include #include #include -#include +#include // Callback for EnumDisplayMonitors in createMonitor @@ -93,7 +95,7 @@ static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DeleteDC(dc); monitor = _glfwAllocMonitor(name, widthMM, heightMM); - free(name); + _glfw_free(name); if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED) monitor->win32.modesPruned = GLFW_TRUE; @@ -142,7 +144,7 @@ void _glfwPollMonitorsWin32(void) disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); @@ -182,6 +184,8 @@ void _glfwPollMonitorsWin32(void) display.DeviceName) == 0) { disconnected[i] = NULL; + // handle may have changed, update + EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]); break; } } @@ -192,7 +196,7 @@ void _glfwPollMonitorsWin32(void) monitor = createMonitor(&adapter, &display); if (!monitor) { - free(disconnected); + _glfw_free(disconnected); return; } @@ -222,7 +226,7 @@ void _glfwPollMonitorsWin32(void) monitor = createMonitor(&adapter, NULL); if (!monitor) { - free(disconnected); + _glfw_free(disconnected); return; } @@ -236,7 +240,7 @@ void _glfwPollMonitorsWin32(void) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - free(disconnected); + _glfw_free(disconnected); } // Change the current video mode @@ -249,7 +253,7 @@ void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) LONG result; best = _glfwChooseVideoMode(monitor, desired); - _glfwPlatformGetVideoMode(monitor, ¤t); + _glfwGetVideoModeWin32(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; @@ -309,12 +313,23 @@ void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) } } -void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) +void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) { UINT xdpi, ydpi; + if (xscale) + *xscale = 0.f; + if (yscale) + *yscale = 0.f; + if (IsWindows8Point1OrGreater()) - GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + { + if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI"); + return; + } + } else { const HDC dc = GetDC(NULL); @@ -324,9 +339,9 @@ void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* ysc } if (xscale) - *xscale = xdpi / 96.f; + *xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI; if (yscale) - *yscale = ydpi / 96.f; + *yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI; } @@ -334,11 +349,11 @@ void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* ysc ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitorWin32(_GLFWmonitor* monitor) { } -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); @@ -355,13 +370,30 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = dm.dmPosition.y; } -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor, + float* xscale, float* yscale) { - _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale); + _glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale); } -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) +{ + MONITORINFO mi = { sizeof(mi) }; + GetMonitorInfoW(monitor->win32.handle, &mi); + + if (xpos) + *xpos = mi.rcWork.left; + if (ypos) + *ypos = mi.rcWork.top; + if (width) + *width = mi.rcWork.right - mi.rcWork.left; + if (height) + *height = mi.rcWork.bottom - mi.rcWork.top; +} + +GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count) { int modeIndex = 0, size = 0; GLFWvidmode* result = NULL; @@ -420,7 +452,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) if (*count == size) { size += 128; - result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); + result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode)); } (*count)++; @@ -430,21 +462,25 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) if (!*count) { // HACK: Report the current mode if no valid modes were found - result = calloc(1, sizeof(GLFWvidmode)); - _glfwPlatformGetVideoMode(monitor, result); + result = _glfw_calloc(1, sizeof(GLFWvidmode)); + _glfwGetVideoModeWin32(monitor, result); *count = 1; } return result; } -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +GLFWbool _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode) { DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); + if (!EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query display settings"); + return GLFW_FALSE; + } mode->width = dm.dmPelsWidth; mode->height = dm.dmPelsHeight; @@ -453,12 +489,14 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) &mode->redBits, &mode->greenBits, &mode->blueBits); + + return GLFW_TRUE; } -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { HDC dc; - WORD values[768]; + WORD values[3][256]; dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); GetDeviceGammaRamp(dc, values); @@ -466,15 +504,17 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) _glfwAllocGammaArrays(ramp, 256); - memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); - memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); - memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); + memcpy(ramp->red, values[0], sizeof(values[0])); + memcpy(ramp->green, values[1], sizeof(values[1])); + memcpy(ramp->blue, values[2], sizeof(values[2])); + + return GLFW_TRUE; } -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { HDC dc; - WORD values[768]; + WORD values[3][256]; if (ramp->size != 256) { @@ -483,9 +523,9 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) return; } - memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); - memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); - memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); + memcpy(values[0], ramp->red, sizeof(values[0])); + memcpy(values[1], ramp->green, sizeof(values[1])); + memcpy(values[2], ramp->blue, sizeof(values[2])); dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); SetDeviceGammaRamp(dc, values); @@ -501,6 +541,13 @@ 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; } @@ -508,6 +555,15 @@ 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 9a66921..7e3d884 100644 --- a/raylib/external/glfw/src/win32_platform.h +++ b/raylib/external/glfw/src/win32_platform.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -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_ARB_debug_output -// callback) but windows.h assumes no one will define APIENTRY before it does +// 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 // GLFW on Windows is Unicode only and does not work in MBCS mode @@ -61,6 +61,9 @@ // GLFW uses DirectInput8 interfaces #define DIRECTINPUT_VERSION 0x0800 +// GLFW uses OEM cursor resources +#define OEMRESOURCE + #include #include #include @@ -74,6 +77,9 @@ #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif +#ifndef WM_DWMCOLORIZATIONCOLORCHANGED + #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#endif #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x0049 #endif @@ -96,7 +102,19 @@ #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif #ifndef _WIN32_WINNT_WINBLUE - #define _WIN32_WINNT_WINBLUE 0x0602 + #define _WIN32_WINNT_WINBLUE 0x0603 +#endif +#ifndef _WIN32_WINNT_WIN8 + #define _WIN32_WINNT_WIN8 0x0602 +#endif +#ifndef WM_GETDPISCALEDSIZE + #define WM_GETDPISCALEDSIZE 0x02e4 +#endif +#ifndef USER_DEFAULT_SCREEN_DPI + #define USER_DEFAULT_SCREEN_DPI 96 +#endif +#ifndef OCR_HAND + #define OCR_HAND 32649 #endif #if WINVER < 0x0601 @@ -140,20 +158,32 @@ typedef enum } MONITOR_DPI_TYPE; #endif /*DPI_ENUMS_DECLARED*/ -// HACK: Define versionhelpers.h functions manually as MinGW lacks the header -BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp); -#define IsWindowsVistaOrGreater() \ - IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \ - LOBYTE(_WIN32_WINNT_VISTA), 0) -#define IsWindows7OrGreater() \ - IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \ - LOBYTE(_WIN32_WINNT_WIN7), 0) -#define IsWindows8OrGreater() \ - IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \ - LOBYTE(_WIN32_WINNT_WIN8), 0) -#define IsWindows8Point1OrGreater() \ - IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \ - LOBYTE(_WIN32_WINNT_WINBLUE), 0) +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 +#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 +// +#define IsWindowsVistaOrGreater() \ + _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \ + LOBYTE(_WIN32_WINNT_VISTA), 0) +#define IsWindows7OrGreater() \ + _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7), \ + LOBYTE(_WIN32_WINNT_WIN7), 0) +#define IsWindows8OrGreater() \ + _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8), \ + LOBYTE(_WIN32_WINNT_WIN8), 0) +#define IsWindows8Point1OrGreater() \ + _glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \ + LOBYTE(_WIN32_WINNT_WINBLUE), 0) + +// Windows 10 Anniversary Update +#define _glfwIsWindows10Version1607OrGreaterWin32() \ + _glfwIsWindows10BuildOrGreaterWin32(14393) +// Windows 10 Creators Update +#define _glfwIsWindows10Version1703OrGreaterWin32() \ + _glfwIsWindows10BuildOrGreaterWin32(15063) // HACK: Define macros that some xinput.h variants don't #ifndef XINPUT_CAPS_WIRELESS @@ -186,12 +216,59 @@ BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp); // HACK: Define macros that some dinput.h variants don't #ifndef DIDFT_OPTIONAL - #define DIDFT_OPTIONAL 0x80000000 + #define DIDFT_OPTIONAL 0x80000000 #endif -// winmm.dll function pointer typedefs -typedef DWORD (WINAPI * PFN_timeGetTime)(void); -#define timeGetTime _glfw.win32.winmm.GetTime +#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 // xinput.dll function pointer typedefs typedef DWORD (WINAPI * PFN_XInputGetCapabilities)(DWORD,DWORD,XINPUT_CAPABILITIES*); @@ -206,16 +283,28 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID* // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); +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*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*); +typedef HRESULT (WINAPI * PFN_DwmGetColorizationColor)(DWORD*,BOOL*); #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush #define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow +#define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -223,6 +312,38 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*, #define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_ #define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_ +// ntdll.dll function pointer typedefs +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 @@ -237,28 +358,55 @@ typedef struct VkWin32SurfaceCreateInfoKHR typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); -#include "win32_joystick.h" -#include "wgl_context.h" -#include "egl_context.h" -#include "osmesa_context.h" +#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; -#define _GLFW_WNDCLASSNAME L"GLFW30" +#define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl; +#define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl; -#define _glfw_dlopen(name) LoadLibraryA(name) -#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) -#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) -#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY +// 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 // @@ -274,19 +422,28 @@ typedef struct _GLFWwindowWin32 GLFWbool maximized; // Whether to enable framebuffer transparency on DWM 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 + 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]; @@ -296,13 +453,13 @@ 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; - - struct { - HINSTANCE instance; - PFN_timeGetTime GetTime; - } winmm; + UINT mouseTrailSize; + // The cursor handle to use to hide the cursor (NULL or a transparent cursor) + HCURSOR blankCursor; struct { HINSTANCE instance; @@ -320,6 +477,11 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_SetProcessDPIAware SetProcessDPIAware_; PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_; + PFN_EnableNonClientDpiScaling EnableNonClientDpiScaling_; + PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_; + PFN_GetDpiForWindow GetDpiForWindow_; + PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_; + PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_; } user32; struct { @@ -327,6 +489,7 @@ typedef struct _GLFWlibraryWin32 PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; + PFN_DwmGetColorizationColor GetColorizationColor; } dwmapi; struct { @@ -335,6 +498,10 @@ typedef struct _GLFWlibraryWin32 PFN_GetDpiForMonitor GetDpiForMonitor_; } shcore; + struct { + HINSTANCE instance; + PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; + } ntdll; } _GLFWlibraryWin32; // Win32-specific per-monitor data @@ -349,7 +516,6 @@ typedef struct _GLFWmonitorWin32 char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; - } _GLFWmonitorWin32; // Win32-specific per-cursor data @@ -357,50 +523,105 @@ typedef struct _GLFWmonitorWin32 typedef struct _GLFWcursorWin32 { HCURSOR handle; - } _GLFWcursorWin32; -// Win32-specific global timer data -// -typedef struct _GLFWtimerWin32 -{ - GLFWbool hasPC; - uint64_t frequency; -} _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); -GLFWbool _glfwIsCompositionEnabledWin32(void); +GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform); +int _glfwInitWin32(void); +void _glfwTerminateWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); +BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp); +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 _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale); +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); diff --git a/raylib/external/glfw/src/win32_thread.c b/raylib/external/glfw/src/win32_thread.c index 98231c1..212e666 100644 --- a/raylib/external/glfw/src/win32_thread.c +++ b/raylib/external/glfw/src/win32_thread.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,6 +27,8 @@ #include "internal.h" +#if defined(GLFW_BUILD_WIN32_THREAD) + #include @@ -41,8 +43,7 @@ GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls) tls->win32.index = TlsAlloc(); if (tls->win32.index == TLS_OUT_OF_INDEXES) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to allocate TLS index"); + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to allocate TLS index"); return GLFW_FALSE; } @@ -95,3 +96,5 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex) LeaveCriticalSection(&mutex->win32.section); } +#endif // GLFW_BUILD_WIN32_THREAD + diff --git a/raylib/external/glfw/src/nsgl_context.h b/raylib/external/glfw/src/win32_thread.h similarity index 56% rename from raylib/external/glfw/src/nsgl_context.h rename to raylib/external/glfw/src/win32_thread.h index 18042de..dd5948f 100644 --- a/raylib/external/glfw/src/nsgl_context.h +++ b/raylib/external/glfw/src/win32_thread.h @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.3 macOS - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2009-2016 Camilla Löwy +// 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 @@ -24,33 +25,29 @@ // //======================================================================== -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl +// 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 -// NSGL-specific per-context data +#define GLFW_WIN32_TLS_STATE _GLFWtlsWin32 win32; +#define GLFW_WIN32_MUTEX_STATE _GLFWmutexWin32 win32; + +// Win32-specific thread local storage data // -typedef struct _GLFWcontextNSGL +typedef struct _GLFWtlsWin32 { - id pixelFormat; - id object; + GLFWbool allocated; + DWORD index; +} _GLFWtlsWin32; -} _GLFWcontextNSGL; - -// NSGL-specific global data +// Win32-specific mutex data // -typedef struct _GLFWlibraryNSGL +typedef struct _GLFWmutexWin32 { - // 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); + 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 f333cd4..a38e15d 100644 --- a/raylib/external/glfw/src/win32_time.c +++ b/raylib/external/glfw/src/win32_time.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,44 +27,22 @@ #include "internal.h" - -////////////////////////////////////////////////////////////////////////// -////// 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; - } -} - +#if defined(GLFW_BUILD_WIN32_TIMER) ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// +void _glfwPlatformInitTimer(void) +{ + QueryPerformanceFrequency((LARGE_INTEGER*) &_glfw.timer.win32.frequency); +} + uint64_t _glfwPlatformGetTimerValue(void) { - if (_glfw.timer.win32.hasPC) - { - uint64_t value; - QueryPerformanceCounter((LARGE_INTEGER*) &value); - return value; - } - else - return (uint64_t) timeGetTime(); + uint64_t value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; } uint64_t _glfwPlatformGetTimerFrequency(void) @@ -72,3 +50,5 @@ 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 new file mode 100644 index 0000000..ef57a5a --- /dev/null +++ b/raylib/external/glfw/src/win32_time.h @@ -0,0 +1,43 @@ +//======================================================================== +// 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 d467f2a..3762b76 100644 --- a/raylib/external/glfw/src/win32_window.c +++ b/raylib/external/glfw/src/win32_window.c @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 Win32 - www.glfw.org +// GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,15 +28,14 @@ #include "internal.h" +#if defined(_GLFW_WIN32) + #include #include -#include #include #include #include -#define _GLFW_KEY_INVALID -2 - // Returns the window style for the specified window // static DWORD getWindowStyle(const _GLFWwindow* window) @@ -98,8 +98,7 @@ 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; @@ -186,60 +185,47 @@ static HICON createIcon(const GLFWimage* image, return handle; } -// Translate client window size to full window size according to styles -// -static void getFullWindowSize(DWORD style, DWORD exStyle, - int clientWidth, int clientHeight, - int* fullWidth, int* fullHeight) -{ - RECT rect = { 0, 0, clientWidth, clientHeight }; - AdjustWindowRectEx(&rect, style, FALSE, exStyle); - *fullWidth = rect.right - rect.left; - *fullHeight = rect.bottom - rect.top; -} - -// Enforce the client rect aspect ratio based on which edge is being dragged +// Enforce the content area aspect ratio based on which edge is being dragged // static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { - int xoff, yoff; + RECT frame = {0}; const float ratio = (float) window->numer / (float) window->denom; + const DWORD style = getWindowStyle(window); + const DWORD exStyle = getWindowExStyle(window); - getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), - 0, 0, &xoff, &yoff); + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle, + GetDpiForWindow(window->win32.handle)); + } + else + AdjustWindowRectEx(&frame, style, FALSE, exStyle); if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) { - area->bottom = area->top + yoff + - (int) ((area->right - area->left - xoff) / ratio); + area->bottom = area->top + (frame.bottom - frame.top) + + (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) { - area->top = area->bottom - yoff - - (int) ((area->right - area->left - xoff) / ratio); + area->top = area->bottom - (frame.bottom - frame.top) - + (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio); } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) { - area->right = area->left + xoff + - (int) ((area->bottom - area->top - yoff) * ratio); + area->right = area->left + (frame.right - frame.left) + + (int) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio); } } -// Centers the cursor over the window client area -// -static void centerCursor(_GLFWwindow* window) -{ - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); -} - // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { - if (window->cursorMode == GLFW_CURSOR_NORMAL) + if (window->cursorMode == GLFW_CURSOR_NORMAL || + window->cursorMode == GLFW_CURSOR_CAPTURED) { if (window->cursor) SetCursor(window->cursor->win32.handle); @@ -247,39 +233,40 @@ 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) { - RECT clipRect; - GetClientRect(window->win32.handle, &clipRect); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); - ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); - ClipCursor(&clipRect); + // 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); } - else - ClipCursor(NULL); } -// Apply disabled cursor mode to a focused window +// Sets the cursor clip rect to the window content area // -static void disableCursor(_GLFWwindow* window) +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; +} + +// Enables WM_INPUT messages for the mouse for the specified window +// +static void enableRawMouseMotion(_GLFWwindow* window) { const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; - _glfw.win32.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.win32.restoreCursorPosX, - &_glfw.win32.restoreCursorPosY); - updateCursorImage(window); - centerCursor(window); - updateClipRect(window); - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -287,19 +274,12 @@ static void disableCursor(_GLFWwindow* window) } } -// Exit disabled cursor mode for the specified window +// Disables WM_INPUT messages for the mouse // -static void enableCursor(_GLFWwindow* window) +static void disableRawMouseMotion(_GLFWwindow* window) { const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; - _glfw.win32.disabledCursorWindow = NULL; - updateClipRect(NULL); - _glfwPlatformSetCursorPos(window, - _glfw.win32.restoreCursorPosX, - _glfw.win32.restoreCursorPosY); - updateCursorImage(window); - if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -307,9 +287,40 @@ static void enableCursor(_GLFWwindow* window) } } -// Returns whether the cursor is in the client area of the specified window +// Apply disabled cursor mode to a focused window // -static GLFWbool cursorInClientArea(_GLFWwindow* window) +static void disableCursor(_GLFWwindow* window) +{ + _glfw.win32.disabledCursorWindow = window; + _glfwGetCursorPosWin32(window, + &_glfw.win32.restoreCursorPosX, + &_glfw.win32.restoreCursorPosY); + updateCursorImage(window); + _glfwCenterCursorInContentArea(window); + captureCursor(window); + + if (window->rawMouseMotion) + enableRawMouseMotion(window); +} + +// Exit disabled cursor mode for the specified window +// +static void enableCursor(_GLFWwindow* window) +{ + if (window->rawMouseMotion) + disableRawMouseMotion(window); + + _glfw.win32.disabledCursorWindow = NULL; + releaseCursor(); + _glfwSetCursorPosWin32(window, + _glfw.win32.restoreCursorPosX, + _glfw.win32.restoreCursorPosY); + updateCursorImage(window); +} + +// Returns whether the cursor is in the content area of the specified window +// +static GLFWbool cursorInContentArea(_GLFWwindow* window) { RECT area; POINT pos; @@ -337,7 +348,16 @@ static void updateWindowStyles(const _GLFWwindow* window) style |= getWindowStyle(window); GetClientRect(window->win32.handle, &rect); - AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, style, FALSE, + getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); + ClientToScreen(window->win32.handle, (POINT*) &rect.left); ClientToScreen(window->win32.handle, (POINT*) &rect.right); SetWindowLongW(window->win32.handle, GWL_STYLE, style); @@ -351,10 +371,17 @@ static void updateWindowStyles(const _GLFWwindow* window) // static void updateFramebufferTransparency(const _GLFWwindow* window) { + BOOL composition, opaque; + DWORD color; + if (!IsWindowsVistaOrGreater()) return; - if (_glfwIsCompositionEnabledWin32()) + if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) + return; + + if (IsWindows8OrGreater() || + (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) { HRGN region = CreateRectRgn(0, 0, -1, -1); DWM_BLURBEHIND bb = {0}; @@ -362,63 +389,21 @@ static void updateFramebufferTransparency(const _GLFWwindow* window) bb.hRgnBlur = region; bb.fEnable = TRUE; - if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb))) - { - // Decorated windows don't repaint the transparent background - // leaving a trail behind animations - // HACK: Making the window layered with a transparency color key - // seems to fix this. Normally, when specifying - // a transparency color key to be used when composing the - // layered window, all pixels painted by the window in this - // color will be transparent. That doesn't seem to be the - // case anymore, at least when used with blur behind window - // plus negative region. - LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - exStyle |= WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); - - // Using a color key not equal to black to fix the trailing - // issue. When set to black, something is making the hit test - // not resize with the window frame. - SetLayeredWindowAttributes(window->win32.handle, - RGB(0, 193, 48), 255, LWA_COLORKEY); - } - + DwmEnableBlurBehindWindow(window->win32.handle, &bb); DeleteObject(region); } else { - LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - exStyle &= ~WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); - RedrawWindow(window->win32.handle, NULL, NULL, - RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); + // HACK: Disable framebuffer transparency on Windows 7 when the + // colorization color is opaque, because otherwise the window + // contents is blended additively with the previous frame instead + // of replacing it + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE; + DwmEnableBlurBehindWindow(window->win32.handle, &bb); } } -// Translates a GLFW standard cursor to a resource ID -// -static LPWSTR translateCursorShape(int shape) -{ - switch (shape) - { - case GLFW_ARROW_CURSOR: - return IDC_ARROW; - case GLFW_IBEAM_CURSOR: - return IDC_IBEAM; - case GLFW_CROSSHAIR_CURSOR: - return IDC_CROSS; - case GLFW_HAND_CURSOR: - return IDC_HAND; - case GLFW_HRESIZE_CURSOR: - return IDC_SIZEWE; - case GLFW_VRESIZE_CURSOR: - return IDC_SIZENS; - } - - return NULL; -} - // Retrieves and translates modifier keys // static int getKeyMods(void) @@ -441,81 +426,10 @@ static int getKeyMods(void) return mods; } -// Retrieves and translates modifier keys -// -static int getAsyncKeyMods(void) -{ - int mods = 0; - - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - mods |= GLFW_MOD_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - mods |= GLFW_MOD_CONTROL; - if (GetAsyncKeyState(VK_MENU) & 0x8000) - mods |= GLFW_MOD_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) - mods |= GLFW_MOD_SUPER; - if (GetAsyncKeyState(VK_CAPITAL) & 1) - mods |= GLFW_MOD_CAPS_LOCK; - if (GetAsyncKeyState(VK_NUMLOCK) & 1) - mods |= GLFW_MOD_NUM_LOCK; - - return mods; -} - -// Translates a Windows key to the corresponding GLFW key -// -static int translateKey(WPARAM wParam, LPARAM lParam) -{ - // The Ctrl keys require special handling - if (wParam == VK_CONTROL) - { - MSG next; - DWORD time; - - // Right side keys have the extended key bit set - if (lParam & 0x01000000) - return GLFW_KEY_RIGHT_CONTROL; - - // HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence - // We only want the Right Alt message, so if the next message is - // Right Alt we ignore this (synthetic) Left Ctrl message - time = GetMessageTime(); - - if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) - { - if (next.message == WM_KEYDOWN || - next.message == WM_SYSKEYDOWN || - next.message == WM_KEYUP || - next.message == WM_SYSKEYUP) - { - if (next.wParam == VK_MENU && - (next.lParam & 0x01000000) && - next.time == time) - { - // Next message is Right Alt down so discard this - return _GLFW_KEY_INVALID; - } - } - } - - return GLFW_KEY_LEFT_CONTROL; - } - - if (wParam == VK_PROCESSKEY) - { - // IME notifies that keys have been filtered by setting the virtual - // key-code to VK_PROCESSKEY - return _GLFW_KEY_INVALID; - } - - return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF]; -} - static void fitToMonitor(_GLFWwindow* window) { MONITORINFO mi = { sizeof(mi) }; - GetMonitorInfo(window->monitor->win32.handle, &mi); + GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -526,10 +440,18 @@ static void fitToMonitor(_GLFWwindow* window) // Make the specified window and its video mode active on its monitor // -static void acquireMonitor(_GLFWwindow* window) +static void acquireMonitorWin32(_GLFWwindow* window) { if (!_glfw.win32.acquiredMonitorCount) + { SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); + + // 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); + } + if (!window->monitor->window) _glfw.win32.acquiredMonitorCount++; @@ -539,51 +461,94 @@ static void acquireMonitor(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitor(_GLFWwindow* window) +static void releaseMonitorWin32(_GLFWwindow* window) { if (window->monitor->window != window) return; _glfw.win32.acquiredMonitorCount--; if (!_glfw.win32.acquiredMonitorCount) + { SetThreadExecutionState(ES_CONTINUOUS); + // HACK: Restore mouse trail length saved in acquireMonitorWin32 + SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); + } + _glfwInputMonitorWindow(window->monitor, NULL); _glfwRestoreVideoModeWin32(window->monitor); } -// Window callback function (handles window messages) +// Manually maximize the window, for when SW_MAXIMIZE cannot be used // -static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) +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) { _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); if (!window) { - // This is the message handling for the hidden helper window - - switch (uMsg) + if (uMsg == WM_NCCREATE) { - case WM_DISPLAYCHANGE: - _glfwPollMonitorsWin32(); - break; - - case WM_DEVICECHANGE: + if (_glfwIsWindows10Version1607OrGreaterWin32()) { - 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(); - } + const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; + const _GLFWwndconfig* wndconfig = cs->lpCreateParams; - break; + // 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) + EnableNonClientDpiScaling(hWnd); } } @@ -598,12 +563,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // clicking a caption button if (HIWORD(lParam) == WM_LBUTTONDOWN) { - if (LOWORD(lParam) == HTCLOSE || - LOWORD(lParam) == HTMINBUTTON || - LOWORD(lParam) == HTMAXBUTTON) - { + if (LOWORD(lParam) != HTCLIENT) window->win32.frameAction = GLFW_TRUE; - } } break; @@ -617,6 +578,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); + else if (window->cursorMode == GLFW_CURSOR_CAPTURED) + captureCursor(window); window->win32.frameAction = GLFW_FALSE; } @@ -635,6 +598,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (window->cursorMode == GLFW_CURSOR_DISABLED) disableCursor(window); + else if (window->cursorMode == GLFW_CURSOR_CAPTURED) + captureCursor(window); return 0; } @@ -643,9 +608,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { if (window->cursorMode == GLFW_CURSOR_DISABLED) enableCursor(window); + else if (window->cursorMode == GLFW_CURSOR_CAPTURED) + releaseCursor(); if (window->monitor && window->autoIconify) - _glfwPlatformIconifyWindow(window); + _glfwIconifyWindowWin32(window); _glfwInputWindowFocus(window, GLFW_FALSE); return 0; @@ -670,7 +637,12 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // User trying to access application menu using ALT? case SC_KEYMENU: - return 0; + { + if (!window->win32.keymenu) + return 0; + + break; + } } break; } @@ -689,11 +661,38 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_CHAR: case WM_SYSCHAR: + { + if (wParam >= 0xd800 && wParam <= 0xdbff) + window->win32.highSurrogate = (WCHAR) wParam; + else + { + uint32_t codepoint = 0; + + if (wParam >= 0xdc00 && wParam <= 0xdfff) + { + if (window->win32.highSurrogate) + { + codepoint += (window->win32.highSurrogate - 0xd800) << 10; + codepoint += (WCHAR) wParam - 0xdc00; + codepoint += 0x10000; + } + } + else + codepoint = (WCHAR) wParam; + + window->win32.highSurrogate = 0; + _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR); + } + + if (uMsg == WM_SYSCHAR && window->win32.keymenu) + break; + + return 0; + } + case WM_UNICHAR: { - const GLFWbool plain = (uMsg != WM_SYSCHAR); - - if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) + if (wParam == UNICODE_NOCHAR) { // WM_UNICHAR is not sent by Windows, but is sent by some // third-party input method engine @@ -701,7 +700,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return TRUE; } - _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain); + _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE); return 0; } @@ -710,19 +709,82 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_KEYUP: case WM_SYSKEYUP: { - const int key = translateKey(wParam, lParam); - const int scancode = (lParam >> 16) & 0x1ff; - const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS; + int key, scancode; + const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; const int mods = getKeyMods(); - if (key == _GLFW_KEY_INVALID) + scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + if (!scancode) + { + // NOTE: Some synthetic key messages have a scancode of zero + // HACK: Map the virtual key back to a usable scancode + 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 + if (wParam == VK_CONTROL) + { + if (HIWORD(lParam) & KF_EXTENDED) + { + // Right side keys have the extended key bit set + key = GLFW_KEY_RIGHT_CONTROL; + } + else + { + // NOTE: Alt Gr sends Left Ctrl followed by Right Alt + // HACK: We only want one event for Alt Gr, so if we detect + // this sequence we discard this Left Ctrl message now + // and later report Right Alt normally + MSG next; + const DWORD time = GetMessageTime(); + + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (HIWORD(next.lParam) & KF_EXTENDED) && + next.time == time) + { + // Next message is Right Alt down so discard this + break; + } + } + } + + // This is a regular Left Ctrl message + key = GLFW_KEY_LEFT_CONTROL; + } + } + else if (wParam == VK_PROCESSKEY) + { + // IME notifies that keys have been filtered by setting the + // virtual key-code to VK_PROCESSKEY break; + } if (action == GLFW_RELEASE && wParam == VK_SHIFT) { // 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 _glfwPlatformPollEvents + // NOTE: The other half of this is in _glfwPollEventsWin32 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); } @@ -799,15 +861,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); - // Disabled cursor motion input is provided by WM_INPUT - if (window->cursorMode == GLFW_CURSOR_DISABLED) - break; - - _glfwInputCursorPos(window, x, y); - - window->win32.lastCursorPosX = x; - window->win32.lastCursorPosY = y; - if (!window->win32.cursorTracked) { TRACKMOUSEEVENT tme; @@ -821,25 +874,46 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, _glfwInputCursorEnter(window, GLFW_TRUE); } + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + const int dx = x - window->win32.lastCursorPosX; + const int dy = y - window->win32.lastCursorPosY; + + if (_glfw.win32.disabledCursorWindow != window) + break; + if (window->rawMouseMotion) + break; + + _glfwInputCursorPos(window, + window->virtualCursorPosX + dx, + window->virtualCursorPosY + dy); + } + else + _glfwInputCursorPos(window, x, y); + + window->win32.lastCursorPosX = x; + window->win32.lastCursorPosY = y; + return 0; } case WM_INPUT: { - UINT size; + UINT size = 0; HRAWINPUT ri = (HRAWINPUT) lParam; - RAWINPUT* data; + RAWINPUT* data = NULL; int dx, dy; - // Only process input when disabled cursor mode is applied if (_glfw.win32.disabledCursorWindow != window) break; + if (!window->rawMouseMotion) + break; GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); if (size > (UINT) _glfw.win32.rawInputSize) { - free(_glfw.win32.rawInput); - _glfw.win32.rawInput = calloc(size, 1); + _glfw_free(_glfw.win32.rawInput); + _glfw.win32.rawInput = _glfw_calloc(size, 1); _glfw.win32.rawInputSize = size; } @@ -856,8 +930,28 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, data = _glfw.win32.rawInput; if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { - dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; - dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; + 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; } else { @@ -898,10 +992,15 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { + if (window->win32.frameAction) + break; + // HACK: Enable the cursor while the user is moving or // 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; } @@ -909,23 +1008,30 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: { + if (window->win32.frameAction) + break; + // HACK: Disable the cursor once the user is done moving or // 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.disabledCursorWindow == window) - updateClipRect(window); + if (_glfw.win32.capturedCursorWindow == window) + captureCursor(window); if (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified); @@ -933,16 +1039,22 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); - _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); - _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + 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); + } if (window->monitor && window->win32.iconified != iconified) { if (iconified) - releaseMonitor(window); + releaseMonitorWin32(window); else { - acquireMonitor(window); + acquireMonitorWin32(window); fitToMonitor(window); } } @@ -954,8 +1066,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_MOVE: { - if (_glfw.win32.disabledCursorWindow == window) - updateClipRect(window); + if (_glfw.win32.capturedCursorWindow == window) + captureCursor(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly @@ -979,27 +1091,34 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_GETMINMAXINFO: { - int xoff, yoff; + RECT frame = {0}; MINMAXINFO* mmi = (MINMAXINFO*) lParam; + const DWORD style = getWindowStyle(window); + const DWORD exStyle = getWindowExStyle(window); if (window->monitor) break; - getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), - 0, 0, &xoff, &yoff); + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle, + GetDpiForWindow(window->win32.handle)); + } + else + AdjustWindowRectEx(&frame, style, FALSE, exStyle); if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { - mmi->ptMinTrackSize.x = window->minwidth + xoff; - mmi->ptMinTrackSize.y = window->minheight + yoff; + mmi->ptMinTrackSize.x = window->minwidth + frame.right - frame.left; + mmi->ptMinTrackSize.y = window->minheight + frame.bottom - frame.top; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { - mmi->ptMaxTrackSize.x = window->maxwidth + xoff; - mmi->ptMaxTrackSize.y = window->maxheight + yoff; + mmi->ptMaxTrackSize.x = window->maxwidth + frame.right - frame.left; + mmi->ptMaxTrackSize.y = window->maxheight + frame.bottom - frame.top; } if (!window->decorated) @@ -1010,7 +1129,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); - GetMonitorInfo(mh, &mi); + GetMonitorInfoW(mh, &mi); mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; @@ -1032,17 +1151,73 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return TRUE; } + case WM_NCACTIVATE: + case WM_NCPAINT: + { + // Prevent title bar from being drawn after restoring a minimized + // undecorated window + if (!window->decorated) + return TRUE; + + break; + } + case WM_DWMCOMPOSITIONCHANGED: + case WM_DWMCOLORIZATIONCOLORCHANGED: { if (window->win32.transparent) updateFramebufferTransparency(window); return 0; } + case WM_GETDPISCALEDSIZE: + { + if (window->win32.scaleToMonitor) + break; + + // Adjust the window size to keep the content area size constant + if (_glfwIsWindows10Version1703OrGreaterWin32()) + { + RECT source = {0}, target = {0}; + SIZE* size = (SIZE*) lParam; + + AdjustWindowRectExForDpi(&source, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + AdjustWindowRectExForDpi(&target, getWindowStyle(window), + FALSE, getWindowExStyle(window), + LOWORD(wParam)); + + size->cx += (target.right - target.left) - + (source.right - source.left); + size->cy += (target.bottom - target.top) - + (source.bottom - source.top); + return TRUE; + } + + break; + } + case WM_DPICHANGED: { - const float xscale = HIWORD(wParam) / 96.f; - const float yscale = LOWORD(wParam) / 96.f; + 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())) + { + RECT* suggested = (RECT*) lParam; + SetWindowPos(window->win32.handle, HWND_TOP, + suggested->left, + suggested->top, + suggested->right - suggested->left, + suggested->bottom - suggested->top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + _glfwInputWindowContentScale(window, xscale, yscale); break; } @@ -1065,7 +1240,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, int i; const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); - char** paths = calloc(count, sizeof(char*)); + char** paths = _glfw_calloc(count, sizeof(char*)); // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); @@ -1074,19 +1249,19 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(drop, i, NULL, 0); - WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); + WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR)); DragQueryFileW(drop, i, buffer, length + 1); paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); - free(buffer); + _glfw_free(buffer); } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) - free(paths[i]); - free(paths); + _glfw_free(paths[i]); + _glfw_free(paths); DragFinish(drop); return 0; @@ -1102,34 +1277,108 @@ static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { - int xpos, ypos, fullWidth, fullHeight; + int frameX, frameY, frameWidth, frameHeight; 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) { - GLFWvidmode mode; + MONITORINFO mi = { sizeof(mi) }; + GetMonitorInfoW(window->monitor->win32.handle, &mi); // 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 - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); - _glfwPlatformGetVideoMode(window->monitor, &mode); - fullWidth = mode.width; - fullHeight = mode.height; + frameX = mi.rcMonitor.left; + frameY = mi.rcMonitor.top; + frameWidth = mi.rcMonitor.right - mi.rcMonitor.left; + frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; } else { - xpos = CW_USEDEFAULT; - ypos = CW_USEDEFAULT; + RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; + window->win32.maximized = wndconfig->maximized; if (wndconfig->maximized) style |= WS_MAXIMIZE; - getFullWindowSize(style, exStyle, - wndconfig->width, wndconfig->height, - &fullWidth, &fullHeight); + 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; } wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); @@ -1137,17 +1386,17 @@ static int createNativeWindow(_GLFWwindow* window, return GLFW_FALSE; window->win32.handle = CreateWindowExW(exStyle, - _GLFW_WNDCLASSNAME, + MAKEINTATOM(_glfw.win32.mainWindowClass), wideTitle, style, - xpos, ypos, - fullWidth, fullHeight, + frameX, frameY, + frameWidth, frameHeight, NULL, // No parent window NULL, // No window menu - GetModuleHandleW(NULL), - NULL); + _glfw.win32.instance, + (LPVOID) wndconfig); - free(wideTitle); + _glfw_free(wideTitle); if (!window->win32.handle) { @@ -1168,6 +1417,68 @@ static int createNativeWindow(_GLFWwindow* window, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } + window->win32.scaleToMonitor = wndconfig->scaleToMonitor; + window->win32.keymenu = wndconfig->win32.keymenu; + window->win32.showDefault = wndconfig->win32.showDefault; + + 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); + } + } + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, + GetDpiForWindow(window->win32.handle)); + } + else + AdjustWindowRectEx(&rect, style, FALSE, exStyle); + + 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); if (fbconfig->transparent) @@ -1176,80 +1487,15 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.transparent = GLFW_TRUE; } - 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; - } + _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height); return GLFW_TRUE; } -// Unregisters the GLFW window class -// -void _glfwUnregisterWindowClassWin32(void) -{ - UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); -} - -// Returns whether desktop compositing is enabled -// -GLFWbool _glfwIsCompositionEnabledWin32(void) -{ - if (IsWindowsVistaOrGreater()) - { - BOOL enabled; - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled))) - return enabled; - } - - return FALSE; -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformCreateWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; @@ -1277,29 +1523,50 @@ int _glfwPlatformCreateWindow(_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) { - _glfwPlatformShowWindow(window); - _glfwPlatformFocusWindow(window); - acquireMonitor(window); + _glfwShowWindowWin32(window); + _glfwFocusWindowWin32(window); + acquireMonitorWin32(window); fitToMonitor(window); + + if (wndconfig->centerCursor) + _glfwCenterCursorInContentArea(window); + } + else + { + if (wndconfig->visible) + { + _glfwShowWindowWin32(window); + if (wndconfig->focused) + _glfwFocusWindowWin32(window); + } } return GLFW_TRUE; } -void _glfwPlatformDestroyWindow(_GLFWwindow* window) +void _glfwDestroyWindowWin32(_GLFWwindow* window) { if (window->monitor) - releaseMonitor(window); + releaseMonitorWin32(window); if (window->context.destroy) window->context.destroy(window); if (_glfw.win32.disabledCursorWindow == window) - _glfw.win32.disabledCursorWindow = NULL; + enableCursor(window); + + if (_glfw.win32.capturedCursorWindow == window) + releaseCursor(); if (window->win32.handle) { @@ -1315,18 +1582,17 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) DestroyIcon(window->win32.smallIcon); } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title) { WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); if (!wideTitle) return; SetWindowTextW(window->win32.handle, wideTitle); - free(wideTitle); + _glfw_free(wideTitle); } -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images) { HICON bigIcon = NULL, smallIcon = NULL; @@ -1348,8 +1614,8 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); } - SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); - SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); + SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); + SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); if (window->win32.bigIcon) DestroyIcon(window->win32.bigIcon); @@ -1364,7 +1630,7 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, } } -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos) { POINT pos = { 0, 0 }; ClientToScreen(window->win32.handle, &pos); @@ -1375,16 +1641,27 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) *ypos = pos.y; } -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos) { RECT rect = { xpos, ypos, xpos, ypos }; - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + { + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); } -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height) { RECT area; GetClientRect(window->win32.handle, &area); @@ -1395,30 +1672,41 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) *height = area.bottom; } -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) { - acquireMonitor(window); + acquireMonitorWin32(window); fitToMonitor(window); } } else { RECT rect = { 0, 0, width, height }; - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + { + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + SetWindowPos(window->win32.handle, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } } -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { RECT area; @@ -1435,7 +1723,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, area.bottom - area.top, TRUE); } -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom) { RECT area; @@ -1450,22 +1738,32 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom area.bottom - area.top, TRUE); } -void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height) { - _glfwPlatformGetWindowSize(window, width, height); + _glfwGetWindowSizeWin32(window, width, height); } -void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { RECT rect; int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeWin32(window, &width, &height); SetRect(&rect, 0, 0, width, height); - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + { + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } if (left) *left = -rect.left; @@ -1477,56 +1775,74 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, *bottom = rect.bottom - height; } -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale) { const HANDLE handle = MonitorFromWindow(window->win32.handle, MONITOR_DEFAULTTONEAREST); - _glfwGetMonitorContentScaleWin32(handle, xscale, yscale); + _glfwGetHMONITORContentScaleWin32(handle, xscale, yscale); } -void _glfwPlatformIconifyWindow(_GLFWwindow* window) +void _glfwIconifyWindowWin32(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); } -void _glfwPlatformRestoreWindow(_GLFWwindow* window) +void _glfwRestoreWindowWin32(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_RESTORE); } -void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +void _glfwMaximizeWindowWin32(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_MAXIMIZE); + if (IsWindowVisible(window->win32.handle)) + ShowWindow(window->win32.handle, SW_MAXIMIZE); + else + maximizeWindowManually(window); } -void _glfwPlatformShowWindow(_GLFWwindow* window) +void _glfwShowWindowWin32(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_SHOWNA); + 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); } -void _glfwPlatformHideWindow(_GLFWwindow* window) +void _glfwHideWindowWin32(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_HIDE); } -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +void _glfwRequestWindowAttentionWin32(_GLFWwindow* window) { FlashWindow(window->win32.handle, TRUE); } -void _glfwPlatformFocusWindow(_GLFWwindow* window) +void _glfwFocusWindowWin32(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); SetForegroundWindow(window->win32.handle); SetFocus(window->win32.handle); } -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwSetWindowMonitorWin32(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { if (window->monitor == monitor) { @@ -1534,15 +1850,26 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, { if (monitor->window == window) { - acquireMonitor(window); + acquireMonitorWin32(window); fitToMonitor(window); } } else { RECT rect = { xpos, ypos, xpos + width, ypos + height }; - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); + + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + { + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + SetWindowPos(window->win32.handle, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, @@ -1553,11 +1880,11 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } if (window->monitor) - releaseMonitor(window); + releaseMonitorWin32(window); _glfwInputWindowMonitor(window, monitor); - if (monitor) + if (window->monitor) { MONITORINFO mi = { sizeof(mi) }; UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; @@ -1571,9 +1898,9 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, flags |= SWP_FRAMECHANGED; } - acquireMonitor(window); + acquireMonitorWin32(window); - GetMonitorInfo(window->monitor->win32.handle, &mi); + GetMonitorInfoW(window->monitor->win32.handle, &mi); SetWindowPos(window->win32.handle, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, @@ -1602,8 +1929,18 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, else after = HWND_NOTOPMOST; - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); + if (_glfwIsWindows10Version1607OrGreaterWin32()) + { + AdjustWindowRectExForDpi(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window), + GetDpiForWindow(window->win32.handle)); + } + else + { + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + } + SetWindowPos(window->win32.handle, after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, @@ -1611,54 +1948,106 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } } -int _glfwPlatformWindowFocused(_GLFWwindow* window) +GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); } -int _glfwPlatformWindowIconified(_GLFWwindow* window) +GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window) { return IsIconic(window->win32.handle); } -int _glfwPlatformWindowVisible(_GLFWwindow* window) +GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window) { return IsWindowVisible(window->win32.handle); } -int _glfwPlatformWindowMaximized(_GLFWwindow* window) +GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window) { return IsZoomed(window->win32.handle); } -int _glfwPlatformWindowHovered(_GLFWwindow* window) +GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window) { - return cursorInClientArea(window); + return cursorInContentArea(window); } -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window) { - return window->win32.transparent && _glfwIsCompositionEnabledWin32(); + BOOL composition, opaque; + DWORD color; + + if (!window->win32.transparent) + return GLFW_FALSE; + + if (!IsWindowsVistaOrGreater()) + return GLFW_FALSE; + + if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) + return GLFW_FALSE; + + if (!IsWindows8OrGreater()) + { + // HACK: Disable framebuffer transparency on Windows 7 when the + // colorization color is opaque, because otherwise the window + // contents is blended additively with the previous frame instead + // of replacing it + if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque) + return GLFW_FALSE; + } + + return GLFW_TRUE; } -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); } -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled) { updateWindowStyles(window); } -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowFloatingWin32(_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); } -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled) +{ + COLORREF key = 0; + BYTE alpha = 0; + DWORD flags = 0; + DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + + if (exStyle & WS_EX_LAYERED) + GetLayeredWindowAttributes(window->win32.handle, &key, &alpha, &flags); + + if (enabled) + exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); + else + { + exStyle &= ~WS_EX_TRANSPARENT; + // NOTE: Window opacity also needs the layered window style so do not + // remove it if the window is alpha blended + if (exStyle & WS_EX_LAYERED) + { + if (!(flags & LWA_ALPHA)) + exStyle &= ~WS_EX_LAYERED; + } + } + + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); + + if (enabled) + SetLayeredWindowAttributes(window->win32.handle, key, alpha, flags); +} + +float _glfwGetWindowOpacityWin32(_GLFWwindow* window) { BYTE alpha; DWORD flags; @@ -1673,25 +2062,44 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) return 1.f; } -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity) { - if (opacity < 1.f) + LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + if (opacity < 1.f || (exStyle & WS_EX_TRANSPARENT)) { const BYTE alpha = (BYTE) (255 * opacity); - DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - style |= WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + exStyle |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); } + else if (exStyle & WS_EX_TRANSPARENT) + { + SetLayeredWindowAttributes(window->win32.handle, 0, 0, 0); + } else { - DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - style &= ~WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + exStyle &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); } } -void _glfwPlatformPollEvents(void) +void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled) +{ + if (_glfw.win32.disabledCursorWindow != window) + return; + + if (enabled) + enableRawMouseMotion(window); + else + disableRawMouseMotion(window); +} + +GLFWbool _glfwRawMouseMotionSupportedWin32(void) +{ + return GLFW_TRUE; +} + +void _glfwPollEventsWin32(void) { MSG msg; HWND handle; @@ -1719,30 +2127,40 @@ void _glfwPlatformPollEvents(void) } } + // HACK: Release modifier keys that the system did not emit KEYUP for + // NOTE: Shift keys on Windows tend to "stick" when both are pressed as + // no key up message is generated by the first key release + // NOTE: Windows key is not reported as released by the Win+V hotkey + // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus + // because they change the input focus + // NOTE: The other half of this is in the WM_*KEY* handler in windowProc handle = GetActiveWindow(); if (handle) { - // NOTE: Shift keys on Windows tend to "stick" when both are pressed as - // no key up message is generated by the first key release - // The other half of this is in the handling of WM_KEYUP - // HACK: Query actual key state and synthesize release events as needed window = GetPropW(handle, L"GLFW"); if (window) { - const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1; - const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1; + int i; + const int keys[4][2] = + { + { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT }, + { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT }, + { VK_LWIN, GLFW_KEY_LEFT_SUPER }, + { VK_RWIN, GLFW_KEY_RIGHT_SUPER } + }; - if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS) + for (i = 0; i < 4; i++) { - const int mods = getAsyncKeyMods(); - const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT]; - _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); - } - else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS) - { - const int mods = getAsyncKeyMods(); - const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT]; - _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); + const int vk = keys[i][0]; + const int key = keys[i][1]; + const int scancode = _glfw.win32.scancodes[key]; + + if ((GetKeyState(vk) & 0x8000)) + continue; + if (window->keys[key] != GLFW_PRESS) + continue; + + _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods()); } } } @@ -1751,38 +2169,39 @@ void _glfwPlatformPollEvents(void) if (window) { int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeWin32(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) { - _glfwPlatformSetCursorPos(window, width / 2, height / 2); + _glfwSetCursorPosWin32(window, width / 2, height / 2); } } } -void _glfwPlatformWaitEvents(void) +void _glfwWaitEventsWin32(void) { WaitMessage(); - _glfwPlatformPollEvents(); + _glfwPollEventsWin32(); } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwWaitEventsTimeoutWin32(double timeout) { - MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); + MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLINPUT); - _glfwPlatformPollEvents(); + _glfwPollEventsWin32(); } -void _glfwPlatformPostEmptyEvent(void) +void _glfwPostEmptyEventWin32(void) { - PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); + PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); } -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) { POINT pos; @@ -1797,7 +2216,7 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) } } -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos) { POINT pos = { (int) xpos, (int) ypos }; @@ -1809,32 +2228,68 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) SetCursorPos(pos.x, pos.y); } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) + if (_glfwWindowFocusedWin32(window)) { - if (_glfwPlatformWindowFocused(window)) - disableCursor(window); + 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); + } } - else if (_glfw.win32.disabledCursorWindow == window) - enableCursor(window); - else if (cursorInClientArea(window)) + + if (cursorInContentArea(window)) updateCursorImage(window); } -const char* _glfwPlatformGetScancodeName(int scancode) +const char* _glfwGetScancodeNameWin32(int scancode) { - return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; + if (scancode < 0 || scancode > (KF_EXTENDED | 0xff)) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); + return NULL; + } + + const int key = _glfw.win32.keycodes[scancode]; + if (key == GLFW_KEY_UNKNOWN) + return NULL; + + return _glfw.win32.keynames[key]; } -int _glfwPlatformGetKeyScancode(int key) +int _glfwGetKeyScancodeWin32(int key) { return _glfw.win32.scancodes[key]; } -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); if (!cursor->win32.handle) @@ -1843,10 +2298,50 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GLFW_TRUE; } -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape) { - cursor->win32.handle = - CopyCursor(LoadCursorW(NULL, translateCursorShape(shape))); + int id = 0; + + switch (shape) + { + 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; + } + + cursor->win32.handle = LoadImageW(NULL, + MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, + LR_DEFAULTSIZE | LR_SHARED); if (!cursor->win32.handle) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, @@ -1857,21 +2352,21 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) return GLFW_TRUE; } -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +void _glfwDestroyCursorWin32(_GLFWcursor* cursor) { if (cursor->win32.handle) DestroyIcon((HICON) cursor->win32.handle); } -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor) { - if (cursorInClientArea(window)) + if (cursorInContentArea(window)) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(const char* string) +void _glfwSetClipboardStringWin32(const char* string) { - int characterCount; + int characterCount, tries = 0; HANDLE object; WCHAR* buffer; @@ -1899,12 +2394,20 @@ void _glfwPlatformSetClipboardString(const char* string) MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); GlobalUnlock(object); - if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + // 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)) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to open clipboard"); - GlobalFree(object); - return; + Sleep(1); + tries++; + + if (tries == 3) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + GlobalFree(object); + return; + } } EmptyClipboard(); @@ -1912,16 +2415,25 @@ void _glfwPlatformSetClipboardString(const char* string) CloseClipboard(); } -const char* _glfwPlatformGetClipboardString(void) +const char* _glfwGetClipboardStringWin32(void) { HANDLE object; WCHAR* buffer; + int tries = 0; - if (!OpenClipboard(_glfw.win32.helperWindowHandle)) + // 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)) { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "Win32: Failed to open clipboard"); - return NULL; + Sleep(1); + tries++; + + if (tries == 3) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "Win32: Failed to open clipboard"); + return NULL; + } } object = GetClipboardData(CF_UNICODETEXT); @@ -1942,7 +2454,7 @@ const char* _glfwPlatformGetClipboardString(void) return NULL; } - free(_glfw.win32.clipboardString); + _glfw_free(_glfw.win32.clipboardString); _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); GlobalUnlock(object); @@ -1951,7 +2463,58 @@ const char* _glfwPlatformGetClipboardString(void) return _glfw.win32.clipboardString; } -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) +{ + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; + + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_d3d) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D9) + type = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE; + else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D11) + type = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_vulkan) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN) + type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; + } + + if (type) + { + *attribs = _glfw_calloc(3, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + + return 0; +} + +EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void) +{ + return GetDC(_glfw.win32.helperWindowHandle); +} + +EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window) +{ + return window->win32.handle; +} + +void _glfwGetRequiredInstanceExtensionsWin32(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) return; @@ -1960,9 +2523,9 @@ void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) extensions[1] = "VK_KHR_win32_surface"; } -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = @@ -1978,10 +2541,10 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); } -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { VkResult err; VkWin32SurfaceCreateInfoKHR sci; @@ -1998,7 +2561,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, memset(&sci, 0, sizeof(sci)); sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - sci.hinstance = GetModuleHandle(NULL); + sci.hinstance = _glfw.win32.instance; sci.hwnd = window->win32.handle; err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); @@ -2012,15 +2575,20 @@ VkResult _glfwPlatformCreateWindowSurface(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 38a8982..1463d16 100644 --- a/raylib/external/glfw/src/window.c +++ b/raylib/external/glfw/src/window.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 - www.glfw.org +// GLFW 3.4 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-2019 Camilla Löwy // Copyright (c) 2012 Torsten Walluhn // // This software is provided 'as-is', without any express or implied @@ -42,6 +42,9 @@ // 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); @@ -53,7 +56,7 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) { if (window->keys[key] == GLFW_PRESS) { - const int scancode = _glfwPlatformGetKeyScancode(key); + const int scancode = _glfw.platform.getKeyScancode(key); _glfwInputKey(window, key, scancode, GLFW_RELEASE, 0); } } @@ -67,10 +70,12 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused) } // Notifies shared code that a window has moved -// The position is specified in client-area relative screen coordinates +// The position is specified in content area relative screen coordinates // void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) { + assert(window != NULL); + if (window->callbacks.pos) window->callbacks.pos((GLFWwindow*) window, x, y); } @@ -80,6 +85,10 @@ 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); } @@ -88,6 +97,9 @@ 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); } @@ -96,6 +108,9 @@ 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); } @@ -105,6 +120,10 @@ 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); } @@ -114,6 +133,12 @@ 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); } @@ -122,6 +147,8 @@ void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscal // void _glfwInputWindowDamage(_GLFWwindow* window) { + assert(window != NULL); + if (window->callbacks.refresh) window->callbacks.refresh((GLFWwindow*) window); } @@ -130,6 +157,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window) // void _glfwInputWindowCloseRequest(_GLFWwindow* window) { + assert(window != NULL); + window->shouldClose = GLFW_TRUE; if (window->callbacks.close) @@ -140,10 +169,10 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window) // void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor) { + assert(window != NULL); window->monitor = monitor; } - ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// @@ -185,7 +214,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; - window = calloc(1, sizeof(_GLFWwindow)); + window = _glfw_calloc(1, sizeof(_GLFWwindow)); window->next = _glfw.windowListHead; _glfw.windowListHead = window; @@ -196,12 +225,16 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->videoMode.blueBits = fbconfig.blueBits; window->videoMode.refreshRate = _glfw.hints.refreshRate; - window->monitor = (_GLFWmonitor*) monitor; - window->resizable = wndconfig.resizable; - window->decorated = wndconfig.decorated; - window->autoIconify = wndconfig.autoIconify; - window->floating = wndconfig.floating; - window->cursorMode = GLFW_CURSOR_NORMAL; + window->monitor = (_GLFWmonitor*) monitor; + window->resizable = wndconfig.resizable; + window->decorated = wndconfig.decorated; + window->autoIconify = wndconfig.autoIconify; + window->floating = wndconfig.floating; + window->focusOnShow = wndconfig.focusOnShow; + window->mousePassthrough = wndconfig.mousePassthrough; + window->cursorMode = GLFW_CURSOR_NORMAL; + + window->doublebuffer = fbconfig.doublebuffer; window->minwidth = GLFW_DONT_CARE; window->minheight = GLFW_DONT_CARE; @@ -209,42 +242,14 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->maxheight = GLFW_DONT_CARE; window->numer = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE; + window->title = _glfw_strdup(title); - // Open the actual window and create its context - if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) + if (!_glfw.platform.createWindow(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 (window->monitor) - { - if (wndconfig.centerCursor) - { - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); - } - } - else - { - if (wndconfig.visible) - { - _glfwPlatformShowWindow(window); - if (wndconfig.focused) - _glfwPlatformFocusWindow(window); - } - } - return (GLFWwindow*) window; } @@ -267,6 +272,10 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.focused = GLFW_TRUE; _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 @@ -281,9 +290,6 @@ 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) @@ -361,15 +367,37 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_VISIBLE: _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_COCOA_RETINA_FRAMEBUFFER: - _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; + case GLFW_POSITION_X: + _glfw.hints.window.xpos = value; + return; + case GLFW_POSITION_Y: + _glfw.hints.window.ypos = value; + 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; + case GLFW_FOCUS_ON_SHOW: + _glfw.hints.window.focusOnShow = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_MOUSE_PASSTHROUGH: + _glfw.hints.window.mousePassthrough = value ? GLFW_TRUE : GLFW_FALSE; + return; case GLFW_CLIENT_API: _glfw.hints.context.client = value; return; @@ -388,7 +416,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_OPENGL_FORWARD_COMPAT: _glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_OPENGL_DEBUG_CONTEXT: + case GLFW_CONTEXT_DEBUG: _glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_CONTEXT_NO_ERROR: @@ -428,6 +456,10 @@ 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); @@ -451,7 +483,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) if (window == _glfwPlatformGetTls(&_glfw.contextSlot)) glfwMakeContextCurrent(NULL); - _glfwPlatformDestroyWindow(window); + _glfw.platform.destroyWindow(window); // Unlink window from global linked list { @@ -463,7 +495,8 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) *prev = window->next; } - free(window); + _glfw_free(window->title); + _glfw_free(window); } GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) @@ -484,6 +517,16 @@ 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; @@ -491,19 +534,45 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) assert(title != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformSetWindowTitle(window, title); + + char* prev = window->title; + window->title = _glfw_strdup(title); + + _glfw.platform.setWindowTitle(window, title); + _glfw_free(prev); } 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(); - _glfwPlatformSetWindowIcon(window, count, images); + + 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); } GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) @@ -517,7 +586,7 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) *ypos = 0; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetWindowPos(window, xpos, ypos); + _glfw.platform.getWindowPos(window, xpos, ypos); } GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) @@ -530,7 +599,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) if (window->monitor) return; - _glfwPlatformSetWindowPos(window, xpos, ypos); + _glfw.platform.setWindowPos(window, xpos, ypos); } GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) @@ -544,7 +613,7 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) *height = 0; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetWindowSize(window, width, height); + _glfw.platform.getWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) @@ -559,7 +628,7 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) window->videoMode.width = width; window->videoMode.height = height; - _glfwPlatformSetWindowSize(window, width, height); + _glfw.platform.setWindowSize(window, width, height); } GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, @@ -602,9 +671,9 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, if (window->monitor || !window->resizable) return; - _glfwPlatformSetWindowSizeLimits(window, - minwidth, minheight, - maxwidth, maxheight); + _glfw.platform.setWindowSizeLimits(window, + minwidth, minheight, + maxwidth, maxheight); } GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) @@ -633,7 +702,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) if (window->monitor || !window->resizable) return; - _glfwPlatformSetWindowAspectRatio(window, numer, denom); + _glfw.platform.setWindowAspectRatio(window, numer, denom); } GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) @@ -647,7 +716,7 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) *height = 0; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetFramebufferSize(window, width, height); + _glfw.platform.getFramebufferSize(window, width, height); } GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, @@ -667,7 +736,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, *bottom = 0; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); + _glfw.platform.getWindowFrameSize(window, left, top, right, bottom); } GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, @@ -682,7 +751,7 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, *yscale = 0.f; _GLFW_REQUIRE_INIT(); - _glfwPlatformGetWindowContentScale(window, xscale, yscale); + _glfw.platform.getWindowContentScale(window, xscale, yscale); } GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) @@ -690,8 +759,8 @@ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(1.f); - return _glfwPlatformGetWindowOpacity(window); + _GLFW_REQUIRE_INIT_OR_RETURN(0.f); + return _glfw.platform.getWindowOpacity(window); } GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) @@ -710,7 +779,7 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) return; } - _glfwPlatformSetWindowOpacity(window, opacity); + _glfw.platform.setWindowOpacity(window, opacity); } GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) @@ -719,7 +788,7 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) assert(window != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformIconifyWindow(window); + _glfw.platform.iconifyWindow(window); } GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) @@ -728,7 +797,7 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) assert(window != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformRestoreWindow(window); + _glfw.platform.restoreWindow(window); } GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) @@ -741,7 +810,7 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) if (window->monitor) return; - _glfwPlatformMaximizeWindow(window); + _glfw.platform.maximizeWindow(window); } GLFWAPI void glfwShowWindow(GLFWwindow* handle) @@ -754,8 +823,10 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) if (window->monitor) return; - _glfwPlatformShowWindow(window); - _glfwPlatformFocusWindow(window); + _glfw.platform.showWindow(window); + + if (window->focusOnShow) + _glfw.platform.focusWindow(window); } GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) @@ -765,7 +836,7 @@ GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - _glfwPlatformRequestWindowAttention(window); + _glfw.platform.requestWindowAttention(window); } GLFWAPI void glfwHideWindow(GLFWwindow* handle) @@ -778,7 +849,7 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) if (window->monitor) return; - _glfwPlatformHideWindow(window); + _glfw.platform.hideWindow(window); } GLFWAPI void glfwFocusWindow(GLFWwindow* handle) @@ -788,7 +859,7 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - _glfwPlatformFocusWindow(window); + _glfw.platform.focusWindow(window); } GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) @@ -801,17 +872,21 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) switch (attrib) { case GLFW_FOCUSED: - return _glfwPlatformWindowFocused(window); + return _glfw.platform.windowFocused(window); case GLFW_ICONIFIED: - return _glfwPlatformWindowIconified(window); + return _glfw.platform.windowIconified(window); case GLFW_VISIBLE: - return _glfwPlatformWindowVisible(window); + return _glfw.platform.windowVisible(window); case GLFW_MAXIMIZED: - return _glfwPlatformWindowMaximized(window); + return _glfw.platform.windowMaximized(window); case GLFW_HOVERED: - return _glfwPlatformWindowHovered(window); + return _glfw.platform.windowHovered(window); + case GLFW_FOCUS_ON_SHOW: + return window->focusOnShow; + case GLFW_MOUSE_PASSTHROUGH: + return window->mousePassthrough; case GLFW_TRANSPARENT_FRAMEBUFFER: - return _glfwPlatformFramebufferTransparent(window); + return _glfw.platform.framebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: @@ -820,6 +895,8 @@ 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: @@ -834,7 +911,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->context.robustness; case GLFW_OPENGL_FORWARD_COMPAT: return window->context.forward; - case GLFW_OPENGL_DEBUG_CONTEXT: + case GLFW_CONTEXT_DEBUG: return window->context.debug; case GLFW_OPENGL_PROFILE: return window->context.profile; @@ -857,37 +934,41 @@ GLFWAPI void glfwSetWindowAttrib(GLFWwindow* handle, int attrib, int value) value = value ? GLFW_TRUE : GLFW_FALSE; - if (attrib == GLFW_AUTO_ICONIFY) - window->autoIconify = value; - else if (attrib == GLFW_RESIZABLE) + switch (attrib) { - if (window->resizable == value) + case GLFW_AUTO_ICONIFY: + window->autoIconify = value; return; - window->resizable = value; - if (!window->monitor) - _glfwPlatformSetWindowResizable(window, value); - } - else if (attrib == GLFW_DECORATED) - { - if (window->decorated == value) + case GLFW_RESIZABLE: + window->resizable = value; + if (!window->monitor) + _glfw.platform.setWindowResizable(window, value); return; - window->decorated = value; - if (!window->monitor) - _glfwPlatformSetWindowDecorated(window, value); - } - else if (attrib == GLFW_FLOATING) - { - if (window->floating == value) + case GLFW_DECORATED: + window->decorated = value; + if (!window->monitor) + _glfw.platform.setWindowDecorated(window, value); return; - window->floating = value; - if (!window->monitor) - _glfwPlatformSetWindowFloating(window, value); + 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; } - else - _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute 0x%08X", attrib); } GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) @@ -933,9 +1014,9 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, window->videoMode.height = height; window->videoMode.refreshRate = refreshRate; - _glfwPlatformSetWindowMonitor(window, monitor, - xpos, ypos, width, height, - refreshRate); + _glfw.platform.setWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); } GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) @@ -963,7 +1044,7 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); + _GLFW_SWAP(GLFWwindowposfun, window->callbacks.pos, cbfun); return cbfun; } @@ -974,7 +1055,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); + _GLFW_SWAP(GLFWwindowsizefun, window->callbacks.size, cbfun); return cbfun; } @@ -985,7 +1066,7 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); + _GLFW_SWAP(GLFWwindowclosefun, window->callbacks.close, cbfun); return cbfun; } @@ -996,7 +1077,7 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); + _GLFW_SWAP(GLFWwindowrefreshfun, window->callbacks.refresh, cbfun); return cbfun; } @@ -1007,7 +1088,7 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); + _GLFW_SWAP(GLFWwindowfocusfun, window->callbacks.focus, cbfun); return cbfun; } @@ -1018,7 +1099,7 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); + _GLFW_SWAP(GLFWwindowiconifyfun, window->callbacks.iconify, cbfun); return cbfun; } @@ -1029,7 +1110,7 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* handle, assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.maximize, cbfun); + _GLFW_SWAP(GLFWwindowmaximizefun, window->callbacks.maximize, cbfun); return cbfun; } @@ -1040,7 +1121,7 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); + _GLFW_SWAP(GLFWframebuffersizefun, window->callbacks.fbsize, cbfun); return cbfun; } @@ -1051,24 +1132,20 @@ GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* assert(window != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - _GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun); + _GLFW_SWAP(GLFWwindowcontentscalefun, window->callbacks.scale, cbfun); return cbfun; } GLFWAPI void glfwPollEvents(void) { _GLFW_REQUIRE_INIT(); - _glfwPlatformPollEvents(); + _glfw.platform.pollEvents(); } GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); - - if (!_glfw.windowListHead) - return; - - _glfwPlatformWaitEvents(); + _glfw.platform.waitEvents(); } GLFWAPI void glfwWaitEventsTimeout(double timeout) @@ -1084,16 +1161,12 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout) return; } - _glfwPlatformWaitEventsTimeout(timeout); + _glfw.platform.waitEventsTimeout(timeout); } GLFWAPI void glfwPostEmptyEvent(void) { _GLFW_REQUIRE_INIT(); - - if (!_glfw.windowListHead) - return; - - _glfwPlatformPostEmptyEvent(); + _glfw.platform.postEmptyEvent(); } diff --git a/raylib/external/glfw/src/wl_init.c b/raylib/external/glfw/src/wl_init.c index c19184d..2428c72 100644 --- a/raylib/external/glfw/src/wl_init.c +++ b/raylib/external/glfw/src/wl_init.c @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.3 Wayland - www.glfw.org +// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // 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 @@ -26,7 +27,10 @@ #include "internal.h" -#include +#if defined(_GLFW_WAYLAND) + +#include +#include #include #include #include @@ -34,670 +38,73 @@ #include #include #include -#include - - -static inline int min(int n1, int n2) -{ - return n1 < n2 ? n1 : n2; -} - -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; -} - -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; - - int focus = 0; - _GLFWwindow* window = wl_surface_get_user_data(surface); - if (!window) - { - window = findWindowFromDecorationSurface(surface, &focus); - if (!window) - return; - } - - window->wl.decorations.focus = focus; - _glfw.wl.pointerSerial = serial; - _glfw.wl.pointerFocus = window; - - window->wl.hovered = GLFW_TRUE; - - _glfwPlatformSetCursor(window, window->wl.currentCursor); - _glfwInputCursorEnter(window, GLFW_TRUE); -} - -static void pointerHandleLeave(void* data, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface) -{ - _GLFWwindow* window = _glfw.wl.pointerFocus; - - if (!window) - return; - - window->wl.hovered = GLFW_FALSE; - - _glfw.wl.pointerSerial = serial; - _glfw.wl.pointerFocus = NULL; - _glfwInputCursorEnter(window, GLFW_FALSE); -} - -static void setCursor(const char* name) -{ - struct wl_buffer* buffer; - struct wl_cursor* cursor; - struct wl_cursor_image* image; - struct wl_surface* surface = _glfw.wl.cursorSurface; - - cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, - name); - if (!cursor) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Standard cursor not found"); - return; - } - 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.pointerSerial, - surface, - image->hotspot_x, - image->hotspot_y); - wl_surface_attach(surface, buffer, 0, 0); - wl_surface_damage(surface, 0, 0, - image->width, image->height); - wl_surface_commit(surface); -} - -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; - - if (!window) - return; - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - return; - else - { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - } - - switch (window->wl.decorations.focus) - { - case mainWindow: - _glfwInputCursorPos(window, - wl_fixed_to_double(sx), - wl_fixed_to_double(sy)); - return; - case topDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) - cursorName = "n-resize"; - else - cursorName = "left_ptr"; - break; - case leftDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) - cursorName = "nw-resize"; - else - cursorName = "w-resize"; - break; - case rightDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) - cursorName = "ne-resize"; - else - cursorName = "e-resize"; - break; - case bottomDecoration: - if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) - cursorName = "sw-resize"; - else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) - cursorName = "se-resize"; - else - cursorName = "s-resize"; - break; - default: - assert(0); - } - setCursor(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; - - // Both xdg-shell and wl_shell use the same values. - uint32_t edges = WL_SHELL_SURFACE_RESIZE_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 = WL_SHELL_SURFACE_RESIZE_TOP; - else - { - if (window->wl.xdg.toplevel) - xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); - else - wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial); - } - break; - case leftDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) - edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; - else - edges = WL_SHELL_SURFACE_RESIZE_LEFT; - break; - case rightDecoration: - if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) - edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; - else - edges = WL_SHELL_SURFACE_RESIZE_RIGHT; - break; - case bottomDecoration: - if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) - edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; - else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) - edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; - else - edges = WL_SHELL_SURFACE_RESIZE_BOTTOM; - break; - default: - assert(0); - } - if (edges != WL_SHELL_SURFACE_RESIZE_NONE) - { - if (window->wl.xdg.toplevel) - xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, - serial, edges); - else - wl_shell_surface_resize(window->wl.shellSurface, _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.pointerSerial = 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.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.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; - - _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; - timer.it_interval.tv_sec = _glfw.wl.keyboardRepeatRate / 1000; - timer.it_interval.tv_nsec = (_glfw.wl.keyboardRepeatRate % 1000) * 1000000; - 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; - - 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 wmBaseHandlePing(void* data, +#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 + +#define types _glfw_wayland_types +#include "wayland-client-protocol-code.h" +#undef types + +#define types _glfw_xdg_shell_types +#include "xdg-shell-client-protocol-code.h" +#undef types + +#define types _glfw_xdg_decoration_types +#include "xdg-decoration-unstable-v1-client-protocol-code.h" +#undef types + +#define types _glfw_viewporter_types +#include "viewporter-client-protocol-code.h" +#undef types + +#define types _glfw_relative_pointer_types +#include "relative-pointer-unstable-v1-client-protocol-code.h" +#undef types + +#define types _glfw_pointer_constraints_types +#include "pointer-constraints-unstable-v1-client-protocol-code.h" +#undef types + +#define types _glfw_fractional_scale_types +#include "fractional-scale-v1-client-protocol-code.h" +#undef types + +#define types _glfw_xdg_activation_types +#include "xdg-activation-v1-client-protocol-code.h" +#undef types + +#define types _glfw_idle_inhibit_types +#include "idle-inhibit-unstable-v1-client-protocol-code.h" +#undef types + +static void wmBaseHandlePing(void* userData, 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* data, +static void registryHandleGlobal(void* userData, struct wl_registry* registry, uint32_t name, const char* interface, @@ -705,10 +112,9 @@ static void registryHandleGlobal(void* data, { if (strcmp(interface, "wl_compositor") == 0) { - _glfw.wl.compositorVersion = min(3, version); _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, - _glfw.wl.compositorVersion); + _glfw_min(3, version)); } else if (strcmp(interface, "wl_subcompositor") == 0) { @@ -720,11 +126,6 @@ static void registryHandleGlobal(void* data, _glfw.wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } - else if (strcmp(interface, "wl_shell") == 0) - { - _glfw.wl.shell = - wl_registry_bind(registry, name, &wl_shell_interface, 1); - } else if (strcmp(interface, "wl_output") == 0) { _glfwAddOutputWayland(name, version); @@ -733,11 +134,19 @@ static void registryHandleGlobal(void* data, { if (!_glfw.wl.seat) { - _glfw.wl.seatVersion = min(4, version); _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, - _glfw.wl.seatVersion); - wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); + _glfw_min(4, version)); + _glfwAddSeatListenerWayland(_glfw.wl.seat); + } + } + else if (strcmp(interface, "wl_data_device_manager") == 0) + { + if (!_glfw.wl.dataDeviceManager) + { + _glfw.wl.dataDeviceManager = + wl_registry_bind(registry, name, + &wl_data_device_manager_interface, 1); } } else if (strcmp(interface, "xdg_wm_base") == 0) @@ -746,6 +155,13 @@ static void registryHandleGlobal(void* data, wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL); } + else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) + { + _glfw.wl.decorationManager = + wl_registry_bind(registry, name, + &zxdg_decoration_manager_v1_interface, + 1); + } else if (strcmp(interface, "wp_viewporter") == 0) { _glfw.wl.viewporter = @@ -772,18 +188,29 @@ static void registryHandleGlobal(void* data, &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 *data, - struct wl_registry *registry, +static void registryHandleGlobalRemove(void* userData, + struct wl_registry* registry, uint32_t name) { - int i; - _GLFWmonitor* monitor; - - for (i = 0; i < _glfw.monitorCount; ++i) + for (int i = 0; i < _glfw.monitorCount; ++i) { - monitor = _glfw.monitors[i]; + _GLFWmonitor* monitor = _glfw.monitors[i]; if (monitor->wl.name == name) { _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0); @@ -793,17 +220,46 @@ static void registryHandleGlobalRemove(void *data, } -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 createKeyTables(void) +static void createKeyTablesWayland(void) { - int scancode; - memset(_glfw.wl.keycodes, -1, sizeof(_glfw.wl.keycodes)); memset(_glfw.wl.scancodes, -1, sizeof(_glfw.wl.scancodes)); @@ -865,7 +321,7 @@ static void createKeyTables(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_MENU] = GLFW_KEY_MENU; + _glfw.wl.keycodes[KEY_COMPOSE] = 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; @@ -908,7 +364,7 @@ static void createKeyTables(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_KPDOT] = GLFW_KEY_KP_MULTIPLY; + _glfw.wl.keycodes[KEY_KPASTERISK] = 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; @@ -921,116 +377,452 @@ static void createKeyTables(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_KPCOMMA] = GLFW_KEY_KP_DECIMAL; + _glfw.wl.keycodes[KEY_KPDOT] = 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 (scancode = 0; scancode < 256; scancode++) + for (int 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 ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformInit(void) +GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform) { - _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); + 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 + }; + + 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"); if (!_glfw.wl.cursor.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to open libwayland-cursor"); + "Wayland: Failed to load libwayland-cursor"); return GLFW_FALSE; } _glfw.wl.cursor.theme_load = (PFN_wl_cursor_theme_load) - _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); + _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_load"); _glfw.wl.cursor.theme_destroy = (PFN_wl_cursor_theme_destroy) - _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); + _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_destroy"); _glfw.wl.cursor.theme_get_cursor = (PFN_wl_cursor_theme_get_cursor) - _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); + _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor"); _glfw.wl.cursor.image_get_buffer = (PFN_wl_cursor_image_get_buffer) - _glfw_dlsym(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); + _glfwPlatformGetModuleSymbol(_glfw.wl.cursor.handle, "wl_cursor_image_get_buffer"); - _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1"); + _glfw.wl.egl.handle = _glfwPlatformLoadModule("libwayland-egl.so.1"); if (!_glfw.wl.egl.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to open libwayland-egl"); + "Wayland: Failed to load libwayland-egl"); return GLFW_FALSE; } _glfw.wl.egl.window_create = (PFN_wl_egl_window_create) - _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_create"); + _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_create"); _glfw.wl.egl.window_destroy = (PFN_wl_egl_window_destroy) - _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_destroy"); + _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_destroy"); _glfw.wl.egl.window_resize = (PFN_wl_egl_window_resize) - _glfw_dlsym(_glfw.wl.egl.handle, "wl_egl_window_resize"); + _glfwPlatformGetModuleSymbol(_glfw.wl.egl.handle, "wl_egl_window_resize"); - _glfw.wl.xkb.handle = _glfw_dlopen("libxkbcommon.so.0"); + _glfw.wl.xkb.handle = _glfwPlatformLoadModule("libxkbcommon.so.0"); if (!_glfw.wl.xkb.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to open libxkbcommon"); + "Wayland: Failed to load libxkbcommon"); return GLFW_FALSE; } _glfw.wl.xkb.context_new = (PFN_xkb_context_new) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_new"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_new"); _glfw.wl.xkb.context_unref = (PFN_xkb_context_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_context_unref"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_context_unref"); _glfw.wl.xkb.keymap_new_from_string = (PFN_xkb_keymap_new_from_string) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_new_from_string"); _glfw.wl.xkb.keymap_unref = (PFN_xkb_keymap_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_unref"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_unref"); _glfw.wl.xkb.keymap_mod_get_index = (PFN_xkb_keymap_mod_get_index) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_keymap_mod_get_index"); _glfw.wl.xkb.keymap_key_repeats = (PFN_xkb_keymap_key_repeats) - _glfw_dlsym(_glfw.wl.xkb.handle, "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.wl.xkb.state_new = (PFN_xkb_state_new) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_new"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_new"); _glfw.wl.xkb.state_unref = (PFN_xkb_state_unref) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_unref"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_unref"); _glfw.wl.xkb.state_key_get_syms = (PFN_xkb_state_key_get_syms) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_state_key_get_syms"); _glfw.wl.xkb.state_update_mask = (PFN_xkb_state_update_mask) - _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"); - -#ifdef HAVE_XKBCOMMON_COMPOSE_H + _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) - _glfw_dlsym(_glfw.wl.xkb.handle, "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) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_table_unref"); + _glfwPlatformGetModuleSymbol(_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"); + _glfwPlatformGetModuleSymbol(_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"); + _glfwPlatformGetModuleSymbol(_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"); + _glfwPlatformGetModuleSymbol(_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"); + _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) - _glfw_dlsym(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); -#endif + _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); - _glfw.wl.display = wl_display_connect(NULL); - if (!_glfw.wl.display) + 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) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Failed to connect to display"); + "Wayland: Failed to load all entry points from libxkbcommon"); 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); - createKeyTables(); + createKeyTablesWayland(); _glfw.wl.xkb.context = xkb_context_new(0); if (!_glfw.wl.xkb.context) @@ -1046,49 +838,85 @@ int _glfwPlatformInit(void) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); -#ifdef __linux__ - if (!_glfwInitJoysticksLinux()) - return GLFW_FALSE; -#endif - - _glfwInitTimerPOSIX(); - - _glfw.wl.timerfd = -1; - if (_glfw.wl.seatVersion >= 4) - _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); - - if (_glfw.wl.pointer && _glfw.wl.shm) + if (_glfw.wl.libdecor.handle) { - _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); - if (!_glfw.wl.cursorTheme) + _glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface); + if (_glfw.wl.libdecor.context) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Unable to load default cursor theme"); - return GLFW_FALSE; + // 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); } - _glfw.wl.cursorSurface = - wl_compositor_create_surface(_glfw.wl.compositor); + } + + 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); + } + + if (!_glfw.wl.wmBase) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to find xdg-shell in your compositor"); + return GLFW_FALSE; + } + + if (!_glfw.wl.shm) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to find wl_shm in your compositor"); + return GLFW_FALSE; + } + + 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); } return GLFW_TRUE; } -void _glfwPlatformTerminate(void) +void _glfwTerminateWayland(void) { -#ifdef __linux__ - _glfwTerminateJoysticksLinux(); -#endif _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) { - _glfw_dlclose(_glfw.wl.egl.handle); + _glfwPlatformFreeModule(_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) @@ -1097,18 +925,25 @@ void _glfwPlatformTerminate(void) xkb_context_unref(_glfw.wl.xkb.context); if (_glfw.wl.xkb.handle) { - _glfw_dlclose(_glfw.wl.xkb.handle); + _glfwPlatformFreeModule(_glfw.wl.xkb.handle); _glfw.wl.xkb.handle = NULL; } if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); + if (_glfw.wl.cursorThemeHiDPI) + wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI); if (_glfw.wl.cursor.handle) { - _glfw_dlclose(_glfw.wl.cursor.handle); + _glfwPlatformFreeModule(_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) @@ -1117,12 +952,22 @@ void _glfwPlatformTerminate(void) wl_compositor_destroy(_glfw.wl.compositor); if (_glfw.wl.shm) wl_shm_destroy(_glfw.wl.shm); - if (_glfw.wl.shell) - wl_shell_destroy(_glfw.wl.shell); if (_glfw.wl.viewporter) wp_viewporter_destroy(_glfw.wl.viewporter); + if (_glfw.wl.decorationManager) + 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.dataDevice) + wl_data_device_destroy(_glfw.wl.dataDevice); + if (_glfw.wl.dataDeviceManager) + wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager); if (_glfw.wl.pointer) wl_pointer_destroy(_glfw.wl.pointer); if (_glfw.wl.keyboard) @@ -1135,6 +980,10 @@ void _glfwPlatformTerminate(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) @@ -1142,20 +991,14 @@ void _glfwPlatformTerminate(void) wl_display_flush(_glfw.wl.display); wl_display_disconnect(_glfw.wl.display); } + + if (_glfw.wl.keyRepeatTimerfd >= 0) + close(_glfw.wl.keyRepeatTimerfd); + if (_glfw.wl.cursorTimerfd >= 0) + close(_glfw.wl.cursorTimerfd); + + _glfw_free(_glfw.wl.clipboardString); } -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " Wayland EGL" -#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) - " clock_gettime" -#else - " gettimeofday" -#endif - " evdev" -#if defined(_GLFW_BUILD_DLL) - " shared" -#endif - ; -} +#endif // _GLFW_WAYLAND diff --git a/raylib/external/glfw/src/wl_monitor.c b/raylib/external/glfw/src/wl_monitor.c index 5af7408..df30313 100644 --- a/raylib/external/glfw/src/wl_monitor.c +++ b/raylib/external/glfw/src/wl_monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 Wayland - www.glfw.org +// GLFW 3.4 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // @@ -26,43 +26,47 @@ #include "internal.h" +#if defined(_GLFW_WAYLAND) + #include #include #include #include +#include + +#include "wayland-client-protocol.h" -static void geometry(void* data, - struct wl_output* output, - int32_t x, - int32_t y, - int32_t physicalWidth, - int32_t physicalHeight, - int32_t subpixel, - const char* make, - const char* model, - int32_t transform) +static void outputHandleGeometry(void* userData, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t physicalWidth, + int32_t physicalHeight, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) { - struct _GLFWmonitor *monitor = data; - char name[1024]; + struct _GLFWmonitor* monitor = userData; monitor->wl.x = x; monitor->wl.y = y; monitor->widthMM = physicalWidth; monitor->heightMM = physicalHeight; - snprintf(name, sizeof(name), "%s %s", make, model); - monitor->name = _glfw_strdup(name); + if (strlen(monitor->name) == 0) + snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model); } -static void mode(void* data, - struct wl_output* output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) +static void outputHandleMode(void* userData, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) { - struct _GLFWmonitor *monitor = data; + struct _GLFWmonitor* monitor = userData; GLFWvidmode mode; mode.width = width; @@ -70,38 +74,81 @@ static void mode(void* data, mode.redBits = 8; mode.greenBits = 8; mode.blueBits = 8; - mode.refreshRate = refresh / 1000; + mode.refreshRate = (int) round(refresh / 1000.0); monitor->modeCount++; monitor->modes = - realloc(monitor->modes, monitor->modeCount * sizeof(GLFWvidmode)); + _glfw_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 done(void* data, struct wl_output* output) +static void outputHandleDone(void* userData, struct wl_output* output) { - struct _GLFWmonitor *monitor = data; + 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; + } _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } -static void scale(void* data, - struct wl_output* output, - int32_t factor) +static void outputHandleScale(void* userData, + struct wl_output* output, + int32_t factor) { - struct _GLFWmonitor *monitor = data; + struct _GLFWmonitor* monitor = userData; 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; + } + } + } } -static const struct wl_output_listener outputListener = { - geometry, - mode, - done, - scale, +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 = +{ + outputHandleGeometry, + outputHandleMode, + outputHandleDone, + outputHandleScale, + outputHandleName, + outputHandleDescription, }; @@ -111,9 +158,6 @@ 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, @@ -121,23 +165,22 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) return; } - // The actual name of this output will be set in the geometry handler. - monitor = _glfwAllocMonitor(NULL, 0, 0); + version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION); - output = wl_registry_bind(_glfw.wl.registry, - name, - &wl_output_interface, - 2); + struct wl_output* output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + version); 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); } @@ -146,13 +189,13 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitorWayland(_GLFWmonitor* monitor) { if (monitor->wl.output) wl_output_destroy(monitor->wl.output); } -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (xpos) *xpos = monitor->wl.x; @@ -160,8 +203,8 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) *ypos = monitor->wl.y; } -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = (float) monitor->wl.scale; @@ -169,29 +212,43 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, *yscale = (float) monitor->wl.scale; } -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) +{ + if (xpos) + *xpos = monitor->wl.x; + if (ypos) + *ypos = monitor->wl.y; + if (width) + *width = monitor->modes[monitor->wl.currentMode].width; + if (height) + *height = monitor->modes[monitor->wl.currentMode].height; +} + +GLFWvidmode* _glfwGetVideoModesWayland(_GLFWmonitor* monitor, int* found) { *found = monitor->modeCount; return monitor->modes; } -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +GLFWbool _glfwGetVideoModeWayland(_GLFWmonitor* monitor, GLFWvidmode* mode) { *mode = monitor->modes[monitor->wl.currentMode]; + return GLFW_TRUE; } -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Gamma ramp getting not supported yet"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: Gamma ramp access is not available"); + return GLFW_FALSE; } -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Gamma ramp setting not supported yet"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: Gamma ramp access is not available"); } @@ -203,6 +260,15 @@ 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 ef8419e..149cd24 100644 --- a/raylib/external/glfw/src/wl_platform.h +++ b/raylib/external/glfw/src/wl_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 Wayland - www.glfw.org +// GLFW 3.4 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // @@ -24,12 +24,11 @@ // //======================================================================== -#include +#include #include -#ifdef HAVE_XKBCOMMON_COMPOSE_H #include -#endif -#include + +#include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -45,37 +44,100 @@ 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 "egl_context.h" -#include "osmesa_context.h" +#include "posix_poll.h" -#include "wayland-xdg-shell-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" +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 -#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) -#define _glfw_dlclose(handle) dlclose(handle) -#define _glfw_dlsym(handle, name) dlsym(handle, name) +struct wl_shm; +struct wl_output; -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native) -#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display) +#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_PLATFORM_CONTEXT_STATE -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE +#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; struct wl_cursor_image { uint32_t width; @@ -111,24 +173,27 @@ 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_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component); +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); #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_serialize_mods _glfw.wl.xkb.state_serialize_mods +#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 -#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); @@ -143,78 +208,211 @@ 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 -#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) +struct libdecor; +struct libdecor_frame; +struct libdecor_state; +struct libdecor_configuration; -typedef enum _GLFWdecorationSideWayland +enum libdecor_error { - mainWindow, - topDecoration, - leftDecoration, - rightDecoration, - bottomDecoration, + LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE, + LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION, +}; -} _GLFWdecorationSideWayland; +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 +}; -typedef struct _GLFWdecorationWayland +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 { struct wl_surface* surface; struct wl_subsurface* subsurface; struct wp_viewport* viewport; +} _GLFWfallbackEdgeWayland; -} _GLFWdecorationWayland; +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; // 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_shell_surface* shellSurface; 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* title; + char* appId; // We need to track the monitors the window spans on to calculate the // optimal scaling factor. - int scale; - _GLFWmonitor** monitors; - int monitorsCount; - int monitorsSize; + 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; struct { - struct zwp_relative_pointer_v1* relativePointer; - struct zwp_locked_pointer_v1* lockedPointer; - } pointerLock; - - struct zwp_idle_inhibitor_v1* idleInhibitor; - - // This is a hack to prevent auto-iconification on creation. - GLFWbool justCreated; - - struct { - struct wl_buffer* buffer; - _GLFWdecorationWayland top, left, right, bottom; - int focus; - } decorations; - + GLFWbool decorations; + struct wl_buffer* buffer; + _GLFWfallbackEdgeWayland top, left, right, bottom; + struct wl_surface* focus; + } fallback; } _GLFWwindowWayland; // Wayland-specific global data @@ -225,31 +423,50 @@ typedef struct _GLFWlibraryWayland struct wl_registry* registry; struct wl_compositor* compositor; struct wl_subcompositor* subcompositor; - struct wl_shell* shell; struct wl_shm* shm; struct wl_seat* seat; struct wl_pointer* pointer; struct wl_keyboard* keyboard; + struct wl_data_device_manager* dataDeviceManager; + struct wl_data_device* dataDevice; 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; - int compositorVersion; - int seatVersion; + _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; struct wl_cursor_theme* cursorTheme; + struct wl_cursor_theme* cursorThemeHiDPI; struct wl_surface* cursorSurface; - uint32_t pointerSerial; + const char* cursorPreviousName; + int cursorTimerfd; + uint32_t serial; + uint32_t pointerEnterSerial; - int32_t keyboardRepeatRate; - int32_t keyboardRepeatDelay; - int keyboardLastKey; - int keyboardLastScancode; - int timerfd; + int keyRepeatTimerfd; + int32_t keyRepeatRate; + int32_t keyRepeatDelay; + int keyRepeatScancode; + + char* clipboardString; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; + char keynames[GLFW_KEY_LAST + 1][5]; struct { void* handle; @@ -257,16 +474,14 @@ typedef struct _GLFWlibraryWayland struct xkb_keymap* keymap; struct xkb_state* state; -#ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_state* composeState; -#endif - 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; + 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; unsigned int modifiers; PFN_xkb_context_new context_new; @@ -275,13 +490,14 @@ 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_serialize_mods state_serialize_mods; + PFN_xkb_state_key_get_layout state_key_get_layout; + PFN_xkb_state_mod_index_is_active state_mod_index_is_active; -#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; @@ -289,12 +505,34 @@ 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; @@ -312,6 +550,37 @@ 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 @@ -319,25 +588,104 @@ typedef struct _GLFWlibraryWayland typedef struct _GLFWmonitorWayland { struct wl_output* output; - int name; + uint32_t name; int currentMode; int x; int y; - int scale; - + int32_t scale; } _GLFWmonitorWayland; // Wayland-specific per-cursor data // typedef struct _GLFWcursorWayland { - struct wl_cursor_image* image; + struct wl_cursor* cursor; + struct wl_cursor* cursorHiDPI; struct wl_buffer* buffer; int width, height; int xhot, yhot; + 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 c165ba7..505166e 100644 --- a/raylib/external/glfw/src/wl_window.c +++ b/raylib/external/glfw/src/wl_window.c @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.3 Wayland - www.glfw.org +// GLFW 3.4 Wayland (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // 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 @@ -28,85 +29,34 @@ #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" -static void handlePing(void* data, - struct wl_shell_surface* shellSurface, - uint32_t serial) -{ - wl_shell_surface_pong(shellSurface, serial); -} +#define GLFW_BORDER_SIZE 4 +#define GLFW_CAPTION_HEIGHT 24 -static void handleConfigure(void* data, - struct wl_shell_surface* shellSurface, - uint32_t edges, - int32_t width, - int32_t height) -{ - _GLFWwindow* window = data; - float aspectRatio; - float targetRatio; - - if (!window->monitor) - { - if (_glfw.wl.viewporter && window->decorated) - { - width -= _GLFW_DECORATION_HORIZONTAL; - height -= _GLFW_DECORATION_VERTICAL; - } - if (width < 1) - width = 1; - if (height < 1) - height = 1; - - 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; - } - - 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 < window->minheight) - height = window->minheight; - else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight) - height = window->maxheight; - } - - _glfwInputWindowSize(window, width, height); - _glfwPlatformSetWindowSize(window, width, height); - _glfwInputWindowDamage(window); -} - -static void handlePopupDone(void* data, - struct wl_shell_surface* shellSurface) -{ -} - -static const struct wl_shell_surface_listener shellSurfaceListener = { - handlePing, - handleConfigure, - handlePopupDone -}; - -static int -createTmpfileCloexec(char* tmpname) +static int createTmpfileCloexec(char* tmpname) { int fd; @@ -133,12 +83,11 @@ createTmpfileCloexec(char* tmpname) * SCM_RIGHTS methods. * * posix_fallocate() is used to guarantee that disk space is available - * for the file at the given size. If disk space is insufficent, errno + * for the file at the given size. If disk space is insufficient, errno * is set to ENOSPC. If posix_fallocate() is not supported, program may * receive SIGBUS on accessing mmap()'ed file contents instead. */ -static int -createAnonymousFile(off_t size) +static int createAnonymousFile(off_t size) { static const char template[] = "/glfw-shared-XXXXXX"; const char* path; @@ -146,24 +95,46 @@ createAnonymousFile(off_t size) int fd; int ret; - path = getenv("XDG_RUNTIME_DIR"); - if (!path) +#ifdef HAVE_MEMFD_CREATE + fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd >= 0) { - errno = ENOENT; - return -1; + // We can add this seal before calling posix_fallocate(), as the file + // is currently zero-sized anyway. + // + // There is also no need to check for the return value, we couldn’t do + // anything with it anyway. + fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); + } + else +#elif defined(SHM_ANON) + fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600); + if (fd < 0) +#endif + { + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = _glfw_calloc(strlen(path) + sizeof(template), 1); + strcpy(name, path); + strcat(name, template); + + fd = createTmpfileCloexec(name); + _glfw_free(name); + if (fd < 0) + return -1; } - name = calloc(strlen(path) + sizeof(template), 1); - strcpy(name, path); - strcat(name, template); - - fd = createTmpfileCloexec(name); - - free(name); - - if (fd < 0) - return -1; +#if defined(SHM_ANON) + // posix_fallocate does not work on SHM descriptors + ret = ftruncate(fd, size); +#else ret = posix_fallocate(fd, 0, size); +#endif if (ret != 0) { close(fd); @@ -175,37 +146,34 @@ createAnonymousFile(off_t size) static struct wl_buffer* createShmBuffer(const GLFWimage* image) { - 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 stride = image->width * 4; + const int length = image->width * image->height * 4; - fd = createAnonymousFile(length); + const int fd = createAnonymousFile(length); if (fd < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Creating a buffer file for %d B failed: %m", - length); - return GLFW_FALSE; + "Wayland: Failed to create buffer file of size %d: %s", + length, strerror(errno)); + return NULL; } - data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void* data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: mmap failed: %m"); + "Wayland: Failed to map file: %s", strerror(errno)); close(fd); - return GLFW_FALSE; + return NULL; } - pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); close(fd); + unsigned char* source = (unsigned char*) image->pixels; unsigned char* target = data; - for (i = 0; i < image->width * image->height; i++, source += 4) + for (int i = 0; i < image->width * image->height; i++, source += 4) { unsigned int alpha = source[3]; @@ -215,7 +183,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) *target++ = (unsigned char) alpha; } - buffer = + struct wl_buffer* buffer = wl_shm_pool_create_buffer(pool, 0, image->width, image->height, @@ -226,89 +194,112 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) return buffer; } -static void createDecoration(_GLFWdecorationWayland* decoration, - struct wl_surface* parent, - struct wl_buffer* buffer, GLFWbool opaque, - int x, int y, - int width, int height) +static void createFallbackEdge(_GLFWwindow* window, + _GLFWfallbackEdgeWayland* edge, + struct wl_surface* parent, + struct wl_buffer* buffer, + int x, int y, + int width, int height) { - struct wl_region* region; + 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); - 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); + 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); } -static void createDecorations(_GLFWwindow* window) +static void createFallbackDecorations(_GLFWwindow* window) { unsigned char data[] = { 224, 224, 224, 255 }; const GLFWimage image = { 1, 1, data }; - GLFWbool opaque = (data[3] == 255); if (!_glfw.wl.viewporter) return; - if (!window->wl.decorations.buffer) - window->wl.decorations.buffer = createShmBuffer(&image); + if (!window->wl.fallback.buffer) + window->wl.fallback.buffer = createShmBuffer(&image); + if (!window->wl.fallback.buffer) + return; - 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); + 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; } -static void destroyDecoration(_GLFWdecorationWayland* decoration) +static void destroyFallbackEdge(_GLFWfallbackEdgeWayland* edge) { - 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; + 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; } -static void destroyDecorations(_GLFWwindow* window) +static void destroyFallbackDecorations(_GLFWwindow* window) { - destroyDecoration(&window->wl.decorations.top); - destroyDecoration(&window->wl.decorations.left); - destroyDecoration(&window->wl.decorations.right); - destroyDecoration(&window->wl.decorations.bottom); + 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); } +static void xdgDecorationHandleConfigure(void* userData, + struct zxdg_toplevel_decoration_v1* decoration, + uint32_t mode) +{ + _GLFWwindow* window = userData; + + window->wl.xdg.decorationMode = mode; + + if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) + { + if (window->decorated && !window->monitor) + createFallbackDecorations(window); + } + else + destroyFallbackDecorations(window); +} + +static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = +{ + xdgDecorationHandleConfigure, +}; + // Makes the surface considered as XRGB instead of ARGB. -static void setOpaqueRegion(_GLFWwindow* window) +static void setContentAreaOpaque(_GLFWwindow* window) { struct wl_region* region; @@ -318,121 +309,174 @@ static void setOpaqueRegion(_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 resizeWindow(_GLFWwindow* window) +static void resizeFramebuffer(_GLFWwindow* window) { - 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.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); + } + if (!window->wl.transparent) - setOpaqueRegion(window); - _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); - _glfwInputWindowContentScale(window, scale, scale); + setContentAreaOpaque(window); - if (!window->wl.decorations.top.surface) - return; - - // 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); + _glfwInputFramebufferSize(window, window->wl.fbWidth, window->wl.fbHeight); } -static void checkScaleChange(_GLFWwindow* window) +static GLFWbool resizeWindow(_GLFWwindow* window, int width, int height) { - int scale = 1; - int i; - int monitorScale; + width = _glfw_max(width, 1); + height = _glfw_max(height, 1); - // Check if we will be able to set the buffer scale or not. - if (_glfw.wl.compositorVersion < 3) + 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) + return; + + // When using fractional scaling, the buffer scale should remain at 1 + if (window->wl.fractionalScale) return; // Get the scale factor from the highest scale monitor. - for (i = 0; i < window->wl.monitorsCount; ++i) - { - monitorScale = window->wl.monitors[i]->wl.scale; - if (scale < monitorScale) - scale = monitorScale; - } + int32_t maxScale = 1; + + for (size_t i = 0; i < window->wl.outputScaleCount; i++) + maxScale = _glfw_max(window->wl.outputScales[i].factor, maxScale); // Only change the framebuffer size if the scale changed. - if (scale != window->wl.scale) + if (window->wl.bufferScale != maxScale) { - window->wl.scale = scale; - wl_surface_set_buffer_scale(window->wl.surface, scale); - resizeWindow(window); + 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); } } -static void handleEnter(void *data, - struct wl_surface *surface, - struct wl_output *output) +static void surfaceHandleEnter(void* userData, + struct wl_surface* surface, + struct wl_output* output) { - _GLFWwindow* window = data; - _GLFWmonitor* monitor = wl_output_get_user_data(output); + if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag) + return; - if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) + _GLFWwindow* window = userData; + _GLFWmonitor* monitor = wl_output_get_user_data(output); + if (!window || !monitor) + return; + + if (window->wl.outputScaleCount + 1 > window->wl.outputScaleSize) { - ++window->wl.monitorsSize; - window->wl.monitors = - realloc(window->wl.monitors, - window->wl.monitorsSize * sizeof(_GLFWmonitor*)); + window->wl.outputScaleSize++; + window->wl.outputScales = + _glfw_realloc(window->wl.outputScales, + window->wl.outputScaleSize * sizeof(_GLFWscaleWayland)); } - window->wl.monitors[window->wl.monitorsCount++] = monitor; + window->wl.outputScaleCount++; + window->wl.outputScales[window->wl.outputScaleCount - 1] = + (_GLFWscaleWayland) { output, monitor->wl.scale }; - checkScaleChange(window); + _glfwUpdateBufferScaleFromOutputsWayland(window); } -static void handleLeave(void *data, - struct wl_surface *surface, - struct wl_output *output) +static void surfaceHandleLeave(void* userData, + struct wl_surface* surface, + struct wl_output* output) { - _GLFWwindow* window = data; - _GLFWmonitor* monitor = wl_output_get_user_data(output); - GLFWbool found; - int i; + if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag) + return; - for (i = 0, found = GLFW_FALSE; i < window->wl.monitorsCount - 1; ++i) + _GLFWwindow* window = userData; + + for (size_t i = 0; i < window->wl.outputScaleCount; i++) { - if (monitor == window->wl.monitors[i]) - found = GLFW_TRUE; - if (found) - window->wl.monitors[i] = window->wl.monitors[i + 1]; + if (window->wl.outputScales[i].output == output) + { + window->wl.outputScales[i] = + window->wl.outputScales[window->wl.outputScaleCount - 1]; + window->wl.outputScaleCount--; + break; + } } - window->wl.monitors[--window->wl.monitorsCount] = NULL; - checkScaleChange(window); + _glfwUpdateBufferScaleFromOutputsWayland(window); } -static const struct wl_surface_listener surfaceListener = { - handleEnter, - handleLeave +static const struct wl_surface_listener surfaceListener = +{ + surfaceHandleEnter, + surfaceHandleLeave }; static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) @@ -444,7 +488,7 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) _glfw.wl.idleInhibitManager, window->wl.surface); if (!window->wl.idleInhibitor) _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Idle inhibitor creation failed"); + "Wayland: Failed to create idle inhibitor"); } else if (!enable && window->wl.idleInhibitor) { @@ -453,337 +497,1639 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable) } } -static GLFWbool createSurface(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) +// Make the specified window and its video mode active on its monitor +// +static void acquireMonitorWayland(_GLFWwindow* window) { - 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); - - if (window->decorated && !window->monitor) - createDecorations(window); - - return GLFW_TRUE; -} - -static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate) -{ - if (window->wl.xdg.toplevel) + if (window->wl.libdecor.frame) { - xdg_toplevel_set_fullscreen( - window->wl.xdg.toplevel, - monitor->wl.output); + libdecor_frame_set_fullscreen(window->wl.libdecor.frame, + window->monitor->wl.output); } - else if (window->wl.shellSurface) + else if (window->wl.xdg.toplevel) { - wl_shell_surface_set_fullscreen( - window->wl.shellSurface, - WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, - refreshRate * 1000, // Convert Hz to mHz. - monitor->wl.output); + xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, + window->monitor->wl.output); } + setIdleInhibitor(window, GLFW_TRUE); - destroyDecorations(window); + + if (window->wl.fallback.decorations) + destroyFallbackDecorations(window); } -static GLFWbool createShellSurface(_GLFWwindow* window) +// Remove the window and restore the original video mode +// +static void releaseMonitorWayland(_GLFWwindow* window) { - if (!_glfw.wl.shell) + 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) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: wl_shell protocol not available"); - return GLFW_FALSE; + if (window->decorated) + createFallbackDecorations(window); } - - window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell, - window->wl.surface); - if (!window->wl.shellSurface) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Shell surface creation failed"); - return GLFW_FALSE; - } - - wl_shell_surface_add_listener(window->wl.shellSurface, - &shellSurfaceListener, - window); - - if (window->wl.title) - wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title); - - if (window->monitor) - { - setFullscreen(window, window->monitor, 0); - } - else if (window->wl.maximized) - { - wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); - setIdleInhibitor(window, GLFW_FALSE); - } - else - { - wl_shell_surface_set_toplevel(window->wl.shellSurface); - setIdleInhibitor(window, GLFW_FALSE); - } - - wl_surface_commit(window->wl.surface); - - return GLFW_TRUE; } -static void xdgToplevelHandleConfigure(void* data, +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, struct xdg_toplevel* toplevel, int32_t width, int32_t height, struct wl_array* states) { - _GLFWwindow* window = data; - float aspectRatio; - float targetRatio; + _GLFWwindow* window = userData; uint32_t* state; - GLFWbool maximized = GLFW_FALSE; - GLFWbool fullscreen = GLFW_FALSE; - GLFWbool activated = GLFW_FALSE; + + window->wl.pending.activated = GLFW_FALSE; + window->wl.pending.maximized = GLFW_FALSE; + window->wl.pending.fullscreen = GLFW_FALSE; wl_array_for_each(state, states) { switch (*state) { case XDG_TOPLEVEL_STATE_MAXIMIZED: - maximized = GLFW_TRUE; + window->wl.pending.maximized = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_FULLSCREEN: - fullscreen = GLFW_TRUE; + window->wl.pending.fullscreen = GLFW_TRUE; break; case XDG_TOPLEVEL_STATE_RESIZING: break; case XDG_TOPLEVEL_STATE_ACTIVATED: - activated = GLFW_TRUE; + window->wl.pending.activated = GLFW_TRUE; break; } } - if (width != 0 && height != 0) + if (width && height) { - if (!maximized && !fullscreen) + if (window->wl.fallback.decorations) { - 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; - } + 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); + } + else + { + window->wl.pending.width = width; + window->wl.pending.height = height; } - - _glfwInputWindowSize(window, width, height); - _glfwPlatformSetWindowSize(window, width, height); - _glfwInputWindowDamage(window); } - - if (!window->wl.justCreated && !activated && window->autoIconify) - _glfwPlatformIconifyWindow(window); - _glfwInputWindowFocus(window, activated); - window->wl.justCreated = GLFW_FALSE; + else + { + window->wl.pending.width = window->wl.width; + window->wl.pending.height = window->wl.height; + } } -static void xdgToplevelHandleClose(void* data, +static void xdgToplevelHandleClose(void* userData, struct xdg_toplevel* toplevel) { - _GLFWwindow* window = data; + _GLFWwindow* window = userData; _glfwInputWindowCloseRequest(window); } -static const struct xdg_toplevel_listener xdgToplevelListener = { +static const struct xdg_toplevel_listener xdgToplevelListener = +{ xdgToplevelHandleConfigure, xdgToplevelHandleClose }; -static void xdgSurfaceHandleConfigure(void* data, +static void xdgSurfaceHandleConfigure(void* userData, 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 }; -static GLFWbool createXdgSurface(_GLFWwindow* window) +void libdecorFrameHandleConfigure(struct libdecor_frame* frame, + struct libdecor_configuration* config, + void* userData) +{ + _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: xdg-surface creation failed"); + "Wayland: Failed to create xdg-surface for window"); return GLFW_FALSE; } - xdg_surface_add_listener(window->wl.xdg.surface, - &xdgSurfaceListener, - window); + 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: xdg-toplevel creation failed"); + "Wayland: Failed to create xdg-toplevel for window"); return GLFW_FALSE; } - xdg_toplevel_add_listener(window->wl.xdg.toplevel, - &xdgToplevelListener, - window); + 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->wl.appId) + xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId); - 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); + 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); + 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); - } 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 = + zxdg_decoration_manager_v1_get_toplevel_decoration( + _glfw.wl.decorationManager, window->wl.xdg.toplevel); + 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); + } + else + { + if (window->decorated && !window->monitor) + createFallbackDecorations(window); + } + + updateXdgSizeLimits(window); + wl_surface_commit(window->wl.surface); wl_display_roundtrip(_glfw.wl.display); + return GLFW_TRUE; +} + +static GLFWbool createShellObjects(_GLFWwindow* window) +{ + if (_glfw.wl.libdecor.context) + { + 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"); + 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); + + 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) + { + 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); + } + } return GLFW_TRUE; } -static void -handleEvents(int timeout) +static void setCursorImage(_GLFWwindow* window, + _GLFWcursorWayland* cursorWayland) { - struct wl_display* display = _glfw.wl.display; - struct pollfd fds[] = { - { wl_display_get_fd(display), POLLIN }, - { _glfw.wl.timerfd, POLLIN }, - }; - ssize_t read_ret; - uint64_t repeats, i; + struct itimerspec timer = {0}; + struct wl_cursor* wlCursor = cursorWayland->cursor; + struct wl_cursor_image* image; + struct wl_buffer* buffer; + struct wl_surface* surface = _glfw.wl.cursorSurface; + int scale = 1; - while (wl_display_prepare_read(display) != 0) - wl_display_dispatch_pending(display); - - // 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) + if (!wlCursor) + buffer = cursorWayland->buffer; + else { - _GLFWwindow* window = _glfw.windowListHead; - while (window) + if (window->wl.bufferScale > 1 && cursorWayland->cursorHiDPI) { - _glfwInputWindowCloseRequest(window); - window = window->next; + wlCursor = cursorWayland->cursorHiDPI; + scale = 2; } - wl_display_cancel_read(display); - return; + + image = wlCursor->images[cursorWayland->currentImage]; + buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + + timer.it_value.tv_sec = image->delay / 1000; + timer.it_value.tv_nsec = (image->delay % 1000) * 1000000; + timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL); + + cursorWayland->width = image->width; + cursorWayland->height = image->height; + cursorWayland->xhot = image->hotspot_x; + cursorWayland->yhot = image->hotspot_y; } - if (poll(fds, 2, timeout) > 0) + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, + surface, + cursorWayland->xhot / scale, + cursorWayland->yhot / scale); + wl_surface_set_buffer_scale(surface, scale); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + cursorWayland->width, cursorWayland->height); + wl_surface_commit(surface); +} + +static void incrementCursorImage(_GLFWwindow* window) +{ + _GLFWcursor* cursor; + + if (!window || !window->wl.hovered) + return; + + cursor = window->wl.currentCursor; + if (cursor && cursor->wl.cursor) { - if (fds[0].revents & POLLIN) + cursor->wl.currentImage += 1; + cursor->wl.currentImage %= cursor->wl.cursor->image_count; + setCursorImage(window, &cursor->wl); + } +} + +static GLFWbool flushDisplay(void) +{ + 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) { - wl_display_read_events(display); - wl_display_dispatch_pending(display); + 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 } + }; + + if (_glfw.wl.libdecor.context) + fds[LIBDECOR_FD].fd = libdecor_get_fd(_glfw.wl.libdecor.context); + + while (!event) + { + while (wl_display_prepare_read(_glfw.wl.display) != 0) + { + if (wl_display_dispatch_pending(_glfw.wl.display) > 0) + 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()) + { + 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; } else + wl_display_cancel_read(_glfw.wl.display); + + if (fds[KEYREPEAT_FD].revents & POLLIN) { - wl_display_cancel_read(display); + uint64_t repeats; + + if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8) + { + for (uint64_t i = 0; i < repeats; i++) + { + _glfwInputKey(_glfw.wl.keyboardFocus, + translateKeyWayland(_glfw.wl.keyRepeatScancode), + _glfw.wl.keyRepeatScancode, + GLFW_PRESS, + _glfw.wl.xkb.modifiers); + inputText(_glfw.wl.keyboardFocus, _glfw.wl.keyRepeatScancode); + } + + event = GLFW_TRUE; + } } - if (fds[1].revents & POLLIN) + if (fds[CURSOR_FD].revents & POLLIN) { - read_ret = read(_glfw.wl.timerfd, &repeats, sizeof(repeats)); - if (read_ret != 8) - return; + uint64_t repeats; - for (i = 0; i < repeats; ++i) - _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, - _glfw.wl.keyboardLastScancode, GLFW_REPEAT, - _glfw.wl.xkb.modifiers); + 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 { - wl_display_cancel_read(display); + if (window->wl.fallback.decorations) + window->wl.fallback.focus = surface; } } -// Translates a GLFW standard cursor to a theme cursor name -// -static char *translateCursorShape(int shape) +static void pointerHandleLeave(void* userData, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) { - switch (shape) + 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) { - case GLFW_ARROW_CURSOR: - return "left_ptr"; - case GLFW_IBEAM_CURSOR: - return "xterm"; - case GLFW_CROSSHAIR_CURSOR: - return "crosshair"; - case GLFW_HAND_CURSOR: - return "grabbing"; - case GLFW_HRESIZE_CURSOR: - return "sb_h_double_arrow"; - case GLFW_VRESIZE_CURSOR: - return "sb_v_double_arrow"; + window->wl.hovered = GLFW_FALSE; + _glfwInputCursorEnter(window, GLFW_FALSE); + } + else + { + if (window->wl.fallback.decorations) + window->wl.fallback.focus = NULL; } - return 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) + 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; + } + } +} + +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; + } + } +} + +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 ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformCreateWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, - const _GLFWfbconfig* fbconfig) +GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { - window->wl.justCreated = GLFW_TRUE; - window->wl.transparent = fbconfig->transparent; - - if (!createSurface(window, wndconfig)) + if (!createNativeSurface(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) @@ -791,6 +2137,16 @@ int _glfwPlatformCreateWindow(_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)) @@ -803,121 +2159,97 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) return GLFW_FALSE; } + + if (!_glfwRefreshContextAttribs(window, ctxconfig)) + return GLFW_FALSE; } - if (wndconfig->title) - window->wl.title = _glfw_strdup(wndconfig->title); + if (wndconfig->mousePassthrough) + _glfwSetWindowMousePassthroughWayland(window, GLFW_TRUE); - if (wndconfig->visible) + if (window->monitor || wndconfig->visible) { - if (_glfw.wl.wmBase) - { - if (!createXdgSurface(window)) - return GLFW_FALSE; - } - else - { - if (!createShellSurface(window)) - return GLFW_FALSE; - } - - window->wl.visible = GLFW_TRUE; + if (!createShellObjects(window)) + return GLFW_FALSE; } - else - { - window->wl.xdg.surface = NULL; - window->wl.xdg.toplevel = NULL; - window->wl.shellSurface = 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 _glfwPlatformDestroyWindow(_GLFWwindow* window) +void _glfwDestroyWindowWayland(_GLFWwindow* window) { if (window == _glfw.wl.pointerFocus) - { _glfw.wl.pointerFocus = NULL; - _glfwInputCursorEnter(window, GLFW_FALSE); - } + if (window == _glfw.wl.keyboardFocus) - { _glfw.wl.keyboardFocus = NULL; - _glfwInputWindowFocus(window, GLFW_FALSE); - } + + if (window->wl.activationToken) + xdg_activation_token_v1_destroy(window->wl.activationToken); 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); - destroyDecorations(window); - if (window->wl.decorations.buffer) - wl_buffer_destroy(window->wl.decorations.buffer); + destroyShellObjects(window); - if (window->wl.native) - wl_egl_window_destroy(window->wl.native); + if (window->wl.fallback.buffer) + wl_buffer_destroy(window->wl.fallback.buffer); - if (window->wl.shellSurface) - wl_shell_surface_destroy(window->wl.shellSurface); - - 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.egl.window) + wl_egl_window_destroy(window->wl.egl.window); if (window->wl.surface) wl_surface_destroy(window->wl.surface); - free(window->wl.title); - free(window->wl.monitors); + _glfw_free(window->wl.appId); + _glfw_free(window->wl.outputScales); } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title) { - if (window->wl.title) - free(window->wl.title); - window->wl.title = _glfw_strdup(title); - if (window->wl.xdg.toplevel) + if (window->wl.libdecor.frame) + libdecor_frame_set_title(window->wl.libdecor.frame, title); + else if (window->wl.xdg.toplevel) xdg_toplevel_set_title(window->wl.xdg.toplevel, title); - else if (window->wl.shellSurface) - wl_shell_surface_set_title(window->wl.shellSurface, title); } -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwSetWindowIconWayland(_GLFWwindow* window, + int count, const GLFWimage* images) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Setting window icon not supported"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not support setting the window icon"); } -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos) { // A Wayland client is not aware of its position, so just warn and leave it // as (0, 0) - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Window position retrieval not supported"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not provide the window position"); } -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos) { // A Wayland client can not set its position, so just warn - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Window position setting not supported"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not support setting the window position"); } -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height) { if (width) *width = window->wl.width; @@ -925,276 +2257,408 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) *height = window->wl.height; } -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height) { - window->wl.width = width; - window->wl.height = height; - resizeWindow(window); -} - -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) -{ - if (_glfw.wl.wmBase) + if (window->monitor) { - 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; - 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); - } + // Video mode setting is not available on Wayland } else { - // TODO: find out how to trigger a resize. - // The actual limits are checked in the wl_shell_surface::configure handler. + 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); } } -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { - // TODO: find out how to trigger a resize. - // The actual limits are checked in the wl_shell_surface::configure handler. + if (window->wl.libdecor.frame) + { + 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 _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom) { - _glfwPlatformGetWindowSize(window, width, height); - *width *= window->wl.scale; - *height *= window->wl.scale; + 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 _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height) { - if (window->decorated && !window->monitor) + 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_DECORATION_TOP; + *top = GLFW_CAPTION_HEIGHT; if (left) - *left = _GLFW_DECORATION_WIDTH; + *left = GLFW_BORDER_SIZE; if (right) - *right = _GLFW_DECORATION_WIDTH; + *right = GLFW_BORDER_SIZE; if (bottom) - *bottom = _GLFW_DECORATION_WIDTH; + *bottom = GLFW_BORDER_SIZE; } } -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwGetWindowContentScaleWayland(_GLFWwindow* window, + float* xscale, float* yscale) { - if (xscale) - *xscale = (float) window->wl.scale; - if (yscale) - *yscale = (float) window->wl.scale; -} - -void _glfwPlatformIconifyWindow(_GLFWwindow* window) -{ - if (_glfw.wl.wmBase) + if (window->wl.fractionalScale) { - if (window->wl.xdg.toplevel) - xdg_toplevel_set_minimized(window->wl.xdg.toplevel); + if (xscale) + *xscale = (float) window->wl.scalingNumerator / 120.f; + if (yscale) + *yscale = (float) window->wl.scalingNumerator / 120.f; } else { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Iconify window not supported on wl_shell"); + if (xscale) + *xscale = (float) window->wl.bufferScale; + if (yscale) + *yscale = (float) window->wl.bufferScale; } } -void _glfwPlatformRestoreWindow(_GLFWwindow* window) +void _glfwIconifyWindowWayland(_GLFWwindow* window) { - if (window->wl.xdg.toplevel) + 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) { - 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 here. - } - else if (window->wl.shellSurface) - { - if (window->monitor || window->wl.maximized) - wl_shell_surface_set_toplevel(window->wl.shellSurface); - } - _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); - } - else if (window->wl.shellSurface) - { - // Let the compositor select the best output. - wl_shell_surface_set_maximized(window->wl.shellSurface, NULL); - } - window->wl.maximized = GLFW_TRUE; -} - -void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - if (!window->wl.visible) - { - if (_glfw.wl.wmBase) - createXdgSurface(window); - else if (!window->wl.shellSurface) - createShellSurface(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; - } - else if (window->wl.shellSurface) - { - wl_shell_surface_destroy(window->wl.shellSurface); - window->wl.shellSurface = NULL; - } - window->wl.visible = GLFW_FALSE; -} - -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) -{ - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Window attention request not implemented yet"); -} - -void _glfwPlatformFocusWindow(_GLFWwindow* window) -{ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Focusing a window requires user interaction"); -} - -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) -{ - if (monitor) - { - setFullscreen(window, monitor, refreshRate); + // minimized, so there is nothing to do in this case. } else { - if (window->wl.xdg.toplevel) - xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); - else if (window->wl.shellSurface) - wl_shell_surface_set_toplevel(window->wl.shellSurface); - setIdleInhibitor(window, GLFW_FALSE); - if (window->decorated) - createDecorations(window); + // 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; + } } - _glfwInputWindowMonitor(window, monitor); } -int _glfwPlatformWindowFocused(_GLFWwindow* window) +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); + wl_surface_commit(window->wl.surface); + } +} + +void _glfwRequestWindowAttentionWayland(_GLFWwindow* window) +{ + 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); +} + +void _glfwFocusWindowWayland(_GLFWwindow* window) +{ + 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); +} + +void _glfwSetWindowMonitorWayland(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (!monitor) + _glfwSetWindowSizeWayland(window, width, height); + + return; + } + + if (window->monitor) + releaseMonitorWayland(window); + + _glfwInputWindowMonitor(window, monitor); + + if (window->monitor) + acquireMonitorWayland(window); + else + _glfwSetWindowSizeWayland(window, width, height); +} + +GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window) { return _glfw.wl.keyboardFocus == window; } -int _glfwPlatformWindowIconified(_GLFWwindow* window) +GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window) { - // wl_shell doesn't have any iconified concept, and xdg-shell doesn’t give - // any way to request whether a surface is iconified. + // xdg-shell doesn’t give any way to request whether a surface is + // iconified. return GLFW_FALSE; } -int _glfwPlatformWindowVisible(_GLFWwindow* window) +GLFWbool _glfwWindowVisibleWayland(_GLFWwindow* window) { return window->wl.visible; } -int _glfwPlatformWindowMaximized(_GLFWwindow* window) +GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window) { return window->wl.maximized; } -int _glfwPlatformWindowHovered(_GLFWwindow* window) +GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window) { return window->wl.hovered; } -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window) { return window->wl.transparent; } -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Window attribute setting not implemented yet"); -} - -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) -{ - if (!window->monitor) + if (window->wl.libdecor.frame) { if (enabled) - createDecorations(window); + { + libdecor_frame_set_capabilities(window->wl.libdecor.frame, + LIBDECOR_ACTION_RESIZE); + } else - destroyDecorations(window); + { + libdecor_frame_unset_capabilities(window->wl.libdecor.frame, + LIBDECOR_ACTION_RESIZE); + } + } + else if (window->wl.xdg.toplevel) + updateXdgSizeLimits(window); +} + +void _glfwSetWindowDecoratedWayland(_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 (enabled) + createFallbackDecorations(window); + else + destroyFallbackDecorations(window); } } -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Window attribute setting not implemented yet"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: Platform does not support making a window floating"); } -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled) +{ + if (enabled) + { + struct wl_region* region = wl_compositor_create_region(_glfw.wl.compositor); + wl_surface_set_input_region(window->wl.surface, region); + wl_region_destroy(region); + } + else + wl_surface_set_input_region(window->wl.surface, NULL); +} + +float _glfwGetWindowOpacityWayland(_GLFWwindow* window) { return 1.f; } -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity) { + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not support setting the window opacity"); } -void _glfwPlatformPollEvents(void) +void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled) { - handleEvents(0); + // This is handled in relativePointerHandleRelativeMotion } -void _glfwPlatformWaitEvents(void) +GLFWbool _glfwRawMouseMotionSupportedWayland(void) { - handleEvents(-1); + return GLFW_TRUE; } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwPollEventsWayland(void) { - handleEvents((int) (timeout * 1e3)); + double timeout = 0.0; + handleEvents(&timeout); } -void _glfwPlatformPostEmptyEvent(void) +void _glfwWaitEventsWayland(void) +{ + handleEvents(NULL); +} + +void _glfwWaitEventsTimeoutWayland(double timeout) +{ + handleEvents(&timeout); +} + +void _glfwPostEmptyEventWayland(void) { wl_display_sync(_glfw.wl.display); + flushDisplay(); } -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos) { if (xpos) *xpos = window->wl.cursorPosX; @@ -1202,40 +2666,87 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) *ypos = window->wl.cursorPosY; } -static GLFWbool isPointerLocked(_GLFWwindow* window); - -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y) { - if (isPointerLocked(window)) + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The platform does not support setting the cursor position"); +} + +void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode) +{ + _glfwSetCursorWayland(window, window->wl.currentCursor); +} + +const char* _glfwGetScancodeNameWayland(int scancode) +{ + if (scancode < 0 || scancode > 255) { - 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); + _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]; } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) -{ - _glfwPlatformSetCursor(window, window->wl.currentCursor); -} - -const char* _glfwPlatformGetScancodeName(int scancode) -{ - // TODO - return NULL; -} - -int _glfwPlatformGetKeyScancode(int key) +int _glfwGetKeyScancodeWayland(int key) { return _glfw.wl.scancodes[key]; } -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, - const GLFWimage* image, - int xhot, int yhot) +GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) { cursor->wl.buffer = createShmBuffer(image); + if (!cursor->wl.buffer) + return GLFW_FALSE; + cursor->wl.width = image->width; cursor->wl.height = image->height; cursor->wl.xhot = xhot; @@ -1243,138 +2754,245 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, return GLFW_TRUE; } -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape) { - struct wl_cursor* standardCursor; + const char* name = NULL; - standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, - translateCursorShape(shape)); - if (!standardCursor) + // Try the XDG names first + switch (shape) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Standard cursor \"%s\" not found", - translateCursorShape(shape)); - return GLFW_FALSE; + 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; + } + + cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); + + if (_glfw.wl.cursorThemeHiDPI) + { + cursor->wl.cursorHiDPI = + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); + } + + if (!cursor->wl.cursor) + { + // Fall back to the core X11 names + switch (shape) + { + 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; + } + + cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name); + if (!cursor->wl.cursor) + { + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "Wayland: Failed to create standard cursor \"%s\"", + name); + return GLFW_FALSE; + } + + if (_glfw.wl.cursorThemeHiDPI) + { + if (!cursor->wl.cursorHiDPI) + { + cursor->wl.cursorHiDPI = + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name); + } + } } - cursor->wl.image = standardCursor->images[0]; return GLFW_TRUE; } -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +void _glfwDestroyCursorWayland(_GLFWcursor* cursor) { // If it's a standard cursor we don't need to do anything here - if (cursor->wl.image) + if (cursor->wl.cursor) return; if (cursor->wl.buffer) wl_buffer_destroy(cursor->wl.buffer); } -static void handleRelativeMotion(void* data, - struct zwp_relative_pointer_v1* pointer, - uint32_t timeHi, - uint32_t timeLo, - wl_fixed_t dx, - wl_fixed_t dy, - wl_fixed_t dxUnaccel, - wl_fixed_t dyUnaccel) +static void relativePointerHandleRelativeMotion(void* userData, + struct zwp_relative_pointer_v1* pointer, + uint32_t timeHi, + uint32_t timeLo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dxUnaccel, + wl_fixed_t dyUnaccel) { - _GLFWwindow* window = data; + _GLFWwindow* window = userData; + double xpos = window->virtualCursorPosX; + double ypos = window->virtualCursorPosY; if (window->cursorMode != GLFW_CURSOR_DISABLED) return; - _glfwInputCursorPos(window, - window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel), - window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel)); + if (window->rawMouseMotion) + { + xpos += wl_fixed_to_double(dxUnaccel); + ypos += wl_fixed_to_double(dyUnaccel); + } + else + { + xpos += wl_fixed_to_double(dx); + ypos += wl_fixed_to_double(dy); + } + + _glfwInputCursorPos(window, xpos, ypos); } -static const struct zwp_relative_pointer_v1_listener relativePointerListener = { - handleRelativeMotion +static const struct zwp_relative_pointer_v1_listener relativePointerListener = +{ + relativePointerHandleRelativeMotion }; -static void handleLocked(void* data, - struct zwp_locked_pointer_v1* lockedPointer) +static void lockedPointerHandleLocked(void* userData, + struct zwp_locked_pointer_v1* lockedPointer) { } -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 handleUnlocked(void* data, - struct zwp_locked_pointer_v1* lockedPointer) +static void lockedPointerHandleUnlocked(void* userData, + struct zwp_locked_pointer_v1* lockedPointer) { } -static const struct zwp_locked_pointer_v1_listener lockedPointerListener = { - handleLocked, - handleUnlocked +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_PLATFORM_ERROR, - "Wayland: no relative pointer manager"); + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The compositor does not support pointer locking"); return; } - relativePointer = + window->wl.relativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer( _glfw.wl.relativePointerManager, _glfw.wl.pointer); - zwp_relative_pointer_v1_add_listener(relativePointer, + zwp_relative_pointer_v1_add_listener(window->wl.relativePointer, &relativePointerListener, window); - lockedPointer = + window->wl.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(lockedPointer, + zwp_locked_pointer_v1_add_listener(window->wl.lockedPointer, &lockedPointerListener, window); - - window->wl.pointerLock.relativePointer = relativePointer; - window->wl.pointerLock.lockedPointer = lockedPointer; - - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, - NULL, 0, 0); } -static GLFWbool isPointerLocked(_GLFWwindow* window) +static void unlockPointer(_GLFWwindow* window) { - return window->wl.pointerLock.lockedPointer != NULL; + zwp_relative_pointer_v1_destroy(window->wl.relativePointer); + window->wl.relativePointer = NULL; + + zwp_locked_pointer_v1_destroy(window->wl.lockedPointer); + window->wl.lockedPointer = NULL; } -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +static void confinedPointerHandleConfined(void* userData, + struct zwp_confined_pointer_v1* confinedPointer) { - struct wl_buffer* buffer; - struct wl_cursor* defaultCursor; - struct wl_cursor_image* image; - struct wl_surface* surface = _glfw.wl.cursorSurface; +} +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; @@ -1382,84 +3000,215 @@ void _glfwPlatformSetCursor(_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 != _glfw.wl.pointerFocus) + if (!window->wl.hovered) return; - // Unlock possible pointer lock if no longer disabled. - if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) - unlockPointer(window); + // 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); + } - if (window->cursorMode == GLFW_CURSOR_NORMAL) + if (window->cursorMode == GLFW_CURSOR_NORMAL || + window->cursorMode == GLFW_CURSOR_CAPTURED) { if (cursor) - image = cursor->wl.image; + setCursorImage(window, &cursor->wl); else { - defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, - "left_ptr"); + struct wl_cursor* defaultCursor = + wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr"); if (!defaultCursor) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Standard cursor not found"); return; } - image = defaultCursor->images[0]; - } - if (image) - { - buffer = wl_cursor_image_get_buffer(image); - if (!buffer) - return; - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, - surface, - image->hotspot_x, - image->hotspot_y); - wl_surface_attach(surface, buffer, 0, 0); - wl_surface_damage(surface, 0, 0, - image->width, image->height); - wl_surface_commit(surface); - } - else - { - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, - surface, - cursor->wl.xhot, - cursor->wl.yhot); - wl_surface_attach(surface, cursor->wl.buffer, 0, 0); - wl_surface_damage(surface, 0, 0, - cursor->wl.width, cursor->wl.height); - wl_surface_commit(surface); + struct wl_cursor* defaultCursorHiDPI = NULL; + if (_glfw.wl.cursorThemeHiDPI) + { + defaultCursorHiDPI = + wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, "left_ptr"); + } + + _GLFWcursorWayland cursorWayland = + { + defaultCursor, + defaultCursorHiDPI, + NULL, + 0, 0, + 0, 0, + 0 + }; + + setCursorImage(window, &cursorWayland); } } - else if (window->cursorMode == GLFW_CURSOR_DISABLED) + else if (window->cursorMode == GLFW_CURSOR_HIDDEN || + window->cursorMode == GLFW_CURSOR_DISABLED) { - if (!isPointerLocked(window)) - lockPointer(window); + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0); } - else if (window->cursorMode == GLFW_CURSOR_HIDDEN) +} + +static void dataSourceHandleTarget(void* userData, + struct wl_data_source* source, + const char* mimeType) +{ + if (_glfw.wl.selectionSource != source) { - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, - NULL, 0, 0); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unknown clipboard data source"); + return; } } -void _glfwPlatformSetClipboardString(const char* string) +static void dataSourceHandleSend(void* userData, + struct wl_data_source* source, + const char* mimeType, + int fd) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Clipboard setting not implemented yet"); + // Ignore it if this is an outdated or invalid request + if (_glfw.wl.selectionSource != source || + strcmp(mimeType, "text/plain;charset=utf-8") != 0) + { + close(fd); + return; + } + + char* string = _glfw.wl.clipboardString; + size_t length = strlen(string); + + while (length > 0) + { + const ssize_t result = write(fd, string, length); + if (result == -1) + { + if (errno == EINTR) + continue; + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Error while writing the clipboard: %s", + strerror(errno)); + break; + } + + length -= result; + string += result; + } + + close(fd); } -const char* _glfwPlatformGetClipboardString(void) +static void dataSourceHandleCancelled(void* userData, + struct wl_data_source* source) { - // TODO - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Clipboard getting not implemented yet"); - return NULL; + wl_data_source_destroy(source); + + if (_glfw.wl.selectionSource != source) + return; + + _glfw.wl.selectionSource = NULL; } -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +static const struct wl_data_source_listener dataSourceListener = +{ + dataSourceHandleTarget, + dataSourceHandleSend, + dataSourceHandleCancelled, +}; + +void _glfwSetClipboardStringWayland(const char* string) +{ + if (_glfw.wl.selectionSource) + { + wl_data_source_destroy(_glfw.wl.selectionSource); + _glfw.wl.selectionSource = NULL; + } + + char* copy = _glfw_strdup(string); + if (!copy) + { + _glfwInputError(GLFW_OUT_OF_MEMORY, NULL); + return; + } + + _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) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create clipboard data source"); + return; + } + wl_data_source_add_listener(_glfw.wl.selectionSource, + &dataSourceListener, + NULL); + wl_data_source_offer(_glfw.wl.selectionSource, "text/plain;charset=utf-8"); + wl_data_device_set_selection(_glfw.wl.dataDevice, + _glfw.wl.selectionSource, + _glfw.wl.serial); +} + +const char* _glfwGetClipboardStringWayland(void) +{ + if (!_glfw.wl.selectionOffer) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "Wayland: No clipboard data available"); + return NULL; + } + + if (_glfw.wl.selectionSource) + return _glfw.wl.clipboardString; + + _glfw_free(_glfw.wl.clipboardString); + _glfw.wl.clipboardString = + readDataOfferAsString(_glfw.wl.selectionOffer, "text/plain;charset=utf-8"); + return _glfw.wl.clipboardString; +} + +EGLenum _glfwGetEGLPlatformWayland(EGLint** attribs) +{ + if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland) + return EGL_PLATFORM_WAYLAND_EXT; + else + return 0; +} + +EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void) +{ + return _glfw.wl.display; +} + +EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window) +{ + return window->wl.egl.window; +} + +void _glfwGetRequiredInstanceExtensionsWayland(char** extensions) { if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_wayland_surface) return; @@ -1468,9 +3217,9 @@ void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) extensions[1] = "VK_KHR_wayland_surface"; } -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, - VkPhysicalDevice device, - uint32_t queuefamily) +GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) { PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR = @@ -1488,10 +3237,10 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, _glfw.wl.display); } -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { VkResult err; VkWaylandSurfaceCreateInfoKHR sci; @@ -1530,6 +3279,14 @@ VkResult _glfwPlatformCreateWindowSurface(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; } @@ -1537,6 +3294,16 @@ 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 c949916..000bde2 100644 --- a/raylib/external/glfw/src/x11_init.c +++ b/raylib/external/glfw/src/x11_init.c @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 X11 - www.glfw.org +// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,33 +28,28 @@ #include "internal.h" -#include +#if defined(_GLFW_X11) #include #include #include #include #include +#include +#include +#include +#include -// Translate an X11 key code to a GLFW key code. +// Translate the X11 KeySyms for a key to a GLFW key code +// NOTE: This is only used as a fallback, in case the XKB method fails +// It is layout-dependent and will fail partially on most non-US layouts // -static int translateKeyCode(int scancode) +static int translateKeySyms(const KeySym* keysyms, int width) { - int keySym; - - // Valid key code range is [8,255], according to the Xlib manual - if (scancode < 8 || scancode > 255) - return GLFW_KEY_UNKNOWN; - - if (_glfw.x11.xkb.available) + if (width > 1) { - // Try secondary keysym, for numeric keypad keys - // Note: This way we always force "NumLock = ON", which is intentional - // since the returned key code should correspond to a physical - // location. - keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1); - switch (keySym) + switch (keysyms[1]) { case XK_KP_0: return GLFW_KEY_KP_0; case XK_KP_1: return GLFW_KEY_KP_1; @@ -71,22 +67,9 @@ static int translateKeyCode(int scancode) case XK_KP_Enter: return GLFW_KEY_KP_ENTER; default: break; } - - // Now try primary keysym for function keys (non-printable keys) - // These should not depend on the current keyboard layout - keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); - } - else - { - int dummy; - KeySym* keySyms; - - keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); - keySym = keySyms[0]; - XFree(keySyms); } - switch (keySym) + switch (keysyms[0]) { case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Tab: return GLFW_KEY_TAB; @@ -228,9 +211,9 @@ static int translateKeyCode(int scancode) // Create key code translation tables // -static void createKeyTables(void) +static void createKeyTablesX11(void) { - int scancode, key; + int scancodeMin, scancodeMax; memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); @@ -240,103 +223,230 @@ static void createKeyTables(void) // Use XKB to determine physical key locations independently of the // current keyboard layout - char name[XkbKeyNameLength + 1]; XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); - XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); + XkbGetNames(_glfw.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc); + + scancodeMin = desc->min_key_code; + scancodeMax = desc->max_key_code; + + const struct + { + int key; + char* name; + } keymap[] = + { + { GLFW_KEY_GRAVE_ACCENT, "TLDE" }, + { GLFW_KEY_1, "AE01" }, + { GLFW_KEY_2, "AE02" }, + { GLFW_KEY_3, "AE03" }, + { GLFW_KEY_4, "AE04" }, + { GLFW_KEY_5, "AE05" }, + { GLFW_KEY_6, "AE06" }, + { GLFW_KEY_7, "AE07" }, + { GLFW_KEY_8, "AE08" }, + { GLFW_KEY_9, "AE09" }, + { GLFW_KEY_0, "AE10" }, + { GLFW_KEY_MINUS, "AE11" }, + { GLFW_KEY_EQUAL, "AE12" }, + { GLFW_KEY_Q, "AD01" }, + { GLFW_KEY_W, "AD02" }, + { GLFW_KEY_E, "AD03" }, + { GLFW_KEY_R, "AD04" }, + { GLFW_KEY_T, "AD05" }, + { GLFW_KEY_Y, "AD06" }, + { GLFW_KEY_U, "AD07" }, + { GLFW_KEY_I, "AD08" }, + { GLFW_KEY_O, "AD09" }, + { GLFW_KEY_P, "AD10" }, + { GLFW_KEY_LEFT_BRACKET, "AD11" }, + { GLFW_KEY_RIGHT_BRACKET, "AD12" }, + { GLFW_KEY_A, "AC01" }, + { GLFW_KEY_S, "AC02" }, + { GLFW_KEY_D, "AC03" }, + { GLFW_KEY_F, "AC04" }, + { GLFW_KEY_G, "AC05" }, + { GLFW_KEY_H, "AC06" }, + { GLFW_KEY_J, "AC07" }, + { GLFW_KEY_K, "AC08" }, + { GLFW_KEY_L, "AC09" }, + { GLFW_KEY_SEMICOLON, "AC10" }, + { GLFW_KEY_APOSTROPHE, "AC11" }, + { GLFW_KEY_Z, "AB01" }, + { GLFW_KEY_X, "AB02" }, + { GLFW_KEY_C, "AB03" }, + { GLFW_KEY_V, "AB04" }, + { GLFW_KEY_B, "AB05" }, + { GLFW_KEY_N, "AB06" }, + { GLFW_KEY_M, "AB07" }, + { GLFW_KEY_COMMA, "AB08" }, + { GLFW_KEY_PERIOD, "AB09" }, + { GLFW_KEY_SLASH, "AB10" }, + { GLFW_KEY_BACKSLASH, "BKSL" }, + { GLFW_KEY_WORLD_1, "LSGT" }, + { GLFW_KEY_SPACE, "SPCE" }, + { GLFW_KEY_ESCAPE, "ESC" }, + { GLFW_KEY_ENTER, "RTRN" }, + { GLFW_KEY_TAB, "TAB" }, + { GLFW_KEY_BACKSPACE, "BKSP" }, + { GLFW_KEY_INSERT, "INS" }, + { GLFW_KEY_DELETE, "DELE" }, + { GLFW_KEY_RIGHT, "RGHT" }, + { GLFW_KEY_LEFT, "LEFT" }, + { GLFW_KEY_DOWN, "DOWN" }, + { GLFW_KEY_UP, "UP" }, + { GLFW_KEY_PAGE_UP, "PGUP" }, + { GLFW_KEY_PAGE_DOWN, "PGDN" }, + { GLFW_KEY_HOME, "HOME" }, + { GLFW_KEY_END, "END" }, + { GLFW_KEY_CAPS_LOCK, "CAPS" }, + { GLFW_KEY_SCROLL_LOCK, "SCLK" }, + { GLFW_KEY_NUM_LOCK, "NMLK" }, + { GLFW_KEY_PRINT_SCREEN, "PRSC" }, + { GLFW_KEY_PAUSE, "PAUS" }, + { GLFW_KEY_F1, "FK01" }, + { GLFW_KEY_F2, "FK02" }, + { GLFW_KEY_F3, "FK03" }, + { GLFW_KEY_F4, "FK04" }, + { GLFW_KEY_F5, "FK05" }, + { GLFW_KEY_F6, "FK06" }, + { GLFW_KEY_F7, "FK07" }, + { GLFW_KEY_F8, "FK08" }, + { GLFW_KEY_F9, "FK09" }, + { GLFW_KEY_F10, "FK10" }, + { GLFW_KEY_F11, "FK11" }, + { GLFW_KEY_F12, "FK12" }, + { GLFW_KEY_F13, "FK13" }, + { GLFW_KEY_F14, "FK14" }, + { GLFW_KEY_F15, "FK15" }, + { GLFW_KEY_F16, "FK16" }, + { GLFW_KEY_F17, "FK17" }, + { GLFW_KEY_F18, "FK18" }, + { GLFW_KEY_F19, "FK19" }, + { GLFW_KEY_F20, "FK20" }, + { GLFW_KEY_F21, "FK21" }, + { GLFW_KEY_F22, "FK22" }, + { GLFW_KEY_F23, "FK23" }, + { GLFW_KEY_F24, "FK24" }, + { GLFW_KEY_F25, "FK25" }, + { GLFW_KEY_KP_0, "KP0" }, + { GLFW_KEY_KP_1, "KP1" }, + { GLFW_KEY_KP_2, "KP2" }, + { GLFW_KEY_KP_3, "KP3" }, + { GLFW_KEY_KP_4, "KP4" }, + { GLFW_KEY_KP_5, "KP5" }, + { GLFW_KEY_KP_6, "KP6" }, + { GLFW_KEY_KP_7, "KP7" }, + { GLFW_KEY_KP_8, "KP8" }, + { GLFW_KEY_KP_9, "KP9" }, + { GLFW_KEY_KP_DECIMAL, "KPDL" }, + { GLFW_KEY_KP_DIVIDE, "KPDV" }, + { GLFW_KEY_KP_MULTIPLY, "KPMU" }, + { GLFW_KEY_KP_SUBTRACT, "KPSU" }, + { GLFW_KEY_KP_ADD, "KPAD" }, + { GLFW_KEY_KP_ENTER, "KPEN" }, + { GLFW_KEY_KP_EQUAL, "KPEQ" }, + { GLFW_KEY_LEFT_SHIFT, "LFSH" }, + { GLFW_KEY_LEFT_CONTROL, "LCTL" }, + { GLFW_KEY_LEFT_ALT, "LALT" }, + { GLFW_KEY_LEFT_SUPER, "LWIN" }, + { GLFW_KEY_RIGHT_SHIFT, "RTSH" }, + { GLFW_KEY_RIGHT_CONTROL, "RCTL" }, + { GLFW_KEY_RIGHT_ALT, "RALT" }, + { GLFW_KEY_RIGHT_ALT, "LVL3" }, + { GLFW_KEY_RIGHT_ALT, "MDSW" }, + { GLFW_KEY_RIGHT_SUPER, "RWIN" }, + { GLFW_KEY_MENU, "MENU" } + }; // Find the X11 key code -> GLFW key code mapping - for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) + for (int scancode = scancodeMin; scancode <= scancodeMax; scancode++) { - memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); - name[XkbKeyNameLength] = '\0'; + int key = GLFW_KEY_UNKNOWN; - // Map the key name to a GLFW key code. Note: We only map printable - // keys here, and we use the US keyboard layout. The rest of the - // keys (function keys) are mapped using traditional KeySym - // translations. - if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; - else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; - else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; - else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; - else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; - else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; - else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; - else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; - else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; - else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; - else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; - else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; - else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; - else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; - else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; - else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; - else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; - else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; - else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; - else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; - else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; - else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; - else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; - else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; - else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; - else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; - else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; - else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; - else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; - else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; - else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; - else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; - else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; - else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; - else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; - else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; - else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; - else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; - else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; - else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; - else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; - else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; - else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; - else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; - else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; - else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; - else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; - else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; - else key = GLFW_KEY_UNKNOWN; + // Map the key name to a GLFW key code. Note: We use the US + // keyboard layout. Because function keys aren't mapped correctly + // when using traditional KeySym translations, they are mapped + // here instead. + for (int i = 0; i < sizeof(keymap) / sizeof(keymap[0]); i++) + { + if (strncmp(desc->names->keys[scancode].name, + keymap[i].name, + XkbKeyNameLength) == 0) + { + key = keymap[i].key; + break; + } + } - if ((scancode >= 0) && (scancode < 256)) - _glfw.x11.keycodes[scancode] = key; + // Fall back to key aliases in case the key name did not match + for (int i = 0; i < desc->names->num_key_aliases; i++) + { + if (key != GLFW_KEY_UNKNOWN) + break; + + if (strncmp(desc->names->key_aliases[i].real, + desc->names->keys[scancode].name, + XkbKeyNameLength) != 0) + { + continue; + } + + for (int j = 0; j < sizeof(keymap) / sizeof(keymap[0]); j++) + { + if (strncmp(desc->names->key_aliases[i].alias, + keymap[j].name, + XkbKeyNameLength) == 0) + { + key = keymap[j].key; + break; + } + } + } + + _glfw.x11.keycodes[scancode] = key; } XkbFreeNames(desc, XkbKeyNamesMask, True); XkbFreeKeyboard(desc, 0, True); } + else + XDisplayKeycodes(_glfw.x11.display, &scancodeMin, &scancodeMax); - for (scancode = 0; scancode < 256; scancode++) + int width; + KeySym* keysyms = XGetKeyboardMapping(_glfw.x11.display, + scancodeMin, + scancodeMax - scancodeMin + 1, + &width); + + for (int scancode = scancodeMin; scancode <= scancodeMax; scancode++) { // Translate the un-translated key codes using traditional X11 KeySym // lookups if (_glfw.x11.keycodes[scancode] < 0) - _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); + { + const size_t base = (scancode - scancodeMin) * width; + _glfw.x11.keycodes[scancode] = translateKeySyms(&keysyms[base], width); + } // Store the reverse translation for faster key name lookup if (_glfw.x11.keycodes[scancode] > 0) _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; } + + XFree(keysyms); } // Check whether the IM has a usable style // static GLFWbool hasUsableInputMethodStyle(void) { - unsigned int i; GLFWbool found = GLFW_FALSE; XIMStyles* styles = NULL; if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) return GLFW_FALSE; - for (i = 0; i < styles->count_styles; i++) + for (unsigned int i = 0; i < styles->count_styles; i++) { if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) { @@ -349,16 +459,49 @@ static GLFWbool hasUsableInputMethodStyle(void) return found; } -// Check whether the specified atom is supported -// -static Atom getSupportedAtom(Atom* supportedAtoms, - unsigned long atomCount, - const char* atomName) +static void inputMethodDestroyCallback(XIM im, XPointer clientData, XPointer callData) +{ + _glfw.x11.im = NULL; +} + +static void inputMethodInstantiateCallback(Display* display, + XPointer clientData, + XPointer callData) +{ + if (_glfw.x11.im) + return; + + _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); + if (_glfw.x11.im) + { + if (!hasUsableInputMethodStyle()) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + } + + if (_glfw.x11.im) + { + XIMCallback callback; + callback.callback = (XIMProc) inputMethodDestroyCallback; + callback.client_data = NULL; + XSetIMValues(_glfw.x11.im, XNDestroyCallback, &callback, NULL); + + for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) + _glfwCreateInputContextX11(window); + } +} + +// Return the atom ID only if it is listed in the specified array +// +static Atom getAtomIfSupported(Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName) { - unsigned long i; const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); - for (i = 0; i < atomCount; i++) + for (unsigned long i = 0; i < atomCount; i++) { if (supportedAtoms[i] == atom) return atom; @@ -371,18 +514,11 @@ static Atom getSupportedAtom(Atom* supportedAtoms, // static void detectEWMH(void) { + // First we read the _NET_SUPPORTING_WM_CHECK property on the root window + Window* windowFromRoot = NULL; - Window* windowFromChild = NULL; - - // First we need a couple of atoms - const Atom supportingWmCheck = - XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); - const Atom wmSupported = - XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); - - // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window if (!_glfwGetWindowPropertyX11(_glfw.x11.root, - supportingWmCheck, + _glfw.x11.NET_SUPPORTING_WM_CHECK, XA_WINDOW, (unsigned char**) &windowFromRoot)) { @@ -391,10 +527,12 @@ static void detectEWMH(void) _glfwGrabErrorHandlerX11(); - // It should be the ID of a child window (of the root) - // Then we look for the same property on the child window + // If it exists, it should be the XID of a top-level window + // Then we look for the same property on that window + + Window* windowFromChild = NULL; if (!_glfwGetWindowPropertyX11(*windowFromRoot, - supportingWmCheck, + _glfw.x11.NET_SUPPORTING_WM_CHECK, XA_WINDOW, (unsigned char**) &windowFromChild)) { @@ -404,7 +542,8 @@ static void detectEWMH(void) _glfwReleaseErrorHandlerX11(); - // It should be the ID of that same child window + // If the property exists, it should contain the XID of the window + if (*windowFromRoot != *windowFromChild) { XFree(windowFromRoot); @@ -415,43 +554,48 @@ static void detectEWMH(void) XFree(windowFromRoot); XFree(windowFromChild); - // We are now fairly sure that an EWMH-compliant window manager is running + // We are now fairly sure that an EWMH-compliant WM is currently running + // We can now start querying the WM about what features it supports by + // looking in the _NET_SUPPORTED property on the root window + // It should contain a list of supported EWMH protocol and state atoms - Atom* supportedAtoms; - unsigned long atomCount; - - // Now we need to check the _NET_SUPPORTED property of the root window - // It should be a list of supported WM protocol and state atoms - atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root, - wmSupported, - XA_ATOM, - (unsigned char**) &supportedAtoms); + Atom* supportedAtoms = NULL; + const unsigned long atomCount = + _glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_SUPPORTED, + XA_ATOM, + (unsigned char**) &supportedAtoms); // See which of the atoms we support that are supported by the WM + _glfw.x11.NET_WM_STATE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE"); _glfw.x11.NET_WM_STATE_ABOVE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + _glfw.x11.NET_WORKAREA = + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA"); + _glfw.x11.NET_CURRENT_DESKTOP = + getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); _glfw.x11.NET_ACTIVE_WINDOW = - getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); _glfw.x11.NET_FRAME_EXTENTS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); if (supportedAtoms) XFree(supportedAtoms); @@ -461,17 +605,21 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { - _glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1"); +#if defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so"); +#else + _glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1"); +#endif if (_glfw.x11.vidmode.handle) { _glfw.x11.vidmode.QueryExtension = (PFN_XF86VidModeQueryExtension) - _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); + _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeQueryExtension"); _glfw.x11.vidmode.GetGammaRamp = (PFN_XF86VidModeGetGammaRamp) - _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); + _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRamp"); _glfw.x11.vidmode.SetGammaRamp = (PFN_XF86VidModeSetGammaRamp) - _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); + _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeSetGammaRamp"); _glfw.x11.vidmode.GetGammaRampSize = (PFN_XF86VidModeGetGammaRampSize) - _glfw_dlsym(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); + _glfwPlatformGetModuleSymbol(_glfw.x11.vidmode.handle, "XF86VidModeGetGammaRampSize"); _glfw.x11.vidmode.available = XF86VidModeQueryExtension(_glfw.x11.display, @@ -480,16 +628,18 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so"); + _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so"); #else - _glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6"); + _glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6"); #endif if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) - _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XIQueryVersion"); _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) - _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xi.handle, "XISelectEvents"); if (XQueryExtension(_glfw.x11.display, "XInputExtension", @@ -510,48 +660,50 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so"); + _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so"); #else - _glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2"); + _glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2"); #endif if (_glfw.x11.randr.handle) { _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRAllocGamma"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeGamma"); _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRFreeScreenResources"); _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputInfo"); _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryExtension"); _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRQueryVersion"); _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSelectInput"); _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) - _glfw_dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + _glfwPlatformGetModuleSymbol(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); if (XRRQueryExtension(_glfw.x11.display, &_glfw.x11.randr.eventBase, @@ -602,33 +754,43 @@ static GLFWbool initExtensions(void) } #if defined(__CYGWIN__) - _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so"); + _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so"); #else - _glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1"); + _glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1"); #endif if (_glfw.x11.xcursor.handle) { _glfw.x11.xcursor.ImageCreate = (PFN_XcursorImageCreate) - _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageCreate"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageCreate"); _glfw.x11.xcursor.ImageDestroy = (PFN_XcursorImageDestroy) - _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageDestroy"); _glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor) - _glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor"); + _glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme) + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetTheme"); + _glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize) + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize"); + _glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage) + _glfwPlatformGetModuleSymbol(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage"); } #if defined(__CYGWIN__) - _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so"); + _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so"); #else - _glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1"); + _glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1"); #endif if (_glfw.x11.xinerama.handle) { _glfw.x11.xinerama.IsActive = (PFN_XineramaIsActive) - _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaIsActive"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaIsActive"); _glfw.x11.xinerama.QueryExtension = (PFN_XineramaQueryExtension) - _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryExtension"); _glfw.x11.xinerama.QueryScreens = (PFN_XineramaQueryScreens) - _glfw_dlsym(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xinerama.handle, "XineramaQueryScreens"); if (XineramaQueryExtension(_glfw.x11.display, &_glfw.x11.xinerama.major, @@ -658,32 +820,47 @@ static GLFWbool initExtensions(void) if (supported) _glfw.x11.xkb.detectable = GLFW_TRUE; } + + XkbStateRec state; + if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success) + _glfw.x11.xkb.group = (unsigned int)state.group; + + XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, + XkbGroupStateMask, XkbGroupStateMask); } + if (_glfw.hints.init.x11.xcbVulkanSurface) + { #if defined(__CYGWIN__) - _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so"); + _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so"); #else - _glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1"); + _glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1"); #endif + } + if (_glfw.x11.x11xcb.handle) { _glfw.x11.x11xcb.GetXCBConnection = (PFN_XGetXCBConnection) - _glfw_dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); + _glfwPlatformGetModuleSymbol(_glfw.x11.x11xcb.handle, "XGetXCBConnection"); } #if defined(__CYGWIN__) - _glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so"); + _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so"); #else - _glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1"); + _glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1"); #endif if (_glfw.x11.xrender.handle) { _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension) - _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryExtension"); _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion) - _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderQueryVersion"); _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat) - _glfw_dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); + _glfwPlatformGetModuleSymbol(_glfw.x11.xrender.handle, "XRenderFindVisualFormat"); if (XRenderQueryExtension(_glfw.x11.display, &_glfw.x11.xrender.errorBase, @@ -698,13 +875,41 @@ 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"); +#else + _glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6"); +#endif + if (_glfw.x11.xshape.handle) + { + _glfw.x11.xshape.QueryExtension = (PFN_XShapeQueryExtension) + _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryExtension"); + _glfw.x11.xshape.ShapeCombineRegion = (PFN_XShapeCombineRegion) + _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineRegion"); + _glfw.x11.xshape.QueryVersion = (PFN_XShapeQueryVersion) + _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeQueryVersion"); + _glfw.x11.xshape.ShapeCombineMask = (PFN_XShapeCombineMask) + _glfwPlatformGetModuleSymbol(_glfw.x11.xshape.handle, "XShapeCombineMask"); + + if (XShapeQueryExtension(_glfw.x11.display, + &_glfw.x11.xshape.errorBase, + &_glfw.x11.xshape.eventBase)) + { + if (XShapeQueryVersion(_glfw.x11.display, + &_glfw.x11.xshape.major, + &_glfw.x11.xshape.minor)) + { + _glfw.x11.xshape.available = GLFW_TRUE; + } + } + } + // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. - createKeyTables(); - - // Detect whether an EWMH-conformant window manager is running - detectEWMH(); + createKeyTablesX11(); // String format atoms _glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False); @@ -749,6 +954,10 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "WM_STATE", False); _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False); + _glfw.x11.NET_SUPPORTED = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False); + _glfw.x11.NET_SUPPORTING_WM_CHECK = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False); _glfw.x11.NET_WM_ICON = XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False); _glfw.x11.NET_WM_PING = @@ -773,6 +982,9 @@ static GLFWbool initExtensions(void) _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); } + // Detect whether an EWMH-conformant window manager is running + detectEWMH(); + return GLFW_TRUE; } @@ -780,12 +992,10 @@ static GLFWbool initExtensions(void) // static void getSystemContentScale(float* xscale, float* yscale) { - // NOTE: Default to the display-wide DPI as we don't currently have a policy - // for which monitor a window is considered to be on - float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) * - 25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen); - float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) * - 25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen); + // Start by assuming the default X11 DPI + // NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it + // would be set to 96, so assume that is the case if we cannot find it + float xdpi = 96.f, ydpi = 96.f; // NOTE: Basing the scale on Xft.dpi where available should provide the most // consistent user experience (matches Qt, Gtk, etc), although not @@ -819,7 +1029,7 @@ static Cursor createHiddenCursor(void) { unsigned char pixels[16 * 16 * 4] = { 0 }; GLFWimage image = { 16, 16, pixels }; - return _glfwCreateCursorX11(&image, 0, 0); + return _glfwCreateNativeCursorX11(&image, 0, 0); } // Create a helper window for IPC @@ -836,10 +1046,44 @@ 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) { + if (_glfw.x11.display != display) + return 0; + _glfw.x11.errorCode = event->error_code; return 0; } @@ -853,8 +1097,9 @@ static int errorHandler(Display *display, XErrorEvent* event) // void _glfwGrabErrorHandlerX11(void) { + assert(_glfw.x11.errorHandler == NULL); _glfw.x11.errorCode = Success; - XSetErrorHandler(errorHandler); + _glfw.x11.errorHandler = XSetErrorHandler(errorHandler); } // Clears the X error handler callback @@ -863,7 +1108,8 @@ void _glfwReleaseErrorHandlerX11(void) { // Synchronize to make sure all commands are processed XSync(_glfw.x11.display, False); - XSetErrorHandler(NULL); + XSetErrorHandler(_glfw.x11.errorHandler); + _glfw.x11.errorHandler = NULL; } // Reports the specified error, appending information about the last X error @@ -879,9 +1125,8 @@ void _glfwInputErrorX11(int error, const char* message) // Creates a native cursor object from the specified image and hotspot // -Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) +Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot) { - int i; Cursor cursor; if (!_glfw.x11.xcursor.handle) @@ -897,7 +1142,7 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) unsigned char* source = (unsigned char*) image->pixels; XcursorPixel* target = native->pixels; - for (i = 0; i < image->width * image->height; i++, target++, source += 4) + for (int i = 0; i < image->width * image->height; i++, target++, source += 4) { unsigned int alpha = source[3]; @@ -918,78 +1163,396 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformInit(void) +GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) { -#if !defined(X_HAVE_UTF8_STRING) - // HACK: If the current locale is "C" and the Xlib UTF-8 functions are - // unavailable, apply the environment's locale in the hope that it's - // both available and not "C" - // This is done because the "C" locale breaks wide character input, - // which is what we fall back on when UTF-8 support is missing + 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 + // in the hope that it is set to something more sane than "C" if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) setlocale(LC_CTYPE, ""); + +#if defined(__CYGWIN__) + void* module = _glfwPlatformLoadModule("libX11-6.so"); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + void* module = _glfwPlatformLoadModule("libX11.so"); +#else + void* module = _glfwPlatformLoadModule("libX11.so.6"); #endif + if (!module) + { + if (platformID == GLFW_PLATFORM_X11) + _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"); + + _glfwPlatformFreeModule(module); + return GLFW_FALSE; + } XInitThreads(); XrmInitialize(); - _glfw.x11.display = XOpenDisplay(NULL); - if (!_glfw.x11.display) + Display* display = XOpenDisplay(NULL); + if (!display) { - const char* display = getenv("DISPLAY"); - if (display) + if (platformID == GLFW_PLATFORM_X11) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to open display %s", display); - } - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: The DISPLAY environment variable is missing"); + 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"); + } } + _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; _glfw.x11.helperWindowHandle = createHelperWindow(); _glfw.x11.hiddenCursorHandle = createHiddenCursor(); - if (XSupportsLocale()) + if (XSupportsLocale() && _glfw.x11.xlib.utf8) { XSetLocaleModifiers(""); - _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL); - if (_glfw.x11.im) - { - if (!hasUsableInputMethodStyle()) - { - XCloseIM(_glfw.x11.im); - _glfw.x11.im = NULL; - } - } + // If an IM is already present our callback will be called right away + XRegisterIMInstantiateCallback(_glfw.x11.display, + NULL, NULL, NULL, + inputMethodInstantiateCallback, + NULL); } -#if defined(__linux__) - if (!_glfwInitJoysticksLinux()) - return GLFW_FALSE; -#endif - - _glfwInitTimerPOSIX(); - _glfwPollMonitorsX11(); return GLFW_TRUE; } -void _glfwPlatformTerminate(void) +void _glfwTerminateX11(void) { if (_glfw.x11.helperWindowHandle) { @@ -1009,8 +1572,13 @@ void _glfwPlatformTerminate(void) _glfw.x11.hiddenCursorHandle = (Cursor) 0; } - free(_glfw.x11.primarySelectionString); - free(_glfw.x11.clipboardString); + _glfw_free(_glfw.x11.primarySelectionString); + _glfw_free(_glfw.x11.clipboardString); + + XUnregisterIMInstantiateCallback(_glfw.x11.display, + NULL, NULL, NULL, + inputMethodInstantiateCallback, + NULL); if (_glfw.x11.im) { @@ -1026,70 +1594,64 @@ void _glfwPlatformTerminate(void) if (_glfw.x11.x11xcb.handle) { - _glfw_dlclose(_glfw.x11.x11xcb.handle); + _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle); _glfw.x11.x11xcb.handle = NULL; } if (_glfw.x11.xcursor.handle) { - _glfw_dlclose(_glfw.x11.xcursor.handle); + _glfwPlatformFreeModule(_glfw.x11.xcursor.handle); _glfw.x11.xcursor.handle = NULL; } if (_glfw.x11.randr.handle) { - _glfw_dlclose(_glfw.x11.randr.handle); + _glfwPlatformFreeModule(_glfw.x11.randr.handle); _glfw.x11.randr.handle = NULL; } if (_glfw.x11.xinerama.handle) { - _glfw_dlclose(_glfw.x11.xinerama.handle); + _glfwPlatformFreeModule(_glfw.x11.xinerama.handle); _glfw.x11.xinerama.handle = NULL; } if (_glfw.x11.xrender.handle) { - _glfw_dlclose(_glfw.x11.xrender.handle); + _glfwPlatformFreeModule(_glfw.x11.xrender.handle); _glfw.x11.xrender.handle = NULL; } if (_glfw.x11.vidmode.handle) { - _glfw_dlclose(_glfw.x11.vidmode.handle); + _glfwPlatformFreeModule(_glfw.x11.vidmode.handle); _glfw.x11.vidmode.handle = NULL; } if (_glfw.x11.xi.handle) { - _glfw_dlclose(_glfw.x11.xi.handle); + _glfwPlatformFreeModule(_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(); _glfwTerminateGLX(); -#if defined(__linux__) - _glfwTerminateJoysticksLinux(); -#endif + if (_glfw.x11.xlib.handle) + { + _glfwPlatformFreeModule(_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]); + } } -const char* _glfwPlatformGetVersionString(void) -{ - return _GLFW_VERSION_NUMBER " X11 GLX EGL" -#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 - ; -} +#endif // _GLFW_X11 diff --git a/raylib/external/glfw/src/x11_monitor.c b/raylib/external/glfw/src/x11_monitor.c index f557fe4..38af7e0 100644 --- a/raylib/external/glfw/src/x11_monitor.c +++ b/raylib/external/glfw/src/x11_monitor.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 X11 - www.glfw.org +// GLFW 3.4 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -27,9 +27,12 @@ #include "internal.h" +#if defined(_GLFW_X11) + #include #include #include +#include // Check whether the display mode should be included in enumeration @@ -44,7 +47,7 @@ static GLFWbool modeIsGood(const XRRModeInfo* mi) static int calculateRefreshRate(const XRRModeInfo* mi) { if (mi->hTotal && mi->vTotal) - return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); + return (int) round((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); else return 0; } @@ -53,9 +56,7 @@ static int calculateRefreshRate(const XRRModeInfo* mi) // static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) { - int i; - - for (i = 0; i < sr->nmode; i++) + for (int i = 0; i < sr->nmode; i++) { if (sr->modes[i].id == id) return sr->modes + i; @@ -101,7 +102,7 @@ void _glfwPollMonitorsX11(void) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - int i, j, disconnectedCount, screenCount = 0; + int disconnectedCount, screenCount = 0; _GLFWmonitor** disconnected = NULL; XineramaScreenInfo* screens = NULL; XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, @@ -115,20 +116,17 @@ void _glfwPollMonitorsX11(void) disconnectedCount = _glfw.monitorCount; if (disconnectedCount) { - disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); + disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*)); memcpy(disconnected, _glfw.monitors, _glfw.monitorCount * sizeof(_GLFWmonitor*)); } - for (i = 0; i < sr->noutput; i++) + for (int i = 0; i < sr->noutput; i++) { - int type, widthMM, heightMM; - XRROutputInfo* oi; - XRRCrtcInfo* ci; - _GLFWmonitor* monitor; + int j, type, widthMM, heightMM; - oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); + XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]); if (oi->connection != RR_Connected || oi->crtc == None) { XRRFreeOutputInfo(oi); @@ -151,7 +149,7 @@ void _glfwPollMonitorsX11(void) continue; } - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) { widthMM = oi->mm_height; @@ -163,7 +161,17 @@ void _glfwPollMonitorsX11(void) heightMM = oi->mm_height; } - monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); + if (widthMM <= 0 || heightMM <= 0) + { + // HACK: If RandR does not provide a physical size, assume the + // X11 default 96 DPI and calculate from the CRTC viewport + // NOTE: These members are affected by rotation, unlike the mode + // info and output info members + widthMM = (int) (ci->width * 25.4f / 96.f); + heightMM = (int) (ci->height * 25.4f / 96.f); + } + + _GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM); monitor->x11.output = sr->outputs[i]; monitor->x11.crtc = oi->crtc; @@ -195,13 +203,13 @@ void _glfwPollMonitorsX11(void) if (screens) XFree(screens); - for (i = 0; i < disconnectedCount; i++) + for (int i = 0; i < disconnectedCount; i++) { if (disconnected[i]) _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); } - free(disconnected); + _glfw_free(disconnected); } else { @@ -220,24 +228,20 @@ void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - XRRScreenResources* sr; - XRRCrtcInfo* ci; - XRROutputInfo* oi; GLFWvidmode current; - const GLFWvidmode* best; RRMode native = None; - int i; - best = _glfwChooseVideoMode(monitor, desired); - _glfwPlatformGetVideoMode(monitor, ¤t); + const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired); + _glfwGetVideoModeX11(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return; - sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); - for (i = 0; i < oi->nmode; i++) + for (int i = 0; i < oi->nmode; i++) { const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); if (!modeIsGood(mi)) @@ -278,14 +282,12 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - XRRScreenResources* sr; - XRRCrtcInfo* ci; - if (monitor->x11.oldMode == None) return; - sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); XRRSetCrtcConfig(_glfw.x11.display, sr, monitor->x11.crtc, @@ -308,32 +310,34 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitorX11(_GLFWmonitor* monitor) { } -void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - XRRScreenResources* sr; - XRRCrtcInfo* ci; + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + if (ci) + { + if (xpos) + *xpos = ci->x; + if (ypos) + *ypos = ci->y; - if (xpos) - *xpos = ci->x; - if (ypos) - *ypos = ci->y; + XRRFreeCrtcInfo(ci); + } - XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } } -void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, - float* xscale, float* yscale) +void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, + float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; @@ -341,7 +345,101 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, *yscale = _glfw.x11.contentScaleY; } -GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) +void _glfwGetMonitorWorkareaX11(_GLFWmonitor* monitor, + int* xpos, int* ypos, + int* width, int* height) +{ + int areaX = 0, areaY = 0, areaWidth = 0, areaHeight = 0; + + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) + { + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + areaX = ci->x; + areaY = ci->y; + + const XRRModeInfo* mi = getModeInfo(sr, ci->mode); + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + areaWidth = mi->height; + areaHeight = mi->width; + } + else + { + areaWidth = mi->width; + areaHeight = mi->height; + } + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + areaWidth = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + areaHeight = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + } + + if (_glfw.x11.NET_WORKAREA && _glfw.x11.NET_CURRENT_DESKTOP) + { + Atom* extents = NULL; + Atom* desktop = NULL; + const unsigned long extentCount = + _glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_WORKAREA, + XA_CARDINAL, + (unsigned char**) &extents); + + if (_glfwGetWindowPropertyX11(_glfw.x11.root, + _glfw.x11.NET_CURRENT_DESKTOP, + XA_CARDINAL, + (unsigned char**) &desktop) > 0) + { + if (extentCount >= 4 && *desktop < extentCount / 4) + { + const int globalX = extents[*desktop * 4 + 0]; + const int globalY = extents[*desktop * 4 + 1]; + const int globalWidth = extents[*desktop * 4 + 2]; + const int globalHeight = extents[*desktop * 4 + 3]; + + if (areaX < globalX) + { + areaWidth -= globalX - areaX; + areaX = globalX; + } + + if (areaY < globalY) + { + areaHeight -= globalY - areaY; + areaY = globalY; + } + + if (areaX + areaWidth > globalX + globalWidth) + areaWidth = globalX - areaX + globalWidth; + if (areaY + areaHeight > globalY + globalHeight) + areaHeight = globalY - areaY + globalHeight; + } + } + + if (extents) + XFree(extents); + if (desktop) + XFree(desktop); + } + + if (xpos) + *xpos = areaX; + if (ypos) + *ypos = areaY; + if (width) + *width = areaWidth; + if (height) + *height = areaHeight; +} + +GLFWvidmode* _glfwGetVideoModesX11(_GLFWmonitor* monitor, int* count) { GLFWvidmode* result; @@ -349,24 +447,21 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - int i, j; - XRRScreenResources* sr; - XRRCrtcInfo* ci; - XRROutputInfo* oi; + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); - sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + result = _glfw_calloc(oi->nmode, sizeof(GLFWvidmode)); - result = calloc(oi->nmode, sizeof(GLFWvidmode)); - - for (i = 0; i < oi->nmode; i++) + for (int i = 0; i < oi->nmode; i++) { const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); if (!modeIsGood(mi)) continue; const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + int j; for (j = 0; j < *count; j++) { @@ -389,27 +484,38 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) else { *count = 1; - result = calloc(1, sizeof(GLFWvidmode)); - _glfwPlatformGetVideoMode(monitor, result); + result = _glfw_calloc(1, sizeof(GLFWvidmode)); + _glfwGetVideoModeX11(monitor, result); } return result; } -void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +GLFWbool _glfwGetVideoModeX11(_GLFWmonitor* monitor, GLFWvidmode* mode) { if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - XRRScreenResources* sr; - XRRCrtcInfo* ci; + XRRScreenResources* sr = + XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + const XRRModeInfo* mi = NULL; - sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + if (ci) + { + mi = getModeInfo(sr, ci->mode); + if (mi) + *mode = vidmodeFromModeInfo(mi, ci); - *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); + XRRFreeCrtcInfo(ci); + } - XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); + + if (!mi) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to query video mode"); + return GLFW_FALSE; + } } else { @@ -420,9 +526,11 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), &mode->redBits, &mode->greenBits, &mode->blueBits); } + + return GLFW_TRUE; } -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +GLFWbool _glfwGetGammaRampX11(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { @@ -438,6 +546,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); XRRFreeGamma(gamma); + return GLFW_TRUE; } else if (_glfw.x11.vidmode.available) { @@ -449,10 +558,17 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) XF86VidModeGetGammaRamp(_glfw.x11.display, _glfw.x11.screen, ramp->size, ramp->red, ramp->green, ramp->blue); + return GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp access not supported by server"); + return GLFW_FALSE; } } -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +void _glfwSetGammaRampX11(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) { if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) { @@ -481,6 +597,11 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) (unsigned short*) ramp->green, (unsigned short*) ramp->blue); } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Gamma ramp access not supported by server"); + } } @@ -492,6 +613,13 @@ 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; } @@ -499,6 +627,15 @@ 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 c37c740..14e363d 100644 --- a/raylib/external/glfw/src/x11_platform.h +++ b/raylib/external/glfw/src/x11_platform.h @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 X11 - www.glfw.org +// GLFW 3.4 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// Copyright (c) 2006-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 @@ -28,11 +28,11 @@ #include #include #include -#include #include #include #include +#include #include // The XRandR extension provides mode setting and gamma control @@ -47,6 +47,258 @@ // The XInput extension provides raw mouse motion input #include +// 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); +typedef int (* PFN_XChangeProperty)(Display*,Window,Atom,Atom,int,int,const unsigned char*,int); +typedef int (* PFN_XChangeWindowAttributes)(Display*,Window,unsigned long,XSetWindowAttributes*); +typedef Bool (* PFN_XCheckIfEvent)(Display*,XEvent*,Bool(*)(Display*,XEvent*,XPointer),XPointer); +typedef Bool (* PFN_XCheckTypedWindowEvent)(Display*,Window,int,XEvent*); +typedef int (* PFN_XCloseDisplay)(Display*); +typedef Status (* PFN_XCloseIM)(XIM); +typedef int (* PFN_XConvertSelection)(Display*,Atom,Atom,Atom,Window,Time); +typedef Colormap (* PFN_XCreateColormap)(Display*,Window,Visual*,int); +typedef Cursor (* PFN_XCreateFontCursor)(Display*,unsigned int); +typedef XIC (* PFN_XCreateIC)(XIM,...); +typedef Region (* PFN_XCreateRegion)(void); +typedef Window (* PFN_XCreateWindow)(Display*,Window,int,int,unsigned int,unsigned int,unsigned int,int,unsigned int,Visual*,unsigned long,XSetWindowAttributes*); +typedef int (* PFN_XDefineCursor)(Display*,Window,Cursor); +typedef int (* PFN_XDeleteContext)(Display*,XID,XContext); +typedef int (* PFN_XDeleteProperty)(Display*,Window,Atom); +typedef void (* PFN_XDestroyIC)(XIC); +typedef int (* PFN_XDestroyRegion)(Region); +typedef int (* PFN_XDestroyWindow)(Display*,Window); +typedef int (* PFN_XDisplayKeycodes)(Display*,int*,int*); +typedef int (* PFN_XEventsQueued)(Display*,int); +typedef Bool (* PFN_XFilterEvent)(XEvent*,Window); +typedef int (* PFN_XFindContext)(Display*,XID,XContext,XPointer*); +typedef int (* PFN_XFlush)(Display*); +typedef int (* PFN_XFree)(void*); +typedef int (* PFN_XFreeColormap)(Display*,Colormap); +typedef int (* PFN_XFreeCursor)(Display*,Cursor); +typedef void (* PFN_XFreeEventData)(Display*,XGenericEventCookie*); +typedef int (* PFN_XGetErrorText)(Display*,int,char*,int); +typedef Bool (* PFN_XGetEventData)(Display*,XGenericEventCookie*); +typedef char* (* PFN_XGetICValues)(XIC,...); +typedef char* (* PFN_XGetIMValues)(XIM,...); +typedef int (* PFN_XGetInputFocus)(Display*,Window*,int*); +typedef KeySym* (* PFN_XGetKeyboardMapping)(Display*,KeyCode,int,int*); +typedef int (* PFN_XGetScreenSaver)(Display*,int*,int*,int*,int*); +typedef Window (* PFN_XGetSelectionOwner)(Display*,Atom); +typedef XVisualInfo* (* PFN_XGetVisualInfo)(Display*,long,XVisualInfo*,int*); +typedef Status (* PFN_XGetWMNormalHints)(Display*,Window,XSizeHints*,long*); +typedef Status (* PFN_XGetWindowAttributes)(Display*,Window,XWindowAttributes*); +typedef int (* PFN_XGetWindowProperty)(Display*,Window,Atom,long,long,Bool,Atom,Atom*,int*,unsigned long*,unsigned long*,unsigned char**); +typedef int (* PFN_XGrabPointer)(Display*,Window,Bool,unsigned int,int,int,Window,Cursor,Time); +typedef Status (* PFN_XIconifyWindow)(Display*,Window,int); +typedef Status (* PFN_XInitThreads)(void); +typedef Atom (* PFN_XInternAtom)(Display*,const char*,Bool); +typedef int (* PFN_XLookupString)(XKeyEvent*,char*,int,KeySym*,XComposeStatus*); +typedef int (* PFN_XMapRaised)(Display*,Window); +typedef int (* PFN_XMapWindow)(Display*,Window); +typedef int (* PFN_XMoveResizeWindow)(Display*,Window,int,int,unsigned int,unsigned int); +typedef int (* PFN_XMoveWindow)(Display*,Window,int,int); +typedef int (* PFN_XNextEvent)(Display*,XEvent*); +typedef Display* (* PFN_XOpenDisplay)(const char*); +typedef XIM (* PFN_XOpenIM)(Display*,XrmDatabase*,char*,char*); +typedef int (* PFN_XPeekEvent)(Display*,XEvent*); +typedef int (* PFN_XPending)(Display*); +typedef Bool (* PFN_XQueryExtension)(Display*,const char*,int*,int*,int*); +typedef Bool (* PFN_XQueryPointer)(Display*,Window,Window*,Window*,int*,int*,int*,int*,unsigned int*); +typedef int (* PFN_XRaiseWindow)(Display*,Window); +typedef Bool (* PFN_XRegisterIMInstantiateCallback)(Display*,void*,char*,char*,XIDProc,XPointer); +typedef int (* PFN_XResizeWindow)(Display*,Window,unsigned int,unsigned int); +typedef char* (* PFN_XResourceManagerString)(Display*); +typedef int (* PFN_XSaveContext)(Display*,XID,XContext,const char*); +typedef int (* PFN_XSelectInput)(Display*,Window,long); +typedef Status (* PFN_XSendEvent)(Display*,Window,Bool,long,XEvent*); +typedef int (* PFN_XSetClassHint)(Display*,Window,XClassHint*); +typedef XErrorHandler (* PFN_XSetErrorHandler)(XErrorHandler); +typedef void (* PFN_XSetICFocus)(XIC); +typedef char* (* PFN_XSetIMValues)(XIM,...); +typedef int (* PFN_XSetInputFocus)(Display*,Window,int,Time); +typedef char* (* PFN_XSetLocaleModifiers)(const char*); +typedef int (* PFN_XSetScreenSaver)(Display*,int,int,int,int); +typedef int (* PFN_XSetSelectionOwner)(Display*,Atom,Window,Time); +typedef int (* PFN_XSetWMHints)(Display*,Window,XWMHints*); +typedef void (* PFN_XSetWMNormalHints)(Display*,Window,XSizeHints*); +typedef Status (* PFN_XSetWMProtocols)(Display*,Window,Atom*,int); +typedef Bool (* PFN_XSupportsLocale)(void); +typedef int (* PFN_XSync)(Display*,Bool); +typedef Bool (* PFN_XTranslateCoordinates)(Display*,Window,Window,int,int,int*,int*,Window*); +typedef int (* PFN_XUndefineCursor)(Display*,Window); +typedef int (* PFN_XUngrabPointer)(Display*,Time); +typedef int (* PFN_XUnmapWindow)(Display*,Window); +typedef void (* PFN_XUnsetICFocus)(XIC); +typedef VisualID (* PFN_XVisualIDFromVisual)(Visual*); +typedef int (* PFN_XWarpPointer)(Display*,Window,Window,int,int,unsigned int,unsigned int,int,int); +typedef void (* PFN_XkbFreeKeyboard)(XkbDescPtr,unsigned int,Bool); +typedef void (* PFN_XkbFreeNames)(XkbDescPtr,unsigned int,Bool); +typedef XkbDescPtr (* PFN_XkbGetMap)(Display*,unsigned int,unsigned int); +typedef Status (* PFN_XkbGetNames)(Display*,unsigned int,XkbDescPtr); +typedef Status (* PFN_XkbGetState)(Display*,unsigned int,XkbStatePtr); +typedef KeySym (* PFN_XkbKeycodeToKeysym)(Display*,KeyCode,int,int); +typedef Bool (* PFN_XkbQueryExtension)(Display*,int*,int*,int*,int*,int*); +typedef Bool (* PFN_XkbSelectEventDetails)(Display*,unsigned int,unsigned int,unsigned long,unsigned long); +typedef Bool (* PFN_XkbSetDetectableAutoRepeat)(Display*,Bool,Bool*); +typedef void (* PFN_XrmDestroyDatabase)(XrmDatabase); +typedef Bool (* PFN_XrmGetResource)(XrmDatabase,const char*,const char*,char**,XrmValue*); +typedef XrmDatabase (* PFN_XrmGetStringDatabase)(const char*); +typedef void (* PFN_XrmInitialize)(void); +typedef XrmQuark (* PFN_XrmUniqueQuark)(void); +typedef Bool (* PFN_XUnregisterIMInstantiateCallback)(Display*,void*,char*,char*,XIDProc,XPointer); +typedef int (* PFN_Xutf8LookupString)(XIC,XKeyPressedEvent*,char*,int,KeySym*,Status*); +typedef void (* PFN_Xutf8SetWMProperties)(Display*,Window,const char*,const char*,char**,int,XSizeHints*,XWMHints*,XClassHint*); +#define XAllocClassHint _glfw.x11.xlib.AllocClassHint +#define XAllocSizeHints _glfw.x11.xlib.AllocSizeHints +#define XAllocWMHints _glfw.x11.xlib.AllocWMHints +#define XChangeProperty _glfw.x11.xlib.ChangeProperty +#define XChangeWindowAttributes _glfw.x11.xlib.ChangeWindowAttributes +#define XCheckIfEvent _glfw.x11.xlib.CheckIfEvent +#define XCheckTypedWindowEvent _glfw.x11.xlib.CheckTypedWindowEvent +#define XCloseDisplay _glfw.x11.xlib.CloseDisplay +#define XCloseIM _glfw.x11.xlib.CloseIM +#define XConvertSelection _glfw.x11.xlib.ConvertSelection +#define XCreateColormap _glfw.x11.xlib.CreateColormap +#define XCreateFontCursor _glfw.x11.xlib.CreateFontCursor +#define XCreateIC _glfw.x11.xlib.CreateIC +#define XCreateRegion _glfw.x11.xlib.CreateRegion +#define XCreateWindow _glfw.x11.xlib.CreateWindow +#define XDefineCursor _glfw.x11.xlib.DefineCursor +#define XDeleteContext _glfw.x11.xlib.DeleteContext +#define XDeleteProperty _glfw.x11.xlib.DeleteProperty +#define XDestroyIC _glfw.x11.xlib.DestroyIC +#define XDestroyRegion _glfw.x11.xlib.DestroyRegion +#define XDestroyWindow _glfw.x11.xlib.DestroyWindow +#define XDisplayKeycodes _glfw.x11.xlib.DisplayKeycodes +#define XEventsQueued _glfw.x11.xlib.EventsQueued +#define XFilterEvent _glfw.x11.xlib.FilterEvent +#define XFindContext _glfw.x11.xlib.FindContext +#define XFlush _glfw.x11.xlib.Flush +#define XFree _glfw.x11.xlib.Free +#define XFreeColormap _glfw.x11.xlib.FreeColormap +#define XFreeCursor _glfw.x11.xlib.FreeCursor +#define XFreeEventData _glfw.x11.xlib.FreeEventData +#define XGetErrorText _glfw.x11.xlib.GetErrorText +#define XGetEventData _glfw.x11.xlib.GetEventData +#define XGetICValues _glfw.x11.xlib.GetICValues +#define XGetIMValues _glfw.x11.xlib.GetIMValues +#define XGetInputFocus _glfw.x11.xlib.GetInputFocus +#define XGetKeyboardMapping _glfw.x11.xlib.GetKeyboardMapping +#define XGetScreenSaver _glfw.x11.xlib.GetScreenSaver +#define XGetSelectionOwner _glfw.x11.xlib.GetSelectionOwner +#define XGetVisualInfo _glfw.x11.xlib.GetVisualInfo +#define XGetWMNormalHints _glfw.x11.xlib.GetWMNormalHints +#define XGetWindowAttributes _glfw.x11.xlib.GetWindowAttributes +#define XGetWindowProperty _glfw.x11.xlib.GetWindowProperty +#define XGrabPointer _glfw.x11.xlib.GrabPointer +#define XIconifyWindow _glfw.x11.xlib.IconifyWindow +#define XInternAtom _glfw.x11.xlib.InternAtom +#define XLookupString _glfw.x11.xlib.LookupString +#define XMapRaised _glfw.x11.xlib.MapRaised +#define XMapWindow _glfw.x11.xlib.MapWindow +#define XMoveResizeWindow _glfw.x11.xlib.MoveResizeWindow +#define XMoveWindow _glfw.x11.xlib.MoveWindow +#define XNextEvent _glfw.x11.xlib.NextEvent +#define XOpenIM _glfw.x11.xlib.OpenIM +#define XPeekEvent _glfw.x11.xlib.PeekEvent +#define XPending _glfw.x11.xlib.Pending +#define XQueryExtension _glfw.x11.xlib.QueryExtension +#define XQueryPointer _glfw.x11.xlib.QueryPointer +#define XRaiseWindow _glfw.x11.xlib.RaiseWindow +#define XRegisterIMInstantiateCallback _glfw.x11.xlib.RegisterIMInstantiateCallback +#define XResizeWindow _glfw.x11.xlib.ResizeWindow +#define XResourceManagerString _glfw.x11.xlib.ResourceManagerString +#define XSaveContext _glfw.x11.xlib.SaveContext +#define XSelectInput _glfw.x11.xlib.SelectInput +#define XSendEvent _glfw.x11.xlib.SendEvent +#define XSetClassHint _glfw.x11.xlib.SetClassHint +#define XSetErrorHandler _glfw.x11.xlib.SetErrorHandler +#define XSetICFocus _glfw.x11.xlib.SetICFocus +#define XSetIMValues _glfw.x11.xlib.SetIMValues +#define XSetInputFocus _glfw.x11.xlib.SetInputFocus +#define XSetLocaleModifiers _glfw.x11.xlib.SetLocaleModifiers +#define XSetScreenSaver _glfw.x11.xlib.SetScreenSaver +#define XSetSelectionOwner _glfw.x11.xlib.SetSelectionOwner +#define XSetWMHints _glfw.x11.xlib.SetWMHints +#define XSetWMNormalHints _glfw.x11.xlib.SetWMNormalHints +#define XSetWMProtocols _glfw.x11.xlib.SetWMProtocols +#define XSupportsLocale _glfw.x11.xlib.SupportsLocale +#define XSync _glfw.x11.xlib.Sync +#define XTranslateCoordinates _glfw.x11.xlib.TranslateCoordinates +#define XUndefineCursor _glfw.x11.xlib.UndefineCursor +#define XUngrabPointer _glfw.x11.xlib.UngrabPointer +#define XUnmapWindow _glfw.x11.xlib.UnmapWindow +#define XUnsetICFocus _glfw.x11.xlib.UnsetICFocus +#define XVisualIDFromVisual _glfw.x11.xlib.VisualIDFromVisual +#define XWarpPointer _glfw.x11.xlib.WarpPointer +#define XkbFreeKeyboard _glfw.x11.xkb.FreeKeyboard +#define XkbFreeNames _glfw.x11.xkb.FreeNames +#define XkbGetMap _glfw.x11.xkb.GetMap +#define XkbGetNames _glfw.x11.xkb.GetNames +#define XkbGetState _glfw.x11.xkb.GetState +#define XkbKeycodeToKeysym _glfw.x11.xkb.KeycodeToKeysym +#define XkbQueryExtension _glfw.x11.xkb.QueryExtension +#define XkbSelectEventDetails _glfw.x11.xkb.SelectEventDetails +#define XkbSetDetectableAutoRepeat _glfw.x11.xkb.SetDetectableAutoRepeat +#define XrmDestroyDatabase _glfw.x11.xrm.DestroyDatabase +#define XrmGetResource _glfw.x11.xrm.GetResource +#define XrmGetStringDatabase _glfw.x11.xrm.GetStringDatabase +#define XrmUniqueQuark _glfw.x11.xrm.UniqueQuark +#define XUnregisterIMInstantiateCallback _glfw.x11.xlib.UnregisterIMInstantiateCallback +#define Xutf8LookupString _glfw.x11.xlib.utf8LookupString +#define Xutf8SetWMProperties _glfw.x11.xlib.utf8SetWMProperties + typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*); @@ -85,9 +337,15 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*); typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int); typedef void (* PFN_XcursorImageDestroy)(XcursorImage*); typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*); +typedef char* (* PFN_XcursorGetTheme)(Display*); +typedef int (* PFN_XcursorGetDefaultSize)(Display*); +typedef XcursorImage* (* PFN_XcursorLibraryLoadImage)(const char*,const char*,int); #define XcursorImageCreate _glfw.x11.xcursor.ImageCreate #define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy #define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor +#define XcursorGetTheme _glfw.x11.xcursor.GetTheme +#define XcursorGetDefaultSize _glfw.x11.xcursor.GetDefaultSize +#define XcursorLibraryLoadImage _glfw.x11.xcursor.LibraryLoadImage typedef Bool (* PFN_XineramaIsActive)(Display*); typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*); @@ -123,6 +381,51 @@ typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const #define XRenderQueryVersion _glfw.x11.xrender.QueryVersion #define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat +typedef Bool (* PFN_XShapeQueryExtension)(Display*,int*,int*); +typedef Status (* PFN_XShapeQueryVersion)(Display*dpy,int*,int*); +typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); +typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); + +#define XShapeQueryExtension _glfw.x11.xshape.QueryExtension +#define XShapeQueryVersion _glfw.x11.xshape.QueryVersion +#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; @@ -149,30 +452,71 @@ 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 "glx_context.h" -#include "egl_context.h" -#include "osmesa_context.h" -#if defined(__linux__) -#include "linux_joystick.h" -#else -#include "null_joystick.h" -#endif +#include "posix_poll.h" -#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_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_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) -#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) +#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 // @@ -180,6 +524,7 @@ typedef struct _GLFWwindowX11 { Colormap colormap; Window handle; + Window parent; XIC ic; GLFWbool overrideRedirect; @@ -198,9 +543,9 @@ typedef struct _GLFWwindowX11 // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; - // The time of the last KeyPress event - Time lastKeyTime; - + // 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 @@ -221,6 +566,8 @@ 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) @@ -228,7 +575,7 @@ typedef struct _GLFWlibraryX11 // Clipboard string (while the selection is owned) char* clipboardString; // Key name string - char keyName[5]; + char keynames[GLFW_KEY_LAST + 1][5]; // X11 keycode to GLFW key LUT short int keycodes[256]; // GLFW key to X11 keycode LUT @@ -237,8 +584,11 @@ 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; + Atom NET_SUPPORTING_WM_CHECK; Atom WM_PROTOCOLS; Atom WM_STATE; Atom WM_DELETE_WINDOW; @@ -259,6 +609,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_WM_WINDOW_OPACITY; Atom NET_WM_CM_Sx; + Atom NET_WORKAREA; + Atom NET_CURRENT_DESKTOP; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; @@ -290,6 +642,104 @@ typedef struct _GLFWlibraryX11 Atom ATOM_PAIR; Atom GLFW_SELECTION; + struct { + void* handle; + GLFWbool utf8; + PFN_XAllocClassHint AllocClassHint; + PFN_XAllocSizeHints AllocSizeHints; + PFN_XAllocWMHints AllocWMHints; + PFN_XChangeProperty ChangeProperty; + PFN_XChangeWindowAttributes ChangeWindowAttributes; + PFN_XCheckIfEvent CheckIfEvent; + PFN_XCheckTypedWindowEvent CheckTypedWindowEvent; + PFN_XCloseDisplay CloseDisplay; + PFN_XCloseIM CloseIM; + PFN_XConvertSelection ConvertSelection; + PFN_XCreateColormap CreateColormap; + PFN_XCreateFontCursor CreateFontCursor; + PFN_XCreateIC CreateIC; + PFN_XCreateRegion CreateRegion; + PFN_XCreateWindow CreateWindow; + PFN_XDefineCursor DefineCursor; + PFN_XDeleteContext DeleteContext; + PFN_XDeleteProperty DeleteProperty; + PFN_XDestroyIC DestroyIC; + PFN_XDestroyRegion DestroyRegion; + PFN_XDestroyWindow DestroyWindow; + PFN_XDisplayKeycodes DisplayKeycodes; + PFN_XEventsQueued EventsQueued; + PFN_XFilterEvent FilterEvent; + PFN_XFindContext FindContext; + PFN_XFlush Flush; + PFN_XFree Free; + PFN_XFreeColormap FreeColormap; + PFN_XFreeCursor FreeCursor; + PFN_XFreeEventData FreeEventData; + PFN_XGetErrorText GetErrorText; + PFN_XGetEventData GetEventData; + PFN_XGetICValues GetICValues; + PFN_XGetIMValues GetIMValues; + PFN_XGetInputFocus GetInputFocus; + PFN_XGetKeyboardMapping GetKeyboardMapping; + PFN_XGetScreenSaver GetScreenSaver; + PFN_XGetSelectionOwner GetSelectionOwner; + PFN_XGetVisualInfo GetVisualInfo; + PFN_XGetWMNormalHints GetWMNormalHints; + PFN_XGetWindowAttributes GetWindowAttributes; + PFN_XGetWindowProperty GetWindowProperty; + PFN_XGrabPointer GrabPointer; + PFN_XIconifyWindow IconifyWindow; + PFN_XInternAtom InternAtom; + PFN_XLookupString LookupString; + PFN_XMapRaised MapRaised; + PFN_XMapWindow MapWindow; + PFN_XMoveResizeWindow MoveResizeWindow; + PFN_XMoveWindow MoveWindow; + PFN_XNextEvent NextEvent; + PFN_XOpenIM OpenIM; + PFN_XPeekEvent PeekEvent; + PFN_XPending Pending; + PFN_XQueryExtension QueryExtension; + PFN_XQueryPointer QueryPointer; + PFN_XRaiseWindow RaiseWindow; + PFN_XRegisterIMInstantiateCallback RegisterIMInstantiateCallback; + PFN_XResizeWindow ResizeWindow; + PFN_XResourceManagerString ResourceManagerString; + PFN_XSaveContext SaveContext; + PFN_XSelectInput SelectInput; + PFN_XSendEvent SendEvent; + PFN_XSetClassHint SetClassHint; + PFN_XSetErrorHandler SetErrorHandler; + PFN_XSetICFocus SetICFocus; + PFN_XSetIMValues SetIMValues; + PFN_XSetInputFocus SetInputFocus; + PFN_XSetLocaleModifiers SetLocaleModifiers; + PFN_XSetScreenSaver SetScreenSaver; + PFN_XSetSelectionOwner SetSelectionOwner; + PFN_XSetWMHints SetWMHints; + PFN_XSetWMNormalHints SetWMNormalHints; + PFN_XSetWMProtocols SetWMProtocols; + PFN_XSupportsLocale SupportsLocale; + PFN_XSync Sync; + PFN_XTranslateCoordinates TranslateCoordinates; + PFN_XUndefineCursor UndefineCursor; + PFN_XUngrabPointer UngrabPointer; + PFN_XUnmapWindow UnmapWindow; + PFN_XUnsetICFocus UnsetICFocus; + PFN_XVisualIDFromVisual VisualIDFromVisual; + PFN_XWarpPointer WarpPointer; + PFN_XUnregisterIMInstantiateCallback UnregisterIMInstantiateCallback; + PFN_Xutf8LookupString utf8LookupString; + PFN_Xutf8SetWMProperties utf8SetWMProperties; + } xlib; + + struct { + PFN_XrmDestroyDatabase DestroyDatabase; + PFN_XrmGetResource GetResource; + PFN_XrmGetStringDatabase GetStringDatabase; + PFN_XrmUniqueQuark UniqueQuark; + } xrm; + struct { GLFWbool available; void* handle; @@ -319,13 +769,23 @@ typedef struct _GLFWlibraryX11 } randr; struct { - GLFWbool available; - GLFWbool detectable; - int majorOpcode; - int eventBase; - int errorBase; - int major; - int minor; + GLFWbool available; + GLFWbool detectable; + int majorOpcode; + int eventBase; + int errorBase; + int major; + int minor; + unsigned int group; + PFN_XkbFreeKeyboard FreeKeyboard; + PFN_XkbFreeNames FreeNames; + PFN_XkbGetMap GetMap; + PFN_XkbGetNames GetNames; + PFN_XkbGetState GetState; + PFN_XkbKeycodeToKeysym KeycodeToKeysym; + PFN_XkbQueryExtension QueryExtension; + PFN_XkbSelectEventDetails SelectEventDetails; + PFN_XkbSetDetectableAutoRepeat SetDetectableAutoRepeat; } xkb; struct { @@ -347,6 +807,9 @@ typedef struct _GLFWlibraryX11 PFN_XcursorImageCreate ImageCreate; PFN_XcursorImageDestroy ImageDestroy; PFN_XcursorImageLoadCursor ImageLoadCursor; + PFN_XcursorGetTheme GetTheme; + PFN_XcursorGetDefaultSize GetDefaultSize; + PFN_XcursorLibraryLoadImage LibraryLoadImage; } xcursor; struct { @@ -399,6 +862,18 @@ typedef struct _GLFWlibraryX11 PFN_XRenderFindVisualFormat FindVisualFormat; } xrender; + struct { + GLFWbool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XShapeQueryExtension QueryExtension; + PFN_XShapeCombineRegion ShapeCombineRegion; + PFN_XShapeQueryVersion QueryVersion; + PFN_XShapeCombineMask ShapeCombineMask; + } xshape; } _GLFWlibraryX11; // X11-specific per-monitor data @@ -412,7 +887,6 @@ typedef struct _GLFWmonitorX11 // Index of corresponding Xinerama screen, // for EWMH full screen window placement int index; - } _GLFWmonitorX11; // X11-specific per-cursor data @@ -420,15 +894,89 @@ 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 _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot); +Cursor _glfwCreateNativeCursorX11(const GLFWimage* image, int xhot, int yhot); unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, @@ -441,4 +989,16 @@ void _glfwReleaseErrorHandlerX11(void); 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 fc24f28..49e60a5 100644 --- a/raylib/external/glfw/src/x11_window.c +++ b/raylib/external/glfw/src/x11_window.c @@ -1,8 +1,9 @@ //======================================================================== -// GLFW 3.3 X11 - www.glfw.org +// GLFW 3.4 X11 (modified for raylib) - www.glfw.org; www.raylib.com //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,10 +28,12 @@ #include "internal.h" +#if defined(_GLFW_X11) + #include #include -#include +#include #include #include @@ -48,52 +51,86 @@ #define Button6 6 #define Button7 7 +// Motif WM hints flags +#define MWM_HINTS_DECORATIONS 2 +#define MWM_DECOR_ALL 1 + #define _GLFW_XDND_VERSION 5 - -// Wait for data to arrive using select +// Wait for event data to arrive on the X11 display socket // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // -static GLFWbool waitForEvent(double* timeout) +static GLFWbool waitForX11Event(double* timeout) { - fd_set fds; - const int fd = ConnectionNumber(_glfw.x11.display); - int count = fd + 1; + struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN }; -#if defined(__linux__) - if (_glfw.linjs.inotify > fd) - count = _glfw.linjs.inotify + 1; + while (!XPending(_glfw.x11.display)) + { + 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; #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 (fds[i].revents & POLLIN) + return GLFW_TRUE; + } + } + + return GLFW_TRUE; +} + +// Writes a byte to the empty event pipe +// +static void writeEmptyEvent(void) +{ for (;;) { - FD_ZERO(&fds); - FD_SET(fd, &fds); -#if defined(__linux__) - if (_glfw.linjs.inotify > 0) - FD_SET(_glfw.linjs.inotify, &fds); -#endif + const char byte = 0; + const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1); + if (result == 1 || (result == -1 && errno != EINTR)) + break; + } +} - if (timeout) - { - 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; - } - else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) - return GLFW_TRUE; +// 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; } } @@ -110,7 +147,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) VisibilityNotify, &dummy)) { - if (!waitForEvent(&timeout)) + if (!waitForX11Event(&timeout)) return GLFW_FALSE; } @@ -175,29 +212,6 @@ static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer po event->xproperty.atom == notification->xselection.property; } -// Translates a GLFW standard cursor to a font cursor shape -// -static int translateCursorShape(int shape) -{ - switch (shape) - { - case GLFW_ARROW_CURSOR: - return XC_left_ptr; - case GLFW_IBEAM_CURSOR: - return XC_xterm; - case GLFW_CROSSHAIR_CURSOR: - return XC_crosshair; - case GLFW_HAND_CURSOR: - return XC_hand1; - case GLFW_HRESIZE_CURSOR: - return XC_sb_h_double_arrow; - case GLFW_VRESIZE_CURSOR: - return XC_sb_v_double_arrow; - } - - return 0; -} - // Translates an X event modifier state mask // static int translateState(int state) @@ -222,41 +236,21 @@ static int translateState(int state) // Translates an X11 key code to a GLFW key token // -static int translateKey(int scancode) +static int translateKeyX11(int scancode) { - // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + // Use the pre-filled LUT (see createKeyTablesX11() in x11_init.c) if (scancode < 0 || scancode > 255) return GLFW_KEY_UNKNOWN; return _glfw.x11.keycodes[scancode]; } -// Return the GLFW window corresponding to the specified X11 window -// -static _GLFWwindow* findWindowByHandle(Window handle) -{ - _GLFWwindow* window; - - if (XFindContext(_glfw.x11.display, - handle, - _glfw.x11.context, - (XPointer*) &window) != 0) - { - return NULL; - } - - return window; -} - // Sends an EWMH or ICCCM event to the window manager // static void sendEventToWM(_GLFWwindow* window, Atom type, long a, long b, long c, long d, long e) { - XEvent event; - memset(&event, 0, sizeof(event)); - - event.type = ClientMessage; + XEvent event = { ClientMessage }; event.xclient.window = window->x11.handle; event.xclient.format = 32; // Data is 32-bit longs event.xclient.message_type = type; @@ -278,6 +272,11 @@ 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) @@ -314,9 +313,6 @@ 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); } @@ -415,96 +411,13 @@ 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) // -#if defined(X_HAVE_UTF8_STRING) -static unsigned int decodeUTF8(const char** s) +static uint32_t decodeUTF8(const char** s) { - unsigned int ch = 0, count = 0; - static const unsigned int offsets[] = + uint32_t codepoint = 0, count = 0; + static const uint32_t offsets[] = { 0x00000000u, 0x00003080u, 0x000e2080u, 0x03c82080u, 0xfa082080u, 0x82082080u @@ -512,15 +425,14 @@ static unsigned int decodeUTF8(const char** s) do { - ch = (ch << 6) + (unsigned char) **s; + codepoint = (codepoint << 6) + (unsigned char) **s; (*s)++; count++; } while ((**s & 0xc0) == 0x80); assert(count <= 6); - return ch - offsets[count - 1]; + return codepoint - offsets[count - 1]; } -#endif /*X_HAVE_UTF8_STRING*/ // Convert the specified Latin-1 string to UTF-8 // @@ -532,29 +444,21 @@ static char* convertLatin1toUTF8(const char* source) for (sp = source; *sp; sp++) size += (*sp & 0x80) ? 2 : 1; - char* target = calloc(size, 1); + char* target = _glfw_calloc(size, 1); char* tp = target; for (sp = source; *sp; sp++) - tp += encodeUTF8(tp, *sp); + tp += _glfwEncodeUTF8(tp, *sp); return target; } -// Centers the cursor over the window client area -// -static void centerCursor(_GLFWwindow* window) -{ - int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); -} - // Updates the cursor image according to its cursor mode // static void updateCursorImage(_GLFWwindow* window) { - if (window->cursorMode == GLFW_CURSOR_NORMAL) + if (window->cursorMode == GLFW_CURSOR_NORMAL || + window->cursorMode == GLFW_CURSOR_CAPTURED) { if (window->cursor) { @@ -571,67 +475,116 @@ static void updateCursorImage(_GLFWwindow* window) } } -// Apply disabled cursor mode to a focused window +// Grabs the cursor and confines it to the window // -static void disableCursor(_GLFWwindow* window) +static void captureCursor(_GLFWwindow* window) { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - XISetMask(mask, XI_RawMotion); - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } - - _glfw.x11.disabledCursorWindow = window; - _glfwPlatformGetCursorPos(window, - &_glfw.x11.restoreCursorPosX, - &_glfw.x11.restoreCursorPosY); - updateCursorImage(window); - centerCursor(window); XGrabPointer(_glfw.x11.display, window->x11.handle, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, window->x11.handle, - _glfw.x11.hiddenCursorHandle, + 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) +{ + XIEventMask em; + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + XISetMask(mask, XI_RawMotion); + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); +} + +// Disable XI2 raw mouse motion events +// +static void disableRawMouseMotion(_GLFWwindow* window) +{ + XIEventMask em; + unsigned char mask[] = { 0 }; + + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); +} + +// Apply disabled cursor mode to a focused window +// +static void disableCursor(_GLFWwindow* window) +{ + if (window->rawMouseMotion) + enableRawMouseMotion(window); + + _glfw.x11.disabledCursorWindow = window; + _glfwGetCursorPosX11(window, + &_glfw.x11.restoreCursorPosX, + &_glfw.x11.restoreCursorPosY); + updateCursorImage(window); + _glfwCenterCursorInContentArea(window); + captureCursor(window); +} + // Exit disabled cursor mode for the specified window // static void enableCursor(_GLFWwindow* window) { - if (_glfw.x11.xi.available) - { - XIEventMask em; - unsigned char mask[] = { 0 }; - - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(_glfw.x11.display, _glfw.x11.root, &em, 1); - } + if (window->rawMouseMotion) + disableRawMouseMotion(window); _glfw.x11.disabledCursorWindow = NULL; - XUngrabPointer(_glfw.x11.display, CurrentTime); - _glfwPlatformSetCursorPos(window, - _glfw.x11.restoreCursorPosX, - _glfw.x11.restoreCursorPosY); + releaseCursor(); + _glfwSetCursorPosX11(window, + _glfw.x11.restoreCursorPosX, + _glfw.x11.restoreCursorPosY); updateCursorImage(window); } +// Clear its handle when the input context has been destroyed +// +static void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData) +{ + _GLFWwindow* window = (_GLFWwindow*) clientData; + window->x11.ic = NULL; +} + // Create the X11 window (and its colormap) // static GLFWbool createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, Visual* visual, int depth) { + int width = wndconfig->width; + int height = wndconfig->height; + + if (wndconfig->scaleToMonitor) + { + width *= _glfw.x11.contentScaleX; + 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, @@ -640,48 +593,43 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, window->x11.transparent = _glfwIsVisualTransparentX11(visual); - // Create the actual window + XSetWindowAttributes wa = { 0 }; + wa.colormap = window->x11.colormap; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + _glfwGrabErrorHandlerX11(); + + window->x11.parent = _glfw.x11.root; + window->x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + xpos, ypos, + width, height, + 0, // Border width + depth, // Color depth + InputOutput, + visual, + CWBorderPixel | CWColormap | CWEventMask, + &wa); + + _glfwReleaseErrorHandlerX11(); + + if (!window->x11.handle) { - XSetWindowAttributes wa; - const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; - - wa.colormap = window->x11.colormap; - wa.border_pixel = 0; - wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | - ExposureMask | FocusChangeMask | VisibilityChangeMask | - EnterWindowMask | LeaveWindowMask | PropertyChangeMask; - - _glfwGrabErrorHandlerX11(); - - window->x11.handle = XCreateWindow(_glfw.x11.display, - _glfw.x11.root, - 0, 0, - wndconfig->width, wndconfig->height, - 0, // Border width - depth, // Color depth - InputOutput, - visual, - wamask, - &wa); - - _glfwReleaseErrorHandlerX11(); - - if (!window->x11.handle) - { - _glfwInputErrorX11(GLFW_PLATFORM_ERROR, - "X11: Failed to create window"); - return GLFW_FALSE; - } - - XSaveContext(_glfw.x11.display, - window->x11.handle, - _glfw.x11.context, - (XPointer) window); + _glfwInputErrorX11(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); + return GLFW_FALSE; } + XSaveContext(_glfw.x11.display, + window->x11.handle, + _glfw.x11.context, + (XPointer) window); + if (!wndconfig->decorated) - _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); + _glfwSetWindowDecoratedX11(window, GLFW_FALSE); if (_glfw.x11.NET_WM_STATE && !window->monitor) { @@ -709,7 +657,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, count); + PropModeReplace, (unsigned char*) states, count); } } @@ -760,7 +708,37 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, XFree(hints); } - updateNormalHints(window, wndconfig->width, wndconfig->height); + // 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); + } // Set ICCCM WM_CLASS property { @@ -800,22 +778,12 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, PropModeReplace, (unsigned char*) &version, 1); } - _glfwPlatformSetWindowTitle(window, wndconfig->title); - if (_glfw.x11.im) - { - window->x11.ic = XCreateIC(_glfw.x11.im, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - window->x11.handle, - XNFocusWindow, - window->x11.handle, - NULL); - } + _glfwCreateInputContextX11(window); - _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); - _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); + _glfwSetWindowTitleX11(window, wndconfig->title); + _glfwGetWindowPosX11(window, &window->x11.xpos, &window->x11.ypos); + _glfwGetWindowSizeX11(window, &window->x11.width, &window->x11.height); return GLFW_TRUE; } @@ -824,7 +792,6 @@ 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]); @@ -867,14 +834,13 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) // Multiple conversions were requested Atom* targets; - unsigned long i, count; + const unsigned long count = + _glfwGetWindowPropertyX11(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); - count = _glfwGetWindowPropertyX11(request->requestor, - request->property, - _glfw.x11.ATOM_PAIR, - (unsigned char**) &targets); - - for (i = 0; i < count; i += 2) + for (unsigned long i = 0; i < count; i += 2) { int j; @@ -932,7 +898,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request) // Conversion to a data target was requested - for (i = 0; i < formatCount; i++) + for (int i = 0; i < formatCount; i++) { if (request->target == formats[i]) { @@ -956,29 +922,12 @@ 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; - XEvent reply; - memset(&reply, 0, sizeof(reply)); - + XEvent reply = { SelectionNotify }; reply.xselection.property = writeTargetToProperty(request); - reply.xselection.type = SelectionNotify; reply.xselection.display = request->display; reply.xselection.requestor = request->requestor; reply.xselection.selection = request->selection; @@ -990,7 +939,6 @@ static void handleSelectionRequest(XEvent* event) static const char* getSelectionString(Atom selection) { - size_t i; char** selectionString = NULL; const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const size_t targetCount = sizeof(targets) / sizeof(targets[0]); @@ -1008,10 +956,10 @@ static const char* getSelectionString(Atom selection) return *selectionString; } - free(*selectionString); + _glfw_free(*selectionString); *selectionString = NULL; - for (i = 0; i < targetCount; i++) + for (size_t i = 0; i < targetCount; i++) { char* data; Atom actualType; @@ -1031,7 +979,7 @@ static const char* getSelectionString(Atom selection) SelectionNotify, ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } if (notification.xselection.property == None) @@ -1067,7 +1015,7 @@ static const char* getSelectionString(Atom selection) isSelPropNewValueNotify, (XPointer) ¬ification)) { - waitForEvent(NULL); + waitForX11Event(NULL); } XFree(data); @@ -1087,20 +1035,23 @@ static const char* getSelectionString(Atom selection) if (itemCount) { size += itemCount; - string = realloc(string, size); + string = _glfw_realloc(string, size); string[size - itemCount - 1] = '\0'; strcat(string, data); } if (!itemCount) { - if (targets[i] == XA_STRING) + if (string) { - *selectionString = convertLatin1toUTF8(string); - free(string); + if (targets[i] == XA_STRING) + { + *selectionString = convertLatin1toUTF8(string); + _glfw_free(string); + } + else + *selectionString = string; } - else - *selectionString = string; break; } @@ -1131,7 +1082,7 @@ static const char* getSelectionString(Atom selection) // Make the specified window and its video mode active on its monitor // -static void acquireMonitor(_GLFWwindow* window) +static void acquireMonitorX11(_GLFWwindow* window) { if (_glfw.x11.saver.count == 0) { @@ -1158,8 +1109,8 @@ static void acquireMonitor(_GLFWwindow* window) GLFWvidmode mode; // Manually position the window over its monitor - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); - _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwGetMonitorPosX11(window->monitor, &xpos, &ypos); + _glfwGetVideoModeX11(window->monitor, &mode); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, mode.width, mode.height); @@ -1170,7 +1121,7 @@ static void acquireMonitor(_GLFWwindow* window) // Remove the window and restore the original video mode // -static void releaseMonitor(_GLFWwindow* window) +static void releaseMonitorX11(_GLFWwindow* window) { if (window->monitor->window != window) return; @@ -1195,7 +1146,6 @@ static void releaseMonitor(_GLFWwindow* window) // static void processEvent(XEvent *event) { - _GLFWwindow* window = NULL; int keycode = 0; Bool filtered = False; @@ -1203,8 +1153,7 @@ static void processEvent(XEvent *event) if (event->type == KeyPress || event->type == KeyRelease) keycode = event->xkey.keycode; - if (_glfw.x11.im) - filtered = XFilterEvent(event, None); + filtered = XFilterEvent(event, None); if (_glfw.x11.randr.available) { @@ -1216,6 +1165,20 @@ static void processEvent(XEvent *event) } } + if (_glfw.x11.xkb.available) + { + if (event->type == _glfw.x11.xkb.eventBase + XkbEventCode) + { + if (((XkbEvent*) event)->any.xkb_type == XkbStateNotify && + (((XkbEvent*) event)->state.changed & XkbGroupStateMask)) + { + _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; + } + + return; + } + } + if (event->type == GenericEvent) { if (_glfw.x11.xi.available) @@ -1223,6 +1186,7 @@ static void processEvent(XEvent *event) _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window && + window->rawMouseMotion && event->xcookie.extension == _glfw.x11.xi.majorOpcode && XGetEventData(_glfw.x11.display, &event->xcookie) && event->xcookie.evtype == XI_RawMotion) @@ -1253,19 +1217,17 @@ static void processEvent(XEvent *event) return; } - if (event->type == SelectionClear) - { - handleSelectionClear(event); - return; - } - else if (event->type == SelectionRequest) + if (event->type == SelectionRequest) { handleSelectionRequest(event); return; } - window = findWindowByHandle(event->xany.window); - if (window == NULL) + _GLFWwindow* window = NULL; + if (XFindContext(_glfw.x11.display, + event->xany.window, + _glfw.x11.context, + (XPointer*) &window) != 0) { // This is an event for a window that has already been destroyed return; @@ -1273,31 +1235,40 @@ static void processEvent(XEvent *event) switch (event->type) { + case ReparentNotify: + { + window->x11.parent = event->xreparent.parent; + return; + } + case KeyPress: { - const int key = translateKey(keycode); + const int key = translateKeyX11(keycode); const int mods = translateState(event->xkey.state); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); if (window->x11.ic) { - // HACK: Ignore duplicate key press events generated by ibus - // These have the same timestamp as the original event - // Corresponding release events are filtered out - // implicitly by the GLFW key repeat logic - if (window->x11.lastKeyTime < event->xkey.time) + // HACK: Do not report the key press events duplicated by XIM + // Duplicate key releases are filtered out implicitly by + // the GLFW key repeat logic in _glfwInputKey + // A timestamp per key is used to handle simultaneous keys + // NOTE: Always allow the first event for each key through + // (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 (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - window->x11.lastKeyTime = event->xkey.time; + window->x11.keyPressTimes[keycode] = event->xkey.time; } if (!filtered) { int count; Status status; -#if defined(X_HAVE_UTF8_STRING) char buffer[100]; char* chars = buffer; @@ -1308,7 +1279,7 @@ static void processEvent(XEvent *event) if (status == XBufferOverflow) { - chars = calloc(count + 1, 1); + chars = _glfw_calloc(count + 1, 1); count = Xutf8LookupString(window->x11.ic, &event->xkey, chars, count, @@ -1322,36 +1293,9 @@ static void processEvent(XEvent *event) while (c - chars < count) _glfwInputChar(window, decodeUTF8(&c), mods, plain); } -#else /*X_HAVE_UTF8_STRING*/ - wchar_t buffer[16]; - wchar_t* chars = buffer; - - count = XwcLookupString(window->x11.ic, - &event->xkey, - buffer, - sizeof(buffer) / sizeof(wchar_t), - NULL, - &status); - - if (status == XBufferOverflow) - { - chars = calloc(count, sizeof(wchar_t)); - count = XwcLookupString(window->x11.ic, - &event->xkey, - chars, count, - NULL, &status); - } - - if (status == XLookupChars || status == XLookupBoth) - { - int i; - for (i = 0; i < count; i++) - _glfwInputChar(window, chars[i], mods, plain); - } -#endif /*X_HAVE_UTF8_STRING*/ if (chars != buffer) - free(chars); + _glfw_free(chars); } } else @@ -1361,9 +1305,9 @@ static void processEvent(XEvent *event) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - const long character = _glfwKeySym2Unicode(keysym); - if (character != -1) - _glfwInputChar(window, character, mods, plain); + const uint32_t codepoint = _glfwKeySym2Unicode(keysym); + if (codepoint != GLFW_INVALID_CODEPOINT) + _glfwInputChar(window, codepoint, mods, plain); } return; @@ -1371,7 +1315,7 @@ static void processEvent(XEvent *event) case KeyRelease: { - const int key = translateKey(keycode); + const int key = translateKeyX11(keycode); const int mods = translateState(event->xkey.state); if (!_glfw.x11.xkb.detectable) @@ -1484,12 +1428,20 @@ static void processEvent(XEvent *event) case EnterNotify: { + // XEnterWindowEvent is XCrossingEvent + const int x = event->xcrossing.x; + const int y = event->xcrossing.y; + // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise // ignore the defined cursor for hidden cursor mode if (window->cursorMode == GLFW_CURSOR_HIDDEN) updateCursorImage(window); _glfwInputCursorEnter(window, GLFW_TRUE); + _glfwInputCursorPos(window, x, y); + + window->x11.lastCursorPosX = x; + window->x11.lastCursorPosY = y; return; } @@ -1513,7 +1465,7 @@ static void processEvent(XEvent *event) { if (_glfw.x11.disabledCursorWindow != window) return; - if (_glfw.x11.xi.available) + if (window->rawMouseMotion) return; const int dx = x - window->x11.lastCursorPosX; @@ -1537,6 +1489,9 @@ 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); @@ -1544,23 +1499,37 @@ 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; } - if (event->xconfigure.x != window->x11.xpos || - event->xconfigure.y != window->x11.ypos) - { - if (window->x11.overrideRedirect || event->xany.send_event) - { - _glfwInputWindowPos(window, - event->xconfigure.x, - event->xconfigure.y); + int xpos = event->xconfigure.x; + int ypos = event->xconfigure.y; - window->x11.xpos = event->xconfigure.x; - window->x11.ypos = event->xconfigure.y; - } + // NOTE: ConfigureNotify events from the server are in local + // coordinates, so if we are reparented we need to translate + // the position into root (screen) coordinates + if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) + { + _glfwGrabErrorHandlerX11(); + + Window dummy; + XTranslateCoordinates(_glfw.x11.display, + window->x11.parent, + _glfw.x11.root, + xpos, ypos, + &xpos, &ypos, + &dummy); + + _glfwReleaseErrorHandlerX11(); + if (_glfw.x11.errorCode == BadWindow) + return; + } + + if (xpos != window->x11.xpos || ypos != window->x11.ypos) + { + window->x11.xpos = xpos; + window->x11.ypos = ypos; + + _glfwInputWindowPos(window, xpos, ypos); } return; @@ -1606,7 +1575,7 @@ static void processEvent(XEvent *event) else if (event->xclient.message_type == _glfw.x11.XdndEnter) { // A drag operation has entered the window - unsigned long i, count; + unsigned long count; Atom* formats = NULL; const GLFWbool list = event->xclient.data.l[1] & 1; @@ -1630,7 +1599,7 @@ static void processEvent(XEvent *event) formats = (Atom*) event->xclient.data.l + 2; } - for (i = 0; i < count; i++) + for (unsigned int i = 0; i < count; i++) { if (formats[i] == _glfw.x11.text_uri_list) { @@ -1665,10 +1634,7 @@ static void processEvent(XEvent *event) } else if (_glfw.x11.xdnd.version >= 2) { - XEvent reply; - memset(&reply, 0, sizeof(reply)); - - reply.type = ClientMessage; + XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndFinished; reply.xclient.format = 32; @@ -1701,10 +1667,7 @@ static void processEvent(XEvent *event) _glfwInputCursorPos(window, xpos, ypos); - XEvent reply; - memset(&reply, 0, sizeof(reply)); - - reply.type = ClientMessage; + XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndStatus; reply.xclient.format = 32; @@ -1742,14 +1705,14 @@ static void processEvent(XEvent *event) if (result) { - int i, count; - char** paths = parseUriList(data, &count); + int count; + char** paths = _glfwParseUriList(data, &count); _glfwInputDrop(window, count, (const char**) paths); - for (i = 0; i < count; i++) - free(paths[i]); - free(paths); + for (int i = 0; i < count; i++) + _glfw_free(paths[i]); + _glfw_free(paths); } if (data) @@ -1757,10 +1720,7 @@ static void processEvent(XEvent *event) if (_glfw.x11.xdnd.version >= 2) { - XEvent reply; - memset(&reply, 0, sizeof(reply)); - - reply.type = ClientMessage; + XEvent reply = { ClientMessage }; reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.message_type = _glfw.x11.XdndFinished; reply.xclient.format = 32; @@ -1779,9 +1739,6 @@ static void processEvent(XEvent *event) case FocusIn: { - if (window->cursorMode == GLFW_CURSOR_DISABLED) - disableCursor(window); - if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) { @@ -1790,6 +1747,11 @@ static void processEvent(XEvent *event) return; } + 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); @@ -1799,9 +1761,6 @@ static void processEvent(XEvent *event) case FocusOut: { - if (window->cursorMode == GLFW_CURSOR_DISABLED) - enableCursor(window); - if (event->xfocus.mode == NotifyGrab || event->xfocus.mode == NotifyUngrab) { @@ -1810,11 +1769,16 @@ static void processEvent(XEvent *event) return; } + 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) - _glfwPlatformIconifyWindow(window); + _glfwIconifyWindowX11(window); _glfwInputWindowFocus(window, GLFW_FALSE); return; @@ -1843,9 +1807,9 @@ static void processEvent(XEvent *event) if (window->monitor) { if (iconified) - releaseMonitor(window); + releaseMonitorX11(window); else - acquireMonitor(window); + acquireMonitorX11(window); } window->x11.iconified = iconified; @@ -1854,7 +1818,7 @@ static void processEvent(XEvent *event) } else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) { - const GLFWbool maximized = _glfwPlatformWindowMaximized(window); + const GLFWbool maximized = _glfwWindowMaximizedX11(window); if (window->x11.maximized != maximized) { window->x11.maximized = maximized; @@ -1935,10 +1899,6 @@ void _glfwPushSelectionToManagerX11(void) handleSelectionRequest(&event); break; - case SelectionClear: - handleSelectionClear(&event); - break; - case SelectionNotify: { if (event.xselection.target == _glfw.x11.SAVE_TARGETS) @@ -1956,7 +1916,39 @@ void _glfwPushSelectionToManagerX11(void) } } - waitForEvent(NULL); + waitForX11Event(NULL); + } +} + +void _glfwCreateInputContextX11(_GLFWwindow* window) +{ + XIMCallback callback; + callback.callback = (XIMProc) inputContextDestroyCallback; + callback.client_data = (XPointer) window; + + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + XNDestroyCallback, + &callback, + NULL); + + if (window->x11.ic) + { + XWindowAttributes attribs; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); + + unsigned long filter = 0; + if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL) + { + XSelectInput(_glfw.x11.display, + window->x11.handle, + attribs.your_event_mask | filter); + } } } @@ -1965,12 +1957,12 @@ void _glfwPushSelectionToManagerX11(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformCreateWindow(_GLFWwindow* window, +GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - Visual* visual; + Visual* visual = NULL; int depth; if (ctxconfig->client != GLFW_NO_API) @@ -1996,8 +1988,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } } - if (ctxconfig->client == GLFW_NO_API || - ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + if (!visual) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); @@ -2023,26 +2014,44 @@ int _glfwPlatformCreateWindow(_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) { - _glfwPlatformShowWindow(window); + _glfwShowWindowX11(window); updateWindowMode(window); - acquireMonitor(window); + acquireMonitorX11(window); + + if (wndconfig->centerCursor) + _glfwCenterCursorInContentArea(window); + } + else + { + if (wndconfig->visible) + { + _glfwShowWindowX11(window); + if (wndconfig->focused) + _glfwFocusWindowX11(window); + } } XFlush(_glfw.x11.display); return GLFW_TRUE; } -void _glfwPlatformDestroyWindow(_GLFWwindow* window) +void _glfwDestroyWindowX11(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window) - _glfw.x11.disabledCursorWindow = NULL; + enableCursor(window); if (window->monitor) - releaseMonitor(window); + releaseMonitorX11(window); if (window->x11.ic) { @@ -2070,23 +2079,16 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title) { -#if defined(X_HAVE_UTF8_STRING) - Xutf8SetWMProperties(_glfw.x11.display, - window->x11.handle, - title, title, - NULL, 0, - NULL, NULL, NULL); -#else - // This may be a slightly better fallback than using XStoreName and - // XSetIconName, which always store their arguments using STRING - XmbSetWMProperties(_glfw.x11.display, - window->x11.handle, - title, title, - NULL, 0, - NULL, NULL, NULL); -#endif + if (_glfw.x11.xlib.utf8) + { + Xutf8SetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); + } XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, @@ -2101,33 +2103,38 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) XFlush(_glfw.x11.display); } -void _glfwPlatformSetWindowIcon(_GLFWwindow* window, - int count, const GLFWimage* images) +void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images) { if (count) { - int i, j, longCount = 0; + int longCount = 0; - for (i = 0; i < count; i++) + for (int i = 0; i < count; i++) longCount += 2 + images[i].width * images[i].height; - long* icon = calloc(longCount, sizeof(long)); - long* target = icon; + unsigned long* icon = _glfw_calloc(longCount, sizeof(unsigned long)); + unsigned long* target = icon; - for (i = 0; i < count; i++) + for (int i = 0; i < count; i++) { *target++ = images[i].width; *target++ = images[i].height; - for (j = 0; j < images[i].width * images[i].height; j++) + for (int j = 0; j < images[i].width * images[i].height; j++) { - *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); + *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); } } + // 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, @@ -2135,7 +2142,7 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, (unsigned char*) icon, longCount); - free(icon); + _glfw_free(icon); } else { @@ -2146,7 +2153,7 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window, XFlush(_glfw.x11.display); } -void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos) { Window dummy; int x, y; @@ -2160,11 +2167,11 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) *ypos = y; } -void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +void _glfwSetWindowPosX11(_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 (!_glfwPlatformWindowVisible(window)) + if (!_glfwWindowVisibleX11(window)) { long supplied; XSizeHints* hints = XAllocSizeHints(); @@ -2184,7 +2191,7 @@ void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) XFlush(_glfw.x11.display); } -void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) { XWindowAttributes attribs; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); @@ -2195,12 +2202,12 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) *height = attribs.height; } -void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) { if (window->monitor) { if (window->monitor->window == window) - acquireMonitor(window); + acquireMonitorX11(window); } else { @@ -2213,32 +2220,32 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) XFlush(_glfw.x11.display); } -void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, - int minwidth, int minheight, - int maxwidth, int maxheight) +void _glfwSetWindowSizeLimitsX11(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) { int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeX11(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } -void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +void _glfwSetWindowAspectRatioX11(_GLFWwindow* window, int numer, int denom) { int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeX11(window, &width, &height); updateNormalHints(window, width, height); XFlush(_glfw.x11.display); } -void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +void _glfwGetFramebufferSizeX11(_GLFWwindow* window, int* width, int* height) { - _glfwPlatformGetWindowSize(window, width, height); + _glfwGetWindowSizeX11(window, width, height); } -void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, - int* left, int* top, - int* right, int* bottom) +void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { long* extents = NULL; @@ -2248,7 +2255,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, if (_glfw.x11.NET_FRAME_EXTENTS == None) return; - if (!_glfwPlatformWindowVisible(window) && + if (!_glfwWindowVisibleX11(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { XEvent event; @@ -2269,7 +2276,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, isFrameExtentsEvent, (XPointer) window)) { - if (!waitForEvent(&timeout)) + if (!waitForX11Event(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); @@ -2297,8 +2304,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, XFree(extents); } -void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, - float* xscale, float* yscale) +void _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; @@ -2306,7 +2312,7 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, *yscale = _glfw.x11.contentScaleY; } -void _glfwPlatformIconifyWindow(_GLFWwindow* window) +void _glfwIconifyWindowX11(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2321,7 +2327,7 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwPlatformRestoreWindow(_GLFWwindow* window) +void _glfwRestoreWindowX11(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2332,12 +2338,12 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) return; } - if (_glfwPlatformWindowIconified(window)) + if (_glfwWindowIconifiedX11(window)) { XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } - else if (_glfwPlatformWindowVisible(window)) + else if (_glfwWindowVisibleX11(window)) { if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && @@ -2355,39 +2361,91 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +void _glfwMaximizeWindowX11(_GLFWwindow* window) { - if (_glfw.x11.NET_WM_STATE && - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + if (!_glfw.x11.NET_WM_STATE || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + return; + } + + if (_glfwWindowVisibleX11(window)) { sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, - 1, 0); - XFlush(_glfw.x11.display); + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); } + else + { + Atom* states = NULL; + unsigned long 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) + + Atom missing[2] = + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; + unsigned long missingCount = 2; + + for (unsigned long i = 0; i < count; i++) + { + for (unsigned long j = 0; j < missingCount; j++) + { + if (states[i] == missing[j]) + { + missing[j] = missing[missingCount - 1]; + missingCount--; + } + } + } + + if (states) + XFree(states); + + if (!missingCount) + return; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeAppend, + (unsigned char*) missing, + missingCount); + } + + XFlush(_glfw.x11.display); } -void _glfwPlatformShowWindow(_GLFWwindow* window) +void _glfwShowWindowX11(_GLFWwindow* window) { - if (_glfwPlatformWindowVisible(window)) + if (_glfwWindowVisibleX11(window)) return; XMapWindow(_glfw.x11.display, window->x11.handle); waitForVisibilityNotify(window); } -void _glfwPlatformHideWindow(_GLFWwindow* window) +void _glfwHideWindowX11(_GLFWwindow* window) { XUnmapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); } -void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) +void _glfwRequestWindowAttentionX11(_GLFWwindow* window) { + if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) + return; + sendEventToWM(window, _glfw.x11.NET_WM_STATE, _NET_WM_STATE_ADD, @@ -2395,11 +2453,11 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) 0, 1, 0); } -void _glfwPlatformFocusWindow(_GLFWwindow* window) +void _glfwFocusWindowX11(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); - else + else if (_glfwWindowVisibleX11(window)) { XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, @@ -2409,43 +2467,56 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } -void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, - _GLFWmonitor* monitor, - int xpos, int ypos, - int width, int height, - int refreshRate) +void _glfwSetWindowMonitorX11(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) { if (window->monitor == monitor) { if (monitor) { if (monitor->window == window) - acquireMonitor(window); + acquireMonitorX11(window); } else { + if (!window->resizable) + updateNormalHints(window, width, height); + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, width, height); } + XFlush(_glfw.x11.display); return; } if (window->monitor) - releaseMonitor(window); + { + _glfwSetWindowDecoratedX11(window, window->decorated); + _glfwSetWindowFloatingX11(window, window->floating); + releaseMonitorX11(window); + } _glfwInputWindowMonitor(window, monitor); updateNormalHints(window, width, height); - updateWindowMode(window); if (window->monitor) { - XMapRaised(_glfw.x11.display, window->x11.handle); - if (waitForVisibilityNotify(window)) - acquireMonitor(window); + if (!_glfwWindowVisibleX11(window)) + { + XMapRaised(_glfw.x11.display, window->x11.handle); + waitForVisibilityNotify(window); + } + + updateWindowMode(window); + acquireMonitorX11(window); } else { + updateWindowMode(window); XMoveResizeWindow(_glfw.x11.display, window->x11.handle, xpos, ypos, width, height); } @@ -2453,7 +2524,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, XFlush(_glfw.x11.display); } -int _glfwPlatformWindowFocused(_GLFWwindow* window) +GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window) { Window focused; int state; @@ -2462,30 +2533,37 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window) return window->x11.handle == focused; } -int _glfwPlatformWindowIconified(_GLFWwindow* window) +GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window) { return getWindowState(window) == IconicState; } -int _glfwPlatformWindowVisible(_GLFWwindow* window) +GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window) { XWindowAttributes wa; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); return wa.map_state == IsViewable; } -int _glfwPlatformWindowMaximized(_GLFWwindow* window) +GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window) { Atom* states; - unsigned long i; GLFWbool maximized = GLFW_FALSE; + + if (!_glfw.x11.NET_WM_STATE || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || + !_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + return maximized; + } + const unsigned long count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, (unsigned char**) &states); - for (i = 0; i < count; i++) + for (unsigned long i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) @@ -2501,7 +2579,7 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return maximized; } -int _glfwPlatformWindowHovered(_GLFWwindow* window) +GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window) { Window w = _glfw.x11.root; while (w) @@ -2510,20 +2588,26 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window) int rootX, rootY, childX, childY; unsigned int mask; - if (!XQueryPointer(_glfw.x11.display, w, - &root, &w, &rootX, &rootY, &childX, &childY, &mask)) - { - return GLFW_FALSE; - } + _glfwGrabErrorHandlerX11(); - if (w == window->x11.handle) + const Bool result = XQueryPointer(_glfw.x11.display, w, + &root, &w, &rootX, &rootY, + &childX, &childY, &mask); + + _glfwReleaseErrorHandlerX11(); + + if (_glfw.x11.errorCode == BadWindow) + w = _glfw.x11.root; + else if (!result) + return GLFW_FALSE; + else if (w == window->x11.handle) return GLFW_TRUE; } return GLFW_FALSE; } -int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) +GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window) { if (!window->x11.transparent) return GLFW_FALSE; @@ -2531,52 +2615,43 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } -void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled) { int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeX11(window, &width, &height); updateNormalHints(window, width, height); } -void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled) { - if (enabled) + struct { - XDeleteProperty(_glfw.x11.display, - window->x11.handle, - _glfw.x11.MOTIF_WM_HINTS); - } - else - { - struct - { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; - } hints; + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } hints = {0}; - hints.flags = 2; // Set decorations - hints.decorations = 0; // No decorations + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = enabled ? MWM_DECOR_ALL : 0; - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.MOTIF_WM_HINTS, - _glfw.x11.MOTIF_WM_HINTS, 32, - PropModeReplace, - (unsigned char*) &hints, - sizeof(hints) / sizeof(long)); - } + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(hints) / sizeof(long)); } -void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) +void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) return; - if (_glfwPlatformWindowVisible(window)) + if (_glfwWindowVisibleX11(window)) { - const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; sendEventToWM(window, _glfw.x11.NET_WM_STATE, action, @@ -2585,18 +2660,20 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) } else { - Atom* states; - unsigned long i, count; + Atom* states = NULL; + const unsigned long count = + _glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_STATE, + XA_ATOM, + (unsigned char**) &states); - count = _glfwGetWindowPropertyX11(window->x11.handle, - _glfw.x11.NET_WM_STATE, - XA_ATOM, - (unsigned char**) &states); - if (!states) - return; + // 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) @@ -2612,29 +2689,48 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) 1); } } - else + else if (states) { - for (i = 0; i < count; i++) + for (unsigned long i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) { 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 - 1); + break; } } - - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, count); } - XFree(states); + if (states) + XFree(states); } XFlush(_glfw.x11.display); } -float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled) +{ + if (!_glfw.x11.xshape.available) + return; + + if (enabled) + { + Region region = XCreateRegion(); + XShapeCombineRegion(_glfw.x11.display, window->x11.handle, + ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); + } + else + { + XShapeCombineMask(_glfw.x11.display, window->x11.handle, + ShapeInput, 0, 0, None, ShapeSet); + } +} + +float _glfwGetWindowOpacityX11(_GLFWwindow* window) { float opacity = 1.f; @@ -2657,7 +2753,7 @@ float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) return opacity; } -void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity) { const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); XChangeProperty(_glfw.x11.display, window->x11.handle, @@ -2665,73 +2761,78 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) PropModeReplace, (unsigned char*) &value, 1); } -void _glfwPlatformPollEvents(void) +void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled) { - _GLFWwindow* window; + if (!_glfw.x11.xi.available) + return; -#if defined(__linux__) - _glfwDetectJoystickConnectionLinux(); + if (_glfw.x11.disabledCursorWindow != window) + return; + + if (enabled) + enableRawMouseMotion(window); + else + disableRawMouseMotion(window); +} + +GLFWbool _glfwRawMouseMotionSupportedX11(void) +{ + return _glfw.x11.xi.available; +} + +void _glfwPollEventsX11(void) +{ + drainEmptyEvents(); + +#if defined(GLFW_BUILD_LINUX_JOYSTICK) + if (_glfw.joysticksInitialized) + _glfwDetectJoystickConnectionLinux(); #endif - int count = XPending(_glfw.x11.display); - while (count--) + XPending(_glfw.x11.display); + + while (QLength(_glfw.x11.display)) { XEvent event; XNextEvent(_glfw.x11.display, &event); processEvent(&event); } - window = _glfw.x11.disabledCursorWindow; + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; - _glfwPlatformGetWindowSize(window, &width, &height); + _glfwGetWindowSizeX11(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) { - _glfwPlatformSetCursorPos(window, width / 2, height / 2); + _glfwSetCursorPosX11(window, width / 2, height / 2); } } XFlush(_glfw.x11.display); } -void _glfwPlatformWaitEvents(void) +void _glfwWaitEventsX11(void) { - while (!XPending(_glfw.x11.display)) - waitForEvent(NULL); - - _glfwPlatformPollEvents(); + waitForAnyEvent(NULL); + _glfwPollEventsX11(); } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwWaitEventsTimeoutX11(double timeout) { - while (!XPending(_glfw.x11.display)) - { - if (!waitForEvent(&timeout)) - break; - } - - _glfwPlatformPollEvents(); + waitForAnyEvent(&timeout); + _glfwPollEventsX11(); } -void _glfwPlatformPostEmptyEvent(void) +void _glfwPostEmptyEventX11(void) { - XEvent event; - - memset(&event, 0, sizeof(event)); - event.type = 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); + writeEmptyEvent(); } -void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) { Window root, child; int rootX, rootY, childX, childY; @@ -2748,7 +2849,7 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) *ypos = childY; } -void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later window->x11.warpCursorPosX = (int) x; @@ -2759,91 +2860,212 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) XFlush(_glfw.x11.display); } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwSetCursorModeX11(_GLFWwindow* window, int mode) { - if (mode == GLFW_CURSOR_DISABLED) + if (_glfwWindowFocusedX11(window)) { - if (_glfwPlatformWindowFocused(window)) - disableCursor(window); - } - else if (_glfw.x11.disabledCursorWindow == window) - enableCursor(window); - else - updateCursorImage(window); + 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); + } + } + + updateCursorImage(window); XFlush(_glfw.x11.display); } -const char* _glfwPlatformGetScancodeName(int scancode) +const char* _glfwGetScancodeNameX11(int scancode) { if (!_glfw.x11.xkb.available) return NULL; - const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + if (scancode < 0 || scancode > 0xff) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", 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 long ch = _glfwKeySym2Unicode(keysym); - if (ch == -1) + const uint32_t codepoint = _glfwKeySym2Unicode(keysym); + if (codepoint == GLFW_INVALID_CODEPOINT) return NULL; - const size_t count = encodeUTF8(_glfw.x11.keyName, (unsigned int) ch); + const size_t count = _glfwEncodeUTF8(_glfw.x11.keynames[key], codepoint); if (count == 0) return NULL; - _glfw.x11.keyName[count] = '\0'; - return _glfw.x11.keyName; + _glfw.x11.keynames[key][count] = '\0'; + return _glfw.x11.keynames[key]; } -int _glfwPlatformGetKeyScancode(int key) +int _glfwGetKeyScancodeX11(int key) { return _glfw.x11.scancodes[key]; } -int _glfwPlatformCreateCursor(_GLFWcursor* cursor, +GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot) { - cursor->x11.handle = _glfwCreateCursorX11(image, xhot, yhot); + cursor->x11.handle = _glfwCreateNativeCursorX11(image, xhot, yhot); if (!cursor->x11.handle) return GLFW_FALSE; return GLFW_TRUE; } -int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) { - cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, - translateCursorShape(shape)); + if (_glfw.x11.xcursor.handle) + { + char* theme = XcursorGetTheme(_glfw.x11.display); + if (theme) + { + 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; + } + + XcursorImage* image = XcursorLibraryLoadImage(name, theme, size); + if (image) + { + cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image); + XcursorImageDestroy(image); + } + } + } + if (!cursor->x11.handle) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to create standard cursor"); - return GLFW_FALSE; + unsigned int native = 0; + + switch (shape) + { + 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; + } + + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GLFW_FALSE; + } } return GLFW_TRUE; } -void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +void _glfwDestroyCursorX11(_GLFWcursor* cursor) { if (cursor->x11.handle) XFreeCursor(_glfw.x11.display, cursor->x11.handle); } -void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor) { - if (window->cursorMode == GLFW_CURSOR_NORMAL) + if (window->cursorMode == GLFW_CURSOR_NORMAL || + window->cursorMode == GLFW_CURSOR_CAPTURED) { updateCursorImage(window); XFlush(_glfw.x11.display); } } -void _glfwPlatformSetClipboardString(const char* string) +void _glfwSetClipboardStringX11(const char* string) { - free(_glfw.x11.clipboardString); - _glfw.x11.clipboardString = _glfw_strdup(string); + char* copy = _glfw_strdup(string); + _glfw_free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = copy; XSetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD, @@ -2858,12 +3080,61 @@ void _glfwPlatformSetClipboardString(const char* string) } } -const char* _glfwPlatformGetClipboardString(void) +const char* _glfwGetClipboardStringX11(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } -void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) +EGLenum _glfwGetEGLPlatformX11(EGLint** attribs) +{ + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; + + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_vulkan) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN) + type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; + } + + if (type) + { + *attribs = _glfw_calloc(5, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE; + (*attribs)[3] = EGL_PLATFORM_X11_EXT; + (*attribs)[4] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + + if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_x11) + return EGL_PLATFORM_X11_EXT; + + return 0; +} + +EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void) +{ + return _glfw.x11.display; +} + +EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window) +{ + if (_glfw.egl.platform) + return &window->x11.handle; + else + return (EGLNativeWindowType) window->x11.handle; +} + +void _glfwGetRequiredInstanceExtensionsX11(char** extensions) { if (!_glfw.vk.KHR_surface) return; @@ -2884,7 +3155,7 @@ void _glfwPlatformGetRequiredInstanceExtensions(char** extensions) extensions[1] = "VK_KHR_xlib_surface"; } -int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, +GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily) { @@ -2937,10 +3208,10 @@ int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, } } -VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, - _GLFWwindow* window, - const VkAllocationCallbacks* allocator, - VkSurfaceKHR* surface) +VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { @@ -3020,6 +3291,13 @@ VkResult _glfwPlatformCreateWindowSurface(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; } @@ -3027,6 +3305,13 @@ 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; } @@ -3034,7 +3319,13 @@ GLFWAPI void glfwSetX11SelectionString(const char* string) { _GLFW_REQUIRE_INIT(); - free(_glfw.x11.primarySelectionString); + if (_glfw.platform.platformID != GLFW_PLATFORM_X11) + { + _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "X11: Platform not initialized"); + return; + } + + _glfw_free(_glfw.x11.primarySelectionString); _glfw.x11.primarySelectionString = _glfw_strdup(string); XSetSelectionOwner(_glfw.x11.display, @@ -3053,6 +3344,15 @@ 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 new file mode 100644 index 0000000..ceece5a --- /dev/null +++ b/raylib/external/glfw/src/xdg-activation-v1-client-protocol-code.h @@ -0,0 +1,85 @@ +/* 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 new file mode 100644 index 0000000..b26c548 --- /dev/null +++ b/raylib/external/glfw/src/xdg-activation-v1-client-protocol.h @@ -0,0 +1,415 @@ +/* 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/xdg-decoration-unstable-v1-client-protocol-code.h b/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol-code.h new file mode 100644 index 0000000..85496af --- /dev/null +++ b/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol-code.h @@ -0,0 +1,76 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2018 Simon Ser + * + * 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 xdg_toplevel_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static const struct wl_interface *xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 1, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 }, + { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 }, +}; + +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 = { + "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/xdg-decoration-unstable-v1-client-protocol.h new file mode 100644 index 0000000..217af20 --- /dev/null +++ b/raylib/external/glfw/src/xdg-decoration-unstable-v1-client-protocol.h @@ -0,0 +1,384 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol + * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager + * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface + * @section page_copyright_xdg_decoration_unstable_v1 Copyright + *
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * 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 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 + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zxdg_decoration_manager_v1_api API + * See @ref iface_zxdg_decoration_manager_v1. + */ +/** + * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * 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 + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + * @section page_iface_zxdg_toplevel_decoration_v1_api API + * See @ref iface_zxdg_toplevel_decoration_v1. + */ +/** + * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * 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 + + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void +zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data); +} + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void * +zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +static inline uint32_t +zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Destroy the decoration manager. This doesn't destroy objects created + * with the manager. + */ +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); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Create a new decoration object associated with the given toplevel. + * + * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + * buffer attached or committed is a client error, and any attempts by a + * client to attach or manipulate a buffer prior to the first + * xdg_toplevel_decoration.configure event must also be treated as + * errors. + */ +static inline struct zxdg_toplevel_decoration_v1 * +zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel) +{ + 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); + + return (struct zxdg_toplevel_decoration_v1 *) id; +} + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +enum zxdg_toplevel_decoration_v1_error { + /** + * xdg_toplevel has a buffer attached before configure + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0, + /** + * xdg_toplevel already has a decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1, + /** + * 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 */ + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * window decoration modes + * + * These values describe window decoration modes. + */ +enum zxdg_toplevel_decoration_v1_mode { + /** + * no server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + /** + * server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * @struct zxdg_toplevel_decoration_v1_listener + */ +struct zxdg_toplevel_decoration_v1_listener { + /** + * notify a decoration mode 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. + * + * A configure event can be sent at any time. The specified mode + * must be obeyed by the client. + * @param mode the decoration mode + */ + void (*configure)(void *data, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode); +}; + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +static inline int +zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0 +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1 +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void +zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data); +} + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void * +zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +static inline uint32_t +zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Switch back to a mode without any server-side decorations at the next + * commit. + */ +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); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Set the toplevel surface decoration mode. This informs the compositor + * 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 + * 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). + * + * The compositor can decide not to use the client's mode and enforce a + * 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 + * 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); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Unset the toplevel surface decoration mode. This informs the compositor + * that the client doesn't prefer a particular decoration mode. + * + * This request has the same semantics as set_mode. + */ +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); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/raylib/external/glfw/src/xdg-shell-client-protocol-code.h b/raylib/external/glfw/src/xdg-shell-client-protocol-code.h new file mode 100644 index 0000000..d698c2c --- /dev/null +++ b/raylib/external/glfw/src/xdg-shell-client-protocol-code.h @@ -0,0 +1,184 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * + * 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_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +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[] = { + NULL, + NULL, + NULL, + NULL, + &xdg_positioner_interface, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &xdg_positioner_interface, + NULL, +}; + +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 }, +}; + +static const struct wl_message xdg_wm_base_events[] = { + { "ping", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 6, + 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 }, +}; + +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 6, + 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 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_surface_interface = { + "xdg_surface", 6, + 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 }, +}; + +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 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 6, + 14, xdg_toplevel_requests, + 4, 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 }, +}; + +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 }, +}; + +WL_PRIVATE const struct wl_interface xdg_popup_interface = { + "xdg_popup", 6, + 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/xdg-shell-client-protocol.h new file mode 100644 index 0000000..1f077b4 --- /dev/null +++ b/raylib/external/glfw/src/xdg-shell-client-protocol.h @@ -0,0 +1,2325 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * 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_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +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 + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * 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 + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * 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. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * 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. + */ +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 + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * 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. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * 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. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * 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. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * 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. + */ +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 + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * 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). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * 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). + * + * 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 + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * 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 +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * 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 */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * 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. + * + * 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. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +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); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_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. + * + * 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 + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *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); + + return (struct xdg_surface *) id; +} + +/** + * @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. + */ +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); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * 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. + */ +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 */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * When set reactive, the surface is reconstrained if the conditions used + * for constraining changed, e.g. the parent window moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, followed by an + * xdg_surface.configure event. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information to + * determine the future state the popup should be constrained using. If + * this doesn't match the dimension of the parent the popup is eventually + * positioned against, the behavior is undefined. + * + * The arguments are given in the surface-local coordinate space. + */ +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); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of an 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. + */ +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); +} + +#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 */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) 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. + */ +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); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +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); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + 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); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * 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. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * 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. + * + * 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); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * 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 + * before its next surface commit. + * + * 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); +} + +#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 +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * 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. + */ +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 + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @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 + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + 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); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @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 + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +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); +} + +/** + * @ingroup iface_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 + * "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. + * + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * 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 +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * 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. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * 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. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * 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. + * + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * 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. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * 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. + * + * 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. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * with border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +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); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +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); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_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. + */ +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); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * 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. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +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); +} + +/** + * @ingroup iface_xdg_popup + * + * Reposition an already-mapped popup. The popup will be placed given the + * details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any parameters set + * by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not take + * effect until the corresponding configure event is acknowledged by the + * client. See xdg_popup.repositioned for details. The token itself is + * opaque, and has no other special meaning. + * + * If multiple reposition requests are sent, the compositor may skip all + * but the last one. + * + * 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 + * 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. + */ +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); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/raylib/external/glfw/src/xkb_unicode.c b/raylib/external/glfw/src/xkb_unicode.c index ecfdc2a..6b8dfca 100644 --- a/raylib/external/glfw/src/xkb_unicode.c +++ b/raylib/external/glfw/src/xkb_unicode.c @@ -1,8 +1,8 @@ //======================================================================== -// GLFW 3.3 X11 - www.glfw.org +// GLFW 3.4 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2016 Camilla Löwy +// 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 @@ -27,6 +27,7 @@ #include "internal.h" +#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) /* * Marcus: This code was originally written by Markus G. Kuhn. @@ -905,7 +906,7 @@ static const struct codepair { // Convert XKB KeySym to Unicode // -long _glfwKeySym2Unicode(unsigned int keysym) +uint32_t _glfwKeySym2Unicode(unsigned int keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; @@ -935,6 +936,8 @@ long _glfwKeySym2Unicode(unsigned int keysym) } // No matching Unicode value found - return -1; + return GLFW_INVALID_CODEPOINT; } +#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 f95e14f..b07408f 100644 --- a/raylib/external/glfw/src/xkb_unicode.h +++ b/raylib/external/glfw/src/xkb_unicode.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.3 Linux - www.glfw.org +// GLFW 3.4 Linux - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ådahl // @@ -24,5 +24,7 @@ // //======================================================================== -long _glfwKeySym2Unicode(unsigned int keysym); +#define GLFW_INVALID_CODEPOINT 0xffffffffu + +uint32_t _glfwKeySym2Unicode(unsigned int keysym); diff --git a/raylib/external/jar_mod.h b/raylib/external/jar_mod.h index c17130a..eacd3b7 100644 --- a/raylib/external/jar_mod.h +++ b/raylib/external/jar_mod.h @@ -81,15 +81,13 @@ #ifndef INCLUDE_JAR_MOD_H #define INCLUDE_JAR_MOD_H -#include -#include -//#include - - -#ifdef __cplusplus -extern "C" { +// Allow custom memory allocators +#ifndef JARMOD_MALLOC + #define JARMOD_MALLOC(sz) malloc(sz) +#endif +#ifndef JARMOD_FREE + #define JARMOD_FREE(p) free(p) #endif - // Basic type @@ -240,7 +238,9 @@ typedef struct jar_mod_tracker_buffer_state_ tracker_state * track_state_buf; }jar_mod_tracker_buffer_state; - +#ifdef __cplusplus +extern "C" { +#endif bool jar_mod_init(jar_mod_context_t * modctx); bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter); @@ -261,6 +261,10 @@ void jar_mod_seek_start(jar_mod_context_t * ctx); //------------------------------------------------------------------------------- #ifdef JAR_MOD_IMPLEMENTATION +#include +#include +//#include + // Effects list #define EFFECT_ARPEGGIO 0x0 // Supported #define EFFECT_PORTAMENTO_UP 0x1 // Supported @@ -1504,7 +1508,7 @@ void jar_mod_unload( jar_mod_context_t * modctx) { if(modctx->modfile) { - free(modctx->modfile); + JARMOD_FREE(modctx->modfile); modctx->modfile = 0; modctx->modfilesize = 0; modctx->loopcount = 0; @@ -1513,14 +1517,12 @@ void jar_mod_unload( jar_mod_context_t * modctx) } } - - mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename) { mulong fsize = 0; if(modctx->modfile) { - free(modctx->modfile); + JARMOD_FREE(modctx->modfile); modctx->modfile = 0; } @@ -1533,7 +1535,7 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename) if(fsize && fsize < 32*1024*1024) { - modctx->modfile = malloc(fsize); + modctx->modfile = JARMOD_MALLOC(fsize); modctx->modfilesize = fsize; memset(modctx->modfile, 0, fsize); fread(modctx->modfile, fsize, 1, f); diff --git a/raylib/external/jar_xm.h b/raylib/external/jar_xm.h index 9d4f5b5..422d82c 100644 --- a/raylib/external/jar_xm.h +++ b/raylib/external/jar_xm.h @@ -1,9 +1,26 @@ -// jar_xm.h - v0.01 - public domain - Joshua Reisenauer, MAR 2016 +// jar_xm.h +// +// ORIGINAL LICENSE - FOR LIBXM: +// +// Author: Romain "Artefact2" Dalmaso +// Contributor: Dan Spencer +// Repackaged into jar_xm.h By: Joshua Adam Reisenauer +// This program is free software. It comes without any warranty, to the +// extent permitted by applicable law. You can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To Public +// License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/wtfpl/COPYING for more details. // // HISTORY: -// -// v0.01 2016-02-22 Setup -// +// v0.1.0 2016-02-22 jar_xm.h - development by Joshua Reisenauer, MAR 2016 +// v0.2.1 2021-03-07 m4ntr0n1c: Fix clipping noise for "bad" xm's (they will always clip), avoid clip noise and just put a ceiling) +// v0.2.2 2021-03-09 m4ntr0n1c: Add complete debug solution (raylib.h must be included) +// v0.2.3 2021-03-11 m4ntr0n1c: Fix tempo, bpm and volume on song stop / start / restart / loop +// v0.2.4 2021-03-17 m4ntr0n1c: Sanitize code for readability +// v0.2.5 2021-03-22 m4ntr0n1c: Minor adjustments +// v0.2.6 2021-04-01 m4ntr0n1c: Minor fixes and optimisation +// v0.3.0 2021-04-03 m4ntr0n1c: Addition of Stereo sample support, Linear Interpolation and Ramping now addressable options in code +// v0.3.1 2021-04-04 m4ntr0n1c: Volume effects column adjustments, sample offset handling adjustments // // USAGE: // @@ -36,260 +53,170 @@ // return 0; // } // -// -// LISCENSE - FOR LIBXM: -// -// Author: Romain "Artefact2" Dalmaso -// Contributor: Dan Spencer -// Repackaged into jar_xm.h By: Joshua Adam Reisenauer -// This program is free software. It comes without any warranty, to the -// extent permitted by applicable law. You can redistribute it and/or -// modify it under the terms of the Do What The Fuck You Want To Public -// License, Version 2, as published by Sam Hocevar. See -// http://sam.zoy.org/wtfpl/COPYING for more details. - #ifndef INCLUDE_JAR_XM_H #define INCLUDE_JAR_XM_H -#define JAR_XM_DEBUG 0 -#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality -#define JAR_XM_DEFENSIVE 1 -#define JAR_XM_RAMPING 1 - -#include -#include #include -#include -#include +#define JAR_XM_DEBUG 0 +#define JAR_XM_DEFENSIVE 1 +//#define JAR_XM_RAYLIB 0 // set to 0 to disable the RayLib visualizer extension +// Allow custom memory allocators +#ifndef JARXM_MALLOC + #define JARXM_MALLOC(sz) malloc(sz) +#endif +#ifndef JARXM_FREE + #define JARXM_FREE(p) free(p) +#endif //------------------------------------------------------------------------------- +struct jar_xm_context_s; +typedef struct jar_xm_context_s jar_xm_context_t; + #ifdef __cplusplus extern "C" { #endif -struct jar_xm_context_s; -typedef struct jar_xm_context_s jar_xm_context_t; - -/** Create a XM context. - * - * @param moddata the contents of the module - * @param rate play rate in Hz, recommended value of 48000 - * - * @returns 0 on success - * @returns 1 if module data is not sane - * @returns 2 if memory allocation failed - * @returns 3 unable to open input file - * @returns 4 fseek() failed - * @returns 5 fread() failed - * @returns 6 unkown error - * - * @deprecated This function is unsafe! - * @see jar_xm_create_context_safe() - */ +//** Create a XM context. +// * @param moddata the contents of the module +// * @param rate play rate in Hz, recommended value of 48000 +// * @returns 0 on success +// * @returns 1 if module data is not sane +// * @returns 2 if memory allocation failed +// * @returns 3 unable to open input file +// * @returns 4 fseek() failed +// * @returns 5 fread() failed +// * @returns 6 unkown error +// * @deprecated This function is unsafe! +// * @see jar_xm_create_context_safe() int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const char* filename); -/** Create a XM context. - * - * @param moddata the contents of the module - * @param rate play rate in Hz, recommended value of 48000 - * - * @returns 0 on success - * @returns 1 if module data is not sane - * @returns 2 if memory allocation failed - * - * @deprecated This function is unsafe! - * @see jar_xm_create_context_safe() - */ +//** Create a XM context. +// * @param moddata the contents of the module +// * @param rate play rate in Hz, recommended value of 48000 +// * @returns 0 on success +// * @returns 1 if module data is not sane +// * @returns 2 if memory allocation failed +// * @deprecated This function is unsafe! +// * @see jar_xm_create_context_safe() int jar_xm_create_context(jar_xm_context_t** ctx, const char* moddata, uint32_t rate); -/** Create a XM context. - * - * @param moddata the contents of the module - * @param moddata_length the length of the contents of the module, in bytes - * @param rate play rate in Hz, recommended value of 48000 - * - * @returns 0 on success - * @returns 1 if module data is not sane - * @returns 2 if memory allocation failed - */ +//** Create a XM context. +// * @param moddata the contents of the module +// * @param moddata_length the length of the contents of the module, in bytes +// * @param rate play rate in Hz, recommended value of 48000 +// * @returns 0 on success +// * @returns 1 if module data is not sane +// * @returns 2 if memory allocation failed int jar_xm_create_context_safe(jar_xm_context_t** ctx, const char* moddata, size_t moddata_length, uint32_t rate); -/** Free a XM context created by jar_xm_create_context(). */ +//** Free a XM context created by jar_xm_create_context(). */ void jar_xm_free_context(jar_xm_context_t* ctx); -/** Play the module and put the sound samples in an output buffer. - * - * @param output buffer of 2*numsamples elements (A left and right value for each sample) - * @param numsamples number of samples to generate - */ +//** Play the module and put the sound samples in an output buffer. +// * @param output buffer of 2*numsamples elements (A left and right value for each sample) +// * @param numsamples number of samples to generate void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples); -/** Play the module, resample from 32 bit to 16 bit, and put the sound samples in an output buffer. - * - * @param output buffer of 2*numsamples elements (A left and right value for each sample) - * @param numsamples number of samples to generate - */ -void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples) -{ - float* musicBuffer = malloc((2*numsamples)*sizeof(float)); +//** Play the module, resample from float to 16 bit, and put the sound samples in an output buffer. +// * @param output buffer of 2*numsamples elements (A left and right value for each sample) +// * @param numsamples number of samples to generate +void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples) { + float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float)); jar_xm_generate_samples(ctx, musicBuffer, numsamples); if(output){ - int x; - for(x=0;x<2*numsamples;x++) - output[x] = musicBuffer[x] * SHRT_MAX; + for(int x=0;x<2*numsamples;x++) output[x] = (musicBuffer[x] * 32767.0f); // scale sample to signed small int } - - free(musicBuffer); + JARXM_FREE(musicBuffer); } -/** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer. - * - * @param output buffer of 2*numsamples elements (A left and right value for each sample) - * @param numsamples number of samples to generate - */ -void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples) -{ - float* musicBuffer = malloc((2*numsamples)*sizeof(float)); +//** Play the module, resample from float to 8 bit, and put the sound samples in an output buffer. +// * @param output buffer of 2*numsamples elements (A left and right value for each sample) +// * @param numsamples number of samples to generate +void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples) { + float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float)); jar_xm_generate_samples(ctx, musicBuffer, numsamples); if(output){ - int x; - for(x=0;x<2*numsamples;x++) - output[x] = musicBuffer[x] * CHAR_MAX; + for(int x=0;x<2*numsamples;x++) output[x] = (musicBuffer[x] * 127.0f); // scale sample to signed 8 bit } - - free(musicBuffer); + JARXM_FREE(musicBuffer); } - - -/** Set the maximum number of times a module can loop. After the - * specified number of loops, calls to jar_xm_generate_samples will only - * generate silence. You can control the current number of loops with - * jar_xm_get_loop_count(). - * - * @param loopcnt maximum number of loops. Use 0 to loop - * indefinitely. */ +//** Set the maximum number of times a module can loop. After the specified number of loops, calls to jar_xm_generate_samples will only generate silence. You can control the current number of loops with jar_xm_get_loop_count(). +// * @param loopcnt maximum number of loops. Use 0 to loop indefinitely. void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt); -/** Get the loop count of the currently playing module. This value is - * 0 when the module is still playing, 1 when the module has looped - * once, etc. */ +//** Get the loop count of the currently playing module. This value is 0 when the module is still playing, 1 when the module has looped once, etc. uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx); - - -/** Mute or unmute a channel. - * - * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...). - * - * @return whether the channel was muted. - */ +//** Mute or unmute a channel. +// * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...). +// * @return whether the channel was muted. bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t, bool); -/** Mute or unmute an instrument. - * - * @note Instrument numbers go from 1 to - * jar_xm_get_number_of_instruments(...). - * - * @return whether the instrument was muted. - */ +//** Mute or unmute an instrument. +// * @note Instrument numbers go from 1 to jar_xm_get_number_of_instruments(...). +// * @return whether the instrument was muted. bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t, bool); - - -/** Get the module name as a NUL-terminated string. */ +//** Get the module name as a NUL-terminated string. const char* jar_xm_get_module_name(jar_xm_context_t* ctx); -/** Get the tracker name as a NUL-terminated string. */ +//** Get the tracker name as a NUL-terminated string. const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx); - - -/** Get the number of channels. */ +//** Get the number of channels. uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx); -/** Get the module length (in patterns). */ +//** Get the module length (in patterns). uint16_t jar_xm_get_module_length(jar_xm_context_t*); -/** Get the number of patterns. */ +//** Get the number of patterns. uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx); -/** Get the number of rows of a pattern. - * - * @note Pattern numbers go from 0 to - * jar_xm_get_number_of_patterns(...)-1. - */ +//** Get the number of rows of a pattern. +// * @note Pattern numbers go from 0 to jar_xm_get_number_of_patterns(...)-1. uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t); -/** Get the number of instruments. */ +//** Get the number of instruments. uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx); -/** Get the number of samples of an instrument. - * - * @note Instrument numbers go from 1 to - * jar_xm_get_number_of_instruments(...). - */ +//** Get the number of samples of an instrument. +// * @note Instrument numbers go from 1 to jar_xm_get_number_of_instruments(...). uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t); - - -/** Get the current module speed. - * - * @param bpm will receive the current BPM - * @param tempo will receive the current tempo (ticks per line) - */ +//** Get the current module speed. +// * @param bpm will receive the current BPM +// * @param tempo will receive the current tempo (ticks per line) void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo); -/** Get the current position in the module being played. - * - * @param pattern_index if not NULL, will receive the current pattern - * index in the POT (pattern order table) - * - * @param pattern if not NULL, will receive the current pattern number - * - * @param row if not NULL, will receive the current row - * - * @param samples if not NULL, will receive the total number of - * generated samples (divide by sample rate to get seconds of - * generated audio) - */ +//** Get the current position in the module being played. +// * @param pattern_index if not NULL, will receive the current pattern index in the POT (pattern order table) +// * @param pattern if not NULL, will receive the current pattern number +// * @param row if not NULL, will receive the current row +// * @param samples if not NULL, will receive the total number of +// * generated samples (divide by sample rate to get seconds of generated audio) void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples); -/** Get the latest time (in number of generated samples) when a - * particular instrument was triggered in any channel. - * - * @note Instrument numbers go from 1 to - * jar_xm_get_number_of_instruments(...). - */ +//** Get the latest time (in number of generated samples) when a particular instrument was triggered in any channel. +// * @note Instrument numbers go from 1 to jar_xm_get_number_of_instruments(...). uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t); -/** Get the latest time (in number of generated samples) when a - * particular sample was triggered in any channel. - * - * @note Instrument numbers go from 1 to - * jar_xm_get_number_of_instruments(...). - * - * @note Sample numbers go from 0 to - * jar_xm_get_nubmer_of_samples(...,instr)-1. - */ +//** Get the latest time (in number of generated samples) when a particular sample was triggered in any channel. +// * @note Instrument numbers go from 1 to jar_xm_get_number_of_instruments(...). +// * @note Sample numbers go from 0 to jar_xm_get_nubmer_of_samples(...,instr)-1. uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample); -/** Get the latest time (in number of generated samples) when any - * instrument was triggered in a given channel. - * - * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...). - */ +//** Get the latest time (in number of generated samples) when any instrument was triggered in a given channel. +// * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...). uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t); -/** Get the number of remaining samples. Divide by 2 to get the number of individual LR data samples. - * - * @note This is the remaining number of samples before the loop starts module again, or halts if on last pass. - * @note This function is very slow and should only be run once, if at all. - */ +//** Get the number of remaining samples. Divide by 2 to get the number of individual LR data samples. +// * @note This is the remaining number of samples before the loop starts module again, or halts if on last pass. +// * @note This function is very slow and should only be run once, if at all. uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx); #ifdef __cplusplus @@ -297,15 +224,12 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx); #endif //------------------------------------------------------------------------------- - - - - - -//Function Definitions----------------------------------------------------------- #ifdef JAR_XM_IMPLEMENTATION #include +#include +#include +#include #include #if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0 @@ -325,19 +249,16 @@ extern int __fail[-1]; #endif /* ----- XM constants ----- */ - #define SAMPLE_NAME_LENGTH 22 #define INSTRUMENT_NAME_LENGTH 22 #define MODULE_NAME_LENGTH 20 #define TRACKER_NAME_LENGTH 20 #define PATTERN_ORDER_TABLE_LENGTH 256 -#define NUM_NOTES 96 -#define NUM_ENVELOPE_POINTS 12 +#define NUM_NOTES 96 // from 1 to 96, where 1 = C-0 +#define NUM_ENVELOPE_POINTS 12 // to be verified if 12 is the max #define MAX_NUM_ROWS 256 -#if JAR_XM_RAMPING -#define jar_xm_SAMPLE_RAMPING_POINTS 0x20 -#endif +#define jar_xm_SAMPLE_RAMPING_POINTS 8 /* ----- Data types ----- */ @@ -384,7 +305,7 @@ typedef struct jar_xm_envelope_s jar_xm_envelope_t; struct jar_xm_sample_s { char name[SAMPLE_NAME_LENGTH + 1]; int8_t bits; /* Either 8 or 16 */ - + int8_t stereo; uint32_t length; uint32_t loop_start; uint32_t loop_length; @@ -441,12 +362,13 @@ struct jar_xm_sample_s { uint16_t num_channels; uint16_t num_patterns; uint16_t num_instruments; + uint16_t linear_interpolation; + uint16_t ramping; jar_xm_frequency_type_t frequency_type; uint8_t pattern_table[PATTERN_ORDER_TABLE_LENGTH]; jar_xm_pattern_t* patterns; - jar_xm_instrument_t* instruments; /* Instrument 1 has index 0, - * instrument 2 has index 1, etc. */ + jar_xm_instrument_t* instruments; /* Instrument 1 has index 0, instrument 2 has index 1, etc. */ }; typedef struct jar_xm_module_s jar_xm_module_t; @@ -512,15 +434,15 @@ struct jar_xm_sample_s { uint64_t latest_trigger; bool muted; -#if JAR_XM_RAMPING - /* These values are updated at the end of each tick, to save - * a couple of float operations on every generated sample. */ + //* These values are updated at the end of each tick, to save a couple of float operations on every generated sample. float target_panning; float target_volume; unsigned long frame_count; - float end_of_previous_sample[jar_xm_SAMPLE_RAMPING_POINTS]; -#endif + float end_of_previous_sample_left[jar_xm_SAMPLE_RAMPING_POINTS]; + float end_of_previous_sample_right[jar_xm_SAMPLE_RAMPING_POINTS]; + float curr_left; + float curr_right; float actual_panning; float actual_volume; @@ -532,18 +454,16 @@ struct jar_xm_sample_s { jar_xm_module_t module; uint32_t rate; - uint16_t tempo; + 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; - float amplification; -#if JAR_XM_RAMPING - /* How much is a channel final volume allowed to change per - * sample; this is used to avoid abrubt volume changes which - * manifest as "clicks" in the generated sound. */ - float volume_ramp; + float volume_ramp; /* How much is a channel final volume allowed to change per sample; this is used to avoid abrubt volume changes which manifest as "clicks" in the generated sound. */ float panning_ramp; /* Same for panning. */ -#endif uint8_t current_table_index; uint8_t current_row; @@ -556,9 +476,7 @@ struct jar_xm_sample_s { uint8_t jump_dest; uint8_t jump_row; - /* Extra ticks to be played before going to the next row - - * Used for EEy effect */ - uint16_t extra_ticks; + uint16_t extra_ticks; /* Extra ticks to be played before going to the next row - Used for EEy effect */ uint8_t* row_loop_count; /* Array of size MAX_NUM_ROWS * module_length */ uint8_t loop_count; @@ -567,51 +485,43 @@ struct jar_xm_sample_s { jar_xm_channel_context_t* channels; }; -/* ----- Internal API ----- */ - #if JAR_XM_DEFENSIVE -/** Check the module data for errors/inconsistencies. - * - * @returns 0 if everything looks OK. Module should be safe to load. - */ +//** Check the module data for errors/inconsistencies. +// * @returns 0 if everything looks OK. Module should be safe to load. int jar_xm_check_sanity_preload(const char*, size_t); -/** Check a loaded module for errors/inconsistencies. - * - * @returns 0 if everything looks OK. - */ +//** Check a loaded module for errors/inconsistencies. +// * @returns 0 if everything looks OK. int jar_xm_check_sanity_postload(jar_xm_context_t*); #endif -/** Get the number of bytes needed to store the module data in a - * dynamically allocated blank context. - * - * Things that are dynamically allocated: - * - sample data - * - sample structures in instruments - * - pattern data - * - row loop count arrays - * - pattern structures in module - * - instrument structures in module - * - channel contexts - * - context structure itself - - * @returns 0 if everything looks OK. - */ +//** Get the number of bytes needed to store the module data in a dynamically allocated blank context. +// * Things that are dynamically allocated: +// * - sample data +// * - sample structures in instruments +// * - pattern data +// * - row loop count arrays +// * - pattern structures in module +// * - instrument structures in module +// * - channel contexts +// * - context structure itself +// * @returns 0 if everything looks OK. size_t jar_xm_get_memory_needed_for_context(const char*, size_t); -/** Populate the context from module data. - * - * @returns pointer to the memory pool - */ +//** Populate the context from module data. +// * @returns pointer to the memory pool char* jar_xm_load_module(jar_xm_context_t*, const char*, size_t, char*); int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t rate) { 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) { @@ -630,10 +540,9 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz #endif bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length); - mempool = malloc(bytes_needed); - if(mempool == NULL && bytes_needed > 0) { - /* malloc() failed, trouble ahead */ - DEBUG("call to malloc() failed, returned %p", (void*)mempool); + mempool = JARXM_MALLOC(bytes_needed); + if(mempool == NULL && bytes_needed > 0) { /* JARXM_MALLOC() failed, trouble ahead */ + DEBUG("call to JARXM_MALLOC() failed, returned %p", (void*)mempool); return 2; } @@ -641,7 +550,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz memset(mempool, 0, bytes_needed); ctx = (*ctxp = (jar_xm_context_t *)mempool); - ctx->allocated_memory = mempool; /* Keep original pointer for free() */ + ctx->allocated_memory = mempool; /* Keep original pointer for JARXM_FREE() */ mempool += sizeof(jar_xm_context_t); ctx->rate = rate; @@ -652,23 +561,19 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t); mempool = ALIGN_PTR(mempool, 16); - ctx->global_volume = 1.f; - ctx->amplification = .25f; /* XXX: some bad modules may still clip. Find out something better. */ + ctx->default_global_volume = 1.f; + ctx->global_volume = ctx->default_global_volume; -#if JAR_XM_RAMPING ctx->volume_ramp = (1.f / 128.f); ctx->panning_ramp = (1.f / 128.f); -#endif for(uint8_t i = 0; i < ctx->module.num_channels; ++i) { - jar_xm_channel_context_t* ch = ctx->channels + i; - + jar_xm_channel_context_t *ch = ctx->channels + i; ch->ping = true; ch->vibrato_waveform = jar_xm_SINE_WAVEFORM; ch->vibrato_waveform_retrigger = true; ch->tremolo_waveform = jar_xm_SINE_WAVEFORM; ch->tremolo_waveform_retrigger = true; - ch->volume = ch->volume_envelope_volume = ch->fadeout_volume = 1.0f; ch->panning = ch->panning_envelope_panning = .5f; ch->actual_volume = .0f; @@ -676,12 +581,11 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz } mempool = ALIGN_PTR(mempool, 16); - ctx->row_loop_count = (uint8_t*)mempool; + ctx->row_loop_count = (uint8_t *)mempool; mempool += MAX_NUM_ROWS * sizeof(uint8_t); #if JAR_XM_DEFENSIVE - if((ret = jar_xm_check_sanity_postload(ctx))) { - DEBUG("jar_xm_check_sanity_postload() returned %i, module is not safe to play", ret); + if((ret = jar_xm_check_sanity_postload(ctx))) { DEBUG("jar_xm_check_sanity_postload() returned %i, module is not safe to play", ret); jar_xm_free_context(ctx); return 1; } @@ -690,106 +594,98 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz return 0; } -void jar_xm_free_context(jar_xm_context_t* ctx) { - free(ctx->allocated_memory); +void jar_xm_free_context(jar_xm_context_t *ctx) { + if (ctx != NULL) { JARXM_FREE(ctx->allocated_memory); } } -void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) { +void jar_xm_set_max_loop_count(jar_xm_context_t *ctx, uint8_t loopcnt) { ctx->max_loop_count = loopcnt; } -uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx) { +uint8_t jar_xm_get_loop_count(jar_xm_context_t *ctx) { return ctx->loop_count; } -bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t channel, bool mute) { +bool jar_xm_mute_channel(jar_xm_context_t *ctx, uint16_t channel, bool mute) { bool old = ctx->channels[channel - 1].muted; ctx->channels[channel - 1].muted = mute; return old; } -bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t instr, bool mute) { +bool jar_xm_mute_instrument(jar_xm_context_t *ctx, uint16_t instr, bool mute) { bool old = ctx->module.instruments[instr - 1].muted; ctx->module.instruments[instr - 1].muted = mute; return old; } - - -const char* jar_xm_get_module_name(jar_xm_context_t* ctx) { +const char* jar_xm_get_module_name(jar_xm_context_t *ctx) { return ctx->module.name; } -const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx) { +const char* jar_xm_get_tracker_name(jar_xm_context_t *ctx) { return ctx->module.trackername; } - - -uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx) { +uint16_t jar_xm_get_number_of_channels(jar_xm_context_t *ctx) { return ctx->module.num_channels; } -uint16_t jar_xm_get_module_length(jar_xm_context_t* ctx) { +uint16_t jar_xm_get_module_length(jar_xm_context_t *ctx) { return ctx->module.length; } -uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx) { +uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t *ctx) { return ctx->module.num_patterns; } -uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t pattern) { +uint16_t jar_xm_get_number_of_rows(jar_xm_context_t *ctx, uint16_t pattern) { return ctx->module.patterns[pattern].num_rows; } -uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx) { +uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t *ctx) { return ctx->module.num_instruments; } -uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t instrument) { +uint16_t jar_xm_get_number_of_samples(jar_xm_context_t *ctx, uint16_t instrument) { return ctx->module.instruments[instrument - 1].num_samples; } - - -void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo) { +void jar_xm_get_playing_speed(jar_xm_context_t *ctx, uint16_t *bpm, uint16_t *tempo) { if(bpm) *bpm = ctx->bpm; if(tempo) *tempo = ctx->tempo; } -void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples) { +void jar_xm_get_position(jar_xm_context_t *ctx, uint8_t *pattern_index, uint8_t *pattern, uint8_t *row, uint64_t *samples) { if(pattern_index) *pattern_index = ctx->current_table_index; if(pattern) *pattern = ctx->module.pattern_table[ctx->current_table_index]; if(row) *row = ctx->current_row; if(samples) *samples = ctx->generated_samples; } -uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t instr) { +uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t *ctx, uint16_t instr) { return ctx->module.instruments[instr - 1].latest_trigger; } -uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample) { +uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t *ctx, uint16_t instr, uint16_t sample) { return ctx->module.instruments[instr - 1].samples[sample].latest_trigger; } -uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t chn) { +uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t *ctx, uint16_t chn) { return ctx->channels[chn - 1].latest_trigger; } -/* .xm files are little-endian. (XXX: Are they really?) */ +//* .xm files are little-endian. (XXX: Are they really?) -/* Bounded reader macros. - * If we attempt to read the buffer out-of-bounds, pretend that the buffer is - * infinitely padded with zeroes. - */ +//* Bound reader macros. +//* If we attempt to read the buffer out-of-bounds, pretend that the buffer is infinitely padded with zeroes. #define READ_U8(offset) (((offset) < moddata_length) ? (*(uint8_t*)(moddata + (offset))) : 0) #define READ_U16(offset) ((uint16_t)READ_U8(offset) | ((uint16_t)READ_U8((offset) + 1) << 8)) #define READ_U32(offset) ((uint32_t)READ_U16(offset) | ((uint32_t)READ_U16((offset) + 2) << 16)) #define READ_MEMCPY(ptr, offset, length) memcpy_pad(ptr, length, moddata, moddata_length, offset) -static void memcpy_pad(void* dst, size_t dst_len, const void* src, size_t src_len, size_t offset) { - uint8_t* dst_c = dst; - const uint8_t* src_c = src; +static void memcpy_pad(void *dst, size_t dst_len, const void *src, size_t src_len, size_t offset) { + uint8_t *dst_c = dst; + const uint8_t *src_c = src; /* how many bytes can be copied without overrunning `src` */ size_t copy_bytes = (src_len >= offset) ? (src_len - offset) : 0; @@ -803,40 +699,22 @@ static void memcpy_pad(void* dst, size_t dst_len, const void* src, size_t src_le #if JAR_XM_DEFENSIVE int jar_xm_check_sanity_preload(const char* module, size_t module_length) { - if(module_length < 60) { - return 4; - } - - if(memcmp("Extended Module: ", module, 17) != 0) { - return 1; - } - - if(module[37] != 0x1A) { - return 2; - } - - if(module[59] != 0x01 || module[58] != 0x04) { - /* Not XM 1.04 */ - return 3; - } - + if(module_length < 60) { return 4; } + if(memcmp("Extended Module: ", module, 17) != 0) { return 1; } + if(module[37] != 0x1A) { return 2; } + if(module[59] != 0x01 || module[58] != 0x04) { return 3; } /* Not XM 1.04 */ return 0; } int jar_xm_check_sanity_postload(jar_xm_context_t* ctx) { - /* @todo: plenty of stuff to do here… */ - /* Check the POT */ for(uint8_t i = 0; i < ctx->module.length; ++i) { if(ctx->module.pattern_table[i] >= ctx->module.num_patterns) { if(i+1 == ctx->module.length && ctx->module.length > 1) { - /* Cheap fix */ - --ctx->module.length; DEBUG("trimming invalid POT at pos %X", i); + --ctx->module.length; } else { - DEBUG("module has invalid POT, pos %X references nonexistent pattern %X", - i, - ctx->module.pattern_table[i]); + DEBUG("module has invalid POT, pos %X references nonexistent pattern %X", i, ctx->module.pattern_table[i]); return 1; } } @@ -849,36 +727,29 @@ int jar_xm_check_sanity_postload(jar_xm_context_t* ctx) { size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_length) { size_t memory_needed = 0; - size_t offset = 60; /* Skip the first header */ + size_t offset = 60; /* 60 = Skip the first header */ uint16_t num_channels; uint16_t num_patterns; uint16_t num_instruments; /* Read the module header */ num_channels = READ_U16(offset + 8); - num_patterns = READ_U16(offset + 10); memory_needed += num_patterns * sizeof(jar_xm_pattern_t); memory_needed = ALIGN(memory_needed, 16); - num_instruments = READ_U16(offset + 12); memory_needed += num_instruments * sizeof(jar_xm_instrument_t); memory_needed = ALIGN(memory_needed, 16); - memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * sizeof(uint8_t); /* Module length */ - /* Header size */ - offset += READ_U32(offset); + offset += READ_U32(offset); /* Header size */ /* Read pattern headers */ for(uint16_t i = 0; i < num_patterns; ++i) { uint16_t num_rows; - num_rows = READ_U16(offset + 5); memory_needed += num_rows * num_channels * sizeof(jar_xm_pattern_slot_t); - - /* Pattern header length + packed pattern data size */ - offset += READ_U32(offset) + READ_U16(offset + 7); + offset += READ_U32(offset) + READ_U16(offset + 7); /* Pattern header length + packed pattern data size */ } memory_needed = ALIGN(memory_needed, 16); @@ -887,42 +758,30 @@ size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_ uint16_t num_samples; uint32_t sample_header_size = 0; uint32_t sample_size_aggregate = 0; - num_samples = READ_U16(offset + 27); memory_needed += num_samples * sizeof(jar_xm_sample_t); + if(num_samples > 0) { sample_header_size = READ_U32(offset + 29); } - if(num_samples > 0) { - sample_header_size = READ_U32(offset + 29); - } - - /* Instrument header size */ - offset += READ_U32(offset); - + offset += READ_U32(offset); /* Instrument header size */ for(uint16_t j = 0; j < num_samples; ++j) { uint32_t sample_size; uint8_t flags; - sample_size = READ_U32(offset); flags = READ_U8(offset + 14); sample_size_aggregate += sample_size; - if(flags & (1 << 4)) { - /* 16 bit sample */ + if(flags & (1 << 4)) { /* 16 bit sample */ memory_needed += sample_size * (sizeof(float) >> 1); - } else { - /* 8 bit sample */ + } else { /* 8 bit sample */ memory_needed += sample_size * sizeof(float); } - offset += sample_header_size; } - offset += sample_size_aggregate; } memory_needed += num_channels * sizeof(jar_xm_channel_context_t); memory_needed += sizeof(jar_xm_context_t); - return memory_needed; } @@ -937,26 +796,25 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd /* Read module header */ uint32_t header_size = READ_U32(offset); - mod->length = READ_U16(offset + 4); mod->restart_position = READ_U16(offset + 6); mod->num_channels = READ_U16(offset + 8); 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->ramping = 1; // ramping can be set after loading mempool += mod->num_patterns * sizeof(jar_xm_pattern_t); mempool = ALIGN_PTR(mempool, 16); - mod->instruments = (jar_xm_instrument_t*)mempool; mempool += mod->num_instruments * sizeof(jar_xm_instrument_t); mempool = ALIGN_PTR(mempool, 16); - uint16_t flags = READ_U32(offset + 14); mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES; - - ctx->tempo = READ_U16(offset + 16); - ctx->bpm = READ_U16(offset + 18); + ctx->default_tempo = READ_U16(offset + 16); + ctx->default_bpm = READ_U16(offset + 18); + ctx->tempo =ctx->default_tempo; + ctx->bpm = ctx->default_bpm; READ_MEMCPY(mod->pattern_table, offset + 20, PATTERN_ORDER_TABLE_LENGTH); offset += header_size; @@ -965,69 +823,52 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd for(uint16_t i = 0; i < mod->num_patterns; ++i) { uint16_t packed_patterndata_size = READ_U16(offset + 7); jar_xm_pattern_t* pat = mod->patterns + i; - pat->num_rows = READ_U16(offset + 5); - 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 */ - /* Pattern header length */ - offset += READ_U32(offset); - - if(packed_patterndata_size == 0) { - /* No pattern data is present */ + 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 { /* This isn't your typical for loop */ for(uint16_t j = 0, k = 0; j < packed_patterndata_size; ++k) { uint8_t note = READ_U8(offset + j); jar_xm_pattern_slot_t* slot = pat->slots + k; - if(note & (1 << 7)) { /* MSB is set, this is a compressed packet */ ++j; - - if(note & (1 << 0)) { - /* Note follows */ + if(note & (1 << 0)) { /* Note follows */ slot->note = READ_U8(offset + j); ++j; } else { slot->note = 0; } - - if(note & (1 << 1)) { - /* Instrument follows */ + if(note & (1 << 1)) { /* Instrument follows */ slot->instrument = READ_U8(offset + j); ++j; } else { slot->instrument = 0; } - - if(note & (1 << 2)) { - /* Volume column follows */ + if(note & (1 << 2)) { /* Volume column follows */ slot->volume_column = READ_U8(offset + j); ++j; } else { slot->volume_column = 0; } - - if(note & (1 << 3)) { - /* Effect follows */ + if(note & (1 << 3)) { /* Effect follows */ slot->effect_type = READ_U8(offset + j); ++j; } else { slot->effect_type = 0; } - - if(note & (1 << 4)) { - /* Effect parameter follows */ + if(note & (1 << 4)) { /* Effect parameter follows */ slot->effect_param = READ_U8(offset + j); ++j; } else { slot->effect_param = 0; } - } else { - /* Uncompressed packet */ + } else { /* Uncompressed packet */ slot->note = note; slot->instrument = READ_U8(offset + j + 1); slot->volume_column = READ_U8(offset + j + 2); @@ -1071,7 +912,6 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd instr->volume_envelope.sustain_point = READ_U8(offset + 227); instr->volume_envelope.loop_start_point = READ_U8(offset + 228); instr->volume_envelope.loop_end_point = READ_U8(offset + 229); - instr->panning_envelope.sustain_point = READ_U8(offset + 230); instr->panning_envelope.loop_start_point = READ_U8(offset + 231); instr->panning_envelope.loop_end_point = READ_U8(offset + 232); @@ -1085,7 +925,6 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd instr->panning_envelope.enabled = flags & (1 << 0); instr->panning_envelope.sustain_enabled = flags & (1 << 1); instr->panning_envelope.loop_enabled = flags & (1 << 2); - instr->vibrato_type = READ_U8(offset + 235); if(instr->vibrato_type == 2) { instr->vibrato_type = 1; @@ -1096,7 +935,6 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd instr->vibrato_depth = READ_U8(offset + 237); instr->vibrato_rate = READ_U8(offset + 238); instr->volume_fadeout = READ_U16(offset + 239); - instr->samples = (jar_xm_sample_t*)mempool; mempool += instr->num_samples * sizeof(jar_xm_sample_t); } else { @@ -1106,7 +944,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd /* Instrument header size */ offset += READ_U32(offset); - for(uint16_t j = 0; j < instr->num_samples; ++j) { + for(int j = 0; j < instr->num_samples; ++j) { /* Read sample header */ jar_xm_sample_t* sample = instr->samples + j; @@ -1114,25 +952,28 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd sample->loop_start = READ_U32(offset + 4); sample->loop_length = READ_U32(offset + 8); sample->loop_end = sample->loop_start + sample->loop_length; - sample->volume = (float)READ_U8(offset + 12) / (float)0x40; + sample->volume = (float)(READ_U8(offset + 12) << 2) / 256.f; + if (sample->volume > 1.0f) {sample->volume = 1.f;}; sample->finetune = (int8_t)READ_U8(offset + 13); uint8_t flags = READ_U8(offset + 14); - if((flags & 3) == 0) { - sample->loop_type = jar_xm_NO_LOOP; - } else if((flags & 3) == 1) { - sample->loop_type = jar_xm_FORWARD_LOOP; - } else { + switch (flags & 3) { + case 2: + case 3: sample->loop_type = jar_xm_PING_PONG_LOOP; - } - - sample->bits = (flags & (1 << 4)) ? 16 : 8; - - sample->panning = (float)READ_U8(offset + 15) / (float)0xFF; + case 1: + sample->loop_type = jar_xm_FORWARD_LOOP; + break; + default: + sample->loop_type = jar_xm_NO_LOOP; + break; + }; + sample->bits = (flags & 0x10) ? 16 : 8; + sample->stereo = (flags & 0x20) ? 1 : 0; + sample->panning = (float)READ_U8(offset + 15) / 255.f; sample->relative_note = (int8_t)READ_U8(offset + 16); READ_MEMCPY(sample->name, 18, SAMPLE_NAME_LENGTH); sample->data = (float*)mempool; - if(sample->bits == 16) { /* 16 bit sample */ mempool += sample->length * (sizeof(float) >> 1); @@ -1144,42 +985,72 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd /* 8 bit sample */ mempool += sample->length * sizeof(float); } + // Adjust loop points to reflect half of the reported length (stereo) + if (sample->stereo && sample->loop_type != jar_xm_NO_LOOP) { + div_t lstart = div(READ_U32(offset + 4), 2); + sample->loop_start = lstart.quot; + div_t llength = div(READ_U32(offset + 8), 2); + sample->loop_length = llength.quot; + sample->loop_end = sample->loop_start + sample->loop_length; + }; offset += sample_header_size; } - for(uint16_t j = 0; j < instr->num_samples; ++j) { + // Read all samples and convert them to float values + for(int j = 0; j < instr->num_samples; ++j) { /* Read sample data */ jar_xm_sample_t* sample = instr->samples + j; - uint32_t length = sample->length; - - if(sample->bits == 16) { - int16_t v = 0; - for(uint32_t k = 0; k < length; ++k) { - v = v + (int16_t)READ_U16(offset + (k << 1)); - sample->data[k] = (float)v / (float)(1 << 15); - } - offset += sample->length << 1; + int length = sample->length; + if (sample->stereo) { + // Since it is stereo, we cut the sample in half (treated as single channel) + div_t result = div(sample->length, 2); + if(sample->bits == 16) { + int16_t v = 0; + for(int k = 0; k < length; ++k) { + if (k == result.quot) { v = 0;}; + v = v + (int16_t)READ_U16(offset + (k << 1)); + sample->data[k] = (float) v / 32768.f ;//* sign; + if(sample->data[k] < -1.0) {sample->data[k] = -1.0;} else if(sample->data[k] > 1.0) {sample->data[k] = 1.0;}; + } + offset += sample->length << 1; + } else { + int8_t v = 0; + for(int k = 0; k < length; ++k) { + if (k == result.quot) { v = 0;}; + v = v + (int8_t)READ_U8(offset + k); + sample->data[k] = (float)v / 128.f ;//* sign; + if(sample->data[k] < -1.0) {sample->data[k] = -1.0;} else if(sample->data[k] > 1.0) {sample->data[k] = 1.0;}; + } + offset += sample->length; + }; + sample->length = result.quot; } else { - int8_t v = 0; - for(uint32_t k = 0; k < length; ++k) { - v = v + (int8_t)READ_U8(offset + k); - sample->data[k] = (float)v / (float)(1 << 7); + if(sample->bits == 16) { + int16_t v = 0; + for(int k = 0; k < length; ++k) { + v = v + (int16_t)READ_U16(offset + (k << 1)); + sample->data[k] = (float) v / 32768.f ;//* sign; + if(sample->data[k] < -1.0) {sample->data[k] = -1.0;} else if(sample->data[k] > 1.0) {sample->data[k] = 1.0;}; + } + offset += sample->length << 1; + } else { + int8_t v = 0; + for(int k = 0; k < length; ++k) { + v = v + (int8_t)READ_U8(offset + k); + sample->data[k] = (float)v / 128.f ;//* sign; + if(sample->data[k] < -1.0) {sample->data[k] = -1.0;} else if(sample->data[k] > 1.0) {sample->data[k] = 1.0;}; + } + offset += sample->length; } - offset += sample->length; } - } - } - + }; + }; return mempool; -} +}; //------------------------------------------------------------------------------- //THE FOLLOWING IS FOR PLAYING -//------------------------------------------------------------------------------- - -/* ----- Static functions ----- */ - static float jar_xm_waveform(jar_xm_waveform_type_t, uint8_t); static void jar_xm_autovibrato(jar_xm_context_t*, jar_xm_channel_context_t*); static void jar_xm_vibrato(jar_xm_context_t*, jar_xm_channel_context_t*, uint8_t, uint16_t); @@ -1211,35 +1082,21 @@ static void jar_xm_post_pattern_change(jar_xm_context_t*); static void jar_xm_row(jar_xm_context_t*); static void jar_xm_tick(jar_xm_context_t*); -static float jar_xm_next_of_sample(jar_xm_channel_context_t*); -static void jar_xm_sample(jar_xm_context_t*, float*, float*); - -/* ----- Other oddities ----- */ +static void jar_xm_next_of_sample(jar_xm_context_t*, jar_xm_channel_context_t*, int); +static void jar_xm_mixdown(jar_xm_context_t*, float*, float*); #define jar_xm_TRIGGER_KEEP_VOLUME (1 << 0) #define jar_xm_TRIGGER_KEEP_PERIOD (1 << 1) #define jar_xm_TRIGGER_KEEP_SAMPLE_POSITION (1 << 2) -static const uint16_t amiga_frequencies[] = { - 1712, 1616, 1525, 1440, /* C-2, C#2, D-2, D#2 */ - 1357, 1281, 1209, 1141, /* E-2, F-2, F#2, G-2 */ - 1077, 1017, 961, 907, /* G#2, A-2, A#2, B-2 */ - 856, /* C-3 */ -}; + // C-2, C#2, D-2, D#2, E-2, F-2, F#2, G-2, G#2, A-2, A#2, B-2, C-3 +static const uint16_t amiga_frequencies[] = { 1712, 1616, 1525, 1440, 1357, 1281, 1209, 1141, 1077, 1017, 961, 907, 856 }; -static const float multi_retrig_add[] = { - 0.f, -1.f, -2.f, -4.f, /* 0, 1, 2, 3 */ - -8.f, -16.f, 0.f, 0.f, /* 4, 5, 6, 7 */ - 0.f, 1.f, 2.f, 4.f, /* 8, 9, A, B */ - 8.f, 16.f, 0.f, 0.f /* C, D, E, F */ -}; + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f +static const float multi_retrig_add[] = { 0.f, -1.f, -2.f, -4.f, -8.f, -16.f, 0.f, 0.f, 0.f, 1.f, 2.f, 4.f, 8.f, 16.f, 0.f, 0.f }; -static const float multi_retrig_multiply[] = { - 1.f, 1.f, 1.f, 1.f, /* 0, 1, 2, 3 */ - 1.f, 1.f, .6666667f, .5f, /* 4, 5, 6, 7 */ - 1.f, 1.f, 1.f, 1.f, /* 8, 9, A, B */ - 1.f, 1.f, 1.5f, 2.f /* C, D, E, F */ -}; + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f +static const float multi_retrig_multiply[] = { 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, .6666667f, .5f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.5f, 2.f }; #define jar_xm_CLAMP_UP1F(vol, limit) do { \ if((vol) > (limit)) (vol) = (limit); \ @@ -1279,43 +1136,26 @@ static const float multi_retrig_multiply[] = { || (s)->effect_param == 6 \ || ((s)->volume_column >> 4) == 0xB) #define NOTE_IS_VALID(n) ((n) > 0 && (n) < 97) - -/* ----- Function definitions ----- */ +#define NOTE_OFF 97 static float jar_xm_waveform(jar_xm_waveform_type_t waveform, uint8_t step) { static unsigned int next_rand = 24492; step %= 0x40; - switch(waveform) { - - case jar_xm_SINE_WAVEFORM: - /* Why not use a table? For saving space, and because there's - * very very little actual performance gain. */ + case jar_xm_SINE_WAVEFORM: /* No SIN() table used, direct calculation. */ return -sinf(2.f * 3.141592f * (float)step / (float)0x40); - - case jar_xm_RAMP_DOWN_WAVEFORM: - /* Ramp down: 1.0f when step = 0; -1.0f when step = 0x40 */ + case jar_xm_RAMP_DOWN_WAVEFORM: /* Ramp down: 1.0f when step = 0; -1.0f when step = 0x40 */ return (float)(0x20 - step) / 0x20; - - case jar_xm_SQUARE_WAVEFORM: - /* Square with a 50% duty */ + case jar_xm_SQUARE_WAVEFORM: /* Square with a 50% duty */ return (step >= 0x20) ? 1.f : -1.f; - - case jar_xm_RANDOM_WAVEFORM: - /* Use the POSIX.1-2001 example, just to be deterministic - * across different machines */ + case jar_xm_RANDOM_WAVEFORM: /* Use the POSIX.1-2001 example, just to be deterministic across different machines */ next_rand = next_rand * 1103515245 + 12345; return (float)((next_rand >> 16) & 0x7FFF) / (float)0x4000 - 1.f; - - case jar_xm_RAMP_UP_WAVEFORM: - /* Ramp up: -1.f when step = 0; 1.f when step = 0x40 */ + case jar_xm_RAMP_UP_WAVEFORM: /* Ramp up: -1.f when step = 0; 1.f when step = 0x40 */ return (float)(step - 0x20) / 0x20; - default: break; - } - return .0f; } @@ -1323,33 +1163,21 @@ static void jar_xm_autovibrato(jar_xm_context_t* ctx, jar_xm_channel_context_t* if(ch->instrument == NULL || ch->instrument->vibrato_depth == 0) return; jar_xm_instrument_t* instr = ch->instrument; float sweep = 1.f; - - if(ch->autovibrato_ticks < instr->vibrato_sweep) { - /* No idea if this is correct, but it sounds close enough… */ - sweep = jar_xm_LERP(0.f, 1.f, (float)ch->autovibrato_ticks / (float)instr->vibrato_sweep); - } - + if(ch->autovibrato_ticks < instr->vibrato_sweep) { sweep = jar_xm_LERP(0.f, 1.f, (float)ch->autovibrato_ticks / (float)instr->vibrato_sweep); } unsigned int step = ((ch->autovibrato_ticks++) * instr->vibrato_rate) >> 2; - ch->autovibrato_note_offset = .25f * jar_xm_waveform(instr->vibrato_type, step) - * (float)instr->vibrato_depth / (float)0xF * sweep; + ch->autovibrato_note_offset = .25f * jar_xm_waveform(instr->vibrato_type, step) * (float)instr->vibrato_depth / (float)0xF * sweep; jar_xm_update_frequency(ctx, ch); } static void jar_xm_vibrato(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t pos) { unsigned int step = pos * (param >> 4); - ch->vibrato_note_offset = - 2.f - * jar_xm_waveform(ch->vibrato_waveform, step) - * (float)(param & 0x0F) / (float)0xF; + ch->vibrato_note_offset = 2.f * jar_xm_waveform(ch->vibrato_waveform, step) * (float)(param & 0x0F) / (float)0xF; jar_xm_update_frequency(ctx, ch); } static void jar_xm_tremolo(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t pos) { unsigned int step = pos * (param >> 4); - /* Not so sure about this, it sounds correct by ear compared with - * MilkyTracker, but it could come from other bugs */ - ch->tremolo_volume = -1.f * jar_xm_waveform(ch->tremolo_waveform, step) - * (float)(param & 0x0F) / (float)0xF; + ch->tremolo_volume = -1.f * jar_xm_waveform(ch->tremolo_waveform, step) * (float)(param & 0x0F) / (float)0xF; } static void jar_xm_arpeggio(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, uint8_t param, uint16_t tick) { @@ -1367,80 +1195,36 @@ static void jar_xm_arpeggio(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, ch->arp_note_offset = param & 0x0F; break; } - jar_xm_update_frequency(ctx, ch); } static void jar_xm_tone_portamento(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch) { - /* 3xx called without a note, wait until we get an actual - * target note. */ - if(ch->tone_portamento_target_period == 0.f) return; - + /* 3xx called without a note, wait until we get an actual target note. */ + if(ch->tone_portamento_target_period == 0.f) return; /* no value, exit */ if(ch->period != ch->tone_portamento_target_period) { - jar_xm_SLIDE_TOWARDS(ch->period, - ch->tone_portamento_target_period, - (ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES ? - 4.f : 1.f) * ch->tone_portamento_param - ); + jar_xm_SLIDE_TOWARDS(ch->period, ch->tone_portamento_target_period, (ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES ? 4.f : 1.f) * ch->tone_portamento_param); jar_xm_update_frequency(ctx, ch); } } 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™. */ - if(ctx->module.frequency_type == jar_xm_LINEAR_FREQUENCIES) { - period_offset *= 4.f; - } - + /* 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); /* XXX: upper bound of period ? */ - jar_xm_update_frequency(ctx, ch); } static void jar_xm_panning_slide(jar_xm_channel_context_t* ch, uint8_t rawval) { - float f; - - if((rawval & 0xF0) && (rawval & 0x0F)) { - /* Illegal state */ - return; - } - - if(rawval & 0xF0) { - /* Slide right */ - f = (float)(rawval >> 4) / (float)0xFF; - ch->panning += f; - jar_xm_CLAMP_UP(ch->panning); - } else { - /* Slide left */ - f = (float)(rawval & 0x0F) / (float)0xFF; - ch->panning -= f; - jar_xm_CLAMP_DOWN(ch->panning); - } -} + if (rawval & 0xF0) {ch->panning += (float)((rawval & 0xF0 )>> 4) / (float)0xFF;}; + if (rawval & 0x0F) {ch->panning -= (float)(rawval & 0x0F) / (float)0xFF;}; +}; static void jar_xm_volume_slide(jar_xm_channel_context_t* ch, uint8_t rawval) { - float f; - - if((rawval & 0xF0) && (rawval & 0x0F)) { - /* Illegal state */ - return; - } - - if(rawval & 0xF0) { - /* Slide up */ - f = (float)(rawval >> 4) / (float)0x40; - ch->volume += f; - jar_xm_CLAMP_UP(ch->volume); - } else { - /* Slide down */ - f = (float)(rawval & 0x0F) / (float)0x40; - ch->volume -= f; - jar_xm_CLAMP_DOWN(ch->volume); - } -} + if (rawval & 0xF0) {ch->volume += (float)((rawval & 0xF0) >> 4) / (float)0x40;}; + if (rawval & 0x0F) {ch->volume -= (float)(rawval & 0x0F) / (float)0x40;}; +}; static float jar_xm_envelope_lerp(jar_xm_envelope_point_t* a, jar_xm_envelope_point_t* b, uint16_t pos) { /* Linear interpolation between two envelope points */ @@ -1456,6 +1240,9 @@ 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->bpm = ctx->default_bpm; // reset to file default value + ctx->global_volume = ctx->default_global_volume; // reset to file default value } } @@ -1472,24 +1259,19 @@ static float jar_xm_amiga_period(float note) { uint8_t a = intnote % 12; int8_t octave = note / 12.f - 2; uint16_t p1 = amiga_frequencies[a], p2 = amiga_frequencies[a + 1]; - if(octave > 0) { p1 >>= octave; p2 >>= octave; } else if(octave < 0) { - p1 <<= (-octave); - p2 <<= (-octave); + p1 <<= -octave; + p2 <<= -octave; } - return jar_xm_LERP(p1, p2, note - intnote); } static float jar_xm_amiga_frequency(float period) { if(period == .0f) return .0f; - - /* This is the PAL value. No reason to choose this one over the - * NTSC value. */ - return 7093789.2f / (period * 2.f); + return 7093789.2f / (period * 2.f); /* This is the PAL value. (we could use the NTSC value also) */ } static float jar_xm_period(jar_xm_context_t* ctx, float note) { @@ -1503,29 +1285,20 @@ static float jar_xm_period(jar_xm_context_t* ctx, float note) { } static float jar_xm_frequency(jar_xm_context_t* ctx, float period, float note_offset) { - uint8_t a; - int8_t octave; - float note; - uint16_t p1, p2; - switch(ctx->module.frequency_type) { - case jar_xm_LINEAR_FREQUENCIES: return jar_xm_linear_frequency(period - 64.f * note_offset); - case jar_xm_AMIGA_FREQUENCIES: - if(note_offset == 0) { - /* A chance to escape from insanity */ - return jar_xm_amiga_frequency(period); - } - - /* FIXME: this is very crappy at best */ - a = octave = 0; + if(note_offset == 0) { return jar_xm_amiga_frequency(period); }; + int8_t octave; + float note; + uint16_t p1, p2; + uint8_t a = octave = 0; /* Find the octave of the current period */ if(period > amiga_frequencies[0]) { --octave; - while(period > (amiga_frequencies[0] << (-octave))) --octave; + while(period > (amiga_frequencies[0] << -octave)) --octave; } else if(period < amiga_frequencies[12]) { ++octave; while(period < (amiga_frequencies[12] >> octave)) ++octave; @@ -1534,7 +1307,6 @@ static float jar_xm_frequency(jar_xm_context_t* ctx, float period, float note_of /* Find the smallest note closest to the current period */ for(uint8_t i = 0; i < 12; ++i) { p1 = amiga_frequencies[i], p2 = amiga_frequencies[i + 1]; - if(octave > 0) { p1 >>= octave; p2 >>= octave; @@ -1542,51 +1314,36 @@ static float jar_xm_frequency(jar_xm_context_t* ctx, float period, float note_of p1 <<= (-octave); p2 <<= (-octave); } - if(p2 <= period && period <= p1) { a = i; break; } } - - if(JAR_XM_DEBUG && (p1 < period || p2 > period)) { - DEBUG("%i <= %f <= %i should hold but doesn't, this is a bug", p2, period, p1); - } - + if(JAR_XM_DEBUG && (p1 < period || p2 > period)) { DEBUG("%i <= %f <= %i should hold but doesn't, this is a bug", p2, period, p1); } note = 12.f * (octave + 2) + a + jar_xm_INVERSE_LERP(p1, p2, period); - return jar_xm_amiga_frequency(jar_xm_amiga_period(note + note_offset)); - } return .0f; } static void jar_xm_update_frequency(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch) { - ch->frequency = jar_xm_frequency( - ctx, ch->period, - (ch->arp_note_offset > 0 ? ch->arp_note_offset : ( - ch->vibrato_note_offset + ch->autovibrato_note_offset - )) - ); + ch->frequency = jar_xm_frequency( ctx, ch->period, (ch->arp_note_offset > 0 ? ch->arp_note_offset : ( ch->vibrato_note_offset + ch->autovibrato_note_offset )) ); ch->step = ch->frequency / ctx->rate; } -static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, - jar_xm_pattern_slot_t* s) { +static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, jar_xm_pattern_slot_t* s) { + jar_xm_module_t* mod = &(ctx->module); if(s->instrument > 0) { - if(HAS_TONE_PORTAMENTO(ch->current) && ch->instrument != NULL && ch->sample != NULL) { - /* Tone portamento in effect, unclear stuff happens */ + if(HAS_TONE_PORTAMENTO(ch->current) && ch->instrument != NULL && ch->sample != NULL) { /* Tone portamento in effect */ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_PERIOD | jar_xm_TRIGGER_KEEP_SAMPLE_POSITION); - } else if(s->instrument > ctx->module.num_instruments) { - /* Invalid instrument, Cut current note */ + } else if(s->instrument > ctx->module.num_instruments) { /* Invalid instrument, Cut current note */ jar_xm_cut_note(ch); ch->instrument = NULL; ch->sample = NULL; } else { ch->instrument = ctx->module.instruments + (s->instrument - 1); - if(s->note == 0 && ch->sample != NULL) { - /* Ghost instrument, trigger note */ + if(s->note == 0 && ch->sample != NULL) { /* Ghost instrument, trigger note */ /* Sample position is kept, but envelopes are reset */ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_SAMPLE_POSITION); } @@ -1594,270 +1351,174 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan } if(NOTE_IS_VALID(s->note)) { - /* Yes, the real note number is s->note -1. Try finding - * THAT in any of the specs! :-) */ - + // note value is s->note -1 jar_xm_instrument_t* instr = ch->instrument; - if(HAS_TONE_PORTAMENTO(ch->current) && instr != NULL && ch->sample != NULL) { /* Tone portamento in effect */ ch->note = s->note + ch->sample->relative_note + ch->sample->finetune / 128.f - 1.f; ch->tone_portamento_target_period = jar_xm_period(ctx, ch->note); - } else if(instr == NULL || ch->instrument->num_samples == 0) { - /* Bad instrument */ + } else if(instr == NULL || ch->instrument->num_samples == 0) { /* Issue on instrument */ jar_xm_cut_note(ch); } else { if(instr->sample_of_notes[s->note - 1] < instr->num_samples) { -#if JAR_XM_RAMPING - for(unsigned int z = 0; z < jar_xm_SAMPLE_RAMPING_POINTS; ++z) { - ch->end_of_previous_sample[z] = jar_xm_next_of_sample(ch); - } - ch->frame_count = 0; -#endif + if (mod->ramping) { + for(int i = 0; i < jar_xm_SAMPLE_RAMPING_POINTS; ++i) { + jar_xm_next_of_sample(ctx, ch, i); + } + ch->frame_count = 0; + }; ch->sample = instr->samples + instr->sample_of_notes[s->note - 1]; - ch->orig_note = ch->note = s->note + ch->sample->relative_note - + ch->sample->finetune / 128.f - 1.f; + ch->orig_note = ch->note = s->note + ch->sample->relative_note + ch->sample->finetune / 128.f - 1.f; if(s->instrument > 0) { jar_xm_trigger_note(ctx, ch, 0); - } else { - /* Ghost note: keep old volume */ + } else { /* Ghost note: keep old volume */ jar_xm_trigger_note(ctx, ch, jar_xm_TRIGGER_KEEP_VOLUME); } } else { - /* Bad sample */ jar_xm_cut_note(ch); } } - } else if(s->note == 97) { - /* Key Off */ + } else if(s->note == NOTE_OFF) { jar_xm_key_off(ch); } - switch(s->volume_column >> 4) { - - case 0x5: - if(s->volume_column > 0x50) break; - case 0x1: - case 0x2: - case 0x3: - case 0x4: - /* Set volume */ - ch->volume = (float)(s->volume_column - 0x10) / (float)0x40; - break; - - case 0x8: /* Fine volume slide down */ - jar_xm_volume_slide(ch, s->volume_column & 0x0F); - break; - - case 0x9: /* Fine volume slide up */ - jar_xm_volume_slide(ch, s->volume_column << 4); - break; - - case 0xA: /* Set vibrato speed */ - ch->vibrato_param = (ch->vibrato_param & 0x0F) | ((s->volume_column & 0x0F) << 4); - break; - - case 0xC: /* Set panning */ - ch->panning = (float)( - ((s->volume_column & 0x0F) << 4) | (s->volume_column & 0x0F) - ) / (float)0xFF; - break; - - case 0xF: /* Tone portamento */ - if(s->volume_column & 0x0F) { - ch->tone_portamento_param = ((s->volume_column & 0x0F) << 4) - | (s->volume_column & 0x0F); - } - break; - - default: - break; - - } - + // Interpret Effect column switch(s->effect_type) { - case 1: /* 1xx: Portamento up */ - if(s->effect_param > 0) { - ch->portamento_up_param = s->effect_param; - } + if(s->effect_param > 0) { ch->portamento_up_param = s->effect_param; } break; - case 2: /* 2xx: Portamento down */ - if(s->effect_param > 0) { - ch->portamento_down_param = s->effect_param; - } + if(s->effect_param > 0) { ch->portamento_down_param = s->effect_param; } break; - case 3: /* 3xx: Tone portamento */ - if(s->effect_param > 0) { - ch->tone_portamento_param = s->effect_param; - } + if(s->effect_param > 0) { ch->tone_portamento_param = s->effect_param; } break; - case 4: /* 4xy: Vibrato */ - if(s->effect_param & 0x0F) { - /* Set vibrato depth */ - ch->vibrato_param = (ch->vibrato_param & 0xF0) | (s->effect_param & 0x0F); - } - if(s->effect_param >> 4) { - /* Set vibrato speed */ - ch->vibrato_param = (s->effect_param & 0xF0) | (ch->vibrato_param & 0x0F); - } + if(s->effect_param & 0x0F) { ch->vibrato_param = (ch->vibrato_param & 0xF0) | (s->effect_param & 0x0F); } /* Set vibrato depth */ + if(s->effect_param >> 4) { ch->vibrato_param = (s->effect_param & 0xF0) | (ch->vibrato_param & 0x0F); } /* Set vibrato speed */ break; - case 5: /* 5xy: Tone portamento + Volume slide */ - if(s->effect_param > 0) { - ch->volume_slide_param = s->effect_param; - } + if(s->effect_param > 0) { ch->volume_slide_param = s->effect_param; } break; - case 6: /* 6xy: Vibrato + Volume slide */ - if(s->effect_param > 0) { - ch->volume_slide_param = s->effect_param; - } + if(s->effect_param > 0) { ch->volume_slide_param = s->effect_param; } break; - case 7: /* 7xy: Tremolo */ - if(s->effect_param & 0x0F) { - /* Set tremolo depth */ - ch->tremolo_param = (ch->tremolo_param & 0xF0) | (s->effect_param & 0x0F); - } - if(s->effect_param >> 4) { - /* Set tremolo speed */ - ch->tremolo_param = (s->effect_param & 0xF0) | (ch->tremolo_param & 0x0F); - } + if(s->effect_param & 0x0F) { ch->tremolo_param = (ch->tremolo_param & 0xF0) | (s->effect_param & 0x0F); } /* Set tremolo depth */ + if(s->effect_param >> 4) { ch->tremolo_param = (s->effect_param & 0xF0) | (ch->tremolo_param & 0x0F); } /* Set tremolo speed */ break; - case 8: /* 8xx: Set panning */ - ch->panning = (float)s->effect_param / (float)0xFF; + ch->panning = (float)s->effect_param / 255.f; break; - case 9: /* 9xx: Sample offset */ - if(ch->sample != NULL && NOTE_IS_VALID(s->note)) { + if(ch->sample != 0) { //&& NOTE_IS_VALID(s->note)) { uint32_t final_offset = s->effect_param << (ch->sample->bits == 16 ? 7 : 8); - if(final_offset >= ch->sample->length) { - /* Pretend the sample dosen't loop and is done playing */ - ch->sample_position = -1; + switch (ch->sample->loop_type) { + case jar_xm_NO_LOOP: + if(final_offset >= ch->sample->length) { /* Pretend the sample dosen't loop and is done playing */ + ch->sample_position = -1; + } else { + ch->sample_position = final_offset; + } + break; + case jar_xm_FORWARD_LOOP: + if (final_offset >= ch->sample->loop_end) { + ch->sample_position -= ch->sample->loop_length; + } else if(final_offset >= ch->sample->length) { + ch->sample_position = ch->sample->loop_start; + } else { + ch->sample_position = final_offset; + } + break; + case jar_xm_PING_PONG_LOOP: + if(final_offset >= ch->sample->loop_end) { + ch->ping = false; + ch->sample_position = (ch->sample->loop_end << 1) - ch->sample_position; + } else if(final_offset >= ch->sample->length) { + ch->ping = false; + ch->sample_position -= ch->sample->length - 1; + } else { + ch->sample_position = final_offset; + }; break; } - ch->sample_position = final_offset; } break; - case 0xA: /* Axy: Volume slide */ - if(s->effect_param > 0) { - ch->volume_slide_param = s->effect_param; - } + if(s->effect_param > 0) { ch->volume_slide_param = s->effect_param; } break; - case 0xB: /* Bxx: Position jump */ if(s->effect_param < ctx->module.length) { ctx->position_jump = true; ctx->jump_dest = s->effect_param; } break; - case 0xC: /* Cxx: Set volume */ - ch->volume = (float)((s->effect_param > 0x40) - ? 0x40 : s->effect_param) / (float)0x40; + ch->volume = (float)((s->effect_param > 0x40) ? 0x40 : s->effect_param) / (float)0x40; break; - case 0xD: /* Dxx: Pattern break */ /* Jump after playing this line */ ctx->pattern_break = true; ctx->jump_row = (s->effect_param >> 4) * 10 + (s->effect_param & 0x0F); break; - case 0xE: /* EXy: Extended command */ switch(s->effect_param >> 4) { - case 1: /* E1y: Fine portamento up */ - if(s->effect_param & 0x0F) { - ch->fine_portamento_up_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->fine_portamento_up_param = s->effect_param & 0x0F; } jar_xm_pitch_slide(ctx, ch, -ch->fine_portamento_up_param); break; - case 2: /* E2y: Fine portamento down */ - if(s->effect_param & 0x0F) { - ch->fine_portamento_down_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->fine_portamento_down_param = s->effect_param & 0x0F; } jar_xm_pitch_slide(ctx, ch, ch->fine_portamento_down_param); break; - case 4: /* E4y: Set vibrato control */ ch->vibrato_waveform = s->effect_param & 3; ch->vibrato_waveform_retrigger = !((s->effect_param >> 2) & 1); break; - case 5: /* E5y: Set finetune */ if(NOTE_IS_VALID(ch->current->note) && ch->sample != NULL) { - ch->note = ch->current->note + ch->sample->relative_note + - (float)(((s->effect_param & 0x0F) - 8) << 4) / 128.f - 1.f; + ch->note = ch->current->note + ch->sample->relative_note + (float)(((s->effect_param & 0x0F) - 8) << 4) / 128.f - 1.f; ch->period = jar_xm_period(ctx, ch->note); jar_xm_update_frequency(ctx, ch); } break; - case 6: /* E6y: Pattern loop */ if(s->effect_param & 0x0F) { - if((s->effect_param & 0x0F) == ch->pattern_loop_count) { - /* Loop is over */ + if((s->effect_param & 0x0F) == ch->pattern_loop_count) { /* Loop is over */ ch->pattern_loop_count = 0; - break; + ctx->position_jump = false; + } else { /* Jump to the beginning of the loop */ + ch->pattern_loop_count++; + ctx->position_jump = true; + ctx->jump_row = ch->pattern_loop_origin; + ctx->jump_dest = ctx->current_table_index; } - - /* Jump to the beginning of the loop */ - ch->pattern_loop_count++; - ctx->position_jump = true; - ctx->jump_row = ch->pattern_loop_origin; - ctx->jump_dest = ctx->current_table_index; } else { - /* Set loop start point */ - ch->pattern_loop_origin = ctx->current_row; - /* Replicate FT2 E60 bug */ - ctx->jump_row = ch->pattern_loop_origin; + ch->pattern_loop_origin = ctx->current_row; /* Set loop start point */ + ctx->jump_row = ch->pattern_loop_origin; /* Replicate FT2 E60 bug */ } break; - case 7: /* E7y: Set tremolo control */ ch->tremolo_waveform = s->effect_param & 3; ch->tremolo_waveform_retrigger = !((s->effect_param >> 2) & 1); break; - case 0xA: /* EAy: Fine volume slide up */ - if(s->effect_param & 0x0F) { - ch->fine_volume_slide_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->fine_volume_slide_param = s->effect_param & 0x0F; } jar_xm_volume_slide(ch, ch->fine_volume_slide_param << 4); break; - case 0xB: /* EBy: Fine volume slide down */ - if(s->effect_param & 0x0F) { - ch->fine_volume_slide_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->fine_volume_slide_param = s->effect_param & 0x0F; } 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) { ch->note = ch->orig_note; jar_xm_trigger_note(ctx, ch, flags); } else { - jar_xm_trigger_note( - ctx, ch, - flags - | jar_xm_TRIGGER_KEEP_PERIOD - | jar_xm_TRIGGER_KEEP_SAMPLE_POSITION - ); + jar_xm_trigger_note(ctx, ch, flags | jar_xm_TRIGGER_KEEP_PERIOD | jar_xm_TRIGGER_KEEP_SAMPLE_POSITION ); } } break; @@ -1865,107 +1526,77 @@ static void jar_xm_handle_note_and_instrument(jar_xm_context_t* ctx, jar_xm_chan case 0xE: /* EEy: Pattern delay */ ctx->extra_ticks = (ch->current->effect_param & 0x0F) * ctx->tempo; break; - default: break; - } break; case 0xF: /* Fxx: Set tempo/BPM */ if(s->effect_param > 0) { - if(s->effect_param <= 0x1F) { + if(s->effect_param <= 0x1F) { // First 32 possible values adjust the ticks (goes into tempo) ctx->tempo = s->effect_param; - } else { + } else { //32 and greater values adjust the BPM ctx->bpm = s->effect_param; } } break; case 16: /* Gxx: Set global volume */ - ctx->global_volume = (float)((s->effect_param > 0x40) - ? 0x40 : s->effect_param) / (float)0x40; + ctx->global_volume = (float)((s->effect_param > 0x40) ? 0x40 : s->effect_param) / (float)0x40; break; - case 17: /* Hxy: Global volume slide */ - if(s->effect_param > 0) { - ch->global_volume_slide_param = s->effect_param; - } + if(s->effect_param > 0) { ch->global_volume_slide_param = s->effect_param; } break; - case 21: /* Lxx: Set envelope position */ ch->volume_envelope_frame_count = s->effect_param; ch->panning_envelope_frame_count = s->effect_param; break; - case 25: /* Pxy: Panning slide */ - if(s->effect_param > 0) { - ch->panning_slide_param = s->effect_param; - } + if(s->effect_param > 0) { ch->panning_slide_param = s->effect_param; } break; - case 27: /* Rxy: Multi retrig note */ if(s->effect_param > 0) { - if((s->effect_param >> 4) == 0) { - /* Keep previous x value */ + if((s->effect_param >> 4) == 0) { /* Keep previous x value */ ch->multi_retrig_param = (ch->multi_retrig_param & 0xF0) | (s->effect_param & 0x0F); } else { ch->multi_retrig_param = s->effect_param; } } break; - case 29: /* Txy: Tremor */ - if(s->effect_param > 0) { - /* Tremor x and y params do not appear to be separately - * kept in memory, unlike Rxy */ - ch->tremor_param = s->effect_param; - } + if(s->effect_param > 0) { ch->tremor_param = s->effect_param; } /* Tremor x and y params are not separately kept in memory, unlike Rxy */ break; - case 33: /* Xxy: Extra stuff */ switch(s->effect_param >> 4) { - case 1: /* X1y: Extra fine portamento up */ - if(s->effect_param & 0x0F) { - ch->extra_fine_portamento_up_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->extra_fine_portamento_up_param = s->effect_param & 0x0F; } jar_xm_pitch_slide(ctx, ch, -1.0f * ch->extra_fine_portamento_up_param); break; - case 2: /* X2y: Extra fine portamento down */ - if(s->effect_param & 0x0F) { - ch->extra_fine_portamento_down_param = s->effect_param & 0x0F; - } + if(s->effect_param & 0x0F) { ch->extra_fine_portamento_down_param = s->effect_param & 0x0F; } jar_xm_pitch_slide(ctx, ch, ch->extra_fine_portamento_down_param); break; - default: break; - } break; - default: break; - } } static void jar_xm_trigger_note(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, unsigned int flags) { - if(!(flags & jar_xm_TRIGGER_KEEP_SAMPLE_POSITION)) { + if (!(flags & jar_xm_TRIGGER_KEEP_SAMPLE_POSITION)) { ch->sample_position = 0.f; ch->ping = true; - } - - if(ch->sample != NULL) { - if(!(flags & jar_xm_TRIGGER_KEEP_VOLUME)) { - ch->volume = ch->sample->volume; - } - - ch->panning = ch->sample->panning; - } + }; + if (!(flags & jar_xm_TRIGGER_KEEP_VOLUME)) { + if(ch->sample != NULL) { + ch->volume = ch->sample->volume; + }; + }; + ch->panning = ch->sample->panning; ch->sustained = true; ch->fadeout_volume = ch->volume_envelope_volume = 1.0f; ch->panning_envelope_panning = .5f; @@ -1973,44 +1604,28 @@ static void jar_xm_trigger_note(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch->vibrato_note_offset = 0.f; ch->tremolo_volume = 0.f; ch->tremor_on = false; - ch->autovibrato_ticks = 0; - if(ch->vibrato_waveform_retrigger) { - ch->vibrato_ticks = 0; /* XXX: should the waveform itself also - * be reset to sine? */ - } - if(ch->tremolo_waveform_retrigger) { - ch->tremolo_ticks = 0; - } - + if(ch->vibrato_waveform_retrigger) { ch->vibrato_ticks = 0; } /* XXX: should the waveform itself also be reset to sine? */ + if(ch->tremolo_waveform_retrigger) { ch->tremolo_ticks = 0; } if(!(flags & jar_xm_TRIGGER_KEEP_PERIOD)) { ch->period = jar_xm_period(ctx, ch->note); jar_xm_update_frequency(ctx, ch); } - ch->latest_trigger = ctx->generated_samples; - if(ch->instrument != NULL) { - ch->instrument->latest_trigger = ctx->generated_samples; - } - if(ch->sample != NULL) { - ch->sample->latest_trigger = ctx->generated_samples; - } + if(ch->instrument != NULL) { ch->instrument->latest_trigger = ctx->generated_samples; } + if(ch->sample != NULL) { ch->sample->latest_trigger = ctx->generated_samples; } } static void jar_xm_cut_note(jar_xm_channel_context_t* ch) { - /* NB: this is not the same as Key Off */ - ch->volume = .0f; + ch->volume = .0f; /* NB: this is not the same as Key Off */ +// ch->curr_left = .0f; +// ch->curr_right = .0f; } static void jar_xm_key_off(jar_xm_channel_context_t* ch) { - /* Key Off */ - ch->sustained = false; - - /* If no volume envelope is used, also cut the note */ - if(ch->instrument == NULL || !ch->instrument->volume_envelope.enabled) { - jar_xm_cut_note(ch); - } + ch->sustained = false; /* Key Off */ + if(ch->instrument == NULL || !ch->instrument->volume_envelope.enabled) { jar_xm_cut_note(ch); } /* If no volume envelope is used, also cut the note */ } static void jar_xm_row(jar_xm_context_t* ctx) { @@ -2028,24 +1643,24 @@ static void jar_xm_row(jar_xm_context_t* ctx) { ctx->jump_row = 0; jar_xm_post_pattern_change(ctx); } - jar_xm_pattern_t* cur = ctx->module.patterns + ctx->module.pattern_table[ctx->current_table_index]; bool in_a_loop = false; - /* Read notes… */ + /* Read notes information for all channels into temporary pattern slot */ for(uint8_t i = 0; i < ctx->module.num_channels; ++i) { jar_xm_pattern_slot_t* s = cur->slots + ctx->current_row * ctx->module.num_channels + i; jar_xm_channel_context_t* ch = ctx->channels + i; - ch->current = s; - + // If there is no note delay effect (0xED) then... if(s->effect_type != 0xE || s->effect_param >> 4 != 0xD) { + //********** Process the channel slot information ********** jar_xm_handle_note_and_instrument(ctx, ch, s); } else { + // read the note delay information ch->note_delay_param = s->effect_param & 0x0F; } - if(!in_a_loop && ch->pattern_loop_count > 0) { + // clarify if in a loop or not in_a_loop = true; } } @@ -2055,100 +1670,67 @@ static void jar_xm_row(jar_xm_context_t* ctx) { ctx->loop_count = (ctx->row_loop_count[MAX_NUM_ROWS * ctx->current_table_index + ctx->current_row]++); } - ctx->current_row++; /* Since this is an uint8, this line 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)) { + /// 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)) { ctx->current_table_index++; - ctx->current_row = ctx->jump_row; /* This will be 0 most of - * the time, except when E60 - * is used */ + ctx->current_row = ctx->jump_row; /* This will be 0 most of the time, except when E60 is used */ ctx->jump_row = 0; jar_xm_post_pattern_change(ctx); } } -static void jar_xm_envelope_tick(jar_xm_channel_context_t* ch, - jar_xm_envelope_t* env, - uint16_t* counter, - float* outval) { +static void jar_xm_envelope_tick(jar_xm_channel_context_t *ch, jar_xm_envelope_t *env, uint16_t *counter, float *outval) { if(env->num_points < 2) { - /* Don't really know what to do… */ if(env->num_points == 1) { - /* XXX I am pulling this out of my ass */ *outval = (float)env->points[0].value / (float)0x40; - if(*outval > 1) { - *outval = 1; - } - } - - return; + if(*outval > 1) { *outval = 1; }; + } else {; + return; + }; } else { - uint8_t j; - if(env->loop_enabled) { uint16_t loop_start = env->points[env->loop_start_point].frame; uint16_t loop_end = env->points[env->loop_end_point].frame; uint16_t loop_length = loop_end - loop_start; - - if(*counter >= loop_end) { - *counter -= loop_length; - } - } - - for(j = 0; j < (env->num_points - 2); ++j) { - if(env->points[j].frame <= *counter && - env->points[j+1].frame >= *counter) { + if(*counter >= loop_end) { *counter -= loop_length; }; + }; + for(uint8_t j = 0; j < (env->num_points - 1); ++j) { + if(env->points[j].frame <= *counter && env->points[j+1].frame >= *counter) { + *outval = jar_xm_envelope_lerp(env->points + j, env->points + j + 1, *counter) / (float)0x40; break; - } - } - - *outval = jar_xm_envelope_lerp(env->points + j, env->points + j + 1, *counter) / (float)0x40; - + }; + }; /* Make sure it is safe to increment frame count */ - if(!ch->sustained || !env->sustain_enabled || - *counter != env->points[env->sustain_point].frame) { - (*counter)++; - } - } -} + if(!ch->sustained || !env->sustain_enabled || *counter != env->points[env->sustain_point].frame) { (*counter)++; }; + }; +}; -static void jar_xm_envelopes(jar_xm_channel_context_t* ch) { +static void jar_xm_envelopes(jar_xm_channel_context_t *ch) { if(ch->instrument != NULL) { if(ch->instrument->volume_envelope.enabled) { if(!ch->sustained) { ch->fadeout_volume -= (float)ch->instrument->volume_fadeout / 65536.f; jar_xm_CLAMP_DOWN(ch->fadeout_volume); - } - - jar_xm_envelope_tick(ch, - &(ch->instrument->volume_envelope), - &(ch->volume_envelope_frame_count), - &(ch->volume_envelope_volume)); - } - + }; + jar_xm_envelope_tick(ch, &(ch->instrument->volume_envelope), &(ch->volume_envelope_frame_count), &(ch->volume_envelope_volume)); + }; if(ch->instrument->panning_envelope.enabled) { - jar_xm_envelope_tick(ch, - &(ch->instrument->panning_envelope), - &(ch->panning_envelope_frame_count), - &(ch->panning_envelope_panning)); - } - } -} + jar_xm_envelope_tick(ch, &(ch->instrument->panning_envelope), &(ch->panning_envelope_frame_count), &(ch->panning_envelope_panning)); + }; + }; +}; static void jar_xm_tick(jar_xm_context_t* ctx) { if(ctx->current_tick == 0) { - jar_xm_row(ctx); + 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; - jar_xm_envelopes(ch); jar_xm_autovibrato(ctx, ch); - if(ch->arp_in_progress && !HAS_ARPEGGIO(ch->current)) { ch->arp_in_progress = false; ch->arp_note_offset = 0; @@ -2160,51 +1742,64 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { jar_xm_update_frequency(ctx, ch); } - switch(ch->current->volume_column >> 4) { - - case 0x6: /* Volume slide down */ - if(ctx->current_tick == 0) break; + // Effects in volumne column mostly handled on a per tick basis + switch(ch->current->volume_column & 0xF0) { + case 0x50: // Checks for volume = 64 + if(ch->current->volume_column != 0x50) break; + case 0x10: // Set volume 0-15 + case 0x20: // Set volume 16-32 + case 0x30: // Set volume 32-48 + case 0x40: // Set volume 48-64 + ch->volume = (float)(ch->current->volume_column - 16) / 64.0f; + break; + case 0x60: // Volume slide down jar_xm_volume_slide(ch, ch->current->volume_column & 0x0F); break; - - case 0x7: /* Volume slide up */ - if(ctx->current_tick == 0) break; + case 0x70: // Volume slide up jar_xm_volume_slide(ch, ch->current->volume_column << 4); break; - - case 0xB: /* Vibrato */ - if(ctx->current_tick == 0) break; + case 0x80: // Fine volume slide down + jar_xm_volume_slide(ch, ch->current->volume_column & 0x0F); + break; + case 0x90: // Fine volume slide up + jar_xm_volume_slide(ch, ch->current->volume_column << 4); + break; + case 0xA0: // Set vibrato speed + ch->vibrato_param = (ch->vibrato_param & 0x0F) | ((ch->current->volume_column & 0x0F) << 4); + break; + case 0xB0: // Vibrato ch->vibrato_in_progress = false; jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++); break; - - case 0xD: /* Panning slide left */ - if(ctx->current_tick == 0) break; + case 0xC0: // Set panning + if(!ctx->current_tick ) { + ch->panning = (float)(ch->current->volume_column & 0x0F) / 15.0f; + } + break; + case 0xD0: // Panning slide left jar_xm_panning_slide(ch, ch->current->volume_column & 0x0F); break; - - case 0xE: /* Panning slide right */ - if(ctx->current_tick == 0) break; + case 0xE0: // Panning slide right jar_xm_panning_slide(ch, ch->current->volume_column << 4); break; - - case 0xF: /* Tone portamento */ - if(ctx->current_tick == 0) break; + case 0xF0: // Tone portamento + if(!ctx->current_tick ) { + if(ch->current->volume_column & 0x0F) { ch->tone_portamento_param = ((ch->current->volume_column & 0x0F) << 4) | (ch->current->volume_column & 0x0F); } + }; jar_xm_tone_portamento(ctx, ch); break; - default: break; - } + // Only some standard effects handled on a per tick basis + // see jar_xm_handle_note_and_instrument for all effects handling on a per row basis switch(ch->current->effect_type) { - case 0: /* 0xy: Arpeggio */ 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; @@ -2212,7 +1807,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; @@ -2220,7 +1815,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; @@ -2232,49 +1827,44 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { if(ctx->current_tick == 0) break; jar_xm_pitch_slide(ctx, ch, -ch->portamento_up_param); break; - case 2: /* 2xx: Portamento down */ if(ctx->current_tick == 0) break; jar_xm_pitch_slide(ctx, ch, ch->portamento_down_param); break; - case 3: /* 3xx: Tone portamento */ if(ctx->current_tick == 0) break; jar_xm_tone_portamento(ctx, ch); break; - case 4: /* 4xy: Vibrato */ if(ctx->current_tick == 0) break; ch->vibrato_in_progress = true; jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++); break; - case 5: /* 5xy: Tone portamento + Volume slide */ if(ctx->current_tick == 0) break; jar_xm_tone_portamento(ctx, ch); jar_xm_volume_slide(ch, ch->volume_slide_param); break; - case 6: /* 6xy: Vibrato + Volume slide */ if(ctx->current_tick == 0) break; ch->vibrato_in_progress = true; jar_xm_vibrato(ctx, ch, ch->vibrato_param, ch->vibrato_ticks++); jar_xm_volume_slide(ch, ch->volume_slide_param); break; - case 7: /* 7xy: Tremolo */ if(ctx->current_tick == 0) break; jar_xm_tremolo(ctx, ch, ch->tremolo_param, ch->tremolo_ticks++); break; - + case 8: /* 8xy: Set panning */ + break; + case 9: /* 9xy: Sample offset */ + break; case 0xA: /* Axy: Volume slide */ if(ctx->current_tick == 0) break; jar_xm_volume_slide(ch, ch->volume_slide_param); break; - case 0xE: /* EXy: Extended command */ switch(ch->current->effect_param >> 4) { - case 0x9: /* E9y: Retrigger note */ if(ctx->current_tick != 0 && ch->current->effect_param & 0x0F) { if(!(ctx->current_tick % (ch->current->effect_param & 0x0F))) { @@ -2283,59 +1873,46 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { } } break; - case 0xC: /* ECy: Note cut */ if((ch->current->effect_param & 0x0F) == ctx->current_tick) { jar_xm_cut_note(ch); } break; - case 0xD: /* EDy: Note delay */ if(ch->note_delay_param == ctx->current_tick) { jar_xm_handle_note_and_instrument(ctx, ch, ch->current); jar_xm_envelopes(ch); } break; - default: break; - } break; - + case 16: /* Fxy: Set tempo/BPM */ + 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)) { - /* Illegal state */ - break; - } - if(ch->global_volume_slide_param & 0xF0) { - /* Global slide up */ + if((ch->global_volume_slide_param & 0xF0) && (ch->global_volume_slide_param & 0x0F)) { break; }; /* Invalid state */ + if(ch->global_volume_slide_param & 0xF0) { /* Global slide up */ float f = (float)(ch->global_volume_slide_param >> 4) / (float)0x40; ctx->global_volume += f; jar_xm_CLAMP_UP(ctx->global_volume); - } else { - /* Global slide down */ + } else { /* Global slide down */ float f = (float)(ch->global_volume_slide_param & 0x0F) / (float)0x40; ctx->global_volume -= f; jar_xm_CLAMP_DOWN(ctx->global_volume); - } + }; break; case 20: /* Kxx: Key off */ - /* Most documentations will tell you the parameter has no - * use. Don't be fooled. */ - if(ctx->current_tick == ch->current->effect_param) { - jar_xm_key_off(ch); - } + if(ctx->current_tick == ch->current->effect_param) { jar_xm_key_off(ch); }; + break; + case 21: /* Lxx: Set envelope position */ break; - case 25: /* Pxy: Panning slide */ if(ctx->current_tick == 0) break; jar_xm_panning_slide(ch, ch->panning_slide_param); break; - case 27: /* Rxy: Multi retrig note */ if(ctx->current_tick == 0) break; if(((ch->multi_retrig_param) & 0x0F) == 0) break; @@ -2345,228 +1922,251 @@ static void jar_xm_tick(jar_xm_context_t* ctx) { jar_xm_CLAMP(v); jar_xm_trigger_note(ctx, ch, 0); ch->volume = v; - } + }; break; case 29: /* Txy: Tremor */ if(ctx->current_tick == 0) break; - ch->tremor_on = ( - (ctx->current_tick - 1) % ((ch->tremor_param >> 4) + (ch->tremor_param & 0x0F) + 2) - > - (ch->tremor_param >> 4) - ); + ch->tremor_on = ( (ctx->current_tick - 1) % ((ch->tremor_param >> 4) + (ch->tremor_param & 0x0F) + 2) > (ch->tremor_param >> 4) ); break; - default: break; - - } + }; float panning, volume; - - panning = ch->panning + - (ch->panning_envelope_panning - .5f) * (.5f - fabsf(ch->panning - .5f)) * 2.0f; - + panning = ch->panning + (ch->panning_envelope_panning - .5f) * (.5f - fabs(ch->panning - .5f)) * 2.0f; if(ch->tremor_on) { - volume = .0f; + volume = .0f; } else { volume = ch->volume + ch->tremolo_volume; jar_xm_CLAMP(volume); volume *= ch->fadeout_volume * ch->volume_envelope_volume; - } + }; -#if JAR_XM_RAMPING - ch->target_panning = panning; - ch->target_volume = volume; -#else - ch->actual_panning = panning; - ch->actual_volume = volume; -#endif - } + if (mod->ramping) { + ch->target_panning = panning; + ch->target_volume = volume; + } else { + ch->actual_panning = panning; + ch->actual_volume = volume; + }; + }; - ctx->current_tick++; + ctx->current_tick++; // ok so we understand that ticks increment within the row if(ctx->current_tick >= ctx->tempo + ctx->extra_ticks) { + // This means it reached the end of the row and we reset ctx->current_tick = 0; ctx->extra_ticks = 0; - } + }; - /* FT2 manual says number of ticks / second = BPM * 0.4 */ + // Number of ticks / second = BPM * 0.4 ctx->remaining_samples_in_tick += (float)ctx->rate / ((float)ctx->bpm * 0.4f); -} +}; -static float jar_xm_next_of_sample(jar_xm_channel_context_t* ch) { +static void jar_xm_next_of_sample(jar_xm_context_t* ctx, jar_xm_channel_context_t* ch, int previous) { + jar_xm_module_t* mod = &(ctx->module); + +// ch->curr_left = 0.f; +// ch->curr_right = 0.f; if(ch->instrument == NULL || ch->sample == NULL || ch->sample_position < 0) { -#if JAR_XM_RAMPING - if(ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) { - return jar_xm_LERP(ch->end_of_previous_sample[ch->frame_count], .0f, - (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); - } -#endif - return .0f; - } + ch->curr_left = 0.f; + ch->curr_right = 0.f; + if (mod->ramping) { + if (ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) { + if (previous > -1) { + ch->end_of_previous_sample_left[previous] = jar_xm_LERP(ch->end_of_previous_sample_left[ch->frame_count], ch->curr_left, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + ch->end_of_previous_sample_right[previous] = jar_xm_LERP(ch->end_of_previous_sample_right[ch->frame_count], ch->curr_right, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + } else { + ch->curr_left = jar_xm_LERP(ch->end_of_previous_sample_left[ch->frame_count], ch->curr_left, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + ch->curr_right = jar_xm_LERP(ch->end_of_previous_sample_right[ch->frame_count], ch->curr_right, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + }; + }; + }; + return; + }; if(ch->sample->length == 0) { - return .0f; - } + return; + }; - float u, v, t; - uint32_t a, b; - a = (uint32_t)ch->sample_position; /* This cast is fine, - * sample_position will not - * go above integer - * ranges */ - if(JAR_XM_LINEAR_INTERPOLATION) { - b = a + 1; - t = ch->sample_position - a; /* Cheaper than fmodf(., 1.f) */ - } - u = ch->sample->data[a]; + float t = 0.f; + uint32_t b = 0; + if(mod->linear_interpolation) { + b = ch->sample_position + 1; + t = ch->sample_position - (uint32_t)ch->sample_position; /* Cheaper than fmodf(., 1.f) */ + }; + float u_left, u_right; + u_left = ch->sample->data[(uint32_t)ch->sample_position]; + if (ch->sample->stereo) { + u_right = ch->sample->data[(uint32_t)ch->sample_position + ch->sample->length]; + } else { + u_right = u_left; + }; + float v_left = 0.f, v_right = 0.f; switch(ch->sample->loop_type) { - case jar_xm_NO_LOOP: - if(JAR_XM_LINEAR_INTERPOLATION) { - v = (b < ch->sample->length) ? ch->sample->data[b] : .0f; - } + if(mod->linear_interpolation) { + v_left = (b < ch->sample->length) ? ch->sample->data[b] : .0f; + if (ch->sample->stereo) { + v_right = (b < ch->sample->length) ? ch->sample->data[b + ch->sample->length] : .0f; + } else { + v_right = v_left; + }; + }; ch->sample_position += ch->step; - if(ch->sample_position >= ch->sample->length) { - ch->sample_position = -1; - } + if(ch->sample_position >= ch->sample->length) { ch->sample_position = -1; } // stop playing this sample break; - case jar_xm_FORWARD_LOOP: - if(JAR_XM_LINEAR_INTERPOLATION) { - v = ch->sample->data[ - (b == ch->sample->loop_end) ? ch->sample->loop_start : b - ]; - } + if(mod->linear_interpolation) { + v_left = ch->sample->data[ (b == ch->sample->loop_end) ? ch->sample->loop_start : b ]; + if (ch->sample->stereo) { + v_right = ch->sample->data[ (b == ch->sample->loop_end) ? ch->sample->loop_start + ch->sample->length : b + ch->sample->length]; + } else { + v_right = v_left; + }; + }; ch->sample_position += ch->step; - while(ch->sample_position >= ch->sample->loop_end) { + if (ch->sample_position >= ch->sample->loop_end) { ch->sample_position -= ch->sample->loop_length; - } + }; + if(ch->sample_position >= ch->sample->length) { + ch->sample_position = ch->sample->loop_start; + }; break; - case jar_xm_PING_PONG_LOOP: if(ch->ping) { + if(mod->linear_interpolation) { + v_left = (b >= ch->sample->loop_end) ? ch->sample->data[(uint32_t)ch->sample_position] : ch->sample->data[b]; + if (ch->sample->stereo) { + v_right = (b >= ch->sample->loop_end) ? ch->sample->data[(uint32_t)ch->sample_position + ch->sample->length] : ch->sample->data[b + ch->sample->length]; + } else { + v_right = v_left; + }; + }; ch->sample_position += ch->step; - } else { - ch->sample_position -= ch->step; - } - /* XXX: this may not work for very tight ping-pong loops - * (ie switches direction more than once per sample */ - if(ch->ping) { - if(JAR_XM_LINEAR_INTERPOLATION) { - v = (b >= ch->sample->loop_end) ? ch->sample->data[a] : ch->sample->data[b]; - } if(ch->sample_position >= ch->sample->loop_end) { ch->ping = false; ch->sample_position = (ch->sample->loop_end << 1) - ch->sample_position; - } - /* sanity checking */ + }; if(ch->sample_position >= ch->sample->length) { ch->ping = false; ch->sample_position -= ch->sample->length - 1; - } + }; } else { - if(JAR_XM_LINEAR_INTERPOLATION) { - v = u; - u = (b == 1 || b - 2 <= ch->sample->loop_start) ? ch->sample->data[a] : ch->sample->data[b - 2]; - } + if(mod->linear_interpolation) { + v_left = u_left; + v_right = u_right; + u_left = (b == 1 || b - 2 <= ch->sample->loop_start) ? ch->sample->data[(uint32_t)ch->sample_position] : ch->sample->data[b - 2]; + if (ch->sample->stereo) { + u_right = (b == 1 || b - 2 <= ch->sample->loop_start) ? ch->sample->data[(uint32_t)ch->sample_position + ch->sample->length] : ch->sample->data[b + ch->sample->length - 2]; + } else { + u_right = u_left; + }; + }; + ch->sample_position -= ch->step; if(ch->sample_position <= ch->sample->loop_start) { ch->ping = true; ch->sample_position = (ch->sample->loop_start << 1) - ch->sample_position; - } - /* sanity checking */ - if(ch->sample_position <= .0f) { + }; + if (ch->sample_position <= .0f) { ch->ping = true; ch->sample_position = .0f; - } - } + }; + }; break; default: - v = .0f; + v_left = .0f; + v_right = .0f; break; - } + }; - float endval = JAR_XM_LINEAR_INTERPOLATION ? jar_xm_LERP(u, v, t) : u; + float endval_left = mod->linear_interpolation ? jar_xm_LERP(u_left, v_left, t) : u_left; + float endval_right = mod->linear_interpolation ? jar_xm_LERP(u_right, v_right, t) : u_right; -#if JAR_XM_RAMPING - if(ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) { - /* Smoothly transition between old and new sample. */ - return jar_xm_LERP(ch->end_of_previous_sample[ch->frame_count], endval, - (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); - } -#endif + if (mod->ramping) { + if(ch->frame_count < jar_xm_SAMPLE_RAMPING_POINTS) { + /* Smoothly transition between old and new sample. */ + if (previous > -1) { + ch->end_of_previous_sample_left[previous] = jar_xm_LERP(ch->end_of_previous_sample_left[ch->frame_count], endval_left, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + ch->end_of_previous_sample_right[previous] = jar_xm_LERP(ch->end_of_previous_sample_right[ch->frame_count], endval_right, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + } else { + ch->curr_left = jar_xm_LERP(ch->end_of_previous_sample_left[ch->frame_count], endval_left, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + ch->curr_right = jar_xm_LERP(ch->end_of_previous_sample_right[ch->frame_count], endval_right, (float)ch->frame_count / (float)jar_xm_SAMPLE_RAMPING_POINTS); + }; + }; + }; - return endval; -} + if (previous > -1) { + ch->end_of_previous_sample_left[previous] = endval_left; + ch->end_of_previous_sample_right[previous] = endval_right; + } else { + ch->curr_left = endval_left; + ch->curr_right = endval_right; + }; +}; + +// 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); -static void jar_xm_sample(jar_xm_context_t* ctx, float* left, float* right) { if(ctx->remaining_samples_in_tick <= 0) { jar_xm_tick(ctx); - } + }; ctx->remaining_samples_in_tick--; - *left = 0.f; *right = 0.f; - - if(ctx->max_loop_count > 0 && ctx->loop_count >= ctx->max_loop_count) { - return; - } + if(ctx->max_loop_count > 0 && ctx->loop_count > ctx->max_loop_count) { return; } for(uint8_t i = 0; i < ctx->module.num_channels; ++i) { jar_xm_channel_context_t* ch = ctx->channels + i; + if(ch->instrument != NULL && ch->sample != NULL && ch->sample_position >= 0) { + jar_xm_next_of_sample(ctx, ch, -1); + if(!ch->muted && !ch->instrument->muted) { + *left += ch->curr_left * ch->actual_volume * (1.f - ch->actual_panning); + *right += ch->curr_right * ch->actual_volume * ch->actual_panning; + }; - if(ch->instrument == NULL || ch->sample == NULL || ch->sample_position < 0) { - continue; - } + if (mod->ramping) { + ch->frame_count++; + jar_xm_SLIDE_TOWARDS(ch->actual_volume, ch->target_volume, ctx->volume_ramp); + jar_xm_SLIDE_TOWARDS(ch->actual_panning, ch->target_panning, ctx->panning_ramp); + }; + }; + }; + if (ctx->global_volume != 1.0f) { + *left *= ctx->global_volume; + *right *= ctx->global_volume; + }; - const float fval = jar_xm_next_of_sample(ch); + // experimental +// float counter = (float)ctx->generated_samples * 0.0001f +// *left = tan(&left + sin(counter)); +// *right = tan(&right + cos(counter)); - if(!ch->muted && !ch->instrument->muted) { - *left += fval * ch->actual_volume * (1.f - ch->actual_panning); - *right += fval * ch->actual_volume * ch->actual_panning; - } - -#if JAR_XM_RAMPING - ch->frame_count++; - jar_xm_SLIDE_TOWARDS(ch->actual_volume, ch->target_volume, ctx->volume_ramp); - jar_xm_SLIDE_TOWARDS(ch->actual_panning, ch->target_panning, ctx->panning_ramp); -#endif - } - - const float fgvol = ctx->global_volume * ctx->amplification; - *left *= fgvol; - *right *= fgvol; - -#if JAR_XM_DEBUG - if(fabs(*left) > 1 || fabs(*right) > 1) { - DEBUG("clipping frame: %f %f, this is a bad module or a libxm bug", *left, *right); - } -#endif -} + // 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;}; +}; void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples) { if(ctx && output) { ctx->generated_samples += numsamples; for(size_t i = 0; i < numsamples; i++) { - jar_xm_sample(ctx, output + (2 * i), output + (2 * i + 1)); - } - } -} + jar_xm_mixdown(ctx, output + (2 * i), output + (2 * i + 1)); + }; + }; +}; -uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx) -{ +uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx) { uint64_t total = 0; uint8_t currentLoopCount = jar_xm_get_loop_count(ctx); jar_xm_set_max_loop_count(ctx, 0); - - while(jar_xm_get_loop_count(ctx) == currentLoopCount) - { + while(jar_xm_get_loop_count(ctx) == currentLoopCount) { total += ctx->remaining_samples_in_tick; ctx->remaining_samples_in_tick = 0; jar_xm_tick(ctx); } - ctx->loop_count = currentLoopCount; return total; } @@ -2574,7 +2174,6 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx) //-------------------------------------------- //FILE LOADER - TODO - NEEDS TO BE CLEANED UP //-------------------------------------------- - #undef DEBUG #define DEBUG(...) do { \ fprintf(stderr, __VA_ARGS__); \ @@ -2621,11 +2220,11 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const return 4; } - char* data = malloc(size + 1); + char* data = JARXM_MALLOC(size + 1); if(!data || fread(data, 1, size, xmf) < size) { fclose(xmf); - DEBUG_ERR(data ? "fread() failed" : "malloc() failed"); - free(data); + DEBUG_ERR(data ? "fread() failed" : "JARXM_MALLOC() failed"); + JARXM_FREE(data); *ctx = NULL; return 5; } @@ -2633,33 +2232,243 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const fclose(xmf); ret = jar_xm_create_context_safe(ctx, data, size, rate); - free(data); + JARXM_FREE(data); switch(ret) { case 0: break; - - case 1: - DEBUG("could not create context: module is not sane\n"); + case 1: DEBUG("could not create context: module is not sane\n"); *ctx = NULL; return 1; break; - - case 2: - FATAL("could not create context: malloc failed\n"); + case 2: FATAL("could not create context: malloc failed\n"); return 2; break; - - default: - FATAL("could not create context: unknown error\n"); + default: FATAL("could not create context: unknown error\n"); return 6; break; - } return 0; } +// not part of the original library +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->bpm = ctx->default_bpm; // reset to file default value + ctx->global_volume = ctx->default_global_volume; // reset to file default value +} + + +void jar_xm_flip_linear_interpolation(jar_xm_context_t* ctx) { + if (ctx->module.linear_interpolation) { + ctx->module.linear_interpolation = 0; + } else { + ctx->module.linear_interpolation = 1; + } +} + +void jar_xm_table_jump(jar_xm_context_t* ctx, int table_ptr) { + for (uint16_t i = 0; i < jar_xm_get_number_of_channels(ctx); i++) { + jar_xm_cut_note(&ctx->channels[i]); + } + ctx->current_row = 0; + ctx->current_tick = 0; + if(table_ptr > 0 && table_ptr < ctx->module.length) { + ctx->current_table_index = table_ptr; + ctx->module.restart_position = table_ptr; // The reason to jump is to start a new loop or track + } 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->bpm = ctx->default_bpm; // reset to file default value + ctx->global_volume = ctx->default_global_volume; // reset to file default value + }; +} + + +// TRANSLATE NOTE NUMBER INTO USER VALUE (ie. 1 = C-1, 2 = C#1, 3 = D-1 ... ) +const char* xm_note_chr(int number) { + if (number == NOTE_OFF) { + return "=="; + }; + number = number % 12; + switch(number) { + case 1: return "C-"; + case 2: return "C#"; + case 3: return "D-"; + case 4: return "D#"; + case 5: return "E-"; + case 6: return "F-"; + case 7: return "F#"; + case 8: return "G-"; + case 9: return "G#"; + case 10: return "A-"; + case 11: return "A#"; + case 12: return "B-"; + }; + return "??"; +}; + +const char* xm_octave_chr(int number) { + if (number == NOTE_OFF) { + return "="; + }; + + int number2 = number - number % 12; + int result = floor(number2 / 12) + 1; + switch(result) { + case 1: return "1"; + case 2: return "2"; + case 3: return "3"; + case 4: return "4"; + case 5: return "5"; + case 6: return "6"; + case 7: return "7"; + case 8: return "8"; + default: return "?"; /* UNKNOWN */ + }; + +}; + +// TRANSLATE NOTE EFFECT CODE INTO USER VALUE +const char* xm_effect_chr(int fx) { + switch(fx) { + case 0: return "0"; /* ZERO = NO EFFECT */ + case 1: return "1"; /* 1xx: Portamento up */ + case 2: return "2"; /* 2xx: Portamento down */ + case 3: return "3"; /* 3xx: Tone portamento */ + case 4: return "4"; /* 4xy: Vibrato */ + case 5: return "5"; /* 5xy: Tone portamento + Volume slide */ + case 6: return "6"; /* 6xy: Vibrato + Volume slide */ + case 7: return "7"; /* 7xy: Tremolo */ + case 8: return "8"; /* 8xx: Set panning */ + case 9: return "9"; /* 9xx: Sample offset */ + case 0xA: return "A";/* Axy: Volume slide */ + case 0xB: return "B";/* Bxx: Position jump */ + case 0xC: return "C";/* Cxx: Set volume */ + case 0xD: return "D";/* Dxx: Pattern break */ + case 0xE: return "E";/* EXy: Extended command */ + case 0xF: return "F";/* Fxx: Set tempo/BPM */ + case 16: return "G"; /* Gxx: Set global volume */ + case 17: return "H"; /* Hxy: Global volume slide */ + case 21: return "L"; /* Lxx: Set envelope position */ + case 25: return "P"; /* Pxy: Panning slide */ + case 27: return "R"; /* Rxy: Multi retrig note */ + case 29: return "T"; /* Txy: Tremor */ + case 33: return "X"; /* Xxy: Extra stuff */ + default: return "?"; /* UNKNOWN */ + }; +} + +#ifdef JAR_XM_RAYLIB + +#include "raylib.h" // Need RayLib API calls for the DEBUG display + +void jar_xm_debug(jar_xm_context_t *ctx) { + int size=40; + int x = 0, y = 0; + + // DEBUG VARIABLES + y += size; DrawText(TextFormat("CUR TBL = %i", ctx->current_table_index), x, y, size, WHITE); + y += size; DrawText(TextFormat("CUR PAT = %i", ctx->module.pattern_table[ctx->current_table_index]), x, y, size, WHITE); + y += size; DrawText(TextFormat("POS JMP = %d", ctx->position_jump), x, y, size, WHITE); + y += size; DrawText(TextFormat("JMP DST = %i", ctx->jump_dest), x, y, size, WHITE); + y += size; DrawText(TextFormat("PTN BRK = %d", ctx->pattern_break), x, y, size, WHITE); + y += size; DrawText(TextFormat("CUR ROW = %i", ctx->current_row), x, y, size, WHITE); + y += size; DrawText(TextFormat("JMP ROW = %i", ctx->jump_row), x, y, size, WHITE); + y += size; DrawText(TextFormat("ROW LCT = %i", ctx->row_loop_count), x, y, size, WHITE); + 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); + } else { + 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); + DrawText(TextFormat("%02X", ctx->current_row), i * size * 2, y - size, size, YELLOW); + } else { + DrawRectangle(i * size * 2, y, size * 2, size, ORANGE); + }; + DrawText(TextFormat("%02X", ctx->module.pattern_table[i]), i * size * 2, y, size, WHITE); + }; + y += size; + + jar_xm_pattern_t* cur = ctx->module.patterns + ctx->module.pattern_table[ctx->current_table_index]; + + /* DISPLAY CURRENTLY PLAYING PATTERN */ + + x += 2 * size; + for(uint8_t i = 0; i < ctx->module.num_channels; i++) { + DrawRectangle(x, y, 8 * size, size, PURPLE); + DrawText("N", x, y, size, YELLOW); + DrawText("I", x + size * 2, y, size, YELLOW); + DrawText("V", x + size * 4, y, size, YELLOW); + DrawText("FX", x + size * 6, y, size, YELLOW); + x += 9 * 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); + 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); + } else { + 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; + if (s->note > 0) {DrawText(TextFormat("%s%s", xm_note_chr(s->note), xm_octave_chr(s->note) ), x, y, size, WHITE);} else {DrawText("...", x, y, size, GRAY);}; + if (s->instrument > 0) { + DrawText(TextFormat("%02X", s->instrument), x + size * 2, y, size, WHITE); + if (s->volume_column == 0) { + DrawText(TextFormat("%02X", 64), x + size * 4, y, size, YELLOW); + }; + } else { + DrawText("..", x + size * 2, y, size, GRAY); + if (s->volume_column == 0) { + DrawText("..", x + size * 4, y, size, GRAY); + }; + }; + if (s->volume_column > 0) {DrawText(TextFormat("%02X", (s->volume_column - 16)), x + size * 4, y, size, WHITE);}; + if (s->effect_type > 0 || s->effect_param > 0) {DrawText(TextFormat("%s%02X", xm_effect_chr(s->effect_type), s->effect_param), x + size * 6, y, size, WHITE);}; + x += 9 * size; + }; + }; + }; + +} +#endif // RayLib extension + #endif//end of JAR_XM_IMPLEMENTATION //------------------------------------------------------------------------------- diff --git a/raylib/external/m3d.h b/raylib/external/m3d.h new file mode 100644 index 0000000..6abaad1 --- /dev/null +++ b/raylib/external/m3d.h @@ -0,0 +1,6547 @@ +/* + * 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/mini_al.h b/raylib/external/mini_al.h deleted file mode 100644 index d69abe4..0000000 --- a/raylib/external/mini_al.h +++ /dev/null @@ -1,11653 +0,0 @@ -// Audio playback and capture library. Public domain. See "unlicense" statement at the end of this file. -// mini_al - v0.6b - 2018-02-03 -// -// David Reid - davidreidsoftware@gmail.com - -// ABOUT -// ===== -// mini_al is a small library for making it easy to connect to a playback or capture device and send -// or receive data from that device. -// -// mini_al uses an asynchronous API. Every device is created with it's own thread, with audio data -// being delivered to or from the device via a callback. Synchronous APIs are not supported in the -// interest of keeping the library as simple and light-weight as possible. -// -// Supported Backends: -// - WASAPI -// - DirectSound -// - WinMM -// - ALSA -// - OSS -// - OpenSL|ES / Android -// - OpenAL -// - SDL -// - Null (Silence) -// - ... and more in the future. -// - Core Audio (OSX, iOS) -// -// Supported Formats: -// - Unsigned 8-bit PCM -// - Signed 16-bit PCM -// - Signed 24-bit PCM (tightly packed) -// - Signed 32-bit PCM -// - IEEE 32-bit floating point PCM -// -// -// USAGE -// ===== -// mini_al is a single-file library. To use it, do something like the following in one .c file. -// #define MAL_IMPLEMENTATION -// #include "mini_al.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. -// -// The implementation of this library will try #include-ing necessary headers for each backend. If you do not have -// the development packages for any particular backend you can disable it by #define-ing the appropriate MAL_NO_* -// option before the implementation. -// -// -// Building (Windows) -// ------------------ -// The Windows build should compile clean on all modern versions of MSVC without the need to configure any include -// paths nor link to any libraries. The same applies to MinGW/GCC and Clang. -// -// Building (Linux) -// ---------------- -// The Linux build uses ALSA for it's backend so you will need to install the relevant ALSA development packages -// for your preferred distro. It also uses pthreads. Dependencies are dynamically linked at runtime so you do not -// need to link to -lasound nor -lpthread. You will need to link to -ldl. -// -// Building (BSD) -// -------------- -// BSD build uses OSS. Requires linking to -lossaudio on {Open,Net}BSD, but not FreeBSD. -// -// Building (Emscripten) -// --------------------- -// The Emscripten build currently uses SDL 1.2 for it's backend which means specifying "-s USE_SDL=2" is unecessary -// as of this version. However, if in the future there is legitimate benefit or enough demand for SDL 2 to be used -// instead, you will need to specify this when compiling. -// -// -// Playback Example -// ---------------- -// mal_uint32 on_send_samples(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) -// { -// // This callback is set at initialization time and will be called when a playback device needs more -// // data. You need to write as many frames as you can to pSamples (but no more than frameCount) and -// // then return the number of frames you wrote. -// // -// // The user data (pDevice->pUserData) is set by mal_device_init(). -// return (mal_uint32)drwav_read_f32((drwav*)pDevice->pUserData, frameCount * pDevice->channels, (float*)pSamples) / pDevice->channels; -// } -// -// ... -// -// mal_context context; -// if (mal_context_init(NULL, 0, NULL, &context) != MAL_SUCCESS) { -// printf("Failed to initialize context."); -// return -3; -// } -// -// mal_device_config config = mal_device_config_init_playback(mal_format_s16, wav.channels, wav.sampleRate, on_send_frames_to_device); -// -// mal_device device; -// mal_result result = mal_device_init(&context, mal_device_type_playback, NULL, &config, pMyData, &device); -// if (result != MAL_SUCCESS) { -// return -1; -// } -// -// mal_device_start(&device); // The device is sleeping by default so you'll need to start it manually. -// -// ... -// -// mal_device_uninit(&device); // This will stop the device so no need to do that manually. -// -// -// -// NOTES -// ===== -// - This library uses an asynchronous API for delivering and requesting audio data. Each device will have -// it's own worker thread which is managed by the library. -// - If mal_device_init() is called with a device that's not aligned to the platform's natural alignment -// boundary (4 bytes on 32-bit, 8 bytes on 64-bit), it will _not_ be thread-safe. The reason for this -// is that it depends on members of mal_device being correctly aligned for atomic assignments. -// - Sample data is always little-endian and interleaved. For example, mal_format_s16 means signed 16-bit -// integer samples, interleaved. Let me know if you need non-interleaved and I'll look into it. -// -// -// -// BACKEND NUANCES -// =============== -// - The absolute best latency I am able to get on DirectSound is about 10 milliseconds. This seems very -// consistent so I'm suspecting there's some kind of hard coded limit there or something. -// - DirectSound currently supports a maximum of 4 periods. -// - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: -// -// - UWP is only supported when compiling as C++. -// - UWP only supports default playback and capture devices. -// - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): -// -// ... -// -// -// -// -// -// -// OPTIONS -// ======= -// #define these options before including this file. -// -// #define MAL_NO_WASAPI -// Disables the WASAPI backend. -// -// #define MAL_NO_DSOUND -// Disables the DirectSound backend. -// -// #define MAL_NO_WINMM -// Disables the WinMM backend. -// -// #define MAL_NO_ALSA -// Disables the ALSA backend. -// -// #define MAL_NO_OSS -// Disables the OSS backend. -// -// #define MAL_NO_OPENSL -// Disables the OpenSL|ES backend. -// -// #define MAL_NO_OPENAL -// Disables the OpenAL backend. -// -// #define MAL_NO_SDL -// Disables the SDL backend. -// -// #define MAL_NO_NULL -// Disables the null backend. -// -// #define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS -// When a buffer size of 0 is specified when a device is initialized, it will default to a size with -// this number of milliseconds worth of data. Note that some backends may adjust this setting if that -// particular backend has unusual latency characteristics. -// -// #define MAL_DEFAULT_PERIODS -// When a period count of 0 is specified when a device is initialized, it will default to this. - -#ifndef mini_al_h -#define mini_al_h - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4201) // nonstandard extension used: nameless struct/union -#endif - -// Platform/backend detection. -#ifdef _WIN32 - #define MAL_WIN32 - #if (!defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) - #define MAL_WIN32_DESKTOP - #endif -#else - #define MAL_POSIX - #include // Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. - - #define MAL_UNIX - #ifdef __linux__ - #define MAL_LINUX - #endif - #ifdef __APPLE__ - #define MAL_APPLE - #endif - #ifdef __ANDROID__ - #define MAL_ANDROID - #endif - #ifdef __EMSCRIPTEN__ - #define MAL_EMSCRIPTEN - #endif -#endif - -// Some backends are only supported on certain platforms. -#if defined(MAL_WIN32) - #define MAL_SUPPORT_WASAPI - #if defined(MAL_WIN32_DESKTOP) // DirectSound and WinMM backends are only supported on desktop's. - #define MAL_SUPPORT_DSOUND - #define MAL_SUPPORT_WINMM - #endif - - // Don't support WASAPI on older versions of MSVC for now. - #if defined(_MSC_VER) - #if _MSC_VER < 1600 - #if !defined(__audioclient_h__) - #undef MAL_SUPPORT_WASAPI - #endif - #endif - #endif -#endif -#if defined(MAL_UNIX) - #if defined(MAL_LINUX) - #if !defined(MAL_ANDROID) // ALSA is not supported on Android. - #define MAL_SUPPORT_ALSA - #endif - #endif - #if defined(MAL_APPLE) - #define MAL_SUPPORT_COREAUDIO - #endif - #if defined(MAL_ANDROID) - #define MAL_SUPPORT_OPENSL - #endif - #if !defined(MAL_LINUX) && !defined(MAL_APPLE) && !defined(MAL_ANDROID) && !defined(MAL_EMSCRIPTEN) - #define MAL_SUPPORT_OSS - #endif -#endif - -#define MAL_SUPPORT_SDL // All platforms support SDL. - -// Explicitly disable OpenAL and Null backends for Emscripten because they both use a background thread which is not properly supported right now. -#if !defined(MAL_EMSCRIPTEN) -#define MAL_SUPPORT_OPENAL -#define MAL_SUPPORT_NULL // All platforms support the null backend. -#endif - - -#if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI) - #define MAL_ENABLE_WASAPI -#endif -#if !defined(MAL_NO_DSOUND) && defined(MAL_SUPPORT_DSOUND) - #define MAL_ENABLE_DSOUND -#endif -#if !defined(MAL_NO_WINMM) && defined(MAL_SUPPORT_WINMM) - #define MAL_ENABLE_WINMM -#endif -#if !defined(MAL_NO_ALSA) && defined(MAL_SUPPORT_ALSA) - #define MAL_ENABLE_ALSA -#endif -#if !defined(MAL_NO_COREAUDIO) && defined(MAL_SUPPORT_COREAUDIO) - #define MAL_ENABLE_COREAUDIO -#endif -#if !defined(MAL_NO_OSS) && defined(MAL_SUPPORT_OSS) - #define MAL_ENABLE_OSS -#endif -#if !defined(MAL_NO_OPENSL) && defined(MAL_SUPPORT_OPENSL) - #define MAL_ENABLE_OPENSL -#endif -#if !defined(MAL_NO_OPENAL) && defined(MAL_SUPPORT_OPENAL) - #define MAL_ENABLE_OPENAL -#endif -#if !defined(MAL_NO_SDL) && defined(MAL_SUPPORT_SDL) - #define MAL_ENABLE_SDL -#endif -#if !defined(MAL_NO_NULL) && defined(MAL_SUPPORT_NULL) - #define MAL_ENABLE_NULL -#endif - - -#if defined(_MSC_VER) && _MSC_VER < 1600 -typedef signed char mal_int8; -typedef unsigned char mal_uint8; -typedef signed short mal_int16; -typedef unsigned short mal_uint16; -typedef signed int mal_int32; -typedef unsigned int mal_uint32; -typedef signed __int64 mal_int64; -typedef unsigned __int64 mal_uint64; -#else -#include -typedef int8_t mal_int8; -typedef uint8_t mal_uint8; -typedef int16_t mal_int16; -typedef uint16_t mal_uint16; -typedef int32_t mal_int32; -typedef uint32_t mal_uint32; -typedef int64_t mal_int64; -typedef uint64_t mal_uint64; -#endif -typedef mal_uint8 mal_bool8; -typedef mal_uint32 mal_bool32; -#define MAL_TRUE 1 -#define MAL_FALSE 0 - -typedef void* mal_handle; -typedef void* mal_ptr; -typedef void (* mal_proc)(); - -typedef struct mal_context mal_context; -typedef struct mal_device mal_device; - -typedef struct -{ - mal_context* pContext; - - union - { -#ifdef MAL_WIN32 - struct - { - /*HANDLE*/ mal_handle hThread; - } win32; -#endif -#ifdef MAL_POSIX - struct - { - pthread_t thread; - } posix; -#endif - - int _unused; - }; -} mal_thread; - -typedef struct -{ - mal_context* pContext; - - union - { -#ifdef MAL_WIN32 - struct - { - /*HANDLE*/ mal_handle hMutex; - } win32; -#endif -#ifdef MAL_POSIX - struct - { - pthread_mutex_t mutex; - } posix; -#endif - - int _unused; - }; -} mal_mutex; - -typedef struct -{ - mal_context* pContext; - - union - { -#ifdef MAL_WIN32 - struct - { - /*HANDLE*/ mal_handle hEvent; - } win32; -#endif -#ifdef MAL_POSIX - struct - { - pthread_mutex_t mutex; - pthread_cond_t condition; - mal_uint32 value; - } posix; -#endif - - int _unused; - }; -} mal_event; - -#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) -typedef mal_uint16 wchar_t; -#endif - -// Define NULL for some compilers. -#ifndef NULL -#define NULL 0 -#endif - -#define MAL_MAX_PERIODS_DSOUND 4 -#define MAL_MAX_PERIODS_OPENAL 4 - -typedef mal_uint8 mal_channel; -#define MAL_CHANNEL_NONE 0 -#define MAL_CHANNEL_FRONT_LEFT 1 -#define MAL_CHANNEL_FRONT_RIGHT 2 -#define MAL_CHANNEL_FRONT_CENTER 3 -#define MAL_CHANNEL_LFE 4 -#define MAL_CHANNEL_BACK_LEFT 5 -#define MAL_CHANNEL_BACK_RIGHT 6 -#define MAL_CHANNEL_FRONT_LEFT_CENTER 7 -#define MAL_CHANNEL_FRONT_RIGHT_CENTER 8 -#define MAL_CHANNEL_BACK_CENTER 9 -#define MAL_CHANNEL_SIDE_LEFT 10 -#define MAL_CHANNEL_SIDE_RIGHT 11 -#define MAL_CHANNEL_TOP_CENTER 12 -#define MAL_CHANNEL_TOP_FRONT_LEFT 13 -#define MAL_CHANNEL_TOP_FRONT_CENTER 14 -#define MAL_CHANNEL_TOP_FRONT_RIGHT 15 -#define MAL_CHANNEL_TOP_BACK_LEFT 16 -#define MAL_CHANNEL_TOP_BACK_CENTER 17 -#define MAL_CHANNEL_TOP_BACK_RIGHT 18 -#define MAL_CHANNEL_MONO MAL_CHANNEL_FRONT_CENTER -#define MAL_MAX_CHANNELS 18 - -#define MAL_MAX_SAMPLE_SIZE_IN_BYTES 8 - -typedef int mal_result; -#define MAL_SUCCESS 0 -#define MAL_ERROR -1 // A generic error. -#define MAL_INVALID_ARGS -2 -#define MAL_OUT_OF_MEMORY -3 -#define MAL_FORMAT_NOT_SUPPORTED -4 -#define MAL_NO_BACKEND -5 -#define MAL_NO_DEVICE -6 -#define MAL_API_NOT_FOUND -7 -#define MAL_DEVICE_BUSY -8 -#define MAL_DEVICE_NOT_INITIALIZED -9 -#define MAL_DEVICE_ALREADY_STARTED -10 -#define MAL_DEVICE_ALREADY_STARTING -11 -#define MAL_DEVICE_ALREADY_STOPPED -12 -#define MAL_DEVICE_ALREADY_STOPPING -13 -#define MAL_FAILED_TO_MAP_DEVICE_BUFFER -14 -#define MAL_FAILED_TO_INIT_BACKEND -15 -#define MAL_FAILED_TO_READ_DATA_FROM_CLIENT -16 -#define MAL_FAILED_TO_READ_DATA_FROM_DEVICE -17 -#define MAL_FAILED_TO_SEND_DATA_TO_CLIENT -18 -#define MAL_FAILED_TO_SEND_DATA_TO_DEVICE -19 -#define MAL_FAILED_TO_OPEN_BACKEND_DEVICE -20 -#define MAL_FAILED_TO_START_BACKEND_DEVICE -21 -#define MAL_FAILED_TO_STOP_BACKEND_DEVICE -22 -#define MAL_FAILED_TO_CREATE_MUTEX -23 -#define MAL_FAILED_TO_CREATE_EVENT -24 -#define MAL_FAILED_TO_CREATE_THREAD -25 -#define MAL_INVALID_DEVICE_CONFIG -26 -#define MAL_ACCESS_DENIED -27 -#define MAL_DSOUND_FAILED_TO_CREATE_DEVICE -1024 -#define MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL -1025 -#define MAL_DSOUND_FAILED_TO_CREATE_BUFFER -1026 -#define MAL_DSOUND_FAILED_TO_QUERY_INTERFACE -1027 -#define MAL_DSOUND_FAILED_TO_SET_NOTIFICATIONS -1028 -#define MAL_ALSA_FAILED_TO_OPEN_DEVICE -2048 -#define MAL_ALSA_FAILED_TO_SET_HW_PARAMS -2049 -#define MAL_ALSA_FAILED_TO_SET_SW_PARAMS -2050 -#define MAL_ALSA_FAILED_TO_PREPARE_DEVICE -2051 -#define MAL_ALSA_FAILED_TO_RECOVER_DEVICE -2052 -#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR -3072 -#define MAL_WASAPI_FAILED_TO_CREATE_DEVICE -3073 -#define MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE -3074 -#define MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE -3075 -#define MAL_WASAPI_FAILED_TO_FIND_BEST_FORMAT -3076 -#define MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER -3077 -#define MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER -3078 -#define MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS -4096 -#define MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS -4097 - -typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message); -typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples); -typedef mal_uint32 (* mal_send_proc)(mal_device* pDevice, mal_uint32 frameCount, void* pSamples); -typedef void (* mal_stop_proc)(mal_device* pDevice); - -typedef enum -{ - mal_backend_null, - mal_backend_wasapi, - mal_backend_dsound, - mal_backend_winmm, - mal_backend_alsa, - mal_backend_oss, - mal_backend_opensl, - mal_backend_openal, - mal_backend_sdl -} mal_backend; - -typedef enum -{ - mal_device_type_playback, - mal_device_type_capture -} mal_device_type; - -typedef enum -{ - // I like to keep these explicitly defined because they're used as a key into a lookup table. When items are - // added to this, make sure there are no gaps and that they're added to the lookup table in mal_get_sample_size_in_bytes(). - mal_format_unknown = 0, // Mainly used for indicating an error. - mal_format_u8 = 1, - mal_format_s16 = 2, // Seems to be the most widely supported format. - mal_format_s24 = 3, // Tightly packed. 3 bytes per sample. - mal_format_s32 = 4, - mal_format_f32 = 5, -} mal_format; - -typedef enum -{ - mal_channel_mix_mode_basic, // Drop excess channels; zeroed out extra channels. - mal_channel_mix_mode_blend, // Blend channels based on locality. -} mal_channel_mix_mode; - -typedef union -{ -#ifdef MAL_SUPPORT_WASAPI - wchar_t wasapi[64]; // WASAPI uses a wchar_t string for identification. -#endif -#ifdef MAL_SUPPORT_DSOUND - mal_uint8 dsound[16]; // DirectSound uses a GUID for identification. -#endif -#ifdef MAL_SUPPORT_WINMM - /*UINT_PTR*/ mal_uint32 winmm; // When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. -#endif -#ifdef MAL_SUPPORT_ALSA - char alsa[256]; // ALSA uses a name string for identification. -#endif -#ifdef MAL_SUPPORT_COREAUDIO - // TODO: Implement me. -#endif -#ifdef MAL_SUPPORT_OSS - char oss[64]; // "dev/dsp0", etc. "dev/dsp" for the default device. -#endif -#ifdef MAL_SUPPORT_OPENSL - mal_uint32 opensl; // OpenSL|ES uses a 32-bit unsigned integer for identification. -#endif -#ifdef MAL_SUPPORT_OPENAL - char openal[256]; // OpenAL seems to use human-readable device names as the ID. -#endif -#ifdef MAL_SUPPORT_SDL - int sdl; // SDL devices are identified with an index. -#endif -#ifdef MAL_SUPPORT_NULL - int nullbackend; // Always 0. -#endif -} mal_device_id; - -typedef struct -{ - mal_device_id id; - char name[256]; -} mal_device_info; - -typedef struct -{ - mal_int64 counter; -} mal_timer; - - -typedef struct mal_src mal_src; -typedef mal_uint32 (* mal_src_read_proc)(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. - -typedef enum -{ - mal_src_algorithm_none, - mal_src_algorithm_linear -} mal_src_algorithm; - -#define MAL_SRC_CACHE_SIZE_IN_FRAMES 512 -typedef struct -{ - mal_src* pSRC; - float pCachedFrames[MAL_MAX_CHANNELS * MAL_SRC_CACHE_SIZE_IN_FRAMES]; - mal_uint32 cachedFrameCount; - mal_uint32 iNextFrame; -} mal_src_cache; - -typedef struct -{ - mal_uint32 sampleRateIn; - mal_uint32 sampleRateOut; - mal_format formatIn; - mal_format formatOut; - mal_uint32 channels; - mal_src_algorithm algorithm; - mal_uint32 cacheSizeInFrames; // The number of frames to read from the client at a time. -} mal_src_config; - -struct mal_src -{ - mal_src_config config; - mal_src_read_proc onRead; - void* pUserData; - float bin[256]; - mal_src_cache cache; // <-- For simplifying and optimizing client -> memory reading. - - union - { - struct - { - float alpha; - mal_bool32 isPrevFramesLoaded : 1; - mal_bool32 isNextFramesLoaded : 1; - } linear; - }; -}; - -typedef struct mal_dsp mal_dsp; -typedef mal_uint32 (* mal_dsp_read_proc)(mal_dsp* pDSP, mal_uint32 frameCount, void* pSamplesOut, void* pUserData); - -typedef struct -{ - mal_format formatIn; - mal_uint32 channelsIn; - mal_uint32 sampleRateIn; - mal_channel channelMapIn[MAL_MAX_CHANNELS]; - mal_format formatOut; - mal_uint32 channelsOut; - mal_uint32 sampleRateOut; - mal_channel channelMapOut[MAL_MAX_CHANNELS]; - mal_uint32 cacheSizeInFrames; // Applications should set this to 0 for now. -} mal_dsp_config; - -struct mal_dsp -{ - mal_dsp_config config; - mal_dsp_read_proc onRead; - void* pUserDataForOnRead; - mal_src src; // For sample rate conversion. - mal_channel channelMapInPostMix[MAL_MAX_CHANNELS]; // <-- When mixing, new channels may need to be created. This represents the channel map after mixing. - mal_channel channelShuffleTable[MAL_MAX_CHANNELS]; - mal_bool32 isChannelMappingRequired : 1; - mal_bool32 isSRCRequired : 1; - mal_bool32 isPassthrough : 1; // <-- Will be set to true when the DSP pipeline is an optimized passthrough. -}; - - -typedef struct -{ - mal_format format; - mal_uint32 channels; - mal_uint32 sampleRate; - mal_channel channelMap[MAL_MAX_CHANNELS]; - mal_uint32 bufferSizeInFrames; - mal_uint32 periods; - mal_bool32 preferExclusiveMode; - mal_recv_proc onRecvCallback; - mal_send_proc onSendCallback; - mal_stop_proc onStopCallback; - - struct - { - mal_bool32 noMMap; // Disables MMap mode. - } alsa; -} mal_device_config; - -typedef struct -{ - mal_log_proc onLog; - - struct - { - mal_bool32 useVerboseDeviceEnumeration; - mal_bool32 excludeNullDevice; - } alsa; -} mal_context_config; - -struct mal_context -{ - mal_backend backend; // DirectSound, ALSA, etc. - mal_context_config config; - - union - { -#ifdef MAL_SUPPORT_WASAPI - struct - { - int _unused; - } wasapi; -#endif -#ifdef MAL_SUPPORT_DSOUND - struct - { - /*HMODULE*/ mal_handle hDSoundDLL; - } dsound; -#endif -#ifdef MAL_SUPPORT_WINMM - struct - { - /*HMODULE*/ mal_handle hWinMM; - mal_proc waveOutGetNumDevs; - mal_proc waveOutGetDevCapsA; - mal_proc waveOutOpen; - mal_proc waveOutClose; - mal_proc waveOutPrepareHeader; - mal_proc waveOutUnprepareHeader; - mal_proc waveOutWrite; - mal_proc waveOutReset; - mal_proc waveInGetNumDevs; - mal_proc waveInGetDevCapsA; - mal_proc waveInOpen; - mal_proc waveInClose; - mal_proc waveInPrepareHeader; - mal_proc waveInUnprepareHeader; - mal_proc waveInAddBuffer; - mal_proc waveInStart; - mal_proc waveInReset; - } winmm; -#endif -#ifdef MAL_SUPPORT_ALSA - struct - { - mal_handle asoundSO; - mal_proc snd_pcm_open; - mal_proc snd_pcm_close; - mal_proc snd_pcm_hw_params_sizeof; - mal_proc snd_pcm_hw_params_any; - mal_proc snd_pcm_hw_params_set_format; - mal_proc snd_pcm_hw_params_set_format_first; - mal_proc snd_pcm_hw_params_get_format_mask; - mal_proc snd_pcm_hw_params_set_channels_near; - mal_proc snd_pcm_hw_params_set_rate_resample; - mal_proc snd_pcm_hw_params_set_rate_near; - mal_proc snd_pcm_hw_params_set_buffer_size_near; - mal_proc snd_pcm_hw_params_set_periods_near; - mal_proc snd_pcm_hw_params_set_access; - mal_proc snd_pcm_hw_params_get_format; - mal_proc snd_pcm_hw_params_get_channels; - mal_proc snd_pcm_hw_params_get_rate; - mal_proc snd_pcm_hw_params_get_buffer_size; - mal_proc snd_pcm_hw_params_get_periods; - mal_proc snd_pcm_hw_params_get_access; - mal_proc snd_pcm_hw_params; - mal_proc snd_pcm_sw_params_sizeof; - mal_proc snd_pcm_sw_params_current; - mal_proc snd_pcm_sw_params_set_avail_min; - mal_proc snd_pcm_sw_params_set_start_threshold; - mal_proc snd_pcm_sw_params; - mal_proc snd_pcm_format_mask_sizeof; - mal_proc snd_pcm_format_mask_test; - mal_proc snd_pcm_get_chmap; - mal_proc snd_pcm_prepare; - mal_proc snd_pcm_start; - mal_proc snd_pcm_drop; - mal_proc snd_device_name_hint; - mal_proc snd_device_name_get_hint; - mal_proc snd_card_get_index; - mal_proc snd_device_name_free_hint; - mal_proc snd_pcm_mmap_begin; - mal_proc snd_pcm_mmap_commit; - mal_proc snd_pcm_recover; - mal_proc snd_pcm_readi; - mal_proc snd_pcm_writei; - mal_proc snd_pcm_avail; - mal_proc snd_pcm_avail_update; - mal_proc snd_pcm_wait; - mal_proc snd_pcm_info; - mal_proc snd_pcm_info_sizeof; - mal_proc snd_pcm_info_get_name; - } alsa; -#endif -#ifdef MAL_SUPPORT_COREAUDIO - struct - { - int _unused; - } coreaudio; -#endif -#ifdef MAL_SUPPORT_OSS - struct - { - int versionMajor; - int versionMinor; - } oss; -#endif -#ifdef MAL_SUPPORT_OPENSL - struct - { - int _unused; - } opensl; -#endif -#ifdef MAL_SUPPORT_OPENAL - struct - { - /*HMODULE*/ mal_handle hOpenAL; // OpenAL32.dll, etc. - mal_proc alcCreateContext; - mal_proc alcMakeContextCurrent; - mal_proc alcProcessContext; - mal_proc alcSuspendContext; - mal_proc alcDestroyContext; - mal_proc alcGetCurrentContext; - mal_proc alcGetContextsDevice; - mal_proc alcOpenDevice; - mal_proc alcCloseDevice; - mal_proc alcGetError; - mal_proc alcIsExtensionPresent; - mal_proc alcGetProcAddress; - mal_proc alcGetEnumValue; - mal_proc alcGetString; - mal_proc alcGetIntegerv; - mal_proc alcCaptureOpenDevice; - mal_proc alcCaptureCloseDevice; - mal_proc alcCaptureStart; - mal_proc alcCaptureStop; - mal_proc alcCaptureSamples; - - mal_proc alEnable; - mal_proc alDisable; - mal_proc alIsEnabled; - mal_proc alGetString; - mal_proc alGetBooleanv; - mal_proc alGetIntegerv; - mal_proc alGetFloatv; - mal_proc alGetDoublev; - mal_proc alGetBoolean; - mal_proc alGetInteger; - mal_proc alGetFloat; - mal_proc alGetDouble; - mal_proc alGetError; - mal_proc alIsExtensionPresent; - mal_proc alGetProcAddress; - mal_proc alGetEnumValue; - mal_proc alGenSources; - mal_proc alDeleteSources; - mal_proc alIsSource; - mal_proc alSourcef; - mal_proc alSource3f; - mal_proc alSourcefv; - mal_proc alSourcei; - mal_proc alSource3i; - mal_proc alSourceiv; - mal_proc alGetSourcef; - mal_proc alGetSource3f; - mal_proc alGetSourcefv; - mal_proc alGetSourcei; - mal_proc alGetSource3i; - mal_proc alGetSourceiv; - mal_proc alSourcePlayv; - mal_proc alSourceStopv; - mal_proc alSourceRewindv; - mal_proc alSourcePausev; - mal_proc alSourcePlay; - mal_proc alSourceStop; - mal_proc alSourceRewind; - mal_proc alSourcePause; - mal_proc alSourceQueueBuffers; - mal_proc alSourceUnqueueBuffers; - mal_proc alGenBuffers; - mal_proc alDeleteBuffers; - mal_proc alIsBuffer; - mal_proc alBufferData; - mal_proc alBufferf; - mal_proc alBuffer3f; - mal_proc alBufferfv; - mal_proc alBufferi; - mal_proc alBuffer3i; - mal_proc alBufferiv; - mal_proc alGetBufferf; - mal_proc alGetBuffer3f; - mal_proc alGetBufferfv; - mal_proc alGetBufferi; - mal_proc alGetBuffer3i; - mal_proc alGetBufferiv; - - mal_bool32 isEnumerationSupported : 1; - mal_bool32 isFloat32Supported : 1; - mal_bool32 isMCFormatsSupported : 1; - } openal; -#endif -#ifdef MAL_SUPPORT_SDL - struct - { - mal_handle hSDL; // SDL - mal_proc SDL_InitSubSystem; - mal_proc SDL_QuitSubSystem; - mal_proc SDL_CloseAudio; - mal_proc SDL_OpenAudio; - mal_proc SDL_PauseAudio; - mal_proc SDL_GetNumAudioDevices; - mal_proc SDL_GetAudioDeviceName; - mal_proc SDL_CloseAudioDevice; - mal_proc SDL_OpenAudioDevice; - mal_proc SDL_PauseAudioDevice; - - mal_bool32 usingSDL1; - } sdl; -#endif -#ifdef MAL_SUPPORT_NULL - struct - { - int _unused; - } null_backend; -#endif - }; - - union - { -#ifdef MAL_WIN32 - struct - { - /*HMODULE*/ mal_handle hOle32DLL; - mal_proc CoInitializeEx; - mal_proc CoUninitialize; - mal_proc CoCreateInstance; - mal_proc CoTaskMemFree; - mal_proc PropVariantClear; - - /*HMODULE*/ mal_handle hUser32DLL; - mal_proc GetForegroundWindow; - mal_proc GetDesktopWindow; - } win32; -#endif -#ifdef MAL_POSIX - struct - { - mal_handle pthreadSO; - mal_proc pthread_create; - mal_proc pthread_join; - mal_proc pthread_mutex_init; - mal_proc pthread_mutex_destroy; - mal_proc pthread_mutex_lock; - mal_proc pthread_mutex_unlock; - mal_proc pthread_cond_init; - mal_proc pthread_cond_destroy; - mal_proc pthread_cond_wait; - mal_proc pthread_cond_signal; - } posix; -#endif - int _unused; - }; -}; - -struct mal_device -{ - mal_context* pContext; - mal_device_type type; - mal_format format; - mal_uint32 channels; - mal_uint32 sampleRate; - mal_uint8 channelMap[MAL_MAX_CHANNELS]; - mal_uint32 bufferSizeInFrames; - mal_uint32 periods; - mal_uint32 state; - mal_recv_proc onRecv; - mal_send_proc onSend; - mal_stop_proc onStop; - void* pUserData; // Application defined data. - char name[256]; - mal_mutex lock; - mal_event wakeupEvent; - mal_event startEvent; - mal_event stopEvent; - mal_thread thread; - mal_result workResult; // This is set by the worker thread after it's finished doing a job. - mal_bool32 usingDefaultBufferSize : 1; - mal_bool32 usingDefaultPeriods : 1; - mal_bool32 exclusiveMode : 1; - mal_format internalFormat; - mal_uint32 internalChannels; - mal_uint32 internalSampleRate; - mal_uint8 internalChannelMap[MAL_MAX_CHANNELS]; - mal_dsp dsp; // Samples run through this to convert samples to a format suitable for use by the backend. - mal_uint32 _dspFrameCount; // Internal use only. Used when running the device -> DSP -> client pipeline. See mal_device__on_read_from_device(). - const mal_uint8* _dspFrames; // ^^^ AS ABOVE ^^^ - - union - { -#ifdef MAL_SUPPORT_WASAPI - struct - { - /*IAudioClient**/ mal_ptr pAudioClient; - /*IAudioRenderClient**/ mal_ptr pRenderClient; - /*IAudioCaptureClient**/ mal_ptr pCaptureClient; - /*HANDLE*/ mal_handle hEvent; - /*HANDLE*/ mal_handle hStopEvent; - mal_bool32 breakFromMainLoop; - } wasapi; -#endif -#ifdef MAL_SUPPORT_DSOUND - struct - { - /*HMODULE*/ mal_handle hDSoundDLL; - /*LPDIRECTSOUND*/ mal_ptr pPlayback; - /*LPDIRECTSOUNDBUFFER*/ mal_ptr pPlaybackPrimaryBuffer; - /*LPDIRECTSOUNDBUFFER*/ mal_ptr pPlaybackBuffer; - /*LPDIRECTSOUNDCAPTURE*/ mal_ptr pCapture; - /*LPDIRECTSOUNDCAPTUREBUFFER*/ mal_ptr pCaptureBuffer; - /*LPDIRECTSOUNDNOTIFY*/ mal_ptr pNotify; - /*HANDLE*/ mal_handle pNotifyEvents[MAL_MAX_PERIODS_DSOUND]; // One event handle for each period. - /*HANDLE*/ mal_handle hStopEvent; - mal_uint32 lastProcessedFrame; // This is circular. - mal_bool32 breakFromMainLoop; - } dsound; -#endif -#ifdef MAL_SUPPORT_WINMM - struct - { - /*HWAVEOUT, HWAVEIN*/ mal_handle hDevice; - /*HANDLE*/ mal_handle hEvent; - mal_uint32 fragmentSizeInFrames; - mal_uint32 fragmentSizeInBytes; - mal_uint32 iNextHeader; // [0,periods). Used as an index into pWAVEHDR. - /*WAVEHDR**/ mal_uint8* pWAVEHDR; // One instantiation for each period. - mal_uint8* pIntermediaryBuffer; - mal_uint8* _pHeapData; // Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. - mal_bool32 breakFromMainLoop; - } winmm; -#endif -#ifdef MAL_SUPPORT_ALSA - struct - { - /*snd_pcm_t**/ mal_ptr pPCM; - mal_bool32 isUsingMMap : 1; - mal_bool32 breakFromMainLoop : 1; - void* pIntermediaryBuffer; - } alsa; -#endif -#ifdef MAL_SUPPORT_COREAUDIO - struct - { - int _unused; - } coreaudio; -#endif -#ifdef MAL_SUPPORT_OSS - struct - { - int fd; - mal_uint32 fragmentSizeInFrames; - mal_bool32 breakFromMainLoop; - void* pIntermediaryBuffer; - } oss; -#endif -#ifdef MAL_SUPPORT_OPENSL - struct - { - /*SLObjectItf*/ mal_ptr pOutputMixObj; - /*SLOutputMixItf*/ mal_ptr pOutputMix; - /*SLObjectItf*/ mal_ptr pAudioPlayerObj; - /*SLPlayItf*/ mal_ptr pAudioPlayer; - /*SLObjectItf*/ mal_ptr pAudioRecorderObj; - /*SLRecordItf*/ mal_ptr pAudioRecorder; - /*SLAndroidSimpleBufferQueueItf*/ mal_ptr pBufferQueue; - mal_uint32 periodSizeInFrames; - mal_uint32 currentBufferIndex; - mal_uint8* pBuffer; // This is malloc()'d and is used for storing audio data. Typed as mal_uint8 for easy offsetting. - } opensl; -#endif -#ifdef MAL_SUPPORT_OPENAL - struct - { - /*ALCcontext**/ mal_ptr pContextALC; - /*ALCdevice**/ mal_ptr pDeviceALC; - /*ALuint*/ mal_uint32 sourceAL; - /*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL]; - /*ALenum*/ mal_uint32 formatAL; - mal_uint32 subBufferSizeInFrames; // This is the size of each of the OpenAL buffers (buffersAL). - mal_uint8* pIntermediaryBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting. - mal_uint32 iNextBuffer; // The next buffer to unenqueue and then re-enqueue as new data is read. - mal_bool32 breakFromMainLoop; - } openal; -#endif -#ifdef MAL_SUPPORT_SDL - struct - { - mal_uint32 deviceID; - } sdl; -#endif -#ifdef MAL_SUPPORT_NULL - struct - { - mal_timer timer; - mal_uint32 lastProcessedFrame; // This is circular. - mal_bool32 breakFromMainLoop; - mal_uint8* pBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting. - } null_device; -#endif - }; -}; -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - -// Initializes a context. -// -// The context is used for selecting and initializing the relevant backends. -// -// Note that the location of the device cannot change throughout it's lifetime. Consider allocating -// the mal_context object with malloc() if this is an issue. The reason for this is that a pointer -// to the context is stored in the mal_device structure. -// -// is used to allow the application to prioritize backends depending on it's specific -// requirements. This can be null in which case it uses the default priority, which is as follows: -// - WASAPI -// - DirectSound -// - WinMM -// - ALSA -// - OSS -// - OpenSL|ES -// - OpenAL -// - SDL -// - Null -// -// The onLog callback is used for posting log messages back to the client for diagnostics, debugging, -// etc. You can pass NULL for this if you do not need it. -// -// Return Value: -// MAL_SUCCESS if successful; any other error code otherwise. -// -// Thread Safety: UNSAFE -// -// Effeciency: LOW -// This will dynamically load backends DLLs/SOs (such as dsound.dll). -mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, const mal_context_config* pConfig, mal_context* pContext); - -// Uninitializes a context. -// -// Results are undefined if you call this while any device created by this context is still active. -// -// Return Value: -// MAL_SUCCESS if successful; any other error code otherwise. -// -// Thread Safety: UNSAFE -// -// Efficiency: LOW -// This will unload the backend DLLs/SOs. -mal_result mal_context_uninit(mal_context* pContext); - -// Enumerates over each device of the given type (playback or capture). -// -// It is _not_ safe to assume the first enumerated device is the default device. -// -// Some backends and platforms may only support default playback and capture devices. -// -// Return Value: -// MAL_SUCCESS if successful; any other error code otherwise. -// -// Thread Safety: SAFE, SEE NOTES. -// This API uses an application-defined buffer for output. This is thread-safe so long as the -// application ensures mutal exclusion to the output buffer at their level. -// -// Efficiency: LOW -mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo); - -// Initializes a device. -// -// The device ID (pDeviceID) can be null, in which case the default device is used. Otherwise, you -// can retrieve the ID by calling mal_enumerate_devices() and using the ID from the returned data. -// Set pDeviceID to NULL to use the default device. Do _not_ rely on the first device ID returned -// by mal_enumerate_devices() to be the default device. -// -// This will try it's hardest to create a valid device, even if it means adjusting input arguments. -// Look at pDevice->internalChannels, pDevice->internalSampleRate, etc. to determine the actual -// properties after initialization. -// -// If is 0, it will default to MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS. If -// is set to 0 it will default to MAL_DEFAULT_PERIODS. -// -// The property controls how frequently the background thread is woken to check for more -// data. It's tied to the buffer size, so as an example, if your buffer size is equivalent to 10 -// milliseconds and you have 2 periods, the CPU will wake up approximately every 5 milliseconds. -// -// Use mal_device_config_init(), mal_device_config_init_playback(), etc. to initialize a -// mal_device_config object. -// -// When compiling for UWP you must ensure you call this function on the main UI thread because the -// operating system may need to present the user with a message asking for permissions. Please refer -// to the official documentation for ActivateAudioInterfaceAsync() for more information. -// -// Return Value: -// MAL_SUCCESS if successful; any other error code otherwise. -// -// Thread Safety: UNSAFE -// It is not safe to call this function simultaneously for different devices because some backends -// depend on and mutate global state (such as OpenSL|ES). The same applies to calling this as the -// same time as mal_device_uninit(). -// -// Results are undefined if you try using a device before this function has returned. -// -// Efficiency: LOW -// This is just slow due to the nature of it being an initialization API. -mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, void* pUserData, mal_device* pDevice); - -// Uninitializes a device. -// -// This will explicitly stop the device. You do not need to call mal_device_stop() beforehand, but it's -// harmless if you do. -// -// Return Value: -// MAL_SUCCESS if successful; any other error code otherwise. -// -// Thread Safety: UNSAFE -// As soon as this API is called the device should be considered undefined. All bets are off if you -// try using the device at the same time as uninitializing it. -// -// Efficiency: LOW -// This will stop the device with mal_device_stop() which is a slow, synchronized call. It also needs -// to destroy internal objects like the backend-specific objects and the background thread. -void mal_device_uninit(mal_device* pDevice); - -// Sets the callback to use when the application has received data from the device. -// -// Thread Safety: SAFE -// This API is implemented as a simple atomic assignment. -// -// Efficiency: HIGH -// This is just an atomic assignment. -void mal_device_set_recv_callback(mal_device* pDevice, mal_recv_proc proc); - -// Sets the callback to use when the application needs to send data to the device for playback. -// -// Note that the implementation of this callback must copy over as many samples as is available. The -// return value specifies how many samples were written to the output buffer. The backend will fill -// any leftover samples with silence. -// -// Thread Safety: SAFE -// This API is implemented as a simple atomic assignment. -// -// Efficiency: HIGH -// This is just an atomic assignment. -void mal_device_set_send_callback(mal_device* pDevice, mal_send_proc proc); - -// Sets the callback to use when the device has stopped, either explicitly or as a result of an error. -// -// Thread Safety: SAFE -// This API is implemented as a simple atomic assignment. -// -// Efficiency: HIGH -// This is just an atomic assignment. -void mal_device_set_stop_callback(mal_device* pDevice, mal_stop_proc proc); - -// Activates the device. For playback devices this begins playback. For capture devices it begins -// recording. -// -// For a playback device, this will retrieve an initial chunk of audio data from the client before -// returning. The reason for this is to ensure there is valid audio data in the buffer, which needs -// to be done _before_ the device begins playback. -// -// Return Value: -// - MAL_SUCCESS if successful; any other error code otherwise. -// - MAL_INVALID_ARGS -// One or more of the input arguments is invalid. -// - MAL_DEVICE_NOT_INITIALIZED -// The device is not currently or was never initialized. -// - MAL_DEVICE_BUSY -// The device is in the process of stopping. This will only happen if mal_device_start() and -// mal_device_stop() is called simultaneous on separate threads. This will never be returned in -// single-threaded applications. -// - MAL_DEVICE_ALREADY_STARTING -// The device is already in the process of starting. This will never be returned in single-threaded -// applications. -// - MAL_DEVICE_ALREADY_STARTED -// The device is already started. -// - MAL_FAILED_TO_READ_DATA_FROM_CLIENT -// Failed to read the initial chunk of audio data from the client. This initial chunk of data is -// required so that the device has valid audio data as soon as it starts playing. This will never -// be returned for capture devices. -// - MAL_FAILED_TO_START_BACKEND_DEVICE -// There was a backend-specific error starting the device. -// -// Thread Safety: SAFE -// -// Efficiency: LOW -// This API waits until the backend device has been started for real by the worker thread. It also -// waits on a mutex for thread-safety. -mal_result mal_device_start(mal_device* pDevice); - -// Puts the device to sleep, but does not uninitialize it. Use mal_device_start() to start it up again. -// -// Return Value: -// - MAL_SUCCESS if successful; any other error code otherwise. -// - MAL_INVALID_ARGS -// One or more of the input arguments is invalid. -// - MAL_DEVICE_NOT_INITIALIZED -// The device is not currently or was never initialized. -// - MAL_DEVICE_BUSY -// The device is in the process of starting. This will only happen if mal_device_start() and -// mal_device_stop() is called simultaneous on separate threads. This will never be returned in -// single-threaded applications. -// - MAL_DEVICE_ALREADY_STOPPING -// The device is already in the process of stopping. This will never be returned in single-threaded -// applications. -// - MAL_DEVICE_ALREADY_STOPPED -// The device is already stopped. -// - MAL_FAILED_TO_STOP_BACKEND_DEVICE -// There was a backend-specific error stopping the device. -// -// Thread Safety: SAFE -// -// Efficiency: LOW -// This API needs to wait on the worker thread to stop the backend device properly before returning. It -// also waits on a mutex for thread-safety. -// -// In addition, some backends need to wait for the device to finish playback/recording of the current -// fragment which can take some time (usually proportionate to the buffer size used when initializing -// the device). -mal_result mal_device_stop(mal_device* pDevice); - -// Determines whether or not the device is started. -// -// Return Value: -// True if the device is started, false otherwise. -// -// Thread Safety: SAFE -// If another thread calls mal_device_start() or mal_device_stop() at this same time as this function -// is called, there's a very small chance the return value will be out of sync. -// -// Efficiency: HIGH -// This is implemented with a simple accessor. -mal_bool32 mal_device_is_started(mal_device* pDevice); - -// Retrieves the size of the buffer in bytes for the given device. -// -// Thread Safety: SAFE -// This is calculated from constant values which are set at initialization time and never change. -// -// Efficiency: HIGH -// This is implemented with just a few 32-bit integer multiplications. -mal_uint32 mal_device_get_buffer_size_in_bytes(mal_device* pDevice); - -// Retrieves the size of a sample in bytes for the given format. -// -// Thread Safety: SAFE -// This is API is pure. -// -// Efficiency: HIGH -// This is implemented with a lookup table. -mal_uint32 mal_get_sample_size_in_bytes(mal_format format); - -// Helper function for initializing a mal_context_config object. -mal_context_config mal_context_config_init(mal_log_proc onLog); - -// Helper function for initializing a mal_device_config object. -// -// This is just a helper API, and as such the returned object can be safely modified as needed. -// -// The default channel mapping is based on the channel count, as per the table below. Note that these -// can be freely changed after this function returns if you are needing something in particular. -// -// |---------------|------------------------------| -// | Channel Count | Mapping | -// |---------------|------------------------------| -// | 1 (Mono) | 0: MAL_CHANNEL_FRONT_CENTER | -// |---------------|------------------------------| -// | 2 (Stereo) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// |---------------|------------------------------| -// | 3 (2.1) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// | | 2: MAL_CHANNEL_LFE | -// |---------------|------------------------------| -// | 4 (Quad) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// | | 2: MAL_CHANNEL_BACK_LEFT | -// | | 3: MAL_CHANNEL_BACK_RIGHT | -// |---------------|------------------------------| -// | 5 (4.1) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// | | 2: MAL_CHANNEL_BACK_LEFT | -// | | 3: MAL_CHANNEL_BACK_RIGHT | -// | | 4: MAL_CHANNEL_LFE | -// |---------------|------------------------------| -// | 6 (5.1) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// | | 2: MAL_CHANNEL_FRONT_CENTER | -// | | 3: MAL_CHANNEL_LFE | -// | | 4: MAL_CHANNEL_BACK_LEFT | -// | | 5: MAL_CHANNEL_BACK_RIGHT | -// |---------------|------------------------------| -// | 8 (7.1) | 0: MAL_CHANNEL_FRONT_LEFT | -// | | 1: MAL_CHANNEL_FRONT_RIGHT | -// | | 2: MAL_CHANNEL_FRONT_CENTER | -// | | 3: MAL_CHANNEL_LFE | -// | | 4: MAL_CHANNEL_BACK_LEFT | -// | | 5: MAL_CHANNEL_BACK_RIGHT | -// | | 6: MAL_CHANNEL_SIDE_LEFT | -// | | 7: MAL_CHANNEL_SIDE_RIGHT | -// |---------------|------------------------------| -// | Other | All channels set to 0. This | -// | | is equivalent to the same | -// | | mapping as the device. | -// |---------------|------------------------------| -// -// Thread Safety: SAFE -// -// Efficiency: HIGH -// This just returns a stack allocated object and consists of just a few assignments. -mal_device_config mal_device_config_init(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback, mal_send_proc onSendCallback); - -// A simplified version of mal_device_config_init() for capture devices. -static inline mal_device_config mal_device_config_init_capture(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback) { return mal_device_config_init(format, channels, sampleRate, onRecvCallback, NULL); } - -// A simplified version of mal_device_config_init() for playback devices. -static inline mal_device_config mal_device_config_init_playback(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_send_proc onSendCallback) { return mal_device_config_init(format, channels, sampleRate, NULL, onSendCallback); } - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// SRC -// -/////////////////////////////////////////////////////////////////////////////// - -// Initializes a sample rate conversion object. -mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC); - -// Dynamically adjusts the output sample rate. -// -// This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this -// is not acceptable you will need to use your own algorithm. -mal_result mal_src_set_output_sample_rate(mal_src* pSRC, mal_uint32 sampleRateOut); - -// Reads a number of frames. -// -// Returns the number of frames actually read. -mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut); - -// The same mal_src_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. -// -// Internally there exists a buffer that keeps track of the previous and next samples for sample rate conversion. The simple -// version of this function does _not_ flush this buffer because otherwise it causes glitches for streaming based conversion -// pipelines. The problem, however, is that sometimes you need those last few samples (such as if you're doing a bulk conversion -// of a static file). Enabling flushing will fix this for you. -mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// DSP -// -/////////////////////////////////////////////////////////////////////////////// - -// Initializes a DSP object. -mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP); - -// Dynamically adjusts the output sample rate. -// -// This is useful for dynamically adjust pitch. Keep in mind, however, that this will speed up or slow down the sound. If this -// is not acceptable you will need to use your own algorithm. -mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut); - -// Reads a number of frames and runs them through the DSP processor. -// -// This this _not_ flush the internal buffers which means you may end up with a few less frames than you may expect. Look at -// mal_dsp_read_frames_ex() if you want to flush the buffers at the end of the read. -mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut); - -// The same mal_dsp_read_frames() with extra control over whether or not the internal buffers should be flushed at the end. -// -// See documentation for mal_src_read_frames_ex() for an explanation on flushing. -mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); - -// High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to -// determine the required size of the output buffer. -// -// A return value of 0 indicates an error. -// -// This function is useful for one-off bulk conversions, but if you're streaming data you should use the DSP APIs instead. -mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut, const void* pIn, mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_uint32 frameCountIn); - -// Helper for initializing a mal_dsp_config object. -mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Utiltities -// -/////////////////////////////////////////////////////////////////////////////// - -// Creates a mutex. -// -// A mutex must be created from a valid context. A mutex is initially unlocked. -mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex); - -// Deletes a mutex. -void mal_mutex_uninit(mal_mutex* pMutex); - -// Locks a mutex with an infinite timeout. -void mal_mutex_lock(mal_mutex* pMutex); - -// Unlocks a mutex. -void mal_mutex_unlock(mal_mutex* pMutex); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Miscellaneous Helpers -// -/////////////////////////////////////////////////////////////////////////////// - -// Retrieves a friendly name for a backend. -const char* mal_get_backend_name(mal_backend backend); - -// Retrieves a friendly name for a format. -const char* mal_get_format_name(mal_format format); - -// Blends two frames in floating point format. -void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels); - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Format Conversion -// -/////////////////////////////////////////////////////////////////////////////// -void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count); -void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count); -void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count); -void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count); -void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_format formatIn, unsigned int sampleCount); - -#ifdef __cplusplus -} -#endif -#endif //mini_al_h - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_IMPLEMENTATION -#include - -#ifdef MAL_WIN32 -#include -#else -#include // For malloc()/free() -#include // For memset() -#endif - -#if defined(MAL_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) -#include // For mach_absolute_time() -#endif - -#ifdef MAL_POSIX -#include -#include -#endif - -#if !defined(MAL_64BIT) && !defined(MAL_32BIT) -#ifdef _WIN32 -#ifdef _WIN64 -#define MAL_64BIT -#else -#define MAL_32BIT -#endif -#endif -#endif - -#if !defined(MAL_64BIT) && !defined(MAL_32BIT) -#ifdef __GNUC__ -#ifdef __LP64__ -#define MAL_64BIT -#else -#define MAL_32BIT -#endif -#endif -#endif - -#if !defined(MAL_64BIT) && !defined(MAL_32BIT) -#include -#if INTPTR_MAX == INT64_MAX -#define MAL_64BIT -#else -#define MAL_32BIT -#endif -#endif - - -// Disable run-time linking on certain backends. -#ifndef MAL_NO_RUNTIME_LINKING - #if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN) - #define MAL_NO_RUNTIME_LINKING - #endif -#endif - -// Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not -// certain unused functions and variables can be excluded from the build to avoid warnings. -#ifdef MAL_ENABLE_WASAPI - #define MAL_HAS_WASAPI - #ifdef __has_include - #if !__has_include() - #undef MAL_HAS_WASAPI - #endif - #endif -#endif -#ifdef MAL_ENABLE_DSOUND - #define MAL_HAS_DSOUND - #ifdef __has_include - #if !__has_include() - #undef MAL_HAS_DSOUND - #endif - #endif -#endif -#ifdef MAL_ENABLE_WINMM - #define MAL_HAS_WINMM // Every compiler I'm aware of supports WinMM. -#endif -#ifdef MAL_ENABLE_ALSA - #define MAL_HAS_ALSA - #ifdef __has_include - #if !__has_include() - #undef MAL_HAS_ALSA - #endif - #endif -#endif -#ifdef MAL_ENABLE_COREAUDIO - #define MAL_HAS_COREAUDIO -#endif -#ifdef MAL_ENABLE_OSS - #define MAL_HAS_OSS // OSS is the only supported backend for Unix and BSD, so it must be present else this library is useless. -#endif -#ifdef MAL_ENABLE_OPENSL - #define MAL_HAS_OPENSL // Like OSS, OpenSL is the only supported backend for Android. It must be present. -#endif -#ifdef MAL_ENABLE_OPENAL - #define MAL_HAS_OPENAL - #ifdef MAL_NO_RUNTIME_LINKING - #ifdef __has_include - #if !__has_include() - #undef MAL_HAS_OPENAL - #endif - #endif - #endif -#endif -#ifdef MAL_ENABLE_SDL - #define MAL_HAS_SDL - - // SDL headers are necessary if using compile-time linking. - #ifdef MAL_NO_RUNTIME_LINKING - #ifdef __has_include - #ifdef MAL_EMSCRIPTEN - #if !__has_include() - #undef MAL_HAS_SDL - #endif - #else - #if !__has_include() - #undef MAL_HAS_SDL - #endif - #endif - #endif - #endif -#endif -#ifdef MAL_ENABLE_NULL - #define MAL_HAS_NULL // Everything supports the null backend. -#endif - - -#ifdef MAL_WIN32 - #define MAL_THREADCALL WINAPI - typedef unsigned long mal_thread_result; -#else - #define MAL_THREADCALL - typedef void* mal_thread_result; -#endif -typedef mal_thread_result (MAL_THREADCALL * mal_thread_entry_proc)(void* pData); - -#ifdef MAL_WIN32 -typedef HRESULT (WINAPI * MAL_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); -typedef void (WINAPI * MAL_PFN_CoUninitialize)(); -typedef HRESULT (WINAPI * MAL_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); -typedef void (WINAPI * MAL_PFN_CoTaskMemFree)(LPVOID pv); -typedef HRESULT (WINAPI * MAL_PFN_PropVariantClear)(PROPVARIANT *pvar); - -typedef HWND (WINAPI * MAL_PFN_GetForegroundWindow)(); -typedef HWND (WINAPI * MAL_PFN_GetDesktopWindow)(); -#endif - - -#define MAL_STATE_UNINITIALIZED 0 -#define MAL_STATE_STOPPED 1 // The device's default state after initialization. -#define MAL_STATE_STARTED 2 // The worker thread is in it's main loop waiting for the driver to request or deliver audio data. -#define MAL_STATE_STARTING 3 // Transitioning from a stopped state to started. -#define MAL_STATE_STOPPING 4 // Transitioning from a started state to stopped. - - -// The default size of the device's buffer in milliseconds. -// -// If this is too small you may get underruns and overruns in which case you'll need to either increase -// this value or use an explicit buffer size. -#ifndef MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS -#define MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS 25 -#endif - -// Default periods when none is specified in mal_device_init(). More periods means more work on the CPU. -#ifndef MAL_DEFAULT_PERIODS -#define MAL_DEFAULT_PERIODS 2 -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// -// Standard Library Stuff -// -/////////////////////////////////////////////////////////////////////////////// -#ifndef mal_zero_memory -#ifdef MAL_WIN32 -#define mal_zero_memory(p, sz) ZeroMemory((p), (sz)) -#else -#define mal_zero_memory(p, sz) memset((p), 0, (sz)) -#endif -#endif - -#define mal_zero_object(p) mal_zero_memory((p), sizeof(*(p))) - -#ifndef mal_copy_memory -#ifdef MAL_WIN32 -#define mal_copy_memory(dst, src, sz) CopyMemory((dst), (src), (sz)) -#else -#define mal_copy_memory(dst, src, sz) memcpy((dst), (src), (sz)) -#endif -#endif - -#ifndef mal_malloc -#ifdef MAL_WIN32 -#define mal_malloc(sz) HeapAlloc(GetProcessHeap(), 0, (sz)) -#else -#define mal_malloc(sz) malloc((sz)) -#endif -#endif - -#ifndef mal_realloc -#ifdef MAL_WIN32 -#define mal_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 mal_realloc(p, sz) realloc((p), (sz)) -#endif -#endif - -#ifndef mal_free -#ifdef MAL_WIN32 -#define mal_free(p) HeapFree(GetProcessHeap(), 0, (p)) -#else -#define mal_free(p) free((p)) -#endif -#endif - -#ifndef mal_assert -#ifdef MAL_WIN32 -#define mal_assert(condition) assert(condition) -#else -#define mal_assert(condition) assert(condition) -#endif -#endif - -#define mal_countof(x) (sizeof(x) / sizeof(x[0])) -#define mal_max(x, y) (((x) > (y)) ? (x) : (y)) -#define mal_min(x, y) (((x) < (y)) ? (x) : (y)) - -#define mal_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / mal_get_sample_size_in_bytes(format) / (channels)) - -// Some of these string utility functions are unused on some platforms. -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4505) -#elif defined(__GNUC__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-function" -#endif -// Return Values: -// 0: Success -// 22: EINVAL -// 34: ERANGE -// -// Not using symbolic constants for errors because I want to avoid #including errno.h -static int mal_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - size_t i; - for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (i < dstSizeInBytes) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return 34; -} - -static int mal_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) -{ - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - size_t maxcount = count; - if (count == ((size_t)-1) || count >= dstSizeInBytes) { // -1 = _TRUNCATE - maxcount = dstSizeInBytes - 1; - } - - size_t i; - for (i = 0; i < maxcount && src[i] != '\0'; ++i) { - dst[i] = src[i]; - } - - if (src[i] == '\0' || i == count || count == ((size_t)-1)) { - dst[i] = '\0'; - return 0; - } - - dst[0] = '\0'; - return 34; -} - -static int mal_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) -{ - if (dst == 0) { - return 22; - } - if (dstSizeInBytes == 0) { - return 34; - } - if (src == 0) { - dst[0] = '\0'; - return 22; - } - - char* dstorig = dst; - - while (dstSizeInBytes > 0 && dst[0] != '\0') { - dst += 1; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - return 22; // Unterminated. - } - - - while (dstSizeInBytes > 0 && src[0] != '\0') { - *dst++ = *src++; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes > 0) { - dst[0] = '\0'; - } else { - dstorig[0] = '\0'; - return 34; - } - - return 0; -} - -static int mal_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) -{ - if (dst == NULL || dstSizeInBytes == 0) { - return 22; - } - if (radix < 2 || radix > 36) { - dst[0] = '\0'; - return 22; - } - - int sign = (value < 0 && radix == 10) ? -1 : 1; // The negative sign is only used when the base is 10. - - unsigned int valueU; - if (value < 0) { - valueU = -value; - } else { - valueU = value; - } - - char* dstEnd = dst; - do - { - int remainder = valueU % radix; - if (remainder > 9) { - *dstEnd = (char)((remainder - 10) + 'a'); - } else { - *dstEnd = (char)(remainder + '0'); - } - - dstEnd += 1; - dstSizeInBytes -= 1; - valueU /= radix; - } while (dstSizeInBytes > 0 && valueU > 0); - - if (dstSizeInBytes == 0) { - dst[0] = '\0'; - return 22; // Ran out of room in the output buffer. - } - - if (sign < 0) { - *dstEnd++ = '-'; - dstSizeInBytes -= 1; - } - - if (dstSizeInBytes == 0) { - dst[0] = '\0'; - return 22; // Ran out of room in the output buffer. - } - - *dstEnd = '\0'; - - - // At this point the string will be reversed. - dstEnd -= 1; - while (dst < dstEnd) { - char temp = *dst; - *dst = *dstEnd; - *dstEnd = temp; - - dst += 1; - dstEnd -= 1; - } - - return 0; -} - -static int mal_strcmp(const char* str1, const char* str2) -{ - if (str1 == str2) return 0; - - // These checks differ from the standard implementation. It's not important, but I prefer - // it just for sanity. - if (str1 == NULL) return -1; - if (str2 == NULL) return 1; - - for (;;) { - if (str1[0] == '\0') { - break; - } - if (str1[0] != str2[0]) { - break; - } - - str1 += 1; - str2 += 1; - } - - return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; -} -#if defined(_MSC_VER) - #pragma warning(pop) -#elif defined(__GNUC__) - #pragma GCC diagnostic pop -#endif - - -// Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 -static inline unsigned int mal_next_power_of_2(unsigned int x) -{ - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - - return x; -} - -static inline unsigned int mal_prev_power_of_2(unsigned int x) -{ - return mal_next_power_of_2(x) >> 1; -} - -static inline unsigned int mal_round_to_power_of_2(unsigned int x) -{ - unsigned int prev = mal_prev_power_of_2(x); - unsigned int next = mal_next_power_of_2(x); - if ((next - x) > (x - prev)) { - return prev; - } else { - return next; - } -} - - - -// Clamps an f32 sample to -1..1 -static inline float mal_clip_f32(float x) -{ - if (x < -1) return -1; - if (x > +1) return +1; - return x; -} - -static inline float mal_mix_f32(float x, float y, float a) -{ - return x*(1-a) + y*a; -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Atomics -// -/////////////////////////////////////////////////////////////////////////////// -#if defined(_WIN32) && !defined(__GNUC__) -#define mal_memory_barrier() MemoryBarrier() -#define mal_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b) -#define mal_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b) -#define mal_atomic_increment_32(a) InterlockedIncrement((LONG*)a) -#define mal_atomic_decrement_32(a) InterlockedDecrement((LONG*)a) -#else -#define mal_memory_barrier() __sync_synchronize() -#define mal_atomic_exchange_32(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() -#define mal_atomic_exchange_64(a, b) (void)__sync_lock_test_and_set(a, b); __sync_synchronize() -#define mal_atomic_increment_32(a) __sync_add_and_fetch(a, 1) -#define mal_atomic_decrement_32(a) __sync_sub_and_fetch(a, 1) -#endif - -#ifdef MAL_64BIT -#define mal_atomic_exchange_ptr mal_atomic_exchange_64 -#endif -#ifdef MAL_32BIT -#define mal_atomic_exchange_ptr mal_atomic_exchange_32 -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// -// Timing -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_WIN32 -static LARGE_INTEGER g_mal_TimerFrequency = {{0}}; -void mal_timer_init(mal_timer* pTimer) -{ - if (g_mal_TimerFrequency.QuadPart == 0) { - QueryPerformanceFrequency(&g_mal_TimerFrequency); - } - - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - pTimer->counter = (mal_uint64)counter.QuadPart; -} - -double mal_timer_get_time_in_seconds(mal_timer* pTimer) -{ - LARGE_INTEGER counter; - if (!QueryPerformanceCounter(&counter)) { - return 0; - } - - return (counter.QuadPart - pTimer->counter) / (double)g_mal_TimerFrequency.QuadPart; -} -#elif defined(MAL_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) -static uint64_t g_mal_TimerFrequency = 0; -void mal_timer_init(mal_timer* pTimer) -{ - mach_timebase_info_data_t baseTime; - mach_timebase_info(&baseTime); - g_mal_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer; - - pTimer->counter = mach_absolute_time(); -} - -double mal_timer_get_time_in_seconds(mal_timer* pTimer) -{ - uint64_t newTimeCounter = mach_absolute_time(); - uint64_t oldTimeCounter = pTimer->counter; - - return (newTimeCounter - oldTimeCounter) / g_mal_TimerFrequency; -} -#else -void mal_timer_init(mal_timer* pTimer) -{ - struct timespec newTime; - clock_gettime(CLOCK_MONOTONIC, &newTime); - - pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; -} - -double mal_timer_get_time_in_seconds(mal_timer* pTimer) -{ - struct timespec newTime; - clock_gettime(CLOCK_MONOTONIC, &newTime); - - uint64_t newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; - uint64_t oldTimeCounter = pTimer->counter; - - return (newTimeCounter - oldTimeCounter) / 1000000000.0; -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// -// Dynamic Linking -// -/////////////////////////////////////////////////////////////////////////////// -mal_handle mal_dlopen(const char* filename) -{ -#ifdef _WIN32 -#ifdef MAL_WIN32_DESKTOP - return (mal_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) { - return NULL; - } - - return (mal_handle)LoadPackagedLibrary(filenameW, 0); -#endif -#else - return (mal_handle)dlopen(filename, RTLD_NOW); -#endif -} - -void mal_dlclose(mal_handle handle) -{ -#ifdef _WIN32 - FreeLibrary((HMODULE)handle); -#else - dlclose((void*)handle); -#endif -} - -mal_proc mal_dlsym(mal_handle handle, const char* symbol) -{ -#ifdef _WIN32 - return (mal_proc)GetProcAddress((HMODULE)handle, symbol); -#else - return (mal_proc)dlsym((void*)handle, symbol); -#endif -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Threading -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_WIN32 -mal_result mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) -{ - (void)pContext; - - pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); - if (pThread->win32.hThread == NULL) { - return MAL_FAILED_TO_CREATE_THREAD; - } - - return MAL_SUCCESS; -} - -void mal_thread_wait__win32(mal_thread* pThread) -{ - WaitForSingleObject(pThread->win32.hThread, INFINITE); -} - -void mal_sleep__win32(mal_uint32 milliseconds) -{ - Sleep((DWORD)milliseconds); -} - - -mal_result mal_mutex_init__win32(mal_context* pContext, mal_mutex* pMutex) -{ - (void)pContext; - - pMutex->win32.hMutex = CreateEventA(NULL, FALSE, TRUE, NULL); - if (pMutex->win32.hMutex == NULL) { - return MAL_FAILED_TO_CREATE_MUTEX; - } - - return MAL_SUCCESS; -} - -void mal_mutex_uninit__win32(mal_mutex* pMutex) -{ - CloseHandle(pMutex->win32.hMutex); -} - -void mal_mutex_lock__win32(mal_mutex* pMutex) -{ - WaitForSingleObject(pMutex->win32.hMutex, INFINITE); -} - -void mal_mutex_unlock__win32(mal_mutex* pMutex) -{ - SetEvent(pMutex->win32.hMutex); -} - - -mal_result mal_event_init__win32(mal_context* pContext, mal_event* pEvent) -{ - (void)pContext; - - pEvent->win32.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if (pEvent->win32.hEvent == NULL) { - return MAL_FAILED_TO_CREATE_EVENT; - } - - return MAL_SUCCESS; -} - -void mal_event_uninit__win32(mal_event* pEvent) -{ - CloseHandle(pEvent->win32.hEvent); -} - -mal_bool32 mal_event_wait__win32(mal_event* pEvent) -{ - return WaitForSingleObject(pEvent->win32.hEvent, INFINITE) == WAIT_OBJECT_0; -} - -mal_bool32 mal_event_signal__win32(mal_event* pEvent) -{ - return SetEvent(pEvent->win32.hEvent); -} -#endif - - -#ifdef MAL_POSIX -typedef int (* mal_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -typedef int (* mal_pthread_join_proc)(pthread_t thread, void **retval); -typedef int (* mal_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr); -typedef int (* mal_pthread_mutex_destroy_proc)(pthread_mutex_t *__mutex); -typedef int (* mal_pthread_mutex_lock_proc)(pthread_mutex_t *__mutex); -typedef int (* mal_pthread_mutex_unlock_proc)(pthread_mutex_t *__mutex); -typedef int (* mal_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr); -typedef int (* mal_pthread_cond_destroy_proc)(pthread_cond_t *__cond); -typedef int (* mal_pthread_cond_signal_proc)(pthread_cond_t *__cond); -typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex); - -mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) -{ - int result = ((mal_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, NULL, entryProc, pData); - if (result != 0) { - return MAL_FAILED_TO_CREATE_THREAD; - } - - return MAL_SUCCESS; -} - -void mal_thread_wait__posix(mal_thread* pThread) -{ - ((mal_pthread_join_proc)pThread->pContext->posix.pthread_join)(pThread->posix.thread, NULL); -} - -void mal_sleep__posix(mal_uint32 milliseconds) -{ - usleep(milliseconds * 1000); // <-- usleep is in microseconds. -} - - -mal_result mal_mutex_init__posix(mal_context* pContext, mal_mutex* pMutex) -{ - int result = ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pMutex->posix.mutex, NULL); - if (result != 0) { - return MAL_FAILED_TO_CREATE_MUTEX; - } - - return MAL_SUCCESS; -} - -void mal_mutex_uninit__posix(mal_mutex* pMutex) -{ - ((mal_pthread_mutex_destroy_proc)pMutex->pContext->posix.pthread_mutex_destroy)(&pMutex->posix.mutex); -} - -void mal_mutex_lock__posix(mal_mutex* pMutex) -{ - ((mal_pthread_mutex_lock_proc)pMutex->pContext->posix.pthread_mutex_lock)(&pMutex->posix.mutex); -} - -void mal_mutex_unlock__posix(mal_mutex* pMutex) -{ - ((mal_pthread_mutex_unlock_proc)pMutex->pContext->posix.pthread_mutex_unlock)(&pMutex->posix.mutex); -} - - -mal_result mal_event_init__posix(mal_context* pContext, mal_event* pEvent) -{ - if (((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->posix.mutex, NULL) != 0) { - return MAL_FAILED_TO_CREATE_MUTEX; - } - - if (((mal_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->posix.condition, NULL) != 0) { - return MAL_FAILED_TO_CREATE_EVENT; - } - - pEvent->posix.value = 0; - return MAL_SUCCESS; -} - -void mal_event_uninit__posix(mal_event* pEvent) -{ - ((mal_pthread_cond_destroy_proc)pEvent->pContext->posix.pthread_cond_destroy)(&pEvent->posix.condition); - ((mal_pthread_mutex_destroy_proc)pEvent->pContext->posix.pthread_mutex_destroy)(&pEvent->posix.mutex); -} - -mal_bool32 mal_event_wait__posix(mal_event* pEvent) -{ - ((mal_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); - { - while (pEvent->posix.value == 0) { - ((mal_pthread_cond_wait_proc)pEvent->pContext->posix.pthread_cond_wait)(&pEvent->posix.condition, &pEvent->posix.mutex); - } - - pEvent->posix.value = 0; // Auto-reset. - } - ((mal_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); - - return MAL_TRUE; -} - -mal_bool32 mal_event_signal__posix(mal_event* pEvent) -{ - ((mal_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex); - { - pEvent->posix.value = 1; - ((mal_pthread_cond_signal_proc)pEvent->pContext->posix.pthread_cond_signal)(&pEvent->posix.condition); - } - ((mal_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex); - - return MAL_TRUE; -} -#endif - -mal_result mal_thread_create(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) -{ - if (pContext == NULL || pThread == NULL || entryProc == NULL) return MAL_FALSE; - - pThread->pContext = pContext; - -#ifdef MAL_WIN32 - return mal_thread_create__win32(pContext, pThread, entryProc, pData); -#endif -#ifdef MAL_POSIX - return mal_thread_create__posix(pContext, pThread, entryProc, pData); -#endif -} - -void mal_thread_wait(mal_thread* pThread) -{ - if (pThread == NULL) return; - -#ifdef MAL_WIN32 - mal_thread_wait__win32(pThread); -#endif -#ifdef MAL_POSIX - mal_thread_wait__posix(pThread); -#endif -} - -void mal_sleep(mal_uint32 milliseconds) -{ -#ifdef MAL_WIN32 - mal_sleep__win32(milliseconds); -#endif -#ifdef MAL_POSIX - mal_sleep__posix(milliseconds); -#endif -} - - -mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex) -{ - if (pContext == NULL || pMutex == NULL) return MAL_INVALID_ARGS; - - pMutex->pContext = pContext; - -#ifdef MAL_WIN32 - return mal_mutex_init__win32(pContext, pMutex); -#endif -#ifdef MAL_POSIX - return mal_mutex_init__posix(pContext, pMutex); -#endif -} - -void mal_mutex_uninit(mal_mutex* pMutex) -{ - if (pMutex == NULL || pMutex->pContext == NULL) return; - -#ifdef MAL_WIN32 - mal_mutex_uninit__win32(pMutex); -#endif -#ifdef MAL_POSIX - mal_mutex_uninit__posix(pMutex); -#endif -} - -void mal_mutex_lock(mal_mutex* pMutex) -{ - if (pMutex == NULL || pMutex->pContext == NULL) return; - -#ifdef MAL_WIN32 - mal_mutex_lock__win32(pMutex); -#endif -#ifdef MAL_POSIX - mal_mutex_lock__posix(pMutex); -#endif -} - -void mal_mutex_unlock(mal_mutex* pMutex) -{ - if (pMutex == NULL || pMutex->pContext == NULL) return; - -#ifdef MAL_WIN32 - mal_mutex_unlock__win32(pMutex); -#endif -#ifdef MAL_POSIX - mal_mutex_unlock__posix(pMutex); -#endif -} - - -mal_result mal_event_init(mal_context* pContext, mal_event* pEvent) -{ - if (pContext == NULL || pEvent == NULL) return MAL_FALSE; - - pEvent->pContext = pContext; - -#ifdef MAL_WIN32 - return mal_event_init__win32(pContext, pEvent); -#endif -#ifdef MAL_POSIX - return mal_event_init__posix(pContext, pEvent); -#endif -} - -void mal_event_uninit(mal_event* pEvent) -{ - if (pEvent == NULL || pEvent->pContext == NULL) return; - -#ifdef MAL_WIN32 - mal_event_uninit__win32(pEvent); -#endif -#ifdef MAL_POSIX - mal_event_uninit__posix(pEvent); -#endif -} - -mal_bool32 mal_event_wait(mal_event* pEvent) -{ - if (pEvent == NULL || pEvent->pContext == NULL) return MAL_FALSE; - -#ifdef MAL_WIN32 - return mal_event_wait__win32(pEvent); -#endif -#ifdef MAL_POSIX - return mal_event_wait__posix(pEvent); -#endif -} - -mal_bool32 mal_event_signal(mal_event* pEvent) -{ - if (pEvent == NULL || pEvent->pContext == NULL) return MAL_FALSE; - -#ifdef MAL_WIN32 - return mal_event_signal__win32(pEvent); -#endif -#ifdef MAL_POSIX - return mal_event_signal__posix(pEvent); -#endif -} - - -// Posts a log message. -static void mal_log(mal_context* pContext, mal_device* pDevice, const char* message) -{ - if (pContext == NULL) return; - - mal_log_proc onLog = pContext->config.onLog; - if (onLog) { - onLog(pContext, pDevice, message); - } -} - -// Posts an error. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". -static mal_result mal_context_post_error(mal_context* pContext, mal_device* pDevice, const char* message, mal_result resultCode) -{ - // Derive the context from the device if necessary. - if (pContext == NULL) { - if (pDevice != NULL) { - pContext = pDevice->pContext; - } - } - - mal_log(pContext, pDevice, message); - return resultCode; -} - -static mal_result mal_post_error(mal_device* pDevice, const char* message, mal_result resultCode) -{ - return mal_context_post_error(NULL, pDevice, message, resultCode); -} - - -#if !defined(MAL_ANDROID) -static void mal_get_default_channel_mapping(mal_backend backend, mal_uint32 channels, mal_channel channelMap[MAL_MAX_CHANNELS]) -{ - if (channels == 1) { // Mono - channelMap[0] = MAL_CHANNEL_FRONT_CENTER; - } else if (channels == 2) { // Stereo - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - } else if (channels == 3) { // 2.1 - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_LFE; - } else if (channels == 4) { // 4.0 - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_SIDE_LEFT; - channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; - } else if (channels == 5) { // Not sure about this one. 4.1? - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_SIDE_LEFT; - channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; - channelMap[4] = MAL_CHANNEL_LFE; - } else if (channels >= 6) { // 5.1 - // Some backends use different default layouts. - if (backend == mal_backend_wasapi || backend == mal_backend_dsound || backend == mal_backend_winmm || backend == mal_backend_oss) { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_FRONT_CENTER; - channelMap[3] = MAL_CHANNEL_LFE; - channelMap[4] = MAL_CHANNEL_SIDE_LEFT; - channelMap[5] = MAL_CHANNEL_SIDE_RIGHT; - } else { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - channelMap[2] = MAL_CHANNEL_SIDE_LEFT; - channelMap[3] = MAL_CHANNEL_SIDE_RIGHT; - channelMap[4] = MAL_CHANNEL_FRONT_CENTER; - channelMap[5] = MAL_CHANNEL_LFE; - } - - if (channels == 7) { // Not sure about this one. - channelMap[6] = MAL_CHANNEL_BACK_CENTER; - } else { - // I don't know what mapping to use in this case, but I'm making it upwards compatible with 7.1. Good luck! - mal_assert(channels >= 8); - channelMap[6] = MAL_CHANNEL_BACK_LEFT; - channelMap[7] = MAL_CHANNEL_BACK_RIGHT; - - // Beyond 7.1 I'm just guessing... - if (channels == 9) { - channelMap[8] = MAL_CHANNEL_BACK_CENTER; - } else if (channels == 10) { - channelMap[8] = MAL_CHANNEL_FRONT_LEFT_CENTER; - channelMap[9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; - } else if (channels == 11) { - channelMap[ 8] = MAL_CHANNEL_FRONT_LEFT_CENTER; - channelMap[ 9] = MAL_CHANNEL_FRONT_RIGHT_CENTER; - channelMap[10] = MAL_CHANNEL_BACK_CENTER; - } else { - mal_assert(channels >= 12); - for (mal_uint8 iChannel = 11; iChannel < channels && iChannel < MAL_MAX_CHANNELS; ++iChannel) { - channelMap[iChannel] = iChannel + 1; - } - } - } - } -} -#endif - - -// The callback for reading from the client -> DSP -> device. -static inline mal_uint32 mal_device__on_read_from_client(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - (void)pDSP; - - mal_device* pDevice = (mal_device*)pUserData; - mal_assert(pDevice != NULL); - - mal_send_proc onSend = pDevice->onSend; - if (onSend) { - return onSend(pDevice, frameCount, pFramesOut); - } - - return 0; -} - -// The callback for reading from the device -> DSP -> client. -static inline mal_uint32 mal_device__on_read_from_device(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - (void)pDSP; - - mal_device* pDevice = (mal_device*)pUserData; - mal_assert(pDevice != NULL); - - if (pDevice->_dspFrameCount == 0) { - return 0; // Nothing left. - } - - mal_uint32 framesToRead = frameCount; - if (framesToRead > pDevice->_dspFrameCount) { - framesToRead = pDevice->_dspFrameCount; - } - - mal_uint32 bytesToRead = framesToRead * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - mal_copy_memory(pFramesOut, pDevice->_dspFrames, bytesToRead); - pDevice->_dspFrameCount -= framesToRead; - pDevice->_dspFrames += bytesToRead; - - return framesToRead; -} - -// A helper function for reading sample data from the client. Returns the number of samples read from the client. Remaining samples -// are filled with silence. -static inline mal_uint32 mal_device__read_frames_from_client(mal_device* pDevice, mal_uint32 frameCount, void* pSamples) -{ - mal_assert(pDevice != NULL); - mal_assert(frameCount > 0); - mal_assert(pSamples != NULL); - - mal_uint32 framesRead = mal_dsp_read_frames(&pDevice->dsp, frameCount, pSamples); - mal_uint32 samplesRead = framesRead * pDevice->internalChannels; - mal_uint32 sampleSize = mal_get_sample_size_in_bytes(pDevice->internalFormat); - mal_uint32 consumedBytes = samplesRead*sampleSize; - mal_uint32 remainingBytes = ((frameCount * pDevice->internalChannels) - samplesRead)*sampleSize; - mal_zero_memory((mal_uint8*)pSamples + consumedBytes, remainingBytes); - - return samplesRead; -} - -// A helper for sending sample data to the client. -static inline void mal_device__send_frames_to_client(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples) -{ - mal_assert(pDevice != NULL); - mal_assert(frameCount > 0); - mal_assert(pSamples != NULL); - - mal_recv_proc onRecv = pDevice->onRecv; - if (onRecv) { - pDevice->_dspFrameCount = frameCount; - pDevice->_dspFrames = (const mal_uint8*)pSamples; - - mal_uint8 chunkBuffer[4096]; - mal_uint32 chunkFrameCount = sizeof(chunkBuffer) / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; - - for (;;) { - mal_uint32 framesJustRead = mal_dsp_read_frames(&pDevice->dsp, chunkFrameCount, chunkBuffer); - if (framesJustRead == 0) { - break; - } - - onRecv(pDevice, framesJustRead, chunkBuffer); - - if (framesJustRead < chunkFrameCount) { - break; - } - } - } -} - -// A helper for changing the state of the device. -static inline void mal_device__set_state(mal_device* pDevice, mal_uint32 newState) -{ - mal_atomic_exchange_32(&pDevice->state, newState); -} - -// A helper for getting the state of the device. -static inline mal_uint32 mal_device__get_state(mal_device* pDevice) -{ - return pDevice->state; -} - - -#ifdef MAL_WIN32 - #if defined(MAL_HAS_WASAPI) || defined(MAL_HAS_DSOUND) - static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - //static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - //static GUID MAL_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - #endif -#endif - - -// Generic function for retrieving the name of a device by it's ID. -// -// This function simply enumerates every device and then retrieves the name of the first device that has the same ID. -static mal_result mal_context__try_get_device_name_by_id(mal_context* pContext, mal_device_type type, const mal_device_id* pDeviceID, char* pName, size_t nameBufferSize) -{ - mal_assert(pContext != NULL); - mal_assert(pName != NULL); - - if (pDeviceID == NULL) { - return MAL_NO_DEVICE; - } - - mal_uint32 deviceCount; - mal_result result = mal_enumerate_devices(pContext, type, &deviceCount, NULL); - if (result != MAL_SUCCESS) { - return result; - } - - mal_device_info* pInfos = (mal_device_info*)mal_malloc(sizeof(*pInfos) * deviceCount); - if (pInfos == NULL) { - return MAL_OUT_OF_MEMORY; - } - - result = mal_enumerate_devices(pContext, type, &deviceCount, pInfos); - if (result != MAL_SUCCESS) { - mal_free(pInfos); - return result; - } - - mal_bool32 found = MAL_FALSE; - for (mal_uint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { - // Prefer backend specific comparisons for efficiency and accuracy, but fall back to a generic method if a backend-specific comparison - // is not implemented. - switch (pContext->backend) - { - #ifdef MAL_HAS_WASAPI - case mal_backend_wasapi: - { - if (memcmp(pDeviceID->wasapi, &pInfos[iDevice].id.wasapi, sizeof(pDeviceID->wasapi)) == 0) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_DSOUND - case mal_backend_dsound: - { - if (memcmp(pDeviceID->dsound, &pInfos[iDevice].id.dsound, sizeof(pDeviceID->dsound)) == 0) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_WINMM - case mal_backend_winmm: - { - if (pInfos[iDevice].id.winmm == pDeviceID->winmm) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_ALSA - case mal_backend_alsa: - { - if (mal_strcmp(pInfos[iDevice].id.alsa, pDeviceID->alsa) == 0) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_COREAUDIO - //case mal_backend_coreaudio: - //{ - // // TODO: Implement me. - //} break; - #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - if (mal_strcmp(pInfos[iDevice].id.oss, pDeviceID->oss) == 0) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_OPENSL - case mal_backend_opensl: - { - if (pInfos[iDevice].id.opensl == pDeviceID->opensl) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_OPENAL - case mal_backend_openal: - { - if (mal_strcmp(pInfos[iDevice].id.openal, pDeviceID->openal) == 0) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_SDL - case mal_backend_sdl: - { - if (pInfos[iDevice].id.sdl == pDeviceID->sdl) { - found = MAL_TRUE; - } - } break; - #endif - #ifdef MAL_HAS_NULL - case mal_backend_null: - { - if (pInfos[iDevice].id.nullbackend == pDeviceID->nullbackend) { - found = MAL_TRUE; - } - } break; - #endif - - // Fall back to a generic memory comparison. - default: - { - if (memcmp(pDeviceID, &pInfos[iDevice].id, sizeof(*pDeviceID)) == 0) { - found = MAL_TRUE; - } - } break; - } - - if (found) { - mal_strncpy_s(pName, nameBufferSize, pInfos[iDevice].name, (size_t)-1); - result = MAL_SUCCESS; - break; - } - } - - mal_free(pInfos); - return result; -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// Null Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_NULL -mal_result mal_context_init__null(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - // The null backend always works. - (void)pContext; - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__null(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_null); - - (void)pContext; - return MAL_SUCCESS; -} - -static mal_result mal_enumerate_devices__null(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 1; // There's only one "device" each for playback and recording for the null backend. - - if (pInfo != NULL && infoSize > 0) { - mal_zero_object(pInfo); - - if (type == mal_device_type_playback) { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "NULL Playback Device", (size_t)-1); - } else { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "NULL Capture Device", (size_t)-1); - } - } - - return MAL_SUCCESS; -} - -static void mal_device_uninit__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - mal_free(pDevice->null_device.pBuffer); -} - -static mal_result mal_device_init__null(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - (void)type; - (void)pDeviceID; - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->null_device); - - pDevice->bufferSizeInFrames = pConfig->bufferSizeInFrames; - pDevice->periods = pConfig->periods; - - pDevice->null_device.pBuffer = (mal_uint8*)mal_malloc(pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format)); - if (pDevice->null_device.pBuffer == NULL) { - return MAL_OUT_OF_MEMORY; - } - - mal_zero_memory(pDevice->null_device.pBuffer, mal_device_get_buffer_size_in_bytes(pDevice)); - - return MAL_SUCCESS; -} - -static mal_result mal_device__start_backend__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_timer_init(&pDevice->null_device.timer); - pDevice->null_device.lastProcessedFrame = 0; - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - (void)pDevice; - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->null_device.breakFromMainLoop = MAL_TRUE; - return MAL_SUCCESS; -} - -static mal_bool32 mal_device__get_current_frame__null(mal_device* pDevice, mal_uint32* pCurrentPos) -{ - mal_assert(pDevice != NULL); - mal_assert(pCurrentPos != NULL); - *pCurrentPos = 0; - - mal_uint64 currentFrameAbs = (mal_uint64)(mal_timer_get_time_in_seconds(&pDevice->null_device.timer) * pDevice->sampleRate) / pDevice->channels; - - *pCurrentPos = (mal_uint32)(currentFrameAbs % pDevice->bufferSizeInFrames); - return MAL_TRUE; -} - -static mal_uint32 mal_device__get_available_frames__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_uint32 currentFrame; - if (!mal_device__get_current_frame__null(pDevice, ¤tFrame)) { - return 0; - } - - // In a playback device the last processed frame should always be ahead of the current frame. The space between - // the last processed and current frame (moving forward, starting from the last processed frame) is the amount - // of space available to write. - // - // For a recording device it's the other way around - the last processed frame is always _behind_ the current - // frame and the space between is the available space. - mal_uint32 totalFrameCount = pDevice->bufferSizeInFrames; - if (pDevice->type == mal_device_type_playback) { - mal_uint32 committedBeg = currentFrame; - mal_uint32 committedEnd = pDevice->null_device.lastProcessedFrame; - if (committedEnd <= committedBeg) { - committedEnd += totalFrameCount; // Wrap around. - } - - mal_uint32 committedSize = (committedEnd - committedBeg); - mal_assert(committedSize <= totalFrameCount); - - return totalFrameCount - committedSize; - } else { - mal_uint32 validBeg = pDevice->null_device.lastProcessedFrame; - mal_uint32 validEnd = currentFrame; - if (validEnd < validBeg) { - validEnd += totalFrameCount; // Wrap around. - } - - mal_uint32 validSize = (validEnd - validBeg); - mal_assert(validSize <= totalFrameCount); - - return validSize; - } -} - -static mal_uint32 mal_device__wait_for_frames__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - while (!pDevice->null_device.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__get_available_frames__null(pDevice); - if (framesAvailable > 0) { - return framesAvailable; - } - - mal_sleep(16); - } - - // We'll get here if the loop was terminated. Just return whatever's available. - return mal_device__get_available_frames__null(pDevice); -} - -static mal_result mal_device__main_loop__null(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->null_device.breakFromMainLoop = MAL_FALSE; - while (!pDevice->null_device.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__null(pDevice); - if (framesAvailable == 0) { - continue; - } - - // If it's a playback device, don't bother grabbing more data if the device is being stopped. - if (pDevice->null_device.breakFromMainLoop && pDevice->type == mal_device_type_playback) { - return MAL_FALSE; - } - - if (framesAvailable + pDevice->null_device.lastProcessedFrame > pDevice->bufferSizeInFrames) { - framesAvailable = pDevice->bufferSizeInFrames - pDevice->null_device.lastProcessedFrame; - } - - mal_uint32 sampleCount = framesAvailable * pDevice->channels; - mal_uint32 lockOffset = pDevice->null_device.lastProcessedFrame * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); - mal_uint32 lockSize = sampleCount * mal_get_sample_size_in_bytes(pDevice->format); - - if (pDevice->type == mal_device_type_playback) { - if (pDevice->null_device.breakFromMainLoop) { - return MAL_FALSE; - } - - mal_device__read_frames_from_client(pDevice, framesAvailable, pDevice->null_device.pBuffer + lockOffset); - } else { - mal_zero_memory(pDevice->null_device.pBuffer + lockOffset, lockSize); - mal_device__send_frames_to_client(pDevice, framesAvailable, pDevice->null_device.pBuffer + lockOffset); - } - - pDevice->null_device.lastProcessedFrame = (pDevice->null_device.lastProcessedFrame + framesAvailable) % pDevice->bufferSizeInFrames; - } - - return MAL_SUCCESS; -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// -// WIN32 COMMON -// -/////////////////////////////////////////////////////////////////////////////// -#if defined(MAL_WIN32) -#include "objbase.h" -#if defined(MAL_WIN32_DESKTOP) - #define mal_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MAL_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit) - #define mal_CoUninitialize(pContext) ((MAL_PFN_CoUninitialize)pContext->win32.CoUninitialize)() - #define mal_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MAL_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv) - #define mal_CoTaskMemFree(pContext, pv) ((MAL_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv) - #define mal_PropVariantClear(pContext, pvar) ((MAL_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar) -#else - #define mal_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit) - #define mal_CoUninitialize(pContext) CoUninitialize() - #define mal_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) - #define mal_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv) - #define mal_PropVariantClear(pContext, pvar) PropVariantClear(pvar) -#endif -#endif - -#if defined(MAL_HAS_WASAPI) || defined(MAL_HAS_DSOUND) -#include - -#ifndef SPEAKER_FRONT_LEFT -#define SPEAKER_FRONT_LEFT 0x1 -#define SPEAKER_FRONT_RIGHT 0x2 -#define SPEAKER_FRONT_CENTER 0x4 -#define SPEAKER_LOW_FREQUENCY 0x8 -#define SPEAKER_BACK_LEFT 0x10 -#define SPEAKER_BACK_RIGHT 0x20 -#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 -#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 -#define SPEAKER_BACK_CENTER 0x100 -#define SPEAKER_SIDE_LEFT 0x200 -#define SPEAKER_SIDE_RIGHT 0x400 -#define SPEAKER_TOP_CENTER 0x800 -#define SPEAKER_TOP_FRONT_LEFT 0x1000 -#define SPEAKER_TOP_FRONT_CENTER 0x2000 -#define SPEAKER_TOP_FRONT_RIGHT 0x4000 -#define SPEAKER_TOP_BACK_LEFT 0x8000 -#define SPEAKER_TOP_BACK_CENTER 0x10000 -#define SPEAKER_TOP_BACK_RIGHT 0x20000 -#endif - -// 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_) -typedef struct -{ - WAVEFORMATEX Format; - union - { - WORD wValidBitsPerSample; - WORD wSamplesPerBlock; - WORD wReserved; - } Samples; - DWORD dwChannelMask; - GUID SubFormat; -} WAVEFORMATEXTENSIBLE; -#endif - -#ifndef WAVE_FORMAT_EXTENSIBLE -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif - -// Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to mini_al. -static mal_uint8 mal_channel_id_to_mal__win32(DWORD id) -{ - switch (id) - { - case SPEAKER_FRONT_LEFT: return MAL_CHANNEL_FRONT_LEFT; - case SPEAKER_FRONT_RIGHT: return MAL_CHANNEL_FRONT_RIGHT; - case SPEAKER_FRONT_CENTER: return MAL_CHANNEL_FRONT_CENTER; - case SPEAKER_LOW_FREQUENCY: return MAL_CHANNEL_LFE; - case SPEAKER_BACK_LEFT: return MAL_CHANNEL_BACK_LEFT; - case SPEAKER_BACK_RIGHT: return MAL_CHANNEL_BACK_RIGHT; - case SPEAKER_FRONT_LEFT_OF_CENTER: return MAL_CHANNEL_FRONT_LEFT_CENTER; - case SPEAKER_FRONT_RIGHT_OF_CENTER: return MAL_CHANNEL_FRONT_RIGHT_CENTER; - case SPEAKER_BACK_CENTER: return MAL_CHANNEL_BACK_CENTER; - case SPEAKER_SIDE_LEFT: return MAL_CHANNEL_SIDE_LEFT; - case SPEAKER_SIDE_RIGHT: return MAL_CHANNEL_SIDE_RIGHT; - case SPEAKER_TOP_CENTER: return MAL_CHANNEL_TOP_CENTER; - case SPEAKER_TOP_FRONT_LEFT: return MAL_CHANNEL_TOP_FRONT_LEFT; - case SPEAKER_TOP_FRONT_CENTER: return MAL_CHANNEL_TOP_FRONT_CENTER; - case SPEAKER_TOP_FRONT_RIGHT: return MAL_CHANNEL_TOP_FRONT_RIGHT; - case SPEAKER_TOP_BACK_LEFT: return MAL_CHANNEL_TOP_BACK_LEFT; - case SPEAKER_TOP_BACK_CENTER: return MAL_CHANNEL_TOP_BACK_CENTER; - case SPEAKER_TOP_BACK_RIGHT: return MAL_CHANNEL_TOP_BACK_RIGHT; - default: return 0; - } -} - -// Converts an individual mini_al channel identifier (MAL_CHANNEL_FRONT_LEFT, etc.) to Win32-style. -static DWORD mal_channel_id_to_win32(DWORD id) -{ - switch (id) - { - case MAL_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; - case MAL_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; - case MAL_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; - case MAL_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; - case MAL_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; - case MAL_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; - case MAL_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; - case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER; - case MAL_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; - case MAL_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; - case MAL_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; - case MAL_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; - case MAL_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; - case MAL_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; - case MAL_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; - case MAL_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; - case MAL_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; - case MAL_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; - default: return 0; - } -} - -// Converts a channel mapping to a Win32-style channel mask. -static DWORD mal_channel_map_to_channel_mask__win32(const mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) -{ - DWORD dwChannelMask = 0; - for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { - dwChannelMask |= mal_channel_id_to_win32(channelMap[iChannel]); - } - - return dwChannelMask; -} - -// Converts a Win32-style channel mask to a mini_al channel map. -static void mal_channel_mask_to_channel_map__win32(DWORD dwChannelMask, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - if (channels == 1 && dwChannelMask == 0) { - channelMap[0] = MAL_CHANNEL_FRONT_CENTER; - } else if (channels == 2 && dwChannelMask == 0) { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - } else { - // Just iterate over each bit. - mal_uint32 iChannel = 0; - for (mal_uint32 iBit = 0; iBit < 32; ++iBit) { - DWORD bitValue = (dwChannelMask & (1 << iBit)); - if (bitValue != 0) { - // The bit is set. - channelMap[iChannel] = mal_channel_id_to_mal__win32(bitValue); - iChannel += 1; - } - } - } -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// -// WASAPI Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_WASAPI -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:4091) // 'typedef ': ignored on left of '' when no variable is declared -#endif -#include -#include -#include -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - -const PROPERTYKEY g_malPKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}}, 14}; -const PROPERTYKEY g_malPKEY_AudioEngine_DeviceFormat = {{0xf19f064d, 0x82c, 0x4e27, {0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c}}, 0}; - -const IID g_malCLSID_MMDeviceEnumerator_Instance = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; // BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) -const IID g_malIID_IMMDeviceEnumerator_Instance = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; // A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) -const IID g_malIID_IAudioClient_Instance = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; // 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) -const IID g_malIID_IAudioRenderClient_Instance = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; // F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) -const IID g_malIID_IAudioCaptureClient_Instance = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; // C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) - -#ifndef MAL_WIN32_DESKTOP -const IID g_malIID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; // E6327CAD-DCEC-4949-AE8A-991E976A79D2 -const IID g_malIID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; // 2EEF81BE-33FA-4800-9670-1CD474972C3F -#endif - -#ifdef __cplusplus -#define g_malCLSID_MMDeviceEnumerator g_malCLSID_MMDeviceEnumerator_Instance -#define g_malIID_IMMDeviceEnumerator g_malIID_IMMDeviceEnumerator_Instance -#define g_malIID_IAudioClient g_malIID_IAudioClient_Instance -#define g_malIID_IAudioRenderClient g_malIID_IAudioRenderClient_Instance -#define g_malIID_IAudioCaptureClient g_malIID_IAudioCaptureClient_Instance -#else -#define g_malCLSID_MMDeviceEnumerator &g_malCLSID_MMDeviceEnumerator_Instance -#define g_malIID_IMMDeviceEnumerator &g_malIID_IMMDeviceEnumerator_Instance -#define g_malIID_IAudioClient &g_malIID_IAudioClient_Instance -#define g_malIID_IAudioRenderClient &g_malIID_IAudioRenderClient_Instance -#define g_malIID_IAudioCaptureClient &g_malIID_IAudioCaptureClient_Instance -#endif - -#ifdef __cplusplus -#define mal_is_guid_equal(a, b) IsEqualGUID(a, b) -#else -#define mal_is_guid_equal(a, b) IsEqualGUID(&a, &b) -#endif - -#ifdef MAL_WIN32_DESKTOP - // IMMDeviceEnumerator - #ifdef __cplusplus - #define IMMDeviceEnumerator_Release(p) ((IMMDeviceEnumerator*)p)->Release() - #else - #define IMMDeviceEnumerator_Release(p) ((IMMDeviceEnumerator*)p)->lpVtbl->Release((IMMDeviceEnumerator*)p) - #endif - #ifdef __cplusplus - #define IMMDeviceEnumerator_EnumAudioEndpoints(p, a, b, c) ((IMMDeviceEnumerator*)p)->EnumAudioEndpoints(a, b, c) - #else - #define IMMDeviceEnumerator_EnumAudioEndpoints(p, a, b, c) ((IMMDeviceEnumerator*)p)->lpVtbl->EnumAudioEndpoints(p, a, b, c) - #endif - #ifdef __cplusplus - #define IMMDeviceEnumerator_GetDefaultAudioEndpoint(p, a, b, c) ((IMMDeviceEnumerator*)p)->GetDefaultAudioEndpoint(a, b, c) - #else - #define IMMDeviceEnumerator_GetDefaultAudioEndpoint(p, a, b, c) ((IMMDeviceEnumerator*)p)->lpVtbl->GetDefaultAudioEndpoint(p, a, b, c) - #endif - #ifdef __cplusplus - #define IMMDeviceEnumerator_GetDevice(p, a, b) ((IMMDeviceEnumerator*)p)->GetDevice(a, b) - #else - #define IMMDeviceEnumerator_GetDevice(p, a, b) ((IMMDeviceEnumerator*)p)->lpVtbl->GetDevice(p, a, b) - #endif - - // IMMDeviceCollection - #ifdef __cplusplus - #define IMMDeviceCollection_Release(p) ((IMMDeviceCollection*)p)->Release() - #else - #define IMMDeviceCollection_Release(p) ((IMMDeviceCollection*)p)->lpVtbl->Release((IMMDeviceCollection*)p) - #endif - #ifdef __cplusplus - #define IMMDeviceCollection_GetCount(p, a) ((IMMDeviceCollection*)p)->GetCount(a) - #else - #define IMMDeviceCollection_GetCount(p, a) ((IMMDeviceCollection*)p)->lpVtbl->GetCount((IMMDeviceCollection*)p, a) - #endif - #ifdef __cplusplus - #define IMMDeviceCollection_Item(p, a, b) ((IMMDeviceCollection*)p)->Item(a, b) - #else - #define IMMDeviceCollection_Item(p, a, b) ((IMMDeviceCollection*)p)->lpVtbl->Item((IMMDeviceCollection*)p, a, b) - #endif - - // IMMDevice - #ifdef __cplusplus - #define IMMDevice_Release(p) ((IMMDevice*)p)->Release() - #else - #define IMMDevice_Release(p) ((IMMDevice*)p)->lpVtbl->Release((IMMDevice*)p) - #endif - #ifdef __cplusplus - #define IMMDevice_GetId(p, a) ((IMMDevice*)p)->GetId(a) - #else - #define IMMDevice_GetId(p, a) ((IMMDevice*)p)->lpVtbl->GetId((IMMDevice*)p, a) - #endif - #ifdef __cplusplus - #define IMMDevice_OpenPropertyStore(p, a, b) ((IMMDevice*)p)->OpenPropertyStore(a, b) - #else - #define IMMDevice_OpenPropertyStore(p, a, b) ((IMMDevice*)p)->lpVtbl->OpenPropertyStore((IMMDevice*)p, a, b) - #endif - #ifdef __cplusplus - #define IMMDevice_Activate(p, a, b, c, d) ((IMMDevice*)p)->Activate(a, b, c, d) - #else - #define IMMDevice_Activate(p, a, b, c, d) ((IMMDevice*)p)->lpVtbl->Activate((IMMDevice*)p, a, b, c, d) - #endif -#else - // IActivateAudioInterfaceAsyncOperation - #ifdef __cplusplus - #define IActivateAudioInterfaceAsyncOperation_Release(p) ((IActivateAudioInterfaceAsyncOperation*)p)->Release() - #else - #define IActivateAudioInterfaceAsyncOperation_Release(p) ((IActivateAudioInterfaceAsyncOperation*)p)->lpVtbl->Release((IActivateAudioInterfaceAsyncOperation*)p) - #endif - #ifdef __cplusplus - #define IActivateAudioInterfaceAsyncOperation_GetActivateResult(p, a, b) ((IActivateAudioInterfaceAsyncOperation*)p)->GetActivateResult(a, b) - #else - #define IActivateAudioInterfaceAsyncOperation_GetActivateResult(p, a, b) ((IActivateAudioInterfaceAsyncOperation*)p)->lpVtbl->GetActivateResult((IActivateAudioInterfaceAsyncOperation*)p, a, b) - #endif -#endif - -// IPropertyStore -#ifdef __cplusplus - #define IPropertyStore_Release(p) ((IPropertyStore*)p)->Release() -#else - #define IPropertyStore_Release(p) ((IPropertyStore*)p)->lpVtbl->Release((IPropertyStore*)p) -#endif -#ifdef __cplusplus - #define IPropertyStore_GetValue(p, a, b) ((IPropertyStore*)p)->GetValue(a, b) -#else - #define IPropertyStore_GetValue(p, a, b) ((IPropertyStore*)p)->lpVtbl->GetValue((IPropertyStore*)p, &a, b) -#endif - -// IAudioClient -#ifdef __cplusplus - #define IAudioClient_Release(p) ((IAudioClient*)p)->Release() -#else - #define IAudioClient_Release(p) ((IAudioClient*)p)->lpVtbl->Release((IAudioClient*)p) -#endif -#ifdef __cplusplus - #define IAudioClient_IsFormatSupported(p, a, b, c) ((IAudioClient*)p)->IsFormatSupported(a, b, c) -#else - #define IAudioClient_IsFormatSupported(p, a, b, c) ((IAudioClient*)p)->lpVtbl->IsFormatSupported((IAudioClient*)p, a, b, c) -#endif -#ifdef __cplusplus - #define IAudioClient_GetMixFormat(p, a) ((IAudioClient*)p)->GetMixFormat(a) -#else - #define IAudioClient_GetMixFormat(p, a) ((IAudioClient*)p)->lpVtbl->GetMixFormat((IAudioClient*)p, a) -#endif -#ifdef __cplusplus - #define IAudioClient_Initialize(p, a, b, c, d, e, f) ((IAudioClient*)p)->Initialize(a, b, c, d, e, f) -#else - #define IAudioClient_Initialize(p, a, b, c, d, e, f) ((IAudioClient*)p)->lpVtbl->Initialize((IAudioClient*)p, a, b, c, d, e, f) -#endif -#ifdef __cplusplus - #define IAudioClient_GetBufferSize(p, a) ((IAudioClient*)p)->GetBufferSize(a) -#else - #define IAudioClient_GetBufferSize(p, a) ((IAudioClient*)p)->lpVtbl->GetBufferSize((IAudioClient*)p, a) -#endif -#ifdef __cplusplus - #define IAudioClient_GetService(p, a, b) ((IAudioClient*)p)->GetService(a, b) -#else - #define IAudioClient_GetService(p, a, b) ((IAudioClient*)p)->lpVtbl->GetService((IAudioClient*)p, a, b) -#endif -#ifdef __cplusplus - #define IAudioClient_Start(p) ((IAudioClient*)p)->Start() -#else - #define IAudioClient_Start(p) ((IAudioClient*)p)->lpVtbl->Start((IAudioClient*)p) -#endif -#ifdef __cplusplus - #define IAudioClient_Stop(p) ((IAudioClient*)p)->Stop() -#else - #define IAudioClient_Stop(p) ((IAudioClient*)p)->lpVtbl->Stop((IAudioClient*)p) -#endif -#ifdef __cplusplus - #define IAudioClient_GetCurrentPadding(p, a) ((IAudioClient*)p)->GetCurrentPadding(a) -#else - #define IAudioClient_GetCurrentPadding(p, a) ((IAudioClient*)p)->lpVtbl->GetCurrentPadding((IAudioClient*)p, a) -#endif -#ifdef __cplusplus - #define IAudioClient_SetEventHandle(p, a) ((IAudioClient*)p)->SetEventHandle(a) -#else - #define IAudioClient_SetEventHandle(p, a) ((IAudioClient*)p)->lpVtbl->SetEventHandle((IAudioClient*)p, a) -#endif - -// IAudioRenderClient -#ifdef __cplusplus - #define IAudioRenderClient_Release(p) ((IAudioRenderClient*)p)->Release() -#else - #define IAudioRenderClient_Release(p) ((IAudioRenderClient*)p)->lpVtbl->Release((IAudioRenderClient*)p) -#endif -#ifdef __cplusplus - #define IAudioRenderClient_GetBuffer(p, a, b) ((IAudioRenderClient*)p)->GetBuffer(a, b) -#else - #define IAudioRenderClient_GetBuffer(p, a, b) ((IAudioRenderClient*)p)->lpVtbl->GetBuffer((IAudioRenderClient*)p, a, b) -#endif -#ifdef __cplusplus - #define IAudioRenderClient_ReleaseBuffer(p, a, b) ((IAudioRenderClient*)p)->ReleaseBuffer(a, b) -#else - #define IAudioRenderClient_ReleaseBuffer(p, a, b) ((IAudioRenderClient*)p)->lpVtbl->ReleaseBuffer((IAudioRenderClient*)p, a, b) -#endif - -// IAudioCaptureClient -#ifdef __cplusplus - #define IAudioCaptureClient_Release(p) ((IAudioCaptureClient*)p)->Release() -#else - #define IAudioCaptureClient_Release(p) ((IAudioCaptureClient*)p)->lpVtbl->Release((IAudioCaptureClient*)p) -#endif -#ifdef __cplusplus - #define IAudioCaptureClient_GetNextPacketSize(p, a) ((IAudioCaptureClient*)p)->GetNextPacketSize(a) -#else - #define IAudioCaptureClient_GetNextPacketSize(p, a) ((IAudioCaptureClient*)p)->lpVtbl->GetNextPacketSize((IAudioCaptureClient*)p, a) -#endif -#ifdef __cplusplus - #define IAudioCaptureClient_GetBuffer(p, a, b, c, d, e) ((IAudioCaptureClient*)p)->GetBuffer(a, b, c, d, e) -#else - #define IAudioCaptureClient_GetBuffer(p, a, b, c, d, e) ((IAudioCaptureClient*)p)->lpVtbl->GetBuffer((IAudioCaptureClient*)p, a, b, c, d, e) -#endif -#ifdef __cplusplus - #define IAudioCaptureClient_ReleaseBuffer(p, a) ((IAudioCaptureClient*)p)->ReleaseBuffer(a) -#else - #define IAudioCaptureClient_ReleaseBuffer(p, a) ((IAudioCaptureClient*)p)->lpVtbl->ReleaseBuffer((IAudioCaptureClient*)p, a) -#endif - -mal_result mal_context_init__wasapi(mal_context* pContext) -{ - mal_assert(pContext != NULL); - (void)pContext; - -#ifdef MAL_WIN32_DESKTOP - // WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven - // exclusive mode does not work until SP1. - OSVERSIONINFOEXW osvi; - mal_zero_object(&osvi); - osvi.dwOSVersionInfoSize = sizeof(osvi); - osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); - osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); - osvi.wServicePackMajor = 1; - if (VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), VER_MINORVERSION, VER_GREATER_EQUAL), VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL))) { - return MAL_SUCCESS; - } else { - return MAL_NO_BACKEND; - } -#else - return MAL_SUCCESS; -#endif -} - -mal_result mal_context_uninit__wasapi(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_wasapi); - (void)pContext; - - return MAL_SUCCESS; -} - -static mal_result mal_enumerate_devices__wasapi(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - mal_uint32 infoSize = *pCount; - *pCount = 0; - -#ifdef MAL_WIN32_DESKTOP - IMMDeviceEnumerator* pDeviceEnumerator; - HRESULT hr = mal_CoCreateInstance(pContext, g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - if (FAILED(hr)) { - return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to create device enumerator.", MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR); - } - - IMMDeviceCollection* pDeviceCollection; - hr = IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, (type == mal_device_type_playback) ? eRender : eCapture, DEVICE_STATE_ACTIVE, &pDeviceCollection); - if (FAILED(hr)) { - IMMDeviceEnumerator_Release(pDeviceEnumerator); - return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to enumerate audio endpoints.", MAL_NO_DEVICE); - } - - IMMDeviceEnumerator_Release(pDeviceEnumerator); - - UINT count; - hr = IMMDeviceCollection_GetCount(pDeviceCollection, &count); - if (FAILED(hr)) { - IMMDeviceCollection_Release(pDeviceCollection); - return mal_context_post_error(pContext, NULL, "[WASAPI] Failed to get device count.", MAL_NO_DEVICE); - } - - for (mal_uint32 iDevice = 0; iDevice < count; ++iDevice) { - if (pInfo != NULL) { - if (infoSize > 0) { - mal_zero_object(pInfo); - - IMMDevice* pDevice; - hr = IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pDevice); - if (SUCCEEDED(hr)) { - // ID. - LPWSTR id; - hr = IMMDevice_GetId(pDevice, &id); - if (SUCCEEDED(hr)) { - size_t idlen = wcslen(id); - if (idlen+sizeof(wchar_t) > sizeof(pInfo->id.wasapi)) { - mal_CoTaskMemFree(pContext, id); - mal_assert(MAL_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. - continue; - } - - memcpy(pInfo->id.wasapi, id, idlen * sizeof(wchar_t)); - pInfo->id.wasapi[idlen] = '\0'; - - mal_CoTaskMemFree(pContext, id); - } - - // Description / Friendly Name. - IPropertyStore *pProperties; - hr = IMMDevice_OpenPropertyStore(pDevice, STGM_READ, &pProperties); - if (SUCCEEDED(hr)) { - PROPVARIANT varName; - PropVariantInit(&varName); - hr = IPropertyStore_GetValue(pProperties, g_malPKEY_Device_FriendlyName, &varName); - if (SUCCEEDED(hr)) { - WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE); - mal_PropVariantClear(pContext, &varName); - } - - IPropertyStore_Release(pProperties); - } - } - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - - IMMDeviceCollection_Release(pDeviceCollection); -#else - // The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate - // over devices without using MMDevice, I'm restricting devices to defaults. - if (pInfo != NULL) { - if (infoSize > 0) { - if (type == mal_device_type_playback) { - mal_copy_memory(pInfo->id.wasapi, &g_malIID_DEVINTERFACE_AUDIO_RENDER, sizeof(g_malIID_DEVINTERFACE_AUDIO_RENDER)); - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); - } else { - mal_copy_memory(pInfo->id.wasapi, &g_malIID_DEVINTERFACE_AUDIO_CAPTURE, sizeof(g_malIID_DEVINTERFACE_AUDIO_CAPTURE)); - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); - } - - pInfo += 1; - *pCount += 1; - } - } else { - *pCount += 1; - } -#endif - - return MAL_SUCCESS; -} - -static void mal_device_uninit__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->wasapi.pRenderClient) { - IAudioRenderClient_Release(pDevice->wasapi.pRenderClient); - } - if (pDevice->wasapi.pCaptureClient) { - IAudioCaptureClient_Release(pDevice->wasapi.pCaptureClient); - } - if (pDevice->wasapi.pAudioClient) { - IAudioClient_Release(pDevice->wasapi.pAudioClient); - } - - if (pDevice->wasapi.hEvent) { - CloseHandle(pDevice->wasapi.hEvent); - } - if (pDevice->wasapi.hStopEvent) { - CloseHandle(pDevice->wasapi.hStopEvent); - } -} - -#ifndef MAL_WIN32_DESKTOP - #ifdef __cplusplus - #include - class malCompletionHandler : public Microsoft::WRL::RuntimeClass< Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::ClassicCom >, Microsoft::WRL::FtmBase, IActivateAudioInterfaceCompletionHandler > - { - public: - - malCompletionHandler() - : m_hEvent(NULL) - { - } - - mal_result Init() - { - m_hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (m_hEvent == NULL) { - return MAL_ERROR; - } - - return MAL_SUCCESS; - } - - void Uninit() - { - if (m_hEvent != NULL) { - CloseHandle(m_hEvent); - } - } - - void Wait() - { - WaitForSingleObject(m_hEvent, INFINITE); - } - - HRESULT STDMETHODCALLTYPE ActivateCompleted(IActivateAudioInterfaceAsyncOperation *activateOperation) - { - (void)activateOperation; - SetEvent(m_hEvent); - return S_OK; - } - - private: - HANDLE m_hEvent; // This is created in Init(), deleted in Uninit(), waited on in Wait() and signaled in ActivateCompleted(). - }; - #else - #error "The UWP build is currently only supported in C++." - #endif -#endif // !MAL_WIN32_DESKTOP - -static mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->wasapi); - - HRESULT hr; - mal_result result = MAL_SUCCESS; - const char* errorMsg = ""; - AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED; - - WAVEFORMATEXTENSIBLE wf; - mal_zero_object(&wf); - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = (WORD)pDevice->channels; - wf.Format.nSamplesPerSec = (DWORD)pDevice->sampleRate; - wf.Format.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pDevice->format)*8; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = mal_channel_map_to_channel_mask__win32(pDevice->channelMap, pDevice->channels); - if (pDevice->format == mal_format_f32) { - wf.SubFormat = MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } else { - wf.SubFormat = MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM; - } - -#ifdef MAL_WIN32_DESKTOP - IMMDevice* pMMDevice = NULL; - - IMMDeviceEnumerator* pDeviceEnumerator; - hr = mal_CoCreateInstance(pContext, g_malCLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, g_malIID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to create IMMDeviceEnumerator.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE_ENUMERATOR; - goto done; - } - - if (pDeviceID == NULL) { - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (type == mal_device_type_playback) ? eRender : eCapture, eConsole, &pMMDevice); - if (FAILED(hr)) { - IMMDeviceEnumerator_Release(pDeviceEnumerator); - errorMsg = "[WASAPI] Failed to create default backend device.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE; - goto done; - } - } else { - hr = IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, &pMMDevice); - if (FAILED(hr)) { - IMMDeviceEnumerator_Release(pDeviceEnumerator); - errorMsg = "[WASAPI] Failed to create backend device.", result = MAL_WASAPI_FAILED_TO_CREATE_DEVICE; - goto done; - } - } - - IMMDeviceEnumerator_Release(pDeviceEnumerator); - - hr = IMMDevice_Activate(pMMDevice, g_malIID_IAudioClient, CLSCTX_ALL, NULL, &pDevice->wasapi.pAudioClient); - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to activate device.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } -#else - IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL; - malCompletionHandler completionHandler; - - IID iid; - if (pDeviceID != NULL) { - mal_copy_memory(&iid, pDeviceID->wasapi, sizeof(iid)); - } else { - if (type == mal_device_type_playback) { - iid = g_malIID_DEVINTERFACE_AUDIO_RENDER; - } else { - iid = g_malIID_DEVINTERFACE_AUDIO_CAPTURE; - } - } - - LPOLESTR iidStr; - hr = StringFromIID(iid, &iidStr); - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", result = MAL_OUT_OF_MEMORY; - goto done; - } - - result = completionHandler.Init(); - if (result != MAL_SUCCESS) { - mal_CoTaskMemFree(pContext, iidStr); - - errorMsg = "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } - - hr = ActivateAudioInterfaceAsync(iidStr, g_malIID_IAudioClient, NULL, &completionHandler, &pAsyncOp); - if (FAILED(hr)) { - completionHandler.Uninit(); - mal_CoTaskMemFree(pContext, iidStr); - - errorMsg = "[WASAPI] ActivateAudioInterfaceAsync() failed.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } - - mal_CoTaskMemFree(pContext, iidStr); - - // Wait for the async operation for finish. - completionHandler.Wait(); - completionHandler.Uninit(); - - HRESULT activateResult; - IUnknown* pActivatedInterface; - hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface); - if (FAILED(hr) || FAILED(activateResult)) { - errorMsg = "[WASAPI] Failed to activate device.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } - - // Here is where we grab the IAudioClient interface. - hr = pActivatedInterface->QueryInterface(g_malIID_IAudioClient, &pDevice->wasapi.pAudioClient); - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to query IAudioClient interface.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } -#endif - - // 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. - WAVEFORMATEXTENSIBLE* pBestFormatTemp = NULL; - result = MAL_FORMAT_NOT_SUPPORTED; - if (pConfig->preferExclusiveMode) { - hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL); - #ifdef MAL_WIN32_DESKTOP - if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) { - // The format isn't supported, so retrieve the actual format from the property store and try that. - IPropertyStore* pStore = NULL; - hr = IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pStore); - if (SUCCEEDED(hr)) { - PROPVARIANT prop; - PropVariantInit(&prop); - hr = IPropertyStore_GetValue(pStore, g_malPKEY_AudioEngine_DeviceFormat, &prop); - if (SUCCEEDED(hr)) { - WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData; - hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL); - if (SUCCEEDED(hr)) { - mal_copy_memory(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE)); - } - - mal_PropVariantClear(pDevice->pContext, &prop); - } - - IPropertyStore_Release(pStore); - } - } - #endif - - if (hr == S_OK) { - shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - result = MAL_SUCCESS; - } - } - - // Fall back to shared mode if necessary. - if (result != MAL_SUCCESS) { - hr = IAudioClient_IsFormatSupported(pDevice->wasapi.pAudioClient, AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&wf, (WAVEFORMATEX**)&pBestFormatTemp); - if (hr != S_OK && hr != S_FALSE) { - hr = IAudioClient_GetMixFormat(pDevice->wasapi.pAudioClient, (WAVEFORMATEX**)&pBestFormatTemp); - if (hr != S_OK) { - result = MAL_WASAPI_FAILED_TO_FIND_BEST_FORMAT; - } else { - result = MAL_SUCCESS; - } - } else { - result = MAL_SUCCESS; - } - - shareMode = AUDCLNT_SHAREMODE_SHARED; - } - - // Return an error if we still haven't found a format. - if (result != MAL_SUCCESS) { - errorMsg = "[WASAPI] Failed to find best device mix format.", result = MAL_WASAPI_FAILED_TO_ACTIVATE_DEVICE; - goto done; - } - - if (pBestFormatTemp != NULL) { - mal_copy_memory(&wf, pBestFormatTemp, sizeof(wf)); - mal_CoTaskMemFree(pDevice->pContext, pBestFormatTemp); - } - - - REFERENCE_TIME bufferDurationInMicroseconds = ((mal_uint64)pDevice->bufferSizeInFrames * 1000 * 1000) / pConfig->sampleRate; - - if (mal_is_guid_equal(wf.SubFormat, MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { - pDevice->internalFormat = mal_format_f32; - } else { - if (wf.Format.wBitsPerSample == 32) { - pDevice->internalFormat = mal_format_s32; - } else if (wf.Format.wBitsPerSample == 24) { - pDevice->internalFormat = mal_format_s24; - } else if (wf.Format.wBitsPerSample == 16) { - pDevice->internalFormat = mal_format_s16; - } else if (wf.Format.wBitsPerSample == 8) { - pDevice->internalFormat = mal_format_u8; - } else { - errorMsg = "[WASAPI] Device's native format is not supported.", result = MAL_FORMAT_NOT_SUPPORTED; - goto done; - } - } - - pDevice->internalChannels = wf.Format.nChannels; - pDevice->internalSampleRate = wf.Format.nSamplesPerSec; - - // Get the internal channel map based on the channel mask. - mal_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap); - - // Slightly different initialization for shared and exclusive modes. - if (shareMode == AUDCLNT_SHAREMODE_SHARED) { - // Shared. - REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; - hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL); - if (FAILED(hr)) { - if (hr == E_ACCESSDENIED) { - errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MAL_ACCESS_DENIED; - } else { - errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; - } - - goto done; - } - } else { - // Exclusive. - REFERENCE_TIME bufferDuration = bufferDurationInMicroseconds*10; - hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); - if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { - UINT bufferSizeInFrames; - hr = IAudioClient_GetBufferSize(pDevice->wasapi.pAudioClient, &bufferSizeInFrames); - if (SUCCEEDED(hr)) { - bufferDuration = (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?! - IAudioClient_Release(pDevice->wasapi.pAudioClient); - - #ifdef MAL_WIN32_DESKTOP - hr = IMMDevice_Activate(pMMDevice, g_malIID_IAudioClient, CLSCTX_ALL, NULL, &pDevice->wasapi.pAudioClient); - #else - hr = pActivatedInterface->QueryInterface(g_malIID_IAudioClient, &pDevice->wasapi.pAudioClient); - #endif - - if (SUCCEEDED(hr)) { - hr = IAudioClient_Initialize(pDevice->wasapi.pAudioClient, shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL); - } - } - } - - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to initialize device.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; - goto done; - } - } - - hr = IAudioClient_GetBufferSize(pDevice->wasapi.pAudioClient, &pDevice->bufferSizeInFrames); - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; - goto done; - } - - if (type == mal_device_type_playback) { - hr = IAudioClient_GetService((IAudioClient*)pDevice->wasapi.pAudioClient, g_malIID_IAudioRenderClient, &pDevice->wasapi.pRenderClient); - } else { - hr = IAudioClient_GetService((IAudioClient*)pDevice->wasapi.pAudioClient, g_malIID_IAudioCaptureClient, &pDevice->wasapi.pCaptureClient); - } - - if (FAILED(hr)) { - errorMsg = "[WASAPI] Failed to get audio client service.", result = MAL_WASAPI_FAILED_TO_INITIALIZE_DEVICE; - goto done; - } - - - if (shareMode == AUDCLNT_SHAREMODE_SHARED) { - pDevice->exclusiveMode = MAL_FALSE; - } else /*if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)*/ { - pDevice->exclusiveMode = MAL_TRUE; - } - - - // We need to create and set the event for event-driven mode. This event is signalled whenever a new chunk of audio - // data needs to be written or read from the device. - pDevice->wasapi.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDevice->wasapi.hEvent == NULL) { - errorMsg = "[WASAPI] Failed to create main event for main loop.", result = MAL_FAILED_TO_CREATE_EVENT; - goto done; - } - - IAudioClient_SetEventHandle(pDevice->wasapi.pAudioClient, pDevice->wasapi.hEvent); - - - // When the device is playing the worker thread will be waiting on a bunch of notification events. To return from - // this wait state we need to signal a special event. - pDevice->wasapi.hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDevice->wasapi.hStopEvent == NULL) { - errorMsg = "[WASAPI] Failed to create stop event for main loop break notification.", result = MAL_FAILED_TO_CREATE_EVENT; - goto done; - } - - result = MAL_SUCCESS; - -done: - // Clean up. -#ifdef MAL_WIN32_DESKTOP - if (pMMDevice != NULL) { - IMMDevice_Release(pMMDevice); - } -#else - if (pAsyncOp != NULL) { - IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp); - } -#endif - - if (result != MAL_SUCCESS) { - mal_device_uninit__wasapi(pDevice); - return mal_post_error(pDevice, errorMsg, result); - } else { - return MAL_SUCCESS; - } -} - -static mal_result mal_device__start_backend__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Playback devices need to have an initial chunk of data loaded. - if (pDevice->type == mal_device_type_playback) { - BYTE* pData; - HRESULT hr = IAudioRenderClient_GetBuffer(pDevice->wasapi.pRenderClient, pDevice->bufferSizeInFrames, &pData); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to retrieve buffer from internal playback device.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); - } - - mal_device__read_frames_from_client(pDevice, pDevice->bufferSizeInFrames, pData); - - hr = IAudioRenderClient_ReleaseBuffer(pDevice->wasapi.pRenderClient, pDevice->bufferSizeInFrames, 0); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to release internal buffer for playback device.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); - } - } - - HRESULT hr = IAudioClient_Start(pDevice->wasapi.pAudioClient); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to start internal device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - HRESULT hr = IAudioClient_Stop(pDevice->wasapi.pAudioClient); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to stop internal device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events - // is a special event we use for forcing that function to return. - pDevice->wasapi.breakFromMainLoop = MAL_TRUE; - SetEvent(pDevice->wasapi.hStopEvent); - return MAL_SUCCESS; -} - -static mal_uint32 mal_device__get_available_frames__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - -#if 1 - if (pDevice->type == mal_device_type_playback) { - UINT32 paddingFramesCount; - HRESULT hr = IAudioClient_GetCurrentPadding(pDevice->wasapi.pAudioClient, &paddingFramesCount); - if (FAILED(hr)) { - return 0; - } - - if (pDevice->exclusiveMode) { - return paddingFramesCount; - } else { - return pDevice->bufferSizeInFrames - paddingFramesCount; - } - } else { - UINT32 framesAvailable; - HRESULT hr = IAudioCaptureClient_GetNextPacketSize(pDevice->wasapi.pCaptureClient, &framesAvailable); - if (FAILED(hr)) { - return 0; - } - - return framesAvailable; - } -#else - UINT32 paddingFramesCount; - HRESULT hr = IAudioClient_GetCurrentPadding(pDevice->wasapi.pAudioClient, &paddingFramesCount); - if (FAILED(hr)) { - return 0; - } - - if (pDevice->exclusiveMode) { - return paddingFramesCount; - } else { - return pDevice->bufferSizeInFrames - paddingFramesCount; - } -#endif -} - -static mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - while (!pDevice->wasapi.breakFromMainLoop) { - // Wait for a buffer to become available or for the stop event to be signalled. - HANDLE hEvents[2]; - hEvents[0] = (HANDLE)pDevice->wasapi.hEvent; - hEvents[1] = (HANDLE)pDevice->wasapi.hStopEvent; - if (WaitForMultipleObjects(mal_countof(hEvents), hEvents, FALSE, INFINITE) == WAIT_FAILED) { - break; - } - - // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } - - mal_uint32 framesAvailable = mal_device__get_available_frames__wasapi(pDevice); - if (framesAvailable > 0) { - return framesAvailable; - } - } - - // We'll get here if the loop was terminated. Just return whatever's available. - return mal_device__get_available_frames__wasapi(pDevice); -} - -static mal_result mal_device__main_loop__wasapi(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects(). - ResetEvent(pDevice->wasapi.hStopEvent); - - pDevice->wasapi.breakFromMainLoop = MAL_FALSE; - while (!pDevice->wasapi.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__wasapi(pDevice); - if (framesAvailable == 0) { - continue; - } - - // If it's a playback device, don't bother grabbing more data if the device is being stopped. - if (pDevice->wasapi.breakFromMainLoop && pDevice->type == mal_device_type_playback) { - return MAL_FALSE; - } - - if (pDevice->type == mal_device_type_playback) { - BYTE* pData; - HRESULT hr = IAudioRenderClient_GetBuffer(pDevice->wasapi.pRenderClient, framesAvailable, &pData); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for sending new data to the device.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); - } - - mal_device__read_frames_from_client(pDevice, framesAvailable, pData); - - hr = IAudioRenderClient_ReleaseBuffer(pDevice->wasapi.pRenderClient, framesAvailable, 0); - if (FAILED(hr)) { - return mal_post_error(pDevice, "[WASAPI] Failed to release internal buffer from playback device in preparation for sending new data to the device.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); - } - } else { - UINT32 framesRemaining = framesAvailable; - while (framesRemaining > 0) { - BYTE* pData; - UINT32 framesToSend; - DWORD flags; - HRESULT hr = IAudioCaptureClient_GetBuffer(pDevice->wasapi.pCaptureClient, &pData, &framesToSend, &flags, NULL, NULL); - if (FAILED(hr)) { - mal_post_error(pDevice, "[WASAPI] WARNING: Failed to retrieve internal buffer from capture device in preparation for sending new data to the client.", MAL_WASAPI_FAILED_TO_GET_INTERNAL_BUFFER); - break; - } - - if (hr != AUDCLNT_S_BUFFER_EMPTY) { - mal_device__send_frames_to_client(pDevice, framesToSend, pData); - - hr = IAudioCaptureClient_ReleaseBuffer(pDevice->wasapi.pCaptureClient, framesToSend); - if (FAILED(hr)) { - mal_post_error(pDevice, "[WASAPI] WARNING: Failed to release internal buffer from capture device in preparation for sending new data to the client.", MAL_WASAPI_FAILED_TO_RELEASE_INTERNAL_BUFFER); - break; - } - - if (framesRemaining >= framesToSend) { - framesRemaining -= framesToSend; - } else { - framesRemaining = 0; - } - } - } - } - } - - return MAL_SUCCESS; -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// -// DirectSound Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_DSOUND -#include - -#if 0 // MAL_GUID_NULL is not currently used, but leaving it here in case I need to add it back again. -static GUID MAL_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -#endif -static GUID MAL_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; -static GUID MAL_GUID_IID_IDirectSoundCaptureBuffer = {0xb0210782, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}}; - -typedef HRESULT (WINAPI * mal_DirectSoundCreateProc)(const GUID* pcGuidDevice, LPDIRECTSOUND *ppDS8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * mal_DirectSoundEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); -typedef HRESULT (WINAPI * mal_DirectSoundCaptureCreateProc)(const GUID* pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC8, LPUNKNOWN pUnkOuter); -typedef HRESULT (WINAPI * mal_DirectSoundCaptureEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); - -static HMODULE mal_open_dsound_dll() -{ - return LoadLibraryW(L"dsound.dll"); -} - -static void mal_close_dsound_dll(HMODULE hModule) -{ - FreeLibrary(hModule); -} - - -mal_result mal_context_init__dsound(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - (void)pContext; - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__dsound(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_dsound); - - (void)pContext; - return MAL_SUCCESS; -} - - -typedef struct -{ - mal_uint32 deviceCount; - mal_uint32 infoCount; - mal_device_info* pInfo; -} mal_device_enum_data__dsound; - -static BOOL CALLBACK mal_enum_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - (void)lpcstrModule; - - mal_device_enum_data__dsound* pData = (mal_device_enum_data__dsound*)lpContext; - mal_assert(pData != NULL); - - if (pData->pInfo != NULL) { - if (pData->infoCount > 0) { - mal_zero_object(pData->pInfo); - mal_strncpy_s(pData->pInfo->name, sizeof(pData->pInfo->name), lpcstrDescription, (size_t)-1); - - if (lpGuid != NULL) { - mal_copy_memory(pData->pInfo->id.dsound, lpGuid, 16); - } else { - mal_zero_memory(pData->pInfo->id.dsound, 16); - } - - pData->pInfo += 1; - pData->infoCount -= 1; - pData->deviceCount += 1; - } - } else { - pData->deviceCount += 1; - } - - return TRUE; -} - -static mal_result mal_enumerate_devices__dsound(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - - mal_device_enum_data__dsound enumData; - enumData.deviceCount = 0; - enumData.infoCount = infoSize; - enumData.pInfo = pInfo; - - HMODULE dsoundDLL = mal_open_dsound_dll(); - if (dsoundDLL == NULL) { - return MAL_NO_BACKEND; - } - - if (type == mal_device_type_playback) { - mal_DirectSoundEnumerateAProc pDirectSoundEnumerateA = (mal_DirectSoundEnumerateAProc)GetProcAddress(dsoundDLL, "DirectSoundEnumerateA"); - if (pDirectSoundEnumerateA) { - pDirectSoundEnumerateA(mal_enum_devices_callback__dsound, &enumData); - } - } else { - mal_DirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA = (mal_DirectSoundCaptureEnumerateAProc)GetProcAddress(dsoundDLL, "DirectSoundCaptureEnumerateA"); - if (pDirectSoundCaptureEnumerateA) { - pDirectSoundCaptureEnumerateA(mal_enum_devices_callback__dsound, &enumData); - } - } - - - mal_close_dsound_dll(dsoundDLL); - - *pCount = enumData.deviceCount; - return MAL_SUCCESS; -} - -static void mal_device_uninit__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->dsound.hDSoundDLL != NULL) { - if (pDevice->dsound.pNotify) { - IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)pDevice->dsound.pNotify); - } - - if (pDevice->dsound.hStopEvent) { - CloseHandle(pDevice->dsound.hStopEvent); - } - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - if (pDevice->dsound.pNotifyEvents[i]) { - CloseHandle(pDevice->dsound.pNotifyEvents[i]); - } - } - - if (pDevice->dsound.pCaptureBuffer) { - IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pCaptureBuffer); - } - if (pDevice->dsound.pCapture) { - IDirectSoundCapture_Release((LPDIRECTSOUNDCAPTURE)pDevice->dsound.pCapture); - } - - if (pDevice->dsound.pPlaybackBuffer) { - IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer); - } - if (pDevice->dsound.pPlaybackPrimaryBuffer) { - IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer); - } - if (pDevice->dsound.pPlayback != NULL) { - IDirectSound_Release((LPDIRECTSOUND)pDevice->dsound.pPlayback); - } - - mal_close_dsound_dll((HMODULE)pDevice->dsound.hDSoundDLL); - } -} - -static mal_result mal_device_init__dsound(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - -#ifdef __cplusplus - GUID _MAL_GUID_IID_DirectSoundNotify = MAL_GUID_IID_DirectSoundNotify; - GUID _MAL_GUID_IID_IDirectSoundCaptureBuffer = MAL_GUID_IID_IDirectSoundCaptureBuffer; -#else - GUID* _MAL_GUID_IID_DirectSoundNotify = &MAL_GUID_IID_DirectSoundNotify; - GUID* _MAL_GUID_IID_IDirectSoundCaptureBuffer = &MAL_GUID_IID_IDirectSoundCaptureBuffer; -#endif - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->dsound); - - pDevice->dsound.hDSoundDLL = (mal_handle)mal_open_dsound_dll(); - if (pDevice->dsound.hDSoundDLL == NULL) { - return MAL_NO_BACKEND; - } - - // Check that we have a valid format. - GUID subformat; - switch (pConfig->format) - { - case mal_format_u8: - case mal_format_s16: - case mal_format_s24: - case mal_format_s32: - { - subformat = MAL_GUID_KSDATAFORMAT_SUBTYPE_PCM; - } break; - - case mal_format_f32: - { - subformat = MAL_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } break; - - default: - return MAL_FORMAT_NOT_SUPPORTED; - } - - - WAVEFORMATEXTENSIBLE wf; - mal_zero_object(&wf); - wf.Format.cbSize = sizeof(wf); - wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wf.Format.nChannels = (WORD)pConfig->channels; - wf.Format.nSamplesPerSec = (DWORD)pConfig->sampleRate; - wf.Format.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pConfig->format)*8; - wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8; - wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec; - wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample; - wf.dwChannelMask = mal_channel_map_to_channel_mask__win32(pConfig->channelMap, pConfig->channels); - wf.SubFormat = subformat; - - DWORD bufferSizeInBytes = 0; - - // Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices :( - if (type == mal_device_type_playback) { - mal_DirectSoundCreateProc pDirectSoundCreate = (mal_DirectSoundCreateProc)GetProcAddress((HMODULE)pDevice->dsound.hDSoundDLL, "DirectSoundCreate"); - if (pDirectSoundCreate == NULL) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Could not find DirectSoundCreate().", MAL_API_NOT_FOUND); - } - - if (FAILED(pDirectSoundCreate((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, (LPDIRECTSOUND*)&pDevice->dsound.pPlayback, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] DirectSoundCreate() failed for playback device.", MAL_DSOUND_FAILED_TO_CREATE_DEVICE); - } - - // The cooperative level must be set before doing anything else. - HWND hWnd = ((MAL_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); - if (hWnd == NULL) { - hWnd = ((MAL_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); - } - if (FAILED(IDirectSound_SetCooperativeLevel((LPDIRECTSOUND)pDevice->dsound.pPlayback, hWnd, (pConfig->preferExclusiveMode) ? DSSCL_EXCLUSIVE : DSSCL_PRIORITY))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", MAL_DSOUND_FAILED_TO_SET_COOP_LEVEL); - } - - DSBUFFERDESC descDSPrimary; - mal_zero_object(&descDSPrimary); - descDSPrimary.dwSize = sizeof(DSBUFFERDESC); - descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; - if (FAILED(IDirectSound_CreateSoundBuffer((LPDIRECTSOUND)pDevice->dsound.pPlayback, &descDSPrimary, (LPDIRECTSOUNDBUFFER*)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); - } - - // From MSDN: - // - // The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest - // 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. - if (FAILED(IDirectSoundBuffer_SetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Failed to set format of playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); - } - - // Get the _actual_ properties of the buffer. This is silly API design... - DWORD requiredSize; - if (FAILED(IDirectSoundBuffer_GetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, NULL, 0, &requiredSize))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); - } - - char rawdata[1024]; - WAVEFORMATEXTENSIBLE* pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata; - if (FAILED(IDirectSoundBuffer_GetFormat((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, requiredSize, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", MAL_FORMAT_NOT_SUPPORTED); - } - - pDevice->internalChannels = pActualFormat->Format.nChannels; - pDevice->internalSampleRate = pActualFormat->Format.nSamplesPerSec; - bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->format); - - // Get the internal channel map based on the channel mask. - mal_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->internalChannels, pDevice->internalChannelMap); - - - // Meaning of dwFlags (from MSDN): - // - // DSBCAPS_CTRLPOSITIONNOTIFY - // The buffer has position notification capability. - // - // DSBCAPS_GLOBALFOCUS - // With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to - // another application, even if the new application uses DirectSound. - // - // DSBCAPS_GETCURRENTPOSITION2 - // In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated - // sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the - // application can get a more accurate play cursor. - DSBUFFERDESC descDS; - mal_zero_object(&descDS); - descDS.dwSize = sizeof(DSBUFFERDESC); - descDS.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; - descDS.dwBufferBytes = bufferSizeInBytes; - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; - if (FAILED(IDirectSound_CreateSoundBuffer((LPDIRECTSOUND)pDevice->dsound.pPlayback, &descDS, (LPDIRECTSOUNDBUFFER*)&pDevice->dsound.pPlaybackBuffer, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); - } - - // Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer. - if (FAILED(IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, _MAL_GUID_IID_DirectSoundNotify, (void**)&pDevice->dsound.pNotify))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_QueryInterface() failed for playback device's IDirectSoundNotify object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); - } - } else { - // The default buffer size is treated slightly differently for DirectSound which, for some reason, seems to - // have worse latency with capture than playback (sometimes _much_ worse). - if (pDevice->usingDefaultBufferSize) { - pDevice->bufferSizeInFrames *= 2; // <-- Might need to fiddle with this to find a more ideal value. May even be able to just add a fixed amount rather than scaling. - } - - mal_DirectSoundCaptureCreateProc pDirectSoundCaptureCreate = (mal_DirectSoundCaptureCreateProc)GetProcAddress((HMODULE)pDevice->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); - if (pDirectSoundCaptureCreate == NULL) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Could not find DirectSoundCreate().", MAL_API_NOT_FOUND); - } - - if (FAILED(pDirectSoundCaptureCreate((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, (LPDIRECTSOUNDCAPTURE*)&pDevice->dsound.pCapture, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", MAL_DSOUND_FAILED_TO_CREATE_DEVICE); - } - - bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); - - DSCBUFFERDESC descDS; - mal_zero_object(&descDS); - descDS.dwSize = sizeof(descDS); - descDS.dwFlags = 0; - descDS.dwBufferBytes = bufferSizeInBytes; - descDS.lpwfxFormat = (WAVEFORMATEX*)&wf; - LPDIRECTSOUNDCAPTUREBUFFER pDSCB_Temp; - if (FAILED(IDirectSoundCapture_CreateCaptureBuffer((LPDIRECTSOUNDCAPTURE)pDevice->dsound.pCapture, &descDS, &pDSCB_Temp, NULL))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", MAL_DSOUND_FAILED_TO_CREATE_BUFFER); - } - - HRESULT hr = IDirectSoundCapture_QueryInterface(pDSCB_Temp, _MAL_GUID_IID_IDirectSoundCaptureBuffer, (LPVOID*)&pDevice->dsound.pCaptureBuffer); - IDirectSoundCaptureBuffer_Release(pDSCB_Temp); - if (FAILED(hr)) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCapture_QueryInterface() failed for capture device's IDirectSoundCaptureBuffer8 object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); - } - - // Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer. - if (FAILED(IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, _MAL_GUID_IID_DirectSoundNotify, (void**)&pDevice->dsound.pNotify))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_QueryInterface() failed for capture device's IDirectSoundNotify object.", MAL_DSOUND_FAILED_TO_QUERY_INTERFACE); - } - } - - // We need a notification for each period. The notification offset is slightly different depending on whether or not the - // device is a playback or capture device. For a playback device we want to be notified when a period just starts playing, - // whereas for a capture device we want to be notified when a period has just _finished_ capturing. - mal_uint32 periodSizeInBytes = pDevice->bufferSizeInFrames / pDevice->periods; - DSBPOSITIONNOTIFY notifyPoints[MAL_MAX_PERIODS_DSOUND]; // One notification event for each period. - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - pDevice->dsound.pNotifyEvents[i] = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDevice->dsound.pNotifyEvents[i] == NULL) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Failed to create event for buffer notifications.", MAL_FAILED_TO_CREATE_EVENT); - } - - // The notification offset is in bytes. - notifyPoints[i].dwOffset = i * periodSizeInBytes; - notifyPoints[i].hEventNotify = pDevice->dsound.pNotifyEvents[i]; - } - - if (FAILED(IDirectSoundNotify_SetNotificationPositions((LPDIRECTSOUNDNOTIFY)pDevice->dsound.pNotify, pDevice->periods, notifyPoints))) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] IDirectSoundNotify_SetNotificationPositions() failed.", MAL_DSOUND_FAILED_TO_SET_NOTIFICATIONS); - } - - // When the device is playing the worker thread will be waiting on a bunch of notification events. To return from - // this wait state we need to signal a special event. - pDevice->dsound.hStopEvent = CreateEventA(NULL, FALSE, FALSE, NULL); - if (pDevice->dsound.hStopEvent == NULL) { - mal_device_uninit__dsound(pDevice); - return mal_post_error(pDevice, "[DirectSound] Failed to create event for main loop break notification.", MAL_FAILED_TO_CREATE_EVENT); - } - - return MAL_SUCCESS; -} - - -static mal_result mal_device__start_backend__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - // Before playing anything we need to grab an initial group of samples from the client. - mal_uint32 framesToRead = pDevice->bufferSizeInFrames / pDevice->periods; - mal_uint32 desiredLockSize = framesToRead * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); - - void* pLockPtr; - DWORD actualLockSize; - void* pLockPtr2; - DWORD actualLockSize2; - if (SUCCEEDED(IDirectSoundBuffer_Lock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0, desiredLockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { - framesToRead = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; - mal_device__read_frames_from_client(pDevice, framesToRead, pLockPtr); - IDirectSoundBuffer_Unlock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); - - pDevice->dsound.lastProcessedFrame = framesToRead; - if (FAILED(IDirectSoundBuffer_Play((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0, 0, DSBPLAY_LOOPING))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Play() failed.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } else { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); - } - } else { - if (FAILED(IDirectSoundCaptureBuffer_Start((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, DSCBSTART_LOOPING))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - if (FAILED(IDirectSoundBuffer_Stop((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Stop() failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - - IDirectSoundBuffer_SetCurrentPosition((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, 0); - } else { - if (FAILED(IDirectSoundCaptureBuffer_Stop((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events - // is a special event we use for forcing that function to return. - pDevice->dsound.breakFromMainLoop = MAL_TRUE; - SetEvent(pDevice->dsound.hStopEvent); - return MAL_SUCCESS; -} - -static mal_bool32 mal_device__get_current_frame__dsound(mal_device* pDevice, mal_uint32* pCurrentPos) -{ - mal_assert(pDevice != NULL); - mal_assert(pCurrentPos != NULL); - *pCurrentPos = 0; - - DWORD dwCurrentPosition; - if (pDevice->type == mal_device_type_playback) { - if (FAILED(IDirectSoundBuffer_GetCurrentPosition((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, NULL, &dwCurrentPosition))) { - return MAL_FALSE; - } - } else { - if (FAILED(IDirectSoundCaptureBuffer_GetCurrentPosition((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, &dwCurrentPosition, NULL))) { - return MAL_FALSE; - } - } - - *pCurrentPos = (mal_uint32)dwCurrentPosition / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; - return MAL_TRUE; -} - -static mal_uint32 mal_device__get_available_frames__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_uint32 currentFrame; - if (!mal_device__get_current_frame__dsound(pDevice, ¤tFrame)) { - return 0; - } - - // In a playback device the last processed frame should always be ahead of the current frame. The space between - // the last processed and current frame (moving forward, starting from the last processed frame) is the amount - // of space available to write. - // - // For a recording device it's the other way around - the last processed frame is always _behind_ the current - // frame and the space between is the available space. - mal_uint32 totalFrameCount = pDevice->bufferSizeInFrames; - if (pDevice->type == mal_device_type_playback) { - mal_uint32 committedBeg = currentFrame; - mal_uint32 committedEnd; - committedEnd = pDevice->dsound.lastProcessedFrame; - if (committedEnd <= committedBeg) { - committedEnd += totalFrameCount; - } - - mal_uint32 committedSize = (committedEnd - committedBeg); - mal_assert(committedSize <= totalFrameCount); - - return totalFrameCount - committedSize; - } else { - mal_uint32 validBeg = pDevice->dsound.lastProcessedFrame; - mal_uint32 validEnd = currentFrame; - if (validEnd < validBeg) { - validEnd += totalFrameCount; // Wrap around. - } - - mal_uint32 validSize = (validEnd - validBeg); - mal_assert(validSize <= totalFrameCount); - - return validSize; - } -} - -static mal_uint32 mal_device__wait_for_frames__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // The timeout to use for putting the thread to sleep is based on the size of the buffer and the period count. - DWORD timeoutInMilliseconds = (pDevice->bufferSizeInFrames / (pDevice->sampleRate/1000)) / pDevice->periods; - if (timeoutInMilliseconds < 1) { - timeoutInMilliseconds = 1; - } - - unsigned int eventCount = pDevice->periods + 1; - HANDLE pEvents[MAL_MAX_PERIODS_DSOUND + 1]; // +1 for the stop event. - mal_copy_memory(pEvents, pDevice->dsound.pNotifyEvents, sizeof(HANDLE) * pDevice->periods); - pEvents[eventCount-1] = pDevice->dsound.hStopEvent; - - while (!pDevice->dsound.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__get_available_frames__dsound(pDevice); - if (framesAvailable > 0) { - return framesAvailable; - } - - // If we get here it means we weren't able to find any frames. We'll just wait here for a bit. - WaitForMultipleObjects(eventCount, pEvents, FALSE, timeoutInMilliseconds); - } - - // We'll get here if the loop was terminated. Just return whatever's available. - return mal_device__get_available_frames__dsound(pDevice); -} - -static mal_result mal_device__main_loop__dsound(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects(). - ResetEvent(pDevice->dsound.hStopEvent); - - pDevice->dsound.breakFromMainLoop = MAL_FALSE; - while (!pDevice->dsound.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__dsound(pDevice); - if (framesAvailable == 0) { - continue; - } - - // If it's a playback device, don't bother grabbing more data if the device is being stopped. - if (pDevice->dsound.breakFromMainLoop && pDevice->type == mal_device_type_playback) { - return MAL_FALSE; - } - - DWORD lockOffset = pDevice->dsound.lastProcessedFrame * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); - DWORD lockSize = framesAvailable * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); - - if (pDevice->type == mal_device_type_playback) { - void* pLockPtr; - DWORD actualLockSize; - void* pLockPtr2; - DWORD actualLockSize2; - if (FAILED(IDirectSoundBuffer_Lock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, lockOffset, lockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); - } - - mal_uint32 frameCount = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; - mal_device__read_frames_from_client(pDevice, frameCount, pLockPtr); - pDevice->dsound.lastProcessedFrame = (pDevice->dsound.lastProcessedFrame + frameCount) % pDevice->bufferSizeInFrames; - - IDirectSoundBuffer_Unlock((LPDIRECTSOUNDBUFFER)pDevice->dsound.pPlaybackBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); - } else { - void* pLockPtr; - DWORD actualLockSize; - void* pLockPtr2; - DWORD actualLockSize2; - if (FAILED(IDirectSoundCaptureBuffer_Lock((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, lockOffset, lockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) { - return mal_post_error(pDevice, "[DirectSound] IDirectSoundCaptureBuffer_Lock() failed.", MAL_FAILED_TO_MAP_DEVICE_BUFFER); - } - - mal_uint32 frameCount = actualLockSize / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels; - mal_device__send_frames_to_client(pDevice, frameCount, pLockPtr); - pDevice->dsound.lastProcessedFrame = (pDevice->dsound.lastProcessedFrame + frameCount) % pDevice->bufferSizeInFrames; - - IDirectSoundCaptureBuffer_Unlock((LPDIRECTSOUNDCAPTUREBUFFER)pDevice->dsound.pCaptureBuffer, pLockPtr, actualLockSize, pLockPtr2, actualLockSize2); - } - } - - return MAL_SUCCESS; -} -#endif - - - -/////////////////////////////////////////////////////////////////////////////// -// -// WinMM Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_WINMM -#include - -#if !defined(MAXULONG_PTR) -typedef size_t DWORD_PTR; -#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 -#endif - -typedef UINT (WINAPI * MAL_PFN_waveOutGetNumDevs)(void); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutGetDevCapsA)(UINT_PTR uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutClose)(HWAVEOUT hwo); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveOutReset)(HWAVEOUT hwo); -typedef UINT (WINAPI * MAL_PFN_waveInGetNumDevs)(void); -typedef MMRESULT (WINAPI * MAL_PFN_waveInGetDevCapsA)(UINT_PTR uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic); -typedef MMRESULT (WINAPI * MAL_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); -typedef MMRESULT (WINAPI * MAL_PFN_waveInClose)(HWAVEIN hwi); -typedef MMRESULT (WINAPI * MAL_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh); -typedef MMRESULT (WINAPI * MAL_PFN_waveInStart)(HWAVEIN hwi); -typedef MMRESULT (WINAPI * MAL_PFN_waveInReset)(HWAVEIN hwi); - -mal_result mal_result_from_MMRESULT(MMRESULT resultMM) -{ - switch (resultMM) { - case MMSYSERR_NOERROR: return MAL_SUCCESS; - case MMSYSERR_BADDEVICEID: return MAL_INVALID_ARGS; - case MMSYSERR_INVALHANDLE: return MAL_INVALID_ARGS; - case MMSYSERR_NOMEM: return MAL_OUT_OF_MEMORY; - case MMSYSERR_INVALFLAG: return MAL_INVALID_ARGS; - case MMSYSERR_INVALPARAM: return MAL_INVALID_ARGS; - case MMSYSERR_HANDLEBUSY: return MAL_DEVICE_BUSY; - case MMSYSERR_ERROR: return MAL_ERROR; - default: return MAL_ERROR; - } -} - -mal_result mal_context_init__winmm(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - pContext->winmm.hWinMM = mal_dlopen("winmm.dll"); - if (pContext->winmm.hWinMM == NULL) { - return MAL_NO_BACKEND; - } - - pContext->winmm.waveOutGetNumDevs = mal_dlsym(pContext->winmm.hWinMM, "waveOutGetNumDevs"); - pContext->winmm.waveOutGetDevCapsA = mal_dlsym(pContext->winmm.hWinMM, "waveOutGetDevCapsA"); - pContext->winmm.waveOutOpen = mal_dlsym(pContext->winmm.hWinMM, "waveOutOpen"); - pContext->winmm.waveOutClose = mal_dlsym(pContext->winmm.hWinMM, "waveOutClose"); - pContext->winmm.waveOutPrepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveOutPrepareHeader"); - pContext->winmm.waveOutUnprepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveOutUnprepareHeader"); - pContext->winmm.waveOutWrite = mal_dlsym(pContext->winmm.hWinMM, "waveOutWrite"); - pContext->winmm.waveOutReset = mal_dlsym(pContext->winmm.hWinMM, "waveOutReset"); - pContext->winmm.waveInGetNumDevs = mal_dlsym(pContext->winmm.hWinMM, "waveInGetNumDevs"); - pContext->winmm.waveInGetDevCapsA = mal_dlsym(pContext->winmm.hWinMM, "waveInGetDevCapsA"); - pContext->winmm.waveInOpen = mal_dlsym(pContext->winmm.hWinMM, "waveInOpen"); - pContext->winmm.waveInClose = mal_dlsym(pContext->winmm.hWinMM, "waveInClose"); - pContext->winmm.waveInPrepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInPrepareHeader"); - pContext->winmm.waveInUnprepareHeader = mal_dlsym(pContext->winmm.hWinMM, "waveInUnprepareHeader"); - pContext->winmm.waveInAddBuffer = mal_dlsym(pContext->winmm.hWinMM, "waveInAddBuffer"); - pContext->winmm.waveInStart = mal_dlsym(pContext->winmm.hWinMM, "waveInStart"); - pContext->winmm.waveInReset = mal_dlsym(pContext->winmm.hWinMM, "waveInReset"); - - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__winmm(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_winmm); - - mal_dlclose(pContext->winmm.hWinMM); - return MAL_SUCCESS; -} - -static mal_result mal_enumerate_devices__winmm(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - - if (type == mal_device_type_playback) { - UINT deviceCount = ((MAL_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)(); - for (UINT iDevice = 0; iDevice < deviceCount; ++iDevice) { - if (pInfo != NULL) { - if (infoSize > 0) { - WAVEOUTCAPSA caps; - MMRESULT result = ((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iDevice, &caps, sizeof(caps)); - if (result == MMSYSERR_NOERROR) { - pInfo->id.winmm = iDevice; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), caps.szPname, (size_t)-1); - } - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - } else { - UINT deviceCount = ((MAL_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)(); - for (UINT iDevice = 0; iDevice < deviceCount; ++iDevice) { - if (pInfo != NULL) { - if (infoSize > 0) { - WAVEINCAPSA caps; - MMRESULT result = ((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iDevice, &caps, sizeof(caps)); - if (result == MMSYSERR_NOERROR) { - pInfo->id.winmm = iDevice; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), caps.szPname, (size_t)-1); - } - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - } - - return MAL_SUCCESS; -} - -static void mal_device_uninit__winmm(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - ((MAL_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevice); - } else { - ((MAL_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDevice); - } - - mal_free(pDevice->winmm._pHeapData); - CloseHandle((HANDLE)pDevice->winmm.hEvent); -} - -static mal_result mal_device_init__winmm(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - - mal_uint32 heapSize; - mal_uint32 iBit; - - WORD closestBitsPerSample = 0; - WORD closestChannels = 0; - DWORD closestSampleRate = 0; - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->winmm); - - UINT winMMDeviceID = 0; - if (pDeviceID != NULL) { - winMMDeviceID = (UINT)pDeviceID->winmm; - } - - const char* errorMsg = ""; - mal_result errorCode = MAL_ERROR; - - - // WinMM doesn't seem to have a good way to query the format of the device. Therefore, we'll restrict the formats to the - // standard formats documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd743855(v=vs.85).aspx. If - // that link goes stale, just look up the documentation for WAVEOUTCAPS or WAVEINCAPS. - WAVEFORMATEX wf; - mal_zero_object(&wf); - wf.cbSize = sizeof(wf); - wf.wFormatTag = WAVE_FORMAT_PCM; - wf.nChannels = (WORD)pConfig->channels; - wf.nSamplesPerSec = (DWORD)pConfig->sampleRate; - wf.wBitsPerSample = (WORD)mal_get_sample_size_in_bytes(pConfig->format)*8; - - if (wf.nChannels > 2) { - wf.nChannels = 2; - } - - if (wf.wBitsPerSample != 8 && wf.wBitsPerSample != 16) { - if (wf.wBitsPerSample <= 8) { - wf.wBitsPerSample = 8; - } else { - wf.wBitsPerSample = 16; - } - } - - if (wf.nSamplesPerSec <= 11025) { - wf.nSamplesPerSec = 11025; - } else if (wf.nSamplesPerSec <= 22050) { - wf.nSamplesPerSec = 22050; - } else if (wf.nSamplesPerSec <= 44100) { - wf.nSamplesPerSec = 44100; - } else if (wf.nSamplesPerSec <= 48000) { - wf.nSamplesPerSec = 48000; - } else { - wf.nSamplesPerSec = 96000; - } - - - // Change the format based on the closest match of the supported standard formats. - DWORD dwFormats = 0; - if (type == mal_device_type_playback) { - WAVEOUTCAPSA caps; - if (((MAL_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) { - dwFormats = caps.dwFormats; - } else { - errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS; - goto on_error; - } - } else { - WAVEINCAPSA caps; - if (((MAL_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, &caps, sizeof(caps)) == MMSYSERR_NOERROR) { - dwFormats = caps.dwFormats; - } else { - errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS; - goto on_error; - } - } - - if (dwFormats == 0) { - errorMsg = "[WinMM] Failed to retrieve the supported formats for the internal device.", errorCode = MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS; - goto on_error; - } - - for (iBit = 0; iBit < 32; ++iBit) { - WORD formatBitsPerSample = 0; - WORD formatChannels = 0; - DWORD formatSampleRate = 0; - - DWORD format = (dwFormats & (1 << iBit)); - if (format != 0) { - switch (format) - { - case WAVE_FORMAT_1M08: - { - formatBitsPerSample = 8; - formatChannels = 1; - formatSampleRate = 110025; - } break; - case WAVE_FORMAT_1M16: - { - formatBitsPerSample = 16; - formatChannels = 1; - formatSampleRate = 110025; - } break; - case WAVE_FORMAT_1S08: - { - formatBitsPerSample = 8; - formatChannels = 2; - formatSampleRate = 110025; - } break; - case WAVE_FORMAT_1S16: - { - formatBitsPerSample = 16; - formatChannels = 2; - formatSampleRate = 110025; - } break; - case WAVE_FORMAT_2M08: - { - formatBitsPerSample = 8; - formatChannels = 1; - formatSampleRate = 22050; - } break; - case WAVE_FORMAT_2M16: - { - formatBitsPerSample = 16; - formatChannels = 1; - formatSampleRate = 22050; - } break; - case WAVE_FORMAT_2S08: - { - formatBitsPerSample = 8; - formatChannels = 2; - formatSampleRate = 22050; - } break; - case WAVE_FORMAT_2S16: - { - formatBitsPerSample = 16; - formatChannels = 2; - formatSampleRate = 22050; - } break; - case WAVE_FORMAT_44M08: - { - formatBitsPerSample = 8; - formatChannels = 1; - formatSampleRate = 44100; - } break; - case WAVE_FORMAT_44M16: - { - formatBitsPerSample = 16; - formatChannels = 1; - formatSampleRate = 44100; - } break; - case WAVE_FORMAT_44S08: - { - formatBitsPerSample = 8; - formatChannels = 2; - formatSampleRate = 44100; - } break; - case WAVE_FORMAT_44S16: - { - formatBitsPerSample = 16; - formatChannels = 2; - formatSampleRate = 44100; - } break; - case WAVE_FORMAT_48M08: - { - formatBitsPerSample = 8; - formatChannels = 1; - formatSampleRate = 48000; - } break; - case WAVE_FORMAT_48M16: - { - formatBitsPerSample = 16; - formatChannels = 1; - formatSampleRate = 48000; - } break; - case WAVE_FORMAT_48S08: - { - formatBitsPerSample = 8; - formatChannels = 2; - formatSampleRate = 48000; - } break; - case WAVE_FORMAT_48S16: - { - formatBitsPerSample = 16; - formatChannels = 2; - formatSampleRate = 48000; - } break; - case WAVE_FORMAT_96M08: - { - formatBitsPerSample = 8; - formatChannels = 1; - formatSampleRate = 96000; - } break; - case WAVE_FORMAT_96M16: - { - formatBitsPerSample = 16; - formatChannels = 1; - formatSampleRate = 96000; - } break; - case WAVE_FORMAT_96S08: - { - formatBitsPerSample = 8; - formatChannels = 2; - formatSampleRate = 96000; - } break; - case WAVE_FORMAT_96S16: - { - formatBitsPerSample = 16; - formatChannels = 2; - formatSampleRate = 96000; - } break; - default: - { - errorMsg = "[WinMM] The internal device does not support any of the standard formats.", errorCode = MAL_ERROR; // <-- Should never hit this. - goto on_error; - } break; - } - - if (formatBitsPerSample == wf.wBitsPerSample && formatChannels == wf.nChannels && formatSampleRate == wf.nSamplesPerSec) { - break; // It's an exact match. - } else { - // It's not an exact match. Compare it with the closest match. - if (closestBitsPerSample == 0) { - // This is the first format, so nothing to compare against. - closestBitsPerSample = formatBitsPerSample; - closestChannels = formatChannels; - closestSampleRate = formatSampleRate; - } else { - // Prefer the channel count be the same over the others. - if (formatChannels != closestChannels) { - // Channels aren't equal. Favour the one equal to our desired channel count. - if (formatChannels == wf.nChannels) { - closestBitsPerSample = formatBitsPerSample; - closestChannels = formatChannels; - closestSampleRate = formatSampleRate; - } - } else { - // The channels are equal. Look at the format now. - if (formatBitsPerSample != closestBitsPerSample) { - if (formatBitsPerSample == wf.wBitsPerSample) { - closestBitsPerSample = formatBitsPerSample; - closestChannels = formatChannels; - closestSampleRate = formatSampleRate; - } - } else { - // Both the channels and formats are the same, so now just favour whichever's sample rate is closest to the requested rate. - mal_uint32 closestRateDiff = (closestSampleRate > wf.nSamplesPerSec) ? (closestSampleRate - wf.nSamplesPerSec) : (wf.nSamplesPerSec - closestSampleRate); - mal_uint32 formatRateDiff = (formatSampleRate > wf.nSamplesPerSec) ? (formatSampleRate - wf.nSamplesPerSec) : (wf.nSamplesPerSec - formatSampleRate); - if (formatRateDiff < closestRateDiff) { - closestBitsPerSample = formatBitsPerSample; - closestChannels = formatChannels; - closestSampleRate = formatSampleRate; - } - } - } - } - } - } - } - - wf.wBitsPerSample = closestBitsPerSample; - wf.nChannels = closestChannels; - wf.nSamplesPerSec = closestSampleRate; - wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8; - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; - - - // We use an event to know when a new fragment needs to be enqueued. - pDevice->winmm.hEvent = (mal_handle)CreateEvent(NULL, TRUE, TRUE, NULL); - if (pDevice->winmm.hEvent == NULL) { - errorMsg = "[WinMM] Failed to create event for fragment enqueing.", errorCode = MAL_FAILED_TO_CREATE_EVENT; - goto on_error; - } - - - if (type == mal_device_type_playback) { - MMRESULT result = ((MAL_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); - if (result != MMSYSERR_NOERROR) { - errorMsg = "[WinMM] Failed to open playback device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; - goto on_error; - } - } else { - MMRESULT result = ((MAL_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDevice, winMMDeviceID, &wf, (DWORD_PTR)pDevice->winmm.hEvent, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC); - if (result != MMSYSERR_NOERROR) { - errorMsg = "[WinMM] Failed to open capture device.", errorCode = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; - goto on_error; - } - } - - - // The internal formats need to be set based on the wf object. - if (wf.wFormatTag == WAVE_FORMAT_PCM) { - switch (wf.wBitsPerSample) { - case 8: pDevice->internalFormat = mal_format_u8; break; - case 16: pDevice->internalFormat = mal_format_s16; break; - case 24: pDevice->internalFormat = mal_format_s24; break; - case 32: pDevice->internalFormat = mal_format_s32; break; - default: mal_post_error(pDevice, "[WinMM] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); - } - } else { - errorMsg = "[WinMM] The device's internal format is not supported by mini_al.", errorCode = MAL_FORMAT_NOT_SUPPORTED; - goto on_error; - } - - pDevice->internalChannels = wf.nChannels; - pDevice->internalSampleRate = wf.nSamplesPerSec; - - - // Just use the default channel mapping. WinMM only supports mono or stereo anyway so it'll reliably be left/right order for stereo. - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); - - - // Latency with WinMM seems pretty bad from my testing... Need to increase the default buffer size. - if (pDevice->usingDefaultBufferSize) { - if (pDevice->type == mal_device_type_playback) { - pDevice->bufferSizeInFrames *= 4; // <-- Might need to fiddle with this to find a more ideal value. May even be able to just add a fixed amount rather than scaling. - } else { - pDevice->bufferSizeInFrames *= 2; - } - } - - // The size of the intermediary buffer needs to be able to fit every fragment. - pDevice->winmm.fragmentSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; - pDevice->winmm.fragmentSizeInBytes = pDevice->winmm.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - - heapSize = (sizeof(WAVEHDR) * pDevice->periods) + (pDevice->winmm.fragmentSizeInBytes * pDevice->periods); - pDevice->winmm._pHeapData = (mal_uint8*)mal_malloc(heapSize); - if (pDevice->winmm._pHeapData == NULL) { - errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MAL_OUT_OF_MEMORY; - goto on_error; - } - - mal_zero_memory(pDevice->winmm._pHeapData, pDevice->winmm.fragmentSizeInBytes * pDevice->periods); - - pDevice->winmm.pWAVEHDR = pDevice->winmm._pHeapData; - pDevice->winmm.pIntermediaryBuffer = pDevice->winmm._pHeapData + (sizeof(WAVEHDR) * pDevice->periods); - - - return MAL_SUCCESS; - -on_error: - if (pDevice->type == mal_device_type_playback) { - ((MAL_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevice); - } else { - ((MAL_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDevice); - } - - mal_free(pDevice->winmm._pHeapData); - return mal_post_error(pDevice, errorMsg, errorCode); -} - - -static mal_result mal_device__start_backend__winmm(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - // Playback. The device is started when we call waveOutWrite() with a block of data. From MSDN: - // - // Unless the device is paused by calling the waveOutPause function, playback begins when the first data block is sent to the device. - // - // When starting the device we commit every fragment. We signal the event before calling waveOutWrite(). - mal_uint32 i; - for (i = 0; i < pDevice->periods; ++i) { - mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; - mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); - - if (((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { - return mal_post_error(pDevice, "[WinMM] Failed to start backend device. Failed to prepare header.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - - ResetEvent(pDevice->winmm.hEvent); - - for (i = 0; i < pDevice->periods; ++i) { - if (((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { - return mal_post_error(pDevice, "[WinMM] Failed to start backend device. Failed to send data to the backend device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - } else { - // Capture. - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; - - MMRESULT resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); - break; - } - - resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); - break; - } - } - - ResetEvent(pDevice->winmm.hEvent); - - if (((MAL_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDevice) != MMSYSERR_NOERROR) { - return mal_post_error(pDevice, "[WinMM] Failed to start backend device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - - pDevice->winmm.iNextHeader = 0; - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__winmm(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - MMRESULT resultMM = ((MAL_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevice); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] WARNING: Failed to reset playback device.", mal_result_from_MMRESULT(resultMM)); - } - - // Unprepare all WAVEHDR structures. - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] WARNING: Failed to unprepare header for playback device.", mal_result_from_MMRESULT(resultMM)); - } - } - } else { - MMRESULT resultMM = ((MAL_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDevice); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] WARNING: Failed to reset capture device.", mal_result_from_MMRESULT(resultMM)); - } - - // Unprepare all WAVEHDR structures. - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] WARNING: Failed to unprepare header for playback device.", mal_result_from_MMRESULT(resultMM)); - } - } - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__winmm(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->winmm.breakFromMainLoop = MAL_TRUE; - SetEvent((HANDLE)pDevice->winmm.hEvent); - - return MAL_SUCCESS; -} - -static mal_result mal_device__main_loop__winmm(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_uint32 counter; - - pDevice->winmm.breakFromMainLoop = MAL_FALSE; - while (!pDevice->winmm.breakFromMainLoop) { - // Wait for a block of data to finish processing... - if (WaitForSingleObject((HANDLE)pDevice->winmm.hEvent, INFINITE) != WAIT_OBJECT_0) { - break; - } - - // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } - - // Any headers that are marked as done need to be handled. We start by processing the completed blocks. Then we reset the event - // and then write or add replacement buffers to the device. - mal_uint32 iFirstHeader = pDevice->winmm.iNextHeader; - for (counter = 0; counter < pDevice->periods; ++counter) { - mal_uint32 i = pDevice->winmm.iNextHeader; - if ((((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags & WHDR_DONE) == 0) { - break; - } - - if (pDevice->type == mal_device_type_playback) { - // Playback. - MMRESULT resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to unprepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); - break; - } - - mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 1; // <-- Used in the next section to identify the buffers that needs to be re-written to the device. - mal_device__read_frames_from_client(pDevice, pDevice->winmm.fragmentSizeInFrames, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); - - resultMM = ((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to prepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); - break; - } - } else { - // Capture. - mal_uint32 framesCaptured = (mal_uint32)(((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBytesRecorded) / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); - if (framesCaptured > 0) { - mal_device__send_frames_to_client(pDevice, framesCaptured, ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData); - } - - MMRESULT resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to unprepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); - break; - } - - mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBuffer + (pDevice->winmm.fragmentSizeInBytes * i)); - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwBufferLength = pDevice->winmm.fragmentSizeInBytes; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwFlags = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwLoops = 0L; - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 1; // <-- Used in the next section to identify the buffers that needs to be re-added to the device. - - resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); - break; - } - } - - pDevice->winmm.iNextHeader = (pDevice->winmm.iNextHeader + 1) % pDevice->periods; - } - - ResetEvent((HANDLE)pDevice->winmm.hEvent); - - for (counter = 0; counter < pDevice->periods; ++counter) { - mal_uint32 i = (iFirstHeader + counter) % pDevice->periods; - - if (((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser == 1) { - ((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i].dwUser = 0; - - if (pDevice->type == mal_device_type_playback) { - // Playback. - MMRESULT resultMM = ((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to write data to the internal playback device.", mal_result_from_MMRESULT(resultMM)); - break; - } - } else { - // Capture. - MMRESULT resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); - if (resultMM != MMSYSERR_NOERROR) { - mal_post_error(pDevice, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); - break; - } - } - } - } - } - - return MAL_SUCCESS; -} -#endif - - - -/////////////////////////////////////////////////////////////////////////////// -// -// ALSA Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_ALSA -#include - -// This array allows mini_al to control device-specific default buffer sizes. This uses a scaling factor. Order is important. If -// any part of the string is present in the device's name, the associated scale will be used. -struct -{ - const char* name; - float scale; -} g_malDefaultBufferSizeScalesALSA[] = { - {"bcm2835 IEC958/HDMI", 20}, - {"bcm2835 ALSA", 20} -}; - -static float mal_find_default_buffer_size_scale__alsa(const char* deviceName) -{ - if (deviceName == NULL) { - return 1; - } - - for (size_t i = 0; i < mal_countof(g_malDefaultBufferSizeScalesALSA); ++i) { - if (strstr(g_malDefaultBufferSizeScalesALSA[i].name, deviceName) != NULL) { - return g_malDefaultBufferSizeScalesALSA[i].scale; - } - } - - return 1; -} - - -typedef int (* mal_snd_pcm_open_proc) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); -typedef int (* mal_snd_pcm_close_proc) (snd_pcm_t *pcm); -typedef size_t (* mal_snd_pcm_hw_params_sizeof_proc) (void); -typedef int (* mal_snd_pcm_hw_params_any_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -typedef int (* mal_snd_pcm_hw_params_set_format_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); -typedef int (* mal_snd_pcm_hw_params_set_format_first_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t *format); -typedef void (* mal_snd_pcm_hw_params_get_format_mask_proc) (snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask); -typedef int (* mal_snd_pcm_hw_params_set_channels_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val); -typedef int (* mal_snd_pcm_hw_params_set_rate_resample_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); -typedef int (* mal_snd_pcm_hw_params_set_rate_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -typedef int (* mal_snd_pcm_hw_params_set_buffer_size_near_proc)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -typedef int (* mal_snd_pcm_hw_params_set_periods_near_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -typedef int (* mal_snd_pcm_hw_params_set_access_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); -typedef int (* mal_snd_pcm_hw_params_get_format_proc) (snd_pcm_hw_params_t *params, snd_pcm_format_t *format); -typedef int (* mal_snd_pcm_hw_params_get_channels_proc) (snd_pcm_hw_params_t *params, unsigned int *val); -typedef int (* mal_snd_pcm_hw_params_get_rate_proc) (snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); -typedef int (* mal_snd_pcm_hw_params_get_buffer_size_proc) (snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); -typedef int (* mal_snd_pcm_hw_params_get_periods_proc) (snd_pcm_hw_params_t *params, unsigned int *val, int *dir); -typedef int (* mal_snd_pcm_hw_params_get_access_proc) (snd_pcm_hw_params_t *params, snd_pcm_access_t *_access); -typedef int (* mal_snd_pcm_hw_params_proc) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); -typedef size_t (* mal_snd_pcm_sw_params_sizeof_proc) (void); -typedef int (* mal_snd_pcm_sw_params_current_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); -typedef int (* mal_snd_pcm_sw_params_set_avail_min_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -typedef int (* mal_snd_pcm_sw_params_set_start_threshold_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); -typedef int (* mal_snd_pcm_sw_params_proc) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); -typedef size_t (* mal_snd_pcm_format_mask_sizeof_proc) (void); -typedef int (* mal_snd_pcm_format_mask_test_proc) (const snd_pcm_format_mask_t *mask, snd_pcm_format_t val); -typedef snd_pcm_chmap_t * (* mal_snd_pcm_get_chmap_proc) (snd_pcm_t *pcm); -typedef int (* mal_snd_pcm_prepare_proc) (snd_pcm_t *pcm); -typedef int (* mal_snd_pcm_start_proc) (snd_pcm_t *pcm); -typedef int (* mal_snd_pcm_drop_proc) (snd_pcm_t *pcm); -typedef int (* mal_snd_device_name_hint_proc) (int card, const char *iface, void ***hints); -typedef char * (* mal_snd_device_name_get_hint_proc) (const void *hint, const char *id); -typedef int (* mal_snd_card_get_index_proc) (const char *name); -typedef int (* mal_snd_device_name_free_hint_proc) (void **hints); -typedef int (* mal_snd_pcm_mmap_begin_proc) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); -typedef snd_pcm_sframes_t (* mal_snd_pcm_mmap_commit_proc) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); -typedef int (* mal_snd_pcm_recover_proc) (snd_pcm_t *pcm, int err, int silent); -typedef snd_pcm_sframes_t (* mal_snd_pcm_readi_proc) (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size); -typedef snd_pcm_sframes_t (* mal_snd_pcm_writei_proc) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); -typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_proc) (snd_pcm_t *pcm); -typedef snd_pcm_sframes_t (* mal_snd_pcm_avail_update_proc) (snd_pcm_t *pcm); -typedef int (* mal_snd_pcm_wait_proc) (snd_pcm_t *pcm, int timeout); -typedef int (* mal_snd_pcm_info) (snd_pcm_t *pcm, snd_pcm_info_t* info); -typedef size_t (* mal_snd_pcm_info_sizeof) (); -typedef const char* (* mal_snd_pcm_info_get_name) (const snd_pcm_info_t* info); - -static snd_pcm_format_t g_mal_ALSAFormats[] = { - SND_PCM_FORMAT_UNKNOWN, // mal_format_unknown - SND_PCM_FORMAT_U8, // mal_format_u8 - SND_PCM_FORMAT_S16_LE, // mal_format_s16 - SND_PCM_FORMAT_S24_3LE, // mal_format_s24 - SND_PCM_FORMAT_S32_LE, // mal_format_s32 - SND_PCM_FORMAT_FLOAT_LE // mal_format_f32 -}; - -snd_pcm_format_t mal_convert_mal_format_to_alsa_format(mal_format format) -{ - return g_mal_ALSAFormats[format]; -} - -mal_format mal_convert_alsa_format_to_mal_format(snd_pcm_format_t formatALSA) -{ - switch (formatALSA) - { - case SND_PCM_FORMAT_U8: return mal_format_u8; - case SND_PCM_FORMAT_S16_LE: return mal_format_s16; - case SND_PCM_FORMAT_S24_3LE: return mal_format_s24; - case SND_PCM_FORMAT_S32_LE: return mal_format_s32; - case SND_PCM_FORMAT_FLOAT_LE: return mal_format_f32; - default: return mal_format_unknown; - } -} - -mal_channel mal_convert_alsa_channel_position_to_mal_channel(unsigned int alsaChannelPos) -{ - switch (alsaChannelPos) - { - case SND_CHMAP_FL: return MAL_CHANNEL_FRONT_LEFT; - case SND_CHMAP_FR: return MAL_CHANNEL_FRONT_RIGHT; - case SND_CHMAP_RL: return MAL_CHANNEL_BACK_LEFT; - case SND_CHMAP_RR: return MAL_CHANNEL_BACK_RIGHT; - case SND_CHMAP_FC: return MAL_CHANNEL_FRONT_CENTER; - case SND_CHMAP_LFE: return MAL_CHANNEL_LFE; - case SND_CHMAP_SL: return MAL_CHANNEL_SIDE_LEFT; - case SND_CHMAP_SR: return MAL_CHANNEL_SIDE_RIGHT; - case SND_CHMAP_RC: return MAL_CHANNEL_BACK_CENTER; - case SND_CHMAP_FLC: return MAL_CHANNEL_FRONT_LEFT_CENTER; - case SND_CHMAP_FRC: return MAL_CHANNEL_FRONT_RIGHT_CENTER; - case SND_CHMAP_RLC: return 0; - case SND_CHMAP_RRC: return 0; - case SND_CHMAP_FLW: return 0; - case SND_CHMAP_FRW: return 0; - case SND_CHMAP_FLH: return 0; - case SND_CHMAP_FCH: return 0; - case SND_CHMAP_FRH: return 0; - case SND_CHMAP_TC: return MAL_CHANNEL_TOP_CENTER; - case SND_CHMAP_TFL: return MAL_CHANNEL_TOP_FRONT_LEFT; - case SND_CHMAP_TFR: return MAL_CHANNEL_TOP_FRONT_RIGHT; - case SND_CHMAP_TFC: return MAL_CHANNEL_TOP_FRONT_CENTER; - case SND_CHMAP_TRL: return MAL_CHANNEL_TOP_BACK_LEFT; - case SND_CHMAP_TRR: return MAL_CHANNEL_TOP_BACK_RIGHT; - case SND_CHMAP_TRC: return MAL_CHANNEL_TOP_BACK_CENTER; - default: break; - } - - return 0; -} - -mal_result mal_context_init__alsa(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - pContext->alsa.asoundSO = mal_dlopen("libasound.so"); - if (pContext->alsa.asoundSO == NULL) { - return MAL_NO_BACKEND; - } - - pContext->alsa.snd_pcm_open = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_open"); - pContext->alsa.snd_pcm_close = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_close"); - pContext->alsa.snd_pcm_hw_params_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); - pContext->alsa.snd_pcm_hw_params_any = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); - pContext->alsa.snd_pcm_hw_params_set_format = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); - pContext->alsa.snd_pcm_hw_params_set_format_first = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); - pContext->alsa.snd_pcm_hw_params_get_format_mask = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); - pContext->alsa.snd_pcm_hw_params_set_channels_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); - pContext->alsa.snd_pcm_hw_params_set_rate_resample = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); - pContext->alsa.snd_pcm_hw_params_set_rate_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); - pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); - pContext->alsa.snd_pcm_hw_params_set_periods_near = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); - pContext->alsa.snd_pcm_hw_params_set_access = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); - pContext->alsa.snd_pcm_hw_params_get_format = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); - pContext->alsa.snd_pcm_hw_params_get_channels = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); - pContext->alsa.snd_pcm_hw_params_get_rate = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); - pContext->alsa.snd_pcm_hw_params_get_buffer_size = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); - pContext->alsa.snd_pcm_hw_params_get_periods = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); - pContext->alsa.snd_pcm_hw_params_get_access = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); - pContext->alsa.snd_pcm_hw_params = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params"); - pContext->alsa.snd_pcm_sw_params_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); - pContext->alsa.snd_pcm_sw_params_current = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); - pContext->alsa.snd_pcm_sw_params_set_avail_min = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); - pContext->alsa.snd_pcm_sw_params_set_start_threshold = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); - pContext->alsa.snd_pcm_sw_params = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params"); - pContext->alsa.snd_pcm_format_mask_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); - pContext->alsa.snd_pcm_format_mask_test = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); - pContext->alsa.snd_pcm_get_chmap = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_get_chmap"); - pContext->alsa.snd_pcm_prepare = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_prepare"); - pContext->alsa.snd_pcm_start = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_start"); - pContext->alsa.snd_pcm_drop = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_drop"); - pContext->alsa.snd_device_name_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_hint"); - pContext->alsa.snd_device_name_get_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_get_hint"); - pContext->alsa.snd_card_get_index = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_card_get_index"); - pContext->alsa.snd_device_name_free_hint = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_device_name_free_hint"); - pContext->alsa.snd_pcm_mmap_begin = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); - pContext->alsa.snd_pcm_mmap_commit = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); - pContext->alsa.snd_pcm_recover = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_recover"); - pContext->alsa.snd_pcm_readi = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_readi"); - pContext->alsa.snd_pcm_writei = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_writei"); - pContext->alsa.snd_pcm_avail = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail"); - pContext->alsa.snd_pcm_avail_update = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail_update"); - pContext->alsa.snd_pcm_wait = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_wait"); - pContext->alsa.snd_pcm_info = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info"); - pContext->alsa.snd_pcm_info_sizeof = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); - pContext->alsa.snd_pcm_info_get_name = (mal_proc)mal_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_get_name"); - - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__alsa(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_alsa); - - (void)pContext; - return MAL_SUCCESS; -} - -static const char* mal_find_char(const char* str, char c, int* index) -{ - int i = 0; - for (;;) { - if (str[i] == '\0') { - if (index) *index = -1; - return NULL; - } - - if (str[i] == c) { - if (index) *index = i; - return str + i; - } - - i += 1; - } - - // Should never get here, but treat it as though the character was not found to make me feel - // better inside. - if (index) *index = -1; - return NULL; -} - -// Waits for a number of frames to become available for either capture or playback. The return -// value is the number of frames available. -// -// This will return early if the main loop is broken with mal_device__break_main_loop(). -static mal_uint32 mal_device__wait_for_frames__alsa(mal_device* pDevice, mal_bool32* pRequiresRestart) -{ - mal_assert(pDevice != NULL); - - if (pRequiresRestart) *pRequiresRestart = MAL_FALSE; - - mal_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; - - while (!pDevice->alsa.breakFromMainLoop) { - // Wait for something to become available. The timeout should not affect latency - it's only used to break from the wait - // so we can check whether or not the device has been stopped. - const int timeoutInMilliseconds = 10; - int waitResult = ((mal_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((snd_pcm_t*)pDevice->alsa.pPCM, timeoutInMilliseconds); - if (waitResult < 0) { - if (waitResult == -EPIPE) { - if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, waitResult, MAL_TRUE) < 0) { - return 0; - } - - if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. - } - } - - if (pDevice->alsa.breakFromMainLoop) { - return 0; - } - - snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); - if (framesAvailable < 0) { - if (framesAvailable == -EPIPE) { - if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MAL_TRUE) < 0) { - return 0; - } - - if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. - - // Try again, but if it fails this time just return an error. - framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); - if (framesAvailable < 0) { - return 0; - } - } - } - - // Keep the returned number of samples consistent and based on the period size. - if (framesAvailable >= periodSizeInFrames) { - return periodSizeInFrames; - } - } - - // We'll get here if the loop was terminated. Just return whatever's available. - snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); - if (framesAvailable < 0) { - return 0; - } - - return framesAvailable; -} - -static mal_bool32 mal_device_write__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - if (!mal_device_is_started(pDevice) && mal_device__get_state(pDevice) != MAL_STATE_STARTING) { - return MAL_FALSE; - } - if (pDevice->alsa.breakFromMainLoop) { - return MAL_FALSE; - } - - - if (pDevice->alsa.isUsingMMap) { - // mmap. - mal_bool32 requiresRestart; - mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, &requiresRestart); - if (framesAvailable == 0) { - return MAL_FALSE; - } - - // Don't bother asking the client for more audio data if we're just stopping the device anyway. - if (pDevice->alsa.breakFromMainLoop) { - return MAL_FALSE; - } - - const snd_pcm_channel_area_t* pAreas; - snd_pcm_uframes_t mappedOffset; - snd_pcm_uframes_t mappedFrames = framesAvailable; - while (framesAvailable > 0) { - int result = ((mal_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); - if (result < 0) { - return MAL_FALSE; - } - - if (mappedFrames > 0) { - void* pBuffer = (mal_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); - mal_device__read_frames_from_client(pDevice, mappedFrames, pBuffer); - } - - result = ((mal_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); - if (result < 0 || (snd_pcm_uframes_t)result != mappedFrames) { - ((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, result, MAL_TRUE); - return MAL_FALSE; - } - - if (requiresRestart) { - if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { - return MAL_FALSE; - } - } - - framesAvailable -= mappedFrames; - } - } else { - // readi/writei. - while (!pDevice->alsa.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, NULL); - if (framesAvailable == 0) { - continue; - } - - // Don't bother asking the client for more audio data if we're just stopping the device anyway. - if (pDevice->alsa.breakFromMainLoop) { - return MAL_FALSE; - } - - mal_device__read_frames_from_client(pDevice, framesAvailable, pDevice->alsa.pIntermediaryBuffer); - - snd_pcm_sframes_t framesWritten = ((mal_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); - if (framesWritten < 0) { - if (framesWritten == -EAGAIN) { - continue; // Just keep trying... - } else if (framesWritten == -EPIPE) { - // Underrun. Just recover and try writing again. - if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MAL_TRUE) < 0) { - mal_post_error(pDevice, "[ALSA] Failed to recover device after underrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE); - return MAL_FALSE; - } - - framesWritten = ((mal_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); - if (framesWritten < 0) { - mal_post_error(pDevice, "[ALSA] Failed to write data to the internal device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - return MAL_FALSE; - } - - break; // Success. - } else { - mal_post_error(pDevice, "[ALSA] snd_pcm_writei() failed when writing initial data.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - return MAL_FALSE; - } - } else { - break; // Success. - } - } - } - - return MAL_TRUE; -} - -static mal_bool32 mal_device_read__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - if (!mal_device_is_started(pDevice)) { - return MAL_FALSE; - } - if (pDevice->alsa.breakFromMainLoop) { - return MAL_FALSE; - } - - mal_uint32 framesToSend = 0; - void* pBuffer = NULL; - if (pDevice->alsa.pIntermediaryBuffer == NULL) { - // mmap. - mal_bool32 requiresRestart; - mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, &requiresRestart); - if (framesAvailable == 0) { - return MAL_FALSE; - } - - const snd_pcm_channel_area_t* pAreas; - snd_pcm_uframes_t mappedOffset; - snd_pcm_uframes_t mappedFrames = framesAvailable; - while (framesAvailable > 0) { - int result = ((mal_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames); - if (result < 0) { - return MAL_FALSE; - } - - if (mappedFrames > 0) { - void* pBuffer = (mal_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8); - mal_device__send_frames_to_client(pDevice, mappedFrames, pBuffer); - } - - result = ((mal_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames); - if (result < 0 || (snd_pcm_uframes_t)result != mappedFrames) { - ((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, result, MAL_TRUE); - return MAL_FALSE; - } - - if (requiresRestart) { - if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { - return MAL_FALSE; - } - } - - framesAvailable -= mappedFrames; - } - } else { - // readi/writei. - snd_pcm_sframes_t framesRead = 0; - while (!pDevice->alsa.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, NULL); - if (framesAvailable == 0) { - continue; - } - - framesRead = ((mal_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); - if (framesRead < 0) { - if (framesRead == -EAGAIN) { - continue; // Just keep trying... - } else if (framesRead == -EPIPE) { - // Overrun. Just recover and try reading again. - if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MAL_TRUE) < 0) { - mal_post_error(pDevice, "[ALSA] Failed to recover device after overrun.", MAL_ALSA_FAILED_TO_RECOVER_DEVICE); - return MAL_FALSE; - } - - framesRead = ((mal_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable); - if (framesRead < 0) { - mal_post_error(pDevice, "[ALSA] Failed to read data from the internal device.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); - return MAL_FALSE; - } - - break; // Success. - } else { - return MAL_FALSE; - } - } else { - break; // Success. - } - } - - framesToSend = framesRead; - pBuffer = pDevice->alsa.pIntermediaryBuffer; - } - - if (framesToSend > 0) { - mal_device__send_frames_to_client(pDevice, framesToSend, pBuffer); - } - - return MAL_TRUE; -} - - - -static mal_bool32 mal_is_device_name_in_hw_format__alsa(const char* hwid) -{ - // This function is just checking whether or not hwid is in "hw:%d,%d" format. - - if (hwid == NULL) { - return MAL_FALSE; - } - - if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') { - return MAL_FALSE; - } - - hwid += 3; - - int commaPos; - const char* dev = mal_find_char(hwid, ',', &commaPos); - if (dev == NULL) { - return MAL_FALSE; - } else { - dev += 1; // Skip past the ",". - } - - // Check if the part between the ":" and the "," contains only numbers. If not, return false. - for (int i = 0; i < commaPos; ++i) { - if (hwid[i] < '0' || hwid[i] > '9') { - return MAL_FALSE; - } - } - - // Check if everything after the "," is numeric. If not, return false. - int i = 0; - while (dev[i] != '\0') { - if (dev[i] < '0' || dev[i] > '9') { - return MAL_FALSE; - } - i += 1; - } - - return MAL_TRUE; -} - -static int mal_convert_device_name_to_hw_format__alsa(mal_context* pContext, char* dst, size_t dstSize, const char* src) // Returns 0 on success, non-0 on error. -{ - // src should look something like this: "hw:CARD=I82801AAICH,DEV=0" - - if (dst == NULL) return -1; - if (dstSize < 7) return -1; // Absolute minimum size of the output buffer is 7 bytes. - - *dst = '\0'; // Safety. - if (src == NULL) return -1; - - // If the input name is already in "hw:%d,%d" format, just return that verbatim. - if (mal_is_device_name_in_hw_format__alsa(src)) { - return mal_strcpy_s(dst, dstSize, src); - } - - - int colonPos; - src = mal_find_char(src, ':', &colonPos); - if (src == NULL) { - return -1; // Couldn't find a colon - } - - char card[256]; - - int commaPos; - const char* dev = mal_find_char(src, ',', &commaPos); - if (dev == NULL) { - dev = "0"; - mal_strncpy_s(card, sizeof(card), src+6, (size_t)-1); // +6 = ":CARD=" - } else { - dev = dev + 5; // +5 = ",DEV=" - mal_strncpy_s(card, sizeof(card), src+6, commaPos-6); // +6 = ":CARD=" - } - - int cardIndex = ((mal_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card); - if (cardIndex < 0) { - 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] = ':'; - if (mal_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) { - return -3; - } - if (mal_strcat_s(dst, dstSize, ",") != 0) { - return -3; - } - if (mal_strcat_s(dst, dstSize, dev) != 0) { - return -3; - } - - return 0; -} - -static mal_bool32 mal_does_id_exist_in_list__alsa(mal_device_id* pUniqueIDs, mal_uint32 count, const char* pHWID) -{ - mal_assert(pHWID != NULL); - - for (mal_uint32 i = 0; i < count; ++i) { - if (mal_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) { - return MAL_TRUE; - } - } - - return MAL_FALSE; -} - -static mal_result mal_enumerate_devices__alsa(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - - char** ppDeviceHints; - if (((mal_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { - return MAL_NO_BACKEND; - } - - mal_device_id* pUniqueIDs = NULL; - mal_uint32 uniqueIDCount = 0; - - char** ppNextDeviceHint = ppDeviceHints; - while (*ppNextDeviceHint != NULL) { - char* NAME = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); - char* DESC = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); - char* IOID = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); - - // Only include devices if they are of the correct type. Special cases for "default", "null" and "pulse" - these are included for both playback and capture - // regardless of the IOID setting. - mal_bool32 includeThisDevice = MAL_FALSE; - if (strcmp(NAME, "default") == 0 || strcmp(NAME, "pulse") == 0 || strcmp(NAME, "null") == 0) { - includeThisDevice = MAL_TRUE; - - // Exclude the "null" device if requested. - if (strcmp(NAME, "null") == 0 && pContext->config.alsa.excludeNullDevice) { - includeThisDevice = MAL_FALSE; - } - } else { - if ((type == mal_device_type_playback && (IOID == NULL || strcmp(IOID, "Output") == 0)) || - (type == mal_device_type_capture && (IOID != NULL && strcmp(IOID, "Input" ) == 0))) { - includeThisDevice = MAL_TRUE; - } - } - - - - if (includeThisDevice) { -#if 0 - printf("NAME: %s\n", NAME); - printf("DESC: %s\n", DESC); - printf("IOID: %s\n", IOID); - - char hwid2[256]; - mal_convert_device_name_to_hw_format__alsa(pContext, hwid2, sizeof(hwid2), NAME); - printf("DEVICE ID: %s (%d)\n\n", hwid2, *pCount); -#endif - - char hwid[sizeof(pUniqueIDs->alsa)]; - if (NAME != NULL) { - if (pContext->config.alsa.useVerboseDeviceEnumeration) { - // Verbose mode. Use the name exactly as-is. - mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); - } else { - // Simplified mode. Use ":%d,%d" format. - if (mal_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) { - // 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 and use the most appropriate plugin depending on the - // device type and sharing mode. - char* dst = hwid; - char* src = hwid+2; - while ((*dst++ = *src++)); - } else { - // Conversion to "hw:%d,%d" failed. Just use the name as-is. - mal_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); - } - - if (mal_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) { - 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. - mal_device_id* pNewUniqueIDs = mal_realloc(pUniqueIDs, sizeof(*pUniqueIDs) * (uniqueIDCount + 1)); - if (pNewUniqueIDs == NULL) { - goto next_device; // Failed to allocate memory. - } - - pUniqueIDs = pNewUniqueIDs; - mal_copy_memory(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid)); - uniqueIDCount += 1; - } - } - } else { - mal_zero_memory(hwid, sizeof(hwid)); - } - - if (pInfo != NULL) { - if (infoSize > 0) { - mal_zero_object(pInfo); - mal_strncpy_s(pInfo->id.alsa, sizeof(pInfo->id.alsa), hwid, (size_t)-1); - - // DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose - // device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish - // between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the - // description. - // - // The value in DESC seems to be split into two lines, with the first line being the name of the device and the - // second line being a description of the device. I don't like having the description be across two lines because - // it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line - // being put into parentheses. In simplified mode I'm just stripping the second line entirely. - if (DESC != NULL) { - int lfPos; - const char* line2 = mal_find_char(DESC, '\n', &lfPos); - if (line2 != NULL) { - line2 += 1; // Skip past the new-line character. - - if (pContext->config.alsa.useVerboseDeviceEnumeration) { - // Verbose mode. Put the second line in brackets. - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), DESC, lfPos); - mal_strcat_s (pInfo->name, sizeof(pInfo->name), " ("); - mal_strcat_s (pInfo->name, sizeof(pInfo->name), line2); - mal_strcat_s (pInfo->name, sizeof(pInfo->name), ")"); - } else { - // Simplified mode. Strip the second line entirely. - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), DESC, lfPos); - } - } else { - // There's no second line. Just copy the whole description. - mal_strcpy_s(pInfo->name, sizeof(pInfo->name), DESC); - } - } - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - - next_device: - free(NAME); - free(DESC); - free(IOID); - ppNextDeviceHint += 1; - } - - mal_free(pUniqueIDs); - - ((mal_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); - return MAL_SUCCESS; -} - -static void mal_device_uninit__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if ((snd_pcm_t*)pDevice->alsa.pPCM) { - ((mal_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((snd_pcm_t*)pDevice->alsa.pPCM); - - if (pDevice->alsa.pIntermediaryBuffer != NULL) { - mal_free(pDevice->alsa.pIntermediaryBuffer); - } - } -} - -static mal_result mal_device_init__alsa(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->alsa); - - snd_pcm_format_t formatALSA = mal_convert_mal_format_to_alsa_format(pConfig->format); - snd_pcm_stream_t stream = (type == mal_device_type_playback) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; - - if (pDeviceID == NULL) { - // We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes - // me feel better to try as hard as we can get to get _something_ working. - const char* defaultDeviceNames[] = { - "default", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }; - - if (pConfig->preferExclusiveMode) { - defaultDeviceNames[1] = "hw"; - defaultDeviceNames[2] = "hw:0"; - defaultDeviceNames[3] = "hw:0,0"; - } else { - if (type == mal_device_type_playback) { - defaultDeviceNames[1] = "dmix"; - defaultDeviceNames[2] = "dmix:0"; - defaultDeviceNames[3] = "dmix:0,0"; - } else { - defaultDeviceNames[1] = "dsnoop"; - defaultDeviceNames[2] = "dsnoop:0"; - defaultDeviceNames[3] = "dsnoop:0,0"; - } - defaultDeviceNames[4] = "hw"; - defaultDeviceNames[5] = "hw:0"; - defaultDeviceNames[6] = "hw:0,0"; - } - - mal_bool32 isDeviceOpen = MAL_FALSE; - for (size_t i = 0; i < mal_countof(defaultDeviceNames); ++i) { - if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') { - if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, defaultDeviceNames[i], stream, 0) == 0) { - isDeviceOpen = MAL_TRUE; - break; - } - } - } - - if (!isDeviceOpen) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MAL_ALSA_FAILED_TO_OPEN_DEVICE); - } - } else { - // We're trying to open a specific device. There's a few things to consider here: - // - // mini_al 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 mini_al 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"). - mal_bool32 isDeviceOpen = MAL_FALSE; - if (pDeviceID->alsa[0] != ':') { - // The ID is not in ":0,0" format. Use the ID exactly as-is. - if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, pDeviceID->alsa, stream, 0) == 0) { - isDeviceOpen = MAL_TRUE; - } - } else { - // The ID is in ":0,0" format. Try different plugins depending on the shared mode. - if (pDeviceID->alsa[1] == '\0') { - pDeviceID->alsa[0] = '\0'; // An ID of ":" should be converted to "". - } - - char hwid[256]; - if (!pConfig->preferExclusiveMode) { - if (type == mal_device_type_playback) { - mal_strcpy_s(hwid, sizeof(hwid), "dmix"); - } else { - mal_strcpy_s(hwid, sizeof(hwid), "dsnoop"); - } - - if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) { - if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) { - isDeviceOpen = MAL_TRUE; - } - } - } - - // If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. - if (!isDeviceOpen) { - mal_strcpy_s(hwid, sizeof(hwid), "hw"); - if (mal_strcat_s(hwid, sizeof(hwid), pDeviceID->alsa) == 0) { - if (((mal_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)((snd_pcm_t**)&pDevice->alsa.pPCM, hwid, stream, 0) == 0) { - isDeviceOpen = MAL_TRUE; - } - } - } - } - - if (!isDeviceOpen) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] snd_pcm_open() failed.", MAL_ALSA_FAILED_TO_OPEN_DEVICE); - } - } - - // We may need to scale the size of the buffer depending on the device. - if (pDevice->usingDefaultBufferSize) { - float bufferSizeScale = 1; - - snd_pcm_info_t* pInfo = (snd_pcm_info_t*)alloca(((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); - mal_zero_memory(pInfo, ((mal_snd_pcm_info_sizeof)pContext->alsa.snd_pcm_info_sizeof)()); - - if (((mal_snd_pcm_info)pContext->alsa.snd_pcm_info)((snd_pcm_t*)pDevice->alsa.pPCM, pInfo) == 0) { - const char* deviceName = ((mal_snd_pcm_info_get_name)pContext->alsa.snd_pcm_info_get_name)(pInfo); - if (deviceName != NULL) { - if (strcmp(deviceName, "default") == 0) { - // It's the default device. We need to use DESC from snd_device_name_hint(). - char** ppDeviceHints; - if (((mal_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) { - return MAL_NO_BACKEND; - } - - char** ppNextDeviceHint = ppDeviceHints; - while (*ppNextDeviceHint != NULL) { - char* NAME = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); - char* DESC = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); - char* IOID = ((mal_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); - - mal_bool32 foundDevice = MAL_FALSE; - if ((type == mal_device_type_playback && (IOID == NULL || strcmp(IOID, "Output") == 0)) || - (type == mal_device_type_capture && (IOID != NULL && strcmp(IOID, "Input" ) == 0))) { - if (strcmp(NAME, deviceName) == 0) { - bufferSizeScale = mal_find_default_buffer_size_scale__alsa(DESC); - foundDevice = MAL_TRUE; - } - } - - free(NAME); - free(DESC); - free(IOID); - ppNextDeviceHint += 1; - - if (foundDevice) { - break; - } - } - - ((mal_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints); - } else { - bufferSizeScale = mal_find_default_buffer_size_scale__alsa(deviceName); - } - } - - pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->bufferSizeInFrames * bufferSizeScale); - } - } - - - // Hardware parameters. - snd_pcm_hw_params_t* pHWParams = (snd_pcm_hw_params_t*)alloca(((mal_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); - mal_zero_memory(pHWParams, ((mal_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)()); - - if (((mal_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", MAL_ALSA_FAILED_TO_SET_HW_PARAMS); - } - - - // MMAP Mode - // - // Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. - pDevice->alsa.isUsingMMap = MAL_FALSE; - if (!pConfig->alsa.noMMap && pDevice->type != mal_device_type_capture) { // <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it so I can test it... Contributions welcome. - if (((mal_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) { - pDevice->alsa.isUsingMMap = MAL_TRUE; - } - } - - if (!pDevice->alsa.isUsingMMap) { - if (((mal_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {; - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[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.", MAL_FORMAT_NOT_SUPPORTED); - } - } - - - // Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't - // find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS. - - // Format. - // Try getting every supported format. - snd_pcm_format_mask_t* pFormatMask = (snd_pcm_format_mask_t*)alloca(((mal_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); - mal_zero_memory(pFormatMask, ((mal_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)()); - - ((mal_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask); - - // At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is - // supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one. - if (!((mal_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, formatALSA)) { - // The requested format is not supported so now try running through the list of formats and return the best one. - snd_pcm_format_t preferredFormatsALSA[] = { - SND_PCM_FORMAT_FLOAT_LE, // mal_format_f32 - SND_PCM_FORMAT_S32_LE, // mal_format_s32 - SND_PCM_FORMAT_S24_3LE, // mal_format_s24 - SND_PCM_FORMAT_S16_LE, // mal_format_s16 - SND_PCM_FORMAT_U8 // mal_format_u8 - }; - - formatALSA = SND_PCM_FORMAT_UNKNOWN; - for (size_t i = 0; i < (sizeof(preferredFormatsALSA) / sizeof(preferredFormatsALSA[0])); ++i) { - if (((mal_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, preferredFormatsALSA[i])) { - formatALSA = preferredFormatsALSA[i]; - break; - } - } - - if (formatALSA == SND_PCM_FORMAT_UNKNOWN) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Format not supported. The device does not support any mini_al formats.", MAL_FORMAT_NOT_SUPPORTED); - } - } - - if (((mal_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, formatALSA) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - - pDevice->internalFormat = mal_convert_alsa_format_to_mal_format(formatALSA); - if (pDevice->internalFormat == mal_format_unknown) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] The chosen format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); - } - - // Channels. - mal_uint32 channels = pConfig->channels; - if (((mal_snd_pcm_hw_params_set_channels_near_proc)pContext->alsa.snd_pcm_hw_params_set_channels_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &channels) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - pDevice->internalChannels = channels; - - - // Sample Rate. It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling - // enabled causes problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we - // need to disable resampling. - // - // To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a - // sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling - // doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly - // faster rate. - // - // mini_al has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine - // for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very - // good quality until I get a chance to improve the quality of mini_al's software sample rate conversion. - // - // I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce - // this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins. - ((mal_snd_pcm_hw_params_set_rate_resample_proc)pContext->alsa.snd_pcm_hw_params_set_rate_resample)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, 0); - - mal_uint32 sampleRate = pConfig->sampleRate; - if (((mal_snd_pcm_hw_params_set_rate_near_proc)pContext->alsa.snd_pcm_hw_params_set_rate_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &sampleRate, 0) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - pDevice->internalSampleRate = sampleRate; - - - // Periods. - mal_uint32 periods = pConfig->periods; - int dir = 0; - if (((mal_snd_pcm_hw_params_set_periods_near_proc)pContext->alsa.snd_pcm_hw_params_set_periods_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &periods, &dir) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - pDevice->periods = periods; - - // Buffer Size - snd_pcm_uframes_t actualBufferSize = pDevice->bufferSizeInFrames; - if (((mal_snd_pcm_hw_params_set_buffer_size_near_proc)pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams, &actualBufferSize) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - pDevice->bufferSizeInFrames = actualBufferSize; - - - // Apply hardware parameters. - if (((mal_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)((snd_pcm_t*)pDevice->alsa.pPCM, pHWParams) < 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", MAL_ALSA_FAILED_TO_SET_HW_PARAMS); - } - - - - - // Software parameters. - snd_pcm_sw_params_t* pSWParams = (snd_pcm_sw_params_t*)alloca(((mal_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); - mal_zero_memory(pSWParams, ((mal_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)()); - - if (((mal_snd_pcm_sw_params_current_proc)pContext->alsa.snd_pcm_sw_params_current)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams) != 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); - } - - if (((mal_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams, (pDevice->sampleRate/1000) * 1) != 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", MAL_FORMAT_NOT_SUPPORTED); - } - - if (type == mal_device_type_playback && !pDevice->alsa.isUsingMMap) { // Only playback devices in writei/readi mode need a start threshold. - if (((mal_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams, (pDevice->sampleRate/1000) * 1) != 0) { //mal_prev_power_of_2(pDevice->bufferSizeInFrames/pDevice->periods) - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); - } - } - - if (((mal_snd_pcm_sw_params_proc)pContext->alsa.snd_pcm_sw_params)((snd_pcm_t*)pDevice->alsa.pPCM, pSWParams) != 0) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", MAL_ALSA_FAILED_TO_SET_SW_PARAMS); - } - - - - // If we're _not_ using mmap we need to use an intermediary buffer. - if (!pDevice->alsa.isUsingMMap) { - pDevice->alsa.pIntermediaryBuffer = mal_malloc(pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format)); - if (pDevice->alsa.pIntermediaryBuffer == NULL) { - mal_device_uninit__alsa(pDevice); - return mal_post_error(pDevice, "[ALSA] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); - } - } - - - - // 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. - snd_pcm_chmap_t* pChmap = ((mal_snd_pcm_get_chmap_proc)pContext->alsa.snd_pcm_get_chmap)((snd_pcm_t*)pDevice->alsa.pPCM); - if (pChmap != NULL) { - // There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). - if (pChmap->channels >= pDevice->internalChannels) { - // Drop excess channels. - for (mal_uint32 iChannel = 0; iChannel < pDevice->internalChannels; ++iChannel) { - pDevice->internalChannelMap[iChannel] = mal_convert_alsa_channel_position_to_mal_channel(pChmap->pos[iChannel]); - } - } else { - // Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate - // channels. If validation fails, fall back to defaults. - - // Fill with defaults. - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); - - // Overwrite first pChmap->channels channels. - for (mal_uint32 iChannel = 0; iChannel < pChmap->channels; ++iChannel) { - pDevice->internalChannelMap[iChannel] = mal_convert_alsa_channel_position_to_mal_channel(pChmap->pos[iChannel]); - } - - // Validate. - mal_bool32 isValid = MAL_TRUE; - for (mal_uint32 i = 0; i < pDevice->internalChannels && isValid; ++i) { - for (mal_uint32 j = i+1; j < pDevice->internalChannels; ++j) { - if (pDevice->internalChannelMap[i] == pDevice->internalChannelMap[j]) { - isValid = MAL_FALSE; - break; - } - } - } - - // If our channel map is invalid, fall back to defaults. - if (!isValid) { - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); - } - } - - free(pChmap); - pChmap = NULL; - } else { - // Could not retrieve the channel map. Fall back to a hard-coded assumption. - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); - } - - return MAL_SUCCESS; -} - - -static mal_result mal_device__start_backend__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Prepare the device first... - if (((mal_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { - return mal_post_error(pDevice, "[ALSA] Failed to prepare device.", MAL_ALSA_FAILED_TO_PREPARE_DEVICE); - } - - // ... and then grab an initial chunk from the client. After this is done, the device should - // automatically start playing, since that's how we configured the software parameters. - if (pDevice->type == mal_device_type_playback) { - if (!mal_device_write__alsa(pDevice)) { - return mal_post_error(pDevice, "[ALSA] Failed to write initial chunk of data to the playback device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - } - - // mmap mode requires an explicit start. - if (pDevice->alsa.isUsingMMap) { - if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { - return mal_post_error(pDevice, "[ALSA] Failed to start capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - } else { - if (((mal_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((snd_pcm_t*)pDevice->alsa.pPCM) < 0) { - return mal_post_error(pDevice, "[ALSA] Failed to start capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - ((mal_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((snd_pcm_t*)pDevice->alsa.pPCM); - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Fallback. We just set a variable to tell the worker thread to terminate after handling the - // next bunch of frames. This is a slow way of handling this. - pDevice->alsa.breakFromMainLoop = MAL_TRUE; - return MAL_SUCCESS; -} - -static mal_result mal_device__main_loop__alsa(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->alsa.breakFromMainLoop = MAL_FALSE; - if (pDevice->type == mal_device_type_playback) { - // Playback. Read from client, write to device. - while (!pDevice->alsa.breakFromMainLoop && mal_device_write__alsa(pDevice)) { - } - } else { - // Capture. Read from device, write to client. - while (!pDevice->alsa.breakFromMainLoop && mal_device_read__alsa(pDevice)) { - } - } - - return MAL_SUCCESS; -} -#endif // ALSA - - -/////////////////////////////////////////////////////////////////////////////// -// -// OSS Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_OSS -#include -#include -#include -#include - -#ifndef SNDCTL_DSP_HALT -#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET -#endif - -int mal_open_temp_device__oss() -{ - // The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. - int fd = open("/dev/mixer", O_RDONLY, 0); - if (fd >= 0) { - return fd; - } - - return -1; -} - -mal_result mal_context_init__oss(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - // Try opening a temporary device first so we can get version information. This is closed at the end. - int fd = mal_open_temp_device__oss(); - if (fd == -1) { - return mal_context_post_error(pContext, NULL, "[OSS] Failed to open temporary device for retrieving system properties.", MAL_NO_BACKEND); // Looks liks OSS isn't installed, or there are no available devices. - } - - // Grab the OSS version. - int ossVersion = 0; - int result = ioctl(fd, OSS_GETVERSION, &ossVersion); - if (result == -1) { - close(fd); - return mal_context_post_error(pContext, NULL, "[OSS] Failed to retrieve OSS version.", MAL_NO_BACKEND); - } - - pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); - pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); - - close(fd); - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__oss(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_oss); - - (void)pContext; - return MAL_SUCCESS; -} - -static mal_result mal_enumerate_devices__oss(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - - // The object returned by SNDCTL_SYSINFO will have the information we're after. - int fd = mal_open_temp_device__oss(); - if (fd == -1) { - return mal_context_post_error(pContext, NULL, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MAL_NO_BACKEND); - } - - oss_sysinfo si; - int result = ioctl(fd, SNDCTL_SYSINFO, &si); - if (result != -1) { - for (int iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { - oss_audioinfo ai; - ai.dev = iAudioDevice; - result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); - if (result != -1) { - mal_bool32 includeThisDevice = MAL_FALSE; - if (type == mal_device_type_playback && (ai.caps & PCM_CAP_OUTPUT) != 0) { - includeThisDevice = MAL_TRUE; - } else if (type == mal_device_type_capture && (ai.caps & PCM_CAP_INPUT) != 0) { - includeThisDevice = MAL_TRUE; - } - - if (includeThisDevice) { - if (ai.devnode[0] != '\0') { // <-- Can be blank, according to documentation. - if (pInfo != NULL) { - if (infoSize > 0) { - mal_strncpy_s(pInfo->id.oss, sizeof(pInfo->id.oss), ai.devnode, (size_t)-1); - - // The human readable device name should be in the "ai.handle" variable, but it can - // sometimes be empty in which case we just fall back to "ai.name" which is less user - // friendly, but usually has a value. - if (ai.handle[0] != '\0') { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.handle, (size_t)-1); - } else { - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ai.name, (size_t)-1); - } - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - } - } - } - } else { - // Failed to retrieve the system information. Just return a default device for both playback and capture. - if (pInfo != NULL) { - if (infoSize > 0) { - mal_strncpy_s(pInfo[0].id.oss, sizeof(pInfo[0].id.oss), "/dev/dsp", (size_t)-1); - if (type == mal_device_type_playback) { - mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Playback Device", (size_t)-1); - } else { - mal_strncpy_s(pInfo[0].name, sizeof(pInfo[0].name), "Default Capture Device", (size_t)-1); - } - - *pCount = 1; - } - } else { - *pCount = 1; - } - } - - close(fd); - return MAL_SUCCESS; -} - -static void mal_device_uninit__oss(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - close(pDevice->oss.fd); - mal_free(pDevice->oss.pIntermediaryBuffer); -} - -static mal_result mal_device_init__oss(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->oss); - - char deviceName[64]; - if (pDeviceID != NULL) { - mal_strncpy_s(deviceName, sizeof(deviceName), pDeviceID->oss, (size_t)-1); - } else { - mal_strncpy_s(deviceName, sizeof(deviceName), "/dev/dsp", (size_t)-1); - } - - pDevice->oss.fd = open(deviceName, (type == mal_device_type_playback) ? O_WRONLY : O_RDONLY, 0); - if (pDevice->oss.fd == -1) { - return mal_post_error(pDevice, "[OSS] Failed to open device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - // The OSS documantation is very clear about the order we should be initializing the device's properties: - // 1) Format - // 2) Channels - // 3) Sample rate. - - // Format. - int ossFormat = AFMT_U8; - switch (pDevice->format) { - case mal_format_s16: ossFormat = AFMT_S16_LE; break; - case mal_format_s24: ossFormat = AFMT_S32_LE; break; - case mal_format_s32: ossFormat = AFMT_S32_LE; break; - case mal_format_f32: ossFormat = AFMT_S32_LE; break; - case mal_format_u8: - default: ossFormat = AFMT_U8; break; - } - int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFMT, &ossFormat); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set format.", MAL_FORMAT_NOT_SUPPORTED); - } - - switch (ossFormat) { - case AFMT_U8: pDevice->internalFormat = mal_format_u8; break; - case AFMT_S16_LE: pDevice->internalFormat = mal_format_s16; break; - case AFMT_S32_LE: pDevice->internalFormat = mal_format_s32; break; - default: mal_post_error(pDevice, "[OSS] The device's internal format is not supported by mini_al.", MAL_FORMAT_NOT_SUPPORTED); - } - - - // Channels. - int ossChannels = (int)pConfig->channels; - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_CHANNELS, &ossChannels); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set channel count.", MAL_FORMAT_NOT_SUPPORTED); - } - - pDevice->internalChannels = ossChannels; - - - // Sample rate. - int ossSampleRate = (int)pConfig->sampleRate; - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SPEED, &ossSampleRate); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set sample rate.", MAL_FORMAT_NOT_SUPPORTED); - } - - pDevice->sampleRate = ossSampleRate; - - - - // The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if - // it should be done before or after format/channels/rate. - // - // OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual - // value. - mal_uint32 fragmentSizeInBytes = mal_round_to_power_of_2(pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (fragmentSizeInBytes < 16) { - fragmentSizeInBytes = 16; - } - - mal_uint32 ossFragmentSizePower = 4; - fragmentSizeInBytes >>= 4; - while (fragmentSizeInBytes >>= 1) { - ossFragmentSizePower += 1; - } - - int ossFragment = (int)((pDevice->periods << 16) | ossFragmentSizePower); - result = ioctl(pDevice->oss.fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment); - if (result == -1) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to set fragment size and period count.", MAL_FORMAT_NOT_SUPPORTED); - } - - int actualFragmentSizeInBytes = 1 << (ossFragment & 0xFFFF); - pDevice->oss.fragmentSizeInFrames = actualFragmentSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; - - pDevice->periods = (mal_uint32)(ossFragment >> 16); - pDevice->bufferSizeInFrames = (mal_uint32)(pDevice->oss.fragmentSizeInFrames * pDevice->periods); - - - // Set the internal channel map. Not sure if this can be queried. For now just using our default assumptions. - mal_get_default_channel_mapping(pDevice->pContext->backend, pDevice->internalChannels, pDevice->internalChannelMap); - - - // When not using MMAP mode, we need to use an intermediary buffer for the client <-> device transfer. We do - // everything by the size of a fragment. - pDevice->oss.pIntermediaryBuffer = mal_malloc(actualFragmentSizeInBytes); - if (pDevice->oss.pIntermediaryBuffer == NULL) { - close(pDevice->oss.fd); - return mal_post_error(pDevice, "[OSS] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); - } - - return MAL_SUCCESS; -} - - -static mal_result mal_device__start_backend__oss(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // The device is started by the next calls to read() and write(). For playback it's simple - just read - // data from the client, then write it to the device with write() which will in turn start the device. - // For capture it's a bit less intuitive - we do nothing (it'll be started automatically by the first - // call to read(). - if (pDevice->type == mal_device_type_playback) { - // Playback. - mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); - - int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesWritten == -1) { - return mal_post_error(pDevice, "[OSS] Failed to send initial chunk of data to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - } - } else { - // Capture. Do nothing. - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__oss(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // We want to use SNDCTL_DSP_HALT. From the documentation: - // - // In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread - // that actually reads/writes the audio device. It must not be called by some master thread to kill the - // audio thread. The audio thread will not stop or get any kind of notification that the device was - // stopped by the master thread. The device gets stopped but the next read or write call will silently - // restart the device. - // - // This is actually safe in our case, because this function is only ever called from within our worker - // thread anyway. Just keep this in mind, though... - - int result = ioctl(pDevice->oss.fd, SNDCTL_DSP_HALT, 0); - if (result == -1) { - return mal_post_error(pDevice, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__oss(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->oss.breakFromMainLoop = MAL_TRUE; - return MAL_SUCCESS; -} - -static mal_result mal_device__main_loop__oss(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->oss.breakFromMainLoop = MAL_FALSE; - while (!pDevice->oss.breakFromMainLoop) { - // Break from the main loop if the device isn't started anymore. Likely what's happened is the application - // has requested that the device be stopped. - if (!mal_device_is_started(pDevice)) { - break; - } - - if (pDevice->type == mal_device_type_playback) { - // Playback. - mal_device__read_frames_from_client(pDevice, pDevice->oss.fragmentSizeInFrames, pDevice->oss.pIntermediaryBuffer); - - int bytesWritten = write(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesWritten < 0) { - return mal_post_error(pDevice, "[OSS] Failed to send data from the client to the device.", MAL_FAILED_TO_SEND_DATA_TO_DEVICE); - } - } else { - // Capture. - int bytesRead = read(pDevice->oss.fd, pDevice->oss.pIntermediaryBuffer, pDevice->oss.fragmentSizeInFrames * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (bytesRead < 0) { - return mal_post_error(pDevice, "[OSS] Failed to read data from the device to be sent to the client.", MAL_FAILED_TO_READ_DATA_FROM_DEVICE); - } - - mal_uint32 framesRead = (mal_uint32)bytesRead / pDevice->internalChannels / mal_get_sample_size_in_bytes(pDevice->internalFormat); - mal_device__send_frames_to_client(pDevice, framesRead, pDevice->oss.pIntermediaryBuffer); - } - } - - return MAL_SUCCESS; -} -#endif // OSS - - -/////////////////////////////////////////////////////////////////////////////// -// -// OpenSL|ES Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_OPENSL -#include -#ifdef MAL_ANDROID -#include -#endif - -// Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to mini_al. -static mal_uint8 mal_channel_id_to_mal__opensl(SLuint32 id) -{ - switch (id) - { - case SL_SPEAKER_FRONT_LEFT: return MAL_CHANNEL_FRONT_LEFT; - case SL_SPEAKER_FRONT_RIGHT: return MAL_CHANNEL_FRONT_RIGHT; - case SL_SPEAKER_FRONT_CENTER: return MAL_CHANNEL_FRONT_CENTER; - case SL_SPEAKER_LOW_FREQUENCY: return MAL_CHANNEL_LFE; - case SL_SPEAKER_BACK_LEFT: return MAL_CHANNEL_BACK_LEFT; - case SL_SPEAKER_BACK_RIGHT: return MAL_CHANNEL_BACK_RIGHT; - case SL_SPEAKER_FRONT_LEFT_OF_CENTER: return MAL_CHANNEL_FRONT_LEFT_CENTER; - case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MAL_CHANNEL_FRONT_RIGHT_CENTER; - case SL_SPEAKER_BACK_CENTER: return MAL_CHANNEL_BACK_CENTER; - case SL_SPEAKER_SIDE_LEFT: return MAL_CHANNEL_SIDE_LEFT; - case SL_SPEAKER_SIDE_RIGHT: return MAL_CHANNEL_SIDE_RIGHT; - case SL_SPEAKER_TOP_CENTER: return MAL_CHANNEL_TOP_CENTER; - case SL_SPEAKER_TOP_FRONT_LEFT: return MAL_CHANNEL_TOP_FRONT_LEFT; - case SL_SPEAKER_TOP_FRONT_CENTER: return MAL_CHANNEL_TOP_FRONT_CENTER; - case SL_SPEAKER_TOP_FRONT_RIGHT: return MAL_CHANNEL_TOP_FRONT_RIGHT; - case SL_SPEAKER_TOP_BACK_LEFT: return MAL_CHANNEL_TOP_BACK_LEFT; - case SL_SPEAKER_TOP_BACK_CENTER: return MAL_CHANNEL_TOP_BACK_CENTER; - case SL_SPEAKER_TOP_BACK_RIGHT: return MAL_CHANNEL_TOP_BACK_RIGHT; - default: return 0; - } -} - -// Converts an individual mini_al channel identifier (MAL_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. -static SLuint32 mal_channel_id_to_opensl(mal_uint8 id) -{ - switch (id) - { - case MAL_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; - case MAL_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; - case MAL_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; - case MAL_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; - case MAL_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; - case MAL_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; - case MAL_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; - case MAL_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER; - case MAL_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; - case MAL_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; - case MAL_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; - case MAL_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; - case MAL_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; - case MAL_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; - case MAL_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; - case MAL_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; - case MAL_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; - case MAL_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; - default: return 0; - } -} - -// Converts a channel mapping to an OpenSL-style channel mask. -static SLuint32 mal_channel_map_to_channel_mask__opensl(const mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_uint32 channels) -{ - SLuint32 channelMask = 0; - for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { - channelMask |= mal_channel_id_to_opensl(channelMap[iChannel]); - } - - return channelMask; -} - -// Converts an OpenSL-style channel mask to a mini_al channel map. -static void mal_channel_mask_to_channel_map__opensl(SLuint32 channelMask, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - if (channels == 2 && channelMask == 0) { - channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - } else { - // Just iterate over each bit. - mal_uint32 iChannel = 0; - for (mal_uint32 iBit = 0; iBit < 32; ++iBit) { - SLuint32 bitValue = (channelMask & (1 << iBit)); - if (bitValue != 0) { - // The bit is set. - channelMap[iChannel] = mal_channel_id_to_mal__opensl(bitValue); - iChannel += 1; - } - } - } -} - -SLuint32 mal_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec) -{ - if (samplesPerSec <= SL_SAMPLINGRATE_8) { - return SL_SAMPLINGRATE_8; - } - if (samplesPerSec <= SL_SAMPLINGRATE_11_025) { - return SL_SAMPLINGRATE_11_025; - } - if (samplesPerSec <= SL_SAMPLINGRATE_12) { - return SL_SAMPLINGRATE_12; - } - if (samplesPerSec <= SL_SAMPLINGRATE_16) { - return SL_SAMPLINGRATE_16; - } - if (samplesPerSec <= SL_SAMPLINGRATE_22_05) { - return SL_SAMPLINGRATE_22_05; - } - if (samplesPerSec <= SL_SAMPLINGRATE_24) { - return SL_SAMPLINGRATE_24; - } - if (samplesPerSec <= SL_SAMPLINGRATE_32) { - return SL_SAMPLINGRATE_32; - } - if (samplesPerSec <= SL_SAMPLINGRATE_44_1) { - return SL_SAMPLINGRATE_44_1; - } - if (samplesPerSec <= SL_SAMPLINGRATE_48) { - return SL_SAMPLINGRATE_48; - } - - // Android doesn't support more than 48000. -#ifndef MAL_ANDROID - if (samplesPerSec <= SL_SAMPLINGRATE_64) { - return SL_SAMPLINGRATE_64; - } - if (samplesPerSec <= SL_SAMPLINGRATE_88_2) { - return SL_SAMPLINGRATE_88_2; - } - if (samplesPerSec <= SL_SAMPLINGRATE_96) { - return SL_SAMPLINGRATE_96; - } - if (samplesPerSec <= SL_SAMPLINGRATE_192) { - return SL_SAMPLINGRATE_192; - } -#endif - - return SL_SAMPLINGRATE_16; -} - -mal_result mal_context_init__opensl(mal_context* pContext) -{ - mal_assert(pContext != NULL); - - (void)pContext; - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__opensl(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_opensl); - - (void)pContext; - return MAL_SUCCESS; -} - -mal_result mal_enumerate_devices__opensl(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - - SLObjectItf engineObj; - SLresult resultSL = slCreateEngine(&engineObj, 0, NULL, 0, NULL, NULL); - if (resultSL != SL_RESULT_SUCCESS) { - return MAL_NO_BACKEND; - } - - (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE); - - // TODO: Test Me. - // - // This is currently untested, so for now we are just returning default devices. -#if 0 - SLuint32 pDeviceIDs[128]; - SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]); - - SLAudioIODeviceCapabilitiesItf deviceCaps; - resultSL = (*engineObj)->GetInterface(engineObj, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); - if (resultSL != SL_RESULT_SUCCESS) { - // The interface may not be supported so just report a default device. - (*engineObj)->Destroy(engineObj); - goto return_default_device; - } - - if (type == mal_device_type_playback) { - resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs); - if (resultSL != SL_RESULT_SUCCESS) { - (*engineObj)->Destroy(engineObj); - return MAL_NO_DEVICE; - } - } else { - resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs); - if (resultSL != SL_RESULT_SUCCESS) { - (*engineObj)->Destroy(engineObj); - return MAL_NO_DEVICE; - } - } - - for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { - if (pInfo != NULL) { - if (infoSize > 0) { - mal_zero_object(pInfo); - pInfo->id.opensl = pDeviceIDs[iDevice]; - - mal_bool32 isValidDevice = MAL_TRUE; - if (type == mal_device_type_playback) { - SLAudioOutputDescriptor desc; - resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pInfo->id.opensl, &desc); - if (resultSL != SL_RESULT_SUCCESS) { - isValidDevice = MAL_FALSE; - } - - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)desc.pDeviceName, (size_t)-1); - } else { - SLAudioInputDescriptor desc; - resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pInfo->id.opensl, &desc); - if (resultSL != SL_RESULT_SUCCESS) { - isValidDevice = MAL_FALSE; - } - - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)desc.deviceName, (size_t)-1); - } - - if (isValidDevice) { - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } - } else { - *pCount += 1; - } - } - - (*engineObj)->Destroy(engineObj); - return MAL_SUCCESS; -#else - (*engineObj)->Destroy(engineObj); - goto return_default_device; -#endif - -return_default_device: - *pCount = 1; - if (pInfo != NULL) { - if (infoSize > 0) { - if (type == mal_device_type_playback) { - pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); - } else { - pInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); - } - } - } - - return MAL_SUCCESS; -} - - -// OpenSL|ES has one-per-application objects :( -static SLObjectItf g_malEngineObjectSL = NULL; -static SLEngineItf g_malEngineSL = NULL; -static mal_uint32 g_malOpenSLInitCounter = 0; - -#define MAL_OPENSL_OBJ(p) (*((SLObjectItf)(p))) -#define MAL_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p))) -#define MAL_OPENSL_PLAY(p) (*((SLPlayItf)(p))) -#define MAL_OPENSL_RECORD(p) (*((SLRecordItf)(p))) - -#ifdef MAL_ANDROID -#define MAL_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p))) -#else -#define MAL_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p))) -#endif - -#ifdef MAL_ANDROID -//static void mal_buffer_queue_callback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext) -static void mal_buffer_queue_callback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) -{ - (void)pBufferQueue; - - // For now, only supporting Android implementations of OpenSL|ES since that's the only one I've - // been able to test with and I currently depend on Android-specific extensions (simple buffer - // queues). -#ifndef MAL_ANDROID - return MAL_NO_BACKEND; -#endif - - mal_device* pDevice = (mal_device*)pUserData; - mal_assert(pDevice != NULL); - - // For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like - // OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this, - // but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :( - if (pDevice->state != MAL_STATE_STARTED) { - return; - } - - size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - mal_uint8* pBuffer = pDevice->opensl.pBuffer + (pDevice->opensl.currentBufferIndex * periodSizeInBytes); - - if (pDevice->type == mal_device_type_playback) { - if (pDevice->state != MAL_STATE_STARTED) { - return; - } - - mal_device__read_frames_from_client(pDevice, pDevice->opensl.periodSizeInFrames, pBuffer); - - SLresult resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pBuffer, periodSizeInBytes); - if (resultSL != SL_RESULT_SUCCESS) { - return; - } - } else { - mal_device__send_frames_to_client(pDevice, pDevice->opensl.periodSizeInFrames, pBuffer); - - SLresult resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pBuffer, periodSizeInBytes); - if (resultSL != SL_RESULT_SUCCESS) { - return; - } - } - - pDevice->opensl.currentBufferIndex = (pDevice->opensl.currentBufferIndex + 1) % pDevice->periods; -} -#endif - -static void mal_device_uninit__opensl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - // Uninit device. - if (pDevice->type == mal_device_type_playback) { - if (pDevice->opensl.pAudioPlayerObj) MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj); - if (pDevice->opensl.pOutputMixObj) MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); - } else { - if (pDevice->opensl.pAudioRecorderObj) MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); - } - - mal_free(pDevice->opensl.pBuffer); - - - // Uninit global data. - if (g_malOpenSLInitCounter > 0) { - if (mal_atomic_decrement_32(&g_malOpenSLInitCounter) == 0) { - (*g_malEngineObjectSL)->Destroy(g_malEngineObjectSL); - } - } -} - -static mal_result mal_device_init__opensl(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - (void)pContext; - - // For now, only supporting Android implementations of OpenSL|ES since that's the only one I've - // been able to test with and I currently depend on Android-specific extensions (simple buffer - // queues). -#ifndef MAL_ANDROID - return MAL_NO_BACKEND; -#endif - - // Use s32 as the internal format for when floating point is specified. - if (pConfig->format == mal_format_f32) { - pDevice->internalFormat = mal_format_s32; - } - - // Initialize global data first if applicable. - if (mal_atomic_increment_32(&g_malOpenSLInitCounter) == 1) { - SLresult resultSL = slCreateEngine(&g_malEngineObjectSL, 0, NULL, 0, NULL, NULL); - if (resultSL != SL_RESULT_SUCCESS) { - mal_atomic_decrement_32(&g_malOpenSLInitCounter); - return mal_post_error(pDevice, "[OpenSL] slCreateEngine() failed.", MAL_NO_BACKEND); - } - - (*g_malEngineObjectSL)->Realize(g_malEngineObjectSL, SL_BOOLEAN_FALSE); - - resultSL = (*g_malEngineObjectSL)->GetInterface(g_malEngineObjectSL, SL_IID_ENGINE, &g_malEngineSL); - if (resultSL != SL_RESULT_SUCCESS) { - (*g_malEngineObjectSL)->Destroy(g_malEngineObjectSL); - mal_atomic_decrement_32(&g_malOpenSLInitCounter); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ENGINE interface.", MAL_NO_BACKEND); - } - } - - - // Now we can start initializing the device properly. - mal_assert(pDevice != NULL); - mal_zero_object(&pDevice->opensl); - - pDevice->opensl.currentBufferIndex = 0; - pDevice->opensl.periodSizeInFrames = pDevice->bufferSizeInFrames / pConfig->periods; - pDevice->bufferSizeInFrames = pDevice->opensl.periodSizeInFrames * pConfig->periods; - - SLDataLocator_AndroidSimpleBufferQueue queue; - queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - queue.numBuffers = pConfig->periods; - - SLDataFormat_PCM* pFormat = NULL; - -#if defined(MAL_ANDROID) && __ANDROID_API__ >= 21 - SLAndroidDataFormat_PCM_EX pcmEx; - if (pDevice->format == mal_format_f32 /*|| pDevice->format == mal_format_f64*/) { - pcmEx.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; - pcmEx.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; - } else { - pcmEx.formatType = SL_DATAFORMAT_PCM; - } - pFormat = (SLDataFormat_PCM*)&pcmEx; -#else - SLDataFormat_PCM pcm; - pcm.formatType = SL_DATAFORMAT_PCM; - pFormat = &pcm; -#endif - - pFormat->numChannels = pDevice->channels; - pFormat->samplesPerSec = mal_round_to_standard_sample_rate__opensl(pDevice->sampleRate * 1000); // In millihertz. - pFormat->bitsPerSample = mal_get_sample_size_in_bytes(pDevice->format)*8; - pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. - pFormat->channelMask = mal_channel_map_to_channel_mask__opensl(pConfig->channelMap, pFormat->numChannels); - pFormat->endianness = SL_BYTEORDER_LITTLEENDIAN; - - // Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html - // - Only mono and stereo is supported. - // - Only u8 and s16 formats are supported. - // - Limited to a sample rate of 48000. -#ifdef MAL_ANDROID - if (pFormat->numChannels > 2) { - pFormat->numChannels = 2; - } -#if __ANDROID_API__ >= 21 - if (pFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { - // It's floating point. - mal_assert(pcmEx.representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); - if (pFormat->bitsPerSample > 32) { - pFormat->bitsPerSample = 32; - } - } else { - if (pFormat->bitsPerSample > 16) { - pFormat->bitsPerSample = 16; - } - } -#else - if (pFormat->bitsPerSample > 16) { - pFormat->bitsPerSample = 16; - } -#endif - pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. - - if (pFormat->samplesPerSec > SL_SAMPLINGRATE_48) { - pFormat->samplesPerSec = SL_SAMPLINGRATE_48; - } -#endif - - if (type == mal_device_type_playback) { - SLresult resultSL = (*g_malEngineSL)->CreateOutputMix(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL); - if (resultSL != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to create output mix.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE)) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to realize output mix object.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - // Set the output device. - if (pDeviceID != NULL) { - MAL_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &pDeviceID->opensl); - } - - SLDataSource source; - source.pLocator = &queue; - source.pFormat = pFormat; - - SLDataLocator_OutputMix outmixLocator; - outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX; - outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj; - - SLDataSink sink; - sink.pLocator = &outmixLocator; - sink.pFormat = NULL; - - const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; - const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; - resultSL = (*g_malEngineSL)->CreateAudioPlayer(g_malEngineSL, (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. - pFormat->formatType = SL_DATAFORMAT_PCM; - pFormat->numChannels = 2; - pFormat->samplesPerSec = SL_SAMPLINGRATE_16; - pFormat->bitsPerSample = 16; - pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. - pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - resultSL = (*g_malEngineSL)->CreateAudioPlayer(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); - } - - if (resultSL != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to create audio player.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to realize audio player.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_PLAY, &pDevice->opensl.pAudioPlayer) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueue) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, mal_buffer_queue_callback__opensl_android, pDevice) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to register buffer queue callback.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - } else { - SLDataLocator_IODevice locatorDevice; - locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; - locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; - locatorDevice.deviceID = (pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDeviceID->opensl; - locatorDevice.device = NULL; - - SLDataSource source; - source.pLocator = &locatorDevice; - source.pFormat = NULL; - - SLDataSink sink; - sink.pLocator = &queue; - sink.pFormat = pFormat; - - const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; - const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; - SLresult resultSL = (*g_malEngineSL)->CreateAudioRecorder(g_malEngineSL, (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. - pFormat->formatType = SL_DATAFORMAT_PCM; - pFormat->numChannels = 1; - pFormat->samplesPerSec = SL_SAMPLINGRATE_16; - pFormat->bitsPerSample = 16; - pFormat->containerSize = pFormat->bitsPerSample; // Always tightly packed for now. - pFormat->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - resultSL = (*g_malEngineSL)->CreateAudioRecorder(g_malEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); - } - - if (resultSL != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to create audio recorder.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to realize audio recorder.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_RECORD, &pDevice->opensl.pAudioRecorder) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueue) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - - if (MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, mal_buffer_queue_callback__opensl_android, pDevice) != SL_RESULT_SUCCESS) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to register buffer queue callback.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - } - - - // The internal format is determined by the pFormat object. - mal_bool32 isFloatingPoint = MAL_FALSE; -#if defined(MAL_ANDROID) && __ANDROID_API__ >= 21 - if (pFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { - mal_assert(pcmEx.representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); - isFloatingPoint = MAL_TRUE; - } -#endif - if (isFloatingPoint) { - if (pFormat->bitsPerSample == 32) { - pDevice->internalFormat = mal_format_f32; - } -#if 0 - if (pFormat->bitsPerSample == 64) { - pDevice->internalFormat = mal_format_f64; - } -#endif - } else { - if (pFormat->bitsPerSample == 8) { - pDevice->internalFormat = mal_format_u8; - } else if (pFormat->bitsPerSample == 16) { - pDevice->internalFormat = mal_format_s16; - } else if (pFormat->bitsPerSample == 24) { - pDevice->internalFormat = mal_format_s24; - } else if (pFormat->bitsPerSample == 32) { - pDevice->internalFormat = mal_format_s32; - } - } - - pDevice->internalChannels = pFormat->numChannels; - pDevice->internalSampleRate = pFormat->samplesPerSec / 1000; - mal_channel_mask_to_channel_map__opensl(pFormat->channelMask, pDevice->internalChannels, pDevice->internalChannelMap); - - - size_t bufferSizeInBytes = pDevice->bufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - pDevice->opensl.pBuffer = (mal_uint8*)mal_malloc(bufferSizeInBytes); - if (pDevice->opensl.pBuffer == NULL) { - mal_device_uninit__opensl(pDevice); - return mal_post_error(pDevice, "[OpenSL] Failed to allocate memory for data buffer.", MAL_OUT_OF_MEMORY); - } - - mal_zero_memory(pDevice->opensl.pBuffer, bufferSizeInBytes); - - return MAL_SUCCESS; -} - -static mal_result mal_device__start_backend__opensl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - SLresult resultSL = MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING); - if (resultSL != SL_RESULT_SUCCESS) { - return mal_post_error(pDevice, "[OpenSL] Failed to start internal playback device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - - // We need to enqueue a buffer for each period. - mal_device__read_frames_from_client(pDevice, pDevice->bufferSizeInFrames, pDevice->opensl.pBuffer); - - size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - for (mal_uint32 iPeriod = 0; iPeriod < pDevice->periods; ++iPeriod) { - resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pDevice->opensl.pBuffer + (periodSizeInBytes * iPeriod), periodSizeInBytes); - if (resultSL != SL_RESULT_SUCCESS) { - MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); - return mal_post_error(pDevice, "[OpenSL] Failed to enqueue buffer for playback device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - } else { - SLresult resultSL = MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING); - if (resultSL != SL_RESULT_SUCCESS) { - return mal_post_error(pDevice, "[OpenSL] Failed to start internal capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - - size_t periodSizeInBytes = pDevice->opensl.periodSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat); - for (mal_uint32 iPeriod = 0; iPeriod < pDevice->periods; ++iPeriod) { - resultSL = MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue, pDevice->opensl.pBuffer + (periodSizeInBytes * iPeriod), periodSizeInBytes); - if (resultSL != SL_RESULT_SUCCESS) { - MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); - return mal_post_error(pDevice, "[OpenSL] Failed to enqueue buffer for capture device.", MAL_FAILED_TO_START_BACKEND_DEVICE); - } - } - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__opensl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - SLresult resultSL = MAL_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED); - if (resultSL != SL_RESULT_SUCCESS) { - return mal_post_error(pDevice, "[OpenSL] Failed to stop internal playback device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - } else { - SLresult resultSL = MAL_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); - if (resultSL != SL_RESULT_SUCCESS) { - return mal_post_error(pDevice, "[OpenSL] Failed to stop internal capture device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE); - } - } - - // Make sure any queued buffers are cleared. - MAL_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueue)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueue); - - // 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. - mal_device__set_state(pDevice, MAL_STATE_STOPPED); - if (pDevice->onStop) { - pDevice->onStop(pDevice); - } - - return MAL_SUCCESS; -} -#endif // OpenSL|ES - -/////////////////////////////////////////////////////////////////////////////// -// -// OpenAL Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_OPENAL -#ifdef MAL_WIN32 -#define MAL_AL_APIENTRY __cdecl -#else -#define MAL_AL_APIENTRY -#endif - -#ifdef MAL_NO_RUNTIME_LINKING - #if defined(MAL_APPLE) - #include - #include - #else - #include - #include - #endif -#endif - -typedef struct mal_ALCdevice_struct mal_ALCdevice; -typedef struct mal_ALCcontext_struct mal_ALCcontext; -typedef char mal_ALCboolean; -typedef char mal_ALCchar; -typedef signed char mal_ALCbyte; -typedef unsigned char mal_ALCubyte; -typedef short mal_ALCshort; -typedef unsigned short mal_ALCushort; -typedef int mal_ALCint; -typedef unsigned int mal_ALCuint; -typedef int mal_ALCsizei; -typedef int mal_ALCenum; -typedef float mal_ALCfloat; -typedef double mal_ALCdouble; -typedef void mal_ALCvoid; - -typedef mal_ALCboolean mal_ALboolean; -typedef mal_ALCchar mal_ALchar; -typedef mal_ALCbyte mal_ALbyte; -typedef mal_ALCubyte mal_ALubyte; -typedef mal_ALCshort mal_ALshort; -typedef mal_ALCushort mal_ALushort; -typedef mal_ALCint mal_ALint; -typedef mal_ALCuint mal_ALuint; -typedef mal_ALCsizei mal_ALsizei; -typedef mal_ALCenum mal_ALenum; -typedef mal_ALCfloat mal_ALfloat; -typedef mal_ALCdouble mal_ALdouble; -typedef mal_ALCvoid mal_ALvoid; - -#define MAL_ALC_DEVICE_SPECIFIER 0x1005 -#define MAL_ALC_CAPTURE_DEVICE_SPECIFIER 0x310 -#define MAL_ALC_CAPTURE_SAMPLES 0x312 - -#define MAL_AL_SOURCE_STATE 0x1010 -#define MAL_AL_INITIAL 0x1011 -#define MAL_AL_PLAYING 0x1012 -#define MAL_AL_PAUSED 0x1013 -#define MAL_AL_STOPPED 0x1014 -#define MAL_AL_BUFFERS_PROCESSED 0x1016 - -#define MAL_AL_FORMAT_MONO8 0x1100 -#define MAL_AL_FORMAT_MONO16 0x1101 -#define MAL_AL_FORMAT_STEREO8 0x1102 -#define MAL_AL_FORMAT_STEREO16 0x1103 -#define MAL_AL_FORMAT_MONO_FLOAT32 0x10010 -#define MAL_AL_FORMAT_STEREO_FLOAT32 0x10011 -#define MAL_AL_FORMAT_51CHN16 0x120B -#define MAL_AL_FORMAT_51CHN32 0x120C -#define MAL_AL_FORMAT_51CHN8 0x120A -#define MAL_AL_FORMAT_61CHN16 0x120E -#define MAL_AL_FORMAT_61CHN32 0x120F -#define MAL_AL_FORMAT_61CHN8 0x120D -#define MAL_AL_FORMAT_71CHN16 0x1211 -#define MAL_AL_FORMAT_71CHN32 0x1212 -#define MAL_AL_FORMAT_71CHN8 0x1210 -#define MAL_AL_FORMAT_QUAD16 0x1205 -#define MAL_AL_FORMAT_QUAD32 0x1206 -#define MAL_AL_FORMAT_QUAD8 0x1204 -#define MAL_AL_FORMAT_REAR16 0x1208 -#define MAL_AL_FORMAT_REAR32 0x1209 -#define MAL_AL_FORMAT_REAR8 0x1207 - -typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (mal_ALCdevice *device, const mal_ALCint *attrlist); -typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT) (mal_ALCcontext *context); -typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (mal_ALCcontext *context); -typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (mal_ALCcontext *context); -typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (mal_ALCcontext *context); -typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCGETCURRENTCONTEXT) (void); -typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (mal_ALCcontext *context); -typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const mal_ALCchar *devicename); -typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (mal_ALCdevice *device); -typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (mal_ALCdevice *device); -typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT) (mal_ALCdevice *device, const mal_ALCchar *extname); -typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (mal_ALCdevice *device, const mal_ALCchar *funcname); -typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (mal_ALCdevice *device, const mal_ALCchar *enumname); -typedef const mal_ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (mal_ALCdevice *device, mal_ALCenum param); -typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (mal_ALCdevice *device, mal_ALCenum param, mal_ALCsizei size, mal_ALCint *values); -typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const mal_ALCchar *devicename, mal_ALCuint frequency, mal_ALCenum format, mal_ALCsizei buffersize); -typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE) (mal_ALCdevice *device); -typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (mal_ALCdevice *device); -typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (mal_ALCdevice *device); -typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (mal_ALCdevice *device, mal_ALCvoid *buffer, mal_ALCsizei samples); - -typedef void (MAL_AL_APIENTRY * MAL_LPALENABLE) (mal_ALenum capability); -typedef void (MAL_AL_APIENTRY * MAL_LPALDISABLE) (mal_ALenum capability); -typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISENABLED) (mal_ALenum capability); -typedef const mal_ALchar* (MAL_AL_APIENTRY * MAL_LPALGETSTRING) (mal_ALenum param); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBOOLEANV) (mal_ALenum param, mal_ALboolean *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETINTEGERV) (mal_ALenum param, mal_ALint *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETFLOATV) (mal_ALenum param, mal_ALfloat *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETDOUBLEV) (mal_ALenum param, mal_ALdouble *values); -typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALGETBOOLEAN) (mal_ALenum param); -typedef mal_ALint (MAL_AL_APIENTRY * MAL_LPALGETINTEGER) (mal_ALenum param); -typedef mal_ALfloat (MAL_AL_APIENTRY * MAL_LPALGETFLOAT) (mal_ALenum param); -typedef mal_ALdouble (MAL_AL_APIENTRY * MAL_LPALGETDOUBLE) (mal_ALenum param); -typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETERROR) (void); -typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISEXTENSIONPRESENT) (const mal_ALchar *extname); -typedef void* (MAL_AL_APIENTRY * MAL_LPALGETPROCADDRESS) (const mal_ALchar *fname); -typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETENUMVALUE) (const mal_ALchar *ename); -typedef void (MAL_AL_APIENTRY * MAL_LPALGENSOURCES) (mal_ALsizei n, mal_ALuint *sources); -typedef void (MAL_AL_APIENTRY * MAL_LPALDELETESOURCES) (mal_ALsizei n, const mal_ALuint *sources); -typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISSOURCE) (mal_ALuint source); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat value); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEFV) (mal_ALuint source, mal_ALenum param, const mal_ALfloat *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint value); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEIV) (mal_ALuint source, mal_ALenum param, const mal_ALint *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEFV) (mal_ALuint source, mal_ALenum param, mal_ALfloat *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint *value); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEIV) (mal_ALuint source, mal_ALenum param, mal_ALint *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAYV) (mal_ALsizei n, const mal_ALuint *sources); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOPV) (mal_ALsizei n, const mal_ALuint *sources); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWINDV) (mal_ALsizei n, const mal_ALuint *sources); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSEV) (mal_ALsizei n, const mal_ALuint *sources); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAY) (mal_ALuint source); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOP) (mal_ALuint source); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWIND) (mal_ALuint source); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSE) (mal_ALuint source); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEQUEUEBUFFERS) (mal_ALuint source, mal_ALsizei nb, const mal_ALuint *buffers); -typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEUNQUEUEBUFFERS)(mal_ALuint source, mal_ALsizei nb, mal_ALuint *buffers); -typedef void (MAL_AL_APIENTRY * MAL_LPALGENBUFFERS) (mal_ALsizei n, mal_ALuint *buffers); -typedef void (MAL_AL_APIENTRY * MAL_LPALDELETEBUFFERS) (mal_ALsizei n, const mal_ALuint *buffers); -typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISBUFFER) (mal_ALuint buffer); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERDATA) (mal_ALuint buffer, mal_ALenum format, const mal_ALvoid *data, mal_ALsizei size, mal_ALsizei freq); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERFV) (mal_ALuint buffer, mal_ALenum param, const mal_ALfloat *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint value); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERIV) (mal_ALuint buffer, mal_ALenum param, const mal_ALint *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERFV) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *values); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3); -typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERIV) (mal_ALuint buffer, mal_ALenum param, mal_ALint *values); - -mal_result mal_context_init__openal(mal_context* pContext) -{ - mal_assert(pContext != NULL); - -#ifndef MAL_NO_RUNTIME_LINKING - const char* libName = NULL; -#ifdef MAL_WIN32 - libName = "OpenAL32.dll"; -#endif -#if defined(MAL_UNIX) && !defined(MAL_APPLE) - libName = "libopenal.so"; -#endif -#ifdef MAL_APPLE - libName = "OpenAL.framework/OpenAL"; -#endif - if (libName == NULL) { - return MAL_NO_BACKEND; // Don't know what the library name is called. - } - - - pContext->openal.hOpenAL = mal_dlopen(libName); - -#ifdef MAL_WIN32 - // Special case for Win32 - try "soft_oal.dll" for OpenAL-Soft drop-ins. - if (pContext->openal.hOpenAL == NULL) { - pContext->openal.hOpenAL = mal_dlopen("soft_oal.dll"); - } -#endif - - if (pContext->openal.hOpenAL == NULL) { - return MAL_FAILED_TO_INIT_BACKEND; - } - - pContext->openal.alcCreateContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCreateContext"); - pContext->openal.alcMakeContextCurrent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcMakeContextCurrent"); - pContext->openal.alcProcessContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcProcessContext"); - pContext->openal.alcSuspendContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcSuspendContext"); - pContext->openal.alcDestroyContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcDestroyContext"); - pContext->openal.alcGetCurrentContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetCurrentContext"); - pContext->openal.alcGetContextsDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetContextsDevice"); - pContext->openal.alcOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcOpenDevice"); - pContext->openal.alcCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCloseDevice"); - pContext->openal.alcGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetError"); - pContext->openal.alcIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcIsExtensionPresent"); - pContext->openal.alcGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetProcAddress"); - pContext->openal.alcGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetEnumValue"); - pContext->openal.alcGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetString"); - pContext->openal.alcGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetIntegerv"); - pContext->openal.alcCaptureOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureOpenDevice"); - pContext->openal.alcCaptureCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureCloseDevice"); - pContext->openal.alcCaptureStart = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStart"); - pContext->openal.alcCaptureStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStop"); - pContext->openal.alcCaptureSamples = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureSamples"); - - pContext->openal.alEnable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alEnable"); - pContext->openal.alDisable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDisable"); - pContext->openal.alIsEnabled = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsEnabled"); - pContext->openal.alGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetString"); - pContext->openal.alGetBooleanv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBooleanv"); - pContext->openal.alGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetIntegerv"); - pContext->openal.alGetFloatv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloatv"); - pContext->openal.alGetDoublev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDoublev"); - pContext->openal.alGetBoolean = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBoolean"); - pContext->openal.alGetInteger = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetInteger"); - pContext->openal.alGetFloat = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloat"); - pContext->openal.alGetDouble = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDouble"); - pContext->openal.alGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetError"); - pContext->openal.alIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsExtensionPresent"); - pContext->openal.alGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetProcAddress"); - pContext->openal.alGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetEnumValue"); - pContext->openal.alGenSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenSources"); - pContext->openal.alDeleteSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteSources"); - pContext->openal.alIsSource = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsSource"); - pContext->openal.alSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcef"); - pContext->openal.alSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3f"); - pContext->openal.alSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcefv"); - pContext->openal.alSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcei"); - pContext->openal.alSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3i"); - pContext->openal.alSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceiv"); - pContext->openal.alGetSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcef"); - pContext->openal.alGetSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3f"); - pContext->openal.alGetSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcefv"); - pContext->openal.alGetSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcei"); - pContext->openal.alGetSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3i"); - pContext->openal.alGetSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourceiv"); - pContext->openal.alSourcePlayv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlayv"); - pContext->openal.alSourceStopv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStopv"); - pContext->openal.alSourceRewindv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewindv"); - pContext->openal.alSourcePausev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePausev"); - pContext->openal.alSourcePlay = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlay"); - pContext->openal.alSourceStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStop"); - pContext->openal.alSourceRewind = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewind"); - pContext->openal.alSourcePause = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePause"); - pContext->openal.alSourceQueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceQueueBuffers"); - pContext->openal.alSourceUnqueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceUnqueueBuffers"); - pContext->openal.alGenBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenBuffers"); - pContext->openal.alDeleteBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteBuffers"); - pContext->openal.alIsBuffer = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsBuffer"); - pContext->openal.alBufferData = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferData"); - pContext->openal.alBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferf"); - pContext->openal.alBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3f"); - pContext->openal.alBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferfv"); - pContext->openal.alBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferi"); - pContext->openal.alBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3i"); - pContext->openal.alBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferiv"); - pContext->openal.alGetBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferf"); - pContext->openal.alGetBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3f"); - pContext->openal.alGetBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferfv"); - pContext->openal.alGetBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferi"); - pContext->openal.alGetBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3i"); - pContext->openal.alGetBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferiv"); -#else - pContext->openal.alcCreateContext = (mal_proc)alcCreateContext; - pContext->openal.alcMakeContextCurrent = (mal_proc)alcMakeContextCurrent; - pContext->openal.alcProcessContext = (mal_proc)alcProcessContext; - pContext->openal.alcSuspendContext = (mal_proc)alcSuspendContext; - pContext->openal.alcDestroyContext = (mal_proc)alcDestroyContext; - pContext->openal.alcGetCurrentContext = (mal_proc)alcGetCurrentContext; - pContext->openal.alcGetContextsDevice = (mal_proc)alcGetContextsDevice; - pContext->openal.alcOpenDevice = (mal_proc)alcOpenDevice; - pContext->openal.alcCloseDevice = (mal_proc)alcCloseDevice; - pContext->openal.alcGetError = (mal_proc)alcGetError; - pContext->openal.alcIsExtensionPresent = (mal_proc)alcIsExtensionPresent; - pContext->openal.alcGetProcAddress = (mal_proc)alcGetProcAddress; - pContext->openal.alcGetEnumValue = (mal_proc)alcGetEnumValue; - pContext->openal.alcGetString = (mal_proc)alcGetString; - pContext->openal.alcGetIntegerv = (mal_proc)alcGetIntegerv; - pContext->openal.alcCaptureOpenDevice = (mal_proc)alcCaptureOpenDevice; - pContext->openal.alcCaptureCloseDevice = (mal_proc)alcCaptureCloseDevice; - pContext->openal.alcCaptureStart = (mal_proc)alcCaptureStart; - pContext->openal.alcCaptureStop = (mal_proc)alcCaptureStop; - pContext->openal.alcCaptureSamples = (mal_proc)alcCaptureSamples; - - pContext->openal.alEnable = (mal_proc)alEnable; - pContext->openal.alDisable = (mal_proc)alDisable; - pContext->openal.alIsEnabled = (mal_proc)alIsEnabled; - pContext->openal.alGetString = (mal_proc)alGetString; - pContext->openal.alGetBooleanv = (mal_proc)alGetBooleanv; - pContext->openal.alGetIntegerv = (mal_proc)alGetIntegerv; - pContext->openal.alGetFloatv = (mal_proc)alGetFloatv; - pContext->openal.alGetDoublev = (mal_proc)alGetDoublev; - pContext->openal.alGetBoolean = (mal_proc)alGetBoolean; - pContext->openal.alGetInteger = (mal_proc)alGetInteger; - pContext->openal.alGetFloat = (mal_proc)alGetFloat; - pContext->openal.alGetDouble = (mal_proc)alGetDouble; - pContext->openal.alGetError = (mal_proc)alGetError; - pContext->openal.alIsExtensionPresent = (mal_proc)alIsExtensionPresent; - pContext->openal.alGetProcAddress = (mal_proc)alGetProcAddress; - pContext->openal.alGetEnumValue = (mal_proc)alGetEnumValue; - pContext->openal.alGenSources = (mal_proc)alGenSources; - pContext->openal.alDeleteSources = (mal_proc)alDeleteSources; - pContext->openal.alIsSource = (mal_proc)alIsSource; - pContext->openal.alSourcef = (mal_proc)alSourcef; - pContext->openal.alSource3f = (mal_proc)alSource3f; - pContext->openal.alSourcefv = (mal_proc)alSourcefv; - pContext->openal.alSourcei = (mal_proc)alSourcei; - pContext->openal.alSource3i = (mal_proc)alSource3i; - pContext->openal.alSourceiv = (mal_proc)alSourceiv; - pContext->openal.alGetSourcef = (mal_proc)alGetSourcef; - pContext->openal.alGetSource3f = (mal_proc)alGetSource3f; - pContext->openal.alGetSourcefv = (mal_proc)alGetSourcefv; - pContext->openal.alGetSourcei = (mal_proc)alGetSourcei; - pContext->openal.alGetSource3i = (mal_proc)alGetSource3i; - pContext->openal.alGetSourceiv = (mal_proc)alGetSourceiv; - pContext->openal.alSourcePlayv = (mal_proc)alSourcePlayv; - pContext->openal.alSourceStopv = (mal_proc)alSourceStopv; - pContext->openal.alSourceRewindv = (mal_proc)alSourceRewindv; - pContext->openal.alSourcePausev = (mal_proc)alSourcePausev; - pContext->openal.alSourcePlay = (mal_proc)alSourcePlay; - pContext->openal.alSourceStop = (mal_proc)alSourceStop; - pContext->openal.alSourceRewind = (mal_proc)alSourceRewind; - pContext->openal.alSourcePause = (mal_proc)alSourcePause; - pContext->openal.alSourceQueueBuffers = (mal_proc)alSourceQueueBuffers; - pContext->openal.alSourceUnqueueBuffers = (mal_proc)alSourceUnqueueBuffers; - pContext->openal.alGenBuffers = (mal_proc)alGenBuffers; - pContext->openal.alDeleteBuffers = (mal_proc)alDeleteBuffers; - pContext->openal.alIsBuffer = (mal_proc)alIsBuffer; - pContext->openal.alBufferData = (mal_proc)alBufferData; - pContext->openal.alBufferf = (mal_proc)alBufferf; - pContext->openal.alBuffer3f = (mal_proc)alBuffer3f; - pContext->openal.alBufferfv = (mal_proc)alBufferfv; - pContext->openal.alBufferi = (mal_proc)alBufferi; - pContext->openal.alBuffer3i = (mal_proc)alBuffer3i; - pContext->openal.alBufferiv = (mal_proc)alBufferiv; - pContext->openal.alGetBufferf = (mal_proc)alGetBufferf; - pContext->openal.alGetBuffer3f = (mal_proc)alGetBuffer3f; - pContext->openal.alGetBufferfv = (mal_proc)alGetBufferfv; - pContext->openal.alGetBufferi = (mal_proc)alGetBufferi; - pContext->openal.alGetBuffer3i = (mal_proc)alGetBuffer3i; - pContext->openal.alGetBufferiv = (mal_proc)alGetBufferiv; -#endif - - // We depend on the ALC_ENUMERATION_EXT extension for enumeration. If this is not supported we fall back to default devices. - pContext->openal.isEnumerationSupported = ((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT"); - pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32"); - pContext->openal.isMCFormatsSupported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_MCFORMATS"); - - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__openal(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_openal); - -#ifndef MAL_NO_RUNTIME_LINKING - mal_dlclose(pContext->openal.hOpenAL); -#endif - - return MAL_SUCCESS; -} - -mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - mal_uint32 infoSize = *pCount; - *pCount = 0; - - if (pContext->openal.isEnumerationSupported) { - const mal_ALCchar* pDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, (type == mal_device_type_playback) ? MAL_ALC_DEVICE_SPECIFIER : MAL_ALC_CAPTURE_DEVICE_SPECIFIER); - if (pDeviceNames == NULL) { - return MAL_NO_DEVICE; - } - - // Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated. - const mal_ALCchar* pNextDeviceName = pDeviceNames; - while (pNextDeviceName[0] != '\0') { - if (pInfo != NULL) { - if (infoSize > 0) { - mal_strncpy_s(pInfo->id.openal, sizeof(pInfo->id.openal), (const char*)pNextDeviceName, (size_t)-1); - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), (const char*)pNextDeviceName, (size_t)-1); - - pInfo += 1; - infoSize -= 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - - // Move to the next device name. - while (*pNextDeviceName != '\0') { - pNextDeviceName += 1; - } - - // Skip past the null terminator. - pNextDeviceName += 1; - }; - } else { - // Enumeration is not supported. Use default devices. - if (pInfo != NULL) { - if (infoSize > 0) { - if (type == mal_device_type_playback) { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); - } else { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); - } - - pInfo += 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - - return MAL_SUCCESS; -} - -void mal_device_uninit__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(NULL); - ((MAL_LPALCDESTROYCONTEXT)pDevice->pContext->openal.alcDestroyContext)((mal_ALCcontext*)pDevice->openal.pContextALC); - - if (pDevice->type == mal_device_type_playback) { - ((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC); - } else { - ((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC); - } - - mal_free(pDevice->openal.pIntermediaryBuffer); -} - -mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - if (pDevice->periods > MAL_MAX_PERIODS_OPENAL) { - pDevice->periods = MAL_MAX_PERIODS_OPENAL; - } - - // OpenAL has bad latency in my testing :( - if (pDevice->usingDefaultBufferSize) { - pDevice->bufferSizeInFrames *= 4; - } - - mal_ALCsizei bufferSizeInSamplesAL = pDevice->bufferSizeInFrames; - mal_ALCuint frequencyAL = pConfig->sampleRate; - - mal_uint32 channelsAL = 0; - - // OpenAL currently only supports only mono and stereo. TODO: Check for the AL_EXT_MCFORMATS extension and use one of those formats for quad, 5.1, etc. - mal_ALCenum formatAL = 0; - if (pConfig->channels == 1) { - // Mono. - channelsAL = 1; - if (pConfig->format == mal_format_f32) { - if (pContext->openal.isFloat32Supported) { - formatAL = MAL_AL_FORMAT_MONO_FLOAT32; - } else { - formatAL = MAL_AL_FORMAT_MONO16; - } - } else if (pConfig->format == mal_format_s32) { - formatAL = MAL_AL_FORMAT_MONO16; - } else if (pConfig->format == mal_format_s24) { - formatAL = MAL_AL_FORMAT_MONO16; - } else if (pConfig->format == mal_format_s16) { - formatAL = MAL_AL_FORMAT_MONO16; - } else if (pConfig->format == mal_format_u8) { - formatAL = MAL_AL_FORMAT_MONO8; - } - } else { - // Stereo. - channelsAL = 2; - if (pConfig->format == mal_format_f32) { - if (pContext->openal.isFloat32Supported) { - formatAL = MAL_AL_FORMAT_STEREO_FLOAT32; - } else { - formatAL = MAL_AL_FORMAT_STEREO16; - } - } else if (pConfig->format == mal_format_s32) { - formatAL = MAL_AL_FORMAT_STEREO16; - } else if (pConfig->format == mal_format_s24) { - formatAL = MAL_AL_FORMAT_STEREO16; - } else if (pConfig->format == mal_format_s16) { - formatAL = MAL_AL_FORMAT_STEREO16; - } else if (pConfig->format == mal_format_u8) { - formatAL = MAL_AL_FORMAT_STEREO8; - } - } - - if (formatAL == 0) { - return mal_context_post_error(pContext, NULL, "[OpenAL] Format not supported.", MAL_FORMAT_NOT_SUPPORTED); - } - - bufferSizeInSamplesAL *= channelsAL; - - - // OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have - // many context's... - mal_ALCdevice* pDeviceALC = NULL; - if (type == mal_device_type_playback) { - pDeviceALC = ((MAL_LPALCOPENDEVICE)pContext->openal.alcOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal); - } else { - pDeviceALC = ((MAL_LPALCCAPTUREOPENDEVICE)pContext->openal.alcCaptureOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal, frequencyAL, formatAL, bufferSizeInSamplesAL); - } - - if (pDeviceALC == NULL) { - return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to open device.", MAL_FAILED_TO_INIT_BACKEND); - } - - // A context is only required for playback. - mal_ALCcontext* pContextALC = NULL; - if (pDevice->type == mal_device_type_playback) { - pContextALC = ((MAL_LPALCCREATECONTEXT)pContext->openal.alcCreateContext)(pDeviceALC, NULL); - if (pContextALC == NULL) { - ((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)(pDeviceALC); - return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to open OpenAL context.", MAL_FAILED_TO_INIT_BACKEND); - } - - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(pContextALC); - - mal_ALuint sourceAL; - ((MAL_LPALGENSOURCES)pDevice->pContext->openal.alGenSources)(1, &sourceAL); - pDevice->openal.sourceAL = sourceAL; - - // We create the buffers, but only fill and queue them when the device is started. - mal_ALuint buffersAL[MAL_MAX_PERIODS_OPENAL]; - ((MAL_LPALGENBUFFERS)pDevice->pContext->openal.alGenBuffers)(pDevice->periods, buffersAL); - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - pDevice->openal.buffersAL[i] = buffersAL[i]; - } - } - - pDevice->internalChannels = channelsAL; - pDevice->internalSampleRate = frequencyAL; - - // The internal format is a little bit straight with OpenAL. - switch (formatAL) - { - case MAL_AL_FORMAT_MONO8: - case MAL_AL_FORMAT_STEREO8: - case MAL_AL_FORMAT_REAR8: - case MAL_AL_FORMAT_QUAD8: - case MAL_AL_FORMAT_51CHN8: - case MAL_AL_FORMAT_61CHN8: - case MAL_AL_FORMAT_71CHN8: - { - pDevice->internalFormat = mal_format_u8; - } break; - - case MAL_AL_FORMAT_MONO16: - case MAL_AL_FORMAT_STEREO16: - case MAL_AL_FORMAT_REAR16: - case MAL_AL_FORMAT_QUAD16: - case MAL_AL_FORMAT_51CHN16: - case MAL_AL_FORMAT_61CHN16: - case MAL_AL_FORMAT_71CHN16: - { - pDevice->internalFormat = mal_format_s16; - } break; - - case MAL_AL_FORMAT_REAR32: - case MAL_AL_FORMAT_QUAD32: - case MAL_AL_FORMAT_51CHN32: - case MAL_AL_FORMAT_61CHN32: - case MAL_AL_FORMAT_71CHN32: - { - pDevice->internalFormat = mal_format_s32; - } break; - - case MAL_AL_FORMAT_MONO_FLOAT32: - case MAL_AL_FORMAT_STEREO_FLOAT32: - { - pDevice->internalFormat = mal_format_f32; - } break; - } - - // From what I can tell, the ordering of channels is fixed for OpenAL. - switch (formatAL) - { - case MAL_AL_FORMAT_MONO8: - case MAL_AL_FORMAT_MONO16: - case MAL_AL_FORMAT_MONO_FLOAT32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_CENTER; - } break; - - case MAL_AL_FORMAT_STEREO8: - case MAL_AL_FORMAT_STEREO16: - case MAL_AL_FORMAT_STEREO_FLOAT32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - } break; - - case MAL_AL_FORMAT_REAR8: - case MAL_AL_FORMAT_REAR16: - case MAL_AL_FORMAT_REAR32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_BACK_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_BACK_RIGHT; - } break; - - case MAL_AL_FORMAT_QUAD8: - case MAL_AL_FORMAT_QUAD16: - case MAL_AL_FORMAT_QUAD32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - pDevice->internalChannelMap[2] = MAL_CHANNEL_BACK_LEFT; - pDevice->internalChannelMap[3] = MAL_CHANNEL_BACK_RIGHT; - } break; - - case MAL_AL_FORMAT_51CHN8: - case MAL_AL_FORMAT_51CHN16: - case MAL_AL_FORMAT_51CHN32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; - pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; - pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT; - pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT; - } break; - - case MAL_AL_FORMAT_61CHN8: - case MAL_AL_FORMAT_61CHN16: - case MAL_AL_FORMAT_61CHN32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; - pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; - pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_CENTER; - pDevice->internalChannelMap[5] = MAL_CHANNEL_SIDE_LEFT; - pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_RIGHT; - } break; - - case MAL_AL_FORMAT_71CHN8: - case MAL_AL_FORMAT_71CHN16: - case MAL_AL_FORMAT_71CHN32: - { - pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT; - pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER; - pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE; - pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT; - pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT; - pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_LEFT; - pDevice->internalChannelMap[7] = MAL_CHANNEL_SIDE_RIGHT; - } break; - - default: break; - } - - pDevice->openal.pDeviceALC = pDeviceALC; - pDevice->openal.pContextALC = pContextALC; - pDevice->openal.formatAL = formatAL; - pDevice->openal.subBufferSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; - pDevice->openal.pIntermediaryBuffer = (mal_uint8*)mal_malloc(pDevice->openal.subBufferSizeInFrames * channelsAL * mal_get_sample_size_in_bytes(pDevice->internalFormat)); - if (pDevice->openal.pIntermediaryBuffer == NULL) { - mal_device_uninit__openal(pDevice); - return mal_context_post_error(pContext, NULL, "[OpenAL] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__start_backend__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - // Playback. - // - // When starting playback we want to ensure each buffer is filled and queued before playing the source. - pDevice->openal.iNextBuffer = 0; - - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); - - for (mal_uint32 i = 0; i < pDevice->periods; ++i) { - mal_device__read_frames_from_client(pDevice, pDevice->openal.subBufferSizeInFrames, pDevice->openal.pIntermediaryBuffer); - - mal_ALuint bufferAL = pDevice->openal.buffersAL[i]; - ((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat), pDevice->internalSampleRate); - ((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); - } - - // Start the source only after filling and queueing each buffer. - ((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL); - } else { - // Capture. - ((MAL_LPALCCAPTURESTART)pDevice->pContext->openal.alcCaptureStart)((mal_ALCdevice*)pDevice->openal.pDeviceALC); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); - ((MAL_LPALSOURCESTOP)pDevice->pContext->openal.alSourceStop)(pDevice->openal.sourceAL); - } else { - ((MAL_LPALCCAPTURESTOP)pDevice->pContext->openal.alcCaptureStop)((mal_ALCdevice*)pDevice->openal.pDeviceALC); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__break_main_loop__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->openal.breakFromMainLoop = MAL_TRUE; - return MAL_SUCCESS; -} - -static mal_uint32 mal_device__get_available_frames__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - if (pDevice->type == mal_device_type_playback) { - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); - - mal_ALint processedBufferCount = 0; - ((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_BUFFERS_PROCESSED, &processedBufferCount); - - return processedBufferCount * pDevice->openal.subBufferSizeInFrames; - } else { - mal_ALint samplesAvailable = 0; - ((MAL_LPALCGETINTEGERV)pDevice->pContext->openal.alcGetIntegerv)((mal_ALCdevice*)pDevice->openal.pDeviceALC, MAL_ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); - - return samplesAvailable / pDevice->channels; - } -} - -static mal_uint32 mal_device__wait_for_frames__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - while (!pDevice->openal.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__get_available_frames__openal(pDevice); - if (framesAvailable > 0) { - return framesAvailable; - } - - mal_sleep(1); - } - - // We'll get here if the loop was terminated. When capturing we want to return whatever is available. For playback we just drop it. - if (pDevice->type == mal_device_type_playback) { - return 0; - } else { - return mal_device__get_available_frames__openal(pDevice); - } -} - -static mal_result mal_device__main_loop__openal(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - pDevice->openal.breakFromMainLoop = MAL_FALSE; - while (!pDevice->openal.breakFromMainLoop) { - mal_uint32 framesAvailable = mal_device__wait_for_frames__openal(pDevice); - if (framesAvailable == 0) { - continue; - } - - // If it's a playback device, don't bother grabbing more data if the device is being stopped. - if (pDevice->openal.breakFromMainLoop && pDevice->type == mal_device_type_playback) { - return MAL_FALSE; - } - - if (pDevice->type == mal_device_type_playback) { - while (framesAvailable > 0) { - mal_uint32 framesToRead = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable; - - mal_ALuint bufferAL = pDevice->openal.buffersAL[pDevice->openal.iNextBuffer]; - pDevice->openal.iNextBuffer = (pDevice->openal.iNextBuffer + 1) % pDevice->periods; - - mal_device__read_frames_from_client(pDevice, framesToRead, pDevice->openal.pIntermediaryBuffer); - - ((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC); - ((MAL_LPALSOURCEUNQUEUEBUFFERS)pDevice->pContext->openal.alSourceUnqueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); - ((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_sample_size_in_bytes(pDevice->internalFormat), pDevice->internalSampleRate); - ((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL); - - framesAvailable -= framesToRead; - } - - - // There's a chance the source has stopped playing due to there not being any buffer's queue. Make sure it's restarted. - mal_ALenum state; - ((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_SOURCE_STATE, &state); - - if (state != MAL_AL_PLAYING) { - ((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL); - } - } else { - while (framesAvailable > 0) { - mal_uint32 framesToSend = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable; - ((MAL_LPALCCAPTURESAMPLES)pDevice->pContext->openal.alcCaptureSamples)((mal_ALCdevice*)pDevice->openal.pDeviceALC, pDevice->openal.pIntermediaryBuffer, framesToSend); - - mal_device__send_frames_to_client(pDevice, framesToSend, pDevice->openal.pIntermediaryBuffer); - framesAvailable -= framesToSend; - } - } - } - - return MAL_SUCCESS; -} -#endif // OpenAL - - - -/////////////////////////////////////////////////////////////////////////////// -// -// SDL Backend -// -/////////////////////////////////////////////////////////////////////////////// -#ifdef MAL_HAS_SDL - -//#define MAL_USE_SDL_1 - -#define MAL_SDL_INIT_AUDIO 0x00000010 -#define MAL_AUDIO_U8 0x0008 -#define MAL_AUDIO_S16 0x8010 -#define MAL_AUDIO_S32 0x8020 -#define MAL_AUDIO_F32 0x8120 -#define MAL_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001 -#define MAL_SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002 -#define MAL_SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004 -#define MAL_SDL_AUDIO_ALLOW_ANY_CHANGE (MAL_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | MAL_SDL_AUDIO_ALLOW_FORMAT_CHANGE | MAL_SDL_AUDIO_ALLOW_CHANNELS_CHANGE) - -// If we are linking at compile time we'll just #include SDL.h. Otherwise we can just redeclare some stuff to avoid the -// need for development packages to be installed. -#ifdef MAL_NO_RUNTIME_LINKING - #define SDL_MAIN_HANDLED - #ifdef MAL_EMSCRIPTEN - #include - - // For now just use SDL 1.2 with Emscripten. This avoids the need for "-s USE_SDL=2" at compile time. - #ifndef MAL_USE_SDL_1 - #define MAL_USE_SDL_1 - #endif - #else - #include - #endif - - typedef SDL_AudioCallback MAL_SDL_AudioCallback; - typedef SDL_AudioSpec MAL_SDL_AudioSpec; - typedef SDL_AudioFormat MAL_SDL_AudioFormat; - typedef SDL_AudioDeviceID MAL_SDL_AudioDeviceID; -#else - typedef void (* MAL_SDL_AudioCallback)(void* userdata, mal_uint8* stream, int len); - typedef mal_uint16 MAL_SDL_AudioFormat; - typedef mal_uint32 MAL_SDL_AudioDeviceID; - - typedef struct MAL_SDL_AudioSpec - { - int freq; - MAL_SDL_AudioFormat format; - mal_uint8 channels; - mal_uint8 silence; - mal_uint16 samples; - mal_uint16 padding; - mal_uint32 size; - MAL_SDL_AudioCallback callback; - void* userdata; - } MAL_SDL_AudioSpec; -#endif - -typedef int (* MAL_PFN_SDL_InitSubSystem)(mal_uint32 flags); -typedef void (* MAL_PFN_SDL_QuitSubSystem)(mal_uint32 flags); -typedef int (* MAL_PFN_SDL_GetNumAudioDevices)(int iscapture); -typedef const char* (* MAL_PFN_SDL_GetAudioDeviceName)(int index, int iscapture); -typedef void (* MAL_PFN_SDL_CloseAudio)(void); -typedef void (* MAL_PFN_SDL_CloseAudioDevice)(MAL_SDL_AudioDeviceID dev); -typedef int (* MAL_PFN_SDL_OpenAudio)(MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained); -typedef MAL_SDL_AudioDeviceID (* MAL_PFN_SDL_OpenAudioDevice)(const char* device, int iscapture, const MAL_SDL_AudioSpec* desired, MAL_SDL_AudioSpec* obtained, int allowed_changes); -typedef void (* MAL_PFN_SDL_PauseAudio)(int pause_on); -typedef void (* MAL_PFN_SDL_PauseAudioDevice)(MAL_SDL_AudioDeviceID dev, int pause_on); - -MAL_SDL_AudioFormat mal_format_to_sdl(mal_format format) -{ - switch (format) - { - case mal_format_unknown: return 0; - case mal_format_u8: return MAL_AUDIO_U8; - case mal_format_s16: return MAL_AUDIO_S16; - case mal_format_s24: return MAL_AUDIO_S32; // Closest match. - case mal_format_s32: return MAL_AUDIO_S32; - default: return 0; - } -} - -mal_format mal_format_from_sdl(MAL_SDL_AudioFormat format) -{ - switch (format) - { - case MAL_AUDIO_U8: return mal_format_u8; - case MAL_AUDIO_S16: return mal_format_s16; - case MAL_AUDIO_S32: return mal_format_s32; - case MAL_AUDIO_F32: return mal_format_f32; - default: return mal_format_unknown; - } -} - - -mal_result mal_context_init__sdl(mal_context* pContext) -{ - mal_assert(pContext != NULL); - -#ifndef MAL_NO_RUNTIME_LINKING - // Run-time linking. - const char* libNames[] = { -#if defined(MAL_WIN32) - "SDL2.dll", - "SDL.dll" -#elif defined(MAL_APPLE) - "libSDL2-2.0.0.dylib", // Can any Mac users out there comfirm these library names? - "libSDL-1.2.0.dylib" -#else - "libSDL2-2.0.so.0", - "libSDL-1.2.so.0" -#endif - }; - - for (size_t i = 0; i < mal_countof(libNames); ++i) { - pContext->sdl.hSDL = mal_dlopen(libNames[i]); - if (pContext->sdl.hSDL != NULL) { - break; - } - } - - if (pContext->sdl.hSDL == NULL) { - return MAL_NO_BACKEND; // Couldn't find SDL2.dll, etc. Most likely it's not installed. - } - - pContext->sdl.SDL_InitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_InitSubSystem"); - pContext->sdl.SDL_QuitSubSystem = mal_dlsym(pContext->sdl.hSDL, "SDL_QuitSubSystem"); - pContext->sdl.SDL_CloseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudio"); - pContext->sdl.SDL_OpenAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudio"); - pContext->sdl.SDL_PauseAudio = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudio"); -#ifndef MAL_USE_SDL_1 - pContext->sdl.SDL_GetNumAudioDevices = mal_dlsym(pContext->sdl.hSDL, "SDL_GetNumAudioDevices"); - pContext->sdl.SDL_GetAudioDeviceName = mal_dlsym(pContext->sdl.hSDL, "SDL_GetAudioDeviceName"); - pContext->sdl.SDL_CloseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_CloseAudioDevice"); - pContext->sdl.SDL_OpenAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_OpenAudioDevice"); - pContext->sdl.SDL_PauseAudioDevice = mal_dlsym(pContext->sdl.hSDL, "SDL_PauseAudioDevice"); -#endif -#else - // Compile-time linking. - pContext->sdl.SDL_InitSubSystem = (mal_proc)SDL_InitSubSystem; - pContext->sdl.SDL_QuitSubSystem = (mal_proc)SDL_QuitSubSystem; - pContext->sdl.SDL_CloseAudio = (mal_proc)SDL_CloseAudio; - pContext->sdl.SDL_OpenAudio = (mal_proc)SDL_OpenAudio; - pContext->sdl.SDL_PauseAudio = (mal_proc)SDL_PauseAudio; -#ifndef MAL_USE_SDL_1 - pContext->sdl.SDL_GetNumAudioDevices = (mal_proc)SDL_GetNumAudioDevices; - pContext->sdl.SDL_GetAudioDeviceName = (mal_proc)SDL_GetAudioDeviceName; - pContext->sdl.SDL_CloseAudioDevice = (mal_proc)SDL_CloseAudioDevice; - pContext->sdl.SDL_OpenAudioDevice = (mal_proc)SDL_OpenAudioDevice; - pContext->sdl.SDL_PauseAudioDevice = (mal_proc)SDL_PauseAudioDevice; -#endif -#endif - - // We need to determine whether or not we are using SDL2 or SDL1. We can know this by looking at whether or not certain - // function pointers are NULL. - if (pContext->sdl.SDL_GetNumAudioDevices == NULL || - pContext->sdl.SDL_GetAudioDeviceName == NULL || - pContext->sdl.SDL_CloseAudioDevice == NULL || - pContext->sdl.SDL_OpenAudioDevice == NULL || - pContext->sdl.SDL_PauseAudioDevice == NULL) { - pContext->sdl.usingSDL1 = MAL_TRUE; - } - - int resultSDL = ((MAL_PFN_SDL_InitSubSystem)pContext->sdl.SDL_InitSubSystem)(MAL_SDL_INIT_AUDIO); - if (resultSDL != 0) { - return MAL_ERROR; - } - - return MAL_SUCCESS; -} - -mal_result mal_context_uninit__sdl(mal_context* pContext) -{ - mal_assert(pContext != NULL); - mal_assert(pContext->backend == mal_backend_sdl); - - ((MAL_PFN_SDL_QuitSubSystem)pContext->sdl.SDL_QuitSubSystem)(MAL_SDL_INIT_AUDIO); - return MAL_SUCCESS; -} - -mal_result mal_enumerate_devices__sdl(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - (void)pContext; - - mal_uint32 infoSize = *pCount; - *pCount = 0; - -#ifndef MAL_USE_SDL_1 - if (!pContext->sdl.usingSDL1) { - int deviceCount = ((MAL_PFN_SDL_GetNumAudioDevices)pContext->sdl.SDL_GetNumAudioDevices)((type == mal_device_type_playback) ? 0 : 1); - for (int i = 0; i < deviceCount; ++i) { - if (pInfo != NULL) { - if (infoSize > 0) { - pInfo->id.sdl = i; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), ((MAL_PFN_SDL_GetAudioDeviceName)pContext->sdl.SDL_GetAudioDeviceName)(i, (type == mal_device_type_playback) ? 0 : 1), (size_t)-1); - - pInfo += 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - } else -#endif - { - if (pInfo != NULL) { - if (infoSize > 0) { - // SDL1 uses default devices. - if (type == mal_device_type_playback) { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1); - } else { - pInfo->id.sdl = 0; - mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1); - } - - pInfo += 1; - *pCount += 1; - } - } else { - *pCount += 1; - } - } - - return MAL_SUCCESS; -} - -void mal_device_uninit__sdl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - -#ifndef MAL_USE_SDL_1 - if (!pDevice->pContext->sdl.usingSDL1) { - ((MAL_PFN_SDL_CloseAudioDevice)pDevice->pContext->sdl.SDL_CloseAudioDevice)(pDevice->sdl.deviceID); - } else -#endif - { - ((MAL_PFN_SDL_CloseAudio)pDevice->pContext->sdl.SDL_CloseAudio)(); - } -} - - -static void mal_audio_callback__sdl(void* pUserData, mal_uint8* pBuffer, int bufferSizeInBytes) -{ - mal_device* pDevice = (mal_device*)pUserData; - mal_assert(pDevice != NULL); - - mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_sample_size_in_bytes(pDevice->internalFormat) / pDevice->internalChannels; - - if (pDevice->type == mal_device_type_playback) { - mal_device__read_frames_from_client(pDevice, bufferSizeInFrames, pBuffer); - } else { - mal_device__send_frames_to_client(pDevice, bufferSizeInFrames, pBuffer); - } -} - -mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice) -{ - mal_assert(pContext != NULL); - mal_assert(pConfig != NULL); - mal_assert(pDevice != NULL); - - (void)pContext; - - // SDL wants the buffer size to be a power of 2. The SDL_AudioSpec property for this is only a Uint16, so we need - // to explicitly clamp this because it will be easy to overflow. - mal_uint32 bufferSize = pConfig->bufferSizeInFrames; - if (bufferSize > 32768) { - bufferSize = 32768; - } else { - bufferSize = mal_next_power_of_2(bufferSize); - } - - mal_assert(bufferSize <= 32768); - - - MAL_SDL_AudioSpec desiredSpec, obtainedSpec; - mal_zero_memory(&desiredSpec, sizeof(desiredSpec)); - desiredSpec.freq = (int)pConfig->sampleRate; - desiredSpec.format = mal_format_to_sdl(pConfig->format); - desiredSpec.channels = (mal_uint8)pConfig->channels; - desiredSpec.samples = (mal_uint16)bufferSize; - desiredSpec.callback = mal_audio_callback__sdl; - desiredSpec.userdata = pDevice; - - // Fall back to f32 if we don't have an appropriate mapping between mini_al and SDL. - if (desiredSpec.format == 0) { - desiredSpec.format = MAL_AUDIO_F32; - } - -#ifndef MAL_USE_SDL_1 - if (!pDevice->pContext->sdl.usingSDL1) { - int isCapture = (type == mal_device_type_playback) ? 0 : 1; - - const char* pDeviceName = NULL; - if (pDeviceID != NULL) { - pDeviceName = ((MAL_PFN_SDL_GetAudioDeviceName)pDevice->pContext->sdl.SDL_GetAudioDeviceName)(pDeviceID->sdl, isCapture); - } - - pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudioDevice)pDevice->pContext->sdl.SDL_OpenAudioDevice)(pDeviceName, isCapture, &desiredSpec, &obtainedSpec, MAL_SDL_AUDIO_ALLOW_ANY_CHANGE); - if (pDevice->sdl.deviceID == 0) { - return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - } else -#endif - { - // SDL1 uses default devices. - (void)pDeviceID; - - // SDL1 only supports playback as far as I can tell. - if (type != mal_device_type_playback) { - return MAL_NO_DEVICE; - } - - // SDL1 does not support floating point formats. - if (desiredSpec.format == MAL_AUDIO_F32) { - desiredSpec.format = MAL_AUDIO_S16; - } - - pDevice->sdl.deviceID = ((MAL_PFN_SDL_OpenAudio)pDevice->pContext->sdl.SDL_OpenAudio)(&desiredSpec, &obtainedSpec); - if (pDevice->sdl.deviceID != 0) { - return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE); - } - } - - pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format); - pDevice->internalChannels = obtainedSpec.channels; - pDevice->internalSampleRate = (mal_uint32)obtainedSpec.freq; - pDevice->bufferSizeInFrames = obtainedSpec.samples; - pDevice->periods = 1; // SDL doesn't seem to tell us what the period count is. Just set this 1. - -#if 0 - printf("=== SDL CONFIG ===\n"); - printf("REQUESTED -> RECEIVED\n"); - printf(" FORMAT: %s -> %s\n", mal_get_format_name(pConfig->format), mal_get_format_name(pDevice->internalFormat)); - printf(" CHANNELS: %d -> %d\n", desiredSpec.channels, obtainedSpec.channels); - printf(" SAMPLE RATE: %d -> %d\n", desiredSpec.freq, obtainedSpec.freq); - printf(" BUFFER SIZE IN SAMPLES: %d -> %d\n", desiredSpec.samples, obtainedSpec.samples); -#endif - - return MAL_SUCCESS; -} - -static mal_result mal_device__start_backend__sdl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - -#ifndef MAL_USE_SDL_1 - if (!pDevice->pContext->sdl.usingSDL1) { - ((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 0); - } else -#endif - { - ((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(0); - } - - return MAL_SUCCESS; -} - -static mal_result mal_device__stop_backend__sdl(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - -#ifndef MAL_USE_SDL_1 - if (!pDevice->pContext->sdl.usingSDL1) { - ((MAL_PFN_SDL_PauseAudioDevice)pDevice->pContext->sdl.SDL_PauseAudioDevice)(pDevice->sdl.deviceID, 1); - } else -#endif - { - ((MAL_PFN_SDL_PauseAudio)pDevice->pContext->sdl.SDL_PauseAudio)(1); - } - - return MAL_SUCCESS; -} -#endif // SDL - - - - -mal_bool32 mal__is_channel_map_valid(const mal_channel* channelMap, mal_uint32 channels) -{ - mal_assert(channels > 0); - - // A channel cannot be present in the channel map more than once. - for (mal_uint32 iChannel = 0; iChannel < channels; ++iChannel) { - for (mal_uint32 jChannel = iChannel + 1; jChannel < channels; ++jChannel) { - if (channelMap[iChannel] == channelMap[jChannel]) { - return MAL_FALSE; - } - } - } - - return MAL_TRUE; -} - - -static mal_result mal_device__start_backend(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_HAS_WASAPI - if (pDevice->pContext->backend == mal_backend_wasapi) { - result = mal_device__start_backend__wasapi(pDevice); - } -#endif -#ifdef MAL_HAS_DSOUND - if (pDevice->pContext->backend == mal_backend_dsound) { - result = mal_device__start_backend__dsound(pDevice); - } -#endif -#ifdef MAL_HAS_WINMM - if (pDevice->pContext->backend == mal_backend_winmm) { - result = mal_device__start_backend__winmm(pDevice); - } -#endif -#ifdef MAL_HAS_ALSA - if (pDevice->pContext->backend == mal_backend_alsa) { - result = mal_device__start_backend__alsa(pDevice); - } -#endif -#ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__start_backend__oss(pDevice); - } -#endif -#ifdef MAL_HAS_OPENAL - if (pDevice->pContext->backend == mal_backend_openal) { - result = mal_device__start_backend__openal(pDevice); - } -#endif -#ifdef MAL_HAS_NULL - if (pDevice->pContext->backend == mal_backend_null) { - result = mal_device__start_backend__null(pDevice); - } -#endif - - return result; -} - -static mal_result mal_device__stop_backend(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_HAS_WASAPI - if (pDevice->pContext->backend == mal_backend_wasapi) { - result = mal_device__stop_backend__wasapi(pDevice); - } -#endif -#ifdef MAL_HAS_DSOUND - if (pDevice->pContext->backend == mal_backend_dsound) { - result = mal_device__stop_backend__dsound(pDevice); - } -#endif -#ifdef MAL_HAS_WINMM - if (pDevice->pContext->backend == mal_backend_winmm) { - result = mal_device__stop_backend__winmm(pDevice); - } -#endif -#ifdef MAL_HAS_ALSA - if (pDevice->pContext->backend == mal_backend_alsa) { - result = mal_device__stop_backend__alsa(pDevice); - } -#endif -#ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__stop_backend__oss(pDevice); - } -#endif -#ifdef MAL_HAS_OPENAL - if (pDevice->pContext->backend == mal_backend_openal) { - result = mal_device__stop_backend__openal(pDevice); - } -#endif -#ifdef MAL_HAS_NULL - if (pDevice->pContext->backend == mal_backend_null) { - result = mal_device__stop_backend__null(pDevice); - } -#endif - - return result; -} - -static mal_result mal_device__break_main_loop(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_HAS_WASAPI - if (pDevice->pContext->backend == mal_backend_wasapi) { - result = mal_device__break_main_loop__wasapi(pDevice); - } -#endif -#ifdef MAL_HAS_DSOUND - if (pDevice->pContext->backend == mal_backend_dsound) { - result = mal_device__break_main_loop__dsound(pDevice); - } -#endif -#ifdef MAL_HAS_WINMM - if (pDevice->pContext->backend == mal_backend_winmm) { - result = mal_device__break_main_loop__winmm(pDevice); - } -#endif -#ifdef MAL_HAS_ALSA - if (pDevice->pContext->backend == mal_backend_alsa) { - result = mal_device__break_main_loop__alsa(pDevice); - } -#endif -#ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__break_main_loop__oss(pDevice); - } -#endif -#ifdef MAL_HAS_OPENAL - if (pDevice->pContext->backend == mal_backend_openal) { - result = mal_device__break_main_loop__openal(pDevice); - } -#endif -#ifdef MAL_HAS_NULL - if (pDevice->pContext->backend == mal_backend_null) { - result = mal_device__break_main_loop__null(pDevice); - } -#endif - - return result; -} - -static mal_result mal_device__main_loop(mal_device* pDevice) -{ - mal_assert(pDevice != NULL); - - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_HAS_WASAPI - if (pDevice->pContext->backend == mal_backend_wasapi) { - result = mal_device__main_loop__wasapi(pDevice); - } -#endif -#ifdef MAL_HAS_DSOUND - if (pDevice->pContext->backend == mal_backend_dsound) { - result = mal_device__main_loop__dsound(pDevice); - } -#endif -#ifdef MAL_HAS_WINMM - if (pDevice->pContext->backend == mal_backend_winmm) { - result = mal_device__main_loop__winmm(pDevice); - } -#endif -#ifdef MAL_HAS_ALSA - if (pDevice->pContext->backend == mal_backend_alsa) { - result = mal_device__main_loop__alsa(pDevice); - } -#endif -#ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - result = mal_device__main_loop__oss(pDevice); - } -#endif -#ifdef MAL_HAS_OPENAL - if (pDevice->pContext->backend == mal_backend_openal) { - result = mal_device__main_loop__openal(pDevice); - } -#endif -#ifdef MAL_HAS_NULL - if (pDevice->pContext->backend == mal_backend_null) { - result = mal_device__main_loop__null(pDevice); - } -#endif - - return result; -} - -mal_thread_result MAL_THREADCALL mal_worker_thread(void* pData) -{ - mal_device* pDevice = (mal_device*)pData; - mal_assert(pDevice != NULL); - -#ifdef MAL_WIN32 - mal_CoInitializeEx(pDevice->pContext, NULL, 0); // 0 = COINIT_MULTITHREADED -#endif - - // This is only used to prevent posting onStop() when the device is first initialized. - mal_bool32 skipNextStopEvent = MAL_TRUE; - - for (;;) { - // At the start of iteration the device is stopped - we must explicitly mark it as such. - mal_device__stop_backend(pDevice); - - if (!skipNextStopEvent) { - mal_stop_proc onStop = pDevice->onStop; - if (onStop) { - onStop(pDevice); - } - } else { - skipNextStopEvent = MAL_FALSE; - } - - - // Let the other threads know that the device has stopped. - mal_device__set_state(pDevice, MAL_STATE_STOPPED); - mal_event_signal(&pDevice->stopEvent); - - // We use an event to wait for a request to wake up. - mal_event_wait(&pDevice->wakeupEvent); - - // Default result code. - pDevice->workResult = MAL_SUCCESS; - - // Just break if we're terminating. - if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) { - break; - } - - - // Getting here means we just started the device and we need to wait for the device to - // either deliver us data (recording) or request more data (playback). - mal_assert(mal_device__get_state(pDevice) == MAL_STATE_STARTING); - - pDevice->workResult = mal_device__start_backend(pDevice); - if (pDevice->workResult != MAL_SUCCESS) { - mal_event_signal(&pDevice->startEvent); - continue; - } - - // The thread that requested the device to start playing is waiting for this thread to start the - // device for real, which is now. - mal_device__set_state(pDevice, MAL_STATE_STARTED); - mal_event_signal(&pDevice->startEvent); - - // Now we just enter the main loop. The main loop can be broken with mal_device__break_main_loop(). - mal_device__main_loop(pDevice); - } - - // Make sure we aren't continuously waiting on a stop event. - mal_event_signal(&pDevice->stopEvent); // <-- Is this still needed? - -#ifdef MAL_WIN32 - mal_CoUninitialize(pDevice->pContext); -#endif - - return (mal_thread_result)0; -} - - -// Helper for determining whether or not the given device is initialized. -mal_bool32 mal_device__is_initialized(mal_device* pDevice) -{ - if (pDevice == NULL) return MAL_FALSE; - return mal_device__get_state(pDevice) != MAL_STATE_UNINITIALIZED; -} - - -#ifdef MAL_WIN32 -mal_result mal_context_uninit_backend_apis__win32(mal_context* pContext) -{ - mal_CoUninitialize(pContext); - mal_dlclose(pContext->win32.hUser32DLL); - mal_dlclose(pContext->win32.hOle32DLL); - - return MAL_SUCCESS; -} - -mal_result mal_context_init_backend_apis__win32(mal_context* pContext) -{ -#ifdef MAL_WIN32_DESKTOP - // Ole32.dll - pContext->win32.hOle32DLL = mal_dlopen("ole32.dll"); - if (pContext->win32.hOle32DLL == NULL) { - return MAL_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.CoInitializeEx = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (mal_proc)mal_dlsym(pContext->win32.hOle32DLL, "PropVariantClear"); - - - // User32.dll - pContext->win32.hUser32DLL = mal_dlopen("user32.dll"); - if (pContext->win32.hUser32DLL == NULL) { - return MAL_FAILED_TO_INIT_BACKEND; - } - - pContext->win32.GetForegroundWindow = (mal_proc)mal_dlsym(pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (mal_proc)mal_dlsym(pContext->win32.hUser32DLL, "GetDesktopWindow"); -#endif - - mal_CoInitializeEx(pContext, NULL, 0); // 0 = COINIT_MULTITHREADED - return MAL_SUCCESS; -} -#else -mal_result mal_context_uninit_backend_apis__nix(mal_context* pContext) -{ - mal_dlclose(pContext->posix.pthreadSO); - - return MAL_SUCCESS; -} - -mal_result mal_context_init_backend_apis__nix(mal_context* pContext) -{ - // pthread -#if !defined(MAL_NO_RUNTIME_LINKING) - const char* libpthreadFileNames[] = { - "libpthread.so", - "libpthread.so.0", - "libpthread.dylib" - }; - - for (size_t i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { - pContext->posix.pthreadSO = mal_dlopen(libpthreadFileNames[i]); - if (pContext->posix.pthreadSO != NULL) { - break; - } - } - - if (pContext->posix.pthreadSO == NULL) { - return MAL_FAILED_TO_INIT_BACKEND; - } - - pContext->posix.pthread_create = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_create"); - pContext->posix.pthread_join = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_join"); - pContext->posix.pthread_mutex_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_init"); - pContext->posix.pthread_mutex_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_destroy"); - pContext->posix.pthread_mutex_lock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_lock"); - pContext->posix.pthread_mutex_unlock = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_mutex_unlock"); - pContext->posix.pthread_cond_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_init"); - pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy"); - pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait"); - pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal"); -#else - pContext->posix.pthread_create = (mal_proc)pthread_create; - pContext->posix.pthread_join = (mal_proc)pthread_join; - pContext->posix.pthread_mutex_init = (mal_proc)pthread_mutex_init; - pContext->posix.pthread_mutex_destroy = (mal_proc)pthread_mutex_destroy; - pContext->posix.pthread_mutex_lock = (mal_proc)pthread_mutex_lock; - pContext->posix.pthread_mutex_unlock = (mal_proc)pthread_mutex_unlock; - pContext->posix.pthread_cond_init = (mal_proc)pthread_cond_init; - pContext->posix.pthread_cond_destroy = (mal_proc)pthread_cond_destroy; - pContext->posix.pthread_cond_wait = (mal_proc)pthread_cond_wait; - pContext->posix.pthread_cond_signal = (mal_proc)pthread_cond_signal; -#endif - - return MAL_SUCCESS; -} -#endif - -mal_result mal_context_init_backend_apis(mal_context* pContext) -{ - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_WIN32 - result = mal_context_init_backend_apis__win32(pContext); -#else - result = mal_context_init_backend_apis__nix(pContext); -#endif - - return result; -} - -mal_result mal_context_uninit_backend_apis(mal_context* pContext) -{ - mal_result result = MAL_NO_BACKEND; -#ifdef MAL_WIN32 - result = mal_context_uninit_backend_apis__win32(pContext); -#else - result = mal_context_uninit_backend_apis__nix(pContext); -#endif - - return result; -} - -mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, const mal_context_config* pConfig, mal_context* pContext) -{ - if (pContext == NULL) return MAL_INVALID_ARGS; - mal_zero_object(pContext); - - // Always make sure the config is set first to ensure properties are available as soon as possible. - if (pConfig != NULL) { - pContext->config = *pConfig; - } else { - pContext->config = mal_context_config_init(NULL); - } - - // Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. - mal_result result = mal_context_init_backend_apis(pContext); - if (result != MAL_SUCCESS) { - return result; - } - - static mal_backend defaultBackends[] = { - mal_backend_wasapi, - mal_backend_dsound, - mal_backend_winmm, - mal_backend_alsa, - mal_backend_oss, - mal_backend_opensl, - mal_backend_openal, - mal_backend_sdl, - mal_backend_null - }; - - if (backends == NULL) { - backends = defaultBackends; - backendCount = sizeof(defaultBackends) / sizeof(defaultBackends[0]); - } - - mal_assert(backends != NULL); - - for (mal_uint32 iBackend = 0; iBackend < backendCount; ++iBackend) { - mal_backend backend = backends[iBackend]; - - result = MAL_NO_BACKEND; - switch (backend) { - #ifdef MAL_HAS_WASAPI - case mal_backend_wasapi: - { - result = mal_context_init__wasapi(pContext); - } break; - #endif - #ifdef MAL_HAS_DSOUND - case mal_backend_dsound: - { - result = mal_context_init__dsound(pContext); - } break; - #endif - #ifdef MAL_HAS_WINMM - case mal_backend_winmm: - { - result = mal_context_init__winmm(pContext); - } break; - #endif - #ifdef MAL_HAS_ALSA - case mal_backend_alsa: - { - result = mal_context_init__alsa(pContext); - } break; - #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - result = mal_context_init__oss(pContext); - } break; - #endif - #ifdef MAL_HAS_OPENSL - case mal_backend_opensl: - { - result = mal_context_init__opensl(pContext); - } break; - #endif - #ifdef MAL_HAS_OPENAL - case mal_backend_openal: - { - result = mal_context_init__openal(pContext); - } break; - #endif - #ifdef MAL_HAS_SDL - case mal_backend_sdl: - { - result = mal_context_init__sdl(pContext); - } break; - #endif - #ifdef MAL_HAS_NULL - case mal_backend_null: - { - result = mal_context_init__null(pContext); - } break; - #endif - - default: break; - } - - // If this iteration was successful, return. - if (result == MAL_SUCCESS) { - pContext->backend = backend; - return result; - } - } - - mal_zero_object(pContext); // Safety. - return MAL_NO_BACKEND; -} - -mal_result mal_context_uninit(mal_context* pContext) -{ - if (pContext == NULL) return MAL_INVALID_ARGS; - - switch (pContext->backend) { - #ifdef MAL_HAS_WASAPI - case mal_backend_wasapi: - { - return mal_context_uninit__wasapi(pContext); - } break; - #endif - #ifdef MAL_HAS_DSOUND - case mal_backend_dsound: - { - return mal_context_uninit__dsound(pContext); - } break; - #endif - #ifdef MAL_HAS_WINMM - case mal_backend_winmm: - { - return mal_context_uninit__winmm(pContext); - } break; - #endif - #ifdef MAL_HAS_ALSA - case mal_backend_alsa: - { - return mal_context_uninit__alsa(pContext); - } break; - #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - return mal_context_uninit__oss(pContext); - } break; - #endif - #ifdef MAL_HAS_OPENSL - case mal_backend_opensl: - { - return mal_context_uninit__opensl(pContext); - } break; - #endif - #ifdef MAL_HAS_OPENAL - case mal_backend_openal: - { - return mal_context_uninit__openal(pContext); - } break; - #endif - #ifdef MAL_HAS_SDL - case mal_backend_sdl: - { - return mal_context_uninit__sdl(pContext); - } break; - #endif - #ifdef MAL_HAS_NULL - case mal_backend_null: - { - return mal_context_uninit__null(pContext); - } break; - #endif - - default: break; - } - - mal_context_uninit_backend_apis(pContext); - - mal_assert(MAL_FALSE); - return MAL_NO_BACKEND; -} - - -mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo) -{ - if (pCount == NULL) return mal_post_error(NULL, "mal_enumerate_devices() called with invalid arguments (pCount == 0).", MAL_INVALID_ARGS); - - // The output buffer needs to be initialized to zero. - if (pInfo != NULL) { - mal_zero_memory(pInfo, (*pCount) * sizeof(*pInfo)); - } - - switch (pContext->backend) - { - #ifdef MAL_HAS_WASAPI - case mal_backend_wasapi: - { - return mal_enumerate_devices__wasapi(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_DSOUND - case mal_backend_dsound: - { - return mal_enumerate_devices__dsound(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_WINMM - case mal_backend_winmm: - { - return mal_enumerate_devices__winmm(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_ALSA - case mal_backend_alsa: - { - return mal_enumerate_devices__alsa(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - return mal_enumerate_devices__oss(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_OPENSL - case mal_backend_opensl: - { - return mal_enumerate_devices__opensl(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_OPENAL - case mal_backend_openal: - { - return mal_enumerate_devices__openal(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_SDL - case mal_backend_sdl: - { - return mal_enumerate_devices__sdl(pContext, type, pCount, pInfo); - } break; - #endif - #ifdef MAL_HAS_NULL - case mal_backend_null: - { - return mal_enumerate_devices__null(pContext, type, pCount, pInfo); - } break; - #endif - - default: break; - } - - mal_assert(MAL_FALSE); - return MAL_NO_BACKEND; -} - -mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, void* pUserData, mal_device* pDevice) -{ - if (pDevice == NULL) { - return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); - } - if (pConfig == NULL) { - return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pConfig == NULL).", MAL_INVALID_ARGS); - } - - // Make a copy of the config to ensure we don't override the caller's object. - mal_device_config config = *pConfig; - - mal_zero_object(pDevice); - pDevice->pContext = pContext; - - // Set the user data and log callback ASAP to ensure it is available for the entire initialization process. - pDevice->pUserData = pUserData; - pDevice->onStop = config.onStopCallback; - pDevice->onSend = config.onSendCallback; - pDevice->onRecv = config.onRecvCallback; - - if (((size_t)pDevice % sizeof(pDevice)) != 0) { - if (pContext->config.onLog) { - pContext->config.onLog(pContext, pDevice, "WARNING: mal_device_init() called for a device that is not properly aligned. Thread safety is not supported."); - } - } - - - if (pContext == NULL) { - return mal_post_error(pDevice, "mal_device_init() called with invalid arguments (pContext == NULL).", MAL_INVALID_ARGS); - } - - - // Basic config validation. - if (config.channels == 0) { - return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Channel count must be greater than 0.", MAL_INVALID_DEVICE_CONFIG); - } - if (config.channels > MAL_MAX_CHANNELS) { - return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Channel count cannot exceed 18.", MAL_INVALID_DEVICE_CONFIG); - } - - if (config.sampleRate == 0) { - return mal_post_error(pDevice, "mal_device_init() called with an invalid config. Sample rate must be greater than 0.", MAL_INVALID_DEVICE_CONFIG); - } - - if (!mal__is_channel_map_valid(pConfig->channelMap, pConfig->channels)) { - return mal_post_error(pDevice, "mal_device_init() called with invalid arguments. Channel map is invalid.", MAL_INVALID_DEVICE_CONFIG); - } - - - // Default buffer size and periods. - if (config.bufferSizeInFrames == 0) { - config.bufferSizeInFrames = (config.sampleRate/1000) * MAL_DEFAULT_BUFFER_SIZE_IN_MILLISECONDS; - pDevice->usingDefaultBufferSize = MAL_TRUE; - } - if (config.periods == 0) { - config.periods = MAL_DEFAULT_PERIODS; - pDevice->usingDefaultPeriods = MAL_TRUE; - } - - pDevice->type = type; - pDevice->format = config.format; - pDevice->channels = config.channels; - mal_copy_memory(config.channelMap, config.channelMap, sizeof(config.channelMap[0]) * config.channels); - pDevice->sampleRate = config.sampleRate; - pDevice->bufferSizeInFrames = config.bufferSizeInFrames; - pDevice->periods = config.periods; - - // The internal format, channel count and sample rate can be modified by the backend. - pDevice->internalFormat = pDevice->format; - pDevice->internalChannels = pDevice->channels; - pDevice->internalSampleRate = pDevice->sampleRate; - mal_copy_memory(pDevice->internalChannelMap, pDevice->channelMap, sizeof(pDevice->channelMap)); - - if (mal_mutex_init(pContext, &pDevice->lock) != MAL_SUCCESS) { - return mal_post_error(pDevice, "Failed to create mutex.", MAL_FAILED_TO_CREATE_MUTEX); - } - - // When the device is started, the worker thread is the one that does the actual startup of the backend device. We - // use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device. - // - // Each of these semaphores is released internally by the worker thread when the work is completed. The start - // semaphore is also used to wake up the worker thread. - if (mal_event_init(pContext, &pDevice->wakeupEvent) != MAL_SUCCESS) { - mal_mutex_uninit(&pDevice->lock); - return mal_post_error(pDevice, "Failed to create worker thread wakeup event.", MAL_FAILED_TO_CREATE_EVENT); - } - if (mal_event_init(pContext, &pDevice->startEvent) != MAL_SUCCESS) { - mal_event_uninit(&pDevice->wakeupEvent); - mal_mutex_uninit(&pDevice->lock); - return mal_post_error(pDevice, "Failed to create worker thread start event.", MAL_FAILED_TO_CREATE_EVENT); - } - if (mal_event_init(pContext, &pDevice->stopEvent) != MAL_SUCCESS) { - mal_event_uninit(&pDevice->startEvent); - mal_event_uninit(&pDevice->wakeupEvent); - mal_mutex_uninit(&pDevice->lock); - return mal_post_error(pDevice, "Failed to create worker thread stop event.", MAL_FAILED_TO_CREATE_EVENT); - } - - - mal_result result = MAL_NO_BACKEND; - switch (pContext->backend) - { - #ifdef MAL_HAS_WASAPI - case mal_backend_wasapi: - { - result = mal_device_init__wasapi(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_DSOUND - case mal_backend_dsound: - { - result = mal_device_init__dsound(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_WINMM - case mal_backend_winmm: - { - result = mal_device_init__winmm(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_ALSA - case mal_backend_alsa: - { - result = mal_device_init__alsa(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_OSS - case mal_backend_oss: - { - result = mal_device_init__oss(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_OPENSL - case mal_backend_opensl: - { - result = mal_device_init__opensl(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_OPENAL - case mal_backend_openal: - { - result = mal_device_init__openal(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_SDL - case mal_backend_sdl: - { - result = mal_device_init__sdl(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - #ifdef MAL_HAS_NULL - case mal_backend_null: - { - result = mal_device_init__null(pContext, type, pDeviceID, &config, pDevice); - } break; - #endif - - default: break; - } - - if (result != MAL_SUCCESS) { - return MAL_NO_BACKEND; // The error message will have been posted with mal_post_error() by the source of the error so don't bother calling it here. - } - - - // If the backend did not fill out a name for the device, try a generic method. - if (pDevice->name[0] == '\0') { - if (mal_context__try_get_device_name_by_id(pContext, type, pDeviceID, pDevice->name, sizeof(pDevice->name)) != MAL_SUCCESS) { - // We failed to get the device name, so fall back to some generic names. - if (pDeviceID == NULL) { - if (type == mal_device_type_playback) { - mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Default Playback Device", (size_t)-1); - } else { - mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Default Capture Device", (size_t)-1); - } - } else { - if (type == mal_device_type_playback) { - mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Playback Device", (size_t)-1); - } else { - mal_strncpy_s(pDevice->name, sizeof(pDevice->name), "Capture Device", (size_t)-1); - } - } - } - } - - - // We need a DSP object which is where samples are moved through in order to convert them to the - // format required by the backend. - mal_dsp_config dspConfig; - dspConfig.cacheSizeInFrames = pDevice->bufferSizeInFrames; - if (type == mal_device_type_playback) { - dspConfig.formatIn = pDevice->format; - dspConfig.channelsIn = pDevice->channels; - dspConfig.sampleRateIn = pDevice->sampleRate; - mal_copy_memory(dspConfig.channelMapIn, pDevice->channelMap, sizeof(dspConfig.channelMapIn)); - dspConfig.formatOut = pDevice->internalFormat; - dspConfig.channelsOut = pDevice->internalChannels; - dspConfig.sampleRateOut = pDevice->internalSampleRate; - mal_copy_memory(dspConfig.channelMapOut, pDevice->internalChannelMap, sizeof(dspConfig.channelMapOut)); - mal_dsp_init(&dspConfig, mal_device__on_read_from_client, pDevice, &pDevice->dsp); - } else { - dspConfig.formatIn = pDevice->internalFormat; - dspConfig.channelsIn = pDevice->internalChannels; - dspConfig.sampleRateIn = pDevice->internalSampleRate; - mal_copy_memory(dspConfig.channelMapIn, pDevice->internalChannelMap, sizeof(dspConfig.channelMapIn)); - dspConfig.formatOut = pDevice->format; - dspConfig.channelsOut = pDevice->channels; - dspConfig.sampleRateOut = pDevice->sampleRate; - mal_copy_memory(dspConfig.channelMapOut, pDevice->channelMap, sizeof(dspConfig.channelMapOut)); - mal_dsp_init(&dspConfig, mal_device__on_read_from_device, pDevice, &pDevice->dsp); - } - - - - - // Some backends don't require the worker thread. - if (pContext->backend != mal_backend_opensl && pContext->backend != mal_backend_sdl) { - // The worker thread. - if (mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice) != MAL_SUCCESS) { - mal_device_uninit(pDevice); - return mal_post_error(pDevice, "Failed to create worker thread.", MAL_FAILED_TO_CREATE_THREAD); - } - - // Wait for the worker thread to put the device into it's stopped state for real. - mal_event_wait(&pDevice->stopEvent); - } else { - mal_device__set_state(pDevice, MAL_STATE_STOPPED); - } - - mal_assert(mal_device__get_state(pDevice) == MAL_STATE_STOPPED); - return MAL_SUCCESS; -} - -void mal_device_uninit(mal_device* pDevice) -{ - if (!mal_device__is_initialized(pDevice)) return; - - // 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 (mal_device_is_started(pDevice)) { - while (mal_device_stop(pDevice) == MAL_DEVICE_BUSY) { - mal_sleep(1); - } - } - - // Putting the device into an uninitialized state will make the worker thread return. - mal_device__set_state(pDevice, MAL_STATE_UNINITIALIZED); - - // Wake up the worker thread and wait for it to properly terminate. - if (pDevice->pContext->backend != mal_backend_opensl && pDevice->pContext->backend != mal_backend_sdl) { - mal_event_signal(&pDevice->wakeupEvent); - mal_thread_wait(&pDevice->thread); - } - - mal_event_uninit(&pDevice->stopEvent); - mal_event_uninit(&pDevice->startEvent); - mal_event_uninit(&pDevice->wakeupEvent); - mal_mutex_uninit(&pDevice->lock); - -#ifdef MAL_HAS_WASAPI - if (pDevice->pContext->backend == mal_backend_wasapi) { - mal_device_uninit__wasapi(pDevice); - } -#endif -#ifdef MAL_HAS_DSOUND - if (pDevice->pContext->backend == mal_backend_dsound) { - mal_device_uninit__dsound(pDevice); - } -#endif -#ifdef MAL_HAS_WINMM - if (pDevice->pContext->backend == mal_backend_winmm) { - mal_device_uninit__winmm(pDevice); - } -#endif -#ifdef MAL_HAS_ALSA - if (pDevice->pContext->backend == mal_backend_alsa) { - mal_device_uninit__alsa(pDevice); - } -#endif -#ifdef MAL_HAS_OSS - if (pDevice->pContext->backend == mal_backend_oss) { - mal_device_uninit__oss(pDevice); - } -#endif -#ifdef MAL_HAS_OPENSL - if (pDevice->pContext->backend == mal_backend_opensl) { - mal_device_uninit__opensl(pDevice); - } -#endif -#ifdef MAL_HAS_OPENAL - if (pDevice->pContext->backend == mal_backend_openal) { - mal_device_uninit__openal(pDevice); - } -#endif -#ifdef MAL_HAS_SDL - if (pDevice->pContext->backend == mal_backend_sdl) { - mal_device_uninit__sdl(pDevice); - } -#endif -#ifdef MAL_HAS_NULL - if (pDevice->pContext->backend == mal_backend_null) { - mal_device_uninit__null(pDevice); - } -#endif - - mal_zero_object(pDevice); -} - -void mal_device_set_recv_callback(mal_device* pDevice, mal_recv_proc proc) -{ - if (pDevice == NULL) return; - mal_atomic_exchange_ptr(&pDevice->onRecv, proc); -} - -void mal_device_set_send_callback(mal_device* pDevice, mal_send_proc proc) -{ - if (pDevice == NULL) return; - mal_atomic_exchange_ptr(&pDevice->onSend, proc); -} - -void mal_device_set_stop_callback(mal_device* pDevice, mal_stop_proc proc) -{ - if (pDevice == NULL) return; - mal_atomic_exchange_ptr(&pDevice->onStop, proc); -} - -mal_result mal_device_start(mal_device* pDevice) -{ - if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_start() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); - if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); - - mal_result result = MAL_ERROR; - mal_mutex_lock(&pDevice->lock); - { - // Be a bit more descriptive if the device is already started or is already in the process of starting. This is likely - // a bug with the application. - if (mal_device__get_state(pDevice) == MAL_STATE_STARTING) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_start() called while another thread is already starting it.", MAL_DEVICE_ALREADY_STARTING); - } - if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_start() called for a device that's already started.", MAL_DEVICE_ALREADY_STARTED); - } - - // The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy. - if (mal_device__get_state(pDevice) != MAL_STATE_STOPPED) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_start() called while another thread is in the process of stopping it.", MAL_DEVICE_BUSY); - } - - mal_device__set_state(pDevice, MAL_STATE_STARTING); - - // Asynchronous backends need to be handled differently. -#ifdef MAL_HAS_OPENSL - if (pDevice->pContext->backend == mal_backend_opensl) { - result = mal_device__start_backend__opensl(pDevice); - if (result == MAL_SUCCESS) { - mal_device__set_state(pDevice, MAL_STATE_STARTED); - } - } else -#endif -#ifdef MAL_HAS_SDL - if (pDevice->pContext->backend == mal_backend_sdl) { - result = mal_device__start_backend__sdl(pDevice); - if (result == MAL_SUCCESS) { - mal_device__set_state(pDevice, MAL_STATE_STARTED); - } - } else -#endif - // Synchronous backends. - { - mal_event_signal(&pDevice->wakeupEvent); - - // Wait for the worker thread to finish starting the device. Note that the worker thread will be the one - // who puts the device into the started state. Don't call mal_device__set_state() here. - mal_event_wait(&pDevice->startEvent); - result = pDevice->workResult; - } - } - mal_mutex_unlock(&pDevice->lock); - - return result; -} - -mal_result mal_device_stop(mal_device* pDevice) -{ - if (pDevice == NULL) return mal_post_error(pDevice, "mal_device_stop() called with invalid arguments (pDevice == NULL).", MAL_INVALID_ARGS); - if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_stop() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); - - mal_result result = MAL_ERROR; - mal_mutex_lock(&pDevice->lock); - { - // Be a bit more descriptive if the device is already stopped or is already in the process of stopping. This is likely - // a bug with the application. - if (mal_device__get_state(pDevice) == MAL_STATE_STOPPING) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_stop() called while another thread is already stopping it.", MAL_DEVICE_ALREADY_STOPPING); - } - if (mal_device__get_state(pDevice) == MAL_STATE_STOPPED) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_stop() called for a device that's already stopped.", MAL_DEVICE_ALREADY_STOPPED); - } - - // The device needs to be in a started state. If it's not, we just let the caller know the device is busy. - if (mal_device__get_state(pDevice) != MAL_STATE_STARTED) { - mal_mutex_unlock(&pDevice->lock); - return mal_post_error(pDevice, "mal_device_stop() called while another thread is in the process of starting it.", MAL_DEVICE_BUSY); - } - - mal_device__set_state(pDevice, MAL_STATE_STOPPING); - - // There's no need to wake up the thread like we do when starting. - - // Asynchronous backends need to be handled differently. -#ifdef MAL_HAS_OPENSL - if (pDevice->pContext->backend == mal_backend_opensl) { - mal_device__stop_backend__opensl(pDevice); - } else -#endif -#ifdef MAL_HAS_SDL - if (pDevice->pContext->backend == mal_backend_sdl) { - mal_device__stop_backend__sdl(pDevice); - } else -#endif - // Synchronous backends. - { - // When we get here the worker thread is likely in a wait state while waiting for the backend device to deliver or request - // audio data. We need to force these to return as quickly as possible. - mal_device__break_main_loop(pDevice); - - // We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be - // the one who puts the device into the stopped state. Don't call mal_device__set_state() here. - mal_event_wait(&pDevice->stopEvent); - result = MAL_SUCCESS; - } - } - mal_mutex_unlock(&pDevice->lock); - - return result; -} - -mal_bool32 mal_device_is_started(mal_device* pDevice) -{ - if (pDevice == NULL) return MAL_FALSE; - return mal_device__get_state(pDevice) == MAL_STATE_STARTED; -} - -mal_uint32 mal_device_get_buffer_size_in_bytes(mal_device* pDevice) -{ - if (pDevice == NULL) return 0; - return pDevice->bufferSizeInFrames * pDevice->channels * mal_get_sample_size_in_bytes(pDevice->format); -} - -mal_uint32 mal_get_sample_size_in_bytes(mal_format format) -{ - mal_uint32 sizes[] = { - 0, // unknown - 1, // u8 - 2, // s16 - 3, // s24 - 4, // s32 - 4, // f32 - }; - return sizes[format]; -} - -mal_context_config mal_context_config_init(mal_log_proc onLog) -{ - mal_context_config config; - mal_zero_object(&config); - - config.onLog = onLog; - - return config; -} - -mal_device_config mal_device_config_init(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_recv_proc onRecvCallback, mal_send_proc onSendCallback) -{ - mal_device_config config; - mal_zero_object(&config); - - config.format = format; - config.channels = channels; - config.sampleRate = sampleRate; - config.onRecvCallback = onRecvCallback; - config.onSendCallback = onSendCallback; - - switch (channels) - { - case 1: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_CENTER; - } break; - - case 2: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - } break; - - case 3: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - config.channelMap[2] = MAL_CHANNEL_LFE; - } break; - - case 4: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - config.channelMap[2] = MAL_CHANNEL_BACK_LEFT; - config.channelMap[3] = MAL_CHANNEL_BACK_RIGHT; - } break; - - case 5: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - config.channelMap[2] = MAL_CHANNEL_BACK_LEFT; - config.channelMap[3] = MAL_CHANNEL_BACK_RIGHT; - config.channelMap[4] = MAL_CHANNEL_LFE; - } break; - - case 6: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - config.channelMap[2] = MAL_CHANNEL_FRONT_CENTER; - config.channelMap[3] = MAL_CHANNEL_LFE; - config.channelMap[4] = MAL_CHANNEL_BACK_LEFT; - config.channelMap[5] = MAL_CHANNEL_BACK_RIGHT; - } break; - - case 8: - { - config.channelMap[0] = MAL_CHANNEL_FRONT_LEFT; - config.channelMap[1] = MAL_CHANNEL_FRONT_RIGHT; - config.channelMap[2] = MAL_CHANNEL_FRONT_CENTER; - config.channelMap[3] = MAL_CHANNEL_LFE; - config.channelMap[4] = MAL_CHANNEL_BACK_LEFT; - config.channelMap[5] = MAL_CHANNEL_BACK_RIGHT; - config.channelMap[6] = MAL_CHANNEL_SIDE_LEFT; - config.channelMap[7] = MAL_CHANNEL_SIDE_RIGHT; - } break; - - default: - { - // Just leave it all blank in this case. This will use the same mapping as the device's native mapping. - } break; - } - - return config; -} - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// SRC -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void mal_src_cache_init(mal_src* pSRC, mal_src_cache* pCache) -{ - mal_assert(pSRC != NULL); - mal_assert(pCache != NULL); - - pCache->pSRC = pSRC; - pCache->cachedFrameCount = 0; - pCache->iNextFrame = 0; -} - -mal_uint32 mal_src_cache_read_frames(mal_src_cache* pCache, mal_uint32 frameCount, float* pFramesOut) -{ - mal_assert(pCache != NULL); - mal_assert(pCache->pSRC != NULL); - mal_assert(pCache->pSRC->onRead != NULL); - mal_assert(frameCount > 0); - mal_assert(pFramesOut != NULL); - - mal_uint32 channels = pCache->pSRC->config.channels; - - mal_uint32 totalFramesRead = 0; - while (frameCount > 0) { - // If there's anything in memory go ahead and copy that over first. - mal_uint32 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame; - mal_uint32 framesToReadFromMemory = frameCount; - if (framesToReadFromMemory > framesRemainingInMemory) { - framesToReadFromMemory = framesRemainingInMemory; - } - - mal_copy_memory(pFramesOut, pCache->pCachedFrames + pCache->iNextFrame*channels, framesToReadFromMemory * channels * sizeof(float)); - pCache->iNextFrame += framesToReadFromMemory; - - totalFramesRead += framesToReadFromMemory; - frameCount -= framesToReadFromMemory; - if (frameCount == 0) { - break; - } - - - // At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. - mal_assert(frameCount > 0); - pFramesOut += framesToReadFromMemory * channels; - - pCache->iNextFrame = 0; - pCache->cachedFrameCount = 0; - if (pCache->pSRC->config.formatIn == mal_format_f32) { - // No need for a conversion - read straight into the cache. - mal_uint32 framesToReadFromClient = mal_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; - if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { - framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; - } - - pCache->cachedFrameCount = pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); - } else { - // A format conversion is required which means we need to use an intermediary buffer. - mal_uint8 pIntermediaryBuffer[sizeof(pCache->pCachedFrames)]; - mal_uint32 framesToReadFromClient = mal_min(mal_buffer_frame_capacity(pIntermediaryBuffer, channels, pCache->pSRC->config.formatIn), mal_buffer_frame_capacity(pCache->pCachedFrames, channels, mal_format_f32)); - if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { - framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; - } - - pCache->cachedFrameCount = pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pIntermediaryBuffer, pCache->pSRC->pUserData); - - // Convert to f32. - mal_pcm_convert(pCache->pCachedFrames, mal_format_f32, pIntermediaryBuffer, pCache->pSRC->config.formatIn, pCache->cachedFrameCount * channels); - } - - - // Get out of this loop if nothing was able to be retrieved. - if (pCache->cachedFrameCount == 0) { - break; - } - } - - return totalFramesRead; -} - - -mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); -mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush); - -mal_result mal_src_init(mal_src_config* pConfig, mal_src_read_proc onRead, void* pUserData, mal_src* pSRC) -{ - if (pSRC == NULL) return MAL_INVALID_ARGS; - mal_zero_object(pSRC); - - if (pConfig == NULL || onRead == NULL) return MAL_INVALID_ARGS; - if (pConfig->channels == 0 || pConfig->channels > MAL_MAX_CHANNELS) return MAL_INVALID_ARGS; - - pSRC->config = *pConfig; - pSRC->onRead = onRead; - pSRC->pUserData = pUserData; - - if (pSRC->config.cacheSizeInFrames > MAL_SRC_CACHE_SIZE_IN_FRAMES || pSRC->config.cacheSizeInFrames == 0) { - pSRC->config.cacheSizeInFrames = MAL_SRC_CACHE_SIZE_IN_FRAMES; - } - - mal_src_cache_init(pSRC, &pSRC->cache); - return MAL_SUCCESS; -} - -mal_result mal_src_set_output_sample_rate(mal_src* pSRC, mal_uint32 sampleRateOut) -{ - if (pSRC == NULL) return MAL_INVALID_ARGS; - - // Must have a sample rate of > 0. - if (sampleRateOut == 0) { - return MAL_INVALID_ARGS; - } - - pSRC->config.sampleRateOut = sampleRateOut; - return MAL_SUCCESS; -} - -mal_uint32 mal_src_read_frames(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut) -{ - return mal_src_read_frames_ex(pSRC, frameCount, pFramesOut, MAL_FALSE); -} - -mal_uint32 mal_src_read_frames_ex(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) -{ - if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; - - mal_src_algorithm algorithm = pSRC->config.algorithm; - - // Always use passthrough if the sample rates are the same. - if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { - algorithm = mal_src_algorithm_none; - } - - // Could just use a function pointer instead of a switch for this... - switch (algorithm) - { - case mal_src_algorithm_none: return mal_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); - case mal_src_algorithm_linear: return mal_src_read_frames_linear(pSRC, frameCount, pFramesOut, flush); - default: return 0; - } -} - -mal_uint32 mal_src_read_frames_passthrough(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) -{ - mal_assert(pSRC != NULL); - mal_assert(frameCount > 0); - mal_assert(pFramesOut != NULL); - - (void)flush; // Passthrough need not care about flushing. - - // Fast path. No need for data conversion - just pass right through. - if (pSRC->config.formatIn == pSRC->config.formatOut) { - return pSRC->onRead(pSRC, frameCount, pFramesOut, pSRC->pUserData); - } - - // Slower path. Need to do a format conversion. - mal_uint32 totalFramesRead = 0; - while (frameCount > 0) { - mal_uint8 pStagingBuffer[MAL_MAX_CHANNELS * 2048]; - mal_uint32 stagingBufferSizeInFrames = sizeof(pStagingBuffer) / mal_get_sample_size_in_bytes(pSRC->config.formatIn) / pSRC->config.channels; - mal_uint32 framesToRead = stagingBufferSizeInFrames; - if (framesToRead > frameCount) { - framesToRead = frameCount; - } - - mal_uint32 framesRead = pSRC->onRead(pSRC, framesToRead, pStagingBuffer, pSRC->pUserData); - if (framesRead == 0) { - break; - } - - mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pStagingBuffer, pSRC->config.formatIn, framesRead * pSRC->config.channels); - - pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pSRC->config.channels * mal_get_sample_size_in_bytes(pSRC->config.formatOut)); - frameCount -= framesRead; - totalFramesRead += framesRead; - } - - return totalFramesRead; -} - -mal_uint32 mal_src_read_frames_linear(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) -{ - mal_assert(pSRC != NULL); - mal_assert(frameCount > 0); - mal_assert(pFramesOut != NULL); - - // For linear SRC, the bin is only 2 frames: 1 prior, 1 future. - - // Load the bin if necessary. - if (!pSRC->linear.isPrevFramesLoaded) { - mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin); - if (framesRead == 0) { - return 0; - } - pSRC->linear.isPrevFramesLoaded = MAL_TRUE; - } - if (!pSRC->linear.isNextFramesLoaded) { - mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin + pSRC->config.channels); - if (framesRead == 0) { - return 0; - } - pSRC->linear.isNextFramesLoaded = MAL_TRUE; - } - - float factor = (float)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; - - mal_uint32 totalFramesRead = 0; - while (frameCount > 0) { - // The bin is where the previous and next frames are located. - float* pPrevFrame = pSRC->bin; - float* pNextFrame = pSRC->bin + pSRC->config.channels; - - float pFrame[MAL_MAX_CHANNELS]; - mal_blend_f32(pFrame, pPrevFrame, pNextFrame, pSRC->linear.alpha, pSRC->config.channels); - - pSRC->linear.alpha += factor; - - // The new alpha value is how we determine whether or not we need to read fresh frames. - mal_uint32 framesToReadFromClient = (mal_uint32)pSRC->linear.alpha; - pSRC->linear.alpha = pSRC->linear.alpha - framesToReadFromClient; - - for (mal_uint32 i = 0; i < framesToReadFromClient; ++i) { - for (mal_uint32 j = 0; j < pSRC->config.channels; ++j) { - pPrevFrame[j] = pNextFrame[j]; - } - - mal_uint32 framesRead = mal_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); - if (framesRead == 0) { - for (mal_uint32 j = 0; j < pSRC->config.channels; ++j) { - pNextFrame[j] = 0; - } - - if (pSRC->linear.isNextFramesLoaded) { - pSRC->linear.isNextFramesLoaded = MAL_FALSE; - } else { - if (flush) { - pSRC->linear.isPrevFramesLoaded = MAL_FALSE; - } - } - - break; - } - } - - mal_pcm_convert(pFramesOut, pSRC->config.formatOut, pFrame, mal_format_f32, 1 * pSRC->config.channels); - - pFramesOut = (mal_uint8*)pFramesOut + (1 * pSRC->config.channels * mal_get_sample_size_in_bytes(pSRC->config.formatOut)); - frameCount -= 1; - totalFramesRead += 1; - - // If there's no frames available we need to get out of this loop. - if (!pSRC->linear.isNextFramesLoaded && (!flush || !pSRC->linear.isPrevFramesLoaded)) { - break; - } - } - - return totalFramesRead; -} - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// FORMAT CONVERSION -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count); -void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count); -void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count); -void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count); -void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count); -void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count); -void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count); -void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count); -void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count); - -void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_format formatIn, unsigned int sampleCount) -{ - if (formatOut == formatIn) { - mal_copy_memory(pOut, pIn, sampleCount * mal_get_sample_size_in_bytes(formatOut)); - return; - } - - switch (formatIn) - { - case mal_format_u8: - { - switch (formatOut) - { - case mal_format_s16: mal_pcm_u8_to_s16((short*)pOut, (const unsigned char*)pIn, sampleCount); return; - case mal_format_s24: mal_pcm_u8_to_s24( pOut, (const unsigned char*)pIn, sampleCount); return; - case mal_format_s32: mal_pcm_u8_to_s32( (int*)pOut, (const unsigned char*)pIn, sampleCount); return; - case mal_format_f32: mal_pcm_u8_to_f32((float*)pOut, (const unsigned char*)pIn, sampleCount); return; - default: break; - } - } break; - - case mal_format_s16: - { - switch (formatOut) - { - case mal_format_u8: mal_pcm_s16_to_u8( (unsigned char*)pOut, (const short*)pIn, sampleCount); return; - case mal_format_s24: mal_pcm_s16_to_s24( pOut, (const short*)pIn, sampleCount); return; - case mal_format_s32: mal_pcm_s16_to_s32( (int*)pOut, (const short*)pIn, sampleCount); return; - case mal_format_f32: mal_pcm_s16_to_f32( (float*)pOut, (const short*)pIn, sampleCount); return; - default: break; - } - } break; - - case mal_format_s24: - { - switch (formatOut) - { - case mal_format_u8: mal_pcm_s24_to_u8( (unsigned char*)pOut, pIn, sampleCount); return; - case mal_format_s16: mal_pcm_s24_to_s16( (short*)pOut, pIn, sampleCount); return; - case mal_format_s32: mal_pcm_s24_to_s32( (int*)pOut, pIn, sampleCount); return; - case mal_format_f32: mal_pcm_s24_to_f32( (float*)pOut, pIn, sampleCount); return; - default: break; - } - } break; - - case mal_format_s32: - { - switch (formatOut) - { - case mal_format_u8: mal_pcm_s32_to_u8( (unsigned char*)pOut, (const int*)pIn, sampleCount); return; - case mal_format_s16: mal_pcm_s32_to_s16( (short*)pOut, (const int*)pIn, sampleCount); return; - case mal_format_s24: mal_pcm_s32_to_s24( pOut, (const int*)pIn, sampleCount); return; - case mal_format_f32: mal_pcm_s32_to_f32( (float*)pOut, (const int*)pIn, sampleCount); return; - default: break; - } - } break; - - case mal_format_f32: - { - switch (formatOut) - { - case mal_format_u8: mal_pcm_f32_to_u8( (unsigned char*)pOut, (const float*)pIn, sampleCount); return; - case mal_format_s16: mal_pcm_f32_to_s16( (short*)pOut, (const float*)pIn, sampleCount); return; - case mal_format_s24: mal_pcm_f32_to_s24( pOut, (const float*)pIn, sampleCount); return; - case mal_format_s32: mal_pcm_f32_to_s32( (int*)pOut, (const float*)pIn, sampleCount); return; - default: break; - } - } break; - - default: break; - } -} - - -static void mal_rearrange_channels_u8(mal_uint8* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - mal_uint8 temp[MAL_MAX_CHANNELS]; - mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); - - switch (channels) { - case 18: pFrame[17] = temp[channelMap[17]]; - case 17: pFrame[16] = temp[channelMap[16]]; - case 16: pFrame[15] = temp[channelMap[15]]; - case 15: pFrame[14] = temp[channelMap[14]]; - case 14: pFrame[13] = temp[channelMap[13]]; - case 13: pFrame[12] = temp[channelMap[12]]; - case 12: pFrame[11] = temp[channelMap[11]]; - case 11: pFrame[10] = temp[channelMap[10]]; - case 10: pFrame[ 9] = temp[channelMap[ 9]]; - case 9: pFrame[ 8] = temp[channelMap[ 8]]; - case 8: pFrame[ 7] = temp[channelMap[ 7]]; - case 7: pFrame[ 6] = temp[channelMap[ 6]]; - case 6: pFrame[ 5] = temp[channelMap[ 5]]; - case 5: pFrame[ 4] = temp[channelMap[ 4]]; - case 4: pFrame[ 3] = temp[channelMap[ 3]]; - case 3: pFrame[ 2] = temp[channelMap[ 2]]; - case 2: pFrame[ 1] = temp[channelMap[ 1]]; - case 1: pFrame[ 0] = temp[channelMap[ 0]]; - } -} - -static void mal_rearrange_channels_s16(mal_int16* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - mal_int16 temp[MAL_MAX_CHANNELS]; - mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); - - switch (channels) { - case 18: pFrame[17] = temp[channelMap[17]]; - case 17: pFrame[16] = temp[channelMap[16]]; - case 16: pFrame[15] = temp[channelMap[15]]; - case 15: pFrame[14] = temp[channelMap[14]]; - case 14: pFrame[13] = temp[channelMap[13]]; - case 13: pFrame[12] = temp[channelMap[12]]; - case 12: pFrame[11] = temp[channelMap[11]]; - case 11: pFrame[10] = temp[channelMap[10]]; - case 10: pFrame[ 9] = temp[channelMap[ 9]]; - case 9: pFrame[ 8] = temp[channelMap[ 8]]; - case 8: pFrame[ 7] = temp[channelMap[ 7]]; - case 7: pFrame[ 6] = temp[channelMap[ 6]]; - case 6: pFrame[ 5] = temp[channelMap[ 5]]; - case 5: pFrame[ 4] = temp[channelMap[ 4]]; - case 4: pFrame[ 3] = temp[channelMap[ 3]]; - case 3: pFrame[ 2] = temp[channelMap[ 2]]; - case 2: pFrame[ 1] = temp[channelMap[ 1]]; - case 1: pFrame[ 0] = temp[channelMap[ 0]]; - } -} - -static void mal_rearrange_channels_s32(mal_int32* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - mal_int32 temp[MAL_MAX_CHANNELS]; - mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); - - switch (channels) { - case 18: pFrame[17] = temp[channelMap[17]]; - case 17: pFrame[16] = temp[channelMap[16]]; - case 16: pFrame[15] = temp[channelMap[15]]; - case 15: pFrame[14] = temp[channelMap[14]]; - case 14: pFrame[13] = temp[channelMap[13]]; - case 13: pFrame[12] = temp[channelMap[12]]; - case 12: pFrame[11] = temp[channelMap[11]]; - case 11: pFrame[10] = temp[channelMap[10]]; - case 10: pFrame[ 9] = temp[channelMap[ 9]]; - case 9: pFrame[ 8] = temp[channelMap[ 8]]; - case 8: pFrame[ 7] = temp[channelMap[ 7]]; - case 7: pFrame[ 6] = temp[channelMap[ 6]]; - case 6: pFrame[ 5] = temp[channelMap[ 5]]; - case 5: pFrame[ 4] = temp[channelMap[ 4]]; - case 4: pFrame[ 3] = temp[channelMap[ 3]]; - case 3: pFrame[ 2] = temp[channelMap[ 2]]; - case 2: pFrame[ 1] = temp[channelMap[ 1]]; - case 1: pFrame[ 0] = temp[channelMap[ 0]]; - } -} - -static void mal_rearrange_channels_f32(float* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS]) -{ - float temp[MAL_MAX_CHANNELS]; - mal_copy_memory(temp, pFrame, sizeof(temp[0]) * channels); - - switch (channels) { - case 18: pFrame[17] = temp[channelMap[17]]; - case 17: pFrame[16] = temp[channelMap[16]]; - case 16: pFrame[15] = temp[channelMap[15]]; - case 15: pFrame[14] = temp[channelMap[14]]; - case 14: pFrame[13] = temp[channelMap[13]]; - case 13: pFrame[12] = temp[channelMap[12]]; - case 12: pFrame[11] = temp[channelMap[11]]; - case 11: pFrame[10] = temp[channelMap[10]]; - case 10: pFrame[ 9] = temp[channelMap[ 9]]; - case 9: pFrame[ 8] = temp[channelMap[ 8]]; - case 8: pFrame[ 7] = temp[channelMap[ 7]]; - case 7: pFrame[ 6] = temp[channelMap[ 6]]; - case 6: pFrame[ 5] = temp[channelMap[ 5]]; - case 5: pFrame[ 4] = temp[channelMap[ 4]]; - case 4: pFrame[ 3] = temp[channelMap[ 3]]; - case 3: pFrame[ 2] = temp[channelMap[ 2]]; - case 2: pFrame[ 1] = temp[channelMap[ 1]]; - case 1: pFrame[ 0] = temp[channelMap[ 0]]; - } -} - -static void mal_rearrange_channels_generic(void* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_format format) -{ - mal_uint32 sampleSizeInBytes = mal_get_sample_size_in_bytes(format); - - mal_uint8 temp[MAL_MAX_CHANNELS * 8]; // x8 to ensure it's large enough for all formats. - mal_copy_memory(temp, pFrame, sampleSizeInBytes * channels); - - switch (channels) { - case 18: mal_copy_memory((mal_uint8*)pFrame + (17 * sampleSizeInBytes), &temp[channelMap[17] * sampleSizeInBytes], sampleSizeInBytes); - case 17: mal_copy_memory((mal_uint8*)pFrame + (16 * sampleSizeInBytes), &temp[channelMap[16] * sampleSizeInBytes], sampleSizeInBytes); - case 16: mal_copy_memory((mal_uint8*)pFrame + (15 * sampleSizeInBytes), &temp[channelMap[15] * sampleSizeInBytes], sampleSizeInBytes); - case 15: mal_copy_memory((mal_uint8*)pFrame + (14 * sampleSizeInBytes), &temp[channelMap[14] * sampleSizeInBytes], sampleSizeInBytes); - case 14: mal_copy_memory((mal_uint8*)pFrame + (13 * sampleSizeInBytes), &temp[channelMap[13] * sampleSizeInBytes], sampleSizeInBytes); - case 13: mal_copy_memory((mal_uint8*)pFrame + (12 * sampleSizeInBytes), &temp[channelMap[12] * sampleSizeInBytes], sampleSizeInBytes); - case 12: mal_copy_memory((mal_uint8*)pFrame + (11 * sampleSizeInBytes), &temp[channelMap[11] * sampleSizeInBytes], sampleSizeInBytes); - case 11: mal_copy_memory((mal_uint8*)pFrame + (10 * sampleSizeInBytes), &temp[channelMap[10] * sampleSizeInBytes], sampleSizeInBytes); - case 10: mal_copy_memory((mal_uint8*)pFrame + ( 9 * sampleSizeInBytes), &temp[channelMap[ 9] * sampleSizeInBytes], sampleSizeInBytes); - case 9: mal_copy_memory((mal_uint8*)pFrame + ( 8 * sampleSizeInBytes), &temp[channelMap[ 8] * sampleSizeInBytes], sampleSizeInBytes); - case 8: mal_copy_memory((mal_uint8*)pFrame + ( 7 * sampleSizeInBytes), &temp[channelMap[ 7] * sampleSizeInBytes], sampleSizeInBytes); - case 7: mal_copy_memory((mal_uint8*)pFrame + ( 6 * sampleSizeInBytes), &temp[channelMap[ 6] * sampleSizeInBytes], sampleSizeInBytes); - case 6: mal_copy_memory((mal_uint8*)pFrame + ( 5 * sampleSizeInBytes), &temp[channelMap[ 5] * sampleSizeInBytes], sampleSizeInBytes); - case 5: mal_copy_memory((mal_uint8*)pFrame + ( 4 * sampleSizeInBytes), &temp[channelMap[ 4] * sampleSizeInBytes], sampleSizeInBytes); - case 4: mal_copy_memory((mal_uint8*)pFrame + ( 3 * sampleSizeInBytes), &temp[channelMap[ 3] * sampleSizeInBytes], sampleSizeInBytes); - case 3: mal_copy_memory((mal_uint8*)pFrame + ( 2 * sampleSizeInBytes), &temp[channelMap[ 2] * sampleSizeInBytes], sampleSizeInBytes); - case 2: mal_copy_memory((mal_uint8*)pFrame + ( 1 * sampleSizeInBytes), &temp[channelMap[ 1] * sampleSizeInBytes], sampleSizeInBytes); - case 1: mal_copy_memory((mal_uint8*)pFrame + ( 0 * sampleSizeInBytes), &temp[channelMap[ 0] * sampleSizeInBytes], sampleSizeInBytes); - } -} - -static void mal_rearrange_channels(void* pFrame, mal_uint32 channels, mal_uint8 channelMap[MAL_MAX_CHANNELS], mal_format format) -{ - switch (format) - { - case mal_format_u8: mal_rearrange_channels_u8( (mal_uint8*)pFrame, channels, channelMap); break; - case mal_format_s16: mal_rearrange_channels_s16((mal_int16*)pFrame, channels, channelMap); break; - case mal_format_s32: mal_rearrange_channels_s32((mal_int32*)pFrame, channels, channelMap); break; - case mal_format_f32: mal_rearrange_channels_f32( (float*)pFrame, channels, channelMap); break; - default: mal_rearrange_channels_generic(pFrame, channels, channelMap, format); break; - } -} - -static void mal_dsp_mix_channels__dec(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) -{ - mal_assert(pFramesOut != NULL); - mal_assert(channelsOut > 0); - mal_assert(pFramesIn != NULL); - mal_assert(channelsIn > 0); - mal_assert(channelsOut < channelsIn); - - (void)channelMapOut; - (void)channelMapIn; - - if (mode == mal_channel_mix_mode_basic) { - // Basic mode is where we just drop excess channels. - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - switch (channelsOut) { - case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+16]; - case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+15]; - case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+14]; - case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+13]; - case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+12]; - case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+11]; - case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+10]; - case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+ 9]; - case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+ 8]; - case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+ 7]; - case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+ 6]; - case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+ 5]; - case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+ 4]; - case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+ 3]; - case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+ 2]; - case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+ 1]; - case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+ 0]; - } - } - } else { - // Blend mode is where we just use simple averaging to blend based on spacial locality. - if (channelsOut == 1) { - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - float total = 0; - switch (channelsIn) { - case 18: total += pFramesIn[iFrame*channelsIn+17]; - case 17: total += pFramesIn[iFrame*channelsIn+16]; - case 16: total += pFramesIn[iFrame*channelsIn+15]; - case 15: total += pFramesIn[iFrame*channelsIn+14]; - case 14: total += pFramesIn[iFrame*channelsIn+13]; - case 13: total += pFramesIn[iFrame*channelsIn+12]; - case 12: total += pFramesIn[iFrame*channelsIn+11]; - case 11: total += pFramesIn[iFrame*channelsIn+10]; - case 10: total += pFramesIn[iFrame*channelsIn+ 9]; - case 9: total += pFramesIn[iFrame*channelsIn+ 8]; - case 8: total += pFramesIn[iFrame*channelsIn+ 7]; - case 7: total += pFramesIn[iFrame*channelsIn+ 6]; - case 6: total += pFramesIn[iFrame*channelsIn+ 5]; - case 5: total += pFramesIn[iFrame*channelsIn+ 4]; - case 4: total += pFramesIn[iFrame*channelsIn+ 3]; - case 3: total += pFramesIn[iFrame*channelsIn+ 2]; - case 2: total += pFramesIn[iFrame*channelsIn+ 1]; - case 1: total += pFramesIn[iFrame*channelsIn+ 0]; - } - - pFramesOut[iFrame+0] = total / channelsIn; - } - } else if (channelsOut == 2) { - // TODO: Implement proper stereo blending. - mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); - } else { - // Fall back to basic mode. - mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); - } - } -} - -static void mal_dsp_mix_channels__inc(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) -{ - mal_assert(pFramesOut != NULL); - mal_assert(channelsOut > 0); - mal_assert(pFramesIn != NULL); - mal_assert(channelsIn > 0); - mal_assert(channelsOut > channelsIn); - - (void)channelMapOut; - (void)channelMapIn; - - if (mode == mal_channel_mix_mode_basic) { - // Basic mode is where we just zero out extra channels. - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - switch (channelsIn) { - case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+16]; - case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+15]; - case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+14]; - case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+13]; - case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+12]; - case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+11]; - case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+10]; - case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+ 9]; - case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+ 8]; - case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+ 7]; - case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+ 6]; - case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+ 5]; - case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+ 4]; - case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+ 3]; - case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+ 2]; - case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+ 1]; - case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+ 0]; - } - - // Zero out extra channels. - switch (channelsOut - channelsIn) { - case 17: pFramesOut[iFrame*channelsOut+16 + channelsIn] = 0; - case 16: pFramesOut[iFrame*channelsOut+15 + channelsIn] = 0; - case 15: pFramesOut[iFrame*channelsOut+14 + channelsIn] = 0; - case 14: pFramesOut[iFrame*channelsOut+13 + channelsIn] = 0; - case 13: pFramesOut[iFrame*channelsOut+12 + channelsIn] = 0; - case 12: pFramesOut[iFrame*channelsOut+11 + channelsIn] = 0; - case 11: pFramesOut[iFrame*channelsOut+10 + channelsIn] = 0; - case 10: pFramesOut[iFrame*channelsOut+ 9 + channelsIn] = 0; - case 9: pFramesOut[iFrame*channelsOut+ 8 + channelsIn] = 0; - case 8: pFramesOut[iFrame*channelsOut+ 7 + channelsIn] = 0; - case 7: pFramesOut[iFrame*channelsOut+ 6 + channelsIn] = 0; - case 6: pFramesOut[iFrame*channelsOut+ 5 + channelsIn] = 0; - case 5: pFramesOut[iFrame*channelsOut+ 4 + channelsIn] = 0; - case 4: pFramesOut[iFrame*channelsOut+ 3 + channelsIn] = 0; - case 3: pFramesOut[iFrame*channelsOut+ 2 + channelsIn] = 0; - case 2: pFramesOut[iFrame*channelsOut+ 1 + channelsIn] = 0; - case 1: pFramesOut[iFrame*channelsOut+ 0 + channelsIn] = 0; - } - } - } else { - // Using blended mixing mode. Basically this is just the mode where audio is distributed across all channels - // based on spacial locality. - if (channelsIn == 1) { - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - switch (channelsOut) { - case 18: pFramesOut[iFrame*channelsOut+17] = pFramesIn[iFrame*channelsIn+0]; - case 17: pFramesOut[iFrame*channelsOut+16] = pFramesIn[iFrame*channelsIn+0]; - case 16: pFramesOut[iFrame*channelsOut+15] = pFramesIn[iFrame*channelsIn+0]; - case 15: pFramesOut[iFrame*channelsOut+14] = pFramesIn[iFrame*channelsIn+0]; - case 14: pFramesOut[iFrame*channelsOut+13] = pFramesIn[iFrame*channelsIn+0]; - case 13: pFramesOut[iFrame*channelsOut+12] = pFramesIn[iFrame*channelsIn+0]; - case 12: pFramesOut[iFrame*channelsOut+11] = pFramesIn[iFrame*channelsIn+0]; - case 11: pFramesOut[iFrame*channelsOut+10] = pFramesIn[iFrame*channelsIn+0]; - case 10: pFramesOut[iFrame*channelsOut+ 9] = pFramesIn[iFrame*channelsIn+0]; - case 9: pFramesOut[iFrame*channelsOut+ 8] = pFramesIn[iFrame*channelsIn+0]; - case 8: pFramesOut[iFrame*channelsOut+ 7] = pFramesIn[iFrame*channelsIn+0]; - case 7: pFramesOut[iFrame*channelsOut+ 6] = pFramesIn[iFrame*channelsIn+0]; - case 6: pFramesOut[iFrame*channelsOut+ 5] = pFramesIn[iFrame*channelsIn+0]; - case 5: pFramesOut[iFrame*channelsOut+ 4] = pFramesIn[iFrame*channelsIn+0]; - case 4: pFramesOut[iFrame*channelsOut+ 3] = pFramesIn[iFrame*channelsIn+0]; - case 3: pFramesOut[iFrame*channelsOut+ 2] = pFramesIn[iFrame*channelsIn+0]; - case 2: pFramesOut[iFrame*channelsOut+ 1] = pFramesIn[iFrame*channelsIn+0]; - case 1: pFramesOut[iFrame*channelsOut+ 0] = pFramesIn[iFrame*channelsIn+0]; - } - } - } else if (channelsIn == 2) { - // TODO: Implement an optimized stereo conversion. - mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); - } else { - // Fall back to basic mixing mode. - mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mal_channel_mix_mode_basic); - } - } -} - -static void mal_dsp_mix_channels(float* pFramesOut, mal_uint32 channelsOut, const mal_uint8 channelMapOut[MAL_MAX_CHANNELS], const float* pFramesIn, mal_uint32 channelsIn, const mal_uint8 channelMapIn[MAL_MAX_CHANNELS], mal_uint32 frameCount, mal_channel_mix_mode mode) -{ - if (channelsIn < channelsOut) { - // Increasing the channel count. - mal_dsp_mix_channels__inc(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mode); - } else { - // Decreasing the channel count. - mal_dsp_mix_channels__dec(pFramesOut, channelsOut, channelMapOut, pFramesIn, channelsIn, channelMapIn, frameCount, mode); - } -} - - -mal_uint32 mal_dsp__src_on_read(mal_src* pSRC, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - (void)pSRC; - - mal_dsp* pDSP = (mal_dsp*)pUserData; - mal_assert(pDSP != NULL); - - return pDSP->onRead(pDSP, frameCount, pFramesOut, pDSP->pUserDataForOnRead); -} - -mal_result mal_dsp_init(mal_dsp_config* pConfig, mal_dsp_read_proc onRead, void* pUserData, mal_dsp* pDSP) -{ - if (pDSP == NULL) return MAL_INVALID_ARGS; - mal_zero_object(pDSP); - pDSP->config = *pConfig; - pDSP->onRead = onRead; - pDSP->pUserDataForOnRead = pUserData; - - if (pDSP->config.cacheSizeInFrames > MAL_SRC_CACHE_SIZE_IN_FRAMES || pDSP->config.cacheSizeInFrames == 0) { - pDSP->config.cacheSizeInFrames = MAL_SRC_CACHE_SIZE_IN_FRAMES; - } - - if (pConfig->sampleRateIn != pConfig->sampleRateOut) { - pDSP->isSRCRequired = MAL_TRUE; - - mal_src_config srcConfig; - srcConfig.sampleRateIn = pConfig->sampleRateIn; - srcConfig.sampleRateOut = pConfig->sampleRateOut; - srcConfig.formatIn = pConfig->formatIn; - srcConfig.formatOut = mal_format_f32; - srcConfig.channels = pConfig->channelsIn; - srcConfig.algorithm = mal_src_algorithm_linear; - srcConfig.cacheSizeInFrames = pConfig->cacheSizeInFrames; - mal_result result = mal_src_init(&srcConfig, mal_dsp__src_on_read, pDSP, &pDSP->src); - if (result != MAL_SUCCESS) { - return result; - } - } - - - - pDSP->isChannelMappingRequired = MAL_FALSE; - if (pConfig->channelMapIn[0] != MAL_CHANNEL_NONE && pConfig->channelMapOut[0] != MAL_CHANNEL_NONE) { // <-- Channel mapping will be ignored if the first channel map is MAL_CHANNEL_NONE. - // When using channel mapping we need to figure out a shuffling table. The first thing to do is convert the input channel map - // so that it contains the same number of channels as the output channel count. - mal_uint32 iChannel; - mal_uint32 channelsMin = mal_min(pConfig->channelsIn, pConfig->channelsOut); - for (iChannel = 0; iChannel < channelsMin; ++iChannel) { - pDSP->channelMapInPostMix[iChannel] = pConfig->channelMapIn[iChannel]; - } - - // Any excess channels need to be filled with the relevant channels from the output channel map. Currently we're justing filling it with - // the first channels that are not present in the input channel map. - if (pConfig->channelsOut > pConfig->channelsIn) { - for (iChannel = pConfig->channelsIn; iChannel < pConfig->channelsOut; ++iChannel) { - mal_uint8 newChannel = MAL_CHANNEL_NONE; - for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) { - mal_bool32 exists = MAL_FALSE; - for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsIn; ++iChannelIn) { - if (pConfig->channelMapOut[iChannelOut] == pConfig->channelMapIn[iChannelIn]) { - exists = MAL_TRUE; - break; - } - } - - if (!exists) { - newChannel = pConfig->channelMapOut[iChannelOut]; - break; - } - } - - pDSP->channelMapInPostMix[iChannel] = newChannel; - } - } - - // We only need to do a channel mapping if the map after mixing is different to the final output map. - for (iChannel = 0; iChannel < pConfig->channelsOut; ++iChannel) { - if (pDSP->channelMapInPostMix[iChannel] != pConfig->channelMapOut[iChannel]) { - pDSP->isChannelMappingRequired = MAL_TRUE; - break; - } - } - - // Now we need to create the shuffling table. - if (pDSP->isChannelMappingRequired) { - for (mal_uint32 iChannelIn = 0; iChannelIn < pConfig->channelsOut; ++iChannelIn) { - for (mal_uint32 iChannelOut = 0; iChannelOut < pConfig->channelsOut; ++iChannelOut) { - if (pDSP->channelMapInPostMix[iChannelOut] == pConfig->channelMapOut[iChannelIn]) { - pDSP->channelShuffleTable[iChannelOut] = (mal_uint8)iChannelIn; - } - } - } - } - } - - if (pConfig->formatIn == pConfig->formatOut && pConfig->channelsIn == pConfig->channelsOut && pConfig->sampleRateIn == pConfig->sampleRateOut && !pDSP->isChannelMappingRequired) { - pDSP->isPassthrough = MAL_TRUE; - } else { - pDSP->isPassthrough = MAL_FALSE; - } - - return MAL_SUCCESS; -} - -mal_result mal_dsp_set_output_sample_rate(mal_dsp* pDSP, mal_uint32 sampleRateOut) -{ - if (pDSP == NULL) return MAL_INVALID_ARGS; - - // Must have a sample rate of > 0. - if (sampleRateOut == 0) { - return MAL_INVALID_ARGS; - } - - pDSP->config.sampleRateOut = sampleRateOut; - - // If we already have an SRC pipeline initialized we do _not_ want to re-create it. Instead we adjust it. If we didn't previously - // have an SRC pipeline in place we'll need to initialize it. - if (pDSP->isSRCRequired) { - if (pDSP->config.sampleRateIn != pDSP->config.sampleRateOut) { - mal_src_set_output_sample_rate(&pDSP->src, sampleRateOut); - } else { - pDSP->isSRCRequired = MAL_FALSE; - } - } else { - // We may need a new SRC pipeline. - if (pDSP->config.sampleRateIn != pDSP->config.sampleRateOut) { - pDSP->isSRCRequired = MAL_TRUE; - - mal_src_config srcConfig; - srcConfig.sampleRateIn = pDSP->config.sampleRateIn; - srcConfig.sampleRateOut = pDSP->config.sampleRateOut; - srcConfig.formatIn = pDSP->config.formatIn; - srcConfig.formatOut = mal_format_f32; - srcConfig.channels = pDSP->config.channelsIn; - srcConfig.algorithm = mal_src_algorithm_linear; - srcConfig.cacheSizeInFrames = pDSP->config.cacheSizeInFrames; - mal_result result = mal_src_init(&srcConfig, mal_dsp__src_on_read, pDSP, &pDSP->src); - if (result != MAL_SUCCESS) { - return result; - } - } else { - pDSP->isSRCRequired = MAL_FALSE; - } - } - - // Update whether or not the pipeline is a passthrough. - if (pDSP->config.formatIn == pDSP->config.formatOut && pDSP->config.channelsIn == pDSP->config.channelsOut && pDSP->config.sampleRateIn == pDSP->config.sampleRateOut && !pDSP->isChannelMappingRequired) { - pDSP->isPassthrough = MAL_TRUE; - } else { - pDSP->isPassthrough = MAL_FALSE; - } - - return MAL_SUCCESS; -} - -mal_uint32 mal_dsp_read_frames(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut) -{ - return mal_dsp_read_frames_ex(pDSP, frameCount, pFramesOut, MAL_FALSE); -} - -mal_uint32 mal_dsp_read_frames_ex(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, mal_bool32 flush) -{ - if (pDSP == NULL || pFramesOut == NULL) return 0; - - // Fast path. - if (pDSP->isPassthrough) { - return pDSP->onRead(pDSP, frameCount, pFramesOut, pDSP->pUserDataForOnRead); - } - - - // Slower path - where the real work is done. - mal_uint8 pFrames[2][MAL_MAX_CHANNELS * 512 * MAL_MAX_SAMPLE_SIZE_IN_BYTES]; - mal_format pFramesFormat[2]; - mal_uint32 iFrames = 0; // <-- Used as an index into pFrames and cycles between 0 and 1. - - mal_uint32 totalFramesRead = 0; - while (frameCount > 0) { - iFrames = 0; - - mal_uint32 framesToRead = mal_countof(pFrames[0]) / (mal_max(pDSP->config.channelsIn, pDSP->config.channelsOut) * MAL_MAX_SAMPLE_SIZE_IN_BYTES); - if (framesToRead > frameCount) { - framesToRead = frameCount; - } - - // The initial filling of sample data depends on whether or not we are using SRC. - mal_uint32 framesRead = 0; - if (pDSP->isSRCRequired) { - framesRead = mal_src_read_frames_ex(&pDSP->src, framesToRead, pFrames[iFrames], flush); - pFramesFormat[iFrames] = pDSP->src.config.formatOut; // Should always be f32. - } else { - framesRead = pDSP->onRead(pDSP, framesToRead, pFrames[iFrames], pDSP->pUserDataForOnRead); - pFramesFormat[iFrames] = pDSP->config.formatIn; - } - - if (framesRead == 0) { - break; - } - - - // Channel mixing. The input format must be in f32 which may require a conversion. - if (pDSP->config.channelsIn != pDSP->config.channelsOut) { - if (pFramesFormat[iFrames] != mal_format_f32) { - mal_pcm_convert(pFrames[(iFrames + 1) % 2], mal_format_f32, pFrames[iFrames], pDSP->config.formatIn, framesRead * pDSP->config.channelsIn); - iFrames = (iFrames + 1) % 2; - pFramesFormat[iFrames] = mal_format_f32; - } - - mal_dsp_mix_channels((float*)(pFrames[(iFrames + 1) % 2]), pDSP->config.channelsOut, pDSP->config.channelMapOut, (const float*)(pFrames[iFrames]), pDSP->config.channelsIn, pDSP->config.channelMapIn, framesRead, mal_channel_mix_mode_blend); - iFrames = (iFrames + 1) % 2; - pFramesFormat[iFrames] = mal_format_f32; - } - - - // Channel mapping. - if (pDSP->isChannelMappingRequired) { - for (mal_uint32 i = 0; i < framesRead; ++i) { - mal_rearrange_channels(pFrames[iFrames] + (i * pDSP->config.channelsOut * mal_get_sample_size_in_bytes(pFramesFormat[iFrames])), pDSP->config.channelsOut, pDSP->channelShuffleTable, pFramesFormat[iFrames]); - } - } - - - // Final conversion to output format. - mal_pcm_convert(pFramesOut, pDSP->config.formatOut, pFrames[iFrames], pFramesFormat[iFrames], framesRead * pDSP->config.channelsOut); - - pFramesOut = (mal_uint8*)pFramesOut + (framesRead * pDSP->config.channelsOut * mal_get_sample_size_in_bytes(pDSP->config.formatOut)); - frameCount -= framesRead; - totalFramesRead += framesRead; - } - - return totalFramesRead; -} - - -mal_uint32 mal_calculate_frame_count_after_src(mal_uint32 sampleRateOut, mal_uint32 sampleRateIn, mal_uint32 frameCountIn) -{ - double srcRatio = (double)sampleRateOut / sampleRateIn; - double frameCountOutF = frameCountIn * srcRatio; - - mal_uint32 frameCountOut = (mal_uint32)frameCountOutF; - - // If the output frame count is fractional, make sure we add an extra frame to ensure there's enough room for that last sample. - if ((frameCountOutF - frameCountOut) > 0.0) { - frameCountOut += 1; - } - - return frameCountOut; -} - -typedef struct -{ - const void* pDataIn; - mal_format formatIn; - mal_uint32 channelsIn; - mal_uint32 totalFrameCount; - mal_uint32 iNextFrame; -} mal_convert_frames__data; - -mal_uint32 mal_convert_frames__on_read(mal_dsp* pDSP, mal_uint32 frameCount, void* pFramesOut, void* pUserData) -{ - (void)pDSP; - - mal_convert_frames__data* pData = (mal_convert_frames__data*)pUserData; - mal_assert(pData != NULL); - mal_assert(pData->totalFrameCount >= pData->iNextFrame); - - mal_uint32 framesToRead = frameCount; - mal_uint32 framesRemaining = (pData->totalFrameCount - pData->iNextFrame); - if (framesToRead > framesRemaining) { - framesToRead = framesRemaining; - } - - mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(pData->formatIn) * pData->channelsIn; - mal_copy_memory(pFramesOut, (const mal_uint8*)pData->pDataIn + (frameSizeInBytes * pData->iNextFrame), frameSizeInBytes * framesToRead); - - pData->iNextFrame += framesToRead; - return framesToRead; -} - -mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut, const void* pIn, mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_uint32 frameCountIn) -{ - if (frameCountIn == 0) { - return 0; - } - - mal_uint32 frameCountOut = mal_calculate_frame_count_after_src(sampleRateOut, sampleRateIn, frameCountIn); - if (pOut == NULL) { - return frameCountOut; - } - - mal_convert_frames__data data; - data.pDataIn = pIn; - data.formatIn = formatIn; - data.channelsIn = channelsIn; - data.totalFrameCount = frameCountIn; - data.iNextFrame = 0; - - mal_dsp_config config; - mal_zero_object(&config); - config.formatIn = formatIn; - config.channelsIn = channelsIn; - config.sampleRateIn = sampleRateIn; - config.formatOut = formatOut; - config.channelsOut = channelsOut; - config.sampleRateOut = sampleRateOut; - - mal_dsp dsp; - if (mal_dsp_init(&config, mal_convert_frames__on_read, &data, &dsp) != MAL_SUCCESS) { - return 0; - } - - return mal_dsp_read_frames_ex(&dsp, frameCountOut, pOut, MAL_TRUE); -} - -mal_dsp_config mal_dsp_config_init(mal_format formatIn, mal_uint32 channelsIn, mal_uint32 sampleRateIn, mal_format formatOut, mal_uint32 channelsOut, mal_uint32 sampleRateOut) -{ - mal_dsp_config config; - mal_zero_object(&config); - config.formatIn = formatIn; - config.channelsIn = channelsIn; - config.sampleRateIn = sampleRateIn; - config.formatOut = formatOut; - config.channelsOut = channelsOut; - config.sampleRateOut = sampleRateOut; - - return config; -} - - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Miscellaneous Helpers -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -const char* mal_get_backend_name(mal_backend backend) -{ - switch (backend) - { - case mal_backend_null: return "Null"; - case mal_backend_wasapi: return "WASAPI"; - case mal_backend_dsound: return "DirectSound"; - case mal_backend_winmm: return "WinMM"; - case mal_backend_alsa: return "ALSA"; - //case mal_backend_pulse: return "PulseAudio"; - //case mal_backend_jack: return "JACK"; - //case mal_backend_coreaudio: return "Core Audio"; - case mal_backend_oss: return "OSS"; - case mal_backend_opensl: return "OpenSL|ES"; - case mal_backend_openal: return "OpenAL"; - case mal_backend_sdl: return "SDL"; - default: return "Unknown"; - } -} - -const char* mal_get_format_name(mal_format format) -{ - switch (format) - { - case mal_format_unknown: return "Unknown"; - case mal_format_u8: return "8-bit Unsigned Integer"; - case mal_format_s16: return "16-bit Signed Integer"; - case mal_format_s24: return "24-bit Signed Integer (Tightly Packed)"; - case mal_format_s32: return "32-bit Signed Integer"; - case mal_format_f32: return "32-bit IEEE Floating Point"; - default: return "Invalid"; - } -} - -void mal_blend_f32(float* pOut, float* pInA, float* pInB, float factor, mal_uint32 channels) -{ - for (mal_uint32 i = 0; i < channels; ++i) { - pOut[i] = mal_mix_f32(pInA[i], pInB[i], factor); - } -} - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// -// -// AUTO-GENERATED -// -// -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// FORMAT CONVERSION -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mal_pcm_u8_to_s16(short* pOut, const unsigned char* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x - 128; - r = r << 8; - pOut[i] = (short)r; - } -} - -void mal_pcm_u8_to_s24(void* pOut, const unsigned char* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x - 128; - r = r << 16; - ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); - } -} - -void mal_pcm_u8_to_s32(int* pOut, const unsigned char* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x - 128; - r = r << 24; - pOut[i] = (int)r; - } -} - -void mal_pcm_u8_to_f32(float* pOut, const unsigned char* pIn, unsigned int count) -{ - float r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x * 0.00784313725490196078f; - r = r - 1; - pOut[i] = (float)r; - } -} - -void mal_pcm_s16_to_u8(unsigned char* pOut, const short* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x >> 8; - r = r + 128; - pOut[i] = (unsigned char)r; - } -} - -void mal_pcm_s16_to_s24(void* pOut, const short* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x << 8; - ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); - } -} - -void mal_pcm_s16_to_s32(int* pOut, const short* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x << 16; - pOut[i] = (int)r; - } -} - -void mal_pcm_s16_to_f32(float* pOut, const short* pIn, unsigned int count) -{ - float r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = (float)(x + 32768); - r = r * 0.00003051804379339284f; - r = r - 1; - pOut[i] = (float)r; - } -} - -void mal_pcm_s24_to_u8(unsigned char* pOut, const void* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; - r = x >> 16; - r = r + 128; - pOut[i] = (unsigned char)r; - } -} - -void mal_pcm_s24_to_s16(short* pOut, const void* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; - r = x >> 8; - pOut[i] = (short)r; - } -} - -void mal_pcm_s24_to_s32(int* pOut, const void* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; - r = x << 8; - pOut[i] = (int)r; - } -} - -void mal_pcm_s24_to_f32(float* pOut, const void* pIn, unsigned int count) -{ - float r; - for (unsigned int i = 0; i < count; ++i) { - int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8; - r = (float)(x + 8388608); - r = r * 0.00000011920929665621f; - r = r - 1; - pOut[i] = (float)r; - } -} - -void mal_pcm_s32_to_u8(unsigned char* pOut, const int* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x >> 24; - r = r + 128; - pOut[i] = (unsigned char)r; - } -} - -void mal_pcm_s32_to_s16(short* pOut, const int* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x >> 16; - pOut[i] = (short)r; - } -} - -void mal_pcm_s32_to_s24(void* pOut, const int* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - r = x >> 8; - ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); - } -} - -void mal_pcm_s32_to_f32(float* pOut, const int* pIn, unsigned int count) -{ - float r; - for (unsigned int i = 0; i < count; ++i) { - int x = pIn[i]; - double t; - t = (double)(x + 2147483647); - t = t + 1; - t = t * 0.0000000004656612873077392578125; - r = (float)(t - 1); - pOut[i] = (float)r; - } -} - -void mal_pcm_f32_to_u8(unsigned char* pOut, const float* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - float x = pIn[i]; - float c; - c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - c = c + 1; - r = (int)(c * 127.5f); - pOut[i] = (unsigned char)r; - } -} - -void mal_pcm_f32_to_s16(short* pOut, const float* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - float x = pIn[i]; - float c; - c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - c = c + 1; - r = (int)(c * 32767.5f); - r = r - 32768; - pOut[i] = (short)r; - } -} - -void mal_pcm_f32_to_s24(void* pOut, const float* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - float x = pIn[i]; - float c; - c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - c = c + 1; - r = (int)(c * 8388607.5f); - r = r - 8388608; - ((unsigned char*)pOut)[(i*3)+0] = (unsigned char)(r & 0xFF); ((unsigned char*)pOut)[(i*3)+1] = (unsigned char)((r & 0xFF00) >> 8); ((unsigned char*)pOut)[(i*3)+2] = (unsigned char)((r & 0xFF0000) >> 16); - } -} - -void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) -{ - int r; - for (unsigned int i = 0; i < count; ++i) { - float x = pIn[i]; - float c; - mal_int64 t; - c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); - c = c + 1; - t = (mal_int64)(c * 2147483647.5); - t = t - 2147483647; - r = (int)(t - 1); - pOut[i] = (int)r; - } -} - -#endif - - -// REVISION HISTORY -// ================ -// -// 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 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. - -For more information, please refer to -*/ diff --git a/raylib/external/miniaudio.h b/raylib/external/miniaudio.h new file mode 100644 index 0000000..c74bebe --- /dev/null +++ b/raylib/external/miniaudio.h @@ -0,0 +1,93468 @@ +/* +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 + +David Reid - mackron@gmail.com + +Website: https://miniaud.io +Documentation: https://miniaud.io/docs +GitHub: https://github.com/mackron/miniaudio +*/ + +/* +1. Introduction +=============== +To use miniaudio, include "miniaudio.h": + + ```c + #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: + + ```c + #include "miniaudio.c" + ``` + +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. + +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. + + ```c + void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) + { + // In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both + // pOutput and pInput will be valid and you can move data from pInput into pOutput. Never process more than + // frameCount frames. + } + + int main() + { + ma_device_config config = ma_device_config_init(ma_device_type_playback); + config.playback.format = ma_format_f32; // Set to ma_format_unknown to use the device's native format. + config.playback.channels = 2; // Set to 0 to use the device's native channel count. + config.sampleRate = 48000; // Set to 0 to use the device's native sample rate. + config.dataCallback = data_callback; // This function will be called when miniaudio needs more data. + config.pUserData = pMyCustomData; // Can be accessed from the device object (device.pUserData). + + ma_device device; + if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) { + return -1; // Failed to initialize the device. + } + + ma_device_start(&device); // The device is sleeping by default so you'll need to start it manually. + + // Do something here. Probably your program's main loop. + + ma_device_uninit(&device); + 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. + +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 | + +---------------+----------------------------------------+---------------------------+ + | ma_format_f32 | 32-bit floating point | [-1, 1] | + | ma_format_s16 | 16-bit signed integer | [-32768, 32767] | + | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607] | + | ma_format_s32 | 32-bit signed integer | [-2147483648, 2147483647] | + | 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. + +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. + +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() + ma_device_init_ex() + ma_device_uninit() + ma_device_start() + 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. + +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); + config.capture.format = MY_FORMAT; + 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`). + +These are the available device types and how you should handle the buffers in the callback: + + +-------------------------+--------------------------------------------------------+ + | Device Type | Callback Behavior | + +-------------------------+--------------------------------------------------------+ + | ma_device_type_playback | Write to output buffer, leave input buffer untouched. | + | ma_device_type_capture | Read from input buffer, leave output buffer untouched. | + | ma_device_type_duplex | Read from input buffer, write to output buffer. | + | 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. + +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. + + ```c + ma_context context; + if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) { + // Error. + } + + ma_device_info* pPlaybackInfos; + ma_uint32 playbackCount; + ma_device_info* pCaptureInfos; + ma_uint32 captureCount; + if (ma_context_get_devices(&context, &pPlaybackInfos, &playbackCount, &pCaptureInfos, &captureCount) != MA_SUCCESS) { + // Error. + } + + // Loop over each device info and do something with it. Here we just print the name with their index. You may want + // to give the user the opportunity to choose which device they'd prefer. + for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) { + printf("%d - %s\n", iDevice, pPlaybackInfos[iDevice].name); + } + + ma_device_config config = ma_device_config_init(ma_device_type_playback); + config.playback.pDeviceID = &pPlaybackInfos[chosenPlaybackDeviceIndex].id; + config.playback.format = MY_FORMAT; + config.playback.channels = MY_CHANNEL_COUNT; + config.sampleRate = MY_SAMPLE_RATE; + config.dataCallback = data_callback; + config.pUserData = pMyCustomData; + + ma_device device; + if (ma_device_init(&context, &config, &device) != MA_SUCCESS) { + // Error + } + + ... + + ma_device_uninit(&device); + 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. + +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. + +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. + + + +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`. + + +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()`. + + +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`. + +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: + + ``` + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.allow-unsigned-executable-memory + + ``` + +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. + + +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. + + +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. + + +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 + + + +2.7. Build Options +------------------ +`#define` these options before including miniaudio.c, or pass them as compiler flags: + + +----------------------------------+--------------------------------------------------------------------+ + | Option | Description | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_WASAPI | Disables the WASAPI backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_DSOUND | Disables the DirectSound backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_WINMM | Disables the WinMM backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_ALSA | Disables the ALSA backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_PULSEAUDIO | Disables the PulseAudio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_JACK | Disables the JACK backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_COREAUDIO | Disables the Core Audio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_SNDIO | Disables the sndio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_AUDIO4 | Disables the audio(4) backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_OSS | Disables the OSS backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_AAUDIO | Disables the AAudio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_OPENSL | Disables the OpenSL|ES backend. | + +----------------------------------+--------------------------------------------------------------------+ + | 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 | + | | enable specific backends. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_WASAPI | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the WASAPI backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_DSOUND | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the DirectSound backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_WINMM | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the WinMM backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_ALSA | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the ALSA backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_PULSEAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the PulseAudio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_JACK | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the JACK backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_COREAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the Core Audio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_SNDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the sndio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_AUDIO4 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the audio(4) backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_OSS | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the OSS backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_AAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the AAudio backend. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_OPENSL | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable the OpenSL|ES backend. | + +----------------------------------+--------------------------------------------------------------------+ + | 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. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_DECODING | Disables decoding APIs. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_ENCODING | Disables encoding APIs. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_WAV | Disables the built-in WAV decoder and encoder. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_FLAC | Disables the built-in FLAC decoder. | + +----------------------------------+--------------------------------------------------------------------+ + | 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_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_DEVICE_IO | + | | ``` | + +----------------------------------+--------------------------------------------------------------------+ + | 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_NEON | Disables NEON optimizations. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_RUNTIME_LINKING | Disables runtime linking. This is useful for passing Apple's | + | | notarization process. When enabling this, you may need to avoid | + | | using `-std=c89` or `-std=c99` on Linux builds or else you may end | + | | up with compilation errors due to conflicts with `timespec` and | + | | `timeval` data types. | + | | | + | | 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_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | + +----------------------------------+--------------------------------------------------------------------+ + | 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`. | + +----------------------------------+--------------------------------------------------------------------+ + + +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. + +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. + +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". + +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. + +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. + +3.5. Formats +------------ +Throughout miniaudio you will see references to different sample formats: + + +---------------+----------------------------------------+---------------------------+ + | Symbol | Description | Range | + +---------------+----------------------------------------+---------------------------+ + | ma_format_f32 | 32-bit floating point | [-1, 1] | + | ma_format_s16 | 16-bit signed integer | [-32768, 32767] | + | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607] | + | ma_format_s32 | 32-bit signed integer | [-2147483648, 2147483647] | + | ma_format_u8 | 8-bit unsigned integer | [0, 255] | + +---------------+----------------------------------------+---------------------------+ + +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 +=========== +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: + + +---------+ + | Format | + +---------+ + | WAV | + | MP3 | + | FLAC | + +---------+ + +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 + #define MA_NO_MP3 + #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. + +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; + ma_result result = ma_decoder_init_file("MySong.mp3", NULL, &decoder); + if (result != MA_SUCCESS) { + return false; // An error occurred. + } + + ... + + 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: + + ```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. + +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. + + ```c + ma_result result = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead, &framesRead); + if (framesRead < framesToRead) { + // Reached the end. + } + ``` + +You can also seek to a specific frame like so: + + ```c + ma_result result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame); + if (result != MA_SUCCESS) { + return false; // An error occurred. + } + ``` + +If you want to loop back to the start, you can simply seek back to the first PCM frame: + + ```c + 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: + + ```c + decoderConfig.encodingFormat = ma_encoding_format_wav; + ``` + +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. + + + +9. 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: + + ```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. + + ```c + ma_encoder_config config = ma_encoder_config_init(ma_encoding_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) { + // Error + } + + ... + + 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: + + +------------------------+-------------+ + | Enum | Description | + +------------------------+-------------+ + | ma_encoding_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: + + ```c + ma_uint64 framesWritten; + result = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite, &framesWritten); + if (result != MA_SUCCESS) { + ... handle error ... + } + ``` + +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. + + +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. + + +10.1.1. Dithering +----------------- +Dithering can be set using the ditherMode parameter. + +The different dithering modes include the following, in order of efficiency: + + +-----------+--------------------------+ + | Type | Enum Token | + +-----------+--------------------------+ + | None | ma_dither_mode_none | + | Rectangle | ma_dither_mode_rectangle | + | 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: + + ``` + s16 -> u8 + s24 -> u8 + s32 -> u8 + f32 -> u8 + s24 -> s16 + s32 -> s16 + 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. + + + +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. + + ```c + ma_channel_converter_config config = ma_channel_converter_config_init( + ma_format, // Sample format + 1, // Input channels + NULL, // Input channel map + 2, // Output channels + 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); + if (result != MA_SUCCESS) { + // Error. + } + ``` + +To perform the conversion simply call `ma_channel_converter_process_pcm_frames()` like so: + + ```c + ma_result result = ma_channel_converter_process_pcm_frames(&converter, pFramesOut, pFramesIn, frameCount); + if (result != MA_SUCCESS) { + // Error. + } + ``` + +It is up to the caller to ensure the output buffer is large enough to accommodate 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. + +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. + +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 +`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: + + +-----------------------------------+-----------------------------------------------------------+ + | Name | Description | + +-----------------------------------+-----------------------------------------------------------+ + | ma_standard_channel_map_default | Default channel map used by miniaudio. See below. | + | ma_standard_channel_map_microsoft | Channel map used by Microsoft's bitfield channel maps. | + | ma_standard_channel_map_alsa | Default ALSA channel map. | + | ma_standard_channel_map_rfc3551 | RFC 3551. Based on AIFF. | + | ma_standard_channel_map_flac | FLAC channel map. | + | ma_standard_channel_map_vorbis | Vorbis channel map. | + | ma_standard_channel_map_sound4 | FreeBSD's sound(4). | + | ma_standard_channel_map_sndio | sndio channel map. http://www.sndio.org/tips.html. | + | ma_standard_channel_map_webaudio | https://webaudio.github.io/web-audio-api/#ChannelOrdering | + +-----------------------------------+-----------------------------------------------------------+ + +Below are the channel maps used by default in miniaudio (`ma_standard_channel_map_default`): + + +---------------+---------------------------------+ + | Channel Count | Mapping | + +---------------+---------------------------------+ + | 1 (Mono) | 0: MA_CHANNEL_MONO | + +---------------+---------------------------------+ + | 2 (Stereo) | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT | + +---------------+---------------------------------+ + | 3 | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER | + +---------------+---------------------------------+ + | 4 (Surround) | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER
| + | | 3: MA_CHANNEL_BACK_CENTER | + +---------------+---------------------------------+ + | 5 | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER
| + | | 3: MA_CHANNEL_BACK_LEFT
| + | | 4: MA_CHANNEL_BACK_RIGHT | + +---------------+---------------------------------+ + | 6 (5.1) | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER
| + | | 3: MA_CHANNEL_LFE
| + | | 4: MA_CHANNEL_SIDE_LEFT
| + | | 5: MA_CHANNEL_SIDE_RIGHT | + +---------------+---------------------------------+ + | 7 | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER
| + | | 3: MA_CHANNEL_LFE
| + | | 4: MA_CHANNEL_BACK_CENTER
| + | | 4: MA_CHANNEL_SIDE_LEFT
| + | | 5: MA_CHANNEL_SIDE_RIGHT | + +---------------+---------------------------------+ + | 8 (7.1) | 0: MA_CHANNEL_FRONT_LEFT
| + | | 1: MA_CHANNEL_FRONT_RIGHT
| + | | 2: MA_CHANNEL_FRONT_CENTER
| + | | 3: MA_CHANNEL_LFE
| + | | 4: MA_CHANNEL_BACK_LEFT
| + | | 5: MA_CHANNEL_BACK_RIGHT
| + | | 6: MA_CHANNEL_SIDE_LEFT
| + | | 7: MA_CHANNEL_SIDE_RIGHT | + +---------------+---------------------------------+ + | Other | All channels set to 0. This | + | | is equivalent to the same | + | | mapping as the device. | + +---------------+---------------------------------+ + + + +10.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( + ma_format_s16, + channels, + sampleRateIn, + sampleRateOut, + ma_resample_algorithm_linear); + + ma_resampler resampler; + ma_result result = ma_resampler_init(&config, NULL, &resampler); + if (result != MA_SUCCESS) { + // An error occurred... + } + ``` + +Do the following to uninitialize the resampler: + + ```c + ma_resampler_uninit(&resampler); + ``` + +The following example shows how data can be processed + + ```c + ma_uint64 frameCountIn = 1000; + ma_uint64 frameCountOut = 2000; + ma_result result = ma_resampler_process_pcm_frames(&resampler, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut); + if (result != MA_SUCCESS) { + // An error occurred... + } + + // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the + // 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. + +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 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: + + +-----------+------------------------------+ + | Algorithm | Enum Token | + +-----------+------------------------------+ + | Linear | ma_resample_algorithm_linear | + | Custom | ma_resample_algorithm_custom | + +-----------+------------------------------+ + +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. + +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()`. + +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. + + +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. + +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 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 +------------------------- +You can implement a custom resampler by using the `ma_resample_algorithm_custom` resampling +algorithm and setting a vtable in the resampler config: + + ```c + ma_resampler_config config = ma_resampler_config_init(..., ma_resample_algorithm_custom); + config.pBackendVTable = &g_customResamplerVTable; + ``` + +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. + +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. + +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`. + +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. + + + +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: + + ```c + ma_data_converter_config config = ma_data_converter_config_init( + inputFormat, + outputFormat, + inputChannels, + outputChannels, + inputSampleRate, + outputSampleRate + ); + + ma_data_converter converter; + ma_result result = ma_data_converter_init(&config, NULL, &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: + + ```c + ma_data_converter_config config = ma_data_converter_config_init_default(); + config.formatIn = inputFormat; + config.formatOut = outputFormat; + config.channelsIn = inputChannels; + 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); + config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER; + ``` + +Do the following to uninitialize the data converter: + + ```c + ma_data_converter_uninit(&converter, NULL); + ``` + +The following example shows how data can be processed + + ```c + ma_uint64 frameCountIn = 1000; + ma_uint64 frameCountOut = 2000; + ma_result result = ma_data_converter_process_pcm_frames(&converter, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut); + if (result != MA_SUCCESS) { + // An error occurred... + } + + // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number + // 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. + +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. + +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()`. + + + +11. Filtering +============= + +11.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); + if (result != MA_SUCCESS) { + // Error. + } + + ... + + 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. + +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: + + ```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. + + +11.2. Low-Pass Filtering +------------------------ +Low-pass filtering is achieved with the following APIs: + + +---------+------------------------------------------+ + | API | Description | + +---------+------------------------------------------+ + | ma_lpf1 | First order low-pass filter | + | ma_lpf2 | Second order low-pass filter | + | ma_lpf | High order low-pass filter (Butterworth) | + +---------+------------------------------------------+ + +Low-pass filter example: + + ```c + ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + ma_result result = ma_lpf_init(&config, &lpf); + if (result != MA_SUCCESS) { + // Error. + } + + ... + + 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. + +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. + + ```c + for (iFilter = 0; iFilter < filterCount; iFilter += 1) { + ma_lpf2_process_pcm_frames(&lpf2[iFilter], pMyData, pMyData, frameCount); + } + ``` + +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. + +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. + + +11.3. High-Pass Filtering +------------------------- +High-pass filtering is achieved with the following APIs: + + +---------+-------------------------------------------+ + | API | Description | + +---------+-------------------------------------------+ + | ma_hpf1 | First order high-pass filter | + | ma_hpf2 | Second order high-pass filter | + | 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. + + +11.4. Band-Pass Filtering +------------------------- +Band-pass filtering is achieved with the following APIs: + + +---------+-------------------------------+ + | API | Description | + +---------+-------------------------------+ + | ma_bpf2 | Second order band-pass filter | + | 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. + + +11.5. Notch Filtering +--------------------- +Notch filtering is achieved with the following APIs: + + +-----------+------------------------------------------+ + | API | Description | + +-----------+------------------------------------------+ + | ma_notch2 | Second order notching filter | + +-----------+------------------------------------------+ + + +11.6. Peaking EQ Filtering +------------------------- +Peaking filtering is achieved with the following APIs: + + +----------+------------------------------------------+ + | API | Description | + +----------+------------------------------------------+ + | ma_peak2 | Second order peaking filter | + +----------+------------------------------------------+ + + +11.7. Low Shelf Filtering +------------------------- +Low shelf filtering is achieved with the following APIs: + + +-------------+------------------------------------------+ + | API | Description | + +-------------+------------------------------------------+ + | 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. + + +11.8. High Shelf Filtering +-------------------------- +High shelf filtering is achieved with the following APIs: + + +-------------+------------------------------------------+ + | API | Description | + +-------------+------------------------------------------+ + | 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. + + + + +12. 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: + + ```c + ma_waveform_config config = ma_waveform_config_init( + FORMAT, + CHANNELS, + SAMPLE_RATE, + ma_waveform_type_sine, + amplitude, + frequency); + + ma_waveform waveform; + ma_result result = ma_waveform_init(&config, &waveform); + if (result != MA_SUCCESS) { + // Error. + } + + ... + + 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. + +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: + + +---------------------------+ + | Enum Name | + +---------------------------+ + | ma_waveform_type_sine | + | ma_waveform_type_square | + | ma_waveform_type_triangle | + | ma_waveform_type_sawtooth | + +---------------------------+ + + + +12.2. Noise +----------- +miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example: + + ```c + ma_noise_config config = ma_noise_config_init( + FORMAT, + CHANNELS, + ma_noise_type_white, + SEED, + amplitude); + + ma_noise noise; + ma_result result = ma_noise_init(&config, &noise); + if (result != MA_SUCCESS) { + // Error. + } + + ... + + 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 amplitude and seed can be changed dynamically with `ma_noise_set_amplitude()` and +`ma_noise_set_seed()` 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: + + ```c + config.duplicateChannels = MA_TRUE; + ``` + +Below are the supported noise types. + + +------------------------+ + | Enum Name | + +------------------------+ + | ma_noise_type_white | + | ma_noise_type_pink | + | ma_noise_type_brownian | + +------------------------+ + + + +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. + +Audio buffers are initialized using the standard configuration system used everywhere in miniaudio: + + ```c + ma_audio_buffer_config config = ma_audio_buffer_config_init( + format, + channels, + sizeInFrames, + pExistingData, + &allocationCallbacks); + + ma_audio_buffer buffer; + result = ma_audio_buffer_init(&config, &buffer); + if (result != MA_SUCCESS) { + // Error. + } + + ... + + 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()`. + +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( + format, + channels, + sizeInFrames, + pExistingData, + &allocationCallbacks); + + ma_audio_buffer* pBuffer + result = ma_audio_buffer_alloc_and_init(&config, &pBuffer); + if (result != MA_SUCCESS) { + // Error + } + + ... + + 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()`. + +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); + if (framesRead < desiredFrameCount) { + // If not looping, this means the end has been reached. This should never happen in looping mode with valid input. + } + ``` + +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; + ma_uint64 frameCount = frameCountToTryMapping; + ma_result result = ma_audio_buffer_map(pAudioBuffer, &pMappedFrames, &frameCount); + if (result == MA_SUCCESS) { + // Map was successful. The value in frameCount will be how many frames were _actually_ mapped, which may be + // less due to the end of the buffer being reached. + ma_copy_pcm_frames(pFramesOut, pMappedFrames, frameCount, pAudioBuffer->format, pAudioBuffer->channels); + + // You must unmap the buffer. + ma_audio_buffer_unmap(pAudioBuffer, frameCount); + } + ``` + +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 +================ +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. + +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; + ma_result result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &rb); + if (result != MA_SUCCESS) { + // Error + } + ``` + +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. + +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. + +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 +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. + +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. + + + +15. 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. + + +-------------+-----------------------+--------------------------------------------------------+ + | Name | Enum Name | Supported Operating Systems | + +-------------+-----------------------+--------------------------------------------------------+ + | WASAPI | ma_backend_wasapi | Windows Vista+ | + | DirectSound | ma_backend_dsound | Windows XP+ | + | WinMM | ma_backend_winmm | Windows 95+ | + | Core Audio | ma_backend_coreaudio | macOS, iOS | + | 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) | + | Custom | ma_backend_custom | Cross Platform | + | Null | ma_backend_null | Cross Platform (not used on Web) | + +-------------+-----------------------+--------------------------------------------------------+ + +Some backends have some nuance details you may want to be aware of. + +15.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. + +15.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. + +15.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. + +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 +--------- +- UWP only supports default playback and capture devices. +- UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest): + + ``` + + ... + + + + + ``` + +15.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. + + + +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 +======================= +- 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. +*/ + +#ifndef miniaudio_h +#define miniaudio_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define MA_STRINGIFY(x) #x +#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_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) + +#if defined(_MSC_VER) && !defined(__clang__) + #pragma warning(push) + #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */ + #pragma warning(disable:4214) /* nonstandard extension used: bit field types other than int */ + #pragma warning(disable:4324) /* structure was padded due to alignment specifier */ +#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 + + +#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 +#else + #define MA_SIZEOF_PTR 4 +#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; +#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 + #endif + #endif +#endif /* MA_USE_STDINT */ + +#if MA_SIZEOF_PTR == 8 + typedef ma_uint64 ma_uintptr; +#else + typedef ma_uint32 ma_uintptr; +#endif + +typedef ma_uint8 ma_bool8; +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 + +#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) +typedef ma_uint16 wchar_t; +#endif + +/* Define NULL for some compilers. */ +#ifndef NULL +#define NULL 0 +#endif + +#if defined(SIZE_MAX) + #define MA_SIZE_MAX SIZE_MAX +#else + #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */ +#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 + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define MA_GNUC_INLINE_HINT __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)) + #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(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_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 + + + +/* +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. + +MA_LOG_LEVEL_DEBUG + Used for debugging. Useful for debug and test builds, but should be disabled in release builds. + +MA_LOG_LEVEL_INFO + Informational logging. Useful for debugging. 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. + +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. +*/ +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; + +/* +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. +*/ +#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 + +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_MIN_CHANNELS 1 +#ifndef MA_MAX_CHANNELS +#define MA_MAX_CHANNELS 254 +#endif + +#ifndef MA_MAX_FILTER_ORDER +#define MA_MAX_FILTER_ORDER 8 +#endif + +typedef enum +{ + ma_stream_format_pcm = 0 +} ma_stream_format; + +typedef enum +{ + ma_stream_layout_interleaved = 0, + ma_stream_layout_deinterleaved +} ma_stream_layout; + +typedef enum +{ + ma_dither_mode_none = 0, + ma_dither_mode_rectangle, + ma_dither_mode_triangle +} ma_dither_mode; + +typedef enum +{ + /* + I like to keep these explicitly defined because they're used as a key into a lookup table. When items are + added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample(). + */ + ma_format_unknown = 0, /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */ + ma_format_u8 = 1, + ma_format_s16 = 2, /* Seems to be the most widely supported format. */ + ma_format_s24 = 3, /* Tightly packed. 3 bytes per sample. */ + ma_format_s32 = 4, + ma_format_f32 = 5, + ma_format_count +} ma_format; + +typedef enum +{ + /* Standard rates need to be in priority order. */ + ma_standard_sample_rate_48000 = 48000, /* Most common */ + ma_standard_sample_rate_44100 = 44100, + + 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_8000 = 8000, + + ma_standard_sample_rate_352800 = 352800, /* Extreme highs */ + ma_standard_sample_rate_384000 = 384000, + + ma_standard_sample_rate_min = ma_standard_sample_rate_8000, + ma_standard_sample_rate_max = ma_standard_sample_rate_384000, + 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; + + +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; + +typedef enum +{ + ma_standard_channel_map_microsoft, + ma_standard_channel_map_alsa, + ma_standard_channel_map_rfc3551, /* Based off AIFF. */ + ma_standard_channel_map_flac, + ma_standard_channel_map_vorbis, + ma_standard_channel_map_sound4, /* FreeBSD's sound(4). */ + ma_standard_channel_map_sndio, /* www.sndio.org/tips.html */ + ma_standard_channel_map_webaudio = ma_standard_channel_map_flac, /* https://webaudio.github.io/web-audio-api/#ChannelOrdering. Only 1, 2, 4 and 6 channels are defined, but can fill in the gaps with logical assumptions. */ + ma_standard_channel_map_default = ma_standard_channel_map_microsoft +} ma_standard_channel_map; + +typedef enum +{ + ma_performance_profile_low_latency = 0, + ma_performance_profile_conservative +} ma_performance_profile; + + +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); +} ma_allocation_callbacks; + +typedef struct +{ + ma_int32 state; +} 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) + + +/* 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_POSIX) + typedef ma_pthread_t ma_thread; + #elif defined(MA_WIN32) + typedef ma_handle ma_thread; + #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_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 +#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 +#endif /* MA_NO_THREADING */ + + +/* +Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required. +*/ +MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision); + +/* +Retrieves the version of miniaudio as a string which can be useful for logging purposes. +*/ +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 + +**************************************************************************************************************************************************************/ +typedef union +{ + float f32; + ma_int32 s32; +} ma_biquad_coefficient; + +typedef struct +{ + ma_format format; + ma_uint32 channels; + double b0; + double b1; + double b2; + double a0; + double a1; + double a2; +} ma_biquad_config; + +MA_API ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_biquad_coefficient b0; + ma_biquad_coefficient b1; + 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; + +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_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); + + +/************************************************************************************************************************************************************** + +Low-Pass Filtering + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + double q; +} ma_lpf1_config, ma_lpf2_config; + +MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency); +MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_biquad_coefficient a; + ma_biquad_coefficient* pR1; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} 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_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); + +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_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); + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */ +} ma_lpf_config; + +MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_uint32 lpf1Count; + ma_uint32 lpf2Count; + ma_lpf1* pLPF1; + ma_lpf2* pLPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} 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_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); + + +/************************************************************************************************************************************************************** + +High-Pass Filtering + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + double q; +} ma_hpf1_config, ma_hpf2_config; + +MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency); +MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_biquad_coefficient a; + ma_biquad_coefficient* pR1; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} 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_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); + +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_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); + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */ +} ma_hpf_config; + +MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_uint32 hpf1Count; + ma_uint32 hpf2Count; + ma_hpf1* pHPF1; + ma_hpf2* pHPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} 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_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); + + +/************************************************************************************************************************************************************** + +Band-Pass Filtering + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + double q; +} ma_bpf2_config; + +MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q); + +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_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); + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double cutoffFrequency; + ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */ +} ma_bpf_config; + +MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 bpf2Count; + ma_bpf2* pBPF2; + + /* Memory management. */ + void* _pHeap; + ma_bool32 _ownsHeap; +} 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_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); + + +/************************************************************************************************************************************************************** + +Notching Filter + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double q; + double frequency; +} ma_notch2_config, ma_notch_config; + +MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency); + +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_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); + + +/************************************************************************************************************************************************************** + +Peaking EQ Filter + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double gainDB; + double q; + double frequency; +} ma_peak2_config, ma_peak_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); + +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_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); + + +/************************************************************************************************************************************************************** + +Low Shelf Filter + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double gainDB; + double shelfSlope; + double frequency; +} ma_loshelf2_config, ma_loshelf_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); + +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_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); + + +/************************************************************************************************************************************************************** + +High Shelf Filter + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + double gainDB; + double shelfSlope; + double frequency; +} ma_hishelf2_config, ma_hishelf_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); + +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_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); + + + +/************************************************************************************************************************************************************ +************************************************************************************************************************************************************* + +DATA CONVERSION +=============== + +This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc. + +************************************************************************************************************************************************************* +************************************************************************************************************************************************************/ + +/************************************************************************************************************************************************************** + +Resampling + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRateIn; + ma_uint32 sampleRateOut; + ma_uint32 lpfOrder; /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */ + double lpfNyquistFactor; /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */ +} ma_linear_resampler_config; + +MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); + +typedef struct +{ + ma_linear_resampler_config config; + ma_uint32 inAdvanceInt; + ma_uint32 inAdvanceFrac; + ma_uint32 inTimeInt; + ma_uint32 inTimeFrac; + union + { + float* f32; + ma_int16* s16; + } x0; /* The previous input frame. */ + union + { + float* f32; + ma_int16* s16; + } 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_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_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; + +struct ma_resampler_config +{ + 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; + struct + { + ma_uint32 lpfOrder; + } linear; +}; + +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; + 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; +} 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); + +/* +Uninitializes a resampler. +*/ +MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +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. + +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 +ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames. + +On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole +input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames +you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead. + +If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of +output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input +frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be +processed. In this case, any internal filter state will be updated as if zeroes were passed in. + +It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL. + +It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL. +*/ +MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut); + + +/* +Sets the input and output sample rate. +*/ +MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut); + +/* +Sets the input and output sample rate as a ratio. + +The ration is in/out. +*/ +MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio); + +/* +Retrieves the latency introduced by the resampler in input frames. +*/ +MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler); + +/* +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); + + +/************************************************************************************************************************************************************** + +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_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. */ +} 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); + +typedef struct +{ + ma_format format; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + 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; +} 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_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); + + +/************************************************************************************************************************************************************** + +Data Conversion + +**************************************************************************************************************************************************************/ +typedef struct +{ + ma_format formatIn; + ma_format formatOut; + ma_uint32 channelsIn; + ma_uint32 channelsOut; + ma_uint32 sampleRateIn; + ma_uint32 sampleRateOut; + ma_channel* pChannelMapIn; + ma_channel* pChannelMapOut; + 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; +} 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_channel_converter channelConverter; + ma_resampler resampler; + ma_bool8 hasPreFormatConversion; + ma_bool8 hasPostFormatConversion; + 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_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_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); + + +/************************************************************************************************************************************************************ + +Format Conversion + +************************************************************************************************************************************************************/ +MA_API void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_u8_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_u8_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_u8_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s16_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s16_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s16_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s16_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s24_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s24_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s24_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s24_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_s32_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_f32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_f32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_f32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_f32_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode); +MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode); +MA_API void ma_convert_pcm_frames_format(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 frameCount, ma_uint32 channels, ma_dither_mode ditherMode); + +/* +Deinterleaves an interleaved buffer. +*/ +MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames); + +/* +Interleaves a group of deinterleaved buffers. +*/ +MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames); + + +/************************************************************************************************************************************************************ + +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); + +/* +Helper for retrieving a standard channel map. + +The output channel map buffer must have a capacity of at least `channelMapCap`. +*/ +MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels); + +/* +Copies a channel map. + +Both input and output channel map buffers must have a capacity of at least `channels`. +*/ +MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); + +/* +Copies a channel map if one is specified, otherwise copies the default channel map. + +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); + + +/* +Determines whether or not a channel map is valid. + +A blank channel map is valid (all channels set to MA_CHANNEL_NONE). The way a blank channel map is handled is context specific, but +is usually treated as a passthrough. + +Invalid channel maps: + - A channel map with no channels + - A channel map with more than one channel and a mono channel + +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); + +/* +Helper for comparing two channel maps for equality. + +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); + +/* +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); + +/* +Helper for determining whether or not a channel is present in the given channel map. + +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); + + +/************************************************************************************************************************************************************ + +Conversion Helpers + +************************************************************************************************************************************************************/ + +/* +High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to +determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is +ignored. + +A return value of 0 indicates an error. + +This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead. +*/ +MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn); +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 + +************************************************************************************************************************************************************/ +typedef struct +{ + void* pBuffer; + 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_allocation_callbacks allocationCallbacks; +} ma_rb; + +MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB); +MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB); +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_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_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. */ +MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB); +MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB); +MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB); +MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB); +MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex); +MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer); + + +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); +MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB); +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_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_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. */ +MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB); +MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB); +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); + + +/* +The idea of the duplex ring buffer is to act as the intermediary buffer when running two asynchronous devices in a duplex set up. The +capture device writes to it, and then a playback device reads from it. + +At the moment this is just a simple naive implementation, but in the future I want to implement some dynamic resampling to seamlessly +handle desyncs. Note that the API is work in progress and may change at any time in any version. + +The size of the buffer is based on the capture side since that's what'll be written to the buffer. It is based on the capture period size +in frames. The internal sample rate of the capture device is also needed in order to calculate the size. +*/ +typedef struct +{ + ma_pcm_rb rb; +} ma_duplex_rb; + +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); +MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB); + + +/************************************************************************************************************************************************************ + +Miscellaneous Helpers + +************************************************************************************************************************************************************/ +/* +Retrieves a human readable description of the given result code. +*/ +MA_API const char* ma_result_description(ma_result result); + +/* +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() +*/ +MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +free() +*/ +MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +Performs an aligned malloc, with the assumption that the alignment is a power of 2. +*/ +MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +Free's an aligned malloc'd buffer. +*/ +MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks); + +/* +Retrieves a friendly name for a format. +*/ +MA_API const char* ma_get_format_name(ma_format format); + +/* +Blends two frames in floating point format. +*/ +MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels); + +/* +Retrieves the size of a sample in bytes for the given format. + +This API is efficient and is implemented using a lookup table. + +Thread Safety: SAFE + This API is pure. +*/ +MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format); +static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; } + +/* +Converts a log level to a string. +*/ +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. */ + + + +/************************************************************************************************************************************************************ +************************************************************************************************************************************************************* + +DEVICE I/O +========== + +This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc. + +************************************************************************************************************************************************************* +************************************************************************************************************************************************************/ +#ifndef MA_NO_DEVICE_IO +/* 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. */ + #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 + #endif +#endif +#if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO) + #if defined(MA_LINUX) + #if !defined(MA_ANDROID) && !defined(__COSMOPOLITAN__) /* ALSA is not supported on Android. */ + #define MA_SUPPORT_ALSA + #endif + #endif + #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN) + #define MA_SUPPORT_PULSEAUDIO + #define MA_SUPPORT_JACK + #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 + #if defined(__NetBSD__) || defined(__OpenBSD__) + #define MA_SUPPORT_AUDIO4 /* Only support audio(4) on platforms with known support. */ + #endif + #if defined(__FreeBSD__) || defined(__DragonFly__) + #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 +#if defined(MA_EMSCRIPTEN) + #define MA_SUPPORT_WEBAUDIO +#endif + +/* All platforms should support custom backends. */ +#define MA_SUPPORT_CUSTOM + +/* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */ +#if !defined(MA_EMSCRIPTEN) +#define MA_SUPPORT_NULL +#endif + + +#if defined(MA_SUPPORT_WASAPI) && !defined(MA_NO_WASAPI) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WASAPI)) + #define MA_HAS_WASAPI +#endif +#if defined(MA_SUPPORT_DSOUND) && !defined(MA_NO_DSOUND) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_DSOUND)) + #define MA_HAS_DSOUND +#endif +#if defined(MA_SUPPORT_WINMM) && !defined(MA_NO_WINMM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WINMM)) + #define MA_HAS_WINMM +#endif +#if defined(MA_SUPPORT_ALSA) && !defined(MA_NO_ALSA) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_ALSA)) + #define MA_HAS_ALSA +#endif +#if defined(MA_SUPPORT_PULSEAUDIO) && !defined(MA_NO_PULSEAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_PULSEAUDIO)) + #define MA_HAS_PULSEAUDIO +#endif +#if defined(MA_SUPPORT_JACK) && !defined(MA_NO_JACK) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_JACK)) + #define MA_HAS_JACK +#endif +#if defined(MA_SUPPORT_COREAUDIO) && !defined(MA_NO_COREAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_COREAUDIO)) + #define MA_HAS_COREAUDIO +#endif +#if defined(MA_SUPPORT_SNDIO) && !defined(MA_NO_SNDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_SNDIO)) + #define MA_HAS_SNDIO +#endif +#if defined(MA_SUPPORT_AUDIO4) && !defined(MA_NO_AUDIO4) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AUDIO4)) + #define MA_HAS_AUDIO4 +#endif +#if defined(MA_SUPPORT_OSS) && !defined(MA_NO_OSS) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OSS)) + #define MA_HAS_OSS +#endif +#if defined(MA_SUPPORT_AAUDIO) && !defined(MA_NO_AAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AAUDIO)) + #define MA_HAS_AAUDIO +#endif +#if defined(MA_SUPPORT_OPENSL) && !defined(MA_NO_OPENSL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OPENSL)) + #define MA_HAS_OPENSL +#endif +#if defined(MA_SUPPORT_WEBAUDIO) && !defined(MA_NO_WEBAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WEBAUDIO)) + #define MA_HAS_WEBAUDIO +#endif +#if defined(MA_SUPPORT_CUSTOM) && !defined(MA_NO_CUSTOM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_CUSTOM)) + #define MA_HAS_CUSTOM +#endif +#if defined(MA_SUPPORT_NULL) && !defined(MA_NO_NULL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_NULL)) + #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) + + +#ifdef MA_SUPPORT_WASAPI +/* We need a IMMNotificationClient object for WASAPI. */ +typedef struct +{ + void* lpVtbl; + ma_uint32 counter; + ma_device* pDevice; +} ma_IMMNotificationClient; +#endif + +/* Backend enums must be in priority order. */ +typedef enum +{ + ma_backend_wasapi, + ma_backend_dsound, + ma_backend_winmm, + ma_backend_coreaudio, + ma_backend_sndio, + ma_backend_audio4, + ma_backend_oss, + ma_backend_pulseaudio, + ma_backend_alsa, + ma_backend_jack, + ma_backend_aaudio, + ma_backend_opensl, + ma_backend_webaudio, + ma_backend_custom, /* <-- Custom backend, with callbacks defined by the context config. */ + ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */ +} ma_backend; + +#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. + +The data callback is fired by miniaudio whenever the device needs to have more data delivered to a playback device, or when a capture device has some data +available. This is called as soon as the backend asks for more data which means it may be called with inconsistent frame counts. You cannot assume the +callback will be fired with a consistent frame count. + + +Parameters +---------- +pDevice (in) + A pointer to the relevant device. + +pOutput (out) + A pointer to the output buffer that will receive audio data that will later be played back through the speakers. This will be non-null for a playback or + full-duplex device and null for a capture and loopback device. + +pInput (in) + A pointer to the buffer containing input data from a recording device. This will be non-null for a capture, full-duplex or loopback device and null for a + playback device. + +frameCount (in) + The number of PCM frames to process. Note that this will not necessarily be equal to what you requested when you initialized the device. The + `periodSizeInFrames` and `periodSizeInMilliseconds` members of the device config are just hints, and are not necessarily exactly what you'll get. You must + not assume this will always be the same value each time the callback is fired. + + +Remarks +------- +You cannot stop and start the device from inside the callback or else you'll get a deadlock. You must also not uninitialize the device from inside the +callback. The following APIs cannot be called from inside the callback: + + ma_device_init() + ma_device_init_ex() + ma_device_uninit() + ma_device_start() + ma_device_stop() + +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); + + + + +/* +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. + + +Parameters +---------- +pDevice (in) + A pointer to the device that has just stopped. + + +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 enum +{ + ma_device_type_playback = 1, + ma_device_type_capture = 2, + ma_device_type_duplex = ma_device_type_playback | ma_device_type_capture, /* 3 */ + ma_device_type_loopback = 4 +} ma_device_type; + +typedef enum +{ + ma_share_mode_shared = 0, + ma_share_mode_exclusive +} ma_share_mode; + +/* iOS/tvOS/watchOS session categories. */ +typedef enum +{ + ma_ios_session_category_default = 0, /* AVAudioSessionCategoryPlayAndRecord. */ + ma_ios_session_category_none, /* Leave the session category unchanged. */ + ma_ios_session_category_ambient, /* AVAudioSessionCategoryAmbient */ + ma_ios_session_category_solo_ambient, /* AVAudioSessionCategorySoloAmbient */ + ma_ios_session_category_playback, /* AVAudioSessionCategoryPlayback */ + ma_ios_session_category_record, /* AVAudioSessionCategoryRecord */ + ma_ios_session_category_play_and_record, /* AVAudioSessionCategoryPlayAndRecord */ + ma_ios_session_category_multi_route /* AVAudioSessionCategoryMultiRoute */ +} ma_ios_session_category; + +/* iOS/tvOS/watchOS session category options */ +typedef enum +{ + ma_ios_session_category_option_mix_with_others = 0x01, /* AVAudioSessionCategoryOptionMixWithOthers */ + ma_ios_session_category_option_duck_others = 0x02, /* AVAudioSessionCategoryOptionDuckOthers */ + ma_ios_session_category_option_allow_bluetooth = 0x04, /* AVAudioSessionCategoryOptionAllowBluetooth */ + ma_ios_session_category_option_default_to_speaker = 0x08, /* AVAudioSessionCategoryOptionDefaultToSpeaker */ + ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others = 0x11, /* AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */ + ma_ios_session_category_option_allow_bluetooth_a2dp = 0x20, /* AVAudioSessionCategoryOptionAllowBluetoothA2DP */ + ma_ios_session_category_option_allow_air_play = 0x40, /* AVAudioSessionCategoryOptionAllowAirPlay */ +} ma_ios_session_category_option; + +/* OpenSL stream types. */ +typedef enum +{ + ma_opensl_stream_type_default = 0, /* Leaves the stream type unset. */ + ma_opensl_stream_type_voice, /* SL_ANDROID_STREAM_VOICE */ + ma_opensl_stream_type_system, /* SL_ANDROID_STREAM_SYSTEM */ + ma_opensl_stream_type_ring, /* SL_ANDROID_STREAM_RING */ + ma_opensl_stream_type_media, /* SL_ANDROID_STREAM_MEDIA */ + ma_opensl_stream_type_alarm, /* SL_ANDROID_STREAM_ALARM */ + ma_opensl_stream_type_notification /* SL_ANDROID_STREAM_NOTIFICATION */ +} ma_opensl_stream_type; + +/* OpenSL recording presets. */ +typedef enum +{ + ma_opensl_recording_preset_default = 0, /* Leaves the input preset unset. */ + ma_opensl_recording_preset_generic, /* SL_ANDROID_RECORDING_PRESET_GENERIC */ + ma_opensl_recording_preset_camcorder, /* SL_ANDROID_RECORDING_PRESET_CAMCORDER */ + ma_opensl_recording_preset_voice_recognition, /* SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION */ + ma_opensl_recording_preset_voice_communication, /* SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION */ + 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_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; + +/* 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; + +/* AAudio input presets. */ +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_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 +{ + ma_int64 counter; + double counterD; +} ma_timer; + +typedef union +{ + ma_wchar_win32 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. */ + char pulse[256]; /* PulseAudio uses a name string for identification. */ + int jack; /* JACK always uses default devices. */ + char coreaudio[256]; /* Core Audio uses a string for identification. */ + char sndio[256]; /* "snd/0", etc. */ + char audio4[256]; /* "/dev/audio", etc. */ + char oss[64]; /* "dev/dsp0", etc. "dev/dsp" for the default device. */ + ma_int32 aaudio; /* AAudio uses a 32-bit integer for identification. */ + ma_uint32 opensl; /* OpenSL|ES uses a 32-bit unsigned integer for identification. */ + char webaudio[32]; /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */ + union + { + int i; + char s[256]; + void* p; + } custom; /* The custom backend could be anything. Give them a few options. */ + 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; +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. */ + ma_bool32 isDefault; + + ma_uint32 nativeDataFormatCount; + struct + { + ma_format format; /* Sample format. If set to ma_format_unknown, all sample formats are supported. */ + ma_uint32 channels; /* If set to 0, all channels are supported. */ + ma_uint32 sampleRate; /* If set to 0, all sample rates are supported. */ + ma_uint32 flags; /* A combination of MA_DATA_FORMAT_FLAG_* flags. */ + } nativeDataFormats[/*ma_format_count * ma_standard_sample_rate_count * MA_MAX_CHANNELS*/ 64]; /* Not sure how big to make this. There can be *many* permutations for virtual devices which can support anything. */ +} ma_device_info; + +struct ma_device_config +{ + ma_device_type deviceType; + ma_uint32 sampleRate; + ma_uint32 periodSizeInFrames; + 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_stop_proc stopCallback; + void* pUserData; + ma_resampler_config resampling; + struct + { + const ma_device_id* pDeviceID; + ma_format format; + ma_uint32 channels; + ma_channel* pChannelMap; + 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 + { + const ma_device_id* pDeviceID; + ma_format format; + ma_uint32 channels; + ma_channel* pChannelMap; + 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. */ + } wasapi; + struct + { + ma_bool32 noMMap; /* Disables MMap mode. */ + ma_bool32 noAutoFormat; /* Opens the ALSA device with SND_PCM_NO_AUTO_FORMAT. */ + ma_bool32 noAutoChannels; /* Opens the ALSA device with SND_PCM_NO_AUTO_CHANNELS. */ + ma_bool32 noAutoResample; /* Opens the ALSA device with SND_PCM_NO_AUTO_RESAMPLE. */ + } alsa; + struct + { + const char* pStreamNamePlayback; + const char* pStreamNameCapture; + int channelMap; + } pulse; + struct + { + ma_bool32 allowNominalSampleRateChange; /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */ + } coreaudio; + struct + { + 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()`. + + +Parameters +---------- +pContext (in) + A pointer to the context performing the enumeration. + +deviceType (in) + The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`. + +pInfo (in) + A pointer to a `ma_device_info` containing the ID and name of the enumerated device. Note that this will not include detailed information about the device, + only basic information (ID and name). The reason for this is that it would otherwise require opening the backend device to probe for the information which + is too inefficient. + +pUserData (in) + The user data pointer passed into `ma_context_enumerate_devices()`. +*/ +typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData); + + +/* +Describes some basic details about a playback or capture device. +*/ +typedef struct +{ + const ma_device_id* pDeviceID; + ma_share_mode shareMode; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_channel channelMap[MA_MAX_CHANNELS]; + ma_uint32 periodSizeInFrames; + ma_uint32 periodSizeInMilliseconds; + ma_uint32 periodCount; +} ma_device_descriptor; + +/* +These are the callbacks required to be implemented for a backend. These callbacks are grouped into two parts: context and device. There is one context +to many devices. A device is created from a context. + +The general flow goes like this: + + 1) A context is created with `onContextInit()` + 1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required. + 1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required. + 2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was + selected from device enumeration via `onContextEnumerateDevices()`. + 3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()` + 4) Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call + to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by + miniaudio internally. + +Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the +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. + +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 +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 +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 +`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` +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 +asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should always be implemented. + +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. +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 +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 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 +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 +{ + ma_result (* onContextInit)(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks); + ma_result (* onContextUninit)(ma_context* pContext); + ma_result (* onContextEnumerateDevices)(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); + ma_result (* onContextGetDeviceInfo)(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo); + ma_result (* onDeviceInit)(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture); + ma_result (* onDeviceUninit)(ma_device* pDevice); + ma_result (* onDeviceStart)(ma_device* pDevice); + ma_result (* onDeviceStop)(ma_device* pDevice); + ma_result (* onDeviceRead)(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead); + 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_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; + struct + { + const char* pApplicationName; + const char* pServerName; + ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */ + } pulse; + struct + { + ma_ios_session_category sessionCategory; + ma_uint32 sessionCategoryOptions; + ma_bool32 noAudioSessionActivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. */ + ma_bool32 noAudioSessionDeactivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */ + } coreaudio; + struct + { + const char* pClientName; + ma_bool32 tryStartServer; + } jack; + ma_backend_callbacks custom; +}; + +/* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */ +typedef struct +{ + int code; + ma_event* pEvent; /* This will be signalled when the event is complete. */ + union + { + struct + { + int _unused; + } quit; + struct + { + ma_device_type deviceType; + void* pAudioClient; + void** ppAudioClientService; + ma_result* pResult; /* The result from creating the audio client service. */ + } createAudioClient; + struct + { + ma_device* pDevice; + ma_device_type deviceType; + } releaseAudioClient; + } data; +} ma_context_command__wasapi; + +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_thread_priority threadPriority; + size_t threadStackSize; + void* pUserData; + ma_allocation_callbacks allocationCallbacks; + ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */ + ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */ + ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */ + ma_uint32 playbackDeviceInfoCount; + ma_uint32 captureDeviceInfoCount; + ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */ + + union + { +#ifdef MA_SUPPORT_WASAPI + struct + { + ma_thread commandThread; + ma_mutex commandLock; + ma_semaphore commandSem; + 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; + ma_proc DirectSoundCaptureCreate; + ma_proc DirectSoundCaptureEnumerateA; + } dsound; +#endif +#ifdef MA_SUPPORT_WINMM + struct + { + ma_handle hWinMM; + ma_proc waveOutGetNumDevs; + ma_proc waveOutGetDevCapsA; + ma_proc waveOutOpen; + ma_proc waveOutClose; + ma_proc waveOutPrepareHeader; + ma_proc waveOutUnprepareHeader; + ma_proc waveOutWrite; + ma_proc waveOutReset; + ma_proc waveInGetNumDevs; + ma_proc waveInGetDevCapsA; + ma_proc waveInOpen; + ma_proc waveInClose; + ma_proc waveInPrepareHeader; + ma_proc waveInUnprepareHeader; + ma_proc waveInAddBuffer; + ma_proc waveInStart; + ma_proc waveInReset; + } winmm; +#endif +#ifdef MA_SUPPORT_ALSA + struct + { + ma_handle asoundSO; + ma_proc snd_pcm_open; + ma_proc snd_pcm_close; + ma_proc snd_pcm_hw_params_sizeof; + ma_proc snd_pcm_hw_params_any; + ma_proc snd_pcm_hw_params_set_format; + ma_proc snd_pcm_hw_params_set_format_first; + ma_proc snd_pcm_hw_params_get_format_mask; + ma_proc snd_pcm_hw_params_set_channels; + ma_proc snd_pcm_hw_params_set_channels_near; + ma_proc snd_pcm_hw_params_set_channels_minmax; + ma_proc snd_pcm_hw_params_set_rate_resample; + ma_proc snd_pcm_hw_params_set_rate; + ma_proc snd_pcm_hw_params_set_rate_near; + ma_proc snd_pcm_hw_params_set_buffer_size_near; + ma_proc snd_pcm_hw_params_set_periods_near; + ma_proc snd_pcm_hw_params_set_access; + ma_proc snd_pcm_hw_params_get_format; + ma_proc snd_pcm_hw_params_get_channels; + ma_proc snd_pcm_hw_params_get_channels_min; + ma_proc snd_pcm_hw_params_get_channels_max; + ma_proc snd_pcm_hw_params_get_rate; + ma_proc snd_pcm_hw_params_get_rate_min; + ma_proc snd_pcm_hw_params_get_rate_max; + ma_proc snd_pcm_hw_params_get_buffer_size; + ma_proc snd_pcm_hw_params_get_periods; + ma_proc snd_pcm_hw_params_get_access; + ma_proc snd_pcm_hw_params_test_format; + ma_proc snd_pcm_hw_params_test_channels; + ma_proc snd_pcm_hw_params_test_rate; + ma_proc snd_pcm_hw_params; + ma_proc snd_pcm_sw_params_sizeof; + ma_proc snd_pcm_sw_params_current; + ma_proc snd_pcm_sw_params_get_boundary; + ma_proc snd_pcm_sw_params_set_avail_min; + ma_proc snd_pcm_sw_params_set_start_threshold; + ma_proc snd_pcm_sw_params_set_stop_threshold; + ma_proc snd_pcm_sw_params; + ma_proc snd_pcm_format_mask_sizeof; + ma_proc snd_pcm_format_mask_test; + ma_proc snd_pcm_get_chmap; + ma_proc snd_pcm_state; + ma_proc snd_pcm_prepare; + 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; + ma_proc snd_device_name_free_hint; + ma_proc snd_pcm_mmap_begin; + ma_proc snd_pcm_mmap_commit; + ma_proc snd_pcm_recover; + ma_proc snd_pcm_readi; + ma_proc snd_pcm_writei; + 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; + ma_bool32 useVerboseDeviceEnumeration; + } alsa; +#endif +#ifdef MA_SUPPORT_PULSEAUDIO + struct + { + ma_handle pulseSO; + ma_proc pa_mainloop_new; + ma_proc pa_mainloop_free; + ma_proc pa_mainloop_quit; + ma_proc pa_mainloop_get_api; + ma_proc pa_mainloop_iterate; + ma_proc pa_mainloop_wakeup; + ma_proc pa_threaded_mainloop_new; + ma_proc pa_threaded_mainloop_free; + ma_proc pa_threaded_mainloop_start; + ma_proc pa_threaded_mainloop_stop; + ma_proc pa_threaded_mainloop_lock; + ma_proc pa_threaded_mainloop_unlock; + ma_proc pa_threaded_mainloop_wait; + ma_proc pa_threaded_mainloop_signal; + ma_proc pa_threaded_mainloop_accept; + ma_proc pa_threaded_mainloop_get_retval; + ma_proc pa_threaded_mainloop_get_api; + ma_proc pa_threaded_mainloop_in_thread; + ma_proc pa_threaded_mainloop_set_name; + ma_proc pa_context_new; + ma_proc pa_context_unref; + ma_proc pa_context_connect; + ma_proc pa_context_disconnect; + ma_proc pa_context_set_state_callback; + ma_proc pa_context_get_state; + ma_proc pa_context_get_sink_info_list; + ma_proc pa_context_get_source_info_list; + ma_proc pa_context_get_sink_info_by_name; + ma_proc pa_context_get_source_info_by_name; + ma_proc pa_operation_unref; + ma_proc pa_operation_get_state; + ma_proc pa_channel_map_init_extend; + ma_proc pa_channel_map_valid; + ma_proc pa_channel_map_compatible; + ma_proc pa_stream_new; + ma_proc pa_stream_unref; + ma_proc pa_stream_connect_playback; + ma_proc pa_stream_connect_record; + ma_proc pa_stream_disconnect; + ma_proc pa_stream_get_state; + ma_proc pa_stream_get_sample_spec; + ma_proc pa_stream_get_channel_map; + ma_proc pa_stream_get_buffer_attr; + ma_proc pa_stream_set_buffer_attr; + 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; + ma_proc pa_stream_cork; + ma_proc pa_stream_trigger; + ma_proc pa_stream_begin_write; + ma_proc pa_stream_write; + ma_proc pa_stream_peek; + ma_proc pa_stream_drop; + ma_proc pa_stream_writable_size; + ma_proc pa_stream_readable_size; + + /*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 + struct + { + ma_handle jackSO; + ma_proc jack_client_open; + ma_proc jack_client_close; + ma_proc jack_client_name_size; + ma_proc jack_set_process_callback; + ma_proc jack_set_buffer_size_callback; + ma_proc jack_on_shutdown; + ma_proc jack_get_sample_rate; + ma_proc jack_get_buffer_size; + ma_proc jack_get_ports; + ma_proc jack_activate; + ma_proc jack_deactivate; + ma_proc jack_connect; + ma_proc jack_port_register; + ma_proc jack_port_name; + ma_proc jack_port_get_buffer; + ma_proc jack_free; + + char* pClientName; + ma_bool32 tryStartServer; + } jack; +#endif +#ifdef MA_SUPPORT_COREAUDIO + struct + { + ma_handle hCoreFoundation; + ma_proc CFStringGetCString; + ma_proc CFRelease; + + ma_handle hCoreAudio; + ma_proc AudioObjectGetPropertyData; + ma_proc AudioObjectGetPropertyDataSize; + ma_proc AudioObjectSetPropertyData; + ma_proc AudioObjectAddPropertyListener; + ma_proc AudioObjectRemovePropertyListener; + + ma_handle hAudioUnit; /* Could possibly be set to AudioToolbox on later versions of macOS. */ + ma_proc AudioComponentFindNext; + ma_proc AudioComponentInstanceDispose; + ma_proc AudioComponentInstanceNew; + ma_proc AudioOutputUnitStart; + ma_proc AudioOutputUnitStop; + ma_proc AudioUnitAddPropertyListener; + ma_proc AudioUnitGetPropertyInfo; + ma_proc AudioUnitGetProperty; + ma_proc AudioUnitSetProperty; + ma_proc AudioUnitInitialize; + ma_proc AudioUnitRender; + + /*AudioComponent*/ ma_ptr component; + ma_bool32 noAudioSessionDeactivate; /* For tracking whether or not the iOS audio session should be explicitly deactivated. Set from the config in ma_context_init__coreaudio(). */ + } coreaudio; +#endif +#ifdef MA_SUPPORT_SNDIO + struct + { + ma_handle sndioSO; + ma_proc sio_open; + ma_proc sio_close; + ma_proc sio_setpar; + ma_proc sio_getpar; + ma_proc sio_getcap; + ma_proc sio_start; + ma_proc sio_stop; + ma_proc sio_read; + ma_proc sio_write; + ma_proc sio_onmove; + ma_proc sio_nfds; + ma_proc sio_pollfd; + ma_proc sio_revents; + ma_proc sio_eof; + ma_proc sio_setvol; + ma_proc sio_onvol; + ma_proc sio_initpar; + } sndio; +#endif +#ifdef MA_SUPPORT_AUDIO4 + struct + { + int _unused; + } audio4; +#endif +#ifdef MA_SUPPORT_OSS + struct + { + int versionMajor; + int versionMinor; + } oss; +#endif +#ifdef MA_SUPPORT_AAUDIO + struct + { + ma_handle hAAudio; /* libaaudio.so */ + ma_proc AAudio_createStreamBuilder; + ma_proc AAudioStreamBuilder_delete; + ma_proc AAudioStreamBuilder_setDeviceId; + ma_proc AAudioStreamBuilder_setDirection; + ma_proc AAudioStreamBuilder_setSharingMode; + ma_proc AAudioStreamBuilder_setFormat; + ma_proc AAudioStreamBuilder_setChannelCount; + ma_proc AAudioStreamBuilder_setSampleRate; + ma_proc AAudioStreamBuilder_setBufferCapacityInFrames; + ma_proc AAudioStreamBuilder_setFramesPerDataCallback; + ma_proc AAudioStreamBuilder_setDataCallback; + ma_proc AAudioStreamBuilder_setErrorCallback; + ma_proc AAudioStreamBuilder_setPerformanceMode; + 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; + ma_proc AAudioStream_waitForStateChange; + ma_proc AAudioStream_getFormat; + ma_proc AAudioStream_getChannelCount; + ma_proc AAudioStream_getSampleRate; + ma_proc AAudioStream_getBufferCapacityInFrames; + ma_proc AAudioStream_getFramesPerDataCallback; + 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 + struct + { + ma_handle libOpenSLES; + ma_handle SL_IID_ENGINE; + ma_handle SL_IID_AUDIOIODEVICECAPABILITIES; + ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + ma_handle SL_IID_RECORD; + ma_handle SL_IID_PLAY; + ma_handle SL_IID_OUTPUTMIX; + ma_handle SL_IID_ANDROIDCONFIGURATION; + ma_proc slCreateEngine; + } opensl; +#endif +#ifdef MA_SUPPORT_WEBAUDIO + struct + { + int _unused; + } webaudio; +#endif +#ifdef MA_SUPPORT_NULL + struct + { + int _unused; + } null_backend; +#endif + }; + + union + { +#if defined(MA_WIN32) + struct + { + /*HMODULE*/ ma_handle hOle32DLL; + ma_proc CoInitialize; + ma_proc CoInitializeEx; + ma_proc CoUninitialize; + ma_proc CoCreateInstance; + ma_proc CoTaskMemFree; + ma_proc PropVariantClear; + ma_proc StringFromGUID2; + + /*HMODULE*/ ma_handle hUser32DLL; + ma_proc GetForegroundWindow; + ma_proc GetDesktopWindow; + + /*HMODULE*/ ma_handle hAdvapi32DLL; + ma_proc RegOpenKeyExA; + ma_proc RegCloseKey; + ma_proc RegQueryValueExA; + + /*HRESULT*/ long CoInitializeResult; + } win32; +#endif +#ifdef MA_POSIX + struct + { + int _unused; + } posix; +#endif + int _unused; + }; +}; + +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_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_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. */ + struct + { + ma_resample_algorithm algorithm; + ma_resampling_backend_vtable* pBackendVTable; + void* pBackendUserData; + struct + { + ma_uint32 lpfOrder; + } linear; + } 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. */ + ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ + ma_format format; + ma_uint32 channels; + ma_channel channelMap[MA_MAX_CHANNELS]; + ma_format internalFormat; + ma_uint32 internalChannels; + ma_uint32 internalSampleRate; + ma_channel internalChannelMap[MA_MAX_CHANNELS]; + 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. */ + ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */ + ma_format format; + ma_uint32 channels; + ma_channel channelMap[MA_MAX_CHANNELS]; + ma_format internalFormat; + ma_uint32 internalChannels; + ma_uint32 internalSampleRate; + ma_channel internalChannelMap[MA_MAX_CHANNELS]; + 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 + { +#ifdef MA_SUPPORT_WASAPI + struct + { + /*IAudioClient**/ ma_ptr pAudioClientPlayback; + /*IAudioClient**/ ma_ptr pAudioClientCapture; + /*IAudioRenderClient**/ ma_ptr pRenderClient; + /*IAudioCaptureClient**/ ma_ptr pCaptureClient; + /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator; /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */ + 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 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_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; + ma_bool8 allowCaptureAutoStreamRouting; + ma_bool8 allowPlaybackAutoStreamRouting; + ma_bool8 isDetachedPlayback; + ma_bool8 isDetachedCapture; + ma_wasapi_usage usage; + void* hAvrtHandle; + ma_mutex rerouteLock; + } wasapi; +#endif +#ifdef MA_SUPPORT_DSOUND + struct + { + /*LPDIRECTSOUND*/ ma_ptr pPlayback; + /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer; + /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer; + /*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture; + /*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer; + } dsound; +#endif +#ifdef MA_SUPPORT_WINMM + struct + { + /*HWAVEOUT*/ ma_handle hDevicePlayback; + /*HWAVEIN*/ ma_handle hDeviceCapture; + /*HANDLE*/ ma_handle hEventPlayback; + /*HANDLE*/ ma_handle hEventCapture; + ma_uint32 fragmentSizeInFrames; + ma_uint32 iNextHeaderPlayback; /* [0,periods). Used as an index into pWAVEHDRPlayback. */ + ma_uint32 iNextHeaderCapture; /* [0,periods). Used as an index into pWAVEHDRCapture. */ + ma_uint32 headerFramesConsumedPlayback; /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */ + ma_uint32 headerFramesConsumedCapture; /* ^^^ */ + /*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback; /* One instantiation for each period. */ + /*WAVEHDR**/ ma_uint8* pWAVEHDRCapture; /* One instantiation for each period. */ + ma_uint8* pIntermediaryBufferPlayback; + ma_uint8* pIntermediaryBufferCapture; + ma_uint8* _pHeapData; /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */ + } winmm; +#endif +#ifdef MA_SUPPORT_ALSA + struct + { + /*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; +#endif +#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; +#endif +#ifdef MA_SUPPORT_JACK + struct + { + /*jack_client_t**/ ma_ptr pClient; + /*jack_port_t**/ ma_ptr* ppPortsPlayback; + /*jack_port_t**/ ma_ptr* ppPortsCapture; + float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */ + float* pIntermediaryBufferCapture; + } jack; +#endif +#ifdef MA_SUPPORT_COREAUDIO + struct + { + ma_uint32 deviceObjectIDPlayback; + ma_uint32 deviceObjectIDCapture; + /*AudioUnit*/ ma_ptr audioUnitPlayback; + /*AudioUnit*/ ma_ptr audioUnitCapture; + /*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */ + ma_uint32 audioBufferCapInFrames; /* Only used for input devices. The capacity in frames of each buffer in pAudioBufferList. */ + ma_event stopEvent; + ma_uint32 originalPeriodSizeInFrames; + ma_uint32 originalPeriodSizeInMilliseconds; + ma_uint32 originalPeriods; + ma_performance_profile originalPerformanceProfile; + ma_bool32 isDefaultPlaybackDevice; + 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. */ + } coreaudio; +#endif +#ifdef MA_SUPPORT_SNDIO + struct + { + ma_ptr handlePlayback; + ma_ptr handleCapture; + ma_bool32 isStartedPlayback; + ma_bool32 isStartedCapture; + } sndio; +#endif +#ifdef MA_SUPPORT_AUDIO4 + struct + { + int fdPlayback; + int fdCapture; + } audio4; +#endif +#ifdef MA_SUPPORT_OSS + struct + { + int fdPlayback; + int fdCapture; + } oss; +#endif +#ifdef MA_SUPPORT_AAUDIO + struct + { + /*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 + struct + { + /*SLObjectItf*/ ma_ptr pOutputMixObj; + /*SLOutputMixItf*/ ma_ptr pOutputMix; + /*SLObjectItf*/ ma_ptr pAudioPlayerObj; + /*SLPlayItf*/ ma_ptr pAudioPlayer; + /*SLObjectItf*/ ma_ptr pAudioRecorderObj; + /*SLRecordItf*/ ma_ptr pAudioRecorder; + /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback; + /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture; + ma_bool32 isDrainingCapture; + ma_bool32 isDrainingPlayback; + ma_uint32 currentBufferIndexPlayback; + ma_uint32 currentBufferIndexCapture; + ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */ + ma_uint8* pBufferCapture; + } opensl; +#endif +#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. */ + } webaudio; +#endif +#ifdef MA_SUPPORT_NULL + struct + { + ma_thread deviceThread; + ma_event operationEvent; + ma_event operationCompletionEvent; + ma_semaphore operationSemaphore; + ma_uint32 operation; + ma_result operationResult; + ma_timer timer; + double priorRunTime; + ma_uint32 currentPeriodFramesRemainingPlayback; + 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. */ + } null_device; +#endif + }; +}; +#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 /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */ +#endif + +/* +Initializes a `ma_context_config` object. + + +Return Value +------------ +A `ma_context_config` initialized to defaults. + + +Remarks +------- +You must always use this to initialize the default state of the `ma_context_config` object. Not using this will result in your program breaking when miniaudio +is updated and new members are added to `ma_context_config`. It also sets logical defaults. + +You can override members of the returned object by changing it's members directly. + + +See Also +-------- +ma_context_init() +*/ +MA_API ma_context_config ma_context_config_init(void); + +/* +Initializes a context. + +The context is used for selecting and initializing an appropriate backend and to represent the backend at a more global level than that of an individual +device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices. + + +Parameters +---------- +backends (in, optional) + A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. + +backendCount (in, optional) + The number of items in `backend`. Ignored if `backend` is NULL. + +pConfig (in, optional) + The context configuration. + +pContext (in) + A pointer to the context object being initialized. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. Do not call this function across multiple threads as some backends read and write to global state. + + +Remarks +------- +When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order: + + |-------------|-----------------------|--------------------------------------------------------| + | Name | Enum Name | Supported Operating Systems | + |-------------|-----------------------|--------------------------------------------------------| + | WASAPI | ma_backend_wasapi | Windows Vista+ | + | DirectSound | ma_backend_dsound | Windows XP+ | + | 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 | + | AAudio | ma_backend_aaudio | Android 8+ | + | OpenSL|ES | ma_backend_opensl | Android (API level 16+) | + | Web Audio | ma_backend_webaudio | Web (via Emscripten) | + | Null | ma_backend_null | Cross Platform (not used on Web) | + |-------------|-----------------------|--------------------------------------------------------| + +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. + + threadPriority + The desired priority to use for the audio thread. Allowable values include the following: + + |--------------------------------------| + | Thread Priority | + |--------------------------------------| + | ma_thread_priority_idle | + | ma_thread_priority_lowest | + | ma_thread_priority_low | + | ma_thread_priority_normal | + | ma_thread_priority_high | + | ma_thread_priority_highest (default) | + | ma_thread_priority_realtime | + | 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`. + + allocationCallbacks + Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation + callbacks will be used for anything tied to the context, including devices. + + alsa.useVerboseDeviceEnumeration + ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique + card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes + it so the ALSA backend includes all devices. Defaults to false. + + pulse.pApplicationName + PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`. + + pulse.pServerName + PulseAudio only. The name of the server to connect to with `pa_context_connect()`. + + pulse.tryAutoSpawn + PulseAudio only. Whether or not to try automatically starting the PulseAudio daemon. Defaults to false. If you set this to true, keep in mind that + miniaudio uses a trial and error method to find the most appropriate backend, and this will result in the PulseAudio daemon starting which may be + intrusive for the end user. + + coreaudio.sessionCategory + iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. + + |-----------------------------------------|-------------------------------------| + | miniaudio Token | Core Audio Token | + |-----------------------------------------|-------------------------------------| + | ma_ios_session_category_ambient | AVAudioSessionCategoryAmbient | + | ma_ios_session_category_solo_ambient | AVAudioSessionCategorySoloAmbient | + | ma_ios_session_category_playback | AVAudioSessionCategoryPlayback | + | ma_ios_session_category_record | AVAudioSessionCategoryRecord | + | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord | + | ma_ios_session_category_multi_route | AVAudioSessionCategoryMultiRoute | + | ma_ios_session_category_none | AVAudioSessionCategoryAmbient | + | ma_ios_session_category_default | AVAudioSessionCategoryAmbient | + |-----------------------------------------|-------------------------------------| + + coreaudio.sessionCategoryOptions + iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents. + + |---------------------------------------------------------------------------|------------------------------------------------------------------| + | miniaudio Token | Core Audio Token | + |---------------------------------------------------------------------------|------------------------------------------------------------------| + | ma_ios_session_category_option_mix_with_others | AVAudioSessionCategoryOptionMixWithOthers | + | ma_ios_session_category_option_duck_others | AVAudioSessionCategoryOptionDuckOthers | + | ma_ios_session_category_option_allow_bluetooth | AVAudioSessionCategoryOptionAllowBluetooth | + | ma_ios_session_category_option_default_to_speaker | AVAudioSessionCategoryOptionDefaultToSpeaker | + | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | + | ma_ios_session_category_option_allow_bluetooth_a2dp | AVAudioSessionCategoryOptionAllowBluetoothA2DP | + | 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()`. + + jack.tryStartServer + Whether or not to try auto-starting the JACK server. Defaults to false. + + +It is recommended that only a single context is active at any given time because it's a bulky data structure which performs run-time linking for the +relevant backends every time it's initialized. + +The location of the context cannot change throughout it's lifetime. Consider allocating the `ma_context` object with `malloc()` if this is an issue. The +reason for this is that a pointer to the context is stored in the `ma_device` structure. + + +Example 1 - Default Initialization +---------------------------------- +The example below shows how to initialize the context using the default configuration. + +```c +ma_context context; +ma_result result = ma_context_init(NULL, 0, NULL, &context); +if (result != MA_SUCCESS) { + // Error. +} +``` + + +Example 2 - Custom Configuration +-------------------------------- +The example below shows how to initialize the context using custom backend priorities and a custom configuration. In this hypothetical example, the program +wants to prioritize ALSA over PulseAudio on Linux. They also want to avoid using the WinMM backend on Windows because it's latency is too high. They also +want an error to be returned if no valid backend is available which they achieve by excluding the Null backend. + +For the configuration, the program wants to capture any log messages so they can, for example, route it to a log file and user interface. + +```c +ma_backend backends[] = { + ma_backend_alsa, + ma_backend_pulseaudio, + ma_backend_wasapi, + 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. + +ma_context context; +ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context); +if (result != MA_SUCCESS) { + // Error. + if (result == MA_NO_BACKEND) { + // 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)); +``` + + +See Also +-------- +ma_context_config_init() +ma_context_uninit() +*/ +MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext); + +/* +Uninitializes a context. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. Do not call this function across multiple threads as some backends read and write to global state. + + +Remarks +------- +Results are undefined if you call this while any device created by this context is still active. + + +See Also +-------- +ma_context_init() +*/ +MA_API ma_result ma_context_uninit(ma_context* pContext); + +/* +Retrieves the size of the ma_context object. + +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). + +This is a lower-level enumeration function to the easier to use `ma_context_get_devices()`. Use `ma_context_enumerate_devices()` if you would rather not incur +an internal heap allocation, or it simply suits your code better. + +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. + +Returning false from the callback will stop enumeration. Returning true will continue enumeration. + + +Parameters +---------- +pContext (in) + A pointer to the context performing the enumeration. + +callback (in) + The callback to fire for each enumerated device. + +pUserData (in) + A pointer to application-defined data passed to the callback. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Safe. This is guarded using a simple mutex lock. + + +Remarks +------- +Do _not_ assume the first enumerated device of a given type is the default device. + +Some backends and platforms may only support default playback and capture devices. + +In general, you should not do anything complicated from within the callback. In particular, do not try initializing a device from within the callback. Also, +do not try to call `ma_context_get_device_info()` from within the callback. + +Consider using `ma_context_get_devices()` for a simpler and safer API, albeit at the expense of an internal heap allocation. + + +Example 1 - Simple Enumeration +------------------------------ +ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) +{ + printf("Device Name: %s\n", pInfo->name); + return MA_TRUE; +} + +ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData); +if (result != MA_SUCCESS) { + // Error. +} + + +See Also +-------- +ma_context_get_devices() +*/ +MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); + +/* +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 +---------- +pContext (in) + A pointer to the context performing the enumeration. + +ppPlaybackDeviceInfos (out) + A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices. + +pPlaybackDeviceCount (out) + A pointer to an unsigned integer that will receive the number of playback devices. + +ppCaptureDeviceInfos (out) + A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices. + +pCaptureDeviceCount (out) + A pointer to an unsigned integer that will receive the number of capture devices. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple +threads. Instead, you need to make a copy of the returned data with your own higher level synchronization. + + +Remarks +------- +It is _not_ safe to assume the first device in the list is the default device. + +You can pass in NULL for the playback or capture lists in which case they'll be ignored. + +The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers. + + +See Also +-------- +ma_context_enumerate_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); + +/* +Retrieves information about a device of the given type, with the specified ID and share mode. + + +Parameters +---------- +pContext (in) + A pointer to the context performing the query. + +deviceType (in) + The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`. + +pDeviceID (in) + The ID of the device being queried. + +pDeviceInfo (out) + A pointer to the `ma_device_info` structure that will receive the device information. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Safe. This is guarded using a simple mutex lock. + + +Remarks +------- +Do _not_ call this from within the `ma_context_enumerate_devices()` callback. + +It's possible for a device to have different information and capabilities depending on whether or not it's opened in shared or exclusive mode. For example, in +shared mode, WASAPI always uses floating point samples for mixing, but in exclusive mode it can be anything. Therefore, this function allows you to specify +which share mode you want information for. Note that not all backends and devices support shared or exclusive mode, in which case this function will fail if +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); + +/* +Determines if the given context supports loopback mode. + + +Parameters +---------- +pContext (in) + A pointer to the context getting queried. + + +Return Value +------------ +MA_TRUE if the context supports loopback mode; MA_FALSE otherwise. +*/ +MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext); + + + +/* +Initializes a device config with default settings. + + +Parameters +---------- +deviceType (in) + The type of the device this config is being initialized for. This must set to one of the following: + + |-------------------------| + | Device Type | + |-------------------------| + | ma_device_type_playback | + | ma_device_type_capture | + | ma_device_type_duplex | + | ma_device_type_loopback | + |-------------------------| + + +Return Value +------------ +A new device config object with default settings. You will typically want to adjust the config after this function returns. See remarks. + + +Thread Safety +------------- +Safe. + + +Callback Safety +--------------- +Safe, but don't try initializing a device in a callback. + + +Remarks +------- +The returned config will be initialized to defaults. You will normally want to customize a few variables before initializing the device. See Example 1 for a +typical configuration which sets the sample format, channel count, sample rate, data callback and user data. These are usually things you will want to change +before initializing the device. + +See `ma_device_init()` for details on specific configuration options. + + +Example 1 - Simple Configuration +-------------------------------- +The example below is what a program will typically want to configure for each device at a minimum. Notice how `ma_device_config_init()` is called first, and +then the returned object is modified directly. This is important because it ensures that your program continues to work as new configuration options are added +to the `ma_device_config` structure. + +```c +ma_device_config config = ma_device_config_init(ma_device_type_playback); +config.playback.format = ma_format_f32; +config.playback.channels = 2; +config.sampleRate = 48000; +config.dataCallback = ma_data_callback; +config.pUserData = pMyUserData; +``` + + +See Also +-------- +ma_device_init() +ma_device_init_ex() +*/ +MA_API ma_device_config ma_device_config_init(ma_device_type deviceType); + + +/* +Initializes a device. + +A device represents a physical audio device. The idea is you send or receive audio data from the device to either play it back through a speaker, or capture it +from a microphone. Whether or not you should send or receive data from the device (or both) depends on the type of device you are initializing which can be +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 +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 +media player you can make it larger. Note that the period size you request is actually just a hint - miniaudio will tell the backend what you want, but the +backend is ultimately responsible for what it gives you. You cannot assume you will get exactly what you ask for. + +When delivering data to and from a device you need to make sure it's in the correct format which you can set through the device configuration. You just set the +format that you want to use and miniaudio will perform all of the necessary conversion for you internally. When delivering data to and from the callback you +can assume the format is the same as what you requested when you initialized the device. See Remarks for more details on miniaudio's data conversion pipeline. + + +Parameters +---------- +pContext (in, optional) + A pointer to the context that owns the device. This can be null, in which case it creates a default context internally. + +pConfig (in) + A pointer to the device configuration. Cannot be null. See remarks for details. + +pDevice (out) + A pointer to the device object being initialized. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. It is not safe to call this function simultaneously for different devices because some backends depend on and mutate global state. The same applies to +calling this at the same time as `ma_device_uninit()`. + + +Callback Safety +--------------- +Unsafe. It is not safe to call this inside any callback. + + +Remarks +------- +Setting `pContext` to NULL will result in miniaudio creating a default context internally and is equivalent to passing in a context initialized like so: + + ```c + ma_context_init(NULL, 0, NULL, &context); + ``` + +Do not set `pContext` to NULL if you are needing to open multiple devices. You can, however, use NULL when initializing the first device, and then use +device.pContext for the initialization of other devices. + +The device can be configured via the `pConfig` argument. The config object is initialized with `ma_device_config_init()`. Individual configuration settings can +then be set directly on the structure. Below are the members of the `ma_device_config` object. + + deviceType + Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`. + + sampleRate + The sample rate, in hertz. The most common sample rates are 48000 and 44100. Setting this to 0 will use the device's native sample rate. + + periodSizeInFrames + The desired size of a period in PCM frames. If this is 0, `periodSizeInMilliseconds` will be used instead. If both are 0 the default buffer size will + be used depending on the selected performance profile. This value affects latency. See below for details. + + periodSizeInMilliseconds + The desired size of a period in milliseconds. If this is 0, `periodSizeInFrames` will be used instead. If both are 0 the default buffer size will be + used depending on the selected performance profile. The value affects latency. See below for details. + + periods + The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by + this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured. + + 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. + + noPreSilencedOutputBuffer + 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 + 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. + + pUserData + The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`. + + resampling.algorithm + 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 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)`. + + playback.pDeviceID + A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's + default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. + + playback.format + The sample format to use for playback. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after + initialization from the device object directly with `device.playback.format`. + + playback.channels + 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 + 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. + + 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 + exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to + ma_share_mode_shared and reinitializing. + + capture.pDeviceID + A pointer to a `ma_device_id` structure containing the ID of the capture device to initialize. Setting this NULL (default) will use the system's + default capture device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration. + + capture.format + The sample format to use for capture. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after + initialization from the device object directly with `device.capture.format`. + + capture.channels + 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 + 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. + + 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 + exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to + ma_share_mode_shared and reinitializing. + + wasapi.noAutoConvertSRC + WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false. + + wasapi.noDefaultQualitySRC + WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`. + You should usually leave this set to false, which is the default. + + wasapi.noAutoStreamRouting + WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false. + + wasapi.noHardwareOffloading + WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false. + + alsa.noMMap + ALSA only. When set to true, disables MMap mode. Defaults to false. + + alsa.noAutoFormat + ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false. + + alsa.noAutoChannels + ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false. + + alsa.noAutoResample + ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false. + + pulse.pStreamNamePlayback + PulseAudio only. Sets the stream name for playback. + + 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 + that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will + 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. + +After initializing the device it will be in a stopped state. To start it, use `ma_device_start()`. + +If both `periodSizeInFrames` and `periodSizeInMilliseconds` are set to zero, it will default to `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY` or +`MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE`, depending on whether or not `performanceProfile` is set to `ma_performance_profile_low_latency` or +`ma_performance_profile_conservative`. + +If you request exclusive mode and the backend does not support it an error will be returned. For robustness, you may want to first try initializing the device +in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the +config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA, +for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user. +Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary. + +When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by the config +and the format used internally by the backend. If you pass in 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run +on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`, +`playback/capture.channels` and `sampleRate` members of the device object. + +When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message +asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information. + +ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture. +If these fail it will try falling back to the "hw" device. + + +Example 1 - Simple Initialization +--------------------------------- +This example shows how to initialize a simple playback device using a standard configuration. If you are just needing to do simple playback from the default +playback device this is usually all you need. + +```c +ma_device_config config = ma_device_config_init(ma_device_type_playback); +config.playback.format = ma_format_f32; +config.playback.channels = 2; +config.sampleRate = 48000; +config.dataCallback = ma_data_callback; +config.pMyUserData = pMyUserData; + +ma_device device; +ma_result result = ma_device_init(NULL, &config, &device); +if (result != MA_SUCCESS) { + // Error +} +``` + + +Example 2 - Advanced Initialization +----------------------------------- +This example shows how you might do some more advanced initialization. In this hypothetical example we want to control the latency by setting the buffer size +and period count. We also want to allow the user to be able to choose which device to output from which means we need a context so we can perform device +enumeration. + +```c +ma_context context; +ma_result result = ma_context_init(NULL, 0, NULL, &context); +if (result != MA_SUCCESS) { + // Error +} + +ma_device_info* pPlaybackDeviceInfos; +ma_uint32 playbackDeviceCount; +result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); +if (result != MA_SUCCESS) { + // Error +} + +// ... choose a device from pPlaybackDeviceInfos ... + +ma_device_config config = ma_device_config_init(ma_device_type_playback); +config.playback.pDeviceID = pMyChosenDeviceID; // <-- Get this from the `id` member of one of the `ma_device_info` objects returned by ma_context_get_devices(). +config.playback.format = ma_format_f32; +config.playback.channels = 2; +config.sampleRate = 48000; +config.dataCallback = ma_data_callback; +config.pUserData = pMyUserData; +config.periodSizeInMilliseconds = 10; +config.periods = 3; + +ma_device device; +result = ma_device_init(&context, &config, &device); +if (result != MA_SUCCESS) { + // Error +} +``` + + +See Also +-------- +ma_device_config_init() +ma_device_uninit() +ma_device_start() +ma_context_init() +ma_context_get_devices() +ma_context_enumerate_devices() +*/ +MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice); + +/* +Initializes a device without a context, with extra parameters for controlling the configuration of the internal self-managed context. + +This is the same as `ma_device_init()`, only instead of a context being passed in, the parameters from `ma_context_init()` are passed in instead. This function +allows you to configure the internally created context. + + +Parameters +---------- +backends (in, optional) + A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order. + +backendCount (in, optional) + The number of items in `backend`. Ignored if `backend` is NULL. + +pContextConfig (in, optional) + The context configuration. + +pConfig (in) + A pointer to the device configuration. Cannot be null. See remarks for details. + +pDevice (out) + A pointer to the device object being initialized. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Unsafe. It is not safe to call this function simultaneously for different devices because some backends depend on and mutate global state. The same applies to +calling this at the same time as `ma_device_uninit()`. + + +Callback Safety +--------------- +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 +your own context. + +See the documentation for `ma_context_init()` for information on the different context configuration options. + + +See Also +-------- +ma_device_init() +ma_device_uninit() +ma_device_config_init() +ma_context_init() +*/ +MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice); + +/* +Uninitializes a device. + +This will explicitly stop the device. You do not need to call `ma_device_stop()` beforehand, but it's harmless if you do. + + +Parameters +---------- +pDevice (in) + A pointer to the device to stop. + + +Return Value +------------ +Nothing + + +Thread Safety +------------- +Unsafe. As soon as this API is called the device should be considered undefined. + + +Callback Safety +--------------- +Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock. + + +See Also +-------- +ma_device_init() +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. + +Use `ma_device_stop()` to stop the device. + + +Parameters +---------- +pDevice (in) + A pointer to the device to start. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Safe. It's safe to call this from any thread with the exception of the callback thread. + + +Callback Safety +--------------- +Unsafe. It is not safe to call this inside any callback. + + +Remarks +------- +For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid +audio data in the buffer, which needs to be done before the device begins playback. + +This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety. + +Do not call this in any callback. + + +See Also +-------- +ma_device_stop() +*/ +MA_API ma_result ma_device_start(ma_device* pDevice); + +/* +Stops the device. For playback devices this stops playback. For capture devices it stops recording. + +Use `ma_device_start()` to start the device again. + + +Parameters +---------- +pDevice (in) + A pointer to the device to stop. + + +Return Value +------------ +MA_SUCCESS if successful; any other error code otherwise. + + +Thread Safety +------------- +Safe. It's safe to call this from any thread with the exception of the callback thread. + + +Callback Safety +--------------- +Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock. + + +Remarks +------- +This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some +backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size +that was specified at initialization time). + +Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and +the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the +speakers or received from the microphone which can in turn result in de-syncs. + +Do not call this in any callback. + + +See Also +-------- +ma_device_start() +*/ +MA_API ma_result ma_device_stop(ma_device* pDevice); + +/* +Determines whether or not the device is started. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose start state is being retrieved. + + +Return Value +------------ +True if the device is started, false otherwise. + + +Thread Safety +------------- +Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return +value will be out of sync. + + +Callback Safety +--------------- +Safe. This is implemented as a simple accessor. + + +See Also +-------- +ma_device_start() +ma_device_stop() +*/ +MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice); + + +/* +Retrieves the state of the device. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose state is being retrieved. + + +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. | + +-------------------------------+------------------------------------------------------------------------------+ + + +Thread Safety +------------- +Safe. This is implemented as a simple accessor. Note that if the device is started or stopped at the same time as this function is called, +there's a possibility the return value could be out of sync. See remarks. + + +Callback Safety +--------------- +Safe. This is implemented as a simple accessor. + + +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 + ``` + +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); + + +/* +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 +values less than 0 decreases the volume. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose volume is being set. + +volume (in) + The new volume factor. Must be >= 0. + + +Return Value +------------ +MA_SUCCESS if the volume was set successfully. +MA_INVALID_ARGS if pDevice is NULL. +MA_INVALID_ARGS if volume is negative. + + +Thread Safety +------------- +Safe. This just sets a local member of the device object. + + +Callback Safety +--------------- +Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied. + + +Remarks +------- +This applies the volume factor across all channels. + +This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream. + + +See Also +-------- +ma_device_get_master_volume() +ma_device_set_master_volume_db() +ma_device_get_master_volume_db() +*/ +MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume); + +/* +Retrieves the master volume factor for the device. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose volume factor is being retrieved. + +pVolume (in) + A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1]. + + +Return Value +------------ +MA_SUCCESS if successful. +MA_INVALID_ARGS if pDevice is NULL. +MA_INVALID_ARGS if pVolume is NULL. + + +Thread Safety +------------- +Safe. This just a simple member retrieval. + + +Callback Safety +--------------- +Safe. + + +Remarks +------- +If an error occurs, `*pVolume` will be set to 0. + + +See Also +-------- +ma_device_set_master_volume() +ma_device_set_master_volume_gain_db() +ma_device_get_master_volume_gain_db() +*/ +MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume); + +/* +Sets the master volume for the device as gain in decibels. + +A gain of 0 is full volume, whereas a gain of < 0 will decrease the volume. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose gain is being set. + +gainDB (in) + The new volume as gain in decibels. Must be less than or equal to 0, where 0 is full volume and anything less than 0 decreases the volume. + + +Return Value +------------ +MA_SUCCESS if the volume was set successfully. +MA_INVALID_ARGS if pDevice is NULL. +MA_INVALID_ARGS if the gain is > 0. + + +Thread Safety +------------- +Safe. This just sets a local member of the device object. + + +Callback Safety +--------------- +Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied. + + +Remarks +------- +This applies the gain across all channels. + +This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream. + + +See Also +-------- +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); + +/* +Retrieves the master gain in decibels. + + +Parameters +---------- +pDevice (in) + A pointer to the device whose gain is being retrieved. + +pGainDB (in) + A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0. + + +Return Value +------------ +MA_SUCCESS if successful. +MA_INVALID_ARGS if pDevice is NULL. +MA_INVALID_ARGS if pGainDB is NULL. + + +Thread Safety +------------- +Safe. This just a simple member retrieval. + + +Callback Safety +--------------- +Safe. + + +Remarks +------- +If an error occurs, `*pGainDB` will be set to 0. + + +See Also +-------- +ma_device_set_master_volume_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); + + +/* +Called from the data callback of asynchronous backends to allow miniaudio to process the data and fire the miniaudio data callback. + + +Parameters +---------- +pDevice (in) + A pointer to device whose processing the data callback. + +pOutput (out) + A pointer to the buffer that will receive the output PCM frame data. On a playback device this must not be NULL. On a duplex device + this can be NULL, in which case pInput must not be NULL. + +pInput (in) + A pointer to the buffer containing input PCM frame data. On a capture device this must not be NULL. On a duplex device this can be + NULL, in which case `pOutput` must not be NULL. + +frameCount (in) + The number of frames being processed. + + +Return Value +------------ +MA_SUCCESS if successful; any other result code otherwise. + + +Thread Safety +------------- +This function should only ever be called from the internal data callback of the backend. It is safe to call this simultaneously between a +playback and capture device in duplex setups. + + +Callback Safety +--------------- +Do not call this from the miniaudio data callback. It should only ever be called from the internal data callback of the backend. + + +Remarks +------- +If both `pOutput` and `pInput` are NULL, and error will be returned. In duplex scenarios, both `pOutput` and `pInput` can be non-NULL, in +which case `pInput` will be processed first, followed by `pOutput`. + +If you are implementing a custom backend, and that backend uses a callback for data delivery, you'll need to call this from inside that +callback. +*/ +MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + + +/* +Calculates an appropriate buffer size from a descriptor, native sample rate and performance profile. + +This function is used by backends for helping determine an appropriately sized buffer to use with +the device depending on the values of `periodSizeInFrames` and `periodSizeInMilliseconds` in the +`pDescriptor` object. Since buffer size calculations based on time depends on the sample rate, a +best guess at the device's native sample rate is also required which is where `nativeSampleRate` +comes in. In addition, the performance profile is also needed for cases where both the period size +in frames and milliseconds are both zero. + + +Parameters +---------- +pDescriptor (in) + A pointer to device descriptor whose `periodSizeInFrames` and `periodSizeInMilliseconds` members + will be used for the calculation of the buffer size. + +nativeSampleRate (in) + The device's native sample rate. This is only ever used when the `periodSizeInFrames` member of + `pDescriptor` is zero. In this case, `periodSizeInMilliseconds` will be used instead, in which + case a sample rate is required to convert to a size in frames. + +performanceProfile (in) + When both the `periodSizeInFrames` and `periodSizeInMilliseconds` members of `pDescriptor` are + zero, miniaudio will fall back to a buffer size based on the performance profile. The profile + to use for this calculation is determine by this parameter. + + +Return Value +------------ +The calculated buffer size in frames. + + +Thread Safety +------------- +This is safe so long as nothing modifies `pDescriptor` at the same time. However, this function +should only ever be called from within the backend's device initialization routine and therefore +shouldn't have any multithreading concerns. + + +Callback Safety +--------------- +This is safe to call within the data callback, but there is no reason to ever do this. + + +Remarks +------- +If `nativeSampleRate` is zero, this function will fall back to `pDescriptor->sampleRate`. If that +is also zero, `MA_DEFAULT_SAMPLE_RATE` will be used instead. +*/ +MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile); + + + +/* +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. +*/ +MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend); + +/* +Retrieves compile-time enabled backends. + + +Parameters +---------- +pBackends (out, optional) + A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting + the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends. + +backendCap (in) + The capacity of the `pBackends` buffer. + +pBackendCount (out) + A pointer to the variable that will receive the enabled backend count. + + +Return Value +------------ +MA_SUCCESS if successful. +MA_INVALID_ARGS if `pBackendCount` is NULL. +MA_NO_SPACE if the capacity of `pBackends` is not large enough. + +If `MA_NO_SPACE` is returned, the `pBackends` buffer will be filled with `*pBackendCount` values. + + +Thread Safety +------------- +Safe. + + +Callback Safety +--------------- +Safe. + + +Remarks +------- +If you want to retrieve the number of backends so you can determine the capacity of `pBackends` buffer, you can call +this function with `pBackends` set to NULL. + +This will also enumerate the null backend. If you don't want to include this you need to check for `ma_backend_null` +when you enumerate over the returned backends and handle it appropriately. Alternatively, you can disable it at +compile time with `MA_NO_NULL`. + +The returned backends are determined based on compile time settings, not the platform it's currently running on. For +example, PulseAudio will be returned if it was enabled at compile time, even when the user doesn't actually have +PulseAudio installed. + + +Example 1 +--------- +The example below retrieves the enabled backend count using a fixed sized buffer allocated on the stack. The buffer is +given a capacity of `MA_BACKEND_COUNT` which will guarantee it'll be large enough to store all available backends. +Since `MA_BACKEND_COUNT` is always a relatively small value, this should be suitable for most scenarios. + +``` +ma_backend enabledBackends[MA_BACKEND_COUNT]; +size_t enabledBackendCount; + +result = ma_get_enabled_backends(enabledBackends, MA_BACKEND_COUNT, &enabledBackendCount); +if (result != MA_SUCCESS) { + // Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid. +} +``` + + +See Also +-------- +ma_is_backend_enabled() +*/ +MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount); + +/* +Determines whether or not loopback mode is support by a backend. +*/ +MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend); + +#endif /* MA_NO_DEVICE_IO */ + + + +/************************************************************************************************************************************************************ + +Utilities + +************************************************************************************************************************************************************/ + +/* +Calculates a buffer size in milliseconds (rounded up) 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); + +/* +Calculates a buffer size in frames from the specified number of milliseconds and sample rate. +*/ +MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate); + +/* +Copies PCM frames from one buffer to another. +*/ +MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels); + +/* +Copies silent frames into the given buffer. + +Remarks +------- +For all formats except `ma_format_u8`, the output buffer will be filled with 0. For `ma_format_u8` it will be filled with 128. The reason for this is that it +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); + + +/* +Offsets a pointer by the specified number of PCM frames. +*/ +MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); +MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels); +static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_ptr((void*)p, offsetInFrames, ma_format_f32, channels); } +static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (const float*)ma_offset_pcm_frames_const_ptr((const void*)p, offsetInFrames, ma_format_f32, channels); } + + +/* +Clips 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); + +/* +Helper for applying a volume factor to samples. + +Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place. +*/ +MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor); +MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor); +MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor); +MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor); +MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor); + +MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor); +MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor); +MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor); +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(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); +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_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float 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_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); + +/* +Helper for converting gain in decibels to a linear factor. +*/ +MA_API float ma_volume_db_to_linear(float gain); + + +/* +Mixes the specified number of frames in floating point format with a volume factor. + +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); + + + + +/************************************************************************************************************************************************************ + +VFS +=== + +The VFS object (virtual file system) is what's used to customize file access. This is useful in cases where stdio FILE* based APIs may not be entirely +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; + +typedef enum +{ + ma_seek_origin_start, + ma_seek_origin_current, + ma_seek_origin_end /* Not used by decoders. */ +} ma_seek_origin; + +typedef struct +{ + ma_uint64 sizeInBytes; +} ma_file_info; + +typedef struct +{ + ma_result (* onOpen) (ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile); + ma_result (* onOpenW)(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile); + ma_result (* onClose)(ma_vfs* pVFS, ma_vfs_file file); + ma_result (* onRead) (ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead); + ma_result (* onWrite)(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten); + ma_result (* onSeek) (ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin); + ma_result (* onTell) (ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor); + ma_result (* onInfo) (ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo); +} ma_vfs_callbacks; + +MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile); +MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile); +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_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten); +MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin); +MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor); +MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo); +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); + +typedef struct +{ + ma_vfs_callbacks cb; + ma_allocation_callbacks allocationCallbacks; /* Only used for the wchar_t version of open() on non-Windows platforms. */ +} ma_default_vfs; + +MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks); + + + +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; +#endif + +/************************************************************************************************************************************************************ + +Decoding +======== + +Decoders are independent of the main device API. Decoding APIs can be called freely inside the device's data callback, but they are not thread safe unless +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 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_mix_mode channelMixMode; + ma_dither_mode ditherMode; + ma_resampler_config 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_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_allocation_callbacks allocationCallbacks; + union + { + struct + { + ma_vfs* pVFS; + ma_vfs_file file; + } vfs; + struct + { + const ma_uint8* pData; + size_t dataSize; + size_t currentReadPos; + } memory; /* Only used for decoders that were opened against a block of memory. */ + } data; +}; + +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_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, 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_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_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. +*/ +MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor); + +/* +Retrieves the length of the decoder in PCM frames. + +Do not call this on streams of an undefined length, such as internet radio. + +If the length is unknown or an error occurs, 0 will be returned. + +This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio +uses internally. + +For MP3's, this will decode the entire file. Do not call this in time critical scenarios. + +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); + +/* +Retrieves the number of frames that can be read before reaching the end. + +This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in +particular ensuring you do not call it on streams of an undefined length, such as internet radio. + +If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be +returned. +*/ +MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames); + +/* +Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input, +pConfig should be set to what you want. On output it will be set to what you got. +*/ +MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut); +MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut); +MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut); + +#endif /* MA_NO_DECODING */ + + +/************************************************************************************************************************************************************ + +Encoding +======== + +Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned. + +************************************************************************************************************************************************************/ +#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 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 struct +{ + ma_encoding_format encodingFormat; + 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); + +struct ma_encoder +{ + ma_encoder_config config; + ma_encoder_write_proc onWrite; + ma_encoder_seek_proc onSeek; + ma_encoder_init_proc onInit; + 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; +}; + +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); + +#endif /* MA_NO_ENCODING */ + + +/************************************************************************************************************************************************************ + +Generation + +************************************************************************************************************************************************************/ +#ifndef MA_NO_GENERATION +typedef enum +{ + ma_waveform_type_sine, + ma_waveform_type_square, + ma_waveform_type_triangle, + ma_waveform_type_sawtooth +} ma_waveform_type; + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_waveform_type type; + double amplitude; + double frequency; +} ma_waveform_config; + +MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency); + +typedef struct +{ + ma_data_source_base 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_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, + ma_noise_type_pink, + ma_noise_type_brownian +} ma_noise_type; + + +typedef struct +{ + ma_format format; + ma_uint32 channels; + ma_noise_type type; + ma_int32 seed; + double amplitude; + ma_bool32 duplicateChannels; +} ma_noise_config; + +MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude); + +typedef struct +{ + ma_data_source_base ds; + ma_noise_config config; + ma_lcg lcg; + union + { + struct + { + double** bin; + double* accumulation; + ma_uint32* counter; + } pink; + struct + { + double* accumulation; + } 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_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 + +/************************************************************************************************************************************************************ +************************************************************************************************************************************************************* + +IMPLEMENTATION + +************************************************************************************************************************************************************* +************************************************************************************************************************************************************/ +#if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION) +#ifndef miniaudio_c +#define miniaudio_c + +#include +#include /* For INT_MAX */ +#include /* sin(), etc. */ +#include /* For malloc(), free(), wcstombs(). */ +#include /* For memset() */ + +#include +#include +#if !defined(_MSC_VER) && !defined(__DMC__) + #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) +#include +#include /* select() (used for ma_sleep()). */ +#include +#endif + +#ifdef MA_NX +#include /* For nanosleep() */ +#endif + +#include /* For fstat(), etc. */ + +#ifdef MA_EMSCRIPTEN +#include +#endif + + +/* Architecture Detection */ +#if !defined(MA_64BIT) && !defined(MA_32BIT) +#ifdef _WIN32 +#ifdef _WIN64 +#define MA_64BIT +#else +#define MA_32BIT +#endif +#endif +#endif + +#if !defined(MA_64BIT) && !defined(MA_32BIT) +#ifdef __GNUC__ +#ifdef __LP64__ +#define MA_64BIT +#else +#define MA_32BIT +#endif +#endif +#endif + +#if !defined(MA_64BIT) && !defined(MA_32BIT) +#include +#if INTPTR_MAX == INT64_MAX +#define MA_64BIT +#else +#define MA_32BIT +#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 + +#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) +#define MA_ARM +#endif + +/* Intrinsics Support */ +#if (defined(MA_X64) || defined(MA_X86)) && !defined(__COSMOPOLITAN__) + #if defined(_MSC_VER) && !defined(__clang__) + /* MSVC. */ + #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2) /* 2005 */ + #define MA_SUPPORT_SSE2 + #endif + /*#if _MSC_VER >= 1600 && !defined(MA_NO_AVX)*/ /* 2010 */ + /* #define MA_SUPPORT_AVX*/ + /*#endif*/ + #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2) /* 2012 */ + #define MA_SUPPORT_AVX2 + #endif + #else + /* Assume GNUC-style. */ + #if defined(__SSE2__) && !defined(MA_NO_SSE2) + #define MA_SUPPORT_SSE2 + #endif + /*#if defined(__AVX__) && !defined(MA_NO_AVX)*/ + /* #define MA_SUPPORT_AVX*/ + /*#endif*/ + #if defined(__AVX2__) && !defined(MA_NO_AVX2) + #define MA_SUPPORT_AVX2 + #endif + #endif + + /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && __has_include() + #define MA_SUPPORT_SSE2 + #endif + /*#if !defined(MA_SUPPORT_AVX) && !defined(MA_NO_AVX) && __has_include()*/ + /* #define MA_SUPPORT_AVX*/ + /*#endif*/ + #if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include() + #define MA_SUPPORT_AVX2 + #endif + #endif + + #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX) + #include + #elif defined(MA_SUPPORT_SSE2) + #include + #endif +#endif + +#if defined(MA_ARM) + #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + #define MA_SUPPORT_NEON + #include + #endif +#endif + +/* Begin globally disabled warnings. */ +#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) + #if defined(_MSC_VER) && !defined(__clang__) + #if _MSC_VER >= 1400 + #include + static MA_INLINE void ma_cpuid(int info[4], int fid) + { + __cpuid(info, fid); + } + #else + #define MA_NO_CPUID + #endif + + #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219) + static MA_INLINE unsigned __int64 ma_xgetbv(int reg) + { + return _xgetbv(reg); + } + #else + #define MA_NO_XGETBV + #endif + #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID) + static MA_INLINE void ma_cpuid(int info[4], int fid) + { + /* + It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the + specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for + supporting different assembly dialects. + + What's basically happening is that we're saving and restoring the ebx register manually. + */ + #if defined(MA_X86) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg{l} {%%}ebx, %k1;" + "cpuid;" + "xchg{l} {%%}ebx, %k1;" + : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #else + __asm__ __volatile__ ( + "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #endif + } + + static MA_INLINE ma_uint64 ma_xgetbv(int reg) + { + unsigned int hi; + unsigned int lo; + + __asm__ __volatile__ ( + "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg) + ); + + return ((ma_uint64)hi << 32) | (ma_uint64)lo; + } + #else + #define MA_NO_CPUID + #define MA_NO_XGETBV + #endif +#else + #define MA_NO_CPUID + #define MA_NO_XGETBV +#endif + +static MA_INLINE ma_bool32 ma_has_sse2(void) +{ +#if defined(MA_SUPPORT_SSE2) + #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2) + #if defined(MA_X64) + return MA_TRUE; /* 64-bit targets always support SSE2. */ + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) + return MA_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ + #else + #if defined(MA_NO_CPUID) + return MA_FALSE; + #else + int info[4]; + ma_cpuid(info, 1); + return (info[3] & (1 << 26)) != 0; + #endif + #endif + #else + return MA_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ + #endif +#else + return MA_FALSE; /* No compiler support. */ +#endif +} + +#if 0 +static MA_INLINE ma_bool32 ma_has_avx() +{ +#if defined(MA_SUPPORT_AVX) + #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX) + #if defined(_AVX_) || defined(__AVX__) + return MA_TRUE; /* If the compiler is allowed to freely generate AVX code we can assume support. */ + #else + /* AVX requires both CPU and OS support. */ + #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV) + return MA_FALSE; + #else + int info[4]; + ma_cpuid(info, 1); + if (((info[2] & (1 << 27)) != 0) && ((info[2] & (1 << 28)) != 0)) { + ma_uint64 xrc = ma_xgetbv(0); + if ((xrc & 0x06) == 0x06) { + return MA_TRUE; + } else { + return MA_FALSE; + } + } else { + return MA_FALSE; + } + #endif + #endif + #else + return MA_FALSE; /* AVX is only supported on x86 and x64 architectures. */ + #endif +#else + return MA_FALSE; /* No compiler support. */ +#endif +} +#endif + +static MA_INLINE ma_bool32 ma_has_avx2(void) +{ +#if defined(MA_SUPPORT_AVX2) + #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX2) + #if defined(_AVX2_) || defined(__AVX2__) + return MA_TRUE; /* If the compiler is allowed to freely generate AVX2 code we can assume support. */ + #else + /* AVX2 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 << 5)) != 0)) { + ma_uint64 xrc = ma_xgetbv(0); + if ((xrc & 0x06) == 0x06) { + return MA_TRUE; + } else { + return MA_FALSE; + } + } else { + return MA_FALSE; + } + #endif + #endif + #else + return MA_FALSE; /* AVX2 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) + #if defined(MA_ARM) && !defined(MA_NO_NEON) + #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + return MA_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */ + #else + /* TODO: Runtime check. */ + return MA_FALSE; + #endif + #else + return MA_FALSE; /* NEON is only supported on ARM architectures. */ + #endif +#else + return MA_FALSE; /* No compiler support. */ +#endif +} + +#if defined(__has_builtin) + #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x) +#else + #define MA_COMPILER_HAS_BUILTIN(x) 0 +#endif + +#ifndef MA_ASSUME + #if MA_COMPILER_HAS_BUILTIN(__builtin_assume) + #define MA_ASSUME(x) __builtin_assume(x) + #elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable) + #define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0) + #elif defined(_MSC_VER) + #define MA_ASSUME(x) __assume(x) + #else + #define MA_ASSUME(x) (void)(x) + #endif +#endif + +#ifndef MA_RESTRICT + #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + #define MA_RESTRICT __restrict + #else + #define MA_RESTRICT + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + #define MA_HAS_BYTESWAP16_INTRINSIC + #define MA_HAS_BYTESWAP32_INTRINSIC + #define MA_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16) + #define MA_HAS_BYTESWAP16_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32) + #define MA_HAS_BYTESWAP32_INTRINSIC + #endif + #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64) + #define MA_HAS_BYTESWAP64_INTRINSIC + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define MA_HAS_BYTESWAP32_INTRINSIC + #define MA_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define MA_HAS_BYTESWAP16_INTRINSIC + #endif +#endif + + +static MA_INLINE ma_bool32 ma_is_little_endian(void) +{ +#if defined(MA_X86) || defined(MA_X64) + return MA_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} + +static MA_INLINE ma_bool32 ma_is_big_endian(void) +{ + return !ma_is_little_endian(); +} + + +static MA_INLINE ma_uint32 ma_swap_endian_uint32(ma_uint32 n) +{ +#ifdef MA_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) /* <-- 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(). */ + ma_uint32 r; + __asm__ __volatile__ ( + #if defined(MA_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + + +#if !defined(MA_EMSCRIPTEN) +#ifdef MA_WIN32 +static void ma_sleep__win32(ma_uint32 milliseconds) +{ + Sleep((DWORD)milliseconds); +} +#endif +#ifdef MA_POSIX +static void ma_sleep__posix(ma_uint32 milliseconds) +{ +#ifdef MA_EMSCRIPTEN + (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) + struct timespec ts; + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = milliseconds % 1000 * 1000000; + nanosleep(&ts, NULL); + #else + struct timeval tv; + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = milliseconds % 1000 * 1000; + select(0, NULL, NULL, NULL, &tv); + #endif +#endif +} +#endif + +static MA_INLINE void ma_sleep(ma_uint32 milliseconds) +{ +#ifdef MA_WIN32 + ma_sleep__win32(milliseconds); +#endif +#ifdef MA_POSIX + ma_sleep__posix(milliseconds); +#endif +} +#endif + +static MA_INLINE void ma_yield(void) +{ +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + /* x86/x64 */ + #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(__clang__) + #if _MSC_VER >= 1400 + _mm_pause(); + #else + #if defined(__DMC__) + /* Digital Mars does not recognize the PAUSE opcode. Fall back to NOP. */ + __asm nop; + #else + __asm pause; + #endif + #endif + #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__) + /* 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. */ + __yield(); + #else + __asm__ __volatile__ ("yield"); /* ARMv6K/ARMv6T2 and above. */ + #endif +#else + /* Unknown or unsupported architecture. No-op. */ +#endif +} + + +#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 */ +#endif + + +#ifndef MA_FLT_MAX + #ifdef FLT_MAX + #define MA_FLT_MAX FLT_MAX + #else + #define MA_FLT_MAX 3.402823466e+38F + #endif +#endif + + +#ifndef MA_PI +#define MA_PI 3.14159265358979323846264f +#endif +#ifndef MA_PI_D +#define MA_PI_D 3.14159265358979323846264 +#endif +#ifndef MA_TAU +#define MA_TAU 6.28318530717958647693f +#endif +#ifndef MA_TAU_D +#define MA_TAU_D 6.28318530717958647693 +#endif + + +/* The default format when ma_format_unknown (0) is requested when initializing a device. */ +#ifndef MA_DEFAULT_FORMAT +#define MA_DEFAULT_FORMAT ma_format_f32 +#endif + +/* The default channel count to use when 0 is used when initializing a device. */ +#ifndef MA_DEFAULT_CHANNELS +#define MA_DEFAULT_CHANNELS 2 +#endif + +/* The default sample rate to use when 0 is used when initializing a device. */ +#ifndef MA_DEFAULT_SAMPLE_RATE +#define MA_DEFAULT_SAMPLE_RATE 48000 +#endif + +/* Default periods when none is specified in ma_device_init(). More periods means more work on the CPU. */ +#ifndef MA_DEFAULT_PERIODS +#define MA_DEFAULT_PERIODS 3 +#endif + +/* The default period size in milliseconds for low latency mode. */ +#ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY +#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY 10 +#endif + +/* The default buffer size in milliseconds for conservative mode. */ +#ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE +#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE 100 +#endif + +/* The default LPF filter order for linear resampling. Note that this is clamped to MA_MAX_FILTER_ORDER. */ +#ifndef MA_DEFAULT_RESAMPLER_LPF_ORDER + #if MA_MAX_FILTER_ORDER >= 4 + #define MA_DEFAULT_RESAMPLER_LPF_ORDER 4 + #else + #define MA_DEFAULT_RESAMPLER_LPF_ORDER MA_MAX_FILTER_ORDER + #endif +#endif + + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +/* Standard sample rates, in order of priority. */ +static ma_uint32 g_maStandardSampleRatePriorities[] = { + (ma_uint32)ma_standard_sample_rate_48000, + (ma_uint32)ma_standard_sample_rate_44100, + + (ma_uint32)ma_standard_sample_rate_32000, + (ma_uint32)ma_standard_sample_rate_24000, + (ma_uint32)ma_standard_sample_rate_22050, + + (ma_uint32)ma_standard_sample_rate_88200, + (ma_uint32)ma_standard_sample_rate_96000, + (ma_uint32)ma_standard_sample_rate_176400, + (ma_uint32)ma_standard_sample_rate_192000, + + (ma_uint32)ma_standard_sample_rate_16000, + (ma_uint32)ma_standard_sample_rate_11025, + (ma_uint32)ma_standard_sample_rate_8000, + + (ma_uint32)ma_standard_sample_rate_352800, + (ma_uint32)ma_standard_sample_rate_384000 +}; + +static MA_INLINE ma_bool32 ma_is_standard_sample_rate(ma_uint32 sampleRate) +{ + ma_uint32 iSampleRate; + + for (iSampleRate = 0; iSampleRate < sizeof(g_maStandardSampleRatePriorities) / sizeof(g_maStandardSampleRatePriorities[0]); iSampleRate += 1) { + if (g_maStandardSampleRatePriorities[iSampleRate] == sampleRate) { + return MA_TRUE; + } + } + + /* Getting here means the sample rate is not supported. */ + return MA_FALSE; +} + + +static ma_format g_maFormatPriorities[] = { + ma_format_s16, /* Most common */ + ma_format_f32, + + /*ma_format_s24_32,*/ /* Clean alignment */ + ma_format_s32, + + ma_format_s24, /* Unclean alignment */ + + ma_format_u8 /* Low quality */ +}; +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop +#endif + + +MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +{ + if (pMajor) { + *pMajor = MA_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = MA_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = MA_VERSION_REVISION; + } +} + +MA_API const char* ma_version_string(void) +{ + return MA_VERSION_STRING; +} + + +/****************************************************************************** + +Standard Library Stuff + +******************************************************************************/ +#ifndef MA_ASSERT +#define MA_ASSERT(condition) assert(condition) +#endif + +#ifndef MA_MALLOC +#define MA_MALLOC(sz) malloc((sz)) +#endif +#ifndef MA_REALLOC +#define MA_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef MA_FREE +#define MA_FREE(p) free((p)) +#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)) +#endif +#ifndef MA_COPY_MEMORY +#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))) + +#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_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels)) + +static MA_INLINE double ma_sind(double x) +{ + /* TODO: Implement custom sin(x). */ + return sin(x); +} + +static MA_INLINE double ma_expd(double x) +{ + /* TODO: Implement custom exp(x). */ + return exp(x); +} + +static MA_INLINE double ma_logd(double x) +{ + /* TODO: Implement custom log(x). */ + return log(x); +} + +static MA_INLINE double ma_powd(double x, double y) +{ + /* TODO: Implement custom pow(x, y). */ + return pow(x, y); +} + +static MA_INLINE double ma_sqrtd(double x) +{ + /* TODO: Implement custom sqrt(x). */ + return sqrt(x); +} + + +static MA_INLINE float ma_rsqrtf(float 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 +} + + +static MA_INLINE float ma_sinf(float 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; +} + +static MA_INLINE float ma_powf(float x, float y) +{ + return (float)ma_powd((double)x, (double)y); +} + +static MA_INLINE float ma_log10f(float x) +{ + return (float)ma_log10d((double)x); +} + + +static MA_INLINE double ma_degrees_to_radians(double degrees) +{ + return degrees * 0.01745329252; +} + +static MA_INLINE double ma_radians_to_degrees(double radians) +{ + return radians * 57.295779512896; +} + +static MA_INLINE float ma_degrees_to_radians_f(float degrees) +{ + return degrees * 0.01745329252f; +} + +static MA_INLINE float ma_radians_to_degrees_f(float radians) +{ + return radians * 57.295779512896f; +} + + +/* +Return Values: + 0: Success + 22: EINVAL + 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) +{ + size_t i; + + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) { + dst[i] = src[i]; + } + + if (i < dstSizeInBytes) { + dst[i] = '\0'; + return 0; + } + + dst[0] = '\0'; + return 34; +} + +MA_API MA_NO_INLINE int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* 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; +} + + +MA_API MA_NO_INLINE int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +{ + size_t maxcount; + size_t i; + + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + maxcount = count; + if (count == ((size_t)-1) || count >= dstSizeInBytes) { /* -1 = _TRUNCATE */ + maxcount = dstSizeInBytes - 1; + } + + for (i = 0; i < maxcount && src[i] != '\0'; ++i) { + dst[i] = src[i]; + } + + if (src[i] == '\0' || i == count || count == ((size_t)-1)) { + dst[i] = '\0'; + return 0; + } + + dst[0] = '\0'; + return 34; +} + +MA_API MA_NO_INLINE int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) +{ + char* dstorig; + + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + dst[0] = '\0'; + return 22; + } + + dstorig = dst; + + while (dstSizeInBytes > 0 && dst[0] != '\0') { + dst += 1; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + return 22; /* Unterminated. */ + } + + + while (dstSizeInBytes > 0 && src[0] != '\0') { + *dst++ = *src++; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes > 0) { + dst[0] = '\0'; + } else { + dstorig[0] = '\0'; + return 34; + } + + return 0; +} + +MA_API MA_NO_INLINE int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +{ + char* dstorig; + + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + return 22; + } + + dstorig = dst; + + while (dstSizeInBytes > 0 && dst[0] != '\0') { + dst += 1; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + return 22; /* Unterminated. */ + } + + + if (count == ((size_t)-1)) { /* _TRUNCATE */ + count = dstSizeInBytes - 1; + } + + while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) { + *dst++ = *src++; + dstSizeInBytes -= 1; + count -= 1; + } + + if (dstSizeInBytes > 0) { + dst[0] = '\0'; + } else { + dstorig[0] = '\0'; + return 34; + } + + return 0; +} + +MA_API MA_NO_INLINE int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) +{ + int sign; + unsigned int valueU; + char* dstEnd; + + if (dst == NULL || dstSizeInBytes == 0) { + return 22; + } + if (radix < 2 || radix > 36) { + dst[0] = '\0'; + return 22; + } + + sign = (value < 0 && radix == 10) ? -1 : 1; /* The negative sign is only used when the base is 10. */ + + if (value < 0) { + valueU = -value; + } else { + valueU = value; + } + + dstEnd = dst; + do + { + int remainder = valueU % radix; + if (remainder > 9) { + *dstEnd = (char)((remainder - 10) + 'a'); + } else { + *dstEnd = (char)(remainder + '0'); + } + + dstEnd += 1; + dstSizeInBytes -= 1; + valueU /= radix; + } while (dstSizeInBytes > 0 && valueU > 0); + + if (dstSizeInBytes == 0) { + dst[0] = '\0'; + return 22; /* Ran out of room in the output buffer. */ + } + + if (sign < 0) { + *dstEnd++ = '-'; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + dst[0] = '\0'; + return 22; /* Ran out of room in the output buffer. */ + } + + *dstEnd = '\0'; + + + /* At this point the string will be reversed. */ + dstEnd -= 1; + while (dst < dstEnd) { + char temp = *dst; + *dst = *dstEnd; + *dstEnd = temp; + + dst += 1; + dstEnd -= 1; + } + + return 0; +} + +MA_API MA_NO_INLINE int ma_strcmp(const char* str1, const char* str2) +{ + if (str1 == str2) return 0; + + /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */ + if (str1 == NULL) return -1; + if (str2 == NULL) return 1; + + for (;;) { + if (str1[0] == '\0') { + break; + } + if (str1[0] != str2[0]) { + break; + } + + str1 += 1; + str2 += 1; + } + + 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) +{ + int result; + + result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1); + if (result != 0) { + return result; + } + + result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1); + if (result != 0) { + return result; + } + + return result; +} + +MA_API MA_NO_INLINE 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); + if (dst == NULL) { + return NULL; + } + + ma_strcpy_s(dst, sz, src); + + return dst; +} + +MA_API MA_NO_INLINE 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); + if (dst == NULL) { + return NULL; + } + + ma_wcscpy_s(dst, sz, src); + + return dst; +} + + + +#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; + } +} + +MA_API ma_result ma_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; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_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) { + ma_result result = ma_result_from_errno(errno); + if (result == MA_SUCCESS) { + result = MA_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return MA_SUCCESS; +} + + + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define MA_HAS_WFOPEN + #endif +#endif + +MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return ma_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return ma_result_from_errno(errno); + } + #endif + (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. + */ + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + MA_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return ma_result_from_errno(errno); + } + + pFilePathMB = (char*)ma_malloc(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return MA_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + MA_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + + *ppFile = fopen(pFilePathMB, pOpenModeMB); + + ma_free(pFilePathMB, pAllocationCallbacks); + } + + if (*ppFile == NULL) { + return MA_ERROR; + } +#endif + + return MA_SUCCESS; +} + + + +static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes) +{ +#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX + MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes); +#else + while (sizeInBytes > 0) { + ma_uint64 bytesToCopyNow = sizeInBytes; + if (bytesToCopyNow > MA_SIZE_MAX) { + bytesToCopyNow = MA_SIZE_MAX; + } + + MA_COPY_MEMORY(dst, src, (size_t)bytesToCopyNow); /* Safe cast to size_t. */ + + sizeInBytes -= bytesToCopyNow; + dst = ( void*)(( ma_uint8*)dst + bytesToCopyNow); + src = (const void*)((const ma_uint8*)src + bytesToCopyNow); + } +#endif +} + +static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes) +{ +#if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX + MA_ZERO_MEMORY(dst, (size_t)sizeInBytes); +#else + while (sizeInBytes > 0) { + ma_uint64 bytesToZeroNow = sizeInBytes; + if (bytesToZeroNow > MA_SIZE_MAX) { + bytesToZeroNow = MA_SIZE_MAX; + } + + MA_ZERO_MEMORY(dst, (size_t)bytesToZeroNow); /* Safe cast to size_t. */ + + sizeInBytes -= bytesToZeroNow; + dst = (void*)((ma_uint8*)dst + bytesToZeroNow); + } +#endif +} + + +/* Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ +static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + + return x; +} + +static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x) +{ + return ma_next_power_of_2(x) >> 1; +} + +static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x) +{ + unsigned int prev = ma_prev_power_of_2(x); + unsigned int next = ma_next_power_of_2(x); + if ((next - x) > (x - prev)) { + return prev; + } else { + return next; + } +} + +static MA_INLINE unsigned int ma_count_set_bits(unsigned int x) +{ + unsigned int count = 0; + while (x != 0) { + if (x & 1) { + count += 1; + } + + x = x >> 1; + } + + return count; +} + + + +/************************************************************************************************************************************************************** + +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); +} + +static MA_INLINE float ma_clip_f32(float x) +{ + if (x < -1) return -1; + if (x > +1) return +1; + return x; +} + + +static MA_INLINE float ma_mix_f32(float x, float y, float a) +{ + return x*(1-a) + y*a; +} +static MA_INLINE float ma_mix_f32_fast(float x, float y, float a) +{ + float r0 = (y - x); + float r1 = r0*a; + return x + r1; + /*return x + (y - x)*a;*/ +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a) +{ + return _mm_add_ps(x, _mm_mul_ps(_mm_sub_ps(y, x), a)); +} +#endif +#if defined(MA_SUPPORT_AVX2) +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_NEON) +static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a) +{ + return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a)); +} +#endif + + +static MA_INLINE double ma_mix_f64(double x, double y, double a) +{ + return x*(1-a) + y*a; +} +static MA_INLINE double ma_mix_f64_fast(double x, double y, double a) +{ + return x + (y - x)*a; +} + +static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi) +{ + return lo + x*(hi-lo); +} + + +/* +Greatest common factor using Euclid's algorithm iteratively. +*/ +static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b) +{ + for (;;) { + if (b == 0) { + break; + } else { + ma_uint32 t = a; + a = b; + b = t % a; + } + } + + return a; +} + + +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 + +miniaudio uses the LCG random number generation algorithm. This is good enough for audio. + +Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across +multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for +miniaudio's purposes. +*/ +#ifndef MA_DEFAULT_LCG_SEED +#define MA_DEFAULT_LCG_SEED 4321 +#endif + +#define MA_LCG_M 2147483647 +#define MA_LCG_A 48271 +#define MA_LCG_C 0 + +static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */ + +static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed) +{ + MA_ASSERT(pLCG != NULL); + pLCG->state = seed; +} + +static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg* pLCG) +{ + pLCG->state = (MA_LCG_A * pLCG->state + MA_LCG_C) % MA_LCG_M; + return pLCG->state; +} + +static MA_INLINE ma_uint32 ma_lcg_rand_u32(ma_lcg* pLCG) +{ + return (ma_uint32)ma_lcg_rand_s32(pLCG); +} + +static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg* pLCG) +{ + return (ma_int16)(ma_lcg_rand_s32(pLCG) & 0xFFFF); +} + +static MA_INLINE double ma_lcg_rand_f64(ma_lcg* pLCG) +{ + return ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF; +} + +static MA_INLINE float ma_lcg_rand_f32(ma_lcg* pLCG) +{ + return (float)ma_lcg_rand_f64(pLCG); +} + +static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg* pLCG, float lo, float hi) +{ + return ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG), lo, hi); +} + +static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_int32 hi) +{ + if (lo == hi) { + return lo; + } + + return lo + ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi - lo + 1) + 1); +} + + + +static MA_INLINE void ma_seed(ma_int32 seed) +{ + ma_lcg_seed(&g_maLCG, seed); +} + +static MA_INLINE ma_int32 ma_rand_s32(void) +{ + return ma_lcg_rand_s32(&g_maLCG); +} + +static MA_INLINE ma_uint32 ma_rand_u32(void) +{ + return ma_lcg_rand_u32(&g_maLCG); +} + +static MA_INLINE double ma_rand_f64(void) +{ + return ma_lcg_rand_f64(&g_maLCG); +} + +static MA_INLINE float ma_rand_f32(void) +{ + return ma_lcg_rand_f32(&g_maLCG); +} + +static MA_INLINE float ma_rand_range_f32(float lo, float hi) +{ + return ma_lcg_rand_range_f32(&g_maLCG, lo, hi); +} + +static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo, ma_int32 hi) +{ + return ma_lcg_rand_range_s32(&g_maLCG, lo, hi); +} + + +static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax) +{ + return ma_rand_range_f32(ditherMin, ditherMax); +} + +static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax) +{ + float a = ma_rand_range_f32(ditherMin, 0); + float b = ma_rand_range_f32(0, ditherMax); + return a + b; +} + +static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax) +{ + if (ditherMode == ma_dither_mode_rectangle) { + return ma_dither_f32_rectangle(ditherMin, ditherMax); + } + if (ditherMode == ma_dither_mode_triangle) { + return ma_dither_f32_triangle(ditherMin, ditherMax); + } + + return 0; +} + +static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax) +{ + if (ditherMode == ma_dither_mode_rectangle) { + ma_int32 a = ma_rand_range_s32(ditherMin, ditherMax); + return a; + } + if (ditherMode == ma_dither_mode_triangle) { + ma_int32 a = ma_rand_range_s32(ditherMin, 0); + ma_int32 b = ma_rand_range_s32(0, ditherMax); + return a + b; + } + + return 0; +} + + +/************************************************************************************************************************************************************** + +Atomics + +**************************************************************************************************************************************************************/ +/* c89atomic.h begin */ +#ifndef ma_atomic_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" + #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 +#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 + #endif + #if _MSC_VER < 1600 + #undef MA_ATOMIC_HAS_8 + #undef MA_ATOMIC_HAS_16 + #endif + #if !defined(MA_ATOMIC_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) + { + ma_uint8 result = 0; + __asm { + mov ecx, dst + mov al, expected + mov dl, desired + lock cmpxchg [ecx], dl + mov result, al + } + 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) + { + ma_uint16 result = 0; + __asm { + mov ecx, dst + mov ax, expected + mov dx, desired + lock cmpxchg [ecx], dx + mov result, ax + } + 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) + { + ma_uint32 result = 0; + __asm { + mov ecx, dst + mov eax, expected + mov edx, desired + lock cmpxchg [ecx], edx + mov result, eax + } + 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) + { + ma_uint32 resultEAX = 0; + ma_uint32 resultEDX = 0; + __asm { + mov esi, dst + mov eax, dword ptr expected + mov edx, dword ptr expected + 4 + mov ebx, dword ptr desired + mov ecx, dword ptr desired + 4 + lock cmpxchg8b qword ptr [esi] + mov resultEAX, eax + mov resultEDX, edx + } + return ((ma_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) + #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) + #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) + #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) + #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) + { + ma_uint8 result = 0; + (void)order; + __asm { + mov ecx, dst + mov al, src + lock xchg [ecx], al + mov result, al + } + 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) + { + ma_uint16 result = 0; + (void)order; + __asm { + mov ecx, dst + mov ax, src + lock xchg [ecx], ax + mov result, ax + } + 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) + { + ma_uint32 result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, src + lock xchg [ecx], eax + mov result, eax + } + return result; + } + #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(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 + } + #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(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 + } + #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(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 + } + #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(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 + } + #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) + { + ma_uint64 oldValue; + do { + oldValue = *dst; + } while (ma_atomic_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) + { + ma_uint8 result = 0; + (void)order; + __asm { + mov ecx, dst + mov al, src + lock xadd [ecx], al + mov result, al + } + 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) + { + ma_uint16 result = 0; + (void)order; + __asm { + mov ecx, dst + mov ax, src + lock xadd [ecx], ax + mov result, ax + } + 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) + { + ma_uint32 result = 0; + (void)order; + __asm { + mov ecx, dst + mov eax, src + lock xadd [ecx], eax + mov result, eax + } + return result; + } + #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(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 + } + #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(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 + } + #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(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 + } + #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(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 + } + #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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue + src; + } while (ma_atomic_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) + { + (void)order; + __asm { + lock add [esp], 0 + } + } + #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 + #else + static MA_INLINE void ma_atomic_thread_fence(ma_atomic_memory_order order) + { + volatile ma_uint32 barrier = 0; + ma_atomic_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) + { + #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 + } + #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(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 + } + #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(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 + } + #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(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 + } + #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) + #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) + #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) + #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) + #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) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue - src); + } while (ma_atomic_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) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue - src); + } while (ma_atomic_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) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue & src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue & src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedAnd64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue ^ src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue ^ src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedXor64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr8, ma_uint8, char); + #else + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue | src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr16, ma_uint16, short); + #else + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue | src); + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr, ma_uint32, long); + #else + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_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(MA_ARM) + MA_ATOMIC_MSVC_ARM_INTRINSIC(dst, src, order, _InterlockedOr64, ma_uint64, long long); + #else + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_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) + #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) + #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) + #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) + #endif + #if defined(MA_ATOMIC_HAS_8) + #define ma_atomic_clear_explicit_8( dst, order) ma_atomic_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) + #endif + #if defined(MA_ATOMIC_HAS_32) + #define ma_atomic_clear_explicit_32(dst, order) ma_atomic_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) + #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) + #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) + #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) +#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") + #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) + { + if (order > ma_atomic_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) + { + ma_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) + { + ma_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) + { + ma_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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + { + (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) + #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") + #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) + { + ma_uint8 result; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint16 result; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint32 result; + #if defined(MA_X86) || defined(MA_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) + { + volatile ma_uint64 result; + #if defined(MA_X86) + ma_uint32 resultEAX; + ma_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) + __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) + { + ma_uint8 result = 0; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint16 result = 0; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint64 result; + (void)order; + #if defined(MA_X86) + do { + result = *dst; + } while (ma_atomic_compare_and_swap_64(dst, result, src) != result); + #elif defined(MA_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) + { + ma_uint8 result; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint16 result; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + ma_uint32 result; + (void)order; + #if defined(MA_X86) || defined(MA_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) + { + #if defined(MA_X86) + ma_uint64 oldValue; + ma_uint64 newValue; + (void)order; + do { + oldValue = *dst; + newValue = oldValue + src; + } while (ma_atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue); + return oldValue; + #elif defined(MA_X64) + ma_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) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue - src); + } while (ma_atomic_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) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue - src); + } while (ma_atomic_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) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue - src; + } while (ma_atomic_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) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue & src); + } while (ma_atomic_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) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue & src); + } while (ma_atomic_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) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue & src; + } while (ma_atomic_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) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue ^ src); + } while (ma_atomic_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) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue ^ src); + } while (ma_atomic_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) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue ^ src; + } while (ma_atomic_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) + { + ma_uint8 oldValue; + ma_uint8 newValue; + do { + oldValue = *dst; + newValue = (ma_uint8)(oldValue | src); + } while (ma_atomic_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) + { + ma_uint16 oldValue; + ma_uint16 newValue; + do { + oldValue = *dst; + newValue = (ma_uint16)(oldValue | src); + } while (ma_atomic_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) + { + ma_uint32 oldValue; + ma_uint32 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_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) + { + ma_uint64 oldValue; + ma_uint64 newValue; + do { + oldValue = *dst; + newValue = oldValue | src; + } while (ma_atomic_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) + { + (void)order; + return ma_atomic_compare_and_swap_8((ma_uint8*)ptr, 0, 0); + } + static MA_INLINE ma_uint16 ma_atomic_load_explicit_16(volatile const ma_uint16* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_16((ma_uint16*)ptr, 0, 0); + } + static MA_INLINE ma_uint32 ma_atomic_load_explicit_32(volatile const ma_uint32* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_32((ma_uint32*)ptr, 0, 0); + } + static MA_INLINE ma_uint64 ma_atomic_load_explicit_64(volatile const ma_uint64* ptr, ma_atomic_memory_order order) + { + (void)order; + return ma_atomic_compare_and_swap_64((ma_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) +#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) + { + ma_uint8 expectedValue; + ma_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); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_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) + { + ma_uint16 expectedValue; + ma_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); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_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) + { + ma_uint32 expectedValue; + ma_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); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_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) + { + ma_uint64 expectedValue; + ma_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); + if (result == expectedValue) { + return 1; + } else { + ma_atomic_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) +#endif +#if !defined(MA_ATOMIC_HAS_NATIVE_IS_LOCK_FREE) + static MA_INLINE ma_bool32 ma_atomic_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) + { + (void)ptr; + return 1; + } + static MA_INLINE ma_bool32 ma_atomic_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) + { + (void)ptr; + #if defined(MA_64BIT) + return 1; + #else + #if defined(MA_X86) || defined(MA_X64) + return 1; + #else + return 0; + #endif + #endif + } +#endif +#if defined(MA_64BIT) + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) + { + return ma_atomic_is_lock_free_64((volatile ma_uint64*)ptr); + } + static MA_INLINE void* ma_atomic_load_explicit_ptr(volatile void** ptr, ma_atomic_memory_order order) + { + return (void*)ma_atomic_load_explicit_64((volatile ma_uint64*)ptr, order); + } + static MA_INLINE void ma_atomic_store_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + { + ma_atomic_store_explicit_64((volatile ma_uint64*)dst, (ma_uint64)src, order); + } + static MA_INLINE void* ma_atomic_exchange_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + { + return (void*)ma_atomic_exchange_explicit_64((volatile ma_uint64*)dst, (ma_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) + { + return ma_atomic_compare_exchange_strong_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_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) + { + return ma_atomic_compare_exchange_weak_explicit_64((volatile ma_uint64*)dst, (ma_uint64*)expected, (ma_uint64)desired, successOrder, failureOrder); + } + static MA_INLINE void* ma_atomic_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); + } +#elif defined(MA_32BIT) + static MA_INLINE ma_bool32 ma_atomic_is_lock_free_ptr(volatile void** ptr) + { + return ma_atomic_is_lock_free_32((volatile ma_uint32*)ptr); + } + static MA_INLINE void* ma_atomic_load_explicit_ptr(volatile void** ptr, ma_atomic_memory_order order) + { + return (void*)ma_atomic_load_explicit_32((volatile ma_uint32*)ptr, order); + } + static MA_INLINE void ma_atomic_store_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + { + ma_atomic_store_explicit_32((volatile ma_uint32*)dst, (ma_uint32)src, order); + } + static MA_INLINE void* ma_atomic_exchange_explicit_ptr(volatile void** dst, void* src, ma_atomic_memory_order order) + { + return (void*)ma_atomic_exchange_explicit_32((volatile ma_uint32*)dst, (ma_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) + { + return ma_atomic_compare_exchange_strong_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_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) + { + return ma_atomic_compare_exchange_weak_explicit_32((volatile ma_uint32*)dst, (ma_uint32*)expected, (ma_uint32)desired, successOrder, failureOrder); + } + static MA_INLINE void* ma_atomic_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); + } +#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) +typedef union +{ + ma_uint32 i; + float f; +} ma_atomic_if32; +typedef union +{ + ma_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) +{ + ma_atomic_if32 x; + x.f = src; + ma_atomic_store_explicit_32((volatile ma_uint32*)dst, x.i, order); +} +static MA_INLINE void ma_atomic_store_explicit_f64(volatile double* dst, double src, ma_atomic_memory_order order) +{ + ma_atomic_if64 x; + x.f = src; + ma_atomic_store_explicit_64((volatile ma_uint64*)dst, x.i, order); +} +static MA_INLINE float ma_atomic_load_explicit_f32(volatile const float* ptr, ma_atomic_memory_order order) +{ + ma_atomic_if32 r; + r.i = ma_atomic_load_explicit_32((volatile const ma_uint32*)ptr, order); + return r.f; +} +static MA_INLINE double ma_atomic_load_explicit_f64(volatile const double* ptr, ma_atomic_memory_order order) +{ + ma_atomic_if64 r; + r.i = ma_atomic_load_explicit_64((volatile const ma_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) +{ + ma_atomic_if32 r; + ma_atomic_if32 x; + x.f = src; + r.i = ma_atomic_exchange_explicit_32((volatile ma_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) +{ + ma_atomic_if64 r; + ma_atomic_if64 x; + x.f = src; + r.i = ma_atomic_exchange_explicit_64((volatile ma_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) +{ + for (;;) { + if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { + break; + } + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + } + } +} +static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSpinlock) +{ + ma_atomic_flag_clear_explicit(pSpinlock, ma_atomic_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) + +#if !defined(MA_NO_DEVICE_IO) +MA_ATOMIC_SAFE_TYPE_IMPL(i32, device_state) +#endif + + +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; + } + + if (sampleRateOut == sampleRateIn) { + return frameCountIn; + } + + outputFrameCount = (frameCountIn * sampleRateOut) / sampleRateIn; + + preliminaryInputFrameCountFromFrac = (outputFrameCount * (sampleRateIn / sampleRateOut)) / sampleRateOut; + preliminaryInputFrameCount = (outputFrameCount * (sampleRateIn % sampleRateOut)) + preliminaryInputFrameCountFromFrac; + + if (preliminaryInputFrameCount <= frameCountIn) { + outputFrameCount += 1; + } + + return outputFrameCount; +} + +#ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE +#define MA_DATA_CONVERTER_STACK_BUFFER_SIZE 4096 +#endif + + + +#if defined(MA_WIN32) +static ma_result ma_result_from_GetLastError(DWORD error) +{ + switch (error) + { + case ERROR_SUCCESS: return MA_SUCCESS; + case ERROR_PATH_NOT_FOUND: return MA_DOES_NOT_EXIST; + 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_NEGATIVE_SEEK: return MA_BAD_SEEK; + case ERROR_INVALID_PARAMETER: return MA_INVALID_ARGS; + case ERROR_ACCESS_DENIED: return MA_ACCESS_DENIED; + case ERROR_SEM_TIMEOUT: return MA_TIMEOUT; + case ERROR_FILE_NOT_FOUND: return MA_DOES_NOT_EXIST; + default: break; + } + + return MA_ERROR; +} +#endif /* MA_WIN32 */ + + +/******************************************************************************* + +Threading + +*******************************************************************************/ +static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, ma_bool32 yield) +{ + if (pSpinlock == NULL) { + return MA_INVALID_ARGS; + } + + for (;;) { + if (ma_atomic_exchange_explicit_32(pSpinlock, 1, ma_atomic_memory_order_acquire) == 0) { + break; + } + + while (ma_atomic_load_explicit_32(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + if (yield) { + ma_yield(); + } + } + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock) +{ + return ma_spinlock_lock_ex(pSpinlock, MA_TRUE); +} + +MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock) +{ + return ma_spinlock_lock_ex(pSpinlock, MA_FALSE); +} + +MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock) +{ + if (pSpinlock == NULL) { + return MA_INVALID_ARGS; + } + + ma_atomic_store_explicit_32(pSpinlock, 0, ma_atomic_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) +static int ma_thread_priority_to_win32(ma_thread_priority priority) +{ + switch (priority) { + case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE; + case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST; + case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL; + case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL; + case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL; + case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST; + case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL; + default: return THREAD_PRIORITY_NORMAL; + } +} + +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); + if (*pThread == NULL) { + return ma_result_from_GetLastError(GetLastError()); + } + + SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority)); + + return MA_SUCCESS; +} + +static void ma_thread_wait__win32(ma_thread* pThread) +{ + WaitForSingleObject((HANDLE)*pThread, INFINITE); + CloseHandle((HANDLE)*pThread); +} + + +static ma_result ma_mutex_init__win32(ma_mutex* pMutex) +{ + *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); + if (*pMutex == NULL) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + +static void ma_mutex_uninit__win32(ma_mutex* pMutex) +{ + CloseHandle((HANDLE)*pMutex); +} + +static void ma_mutex_lock__win32(ma_mutex* pMutex) +{ + WaitForSingleObject((HANDLE)*pMutex, INFINITE); +} + +static void ma_mutex_unlock__win32(ma_mutex* pMutex) +{ + SetEvent((HANDLE)*pMutex); +} + + +static ma_result ma_event_init__win32(ma_event* pEvent) +{ + *pEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (*pEvent == NULL) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + +static void ma_event_uninit__win32(ma_event* pEvent) +{ + CloseHandle((HANDLE)*pEvent); +} + +static ma_result ma_event_wait__win32(ma_event* pEvent) +{ + DWORD result = WaitForSingleObject((HANDLE)*pEvent, INFINITE); + if (result == WAIT_OBJECT_0) { + return MA_SUCCESS; + } + + if (result == WAIT_TIMEOUT) { + return MA_TIMEOUT; + } + + return ma_result_from_GetLastError(GetLastError()); +} + +static ma_result ma_event_signal__win32(ma_event* pEvent) +{ + BOOL result = SetEvent((HANDLE)*pEvent); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + + +static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore) +{ + *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL); + if (*pSemaphore == NULL) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + +static void ma_semaphore_uninit__win32(ma_semaphore* pSemaphore) +{ + CloseHandle((HANDLE)*pSemaphore); +} + +static ma_result ma_semaphore_wait__win32(ma_semaphore* pSemaphore) +{ + DWORD result = WaitForSingleObject((HANDLE)*pSemaphore, INFINITE); + if (result == WAIT_OBJECT_0) { + return MA_SUCCESS; + } + + if (result == WAIT_TIMEOUT) { + return MA_TIMEOUT; + } + + return ma_result_from_GetLastError(GetLastError()); +} + +static ma_result ma_semaphore_release__win32(ma_semaphore* pSemaphore) +{ + BOOL result = ReleaseSemaphore((HANDLE)*pSemaphore, 1, NULL); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} +#endif + +typedef struct +{ + ma_thread_entry_proc entryProc; + void* pData; + ma_allocation_callbacks allocationCallbacks; +} ma_thread_proxy_data; + +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(MA_ON_THREAD_ENTRY) + MA_ON_THREAD_ENTRY + #endif + + entryProc = pProxyData->entryProc; + pEntryProcData = pProxyData->pData; + + /* Free the proxy data before getting into the real thread entry proc. */ + ma_free(pProxyData, &pProxyData->allocationCallbacks); + + 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; + } +#endif + + pProxyData->entryProc = entryProc; + pProxyData->pData = pData; + ma_allocation_callbacks_init_copy(&pProxyData->allocationCallbacks, pAllocationCallbacks); + +#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 + + if (result != MA_SUCCESS) { + ma_free(pProxyData, pAllocationCallbacks); + return result; + } + + return MA_SUCCESS; +} + +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) + ma_thread_wait__win32(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. */ + return MA_INVALID_ARGS; + } + +#if defined(MA_POSIX) + return ma_mutex_init__posix(pMutex); +#elif defined(MA_WIN32) + return ma_mutex_init__win32(pMutex); +#endif +} + +MA_API void ma_mutex_uninit(ma_mutex* pMutex) +{ + if (pMutex == NULL) { + return; + } + +#if defined(MA_POSIX) + ma_mutex_uninit__posix(pMutex); +#elif defined(MA_WIN32) + ma_mutex_uninit__win32(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. */ + return; + } + +#if defined(MA_POSIX) + ma_mutex_lock__posix(pMutex); +#elif defined(MA_WIN32) + ma_mutex_lock__win32(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. */ + return; + } + +#if defined(MA_POSIX) + ma_mutex_unlock__posix(pMutex); +#elif defined(MA_WIN32) + ma_mutex_unlock__win32(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. */ + return MA_INVALID_ARGS; + } + +#if defined(MA_POSIX) + return ma_event_init__posix(pEvent); +#elif defined(MA_WIN32) + return ma_event_init__win32(pEvent); +#endif +} + +#if 0 +static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_result result; + ma_event* pEvent; + + if (ppEvent == NULL) { + return MA_INVALID_ARGS; + } + + *ppEvent = NULL; + + pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks); + if (pEvent == NULL) { + return MA_OUT_OF_MEMORY; + } + + result = ma_event_init(pEvent); + if (result != MA_SUCCESS) { + ma_free(pEvent, pAllocationCallbacks); + return result; + } + + *ppEvent = pEvent; + return result; +} +#endif + +MA_API void ma_event_uninit(ma_event* pEvent) +{ + if (pEvent == NULL) { + return; + } + +#if defined(MA_POSIX) + ma_event_uninit__posix(pEvent); +#elif defined(MA_WIN32) + ma_event_uninit__win32(pEvent); +#endif +} + +#if 0 +static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pEvent == NULL) { + return; + } + + ma_event_uninit(pEvent); + ma_free(pEvent, pAllocationCallbacks); +} +#endif + +MA_API ma_result ma_event_wait(ma_event* pEvent) +{ + if (pEvent == NULL) { + 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_wait__posix(pEvent); +#elif defined(MA_WIN32) + return ma_event_wait__win32(pEvent); +#endif +} + +MA_API ma_result ma_event_signal(ma_event* pEvent) +{ + if (pEvent == NULL) { + 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_signal__posix(pEvent); +#elif defined(MA_WIN32) + return ma_event_signal__win32(pEvent); +#endif +} + + +MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + return MA_INVALID_ARGS; + } + +#if defined(MA_POSIX) + return ma_semaphore_init__posix(initialValue, pSemaphore); +#elif defined(MA_WIN32) + return ma_semaphore_init__win32(initialValue, pSemaphore); +#endif +} + +MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + return; + } + +#if defined(MA_POSIX) + ma_semaphore_uninit__posix(pSemaphore); +#elif defined(MA_WIN32) + ma_semaphore_uninit__win32(pSemaphore); +#endif +} + +MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + return MA_INVALID_ARGS; + } + +#if defined(MA_POSIX) + return ma_semaphore_wait__posix(pSemaphore); +#elif defined(MA_WIN32) + return ma_semaphore_wait__win32(pSemaphore); +#endif +} + +MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore) +{ + if (pSemaphore == NULL) { + MA_ASSERT(MA_FALSE); /* Fire an assert so the caller is aware of this bug. */ + return MA_INVALID_ARGS; + } + +#if defined(MA_POSIX) + return ma_semaphore_release__posix(pSemaphore); +#elif defined(MA_WIN32) + return ma_semaphore_release__win32(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. */ +#ifndef MA_NO_DEVICE_IO +#error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO"; +#endif +#endif /* MA_NO_THREADING */ + + + +#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 +} + + + +/************************************************************************************************************************************************************ +************************************************************************************************************************************************************* + +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 + +#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 +#endif + +/* This must be set to at least 26. */ +#ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION +#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 27 +#endif + + +MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags) +{ + if (pDeviceInfo == NULL) { + return; + } + + if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats)) { + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = flags; + pDeviceInfo->nativeDataFormatCount += 1; + } +} + + +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"; + } + + 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) +{ + /* + This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers + about some enums not being handled by the switch statement. + */ + switch (backend) + { + case ma_backend_wasapi: + #if defined(MA_HAS_WASAPI) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_dsound: + #if defined(MA_HAS_DSOUND) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_winmm: + #if defined(MA_HAS_WINMM) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_coreaudio: + #if defined(MA_HAS_COREAUDIO) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_sndio: + #if defined(MA_HAS_SNDIO) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_audio4: + #if defined(MA_HAS_AUDIO4) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_oss: + #if defined(MA_HAS_OSS) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_pulseaudio: + #if defined(MA_HAS_PULSEAUDIO) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_alsa: + #if defined(MA_HAS_ALSA) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_jack: + #if defined(MA_HAS_JACK) + return MA_TRUE; + #else + return MA_FALSE; + #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 + #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 + #else + return MA_FALSE; + #endif + case ma_backend_webaudio: + #if defined(MA_HAS_WEBAUDIO) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_custom: + #if defined(MA_HAS_CUSTOM) + return MA_TRUE; + #else + return MA_FALSE; + #endif + case ma_backend_null: + #if defined(MA_HAS_NULL) + return MA_TRUE; + #else + return MA_FALSE; + #endif + + default: return MA_FALSE; + } +} + +MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount) +{ + size_t backendCount; + size_t iBackend; + ma_result result = MA_SUCCESS; + + if (pBackendCount == NULL) { + return MA_INVALID_ARGS; + } + + backendCount = 0; + + for (iBackend = 0; iBackend <= ma_backend_null; iBackend += 1) { + ma_backend backend = (ma_backend)iBackend; + + if (ma_is_backend_enabled(backend)) { + /* The backend is enabled. Try adding it to the list. If there's no room, MA_NO_SPACE needs to be returned. */ + if (backendCount == backendCap) { + result = MA_NO_SPACE; + break; + } else { + pBackends[backendCount] = backend; + backendCount += 1; + } + } + } + + if (pBackendCount != NULL) { + *pBackendCount = backendCount; + } + + return result; +} + +MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend) +{ + switch (backend) + { + case ma_backend_wasapi: return MA_TRUE; + case ma_backend_dsound: return MA_FALSE; + case ma_backend_winmm: return MA_FALSE; + case ma_backend_coreaudio: return MA_FALSE; + case ma_backend_sndio: return MA_FALSE; + case ma_backend_audio4: return MA_FALSE; + case ma_backend_oss: return MA_FALSE; + case ma_backend_pulseaudio: return MA_FALSE; + case ma_backend_alsa: return MA_FALSE; + case ma_backend_jack: return MA_FALSE; + case ma_backend_aaudio: return MA_FALSE; + case ma_backend_opensl: return MA_FALSE; + case ma_backend_webaudio: return MA_FALSE; + case ma_backend_custom: return MA_FALSE; /* <-- Will depend on the implementation of the backend. */ + case ma_backend_null: return MA_FALSE; + default: return MA_FALSE; + } +} + + + +#if defined(MA_WIN32) +/* WASAPI error codes. */ +#define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001) +#define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002) +#define MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE ((HRESULT)0x88890003) +#define MA_AUDCLNT_E_DEVICE_INVALIDATED ((HRESULT)0x88890004) +#define MA_AUDCLNT_E_NOT_STOPPED ((HRESULT)0x88890005) +#define MA_AUDCLNT_E_BUFFER_TOO_LARGE ((HRESULT)0x88890006) +#define MA_AUDCLNT_E_OUT_OF_ORDER ((HRESULT)0x88890007) +#define MA_AUDCLNT_E_UNSUPPORTED_FORMAT ((HRESULT)0x88890008) +#define MA_AUDCLNT_E_INVALID_SIZE ((HRESULT)0x88890009) +#define MA_AUDCLNT_E_DEVICE_IN_USE ((HRESULT)0x8889000A) +#define MA_AUDCLNT_E_BUFFER_OPERATION_PENDING ((HRESULT)0x8889000B) +#define MA_AUDCLNT_E_THREAD_NOT_REGISTERED ((HRESULT)0x8889000C) +#define MA_AUDCLNT_E_NO_SINGLE_PROCESS ((HRESULT)0x8889000D) +#define MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED ((HRESULT)0x8889000E) +#define MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED ((HRESULT)0x8889000F) +#define MA_AUDCLNT_E_SERVICE_NOT_RUNNING ((HRESULT)0x88890010) +#define MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED ((HRESULT)0x88890011) +#define MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY ((HRESULT)0x88890012) +#define MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL ((HRESULT)0x88890013) +#define MA_AUDCLNT_E_EVENTHANDLE_NOT_SET ((HRESULT)0x88890014) +#define MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE ((HRESULT)0x88890015) +#define MA_AUDCLNT_E_BUFFER_SIZE_ERROR ((HRESULT)0x88890016) +#define MA_AUDCLNT_E_CPUUSAGE_EXCEEDED ((HRESULT)0x88890017) +#define MA_AUDCLNT_E_BUFFER_ERROR ((HRESULT)0x88890018) +#define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED ((HRESULT)0x88890019) +#define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD ((HRESULT)0x88890020) +#define MA_AUDCLNT_E_INVALID_STREAM_FLAG ((HRESULT)0x88890021) +#define MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE ((HRESULT)0x88890022) +#define MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES ((HRESULT)0x88890023) +#define MA_AUDCLNT_E_OFFLOAD_MODE_ONLY ((HRESULT)0x88890024) +#define MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY ((HRESULT)0x88890025) +#define MA_AUDCLNT_E_RESOURCES_INVALIDATED ((HRESULT)0x88890026) +#define MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED ((HRESULT)0x88890027) +#define MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED ((HRESULT)0x88890028) +#define MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED ((HRESULT)0x88890029) +#define MA_AUDCLNT_E_HEADTRACKING_ENABLED ((HRESULT)0x88890030) +#define MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED ((HRESULT)0x88890040) +#define MA_AUDCLNT_S_BUFFER_EMPTY ((HRESULT)0x08890001) +#define MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED ((HRESULT)0x08890002) +#define MA_AUDCLNT_S_POSITION_STALLED ((HRESULT)0x08890003) + +#define MA_DS_OK ((HRESULT)0) +#define MA_DS_NO_VIRTUALIZATION ((HRESULT)0x0878000A) +#define MA_DSERR_ALLOCATED ((HRESULT)0x8878000A) +#define MA_DSERR_CONTROLUNAVAIL ((HRESULT)0x8878001E) +#define MA_DSERR_INVALIDPARAM ((HRESULT)0x80070057) /*E_INVALIDARG*/ +#define MA_DSERR_INVALIDCALL ((HRESULT)0x88780032) +#define MA_DSERR_GENERIC ((HRESULT)0x80004005) /*E_FAIL*/ +#define MA_DSERR_PRIOLEVELNEEDED ((HRESULT)0x88780046) +#define MA_DSERR_OUTOFMEMORY ((HRESULT)0x8007000E) /*E_OUTOFMEMORY*/ +#define MA_DSERR_BADFORMAT ((HRESULT)0x88780064) +#define MA_DSERR_UNSUPPORTED ((HRESULT)0x80004001) /*E_NOTIMPL*/ +#define MA_DSERR_NODRIVER ((HRESULT)0x88780078) +#define MA_DSERR_ALREADYINITIALIZED ((HRESULT)0x88780082) +#define MA_DSERR_NOAGGREGATION ((HRESULT)0x80040110) /*CLASS_E_NOAGGREGATION*/ +#define MA_DSERR_BUFFERLOST ((HRESULT)0x88780096) +#define MA_DSERR_OTHERAPPHASPRIO ((HRESULT)0x887800A0) +#define MA_DSERR_UNINITIALIZED ((HRESULT)0x887800AA) +#define MA_DSERR_NOINTERFACE ((HRESULT)0x80004002) /*E_NOINTERFACE*/ +#define MA_DSERR_ACCESSDENIED ((HRESULT)0x80070005) /*E_ACCESSDENIED*/ +#define MA_DSERR_BUFFERTOOSMALL ((HRESULT)0x887800B4) +#define MA_DSERR_DS8_REQUIRED ((HRESULT)0x887800BE) +#define MA_DSERR_SENDLOOP ((HRESULT)0x887800C8) +#define MA_DSERR_BADSENDBUFFERGUID ((HRESULT)0x887800D2) +#define MA_DSERR_OBJECTNOTFOUND ((HRESULT)0x88781161) +#define MA_DSERR_FXUNAVAILABLE ((HRESULT)0x887800DC) + +static ma_result ma_result_from_HRESULT(HRESULT hr) +{ + switch (hr) + { + case NOERROR: return MA_SUCCESS; + /*case S_OK: return MA_SUCCESS;*/ + + case E_POINTER: return MA_INVALID_ARGS; + case E_UNEXPECTED: return MA_ERROR; + case E_NOTIMPL: return MA_NOT_IMPLEMENTED; + case E_OUTOFMEMORY: return MA_OUT_OF_MEMORY; + case E_INVALIDARG: return MA_INVALID_ARGS; + case E_NOINTERFACE: return MA_API_NOT_FOUND; + case E_HANDLE: return MA_INVALID_ARGS; + case E_ABORT: return MA_ERROR; + case E_FAIL: return MA_ERROR; + case E_ACCESSDENIED: return MA_ACCESS_DENIED; + + /* WASAPI */ + case MA_AUDCLNT_E_NOT_INITIALIZED: return MA_DEVICE_NOT_INITIALIZED; + case MA_AUDCLNT_E_ALREADY_INITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED; + case MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_DEVICE_INVALIDATED: return MA_UNAVAILABLE; + case MA_AUDCLNT_E_NOT_STOPPED: return MA_DEVICE_NOT_STOPPED; + case MA_AUDCLNT_E_BUFFER_TOO_LARGE: return MA_TOO_BIG; + case MA_AUDCLNT_E_OUT_OF_ORDER: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_UNSUPPORTED_FORMAT: return MA_FORMAT_NOT_SUPPORTED; + case MA_AUDCLNT_E_INVALID_SIZE: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_DEVICE_IN_USE: return MA_BUSY; + case MA_AUDCLNT_E_BUFFER_OPERATION_PENDING: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_THREAD_NOT_REGISTERED: return MA_DOES_NOT_EXIST; + case MA_AUDCLNT_E_NO_SINGLE_PROCESS: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: return MA_SHARE_MODE_NOT_SUPPORTED; + case MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED: return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + case MA_AUDCLNT_E_SERVICE_NOT_RUNNING: return MA_NOT_CONNECTED; + case MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY: return MA_SHARE_MODE_NOT_SUPPORTED; + case MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_EVENTHANDLE_NOT_SET: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_BUFFER_SIZE_ERROR: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_CPUUSAGE_EXCEEDED: return MA_ERROR; + case MA_AUDCLNT_E_BUFFER_ERROR: return MA_ERROR; + case MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_INVALID_DEVICE_PERIOD: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_INVALID_STREAM_FLAG: return MA_INVALID_ARGS; + case MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES: return MA_OUT_OF_MEMORY; + case MA_AUDCLNT_E_OFFLOAD_MODE_ONLY: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_RESOURCES_INVALIDATED: return MA_INVALID_DATA; + case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_HEADTRACKING_ENABLED: return MA_INVALID_OPERATION; + case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED: return MA_INVALID_OPERATION; + case MA_AUDCLNT_S_BUFFER_EMPTY: return MA_NO_SPACE; + case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED: return MA_ALREADY_EXISTS; + case MA_AUDCLNT_S_POSITION_STALLED: return MA_ERROR; + + /* DirectSound */ + /*case MA_DS_OK: return MA_SUCCESS;*/ /* S_OK */ + case MA_DS_NO_VIRTUALIZATION: return MA_SUCCESS; + case MA_DSERR_ALLOCATED: return MA_ALREADY_IN_USE; + case MA_DSERR_CONTROLUNAVAIL: return MA_INVALID_OPERATION; + /*case MA_DSERR_INVALIDPARAM: return MA_INVALID_ARGS;*/ /* E_INVALIDARG */ + case MA_DSERR_INVALIDCALL: return MA_INVALID_OPERATION; + /*case MA_DSERR_GENERIC: return MA_ERROR;*/ /* E_FAIL */ + case MA_DSERR_PRIOLEVELNEEDED: return MA_INVALID_OPERATION; + /*case MA_DSERR_OUTOFMEMORY: return MA_OUT_OF_MEMORY;*/ /* E_OUTOFMEMORY */ + case MA_DSERR_BADFORMAT: return MA_FORMAT_NOT_SUPPORTED; + /*case MA_DSERR_UNSUPPORTED: return MA_NOT_IMPLEMENTED;*/ /* E_NOTIMPL */ + case MA_DSERR_NODRIVER: return MA_FAILED_TO_INIT_BACKEND; + case MA_DSERR_ALREADYINITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED; + case MA_DSERR_NOAGGREGATION: return MA_ERROR; + case MA_DSERR_BUFFERLOST: return MA_UNAVAILABLE; + case MA_DSERR_OTHERAPPHASPRIO: return MA_ACCESS_DENIED; + case MA_DSERR_UNINITIALIZED: return MA_DEVICE_NOT_INITIALIZED; + /*case MA_DSERR_NOINTERFACE: return MA_API_NOT_FOUND;*/ /* E_NOINTERFACE */ + /*case MA_DSERR_ACCESSDENIED: return MA_ACCESS_DENIED;*/ /* E_ACCESSDENIED */ + case MA_DSERR_BUFFERTOOSMALL: return MA_NO_SPACE; + case MA_DSERR_DS8_REQUIRED: return MA_INVALID_OPERATION; + case MA_DSERR_SENDLOOP: return MA_DEADLOCK; + case MA_DSERR_BADSENDBUFFERGUID: return MA_INVALID_ARGS; + case MA_DSERR_OBJECTNOTFOUND: return MA_NO_DEVICE; + case MA_DSERR_FXUNAVAILABLE: return MA_UNAVAILABLE; + + default: return MA_ERROR; + } +} + +/* 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 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 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 */ + + +#define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device" +#define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device" + + + + +/******************************************************************************* + +Timing + +*******************************************************************************/ +#if defined(MA_WIN32) && !defined(MA_POSIX) + static LARGE_INTEGER g_ma_TimerFrequency; /* <-- Initialized to zero since it's static. */ + static void ma_timer_init(ma_timer* pTimer) + { + LARGE_INTEGER counter; + + if (g_ma_TimerFrequency.QuadPart == 0) { + QueryPerformanceFrequency(&g_ma_TimerFrequency); + } + + QueryPerformanceCounter(&counter); + pTimer->counter = counter.QuadPart; + } + + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + { + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) { + return 0; + } + + return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart; + } +#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) + { + mach_timebase_info_data_t baseTime; + mach_timebase_info(&baseTime); + g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer; + + pTimer->counter = mach_absolute_time(); + } + + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + { + ma_uint64 newTimeCounter = mach_absolute_time(); + ma_uint64 oldTimeCounter = pTimer->counter; + + return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency; + } +#elif defined(MA_EMSCRIPTEN) + static MA_INLINE void ma_timer_init(ma_timer* pTimer) + { + pTimer->counterD = emscripten_get_now(); + } + + static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer) + { + return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */ + } +#else + #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L + #if defined(CLOCK_MONOTONIC) + #define MA_CLOCK_ID CLOCK_MONOTONIC + #else + #define MA_CLOCK_ID CLOCK_REALTIME + #endif + + static void ma_timer_init(ma_timer* pTimer) + { + struct timespec newTime; + clock_gettime(MA_CLOCK_ID, &newTime); + + pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; + } + + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + { + ma_uint64 newTimeCounter; + ma_uint64 oldTimeCounter; + + struct timespec newTime; + clock_gettime(MA_CLOCK_ID, &newTime); + + newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec; + oldTimeCounter = pTimer->counter; + + return (newTimeCounter - oldTimeCounter) / 1000000000.0; + } + #else + static void ma_timer_init(ma_timer* pTimer) + { + struct timeval newTime; + gettimeofday(&newTime, NULL); + + pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec; + } + + static double ma_timer_get_time_in_seconds(ma_timer* pTimer) + { + ma_uint64 newTimeCounter; + ma_uint64 oldTimeCounter; + + struct timeval newTime; + gettimeofday(&newTime, NULL); + + newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec; + oldTimeCounter = pTimer->counter; + + return (newTimeCounter - oldTimeCounter) / 1000000.0; + } + #endif +#endif + + + +#if 0 +static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn) +{ + ma_uint32 closestRate = 0; + ma_uint32 closestDiff = 0xFFFFFFFF; + size_t iStandardRate; + + for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) { + ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate]; + ma_uint32 diff; + + if (sampleRateIn > standardRate) { + diff = sampleRateIn - standardRate; + } else { + diff = standardRate - sampleRateIn; + } + + if (diff == 0) { + return standardRate; /* The input sample rate is a standard rate. */ + } + + if (closestDiff > diff) { + closestDiff = diff; + closestRate = standardRate; + } + } + + return closestRate; +} +#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) { + ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); + } + } +} + + + +/* A helper function for reading sample data from the client. */ +static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pFramesOut) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(frameCount > 0); + MA_ASSERT(pFramesOut != NULL); + + if (pDevice->playback.converter.isPassthrough) { + ma_device__handle_data_callback(pDevice, pFramesOut, NULL, frameCount); + } else { + ma_result result; + ma_uint64 totalFramesReadOut; + void* pRunningFramesOut; + + totalFramesReadOut = 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; + + /* 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; + } + } + } 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; + } + + ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut, &requiredInputFrameCount); + if (framesToReadThisIterationIn > requiredInputFrameCount) { + framesToReadThisIterationIn = requiredInputFrameCount; + } + + 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; + } + + 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. */ + } + } + } + } +} + +/* A helper for sending sample data to the client. */ +static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(frameCountInDeviceFormat > 0); + MA_ASSERT(pFramesInDeviceFormat != NULL); + + if (pDevice->capture.converter.isPassthrough) { + ma_device__handle_data_callback(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat); + } else { + ma_result result; + ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint64 framesInClientFormatCap = sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint64 totalDeviceFramesProcessed = 0; + 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. */ + for (;;) { + ma_uint64 deviceFramesProcessedThisIteration; + ma_uint64 clientFramesProcessedThisIteration; + + deviceFramesProcessedThisIteration = (frameCountInDeviceFormat - totalDeviceFramesProcessed); + clientFramesProcessedThisIteration = framesInClientFormatCap; + + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &deviceFramesProcessedThisIteration, pFramesInClientFormat, &clientFramesProcessedThisIteration); + if (result != MA_SUCCESS) { + break; + } + + if (clientFramesProcessedThisIteration > 0) { + ma_device__handle_data_callback(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. */ + } + } + } +} + +static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB) +{ + ma_result result; + ma_uint32 totalDeviceFramesProcessed = 0; + const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(frameCountInDeviceFormat > 0); + MA_ASSERT(pFramesInDeviceFormat != NULL); + MA_ASSERT(pRB != NULL); + + /* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */ + for (;;) { + ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed); + ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint64 framesProcessedInDeviceFormat; + ma_uint64 framesProcessedInClientFormat; + void* pFramesInClientFormat; + + 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."); + break; + } + + if (framesToProcessInClientFormat == 0) { + if (ma_pcm_rb_pointer_distance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) { + break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */ + } + } + + /* Convert. */ + framesProcessedInDeviceFormat = framesToProcessInDeviceFormat; + framesProcessedInClientFormat = framesToProcessInClientFormat; + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &framesProcessedInDeviceFormat, pFramesInClientFormat, &framesProcessedInClientFormat); + if (result != MA_SUCCESS) { + break; + } + + result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat); /* 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."); + break; + } + + pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); + totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */ + + /* We're done when we're unable to process any client nor device frames. */ + if (framesProcessedInClientFormat == 0 && framesProcessedInDeviceFormat == 0) { + break; /* Done. */ + } + } + + return MA_SUCCESS; +} + +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 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + 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 + the whole frameCount frames we just use silence instead for the input data. + */ + 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); + + 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)); + } + + /* 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. */ + } + } + } 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); + } + + pDevice->playback.inputCacheConsumed = 0; + pDevice->playback.inputCacheRemaining = inputFrameCount; + + result = ma_pcm_rb_commit_read(pRB, inputFrameCount); + if (result != MA_SUCCESS) { + return result; /* Should never happen. */ + } + } + } + + return MA_SUCCESS; +} + +/* A helper for changing the state of the device. */ +static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state newState) +{ + ma_atomic_device_state_set(&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}};*/ +#endif + + + +MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */ +{ + ma_uint32 i; + for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) { + if (g_maFormatPriorities[i] == format) { + return i; + } + } + + /* Getting here means the format could not be found or is equal to ma_format_unknown. */ + return (ma_uint32)-1; +} + +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) { + return MA_FALSE; + } + + if (pDeviceDescriptor->format == ma_format_unknown) { + return MA_FALSE; + } + + if (pDeviceDescriptor->channels == 0 || pDeviceDescriptor->channels > MA_MAX_CHANNELS) { + return MA_FALSE; + } + + if (pDeviceDescriptor->sampleRate == 0) { + return MA_FALSE; + } + + return MA_TRUE; +} + + +static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) +{ + ma_result result = MA_SUCCESS; + ma_bool32 exitLoop = MA_FALSE; + ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 capturedDeviceDataCapInFrames = 0; + ma_uint32 playbackDeviceDataCapInFrames = 0; + + MA_ASSERT(pDevice != NULL); + + /* Just some quick validation on the device type and the available callbacks. */ + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + if (pDevice->pContext->callbacks.onDeviceRead == NULL) { + return MA_NOT_IMPLEMENTED; + } + + capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + if (pDevice->pContext->callbacks.onDeviceWrite == NULL) { + return MA_NOT_IMPLEMENTED; + } + + playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + } + + /* NOTE: The device was started outside of this function, in the worker thread. */ + + while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) { + switch (pDevice->type) { + case ma_device_type_duplex: + { + /* The process is: onDeviceRead() -> convert -> callback -> convert -> onDeviceWrite() */ + ma_uint32 totalCapturedDeviceFramesProcessed = 0; + ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames); + + while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) { + ma_uint32 capturedDeviceFramesRemaining; + ma_uint32 capturedDeviceFramesProcessed; + ma_uint32 capturedDeviceFramesToProcess; + ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed; + if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) { + capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames; + } + + result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; + } + + capturedDeviceFramesRemaining = capturedDeviceFramesToProcess; + capturedDeviceFramesProcessed = 0; + + /* At this point we have our captured data in device format and we now need to convert it to client format. */ + for (;;) { + ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames); + ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining; + ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels)); + + /* Convert capture data from device format to client format. */ + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration); + if (result != MA_SUCCESS) { + break; + } + + /* + 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 + 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 .*/ + + capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ + capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */ + + /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */ + for (;;) { + ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration; + ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames; + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount); + if (result != MA_SUCCESS) { + break; + } + + result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; + } + + capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */ + if (capturedClientFramesToProcessThisIteration == 0) { + break; + } + } + + /* In case an error happened from ma_device_write__null()... */ + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; + } + } + + /* Make sure we don't get stuck in the inner loop. */ + if (capturedDeviceFramesProcessed == 0) { + break; + } + + totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed; + } + } break; + + case ma_device_type_capture: + case ma_device_type_loopback: + { + ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames; + ma_uint32 framesReadThisPeriod = 0; + while (framesReadThisPeriod < periodSizeInFrames) { + ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod; + ma_uint32 framesProcessed; + ma_uint32 framesToReadThisIteration = framesRemainingInPeriod; + if (framesToReadThisIteration > capturedDeviceDataCapInFrames) { + framesToReadThisIteration = capturedDeviceDataCapInFrames; + } + + result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + 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; + } + } break; + + case ma_device_type_playback: + { + /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */ + ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames; + ma_uint32 framesWrittenThisPeriod = 0; + while (framesWrittenThisPeriod < periodSizeInFrames) { + ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod; + ma_uint32 framesProcessed; + ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod; + if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) { + framesToWriteThisIteration = playbackDeviceDataCapInFrames; + } + + ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData); + + result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed); + if (result != MA_SUCCESS) { + exitLoop = MA_TRUE; + break; + } + + /* Make sure we don't get stuck in the inner loop. */ + if (framesProcessed == 0) { + break; + } + + framesWrittenThisPeriod += framesProcessed; + } + } break; + + /* Should never get here. */ + default: break; + } + } + + return result; +} + + + +/******************************************************************************* + +Null Backend + +*******************************************************************************/ +#ifdef MA_HAS_NULL + +#define MA_DEVICE_OP_NONE__NULL 0 +#define MA_DEVICE_OP_START__NULL 1 +#define MA_DEVICE_OP_SUSPEND__NULL 2 +#define MA_DEVICE_OP_KILL__NULL 3 + +static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData) +{ + ma_device* pDevice = (ma_device*)pData; + MA_ASSERT(pDevice != NULL); + + for (;;) { /* Keep the thread alive until the device is uninitialized. */ + ma_uint32 operation; + + /* Wait for an operation to be requested. */ + ma_event_wait(&pDevice->null_device.operationEvent); + + /* At this point an event should have been triggered. */ + operation = pDevice->null_device.operation; + + /* Starting the device needs to put the thread into a loop. */ + if (operation == MA_DEVICE_OP_START__NULL) { + /* Reset the timer just in case. */ + ma_timer_init(&pDevice->null_device.timer); + + /* Getting here means a suspend or kill operation has been requested. */ + pDevice->null_device.operationResult = MA_SUCCESS; + ma_event_signal(&pDevice->null_device.operationCompletionEvent); + ma_semaphore_release(&pDevice->null_device.operationSemaphore); + continue; + } + + /* Suspending the device means we need to stop the timer and just continue the loop. */ + if (operation == MA_DEVICE_OP_SUSPEND__NULL) { + /* We need to add the current run time to the prior run time, then reset the timer. */ + pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer); + ma_timer_init(&pDevice->null_device.timer); + + /* We're done. */ + pDevice->null_device.operationResult = MA_SUCCESS; + ma_event_signal(&pDevice->null_device.operationCompletionEvent); + ma_semaphore_release(&pDevice->null_device.operationSemaphore); + continue; + } + + /* Killing the device means we need to get out of this loop so that this thread can terminate. */ + if (operation == MA_DEVICE_OP_KILL__NULL) { + pDevice->null_device.operationResult = MA_SUCCESS; + ma_event_signal(&pDevice->null_device.operationCompletionEvent); + ma_semaphore_release(&pDevice->null_device.operationSemaphore); + break; + } + + /* Getting a signal on a "none" operation probably means an error. Return invalid operation. */ + if (operation == MA_DEVICE_OP_NONE__NULL) { + MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */ + pDevice->null_device.operationResult = MA_INVALID_OPERATION; + ma_event_signal(&pDevice->null_device.operationCompletionEvent); + ma_semaphore_release(&pDevice->null_device.operationSemaphore); + continue; /* Continue the loop. Don't terminate. */ + } + } + + return (ma_thread_result)0; +} + +static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation) +{ + ma_result result; + + /* + TODO: Need to review this and consider just using mutual exclusion. I think the original motivation + for this was to just post the event to a queue and return immediately, but that has since changed + and now this function is synchronous. I think this can be simplified to just use a mutex. + */ + + /* + 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. + */ + result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore); + if (result != MA_SUCCESS) { + return result; /* Failed to wait for the event. */ + } + + /* + When we get here it means the background thread is not referencing the operation code and it can be changed. After changing this we need to + signal an event to the worker thread to let it know that it can start work. + */ + pDevice->null_device.operation = operation; + + /* Once the operation code has been set, the worker thread can start work. */ + if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) { + return MA_ERROR; + } + + /* We want everything to be synchronous so we're going to wait for the worker thread to complete it's operation. */ + if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) { + return MA_ERROR; + } + + return pDevice->null_device.operationResult; +} + +static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice) +{ + ma_uint32 internalSampleRate; + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + internalSampleRate = pDevice->capture.internalSampleRate; + } else { + internalSampleRate = pDevice->playback.internalSampleRate; + } + + return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate); +} + +static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 cbResult = MA_TRUE; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Playback. */ + if (cbResult) { + 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); + } + + /* Capture. */ + if (cbResult) { + 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); + } + + (void)cbResult; /* Silence a static analysis warning. */ + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__null(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pContext != NULL); + + if (pDeviceID != NULL && pDeviceID->nullbackend != 0) { + return MA_NO_DEVICE; /* Don't know the device. */ + } + + /* Name / Description */ + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1); + } else { + 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; + pDeviceInfo->nativeDataFormats[0].sampleRate = 0; + pDeviceInfo->nativeDataFormats[0].flags = 0; + pDeviceInfo->nativeDataFormatCount = 1; + + (void)pContext; + return MA_SUCCESS; +} + + +static ma_result ma_device_uninit__null(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* Keep it clean and wait for the device thread to finish before returning. */ + ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL); + + /* Wait for the thread to finish before continuing. */ + ma_thread_wait(&pDevice->null_device.deviceThread); + + /* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */ + ma_semaphore_uninit(&pDevice->null_device.operationSemaphore); + ma_event_uninit(&pDevice->null_device.operationCompletionEvent); + ma_event_uninit(&pDevice->null_device.operationEvent); + + return MA_SUCCESS; +} + +static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->null_device); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* The null backend supports everything exactly as we specify it. */ + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + pDescriptorCapture->format = (pDescriptorCapture->format != ma_format_unknown) ? pDescriptorCapture->format : MA_DEFAULT_FORMAT; + pDescriptorCapture->channels = (pDescriptorCapture->channels != 0) ? pDescriptorCapture->channels : MA_DEFAULT_CHANNELS; + 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); + } + + pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + pDescriptorPlayback->format = (pDescriptorPlayback->format != ma_format_unknown) ? pDescriptorPlayback->format : MA_DEFAULT_FORMAT; + pDescriptorPlayback->channels = (pDescriptorPlayback->channels != 0) ? pDescriptorPlayback->channels : MA_DEFAULT_CHANNELS; + 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); + } + + pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); + } + + /* + In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the + first period is "written" to it, and then stopped in ma_device_stop__null(). + */ + result = ma_event_init(&pDevice->null_device.operationEvent); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_event_init(&pDevice->null_device.operationCompletionEvent); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_semaphore_init(1, &pDevice->null_device.operationSemaphore); /* <-- It's important that the initial value is set to 1. */ + if (result != MA_SUCCESS) { + return result; + } + + result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice, &pDevice->pContext->allocationCallbacks); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__null(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL); + + ma_atomic_bool32_set(&pDevice->null_device.isStarted, MA_TRUE); + return MA_SUCCESS; +} + +static ma_result ma_device_stop__null(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL); + + ma_atomic_bool32_set(&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; + ma_uint32 totalPCMFramesProcessed; + ma_bool32 wasStartedOnEntry; + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + wasStartedOnEntry = ma_device_is_started__null(pDevice); + + /* Keep going until everything has been read. */ + totalPCMFramesProcessed = 0; + while (totalPCMFramesProcessed < frameCount) { + ma_uint64 targetFrame; + + /* If there are any frames remaining in the current period, consume those first. */ + if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) { + ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); + ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback; + if (framesToProcess > framesRemaining) { + framesToProcess = framesRemaining; + } + + /* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */ + (void)pPCMFrames; + + pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess; + totalPCMFramesProcessed += framesToProcess; + } + + /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */ + if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) { + pDevice->null_device.currentPeriodFramesRemainingPlayback = 0; + + if (!ma_device_is_started__null(pDevice) && !wasStartedOnEntry) { + result = ma_device_start__null(pDevice); + if (result != MA_SUCCESS) { + break; + } + } + } + + /* If we've consumed the whole buffer we can return now. */ + MA_ASSERT(totalPCMFramesProcessed <= frameCount); + if (totalPCMFramesProcessed == frameCount) { + break; + } + + /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */ + targetFrame = pDevice->null_device.lastProcessedFramePlayback; + for (;;) { + ma_uint64 currentFrame; + + /* Stop waiting if the device has been stopped. */ + if (!ma_device_is_started__null(pDevice)) { + break; + } + + currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice); + if (currentFrame >= targetFrame) { + break; + } + + /* Getting here means we haven't yet reached the target sample, so continue waiting. */ + ma_sleep(10); + } + + pDevice->null_device.lastProcessedFramePlayback += pDevice->playback.internalPeriodSizeInFrames; + pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalPeriodSizeInFrames; + } + + if (pFramesWritten != NULL) { + *pFramesWritten = totalPCMFramesProcessed; + } + + return result; +} + +static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) +{ + ma_result result = MA_SUCCESS; + ma_uint32 totalPCMFramesProcessed; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + /* Keep going until everything has been read. */ + totalPCMFramesProcessed = 0; + while (totalPCMFramesProcessed < frameCount) { + ma_uint64 targetFrame; + + /* If there are any frames remaining in the current period, consume those first. */ + if (pDevice->null_device.currentPeriodFramesRemainingCapture > 0) { + ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed); + ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingCapture; + if (framesToProcess > framesRemaining) { + framesToProcess = framesRemaining; + } + + /* We need to ensure the output buffer is zeroed. */ + MA_ZERO_MEMORY(ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed*bpf), framesToProcess*bpf); + + pDevice->null_device.currentPeriodFramesRemainingCapture -= framesToProcess; + totalPCMFramesProcessed += framesToProcess; + } + + /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */ + if (pDevice->null_device.currentPeriodFramesRemainingCapture == 0) { + pDevice->null_device.currentPeriodFramesRemainingCapture = 0; + } + + /* If we've consumed the whole buffer we can return now. */ + MA_ASSERT(totalPCMFramesProcessed <= frameCount); + if (totalPCMFramesProcessed == frameCount) { + break; + } + + /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */ + targetFrame = pDevice->null_device.lastProcessedFrameCapture + pDevice->capture.internalPeriodSizeInFrames; + for (;;) { + ma_uint64 currentFrame; + + /* Stop waiting if the device has been stopped. */ + if (!ma_device_is_started__null(pDevice)) { + break; + } + + currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice); + if (currentFrame >= targetFrame) { + break; + } + + /* Getting here means we haven't yet reached the target sample, so continue waiting. */ + ma_sleep(10); + } + + pDevice->null_device.lastProcessedFrameCapture += pDevice->capture.internalPeriodSizeInFrames; + pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalPeriodSizeInFrames; + } + + if (pFramesRead != NULL) { + *pFramesRead = totalPCMFramesProcessed; + } + + return result; +} + +static ma_result ma_context_uninit__null(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_null); + + (void)pContext; + return MA_SUCCESS; +} + +static ma_result ma_context_init__null(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + MA_ASSERT(pContext != NULL); + + (void)pConfig; + (void)pContext; + + pCallbacks->onContextInit = ma_context_init__null; + pCallbacks->onContextUninit = ma_context_uninit__null; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__null; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__null; + pCallbacks->onDeviceInit = ma_device_init__null; + pCallbacks->onDeviceUninit = ma_device_uninit__null; + pCallbacks->onDeviceStart = ma_device_start__null; + pCallbacks->onDeviceStop = ma_device_stop__null; + pCallbacks->onDeviceRead = ma_device_read__null; + pCallbacks->onDeviceWrite = ma_device_write__null; + pCallbacks->onDeviceDataLoop = NULL; /* Our backend is asynchronous with a blocking read-write API which means we can get miniaudio to deal with the audio thread. */ + + /* The null backend always works. */ + return MA_SUCCESS; +} +#endif + + + +/******************************************************************************* + +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)) + #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) + #define ma_PropVariantClear(pContext, pvar) ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar) +#else + #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit) + #define ma_CoUninitialize(pContext) CoUninitialize() + #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) + #define ma_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv) + #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar) +#endif + +#if !defined(MAXULONG_PTR) && !defined(__WATCOMC__) +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 +#endif + +#ifndef SPEAKER_FRONT_LEFT +#define SPEAKER_FRONT_LEFT 0x1 +#define SPEAKER_FRONT_RIGHT 0x2 +#define SPEAKER_FRONT_CENTER 0x4 +#define SPEAKER_LOW_FREQUENCY 0x8 +#define SPEAKER_BACK_LEFT 0x10 +#define SPEAKER_BACK_RIGHT 0x20 +#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 +#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 +#define SPEAKER_BACK_CENTER 0x100 +#define SPEAKER_SIDE_LEFT 0x200 +#define SPEAKER_SIDE_RIGHT 0x400 +#define SPEAKER_TOP_CENTER 0x800 +#define SPEAKER_TOP_FRONT_LEFT 0x1000 +#define SPEAKER_TOP_FRONT_CENTER 0x2000 +#define SPEAKER_TOP_FRONT_RIGHT 0x4000 +#define SPEAKER_TOP_BACK_LEFT 0x8000 +#define SPEAKER_TOP_BACK_CENTER 0x10000 +#define SPEAKER_TOP_BACK_RIGHT 0x20000 +#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. +*/ +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; + union + { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +} MA_WAVEFORMATEXTENSIBLE; + + + +#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 + +/* Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to miniaudio. */ +static ma_uint8 ma_channel_id_to_ma__win32(DWORD id) +{ + switch (id) + { + case SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; + case SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; + case SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; + case SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE; + case SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT; + case SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT; + case SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; + case SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER; + case SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; + case SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; + case SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; + case SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; + case SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; + case SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; + case SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; + case SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; + case SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; + default: return 0; + } +} + +/* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to Win32-style. */ +static DWORD ma_channel_id_to_win32(DWORD id) +{ + switch (id) + { + case MA_CHANNEL_MONO: return SPEAKER_FRONT_CENTER; + case MA_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT; + case MA_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT; + case MA_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER; + case MA_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY; + case MA_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT; + case MA_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT; + case MA_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER; + case MA_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER; + case MA_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER; + case MA_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT; + case MA_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT; + case MA_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER; + case MA_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT; + case MA_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER; + case MA_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT; + case MA_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT; + case MA_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER; + case MA_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT; + default: return 0; + } +} + +/* Converts a channel mapping to a Win32-style channel mask. */ +static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel* pChannelMap, ma_uint32 channels) +{ + DWORD dwChannelMask = 0; + ma_uint32 iChannel; + + for (iChannel = 0; iChannel < channels; ++iChannel) { + dwChannelMask |= ma_channel_id_to_win32(pChannelMap[iChannel]); + } + + return dwChannelMask; +} + +/* 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); + } else { + if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) { + pChannelMap[0] = MA_CHANNEL_MONO; + } else { + /* Just iterate over each bit. */ + ma_uint32 iChannel = 0; + ma_uint32 iBit; + + for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) { + DWORD bitValue = (dwChannelMask & (1UL << iBit)); + if (bitValue != 0) { + /* The bit is set. */ + pChannelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue); + iChannel += 1; + } + } + } + } +} + +#ifdef __cplusplus +static ma_bool32 ma_is_guid_equal(const void* a, const void* b) +{ + return IsEqualGUID(*(const GUID*)a, *(const GUID*)b); +} +#else +#define ma_is_guid_equal(a, b) IsEqualGUID((const GUID*)a, (const GUID*)b) +#endif + +static MA_INLINE ma_bool32 ma_is_guid_null(const void* guid) +{ + static GUID nullguid = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + return ma_is_guid_equal(guid, &nullguid); +} + +static ma_format ma_format_from_WAVEFORMATEX(const MA_WAVEFORMATEX* pWF) +{ + MA_ASSERT(pWF != NULL); + + if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + const MA_WAVEFORMATEXTENSIBLE* pWFEX = (const MA_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->wBitsPerSample == 24) { + return ma_format_s24; + } + } + if (pWFEX->Samples.wValidBitsPerSample == 16) { + return ma_format_s16; + } + if (pWFEX->Samples.wValidBitsPerSample == 8) { + return ma_format_u8; + } + } + if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + if (pWFEX->Samples.wValidBitsPerSample == 32) { + return ma_format_f32; + } + /* + if (pWFEX->Samples.wValidBitsPerSample == 64) { + return ma_format_f64; + } + */ + } + } else { + if (pWF->wFormatTag == WAVE_FORMAT_PCM) { + if (pWF->wBitsPerSample == 32) { + return ma_format_s32; + } + if (pWF->wBitsPerSample == 24) { + return ma_format_s24; + } + if (pWF->wBitsPerSample == 16) { + return ma_format_s16; + } + if (pWF->wBitsPerSample == 8) { + return ma_format_u8; + } + } + if (pWF->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { + if (pWF->wBitsPerSample == 32) { + return ma_format_f32; + } + if (pWF->wBitsPerSample == 64) { + /*return ma_format_f64;*/ + } + } + } + + return ma_format_unknown; +} +#endif + + +/******************************************************************************* + +WASAPI Backend + +*******************************************************************************/ +#ifdef MA_HAS_WASAPI +#if 0 +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable:4091) /* 'typedef ': ignored on left of '' when no variable is declared */ +#endif +#include +#include +#if defined(_MSC_VER) + #pragma warning(pop) +#endif +#endif /* 0 */ + +static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType); + +/* Some compilers don't define VerifyVersionInfoW. Need to write this ourselves. */ +#define MA_WIN32_WINNT_VISTA 0x0600 +#define MA_VER_MINORVERSION 0x01 +#define MA_VER_MAJORVERSION 0x02 +#define MA_VER_SERVICEPACKMAJOR 0x20 +#define MA_VER_GREATER_EQUAL 0x03 + +typedef struct { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; +} ma_OSVERSIONINFOEXW; + +typedef BOOL (WINAPI * ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW* lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask); +typedef ULONGLONG (WINAPI * ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask); + + +#ifndef PROPERTYKEY_DEFINED +#define PROPERTYKEY_DEFINED +#ifndef __WATCOMC__ +typedef struct +{ + GUID fmtid; + DWORD pid; +} PROPERTYKEY; +#endif +#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) +{ + MA_ZERO_OBJECT(pProp); +} + + +static const PROPERTYKEY MA_PKEY_Device_FriendlyName = {{0xA45C254E, 0xDF1C, 0x4EFD, {0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0}}, 14}; +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) +static const IID MA_IID_IAgileObject = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */ +#endif + +static const IID MA_IID_IAudioClient = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; /* 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) */ +static const IID MA_IID_IAudioClient2 = {0x726778CD, 0xF60A, 0x4EDA, {0x82, 0xDE, 0xE4, 0x76, 0x10, 0xCD, 0x78, 0xAA}}; /* 726778CD-F60A-4EDA-82DE-E47610CD78AA = __uuidof(IAudioClient2) */ +static const IID MA_IID_IAudioClient3 = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */ +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) +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) */ + +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +#define MA_MM_DEVICE_STATE_ACTIVE 1 +#define MA_MM_DEVICE_STATE_DISABLED 2 +#define MA_MM_DEVICE_STATE_NOTPRESENT 4 +#define MA_MM_DEVICE_STATE_UNPLUGGED 8 + +typedef struct ma_IMMDeviceEnumerator ma_IMMDeviceEnumerator; +typedef struct ma_IMMDeviceCollection ma_IMMDeviceCollection; +typedef struct ma_IMMDevice ma_IMMDevice; +#else +typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler; +typedef struct ma_IActivateAudioInterfaceAsyncOperation ma_IActivateAudioInterfaceAsyncOperation; +#endif +typedef struct ma_IPropertyStore ma_IPropertyStore; +typedef struct ma_IAudioClient ma_IAudioClient; +typedef struct ma_IAudioClient2 ma_IAudioClient2; +typedef struct ma_IAudioClient3 ma_IAudioClient3; +typedef struct ma_IAudioRenderClient ma_IAudioRenderClient; +typedef struct ma_IAudioCaptureClient ma_IAudioCaptureClient; + +typedef ma_int64 MA_REFERENCE_TIME; + +#define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS 0x00010000 +#define MA_AUDCLNT_STREAMFLAGS_LOOPBACK 0x00020000 +#define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK 0x00040000 +#define MA_AUDCLNT_STREAMFLAGS_NOPERSIST 0x00080000 +#define MA_AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000 +#define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000 +#define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000 +#define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED 0x10000000 +#define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE 0x20000000 +#define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED 0x40000000 + +/* Buffer flags. */ +#define MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY 1 +#define MA_AUDCLNT_BUFFERFLAGS_SILENT 2 +#define MA_AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR 4 + +typedef enum +{ + ma_eRender = 0, + ma_eCapture = 1, + ma_eAll = 2 +} ma_EDataFlow; + +typedef enum +{ + ma_eConsole = 0, + ma_eMultimedia = 1, + ma_eCommunications = 2 +} ma_ERole; + +typedef enum +{ + MA_AUDCLNT_SHAREMODE_SHARED, + MA_AUDCLNT_SHAREMODE_EXCLUSIVE +} MA_AUDCLNT_SHAREMODE; + +typedef enum +{ + MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */ +} MA_AUDIO_STREAM_CATEGORY; + +typedef struct +{ + ma_uint32 cbSize; + BOOL bIsOffload; + MA_AUDIO_STREAM_CATEGORY eCategory; +} ma_AudioClientProperties; + +/* IUnknown */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IUnknown* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IUnknown* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IUnknown* pThis); +} ma_IUnknownVtbl; +struct ma_IUnknown +{ + ma_IUnknownVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +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) + /* IMMNotificationClient */ + typedef struct + { + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMNotificationClient* 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); + } ma_IMMNotificationClientVtbl; + + /* IMMDeviceEnumerator */ + typedef struct + { + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceEnumerator* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceEnumerator* 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 * RegisterEndpointNotificationCallback) (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); + HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient); + } ma_IMMDeviceEnumeratorVtbl; + struct ma_IMMDeviceEnumerator + { + ma_IMMDeviceEnumeratorVtbl* lpVtbl; + }; + static MA_INLINE HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } + static MA_INLINE ULONG ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->AddRef(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_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); } + + + /* IMMDeviceCollection */ + typedef struct + { + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceCollection* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceCollection* pThis); + + /* IMMDeviceCollection */ + HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IMMDeviceCollection* pThis, UINT* pDevices); + HRESULT (STDMETHODCALLTYPE * Item) (ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice); + } ma_IMMDeviceCollectionVtbl; + struct ma_IMMDeviceCollection + { + ma_IMMDeviceCollectionVtbl* lpVtbl; + }; + static MA_INLINE HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } + static MA_INLINE ULONG ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->AddRef(pThis); } + static MA_INLINE ULONG ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->Release(pThis); } + static MA_INLINE HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection* pThis, UINT* pDevices) { return pThis->lpVtbl->GetCount(pThis, pDevices); } + static MA_INLINE HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->Item(pThis, nDevice, ppDevice); } + + + /* IMMDevice */ + typedef struct + { + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDevice* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDevice* 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 * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties); + HRESULT (STDMETHODCALLTYPE * GetId) (ma_IMMDevice* pThis, WCHAR** pID); + HRESULT (STDMETHODCALLTYPE * GetState) (ma_IMMDevice* pThis, DWORD *pState); + } ma_IMMDeviceVtbl; + struct ma_IMMDevice + { + ma_IMMDeviceVtbl* lpVtbl; + }; + 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_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_GetState(ma_IMMDevice* pThis, DWORD *pState) { return pThis->lpVtbl->GetState(pThis, pState); } +#else + /* IActivateAudioInterfaceAsyncOperation */ + typedef struct + { + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IActivateAudioInterfaceAsyncOperation* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IActivateAudioInterfaceAsyncOperation* pThis); + + /* IActivateAudioInterfaceAsyncOperation */ + HRESULT (STDMETHODCALLTYPE * GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface); + } ma_IActivateAudioInterfaceAsyncOperationVtbl; + struct ma_IActivateAudioInterfaceAsyncOperation + { + ma_IActivateAudioInterfaceAsyncOperationVtbl* lpVtbl; + }; + static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } + static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->AddRef(pThis); } + static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->Release(pThis); } + static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface) { return pThis->lpVtbl->GetActivateResult(pThis, pActivateResult, ppActivatedInterface); } +#endif + +/* IPropertyStore */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IPropertyStore* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IPropertyStore* pThis); + + /* 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 * Commit) (ma_IPropertyStore* pThis); +} ma_IPropertyStoreVtbl; +struct ma_IPropertyStore +{ + ma_IPropertyStoreVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis) { return pThis->lpVtbl->AddRef(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_Commit(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Commit(pThis); } + + +/* IAudioClient */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient* pThis); + 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 * 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 * GetDevicePeriod) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); + HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient* pThis); + HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient* pThis); + HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient* pThis); + HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient* pThis, HANDLE eventHandle); + HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient* pThis, const IID* const riid, void** pp); +} ma_IAudioClientVtbl; +struct ma_IAudioClient +{ + ma_IAudioClientVtbl* lpVtbl; +}; +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_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_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); } +static MA_INLINE HRESULT ma_IAudioClient_Reset(ma_IAudioClient* pThis) { return pThis->lpVtbl->Reset(pThis); } +static MA_INLINE HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } +static MA_INLINE HRESULT ma_IAudioClient_GetService(ma_IAudioClient* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); } + +/* IAudioClient2 */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient2* pThis); + 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 * 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 * GetDevicePeriod) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); + HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient2* pThis); + HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient2* pThis); + HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient2* pThis); + HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient2* pThis, HANDLE eventHandle); + HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient2* pThis, const IID* const riid, void** pp); + + /* 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); +} ma_IAudioClient2Vtbl; +struct ma_IAudioClient2 +{ + ma_IAudioClient2Vtbl* lpVtbl; +}; +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_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_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); } +static MA_INLINE HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Reset(pThis); } +static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } +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); } + + +/* IAudioClient3 */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient3* pThis); + 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 * 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 * GetDevicePeriod) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod); + HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient3* pThis); + HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient3* pThis); + HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient3* pThis); + HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient3* pThis, HANDLE eventHandle); + HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient3* pThis, const IID* const riid, void** pp); + + /* 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); + + /* 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); +} ma_IAudioClient3Vtbl; +struct ma_IAudioClient3 +{ + ma_IAudioClient3Vtbl* lpVtbl; +}; +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_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_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); } +static MA_INLINE HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Reset(pThis); } +static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); } +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); } + + +/* IAudioRenderClient */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioRenderClient* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioRenderClient* pThis); + + /* IAudioRenderClient */ + HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData); + HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags); +} ma_IAudioRenderClientVtbl; +struct ma_IAudioRenderClient +{ + ma_IAudioRenderClientVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->Release(pThis); } +static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData) { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); } +static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); } + + +/* IAudioCaptureClient */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioCaptureClient* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioCaptureClient* pThis); + + /* IAudioRenderClient */ + HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition); + HRESULT (STDMETHODCALLTYPE * ReleaseBuffer) (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead); + HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket); +} ma_IAudioCaptureClientVtbl; +struct ma_IAudioCaptureClient +{ + ma_IAudioCaptureClientVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->Release(pThis); } +static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition) { return pThis->lpVtbl->GetBuffer(pThis, ppData, pNumFramesToRead, pFlags, pDevicePosition, pQPCPosition); } +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) +typedef struct ma_completion_handler_uwp ma_completion_handler_uwp; + +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_completion_handler_uwp* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_completion_handler_uwp* pThis); + + /* IActivateAudioInterfaceCompletionHandler */ + HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation); +} ma_completion_handler_uwp_vtbl; +struct ma_completion_handler_uwp +{ + ma_completion_handler_uwp_vtbl* lpVtbl; + MA_ATOMIC(4, ma_uint32) counter; + HANDLE hEvent; +}; + +static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject) +{ + /* + We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To + "implement" this, we just make sure we return pThis when the IAgileObject is requested. + */ + if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) { + *ppObject = NULL; + return E_NOINTERFACE; + } + + /* Getting here means the IID is IUnknown or IMMNotificationClient. */ + *ppObject = (void*)pThis; + ((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis); + return S_OK; +} + +static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis) +{ + return (ULONG)ma_atomic_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; + if (newRefCount == 0) { + return 0; /* We don't free anything here because we never allocate the object on the heap. */ + } + + return (ULONG)newRefCount; +} + +static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation) +{ + (void)pActivateOperation; + SetEvent(pThis->hEvent); + return S_OK; +} + + +static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = { + ma_completion_handler_uwp_QueryInterface, + ma_completion_handler_uwp_AddRef, + ma_completion_handler_uwp_Release, + ma_completion_handler_uwp_ActivateCompleted +}; + +static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler) +{ + MA_ASSERT(pHandler != NULL); + MA_ZERO_OBJECT(pHandler); + + pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance; + pHandler->counter = 1; + pHandler->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); + if (pHandler->hEvent == NULL) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + +static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler) +{ + if (pHandler->hEvent != NULL) { + CloseHandle(pHandler->hEvent); + } +} + +static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler) +{ + WaitForSingleObject((HANDLE)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) +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject) +{ + /* + We care about two interfaces - IUnknown and IMMNotificationClient. If the requested IID is something else + we just return E_NOINTERFACE. Otherwise we need to increment the reference counter and return S_OK. + */ + if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IMMNotificationClient)) { + *ppObject = NULL; + return E_NOINTERFACE; + } + + /* Getting here means the IID is IUnknown or IMMNotificationClient. */ + *ppObject = (void*)pThis; + ((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis); + return S_OK; +} + +static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis) +{ + return (ULONG)ma_atomic_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; + if (newRefCount == 0) { + return 0; /* We don't free anything here because we never allocate the object on the heap. */ + } + + return (ULONG)newRefCount; +} + +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, const WCHAR* 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);*/ +#endif + + /* + There have been reports of a hang when a playback device is disconnected. The idea with this code is to explicitly stop the device if we detect + that the device is disabled or has been unplugged. + */ + 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) { + 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) { + isThisDevice = MA_TRUE; + } + } + + + /* + If the device ID matches our device we need to mark our device as detached and stop it. When a + device is added in OnDeviceAdded(), we'll restart it. We only mark it as detached if the device + was started at the time of being removed. + */ + if (isThisDevice) { + if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) == 0) { + /* + Unplugged or otherwise unavailable. Mark as detached if we were in a playing state. We'll + 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 (isPlayback) { + pThis->pDevice->wasapi.isDetachedPlayback = MA_TRUE; + } + if (isCapture) { + pThis->pDevice->wasapi.isDetachedCapture = MA_TRUE; + } + + ma_device_stop(pThis->pDevice); + } + } + + if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) != 0) { + /* The device was activated. If we were detached, we need to start it again. */ + ma_bool8 tryRestartingDevice = MA_FALSE; + + if (isPlayback) { + if (pThis->pDevice->wasapi.isDetachedPlayback) { + pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE; + ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback); + tryRestartingDevice = MA_TRUE; + } + } + + if (isCapture) { + if (pThis->pDevice->wasapi.isDetachedCapture) { + pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE; + ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture); + tryRestartingDevice = MA_TRUE; + } + } + + if (tryRestartingDevice) { + if (pThis->pDevice->wasapi.isDetachedPlayback == MA_FALSE && pThis->pDevice->wasapi.isDetachedCapture == MA_FALSE) { + ma_device_start(pThis->pDevice); + } + } + } + } + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, const WCHAR* 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)");*/ +#endif + + /* We don't need to worry about this event for our purposes. */ + (void)pThis; + (void)pDeviceID; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, const WCHAR* 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)");*/ +#endif + + /* We don't need to worry about this event for our purposes. */ + (void)pThis; + (void)pDeviceID; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, const WCHAR* 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)");*/ +#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"); + 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; + } + + /* 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"); + return S_OK; + } + + /* + Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to + AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once + it's fixed. + */ + 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"); + 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. + */ + { + 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) { + 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 (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); + + 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); + } + } + } + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, const WCHAR* 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)");*/ +#endif + + (void)pThis; + (void)pDeviceID; + (void)key; + return S_OK; +} + +static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = { + ma_IMMNotificationClient_QueryInterface, + ma_IMMNotificationClient_AddRef, + ma_IMMNotificationClient_Release, + ma_IMMNotificationClient_OnDeviceStateChanged, + ma_IMMNotificationClient_OnDeviceAdded, + ma_IMMNotificationClient_OnDeviceRemoved, + ma_IMMNotificationClient_OnDefaultDeviceChanged, + ma_IMMNotificationClient_OnPropertyValueChanged +}; +#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) +typedef ma_IMMDevice ma_WASAPIDeviceInterface; +#else +typedef ma_IUnknown ma_WASAPIDeviceInterface; +#endif + + +#define MA_CONTEXT_COMMAND_QUIT__WASAPI 1 +#define MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI 2 +#define MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI 3 + +static ma_context_command__wasapi ma_context_init_command__wasapi(int code) +{ + ma_context_command__wasapi cmd; + + MA_ZERO_OBJECT(&cmd); + cmd.code = code; + + return cmd; +} + +static ma_result ma_context_post_command__wasapi(ma_context* pContext, const ma_context_command__wasapi* pCmd) +{ + /* For now we are doing everything synchronously, but I might relax this later if the need arises. */ + ma_result result; + ma_bool32 isUsingLocalEvent = MA_FALSE; + ma_event localEvent; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pCmd != NULL); + + if (pCmd->pEvent == NULL) { + isUsingLocalEvent = MA_TRUE; + + result = ma_event_init(&localEvent); + if (result != MA_SUCCESS) { + return result; /* Failed to create the event for this command. */ + } + } + + /* Here is where we add the command to the list. If there's not enough room we'll spin until there is. */ + ma_mutex_lock(&pContext->wasapi.commandLock); + { + ma_uint32 index; + + /* Spin until we've got some space available. */ + while (pContext->wasapi.commandCount == ma_countof(pContext->wasapi.commands)) { + ma_yield(); + } + + /* Space is now available. Can safely add to the list. */ + index = (pContext->wasapi.commandIndex + pContext->wasapi.commandCount) % ma_countof(pContext->wasapi.commands); + pContext->wasapi.commands[index] = *pCmd; + pContext->wasapi.commands[index].pEvent = &localEvent; + pContext->wasapi.commandCount += 1; + + /* 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); + + if (isUsingLocalEvent) { + ma_event_wait(&localEvent); + ma_event_uninit(&localEvent); + } + + return MA_SUCCESS; +} + +static ma_result ma_context_next_command__wasapi(ma_context* pContext, ma_context_command__wasapi* pCmd) +{ + ma_result result = MA_SUCCESS; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pCmd != NULL); + + result = ma_semaphore_wait(&pContext->wasapi.commandSem); + if (result == MA_SUCCESS) { + ma_mutex_lock(&pContext->wasapi.commandLock); + { + *pCmd = pContext->wasapi.commands[pContext->wasapi.commandIndex]; + pContext->wasapi.commandIndex = (pContext->wasapi.commandIndex + 1) % ma_countof(pContext->wasapi.commands); + pContext->wasapi.commandCount -= 1; + } + ma_mutex_unlock(&pContext->wasapi.commandLock); + } + + return result; +} + +static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pUserData) +{ + ma_result result; + ma_context* pContext = (ma_context*)pUserData; + MA_ASSERT(pContext != NULL); + + for (;;) { + ma_context_command__wasapi cmd; + result = ma_context_next_command__wasapi(pContext, &cmd); + if (result != MA_SUCCESS) { + break; + } + + switch (cmd.code) + { + case MA_CONTEXT_COMMAND_QUIT__WASAPI: + { + /* Do nothing. Handled after the switch. */ + } break; + + 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)); + } 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)); + } + } break; + + case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI: + { + 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; + } + } + + if (cmd.data.releaseAudioClient.deviceType == ma_device_type_capture) { + if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture != NULL) { + ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture); + cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture = NULL; + } + } + } break; + + default: + { + /* Unknown command. Ignore it, but trigger an assert in debug mode so we're aware of it. */ + MA_ASSERT(MA_FALSE); + } break; + } + + if (cmd.pEvent != NULL) { + ma_event_signal(cmd.pEvent); + } + + if (cmd.code == MA_CONTEXT_COMMAND_QUIT__WASAPI) { + break; /* Received a quit message. Get out of here. */ + } + } + + return (ma_thread_result)0; +} + +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. */ + + 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; +} + +#if 0 /* Not used at the moment, but leaving here for future use. */ +static ma_result ma_device_release_IAudioClient_service__wasapi(ma_device* pDevice, ma_device_type deviceType) +{ + ma_result result; + ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI); + cmd.data.releaseAudioClient.pDevice = pDevice; + cmd.data.releaseAudioClient.deviceType = deviceType; + + result = ma_context_post_command__wasapi(pDevice->pContext, &cmd); /* This will not return until the command has actually been run. */ + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} +#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) +{ + MA_ASSERT(pWF != NULL); + MA_ASSERT(pInfo != NULL); + + if (pInfo->nativeDataFormatCount >= ma_countof(pInfo->nativeDataFormats)) { + return; /* Too many data formats. Need to ignore this one. Don't think this should ever happen with WASAPI. */ + } + + pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].format = ma_format_from_WAVEFORMATEX(pWF); + pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].channels = pWF->nChannels; + pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].sampleRate = pWF->nSamplesPerSec; + pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].flags = (shareMode == ma_share_mode_exclusive) ? MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE : 0; + pInfo->nativeDataFormatCount += 1; +} + +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; + + MA_ASSERT(pAudioClient != NULL); + MA_ASSERT(pInfo != NULL); + + /* Shared Mode. We use GetMixFormat() here. */ + hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (MA_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); + } + + /* + Exclusive 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) + { + ma_IPropertyStore *pProperties; + + /* + The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is + correct which will simplify our searching. + */ + hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties); + if (SUCCEEDED(hr)) { + MA_PROPVARIANT var; + ma_PropVariantInit(&var); + + hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var); + if (SUCCEEDED(hr)) { + pWF = (MA_WAVEFORMATEX*)var.blob.pBlobData; + + /* + In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format + first. If this fails, fall back to a search. + */ + hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL); + if (SUCCEEDED(hr)) { + /* The format returned by PKEY_AudioEngine_DeviceFormat is supported. */ + ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_exclusive, pInfo); + } else { + /* + 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_channel defaultChannelMap[MA_MAX_CHANNELS]; + MA_WAVEFORMATEXTENSIBLE wf; + ma_bool32 found; + ma_uint32 iFormat; + + /* Make sure we don't overflow the channel map. */ + if (channels > MA_MAX_CHANNELS) { + channels = MA_MAX_CHANNELS; + } + + ma_channel_map_init_standard(ma_standard_channel_map_microsoft, defaultChannelMap, ma_countof(defaultChannelMap), channels); + + MA_ZERO_OBJECT(&wf); + wf.cbSize = sizeof(wf); + wf.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wf.nChannels = (WORD)channels; + wf.dwChannelMask = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels); + + found = MA_FALSE; + for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) { + 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; + if (format == ma_format_f32) { + wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } else { + wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; + } + + for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) { + wf.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate]; + + hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (MA_WAVEFORMATEX*)&wf, NULL); + if (SUCCEEDED(hr)) { + ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((MA_WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo); + found = MA_TRUE; + break; + } + } + + if (found) { + break; + } + } + + 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."); + } + } + } else { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval."); + } + + 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."); + } + } + #else + { + (void)pMMDevice; /* Unused. */ + } + #endif + + return MA_SUCCESS; +} + +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) +static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType) +{ + if (deviceType == ma_device_type_playback) { + return ma_eRender; + } else if (deviceType == ma_device_type_capture) { + return ma_eCapture; + } else { + MA_ASSERT(MA_FALSE); + return ma_eRender; /* Should never hit this. */ + } +} + +static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator** ppDeviceEnumerator) +{ + HRESULT hr; + ma_IMMDeviceEnumerator* pDeviceEnumerator; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppDeviceEnumerator != NULL); + + *ppDeviceEnumerator = NULL; /* Safety. */ + + 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); + } + + *ppDeviceEnumerator = pDeviceEnumerator; + + return MA_SUCCESS; +} + +static WCHAR* 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; + ma_EDataFlow dataFlow; + ma_ERole role; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceEnumerator != NULL); + + (void)pContext; + + /* Grab the EDataFlow type from the device type. */ + dataFlow = ma_device_type_to_EDataFlow(deviceType); + + /* The role is always eConsole, but we may make this configurable later. */ + role = ma_eConsole; + + hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, dataFlow, role, &pMMDefaultDevice); + if (FAILED(hr)) { + return NULL; + } + + hr = ma_IMMDevice_GetId(pMMDefaultDevice, &pDefaultDeviceID); + + ma_IMMDevice_Release(pMMDefaultDevice); + pMMDefaultDevice = NULL; + + if (FAILED(hr)) { + return NULL; + } + + 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() */ +{ + ma_result result; + ma_IMMDeviceEnumerator* pDeviceEnumerator; + WCHAR* pDefaultDeviceID = NULL; + + MA_ASSERT(pContext != NULL); + + result = ma_context_create_IMMDeviceEnumerator__wasapi(pContext, &pDeviceEnumerator); + if (result != MA_SUCCESS) { + return NULL; + } + + pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType); + + ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); + return pDefaultDeviceID; +} + +static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IMMDevice** ppMMDevice) +{ + ma_IMMDeviceEnumerator* pDeviceEnumerator; + HRESULT hr; + + 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); + } + + if (pDeviceID == NULL) { + hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (deviceType == ma_device_type_capture) ? ma_eCapture : ma_eRender, ma_eConsole, ppMMDevice); + } else { + hr = ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, ppMMDevice); + } + + 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_SUCCESS; +} + +static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_device_id* pDeviceID) +{ + WCHAR* pDeviceIDString; + HRESULT hr; + + MA_ASSERT(pDeviceID != NULL); + + hr = ma_IMMDevice_GetId(pMMDevice, &pDeviceIDString); + if (SUCCEEDED(hr)) { + size_t idlen = ma_strlen_WCHAR(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. */ + return MA_ERROR; + } + + MA_COPY_MEMORY(pDeviceID->wasapi, pDeviceIDString, idlen * sizeof(wchar_t)); + pDeviceID->wasapi[idlen] = '\0'; + + ma_CoTaskMemFree(pContext, pDeviceIDString); + + return MA_SUCCESS; + } + + 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) +{ + ma_result result; + HRESULT hr; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pMMDevice != NULL); + MA_ASSERT(pInfo != NULL); + + /* ID. */ + 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) { + pInfo->isDefault = MA_TRUE; + } + } + } + + /* Description / Friendly Name */ + { + ma_IPropertyStore *pProperties; + hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties); + if (SUCCEEDED(hr)) { + MA_PROPVARIANT var; + + ma_PropVariantInit(&var); + hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var); + if (SUCCEEDED(hr)) { + WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE); + ma_PropVariantClear(pContext, &var); + } + + ma_IPropertyStore_Release(pProperties); + } + } + + /* Format */ + if (!onlySimpleInfo) { + ma_IAudioClient* pAudioClient; + hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient); + if (SUCCEEDED(hr)) { + result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, pInfo); + + 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_SUCCESS; +} + +static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_result result = MA_SUCCESS; + UINT deviceCount; + HRESULT hr; + ma_uint32 iDevice; + WCHAR* pDefaultDeviceID = NULL; + ma_IMMDeviceCollection* pDeviceCollection = NULL; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Grab the default device. We use this to know whether or not flag the returned device info as being the default. */ + pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType); + + /* We need to enumerate the devices which returns a device collection. */ + hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_device_type_to_EDataFlow(deviceType), MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection); + 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); + goto done; + } + + for (iDevice = 0; iDevice < deviceCount; ++iDevice) { + ma_device_info deviceInfo; + ma_IMMDevice* pMMDevice; + + MA_ZERO_OBJECT(&deviceInfo); + + hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice); + if (SUCCEEDED(hr)) { + result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_TRUE, &deviceInfo); /* MA_TRUE = onlySimpleInfo. */ + + ma_IMMDevice_Release(pMMDevice); + if (result == MA_SUCCESS) { + ma_bool32 cbResult = callback(pContext, deviceType, &deviceInfo, pUserData); + if (cbResult == MA_FALSE) { + break; + } + } + } + } + } + +done: + if (pDefaultDeviceID != NULL) { + ma_CoTaskMemFree(pContext, pDefaultDeviceID); + pDefaultDeviceID = NULL; + } + + if (pDeviceCollection != NULL) { + ma_IMMDeviceCollection_Release(pDeviceCollection); + pDeviceCollection = NULL; + } + + 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) +{ + ma_result result; + HRESULT hr; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppAudioClient != NULL); + MA_ASSERT(ppMMDevice != NULL); + + result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice); + if (result != MA_SUCCESS) { + return result; + } + + hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, pActivationParams, (void**)ppAudioClient); + if (FAILED(hr)) { + return ma_result_from_HRESULT(hr); + } + + 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) +{ + ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL; + ma_completion_handler_uwp completionHandler; + IID iid; + WCHAR* iidStr; + HRESULT hr; + ma_result result; + HRESULT activateResult; + ma_IUnknown* pActivatedInterface; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppAudioClient != NULL); + + if (pDeviceID != NULL) { + iidStr = (WCHAR*)pDeviceID->wasapi; + } else { + if (deviceType == ma_device_type_capture) { + iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE; + } else { + iid = MA_IID_DEVINTERFACE_AUDIO_RENDER; + } + + #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); + } + } + + 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; + } + + hr = ((MA_PFN_ActivateAudioInterfaceAsync)pContext->wasapi.ActivateAudioInterfaceAsync)(iidStr, &MA_IID_IAudioClient, pActivationParams, (ma_IActivateAudioInterfaceCompletionHandler*)&completionHandler, (ma_IActivateAudioInterfaceAsyncOperation**)&pAsyncOp); + 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); + } + + if (pDeviceID == NULL) { + ma_CoTaskMemFree(pContext, iidStr); + } + + /* Wait for the async operation for finish. */ + ma_completion_handler_uwp_wait(&completionHandler); + ma_completion_handler_uwp_uninit(&completionHandler); + + hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface); + 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); + } + + /* 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); + } + + if (ppActivatedInterface) { + *ppActivatedInterface = pActivatedInterface; + } else { + ma_IUnknown_Release(pActivatedInterface); + } + + return MA_SUCCESS; +} +#endif + + +/* https://docs.microsoft.com/en-us/windows/win32/api/audioclientactivationparams/ne-audioclientactivationparams-audioclient_activation_type */ +typedef enum +{ + 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); +#else + result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, pActivationParams, 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) + /* Desktop */ + HRESULT hr; + ma_IMMDeviceEnumerator* 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); + } + + ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData); + ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_capture, callback, pUserData); + + ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); +#else + /* + UWP + + The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate + over devices without using MMDevice, I'm restricting devices to defaults. + + Hint: DeviceInformation::FindAllAsync() with DeviceClass.AudioCapture/AudioRender. https://blogs.windows.com/buildingapps/2014/05/15/real-time-audio-in-windows-store-and-windows-phone-apps/ + */ + if (callback) { + ma_bool32 cbResult = MA_TRUE; + + /* Playback. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; + cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + + /* Capture. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; + cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + } +#endif + + return MA_SUCCESS; +} + +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) + ma_result result; + ma_IMMDevice* pMMDevice = NULL; + WCHAR* pDefaultDeviceID = NULL; + + result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice); + if (result != MA_SUCCESS) { + return result; + } + + /* We need the default device ID so we can set the isDefault flag in the device info. */ + pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType); + + result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_FALSE, pDeviceInfo); /* MA_FALSE = !onlySimpleInfo. */ + + if (pDefaultDeviceID != NULL) { + ma_CoTaskMemFree(pContext, pDefaultDeviceID); + pDefaultDeviceID = NULL; + } + + ma_IMMDevice_Release(pMMDevice); + + return result; +#else + ma_IAudioClient* pAudioClient; + ma_result result; + + /* UWP currently only uses default devices. */ + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + 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); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, pDeviceInfo); + + pDeviceInfo->isDefault = MA_TRUE; /* UWP only supports default devices. */ + + ma_IAudioClient_Release(pAudioClient); + return result; +#endif +} + +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); + } + #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); + } + + if (pDevice->wasapi.pAudioClientPlayback) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + } + if (pDevice->wasapi.pAudioClientCapture) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + } + + if (pDevice->wasapi.hEventPlayback) { + CloseHandle((HANDLE)pDevice->wasapi.hEventPlayback); + } + if (pDevice->wasapi.hEventCapture) { + CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + } + + return MA_SUCCESS; +} + + +typedef struct +{ + /* Input. */ + ma_format formatIn; + ma_uint32 channelsIn; + ma_uint32 sampleRateIn; + ma_channel channelMapIn[MA_MAX_CHANNELS]; + ma_uint32 periodSizeInFramesIn; + ma_uint32 periodSizeInMillisecondsIn; + ma_uint32 periodsIn; + ma_share_mode shareMode; + ma_performance_profile performanceProfile; + ma_bool32 noAutoConvertSRC; + ma_bool32 noDefaultQualitySRC; + ma_bool32 noHardwareOffloading; + ma_uint32 loopbackProcessID; + ma_bool32 loopbackProcessExclude; + + /* Output. */ + ma_IAudioClient* pAudioClient; + ma_IAudioRenderClient* pRenderClient; + ma_IAudioCaptureClient* pCaptureClient; + ma_format formatOut; + ma_uint32 channelsOut; + ma_uint32 sampleRateOut; + ma_channel channelMapOut[MA_MAX_CHANNELS]; + ma_uint32 periodSizeInFramesOut; + ma_uint32 periodsOut; + ma_bool32 usingAudioClient3; + char deviceName[256]; + ma_device_id id; +} ma_device_init_internal_data__wasapi; + +static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__wasapi* pData) +{ + HRESULT hr; + ma_result result = MA_SUCCESS; + const char* errorMsg = ""; + MA_AUDCLNT_SHAREMODE shareMode = MA_AUDCLNT_SHAREMODE_SHARED; + DWORD streamFlags = 0; + MA_REFERENCE_TIME periodDurationInMicroseconds; + ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE; + MA_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); + + /* This function is only used to initialize one device type: either playback, capture or loopback. Never full-duplex. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + usingProcessLoopback = deviceType == ma_device_type_loopback && pData->loopbackProcessID != 0 && pDeviceID == NULL; + + pData->pAudioClient = NULL; + pData->pRenderClient = NULL; + pData->pCaptureClient = NULL; + + streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) { /* <-- Exclusive streams must use the native sample rate. */ + streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; + } + if (!pData->noDefaultQualitySRC && pData->sampleRateIn != 0 && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) { + streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; + } + if (deviceType == ma_device_type_loopback) { + streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK; + } + + result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, pData->loopbackProcessID, pData->loopbackProcessExclude, &pData->pAudioClient, &pDeviceInterface); + if (result != MA_SUCCESS) { + goto done; + } + + MA_ZERO_OBJECT(&wf); + + /* Try enabling hardware offloading. */ + if (!pData->noHardwareOffloading) { + hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2); + if (SUCCEEDED(hr)) { + BOOL isHardwareOffloadingSupported = 0; + hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported); + if (SUCCEEDED(hr) && isHardwareOffloadingSupported) { + ma_AudioClientProperties clientProperties; + MA_ZERO_OBJECT(&clientProperties); + clientProperties.cbSize = sizeof(clientProperties); + clientProperties.bIsOffload = 1; + clientProperties.eCategory = MA_AudioCategory_Other; + ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties); + } + + pAudioClient2->lpVtbl->Release(pAudioClient2); + } + } + + /* 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) + /* 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; + ma_PropVariantInit(&prop); + hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop); + if (SUCCEEDED(hr)) { + MA_WAVEFORMATEX* pActualFormat = (MA_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_PropVariantClear(pContext, &prop); + } + + ma_IPropertyStore_Release(pStore); + } + #else + /* + I do not know how to query the device's native format on UWP so for now I'm just disabling support for + exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported() + until you find one that works. + + TODO: Add support for exclusive mode to UWP. + */ + hr = S_FALSE; + #endif + + if (hr == S_OK) { + shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE; + result = MA_SUCCESS; + } else { + result = MA_SHARE_MODE_NOT_SUPPORTED; + } + } 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); + 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; + } + } 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); + } + + result = MA_SUCCESS; + } + + ma_CoTaskMemFree(pContext, pNativeFormat); + + shareMode = MA_AUDCLNT_SHAREMODE_SHARED; + } + + /* Return an error if we still haven't found a format. */ + if (result != MA_SUCCESS) { + errorMsg = "[WASAPI] Failed to find best device mix format."; + goto done; + } + + /* + 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; + if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) { + wf.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE; + wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; + } + + pData->formatOut = ma_format_from_WAVEFORMATEX((MA_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 + in this case so that the caller can detect it and fall back to shared mode if desired. We should never get here if shared mode was requested, but just for + completeness we'll check for it and return MA_FORMAT_NOT_SUPPORTED. + */ + if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) { + result = MA_SHARE_MODE_NOT_SUPPORTED; + } else { + result = MA_FORMAT_NOT_SUPPORTED; + } + + errorMsg = "[WASAPI] Native format not supported."; + goto done; + } + + pData->channelsOut = wf.nChannels; + pData->sampleRateOut = wf.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); + } + + /* Period size. */ + pData->periodsOut = (pData->periodsIn != 0) ? pData->periodsIn : MA_DEFAULT_PERIODS; + pData->periodSizeInFramesOut = pData->periodSizeInFramesIn; + 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); + } else { + pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, wf.nSamplesPerSec); + } + } else { + pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.nSamplesPerSec); + } + } + + periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.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; + + /* + If the periodicity 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); + 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. */ + break; + } + + bufferDuration = bufferDuration * 2; + continue; + } + } else { + break; + } + } + + if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { + 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); + + /* 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) + 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); + } + } + } + + if (FAILED(hr)) { + /* Failed to initialize in exclusive mode. Don't fall back to shared mode - instead tell the client about it. They can reinitialize in shared mode if they want. */ + if (hr == E_ACCESSDENIED) { + errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", result = MA_ACCESS_DENIED; + } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) { + errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", result = MA_BUSY; + } else { + errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; result = ma_result_from_HRESULT(hr); + } + goto done; + } + } + + if (shareMode == MA_AUDCLNT_SHAREMODE_SHARED) { + /* + Low latency shared mode via IAudioClient3. + + NOTE + ==== + Contrary to the documentation on MSDN (https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient3-initializesharedaudiostream), the + use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM and AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY with IAudioClient3_InitializeSharedAudioStream() absolutely does not work. Using + 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); + 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; + + /* 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); + + 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 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"); + } + } 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"); + } + } else { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n"); + } + + 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 + + /* 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); + if (FAILED(hr)) { + if (hr == E_ACCESSDENIED) { + errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED; + } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) { + errorMsg = "[WASAPI] Failed to initialize device. Device in use.", result = MA_BUSY; + } else { + errorMsg = "[WASAPI] Failed to initialize device.", result = ma_result_from_HRESULT(hr); + } + + goto done; + } + } + } + + if (!wasInitializedUsingIAudioClient3) { + ma_uint32 bufferSizeInFrames = 0; + 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 { + result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pCaptureClient); + } + + /*if (FAILED(hr)) {*/ + if (result != MA_SUCCESS) { + errorMsg = "[WASAPI] Failed to get audio client service."; + goto done; + } + + + /* Grab the name of the device. */ + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + { + ma_IPropertyStore *pProperties; + hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties); + if (SUCCEEDED(hr)) { + MA_PROPVARIANT varName; + ma_PropVariantInit(&varName); + hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName); + if (SUCCEEDED(hr)) { + WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pData->deviceName, sizeof(pData->deviceName), 0, FALSE); + ma_PropVariantClear(pContext, &varName); + } + + ma_IPropertyStore_Release(pProperties); + } + } + #endif + + /* + For the WASAPI backend we need to know the actual IDs of the device in order to do automatic + 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) + { + /* Desktop */ + ma_context_get_device_id_from_MMDevice__wasapi(pContext, pDeviceInterface, &pData->id); + } + #else + { + /* UWP */ + /* TODO: Implement me. Need to figure out how to get the ID of the default device. */ + } + #endif + +done: + /* Clean up. */ +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + if (pDeviceInterface != NULL) { + ma_IMMDevice_Release(pDeviceInterface); + } +#else + if (pDeviceInterface != NULL) { + ma_IUnknown_Release(pDeviceInterface); + } +#endif + + if (result != MA_SUCCESS) { + if (pData->pRenderClient) { + ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient); + pData->pRenderClient = NULL; + } + if (pData->pCaptureClient) { + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient); + pData->pCaptureClient = NULL; + } + if (pData->pAudioClient) { + ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient); + pData->pAudioClient = NULL; + } + + if (errorMsg != NULL && errorMsg[0] != '\0') { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "%s\n", errorMsg); + } + + return result; + } else { + return MA_SUCCESS; + } +} + +static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type deviceType) +{ + ma_device_init_internal_data__wasapi data; + ma_result result; + + MA_ASSERT(pDevice != NULL); + + /* We only re-initialize the playback or capture device. Never a full-duplex device. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + + /* + Before reinitializing the device we need to free the previous audio clients. + + There's a known memory leak here. We will be calling this from the routing change callback that + is fired by WASAPI. If we attempt to release the IAudioClient we will deadlock. In my opinion + this is a bug. I'm not sure what I need to do to handle this cleanly, but I think we'll probably + need some system where we post an event, but delay the execution of it until the callback has + returned. I'm not sure how to do this reliably, however. I have set up some infrastructure for + a command thread which might be useful for this. + */ + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) { + if (pDevice->wasapi.pCaptureClient) { + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); + pDevice->wasapi.pCaptureClient = NULL; + } + + if (pDevice->wasapi.pAudioClientCapture) { + /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_capture);*/ + pDevice->wasapi.pAudioClientCapture = NULL; + } + } + + if (deviceType == ma_device_type_playback) { + if (pDevice->wasapi.pRenderClient) { + ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); + pDevice->wasapi.pRenderClient = NULL; + } + + if (pDevice->wasapi.pAudioClientPlayback) { + /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_playback);*/ + pDevice->wasapi.pAudioClientPlayback = NULL; + } + } + + + if (deviceType == ma_device_type_playback) { + data.formatIn = pDevice->playback.format; + data.channelsIn = pDevice->playback.channels; + MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap)); + data.shareMode = pDevice->playback.shareMode; + } else { + data.formatIn = pDevice->capture.format; + data.channelsIn = pDevice->capture.channels; + MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap)); + data.shareMode = pDevice->capture.shareMode; + } + + data.sampleRateIn = pDevice->sampleRate; + data.periodSizeInFramesIn = pDevice->wasapi.originalPeriodSizeInFrames; + data.periodSizeInMillisecondsIn = pDevice->wasapi.originalPeriodSizeInMilliseconds; + data.periodsIn = pDevice->wasapi.originalPeriods; + data.performanceProfile = pDevice->wasapi.originalPerformanceProfile; + 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; + } + + /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */ + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) { + pDevice->wasapi.pAudioClientCapture = data.pAudioClient; + pDevice->wasapi.pCaptureClient = data.pCaptureClient; + + pDevice->capture.internalFormat = data.formatOut; + pDevice->capture.internalChannels = data.channelsOut; + pDevice->capture.internalSampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut; + 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); + + pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); + + /* We must always have a valid ID. */ + ma_strcpy_s_WCHAR(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi); + } + + if (deviceType == ma_device_type_playback) { + pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; + pDevice->wasapi.pRenderClient = data.pRenderClient; + + pDevice->playback.internalFormat = data.formatOut; + pDevice->playback.internalChannels = data.channelsOut; + pDevice->playback.internalSampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut; + 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); + + pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); + + /* 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); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result = MA_SUCCESS; + +#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + HRESULT hr; + ma_IMMDeviceEnumerator* pDeviceEnumerator; +#endif + + 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; + + /* Exclusive mode is not allowed with loopback. */ + if (pConfig->deviceType == ma_device_type_loopback && pConfig->playback.shareMode == ma_share_mode_exclusive) { + return MA_INVALID_DEVICE_CONFIG; + } + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { + ma_device_init_internal_data__wasapi data; + data.formatIn = pDescriptorCapture->format; + data.channelsIn = pDescriptorCapture->channels; + data.sampleRateIn = pDescriptorCapture->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap)); + data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames; + data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds; + data.periodsIn = pDescriptorCapture->periodCount; + data.shareMode = pDescriptorCapture->shareMode; + data.performanceProfile = pConfig->performanceProfile; + 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) { + return result; + } + + pDevice->wasapi.pAudioClientCapture = data.pAudioClient; + pDevice->wasapi.pCaptureClient = data.pCaptureClient; + pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds; + pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; + pDevice->wasapi.originalPeriods = pDescriptorCapture->periodCount; + pDevice->wasapi.originalPerformanceProfile = pConfig->performanceProfile; + + /* + 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. */ + if (pDevice->wasapi.hEventCapture == NULL) { + result = ma_result_from_GetLastError(GetLastError()); + + if (pDevice->wasapi.pCaptureClient != NULL) { + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); + pDevice->wasapi.pCaptureClient = NULL; + } + if (pDevice->wasapi.pAudioClientCapture != NULL) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + 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; + } + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, (HANDLE)pDevice->wasapi.hEventCapture); + + pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture); + + /* We must always have a valid ID. */ + ma_strcpy_s_WCHAR(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; + pDescriptorCapture->channels = data.channelsOut; + pDescriptorCapture->sampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut; + pDescriptorCapture->periodCount = data.periodsOut; + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_device_init_internal_data__wasapi data; + data.formatIn = pDescriptorPlayback->format; + data.channelsIn = pDescriptorPlayback->channels; + data.sampleRateIn = pDescriptorPlayback->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); + data.periodSizeInFramesIn = pDescriptorPlayback->periodSizeInFrames; + data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds; + data.periodsIn = pDescriptorPlayback->periodCount; + data.shareMode = pDescriptorPlayback->shareMode; + data.performanceProfile = pConfig->performanceProfile; + 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) { + if (pConfig->deviceType == ma_device_type_duplex) { + if (pDevice->wasapi.pCaptureClient != NULL) { + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); + pDevice->wasapi.pCaptureClient = NULL; + } + if (pDevice->wasapi.pAudioClientCapture != NULL) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + pDevice->wasapi.pAudioClientCapture = NULL; + } + + CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + pDevice->wasapi.hEventCapture = NULL; + } + return result; + } + + pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; + pDevice->wasapi.pRenderClient = data.pRenderClient; + pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds; + pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; + pDevice->wasapi.originalPeriods = pDescriptorPlayback->periodCount; + pDevice->wasapi.originalPerformanceProfile = pConfig->performanceProfile; + + /* + The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled + only after the whole available space has been filled, never before. + + 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. */ + if (pDevice->wasapi.hEventPlayback == NULL) { + result = ma_result_from_GetLastError(GetLastError()); + + if (pConfig->deviceType == ma_device_type_duplex) { + if (pDevice->wasapi.pCaptureClient != NULL) { + ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient); + pDevice->wasapi.pCaptureClient = NULL; + } + if (pDevice->wasapi.pAudioClientCapture != NULL) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + pDevice->wasapi.pAudioClientCapture = NULL; + } + + CloseHandle((HANDLE)pDevice->wasapi.hEventCapture); + pDevice->wasapi.hEventCapture = NULL; + } + + if (pDevice->wasapi.pRenderClient != NULL) { + ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient); + pDevice->wasapi.pRenderClient = NULL; + } + if (pDevice->wasapi.pAudioClientPlayback != NULL) { + ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + 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; + } + ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, (HANDLE)pDevice->wasapi.hEventPlayback); + + pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; + ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback); + + /* 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); + + /* The descriptor needs to be updated with actual values. */ + pDescriptorPlayback->format = data.formatOut; + pDescriptorPlayback->channels = data.channelsOut; + pDescriptorPlayback->sampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut; + pDescriptorPlayback->periodCount = data.periodsOut; + } + + /* + We need to register a notification client to detect when the device has been disabled, unplugged or re-routed (when the default device changes). When + 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) + 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) { + pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE; + } + if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) { + pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE; + } + } + + ma_mutex_init(&pDevice->wasapi.rerouteLock); + + 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); + } + + pDevice->wasapi.notificationClient.lpVtbl = (void*)&g_maNotificationCientVtbl; + pDevice->wasapi.notificationClient.counter = 1; + pDevice->wasapi.notificationClient.pDevice = pDevice; + + hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient); + if (SUCCEEDED(hr)) { + pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator; + } else { + /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */ + ma_IMMDeviceEnumerator_Release(pDeviceEnumerator); + } +#endif + + ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); + ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + + return MA_SUCCESS; +} + +static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount) +{ + ma_uint32 paddingFramesCount; + HRESULT hr; + ma_share_mode shareMode; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pFrameCount != NULL); + + *pFrameCount = 0; + + if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) { + return MA_INVALID_OPERATION; + } + + /* + I've had a report that GetCurrentPadding() is returning a frame count of 0 which is preventing + higher level function calls from doing anything because it thinks nothing is available. I have + taken a look at the documentation and it looks like this is unnecessary in exclusive mode. + + From Microsoft's documentation: + + For an exclusive-mode rendering or capture stream that was initialized with the + AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag, the client typically has no use for the padding + value reported by GetCurrentPadding. Instead, the client accesses an entire buffer during + each processing pass. + + Considering this, I'm going to skip GetCurrentPadding() for exclusive mode and just report the + entire buffer. This depends on the caller making sure they wait on the event handler. + */ + shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode; + if (shareMode == ma_share_mode_shared) { + /* Shared mode. */ + hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount); + if (FAILED(hr)) { + return ma_result_from_HRESULT(hr); + } + + if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount; + } else { + *pFrameCount = paddingFramesCount; + } + } else { + /* Exclusive mode. */ + if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback; + } else { + *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesCapture; + } + } + + return MA_SUCCESS; +} + + +static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType) +{ + ma_result result; + + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== CHANGING DEVICE ===\n"); + + 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"); + 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); + 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); + } + + /* 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); + } + + 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); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__wasapi(ma_device* pDevice) +{ + ma_result result; + + 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); + + return result; +} + + +#ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS +#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) +{ + ma_result result = MA_SUCCESS; + ma_uint32 totalFramesProcessed = 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. + */ + + /* 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 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; + } + + /* 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 + ); + + totalFramesProcessed += framesToProcessNow; + pDevice->wasapi.mappedBufferCaptureLen -= framesToProcessNow; + + /* 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; + + /* 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); + } + } + } + #endif + + /* Overrun detection. */ + if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { + /* Glitched. Probably due to an overrun. */ + + /* + 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); + 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; + + 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"); + } + } + + 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); + } + + break; + } + } + + /* 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; + } + } + } + + continue; + } else { + if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || hr == MA_AUDCLNT_E_BUFFER_ERROR) { + /* + 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. + */ + + /* Experiment: Use a shorter timeout for loopback mode. */ + DWORD timeoutInMilliseconds = MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS; + if (pDevice->type == ma_device_type_loopback) { + timeoutInMilliseconds = 10; + } + + 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); + break; + } + } + } + } + + /* + 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; + } + } + } + } + + if (pFramesWritten != NULL) { + *pFramesWritten = totalFramesProcessed; + } + + return result; +} + +static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + SetEvent((HANDLE)pDevice->wasapi.hEventCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + SetEvent((HANDLE)pDevice->wasapi.hEventPlayback); + } + + return MA_SUCCESS; +} + + +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); + + 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; + } + + #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; +} + +static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + ma_result result = MA_SUCCESS; + + MA_ASSERT(pContext != NULL); + + (void)pConfig; + +#ifdef MA_WIN32_DESKTOP + /* + WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven + exclusive mode does not work until SP1. + + Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a link error. + */ + { + ma_OSVERSIONINFOEXW osvi; + ma_handle kernel32DLL; + ma_PFNVerifyVersionInfoW _VerifyVersionInfoW; + ma_PFNVerSetConditionMask _VerSetConditionMask; + + kernel32DLL = ma_dlopen(ma_context_get_log(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"); + if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) { + ma_dlclose(ma_context_get_log(pContext), kernel32DLL); + return MA_NO_BACKEND; + } + + MA_ZERO_OBJECT(&osvi); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = ((MA_WIN32_WINNT_VISTA >> 8) & 0xFF); + osvi.dwMinorVersion = ((MA_WIN32_WINNT_VISTA >> 0) & 0xFF); + osvi.wServicePackMajor = 1; + if (_VerifyVersionInfoW(&osvi, MA_VER_MAJORVERSION | MA_VER_MINORVERSION | MA_VER_SERVICEPACKMAJOR, _VerSetConditionMask(_VerSetConditionMask(_VerSetConditionMask(0, MA_VER_MAJORVERSION, MA_VER_GREATER_EQUAL), MA_VER_MINORVERSION, MA_VER_GREATER_EQUAL), MA_VER_SERVICEPACKMAJOR, MA_VER_GREATER_EQUAL))) { + result = MA_SUCCESS; + } else { + result = MA_NO_BACKEND; + } + + ma_dlclose(ma_context_get_log(pContext), kernel32DLL); + } +#endif + + if (result != MA_SUCCESS) { + return result; + } + + 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 + situations: + + 1) When calling ma_device_uninit() from a different thread to ma_device_init(); and + 2) When uninitializing and reinitializing the internal IAudioClient object in response to + automatic stream routing. + + We could define ma_device_uninit() such that it must be called on the same thread as + ma_device_init(). We could also just not release the IAudioClient when performing automatic + stream routing to avoid the deadlock. Neither of these are acceptable solutions in my view so + we're going to have to work around this with a worker thread. This is not ideal, but I can't + think of a better way to do this. + + More information about this can be found here: + + https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudiorenderclient + + Note this section: + + When releasing an IAudioRenderClient interface instance, the client must call the interface's + Release method from the same thread as the call to IAudioClient::GetService that created the + object. + */ + { + result = ma_mutex_init(&pContext->wasapi.commandLock); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_semaphore_init(0, &pContext->wasapi.commandSem); + if (result != MA_SUCCESS) { + ma_mutex_uninit(&pContext->wasapi.commandLock); + return result; + } + + result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext, &pContext->allocationCallbacks); + if (result != MA_SUCCESS) { + ma_semaphore_uninit(&pContext->wasapi.commandSem); + ma_mutex_uninit(&pContext->wasapi.commandLock); + return result; + } + } + + + pCallbacks->onContextInit = ma_context_init__wasapi; + pCallbacks->onContextUninit = ma_context_uninit__wasapi; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__wasapi; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__wasapi; + pCallbacks->onDeviceInit = ma_device_init__wasapi; + 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->onDeviceDataLoopWakeup = ma_device_data_loop_wakeup__wasapi; + + return MA_SUCCESS; +} +#endif + +/****************************************************************************** + +DirectSound Backend + +******************************************************************************/ +#ifdef MA_HAS_DSOUND +/*#include */ + +/*static const GUID MA_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}};*/ + +/* miniaudio only uses priority or exclusive modes. */ +#define MA_DSSCL_NORMAL 1 +#define MA_DSSCL_PRIORITY 2 +#define MA_DSSCL_EXCLUSIVE 3 +#define MA_DSSCL_WRITEPRIMARY 4 + +#define MA_DSCAPS_PRIMARYMONO 0x00000001 +#define MA_DSCAPS_PRIMARYSTEREO 0x00000002 +#define MA_DSCAPS_PRIMARY8BIT 0x00000004 +#define MA_DSCAPS_PRIMARY16BIT 0x00000008 +#define MA_DSCAPS_CONTINUOUSRATE 0x00000010 +#define MA_DSCAPS_EMULDRIVER 0x00000020 +#define MA_DSCAPS_CERTIFIED 0x00000040 +#define MA_DSCAPS_SECONDARYMONO 0x00000100 +#define MA_DSCAPS_SECONDARYSTEREO 0x00000200 +#define MA_DSCAPS_SECONDARY8BIT 0x00000400 +#define MA_DSCAPS_SECONDARY16BIT 0x00000800 + +#define MA_DSBCAPS_PRIMARYBUFFER 0x00000001 +#define MA_DSBCAPS_STATIC 0x00000002 +#define MA_DSBCAPS_LOCHARDWARE 0x00000004 +#define MA_DSBCAPS_LOCSOFTWARE 0x00000008 +#define MA_DSBCAPS_CTRL3D 0x00000010 +#define MA_DSBCAPS_CTRLFREQUENCY 0x00000020 +#define MA_DSBCAPS_CTRLPAN 0x00000040 +#define MA_DSBCAPS_CTRLVOLUME 0x00000080 +#define MA_DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 +#define MA_DSBCAPS_CTRLFX 0x00000200 +#define MA_DSBCAPS_STICKYFOCUS 0x00004000 +#define MA_DSBCAPS_GLOBALFOCUS 0x00008000 +#define MA_DSBCAPS_GETCURRENTPOSITION2 0x00010000 +#define MA_DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 +#define MA_DSBCAPS_LOCDEFER 0x00040000 +#define MA_DSBCAPS_TRUEPLAYPOSITION 0x00080000 + +#define MA_DSBPLAY_LOOPING 0x00000001 +#define MA_DSBPLAY_LOCHARDWARE 0x00000002 +#define MA_DSBPLAY_LOCSOFTWARE 0x00000004 +#define MA_DSBPLAY_TERMINATEBY_TIME 0x00000008 +#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 +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + MA_WAVEFORMATEX* lpwfxFormat; + GUID guid3DAlgorithm; +} MA_DSBUFFERDESC; + +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + MA_WAVEFORMATEX* lpwfxFormat; + DWORD dwFXCount; + void* lpDSCFXDesc; /* <-- miniaudio doesn't use this, so set to void*. */ +} MA_DSCBUFFERDESC; + +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwMinSecondarySampleRate; + DWORD dwMaxSecondarySampleRate; + DWORD dwPrimaryBuffers; + DWORD dwMaxHwMixingAllBuffers; + DWORD dwMaxHwMixingStaticBuffers; + DWORD dwMaxHwMixingStreamingBuffers; + DWORD dwFreeHwMixingAllBuffers; + DWORD dwFreeHwMixingStaticBuffers; + DWORD dwFreeHwMixingStreamingBuffers; + DWORD dwMaxHw3DAllBuffers; + DWORD dwMaxHw3DStaticBuffers; + DWORD dwMaxHw3DStreamingBuffers; + DWORD dwFreeHw3DAllBuffers; + DWORD dwFreeHw3DStaticBuffers; + DWORD dwFreeHw3DStreamingBuffers; + DWORD dwTotalHwMemBytes; + DWORD dwFreeHwMemBytes; + DWORD dwMaxContigFreeHwMemBytes; + DWORD dwUnlockTransferRateHwBuffers; + DWORD dwPlayCpuOverheadSwBuffers; + DWORD dwReserved1; + DWORD dwReserved2; +} MA_DSCAPS; + +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwUnlockTransferRate; + DWORD dwPlayCpuOverhead; +} MA_DSBCAPS; + +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFormats; + DWORD dwChannels; +} MA_DSCCAPS; + +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; +} MA_DSCBCAPS; + +typedef struct +{ + DWORD dwOffset; + HANDLE hEventNotify; +} MA_DSBPOSITIONNOTIFY; + +typedef struct ma_IDirectSound ma_IDirectSound; +typedef struct ma_IDirectSoundBuffer ma_IDirectSoundBuffer; +typedef struct ma_IDirectSoundCapture ma_IDirectSoundCapture; +typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer; +typedef struct ma_IDirectSoundNotify ma_IDirectSoundNotify; + + +/* +COM objects. The way these work is that you have a vtable (a list of function pointers, kind of +like how C++ works internally), and then you have a structure with a single member, which is a +pointer to the vtable. The vtable is where the methods of the object are defined. Methods need +to be in a specific order, and parent classes need to have their methods declared first. +*/ + +/* IDirectSound */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSound* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSound* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSound* pThis); + + /* IDirectSound */ + HRESULT (STDMETHODCALLTYPE * CreateSoundBuffer) (ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter); + HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps); + HRESULT (STDMETHODCALLTYPE * DuplicateSoundBuffer)(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate); + HRESULT (STDMETHODCALLTYPE * SetCooperativeLevel) (ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel); + HRESULT (STDMETHODCALLTYPE * Compact) (ma_IDirectSound* pThis); + HRESULT (STDMETHODCALLTYPE * GetSpeakerConfig) (ma_IDirectSound* pThis, DWORD* pSpeakerConfig); + HRESULT (STDMETHODCALLTYPE * SetSpeakerConfig) (ma_IDirectSound* pThis, DWORD dwSpeakerConfig); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSound* pThis, const GUID* pGuidDevice); +} ma_IDirectSoundVtbl; +struct ma_IDirectSound +{ + ma_IDirectSoundVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSound_AddRef(ma_IDirectSound* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IDirectSound_Release(ma_IDirectSound* pThis) { return pThis->lpVtbl->Release(pThis); } +static MA_INLINE HRESULT ma_IDirectSound_CreateSoundBuffer(ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateSoundBuffer(pThis, pDSBufferDesc, ppDSBuffer, pUnkOuter); } +static MA_INLINE HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCaps); } +static MA_INLINE HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate) { return pThis->lpVtbl->DuplicateSoundBuffer(pThis, pDSBufferOriginal, ppDSBufferDuplicate); } +static MA_INLINE HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel) { return pThis->lpVtbl->SetCooperativeLevel(pThis, hwnd, dwLevel); } +static MA_INLINE HRESULT ma_IDirectSound_Compact(ma_IDirectSound* pThis) { return pThis->lpVtbl->Compact(pThis); } +static MA_INLINE HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound* pThis, DWORD* pSpeakerConfig) { return pThis->lpVtbl->GetSpeakerConfig(pThis, pSpeakerConfig); } +static MA_INLINE HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound* pThis, DWORD dwSpeakerConfig) { return pThis->lpVtbl->SetSpeakerConfig(pThis, dwSpeakerConfig); } +static MA_INLINE HRESULT ma_IDirectSound_Initialize(ma_IDirectSound* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); } + + +/* IDirectSoundBuffer */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundBuffer* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundBuffer* pThis); + + /* 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 * GetVolume) (ma_IDirectSoundBuffer* pThis, LONG* pVolume); + HRESULT (STDMETHODCALLTYPE * GetPan) (ma_IDirectSoundBuffer* pThis, LONG* pPan); + HRESULT (STDMETHODCALLTYPE * GetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency); + HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundBuffer* pThis, DWORD* pStatus); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc); + 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 * SetVolume) (ma_IDirectSoundBuffer* pThis, LONG volume); + HRESULT (STDMETHODCALLTYPE * SetPan) (ma_IDirectSoundBuffer* pThis, LONG pan); + HRESULT (STDMETHODCALLTYPE * SetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency); + HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundBuffer* pThis); + HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2); + HRESULT (STDMETHODCALLTYPE * Restore) (ma_IDirectSoundBuffer* pThis); +} ma_IDirectSoundBufferVtbl; +struct ma_IDirectSoundBuffer +{ + ma_IDirectSoundBufferVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); } +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_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); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSound, pDSBufferDesc); } +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_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); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_Unlock(ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); } +static MA_INLINE HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Restore(pThis); } + + +/* IDirectSoundCapture */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCapture* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCapture* pThis); + + /* IDirectSoundCapture */ + HRESULT (STDMETHODCALLTYPE * CreateCaptureBuffer)(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter); + HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps); + HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice); +} ma_IDirectSoundCaptureVtbl; +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_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); } + + +/* IDirectSoundCaptureBuffer */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCaptureBuffer* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCaptureBuffer* pThis); + + /* 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 * 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); + HRESULT (STDMETHODCALLTYPE * Start) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags); + HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundCaptureBuffer* pThis); + HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2); +} ma_IDirectSoundCaptureBufferVtbl; +struct ma_IDirectSoundCaptureBuffer +{ + ma_IDirectSoundCaptureBufferVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); } +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_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); } +static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags) { return pThis->lpVtbl->Start(pThis, dwFlags); } +static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); } +static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Unlock(ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); } + + +/* IDirectSoundNotify */ +typedef struct +{ + /* IUnknown */ + HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject); + ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundNotify* pThis); + ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundNotify* pThis); + + /* IDirectSoundNotify */ + HRESULT (STDMETHODCALLTYPE * SetNotificationPositions)(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies); +} ma_IDirectSoundNotifyVtbl; +struct ma_IDirectSoundNotify +{ + ma_IDirectSoundNotifyVtbl* lpVtbl; +}; +static MA_INLINE HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); } +static MA_INLINE ULONG ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->AddRef(pThis); } +static MA_INLINE ULONG ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->Release(pThis); } +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); + +static ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax) +{ + /* Normalize the range in case we were given something stupid. */ + if (sampleRateMin < (ma_uint32)ma_standard_sample_rate_min) { + sampleRateMin = (ma_uint32)ma_standard_sample_rate_min; + } + if (sampleRateMax > (ma_uint32)ma_standard_sample_rate_max) { + sampleRateMax = (ma_uint32)ma_standard_sample_rate_max; + } + if (sampleRateMin > sampleRateMax) { + sampleRateMin = sampleRateMax; + } + + if (sampleRateMin == sampleRateMax) { + return sampleRateMax; + } else { + size_t iStandardRate; + for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) { + ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate]; + if (standardRate >= sampleRateMin && standardRate <= sampleRateMax) { + return standardRate; + } + } + } + + /* Should never get here. */ + MA_ASSERT(MA_FALSE); + return 0; +} + +/* +Retrieves the channel count and channel map for the given speaker configuration. If the speaker configuration is unknown, +the channel count and channel map will be left unmodified. +*/ +static void ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pChannelsOut, DWORD* pChannelMapOut) +{ + WORD channels; + DWORD channelMap; + + channels = 0; + if (pChannelsOut != NULL) { + channels = *pChannelsOut; + } + + channelMap = 0; + if (pChannelMapOut != NULL) { + channelMap = *pChannelMapOut; + } + + /* + The speaker configuration is a combination of speaker config and speaker geometry. The lower 8 bits is what we care about. The upper + 16 bits is for the geometry. + */ + switch ((BYTE)(speakerConfig)) { + case 1 /*DSSPEAKER_HEADPHONE*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; + case 2 /*DSSPEAKER_MONO*/: channels = 1; channelMap = SPEAKER_FRONT_CENTER; break; + case 3 /*DSSPEAKER_QUAD*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; + case 4 /*DSSPEAKER_STEREO*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break; + case 5 /*DSSPEAKER_SURROUND*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER; break; + case 6 /*DSSPEAKER_5POINT1_BACK*/ /*DSSPEAKER_5POINT1*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break; + case 7 /*DSSPEAKER_7POINT1_WIDE*/ /*DSSPEAKER_7POINT1*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; break; + case 8 /*DSSPEAKER_7POINT1_SURROUND*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; + case 9 /*DSSPEAKER_5POINT1_SURROUND*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; + default: break; + } + + if (pChannelsOut != NULL) { + *pChannelsOut = channels; + } + + if (pChannelMapOut != NULL) { + *pChannelMapOut = channelMap; + } +} + + +static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSound** ppDirectSound) +{ + ma_IDirectSound* pDirectSound; + HWND hWnd; + HRESULT hr; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppDirectSound != NULL); + + *ppDirectSound = NULL; + 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; + } + + /* 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)(); + } + } + + 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); + } + + *ppDirectSound = pDirectSound; + return MA_SUCCESS; +} + +static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSoundCapture** ppDirectSoundCapture) +{ + ma_IDirectSoundCapture* pDirectSoundCapture; + HRESULT hr; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppDirectSoundCapture != NULL); + + /* DirectSound does not support exclusive mode for capture. */ + if (shareMode == ma_share_mode_exclusive) { + return MA_SHARE_MODE_NOT_SUPPORTED; + } + + *ppDirectSoundCapture = NULL; + pDirectSoundCapture = NULL; + + 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); + } + + *ppDirectSoundCapture = pDirectSoundCapture; + return MA_SUCCESS; +} + +static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context* pContext, ma_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate) +{ + HRESULT hr; + MA_DSCCAPS caps; + WORD bitsPerSample; + DWORD sampleRate; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDirectSoundCapture != NULL); + + if (pChannels) { + *pChannels = 0; + } + if (pBitsPerSample) { + *pBitsPerSample = 0; + } + if (pSampleRate) { + *pSampleRate = 0; + } + + MA_ZERO_OBJECT(&caps); + 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); + } + + if (pChannels) { + *pChannels = (WORD)caps.dwChannels; + } + + /* The device can support multiple formats. We just go through the different formats in order of priority and pick the first one. This the same type of system as the WinMM backend. */ + bitsPerSample = 16; + sampleRate = 48000; + + if (caps.dwChannels == 1) { + if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) { + sampleRate = 48000; + } else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) { + sampleRate = 44100; + } else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) { + sampleRate = 22050; + } else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) { + sampleRate = 11025; + } else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 8; + if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) { + sampleRate = 48000; + } else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) { + sampleRate = 44100; + } else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) { + sampleRate = 22050; + } else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) { + sampleRate = 11025; + } else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */ + } + } + } else if (caps.dwChannels == 2) { + if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) { + sampleRate = 48000; + } else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) { + sampleRate = 44100; + } else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) { + sampleRate = 22050; + } else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) { + sampleRate = 11025; + } else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 8; + if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) { + sampleRate = 48000; + } else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) { + sampleRate = 44100; + } else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) { + sampleRate = 22050; + } else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) { + sampleRate = 11025; + } else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */ + } + } + } + + if (pBitsPerSample) { + *pBitsPerSample = bitsPerSample; + } + if (pSampleRate) { + *pSampleRate = sampleRate; + } + + return MA_SUCCESS; +} + + +typedef struct +{ + ma_context* pContext; + ma_device_type deviceType; + ma_enum_devices_callback_proc callback; + void* pUserData; + 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) +{ + ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext; + ma_device_info deviceInfo; + + (void)lpcstrModule; + + MA_ZERO_OBJECT(&deviceInfo); + + /* ID. */ + if (lpGuid != NULL) { + MA_COPY_MEMORY(deviceInfo.id.dsound, lpGuid, 16); + } else { + MA_ZERO_MEMORY(deviceInfo.id.dsound, 16); + deviceInfo.isDefault = MA_TRUE; + } + + /* Name / Description */ + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), lpcstrDescription, (size_t)-1); + + + /* 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); + if (pData->terminated) { + return FALSE; /* Stop enumeration. */ + } else { + return TRUE; /* Continue enumeration. */ + } +} + +static ma_result ma_context_enumerate_devices__dsound(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_context_enumerate_devices_callback_data__dsound data; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + data.pContext = pContext; + data.callback = callback; + data.pUserData = pUserData; + data.terminated = MA_FALSE; + + /* Playback. */ + if (!data.terminated) { + data.deviceType = ma_device_type_playback; + ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data); + } + + /* Capture. */ + if (!data.terminated) { + data.deviceType = ma_device_type_capture; + ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data); + } + + return MA_SUCCESS; +} + + +typedef struct +{ + const ma_device_id* pDeviceID; + ma_device_info* pDeviceInfo; + 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) +{ + ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext; + MA_ASSERT(pData != NULL); + + if ((pData->pDeviceID == NULL || ma_is_guid_null(pData->pDeviceID->dsound)) && (lpGuid == NULL || ma_is_guid_null(lpGuid))) { + /* Default device. */ + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1); + pData->pDeviceInfo->isDefault = MA_TRUE; + pData->found = MA_TRUE; + return FALSE; /* Stop enumeration. */ + } else { + /* Not the default device. */ + if (lpGuid != NULL && pData->pDeviceID != NULL) { + if (memcmp(pData->pDeviceID->dsound, lpGuid, sizeof(pData->pDeviceID->dsound)) == 0) { + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1); + pData->found = MA_TRUE; + return FALSE; /* Stop enumeration. */ + } + } + } + + (void)lpcstrModule; + return TRUE; +} + +static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_result result; + HRESULT hr; + + if (pDeviceID != NULL) { + ma_context_get_device_info_callback_data__dsound data; + + /* ID. */ + MA_COPY_MEMORY(pDeviceInfo->id.dsound, pDeviceID->dsound, 16); + + /* Name / Description. This is retrieved by enumerating over each device until we find that one that matches the input ID. */ + data.pDeviceID = pDeviceID; + data.pDeviceInfo = pDeviceInfo; + data.found = MA_FALSE; + if (deviceType == ma_device_type_playback) { + ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound, &data); + } else { + ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound, &data); + } + + if (!data.found) { + return MA_NO_DEVICE; + } + } else { + /* I don't think there's a way to get the name of the default device with DirectSound. In this case we just need to use defaults. */ + + /* ID */ + MA_ZERO_MEMORY(pDeviceInfo->id.dsound, 16); + + /* Name / Description */ + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + + pDeviceInfo->isDefault = MA_TRUE; + } + + /* Retrieving detailed information is slightly different depending on the device type. */ + if (deviceType == ma_device_type_playback) { + /* Playback. */ + ma_IDirectSound* pDirectSound; + MA_DSCAPS caps; + WORD channels; + + result = ma_context_create_IDirectSound__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSound); + if (result != MA_SUCCESS) { + return result; + } + + MA_ZERO_OBJECT(&caps); + 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); + } + + + /* Channels. Only a single channel count is reported for DirectSound. */ + if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) { + /* It supports at least stereo, but could support more. */ + DWORD speakerConfig; + + channels = 2; + + /* Look at the speaker configuration to get a better idea on the channel count. */ + hr = ma_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig); + if (SUCCEEDED(hr)) { + ma_get_channels_from_speaker_config__dsound(speakerConfig, &channels, NULL); + } + } else { + /* It does not support stereo, which means we are stuck with mono. */ + channels = 1; + } + + + /* + In DirectSound, our native formats are centered around sample rates. All formats are supported, and we're only reporting a single channel + count. However, DirectSound can report a range of supported sample rates. We're only going to include standard rates known by miniaudio + in order to keep the size of this within reason. + */ + if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) { + /* Multiple sample rates are supported. We'll report in order of our preferred sample rates. */ + size_t iStandardSampleRate; + for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) { + ma_uint32 sampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate]; + if (sampleRate >= caps.dwMinSecondarySampleRate && sampleRate <= caps.dwMaxSecondarySampleRate) { + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = ma_format_unknown; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = 0; + pDeviceInfo->nativeDataFormatCount += 1; + } + } + } else { + /* Only a single sample rate is supported. */ + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = ma_format_unknown; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = caps.dwMaxSecondarySampleRate; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = 0; + pDeviceInfo->nativeDataFormatCount += 1; + } + + ma_IDirectSound_Release(pDirectSound); + } else { + /* + Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture + devices can support a number of different formats, but for simplicity and consistency with ma_device_init() I'm just + reporting the best format. + */ + ma_IDirectSoundCapture* pDirectSoundCapture; + WORD channels; + WORD bitsPerSample; + DWORD sampleRate; + + result = ma_context_create_IDirectSoundCapture__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSoundCapture); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate); + if (result != MA_SUCCESS) { + ma_IDirectSoundCapture_Release(pDirectSoundCapture); + return result; + } + + ma_IDirectSoundCapture_Release(pDirectSoundCapture); + + /* 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; + } else if (bitsPerSample == 16) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s16; + } else if (bitsPerSample == 24) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s24; + } else if (bitsPerSample == 32) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s32; + } else { + return MA_FORMAT_NOT_SUPPORTED; + } + + pDeviceInfo->nativeDataFormats[0].channels = channels; + pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[0].flags = 0; + pDeviceInfo->nativeDataFormatCount = 1; + } + + return MA_SUCCESS; +} + + + +static ma_result ma_device_uninit__dsound(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->dsound.pCaptureBuffer != NULL) { + ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); + } + if (pDevice->dsound.pCapture != NULL) { + ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)pDevice->dsound.pCapture); + } + + if (pDevice->dsound.pPlaybackBuffer != NULL) { + ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer); + } + if (pDevice->dsound.pPlaybackPrimaryBuffer != NULL) { + ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer); + } + if (pDevice->dsound.pPlayback != NULL) { + ma_IDirectSound_Release((ma_IDirectSound*)pDevice->dsound.pPlayback); + } + + 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) +{ + GUID subformat; + + if (format == ma_format_unknown) { + format = MA_DEFAULT_FORMAT; + } + + if (channels == 0) { + channels = MA_DEFAULT_CHANNELS; + } + + if (sampleRate == 0) { + sampleRate = MA_DEFAULT_SAMPLE_RATE; + } + + switch (format) + { + case ma_format_u8: + case ma_format_s16: + case ma_format_s24: + /*case ma_format_s24_32:*/ + case ma_format_s32: + { + subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM; + } break; + + case ma_format_f32: + { + subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } break; + + default: + return MA_FORMAT_NOT_SUPPORTED; + } + + 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->dwChannelMask = ma_channel_map_to_channel_mask__win32(pChannelMap, channels); + pWF->SubFormat = subformat; + + return MA_SUCCESS; +} + +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); + ma_uint32 periodSizeInFrames; + + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile); + if (periodSizeInFrames < minPeriodSizeInFrames) { + periodSizeInFrames = minPeriodSizeInFrames; + } + + return periodSizeInFrames; +} + +static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + HRESULT hr; + + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->dsound); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* + 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 + full-duplex mode. + */ + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + MA_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; + + result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &wf); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_context_create_IDirectSoundCapture__dsound(pDevice->pContext, pDescriptorCapture->shareMode, pDescriptorCapture->pDeviceID, (ma_IDirectSoundCapture**)&pDevice->dsound.pCapture); + if (result != MA_SUCCESS) { + ma_device_uninit__dsound(pDevice); + return result; + } + + result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pDevice->pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.nChannels, &wf.wBitsPerSample, &wf.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.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); + 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; + 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); + } + + /* 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); + 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); + } + + /* 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; + + /* Get the native channel map based on the channel mask. */ + if (pActualFormat->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); + } + + /* + After getting the actual format the size of the buffer in frames may have actually changed. However, we want this to be as close to what the + user has asked for as possible, so let's go ahead and release the old capture buffer and create a new one in this case. + */ + if (periodSizeInFrames != (descDS.dwBufferBytes / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / periodCount)) { + descDS.dwBufferBytes = periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * periodCount; + ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer); + + 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); + } + } + + /* DirectSound should give us a buffer exactly the size we asked for. */ + pDescriptorCapture->periodSizeInFrames = periodSizeInFrames; + pDescriptorCapture->periodCount = periodCount; + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + MA_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; + 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) { + return result; + } + + result = ma_context_create_IDirectSound__dsound(pDevice->pContext, pDescriptorPlayback->shareMode, pDescriptorPlayback->pDeviceID, (ma_IDirectSound**)&pDevice->dsound.pPlayback); + if (result != MA_SUCCESS) { + ma_device_uninit__dsound(pDevice); + return result; + } + + MA_ZERO_OBJECT(&descDSPrimary); + descDSPrimary.dwSize = sizeof(MA_DSBUFFERDESC); + descDSPrimary.dwFlags = MA_DSBCAPS_PRIMARYBUFFER | MA_DSBCAPS_CTRLVOLUME; + 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); + } + + + /* We may want to make some adjustments to the format if we are using defaults. */ + MA_ZERO_OBJECT(&caps); + caps.dwSize = sizeof(caps); + 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; + } + + if (pDescriptorPlayback->channels == 0) { + wf.nChannels = nativeChannelCount; + wf.dwChannelMask = nativeChannelMask; + } + + 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); + } else { + wf.nSamplesPerSec = caps.dwMaxSecondarySampleRate; + } + } + + wf.nBlockAlign = (WORD)(wf.nChannels * wf.wBitsPerSample / 8); + wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; + + /* + From MSDN: + + The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest + 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); + 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); + } + } + + /* 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); + 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); + } + + /* 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; + + /* Get the internal channel map based on the channel mask. */ + if (pActualFormat->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); + } + + /* The size of the buffer must be a clean multiple of the period count. */ + periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); + periodCount = (pDescriptorPlayback->periodCount > 0) ? pDescriptorPlayback->periodCount : MA_DEFAULT_PERIODS; + + /* + Meaning of dwFlags (from MSDN): + + DSBCAPS_CTRLPOSITIONNOTIFY + The buffer has position notification capability. + + DSBCAPS_GLOBALFOCUS + With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to + another application, even if the new application uses DirectSound. + + DSBCAPS_GETCURRENTPOSITION2 + In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated + sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the + application can get a more accurate play cursor. + */ + MA_ZERO_OBJECT(&descDS); + 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; + 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); + } + + /* DirectSound should give us a buffer exactly the size we asked for. */ + pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames; + pDescriptorPlayback->periodCount = periodCount; + } + + return MA_SUCCESS; +} + + +static ma_result ma_device_data_loop__dsound(ma_device* pDevice) +{ + ma_result result = MA_SUCCESS; + ma_uint32 bpfDeviceCapture = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + ma_uint32 bpfDevicePlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + HRESULT hr; + DWORD lockOffsetInBytesCapture; + DWORD lockSizeInBytesCapture; + DWORD mappedSizeInBytesCapture; + DWORD mappedDeviceFramesProcessedCapture; + void* pMappedDeviceBufferCapture; + DWORD lockOffsetInBytesPlayback; + DWORD lockSizeInBytesPlayback; + DWORD mappedSizeInBytesPlayback; + void* pMappedDeviceBufferPlayback; + DWORD prevReadCursorInBytesCapture = 0; + DWORD prevPlayCursorInBytesPlayback = 0; + ma_bool32 physicalPlayCursorLoopFlagPlayback = 0; + DWORD virtualWriteCursorInBytesPlayback = 0; + ma_bool32 virtualWriteCursorLoopFlagPlayback = 0; + 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); + } + } + + while (ma_device_get_state(pDevice) == ma_device_state_started) { + switch (pDevice->type) + { + case ma_device_type_duplex: + { + DWORD physicalCaptureCursorInBytes; + DWORD physicalReadCursorInBytes; + hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes); + if (FAILED(hr)) { + return ma_result_from_HRESULT(hr); + } + + /* If nothing is available we just sleep for a bit and return from this iteration. */ + if (physicalReadCursorInBytes == prevReadCursorInBytesCapture) { + ma_sleep(waitTimeInMilliseconds); + continue; /* Nothing is available in the capture buffer. */ + } + + /* + The current position has moved. We need to map all of the captured samples and write them to the playback device, making sure + we don't return until every frame has been copied over. + */ + if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) { + /* The capture position has not looped. This is the simple case. */ + lockOffsetInBytesCapture = prevReadCursorInBytesCapture; + lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture); + } else { + /* + The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything, + do it again from the start. + */ + if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) { + /* Lock up to the end of the buffer. */ + lockOffsetInBytesCapture = prevReadCursorInBytesCapture; + lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture; + } else { + /* Lock starting from the start of the buffer. */ + lockOffsetInBytesCapture = 0; + lockSizeInBytesCapture = physicalReadCursorInBytes; + } + } + + if (lockSizeInBytesCapture == 0) { + ma_sleep(waitTimeInMilliseconds); + continue; /* Nothing is available in the capture buffer. */ + } + + 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); + } + + + /* At this point we have some input data that we need to output. We do not return until every mapped frame of the input data is written to the playback device. */ + mappedDeviceFramesProcessedCapture = 0; + + for (;;) { /* Keep writing to the playback device. */ + ma_uint8 inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); + ma_uint8 outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); + ma_uint32 outputFramesInClientFormatCount; + ma_uint32 outputFramesInClientFormatConsumed = 0; + ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap); + ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture; + void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture); + + result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess); + if (result != MA_SUCCESS) { + break; + } + + outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess; + mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess; + + ma_device__handle_data_callback(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 (;;) { + ma_uint32 framesWrittenThisIteration; + DWORD physicalPlayCursorInBytes; + DWORD physicalWriteCursorInBytes; + DWORD availableBytesPlayback; + DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */ + + /* We need the physical play and write cursors. */ + if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) { + break; + } + + if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { + physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; + } + prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; + + /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */ + if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { + /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { + availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback; + 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); + availableBytesPlayback = 0; + } + } else { + /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { + 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); + availableBytesPlayback = 0; + } + } + + /* 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. */ + if (!isPlaybackDeviceStarted) { + 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); + } + isPlaybackDeviceStarted = MA_TRUE; + } else { + ma_sleep(waitTimeInMilliseconds); + continue; + } + } + + + /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */ + lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback; + if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { + /* Same loop iteration. Go up to the end of the buffer. */ + lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback; + } else { + /* Different loop iterations. Go up to the physical play cursor. */ + lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; + } + + 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); + break; + } + + /* + Experiment: If the playback buffer is being starved, pad it with some silence to get it back in sync. This will cause a glitch, but it may prevent + endless glitching due to it constantly running out of data. + */ + if (isPlaybackDeviceStarted) { + DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback; + if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) { + silentPaddingInBytes = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback; + if (silentPaddingInBytes > lockSizeInBytesPlayback) { + 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); + } + } + + /* At this point we have a buffer for output. */ + if (silentPaddingInBytes > 0) { + MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes); + framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback; + } else { + ma_uint64 convertedFrameCountIn = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed); + ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback; + void* pConvertedFramesIn = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback); + void* pConvertedFramesOut = pMappedDeviceBufferPlayback; + + result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut); + if (result != MA_SUCCESS) { + break; + } + + outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut; + framesWrittenThisIteration = (ma_uint32)convertedFrameCountOut; + } + + + 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); + break; + } + + virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback; + if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) { + virtualWriteCursorInBytesPlayback = 0; + virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback; + } + + /* + We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds + a bit of a buffer to prevent the playback buffer from getting starved. + */ + framesWrittenToPlaybackDevice += framesWrittenThisIteration; + if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= (pDevice->playback.internalPeriodSizeInFrames*2)) { + 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); + } + isPlaybackDeviceStarted = MA_TRUE; + } + + if (framesWrittenThisIteration < mappedSizeInBytesPlayback/bpfDevicePlayback) { + break; /* We're finished with the output data.*/ + } + } + + if (clientCapturedFramesToProcess == 0) { + break; /* We just consumed every input sample. */ + } + } + + + /* 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); + } + prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture); + } break; + + + + case ma_device_type_capture: + { + DWORD physicalCaptureCursorInBytes; + DWORD physicalReadCursorInBytes; + hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes); + if (FAILED(hr)) { + return MA_ERROR; + } + + /* If the previous capture position is the same as the current position we need to wait a bit longer. */ + if (prevReadCursorInBytesCapture == physicalReadCursorInBytes) { + ma_sleep(waitTimeInMilliseconds); + continue; + } + + /* Getting here means we have capture data available. */ + if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) { + /* The capture position has not looped. This is the simple case. */ + lockOffsetInBytesCapture = prevReadCursorInBytesCapture; + lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture); + } else { + /* + The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything, + do it again from the start. + */ + if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) { + /* Lock up to the end of the buffer. */ + lockOffsetInBytesCapture = prevReadCursorInBytesCapture; + lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture; + } else { + /* Lock starting from the start of the buffer. */ + lockOffsetInBytesCapture = 0; + lockSizeInBytesCapture = physicalReadCursorInBytes; + } + } + + if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) { + ma_sleep(waitTimeInMilliseconds); + continue; /* Nothing is available in the capture buffer. */ + } + + 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); + } + + if (lockSizeInBytesCapture != mappedSizeInBytesCapture) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture); + } + + 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); + } + prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture; + + if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) { + prevReadCursorInBytesCapture = 0; + } + } break; + + + + case ma_device_type_playback: + { + DWORD availableBytesPlayback; + DWORD physicalPlayCursorInBytes; + DWORD physicalWriteCursorInBytes; + hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes); + if (FAILED(hr)) { + 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; + } + prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; + + /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */ + if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { + /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { + availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback; + 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); + availableBytesPlayback = 0; + } + } else { + /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { + 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); + availableBytesPlayback = 0; + } + } + + /* 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); + } + isPlaybackDeviceStarted = MA_TRUE; + } else { + ma_sleep(waitTimeInMilliseconds); + continue; + } + } + + /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */ + lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback; + if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { + /* Same loop iteration. Go up to the end of the buffer. */ + lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback; + } else { + /* Different loop iterations. Go up to the physical play cursor. */ + lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; + } + + 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); + break; + } + + /* At this point we have a buffer for output. */ + ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback); + + 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); + break; + } + + virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback; + if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) { + virtualWriteCursorInBytesPlayback = 0; + virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback; + } + + /* + We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds + a bit of a buffer to prevent the playback buffer from getting starved. + */ + framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback; + 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); + } + isPlaybackDeviceStarted = MA_TRUE; + } + } break; + + + default: return MA_INVALID_ARGS; /* Invalid device type. */ + } + + if (result != MA_SUCCESS) { + return result; + } + } + + /* Getting here means the device is being stopped. */ + 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); + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + /* The playback device should be drained before stopping. All we do is wait until the available bytes is equal to the size of the buffer. */ + if (isPlaybackDeviceStarted) { + for (;;) { + DWORD availableBytesPlayback = 0; + DWORD physicalPlayCursorInBytes; + DWORD physicalWriteCursorInBytes; + hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes); + if (FAILED(hr)) { + break; + } + + if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { + physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; + } + prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes; + + if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) { + /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) { + availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback; + availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */ + } else { + break; + } + } else { + /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */ + if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) { + availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback; + } else { + break; + } + } + + if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) { + break; + } + + ma_sleep(waitTimeInMilliseconds); + } + } + + 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); + } + + ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0); + } + + return MA_SUCCESS; +} + +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); + + return MA_SUCCESS; +} + +static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + MA_ASSERT(pContext != NULL); + + (void)pConfig; + + pContext->dsound.hDSoundDLL = ma_dlopen(ma_context_get_log(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; + + pCallbacks->onContextInit = ma_context_init__dsound; + pCallbacks->onContextUninit = ma_context_uninit__dsound; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__dsound; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__dsound; + pCallbacks->onDeviceInit = ma_device_init__dsound; + pCallbacks->onDeviceUninit = ma_device_uninit__dsound; + pCallbacks->onDeviceStart = NULL; /* Not used. Started in onDeviceDataLoop. */ + pCallbacks->onDeviceStop = NULL; /* Not used. Stopped in onDeviceDataLoop. */ + pCallbacks->onDeviceRead = NULL; /* Not used. Data is read directly in onDeviceDataLoop. */ + pCallbacks->onDeviceWrite = NULL; /* Not used. Data is written directly in onDeviceDataLoop. */ + pCallbacks->onDeviceDataLoop = ma_device_data_loop__dsound; + + return MA_SUCCESS; +} +#endif + + + +/****************************************************************************** + +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. +*/ +#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]; + DWORD dwFormats; + WORD wChannels; + WORD wReserved1; + DWORD dwSupport; + GUID ManufacturerGuid; + GUID ProductGuid; + GUID NameGuid; +} MA_WAVEOUTCAPS2A; + +typedef struct +{ + WORD wMid; + WORD wPid; + MA_MMVERSION vDriverVersion; + CHAR szPname[MA_MAXPNAMELEN]; + DWORD dwFormats; + WORD wChannels; + WORD wReserved1; + GUID ManufacturerGuid; + GUID ProductGuid; + 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); + +static ma_result ma_result_from_MMRESULT(MA_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; + } +} + +static char* ma_find_last_character(char* str, char ch) +{ + char* last; + + if (str == NULL) { + return NULL; + } + + last = NULL; + while (*str != '\0') { + if (*str == ch) { + last = str; + } + + str += 1; + } + + return last; +} + +static ma_uint32 ma_get_period_size_in_bytes(ma_uint32 periodSizeInFrames, ma_format format, ma_uint32 channels) +{ + return periodSizeInFrames * ma_get_bytes_per_frame(format, channels); +} + + +/* +Our own "WAVECAPS" structure that contains generic information shared between WAVEOUTCAPS2 and WAVEINCAPS2 so +we can do things generically and typesafely. Names are being kept the same for consistency. +*/ +typedef struct +{ + CHAR szPname[MA_MAXPNAMELEN]; + DWORD dwFormats; + WORD wChannels; + GUID NameGuid; +} MA_WAVECAPSA; + +static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WORD channels, WORD* pBitsPerSample, DWORD* pSampleRate) +{ + WORD bitsPerSample = 0; + DWORD sampleRate = 0; + + if (pBitsPerSample) { + *pBitsPerSample = 0; + } + if (pSampleRate) { + *pSampleRate = 0; + } + + if (channels == 1) { + bitsPerSample = 16; + if ((dwFormats & WAVE_FORMAT_48M16) != 0) { + sampleRate = 48000; + } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) { + sampleRate = 44100; + } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) { + sampleRate = 22050; + } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) { + sampleRate = 11025; + } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 8; + if ((dwFormats & WAVE_FORMAT_48M08) != 0) { + sampleRate = 48000; + } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) { + sampleRate = 44100; + } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) { + sampleRate = 22050; + } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) { + sampleRate = 11025; + } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) { + sampleRate = 96000; + } else { + return MA_FORMAT_NOT_SUPPORTED; + } + } + } else { + bitsPerSample = 16; + if ((dwFormats & WAVE_FORMAT_48S16) != 0) { + sampleRate = 48000; + } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) { + sampleRate = 44100; + } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) { + sampleRate = 22050; + } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) { + sampleRate = 11025; + } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) { + sampleRate = 96000; + } else { + bitsPerSample = 8; + if ((dwFormats & WAVE_FORMAT_48S08) != 0) { + sampleRate = 48000; + } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) { + sampleRate = 44100; + } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) { + sampleRate = 22050; + } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) { + sampleRate = 11025; + } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) { + sampleRate = 96000; + } else { + return MA_FORMAT_NOT_SUPPORTED; + } + } + } + + if (pBitsPerSample) { + *pBitsPerSample = bitsPerSample; + } + if (pSampleRate) { + *pSampleRate = sampleRate; + } + + return MA_SUCCESS; +} + +static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, MA_WAVEFORMATEX* pWF) +{ + ma_result result; + + MA_ASSERT(pWF != NULL); + + MA_ZERO_OBJECT(pWF); + pWF->cbSize = sizeof(*pWF); + pWF->wFormatTag = WAVE_FORMAT_PCM; + pWF->nChannels = (WORD)channels; + if (pWF->nChannels > 2) { + pWF->nChannels = 2; + } + + result = ma_get_best_info_from_formats_flags__winmm(dwFormats, channels, &pWF->wBitsPerSample, &pWF->nSamplesPerSec); + if (result != MA_SUCCESS) { + return result; + } + + pWF->nBlockAlign = (WORD)(pWF->nChannels * pWF->wBitsPerSample / 8); + pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec; + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, MA_WAVECAPSA* pCaps, ma_device_info* pDeviceInfo) +{ + WORD bitsPerSample; + DWORD sampleRate; + ma_result result; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pCaps != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + /* + Name / Description + + Unfortunately the name specified in WAVE(OUT/IN)CAPS2 is limited to 31 characters. This results in an unprofessional looking + situation where the names of the devices are truncated. To help work around this, we need to look at the name GUID and try + looking in the registry for the full name. If we can't find it there, we need to just fall back to the default name. + */ + + /* Set the default to begin with. */ + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), pCaps->szPname, (size_t)-1); + + /* + Now try the registry. There's a few things to consider here: + - The name GUID can be null, in which we case we just need to stick to the original 31 characters. + - 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 + 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]; + if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) { + char guidStr[256]; + char keyStr[1024]; + HKEY hKey; + + WideCharToMultiByte(CP_UTF8, 0, guidStrW, -1, guidStr, sizeof(guidStr), 0, FALSE); + + ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\"); + ma_strcat_s(keyStr, sizeof(keyStr), guidStr); + + 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); + ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey); + + if (resultWin32 == 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) { + char* nameBeg = ma_find_last_character(name, '('); + if (nameBeg != NULL) { + size_t leadingLen = (nameBeg - name); + ma_strncpy_s(nameBeg + 1, sizeof(name) - leadingLen, (const char*)nameFromReg, (size_t)-1); + + /* The closing ")", if it can fit. */ + if (leadingLen + nameFromRegSize < sizeof(name)-1) { + ma_strcat_s(name, sizeof(name), ")"); + } + + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), name, (size_t)-1); + } + } + } + } + } + } + + + result = ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats, pCaps->wChannels, &bitsPerSample, &sampleRate); + if (result != MA_SUCCESS) { + return result; + } + + if (bitsPerSample == 8) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_u8; + } else if (bitsPerSample == 16) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s16; + } else if (bitsPerSample == 24) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s24; + } else if (bitsPerSample == 32) { + pDeviceInfo->nativeDataFormats[0].format = ma_format_s32; + } else { + return MA_FORMAT_NOT_SUPPORTED; + } + pDeviceInfo->nativeDataFormats[0].channels = pCaps->wChannels; + pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[0].flags = 0; + pDeviceInfo->nativeDataFormatCount = 1; + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pContext, MA_WAVEOUTCAPS2A* pCaps, ma_device_info* pDeviceInfo) +{ + MA_WAVECAPSA caps; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pCaps != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname)); + caps.dwFormats = pCaps->dwFormats; + caps.wChannels = pCaps->wChannels; + caps.NameGuid = pCaps->NameGuid; + return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo); +} + +static ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContext, MA_WAVEINCAPS2A* pCaps, ma_device_info* pDeviceInfo) +{ + MA_WAVECAPSA caps; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pCaps != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname)); + caps.dwFormats = pCaps->dwFormats; + caps.wChannels = pCaps->wChannels; + caps.NameGuid = pCaps->NameGuid; + return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo); +} + + +static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + UINT playbackDeviceCount; + UINT captureDeviceCount; + UINT iPlaybackDevice; + UINT iCaptureDevice; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Playback. */ + playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)(); + for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) { + MA_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) { + ma_device_info deviceInfo; + + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.winmm = iPlaybackDevice; + + /* The first enumerated device is the default device. */ + if (iPlaybackDevice == 0) { + deviceInfo.isDefault = MA_TRUE; + } + + if (ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) { + ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + if (cbResult == MA_FALSE) { + return MA_SUCCESS; /* Enumeration was stopped. */ + } + } + } + } + + /* Capture. */ + captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)(); + for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) { + MA_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) { + ma_device_info deviceInfo; + + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.winmm = iCaptureDevice; + + /* The first enumerated device is the default device. */ + if (iCaptureDevice == 0) { + deviceInfo.isDefault = MA_TRUE; + } + + if (ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) { + ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + if (cbResult == MA_FALSE) { + return MA_SUCCESS; /* Enumeration was stopped. */ + } + } + } + } + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + UINT winMMDeviceID; + + MA_ASSERT(pContext != NULL); + + winMMDeviceID = 0; + if (pDeviceID != NULL) { + winMMDeviceID = (UINT)pDeviceID->winmm; + } + + pDeviceInfo->id.winmm = winMMDeviceID; + + /* The first ID is the default device. */ + if (winMMDeviceID == 0) { + pDeviceInfo->isDefault = MA_TRUE; + } + + if (deviceType == ma_device_type_playback) { + MA_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) { + return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo); + } + } else { + MA_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) { + return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo); + } + } + + return MA_NO_DEVICE; +} + + +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); + 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); + CloseHandle((HANDLE)pDevice->winmm.hEventPlayback); + } + + ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks); + + MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */ + + return MA_SUCCESS; +} + +static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__winmm(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) +{ + /* WinMM has a minimum period size of 40ms. */ + ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(40, nativeSampleRate); + ma_uint32 periodSizeInFrames; + + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile); + if (periodSizeInFrames < minPeriodSizeInFrames) { + periodSizeInFrames = minPeriodSizeInFrames; + } + + return periodSizeInFrames; +} + +static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + const char* errorMsg = ""; + ma_result errorCode = MA_ERROR; + ma_result result = MA_SUCCESS; + ma_uint32 heapSize; + UINT winMMDeviceIDPlayback = 0; + UINT winMMDeviceIDCapture = 0; + + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->winmm); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* No exclusive 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; + } + + if (pDescriptorPlayback->pDeviceID != NULL) { + winMMDeviceIDPlayback = (UINT)pDescriptorPlayback->pDeviceID->winmm; + } + if (pDescriptorCapture->pDeviceID != NULL) { + winMMDeviceIDCapture = (UINT)pDescriptorCapture->pDeviceID->winmm; + } + + /* 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; + + /* We use an event to know when a new fragment needs to be enqueued. */ + pDevice->winmm.hEventCapture = (ma_handle)CreateEventA(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()); + 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) { + errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; + goto on_error; + } + + result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf); + if (result != MA_SUCCESS) { + errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result; + 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) { + errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; + goto on_error; + } + + 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); + 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; + + /* We use an event to know when a new fragment needs to be enqueued. */ + pDevice->winmm.hEventPlayback = (ma_handle)CreateEventA(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()); + 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) { + errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED; + goto on_error; + } + + result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf); + if (result != MA_SUCCESS) { + errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result; + 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) { + errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE; + goto on_error; + } + + 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); + pDescriptorPlayback->periodCount = pDescriptorPlayback->periodCount; + pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); + } + + /* + The heap allocated data is allocated like so: + + [Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer] + */ + 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)); + } + 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)); + } + + pDevice->winmm._pHeapData = (ma_uint8*)ma_calloc(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; + } + + MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize); + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_uint32 iPeriod; + + if (pConfig->deviceType == ma_device_type_capture) { + pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; + pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(MA_WAVEHDR)*(pDescriptorCapture->periodCount)); + } else { + pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData; + pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(MA_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)); + + /* + 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 + it's unlocked and available for writing. A value of 1 means it's locked. + */ + ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0; + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_uint32 iPeriod; + + if (pConfig->deviceType == ma_device_type_playback) { + pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData; + pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(MA_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)); + } + + /* 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)); + + /* + 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 + it's unlocked and available for writing. A value of 1 means it's locked. + */ + ((MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0; + } + } + + return MA_SUCCESS; + +on_error: + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + 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_waveInClose)pDevice->pContext->winmm.waveInClose)((MA_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_waveOutClose)pDevice->pContext->winmm.waveOutClose)((MA_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; +} + +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; + ma_uint32 iPeriod; + + pWAVEHDR = (MA_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); + } + + /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */ + pWAVEHDR[iPeriod].dwUser = 1; /* 1 = locked. */ + } + + /* 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); + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + /* Don't need to do anything for playback. It'll be started automatically in ma_device_start__winmm(). */ + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__winmm(ma_device* pDevice) +{ + MA_MMRESULT resultMM; + + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + if (pDevice->winmm.hDeviceCapture == NULL) { + 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."); + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_uint32 iPeriod; + MA_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; + 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) { + break; /* An error occurred so just abandon ship and stop the device without draining. */ + } + + pWAVEHDR[iPeriod].dwUser = 0; + } + } + + 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."); + } + } + + return MA_SUCCESS; +} + +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; + ma_uint32 totalFramesWritten; + MA_WAVEHDR* pWAVEHDR; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pPCMFrames != NULL); + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback; + + /* Keep processing as much data as possible. */ + totalFramesWritten = 0; + while (totalFramesWritten < frameCount) { + /* If the current header has some space available we need to write part of it. */ + if (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser == 0) { /* 0 = unlocked. */ + /* + This header has room in it. We copy as much of it as we can. If we end up fully consuming the buffer we need to + write it out and move on to the next iteration. + */ + ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedPlayback; + + ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesWritten)); + const void* pSrc = ma_offset_ptr(pPCMFrames, totalFramesWritten*bpf); + void* pDst = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].lpData, pDevice->winmm.headerFramesConsumedPlayback*bpf); + MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf); + + pDevice->winmm.headerFramesConsumedPlayback += framesToCopy; + totalFramesWritten += framesToCopy; + + /* 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. */ + + /* 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) { + result = ma_result_from_MMRESULT(resultMM); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed."); + break; + } + + /* Make sure we move to the next header. */ + pDevice->winmm.iNextHeaderPlayback = (pDevice->winmm.iNextHeaderPlayback + 1) % pDevice->playback.internalPeriods; + pDevice->winmm.headerFramesConsumedPlayback = 0; + } + + /* If at this point we have consumed the entire input buffer we can return. */ + MA_ASSERT(totalFramesWritten <= frameCount); + if (totalFramesWritten == frameCount) { + break; + } + + /* Getting here means there's more to process. */ + continue; + } + + /* Getting here means there isn't enough room in the buffer and we need to wait for one to become available. */ + if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) { + result = MA_ERROR; + break; + } + + /* 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) { + 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) { + break; + } + } + + if (pFramesWritten != NULL) { + *pFramesWritten = totalFramesWritten; + } + + return result; +} + +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; + ma_uint32 totalFramesRead; + MA_WAVEHDR* pWAVEHDR; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pPCMFrames != NULL); + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + pWAVEHDR = (MA_WAVEHDR*)pDevice->winmm.pWAVEHDRCapture; + + /* Keep processing as much data as possible. */ + totalFramesRead = 0; + while (totalFramesRead < frameCount) { + /* If the current header has some space available we need to write part of it. */ + if (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser == 0) { /* 0 = unlocked. */ + /* The buffer is available for reading. If we fully consume it we need to add it back to the buffer. */ + ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedCapture; + + ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesRead)); + const void* pSrc = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderCapture].lpData, pDevice->winmm.headerFramesConsumedCapture*bpf); + void* pDst = ma_offset_ptr(pPCMFrames, totalFramesRead*bpf); + MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf); + + pDevice->winmm.headerFramesConsumedCapture += framesToCopy; + totalFramesRead += framesToCopy; + + /* 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. */ + + /* 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) { + result = ma_result_from_MMRESULT(resultMM); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed."); + break; + } + + /* Make sure we move to the next header. */ + pDevice->winmm.iNextHeaderCapture = (pDevice->winmm.iNextHeaderCapture + 1) % pDevice->capture.internalPeriods; + pDevice->winmm.headerFramesConsumedCapture = 0; + } + + /* If at this point we have filled the entire input buffer we can return. */ + MA_ASSERT(totalFramesRead <= frameCount); + if (totalFramesRead == frameCount) { + break; + } + + /* Getting here means there's more to process. */ + continue; + } + + /* Getting here means there isn't enough any data left to send to the client which means we need to wait for more. */ + if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventCapture, INFINITE) != WAIT_OBJECT_0) { + result = MA_ERROR; + break; + } + + /* 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) { + 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) { + break; + } + } + + if (pFramesRead != NULL) { + *pFramesRead = totalFramesRead; + } + + return result; +} + +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); + return MA_SUCCESS; +} + +static ma_result ma_context_init__winmm(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + MA_ASSERT(pContext != NULL); + + (void)pConfig; + + pContext->winmm.hWinMM = ma_dlopen(ma_context_get_log(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"); + + pCallbacks->onContextInit = ma_context_init__winmm; + pCallbacks->onContextUninit = ma_context_uninit__winmm; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__winmm; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__winmm; + pCallbacks->onDeviceInit = ma_device_init__winmm; + pCallbacks->onDeviceUninit = ma_device_uninit__winmm; + pCallbacks->onDeviceStart = ma_device_start__winmm; + pCallbacks->onDeviceStop = ma_device_stop__winmm; + pCallbacks->onDeviceRead = ma_device_read__winmm; + pCallbacks->onDeviceWrite = ma_device_write__winmm; + pCallbacks->onDeviceDataLoop = NULL; /* This is a blocking read-write API, so this can be NULL since miniaudio will manage the audio thread for us. */ + + return MA_SUCCESS; +} +#endif + + + + +/****************************************************************************** + +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. */ +#if !defined(__cplusplus) + #if defined(__STRICT_ANSI__) + #if !defined(inline) + #define inline __inline__ __attribute__((always_inline)) + #define MA_INLINE_DEFINED + #endif + #endif +#endif +#include +#if defined(MA_INLINE_DEFINED) + #undef inline + #undef MA_INLINE_DEFINED +#endif + +typedef snd_pcm_uframes_t ma_snd_pcm_uframes_t; +typedef snd_pcm_sframes_t ma_snd_pcm_sframes_t; +typedef snd_pcm_stream_t ma_snd_pcm_stream_t; +typedef snd_pcm_format_t ma_snd_pcm_format_t; +typedef snd_pcm_access_t ma_snd_pcm_access_t; +typedef snd_pcm_t ma_snd_pcm_t; +typedef snd_pcm_hw_params_t ma_snd_pcm_hw_params_t; +typedef snd_pcm_sw_params_t ma_snd_pcm_sw_params_t; +typedef snd_pcm_format_mask_t ma_snd_pcm_format_mask_t; +typedef snd_pcm_info_t ma_snd_pcm_info_t; +typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t; +typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t; +typedef snd_pcm_state_t ma_snd_pcm_state_t; + +/* snd_pcm_stream_t */ +#define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK +#define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE + +/* snd_pcm_format_t */ +#define MA_SND_PCM_FORMAT_UNKNOWN SND_PCM_FORMAT_UNKNOWN +#define MA_SND_PCM_FORMAT_U8 SND_PCM_FORMAT_U8 +#define MA_SND_PCM_FORMAT_S16_LE SND_PCM_FORMAT_S16_LE +#define MA_SND_PCM_FORMAT_S16_BE SND_PCM_FORMAT_S16_BE +#define MA_SND_PCM_FORMAT_S24_LE SND_PCM_FORMAT_S24_LE +#define MA_SND_PCM_FORMAT_S24_BE SND_PCM_FORMAT_S24_BE +#define MA_SND_PCM_FORMAT_S32_LE SND_PCM_FORMAT_S32_LE +#define MA_SND_PCM_FORMAT_S32_BE SND_PCM_FORMAT_S32_BE +#define MA_SND_PCM_FORMAT_FLOAT_LE SND_PCM_FORMAT_FLOAT_LE +#define MA_SND_PCM_FORMAT_FLOAT_BE SND_PCM_FORMAT_FLOAT_BE +#define MA_SND_PCM_FORMAT_FLOAT64_LE SND_PCM_FORMAT_FLOAT64_LE +#define MA_SND_PCM_FORMAT_FLOAT64_BE SND_PCM_FORMAT_FLOAT64_BE +#define MA_SND_PCM_FORMAT_MU_LAW SND_PCM_FORMAT_MU_LAW +#define MA_SND_PCM_FORMAT_A_LAW SND_PCM_FORMAT_A_LAW +#define MA_SND_PCM_FORMAT_S24_3LE SND_PCM_FORMAT_S24_3LE +#define MA_SND_PCM_FORMAT_S24_3BE SND_PCM_FORMAT_S24_3BE + +/* ma_snd_pcm_access_t */ +#define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED SND_PCM_ACCESS_MMAP_INTERLEAVED +#define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED SND_PCM_ACCESS_MMAP_NONINTERLEAVED +#define MA_SND_PCM_ACCESS_MMAP_COMPLEX SND_PCM_ACCESS_MMAP_COMPLEX +#define MA_SND_PCM_ACCESS_RW_INTERLEAVED SND_PCM_ACCESS_RW_INTERLEAVED +#define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED SND_PCM_ACCESS_RW_NONINTERLEAVED + +/* Channel positions. */ +#define MA_SND_CHMAP_UNKNOWN SND_CHMAP_UNKNOWN +#define MA_SND_CHMAP_NA SND_CHMAP_NA +#define MA_SND_CHMAP_MONO SND_CHMAP_MONO +#define MA_SND_CHMAP_FL SND_CHMAP_FL +#define MA_SND_CHMAP_FR SND_CHMAP_FR +#define MA_SND_CHMAP_RL SND_CHMAP_RL +#define MA_SND_CHMAP_RR SND_CHMAP_RR +#define MA_SND_CHMAP_FC SND_CHMAP_FC +#define MA_SND_CHMAP_LFE SND_CHMAP_LFE +#define MA_SND_CHMAP_SL SND_CHMAP_SL +#define MA_SND_CHMAP_SR SND_CHMAP_SR +#define MA_SND_CHMAP_RC SND_CHMAP_RC +#define MA_SND_CHMAP_FLC SND_CHMAP_FLC +#define MA_SND_CHMAP_FRC SND_CHMAP_FRC +#define MA_SND_CHMAP_RLC SND_CHMAP_RLC +#define MA_SND_CHMAP_RRC SND_CHMAP_RRC +#define MA_SND_CHMAP_FLW SND_CHMAP_FLW +#define MA_SND_CHMAP_FRW SND_CHMAP_FRW +#define MA_SND_CHMAP_FLH SND_CHMAP_FLH +#define MA_SND_CHMAP_FCH SND_CHMAP_FCH +#define MA_SND_CHMAP_FRH SND_CHMAP_FRH +#define MA_SND_CHMAP_TC SND_CHMAP_TC +#define MA_SND_CHMAP_TFL SND_CHMAP_TFL +#define MA_SND_CHMAP_TFR SND_CHMAP_TFR +#define MA_SND_CHMAP_TFC SND_CHMAP_TFC +#define MA_SND_CHMAP_TRL SND_CHMAP_TRL +#define MA_SND_CHMAP_TRR SND_CHMAP_TRR +#define MA_SND_CHMAP_TRC SND_CHMAP_TRC +#define MA_SND_CHMAP_TFLC SND_CHMAP_TFLC +#define MA_SND_CHMAP_TFRC SND_CHMAP_TFRC +#define MA_SND_CHMAP_TSL SND_CHMAP_TSL +#define MA_SND_CHMAP_TSR SND_CHMAP_TSR +#define MA_SND_CHMAP_LLFE SND_CHMAP_LLFE +#define MA_SND_CHMAP_RLFE SND_CHMAP_RLFE +#define MA_SND_CHMAP_BC SND_CHMAP_BC +#define MA_SND_CHMAP_BLC SND_CHMAP_BLC +#define MA_SND_CHMAP_BRC SND_CHMAP_BRC + +/* Open mode flags. */ +#define MA_SND_PCM_NO_AUTO_RESAMPLE SND_PCM_NO_AUTO_RESAMPLE +#define MA_SND_PCM_NO_AUTO_CHANNELS SND_PCM_NO_AUTO_CHANNELS +#define MA_SND_PCM_NO_AUTO_FORMAT SND_PCM_NO_AUTO_FORMAT +#else +#include /* For EPIPE, etc. */ +typedef unsigned long ma_snd_pcm_uframes_t; +typedef long ma_snd_pcm_sframes_t; +typedef int ma_snd_pcm_stream_t; +typedef int ma_snd_pcm_format_t; +typedef int ma_snd_pcm_access_t; +typedef int ma_snd_pcm_state_t; +typedef struct ma_snd_pcm_t ma_snd_pcm_t; +typedef struct ma_snd_pcm_hw_params_t ma_snd_pcm_hw_params_t; +typedef struct ma_snd_pcm_sw_params_t ma_snd_pcm_sw_params_t; +typedef struct ma_snd_pcm_format_mask_t ma_snd_pcm_format_mask_t; +typedef struct ma_snd_pcm_info_t ma_snd_pcm_info_t; +typedef struct +{ + void* addr; + unsigned int first; + unsigned int step; +} ma_snd_pcm_channel_area_t; +typedef struct +{ + unsigned int channels; + unsigned int pos[1]; +} ma_snd_pcm_chmap_t; + +/* snd_pcm_state_t */ +#define MA_SND_PCM_STATE_OPEN 0 +#define MA_SND_PCM_STATE_SETUP 1 +#define MA_SND_PCM_STATE_PREPARED 2 +#define MA_SND_PCM_STATE_RUNNING 3 +#define MA_SND_PCM_STATE_XRUN 4 +#define MA_SND_PCM_STATE_DRAINING 5 +#define MA_SND_PCM_STATE_PAUSED 6 +#define MA_SND_PCM_STATE_SUSPENDED 7 +#define MA_SND_PCM_STATE_DISCONNECTED 8 + +/* snd_pcm_stream_t */ +#define MA_SND_PCM_STREAM_PLAYBACK 0 +#define MA_SND_PCM_STREAM_CAPTURE 1 + +/* snd_pcm_format_t */ +#define MA_SND_PCM_FORMAT_UNKNOWN -1 +#define MA_SND_PCM_FORMAT_U8 1 +#define MA_SND_PCM_FORMAT_S16_LE 2 +#define MA_SND_PCM_FORMAT_S16_BE 3 +#define MA_SND_PCM_FORMAT_S24_LE 6 +#define MA_SND_PCM_FORMAT_S24_BE 7 +#define MA_SND_PCM_FORMAT_S32_LE 10 +#define MA_SND_PCM_FORMAT_S32_BE 11 +#define MA_SND_PCM_FORMAT_FLOAT_LE 14 +#define MA_SND_PCM_FORMAT_FLOAT_BE 15 +#define MA_SND_PCM_FORMAT_FLOAT64_LE 16 +#define MA_SND_PCM_FORMAT_FLOAT64_BE 17 +#define MA_SND_PCM_FORMAT_MU_LAW 20 +#define MA_SND_PCM_FORMAT_A_LAW 21 +#define MA_SND_PCM_FORMAT_S24_3LE 32 +#define MA_SND_PCM_FORMAT_S24_3BE 33 + +/* snd_pcm_access_t */ +#define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED 0 +#define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED 1 +#define MA_SND_PCM_ACCESS_MMAP_COMPLEX 2 +#define MA_SND_PCM_ACCESS_RW_INTERLEAVED 3 +#define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED 4 + +/* Channel positions. */ +#define MA_SND_CHMAP_UNKNOWN 0 +#define MA_SND_CHMAP_NA 1 +#define MA_SND_CHMAP_MONO 2 +#define MA_SND_CHMAP_FL 3 +#define MA_SND_CHMAP_FR 4 +#define MA_SND_CHMAP_RL 5 +#define MA_SND_CHMAP_RR 6 +#define MA_SND_CHMAP_FC 7 +#define MA_SND_CHMAP_LFE 8 +#define MA_SND_CHMAP_SL 9 +#define MA_SND_CHMAP_SR 10 +#define MA_SND_CHMAP_RC 11 +#define MA_SND_CHMAP_FLC 12 +#define MA_SND_CHMAP_FRC 13 +#define MA_SND_CHMAP_RLC 14 +#define MA_SND_CHMAP_RRC 15 +#define MA_SND_CHMAP_FLW 16 +#define MA_SND_CHMAP_FRW 17 +#define MA_SND_CHMAP_FLH 18 +#define MA_SND_CHMAP_FCH 19 +#define MA_SND_CHMAP_FRH 20 +#define MA_SND_CHMAP_TC 21 +#define MA_SND_CHMAP_TFL 22 +#define MA_SND_CHMAP_TFR 23 +#define MA_SND_CHMAP_TFC 24 +#define MA_SND_CHMAP_TRL 25 +#define MA_SND_CHMAP_TRR 26 +#define MA_SND_CHMAP_TRC 27 +#define MA_SND_CHMAP_TFLC 28 +#define MA_SND_CHMAP_TFRC 29 +#define MA_SND_CHMAP_TSL 30 +#define MA_SND_CHMAP_TSR 31 +#define MA_SND_CHMAP_LLFE 32 +#define MA_SND_CHMAP_RLFE 33 +#define MA_SND_CHMAP_BC 34 +#define MA_SND_CHMAP_BLC 35 +#define MA_SND_CHMAP_BRC 36 + +/* Open mode flags. */ +#define MA_SND_PCM_NO_AUTO_RESAMPLE 0x00010000 +#define MA_SND_PCM_NO_AUTO_CHANNELS 0x00020000 +#define MA_SND_PCM_NO_AUTO_FORMAT 0x00040000 +#endif + +typedef int (* ma_snd_pcm_open_proc) (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode); +typedef int (* ma_snd_pcm_close_proc) (ma_snd_pcm_t *pcm); +typedef size_t (* ma_snd_pcm_hw_params_sizeof_proc) (void); +typedef int (* ma_snd_pcm_hw_params_any_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params); +typedef int (* ma_snd_pcm_hw_params_set_format_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t val); +typedef int (* ma_snd_pcm_hw_params_set_format_first_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format); +typedef void (* ma_snd_pcm_hw_params_get_format_mask_proc) (ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_mask_t *mask); +typedef int (* ma_snd_pcm_hw_params_set_channels_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); +typedef int (* ma_snd_pcm_hw_params_set_channels_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* ma_snd_pcm_hw_params_set_channels_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *minimum, unsigned int *maximum); +typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); +typedef int (* ma_snd_pcm_hw_params_set_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); +typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); +typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access); +typedef int (* ma_snd_pcm_hw_params_get_format_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format); +typedef int (* ma_snd_pcm_hw_params_get_channels_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* ma_snd_pcm_hw_params_get_channels_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* ma_snd_pcm_hw_params_get_channels_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val); +typedef int (* ma_snd_pcm_hw_params_get_rate_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); +typedef int (* ma_snd_pcm_hw_params_get_rate_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); +typedef int (* ma_snd_pcm_hw_params_get_rate_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir); +typedef int (* ma_snd_pcm_hw_params_get_buffer_size_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val); +typedef int (* ma_snd_pcm_hw_params_get_periods_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir); +typedef int (* ma_snd_pcm_hw_params_get_access_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t *_access); +typedef int (* ma_snd_pcm_hw_params_test_format_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t val); +typedef int (* ma_snd_pcm_hw_params_test_channels_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val); +typedef int (* ma_snd_pcm_hw_params_test_rate_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir); +typedef int (* ma_snd_pcm_hw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params); +typedef size_t (* ma_snd_pcm_sw_params_sizeof_proc) (void); +typedef int (* ma_snd_pcm_sw_params_current_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params); +typedef int (* ma_snd_pcm_sw_params_get_boundary_proc) (const ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t* val); +typedef int (* ma_snd_pcm_sw_params_set_avail_min_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); +typedef int (* ma_snd_pcm_sw_params_set_start_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); +typedef int (* ma_snd_pcm_sw_params_set_stop_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val); +typedef int (* ma_snd_pcm_sw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params); +typedef size_t (* ma_snd_pcm_format_mask_sizeof_proc) (void); +typedef int (* ma_snd_pcm_format_mask_test_proc) (const ma_snd_pcm_format_mask_t *mask, ma_snd_pcm_format_t val); +typedef ma_snd_pcm_chmap_t * (* ma_snd_pcm_get_chmap_proc) (ma_snd_pcm_t *pcm); +typedef ma_snd_pcm_state_t (* ma_snd_pcm_state_proc) (ma_snd_pcm_t *pcm); +typedef int (* ma_snd_pcm_prepare_proc) (ma_snd_pcm_t *pcm); +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); +typedef int (* ma_snd_device_name_free_hint_proc) (void **hints); +typedef int (* ma_snd_pcm_mmap_begin_proc) (ma_snd_pcm_t *pcm, const ma_snd_pcm_channel_area_t **areas, ma_snd_pcm_uframes_t *offset, ma_snd_pcm_uframes_t *frames); +typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_mmap_commit_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_uframes_t offset, ma_snd_pcm_uframes_t frames); +typedef int (* ma_snd_pcm_recover_proc) (ma_snd_pcm_t *pcm, int err, int silent); +typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_readi_proc) (ma_snd_pcm_t *pcm, void *buffer, ma_snd_pcm_uframes_t size); +typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_writei_proc) (ma_snd_pcm_t *pcm, const void *buffer, ma_snd_pcm_uframes_t size); +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. */ +static const char* g_maCommonDeviceNamesALSA[] = { + "default", + "null", + "pulse", + "jack" +}; + +/* This array allows us to blacklist specific playback devices. */ +static const char* g_maBlacklistedPlaybackDeviceNamesALSA[] = { + "" +}; + +/* This array allows us to blacklist specific capture devices. */ +static const char* g_maBlacklistedCaptureDeviceNamesALSA[] = { + "" +}; + + +static ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format) +{ + ma_snd_pcm_format_t ALSAFormats[] = { + MA_SND_PCM_FORMAT_UNKNOWN, /* ma_format_unknown */ + MA_SND_PCM_FORMAT_U8, /* ma_format_u8 */ + MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */ + MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */ + MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */ + MA_SND_PCM_FORMAT_FLOAT_LE /* ma_format_f32 */ + }; + + if (ma_is_big_endian()) { + ALSAFormats[0] = MA_SND_PCM_FORMAT_UNKNOWN; + ALSAFormats[1] = MA_SND_PCM_FORMAT_U8; + ALSAFormats[2] = MA_SND_PCM_FORMAT_S16_BE; + ALSAFormats[3] = MA_SND_PCM_FORMAT_S24_3BE; + ALSAFormats[4] = MA_SND_PCM_FORMAT_S32_BE; + ALSAFormats[5] = MA_SND_PCM_FORMAT_FLOAT_BE; + } + + return ALSAFormats[format]; +} + +static ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA) +{ + if (ma_is_little_endian()) { + switch (formatALSA) { + case MA_SND_PCM_FORMAT_S16_LE: return ma_format_s16; + case MA_SND_PCM_FORMAT_S24_3LE: return ma_format_s24; + case MA_SND_PCM_FORMAT_S32_LE: return ma_format_s32; + case MA_SND_PCM_FORMAT_FLOAT_LE: return ma_format_f32; + default: break; + } + } else { + switch (formatALSA) { + case MA_SND_PCM_FORMAT_S16_BE: return ma_format_s16; + case MA_SND_PCM_FORMAT_S24_3BE: return ma_format_s24; + case MA_SND_PCM_FORMAT_S32_BE: return ma_format_s32; + case MA_SND_PCM_FORMAT_FLOAT_BE: return ma_format_f32; + default: break; + } + } + + /* Endian agnostic. */ + switch (formatALSA) { + case MA_SND_PCM_FORMAT_U8: return ma_format_u8; + default: return ma_format_unknown; + } +} + +static ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos) +{ + switch (alsaChannelPos) + { + case MA_SND_CHMAP_MONO: return MA_CHANNEL_MONO; + case MA_SND_CHMAP_FL: return MA_CHANNEL_FRONT_LEFT; + case MA_SND_CHMAP_FR: return MA_CHANNEL_FRONT_RIGHT; + case MA_SND_CHMAP_RL: return MA_CHANNEL_BACK_LEFT; + case MA_SND_CHMAP_RR: return MA_CHANNEL_BACK_RIGHT; + case MA_SND_CHMAP_FC: return MA_CHANNEL_FRONT_CENTER; + case MA_SND_CHMAP_LFE: return MA_CHANNEL_LFE; + case MA_SND_CHMAP_SL: return MA_CHANNEL_SIDE_LEFT; + case MA_SND_CHMAP_SR: return MA_CHANNEL_SIDE_RIGHT; + case MA_SND_CHMAP_RC: return MA_CHANNEL_BACK_CENTER; + case MA_SND_CHMAP_FLC: return MA_CHANNEL_FRONT_LEFT_CENTER; + case MA_SND_CHMAP_FRC: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case MA_SND_CHMAP_RLC: return 0; + case MA_SND_CHMAP_RRC: return 0; + case MA_SND_CHMAP_FLW: return 0; + case MA_SND_CHMAP_FRW: return 0; + case MA_SND_CHMAP_FLH: return 0; + case MA_SND_CHMAP_FCH: return 0; + case MA_SND_CHMAP_FRH: return 0; + case MA_SND_CHMAP_TC: return MA_CHANNEL_TOP_CENTER; + case MA_SND_CHMAP_TFL: return MA_CHANNEL_TOP_FRONT_LEFT; + case MA_SND_CHMAP_TFR: return MA_CHANNEL_TOP_FRONT_RIGHT; + case MA_SND_CHMAP_TFC: return MA_CHANNEL_TOP_FRONT_CENTER; + case MA_SND_CHMAP_TRL: return MA_CHANNEL_TOP_BACK_LEFT; + case MA_SND_CHMAP_TRR: return MA_CHANNEL_TOP_BACK_RIGHT; + case MA_SND_CHMAP_TRC: return MA_CHANNEL_TOP_BACK_CENTER; + default: break; + } + + return 0; +} + +static ma_bool32 ma_is_common_device_name__alsa(const char* name) +{ + size_t iName; + for (iName = 0; iName < ma_countof(g_maCommonDeviceNamesALSA); ++iName) { + if (ma_strcmp(name, g_maCommonDeviceNamesALSA[iName]) == 0) { + return MA_TRUE; + } + } + + return MA_FALSE; +} + + +static ma_bool32 ma_is_playback_device_blacklisted__alsa(const char* name) +{ + size_t iName; + for (iName = 0; iName < ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA); ++iName) { + if (ma_strcmp(name, g_maBlacklistedPlaybackDeviceNamesALSA[iName]) == 0) { + return MA_TRUE; + } + } + + return MA_FALSE; +} + +static ma_bool32 ma_is_capture_device_blacklisted__alsa(const char* name) +{ + size_t iName; + for (iName = 0; iName < ma_countof(g_maBlacklistedCaptureDeviceNamesALSA); ++iName) { + if (ma_strcmp(name, g_maBlacklistedCaptureDeviceNamesALSA[iName]) == 0) { + return MA_TRUE; + } + } + + return MA_FALSE; +} + +static ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType, const char* name) +{ + if (deviceType == ma_device_type_playback) { + return ma_is_playback_device_blacklisted__alsa(name); + } else { + return ma_is_capture_device_blacklisted__alsa(name); + } +} + + +static const char* ma_find_char(const char* str, char c, int* index) +{ + int i = 0; + for (;;) { + if (str[i] == '\0') { + if (index) *index = -1; + return NULL; + } + + if (str[i] == c) { + if (index) *index = i; + return str + i; + } + + i += 1; + } + + /* Should never get here, but treat it as though the character was not found to make me feel better inside. */ + if (index) *index = -1; + return NULL; +} + +static ma_bool32 ma_is_device_name_in_hw_format__alsa(const char* hwid) +{ + /* This function is just checking whether or not hwid is in "hw:%d,%d" format. */ + + int commaPos; + const char* dev; + int i; + + if (hwid == NULL) { + return MA_FALSE; + } + + if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') { + return MA_FALSE; + } + + hwid += 3; + + dev = ma_find_char(hwid, ',', &commaPos); + if (dev == NULL) { + return MA_FALSE; + } else { + dev += 1; /* Skip past the ",". */ + } + + /* Check if the part between the ":" and the "," contains only numbers. If not, return false. */ + for (i = 0; i < commaPos; ++i) { + if (hwid[i] < '0' || hwid[i] > '9') { + return MA_FALSE; + } + } + + /* Check if everything after the "," is numeric. If not, return false. */ + i = 0; + while (dev[i] != '\0') { + if (dev[i] < '0' || dev[i] > '9') { + return MA_FALSE; + } + i += 1; + } + + return MA_TRUE; +} + +static int ma_convert_device_name_to_hw_format__alsa(ma_context* pContext, char* dst, size_t dstSize, const char* src) /* Returns 0 on success, non-0 on error. */ +{ + /* src should look something like this: "hw:CARD=I82801AAICH,DEV=0" */ + + int colonPos; + int commaPos; + char card[256]; + const char* dev; + int cardIndex; + + if (dst == NULL) { + return -1; + } + if (dstSize < 7) { + return -1; /* Absolute minimum size of the output buffer is 7 bytes. */ + } + + *dst = '\0'; /* Safety. */ + if (src == NULL) { + return -1; + } + + /* If the input name is already in "hw:%d,%d" format, just return that verbatim. */ + if (ma_is_device_name_in_hw_format__alsa(src)) { + return ma_strcpy_s(dst, dstSize, src); + } + + src = ma_find_char(src, ':', &colonPos); + if (src == NULL) { + return -1; /* Couldn't find a colon */ + } + + dev = ma_find_char(src, ',', &commaPos); + if (dev == NULL) { + dev = "0"; + ma_strncpy_s(card, sizeof(card), src+6, (size_t)-1); /* +6 = ":CARD=" */ + } else { + dev = dev + 5; /* +5 = ",DEV=" */ + ma_strncpy_s(card, sizeof(card), src+6, commaPos-6); /* +6 = ":CARD=" */ + } + + cardIndex = ((ma_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card); + if (cardIndex < 0) { + return -2; /* Failed to retrieve the card index. */ + } + + + /* Construction. */ + dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':'; + if (ma_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) { + return -3; + } + if (ma_strcat_s(dst, dstSize, ",") != 0) { + return -3; + } + if (ma_strcat_s(dst, dstSize, dev) != 0) { + return -3; + } + + return 0; +} + +static ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id* pUniqueIDs, ma_uint32 count, const char* pHWID) +{ + ma_uint32 i; + + MA_ASSERT(pHWID != NULL); + + for (i = 0; i < count; ++i) { + if (ma_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) { + return MA_TRUE; + } + } + + return MA_FALSE; +} + + +static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode shareMode, ma_device_type deviceType, const ma_device_id* pDeviceID, int openMode, ma_snd_pcm_t** ppPCM) +{ + ma_snd_pcm_t* pPCM; + ma_snd_pcm_stream_t stream; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppPCM != NULL); + + *ppPCM = NULL; + pPCM = NULL; + + stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE; + + if (pDeviceID == NULL) { + ma_bool32 isDeviceOpen; + size_t i; + + /* + We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes + me feel better to try as hard as we can get to get _something_ working. + */ + const char* defaultDeviceNames[] = { + "default", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; + + if (shareMode == ma_share_mode_exclusive) { + defaultDeviceNames[1] = "hw"; + defaultDeviceNames[2] = "hw:0"; + defaultDeviceNames[3] = "hw:0,0"; + } else { + if (deviceType == ma_device_type_playback) { + defaultDeviceNames[1] = "dmix"; + defaultDeviceNames[2] = "dmix:0"; + defaultDeviceNames[3] = "dmix:0,0"; + } else { + defaultDeviceNames[1] = "dsnoop"; + defaultDeviceNames[2] = "dsnoop:0"; + defaultDeviceNames[3] = "dsnoop:0,0"; + } + defaultDeviceNames[4] = "hw"; + defaultDeviceNames[5] = "hw:0"; + defaultDeviceNames[6] = "hw:0,0"; + } + + isDeviceOpen = MA_FALSE; + for (i = 0; i < ma_countof(defaultDeviceNames); ++i) { + if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') { + if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) { + isDeviceOpen = MA_TRUE; + break; + } + } + } + + 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; + } + } 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 + 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"). + */ + + /* May end up needing to make small adjustments to the ID, so make a copy. */ + ma_device_id deviceID = *pDeviceID; + int resultALSA = -ENODEV; + + if (deviceID.alsa[0] != ':') { + /* The ID is not in ":0,0" format. Use the ID exactly as-is. */ + resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode); + } else { + char hwid[256]; + + /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */ + if (deviceID.alsa[1] == '\0') { + deviceID.alsa[0] = '\0'; /* An ID of ":" should be converted to "". */ + } + + if (shareMode == ma_share_mode_shared) { + if (deviceType == ma_device_type_playback) { + ma_strcpy_s(hwid, sizeof(hwid), "dmix"); + } else { + ma_strcpy_s(hwid, sizeof(hwid), "dsnoop"); + } + + if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) { + resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode); + } + } + + /* If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. */ + if (resultALSA != 0) { + ma_strcpy_s(hwid, sizeof(hwid), "hw"); + if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) { + resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode); + } + } + } + + 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); + } + } + + *ppPCM = pPCM; + return MA_SUCCESS; +} + + +static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + int resultALSA; + ma_bool32 cbResult = MA_TRUE; + char** ppDeviceHints; + ma_device_id* pUniqueIDs = NULL; + ma_uint32 uniqueIDCount = 0; + char** ppNextDeviceHint; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock); + + resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints); + if (resultALSA < 0) { + ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock); + return ma_result_from_errno(-resultALSA); + } + + ppNextDeviceHint = ppDeviceHints; + while (*ppNextDeviceHint != NULL) { + char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME"); + char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC"); + char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID"); + ma_device_type deviceType = ma_device_type_playback; + ma_bool32 stopEnumeration = MA_FALSE; + char hwid[sizeof(pUniqueIDs->alsa)]; + ma_device_info deviceInfo; + + if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) { + deviceType = ma_device_type_playback; + } + if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) { + deviceType = ma_device_type_capture; + } + + if (NAME != NULL) { + if (pContext->alsa.useVerboseDeviceEnumeration) { + /* Verbose mode. Use the name exactly as-is. */ + ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); + } else { + /* Simplified mode. Use ":%d,%d" format. */ + if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) { + /* + 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 + device type and sharing mode. + */ + char* dst = hwid; + char* src = hwid+2; + while ((*dst++ = *src++)); + } else { + /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */ + ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1); + } + + if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) { + 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 newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1); + ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, newCapacity, &pContext->allocationCallbacks); + if (pNewUniqueIDs == NULL) { + goto next_device; /* Failed to allocate memory. */ + } + + pUniqueIDs = pNewUniqueIDs; + MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid)); + uniqueIDCount += 1; + } + } + } else { + MA_ZERO_MEMORY(hwid, sizeof(hwid)); + } + + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1); + + /* + There's no good way to determine whether or not a device is the default on Linux. We're just going to do something simple and + just use the name of "default" as the indicator. + */ + if (ma_strcmp(deviceInfo.id.alsa, "default") == 0) { + deviceInfo.isDefault = MA_TRUE; + } + + + /* + DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose + device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish + between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the + description. + + The value in DESC seems to be split into two lines, with the first line being the name of the device and the + second line being a description of the device. I don't like having the description be across two lines because + it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line + being put into parentheses. In simplified mode I'm just stripping the second line entirely. + */ + if (DESC != NULL) { + int lfPos; + const char* line2 = ma_find_char(DESC, '\n', &lfPos); + if (line2 != NULL) { + line2 += 1; /* Skip past the new-line character. */ + + if (pContext->alsa.useVerboseDeviceEnumeration) { + /* Verbose mode. Put the second line in brackets. */ + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos); + ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " ("); + ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2); + ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")"); + } else { + /* Simplified mode. Strip the second line entirely. */ + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos); + } + } else { + /* There's no second line. Just copy the whole description. */ + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1); + } + } + + if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) { + cbResult = callback(pContext, deviceType, &deviceInfo, pUserData); + } + + /* + 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. + */ + if (cbResult) { + if (ma_is_common_device_name__alsa(NAME) || IOID == NULL) { + if (deviceType == ma_device_type_playback) { + if (!ma_is_capture_device_blacklisted__alsa(NAME)) { + cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + } else { + if (!ma_is_playback_device_blacklisted__alsa(NAME)) { + cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + } + } + } + + if (cbResult == MA_FALSE) { + stopEnumeration = MA_TRUE; + } + + next_device: + free(NAME); + free(DESC); + free(IOID); + ppNextDeviceHint += 1; + + /* We need to stop enumeration if the callback returned false. */ + if (stopEnumeration) { + break; + } + } + + ma_free(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); + + return MA_SUCCESS; +} + + +typedef struct +{ + ma_device_type deviceType; + const ma_device_id* pDeviceID; + ma_share_mode shareMode; + ma_device_info* pDeviceInfo; + ma_bool32 foundDevice; +} ma_context_get_device_info_enum_callback_data__alsa; + +static ma_bool32 ma_context_get_device_info_enum_callback__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData) +{ + ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData; + MA_ASSERT(pData != NULL); + + (void)pContext; + + if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) { + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1); + pData->foundDevice = MA_TRUE; + } else { + if (pData->deviceType == deviceType && (pData->pDeviceID != NULL && ma_strcmp(pData->pDeviceID->alsa, pDeviceInfo->id.alsa) == 0)) { + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1); + pData->foundDevice = MA_TRUE; + } + } + + /* Keep enumerating until we have found the device. */ + return !pData->foundDevice; +} + +static void ma_context_test_rate_and_add_native_data_format__alsa(ma_context* pContext, ma_snd_pcm_t* pPCM, ma_snd_pcm_hw_params_t* pHWParams, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pPCM != NULL); + MA_ASSERT(pHWParams != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats) && ((ma_snd_pcm_hw_params_test_rate_proc)pContext->alsa.snd_pcm_hw_params_test_rate)(pPCM, pHWParams, sampleRate, 0) == 0) { + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = flags; + pDeviceInfo->nativeDataFormatCount += 1; + } +} + +static void ma_context_iterate_rates_and_add_native_data_format__alsa(ma_context* pContext, ma_snd_pcm_t* pPCM, ma_snd_pcm_hw_params_t* pHWParams, ma_format format, ma_uint32 channels, ma_uint32 flags, ma_device_info* pDeviceInfo) +{ + ma_uint32 iSampleRate; + unsigned int minSampleRate; + unsigned int maxSampleRate; + int sampleRateDir; /* Not used. Just passed into snd_pcm_hw_params_get_rate_min/max(). */ + + /* There could be a range. */ + ((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. */ + 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); + + for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) { + ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate]; + + if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) { + ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, standardSampleRate, flags, pDeviceInfo); + } + } + + /* Now make sure our min and max rates are included just in case they aren't in the range of our standard rates. */ + if (!ma_is_standard_sample_rate(minSampleRate)) { + ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, minSampleRate, flags, pDeviceInfo); + } + + if (!ma_is_standard_sample_rate(maxSampleRate) && maxSampleRate != minSampleRate) { + ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, maxSampleRate, flags, pDeviceInfo); + } +} + +static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_context_get_device_info_enum_callback_data__alsa data; + ma_result result; + int resultALSA; + ma_snd_pcm_t* pPCM; + ma_snd_pcm_hw_params_t* pHWParams; + ma_uint32 iFormat; + ma_uint32 iChannel; + + MA_ASSERT(pContext != NULL); + + /* We just enumerate to find basic information about the device. */ + data.deviceType = deviceType; + data.pDeviceID = pDeviceID; + data.pDeviceInfo = pDeviceInfo; + data.foundDevice = MA_FALSE; + result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data); + if (result != MA_SUCCESS) { + return result; + } + + if (!data.foundDevice) { + return MA_NO_DEVICE; + } + + if (ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) { + pDeviceInfo->isDefault = MA_TRUE; + } + + /* For detailed info we need to open the device. */ + result = ma_context_open_pcm__alsa(pContext, ma_share_mode_shared, deviceType, pDeviceID, 0, &pPCM); + if (result != MA_SUCCESS) { + return result; + } + + /* 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); + if (pHWParams == NULL) { + ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); + return MA_OUT_OF_MEMORY; + } + + 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_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); + } + + /* + 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 + 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 + 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]; + + /* + For each format we need to make sure we reset the configuration space so we don't return + channel counts and rates that aren't compatible with a format. + */ + ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); + + /* Test the format first. If this fails it means the format is not supported and we can skip it. */ + if (((ma_snd_pcm_hw_params_test_format_proc)pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format)) == 0) { + /* The format is supported. */ + unsigned int minChannels; + unsigned int maxChannels; + + /* + The configuration space needs to be restricted to this format so we can get an accurate + picture of which sample rates and channel counts are support with this format. + */ + ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format)); + + /* Now we need to check for supported channels. */ + ((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &minChannels); + ((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &maxChannels); + + if (minChannels > MA_MAX_CHANNELS) { + continue; /* Too many channels. */ + } + if (maxChannels < MA_MIN_CHANNELS) { + continue; /* Not enough channels. */ + } + + /* + Make sure the channel count is clamped. This is mainly intended for the max channels + because some devices can report an unbound maximum. + */ + minChannels = ma_clamp(minChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS); + maxChannels = ma_clamp(maxChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS); + + if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) { + /* The device supports all channels. Don't iterate over every single one. Instead just set the channels to 0 which means all channels are supported. */ + ma_context_iterate_rates_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, 0, 0, pDeviceInfo); /* Intentionally setting the channel count to 0 as that means all channels are supported. */ + } else { + /* The device only supports a specific set of channels. We need to iterate over all of them. */ + for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) { + /* Test the channel before applying it to the configuration space. */ + unsigned int channels = iChannel; + + /* Make sure our channel range is reset before testing again or else we'll always fail the test. */ + ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams); + ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format)); + + if (((ma_snd_pcm_hw_params_test_channels_proc)pContext->alsa.snd_pcm_hw_params_test_channels)(pPCM, pHWParams, channels) == 0) { + /* The channel count is supported. */ + + /* The configuration space now needs to be restricted to the channel count before extracting the sample rate. */ + ((ma_snd_pcm_hw_params_set_channels_proc)pContext->alsa.snd_pcm_hw_params_set_channels)(pPCM, pHWParams, channels); + + /* Only after the configuration space has been restricted to the specific channel count should we iterate over our sample rates. */ + ma_context_iterate_rates_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, 0, pDeviceInfo); + } else { + /* The channel count is not supported. Skip. */ + } + } + } + } else { + /* The format is not supported. Skip. */ + } + } + + ma_free(pHWParams, &pContext->allocationCallbacks); + + ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM); + return MA_SUCCESS; +} + +static ma_result ma_device_uninit__alsa(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + 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; +} + +static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) +{ + ma_result result; + int resultALSA; + ma_snd_pcm_t* pPCM; + ma_bool32 isUsingMMap; + ma_snd_pcm_format_t formatALSA; + ma_format internalFormat; + ma_uint32 internalChannels; + ma_uint32 internalSampleRate; + ma_channel internalChannelMap[MA_MAX_CHANNELS]; + ma_uint32 internalPeriodSizeInFrames; + ma_uint32 internalPeriods; + int openMode; + 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. */ + MA_ASSERT(pDevice != NULL); + + formatALSA = ma_convert_ma_format_to_alsa_format(pDescriptor->format); + + openMode = 0; + if (pConfig->alsa.noAutoResample) { + openMode |= MA_SND_PCM_NO_AUTO_RESAMPLE; + } + if (pConfig->alsa.noAutoChannels) { + openMode |= MA_SND_PCM_NO_AUTO_CHANNELS; + } + if (pConfig->alsa.noAutoFormat) { + openMode |= MA_SND_PCM_NO_AUTO_FORMAT; + } + + result = ma_context_open_pcm__alsa(pDevice->pContext, pDescriptor->shareMode, deviceType, pDescriptor->pDeviceID, openMode, &pPCM); + if (result != MA_SUCCESS) { + return result; + } + + + /* 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); + 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_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); + } + + /* 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 (((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; + } + } + } +#endif + + 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_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); + } + } + + /* + Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't + find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS. + */ + + /* Format. */ + { + /* + At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is + supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one. + */ + if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN || ((ma_snd_pcm_hw_params_test_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, formatALSA) != 0) { + /* We're either requesting the native format or the specified format is not supported. */ + size_t iFormat; + + formatALSA = MA_SND_PCM_FORMAT_UNKNOWN; + for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) { + if (((ma_snd_pcm_hw_params_test_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat])) == 0) { + formatALSA = ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]); + break; + } + } + + if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) { + ma_free(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; + } + } + + 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_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); + } + + internalFormat = ma_format_from_alsa(formatALSA); + if (internalFormat == ma_format_unknown) { + ma_free(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; + } + } + + /* Channels. */ + { + unsigned int channels = pDescriptor->channels; + if (channels == 0) { + channels = MA_DEFAULT_CHANNELS; + } + + 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_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); + } + + internalChannels = (ma_uint32)channels; + } + + /* Sample Rate */ + { + unsigned int sampleRate; + + /* + It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes + problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable + resampling. + + To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a + sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling + doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly + faster rate. + + miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine + for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very + good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion. + + I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce + this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins. + */ + ((ma_snd_pcm_hw_params_set_rate_resample_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0); + + sampleRate = pDescriptor->sampleRate; + if (sampleRate == 0) { + sampleRate = MA_DEFAULT_SAMPLE_RATE; + } + + 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_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); + } + + internalSampleRate = (ma_uint32)sampleRate; + } + + /* Periods. */ + { + ma_uint32 periods = pDescriptor->periodCount; + + 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_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); + } + + internalPeriods = periods; + } + + /* Buffer Size */ + { + ma_snd_pcm_uframes_t actualBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile) * internalPeriods; + + 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_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); + } + + internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods; + } + + /* 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_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); + } + + ma_free(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); + 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_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); + } + + 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_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); + } + + resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pDevice->pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary); + if (resultALSA < 0) { + bufferBoundary = internalPeriodSizeInFrames * internalPeriods; + } + + 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 + the size of a period. But for full-duplex we need to set it such that it is at least two periods. + */ + 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_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); + } + + 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_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); + } + } + + 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_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); + } + + ma_free(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); + } + + if (pChmap != NULL) { + ma_uint32 iChannel; + + /* There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). */ + if (pChmap->channels >= internalChannels) { + /* Drop excess channels. */ + for (iChannel = 0; iChannel < internalChannels; ++iChannel) { + internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]); + } + } else { + ma_uint32 i; + + /* + Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate + channels. If validation fails, fall back to defaults. + */ + ma_bool32 isValid = MA_TRUE; + + /* Fill with defaults. */ + ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels); + + /* Overwrite first pChmap->channels channels. */ + for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) { + internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]); + } + + /* Validate. */ + for (i = 0; i < internalChannels && isValid; ++i) { + ma_uint32 j; + for (j = i+1; j < internalChannels; ++j) { + if (internalChannelMap[i] == internalChannelMap[j]) { + isValid = MA_FALSE; + break; + } + } + } + + /* 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); + } + } + + free(pChmap); + 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); + } + } + + + /* + 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); + } + + + if (deviceType == ma_device_type_capture) { + pDevice->alsa.pPCMCapture = (ma_ptr)pPCM; + pDevice->alsa.isUsingMMapCapture = isUsingMMap; + } else { + pDevice->alsa.pPCMPlayback = (ma_ptr)pPCM; + pDevice->alsa.isUsingMMapPlayback = isUsingMMap; + } + + pDescriptor->format = internalFormat; + pDescriptor->channels = internalChannels; + pDescriptor->sampleRate = internalSampleRate; + ma_channel_map_copy(pDescriptor->channelMap, internalChannelMap, ma_min(internalChannels, MA_MAX_CHANNELS)); + pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; + pDescriptor->periodCount = internalPeriods; + + return MA_SUCCESS; +} + +static ma_result ma_device_init__alsa(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->alsa); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__alsa(ma_device* pDevice) +{ + int resultALSA; + + 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); + } + } + + 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); + } + } + + return MA_SUCCESS; +} + +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"); + + /* 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); + } + } + } + + 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"); + + /* 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); + } + } + } + + 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_ASSERT(pDevice != NULL); + MA_ASSERT(pFramesOut != NULL); + + if (pFramesRead != NULL) { + *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. */ + 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");*/ + continue; /* Try again. */ + } else if (resultALSA == -EPIPE) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n"); + + /* 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); + } + + 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); + } + + continue; /* Try reading again. */ + } + } + } + + if (pFramesRead != NULL) { + *pFramesRead = resultALSA; + } + + return MA_SUCCESS; +} + +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_ASSERT(pDevice != NULL); + MA_ASSERT(pFrames != NULL); + + if (pFramesWritten != NULL) { + *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; + } + + 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");*/ + continue; /* Try again. */ + } else if (resultALSA == -EPIPE) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n"); + + /* 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); + } + + /* + In my testing I have had a situation where writei() does not automatically restart the device even though I've set it + up as such in the software parameters. What will happen is writei() will block indefinitely even though the number of + frames is well beyond the auto-start threshold. To work around this I've needed to add an explicit start here. Not sure + if this is me just being stupid and not recovering the device properly, but this definitely feels like something isn't + quite right here. + */ + 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); + } + + continue; /* Try writing again. */ + } + } + } + + if (pFramesWritten != NULL) { + *pFramesWritten = resultALSA; + } + + 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); + MA_ASSERT(pContext->backend == ma_backend_alsa); + + /* Clean up memory for memory leak checkers. */ + ((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); +#endif + + ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock); + + return MA_SUCCESS; +} + +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", + "libasound.so" + }; + size_t i; + + for (i = 0; i < ma_countof(libasoundNames); ++i) { + pContext->alsa.asoundSO = ma_dlopen(ma_context_get_log(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"); + 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"); +#else + /* The system below is just for type safety. */ + ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open; + ma_snd_pcm_close_proc _snd_pcm_close = snd_pcm_close; + ma_snd_pcm_hw_params_sizeof_proc _snd_pcm_hw_params_sizeof = snd_pcm_hw_params_sizeof; + ma_snd_pcm_hw_params_any_proc _snd_pcm_hw_params_any = snd_pcm_hw_params_any; + ma_snd_pcm_hw_params_set_format_proc _snd_pcm_hw_params_set_format = snd_pcm_hw_params_set_format; + ma_snd_pcm_hw_params_set_format_first_proc _snd_pcm_hw_params_set_format_first = snd_pcm_hw_params_set_format_first; + ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask; + ma_snd_pcm_hw_params_set_channels_proc _snd_pcm_hw_params_set_channels = snd_pcm_hw_params_set_channels; + ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near; + ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample; + ma_snd_pcm_hw_params_set_rate_near _snd_pcm_hw_params_set_rate = snd_pcm_hw_params_set_rate; + ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near; + ma_snd_pcm_hw_params_set_rate_minmax_proc _snd_pcm_hw_params_set_rate_minmax = snd_pcm_hw_params_set_rate_minmax; + ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near; + ma_snd_pcm_hw_params_set_periods_near_proc _snd_pcm_hw_params_set_periods_near = snd_pcm_hw_params_set_periods_near; + ma_snd_pcm_hw_params_set_access_proc _snd_pcm_hw_params_set_access = snd_pcm_hw_params_set_access; + ma_snd_pcm_hw_params_get_format_proc _snd_pcm_hw_params_get_format = snd_pcm_hw_params_get_format; + ma_snd_pcm_hw_params_get_channels_proc _snd_pcm_hw_params_get_channels = snd_pcm_hw_params_get_channels; + ma_snd_pcm_hw_params_get_channels_min_proc _snd_pcm_hw_params_get_channels_min = snd_pcm_hw_params_get_channels_min; + ma_snd_pcm_hw_params_get_channels_max_proc _snd_pcm_hw_params_get_channels_max = snd_pcm_hw_params_get_channels_max; + ma_snd_pcm_hw_params_get_rate_proc _snd_pcm_hw_params_get_rate = snd_pcm_hw_params_get_rate; + ma_snd_pcm_hw_params_get_rate_min_proc _snd_pcm_hw_params_get_rate_min = snd_pcm_hw_params_get_rate_min; + ma_snd_pcm_hw_params_get_rate_max_proc _snd_pcm_hw_params_get_rate_max = snd_pcm_hw_params_get_rate_max; + ma_snd_pcm_hw_params_get_buffer_size_proc _snd_pcm_hw_params_get_buffer_size = snd_pcm_hw_params_get_buffer_size; + ma_snd_pcm_hw_params_get_periods_proc _snd_pcm_hw_params_get_periods = snd_pcm_hw_params_get_periods; + ma_snd_pcm_hw_params_get_access_proc _snd_pcm_hw_params_get_access = snd_pcm_hw_params_get_access; + ma_snd_pcm_hw_params_test_format_proc _snd_pcm_hw_params_test_format = snd_pcm_hw_params_test_format; + ma_snd_pcm_hw_params_test_channels_proc _snd_pcm_hw_params_test_channels = snd_pcm_hw_params_test_channels; + ma_snd_pcm_hw_params_test_rate_proc _snd_pcm_hw_params_test_rate = snd_pcm_hw_params_test_rate; + ma_snd_pcm_hw_params_proc _snd_pcm_hw_params = snd_pcm_hw_params; + ma_snd_pcm_sw_params_sizeof_proc _snd_pcm_sw_params_sizeof = snd_pcm_sw_params_sizeof; + ma_snd_pcm_sw_params_current_proc _snd_pcm_sw_params_current = snd_pcm_sw_params_current; + ma_snd_pcm_sw_params_get_boundary_proc _snd_pcm_sw_params_get_boundary = snd_pcm_sw_params_get_boundary; + ma_snd_pcm_sw_params_set_avail_min_proc _snd_pcm_sw_params_set_avail_min = snd_pcm_sw_params_set_avail_min; + ma_snd_pcm_sw_params_set_start_threshold_proc _snd_pcm_sw_params_set_start_threshold = snd_pcm_sw_params_set_start_threshold; + ma_snd_pcm_sw_params_set_stop_threshold_proc _snd_pcm_sw_params_set_stop_threshold = snd_pcm_sw_params_set_stop_threshold; + ma_snd_pcm_sw_params_proc _snd_pcm_sw_params = snd_pcm_sw_params; + ma_snd_pcm_format_mask_sizeof_proc _snd_pcm_format_mask_sizeof = snd_pcm_format_mask_sizeof; + ma_snd_pcm_format_mask_test_proc _snd_pcm_format_mask_test = snd_pcm_format_mask_test; + ma_snd_pcm_get_chmap_proc _snd_pcm_get_chmap = snd_pcm_get_chmap; + ma_snd_pcm_state_proc _snd_pcm_state = snd_pcm_state; + ma_snd_pcm_prepare_proc _snd_pcm_prepare = snd_pcm_prepare; + 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; + ma_snd_device_name_free_hint_proc _snd_device_name_free_hint = snd_device_name_free_hint; + ma_snd_pcm_mmap_begin_proc _snd_pcm_mmap_begin = snd_pcm_mmap_begin; + ma_snd_pcm_mmap_commit_proc _snd_pcm_mmap_commit = snd_pcm_mmap_commit; + ma_snd_pcm_recover_proc _snd_pcm_recover = snd_pcm_recover; + ma_snd_pcm_readi_proc _snd_pcm_readi = snd_pcm_readi; + ma_snd_pcm_writei_proc _snd_pcm_writei = snd_pcm_writei; + 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; + pContext->alsa.snd_pcm_close = (ma_proc)_snd_pcm_close; + pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)_snd_pcm_hw_params_sizeof; + pContext->alsa.snd_pcm_hw_params_any = (ma_proc)_snd_pcm_hw_params_any; + pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)_snd_pcm_hw_params_set_format; + pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)_snd_pcm_hw_params_set_format_first; + pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)_snd_pcm_hw_params_get_format_mask; + pContext->alsa.snd_pcm_hw_params_set_channels = (ma_proc)_snd_pcm_hw_params_set_channels; + pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)_snd_pcm_hw_params_set_channels_near; + pContext->alsa.snd_pcm_hw_params_set_channels_minmax = (ma_proc)_snd_pcm_hw_params_set_channels_minmax; + pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample; + pContext->alsa.snd_pcm_hw_params_set_rate = (ma_proc)_snd_pcm_hw_params_set_rate; + pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near; + pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near; + pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near; + pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access; + pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)_snd_pcm_hw_params_get_format; + pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)_snd_pcm_hw_params_get_channels; + pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)_snd_pcm_hw_params_get_channels_min; + pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)_snd_pcm_hw_params_get_channels_max; + pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)_snd_pcm_hw_params_get_rate; + pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)_snd_pcm_hw_params_get_rate_min; + pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)_snd_pcm_hw_params_get_rate_max; + pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)_snd_pcm_hw_params_get_buffer_size; + pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)_snd_pcm_hw_params_get_periods; + pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)_snd_pcm_hw_params_get_access; + pContext->alsa.snd_pcm_hw_params_test_format = (ma_proc)_snd_pcm_hw_params_test_format; + pContext->alsa.snd_pcm_hw_params_test_channels = (ma_proc)_snd_pcm_hw_params_test_channels; + pContext->alsa.snd_pcm_hw_params_test_rate = (ma_proc)_snd_pcm_hw_params_test_rate; + pContext->alsa.snd_pcm_hw_params = (ma_proc)_snd_pcm_hw_params; + pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)_snd_pcm_sw_params_sizeof; + pContext->alsa.snd_pcm_sw_params_current = (ma_proc)_snd_pcm_sw_params_current; + pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)_snd_pcm_sw_params_get_boundary; + pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)_snd_pcm_sw_params_set_avail_min; + pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)_snd_pcm_sw_params_set_start_threshold; + pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)_snd_pcm_sw_params_set_stop_threshold; + pContext->alsa.snd_pcm_sw_params = (ma_proc)_snd_pcm_sw_params; + pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)_snd_pcm_format_mask_sizeof; + pContext->alsa.snd_pcm_format_mask_test = (ma_proc)_snd_pcm_format_mask_test; + pContext->alsa.snd_pcm_get_chmap = (ma_proc)_snd_pcm_get_chmap; + pContext->alsa.snd_pcm_state = (ma_proc)_snd_pcm_state; + pContext->alsa.snd_pcm_prepare = (ma_proc)_snd_pcm_prepare; + 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; + pContext->alsa.snd_device_name_free_hint = (ma_proc)_snd_device_name_free_hint; + pContext->alsa.snd_pcm_mmap_begin = (ma_proc)_snd_pcm_mmap_begin; + pContext->alsa.snd_pcm_mmap_commit = (ma_proc)_snd_pcm_mmap_commit; + pContext->alsa.snd_pcm_recover = (ma_proc)_snd_pcm_recover; + pContext->alsa.snd_pcm_readi = (ma_proc)_snd_pcm_readi; + pContext->alsa.snd_pcm_writei = (ma_proc)_snd_pcm_writei; + 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; + } + + pCallbacks->onContextInit = ma_context_init__alsa; + pCallbacks->onContextUninit = ma_context_uninit__alsa; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__alsa; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__alsa; + pCallbacks->onDeviceInit = ma_device_init__alsa; + pCallbacks->onDeviceUninit = ma_device_uninit__alsa; + pCallbacks->onDeviceStart = ma_device_start__alsa; + pCallbacks->onDeviceStop = ma_device_stop__alsa; + 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 */ + + + +/****************************************************************************** + +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 +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 +allows you to enumerate over devices, nor does it seem to support the ability to stop and start streams. Looking at the documentation, it +appears as though the stream is constantly running and you prevent sound from being emitted or captured by simply not calling the read or +write functions. This is not a professional solution as it would be much better to *actually* stop the underlying stream. Perhaps the +simple API has some smarts to do this automatically, but I'm not sure. Another limitation with the simple API is that it seems inefficient +when you want to have multiple streams to a single context. For these reasons, miniaudio is not using the simple API. + +Since we're not using the simple API, we're left with the asynchronous API as our only other option. And boy, is this where it starts to +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 +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 +vtable, but it's much easier to just use one of the built-in main loop implementations. There's two generic implementations called +pa_mainloop and pa_threaded_mainloop, and another implementation specific to GLib called pa_glib_mainloop. We're using pa_threaded_mainloop +because it simplifies management of the worker thread. The idea of the main loop object is pretty self explanatory - you're supposed to use +it to implement a worker thread which runs in a loop. The main loop is where operations are actually executed. + +To initialize the main loop, you just use `pa_threaded_mainloop_new()`. This is the first function you'll call. You can then get a pointer +to the vtable with `pa_threaded_mainloop_get_api()` (the main loop vtable is called `pa_mainloop_api`). Again, you can bypass the threaded +main loop object entirely and just implement `pa_mainloop_api` directly, but there's no need for it unless you're doing something extremely +specialized such as if you want to integrate it into your application's existing main loop infrastructure. + +(EDIT 2021-01-26: miniaudio is no longer using `pa_threaded_mainloop` due to this issue: https://github.com/mackron/miniaudio/issues/262. +It is now using `pa_mainloop` which turns out to be a simpler solution anyway. The rest of this rant still applies, however.) + +Once you have your main loop vtable (the `pa_mainloop_api` object) you can create the PulseAudio context. This is very similar to +miniaudio's context and they map to each other quite well. You have one context to many streams, which is basically the same as miniaudio's +one `ma_context` to many `ma_device`s. Here's where it starts to get annoying, however. When you first create the PulseAudio context, which +is done with `pa_context_new()`, it's not actually connected to anything. When you connect, you call `pa_context_connect()`. However, if +you remember, PulseAudio is an asynchronous API. That means you cannot just assume the context is connected after `pa_context_context()` +has returned. You instead need to wait for it to connect. To do this, you need to either wait for a callback to get fired, which you can +set with `pa_context_set_state_callback()`, or you can continuously poll the context's state. Either way, you need to run this in a loop. +All objects from here out are created from the context, and, I believe, you can't be creating these objects until the context is connected. +This waiting loop is therefore unavoidable. In order for the waiting to ever complete, however, the main loop needs to be running. Before +attempting to connect the context, the main loop needs to be started with `pa_threaded_mainloop_start()`. + +The reason for this asynchronous design is to support cases where you're connecting to a remote server, say through a local network or an +internet connection. However, the *VAST* majority of cases don't involve this at all - they just connect to a local "server" running on the +host machine. The fact that this would be the default rather than making `pa_context_connect()` synchronous tends to boggle the mind. + +Once the context has been created and connected you can start creating a stream. A PulseAudio stream is analogous to miniaudio's device. +The initialization of a stream is fairly standard - you configure some attributes (analogous to miniaudio's device config) and then call +`pa_stream_new()` to actually create it. Here is where we start to get into "operations". When configuring the stream, you can get +information about the source (such as sample format, sample rate, etc.), however it's not synchronous. Instead, a `pa_operation` object +is returned from `pa_context_get_source_info_by_name()` (capture) or `pa_context_get_sink_info_by_name()` (playback). Then, you need to +run a loop (again!) to wait for the operation to complete which you can determine via a callback or polling, just like we did with the +context. Then, as an added bonus, you need to decrement the reference counter of the `pa_operation` object to ensure memory is cleaned up. +All of that just to retrieve basic information about a device! + +Once the basic information about the device has been retrieved, miniaudio can now create the stream with `ma_stream_new()`. Like the +context, this needs to be connected. But we need to be careful here, because we're now about to introduce one of the most horrific design +choices in PulseAudio. + +PulseAudio allows you to specify a callback that is fired when data can be written to or read from a stream. The language is important here +because PulseAudio takes it literally, specifically the "can be". You would think these callbacks would be appropriate as the place for +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) +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 +that point (it may still need to load files or whatnot). Instead, this callback should only be fired when the application requests the +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 +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 +continuously fire the callback at regular intervals based on the size of the internal buffer. This will only ever be fired when the device +is running, and will be fired regardless of whether or not the user actually wrote anything to the device/stream. This not the case in +PulseAudio. In PulseAudio, the data callback will *only* be called if you wrote something to it previously. That means, if you don't call +`pa_stream_write()`, the callback will not get fired. On the surface you wouldn't think this would matter because you should be always +writing data, and if you don't have anything to write, just write silence. That's fine until you want to drain the stream. You see, if +you're continuously writing data to the stream, the stream will never get drained! That means in order to drain the stream, you need to +*not* write data to it! But remember, when you don't write data to the stream, the callback won't get fired again! Why is draining +important? Because that's how we've defined stopping to work in miniaudio. In miniaudio, stopping the device requires it to be drained +before returning from ma_device_stop(). So we've stopped the device, which requires us to drain, but draining requires us to *not* write +data to the stream (or else it won't ever complete draining), but not writing to the stream means the callback won't get fired again! + +This becomes a problem when stopping and then restarting the device. When the device is stopped, it's drained, which requires us to *not* +write anything to the stream. But then, since we didn't write anything to it, the write callback will *never* get called again if we just +resume the stream naively. This means that starting the stream requires us to write data to the stream from outside the callback. This +disconnect is something PulseAudio has got seriously wrong - there should only ever be a single source of data delivery, that being the +callback. (I have tried using `pa_stream_flush()` to trigger the write callback to fire, but this just doesn't work for some reason.) + +Once you've created the stream, you need to connect it which involves the whole waiting procedure. This is the same process as the context, +only this time you'll poll for the state with `pa_stream_get_status()`. The starting and stopping of a streaming is referred to as +"corking" in PulseAudio. The analogy is corking a barrel. To start the stream, you uncork it, to stop it you cork it. Personally I think +it's silly - why would you not just call it "starting" and "stopping" like any other normal audio API? Anyway, the act of corking is, you +guessed it, asynchronous. This means you'll need our waiting loop as usual. Again, why this asynchronous design is the default is +absolutely beyond me. Would it really be that hard to just make it run synchronously? + +Teardown is pretty simple (what?!). It's just a matter of calling the relevant `_unref()` function on each object in reverse order that +they were initialized in. + +That's about it from the PulseAudio side. A bit ranty, I know, but they really need to fix that main loop and callback system. They're +embarrassingly unpractical. The main loop thing is an easy fix - have synchronous versions of all APIs. If an application wants these to +run asynchronously, they can execute them in a separate thread themselves. The desire to run these asynchronously is such a niche +requirement - it makes no sense to make it the default. The stream write callback needs to be change, or an alternative provided, that is +constantly fired, regardless of whether or not `pa_stream_write()` has been called, and it needs to take a pointer to a buffer as a +parameter which the program just writes to directly rather than having to call `pa_stream_writable_size()` and `pa_stream_write()`. These +changes alone will change PulseAudio from one of the worst audio APIs to one of the best. +*/ + + +/* +It is assumed pulseaudio.h is available when linking at compile time. When linking at compile time, we use the declarations in the header +to check for type safety. We cannot do this when linking at run time because the header might not be available. +*/ +#ifdef MA_NO_RUNTIME_LINKING + +/* pulseaudio.h marks some functions with "inline" which isn't always supported. Need to emulate it. */ +#if !defined(__cplusplus) + #if defined(__STRICT_ANSI__) + #if !defined(inline) + #define inline __inline__ __attribute__((always_inline)) + #define MA_INLINE_DEFINED + #endif + #endif +#endif +#include +#if defined(MA_INLINE_DEFINED) + #undef inline + #undef MA_INLINE_DEFINED +#endif + +#define MA_PA_OK PA_OK +#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 + +typedef pa_context_flags_t ma_pa_context_flags_t; +#define MA_PA_CONTEXT_NOFLAGS PA_CONTEXT_NOFLAGS +#define MA_PA_CONTEXT_NOAUTOSPAWN PA_CONTEXT_NOAUTOSPAWN +#define MA_PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL + +typedef pa_stream_flags_t ma_pa_stream_flags_t; +#define MA_PA_STREAM_NOFLAGS PA_STREAM_NOFLAGS +#define MA_PA_STREAM_START_CORKED PA_STREAM_START_CORKED +#define MA_PA_STREAM_INTERPOLATE_TIMING PA_STREAM_INTERPOLATE_TIMING +#define MA_PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONIC +#define MA_PA_STREAM_AUTO_TIMING_UPDATE PA_STREAM_AUTO_TIMING_UPDATE +#define MA_PA_STREAM_NO_REMAP_CHANNELS PA_STREAM_NO_REMAP_CHANNELS +#define MA_PA_STREAM_NO_REMIX_CHANNELS PA_STREAM_NO_REMIX_CHANNELS +#define MA_PA_STREAM_FIX_FORMAT PA_STREAM_FIX_FORMAT +#define MA_PA_STREAM_FIX_RATE PA_STREAM_FIX_RATE +#define MA_PA_STREAM_FIX_CHANNELS PA_STREAM_FIX_CHANNELS +#define MA_PA_STREAM_DONT_MOVE PA_STREAM_DONT_MOVE +#define MA_PA_STREAM_VARIABLE_RATE PA_STREAM_VARIABLE_RATE +#define MA_PA_STREAM_PEAK_DETECT PA_STREAM_PEAK_DETECT +#define MA_PA_STREAM_START_MUTED PA_STREAM_START_MUTED +#define MA_PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY +#define MA_PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS +#define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND +#define MA_PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED +#define MA_PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND +#define MA_PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME +#define MA_PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH + +typedef pa_sink_flags_t ma_pa_sink_flags_t; +#define MA_PA_SINK_NOFLAGS PA_SINK_NOFLAGS +#define MA_PA_SINK_HW_VOLUME_CTRL PA_SINK_HW_VOLUME_CTRL +#define MA_PA_SINK_LATENCY PA_SINK_LATENCY +#define MA_PA_SINK_HARDWARE PA_SINK_HARDWARE +#define MA_PA_SINK_NETWORK PA_SINK_NETWORK +#define MA_PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL +#define MA_PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME +#define MA_PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME +#define MA_PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY +#define MA_PA_SINK_SET_FORMATS PA_SINK_SET_FORMATS + +typedef pa_source_flags_t ma_pa_source_flags_t; +#define MA_PA_SOURCE_NOFLAGS PA_SOURCE_NOFLAGS +#define MA_PA_SOURCE_HW_VOLUME_CTRL PA_SOURCE_HW_VOLUME_CTRL +#define MA_PA_SOURCE_LATENCY PA_SOURCE_LATENCY +#define MA_PA_SOURCE_HARDWARE PA_SOURCE_HARDWARE +#define MA_PA_SOURCE_NETWORK PA_SOURCE_NETWORK +#define MA_PA_SOURCE_HW_MUTE_CTRL PA_SOURCE_HW_MUTE_CTRL +#define MA_PA_SOURCE_DECIBEL_VOLUME PA_SOURCE_DECIBEL_VOLUME +#define MA_PA_SOURCE_DYNAMIC_LATENCY PA_SOURCE_DYNAMIC_LATENCY +#define MA_PA_SOURCE_FLAT_VOLUME PA_SOURCE_FLAT_VOLUME + +typedef pa_context_state_t ma_pa_context_state_t; +#define MA_PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED +#define MA_PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING +#define MA_PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING +#define MA_PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME +#define MA_PA_CONTEXT_READY PA_CONTEXT_READY +#define MA_PA_CONTEXT_FAILED PA_CONTEXT_FAILED +#define MA_PA_CONTEXT_TERMINATED PA_CONTEXT_TERMINATED + +typedef pa_stream_state_t ma_pa_stream_state_t; +#define MA_PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED +#define MA_PA_STREAM_CREATING PA_STREAM_CREATING +#define MA_PA_STREAM_READY PA_STREAM_READY +#define MA_PA_STREAM_FAILED PA_STREAM_FAILED +#define MA_PA_STREAM_TERMINATED PA_STREAM_TERMINATED + +typedef pa_operation_state_t ma_pa_operation_state_t; +#define MA_PA_OPERATION_RUNNING PA_OPERATION_RUNNING +#define MA_PA_OPERATION_DONE PA_OPERATION_DONE +#define MA_PA_OPERATION_CANCELLED PA_OPERATION_CANCELLED + +typedef pa_sink_state_t ma_pa_sink_state_t; +#define MA_PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE +#define MA_PA_SINK_RUNNING PA_SINK_RUNNING +#define MA_PA_SINK_IDLE PA_SINK_IDLE +#define MA_PA_SINK_SUSPENDED PA_SINK_SUSPENDED + +typedef pa_source_state_t ma_pa_source_state_t; +#define MA_PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE +#define MA_PA_SOURCE_RUNNING PA_SOURCE_RUNNING +#define MA_PA_SOURCE_IDLE PA_SOURCE_IDLE +#define MA_PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED + +typedef pa_seek_mode_t ma_pa_seek_mode_t; +#define MA_PA_SEEK_RELATIVE PA_SEEK_RELATIVE +#define MA_PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE +#define MA_PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ +#define MA_PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END + +typedef pa_channel_position_t ma_pa_channel_position_t; +#define MA_PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID +#define MA_PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO +#define MA_PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT +#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT +#define MA_PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER +#define MA_PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER +#define MA_PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT +#define MA_PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT +#define MA_PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE +#define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER +#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER +#define MA_PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT +#define MA_PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT +#define MA_PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0 +#define MA_PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1 +#define MA_PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2 +#define MA_PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3 +#define MA_PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4 +#define MA_PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5 +#define MA_PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6 +#define MA_PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7 +#define MA_PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8 +#define MA_PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9 +#define MA_PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10 +#define MA_PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11 +#define MA_PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12 +#define MA_PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13 +#define MA_PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14 +#define MA_PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15 +#define MA_PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16 +#define MA_PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17 +#define MA_PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18 +#define MA_PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19 +#define MA_PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20 +#define MA_PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21 +#define MA_PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22 +#define MA_PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23 +#define MA_PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24 +#define MA_PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25 +#define MA_PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26 +#define MA_PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27 +#define MA_PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28 +#define MA_PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29 +#define MA_PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30 +#define MA_PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31 +#define MA_PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER +#define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT +#define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT +#define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER +#define MA_PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT +#define MA_PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT +#define MA_PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER +#define MA_PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER + +typedef pa_channel_map_def_t ma_pa_channel_map_def_t; +#define MA_PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF +#define MA_PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA +#define MA_PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX +#define MA_PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX +#define MA_PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS +#define MA_PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT + +typedef pa_sample_format_t ma_pa_sample_format_t; +#define MA_PA_SAMPLE_INVALID PA_SAMPLE_INVALID +#define MA_PA_SAMPLE_U8 PA_SAMPLE_U8 +#define MA_PA_SAMPLE_ALAW PA_SAMPLE_ALAW +#define MA_PA_SAMPLE_ULAW PA_SAMPLE_ULAW +#define MA_PA_SAMPLE_S16LE PA_SAMPLE_S16LE +#define MA_PA_SAMPLE_S16BE PA_SAMPLE_S16BE +#define MA_PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE +#define MA_PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE +#define MA_PA_SAMPLE_S32LE PA_SAMPLE_S32LE +#define MA_PA_SAMPLE_S32BE PA_SAMPLE_S32BE +#define MA_PA_SAMPLE_S24LE PA_SAMPLE_S24LE +#define MA_PA_SAMPLE_S24BE PA_SAMPLE_S24BE +#define MA_PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE +#define MA_PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE + +typedef pa_mainloop ma_pa_mainloop; +typedef pa_threaded_mainloop ma_pa_threaded_mainloop; +typedef pa_mainloop_api ma_pa_mainloop_api; +typedef pa_context ma_pa_context; +typedef pa_operation ma_pa_operation; +typedef pa_stream ma_pa_stream; +typedef pa_spawn_api ma_pa_spawn_api; +typedef pa_buffer_attr ma_pa_buffer_attr; +typedef pa_channel_map ma_pa_channel_map; +typedef pa_cvolume ma_pa_cvolume; +typedef pa_sample_spec ma_pa_sample_spec; +typedef pa_sink_info ma_pa_sink_info; +typedef pa_source_info ma_pa_source_info; + +typedef pa_context_notify_cb_t ma_pa_context_notify_cb_t; +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 + +typedef int ma_pa_context_flags_t; +#define MA_PA_CONTEXT_NOFLAGS 0x00000000 +#define MA_PA_CONTEXT_NOAUTOSPAWN 0x00000001 +#define MA_PA_CONTEXT_NOFAIL 0x00000002 + +typedef int ma_pa_stream_flags_t; +#define MA_PA_STREAM_NOFLAGS 0x00000000 +#define MA_PA_STREAM_START_CORKED 0x00000001 +#define MA_PA_STREAM_INTERPOLATE_TIMING 0x00000002 +#define MA_PA_STREAM_NOT_MONOTONIC 0x00000004 +#define MA_PA_STREAM_AUTO_TIMING_UPDATE 0x00000008 +#define MA_PA_STREAM_NO_REMAP_CHANNELS 0x00000010 +#define MA_PA_STREAM_NO_REMIX_CHANNELS 0x00000020 +#define MA_PA_STREAM_FIX_FORMAT 0x00000040 +#define MA_PA_STREAM_FIX_RATE 0x00000080 +#define MA_PA_STREAM_FIX_CHANNELS 0x00000100 +#define MA_PA_STREAM_DONT_MOVE 0x00000200 +#define MA_PA_STREAM_VARIABLE_RATE 0x00000400 +#define MA_PA_STREAM_PEAK_DETECT 0x00000800 +#define MA_PA_STREAM_START_MUTED 0x00001000 +#define MA_PA_STREAM_ADJUST_LATENCY 0x00002000 +#define MA_PA_STREAM_EARLY_REQUESTS 0x00004000 +#define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND 0x00008000 +#define MA_PA_STREAM_START_UNMUTED 0x00010000 +#define MA_PA_STREAM_FAIL_ON_SUSPEND 0x00020000 +#define MA_PA_STREAM_RELATIVE_VOLUME 0x00040000 +#define MA_PA_STREAM_PASSTHROUGH 0x00080000 + +typedef int ma_pa_sink_flags_t; +#define MA_PA_SINK_NOFLAGS 0x00000000 +#define MA_PA_SINK_HW_VOLUME_CTRL 0x00000001 +#define MA_PA_SINK_LATENCY 0x00000002 +#define MA_PA_SINK_HARDWARE 0x00000004 +#define MA_PA_SINK_NETWORK 0x00000008 +#define MA_PA_SINK_HW_MUTE_CTRL 0x00000010 +#define MA_PA_SINK_DECIBEL_VOLUME 0x00000020 +#define MA_PA_SINK_FLAT_VOLUME 0x00000040 +#define MA_PA_SINK_DYNAMIC_LATENCY 0x00000080 +#define MA_PA_SINK_SET_FORMATS 0x00000100 + +typedef int ma_pa_source_flags_t; +#define MA_PA_SOURCE_NOFLAGS 0x00000000 +#define MA_PA_SOURCE_HW_VOLUME_CTRL 0x00000001 +#define MA_PA_SOURCE_LATENCY 0x00000002 +#define MA_PA_SOURCE_HARDWARE 0x00000004 +#define MA_PA_SOURCE_NETWORK 0x00000008 +#define MA_PA_SOURCE_HW_MUTE_CTRL 0x00000010 +#define MA_PA_SOURCE_DECIBEL_VOLUME 0x00000020 +#define MA_PA_SOURCE_DYNAMIC_LATENCY 0x00000040 +#define MA_PA_SOURCE_FLAT_VOLUME 0x00000080 + +typedef int ma_pa_context_state_t; +#define MA_PA_CONTEXT_UNCONNECTED 0 +#define MA_PA_CONTEXT_CONNECTING 1 +#define MA_PA_CONTEXT_AUTHORIZING 2 +#define MA_PA_CONTEXT_SETTING_NAME 3 +#define MA_PA_CONTEXT_READY 4 +#define MA_PA_CONTEXT_FAILED 5 +#define MA_PA_CONTEXT_TERMINATED 6 + +typedef int ma_pa_stream_state_t; +#define MA_PA_STREAM_UNCONNECTED 0 +#define MA_PA_STREAM_CREATING 1 +#define MA_PA_STREAM_READY 2 +#define MA_PA_STREAM_FAILED 3 +#define MA_PA_STREAM_TERMINATED 4 + +typedef int ma_pa_operation_state_t; +#define MA_PA_OPERATION_RUNNING 0 +#define MA_PA_OPERATION_DONE 1 +#define MA_PA_OPERATION_CANCELLED 2 + +typedef int ma_pa_sink_state_t; +#define MA_PA_SINK_INVALID_STATE -1 +#define MA_PA_SINK_RUNNING 0 +#define MA_PA_SINK_IDLE 1 +#define MA_PA_SINK_SUSPENDED 2 + +typedef int ma_pa_source_state_t; +#define MA_PA_SOURCE_INVALID_STATE -1 +#define MA_PA_SOURCE_RUNNING 0 +#define MA_PA_SOURCE_IDLE 1 +#define MA_PA_SOURCE_SUSPENDED 2 + +typedef int ma_pa_seek_mode_t; +#define MA_PA_SEEK_RELATIVE 0 +#define MA_PA_SEEK_ABSOLUTE 1 +#define MA_PA_SEEK_RELATIVE_ON_READ 2 +#define MA_PA_SEEK_RELATIVE_END 3 + +typedef int ma_pa_channel_position_t; +#define MA_PA_CHANNEL_POSITION_INVALID -1 +#define MA_PA_CHANNEL_POSITION_MONO 0 +#define MA_PA_CHANNEL_POSITION_FRONT_LEFT 1 +#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT 2 +#define MA_PA_CHANNEL_POSITION_FRONT_CENTER 3 +#define MA_PA_CHANNEL_POSITION_REAR_CENTER 4 +#define MA_PA_CHANNEL_POSITION_REAR_LEFT 5 +#define MA_PA_CHANNEL_POSITION_REAR_RIGHT 6 +#define MA_PA_CHANNEL_POSITION_LFE 7 +#define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER 8 +#define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER 9 +#define MA_PA_CHANNEL_POSITION_SIDE_LEFT 10 +#define MA_PA_CHANNEL_POSITION_SIDE_RIGHT 11 +#define MA_PA_CHANNEL_POSITION_AUX0 12 +#define MA_PA_CHANNEL_POSITION_AUX1 13 +#define MA_PA_CHANNEL_POSITION_AUX2 14 +#define MA_PA_CHANNEL_POSITION_AUX3 15 +#define MA_PA_CHANNEL_POSITION_AUX4 16 +#define MA_PA_CHANNEL_POSITION_AUX5 17 +#define MA_PA_CHANNEL_POSITION_AUX6 18 +#define MA_PA_CHANNEL_POSITION_AUX7 19 +#define MA_PA_CHANNEL_POSITION_AUX8 20 +#define MA_PA_CHANNEL_POSITION_AUX9 21 +#define MA_PA_CHANNEL_POSITION_AUX10 22 +#define MA_PA_CHANNEL_POSITION_AUX11 23 +#define MA_PA_CHANNEL_POSITION_AUX12 24 +#define MA_PA_CHANNEL_POSITION_AUX13 25 +#define MA_PA_CHANNEL_POSITION_AUX14 26 +#define MA_PA_CHANNEL_POSITION_AUX15 27 +#define MA_PA_CHANNEL_POSITION_AUX16 28 +#define MA_PA_CHANNEL_POSITION_AUX17 29 +#define MA_PA_CHANNEL_POSITION_AUX18 30 +#define MA_PA_CHANNEL_POSITION_AUX19 31 +#define MA_PA_CHANNEL_POSITION_AUX20 32 +#define MA_PA_CHANNEL_POSITION_AUX21 33 +#define MA_PA_CHANNEL_POSITION_AUX22 34 +#define MA_PA_CHANNEL_POSITION_AUX23 35 +#define MA_PA_CHANNEL_POSITION_AUX24 36 +#define MA_PA_CHANNEL_POSITION_AUX25 37 +#define MA_PA_CHANNEL_POSITION_AUX26 38 +#define MA_PA_CHANNEL_POSITION_AUX27 39 +#define MA_PA_CHANNEL_POSITION_AUX28 40 +#define MA_PA_CHANNEL_POSITION_AUX29 41 +#define MA_PA_CHANNEL_POSITION_AUX30 42 +#define MA_PA_CHANNEL_POSITION_AUX31 43 +#define MA_PA_CHANNEL_POSITION_TOP_CENTER 44 +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT 45 +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT 46 +#define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER 47 +#define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT 48 +#define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT 49 +#define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER 50 +#define MA_PA_CHANNEL_POSITION_LEFT MA_PA_CHANNEL_POSITION_FRONT_LEFT +#define MA_PA_CHANNEL_POSITION_RIGHT MA_PA_CHANNEL_POSITION_FRONT_RIGHT +#define MA_PA_CHANNEL_POSITION_CENTER MA_PA_CHANNEL_POSITION_FRONT_CENTER +#define MA_PA_CHANNEL_POSITION_SUBWOOFER MA_PA_CHANNEL_POSITION_LFE + +typedef int ma_pa_channel_map_def_t; +#define MA_PA_CHANNEL_MAP_AIFF 0 +#define MA_PA_CHANNEL_MAP_ALSA 1 +#define MA_PA_CHANNEL_MAP_AUX 2 +#define MA_PA_CHANNEL_MAP_WAVEEX 3 +#define MA_PA_CHANNEL_MAP_OSS 4 +#define MA_PA_CHANNEL_MAP_DEFAULT MA_PA_CHANNEL_MAP_AIFF + +typedef int ma_pa_sample_format_t; +#define MA_PA_SAMPLE_INVALID -1 +#define MA_PA_SAMPLE_U8 0 +#define MA_PA_SAMPLE_ALAW 1 +#define MA_PA_SAMPLE_ULAW 2 +#define MA_PA_SAMPLE_S16LE 3 +#define MA_PA_SAMPLE_S16BE 4 +#define MA_PA_SAMPLE_FLOAT32LE 5 +#define MA_PA_SAMPLE_FLOAT32BE 6 +#define MA_PA_SAMPLE_S32LE 7 +#define MA_PA_SAMPLE_S32BE 8 +#define MA_PA_SAMPLE_S24LE 9 +#define MA_PA_SAMPLE_S24BE 10 +#define MA_PA_SAMPLE_S24_32LE 11 +#define MA_PA_SAMPLE_S24_32BE 12 + +typedef struct ma_pa_mainloop ma_pa_mainloop; +typedef struct ma_pa_threaded_mainloop ma_pa_threaded_mainloop; +typedef struct ma_pa_mainloop_api ma_pa_mainloop_api; +typedef struct ma_pa_context ma_pa_context; +typedef struct ma_pa_operation ma_pa_operation; +typedef struct ma_pa_stream ma_pa_stream; +typedef struct ma_pa_spawn_api ma_pa_spawn_api; + +typedef struct +{ + ma_uint32 maxlength; + ma_uint32 tlength; + ma_uint32 prebuf; + ma_uint32 minreq; + ma_uint32 fragsize; +} ma_pa_buffer_attr; + +typedef struct +{ + ma_uint8 channels; + ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX]; +} ma_pa_channel_map; + +typedef struct +{ + ma_uint8 channels; + ma_uint32 values[MA_PA_CHANNELS_MAX]; +} ma_pa_cvolume; + +typedef struct +{ + ma_pa_sample_format_t format; + ma_uint32 rate; + ma_uint8 channels; +} ma_pa_sample_spec; + +typedef struct +{ + const char* name; + ma_uint32 index; + const char* description; + ma_pa_sample_spec sample_spec; + ma_pa_channel_map channel_map; + ma_uint32 owner_module; + ma_pa_cvolume volume; + int mute; + ma_uint32 monitor_source; + const char* monitor_source_name; + ma_uint64 latency; + const char* driver; + ma_pa_sink_flags_t flags; + void* proplist; + ma_uint64 configured_latency; + ma_uint32 base_volume; + ma_pa_sink_state_t state; + ma_uint32 n_volume_steps; + ma_uint32 card; + ma_uint32 n_ports; + void** ports; + void* active_port; + ma_uint8 n_formats; + void** formats; +} ma_pa_sink_info; + +typedef struct +{ + const char *name; + ma_uint32 index; + const char *description; + ma_pa_sample_spec sample_spec; + ma_pa_channel_map channel_map; + ma_uint32 owner_module; + ma_pa_cvolume volume; + int mute; + ma_uint32 monitor_of_sink; + const char *monitor_of_sink_name; + ma_uint64 latency; + const char *driver; + ma_pa_source_flags_t flags; + void* proplist; + ma_uint64 configured_latency; + ma_uint32 base_volume; + ma_pa_source_state_t state; + ma_uint32 n_volume_steps; + ma_uint32 card; + ma_uint32 n_ports; + void** ports; + void* active_port; + ma_uint8 n_formats; + void** formats; +} ma_pa_source_info; + +typedef void (* ma_pa_context_notify_cb_t)(ma_pa_context* c, void* userdata); +typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_info* i, int eol, void* userdata); +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 + + +typedef ma_pa_mainloop* (* ma_pa_mainloop_new_proc) (void); +typedef void (* ma_pa_mainloop_free_proc) (ma_pa_mainloop* m); +typedef void (* ma_pa_mainloop_quit_proc) (ma_pa_mainloop* m, int retval); +typedef ma_pa_mainloop_api* (* ma_pa_mainloop_get_api_proc) (ma_pa_mainloop* m); +typedef int (* ma_pa_mainloop_iterate_proc) (ma_pa_mainloop* m, int block, int* retval); +typedef void (* ma_pa_mainloop_wakeup_proc) (ma_pa_mainloop* m); +typedef ma_pa_threaded_mainloop* (* ma_pa_threaded_mainloop_new_proc) (void); +typedef void (* ma_pa_threaded_mainloop_free_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_start_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_stop_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_lock_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_unlock_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_wait_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_signal_proc) (ma_pa_threaded_mainloop* m, int wait_for_accept); +typedef void (* ma_pa_threaded_mainloop_accept_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_get_retval_proc) (ma_pa_threaded_mainloop* m); +typedef ma_pa_mainloop_api* (* ma_pa_threaded_mainloop_get_api_proc) (ma_pa_threaded_mainloop* m); +typedef int (* ma_pa_threaded_mainloop_in_thread_proc) (ma_pa_threaded_mainloop* m); +typedef void (* ma_pa_threaded_mainloop_set_name_proc) (ma_pa_threaded_mainloop* m, const char* name); +typedef ma_pa_context* (* ma_pa_context_new_proc) (ma_pa_mainloop_api* mainloop, const char* name); +typedef void (* ma_pa_context_unref_proc) (ma_pa_context* c); +typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api); +typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c); +typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata); +typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c); +typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata); +typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata); +typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata); +typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata); +typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o); +typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o); +typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def); +typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m); +typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss); +typedef ma_pa_stream* (* ma_pa_stream_new_proc) (ma_pa_context* c, const char* name, const ma_pa_sample_spec* ss, const ma_pa_channel_map* map); +typedef void (* ma_pa_stream_unref_proc) (ma_pa_stream* s); +typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream); +typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags); +typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s); +typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s); +typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s); +typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s); +typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s); +typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata); +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); +typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata); +typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); +typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes); +typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek); +typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes); +typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s); +typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s); + +typedef struct +{ + ma_uint32 count; + ma_uint32 capacity; + ma_device_info* pInfo; +} ma_pulse_device_enum_data; + +static ma_result ma_result_from_pulse(int result) +{ + if (result < 0) { + return MA_ERROR; + } + + switch (result) { + case MA_PA_OK: return MA_SUCCESS; + case MA_PA_ERR_ACCESS: return MA_ACCESS_DENIED; + case MA_PA_ERR_INVALID: return MA_INVALID_ARGS; + case MA_PA_ERR_NOENTITY: return MA_NO_DEVICE; + default: return MA_ERROR; + } +} + +#if 0 +static ma_pa_sample_format_t ma_format_to_pulse(ma_format format) +{ + if (ma_is_little_endian()) { + switch (format) { + case ma_format_s16: return MA_PA_SAMPLE_S16LE; + case ma_format_s24: return MA_PA_SAMPLE_S24LE; + case ma_format_s32: return MA_PA_SAMPLE_S32LE; + case ma_format_f32: return MA_PA_SAMPLE_FLOAT32LE; + default: break; + } + } else { + switch (format) { + case ma_format_s16: return MA_PA_SAMPLE_S16BE; + case ma_format_s24: return MA_PA_SAMPLE_S24BE; + case ma_format_s32: return MA_PA_SAMPLE_S32BE; + case ma_format_f32: return MA_PA_SAMPLE_FLOAT32BE; + default: break; + } + } + + /* Endian agnostic. */ + switch (format) { + case ma_format_u8: return MA_PA_SAMPLE_U8; + default: return MA_PA_SAMPLE_INVALID; + } +} +#endif + +static ma_format ma_format_from_pulse(ma_pa_sample_format_t format) +{ + if (ma_is_little_endian()) { + switch (format) { + case MA_PA_SAMPLE_S16LE: return ma_format_s16; + case MA_PA_SAMPLE_S24LE: return ma_format_s24; + case MA_PA_SAMPLE_S32LE: return ma_format_s32; + case MA_PA_SAMPLE_FLOAT32LE: return ma_format_f32; + default: break; + } + } else { + switch (format) { + case MA_PA_SAMPLE_S16BE: return ma_format_s16; + case MA_PA_SAMPLE_S24BE: return ma_format_s24; + case MA_PA_SAMPLE_S32BE: return ma_format_s32; + case MA_PA_SAMPLE_FLOAT32BE: return ma_format_f32; + default: break; + } + } + + /* Endian agnostic. */ + switch (format) { + case MA_PA_SAMPLE_U8: return ma_format_u8; + default: return ma_format_unknown; + } +} + +static ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position) +{ + switch (position) + { + case MA_PA_CHANNEL_POSITION_INVALID: return MA_CHANNEL_NONE; + case MA_PA_CHANNEL_POSITION_MONO: return MA_CHANNEL_MONO; + case MA_PA_CHANNEL_POSITION_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; + case MA_PA_CHANNEL_POSITION_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; + case MA_PA_CHANNEL_POSITION_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; + case MA_PA_CHANNEL_POSITION_REAR_CENTER: return MA_CHANNEL_BACK_CENTER; + case MA_PA_CHANNEL_POSITION_REAR_LEFT: return MA_CHANNEL_BACK_LEFT; + case MA_PA_CHANNEL_POSITION_REAR_RIGHT: return MA_CHANNEL_BACK_RIGHT; + case MA_PA_CHANNEL_POSITION_LFE: return MA_CHANNEL_LFE; + case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; + case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case MA_PA_CHANNEL_POSITION_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; + case MA_PA_CHANNEL_POSITION_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; + case MA_PA_CHANNEL_POSITION_AUX0: return MA_CHANNEL_AUX_0; + case MA_PA_CHANNEL_POSITION_AUX1: return MA_CHANNEL_AUX_1; + case MA_PA_CHANNEL_POSITION_AUX2: return MA_CHANNEL_AUX_2; + case MA_PA_CHANNEL_POSITION_AUX3: return MA_CHANNEL_AUX_3; + case MA_PA_CHANNEL_POSITION_AUX4: return MA_CHANNEL_AUX_4; + case MA_PA_CHANNEL_POSITION_AUX5: return MA_CHANNEL_AUX_5; + case MA_PA_CHANNEL_POSITION_AUX6: return MA_CHANNEL_AUX_6; + case MA_PA_CHANNEL_POSITION_AUX7: return MA_CHANNEL_AUX_7; + case MA_PA_CHANNEL_POSITION_AUX8: return MA_CHANNEL_AUX_8; + case MA_PA_CHANNEL_POSITION_AUX9: return MA_CHANNEL_AUX_9; + case MA_PA_CHANNEL_POSITION_AUX10: return MA_CHANNEL_AUX_10; + case MA_PA_CHANNEL_POSITION_AUX11: return MA_CHANNEL_AUX_11; + case MA_PA_CHANNEL_POSITION_AUX12: return MA_CHANNEL_AUX_12; + case MA_PA_CHANNEL_POSITION_AUX13: return MA_CHANNEL_AUX_13; + case MA_PA_CHANNEL_POSITION_AUX14: return MA_CHANNEL_AUX_14; + case MA_PA_CHANNEL_POSITION_AUX15: return MA_CHANNEL_AUX_15; + case MA_PA_CHANNEL_POSITION_AUX16: return MA_CHANNEL_AUX_16; + case MA_PA_CHANNEL_POSITION_AUX17: return MA_CHANNEL_AUX_17; + case MA_PA_CHANNEL_POSITION_AUX18: return MA_CHANNEL_AUX_18; + case MA_PA_CHANNEL_POSITION_AUX19: return MA_CHANNEL_AUX_19; + case MA_PA_CHANNEL_POSITION_AUX20: return MA_CHANNEL_AUX_20; + case MA_PA_CHANNEL_POSITION_AUX21: return MA_CHANNEL_AUX_21; + case MA_PA_CHANNEL_POSITION_AUX22: return MA_CHANNEL_AUX_22; + case MA_PA_CHANNEL_POSITION_AUX23: return MA_CHANNEL_AUX_23; + case MA_PA_CHANNEL_POSITION_AUX24: return MA_CHANNEL_AUX_24; + case MA_PA_CHANNEL_POSITION_AUX25: return MA_CHANNEL_AUX_25; + case MA_PA_CHANNEL_POSITION_AUX26: return MA_CHANNEL_AUX_26; + case MA_PA_CHANNEL_POSITION_AUX27: return MA_CHANNEL_AUX_27; + case MA_PA_CHANNEL_POSITION_AUX28: return MA_CHANNEL_AUX_28; + case MA_PA_CHANNEL_POSITION_AUX29: return MA_CHANNEL_AUX_29; + case MA_PA_CHANNEL_POSITION_AUX30: return MA_CHANNEL_AUX_30; + case MA_PA_CHANNEL_POSITION_AUX31: return MA_CHANNEL_AUX_31; + case MA_PA_CHANNEL_POSITION_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; + case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; + case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; + case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; + case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; + case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; + case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; + default: return MA_CHANNEL_NONE; + } +} + +#if 0 +static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position) +{ + switch (position) + { + case MA_CHANNEL_NONE: return MA_PA_CHANNEL_POSITION_INVALID; + case MA_CHANNEL_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_FRONT_LEFT; + case MA_CHANNEL_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT; + case MA_CHANNEL_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_CENTER; + case MA_CHANNEL_LFE: return MA_PA_CHANNEL_POSITION_LFE; + case MA_CHANNEL_BACK_LEFT: return MA_PA_CHANNEL_POSITION_REAR_LEFT; + case MA_CHANNEL_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_REAR_RIGHT; + case MA_CHANNEL_FRONT_LEFT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; + case MA_CHANNEL_FRONT_RIGHT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + case MA_CHANNEL_BACK_CENTER: return MA_PA_CHANNEL_POSITION_REAR_CENTER; + case MA_CHANNEL_SIDE_LEFT: return MA_PA_CHANNEL_POSITION_SIDE_LEFT; + case MA_CHANNEL_SIDE_RIGHT: return MA_PA_CHANNEL_POSITION_SIDE_RIGHT; + case MA_CHANNEL_TOP_CENTER: return MA_PA_CHANNEL_POSITION_TOP_CENTER; + case MA_CHANNEL_TOP_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT; + case MA_CHANNEL_TOP_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER; + case MA_CHANNEL_TOP_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; + case MA_CHANNEL_TOP_BACK_LEFT: return MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT; + case MA_CHANNEL_TOP_BACK_CENTER: return MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER; + case MA_CHANNEL_TOP_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT; + case MA_CHANNEL_19: return MA_PA_CHANNEL_POSITION_AUX18; + case MA_CHANNEL_20: return MA_PA_CHANNEL_POSITION_AUX19; + case MA_CHANNEL_21: return MA_PA_CHANNEL_POSITION_AUX20; + case MA_CHANNEL_22: return MA_PA_CHANNEL_POSITION_AUX21; + case MA_CHANNEL_23: return MA_PA_CHANNEL_POSITION_AUX22; + case MA_CHANNEL_24: return MA_PA_CHANNEL_POSITION_AUX23; + case MA_CHANNEL_25: return MA_PA_CHANNEL_POSITION_AUX24; + case MA_CHANNEL_26: return MA_PA_CHANNEL_POSITION_AUX25; + case MA_CHANNEL_27: return MA_PA_CHANNEL_POSITION_AUX26; + case MA_CHANNEL_28: return MA_PA_CHANNEL_POSITION_AUX27; + case MA_CHANNEL_29: return MA_PA_CHANNEL_POSITION_AUX28; + case MA_CHANNEL_30: return MA_PA_CHANNEL_POSITION_AUX29; + case MA_CHANNEL_31: return MA_PA_CHANNEL_POSITION_AUX30; + case MA_CHANNEL_32: return MA_PA_CHANNEL_POSITION_AUX31; + default: return (ma_pa_channel_position_t)position; + } +} +#endif + +static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) +{ + int resultPA; + ma_pa_operation_state_t state; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pOP != NULL); + + for (;;) { + state = ((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP); + if (state != MA_PA_OPERATION_RUNNING) { + break; /* Done. */ + } + + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + if (resultPA < 0) { + return ma_result_from_pulse(resultPA); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP) +{ + ma_result result; + + if (pOP == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_wait_for_operation__pulse(pContext, pMainLoop, 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) +{ + 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); + 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; + } + + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + if (resultPA < 0) { + return ma_result_from_pulse(resultPA); + } + } + + /* Should never get here. */ + return MA_SUCCESS; +} + +static ma_result ma_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr 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); + 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; + } + + resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL); + if (resultPA < 0) { + return ma_result_from_pulse(resultPA); + } + } + + return MA_SUCCESS; +} + + +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; + + if (endOfList > 0) { + 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); + + *pInfoOut = *pInfo; + + (void)pPulseContext; /* Unused. */ +} + +static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) +{ + ma_pa_source_info* pInfoOut; + + if (endOfList > 0) { + 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); + + *pInfoOut = *pInfo; + + (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; + + if (endOfList > 0) { + return; + } + + pDevice = (ma_device*)pUserData; + MA_ASSERT(pDevice != NULL); + + ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), pInfo->description, (size_t)-1); + + (void)pPulseContext; /* Unused. */ +} + +static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) +{ + ma_device* pDevice; + + if (endOfList > 0) { + return; + } + + pDevice = (ma_device*)pUserData; + MA_ASSERT(pDevice != NULL); + + ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), pInfo->description, (size_t)-1); + + (void)pPulseContext; /* Unused. */ +} +#endif + +static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_sink_info* pSinkInfo) +{ + ma_pa_operation* pOP; + + 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_device_sink_info_callback, pSinkInfo); + if (pOP == NULL) { + return MA_ERROR; + } + + return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); +} + +static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_source_info* pSourceInfo) +{ + ma_pa_operation* pOP; + + 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_device_source_info_callback, pSourceInfo); + if (pOP == NULL) { + return MA_ERROR; + } + + return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); +} + +static ma_result ma_context_get_default_device_index__pulse(ma_context* pContext, ma_device_type deviceType, ma_uint32* pIndex) +{ + ma_result result; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pIndex != NULL); + + if (pIndex != NULL) { + *pIndex = (ma_uint32)-1; + } + + if (deviceType == ma_device_type_playback) { + ma_pa_sink_info sinkInfo; + result = ma_context_get_sink_info__pulse(pContext, NULL, &sinkInfo); + if (result != MA_SUCCESS) { + return result; + } + + if (pIndex != NULL) { + *pIndex = sinkInfo.index; + } + } + + if (deviceType == ma_device_type_capture) { + ma_pa_source_info sourceInfo; + result = ma_context_get_source_info__pulse(pContext, NULL, &sourceInfo); + if (result != MA_SUCCESS) { + return result; + } + + if (pIndex != NULL) { + *pIndex = sourceInfo.index; + } + } + + return MA_SUCCESS; +} + + +typedef struct +{ + ma_context* pContext; + ma_enum_devices_callback_proc callback; + void* pUserData; + ma_bool32 isTerminated; + ma_uint32 defaultDeviceIndexPlayback; + ma_uint32 defaultDeviceIndexCapture; +} ma_context_enumerate_devices_callback_data__pulse; + +static void ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pSinkInfo, int endOfList, void* pUserData) +{ + ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData; + ma_device_info deviceInfo; + + MA_ASSERT(pData != NULL); + + if (endOfList || pData->isTerminated) { + return; + } + + MA_ZERO_OBJECT(&deviceInfo); + + /* The name from PulseAudio is the ID for miniaudio. */ + if (pSinkInfo->name != NULL) { + ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1); + } + + /* The description from PulseAudio is the name for miniaudio. */ + if (pSinkInfo->description != NULL) { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1); + } + + if (pSinkInfo->index == pData->defaultDeviceIndexPlayback) { + deviceInfo.isDefault = MA_TRUE; + } + + pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_playback, &deviceInfo, pData->pUserData); + + (void)pPulseContext; /* Unused. */ +} + +static void ma_context_enumerate_devices_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pSourceInfo, int endOfList, void* pUserData) +{ + ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData; + ma_device_info deviceInfo; + + MA_ASSERT(pData != NULL); + + if (endOfList || pData->isTerminated) { + return; + } + + MA_ZERO_OBJECT(&deviceInfo); + + /* The name from PulseAudio is the ID for miniaudio. */ + if (pSourceInfo->name != NULL) { + ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSourceInfo->name, (size_t)-1); + } + + /* The description from PulseAudio is the name for miniaudio. */ + if (pSourceInfo->description != NULL) { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSourceInfo->description, (size_t)-1); + } + + if (pSourceInfo->index == pData->defaultDeviceIndexCapture) { + deviceInfo.isDefault = MA_TRUE; + } + + pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_capture, &deviceInfo, pData->pUserData); + + (void)pPulseContext; /* Unused. */ +} + +static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_result result = MA_SUCCESS; + ma_context_enumerate_devices_callback_data__pulse callbackData; + ma_pa_operation* pOP = NULL; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + callbackData.pContext = pContext; + callbackData.callback = callback; + callbackData.pUserData = pUserData; + callbackData.isTerminated = MA_FALSE; + callbackData.defaultDeviceIndexPlayback = (ma_uint32)-1; + callbackData.defaultDeviceIndexCapture = (ma_uint32)-1; + + /* We need to get the index of the default devices. */ + ma_context_get_default_device_index__pulse(pContext, ma_device_type_playback, &callbackData.defaultDeviceIndexPlayback); + ma_context_get_default_device_index__pulse(pContext, ma_device_type_capture, &callbackData.defaultDeviceIndexCapture); + + /* Playback. */ + if (!callbackData.isTerminated) { + pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_sink_callback__pulse, &callbackData); + if (pOP == NULL) { + result = MA_ERROR; + goto done; + } + + result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); + ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); + + if (result != MA_SUCCESS) { + goto done; + } + } + + + /* Capture. */ + if (!callbackData.isTerminated) { + pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_source_callback__pulse, &callbackData); + if (pOP == NULL) { + result = MA_ERROR; + goto done; + } + + result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP); + ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP); + + if (result != MA_SUCCESS) { + goto done; + } + } + +done: + return result; +} + + +typedef struct +{ + ma_device_info* pDeviceInfo; + ma_uint32 defaultDeviceIndex; + ma_bool32 foundDevice; +} ma_context_get_device_info_callback_data__pulse; + +static void ma_context_get_device_info_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData) +{ + ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData; + + if (endOfList > 0) { + return; + } + + MA_ASSERT(pData != NULL); + pData->foundDevice = MA_TRUE; + + if (pInfo->name != NULL) { + ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1); + } + + if (pInfo->description != NULL) { + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1); + } + + /* + We're just reporting a single data format here. I think technically PulseAudio might support + all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to + report the "native" device format. + */ + pData->pDeviceInfo->nativeDataFormats[0].format = ma_format_from_pulse(pInfo->sample_spec.format); + pData->pDeviceInfo->nativeDataFormats[0].channels = pInfo->sample_spec.channels; + pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate; + pData->pDeviceInfo->nativeDataFormats[0].flags = 0; + pData->pDeviceInfo->nativeDataFormatCount = 1; + + if (pData->defaultDeviceIndex == pInfo->index) { + pData->pDeviceInfo->isDefault = MA_TRUE; + } + + (void)pPulseContext; /* Unused. */ +} + +static void ma_context_get_device_info_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData) +{ + ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData; + + if (endOfList > 0) { + return; + } + + MA_ASSERT(pData != NULL); + pData->foundDevice = MA_TRUE; + + if (pInfo->name != NULL) { + ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1); + } + + if (pInfo->description != NULL) { + ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1); + } + + /* + We're just reporting a single data format here. I think technically PulseAudio might support + all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to + report the "native" device format. + */ + pData->pDeviceInfo->nativeDataFormats[0].format = ma_format_from_pulse(pInfo->sample_spec.format); + pData->pDeviceInfo->nativeDataFormats[0].channels = pInfo->sample_spec.channels; + pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate; + pData->pDeviceInfo->nativeDataFormats[0].flags = 0; + pData->pDeviceInfo->nativeDataFormatCount = 1; + + if (pData->defaultDeviceIndex == pInfo->index) { + pData->pDeviceInfo->isDefault = MA_TRUE; + } + + (void)pPulseContext; /* Unused. */ +} + +static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + 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); + } 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); + } + + if (pOP != NULL) { + ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP); + } else { + result = MA_ERROR; + goto done; + } + + if (!callbackData.foundDevice) { + result = MA_NO_DEVICE; + goto done; + } + +done: + return result; +} + +static ma_result ma_device_uninit__pulse(ma_device* pDevice) +{ + ma_context* pContext; + + MA_ASSERT(pDevice != NULL); + + pContext = pDevice->pContext; + MA_ASSERT(pContext != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + } + + if (pDevice->type == ma_device_type_duplex) { + 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; +} + +static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss) +{ + ma_pa_buffer_attr attr; + attr.maxlength = periodSizeInFrames * periods * ma_get_bytes_per_frame(ma_format_from_pulse(ss->format), ss->channels); + attr.tlength = attr.maxlength / periods; + attr.prebuf = (ma_uint32)-1; + attr.minreq = (ma_uint32)-1; + attr.fragsize = attr.maxlength / periods; + + 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_atomic_uint32 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_atomic_uint32_fetch_add(&g_StreamCounter, 1); + + return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); +} + + +static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData) +{ + 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) { + const void* pMappedPCMFrames; + size_t bytesMapped; + ma_uint64 framesMapped; + + int pulseResult = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)(pStream, &pMappedPCMFrames, &bytesMapped); + if (pulseResult < 0) { + break; /* Failed to map. Abort. */ + } + + framesMapped = bytesMapped / bpf; + if (framesMapped > 0) { + if (pMappedPCMFrames != NULL) { + 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"); + } + + pulseResult = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)(pStream); + if (pulseResult < 0) { + break; /* Failed to drop the buffer. */ + } + + framesProcessed += framesMapped; + + } else { + /* Nothing was mapped. Just abort. */ + break; + } + } +} + +static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stream* pStream, ma_uint64* pFramesProcessed) +{ + ma_result result = MA_SUCCESS; + ma_uint64 framesProcessed = 0; + size_t bytesMapped; + ma_uint32 bpf; + ma_uint32 deviceState; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pStream != NULL); + + bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + MA_ASSERT(bpf > 0); + + deviceState = ma_device_get_state(pDevice); + + bytesMapped = ((ma_pa_stream_writable_size_proc)pDevice->pContext->pulse.pa_stream_writable_size)(pStream); + if (bytesMapped != (size_t)-1) { + if (bytesMapped > 0) { + ma_uint64 framesMapped; + void* pMappedPCMFrames; + int pulseResult = ((ma_pa_stream_begin_write_proc)pDevice->pContext->pulse.pa_stream_begin_write)(pStream, &pMappedPCMFrames, &bytesMapped); + if (pulseResult < 0) { + result = ma_result_from_pulse(pulseResult); + goto done; + } + + 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. */ + 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); + } + + pulseResult = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)(pStream, pMappedPCMFrames, bytesMapped, NULL, 0, MA_PA_SEEK_RELATIVE); + if (pulseResult < 0) { + result = ma_result_from_pulse(pulseResult); + goto done; /* Failed to write data to stream. */ + } + + framesProcessed += framesMapped; + } else { + result = MA_SUCCESS; /* No data available for writing. */ + goto done; + } + } else { + result = MA_ERROR; /* Failed to retrieve the writable size. Abort. */ + goto done; + } + +done: + if (pFramesProcessed != NULL) { + *pFramesProcessed = framesProcessed; + } + + return result; +} + +static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + ma_uint32 bpf; + ma_uint64 frameCount; + ma_uint64 framesProcessed; + ma_uint32 deviceState; + ma_result result; + + 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->playback.internalFormat, pDevice->playback.internalChannels); + MA_ASSERT(bpf > 0); + + frameCount = byteCount / bpf; + framesProcessed = 0; + + while (framesProcessed < frameCount) { + ma_uint64 framesProcessedThisIteration; + + /* 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) { + break; + } + + result = ma_device_write_to_stream__pulse(pDevice, pStream, &framesProcessedThisIteration); + if (result != MA_SUCCESS) { + break; + } + + framesProcessed += framesProcessedThisIteration; + } +} + +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: + + - 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. + + - Do not ever, *ever* forget to use MA_PA_STREAM_ADJUST_LATENCY. If you don't specify this + flag, capture mode will just not work properly until you open another PulseAudio app. + */ + + ma_result result = MA_SUCCESS; + int error = 0; + const char* devPlayback = NULL; + const char* devCapture = NULL; + ma_format format = ma_format_unknown; + ma_uint32 channels = 0; + ma_uint32 sampleRate = 0; + ma_pa_sink_info sinkInfo; + ma_pa_source_info sourceInfo; + ma_pa_sample_spec ss; + ma_pa_channel_map cmap; + ma_pa_buffer_attr attr; + const ma_pa_sample_spec* pActualSS = NULL; + const ma_pa_buffer_attr* pActualAttr = NULL; + const ma_pa_channel_map* pActualChannelMap = NULL; + ma_uint32 iChannel; + ma_pa_stream_flags_t streamFlags; + + MA_ASSERT(pDevice != NULL); + MA_ZERO_OBJECT(&pDevice->pulse); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* No exclusive mode with the PulseAudio backend. */ + if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) || + ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode == ma_share_mode_exclusive)) { + return MA_SHARE_MODE_NOT_SUPPORTED; + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + if (pDescriptorPlayback->pDeviceID != NULL) { + devPlayback = pDescriptorPlayback->pDeviceID->pulse; + } + + format = pDescriptorPlayback->format; + channels = pDescriptorPlayback->channels; + sampleRate = pDescriptorPlayback->sampleRate; + } + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + 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."); + 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); + + 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); + + pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, 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; + goto on_error0; + } + + + /* 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. */ + 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); + goto on_error1; + } + + result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (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. */ + } + + /* + 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. */ + } + } + + + /* Buffer. */ + pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + if (pActualAttr != NULL) { + attr = *pActualAttr; + } + + if (attr.fragsize > 0) { + pDescriptorCapture->periodCount = ma_max(attr.maxlength / attr.fragsize, 1); + } else { + pDescriptorCapture->periodCount = 1; + } + + 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); + } + + 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"); + 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); + + attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss); + + 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); + 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; + 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. + */ + ((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. */ + 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); + goto on_error3; + } + + result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (result != MA_SUCCESS) { + goto on_error3; + } + + + /* Internal format. */ + 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. */ + } + + /* + 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. */ + } + } + + + /* Buffer. */ + pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (pActualAttr != NULL) { + attr = *pActualAttr; + } + + if (attr.tlength > 0) { + pDescriptorPlayback->periodCount = ma_max(attr.maxlength / attr.tlength, 1); + } else { + pDescriptorPlayback->periodCount = 1; + } + + 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); + } + + + /* + We need a ring buffer for handling duplex mode. We can use the main duplex ring buffer in the main + part of the ma_device struct. We cannot, however, depend on ma_device_init() initializing this for + us later on because that will only do it if it's a fully asynchronous backend - i.e. the + 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); + 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)); + goto on_error4; + } + } + + return MA_SUCCESS; + + +on_error4: + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + } +on_error3: + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + } +on_error2: + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + } +on_error1: + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + } +on_error0: + return result; +} + + +static void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData) +{ + ma_bool32* pIsSuccessful = (ma_bool32*)pUserData; + MA_ASSERT(pIsSuccessful != NULL); + + *pIsSuccessful = (ma_bool32)success; + + (void)pStream; /* Unused. */ +} + +static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork) +{ + ma_context* pContext = pDevice->pContext; + ma_bool32 wasSuccessful; + ma_pa_stream* pStream; + ma_pa_operation* pOP; + ma_result result; + + /* This should not be called with a duplex device type. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + wasSuccessful = MA_FALSE; + + pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback); + MA_ASSERT(pStream != NULL); + + 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; + } + + result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, 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; + } + + 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; + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__pulse(ma_device* pDevice) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0); + if (result != MA_SUCCESS) { + return result; + } + } + + 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.*/ + + result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__pulse(ma_device* pDevice) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 1); + if (result != MA_SUCCESS) { + return result; + } + } + + 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 + 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 + + result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_data_loop__pulse(ma_device* pDevice) +{ + int resultPA; + + MA_ASSERT(pDevice != NULL); + + /* NOTE: Don't start the device here. It'll be done at a higher level. */ + + /* + 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); + if (resultPA < 0) { + break; + } + } + + /* NOTE: Don't stop the device here. It'll be done at a higher level. */ + return MA_SUCCESS; +} + +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); + + return MA_SUCCESS; +} + +static ma_result ma_context_uninit__pulse(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_pulseaudio); + + ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pContext->pulse.pPulseContext); + ((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); +#endif + + return MA_SUCCESS; +} + +static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + ma_result result; +#ifndef MA_NO_RUNTIME_LINKING + const char* libpulseNames[] = { + "libpulse.so", + "libpulse.so.0" + }; + size_t i; + + for (i = 0; i < ma_countof(libpulseNames); ++i) { + pContext->pulse.pulseSO = ma_dlopen(ma_context_get_log(pContext), libpulseNames[i]); + if (pContext->pulse.pulseSO != NULL) { + break; + } + } + + if (pContext->pulse.pulseSO == NULL) { + 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"); +#else + /* This strange assignment system is just for type safety. */ + ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new; + ma_pa_mainloop_free_proc _pa_mainloop_free = pa_mainloop_free; + ma_pa_mainloop_quit_proc _pa_mainloop_quit = pa_mainloop_quit; + ma_pa_mainloop_get_api_proc _pa_mainloop_get_api = pa_mainloop_get_api; + ma_pa_mainloop_iterate_proc _pa_mainloop_iterate = pa_mainloop_iterate; + ma_pa_mainloop_wakeup_proc _pa_mainloop_wakeup = pa_mainloop_wakeup; + ma_pa_threaded_mainloop_new_proc _pa_threaded_mainloop_new = pa_threaded_mainloop_new; + ma_pa_threaded_mainloop_free_proc _pa_threaded_mainloop_free = pa_threaded_mainloop_free; + ma_pa_threaded_mainloop_start_proc _pa_threaded_mainloop_start = pa_threaded_mainloop_start; + ma_pa_threaded_mainloop_stop_proc _pa_threaded_mainloop_stop = pa_threaded_mainloop_stop; + ma_pa_threaded_mainloop_lock_proc _pa_threaded_mainloop_lock = pa_threaded_mainloop_lock; + ma_pa_threaded_mainloop_unlock_proc _pa_threaded_mainloop_unlock = pa_threaded_mainloop_unlock; + ma_pa_threaded_mainloop_wait_proc _pa_threaded_mainloop_wait = pa_threaded_mainloop_wait; + ma_pa_threaded_mainloop_signal_proc _pa_threaded_mainloop_signal = pa_threaded_mainloop_signal; + ma_pa_threaded_mainloop_accept_proc _pa_threaded_mainloop_accept = pa_threaded_mainloop_accept; + ma_pa_threaded_mainloop_get_retval_proc _pa_threaded_mainloop_get_retval = pa_threaded_mainloop_get_retval; + ma_pa_threaded_mainloop_get_api_proc _pa_threaded_mainloop_get_api = pa_threaded_mainloop_get_api; + ma_pa_threaded_mainloop_in_thread_proc _pa_threaded_mainloop_in_thread = pa_threaded_mainloop_in_thread; + ma_pa_threaded_mainloop_set_name_proc _pa_threaded_mainloop_set_name = pa_threaded_mainloop_set_name; + ma_pa_context_new_proc _pa_context_new = pa_context_new; + ma_pa_context_unref_proc _pa_context_unref = pa_context_unref; + ma_pa_context_connect_proc _pa_context_connect = pa_context_connect; + ma_pa_context_disconnect_proc _pa_context_disconnect = pa_context_disconnect; + ma_pa_context_set_state_callback_proc _pa_context_set_state_callback = pa_context_set_state_callback; + ma_pa_context_get_state_proc _pa_context_get_state = pa_context_get_state; + ma_pa_context_get_sink_info_list_proc _pa_context_get_sink_info_list = pa_context_get_sink_info_list; + ma_pa_context_get_source_info_list_proc _pa_context_get_source_info_list = pa_context_get_source_info_list; + ma_pa_context_get_sink_info_by_name_proc _pa_context_get_sink_info_by_name = pa_context_get_sink_info_by_name; + ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name; + ma_pa_operation_unref_proc _pa_operation_unref = pa_operation_unref; + ma_pa_operation_get_state_proc _pa_operation_get_state = pa_operation_get_state; + ma_pa_channel_map_init_extend_proc _pa_channel_map_init_extend = pa_channel_map_init_extend; + ma_pa_channel_map_valid_proc _pa_channel_map_valid = pa_channel_map_valid; + ma_pa_channel_map_compatible_proc _pa_channel_map_compatible = pa_channel_map_compatible; + ma_pa_stream_new_proc _pa_stream_new = pa_stream_new; + ma_pa_stream_unref_proc _pa_stream_unref = pa_stream_unref; + ma_pa_stream_connect_playback_proc _pa_stream_connect_playback = pa_stream_connect_playback; + ma_pa_stream_connect_record_proc _pa_stream_connect_record = pa_stream_connect_record; + ma_pa_stream_disconnect_proc _pa_stream_disconnect = pa_stream_disconnect; + ma_pa_stream_get_state_proc _pa_stream_get_state = pa_stream_get_state; + ma_pa_stream_get_sample_spec_proc _pa_stream_get_sample_spec = pa_stream_get_sample_spec; + ma_pa_stream_get_channel_map_proc _pa_stream_get_channel_map = pa_stream_get_channel_map; + ma_pa_stream_get_buffer_attr_proc _pa_stream_get_buffer_attr = pa_stream_get_buffer_attr; + ma_pa_stream_set_buffer_attr_proc _pa_stream_set_buffer_attr = pa_stream_set_buffer_attr; + 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; + ma_pa_stream_cork_proc _pa_stream_cork = pa_stream_cork; + ma_pa_stream_trigger_proc _pa_stream_trigger = pa_stream_trigger; + ma_pa_stream_begin_write_proc _pa_stream_begin_write = pa_stream_begin_write; + ma_pa_stream_write_proc _pa_stream_write = pa_stream_write; + ma_pa_stream_peek_proc _pa_stream_peek = pa_stream_peek; + ma_pa_stream_drop_proc _pa_stream_drop = pa_stream_drop; + ma_pa_stream_writable_size_proc _pa_stream_writable_size = pa_stream_writable_size; + ma_pa_stream_readable_size_proc _pa_stream_readable_size = pa_stream_readable_size; + + pContext->pulse.pa_mainloop_new = (ma_proc)_pa_mainloop_new; + pContext->pulse.pa_mainloop_free = (ma_proc)_pa_mainloop_free; + pContext->pulse.pa_mainloop_quit = (ma_proc)_pa_mainloop_quit; + pContext->pulse.pa_mainloop_get_api = (ma_proc)_pa_mainloop_get_api; + pContext->pulse.pa_mainloop_iterate = (ma_proc)_pa_mainloop_iterate; + pContext->pulse.pa_mainloop_wakeup = (ma_proc)_pa_mainloop_wakeup; + pContext->pulse.pa_threaded_mainloop_new = (ma_proc)_pa_threaded_mainloop_new; + pContext->pulse.pa_threaded_mainloop_free = (ma_proc)_pa_threaded_mainloop_free; + pContext->pulse.pa_threaded_mainloop_start = (ma_proc)_pa_threaded_mainloop_start; + pContext->pulse.pa_threaded_mainloop_stop = (ma_proc)_pa_threaded_mainloop_stop; + pContext->pulse.pa_threaded_mainloop_lock = (ma_proc)_pa_threaded_mainloop_lock; + pContext->pulse.pa_threaded_mainloop_unlock = (ma_proc)_pa_threaded_mainloop_unlock; + pContext->pulse.pa_threaded_mainloop_wait = (ma_proc)_pa_threaded_mainloop_wait; + pContext->pulse.pa_threaded_mainloop_signal = (ma_proc)_pa_threaded_mainloop_signal; + pContext->pulse.pa_threaded_mainloop_accept = (ma_proc)_pa_threaded_mainloop_accept; + pContext->pulse.pa_threaded_mainloop_get_retval = (ma_proc)_pa_threaded_mainloop_get_retval; + pContext->pulse.pa_threaded_mainloop_get_api = (ma_proc)_pa_threaded_mainloop_get_api; + pContext->pulse.pa_threaded_mainloop_in_thread = (ma_proc)_pa_threaded_mainloop_in_thread; + pContext->pulse.pa_threaded_mainloop_set_name = (ma_proc)_pa_threaded_mainloop_set_name; + pContext->pulse.pa_context_new = (ma_proc)_pa_context_new; + pContext->pulse.pa_context_unref = (ma_proc)_pa_context_unref; + pContext->pulse.pa_context_connect = (ma_proc)_pa_context_connect; + pContext->pulse.pa_context_disconnect = (ma_proc)_pa_context_disconnect; + pContext->pulse.pa_context_set_state_callback = (ma_proc)_pa_context_set_state_callback; + pContext->pulse.pa_context_get_state = (ma_proc)_pa_context_get_state; + pContext->pulse.pa_context_get_sink_info_list = (ma_proc)_pa_context_get_sink_info_list; + pContext->pulse.pa_context_get_source_info_list = (ma_proc)_pa_context_get_source_info_list; + pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)_pa_context_get_sink_info_by_name; + pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name; + pContext->pulse.pa_operation_unref = (ma_proc)_pa_operation_unref; + pContext->pulse.pa_operation_get_state = (ma_proc)_pa_operation_get_state; + pContext->pulse.pa_channel_map_init_extend = (ma_proc)_pa_channel_map_init_extend; + pContext->pulse.pa_channel_map_valid = (ma_proc)_pa_channel_map_valid; + pContext->pulse.pa_channel_map_compatible = (ma_proc)_pa_channel_map_compatible; + pContext->pulse.pa_stream_new = (ma_proc)_pa_stream_new; + pContext->pulse.pa_stream_unref = (ma_proc)_pa_stream_unref; + pContext->pulse.pa_stream_connect_playback = (ma_proc)_pa_stream_connect_playback; + pContext->pulse.pa_stream_connect_record = (ma_proc)_pa_stream_connect_record; + pContext->pulse.pa_stream_disconnect = (ma_proc)_pa_stream_disconnect; + pContext->pulse.pa_stream_get_state = (ma_proc)_pa_stream_get_state; + pContext->pulse.pa_stream_get_sample_spec = (ma_proc)_pa_stream_get_sample_spec; + pContext->pulse.pa_stream_get_channel_map = (ma_proc)_pa_stream_get_channel_map; + pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)_pa_stream_get_buffer_attr; + pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)_pa_stream_set_buffer_attr; + 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; + pContext->pulse.pa_stream_cork = (ma_proc)_pa_stream_cork; + pContext->pulse.pa_stream_trigger = (ma_proc)_pa_stream_trigger; + pContext->pulse.pa_stream_begin_write = (ma_proc)_pa_stream_begin_write; + pContext->pulse.pa_stream_write = (ma_proc)_pa_stream_write; + pContext->pulse.pa_stream_peek = (ma_proc)_pa_stream_peek; + pContext->pulse.pa_stream_drop = (ma_proc)_pa_stream_drop; + pContext->pulse.pa_stream_writable_size = (ma_proc)_pa_stream_writable_size; + 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); + #ifndef MA_NO_RUNTIME_LINKING + ma_dlclose(ma_context_get_log(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; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__pulse; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__pulse; + pCallbacks->onDeviceInit = ma_device_init__pulse; + pCallbacks->onDeviceUninit = ma_device_uninit__pulse; + pCallbacks->onDeviceStart = ma_device_start__pulse; + pCallbacks->onDeviceStop = ma_device_stop__pulse; + pCallbacks->onDeviceRead = NULL; /* Not used because we're implementing onDeviceDataLoop. */ + pCallbacks->onDeviceWrite = NULL; /* Not used because we're implementing onDeviceDataLoop. */ + pCallbacks->onDeviceDataLoop = ma_device_data_loop__pulse; + pCallbacks->onDeviceDataLoopWakeup = ma_device_data_loop_wakeup__pulse; + + return MA_SUCCESS; +} +#endif + + +/****************************************************************************** + +JACK Backend + +******************************************************************************/ +#ifdef MA_HAS_JACK + +/* It is assumed jack.h is available when compile-time linking is being used. */ +#ifdef MA_NO_RUNTIME_LINKING +#include + +typedef jack_nframes_t ma_jack_nframes_t; +typedef jack_options_t ma_jack_options_t; +typedef jack_status_t ma_jack_status_t; +typedef jack_client_t ma_jack_client_t; +typedef jack_port_t ma_jack_port_t; +typedef JackProcessCallback ma_JackProcessCallback; +typedef JackBufferSizeCallback ma_JackBufferSizeCallback; +typedef JackShutdownCallback ma_JackShutdownCallback; +#define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE +#define ma_JackNoStartServer JackNoStartServer +#define ma_JackPortIsInput JackPortIsInput +#define ma_JackPortIsOutput JackPortIsOutput +#define ma_JackPortIsPhysical JackPortIsPhysical +#else +typedef ma_uint32 ma_jack_nframes_t; +typedef int ma_jack_options_t; +typedef int ma_jack_status_t; +typedef struct ma_jack_client_t ma_jack_client_t; +typedef struct ma_jack_port_t ma_jack_port_t; +typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg); +typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg); +typedef void (* ma_JackShutdownCallback) (void* arg); +#define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio" +#define ma_JackNoStartServer 1 +#define ma_JackPortIsInput 1 +#define ma_JackPortIsOutput 2 +#define ma_JackPortIsPhysical 4 +#endif + +typedef ma_jack_client_t* (* ma_jack_client_open_proc) (const char* client_name, ma_jack_options_t options, ma_jack_status_t* status, ...); +typedef int (* ma_jack_client_close_proc) (ma_jack_client_t* client); +typedef int (* ma_jack_client_name_size_proc) (void); +typedef int (* ma_jack_set_process_callback_proc) (ma_jack_client_t* client, ma_JackProcessCallback process_callback, void* arg); +typedef int (* ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t* client, ma_JackBufferSizeCallback bufsize_callback, void* arg); +typedef void (* ma_jack_on_shutdown_proc) (ma_jack_client_t* client, ma_JackShutdownCallback function, void* arg); +typedef ma_jack_nframes_t (* ma_jack_get_sample_rate_proc) (ma_jack_client_t* client); +typedef ma_jack_nframes_t (* ma_jack_get_buffer_size_proc) (ma_jack_client_t* client); +typedef const char** (* ma_jack_get_ports_proc) (ma_jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags); +typedef int (* ma_jack_activate_proc) (ma_jack_client_t* client); +typedef int (* ma_jack_deactivate_proc) (ma_jack_client_t* client); +typedef int (* ma_jack_connect_proc) (ma_jack_client_t* client, const char* source_port, const char* destination_port); +typedef ma_jack_port_t* (* ma_jack_port_register_proc) (ma_jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); +typedef const char* (* ma_jack_port_name_proc) (const ma_jack_port_t* port); +typedef void* (* ma_jack_port_get_buffer_proc) (ma_jack_port_t* port, ma_jack_nframes_t nframes); +typedef void (* ma_jack_free_proc) (void* ptr); + +static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t** ppClient) +{ + size_t maxClientNameSize; + char clientName[256]; + ma_jack_status_t status; + ma_jack_client_t* pClient; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppClient != NULL); + + if (ppClient) { + *ppClient = NULL; + } + + maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */ + ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1); + + pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL); + if (pClient == NULL) { + return MA_FAILED_TO_OPEN_BACKEND_DEVICE; + } + + if (ppClient) { + *ppClient = pClient; + } + + return MA_SUCCESS; +} + + +static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 cbResult = MA_TRUE; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Playback. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; /* JACK only uses default devices. */ + cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + + /* Capture. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; /* JACK only uses default devices. */ + cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + + (void)cbResult; /* For silencing a static analysis warning. */ + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_jack_client_t* pClient; + ma_result result; + const char** ppPorts; + + MA_ASSERT(pContext != NULL); + + if (pDeviceID != NULL && pDeviceID->jack != 0) { + return MA_NO_DEVICE; /* Don't know the device. */ + } + + /* Name / Description */ + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + + /* Jack only uses default devices. */ + pDeviceInfo->isDefault = MA_TRUE; + + /* Jack only supports f32 and has a specific channel count and sample rate. */ + pDeviceInfo->nativeDataFormats[0].format = ma_format_f32; + + /* 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; + } + + pDeviceInfo->nativeDataFormats[0].sampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient); + pDeviceInfo->nativeDataFormats[0].channels = 0; + + 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; + } + + while (ppPorts[pDeviceInfo->nativeDataFormats[0].channels] != NULL) { + pDeviceInfo->nativeDataFormats[0].channels += 1; + } + + pDeviceInfo->nativeDataFormats[0].flags = 0; + pDeviceInfo->nativeDataFormatCount = 1; + + ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts); + ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient); + + (void)pContext; + return MA_SUCCESS; +} + + +static ma_result ma_device_uninit__jack(ma_device* pDevice) +{ + ma_context* pContext; + + MA_ASSERT(pDevice != NULL); + + pContext = pDevice->pContext; + MA_ASSERT(pContext != NULL); + + if (pDevice->jack.pClient != NULL) { + ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient); + } + + 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); + } + + 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); + } + + return MA_SUCCESS; +} + +static void ma_device__jack_shutdown_callback(void* pUserData) +{ + /* JACK died. Stop the device. */ + ma_device* pDevice = (ma_device*)pUserData; + MA_ASSERT(pDevice != NULL); + + ma_device_stop(pDevice); +} + +static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + MA_ASSERT(pDevice != NULL); + + 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); + if (pNewBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks); + + pDevice->jack.pIntermediaryBufferCapture = pNewBuffer; + pDevice->playback.internalPeriodSizeInFrames = frameCount; + } + + 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); + if (pNewBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks); + + pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer; + pDevice->playback.internalPeriodSizeInFrames = frameCount; + } + + return 0; +} + +static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData) +{ + ma_device* pDevice; + ma_context* pContext; + ma_uint32 iChannel; + + pDevice = (ma_device*)pUserData; + MA_ASSERT(pDevice != NULL); + + pContext = pDevice->pContext; + MA_ASSERT(pContext != NULL); + + 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); + if (pSrc != NULL) { + float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel; + ma_jack_nframes_t iFrame; + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + *pDst = *pSrc; + + pDst += pDevice->capture.internalChannels; + pSrc += 1; + } + } + } + + ma_device_handle_backend_data_callback(pDevice, NULL, pDevice->jack.pIntermediaryBufferCapture, frameCount); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_device_handle_backend_data_callback(pDevice, pDevice->jack.pIntermediaryBufferPlayback, NULL, frameCount); + + /* 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); + if (pDst != NULL) { + const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel; + ma_jack_nframes_t iFrame; + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + *pDst = *pSrc; + + pDst += 1; + pSrc += pDevice->playback.internalChannels; + } + } + } + } + + return 0; +} + +static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + ma_uint32 periodSizeInFrames; + + MA_ASSERT(pConfig != NULL); + 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; + } + + /* 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; + } + 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; + } + + ((ma_jack_on_shutdown_proc)pDevice->pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice); + + + /* The buffer size in frames can change. */ + 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); + + 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; + } + + /* 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" */ + + 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) { + ((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; + } + } + + ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); + + 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); + if (pDevice->jack.pIntermediaryBufferCapture == NULL) { + ma_device_uninit__jack(pDevice); + return MA_OUT_OF_MEMORY; + } + } + + 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); + + 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; + } + + /* 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" */ + + 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) { + ((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; + } + } + + ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts); + + 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); + if (pDevice->jack.pIntermediaryBufferPlayback == NULL) { + ma_device_uninit__jack(pDevice); + return MA_OUT_OF_MEMORY; + } + } + + return MA_SUCCESS; +} + + +static ma_result ma_device_start__jack(ma_device* pDevice) +{ + ma_context* pContext = pDevice->pContext; + int resultJACK; + size_t i; + + 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; + } + + 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; + } + + 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]); + + 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; + } + } + + ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); + } + + if (pDevice->type == ma_device_type_playback || 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_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; + } + + 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]); + + 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; + } + } + + ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__jack(ma_device* pDevice) +{ + ma_context* pContext = pDevice->pContext; + + 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; + } + + ma_device__on_notification_stopped(pDevice); + + return MA_SUCCESS; +} + + +static ma_result ma_context_uninit__jack(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_jack); + + ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks); + pContext->jack.pClientName = NULL; + +#ifndef MA_NO_RUNTIME_LINKING + ma_dlclose(ma_context_get_log(pContext), pContext->jack.jackSO); +#endif + + return MA_SUCCESS; +} + +static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ +#ifndef MA_NO_RUNTIME_LINKING + const char* libjackNames[] = { +#if defined(MA_WIN32) + "libjack.dll", + "libjack64.dll" +#endif +#if defined(MA_UNIX) + "libjack.so", + "libjack.so.0" +#endif + }; + size_t i; + + for (i = 0; i < ma_countof(libjackNames); ++i) { + pContext->jack.jackSO = ma_dlopen(ma_context_get_log(pContext), libjackNames[i]); + if (pContext->jack.jackSO != NULL) { + break; + } + } + + if (pContext->jack.jackSO == NULL) { + 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"); +#else + /* + This strange assignment system is here just to ensure type safety of miniaudio's function pointer + types. If anything differs slightly the compiler should throw a warning. + */ + ma_jack_client_open_proc _jack_client_open = jack_client_open; + ma_jack_client_close_proc _jack_client_close = jack_client_close; + ma_jack_client_name_size_proc _jack_client_name_size = jack_client_name_size; + ma_jack_set_process_callback_proc _jack_set_process_callback = jack_set_process_callback; + ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback = jack_set_buffer_size_callback; + ma_jack_on_shutdown_proc _jack_on_shutdown = jack_on_shutdown; + ma_jack_get_sample_rate_proc _jack_get_sample_rate = jack_get_sample_rate; + ma_jack_get_buffer_size_proc _jack_get_buffer_size = jack_get_buffer_size; + ma_jack_get_ports_proc _jack_get_ports = jack_get_ports; + ma_jack_activate_proc _jack_activate = jack_activate; + ma_jack_deactivate_proc _jack_deactivate = jack_deactivate; + ma_jack_connect_proc _jack_connect = jack_connect; + ma_jack_port_register_proc _jack_port_register = jack_port_register; + ma_jack_port_name_proc _jack_port_name = jack_port_name; + ma_jack_port_get_buffer_proc _jack_port_get_buffer = jack_port_get_buffer; + ma_jack_free_proc _jack_free = jack_free; + + pContext->jack.jack_client_open = (ma_proc)_jack_client_open; + pContext->jack.jack_client_close = (ma_proc)_jack_client_close; + pContext->jack.jack_client_name_size = (ma_proc)_jack_client_name_size; + pContext->jack.jack_set_process_callback = (ma_proc)_jack_set_process_callback; + pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback; + pContext->jack.jack_on_shutdown = (ma_proc)_jack_on_shutdown; + pContext->jack.jack_get_sample_rate = (ma_proc)_jack_get_sample_rate; + pContext->jack.jack_get_buffer_size = (ma_proc)_jack_get_buffer_size; + pContext->jack.jack_get_ports = (ma_proc)_jack_get_ports; + pContext->jack.jack_activate = (ma_proc)_jack_activate; + pContext->jack.jack_deactivate = (ma_proc)_jack_deactivate; + pContext->jack.jack_connect = (ma_proc)_jack_connect; + pContext->jack.jack_port_register = (ma_proc)_jack_port_register; + pContext->jack.jack_port_name = (ma_proc)_jack_port_name; + pContext->jack.jack_port_get_buffer = (ma_proc)_jack_port_get_buffer; + pContext->jack.jack_free = (ma_proc)_jack_free; +#endif + + if (pConfig->jack.pClientName != NULL) { + pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName, &pContext->allocationCallbacks); + } + pContext->jack.tryStartServer = pConfig->jack.tryStartServer; + + /* + Getting here means the JACK library is installed, but it doesn't necessarily mean it's usable. We need to quickly test this by connecting + a temporary client. + */ + { + ma_jack_client_t* pDummyClient; + ma_result result = ma_context_open_client__jack(pContext, &pDummyClient); + 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); + #endif + return MA_NO_BACKEND; + } + + ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient); + } + + + pCallbacks->onContextInit = ma_context_init__jack; + pCallbacks->onContextUninit = ma_context_uninit__jack; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__jack; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__jack; + pCallbacks->onDeviceInit = ma_device_init__jack; + pCallbacks->onDeviceUninit = ma_device_uninit__jack; + pCallbacks->onDeviceStart = ma_device_start__jack; + pCallbacks->onDeviceStop = ma_device_stop__jack; + pCallbacks->onDeviceRead = NULL; /* Not used because JACK is asynchronous. */ + pCallbacks->onDeviceWrite = NULL; /* Not used because JACK is asynchronous. */ + pCallbacks->onDeviceDataLoop = NULL; /* Not used because JACK is asynchronous. */ + + return MA_SUCCESS; +} +#endif /* MA_HAS_JACK */ + + + +/****************************************************************************** + +Core Audio Backend + +References +========== +- Technical Note TN2091: Device input using the HAL Output Audio Unit + https://developer.apple.com/library/archive/technotes/tn2091/_index.html + +******************************************************************************/ +#ifdef MA_HAS_COREAUDIO +#include + +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 + #define MA_APPLE_MOBILE + #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + #define MA_APPLE_TV + #endif + #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 + +#if defined(MA_APPLE_DESKTOP) +#include +#else +#include +#endif + +#include + +/* CoreFoundation */ +typedef Boolean (* ma_CFStringGetCString_proc)(CFStringRef theString, char* buffer, CFIndex bufferSize, CFStringEncoding encoding); +typedef void (* ma_CFRelease_proc)(CFTypeRef cf); + +/* CoreAudio */ +#if defined(MA_APPLE_DESKTOP) +typedef OSStatus (* ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* ioDataSize, void* outData); +typedef OSStatus (* ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize); +typedef OSStatus (* ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData); +typedef OSStatus (* ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData); +typedef OSStatus (* ma_AudioObjectRemovePropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData); +#endif + +/* AudioToolbox */ +typedef AudioComponent (* ma_AudioComponentFindNext_proc)(AudioComponent inComponent, const AudioComponentDescription* inDesc); +typedef OSStatus (* ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance); +typedef OSStatus (* ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent, AudioComponentInstance* outInstance); +typedef OSStatus (* ma_AudioOutputUnitStart_proc)(AudioUnit inUnit); +typedef OSStatus (* ma_AudioOutputUnitStop_proc)(AudioUnit inUnit); +typedef OSStatus (* ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcUserData); +typedef OSStatus (* ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32* outDataSize, Boolean* outWriteable); +typedef OSStatus (* ma_AudioUnitGetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData, UInt32* ioDataSize); +typedef OSStatus (* ma_AudioUnitSetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize); +typedef OSStatus (* ma_AudioUnitInitialize_proc)(AudioUnit inUnit); +typedef OSStatus (* ma_AudioUnitRender_proc)(AudioUnit inUnit, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData); + + +#define MA_COREAUDIO_OUTPUT_BUS 0 +#define MA_COREAUDIO_INPUT_BUS 1 + +#if defined(MA_APPLE_DESKTOP) +static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit); +#endif + +/* +Core Audio + +So far, Core Audio has been the worst backend to work with due to being both unintuitive and having almost no documentation +apart from comments in the headers (which admittedly are quite good). For my own purposes, and for anybody out there whose +needing to figure out how this darn thing works, I'm going to outline a few things here. + +Since miniaudio is a fairly low-level API, one of the things it needs is control over specific devices, and it needs to be +able to identify whether or not it can be used as playback and/or capture. The AudioObject API is the only one I've seen +that supports this level of detail. There was some public domain sample code I stumbled across that used the AudioComponent +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 +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 +the central APIs for retrieving information about the system and specific devices. + +To use the AudioObjectGetPropertyData() API you need to use the notion of a property address. A property address is a +structure with three variables and is used to identify which property you are getting or setting. The first is the "selector" +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. + +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 +address with the kAudioHardwarePropertyDevices selector and the kAudioObjectPropertyScopeGlobal scope. Once you have the +size, allocate a block of memory of that size and then call AudioObjectGetPropertyData(). The data is just a list of +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) + { + case noErr: return MA_SUCCESS; + #if defined(MA_APPLE_DESKTOP) + case kAudioHardwareNotRunningError: return MA_DEVICE_NOT_STARTED; + case kAudioHardwareUnspecifiedError: return MA_ERROR; + case kAudioHardwareUnknownPropertyError: return MA_INVALID_ARGS; + case kAudioHardwareBadPropertySizeError: return MA_INVALID_OPERATION; + case kAudioHardwareIllegalOperationError: return MA_INVALID_OPERATION; + case kAudioHardwareBadObjectError: return MA_INVALID_ARGS; + case kAudioHardwareBadDeviceError: return MA_INVALID_ARGS; + case kAudioHardwareBadStreamError: return MA_INVALID_ARGS; + case kAudioHardwareUnsupportedOperationError: return MA_INVALID_OPERATION; + case kAudioDeviceUnsupportedFormatError: return MA_FORMAT_NOT_SUPPORTED; + case kAudioDevicePermissionsError: return MA_ACCESS_DENIED; + #endif + default: return MA_ERROR; + } +} + +#if 0 +static ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit) +{ + switch (bit) + { + case kAudioChannelBit_Left: return MA_CHANNEL_LEFT; + case kAudioChannelBit_Right: return MA_CHANNEL_RIGHT; + case kAudioChannelBit_Center: return MA_CHANNEL_FRONT_CENTER; + case kAudioChannelBit_LFEScreen: return MA_CHANNEL_LFE; + case kAudioChannelBit_LeftSurround: return MA_CHANNEL_BACK_LEFT; + case kAudioChannelBit_RightSurround: return MA_CHANNEL_BACK_RIGHT; + case kAudioChannelBit_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER; + case kAudioChannelBit_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case kAudioChannelBit_CenterSurround: return MA_CHANNEL_BACK_CENTER; + case kAudioChannelBit_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT; + case kAudioChannelBit_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT; + case kAudioChannelBit_TopCenterSurround: return MA_CHANNEL_TOP_CENTER; + case kAudioChannelBit_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT; + case kAudioChannelBit_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER; + case kAudioChannelBit_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT; + case kAudioChannelBit_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT; + case kAudioChannelBit_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER; + case kAudioChannelBit_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT; + default: return MA_CHANNEL_NONE; + } +} +#endif + +static ma_result ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription* pDescription, ma_format* pFormatOut) +{ + MA_ASSERT(pDescription != NULL); + MA_ASSERT(pFormatOut != NULL); + + *pFormatOut = ma_format_unknown; /* Safety. */ + + /* There's a few things miniaudio doesn't support. */ + if (pDescription->mFormatID != kAudioFormatLinearPCM) { + return MA_FORMAT_NOT_SUPPORTED; + } + + /* We don't support any non-packed formats that are aligned high. */ + if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) != 0) { + return MA_FORMAT_NOT_SUPPORTED; + } + + /* Only supporting native-endian. */ + if ((ma_is_little_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) || (ma_is_big_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) == 0)) { + return MA_FORMAT_NOT_SUPPORTED; + } + + /* We are not currently supporting non-interleaved formats (this will be added in a future version of miniaudio). */ + /*if ((pDescription->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) { + return MA_FORMAT_NOT_SUPPORTED; + }*/ + + if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) { + if (pDescription->mBitsPerChannel == 32) { + *pFormatOut = ma_format_f32; + return MA_SUCCESS; + } + } else { + if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) { + if (pDescription->mBitsPerChannel == 16) { + *pFormatOut = ma_format_s16; + return MA_SUCCESS; + } else if (pDescription->mBitsPerChannel == 24) { + if (pDescription->mBytesPerFrame == (pDescription->mBitsPerChannel/8 * pDescription->mChannelsPerFrame)) { + *pFormatOut = ma_format_s24; + return MA_SUCCESS; + } else { + if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame == sizeof(ma_int32)) { + /* TODO: Implement ma_format_s24_32. */ + /**pFormatOut = ma_format_s24_32;*/ + /*return MA_SUCCESS;*/ + return MA_FORMAT_NOT_SUPPORTED; + } + } + } else if (pDescription->mBitsPerChannel == 32) { + *pFormatOut = ma_format_s32; + return MA_SUCCESS; + } + } else { + if (pDescription->mBitsPerChannel == 8) { + *pFormatOut = ma_format_u8; + return MA_SUCCESS; + } + } + } + + /* Getting here means the format is not supported. */ + return MA_FORMAT_NOT_SUPPORTED; +} + +#if defined(MA_APPLE_DESKTOP) +static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label) +{ + switch (label) + { + case kAudioChannelLabel_Unknown: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Unused: return MA_CHANNEL_NONE; + case kAudioChannelLabel_UseCoordinates: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Left: return MA_CHANNEL_LEFT; + case kAudioChannelLabel_Right: return MA_CHANNEL_RIGHT; + case kAudioChannelLabel_Center: return MA_CHANNEL_FRONT_CENTER; + case kAudioChannelLabel_LFEScreen: return MA_CHANNEL_LFE; + case kAudioChannelLabel_LeftSurround: return MA_CHANNEL_BACK_LEFT; + case kAudioChannelLabel_RightSurround: return MA_CHANNEL_BACK_RIGHT; + case kAudioChannelLabel_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER; + case kAudioChannelLabel_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case kAudioChannelLabel_CenterSurround: return MA_CHANNEL_BACK_CENTER; + case kAudioChannelLabel_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT; + case kAudioChannelLabel_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT; + case kAudioChannelLabel_TopCenterSurround: return MA_CHANNEL_TOP_CENTER; + case kAudioChannelLabel_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT; + case kAudioChannelLabel_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER; + case kAudioChannelLabel_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT; + case kAudioChannelLabel_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT; + case kAudioChannelLabel_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER; + case kAudioChannelLabel_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT; + case kAudioChannelLabel_RearSurroundLeft: return MA_CHANNEL_BACK_LEFT; + case kAudioChannelLabel_RearSurroundRight: return MA_CHANNEL_BACK_RIGHT; + case kAudioChannelLabel_LeftWide: return MA_CHANNEL_SIDE_LEFT; + case kAudioChannelLabel_RightWide: return MA_CHANNEL_SIDE_RIGHT; + case kAudioChannelLabel_LFE2: return MA_CHANNEL_LFE; + case kAudioChannelLabel_LeftTotal: return MA_CHANNEL_LEFT; + case kAudioChannelLabel_RightTotal: return MA_CHANNEL_RIGHT; + case kAudioChannelLabel_HearingImpaired: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Narration: return MA_CHANNEL_MONO; + case kAudioChannelLabel_Mono: return MA_CHANNEL_MONO; + case kAudioChannelLabel_DialogCentricMix: return MA_CHANNEL_MONO; + case kAudioChannelLabel_CenterSurroundDirect: return MA_CHANNEL_BACK_CENTER; + case kAudioChannelLabel_Haptic: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Ambisonic_W: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Ambisonic_X: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Ambisonic_Y: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Ambisonic_Z: return MA_CHANNEL_NONE; + case kAudioChannelLabel_MS_Mid: return MA_CHANNEL_LEFT; + case kAudioChannelLabel_MS_Side: return MA_CHANNEL_RIGHT; + case kAudioChannelLabel_XY_X: return MA_CHANNEL_LEFT; + case kAudioChannelLabel_XY_Y: return MA_CHANNEL_RIGHT; + case kAudioChannelLabel_HeadphonesLeft: return MA_CHANNEL_LEFT; + case kAudioChannelLabel_HeadphonesRight: return MA_CHANNEL_RIGHT; + case kAudioChannelLabel_ClickTrack: return MA_CHANNEL_NONE; + case kAudioChannelLabel_ForeignLanguage: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Discrete: return MA_CHANNEL_NONE; + case kAudioChannelLabel_Discrete_0: return MA_CHANNEL_AUX_0; + case kAudioChannelLabel_Discrete_1: return MA_CHANNEL_AUX_1; + case kAudioChannelLabel_Discrete_2: return MA_CHANNEL_AUX_2; + case kAudioChannelLabel_Discrete_3: return MA_CHANNEL_AUX_3; + case kAudioChannelLabel_Discrete_4: return MA_CHANNEL_AUX_4; + case kAudioChannelLabel_Discrete_5: return MA_CHANNEL_AUX_5; + case kAudioChannelLabel_Discrete_6: return MA_CHANNEL_AUX_6; + case kAudioChannelLabel_Discrete_7: return MA_CHANNEL_AUX_7; + case kAudioChannelLabel_Discrete_8: return MA_CHANNEL_AUX_8; + case kAudioChannelLabel_Discrete_9: return MA_CHANNEL_AUX_9; + case kAudioChannelLabel_Discrete_10: return MA_CHANNEL_AUX_10; + case kAudioChannelLabel_Discrete_11: return MA_CHANNEL_AUX_11; + case kAudioChannelLabel_Discrete_12: return MA_CHANNEL_AUX_12; + case kAudioChannelLabel_Discrete_13: return MA_CHANNEL_AUX_13; + case kAudioChannelLabel_Discrete_14: return MA_CHANNEL_AUX_14; + case kAudioChannelLabel_Discrete_15: return MA_CHANNEL_AUX_15; + case kAudioChannelLabel_Discrete_65535: return MA_CHANNEL_NONE; + + #if 0 /* Introduced in a later version of macOS. */ + case kAudioChannelLabel_HOA_ACN: return MA_CHANNEL_NONE; + case kAudioChannelLabel_HOA_ACN_0: return MA_CHANNEL_AUX_0; + case kAudioChannelLabel_HOA_ACN_1: return MA_CHANNEL_AUX_1; + case kAudioChannelLabel_HOA_ACN_2: return MA_CHANNEL_AUX_2; + case kAudioChannelLabel_HOA_ACN_3: return MA_CHANNEL_AUX_3; + case kAudioChannelLabel_HOA_ACN_4: return MA_CHANNEL_AUX_4; + case kAudioChannelLabel_HOA_ACN_5: return MA_CHANNEL_AUX_5; + case kAudioChannelLabel_HOA_ACN_6: return MA_CHANNEL_AUX_6; + case kAudioChannelLabel_HOA_ACN_7: return MA_CHANNEL_AUX_7; + case kAudioChannelLabel_HOA_ACN_8: return MA_CHANNEL_AUX_8; + case kAudioChannelLabel_HOA_ACN_9: return MA_CHANNEL_AUX_9; + case kAudioChannelLabel_HOA_ACN_10: return MA_CHANNEL_AUX_10; + case kAudioChannelLabel_HOA_ACN_11: return MA_CHANNEL_AUX_11; + case kAudioChannelLabel_HOA_ACN_12: return MA_CHANNEL_AUX_12; + case kAudioChannelLabel_HOA_ACN_13: return MA_CHANNEL_AUX_13; + case kAudioChannelLabel_HOA_ACN_14: return MA_CHANNEL_AUX_14; + case kAudioChannelLabel_HOA_ACN_15: return MA_CHANNEL_AUX_15; + case kAudioChannelLabel_HOA_ACN_65024: return MA_CHANNEL_NONE; + #endif + + default: return MA_CHANNEL_NONE; + } +} + +static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel* pChannelMap, size_t channelMapCap) +{ + MA_ASSERT(pChannelLayout != NULL); + + if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { + UInt32 iChannel; + for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) { + pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel); + } + } else +#if 0 + if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { + /* This is the same kind of system that's used by Windows audio APIs. */ + UInt32 iChannel = 0; + UInt32 iBit; + AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap; + for (iBit = 0; iBit < 32 && iChannel < channelMapCap; ++iBit) { + AudioChannelBitmap bit = bitmap & (1 << iBit); + if (bit != 0) { + pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit); + } + } + } else +#endif + { + /* + Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should + be updated to determine the mapping based on the tag. + */ + UInt32 channelCount; + + /* Our channel map retrieval APIs below take 32-bit integers, so we'll want to clamp the channel map capacity. */ + if (channelMapCap > 0xFFFFFFFF) { + channelMapCap = 0xFFFFFFFF; + } + + channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), (UInt32)channelMapCap); + + switch (pChannelLayout->mChannelLayoutTag) + { + case kAudioChannelLayoutTag_Mono: + case kAudioChannelLayoutTag_Stereo: + case kAudioChannelLayoutTag_StereoHeadphones: + case kAudioChannelLayoutTag_MatrixStereo: + case kAudioChannelLayoutTag_MidSide: + case kAudioChannelLayoutTag_XY: + case kAudioChannelLayoutTag_Binaural: + case kAudioChannelLayoutTag_Ambisonic_B_Format: + { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); + } break; + + case kAudioChannelLayoutTag_Octagonal: + { + pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT; + pChannelMap[6] = MA_CHANNEL_SIDE_LEFT; + } MA_FALLTHROUGH; /* Intentional fallthrough. */ + case kAudioChannelLayoutTag_Hexagonal: + { + pChannelMap[5] = MA_CHANNEL_BACK_CENTER; + } MA_FALLTHROUGH; /* Intentional fallthrough. */ + case kAudioChannelLayoutTag_Pentagonal: + { + pChannelMap[4] = MA_CHANNEL_FRONT_CENTER; + } MA_FALLTHROUGH; /* Intentional fallthrough. */ + case kAudioChannelLayoutTag_Quadraphonic: + { + pChannelMap[3] = MA_CHANNEL_BACK_RIGHT; + pChannelMap[2] = MA_CHANNEL_BACK_LEFT; + pChannelMap[1] = MA_CHANNEL_RIGHT; + pChannelMap[0] = MA_CHANNEL_LEFT; + } break; + + /* TODO: Add support for more tags here. */ + + default: + { + ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount); + } break; + } + } + + 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; + UInt32 deviceObjectsDataSize; + OSStatus status; + AudioObjectID* pDeviceObjectIDs; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceCount != NULL); + MA_ASSERT(ppDeviceObjectIDs != NULL); + + /* Safety. */ + *pDeviceCount = 0; + *ppDeviceObjectIDs = NULL; + + propAddressDevices.mSelector = kAudioHardwarePropertyDevices; + propAddressDevices.mScope = kAudioObjectPropertyScopeGlobal; + propAddressDevices.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + pDeviceObjectIDs = (AudioObjectID*)ma_malloc(deviceObjectsDataSize, &pContext->allocationCallbacks); + if (pDeviceObjectIDs == NULL) { + return MA_OUT_OF_MEMORY; + } + + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize, pDeviceObjectIDs); + if (status != noErr) { + ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks); + return ma_result_from_OSStatus(status); + } + + *pDeviceCount = deviceObjectsDataSize / sizeof(AudioObjectID); + *ppDeviceObjectIDs = pDeviceObjectIDs; + + return MA_SUCCESS; +} + +static ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, AudioObjectID objectID, CFStringRef* pUID) +{ + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + + MA_ASSERT(pContext != NULL); + + propAddress.mSelector = kAudioDevicePropertyDeviceUID; + propAddress.mScope = kAudioObjectPropertyScopeGlobal; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + dataSize = sizeof(*pUID); + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + return MA_SUCCESS; +} + +static ma_result ma_get_AudioObject_uid(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut) +{ + CFStringRef uid; + ma_result result; + + MA_ASSERT(pContext != NULL); + + result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid); + if (result != MA_SUCCESS) { + return result; + } + + if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) { + return MA_ERROR; + } + + ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(uid); + return MA_SUCCESS; +} + +static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut) +{ + AudioObjectPropertyAddress propAddress; + CFStringRef deviceName = NULL; + UInt32 dataSize; + OSStatus status; + + MA_ASSERT(pContext != NULL); + + propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; + propAddress.mScope = kAudioObjectPropertyScopeGlobal; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + dataSize = sizeof(deviceName); + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) { + return MA_ERROR; + } + + ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(deviceName); + return MA_SUCCESS; +} + +static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope) +{ + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + AudioBufferList* pBufferList; + ma_bool32 isSupported; + + MA_ASSERT(pContext != NULL); + + /* 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; + + 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); + 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); + return MA_FALSE; + } + + isSupported = MA_FALSE; + if (pBufferList->mNumberBuffers > 0) { + isSupported = MA_TRUE; + } + + ma_free(pBufferList, &pContext->allocationCallbacks); + return isSupported; +} + +static ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID) +{ + return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput); +} + +static ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID) +{ + return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput); +} + + +static ma_result ma_get_AudioObject_stream_descriptions(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pDescriptionCount, AudioStreamRangedDescription** ppDescriptions) /* NOTE: Free the returned pointer with ma_free(). */ +{ + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + AudioStreamRangedDescription* pDescriptions; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDescriptionCount != NULL); + MA_ASSERT(ppDescriptions != NULL); + + /* + TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My + MacBook Pro uses s24/32 format, however, which miniaudio does not currently support. + */ + propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/ + propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize, &pContext->allocationCallbacks); + if (pDescriptions == NULL) { + return MA_OUT_OF_MEMORY; + } + + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions); + if (status != noErr) { + ma_free(pDescriptions, &pContext->allocationCallbacks); + return ma_result_from_OSStatus(status); + } + + *pDescriptionCount = dataSize / sizeof(*pDescriptions); + *ppDescriptions = pDescriptions; + return MA_SUCCESS; +} + + +static ma_result ma_get_AudioObject_channel_layout(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, AudioChannelLayout** ppChannelLayout) /* NOTE: Free the returned pointer with ma_free(). */ +{ + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + AudioChannelLayout* pChannelLayout; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(ppChannelLayout != NULL); + + *ppChannelLayout = NULL; /* Safety. */ + + propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout; + propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + pChannelLayout = (AudioChannelLayout*)ma_malloc(dataSize, &pContext->allocationCallbacks); + if (pChannelLayout == NULL) { + return MA_OUT_OF_MEMORY; + } + + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pChannelLayout); + if (status != noErr) { + ma_free(pChannelLayout, &pContext->allocationCallbacks); + return ma_result_from_OSStatus(status); + } + + *ppChannelLayout = pChannelLayout; + return MA_SUCCESS; +} + +static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pChannelCount) +{ + AudioChannelLayout* pChannelLayout; + ma_result result; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pChannelCount != NULL); + + *pChannelCount = 0; /* Safety. */ + + result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout); + if (result != MA_SUCCESS) { + return result; + } + + if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) { + *pChannelCount = pChannelLayout->mNumberChannelDescriptions; + } else if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { + *pChannelCount = ma_count_set_bits(pChannelLayout->mChannelBitmap); + } else { + *pChannelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag); + } + + ma_free(pChannelLayout, &pContext->allocationCallbacks); + return MA_SUCCESS; +} + +#if 0 +static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap) +{ + AudioChannelLayout* pChannelLayout; + ma_result result; + + MA_ASSERT(pContext != NULL); + + result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout); + if (result != MA_SUCCESS) { + return result; /* Rather than always failing here, would it be more robust to simply assume a default? */ + } + + result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap); + if (result != MA_SUCCESS) { + ma_free(pChannelLayout, &pContext->allocationCallbacks); + return result; + } + + ma_free(pChannelLayout, &pContext->allocationCallbacks); + return result; +} +#endif + +static ma_result ma_get_AudioObject_sample_rates(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pSampleRateRangesCount, AudioValueRange** ppSampleRateRanges) /* NOTE: Free the returned pointer with ma_free(). */ +{ + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + AudioValueRange* pSampleRateRanges; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pSampleRateRangesCount != NULL); + MA_ASSERT(ppSampleRateRanges != NULL); + + /* Safety. */ + *pSampleRateRangesCount = 0; + *ppSampleRateRanges = NULL; + + propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; + propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + pSampleRateRanges = (AudioValueRange*)ma_malloc(dataSize, &pContext->allocationCallbacks); + if (pSampleRateRanges == NULL) { + return MA_OUT_OF_MEMORY; + } + + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pSampleRateRanges); + if (status != noErr) { + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return ma_result_from_OSStatus(status); + } + + *pSampleRateRangesCount = dataSize / sizeof(*pSampleRateRanges); + *ppSampleRateRanges = pSampleRateRanges; + return MA_SUCCESS; +} + +#if 0 +static ma_result ma_get_AudioObject_get_closest_sample_rate(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 sampleRateIn, ma_uint32* pSampleRateOut) +{ + UInt32 sampleRateRangeCount; + AudioValueRange* pSampleRateRanges; + ma_result result; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pSampleRateOut != NULL); + + *pSampleRateOut = 0; /* Safety. */ + + result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges); + if (result != MA_SUCCESS) { + return result; + } + + if (sampleRateRangeCount == 0) { + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return MA_ERROR; /* Should never hit this case should we? */ + } + + if (sampleRateIn == 0) { + /* Search in order of miniaudio's preferred priority. */ + UInt32 iMALSampleRate; + for (iMALSampleRate = 0; iMALSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iMALSampleRate) { + ma_uint32 malSampleRate = g_maStandardSampleRatePriorities[iMALSampleRate]; + UInt32 iCASampleRate; + for (iCASampleRate = 0; iCASampleRate < sampleRateRangeCount; ++iCASampleRate) { + AudioValueRange caSampleRate = pSampleRateRanges[iCASampleRate]; + if (caSampleRate.mMinimum <= malSampleRate && caSampleRate.mMaximum >= malSampleRate) { + *pSampleRateOut = malSampleRate; + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return MA_SUCCESS; + } + } + } + + /* + If we get here it means none of miniaudio's standard sample rates matched any of the supported sample rates from the device. In this + case we just fall back to the first one reported by Core Audio. + */ + MA_ASSERT(sampleRateRangeCount > 0); + + *pSampleRateOut = pSampleRateRanges[0].mMinimum; + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return MA_SUCCESS; + } else { + /* Find the closest match to this sample rate. */ + UInt32 currentAbsoluteDifference = INT32_MAX; + UInt32 iCurrentClosestRange = (UInt32)-1; + UInt32 iRange; + for (iRange = 0; iRange < sampleRateRangeCount; ++iRange) { + if (pSampleRateRanges[iRange].mMinimum <= sampleRateIn && pSampleRateRanges[iRange].mMaximum >= sampleRateIn) { + *pSampleRateOut = sampleRateIn; + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return MA_SUCCESS; + } else { + UInt32 absoluteDifference; + if (pSampleRateRanges[iRange].mMinimum > sampleRateIn) { + absoluteDifference = pSampleRateRanges[iRange].mMinimum - sampleRateIn; + } else { + absoluteDifference = sampleRateIn - pSampleRateRanges[iRange].mMaximum; + } + + if (currentAbsoluteDifference > absoluteDifference) { + currentAbsoluteDifference = absoluteDifference; + iCurrentClosestRange = iRange; + } + } + } + + MA_ASSERT(iCurrentClosestRange != (UInt32)-1); + + *pSampleRateOut = pSampleRateRanges[iCurrentClosestRange].mMinimum; + ma_free(pSampleRateRanges, &pContext->allocationCallbacks); + return MA_SUCCESS; + } + + /* Should never get here, but it would mean we weren't able to find any suitable sample rates. */ + /*ma_free(pSampleRateRanges, &pContext->allocationCallbacks);*/ + /*return MA_ERROR;*/ +} +#endif + +static ma_result ma_get_AudioObject_closest_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 bufferSizeInFramesIn, ma_uint32* pBufferSizeInFramesOut) +{ + AudioObjectPropertyAddress propAddress; + AudioValueRange bufferSizeRange; + UInt32 dataSize; + OSStatus status; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pBufferSizeInFramesOut != NULL); + + *pBufferSizeInFramesOut = 0; /* Safety. */ + + propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange; + propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + dataSize = sizeof(bufferSizeRange); + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + /* This is just a clamp. */ + if (bufferSizeInFramesIn < bufferSizeRange.mMinimum) { + *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMinimum; + } else if (bufferSizeInFramesIn > bufferSizeRange.mMaximum) { + *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMaximum; + } else { + *pBufferSizeInFramesOut = bufferSizeInFramesIn; + } + + return MA_SUCCESS; +} + +static ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pPeriodSizeInOut) +{ + ma_result result; + ma_uint32 chosenBufferSizeInFrames; + AudioObjectPropertyAddress propAddress; + UInt32 dataSize; + OSStatus status; + + MA_ASSERT(pContext != NULL); + + result = ma_get_AudioObject_closest_buffer_size_in_frames(pContext, deviceObjectID, deviceType, *pPeriodSizeInOut, &chosenBufferSizeInFrames); + if (result != MA_SUCCESS) { + return result; + } + + /* 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; + + ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames); + + /* Get the actual size of the buffer. */ + dataSize = sizeof(*pPeriodSizeInOut); + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &chosenBufferSizeInFrames); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + *pPeriodSizeInOut = chosenBufferSizeInFrames; + return MA_SUCCESS; +} + +static ma_result ma_find_default_AudioObjectID(ma_context* pContext, ma_device_type deviceType, AudioObjectID* pDeviceObjectID) +{ + AudioObjectPropertyAddress propAddressDefaultDevice; + UInt32 defaultDeviceObjectIDSize = sizeof(AudioObjectID); + AudioObjectID defaultDeviceObjectID; + OSStatus status; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceObjectID != NULL); + + /* Safety. */ + *pDeviceObjectID = 0; + + propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal; + propAddressDefaultDevice.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + if (deviceType == ma_device_type_playback) { + propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + } else { + propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultInputDevice; + } + + defaultDeviceObjectIDSize = sizeof(AudioObjectID); + status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDefaultDevice, 0, NULL, &defaultDeviceObjectIDSize, &defaultDeviceObjectID); + if (status == noErr) { + *pDeviceObjectID = defaultDeviceObjectID; + return MA_SUCCESS; + } + + /* If we get here it means we couldn't find the device. */ + return MA_NO_DEVICE; +} + +static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, AudioObjectID* pDeviceObjectID) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceObjectID != NULL); + + /* Safety. */ + *pDeviceObjectID = 0; + + if (pDeviceID == NULL) { + /* Default device. */ + return ma_find_default_AudioObjectID(pContext, deviceType, pDeviceObjectID); + } else { + /* Explicit device. */ + UInt32 deviceCount; + AudioObjectID* pDeviceObjectIDs; + ma_result result; + UInt32 iDevice; + + result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs); + if (result != MA_SUCCESS) { + return result; + } + + for (iDevice = 0; iDevice < deviceCount; ++iDevice) { + AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice]; + + char uid[256]; + if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(uid), uid) != MA_SUCCESS) { + continue; + } + + if (deviceType == ma_device_type_playback) { + if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) { + if (strcmp(uid, pDeviceID->coreaudio) == 0) { + *pDeviceObjectID = deviceObjectID; + ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks); + return MA_SUCCESS; + } + } + } else { + if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) { + if (strcmp(uid, pDeviceID->coreaudio) == 0) { + *pDeviceObjectID = deviceObjectID; + ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks); + return MA_SUCCESS; + } + } + } + } + + ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks); + } + + /* If we get here it means we couldn't find the device. */ + return MA_NO_DEVICE; +} + + +static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const AudioStreamBasicDescription* pOrigFormat, AudioStreamBasicDescription* pFormat) +{ + UInt32 deviceFormatDescriptionCount; + AudioStreamRangedDescription* pDeviceFormatDescriptions; + ma_result result; + ma_uint32 desiredSampleRate; + ma_uint32 desiredChannelCount; + ma_format desiredFormat; + AudioStreamBasicDescription bestDeviceFormatSoFar; + ma_bool32 hasSupportedFormat; + UInt32 iFormat; + + result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &deviceFormatDescriptionCount, &pDeviceFormatDescriptions); + if (result != MA_SUCCESS) { + return result; + } + + desiredSampleRate = sampleRate; + if (desiredSampleRate == 0) { + desiredSampleRate = (ma_uint32)pOrigFormat->mSampleRate; + } + + desiredChannelCount = channels; + if (desiredChannelCount == 0) { + desiredChannelCount = pOrigFormat->mChannelsPerFrame; + } + + desiredFormat = format; + if (desiredFormat == ma_format_unknown) { + result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat); + if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) { + desiredFormat = g_maFormatPriorities[0]; + } + } + + /* + If we get here it means we don't have an exact match to what the client is asking for. We'll need to find the closest one. The next + loop will check for formats that have the same sample rate to what we're asking for. If there is, we prefer that one in all cases. + */ + MA_ZERO_OBJECT(&bestDeviceFormatSoFar); + + 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) { + hasSupportedFormat = MA_TRUE; + bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat; + break; + } + } + + if (!hasSupportedFormat) { + ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks); + return MA_FORMAT_NOT_SUPPORTED; + } + + + for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) { + AudioStreamBasicDescription thisDeviceFormat = pDeviceFormatDescriptions[iFormat].mFormat; + ma_format thisSampleFormat; + ma_result formatResult; + ma_format bestSampleFormatSoFar; + + /* If the format is not supported by miniaudio we need to skip this one entirely. */ + formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &thisSampleFormat); + if (formatResult != MA_SUCCESS || thisSampleFormat == ma_format_unknown) { + continue; /* The format is not supported by miniaudio. Skip. */ + } + + ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar, &bestSampleFormatSoFar); + + /* Getting here means the format is supported by miniaudio which makes this format a candidate. */ + if (thisDeviceFormat.mSampleRate != desiredSampleRate) { + /* + The sample rate does not match, but this format could still be usable, although it's a very low priority. If the best format + so far has an equal sample rate we can just ignore this one. + */ + if (bestDeviceFormatSoFar.mSampleRate == desiredSampleRate) { + continue; /* The best sample rate so far has the same sample rate as what we requested which means it's still the best so far. Skip this format. */ + } else { + /* In this case, neither the best format so far nor this one have the same sample rate. Check the channel count next. */ + if (thisDeviceFormat.mChannelsPerFrame != desiredChannelCount) { + /* This format has a different sample rate _and_ a different channel count. */ + if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { + continue; /* No change to the best format. */ + } else { + /* + Both this format and the best so far have different sample rates and different channel counts. Whichever has the + best format is the new best. + */ + if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + continue; /* No change to the best format. */ + } + } + } else { + /* This format has a different sample rate but the desired channel count. */ + if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { + /* Both this format and the best so far have the desired channel count. Whichever has the best format is the new best. */ + if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + continue; /* No change to the best format for now. */ + } + } else { + /* This format has the desired channel count, but the best so far does not. We have a new best. */ + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } + } + } + } else { + /* + The sample rates match which makes this format a very high priority contender. If the best format so far has a different + sample rate it needs to be replaced with this one. + */ + if (bestDeviceFormatSoFar.mSampleRate != desiredSampleRate) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + /* In this case both this format and the best format so far have the same sample rate. Check the channel count next. */ + if (thisDeviceFormat.mChannelsPerFrame == desiredChannelCount) { + /* + In this case this format has the same channel count as what the client is requesting. If the best format so far has + a different count, this one becomes the new best. + */ + if (bestDeviceFormatSoFar.mChannelsPerFrame != desiredChannelCount) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + /* In this case both this format and the best so far have the ideal sample rate and channel count. Check the format. */ + if (thisSampleFormat == desiredFormat) { + bestDeviceFormatSoFar = thisDeviceFormat; + break; /* Found the exact match. */ + } else { + /* The formats are different. The new best format is the one with the highest priority format according to miniaudio. */ + if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + continue; /* No change to the best format for now. */ + } + } + } + } else { + /* + In this case the channel count is different to what the client has requested. If the best so far has the same channel + count as the requested count then it remains the best. + */ + if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) { + continue; + } else { + /* + This is the case where both have the same sample rate (good) but different channel counts. Right now both have about + the same priority, but we need to compare the format now. + */ + if (thisSampleFormat == bestSampleFormatSoFar) { + if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) { + bestDeviceFormatSoFar = thisDeviceFormat; + continue; + } else { + continue; /* No change to the best format for now. */ + } + } + } + } + } + } + } + + *pFormat = bestDeviceFormatSoFar; + + ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks); + return MA_SUCCESS; +} + +static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap) +{ + AudioUnitScope deviceScope; + AudioUnitElement deviceBus; + UInt32 channelLayoutSize; + OSStatus status; + AudioChannelLayout* pChannelLayout; + ma_result result; + + MA_ASSERT(pContext != NULL); + + if (deviceType == ma_device_type_playback) { + deviceScope = kAudioUnitScope_Input; + deviceBus = MA_COREAUDIO_OUTPUT_BUS; + } else { + deviceScope = kAudioUnitScope_Output; + deviceBus = MA_COREAUDIO_INPUT_BUS; + } + + status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + pChannelLayout = (AudioChannelLayout*)ma_malloc(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); + 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); + return result; + } + + ma_free(pChannelLayout, &pContext->allocationCallbacks); + return MA_SUCCESS; +} +#endif /* MA_APPLE_DESKTOP */ + + +#if !defined(MA_APPLE_DESKTOP) +static void ma_AVAudioSessionPortDescription_to_device_info(AVAudioSessionPortDescription* pPortDesc, ma_device_info* pInfo) +{ + MA_ZERO_OBJECT(pInfo); + ma_strncpy_s(pInfo->name, sizeof(pInfo->name), [pPortDesc.portName UTF8String], (size_t)-1); + ma_strncpy_s(pInfo->id.coreaudio, sizeof(pInfo->id.coreaudio), [pPortDesc.UID UTF8String], (size_t)-1); +} +#endif + +static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ +#if defined(MA_APPLE_DESKTOP) + UInt32 deviceCount; + AudioObjectID* pDeviceObjectIDs; + AudioObjectID defaultDeviceObjectIDPlayback; + AudioObjectID defaultDeviceObjectIDCapture; + ma_result result; + UInt32 iDevice; + + ma_find_default_AudioObjectID(pContext, ma_device_type_playback, &defaultDeviceObjectIDPlayback); /* OK if this fails. */ + ma_find_default_AudioObjectID(pContext, ma_device_type_capture, &defaultDeviceObjectIDCapture); /* OK if this fails. */ + + result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs); + if (result != MA_SUCCESS) { + return result; + } + + for (iDevice = 0; iDevice < deviceCount; ++iDevice) { + AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice]; + ma_device_info info; + + MA_ZERO_OBJECT(&info); + if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) { + continue; + } + if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) { + continue; + } + + if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) { + if (deviceObjectID == defaultDeviceObjectIDPlayback) { + info.isDefault = MA_TRUE; + } + + if (!callback(pContext, ma_device_type_playback, &info, pUserData)) { + break; + } + } + if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) { + if (deviceObjectID == defaultDeviceObjectIDCapture) { + info.isDefault = MA_TRUE; + } + + if (!callback(pContext, ma_device_type_capture, &info, pUserData)) { + break; + } + } + } + + ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks); +#else + ma_device_info info; + NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs]; + NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs]; + + for (AVAudioSessionPortDescription* pPortDesc in pOutputs) { + ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info); + if (!callback(pContext, ma_device_type_playback, &info, pUserData)) { + return MA_SUCCESS; + } + } + + for (AVAudioSessionPortDescription* pPortDesc in pInputs) { + ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info); + if (!callback(pContext, ma_device_type_capture, &info, pUserData)) { + return MA_SUCCESS; + } + } +#endif + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_result result; + + MA_ASSERT(pContext != NULL); + +#if defined(MA_APPLE_DESKTOP) + /* Desktop */ + { + AudioObjectID deviceObjectID; + AudioObjectID defaultDeviceObjectID; + UInt32 streamDescriptionCount; + AudioStreamRangedDescription* pStreamDescriptions; + UInt32 iStreamDescription; + UInt32 sampleRateRangeCount; + AudioValueRange* pSampleRateRanges; + + ma_find_default_AudioObjectID(pContext, deviceType, &defaultDeviceObjectID); /* OK if this fails. */ + + result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(pDeviceInfo->id.coreaudio), pDeviceInfo->id.coreaudio); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pDeviceInfo->name), pDeviceInfo->name); + if (result != MA_SUCCESS) { + return result; + } + + 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 + one of miniaudio's recognized "standard" rates. If there are still more formats than can fit into + our fixed sized array we'll just need to truncate them. This is unlikely and will probably only happen + if some driver performs software data conversion and therefore reports every possible format and + 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) { + return result; + } + + for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) { + ma_format format; + ma_bool32 hasFormatBeenHandled = MA_FALSE; + ma_uint32 iOutputFormat; + ma_uint32 iSampleRate; + + result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format); + if (result != MA_SUCCESS) { + continue; + } + + MA_ASSERT(format != ma_format_unknown); + + /* Make sure the format isn't already in the output list. */ + for (iOutputFormat = 0; iOutputFormat < uniqueFormatCount; ++iOutputFormat) { + if (uniqueFormats[iOutputFormat] == format) { + hasFormatBeenHandled = MA_TRUE; + 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. + */ + for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) { + ma_uint32 iStandardSampleRate; + for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) { + ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate]; + if (standardSampleRate >= pSampleRateRanges[iSampleRate].mMinimum && standardSampleRate <= pSampleRateRanges[iSampleRate].mMaximum) { + /* We have a new data format. Add it to the list. */ + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + 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)) { + break; /* No more room for any more formats. */ + } + } + + ma_free(pStreamDescriptions, &pContext->allocationCallbacks); + } + } +#else + /* Mobile */ + { + AudioComponentDescription desc; + AudioComponent component; + AudioUnit audioUnit; + OSStatus status; + AudioUnitScope formatScope; + AudioUnitElement formatElement; + AudioStreamBasicDescription bestFormat; + UInt32 propSize; + + /* We want to ensure we use a consistent device name to device enumeration. */ + if (pDeviceID != NULL && pDeviceID->coreaudio[0] != '\0') { + ma_bool32 found = MA_FALSE; + if (deviceType == ma_device_type_playback) { + NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs]; + for (AVAudioSessionPortDescription* pPortDesc in pOutputs) { + if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) { + ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo); + found = MA_TRUE; + break; + } + } + } else { + NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs]; + for (AVAudioSessionPortDescription* pPortDesc in pInputs) { + if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) { + ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo); + found = MA_TRUE; + break; + } + } + } + + if (!found) { + return MA_DOES_NOT_EXIST; + } + } else { + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + } + + + /* + Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is + reported on a temporary I/O unit. The problem, however, is that this doesn't return a value for the sample rate which we need to + retrieve from the AVAudioSession shared instance. + */ + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_RemoteIO; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc); + if (component == NULL) { + return MA_FAILED_TO_INIT_BACKEND; + } + + status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output; + formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS; + + propSize = sizeof(bestFormat); + status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit); + return ma_result_from_OSStatus(status); + } + + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit); + audioUnit = NULL; + + /* 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; + + /* + It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do + this we just get the shared instance and inspect. + */ + @autoreleasepool { + AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; + MA_ASSERT(pAudioSession != NULL); + + pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate; + } + } +#endif + + (void)pDeviceInfo; /* Unused. */ + return MA_SUCCESS; +} + +static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout, const ma_allocation_callbacks* pAllocationCallbacks) +{ + AudioBufferList* pBufferList; + UInt32 audioBufferSizeInBytes; + size_t allocationSize; + + MA_ASSERT(sizeInFrames > 0); + MA_ASSERT(format != ma_format_unknown); + MA_ASSERT(channels > 0); + + allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */ + if (layout == ma_stream_layout_interleaved) { + /* Interleaved case. This is the simple case because we just have one buffer. */ + allocationSize += sizeof(AudioBuffer) * 1; + } else { + /* Non-interleaved case. This is the more complex case because there's more than one buffer. */ + allocationSize += sizeof(AudioBuffer) * channels; + } + + allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels); + + pBufferList = (AudioBufferList*)ma_malloc(allocationSize, pAllocationCallbacks); + if (pBufferList == NULL) { + return NULL; + } + + audioBufferSizeInBytes = (UInt32)(sizeInFrames * ma_get_bytes_per_sample(format)); + + if (layout == ma_stream_layout_interleaved) { + pBufferList->mNumberBuffers = 1; + pBufferList->mBuffers[0].mNumberChannels = channels; + pBufferList->mBuffers[0].mDataByteSize = audioBufferSizeInBytes * channels; + pBufferList->mBuffers[0].mData = (ma_uint8*)pBufferList + sizeof(AudioBufferList); + } else { + ma_uint32 iBuffer; + pBufferList->mNumberBuffers = channels; + for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) { + pBufferList->mBuffers[iBuffer].mNumberChannels = 1; + pBufferList->mBuffers[iBuffer].mDataByteSize = audioBufferSizeInBytes; + pBufferList->mBuffers[iBuffer].mData = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * channels)) + (audioBufferSizeInBytes * iBuffer); + } + } + + return pBufferList; +} + +static ma_result ma_device_realloc_AudioBufferList__coreaudio(ma_device* pDevice, ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(format != ma_format_unknown); + MA_ASSERT(channels > 0); + + /* Only resize the buffer if necessary. */ + if (pDevice->coreaudio.audioBufferCapInFrames < sizeInFrames) { + AudioBufferList* pNewAudioBufferList; + + pNewAudioBufferList = ma_allocate_AudioBufferList__coreaudio(sizeInFrames, format, channels, layout, &pDevice->pContext->allocationCallbacks); + 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); + pDevice->coreaudio.pAudioBufferList = pNewAudioBufferList; + pDevice->coreaudio.audioBufferCapInFrames = sizeInFrames; + } + + /* Getting here means the capacity of the audio is fine. */ + return MA_SUCCESS; +} + + +static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufferList) +{ + ma_device* pDevice = (ma_device*)pUserData; + ma_stream_layout layout; + + 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);*/ + + /* 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; + if (pBufferList->mBuffers[0].mNumberChannels != pDevice->playback.internalChannels) { + layout = ma_stream_layout_deinterleaved; + } + + if (layout == ma_stream_layout_interleaved) { + /* For now we can assume everything is interleaved. */ + UInt32 iBuffer; + for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) { + if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) { + ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + if (frameCountForThisBuffer > 0) { + 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);*/ + } 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 + not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. We just + 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);*/ + } + } + } 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. */ + + /* + For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something + very strange has happened and we're not going to support it. + */ + if ((pBufferList->mNumberBuffers % pDevice->playback.internalChannels) == 0) { + ma_uint8 tempBuffer[4096]; + UInt32 iBuffer; + + for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; iBuffer += pDevice->playback.internalChannels) { + ma_uint32 frameCountPerBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(pDevice->playback.internalFormat); + ma_uint32 framesRemaining = frameCountPerBuffer; + + while (framesRemaining > 0) { + void* ppDeinterleavedBuffers[MA_MAX_CHANNELS]; + ma_uint32 iChannel; + ma_uint32 framesToRead = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + if (framesToRead > framesRemaining) { + framesToRead = framesRemaining; + } + + ma_device_handle_backend_data_callback(pDevice, tempBuffer, NULL, framesToRead); + + for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) { + ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat)); + } + + ma_deinterleave_pcm_frames(pDevice->playback.internalFormat, pDevice->playback.internalChannels, framesToRead, tempBuffer, ppDeinterleavedBuffers); + + framesRemaining -= framesToRead; + } + } + } + } + + (void)pActionFlags; + (void)pTimeStamp; + (void)busNumber; + (void)frameCount; + + return noErr; +} + +static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pUnusedBufferList) +{ + ma_device* pDevice = (ma_device*)pUserData; + AudioBufferList* pRenderedBufferList; + ma_result result; + ma_stream_layout layout; + ma_uint32 iBuffer; + OSStatus status; + + MA_ASSERT(pDevice != NULL); + + pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList; + MA_ASSERT(pRenderedBufferList); + + /* 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; + if (pRenderedBufferList->mBuffers[0].mNumberChannels != pDevice->capture.internalChannels) { + 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);*/ + + /* + There has been a situation reported where frame count passed into this function is greater than the capacity of + our capture buffer. There doesn't seem to be a reliable way to determine what the maximum frame count will be, + so we need to instead resort to dynamically reallocating our buffer to ensure it's large enough to capture the + number of frames requested by this callback. + */ + 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"); + 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 + being set to the capacity of the buffer, but instead the size in bytes of the previous render. This will cause a + problem when a future call to this callback specifies a larger number of frames. + + To work around this we need to explicitly set the size of each buffer to their respective size in bytes. + */ + 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); + return status; + } + + if (layout == ma_stream_layout_interleaved) { + 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);*/ + } 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 + not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. + */ + ma_uint8 silentBuffer[4096]; + ma_uint32 framesRemaining; + + MA_ZERO_MEMORY(silentBuffer, sizeof(silentBuffer)); + + framesRemaining = frameCount; + while (framesRemaining > 0) { + ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + 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);*/ + } + } + } else { + /* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */ + MA_ASSERT(pDevice->capture.internalChannels <= MA_MAX_CHANNELS); /* This should have 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 + very strange has happened and we're not going to support it. + */ + if ((pRenderedBufferList->mNumberBuffers % pDevice->capture.internalChannels) == 0) { + ma_uint8 tempBuffer[4096]; + for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) { + ma_uint32 framesRemaining = frameCount; + while (framesRemaining > 0) { + void* ppDeinterleavedBuffers[MA_MAX_CHANNELS]; + ma_uint32 iChannel; + ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + if (framesToSend > framesRemaining) { + framesToSend = framesRemaining; + } + + for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) { + ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat)); + } + + ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer); + ma_device_handle_backend_data_callback(pDevice, NULL, tempBuffer, framesToSend); + + framesRemaining -= framesToSend; + } + } + } + } + + (void)pActionFlags; + (void)pTimeStamp; + (void)busNumber; + (void)frameCount; + (void)pUnusedBufferList; + + return noErr; +} + +static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element) +{ + 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); + } 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... */ + } + + if (!isRunning) { + /* + 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: + + 1) When the device is unplugged, this will be called _before_ the default device change notification. + 2) When the device is changed via the default device change notification, this will be called _after_ the switch. + + For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag. + */ + if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) || + ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isDefaultCaptureDevice)) { + /* + 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 + hasn't!). + */ + if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) || + ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) { + goto done; + } + + /* + Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core 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. + */ + goto done; + } + + /* Getting here means we need to stop the device. */ + ma_device__on_notification_stopped(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) +static ma_spinlock g_DeviceTrackingInitLock_CoreAudio = 0; /* A spinlock for mutal exclusion of the init/uninit of the global tracking data. Initialization to 0 is what we need. */ +static ma_uint32 g_DeviceTrackingInitCounter_CoreAudio = 0; +static ma_mutex g_DeviceTrackingMutex_CoreAudio; +static ma_device** g_ppTrackedDevices_CoreAudio = NULL; +static ma_uint32 g_TrackedDeviceCap_CoreAudio = 0; +static ma_uint32 g_TrackedDeviceCount_CoreAudio = 0; + +static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData) +{ + ma_device_type deviceType; + + /* Not sure if I really need to check this, but it makes me feel better. */ + if (addressCount == 0) { + return noErr; + } + + if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) { + deviceType = ma_device_type_playback; + } else if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) { + deviceType = ma_device_type_capture; + } else { + return noErr; /* Should never hit this. */ + } + + ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio); + { + ma_uint32 iDevice; + for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) { + ma_result reinitResult; + ma_device* pDevice; + + pDevice = g_ppTrackedDevices_CoreAudio[iDevice]; + if (pDevice->type == deviceType || pDevice->type == ma_device_type_duplex) { + if (deviceType == ma_device_type_playback) { + pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE; + reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE); + pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE; + } else { + pDevice->coreaudio.isSwitchingCaptureDevice = MA_TRUE; + reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE); + pDevice->coreaudio.isSwitchingCaptureDevice = MA_FALSE; + } + + if (reinitResult == MA_SUCCESS) { + 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) { + OSStatus status; + if (deviceType == ma_device_type_playback) { + status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + if (status != noErr) { + 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); + } + } else if (deviceType == ma_device_type_capture) { + status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + if (status != noErr) { + 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__on_notification_rerouted(pDevice); + } + } + } + } + ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); + + /* Unused parameters. */ + (void)objectID; + (void)pUserData; + + return noErr; +} + +static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + + ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio); + { + /* Don't do anything if we've already initialized device tracking. */ + if (g_DeviceTrackingInitCounter_CoreAudio == 0) { + AudioObjectPropertyAddress propAddress; + propAddress.mScope = kAudioObjectPropertyScopeGlobal; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + ma_mutex_init(&g_DeviceTrackingMutex_CoreAudio); + + propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); + + propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); + + } + g_DeviceTrackingInitCounter_CoreAudio += 1; + } + ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio); + + return MA_SUCCESS; +} + +static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + + ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio); + { + if (g_DeviceTrackingInitCounter_CoreAudio > 0) + g_DeviceTrackingInitCounter_CoreAudio -= 1; + + if (g_DeviceTrackingInitCounter_CoreAudio == 0) { + AudioObjectPropertyAddress propAddress; + propAddress.mScope = kAudioObjectPropertyScopeGlobal; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); + + propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL); + + /* 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_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio); + } + } + ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio); + + return MA_SUCCESS; +} + +static ma_result ma_device__track__coreaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio); + { + /* Allocate memory if required. */ + if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) { + ma_uint32 newCap; + ma_device** ppNewDevices; + + 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); + if (ppNewDevices == NULL) { + ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); + return MA_OUT_OF_MEMORY; + } + + g_ppTrackedDevices_CoreAudio = ppNewDevices; + g_TrackedDeviceCap_CoreAudio = newCap; + } + + g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio] = pDevice; + g_TrackedDeviceCount_CoreAudio += 1; + } + ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); + + return MA_SUCCESS; +} + +static ma_result ma_device__untrack__coreaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio); + { + ma_uint32 iDevice; + for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) { + if (g_ppTrackedDevices_CoreAudio[iDevice] == pDevice) { + /* We've found the device. We now need to remove it from the list. */ + ma_uint32 jDevice; + for (jDevice = iDevice; jDevice < g_TrackedDeviceCount_CoreAudio-1; jDevice += 1) { + g_ppTrackedDevices_CoreAudio[jDevice] = g_ppTrackedDevices_CoreAudio[jDevice+1]; + } + + g_TrackedDeviceCount_CoreAudio -= 1; + + /* 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); + g_ppTrackedDevices_CoreAudio = NULL; + g_TrackedDeviceCap_CoreAudio = 0; + } + + break; + } + } + } + ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio); + + return MA_SUCCESS; +} +#endif + +#if defined(MA_APPLE_MOBILE) +@interface ma_ios_notification_handler:NSObject { + ma_device* m_pDevice; +} +@end + +@implementation ma_ios_notification_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 +{ + AVAudioSession* pSession = [AVAudioSession sharedInstance]; + + NSInteger reason = [[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; + switch (reason) + { + case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n"); + } break; + + case AVAudioSessionRouteChangeReasonNewDeviceAvailable: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n"); + } break; + + case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n"); + } break; + + case AVAudioSessionRouteChangeReasonWakeFromSleep: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n"); + } break; + + case AVAudioSessionRouteChangeReasonOverride: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n"); + } break; + + case AVAudioSessionRouteChangeReasonCategoryChange: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n"); + } break; + + case AVAudioSessionRouteChangeReasonUnknown: + default: + { + ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_INFO, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n"); + } 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); + + /* Let the application know about the route change. */ + ma_device__on_notification_rerouted(m_pDevice); +} +@end +#endif + +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); + +#if defined(MA_APPLE_DESKTOP) + /* + Make sure we're no longer tracking the device. It doesn't matter if we call this for a non-default device because it'll + just gracefully ignore it. + */ + 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]; + } +#endif + + if (pDevice->coreaudio.audioUnitCapture != NULL) { + ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + } + if (pDevice->coreaudio.audioUnitPlayback != NULL) { + ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + } + + if (pDevice->coreaudio.pAudioBufferList) { + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + } + + return MA_SUCCESS; +} + +typedef struct +{ + ma_bool32 allowNominalSampleRateChange; + + /* Input. */ + ma_format formatIn; + ma_uint32 channelsIn; + ma_uint32 sampleRateIn; + ma_channel channelMapIn[MA_MAX_CHANNELS]; + ma_uint32 periodSizeInFramesIn; + ma_uint32 periodSizeInMillisecondsIn; + ma_uint32 periodsIn; + ma_share_mode shareMode; + ma_performance_profile performanceProfile; + ma_bool32 registerStopEvent; + + /* Output. */ +#if defined(MA_APPLE_DESKTOP) + AudioObjectID deviceObjectID; +#endif + AudioComponent component; + AudioUnit audioUnit; + AudioBufferList* pAudioBufferList; /* Only used for input devices. */ + ma_format formatOut; + ma_uint32 channelsOut; + ma_uint32 sampleRateOut; + ma_channel channelMapOut[MA_MAX_CHANNELS]; + ma_uint32 periodSizeInFramesOut; + ma_uint32 periodsOut; + char deviceName[256]; +} ma_device_init_internal_data__coreaudio; + +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; + OSStatus status; + UInt32 enableIOFlag; + AudioStreamBasicDescription bestFormat; + ma_uint32 actualPeriodSizeInFrames; + AURenderCallbackStruct callbackInfo; +#if defined(MA_APPLE_DESKTOP) + AudioObjectID deviceObjectID; +#endif + + /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + MA_ASSERT(pContext != NULL); + MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture); + +#if defined(MA_APPLE_DESKTOP) + pData->deviceObjectID = 0; +#endif + pData->component = NULL; + pData->audioUnit = NULL; + pData->pAudioBufferList = NULL; + +#if defined(MA_APPLE_DESKTOP) + result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID); + if (result != MA_SUCCESS) { + return result; + } + + pData->deviceObjectID = deviceObjectID; +#endif + + /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */ + pData->periodsOut = pData->periodsIn; + if (pData->periodsOut == 0) { + pData->periodsOut = MA_DEFAULT_PERIODS; + } + if (pData->periodsOut > 16) { + pData->periodsOut = 16; + } + + + /* Audio unit. */ + status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + + + /* The input/output buses need to be explicitly enabled and disabled. We set the flag based on the output unit first, then we just swap it for input. */ + enableIOFlag = 1; + if (deviceType == ma_device_type_capture) { + enableIOFlag = 0; + } + + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + + enableIOFlag = (enableIOFlag == 0) ? 1 : 0; + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + + + /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */ +#if defined(MA_APPLE_DESKTOP) + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(result); + } +#else + /* + For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change + the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices. + */ + if (pDeviceID != NULL) { + if (deviceType == ma_device_type_capture) { + ma_bool32 found = MA_FALSE; + NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs]; + for (AVAudioSessionPortDescription* pPortDesc in pInputs) { + if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) { + [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil]; + found = MA_TRUE; + break; + } + } + + if (found == MA_FALSE) { + return MA_DOES_NOT_EXIST; + } + } + } +#endif + + /* + Format. This is the hardest part of initialization because there's a few variables to take into account. + 1) The format must be supported by the device. + 2) The format must be supported miniaudio. + 3) There's a priority that miniaudio prefers. + + Ideally we would like to use a format that's as close to the hardware as possible so we can get as close to a passthrough as possible. The + most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same + for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely. + + On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to. + */ + { + AudioStreamBasicDescription origFormat; + UInt32 origFormatSize = sizeof(origFormat); + AudioUnitScope formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output; + AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS; + + if (deviceType == ma_device_type_playback) { + status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize); + } else { + status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize); + } + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + + #if defined(MA_APPLE_DESKTOP) + result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat); + if (result != MA_SUCCESS) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return result; + } + + /* + Technical Note TN2091: Device input using the HAL Output Audio Unit + https://developer.apple.com/library/archive/technotes/tn2091/_index.html + + This documentation says the following: + + The internal AudioConverter can handle any *simple* conversion. Typically, this means that a client can specify ANY + variant of the PCM formats. Consequently, the device's sample rate should match the desired sample rate. If sample rate + conversion is needed, it can be accomplished by buffering the input and converting the data on a separate thread with + another AudioConverter. + + The important part here is the mention that it can handle *simple* conversions, which does *not* include sample rate. We + therefore want to ensure the sample rate stays consistent. This document is specifically for input, but I'm going to play it + safe and apply the same rule to output as well. + + I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender() + 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 + 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 + rate will be allowed. Otherwise it'll be fixed to the current sample rate. To check the system-defined sample rate, run + the Audio MIDI Setup program that comes installed on macOS and observe how the sample rate changes as the sample rate is + changed by miniaudio. + */ + if (pData->allowNominalSampleRateChange) { + AudioValueRange sampleRateRange; + AudioObjectPropertyAddress propAddress; + + sampleRateRange.mMinimum = bestFormat.mSampleRate; + sampleRateRange.mMaximum = bestFormat.mSampleRate; + + propAddress.mSelector = kAudioDevicePropertyNominalSampleRate; + propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput; + propAddress.mElement = AUDIO_OBJECT_PROPERTY_ELEMENT; + + status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange); + if (status != noErr) { + bestFormat.mSampleRate = origFormat.mSampleRate; + } + } else { + bestFormat.mSampleRate = origFormat.mSampleRate; + } + + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat)); + if (status != noErr) { + /* We failed to set the format, so fall back to the current format of the audio unit. */ + bestFormat = origFormat; + } + #else + bestFormat = origFormat; + + /* + Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try + setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since + it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I + can tell, it looks like the sample rate is shared between playback and capture for everything. + */ + @autoreleasepool { + AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; + MA_ASSERT(pAudioSession != NULL); + + [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil]; + bestFormat.mSampleRate = pAudioSession.sampleRate; + + /* + 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); + return ma_result_from_OSStatus(status); + } + #endif + + result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut); + if (result != MA_SUCCESS) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return result; + } + + if (pData->formatOut == ma_format_unknown) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return MA_FORMAT_NOT_SUPPORTED; + } + + pData->channelsOut = bestFormat.mChannelsPerFrame; + pData->sampleRateOut = (ma_uint32)bestFormat.mSampleRate; + } + + /* Clamp the channel count for safety. */ + if (pData->channelsOut > MA_MAX_CHANNELS) { + pData->channelsOut = MA_MAX_CHANNELS; + } + + /* + Internal channel map. This is weird in my testing. If I use the AudioObject to get the + channel map, the channel descriptions are set to "Unknown" for some reason. To work around + this it looks like retrieving it from the AudioUnit will work. However, and this is where + it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore + I'm going to fall back to a default assumption in these cases. + */ +#if defined(MA_APPLE_DESKTOP) + result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut); + if (result != MA_SUCCESS) { + #if 0 + /* Try falling back to the channel map from the AudioObject. */ + result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut); + if (result != MA_SUCCESS) { + return result; + } + #else + /* Fall back to default assumptions. */ + ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut); + #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); +#endif + + + /* Buffer size. Not allowing this to be configurable on iOS. */ + if (pData->periodSizeInFramesIn == 0) { + if (pData->periodSizeInMillisecondsIn == 0) { + if (pData->performanceProfile == ma_performance_profile_low_latency) { + actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, pData->sampleRateOut); + } else { + actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, pData->sampleRateOut); + } + } else { + actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut); + } + } else { + actualPeriodSizeInFrames = pData->periodSizeInFramesIn; + } + +#if defined(MA_APPLE_DESKTOP) + result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames); + if (result != MA_SUCCESS) { + return result; + } +#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. + */ + @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)); + } +#endif + + + /* + During testing I discovered that the buffer size can be too big. You'll get an error like this: + + kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512 + + Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that + of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice. + */ + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, sizeof(actualPeriodSizeInFrames)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + + pData->periodSizeInFramesOut = (ma_uint32)actualPeriodSizeInFrames; + + /* We need a buffer list if this is an input device. We render into this in the input callback. */ + if (deviceType == ma_device_type_capture) { + ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0; + AudioBufferList* pBufferList; + + pBufferList = ma_allocate_AudioBufferList__coreaudio(pData->periodSizeInFramesOut, pData->formatOut, pData->channelsOut, (isInterleaved) ? ma_stream_layout_interleaved : ma_stream_layout_deinterleaved, &pContext->allocationCallbacks); + if (pBufferList == NULL) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return MA_OUT_OF_MEMORY; + } + + pData->pAudioBufferList = pBufferList; + } + + /* Callbacks. */ + callbackInfo.inputProcRefCon = pDevice_DoNotReference; + if (deviceType == ma_device_type_playback) { + callbackInfo.inputProc = ma_on_output__coreaudio; + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + } else { + callbackInfo.inputProc = ma_on_input__coreaudio; + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo)); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + } + + /* We need to listen for stop events. */ + if (pData->registerStopEvent) { + status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference); + if (status != noErr) { + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + } + + /* Initialize the audio unit. */ + status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit); + if (status != noErr) { + ma_free(pData->pAudioBufferList, &pContext->allocationCallbacks); + pData->pAudioBufferList = NULL; + ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); + return ma_result_from_OSStatus(status); + } + + /* Grab the name. */ +#if defined(MA_APPLE_DESKTOP) + ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName); +#else + if (deviceType == ma_device_type_playback) { + ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME); + } else { + ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME); + } +#endif + + return result; +} + +#if defined(MA_APPLE_DESKTOP) +static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit) +{ + ma_device_init_internal_data__coreaudio data; + ma_result result; + + /* This should only be called for playback or capture, not duplex. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + data.allowNominalSampleRateChange = MA_FALSE; /* Don't change the nominal sample rate when switching devices. */ + + if (deviceType == ma_device_type_capture) { + data.formatIn = pDevice->capture.format; + data.channelsIn = pDevice->capture.channels; + data.sampleRateIn = pDevice->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap)); + data.shareMode = pDevice->capture.shareMode; + data.performanceProfile = pDevice->coreaudio.originalPerformanceProfile; + data.registerStopEvent = MA_TRUE; + + if (disposePreviousAudioUnit) { + ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + } + if (pDevice->coreaudio.pAudioBufferList) { + ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks); + } + } else if (deviceType == ma_device_type_playback) { + data.formatIn = pDevice->playback.format; + data.channelsIn = pDevice->playback.channels; + data.sampleRateIn = pDevice->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap)); + data.shareMode = pDevice->playback.shareMode; + data.performanceProfile = pDevice->coreaudio.originalPerformanceProfile; + data.registerStopEvent = (pDevice->type != ma_device_type_duplex); + + if (disposePreviousAudioUnit) { + ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + } + } + data.periodSizeInFramesIn = pDevice->coreaudio.originalPeriodSizeInFrames; + data.periodSizeInMillisecondsIn = pDevice->coreaudio.originalPeriodSizeInMilliseconds; + data.periodsIn = pDevice->coreaudio.originalPeriods; + + /* Need at least 3 periods for duplex. */ + if (data.periodsIn < 3 && pDevice->type == ma_device_type_duplex) { + data.periodsIn = 3; + } + + result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice); + if (result != MA_SUCCESS) { + return result; + } + + 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; + pDevice->coreaudio.audioBufferCapInFrames = data.periodSizeInFramesOut; + + pDevice->capture.internalFormat = data.formatOut; + pDevice->capture.internalChannels = data.channelsOut; + pDevice->capture.internalSampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut; + pDevice->capture.internalPeriods = data.periodsOut; + } 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; + + pDevice->playback.internalFormat = data.formatOut; + pDevice->playback.internalChannels = data.channelsOut; + pDevice->playback.internalSampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut; + pDevice->playback.internalPeriods = data.periodsOut; + } + + return MA_SUCCESS; +} +#endif /* MA_APPLE_DESKTOP */ + +static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pConfig != NULL); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* No exclusive mode with the Core Audio backend for now. */ + if (((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive) || + ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive)) { + return MA_SHARE_MODE_NOT_SUPPORTED; + } + + /* Capture needs to be initialized first. */ + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_device_init_internal_data__coreaudio data; + data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange; + data.formatIn = pDescriptorCapture->format; + data.channelsIn = pDescriptorCapture->channels; + data.sampleRateIn = pDescriptorCapture->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap)); + data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames; + data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds; + data.periodsIn = pDescriptorCapture->periodCount; + data.shareMode = pDescriptorCapture->shareMode; + data.performanceProfile = pConfig->performanceProfile; + data.registerStopEvent = MA_TRUE; + + /* Need at least 3 periods for duplex. */ + if (data.periodsIn < 3 && pConfig->deviceType == ma_device_type_duplex) { + data.periodsIn = 3; + } + + result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pDescriptorCapture->pDeviceID, &data, (void*)pDevice); + if (result != MA_SUCCESS) { + return result; + } + + pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL); + #if defined(MA_APPLE_DESKTOP) + pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID; + #endif + pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit; + pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList; + pDevice->coreaudio.audioBufferCapInFrames = data.periodSizeInFramesOut; + pDevice->coreaudio.originalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; + pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds; + pDevice->coreaudio.originalPeriods = pDescriptorCapture->periodCount; + pDevice->coreaudio.originalPerformanceProfile = pConfig->performanceProfile; + + pDescriptorCapture->format = data.formatOut; + pDescriptorCapture->channels = data.channelsOut; + pDescriptorCapture->sampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut; + 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 + switch the device in the background. + */ + if (pConfig->capture.pDeviceID == NULL) { + ma_device__track__coreaudio(pDevice); + } + #endif + } + + /* Playback. */ + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_device_init_internal_data__coreaudio data; + data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange; + data.formatIn = pDescriptorPlayback->format; + data.channelsIn = pDescriptorPlayback->channels; + data.sampleRateIn = pDescriptorPlayback->sampleRate; + MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap)); + data.shareMode = pDescriptorPlayback->shareMode; + data.performanceProfile = pConfig->performanceProfile; + + /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */ + if (pConfig->deviceType == ma_device_type_duplex) { + data.periodSizeInFramesIn = pDescriptorCapture->periodSizeInFrames; + data.periodsIn = pDescriptorCapture->periodCount; + data.registerStopEvent = MA_FALSE; + } else { + data.periodSizeInFramesIn = pDescriptorPlayback->periodSizeInFrames; + data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds; + data.periodsIn = pDescriptorPlayback->periodCount; + data.registerStopEvent = MA_TRUE; + } + + result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data, (void*)pDevice); + if (result != MA_SUCCESS) { + 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); + } + } + return result; + } + + pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL); + #if defined(MA_APPLE_DESKTOP) + pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID; + #endif + pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit; + pDevice->coreaudio.originalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; + pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds; + pDevice->coreaudio.originalPeriods = pDescriptorPlayback->periodCount; + pDevice->coreaudio.originalPerformanceProfile = pConfig->performanceProfile; + + pDescriptorPlayback->format = data.formatOut; + pDescriptorPlayback->channels = data.channelsOut; + pDescriptorPlayback->sampleRate = data.sampleRateOut; + MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut)); + pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut; + 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 + switch the device in the background. + */ + if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) { + ma_device__track__coreaudio(pDevice); + } + #endif + } + + + + /* + When stopping the device, a callback is called on another thread. We need to wait for this callback + before returning from ma_device_stop(). This event is used for this. + */ + ma_event_init(&pDevice->coreaudio.stopEvent); + + /* + We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done + 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]; +#endif + + return MA_SUCCESS; +} + + +static ma_result ma_device_start__coreaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + if (status != noErr) { + if (pDevice->type == ma_device_type_duplex) { + ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + } + return ma_result_from_OSStatus(status); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__coreaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* It's not clear from the documentation whether or not AudioOutputUnitStop() actually drains the device or not. */ + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback); + if (status != noErr) { + return ma_result_from_OSStatus(status); + } + } + + /* We need to wait for the callback to finish before returning. */ + ma_event_wait(&pDevice->coreaudio.stopEvent); + return MA_SUCCESS; +} + + +static ma_result ma_context_uninit__coreaudio(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_coreaudio); + +#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; + } + } +#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); +#endif + +#if !defined(MA_APPLE_MOBILE) + ma_context__uninit_device_tracking__coreaudio(pContext); +#endif + + (void)pContext; + return MA_SUCCESS; +} + +#if defined(MA_APPLE_MOBILE) && defined(__IPHONE_12_0) +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. */ + MA_ASSERT(category != ma_ios_session_category_default); + MA_ASSERT(category != ma_ios_session_category_none); + + switch (category) { + case ma_ios_session_category_ambient: return AVAudioSessionCategoryAmbient; + case ma_ios_session_category_solo_ambient: return AVAudioSessionCategorySoloAmbient; + case ma_ios_session_category_playback: return AVAudioSessionCategoryPlayback; + case ma_ios_session_category_record: return AVAudioSessionCategoryRecord; + case ma_ios_session_category_play_and_record: return AVAudioSessionCategoryPlayAndRecord; + case ma_ios_session_category_multi_route: return AVAudioSessionCategoryMultiRoute; + case ma_ios_session_category_none: return AVAudioSessionCategoryAmbient; + case ma_ios_session_category_default: return AVAudioSessionCategoryAmbient; + default: return AVAudioSessionCategoryAmbient; + } +} +#endif + +static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ +#if !defined(MA_APPLE_MOBILE) + ma_result result; +#endif + + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pContext != NULL); + +#if defined(MA_APPLE_MOBILE) + @autoreleasepool { + AVAudioSession* pAudioSession = [AVAudioSession sharedInstance]; + AVAudioSessionCategoryOptions options = pConfig->coreaudio.sessionCategoryOptions; + + MA_ASSERT(pAudioSession != NULL); + + if (pConfig->coreaudio.sessionCategory == ma_ios_session_category_default) { + /* + I'm going to use trial and error to determine our default session category. First we'll try PlayAndRecord. If that fails + we'll try Playback and if that fails we'll try record. If all of these fail we'll just not set the category. + */ + #if !defined(MA_APPLE_TV) && !defined(MA_APPLE_WATCH) + options |= AVAudioSessionCategoryOptionDefaultToSpeaker; + #endif + + if ([pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) { + /* Using PlayAndRecord */ + } else if ([pAudioSession setCategory: AVAudioSessionCategoryPlayback withOptions:options error:nil]) { + /* Using Playback */ + } else if ([pAudioSession setCategory: AVAudioSessionCategoryRecord withOptions:options error:nil]) { + /* Using Record */ + } else { + /* Leave as default? */ + } + } 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; + } + } + } +#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"); + 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.hCoreAudio = ma_dlopen(ma_context_get_log(pContext), "/System/Library/Frameworks/CoreAudio.framework/CoreAudio"); + if (pContext->coreaudio.hCoreAudio == NULL) { + ma_dlclose(ma_context_get_log(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"); + + /* + It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still + defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback. + 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"); + 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); + return MA_API_NOT_FOUND; + } + + if (ma_dlsym(ma_context_get_log(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"); + 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); + 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"); +#else + pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString; + pContext->coreaudio.CFRelease = (ma_proc)CFRelease; + + #if defined(MA_APPLE_DESKTOP) + pContext->coreaudio.AudioObjectGetPropertyData = (ma_proc)AudioObjectGetPropertyData; + pContext->coreaudio.AudioObjectGetPropertyDataSize = (ma_proc)AudioObjectGetPropertyDataSize; + pContext->coreaudio.AudioObjectSetPropertyData = (ma_proc)AudioObjectSetPropertyData; + pContext->coreaudio.AudioObjectAddPropertyListener = (ma_proc)AudioObjectAddPropertyListener; + pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener; + #endif + + pContext->coreaudio.AudioComponentFindNext = (ma_proc)AudioComponentFindNext; + pContext->coreaudio.AudioComponentInstanceDispose = (ma_proc)AudioComponentInstanceDispose; + pContext->coreaudio.AudioComponentInstanceNew = (ma_proc)AudioComponentInstanceNew; + pContext->coreaudio.AudioOutputUnitStart = (ma_proc)AudioOutputUnitStart; + pContext->coreaudio.AudioOutputUnitStop = (ma_proc)AudioOutputUnitStop; + pContext->coreaudio.AudioUnitAddPropertyListener = (ma_proc)AudioUnitAddPropertyListener; + pContext->coreaudio.AudioUnitGetPropertyInfo = (ma_proc)AudioUnitGetPropertyInfo; + pContext->coreaudio.AudioUnitGetProperty = (ma_proc)AudioUnitGetProperty; + pContext->coreaudio.AudioUnitSetProperty = (ma_proc)AudioUnitSetProperty; + pContext->coreaudio.AudioUnitInitialize = (ma_proc)AudioUnitInitialize; + pContext->coreaudio.AudioUnitRender = (ma_proc)AudioUnitRender; +#endif + + /* Audio component. */ + { + AudioComponentDescription desc; + desc.componentType = kAudioUnitType_Output; + #if defined(MA_APPLE_DESKTOP) + desc.componentSubType = kAudioUnitSubType_HALOutput; + #else + desc.componentSubType = kAudioUnitSubType_RemoteIO; + #endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + 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); + #endif + return MA_FAILED_TO_INIT_BACKEND; + } + } + +#if !defined(MA_APPLE_MOBILE) + 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); + #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; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__coreaudio; + pCallbacks->onDeviceInit = ma_device_init__coreaudio; + pCallbacks->onDeviceUninit = ma_device_uninit__coreaudio; + pCallbacks->onDeviceStart = ma_device_start__coreaudio; + pCallbacks->onDeviceStop = ma_device_stop__coreaudio; + pCallbacks->onDeviceRead = NULL; + pCallbacks->onDeviceWrite = NULL; + pCallbacks->onDeviceDataLoop = NULL; + + return MA_SUCCESS; +} +#endif /* MA_HAS_COREAUDIO */ + + + +/****************************************************************************** + +sndio Backend + +******************************************************************************/ +#ifdef MA_HAS_SNDIO +#include + +/* +Only supporting OpenBSD. This did not work very well at all on FreeBSD when I tried it. Not sure if this is due +to miniaudio's implementation or if it's some kind of system configuration issue, but basically the default device +just doesn't emit any sound, or at times you'll hear tiny pieces. I will consider enabling this when there's +demand for it or if I can get it tested and debugged more thoroughly. +*/ +#if 0 +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include +#endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include +#endif +#endif + +#define MA_SIO_DEVANY "default" +#define MA_SIO_PLAY 1 +#define MA_SIO_REC 2 +#define MA_SIO_NENC 8 +#define MA_SIO_NCHAN 8 +#define MA_SIO_NRATE 16 +#define MA_SIO_NCONF 4 + +struct ma_sio_hdl; /* <-- Opaque */ + +struct ma_sio_par +{ + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; + unsigned int rchan; + unsigned int pchan; + unsigned int rate; + unsigned int bufsz; + unsigned int xrun; + unsigned int round; + unsigned int appbufsz; + int __pad[3]; + unsigned int __magic; +}; + +struct ma_sio_enc +{ + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; +}; + +struct ma_sio_conf +{ + unsigned int enc; + unsigned int rchan; + unsigned int pchan; + unsigned int rate; +}; + +struct ma_sio_cap +{ + struct ma_sio_enc enc[MA_SIO_NENC]; + unsigned int rchan[MA_SIO_NCHAN]; + unsigned int pchan[MA_SIO_NCHAN]; + unsigned int rate[MA_SIO_NRATE]; + int __pad[7]; + unsigned int nconf; + struct ma_sio_conf confs[MA_SIO_NCONF]; +}; + +typedef struct ma_sio_hdl* (* ma_sio_open_proc) (const char*, unsigned int, int); +typedef void (* ma_sio_close_proc) (struct ma_sio_hdl*); +typedef int (* ma_sio_setpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*); +typedef int (* ma_sio_getpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*); +typedef int (* ma_sio_getcap_proc) (struct ma_sio_hdl*, struct ma_sio_cap*); +typedef size_t (* ma_sio_write_proc) (struct ma_sio_hdl*, const void*, size_t); +typedef size_t (* ma_sio_read_proc) (struct ma_sio_hdl*, void*, size_t); +typedef int (* ma_sio_start_proc) (struct ma_sio_hdl*); +typedef int (* ma_sio_stop_proc) (struct ma_sio_hdl*); +typedef int (* ma_sio_initpar_proc)(struct ma_sio_par*); + +static ma_uint32 ma_get_standard_sample_rate_priority_index__sndio(ma_uint32 sampleRate) /* Lower = higher priority */ +{ + ma_uint32 i; + for (i = 0; i < ma_countof(g_maStandardSampleRatePriorities); ++i) { + if (g_maStandardSampleRatePriorities[i] == sampleRate) { + return i; + } + } + + return (ma_uint32)-1; +} + +static ma_format ma_format_from_sio_enc__sndio(unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le, unsigned int msb) +{ + /* We only support native-endian right now. */ + if ((ma_is_little_endian() && le == 0) || (ma_is_big_endian() && le == 1)) { + return ma_format_unknown; + } + + if (bits == 8 && bps == 1 && sig == 0) { + return ma_format_u8; + } + if (bits == 16 && bps == 2 && sig == 1) { + return ma_format_s16; + } + if (bits == 24 && bps == 3 && sig == 1) { + return ma_format_s24; + } + if (bits == 24 && bps == 4 && sig == 1 && msb == 0) { + /*return ma_format_s24_32;*/ + } + if (bits == 32 && bps == 4 && sig == 1) { + return ma_format_s32; + } + + return ma_format_unknown; +} + +static ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap* caps) +{ + ma_format bestFormat; + unsigned int iConfig; + + MA_ASSERT(caps != NULL); + + bestFormat = ma_format_unknown; + for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { + unsigned int iEncoding; + for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; + ma_format format; + + if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { + continue; + } + + bits = caps->enc[iEncoding].bits; + bps = caps->enc[iEncoding].bps; + sig = caps->enc[iEncoding].sig; + le = caps->enc[iEncoding].le; + msb = caps->enc[iEncoding].msb; + format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); + if (format == ma_format_unknown) { + continue; /* Format not supported. */ + } + + if (bestFormat == ma_format_unknown) { + bestFormat = format; + } else { + if (ma_get_format_priority_index(bestFormat) > ma_get_format_priority_index(format)) { /* <-- Lower = better. */ + bestFormat = format; + } + } + } + } + + return bestFormat; +} + +static ma_uint32 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat) +{ + ma_uint32 maxChannels; + unsigned int iConfig; + + MA_ASSERT(caps != NULL); + MA_ASSERT(requiredFormat != ma_format_unknown); + + /* Just pick whatever configuration has the most channels. */ + maxChannels = 0; + for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { + /* The encoding should be of requiredFormat. */ + unsigned int iEncoding; + for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { + unsigned int iChannel; + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; + ma_format format; + + if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { + continue; + } + + bits = caps->enc[iEncoding].bits; + bps = caps->enc[iEncoding].bps; + sig = caps->enc[iEncoding].sig; + le = caps->enc[iEncoding].le; + msb = caps->enc[iEncoding].msb; + format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); + if (format != requiredFormat) { + continue; + } + + /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */ + for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { + unsigned int chan = 0; + unsigned int channels; + + if (deviceType == ma_device_type_playback) { + chan = caps->confs[iConfig].pchan; + } else { + chan = caps->confs[iConfig].rchan; + } + + if ((chan & (1UL << iChannel)) == 0) { + continue; + } + + if (deviceType == ma_device_type_playback) { + channels = caps->pchan[iChannel]; + } else { + channels = caps->rchan[iChannel]; + } + + if (maxChannels < channels) { + maxChannels = channels; + } + } + } + } + + return maxChannels; +} + +static ma_uint32 ma_find_best_sample_rate_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat, ma_uint32 requiredChannels) +{ + ma_uint32 firstSampleRate; + ma_uint32 bestSampleRate; + unsigned int iConfig; + + MA_ASSERT(caps != NULL); + MA_ASSERT(requiredFormat != ma_format_unknown); + MA_ASSERT(requiredChannels > 0); + MA_ASSERT(requiredChannels <= MA_MAX_CHANNELS); + + firstSampleRate = 0; /* <-- If the device does not support a standard rate we'll fall back to the first one that's found. */ + bestSampleRate = 0; + + for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) { + /* The encoding should be of requiredFormat. */ + unsigned int iEncoding; + for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { + unsigned int iChannel; + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; + ma_format format; + + if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) { + continue; + } + + bits = caps->enc[iEncoding].bits; + bps = caps->enc[iEncoding].bps; + sig = caps->enc[iEncoding].sig; + le = caps->enc[iEncoding].le; + msb = caps->enc[iEncoding].msb; + format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); + if (format != requiredFormat) { + continue; + } + + /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */ + for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { + unsigned int chan = 0; + unsigned int channels; + unsigned int iRate; + + if (deviceType == ma_device_type_playback) { + chan = caps->confs[iConfig].pchan; + } else { + chan = caps->confs[iConfig].rchan; + } + + if ((chan & (1UL << iChannel)) == 0) { + continue; + } + + if (deviceType == ma_device_type_playback) { + channels = caps->pchan[iChannel]; + } else { + channels = caps->rchan[iChannel]; + } + + if (channels != requiredChannels) { + continue; + } + + /* Getting here means we have found a compatible encoding/channel pair. */ + for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) { + ma_uint32 rate = (ma_uint32)caps->rate[iRate]; + ma_uint32 ratePriority; + + if (firstSampleRate == 0) { + firstSampleRate = rate; + } + + /* Disregard this rate if it's not a standard one. */ + ratePriority = ma_get_standard_sample_rate_priority_index__sndio(rate); + if (ratePriority == (ma_uint32)-1) { + continue; + } + + if (ma_get_standard_sample_rate_priority_index__sndio(bestSampleRate) > ratePriority) { /* Lower = better. */ + bestSampleRate = rate; + } + } + } + } + } + + /* If a standard sample rate was not found just fall back to the first one that was iterated. */ + if (bestSampleRate == 0) { + bestSampleRate = firstSampleRate; + } + + return bestSampleRate; +} + + +static ma_result ma_context_enumerate_devices__sndio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 isTerminating = MA_FALSE; + struct ma_sio_hdl* handle; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* sndio doesn't seem to have a good device enumeration API, so I'm therefore only enumerating over default devices for now. */ + + /* Playback. */ + if (!isTerminating) { + handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_PLAY, 0); + if (handle != NULL) { + /* Supports playback. */ + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), MA_SIO_DEVANY); + ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME); + + isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + + ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); + } + } + + /* Capture. */ + if (!isTerminating) { + handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_REC, 0); + if (handle != NULL) { + /* Supports capture. */ + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default"); + ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME); + + isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + + ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__sndio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + char devid[256]; + struct ma_sio_hdl* handle; + struct ma_sio_cap caps; + unsigned int iConfig; + + MA_ASSERT(pContext != NULL); + + /* We need to open the device before we can get information about it. */ + if (pDeviceID == NULL) { + ma_strcpy_s(devid, sizeof(devid), MA_SIO_DEVANY); + ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (deviceType == ma_device_type_playback) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : MA_DEFAULT_CAPTURE_DEVICE_NAME); + } else { + ma_strcpy_s(devid, sizeof(devid), pDeviceID->sndio); + ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), devid); + } + + handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(devid, (deviceType == ma_device_type_playback) ? MA_SIO_PLAY : MA_SIO_REC, 0); + if (handle == NULL) { + return MA_NO_DEVICE; + } + + if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)(handle, &caps) == 0) { + return MA_ERROR; + } + + pDeviceInfo->nativeDataFormatCount = 0; + + for (iConfig = 0; iConfig < caps.nconf; iConfig += 1) { + /* + The main thing we care about is that the encoding is supported by miniaudio. If it is, we want to give + preference to some formats over others. + */ + unsigned int iEncoding; + unsigned int iChannel; + unsigned int iRate; + + for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) { + unsigned int bits; + unsigned int bps; + unsigned int sig; + unsigned int le; + unsigned int msb; + ma_format format; + + if ((caps.confs[iConfig].enc & (1UL << iEncoding)) == 0) { + continue; + } + + bits = caps.enc[iEncoding].bits; + bps = caps.enc[iEncoding].bps; + sig = caps.enc[iEncoding].sig; + le = caps.enc[iEncoding].le; + msb = caps.enc[iEncoding].msb; + format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb); + if (format == ma_format_unknown) { + continue; /* Format not supported. */ + } + + + /* Channels. */ + for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) { + unsigned int chan = 0; + unsigned int channels; + + if (deviceType == ma_device_type_playback) { + chan = caps.confs[iConfig].pchan; + } else { + chan = caps.confs[iConfig].rchan; + } + + if ((chan & (1UL << iChannel)) == 0) { + continue; + } + + if (deviceType == ma_device_type_playback) { + channels = caps.pchan[iChannel]; + } else { + channels = caps.rchan[iChannel]; + } + + + /* Sample Rates. */ + for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) { + if ((caps.confs[iConfig].rate & (1UL << iRate)) != 0) { + ma_device_info_add_native_data_format(pDeviceInfo, format, channels, caps.rate[iRate], 0); + } + } + } + } + } + + ((ma_sio_close_proc)pContext->sndio.sio_close)(handle); + return MA_SUCCESS; +} + +static ma_result ma_device_uninit__sndio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + 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.handleCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) +{ + const char* pDeviceName; + ma_ptr handle; + int openFlags = 0; + struct ma_sio_cap caps; + struct ma_sio_par par; + const ma_device_id* pDeviceID; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + ma_format internalFormat; + ma_uint32 internalChannels; + ma_uint32 internalSampleRate; + ma_uint32 internalPeriodSizeInFrames; + ma_uint32 internalPeriods; + + MA_ASSERT(pConfig != NULL); + MA_ASSERT(deviceType != ma_device_type_duplex); + MA_ASSERT(pDevice != NULL); + + if (deviceType == ma_device_type_capture) { + openFlags = MA_SIO_REC; + } else { + openFlags = MA_SIO_PLAY; + } + + pDeviceID = pDescriptor->pDeviceID; + format = pDescriptor->format; + channels = pDescriptor->channels; + sampleRate = pDescriptor->sampleRate; + + pDeviceName = MA_SIO_DEVANY; + if (pDeviceID != NULL) { + pDeviceName = pDeviceID->sndio; + } + + 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; + } + + /* 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; + } + + /* + Note: sndio reports a huge range of available channels. This is inconvenient for us because there's no real + way, as far as I can tell, to get the _actual_ channel count of the device. I'm therefore restricting this + to the requested channels, regardless of whether or not the default channel count is requested. + + For hardware devices, I'm suspecting only a single channel count will be reported and we can safely use the + value returned by ma_find_best_channels_from_sio_cap__sndio(). + */ + if (deviceType == ma_device_type_capture) { + if (format == ma_format_unknown) { + format = ma_find_best_format_from_sio_cap__sndio(&caps); + } + + if (channels == 0) { + if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) { + channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format); + } else { + channels = MA_DEFAULT_CHANNELS; + } + } + } else { + if (format == ma_format_unknown) { + format = ma_find_best_format_from_sio_cap__sndio(&caps); + } + + if (channels == 0) { + if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) { + channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format); + } else { + channels = MA_DEFAULT_CHANNELS; + } + } + } + + if (sampleRate == 0) { + sampleRate = ma_find_best_sample_rate_from_sio_cap__sndio(&caps, pConfig->deviceType, format, channels); + } + + + ((ma_sio_initpar_proc)pDevice->pContext->sndio.sio_initpar)(&par); + par.msb = 0; + par.le = ma_is_little_endian(); + + switch (format) { + case ma_format_u8: + { + par.bits = 8; + par.bps = 1; + par.sig = 0; + } break; + + case ma_format_s24: + { + par.bits = 24; + par.bps = 3; + par.sig = 1; + } break; + + case ma_format_s32: + { + par.bits = 32; + par.bps = 4; + par.sig = 1; + } break; + + case ma_format_s16: + case ma_format_f32: + case ma_format_unknown: + default: + { + par.bits = 16; + par.bps = 2; + par.sig = 1; + } break; + } + + if (deviceType == ma_device_type_capture) { + par.rchan = channels; + } else { + par.pchan = channels; + } + + par.rate = sampleRate; + + internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, par.rate, pConfig->performanceProfile); + + par.round = internalPeriodSizeInFrames; + par.appbufsz = par.round * pDescriptor->periodCount; + + 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; + } + + 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; + } + + internalFormat = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb); + internalChannels = (deviceType == ma_device_type_capture) ? par.rchan : par.pchan; + internalSampleRate = par.rate; + internalPeriods = par.appbufsz / par.round; + internalPeriodSizeInFrames = par.round; + + if (deviceType == ma_device_type_capture) { + pDevice->sndio.handleCapture = handle; + } else { + pDevice->sndio.handlePlayback = handle; + } + + 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); + pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; + pDescriptor->periodCount = internalPeriods; + + return MA_SUCCESS; +} + +static ma_result ma_device_init__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->sndio); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__sndio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); /* <-- Doesn't actually playback until data is written. */ + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__sndio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* + From the documentation: + + The sio_stop() function puts the audio subsystem in the same state as before sio_start() is called. It stops recording, drains the play buffer and then + stops playback. If samples to play are queued but playback hasn't started yet then playback is forced immediately; playback will actually stop once the + buffer is drained. In no case are samples in the play buffer discarded. + + Therefore, sio_stop() performs all of the necessary draining for us. + */ + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) +{ + int result; + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + 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; + } + + if (pFramesWritten != NULL) { + *pFramesWritten = frameCount; + } + + return MA_SUCCESS; +} + +static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) +{ + int result; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + 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; + } + + if (pFramesRead != NULL) { + *pFramesRead = frameCount; + } + + return MA_SUCCESS; +} + +static ma_result ma_context_uninit__sndio(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_sndio); + + (void)pContext; + return MA_SUCCESS; +} + +static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ +#ifndef MA_NO_RUNTIME_LINKING + const char* libsndioNames[] = { + "libsndio.so" + }; + size_t i; + + for (i = 0; i < ma_countof(libsndioNames); ++i) { + pContext->sndio.sndioSO = ma_dlopen(ma_context_get_log(pContext), libsndioNames[i]); + if (pContext->sndio.sndioSO != NULL) { + break; + } + } + + if (pContext->sndio.sndioSO == NULL) { + 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"); +#else + pContext->sndio.sio_open = sio_open; + pContext->sndio.sio_close = sio_close; + pContext->sndio.sio_setpar = sio_setpar; + pContext->sndio.sio_getpar = sio_getpar; + pContext->sndio.sio_getcap = sio_getcap; + pContext->sndio.sio_write = sio_write; + pContext->sndio.sio_read = sio_read; + pContext->sndio.sio_start = sio_start; + pContext->sndio.sio_stop = sio_stop; + pContext->sndio.sio_initpar = sio_initpar; +#endif + + pCallbacks->onContextInit = ma_context_init__sndio; + pCallbacks->onContextUninit = ma_context_uninit__sndio; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__sndio; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__sndio; + pCallbacks->onDeviceInit = ma_device_init__sndio; + pCallbacks->onDeviceUninit = ma_device_uninit__sndio; + pCallbacks->onDeviceStart = ma_device_start__sndio; + pCallbacks->onDeviceStop = ma_device_stop__sndio; + pCallbacks->onDeviceRead = ma_device_read__sndio; + pCallbacks->onDeviceWrite = ma_device_write__sndio; + pCallbacks->onDeviceDataLoop = NULL; + + (void)pConfig; + return MA_SUCCESS; +} +#endif /* MA_HAS_SNDIO */ + + + +/****************************************************************************** + +audio(4) Backend + +******************************************************************************/ +#ifdef MA_HAS_AUDIO4 +#include +#include +#include +#include +#include +#include +#include + +#ifdef __NetBSD__ +#include +#endif + +#if defined(__OpenBSD__) + #include + #if defined(OpenBSD) && OpenBSD >= 201709 + #define MA_AUDIO4_USE_NEW_API + #endif +#endif + +static void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex) +{ + size_t baseLen; + + MA_ASSERT(id != NULL); + MA_ASSERT(idSize > 0); + MA_ASSERT(deviceIndex >= 0); + + baseLen = strlen(base); + MA_ASSERT(idSize > baseLen); + + ma_strcpy_s(id, idSize, base); + ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10); +} + +static ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut) +{ + size_t idLen; + size_t baseLen; + const char* deviceIndexStr; + + MA_ASSERT(id != NULL); + MA_ASSERT(base != NULL); + MA_ASSERT(pIndexOut != NULL); + + idLen = strlen(id); + baseLen = strlen(base); + if (idLen <= baseLen) { + return MA_ERROR; /* Doesn't look like the id starts with the base. */ + } + + if (strncmp(id, base, baseLen) != 0) { + return MA_ERROR; /* ID does not begin with base. */ + } + + deviceIndexStr = id + baseLen; + if (deviceIndexStr[0] == '\0') { + return MA_ERROR; /* No index specified in the ID. */ + } + + if (pIndexOut) { + *pIndexOut = atoi(deviceIndexStr); + } + + return MA_SUCCESS; +} + + +#if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */ +static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision) +{ + if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) { + return ma_format_u8; + } else { + if (ma_is_little_endian() && encoding == AUDIO_ENCODING_SLINEAR_LE) { + if (precision == 16) { + return ma_format_s16; + } else if (precision == 24) { + return ma_format_s24; + } else if (precision == 32) { + return ma_format_s32; + } + } else if (ma_is_big_endian() && encoding == AUDIO_ENCODING_SLINEAR_BE) { + if (precision == 16) { + return ma_format_s16; + } else if (precision == 24) { + return ma_format_s24; + } else if (precision == 32) { + return ma_format_s32; + } + } + } + + return ma_format_unknown; /* Encoding not supported. */ +} + +static void ma_encoding_from_format__audio4(ma_format format, unsigned int* pEncoding, unsigned int* pPrecision) +{ + MA_ASSERT(pEncoding != NULL); + MA_ASSERT(pPrecision != NULL); + + switch (format) + { + case ma_format_u8: + { + *pEncoding = AUDIO_ENCODING_ULINEAR; + *pPrecision = 8; + } break; + + case ma_format_s24: + { + *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; + *pPrecision = 24; + } break; + + case ma_format_s32: + { + *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; + *pPrecision = 32; + } break; + + case ma_format_s16: + case ma_format_f32: + case ma_format_unknown: + default: + { + *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE; + *pPrecision = 16; + } break; + } +} + +static ma_format ma_format_from_prinfo__audio4(struct audio_prinfo* prinfo) +{ + return ma_format_from_encoding__audio4(prinfo->encoding, prinfo->precision); +} + +static ma_format ma_best_format_from_fd__audio4(int fd, ma_format preferredFormat) +{ + audio_encoding_t encoding; + ma_uint32 iFormat; + int counter = 0; + + /* First check to see if the preferred format is supported. */ + if (preferredFormat != ma_format_unknown) { + counter = 0; + for (;;) { + MA_ZERO_OBJECT(&encoding); + encoding.index = counter; + if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) { + break; + } + + if (preferredFormat == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) { + return preferredFormat; /* Found the preferred format. */ + } + + /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */ + counter += 1; + } + } + + /* Getting here means our preferred format is not supported, so fall back to our standard priorities. */ + for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) { + ma_format format = g_maFormatPriorities[iFormat]; + + counter = 0; + for (;;) { + MA_ZERO_OBJECT(&encoding); + encoding.index = counter; + if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) { + break; + } + + if (format == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) { + return format; /* Found a workable format. */ + } + + /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */ + counter += 1; + } + } + + /* Getting here means not appropriate format was found. */ + return ma_format_unknown; +} +#else +static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par) +{ + if (par->bits == 8 && par->bps == 1 && par->sig == 0) { + return ma_format_u8; + } + if (par->bits == 16 && par->bps == 2 && par->sig == 1 && par->le == ma_is_little_endian()) { + return ma_format_s16; + } + if (par->bits == 24 && par->bps == 3 && par->sig == 1 && par->le == ma_is_little_endian()) { + return ma_format_s24; + } + if (par->bits == 32 && par->bps == 4 && par->sig == 1 && par->le == ma_is_little_endian()) { + return ma_format_f32; + } + + /* Format not supported. */ + return ma_format_unknown; +} +#endif + +static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pDeviceInfo) +{ + audio_device_t fdDevice; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(fd >= 0); + MA_ASSERT(pDeviceInfo != NULL); + + (void)pContext; + (void)deviceType; + + if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) { + return MA_ERROR; /* Failed to retrieve device info. */ + } + + /* Name. */ + ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), fdDevice.name); + + #if !defined(MA_AUDIO4_USE_NEW_API) + { + audio_info_t fdInfo; + int counter = 0; + 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; + sampleRate = fdInfo.play.sample_rate; + } else { + channels = fdInfo.record.channels; + sampleRate = fdInfo.record.sample_rate; + } + + /* Supported formats. We get this by looking at the encodings. */ + pDeviceInfo->nativeDataFormatCount = 0; + for (;;) { + audio_encoding_t encoding; + ma_format format; + + MA_ZERO_OBJECT(&encoding); + encoding.index = counter; + if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) { + break; + } + + format = ma_format_from_encoding__audio4(encoding.encoding, encoding.precision); + if (format != ma_format_unknown) { + ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0); + } + + counter += 1; + } + } + #else + { + struct audio_swpar fdPar; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + + if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) { + return MA_ERROR; + } + + format = ma_format_from_swpar__audio4(&fdPar); + if (format == ma_format_unknown) { + return MA_FORMAT_NOT_SUPPORTED; + } + + if (deviceType == ma_device_type_playback) { + channels = fdPar.pchan; + } else { + channels = fdPar.rchan; + } + + sampleRate = fdPar.rate; + + pDeviceInfo->nativeDataFormatCount = 0; + ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0); + } + #endif + + return MA_SUCCESS; +} + +static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + const int maxDevices = 64; + char devpath[256]; + int iDevice; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* + Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN" + version here since we can open it even when another process has control of the "/dev/audioN" device. + */ + for (iDevice = 0; iDevice < maxDevices; ++iDevice) { + struct stat st; + int fd; + ma_bool32 isTerminating = MA_FALSE; + + ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl"); + ma_itoa_s(iDevice, devpath+strlen(devpath), sizeof(devpath)-strlen(devpath), 10); + + if (stat(devpath, &st) < 0) { + break; + } + + /* The device exists, but we need to check if it's usable as playback and/or capture. */ + + /* Playback. */ + if (!isTerminating) { + fd = open(devpath, O_RDONLY, 0); + if (fd >= 0) { + /* Supports playback. */ + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice); + if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) { + isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + + close(fd); + } + } + + /* Capture. */ + if (!isTerminating) { + fd = open(devpath, O_WRONLY, 0); + if (fd >= 0) { + /* Supports capture. */ + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice); + if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) { + isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + + close(fd); + } + } + + if (isTerminating) { + break; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__audio4(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + int fd = -1; + int deviceIndex = -1; + char ctlid[256]; + ma_result result; + + MA_ASSERT(pContext != NULL); + + /* + We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number + from the device ID which will be in "/dev/audioN" format. + */ + if (pDeviceID == NULL) { + /* Default device. */ + ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl"); + } else { + /* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */ + result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex); + if (result != MA_SUCCESS) { + return result; + } + + ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex); + } + + fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0); + if (fd == -1) { + return MA_NO_DEVICE; + } + + if (deviceIndex == -1) { + ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio"); + } else { + ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex); + } + + result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo); + + close(fd); + return result; +} + +static ma_result ma_device_uninit__audio4(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + close(pDevice->audio4.fdCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + close(pDevice->audio4.fdPlayback); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) +{ + const char* pDefaultDeviceNames[] = { + "/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; + ma_uint32 internalPeriodSizeInFrames; + ma_uint32 internalPeriods; + + MA_ASSERT(pConfig != NULL); + MA_ASSERT(deviceType != ma_device_type_duplex); + MA_ASSERT(pDevice != NULL); + + /* The first thing to do is open the file. */ + if (deviceType == ma_device_type_capture) { + fdFlags = O_RDONLY; + } else { + fdFlags = O_WRONLY; + } + /*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); + if (fd != -1) { + break; + } + } + } 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); + } + + #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 + following: + + Regardless of formats supported by underlying driver, the audio driver accepts the + following formats. + + By then the next sentence says this: + + `encoding` and `precision` are one of the values obtained by AUDIO_GETENC. + + It sounds like a direct contradiction to me. I'm going to play this safe any only use the + best sample format returned by AUDIO_GETENC. If the requested format is supported we'll + use that, but otherwise we'll just use our standard format priorities to pick an + appropriate one. + */ + 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; + ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.record.encoding, &fdInfo.record.precision); + + if (pDescriptor->channels != 0) { + fdInfo.record.channels = ma_clamp(pDescriptor->channels, 1, 12); /* From the documentation: `channels` ranges from 1 to 12. */ + } + + if (pDescriptor->sampleRate != 0) { + fdInfo.record.sample_rate = ma_clamp(pDescriptor->sampleRate, 1000, 192000); /* From the documentation: `frequency` ranges from 1000Hz to 192000Hz. (They mean `sample_rate` instead of `frequency`.) */ + } + } else { + fdInfo.mode = AUMODE_PLAY; + ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.play.encoding, &fdInfo.play.precision); + + if (pDescriptor->channels != 0) { + fdInfo.play.channels = ma_clamp(pDescriptor->channels, 1, 12); /* From the documentation: `channels` ranges from 1 to 12. */ + } + + if (pDescriptor->sampleRate != 0) { + fdInfo.play.sample_rate = ma_clamp(pDescriptor->sampleRate, 1000, 192000); /* From the documentation: `frequency` ranges from 1000Hz to 192000Hz. (They mean `sample_rate` instead of `frequency`.) */ + } + } + + 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); + } + + 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); + } + + if (deviceType == ma_device_type_capture) { + internalFormat = ma_format_from_prinfo__audio4(&fdInfo.record); + internalChannels = fdInfo.record.channels; + internalSampleRate = fdInfo.record.sample_rate; + } else { + internalFormat = ma_format_from_prinfo__audio4(&fdInfo.play); + internalChannels = fdInfo.play.channels; + internalSampleRate = fdInfo.play.sample_rate; + } + + 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; + } + + /* Buffer. */ + { + ma_uint32 internalPeriodSizeInBytes; + + internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile); + + internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels); + if (internalPeriodSizeInBytes < 16) { + internalPeriodSizeInBytes = 16; + } + + internalPeriods = pDescriptor->periodCount; + if (internalPeriods < 2) { + internalPeriods = 2; + } + + /* What miniaudio calls a period, audio4 calls a block. */ + AUDIO_INITINFO(&fdInfo); + fdInfo.hiwat = internalPeriods; + fdInfo.lowat = internalPeriods-1; + 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); + } + + internalPeriods = fdInfo.hiwat; + internalPeriodSizeInFrames = fdInfo.blocksize / ma_get_bytes_per_frame(internalFormat, internalChannels); + } + } + #else + { + struct audio_swpar fdPar; + + /* 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); + } + + internalFormat = ma_format_from_swpar__audio4(&fdPar); + internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan; + internalSampleRate = fdPar.rate; + + 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; + } + + /* Buffer. */ + { + ma_uint32 internalPeriodSizeInBytes; + + internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile); + + /* What miniaudio calls a period, audio4 calls a block. */ + internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels); + if (internalPeriodSizeInBytes < 16) { + internalPeriodSizeInBytes = 16; + } + + fdPar.nblks = pDescriptor->periodCount; + fdPar.round = internalPeriodSizeInBytes; + + 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); + } + + 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); + } + } + + internalFormat = ma_format_from_swpar__audio4(&fdPar); + internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan; + internalSampleRate = fdPar.rate; + internalPeriods = fdPar.nblks; + internalPeriodSizeInFrames = fdPar.round / ma_get_bytes_per_frame(internalFormat, internalChannels); + } + #endif + + 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; + } + + if (deviceType == ma_device_type_capture) { + pDevice->audio4.fdCapture = fd; + } else { + pDevice->audio4.fdPlayback = fd; + } + + 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); + pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames; + pDescriptor->periodCount = internalPeriods; + + return MA_SUCCESS; +} + +static ma_result ma_device_init__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + MA_ASSERT(pDevice != NULL); + + MA_ZERO_OBJECT(&pDevice->audio4); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + pDevice->audio4.fdCapture = -1; + pDevice->audio4.fdPlayback = -1; + + /* + The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD + introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as + I'm aware. + */ +#if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000 + /* NetBSD 8.0+ */ + 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; + } +#else + /* All other flavors. */ +#endif + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback); + if (result != MA_SUCCESS) { + if (pConfig->deviceType == ma_device_type_duplex) { + close(pDevice->audio4.fdCapture); + } + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__audio4(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + if (pDevice->audio4.fdCapture == -1) { + return MA_INVALID_ARGS; + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + if (pDevice->audio4.fdPlayback == -1) { + return MA_INVALID_ARGS; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd) +{ + if (fd == -1) { + return MA_INVALID_ARGS; + } + +#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); + } +#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); + } +#endif + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__audio4(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_result result; + + result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_result result; + + /* Drain the device first. If this fails we'll just need to flush without draining. Unfortunately draining isn't available on newer version of OpenBSD. */ + #if !defined(MA_AUDIO4_USE_NEW_API) + ioctl(pDevice->audio4.fdPlayback, AUDIO_DRAIN, 0); + #endif + + /* Here is where the device is stopped immediately. */ + result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) +{ + int result; + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + 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); + } + + if (pFramesWritten != NULL) { + *pFramesWritten = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) +{ + int result; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + 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); + } + + if (pFramesRead != NULL) { + *pFramesRead = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + } + + return MA_SUCCESS; +} + +static ma_result ma_context_uninit__audio4(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_audio4); + + (void)pContext; + return MA_SUCCESS; +} + +static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + MA_ASSERT(pContext != NULL); + + (void)pConfig; + + pCallbacks->onContextInit = ma_context_init__audio4; + pCallbacks->onContextUninit = ma_context_uninit__audio4; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__audio4; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__audio4; + pCallbacks->onDeviceInit = ma_device_init__audio4; + pCallbacks->onDeviceUninit = ma_device_uninit__audio4; + pCallbacks->onDeviceStart = ma_device_start__audio4; + pCallbacks->onDeviceStop = ma_device_stop__audio4; + pCallbacks->onDeviceRead = ma_device_read__audio4; + pCallbacks->onDeviceWrite = ma_device_write__audio4; + pCallbacks->onDeviceDataLoop = NULL; + + return MA_SUCCESS; +} +#endif /* MA_HAS_AUDIO4 */ + + +/****************************************************************************** + +OSS Backend + +******************************************************************************/ +#ifdef MA_HAS_OSS +#include +#include +#include +#include + +#ifndef SNDCTL_DSP_HALT +#define SNDCTL_DSP_HALT SNDCTL_DSP_RESET +#endif + +#define MA_OSS_DEFAULT_DEVICE_NAME "/dev/dsp" + +static int ma_open_temp_device__oss() +{ + /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */ + int fd = open("/dev/mixer", O_RDONLY, 0); + if (fd >= 0) { + return fd; + } + + return -1; +} + +static ma_result ma_context_open_device__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, int* pfd) +{ + const char* deviceName; + int flags; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pfd != NULL); + (void)pContext; + + *pfd = -1; + + /* This function should only be called for playback or capture, not duplex. */ + if (deviceType == ma_device_type_duplex) { + return MA_INVALID_ARGS; + } + + deviceName = MA_OSS_DEFAULT_DEVICE_NAME; + if (pDeviceID != NULL) { + deviceName = pDeviceID->oss; + } + + flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY; + if (shareMode == ma_share_mode_exclusive) { + flags |= O_EXCL; + } + + *pfd = open(deviceName, flags, 0); + if (*pfd == -1) { + return ma_result_from_errno(errno); + } + + return MA_SUCCESS; +} + +static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + int fd; + oss_sysinfo si; + int result; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + 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; + } + + result = ioctl(fd, SNDCTL_SYSINFO, &si); + if (result != -1) { + int iAudioDevice; + for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { + oss_audioinfo ai; + ai.dev = iAudioDevice; + result = ioctl(fd, SNDCTL_AUDIOINFO, &ai); + if (result != -1) { + if (ai.devnode[0] != '\0') { /* <-- Can be blank, according to documentation. */ + ma_device_info deviceInfo; + ma_bool32 isTerminating = MA_FALSE; + + MA_ZERO_OBJECT(&deviceInfo); + + /* ID */ + ma_strncpy_s(deviceInfo.id.oss, sizeof(deviceInfo.id.oss), ai.devnode, (size_t)-1); + + /* + The human readable device name should be in the "ai.handle" variable, but it can + sometimes be empty in which case we just fall back to "ai.name" which is less user + friendly, but usually has a value. + */ + if (ai.handle[0] != '\0') { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.handle, (size_t)-1); + } else { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.name, (size_t)-1); + } + + /* The device can be both playback and capture. */ + if (!isTerminating && (ai.caps & PCM_CAP_OUTPUT) != 0) { + isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + if (!isTerminating && (ai.caps & PCM_CAP_INPUT) != 0) { + isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + + if (isTerminating) { + break; + } + } + } + } + } 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; + } + + close(fd); + return MA_SUCCESS; +} + +static void ma_context_add_native_data_format__oss(ma_context* pContext, oss_audioinfo* pAudioInfo, ma_format format, ma_device_info* pDeviceInfo) +{ + unsigned int minChannels; + unsigned int maxChannels; + unsigned int iRate; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pAudioInfo != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + /* If we support all channels we just report 0. */ + minChannels = ma_clamp(pAudioInfo->min_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS); + maxChannels = ma_clamp(pAudioInfo->max_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS); + + /* + OSS has this annoying thing where sample rates can be reported in two ways. We prefer explicitness, + which OSS has in the form of nrates/rates, however there are times where nrates can be 0, in which + case we'll need to use min_rate and max_rate and report only standard rates. + */ + if (pAudioInfo->nrates > 0) { + for (iRate = 0; iRate < pAudioInfo->nrates; iRate += 1) { + unsigned int rate = pAudioInfo->rates[iRate]; + + if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) { + ma_device_info_add_native_data_format(pDeviceInfo, format, 0, rate, 0); /* Set the channel count to 0 to indicate that all channel counts are supported. */ + } else { + unsigned int iChannel; + for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) { + ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, rate, 0); + } + } + } + } else { + for (iRate = 0; iRate < ma_countof(g_maStandardSampleRatePriorities); iRate += 1) { + ma_uint32 standardRate = g_maStandardSampleRatePriorities[iRate]; + + if (standardRate >= (ma_uint32)pAudioInfo->min_rate && standardRate <= (ma_uint32)pAudioInfo->max_rate) { + if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) { + ma_device_info_add_native_data_format(pDeviceInfo, format, 0, standardRate, 0); /* Set the channel count to 0 to indicate that all channel counts are supported. */ + } else { + unsigned int iChannel; + for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) { + ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, standardRate, 0); + } + } + } + } + } +} + +static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_bool32 foundDevice; + int fdTemp; + oss_sysinfo si; + int result; + + MA_ASSERT(pContext != NULL); + + /* Handle the default device a little differently. */ + if (pDeviceID == NULL) { + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + + return MA_SUCCESS; + } + + + /* If we get here it means we are _not_ using the default device. */ + foundDevice = MA_FALSE; + + 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; + } + + result = ioctl(fdTemp, SNDCTL_SYSINFO, &si); + if (result != -1) { + int iAudioDevice; + for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) { + oss_audioinfo ai; + ai.dev = iAudioDevice; + result = ioctl(fdTemp, SNDCTL_AUDIOINFO, &ai); + if (result != -1) { + if (ma_strcmp(ai.devnode, pDeviceID->oss) == 0) { + /* It has the same name, so now just confirm the type. */ + if ((deviceType == ma_device_type_playback && ((ai.caps & PCM_CAP_OUTPUT) != 0)) || + (deviceType == ma_device_type_capture && ((ai.caps & PCM_CAP_INPUT) != 0))) { + unsigned int formatMask; + + /* ID */ + ma_strncpy_s(pDeviceInfo->id.oss, sizeof(pDeviceInfo->id.oss), ai.devnode, (size_t)-1); + + /* + The human readable device name should be in the "ai.handle" variable, but it can + sometimes be empty in which case we just fall back to "ai.name" which is less user + friendly, but usually has a value. + */ + if (ai.handle[0] != '\0') { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.handle, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1); + } + + + pDeviceInfo->nativeDataFormatCount = 0; + + if (deviceType == ma_device_type_playback) { + formatMask = ai.oformats; + } else { + formatMask = ai.iformats; + } + + if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) { + ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s16, pDeviceInfo); + } + if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) { + ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s32, pDeviceInfo); + } + if ((formatMask & AFMT_U8) != 0) { + ma_context_add_native_data_format__oss(pContext, &ai, ma_format_u8, pDeviceInfo); + } + + foundDevice = MA_TRUE; + break; + } + } + } + } + } 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; + } + + + close(fdTemp); + + if (!foundDevice) { + return MA_NO_DEVICE; + } + + return MA_SUCCESS; +} + +static ma_result ma_device_uninit__oss(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + close(pDevice->oss.fdCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + close(pDevice->oss.fdPlayback); + } + + return MA_SUCCESS; +} + +static int ma_format_to_oss(ma_format format) +{ + int ossFormat = AFMT_U8; + switch (format) { + case ma_format_s16: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break; + case ma_format_s24: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break; + case ma_format_s32: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break; + case ma_format_f32: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break; + case ma_format_u8: + default: ossFormat = AFMT_U8; break; + } + + return ossFormat; +} + +static ma_format ma_format_from_oss(int ossFormat) +{ + if (ossFormat == AFMT_U8) { + return ma_format_u8; + } else { + if (ma_is_little_endian()) { + switch (ossFormat) { + case AFMT_S16_LE: return ma_format_s16; + case AFMT_S32_LE: return ma_format_s32; + default: return ma_format_unknown; + } + } else { + switch (ossFormat) { + case AFMT_S16_BE: return ma_format_s16; + case AFMT_S32_BE: return ma_format_s32; + default: return ma_format_unknown; + } + } + } + + return ma_format_unknown; +} + +static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType) +{ + ma_result result; + int ossResult; + int fd; + const ma_device_id* pDeviceID = NULL; + ma_share_mode shareMode; + int ossFormat; + int ossChannels; + int ossSampleRate; + int ossFragment; + + 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. */ + ossChannels = (int)(pDescriptor->channels > 0) ? pDescriptor->channels : MA_DEFAULT_CHANNELS; + ossSampleRate = (int)(pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE; + + 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; + } + + /* + The OSS documentation is very clear about the order we should be initializing the device's properties: + 1) Format + 2) Channels + 3) Sample rate. + */ + + /* Format. */ + 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); + } + + /* 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); + } + + /* 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); + } + + /* + Buffer. + + The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if + it should be done before or after format/channels/rate. + + OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual + value. + */ + { + ma_uint32 periodSizeInFrames; + ma_uint32 periodSizeInBytes; + ma_uint32 ossFragmentSizePower; + + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, (ma_uint32)ossSampleRate, pConfig->performanceProfile); + + periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels)); + if (periodSizeInBytes < 16) { + periodSizeInBytes = 16; + } + + ossFragmentSizePower = 4; + periodSizeInBytes >>= 4; + while (periodSizeInBytes >>= 1) { + ossFragmentSizePower += 1; + } + + ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower); + 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); + } + } + + /* Internal settings. */ + if (deviceType == ma_device_type_capture) { + pDevice->oss.fdCapture = fd; + } else { + pDevice->oss.fdPlayback = fd; + } + + 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); + 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_SUCCESS; +} + +static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pConfig != NULL); + + MA_ZERO_OBJECT(&pDevice->oss); + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + 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; + } + } + + 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_SUCCESS; +} + +/* +Note on Starting and Stopping +============================= +In the past I was using SNDCTL_DSP_HALT to stop the device, however this results in issues when +trying to resume the device again. If we use SNDCTL_DSP_HALT, the next write() or read() will +fail. Instead what we need to do is just not write or read to and from the device when the +device is not running. + +As a result, both the start and stop functions for OSS are just empty stubs. The starting and +stopping logic is handled by ma_device_write__oss() and ma_device_read__oss(). These will check +the device state, and if the device is stopped they will simply not do any kind of processing. + +The downside to this technique is that I've noticed a fairly lengthy delay in stopping the +device, up to a second. This is on a virtual machine, and as such might just be due to the +virtual drivers, but I'm not fully sure. I am not sure how to work around this problem so for +the moment that's just how it's going to have to be. + +When starting the device, OSS will automatically start it when write() or read() is called. +*/ +static ma_result ma_device_start__oss(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* The device is automatically started with reading and writing. */ + (void)pDevice; + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__oss(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* See note above on why this is empty. */ + (void)pDevice; + + return MA_SUCCESS; +} + +static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten) +{ + int resultOSS; + ma_uint32 deviceState; + + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + /* 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) { + 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); + } + + if (pFramesWritten != NULL) { + *pFramesWritten = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + } + + return MA_SUCCESS; +} + +static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead) +{ + int resultOSS; + ma_uint32 deviceState; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + /* 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) { + 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); + } + + if (pFramesRead != NULL) { + *pFramesRead = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + } + + return MA_SUCCESS; +} + +static ma_result ma_context_uninit__oss(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_oss); + + (void)pContext; + return MA_SUCCESS; +} + +static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + int fd; + int ossVersion; + int result; + + MA_ASSERT(pContext != NULL); + + (void)pConfig; + + /* 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; + } + + /* Grab the OSS version. */ + ossVersion = 0; + 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; + } + + /* The file handle to temp device is no longer needed. Close ASAP. */ + close(fd); + + pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16); + pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8); + + pCallbacks->onContextInit = ma_context_init__oss; + pCallbacks->onContextUninit = ma_context_uninit__oss; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__oss; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__oss; + pCallbacks->onDeviceInit = ma_device_init__oss; + pCallbacks->onDeviceUninit = ma_device_uninit__oss; + pCallbacks->onDeviceStart = ma_device_start__oss; + pCallbacks->onDeviceStop = ma_device_stop__oss; + pCallbacks->onDeviceRead = ma_device_read__oss; + pCallbacks->onDeviceWrite = ma_device_write__oss; + pCallbacks->onDeviceDataLoop = NULL; + + return MA_SUCCESS; +} +#endif /* MA_HAS_OSS */ + + + + + +/****************************************************************************** + +AAudio Backend + +******************************************************************************/ +#ifdef MA_HAS_AAUDIO + +#ifdef MA_NO_RUNTIME_LINKING + #include +#endif + +typedef int32_t ma_aaudio_result_t; +typedef int32_t ma_aaudio_direction_t; +typedef int32_t ma_aaudio_sharing_mode_t; +typedef int32_t ma_aaudio_format_t; +typedef int32_t ma_aaudio_stream_state_t; +typedef int32_t ma_aaudio_performance_mode_t; +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; + +#define MA_AAUDIO_UNSPECIFIED 0 + +/* Result codes. miniaudio only cares about the success code. */ +#define MA_AAUDIO_OK 0 + +/* Directions. */ +#define MA_AAUDIO_DIRECTION_OUTPUT 0 +#define MA_AAUDIO_DIRECTION_INPUT 1 + +/* Sharing modes. */ +#define MA_AAUDIO_SHARING_MODE_EXCLUSIVE 0 +#define MA_AAUDIO_SHARING_MODE_SHARED 1 + +/* Formats. */ +#define MA_AAUDIO_FORMAT_PCM_I16 1 +#define MA_AAUDIO_FORMAT_PCM_FLOAT 2 + +/* Stream states. */ +#define MA_AAUDIO_STREAM_STATE_UNINITIALIZED 0 +#define MA_AAUDIO_STREAM_STATE_UNKNOWN 1 +#define MA_AAUDIO_STREAM_STATE_OPEN 2 +#define MA_AAUDIO_STREAM_STATE_STARTING 3 +#define MA_AAUDIO_STREAM_STATE_STARTED 4 +#define MA_AAUDIO_STREAM_STATE_PAUSING 5 +#define MA_AAUDIO_STREAM_STATE_PAUSED 6 +#define MA_AAUDIO_STREAM_STATE_FLUSHING 7 +#define MA_AAUDIO_STREAM_STATE_FLUSHED 8 +#define MA_AAUDIO_STREAM_STATE_STOPPING 9 +#define MA_AAUDIO_STREAM_STATE_STOPPED 10 +#define MA_AAUDIO_STREAM_STATE_CLOSING 11 +#define MA_AAUDIO_STREAM_STATE_CLOSED 12 +#define MA_AAUDIO_STREAM_STATE_DISCONNECTED 13 + +/* Performance modes. */ +#define MA_AAUDIO_PERFORMANCE_MODE_NONE 10 +#define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING 11 +#define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY 12 + +/* Usage types. */ +#define MA_AAUDIO_USAGE_MEDIA 1 +#define MA_AAUDIO_USAGE_VOICE_COMMUNICATION 2 +#define MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING 3 +#define MA_AAUDIO_USAGE_ALARM 4 +#define MA_AAUDIO_USAGE_NOTIFICATION 5 +#define MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE 6 +#define MA_AAUDIO_USAGE_NOTIFICATION_EVENT 10 +#define MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY 11 +#define MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE 12 +#define MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION 13 +#define MA_AAUDIO_USAGE_GAME 14 +#define MA_AAUDIO_USAGE_ASSISTANT 16 +#define MA_AAUDIO_SYSTEM_USAGE_EMERGENCY 1000 +#define MA_AAUDIO_SYSTEM_USAGE_SAFETY 1001 +#define MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS 1002 +#define MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT 1003 + +/* Content types. */ +#define MA_AAUDIO_CONTENT_TYPE_SPEECH 1 +#define MA_AAUDIO_CONTENT_TYPE_MUSIC 2 +#define MA_AAUDIO_CONTENT_TYPE_MOVIE 3 +#define MA_AAUDIO_CONTENT_TYPE_SONIFICATION 4 + +/* Input presets. */ +#define MA_AAUDIO_INPUT_PRESET_GENERIC 1 +#define MA_AAUDIO_INPUT_PRESET_CAMCORDER 5 +#define MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION 6 +#define MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION 7 +#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 + + +typedef ma_aaudio_data_callback_result_t (* ma_AAudioStream_dataCallback) (ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames); +typedef void (* ma_AAudioStream_errorCallback)(ma_AAudioStream *pStream, void *pUserData, ma_aaudio_result_t error); + +typedef ma_aaudio_result_t (* MA_PFN_AAudio_createStreamBuilder) (ma_AAudioStreamBuilder** ppBuilder); +typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_delete) (ma_AAudioStreamBuilder* pBuilder); +typedef void (* MA_PFN_AAudioStreamBuilder_setDeviceId) (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId); +typedef void (* MA_PFN_AAudioStreamBuilder_setDirection) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction); +typedef void (* MA_PFN_AAudioStreamBuilder_setSharingMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode); +typedef void (* MA_PFN_AAudioStreamBuilder_setFormat) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format); +typedef void (* MA_PFN_AAudioStreamBuilder_setChannelCount) (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount); +typedef void (* MA_PFN_AAudioStreamBuilder_setSampleRate) (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate); +typedef void (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames); +typedef void (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames); +typedef void (* MA_PFN_AAudioStreamBuilder_setDataCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData); +typedef void (* MA_PFN_AAudioStreamBuilder_setErrorCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_errorCallback callback, void* pUserData); +typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode); +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); +typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_waitForStateChange) (ma_AAudioStream* pStream, ma_aaudio_stream_state_t inputState, ma_aaudio_stream_state_t* pNextState, int64_t timeoutInNanoseconds); +typedef ma_aaudio_format_t (* MA_PFN_AAudioStream_getFormat) (ma_AAudioStream* pStream); +typedef int32_t (* MA_PFN_AAudioStream_getChannelCount) (ma_AAudioStream* pStream); +typedef int32_t (* MA_PFN_AAudioStream_getSampleRate) (ma_AAudioStream* pStream); +typedef int32_t (* MA_PFN_AAudioStream_getBufferCapacityInFrames) (ma_AAudioStream* pStream); +typedef int32_t (* MA_PFN_AAudioStream_getFramesPerDataCallback) (ma_AAudioStream* pStream); +typedef int32_t (* MA_PFN_AAudioStream_getFramesPerBurst) (ma_AAudioStream* pStream); +typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStart) (ma_AAudioStream* pStream); +typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStop) (ma_AAudioStream* pStream); + +static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA) +{ + switch (resultAA) + { + case MA_AAUDIO_OK: return MA_SUCCESS; + default: break; + } + + return MA_ERROR; +} + +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; + default: break; + } + + return MA_AAUDIO_USAGE_MEDIA; +} + +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_sonification: return MA_AAUDIO_CONTENT_TYPE_SONIFICATION; + default: break; + } + + return MA_AAUDIO_CONTENT_TYPE_SPEECH; +} + +static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_preset inputPreset) +{ + 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_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; + } + + 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)); + /* + 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. + */ + 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; + } +} + +static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount) +{ + 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); + } + + (void)pStream; + return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; +} + +static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount) +{ + 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); + } + + (void)pStream; + return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; +} + +static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* pContext, const ma_device_id* pDeviceID, ma_device_type deviceType, ma_share_mode shareMode, const ma_device_descriptor* pDescriptor, const ma_device_config* pConfig, ma_device* pDevice, ma_AAudioStreamBuilder** ppBuilder) +{ + ma_AAudioStreamBuilder* pBuilder; + ma_aaudio_result_t resultAA; + + /* Safety. */ + *ppBuilder = NULL; + + resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder); + if (resultAA != MA_AAUDIO_OK) { + return ma_result_from_aaudio(resultAA); + } + + if (pDeviceID != NULL) { + ((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio); + } + + ((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT); + ((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE); + + + /* If we have a device descriptor make sure we configure the stream builder to take our requested parameters. */ + if (pDescriptor != NULL) { + MA_ASSERT(pConfig != NULL); /* We must have a device config if we also have a descriptor. The config is required for AAudio specific configuration options. */ + + if (pDescriptor->sampleRate != 0) { + ((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 (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. + */ + 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... :/ + + 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); + } + + if (deviceType == ma_device_type_capture) { + if (pConfig->aaudio.inputPreset != ma_aaudio_input_preset_default && pContext->aaudio.AAudioStreamBuilder_setInputPreset != NULL) { + ((MA_PFN_AAudioStreamBuilder_setInputPreset)pContext->aaudio.AAudioStreamBuilder_setInputPreset)(pBuilder, ma_to_input_preset__aaudio(pConfig->aaudio.inputPreset)); + } + + ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_capture__aaudio, (void*)pDevice); + } else { + if (pConfig->aaudio.usage != ma_aaudio_usage_default && pContext->aaudio.AAudioStreamBuilder_setUsage != NULL) { + ((MA_PFN_AAudioStreamBuilder_setUsage)pContext->aaudio.AAudioStreamBuilder_setUsage)(pBuilder, ma_to_usage__aaudio(pConfig->aaudio.usage)); + } + + if (pConfig->aaudio.contentType != ma_aaudio_content_type_default && pContext->aaudio.AAudioStreamBuilder_setContentType != NULL) { + ((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. + */ + ((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); + } + } + + *ppBuilder = pBuilder; + + return MA_SUCCESS; +} + +static ma_result ma_open_stream_and_close_builder__aaudio(ma_context* pContext, ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream) +{ + ma_result result; + + result = ma_result_from_aaudio(((MA_PFN_AAudioStreamBuilder_openStream)pContext->aaudio.AAudioStreamBuilder_openStream)(pBuilder, ppStream)); + ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder); + + return result; +} + +static ma_result ma_open_stream_basic__aaudio(ma_context* pContext, const ma_device_id* pDeviceID, ma_device_type deviceType, ma_share_mode shareMode, ma_AAudioStream** ppStream) +{ + ma_result result; + ma_AAudioStreamBuilder* pBuilder; + + *ppStream = NULL; + + result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pContext, pDeviceID, deviceType, shareMode, NULL, NULL, NULL, &pBuilder); + if (result != MA_SUCCESS) { + 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); +} + +static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_type deviceType, const ma_device_descriptor* pDescriptor, ma_AAudioStream** ppStream) +{ + 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. */ + + *ppStream = NULL; + + result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pDevice->pContext, pDescriptor->pDeviceID, deviceType, pDescriptor->shareMode, pDescriptor, pConfig, pDevice, &pBuilder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_open_stream_and_close_builder__aaudio(pDevice->pContext, pBuilder, ppStream); +} + +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)); +} + +static ma_bool32 ma_has_default_device__aaudio(ma_context* pContext, ma_device_type deviceType) +{ + /* The only way to know this is to try creating a stream. */ + ma_AAudioStream* pStream; + ma_result result = ma_open_stream_basic__aaudio(pContext, NULL, deviceType, ma_share_mode_shared, &pStream); + if (result != MA_SUCCESS) { + return MA_FALSE; + } + + ma_close_stream__aaudio(pContext, pStream); + return MA_TRUE; +} + +static ma_result ma_wait_for_simple_state_transition__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_aaudio_stream_state_t oldState, ma_aaudio_stream_state_t newState) +{ + ma_aaudio_stream_state_t actualNewState; + ma_aaudio_result_t resultAA = ((MA_PFN_AAudioStream_waitForStateChange)pContext->aaudio.AAudioStream_waitForStateChange)(pStream, oldState, &actualNewState, 5000000000); /* 5 second timeout. */ + if (resultAA != MA_AAUDIO_OK) { + return ma_result_from_aaudio(resultAA); + } + + if (newState != actualNewState) { + return MA_ERROR; /* Failed to transition into the expected state. */ + } + + return MA_SUCCESS; +} + + +static ma_result ma_context_enumerate_devices__aaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 cbResult = MA_TRUE; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Unfortunately AAudio does not have an enumeration API. Therefore I'm only going to report default devices, but only if it can instantiate a stream. */ + + /* Playback. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED; + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + + if (ma_has_default_device__aaudio(pContext, ma_device_type_playback)) { + cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + } + + /* Capture. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED; + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + + if (ma_has_default_device__aaudio(pContext, ma_device_type_capture)) { + cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + } + + return MA_SUCCESS; +} + +static void ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_format format, ma_uint32 flags, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pStream != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)(pStream); + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)(pStream); + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = flags; + pDeviceInfo->nativeDataFormatCount += 1; +} + +static void ma_context_add_native_data_format_from_AAudioStream__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_uint32 flags, ma_device_info* pDeviceInfo) +{ + /* AAudio supports s16 and f32. */ + ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_f32, flags, pDeviceInfo); + ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_s16, flags, pDeviceInfo); +} + +static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + ma_AAudioStream* pStream; + ma_result result; + + MA_ASSERT(pContext != NULL); + + /* ID */ + if (pDeviceID != NULL) { + pDeviceInfo->id.aaudio = pDeviceID->aaudio; + } else { + pDeviceInfo->id.aaudio = MA_AAUDIO_UNSPECIFIED; + } + + /* Name */ + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + + + pDeviceInfo->nativeDataFormatCount = 0; + + /* We'll need to open the device to get accurate sample rate and channel count information. */ + result = ma_open_stream_basic__aaudio(pContext, pDeviceID, deviceType, ma_share_mode_shared, &pStream); + if (result != MA_SUCCESS) { + return result; + } + + ma_context_add_native_data_format_from_AAudioStream__aaudio(pContext, pStream, 0, pDeviceInfo); + + ma_close_stream__aaudio(pContext, pStream); + pStream = NULL; + + 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); + } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + + /* Destroy re-routing lock. */ + ma_mutex_uninit(&pDevice->aaudio.rerouteLock); + + return MA_SUCCESS; +} + +static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_type deviceType, ma_device_descriptor* pDescriptor, ma_AAudioStream** ppStream) +{ + ma_result result; + int32_t bufferCapacityInFrames; + int32_t framesPerDataCallback; + ma_AAudioStream* pStream; + + MA_ASSERT(pDevice != NULL); + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDescriptor != NULL); + + *ppStream = NULL; /* Safety. */ + + /* First step is to open the stream. From there we'll be able to extract the internal configuration. */ + result = ma_open_stream__aaudio(pDevice, pConfig, deviceType, pDescriptor, &pStream); + if (result != MA_SUCCESS) { + return result; /* Failed to open the AAudio stream. */ + } + + /* Now extract the internal configuration. */ + pDescriptor->format = (((MA_PFN_AAudioStream_getFormat)pDevice->pContext->aaudio.AAudioStream_getFormat)(pStream) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32; + pDescriptor->channels = ((MA_PFN_AAudioStream_getChannelCount)pDevice->pContext->aaudio.AAudioStream_getChannelCount)(pStream); + pDescriptor->sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pDevice->pContext->aaudio.AAudioStream_getSampleRate)(pStream); + + /* 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. */ + } else { + ma_channel_map_init_blank(pDescriptor->channelMap, MA_MAX_CHANNELS); /* Too many channels. Use a blank channel map. */ + } + + bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pDevice->pContext->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream); + framesPerDataCallback = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pDevice->pContext->aaudio.AAudioStream_getFramesPerDataCallback)(pStream); + + if (framesPerDataCallback > 0) { + pDescriptor->periodSizeInFrames = framesPerDataCallback; + pDescriptor->periodCount = bufferCapacityInFrames / framesPerDataCallback; + } else { + pDescriptor->periodSizeInFrames = bufferCapacityInFrames; + pDescriptor->periodCount = 1; + } + + *ppStream = pStream; + + 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) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + if (pConfig->deviceType == ma_device_type_loopback) { + 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; + + 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); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_playback, pDescriptorPlayback, (ma_AAudioStream**)&pDevice->aaudio.pStreamPlayback); + if (result != MA_SUCCESS) { + return result; + } + } + + 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; + ma_aaudio_stream_state_t currentState; + + 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? */ + + /* 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); + if (currentState != MA_AAUDIO_STREAM_STATE_STARTED) { + ma_result result; + + if (currentState != MA_AAUDIO_STREAM_STATE_STARTING) { + return MA_ERROR; /* Expecting the stream to be a starting or started state. */ + } + + result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STARTED); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream) +{ + ma_aaudio_result_t resultAA; + ma_aaudio_stream_state_t currentState; + + MA_ASSERT(pDevice != NULL); + + if (pStream == NULL) { + return MA_INVALID_ARGS; + } + + /* + From the AAudio documentation: + + The stream will stop after all of the data currently buffered has been played. + + 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) { + return ma_result_from_aaudio(resultAA); + } + + /* The device should be in either a stopping or stopped state. If it's not set to started we need to wait for it to transition. It should go from stopping to stopped. */ + currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); + if (currentState != MA_AAUDIO_STREAM_STATE_STOPPED) { + ma_result result; + + if (currentState != MA_AAUDIO_STREAM_STATE_STOPPING) { + return MA_ERROR; /* Expecting the stream to be a stopping or stopped state. */ + } + + result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STOPPED); + if (result != MA_SUCCESS) { + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_start__aaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + if (result != MA_SUCCESS) { + if (pDevice->type == ma_device_type_duplex) { + ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + } + return result; + } + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__aaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + if (result != MA_SUCCESS) { + return result; + } + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + if (result != MA_SUCCESS) { + return result; + } + } + + 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; + } +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; +} + + +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); + pContext->aaudio.hAAudio = NULL; + + return MA_SUCCESS; +} + +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]); + if (pContext->aaudio.hAAudio != NULL) { + break; + } + } + + if (pContext->aaudio.hAAudio == NULL) { + 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 + + pCallbacks->onContextInit = ma_context_init__aaudio; + pCallbacks->onContextUninit = ma_context_uninit__aaudio; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__aaudio; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__aaudio; + pCallbacks->onDeviceInit = ma_device_init__aaudio; + pCallbacks->onDeviceUninit = ma_device_uninit__aaudio; + pCallbacks->onDeviceStart = ma_device_start__aaudio; + pCallbacks->onDeviceStop = ma_device_stop__aaudio; + 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 */ + + +/****************************************************************************** + +OpenSL|ES Backend + +******************************************************************************/ +#ifdef MA_HAS_OPENSL +#include +#ifdef MA_ANDROID +#include +#endif + +typedef SLresult (SLAPIENTRY * ma_slCreateEngine_proc)(SLObjectItf* pEngine, SLuint32 numOptions, SLEngineOption* pEngineOptions, SLuint32 numInterfaces, SLInterfaceID* pInterfaceIds, SLboolean* pInterfaceRequired); + +/* OpenSL|ES has one-per-application objects :( */ +static SLObjectItf g_maEngineObjectSL = NULL; +static SLEngineItf g_maEngineSL = NULL; +static ma_uint32 g_maOpenSLInitCounter = 0; +static ma_spinlock g_maOpenSLSpinlock = 0; /* For init/uninit. */ + +#define MA_OPENSL_OBJ(p) (*((SLObjectItf)(p))) +#define MA_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p))) +#define MA_OPENSL_PLAY(p) (*((SLPlayItf)(p))) +#define MA_OPENSL_RECORD(p) (*((SLRecordItf)(p))) + +#ifdef MA_ANDROID +#define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p))) +#else +#define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p))) +#endif + +static ma_result ma_result_from_OpenSL(SLuint32 result) +{ + switch (result) + { + case SL_RESULT_SUCCESS: return MA_SUCCESS; + case SL_RESULT_PRECONDITIONS_VIOLATED: return MA_ERROR; + case SL_RESULT_PARAMETER_INVALID: return MA_INVALID_ARGS; + case SL_RESULT_MEMORY_FAILURE: return MA_OUT_OF_MEMORY; + case SL_RESULT_RESOURCE_ERROR: return MA_INVALID_DATA; + case SL_RESULT_RESOURCE_LOST: return MA_ERROR; + case SL_RESULT_IO_ERROR: return MA_IO_ERROR; + case SL_RESULT_BUFFER_INSUFFICIENT: return MA_NO_SPACE; + case SL_RESULT_CONTENT_CORRUPTED: return MA_INVALID_DATA; + case SL_RESULT_CONTENT_UNSUPPORTED: return MA_FORMAT_NOT_SUPPORTED; + case SL_RESULT_CONTENT_NOT_FOUND: return MA_ERROR; + case SL_RESULT_PERMISSION_DENIED: return MA_ACCESS_DENIED; + case SL_RESULT_FEATURE_UNSUPPORTED: return MA_NOT_IMPLEMENTED; + case SL_RESULT_INTERNAL_ERROR: return MA_ERROR; + case SL_RESULT_UNKNOWN_ERROR: return MA_ERROR; + case SL_RESULT_OPERATION_ABORTED: return MA_ERROR; + case SL_RESULT_CONTROL_LOST: return MA_ERROR; + default: return MA_ERROR; + } +} + +/* Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to miniaudio. */ +static ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id) +{ + switch (id) + { + case SL_SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT; + case SL_SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT; + case SL_SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER; + case SL_SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE; + case SL_SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT; + case SL_SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT; + case SL_SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER; + case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER; + case SL_SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER; + case SL_SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT; + case SL_SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT; + case SL_SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER; + case SL_SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT; + case SL_SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER; + case SL_SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT; + case SL_SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT; + case SL_SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER; + case SL_SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT; + default: return 0; + } +} + +/* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. */ +static SLuint32 ma_channel_id_to_opensl(ma_uint8 id) +{ + switch (id) + { + case MA_CHANNEL_MONO: return SL_SPEAKER_FRONT_CENTER; + case MA_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT; + case MA_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT; + case MA_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER; + case MA_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY; + case MA_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT; + case MA_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT; + case MA_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER; + case MA_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER; + case MA_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER; + case MA_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT; + case MA_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT; + case MA_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER; + case MA_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT; + case MA_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER; + case MA_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT; + case MA_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT; + case MA_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER; + case MA_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT; + default: return 0; + } +} + +/* Converts a channel mapping to an OpenSL-style channel mask. */ +static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel* pChannelMap, ma_uint32 channels) +{ + SLuint32 channelMask = 0; + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + channelMask |= ma_channel_id_to_opensl(pChannelMap[iChannel]); + } + + return channelMask; +} + +/* Converts an OpenSL-style channel mask to a miniaudio channel map. */ +static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel* pChannelMap) +{ + if (channels == 1 && channelMask == 0) { + pChannelMap[0] = MA_CHANNEL_MONO; + } else if (channels == 2 && channelMask == 0) { + pChannelMap[0] = MA_CHANNEL_FRONT_LEFT; + pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT; + } else { + if (channels == 1 && (channelMask & SL_SPEAKER_FRONT_CENTER) != 0) { + pChannelMap[0] = MA_CHANNEL_MONO; + } else { + /* Just iterate over each bit. */ + ma_uint32 iChannel = 0; + ma_uint32 iBit; + for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) { + SLuint32 bitValue = (channelMask & (1UL << iBit)); + if (bitValue != 0) { + /* The bit is set. */ + pChannelMap[iChannel] = ma_channel_id_to_ma__opensl(bitValue); + iChannel += 1; + } + } + } + } +} + +static SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec) +{ + if (samplesPerSec <= SL_SAMPLINGRATE_8) { + return SL_SAMPLINGRATE_8; + } + if (samplesPerSec <= SL_SAMPLINGRATE_11_025) { + return SL_SAMPLINGRATE_11_025; + } + if (samplesPerSec <= SL_SAMPLINGRATE_12) { + return SL_SAMPLINGRATE_12; + } + if (samplesPerSec <= SL_SAMPLINGRATE_16) { + return SL_SAMPLINGRATE_16; + } + if (samplesPerSec <= SL_SAMPLINGRATE_22_05) { + return SL_SAMPLINGRATE_22_05; + } + if (samplesPerSec <= SL_SAMPLINGRATE_24) { + return SL_SAMPLINGRATE_24; + } + if (samplesPerSec <= SL_SAMPLINGRATE_32) { + return SL_SAMPLINGRATE_32; + } + if (samplesPerSec <= SL_SAMPLINGRATE_44_1) { + return SL_SAMPLINGRATE_44_1; + } + if (samplesPerSec <= SL_SAMPLINGRATE_48) { + return SL_SAMPLINGRATE_48; + } + + /* Android doesn't support more than 48000. */ +#ifndef MA_ANDROID + if (samplesPerSec <= SL_SAMPLINGRATE_64) { + return SL_SAMPLINGRATE_64; + } + if (samplesPerSec <= SL_SAMPLINGRATE_88_2) { + return SL_SAMPLINGRATE_88_2; + } + if (samplesPerSec <= SL_SAMPLINGRATE_96) { + return SL_SAMPLINGRATE_96; + } + if (samplesPerSec <= SL_SAMPLINGRATE_192) { + return SL_SAMPLINGRATE_192; + } +#endif + + return SL_SAMPLINGRATE_16; +} + + +static SLint32 ma_to_stream_type__opensl(ma_opensl_stream_type streamType) +{ + switch (streamType) { + case ma_opensl_stream_type_voice: return SL_ANDROID_STREAM_VOICE; + case ma_opensl_stream_type_system: return SL_ANDROID_STREAM_SYSTEM; + case ma_opensl_stream_type_ring: return SL_ANDROID_STREAM_RING; + case ma_opensl_stream_type_media: return SL_ANDROID_STREAM_MEDIA; + case ma_opensl_stream_type_alarm: return SL_ANDROID_STREAM_ALARM; + case ma_opensl_stream_type_notification: return SL_ANDROID_STREAM_NOTIFICATION; + default: break; + } + + return SL_ANDROID_STREAM_VOICE; +} + +static SLint32 ma_to_recording_preset__opensl(ma_opensl_recording_preset recordingPreset) +{ + switch (recordingPreset) { + case ma_opensl_recording_preset_generic: return SL_ANDROID_RECORDING_PRESET_GENERIC; + case ma_opensl_recording_preset_camcorder: return SL_ANDROID_RECORDING_PRESET_CAMCORDER; + case ma_opensl_recording_preset_voice_recognition: return SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; + case ma_opensl_recording_preset_voice_communication: return SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; + case ma_opensl_recording_preset_voice_unprocessed: return SL_ANDROID_RECORDING_PRESET_UNPROCESSED; + default: break; + } + + return SL_ANDROID_RECORDING_PRESET_NONE; +} + + +static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 cbResult; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + 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 enumerate devices. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + /* + TODO: Test Me. + + This is currently untested, so for now we are just returning default devices. + */ +#if 0 && !defined(MA_ANDROID) + ma_bool32 isTerminated = MA_FALSE; + + SLuint32 pDeviceIDs[128]; + SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]); + + SLAudioIODeviceCapabilitiesItf deviceCaps; + SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); + if (resultSL != SL_RESULT_SUCCESS) { + /* The interface may not be supported so just report a default device. */ + goto return_default_device; + } + + /* Playback */ + if (!isTerminated) { + resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs); + if (resultSL != SL_RESULT_SUCCESS) { + return ma_result_from_OpenSL(resultSL); + } + + for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.opensl = pDeviceIDs[iDevice]; + + SLAudioOutputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc); + if (resultSL == SL_RESULT_SUCCESS) { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.pDeviceName, (size_t)-1); + + ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + if (cbResult == MA_FALSE) { + isTerminated = MA_TRUE; + break; + } + } + } + } + + /* Capture */ + if (!isTerminated) { + resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs); + if (resultSL != SL_RESULT_SUCCESS) { + return ma_result_from_OpenSL(resultSL); + } + + for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + deviceInfo.id.opensl = pDeviceIDs[iDevice]; + + SLAudioInputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc); + if (resultSL == SL_RESULT_SUCCESS) { + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.deviceName, (size_t)-1); + + ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + if (cbResult == MA_FALSE) { + isTerminated = MA_TRUE; + break; + } + } + } + } + + return MA_SUCCESS; +#else + goto return_default_device; +#endif + +return_default_device:; + cbResult = MA_TRUE; + + /* Playback. */ + 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); + } + + /* Capture. */ + 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); + } + + return MA_SUCCESS; +} + +static void ma_context_add_data_format_ex__opensl(ma_context* pContext, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format = format; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels = channels; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate; + pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags = 0; + pDeviceInfo->nativeDataFormatCount += 1; +} + +static void ma_context_add_data_format__opensl(ma_context* pContext, ma_format format, ma_device_info* pDeviceInfo) +{ + ma_uint32 minChannels = 1; + ma_uint32 maxChannels = 2; + ma_uint32 minSampleRate = (ma_uint32)ma_standard_sample_rate_8000; + ma_uint32 maxSampleRate = (ma_uint32)ma_standard_sample_rate_48000; + ma_uint32 iChannel; + ma_uint32 iSampleRate; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(pDeviceInfo != NULL); + + /* + Each sample format can support mono and stereo, and we'll support a small subset of standard + rates (up to 48000). A better solution would be to somehow find a native sample rate. + */ + for (iChannel = minChannels; iChannel < maxChannels; iChannel += 1) { + for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) { + ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate]; + if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) { + ma_context_add_data_format_ex__opensl(pContext, format, iChannel, standardSampleRate, pDeviceInfo); + } + } + } +} + +static ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pContext != NULL); + + 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 get device info. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + /* + TODO: Test Me. + + This is currently untested, so for now we are just returning default devices. + */ +#if 0 && !defined(MA_ANDROID) + SLAudioIODeviceCapabilitiesItf deviceCaps; + SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps); + if (resultSL != SL_RESULT_SUCCESS) { + /* The interface may not be supported so just report a default device. */ + goto return_default_device; + } + + if (deviceType == ma_device_type_playback) { + SLAudioOutputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pDeviceID->opensl, &desc); + if (resultSL != SL_RESULT_SUCCESS) { + return ma_result_from_OpenSL(resultSL); + } + + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.pDeviceName, (size_t)-1); + } else { + SLAudioInputDescriptor desc; + resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pDeviceID->opensl, &desc); + if (resultSL != SL_RESULT_SUCCESS) { + return ma_result_from_OpenSL(resultSL); + } + + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.deviceName, (size_t)-1); + } + + goto return_detailed_info; +#else + goto return_default_device; +#endif + +return_default_device: + if (pDeviceID != NULL) { + if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) || + (deviceType == ma_device_type_capture && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) { + return MA_NO_DEVICE; /* Don't know the device. */ + } + } + + /* ID and 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); + } + + pDeviceInfo->isDefault = MA_TRUE; + + goto return_detailed_info; + + +return_detailed_info: + + /* + For now we're just outputting a set of values that are supported by the API but not necessarily supported + by the device natively. Later on we should work on this so that it more closely reflects the device's + actual native format. + */ + pDeviceInfo->nativeDataFormatCount = 0; +#if defined(MA_ANDROID) && __ANDROID_API__ >= 21 + ma_context_add_data_format__opensl(pContext, ma_format_f32, pDeviceInfo); +#endif + ma_context_add_data_format__opensl(pContext, ma_format_s16, pDeviceInfo); + ma_context_add_data_format__opensl(pContext, ma_format_u8, pDeviceInfo); + + return MA_SUCCESS; +} + + +#ifdef MA_ANDROID +/*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/ +static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + size_t periodSizeInBytes; + ma_uint8* pBuffer; + SLresult resultSL; + + MA_ASSERT(pDevice != NULL); + + (void)pBufferQueue; + + /* + For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like + OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this, + but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :( + */ + + /* Don't do anything if the device is not started. */ + if (ma_device_get_state(pDevice) != ma_device_state_started) { + return; + } + + /* Don't do anything if the device is being drained. */ + if (pDevice->opensl.isDrainingCapture) { + return; + } + + periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes); + + ma_device_handle_backend_data_callback(pDevice, NULL, pBuffer, pDevice->capture.internalPeriodSizeInFrames); + + resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + return; + } + + pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods; +} + +static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + size_t periodSizeInBytes; + ma_uint8* pBuffer; + SLresult resultSL; + + MA_ASSERT(pDevice != NULL); + + (void)pBufferQueue; + + /* Don't do anything if the device is not started. */ + if (ma_device_get_state(pDevice) != ma_device_state_started) { + return; + } + + /* Don't do anything if the device is being drained. */ + if (pDevice->opensl.isDrainingPlayback) { + return; + } + + periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes); + + ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, pDevice->playback.internalPeriodSizeInFrames); + + resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes); + if (resultSL != SL_RESULT_SUCCESS) { + return; + } + + pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods; +} +#endif + +static ma_result ma_device_uninit__opensl(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before uninitializing the device. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + if (pDevice->opensl.pAudioRecorderObj) { + MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj); + } + + ma_free(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + if (pDevice->opensl.pAudioPlayerObj) { + MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj); + } + if (pDevice->opensl.pOutputMixObj) { + MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj); + } + + ma_free(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks); + } + + return MA_SUCCESS; +} + +#if defined(MA_ANDROID) && __ANDROID_API__ >= 21 +typedef SLAndroidDataFormat_PCM_EX ma_SLDataFormat_PCM; +#else +typedef SLDataFormat_PCM ma_SLDataFormat_PCM; +#endif + +static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* channelMap, ma_SLDataFormat_PCM* pDataFormat) +{ + /* We need to convert our format/channels/rate so that they aren't set to default. */ + if (format == ma_format_unknown) { + format = MA_DEFAULT_FORMAT; + } + if (channels == 0) { + channels = MA_DEFAULT_CHANNELS; + } + if (sampleRate == 0) { + sampleRate = MA_DEFAULT_SAMPLE_RATE; + } + +#if defined(MA_ANDROID) && __ANDROID_API__ >= 21 + if (format == ma_format_f32) { + pDataFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; + } else { + pDataFormat->formatType = SL_DATAFORMAT_PCM; + } +#else + pDataFormat->formatType = SL_DATAFORMAT_PCM; +#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; + pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels); + pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; + + /* + Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html + - Only mono and stereo is supported. + - Only u8 and s16 formats are supported. + - Maximum sample rate of 48000. + */ +#ifdef MA_ANDROID + if (pDataFormat->numChannels > 2) { + pDataFormat->numChannels = 2; + } +#if __ANDROID_API__ >= 21 + if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { + /* It's floating point. */ + MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); + if (pDataFormat->bitsPerSample > 32) { + pDataFormat->bitsPerSample = 32; + } + } else { + if (pDataFormat->bitsPerSample > 16) { + pDataFormat->bitsPerSample = 16; + } + } +#else + if (pDataFormat->bitsPerSample > 16) { + pDataFormat->bitsPerSample = 16; + } +#endif + if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) { + ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = SL_SAMPLINGRATE_48; + } +#endif + + pDataFormat->containerSize = pDataFormat->bitsPerSample; /* Always tightly packed for now. */ + + return MA_SUCCESS; +} + +static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + ma_bool32 isFloatingPoint = MA_FALSE; +#if defined(MA_ANDROID) && __ANDROID_API__ >= 21 + if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) { + MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT); + isFloatingPoint = MA_TRUE; + } +#endif + if (isFloatingPoint) { + if (pDataFormat->bitsPerSample == 32) { + *pFormat = ma_format_f32; + } + } else { + if (pDataFormat->bitsPerSample == 8) { + *pFormat = ma_format_u8; + } else if (pDataFormat->bitsPerSample == 16) { + *pFormat = ma_format_s16; + } else if (pDataFormat->bitsPerSample == 24) { + *pFormat = ma_format_s24; + } else if (pDataFormat->bitsPerSample == 32) { + *pFormat = ma_format_s32; + } + } + + *pChannels = pDataFormat->numChannels; + *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000; + ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, ma_min(pDataFormat->numChannels, channelMapCap), pChannelMap); + + return MA_SUCCESS; +} + +static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ +#ifdef MA_ANDROID + 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 */ + }; +#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. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* + For now, only supporting Android implementations of OpenSL|ES since that's the only one I've + been able to test with and I currently depend on Android-specific extensions (simple buffer + queues). + */ +#ifdef MA_ANDROID + itfIDs[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + itfIDs[1] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION; + + /* 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) || + ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { + return MA_SHARE_MODE_NOT_SUPPORTED; + } + + /* Now we can start initializing the device properly. */ + MA_ASSERT(pDevice != NULL); + MA_ZERO_OBJECT(&pDevice->opensl); + + queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { + ma_SLDataFormat_PCM pcm; + SLDataLocator_IODevice locatorDevice; + SLDataSource source; + SLDataSink sink; + SLAndroidConfigurationItf pRecorderConfig; + + ma_SLDataFormat_PCM_init__opensl(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &pcm); + + locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE; + locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT; + locatorDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; /* Must always use the default device with Android. */ + locatorDevice.device = NULL; + + source.pLocator = &locatorDevice; + source.pFormat = NULL; + + queue.numBuffers = pDescriptorCapture->periodCount; + + 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) { + /* 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); + } + + 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); + } + + + /* 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); + 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)); + if (resultSL != SL_RESULT_SUCCESS) { + /* Failed to set the configuration. Just keep going. */ + } + } + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + /* The internal format is determined by the "pcm" object. */ + ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorCapture->format, &pDescriptorCapture->channels, &pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap)); + + /* Buffer. */ + pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile); + 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); + 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; + } + MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes); + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + ma_SLDataFormat_PCM pcm; + SLDataSource source; + SLDataLocator_OutputMix outmixLocator; + SLDataSink sink; + SLAndroidConfigurationItf pPlayerConfig; + + ma_SLDataFormat_PCM_init__opensl(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &pcm); + + 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); + } + + 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); + } + + 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); + } + + /* Set the output device. */ + if (pDescriptorPlayback->pDeviceID != NULL) { + SLuint32 deviceID_OpenSL = pDescriptorPlayback->pDeviceID->opensl; + MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL); + } + + queue.numBuffers = pDescriptorPlayback->periodCount; + + source.pLocator = &queue; + source.pFormat = (SLDataFormat_PCM*)&pcm; + + outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX; + outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj; + + 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) { + /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ + pcm.formatType = SL_DATAFORMAT_PCM; + pcm.numChannels = 2; + ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; + 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); + } + + 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); + } + + + /* Set the stream type before realizing the player. */ + if (pConfig->opensl.streamType != ma_opensl_stream_type_default) { + resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pPlayerConfig); + if (resultSL == SL_RESULT_SUCCESS) { + SLint32 streamType = ma_to_stream_type__opensl(pConfig->opensl.streamType); + resultSL = (*pPlayerConfig)->SetConfiguration(pPlayerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32)); + if (resultSL != SL_RESULT_SUCCESS) { + /* Failed to set the configuration. Just keep going. */ + } + } + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + /* The internal format is determined by the "pcm" object. */ + ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorPlayback->format, &pDescriptorPlayback->channels, &pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap)); + + /* Buffer. */ + pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile); + 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); + 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; + } + MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes); + } + + return MA_SUCCESS; +#else + return MA_NO_BACKEND; /* Non-Android implementations are not supported. */ +#endif +} + +static ma_result ma_device_start__opensl(ma_device* pDevice) +{ + SLresult resultSL; + size_t periodSizeInBytes; + ma_uint32 iPeriod; + + MA_ASSERT(pDevice != NULL); + + 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 start the device. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + 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); + } + + periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); + for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { + 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); + } + } + } + + 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); + } + + /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueue 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 { + ma_device__read_frames_from_client(pDevice, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods, pDevice->opensl.pBufferPlayback); + } + + periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels); + for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) { + 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_SUCCESS; +} + +static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type deviceType) +{ + SLAndroidSimpleBufferQueueItf pBufferQueue; + + MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback); + + if (pDevice->type == ma_device_type_capture) { + pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture; + pDevice->opensl.isDrainingCapture = MA_TRUE; + } else { + pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback; + pDevice->opensl.isDrainingPlayback = MA_TRUE; + } + + for (;;) { + SLAndroidSimpleBufferQueueState state; + + MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue, &state); + if (state.count == 0) { + break; + } + + ma_sleep(10); + } + + if (pDevice->type == ma_device_type_capture) { + pDevice->opensl.isDrainingCapture = MA_FALSE; + } else { + pDevice->opensl.isDrainingPlayback = MA_FALSE; + } + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__opensl(ma_device* pDevice) +{ + SLresult resultSL; + + MA_ASSERT(pDevice != NULL); + + MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before stopping/uninitializing the device. */ + if (g_maOpenSLInitCounter == 0) { + return MA_INVALID_OPERATION; + } + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_device_drain__opensl(pDevice, ma_device_type_capture); + + 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); + } + + MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_device_drain__opensl(pDevice, ma_device_type_playback); + + 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); + } + + 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); + + return MA_SUCCESS; +} + + +static ma_result ma_context_uninit__opensl(ma_context* pContext) +{ + MA_ASSERT(pContext != NULL); + MA_ASSERT(pContext->backend == ma_backend_opensl); + (void)pContext; + + /* Uninit global data. */ + ma_spinlock_lock(&g_maOpenSLSpinlock); + { + MA_ASSERT(g_maOpenSLInitCounter > 0); /* If you've triggered this, it means you have ma_context_init/uninit mismatch. Each successful call to ma_context_init() must be matched up with a call to ma_context_uninit(). */ + + g_maOpenSLInitCounter -= 1; + if (g_maOpenSLInitCounter == 0) { + (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL); + } + } + ma_spinlock_unlock(&g_maOpenSLSpinlock); + + return MA_SUCCESS; +} + +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); + if (p == NULL) { + ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol %s", pName); + return MA_NO_BACKEND; + } + + *pHandle = *p; + return MA_SUCCESS; +} + +static ma_result ma_context_init_engine_nolock__opensl(ma_context* pContext) +{ + g_maOpenSLInitCounter += 1; + if (g_maOpenSLInitCounter == 1) { + SLresult resultSL; + + resultSL = ((ma_slCreateEngine_proc)pContext->opensl.slCreateEngine)(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL); + if (resultSL != SL_RESULT_SUCCESS) { + g_maOpenSLInitCounter -= 1; + return ma_result_from_OpenSL(resultSL); + } + + (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE); + + resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_ENGINE, &g_maEngineSL); + if (resultSL != SL_RESULT_SUCCESS) { + (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL); + g_maOpenSLInitCounter -= 1; + return ma_result_from_OpenSL(resultSL); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + ma_result result; + +#if !defined(MA_NO_RUNTIME_LINKING) + size_t i; + const char* libOpenSLESNames[] = { + "libOpenSLES.so" + }; +#endif + + MA_ASSERT(pContext != NULL); + + (void)pConfig; + +#if !defined(MA_NO_RUNTIME_LINKING) + /* + Dynamically link against libOpenSLES.so. I have now had multiple reports that SL_IID_ANDROIDSIMPLEBUFFERQUEUE cannot be found. One + report was happening at compile time and another at runtime. To try working around this, I'm going to link to libOpenSLES at runtime + and extract the symbols rather than reference them directly. This should, hopefully, fix these issues as the compiler won't see any + 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]); + 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"); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + return result; + } + + pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(ma_context_get_log(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."); + return MA_NO_BACKEND; + } +#else + pContext->opensl.SL_IID_ENGINE = (ma_handle)SL_IID_ENGINE; + pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES = (ma_handle)SL_IID_AUDIOIODEVICECAPABILITIES; + pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (ma_handle)SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + pContext->opensl.SL_IID_RECORD = (ma_handle)SL_IID_RECORD; + pContext->opensl.SL_IID_PLAY = (ma_handle)SL_IID_PLAY; + pContext->opensl.SL_IID_OUTPUTMIX = (ma_handle)SL_IID_OUTPUTMIX; + pContext->opensl.SL_IID_ANDROIDCONFIGURATION = (ma_handle)SL_IID_ANDROIDCONFIGURATION; + pContext->opensl.slCreateEngine = (ma_proc)slCreateEngine; +#endif + + + /* Initialize global data first if applicable. */ + ma_spinlock_lock(&g_maOpenSLSpinlock); + { + result = ma_context_init_engine_nolock__opensl(pContext); + } + 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."); + return result; + } + + pCallbacks->onContextInit = ma_context_init__opensl; + pCallbacks->onContextUninit = ma_context_uninit__opensl; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__opensl; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__opensl; + pCallbacks->onDeviceInit = ma_device_init__opensl; + pCallbacks->onDeviceUninit = ma_device_uninit__opensl; + pCallbacks->onDeviceStart = ma_device_start__opensl; + pCallbacks->onDeviceStop = ma_device_stop__opensl; + pCallbacks->onDeviceRead = NULL; /* Not needed because OpenSL|ES is asynchronous. */ + pCallbacks->onDeviceWrite = NULL; /* Not needed because OpenSL|ES is asynchronous. */ + pCallbacks->onDeviceDataLoop = NULL; /* Not needed because OpenSL|ES is asynchronous. */ + + return MA_SUCCESS; +} +#endif /* OpenSL|ES */ + + +/****************************************************************************** + +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({ + return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined); + }, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */ +} + +#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); +} + +void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames) +{ + ma_device_handle_backend_data_callback(pDevice, pFrames, NULL, (ma_uint32)frameCount); +} +#ifdef __cplusplus +} +#endif + +static ma_result ma_context_enumerate_devices__webaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) +{ + ma_bool32 cbResult = MA_TRUE; + + MA_ASSERT(pContext != NULL); + MA_ASSERT(callback != NULL); + + /* Only supporting default devices for now. */ + + /* Playback. */ + if (cbResult) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; /* Only supporting default devices. */ + cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData); + } + + /* Capture. */ + if (cbResult) { + if (ma_is_capture_supported__webaudio()) { + ma_device_info deviceInfo; + MA_ZERO_OBJECT(&deviceInfo); + ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + deviceInfo.isDefault = MA_TRUE; /* Only supporting default devices. */ + cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo) +{ + MA_ASSERT(pContext != NULL); + + if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) { + return MA_NO_DEVICE; + } + + MA_ZERO_MEMORY(pDeviceInfo->id.webaudio, sizeof(pDeviceInfo->id.webaudio)); + + /* Only supporting default devices for now. */ + (void)pDeviceID; + if (deviceType == ma_device_type_playback) { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); + } else { + ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); + } + + /* Only supporting default devices. */ + pDeviceInfo->isDefault = MA_TRUE; + + /* Web Audio can support any number of channels and sample rates. It only supports f32 formats, however. */ + pDeviceInfo->nativeDataFormats[0].flags = 0; + pDeviceInfo->nativeDataFormats[0].format = ma_format_unknown; + pDeviceInfo->nativeDataFormats[0].channels = 0; /* All channels are supported. */ + pDeviceInfo->nativeDataFormats[0].sampleRate = EM_ASM_INT({ + try { + var temp = new (window.AudioContext || window.webkitAudioContext)(); + var sampleRate = temp.sampleRate; + temp.close(); + return sampleRate; + } catch(e) { + return 0; + } + }, 0); /* Must pass in a dummy argument for C99 compatibility. */ + + if (pDeviceInfo->nativeDataFormats[0].sampleRate == 0) { + return MA_NO_DEVICE; + } + + pDeviceInfo->nativeDataFormatCount = 1; + + return MA_SUCCESS; +} + +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); + } + #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); + } + #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. + */ + 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) { + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(33, nativeSampleRate); /* 1 frame @ 30 FPS */ + } else { + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(333, nativeSampleRate); + } + } else { + periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate); + } + } else { + periodSizeInFrames = pDescriptor->periodSizeInFrames; + } + + /* The size of the buffer must be a power of 2 and between 256 and 16384. */ + if (periodSizeInFrames < 256) { + periodSizeInFrames = 256; + } else if (periodSizeInFrames > 16384) { + periodSizeInFrames = 16384; + } else { + periodSizeInFrames = ma_next_power_of_2(periodSizeInFrames); + } + + return periodSizeInFrames; +} +#endif + + +#if defined(MA_USE_AUDIO_WORKLETS) +typedef struct +{ + ma_device* pDevice; + const ma_device_config* pConfig; + ma_device_descriptor* pDescriptorPlayback; + ma_device_descriptor* pDescriptorCapture; +} ma_audio_worklet_thread_initialized_data; + +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; + + (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 (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)); + } + + return EM_TRUE; + } + + 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]; + } + } + + ma_device_process_pcm_frames_capture__webaudio(pDevice, frameCount, pDevice->webaudio.pIntermediaryBuffer); + } + + 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); + + /* 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]; + } + } + } + } + + return EM_TRUE; +} + + +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; + + if (success == EM_FALSE) { + pParameters->pDevice->webaudio.initResult = MA_ERROR; + ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); + return; + } + + /* The next step is to initialize the audio worklet node. */ + MA_ZERO_OBJECT(&audioWorkletOptions); + + /* + 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); + + if (pParameters->pConfig->deviceType == ma_device_type_duplex) { + audioWorkletOptions.numberOfInputs = 1; + } else { + audioWorkletOptions.numberOfInputs = 0; + } + } + + 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); + + 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 */ + }) + .catch(function(error) { + console.log("navigator.mediaDevices.getUserMedia Failed: " + error); + getUserMediaResult = -1; /* -1 = MA_ERROR */ + }); + + return getUserMediaResult; + }, 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 capture node."); + emscripten_destroy_web_audio_node(pParameters->pDevice->webaudio.audioWorklet); + pParameters->pDevice->webaudio.initResult = attachmentResult; + ma_free(pParameters, &pParameters->pDevice->pContext->allocationCallbacks); + return; + } + } + + /* 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; + } + } + + /* 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); + + 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); +} + +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) +{ + if (pConfig->deviceType == ma_device_type_loopback) { + return MA_DEVICE_TYPE_NOT_SUPPORTED; + } + + /* No exclusive mode with Web Audio. */ + 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; + } + + /* + 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; + } + + /* + 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. */ + } + + 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; + } + + 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 +} + +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); + + return MA_SUCCESS; +} + +static ma_result ma_device_stop__webaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* + From the WebAudio API documentation for AudioContext.suspend(): + + Suspends the progression of AudioContext's currentTime, allows any current context processing blocks that are already processed to be played to the + destination, and then allows the system to release its claim on audio hardware. + + 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); + + return MA_SUCCESS; +} + +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; + } + } + }); + + return MA_SUCCESS; +} + +static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) +{ + int resultFromJS; + + MA_ASSERT(pContext != NULL); + + (void)pConfig; /* Unused. */ + + /* Here is where our global JavaScript object is initialized. */ + resultFromJS = EM_ASM_INT({ + if (typeof window === 'undefined' || (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 = []; + + miniaudio.track_device = function(device) { + /* Try inserting into a free slot first. */ + for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) { + if (miniaudio.devices[iDevice] == null) { + miniaudio.devices[iDevice] = device; + return iDevice; + } + } + + /* Getting here means there is no empty slots in the array so we just push to the end. */ + miniaudio.devices.push(device); + return miniaudio.devices.length - 1; + }; + + miniaudio.untrack_device_by_index = function(deviceIndex) { + /* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */ + miniaudio.devices[deviceIndex] = null; + + /* Trim the array if possible. */ + while (miniaudio.devices.length > 0) { + if (miniaudio.devices[miniaudio.devices.length-1] == null) { + miniaudio.devices.pop(); + } else { + break; + } + } + }; + + miniaudio.untrack_device = function(device) { + for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) { + if (miniaudio.devices[iDevice] == device) { + return miniaudio.untrack_device_by_index(iDevice); + } + } + }; + + miniaudio.get_device_by_index = function(deviceIndex) { + return miniaudio.devices[deviceIndex]; + }; + + miniaudio.unlock_event_types = (function(){ + return ['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); + }); + } + } + miniaudio.unlock_event_types.map(function(event_type) { + document.removeEventListener(event_type, miniaudio.unlock, true); + }); + }; + + miniaudio.unlock_event_types.map(function(event_type) { + document.addEventListener(event_type, miniaudio.unlock, true); + }); + } + + 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); + + if (resultFromJS != 1) { + return MA_FAILED_TO_INIT_BACKEND; + } + + pCallbacks->onContextInit = ma_context_init__webaudio; + pCallbacks->onContextUninit = ma_context_uninit__webaudio; + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__webaudio; + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__webaudio; + pCallbacks->onDeviceInit = ma_device_init__webaudio; + pCallbacks->onDeviceUninit = ma_device_uninit__webaudio; + pCallbacks->onDeviceStart = ma_device_start__webaudio; + pCallbacks->onDeviceStop = ma_device_stop__webaudio; + pCallbacks->onDeviceRead = NULL; /* Not needed because WebAudio is asynchronous. */ + pCallbacks->onDeviceWrite = NULL; /* Not needed because WebAudio is asynchronous. */ + pCallbacks->onDeviceDataLoop = NULL; /* Not needed because WebAudio is asynchronous. */ + + return MA_SUCCESS; +} +#endif /* MA_HAS_WEBAUDIO */ + + + +static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, 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) { + ma_uint32 iChannel; + + if (channels == 0 || channels > MA_MAX_CHANNELS) { + return MA_FALSE; /* Channel count out of range. */ + } + + /* A channel cannot be present in the channel map more than once. */ + for (iChannel = 0; iChannel < channels; ++iChannel) { + ma_uint32 jChannel; + for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) { + if (pChannelMap[iChannel] == pChannelMap[jChannel]) { + return MA_FALSE; + } + } + } + } + + return MA_TRUE; +} + + +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 (pDevice->capture.format == ma_format_unknown) { + pDevice->capture.format = pDevice->capture.internalFormat; + } + if (pDevice->capture.channels == 0) { + pDevice->capture.channels = pDevice->capture.internalChannels; + } + if (pDevice->capture.channelMap[0] == MA_CHANNEL_NONE) { + MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS); + if (pDevice->capture.internalChannels == pDevice->capture.channels) { + 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); + } else { + ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pDevice->capture.channels); + } + } + } + } + + if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { + if (pDevice->playback.format == ma_format_unknown) { + pDevice->playback.format = pDevice->playback.internalFormat; + } + if (pDevice->playback.channels == 0) { + pDevice->playback.channels = pDevice->playback.internalChannels; + } + if (pDevice->playback.channelMap[0] == MA_CHANNEL_NONE) { + MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS); + if (pDevice->playback.internalChannels == pDevice->playback.channels) { + 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); + } else { + ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pDevice->playback.channels); + } + } + } + } + + if (pDevice->sampleRate == 0) { + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { + pDevice->sampleRate = pDevice->capture.internalSampleRate; + } else { + pDevice->sampleRate = pDevice->playback.internalSampleRate; + } + } + + /* Data converters. */ + 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; + + /* 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); + if (result != MA_SUCCESS) { + return result; + } + } + + 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; + + /* 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); + 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); +#endif + + /* + When the device is being initialized its initial state is set to ma_device_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_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. */ + + /* 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); + + /* Default result code. */ + 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) { + break; + } + + /* + Getting to this point means the device is wanting to get started. The function that has requested that the device + 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); + + /* 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; + } + + /* 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_event_signal(&pDevice->startEvent); + + ma_device__on_notification_started(pDevice); + + if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) { + pDevice->pContext->callbacks.onDeviceDataLoop(pDevice); + } else { + /* The backend is not using a custom main loop implementation, so now fall back to the blocking read-write implementation. */ + 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. */ + } + + /* + 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. + */ + if (stopResult == MA_SUCCESS) { + ma_device__on_notification_stopped(pDevice); + } + + /* 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); + } + +#ifdef MA_WIN32 + if (CoInitializeResult == S_OK) { + ma_CoUninitialize(pDevice->pContext); + } +#endif + + return (ma_thread_result)0; +} + + +/* Helper for determining whether or not the given device is initialized. */ +static ma_bool32 ma_device__is_initialized(ma_device* pDevice) +{ + if (pDevice == NULL) { + return MA_FALSE; + } + + return ma_device_get_state(pDevice) != ma_device_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 + + 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 + + /* Ole32.dll */ + pContext->win32.hOle32DLL = ma_dlopen(ma_context_get_log(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. */ +#endif + + pContext->win32.CoInitializeResult = ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + return MA_SUCCESS; +} +#else +static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext) +{ + (void)pContext; + + return MA_SUCCESS; +} + +static ma_result ma_context_init_backend_apis__nix(ma_context* pContext) +{ + (void)pContext; + + return MA_SUCCESS; +} +#endif + +static ma_result ma_context_init_backend_apis(ma_context* pContext) +{ + ma_result result; +#ifdef MA_WIN32 + result = ma_context_init_backend_apis__win32(pContext); +#else + result = ma_context_init_backend_apis__nix(pContext); +#endif + + return result; +} + +static ma_result ma_context_uninit_backend_apis(ma_context* pContext) +{ + ma_result result; +#ifdef MA_WIN32 + result = ma_context_uninit_backend_apis__win32(pContext); +#else + result = ma_context_uninit_backend_apis__nix(pContext); +#endif + + return result; +} + + +/* 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) +{ + ma_device_job_thread_config config; + + 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]) { + return MA_FALSE; + } + } + + return MA_TRUE; +} + + + +MA_API ma_context_config ma_context_config_init(void) +{ + ma_context_config config; + MA_ZERO_OBJECT(&config); + + return config; +} + +MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext) +{ + ma_result result; + ma_context_config defaultConfig; + ma_backend defaultBackends[ma_backend_null+1]; + ma_uint32 iBackend; + ma_backend* pBackendsToIterate; + ma_uint32 backendsToIterateCount; + + if (pContext == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pContext); + + /* Always make sure the config is set first to ensure properties are available as soon as possible. */ + if (pConfig == NULL) { + defaultConfig = ma_context_config_init(); + pConfig = &defaultConfig; + } + + /* Allocation callbacks need to come first because they'll be passed around to other areas. */ + 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) { + return result; + } + + for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) { + defaultBackends[iBackend] = (ma_backend)iBackend; + } + + pBackendsToIterate = (ma_backend*)backends; + backendsToIterateCount = backendCount; + if (pBackendsToIterate == NULL) { + pBackendsToIterate = (ma_backend*)defaultBackends; + backendsToIterateCount = ma_countof(defaultBackends); + } + + MA_ASSERT(pBackendsToIterate != NULL); + + for (iBackend = 0; iBackend < backendsToIterateCount; iBackend += 1) { + ma_backend backend = pBackendsToIterate[iBackend]; + + /* Make sure all callbacks are reset so we don't accidentally drag in any from previously failed initialization attempts. */ + MA_ZERO_OBJECT(&pContext->callbacks); + + /* These backends are using the new callback system. */ + switch (backend) { + #ifdef MA_HAS_WASAPI + case ma_backend_wasapi: + { + pContext->callbacks.onContextInit = ma_context_init__wasapi; + } break; + #endif + #ifdef MA_HAS_DSOUND + case ma_backend_dsound: + { + pContext->callbacks.onContextInit = ma_context_init__dsound; + } break; + #endif + #ifdef MA_HAS_WINMM + case ma_backend_winmm: + { + pContext->callbacks.onContextInit = ma_context_init__winmm; + } break; + #endif + #ifdef MA_HAS_COREAUDIO + case ma_backend_coreaudio: + { + pContext->callbacks.onContextInit = ma_context_init__coreaudio; + } break; + #endif + #ifdef MA_HAS_SNDIO + case ma_backend_sndio: + { + pContext->callbacks.onContextInit = ma_context_init__sndio; + } break; + #endif + #ifdef MA_HAS_AUDIO4 + case ma_backend_audio4: + { + pContext->callbacks.onContextInit = ma_context_init__audio4; + } break; + #endif + #ifdef MA_HAS_OSS + case ma_backend_oss: + { + pContext->callbacks.onContextInit = ma_context_init__oss; + } break; + #endif + #ifdef MA_HAS_PULSEAUDIO + case ma_backend_pulseaudio: + { + pContext->callbacks.onContextInit = ma_context_init__pulse; + } break; + #endif + #ifdef MA_HAS_ALSA + case ma_backend_alsa: + { + pContext->callbacks.onContextInit = ma_context_init__alsa; + } break; + #endif + #ifdef MA_HAS_JACK + case ma_backend_jack: + { + pContext->callbacks.onContextInit = ma_context_init__jack; + } break; + #endif + #ifdef MA_HAS_AAUDIO + case ma_backend_aaudio: + { + if (ma_is_backend_enabled(backend)) { + 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; + } + } break; + #endif + #ifdef MA_HAS_WEBAUDIO + case ma_backend_webaudio: + { + pContext->callbacks.onContextInit = ma_context_init__webaudio; + } break; + #endif + #ifdef MA_HAS_CUSTOM + case ma_backend_custom: + { + /* Slightly different logic for custom backends. Custom backends can optionally set all of their callbacks in the config. */ + pContext->callbacks = pConfig->custom; + } break; + #endif + #ifdef MA_HAS_NULL + case ma_backend_null: + { + pContext->callbacks.onContextInit = ma_context_init__null; + } break; + #endif + + default: break; + } + + 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)); + 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 + } + } + + /* 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"); + } + + 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_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"); + + 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)); + } + } + } + + /* If we get here it means an error occurred. */ + MA_ZERO_OBJECT(pContext); /* Safety. */ + return MA_NO_BACKEND; +} + +MA_API ma_result ma_context_uninit(ma_context* pContext) +{ + if (pContext == NULL) { + return MA_INVALID_ARGS; + } + + if (pContext->callbacks.onContextUninit != NULL) { + pContext->callbacks.onContextUninit(pContext); + } + + ma_mutex_uninit(&pContext->deviceEnumLock); + ma_mutex_uninit(&pContext->deviceInfoLock); + ma_free(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) +{ + 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; + + if (pContext == NULL || callback == NULL) { + return MA_INVALID_ARGS; + } + + if (pContext->callbacks.onContextEnumerateDevices == NULL) { + return MA_INVALID_OPERATION; + } + + ma_mutex_lock(&pContext->deviceEnumLock); + { + result = pContext->callbacks.onContextEnumerateDevices(pContext, callback, pUserData); + } + ma_mutex_unlock(&pContext->deviceEnumLock); + + return result; +} + + +static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) +{ + /* + We need to insert the device info into our main internal buffer. Where it goes depends on the device type. If it's a capture device + it's just appended to the end. If it's a playback device it's inserted just before the first capture device. + */ + + /* + First make sure we have room. Since the number of devices we add to the list is usually relatively small I've decided to use a + simple fixed size increment for buffer expansion. + */ + const ma_uint32 bufferExpansionCount = 2; + 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); + if (pNewInfos == NULL) { + return MA_FALSE; /* Out of memory. */ + } + + pContext->pDeviceInfos = pNewInfos; + pContext->deviceInfoCapacity = newCapacity; + } + + if (deviceType == ma_device_type_playback) { + /* Playback. Insert just before the first capture device. */ + + /* The first thing to do is move all of the capture devices down a slot. */ + ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount; + size_t iCaptureDevice; + for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) { + pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1]; + } + + /* Now just insert where the first capture device was before moving it down a slot. */ + pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo; + pContext->playbackDeviceInfoCount += 1; + } else { + /* Capture. Insert at the end. */ + pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo; + pContext->captureDeviceInfoCount += 1; + } + + (void)pUserData; + return MA_TRUE; +} + +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) +{ + ma_result result; + + /* Safety. */ + if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL; + if (pPlaybackDeviceCount != NULL) *pPlaybackDeviceCount = 0; + if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL; + if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0; + + if (pContext == NULL) { + return MA_INVALID_ARGS; + } + + if (pContext->callbacks.onContextEnumerateDevices == NULL) { + return MA_INVALID_OPERATION; + } + + /* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */ + ma_mutex_lock(&pContext->deviceEnumLock); + { + /* Reset everything first. */ + pContext->playbackDeviceInfoCount = 0; + pContext->captureDeviceInfoCount = 0; + + /* Now enumerate over available devices. */ + result = pContext->callbacks.onContextEnumerateDevices(pContext, ma_context_get_devices__enum_callback, NULL); + if (result == MA_SUCCESS) { + /* Playback devices. */ + if (ppPlaybackDeviceInfos != NULL) { + *ppPlaybackDeviceInfos = pContext->pDeviceInfos; + } + if (pPlaybackDeviceCount != NULL) { + *pPlaybackDeviceCount = pContext->playbackDeviceInfoCount; + } + + /* 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; + } + } + if (pCaptureDeviceCount != NULL) { + *pCaptureDeviceCount = pContext->captureDeviceInfoCount; + } + } + } + ma_mutex_unlock(&pContext->deviceEnumLock); + + 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_result result; + ma_device_info deviceInfo; + + /* 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; + } + + MA_ZERO_OBJECT(&deviceInfo); + + /* Help the backend out by copying over the device ID if we have one. */ + if (pDeviceID != NULL) { + MA_COPY_MEMORY(&deviceInfo.id, pDeviceID, sizeof(*pDeviceID)); + } + + if (pContext->callbacks.onContextGetDeviceInfo == NULL) { + return MA_INVALID_OPERATION; + } + + ma_mutex_lock(&pContext->deviceInfoLock); + { + result = pContext->callbacks.onContextGetDeviceInfo(pContext, deviceType, pDeviceID, &deviceInfo); + } + ma_mutex_unlock(&pContext->deviceInfoLock); + + *pDeviceInfo = deviceInfo; + return result; +} + +MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext) +{ + if (pContext == NULL) { + return MA_FALSE; + } + + return ma_is_loopback_supported(pContext->backend); +} + + +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. */ + + return config; +} + +MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice) +{ + ma_result result; + ma_device_descriptor descriptorPlayback; + ma_device_descriptor descriptorCapture; + + /* The context can be null, in which case we self-manage it. */ + if (pContext == NULL) { + return ma_device_init_ex(NULL, 0, NULL, pConfig, pDevice); + } + + if (pDevice == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDevice); + + if (pConfig == NULL) { + return 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_capture || pConfig->deviceType == ma_device_type_duplex) { + if (pConfig->capture.channels > MA_MAX_CHANNELS) { + return MA_INVALID_ARGS; + } + + if (!ma__is_channel_map_valid(pConfig->capture.pChannelMap, pConfig->capture.channels)) { + return MA_INVALID_ARGS; + } + } + + 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; + } + + if (!ma__is_channel_map_valid(pConfig->playback.pChannelMap, pConfig->playback.channels)) { + return MA_INVALID_ARGS; + } + } + + 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; + + 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->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->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; + + result = ma_mutex_init(&pDevice->startStopLock); + if (result != MA_SUCCESS) { + return result; + } + + /* + When the device is started, the worker thread is the one that does the actual startup of the backend device. We + use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device. + + Each of these semaphores is released internally by the worker thread when the work is completed. The start + semaphore is also used to wake up the worker thread. + */ + result = ma_event_init(&pDevice->wakeupEvent); + if (result != MA_SUCCESS) { + ma_mutex_uninit(&pDevice->startStopLock); + return result; + } + + result = ma_event_init(&pDevice->startEvent); + if (result != MA_SUCCESS) { + ma_event_uninit(&pDevice->wakeupEvent); + ma_mutex_uninit(&pDevice->startStopLock); + return result; + } + + result = ma_event_init(&pDevice->stopEvent); + if (result != MA_SUCCESS) { + ma_event_uninit(&pDevice->startEvent); + ma_event_uninit(&pDevice->wakeupEvent); + ma_mutex_uninit(&pDevice->startStopLock); + return result; + } + + + MA_ZERO_OBJECT(&descriptorPlayback); + descriptorPlayback.pDeviceID = pConfig->playback.pDeviceID; + descriptorPlayback.shareMode = pConfig->playback.shareMode; + 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); + descriptorPlayback.periodSizeInFrames = pConfig->periodSizeInFrames; + descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; + descriptorPlayback.periodCount = pConfig->periods; + + if (descriptorPlayback.periodCount == 0) { + descriptorPlayback.periodCount = MA_DEFAULT_PERIODS; + } + + + MA_ZERO_OBJECT(&descriptorCapture); + descriptorCapture.pDeviceID = pConfig->capture.pDeviceID; + descriptorCapture.shareMode = pConfig->capture.shareMode; + 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); + descriptorCapture.periodSizeInFrames = pConfig->periodSizeInFrames; + descriptorCapture.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds; + descriptorCapture.periodCount = pConfig->periods; + + if (descriptorCapture.periodCount == 0) { + descriptorCapture.periodCount = MA_DEFAULT_PERIODS; + } + + + result = pContext->callbacks.onDeviceInit(pDevice, pConfig, &descriptorPlayback, &descriptorCapture); + if (result != MA_SUCCESS) { + ma_event_uninit(&pDevice->startEvent); + ma_event_uninit(&pDevice->wakeupEvent); + ma_mutex_uninit(&pDevice->startStopLock); + 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. + */ + if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) { + if (!ma_device_descriptor_is_valid(&descriptorCapture)) { + ma_device_uninit(pDevice); + return MA_INVALID_ARGS; + } + + pDevice->capture.internalFormat = descriptorCapture.format; + pDevice->capture.internalChannels = descriptorCapture.channels; + pDevice->capture.internalSampleRate = descriptorCapture.sampleRate; + ma_channel_map_copy(pDevice->capture.internalChannelMap, descriptorCapture.channelMap, descriptorCapture.channels); + pDevice->capture.internalPeriodSizeInFrames = descriptorCapture.periodSizeInFrames; + pDevice->capture.internalPeriods = descriptorCapture.periodCount; + + if (pDevice->capture.internalPeriodSizeInFrames == 0) { + pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorCapture.periodSizeInMilliseconds, descriptorCapture.sampleRate); + } + } + + if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { + if (!ma_device_descriptor_is_valid(&descriptorPlayback)) { + ma_device_uninit(pDevice); + return MA_INVALID_ARGS; + } + + pDevice->playback.internalFormat = descriptorPlayback.format; + pDevice->playback.internalChannels = descriptorPlayback.channels; + pDevice->playback.internalSampleRate = descriptorPlayback.sampleRate; + ma_channel_map_copy(pDevice->playback.internalChannelMap, descriptorPlayback.channelMap, descriptorPlayback.channels); + pDevice->playback.internalPeriodSizeInFrames = descriptorPlayback.periodSizeInFrames; + pDevice->playback.internalPeriods = descriptorPlayback.periodCount; + + if (pDevice->playback.internalPeriodSizeInFrames == 0) { + pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorPlayback.periodSizeInMilliseconds, descriptorPlayback.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 (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); + 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 (descriptorCapture.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 (pConfig->deviceType == ma_device_type_playback || pConfig->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 (descriptorPlayback.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); + } + } + } + } + + + 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); + if (result != MA_SUCCESS) { + ma_device_uninit(pDevice); + return result; + } + + /* Wait for the worker thread to put the device into its stopped state for real. */ + ma_event_wait(&pDevice->stopEvent); + MA_ASSERT(ma_device_get_state(pDevice) == ma_device_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 + after ma_device__post_init_setup(). + */ + if (ma_context_is_backend_asynchronous(pContext)) { + if (pConfig->deviceType == ma_device_type_duplex) { + result = ma_duplex_rb_init(pDevice->capture.format, pDevice->capture.channels, pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB); + if (result != MA_SUCCESS) { + ma_device_uninit(pDevice); + return result; + } + } + } + + ma_device__set_state(pDevice, ma_device_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_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); + return MA_SUCCESS; +} + +MA_API ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice) +{ + ma_result result; + ma_context* pContext; + ma_backend defaultBackends[ma_backend_null+1]; + ma_uint32 iBackend; + ma_backend* pBackendsToIterate; + ma_uint32 backendsToIterateCount; + ma_allocation_callbacks allocationCallbacks; + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pContextConfig != NULL) { + result = ma_allocation_callbacks_init_copy(&allocationCallbacks, &pContextConfig->allocationCallbacks); + if (result != MA_SUCCESS) { + return result; + } + } else { + allocationCallbacks = ma_allocation_callbacks_init_default(); + } + + pContext = (ma_context*)ma_malloc(sizeof(*pContext), &allocationCallbacks); + if (pContext == NULL) { + return MA_OUT_OF_MEMORY; + } + + for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) { + defaultBackends[iBackend] = (ma_backend)iBackend; + } + + pBackendsToIterate = (ma_backend*)backends; + backendsToIterateCount = backendCount; + if (pBackendsToIterate == NULL) { + pBackendsToIterate = (ma_backend*)defaultBackends; + backendsToIterateCount = ma_countof(defaultBackends); + } + + 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); + if (result == MA_SUCCESS) { + break; /* Success. */ + } else { + ma_context_uninit(pContext); /* Failure. */ + } + } + } + + if (result != MA_SUCCESS) { + ma_free(pContext, &allocationCallbacks); + return result; + } + + pDevice->isOwnerOfContext = MA_TRUE; + return result; +} + +MA_API void ma_device_uninit(ma_device* pDevice) +{ + if (!ma_device__is_initialized(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); + } + } + #endif + + /* Putting the device into an uninitialized state will make the worker thread return. */ + ma_device__set_state(pDevice, ma_device_state_uninitialized); + + /* Wake up the worker thread and wait for it to properly terminate. */ + if (!ma_context_is_backend_asynchronous(pDevice->pContext)) { + ma_event_signal(&pDevice->wakeupEvent); + ma_thread_wait(&pDevice->thread); + } + + if (pDevice->pContext->callbacks.onDeviceUninit != NULL) { + pDevice->pContext->callbacks.onDeviceUninit(pDevice); + } + + + ma_event_uninit(&pDevice->stopEvent); + ma_event_uninit(&pDevice->startEvent); + ma_event_uninit(&pDevice->wakeupEvent); + ma_mutex_uninit(&pDevice->startStopLock); + + if (ma_context_is_backend_asynchronous(pDevice->pContext)) { + if (pDevice->type == ma_device_type_duplex) { + ma_duplex_rb_uninit(&pDevice->duplexRB); + } + } + + 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_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; + } + + if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) { + return MA_INVALID_OPERATION; /* Not initialized. */ + } + + if (ma_device_get_state(pDevice) == ma_device_state_started) { + return MA_SUCCESS; /* Already started. */ + } + + 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_device__set_state(pDevice, ma_device_state_starting); + + /* Asynchronous backends need to be handled differently. */ + if (ma_context_is_backend_asynchronous(pDevice->pContext)) { + if (pDevice->pContext->callbacks.onDeviceStart != NULL) { + result = pDevice->pContext->callbacks.onDeviceStart(pDevice); + } else { + result = MA_INVALID_OPERATION; + } + + if (result == MA_SUCCESS) { + ma_device__set_state(pDevice, ma_device_state_started); + ma_device__on_notification_started(pDevice); + } + } else { + /* + Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the + thread and then wait for the start event. + */ + ma_event_signal(&pDevice->wakeupEvent); + + /* + Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device + into the started state. Don't call ma_device__set_state() here. + */ + ma_event_wait(&pDevice->startEvent); + result = pDevice->workResult; + } + + /* 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_mutex_unlock(&pDevice->startStopLock); + + return result; +} + +MA_API ma_result ma_device_stop(ma_device* pDevice) +{ + ma_result result; + + if (pDevice == NULL) { + return 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_device_state_stopped) { + return MA_SUCCESS; /* Already stopped. */ + } + + 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_device__set_state(pDevice, ma_device_state_stopping); + + /* Asynchronous backends need to be handled differently. */ + if (ma_context_is_backend_asynchronous(pDevice->pContext)) { + /* Asynchronous backends must have a stop operation. */ + if (pDevice->pContext->callbacks.onDeviceStop != NULL) { + result = pDevice->pContext->callbacks.onDeviceStop(pDevice); + } else { + result = MA_INVALID_OPERATION; + } + + ma_device__set_state(pDevice, ma_device_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 + 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); + + if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) { + pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice); + } + + /* + We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be + the one who puts the device into the stopped state. Don't call ma_device__set_state() here. + */ + 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); + + return result; +} + +MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice) +{ + return ma_device_get_state(pDevice) == ma_device_state_started; +} + +MA_API ma_device_state ma_device_get_state(const ma_device* pDevice) +{ + if (pDevice == NULL) { + return ma_device_state_uninitialized; + } + + return ma_atomic_device_state_get((ma_atomic_device_state*)&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) +{ + if (pDevice == NULL) { + return MA_INVALID_ARGS; + } + + if (volume < 0.0f) { + return MA_INVALID_ARGS; + } + + ma_atomic_float_set(&pDevice->masterVolumeFactor, volume); + + return MA_SUCCESS; +} + +MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume) +{ + if (pVolume == NULL) { + return MA_INVALID_ARGS; + } + + if (pDevice == NULL) { + *pVolume = 0; + return MA_INVALID_ARGS; + } + + *pVolume = ma_atomic_float_get(&pDevice->masterVolumeFactor); + + return MA_SUCCESS; +} + +MA_API ma_result ma_device_set_master_volume_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)); +} + +MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB) +{ + float factor; + ma_result result; + + if (pGainDB == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_device_get_master_volume(pDevice, &factor); + if (result != MA_SUCCESS) { + *pGainDB = 0; + return result; + } + + *pGainDB = ma_volume_linear_to_db(factor); + + return MA_SUCCESS; +} + + +MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +{ + if (pDevice == NULL) { + return MA_INVALID_ARGS; + } + + if (pOutput == NULL && pInput == NULL) { + 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); + } + + if (pOutput != NULL) { + ma_device__handle_duplex_callback_playback(pDevice, frameCount, pOutput, &pDevice->duplexRB.rb); + } + } else { + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_loopback) { + if (pInput == NULL) { + return MA_INVALID_ARGS; + } + + ma_device__send_frames_to_client(pDevice, frameCount, pInput); + } + + if (pDevice->type == ma_device_type_playback) { + if (pOutput == NULL) { + return MA_INVALID_ARGS; + } + + ma_device__read_frames_from_client(pDevice, frameCount, pOutput); + } + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile) +{ + if (pDescriptor == NULL) { + return 0; + } + + /* + We must have a non-0 native sample rate, but some backends don't allow retrieval of this at the + time when the size of the buffer needs to be determined. In this case we need to just take a best + guess and move on. We'll try using the sample rate in pDescriptor first. If that's not set we'll + just fall back to MA_DEFAULT_SAMPLE_RATE. + */ + if (nativeSampleRate == 0) { + nativeSampleRate = pDescriptor->sampleRate; + } + if (nativeSampleRate == 0) { + nativeSampleRate = MA_DEFAULT_SAMPLE_RATE; + } + + 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(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, nativeSampleRate); + } else { + return ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, nativeSampleRate); + } + } else { + return ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate); + } + } else { + return pDescriptor->periodSizeInFrames; + } +} +#endif /* MA_NO_DEVICE_IO */ + + +MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate) +{ + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + + return (bufferSizeInFrames*1000 + (sampleRate - 1)) / sampleRate; +} + +MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) +{ + /* Prevent a division by zero. */ + if (sampleRate == 0) { + return 0; + } + + return bufferSizeInMilliseconds*sampleRate / 1000; +} + +MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels) +{ + if (dst == src) { + return; /* No-op. */ + } + + ma_copy_memory_64(dst, src, frameCount * ma_get_bytes_per_frame(format, channels)); +} + +MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels) +{ + if (format == ma_format_u8) { + ma_uint64 sampleCount = frameCount * channels; + ma_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + ((ma_uint8*)p)[iSample] = 128; + } + } else { + ma_zero_memory_64(p, frameCount * ma_get_bytes_per_frame(format, channels)); + } +} + +MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels) +{ + return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels)); +} + +MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels) +{ + return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels)); +} + + +MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* 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_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; + } +} + + +MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor) +{ + ma_uint64 iSample; + + if (pSamplesOut == NULL || pSamplesIn == NULL) { + return; + } + + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = (ma_uint8)(pSamplesIn[iSample] * factor); + } +} + +MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor) +{ + ma_uint64 iSample; + + if (pSamplesOut == NULL || pSamplesIn == NULL) { + return; + } + + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = (ma_int16)(pSamplesIn[iSample] * factor); + } +} + +MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor) +{ + ma_uint64 iSample; + ma_uint8* pSamplesOut8; + ma_uint8* pSamplesIn8; + + if (pSamplesOut == NULL || pSamplesIn == NULL) { + return; + } + + pSamplesOut8 = (ma_uint8*)pSamplesOut; + pSamplesIn8 = (ma_uint8*)pSamplesIn; + + for (iSample = 0; iSample < sampleCount; iSample += 1) { + ma_int32 sampleS32; + + sampleS32 = (ma_int32)(((ma_uint32)(pSamplesIn8[iSample*3+0]) << 8) | ((ma_uint32)(pSamplesIn8[iSample*3+1]) << 16) | ((ma_uint32)(pSamplesIn8[iSample*3+2])) << 24); + sampleS32 = (ma_int32)(sampleS32 * factor); + + pSamplesOut8[iSample*3+0] = (ma_uint8)(((ma_uint32)sampleS32 & 0x0000FF00) >> 8); + pSamplesOut8[iSample*3+1] = (ma_uint8)(((ma_uint32)sampleS32 & 0x00FF0000) >> 16); + pSamplesOut8[iSample*3+2] = (ma_uint8)(((ma_uint32)sampleS32 & 0xFF000000) >> 24); + } +} + +MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor) +{ + ma_uint64 iSample; + + if (pSamplesOut == NULL || pSamplesIn == NULL) { + return; + } + + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamplesOut[iSample] = (ma_int32)(pSamplesIn[iSample] * factor); + } +} + +MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor) +{ + ma_uint64 iSample; + + if (pSamplesOut == NULL || pSamplesIn == NULL) { + 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; + } + } +} + +MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor) +{ + ma_copy_and_apply_volume_factor_u8(pSamples, pSamples, sampleCount, factor); +} + +MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor) +{ + ma_copy_and_apply_volume_factor_s16(pSamples, pSamples, sampleCount, factor); +} + +MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor) +{ + ma_copy_and_apply_volume_factor_s24(pSamples, pSamples, sampleCount, factor); +} + +MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor) +{ + ma_copy_and_apply_volume_factor_s32(pSamples, pSamples, sampleCount, factor); +} + +MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor) +{ + 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_copy_and_apply_volume_factor_u8(pFramesOut, pFramesIn, 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_copy_and_apply_volume_factor_s16(pFramesOut, pFramesIn, 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_copy_and_apply_volume_factor_s24(pFramesOut, pFramesIn, 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_copy_and_apply_volume_factor_s32(pFramesOut, pFramesIn, 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_copy_and_apply_volume_factor_f32(pFramesOut, pFramesIn, 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) +{ + 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; + 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_copy_and_apply_volume_factor_pcm_frames_u8(pFrames, pFrames, 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_copy_and_apply_volume_factor_pcm_frames_s16(pFrames, pFrames, frameCount, channels, factor); +} + +MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +{ + ma_copy_and_apply_volume_factor_pcm_frames_s24(pFrames, pFrames, 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_copy_and_apply_volume_factor_pcm_frames_s32(pFrames, pFrames, frameCount, channels, factor); +} + +MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor) +{ + ma_copy_and_apply_volume_factor_pcm_frames_f32(pFrames, pFrames, 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_copy_and_apply_volume_factor_pcm_frames(pFramesOut, pFramesOut, 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_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]; + } + } +} + + + +static MA_INLINE ma_int16 ma_apply_volume_unclipped_u8(ma_int16 x, ma_int16 volume) +{ + return (ma_int16)(((ma_int32)x * (ma_int32)volume) >> 8); +} + +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; +} + + + +/************************************************************************************************************************************************************** + +Format Conversion + +**************************************************************************************************************************************************************/ + +static MA_INLINE ma_int16 ma_pcm_sample_f32_to_s16(float x) +{ + return (ma_int16)(x * 32767.0f); +} + +static MA_INLINE ma_int16 ma_pcm_sample_u8_to_s16_no_scale(ma_uint8 x) +{ + return (ma_int16)((ma_int16)x - 128); +} + +static MA_INLINE ma_int64 ma_pcm_sample_s24_to_s32_no_scale(const ma_uint8* x) +{ + return (ma_int64)(((ma_uint64)x[0] << 40) | ((ma_uint64)x[1] << 48) | ((ma_uint64)x[2] << 56)) >> 40; /* Make sure the sign bits are maintained. */ +} + +static MA_INLINE void ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x, ma_uint8* s24) +{ + s24[0] = (ma_uint8)((x & 0x000000FF) >> 0); + s24[1] = (ma_uint8)((x & 0x0000FF00) >> 8); + s24[2] = (ma_uint8)((x & 0x00FF0000) >> 16); +} + + +/* u8 */ +MA_API void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + (void)ditherMode; + ma_copy_memory_64(dst, src, count * sizeof(ma_uint8)); +} + + +static MA_INLINE void ma_pcm_u8_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int16* dst_s16 = (ma_int16*)dst; + const ma_uint8* src_u8 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int16 x = src_u8[i]; + x = (ma_int16)(x - 128); + x = (ma_int16)(x << 8); + dst_s16[i] = x; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_u8_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_u8_to_s16__sse2(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) +{ + ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_u8_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_s24 = (ma_uint8*)dst; + const ma_uint8* src_u8 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int16 x = src_u8[i]; + x = (ma_int16)(x - 128); + + dst_s24[i*3+0] = 0; + dst_s24[i*3+1] = 0; + dst_s24[i*3+2] = (ma_uint8)((ma_int8)x); + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_u8_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_u8_to_s24__sse2(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) +{ + ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_u8_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int32* dst_s32 = (ma_int32*)dst; + const ma_uint8* src_u8 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = src_u8[i]; + x = x - 128; + x = x << 24; + dst_s32[i] = x; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_u8_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_u8_to_s32__sse2(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) +{ + ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_u8_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + float* dst_f32 = (float*)dst; + const ma_uint8* src_u8 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + float x = (float)src_u8[i]; + x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ + + dst_f32[i] = x; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_u8_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_u8_to_f32__sse2(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) +{ + ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +#ifdef MA_USE_REFERENCE_CONVERSION_APIS +static MA_INLINE void ma_pcm_interleave_u8__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_uint8* dst_u8 = (ma_uint8*)dst; + const ma_uint8** src_u8 = (const ma_uint8**)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame]; + } + } +} +#else +static MA_INLINE void ma_pcm_interleave_u8__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_uint8* dst_u8 = (ma_uint8*)dst; + const ma_uint8** src_u8 = (const ma_uint8**)src; + + if (channels == 1) { + ma_copy_memory_64(dst, src[0], frameCount * sizeof(ma_uint8)); + } else if (channels == 2) { + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + dst_u8[iFrame*2 + 0] = src_u8[0][iFrame]; + dst_u8[iFrame*2 + 1] = src_u8[1][iFrame]; + } + } else { + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame]; + } + } + } +} +#endif + +MA_API void ma_pcm_interleave_u8(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_interleave_u8__reference(dst, src, frameCount, channels); +#else + ma_pcm_interleave_u8__optimized(dst, src, frameCount, channels); +#endif +} + + +static MA_INLINE void ma_pcm_deinterleave_u8__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_uint8** dst_u8 = (ma_uint8**)dst; + const ma_uint8* src_u8 = (const ma_uint8*)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_u8[iChannel][iFrame] = src_u8[iFrame*channels + iChannel]; + } + } +} + +static MA_INLINE void ma_pcm_deinterleave_u8__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_deinterleave_u8(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels); +#else + ma_pcm_deinterleave_u8__optimized(dst, src, frameCount, channels); +#endif +} + + +/* s16 */ +static MA_INLINE void ma_pcm_s16_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_u8 = (ma_uint8*)dst; + const ma_int16* src_s16 = (const ma_int16*)src; + + if (ditherMode == ma_dither_mode_none) { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int16 x = src_s16[i]; + x = (ma_int16)(x >> 8); + x = (ma_int16)(x + 128); + dst_u8[i] = (ma_uint8)x; + } + } else { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int16 x = src_s16[i]; + + /* Dither. Don't overflow. */ + ma_int32 dither = ma_dither_s32(ditherMode, -0x80, 0x7F); + if ((x + dither) <= 0x7FFF) { + x = (ma_int16)(x + dither); + } else { + x = 0x7FFF; + } + + x = (ma_int16)(x >> 8); + x = (ma_int16)(x + 128); + dst_u8[i] = (ma_uint8)x; + } + } +} + +static MA_INLINE void ma_pcm_s16_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s16_to_u8__sse2(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) +{ + ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode); + } +#endif +} + + +MA_API void ma_pcm_s16_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + (void)ditherMode; + ma_copy_memory_64(dst, src, count * sizeof(ma_int16)); +} + + +static MA_INLINE void ma_pcm_s16_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_s24 = (ma_uint8*)dst; + const ma_int16* src_s16 = (const ma_int16*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + dst_s24[i*3+0] = 0; + dst_s24[i*3+1] = (ma_uint8)(src_s16[i] & 0xFF); + dst_s24[i*3+2] = (ma_uint8)(src_s16[i] >> 8); + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_s16_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s16_to_s24__sse2(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) +{ + ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int32* dst_s32 = (ma_int32*)dst; + const ma_int16* src_s16 = (const ma_int16*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + dst_s32[i] = src_s16[i] << 16; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_s16_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s16_to_s32__sse2(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) +{ + ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s16_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + float* dst_f32 = (float*)dst; + const ma_int16* src_s16 = (const ma_int16*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + float x = (float)src_s16[i]; + +#if 0 + /* The accurate way. */ + x = x + 32768.0f; /* -32768..32767 to 0..65535 */ + x = x * 0.00003051804379339284f; /* 0..65535 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ +#else + /* The fast way. */ + x = x * 0.000030517578125f; /* -32768..32767 to -1..0.999969482421875 */ +#endif + + dst_f32[i] = x; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_s16_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s16_to_f32__sse2(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) +{ + ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_interleave_s16__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_int16* dst_s16 = (ma_int16*)dst; + const ma_int16** src_s16 = (const ma_int16**)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_s16[iFrame*channels + iChannel] = src_s16[iChannel][iFrame]; + } + } +} + +static MA_INLINE void ma_pcm_interleave_s16__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_interleave_s16__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_interleave_s16(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_interleave_s16__reference(dst, src, frameCount, channels); +#else + ma_pcm_interleave_s16__optimized(dst, src, frameCount, channels); +#endif +} + + +static MA_INLINE void ma_pcm_deinterleave_s16__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_int16** dst_s16 = (ma_int16**)dst; + const ma_int16* src_s16 = (const ma_int16*)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_s16[iChannel][iFrame] = src_s16[iFrame*channels + iChannel]; + } + } +} + +static MA_INLINE void ma_pcm_deinterleave_s16__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_deinterleave_s16(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels); +#else + ma_pcm_deinterleave_s16__optimized(dst, src, frameCount, channels); +#endif +} + + +/* s24 */ +static MA_INLINE void ma_pcm_s24_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_u8 = (ma_uint8*)dst; + const ma_uint8* src_s24 = (const ma_uint8*)src; + + if (ditherMode == ma_dither_mode_none) { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + dst_u8[i] = (ma_uint8)((ma_int8)src_s24[i*3 + 2] + 128); + } + } else { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); + + /* Dither. Don't overflow. */ + ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF); + if ((ma_int64)x + dither <= 0x7FFFFFFF) { + x = x + dither; + } else { + x = 0x7FFFFFFF; + } + + x = x >> 24; + x = x + 128; + dst_u8[i] = (ma_uint8)x; + } + } +} + +static MA_INLINE void ma_pcm_s24_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s24_to_u8__sse2(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) +{ + ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s24_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int16* dst_s16 = (ma_int16*)dst; + const ma_uint8* src_s24 = (const ma_uint8*)src; + + if (ditherMode == ma_dither_mode_none) { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_uint16 dst_lo = ((ma_uint16)src_s24[i*3 + 1]); + ma_uint16 dst_hi = (ma_uint16)((ma_uint16)src_s24[i*3 + 2] << 8); + dst_s16[i] = (ma_int16)(dst_lo | dst_hi); + } + } else { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); + + /* Dither. Don't overflow. */ + ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF); + if ((ma_int64)x + dither <= 0x7FFFFFFF) { + x = x + dither; + } else { + x = 0x7FFFFFFF; + } + + x = x >> 16; + dst_s16[i] = (ma_int16)x; + } + } +} + +static MA_INLINE void ma_pcm_s24_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s24_to_s16__sse2(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) +{ + ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode); + } +#endif +} + + +MA_API void ma_pcm_s24_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + (void)ditherMode; + + ma_copy_memory_64(dst, src, count * 3); +} + + +static MA_INLINE void ma_pcm_s24_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int32* dst_s32 = (ma_int32*)dst; + const ma_uint8* src_s24 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + dst_s32[i] = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24); + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_s24_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s24_to_s32__sse2(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) +{ + ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s24_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + float* dst_f32 = (float*)dst; + const ma_uint8* src_s24 = (const ma_uint8*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + float x = (float)(((ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24)) >> 8); + +#if 0 + /* The accurate way. */ + x = x + 8388608.0f; /* -8388608..8388607 to 0..16777215 */ + x = x * 0.00000011920929665621f; /* 0..16777215 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ +#else + /* The fast way. */ + x = x * 0.00000011920928955078125f; /* -8388608..8388607 to -1..0.999969482421875 */ +#endif + + dst_f32[i] = x; + } + + (void)ditherMode; +} + +static MA_INLINE void ma_pcm_s24_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s24_to_f32__sse2(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) +{ + ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_interleave_s24__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_uint8* dst8 = (ma_uint8*)dst; + const ma_uint8** src8 = (const ma_uint8**)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst8[iFrame*3*channels + iChannel*3 + 0] = src8[iChannel][iFrame*3 + 0]; + dst8[iFrame*3*channels + iChannel*3 + 1] = src8[iChannel][iFrame*3 + 1]; + dst8[iFrame*3*channels + iChannel*3 + 2] = src8[iChannel][iFrame*3 + 2]; + } + } +} + +static MA_INLINE void ma_pcm_interleave_s24__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_interleave_s24__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_interleave_s24(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_interleave_s24__reference(dst, src, frameCount, channels); +#else + ma_pcm_interleave_s24__optimized(dst, src, frameCount, channels); +#endif +} + + +static MA_INLINE void ma_pcm_deinterleave_s24__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_uint8** dst8 = (ma_uint8**)dst; + const ma_uint8* src8 = (const ma_uint8*)src; + + ma_uint32 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst8[iChannel][iFrame*3 + 0] = src8[iFrame*3*channels + iChannel*3 + 0]; + dst8[iChannel][iFrame*3 + 1] = src8[iFrame*3*channels + iChannel*3 + 1]; + dst8[iChannel][iFrame*3 + 2] = src8[iFrame*3*channels + iChannel*3 + 2]; + } + } +} + +static MA_INLINE void ma_pcm_deinterleave_s24__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_deinterleave_s24(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels); +#else + ma_pcm_deinterleave_s24__optimized(dst, src, frameCount, channels); +#endif +} + + + +/* s32 */ +static MA_INLINE void ma_pcm_s32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_u8 = (ma_uint8*)dst; + const ma_int32* src_s32 = (const ma_int32*)src; + + if (ditherMode == ma_dither_mode_none) { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = src_s32[i]; + x = x >> 24; + x = x + 128; + dst_u8[i] = (ma_uint8)x; + } + } else { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = src_s32[i]; + + /* Dither. Don't overflow. */ + ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF); + if ((ma_int64)x + dither <= 0x7FFFFFFF) { + x = x + dither; + } else { + x = 0x7FFFFFFF; + } + + x = x >> 24; + x = x + 128; + dst_u8[i] = (ma_uint8)x; + } + } +} + +static MA_INLINE void ma_pcm_s32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s32_to_u8__sse2(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) +{ + ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int16* dst_s16 = (ma_int16*)dst; + const ma_int32* src_s32 = (const ma_int32*)src; + + if (ditherMode == ma_dither_mode_none) { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = src_s32[i]; + x = x >> 16; + dst_s16[i] = (ma_int16)x; + } + } else { + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 x = src_s32[i]; + + /* Dither. Don't overflow. */ + ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF); + if ((ma_int64)x + dither <= 0x7FFFFFFF) { + x = x + dither; + } else { + x = 0x7FFFFFFF; + } + + x = x >> 16; + dst_s16[i] = (ma_int16)x; + } + } +} + +static MA_INLINE void ma_pcm_s32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s32_to_s16__sse2(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) +{ + ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_s32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_s24 = (ma_uint8*)dst; + const ma_int32* src_s32 = (const ma_int32*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_uint32 x = (ma_uint32)src_s32[i]; + dst_s24[i*3+0] = (ma_uint8)((x & 0x0000FF00) >> 8); + dst_s24[i*3+1] = (ma_uint8)((x & 0x00FF0000) >> 16); + dst_s24[i*3+2] = (ma_uint8)((x & 0xFF000000) >> 24); + } + + (void)ditherMode; /* No dithering for s32 -> s24. */ +} + +static MA_INLINE void ma_pcm_s32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s32_to_s24__sse2(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) +{ + ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode); + } +#endif +} + + +MA_API void ma_pcm_s32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + (void)ditherMode; + + ma_copy_memory_64(dst, src, count * sizeof(ma_int32)); +} + + +static MA_INLINE void ma_pcm_s32_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + float* dst_f32 = (float*)dst; + const ma_int32* src_s32 = (const ma_int32*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + double x = src_s32[i]; + +#if 0 + x = x + 2147483648.0; + x = x * 0.0000000004656612873077392578125; + x = x - 1; +#else + x = x / 2147483648.0; +#endif + + dst_f32[i] = (float)x; + } + + (void)ditherMode; /* No dithering for s32 -> f32. */ +} + +static MA_INLINE void ma_pcm_s32_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_s32_to_f32__sse2(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) +{ + ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_interleave_s32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_int32* dst_s32 = (ma_int32*)dst; + const ma_int32** src_s32 = (const ma_int32**)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_s32[iFrame*channels + iChannel] = src_s32[iChannel][iFrame]; + } + } +} + +static MA_INLINE void ma_pcm_interleave_s32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_interleave_s32__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_interleave_s32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_interleave_s32__reference(dst, src, frameCount, channels); +#else + ma_pcm_interleave_s32__optimized(dst, src, frameCount, channels); +#endif +} + + +static MA_INLINE void ma_pcm_deinterleave_s32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_int32** dst_s32 = (ma_int32**)dst; + const ma_int32* src_s32 = (const ma_int32*)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_s32[iChannel][iFrame] = src_s32[iFrame*channels + iChannel]; + } + } +} + +static MA_INLINE void ma_pcm_deinterleave_s32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_deinterleave_s32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels); +#else + ma_pcm_deinterleave_s32__optimized(dst, src, frameCount, channels); +#endif +} + + +/* f32 */ +static MA_INLINE void ma_pcm_f32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint64 i; + + ma_uint8* dst_u8 = (ma_uint8*)dst; + const float* src_f32 = (const float*)src; + + float ditherMin = 0; + float ditherMax = 0; + if (ditherMode != ma_dither_mode_none) { + ditherMin = 1.0f / -128; + ditherMax = 1.0f / 127; + } + + for (i = 0; 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 + 1; /* -1..1 to 0..2 */ + x = x * 127.5f; /* 0..2 to 0..255 */ + + dst_u8[i] = (ma_uint8)x; + } +} + +static MA_INLINE void ma_pcm_f32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_f32_to_u8__sse2(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) +{ + ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode); + } +#endif +} + +#ifdef MA_USE_REFERENCE_CONVERSION_APIS +static MA_INLINE void ma_pcm_f32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint64 i; + + ma_int16* dst_s16 = (ma_int16*)dst; + const float* src_f32 = (const float*)src; + + float ditherMin = 0; + float ditherMax = 0; + if (ditherMode != ma_dither_mode_none) { + ditherMin = 1.0f / -32768; + ditherMax = 1.0f / 32767; + } + + for (i = 0; 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 */ + +#if 0 + /* The accurate way. */ + x = x + 1; /* -1..1 to 0..2 */ + x = x * 32767.5f; /* 0..2 to 0..65535 */ + x = x - 32768.0f; /* 0...65535 to -32768..32767 */ +#else + /* The fast way. */ + x = x * 32767.0f; /* -1..1 to -32767..32767 */ +#endif + + dst_s16[i] = (ma_int16)x; + } +} +#else +static MA_INLINE void ma_pcm_f32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint64 i; + ma_uint64 i4; + ma_uint64 count4; + + ma_int16* dst_s16 = (ma_int16*)dst; + const float* src_f32 = (const float*)src; + + float ditherMin = 0; + float ditherMax = 0; + if (ditherMode != ma_dither_mode_none) { + ditherMin = 1.0f / -32768; + ditherMax = 1.0f / 32767; + } + + /* Unrolled. */ + i = 0; + count4 = count >> 2; + for (i4 = 0; i4 < count4; i4 += 1) { + float d0 = ma_dither_f32(ditherMode, ditherMin, ditherMax); + float d1 = ma_dither_f32(ditherMode, ditherMin, ditherMax); + float d2 = ma_dither_f32(ditherMode, ditherMin, ditherMax); + float d3 = ma_dither_f32(ditherMode, ditherMin, ditherMax); + + float x0 = src_f32[i+0]; + float x1 = src_f32[i+1]; + float x2 = src_f32[i+2]; + float x3 = src_f32[i+3]; + + x0 = x0 + d0; + x1 = x1 + d1; + x2 = x2 + d2; + x3 = x3 + d3; + + x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0)); + x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1)); + x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2)); + x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3)); + + x0 = x0 * 32767.0f; + x1 = x1 * 32767.0f; + x2 = x2 * 32767.0f; + x3 = x3 * 32767.0f; + + dst_s16[i+0] = (ma_int16)x0; + dst_s16[i+1] = (ma_int16)x1; + dst_s16[i+2] = (ma_int16)x2; + dst_s16[i+3] = (ma_int16)x3; + + i += 4; + } + + /* 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; + } +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint64 i; + ma_uint64 i8; + ma_uint64 count8; + ma_int16* dst_s16; + const float* src_f32; + float ditherMin; + float ditherMax; + + /* Both the input and output buffers need to be aligned to 16 bytes. */ + if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 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; + + /* SSE2. SSE allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */ + count8 = count >> 3; + for (i8 = 0; i8 < count8; i8 += 1) { + __m128 d0; + __m128 d1; + __m128 x0; + __m128 x1; + + if (ditherMode == ma_dither_mode_none) { + d0 = _mm_set1_ps(0); + d1 = _mm_set1_ps(0); + } else if (ditherMode == ma_dither_mode_rectangle) { + d0 = _mm_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) + ); + d1 = _mm_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) + ); + } else { + d0 = _mm_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) + ); + d1 = _mm_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) + ); + } + + x0 = *((__m128*)(src_f32 + i) + 0); + x1 = *((__m128*)(src_f32 + i) + 1); + + x0 = _mm_add_ps(x0, d0); + x1 = _mm_add_ps(x1, d1); + + x0 = _mm_mul_ps(x0, _mm_set1_ps(32767.0f)); + x1 = _mm_mul_ps(x1, _mm_set1_ps(32767.0f)); + + _mm_stream_si128(((__m128i*)(dst_s16 + i)), _mm_packs_epi32(_mm_cvttps_epi32(x0), _mm_cvttps_epi32(x1))); + + i += 8; + } + + + /* 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 /* SSE2 */ + +#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) +{ + ma_uint64 i; + ma_uint64 i8; + ma_uint64 count8; + ma_int16* dst_s16; + const float* src_f32; + float ditherMin; + float ditherMax; + + if (!ma_has_neon()) { + ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); + return; + } + + /* Both the input and output buffers need to be aligned to 16 bytes. */ + if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 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; + + /* NEON. NEON allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */ + count8 = count >> 3; + for (i8 = 0; i8 < count8; i8 += 1) { + float32x4_t d0; + float32x4_t d1; + float32x4_t x0; + float32x4_t x1; + int32x4_t i0; + int32x4_t i1; + + if (ditherMode == ma_dither_mode_none) { + d0 = vmovq_n_f32(0); + 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); + + d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax); + d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax); + d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax); + d1v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax); + 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); + + d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax); + d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax); + d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax); + d1v[3] = ma_dither_f32_triangle(ditherMin, ditherMax); + d1 = vld1q_f32(d1v); + } + + x0 = *((float32x4_t*)(src_f32 + i) + 0); + x1 = *((float32x4_t*)(src_f32 + i) + 1); + + x0 = vaddq_f32(x0, d0); + x1 = vaddq_f32(x1, d1); + + x0 = vmulq_n_f32(x0, 32767.0f); + x1 = vmulq_n_f32(x1, 32767.0f); + + i0 = vcvtq_s32_f32(x0); + i1 = vcvtq_s32_f32(x1); + *((int16x8_t*)(dst_s16 + i)) = vcombine_s16(vqmovn_s32(i0), vqmovn_s32(i1)); + + i += 8; + } + + + /* 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 /* Neon */ +#endif /* MA_USE_REFERENCE_CONVERSION_APIS */ + +MA_API void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_f32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_uint8* dst_s24 = (ma_uint8*)dst; + const float* src_f32 = (const float*)src; + + ma_uint64 i; + for (i = 0; i < count; i += 1) { + ma_int32 r; + float x = src_f32[i]; + x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ + +#if 0 + /* The accurate way. */ + x = x + 1; /* -1..1 to 0..2 */ + x = x * 8388607.5f; /* 0..2 to 0..16777215 */ + x = x - 8388608.0f; /* 0..16777215 to -8388608..8388607 */ +#else + /* The fast way. */ + x = x * 8388607.0f; /* -1..1 to -8388607..8388607 */ +#endif + + r = (ma_int32)x; + dst_s24[(i*3)+0] = (ma_uint8)((r & 0x0000FF) >> 0); + dst_s24[(i*3)+1] = (ma_uint8)((r & 0x00FF00) >> 8); + dst_s24[(i*3)+2] = (ma_uint8)((r & 0xFF0000) >> 16); + } + + (void)ditherMode; /* No dithering for f32 -> s24. */ +} + +static MA_INLINE void ma_pcm_f32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_f32_to_s24__sse2(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) +{ + ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode); + } +#endif +} + + +static MA_INLINE void ma_pcm_f32_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_int32* dst_s32 = (ma_int32*)dst; + const float* src_f32 = (const float*)src; + + ma_uint32 i; + for (i = 0; i < count; i += 1) { + double x = src_f32[i]; + x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */ + +#if 0 + /* The accurate way. */ + x = x + 1; /* -1..1 to 0..2 */ + x = x * 2147483647.5; /* 0..2 to 0..4294967295 */ + x = x - 2147483648.0; /* 0...4294967295 to -2147483648..2147483647 */ +#else + /* The fast way. */ + x = x * 2147483647.0; /* -1..1 to -2147483647..2147483647 */ +#endif + + dst_s32[i] = (ma_int32)x; + } + + (void)ditherMode; /* No dithering for f32 -> s32. */ +} + +static MA_INLINE void ma_pcm_f32_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); +} + +#if defined(MA_SUPPORT_SSE2) +static MA_INLINE void ma_pcm_f32_to_s32__sse2(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) +{ + ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); +} +#endif + +MA_API void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode); +#else + # if defined(MA_SUPPORT_SSE2) + if (ma_has_sse2()) { + ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode); + } else + #elif defined(MA_SUPPORT_NEON) + if (ma_has_neon()) { + ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode); + } else + #endif + { + ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode); + } +#endif +} + + +MA_API void ma_pcm_f32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode) +{ + (void)ditherMode; + + ma_copy_memory_64(dst, src, count * sizeof(float)); +} + + +static void ma_pcm_interleave_f32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + float* dst_f32 = (float*)dst; + const float** src_f32 = (const float**)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_f32[iFrame*channels + iChannel] = src_f32[iChannel][iFrame]; + } + } +} + +static void ma_pcm_interleave_f32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_interleave_f32__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_interleave_f32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_interleave_f32__reference(dst, src, frameCount, channels); +#else + ma_pcm_interleave_f32__optimized(dst, src, frameCount, channels); +#endif +} + + +static void ma_pcm_deinterleave_f32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + float** dst_f32 = (float**)dst; + const float* src_f32 = (const float*)src; + + ma_uint64 iFrame; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; iChannel += 1) { + dst_f32[iChannel][iFrame] = src_f32[iFrame*channels + iChannel]; + } + } +} + +static void ma_pcm_deinterleave_f32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ + ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels); +} + +MA_API void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels) +{ +#ifdef MA_USE_REFERENCE_CONVERSION_APIS + ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels); +#else + ma_pcm_deinterleave_f32__optimized(dst, src, frameCount, channels); +#endif +} + + +MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode) +{ + if (formatOut == formatIn) { + ma_copy_memory_64(pOut, pIn, sampleCount * ma_get_bytes_per_sample(formatOut)); + return; + } + + switch (formatIn) + { + case ma_format_u8: + { + switch (formatOut) + { + case ma_format_s16: ma_pcm_u8_to_s16(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s24: ma_pcm_u8_to_s24(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s32: ma_pcm_u8_to_s32(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_f32: ma_pcm_u8_to_f32(pOut, pIn, sampleCount, ditherMode); return; + default: break; + } + } break; + + case ma_format_s16: + { + switch (formatOut) + { + case ma_format_u8: ma_pcm_s16_to_u8( pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s24: ma_pcm_s16_to_s24(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s32: ma_pcm_s16_to_s32(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_f32: ma_pcm_s16_to_f32(pOut, pIn, sampleCount, ditherMode); return; + default: break; + } + } break; + + case ma_format_s24: + { + switch (formatOut) + { + case ma_format_u8: ma_pcm_s24_to_u8( pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s16: ma_pcm_s24_to_s16(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s32: ma_pcm_s24_to_s32(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_f32: ma_pcm_s24_to_f32(pOut, pIn, sampleCount, ditherMode); return; + default: break; + } + } break; + + case ma_format_s32: + { + switch (formatOut) + { + case ma_format_u8: ma_pcm_s32_to_u8( pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s16: ma_pcm_s32_to_s16(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s24: ma_pcm_s32_to_s24(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_f32: ma_pcm_s32_to_f32(pOut, pIn, sampleCount, ditherMode); return; + default: break; + } + } break; + + case ma_format_f32: + { + switch (formatOut) + { + case ma_format_u8: ma_pcm_f32_to_u8( pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s16: ma_pcm_f32_to_s16(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s24: ma_pcm_f32_to_s24(pOut, pIn, sampleCount, ditherMode); return; + case ma_format_s32: ma_pcm_f32_to_s32(pOut, pIn, sampleCount, ditherMode); return; + default: break; + } + } break; + + default: break; + } +} + +MA_API void ma_convert_pcm_frames_format(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 frameCount, ma_uint32 channels, ma_dither_mode ditherMode) +{ + ma_pcm_convert(pOut, formatOut, pIn, formatIn, frameCount * channels, ditherMode); +} + +MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames) +{ + if (pInterleavedPCMFrames == NULL || ppDeinterleavedPCMFrames == NULL) { + return; /* Invalid args. */ + } + + /* For efficiency we do this per format. */ + switch (format) { + case ma_format_s16: + { + const ma_int16* pSrcS16 = (const ma_int16*)pInterleavedPCMFrames; + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + ma_int16* pDstS16 = (ma_int16*)ppDeinterleavedPCMFrames[iChannel]; + pDstS16[iPCMFrame] = pSrcS16[iPCMFrame*channels+iChannel]; + } + } + } break; + + case ma_format_f32: + { + const float* pSrcF32 = (const float*)pInterleavedPCMFrames; + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + float* pDstF32 = (float*)ppDeinterleavedPCMFrames[iChannel]; + pDstF32[iPCMFrame] = pSrcF32[iPCMFrame*channels+iChannel]; + } + } + } break; + + default: + { + ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format); + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + void* pDst = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes); + const void* pSrc = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes); + memcpy(pDst, pSrc, sampleSizeInBytes); + } + } + } break; + } +} + +MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames) +{ + switch (format) + { + case ma_format_s16: + { + ma_int16* pDstS16 = (ma_int16*)pInterleavedPCMFrames; + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + const ma_int16* pSrcS16 = (const ma_int16*)ppDeinterleavedPCMFrames[iChannel]; + pDstS16[iPCMFrame*channels+iChannel] = pSrcS16[iPCMFrame]; + } + } + } break; + + case ma_format_f32: + { + float* pDstF32 = (float*)pInterleavedPCMFrames; + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + const float* pSrcF32 = (const float*)ppDeinterleavedPCMFrames[iChannel]; + pDstF32[iPCMFrame*channels+iChannel] = pSrcF32[iPCMFrame]; + } + } + } break; + + default: + { + ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format); + ma_uint64 iPCMFrame; + for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + void* pDst = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes); + const void* pSrc = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes); + memcpy(pDst, pSrc, sampleSizeInBytes); + } + } + } break; + } +} + + +/************************************************************************************************************************************************************** + +Biquad Filter + +**************************************************************************************************************************************************************/ +#ifndef MA_BIQUAD_FIXED_POINT_SHIFT +#define MA_BIQUAD_FIXED_POINT_SHIFT 14 +#endif + +static ma_int32 ma_biquad_float_to_fp(double x) +{ + return (ma_int32)(x * (1 << MA_BIQUAD_FIXED_POINT_SHIFT)); +} + +MA_API ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2) +{ + ma_biquad_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.b0 = b0; + config.b1 = b1; + config.b2 = b2; + config.a0 = a0; + config.a1 = a1; + config.a2 = a2; + + return config; +} + + +typedef struct +{ + 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; + } + + 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); + + 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) { + return MA_INVALID_ARGS; + } + + if (pConfig->a0 == 0) { + return MA_INVALID_ARGS; /* Division by zero. */ + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pBQ->format != ma_format_unknown && pBQ->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pBQ->channels != 0 && pBQ->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + + pBQ->format = pConfig->format; + pBQ->channels = pConfig->channels; + + /* Normalize. */ + if (pConfig->format == ma_format_f32) { + pBQ->b0.f32 = (float)(pConfig->b0 / pConfig->a0); + pBQ->b1.f32 = (float)(pConfig->b1 / pConfig->a0); + pBQ->b2.f32 = (float)(pConfig->b2 / pConfig->a0); + pBQ->a1.f32 = (float)(pConfig->a1 / pConfig->a0); + pBQ->a2.f32 = (float)(pConfig->a2 / pConfig->a0); + } else { + pBQ->b0.s32 = ma_biquad_float_to_fp(pConfig->b0 / pConfig->a0); + pBQ->b1.s32 = ma_biquad_float_to_fp(pConfig->b1 / pConfig->a0); + pBQ->b2.s32 = ma_biquad_float_to_fp(pConfig->b2 / pConfig->a0); + pBQ->a1.s32 = ma_biquad_float_to_fp(pConfig->a1 / pConfig->a0); + pBQ->a2.s32 = ma_biquad_float_to_fp(pConfig->a2 / pConfig->a0); + } + + 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; + const ma_uint32 channels = pBQ->channels; + const float b0 = pBQ->b0.f32; + const float b1 = pBQ->b1.f32; + const float b2 = pBQ->b2.f32; + const float a1 = pBQ->a1.f32; + const float a2 = pBQ->a2.f32; + + MA_ASSUME(channels > 0); + for (c = 0; c < channels; c += 1) { + float r1 = pBQ->pR1[c].f32; + float r2 = pBQ->pR2[c].f32; + float x = pX[c]; + float y; + + y = b0*x + r1; + r1 = b1*x - a1*y + r2; + r2 = b2*x - a2*y; + + pY[c] = y; + pBQ->pR1[c].f32 = r1; + pBQ->pR2[c].f32 = r2; + } +} + +static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, const float* pX) +{ + ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX); +} + +static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX) +{ + ma_uint32 c; + const ma_uint32 channels = pBQ->channels; + const ma_int32 b0 = pBQ->b0.s32; + const ma_int32 b1 = pBQ->b1.s32; + const ma_int32 b2 = pBQ->b2.s32; + const ma_int32 a1 = pBQ->a1.s32; + const ma_int32 a2 = pBQ->a2.s32; + + MA_ASSUME(channels > 0); + for (c = 0; c < channels; c += 1) { + ma_int32 r1 = pBQ->pR1[c].s32; + ma_int32 r2 = pBQ->pR2[c].s32; + ma_int32 x = pX[c]; + ma_int32 y; + + y = (b0*x + r1) >> MA_BIQUAD_FIXED_POINT_SHIFT; + 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; + } +} + +static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX) +{ + ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX); +} + +MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint32 n; + + if (pBQ == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */ + + if (pBQ->format == ma_format_f32) { + /* */ float* pY = ( float*)pFramesOut; + const float* pX = (const float*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX); + pY += pBQ->channels; + pX += pBQ->channels; + } + } else if (pBQ->format == ma_format_s16) { + /* */ ma_int16* pY = ( ma_int16*)pFramesOut; + const ma_int16* pX = (const ma_int16*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX); + pY += pBQ->channels; + pX += pBQ->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */ + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ) +{ + if (pBQ == NULL) { + return 0; + } + + return 2; +} + + +/************************************************************************************************************************************************************** + +Low-Pass Filter + +**************************************************************************************************************************************************************/ +MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency) +{ + ma_lpf1_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.q = 0.5; + + return config; +} + +MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q) +{ + ma_lpf2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.q = q; + + /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */ + if (config.q == 0) { + config.q = 0.707107; + } + + return config; +} + + +typedef struct +{ + 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; + } + + pLPF->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset); + + 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; + + if (pLPF == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + pLPF->format = pConfig->format; + pLPF->channels = pConfig->channels; + + a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); + if (pConfig->format == ma_format_f32) { + pLPF->a.f32 = (float)a; + } else { + pLPF->a.s32 = ma_biquad_float_to_fp(a); + } + + 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; + const ma_uint32 channels = pLPF->channels; + const float a = pLPF->a.f32; + const float b = 1 - a; + + MA_ASSUME(channels > 0); + for (c = 0; c < channels; c += 1) { + float r1 = pLPF->pR1[c].f32; + float x = pX[c]; + float y; + + y = b*x + a*r1; + + pY[c] = y; + pLPF->pR1[c].f32 = y; + } +} + +static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX) +{ + ma_uint32 c; + const ma_uint32 channels = pLPF->channels; + const ma_int32 a = pLPF->a.s32; + const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a); + + MA_ASSUME(channels > 0); + for (c = 0; c < channels; c += 1) { + ma_int32 r1 = pLPF->pR1[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; + } +} + +MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint32 n; + + if (pLPF == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */ + + if (pLPF->format == ma_format_f32) { + /* */ float* pY = ( float*)pFramesOut; + const float* pX = (const float*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_lpf1_process_pcm_frame_f32(pLPF, pY, pX); + pY += pLPF->channels; + pX += pLPF->channels; + } + } else if (pLPF->format == ma_format_s16) { + /* */ ma_int16* pY = ( ma_int16*)pFramesOut; + const ma_int16* pX = (const ma_int16*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_lpf1_process_pcm_frame_s16(pLPF, pY, pX); + pY += pLPF->channels; + pX += pLPF->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */ + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF) +{ + if (pLPF == NULL) { + return 0; + } + + return 1; +} + + +static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_config* pConfig) +{ + ma_biquad_config bqConfig; + double q; + double w; + double s; + double c; + double a; + + MA_ASSERT(pConfig != NULL); + + q = pConfig->q; + w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; + s = ma_sind(w); + c = ma_cosd(w); + a = s / (2*q); + + bqConfig.b0 = (1 - c) / 2; + bqConfig.b1 = 1 - c; + bqConfig.b2 = (1 - c) / 2; + bqConfig.a0 = 1 + a; + bqConfig.a1 = -2 * c; + bqConfig.a2 = 1 - a; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pLPF); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_lpf2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pLPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pLPF == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_lpf2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pLPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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); +} + +static MA_INLINE void ma_lpf2_process_pcm_frame_f32(ma_lpf2* pLPF, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pLPF->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pLPF->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF) +{ + if (pLPF == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pLPF->bq); +} + + +MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_lpf_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.order = ma_min(order, MA_MAX_FILTER_ORDER); + + 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) +{ + ma_result result; + ma_uint32 lpf1Count; + ma_uint32 lpf2Count; + 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; + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + if (pConfig->order > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count); + + /* The filter order can't change between reinits. */ + if (!isNew) { + if (pLPF->lpf1Count != lpf1Count || pLPF->lpf2Count != lpf2Count) { + return MA_INVALID_OPERATION; + } + } + + 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]); + } + } else { + result = ma_lpf1_reinit(&lpf1Config, &pLPF->pLPF1[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; + } + } + + for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) { + ma_lpf2_config lpf2Config; + double q; + double a; + + /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */ + if (lpf1Count == 1) { + a = (1 + ilpf2*1) * (MA_PI_D/(pConfig->order*1)); /* Odd order. */ + } else { + a = (1 + ilpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */ + } + q = 1 / (2*ma_cosd(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]); + } + } else { + result = ma_lpf2_reinit(&lpf2Config, &pLPF->pLPF2[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; + } + } + + pLPF->lpf1Count = lpf1Count; + pLPF->lpf2Count = lpf2Count; + pLPF->format = pConfig->format; + pLPF->channels = pConfig->channels; + pLPF->sampleRate = pConfig->sampleRate; + + 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) +{ + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + 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 (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); + } +} + +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; +} + +static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX) +{ + ma_uint32 ilpf1; + ma_uint32 ilpf2; + + MA_ASSERT(pLPF->format == ma_format_f32); + + MA_MOVE_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); + } + + for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { + ma_lpf2_process_pcm_frame_f32(&pLPF->pLPF2[ilpf2], pY, pY); + } +} + +static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, const ma_int16* pX) +{ + ma_uint32 ilpf1; + ma_uint32 ilpf2; + + MA_ASSERT(pLPF->format == ma_format_s16); + + MA_MOVE_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); + } + + for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) { + ma_lpf2_process_pcm_frame_s16(&pLPF->pLPF2[ilpf2], pY, pY); + } +} + +MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_result result; + ma_uint32 ilpf1; + ma_uint32 ilpf2; + + if (pLPF == NULL) { + return MA_INVALID_ARGS; + } + + /* 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); + 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); + if (result != MA_SUCCESS) { + return result; + } + } + } + + /* Slightly slower path for copying. */ + if (pFramesOut != pFramesIn) { + ma_uint32 iFrame; + + /* */ if (pLPF->format == ma_format_f32) { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_lpf_process_pcm_frame_f32(pLPF, pFramesOutF32, pFramesInF32); + pFramesOutF32 += pLPF->channels; + pFramesInF32 += pLPF->channels; + } + } else if (pLPF->format == ma_format_s16) { + /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; + const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_lpf_process_pcm_frame_s16(pLPF, pFramesOutS16, pFramesInS16); + pFramesOutS16 += pLPF->channels; + pFramesInS16 += pLPF->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; /* Should never hit this. */ + } + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF) +{ + if (pLPF == NULL) { + return 0; + } + + return pLPF->lpf2Count*2 + pLPF->lpf1Count; +} + + +/************************************************************************************************************************************************************** + +High-Pass Filtering + +**************************************************************************************************************************************************************/ +MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency) +{ + ma_hpf1_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + + return config; +} + +MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q) +{ + ma_hpf2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.q = q; + + /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */ + if (config.q == 0) { + config.q = 0.707107; + } + + return config; +} + + +typedef struct +{ + size_t sizeInBytes; + size_t r1Offset; +} ma_hpf1_heap_layout; + +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); + + 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_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); + } +} + +MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF) +{ + double a; + + if (pHPF == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + pHPF->format = pConfig->format; + pHPF->channels = pConfig->channels; + + a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate); + if (pConfig->format == ma_format_f32) { + pHPF->a.f32 = (float)a; + } else { + pHPF->a.s32 = ma_biquad_float_to_fp(a); + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX) +{ + ma_uint32 c; + const ma_uint32 channels = pHPF->channels; + const float a = 1 - pHPF->a.f32; + const float b = 1 - a; + + MA_ASSUME(channels > 0); + for (c = 0; c < channels; c += 1) { + float r1 = pHPF->pR1[c].f32; + float x = pX[c]; + float y; + + y = b*x - a*r1; + + pY[c] = y; + pHPF->pR1[c].f32 = y; + } +} + +static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX) +{ + ma_uint32 c; + const ma_uint32 channels = pHPF->channels; + 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); + for (c = 0; c < channels; c += 1) { + ma_int32 r1 = pHPF->pR1[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; + } +} + +MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint32 n; + + if (pHPF == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */ + + if (pHPF->format == ma_format_f32) { + /* */ float* pY = ( float*)pFramesOut; + const float* pX = (const float*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_hpf1_process_pcm_frame_f32(pHPF, pY, pX); + pY += pHPF->channels; + pX += pHPF->channels; + } + } else if (pHPF->format == ma_format_s16) { + /* */ ma_int16* pY = ( ma_int16*)pFramesOut; + const ma_int16* pX = (const ma_int16*)pFramesIn; + + for (n = 0; n < frameCount; n += 1) { + ma_hpf1_process_pcm_frame_s16(pHPF, pY, pX); + pY += pHPF->channels; + pX += pHPF->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */ + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF) +{ + if (pHPF == NULL) { + return 0; + } + + return 1; +} + + +static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_config* pConfig) +{ + ma_biquad_config bqConfig; + double q; + double w; + double s; + double c; + double a; + + MA_ASSERT(pConfig != NULL); + + q = pConfig->q; + w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; + s = ma_sind(w); + c = ma_cosd(w); + a = s / (2*q); + + bqConfig.b0 = (1 + c) / 2; + bqConfig.b1 = -(1 + c); + bqConfig.b2 = (1 + c) / 2; + bqConfig.a0 = 1 + a; + bqConfig.a1 = -2 * c; + bqConfig.a2 = 1 - a; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pHPF == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pHPF); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_hpf2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pHPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pHPF == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_hpf2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pHPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_hpf2_process_pcm_frame_s16(ma_hpf2* pHPF, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pHPF->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_hpf2_process_pcm_frame_f32(ma_hpf2* pHPF, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pHPF->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pHPF == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pHPF->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF) +{ + if (pHPF == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pHPF->bq); +} + + +MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_hpf_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.order = ma_min(order, MA_MAX_FILTER_ORDER); + + 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) +{ + ma_result result; + ma_uint32 hpf1Count; + ma_uint32 hpf2Count; + 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; + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + if (pConfig->order > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count); + + /* The filter order can't change between reinits. */ + if (!isNew) { + if (pHPF->hpf1Count != hpf1Count || pHPF->hpf2Count != hpf2Count) { + return MA_INVALID_OPERATION; + } + } + + 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]); + } + } else { + result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[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; + } + } + + for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) { + ma_hpf2_config hpf2Config; + double q; + double a; + + /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */ + if (hpf1Count == 1) { + a = (1 + ihpf2*1) * (MA_PI_D/(pConfig->order*1)); /* Odd order. */ + } else { + a = (1 + ihpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */ + } + q = 1 / (2*ma_cosd(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]); + } + } else { + result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[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; + } + } + + pHPF->hpf1Count = hpf1Count; + pHPF->hpf2Count = hpf2Count; + pHPF->format = pConfig->format; + pHPF->channels = pConfig->channels; + pHPF->sampleRate = pConfig->sampleRate; + + return MA_SUCCESS; +} + +MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes) +{ + 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; + } + + for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) { + ma_hpf1_uninit(&pHPF->pHPF1[ihpf1], pAllocationCallbacks); + } + + for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { + ma_hpf2_uninit(&pHPF->pHPF2[ihpf2], pAllocationCallbacks); + } + + if (pHPF->_ownsHeap) { + ma_free(pHPF->_pHeap, pAllocationCallbacks); + } +} + +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); +} + +MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_result result; + ma_uint32 ihpf1; + ma_uint32 ihpf2; + + if (pHPF == NULL) { + return MA_INVALID_ARGS; + } + + /* 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); + 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); + if (result != MA_SUCCESS) { + return result; + } + } + } + + /* Slightly slower path for copying. */ + if (pFramesOut != pFramesIn) { + ma_uint32 iFrame; + + /* */ if (pHPF->format == ma_format_f32) { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + 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); + } + + for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { + ma_hpf2_process_pcm_frame_f32(&pHPF->pHPF2[ihpf2], pFramesOutF32, pFramesOutF32); + } + + pFramesOutF32 += pHPF->channels; + pFramesInF32 += pHPF->channels; + } + } else if (pHPF->format == ma_format_s16) { + /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; + const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + 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); + } + + for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) { + ma_hpf2_process_pcm_frame_s16(&pHPF->pHPF2[ihpf2], pFramesOutS16, pFramesOutS16); + } + + pFramesOutS16 += pHPF->channels; + pFramesInS16 += pHPF->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; /* Should never hit this. */ + } + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF) +{ + if (pHPF == NULL) { + return 0; + } + + return pHPF->hpf2Count*2 + pHPF->hpf1Count; +} + + +/************************************************************************************************************************************************************** + +Band-Pass Filtering + +**************************************************************************************************************************************************************/ +MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q) +{ + ma_bpf2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.q = q; + + /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */ + if (config.q == 0) { + config.q = 0.707107; + } + + return config; +} + + +static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_config* pConfig) +{ + ma_biquad_config bqConfig; + double q; + double w; + double s; + double c; + double a; + + MA_ASSERT(pConfig != NULL); + + q = pConfig->q; + w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate; + s = ma_sind(w); + c = ma_cosd(w); + a = s / (2*q); + + bqConfig.b0 = q * a; + bqConfig.b1 = 0; + bqConfig.b2 = -q * a; + bqConfig.a0 = 1 + a; + bqConfig.a1 = -2 * c; + bqConfig.a2 = 1 - a; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pBPF == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pBPF); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_bpf2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pBPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pBPF == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_bpf2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pBPF->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_bpf2_process_pcm_frame_s16(ma_bpf2* pBPF, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pBPF->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_bpf2_process_pcm_frame_f32(ma_bpf2* pBPF, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pBPF->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pBPF == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pBPF->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF) +{ + if (pBPF == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pBPF->bq); +} + + +MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_bpf_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.cutoffFrequency = cutoffFrequency; + config.order = ma_min(order, MA_MAX_FILTER_ORDER); + + 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) +{ + 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; + } + + /* Only supporting f32 and s16. */ + if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) { + return MA_INVALID_ARGS; + } + + /* The format cannot be changed after initialization. */ + if (pBPF->format != ma_format_unknown && pBPF->format != pConfig->format) { + return MA_INVALID_OPERATION; + } + + /* The channel count cannot be changed after initialization. */ + if (pBPF->channels != 0 && pBPF->channels != pConfig->channels) { + return MA_INVALID_OPERATION; + } + + 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; + + /* The filter order can't change between reinits. */ + if (!isNew) { + if (pBPF->bpf2Count != bpf2Count) { + return MA_INVALID_OPERATION; + } + } + + 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; + + /* TODO: Calculate Q to make this a proper Butterworth filter. */ + q = 0.707107; + + 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]); + } + } else { + result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]); + } + + if (result != MA_SUCCESS) { + return result; + } + } + + pBPF->bpf2Count = bpf2Count; + pBPF->format = pConfig->format; + pBPF->channels = pConfig->channels; + + 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) +{ + if (pBPF == NULL) { + return MA_INVALID_ARGS; + } + + 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 (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); + } +} + +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); +} + +MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_result result; + ma_uint32 ibpf2; + + if (pBPF == NULL) { + return MA_INVALID_ARGS; + } + + /* 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); + if (result != MA_SUCCESS) { + return result; + } + } + } + + /* Slightly slower path for copying. */ + if (pFramesOut != pFramesIn) { + ma_uint32 iFrame; + + /* */ if (pBPF->format == ma_format_f32) { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + 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); + } + + pFramesOutF32 += pBPF->channels; + pFramesInF32 += pBPF->channels; + } + } else if (pBPF->format == ma_format_s16) { + /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; + const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + 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); + } + + pFramesOutS16 += pBPF->channels; + pFramesInS16 += pBPF->channels; + } + } else { + MA_ASSERT(MA_FALSE); + return MA_INVALID_OPERATION; /* Should never hit this. */ + } + } + + return MA_SUCCESS; +} + +MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF) +{ + if (pBPF == NULL) { + return 0; + } + + return pBPF->bpf2Count*2; +} + + +/************************************************************************************************************************************************************** + +Notching Filter + +**************************************************************************************************************************************************************/ +MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency) +{ + ma_notch2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.q = q; + config.frequency = frequency; + + if (config.q == 0) { + config.q = 0.707107; + } + + return config; +} + + +static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_config* pConfig) +{ + ma_biquad_config bqConfig; + double q; + double w; + double s; + double c; + double a; + + MA_ASSERT(pConfig != NULL); + + q = pConfig->q; + w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; + s = ma_sind(w); + c = ma_cosd(w); + a = s / (2*q); + + bqConfig.b0 = 1; + bqConfig.b1 = -2 * c; + bqConfig.b2 = 1; + bqConfig.a0 = 1 + a; + bqConfig.a1 = -2 * c; + bqConfig.a2 = 1 - a; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFilter); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_notch2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pFilter == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_notch2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_notch2_process_pcm_frame_s16(ma_notch2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_notch2_process_pcm_frame_f32(ma_notch2* pFilter, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter) +{ + if (pFilter == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pFilter->bq); +} + + + +/************************************************************************************************************************************************************** + +Peaking EQ Filter + +**************************************************************************************************************************************************************/ +MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_peak2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.gainDB = gainDB; + config.q = q; + config.frequency = frequency; + + if (config.q == 0) { + config.q = 0.707107; + } + + return config; +} + + +static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_config* pConfig) +{ + ma_biquad_config bqConfig; + double q; + double w; + double s; + double c; + double a; + double A; + + MA_ASSERT(pConfig != NULL); + + q = pConfig->q; + w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate; + s = ma_sind(w); + c = ma_cosd(w); + a = s / (2*q); + A = ma_powd(10, (pConfig->gainDB / 40)); + + bqConfig.b0 = 1 + (a * A); + bqConfig.b1 = -2 * c; + bqConfig.b2 = 1 - (a * A); + bqConfig.a0 = 1 + (a / A); + bqConfig.a1 = -2 * c; + bqConfig.a2 = 1 - (a / A); + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFilter); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_peak2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pFilter == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_peak2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_peak2_process_pcm_frame_s16(ma_peak2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_peak2_process_pcm_frame_f32(ma_peak2* pFilter, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter) +{ + if (pFilter == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pFilter->bq); +} + + +/************************************************************************************************************************************************************** + +Low Shelf Filter + +**************************************************************************************************************************************************************/ +MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency) +{ + ma_loshelf2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.gainDB = gainDB; + config.shelfSlope = shelfSlope; + config.frequency = frequency; + + return config; +} + + +static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshelf2_config* pConfig) +{ + ma_biquad_config bqConfig; + double w; + double s; + double c; + double A; + double S; + double a; + double sqrtA; + + 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 = pConfig->shelfSlope; + a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2); + sqrtA = 2*ma_sqrtd(A)*a; + + bqConfig.b0 = A * ((A + 1) - (A - 1)*c + sqrtA); + bqConfig.b1 = 2 * A * ((A - 1) - (A + 1)*c); + bqConfig.b2 = A * ((A + 1) - (A - 1)*c - sqrtA); + bqConfig.a0 = (A + 1) + (A - 1)*c + sqrtA; + bqConfig.a1 = -2 * ((A - 1) + (A + 1)*c); + bqConfig.a2 = (A + 1) + (A - 1)*c - sqrtA; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFilter); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_loshelf2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pFilter == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_loshelf2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_loshelf2_process_pcm_frame_s16(ma_loshelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_loshelf2_process_pcm_frame_f32(ma_loshelf2* pFilter, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter) +{ + if (pFilter == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pFilter->bq); +} + + +/************************************************************************************************************************************************************** + +High Shelf Filter + +**************************************************************************************************************************************************************/ +MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency) +{ + ma_hishelf2_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.gainDB = gainDB; + config.shelfSlope = shelfSlope; + config.frequency = frequency; + + return config; +} + + +static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishelf2_config* pConfig) +{ + ma_biquad_config bqConfig; + double w; + double s; + double c; + double A; + double S; + double a; + double sqrtA; + + 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 = pConfig->shelfSlope; + a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2); + sqrtA = 2*ma_sqrtd(A)*a; + + bqConfig.b0 = A * ((A + 1) + (A - 1)*c + sqrtA); + bqConfig.b1 = -2 * A * ((A - 1) + (A + 1)*c); + bqConfig.b2 = A * ((A + 1) + (A - 1)*c - sqrtA); + bqConfig.a0 = (A + 1) - (A - 1)*c + sqrtA; + bqConfig.a1 = 2 * ((A - 1) - (A + 1)*c); + bqConfig.a2 = (A + 1) - (A - 1)*c - sqrtA; + + bqConfig.format = pConfig->format; + bqConfig.channels = pConfig->channels; + + 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_result result; + ma_biquad_config bqConfig; + + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pFilter); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_hishelf2__get_biquad_config(pConfig); + result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + 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; + ma_biquad_config bqConfig; + + if (pFilter == NULL || pConfig == NULL) { + return MA_INVALID_ARGS; + } + + bqConfig = ma_hishelf2__get_biquad_config(pConfig); + result = ma_biquad_reinit(&bqConfig, &pFilter->bq); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn) +{ + ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn); +} + +static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn) +{ + ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn); +} + +MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pFilter == NULL) { + return MA_INVALID_ARGS; + } + + return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount); +} + +MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter) +{ + if (pFilter == NULL) { + return 0; + } + + return ma_biquad_get_latency(&pFilter->bq); +} + + + +/* +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 + +**************************************************************************************************************************************************************/ +MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) +{ + ma_linear_resampler_config config; + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRateIn = sampleRateIn; + config.sampleRateOut = sampleRateOut; + config.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); + config.lpfNyquistFactor = 1; + + 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) +{ + /* + So what's happening here? Basically we need to adjust the fractional component of the time advance based on the new rate. The old time advance will + be based on the old sample rate, but we are needing to adjust it to that it's based on the new sample rate. + */ + ma_uint32 oldRateTimeWhole = pResampler->inTimeFrac / oldSampleRateOut; /* <-- This should almost never be anything other than 0, but leaving it here to make this more general and robust just in case. */ + ma_uint32 oldRateTimeFract = pResampler->inTimeFrac % oldSampleRateOut; + + pResampler->inTimeFrac = + (oldRateTimeWhole * newSampleRateOut) + + ((oldRateTimeFract * newSampleRateOut) / oldSampleRateOut); + + /* Make sure the fractional part is less than the output sample rate. */ + pResampler->inTimeInt += pResampler->inTimeFrac / pResampler->config.sampleRateOut; + 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) +{ + ma_result result; + ma_uint32 gcf; + ma_uint32 lpfSampleRate; + double lpfCutoffFrequency; + ma_lpf_config lpfConfig; + ma_uint32 oldSampleRateOut; /* Required for adjusting time advance down the bottom. */ + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (sampleRateIn == 0 || sampleRateOut == 0) { + return MA_INVALID_ARGS; + } + + oldSampleRateOut = pResampler->config.sampleRateOut; + + pResampler->config.sampleRateIn = sampleRateIn; + pResampler->config.sampleRateOut = sampleRateOut; + + /* Simplify the sample rate. */ + gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut); + pResampler->config.sampleRateIn /= gcf; + pResampler->config.sampleRateOut /= gcf; + + /* Always initialize the low-pass filter, even when the order is 0. */ + if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) { + return MA_INVALID_ARGS; + } + + lpfSampleRate = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut)); + lpfCutoffFrequency = ( double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor); + + 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 + 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); + } + + if (result != MA_SUCCESS) { + return result; + } + + + pResampler->inAdvanceInt = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut; + pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut; + + /* Our timer was based on the old rate. We need to adjust it so that it's based on the new rate. */ + ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->config.sampleRateOut); + + 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_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; + } + + MA_ZERO_OBJECT(pResampler); + + result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + 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); + if (result != MA_SUCCESS) { + return result; + } + + pResampler->inTimeInt = 1; /* Set this to one to force an input sample to always be loaded for the first output frame. */ + pResampler->inTimeFrac = 0; + + 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) +{ + 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) +{ + ma_int32 b; + ma_int32 c; + ma_int32 r; + + MA_ASSERT(a <= (1<> shift); +} + +static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut) +{ + ma_uint32 c; + ma_uint32 a; + const ma_uint32 channels = pResampler->config.channels; + const ma_uint32 shift = 12; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameOut != NULL); + + a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut; + + MA_ASSUME(channels > 0); + 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; + } +} + + +static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* MA_RESTRICT pFrameOut) +{ + ma_uint32 c; + float a; + const ma_uint32 channels = pResampler->config.channels; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameOut != NULL); + + a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut; + + MA_ASSUME(channels > 0); + 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; + } +} + +static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + const ma_int16* pFramesInS16; + /* */ ma_int16* pFramesOutS16; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameCountIn != NULL); + MA_ASSERT(pFrameCountOut != NULL); + + pFramesInS16 = (const ma_int16*)pFramesIn; + pFramesOutS16 = ( ma_int16*)pFramesOut; + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + framesProcessedIn = 0; + framesProcessedOut = 0; + + while (framesProcessedOut < frameCountOut) { + /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */ + while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) { + ma_uint32 iChannel; + + if (pFramesInS16 != NULL) { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel]; + pResampler->x1.s16[iChannel] = pFramesInS16[iChannel]; + } + pFramesInS16 += pResampler->config.channels; + } else { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel]; + pResampler->x1.s16[iChannel] = 0; + } + } + + /* 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); + } + + framesProcessedIn += 1; + pResampler->inTimeInt -= 1; + } + + if (pResampler->inTimeInt > 0) { + break; /* Ran out of input data. */ + } + + /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */ + if (pFramesOutS16 != NULL) { + MA_ASSERT(pResampler->inTimeInt == 0); + ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16); + + pFramesOutS16 += pResampler->config.channels; + } + + framesProcessedOut += 1; + + /* Advance time forward. */ + pResampler->inTimeInt += pResampler->inAdvanceInt; + pResampler->inTimeFrac += pResampler->inAdvanceFrac; + if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) { + pResampler->inTimeFrac -= pResampler->config.sampleRateOut; + pResampler->inTimeInt += 1; + } + } + + *pFrameCountIn = framesProcessedIn; + *pFrameCountOut = framesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + const ma_int16* pFramesInS16; + /* */ ma_int16* pFramesOutS16; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameCountIn != NULL); + MA_ASSERT(pFrameCountOut != NULL); + + pFramesInS16 = (const ma_int16*)pFramesIn; + pFramesOutS16 = ( ma_int16*)pFramesOut; + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + framesProcessedIn = 0; + framesProcessedOut = 0; + + while (framesProcessedOut < frameCountOut) { + /* Before interpolating we need to load the buffers. */ + while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) { + ma_uint32 iChannel; + + if (pFramesInS16 != NULL) { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel]; + pResampler->x1.s16[iChannel] = pFramesInS16[iChannel]; + } + pFramesInS16 += pResampler->config.channels; + } else { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel]; + pResampler->x1.s16[iChannel] = 0; + } + } + + framesProcessedIn += 1; + pResampler->inTimeInt -= 1; + } + + if (pResampler->inTimeInt > 0) { + break; /* Ran out of input data. */ + } + + /* Getting here means the frames have been loaded and we can generate the next output frame. */ + if (pFramesOutS16 != NULL) { + 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); + } + + pFramesOutS16 += pResampler->config.channels; + } + + framesProcessedOut += 1; + + /* Advance time forward. */ + pResampler->inTimeInt += pResampler->inAdvanceInt; + pResampler->inTimeFrac += pResampler->inAdvanceFrac; + if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) { + pResampler->inTimeFrac -= pResampler->config.sampleRateOut; + pResampler->inTimeInt += 1; + } + } + + *pFrameCountIn = framesProcessedIn; + *pFrameCountOut = framesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_linear_resampler_process_pcm_frames_s16(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pResampler != NULL); + + if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) { + return ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + return ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } +} + + +static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + const float* pFramesInF32; + /* */ float* pFramesOutF32; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameCountIn != NULL); + MA_ASSERT(pFrameCountOut != NULL); + + pFramesInF32 = (const float*)pFramesIn; + pFramesOutF32 = ( float*)pFramesOut; + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + framesProcessedIn = 0; + framesProcessedOut = 0; + + while (framesProcessedOut < frameCountOut) { + /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */ + while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) { + ma_uint32 iChannel; + + if (pFramesInF32 != NULL) { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel]; + pResampler->x1.f32[iChannel] = pFramesInF32[iChannel]; + } + pFramesInF32 += pResampler->config.channels; + } else { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel]; + pResampler->x1.f32[iChannel] = 0; + } + } + + /* 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); + } + + framesProcessedIn += 1; + pResampler->inTimeInt -= 1; + } + + if (pResampler->inTimeInt > 0) { + break; /* Ran out of input data. */ + } + + /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */ + if (pFramesOutF32 != NULL) { + MA_ASSERT(pResampler->inTimeInt == 0); + ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32); + + pFramesOutF32 += pResampler->config.channels; + } + + framesProcessedOut += 1; + + /* Advance time forward. */ + pResampler->inTimeInt += pResampler->inAdvanceInt; + pResampler->inTimeFrac += pResampler->inAdvanceFrac; + if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) { + pResampler->inTimeFrac -= pResampler->config.sampleRateOut; + pResampler->inTimeInt += 1; + } + } + + *pFrameCountIn = framesProcessedIn; + *pFrameCountOut = framesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + const float* pFramesInF32; + /* */ float* pFramesOutF32; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + MA_ASSERT(pResampler != NULL); + MA_ASSERT(pFrameCountIn != NULL); + MA_ASSERT(pFrameCountOut != NULL); + + pFramesInF32 = (const float*)pFramesIn; + pFramesOutF32 = ( float*)pFramesOut; + frameCountIn = *pFrameCountIn; + frameCountOut = *pFrameCountOut; + framesProcessedIn = 0; + framesProcessedOut = 0; + + while (framesProcessedOut < frameCountOut) { + /* Before interpolating we need to load the buffers. */ + while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) { + ma_uint32 iChannel; + + if (pFramesInF32 != NULL) { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel]; + pResampler->x1.f32[iChannel] = pFramesInF32[iChannel]; + } + pFramesInF32 += pResampler->config.channels; + } else { + for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) { + pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel]; + pResampler->x1.f32[iChannel] = 0; + } + } + + framesProcessedIn += 1; + pResampler->inTimeInt -= 1; + } + + if (pResampler->inTimeInt > 0) { + break; /* Ran out of input data. */ + } + + /* Getting here means the frames have been loaded and we can generate the next output frame. */ + if (pFramesOutF32 != NULL) { + 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); + } + + pFramesOutF32 += pResampler->config.channels; + } + + framesProcessedOut += 1; + + /* Advance time forward. */ + pResampler->inTimeInt += pResampler->inAdvanceInt; + pResampler->inTimeFrac += pResampler->inAdvanceFrac; + if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) { + pResampler->inTimeFrac -= pResampler->config.sampleRateOut; + pResampler->inTimeInt += 1; + } + } + + *pFrameCountIn = framesProcessedIn; + *pFrameCountOut = framesProcessedOut; + + return MA_SUCCESS; +} + +static ma_result ma_linear_resampler_process_pcm_frames_f32(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pResampler != NULL); + + if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) { + return ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + return ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } +} + + +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) +{ + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + /* */ if (pResampler->config.format == ma_format_s16) { + return ma_linear_resampler_process_pcm_frames_s16(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else if (pResampler->config.format == ma_format_f32) { + return ma_linear_resampler_process_pcm_frames_f32(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* Should never get here. Getting here means the format is not supported and you didn't check the return value of ma_linear_resampler_init(). */ + MA_ASSERT(MA_FALSE); + return MA_INVALID_ARGS; + } +} + + +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); +} + +MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut) +{ + ma_uint32 n; + ma_uint32 d; + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + if (ratioInOut <= 0) { + return MA_INVALID_ARGS; + } + + d = 1000000; + n = (ma_uint32)(ratioInOut * d); + + if (n == 0) { + return MA_INVALID_ARGS; /* Ratio too small. */ + } + + MA_ASSERT(n != 0); + + return ma_linear_resampler_set_rate(pResampler, n, d); +} + +MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler) +{ + if (pResampler == NULL) { + return 0; + } + + return 1 + ma_lpf_get_latency(&pResampler->lpf); +} + +MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler) +{ + if (pResampler == NULL) { + return 0; + } + + 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; + } + + *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 +}; + + + +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) +{ + ma_resampler_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRateIn = sampleRateIn; + config.sampleRateOut = sampleRateOut; + config.algorithm = algorithm; + + /* Linear. */ + config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER); + + 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_result result; + + if (pResampler == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pResampler); + + if (pConfig == NULL) { + 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 (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onInit == NULL) { + return MA_NOT_IMPLEMENTED; /* onInit not implemented. */ + } + + result = pResampler->pBackendVTable->onInit(pResampler->pBackendUserData, pConfig, pHeap, &pResampler->pBackend); + if (result != MA_SUCCESS) { + return result; + } + + 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) +{ + if (pResampler == NULL) { + return; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onUninit == NULL) { + return; + } + + pResampler->pBackendVTable->onUninit(pResampler->pBackendUserData, pResampler->pBackend, pAllocationCallbacks); + + if (pResampler->_ownsHeap) { + ma_free(pResampler->_pHeap, pAllocationCallbacks); + } +} + +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) { + return MA_INVALID_ARGS; + } + + if (pFrameCountOut == NULL && pFrameCountIn == NULL) { + return MA_INVALID_ARGS; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onProcess == NULL) { + return MA_NOT_IMPLEMENTED; + } + + 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; + } + + if (sampleRateIn == 0 || sampleRateOut == 0) { + return MA_INVALID_ARGS; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onSetRate == NULL) { + return MA_NOT_IMPLEMENTED; + } + + 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; +} + +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; + } + + 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_input_latency(const ma_resampler* pResampler) +{ + if (pResampler == NULL) { + return 0; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetInputLatency == NULL) { + return 0; + } + + return pResampler->pBackendVTable->onGetInputLatency(pResampler->pBackendUserData, pResampler->pBackend); +} + +MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler) +{ + if (pResampler == NULL) { + return 0; + } + + if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetOutputLatency == NULL) { + return 0; + } + + 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); +} + +/************************************************************************************************************************************************************** + +Channel Conversion + +**************************************************************************************************************************************************************/ +#ifndef MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT +#define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT 12 +#endif + +#define MA_PLANE_LEFT 0 +#define MA_PLANE_RIGHT 1 +#define MA_PLANE_FRONT 2 +#define MA_PLANE_BACK 3 +#define MA_PLANE_BOTTOM 4 +#define MA_PLANE_TOP 5 + +static float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6] = { + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_NONE */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_MONO */ + { 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT */ + { 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT */ + { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_CENTER */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_LFE */ + { 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_LEFT */ + { 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_RIGHT */ + { 0.25f, 0.0f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT_CENTER */ + { 0.0f, 0.25f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT_CENTER */ + { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_CENTER */ + { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_LEFT */ + { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_RIGHT */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, /* MA_CHANNEL_TOP_CENTER */ + { 0.33f, 0.0f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_LEFT */ + { 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_FRONT_CENTER */ + { 0.0f, 0.33f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_RIGHT */ + { 0.33f, 0.0f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_LEFT */ + { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_BACK_CENTER */ + { 0.0f, 0.33f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_RIGHT */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_0 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_1 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_2 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_3 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_4 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_5 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_6 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_7 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_8 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_9 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_10 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_11 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_12 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_13 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_14 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_15 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_16 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_17 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_18 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_19 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_20 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_21 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_22 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_23 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_24 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_25 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_26 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_27 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_28 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_29 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_30 */ + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_31 */ +}; + +static float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA, ma_channel channelPositionB) +{ + /* + Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to + the following output configuration: + + - front/left + - side/left + - back/left + + The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount + 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 + 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 + - 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 + + 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 + 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. + */ + + /* Contribution = Sum(Volume to Give * Volume to Take) */ + float contribution = + g_maChannelPlaneRatios[channelPositionA][0] * g_maChannelPlaneRatios[channelPositionB][0] + + g_maChannelPlaneRatios[channelPositionA][1] * g_maChannelPlaneRatios[channelPositionB][1] + + g_maChannelPlaneRatios[channelPositionA][2] * g_maChannelPlaneRatios[channelPositionB][2] + + g_maChannelPlaneRatios[channelPositionA][3] * g_maChannelPlaneRatios[channelPositionB][3] + + g_maChannelPlaneRatios[channelPositionA][4] * g_maChannelPlaneRatios[channelPositionB][4] + + g_maChannelPlaneRatios[channelPositionA][5] * g_maChannelPlaneRatios[channelPositionB][5]; + + return contribution; +} + +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) +{ + ma_channel_converter_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; + config.pChannelMapIn = pChannelMapIn; + config.pChannelMapOut = pChannelMapOut; + config.mixingMode = mixingMode; + + return config; +} + +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; + + if (channelPosition == MA_CHANNEL_NONE || channelPosition == MA_CHANNEL_MONO || channelPosition == MA_CHANNEL_LFE) { + 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; + } + } + + 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_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; + } + + pConverter->_pHeap = pHeap; + MA_ZERO_MEMORY(pConverter->_pHeap, heapLayout.sizeInBytes); + + pConverter->format = pConfig->format; + pConverter->channelsIn = pConfig->channelsIn; + pConverter->channelsOut = 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))); + } + } + + /* 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; + } + } + } + + /* + 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. */ + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) { + ma_channel channelPosIn = ma_channel_map_get_channel(pConverter->pChannelMapIn, pConverter->channelsIn, iChannelIn); + + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_channel channelPosOut = ma_channel_map_get_channel(pConverter->pChannelMapOut, pConverter->channelsOut, iChannelOut); + + if (channelPosIn == channelPosOut) { + float weight = 1; + + 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); + } + } + } + } + + switch (pConverter->mixingMode) + { + 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. */ + } + + for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) { + float weight = pConfig->ppWeights[iChannelIn][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; + + 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; + } + } 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); + + 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(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; + } + } else { + if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) { + pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight); + } + } + } + } + } + } + } + + /* 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); + } + } + } + } + } + } + } + } 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) +{ + 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) +{ + MA_ASSERT(pConverter != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pFramesIn != NULL); + + ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut)); + 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) +{ + 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); +} + +static ma_result ma_channel_converter_process_pcm_frames__mono_in(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + + MA_ASSERT(pConverter != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pFramesIn != NULL); + MA_ASSERT(pConverter->channelsIn == 1); + + 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) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) { + pFramesOutU8[iFrame*pConverter->channelsOut + iChannel] = pFramesInU8[iFrame]; + } + } + } break; + + case ma_format_s16: + { + /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut; + const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn; + + if (pConverter->channelsOut == 2) { + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + pFramesOutS16[iFrame*2 + 0] = pFramesInS16[iFrame]; + pFramesOutS16[iFrame*2 + 1] = pFramesInS16[iFrame]; + } + } else { + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) { + pFramesOutS16[iFrame*pConverter->channelsOut + iChannel] = pFramesInS16[iFrame]; + } + } + } + } 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) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) { + ma_uint64 iSampleOut = iFrame*pConverter->channelsOut + iChannel; + ma_uint64 iSampleIn = iFrame; + pFramesOutS24[iSampleOut*3 + 0] = pFramesInS24[iSampleIn*3 + 0]; + pFramesOutS24[iSampleOut*3 + 1] = pFramesInS24[iSampleIn*3 + 1]; + pFramesOutS24[iSampleOut*3 + 2] = pFramesInS24[iSampleIn*3 + 2]; + } + } + } 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) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) { + pFramesOutS32[iFrame*pConverter->channelsOut + iChannel] = pFramesInS32[iFrame]; + } + } + } break; + + case ma_format_f32: + { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + if (pConverter->channelsOut == 2) { + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + pFramesOutF32[iFrame*2 + 0] = pFramesInF32[iFrame]; + pFramesOutF32[iFrame*2 + 1] = pFramesInF32[iFrame]; + } + } else { + for (iFrame = 0; iFrame < frameCount; ++iFrame) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) { + pFramesOutF32[iFrame*pConverter->channelsOut + iChannel] = pFramesInF32[iFrame]; + } + } + } + } break; + + default: return MA_INVALID_OPERATION; /* Unknown format. */ + } + + 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) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + + MA_ASSERT(pConverter != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pFramesIn != NULL); + MA_ASSERT(pConverter->channelsOut == 1); + + 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) { + 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); + } + } 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) { + 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); + } + } 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) { + 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]); + } + } 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) { + 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); + } + } break; + + case ma_format_f32: + { + /* */ float* pFramesOutF32 = ( float*)pFramesOut; + 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; + } + } break; + + default: return MA_INVALID_OPERATION; /* Unknown format. */ + } + + return MA_SUCCESS; +} + +static ma_result ma_channel_converter_process_pcm_frames__weights(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + ma_uint32 iFrame; + ma_uint32 iChannelIn; + ma_uint32 iChannelOut; + + MA_ASSERT(pConverter != NULL); + MA_ASSERT(pFramesOut != NULL); + MA_ASSERT(pFramesIn != NULL); + + /* This is the more complicated case. Each of the output channels is accumulated with 0 or more input channels. */ + + /* Clear. */ + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut)); + + /* Accumulate. */ + 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) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_int16 u8_O = ma_pcm_sample_u8_to_s16_no_scale(pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut]); + ma_int16 u8_I = ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8 [iFrame*pConverter->channelsIn + iChannelIn ]); + ma_int32 s = (ma_int32)ma_clamp(u8_O + ((u8_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -128, 127); + pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_u8((ma_int16)s); + } + } + } + } 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) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_int32 s = pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut]; + s += (pFramesInS16[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT; + + pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut] = (ma_int16)ma_clamp(s, -32768, 32767); + } + } + } + } 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) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_int64 s24_O = ma_pcm_sample_s24_to_s32_no_scale(&pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*3]); + ma_int64 s24_I = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24 [(iFrame*pConverter->channelsIn + iChannelIn )*3]); + ma_int64 s24 = (ma_int32)ma_clamp(s24_O + ((s24_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -8388608, 8388607); + ma_pcm_sample_s32_to_s24_no_scale(s24, &pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*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) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + ma_int64 s = pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut]; + s += ((ma_int64)pFramesInS32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT; + + pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_s32(s); + } + } + } + } 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) { + for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) { + pFramesOutF32[iFrame*pConverter->channelsOut + iChannelOut] += pFramesInF32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.f32[iChannelIn][iChannelOut]; + } + } + } + } break; + + default: return MA_INVALID_OPERATION; /* Unknown format. */ + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount) +{ + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + if (pFramesOut == NULL) { + return MA_INVALID_ARGS; + } + + if (pFramesIn == NULL) { + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut)); + 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); + } + } +} + +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_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. */ + + /* Linear resampling defaults. */ + config.resampling.linear.lpfOrder = 1; + + return config; +} + +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) +{ + ma_data_converter_config config = ma_data_converter_config_init_default(); + config.formatIn = formatIn; + config.formatOut = formatOut; + config.channelsIn = channelsIn; + config.channelsOut = channelsOut; + 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_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; + } + + MA_ZERO_OBJECT(pConverter); + + result = ma_data_converter_get_heap_layout(pConfig, &heapLayout); + if (result != MA_SUCCESS) { + return result; + } + + pConverter->_pHeap = pHeap; + MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes); + + 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; + + /* + 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. + */ + isResamplingRequired = ma_data_converter_config_is_resampler_required(pConfig); + midFormat = ma_data_converter_config_get_mid_format(pConfig); + + + /* 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); + + result = ma_channel_converter_init_preallocated(&channelConverterConfig, ma_offset_ptr(pHeap, heapLayout.channelConverterOffset), &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) { + pConverter->hasChannelConverter = MA_TRUE; + } + } + + + /* Resampler. */ + if (isResamplingRequired) { + ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig); + + result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pConverter->resampler); + if (result != MA_SUCCESS) { + return result; + } + + pConverter->hasResampler = MA_TRUE; + } + + + /* 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) { + /* The formats are the same so we can just pass through. */ + pConverter->hasPreFormatConversion = MA_FALSE; + pConverter->hasPostFormatConversion = MA_FALSE; + } else { + /* The formats are different so we need to do either pre- or post-format conversion. It doesn't matter which. */ + pConverter->hasPreFormatConversion = MA_FALSE; + pConverter->hasPostFormatConversion = MA_TRUE; + } + } 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->formatOut != midFormat) { + pConverter->hasPostFormatConversion = MA_TRUE; + } + } + + /* We can enable passthrough optimizations if applicable. Note that we'll only be able to do this if the sample rate is static. */ + if (pConverter->hasPreFormatConversion == MA_FALSE && + pConverter->hasPostFormatConversion == MA_FALSE && + pConverter->hasChannelConverter == MA_FALSE && + pConverter->hasResampler == MA_FALSE) { + 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) +{ + 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); + } +} + +static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 frameCount; + + MA_ASSERT(pConverter != NULL); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + frameCount = ma_min(frameCountIn, frameCountOut); + + if (pFramesOut != NULL) { + if (pFramesIn != NULL) { + ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } else { + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = frameCount; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = frameCount; + } + + return MA_SUCCESS; +} + +static ma_result ma_data_converter_process_pcm_frames__format_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 frameCount; + + MA_ASSERT(pConverter != NULL); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + frameCount = ma_min(frameCountIn, frameCountOut); + + if (pFramesOut != NULL) { + if (pFramesIn != NULL) { + ma_convert_pcm_frames_format(pFramesOut, pConverter->formatOut, pFramesIn, pConverter->formatIn, frameCount, pConverter->channelsIn, pConverter->ditherMode); + } else { + ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = frameCount; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = frameCount; + } + + return MA_SUCCESS; +} + + +static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conversion(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_result result = MA_SUCCESS; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + + MA_ASSERT(pConverter != NULL); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + framesProcessedIn = 0; + framesProcessedOut = 0; + + 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 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)); + } else { + pFramesInThisIteration = NULL; + } + + if (pFramesOut != NULL) { + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } else { + pFramesOutThisIteration = NULL; + } + + /* 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); + + frameCountInThisIteration = (frameCountIn - framesProcessedIn); + if (frameCountInThisIteration > tempBufferInCap) { + frameCountInThisIteration = tempBufferInCap; + } + + if (pConverter->hasPostFormatConversion) { + if (frameCountInThisIteration > tempBufferOutCap) { + frameCountInThisIteration = tempBufferOutCap; + } + } + + if (pFramesInThisIteration != NULL) { + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pFramesInThisIteration, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode); + } else { + MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); + } + + frameCountOutThisIteration = (frameCountOut - framesProcessedOut); + + if (pConverter->hasPostFormatConversion) { + /* Both input and output conversion required. Output to the temp buffer. */ + if (frameCountOutThisIteration > tempBufferOutCap) { + frameCountOutThisIteration = tempBufferOutCap; + } + + result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration); + } else { + /* Only pre-format required. Output straight to the output buffer. */ + result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pFramesOutThisIteration, &frameCountOutThisIteration); + } + + if (result != MA_SUCCESS) { + break; + } + } else { + /* No pre-format required. Just read straight from the input buffer. */ + MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE); + + frameCountInThisIteration = (frameCountIn - framesProcessedIn); + frameCountOutThisIteration = (frameCountOut - framesProcessedOut); + if (frameCountOutThisIteration > tempBufferOutCap) { + frameCountOutThisIteration = tempBufferOutCap; + } + + result = ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesInThisIteration, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration); + if (result != MA_SUCCESS) { + break; + } + } + + /* 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); + } + } + + framesProcessedIn += frameCountInThisIteration; + framesProcessedOut += frameCountOutThisIteration; + + MA_ASSERT(framesProcessedIn <= frameCountIn); + MA_ASSERT(framesProcessedOut <= frameCountOut); + + if (frameCountOutThisIteration == 0) { + break; /* Consumed all of our input data. */ + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = framesProcessedIn; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = framesProcessedOut; + } + + return result; +} + +static ma_result ma_data_converter_process_pcm_frames__resample_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + MA_ASSERT(pConverter != NULL); + + if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) { + /* Neither pre- nor post-format required. This is simple case where only resampling is required. */ + return ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } else { + /* Format conversion required. */ + return ma_data_converter_process_pcm_frames__resample_with_format_conversion(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut); + } +} + +static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_result result; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 frameCount; + + MA_ASSERT(pConverter != NULL); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + frameCount = ma_min(frameCountIn, frameCountOut); + + if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) { + /* No format conversion required. */ + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOut, pFramesIn, frameCount); + if (result != MA_SUCCESS) { + return result; + } + } else { + /* Format conversion required. */ + ma_uint64 framesProcessed = 0; + + while (framesProcessed < frameCount) { + ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; + const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); + const void* pFramesInThisIteration; + /* */ void* pFramesOutThisIteration; + ma_uint64 frameCountThisIteration; + + if (pFramesIn != NULL) { + pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + } else { + pFramesInThisIteration = NULL; + } + + if (pFramesOut != NULL) { + pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } else { + pFramesOutThisIteration = NULL; + } + + /* 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->channelConverter.format, pConverter->channelConverter.channelsIn); + + frameCountThisIteration = (frameCount - framesProcessed); + if (frameCountThisIteration > tempBufferInCap) { + frameCountThisIteration = tempBufferInCap; + } + + if (pConverter->hasPostFormatConversion) { + if (frameCountThisIteration > tempBufferOutCap) { + frameCountThisIteration = tempBufferOutCap; + } + } + + if (pFramesInThisIteration != NULL) { + ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->formatIn, frameCountThisIteration, pConverter->channelsIn, pConverter->ditherMode); + } else { + MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn)); + } + + if (pConverter->hasPostFormatConversion) { + /* Both input and output conversion required. Output to the temp buffer. */ + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pTempBufferIn, frameCountThisIteration); + } else { + /* Only pre-format required. Output straight to the output buffer. */ + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOutThisIteration, pTempBufferIn, frameCountThisIteration); + } + + if (result != MA_SUCCESS) { + break; + } + } else { + /* No pre-format required. Just read straight from the input buffer. */ + MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE); + + frameCountThisIteration = (frameCount - framesProcessed); + if (frameCountThisIteration > tempBufferOutCap) { + frameCountThisIteration = tempBufferOutCap; + } + + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pFramesInThisIteration, frameCountThisIteration); + if (result != MA_SUCCESS) { + break; + } + } + + /* 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); + } + } + + framesProcessed += frameCountThisIteration; + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = frameCount; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = frameCount; + } + + 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) +{ + ma_result result; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format. */ + ma_uint64 tempBufferInCap; + ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format, channel converter input format. */ + ma_uint64 tempBufferMidCap; + ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In channel converter output format. */ + 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); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + 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); + tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut); + + while (framesProcessedOut < frameCountOut) { + ma_uint64 frameCountInThisIteration; + ma_uint64 frameCountOutThisIteration; + const void* pRunningFramesIn = NULL; + void* pRunningFramesOut = NULL; + const void* pResampleBufferIn; + void* pChannelsBufferOut; + + if (pFramesIn != NULL) { + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + } + if (pFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut)); + } + + /* Run input data through the resampler and output it to the temporary buffer. */ + frameCountInThisIteration = (frameCountIn - framesProcessedIn); + + if (pConverter->hasPreFormatConversion) { + if (frameCountInThisIteration > tempBufferInCap) { + frameCountInThisIteration = tempBufferInCap; + } + } + + frameCountOutThisIteration = (frameCountOut - framesProcessedOut); + if (frameCountOutThisIteration > tempBufferMidCap) { + frameCountOutThisIteration = tempBufferMidCap; + } + + /* We can't read more frames than can fit in the output buffer. */ + if (pConverter->hasPostFormatConversion) { + if (frameCountOutThisIteration > tempBufferOutCap) { + frameCountOutThisIteration = tempBufferOutCap; + } + } + + /* 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; + } + + 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); + pResampleBufferIn = pTempBufferIn; + } else { + pResampleBufferIn = NULL; + } + } else { + pResampleBufferIn = pRunningFramesIn; + } + + result = ma_resampler_process_pcm_frames(&pConverter->resampler, pResampleBufferIn, &frameCountInThisIteration, pTempBufferMid, &frameCountOutThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + + /* + The input data has been resampled so now we need to run it through the channel converter. The input data is always contained in pTempBufferMid. We only need to do + this part if we have an output buffer. + */ + if (pFramesOut != NULL) { + if (pConverter->hasPostFormatConversion) { + pChannelsBufferOut = pTempBufferOut; + } else { + pChannelsBufferOut = pRunningFramesOut; + } + + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pChannelsBufferOut, pTempBufferMid, frameCountOutThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + /* 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); + } + } + + + framesProcessedIn += frameCountInThisIteration; + framesProcessedOut += frameCountOutThisIteration; + + MA_ASSERT(framesProcessedIn <= frameCountIn); + MA_ASSERT(framesProcessedOut <= frameCountOut); + + if (frameCountOutThisIteration == 0) { + break; /* Consumed all of our input data. */ + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = framesProcessedIn; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = framesProcessedOut; + } + + return MA_SUCCESS; +} + +static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut) +{ + ma_result result; + ma_uint64 frameCountIn; + ma_uint64 frameCountOut; + ma_uint64 framesProcessedIn; + ma_uint64 framesProcessedOut; + ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format. */ + ma_uint64 tempBufferInCap; + ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format, channel converter input format. */ + ma_uint64 tempBufferMidCap; + ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In channel converter output format. */ + 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); + + frameCountIn = 0; + if (pFrameCountIn != NULL) { + frameCountIn = *pFrameCountIn; + } + + frameCountOut = 0; + if (pFrameCountOut != NULL) { + frameCountOut = *pFrameCountOut; + } + + framesProcessedIn = 0; + framesProcessedOut = 0; + + 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); + + while (framesProcessedOut < frameCountOut) { + ma_uint64 frameCountInThisIteration; + ma_uint64 frameCountOutThisIteration; + const void* pRunningFramesIn = NULL; + void* pRunningFramesOut = NULL; + const void* pChannelsBufferIn; + void* pResampleBufferOut; + + if (pFramesIn != NULL) { + pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn)); + } + if (pFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->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. */ + 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); + pChannelsBufferIn = pTempBufferIn; + } else { + pChannelsBufferIn = NULL; + } + } else { + pChannelsBufferIn = pRunningFramesIn; + } + + + /* Channel conversion. */ + result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + + /* Resampling. */ + if (pConverter->hasPostFormatConversion) { + pResampleBufferOut = pTempBufferOut; + } else { + pResampleBufferOut = pRunningFramesOut; + } + + result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferMid, &frameCountInThisIteration, pResampleBufferOut, &frameCountOutThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + + /* 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); + } + } + + + framesProcessedIn += frameCountInThisIteration; + framesProcessedOut += frameCountOutThisIteration; + + MA_ASSERT(framesProcessedIn <= frameCountIn); + MA_ASSERT(framesProcessedOut <= frameCountOut); + + if (frameCountOutThisIteration == 0) { + break; /* Consumed all of our input data. */ + } + } + + if (pFrameCountIn != NULL) { + *pFrameCountIn = framesProcessedIn; + } + if (pFrameCountOut != NULL) { + *pFrameCountOut = framesProcessedOut; + } + + return MA_SUCCESS; +} + +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) +{ + if (pConverter == NULL) { + 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. */ + } +} + +MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut) +{ + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasResampler == MA_FALSE) { + return MA_INVALID_OPERATION; /* Dynamic resampling not enabled. */ + } + + return ma_resampler_set_rate(&pConverter->resampler, sampleRateIn, sampleRateOut); +} + +MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut) +{ + if (pConverter == NULL) { + return MA_INVALID_ARGS; + } + + if (pConverter->hasResampler == MA_FALSE) { + return MA_INVALID_OPERATION; /* Dynamic resampling not enabled. */ + } + + return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut); +} + +MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter) +{ + if (pConverter == NULL) { + return 0; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_input_latency(&pConverter->resampler); + } + + return 0; /* No latency without a resampler. */ +} + +MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter) +{ + if (pConverter == NULL) { + return 0; + } + + if (pConverter->hasResampler) { + return ma_resampler_get_output_latency(&pConverter->resampler); + } + + 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); +} + + + +/************************************************************************************************************************************************************** + +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) +{ + if (pChannelMap == NULL) { + return; + } + + MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels); +} + + +static ma_channel ma_channel_map_init_standard_channel_microsoft(ma_uint32 channelCount, ma_uint32 channelIndex) +{ + 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) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: /* No 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; + } + } 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 + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 6) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } 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; + } + } break; + } + + if (channelCount > 8) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8)); + } + } + + /* 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) +{ + switch (channelCount) + { + case 0: return MA_CHANNEL_NONE; + + case 1: + { + return MA_CHANNEL_MONO; + } break; + + case 2: + { + switch (channelIndex) { + case 0: return MA_CHANNEL_FRONT_LEFT; + case 1: return MA_CHANNEL_FRONT_RIGHT; + } + } break; + + case 3: /* No 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; + } + } 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; + } + } 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_BACK_LEFT; + case 3: return MA_CHANNEL_BACK_RIGHT; + case 4: return 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; + } + } break; + } + + if (channelCount > 6) { + if (channelIndex < 32) { /* We have 32 AUX channels. */ + return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6)); + } + } + + /* 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) +{ + 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); + } break; + + case ma_standard_channel_map_rfc3551: + { + return ma_channel_map_init_standard_channel_rfc3551(channelCount, channelIndex); + } break; + + case ma_standard_channel_map_flac: + { + return ma_channel_map_init_standard_channel_flac(channelCount, channelIndex); + } break; + + case ma_standard_channel_map_vorbis: + { + return ma_channel_map_init_standard_channel_vorbis(channelCount, channelIndex); + } break; + + case ma_standard_channel_map_sound4: + { + return ma_channel_map_init_standard_channel_sound4(channelCount, channelIndex); + } break; + + case ma_standard_channel_map_sndio: + { + return ma_channel_map_init_standard_channel_sndio(channelCount, channelIndex); + } 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); + } 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) { + MA_COPY_MEMORY(pOut, pIn, sizeof(*pOut) * channels); + } +} + +MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels) +{ + if (pOut == NULL || channels == 0) { + return; + } + + 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_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels) +{ + /* A channel count of 0 is invalid. */ + if (channels == 0) { + return MA_FALSE; + } + + /* It does not make sense to have a mono channel when there is more than 1 channel. */ + if (channels > 1) { + ma_uint32 iChannel; + for (iChannel = 0; iChannel < channels; ++iChannel) { + if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == MA_CHANNEL_MONO) { + return MA_FALSE; + } + } + } + + return MA_TRUE; +} + +MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels) +{ + ma_uint32 iChannel; + + if (pChannelMapA == pChannelMapB) { + return MA_TRUE; + } + + for (iChannel = 0; iChannel < channels; ++iChannel) { + if (ma_channel_map_get_channel(pChannelMapA, channels, iChannel) != ma_channel_map_get_channel(pChannelMapB, channels, iChannel)) { + return MA_FALSE; + } + } + + return MA_TRUE; +} + +MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels) +{ + 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; + } + } + + return MA_TRUE; +} + +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; + } + + 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"; +} + + + +/************************************************************************************************************************************************************** + +Conversion Helpers + +**************************************************************************************************************************************************************/ +MA_API ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn) +{ + ma_data_converter_config config; + + config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut); + 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); +} + +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) +{ + ma_result result; + ma_data_converter converter; + + if (frameCountIn == 0 || pConfig == NULL) { + return 0; + } + + result = ma_data_converter_init(pConfig, NULL, &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; + } + } + } + } else { + result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut); + if (result != MA_SUCCESS) { + frameCountOut = 0; + } + } + + ma_data_converter_uninit(&converter, NULL); + return frameCountOut; +} + + +/************************************************************************************************************************************************************** + +Ring Buffer + +**************************************************************************************************************************************************************/ +static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset) +{ + return encodedOffset & 0x7FFFFFFF; +} + +static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset) +{ + return encodedOffset & 0x80000000; +} + +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))); +} + +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))); +} + +static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag) +{ + return offsetLoopFlag | offsetInBytes; +} + +static MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag) +{ + MA_ASSERT(pOffsetInBytes != NULL); + MA_ASSERT(pOffsetLoopFlag != NULL); + + *pOffsetInBytes = ma_rb__extract_offset_in_bytes(encodedOffset); + *pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset); +} + + +MA_API ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB) +{ + ma_result result; + const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1); + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + if (subbufferSizeInBytes == 0 || subbufferCount == 0) { + return MA_INVALID_ARGS; + } + + if (subbufferSizeInBytes > maxSubBufferSize) { + return MA_INVALID_ARGS; /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */ + } + + + MA_ZERO_OBJECT(pRB); + + result = ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks, pAllocationCallbacks); + if (result != MA_SUCCESS) { + return result; + } + + pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes; + pRB->subbufferCount = (ma_uint32)subbufferCount; + + if (pOptionalPreallocatedBuffer != NULL) { + pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes; + pRB->pBuffer = pOptionalPreallocatedBuffer; + } else { + size_t bufferSizeInBytes; + + /* + Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this + we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT. + */ + pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT; + + bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes; + pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks); + if (pRB->pBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + MA_ZERO_MEMORY(pRB->pBuffer, bufferSizeInBytes); + pRB->ownsBuffer = MA_TRUE; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB) +{ + return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB); +} + +MA_API void ma_rb_uninit(ma_rb* pRB) +{ + if (pRB == NULL) { + return; + } + + if (pRB->ownsBuffer) { + ma_aligned_free(pRB->pBuffer, &pRB->allocationCallbacks); + } +} + +MA_API void ma_rb_reset(ma_rb* pRB) +{ + if (pRB == NULL) { + return; + } + + ma_atomic_exchange_32(&pRB->encodedReadOffset, 0); + ma_atomic_exchange_32(&pRB->encodedWriteOffset, 0); +} + +MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) +{ + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + size_t bytesAvailable; + size_t bytesRequested; + + if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) { + return MA_INVALID_ARGS; + } + + /* The returned buffer should never move ahead of the write pointer. */ + writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); + + readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); + + /* + The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we + can only read up to the write pointer. If not, we can only read up to the end of the buffer. + */ + if (readOffsetLoopFlag == writeOffsetLoopFlag) { + bytesAvailable = writeOffsetInBytes - readOffsetInBytes; + } else { + bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes; + } + + bytesRequested = *pSizeInBytes; + if (bytesRequested > bytesAvailable) { + bytesRequested = bytesAvailable; + } + + *pSizeInBytes = bytesRequested; + (*ppBufferOut) = ma_rb__get_read_ptr(pRB); + + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) +{ + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + ma_uint32 newReadOffsetInBytes; + ma_uint32 newReadOffsetLoopFlag; + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + readOffset = ma_atomic_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. */ + newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + sizeInBytes); + if (newReadOffsetInBytes > pRB->subbufferSizeInBytes) { + return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */ + } + + /* Move the read pointer back to the start if necessary. */ + newReadOffsetLoopFlag = readOffsetLoopFlag; + if (newReadOffsetInBytes == pRB->subbufferSizeInBytes) { + newReadOffsetInBytes = 0; + newReadOffsetLoopFlag ^= 0x80000000; + } + + ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); + + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) +{ + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + size_t bytesAvailable; + size_t bytesRequested; + + if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) { + return MA_INVALID_ARGS; + } + + /* The returned buffer should never overtake the read buffer. */ + readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); + + writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); + + /* + In the case of writing, if the write pointer and the read pointer are on the same loop iteration we can only + write up to the end of the buffer. Otherwise we can only write up to the read pointer. The write pointer should + never overtake the read pointer. + */ + if (writeOffsetLoopFlag == readOffsetLoopFlag) { + bytesAvailable = pRB->subbufferSizeInBytes - writeOffsetInBytes; + } else { + bytesAvailable = readOffsetInBytes - writeOffsetInBytes; + } + + bytesRequested = *pSizeInBytes; + if (bytesRequested > bytesAvailable) { + bytesRequested = bytesAvailable; + } + + *pSizeInBytes = bytesRequested; + *ppBufferOut = ma_rb__get_write_ptr(pRB); + + /* Clear the buffer if desired. */ + if (pRB->clearOnWriteAcquire) { + MA_ZERO_MEMORY(*ppBufferOut, *pSizeInBytes); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) +{ + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + ma_uint32 newWriteOffsetInBytes; + ma_uint32 newWriteOffsetLoopFlag; + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + writeOffset = ma_atomic_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. */ + newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + sizeInBytes); + if (newWriteOffsetInBytes > pRB->subbufferSizeInBytes) { + return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */ + } + + /* Move the read pointer back to the start if necessary. */ + newWriteOffsetLoopFlag = writeOffsetLoopFlag; + if (newWriteOffsetInBytes == pRB->subbufferSizeInBytes) { + newWriteOffsetInBytes = 0; + newWriteOffsetLoopFlag ^= 0x80000000; + } + + ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); + + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes) +{ + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + ma_uint32 newReadOffsetInBytes; + ma_uint32 newReadOffsetLoopFlag; + + if (pRB == NULL || offsetInBytes > pRB->subbufferSizeInBytes) { + return MA_INVALID_ARGS; + } + + readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); + + writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); + + newReadOffsetLoopFlag = readOffsetLoopFlag; + + /* We cannot go past the write buffer. */ + if (readOffsetLoopFlag == writeOffsetLoopFlag) { + if ((readOffsetInBytes + offsetInBytes) > writeOffsetInBytes) { + newReadOffsetInBytes = writeOffsetInBytes; + } else { + newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes); + } + } else { + /* May end up looping. */ + if ((readOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) { + newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes; + newReadOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */ + } else { + newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes); + } + } + + ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); + return MA_SUCCESS; +} + +MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes) +{ + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + ma_uint32 newWriteOffsetInBytes; + ma_uint32 newWriteOffsetLoopFlag; + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); + + writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); + + newWriteOffsetLoopFlag = writeOffsetLoopFlag; + + /* We cannot go past the write buffer. */ + if (readOffsetLoopFlag == writeOffsetLoopFlag) { + /* May end up looping. */ + if ((writeOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) { + newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes; + newWriteOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */ + } else { + newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes); + } + } else { + if ((writeOffsetInBytes + offsetInBytes) > readOffsetInBytes) { + newWriteOffsetInBytes = readOffsetInBytes; + } else { + newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes); + } + } + + ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); + return MA_SUCCESS; +} + +MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB) +{ + ma_uint32 readOffset; + ma_uint32 readOffsetInBytes; + ma_uint32 readOffsetLoopFlag; + ma_uint32 writeOffset; + ma_uint32 writeOffsetInBytes; + ma_uint32 writeOffsetLoopFlag; + + if (pRB == NULL) { + return 0; + } + + readOffset = ma_atomic_load_32(&pRB->encodedReadOffset); + ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag); + + writeOffset = ma_atomic_load_32(&pRB->encodedWriteOffset); + ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag); + + if (readOffsetLoopFlag == writeOffsetLoopFlag) { + return writeOffsetInBytes - readOffsetInBytes; + } else { + return writeOffsetInBytes + (pRB->subbufferSizeInBytes - readOffsetInBytes); + } +} + +MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB) +{ + ma_int32 dist; + + if (pRB == NULL) { + return 0; + } + + dist = ma_rb_pointer_distance(pRB); + if (dist < 0) { + return 0; + } + + return dist; +} + +MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return (ma_uint32)(ma_rb_get_subbuffer_size(pRB) - ma_rb_pointer_distance(pRB)); +} + +MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return pRB->subbufferSizeInBytes; +} + +MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + if (pRB->subbufferStrideInBytes == 0) { + return (size_t)pRB->subbufferSizeInBytes; + } + + return (size_t)pRB->subbufferStrideInBytes; +} + +MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex) +{ + if (pRB == NULL) { + return 0; + } + + return subbufferIndex * ma_rb_get_subbuffer_stride(pRB); +} + +MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer) +{ + if (pRB == NULL) { + return NULL; + } + + return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex)); +} + + + +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); + + return ma_get_bytes_per_frame(pRB->format, pRB->channels); +} + +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) +{ + ma_uint32 bpf; + ma_result result; + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pRB); + + bpf = ma_get_bytes_per_frame(format, channels); + if (bpf == 0) { + return MA_INVALID_ARGS; + } + + result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, pAllocationCallbacks, &pRB->rb); + if (result != MA_SUCCESS) { + 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; + } + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB) +{ + return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB); +} + +MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return; + } + + ma_data_source_uninit(&pRB->ds); + ma_rb_uninit(&pRB->rb); +} + +MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return; + } + + ma_rb_reset(&pRB->rb); +} + +MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) +{ + size_t sizeInBytes; + ma_result result; + + if (pRB == NULL || pSizeInFrames == NULL) { + return MA_INVALID_ARGS; + } + + sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB); + + result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut); + if (result != MA_SUCCESS) { + return result; + } + + *pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB)); + return MA_SUCCESS; +} + +MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) +{ + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut) +{ + size_t sizeInBytes; + ma_result result; + + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB); + + result = ma_rb_acquire_write(&pRB->rb, &sizeInBytes, ppBufferOut); + if (result != MA_SUCCESS) { + return result; + } + + *pSizeInFrames = (ma_uint32)(sizeInBytes / ma_pcm_rb_get_bpf(pRB)); + return MA_SUCCESS; +} + +MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames) +{ + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) +{ + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + return ma_rb_seek_read(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames) +{ + if (pRB == NULL) { + return MA_INVALID_ARGS; + } + + return ma_rb_seek_write(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB); +} + +MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return ma_rb_available_read(&pRB->rb) / ma_pcm_rb_get_bpf(pRB); +} + +MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return ma_rb_available_write(&pRB->rb) / ma_pcm_rb_get_bpf(pRB); +} + +MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return (ma_uint32)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB) +{ + if (pRB == NULL) { + return 0; + } + + return (ma_uint32)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB)); +} + +MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex) +{ + if (pRB == NULL) { + return 0; + } + + return (ma_uint32)(ma_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / ma_pcm_rb_get_bpf(pRB)); +} + +MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer) +{ + if (pRB == NULL) { + return NULL; + } + + 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) +{ + ma_result result; + ma_uint32 sizeInFrames; + + sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 5); + if (sizeInFrames == 0) { + return MA_INVALID_ARGS; + } + + result = ma_pcm_rb_init(captureFormat, captureChannels, sizeInFrames, NULL, pAllocationCallbacks, &pRB->rb); + if (result != MA_SUCCESS) { + return result; + } + + /* Seek forward a bit so we have a bit of a buffer in case of desyncs. */ + ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, captureInternalPeriodSizeInFrames * 2); + + return MA_SUCCESS; +} + +MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB) +{ + ma_pcm_rb_uninit((ma_pcm_rb*)pRB); + return MA_SUCCESS; +} + + + +/************************************************************************************************************************************************************** + +Miscellaneous Helpers + +**************************************************************************************************************************************************************/ +MA_API const char* ma_result_description(ma_result result) +{ + switch (result) + { + case MA_SUCCESS: return "No error"; + case MA_ERROR: return "Unknown error"; + case MA_INVALID_ARGS: return "Invalid argument"; + case MA_INVALID_OPERATION: return "Invalid operation"; + case MA_OUT_OF_MEMORY: return "Out of memory"; + case MA_OUT_OF_RANGE: return "Out of range"; + case MA_ACCESS_DENIED: return "Permission denied"; + case MA_DOES_NOT_EXIST: return "Resource does not exist"; + case MA_ALREADY_EXISTS: return "Resource already exists"; + case MA_TOO_MANY_OPEN_FILES: return "Too many open files"; + case MA_INVALID_FILE: return "Invalid file"; + case MA_TOO_BIG: return "Too large"; + case MA_PATH_TOO_LONG: return "Path too long"; + case MA_NAME_TOO_LONG: return "Name too long"; + 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_NO_SPACE: return "No space available"; + case MA_BUSY: return "Device or resource busy"; + case MA_IO_ERROR: return "Input/output error"; + case MA_INTERRUPT: return "Interrupted"; + case MA_UNAVAILABLE: return "Resource unavailable"; + case MA_ALREADY_IN_USE: return "Resource already in use"; + case MA_BAD_ADDRESS: return "Bad address"; + case MA_BAD_SEEK: return "Illegal seek"; + case MA_BAD_PIPE: return "Broken pipe"; + case MA_DEADLOCK: return "Deadlock"; + case MA_TOO_MANY_LINKS: return "Too many links"; + case MA_NOT_IMPLEMENTED: return "Not implemented"; + case MA_NO_MESSAGE: return "No message of desired type"; + case MA_BAD_MESSAGE: return "Invalid message"; + case MA_NO_DATA_AVAILABLE: return "No data available"; + case MA_INVALID_DATA: return "Invalid data"; + case MA_TIMEOUT: return "Timeout"; + case MA_NO_NETWORK: return "Network unavailable"; + case MA_NOT_UNIQUE: return "Not unique"; + case MA_NOT_SOCKET: return "Socket operation on non-socket"; + case MA_NO_ADDRESS: return "Destination address required"; + case MA_BAD_PROTOCOL: return "Protocol wrong type for socket"; + case MA_PROTOCOL_UNAVAILABLE: return "Protocol not available"; + case MA_PROTOCOL_NOT_SUPPORTED: return "Protocol not supported"; + case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported"; + case MA_ADDRESS_FAMILY_NOT_SUPPORTED: return "Address family not supported"; + case MA_SOCKET_NOT_SUPPORTED: return "Socket type not supported"; + case MA_CONNECTION_RESET: return "Connection reset"; + case MA_ALREADY_CONNECTED: return "Already connected"; + case MA_NOT_CONNECTED: return "Not connected"; + case MA_CONNECTION_REFUSED: return "Connection refused"; + case MA_NO_HOST: return "No host"; + 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_FORMAT_NOT_SUPPORTED: return "Format not supported"; + case MA_DEVICE_TYPE_NOT_SUPPORTED: return "Device type not supported"; + case MA_SHARE_MODE_NOT_SUPPORTED: return "Share mode not supported"; + case MA_NO_BACKEND: return "No backend"; + case MA_NO_DEVICE: return "No device"; + case MA_API_NOT_FOUND: return "API not found"; + case MA_INVALID_DEVICE_CONFIG: return "Invalid device config"; + + case MA_DEVICE_NOT_INITIALIZED: return "Device not initialized"; + case MA_DEVICE_NOT_STARTED: return "Device not started"; + + case MA_FAILED_TO_INIT_BACKEND: return "Failed to initialize backend"; + case MA_FAILED_TO_OPEN_BACKEND_DEVICE: return "Failed to open backend device"; + case MA_FAILED_TO_START_BACKEND_DEVICE: return "Failed to start backend device"; + case MA_FAILED_TO_STOP_BACKEND_DEVICE: return "Failed to stop backend device"; + + default: return "Unknown error"; + } +} + +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. */ + } + } 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. */ + } + } else { + return ma__realloc_default(p, sz, NULL); + } +} + +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. */ + } + } else { + ma__free_default(p, NULL); + } +} + +MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks) +{ + size_t extraBytes; + void* pUnaligned; + void* pAligned; + + if (alignment == 0) { + return 0; + } + + extraBytes = alignment-1 + sizeof(void*); + + pUnaligned = ma_malloc(sz + extraBytes, pAllocationCallbacks); + if (pUnaligned == NULL) { + return NULL; + } + + pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1))); + ((void**)pAligned)[-1] = pUnaligned; + + return pAligned; +} + +MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_free(((void**)p)[-1], pAllocationCallbacks); +} + +MA_API const char* ma_get_format_name(ma_format format) +{ + switch (format) + { + case ma_format_unknown: return "Unknown"; + case ma_format_u8: return "8-bit Unsigned Integer"; + case ma_format_s16: return "16-bit Signed Integer"; + case ma_format_s24: return "24-bit Signed Integer (Tightly Packed)"; + case ma_format_s32: return "32-bit Signed Integer"; + case ma_format_f32: return "32-bit IEEE Floating Point"; + default: return "Invalid"; + } +} + +MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels) +{ + ma_uint32 i; + for (i = 0; i < channels; ++i) { + pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor); + } +} + + +MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format) +{ + ma_uint32 sizes[] = { + 0, /* unknown */ + 1, /* u8 */ + 2, /* s16 */ + 3, /* s24 */ + 4, /* s32 */ + 4, /* f32 */ + }; + return sizes[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_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; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + if (pDataSourceBase == NULL) { + return MA_INVALID_ARGS; + } + + loop = ma_data_source_is_looping(pDataSource); + + /* + 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; + } + + return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead); + } + + /* + 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. */ + 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; + } + } + } + + if (pRunningFramesOut != NULL) { + pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels)); + } + } + + 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) +{ + return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked); +} + +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) { + 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); +} + +MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked) +{ + ma_uint64 frameCount; + ma_uint64 framesSeeked = 0; + ma_uint32 sampleRate; + ma_result result; + + if (pDataSource == 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; +} + +MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds) +{ + ma_uint64 frameIndex; + ma_uint32 sampleRate; + ma_result result; + + if (pDataSource == 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); +} + +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_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + ma_result result; + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + + /* 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) { + 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); + if (result != MA_SUCCESS) { + return result; + } + + if (pFormat != NULL) { + *pFormat = format; + } + if (pChannels != NULL) { + *pChannels = channels; + } + if (pSampleRate != NULL) { + *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; + + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + if (pDataSourceBase == NULL) { + return MA_SUCCESS; + } + + MA_ASSERT(pDataSourceBase->vtable != NULL); + + if (pDataSourceBase->vtable->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; +} + +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; + + if (pLength == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = 0; + + if (pDataSourceBase == 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) { + return MA_NOT_IMPLEMENTED; + } + + return pDataSourceBase->vtable->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); + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + if (framesRead < frameCount || framesRead == 0) { + return MA_AT_END; + } + + return MA_SUCCESS; +} + +static ma_result ma_audio_buffer_ref__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + 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) +{ + 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); + + return MA_SUCCESS; +} + +static ma_result ma_audio_buffer_ref__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource; + + *pCursor = pAudioBufferRef->cursor; + + return MA_SUCCESS; +} + +static ma_result ma_audio_buffer_ref__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength) +{ + ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource; + + *pLength = pAudioBufferRef->sizeInFrames; + + 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; + + 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) { + return MA_INVALID_ARGS; + } + + pAudioBufferRef->cursor = 0; + pAudioBufferRef->sizeInFrames = sizeInFrames; + pAudioBufferRef->pData = pData; + + return MA_SUCCESS; +} + +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_uint64 totalFramesRead = 0; + + if (pAudioBufferRef == NULL) { + return 0; + } + + if (frameCount == 0) { + return 0; + } + + while (totalFramesRead < frameCount) { + ma_uint64 framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor; + ma_uint64 framesRemaining = frameCount - totalFramesRead; + ma_uint64 framesToRead; + + framesToRead = framesRemaining; + if (framesToRead > framesAvailable) { + framesToRead = framesAvailable; + } + + 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); + } + + totalFramesRead += framesToRead; + + pAudioBufferRef->cursor += framesToRead; + if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) { + if (loop) { + pAudioBufferRef->cursor = 0; + } else { + break; /* We've reached the end and we're not looping. Done. */ + } + } + + MA_ASSERT(pAudioBufferRef->cursor < pAudioBufferRef->sizeInFrames); + } + + return totalFramesRead; +} + +MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex) +{ + if (pAudioBufferRef == NULL) { + return MA_INVALID_ARGS; + } + + if (frameIndex > pAudioBufferRef->sizeInFrames) { + return MA_INVALID_ARGS; + } + + pAudioBufferRef->cursor = (size_t)frameIndex; + + return MA_SUCCESS; +} + +MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount) +{ + ma_uint64 framesAvailable; + ma_uint64 frameCount = 0; + + if (ppFramesOut != NULL) { + *ppFramesOut = NULL; /* Safety. */ + } + + if (pFrameCount != NULL) { + frameCount = *pFrameCount; + *pFrameCount = 0; /* Safety. */ + } + + if (pAudioBufferRef == NULL || ppFramesOut == NULL || pFrameCount == NULL) { + return MA_INVALID_ARGS; + } + + framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor; + if (frameCount > framesAvailable) { + frameCount = framesAvailable; + } + + *ppFramesOut = ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)); + *pFrameCount = frameCount; + + return MA_SUCCESS; +} + +MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount) +{ + ma_uint64 framesAvailable; + + if (pAudioBufferRef == NULL) { + return MA_INVALID_ARGS; + } + + framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor; + if (frameCount > framesAvailable) { + return MA_INVALID_ARGS; /* The frame count was too big. This should never happen in an unmapping. Need to make sure the caller is aware of this. */ + } + + pAudioBufferRef->cursor += frameCount; + + if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) { + return MA_AT_END; /* Successful. Need to tell the caller that the end has been reached so that it can loop if desired. */ + } else { + return MA_SUCCESS; + } +} + +MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef) +{ + if (pAudioBufferRef == NULL) { + return MA_FALSE; + } + + 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) +{ + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pAudioBufferRef == NULL) { + return MA_INVALID_ARGS; + } + + if (pAudioBufferRef->sizeInFrames <= pAudioBufferRef->cursor) { + *pAvailableFrames = 0; + } else { + *pAvailableFrames = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor; + } + + return MA_SUCCESS; +} + + + + +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) +{ + 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.sizeInFrames = sizeInFrames; + config.pData = pData; + ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks); + + return config; +} + +static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, ma_bool32 doCopy, ma_audio_buffer* pAudioBuffer) +{ + ma_result result; + + if (pAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_MEMORY(pAudioBuffer, sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData)); /* Safety. Don't overwrite the extra data. */ + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->sizeInFrames == 0) { + return MA_INVALID_ARGS; /* Not allowing buffer sizes of 0 frames. */ + } + + result = ma_audio_buffer_ref_init(pConfig->format, pConfig->channels, NULL, 0, &pAudioBuffer->ref); + 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) { + ma_uint64 allocationSizeInBytes; + void* pData; + + allocationSizeInBytes = pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels); + if (allocationSizeInBytes > MA_SIZE_MAX) { + return MA_OUT_OF_MEMORY; /* Too big. */ + } + + pData = ma_malloc((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks); /* Safe cast to size_t. */ + if (pData == NULL) { + return MA_OUT_OF_MEMORY; + } + + if (pConfig->pData != NULL) { + ma_copy_pcm_frames(pData, pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels); + } else { + ma_silence_pcm_frames(pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels); + } + + ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pData, pConfig->sizeInFrames); + pAudioBuffer->ownsData = MA_TRUE; + } else { + ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pConfig->pData, pConfig->sizeInFrames); + pAudioBuffer->ownsData = MA_FALSE; + } + + return MA_SUCCESS; +} + +static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 doFree) +{ + if (pAudioBuffer == NULL) { + return; + } + + 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. */ + } + + if (doFree) { + ma_free(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) +{ + return ma_audio_buffer_init_ex(pConfig, MA_FALSE, pAudioBuffer); +} + +MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer) +{ + return ma_audio_buffer_init_ex(pConfig, MA_TRUE, pAudioBuffer); +} + +MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer) +{ + ma_result result; + ma_audio_buffer* pAudioBuffer; + ma_audio_buffer_config innerConfig; /* We'll be making some changes to the config, so need to make a copy. */ + ma_uint64 allocationSizeInBytes; + + if (ppAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + *ppAudioBuffer = NULL; /* Safety. */ + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + innerConfig = *pConfig; + ma_allocation_callbacks_init_copy(&innerConfig.allocationCallbacks, &pConfig->allocationCallbacks); + + allocationSizeInBytes = sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData) + (pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels)); + if (allocationSizeInBytes > MA_SIZE_MAX) { + return MA_OUT_OF_MEMORY; /* Too big. */ + } + + pAudioBuffer = (ma_audio_buffer*)ma_malloc((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks); /* Safe cast to size_t. */ + if (pAudioBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + if (pConfig->pData != NULL) { + ma_copy_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels); + } else { + ma_silence_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->sizeInFrames, pConfig->format, pConfig->channels); + } + + innerConfig.pData = &pAudioBuffer->_pExtraData[0]; + + result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer); + if (result != MA_SUCCESS) { + ma_free(pAudioBuffer, &innerConfig.allocationCallbacks); + return result; + } + + *ppAudioBuffer = pAudioBuffer; + + return MA_SUCCESS; +} + +MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer) +{ + ma_audio_buffer_uninit_ex(pAudioBuffer, MA_FALSE); +} + +MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer) +{ + ma_audio_buffer_uninit_ex(pAudioBuffer, MA_TRUE); +} + +MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop) +{ + if (pAudioBuffer == NULL) { + return 0; + } + + return ma_audio_buffer_ref_read_pcm_frames(&pAudioBuffer->ref, pFramesOut, frameCount, loop); +} + +MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex) +{ + if (pAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + return ma_audio_buffer_ref_seek_to_pcm_frame(&pAudioBuffer->ref, frameIndex); +} + +MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount) +{ + if (ppFramesOut != NULL) { + *ppFramesOut = NULL; /* Safety. */ + } + + if (pAudioBuffer == NULL) { + if (pFrameCount != NULL) { + *pFrameCount = 0; + } + + return MA_INVALID_ARGS; + } + + return ma_audio_buffer_ref_map(&pAudioBuffer->ref, ppFramesOut, pFrameCount); +} + +MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount) +{ + if (pAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + return ma_audio_buffer_ref_unmap(&pAudioBuffer->ref, frameCount); +} + +MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer) +{ + if (pAudioBuffer == NULL) { + return MA_FALSE; + } + + 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) +{ + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pAudioBuffer == NULL) { + return MA_INVALID_ARGS; + } + + return ma_audio_buffer_ref_get_available_frames(&pAudioBuffer->ref, pAvailableFrames); +} + + + + + +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 + +**************************************************************************************************************************************************************/ +MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pFile == NULL) { + return MA_INVALID_ARGS; + } + + *pFile = NULL; + + if (pVFS == NULL || pFilePath == NULL || openMode == 0) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onOpen == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onOpen(pVFS, pFilePath, openMode, pFile); +} + +MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pFile == NULL) { + return MA_INVALID_ARGS; + } + + *pFile = NULL; + + if (pVFS == NULL || pFilePath == NULL || openMode == 0) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onOpenW == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onOpenW(pVFS, pFilePath, openMode, pFile); +} + +MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pVFS == NULL || file == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onClose == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onClose(pVFS, 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; + } + + if (pVFS == NULL || file == NULL || pDst == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onRead == NULL) { + 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; +} + +MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pBytesWritten != NULL) { + *pBytesWritten = 0; + } + + if (pVFS == NULL || file == NULL || pSrc == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onWrite == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onWrite(pVFS, file, pSrc, sizeInBytes, pBytesWritten); +} + +MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pVFS == NULL || file == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onSeek == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onSeek(pVFS, file, offset, origin); +} + +MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + if (pVFS == NULL || file == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onTell == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onTell(pVFS, file, pCursor); +} + +MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) +{ + ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS; + + if (pInfo == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pInfo); + + if (pVFS == NULL || file == NULL) { + return MA_INVALID_ARGS; + } + + if (pCallbacks->onInfo == NULL) { + return MA_NOT_IMPLEMENTED; + } + + return pCallbacks->onInfo(pVFS, file, 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) +{ + 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"); + } + } +} + +static void ma_default_vfs__get_open_settings_win32(ma_uint32 openMode, DWORD* pDesiredAccess, DWORD* pShareMode, DWORD* pCreationDisposition) +{ + *pDesiredAccess = 0; + if ((openMode & MA_OPEN_MODE_READ) != 0) { + *pDesiredAccess |= GENERIC_READ; + } + if ((openMode & MA_OPEN_MODE_WRITE) != 0) { + *pDesiredAccess |= GENERIC_WRITE; + } + + *pShareMode = 0; + if ((openMode & MA_OPEN_MODE_READ) != 0) { + *pShareMode |= FILE_SHARE_READ; + } + + if ((openMode & MA_OPEN_MODE_WRITE) != 0) { + *pCreationDisposition = CREATE_ALWAYS; /* Opening in write mode. Truncate. */ + } else { + *pCreationDisposition = OPEN_EXISTING; /* Opening in read mode. File must exist. */ + } +} + +static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + + (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); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); + } + + *pFile = hFile; + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + HANDLE hFile; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + + (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); + if (hFile == INVALID_HANDLE_VALUE) { + return ma_result_from_GetLastError(GetLastError()); + } + + *pFile = hFile; + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file) +{ + (void)pVFS; + + if (CloseHandle((HANDLE)file) == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + + +static ma_result ma_default_vfs_read__win32(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) +{ + ma_result result = MA_SUCCESS; + size_t totalBytesRead; + + (void)pVFS; + + totalBytesRead = 0; + while (totalBytesRead < sizeInBytes) { + size_t bytesRemaining; + DWORD bytesToRead; + DWORD bytesRead; + BOOL readResult; + + bytesRemaining = sizeInBytes - totalBytesRead; + if (bytesRemaining >= 0xFFFFFFFF) { + bytesToRead = 0xFFFFFFFF; + } else { + bytesToRead = (DWORD)bytesRemaining; + } + + readResult = ReadFile((HANDLE)file, ma_offset_ptr(pDst, totalBytesRead), bytesToRead, &bytesRead, NULL); + if (readResult == 1 && bytesRead == 0) { + result = MA_AT_END; + break; /* EOF */ + } + + totalBytesRead += bytesRead; + + if (bytesRead < bytesToRead) { + break; /* EOF */ + } + + if (readResult == 0) { + result = ma_result_from_GetLastError(GetLastError()); + break; + } + } + + if (pBytesRead != NULL) { + *pBytesRead = totalBytesRead; + } + + return result; +} + +static ma_result ma_default_vfs_write__win32(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) +{ + ma_result result = MA_SUCCESS; + size_t totalBytesWritten; + + (void)pVFS; + + totalBytesWritten = 0; + while (totalBytesWritten < sizeInBytes) { + size_t bytesRemaining; + DWORD bytesToWrite; + DWORD bytesWritten; + BOOL writeResult; + + bytesRemaining = sizeInBytes - totalBytesWritten; + if (bytesRemaining >= 0xFFFFFFFF) { + bytesToWrite = 0xFFFFFFFF; + } else { + bytesToWrite = (DWORD)bytesRemaining; + } + + writeResult = WriteFile((HANDLE)file, ma_offset_ptr(pSrc, totalBytesWritten), bytesToWrite, &bytesWritten, NULL); + totalBytesWritten += bytesWritten; + + if (writeResult == 0) { + result = ma_result_from_GetLastError(GetLastError()); + break; + } + } + + if (pBytesWritten != NULL) { + *pBytesWritten = totalBytesWritten; + } + + return result; +} + + +static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) +{ + LARGE_INTEGER liDistanceToMove; + DWORD dwMoveMethod; + BOOL result; + + (void)pVFS; + + liDistanceToMove.QuadPart = offset; + + /* */ if (origin == ma_seek_origin_current) { + dwMoveMethod = FILE_CURRENT; + } else if (origin == ma_seek_origin_end) { + dwMoveMethod = FILE_END; + } else { + 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 (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) +{ + LARGE_INTEGER liZero; + LARGE_INTEGER liTell; + BOOL result; + + (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 (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + if (pCursor != NULL) { + *pCursor = liTell.QuadPart; + } + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) +{ + BY_HANDLE_FILE_INFORMATION fi; + BOOL result; + + (void)pVFS; + + result = GetFileInformationByHandle((HANDLE)file, &fi); + if (result == 0) { + return ma_result_from_GetLastError(GetLastError()); + } + + pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow); + + return MA_SUCCESS; +} +#else +static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + ma_result result; + FILE* pFileStd; + const char* pOpenModeStr; + + MA_ASSERT(pFilePath != NULL); + MA_ASSERT(openMode != 0); + MA_ASSERT(pFile != NULL); + + (void)pVFS; + + if ((openMode & MA_OPEN_MODE_READ) != 0) { + if ((openMode & MA_OPEN_MODE_WRITE) != 0) { + pOpenModeStr = "r+"; + } else { + pOpenModeStr = "rb"; + } + } else { + pOpenModeStr = "wb"; + } + + result = ma_fopen(&pFileStd, pFilePath, pOpenModeStr); + if (result != MA_SUCCESS) { + return result; + } + + *pFile = pFileStd; + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_open_w__stdio(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + ma_result result; + FILE* pFileStd; + const wchar_t* pOpenModeStr; + + MA_ASSERT(pFilePath != NULL); + MA_ASSERT(openMode != 0); + MA_ASSERT(pFile != NULL); + + (void)pVFS; + + if ((openMode & MA_OPEN_MODE_READ) != 0) { + if ((openMode & MA_OPEN_MODE_WRITE) != 0) { + pOpenModeStr = L"r+"; + } else { + pOpenModeStr = L"rb"; + } + } else { + pOpenModeStr = L"wb"; + } + + result = ma_wfopen(&pFileStd, pFilePath, pOpenModeStr, (pVFS != NULL) ? &((ma_default_vfs*)pVFS)->allocationCallbacks : NULL); + if (result != MA_SUCCESS) { + return result; + } + + *pFile = pFileStd; + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_close__stdio(ma_vfs* pVFS, ma_vfs_file file) +{ + MA_ASSERT(file != NULL); + + (void)pVFS; + + fclose((FILE*)file); + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_read__stdio(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) +{ + size_t result; + + MA_ASSERT(file != NULL); + MA_ASSERT(pDst != NULL); + + (void)pVFS; + + result = fread(pDst, 1, sizeInBytes, (FILE*)file); + + if (pBytesRead != NULL) { + *pBytesRead = result; + } + + if (result != sizeInBytes) { + if (result == 0 && feof((FILE*)file)) { + return MA_AT_END; + } else { + return ma_result_from_errno(ferror((FILE*)file)); + } + } + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_write__stdio(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) +{ + size_t result; + + MA_ASSERT(file != NULL); + MA_ASSERT(pSrc != NULL); + + (void)pVFS; + + result = fwrite(pSrc, 1, sizeInBytes, (FILE*)file); + + if (pBytesWritten != NULL) { + *pBytesWritten = result; + } + + if (result != sizeInBytes) { + return ma_result_from_errno(ferror((FILE*)file)); + } + + return MA_SUCCESS; +} + +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); + #else + /* No _fseeki64() so restrict to 31 bits. */ + if (offset > 0x7FFFFFFF) { + return MA_OUT_OF_RANGE; + } + + result = fseek((FILE*)file, (int)offset, whence); + #endif +#else + result = fseek((FILE*)file, (long int)offset, whence); +#endif + if (result != 0) { + return MA_ERROR; + } + + return MA_SUCCESS; +} + +static ma_result ma_default_vfs_tell__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) +{ + ma_int64 result; + + MA_ASSERT(file != NULL); + MA_ASSERT(pCursor != NULL); + + (void)pVFS; + +#if defined(_WIN32) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64((FILE*)file); + #else + result = ftell((FILE*)file); + #endif +#else + result = ftell((FILE*)file); +#endif + + *pCursor = result; + + return MA_SUCCESS; +} + +#if !defined(_MSC_VER) && !((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)) && !defined(MA_BSD) +int fileno(FILE *stream); +#endif + +static ma_result ma_default_vfs_info__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) +{ + int fd; + struct stat info; + + MA_ASSERT(file != NULL); + MA_ASSERT(pInfo != NULL); + + (void)pVFS; + +#if defined(_MSC_VER) + fd = _fileno((FILE*)file); +#else + fd = fileno((FILE*)file); +#endif + + if (fstat(fd, &info) != 0) { + return ma_result_from_errno(errno); + } + + pInfo->sizeInBytes = info.st_size; + + return MA_SUCCESS; +} +#endif + + +static ma_result ma_default_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + if (pFile == NULL) { + return MA_INVALID_ARGS; + } + + *pFile = NULL; + + if (pFilePath == NULL || openMode == 0) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_open__win32(pVFS, pFilePath, openMode, pFile); +#else + return ma_default_vfs_open__stdio(pVFS, pFilePath, openMode, pFile); +#endif +} + +static ma_result ma_default_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + if (pFile == NULL) { + return MA_INVALID_ARGS; + } + + *pFile = NULL; + + if (pFilePath == NULL || openMode == 0) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_open_w__win32(pVFS, pFilePath, openMode, pFile); +#else + return ma_default_vfs_open_w__stdio(pVFS, pFilePath, openMode, pFile); +#endif +} + +static ma_result ma_default_vfs_close(ma_vfs* pVFS, ma_vfs_file file) +{ + if (file == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_close__win32(pVFS, file); +#else + return ma_default_vfs_close__stdio(pVFS, file); +#endif +} + +static ma_result ma_default_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) +{ + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + + if (file == NULL || pDst == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_read__win32(pVFS, file, pDst, sizeInBytes, pBytesRead); +#else + return ma_default_vfs_read__stdio(pVFS, file, pDst, sizeInBytes, pBytesRead); +#endif +} + +static ma_result ma_default_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) +{ + if (pBytesWritten != NULL) { + *pBytesWritten = 0; + } + + if (file == NULL || pSrc == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_write__win32(pVFS, file, pSrc, sizeInBytes, pBytesWritten); +#else + return ma_default_vfs_write__stdio(pVFS, file, pSrc, sizeInBytes, pBytesWritten); +#endif +} + +static ma_result ma_default_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) +{ + if (file == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_seek__win32(pVFS, file, offset, origin); +#else + return ma_default_vfs_seek__stdio(pVFS, file, offset, origin); +#endif +} + +static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) +{ + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + if (file == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_tell__win32(pVFS, file, pCursor); +#else + return ma_default_vfs_tell__stdio(pVFS, file, pCursor); +#endif +} + +static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) +{ + if (pInfo == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pInfo); + + if (file == NULL) { + return MA_INVALID_ARGS; + } + +#if defined(MA_USE_WIN32_FILEIO) + return ma_default_vfs_info__win32(pVFS, file, pInfo); +#else + return ma_default_vfs_info__stdio(pVFS, file, pInfo); +#endif +} + + +MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pVFS == NULL) { + return MA_INVALID_ARGS; + } + + pVFS->cb.onOpen = ma_default_vfs_open; + pVFS->cb.onOpenW = ma_default_vfs_open_w; + pVFS->cb.onClose = ma_default_vfs_close; + pVFS->cb.onRead = ma_default_vfs_read; + pVFS->cb.onWrite = ma_default_vfs_write; + pVFS->cb.onSeek = ma_default_vfs_seek; + pVFS->cb.onTell = ma_default_vfs_tell; + pVFS->cb.onInfo = ma_default_vfs_info; + ma_allocation_callbacks_init_copy(&pVFS->allocationCallbacks, pAllocationCallbacks); + + return MA_SUCCESS; +} + + +MA_API ma_result ma_vfs_or_default_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + if (pVFS != NULL) { + return ma_vfs_open(pVFS, pFilePath, openMode, pFile); + } else { + return ma_default_vfs_open(pVFS, pFilePath, openMode, pFile); + } +} + +MA_API ma_result ma_vfs_or_default_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) +{ + if (pVFS != NULL) { + return ma_vfs_open_w(pVFS, pFilePath, openMode, pFile); + } else { + return ma_default_vfs_open_w(pVFS, pFilePath, openMode, pFile); + } +} + +MA_API ma_result ma_vfs_or_default_close(ma_vfs* pVFS, ma_vfs_file file) +{ + if (pVFS != NULL) { + return ma_vfs_close(pVFS, file); + } else { + return ma_default_vfs_close(pVFS, file); + } +} + +MA_API ma_result ma_vfs_or_default_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) +{ + if (pVFS != NULL) { + return ma_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead); + } else { + return ma_default_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead); + } +} + +MA_API ma_result ma_vfs_or_default_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten) +{ + if (pVFS != NULL) { + return ma_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten); + } else { + return ma_default_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten); + } +} + +MA_API ma_result ma_vfs_or_default_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) +{ + if (pVFS != NULL) { + return ma_vfs_seek(pVFS, file, offset, origin); + } else { + return ma_default_vfs_seek(pVFS, file, offset, origin); + } +} + +MA_API ma_result ma_vfs_or_default_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) +{ + if (pVFS != NULL) { + return ma_vfs_tell(pVFS, file, pCursor); + } else { + return ma_default_vfs_tell(pVFS, file, pCursor); + } +} + +MA_API ma_result ma_vfs_or_default_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) +{ + if (pVFS != NULL) { + return ma_vfs_info(pVFS, file, pInfo); + } else { + return ma_default_vfs_info(pVFS, file, pInfo); + } +} + + + +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. + +**************************************************************************************************************************************************************/ +#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 +#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) +#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 enum +{ + ma_dr_wav_seek_origin_start, + ma_dr_wav_seek_origin_current +} ma_dr_wav_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; +typedef struct +{ + union + { + ma_uint8 fourcc[4]; + ma_uint8 guid[16]; + } id; + ma_uint64 sizeInBytes; + unsigned int paddingSize; +} ma_dr_wav_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); +typedef struct +{ + const ma_uint8* data; + size_t dataSize; + size_t currentReadPos; +} ma_dr_wav__memory_stream; +typedef struct +{ + void** ppData; + size_t* pDataSize; + size_t dataSize; + size_t dataCapacity; + size_t currentWritePos; +} ma_dr_wav__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; +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; +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; + 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; + struct + { + ma_uint32 bytesRemainingInBlock; + ma_uint16 predictor[2]; + ma_int32 delta[2]; + ma_int32 cachedFrames[4]; + ma_uint32 cachedFrameCount; + ma_int32 prevFrames[2][2]; + } msadpcm; + struct + { + ma_uint32 bytesRemainingInBlock; + ma_int32 predictor[2]; + ma_int32 stepIndex[2]; + ma_int32 cachedFrames[16]; + ma_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); +#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); +#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); +#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); +#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); +#ifdef __cplusplus +} +#endif +#endif +/* dr_wav_h end */ +#endif /* MA_NO_WAV */ + +#if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) +/* dr_flac_h begin */ +#ifndef ma_dr_flac_h +#define ma_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) +#include +#if defined(_MSC_VER) && _MSC_VER >= 1700 + #define MA_DR_FLAC_DEPRECATED __declspec(deprecated) +#elif (defined(__GNUC__) && __GNUC__ >= 4) + #define MA_DR_FLAC_DEPRECATED __attribute__((deprecated)) +#elif defined(__has_feature) + #if __has_feature(attribute_deprecated) + #define MA_DR_FLAC_DEPRECATED __attribute__((deprecated)) + #else + #define MA_DR_FLAC_DEPRECATED + #endif +#else + #define MA_DR_FLAC_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 +#endif +#ifdef MA_64BIT +typedef ma_uint64 ma_dr_flac_cache_t; +#else +typedef ma_uint32 ma_dr_flac_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 +typedef enum +{ + ma_dr_flac_container_native, + ma_dr_flac_container_ogg, + ma_dr_flac_container_unknown +} ma_dr_flac_container; +typedef enum +{ + ma_dr_flac_seek_origin_start, + ma_dr_flac_seek_origin_current +} ma_dr_flac_seek_origin; +typedef struct +{ + ma_uint64 firstPCMFrame; + ma_uint64 flacFrameOffset; + ma_uint16 pcmFrameCount; +} ma_dr_flac_seekpoint; +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; +typedef struct +{ + ma_uint32 type; + const void* pRawData; + ma_uint32 rawDataSize; + union + { + ma_dr_flac_streaminfo streaminfo; + struct + { + int unused; + } padding; + struct + { + ma_uint32 id; + const void* pData; + ma_uint32 dataSize; + } application; + struct + { + ma_uint32 seekpointCount; + const ma_dr_flac_seekpoint* pSeekpoints; + } seektable; + struct + { + ma_uint32 vendorLength; + const char* vendor; + ma_uint32 commentCount; + const void* pComments; + } vorbis_comment; + struct + { + char catalog[128]; + ma_uint64 leadInSampleCount; + ma_bool32 isCD; + ma_uint8 trackCount; + const void* pTrackData; + } cuesheet; + struct + { + ma_uint32 type; + ma_uint32 mimeLength; + const char* mime; + ma_uint32 descriptionLength; + const char* description; + ma_uint32 width; + ma_uint32 height; + ma_uint32 colorDepth; + ma_uint32 indexColorCount; + ma_uint32 pictureDataSize; + const ma_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); +typedef struct +{ + const ma_uint8* data; + size_t dataSize; + size_t currentReadPos; +} ma_dr_flac__memory_stream; +typedef struct +{ + ma_dr_flac_read_proc onRead; + ma_dr_flac_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; +typedef struct +{ + ma_uint8 subframeType; + ma_uint8 wastedBitsPerSample; + ma_uint8 lpcOrder; + ma_int32* pSamplesS32; +} ma_dr_flac_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; +typedef struct +{ + ma_dr_flac_frame_header header; + ma_uint32 pcmFramesRemaining; + ma_dr_flac_subframe subframes[8]; +} ma_dr_flac_frame; +typedef struct +{ + ma_dr_flac_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; + 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); +#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); +#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); +typedef struct +{ + ma_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); +typedef struct +{ + ma_uint32 countRemaining; + const char* pRunningData; +} ma_dr_flac_cuesheet_track_iterator; +typedef struct +{ + ma_uint64 offset; + ma_uint8 index; + ma_uint8 reserved[3]; +} ma_dr_flac_cuesheet_track_index; +typedef struct +{ + ma_uint64 offset; + ma_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); +#ifdef __cplusplus +} +#endif +#endif +/* dr_flac_h end */ +#endif /* MA_NO_FLAC */ + +#if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) +/* dr_mp3_h begin */ +#ifndef ma_dr_mp3_h +#define ma_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) +#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 struct +{ + int frame_bytes, channels, hz, layer, bitrate_kbps; +} ma_dr_mp3dec_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); +typedef enum +{ + ma_dr_mp3_seek_origin_start, + ma_dr_mp3_seek_origin_current +} ma_dr_mp3_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); +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; + size_t dataSize; + size_t dataCapacity; + size_t dataConsumed; + ma_uint8* pData; + ma_bool32 atEnd : 1; + struct + { + const ma_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); +#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); +#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); +#ifdef __cplusplus +} +#endif +#endif +/* dr_mp3_h end */ +#endif /* MA_NO_MP3 */ + + +/************************************************************************************************************************************************************** + +Decoding + +**************************************************************************************************************************************************************/ +#ifndef MA_NO_DECODING + +static ma_result ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +{ + MA_ASSERT(pDecoder != NULL); + + return pDecoder->onRead(pDecoder, pBufferOut, bytesToRead, pBytesRead); +} + +static ma_result ma_decoder_seek_bytes(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin) +{ + 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; + } + + 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; +} + + +MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate) +{ + 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; + + /* 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; + if (pConfig != NULL) { + config = *pConfig; + } else { + MA_ZERO_OBJECT(&config); + } + + return config; +} + +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) { + return MA_INVALID_ARGS; + } + + + /* Output format. */ + if (pConfig->format == ma_format_unknown) { + pDecoder->outputFormat = internalFormat; + } else { + pDecoder->outputFormat = pConfig->format; + } + + if (pConfig->channels == 0) { + pDecoder->outputChannels = internalChannels; + } else { + pDecoder->outputChannels = pConfig->channels; + } + + if (pConfig->sampleRate == 0) { + pDecoder->outputSampleRate = internalSampleRate; + } else { + pDecoder->outputSampleRate = pConfig->sampleRate; + } + + converterConfig = ma_data_converter_config_init( + internalFormat, pDecoder->outputFormat, + internalChannels, pDecoder->outputChannels, + 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; + + 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; +} + + + +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 +#define MA_HAS_WAV + +typedef struct +{ + 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_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); +} + +static ma_result ma_wav_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_wav_seek_to_pcm_frame((ma_wav*)pDataSource, frameIndex); +} + +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) +{ + return ma_wav_get_data_format((ma_wav*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +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(pWav != NULL); + + result = pWav->onRead(pWav->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); + (void)result; + + return bytesRead; +} + +static ma_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, ma_dr_wav_seek_origin origin) +{ + ma_wav* pWav = (ma_wav*)pUserData; + ma_result result; + ma_seek_origin maSeekOrigin; + + 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; + } 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_SUCCESS; +} + +static ma_result ma_wav_post_init(ma_wav* pWav) +{ + /* + 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; +} + +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); +} + +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); +} + +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); +} + +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); +} +#endif /* ma_dr_wav_h */ + +/* FLAC */ +#ifdef ma_dr_flac_h +#define MA_HAS_FLAC + +typedef struct +{ + 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_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); +} + +static ma_result ma_flac_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_flac_seek_to_pcm_frame((ma_flac*)pDataSource, frameIndex); +} + +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) +{ + return ma_flac_get_data_format((ma_flac*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +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(pFlac != NULL); + + result = pFlac->onRead(pFlac->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); + (void)result; + + return bytesRead; +} + +static ma_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +{ + ma_flac* pFlac = (ma_flac*)pUserData; + ma_result result; + ma_seek_origin maSeekOrigin; + + 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; + } 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_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) +{ + 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 +} + +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); +} + +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); +} + +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); +} + +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); +} +#endif /* ma_dr_flac_h */ + +/* MP3 */ +#ifdef ma_dr_mp3_h +#define MA_HAS_MP3 + +typedef struct +{ + 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_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); +} + +static ma_result ma_mp3_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + return ma_mp3_seek_to_pcm_frame((ma_mp3*)pDataSource, frameIndex); +} + +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) +{ + return ma_mp3_get_data_format((ma_mp3*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +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(pMP3 != NULL); + + result = pMP3->onRead(pMP3->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead); + (void)result; + + return bytesRead; +} + +static ma_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, ma_dr_mp3_seek_origin origin) +{ + ma_mp3* pMP3 = (ma_mp3*)pUserData; + ma_result result; + ma_seek_origin maSeekOrigin; + + 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; + } 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; + + return MA_SUCCESS; +} + +static ma_result ma_mp3_post_init(ma_mp3* pMP3, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_result result; + + result = ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +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); +} + +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); +} + +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); +} + +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); +} +#endif /* ma_dr_mp3_h */ + +/* Vorbis */ +#ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H +#define MA_HAS_VORBIS + +/* The size in bytes of each chunk of data to read from the Vorbis stream. */ +#define MA_VORBIS_DATA_CHUNK_SIZE 4096 + +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; + +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) +{ + return ma_stbvorbis_read_pcm_frames((ma_stbvorbis*)pDataSource, pFramesOut, frameCount, pFramesRead); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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 +}; + + +static ma_result ma_stbvorbis_init_internal(const ma_decoding_backend_config* pConfig, ma_stbvorbis* pVorbis) +{ + ma_result result; + ma_data_source_config dataSourceConfig; + + (void)pConfig; + + if (pVorbis == NULL) { + return MA_INVALID_ARGS; + } + + 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; +} + +#if !defined(MA_NO_VORBIS) +static ma_result ma_stbvorbis_post_init(ma_stbvorbis* pVorbis) +{ + stb_vorbis_info info; + + MA_ASSERT(pVorbis != NULL); + + info = stb_vorbis_get_info(pVorbis->stb); + + pVorbis->channels = info.channels; + pVorbis->sampleRate = info.sample_rate; + + return MA_SUCCESS; +} + +static ma_result ma_stbvorbis_init_internal_decoder_push(ma_stbvorbis* pVorbis) +{ + ma_result result; + stb_vorbis* stb; + size_t dataSize = 0; + size_t dataCapacity = 0; + ma_uint8* pData = NULL; /* <-- Must be initialized to NULL. */ + + for (;;) { + int vorbisError; + int consumedDataSize; /* <-- Fill by stb_vorbis_open_pushdata(). */ + size_t bytesRead; + ma_uint8* pNewData; + + /* Allocate memory for the new chunk. */ + dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE; + pNewData = (ma_uint8*)ma_realloc(pData, dataCapacity, &pVorbis->allocationCallbacks); + if (pNewData == NULL) { + ma_free(pData, &pVorbis->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); + 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; + } + + stb = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL); + if (stb != NULL) { + /* + Successfully opened the Vorbis decoder. We might have some leftover unprocessed + data so we'll need to move that down to the front. + */ + dataSize -= (size_t)consumedDataSize; /* Consume the data. */ + MA_MOVE_MEMORY(pData, ma_offset_ptr(pData, consumedDataSize), dataSize); + + /* + 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; + } 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. */ + } + } + } + + 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); + if (pVorbis == NULL) { + 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; + } + + *ppBackend = pVorbis; + + 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 */ + + + +static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + MA_ASSERT(pDecoder != NULL); + + if (pConfig != NULL) { + return ma_allocation_callbacks_init_copy(&pDecoder->allocationCallbacks, &pConfig->allocationCallbacks); + } else { + pDecoder->allocationCallbacks = ma_allocation_callbacks_init_default(); + return MA_SUCCESS; + } +} + +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); +} + +static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + 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) +{ + return ma_decoder_get_data_format((ma_decoder*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap); +} + +static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + return ma_decoder_get_cursor_in_pcm_frames((ma_decoder*)pDataSource, pCursor); +} + +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); +} + +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) +{ + ma_result result; + ma_data_source_config dataSourceConfig; + + MA_ASSERT(pConfig != NULL); + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + 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; + } + + 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; + } + + return MA_SUCCESS; +} + +static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result; + + 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) { + ma_decoder_uninit(pDecoder); + return result; + } + + return result; +} + + +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) +{ + ma_result result = MA_NO_BACKEND; + + MA_ASSERT(pConfig != NULL); + MA_ASSERT(pDecoder != NULL); + + /* Silence some warnings in the case that we don't have any decoder backends enabled. */ + (void)onRead; + (void)onSeek; + (void)pUserData; + + + /* 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. */ + if (result != MA_SUCCESS) { + onSeek(pDecoder, 0, ma_seek_origin_start); + } + } + + 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. + */ + if (result != MA_SUCCESS) { + result = ma_decoder_init_custom__internal(pConfig, pDecoder); + if (result != MA_SUCCESS) { + 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 + } + + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__postinit(pConfig, pDecoder); +} + +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_decoder_config config; + ma_result result; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(onRead, onSeek, NULL, pUserData, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder_init__internal(onRead, onSeek, pUserData, &config, pDecoder); +} + + +static ma_result ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +{ + size_t bytesRemaining; + + MA_ASSERT(pDecoder->data.memory.dataSize >= pDecoder->data.memory.currentReadPos); + + if (pBytesRead != NULL) { + *pBytesRead = 0; + } + + bytesRemaining = pDecoder->data.memory.dataSize - pDecoder->data.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; + } + + if (pBytesRead != NULL) { + *pBytesRead = bytesToRead; + } + + return MA_SUCCESS; +} + +static ma_result ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 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. */ + } + + 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. */ + } + + 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; + } + } 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. */ + } + } + } + + return MA_SUCCESS; +} + +static ma_result ma_decoder__on_tell_memory(ma_decoder* pDecoder, ma_int64* pCursor) +{ + 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); + if (result != MA_SUCCESS) { + return result; + } + + if (pData == NULL || dataSize == 0) { + return MA_INVALID_ARGS; + } + + pDecoder->data.memory.pData = (const ma_uint8*)pData; + pDecoder->data.memory.dataSize = dataSize; + pDecoder->data.memory.currentReadPos = 0; + + (void)pConfig; + return MA_SUCCESS; +} + +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; + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder__preinit(NULL, NULL, NULL, NULL, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + if (pData == NULL || dataSize == 0) { + return MA_INVALID_ARGS; + } + + /* 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_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 + } + + 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 + } + } + + /* + 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; + } + } + + return MA_SUCCESS; +} + + +#if defined(MA_HAS_WAV) || \ + defined(MA_HAS_MP3) || \ + defined(MA_HAS_FLAC) || \ + defined(MA_HAS_VORBIS) +#define MA_HAS_PATH_API +#endif + +#if defined(MA_HAS_PATH_API) +static const char* ma_path_file_name(const char* path) +{ + const char* fileName; + + if (path == NULL) { + return NULL; + } + + fileName = path; + + /* We just loop through the path until we find the last slash. */ + while (path[0] != '\0') { + if (path[0] == '/' || path[0] == '\\') { + fileName = path; + } + + path += 1; + } + + /* At this point the file name is sitting on a slash, so just move forward. */ + while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { + fileName += 1; + } + + return fileName; +} + +static const wchar_t* ma_path_file_name_w(const wchar_t* path) +{ + const wchar_t* fileName; + + if (path == NULL) { + return NULL; + } + + fileName = path; + + /* We just loop through the path until we find the last slash. */ + while (path[0] != '\0') { + if (path[0] == '/' || path[0] == '\\') { + fileName = path; + } + + path += 1; + } + + /* At this point the file name is sitting on a slash, so just move forward. */ + while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { + fileName += 1; + } + + return fileName; +} + + +static const char* ma_path_extension(const char* path) +{ + const char* extension; + const char* lastOccurance; + + if (path == NULL) { + path = ""; + } + + extension = ma_path_file_name(path); + lastOccurance = NULL; + + /* Just find the last '.' and return. */ + while (extension[0] != '\0') { + if (extension[0] == '.') { + extension += 1; + lastOccurance = extension; + } + + extension += 1; + } + + return (lastOccurance != NULL) ? lastOccurance : extension; +} + +static const wchar_t* ma_path_extension_w(const wchar_t* path) +{ + const wchar_t* extension; + const wchar_t* lastOccurance; + + if (path == NULL) { + path = L""; + } + + extension = ma_path_file_name_w(path); + lastOccurance = NULL; + + /* Just find the last '.' and return. */ + while (extension[0] != '\0') { + if (extension[0] == '.') { + extension += 1; + lastOccurance = extension; + } + + extension += 1; + } + + return (lastOccurance != NULL) ? lastOccurance : extension; +} + + +static ma_bool32 ma_path_extension_equal(const char* path, const char* extension) +{ + const char* ext1; + const char* ext2; + + if (path == NULL || extension == NULL) { + return MA_FALSE; + } + + ext1 = extension; + ext2 = ma_path_extension(path); + +#if defined(_MSC_VER) || defined(__DMC__) + return _stricmp(ext1, ext2) == 0; +#else + return strcasecmp(ext1, ext2) == 0; +#endif +} + +static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension) +{ + const wchar_t* ext1; + const wchar_t* ext2; + + if (path == NULL || extension == NULL) { + return MA_FALSE; + } + + ext1 = extension; + ext2 = ma_path_extension_w(path); + +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__) + return _wcsicmp(ext1, ext2) == 0; +#else + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ + { + char ext1MB[4096]; + char ext2MB[4096]; + const wchar_t* pext1 = ext1; + const wchar_t* pext2 = ext2; + mbstate_t mbs1; + mbstate_t mbs2; + + MA_ZERO_OBJECT(&mbs1); + MA_ZERO_OBJECT(&mbs2); + + if (wcsrtombs(ext1MB, &pext1, sizeof(ext1MB), &mbs1) == (size_t)-1) { + return MA_FALSE; + } + if (wcsrtombs(ext2MB, &pext2, sizeof(ext2MB), &mbs2) == (size_t)-1) { + return MA_FALSE; + } + + return strcasecmp(ext1MB, ext2MB) == 0; + } +#endif +} +#endif /* MA_HAS_PATH_API */ + + + +static ma_result ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead) +{ + 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); +} + +static ma_result ma_decoder__on_seek_vfs(ma_decoder* pDecoder, ma_int64 offset, ma_seek_origin origin) +{ + MA_ASSERT(pDecoder != NULL); + + return ma_vfs_or_default_seek(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, offset, origin); +} + +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); +} + +static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* 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); + if (result != MA_SUCCESS) { + return result; + } + + if (pFilePath == NULL || pFilePath[0] == '\0') { + return MA_INVALID_ARGS; + } + + result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file); + if (result != MA_SUCCESS) { + return result; + } + + pDecoder->data.vfs.pVFS = pVFS; + pDecoder->data.vfs.file = file; + + return MA_SUCCESS; +} + +MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, 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_vfs(pVFS, pFilePath, &config, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + 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. */ + 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. + */ + 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); + } + } + + /* + 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 + } + + /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */ + if (result != MA_SUCCESS) { + result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder); + } else { + result = ma_decoder__postinit(&config, pDecoder); + } + + 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); + } + + return result; + } + + return MA_SUCCESS; +} + + +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); + if (result != MA_SUCCESS) { + return result; + } + + if (pFilePath == NULL || pFilePath[0] == '\0') { + return MA_INVALID_ARGS; + } + + result = ma_vfs_or_default_open_w(pVFS, pFilePath, MA_OPEN_MODE_READ, &file); + if (result != MA_SUCCESS) { + return result; + } + + pDecoder->data.vfs.pVFS = pVFS; + pDecoder->data.vfs.file = file; + + return MA_SUCCESS; +} + +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_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_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. */ + 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. + */ + 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); + } + } + + /* + 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 + } + + /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */ + if (result != MA_SUCCESS) { + result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder); + } else { + result = ma_decoder__postinit(&config, pDecoder); + } + + if (result != MA_SUCCESS) { + ma_vfs_or_default_close(pVFS, pDecoder->data.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_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; +} + +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; +} + +static ma_result ma_decoder__preinit_file_w(const wchar_t* 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; +} + +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; + + config = ma_decoder_config_init_copy(pConfig); + result = ma_decoder__preinit_file_w(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_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 + } + + 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_uninit(ma_decoder* pDecoder) +{ + if (pDecoder == NULL) { + 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->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_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); + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor) +{ + if (pCursor == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = 0; + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + *pCursor = pDecoder->readPointerInPCMFrames; + + return MA_SUCCESS; +} + +MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength) +{ + if (pLength == NULL) { + return MA_INVALID_ARGS; + } + + *pLength = 0; + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + if (pDecoder->pBackend != NULL) { + 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; + } else { + *pLength = ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, internalSampleRate, internalLengthInPCMFrames); + } + + return MA_SUCCESS; + } else { + return MA_NO_BACKEND; + } +} + +MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames) +{ + ma_result result; + ma_uint64 totalFrameCount; + + if (pAvailableFrames == NULL) { + return MA_INVALID_ARGS; + } + + *pAvailableFrames = 0; + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount); + if (result != MA_SUCCESS) { + return result; + } + + if (totalFrameCount <= pDecoder->readPointerInPCMFrames) { + *pAvailableFrames = 0; + } else { + *pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames; + } + + return MA_SUCCESS; +} + + +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; + void* pPCMFramesOut; + + MA_ASSERT(pDecoder != NULL); + + totalFrameCount = 0; + bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels); + + /* The frame count is unknown until we try reading. Thus, we just run in a loop. */ + dataCapInFrames = 0; + pPCMFramesOut = NULL; + for (;;) { + ma_uint64 frameCountToTryReading; + ma_uint64 framesJustRead; + + /* Make room if there's not enough. */ + if (totalFrameCount == dataCapInFrames) { + void* pNewPCMFramesOut; + ma_uint64 newDataCapInFrames = dataCapInFrames*2; + if (newDataCapInFrames == 0) { + newDataCapInFrames = 4096; + } + + if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) { + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + return MA_TOO_BIG; + } + + pNewPCMFramesOut = (void*)ma_realloc(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), &pDecoder->allocationCallbacks); + if (pNewPCMFramesOut == NULL) { + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + return MA_OUT_OF_MEMORY; + } + + dataCapInFrames = newDataCapInFrames; + pPCMFramesOut = pNewPCMFramesOut; + } + + frameCountToTryReading = dataCapInFrames - totalFrameCount; + MA_ASSERT(frameCountToTryReading > 0); + + result = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading, &framesJustRead); + totalFrameCount += framesJustRead; + + if (result != MA_SUCCESS) { + break; + } + + if (framesJustRead < frameCountToTryReading) { + break; + } + } + + + if (pConfigOut != NULL) { + pConfigOut->format = pDecoder->outputFormat; + pConfigOut->channels = pDecoder->outputChannels; + pConfigOut->sampleRate = pDecoder->outputSampleRate; + } + + if (ppPCMFramesOut != NULL) { + *ppPCMFramesOut = pPCMFramesOut; + } else { + ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks); + } + + if (pFrameCountOut != NULL) { + *pFrameCountOut = totalFrameCount; + } + + ma_decoder_uninit(pDecoder); + return MA_SUCCESS; +} + +MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) +{ + ma_result result; + ma_decoder_config config; + ma_decoder decoder; + + if (pFrameCountOut != NULL) { + *pFrameCountOut = 0; + } + if (ppPCMFramesOut != NULL) { + *ppPCMFramesOut = NULL; + } + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder_init_vfs(pVFS, pFilePath, &config, &decoder); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut); + + return result; +} + +MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) +{ + return ma_decode_from_vfs(NULL, pFilePath, pConfig, pFrameCountOut, ppPCMFramesOut); +} + +MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut) +{ + ma_decoder_config config; + ma_decoder decoder; + ma_result result; + + if (pFrameCountOut != NULL) { + *pFrameCountOut = 0; + } + if (ppPCMFramesOut != NULL) { + *ppPCMFramesOut = NULL; + } + + if (pData == NULL || dataSize == 0) { + return MA_INVALID_ARGS; + } + + config = ma_decoder_config_init_copy(pConfig); + + result = ma_decoder_init_memory(pData, dataSize, &config, &decoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut); +} +#endif /* MA_NO_DECODING */ + + +#ifndef MA_NO_ENCODING + +#if defined(MA_HAS_WAV) +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; +} + +static ma_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, ma_dr_wav_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; + } +} + +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; + + MA_ASSERT(pEncoder != NULL); + + pWav = (ma_dr_wav*)ma_malloc(sizeof(*pWav), &pEncoder->config.allocationCallbacks); + if (pWav == NULL) { + return MA_OUT_OF_MEMORY; + } + + wavFormat.container = ma_dr_wav_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; + } else { + wavFormat.format = MA_DR_WAVE_FORMAT_PCM; + } + + allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData; + allocationCallbacks.onMalloc = pEncoder->config.allocationCallbacks.onMalloc; + 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)) { + return MA_ERROR; + } + + pEncoder->pInternalEncoder = pWav; + + return MA_SUCCESS; +} + +static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder) +{ + ma_dr_wav* pWav; + + MA_ASSERT(pEncoder != NULL); + + pWav = (ma_dr_wav*)pEncoder->pInternalEncoder; + MA_ASSERT(pWav != NULL); + + ma_dr_wav_uninit(pWav); + ma_free(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) +{ + ma_dr_wav* pWav; + ma_uint64 framesWritten; + + MA_ASSERT(pEncoder != NULL); + + pWav = (ma_dr_wav*)pEncoder->pInternalEncoder; + MA_ASSERT(pWav != NULL); + + framesWritten = ma_dr_wav_write_pcm_frames(pWav, frameCount, pFramesIn); + + if (pFramesWritten != NULL) { + *pFramesWritten = framesWritten; + } + + return MA_SUCCESS; +} +#endif + +MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate) +{ + ma_encoder_config config; + + MA_ZERO_OBJECT(&config); + config.encodingFormat = encodingFormat; + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + + return config; +} + +MA_API ma_result ma_encoder_preinit(const ma_encoder_config* pConfig, ma_encoder* pEncoder) +{ + ma_result result; + + if (pEncoder == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pEncoder); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sampleRate == 0) { + return MA_INVALID_ARGS; + } + + pEncoder->config = *pConfig; + + result = ma_allocation_callbacks_init_copy(&pEncoder->config.allocationCallbacks, &pConfig->allocationCallbacks); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + +MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, ma_encoder* pEncoder) +{ + ma_result result = MA_SUCCESS; + + /* This assumes ma_encoder_preinit() has been called prior. */ + MA_ASSERT(pEncoder != NULL); + + if (onWrite == NULL || onSeek == NULL) { + return MA_INVALID_ARGS; + } + + pEncoder->onWrite = onWrite; + pEncoder->onSeek = onSeek; + pEncoder->pUserData = pUserData; + + switch (pEncoder->config.encodingFormat) + { + case ma_encoding_format_wav: + { + #if defined(MA_HAS_WAV) + pEncoder->onInit = ma_encoder__on_init_wav; + pEncoder->onUninit = ma_encoder__on_uninit_wav; + pEncoder->onWritePCMFrames = ma_encoder__on_write_pcm_frames_wav; + #else + result = MA_NO_BACKEND; + #endif + } break; + + default: + { + result = MA_INVALID_ARGS; + } break; + } + + /* 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; + } + + 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_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_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_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_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_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_result result; + + result = ma_encoder_preinit(pConfig, pEncoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_encoder_init__internal(onWrite, onSeek, pUserData, pEncoder); +} + + +MA_API void ma_encoder_uninit(ma_encoder* pEncoder) +{ + if (pEncoder == NULL) { + return; + } + + if (pEncoder->onUninit) { + pEncoder->onUninit(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; + } +} + + +MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten) +{ + if (pFramesWritten != NULL) { + *pFramesWritten = 0; + } + + if (pEncoder == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount, pFramesWritten); +} +#endif /* MA_NO_ENCODING */ + + + +/************************************************************************************************************************************************************** + +Generation + +**************************************************************************************************************************************************************/ +#ifndef MA_NO_GENERATION +MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency) +{ + ma_waveform_config config; + + MA_ZERO_OBJECT(&config); + config.format = format; + config.channels = channels; + config.sampleRate = sampleRate; + config.type = type; + config.amplitude = amplitude; + config.frequency = frequency; + + return config; +} + +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); +} + +static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + 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) +{ + 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; +} + +static ma_result ma_waveform__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + ma_waveform* pWaveform = (ma_waveform*)pDataSource; + + *pCursor = (ma_uint64)(pWaveform->time / pWaveform->advance); + + return MA_SUCCESS; +} + +static double ma_waveform__calculate_advance(ma_uint32 sampleRate, double frequency) +{ + return (1.0 / (sampleRate / frequency)); +} + +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; + + 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) { + return MA_INVALID_ARGS; + } + + pWaveform->config.amplitude = amplitude; + return MA_SUCCESS; +} + +MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency) +{ + if (pWaveform == NULL) { + return MA_INVALID_ARGS; + } + + pWaveform->config.frequency = frequency; + ma_waveform__update_advance(pWaveform); + + return MA_SUCCESS; +} + +MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type) +{ + if (pWaveform == NULL) { + return MA_INVALID_ARGS; + } + + pWaveform->config.type = type; + return MA_SUCCESS; +} + +MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate) +{ + if (pWaveform == NULL) { + return MA_INVALID_ARGS; + } + + pWaveform->config.sampleRate = sampleRate; + ma_waveform__update_advance(pWaveform); + + return MA_SUCCESS; +} + +static float ma_waveform_sine_f32(double time, double amplitude) +{ + return (float)(ma_sind(MA_TAU_D * time) * amplitude); +} + +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) +{ + double f = time - (ma_int64)time; + double r; + + if (f < dutyCycle) { + r = amplitude; + } else { + r = -amplitude; + } + + return (float)r; +} + +static ma_int16 ma_waveform_square_s16(double time, double dutyCycle, double amplitude) +{ + return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, dutyCycle, amplitude)); +} + +static float ma_waveform_triangle_f32(double time, double amplitude) +{ + double f = time - (ma_int64)time; + double r; + + r = 2 * ma_abs(2 * (f - 0.5)) - 1; + + return (float)(r * amplitude); +} + +static ma_int16 ma_waveform_triangle_s16(double time, double amplitude) +{ + return ma_pcm_sample_f32_to_s16(ma_waveform_triangle_f32(time, amplitude)); +} + +static float ma_waveform_sawtooth_f32(double time, double amplitude) +{ + double f = time - (ma_int64)time; + double r; + + r = 2 * (f - 0.5); + + return (float)(r * amplitude); +} + +static ma_int16 ma_waveform_sawtooth_s16(double time, double amplitude) +{ + return ma_pcm_sample_f32_to_s16(ma_waveform_sawtooth_f32(time, amplitude)); +} + +static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint64 iChannel; + ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format); + ma_uint32 bpf = bps * pWaveform->config.channels; + + MA_ASSERT(pWaveform != NULL); + MA_ASSERT(pFramesOut != NULL); + + if (pWaveform->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } 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_sine_s16(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } +} + +static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, double dutyCycle, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint64 iChannel; + ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format); + ma_uint32 bpf = bps * pWaveform->config.channels; + + MA_ASSERT(pWaveform != NULL); + MA_ASSERT(pFramesOut != NULL); + + 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); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } 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); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_square_f32(pWaveform->time, dutyCycle, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } +} + +static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint64 iChannel; + ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format); + ma_uint32 bpf = bps * pWaveform->config.channels; + + MA_ASSERT(pWaveform != NULL); + MA_ASSERT(pFramesOut != NULL); + + if (pWaveform->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } 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_triangle_s16(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } +} + +static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint64 iChannel; + ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format); + ma_uint32 bpf = bps * pWaveform->config.channels; + + MA_ASSERT(pWaveform != NULL); + MA_ASSERT(pFramesOut != NULL); + + if (pWaveform->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } 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_sawtooth_s16(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude); + pWaveform->time += pWaveform->advance; + + for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } +} + +MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* 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) { + switch (pWaveform->config.type) + { + case ma_waveform_type_sine: + { + ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount); + } break; + + case ma_waveform_type_square: + { + ma_waveform_read_pcm_frames__square(pWaveform, 0.5, pFramesOut, frameCount); + } break; + + case ma_waveform_type_triangle: + { + ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount); + } break; + + case ma_waveform_type_sawtooth: + { + ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount); + } break; + + default: return MA_INVALID_OPERATION; /* Unknown waveform type. */ + } + } 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; +} + +MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex) +{ + if (pWaveform == NULL) { + return MA_INVALID_ARGS; + } + + pWaveform->time = pWaveform->advance * (ma_int64)frameIndex; /* Casting for VC6. Won't be an issue in practice. */ + + 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) +{ + ma_noise_config config; + MA_ZERO_OBJECT(&config); + + config.format = format; + config.channels = channels; + config.type = type; + config.seed = seed; + config.amplitude = amplitude; + + if (config.seed == 0) { + config.seed = MA_DEFAULT_LCG_SEED; + } + + return config; +} + + +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); +} + +static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + /* No-op. Just pretend to be successful. */ + (void)pDataSource; + (void)frameIndex; + 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) +{ + 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_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; + } + + 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; + } + + 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); + + 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); + + for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) { + pNoise->state.brownian.accumulation[iChannel] = 0; + } + } + + 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) { + return MA_INVALID_ARGS; + } + + pNoise->config.amplitude = amplitude; + return MA_SUCCESS; +} + +MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed) +{ + if (pNoise == NULL) { + return MA_INVALID_ARGS; + } + + pNoise->lcg.state = seed; + return MA_SUCCESS; +} + + +MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type) +{ + if (pNoise == NULL) { + 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; +} + +static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise) +{ + return (float)(ma_lcg_rand_f64(&pNoise->lcg) * pNoise->config.amplitude); +} + +static MA_INLINE ma_int16 ma_noise_s16_white(ma_noise* pNoise) +{ + return ma_pcm_sample_f32_to_s16(ma_noise_f32_white(pNoise)); +} + +static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels > 0); + + if (pNoise->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_white(pNoise); + } + } + } + } else if (pNoise->config.format == ma_format_s16) { + ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_int16 s = ma_noise_s16_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_white(pNoise); + } + } + } + } else { + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; + + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_white(pNoise); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + float s = ma_noise_f32_white(pNoise); + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } + } + + return frameCount; +} + + +static MA_INLINE unsigned int ma_tzcnt32(unsigned int x) +{ + unsigned int n; + + /* Special case for odd numbers since they should happen about half the time. */ + if (x & 0x1) { + return 0; + } + + if (x == 0) { + return sizeof(x) << 3; + } + + n = 1; + if ((x & 0x0000FFFF) == 0) { x >>= 16; n += 16; } + if ((x & 0x000000FF) == 0) { x >>= 8; n += 8; } + if ((x & 0x0000000F) == 0) { x >>= 4; n += 4; } + if ((x & 0x00000003) == 0) { x >>= 2; n += 2; } + n -= x & 0x00000001; + + return n; +} + +/* +Pink noise generation based on Tonic (public domain) with modifications. https://github.com/TonicAudio/Tonic/blob/master/src/Tonic/Noise.h + +This is basically _the_ reference for pink noise from what I've found: http://www.firstpr.com.au/dsp/pink-noise/ +*/ +static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel) +{ + double result; + double binPrev; + double binNext; + unsigned int ibin; + + ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (MA_PINK_NOISE_BIN_SIZE - 1); + + binPrev = pNoise->state.pink.bin[iChannel][ibin]; + binNext = ma_lcg_rand_f64(&pNoise->lcg); + pNoise->state.pink.bin[iChannel][ibin] = binNext; + + pNoise->state.pink.accumulation[iChannel] += (binNext - binPrev); + pNoise->state.pink.counter[iChannel] += 1; + + result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]); + result /= 10; + + return (float)(result * pNoise->config.amplitude); +} + +static MA_INLINE ma_int16 ma_noise_s16_pink(ma_noise* pNoise, ma_uint32 iChannel) +{ + return ma_pcm_sample_f32_to_s16(ma_noise_f32_pink(pNoise, iChannel)); +} + +static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels > 0); + + if (pNoise->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_pink(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel); + } + } + } + } else if (pNoise->config.format == ma_format_s16) { + ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_int16 s = ma_noise_s16_pink(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel); + } + } + } + } else { + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; + + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_pink(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + float s = ma_noise_f32_pink(pNoise, iChannel); + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } + } + + return frameCount; +} + + +static MA_INLINE float ma_noise_f32_brownian(ma_noise* pNoise, ma_uint32 iChannel) +{ + double result; + + result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.brownian.accumulation[iChannel]); + result /= 1.005; /* Don't escape the -1..1 range on average. */ + + pNoise->state.brownian.accumulation[iChannel] = result; + result /= 20; + + return (float)(result * pNoise->config.amplitude); +} + +static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise* pNoise, ma_uint32 iChannel) +{ + return ma_pcm_sample_f32_to_s16(ma_noise_f32_brownian(pNoise, iChannel)); +} + +static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount) +{ + ma_uint64 iFrame; + ma_uint32 iChannel; + const ma_uint32 channels = pNoise->config.channels; + MA_ASSUME(channels > 0); + + if (pNoise->config.format == ma_format_f32) { + float* pFramesOutF32 = (float*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_brownian(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel); + } + } + } + } else if (pNoise->config.format == ma_format_s16) { + ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut; + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + ma_int16 s = ma_noise_s16_brownian(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = s; + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel); + } + } + } + } else { + const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format); + const ma_uint32 bpf = bps * channels; + + if (pNoise->config.duplicateChannels) { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + float s = ma_noise_f32_brownian(pNoise, 0); + for (iChannel = 0; iChannel < channels; iChannel += 1) { + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } else { + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < channels; iChannel += 1) { + float s = ma_noise_f32_brownian(pNoise, iChannel); + ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none); + } + } + } + } + + return frameCount; +} + +MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_uint64 framesRead = 0; + + if (pFramesRead != NULL) { + *pFramesRead = 0; + } + + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + + if (pNoise == NULL) { + return MA_INVALID_ARGS; + } + + /* 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. */ + } + } + + if (pFramesRead != NULL) { + *pFramesRead = framesRead; + } + + return MA_SUCCESS; +} +#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 +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) +/* dr_wav_c begin */ +#ifndef ma_dr_wav_c +#define ma_dr_wav_c +#ifdef __MRC__ +#pragma options opt off +#endif +#include +#include +#include +#ifndef MA_DR_WAV_NO_STDIO +#include +#ifndef MA_DR_WAV_NO_WCHAR +#include +#endif +#endif +#ifndef MA_DR_WAV_ASSERT +#include +#define MA_DR_WAV_ASSERT(expression) assert(expression) +#endif +#ifndef MA_DR_WAV_MALLOC +#define MA_DR_WAV_MALLOC(sz) malloc((sz)) +#endif +#ifndef MA_DR_WAV_REALLOC +#define MA_DR_WAV_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef MA_DR_WAV_FREE +#define MA_DR_WAV_FREE(p) free((p)) +#endif +#ifndef MA_DR_WAV_COPY_MEMORY +#define MA_DR_WAV_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)) +#endif +#ifndef MA_DR_WAV_ZERO_OBJECT +#define MA_DR_WAV_ZERO_OBJECT(p) MA_DR_WAV_ZERO_MEMORY((p), sizeof(*p)) +#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 +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define MA_DR_WAV_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define MA_DR_WAV_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 + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC + #endif +#endif +MA_API void ma_dr_wav_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +{ + if (pMajor) { + *pMajor = MA_DR_WAV_VERSION_MAJOR; + } + if (pMinor) { + *pMinor = MA_DR_WAV_VERSION_MINOR; + } + if (pRevision) { + *pRevision = MA_DR_WAV_VERSION_REVISION; + } +} +MA_API const char* ma_dr_wav_version_string(void) +{ + return MA_DR_WAV_VERSION_STRING; +} +#ifndef MA_DR_WAV_MAX_SAMPLE_RATE +#define MA_DR_WAV_MAX_SAMPLE_RATE 384000 +#endif +#ifndef MA_DR_WAV_MAX_CHANNELS +#define MA_DR_WAV_MAX_CHANNELS 256 +#endif +#ifndef MA_DR_WAV_MAX_BITS_PER_SAMPLE +#define MA_DR_WAV_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) +{ +#if defined(MA_X86) || defined(MA_X64) + return MA_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return MA_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) +{ + int i; + for (i = 0; i < 16; ++i) { + guid[i] = data[i]; + } +} +static MA_INLINE ma_uint16 ma_dr_wav__bswap16(ma_uint16 n) +{ +#ifdef MA_DR_WAV_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} +static MA_INLINE ma_uint32 ma_dr_wav__bswap32(ma_uint32 n) +{ +#ifdef MA_DR_WAV_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; + __asm__ __volatile__ ( + #if defined(MA_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} +static MA_INLINE ma_uint64 ma_dr_wav__bswap64(ma_uint64 n) +{ +#ifdef MA_DR_WAV_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #else + #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); +#endif +} +static MA_INLINE ma_int16 ma_dr_wav__bswap_s16(ma_int16 n) +{ + return (ma_int16)ma_dr_wav__bswap16((ma_uint16)n); +} +static MA_INLINE void ma_dr_wav__bswap_samples_s16(ma_int16* pSamples, ma_uint64 sampleCount) +{ + ma_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = ma_dr_wav__bswap_s16(pSamples[iSample]); + } +} +static MA_INLINE void ma_dr_wav__bswap_s24(ma_uint8* p) +{ + ma_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) +{ + ma_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + ma_uint8* pSample = pSamples + (iSample*3); + ma_dr_wav__bswap_s24(pSample); + } +} +static MA_INLINE ma_int32 ma_dr_wav__bswap_s32(ma_int32 n) +{ + return (ma_int32)ma_dr_wav__bswap32((ma_uint32)n); +} +static MA_INLINE void ma_dr_wav__bswap_samples_s32(ma_int32* pSamples, ma_uint64 sampleCount) +{ + ma_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = ma_dr_wav__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) +{ + union { + ma_uint32 i; + float f; + } x; + x.f = n; + x.i = ma_dr_wav__bswap32(x.i); + return x.f; +} +static MA_INLINE void ma_dr_wav__bswap_samples_f32(float* pSamples, ma_uint64 sampleCount) +{ + ma_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = ma_dr_wav__bswap_f32(pSamples[iSample]); + } +} +static MA_INLINE void ma_dr_wav__bswap_samples(void* pSamples, ma_uint64 sampleCount, ma_uint32 bytesPerSample) +{ + switch (bytesPerSample) + { + case 1: + { + } break; + case 2: + { + ma_dr_wav__bswap_samples_s16((ma_int16*)pSamples, sampleCount); + } break; + case 3: + { + ma_dr_wav__bswap_samples_s24((ma_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); + } break; + default: + { + MA_DR_WAV_ASSERT(MA_FALSE); + } break; + } +} +MA_PRIVATE MA_INLINE ma_bool32 ma_dr_wav_is_container_be(ma_dr_wav_container container) +{ + if (container == ma_dr_wav_container_rifx || container == ma_dr_wav_container_aiff) { + return MA_TRUE; + } else { + return MA_FALSE; + } +} +MA_PRIVATE MA_INLINE ma_uint16 ma_dr_wav_bytes_to_u16_le(const ma_uint8* data) +{ + 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); + } +} +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) +{ + (void)pUserData; + return MA_DR_WAV_MALLOC(sz); +} +MA_PRIVATE void* ma_dr_wav__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_DR_WAV_REALLOC(p, sz); +} +MA_PRIVATE void ma_dr_wav__free_default(void* p, void* pUserData) +{ + (void)pUserData; + MA_DR_WAV_FREE(p); +} +MA_PRIVATE void* ma_dr_wav__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); + } + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + return NULL; +} +MA_PRIVATE void* ma_dr_wav__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); + } + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + if (p != NULL) { + MA_DR_WAV_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) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} +MA_PRIVATE ma_allocation_callbacks ma_dr_wav_copy_allocation_callbacks_or_defaults(const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + return *pAllocationCallbacks; + } else { + ma_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; + return allocationCallbacks; + } +} +static MA_INLINE ma_bool32 ma_dr_wav__is_compressed_format_tag(ma_uint16 formatTag) +{ + return + formatTag == MA_DR_WAVE_FORMAT_ADPCM || + formatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM; +} +MA_PRIVATE unsigned int ma_dr_wav__chunk_padding_size_riff(ma_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 2); +} +MA_PRIVATE unsigned int ma_dr_wav__chunk_padding_size_w64(ma_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) +{ + 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 (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { + return MA_AT_END; + } + if (onRead(pUserData, sizeInBytes, 4) != 4) { + return MA_INVALID_FILE; + } + pHeaderOut->sizeInBytes = ma_dr_wav_bytes_to_u32_ex(sizeInBytes, container); + pHeaderOut->paddingSize = ma_dr_wav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 8; + } else if (container == ma_dr_wav_container_w64) { + ma_uint8 sizeInBytes[8]; + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { + return MA_AT_END; + } + if (onRead(pUserData, sizeInBytes, 8) != 8) { + return MA_INVALID_FILE; + } + pHeaderOut->sizeInBytes = ma_dr_wav_bytes_to_u64(sizeInBytes) - 24; + pHeaderOut->paddingSize = ma_dr_wav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 24; + } else { + return MA_INVALID_FILE; + } + return MA_SUCCESS; +} +MA_PRIVATE ma_bool32 ma_dr_wav__seek_forward(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) +{ + ma_uint64 bytesRemainingToSeek = offset; + while (bytesRemainingToSeek > 0) { + if (bytesRemainingToSeek > 0x7FFFFFFF) { + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + return MA_FALSE; + } + bytesRemainingToSeek -= 0x7FFFFFFF; + } else { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, ma_dr_wav_seek_origin_current)) { + return MA_FALSE; + } + bytesRemainingToSeek = 0; + } + } + return MA_TRUE; +} +MA_PRIVATE ma_bool32 ma_dr_wav__seek_from_start(ma_dr_wav_seek_proc onSeek, ma_uint64 offset, void* pUserData) +{ + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_start); + } + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_start)) { + return MA_FALSE; + } + offset -= 0x7FFFFFFF; + for (;;) { + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, ma_dr_wav_seek_origin_current); + } + if (!onSeek(pUserData, 0x7FFFFFFF, ma_dr_wav_seek_origin_current)) { + return MA_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) +{ + size_t bytesRead; + MA_DR_WAV_ASSERT(onRead != NULL); + MA_DR_WAV_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) +{ + MA_DR_WAV_ASSERT(onSeek != NULL); + MA_DR_WAV_ASSERT(pCursor != NULL); + if (!onSeek(pUserData, offset, origin)) { + return MA_FALSE; + } + if (origin == ma_dr_wav_seek_origin_start) { + *pCursor = offset; + } else { + *pCursor += offset; + } + return MA_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 +{ + 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; + } else { + bytesPerFrame = 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) +{ + if (pFMT == NULL) { + return 0; + } + if (pFMT->formatTag != MA_DR_WAVE_FORMAT_EXTENSIBLE) { + return pFMT->formatTag; + } else { + return ma_dr_wav_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) +{ + if (pWav == NULL || onRead == NULL || onSeek == NULL) { + return MA_FALSE; + } + MA_DR_WAV_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); + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return MA_FALSE; + } + return MA_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) +{ + ma_result result; + ma_uint64 cursor; + ma_bool32 sequential; + ma_uint8 riff[4]; + ma_dr_wav_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; + 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; + } + 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")) { + 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; + } + for (i = 0; i < 12; ++i) { + if (riff2[i] != ma_dr_wavGUID_W64_RIFF[i+4]) { + return MA_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 { + return MA_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 == 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; + } + } else { + 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_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; + } + } 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; + } + if (!ma_dr_wav_fourcc_equal(header.id.fourcc, "ds64")) { + return MA_FALSE; + } + bytesRemainingInChunk = header.sizeInBytes + header.paddingSize; + if (!ma_dr_wav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { + return MA_FALSE; + } + bytesRemainingInChunk -= 8; + cursor += 8; + if (ma_dr_wav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return MA_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; + } + bytesRemainingInChunk -= 8; + sampleCountFromFactChunk = ma_dr_wav_bytes_to_u64(sizeBytes); + if (!ma_dr_wav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { + return MA_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; + } + 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; + } + 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; + } + 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 == 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) { + 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; + } + chunkSize -= 4; + if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM) { + sampleCountFromFactChunk = ma_dr_wav_bytes_to_u32_ex(sampleCount, pWav->container); + } 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; + } + chunkSize -= 8; + } else if (pWav->container == ma_dr_wav_container_rf64) { + } + 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_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; + } + } 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; + } + } + chunkSize += header.paddingSize; + if (ma_dr_wav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == MA_FALSE) { + break; + } + cursor += chunkSize; + } + 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 (!sequential) { + if (!ma_dr_wav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { + return MA_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; + pWav->bitsPerSample = fmt.bitsPerSample; + pWav->bytesRemaining = dataChunkSize; + pWav->translatedFormatTag = translatedFormatTag; + 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; + 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 ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + pWav->totalPCMFrameCount += blockCount; + } + } + if (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_DVI_ADPCM) { + if (pWav->channels > 2) { + ma_dr_wav_free(pWav->pMetadata, &pWav->allocationCallbacks); + return MA_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; + 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; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; + } +#endif + return MA_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) +{ + return ma_dr_wav_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) +{ + if (!ma_dr_wav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + 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); + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + return (ma_uint32)chunkSize; +} +MA_PRIVATE ma_uint32 ma_dr_wav__data_chunk_size_riff(ma_uint64 dataChunkSize) +{ + if (dataChunkSize <= 0xFFFFFFFFUL) { + return (ma_uint32)dataChunkSize; + } else { + return 0xFFFFFFFFUL; + } +} +MA_PRIVATE ma_uint64 ma_dr_wav__riff_chunk_size_w64(ma_uint64 dataChunkSize) +{ + ma_uint64 dataSubchunkPaddingSize = ma_dr_wav__chunk_padding_size_w64(dataChunkSize); + return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; +} +MA_PRIVATE ma_uint64 ma_dr_wav__data_chunk_size_w64(ma_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) +{ + 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); + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + return chunkSize; +} +MA_PRIVATE ma_uint64 ma_dr_wav__data_chunk_size_rf64(ma_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) +{ + if (pWav == NULL || onWrite == NULL) { + return MA_FALSE; + } + if (!isSequential && onSeek == NULL) { + return MA_FALSE; + } + if (pFormat->format == MA_DR_WAVE_FORMAT_EXTENSIBLE) { + return MA_FALSE; + } + if (pFormat->format == MA_DR_WAVE_FORMAT_ADPCM || pFormat->format == MA_DR_WAVE_FORMAT_DVI_ADPCM) { + return MA_FALSE; + } + MA_DR_WAV_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); + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return MA_FALSE; + } + pWav->fmt.formatTag = (ma_uint16)pFormat->format; + pWav->fmt.channels = (ma_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.extendedSize = 0; + pWav->isSequentialWrite = isSequential; + return MA_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) +{ + size_t runningPos = 0; + ma_uint64 initialDataChunkSize = 0; + ma_uint64 chunkSizeFMT; + if (pWav->isSequentialWrite) { + initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; + if (pFormat->container == ma_dr_wav_container_riff) { + if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { + return MA_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 == 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 == ma_dr_wav_container_riff || pFormat->container == ma_dr_wav_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) { + 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 += 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); + } + pWav->container = pFormat->container; + pWav->channels = (ma_uint16)pFormat->channels; + pWav->sampleRate = pFormat->sampleRate; + pWav->bitsPerSample = (ma_uint16)pFormat->bitsPerSample; + pWav->translatedFormatTag = (ma_uint16)pFormat->format; + pWav->dataChunkDataPos = runningPos; + return MA_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) +{ + if (!ma_dr_wav_preinit_write(pWav, pFormat, MA_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + if (!ma_dr_wav_preinit_write(pWav, pFormat, MA_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + if (pFormat == NULL) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + 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); + fileSizeBytes = (8 + riffChunkSizeBytes); + } else if (pFormat->container == ma_dr_wav_container_w64) { + riffChunkSizeBytes = ma_dr_wav__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); + 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) +{ + 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) +{ + 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) +{ + return fseek((FILE*)pUserData, offset, (origin == ma_dr_wav_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) +{ + return ma_dr_wav_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) +{ + 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) { + fclose(pFile); + return result; + } + result = ma_dr_wav_init__internal(pWav, onChunk, pChunkUserData, flags); + if (result != MA_TRUE) { + fclose(pFile); + return result; + } + return MA_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) +{ + FILE* pFile; + if (ma_fopen(&pFile, filename, "rb") != MA_SUCCESS) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + return ma_dr_wav_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) +{ + 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, 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) +{ + 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) { + fclose(pFile); + return result; + } + result = ma_dr_wav_init_write__internal(pWav, pFormat, totalSampleCount); + if (result != MA_TRUE) { + fclose(pFile); + return result; + } + return MA_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) +{ + FILE* pFile; + if (ma_fopen(&pFile, filename, "wb") != MA_SUCCESS) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + FILE* pFile; + if (ma_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != MA_SUCCESS) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + return ma_dr_wav_init_file_write__internal(pWav, filename, pFormat, 0, MA_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) +{ + return ma_dr_wav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, MA_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) +{ + if (pFormat == NULL) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + return ma_dr_wav_init_file_write_w__internal(pWav, filename, pFormat, 0, MA_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) +{ + return ma_dr_wav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, MA_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) +{ + if (pFormat == NULL) { + return MA_FALSE; + } + return ma_dr_wav_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) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + size_t bytesRemaining; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_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); + 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) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + MA_DR_WAV_ASSERT(pWav != NULL); + if (origin == ma_dr_wav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { + return MA_FALSE; + } + } else { + if (pWav->memoryStream.currentReadPos < (size_t)-offset) { + return MA_FALSE; + } + } + pWav->memoryStream.currentReadPos += offset; + } else { + if ((ma_uint32)offset <= pWav->memoryStream.dataSize) { + pWav->memoryStream.currentReadPos = offset; + } else { + return MA_FALSE; + } + } + return MA_TRUE; +} +MA_PRIVATE size_t ma_dr_wav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + size_t bytesRemaining; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); + bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; + if (bytesRemaining < bytesToWrite) { + void* pNewData; + size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2; + 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); + 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); + pWav->memoryStreamWrite.currentWritePos += bytesToWrite; + if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) { + pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos; + } + *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) +{ + ma_dr_wav* pWav = (ma_dr_wav*)pUserData; + MA_DR_WAV_ASSERT(pWav != NULL); + if (origin == ma_dr_wav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { + offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); + } + } else { + if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { + offset = -(int)pWav->memoryStreamWrite.currentWritePos; + } + } + pWav->memoryStreamWrite.currentWritePos += offset; + } else { + if ((ma_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + pWav->memoryStreamWrite.currentWritePos = offset; + } else { + pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; + } + } + return MA_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) +{ + return ma_dr_wav_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) +{ + 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, 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) +{ + if (ppData == NULL || pDataSize == NULL) { + return MA_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; + } + 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); +} +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) +{ + return ma_dr_wav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, MA_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) +{ + return ma_dr_wav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, MA_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) +{ + if (pFormat == NULL) { + return MA_FALSE; + } + return ma_dr_wav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} +MA_API ma_result ma_dr_wav_uninit(ma_dr_wav* pWav) +{ + ma_result result = MA_SUCCESS; + if (pWav == NULL) { + return MA_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); + } else { + paddingSize = ma_dr_wav__chunk_padding_size_w64(pWav->dataChunkDataSize); + } + if (paddingSize > 0) { + ma_uint64 paddingData = 0; + ma_dr_wav__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->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); + } + } 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); + } + 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); + } + } else if (pWav->container == ma_dr_wav_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 + 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->isSequentialWrite) { + if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { + result = MA_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) { + 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) +{ + 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 { + bytesRead = 0; + while (bytesRead < bytesToRead) { + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > 0x7FFFFFFF) { + bytesToSeek = 0x7FFFFFFF; + } + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, ma_dr_wav_seek_origin_current) == MA_FALSE) { + break; + } + bytesRead += bytesToSeek; + } + while (bytesRead < bytesToRead) { + ma_uint8 buffer[4096]; + size_t bytesSeeked; + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > sizeof(buffer)) { + bytesToSeek = sizeof(buffer); + } + bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek); + bytesRead += bytesSeeked; + if (bytesSeeked < bytesToSeek) { + break; + } + } + } + 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) +{ + ma_uint32 bytesPerFrame; + ma_uint64 bytesToRead; + ma_uint64 framesRemainingInFile; + if (pWav == NULL || framesToRead == 0) { + return 0; + } + if (ma_dr_wav__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); + if (bytesPerFrame == 0) { + return 0; + } + bytesToRead = framesToRead * bytesPerFrame; + if (bytesToRead > MA_SIZE_MAX) { + bytesToRead = (MA_SIZE_MAX / bytesPerFrame) * bytesPerFrame; + } + if (bytesToRead == 0) { + return 0; + } + return ma_dr_wav_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) +{ + ma_uint64 framesRead = ma_dr_wav_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); + } + return framesRead; +} +MA_API ma_uint64 ma_dr_wav_read_pcm_frames(ma_dr_wav* pWav, ma_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); + } else { + framesRead = ma_dr_wav_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) +{ + if (pWav->onWrite != NULL) { + return MA_FALSE; + } + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, ma_dr_wav_seek_origin_start)) { + return MA_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); + } else { + MA_DR_WAV_ASSERT(MA_FALSE); + } + } + pWav->readCursorInPCMFrames = 0; + pWav->bytesRemaining = pWav->dataChunkDataSize; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_wav_seek_to_pcm_frame(ma_dr_wav* pWav, ma_uint64 targetFrameIndex) +{ + if (pWav == NULL || pWav->onSeek == NULL) { + return MA_FALSE; + } + if (pWav->onWrite != NULL) { + return MA_FALSE; + } + if (pWav->totalPCMFrameCount == 0) { + return MA_TRUE; + } + if (targetFrameIndex > pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount; + } + 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 (targetFrameIndex > pWav->readCursorInPCMFrames) { + ma_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames; + ma_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; + } + 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); + } else { + MA_DR_WAV_ASSERT(MA_FALSE); + } + if (framesRead != framesToRead) { + return MA_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; + currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + targetBytePos = targetFrameIndex * bytesPerFrame; + if (currentBytePos < targetBytePos) { + offset = (targetBytePos - currentBytePos); + } else { + if (!ma_dr_wav_seek_to_first_pcm_frame(pWav)) { + return MA_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; + } + pWav->readCursorInPCMFrames += offset32 / bytesPerFrame; + pWav->bytesRemaining -= offset32; + offset -= offset32; + } + } + return MA_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) +{ + size_t bytesWritten; + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { + return 0; + } + bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + 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) +{ + ma_uint64 bytesToWrite; + ma_uint64 bytesWritten; + const ma_uint8* pRunningData; + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > MA_SIZE_MAX) { + return 0; + } + bytesWritten = 0; + pRunningData = (const ma_uint8*)pData; + while (bytesToWrite > 0) { + size_t bytesJustWritten; + ma_uint64 bytesToWriteThisIteration; + bytesToWriteThisIteration = bytesToWrite; + MA_DR_WAV_ASSERT(bytesToWriteThisIteration <= MA_SIZE_MAX); + bytesJustWritten = ma_dr_wav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + if (bytesJustWritten == 0) { + break; + } + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + 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) +{ + ma_uint64 bytesToWrite; + ma_uint64 bytesWritten; + ma_uint32 bytesPerSample; + const ma_uint8* pRunningData; + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > MA_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; + } + while (bytesToWrite > 0) { + ma_uint8 temp[4096]; + ma_uint32 sampleCount; + size_t bytesJustWritten; + ma_uint64 bytesToWriteThisIteration; + bytesToWriteThisIteration = bytesToWrite; + MA_DR_WAV_ASSERT(bytesToWriteThisIteration <= MA_SIZE_MAX); + sampleCount = sizeof(temp)/bytesPerSample; + if (bytesToWriteThisIteration > ((ma_uint64)sampleCount)*bytesPerSample) { + bytesToWriteThisIteration = ((ma_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); + if (bytesJustWritten == 0) { + break; + } + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + 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) +{ + if (ma_dr_wav__is_little_endian()) { + return ma_dr_wav_write_pcm_frames_le(pWav, framesToWrite, pData); + } else { + return ma_dr_wav_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) +{ + 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); + if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + ma_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.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]; + 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.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) { + if (pBufferOut != NULL) { + ma_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 += pWav->channels; + } + framesToRead -= 1; + totalFramesRead += 1; + pWav->readCursorInPCMFrames += 1; + pWav->msadpcm.cachedFrameCount -= 1; + } + if (framesToRead == 0) { + break; + } + if (pWav->msadpcm.cachedFrameCount == 0) { + if (pWav->msadpcm.bytesRemainingInBlock == 0) { + continue; + } else { + ma_uint8 nibbles; + ma_int32 nibble0; + ma_int32 nibble1; + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + 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; + 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); + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + 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); + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample1; + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 2; + } else { + ma_int32 newSample0; + ma_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); + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + 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); + pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; + if (pWav->msadpcm.delta[1] < 16) { + pWav->msadpcm.delta[1] = 16; + } + pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.prevFrames[1][1] = newSample1; + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 1; + } + } + } + } + return totalFramesRead; +} +MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__ima(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) +{ + ma_uint64 totalFramesRead = 0; + ma_uint32 iChannel; + static ma_int32 indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + static ma_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, + 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, + 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 + }; + MA_DR_WAV_ASSERT(pWav != NULL); + MA_DR_WAV_ASSERT(framesToRead > 0); + while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + MA_DR_WAV_ASSERT(framesToRead > 0); + if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + ma_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); + 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.cachedFrameCount = 1; + } else { + ma_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); + 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.cachedFrameCount = 1; + } + } + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + ma_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 += pWav->channels; + } + framesToRead -= 1; + totalFramesRead += 1; + pWav->readCursorInPCMFrames += 1; + pWav->ima.cachedFrameCount -= 1; + } + if (framesToRead == 0) { + break; + } + if (pWav->ima.cachedFrameCount == 0) { + if (pWav->ima.bytesRemainingInBlock == 0) { + continue; + } else { + pWav->ima.cachedFrameCount = 8; + for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { + ma_uint32 iByte; + ma_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; + 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); + 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; + step = stepTable[pWav->ima.stepIndex[iChannel]]; + predictor = pWav->ima.predictor[iChannel]; + diff = step >> 3; + if (nibble1 & 1) diff += step >> 2; + 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); + 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; + } + } + } + } + } + return totalFramesRead; +} +#ifndef MA_DR_WAV_NO_CONVERSION_API +static unsigned short g_ma_dr_wavAlawTable[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, + 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 +}; +static unsigned short g_ma_dr_wavMulawTable[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, + 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) +{ + return (short)g_ma_dr_wavAlawTable[sampleIn]; +} +static MA_INLINE ma_int16 ma_dr_wav__mulaw_to_s16(ma_uint8 sampleIn) +{ + return (short)g_ma_dr_wavMulawTable[sampleIn]; +} +MA_PRIVATE void ma_dr_wav__pcm_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + size_t i; + if (bytesPerSample == 1) { + ma_dr_wav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 2) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const ma_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + ma_dr_wav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + ma_dr_wav_s32_to_s16(pOut, (const ma_int32*)pIn, totalSampleCount); + return; + } + if (bytesPerSample > 8) { + MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + for (i = 0; i < totalSampleCount; ++i) { + ma_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; + shift += 8; + } + pIn += j; + *pOut++ = (ma_int16)((ma_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) +{ + if (bytesPerSample == 4) { + ma_dr_wav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + ma_dr_wav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + MA_DR_WAV_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) +{ + 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); + } + 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; + 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); + 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; + 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) +{ + ma_uint64 totalFramesRead; + ma_uint8 sampleData[4096] = {0}; + ma_uint32 bytesPerFrame; + ma_uint32 bytesPerSample; + ma_uint64 samplesRead; + if (pBufferOut == NULL) { + return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + } + 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; + 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); + 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; + 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) +{ + ma_uint64 totalFramesRead; + ma_uint8 sampleData[4096] = {0}; + ma_uint32 bytesPerFrame; + ma_uint32 bytesPerSample; + ma_uint64 samplesRead; + if (pBufferOut == NULL) { + return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + } + 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; + 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); + 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; + 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) +{ + ma_uint64 totalFramesRead; + ma_uint8 sampleData[4096] = {0}; + ma_uint32 bytesPerFrame; + ma_uint32 bytesPerSample; + ma_uint64 samplesRead; + if (pBufferOut == NULL) { + return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + } + 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; + 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); + 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; + 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) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_wav_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 (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM) { + return ma_dr_wav_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 == MA_DR_WAVE_FORMAT_ALAW) { + return ma_dr_wav_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 == MA_DR_WAVE_FORMAT_ADPCM) { + return ma_dr_wav_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); + } + return 0; +} +MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16le(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_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); + } + return framesRead; +} +MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s16be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_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); + } + return framesRead; +} +MA_API void ma_dr_wav_u8_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x << 8; + r = r - 32768; + pOut[i] = (short)r; + } +} +MA_API void ma_dr_wav_s24_to_s16(ma_int16* pOut, const ma_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; + 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) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x >> 16; + pOut[i] = (short)r; + } +} +MA_API void ma_dr_wav_f32_to_s16(ma_int16* pOut, const float* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + float c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5f); + r = r - 32768; + pOut[i] = (short)r; + } +} +MA_API void ma_dr_wav_f64_to_s16(ma_int16* pOut, const double* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + double x = pIn[i]; + double c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5); + r = r - 32768; + pOut[i] = (short)r; + } +} +MA_API void ma_dr_wav_alaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = ma_dr_wav__alaw_to_s16(pIn[i]); + } +} +MA_API void ma_dr_wav_mulaw_to_s16(ma_int16* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = ma_dr_wav__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) +{ + unsigned int i; + if (bytesPerSample == 1) { + ma_dr_wav_u8_to_f32(pOut, pIn, sampleCount); + return; + } + if (bytesPerSample == 2) { + ma_dr_wav_s16_to_f32(pOut, (const ma_int16*)pIn, sampleCount); + return; + } + if (bytesPerSample == 3) { + ma_dr_wav_s24_to_f32(pOut, pIn, sampleCount); + return; + } + if (bytesPerSample == 4) { + ma_dr_wav_s32_to_f32(pOut, (const ma_int32*)pIn, sampleCount); + return; + } + if (bytesPerSample > 8) { + MA_DR_WAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } + for (i = 0; i < sampleCount; ++i) { + ma_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; + shift += 8; + } + pIn += j; + *pOut++ = (float)((ma_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) +{ + if (bytesPerSample == 4) { + unsigned int i; + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((const float*)pIn)[i]; + } + return; + } else if (bytesPerSample == 8) { + ma_dr_wav_f64_to_f32(pOut, (const double*)pIn, sampleCount); + return; + } else { + MA_DR_WAV_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) +{ + 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; + 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); + 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)); + 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) +{ + 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; + 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); + 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; + 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) +{ + 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; + 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); + 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; + 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) +{ + 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; + 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); + 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; + 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) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_wav_read_pcm_frames(pWav, framesToRead, NULL); + } + if (framesToRead * pWav->channels * sizeof(float) > MA_SIZE_MAX) { + framesToRead = MA_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 == 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 == MA_DR_WAVE_FORMAT_IEEE_FLOAT) { + return ma_dr_wav_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 == MA_DR_WAVE_FORMAT_MULAW) { + return ma_dr_wav_read_pcm_frames_f32__mulaw(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) +{ + 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); + } + return framesRead; +} +MA_API ma_uint64 ma_dr_wav_read_pcm_frames_f32be(ma_dr_wav* pWav, ma_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); + } + return framesRead; +} +MA_API void ma_dr_wav_u8_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } +#ifdef MA_DR_WAV_LIBSNDFILE_COMPAT + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (pIn[i] / 256.0f) * 2 - 1; + } +#else + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + x = x * 0.00784313725490196078f; + x = x - 1; + *pOut++ = x; + } +#endif +} +MA_API void ma_dr_wav_s16_to_f32(float* pOut, const ma_int16* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] * 0.000030517578125f; + } +} +MA_API void ma_dr_wav_s24_to_f32(float* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + 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); + *pOut++ = (float)(x * 0.00000011920928955078125); + } +} +MA_API void ma_dr_wav_s32_to_f32(float* pOut, const ma_int32* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)(pIn[i] / 2147483648.0); + } +} +MA_API void ma_dr_wav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)pIn[i]; + } +} +MA_API void ma_dr_wav_alaw_to_f32(float* pOut, const ma_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; + } +} +MA_API void ma_dr_wav_mulaw_to_f32(float* pOut, const ma_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; + } +} +MA_PRIVATE void ma_dr_wav__pcm_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + if (bytesPerSample == 1) { + ma_dr_wav_u8_to_s32(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 2) { + ma_dr_wav_s16_to_s32(pOut, (const ma_int16*)pIn, totalSampleCount); + return; + } + if (bytesPerSample == 3) { + ma_dr_wav_s24_to_s32(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const ma_int32*)pIn)[i]; + } + return; + } + if (bytesPerSample > 8) { + MA_DR_WAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + for (i = 0; i < totalSampleCount; ++i) { + ma_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; + shift += 8; + } + pIn += j; + *pOut++ = (ma_int32)((ma_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) +{ + if (bytesPerSample == 4) { + ma_dr_wav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + ma_dr_wav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + MA_DR_WAV_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) +{ + 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); + } + 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; + 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); + 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)); + 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) +{ + 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; + 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); + 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; + 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) +{ + 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; + 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); + 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; + 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) +{ + 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; + 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); + 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; + 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) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_wav_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 (pWav->translatedFormatTag == MA_DR_WAVE_FORMAT_PCM) { + return ma_dr_wav_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 == MA_DR_WAVE_FORMAT_IEEE_FLOAT) { + return ma_dr_wav_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 == MA_DR_WAVE_FORMAT_MULAW) { + return ma_dr_wav_read_pcm_frames_s32__mulaw(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) +{ + 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); + } + return framesRead; +} +MA_API ma_uint64 ma_dr_wav_read_pcm_frames_s32be(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_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); + } + return framesRead; +} +MA_API void ma_dr_wav_u8_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + *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) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] << 16; + } +} +MA_API void ma_dr_wav_s24_to_s32(ma_int32* pOut, const ma_uint8* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + for (i = 0; i < sampleCount; ++i) { + 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)); + *pOut++ = sample32; + } +} +MA_API void ma_dr_wav_f32_to_s32(ma_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]); + } +} +MA_API void ma_dr_wav_f64_to_s32(ma_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]); + } +} +MA_API void ma_dr_wav_alaw_to_s32(ma_int32* pOut, const ma_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; + } +} +MA_API void ma_dr_wav_mulaw_to_s32(ma_int32* pOut, const ma_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; + } +} +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) +{ + 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); + return NULL; + } + pSampleData = (ma_int16*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + if (pSampleData == NULL) { + ma_dr_wav_uninit(pWav); + return NULL; + } + framesRead = ma_dr_wav_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); + return NULL; + } + ma_dr_wav_uninit(pWav); + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + 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) +{ + ma_uint64 sampleDataSize; + float* pSampleData; + ma_uint64 framesRead; + MA_DR_WAV_ASSERT(pWav != NULL); + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); + if (sampleDataSize > MA_SIZE_MAX) { + ma_dr_wav_uninit(pWav); + return NULL; + } + pSampleData = (float*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + if (pSampleData == NULL) { + ma_dr_wav_uninit(pWav); + return NULL; + } + framesRead = ma_dr_wav_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); + return NULL; + } + ma_dr_wav_uninit(pWav); + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + 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) +{ + 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); + return NULL; + } + pSampleData = (ma_int32*)ma_dr_wav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); + if (pSampleData == NULL) { + ma_dr_wav_uninit(pWav); + return NULL; + } + framesRead = ma_dr_wav_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); + return NULL; + } + ma_dr_wav_uninit(pWav); + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + 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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + ma_dr_wav wav; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + if (!ma_dr_wav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_wav__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) +{ + if (pAllocationCallbacks != NULL) { + ma_dr_wav__free_from_callbacks(p, pAllocationCallbacks); + } else { + ma_dr_wav__free_default(p, NULL); + } +} +MA_API ma_uint16 ma_dr_wav_bytes_to_u16(const ma_uint8* data) +{ + return ((ma_uint16)data[0] << 0) | ((ma_uint16)data[1] << 8); +} +MA_API ma_int16 ma_dr_wav_bytes_to_s16(const ma_uint8* data) +{ + return (ma_int16)ma_dr_wav_bytes_to_u16(data); +} +MA_API ma_uint32 ma_dr_wav_bytes_to_u32(const ma_uint8* data) +{ + return ma_dr_wav_bytes_to_u32_le(data); +} +MA_API float ma_dr_wav_bytes_to_f32(const ma_uint8* data) +{ + union { + ma_uint32 u32; + float f32; + } value; + value.u32 = ma_dr_wav_bytes_to_u32(data); + return value.f32; +} +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) +{ + 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); +} +MA_API ma_int64 ma_dr_wav_bytes_to_s64(const ma_uint8* data) +{ + return (ma_int64)ma_dr_wav_bytes_to_u64(data); +} +MA_API ma_bool32 ma_dr_wav_guid_equal(const ma_uint8 a[16], const ma_uint8 b[16]) +{ + int i; + for (i = 0; i < 16; i += 1) { + if (a[i] != b[i]) { + return MA_FALSE; + } + } + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) +{ + return + a[0] == b[0] && + a[1] == b[1] && + 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 /* MA_NO_WAV */ + +#if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) +#if !defined(MA_DR_FLAC_IMPLEMENTATION) +/* dr_flac_c begin */ +#ifndef ma_dr_flac_c +#define ma_dr_flac_c +#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 +#ifdef __linux__ + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + #ifndef __USE_BSD + #define __USE_BSD + #endif + #include +#endif +#include +#include +#if !defined(MA_DR_FLAC_NO_SIMD) + #if defined(MA_X64) || defined(MA_X86) + #if defined(_MSC_VER) && !defined(__clang__) + #if _MSC_VER >= 1400 && !defined(MA_DR_FLAC_NO_SSE2) + #define MA_DR_FLAC_SUPPORT_SSE2 + #endif + #if _MSC_VER >= 1600 && !defined(MA_DR_FLAC_NO_SSE41) + #define MA_DR_FLAC_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 + #endif + #if defined(__SSE4_1__) && !defined(MA_DR_FLAC_NO_SSE41) + #define MA_DR_FLAC_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 + #endif + #if !defined(MA_DR_FLAC_SUPPORT_SSE41) && !defined(MA_DR_FLAC_NO_SSE41) && __has_include() + #define MA_DR_FLAC_SUPPORT_SSE41 + #endif + #endif + #if defined(MA_DR_FLAC_SUPPORT_SSE41) + #include + #elif defined(MA_DR_FLAC_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 + #include + #endif + #endif +#endif +#if !defined(MA_DR_FLAC_NO_SIMD) && (defined(MA_X86) || defined(MA_X64)) + #if defined(_MSC_VER) && !defined(__clang__) + #if _MSC_VER >= 1400 + #include + static void ma_dr_flac__cpuid(int info[4], int fid) + { + __cpuid(info, fid); + } + #else + #define MA_DR_FLAC_NO_CPUID + #endif + #else + #if defined(__GNUC__) || defined(__clang__) + static void ma_dr_flac__cpuid(int info[4], int fid) + { + #if defined(MA_X86) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg{l} {%%}ebx, %k1;" + "cpuid;" + "xchg{l} {%%}ebx, %k1;" + : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #else + __asm__ __volatile__ ( + "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #endif + } + #else + #define MA_DR_FLAC_NO_CPUID + #endif + #endif +#else + #define MA_DR_FLAC_NO_CPUID +#endif +static MA_INLINE ma_bool32 ma_dr_flac_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; + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) + return MA_TRUE; + #else + #if defined(MA_DR_FLAC_NO_CPUID) + return MA_FALSE; + #else + int info[4]; + ma_dr_flac__cpuid(info, 1); + return (info[3] & (1 << 26)) != 0; + #endif + #endif + #else + return MA_FALSE; + #endif +#else + return MA_FALSE; +#endif +} +static MA_INLINE ma_bool32 ma_dr_flac_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; + #else + #if defined(MA_DR_FLAC_NO_CPUID) + return MA_FALSE; + #else + int info[4]; + ma_dr_flac__cpuid(info, 1); + return (info[2] & (1 << 19)) != 0; + #endif + #endif + #else + return MA_FALSE; + #endif +#else + return MA_FALSE; +#endif +} +#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(MA_X86) || defined(MA_X64)) && !defined(__clang__) + #define MA_DR_FLAC_HAS_LZCNT_INTRINSIC +#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #define MA_DR_FLAC_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 + #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 +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define MA_DR_FLAC_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define MA_DR_FLAC_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 + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define MA_DR_FLAC_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); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + value [ax] \ + modify nomemory; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + value [eax] \ + modify nomemory; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + value [eax edx] \ + modify nomemory; +#endif +#ifndef MA_DR_FLAC_ASSERT +#include +#define MA_DR_FLAC_ASSERT(expression) assert(expression) +#endif +#ifndef MA_DR_FLAC_MALLOC +#define MA_DR_FLAC_MALLOC(sz) malloc((sz)) +#endif +#ifndef MA_DR_FLAC_REALLOC +#define MA_DR_FLAC_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef MA_DR_FLAC_FREE +#define MA_DR_FLAC_FREE(p) free((p)) +#endif +#ifndef MA_DR_FLAC_COPY_MEMORY +#define MA_DR_FLAC_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)) +#endif +#ifndef MA_DR_FLAC_ZERO_OBJECT +#define MA_DR_FLAC_ZERO_OBJECT(p) MA_DR_FLAC_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) +{ + if (pMajor) { + *pMajor = MA_DR_FLAC_VERSION_MAJOR; + } + if (pMinor) { + *pMinor = MA_DR_FLAC_VERSION_MINOR; + } + if (pRevision) { + *pRevision = MA_DR_FLAC_VERSION_REVISION; + } +} +MA_API const char* ma_dr_flac_version_string(void) +{ + return MA_DR_FLAC_VERSION_STRING; +} +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #define MA_DR_FLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #else + #define MA_DR_FLAC_NO_THREAD_SANITIZE + #endif +#else + #define MA_DR_FLAC_NO_THREAD_SANITIZE +#endif +#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) +static ma_bool32 ma_dr_flac__gIsLZCNTSupported = MA_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) +{ + static ma_bool32 isCPUCapsInitialized = MA_FALSE; + if (!isCPUCapsInitialized) { +#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) + int info[4] = {0}; + ma_dr_flac__cpuid(info, 0x80000001); + ma_dr_flac__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; + } +} +#else +static ma_bool32 ma_dr_flac__gIsNEONSupported = MA_FALSE; +static MA_INLINE ma_bool32 ma_dr_flac__has_neon(void) +{ +#if defined(MA_DR_FLAC_SUPPORT_NEON) + #if defined(MA_ARM) && !defined(MA_DR_FLAC_NO_NEON) + #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + return MA_TRUE; + #else + return MA_FALSE; + #endif + #else + return MA_FALSE; + #endif +#else + return MA_FALSE; +#endif +} +MA_DR_FLAC_NO_THREAD_SANITIZE static void ma_dr_flac__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; +#endif +} +#endif +static MA_INLINE ma_bool32 ma_dr_flac__is_little_endian(void) +{ +#if defined(MA_X86) || defined(MA_X64) + return MA_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return MA_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} +static MA_INLINE ma_uint16 ma_dr_flac__swap_endian_uint16(ma_uint16 n) +{ +#ifdef MA_DR_FLAC_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} +static MA_INLINE ma_uint32 ma_dr_flac__swap_endian_uint32(ma_uint32 n) +{ +#ifdef MA_DR_FLAC_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; + __asm__ __volatile__ ( + #if defined(MA_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} +static MA_INLINE ma_uint64 ma_dr_flac__swap_endian_uint64(ma_uint64 n) +{ +#ifdef MA_DR_FLAC_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); + #else + #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); +#endif +} +static MA_INLINE ma_uint16 ma_dr_flac__be2host_16(ma_uint16 n) +{ + if (ma_dr_flac__is_little_endian()) { + return ma_dr_flac__swap_endian_uint16(n); + } + return n; +} +static MA_INLINE ma_uint32 ma_dr_flac__be2host_32(ma_uint32 n) +{ + if (ma_dr_flac__is_little_endian()) { + return ma_dr_flac__swap_endian_uint32(n); + } + return n; +} +static MA_INLINE ma_uint32 ma_dr_flac__be2host_32_ptr_unaligned(const void* pData) +{ + 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); + } + return n; +} +static MA_INLINE ma_uint32 ma_dr_flac__le2host_32(ma_uint32 n) +{ + if (!ma_dr_flac__is_little_endian()) { + return ma_dr_flac__swap_endian_uint32(n); + } + return n; +} +static MA_INLINE ma_uint32 ma_dr_flac__le2host_32_ptr_unaligned(const void* pData) +{ + 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; + 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[] = { + 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, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 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[] = { + 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, + 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, + 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1, + 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, + 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, + 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, + 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, + 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2, + 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342, + 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, + 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, + 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, + 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, + 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2, + 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, + 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, + 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261, + 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) +{ + return ma_dr_flac__crc8_table[crc ^ data]; +} +static MA_INLINE ma_uint8 ma_dr_flac_crc8(ma_uint8 crc, ma_uint32 data, ma_uint32 count) +{ +#ifdef MA_DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + ma_uint8 p = 0x07; + for (int i = count-1; i >= 0; --i) { + ma_uint8 bit = (data & (1 << i)) >> i; + if (crc & 0x80) { + crc = ((crc << 1) | bit) ^ p; + } else { + crc = ((crc << 1) | bit); + } + } + return crc; +#else + ma_uint32 wholeBytes; + ma_uint32 leftoverBits; + ma_uint64 leftoverDataMask; + static ma_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + MA_DR_FLAC_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)]); + } + return crc; +#endif +#endif +} +static MA_INLINE ma_uint16 ma_dr_flac_crc16_byte(ma_uint16 crc, ma_uint8 data) +{ + return (crc << 8) ^ ma_dr_flac__crc16_table[(ma_uint8)(crc >> 8) ^ data]; +} +static MA_INLINE ma_uint16 ma_dr_flac_crc16_cache(ma_uint16 crc, ma_dr_flac_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)); +#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)); + return crc; +} +static MA_INLINE ma_uint16 ma_dr_flac_crc16_bytes(ma_uint16 crc, ma_dr_flac_cache_t data, ma_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)); +#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)); + } + return crc; +} +#if 0 +static MA_INLINE ma_uint16 ma_dr_flac_crc16__32bit(ma_uint16 crc, ma_uint32 data, ma_uint32 count) +{ +#ifdef MA_DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + ma_uint16 p = 0x8005; + for (int i = count-1; i >= 0; --i) { + ma_uint16 bit = (data & (1ULL << i)) >> i; + if (r & 0x8000) { + r = ((r << 1) | bit) ^ p; + } else { + r = ((r << 1) | bit); + } + } + return crc; +#else + ma_uint32 wholeBytes; + ma_uint32 leftoverBits; + ma_uint64 leftoverDataMask; + static ma_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + MA_DR_FLAC_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)]; + } + return crc; +#endif +#endif +} +static MA_INLINE ma_uint16 ma_dr_flac_crc16__64bit(ma_uint16 crc, ma_uint64 data, ma_uint32 count) +{ +#ifdef MA_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] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + MA_DR_FLAC_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)]; + } + return crc; +#endif +} +static MA_INLINE ma_uint16 ma_dr_flac_crc16(ma_uint16 crc, ma_dr_flac_cache_t data, ma_uint32 count) +{ +#ifdef MA_64BIT + return ma_dr_flac_crc16__64bit(crc, data, count); +#else + return ma_dr_flac_crc16__32bit(crc, data, count); +#endif +} +#endif +#ifdef MA_64BIT +#define ma_dr_flac__be2host__cache_line ma_dr_flac__be2host_64 +#else +#define ma_dr_flac__be2host__cache_line ma_dr_flac__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) +{ + bs->crc16 = 0; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +} +static MA_INLINE void ma_dr_flac__update_crc16(ma_dr_flac_bs* bs) +{ + if (bs->crc16CacheIgnoredBytes == 0) { + bs->crc16 = ma_dr_flac_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->crc16CacheIgnoredBytes = 0; + } +} +static MA_INLINE ma_uint16 ma_dr_flac__flush_crc16(ma_dr_flac_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); + } 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->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) +{ + size_t bytesRead; + size_t alignedL1LineCount; + if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return MA_TRUE; + } + if (bs->unalignedByteCount > 0) { + return MA_FALSE; + } + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs)); + bs->nextL2Line = 0; + if (bytesRead == MA_DR_FLAC_CACHE_L2_SIZE_BYTES(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return MA_TRUE; + } + alignedL1LineCount = bytesRead / MA_DR_FLAC_CACHE_L1_SIZE_BYTES(bs); + bs->unalignedByteCount = bytesRead - (alignedL1LineCount * MA_DR_FLAC_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 i; + for (i = alignedL1LineCount; i > 0; --i) { + bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; + } + bs->nextL2Line = (ma_uint32)offset; + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return MA_TRUE; + } else { + bs->nextL2Line = MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs); + return MA_FALSE; + } +} +static ma_bool32 ma_dr_flac__reload_cache(ma_dr_flac_bs* bs) +{ + size_t bytesRead; +#ifndef MA_DR_FLAC_NO_CRC + ma_dr_flac__update_crc16(bs); +#endif + if (ma_dr_flac__reload_l1_cache_from_l2(bs)) { + bs->cache = ma_dr_flac__be2host__cache_line(bs->cache); + bs->consumedBits = 0; +#ifndef MA_DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + return MA_TRUE; + } + bytesRead = bs->unalignedByteCount; + if (bytesRead == 0) { + bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + return MA_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)); + bs->unalignedByteCount = 0; +#ifndef MA_DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache >> bs->consumedBits; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +#endif + return MA_TRUE; +} +static void ma_dr_flac__reset_cache(ma_dr_flac_bs* bs) +{ + bs->nextL2Line = MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs); + bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + bs->cache = 0; + bs->unalignedByteCount = 0; + bs->unalignedCache = 0; +#ifndef MA_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) +{ + 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; + } + } + 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); + 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); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; + } else { + *pResultOut = (ma_uint32)bs->cache; + bs->consumedBits = MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + bs->cache = 0; + } +#endif + return MA_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; + } + 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); + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + return MA_TRUE; + } +} +static ma_bool32 ma_dr_flac__read_int32(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + if (bitCount < 32) { + ma_uint32 signbit; + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + } + *pResult = (ma_int32)result; + return MA_TRUE; +} +#ifdef MA_64BIT +static ma_bool32 ma_dr_flac__read_uint64(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + if (!ma_dr_flac__read_uint32(bs, 32, &resultLo)) { + return MA_FALSE; + } + *pResultOut = (((ma_uint64)resultHi) << 32) | ((ma_uint64)resultLo); + return MA_TRUE; +} +#endif +#if 0 +static ma_bool32 ma_dr_flac__read_int64(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + *pResultOut = (ma_int64)result; + return MA_TRUE; +} +#endif +static ma_bool32 ma_dr_flac__read_uint16(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + *pResult = (ma_uint16)result; + return MA_TRUE; +} +#if 0 +static ma_bool32 ma_dr_flac__read_int16(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + *pResult = (ma_int16)result; + return MA_TRUE; +} +#endif +static ma_bool32 ma_dr_flac__read_uint8(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + *pResult = (ma_uint8)result; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__read_int8(ma_dr_flac_bs* bs, unsigned int bitCount, ma_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; + } + *pResult = (ma_int8)result; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__seek_bits(ma_dr_flac_bs* bs, size_t bitsToSeek) +{ + if (bitsToSeek <= MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs)) { + bs->consumedBits += (ma_uint32)bitsToSeek; + bs->cache <<= bitsToSeek; + return MA_TRUE; + } else { + bitsToSeek -= MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs); + bs->consumedBits += MA_DR_FLAC_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; + } + bitsToSeek -= MA_DR_FLAC_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; + } + bitsToSeek -= MA_DR_FLAC_CACHE_L1_SIZE_BITS(bs); + } +#endif + while (bitsToSeek >= 8) { + ma_uint8 bin; + if (!ma_dr_flac__read_uint8(bs, 8, &bin)) { + return MA_FALSE; + } + bitsToSeek -= 8; + } + if (bitsToSeek > 0) { + ma_uint8 bin; + if (!ma_dr_flac__read_uint8(bs, (ma_uint32)bitsToSeek, &bin)) { + return MA_FALSE; + } + bitsToSeek = 0; + } + MA_DR_FLAC_ASSERT(bitsToSeek == 0); + return MA_TRUE; + } +} +static ma_bool32 ma_dr_flac__find_and_seek_to_next_sync_code(ma_dr_flac_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; + } + for (;;) { + ma_uint8 hi; +#ifndef MA_DR_FLAC_NO_CRC + ma_dr_flac__reset_crc16(bs); +#endif + if (!ma_dr_flac__read_uint8(bs, 8, &hi)) { + return MA_FALSE; + } + if (hi == 0xFF) { + ma_uint8 lo; + if (!ma_dr_flac__read_uint8(bs, 6, &lo)) { + return MA_FALSE; + } + if (lo == 0x3E) { + return MA_TRUE; + } else { + if (!ma_dr_flac__seek_bits(bs, MA_DR_FLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return MA_FALSE; + } + } + } + } +} +#if defined(MA_DR_FLAC_HAS_LZCNT_INTRINSIC) +#define MA_DR_FLAC_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 +#endif +#if defined(__WATCOMC__) && defined(__386__) +#define MA_DR_FLAC_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) +{ + ma_uint32 n; + static ma_uint32 clz_table_4[] = { + 0, + 4, + 3, 3, + 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (x == 0) { + return sizeof(x)*8; + } + 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; } +#else + if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; } + if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; } + if ((x & 0xF0000000) == 0) { n += 4; x <<= 4; } +#endif + n += clz_table_4[x >> (sizeof(x)*8 - 4)]; + } + return n - 1; +} +#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_LZCNT +static MA_INLINE ma_bool32 ma_dr_flac__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; +#else + #ifdef MA_DR_FLAC_HAS_LZCNT_INTRINSIC + return ma_dr_flac__gIsLZCNTSupported; + #else + return MA_FALSE; + #endif +#endif +} +static MA_INLINE ma_uint32 ma_dr_flac__clz_lzcnt(ma_dr_flac_cache_t x) +{ +#if defined(_MSC_VER) + #ifdef MA_64BIT + return (ma_uint32)__lzcnt64(x); + #else + return (ma_uint32)__lzcnt(x); + #endif +#else + #if defined(__GNUC__) || defined(__clang__) + #if defined(MA_X64) + { + ma_uint64 r; + __asm__ __volatile__ ( + "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + ); + return (ma_uint32)r; + } + #elif defined(MA_X86) + { + ma_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) + { + unsigned int r; + __asm__ __volatile__ ( + #if defined(MA_64BIT) + "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) + #else + "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x) + #endif + ); + return r; + } + #else + if (x == 0) { + return sizeof(x)*8; + } + #ifdef MA_64BIT + return (ma_uint32)__builtin_clzll((ma_uint64)x); + #else + return (ma_uint32)__builtin_clzl((ma_uint32)x); + #endif + #endif + #else + #error "This compiler does not support the lzcnt intrinsic." + #endif +#endif +} +#endif +#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_MSVC +#include +static MA_INLINE ma_uint32 ma_dr_flac__clz_msvc(ma_dr_flac_cache_t x) +{ + ma_uint32 n; + if (x == 0) { + return sizeof(x)*8; + } +#ifdef MA_64BIT + _BitScanReverse64((unsigned long*)&n, x); +#else + _BitScanReverse((unsigned long*)&n, x); +#endif + 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 = \ + "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) +{ +#ifdef MA_DR_FLAC_IMPLEMENT_CLZ_LZCNT + if (ma_dr_flac__is_lzcnt_supported()) { + return ma_dr_flac__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); +#else + return ma_dr_flac__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) +{ + ma_uint32 zeroCounter = 0; + ma_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; + } + } + 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 += 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; +} +static ma_bool32 ma_dr_flac__seek_to_byte(ma_dr_flac_bs* bs, ma_uint64 offsetFromStart) +{ + MA_DR_FLAC_ASSERT(bs != NULL); + MA_DR_FLAC_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; + } + bytesRemaining -= 0x7FFFFFFF; + while (bytesRemaining > 0x7FFFFFFF) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + bytesRemaining -= 0x7FFFFFFF; + } + if (bytesRemaining > 0) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + } + } else { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, ma_dr_flac_seek_origin_start)) { + return MA_FALSE; + } + } + ma_dr_flac__reset_cache(bs); + return MA_TRUE; +} +static ma_result ma_dr_flac__read_utf8_coded_number(ma_dr_flac_bs* bs, ma_uint64* pNumberOut, ma_uint8* pCRCOut) +{ + ma_uint8 crc; + ma_uint64 result; + ma_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); + crc = *pCRCOut; + if (!ma_dr_flac__read_uint8(bs, 8, utf8)) { + *pNumberOut = 0; + return MA_AT_END; + } + crc = ma_dr_flac_crc8(crc, utf8[0], 8); + if ((utf8[0] & 0x80) == 0) { + *pNumberOut = utf8[0]; + *pCRCOut = crc; + return MA_SUCCESS; + } + if ((utf8[0] & 0xE0) == 0xC0) { + byteCount = 2; + } else if ((utf8[0] & 0xF0) == 0xE0) { + byteCount = 3; + } else if ((utf8[0] & 0xF8) == 0xF0) { + byteCount = 4; + } else if ((utf8[0] & 0xFC) == 0xF8) { + byteCount = 5; + } else if ((utf8[0] & 0xFE) == 0xFC) { + byteCount = 6; + } else if ((utf8[0] & 0xFF) == 0xFE) { + byteCount = 7; + } else { + *pNumberOut = 0; + return MA_CRC_MISMATCH; + } + MA_DR_FLAC_ASSERT(byteCount > 1); + result = (ma_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + for (i = 1; i < byteCount; ++i) { + if (!ma_dr_flac__read_uint8(bs, 8, utf8 + i)) { + *pNumberOut = 0; + return MA_AT_END; + } + crc = ma_dr_flac_crc8(crc, utf8[i], 8); + result = (result << 6) | (utf8[i] & 0x3F); + } + *pNumberOut = result; + *pCRCOut = crc; + return MA_SUCCESS; +} +static MA_INLINE ma_uint32 ma_dr_flac__ilog2_u32(ma_uint32 x) +{ +#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); + switch (order) + { + case 32: prediction += coefficients[31] * pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1]; + } + return (ma_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) +{ + ma_int64 prediction; + MA_DR_FLAC_ASSERT(order <= 32); +#ifndef MA_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]; + } + 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]; + } + 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]; + } + 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]; + } + 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]; + } + 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]; + } + 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]; + } + else if (order == 2) + { + prediction = coefficients[0] * (ma_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (ma_int64)pDecodedSamples[-2]; + } + else if (order == 1) + { + prediction = coefficients[0] * (ma_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]; + } + 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]; + } + 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]; + } + else + { + int j; + prediction = 0; + for (j = 0; j < (int)order; ++j) { + prediction += coefficients[j] * (ma_int64)pDecodedSamples[-j-1]; + } + } +#endif +#ifdef MA_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]; + } +#endif + return (ma_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) +{ + ma_uint32 i; + MA_DR_FLAC_ASSERT(bs != NULL); + MA_DR_FLAC_ASSERT(pSamplesOut != NULL); + for (i = 0; i < count; ++i) { + ma_uint32 zeroCounter = 0; + for (;;) { + ma_uint8 bit; + if (!ma_dr_flac__read_uint8(bs, 1, &bit)) { + return MA_FALSE; + } + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + ma_uint32 decodedRice; + if (riceParam > 0) { + if (!ma_dr_flac__read_uint32(bs, riceParam, &decodedRice)) { + return MA_FALSE; + } + } else { + decodedRice = 0; + } + decodedRice |= (zeroCounter << riceParam); + if ((decodedRice & 0x01)) { + decodedRice = ~(decodedRice >> 1); + } 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); + } else { + pSamplesOut[i] = decodedRice + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + return MA_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) +{ + ma_uint32 zeroCounter = 0; + ma_uint32 decodedRice; + for (;;) { + ma_uint8 bit; + if (!ma_dr_flac__read_uint8(bs, 1, &bit)) { + return MA_FALSE; + } + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + if (riceParam > 0) { + if (!ma_dr_flac__read_uint32(bs, riceParam, &decodedRice)) { + return MA_FALSE; + } + } else { + decodedRice = 0; + } + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = decodedRice; + return MA_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) +{ + 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); + 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; + } + } + setBitOffsetPlus1 = ma_dr_flac__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)); + bs->consumedBits += riceLength; + bs->cache <<= riceLength; + } else { + ma_uint32 bitCountLo; + ma_dr_flac_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); +#endif + bs->cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->consumedBits = 0; +#ifndef MA_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; + } + } + riceParamPart = (ma_uint32)(resultHi | MA_DR_FLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + } + pZeroCounterOut[0] = zeroCounter; + pRiceParamPartOut[0] = riceParamPart; + return MA_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) +{ + 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); + 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); + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + ma_uint32 riceParamPartHi; + ma_uint32 riceParamPartLo; + ma_uint32 riceParamPartLoBitCount; + riceParamPartHi = (ma_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); + #endif + bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef MA_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; + } + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + riceParamPartLo = (ma_uint32)(bs_cache >> (MA_DR_FLAC_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); + for (;;) { + if (bs->nextL2Line < MA_DR_FLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef MA_DR_FLAC_NO_CRC + ma_dr_flac__update_crc16(bs); + #endif + bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef MA_DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + if (!ma_dr_flac__reload_cache(bs)) { + return MA_FALSE; + } + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + lzcount = ma_dr_flac__clz(bs_cache); + zeroCounter += lzcount; + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + pZeroCounterOut[0] = zeroCounter; + goto extract_rice_param_part; + } + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + return MA_TRUE; +} +static MA_INLINE ma_bool32 ma_dr_flac__seek_rice_parts(ma_dr_flac_bs* bs, ma_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); + if (lzcount < sizeof(bs_cache)*8) { + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + 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); + #endif + bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef MA_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; + } + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + bs_cache <<= riceParamPartLoBitCount; + } + } 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); + #endif + bs_cache = ma_dr_flac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef MA_DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + if (!ma_dr_flac__reload_cache(bs)) { + return MA_FALSE; + } + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + lzcount = ma_dr_flac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + goto extract_rice_param_part; + } + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + return MA_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) +{ + 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); + (void)bitsPerSample; + (void)order; + (void)shift; + (void)coefficients; + riceParamMask = (ma_uint32)~((~0UL) << riceParam); + i = 0; + while (i < count) { + if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return MA_FALSE; + } + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + pSamplesOut[i] = riceParamPart0; + i += 1; + } + return MA_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) +{ + 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); + } + riceParamMask = (ma_uint32)~((~0UL) << riceParam); + pSamplesOutEnd = pSamplesOut + (count & ~3); + if (ma_dr_flac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + 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; + } + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + 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 += 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; + } + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + 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 += 4; + } + } + i = (count & ~3); + while (i < count) { + if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return MA_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); + } else { + pSamplesOut[0] = riceParamPart0 + ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } + i += 1; + pSamplesOut += 1; + } + return MA_TRUE; +} +#if defined(MA_DR_FLAC_SUPPORT_SSE2) +static MA_INLINE __m128i ma_dr_flac__mm_packs_interleaved_epi32(__m128i a, __m128i b) +{ + __m128i r; + r = _mm_packs_epi32(a, b); + r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0)); + r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + return r; +} +#endif +#if defined(MA_DR_FLAC_SUPPORT_SSE41) +static MA_INLINE __m128i ma_dr_flac__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) +{ + __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) +{ + 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) +{ + __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) +{ + 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; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i riceParamMask128; + const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + riceParamMask = (ma_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); +#if 1 + { + int runningOrder = order; + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#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]; + } +#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; + } + 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))); + 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 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else if (order <= 8) { + 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 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else { + for (i = 0; i < 4; i += 1) { + 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 = _mm_srai_epi32(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); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + i = (count & ~3); + while (i < (int)count) { + if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return MA_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); + i += 1; + pDecodedSamples += 1; + } + return MA_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) +{ + 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; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __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); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + prediction128 = _mm_setzero_si128(); + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); +#if 1 + { + int runningOrder = order; + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#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]; + } +#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; + } + 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))); + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_xor_si128(prediction128, prediction128); + switch (order) + { + case 12: + case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0)))); + case 10: + case 9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2)))); + case 8: + case 7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0)))); + case 6: + case 5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2)))); + case 4: + case 3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0)))); + 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 = _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); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + i = (count & ~3); + while (i < (int)count) { + if (!ma_dr_flac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return MA_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); + i += 1; + pDecodedSamples += 1; + } + return MA_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) +{ + 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); + } else { + return ma_dr_flac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + 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) +{ + ma_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) +{ + return vextq_s32(b, a, 1); +} +static MA_INLINE uint32x4_t ma_dr_flac__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) +{ + 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) +{ + return vadd_s64(vget_high_s64(x), vget_low_s64(x)); +} +static MA_INLINE int32x4_t ma_dr_flac__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) +{ + return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF)); +} +static MA_INLINE uint32x4_t ma_dr_flac__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) +{ + int i; + ma_uint32 riceParamMask; + ma_int32* pDecodedSamples = pSamplesOut; + ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + ma_uint32 zeroCountParts[4]; + ma_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int32x2_t shift64; + uint32x4_t one128; + const ma_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + riceParamMask = (ma_uint32)~((~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}; + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; + } + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; + } + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; + } + coefficients128_8 = vld1q_s32(tempC); + 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); + } + 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; + } + 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)); + 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 = 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); + } + } 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 = 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); + } + } 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 = 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); + } + } + 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; + } + 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); + i += 1; + pDecodedSamples += 1; + } + return MA_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) +{ + int i; + ma_uint32 riceParamMask; + ma_int32* pDecodedSamples = pSamplesOut; + ma_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + ma_uint32 zeroCountParts[4]; + ma_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + 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); + 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}; + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; + } + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; + } + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; + } + coefficients128_8 = vld1q_s32(tempC); + 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); + } + 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; + } + 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)); + for (i = 0; i < 4; i += 1) { + int64x1_t prediction64; + prediction128 = veorq_s64(prediction128, prediction128); + switch (order) + { + case 12: + case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8))); + case 10: + case 9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8))); + case 8: + case 7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4))); + case 6: + case 5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4))); + case 4: + case 3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0))); + 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 = 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); + } + 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; + } + 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); + i += 1; + pDecodedSamples += 1; + } + return MA_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) +{ + 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); + } else { + return ma_dr_flac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, 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) +{ +#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); + } 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); + } else +#endif + { + #if 0 + return ma_dr_flac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #else + return ma_dr_flac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, 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) +{ + ma_uint32 i; + MA_DR_FLAC_ASSERT(bs != NULL); + for (i = 0; i < count; ++i) { + if (!ma_dr_flac__seek_rice_parts(bs, riceParam)) { + return MA_FALSE; + } + } + return MA_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) +{ + ma_uint32 i; + MA_DR_FLAC_ASSERT(bs != NULL); + MA_DR_FLAC_ASSERT(unencodedBitsPerSample <= 31); + MA_DR_FLAC_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; + } + } 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); + } else { + pSamplesOut[i] += ma_dr_flac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + return MA_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) +{ + 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; + } + if (residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return MA_FALSE; + } + pDecodedSamples += lpcOrder; + if (!ma_dr_flac__read_uint8(bs, 4, &partitionOrder)) { + return MA_FALSE; + } + if (partitionOrder > 8) { + return MA_FALSE; + } + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { + return MA_FALSE; + } + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + 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; + } + 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; + } + 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; + } + } else { + ma_uint8 unencodedBitsPerSample = 0; + if (!ma_dr_flac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return MA_FALSE; + } + if (!ma_dr_flac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return MA_FALSE; + } + } + pDecodedSamples += samplesInPartition; + if (partitionsRemaining == 1) { + break; + } + partitionsRemaining -= 1; + if (partitionOrder != 0) { + samplesInPartition = blockSize / (1 << partitionOrder); + } + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__read_and_seek_residual(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_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; + } + if (residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != MA_DR_FLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return MA_FALSE; + } + if (!ma_dr_flac__read_uint8(bs, 4, &partitionOrder)) { + return MA_FALSE; + } + if (partitionOrder > 8) { + return MA_FALSE; + } + if ((blockSize / (1 << partitionOrder)) <= order) { + return MA_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; + } + 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; + } + if (riceParam == 31) { + riceParam = 0xFF; + } + } + if (riceParam != 0xFF) { + if (!ma_dr_flac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { + return MA_FALSE; + } + } else { + ma_uint8 unencodedBitsPerSample = 0; + if (!ma_dr_flac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return MA_FALSE; + } + if (!ma_dr_flac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { + return MA_FALSE; + } + } + if (partitionsRemaining == 1) { + break; + } + partitionsRemaining -= 1; + samplesInPartition = blockSize / (1 << partitionOrder); + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__decode_samples__constant(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 subframeBitsPerSample, ma_int32* pDecodedSamples) +{ + ma_uint32 i; + ma_int32 sample; + if (!ma_dr_flac__read_int32(bs, subframeBitsPerSample, &sample)) { + return MA_FALSE; + } + for (i = 0; i < blockSize; ++i) { + pDecodedSamples[i] = sample; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__decode_samples__verbatim(ma_dr_flac_bs* bs, ma_uint32 blockSize, ma_uint32 subframeBitsPerSample, ma_int32* pDecodedSamples) +{ + ma_uint32 i; + for (i = 0; i < blockSize; ++i) { + ma_int32 sample; + if (!ma_dr_flac__read_int32(bs, subframeBitsPerSample, &sample)) { + return MA_FALSE; + } + pDecodedSamples[i] = sample; + } + return MA_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) +{ + ma_uint32 i; + static ma_int32 lpcCoefficientsTable[5][4] = { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {2, -1, 0, 0}, + {3, -3, 1, 0}, + {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; + } + pDecodedSamples[i] = sample; + } + if (!ma_dr_flac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + return MA_FALSE; + } + return MA_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) +{ + ma_uint8 i; + ma_uint8 lpcPrecision; + ma_int8 lpcShift; + ma_int32 coefficients[32]; + for (i = 0; i < lpcOrder; ++i) { + ma_int32 sample; + if (!ma_dr_flac__read_int32(bs, bitsPerSample, &sample)) { + return MA_FALSE; + } + pDecodedSamples[i] = sample; + } + if (!ma_dr_flac__read_uint8(bs, 4, &lpcPrecision)) { + return MA_FALSE; + } + if (lpcPrecision == 15) { + return MA_FALSE; + } + lpcPrecision += 1; + if (!ma_dr_flac__read_int8(bs, 5, &lpcShift)) { + return MA_FALSE; + } + if (lpcShift < 0) { + return MA_FALSE; + } + MA_DR_FLAC_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 (!ma_dr_flac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return MA_FALSE; + } + return MA_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) +{ + 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); + 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; + } + if (!ma_dr_flac__read_uint8(bs, 1, &reserved)) { + return MA_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 = ma_dr_flac_crc8(crc8, blockingStrategy, 1); + if (!ma_dr_flac__read_uint8(bs, 4, &blockSize)) { + return MA_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 = ma_dr_flac_crc8(crc8, sampleRate, 4); + if (!ma_dr_flac__read_uint8(bs, 4, &channelAssignment)) { + return MA_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; + } + 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; + } + if (reserved == 1) { + continue; + } + crc8 = ma_dr_flac_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; + } else { + continue; + } + } + 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; + } else { + continue; + } + } + header->flacFrameNumber = (ma_uint32)flacFrameNumber; + header->pcmFrameNumber = 0; + } + MA_DR_FLAC_ASSERT(blockSize > 0); + if (blockSize == 1) { + header->blockSizeInPCMFrames = 192; + } else if (blockSize <= 5) { + MA_DR_FLAC_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; + } + crc8 = ma_dr_flac_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; + } + header->blockSizeInPCMFrames += 1; + } else { + MA_DR_FLAC_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; + } + crc8 = ma_dr_flac_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; + } + crc8 = ma_dr_flac_crc8(crc8, header->sampleRate, 16); + } else if (sampleRate == 14) { + if (!ma_dr_flac__read_uint32(bs, 16, &header->sampleRate)) { + return MA_FALSE; + } + crc8 = ma_dr_flac_crc8(crc8, header->sampleRate, 16); + header->sampleRate *= 10; + } else { + continue; + } + header->channelAssignment = channelAssignment; + header->bitsPerSample = bitsPerSampleTable[bitsPerSample]; + if (header->bitsPerSample == 0) { + header->bitsPerSample = streaminfoBitsPerSample; + } + if (header->bitsPerSample != streaminfoBitsPerSample) { + return MA_FALSE; + } + if (!ma_dr_flac__read_uint8(bs, 8, &header->crc8)) { + return MA_FALSE; + } +#ifndef MA_DR_FLAC_NO_CRC + if (header->crc8 != crc8) { + continue; + } +#endif + return MA_TRUE; + } +} +static ma_bool32 ma_dr_flac__read_subframe_header(ma_dr_flac_bs* bs, ma_dr_flac_subframe* pSubframe) +{ + ma_uint8 header; + int type; + if (!ma_dr_flac__read_uint8(bs, 8, &header)) { + return MA_FALSE; + } + if ((header & 0x80) != 0) { + return MA_FALSE; + } + pSubframe->lpcOrder = 0; + type = (header & 0x7E) >> 1; + if (type == 0) { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_CONSTANT; + } else if (type == 1) { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_VERBATIM; + } else { + if ((type & 0x20) != 0) { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_LPC; + pSubframe->lpcOrder = (ma_uint8)(type & 0x1F) + 1; + } else if ((type & 0x08) != 0) { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_FIXED; + pSubframe->lpcOrder = (ma_uint8)(type & 0x07); + if (pSubframe->lpcOrder > 4) { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_RESERVED; + pSubframe->lpcOrder = 0; + } + } else { + pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_RESERVED; + } + } + if (pSubframe->subframeType == MA_DR_FLAC_SUBFRAME_RESERVED) { + return MA_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; + } + pSubframe->wastedBitsPerSample = (ma_uint8)wastedBitsPerSample + 1; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__decode_subframe(ma_dr_flac_bs* bs, ma_dr_flac_frame* frame, int subframeIndex, ma_int32* pDecodedSamplesOut) +{ + ma_dr_flac_subframe* pSubframe; + ma_uint32 subframeBitsPerSample; + MA_DR_FLAC_ASSERT(bs != NULL); + MA_DR_FLAC_ASSERT(frame != NULL); + pSubframe = frame->subframes + subframeIndex; + if (!ma_dr_flac__read_subframe_header(bs, pSubframe)) { + return MA_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) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + if (subframeBitsPerSample > 32) { + return MA_FALSE; + } + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return MA_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: + { + ma_dr_flac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + case MA_DR_FLAC_SUBFRAME_VERBATIM: + { + ma_dr_flac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + case MA_DR_FLAC_SUBFRAME_FIXED: + { + ma_dr_flac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + case MA_DR_FLAC_SUBFRAME_LPC: + { + ma_dr_flac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + default: return MA_FALSE; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__seek_subframe(ma_dr_flac_bs* bs, ma_dr_flac_frame* frame, int subframeIndex) +{ + ma_dr_flac_subframe* pSubframe; + ma_uint32 subframeBitsPerSample; + MA_DR_FLAC_ASSERT(bs != NULL); + MA_DR_FLAC_ASSERT(frame != NULL); + pSubframe = frame->subframes + subframeIndex; + if (!ma_dr_flac__read_subframe_header(bs, pSubframe)) { + return MA_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) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return MA_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + pSubframe->pSamplesS32 = NULL; + switch (pSubframe->subframeType) + { + case MA_DR_FLAC_SUBFRAME_CONSTANT: + { + if (!ma_dr_flac__seek_bits(bs, subframeBitsPerSample)) { + return MA_FALSE; + } + } break; + case MA_DR_FLAC_SUBFRAME_VERBATIM: + { + unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample; + if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { + return MA_FALSE; + } + } break; + case MA_DR_FLAC_SUBFRAME_FIXED: + { + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { + return MA_FALSE; + } + if (!ma_dr_flac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return MA_FALSE; + } + } break; + case MA_DR_FLAC_SUBFRAME_LPC: + { + ma_uint8 lpcPrecision; + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { + return MA_FALSE; + } + if (!ma_dr_flac__read_uint8(bs, 4, &lpcPrecision)) { + return MA_FALSE; + } + if (lpcPrecision == 15) { + return MA_FALSE; + } + lpcPrecision += 1; + bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; + if (!ma_dr_flac__seek_bits(bs, bitsToSeek)) { + return MA_FALSE; + } + if (!ma_dr_flac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return MA_FALSE; + } + } break; + default: return MA_FALSE; + } + return MA_TRUE; +} +static MA_INLINE ma_uint8 ma_dr_flac__get_channel_count_from_channel_assignment(ma_int8 channelAssignment) +{ + ma_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; + MA_DR_FLAC_ASSERT(channelAssignment <= 10); + return lookup[channelAssignment]; +} +static ma_result ma_dr_flac__decode_flac_frame(ma_dr_flac* pFlac) +{ + int channelCount; + int i; + ma_uint8 paddingSizeInBits; + ma_uint16 desiredCRC16; +#ifndef MA_DR_FLAC_NO_CRC + ma_uint16 actualCRC16; +#endif + MA_DR_FLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); + if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) { + return MA_ERROR; + } + channelCount = ma_dr_flac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + if (channelCount != (int)pFlac->channels) { + return MA_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; + } + } + paddingSizeInBits = (ma_uint8)(MA_DR_FLAC_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; + } + } +#ifndef MA_DR_FLAC_NO_CRC + actualCRC16 = ma_dr_flac__flush_crc16(&pFlac->bs); +#endif + if (!ma_dr_flac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return MA_AT_END; + } +#ifndef MA_DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return MA_CRC_MISMATCH; + } +#endif + pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + return MA_SUCCESS; +} +static ma_result ma_dr_flac__seek_flac_frame(ma_dr_flac* pFlac) +{ + int channelCount; + int i; + ma_uint16 desiredCRC16; +#ifndef MA_DR_FLAC_NO_CRC + ma_uint16 actualCRC16; +#endif + channelCount = ma_dr_flac__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 (!ma_dr_flac__seek_bits(&pFlac->bs, MA_DR_FLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { + return MA_ERROR; + } +#ifndef MA_DR_FLAC_NO_CRC + actualCRC16 = ma_dr_flac__flush_crc16(&pFlac->bs); +#endif + if (!ma_dr_flac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return MA_AT_END; + } +#ifndef MA_DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return MA_CRC_MISMATCH; + } +#endif + return MA_SUCCESS; +} +static ma_bool32 ma_dr_flac__read_and_decode_next_flac_frame(ma_dr_flac* pFlac) +{ + MA_DR_FLAC_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; + } + result = ma_dr_flac__decode_flac_frame(pFlac); + if (result != MA_SUCCESS) { + if (result == MA_CRC_MISMATCH) { + continue; + } else { + return MA_FALSE; + } + } + return MA_TRUE; + } +} +static void ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(ma_dr_flac* pFlac, ma_uint64* pFirstPCMFrame, ma_uint64* pLastPCMFrame) +{ + ma_uint64 firstPCMFrame; + ma_uint64 lastPCMFrame; + MA_DR_FLAC_ASSERT(pFlac != NULL); + firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber; + if (firstPCMFrame == 0) { + firstPCMFrame = ((ma_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; + } + lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + if (lastPCMFrame > 0) { + lastPCMFrame -= 1; + } + if (pFirstPCMFrame) { + *pFirstPCMFrame = firstPCMFrame; + } + if (pLastPCMFrame) { + *pLastPCMFrame = lastPCMFrame; + } +} +static ma_bool32 ma_dr_flac__seek_to_first_frame(ma_dr_flac* 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)); + pFlac->currentPCMFrame = 0; + return result; +} +static MA_INLINE ma_result ma_dr_flac__seek_to_next_flac_frame(ma_dr_flac* pFlac) +{ + MA_DR_FLAC_ASSERT(pFlac != NULL); + return ma_dr_flac__seek_flac_frame(pFlac); +} +static ma_uint64 ma_dr_flac__seek_forward_by_pcm_frames(ma_dr_flac* pFlac, ma_uint64 pcmFramesToSeek) +{ + ma_uint64 pcmFramesRead = 0; + while (pcmFramesToSeek > 0) { + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!ma_dr_flac__read_and_decode_next_flac_frame(pFlac)) { + break; + } + } else { + if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) { + pcmFramesRead += pcmFramesToSeek; + pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_uint32)pcmFramesToSeek; + pcmFramesToSeek = 0; + } else { + pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining; + pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + } + } + } + pFlac->currentPCMFrame += pcmFramesRead; + return pcmFramesRead; +} +static ma_bool32 ma_dr_flac__seek_to_pcm_frame__brute_force(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +{ + ma_bool32 isMidFrame = MA_FALSE; + ma_uint64 runningPCMFrameCount; + MA_DR_FLAC_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; + } + } else { + isMidFrame = MA_TRUE; + } + } else { + runningPCMFrameCount = 0; + if (!ma_dr_flac__seek_to_first_frame(pFlac)) { + return MA_FALSE; + } + if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return MA_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); + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + ma_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; + } else { + if (result == MA_CRC_MISMATCH) { + goto next_iteration; + } else { + return MA_FALSE; + } + } + } else { + return ma_dr_flac__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) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == MA_CRC_MISMATCH) { + goto next_iteration; + } else { + return MA_FALSE; + } + } + } else { + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = MA_FALSE; + } + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return MA_TRUE; + } + } + next_iteration: + if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return MA_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) +{ + MA_DR_FLAC_ASSERT(pFlac != NULL); + MA_DR_FLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); + MA_DR_FLAC_ASSERT(targetByte >= rangeLo); + MA_DR_FLAC_ASSERT(targetByte <= rangeHi); + *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes; + for (;;) { + ma_uint64 lastTargetByte = targetByte; + if (!ma_dr_flac__seek_to_byte(&pFlac->bs, targetByte)) { + if (targetByte == 0) { + ma_dr_flac__seek_to_first_frame(pFlac); + return MA_FALSE; + } + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + MA_DR_FLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); +#if 1 + if (!ma_dr_flac__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)) { + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#endif + } + if(targetByte == lastTargetByte) { + return MA_FALSE; + } + } + ma_dr_flac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + MA_DR_FLAC_ASSERT(targetByte <= rangeHi); + *pLastSuccessfulSeekOffset = targetByte; + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__decode_flac_frame_and_seek_forward_by_pcm_frames(ma_dr_flac* pFlac, ma_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; + } + } +#endif + return ma_dr_flac__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) +{ + 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); + 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 (pcmRangeLo == newPCMRangeLo) { + if (!ma_dr_flac__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; + } else { + break; + } + } + 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; + } else { + break; + } + } else { + const float approxCompressionRatio = (ma_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((ma_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f); + if (pcmRangeLo > pcmFrameIndex) { + byteRangeHi = lastSuccessfulSeekOffset; + if (byteRangeLo > byteRangeHi) { + byteRangeLo = byteRangeHi; + } + targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2); + if (targetByte < byteRangeLo) { + targetByte = byteRangeLo; + } + } 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; + } else { + break; + } + } else { + byteRangeLo = lastSuccessfulSeekOffset; + if (byteRangeHi < byteRangeLo) { + byteRangeHi = byteRangeLo; + } + targetByte = lastSuccessfulSeekOffset + (ma_uint64)(((ma_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) { + closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset; + } + } + } + } + } else { + break; + } + } + ma_dr_flac__seek_to_first_frame(pFlac); + return MA_FALSE; +} +static ma_bool32 ma_dr_flac__seek_to_pcm_frame__binary_search(ma_dr_flac* pFlac, ma_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; + } + if (pcmFrameIndex < seekForwardThreshold) { + return ma_dr_flac__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); +} +#endif +static ma_bool32 ma_dr_flac__seek_to_pcm_frame__seek_table(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +{ + ma_uint32 iClosestSeekpoint = 0; + ma_bool32 isMidFrame = MA_FALSE; + ma_uint64 runningPCMFrameCount; + ma_uint32 iSeekpoint; + MA_DR_FLAC_ASSERT(pFlac != NULL); + if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { + return MA_FALSE; + } + if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { + return MA_FALSE; + } + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { + break; + } + iClosestSeekpoint = iSeekpoint; + } + if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) { + return MA_FALSE; + } + if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) { + return MA_FALSE; + } +#if !defined(MA_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); + byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset; + if (iClosestSeekpoint < pFlac->seekpointCount-1) { + ma_uint32 iNextSeekpoint = iClosestSeekpoint + 1; + if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) { + return MA_FALSE; + } + if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((ma_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; + } + } + } + } +#endif + 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; + } + } else { + isMidFrame = MA_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 (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return MA_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); + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + ma_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; + } else { + if (result == MA_CRC_MISMATCH) { + goto next_iteration; + } else { + return MA_FALSE; + } + } + } else { + return ma_dr_flac__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) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == MA_CRC_MISMATCH) { + goto next_iteration; + } else { + return MA_FALSE; + } + } + } else { + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = MA_FALSE; + } + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return MA_TRUE; + } + } + next_iteration: + if (!ma_dr_flac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return MA_FALSE; + } + } +} +#ifndef MA_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; +#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; + 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; +#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) +{ + blockHeader = ma_dr_flac__be2host_32(blockHeader); + *isLastBlock = (ma_uint8)((blockHeader & 0x80000000UL) >> 31); + *blockType = (ma_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) +{ + ma_uint32 blockHeader; + *blockSize = 0; + if (onRead(pUserData, &blockHeader, 4) != 4) { + return MA_FALSE; + } + ma_dr_flac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); + return MA_TRUE; +} +static ma_bool32 ma_dr_flac__read_streaminfo(ma_dr_flac_read_proc onRead, void* pUserData, ma_dr_flac_streaminfo* pStreamInfo) +{ + ma_uint32 blockSizes; + ma_uint64 frameSizes = 0; + ma_uint64 importantProps; + ma_uint8 md5[16]; + if (onRead(pUserData, &blockSizes, 4) != 4) { + return MA_FALSE; + } + if (onRead(pUserData, &frameSizes, 6) != 6) { + return MA_FALSE; + } + if (onRead(pUserData, &importantProps, 8) != 8) { + return MA_FALSE; + } + if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { + return MA_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; +} +static void* ma_dr_flac__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_DR_FLAC_MALLOC(sz); +} +static void* ma_dr_flac__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_DR_FLAC_REALLOC(p, sz); +} +static void ma_dr_flac__free_default(void* p, void* pUserData) +{ + (void)pUserData; + MA_DR_FLAC_FREE(p); +} +static void* ma_dr_flac__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); + } + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + return NULL; +} +static void* ma_dr_flac__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); + } + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + if (p != NULL) { + MA_DR_FLAC_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) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + if (pAllocationCallbacks->onFree != NULL) { + 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) +{ + ma_uint64 runningFilePos = 42; + ma_uint64 seektablePos = 0; + ma_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; + } + runningFilePos += 4; + metadata.type = blockType; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + switch (blockType) + { + case MA_DR_FLAC_METADATA_BLOCK_TYPE_APPLICATION: + { + if (blockSize < 4) { + return MA_FALSE; + } + if (onMeta) { + void* pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return MA_FALSE; + } + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_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); + onMeta(pUserDataMD, &metadata); + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_SEEKTABLE: + { + seektablePos = runningFilePos; + seektableSize = blockSize; + if (onMeta) { + ma_uint32 seekpointCount; + ma_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); + if (pRawData == NULL) { + return MA_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); + } + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + metadata.data.seektable.seekpointCount = seekpointCount; + metadata.data.seektable.pSeekpoints = (const ma_dr_flac_seekpoint*)pRawData; + onMeta(pUserDataMD, &metadata); + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: + { + if (blockSize < 8) { + return MA_FALSE; + } + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + ma_uint32 i; + pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return MA_FALSE; + } + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_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.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.pComments = pRunningData; + for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + ma_uint32 commentLength; + if (pRunningDataEnd - pRunningData < 4) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_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; + } + pRunningData += commentLength; + } + onMeta(pUserDataMD, &metadata); + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_CUESHEET: + { + if (blockSize < 396) { + return MA_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); + if (pRawData == NULL) { + return MA_FALSE; + } + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_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; + 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; + } + 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; + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_PICTURE: + { + if (blockSize < 32) { + return MA_FALSE; + } + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return MA_FALSE; + } + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_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.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.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; + } + onMeta(pUserDataMD, &metadata); + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_PADDING: + { + if (onMeta) { + metadata.data.padding.unused = 0; + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + isLastBlock = MA_TRUE; + } else { + onMeta(pUserDataMD, &metadata); + } + } + } break; + case MA_DR_FLAC_METADATA_BLOCK_TYPE_INVALID: + { + if (onMeta) { + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + isLastBlock = MA_TRUE; + } + } + } break; + default: + { + if (onMeta) { + void* pRawData = ma_dr_flac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return MA_FALSE; + } + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + return MA_FALSE; + } + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + onMeta(pUserDataMD, &metadata); + ma_dr_flac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + } + if (onMeta == NULL && blockSize > 0) { + if (!onSeek(pUserData, blockSize, ma_dr_flac_seek_origin_current)) { + isLastBlock = MA_TRUE; + } + } + runningFilePos += blockSize; + if (isLastBlock) { + break; + } + } + *pSeektablePos = seektablePos; + *pSeekpointCount = seektableSize / MA_DR_FLAC_SEEKPOINT_SIZE_IN_BYTES; + *pFirstFramePos = runningFilePos; + return MA_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) +{ + ma_uint8 isLastBlock; + ma_uint8 blockType; + ma_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; + } + if (blockType != MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + if (!relaxed) { + return MA_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; + } + if (pInit->firstFrameHeader.bitsPerSample == 0) { + return MA_FALSE; + } + pInit->sampleRate = pInit->firstFrameHeader.sampleRate; + pInit->channels = ma_dr_flac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; + pInit->maxBlockSizeInPCMFrames = 65535; + return MA_TRUE; + } + } else { + ma_dr_flac_streaminfo streaminfo; + if (!ma_dr_flac__read_streaminfo(onRead, pUserData, &streaminfo)) { + return MA_FALSE; + } + pInit->hasStreamInfoBlock = MA_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; + pInit->hasMetadataBlocks = !isLastBlock; + if (onMeta) { + ma_dr_flac_metadata metadata; + metadata.type = MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + return MA_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 +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[] = { + 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, + 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, + 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, + 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL, + 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, + 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, + 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L, + 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL, + 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L, + 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, + 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, + 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL, + 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L, + 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L, + 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, + 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, + 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL, + 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L, + 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L, + 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, + 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, + 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L, + 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L, + 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL, + 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, + 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, + 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L, + 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL, + 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL, + 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, + 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, + 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL, + 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L, + 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL, + 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, + 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L, + 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L, + 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL, + 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL, + 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, + 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, + 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL, + 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL, + 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L, + 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, + 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, + 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL, + 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L, + 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L, + 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, + 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L, + 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L, + 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L, + 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL, + 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, + 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, + 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L, + 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL, + 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L, + 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, + 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, + 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL, + 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, + 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L +}; +#endif +static MA_INLINE ma_uint32 ma_dr_flac_crc32_byte(ma_uint32 crc32, ma_uint8 data) +{ +#ifndef MA_DR_FLAC_NO_CRC + return (crc32 << 8) ^ ma_dr_flac__crc32_table[(ma_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) +{ + 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)); + return crc32; +} +static MA_INLINE ma_uint32 ma_dr_flac_crc32_uint64(ma_uint32 crc32, ma_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)); + return crc32; +} +#endif +static MA_INLINE ma_uint32 ma_dr_flac_crc32_buffer(ma_uint32 crc32, ma_uint8* pData, ma_uint32 dataSize) +{ + ma_uint32 i; + for (i = 0; i < dataSize; ++i) { + crc32 = ma_dr_flac_crc32_byte(crc32, pData[i]); + } + return crc32; +} +static MA_INLINE ma_bool32 ma_dr_flac_ogg__is_capture_pattern(ma_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) +{ + return 27 + pHeader->segmentCount; +} +static MA_INLINE ma_uint32 ma_dr_flac_ogg__get_page_body_size(ma_dr_flac_ogg_page_header* pHeader) +{ + ma_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) +{ + ma_uint8 data[23]; + ma_uint32 i; + MA_DR_FLAC_ASSERT(*pCRC32 == MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32); + if (onRead(pUserData, data, 23) != 23) { + return MA_AT_END; + } + *pBytesRead += 23; + pHeader->capturePattern[0] = 'O'; + pHeader->capturePattern[1] = 'g'; + pHeader->capturePattern[2] = 'g'; + 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); + 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]); + } + if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { + return MA_AT_END; + } + *pBytesRead += pHeader->segmentCount; + for (i = 0; i < pHeader->segmentCount; ++i) { + *pCRC32 = ma_dr_flac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); + } + return MA_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) +{ + ma_uint8 id[4]; + *pBytesRead = 0; + if (onRead(pUserData, id, 4) != 4) { + return MA_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; + } else { + if (result == MA_CRC_MISMATCH) { + continue; + } else { + return result; + } + } + } else { + id[0] = id[1]; + id[1] = id[2]; + id[2] = id[3]; + if (onRead(pUserData, &id[3], 1) != 1) { + return MA_AT_END; + } + *pBytesRead += 1; + } + } +} +typedef struct +{ + ma_dr_flac_read_proc onRead; + ma_dr_flac_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) +{ + 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) +{ + if (origin == ma_dr_flac_seek_origin_start) { + if (offset <= 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_start)) { + return MA_FALSE; + } + oggbs->currentBytePos = offset; + return MA_TRUE; + } else { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_start)) { + return MA_FALSE; + } + oggbs->currentBytePos = offset; + return ma_dr_flac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, ma_dr_flac_seek_origin_current); + } + } else { + while (offset > 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + oggbs->currentBytePos += 0x7FFFFFFF; + offset -= 0x7FFFFFFF; + } + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + oggbs->currentBytePos += offset; + return MA_TRUE; + } +} +static ma_bool32 ma_dr_flac_oggbs__goto_next_page(ma_dr_flac_oggbs* oggbs, ma_dr_flac_ogg_crc_mismatch_recovery recoveryMethod) +{ + ma_dr_flac_ogg_page_header header; + for (;;) { + ma_uint32 crc32 = 0; + ma_uint32 bytesRead; + ma_uint32 pageBodySize; +#ifndef MA_DR_FLAC_NO_CRC + ma_uint32 actualCRC32; +#endif + if (ma_dr_flac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != MA_SUCCESS) { + return MA_FALSE; + } + oggbs->currentBytePos += bytesRead; + pageBodySize = ma_dr_flac_ogg__get_page_body_size(&header); + if (pageBodySize > MA_DR_FLAC_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; + } + continue; + } + if (ma_dr_flac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { + return MA_FALSE; + } + oggbs->pageDataSize = pageBodySize; +#ifndef MA_DR_FLAC_NO_CRC + actualCRC32 = ma_dr_flac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + if (actualCRC32 != header.checksum) { + if (recoveryMethod == ma_dr_flac_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; + } + } +#else + (void)recoveryMethod; +#endif + oggbs->currentPageHeader = header; + oggbs->bytesRemainingInPage = pageBodySize; + return MA_TRUE; + } +} +#if 0 +static ma_uint8 ma_dr_flac_oggbs__get_current_segment_index(ma_dr_flac_oggbs* oggbs, ma_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; + while (iByte < bytesConsumedInPage) { + ma_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + if (iByte + segmentSize > bytesConsumedInPage) { + break; + } else { + iSeg += 1; + iByte += segmentSize; + } + } + *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (ma_uint8)(bytesConsumedInPage - iByte); + return iSeg; +} +static ma_bool32 ma_dr_flac_oggbs__seek_to_next_packet(ma_dr_flac_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]; + if (segmentSize < 255) { + if (iSeg == oggbs->currentPageHeader.segmentCount-1) { + atEndOfPage = MA_TRUE; + } + break; + } + bytesToEndOfPacketOrPage += segmentSize; + } + ma_dr_flac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, ma_dr_flac_seek_origin_current); + oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; + if (atEndOfPage) { + if (!ma_dr_flac_oggbs__goto_next_page(oggbs)) { + return MA_FALSE; + } + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { + return MA_TRUE; + } + } else { + return MA_TRUE; + } + } +} +static ma_bool32 ma_dr_flac_oggbs__seek_to_next_frame(ma_dr_flac_oggbs* oggbs) +{ + return ma_dr_flac_oggbs__seek_to_next_packet(oggbs); +} +#endif +static size_t ma_dr_flac__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; + size_t bytesRead = 0; + MA_DR_FLAC_ASSERT(oggbs != NULL); + MA_DR_FLAC_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); + bytesRead += bytesRemainingToRead; + oggbs->bytesRemainingInPage -= (ma_uint32)bytesRemainingToRead; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + MA_DR_FLAC_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)) { + break; + } + } + return bytesRead; +} +static ma_bool32 ma_dr_flac__on_seek_ogg(void* pUserData, int offset, ma_dr_flac_seek_origin origin) +{ + ma_dr_flac_oggbs* oggbs = (ma_dr_flac_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; + } + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_fail_on_crc_mismatch)) { + return MA_FALSE; + } + return ma_dr_flac__on_seek_ogg(pUserData, offset, ma_dr_flac_seek_origin_current); + } + MA_DR_FLAC_ASSERT(origin == ma_dr_flac_seek_origin_current); + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + MA_DR_FLAC_ASSERT(bytesRemainingToSeek >= 0); + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + if (oggbs->bytesRemainingInPage > 0) { + 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; + } + } + return MA_TRUE; +} +static ma_bool32 ma_dr_flac_ogg__seek_to_pcm_frame(ma_dr_flac* pFlac, ma_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); + originalBytePos = oggbs->currentBytePos; + if (!ma_dr_flac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { + return MA_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; + } + runningFrameBytePos = oggbs->currentBytePos - ma_dr_flac_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]; + firstBytesInPage[0] = oggbs->pageData[0]; + firstBytesInPage[1] = oggbs->pageData[1]; + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { + runningGranulePosition = oggbs->currentPageHeader.granulePosition; + } + continue; + } + } + } + if (!ma_dr_flac_oggbs__seek_physical(oggbs, runningFrameBytePos, ma_dr_flac_seek_origin_start)) { + return MA_FALSE; + } + if (!ma_dr_flac_oggbs__goto_next_page(oggbs, ma_dr_flac_ogg_recover_on_crc_mismatch)) { + return MA_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; + } + ma_dr_flac__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) { + pFlac->currentPCMFrame = pcmFrameIndex; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + return MA_TRUE; + } else { + return MA_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); + if (pcmFramesToDecode == 0) { + return MA_TRUE; + } + pFlac->currentPCMFrame = runningPCMFrameCount; + return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } else { + if (result == MA_CRC_MISMATCH) { + continue; + } else { + return MA_FALSE; + } + } + } else { + ma_result result = ma_dr_flac__seek_to_next_flac_frame(pFlac); + if (result == MA_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFrame; + } else { + if (result == MA_CRC_MISMATCH) { + continue; + } else { + return MA_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) +{ + ma_dr_flac_ogg_page_header header; + ma_uint32 crc32 = MA_DR_FLAC_OGG_CAPTURE_PATTERN_CRC32; + ma_uint32 bytesRead = 0; + (void)relaxed; + pInit->container = ma_dr_flac_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; + } + pInit->runningFilePos += bytesRead; + for (;;) { + int pageBodySize; + if ((header.headerType & 0x02) == 0) { + return MA_FALSE; + } + pageBodySize = ma_dr_flac_ogg__get_page_body_size(&header); + if (pageBodySize == 51) { + ma_uint32 bytesRemainingInPage = pageBodySize; + ma_uint8 packetType; + if (onRead(pUserData, &packetType, 1) != 1) { + return MA_FALSE; + } + bytesRemainingInPage -= 1; + if (packetType == 0x7F) { + ma_uint8 sig[4]; + if (onRead(pUserData, sig, 4) != 4) { + return MA_FALSE; + } + bytesRemainingInPage -= 4; + if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { + ma_uint8 mappingVersion[2]; + if (onRead(pUserData, mappingVersion, 2) != 2) { + return MA_FALSE; + } + if (mappingVersion[0] != 1) { + return MA_FALSE; + } + if (!onSeek(pUserData, 2, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + if (onRead(pUserData, sig, 4) != 4) { + return MA_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; + } + if (blockType != MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + return MA_FALSE; + } + if (ma_dr_flac__read_streaminfo(onRead, pUserData, &streaminfo)) { + pInit->hasStreamInfoBlock = MA_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; + pInit->hasMetadataBlocks = !isLastBlock; + if (onMeta) { + ma_dr_flac_metadata metadata; + metadata.type = MA_DR_FLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + pInit->runningFilePos += pageBodySize; + pInit->oggFirstBytePos = pInit->runningFilePos - 79; + pInit->oggSerial = header.serialNumber; + pInit->oggBosHeader = header; + break; + } else { + return MA_FALSE; + } + } else { + return MA_FALSE; + } + } else { + if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + } + } else { + if (!onSeek(pUserData, bytesRemainingInPage, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + } + } else { + if (!onSeek(pUserData, pageBodySize, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + } + pInit->runningFilePos += pageBodySize; + if (ma_dr_flac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != MA_SUCCESS) { + return MA_FALSE; + } + pInit->runningFilePos += bytesRead; + } + pInit->hasMetadataBlocks = MA_TRUE; + return MA_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) +{ + ma_bool32 relaxed; + ma_uint8 id[4]; + if (pInit == NULL || onRead == NULL || onSeek == NULL) { + return MA_FALSE; + } + MA_DR_FLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); + pInit->onRead = onRead; + pInit->onSeek = onSeek; + pInit->onMeta = onMeta; + pInit->container = container; + pInit->pUserData = pUserData; + pInit->pUserDataMD = pUserDataMD; + 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; + for (;;) { + if (onRead(pUserData, id, 4) != 4) { + return MA_FALSE; + } + pInit->runningFilePos += 4; + if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { + ma_uint8 header[6]; + ma_uint8 flags; + ma_uint32 headerSize; + if (onRead(pUserData, header, 6) != 6) { + return MA_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)); + if (flags & 0x10) { + headerSize += 10; + } + if (!onSeek(pUserData, headerSize, ma_dr_flac_seek_origin_current)) { + return MA_FALSE; + } + pInit->runningFilePos += headerSize; + } else { + break; + } + } + 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); + } +#ifndef MA_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); + } +#endif + if (relaxed) { + if (container == ma_dr_flac_container_native) { + return ma_dr_flac__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); + } +#endif + } + return MA_FALSE; +} +static void ma_dr_flac__init_from_info(ma_dr_flac* pFlac, const ma_dr_flac_init_info* pInit) +{ + MA_DR_FLAC_ASSERT(pFlac != NULL); + MA_DR_FLAC_ASSERT(pInit != NULL); + MA_DR_FLAC_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->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) +{ + 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; +#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)) { + return NULL; + } + if (pAllocationCallbacks != NULL) { + allocationCallbacks = *pAllocationCallbacks; + if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) { + return NULL; + } + } 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; + } + 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))); + } else { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (MA_DR_FLAC_MAX_SIMD_VECTOR_SIZE / sizeof(ma_int32))) + 1; + } + decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * MA_DR_FLAC_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; + } +#endif + firstFramePos = 42; + seektablePos = 0; + seekpointCount = 0; + if (init.hasMetadataBlocks) { + ma_dr_flac_read_proc onReadOverride = onRead; + ma_dr_flac_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; + } +#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 + return NULL; + } + allocationSize += seekpointCount * sizeof(ma_dr_flac_seekpoint); + } + pFlac = (ma_dr_flac*)ma_dr_flac__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); + 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->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) + { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + else +#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; + } + } + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, ma_dr_flac_seek_origin_start)) { + ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } else { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + } + } + if (!init.hasStreamInfoBlock) { + pFlac->currentFLACFrame.header = init.firstFrameHeader; + for (;;) { + ma_result result = ma_dr_flac__decode_flac_frame(pFlac); + if (result == MA_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); + return NULL; + } + continue; + } else { + ma_dr_flac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } + } + } + return pFlac; +} +#ifndef MA_DR_FLAC_NO_STDIO +#include +#ifndef MA_DR_FLAC_NO_WCHAR +#include +#endif +static size_t ma_dr_flac__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) +{ + MA_DR_FLAC_ASSERT(offset >= 0); + return fseek((FILE*)pUserData, offset, (origin == ma_dr_flac_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) +{ + ma_dr_flac* pFlac; + FILE* pFile; + if (ma_fopen(&pFile, pFileName, "rb") != MA_SUCCESS) { + return NULL; + } + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + FILE* pFile; + if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_SUCCESS) { + return NULL; + } + pFlac = ma_dr_flac_open(ma_dr_flac__on_read_stdio, ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + FILE* pFile; + if (ma_fopen(&pFile, pFileName, "rb") != MA_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); + 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) +{ + ma_dr_flac* pFlac; + FILE* pFile; + if (ma_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != MA_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); + if (pFlac == NULL) { + fclose(pFile); + return pFlac; + } + return pFlac; +} +#endif +#endif +static size_t ma_dr_flac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + ma_dr_flac__memory_stream* memoryStream = (ma_dr_flac__memory_stream*)pUserData; + size_t bytesRemaining; + MA_DR_FLAC_ASSERT(memoryStream != NULL); + MA_DR_FLAC_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); + memoryStream->currentReadPos += bytesToRead; + } + return bytesToRead; +} +static ma_bool32 ma_dr_flac__on_seek_memory(void* pUserData, int offset, ma_dr_flac_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; + } + if (origin == ma_dr_flac_seek_origin_current) { + if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { + memoryStream->currentReadPos += offset; + } else { + return MA_FALSE; + } + } else { + if ((ma_uint32)offset <= memoryStream->dataSize) { + memoryStream->currentReadPos = offset; + } else { + return MA_FALSE; + } + } + return MA_TRUE; +} +MA_API ma_dr_flac* ma_dr_flac_open_memory(const void* pData, size_t dataSize, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_dr_flac__memory_stream memoryStream; + ma_dr_flac* pFlac; + memoryStream.data = (const ma_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); + if (pFlac == NULL) { + return NULL; + } + pFlac->memoryStream = memoryStream; +#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; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + 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) +{ + ma_dr_flac__memory_stream memoryStream; + ma_dr_flac* pFlac; + memoryStream.data = (const ma_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); + if (pFlac == NULL) { + return NULL; + } + pFlac->memoryStream = memoryStream; +#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; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + 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) +{ + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, NULL, ma_dr_flac_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) +{ + return ma_dr_flac_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) +{ + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, ma_dr_flac_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) +{ + return ma_dr_flac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks); +} +MA_API void ma_dr_flac_close(ma_dr_flac* pFlac) +{ + if (pFlac == NULL) { + return; + } +#ifndef MA_DR_FLAC_NO_STDIO + if (pFlac->bs.onRead == ma_dr_flac__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) { + fclose((FILE*)oggbs->pUserData); + } + } +#endif +#endif + ma_dr_flac__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) +{ + ma_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; + } +} +#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) +{ + 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; + 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; + } + 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; + } +} +#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) +{ + 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); + 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); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _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; + } +} +#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) +{ + 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; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + 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)); + } + 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; + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + ma_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; + } +} +#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) +{ + 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; + 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; + } + 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; + } +} +#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) +{ + 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); + 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); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _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; + } +} +#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) +{ + 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; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + 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)); + } + 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; + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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; + 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); + } +} +#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) +{ + 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; + 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; + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + temp0R = (mid0 - side0) << shift; + 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; + } + } 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; + 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; + } + } + 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; + 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); + } +} +#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) +{ + 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); + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _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; + mid = (mid << 1) | (side & 0x01); + pOutputSamples[i*2+0] = (ma_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (ma_int32)(mid - side) >> 1; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _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; + mid = (mid << 1) | (side & 0x01); + pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (ma_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) +{ + 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; + int32x4_t wbpsShift0_4; + int32x4_t wbpsShift1_4; + uint32x4_t one4; + MA_DR_FLAC_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); + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + 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)); + } + 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; + mid = (mid << 1) | (side & 0x01); + pOutputSamples[i*2+0] = (ma_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (ma_int32)(mid - side) >> 1; + } + } else { + int32x4_t shift4; + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + 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)); + } + 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; + mid = (mid << 1) | (side & 0x01); + pOutputSamples[i*2+0] = (ma_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (ma_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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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)); + } +} +#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) +{ + 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; + 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; + } + 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); + } +} +#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) +{ + 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; + 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); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _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); + } +} +#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) +{ + 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; + int32x4_t shift4_0 = vdupq_n_s32(shift0); + int32x4_t shift4_1 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + 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)); + } + 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); + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#endif + } +} +MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s32(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int32* pBufferOut) +{ + ma_uint64 framesRead; + ma_uint32 unusedBitsPerSample; + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + MA_DR_FLAC_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)) { + 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; + 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; + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + ma_dr_flac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + ma_dr_flac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + ma_dr_flac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + ma_dr_flac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + ma_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)); + } + } + } + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_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) +{ + ma_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; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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; + 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; + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + right0 >>= 16; + 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; + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 left = pInputSamples0U32[i] << shift0; + ma_uint32 side = pInputSamples1U32[i] << shift1; + ma_uint32 right = left - side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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); + 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)); + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 left = pInputSamples0U32[i] << shift0; + ma_uint32 side = pInputSamples1U32[i] << shift1; + ma_uint32 right = left - side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + 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); + 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))); + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 left = pInputSamples0U32[i] << shift0; + ma_uint32 side = pInputSamples1U32[i] << shift1; + ma_uint32 right = left - side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + ma_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; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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; + 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; + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + right0 >>= 16; + 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; + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 side = pInputSamples0U32[i] << shift0; + ma_uint32 right = pInputSamples1U32[i] << shift1; + ma_uint32 left = right + side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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); + 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)); + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 side = pInputSamples0U32[i] << shift0; + ma_uint32 right = pInputSamples1U32[i] << shift1; + ma_uint32 left = right + side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ + 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; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + 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); + 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))); + } + for (i = (frameCount4 << 2); i < frameCount; ++i) { + ma_uint32 side = pInputSamples0U32[i] << shift0; + ma_uint32 right = pInputSamples1U32[i] << shift1; + ma_uint32 left = right + side; + left >>= 16; + right >>= 16; + pOutputSamples[i*2+0] = (ma_int16)left; + pOutputSamples[i*2+1] = (ma_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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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; + 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); + } +} +#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) +{ + 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; + 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; + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + temp0R >>= 16; + 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; + } + } 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; + 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 >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + temp0R >>= 16; + 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; + } + } + 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; + 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); + } +} +#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) +{ + 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); + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + 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)); + } + 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; + 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); + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + 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)); + } + 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; + 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); + } + } +} +#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) +{ + 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; + int32x4_t wbpsShift0_4; + int32x4_t wbpsShift1_4; + MA_DR_FLAC_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) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + 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))); + } + 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; + 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); + } + } else { + int32x4_t shift4; + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + 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))); + } + 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; + 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); + } + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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); + } +} +#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) +{ + 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; + 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; + tempL0 >>= 16; + tempL1 >>= 16; + tempL2 >>= 16; + tempL3 >>= 16; + tempR0 >>= 16; + 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; + } + 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); + } +} +#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) +{ + 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; + 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)); + } + 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); + } +} +#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) +{ + 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; + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + int32x4_t right; + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + 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))); + } + 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); + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#endif + } +} +MA_API ma_uint64 ma_dr_flac_read_pcm_frames_s16(ma_dr_flac* pFlac, ma_uint64 framesToRead, ma_int16* pBufferOut) +{ + ma_uint64 framesRead; + ma_uint32 unusedBitsPerSample; + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + MA_DR_FLAC_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)) { + 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; + 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; + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + ma_dr_flac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + ma_dr_flac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + ma_dr_flac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + ma_dr_flac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + ma_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); + } + } + } + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (ma_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) +{ + ma_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); + } +} +#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) +{ + 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; + 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; + } + 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; + } +} +#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) +{ + 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; + __m128 factor; + MA_DR_FLAC_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); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _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; + } +} +#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) +{ + 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; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + float32x4_t leftf; + float32x4_t rightf; + 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); + 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)); + } + 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; + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + ma_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); + } +} +#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) +{ + 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; + 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; + } + 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; + } +} +#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) +{ + 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; + __m128 factor; + MA_DR_FLAC_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); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _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; + } +} +#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) +{ + 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; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + float32x4_t leftf; + float32x4_t rightf; + 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); + 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)); + } + 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; + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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; + 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); + } +} +#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) +{ + 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; + 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; + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + temp0R = (mid0 - side0) << shift; + 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; + } + } 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; + 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; + } + } + 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; + 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; + } +} +#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) +{ + 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; + float factor; + __m128 factor128; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + factor = 1.0f / 8388608.0f; + factor128 = _mm_set1_ps(factor); + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _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; + 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; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _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; + 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; + } + } +} +#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) +{ + 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; + float factor; + float32x4_t factor4; + int32x4_t shift4; + int32x4_t wbps0_4; + int32x4_t wbps1_4; + MA_DR_FLAC_ASSERT(pFlac->bitsPerSample <= 24); + factor = 1.0f / 8388608.0f; + factor4 = vdupq_n_f32(factor); + wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + 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)); + } + 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; + 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; + } + } else { + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + 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)); + } + 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; + 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; + } + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#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) +{ + 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); + } +} +#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) +{ + 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; + 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; + } + 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; + } +} +#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) +{ + 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; + float factor = 1.0f / 8388608.0f; + __m128 factor128 = _mm_set1_ps(factor); + for (i = 0; i < frameCount4; ++i) { + __m128i lefti; + __m128i righti; + __m128 leftf; + __m128 rightf; + lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128); + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _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; + } +} +#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) +{ + 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; + float factor = 1.0f / 8388608.0f; + float32x4_t factor4 = vdupq_n_f32(factor); + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + 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)); + } + 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; + } +} +#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) +{ +#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); + } 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); + } else +#endif + { +#if 0 + ma_dr_flac_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); +#endif + } +} +MA_API ma_uint64 ma_dr_flac_read_pcm_frames_f32(ma_dr_flac* pFlac, ma_uint64 framesToRead, float* pBufferOut) +{ + ma_uint64 framesRead; + ma_uint32 unusedBitsPerSample; + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + if (pBufferOut == NULL) { + return ma_dr_flac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + MA_DR_FLAC_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)) { + 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; + 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; + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + ma_dr_flac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + ma_dr_flac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + ma_dr_flac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + case MA_DR_FLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + ma_dr_flac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + ma_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] = (float)(sampleS32 / 2147483648.0); + } + } + } + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration; + } + } + return framesRead; +} +MA_API ma_bool32 ma_dr_flac_seek_to_pcm_frame(ma_dr_flac* pFlac, ma_uint64 pcmFrameIndex) +{ + if (pFlac == NULL) { + return MA_FALSE; + } + if (pFlac->currentPCMFrame == pcmFrameIndex) { + return MA_TRUE; + } + if (pFlac->firstFLACFramePosInBytes == 0) { + return MA_FALSE; + } + if (pcmFrameIndex == 0) { + pFlac->currentPCMFrame = 0; + return ma_dr_flac__seek_to_first_frame(pFlac); + } else { + ma_bool32 wasSuccessful = MA_FALSE; + ma_uint64 originalPCMFrame = pFlac->currentPCMFrame; + if (pcmFrameIndex > pFlac->totalPCMFrameCount) { + pcmFrameIndex = pFlac->totalPCMFrameCount; + } + if (pcmFrameIndex > pFlac->currentPCMFrame) { + ma_uint32 offset = (ma_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); + if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) { + pFlac->currentFLACFrame.pcmFramesRemaining -= offset; + pFlac->currentPCMFrame = pcmFrameIndex; + return MA_TRUE; + } + } else { + ma_uint32 offsetAbs = (ma_uint32)(pFlac->currentPCMFrame - pcmFrameIndex); + ma_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + ma_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining; + if (currentFLACFramePCMFramesConsumed > offsetAbs) { + pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs; + pFlac->currentPCMFrame = pcmFrameIndex; + return MA_TRUE; + } + } +#ifndef MA_DR_FLAC_NO_OGG + if (pFlac->container == ma_dr_flac_container_ogg) + { + wasSuccessful = ma_dr_flac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); + } + else +#endif + { + if (!pFlac->_noSeekTableSeek) { + wasSuccessful = ma_dr_flac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); + } +#if !defined(MA_DR_FLAC_NO_CRC) + if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) { + wasSuccessful = ma_dr_flac__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); + } + } + 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); + } + } + 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)\ +{ \ + type* pSampleData = NULL; \ + ma_uint64 totalPCMFrameCount; \ + \ + MA_DR_FLAC_ASSERT(pFlac != NULL); \ + \ + totalPCMFrameCount = pFlac->totalPCMFrameCount; \ + \ + if (totalPCMFrameCount == 0) { \ + type buffer[4096]; \ + ma_uint64 pcmFramesRead; \ + size_t sampleDataBufferSize = sizeof(buffer); \ + \ + pSampleData = (type*)ma_dr_flac__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) { \ + 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); \ + if (pNewSampleData == NULL) { \ + ma_dr_flac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ + goto on_error; \ + } \ + \ + sampleDataBufferSize = newSampleDataBufferSize; \ + pSampleData = pNewSampleData; \ + } \ + \ + MA_DR_FLAC_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))); \ + } else { \ + ma_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \ + if (dataSize > (ma_uint64)MA_SIZE_MAX) { \ + goto on_error; \ + } \ + \ + pSampleData = (type*)ma_dr_flac__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); \ + } \ + \ + if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ + if (channelsOut) *channelsOut = pFlac->channels; \ + if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \ + \ + ma_dr_flac_close(pFlac); \ + return pSampleData; \ + \ +on_error: \ + ma_dr_flac_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) +{ + ma_dr_flac* pFlac; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + pFlac = ma_dr_flac_open(onRead, onSeek, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__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) +{ + ma_dr_flac* pFlac; + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + pFlac = ma_dr_flac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + return ma_dr_flac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); +} +MA_API void ma_dr_flac_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + ma_dr_flac__free_from_callbacks(p, pAllocationCallbacks); + } else { + ma_dr_flac__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) +{ + if (pIter == NULL) { + return; + } + 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) +{ + ma_int32 length; + const char* pComment; + if (pCommentLengthOut) { + *pCommentLengthOut = 0; + } + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return NULL; + } + length = ma_dr_flac__le2host_32_ptr_unaligned(pIter->pRunningData); + pIter->pRunningData += 4; + pComment = pIter->pRunningData; + pIter->pRunningData += length; + pIter->countRemaining -= 1; + if (pCommentLengthOut) { + *pCommentLengthOut = length; + } + 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) +{ + if (pIter == NULL) { + return; + } + 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) +{ + ma_dr_flac_cuesheet_track cuesheetTrack; + const char* pRunningData; + ma_uint64 offsetHi; + ma_uint64 offsetLo; + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return MA_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; + cuesheetTrack.offset = offsetLo | (offsetHi << 32); + cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; + MA_DR_FLAC_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); + pIter->pRunningData = pRunningData; + pIter->countRemaining -= 1; + if (pCuesheetTrack) { + *pCuesheetTrack = cuesheetTrack; + } + return MA_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 /* MA_NO_FLAC */ + +#if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) +#if !defined(MA_DR_MP3_IMPLEMENTATION) +/* dr_mp3_c begin */ +#ifndef ma_dr_mp3_c +#define ma_dr_mp3_c +#include +#include +#include +MA_API void ma_dr_mp3_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision) +{ + if (pMajor) { + *pMajor = MA_DR_MP3_VERSION_MAJOR; + } + if (pMinor) { + *pMinor = MA_DR_MP3_VERSION_MINOR; + } + if (pRevision) { + *pRevision = MA_DR_MP3_VERSION_REVISION; + } +} +MA_API const char* ma_dr_mp3_version_string(void) +{ + return MA_DR_MP3_VERSION_STRING; +} +#if defined(__TINYC__) +#define MA_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 +#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 +#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) +#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 +#else +static __inline__ __attribute__((always_inline)) void ma_dr_mp3_cpuid(int CPUInfo[], const int InfoType) +{ +#if defined(__PIC__) + __asm__ __volatile__( +#if defined(__x86_64__) + "push %%rbx\n" + "cpuid\n" + "xchgl %%ebx, %1\n" + "pop %%rbx\n" +#else + "xchgl %%ebx, %1\n" + "cpuid\n" + "xchgl %%ebx, %1\n" +#endif + : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#else + __asm__ __volatile__( + "cpuid" + : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#endif +} +#endif +static int ma_dr_mp3_have_simd(void) +{ +#ifdef MA_DR_MP3_ONLY_SIMD + return 1; +#else + static int g_have_simd; + int CPUInfo[4]; +#ifdef MINIMP3_TEST + static int g_counter; + if (g_counter++ > 100) + return 0; +#endif + if (g_have_simd) + goto end; + ma_dr_mp3_cpuid(CPUInfo, 0); + if (CPUInfo[0] > 0) + { + ma_dr_mp3_cpuid(CPUInfo, 1); + g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; + return g_have_simd - 1; + } +end: + return g_have_simd - 1; +#endif +} +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +#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) +{ + 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 +#endif +#endif +#else +#define MA_DR_MP3_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) +{ + ma_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)) +#endif +typedef struct +{ + const ma_uint8 *buf; + int pos, limit; +} ma_dr_mp3_bs; +typedef struct +{ + float scf[3*64]; + ma_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} ma_dr_mp3_L12_scale_info; +typedef struct +{ + ma_uint8 tab_offset, code_tab_width, band_count; +} ma_dr_mp3_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; +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]; + 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) +{ + 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) +{ + ma_uint32 next, cache = 0, s = bs->pos & 7; + int shl = n + s; + const ma_uint8 *p = bs->buf + (bs->pos >> 3); + if ((bs->pos += n) > bs->limit) + return 0; + next = *p++ & (255 >> s); + while ((shl -= 8) > 0) + { + cache |= next << shl; + next = *p++; + } + return cache | (next >> -shl); +} +static int ma_dr_mp3_hdr_valid(const ma_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); +} +static int ma_dr_mp3_hdr_compare(const ma_uint8 *h1, const ma_uint8 *h2) +{ + return ma_dr_mp3_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)); +} +static unsigned ma_dr_mp3_hdr_bitrate_kbps(const ma_uint8 *h) +{ + static const ma_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)]; +} +static unsigned ma_dr_mp3_hdr_sample_rate_hz(const ma_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); +} +static unsigned ma_dr_mp3_hdr_frame_samples(const ma_uint8 *h) +{ + return MA_DR_MP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)MA_DR_MP3_HDR_IS_FRAME_576(h)); +} +static int ma_dr_mp3_hdr_frame_bytes(const ma_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)) + { + frame_bytes &= ~3; + } + return frame_bytes ? frame_bytes : free_format_size; +} +static int ma_dr_mp3_hdr_padding(const ma_uint8 *h) +{ + return MA_DR_MP3_HDR_TEST_PADDING(h) ? (MA_DR_MP3_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) +{ + 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)) + { + static const ma_dr_mp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } }; + alloc = g_alloc_L1; + nbands = 32; + } else if (!MA_DR_MP3_HDR_TEST_MPEG1(hdr)) + { + static const ma_dr_mp3_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); + if (!kbps) + { + kbps = 192; + } + alloc = g_alloc_L2M1; + nbands = 27; + if (kbps < 56) + { + static const ma_dr_mp3_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) + { + nbands = 30; + } + } + sci->total_bands = (ma_uint8)nbands; + sci->stereo_bands = (ma_uint8)MA_DR_MP3_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 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) + }; + int i, m; + for (i = 0; i < bands; i++) + { + float s = 0; + int ba = *pba++; + int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; + for (m = 4; m; m >>= 1) + { + if (mask & m) + { + int b = ma_dr_mp3_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 const ma_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, + 0,17,18,16, + 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, + 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); + int i, k = 0, ba_bits = 0; + const ma_uint8 *ba_code_tab = g_bitalloc_code_tab; + for (i = 0; i < sci->total_bands; i++) + { + ma_uint8 ba; + if (i == k) + { + k += subband_alloc->band_count; + ba_bits = subband_alloc->code_tab_width; + 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)]; + sci->bitalloc[2*i] = ba; + if (i < sci->stereo_bands) + { + ba = ba_code_tab[ma_dr_mp3_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); + } + ma_dr_mp3_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) +{ + int i, j, k, choff = 576; + for (j = 0; j < 4; j++) + { + float *dst = grbuf + group_size*j; + for (i = 0; i < 2*sci->total_bands; i++) + { + int ba = sci->bitalloc[i]; + if (ba != 0) + { + if (ba < 17) + { + 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); + } + } else + { + unsigned mod = (2 << (ba - 17)) + 1; + unsigned code = ma_dr_mp3_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)); + } + } + } + dst += choff; + choff = 18 - choff; + } + } + 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) +{ + 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)); + for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) + { + for (k = 0; k < 12; k++) + { + dst[k + 0] *= scf[0]; + dst[k + 576] *= scf[3]; + } + } +} +#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 const ma_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 }, + { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, + { 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] = { + { 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 }, + { 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,32,32,32,44,44,44,12,12,12,0 }, + { 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 }, + { 4,4,4,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,22,22,22,30,30,30,56,56,56,0 }, + { 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] = { + { 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 }, + { 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,32,32,32,44,44,44,12,12,12,0 }, + { 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 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,6,6,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,6,6,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 } + }; + 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)) + { + 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); + } else + { + main_data_begin = ma_dr_mp3_bs_get_bits(bs, 8 + gr_count) >> gr_count; + } + do + { + if (MA_DR_MP3_HDR_IS_MONO(hdr)) + { + scfsi <<= 4; + } + gr->part_23_length = (ma_uint16)ma_dr_mp3_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); + 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->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)) + { + gr->block_type = (ma_uint8)ma_dr_mp3_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->region_count[0] = 7; + gr->region_count[1] = 255; + if (gr->block_type == MA_DR_MP3_SHORT_BLOCK_TYPE) + { + scfsi &= 0x0F0F; + if (!gr->mixed_block_flag) + { + gr->region_count[0] = 8; + gr->sfbtab = g_scf_short[sr_idx]; + gr->n_long_sfb = 0; + gr->n_short_sfb = 39; + } else + { + gr->sfbtab = g_scf_mixed[sr_idx]; + gr->n_long_sfb = MA_DR_MP3_HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_short_sfb = 30; + } + } + tables = ma_dr_mp3_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); + } 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); + 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); + scfsi <<= 4; + gr++; + } while(--gr_count); + if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) + { + return -1; + } + 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) +{ + int i, k; + for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) + { + int cnt = scf_count[i]; + if (scfsi & 8) + { + MA_DR_MP3_COPY_MEMORY(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); + } 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; + } + } + } + ist_pos += cnt; + scf += cnt; + } + scf[0] = scf[1] = scf[2] = 0; +} +static float ma_dr_mp3_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); + 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 const ma_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]; + int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; + float gain; + if (MA_DR_MP3_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 }; + 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); + } 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; + 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]); + 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); + 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)); + } + } else if (gr->preflag) + { + static const ma_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]); + } + } + 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); + 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); + } +} +static const float g_ma_dr_mp3_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) +{ + float frac; + int sign, mult = 256; + if (x < 129) + { + return g_ma_dr_mp3_pow43[16 + x]; + } + if (x < 1024) + { + mult = 16; + x <<= 3; + } + 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; +} +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 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, + 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, + -253,-318,-351,-367,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,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -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) + 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); + 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]; + int linbits = g_linbits[tab_num]; + if (linbits) + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MA_DR_MP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[MA_DR_MP3_PEEK_BITS(w)]; + while (leaf < 0) + { + MA_DR_MP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[MA_DR_MP3_PEEK_BITS(w) - (leaf >> 3)]; + } + MA_DR_MP3_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); + } else + { + *dst = g_ma_dr_mp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + MA_DR_MP3_FLUSH_BITS(lsb ? 1 : 0); + } + MA_DR_MP3_CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MA_DR_MP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[MA_DR_MP3_PEEK_BITS(w)]; + while (leaf < 0) + { + MA_DR_MP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[MA_DR_MP3_PEEK_BITS(w) - (leaf >> 3)]; + } + MA_DR_MP3_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); + } + MA_DR_MP3_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)]; + 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) + { + 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; + } + bs->pos = layer3gr_limit; +} +static void ma_dr_mp3_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()) + { + 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 + } +#endif + for (; i < n; i++) + { + float a = left[i]; + float b = right[i]; + left[i] = a + b; + right[i] = a - b; + } +} +static void ma_dr_mp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr) +{ + int i; + for (i = 0; i < n; i++) + { + left[i + 576] = left[i]*kr; + 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]) +{ + int i, k; + max_band[0] = max_band[1] = max_band[2] = -1; + for (i = 0; i < nbands; i++) + { + for (k = 0; k < sfb[i]; k += 2) + { + if (right[k] != 0 || right[k + 1] != 0) + { + max_band[i % 3] = i; + break; + } + } + 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 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; + 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)) + { + 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); + 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)) + { + ma_dr_mp3_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) +{ + 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); + 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]); + } + for (i = 0; i < max_blocks; i++) + { + int default_pos = MA_DR_MP3_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]); + } + ma_dr_mp3_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) +{ + int i, len; + float *src = grbuf, *dst = scratch; + for (;0 != (len = *sfb); sfb += 3, src += 2*len) + { + for (i = 0; i < len; i++, src++) + { + *dst++ = src[0*len]; + *dst++ = src[1*len]; + *dst++ = src[2*len]; + } + } + MA_DR_MP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float)); +} +static void ma_dr_mp3_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}, + {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} + }; + 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) + { + 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)); + } +#endif +#ifndef MA_DR_MP3_ONLY_SIMD + for(; i < 8; i++) + { + float u = grbuf[18 + i]; + float d = grbuf[17 - i]; + grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; + grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; + } +#endif + } +} +static void ma_dr_mp3_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]; + t0 = s0 + s6*0.5f; + s0 -= s6; + t4 = (s4 + s2)*0.93969262f; + t2 = (s8 + s2)*0.76604444f; + s6 = (s4 - s8)*0.17364818f; + s4 += s8 - s2; + s2 = s0 - s4*0.5f; + y[4] = s4 + s0; + s8 = t0 - t2 + s6; + s0 = t0 - t4 + t2; + s4 = t0 + t4 - s6; + s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; + s3 *= 0.86602540f; + t0 = (s5 + s1)*0.98480775f; + t4 = (s5 - s7)*0.34202014f; + t2 = (s1 + s7)*0.64278761f; + s1 = (s1 - s5 - s7)*0.86602540f; + s5 = t0 - s3 - t2; + s7 = t4 - s3 - t0; + s3 = t4 + s3 - t2; + y[0] = s4 - s7; + y[1] = s2 + s1; + y[2] = s0 - s3; + y[3] = s8 + s5; + y[5] = s8 - s5; + y[6] = s0 + s3; + y[7] = s2 - s1; + y[8] = s4 + s7; +} +static void ma_dr_mp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +{ + int i, j; + static const float g_twid9[18] = { + 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f + }; + for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) + { + float co[9], si[9]; + co[0] = -grbuf[0]; + si[0] = grbuf[17]; + for (i = 0; i < 4; i++) + { + si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; + co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; + 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); + 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) + { + 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)); + } +#endif + for (; i < 9; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; + overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; + grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; + grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; + } + } +} +static void ma_dr_mp3_L3_idct3(float x0, float x1, float x2, float *dst) +{ + float m1 = x1*0.86602540f; + float a1 = x0 - x2*0.5f; + dst[1] = x0 + x2; + dst[0] = a1 + m1; + dst[2] = a1 - m1; +} +static void ma_dr_mp3_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); + si[1] = -si[1]; + for (i = 0; i < 3; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; + overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; + dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; + 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) +{ + 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); + } +} +static void ma_dr_mp3_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 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 }, + { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } + }; + if (n_long_bands) + { + ma_dr_mp3_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); + else + ma_dr_mp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == MA_DR_MP3_STOP_BLOCK_TYPE], 32 - n_long_bands); +} +static void ma_dr_mp3_L3_save_reservoir(ma_dr_mp3dec *h, ma_dr_mp3dec_scratch *s) +{ + int pos = (s->bs.pos + 7)/8u; + int remains = s->bs.limit/8u - pos; + if (remains > MA_DR_MP3_MAX_BITRESERVOIR_BYTES) + { + pos += remains - MA_DR_MP3_MAX_BITRESERVOIR_BYTES; + remains = MA_DR_MP3_MAX_BITRESERVOIR_BYTES; + } + if (remains > 0) + { + MA_DR_MP3_MOVE_MEMORY(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) +{ + 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); + 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) +{ + 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); + } + if (MA_DR_MP3_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)) + { + ma_dr_mp3_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); + 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); + } + 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]); + } +} +static void ma_dr_mp3d_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) + { + ma_dr_mp3_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]); + } + 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); + } + 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) +#else +#define MA_DR_MP3_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)); + } + 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]); + } else + { +#define MA_DR_MP3_VSAVE4(i, v) MA_DR_MP3_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)); + } + 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]); + } + } else +#endif +#ifdef MA_DR_MP3_ONLY_SIMD + {} +#else + for (; k < n; k++) + { + float t[4][8], *x, *y = grbuf + k; + for (x = t[0], i = 0; i < 8; i++, x++) + { + float x0 = y[i*18]; + float x1 = y[(15 - i)*18]; + float x2 = y[(16 + i)*18]; + float x3 = y[(31 - i)*18]; + float t0 = x0 + x3; + float t1 = x1 + x2; + float t2 = (x1 - x2)*g_sec[3*i + 0]; + float t3 = (x0 - x3)*g_sec[3*i + 1]; + x[0] = t0 + t1; + x[8] = (t0 - t1)*g_sec[3*i + 2]; + x[16] = t3 + t2; + x[24] = (t3 - t2)*g_sec[3*i + 2]; + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + float 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 = x0 - x7; x0 += x7; + x7 = x1 - x6; x1 += x6; + x6 = x2 - x5; x2 += x5; + x5 = x3 - x4; x3 += x4; + x4 = x0 - x3; x0 += x3; + x3 = x1 - x2; x1 += x2; + x[0] = x0 + x1; + x[4] = (x0 - x1)*0.70710677f; + x5 = x5 + x6; + x6 = (x6 + x7)*0.70710677f; + x7 = x7 + xt; + x3 = (x3 + x4)*0.70710677f; + x5 -= x7*0.198912367f; + x7 += x5*0.382683432f; + x5 -= x7*0.198912367f; + x0 = xt - x6; xt += x6; + x[1] = (xt + x7)*0.50979561f; + x[2] = (x4 + x3)*0.54119611f; + x[3] = (x0 - x5)*0.60134488f; + x[5] = (x0 + x5)*0.89997619f; + x[6] = (x4 - x3)*1.30656302f; + x[7] = (xt - x7)*2.56291556f; + } + for (i = 0; i < 7; i++, y += 4*18) + { + y[0*18] = t[0][i]; + y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; + y[2*18] = t[1][i] + t[1][i + 1]; + y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; + } + y[0*18] = t[0][7]; + y[1*18] = t[2][7] + t[3][7]; + y[2*18] = t[1][7]; + y[3*18] = t[3][7]; + } +#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) +{ + ma_int16 s; +#if MA_DR_MP3_HAVE_ARMV6 + ma_int32 s32 = (ma_int32)(sample + .5f); + s32 -= (s32 < 0); + s = (ma_int16)ma_dr_mp3_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); + s -= (s < 0); +#endif + return s; +} +#else +typedef float ma_dr_mp3d_sample_t; +static float ma_dr_mp3d_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) +{ + float a; + a = (z[14*64] - z[ 0]) * 29; + a += (z[ 1*64] + z[13*64]) * 213; + a += (z[12*64] - z[ 2*64]) * 459; + a += (z[ 3*64] + z[11*64]) * 2037; + a += (z[10*64] - z[ 4*64]) * 5153; + 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); + z += 2; + a = z[14*64] * 104; + a += z[12*64] * 1567; + a += z[10*64] * 9727; + a += z[ 8*64] * 64019; + a += z[ 6*64] * -9975; + a += z[ 4*64] * -45; + a += z[ 2*64] * 146; + a += z[ 0*64] * -5; + pcm[16*nch] = ma_dr_mp3d_scale_pcm(a); +} +static void ma_dr_mp3d_synth(float *xl, ma_dr_mp3d_sample_t *dstl, int nch, float *lins) +{ + int i; + float *xr = xl + 576*(nch - 1); + ma_dr_mp3d_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, + -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, + -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, + -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, + -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, + -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, + -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, + -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, + -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, + -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, + -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, + -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, + -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, + -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 + }; + float *zlin = lins + 15*64; + const float *w = g_win; + zlin[4*15] = xl[18*16]; + zlin[4*15 + 1] = xr[18*16]; + zlin[4*15 + 2] = xl[0]; + zlin[4*15 + 3] = xr[0]; + zlin[4*31] = xl[1 + 18*16]; + 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--) + { +#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; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*i + 64] = xl[1 + 18*(1 + i)]; + 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) + { +#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 }; + __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); +#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))))); + 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); + vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); + vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); + vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); + vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); + 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 + _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))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif +#endif + } + } else +#endif +#ifdef MA_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; } + float a[4], b[4]; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; + 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]); + } +#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) +{ + int i; + for (i = 0; i < nch; i++) + { + ma_dr_mp3d_DCT_II(grbuf + 576*i, nbands); + } + MA_DR_MP3_COPY_MEMORY(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); + } +#ifndef MA_DR_MP3_NONSTANDARD_BUT_LOGICAL + if (nch == 1) + { + for (i = 0; i < 15*64; i += 2) + { + qmf_state[i] = lins[nbands*64 + i]; + } + } else +#endif + { + MA_DR_MP3_COPY_MEMORY(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) +{ + int i, nmatch; + for (i = 0, nmatch = 0; nmatch < MA_DR_MP3_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) + return nmatch > 0; + if (!ma_dr_mp3_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) +{ + int i, k; + for (i = 0; i < mp3_bytes - MA_DR_MP3_HDR_SIZE; i++, mp3++) + { + if (ma_dr_mp3_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++) + { + if (ma_dr_mp3_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)) + continue; + frame_and_padding = k; + frame_bytes = fb; + *free_format_bytes = fb; + } + } + if ((frame_bytes && i + frame_and_padding <= mp3_bytes && + ma_dr_mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + (!i && frame_and_padding == mp3_bytes)) + { + *ptr_frame_bytes = frame_and_padding; + return i; + } + *free_format_bytes = 0; + } + } + *ptr_frame_bytes = 0; + return mp3_bytes; +} +MA_API void ma_dr_mp3dec_init(ma_dr_mp3dec *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) +{ + 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)) + { + 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 = 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); + if (!frame_size || i + frame_size > mp3_bytes) + { + info->frame_bytes = i; + return 0; + } + } + hdr = mp3 + i; + MA_DR_MP3_COPY_MEMORY(dec->header, hdr, MA_DR_MP3_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)) + { + ma_dr_mp3_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); + if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) + { + ma_dr_mp3dec_init(dec); + return 0; + } + success = ma_dr_mp3_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)) + { + 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]); + } + } + ma_dr_mp3_L3_save_reservoir(dec, &scratch); + } else + { +#ifdef MA_DR_MP3_ONLY_MP3 + return 0; +#else + ma_dr_mp3_L12_scale_info sci[1]; + if (pcm == NULL) { + return ma_dr_mp3_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)); + 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))) + { + 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); + } + if (bs_frame->pos > bs_frame->limit) + { + ma_dr_mp3dec_init(dec); + return 0; + } + } +#endif + } + return success*ma_dr_mp3_hdr_frame_samples(dec->header); +} +MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_samples) +{ + size_t i = 0; +#if MA_DR_MP3_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); + __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); +#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))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif + } +#endif + 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; + else + { + short s = (ma_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 +#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) +#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 +#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) +{ + return x*(1-a) + y*a; +} +static MA_INLINE float ma_dr_mp3_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) +{ + for (;;) { + if (b == 0) { + break; + } else { + ma_uint32 t = a; + a = b; + b = t % a; + } + } + return a; +} +static void* ma_dr_mp3__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_DR_MP3_MALLOC(sz); +} +static void* ma_dr_mp3__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return MA_DR_MP3_REALLOC(p, sz); +} +static void ma_dr_mp3__free_default(void* p, void* pUserData) +{ + (void)pUserData; + MA_DR_MP3_FREE(p); +} +static void* ma_dr_mp3__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); + } + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + return NULL; +} +static void* ma_dr_mp3__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); + } + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + if (p != NULL) { + MA_DR_MP3_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) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} +static ma_allocation_callbacks ma_dr_mp3_copy_allocation_callbacks_or_defaults(const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + return *pAllocationCallbacks; + } else { + ma_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; + return allocationCallbacks; + } +} +static size_t ma_dr_mp3__on_read(ma_dr_mp3* 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) +{ + MA_DR_MP3_ASSERT(offset >= 0); + if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) { + return MA_FALSE; + } + if (origin == ma_dr_mp3_seek_origin_start) { + pMP3->streamCursor = (ma_uint64)offset; + } else { + pMP3->streamCursor += offset; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_mp3__on_seek_64(ma_dr_mp3* pMP3, ma_uint64 offset, ma_dr_mp3_seek_origin origin) +{ + if (offset <= 0x7FFFFFFF) { + return ma_dr_mp3__on_seek(pMP3, (int)offset, origin); + } + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_start)) { + return MA_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; + } + offset = 0; + } else { + if (!ma_dr_mp3__on_seek(pMP3, 0x7FFFFFFF, ma_dr_mp3_seek_origin_current)) { + return MA_FALSE; + } + offset -= 0x7FFFFFFF; + } + } + return MA_TRUE; +} +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__callbacks(ma_dr_mp3* pMP3, ma_dr_mp3d_sample_t* pPCMFrames) +{ + ma_uint32 pcmFramesRead = 0; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_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) { + size_t bytesRead; + if (pMP3->pData != NULL) { + MA_DR_MP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + } + pMP3->dataConsumed = 0; + if (pMP3->dataCapacity < MA_DR_MP3_DATA_CHUNK_SIZE) { + ma_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); + 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)); + if (bytesRead == 0) { + if (pMP3->dataSize == 0) { + pMP3->atEnd = MA_TRUE; + return 0; + } + } + pMP3->dataSize += bytesRead; + } + if (pMP3->dataSize > INT_MAX) { + pMP3->atEnd = MA_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); + 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); + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; + pMP3->mp3FrameChannels = info.channels; + pMP3->mp3FrameSampleRate = info.hz; + break; + } else if (info.frame_bytes == 0) { + size_t bytesRead; + MA_DR_MP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize); + pMP3->dataConsumed = 0; + if (pMP3->dataCapacity == pMP3->dataSize) { + ma_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); + 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)); + if (bytesRead == 0) { + pMP3->atEnd = MA_TRUE; + return 0; + } + pMP3->dataSize += bytesRead; + } + }; + return pcmFramesRead; +} +static ma_uint32 ma_dr_mp3_decode_next_frame_ex__memory(ma_dr_mp3* pMP3, ma_dr_mp3d_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); + 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; + } + } + 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) +{ + if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) { + return ma_dr_mp3_decode_next_frame_ex__memory(pMP3, pPCMFrames); + } else { + return ma_dr_mp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames); + } +} +static ma_uint32 ma_dr_mp3_decode_next_frame(ma_dr_mp3* pMP3) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + return ma_dr_mp3_decode_next_frame_ex(pMP3, (ma_dr_mp3d_sample_t*)pMP3->pcmFrames); +} +#if 0 +static ma_uint32 ma_dr_mp3_seek_next_frame(ma_dr_mp3* pMP3) +{ + ma_uint32 pcmFrameCount; + MA_DR_MP3_ASSERT(pMP3 != NULL); + pcmFrameCount = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFrameCount == 0) { + return 0; + } + pMP3->currentPCMFrame += pcmFrameCount; + pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount; + pMP3->pcmFramesRemainingInMP3Frame = 0; + 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) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(onRead != NULL); + ma_dr_mp3dec_init(&pMP3->decoder); + pMP3->onRead = onRead; + pMP3->onSeek = onSeek; + pMP3->pUserData = pUserData; + pMP3->allocationCallbacks = ma_dr_mp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) { + return MA_FALSE; + } + if (ma_dr_mp3_decode_next_frame(pMP3) == 0) { + ma_dr_mp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); + return MA_FALSE; + } + pMP3->channels = pMP3->mp3FrameChannels; + pMP3->sampleRate = pMP3->mp3FrameSampleRate; + return MA_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) +{ + if (pMP3 == NULL || onRead == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); + return ma_dr_mp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks); +} +static size_t ma_dr_mp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + size_t bytesRemaining; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_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); + 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) +{ + ma_dr_mp3* pMP3 = (ma_dr_mp3*)pUserData; + MA_DR_MP3_ASSERT(pMP3 != NULL); + if (origin == ma_dr_mp3_seek_origin_current) { + if (byteOffset > 0) { + if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { + byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); + } + } else { + if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { + byteOffset = -(int)pMP3->memory.currentReadPos; + } + } + pMP3->memory.currentReadPos += byteOffset; + } else { + if ((ma_uint32)byteOffset <= pMP3->memory.dataSize) { + pMP3->memory.currentReadPos = byteOffset; + } else { + pMP3->memory.currentReadPos = pMP3->memory.dataSize; + } + } + return MA_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) +{ + if (pMP3 == NULL) { + return MA_FALSE; + } + MA_DR_MP3_ZERO_OBJECT(pMP3); + if (pData == NULL || dataSize == 0) { + return MA_FALSE; + } + pMP3->memory.pData = (const ma_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); +} +#ifndef MA_DR_MP3_NO_STDIO +#include +#include +static size_t ma_dr_mp3__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) +{ + return fseek((FILE*)pUserData, offset, (origin == ma_dr_mp3_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) +{ + ma_bool32 result; + FILE* pFile; + if (ma_fopen(&pFile, pFilePath, "rb") != MA_SUCCESS) { + return MA_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) { + fclose(pFile); + return result; + } + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_init_file_w(ma_dr_mp3* pMP3, const wchar_t* pFilePath, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_bool32 result; + FILE* pFile; + if (ma_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != MA_SUCCESS) { + return MA_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) { + fclose(pFile); + return result; + } + return MA_TRUE; +} +#endif +MA_API void ma_dr_mp3_uninit(ma_dr_mp3* pMP3) +{ + if (pMP3 == NULL) { + return; + } +#ifndef MA_DR_MP3_NO_STDIO + if (pMP3->onRead == ma_dr_mp3__on_read_stdio) { + FILE* pFile = (FILE*)pMP3->pUserData; + if (pFile != NULL) { + fclose(pFile); + pMP3->pUserData = NULL; + } + } +#endif + ma_dr_mp3__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) +{ + ma_uint64 i; + ma_uint64 i4; + ma_uint64 sampleCount4; + i = 0; + sampleCount4 = sampleCount >> 2; + for (i4 = 0; i4 < sampleCount4; i4 += 1) { + float x0 = src[i+0]; + float x1 = src[i+1]; + float x2 = src[i+2]; + float x3 = src[i+3]; + x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0)); + x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1)); + x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2)); + x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3)); + x0 = x0 * 32767.0f; + 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; + 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; + } +} +#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) +{ + ma_uint64 i; + for (i = 0; i < sampleCount; i += 1) { + float x = (float)src[i]; + x = x * 0.000030517578125f; + dst[i] = x; + } +} +#endif +static ma_uint64 ma_dr_mp3_read_pcm_frames_raw(ma_dr_mp3* pMP3, ma_uint64 framesToRead, void* pBufferOut) +{ + ma_uint64 totalFramesRead = 0; + MA_DR_MP3_ASSERT(pMP3 != NULL); + MA_DR_MP3_ASSERT(pMP3->onRead != NULL); + while (framesToRead > 0) { + ma_uint32 framesToConsume = (ma_uint32)MA_DR_MP3_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); + #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); + #endif + } + pMP3->currentPCMFrame += framesToConsume; + pMP3->pcmFramesConsumedInMP3Frame += framesToConsume; + pMP3->pcmFramesRemainingInMP3Frame -= framesToConsume; + totalFramesRead += framesToConsume; + framesToRead -= framesToConsume; + if (framesToRead == 0) { + break; + } + MA_DR_MP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0); + if (ma_dr_mp3_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) +{ + 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); +#else + { + ma_int16 pTempS16[8192]; + ma_uint64 totalPCMFramesRead = 0; + while (totalPCMFramesRead < framesToRead) { + ma_uint64 framesJustRead; + ma_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + ma_uint64 framesToReadNow = MA_DR_MP3_COUNTOF(pTempS16) / pMP3->channels; + if (framesToReadNow > framesRemaining) { + framesToReadNow = framesRemaining; + } + framesJustRead = ma_dr_mp3_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); + 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) +{ + 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); +#else + { + float pTempF32[4096]; + ma_uint64 totalPCMFramesRead = 0; + while (totalPCMFramesRead < framesToRead) { + ma_uint64 framesJustRead; + ma_uint64 framesRemaining = framesToRead - totalPCMFramesRead; + ma_uint64 framesToReadNow = MA_DR_MP3_COUNTOF(pTempF32) / pMP3->channels; + if (framesToReadNow > framesRemaining) { + framesToReadNow = framesRemaining; + } + framesJustRead = ma_dr_mp3_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); + totalPCMFramesRead += framesJustRead; + } + return totalPCMFramesRead; + } +#endif +} +static void ma_dr_mp3_reset(ma_dr_mp3* pMP3) +{ + MA_DR_MP3_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); +} +static ma_bool32 ma_dr_mp3_seek_to_start_of_stream(ma_dr_mp3* 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; + } + ma_dr_mp3_reset(pMP3); + return MA_TRUE; +} +static ma_bool32 ma_dr_mp3_seek_forward_by_pcm_frames__brute_force(ma_dr_mp3* pMP3, ma_uint64 frameOffset) +{ + ma_uint64 framesRead; +#if defined(MA_DR_MP3_FLOAT_OUTPUT) + framesRead = ma_dr_mp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); +#else + framesRead = ma_dr_mp3_read_pcm_frames_s16(pMP3, frameOffset, NULL); +#endif + if (framesRead != frameOffset) { + return MA_FALSE; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__brute_force(ma_dr_mp3* pMP3, ma_uint64 frameIndex) +{ + MA_DR_MP3_ASSERT(pMP3 != NULL); + if (frameIndex == pMP3->currentPCMFrame) { + return MA_TRUE; + } + if (frameIndex < pMP3->currentPCMFrame) { + if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { + return MA_FALSE; + } + } + MA_DR_MP3_ASSERT(frameIndex >= pMP3->currentPCMFrame); + return ma_dr_mp3_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) +{ + ma_uint32 iSeekPoint; + MA_DR_MP3_ASSERT(pSeekPointIndex != NULL); + *pSeekPointIndex = 0; + if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) { + return MA_FALSE; + } + for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) { + if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) { + break; + } + *pSeekPointIndex = iSeekPoint; + } + return MA_TRUE; +} +static ma_bool32 ma_dr_mp3_seek_to_pcm_frame__seek_table(ma_dr_mp3* pMP3, ma_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)) { + seekPoint = pMP3->pSeekPoints[priorSeekPointIndex]; + } else { + seekPoint.seekPosInBytes = 0; + seekPoint.pcmFrameIndex = 0; + 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; + } + ma_dr_mp3_reset(pMP3); + for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) { + ma_uint32 pcmFramesRead; + ma_dr_mp3d_sample_t* pPCMFrames; + pPCMFrames = NULL; + if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { + pPCMFrames = (ma_dr_mp3d_sample_t*)pMP3->pcmFrames; + } + pcmFramesRead = ma_dr_mp3_decode_next_frame_ex(pMP3, pPCMFrames); + if (pcmFramesRead == 0) { + return MA_FALSE; + } + } + pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard; + leftoverFrames = frameIndex - pMP3->currentPCMFrame; + return ma_dr_mp3_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) +{ + if (pMP3 == NULL || pMP3->onSeek == NULL) { + return MA_FALSE; + } + if (frameIndex == 0) { + return ma_dr_mp3_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); + } else { + return ma_dr_mp3_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) +{ + ma_uint64 currentPCMFrame; + ma_uint64 totalPCMFrameCount; + ma_uint64 totalMP3FrameCount; + if (pMP3 == NULL) { + return MA_FALSE; + } + if (pMP3->onSeek == NULL) { + return MA_FALSE; + } + currentPCMFrame = pMP3->currentPCMFrame; + if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { + return MA_FALSE; + } + totalPCMFrameCount = 0; + totalMP3FrameCount = 0; + for (;;) { + ma_uint32 pcmFramesInCurrentMP3Frame; + pcmFramesInCurrentMP3Frame = ma_dr_mp3_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 (!ma_dr_mp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return MA_FALSE; + } + if (pMP3FrameCount != NULL) { + *pMP3FrameCount = totalMP3FrameCount; + } + if (pPCMFrameCount != NULL) { + *pPCMFrameCount = totalPCMFrameCount; + } + return MA_TRUE; +} +MA_API ma_uint64 ma_dr_mp3_get_pcm_frame_count(ma_dr_mp3* pMP3) +{ + ma_uint64 totalPCMFrameCount; + if (!ma_dr_mp3_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) +{ + ma_uint64 totalMP3FrameCount; + if (!ma_dr_mp3_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) +{ + float srcRatio; + float pcmFrameCountOutF; + ma_uint32 pcmFrameCountOut; + srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; + MA_DR_MP3_ASSERT(srcRatio > 0); + pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio); + pcmFrameCountOut = (ma_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) +{ + ma_uint32 seekPointCount; + ma_uint64 currentPCMFrame; + ma_uint64 totalMP3FrameCount; + ma_uint64 totalPCMFrameCount; + if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) { + return MA_FALSE; + } + seekPointCount = *pSeekPointCount; + if (seekPointCount == 0) { + return MA_FALSE; + } + currentPCMFrame = pMP3->currentPCMFrame; + if (!ma_dr_mp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) { + return MA_FALSE; + } + if (totalMP3FrameCount < MA_DR_MP3_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; + float runningPCMFrameCountFractionalPart = 0; + ma_uint64 nextTargetPCMFrame; + ma_uint32 iMP3Frame; + ma_uint32 iSeekPoint; + if (seekPointCount > totalMP3FrameCount-1) { + seekPointCount = (ma_uint32)totalMP3FrameCount-1; + } + pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1); + if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { + return MA_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); + mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; + mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; + pcmFramesInCurrentMP3FrameIn = ma_dr_mp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFramesInCurrentMP3FrameIn == 0) { + return MA_FALSE; + } + ma_dr_mp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + } + nextTargetPCMFrame = 0; + for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) { + nextTargetPCMFrame += pcmFramesBetweenSeekPoints; + for (;;) { + 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); + break; + } else { + size_t i; + ma_uint32 pcmFramesInCurrentMP3FrameIn; + for (i = 0; i < MA_DR_MP3_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); + 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); + break; + } + ma_dr_mp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); + } + } + } + if (!ma_dr_mp3_seek_to_start_of_stream(pMP3)) { + return MA_FALSE; + } + if (!ma_dr_mp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) { + return MA_FALSE; + } + } + *pSeekPointCount = seekPointCount; + return MA_TRUE; +} +MA_API ma_bool32 ma_dr_mp3_bind_seek_table(ma_dr_mp3* pMP3, ma_uint32 seekPointCount, ma_dr_mp3_seek_point* pSeekPoints) +{ + if (pMP3 == NULL) { + return MA_FALSE; + } + if (seekPointCount == 0 || pSeekPoints == NULL) { + pMP3->seekPointCount = 0; + pMP3->pSeekPoints = NULL; + } else { + pMP3->seekPointCount = seekPointCount; + pMP3->pSeekPoints = pSeekPoints; + } + return MA_TRUE; +} +static float* ma_dr_mp3__full_read_and_close_f32(ma_dr_mp3* pMP3, ma_dr_mp3_config* pConfig, ma_uint64* pTotalFrameCount) +{ + ma_uint64 totalFramesRead = 0; + ma_uint64 framesCapacity = 0; + float* pFrames = NULL; + float temp[4096]; + MA_DR_MP3_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); + if (framesJustRead == 0) { + break; + } + if (framesCapacity < totalFramesRead + framesJustRead) { + ma_uint64 oldFramesBufferSize; + ma_uint64 newFramesBufferSize; + ma_uint64 newFramesCap; + float* pNewFrames; + newFramesCap = framesCapacity * 2; + if (newFramesCap < totalFramesRead + framesJustRead) { + newFramesCap = totalFramesRead + framesJustRead; + } + oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float); + newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float); + if (newFramesBufferSize > (ma_uint64)MA_SIZE_MAX) { + break; + } + pNewFrames = (float*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); + if (pNewFrames == NULL) { + ma_dr_mp3__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))); + totalFramesRead += framesJustRead; + if (framesJustRead != framesToReadRightNow) { + break; + } + } + if (pConfig != NULL) { + pConfig->channels = pMP3->channels; + pConfig->sampleRate = pMP3->sampleRate; + } + ma_dr_mp3_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) +{ + ma_uint64 totalFramesRead = 0; + ma_uint64 framesCapacity = 0; + ma_int16* pFrames = NULL; + ma_int16 temp[4096]; + MA_DR_MP3_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); + if (framesJustRead == 0) { + break; + } + if (framesCapacity < totalFramesRead + framesJustRead) { + ma_uint64 newFramesBufferSize; + ma_uint64 oldFramesBufferSize; + ma_uint64 newFramesCap; + ma_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) { + break; + } + pNewFrames = (ma_int16*)ma_dr_mp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks); + if (pNewFrames == NULL) { + ma_dr_mp3__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))); + totalFramesRead += framesJustRead; + if (framesJustRead != framesToReadRightNow) { + break; + } + } + if (pConfig != NULL) { + pConfig->channels = pMP3->channels; + pConfig->sampleRate = pMP3->sampleRate; + } + ma_dr_mp3_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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init_file(&mp3, filePath, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__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) +{ + ma_dr_mp3 mp3; + if (!ma_dr_mp3_init_file(&mp3, filePath, pAllocationCallbacks)) { + return NULL; + } + return ma_dr_mp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); +} +#endif +MA_API void* ma_dr_mp3_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + return ma_dr_mp3__malloc_from_callbacks(sz, pAllocationCallbacks); + } else { + return ma_dr_mp3__malloc_default(sz, NULL); + } +} +MA_API void ma_dr_mp3_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + ma_dr_mp3__free_from_callbacks(p, pAllocationCallbacks); + } else { + ma_dr_mp3__free_default(p, NULL); + } +} +#endif +/* dr_mp3_c end */ +#endif /* MA_DR_MP3_IMPLEMENTATION */ +#endif /* MA_NO_MP3 */ + + +/* End globally disabled warnings. */ +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + +#endif /* miniaudio_c */ +#endif /* MINIAUDIO_IMPLEMENTATION */ + + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - 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. + +For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2025 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 +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. + +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/msf_gif.h b/raylib/external/msf_gif.h new file mode 100644 index 0000000..bc2c6ed --- /dev/null +++ b/raylib/external/msf_gif.h @@ -0,0 +1,717 @@ +/* +HOW TO USE: + + In exactly one translation unit (.c or .cpp file), #define MSF_GIF_IMPL before including the header, like so: + + #define MSF_GIF_IMPL + #include "msf_gif.h" + + Everywhere else, just include the header like normal. + + +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); + } + 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. + To facilitate integration with custom memory allocators, these calls go through macros, which can be redefined. + The expected function signature equivalents of the macros are as follows: + + void * MSF_GIF_MALLOC(void * context, size_t newSize) + void * MSF_GIF_REALLOC(void * context, void * oldMemory, size_t oldSize, size_t newSize) + void MSF_GIF_FREE(void * context, void * oldMemory, size_t oldSize) + + 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 /// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef MSF_GIF_H +#define MSF_GIF_H + +#include +#include + +typedef struct { + void * data; + size_t dataSize; + + size_t allocSize; //internal use + void * contextPointer; //internal use +} MsfGifResult; + +typedef struct { //internal use + uint32_t * pixels; + 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; + int width, height; + void * customAllocatorContext; + int framesSubmitted; //needed for transparency to work correctly (because we reach into the previous frame) +} MsfGifState; + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/** + * @param width Image width in pixels. + * @param height Image height in pixels. + * @return Non-zero on success, 0 on error. + */ +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`). + * 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. + * @param maxBitDepth Limits how many bits per pixel can be used when quantizing the gif. + * The actual bit depth chosen for a given frame will be less than or equal to + * the supplied maximum, depending on the variety of colors used in the frame. + * `maxBitDepth` will be clamped between 1 and 16. The recommended default is 16. + * Lowering this value can result in faster exports and smaller gifs, + * but the quality may suffer. + * Please experiment with this value to find what works best for your application. + * @param pitchInBytes The number of bytes from the beginning of one row of pixels to the beginning of the next. + * If you want to flip the image, just pass in a negative pitch. + * @return Non-zero on success, 0 on error. + */ +int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes); + +/** + * @return A block of memory containing the gif file data, or NULL on error. + * You are responsible for freeing this via `msf_gif_free()`. + */ +MsfGifResult msf_gif_end(MsfGifState * handle); + +/** + * @param result The MsfGifResult struct, verbatim as it was returned from `msf_gif_end()`. + */ +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 + +#endif //MSF_GIF_H + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef MSF_GIF_IMPL +#ifndef MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT +#define MSF_GIF_ALREADY_IMPLEMENTED_IN_THIS_TRANSLATION_UNIT + +//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 +#else +#error "You must either define all of MSF_GIF_MALLOC, MSF_GIF_REALLOC, and MSF_GIF_FREE, or define none of them" +#endif + +//provide default allocator definitions that redirect to the standard global allocator +#if !defined(MSF_GIF_MALLOC) +#include //malloc, etc. +#define MSF_GIF_MALLOC(contextPointer, newSize) malloc(newSize) +#define MSF_GIF_REALLOC(contextPointer, oldMemory, oldSize, newSize) realloc(oldMemory, newSize) +#define MSF_GIF_FREE(contextPointer, oldMemory, oldSize) free(oldMemory) +#endif + +//instrumentation for capturing profiling traces (useless for the library user, but useful for the library author) +#ifdef MSF_GIF_ENABLE_TRACING +#define MsfTimeFunc TimeFunc +#define MsfTimeLoop TimeLoop +#define msf_init_profiling_thread init_profiling_thread +#else +#define MsfTimeFunc +#define MsfTimeLoop(name) +#define msf_init_profiling_thread() +#endif //MSF_GIF_ENABLE_TRACING + +#include //memcpy + +//TODO: use compiler-specific notation to force-inline functions currently marked inline +#if defined(__GNUC__) //gcc, clang +static inline int msf_bit_log(int i) { return 32 - __builtin_clz(i); } +#elif defined(_MSC_VER) //msvc +#include +static inline int msf_bit_log(int i) { unsigned long idx; _BitScanReverse(&idx, i); return idx + 1; } +#else //fallback implementation for other compilers +//from https://stackoverflow.com/a/31718095/3064745 - thanks! +static inline int msf_bit_log(int i) { + static const int MultiplyDeBruijnBitPosition[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31, + }; + i |= i >> 1; + i |= i >> 2; + i |= i >> 4; + i |= i >> 8; + i |= i >> 16; + return MultiplyDeBruijnBitPosition[(uint32_t)(i * 0x07C4ACDDU) >> 27] + 1; +} +#endif +static inline int msf_imin(int a, int b) { return a < b? a : b; } +static inline int msf_imax(int a, int b) { return b < a? a : b; } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Frame Cooking /// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if (defined (__SSE2__) || defined (_M_X64) || _M_IX86_FP == 2) && !defined(MSF_GIF_NO_SSE2) +#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) +{ 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; + + static const 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; + int count = 0; + MsfTimeLoop("do") do { + int rbits = rdepths[depth], gbits = gdepths[depth], bbits = bdepths[depth]; + int paletteSize = (1 << (rbits + gbits + bbits)) + 1; + memset(used, 0, paletteSize * sizeof(uint8_t)); + + //TODO: document what this math does and why it's correct + int rdiff = (1 << (8 - rbits)) - 1; + int gdiff = (1 << (8 - gbits)) - 1; + int bdiff = (1 << (8 - bbits)) - 1; + short rmul = (short) ((255.0f - rdiff) / 255.0f * 257); + short gmul = (short) ((255.0f - gdiff) / 255.0f * 257); + short bmul = (short) ((255.0f - bdiff) / 255.0f * 257); + + int gmask = ((1 << gbits) - 1) << rbits; + int bmask = ((1 << bbits) - 1) << rbits << gbits; + + MsfTimeLoop("cook") for (int y = 0; y < height; ++y) { + int x = 0; + + #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)); + for (; x < width - 3; x += 4) { + uint8_t * pixels = &raw[y * pitch + x * 4]; + __m128i p = _mm_loadu_si128((__m128i *) pixels); + + __m128i rb = _mm_and_si128(p, _mm_set1_epi32(0x00FF00FF)); + __m128i rb1 = _mm_mullo_epi16(rb, _mm_set_epi16(bmul, rmul, bmul, rmul, bmul, rmul, bmul, rmul)); + __m128i rb2 = _mm_adds_epu16(rb1, k2); + __m128i r3 = _mm_srli_epi32(_mm_and_si128(rb2, _mm_set1_epi32(0x0000FFFF)), 16 - rbits); + __m128i b3 = _mm_and_si128(_mm_srli_epi32(rb2, 32 - rbits - gbits - bbits), _mm_set1_epi32(bmask)); + + __m128i g = _mm_and_si128(_mm_srli_epi32(p, 8), _mm_set1_epi32(0x000000FF)); + __m128i g1 = _mm_mullo_epi16(g, _mm_set1_epi32(gmul)); + __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]; + _mm_storeu_si128((__m128i *) c, out); + } + #endif + + //scalar cleanup loop + 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] = + (msf_imin(65535, p[2] * bmul + (k >> bbits)) >> (16 - rbits - gbits - bbits) & bmask) | + (msf_imin(65535, p[1] * gmul + (k >> gbits)) >> (16 - rbits - gbits ) & gmask) | + msf_imin(65535, p[0] * rmul + (k >> rbits)) >> (16 - rbits ); + } + } + + count = 0; + MsfTimeLoop("mark") 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[j]; + } + } while (count >= 256 && --depth); + + MsfCookedFrame ret = { cooked, depth, count, rdepths[depth], gdepths[depth], bdepths[depth] }; + *frame = ret; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Frame Compression /// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline void 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; + (*writeHead)[idx + 0] |= code << bit ; + (*writeHead)[idx + 1] |= code >> ( 8 - bit); + (*writeHead)[idx + 2] |= code >> (16 - bit); + *blockBits += len; + + //prep the next block buffer if the current one is full + if (*blockBits >= 256 * 8) { + *blockBits -= 255 * 8; + (*writeHead) += 256; + (*writeHead)[2] = (*writeHead)[1]; + (*writeHead)[1] = (*writeHead)[0]; + (*writeHead)[0] = 255; + memset((*writeHead) + 4, 0, 256); + } +} + +typedef struct { + int16_t * data; + int len; + int stride; +} MsfStridedList; + +static inline void msf_lzw_reset(MsfStridedList * lzw, int tableSize, int stride) { MsfTimeFunc + memset(lzw->data, 0xFF, 4096 * stride * sizeof(int16_t)); + lzw->len = tableSize + 2; + 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) +{ 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 }; + + //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 + + //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) { + if (used[i]) { + tlb[i] = tableIdx; + int rmask = (1 << frame.rbits) - 1; + int gmask = (1 << frame.gbits) - 1; + //isolate components + int r = i & rmask; + int g = i >> frame.rbits & gmask; + int b = i >> (frame.rbits + frame.gbits); + //shift into highest bits + r <<= 8 - frame.rbits; + g <<= 8 - frame.gbits; + b <<= 8 - frame.bbits; + 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); + headerBytes[17] |= tableBits - 1; + memcpy(writeHead, headerBytes, 18); + writeHead += 18; + + //local color table + memcpy(writeHead, table, tableSize * sizeof(Color3)); + writeHead += tableSize * sizeof(Color3); + *writeHead++ = tableBits; + + //prep block + memset(writeHead, 0, 260); + writeHead[0] = 255; + uint32_t blockBits = 8; //relative to block.head + + //SPEC: "Encoders should output a Clear code as the first code of each image data stream." + 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]]; + 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 code = (&lzw.data[lastCode * lzw.stride])[color]; + if (code < 0) { + //write to code stream + int codeBits = msf_bit_log(lzw.len - 1); + msf_put_code(&writeHead, &blockBits, codeBits, lastCode); + + if (lzw.len > 4095) { + //reset buffer code table + msf_put_code(&writeHead, &blockBits, codeBits, tableSize); + msf_lzw_reset(&lzw, tableSize, tableIdx); + } else { + (&lzw.data[lastCode * lzw.stride])[color] = lzw.len; + ++lzw.len; + } + + lastCode = color; + } else { + lastCode = code; + } + } + + //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); + + //flush remaining data + if (blockBits > 8) { + int bytes = (blockBits + 7) / 8; //round up + writeHead[0] = bytes - 1; + writeHead += bytes; + } + *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; } + return moved; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// To-memory 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->listTail = handle->listHead; + handle->listHead->next = NULL; + handle->listHead->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"; + memcpy(&headerBytes[6], &width, 2); + memcpy(&headerBytes[8], &height, 2); + memcpy(handle->listHead->data, headerBytes, 32); + return 1; +} + +int msf_gif_frame(MsfGifState * handle, uint8_t * pixelData, int centiSecondsPerFame, int maxBitDepth, int pitchInBytes) +{ MsfTimeFunc + if (!handle->listHead) { return 0; } + + maxBitDepth = msf_imax(1, msf_imin(16, maxBitDepth)); + 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))); + + 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; + handle->listTail = buffer; + + //swap current and previous frames + MsfCookedFrame tmp = handle->previousFrame; + handle->previousFrame = handle->currentFrame; + handle->currentFrame = tmp; + + handle->framesSubmitted += 1; + return 1; +} + +MsfGifResult msf_gif_end(MsfGifState * handle) { MsfTimeFunc + if (!handle->listHead) { MsfGifResult empty = {0}; return empty; } + + //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; } + + //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; + } + *writeHead++ = 0x3B; + } + + //third pass: free buffers + msf_free_gif_state(handle); + + MsfGifResult ret = { buffer, total, total, handle->customAllocatorContext }; + return ret; +} + +void msf_gif_free(MsfGifResult result) { MsfTimeFunc + 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 + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2021 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 +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/par_shapes.h b/raylib/external/par_shapes.h index 39831c8..d530913 100644 --- a/raylib/external/par_shapes.h +++ b/raylib/external/par_shapes.h @@ -10,7 +10,7 @@ // In addition to the comment block above each function declaration, the API // has informal documentation here: // -// http://github.prideout.net/shapes/ +// https://prideout.net/shapes // // For our purposes, a "mesh" is a list of points and a list of triangles; the // former is a flattened list of three-tuples (32-bit floats) and the latter is @@ -21,8 +21,7 @@ // coordinates (one per vertex). That's it! If you need something fancier, // look elsewhere. // -// The MIT License -// Copyright (c) 2015 Philip Rideout +// Distributed under the MIT License, see bottom of file. #ifndef PAR_SHAPES_H #define PAR_SHAPES_H @@ -32,8 +31,7 @@ extern "C" { #endif #include - -// Ray: commented to avoid conflict with raylib bool +// Ray (@raysan5): Commented to avoid conflict with raylib bool /* #if !defined(_MSC_VER) # include @@ -41,9 +39,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 */ @@ -71,6 +69,14 @@ 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); @@ -172,6 +178,17 @@ 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) @@ -205,11 +222,15 @@ void par_shapes_compute_normals(par_shapes_mesh* m); #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*); @@ -298,11 +319,12 @@ static float par_shapes__sqrdist3(float const* a, float const* b) return dx * dx + dy * dy + dz * dz; } -static void par_shapes__compute_welded_normals(par_shapes_mesh* m) +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, 0.01, weldmap); + par_shapes_mesh* welded = par_shapes_weld(m, epsilon, weldmap); par_shapes_compute_normals(welded); float* pdst = m->normals; for (int i = 0; i < m->npoints; i++, pdst += 3) { @@ -325,6 +347,24 @@ 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) { @@ -332,7 +372,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, 0.0001); + par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere); return m; } @@ -343,7 +383,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, 0.0001); + par_shapes_remove_degenerate(m, par_shapes__epsilon_degenerate_sphere); return m; } @@ -579,6 +619,15 @@ 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; @@ -620,6 +669,14 @@ 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; @@ -744,15 +801,15 @@ void par_shapes_rotate(par_shapes_mesh* mesh, float radians, float const* axis) p[1] = y; p[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; + 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; } } } @@ -765,6 +822,27 @@ 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) @@ -1052,7 +1130,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name, total += rule->weight; } } - float r = (float) rand() / RAND_MAX; + float r = (float) rand() / (float) RAND_MAX; float t = 0; for (int i = 0; i < nrules; i++) { rule = rules + i; @@ -1098,8 +1176,8 @@ static par_shapes_mesh* par_shapes__apply_turtle(par_shapes_mesh* mesh, return m; } -static void par_shapes__connect(par_shapes_mesh* scene, - par_shapes_mesh* cylinder, int slices) +void par_shapes__connect(par_shapes_mesh* scene, par_shapes_mesh* cylinder, + int slices) { int stacks = 1; int npoints = (slices + 1) * (stacks + 1); @@ -1118,7 +1196,8 @@ static void par_shapes__connect(par_shapes_mesh* scene, // 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, 2 * scene->ntriangles * 3); + memcpy(triangles, scene->triangles, + sizeof(PAR_SHAPES_T) * scene->ntriangles * 3); int v = scene->npoints - (slices + 1); PAR_SHAPES_T* face = triangles + scene->ntriangles * 3; for (int stack = 0; stack < stacks; stack++) { @@ -1631,8 +1710,9 @@ 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! @@ -1698,6 +1778,9 @@ 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; @@ -2048,3 +2131,25 @@ 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 new file mode 100644 index 0000000..f0f4421 --- /dev/null +++ b/raylib/external/qoa.h @@ -0,0 +1,742 @@ +/* + +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 new file mode 100644 index 0000000..039e279 --- /dev/null +++ b/raylib/external/qoaplay.c @@ -0,0 +1,278 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..f2800b0 --- /dev/null +++ b/raylib/external/qoi.h @@ -0,0 +1,649 @@ +/* + +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/rgif.h b/raylib/external/rgif.h deleted file mode 100644 index 44ee13b..0000000 --- a/raylib/external/rgif.h +++ /dev/null @@ -1,937 +0,0 @@ -/********************************************************************************************** -* -* rgif.h original implementation (gif.h) by Charlie Tangora [ctangora -at- gmail -dot- com] -* adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5) -* -* This file offers a simple, very limited way to create animated GIFs directly in code. -* -* Those looking for particular cleverness are likely to be disappointed; it's pretty -* much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg -* dithering. (It does at least use delta encoding - only the changed portions of each -* frame are saved.) -* -* So resulting files are often quite large. The hope is that it will be handy nonetheless -* as a quick and easily-integrated way for programs to spit out animations. -* -* Only RGBA8 is currently supported as an input format. (The alpha is ignored.) -* -* CONFIGURATION: -* -* #define RGIF_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. -* -* USAGE: -* 1) Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header. -* 2) Pass subsequent frames to GifWriteFrame(). -* 3) Finally, call GifEnd() to close the file handle and free memory. -* -* -* LICENSE: This software is available under 2 licenses -- choose whichever you prefer -* -* ALTERNATIVE A - MIT License -* -* Copyright (c) 2017 Ramon Santamaria -* -* 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. -* -**********************************************************************************************/ - -#ifndef GIF_H -#define GIF_H - -#include // Required for: FILE - -//#define RGIF_STATIC -#ifdef RGIF_STATIC - #define RGIFDEF static // Functions just visible to module including this file -#else - #ifdef __cplusplus - #define RGIFDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) - #else - #define RGIFDEF extern // Functions visible from other files - #endif -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -// NOTE: By default use bitDepth = 8, dither = false -RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither); -RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither); -RGIFDEF bool GifEnd(); - -#endif // GIF_H - - -/*********************************************************************************** -* - * GIF IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RGIF_IMPLEMENTATION) - -#include // Required for: FILE, fopen(), fclose() -#include // Required for: memcpy() - -// Define these macros to hook into a custom memory allocator. -// GIF_TEMP_MALLOC and GIF_TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs -// and any temp memory allocated by a function will be freed before it exits. -#if !defined(GIF_TEMP_MALLOC) - #include - - #define GIF_TEMP_MALLOC malloc - #define GIF_TEMP_FREE free -#endif - -// Check if custom malloc/free functions defined, if not, using standard ones -// GIF_MALLOC and GIF_FREE are used only by GifBegin and GifEnd respectively, -// to allocate a buffer the size of the image, which is used to find changed pixels for delta-encoding. -#if !defined(GIF_MALLOC) - #include // Required for: malloc(), free() - - #define GIF_MALLOC(size) malloc(size) - #define GIF_FREE(ptr) free(ptr) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define GIFMIN(a, b) (((a)<(b))?(a):(b)) -#define GIFMAX(a, b) (((a)>(b))?(a):(b)) -#define GIFABS(x) ((x)<0?-(x):(x)) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// Gif palette structure -typedef struct GifPalette { - int bitDepth; - - unsigned char r[256]; - unsigned char g[256]; - unsigned char b[256]; - - // k-d tree over RGB space, organized in heap fashion - // i.e. left child of node i is node i*2, right child is node i*2 + 1 - // nodes 256-511 are implicitly the leaves, containing a color - unsigned char treeSplitElt[255]; - unsigned char treeSplit[255]; -} GifPalette; - - -// Simple structure to write out the LZW-compressed -// portion of the imageone bit at a time -typedef struct GifBitStatus { - unsigned char bitIndex; // how many bits in the partial byte written so far - unsigned char byte; // current partial byte - - unsigned int chunkIndex; - unsigned char chunk[256]; // bytes are written in here until we have 256 of them, then written to the file -} GifBitStatus; - -// The LZW dictionary is a 256-ary tree constructed -// as the file is encoded, this is one node -typedef struct GifLzwNode { - unsigned short m_next[256]; -} GifLzwNode; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -const int gifTransparentIndex = 0; // Transparent color index - -static FILE *gifFile; -unsigned char *gifFrame; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot); -static void GifSwapPixels(unsigned char *image, int pixA, int pixB); -static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex); -static void GifPartitionByMedian(unsigned char *image, int left, int right, int com, int neededCenter); -static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette *pal); -static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels); -static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned int width, unsigned int height, int bitDepth, bool buildForDither, GifPalette *pPal); -static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal); -static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal); -static void GifWriteBit(GifBitStatus *stat, unsigned int bit); -static void GifWriteChunk(FILE *f, GifBitStatus *stat); -static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length); -static void GifWritePalette(const GifPalette *pPal, FILE *f); -static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Creates a gif file -// NOTE: Initializes internal file pointer (only one gif recording at a time) -// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value. -RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither) -{ -#if _MSC_VER >= 1400 - gifFile = 0; - fopen_s(&gifFile, filename, "wb"); -#else - gifFile = fopen(filename, "wb"); -#endif - - if (!gifFile) return false; - - // Allocate space for one gif frame - gifFrame = (unsigned char *)GIF_MALLOC(width*height*4); - - // GIF Header - fputs("GIF89a",gifFile); - - // Reference: http://www.onicos.com/staff/iz/formats/gif.html - - // GIF Screen Descriptor - fputc(width & 0xff, gifFile); - fputc((width >> 8) & 0xff, gifFile); // Screen width (2 byte) - fputc(height & 0xff, gifFile); - fputc((height >> 8) & 0xff, gifFile); // Screen height (2 byte) - - fputc(0xf0, gifFile); // Color table flags: unsorted global color table of 2 entries (1 byte, bit-flags) - fputc(0, gifFile); // Background color index - fputc(0, gifFile); // Pixel Aspect Ratio (square, we need to specify this because it's 1989) - - // GIF Global Color table (just a dummy palette) - // Color 0: black - fputc(0, gifFile); - fputc(0, gifFile); - fputc(0, gifFile); - // Color 1: also black - fputc(0, gifFile); - fputc(0, gifFile); - fputc(0, gifFile); - - if (delay != 0) - { - // Application Extension Block (19 bytes long) - fputc(0x21, gifFile); // GIF Extension code - fputc(0xff, gifFile); // Application Extension Label - fputc(11, gifFile); // Length of Application Block (11 byte) - fputs("NETSCAPE2.0", gifFile); // Application Identifier (Netscape 2.0 block) - - fputc(0x03, gifFile); // Length of Data Sub-Block (3 bytes) - fputc(0x01, gifFile); // 0x01 - fputc(0x00, gifFile); // This specifies the number of times, - fputc(0x00, gifFile); // the loop should be executed (infinitely) - - fputc(0x00, gifFile); // Data Sub-Block Terminator. - } - - return true; -} - -// Writes out a new frame to a GIF in progress. -// NOTE: gifFile should have been initialized with GifBegin() -// AFAIK, it is legal to use different bit depths for different frames of an image - -// this may be handy to save bits in animations that don't change much. -RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither) -{ - if (!gifFile) return false; - - const unsigned char *oldImage = gifFrame; - - GifPalette pal; - GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal); - - if (dither) GifDitherImage(oldImage, image, gifFrame, width, height, &pal); - else GifThresholdImage(oldImage, image, gifFrame, width, height, &pal); - - GifWriteLzwImage(gifFile, gifFrame, 0, 0, width, height, delay, &pal); - - return true; -} - -// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF. -// Many if not most viewers will still display a GIF properly if the EOF code is missing, -// but it's still a good idea to write it out. -RGIFDEF bool GifEnd() -{ - if (!gifFile) return false; - - fputc(0x3b, gifFile); // Trailer (end of file) - fclose(gifFile); - - GIF_FREE(gifFrame); - - gifFile = NULL; - gifFrame = NULL; - - return true; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -// walks the k-d tree to pick the palette entry for a desired color. -// Takes as in/out parameters the current best color and its error - -// only changes them if it finds a better color in its subtree. -// this is the major hotspot in the code at the moment. -static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot) -{ - // base case, reached the bottom of the tree - if (treeRoot > (1<bitDepth)-1) - { - int ind = treeRoot-(1<bitDepth); - if (ind == gifTransparentIndex) return; - - // check whether this color is better than the current winner - int r_err = r - ((int)pPal->r[ind]); - int g_err = g - ((int)pPal->g[ind]); - int b_err = b - ((int)pPal->b[ind]); - int diff = GIFABS(r_err)+GIFABS(g_err)+GIFABS(b_err); - - if (diff < *bestDiff) - { - *bestInd = ind; - *bestDiff = diff; - } - - return; - } - - // take the appropriate color (r, g, or b) for this node of the k-d tree - int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b; - int splitComp = comps[pPal->treeSplitElt[treeRoot]]; - - int splitPos = pPal->treeSplit[treeRoot]; - if (splitPos > splitComp) - { - // check the left subtree - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); - - if (*bestDiff > (splitPos - splitComp)) - { - // cannot prove there's not a better value in the right subtree, check that too - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1); - } - } - else - { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1); - - if (*bestDiff > splitComp - splitPos) - { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2); - } - } -} - -static void GifSwapPixels(unsigned char *image, int pixA, int pixB) -{ - unsigned char rA = image[pixA*4]; - unsigned char gA = image[pixA*4 + 1]; - unsigned char bA = image[pixA*4+2]; - unsigned char aA = image[pixA*4+3]; - - unsigned char rB = image[pixB*4]; - unsigned char gB = image[pixB*4 + 1]; - unsigned char bB = image[pixB*4+2]; - unsigned char aB = image[pixA*4+3]; - - image[pixA*4] = rB; - image[pixA*4 + 1] = gB; - image[pixA*4+2] = bB; - image[pixA*4+3] = aB; - - image[pixB*4] = rA; - image[pixB*4 + 1] = gA; - image[pixB*4+2] = bA; - image[pixB*4+3] = aA; -} - -// just the partition operation from quicksort -static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex) -{ - const int pivotValue = image[(pivotIndex)*4+elt]; - GifSwapPixels(image, pivotIndex, right-1); - int storeIndex = left; - bool split = 0; - for (int ii=left; ii neededCenter) - GifPartitionByMedian(image, left, pivotIndex, com, neededCenter); - - if (pivotIndex < neededCenter) - GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter); - } -} - -// Builds a palette by creating a balanced k-d tree of all pixels in the image -static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, - int treeNode, bool buildForDither, GifPalette *pal) -{ - if (lastElt <= firstElt || numPixels == 0) - return; - - // base case, bottom of the tree - if (lastElt == firstElt + 1) - { - if (buildForDither) - { - // Dithering needs at least one color as dark as anything - // in the image and at least one brightest color - - // otherwise it builds up error and produces strange artifacts - if (firstElt == 1) - { - // special case: the darkest color in the image - unsigned int r=255, g=255, b=255; - for (int ii=0; iir[firstElt] = r; - pal->g[firstElt] = g; - pal->b[firstElt] = b; - - return; - } - - if (firstElt == (1 << pal->bitDepth)-1) - { - // special case: the lightest color in the image - unsigned int r=0, g=0, b=0; - for (int ii=0; iir[firstElt] = r; - pal->g[firstElt] = g; - pal->b[firstElt] = b; - - return; - } - } - - // otherwise, take the average of all colors in this subcube - unsigned long long r=0, g=0, b=0; - for (int ii=0; iir[firstElt] = (unsigned char)r; - pal->g[firstElt] = (unsigned char)g; - pal->b[firstElt] = (unsigned char)b; - - return; - } - - // Find the axis with the largest range - int minR = 255, maxR = 0; - int minG = 255, maxG = 0; - int minB = 255, maxB = 0; - for (int ii=0; ii maxR) maxR = r; - if (r < minR) minR = r; - - if (g > maxG) maxG = g; - if (g < minG) minG = g; - - if (b > maxB) maxB = b; - if (b < minB) minB = b; - } - - int rRange = maxR - minR; - int gRange = maxG - minG; - int bRange = maxB - minB; - - // and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it) - int splitCom = 1; - if (bRange > gRange) splitCom = 2; - if (rRange > bRange && rRange > gRange) splitCom = 0; - - int subPixelsA = numPixels *(splitElt - firstElt) / (lastElt - firstElt); - int subPixelsB = numPixels-subPixelsA; - - GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA); - - pal->treeSplitElt[treeNode] = splitCom; - pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom]; - - GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal); - GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2 + 1, buildForDither, pal); -} - -// Finds all pixels that have changed from the previous image and -// moves them to the fromt of th buffer. -// This allows us to build a palette optimized for the colors of the -// changed pixels only. -static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels) -{ - int numChanged = 0; - unsigned char *writeIter = frame; - - for (int ii=0; iibitDepth = bitDepth; - - // SplitPalette is destructive (it sorts the pixels by color) so - // we must create a copy of the image for it to destroy - int imageSize = width*height*4*sizeof(unsigned char); - unsigned char *destroyableImage = (unsigned char*)GIF_TEMP_MALLOC(imageSize); - memcpy(destroyableImage, nextFrame, imageSize); - - int numPixels = width*height; - if (lastFrame) - numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels); - - const int lastElt = 1 << bitDepth; - const int splitElt = lastElt/2; - const int splitDist = splitElt/2; - - GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal); - - GIF_TEMP_FREE(destroyableImage); - - // add the bottom node for the transparency index - pPal->treeSplit[1 << (bitDepth-1)] = 0; - pPal->treeSplitElt[1 << (bitDepth-1)] = 0; - - pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; -} - -// Implements Floyd-Steinberg dithering, writes palette value to alpha -static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal) -{ - int numPixels = width*height; - - // quantPixels initially holds color*256 for all pixels - // The extra 8 bits of precision allow for sub-single-color error values - // to be propagated - int *quantPixels = (int*)GIF_TEMP_MALLOC(sizeof(int)*numPixels*4); - - for (int ii=0; iir[bestInd])*256; - int g_err = nextPix[1] - (int)(pPal->g[bestInd])*256; - int b_err = nextPix[2] - (int)(pPal->b[bestInd])*256; - - nextPix[0] = pPal->r[bestInd]; - nextPix[1] = pPal->g[bestInd]; - nextPix[2] = pPal->b[bestInd]; - nextPix[3] = bestInd; - - // Propagate the error to the four adjacent locations - // that we haven't touched yet - int quantloc_7 = (yy*width+xx + 1); - int quantloc_3 = (yy*width+width+xx-1); - int quantloc_5 = (yy*width+width+xx); - int quantloc_1 = (yy*width+width+xx + 1); - - if (quantloc_7 < numPixels) - { - int *pix7 = quantPixels+4*quantloc_7; - pix7[0] += GIFMAX(-pix7[0], r_err*7 / 16); - pix7[1] += GIFMAX(-pix7[1], g_err*7 / 16); - pix7[2] += GIFMAX(-pix7[2], b_err*7 / 16); - } - - if (quantloc_3 < numPixels) - { - int *pix3 = quantPixels+4*quantloc_3; - pix3[0] += GIFMAX(-pix3[0], r_err*3 / 16); - pix3[1] += GIFMAX(-pix3[1], g_err*3 / 16); - pix3[2] += GIFMAX(-pix3[2], b_err*3 / 16); - } - - if (quantloc_5 < numPixels) - { - int *pix5 = quantPixels+4*quantloc_5; - pix5[0] += GIFMAX(-pix5[0], r_err*5 / 16); - pix5[1] += GIFMAX(-pix5[1], g_err*5 / 16); - pix5[2] += GIFMAX(-pix5[2], b_err*5 / 16); - } - - if (quantloc_1 < numPixels) - { - int *pix1 = quantPixels+4*quantloc_1; - pix1[0] += GIFMAX(-pix1[0], r_err / 16); - pix1[1] += GIFMAX(-pix1[1], g_err / 16); - pix1[2] += GIFMAX(-pix1[2], b_err / 16); - } - } - } - - // Copy the palettized result to the output buffer - for (int ii=0; iir[bestInd]; - outFrame[1] = pPal->g[bestInd]; - outFrame[2] = pPal->b[bestInd]; - outFrame[3] = bestInd; - } - - if (lastFrame) lastFrame += 4; - outFrame += 4; - nextFrame += 4; - } -} - - -// insert a single bit -static void GifWriteBit(GifBitStatus *stat, unsigned int bit) -{ - bit = bit & 1; - bit = bit << stat->bitIndex; - stat->byte |= bit; - - ++stat->bitIndex; - if (stat->bitIndex > 7) - { - // move the newly-finished byte to the chunk buffer - stat->chunk[stat->chunkIndex++] = stat->byte; - // and start a new byte - stat->bitIndex = 0; - stat->byte = 0; - } -} - -// write all bytes so far to the file -static void GifWriteChunk(FILE *f, GifBitStatus *stat) -{ - fputc(stat->chunkIndex, f); - fwrite(stat->chunk, 1, stat->chunkIndex, f); - - stat->bitIndex = 0; - stat->byte = 0; - stat->chunkIndex = 0; -} - -static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length) -{ - for (unsigned int ii=0; ii> 1; - - if (stat->chunkIndex == 255) - { - GifWriteChunk(f, stat); - } - } -} - -// write a 256-color (8-bit) image palette to the file -static void GifWritePalette(const GifPalette *pPal, FILE *f) -{ - fputc(0, f); // first color: transparency - fputc(0, f); - fputc(0, f); - - for (int ii=1; ii<(1 << pPal->bitDepth); ++ii) - { - unsigned int r = pPal->r[ii]; - unsigned int g = pPal->g[ii]; - unsigned int b = pPal->b[ii]; - - fputc(r, f); - fputc(g, f); - fputc(b, f); - } -} - -// write the image header, LZW-compress and write out the image -static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal) -{ - // graphics control extension - fputc(0x21, f); - fputc(0xf9, f); - fputc(0x04, f); - fputc(0x05, f); // leave prev frame in place, this frame has transparency - fputc(delay & 0xff, f); - fputc((delay >> 8) & 0xff, f); - fputc(gifTransparentIndex, f); // transparent color index - fputc(0, f); - - fputc(0x2c, f); // image descriptor block - - fputc(left & 0xff, f); // corner of image in canvas space - fputc((left >> 8) & 0xff, f); - fputc(top & 0xff, f); - fputc((top >> 8) & 0xff, f); - - fputc(width & 0xff, f); // width and height of image - fputc((width >> 8) & 0xff, f); - fputc(height & 0xff, f); - fputc((height >> 8) & 0xff, f); - - //fputc(0, f); // no local color table, no transparency - //fputc(0x80, f); // no local color table, but transparency - - fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries - GifWritePalette(pPal, f); - - const int minCodeSize = pPal->bitDepth; - const unsigned int clearCode = 1 << pPal->bitDepth; - - fputc(minCodeSize, f); // min code size 8 bits - - GifLzwNode *codetree = (GifLzwNode *)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096); - - memset(codetree, 0, sizeof(GifLzwNode)*4096); - int curCode = -1; - unsigned int codeSize = minCodeSize + 1; - unsigned int maxCode = clearCode + 1; - - GifBitStatus stat; - stat.byte = 0; - stat.bitIndex = 0; - stat.chunkIndex = 0; - - GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary - - for (unsigned int yy=0; yy= (1ul << codeSize)) - { - // dictionary entry count has broken a size barrier, - // we need more bits for codes - codeSize++; - } - if (maxCode == 4095) - { - // the dictionary is full, clear it out and begin anew - GifWriteCode(f, &stat, clearCode, codeSize); // clear tree - - memset(codetree, 0, sizeof(GifLzwNode)*4096); - codeSize = minCodeSize + 1; - maxCode = clearCode + 1; - } - - curCode = nextValue; - } - } - } - - // compression footer - GifWriteCode(f, &stat, curCode, codeSize); - GifWriteCode(f, &stat, clearCode, codeSize); - GifWriteCode(f, &stat, clearCode + 1, minCodeSize + 1); - - // write out the last partial chunk - while (stat.bitIndex) GifWriteBit(&stat, 0); - if (stat.chunkIndex) GifWriteChunk(f, &stat); - - fputc(0, f); // image block terminator - - GIF_TEMP_FREE(codetree); -} - -#endif // RGIF_IMPLEMENTATION diff --git a/raylib/external/rl_gputex.h b/raylib/external/rl_gputex.h new file mode 100644 index 0000000..4043a92 --- /dev/null +++ b/raylib/external/rl_gputex.h @@ -0,0 +1,826 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..ded6708 --- /dev/null +++ b/raylib/external/rprand.h @@ -0,0 +1,311 @@ +/********************************************************************************************** +* +* 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 fd4ee07..0619c4c 100755 --- a/raylib/external/scripts/glfw-generate-wayland.sh +++ b/raylib/external/scripts/glfw-generate-wayland.sh @@ -4,23 +4,58 @@ TMPDIR="/tmp" GLGLFW_PATH="`pwd`/../glfw/src" cd $TMPDIR -git clone https://github.com/wayland-project/wayland-protocols +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 cd wayland-protocols -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"/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 -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 ./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/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/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/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 ./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 -# 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 +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 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 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 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 diff --git a/raylib/external/sdefl.h b/raylib/external/sdefl.h new file mode 100644 index 0000000..36015b9 --- /dev/null +++ b/raylib/external/sdefl.h @@ -0,0 +1,790 @@ +/*# 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 +as needed to keep the implementation as concise as possible. + +## Features +- Portable single header and source file duo written in ANSI C (ISO C90) +- Dual license with either MIT or public domain +- Small implementation + - Deflate: 525 LoC + - Inflate: 320 LoC +- Webassembly: + - Deflate ~3.7 KB (~2.2KB compressed) + - Inflate ~3.6 KB (~2.2KB compressed) + +## Usage: +This file behaves differently depending on what symbols you define +before including it. + +Header-File mode: +If you do not define `SDEFL_IMPLEMENTATION` before including this file, it +will operate in header only mode. In this mode it declares all used structs +and the API of the library without including the implementation of the library. + +Implementation mode: +If you define `SDEFL_IMPLEMENTATION` before including this file, it will +compile the implementation . Make sure that you only include +this file implementation in *one* C or C++ file to prevent collisions. + +### Benchmark + +| 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 | +| 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 | +| 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 | +| libdeflate 1.3 -12 | 8.13 MB/s | 670 MB/s | 35100568 | 35.10 | + +### 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 | + +## License +``` +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2020-2023 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 +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. +------------------------------------------------------------------------------ +``` +*/ +#ifndef SDEFL_H_INCLUDED +#define SDEFL_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define SDEFL_MAX_OFF (1 << 15) +#define SDEFL_WIN_SIZ SDEFL_MAX_OFF +#define SDEFL_WIN_MSK (SDEFL_WIN_SIZ-1) + +#define SDEFL_HASH_BITS 15 +#define SDEFL_HASH_SIZ (1 << SDEFL_HASH_BITS) +#define SDEFL_HASH_MSK (SDEFL_HASH_SIZ-1) + +#define SDEFL_MIN_MATCH 4 +#define SDEFL_BLK_MAX (256*1024) +#define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX+2)/3) + +#define SDEFL_SYM_MAX (288) +#define SDEFL_OFF_MAX (32) +#define SDEFL_PRE_MAX (19) + +#define SDEFL_LVL_MIN 0 +#define SDEFL_LVL_DEF 5 +#define SDEFL_LVL_MAX 8 + +struct sdefl_freq { + unsigned lit[SDEFL_SYM_MAX]; + unsigned off[SDEFL_OFF_MAX]; +}; +struct sdefl_code_words { + unsigned lit[SDEFL_SYM_MAX]; + unsigned off[SDEFL_OFF_MAX]; +}; +struct sdefl_lens { + unsigned char lit[SDEFL_SYM_MAX]; + unsigned char off[SDEFL_OFF_MAX]; +}; +struct sdefl_codes { + struct sdefl_code_words word; + struct sdefl_lens len; +}; +struct sdefl_seqt { + int off, len; +}; +struct sdefl { + int bits, bitcnt; + int tbl[SDEFL_HASH_SIZ]; + int prv[SDEFL_WIN_SIZ]; + + int seq_cnt; + struct sdefl_seqt seq[SDEFL_SEQ_SIZ]; + struct sdefl_freq freq; + struct sdefl_codes cod; +}; +extern int sdefl_bound(int in_len); +extern int sdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl); +extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl); + +#ifdef __cplusplus +} +#endif + +#endif /* SDEFL_H_INCLUDED */ + +#ifdef SDEFL_IMPLEMENTATION + +#include /* assert */ +#include /* memcpy */ +#include /* CHAR_BIT */ + +#define SDEFL_NIL (-1) +#define SDEFL_MAX_MATCH 258 +#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) +#define SDEFL_CNT_NUM(n) ((((n)+3u/4u)+3u)&~3u) +#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) { + if (!n) return 0; +#ifdef _MSC_VER + unsigned long msbp = 0; + _BitScanReverse(&msbp, (unsigned long)n); + return (int)msbp; +#elif defined(__GNUC__) || defined(__clang__) + return (int)sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl((unsigned long)n); +#else + #define lt(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n + static const char tbl[256] = { + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,lt(4), lt(5), lt(5), lt(6), lt(6), lt(6), lt(6), + lt(7), lt(7), lt(7), lt(7), lt(7), lt(7), lt(7), lt(7)}; + int tt, t; + if ((tt = (n >> 16))) { + return (t = (tt >> 8)) ? 24 + tbl[t] : 16 + tbl[tt]; + } else { + return (t = (n >> 8)) ? 8 + tbl[t] : tbl[n]; + } + #undef lt +#endif +} +static unsigned +sdefl_uload32(const void *p) { + /* hopefully will be optimized to an unaligned read */ + unsigned n = 0; + memcpy(&n, p, sizeof(n)); + return n; +} +static unsigned +sdefl_hash32(const void *p) { + unsigned n = sdefl_uload32(p); + return (n * 0x9E377989) >> (32 - SDEFL_HASH_BITS); +} +static void +sdefl_put(unsigned char **dst, struct sdefl *s, int code, int bitcnt) { + s->bits |= (code << s->bitcnt); + s->bitcnt += bitcnt; + while (s->bitcnt >= 8) { + unsigned char *tar = *dst; + *tar = (unsigned char)(s->bits & 0xFF); + s->bits >>= 8; + s->bitcnt -= 8; + *dst = *dst + 1; + } +} +static void +sdefl_heap_sub(unsigned A[], unsigned len, unsigned sub) { + unsigned c, p = sub; + unsigned v = A[sub]; + while ((c = p << 1) <= len) { + if (c < len && A[c + 1] > A[c]) c++; + if (v >= A[c]) break; + A[p] = A[c], p = c; + } + A[p] = v; +} +static void +sdefl_heap_array(unsigned *A, unsigned len) { + unsigned sub; + for (sub = len >> 1; sub >= 1; sub--) + sdefl_heap_sub(A, len, sub); +} +static void +sdefl_heap_sort(unsigned *A, unsigned n) { + A--; + sdefl_heap_array(A, n); + while (n >= 2) { + unsigned tmp = A[n]; + A[n--] = A[1]; + A[1] = tmp; + sdefl_heap_sub(A, n, 1); + } +} +static unsigned +sdefl_sort_sym(unsigned sym_cnt, unsigned *freqs, + unsigned char *lens, unsigned *sym_out) { + unsigned cnts[SDEFL_CNT_NUM(SDEFL_SYM_MAX)] = {0}; + unsigned cnt_num = SDEFL_CNT_NUM(sym_cnt); + unsigned used_sym = 0; + unsigned sym, i; + for (sym = 0; sym < sym_cnt; sym++) + cnts[freqs[sym] < cnt_num-1 ? freqs[sym]: cnt_num-1]++; + for (i = 1; i < cnt_num; i++) { + unsigned cnt = cnts[i]; + cnts[i] = used_sym; + used_sym += cnt; + } + for (sym = 0; sym < sym_cnt; sym++) { + unsigned freq = freqs[sym]; + if (freq) { + unsigned idx = freq < cnt_num-1 ? freq : cnt_num-1; + sym_out[cnts[idx]++] = sym | (freq << SDEFL_SYM_BITS); + } else lens[sym] = 0; + } + sdefl_heap_sort(sym_out + cnts[cnt_num-2], cnts[cnt_num-1] - cnts[cnt_num-2]); + return used_sym; +} +static void +sdefl_build_tree(unsigned *A, unsigned sym_cnt) { + unsigned i = 0, b = 0, e = 0; + do { + unsigned m, n, freq_shift; + if (i != sym_cnt && (b == e || (A[i] >> SDEFL_SYM_BITS) <= (A[b] >> SDEFL_SYM_BITS))) + m = i++; + else m = b++; + if (i != sym_cnt && (b == e || (A[i] >> SDEFL_SYM_BITS) <= (A[b] >> SDEFL_SYM_BITS))) + n = i++; + else n = b++; + + freq_shift = (A[m] & ~SDEFL_SYM_MSK) + (A[n] & ~SDEFL_SYM_MSK); + A[m] = (A[m] & SDEFL_SYM_MSK) | (e << SDEFL_SYM_BITS); + A[n] = (A[n] & SDEFL_SYM_MSK) | (e << SDEFL_SYM_BITS); + A[e] = (A[e] & SDEFL_SYM_MSK) | freq_shift; + } while (sym_cnt - ++e > 1); +} +static void +sdefl_gen_len_cnt(unsigned *A, unsigned root, unsigned *len_cnt, + unsigned max_code_len) { + int n; + unsigned i; + for (i = 0; i <= max_code_len; i++) + len_cnt[i] = 0; + len_cnt[1] = 2; + + A[root] &= SDEFL_SYM_MSK; + for (n = (int)root - 1; n >= 0; n--) { + unsigned p = A[n] >> SDEFL_SYM_BITS; + unsigned pdepth = A[p] >> SDEFL_SYM_BITS; + unsigned depth = pdepth + 1; + unsigned len = depth; + + A[n] = (A[n] & SDEFL_SYM_MSK) | (depth << SDEFL_SYM_BITS); + if (len >= max_code_len) { + len = max_code_len; + do len--; while (!len_cnt[len]); + } + len_cnt[len]--; + len_cnt[len+1] += 2; + } +} +static void +sdefl_gen_codes(unsigned *A, unsigned char *lens, const unsigned *len_cnt, + unsigned max_code_word_len, unsigned sym_cnt) { + unsigned i, sym, len, nxt[SDEFL_MAX_CODE_LEN + 1]; + for (i = 0, len = max_code_word_len; len >= 1; len--) { + unsigned cnt = len_cnt[len]; + while (cnt--) lens[A[i++] & SDEFL_SYM_MSK] = (unsigned char)len; + } + nxt[0] = nxt[1] = 0; + for (len = 2; len <= max_code_word_len; len++) + nxt[len] = (nxt[len-1] + len_cnt[len-1]) << 1; + for (sym = 0; sym < sym_cnt; sym++) + A[sym] = nxt[lens[sym]]++; +} +static unsigned +sdefl_rev(unsigned c, unsigned char n) { + c = ((c & 0x5555) << 1) | ((c & 0xAAAA) >> 1); + c = ((c & 0x3333) << 2) | ((c & 0xCCCC) >> 2); + c = ((c & 0x0F0F) << 4) | ((c & 0xF0F0) >> 4); + c = ((c & 0x00FF) << 8) | ((c & 0xFF00) >> 8); + return c >> (16-n); +} +static void +sdefl_huff(unsigned char *lens, unsigned *codes, unsigned *freqs, + unsigned num_syms, unsigned max_code_len) { + unsigned c, *A = codes; + unsigned len_cnt[SDEFL_MAX_CODE_LEN + 1]; + unsigned used_syms = sdefl_sort_sym(num_syms, freqs, lens, A); + if (!used_syms) return; + if (used_syms == 1) { + unsigned s = A[0] & SDEFL_SYM_MSK; + unsigned i = s ? s : 1; + codes[0] = 0, lens[0] = 1; + codes[i] = 1, lens[i] = 1; + return; + } + sdefl_build_tree(A, used_syms); + sdefl_gen_len_cnt(A, used_syms-2, len_cnt, max_code_len); + sdefl_gen_codes(A, lens, len_cnt, max_code_len, num_syms); + for (c = 0; c < num_syms; c++) { + codes[c] = sdefl_rev(codes[c], lens[c]); + } +} +struct sdefl_symcnt { + int items; + int lit; + int off; +}; +static void +sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items, + const unsigned char *litlen, const unsigned char *offlen) { + unsigned *at = items; + unsigned run_start = 0; + + unsigned total = 0; + unsigned char lens[SDEFL_SYM_MAX + SDEFL_OFF_MAX]; + for (cnt->lit = SDEFL_SYM_MAX; cnt->lit > 257; cnt->lit--) + if (litlen[cnt->lit - 1]) break; + for (cnt->off = SDEFL_OFF_MAX; cnt->off > 1; cnt->off--) + 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); + do { + unsigned len = lens[run_start]; + unsigned run_end = run_start; + do run_end++; while (run_end != total && len == lens[run_end]); + if (!len) { + while ((run_end - run_start) >= 11) { + unsigned n = (run_end - run_start) - 11; + unsigned xbits = n < 0x7f ? n : 0x7f; + freqs[18]++; + *at++ = 18u | (xbits << 5u); + run_start += 11 + xbits; + } + if ((run_end - run_start) >= 3) { + unsigned n = (run_end - run_start) - 3; + unsigned xbits = n < 0x7 ? n : 0x7; + freqs[17]++; + *at++ = 17u | (xbits << 5u); + run_start += 3 + xbits; + } + } else if ((run_end - run_start) >= 4) { + freqs[len]++; + *at++ = len; + run_start++; + do { + unsigned xbits = (run_end - run_start) - 3; + xbits = xbits < 0x03 ? xbits : 0x03; + *at++ = 16 | (xbits << 5); + run_start += 3 + xbits; + freqs[16]++; + } while ((run_end - run_start) >= 3); + } + while (run_start != run_end) { + freqs[len]++; + *at++ = len; + run_start++; + } + } while (run_start != total); + cnt->items = (int)(at - items); +} +struct sdefl_match_codest { + int ls, lc; + int dc, dx; +}; +static void +sdefl_match_codes(struct sdefl_match_codest *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, + 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, + 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 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}; + static const short lmin[] = {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}; + 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; + 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]); + sdefl_put(dst, s, (int)s->cod.word.off[cod.dc], s->cod.len.off[cod.dc]); + sdefl_put(dst, s, dist - dmin[cod.dc], cod.dx); +} +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; + int j, i = 0, item_cnt = 0; + struct sdefl_symcnt symcnt = {0}; + unsigned codes[SDEFL_PRE_MAX]; + unsigned char lens[SDEFL_PRE_MAX]; + unsigned freqs[SDEFL_PRE_MAX] = {0}; + unsigned items[SDEFL_SYM_MAX + SDEFL_OFF_MAX]; + 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 */ + 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; + } + } + /* 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); + } + 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;} + memset(&s->freq, 0, sizeof(s->freq)); + s->seq_cnt = 0; +} +static void +sdefl_seq(struct sdefl *s, int off, int len) { + assert(s->seq_cnt + 2 < SDEFL_SEQ_SIZ); + s->seq[s->seq_cnt].off = off; + s->seq[s->seq_cnt].len = len; + s->seq_cnt++; +} +static void +sdefl_reg_match(struct sdefl *s, int off, int len) { + struct sdefl_match_codest 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]++; +} +struct sdefl_match { + int off; + 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); + while (i > 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]))) { + int n = SDEFL_MIN_MATCH; + while (n < max_match && in[i + n] == in[p + n]) { + assert(i + n < e); + assert(p + n < e); + n++; + } + if (n > m->len) { + m->len = n, m->off = p - i; + if (n == max_match) + break; + } + } + if (!(--chain_len)) break; + i = s->prv[i & SDEFL_WIN_MSK]; + } +} +static int +sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in, + int in_len, int lvl) { + unsigned char *q = out; + static const unsigned char pref[] = {8,10,14,24,30,48,65,96,130}; + int max_chain = (lvl < 8) ? (1 << (lvl + 1)): (1 << 13); + int n, i = 0, litlen = 0; + 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; + 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 nice_match = pref[lvl] < max_match ? pref[lvl] : max_match; + int run = 1, inc = 1, run_inc = 0; + if (max_match > SDEFL_MIN_MATCH) { + sdefl_fnd(&m, s, max_chain, max_match, in, i, in_len); + } + if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len + 1 < nice_match){ + struct sdefl_match m2 = {0}; + sdefl_fnd(&m2, s, max_chain, m.len + 1, in, i + 1, in_len); + m.len = (m2.len > m.len) ? 0 : m.len; + } + if (m.len >= SDEFL_MIN_MATCH) { + if (litlen) { + sdefl_seq(s, i - litlen, litlen); + litlen = 0; + } + sdefl_seq(s, -m.off, m.len); + sdefl_reg_match(s, m.off, m.len); + if (lvl < 2 && m.len >= nice_match) { + inc = m.len; + } else { + run = m.len; + } + } else { + s->freq.lit[in[i]]++; + litlen++; + } + run_inc = run * inc; + if (in_len - (i + run_inc) > SDEFL_MIN_MATCH) { + while (run-- > 0) { + 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); + } while (i < in_len); + if (s->bitcnt) { + sdefl_put(&q, s, 0x00, 8 - s->bitcnt); + } + assert(s->bitcnt == 0); + return (int)(q - out); +} +extern int +sdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) { + s->bits = s->bitcnt = 0; + return sdefl_compr(s, (unsigned char*)out, (const unsigned char*)in, n, lvl); +} +static unsigned +sdefl_adler32(unsigned adler32, const unsigned char *in, int in_len) { + #define SDEFL_ADLER_INIT (1) + const unsigned ADLER_MOD = 65521; + unsigned s1 = adler32 & 0xffff; + unsigned s2 = adler32 >> 16; + unsigned blk_len, i; + + blk_len = in_len % 5552; + while (in_len) { + for (i = 0; i + 7 < blk_len; i += 8) { + s1 += in[0]; s2 += s1; + s1 += in[1]; s2 += s1; + s1 += in[2]; s2 += s1; + s1 += in[3]; s2 += s1; + s1 += in[4]; s2 += s1; + s1 += in[5]; s2 += s1; + s1 += in[6]; s2 += s1; + s1 += in[7]; s2 += s1; + in += 8; + } + for (; i < blk_len; ++i) { + s1 += *in++, s2 += s1; + } + s1 %= ADLER_MOD; + s2 %= ADLER_MOD; + in_len -= blk_len; + blk_len = 5552; + } + return (unsigned)(s2 << 16) + (unsigned)s1; +} +extern int +zsdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) { + int p = 0; + unsigned a = 0; + unsigned char *q = (unsigned char*)out; + + s->bits = s->bitcnt = 0; + sdefl_put(&q, s, 0x78, 8); /* deflate, 32k window */ + sdefl_put(&q, s, 0x01, 8); /* fast compression */ + q += sdefl_compr(s, q, (const unsigned char*)in, n, lvl); + + /* append adler checksum */ + a = sdefl_adler32(SDEFL_ADLER_INIT, (const unsigned char*)in, n); + for (p = 0; p < 4; ++p) { + sdefl_put(&q, s, (a >> 24) & 0xFF, 8); + a <<= 8; + } + return (int)(q - (unsigned char*)out); +} +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; +} +#endif /* SDEFL_IMPLEMENTATION */ diff --git a/raylib/external/sinfl.h b/raylib/external/sinfl.h new file mode 100644 index 0000000..a749501 --- /dev/null +++ b/raylib/external/sinfl.h @@ -0,0 +1,630 @@ +/* +# 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 +as needed to keep the implementation as concise as possible. + +## Features +- Portable single header and source file duo written in ANSI C (ISO C90) +- Dual license with either MIT or public domain +- Small implementation + - Deflate: 525 LoC + - Inflate: 500 LoC +- Webassembly: + - Deflate ~3.7 KB (~2.2KB compressed) + - Inflate ~3.6 KB (~2.2KB compressed) + +## Usage: +This file behaves differently depending on what symbols you define +before including it. + +Header-File mode: +If you do not define `SINFL_IMPLEMENTATION` before including this file, it +will operate in header only mode. In this mode it declares all used structs +and the API of the library without including the implementation of the library. + +Implementation mode: +If you define `SINFL_IMPLEMENTATION` before including this file, it will +compile the implementation. Make sure that you only include +this file implementation in *one* C or C++ file to prevent collisions. + +### Benchmark + +| 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 | +| 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 | +| 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 | +| libdeflate 1.3 -12 | 8.13 MB/s | 670 MB/s | 35100568 | 35.10 | + +### 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 | + +## License +``` +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2020-2023 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 +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. +------------------------------------------------------------------------------ +``` +*/ +#ifndef SINFL_H_INCLUDED +#define SINFL_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define SINFL_PRE_TBL_SIZE 128 +#define SINFL_LIT_TBL_SIZE 1334 +#define SINFL_OFF_TBL_SIZE 402 + +struct sinfl { + const unsigned char *bitptr; + const unsigned char *bitend; // @raysan5: added + unsigned long long bitbuf; + int 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); + +#ifdef __cplusplus +} +#endif + +#endif /* SINFL_H_INCLUDED */ + +#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__) + 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_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); +} +struct sinfl_gen { + int len; + int cnt; + int word; + short* sorted; +}; +static int +sinfl_build_tbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, + const int *cnt) { + int tbl_end = 0; + while (!(gen->cnt = cnt[gen->len])) { + ++gen->len; + } + tbl_end = 1 << gen->len; + while (gen->len <= tbl_bits) { + do {unsigned bit = 0; + tbl[gen->word] = (*gen->sorted++ << 16) | gen->len; + if (gen->word == tbl_end - 1) { + for (; gen->len < tbl_bits; gen->len++) { + memcpy(&tbl[tbl_end], tbl, (size_t)tbl_end * sizeof(tbl[0])); + tbl_end <<= 1; + } + return 1; + } + bit = 1 << sinfl_bsr((unsigned)(gen->word ^ (tbl_end - 1))); + gen->word &= bit - 1; + gen->word |= bit; + } while (--gen->cnt); + do { + if (++gen->len <= tbl_bits) { + memcpy(&tbl[tbl_end], tbl, (size_t)tbl_end * sizeof(tbl[0])); + tbl_end <<= 1; + } + } while (!(gen->cnt = cnt[gen->len])); + } + return 0; +} +static void +sinfl_build_subtbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, + const int *cnt) { + int sub_bits = 0; + int sub_start = 0; + int sub_prefix = -1; + int tbl_end = 1 << tbl_bits; + while (1) { + unsigned entry; + int bit, stride, i; + /* start new sub-table */ + if ((gen->word & ((1 << tbl_bits)-1)) != sub_prefix) { + int used = 0; + sub_prefix = gen->word & ((1 << tbl_bits)-1); + sub_start = tbl_end; + sub_bits = gen->len - tbl_bits; + used = gen->cnt; + while (used < (1 << sub_bits)) { + sub_bits++; + used = (used << 1) + cnt[tbl_bits + sub_bits]; + } + tbl_end = sub_start + (1 << sub_bits); + tbl[sub_prefix] = (sub_start << 16) | 0x10 | (sub_bits & 0xf); + } + /* fill sub-table */ + entry = (*gen->sorted << 16) | ((gen->len - tbl_bits) & 0xf); + gen->sorted++; + i = sub_start + (gen->word >> tbl_bits); + stride = 1 << (gen->len - tbl_bits); + do { + tbl[i] = entry; + i += stride; + } while (i < tbl_end); + if (gen->word == (1 << gen->len)-1) { + return; + } + bit = 1 << sinfl_bsr(gen->word ^ ((1 << gen->len) - 1)); + gen->word &= bit - 1; + gen->word |= bit; + gen->cnt--; + while (!gen->cnt) { + gen->cnt = cnt[++gen->len]; + } + } +} +static void +sinfl_build(unsigned *tbl, unsigned char *lens, int tbl_bits, int maxlen, + int symcnt) { + int i, used = 0; + short sort[288]; + int cnt[16] = {0}, off[16]= {0}; + struct sinfl_gen gen = {0}; + gen.sorted = sort; + gen.len = 1; + + for (i = 0; i < symcnt; ++i) + cnt[lens[i]]++; + off[1] = cnt[0]; + for (i = 1; i < maxlen; ++i) { + off[i + 1] = off[i] + cnt[i]; + used = (used << 1) + cnt[i]; + } + used = (used << 1) + cnt[i]; + for (i = 0; i < symcnt; ++i) + gen.sorted[off[lens[i]]++] = (short)i; + gen.sorted += off[0]; + + if (used < (1 << maxlen)){ + for (i = 0; i < 1 << tbl_bits; ++i) + tbl[i] = (0 << 16u) | 1; + return; + } + if (!sinfl_build_tbl(&gen, tbl, tbl_bits, cnt)){ + sinfl_build_subtbl(&gen, tbl, tbl_bits, cnt); + } +} +static int +sinfl_decode(struct sinfl *s, const unsigned *tbl, int bit_len) { + int idx = sinfl_peek(s, bit_len); + unsigned key = tbl[idx]; + if (key & 0x10) { + /* sub-table lookup */ + int len = key & 0x0f; + sinfl_eat(s, bit_len); + idx = sinfl_peek(s, len); + key = tbl[((key >> 16) & 0xffff) + (unsigned)idx]; + } + sinfl_eat(s, key & 0x0f); + return (key >> 16) & 0x0fff; +} +static int +sinfl_decompress(unsigned char *out, int cap, 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}; + static const unsigned char dbits[30+2] = {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,0,0}; + static const short lbase[29+2] = {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 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) { + switch (state) { + case hdr: { + /* block header */ + int type = 0; + sinfl_refill(&s); + last = sinfl__get(&s,1); + type = sinfl__get(&s,2); + + switch (type) {default: return (int)(out-o); + case 0x00: state = stored; break; + case 0x01: state = fixed; break; + 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; + + if ((unsigned short)len != (unsigned short)~nlen) + 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); + state = hdr; + } break; + case fixed: { + /* fixed huffman codes */ + int n; unsigned char lens[288+32]; + for (n = 0; n <= 143; n++) lens[n] = 8; + for (n = 144; n <= 255; n++) lens[n] = 9; + for (n = 256; n <= 279; n++) lens[n] = 7; + for (n = 280; n <= 287; n++) lens[n] = 8; + for (n = 0; n < 32; n++) lens[288+n] = 5; + + /* build lit/dist tables */ + sinfl_build(s.lits, lens, 10, 15, 288); + sinfl_build(s.dsts, lens + 288, 8, 15, 32); + 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]; + + 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;} + } 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 */ + 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 (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); + } + } +#endif + else { + *dst++ = *src++; + *dst++ = *src++; + do *dst++ = *src++; + while (dst < out); + }} + } + } 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); +} +static unsigned +sinfl_adler32(unsigned adler32, const unsigned char *in, int in_len) { + const unsigned ADLER_MOD = 65521; + unsigned s1 = adler32 & 0xffff; + unsigned s2 = adler32 >> 16; + unsigned blk_len, i; + + blk_len = in_len % 5552; + while (in_len) { + for (i=0; i + 7 < blk_len; i += 8) { + s1 += in[0]; s2 += s1; + s1 += in[1]; s2 += s1; + s1 += in[2]; s2 += s1; + s1 += in[3]; s2 += s1; + s1 += in[4]; s2 += s1; + s1 += in[5]; s2 += s1; + s1 += in[6]; s2 += s1; + s1 += in[7]; s2 += s1; + in += 8; + } + for (; i < blk_len; ++i) + s1 += *in++, s2 += s1; + s1 %= ADLER_MOD; s2 %= ADLER_MOD; + in_len -= blk_len; + blk_len = 5552; + } return (unsigned)(s2 << 16) + (unsigned)s1; +} +extern int +zsinflate(void *out, int cap, 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); + 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; + } else { + return -1; + } +} +#endif + diff --git a/raylib/external/stb_image.h b/raylib/external/stb_image.h index f090ed3..9eedabe 100644 --- a/raylib/external/stb_image.h +++ b/raylib/external/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.18 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,18 @@ 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 + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes @@ -81,25 +93,37 @@ 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 + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen + Carmelo J Fdez-Aguera Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + 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 + 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 + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + 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. */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -119,7 +143,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 @@ -158,6 +182,42 @@ 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: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// // =========================================================================== // // Philosophy @@ -170,12 +230,12 @@ RECENT REVISION HISTORY: // // Sometimes I let "good performance" creep up in priority over "easy to maintain", // and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important +// performance, in addition to the easy-to-use ones. Nevertheless, it's important // to keep in mind that from the standpoint of you, a client of this library, // all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. +// provide more explicit reasons why performance can't be emphasized. // // - Portable ("ease of use") // - Small source code footprint ("easy to maintain") @@ -218,11 +278,10 @@ RECENT REVISION HISTORY: // // HDR image support (disable by defining STBI_NO_HDR) // -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; // both of these constants can be reconfigured through this interface: // // stbi_hdr_to_ldr_gamma(2.2f); @@ -254,11 +313,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by 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). +// 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). // // 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 @@ -300,7 +358,14 @@ RECENT REVISION HISTORY: // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. #ifndef STBI_NO_STDIO #include @@ -318,6 +383,7 @@ enum STBI_rgb_alpha = 4 }; +#include typedef unsigned char stbi_uc; typedef unsigned short stbi_us; @@ -325,11 +391,13 @@ typedef unsigned short stbi_us; extern "C" { #endif +#ifndef STBIDEF #ifdef STB_IMAGE_STATIC #define STBIDEF static #else #define STBIDEF extern #endif +#endif ////////////////////////////////////////////////////////////////////////////// // @@ -354,10 +422,6 @@ typedef struct STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -#endif - #ifndef STBI_NO_STDIO STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); @@ -365,6 +429,14 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in // for stbi_load_from_file, file pointer is left pointing immediately after image #endif +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + //////////////////////////////////// // // 16-bits-per-channel interface @@ -412,7 +484,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure -// NOT THREADSAFE +// on most compilers (and ALL modern mainstream compilers) this is threadsafe STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() @@ -445,6 +517,13 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left 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 STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); @@ -524,6 +603,12 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_ASSERT(x) assert(x) #endif +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + #ifndef _MSC_VER #ifdef __cplusplus @@ -535,8 +620,25 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define stbi_inline __forceinline #endif +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif -#ifdef _MSC_VER + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -565,7 +667,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) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -648,14 +750,18 @@ static int stbi__cpuid3(void) #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; } +#endif + #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { // If we're even attempting to compile this on GCC/Clang, that means @@ -663,6 +769,8 @@ static int stbi__sse2_available(void) // instructions at will, and so are we. return 1; } +#endif + #endif #endif @@ -673,14 +781,21 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #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 #endif +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + /////////////////////////////////////////////// // // stbi__context struct and start_xxx functions @@ -698,6 +813,7 @@ typedef struct int read_from_callbacks; int buflen; stbi_uc buffer_start[128]; + int callback_already_read; stbi_uc *img_buffer, *img_buffer_end; stbi_uc *img_buffer_original, *img_buffer_original_end; @@ -711,6 +827,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; + s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } @@ -722,7 +839,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; stbi__refill_buffer(s); s->img_buffer_original_end = s->img_buffer_end; } @@ -736,12 +854,17 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { + int ch; fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } } static int stbi__stdio_eof(void *user) { - return feof((FILE*) user); + return feof((FILE*) user) || ferror((FILE *) user); } static stbi_io_callbacks stbi__stdio_callbacks = @@ -837,21 +960,27 @@ 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 -// this is not threadsafe -static const char *stbi__g_failure_reason; +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } +#ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } +#endif static void *stbi__malloc(size_t size) { @@ -890,11 +1019,13 @@ static int stbi__mul2sizes_valid(int a, int b) return a <= INT_MAX/b; } +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow static int stbi__mad2sizes_valid(int a, int b, int add) { return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); } +#endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow static int stbi__mad3sizes_valid(int a, int b, int c, int add) @@ -904,7 +1035,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) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) 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) && @@ -912,12 +1043,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) } #endif +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) { if (!stbi__mad2sizes_valid(a, b, add)) return NULL; return stbi__malloc(a*b + add); } +#endif static void *stbi__malloc_mad3(int a, int b, int c, int add) { @@ -925,7 +1058,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) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) 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; @@ -933,6 +1066,23 @@ 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 @@ -961,13 +1111,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif -static int stbi__vertically_flip_on_load = 0; +static int stbi__vertically_flip_on_load_global = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { - stbi__vertically_flip_on_load = flag_true_if_should_flip; + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields @@ -975,9 +1141,8 @@ 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; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -989,10 +1154,19 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); #endif #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 @@ -1069,6 +1243,7 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) } } +#ifndef STBI_NO_GIF static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) { int slice; @@ -1076,10 +1251,11 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; } } +#endif static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { @@ -1089,8 +1265,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 8; } @@ -1113,8 +1291,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 16; } @@ -1130,7 +1310,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, return (stbi__uint16 *) result; } -#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { @@ -1142,10 +1322,38 @@ 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) +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) +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); +} +#endif + static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; +#if defined(_WIN32) && 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))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + #if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else @@ -1236,15 +1444,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - + stbi__context s; + stbi__start_mem(&s,buffer,len); + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } - return result; + return result; } #endif @@ -1389,6 +1597,7 @@ enum static void stbi__refill_buffer(stbi__context *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); if (n == 0) { // at end of file, treat same as if from memory, but need to handle case // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file @@ -1413,6 +1622,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s) return 0; } +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { @@ -1424,9 +1636,14 @@ stbi_inline static int stbi__at_eof(stbi__context *s) return s->img_buffer >= s->img_buffer_end; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else static void stbi__skip(stbi__context *s, int n) { + if (n == 0) return; // already there! if (n < 0) { s->img_buffer = s->img_buffer_end; return; @@ -1441,7 +1658,11 @@ static void stbi__skip(stbi__context *s, int n) } s->img_buffer += n; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { @@ -1465,18 +1686,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) } else return 0; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } +#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1492,13 +1722,16 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp @@ -1514,7 +1747,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1538,19 +1775,19 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + 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(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(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]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__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); + STBI__CASE(4,2) { dest[0]=stbi__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); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1558,12 +1795,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI_FREE(data); return good; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1587,19 +1832,19 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + 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(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(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]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__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); + STBI__CASE(4,2) { dest[0]=stbi__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); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1607,6 +1852,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI_FREE(data); return good; } +#endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) @@ -1622,7 +1868,11 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) for (k=0; k < n; ++k) { output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } } STBI_FREE(data); return output; @@ -1755,9 +2005,12 @@ 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) @@ -1882,6 +2135,8 @@ 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 @@ -1900,14 +2155,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 = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -1915,6 +2170,7 @@ 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]; @@ -1926,6 +2182,7 @@ 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; @@ -1957,14 +2214,16 @@ 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) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) 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 @@ -1978,6 +2237,7 @@ 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 @@ -2014,11 +2274,14 @@ 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"); 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; - data[0] = (short) (dc << j->succ_low); + 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)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2052,10 +2315,11 @@ 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) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2073,7 +2337,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) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -2872,6 +3136,7 @@ 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; @@ -3004,6 +3269,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); c = stbi__get8(s); if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; @@ -3035,6 +3302,13 @@ 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; @@ -3112,6 +3386,28 @@ 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) { @@ -3128,25 +3424,22 @@ 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 ) { - // 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; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // 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 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3590,12 +3883,16 @@ 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; unsigned int i,j; stbi_uc *output; - stbi_uc *coutput[4]; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; stbi__resample res_comp[4]; @@ -3716,7 +4013,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (n == 1) for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } } } } @@ -3732,6 +4029,8 @@ 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); @@ -3744,6 +4043,8 @@ 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); @@ -3768,6 +4069,8 @@ 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); @@ -3787,6 +4090,7 @@ 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) @@ -3796,8 +4100,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -3874,6 +4178,7 @@ typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; + int hit_zeof_once; stbi__uint32 code_buffer; char *zout; @@ -3884,16 +4189,23 @@ typedef struct stbi__zhuffman z_length, z_distance; } stbi__zbuf; +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; + return stbi__zeof(z) ? 0 : *z->zbuffer++; } static void stbi__fill_bits(stbi__zbuf *z) { do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); @@ -3918,10 +4230,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; - if (s == 16) return -1; // invalid code! + if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); + if (b >= STBI__ZNSYMS) 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; return z->value[b]; @@ -3930,7 +4243,23 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + 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); + } + } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -3944,13 +4273,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; - int cur, limit, old_limit; + unsigned int cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__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) + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); limit *= 2; + } q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); @@ -3991,17 +4323,25 @@ 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) return stbi__err("bad huffman code","Corrupt PNG"); + 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 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 (zout + len > a->zout_end) { + if (len > a->zout_end - zout) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } @@ -4048,11 +4388,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) c = stbi__zreceive(a,2)+3; if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; - } else if (c == 17) + } else if (c == 17) { c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); + } else if (c == 18) { c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); } if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); @@ -4078,7 +4419,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a) a->code_buffer >>= 8; a->num_bits -= 8; } - STBI_ASSERT(a->num_bits == 0); + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); @@ -4100,6 +4441,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png @@ -4107,7 +4449,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 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, @@ -4143,6 +4485,7 @@ 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); @@ -4153,7 +4496,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 , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4298,9 +4641,8 @@ enum { STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first }; static stbi_uc first_row_filter[5] = @@ -4309,29 +4651,56 @@ static stbi_uc first_row_filter[5] = STBI__F_sub, STBI__F_none, STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub }; static int stbi__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; + // 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; } 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 @@ -4343,8 +4712,11 @@ 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, @@ -4352,189 +4724,137 @@ 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) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; + // 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; int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - 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; + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; } - 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]; - // 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; - } + // 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; } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - 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; - } + raw += nk; - // 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; - } - } - } - } - - // 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 + // 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; - // 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 - + // expand bits to bytes first if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; } - 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); + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; } - 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); + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; } - 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; + + // insert alpha=255 values if desired + 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); + } 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) { + 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 (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; + 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 (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]; + 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; } } } } - } 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]; - } } + STBI_FREE(filter_buf); + if (!all_ok) return 0; + return 1; } @@ -4549,6 +4869,7 @@ 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 }; @@ -4669,19 +4990,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = 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; @@ -4730,7 +5078,7 @@ static void stbi__de_iphone(stbi__png *z) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; + stbi_uc has_trans=0, tc[3]={0}; stbi__uint16 tc16[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; int first=1,k,interlace=0, color=0, is_iphone=0; @@ -4756,8 +5104,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); @@ -4769,14 +5119,13 @@ 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; } @@ -4808,10 +5157,14 @@ 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) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + 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 } else { - 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 + 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 } } break; @@ -4820,7 +5173,13 @@ 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) { s->img_n = pal_img_n; return 1; } + 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 ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -4874,6 +5233,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); return 1; } @@ -4904,10 +5265,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) + if (p->depth <= 8) ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; else - ri->bits_per_channel = p->depth; + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { @@ -5008,11 +5371,11 @@ static int stbi__high_bit(unsigned int z) { int n=0; if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } return n; } @@ -5029,7 +5392,7 @@ static int stbi__bitcount(unsigned int a) // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(int v, int shift, int bits) +static int stbi__shiftsigned(unsigned int v, int shift, int bits) { static unsigned int mul_table[9] = { 0, @@ -5043,7 +5406,7 @@ static int stbi__shiftsigned(int v, int shift, int bits) v <<= -shift; else v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); + STBI_ASSERT(v < 256); v >>= (8-bits); STBI_ASSERT(bits >= 0 && bits <= 8); return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; @@ -5053,8 +5416,35 @@ typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; + 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; @@ -5065,6 +5455,9 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { @@ -5079,6 +5472,8 @@ 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 @@ -5093,21 +5488,12 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - 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; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); + info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? @@ -5117,6 +5503,7 @@ 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"); @@ -5124,6 +5511,8 @@ 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 @@ -5156,6 +5545,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; mg = info.mg; mb = info.mb; @@ -5164,13 +5556,35 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz == 12) { if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; + psize = (info.offset - info.extra_read - 24) / 3; } else { if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; + 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); + } } - s->img_n = ma ? 4 : 3; + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 target = req_comp; else @@ -5192,7 +5606,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); if (info.bpp == 1) width = (s->img_x + 7) >> 3; else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; @@ -5206,6 +5620,8 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req out[z++] = pal[color][0]; out[z++] = pal[color][1]; out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; if((--bit_offset) < 0) { bit_offset = 7; v = stbi__get8(s); @@ -5239,7 +5655,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); + stbi__skip(s, info.offset - info.extra_read - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; @@ -5257,6 +5673,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } } for (j=0; j < (int) s->img_y; ++j) { if (easy) { @@ -5298,7 +5715,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *p1 = out + j *s->img_x*target; stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; + t = p1[i]; p1[i] = p2[i]; p2[i] = t; } } } @@ -5478,6 +5895,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req int RLE_repeating = 0; int read_next_pixel = 1; STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); // do a tiny bit of precessing if ( tga_image_type >= 8 ) @@ -5518,6 +5940,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // do I need to load a palette? if ( tga_indexed) { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette @@ -5641,6 +6068,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Microsoft's C compilers happy... [8^( tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); // OK, done return tga_data; } @@ -5725,6 +6153,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req h = stbi__get32be(s); w = stbi__get32be(s); + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // Make sure the depth is 8 bits. bitdepth = stbi__get16be(s); if (bitdepth != 8 && bitdepth != 16) @@ -5788,7 +6219,7 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // Else if n is 128, noop. // Endloop - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, // which we're going to just skip. stbi__skip(s, h * channelCount * 2 ); @@ -6079,6 +6510,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c x = stbi__get16be(s); y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); @@ -6088,6 +6523,7 @@ 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)) { @@ -6126,7 +6562,7 @@ typedef struct int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; + stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; @@ -6187,6 +6623,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in g->ratio = stbi__get8(s); g->transparent = -1; + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; @@ -6200,6 +6639,7 @@ 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 ); @@ -6214,7 +6654,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6223,12 +6663,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; + idx = g->cur_x + g->cur_y; p = &g->out[idx]; - g->history[idx / 4] = 1; + g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6337,31 +6777,36 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int dispose; - int first_frame; - int pi; - int pcount; + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; + first_frame = 0; if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->history = (stbi_uc *) stbi__malloc(g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); - // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to teh color that was there the previous frame. - memset( g->out, 0x00, 4 * g->w * g->h ); - memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - first_frame = 1; + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background @@ -6370,32 +6815,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { - // This is a non-disposal case eithe way, so just + // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } - // clear my history; + // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { - int tag = stbi__get8(s); + int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { @@ -6417,6 +6862,13 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i g->cur_x = g->start_x; g->cur_y = g->start_y; + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + g->lflags = stbi__get8(s); if (g->lflags & 0x40) { @@ -6433,19 +6885,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; + return stbi__errpuc("missing color table", "Corrupt GIF"); - // if this was the first frame, - pcount = g->w * g->h; + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } @@ -6456,7 +6908,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); + int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { @@ -6465,23 +6917,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // unset old transparent if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } + g->pal[g->transparent][3] = 255; + } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; + g->pal[g->transparent][3] = 0; } } else { // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; + stbi__skip(s, 1); + g->transparent = -1; } } else { stbi__skip(s, len); break; } - } + } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } @@ -6497,18 +6949,35 @@ 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)) { - int layers = 0; + int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; - stbi_uc *two_back = 0; + stbi_uc *two_back = 0; stbi__gif g; - int stride; + 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; + *delays = 0; } do { @@ -6518,44 +6987,61 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (u) { *x = g.w; *y = g.h; - ++layers; - stride = g.w * g.h * 4; - + ++layers; + stride = g.w * g.h * 4; + if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + 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_size = layers * sizeof(int); } } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); + 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) ); + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); } } - memcpy( out + ((layers - 1) * stride), u, stride ); + memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out - 2 * stride; } if (delays) { - (*delays)[layers - 1U] = g.delay; + (*delays)[layers - 1U] = g.delay; } } - } while (u != 0); + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; + // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; + *z = layers; return out; } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); + return stbi__errpuc("not GIF", "Image was not as a gif type."); } } @@ -6564,6 +7050,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *u = 0; stbi__gif g; memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); u = stbi__gif_load_next(s, &g, comp, req_comp, 0); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker @@ -6572,14 +7059,17 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req *y = g.h; // moved conversion to after successful load so that the same - // can be done for multiple frames. + // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); } - // free buffers needed for multiple frame loading; + // free buffers needed for multiple frame loading; STBI_FREE(g.history); - STBI_FREE(g.background); + STBI_FREE(g.background); return u; } @@ -6704,6 +7194,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re token += 3; width = (int) strtol(token, NULL, 10); + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + *x = width; *y = height; @@ -6772,12 +7265,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 > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (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 > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (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); } @@ -6846,12 +7339,18 @@ 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); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; - if (comp) *comp = info.ma ? 4 : 3; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } return 1; } #endif @@ -6894,7 +7393,7 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__psd_is16(stbi__context *s) { - int channelCount, dummy, depth; + int channelCount, depth; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; @@ -6909,8 +7408,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - dummy = stbi__get32be(s); - dummy = stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -6989,7 +7488,6 @@ 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 @@ -7010,22 +7508,33 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + 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) return 0; + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + 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"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + 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); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7062,6 +7571,8 @@ 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; @@ -7092,17 +7603,29 @@ 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 > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + 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 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7158,6 +7681,9 @@ 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; } @@ -7237,6 +7763,9 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user /* revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug 1-bit BMP *_is_16_bit api diff --git a/raylib/external/stb_image_resize.h b/raylib/external/stb_image_resize.h deleted file mode 100644 index 031ca99..0000000 --- a/raylib/external/stb_image_resize.h +++ /dev/null @@ -1,2627 +0,0 @@ -/* stb_image_resize - v0.95 - 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.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 - -#ifdef STB_IMAGE_RESIZE_STATIC -#define STBIRDEF static -#else -#ifdef __cplusplus -#define STBIRDEF extern "C" -#else -#define STBIRDEF extern -#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) ((type) * (STBIR_MAX_COLORSPACES) + (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 new file mode 100644 index 0000000..2f26274 --- /dev/null +++ b/raylib/external/stb_image_resize2.h @@ -0,0 +1,10601 @@ +/* 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 eaf5093..e4b32ed 100644 --- a/raylib/external/stb_image_write.h +++ b/raylib/external/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.08 - public domain - http://nothings.org/stb/stb_image_write.h +/* stb_image_write - v1.16 - 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 @@ -10,15 +10,9 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, also before #including, - - #define STBI_MSC_SECURE_CRT - ABOUT: - This header file is a library for writing images to C stdio. It could be - adapted to write to memory or a general streaming interface; let me know. + This header file is a library for writing images to C stdio or a callback. The PNG output is not optimal; it is 20-50% larger than the file written by a decent optimizing implementation; though providing a custom @@ -38,6 +32,14 @@ BUILDING: The returned data will be freed with STBIW_FREE() (free() by default), so it must be heap allocated with STBIW_MALLOC() (malloc() by default), +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + USAGE: There are five functions, one for each image file format: @@ -45,8 +47,8 @@ USAGE: int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); - int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data, int quality); void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically @@ -95,7 +97,7 @@ USAGE: at the end of the line.) PNG allows you to set the deflate compression level by setting the global - variable 'stbi_write_png_level' (it defaults to 8). + variable 'stbi_write_png_compression_level' (it defaults to 8). HDR expects linear float data. Since the format is always 32-bit rgb(e) data, alpha (if provided) is discarded, and for monochrome data it is @@ -103,7 +105,7 @@ USAGE: TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. - + JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). @@ -111,7 +113,7 @@ USAGE: CREDITS: - Sean Barrett - PNG/BMP/TGA + Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements @@ -133,7 +135,13 @@ CREDITS: github:poppolopoppo Patrick Boettcher github:xeekworx - + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + LICENSE See end of file for license information. @@ -143,19 +151,26 @@ LICENSE #ifndef INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H -#ifdef __cplusplus -extern "C" { -#endif +#include +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC -#define STBIWDEF static +#define STBIWDEF static #else -#define STBIWDEF extern +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif #endif +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations STBIWDEF int stbi_write_tga_with_rle; -STBIWDEF int stbi_write_png_comperssion_level; +STBIWDEF int stbi_write_png_compression_level; STBIWDEF int stbi_write_force_png_filter; +#endif #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); @@ -163,6 +178,10 @@ STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 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 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif #endif typedef void stbi_write_func(void *context, void *data, int size); @@ -175,10 +194,6 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); -#ifdef __cplusplus -} -#endif - #endif//INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION @@ -233,17 +248,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #ifdef STB_IMAGE_WRITE_STATIC -static stbi__flip_vertically_on_write=0; -static int stbi_write_png_compression level = 8; +static int stbi_write_png_compression_level = 8; static int stbi_write_tga_with_rle = 1; static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; -int stbi__flip_vertically_on_write=0; int stbi_write_tga_with_rle = 1; int stbi_write_force_png_filter = -1; #endif +static int stbi__flip_vertically_on_write = 0; + STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; @@ -253,6 +268,8 @@ typedef struct { stbi_write_func *func; void *context; + unsigned char buffer[64]; + int buf_used; } stbi__write_context; // initialize a callback-based context @@ -269,15 +286,52 @@ static void stbi__stdio_write(void *context, void *data, int size) fwrite(data,1,size,(FILE*) context); } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_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); + +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); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = fopen(filename, "wb"); + f = _wfopen(wFilename, wMode); #endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } @@ -329,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) va_end(v); } +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { - unsigned char arr[3]; - arr[0] = a, arr[1] = b, arr[2] = c; - s->func(s->context, arr, 3); + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; } static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) @@ -347,7 +421,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in int k; if (write_alpha < 0) - s->func(s->context, &d[comp - 1], 1); + stbiw__write1(s, d[comp - 1]); switch (comp) { case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case @@ -355,7 +429,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp else - s->func(s->context, d, 1); // monochrome TGA + stbiw__write1(s, d[0]); // monochrome TGA break; case 4: if (!write_alpha) { @@ -371,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in break; } if (write_alpha > 0) - s->func(s->context, &d[comp - 1], 1); + stbiw__write1(s, d[comp - 1]); } static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) @@ -385,16 +459,18 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i if (stbi__flip_vertically_on_write) vdir *= -1; - if (vdir < 0) - j_end = -1, j = y-1; - else - j_end = y, j = 0; + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { unsigned char *d = (unsigned char *) data + (j*x+i)*comp; stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); } + stbiw__write_flush(s); s->func(s->context, &zero, scanline_pad); } } @@ -415,16 +491,27 @@ 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) { - 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 + 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 + } } STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_bmp_core(&s, x, y, comp, data); } @@ -432,7 +519,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_bmp_core(&s, x, y, comp, data); stbi__end_write_file(&s); @@ -505,24 +592,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v if (diff) { unsigned char header = STBIW_UCHAR(len - 1); - s->func(s->context, &header, 1); + stbiw__write1(s, header); for (k = 0; k < len; ++k) { stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); } } else { unsigned char header = STBIW_UCHAR(len - 129); - s->func(s->context, &header, 1); + stbiw__write1(s, header); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); } } } + stbiw__write_flush(s); } return 1; } STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_tga_core(&s, x, y, comp, (void *) data); } @@ -530,7 +618,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); stbi__end_write_file(&s); @@ -546,7 +634,9 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); @@ -563,7 +653,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) } } -void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { unsigned char lengthbyte = STBIW_UCHAR(length+128); STBIW_ASSERT(length+128 <= 255); @@ -571,7 +661,7 @@ void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char dat s->func(s->context, &databyte, 1); } -void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { unsigned char lengthbyte = STBIW_UCHAR(length); STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code @@ -579,7 +669,7 @@ void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *d s->func(s->context, data, length); } -void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) { unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; unsigned char rgbe[4]; @@ -680,15 +770,15 @@ 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 STBI_MSC_SECURE_CRT - len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#ifdef __STDC_LIB_EXT1__ + 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); #endif s->func(s->context, buffer, len); for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x); + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); STBIW_FREE(scratch); return 1; } @@ -696,15 +786,14 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); 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; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); stbi__end_write_file(&s); @@ -722,7 +811,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (a) - 2) +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) #define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbn(a) stbiw__sbraw(a)[1] @@ -803,7 +892,7 @@ static unsigned int stbiw__zhash(unsigned char *data) #endif // STBIW_ZLIB_COMPRESS -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS // user provided a zlib compress implementation, use that @@ -816,7 +905,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); if (hash_table == NULL) return NULL; if (quality < 5) quality = 5; @@ -839,7 +928,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { // if entry lies within window int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) best=d,bestloc=hlist[j]; + if (d >= best) { best=d; bestloc=hlist[j]; } } } // when hash table entry is too long, delete half the entries @@ -892,14 +981,31 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l (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; 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; + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; j += blocklen; blocklen = 5552; } @@ -917,6 +1023,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l static unsigned int stbiw__crc32(unsigned char *buffer, int len) { +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else static unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, @@ -958,6 +1067,7 @@ static unsigned int stbiw__crc32(unsigned char *buffer, int len) for (i=0; i < len; ++i) crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; return ~crc; +#endif } #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) @@ -987,31 +1097,35 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int int i; int type = mymap[filter_type]; unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel for (i = 0; i < n; ++i) { switch (type) { - case 0: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; case 5: line_buffer[i] = z[i]; break; case 6: line_buffer[i] = z[i]; break; } } - for (i=n; i < width*n; ++i) { - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i] - z[i-n]; break; - case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; - case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; - case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; - case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } -unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { int force_filter = stbi_write_force_png_filter; int ctype[5] = { -1, 0, 4, 2, 6 }; @@ -1033,11 +1147,11 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in int filter_type; if (force_filter > -1) { filter_type = force_filter; - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); } else { // Estimate the best filter by running through all of them: int best_filter = 0, best_filter_val = 0x7fffffff, est, i; for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); // Estimate the entropy of the line using this filter; the less, the better. est = 0; @@ -1050,7 +1164,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in } } if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); filter_type = best_filter; } } @@ -1102,14 +1216,10 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const { FILE *f; int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; -#else - f = fopen(filename, "wb"); -#endif + + f = stbiw__fopen(filename, "wb"); if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); @@ -1121,7 +1231,7 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) { int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; func(context, png, len); STBIW_FREE(png); @@ -1215,26 +1325,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { bits[0] = val & ((1< 100 ? 100 : quality; quality = quality < 50 ? 5000 / quality : 200 - quality * 2; @@ -1383,7 +1499,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; s->func(s->context, (void*)head0, sizeof(head0)); s->func(s->context, (void*)YTable, sizeof(YTable)); stbiw__putc(s, 1); @@ -1406,38 +1522,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in // Encode 8x8 macroblocks { static const unsigned short fillBits[] = {0x7F, 7}; - const unsigned char *imageData = (const unsigned char *)data; int DCY=0, DCU=0, DCV=0; int bitBuf=0, bitCnt=0; // comp == 2 is grey+alpha (alpha is ignored) int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; int x, y, pos; - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float YDU[64], UDU[64], VDU[64]; - for(row = y, pos = 0; row < y+8; ++row) { - for(col = x; col < x+8; ++col, ++pos) { - int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp; - float r, g, b; - if(row >= height) { - p -= width*comp*(row+1 - height); - } - if(col >= width) { - p -= comp*(col+1 - width); + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - r = imageData[p+0]; - g = imageData[p+ofsG]; - b = imageData[p+ofsB]; - YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; - UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; - VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } } } @@ -1454,7 +1606,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); } @@ -1463,7 +1615,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); stbi__end_write_file(&s); @@ -1476,6 +1628,19 @@ 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 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1.07 (2017-07-24) @@ -1504,7 +1669,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) @@ -1522,38 +1687,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/stb_perlin.h b/raylib/external/stb_perlin.h index 5d76222..47cb9a4 100644 --- a/raylib/external/stb_perlin.h +++ b/raylib/external/stb_perlin.h @@ -1,4 +1,4 @@ -// stb_perlin.h - v0.3 - perlin noise +// stb_perlin.h - v0.5 - perlin noise // public domain single-file C implementation by Sean Barrett // // LICENSE @@ -32,34 +32,45 @@ // details of the implementation, even if you ask for larger or no // wrapping.) // +// float stb_perlin_noise3_seed( float x, +// float y, +// float z, +// int x_wrap=0, +// int y_wrap=0, +// int z_wrap=0, +// int seed) +// +// As above, but 'seed' selects from multiple different variations of the +// noise function. The current implementation only uses the bottom 8 bits +// of 'seed', but possibly in the future more bits will be used. +// +// // Fractal Noise: // -// Three common fractal noise functions are included, which produce -// a wide variety of nice effects depending on the parameters -// provided. Note that each function will call stb_perlin_noise3 +// Three common fractal noise functions are included, which produce +// a wide variety of nice effects depending on the parameters +// provided. Note that each function will call stb_perlin_noise3 // 'octaves' times, so this parameter will affect runtime. // // float stb_perlin_ridge_noise3(float x, float y, float z, -// float lacunarity, float gain, float offset, int octaves, -// int x_wrap, int y_wrap, int z_wrap); +// float lacunarity, float gain, float offset, int octaves) // // float stb_perlin_fbm_noise3(float x, float y, float z, -// float lacunarity, float gain, int octaves, -// int x_wrap, int y_wrap, int z_wrap); +// float lacunarity, float gain, int octaves) // // float stb_perlin_turbulence_noise3(float x, float y, float z, -// float lacunarity, float gain,int octaves, -// int x_wrap, int y_wrap, int z_wrap); +// float lacunarity, float gain, int octaves) // // Typical values to start playing with: // octaves = 6 -- number of "octaves" of noise3() to sum // lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output) // gain = 0.5 -- relative weighting applied to each successive octave // offset = 1.0? -- used to invert the ridges, may need to be larger, not sure -// +// // // Contributors: // Jack Mott - additional noise functions +// Jordan Peck - seeded noise // @@ -67,54 +78,102 @@ extern "C" { #endif extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap); -extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap); -extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap); -extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap); +extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed); +extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves); +extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves); +extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves); +extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed); #ifdef __cplusplus } #endif #ifdef STB_PERLIN_IMPLEMENTATION +#include // fabs() + // not same permutation table as Perlin's reference to avoid copyright issues; // Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/ -// @OPTIMIZE: should this be unsigned char instead of int for cache? static unsigned char stb__perlin_randtab[512] = { - 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, - 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, - 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, - 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, - 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, - 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, - 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, - 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, - 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, - 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, - 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, - 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, - 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, - 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, - 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, - 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, + 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, + 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, + 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, + 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, + 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, + 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, + 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, + 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, + 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, + 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, + 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, + 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, + 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, + 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, + 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, + 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, // and a second copy so we don't need an extra mask or static initializer - 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, - 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, - 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, - 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, - 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, - 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, - 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, - 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, - 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, - 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, - 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, - 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, - 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, - 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, - 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, - 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, + 23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123, + 152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72, + 175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240, + 8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57, + 225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233, + 94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172, + 165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243, + 65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122, + 26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76, + 250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246, + 132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3, + 91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231, + 38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221, + 131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62, + 27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135, + 61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5, +}; + + +// perlin's gradient has 12 cases so some get used 1/16th of the time +// and some 2/16ths. We reduce bias by changing those fractions +// to 5/64ths and 6/64ths + +// this array is designed to match the previous implementation +// of gradient hash: indices[stb__perlin_randtab[i]&63] +static unsigned char stb__perlin_randtab_grad_idx[512] = +{ + 7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7, + 8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8, + 7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8, + 8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5, + 5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1, + 2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4, + 9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11, + 1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6, + 10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0, + 6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2, + 4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3, + 11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11, + 10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1, + 3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10, + 11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7, + 9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5, + + // and a second copy so we don't need an extra mask or static initializer + 7, 9, 5, 0, 11, 1, 6, 9, 3, 9, 11, 1, 8, 10, 4, 7, + 8, 6, 1, 5, 3, 10, 9, 10, 0, 8, 4, 1, 5, 2, 7, 8, + 7, 11, 9, 10, 1, 0, 4, 7, 5, 0, 11, 6, 1, 4, 2, 8, + 8, 10, 4, 9, 9, 2, 5, 7, 9, 1, 7, 2, 2, 6, 11, 5, + 5, 4, 6, 9, 0, 1, 1, 0, 7, 6, 9, 8, 4, 10, 3, 1, + 2, 8, 8, 9, 10, 11, 5, 11, 11, 2, 6, 10, 3, 4, 2, 4, + 9, 10, 3, 2, 6, 3, 6, 10, 5, 3, 4, 10, 11, 2, 9, 11, + 1, 11, 10, 4, 9, 4, 11, 0, 4, 11, 4, 0, 0, 0, 7, 6, + 10, 4, 1, 3, 11, 5, 3, 4, 2, 9, 1, 3, 0, 1, 8, 0, + 6, 7, 8, 7, 0, 4, 6, 10, 8, 2, 3, 11, 11, 8, 0, 2, + 4, 8, 3, 0, 0, 10, 6, 1, 2, 2, 4, 5, 6, 0, 1, 3, + 11, 9, 5, 5, 9, 6, 9, 8, 3, 8, 1, 8, 9, 6, 9, 11, + 10, 7, 5, 6, 5, 9, 1, 3, 7, 0, 2, 10, 11, 2, 6, 1, + 3, 11, 7, 7, 2, 1, 7, 3, 0, 8, 1, 1, 5, 0, 6, 10, + 11, 11, 0, 2, 7, 0, 10, 8, 3, 5, 7, 1, 11, 1, 0, 7, + 9, 0, 11, 5, 10, 3, 2, 3, 5, 9, 7, 9, 8, 4, 6, 5, }; static float stb__perlin_lerp(float a, float b, float t) @@ -124,12 +183,12 @@ static float stb__perlin_lerp(float a, float b, float t) static int stb__perlin_fastfloor(float a) { - int ai = (int) a; - return (a < ai) ? ai-1 : ai; + int ai = (int) a; + return (a < ai) ? ai-1 : ai; } // different grad function from Perlin's, but easy to modify to match reference -static float stb__perlin_grad(int hash, float x, float y, float z) +static float stb__perlin_grad(int grad_idx, float x, float y, float z) { static float basis[12][4] = { @@ -147,26 +206,11 @@ static float stb__perlin_grad(int hash, float x, float y, float z) { 0,-1,-1 }, }; - // perlin's gradient has 12 cases so some get used 1/16th of the time - // and some 2/16ths. We reduce bias by changing those fractions - // to 5/64ths and 6/64ths, and the same 4 cases get the extra weight. - static unsigned char indices[64] = - { - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,9,1,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - 0,1,2,3,4,5,6,7,8,9,10,11, - }; - - // if you use reference permutation table, change 63 below to 15 to match reference - // (this is why the ordering of the table above is funky) - float *grad = basis[indices[hash & 63]]; + float *grad = basis[grad_idx]; return grad[0]*x + grad[1]*y + grad[2]*z; } -float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap) +float stb_perlin_noise3_internal(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed) { float u,v,w; float n000,n001,n010,n011,n100,n101,n110,n111; @@ -190,22 +234,22 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z y -= py; v = stb__perlin_ease(y); z -= pz; w = stb__perlin_ease(z); - r0 = stb__perlin_randtab[x0]; - r1 = stb__perlin_randtab[x1]; + r0 = stb__perlin_randtab[x0+seed]; + r1 = stb__perlin_randtab[x1+seed]; r00 = stb__perlin_randtab[r0+y0]; r01 = stb__perlin_randtab[r0+y1]; r10 = stb__perlin_randtab[r1+y0]; r11 = stb__perlin_randtab[r1+y1]; - n000 = stb__perlin_grad(stb__perlin_randtab[r00+z0], x , y , z ); - n001 = stb__perlin_grad(stb__perlin_randtab[r00+z1], x , y , z-1 ); - n010 = stb__perlin_grad(stb__perlin_randtab[r01+z0], x , y-1, z ); - n011 = stb__perlin_grad(stb__perlin_randtab[r01+z1], x , y-1, z-1 ); - n100 = stb__perlin_grad(stb__perlin_randtab[r10+z0], x-1, y , z ); - n101 = stb__perlin_grad(stb__perlin_randtab[r10+z1], x-1, y , z-1 ); - n110 = stb__perlin_grad(stb__perlin_randtab[r11+z0], x-1, y-1, z ); - n111 = stb__perlin_grad(stb__perlin_randtab[r11+z1], x-1, y-1, z-1 ); + n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z ); + n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 ); + n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z ); + n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 ); + n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z ); + n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 ); + n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z ); + n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 ); n00 = stb__perlin_lerp(n000,n001,w); n01 = stb__perlin_lerp(n010,n011,w); @@ -218,7 +262,17 @@ float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z return stb__perlin_lerp(n0,n1,u); } -float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap) +float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap) +{ + return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap,0); +} + +float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed) +{ + return stb_perlin_noise3_internal(x,y,z,x_wrap,y_wrap,z_wrap, (unsigned char) seed); +} + +float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves) { int i; float frequency = 1.0f; @@ -227,9 +281,8 @@ float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float float sum = 0.0f; for (i = 0; i < octaves; i++) { - float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)); - r = r<0 ? -r : r; // fabs() - r = offset - r; + float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i); + r = offset - (float) fabs(r); r = r*r; sum += r*amplitude*prev; prev = r; @@ -239,38 +292,97 @@ float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float return sum; } -float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap) +float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves) { int i; float frequency = 1.0f; float amplitude = 1.0f; float sum = 0.0f; - + for (i = 0; i < octaves; i++) { - sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude; + sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude; frequency *= lacunarity; amplitude *= gain; } return sum; } -float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap) +float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves) { int i; float frequency = 1.0f; float amplitude = 1.0f; float sum = 0.0f; - + for (i = 0; i < octaves; i++) { - float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude; - r = r<0 ? -r : r; // fabs() - sum += r; + float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude; + sum += (float) fabs(r); frequency *= lacunarity; amplitude *= gain; } return sum; } +float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, unsigned char seed) +{ + float u,v,w; + float n000,n001,n010,n011,n100,n101,n110,n111; + float n00,n01,n10,n11; + float n0,n1; + + int px = stb__perlin_fastfloor(x); + int py = stb__perlin_fastfloor(y); + int pz = stb__perlin_fastfloor(z); + int x_wrap2 = (x_wrap ? x_wrap : 256); + int y_wrap2 = (y_wrap ? y_wrap : 256); + int z_wrap2 = (z_wrap ? z_wrap : 256); + int x0 = px % x_wrap2, x1; + int y0 = py % y_wrap2, y1; + int z0 = pz % z_wrap2, z1; + int r0,r1, r00,r01,r10,r11; + + if (x0 < 0) x0 += x_wrap2; + if (y0 < 0) y0 += y_wrap2; + if (z0 < 0) z0 += z_wrap2; + x1 = (x0+1) % x_wrap2; + y1 = (y0+1) % y_wrap2; + z1 = (z0+1) % z_wrap2; + + #define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a) + + x -= px; u = stb__perlin_ease(x); + y -= py; v = stb__perlin_ease(y); + z -= pz; w = stb__perlin_ease(z); + + r0 = stb__perlin_randtab[x0]; + r0 = stb__perlin_randtab[r0+seed]; + r1 = stb__perlin_randtab[x1]; + r1 = stb__perlin_randtab[r1+seed]; + + r00 = stb__perlin_randtab[r0+y0]; + r01 = stb__perlin_randtab[r0+y1]; + r10 = stb__perlin_randtab[r1+y0]; + r11 = stb__perlin_randtab[r1+y1]; + + n000 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z0], x , y , z ); + n001 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r00+z1], x , y , z-1 ); + n010 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z0], x , y-1, z ); + n011 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r01+z1], x , y-1, z-1 ); + n100 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z0], x-1, y , z ); + n101 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r10+z1], x-1, y , z-1 ); + n110 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z0], x-1, y-1, z ); + n111 = stb__perlin_grad(stb__perlin_randtab_grad_idx[r11+z1], x-1, y-1, z-1 ); + + n00 = stb__perlin_lerp(n000,n001,w); + n01 = stb__perlin_lerp(n010,n011,w); + n10 = stb__perlin_lerp(n100,n101,w); + n11 = stb__perlin_lerp(n110,n111,w); + + n0 = stb__perlin_lerp(n00,n01,v); + n1 = stb__perlin_lerp(n10,n11,v); + + return stb__perlin_lerp(n0,n1,u); +} #endif // STB_PERLIN_IMPLEMENTATION /* @@ -279,38 +391,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/stb_rect_pack.h b/raylib/external/stb_rect_pack.h index 9faf578..6a633ce 100644 --- a/raylib/external/stb_rect_pack.h +++ b/raylib/external/stb_rect_pack.h @@ -1,9 +1,15 @@ -// stb_rect_pack.h - v0.11 - public domain - rectangle packing +// stb_rect_pack.h - v1.01 - 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). @@ -28,12 +34,16 @@ // Minor features // Martins Mozeiko // github:IntellectualKitty -// +// // Bugfixes / warning fixes // Jeremy Jaussaud +// Fabian Giesen // // 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 // 0.10 (2016-10-25) remove cast-away-const to avoid warnings // 0.09 (2016-08-27) fix compiler warnings @@ -72,11 +82,10 @@ 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; -#else -typedef unsigned short stbrp_coord; -#endif + +#define STBRP__MAXVAL 0x7fffffff +// Mostly for internal use, but this is the maximum supported coordinate value. 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 @@ -206,8 +215,10 @@ 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 @@ -250,9 +261,6 @@ 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]; @@ -271,11 +279,7 @@ 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; } @@ -347,6 +351,13 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt width -= width % c->align; STBRP_ASSERT(width % c->align == 0); + // if it can't possibly fit, bail immediately + if (width > c->width || height > c->height) { + fr.prev_link = NULL; + fr.x = fr.y = 0; + return fr; + } + node = c->active_head; prev = &c->active_head; while (node->x + width <= c->width) { @@ -410,7 +421,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt } STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); - if (y + height < c->height) { + if (y + height <= c->height) { if (y <= best_y) { if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { best_x = xpos; @@ -422,7 +433,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt } } tail = tail->next; - } + } } fr.prev_link = best; @@ -492,17 +503,14 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i STBRP_ASSERT(cur->next == NULL); { - stbrp_node *L1 = NULL, *L2 = NULL; int count=0; cur = context->active_head; while (cur) { - L1 = cur; cur = cur->next; ++count; } cur = context->free_head; while (cur) { - L2 = cur; cur = cur->next; ++count; } @@ -513,7 +521,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i return res; } -static int rect_height_compare(const void *a, const void *b) +static int STBRP__CDECL 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; @@ -524,19 +532,13 @@ static int rect_height_compare(const void *a, const void *b) return (p->w > q->w) ? -1 : (p->w < q->w); } -static int rect_original_order(const void *a, const void *b) +static int STBRP__CDECL 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; @@ -544,9 +546,6 @@ STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int nu // we use the 'was_packed' field internally to allow sorting/unsorting for (i=0; i < num_rects; ++i) { rects[i].was_packed = i; - #ifndef STBRP_LARGE_RECTS - STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); - #endif } // sort according to heuristic @@ -587,38 +586,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/stb_truetype.h b/raylib/external/stb_truetype.h index 98c8acc..491a854 100644 --- a/raylib/external/stb_truetype.h +++ b/raylib/external/stb_truetype.h @@ -1,5 +1,14 @@ -// stb_truetype.h - v1.18 - public domain -// authored from 2009-2016 by Sean Barrett / RAD Game Tools +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= // // This library processes TrueType files: // parse files @@ -22,19 +31,21 @@ // Mikko Mononen: compound shape support, more cmap formats // Tor Andersson: kerning, subpixel rendering // Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning // // Misc other: // Ryan Gordon // Simon Glass // github:IntellectualKitty // Imanol Celaya +// Daniel Ribeiro Maciel // // Bug/warning reports/fixes: -// "Zer" on mollyrocket Fabian "ryg" Giesen -// Cass Everitt Martins Mozeiko -// stoiko (Haemimont Games) Cap Petschulat -// Brian Hook Omar Cornut -// Walter van Niftrik github:aloucks +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege // David Gow Peter LaValle // David Given Sergey Popov // Ivan-Assen Ivanov Giumo X. Clanjor @@ -42,11 +53,19 @@ // Johan Duparc Thomas Fields // Hou Qiming Derek Vinyard // Rob Loach Cort Stratton -// Kenney Phillis Jr. github:oyvindjam -// Brian Costabile github:vassvik -// +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) Yakov Galka +// // 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 +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod // 1.18 (2018-01-29) add missing function // 1.17 (2017-07-23) make more arguments const; doc fix // 1.16 (2017-07-12) SDF support @@ -72,7 +91,7 @@ // // USAGE // -// Include this file in whatever places neeed to refer to it. In ONE C/C++ +// Include this file in whatever places need to refer to it. In ONE C/C++ // file, write: // #define STB_TRUETYPE_IMPLEMENTATION // before the #include of this file. This expands out the actual @@ -203,7 +222,7 @@ // // Advancing for the next character: // Call GlyphHMetrics, and compute 'current_point += SF * advance'. -// +// // // ADVANCED USAGE // @@ -239,19 +258,6 @@ // recommend it. // // -// SOURCE STATISTICS (based on v0.6c, 2050 LOC) -// -// Documentation & header file 520 LOC \___ 660 LOC documentation -// Sample code 140 LOC / -// Truetype parsing 620 LOC ---- 620 LOC TrueType -// Software rasterization 240 LOC \ . -// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation -// Bitmap management 100 LOC / -// Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 -// C runtime library abstraction 60 LOC ---- 60 -// -// // PERFORMANCE MEASUREMENTS FOR 1.06: // // 32-bit 64-bit @@ -266,8 +272,8 @@ //// SAMPLE PROGRAMS //// // -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless -// +// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. +// See "tests/truetype_demo_win32.c" for a complete version. #if 0 #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" @@ -293,6 +299,8 @@ 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); @@ -300,10 +308,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.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); + 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); } ++text; } @@ -341,7 +349,7 @@ int main(int argc, char **argv) } return 0; } -#endif +#endif // // Output: // @@ -355,9 +363,9 @@ int main(int argc, char **argv) // :@@. M@M // @@@o@@@@ // :M@@V:@@. -// +// ////////////////////////////////////////////////////////////////////////////// -// +// // Complete program: print "Hello World!" banner, with bugs // #if 0 @@ -411,7 +419,8 @@ int main(int arg, char **argv) //// INTEGRATION WITH YOUR CODEBASE //// //// The following sections allow you to supply alternate definitions -//// of C library functions used by stb_truetype. +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. #ifdef STB_TRUETYPE_IMPLEMENTATION // #define your own (u)stbtt_int8/16/32 before including to override this @@ -427,7 +436,7 @@ int main(int arg, char **argv) typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h #ifndef STBTT_ifloor #include #define STBTT_ifloor(x) ((int) floor(x)) @@ -440,6 +449,11 @@ int main(int arg, char **argv) #define STBTT_pow(x,y) pow(x,y) #endif + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + #ifndef STBTT_cos #include #define STBTT_cos(x) cos(x) @@ -547,6 +561,8 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p // // It's inefficient; you might want to c&p it and optimize it. +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. ////////////////////////////////////////////////////////////////////////////// @@ -632,6 +648,12 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h // To use with PackFontRangesGather etc., you must set it before calls // call to PackFontRangesGatherRects. +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above int char_index, // character to display float *xpos, float *ypos, // pointers to current position in screen pixel space @@ -644,7 +666,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look -// at the source to of stbtt_PackFontRanges() and create a custom version +// at the source to of stbtt_PackFontRanges() and create a custom version // using these functions, e.g. call GatherRects multiple times, // building up a single array of rects, then call PackRects once, // then call RenderIntoRects repeatedly. This may result in a @@ -660,6 +682,7 @@ struct stbtt_pack_context { int height; int stride_in_bytes; int padding; + int skip_missing; unsigned int h_oversample, v_oversample; unsigned char *pixels; void *nodes; @@ -685,7 +708,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // file will only define one font and it always be at offset 0, so it will // return '0' for index 0, and -1 for all other indices. -// The following structure is defined publically so you can declare one on +// The following structure is defined publicly so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. struct stbtt_fontinfo { @@ -695,7 +718,7 @@ struct stbtt_fontinfo int numGlyphs; // number of glyphs, needed for range checking - int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf int index_map; // a cmap mapping for our chosen character encoding int indexToLocFormat; // format needed to map from glyph index to glyph @@ -724,6 +747,7 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep // and you want a speed-up, call this function with the character you're // going to process, then use glyph-based functions instead of the // codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. ////////////////////////////////////////////////////////////////////////////// @@ -777,6 +801,18 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); // as above, but takes one or more glyph indices for greater efficiency +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) ////////////////////////////////////////////////////////////////////////////// // @@ -811,7 +847,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s // returns # of vertices and fills *vertices with the pointer to them // these are expressed in "unscaled" coordinates // -// The shape is a series of countours. Each one starts with +// The shape is a series of contours. Each one starts with // a STBTT_moveto, then consists of a series of mixed // STBTT_lineto and STBTT_curveto segments. A lineto // draws a line from previous endpoint to its x,y; a curveto @@ -821,6 +857,12 @@ 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. +// returns data size or 0 if SVG not found. + ////////////////////////////////////////////////////////////////////////////// // // BITMAP RENDERING @@ -907,7 +949,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); // These functions compute a discretized SDF field for a single character, suitable for storing // in a single-channel texture, sampling with bilinear filtering, and testing against -// larger than some threshhold to produce scalable fonts. +// larger than some threshold to produce scalable fonts. // info -- the font // scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap // glyph/codepoint -- the character to generate the SDF for @@ -950,7 +992,7 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // and computing from that can allow drop-out prevention). // // The algorithm has not been optimized at all, so expect it to be slow -// if computing lots of characters or very large sizes. +// if computing lots of characters or very large sizes. @@ -1322,6 +1364,22 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) return stbtt__cff_get_index(&cff); } +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) { stbtt_uint32 cmap, t; @@ -1338,6 +1396,7 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required if (!cmap || !info->head || !info->hhea || !info->hmtx) return 0; @@ -1400,6 +1459,8 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in else info->numGlyphs = 0xffff; + info->svg = -1; + // find a cmap encoding table we understand *now* to avoid searching // later. (todo: could make this installable) // the same regardless of glyph. @@ -1483,12 +1544,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep search += 2; { - stbtt_uint16 offset, start; + stbtt_uint16 offset, start, last; 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); - if (unicode_codepoint < start) + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) return 0; offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); @@ -1706,7 +1767,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s if (i != 0) num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - // now start the new one + // now start the new one start_off = !(flags & 1); if (start_off) { // if we start off with an off-curve point, then when we need to find a point on the curve @@ -1748,7 +1809,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s } } num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { + } else if (numberOfContours < 0) { // Compound shapes. int more = 1; stbtt_uint8 *comp = data + g + 10; @@ -1759,7 +1820,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s int comp_num_verts = 0, i; stbtt_vertex *comp_verts = 0, *tmp = 0; float mtx[6] = {1,0,0,1,0,0}, m, n; - + flags = ttSHORT(comp); comp+=2; gidx = ttSHORT(comp); comp+=2; @@ -1789,7 +1850,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; } - + // Find transformation scales. m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); @@ -1802,11 +1863,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)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + 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); x=v->cx; y=v->cy; - 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])); + 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); } // Append vertices. tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); @@ -1815,7 +1876,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) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + if (num_vertices > 0 && vertices) 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; @@ -1825,9 +1886,6 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s // More components ? more = flags & (1<<5); } - } else if (numberOfContours < 0) { - // @TODO other compound variations? - STBTT_assert(0); } else { // numberOfCounters == 0, do nothing } @@ -2081,7 +2139,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]; @@ -2186,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st } break; default: - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) + if (b0 != 255 && b0 != 28 && b0 < 32) return STBTT__CSERR("reserved operator"); // push immediate @@ -2256,7 +2314,49 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde } } -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) { stbtt_uint8 *data = info->data + info->kern; stbtt_uint32 needle, straw; @@ -2286,9 +2386,242 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, return 0; } +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); + + // 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; + } + + 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; + } + } + break; + } + + default: return -1; // unsupported + } + + 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; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // 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; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// 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) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + 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 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 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; + } + } + } else + return 0; + break; + } + + 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 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) { - if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs return 0; return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); } @@ -2341,6 +2674,45 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) STBTT_free(v, info->userdata); } +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + ////////////////////////////////////////////////////////////////////////////// // // antialiasing software rasterizer @@ -2466,7 +2838,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); STBTT_assert(z != NULL); if (!z) return z; - + // round dx down to avoid overshooting if (dxdy < 0) z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); @@ -2544,7 +2916,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac } } } - + e = e->next; } } @@ -2690,6 +3062,23 @@ 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; @@ -2744,13 +3133,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; + height = (sy1 - sy0) * e->direction; STBTT_assert(x >= 0 && x < len); - 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 + 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 } else { int x,x1,x2; - float y_crossing, step, sign, area; + float y_crossing, y_final, step, sign, area; // covers 2+ pixels if (x_top > x_bottom) { // flip scanline vertically; signed area is the same @@ -2763,29 +3152,79 @@ 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 = (x1+1 - x0) * dy + y_top; + 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; sign = e->direction; - // 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); - step = sign * dy; + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // 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 + for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 area += step; } - y_crossing += dy * (x2 - (x1+1)); + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); - STBTT_assert(STBTT_fabs(area) <= 1.01f); - - scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); + // 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); + // 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 { @@ -2793,6 +3232,9 @@ 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: @@ -2899,7 +3341,13 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, if (e->y0 != e->y1) { stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); if (z != NULL) { - STBTT_assert(z->ey >= scan_y_top); + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds // insert at front z->next = active; active = z; @@ -2968,7 +3416,7 @@ static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) { - /* threshhold for transitioning to insertion sort */ + /* threshold for transitioning to insertion sort */ while (n > 12) { stbtt__edge t; int c01,c12,c,m,i,j; @@ -3103,7 +3551,7 @@ static void stbtt__add_point(stbtt__point *points, int n, float x, float y) points[n].y = y; } -// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) { // midpoint @@ -3266,7 +3714,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info { int ix0,iy0,ix1,iy1; stbtt__bitmap gbm; - stbtt_vertex *vertices; + stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); if (scale_x == 0) scale_x = scale_y; @@ -3289,7 +3737,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info if (height) *height = gbm.h; if (xoff ) *xoff = ix0; if (yoff ) *yoff = iy0; - + if (gbm.w && gbm.h) { gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); if (gbm.pixels) { @@ -3300,7 +3748,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info } STBTT_free(vertices, info->userdata); return gbm.pixels; -} +} STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) { @@ -3312,7 +3760,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigne int ix0,iy0; stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; + stbtt__bitmap gbm; stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); gbm.pixels = output; @@ -3334,7 +3782,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char * STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) { @@ -3349,7 +3797,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) { @@ -3474,7 +3922,7 @@ static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *no con->y = 0; con->bottom_y = 0; STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); + STBTT__NOTUSED(num_nodes); } static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) @@ -3528,6 +3976,7 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, in spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; spc->h_oversample = 1; spc->v_oversample = 1; + spc->skip_missing = 0; stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); @@ -3553,6 +4002,11 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h spc->v_oversample = v_oversample; } +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + #define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) @@ -3695,6 +4149,7 @@ static float stbtt__oversample_shift(int oversample) STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { int i,j,k; + int missing_glyph_added = 0; k=0; for (i=0; i < num_ranges; ++i) { @@ -3706,13 +4161,19 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb int x0,y0,x1,y1; int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } ++k; } } @@ -3746,7 +4207,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info // rects array must be big enough to accommodate all characters in the given ranges STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { - int i,j,k, return_value = 1; + int i,j,k, missing_glyph = -1, return_value = 1; // save current values int old_h_over = spc->h_oversample; @@ -3765,7 +4226,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const sub_y = stbtt__oversample_shift(spc->v_oversample); for (j=0; j < ranges[i].num_chars; ++j) { stbrp_rect *r = &rects[k]; - if (r->was_packed) { + if (r->was_packed && r->w != 0 && r->h != 0) { stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; int advance, lsb, x0,y0,x1,y1; int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; @@ -3811,6 +4272,13 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const bc->yoff = (float) y0 * recip_v + sub_y; bc->xoff2 = (x0 + r->w) * recip_h + sub_x; bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; } else { return_value = 0; // if any fail, report failure } @@ -3849,7 +4317,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char n = 0; for (i=0; i < num_ranges; ++i) n += ranges[i].num_chars; - + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); if (rects == NULL) return 0; @@ -3860,7 +4328,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); stbtt_PackFontRangesPackRects(spc, rects, n); - + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); STBTT_free(rects, spc->user_allocator_context); @@ -3879,6 +4347,19 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char * return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); } +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) { float ipw = 1.0f / pw, iph = 1.0f / ph; @@ -3932,7 +4413,7 @@ static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float discr = b*b - a*c; if (discr > 0.0) { float rcpna = -1 / a; - float d = (float) sqrt(discr); + float d = (float) STBTT_sqrt(discr); s0 = (b+d) * rcpna; s1 = (b-d) * rcpna; if (s0 >= 0.0 && s0 <= 1.0) @@ -3990,15 +4471,14 @@ 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) fmod(y, 1.0f); + 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) @@ -4008,7 +4488,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) + if (x_inter < x) winding += (y0 < y1) ? 1 : -1; } } @@ -4034,7 +4514,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex y1 = (int)verts[i ].y; if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) + if (x_inter < x) winding += (y0 < y1) ? 1 : -1; } } else { @@ -4046,7 +4526,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex if (hits[1][0] < 0) winding += (hits[1][1] < 0 ? -1 : 1); } - } + } } } return winding; @@ -4060,35 +4540,35 @@ static float stbtt__cuberoot( float x ) return (float) STBTT_pow( x,1.0f/3.0f); } -// x^3 + c*x^2 + b*x + a = 0 +// x^3 + a*x^2 + b*x + c = 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; } } @@ -4099,12 +4579,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc int w,h; unsigned char *data; - // if one scale is 0, use same scale for both - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) return NULL; // if both scales are 0, return NULL - scale_y = scale_x; - } + if (scale == 0) return NULL; stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); @@ -4127,8 +4602,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc // invert for y-downwards bitmaps 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; @@ -4141,15 +4618,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 == 0) ? 0.0f : 1.0f / dist; + precompute[i] = (dist < eps) ? 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 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); + if (len2 >= eps2) + precompute[i] = 1.0f / len2; else precompute[i] = 0.0f; } else @@ -4170,18 +4647,17 @@ 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; - // 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); - - if (verts[i].type == STBTT_vline) { + 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; + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + // 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) - float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + 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 @@ -4208,14 +4684,15 @@ 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],px,py,t,it; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; 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 (a == 0.0) { // if a is 0, it's linear - if (b != 0.0) { + if (STBTT_fabs(a) < eps2) { // if a is 0, it's linear + if (STBTT_fabs(b) >= eps2) { res[num++] = -c/b; } } else { @@ -4235,6 +4712,10 @@ 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; @@ -4276,7 +4757,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc STBTT_free(verts, info->userdata); } return data; -} +} STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) { @@ -4294,7 +4775,7 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) // // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) { stbtt_int32 i=0; @@ -4333,7 +4814,7 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, s return i; } -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) { return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); } @@ -4462,7 +4943,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) { - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); } STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) @@ -4494,6 +4975,15 @@ 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 // 1.16 (2017-07-12) SDF support // 1.15 (2017-03-03) make more arguments const // 1.14 (2017-01-16) num-fonts-in-TTC function @@ -4552,38 +5042,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/stb_vorbis.c b/raylib/external/stb_vorbis.c index 4b72504..3e5c250 100644 --- a/raylib/external/stb_vorbis.c +++ b/raylib/external/stb_vorbis.c @@ -1,4 +1,421 @@ -#include "stb_vorbis.h" +// Ogg Vorbis audio decoder - v1.22 - public domain +// http://nothings.org/stb_vorbis/ +// +// Original version written by Sean Barrett in 2007. +// +// Originally sponsored by RAD Game Tools. Seeking implementation +// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker, +// Elias Software, Aras Pranckevicius, and Sean Barrett. +// +// LICENSE +// +// See end of file for license information. +// +// Limitations: +// +// - floor 0 not supported (used in old ogg vorbis files pre-2004) +// - lossless sample-truncation at beginning ignored +// - cannot concatenate multiple vorbis streams +// - sample positions are 32-bit, limiting seekable 192Khz +// files to around 6 hours (Ogg supports 64-bit) +// +// Feature contributors: +// Dougall Johnson (sample-exact seeking) +// +// Bugfix/warning contributors: +// Terje Mathisen Niklas Frykholm Andy Hill +// Casey Muratori John Bolton Gargaj +// Laurent Gomila Marc LeBlanc Ronny Chevalier +// Bernhard Wodo Evan Balster github:alxprd +// 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 +// +// 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.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 +// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) +// some crash fixes when out of memory or with corrupt files +// fix some inappropriately signed shifts +// 1.05 - 2015-04-19 - don't define __forceinline if it's redundant +// 1.04 - 2014-08-27 - fix missing const-correct case in API +// 1.03 - 2014-08-07 - warning fixes +// 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows +// 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct) +// 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel; +// (API change) report sample rate for decode-full-file funcs +// +// See end of file for full version history. + + +////////////////////////////////////////////////////////////////////////////// +// +// HEADER BEGINS HERE +// + +#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H +#define STB_VORBIS_INCLUDE_STB_VORBIS_H + +#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) +#define STB_VORBIS_NO_STDIO 1 +#endif + +#ifndef STB_VORBIS_NO_STDIO +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////// THREAD SAFETY + +// Individual stb_vorbis* handles are not thread-safe; you cannot decode from +// them from multiple threads at the same time. However, you can have multiple +// stb_vorbis* handles and decode from them independently in multiple thrads. + + +/////////// MEMORY ALLOCATION + +// normally stb_vorbis uses malloc() to allocate memory at startup, +// and alloca() to allocate temporary memory during a frame on the +// stack. (Memory consumption will depend on the amount of setup +// 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 +// 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 +// do not pass in enough data; there is no way to determine how +// much you do need except to succeed (at which point you can +// query get_info to find the exact amount required. yes I know +// this is lame). +// +// If you pass in a non-NULL buffer of the type below, allocation +// will occur from it as described above. Otherwise just pass NULL +// to use malloc()/alloca() + +typedef struct +{ + char *alloc_buffer; + int alloc_buffer_length_in_bytes; +} stb_vorbis_alloc; + + +/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES + +typedef struct stb_vorbis stb_vorbis; + +typedef struct +{ + unsigned int sample_rate; + int channels; + + unsigned int setup_memory_required; + unsigned int setup_temp_memory_required; + unsigned int temp_memory_required; + + 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); + +// get the last error detected (clears it, too) +extern 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); + +// 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); + +// 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); + +/////////// PUSHDATA API + +#ifndef STB_VORBIS_NO_PUSHDATA_API + +// this API allows you to get blocks of data from any source and hand +// them to stb_vorbis. you have to buffer them; stb_vorbis will tell +// you how much it used, and you have to give it the rest next time; +// and stb_vorbis may not have enough data to work with and you will +// 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( + const unsigned char * datablock, int datablock_length_in_bytes, + int *datablock_memory_consumed_in_bytes, + int *error, + const stb_vorbis_alloc *alloc_buffer); +// create a vorbis decoder by passing in the initial data block containing +// the ogg&vorbis headers (you don't need to do parse them, just provide +// the first N bytes of the file--you're told if it's not enough, see below) +// on success, returns an stb_vorbis *, does not set error, returns the amount of +// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; +// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed +// 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( + stb_vorbis *f, + const unsigned char *datablock, int datablock_length_in_bytes, + 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 + ); +// decode a frame of audio sample data if possible from the passed-in data block +// +// return value: number of bytes we used from datablock +// +// possible cases: +// 0 bytes used, 0 samples output (need more data) +// N bytes used, 0 samples output (resynching the stream, keep going) +// N bytes used, M samples output (one frame of data) +// note that after opening a file, you will ALWAYS get one N-bytes,0-sample +// frame, because Vorbis always "discards" the first frame. +// +// Note that on resynch, stb_vorbis will rarely consume all of the buffer, +// instead only datablock_length_in_bytes-3 or less. This is because it wants +// to avoid missing parts of a page header if they cross a datablock boundary, +// without writing state-machiney code to record a partial detection. +// +// 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 contain an array of float* buffers, one per +// 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); +// 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 +// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it +// will begin decoding the _next_ frame. +// +// if you want to seek using pushdata, you need to seek in your file, then +// call stb_vorbis_flush_pushdata(), then start calling decoding, then once +// decoding is returning you data, call stb_vorbis_get_sample_offset, and +// if you don't like the result, seek your file again and repeat. +#endif + + +////////// PULLING INPUT API + +#ifndef STB_VORBIS_NO_PULLDATA_API +// This API assumes stb_vorbis is allowed to pull data from a source-- +// either a block of memory containing the _entire_ vorbis stream, or a +// FILE * that you or it create, or possibly some other reading mechanism +// if you go modify the source to replace the FILE * case with some kind +// of callback to your code. (But if you don't support seeking, you may +// 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); +#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); +#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, + 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, + 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, + 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 +// 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, + 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. +// 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. +#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); +// 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 +// stb_vorbis_get_samples_* will start with the specified sample. If you +// 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); +// 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); +// these functions return the total length of the vorbis stream + +extern 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 +// contain an array of float* buffers, one per channel. These outputs will +// be overwritten on the next call to stb_vorbis_get_frame_*. +// +// You generally should not intermix calls to stb_vorbis_get_frame_*() +// 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); +#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 +// size of your array), but the return value is the number of samples per +// channel, not the total number of samples. +// +// The data is coerced to the number of channels you request according to the +// channel coercion rules (see below). You must pass in the size of your +// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. +// The maximum buffer size needed can be gotten from get_info(); however, +// the Vorbis I specification implies an absolute maximum of 4096 samples +// per channel. + +// Channel coercion rules: +// Let M be the number of channels requested, and N the number of channels present, +// and Cn be the nth channel; let stereo L be the sum of all L and center channels, +// and stereo R be the sum of all R and center channels (channel assignment from the +// vorbis spec). +// M N output +// 1 k sum(Ck) for all k +// 2 * stereo L, stereo R +// k l k > l, the first l channels, then 0s +// k l k <= l, the first k channels +// 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); +// 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); +#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 +// to produce 'channels' channels. 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. + +#endif + +//////// ERROR CODES + +enum STBVorbisError +{ + VORBIS__no_error, + + VORBIS_need_more_data=1, // not a real error + + VORBIS_invalid_api_mixing, // can't mix API modes + VORBIS_outofmem, // not enough memory + VORBIS_feature_not_supported, // uses floor 0 + VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small + VORBIS_file_open_failure, // fopen() failed + VORBIS_seek_without_length, // can't seek in unknown-length file + + VORBIS_unexpected_eof=10, // file is truncated? + VORBIS_seek_invalid, // seek past EOF + + // decoding errors (corrupt/invalid stream) -- you probably + // don't care about the exact details of these + + // vorbis errors: + VORBIS_invalid_setup=20, + VORBIS_invalid_stream, + + // ogg errors: + VORBIS_missing_capture_pattern=30, + VORBIS_invalid_stream_structure_version, + VORBIS_continued_packet_flag_invalid, + VORBIS_incorrect_stream_serial_number, + VORBIS_invalid_first_page, + VORBIS_bad_packet_type, + VORBIS_cant_find_last_page, + VORBIS_seek_failed, + VORBIS_ogg_skeleton_not_supported +}; + + +#ifdef __cplusplus +} +#endif + +#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H +// +// HEADER ENDS HERE +// +////////////////////////////////////////////////////////////////////////////// #ifndef STB_VORBIS_HEADER_ONLY @@ -171,7 +588,7 @@ #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif - #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) + #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) #include #endif #else // STB_VORBIS_NO_CRT @@ -193,7 +610,9 @@ #undef __forceinline #endif #define __forceinline + #ifndef alloca #define alloca __builtin_alloca + #endif #elif !defined(_MSC_VER) #if __GNUC__ #define __forceinline inline @@ -236,6 +655,12 @@ typedef signed int int32; typedef float codetype; +#ifdef _MSC_VER +#define STBV_NOTUSED(v) (void)(v) +#else +#define STBV_NOTUSED(v) (void)sizeof(v) +#endif + // @NOTE // // Some arrays below are tagged "//varies", which means it's actually @@ -367,6 +792,10 @@ 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; @@ -382,8 +811,11 @@ struct stb_vorbis uint8 push_mode; + // the page to seek to when seeking to start, may be zero 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; // memory management @@ -432,7 +864,7 @@ struct stb_vorbis int current_loc_valid; // per-blocksize precomputed data - + // twiddle factors float *A[2],*B[2],*C[2]; float *window[2]; @@ -496,11 +928,7 @@ static int error(vorb *f, enum STBVorbisError e) #define 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)) -#ifdef dealloca -#define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size)) -#else -#define temp_free(f,p) 0 -#endif +#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)) @@ -521,7 +949,7 @@ static void *make_block_array(void *mem, int count, int size) static void *setup_malloc(vorb *f, int sz) { - sz = (sz+3) & ~3; + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. f->setup_memory_required += sz; if (f->alloc.alloc_buffer) { void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; @@ -540,7 +968,7 @@ static void setup_free(vorb *f, void *p) static void *setup_temp_malloc(vorb *f, int sz) { - sz = (sz+3) & ~3; + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. if (f->alloc.alloc_buffer) { if (f->temp_offset - sz < f->setup_offset) return NULL; f->temp_offset -= sz; @@ -552,7 +980,7 @@ static void *setup_temp_malloc(vorb *f, int sz) static void setup_temp_free(vorb *f, void *p, int sz) { if (f->alloc.alloc_buffer) { - f->temp_offset += (sz+3)&~3; + f->temp_offset += (sz+7)&~7; return; } free(p); @@ -633,7 +1061,7 @@ static float float32_unpack(uint32 x) uint32 sign = x & 0x80000000; uint32 exp = (x & 0x7fe00000) >> 21; double res = sign ? -(double)mantissa : (double)mantissa; - return (float) ldexp((float)res, exp-788); + return (float) ldexp((float)res, (int)exp-788); } @@ -664,6 +1092,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) // 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); // add all available leaves @@ -677,6 +1106,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) 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 @@ -686,12 +1116,10 @@ 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); - // propogate availability up the tree + // propagate 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)); @@ -758,7 +1186,7 @@ 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])) + if (include_in_sort(c, lengths[i])) c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); assert(k == c->sorted_entries); } else { @@ -815,8 +1243,10 @@ static int 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 - assert(pow((float) r+1, dim) > entries); - assert((int) floor(pow((float) r, dim)) <= entries); // (int),floor() as above + if (pow((float) r+1, dim) <= entries) + return -1; + if ((int) floor(pow((float) r, dim)) > entries) + return -1; return r; } @@ -939,7 +1369,7 @@ static int getn(vorb *z, uint8 *data, int n) return 1; } - #ifndef STB_VORBIS_NO_STDIO + #ifndef STB_VORBIS_NO_STDIO if (fread(data, n, 1, z->f) == 1) return 1; else { @@ -1014,12 +1444,15 @@ static int capture_pattern(vorb *f) static int start_page_no_capturepattern(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; + } // stream structure version if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); // header flag f->page_flag = get8(f); // absolute granule position - loc0 = get32(f); + loc0 = get32(f); loc1 = get32(f); // @TODO: validate loc0,loc1 as valid positions? // stream serial number -- vorbis doesn't interleave, so discard @@ -1050,15 +1483,12 @@ static int start_page_no_capturepattern(vorb *f) } if (f->first_decode) { int i,len; - ProbedPage p; len = 0; for (i=0; i < f->segment_count; ++i) len += f->segments[i]; len += 27 + f->segment_count; - 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->p_first.page_end = f->p_first.page_start + len; + f->p_first.last_decoded_sample = loc0; } f->next_seg = 0; return TRUE; @@ -1149,6 +1579,16 @@ static int get8_packet(vorb *f) return x; } +static int get32_packet(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); @@ -1179,7 +1619,8 @@ static uint32 get_bits(vorb *f, int n) f->valid_bits += 8; } } - if (f->valid_bits < 0) return 0; + + assert(f->valid_bits >= n); z = f->acc & ((1 << n)-1); f->acc >>= n; f->valid_bits -= n; @@ -1504,69 +1945,69 @@ 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] = { - 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 }; @@ -1626,7 +2067,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]); + LINE_OP(output[x], inverse_db_table[y&255]); for (++x; x < x1; ++x) { err += ady; if (err >= adx) { @@ -1634,7 +2075,7 @@ 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]); + LINE_OP(output[x], inverse_db_table[y&255]); } } } @@ -1740,47 +2181,7 @@ static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int ++class_set; #endif } - } else if (ch == 1) { - while (pcount < part_read) { - int z = r->begin + pcount*r->part_size; - int c_inter = 0, p_inter = z; - if (pass == 0) { - Codebook *c = f->codebooks+r->classbook; - int q; - DECODE(q,f,c); - if (q == 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) { - Codebook *book = f->codebooks + b; - if (!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 { + } else if (ch > 2) { while (pcount < part_read) { int z = r->begin + pcount*r->part_size; int c_inter = z % ch, p_inter = z/ch; @@ -1967,11 +2368,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; @@ -1990,7 +2391,7 @@ void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) 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; @@ -2191,34 +2592,33 @@ 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]; - z[-0] = z[-0] + z[-8]; - z[-1] = z[-1] + z[-9]; - z[-8] = k00; - z[-9] = k11 ; + 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[ -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 + k00 = z[ -4] - z[-12]; 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[-14] = (k00+k11) * A2; - z[-15] = (k00-k11) * A2; + z[-12] = k11; + z[-13] = -k00; + z[-14] = (l11-l00) * A2; + z[-15] = (l00+l11) * -A2; iter_54(z); iter_54(z-8); @@ -2253,7 +2653,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 propogates through linearly to the end, where the numbers + // this propagates through linearly to the end, where the numbers // are 1/2 too small, and need to be compensated for. { @@ -2403,7 +2803,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; @@ -2484,7 +2884,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; @@ -2492,7 +2892,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; @@ -2500,7 +2900,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; @@ -2508,7 +2908,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; @@ -2661,7 +3061,6 @@ static float *get_window(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; } @@ -2684,6 +3083,7 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f 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]) @@ -2786,6 +3186,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // WINDOWING + STBV_NOTUSED(left_end); n = f->blocksize[m->blockflag]; map = &f->mapping[m->mapping]; @@ -2983,7 +3384,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, // 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 = -n2; // start of first frame is positioned for discard + f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around) // 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; @@ -3067,6 +3468,7 @@ static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) if (f->previous_length) { int i,j, n = f->previous_length; float *w = get_window(f, n); + if (w == NULL) return 0; for (i=0; i < f->channels; ++i) { for (j=0; j < n; ++j) f->channel_buffers[i][left+j] = @@ -3114,7 +3516,7 @@ static int vorbis_pump_first_frame(stb_vorbis *f) } #ifndef STB_VORBIS_NO_PUSHDATA_API -static int is_whole_packet_present(stb_vorbis *f, int end_page) +static int is_whole_packet_present(stb_vorbis *f) { // 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 @@ -3134,15 +3536,13 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) break; } // either this continues, or it ends it... - if (end_page) - if (s < f->segment_count-1) return 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); first = FALSE; } for (; s == -1;) { - uint8 *q; + uint8 *q; int n; // check that we have the page header ready @@ -3168,8 +3568,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) if (q[s] < 255) break; } - if (end_page) - if (s < n-1) return 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); @@ -3186,6 +3584,7 @@ static int start_decoder(vorb *f) int longest_floorlist=0; // first page, first packet + f->first_decode = TRUE; if (!start_page(f)) return FALSE; // validate page flag @@ -3194,7 +3593,22 @@ static int start_decoder(vorb *f) if (f->page_flag & PAGEFLAG_continued_packet) return 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) 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); + } + // read packet // check packet header if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); @@ -3228,6 +3642,48 @@ static int start_decoder(vorb *f) 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; + do { len = next_segment(f); skip(f, len); @@ -3239,7 +3695,7 @@ static int start_decoder(vorb *f) #ifndef STB_VORBIS_NO_PUSHDATA_API if (IS_PUSH_MODE(f)) { - if (!is_whole_packet_present(f, TRUE)) { + if (!is_whole_packet_present(f)) { // convert error in ogg header to write type if (f->error == VORBIS_invalid_stream) f->error = VORBIS_invalid_setup; @@ -3293,6 +3749,7 @@ static int start_decoder(vorb *f) 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); } memset(lengths + current_entry, current_length, n); current_entry += n; @@ -3396,7 +3853,9 @@ static int start_decoder(vorb *f) c->value_bits = get_bits(f, 4)+1; c->sequence_p = get_bits(f,1); if (c->lookup_type == 1) { - c->lookup_values = lookup1_values(c->entries, c->dimensions); + int values = lookup1_values(c->entries, c->dimensions); + if (values < 0) return error(f, VORBIS_invalid_setup); + c->lookup_values = (uint32) values; } else { c->lookup_values = c->entries * c->dimensions; } @@ -3426,8 +3885,7 @@ static int start_decoder(vorb *f) unsigned int div=1; for (k=0; k < c->dimensions; ++k) { int off = (z / div) % c->lookup_values; - float val = mults[off]; - val = mults[off]*c->delta_value + c->minimum_value + last; + float val = mults[off]*c->delta_value + c->minimum_value + last; c->multiplicands[j*c->dimensions + k] = val; if (c->sequence_p) last = val; @@ -3495,7 +3953,7 @@ static int start_decoder(vorb *f) } else { stbv__floor_ordering p[31*8+2]; Floor1 *g = &f->floor_config[i].floor1; - int max_class = -1; + int max_class = -1; g->partitions = get_bits(f, 5); for (j=0; j < g->partitions; ++j) { g->partition_class_list[j] = get_bits(f, 4); @@ -3510,7 +3968,7 @@ static int start_decoder(vorb *f) if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } for (k=0; k < 1 << g->class_subclasses[j]; ++k) { - g->subclass_books[j][k] = get_bits(f,8)-1; + 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); } } @@ -3532,11 +3990,14 @@ static int start_decoder(vorb *f) 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); for (j=0; j < g->values; ++j) g->sorted_order[j] = (uint8) p[j].id; // precompute the neighbors for (j=2; j < g->values; ++j) { - int low,hi; + int low = 0,hi = 0; neighbors(g->Xlist, j, &low,&hi); g->neighbors[j][0] = low; g->neighbors[j][1] = hi; @@ -3605,7 +4066,7 @@ static int start_decoder(vorb *f) if (f->mapping == NULL) return 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; + 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)); @@ -3618,6 +4079,7 @@ static int start_decoder(vorb *f) 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); 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)); @@ -3671,6 +4133,7 @@ static int start_decoder(vorb *f) 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); + 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); @@ -3719,7 +4182,6 @@ 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); @@ -3728,7 +4190,17 @@ static int start_decoder(vorb *f) return error(f, VORBIS_outofmem); } - f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + // @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; + } return TRUE; } @@ -3736,6 +4208,13 @@ static int start_decoder(vorb *f) static void 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; @@ -3801,7 +4280,7 @@ static void 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 = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; + p->alloc.alloc_buffer_length_in_bytes &= ~7; p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; } p->eof = 0; @@ -3835,6 +4314,15 @@ 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) { int e = f->error; @@ -3976,7 +4464,7 @@ int stb_vorbis_decode_frame_pushdata( f->error = VORBIS__no_error; // check that we have the entire packet in memory - if (!is_whole_packet_present(f, FALSE)) { + if (!is_whole_packet_present(f)) { *samples = 0; return 0; } @@ -4038,6 +4526,7 @@ stb_vorbis *stb_vorbis_open_pushdata( *error = VORBIS_need_more_data; else *error = p.error; + vorbis_deinit(&p); return NULL; } f = vorbis_alloc(&p); @@ -4095,7 +4584,7 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) header[i] = get8(f); if (f->eof) return 0; if (header[4] != 0) goto invalid; - goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); + goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24); for (i=22; i < 26; ++i) header[i] = 0; crc = 0; @@ -4181,7 +4670,7 @@ static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) return 1; } -// rarely used function to seek back to the preceeding page while finding the +// rarely used function to seek back to the preceding page while finding the // start of a packet static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) { @@ -4212,8 +4701,8 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) { ProbedPage left, right, mid; int i, start_seg_with_known_loc, end_pos, page_start; - uint32 delta, stream_length, padding; - double offset, bytes_per_sample; + uint32 delta, stream_length, padding, last_sample_limit; + double offset = 0.0, bytes_per_sample = 0.0; int probe = 0; // find the last page and validate the target sample @@ -4226,9 +4715,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // indicates should be the granule position (give or take one)). padding = ((f->blocksize_1 - f->blocksize_0) >> 2); if (sample_number < padding) - sample_number = 0; + last_sample_limit = 0; else - sample_number -= padding; + last_sample_limit = sample_number - padding; left = f->p_first; while (left.last_decoded_sample == ~0U) { @@ -4241,9 +4730,12 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) assert(right.last_decoded_sample != ~0U); // starting from the start is handled differently - if (sample_number <= left.last_decoded_sample) { - if (stb_vorbis_seek_start(f)) + 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); return 1; + } return 0; } @@ -4260,10 +4752,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // 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 * (sample_number - left.last_decoded_sample); + offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample); } else { // second probe (try to bound the other side) - double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; + double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample; if (error >= 0 && error < 8000) error = 8000; if (error < 0 && error > -8000) error = -8000; offset += error * 2; @@ -4294,14 +4786,16 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) } // if we've just found the last page again then we're in a tricky file, - // 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; + // 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; + } ++probe; } @@ -4417,8 +4911,8 @@ int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) flush_packet(f); } } - // the next frame will start with the sample - assert(f->current_loc == sample_number); + // the next frame should start with the sample + if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed); return 1; } @@ -4494,7 +4988,7 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) // set. whoops! break; } - previous_safe = last_page_loc+1; + //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging last_page_loc = stb_vorbis_get_file_offset(f); } @@ -4588,8 +5082,14 @@ stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, con stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) { - FILE *f = fopen(filename, "rb"); - if (f) + 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) return stb_vorbis_open_file(f, TRUE, error, alloc); if (error) *error = VORBIS_file_open_failure; return NULL; @@ -4599,7 +5099,10 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const st 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 == NULL) return NULL; + if (!data) { + if (error) *error = VORBIS_unexpected_eof; + return NULL; + } vorbis_init(&p, alloc); p.stream = (uint8 *) data; p.stream_end = (uint8 *) data + len; @@ -4652,7 +5155,7 @@ static int8 channel_position[7][6] = #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 check_endianness() #else #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) #define check_endianness() @@ -4674,11 +5177,11 @@ static void copy_samples(short *dest, float *src, int len) static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE; + #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 += BUFFER_SIZE) { + for (o = 0; o < len; o += STB_BUFFER_SIZE) { memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { @@ -4695,16 +5198,17 @@ static void compute_samples(int mask, short *output, int num_c, float **data, in 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) { - #define BUFFER_SIZE 32 - float buffer[BUFFER_SIZE]; - int i,j,o,n = BUFFER_SIZE >> 1; + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE >> 1; // o is the offset in the source data check_endianness(); - for (o = 0; o < len; o += BUFFER_SIZE >> 1) { + for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) { // o2 is the offset in the output data int o2 = o << 1; memset(buffer, 0, sizeof(buffer)); @@ -4734,6 +5238,7 @@ static void compute_stereo_samples(short *output, int num_c, float **data, int d 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) @@ -4754,7 +5259,7 @@ static void convert_samples_short(int buf_c, short **buffer, int b_offset, int d int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) { - float **output; + float **output = NULL; int len = stb_vorbis_get_frame_float(f, NULL, &output); if (len > num_samples) len = num_samples; if (len) @@ -4806,8 +5311,6 @@ int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short 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; @@ -4826,8 +5329,6 @@ int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, in { 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; @@ -4977,22 +5478,28 @@ int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, in #endif // STB_VORBIS_NO_PULLDATA_API /* Version history - 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.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; + 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.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 - 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) + 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 + 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 - 1.04 - 2014/08/27 - fix missing const-correct case in API - 1.03 - 2014/08/07 - Warning fixes - 1.02 - 2014/07/09 - Declare qsort compare function _cdecl on windows - 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float - 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in multichannel + 1.05 - 2015-04-19 - don't define __forceinline if it's redundant + 1.04 - 2014-08-27 - fix missing const-correct case in API + 1.03 - 2014-08-07 - Warning fixes + 1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows + 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float + 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in multichannel (API change) report sample rate for decode-full-file funcs 0.99996 - bracket #include for macintosh compilation by Laurent Gomila 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem @@ -5040,38 +5547,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/stb_vorbis.h b/raylib/external/stb_vorbis.h deleted file mode 100644 index 4a33909..0000000 --- a/raylib/external/stb_vorbis.h +++ /dev/null @@ -1,392 +0,0 @@ -// Ogg Vorbis audio decoder - v1.13b - public domain -// http://nothings.org/stb_vorbis/ -// -// Original version written by Sean Barrett in 2007. -// -// Originally sponsored by RAD Game Tools. Seeking implementation -// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker, -// Elias Software, Aras Pranckevicius, and Sean Barrett. -// -// LICENSE -// -// See end of file for license information. -// -// Limitations: -// -// - floor 0 not supported (used in old ogg vorbis files pre-2004) -// - lossless sample-truncation at beginning ignored -// - cannot concatenate multiple vorbis streams -// - sample positions are 32-bit, limiting seekable 192Khz -// files to around 6 hours (Ogg supports 64-bit) -// -// Feature contributors: -// Dougall Johnson (sample-exact seeking) -// -// Bugfix/warning contributors: -// Terje Mathisen Niklas Frykholm Andy Hill -// Casey Muratori John Bolton Gargaj -// Laurent Gomila Marc LeBlanc Ronny Chevalier -// Bernhard Wodo Evan Balster alxprd@github -// Tom Beaumont Ingo Leitgeb Nicolas Guillemot -// Phillip Bennefall Rohit Thiago Goulart -// manxorist@github saga musix github:infatum -// -// Partial history: -// 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.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 -// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson) -// some crash fixes when out of memory or with corrupt files -// fix some inappropriately signed shifts -// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant -// 1.04 - 2014/08/27 - fix missing const-correct case in API -// 1.03 - 2014/08/07 - warning fixes -// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows -// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct) -// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel; -// (API change) report sample rate for decode-full-file funcs -// -// See end of file for full version history. - - -////////////////////////////////////////////////////////////////////////////// -// -// HEADER BEGINS HERE -// - -#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H -#define STB_VORBIS_INCLUDE_STB_VORBIS_H - -#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) -#define STB_VORBIS_NO_STDIO 1 -#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 - -/////////// THREAD SAFETY - -// Individual stb_vorbis* handles are not thread-safe; you cannot decode from -// them from multiple threads at the same time. However, you can have multiple -// stb_vorbis* handles and decode from them independently in multiple thrads. - - -/////////// MEMORY ALLOCATION - -// normally stb_vorbis uses malloc() to allocate memory at startup, -// and alloca() to allocate temporary memory during a frame on the -// stack. (Memory consumption will depend on the amount of setup -// 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 -// 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 -// do not pass in enough data; there is no way to determine how -// much you do need except to succeed (at which point you can -// query get_info to find the exact amount required. yes I know -// this is lame). -// -// If you pass in a non-NULL buffer of the type below, allocation -// will occur from it as described above. Otherwise just pass NULL -// to use malloc()/alloca() - -typedef struct -{ - char *alloc_buffer; - int alloc_buffer_length_in_bytes; -} stb_vorbis_alloc; - - -/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES - -typedef struct stb_vorbis stb_vorbis; - -typedef struct -{ - unsigned int sample_rate; - int channels; - - unsigned int setup_memory_required; - unsigned int setup_temp_memory_required; - unsigned int temp_memory_required; - - int max_frame_size; -} stb_vorbis_info; - -// get general information about the file -extern 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); - -// close an ogg vorbis file and free all memory in use -extern 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); - -// 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); - -/////////// PUSHDATA API - -#ifndef STB_VORBIS_NO_PUSHDATA_API - -// this API allows you to get blocks of data from any source and hand -// them to stb_vorbis. you have to buffer them; stb_vorbis will tell -// you how much it used, and you have to give it the rest next time; -// and stb_vorbis may not have enough data to work with and you will -// 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( - const unsigned char * datablock, int datablock_length_in_bytes, - int *datablock_memory_consumed_in_bytes, - int *error, - const stb_vorbis_alloc *alloc_buffer); -// create a vorbis decoder by passing in the initial data block containing -// the ogg&vorbis headers (you don't need to do parse them, just provide -// the first N bytes of the file--you're told if it's not enough, see below) -// on success, returns an stb_vorbis *, does not set error, returns the amount of -// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; -// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed -// 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( - stb_vorbis *f, - const unsigned char *datablock, int datablock_length_in_bytes, - 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 - ); -// decode a frame of audio sample data if possible from the passed-in data block -// -// return value: number of bytes we used from datablock -// -// possible cases: -// 0 bytes used, 0 samples output (need more data) -// N bytes used, 0 samples output (resynching the stream, keep going) -// N bytes used, M samples output (one frame of data) -// note that after opening a file, you will ALWAYS get one N-bytes,0-sample -// frame, because Vorbis always "discards" the first frame. -// -// Note that on resynch, stb_vorbis will rarely consume all of the buffer, -// instead only datablock_length_in_bytes-3 or less. This is because it wants -// to avoid missing parts of a page header if they cross a datablock boundary, -// without writing state-machiney code to record a partial detection. -// -// 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 contain an array of float* buffers, one per -// 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. - -extern 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 -// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it -// will begin decoding the _next_ frame. -// -// if you want to seek using pushdata, you need to seek in your file, then -// call stb_vorbis_flush_pushdata(), then start calling decoding, then once -// decoding is returning you data, call stb_vorbis_get_sample_offset, and -// if you don't like the result, seek your file again and repeat. -#endif - - -////////// PULLING INPUT API - -#ifndef STB_VORBIS_NO_PULLDATA_API -// This API assumes stb_vorbis is allowed to pull data from a source-- -// either a block of memory containing the _entire_ vorbis stream, or a -// FILE * that you or it create, or possibly some other reading mechanism -// if you go modify the source to replace the FILE * case with some kind -// of callback to your code. (But if you don't support seeking, you may -// 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); -#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); -#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, - 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, - 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, - 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. 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, - 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. -// 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. -#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); -// 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 -// stb_vorbis_get_samples_* will start with the specified sample. If you -// 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); -// 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); -// these functions return the total length of the vorbis stream - -extern 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 -// contain an array of float* buffers, one per channel. These outputs will -// be overwritten on the next call to stb_vorbis_get_frame_*. -// -// You generally should not intermix calls to stb_vorbis_get_frame_*() -// 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); -#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 -// size of your array), but the return value is the number of samples per -// channel, not the total number of samples. -// -// The data is coerced to the number of channels you request according to the -// channel coercion rules (see below). You must pass in the size of your -// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. -// The maximum buffer size needed can be gotten from get_info(); however, -// the Vorbis I specification implies an absolute maximum of 4096 samples -// per channel. - -// Channel coercion rules: -// Let M be the number of channels requested, and N the number of channels present, -// and Cn be the nth channel; let stereo L be the sum of all L and center channels, -// and stereo R be the sum of all R and center channels (channel assignment from the -// vorbis spec). -// M N output -// 1 k sum(Ck) for all k -// 2 * stereo L, stereo R -// k l k > l, the first l channels, then 0s -// k l k <= l, the first k channels -// 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); -// 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); -#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 -// to produce 'channels' channels. 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. - -#endif - -//////// ERROR CODES - -enum STBVorbisError -{ - VORBIS__no_error, - - VORBIS_need_more_data=1, // not a real error - - VORBIS_invalid_api_mixing, // can't mix API modes - VORBIS_outofmem, // not enough memory - VORBIS_feature_not_supported, // uses floor 0 - VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small - VORBIS_file_open_failure, // fopen() failed - VORBIS_seek_without_length, // can't seek in unknown-length file - - VORBIS_unexpected_eof=10, // file is truncated? - VORBIS_seek_invalid, // seek past EOF - - // decoding errors (corrupt/invalid stream) -- you probably - // don't care about the exact details of these - - // vorbis errors: - VORBIS_invalid_setup=20, - VORBIS_invalid_stream, - - // ogg errors: - VORBIS_missing_capture_pattern=30, - VORBIS_invalid_stream_structure_version, - VORBIS_continued_packet_flag_invalid, - VORBIS_incorrect_stream_serial_number, - VORBIS_invalid_first_page, - VORBIS_bad_packet_type, - VORBIS_cant_find_last_page, - VORBIS_seek_failed -}; - - -#ifdef __cplusplus -} -#endif - -#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H -// -// HEADER ENDS HERE -// -////////////////////////////////////////////////////////////////////////////// diff --git a/raylib/external/tinyobj_loader_c.h b/raylib/external/tinyobj_loader_c.h new file mode 100644 index 0000000..55d595a --- /dev/null +++ b/raylib/external/tinyobj_loader_c.h @@ -0,0 +1,1594 @@ +/* + The MIT License (MIT) + + Copyright (c) 2016 - 2019 Syoyo Fujita and many contributors. + + 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. + */ +#ifndef TINOBJ_LOADER_C_H_ +#define TINOBJ_LOADER_C_H_ + +/* @todo { Remove stddef dependency. unsigned int? } ---> RAY: DONE. */ +//#include + +typedef struct { + char *name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + float ior; /* index of refraction */ + float dissolve; /* 1 == opaque; 0 == fully transparent */ + /* illumination model (see http://www.fileformat.info/format/material/) */ + int illum; + + int pad0; + + char *ambient_texname; /* map_Ka */ + char *diffuse_texname; /* map_Kd */ + char *specular_texname; /* map_Ks */ + char *specular_highlight_texname; /* map_Ns */ + char *bump_texname; /* map_bump, bump */ + char *displacement_texname; /* disp */ + char *alpha_texname; /* map_d */ +} tinyobj_material_t; + +typedef struct { + char *name; /* group name or object name. */ + unsigned int face_offset; + unsigned int length; +} tinyobj_shape_t; + +typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; + +typedef struct { + unsigned int num_vertices; + unsigned int num_normals; + unsigned int num_texcoords; + unsigned int num_faces; + unsigned int num_face_num_verts; + + int pad0; + + float *vertices; + float *normals; + float *texcoords; + tinyobj_vertex_index_t *faces; + int *face_num_verts; + int *material_ids; +} tinyobj_attrib_t; + + +#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) + +#define TINYOBJ_INVALID_INDEX (0x80000000) + +#define TINYOBJ_SUCCESS (0) +#define TINYOBJ_ERROR_EMPTY (-1) +#define TINYOBJ_ERROR_INVALID_PARAMETER (-2) +#define TINYOBJ_ERROR_FILE_OPERATION (-3) + +/* Parse wavefront .obj(.obj string data is expanded to linear char array `buf') + * flags are combination of TINYOBJ_FLAG_*** + * Returns TINYOBJ_SUCCESS if things goes well. + * Returns TINYOBJ_ERR_*** when there is an error. + */ +extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + unsigned int *num_shapes, tinyobj_material_t **materials, + unsigned int *num_materials, const char *buf, unsigned int len, + unsigned int flags); +extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, + unsigned int *num_materials_out, + const char *filename); + +extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); +extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); +extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes); +extern void tinyobj_materials_free(tinyobj_material_t *materials, + unsigned int num_materials); + +#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION +#include +#include +#include +#include + +#if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE) +/* ok */ +#elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE) +/* ok */ +#else +#error "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE." +#endif + +#ifndef TINYOBJ_MALLOC +#include +#define TINYOBJ_MALLOC malloc +#define TINYOBJ_REALLOC realloc +#define TINYOBJ_CALLOC calloc +#define TINYOBJ_FREE free +#endif + +#define TINYOBJ_MAX_FACES_PER_F_LINE (16) + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +static void skip_space(const char **token) { + while ((*token)[0] == ' ' || (*token)[0] == '\t') { + (*token)++; + } +} + +static void skip_space_and_cr(const char **token) { + while ((*token)[0] == ' ' || (*token)[0] == '\t' || (*token)[0] == '\r') { + (*token)++; + } +} + +static int until_space(const char *token) { + const char *p = token; + while (p[0] != '\0' && p[0] != ' ' && p[0] != '\t' && p[0] != '\r') { + p++; + } + + return (int)(p - token); +} + +static unsigned int length_until_newline(const char *token, unsigned int n) { + unsigned int len = 0; + + /* Assume token[n-1] = '\0' */ + for (len = 0; len < n - 1; len++) { + if (token[len] == '\n') { + break; + } + if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) { + break; + } + } + + return len; +} + +static unsigned int length_until_line_feed(const char *token, unsigned int n) { + unsigned int len = 0; + + /* Assume token[n-1] = '\0' */ + for (len = 0; len < n; len++) { + if ((token[len] == '\n') || (token[len] == '\r')) { + break; + } + } + + return len; +} + +/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work +*/ +static int my_atoi(const char *c) { + int value = 0; + int sign = 1; + if (*c == '+' || *c == '-') { + if (*c == '-') sign = -1; + c++; + } + while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ + value *= 10; + value += (int)(*c - '0'); + c++; + } + return value * sign; +} + +/* Make index zero-base, and also support relative index. */ +static int fixIndex(int idx, unsigned int n) { + if (idx > 0) return idx - 1; + if (idx == 0) return 0; + return (int)n + idx; /* negative value = relative */ +} + +/* Parse raw triples: i, i/j/k, i//k, i/j */ +static tinyobj_vertex_index_t parseRawTriple(const char **token) { + tinyobj_vertex_index_t vi; + /* 0x80000000 = -2147483648 = invalid */ + vi.v_idx = (int)(0x80000000); + vi.vn_idx = (int)(0x80000000); + vi.vt_idx = (int)(0x80000000); + + vi.v_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + /* i//k */ + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + return vi; + } + + /* i/j/k or i/j */ + vi.vt_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + if ((*token)[0] != '/') { + return vi; + } + + /* i/j/k */ + (*token)++; /* skip '/' */ + vi.vn_idx = my_atoi((*token)); + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') { + (*token)++; + } + return vi; +} + +static int parseInt(const char **token) { + int i = 0; + skip_space(token); + i = my_atoi((*token)); + (*token) += until_space((*token)); + return i; +} + +/* + * Tries to parse a floating point number located at s. + * + * s_end should be a location in the string where reading should absolutely + * stop. For example at the end of the string, to prevent buffer overflows. + * + * Parses the following EBNF grammar: + * sign = "+" | "-" ; + * END = ? anything not in digit ? + * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; + * integer = [sign] , digit , {digit} ; + * decimal = integer , ["." , integer] ; + * float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; + * + * Valid strings are for example: + * -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 + * + * If the parsing is a success, result is set to the parsed value and true + * is returned. + * + * The function is greedy and will parse until any of the following happens: + * - a non-conforming character is encountered. + * - s_end is reached. + * + * The following situations triggers a failure: + * - s >= s_end. + * - parse failure. + */ +static int tryParseDouble(const char *s, const char *s_end, double *result) { + double mantissa = 0.0; + /* This exponent is base 2 rather than 10. + * However the exponent we parse is supposed to be one of ten, + * thus we must take care to convert the exponent/and or the + * mantissa to a * 2^E, where a is the mantissa and E is the + * exponent. + * To get the final double we will use ldexp, it requires the + * exponent to be in base 2. + */ + int exponent = 0; + + /* NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + * TO JUMP OVER DEFINITIONS. + */ + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + /* How many characters were read in a loop. */ + int read = 0; + /* Tells whether a loop terminated due to reaching s_end. */ + int end_not_reached = 0; + + /* + BEGIN PARSING. + */ + + if (s >= s_end) { + return 0; /* fail */ + } + + /* Find out what sign we've got. */ + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + /* Read the integer part. */ + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += (int)(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + /* We must make sure we actually got something. */ + if (read == 0) goto fail; + /* We allow numbers of form "#", "###" etc. */ + if (!end_not_reached) goto assemble; + + /* Read the decimal part. */ + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + /* pow(10.0, -read) */ + double frac_value = 1.0; + int f; + for (f = 0; f < read; f++) { + frac_value *= 0.1; + } + mantissa += (int)(*curr - 0x30) * frac_value; + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + /* Read the exponent part. */ + if (*curr == 'e' || *curr == 'E') { + curr++; + /* Figure out if a sign is present and if it is. */ + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + /* Empty E is not allowed. */ + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += (int)(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + if (read == 0) goto fail; + } + +assemble : + + { + double a = 1.0; /* = pow(5.0, exponent); */ + double b = 1.0; /* = 2.0^exponent */ + int i; + for (i = 0; i < exponent; i++) { + a = a * 5.0; + } + + for (i = 0; i < exponent; i++) { + b = b * 2.0; + } + + if (exp_sign == '-') { + a = 1.0 / a; + b = 1.0 / b; + } + + *result = + /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), + exponent); */ + (sign == '+' ? 1 : -1) * (mantissa * a * b); + } + + return 1; +fail: + return 0; +} + +static float parseFloat(const char **token) { + const char *end; + double val = 0.0; + float f = 0.0f; + skip_space(token); + end = (*token) + until_space((*token)); + val = 0.0; + tryParseDouble((*token), end, &val); + f = (float)(val); + (*token) = end; + return f; +} + +static void parseFloat2(float *x, float *y, const char **token) { + (*x) = parseFloat(token); + (*y) = parseFloat(token); +} + +static void parseFloat3(float *x, float *y, float *z, const char **token) { + (*x) = parseFloat(token); + (*y) = parseFloat(token); + (*z) = parseFloat(token); +} + +static unsigned int my_strnlen(const char *s, unsigned int n) { + const char *p = memchr(s, 0, n); + return p ? (unsigned int)(p - s) : n; +} + +static char *my_strdup(const char *s, unsigned int max_length) { + char *d; + unsigned int len; + + if (s == NULL) return NULL; + + /* Do not consider CRLF line ending(#19) */ + len = length_until_line_feed(s, max_length); + /* len = strlen(s); */ + + /* trim line ending and append '\0' */ + d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ + memcpy(d, s, (unsigned int)(len)); + d[len] = '\0'; + + return d; +} + +static char *my_strndup(const char *s, unsigned int len) { + char *d; + unsigned int slen; + + if (s == NULL) return NULL; + if (len == 0) return NULL; + + slen = my_strnlen(s, len); + d = (char *)TINYOBJ_MALLOC(slen + 1); /* + '\0' */ + if (!d) { + return NULL; + } + memcpy(d, s, slen); + d[slen] = '\0'; + + return d; +} + +char *dynamic_fgets(char **buf, unsigned int *size, FILE *file) { + char *offset; + char *ret; + unsigned int old_size; + + if (!(ret = fgets(*buf, (int)*size, file))) { + return ret; + } + + if (NULL != strchr(*buf, '\n')) { + return ret; + } + + do { + old_size = *size; + *size *= 2; + *buf = (char*)TINYOBJ_REALLOC(*buf, *size); + offset = &((*buf)[old_size - 1]); + + ret = fgets(offset, (int)(old_size + 1), file); + } while(ret && (NULL == strchr(*buf, '\n'))); + + return ret; +} + +static void initMaterial(tinyobj_material_t *material) { + int i; + material->name = NULL; + material->ambient_texname = NULL; + material->diffuse_texname = NULL; + material->specular_texname = NULL; + material->specular_highlight_texname = NULL; + material->bump_texname = NULL; + material->displacement_texname = NULL; + material->alpha_texname = NULL; + for (i = 0; i < 3; i++) { + material->ambient[i] = 0.f; + material->diffuse[i] = 0.f; + material->specular[i] = 0.f; + material->transmittance[i] = 0.f; + material->emission[i] = 0.f; + } + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; +} + +/* Implementation of string to int hashtable */ + +#define HASH_TABLE_ERROR 1 +#define HASH_TABLE_SUCCESS 0 + +#define HASH_TABLE_DEFAULT_SIZE 10 + +typedef struct hash_table_entry_t +{ + unsigned long hash; + int filled; + int pad0; + long value; + + struct hash_table_entry_t* next; +} hash_table_entry_t; + +typedef struct +{ + unsigned long* hashes; + hash_table_entry_t* entries; + unsigned int capacity; + unsigned int n; +} hash_table_t; + +static unsigned long hash_djb2(const unsigned char* str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) { + hash = ((hash << 5) + hash) + (unsigned long)(c); + } + + return hash; +} + +static void create_hash_table(unsigned int start_capacity, hash_table_t* hash_table) +{ + if (start_capacity < 1) + start_capacity = HASH_TABLE_DEFAULT_SIZE; + hash_table->hashes = (unsigned long*) TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long)); + hash_table->entries = (hash_table_entry_t*) TINYOBJ_CALLOC(start_capacity, sizeof(hash_table_entry_t)); + hash_table->capacity = start_capacity; + hash_table->n = 0; +} + +static void destroy_hash_table(hash_table_t* hash_table) +{ + TINYOBJ_FREE(hash_table->entries); + TINYOBJ_FREE(hash_table->hashes); +} + +/* Insert with quadratic probing */ +static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table) +{ + /* Insert value */ + unsigned int start_index = hash % hash_table->capacity; + unsigned int index = start_index; + hash_table_entry_t* start_entry = hash_table->entries + start_index; + unsigned int i; + hash_table_entry_t* entry; + + for (i = 1; hash_table->entries[index].filled; i++) + { + if (i >= hash_table->capacity) + return HASH_TABLE_ERROR; + index = (start_index + (i * i)) % hash_table->capacity; + } + + entry = hash_table->entries + index; + entry->hash = hash; + entry->filled = 1; + entry->value = value; + + if (index != start_index) { + /* This is a new entry, but not the start entry, hence we need to add a next pointer to our entry */ + entry->next = start_entry->next; + start_entry->next = entry; + } + + return HASH_TABLE_SUCCESS; +} + +static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table) +{ + int ret = hash_table_insert_value(hash, value, hash_table); + if (ret == HASH_TABLE_SUCCESS) + { + hash_table->hashes[hash_table->n] = hash; + hash_table->n++; + } + return ret; +} + +static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table) +{ + hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity); + while (entry) + { + if (entry->hash == hash && entry->filled) + { + return entry; + } + entry = entry->next; + } + return NULL; +} + +static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table) +{ + unsigned int new_capacity; + hash_table_t new_hash_table; + unsigned int i; + + if (new_n <= hash_table->capacity) { + return; + } + new_capacity = 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n); + /* Create a new hash table. We're not calling create_hash_table because we want to realloc the hash array */ + new_hash_table.hashes = hash_table->hashes = (unsigned long*) TINYOBJ_REALLOC((void*) hash_table->hashes, sizeof(unsigned long) * new_capacity); + new_hash_table.entries = (hash_table_entry_t*) TINYOBJ_CALLOC(new_capacity, sizeof(hash_table_entry_t)); + new_hash_table.capacity = new_capacity; + new_hash_table.n = hash_table->n; + + /* Rehash */ + for (i = 0; i < hash_table->capacity; i++) + { + hash_table_entry_t* entry = hash_table_find(hash_table->hashes[i], hash_table); + hash_table_insert_value(hash_table->hashes[i], entry->value, &new_hash_table); + } + + TINYOBJ_FREE(hash_table->entries); + (*hash_table) = new_hash_table; +} + +static int hash_table_exists(const char* name, hash_table_t* hash_table) +{ + return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL; +} + +static void hash_table_set(const char* name, unsigned int val, hash_table_t* hash_table) +{ + /* Hash name */ + unsigned long hash = hash_djb2((const unsigned char *)name); + + hash_table_entry_t* entry = hash_table_find(hash, hash_table); + if (entry) + { + entry->value = (long)val; + return; + } + + /* Expand if necessary + * Grow until the element has been added + */ + do + { + hash_table_maybe_grow(hash_table->n + 1, hash_table); + } + while (hash_table_insert(hash, (long)val, hash_table) != HASH_TABLE_SUCCESS); +} + +static long hash_table_get(const char* name, hash_table_t* hash_table) +{ + hash_table_entry_t* ret = hash_table_find(hash_djb2((const unsigned char*)(name)), hash_table); + return ret->value; +} + +static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, + unsigned int num_materials, + tinyobj_material_t *new_mat) { + tinyobj_material_t *dst; + dst = (tinyobj_material_t *)TINYOBJ_REALLOC( + prev, sizeof(tinyobj_material_t) * (num_materials + 1)); + + dst[num_materials] = (*new_mat); /* Just copy pointer for char* members */ + return dst; +} + +static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, + unsigned int *num_materials_out, + const char *filename, + hash_table_t* material_table) { + tinyobj_material_t material; + unsigned int buffer_size = 128; + char *linebuf; + FILE *fp; + unsigned int num_materials = 0; + tinyobj_material_t *materials = NULL; + int has_previous_material = 0; + const char *line_end = NULL; + + if (materials_out == NULL) { + return TINYOBJ_ERROR_INVALID_PARAMETER; + } + + if (num_materials_out == NULL) { + return TINYOBJ_ERROR_INVALID_PARAMETER; + } + + (*materials_out) = NULL; + (*num_materials_out) = 0; + + fp = fopen(filename, "rt"); + if (!fp) { + fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); + return TINYOBJ_ERROR_FILE_OPERATION; + } + + /* Create a default material */ + initMaterial(&material); + + linebuf = (char*)TINYOBJ_MALLOC(buffer_size); + while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) { + const char *token = linebuf; + + line_end = token + strlen(token); + + /* Skip leading space. */ + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; /* empty line */ + + if (token[0] == '#') continue; /* comment line */ + + /* new mtl */ + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[4096]; + + /* flush previous material. */ + if (has_previous_material) { + materials = tinyobj_material_add(materials, num_materials, &material); + num_materials++; + } else { + has_previous_material = 1; + } + + /* initial temporary material */ + initMaterial(&material); + + /* set new mtl name */ + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material.name = my_strdup(namebuf, (unsigned int) (line_end - token)); + + /* Add material to material table */ + if (material_table) + hash_table_set(material.name, num_materials, material_table); + + continue; + } + + /* ambient */ + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + /* diffuse */ + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + /* specular */ + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + /* transmittance */ + if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + /* ior(index of refraction) */ + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseFloat(&token); + continue; + } + + /* emission */ + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + float r, g, b; + token += 2; + parseFloat3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + /* shininess */ + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseFloat(&token); + continue; + } + + /* illum model */ + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + /* dissolve */ + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseFloat(&token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + /* Invert value of Tr(assume Tr is in range [0, 1]) */ + material.dissolve = 1.0f - parseFloat(&token); + continue; + } + + /* ambient texture */ + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + material.ambient_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* diffuse texture */ + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + material.diffuse_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* specular texture */ + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + material.specular_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* specular highlight texture */ + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + material.specular_highlight_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* bump texture */ + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + material.bump_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* alpha texture */ + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* bump texture */ + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + material.bump_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* displacement texture */ + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + material.displacement_texname = my_strdup(token, (unsigned int) (line_end - token)); + continue; + } + + /* @todo { unknown parameter } */ + } + + fclose(fp); + + if (material.name) { + /* Flush last material element */ + materials = tinyobj_material_add(materials, num_materials, &material); + num_materials++; + } + + (*num_materials_out) = num_materials; + (*materials_out) = materials; + + if (linebuf) { + TINYOBJ_FREE(linebuf); + } + + return TINYOBJ_SUCCESS; +} + +int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, + unsigned int *num_materials_out, + const char *filename) { + return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL); +} + + +typedef enum { + COMMAND_EMPTY, + COMMAND_V, + COMMAND_VN, + COMMAND_VT, + COMMAND_F, + COMMAND_G, + COMMAND_O, + COMMAND_USEMTL, + COMMAND_MTLLIB + +} CommandType; + +typedef struct { + float vx, vy, vz; + float nx, ny, nz; + float tx, ty; + + /* @todo { Use dynamic array } */ + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + unsigned int num_f; + + int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; + unsigned int num_f_num_verts; + + const char *group_name; + unsigned int group_name_len; + int pad0; + + const char *object_name; + unsigned int object_name_len; + int pad1; + + const char *material_name; + unsigned int material_name_len; + int pad2; + + const char *mtllib_name; + unsigned int mtllib_name_len; + + CommandType type; +} Command; + +static int parseLine(Command *command, const char *p, unsigned int p_len, + int triangulate) { + char linebuf[4096]; + const char *token; + assert(p_len < 4095); + + memcpy(linebuf, p, p_len); + linebuf[p_len] = '\0'; + + token = linebuf; + + command->type = COMMAND_EMPTY; + + /* Skip leading space. */ + skip_space(&token); + + assert(token); + if (token[0] == '\0') { /* empty line */ + return 0; + } + + if (token[0] == '#') { /* comment line */ + return 0; + } + + /* vertex */ + if (token[0] == 'v' && IS_SPACE((token[1]))) { + float x, y, z; + token += 2; + parseFloat3(&x, &y, &z, &token); + command->vx = x; + command->vy = y; + command->vz = z; + command->type = COMMAND_V; + return 1; + } + + /* normal */ + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + float x, y, z; + token += 3; + parseFloat3(&x, &y, &z, &token); + command->nx = x; + command->ny = y; + command->nz = z; + command->type = COMMAND_VN; + return 1; + } + + /* texcoord */ + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + float x, y; + token += 3; + parseFloat2(&x, &y, &token); + command->tx = x; + command->ty = y; + command->type = COMMAND_VT; + return 1; + } + + /* face */ + if (token[0] == 'f' && IS_SPACE((token[1]))) { + unsigned int num_f = 0; + + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + token += 2; + skip_space(&token); + + while (!IS_NEW_LINE(token[0])) { + tinyobj_vertex_index_t vi = parseRawTriple(&token); + skip_space_and_cr(&token); + + f[num_f] = vi; + num_f++; + } + + command->type = COMMAND_F; + + if (triangulate) { + unsigned int k; + unsigned int n = 0; + + tinyobj_vertex_index_t i0 = f[0]; + tinyobj_vertex_index_t i1; + tinyobj_vertex_index_t i2 = f[1]; + + assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + + for (k = 2; k < num_f; k++) { + i1 = i2; + i2 = f[k]; + command->f[3 * n + 0] = i0; + command->f[3 * n + 1] = i1; + command->f[3 * n + 2] = i2; + + command->f_num_verts[n] = 3; + n++; + } + command->num_f = 3 * n; + command->num_f_num_verts = n; + + } else { + unsigned int k = 0; + assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + for (k = 0; k < num_f; k++) { + command->f[k] = f[k]; + } + + command->num_f = num_f; + command->f_num_verts[0] = (int)num_f; + command->num_f_num_verts = 1; + } + + return 1; + } + + /* use mtl */ + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + + skip_space(&token); + command->material_name = p + (token - linebuf); + command->material_name_len = (unsigned int)length_until_newline( + token, (p_len - (unsigned int)(token - linebuf)) + 1); + command->type = COMMAND_USEMTL; + + return 1; + } + + /* load mtl */ + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + /* By specification, `mtllib` should be appear only once in .obj */ + token += 7; + + skip_space(&token); + command->mtllib_name = p + (token - linebuf); + command->mtllib_name_len = (unsigned int)length_until_newline( + token, p_len - (unsigned int)(token - linebuf)) + + 1; + command->type = COMMAND_MTLLIB; + + return 1; + } + + /* group name */ + if (token[0] == 'g' && IS_SPACE((token[1]))) { + /* @todo { multiple group name. } */ + token += 2; + + command->group_name = p + (token - linebuf); + command->group_name_len = (unsigned int)length_until_newline( + token, p_len - (unsigned int)(token - linebuf)) + + 1; + command->type = COMMAND_G; + + return 1; + } + + /* object name */ + if (token[0] == 'o' && IS_SPACE((token[1]))) { + /* @todo { multiple object name? } */ + token += 2; + + command->object_name = p + (token - linebuf); + command->object_name_len = (unsigned int)length_until_newline( + token, p_len - (unsigned int)(token - linebuf)) + + 1; + command->type = COMMAND_O; + + return 1; + } + + return 0; +} + +typedef struct { + unsigned int pos; + unsigned int len; +} LineInfo; + +static int is_line_ending(const char *p, unsigned int i, unsigned int end_i) { + if (p[i] == '\0') return 1; + if (p[i] == '\n') return 1; /* this includes \r\n */ + if (p[i] == '\r') { + if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */ + return 1; + } + } + return 0; +} + +int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + unsigned int *num_shapes, tinyobj_material_t **materials_out, + unsigned int *num_materials_out, const char *buf, unsigned int len, + unsigned int flags) { + LineInfo *line_infos = NULL; + Command *commands = NULL; + unsigned int num_lines = 0; + + unsigned int num_v = 0; + unsigned int num_vn = 0; + unsigned int num_vt = 0; + unsigned int num_f = 0; + unsigned int num_faces = 0; + + int mtllib_line_index = -1; + + tinyobj_material_t *materials = NULL; + unsigned int num_materials = 0; + + hash_table_t material_table; + + if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + + tinyobj_attrib_init(attrib); + /* 1. Find '\n' and create line data. */ + { + unsigned int i; + unsigned int end_idx = len; + unsigned int prev_pos = 0; + unsigned int line_no = 0; + unsigned int last_line_ending = 0; + + /* Count # of lines. */ + for (i = 0; i < end_idx; i++) { + if (is_line_ending(buf, i, end_idx)) { + num_lines++; + last_line_ending = i; + } + } + /* The last char from the input may not be a line + * ending character so add an extra line if there + * are more characters after the last line ending + * that was found. */ + if (end_idx - last_line_ending > 0) { + num_lines++; + } + + if (num_lines == 0) return TINYOBJ_ERROR_EMPTY; + + line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines); + + /* Fill line infos. */ + for (i = 0; i < end_idx; i++) { + 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++; + } + } + if (end_idx - last_line_ending > 0) { + line_infos[line_no].pos = prev_pos; + line_infos[line_no].len = end_idx - 1 - last_line_ending; + } + } + + commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); + + create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table); + + /* 2. parse each line */ + { + unsigned int i = 0; + for (i = 0; i < num_lines; i++) { + int ret = parseLine(&commands[i], &buf[line_infos[i].pos], + line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); + if (ret) { + if (commands[i].type == COMMAND_V) { + num_v++; + } else if (commands[i].type == COMMAND_VN) { + num_vn++; + } else if (commands[i].type == COMMAND_VT) { + num_vt++; + } else if (commands[i].type == COMMAND_F) { + num_f += commands[i].num_f; + num_faces += commands[i].num_f_num_verts; + } + + if (commands[i].type == COMMAND_MTLLIB) { + mtllib_line_index = (int)i; + } + } + } + } + + /* line_infos are not used anymore. Release memory. */ + if (line_infos) { + TINYOBJ_FREE(line_infos); + } + + /* Load material(if exits) */ + if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name && + commands[mtllib_line_index].mtllib_name_len > 0) { + char *filename = my_strndup(commands[mtllib_line_index].mtllib_name, + commands[mtllib_line_index].mtllib_name_len); + + int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table); + + if (ret != TINYOBJ_SUCCESS) { + /* warning. */ + fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret); + } + + TINYOBJ_FREE(filename); + + } + + /* Construct attributes */ + + { + unsigned int v_count = 0; + unsigned int n_count = 0; + unsigned int t_count = 0; + unsigned int f_count = 0; + unsigned int face_count = 0; + int material_id = -1; /* -1 = default unknown material. */ + unsigned int i = 0; + + attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3); + attrib->num_vertices = (unsigned int)num_v; + attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3); + attrib->num_normals = (unsigned int)num_vn; + attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2); + attrib->num_texcoords = (unsigned int)num_vt; + attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f); + attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); + + attrib->num_faces = (unsigned int)num_faces; + attrib->num_face_num_verts = (unsigned int)num_f; + + attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); + + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_EMPTY) { + continue; + } else if (commands[i].type == COMMAND_USEMTL) { + /* @todo + if (commands[t][i].material_name && + commands[t][i].material_name_len > 0) { + std::string material_name(commands[t][i].material_name, + commands[t][i].material_name_len); + + if (material_map.find(material_name) != material_map.end()) { + material_id = material_map[material_name]; + } else { + // Assign invalid material ID + material_id = -1; + } + } + */ + if (commands[i].material_name && + commands[i].material_name_len >0) + { + /* Create a null terminated string */ + char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1); + memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len); + material_name_null_term[commands[i].material_name_len] = 0; + + if (hash_table_exists(material_name_null_term, &material_table)) + material_id = (int)hash_table_get(material_name_null_term, &material_table); + else + material_id = -1; + + TINYOBJ_FREE(material_name_null_term); + } + } else if (commands[i].type == COMMAND_V) { + attrib->vertices[3 * v_count + 0] = commands[i].vx; + attrib->vertices[3 * v_count + 1] = commands[i].vy; + attrib->vertices[3 * v_count + 2] = commands[i].vz; + v_count++; + } else if (commands[i].type == COMMAND_VN) { + attrib->normals[3 * n_count + 0] = commands[i].nx; + attrib->normals[3 * n_count + 1] = commands[i].ny; + attrib->normals[3 * n_count + 2] = commands[i].nz; + n_count++; + } else if (commands[i].type == COMMAND_VT) { + attrib->texcoords[2 * t_count + 0] = commands[i].tx; + attrib->texcoords[2 * t_count + 1] = commands[i].ty; + t_count++; + } else if (commands[i].type == COMMAND_F) { + unsigned int k = 0; + for (k = 0; k < commands[i].num_f; k++) { + tinyobj_vertex_index_t vi = commands[i].f[k]; + int v_idx = fixIndex(vi.v_idx, v_count); + int vn_idx = fixIndex(vi.vn_idx, n_count); + int vt_idx = fixIndex(vi.vt_idx, t_count); + attrib->faces[f_count + k].v_idx = v_idx; + attrib->faces[f_count + k].vn_idx = vn_idx; + attrib->faces[f_count + k].vt_idx = vt_idx; + } + + for (k = 0; k < commands[i].num_f_num_verts; k++) { + attrib->material_ids[face_count + k] = material_id; + attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k]; + } + + f_count += commands[i].num_f; + face_count += commands[i].num_f_num_verts; + } + } + } + + /* 5. Construct shape information. */ + { + unsigned int face_count = 0; + unsigned int i = 0; + unsigned int n = 0; + unsigned int shape_idx = 0; + + const char *shape_name = NULL; + unsigned int shape_name_len = 0; + const char *prev_shape_name = NULL; + unsigned int prev_shape_name_len = 0; + unsigned int prev_shape_face_offset = 0; + unsigned int prev_face_offset = 0; + tinyobj_shape_t prev_shape = {NULL, 0, 0}; + + /* Find the number of shapes in .obj */ + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + n++; + } + } + + /* Allocate array of shapes with maximum possible size(+1 for unnamed + * group/object). + * Actual # of shapes found in .obj is determined in the later */ + (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1)); + + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + if (commands[i].type == COMMAND_O) { + shape_name = commands[i].object_name; + shape_name_len = commands[i].object_name_len; + } else { + shape_name = commands[i].group_name; + shape_name_len = commands[i].group_name_len; + } + + if (face_count == 0) { + /* 'o' or 'g' appears before any 'f' */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + prev_face_offset = face_count; + } else { + if (shape_idx == 0) { + /* 'o' or 'g' after some 'v' lines. */ + (*shapes)[shape_idx].name = my_strndup( + prev_shape_name, prev_shape_name_len); /* may be NULL */ + (*shapes)[shape_idx].face_offset = prev_shape.face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + + prev_face_offset = face_count; + + } else { + if ((face_count - prev_face_offset) > 0) { + (*shapes)[shape_idx].name = + my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + prev_face_offset = face_count; + } + } + + /* Record shape info for succeeding 'o' or 'g' command. */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + } + } + if (commands[i].type == COMMAND_F) { + face_count++; + } + } + + if ((face_count - prev_face_offset) > 0) { + unsigned int length = face_count - prev_shape_face_offset; + if (length > 0) { + (*shapes)[shape_idx].name = + my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + } + } else { + /* Guess no 'v' line occurrence after 'o' or 'g', so discards current + * shape information. */ + } + + (*num_shapes) = shape_idx; + } + + if (commands) { + TINYOBJ_FREE(commands); + } + + destroy_hash_table(&material_table); + + (*materials_out) = materials; + (*num_materials_out) = num_materials; + + return TINYOBJ_SUCCESS; +} + +void tinyobj_attrib_init(tinyobj_attrib_t *attrib) { + attrib->vertices = NULL; + attrib->num_vertices = 0; + attrib->normals = NULL; + attrib->num_normals = 0; + attrib->texcoords = NULL; + attrib->num_texcoords = 0; + attrib->faces = NULL; + attrib->num_faces = 0; + attrib->face_num_verts = NULL; + attrib->num_face_num_verts = 0; + attrib->material_ids = NULL; +} + +void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { + if (attrib->vertices) TINYOBJ_FREE(attrib->vertices); + if (attrib->normals) TINYOBJ_FREE(attrib->normals); + if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords); + if (attrib->faces) TINYOBJ_FREE(attrib->faces); + if (attrib->face_num_verts) TINYOBJ_FREE(attrib->face_num_verts); + if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids); +} + +void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes) { + unsigned int i; + if (shapes == NULL) return; + + for (i = 0; i < num_shapes; i++) { + if (shapes[i].name) TINYOBJ_FREE(shapes[i].name); + } + + TINYOBJ_FREE(shapes); +} + +void tinyobj_materials_free(tinyobj_material_t *materials, + unsigned int num_materials) { + unsigned int i; + if (materials == NULL) return; + + for (i = 0; i < num_materials; i++) { + if (materials[i].name) TINYOBJ_FREE(materials[i].name); + if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname); + if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname); + if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname); + if (materials[i].specular_highlight_texname) + TINYOBJ_FREE(materials[i].specular_highlight_texname); + if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname); + if (materials[i].displacement_texname) + TINYOBJ_FREE(materials[i].displacement_texname); + if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname); + } + + TINYOBJ_FREE(materials); +} +#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ + +#endif /* TINOBJ_LOADER_C_H_ */ diff --git a/raylib/external/vendor.go b/raylib/external/vendor.go new file mode 100644 index 0000000..0fb2a0f --- /dev/null +++ b/raylib/external/vendor.go @@ -0,0 +1,4 @@ +//go:build required +// +build required + +package vendor diff --git a/raylib/external/vox_loader.h b/raylib/external/vox_loader.h new file mode 100644 index 0000000..0d328c0 --- /dev/null +++ b/raylib/external/vox_loader.h @@ -0,0 +1,727 @@ +/* + 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 new file mode 100644 index 0000000..8328564 --- /dev/null +++ b/raylib/external/win32_clipboard.h @@ -0,0 +1,374 @@ +#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/gestures.h b/raylib/gestures.h deleted file mode 100644 index a4546eb..0000000 --- a/raylib/gestures.h +++ /dev/null @@ -1,559 +0,0 @@ -/********************************************************************************************** -* -* 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 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) -* Albert Martos: Complete redesign and testing (2015) -* Ian Eito: Complete redesign and testing (2015) -* Ramon Santamaria: Supervision, review, update and maintenance -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2018 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 GESTURES_H -#define GESTURES_H - -#ifndef PI - #define PI 3.14159265358979323846 -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for GESTURES_STANDALONE usage -//---------------------------------------------------------------------------------- -#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 - -typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; - -// Gesture events -// NOTE: MAX_TOUCH_POINTS fixed to 4 -typedef struct { - int touchAction; - int pointCount; - int pointerId[4]; - Vector2 position[4]; -} GestureEvent; - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -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(GESTURES_STANDALONE) -void SetGesturesEnabled(unsigned int gestureFlags); // 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 -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 - -#ifdef __cplusplus -} -#endif - -#endif // GESTURES_H - -/*********************************************************************************** -* -* GESTURES IMPLEMENTATION -* -************************************************************************************/ - -#if defined(GESTURES_IMPLEMENTATION) - -#if defined(_WIN32) - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); -#elif defined(__linux__) - #if _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 // Required for: timespec - #include // Required for: clock_gettime() - - #include // Required for: atan2(), sqrt() - #include // Required for: uint64_t -#endif - -#if defined(__APPLE__) // macOS also defines __MACH__ - #include // Required for: clock_get_time() - #include // Required for: mach_timespec_t -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time -#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f) -#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f) -#define TAP_TIMEOUT 300 // Time in milliseconds -#define PINCH_TIMEOUT 300 // Time in milliseconds -#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- - -// Touch gesture variables -static Vector2 touchDownPosition = { 0.0f, 0.0f }; -static Vector2 touchDownPosition2 = { 0.0f, 0.0f }; -static Vector2 touchDownDragPosition = { 0.0f, 0.0f }; -static Vector2 touchUpPosition = { 0.0f, 0.0f }; -static Vector2 moveDownPosition = { 0.0f, 0.0f }; -static Vector2 moveDownPosition2 = { 0.0f, 0.0f }; - -static int pointCount = 0; // Touch points counter -static int firstTouchId = -1; // Touch id for first touch point -static double eventTime = 0.0; // Time stamp when an event happened - -// Tap gesture variables -static int tapCounter = 0; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions) - -// Hold gesture variables -static bool resetHold = false; // HOLD reset to get first touch point again -static double timeHold = 0.0f; // HOLD duration in milliseconds - -// Drag gesture variables -static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) -static float dragAngle = 0.0f; // DRAG angle (relative to x-axis) -static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1]) -static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) - -// Swipe gestures variables -static bool startMoving = false; // SWIPE used to define when start measuring swipeTime -static double swipeTime = 0.0; // SWIPE time to calculate drag intensity - -// Pinch gesture variables -static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points) -static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis) -static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1]) - -static int currentGesture = GESTURE_NONE; // Current detected gesture - -// Enabled gestures flags, all gestures enabled by default -static unsigned int enabledGestures = 0b0000001111111111; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#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 getures to be detected -void SetGesturesEnabled(unsigned int gestureFlags) -{ - enabledGestures = gestureFlags; -} - -// Check if a gesture have been detected -bool IsGestureDetected(int gesture) -{ - if ((enabledGestures & currentGesture) == gesture) return true; - else return false; -} - -// Process gesture event and translate it into gestures -void ProcessGestureEvent(GestureEvent event) -{ - // Reset required variables - pointCount = event.pointCount; // Required on UpdateGestures() - - if (pointCount < 2) - { - if (event.touchAction == TOUCH_DOWN) - { - tapCounter++; // Tap counter - - // Detect GESTURE_DOUBLE_TAP - if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) - { - currentGesture = GESTURE_DOUBLETAP; - tapCounter = 0; - } - else // Detect GESTURE_TAP - { - tapCounter = 1; - currentGesture = GESTURE_TAP; - } - - touchDownPosition = event.position[0]; - touchDownDragPosition = event.position[0]; - - touchUpPosition = touchDownPosition; - eventTime = GetCurrentTime(); - - firstTouchId = event.pointerId[0]; - - dragVector = (Vector2){ 0.0f, 0.0f }; - } - else if (event.touchAction == TOUCH_UP) - { - if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; - - // NOTE: dragIntensity dependend on the resolution of the screen - dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); - dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); - - startMoving = false; - - // Detect GESTURE_SWIPE - if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0])) - { - // NOTE: Angle should be inverted in Y - dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition); - - if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right - else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up - else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left - else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down - else currentGesture = GESTURE_NONE; - } - else - { - dragDistance = 0.0f; - dragIntensity = 0.0f; - dragAngle = 0.0f; - - currentGesture = GESTURE_NONE; - } - - touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; - pointCount = 0; - } - else if (event.touchAction == TOUCH_MOVE) - { - if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime(); - - if (!startMoving) - { - swipeTime = GetCurrentTime(); - startMoving = true; - } - - moveDownPosition = event.position[0]; - - if (currentGesture == GESTURE_HOLD) - { - if (resetHold) touchDownPosition = event.position[0]; - - resetHold = false; - - // Detect GESTURE_DRAG - if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) - { - eventTime = GetCurrentTime(); - currentGesture = GESTURE_DRAG; - } - } - - dragVector.x = moveDownPosition.x - touchDownDragPosition.x; - dragVector.y = moveDownPosition.y - touchDownDragPosition.y; - } - } - else // Two touch points - { - if (event.touchAction == TOUCH_DOWN) - { - touchDownPosition = event.position[0]; - touchDownPosition2 = event.position[1]; - - //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); - - pinchVector.x = touchDownPosition2.x - touchDownPosition.x; - pinchVector.y = touchDownPosition2.y - touchDownPosition.y; - - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - else if (event.touchAction == TOUCH_MOVE) - { - pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); - - touchDownPosition = moveDownPosition; - touchDownPosition2 = moveDownPosition2; - - moveDownPosition = event.position[0]; - moveDownPosition2 = event.position[1]; - - pinchVector.x = moveDownPosition2.x - moveDownPosition.x; - pinchVector.y = moveDownPosition2.y - moveDownPosition.y; - - if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH)) - { - if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; - else currentGesture = GESTURE_PINCH_OUT; - } - else - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - - // NOTE: Angle should be inverted in Y - pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2); - } - else if (event.touchAction == TOUCH_UP) - { - pinchDistance = 0.0f; - pinchAngle = 0.0f; - pinchVector = (Vector2){ 0.0f, 0.0f }; - pointCount = 0; - - currentGesture = GESTURE_NONE; - } - } -} - -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events - - // Detect GESTURE_HOLD - if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2)) - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - - if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - resetHold = true; - } - - // Detect GESTURE_NONE - if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) - { - currentGesture = GESTURE_NONE; - } -} - -// Get number of touch points -int GetTouchPointsCount(void) -{ - // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called - - return pointCount; -} - -// Get latest detected gesture -int GetGestureDetected(void) -{ - // Get current gesture only if enabled - return (enabledGestures & currentGesture); -} - -// Hold time measured in ms -float GetGestureHoldDuration(void) -{ - // NOTE: time is calculated on current gesture HOLD - - double time = 0.0; - - if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold; - - return (float)time; -} - -// Get drag vector (between initial touch point to current) -Vector2 GetGestureDragVector(void) -{ - // NOTE: drag vector is calculated on one touch points TOUCH_MOVE - - return dragVector; -} - -// Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGestureDragAngle(void) -{ - // NOTE: drag angle is calculated on one touch points TOUCH_UP - - return dragAngle; -} - -// Get distance between two pinch points -Vector2 GetGesturePinchVector(void) -{ - // NOTE: The position values used for pinchDistance 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 pinchVector; -} - -// 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_MOVE - - return pinchAngle; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -#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); - - if (angle < 0) angle += 360.0f; - - return angle; -} - -// Calculate distance between two Vector2 -static float Vector2Distance(Vector2 v1, Vector2 v2) -{ - float result; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - - result = (float)sqrt(dx*dx + dy*dy); - - return result; -} -#endif - -// Time measure returned are milliseconds -static double GetCurrentTime(void) -{ - double time = 0; - -#if defined(_WIN32) - unsigned long long int clockFrequency, currentTime; - - QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! - QueryPerformanceCounter(¤tTime); - - time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds -#endif - -#if defined(__linux__) - // NOTE: Only for Linux-based systems - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds - - time = ((double)nowTime/1000000.0); // Time in miliseconds -#endif - -#if defined(__APPLE__) - //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 - //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time - - clock_serv_t cclock; - mach_timespec_t now; - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); - - // NOTE: OS X does not have clock_gettime(), using clock_get_time() - clock_get_time(cclock, &now); - mach_port_deallocate(mach_task_self(), cclock); - uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds - - time = ((double)nowTime/1000000.0); // Time in miliseconds -#endif - - return time; -} - -#endif // GESTURES_IMPLEMENTATION diff --git a/raylib/go.mod b/raylib/go.mod new file mode 100644 index 0000000..fe16d16 --- /dev/null +++ b/raylib/go.mod @@ -0,0 +1,10 @@ +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 new file mode 100644 index 0000000..2241fa5 --- /dev/null +++ b/raylib/go.sum @@ -0,0 +1,6 @@ +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/mini_al.c b/raylib/mini_al.c deleted file mode 100644 index 6e9821c..0000000 --- a/raylib/mini_al.c +++ /dev/null @@ -1,4 +0,0 @@ -// 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 "mini_al.h" diff --git a/raylib/models.c b/raylib/models.c deleted file mode 100644 index 3879174..0000000 --- a/raylib/models.c +++ /dev/null @@ -1,2634 +0,0 @@ -/********************************************************************************************** -* -* raylib.models - Basic functions to deal with 3d shapes and 3d models -* -* CONFIGURATION: -* -* #define SUPPORT_FILEFORMAT_OBJ -* Selected desired fileformats to be supported for loading. -* -* #define SUPPORT_FILEFORMAT_MTL -* Selected desired fileformats to be supported for 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) 2014-2018 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 "config.h" - -#include "raylib.h" - -#include "utils.h" // Required for: fopen() Android mapping - -#include // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() -#include // Required for: malloc(), free() -#include // Required for: strcmp() -#include // Required for: sin(), cos() - -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 - -#define PAR_SHAPES_IMPLEMENTATION -#include "external/par_shapes.h" // Shapes 3d parametric generation - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_OBJ) -static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data -#endif -#if defined(SUPPORT_FILEFORMAT_MTL) -static Material LoadMTL(const char *fileName); // Load MTL material data -#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 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 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 - 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; - - 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 -// 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; - - rlEnableTexture(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(); - - rlDisableTexture(); -} - -// 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) -{ - 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/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*i)), - cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); - - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*i)), - cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); - } - } - 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/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*i)), - cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); - - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); - - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); - rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), - sinf(DEG2RAD*(270+(180/(rings + 1))*i)), - cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/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; - - 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/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom); //Bottom Right - rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/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/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/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/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/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/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom); - } - } - - // Draw Base ----------------------------------------------------------------------------------------- - for (int i = 0; i < 360; i += 360/sides) - { - rlVertex3f(0, 0, 0); - rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/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; - - 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/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom); - - rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i + 360/sides))*radiusBottom); - rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/sides))*radiusTop); - - rlVertex3f(sinf(DEG2RAD*(i + 360/sides))*radiusTop, height, cosf(DEG2RAD*(i + 360/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) -{ - // 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_TRIANGLES); - 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); - 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); - 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(); -} - -// Draw gizmo -void DrawGizmo(Vector3 position) -{ - // NOTE: RGB = XYZ - float length = 1.0f; - - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - rlScalef(length, length, length); - - rlBegin(RL_LINES); - rlColor3f(1.0f, 0.0f, 0.0f); rlVertex3f(0.0f, 0.0f, 0.0f); - rlColor3f(1.0f, 0.0f, 0.0f); rlVertex3f(1.0f, 0.0f, 0.0f); - - rlColor3f(0.0f, 1.0f, 0.0f); rlVertex3f(0.0f, 0.0f, 0.0f); - rlColor3f(0.0f, 1.0f, 0.0f); rlVertex3f(0.0f, 1.0f, 0.0f); - - rlColor3f(0.0f, 0.0f, 1.0f); rlVertex3f(0.0f, 0.0f, 0.0f); - rlColor3f(0.0f, 0.0f, 1.0f); rlVertex3f(0.0f, 0.0f, 1.0f); - rlEnd(); - rlPopMatrix(); -} - -// Load model from files (mesh and material) -Model LoadModel(const char *fileName) -{ - Model model = { 0 }; - - model.mesh = LoadMesh(fileName); - model.transform = MatrixIdentity(); - model.material = LoadMaterialDefault(); - - 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.mesh = mesh; - model.transform = MatrixIdentity(); - model.material = LoadMaterialDefault(); - - return model; -} - -// Unload model from memory (RAM and/or VRAM) -void UnloadModel(Model model) -{ - UnloadMesh(&model.mesh); - UnloadMaterial(model.material); - - TraceLog(LOG_INFO, "Unloaded model data (mesh and material) from RAM and VRAM"); -} - -// Load mesh from file -// NOTE: Mesh data loaded in CPU and GPU -Mesh LoadMesh(const char *fileName) -{ - Mesh mesh = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_OBJ) - if (IsFileExtension(fileName, ".obj")) mesh = LoadOBJ(fileName); -#else - TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName); -#endif - - if (mesh.vertexCount == 0) - { - TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!"); - mesh = GenMeshCube(1.0f, 1.0f, 1.0f); - } - else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) - - return mesh; -} - -// Unload mesh from memory (RAM and/or VRAM) -void UnloadMesh(Mesh *mesh) -{ - rlUnloadMesh(mesh); -} - -// Export mesh as an OBJ file -void ExportMesh(const char *fileName, Mesh mesh) -{ - FILE *objFile = fopen(fileName, "wt"); - - fprintf(objFile, "# raylib Mesh OBJ exporter v1.0\n\n"); - fprintf(objFile, "# Mesh exported as triangle faces and not optimized.\n"); - fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount); - fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount); - fprintf(objFile, "# LICENSE: zlib/libpng\n"); - fprintf(objFile, "# Copyright (c) 2018 Ramon Santamaria (@raysan5)\n\n"); - - fprintf(objFile, "g mesh\n"); - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) - { - fprintf(objFile, "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) - { - fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); - } - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) - { - fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); - } - - for (int i = 0; i < mesh.triangleCount; i += 3) - { - fprintf(objFile, "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); - } - - fprintf(objFile, "\n"); - - fclose(objFile); - - TraceLog(LOG_INFO, "Mesh saved: %s", fileName); -} - -#if defined(SUPPORT_MESH_GENERATION) -// 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*6; // 6 vertex by quad - - Vector3 *vertices = (Vector3 *)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 *)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 *)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 *)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 *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.indices = (unsigned short *)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]; - - free(vertices); - free(normals); - free(texcoords); - 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 *)malloc(plane->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(plane->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&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 *)malloc(24*3*sizeof(float)); - memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); - - mesh.texcoords = (float *)malloc(24*2*sizeof(float)); - memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); - - mesh.normals = (float *)malloc(24*3*sizeof(float)); - memcpy(mesh.normals, normals, 24*3*sizeof(float)); - - mesh.indices = (unsigned short *)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 *)malloc(cube->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(cube->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate sphere mesh (standard sphere) -RLAPI Mesh GenMeshSphere(float radius, int rings, int slices) -{ - Mesh mesh = { 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 *)malloc(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate hemi-sphere mesh (half sphere, no bottom cap) -RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices) -{ - Mesh mesh = { 0 }; - - 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 *)malloc(sphere->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate cylinder mesh -Mesh GenMeshCylinder(float radius, float height, int slices) -{ - Mesh mesh = { 0 }; - - // 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_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 *)malloc(cylinder->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(cylinder->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate torus mesh -Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) -{ - Mesh mesh = { 0 }; - - 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 *)malloc(torus->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(torus->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate trefoil knot mesh -Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) -{ - Mesh mesh = { 0 }; - - 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 *)malloc(knot->ntriangles*3*3*sizeof(float)); - mesh.texcoords = (float *)malloc(knot->ntriangles*3*2*sizeof(float)); - mesh.normals = (float *)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) - rlLoadMesh(&mesh, false); - - 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 = GetImageData(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 *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)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 }; - - 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 += 3) - { - mesh.normals[nCounter + i] = 0.0f; - mesh.normals[nCounter + i + 1] = 1.0f; - mesh.normals[nCounter + i + 2] = 0.0f; - } - - // TODO: Calculate normals in an efficient way - - nCounter += 18; // 6 vertex, 18 floats - trisCounter += 2; - } - } - - free(pixels); - - // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); - - return mesh; -} - -// Generate a cubes mesh from pixel data -// NOTE: Vertex data is uploaded to GPU -Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) -{ - Mesh mesh = { 0 }; - - Color *cubicmapPixels = GetImageData(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 *)malloc(maxTriangles*3*sizeof(Vector3)); - Vector2 *mapTexcoords = (Vector2 *)malloc(maxTriangles*3*sizeof(Vector2)); - Vector3 *mapNormals = (Vector3 *)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, we will full cubes - if ((cubicmapPixels[z*cubicmap.width + x].r == 255) && - (cubicmapPixels[z*cubicmap.width + x].g == 255) && - (cubicmapPixels[z*cubicmap.width + x].b == 255)) - { - // Define triangles (Checking Collateral Cubes!) - //---------------------------------------------- - - // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4) - 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; - - if (((z < cubicmap.height - 1) && - (cubicmapPixels[(z + 1)*cubicmap.width + x].r == 0) && - (cubicmapPixels[(z + 1)*cubicmap.width + x].g == 0) && - (cubicmapPixels[(z + 1)*cubicmap.width + x].b == 0)) || (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; - } - - if (((z > 0) && - (cubicmapPixels[(z - 1)*cubicmap.width + x].r == 0) && - (cubicmapPixels[(z - 1)*cubicmap.width + x].g == 0) && - (cubicmapPixels[(z - 1)*cubicmap.width + x].b == 0)) || (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; - } - - if (((x < cubicmap.width - 1) && - (cubicmapPixels[z*cubicmap.width + (x + 1)].r == 0) && - (cubicmapPixels[z*cubicmap.width + (x + 1)].g == 0) && - (cubicmapPixels[z*cubicmap.width + (x + 1)].b == 0)) || (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; - } - - if (((x > 0) && - (cubicmapPixels[z*cubicmap.width + (x - 1)].r == 0) && - (cubicmapPixels[z*cubicmap.width + (x - 1)].g == 0) && - (cubicmapPixels[z*cubicmap.width + (x - 1)].b == 0)) || (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 ((cubicmapPixels[z*cubicmap.width + x].r == 0) && - (cubicmapPixels[z*cubicmap.width + x].g == 0) && - (cubicmapPixels[z*cubicmap.width + x].b == 0)) - { - // 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 *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)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; - } - - free(mapVertices); - free(mapNormals); - free(mapTexcoords); - - free(cubicmapPixels); // Free image pixel data - - // Upload vertex data to GPU (static mesh) - rlLoadMesh(&mesh, false); - - return mesh; -} -#endif // SUPPORT_MESH_GENERATION - -// Load material data (from file) -Material LoadMaterial(const char *fileName) -{ - Material material = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_MTL) - if (IsFileExtension(fileName, ".mtl")) material = LoadMTL(fileName); -#else - TraceLog(LOG_WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName); -#endif - - // Our material uses the default shader (DIFFUSE, SPECULAR, NORMAL) - material.shader = GetShaderDefault(); - - return material; -} - -// Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -Material LoadMaterialDefault(void) -{ - Material material = { 0 }; - - material.shader = GetShaderDefault(); - material.maps[MAP_DIFFUSE].texture = GetTextureDefault(); // White texture (1x1 pixel) - //material.maps[MAP_NORMAL].texture; // NOTE: By default, not set - //material.maps[MAP_SPECULAR].texture; // NOTE: By default, not set - - material.maps[MAP_DIFFUSE].color = WHITE; // Diffuse color - material.maps[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 != GetShaderDefault().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 != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); - } -} - -// 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, 0.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) - //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates - - model.transform = MatrixMultiply(model.transform, matTransform); - model.material.maps[MAP_DIFFUSE].color = tint; // TODO: Multiply tint color by diffuse color? - - rlDrawMesh(model.mesh, model.material, model.transform); -} - -// 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 center, float size, Color tint) -{ - Rectangle sourceRec = { 0, 0, texture.width, texture.height }; - - DrawBillboardRec(camera, texture, sourceRec, center, size, tint); -} - -// Draw a billboard (part of a texture defined by a rectangle) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint) -{ - // NOTE: Billboard size will maintain sourceRec aspect ratio, size will represent billboard width - Vector2 sizeRatio = { size, size*(float)sourceRec.height/sourceRec.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 }; -/* - a-------b - | | - | * | - | | - d-------c -*/ - right = Vector3Scale(right, sizeRatio.x/2); - up = Vector3Scale(up, sizeRatio.y/2); - - Vector3 p1 = Vector3Add(right, up); - Vector3 p2 = Vector3Subtract(right, up); - - Vector3 a = Vector3Subtract(center, p2); - Vector3 b = Vector3Add(center, p1); - Vector3 c = Vector3Add(center, p2); - Vector3 d = Vector3Subtract(center, p1); - - rlEnableTexture(texture.id); - - rlBegin(RL_QUADS); - rlColor4ub(tint.r, tint.g, tint.b, tint.a); - - // Bottom-left corner for texture and quad - rlTexCoord2f((float)sourceRec.x/texture.width, (float)sourceRec.y/texture.height); - rlVertex3f(a.x, a.y, a.z); - - // Top-left corner for texture and quad - rlTexCoord2f((float)sourceRec.x/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height); - rlVertex3f(d.x, d.y, d.z); - - // Top-right corner for texture and quad - rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height); - rlVertex3f(c.x, c.y, c.z); - - // Bottom-right corner for texture and quad - rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)sourceRec.y/texture.height); - rlVertex3f(b.x, b.y, b.z); - rlEnd(); - - rlDisableTexture(); -} - -// Draw a bounding box with wires -void DrawBoundingBox(BoundingBox box, Color color) -{ - Vector3 size; - - 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 centerA, float radiusA, Vector3 centerB, float radiusB) -{ - bool collision = false; - - float dx = centerA.x - centerB.x; // X distance between centers - float dy = centerA.y - centerB.y; // Y distance between centers - float dz = centerA.z - centerB.z; // Y distance between centers - - float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers - - if (distance <= (radiusA + radiusB)) 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 centerSphere, float radiusSphere) -{ - bool collision = false; - - float dmin = 0; - - if (centerSphere.x < box.min.x) dmin += powf(centerSphere.x - box.min.x, 2); - else if (centerSphere.x > box.max.x) dmin += powf(centerSphere.x - box.max.x, 2); - - if (centerSphere.y < box.min.y) dmin += powf(centerSphere.y - box.min.y, 2); - else if (centerSphere.y > box.max.y) dmin += powf(centerSphere.y - box.max.y, 2); - - if (centerSphere.z < box.min.z) dmin += powf(centerSphere.z - box.min.z, 2); - else if (centerSphere.z > box.max.z) dmin += powf(centerSphere.z - box.max.z, 2); - - if (dmin <= (radiusSphere*radiusSphere)) collision = true; - - return collision; -} - -// Detect collision between ray and sphere -bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius) -{ - bool collision = false; - - Vector3 raySpherePos = Vector3Subtract(spherePosition, ray.position); - float distance = Vector3Length(raySpherePos); - float vector = Vector3DotProduct(raySpherePos, ray.direction); - float d = sphereRadius*sphereRadius - (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 spherePosition, float sphereRadius, Vector3 *collisionPoint) -{ - bool collision = false; - - Vector3 raySpherePos = Vector3Subtract(spherePosition, ray.position); - float distance = Vector3Length(raySpherePos); - float vector = Vector3DotProduct(raySpherePos, ray.direction); - float d = sphereRadius*sphereRadius - (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 < sphereRadius) 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]; - 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 model -RayHitInfo GetCollisionRayModel(Ray ray, Model *model) -{ - RayHitInfo result = { 0 }; - - // If mesh doesn't have vertex data on CPU, can't test it. - if (!model->mesh.vertices) return result; - - // model->mesh.triangleCount may not be set, vertexCount is more reliable - int triangleCount = model->mesh.vertexCount/3; - - // Test against all triangles in mesh - for (int i = 0; i < triangleCount; i++) - { - Vector3 a, b, c; - Vector3 *vertdata = (Vector3 *)model->mesh.vertices; - - if (model->mesh.indices) - { - a = vertdata[model->mesh.indices[i*3 + 0]]; - b = vertdata[model->mesh.indices[i*3 + 1]]; - c = vertdata[model->mesh.indices[i*3 + 2]]; - } - else - { - a = vertdata[i*3 + 0]; - b = vertdata[i*3 + 1]; - c = vertdata[i*3 + 2]; - } - - a = Vector3Transform(a, model->transform); - b = Vector3Transform(b, model->transform); - c = Vector3Transform(c, model->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 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)); - } - } - - return result; -} - -// Compute mesh bounding box limits -// NOTE: minVertex and maxVertex should be transformed by model transform matrix -BoundingBox MeshBoundingBox(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; - 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 *)malloc(mesh->vertexCount*4*sizeof(float)); - else TraceLog(LOG_WARNING, "Mesh tangents already exist"); - - Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); - Vector3 *tan2 = (Vector3 *)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, Vector3Multiply(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 - } - - free(tan1); - free(tan2); - - TraceLog(LOG_INFO, "Tangents computed for 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] }; - float tangentW = mesh->tangents[i*4 + 3]; - - Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); - - // TODO: Register computed binormal in mesh->binormal ? - } -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(SUPPORT_FILEFORMAT_OBJ) -// Load OBJ mesh data -static Mesh LoadOBJ(const char *fileName) -{ - Mesh mesh = { 0 }; - - char dataType; - char comments[200]; - - int vertexCount = 0; - int normalCount = 0; - int texcoordCount = 0; - int triangleCount = 0; - - FILE *objFile; - - objFile = fopen(fileName, "rt"); - - if (objFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] OBJ file could not be opened", fileName); - return mesh; - } - - // First reading pass: Get vertexCount, normalCount, texcoordCount, triangleCount - // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) - // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) - while (!feof(objFile)) - { - dataType = '\0'; - fscanf(objFile, "%c", &dataType); - - switch (dataType) - { - case '#': // Comments - case 'o': // Object name (One OBJ file can contain multible named meshes) - case 'g': // Group name - case 's': // Smoothing level - case 'm': // mtllib [external .mtl file name] - case 'u': // usemtl [material name] - { - fgets(comments, 200, objFile); - } break; - case 'v': - { - fscanf(objFile, "%c", &dataType); - - if (dataType == 't') // Read texCoord - { - texcoordCount++; - fgets(comments, 200, objFile); - } - else if (dataType == 'n') // Read normals - { - normalCount++; - fgets(comments, 200, objFile); - } - else // Read vertex - { - vertexCount++; - fgets(comments, 200, objFile); - } - } break; - case 'f': - { - triangleCount++; - fgets(comments, 200, objFile); - } break; - default: break; - } - } - - TraceLog(LOG_DEBUG, "[%s] Model vertices: %i", fileName, vertexCount); - TraceLog(LOG_DEBUG, "[%s] Model texcoords: %i", fileName, texcoordCount); - TraceLog(LOG_DEBUG, "[%s] Model normals: %i", fileName, normalCount); - TraceLog(LOG_DEBUG, "[%s] Model triangles: %i", fileName, triangleCount); - - // Once we know the number of vertices to store, we create required arrays - Vector3 *midVertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); - Vector3 *midNormals = NULL; - if (normalCount > 0) midNormals = (Vector3 *)malloc(normalCount*sizeof(Vector3)); - Vector2 *midTexCoords = NULL; - if (texcoordCount > 0) midTexCoords = (Vector2 *)malloc(texcoordCount*sizeof(Vector2)); - - int countVertex = 0; - int countNormals = 0; - int countTexCoords = 0; - - rewind(objFile); // Return to the beginning of the file, to read again - - // Second reading pass: Get vertex data to fill intermediate arrays - // NOTE: This second pass is required in case of multiple meshes defined in same OBJ - // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals) - while (!feof(objFile)) - { - fscanf(objFile, "%c", &dataType); - - switch (dataType) - { - case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break; - case 'v': - { - fscanf(objFile, "%c", &dataType); - - if (dataType == 't') // Read texCoord - { - fscanf(objFile, "%f %f%*[^\n]s\n", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y); - countTexCoords++; - - fscanf(objFile, "%c", &dataType); - } - else if (dataType == 'n') // Read normals - { - fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z); - countNormals++; - - fscanf(objFile, "%c", &dataType); - } - else // Read vertex - { - fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z); - countVertex++; - - fscanf(objFile, "%c", &dataType); - } - } break; - default: break; - } - } - - // At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals - // Now we can organize that data into our Mesh struct - - mesh.vertexCount = triangleCount*3; - - // Additional arrays to store vertex data as floats - mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.normals = (float *)malloc(mesh.vertexCount*3*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 vCount[3], vtCount[3], vnCount[3]; // Used to store triangle indices for v, vt, vn - - rewind(objFile); // Return to the beginning of the file, to read again - - if (normalCount == 0) TraceLog(LOG_INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName); - - // Third reading pass: Get faces (triangles) data and fill VertexArray - while (!feof(objFile)) - { - fscanf(objFile, "%c", &dataType); - - switch (dataType) - { - case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break; - case 'f': - { - // NOTE: It could be that OBJ does not have normals or texcoords defined! - - if ((normalCount == 0) && (texcoordCount == 0)) fscanf(objFile, "%i %i %i", &vCount[0], &vCount[1], &vCount[2]); - else if (normalCount == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vCount[0], &vtCount[0], &vCount[1], &vtCount[1], &vCount[2], &vtCount[2]); - else if (texcoordCount == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vCount[0], &vnCount[0], &vCount[1], &vnCount[1], &vCount[2], &vnCount[2]); - else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vCount[0], &vtCount[0], &vnCount[0], &vCount[1], &vtCount[1], &vnCount[1], &vCount[2], &vtCount[2], &vnCount[2]); - - mesh.vertices[vCounter] = midVertices[vCount[0]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[0]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[0]-1].z; - vCounter += 3; - mesh.vertices[vCounter] = midVertices[vCount[1]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[1]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[1]-1].z; - vCounter += 3; - mesh.vertices[vCounter] = midVertices[vCount[2]-1].x; - mesh.vertices[vCounter + 1] = midVertices[vCount[2]-1].y; - mesh.vertices[vCounter + 2] = midVertices[vCount[2]-1].z; - vCounter += 3; - - if (normalCount > 0) - { - mesh.normals[nCounter] = midNormals[vnCount[0]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[0]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[0]-1].z; - nCounter += 3; - mesh.normals[nCounter] = midNormals[vnCount[1]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[1]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[1]-1].z; - nCounter += 3; - mesh.normals[nCounter] = midNormals[vnCount[2]-1].x; - mesh.normals[nCounter + 1] = midNormals[vnCount[2]-1].y; - mesh.normals[nCounter + 2] = midNormals[vnCount[2]-1].z; - nCounter += 3; - } - else - { - // If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)] - Vector3 norm = Vector3CrossProduct(Vector3Subtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), Vector3Subtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1])); - norm = Vector3Normalize(norm); - - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - mesh.normals[nCounter] = norm.x; - mesh.normals[nCounter + 1] = norm.y; - mesh.normals[nCounter + 2] = norm.z; - nCounter += 3; - } - - if (texcoordCount > 0) - { - // NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work! - // NOTE: Texture coordinates are Y flipped upside-down - mesh.texcoords[tcCounter] = midTexCoords[vtCount[0]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[0]-1].y; - tcCounter += 2; - mesh.texcoords[tcCounter] = midTexCoords[vtCount[1]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[1]-1].y; - tcCounter += 2; - mesh.texcoords[tcCounter] = midTexCoords[vtCount[2]-1].x; - mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[2]-1].y; - tcCounter += 2; - } - } break; - default: break; - } - } - - fclose(objFile); - - // Now we can free temp mid* arrays - free(midVertices); - free(midNormals); - free(midTexCoords); - - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - TraceLog(LOG_INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName); - - return mesh; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_MTL) -// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/) -// NOTE: Texture map parameters are not supported -static Material LoadMTL(const char *fileName) -{ - #define MAX_BUFFER_SIZE 128 - - Material material = { 0 }; - - char buffer[MAX_BUFFER_SIZE]; - Vector3 color = { 1.0f, 1.0f, 1.0f }; - char mapFileName[128]; - int result = 0; - - FILE *mtlFile; - - mtlFile = fopen(fileName, "rt"); - - if (mtlFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] MTL file could not be opened", fileName); - return material; - } - - while (!feof(mtlFile)) - { - fgets(buffer, MAX_BUFFER_SIZE, mtlFile); - - switch (buffer[0]) - { - case 'n': // newmtl string Material name. Begins a new material description. - { - // TODO: Support multiple materials in a single .mtl - sscanf(buffer, "newmtl %127s", mapFileName); - - TraceLog(LOG_INFO, "[%s] Loading material...", mapFileName); - } - case 'i': // illum int Illumination model - { - // illum = 1 if specular disabled - // illum = 2 if specular enabled (lambertian model) - // ... - } - case 'K': // Ka, Kd, Ks, Ke - { - switch (buffer[1]) - { - case 'a': // Ka float float float Ambient color (RGB) - { - sscanf(buffer, "Ka %f %f %f", &color.x, &color.y, &color.z); - // TODO: Support ambient color - //material.colAmbient.r = (unsigned char)(color.x*255); - //material.colAmbient.g = (unsigned char)(color.y*255); - //material.colAmbient.b = (unsigned char)(color.z*255); - } break; - case 'd': // Kd float float float Diffuse color (RGB) - { - sscanf(buffer, "Kd %f %f %f", &color.x, &color.y, &color.z); - material.maps[MAP_DIFFUSE].color.r = (unsigned char)(color.x*255); - material.maps[MAP_DIFFUSE].color.g = (unsigned char)(color.y*255); - material.maps[MAP_DIFFUSE].color.b = (unsigned char)(color.z*255); - } break; - case 's': // Ks float float float Specular color (RGB) - { - sscanf(buffer, "Ks %f %f %f", &color.x, &color.y, &color.z); - material.maps[MAP_SPECULAR].color.r = (unsigned char)(color.x*255); - material.maps[MAP_SPECULAR].color.g = (unsigned char)(color.y*255); - material.maps[MAP_SPECULAR].color.b = (unsigned char)(color.z*255); - } break; - case 'e': // Ke float float float Emmisive color (RGB) - { - // TODO: Support Ke ? - } break; - default: break; - } - } break; - case 'N': // Ns, Ni - { - if (buffer[1] == 's') // Ns int Shininess (specular exponent). Ranges from 0 to 1000. - { - int shininess = 0; - sscanf(buffer, "Ns %i", &shininess); - - //material.params[PARAM_GLOSSINES] = (float)shininess; - } - else if (buffer[1] == 'i') // Ni int Refraction index. - { - // Not supported... - } - } break; - case 'm': // map_Kd, map_Ks, map_Ka, map_Bump, map_d - { - switch (buffer[4]) - { - case 'K': // Color texture maps - { - if (buffer[5] == 'd') // map_Kd string Diffuse color texture map. - { - result = sscanf(buffer, "map_Kd %127s", mapFileName); - if (result != EOF) material.maps[MAP_DIFFUSE].texture = LoadTexture(mapFileName); - } - else if (buffer[5] == 's') // map_Ks string Specular color texture map. - { - result = sscanf(buffer, "map_Ks %127s", mapFileName); - if (result != EOF) material.maps[MAP_SPECULAR].texture = LoadTexture(mapFileName); - } - else if (buffer[5] == 'a') // map_Ka string Ambient color texture map. - { - // Not supported... - } - } break; - case 'B': // map_Bump string Bump texture map. - { - result = sscanf(buffer, "map_Bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'b': // map_bump string Bump texture map. - { - result = sscanf(buffer, "map_bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'd': // map_d string Opacity texture map. - { - // Not supported... - } break; - default: break; - } - } break; - case 'd': // d, disp - { - if (buffer[1] == ' ') // d float Dissolve factor. d is inverse of Tr - { - float alpha = 1.0f; - sscanf(buffer, "d %f", &alpha); - material.maps[MAP_DIFFUSE].color.a = (unsigned char)(alpha*255); - } - else if (buffer[1] == 'i') // disp string Displacement map - { - // Not supported... - } - } break; - case 'b': // bump string Bump texture map - { - result = sscanf(buffer, "bump %127s", mapFileName); - if (result != EOF) material.maps[MAP_NORMAL].texture = LoadTexture(mapFileName); - } break; - case 'T': // Tr float Transparency Tr (alpha). Tr is inverse of d - { - float ialpha = 0.0f; - sscanf(buffer, "Tr %f", &ialpha); - material.maps[MAP_DIFFUSE].color.a = (unsigned char)((1.0f - ialpha)*255); - - } break; - case 'r': // refl string Reflection texture map - default: break; - } - } - - fclose(mtlFile); - - // NOTE: At this point we have all material data - TraceLog(LOG_INFO, "[%s] Material loaded successfully", fileName); - - return material; -} -#endif diff --git a/raylib/models.go b/raylib/models.go deleted file mode 100644 index 7958e22..0000000 --- a/raylib/models.go +++ /dev/null @@ -1,467 +0,0 @@ -package raylib - -/* -#include "raylib.h" -#include -*/ -import "C" -import "unsafe" - -// cptr returns C pointer -func (m *Mesh) cptr() *C.Mesh { - return (*C.Mesh)(unsafe.Pointer(m)) -} - -// cptr returns C pointer -func (m *Material) cptr() *C.Material { - return (*C.Material)(unsafe.Pointer(m)) -} - -// cptr returns C pointer -func (m *Model) cptr() *C.Model { - return (*C.Model)(unsafe.Pointer(m)) -} - -// cptr returns C pointer -func (r *Ray) cptr() *C.Ray { - return (*C.Ray)(unsafe.Pointer(r)) -} - -// DrawLine3D - Draw a line in 3D world space -func DrawLine3D(startPos Vector3, endPos Vector3, color Color) { - cstartPos := startPos.cptr() - cendPos := endPos.cptr() - ccolor := color.cptr() - C.DrawLine3D(*cstartPos, *cendPos, *ccolor) -} - -// DrawCircle3D - Draw a circle in 3D world space -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 := color.cptr() - C.DrawCircle3D(*ccenter, cradius, *crotationAxis, crotationAngle, *ccolor) -} - -// DrawCube - Draw cube -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 := color.cptr() - C.DrawCube(*cposition, cwidth, cheight, clength, *ccolor) -} - -// DrawCubeV - Draw cube (Vector version) -func DrawCubeV(position Vector3, size Vector3, color Color) { - cposition := position.cptr() - csize := size.cptr() - ccolor := color.cptr() - C.DrawCubeV(*cposition, *csize, *ccolor) -} - -// DrawCubeWires - Draw cube wires -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 := color.cptr() - C.DrawCubeWires(*cposition, cwidth, cheight, clength, *ccolor) -} - -// DrawCubeTexture - Draw cube textured -func DrawCubeTexture(texture Texture2D, position Vector3, width float32, height float32, length float32, color Color) { - ctexture := texture.cptr() - cposition := position.cptr() - 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, color Color) { - ccenterPos := centerPos.cptr() - cradius := (C.float)(radius) - ccolor := color.cptr() - C.DrawSphere(*ccenterPos, cradius, *ccolor) -} - -// DrawSphereEx - Draw sphere with extended parameters -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 := color.cptr() - C.DrawSphereEx(*ccenterPos, cradius, crings, cslices, *ccolor) -} - -// DrawSphereWires - Draw sphere wires -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 := 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, color Color) { - cposition := position.cptr() - cradiusTop := (C.float)(radiusTop) - cradiusBottom := (C.float)(radiusBottom) - cheight := (C.float)(height) - cslices := (C.int)(slices) - ccolor := color.cptr() - C.DrawCylinder(*cposition, cradiusTop, cradiusBottom, cheight, cslices, *ccolor) -} - -// DrawCylinderWires - Draw a cylinder/cone wires -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 := color.cptr() - C.DrawCylinderWires(*cposition, cradiusTop, cradiusBottom, cheight, cslices, *ccolor) -} - -// DrawPlane - Draw a plane XZ -func DrawPlane(centerPos Vector3, size Vector2, color Color) { - ccenterPos := centerPos.cptr() - csize := size.cptr() - ccolor := color.cptr() - C.DrawPlane(*ccenterPos, *csize, *ccolor) -} - -// DrawRay - Draw a ray line -func DrawRay(ray Ray, color Color) { - cray := ray.cptr() - ccolor := color.cptr() - C.DrawRay(*cray, *ccolor) -} - -// DrawGrid - Draw a grid (centered at (0, 0, 0)) -func DrawGrid(slices int32, spacing float32) { - cslices := (C.int)(slices) - cspacing := (C.float)(spacing) - C.DrawGrid(cslices, cspacing) -} - -// DrawGizmo - Draw simple gizmo -func DrawGizmo(position Vector3) { - cposition := position.cptr() - C.DrawGizmo(*cposition) -} - -// LoadMesh - Load mesh from file -func LoadMesh(fileName string) Mesh { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadMesh(cfileName) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadModel - Load model from file -func LoadModel(fileName string) Model { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadModel(cfileName) - v := newModelFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadModelFromMesh - Load model from mesh data -func LoadModelFromMesh(data Mesh) Model { - cdata := data.cptr() - ret := C.LoadModelFromMesh(*cdata) - v := newModelFromPointer(unsafe.Pointer(&ret)) - return v -} - -// UnloadModel - Unload model from memory (RAM and/or VRAM) -func UnloadModel(model Model) { - cmodel := model.cptr() - C.UnloadModel(*cmodel) -} - -// 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 -func ExportMesh(fileName string, mesh Mesh) { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - cmesh := mesh.cptr() - C.ExportMesh(cfileName, *cmesh) -} - -// GenMeshPlane - Generate plane mesh (with subdivisions) -func GenMeshPlane(width, length float32, resX, resZ int) Mesh { - cwidth := (C.float)(width) - clength := (C.float)(length) - cresX := (C.int)(resX) - cresZ := (C.int)(resZ) - - ret := C.GenMeshPlane(cwidth, clength, cresX, cresZ) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshCube - Generate cuboid mesh -func GenMeshCube(width, height, length float32) Mesh { - cwidth := (C.float)(width) - cheight := (C.float)(height) - clength := (C.float)(length) - - ret := C.GenMeshCube(cwidth, cheight, clength) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshSphere - Generate sphere mesh (standard sphere) -func GenMeshSphere(radius float32, rings, slices int) Mesh { - cradius := (C.float)(radius) - crings := (C.int)(rings) - cslices := (C.int)(slices) - - ret := C.GenMeshSphere(cradius, crings, cslices) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshHemiSphere - Generate half-sphere mesh (no bottom cap) -func GenMeshHemiSphere(radius float32, rings, slices int) Mesh { - cradius := (C.float)(radius) - crings := (C.int)(rings) - cslices := (C.int)(slices) - - ret := C.GenMeshHemiSphere(cradius, crings, cslices) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshCylinder - Generate cylinder mesh -func GenMeshCylinder(radius, height float32, slices int) Mesh { - cradius := (C.float)(radius) - cheight := (C.float)(height) - cslices := (C.int)(slices) - - ret := C.GenMeshCylinder(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) - csize := (C.float)(size) - cradSeg := (C.int)(radSeg) - csides := (C.int)(sides) - - ret := C.GenMeshTorus(cradius, csize, cradSeg, csides) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshKnot - Generate trefoil knot mesh -func GenMeshKnot(radius, size float32, radSeg, sides int) Mesh { - cradius := (C.float)(radius) - csize := (C.float)(size) - cradSeg := (C.int)(radSeg) - csides := (C.int)(sides) - - ret := C.GenMeshKnot(cradius, csize, cradSeg, csides) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshHeightmap - Generate heightmap mesh from image data -func GenMeshHeightmap(heightmap Image, size Vector3) Mesh { - cheightmap := heightmap.cptr() - csize := size.cptr() - - ret := C.GenMeshHeightmap(*cheightmap, *csize) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenMeshCubicmap - Generate cubes-based map mesh from image data -func GenMeshCubicmap(cubicmap Image, size Vector3) Mesh { - ccubicmap := cubicmap.cptr() - csize := size.cptr() - - ret := C.GenMeshCubicmap(*ccubicmap, *csize) - v := newMeshFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadMaterial - Load material data (.MTL) -func LoadMaterial(fileName string) Material { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadMaterial(cfileName) - v := newMaterialFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadMaterialDefault - Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -func LoadMaterialDefault() Material { - ret := C.LoadMaterialDefault() - v := newMaterialFromPointer(unsafe.Pointer(&ret)) - return v -} - -// UnloadMaterial - Unload material textures from VRAM -func UnloadMaterial(material Material) { - cmaterial := material.cptr() - C.UnloadMaterial(*cmaterial) -} - -// DrawModel - Draw a model (with texture if set) -func DrawModel(model Model, position Vector3, scale float32, tint Color) { - cmodel := model.cptr() - cposition := position.cptr() - cscale := (C.float)(scale) - ctint := tint.cptr() - 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) { - cmodel := model.cptr() - cposition := position.cptr() - crotationAxis := rotationAxis.cptr() - crotationAngle := (C.float)(rotationAngle) - cscale := scale.cptr() - ctint := tint.cptr() - 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) { - cmodel := model.cptr() - 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 float32, tint Color) { - ccamera := camera.cptr() - ctexture := texture.cptr() - csourceRec := sourceRec.cptr() - ccenter := center.cptr() - csize := (C.float)(size) - ctint := tint.cptr() - C.DrawBillboardRec(*ccamera, *ctexture, *csourceRec, *ccenter, csize, *ctint) -} - -// MeshBoundingBox - Compute mesh bounding box limits -func MeshBoundingBox(mesh Mesh) BoundingBox { - cmesh := mesh.cptr() - ret := C.MeshBoundingBox(*cmesh) - v := newBoundingBoxFromPointer(unsafe.Pointer(&ret)) - return v -} - -// CheckCollisionSpheres - Detect collision between two spheres -func CheckCollisionSpheres(centerA Vector3, radiusA float32, centerB Vector3, radiusB float32) bool { - ccenterA := centerA.cptr() - cradiusA := (C.float)(radiusA) - ccenterB := centerB.cptr() - cradiusB := (C.float)(radiusB) - ret := C.CheckCollisionSpheres(*ccenterA, cradiusA, *ccenterB, cradiusB) - v := bool(int(ret) == 1) - return v -} - -// CheckCollisionBoxes - Detect collision between two bounding boxes -func CheckCollisionBoxes(box1 BoundingBox, box2 BoundingBox) bool { - cbox1 := box1.cptr() - cbox2 := box2.cptr() - ret := C.CheckCollisionBoxes(*cbox1, *cbox2) - v := bool(int(ret) == 1) - return v -} - -// CheckCollisionBoxSphere - Detect collision between box and sphere -func CheckCollisionBoxSphere(box BoundingBox, centerSphere Vector3, radiusSphere float32) bool { - cbox := box.cptr() - ccenterSphere := centerSphere.cptr() - cradiusSphere := (C.float)(radiusSphere) - ret := C.CheckCollisionBoxSphere(*cbox, *ccenterSphere, cradiusSphere) - v := bool(int(ret) == 1) - return v -} - -// CheckCollisionRaySphere - Detect collision between ray and sphere -func CheckCollisionRaySphere(ray Ray, spherePosition Vector3, sphereRadius float32) bool { - cray := ray.cptr() - cspherePosition := spherePosition.cptr() - csphereRadius := (C.float)(sphereRadius) - ret := C.CheckCollisionRaySphere(*cray, *cspherePosition, csphereRadius) - v := bool(int(ret) == 1) - return v -} - -// 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(int(ret) == 1) - return v -} - -// CheckCollisionRayBox - Detect collision between ray and box -func CheckCollisionRayBox(ray Ray, box BoundingBox) bool { - cray := ray.cptr() - cbox := box.cptr() - ret := C.CheckCollisionRayBox(*cray, *cbox) - v := bool(int(ret) == 1) - return v -} diff --git a/raylib/platform_android.c b/raylib/platform_android.c deleted file mode 100644 index 83be1d0..0000000 --- a/raylib/platform_android.c +++ /dev/null @@ -1,10 +0,0 @@ -// +build android - -#include "_cgo_export.h" - -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 c8a5e54..ecde316 100644 --- a/raylib/platform_android.go +++ b/raylib/platform_android.go @@ -1,16 +1,25 @@ +//go:build android // +build android -package raylib +package rl /* #include "raylib.h" +#include #include #include -extern void android_init(); +extern struct android_app* GetAndroidApp(); -AAssetManager* asset_manager; -const char* internal_storage_path; +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; +} */ import "C" @@ -31,7 +40,6 @@ 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 @@ -61,6 +69,11 @@ func IsCursorHidden() bool { return false } +// IsCursorOnScreen - Check if cursor is on the current screen. +func IsCursorOnScreen() bool { + return false +} + // EnableCursor - Enables cursor func EnableCursor() { return @@ -76,13 +89,13 @@ func IsFileDropped() bool { return false } -// GetDroppedFiles - Retrieve dropped files into window -func GetDroppedFiles(count *int32) (files []string) { +// LoadDroppedFiles - Load dropped filepaths +func LoadDroppedFiles() (files []string) { return } -// ClearDroppedFiles - Clear dropped files paths buffer -func ClearDroppedFiles() { +// UnloadDroppedFiles - Unload dropped filepaths +func UnloadDroppedFiles() { return } @@ -91,7 +104,7 @@ func OpenAsset(name string) (Asset, error) { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) - a := &asset{C.AAssetManager_open(C.asset_manager, cname, C.AASSET_MODE_UNKNOWN)} + a := &asset{C.AAssetManager_open(C.GetAssetManager(), cname, C.AASSET_MODE_UNKNOWN)} if a.ptr == nil { return nil, fmt.Errorf("asset file could not be opened") @@ -109,6 +122,7 @@ func (a *asset) Read(p []byte) (n int, err error) { if n == 0 && len(p) > 0 { return 0, io.EOF } + return n, nil } @@ -117,10 +131,16 @@ 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 819ea51..91634fb 100644 --- a/raylib/platform_desktop.go +++ b/raylib/platform_desktop.go @@ -1,6 +1,7 @@ -// +build !android,!arm +//go:build !rgfw && !sdl && !sdl3 && !drm && !android +// +build !rgfw,!sdl,!sdl3,!drm,!android -package raylib +package rl /* #include "raylib.h" @@ -26,7 +27,6 @@ func InitWindow(width int32, height int32, title string) { // SetCallbackFunc - Sets callback function func SetCallbackFunc(func()) { - return } // ShowCursor - Shows cursor @@ -42,7 +42,16 @@ func HideCursor() { // IsCursorHidden - Returns true if cursor is not visible func IsCursorHidden() bool { ret := C.IsCursorHidden() - v := bool(int(ret) == 1) + 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 } @@ -59,17 +68,18 @@ func DisableCursor() { // IsFileDropped - Check if a file have been dropped into window func IsFileDropped() bool { ret := C.IsFileDropped() - v := bool(int(ret) == 1) + v := bool(ret) + return v } -// GetDroppedFiles - Retrieve dropped files into window -func GetDroppedFiles(count *int32) []string { - ccount := (*C.int)(unsafe.Pointer(count)) - ret := C.GetDroppedFiles(ccount) +// LoadDroppedFiles - Load dropped filepaths +func LoadDroppedFiles() []string { + ret := C.LoadDroppedFiles() + defer C.UnloadDroppedFiles(ret) - tmpslice := (*[1 << 24]*C.char)(unsafe.Pointer(ret))[:*count:*count] - gostrings := make([]string, *count) + 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) } @@ -77,9 +87,8 @@ func GetDroppedFiles(count *int32) []string { return gostrings } -// ClearDroppedFiles - Clear dropped files paths buffer -func ClearDroppedFiles() { - C.ClearDroppedFiles() +// UnloadDroppedFiles - Unload dropped filepaths +func UnloadDroppedFiles() { } // OpenAsset - Open asset @@ -88,5 +97,6 @@ func OpenAsset(name string) (Asset, error) { if err != nil { return nil, err } + return f, nil } diff --git a/raylib/platform_desktop_rgfw.go b/raylib/platform_desktop_rgfw.go new file mode 100644 index 0000000..ba77eec --- /dev/null +++ b/raylib/platform_desktop_rgfw.go @@ -0,0 +1,102 @@ +//go:build rgfw && !sdl && !sdl3 && !drm && !android +// +build rgfw,!sdl,!sdl3,!drm,!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_desktop_sdl.go b/raylib/platform_desktop_sdl.go new file mode 100644 index 0000000..82cf7ad --- /dev/null +++ b/raylib/platform_desktop_sdl.go @@ -0,0 +1,105 @@ +//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_arm.go b/raylib/platform_drm.go similarity index 71% rename from raylib/platform_arm.go rename to raylib/platform_drm.go index b335fdf..fa036d5 100644 --- a/raylib/platform_arm.go +++ b/raylib/platform_drm.go @@ -1,6 +1,7 @@ -// +build !android,arm +//go:build linux && drm && !rgfw && !sdl && !sdl3 && !android +// +build linux,drm,!rgfw,!sdl,!sdl3,!android -package raylib +package rl /* #include "raylib.h" @@ -42,7 +43,14 @@ func HideCursor() { // IsCursorHidden - Returns true if cursor is not visible func IsCursorHidden() bool { ret := C.IsCursorHidden() - v := bool(int(ret) == 1) + 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 } @@ -61,13 +69,13 @@ func IsFileDropped() bool { return false } -// GetDroppedFiles - Retrieve dropped files into window -func GetDroppedFiles(count *int32) (files []string) { +// LoadDroppedFiles - Load dropped filepaths +func LoadDroppedFiles() (files []string) { return } -// ClearDroppedFiles - Clear dropped files paths buffer -func ClearDroppedFiles() { +// UnloadDroppedFiles - Unload dropped filepaths +func UnloadDroppedFiles() { return } diff --git a/raylib/platforms/drm-lease-v1.c b/raylib/platforms/drm-lease-v1.c new file mode 100644 index 0000000..5f75126 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.c @@ -0,0 +1,116 @@ +/* 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 new file mode 100644 index 0000000..ef24934 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.h @@ -0,0 +1,743 @@ +/* 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 new file mode 100644 index 0000000..1fca538 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.xml @@ -0,0 +1,317 @@ + + + + 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 new file mode 100644 index 0000000..b41f8a1 --- /dev/null +++ b/raylib/platforms/rcore_android.c @@ -0,0 +1,1414 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..9bbd655 --- /dev/null +++ b/raylib/platforms/rcore_desktop_glfw.c @@ -0,0 +1,1994 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..a1694af --- /dev/null +++ b/raylib/platforms/rcore_desktop_rgfw.c @@ -0,0 +1,1425 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..6af1cb6 --- /dev/null +++ b/raylib/platforms/rcore_desktop_sdl.c @@ -0,0 +1,2096 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..20d676e --- /dev/null +++ b/raylib/platforms/rcore_drm.c @@ -0,0 +1,2258 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..0fb2a0f --- /dev/null +++ b/raylib/platforms/vendor.go @@ -0,0 +1,4 @@ +//go:build required +// +build required + +package vendor diff --git a/raylib/purego_windows.go b/raylib/purego_windows.go new file mode 100644 index 0000000..35cb0ed --- /dev/null +++ b/raylib/purego_windows.go @@ -0,0 +1,61 @@ +//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 new file mode 100644 index 0000000..0faf3ad --- /dev/null +++ b/raylib/raudio.c @@ -0,0 +1,2888 @@ +//go:build !noaudio +// +build !noaudio + +/********************************************************************************************** +* +* raudio v1.1 - A simple and easy-to-use audio library based on miniaudio +* +* FEATURES: +* - Manage audio device (init/close) +* - Manage raw audio context +* - Manage mixing channels +* - Load and unload audio files +* - Format wave data (sample rate, size, channels) +* - 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 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 +* +* DEPENDENCIES: +* miniaudio.h - Audio device management lib (https://github.com/mackron/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 +* 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) 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. +* +**********************************************************************************************/ + +#if defined(RAUDIO_STANDALONE) + #include "raudio.h" +#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 + #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 +// by user at some point and won't be included... +//------------------------------------------------------------------------------------- + +// If defined, the following flags inhibit definition of the indicated items. +#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_ +#define NOVIRTUALKEYCODES // VK_* +#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_* +#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_* +#define NOSYSMETRICS // SM_* +#define NOMENUS // MF_* +#define NOICONS // IDI_* +#define NOKEYSTATES // MK_* +#define NOSYSCOMMANDS // SC_* +#define NORASTEROPS // Binary and Tertiary raster ops +#define NOSHOWWINDOW // SW_* +#define OEMRESOURCE // OEM Resource values +#define NOATOM // Atom Manager routines +#define NOCLIPBOARD // Clipboard routines +#define NOCOLOR // Screen colors +#define NOCTLMGR // Control and Dialog routines +#define NODRAWTEXT // DrawText() and DT_* +#define NOGDI // All GDI defines and routines +#define NOKERNEL // All KERNEL defines and routines +#define NOUSER // All USER defines and routines +//#define NONLS // All NLS defines and routines +#define NOMB // MB_* and MessageBox() +#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines +#define NOMETAFILE // typedef METAFILEPICT +#define NOMINMAX // Macros min(a,b) and max(a,b) +#define NOMSG // typedef MSG and associated routines +#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_* +#define NOSCROLL // SB_* and scrolling routines +#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc. +#define NOSOUND // Sound driver routines +#define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines +#define NOWH // SetWindowsHook and WH_* +#define NOWINOFFSETS // GWL_*, GCL_*, associated routines +#define NOCOMM // COMM driver routines +#define NOKANJI // Kanji support stuff. +#define NOHELP // Help engine interface. +#define NOPROFILER // Profiler interface. +#define NODEFERWINDOWPOS // DeferWindowPos routines +#define NOMCX // Modem Configuration Extensions + +// Type required before windows.h inclusion +typedef struct tagMSG *LPMSG; + +#include // Windows functionality (miniaudio) + +// Type required by some unused function... +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, *PBITMAPINFOHEADER; + +#include // Component Object Model (COM) header +#include // Windows Multimedia, defines some WAVE structs +#include // Windows Multimedia, used by Windows GDI, defines DIBINDEX macro + +// Some required types defined for MSVC/TinyC compiler +#if defined(_MSC_VER) || defined(__TINYC__) + #include "propidl.h" +#endif +#endif + +#define MA_MALLOC RL_MALLOC +#define MA_FREE RL_FREE + +#define MA_NO_JACK +#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 +#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__) + #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(ptr,sz) realloc(ptr,sz) + #endif + #ifndef RL_FREE + #define RL_FREE(ptr) free(ptr) + #endif +#endif + +#if defined(SUPPORT_FILEFORMAT_WAV) + #define DRWAV_MALLOC RL_MALLOC + #define DRWAV_REALLOC RL_REALLOC + #define DRWAV_FREE RL_FREE + + #define DR_WAV_IMPLEMENTATION + #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 + #define DRMP3_FREE RL_FREE + + #define DR_MP3_IMPLEMENTATION + #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 + #define DRFLAC_FREE RL_FREE + + #define DR_FLAC_IMPLEMENTATION + #define DR_FLAC_NO_WIN32_IO + #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 +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef AUDIO_DEVICE_FORMAT + #define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (float-32bit) +#endif +#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 MAX_AUDIO_BUFFER_POOL_CHANNELS + #define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Audio pool channels +#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 +} MusicContextType; + +// NOTE: Different logic is used when feeding data to the playback device +// depending on whether data is streamed (Music vs Sound) +typedef enum { + AUDIO_BUFFER_USAGE_STATIC = 0, + AUDIO_BUFFER_USAGE_STREAM +} AudioBufferUsage; + +// Audio buffer struct +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 + 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 char *data; // Data buffer, on music stream keeps filling + + rAudioBuffer *next; // Next audio buffer on the list + 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 +typedef struct AudioData { + struct { + ma_context context; // miniaudio context data + 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; +} AudioData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static AudioData AUDIO = { // Global AUDIO context + + // NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number + // 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 +}; + +//---------------------------------------------------------------------------------- +// 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 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 bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer); +static void StopAudioBufferInLockedState(AudioBuffer *buffer); +static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount); + +#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 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 bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated +#endif + +//---------------------------------------------------------------------------------- +// AudioBuffer management functions declaration +// NOTE: Those functions are not exposed by raylib... for the moment +//---------------------------------------------------------------------------------- +AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage); +void UnloadAudioBuffer(AudioBuffer *buffer); + +bool IsAudioBufferPlaying(AudioBuffer *buffer); +void PlayAudioBuffer(AudioBuffer *buffer); +void StopAudioBuffer(AudioBuffer *buffer); +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); + + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Audio Device initialization and Closing +//---------------------------------------------------------------------------------- +// Initialize audio device +void InitAudioDevice(void) +{ + // Init audio context + ma_context_config ctxConfig = ma_context_config_init(); + ma_log_callback_init(OnLog, NULL); + + ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context); + if (result != MA_SUCCESS) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize context"); + return; + } + + // Init audio device + // 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.format = AUDIO_DEVICE_FORMAT; + config.playback.channels = AUDIO_DEVICE_CHANNELS; + 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; + config.dataCallback = OnSendAudioDataToDevice; + config.pUserData = NULL; + + result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device); + if (result != MA_SUCCESS) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize playback device"); + ma_context_uninit(&AUDIO.System.context); + 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 + result = ma_device_start(&AUDIO.System.device); + if (result != MA_SUCCESS) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to start playback device"); + ma_device_uninit(&AUDIO.System.device); + ma_context_uninit(&AUDIO.System.context); + return; + } + + TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully"); + 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); + TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods); + + AUDIO.System.isReady = true; +} + +// Close the audio device for all contexts +void CloseAudioDevice(void) +{ + if (AUDIO.System.isReady) + { + 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"); + } + else TRACELOG(LOG_WARNING, "AUDIO: Device could not be closed, not currently initialized"); +} + +// Check if device has been initialized successfully +bool IsAudioDeviceReady(void) +{ + return AUDIO.System.isReady; +} + +// Set master volume (listener) +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 +//---------------------------------------------------------------------------------- + +// Initialize a new audio buffer (filled with silence) +AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage) +{ + AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer)); + + if (audioBuffer == NULL) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to allocate memory for buffer"); + return NULL; + } + + if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1); + + // 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; + + ma_result result = ma_data_converter_init(&converterConfig, NULL, &audioBuffer->converter); + + if (result != MA_SUCCESS) + { + TRACELOG(LOG_WARNING, "AUDIO: Failed to create data conversion pipeline"); + RL_FREE(audioBuffer); + return NULL; + } + + // 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 + // UpdateAudioStream() immediately after initialization works correctly + audioBuffer->isSubBufferProcessed[0] = true; + audioBuffer->isSubBufferProcessed[1] = true; + + // Track audio buffer to linked list next position + TrackAudioBuffer(audioBuffer); + + return audioBuffer; +} + +// Delete an audio buffer +void UnloadAudioBuffer(AudioBuffer *buffer) +{ + if (buffer != NULL) + { + 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 +bool IsAudioBufferPlaying(AudioBuffer *buffer) +{ + bool result = false; + ma_mutex_lock(&AUDIO.System.lock); + result = IsAudioBufferPlayingInLockedState(buffer); + ma_mutex_unlock(&AUDIO.System.lock); + return result; +} + +// Play an audio buffer +// 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 +void StopAudioBuffer(AudioBuffer *buffer) +{ + ma_mutex_lock(&AUDIO.System.lock); + StopAudioBufferInLockedState(buffer); + ma_mutex_unlock(&AUDIO.System.lock); +} + +// 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); + } +} + +// 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); + } +} + +// 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); + } +} + +// Set pitch for an audio buffer +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 + // 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); + + 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); + } +} + +// Track audio buffer to linked list next position +void TrackAudioBuffer(AudioBuffer *buffer) +{ + ma_mutex_lock(&AUDIO.System.lock); + { + if (AUDIO.Buffer.first == NULL) AUDIO.Buffer.first = buffer; + else + { + AUDIO.Buffer.last->next = buffer; + buffer->prev = AUDIO.Buffer.last; + } + + AUDIO.Buffer.last = buffer; + } + ma_mutex_unlock(&AUDIO.System.lock); +} + +// Untrack audio buffer from linked list +void UntrackAudioBuffer(AudioBuffer *buffer) +{ + ma_mutex_lock(&AUDIO.System.lock); + { + if (buffer->prev == NULL) AUDIO.Buffer.first = buffer->next; + else buffer->prev->next = buffer->next; + + if (buffer->next == NULL) AUDIO.Buffer.last = buffer->prev; + else buffer->next->prev = buffer->prev; + + buffer->prev = NULL; + buffer->next = NULL; + } + ma_mutex_unlock(&AUDIO.System.lock); +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Sounds loading and playing (.WAV) +//---------------------------------------------------------------------------------- + +// Load wave data from file +Wave LoadWave(const char *fileName) +{ + Wave wave = { 0 }; + + // Loading file to memory + int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + // Loading wave from memory data + if (fileData != NULL) wave = LoadWaveFromMemory(GetFileExtension(fileName), fileData, dataSize); + + UnloadFileData(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 }; + + 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); + } +#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"); + + } +#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"); + } +#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); + + 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) +{ + Wave wave = LoadWave(fileName); + + Sound sound = LoadSoundFromWave(wave); + + UnloadWave(wave); // Sound is loaded, we can unload wave + + return sound; +} + +// Load sound from wave data +// NOTE: Wave data must be unallocated manually +Sound LoadSoundFromWave(Wave wave) +{ + Sound sound = { 0 }; + + if (wave.data != NULL) + { + // 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 + // + // 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; + + 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"); + + AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, frameCount, 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 + } + + 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.stream.sampleRate = AUDIO.System.device.sampleRate; + sound.stream.sampleSize = 32; + sound.stream.channels = AUDIO_DEVICE_CHANNELS; + sound.stream.buffer = audioBuffer; + } + + 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"); +} + +// 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); + } +} + +// Update sound buffer with new data +void UpdateSound(Sound sound, const void *data, int frameCount) +{ + 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)); + } +} + +// Export wave data to file +bool ExportWave(Wave wave, const char *fileName) +{ + bool success = false; + + 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"); + } +#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); + } + + if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName); + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave data", fileName); + + return success; +} + +// Export wave sample data to code (.h) +bool ExportWaveAsCode(Wave wave, const char *fileName) +{ + bool success = false; + +#ifndef TEXT_BYTES_PER_LINE + #define TEXT_BYTES_PER_LINE 20 +#endif + + int waveDataSize = wave.frameCount*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)); + + 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"); + + // 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 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); + + // 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]); + } + + // 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; +} + +// Play a sound +void PlaySound(Sound sound) +{ + PlayAudioBuffer(sound.stream.buffer); +} + +// Pause a sound +void PauseSound(Sound sound) +{ + PauseAudioBuffer(sound.stream.buffer); +} + +// Resume a paused sound +void ResumeSound(Sound sound) +{ + ResumeAudioBuffer(sound.stream.buffer); +} + +// Stop reproducing a sound +void StopSound(Sound sound) +{ + StopAudioBuffer(sound.stream.buffer); +} + +// Check if a sound is playing +bool IsSoundPlaying(Sound sound) +{ + bool result = false; + + if (IsAudioBufferPlaying(sound.stream.buffer)) result = true; + + return result; +} + +// Set volume for a sound +void SetSoundVolume(Sound sound, float volume) +{ + SetAudioBufferVolume(sound.stream.buffer, volume); +} + +// Set pitch for a sound +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); + + if (frameCount == 0) + { + TRACELOG(LOG_WARNING, "WAVE: Failed to get frame count for format conversion"); + return; + } + + void *data = RL_MALLOC(frameCount*channels*(sampleSize/8)); + + 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->sampleSize = sampleSize; + wave->sampleRate = sampleRate; + wave->channels = channels; + + RL_FREE(wave->data); + wave->data = data; +} + +// Copy a wave to a new wave +Wave WaveCopy(Wave wave) +{ + Wave newWave = { 0 }; + + newWave.data = RL_MALLOC(wave.frameCount*wave.channels*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); + + newWave.frameCount = wave.frameCount; + newWave.sampleRate = wave.sampleRate; + newWave.sampleSize = wave.sampleSize; + newWave.channels = wave.channels; + } + + return newWave; +} + +// Crop a wave to defined frames range +// NOTE: Security check in case of out-of-range +void WaveCrop(Wave *wave, int initFrame, int finalFrame) +{ + if ((initFrame >= 0) && (initFrame < finalFrame) && ((unsigned int)finalFrame <= wave->frameCount)) + { + int frameCount = finalFrame - initFrame; + + void *data = RL_MALLOC(frameCount*wave->channels*wave->sampleSize/8); + + memcpy(data, (unsigned char *)wave->data + (initFrame*wave->channels*wave->sampleSize/8), frameCount*wave->channels*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"); +} + +// Load samples data from wave as a floats array +// NOTE 1: Returned sample values are normalized to range [-1..1] +// 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)); + + // NOTE: sampleCount is the total number of interlaced samples (including channels) + + for (unsigned int i = 0; i < wave.frameCount*wave.channels; 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; + else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i]; + } + + return samples; +} + +// Unload samples data loaded with LoadWaveSamples() +void UnloadWaveSamples(float *samples) +{ + RL_FREE(samples); +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Music loading and stream playing +//---------------------------------------------------------------------------------- + +// Load music stream from file +Music LoadMusicStream(const char *fileName) +{ + Music music = { 0 }; + bool musicLoaded = false; + + if (false) { } +#if defined(SUPPORT_FILEFORMAT_WAV) + else if (IsFileExtension(fileName, ".wav")) + { + drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav)); + bool success = drwav_init_file(ctxWav, fileName, NULL); + + 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.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); + + if (ctxOgg != 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); + + // 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.looping = true; // Looping enabled by default + musicLoaded = true; + } + else + { + stb_vorbis_close(ctxOgg); + } + } +#endif +#if defined(SUPPORT_FILEFORMAT_MP3) + else if (IsFileExtension(fileName, ".mp3")) + { + drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3)); + int result = drmp3_init_file(ctxMp3, fileName, NULL); + + 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.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) + else if (IsFileExtension(fileName, ".xm")) + { + jar_xm_context_t *ctxXm = NULL; + int result = jar_xm_create_context_from_file(&ctxXm, AUDIO.System.device.sampleRate, fileName); + + 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; + + // 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.looping = true; // Looping enabled by default + 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_init(ctxMod); + int result = jar_mod_load_file(ctxMod, fileName); + + 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.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); + + if (!musicLoaded) + { + 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, " > 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) +{ + Music music = { 0 }; + bool musicLoaded = false; + + if (false) { } +#if defined(SUPPORT_FILEFORMAT_WAV) + else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0)) + { + drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav)); + + bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL); + + 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.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)) + { + // Open ogg audio stream + stb_vorbis *ctxOgg = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL); + + if (ctxOgg != 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); + + // 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.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)) + { + drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3)); + int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL); + + 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.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)) + { + qoaplay_desc *ctxQoa = NULL; + if ((data != NULL) && (dataSize > 0)) + { + ctxQoa = qoaplay_open_memory(data, dataSize); + } + + 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 ((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)) + { + jar_xm_context_t *ctxXm = NULL; + 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; + + // 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.looping = true; // Looping enabled by default + 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 ((strcmp(fileType, ".mod") == 0) || (strcmp(fileType, ".MOD") == 0)) + { + jar_mod_context_t *ctxMod = (jar_mod_context_t *)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); + int it = dataSize/sizeof(unsigned char); + 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)) + { + ctxMod->modfilesize = dataSize; + ctxMod->modfile = newData; + if (jar_mod_load(ctxMod, (void *)ctxMod->modfile, dataSize)) result = dataSize; + } + + 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.looping = true; // Looping enabled by default + musicLoaded = true; + } + else + { + jar_mod_unload(ctxMod); + RL_FREE(ctxMod); + } + } +#endif + else TRACELOG(LOG_WARNING, "STREAM: Data format not supported"); + + if (!musicLoaded) + { + TRACELOG(LOG_WARNING, "FILEIO: Music data could not be loaded"); + } + else + { + // Show some music stream info + TRACELOG(LOG_INFO, "FILEIO: Music data loaded successfully"); + 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); + + if (music.ctxData != NULL) + { + 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_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_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 + } +} + +// Start music playing (open stream) from beginning +void PlayMusicStream(Music music) +{ + PlayAudioStream(music.stream); +} + +// Pause music playing +void PauseMusicStream(Music music) +{ + PauseAudioStream(music.stream); +} + +// Resume music playing +void ResumeMusicStream(Music music) +{ + ResumeAudioStream(music.stream); +} + +// Stop music playing (close stream) +void StopMusicStream(Music music) +{ + StopAudioStream(music.stream); + + switch (music.ctxType) + { +#if defined(SUPPORT_FILEFORMAT_WAV) + case MUSIC_AUDIO_WAV: drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); 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; +#endif +#if defined(SUPPORT_FILEFORMAT_XM) + case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break; +#endif +#if defined(SUPPORT_FILEFORMAT_MOD) + case MUSIC_MODULE_MOD: jar_mod_seek_start((jar_mod_context_t *)music.ctxData); break; +#endif + default: break; + } +} + +// 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); + + 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; + + if (AUDIO.System.pcmBufferSize < pcmSize) + { + 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; + + 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); + } + } + } 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); + } + */ + } 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); + } + } 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); + + } break; + #endif + #if defined(SUPPORT_FILEFORMAT_MOD) + 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); + + } break; + #endif + default: break; + } + + UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream); + + music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount; + + if (framesLeft <= subBufferSizeInFrames) + { + if (!music.looping) + { + ma_mutex_unlock(&AUDIO.System.lock); + // Streaming is ending, we filled latest frames from input + StopMusicStream(music); + return; + } + } + } + + ma_mutex_unlock(&AUDIO.System.lock); +} + +// Check if any music is playing +bool IsMusicStreamPlaying(Music music) +{ + return IsAudioStreamPlaying(music.stream); +} + +// Set volume for music +void SetMusicVolume(Music music, float volume) +{ + SetAudioStreamVolume(music.stream, volume); +} + +// Set pitch for music +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; + + return totalSeconds; +} + +// Get current music time played (in seconds) +float GetMusicTimePlayed(Music music) +{ + 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); + } + } + + return secondsPlayed; +} + +// Load audio stream (to stream audio pcm data) +AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) +{ + AudioStream stream = { 0 }; + + stream.sampleRate = sampleRate; + stream.sampleSize = sampleSize; + stream.channels = channels; + + ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32)); + + // 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; + + if (subBufferSize < periodSize) subBufferSize = periodSize; + + // Create a double audio buffer of defined size + stream.buffer = LoadAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM); + + if (stream.buffer != NULL) + { + stream.buffer->looping = true; // Always loop for streaming buffers + TRACELOG(LOG_INFO, "STREAM: Initialized successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo"); + } + else TRACELOG(LOG_WARNING, "STREAM: Failed to load audio buffer, stream could not be created"); + + 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) +{ + UnloadAudioBuffer(stream.buffer); + + TRACELOG(LOG_INFO, "STREAM: Unloaded audio stream data from RAM"); +} + +// 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) +{ + ma_mutex_lock(&AUDIO.System.lock); + UpdateAudioStreamInLockedState(stream, data, frameCount); + ma_mutex_unlock(&AUDIO.System.lock); +} + +// Check if any audio stream buffers requires refill +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; +} + +// Play audio stream +void PlayAudioStream(AudioStream stream) +{ + PlayAudioBuffer(stream.buffer); +} + +// Play audio stream +void PauseAudioStream(AudioStream stream) +{ + PauseAudioBuffer(stream.buffer); +} + +// Resume audio stream playing +void ResumeAudioStream(AudioStream stream) +{ + ResumeAudioBuffer(stream.buffer); +} + +// Check if audio stream is playing +bool IsAudioStreamPlaying(AudioStream stream) +{ + return IsAudioBufferPlaying(stream.buffer); +} + +// Stop audio stream +void StopAudioStream(AudioStream stream) +{ + StopAudioBuffer(stream.buffer); +} + +// Set volume for audio stream (1.0 is max level) +void SetAudioStreamVolume(AudioStream stream, float volume) +{ + SetAudioBufferVolume(stream.buffer, volume); +} + +// Set pitch for audio stream (1.0 is base level) +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) +{ + if (stream.buffer != NULL) + { + ma_mutex_lock(&AUDIO.System.lock); + stream.buffer->callback = callback; + ma_mutex_unlock(&AUDIO.System.lock); + } +} + +// 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) +{ + TRACELOG(LOG_WARNING, "miniaudio: %s", pMessage); // All log messages from miniaudio are errors +} + +// 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 + // we just take a copy here to try and avoid potential synchronization problems + bool isSubBufferProcessed[2] = { 0 }; + isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0]; + isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1]; + + ma_uint32 frameSizeInBytes = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.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; + while (1) + { + // 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 + // Unprocessed halves must keep their audio data in-tact + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) + { + if (framesRead >= frameCount) break; + } + else + { + if (isSubBufferProcessed[currentSubBufferIndex]) break; + } + + ma_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining == 0) break; + + ma_uint32 framesRemainingInOutputBuffer; + if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) + { + framesRemainingInOutputBuffer = audioBuffer->sizeInFrames - audioBuffer->frameCursorPos; + } + else + { + ma_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames*currentSubBufferIndex; + framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer); + } + + ma_uint32 framesToRead = totalFramesRemaining; + if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer; + + memcpy((unsigned char *)framesOut + (framesRead*frameSizeInBytes), audioBuffer->data + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes); + audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->sizeInFrames; + framesRead += framesToRead; + + // If we've read to the end of the buffer, mark it as processed + if (framesToRead == framesRemainingInOutputBuffer) + { + audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true; + isSubBufferProcessed[currentSubBufferIndex] = true; + + currentSubBufferIndex = (currentSubBufferIndex + 1)%2; + + // We need to break from this loop if we're not looping + if (!audioBuffer->looping) + { + StopAudioBufferInLockedState(audioBuffer); + break; + } + } + } + + // Zero-fill excess + ma_uint32 totalFramesRemaining = (frameCount - framesRead); + if (totalFramesRemaining > 0) + { + memset((unsigned char *)framesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); + + // 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 + 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 +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); + + 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); + if (inputFramesToProcessThisIteration > inputBufferFrameCap) + { + inputFramesToProcessThisIteration = inputBufferFrameCap; + } + + float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut); + + // At this point we can convert the data to our mixing format + ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration); + ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration; + ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration); + + totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; // Safe cast + + 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; + } + + 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) +{ + (void)pDevice; + + // Mixing is basically just an accumulation, we need to initialize the output buffer to 0 + memset(pFramesOut, 0, frameCount*pDevice->playback.channels*ma_get_bytes_per_sample(pDevice->playback.format)); + + // Using a mutex here for thread-safety which makes things not real-time + // This is unlikely to be necessary for this project, but may want to consider how you might want to avoid this + ma_mutex_lock(&AUDIO.System.lock); + { + for (AudioBuffer *audioBuffer = AUDIO.Buffer.first; audioBuffer != NULL; audioBuffer = audioBuffer->next) + { + // Ignore stopped or paused sounds + if (!audioBuffer->playing || audioBuffer->paused) continue; + + ma_uint32 framesRead = 0; + + while (1) + { + if (framesRead >= frameCount) break; + + // Just read as much data as we can from the stream + ma_uint32 framesToRead = (frameCount - framesRead); + + while (framesToRead > 0) + { + float tempBuffer[1024] = { 0 }; // Frames for stereo + + ma_uint32 framesToReadRightNow = framesToRead; + if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS) + { + framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS; + } + + ma_uint32 framesJustRead = ReadAudioBufferFramesInMixingFormat(audioBuffer, tempBuffer, framesToReadRightNow); + if (framesJustRead > 0) + { + float *framesOut = (float *)pFramesOut + (framesRead*AUDIO.System.device.playback.channels); + 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); + + framesToRead -= framesJustRead; + framesRead += framesJustRead; + } + + if (!audioBuffer->playing) + { + framesRead = frameCount; + break; + } + + // If we weren't able to read all the frames we requested, break + if (framesJustRead < framesToReadRightNow) + { + if (!audioBuffer->looping) + { + StopAudioBufferInLockedState(audioBuffer); + break; + } + else + { + // Should never get here, but just for safety, + // move the cursor position back to the start and continue the loop + audioBuffer->frameCursorPos = 0; + continue; + } + } + } + + // If for some reason we weren't able to read every frame we'll need to break from the loop + // Not doing this could theoretically put us into an infinite loop + if (framesToRead > 0) break; + } + } + } + + 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) +{ + const float localVolume = buffer->volume; + const ma_uint32 channels = AUDIO.System.device.playback.channels; + + if (channels == 2) // We consider panning + { + 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++) + { + frameOut[0] += (frameIn[0]*levels[0]); + frameOut[1] += (frameIn[1]*levels[1]); + + 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); + } + } + } +} + +// Check if an audio buffer is playing, assuming the audio system mutex has been locked +static bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer) +{ + bool result = false; + + if (buffer != NULL) result = (buffer->playing && !buffer->paused); + + return result; +} + +// Stop an audio buffer, assuming the audio system mutex has been locked +static void StopAudioBufferInLockedState(AudioBuffer *buffer) +{ + if (buffer != NULL) + { + if (IsAudioBufferPlayingInLockedState(buffer)) + { + buffer->playing = false; + buffer->paused = false; + buffer->frameCursorPos = 0; + buffer->framesProcessed = 0; + buffer->isSubBufferProcessed[0] = true; + buffer->isSubBufferProcessed[1] = true; + } + } +} + +// Update audio stream, assuming the audio system mutex has been locked +static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount) +{ + 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); + + // Total frames processed in buffer is always the complete size, filled with 0 if required + stream.buffer->framesProcessed += 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)frameCount) + { + ma_uint32 framesToWrite = (ma_uint32)frameCount; + + 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"); + } +} + +// Some required functions for audio standalone module version +#if defined(RAUDIO_STANDALONE) +// Check file extension +static bool IsFileExtension(const char *fileName, const char *ext) +{ + bool result = false; + const char *fileExt; + + if ((fileExt = strrchr(fileName, '.')) != NULL) + { + if (strcmp(fileExt, ext) == 0) result = true; + } + + return result; +} + +// Get pointer to extension for a filename string (includes the dot: .png) +static 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 +static 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) +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++) + { + if (fileName[i] == '.') + { + // NOTE: We break on first '.' found + fileName[i] = '\0'; + break; + } + } + + return fileName; +} + +// Load data from file into a buffer +static unsigned char *LoadFileData(const char *fileName, int *dataSize) +{ + unsigned char *data = NULL; + *dataSize = 0; + + if (fileName != NULL) + { + FILE *file = fopen(fileName, "rb"); + + if (file != NULL) + { + // 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); + fseek(file, 0, SEEK_SET); + + if (size > 0) + { + data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char)); + + // 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; + + 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); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); + } + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + + return data; +} + +// Save data to file from buffer +static bool SaveFileData(const char *fileName, void *data, int dataSize) +{ + if (fileName != NULL) + { + FILE *file = fopen(fileName, "wb"); + + if (file != NULL) + { + unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), dataSize, 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 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: File name provided is not valid"); + return false; + } + + return true; +} + +// Save text data to file (write), string must be '\0' terminated +static bool SaveFileText(const char *fileName, char *text) +{ + if (fileName != NULL) + { + FILE *file = fopen(fileName, "wt"); + + if (file != NULL) + { + int count = fprintf(file, "%s", text); + + if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName); + else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName); + + fclose(file); + } + else + { + TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); + return false; + } + } + else + { + TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + return false; + } + + return true; +} +#endif + +#undef AudioBuffer + +#endif // SUPPORT_MODULE_RAUDIO diff --git a/raylib/raudio.go b/raylib/raudio.go new file mode 100644 index 0000000..129a71e --- /dev/null +++ b/raylib/raudio.go @@ -0,0 +1,558 @@ +//go:build !noaudio +// +build !noaudio + +package rl + +/* +#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) +} + +// 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() +} + +// CloseAudioDevice - Close the audio device and context +func CloseAudioDevice() { + C.CloseAudioDevice() +} + +// IsAudioDeviceReady - Check if audio device has been initialized successfully +func IsAudioDeviceReady() bool { + ret := C.IsAudioDeviceReady() + v := bool(ret) + return v +} + +// SetMasterVolume - Set master volume (listener) +func SetMasterVolume(volume float32) { + cvolume := (C.float)(volume) + 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) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadWave(cfileName) + v := newWaveFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadWaveFromMemory - Load wave from memory buffer, fileType refers to extension: i.e. ".wav" +func LoadWaveFromMemory(fileType string, fileData []byte, dataSize int32) Wave { + cfileType := C.CString(fileType) + defer C.free(unsafe.Pointer(cfileType)) + cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) + cdataSize := (C.int)(dataSize) + ret := C.LoadWaveFromMemory(cfileType, cfileData, cdataSize) + v := newWaveFromPointer(unsafe.Pointer(&ret)) + 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) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadSound(cfileName) + v := newSoundFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadSoundFromWave - Load sound to memory from wave data +func LoadSoundFromWave(wave Wave) Sound { + cwave := wave.cptr() + ret := C.LoadSoundFromWave(*cwave) + v := newSoundFromPointer(unsafe.Pointer(&ret)) + 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() + cdata := unsafe.Pointer(&data[0]) + csamplesCount := (C.int)(samplesCount) + C.UpdateSound(*csound, cdata, csamplesCount) +} + +// UnloadWave - Unload wave data +func UnloadWave(wave Wave) { + cwave := wave.cptr() + C.UnloadWave(*cwave) +} + +// UnloadSound - Unload sound +func UnloadSound(sound Sound) { + csound := sound.cptr() + 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() + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + C.ExportWave(*cwave, cfileName) +} + +// PlaySound - Play a sound +func PlaySound(sound Sound) { + csound := sound.cptr() + 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() + C.PauseSound(*csound) +} + +// ResumeSound - Resume a paused sound +func ResumeSound(sound Sound) { + csound := sound.cptr() + C.ResumeSound(*csound) +} + +// IsSoundPlaying - Check if a sound is currently playing +func IsSoundPlaying(sound Sound) bool { + csound := sound.cptr() + ret := C.IsSoundPlaying(*csound) + v := bool(ret) + return v +} + +// SetSoundVolume - Set volume for a sound (1.0 is max level) +func SetSoundVolume(sound Sound, volume float32) { + csound := sound.cptr() + cvolume := (C.float)(volume) + C.SetSoundVolume(*csound, cvolume) +} + +// SetSoundPitch - Set pitch for a sound (1.0 is base level) +func SetSoundPitch(sound Sound, pitch float32) { + csound := sound.cptr() + cpitch := (C.float)(pitch) + 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) { + cwave := wave.cptr() + csampleRate := (C.int)(sampleRate) + csampleSize := (C.int)(sampleSize) + cchannels := (C.int)(channels) + C.WaveFormat(cwave, csampleRate, csampleSize, cchannels) +} + +// WaveCopy - Copy a wave to a new wave +func WaveCopy(wave Wave) Wave { + cwave := wave.cptr() + ret := C.WaveCopy(*cwave) + v := newWaveFromPointer(unsafe.Pointer(&ret)) + return v +} + +// WaveCrop - Crop a wave to defined frames range +func WaveCrop(wave *Wave, initFrame int32, finalFrame int32) { + cwave := wave.cptr() + cinitFrame := (C.int)(initFrame) + cfinalFrame := (C.int)(finalFrame) + C.WaveCrop(cwave, cinitFrame, cfinalFrame) +} + +// LoadWaveSamples - Get samples data from wave as a floats array +func LoadWaveSamples(wave Wave) []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]))) +} + +// LoadMusicStream - Load music stream from file +func LoadMusicStream(fileName string) Music { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadMusicStream(cfileName) + v := newMusicFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadMusicStreamFromMemory - Load music stream from data +func LoadMusicStreamFromMemory(fileType string, fileData []byte, dataSize int32) Music { + cfileType := C.CString(fileType) + defer C.free(unsafe.Pointer(cfileType)) + cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) + cdataSize := (C.int)(dataSize) + ret := C.LoadMusicStreamFromMemory(cfileType, cfileData, cdataSize) + v := newMusicFromPointer(unsafe.Pointer(&ret)) + 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)) + C.UnloadMusicStream(cmusic) +} + +// PlayMusicStream - Start music playing +func PlayMusicStream(music Music) { + cmusic := *(*C.Music)(unsafe.Pointer(&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)) + C.UpdateMusicStream(cmusic) +} + +// StopMusicStream - Stop music playing +func StopMusicStream(music Music) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + C.StopMusicStream(cmusic) +} + +// PauseMusicStream - Pause music playing +func PauseMusicStream(music Music) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + C.PauseMusicStream(cmusic) +} + +// ResumeMusicStream - Resume playing paused music +func ResumeMusicStream(music Music) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + C.ResumeMusicStream(cmusic) +} + +// SeekMusicStream - Seek music to a position (in seconds) +func SeekMusicStream(music Music, position float32) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + cposition := (C.float)(position) + C.SeekMusicStream(cmusic, cposition) +} + +// SetMusicVolume - Set volume for music (1.0 is max level) +func SetMusicVolume(music Music, volume float32) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + cvolume := (C.float)(volume) + C.SetMusicVolume(cmusic, cvolume) +} + +// SetMusicPitch - Set pitch for a music (1.0 is base level) +func SetMusicPitch(music Music, pitch float32) { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + cpitch := (C.float)(pitch) + 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)) + ret := C.GetMusicTimeLength(cmusic) + v := (float32)(ret) + return v +} + +// GetMusicTimePlayed - Get current music time played (in seconds) +func GetMusicTimePlayed(music Music) float32 { + cmusic := *(*C.Music)(unsafe.Pointer(&music)) + ret := C.GetMusicTimePlayed(cmusic) + v := (float32)(ret) + return v +} + +// LoadAudioStream - Load audio stream (to stream raw audio pcm data) +func LoadAudioStream(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) + 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) { + cstream := stream.cptr() + cdata := unsafe.Pointer(&data[0]) + csamplesCount := (C.int)(len(data)) + C.UpdateAudioStream(*cstream, cdata, csamplesCount) +} + +// IsAudioStreamProcessed - Check if any audio stream buffers requires refill +func IsAudioStreamProcessed(stream AudioStream) bool { + cstream := stream.cptr() + ret := C.IsAudioStreamProcessed(*cstream) + v := bool(ret) + return v +} + +// PlayAudioStream - Play audio stream +func PlayAudioStream(stream AudioStream) { + cstream := stream.cptr() + C.PlayAudioStream(*cstream) +} + +// PauseAudioStream - Pause audio stream +func PauseAudioStream(stream AudioStream) { + cstream := stream.cptr() + C.PauseAudioStream(*cstream) +} + +// ResumeAudioStream - Resume audio stream +func ResumeAudioStream(stream AudioStream) { + cstream := stream.cptr() + 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) +} + +// 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) +} + +// 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) +} diff --git a/raylib/raylib.go b/raylib/raylib.go index 0873232..0cd3126 100644 --- a/raylib/raylib.go +++ b/raylib/raylib.go @@ -1,42 +1,15 @@ /* -Package raylib - Go bindings for raylib, a simple and easy-to-use library to learn videogames programming. +Package raylib - Go bindings for raylib, a simple and easy-to-use library to enjoy 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() { - raylib.InitWindow(800, 450, "raylib [core] example - basic window") - - raylib.SetTargetFPS(60) - - for !raylib.WindowShouldClose() { - raylib.BeginDrawing() - - raylib.ClearBackground(raylib.RayWhite) - - raylib.DrawText("Congrats! You created your first window!", 190, 200, 20, raylib.LightGray) - - raylib.EndDrawing() - } - - raylib.CloseWindow() - } - - */ -package raylib +package rl import ( - "image" + "image/color" "io" "runtime" "unsafe" @@ -50,7 +23,7 @@ func init() { // Wave type, defines audio wave data type Wave struct { // Number of samples - SampleCount uint32 + FrameCount uint32 // Frequency (samples per second) SampleRate uint32 // Bit depth (bits per sample): 8, 16, 32 (24 not supported) @@ -58,85 +31,159 @@ 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} } -// newWaveFromPointer - Returns new Wave from pointer -func newWaveFromPointer(ptr unsafe.Pointer) Wave { - return *(*Wave)(ptr) -} +// AudioCallback function. +type AudioCallback func(data []float32, frames int) // Sound source type type Sound struct { - // Audio source id - Source uint32 - // Audio buffer id - Buffer uint32 - // Audio format specifier - Format int32 -} - -// NewSound - Returns new Sound -func NewSound(source, buffer uint32, format int32) Sound { - return Sound{source, buffer, format} -} - -// newSoundFromPointer - Returns new Sound from pointer -func newSoundFromPointer(ptr unsafe.Pointer) Sound { - return *(*Sound)(ptr) + Stream AudioStream + FrameCount uint32 + _ [4]byte } // Music type (file streaming from memory) // NOTE: Anything longer than ~10 seconds should be streamed type Music struct { - CtxType uint32 - _ [4]byte - ctxOgg unsafe.Pointer - ctxFlac unsafe.Pointer - ctxXm unsafe.Pointer - ctxMod unsafe.Pointer - Stream AudioStream - LoopCount int32 - TotalSamples uint32 - SamplesLeft uint32 -} - -// newMusicFromPointer - Returns new Music from pointer -func newMusicFromPointer(ptr unsafe.Pointer) Music { - return *(*Music)(ptr) + Stream AudioStream + FrameCount uint32 + Looping bool + CtxType int32 + CtxData unsafe.Pointer } // AudioStream type // NOTE: Useful to create custom audio streams not bound to a specific file type AudioStream struct { + // Buffer + Buffer *AudioBuffer + // Processor + Processor *AudioProcessor // Frequency (samples per second) SampleRate uint32 // Bit depth (bits per sample): 8, 16, 32 (24 not supported) SampleSize uint32 // Number of channels (1-mono, 2-stereo) Channels uint32 - // Audio format specifier - Format int32 - // Audio source id - Source uint32 - // Audio buffers (double buffering) - Buffers [2]uint32 + _ [4]byte } -// NewAudioStream - Returns new AudioStream -func NewAudioStream(sampleRate, sampleSize, channels uint32, format int32, source uint32, buffers [2]uint32) AudioStream { - return AudioStream{sampleRate, sampleSize, channels, format, source, buffers} +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 } -// newAudioStreamFromPointer - Returns new AudioStream from pointer -func newAudioStreamFromPointer(ptr unsafe.Pointer) AudioStream { - return *(*AudioStream)(ptr) +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) } // CameraMode type @@ -151,12 +198,12 @@ const ( CameraThirdPerson ) -// CameraType type -type CameraType int32 +// CameraProjection type +type CameraProjection int32 // Camera projection modes const ( - CameraPerspective CameraType = iota + CameraPerspective CameraProjection = iota CameraOrthographic ) @@ -168,20 +215,41 @@ const ( // Raylib Config Flags - // Set to show raylib logo at startup - FlagShowLogo = 1 - // Set to run program in fullscreen - FlagFullscreenMode = 2 - // Set to allow resizable window - FlagWindowResizable = 4 - // Set to show window decoration (frame and buttons) - FlagWindowDecorated = 8 - // Set to allow transparent window - FlagWindowTransparent = 16 - // Set to try enabling MSAA 4X - FlagMsaa4xHint = 32 // Set to try enabling V-Sync on GPU - FlagVsyncHint = 64 + FlagVsyncHint = 0x00000040 + // Set to run program in fullscreen + FlagFullscreenMode = 0x00000002 + // Set to allow resizable window + FlagWindowResizable = 0x00000004 + // Set to disable window decoration (frame and buttons) + FlagWindowUndecorated = 0x00000008 + // Set to hide window + FlagWindowHidden = 0x00000080 + // Set to minimize window (iconify) + FlagWindowMinimized = 0x00000200 + // Set to maximize window (expanded to monitor) + FlagWindowMaximized = 0x00000400 + // Set to window non focused + FlagWindowUnfocused = 0x00000800 + // Set to window always on top + FlagWindowTopmost = 0x00001000 + // Set to allow windows running while minimized + FlagWindowAlwaysRun = 0x00000100 + // Set to allow transparent window + FlagWindowTransparent = 0x00000010 + // 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 + // Set to try enabling MSAA 4X + FlagMsaa4xHint = 0x00000020 + // Set to try enabling interlaced video format (for V3D) + FlagInterlacedHint = 0x00010000 + + // KeyNull is used for no key pressed + KeyNull = 0 // Keyboard Function Keys KeySpace = 32 @@ -219,128 +287,152 @@ const ( KeyLeftShift = 340 KeyLeftControl = 341 KeyLeftAlt = 342 + KeyLeftSuper = 343 KeyRightShift = 344 KeyRightControl = 345 KeyRightAlt = 346 - KeyGrave = 96 - KeySlash = 47 + KeyRightSuper = 347 + KeyKbMenu = 348 + KeyLeftBracket = 91 KeyBackSlash = 92 + KeyRightBracket = 93 + KeyGrave = 96 + + // Keyboard Number Pad Keys + KeyKp0 = 320 + KeyKp1 = 321 + KeyKp2 = 322 + KeyKp3 = 323 + KeyKp4 = 324 + KeyKp5 = 325 + KeyKp6 = 326 + KeyKp7 = 327 + KeyKp8 = 328 + KeyKp9 = 329 + KeyKpDecimal = 330 + KeyKpDivide = 331 + KeyKpMultiply = 332 + KeyKpSubtract = 333 + KeyKpAdd = 334 + KeyKpEnter = 335 + KeyKpEqual = 336 // Keyboard Alpha Numeric Keys - KeyZero = 48 - KeyOne = 49 - KeyTwo = 50 - KeyThree = 51 - KeyFour = 52 - KeyFive = 53 - KeySix = 54 - KeySeven = 55 - KeyEight = 56 - KeyNine = 57 - KeyA = 65 - KeyB = 66 - KeyC = 67 - KeyD = 68 - KeyE = 69 - KeyF = 70 - KeyG = 71 - KeyH = 72 - KeyI = 73 - KeyJ = 74 - KeyK = 75 - KeyL = 76 - KeyM = 77 - KeyN = 78 - KeyO = 79 - KeyP = 80 - KeyQ = 81 - KeyR = 82 - KeyS = 83 - KeyT = 84 - KeyU = 85 - KeyV = 86 - KeyW = 87 - KeyX = 88 - KeyY = 89 - KeyZ = 90 + KeyApostrophe = 39 + KeyComma = 44 + KeyMinus = 45 + KeyPeriod = 46 + KeySlash = 47 + KeyZero = 48 + KeyOne = 49 + KeyTwo = 50 + KeyThree = 51 + KeyFour = 52 + KeyFive = 53 + KeySix = 54 + KeySeven = 55 + KeyEight = 56 + KeyNine = 57 + KeySemicolon = 59 + KeyEqual = 61 + KeyA = 65 + KeyB = 66 + KeyC = 67 + KeyD = 68 + KeyE = 69 + KeyF = 70 + KeyG = 71 + KeyH = 72 + KeyI = 73 + KeyJ = 74 + KeyK = 75 + KeyL = 76 + KeyM = 77 + KeyN = 78 + KeyO = 79 + KeyP = 80 + KeyQ = 81 + KeyR = 82 + KeyS = 83 + KeyT = 84 + KeyU = 85 + KeyV = 86 + KeyW = 87 + KeyX = 88 + KeyY = 89 + KeyZ = 90 // Android keys KeyBack = 4 - KeyMenu = 82 + KeyMenu = 5 KeyVolumeUp = 24 KeyVolumeDown = 25 - // Mouse Buttons - MouseLeftButton = 0 - MouseRightButton = 1 - MouseMiddleButton = 2 + MouseLeftButton = MouseButtonLeft + MouseRightButton = MouseButtonRight + MouseMiddleButton = MouseButtonMiddle +) - // Touch points registered - MaxTouchPoints = 2 +type MouseButton int32 - // Gamepad Number - GamepadPlayer1 = 0 - GamepadPlayer2 = 1 - GamepadPlayer3 = 2 - GamepadPlayer4 = 3 +// Mouse Buttons +const ( + MouseButtonLeft MouseButton = iota + MouseButtonRight + MouseButtonMiddle + MouseButtonSide + MouseButtonExtra + MouseButtonForward + MouseButtonBack +) - // Gamepad Buttons/Axis +// Mouse cursor +type MouseCursor = int32 - // 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 +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 Axis - GamepadPs3AxisLeftX = 0 - GamepadPs3AxisLeftY = 1 - GamepadPs3AxisRightX = 2 - GamepadPs3AxisRightY = 5 - // [1..-1] (pressure-level) - GamepadPs3AxisL2 = 3 - // [1..-1] (pressure-level) - GamepadPs3AxisR2 = 4 +// 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 +) - // 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 - - // 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 +// 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] ) // Some Basic Colors @@ -411,11 +503,6 @@ 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 @@ -424,13 +511,8 @@ type Vector3 struct { } // NewVector3 - Returns new Vector3 -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) +func NewVector3(x, y, z float32) Vector3 { + return Vector3{x, y, z} } // Vector4 type @@ -442,13 +524,8 @@ type Vector4 struct { } // NewVector4 - Returns new Vector4 -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) +func NewVector4(x, y, z, w float32) Vector4 { + return Vector4{x, y, z, w} } // Matrix type (OpenGL style 4x4 - right handed, column major) @@ -464,11 +541,6 @@ 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 @@ -482,13 +554,8 @@ func NewMat2(m0, m1, m10, m11 float32) Mat2 { return Mat2{m0, m1, m10, m11} } -// Quaternion type -type Quaternion struct { - X float32 - Y float32 - Z float32 - W float32 -} +// Quaternion, 4 components (Vector4 alias) +type Quaternion = Vector4 // NewQuaternion - Returns new Quaternion func NewQuaternion(x, y, z, w float32) Quaternion { @@ -496,21 +563,12 @@ func NewQuaternion(x, y, z, w float32) Quaternion { } // Color type, RGBA (32bit) -type Color struct { - R uint8 - G uint8 - B uint8 - A uint8 -} +// TODO remove later, keep type for now to not break code +type Color = color.RGBA // NewColor - Returns new Color -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) +func NewColor(r, g, b, a uint8) color.RGBA { + return color.RGBA{r, g, b, a} } // Rectangle type @@ -526,11 +584,6 @@ 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{} @@ -572,22 +625,17 @@ type Camera3D struct { // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic Fovy float32 // Camera type, controlling projection type, either CameraPerspective or CameraOrthographic. - Type CameraType + Projection CameraProjection } // Camera type fallback, defaults to Camera3D type Camera = Camera3D // NewCamera3D - Returns new Camera3D -func NewCamera3D(pos, target, up Vector3, fovy float32, ct CameraType) Camera3D { +func NewCamera3D(pos, target, up Vector3, fovy float32, ct CameraProjection) Camera3D { 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) @@ -605,11 +653,6 @@ 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 @@ -623,11 +666,6 @@ 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 @@ -655,36 +693,72 @@ const ( // Shader location point type const ( - LocVertexPosition = iota - LocVertexTexcoord01 - LocVertexTexcoord02 - LocVertexNormal - LocVertexTangent - LocVertexColor - LocMatrixMvp - LocMatrixModel - LocMatrixView - LocMatrixProjection - LocVectorView - LocColorDiffuse - LocColorSpecular - LocColorAmbient - LocMapAlbedo - LocMapMetalness - LocMapNormal - LocMapRoughness - LocMapOcclusion - LocMapEmission - LocMapHeight - LocMapCubemap - LocMapIrradiance - LocMapPrefilter - LocMapBrdf + 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 ) -// Material map type +// 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 const ( - // MapDiffuse MapAlbedo = iota MapMetalness MapNormal @@ -692,21 +766,14 @@ const ( MapOcclusion MapEmission MapHeight - // NOTE: Uses GL_TEXTURE_CUBE_MAP + MapBrdg MapCubemap - // NOTE: Uses GL_TEXTURE_CUBE_MAP MapIrradiance - // NOTE: Uses GL_TEXTURE_CUBE_MAP MapPrefilter MapBrdf -) -// Material map type -const ( - MapDiffuse = MapAlbedo - MapSpecular = MapMetalness - LocMapDiffuse = LocMapAlbedo - LocMapSpecular = LocMapMetalness + MapDiffuse = MapAlbedo + MapSpecular = MapMetalness ) // Shader and material limits @@ -724,33 +791,35 @@ type Mesh struct { // Number of triangles stored (indexed or not) TriangleCount int32 // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) - Vertices *[]float32 + Vertices *float32 // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - Texcoords *[]float32 + Texcoords *float32 // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5) - Texcoords2 *[]float32 + Texcoords2 *float32 // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) - Normals *[]float32 + Normals *float32 // Vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) - Tangents *[]float32 + Tangents *float32 // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - Colors *[]uint8 + Colors *uint8 // Vertex indices (in case vertex data comes indexed) - Indices *[]uint16 + Indices *uint16 + // AnimVertices + AnimVertices *float32 + // AnimNormals + AnimNormals *float32 + // BoneIds + 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 [7]uint32 -} - -// NewMesh - Returns new Mesh -func NewMesh(vertexCount, triangleCount int32, vertices, texcoords, texcoords2, normals, tangents *[]float32, colors *[]uint8, indices *[]uint16, vaoID uint32, vboID [7]uint32) Mesh { - return Mesh{vertexCount, triangleCount, vertices, texcoords, texcoords2, normals, tangents, colors, indices, vaoID, vboID} -} - -// newMeshFromPointer - Returns new Mesh from pointer -func newMeshFromPointer(ptr unsafe.Pointer) Mesh { - return *(*Mesh)(ptr) + VboID *uint32 } // Material type @@ -758,21 +827,14 @@ type Material struct { // Shader Shader Shader // Maps - Maps [MaxMaterialMaps]MaterialMap - // Padding - _ [4]byte + Maps *MaterialMap // Generic parameters (if required) - Params *[]float32 + Params [4]float32 } -// NewMaterial - Returns new Material -func NewMaterial(shader Shader, maps [MaxMaterialMaps]MaterialMap, params *[]float32) Material { - return Material{shader, maps, [4]byte{}, params} -} - -// newMaterialFromPointer - Returns new Material from pointer -func newMaterialFromPointer(ptr unsafe.Pointer) Material { - return *(*Material)(ptr) +// 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{}))) } // MaterialMap type @@ -780,31 +842,72 @@ type MaterialMap struct { // Texture Texture Texture2D // Color - Color Color + Color color.RGBA // Value Value float32 } -// Model type +// Model is struct of model, meshes, materials and animation data type Model struct { - // Vertex data buffers (RAM and VRAM) - Mesh Mesh // Local transform matrix Transform Matrix - // Shader and textures data - Material Material - // Padding - _ [4]byte + // Number of meshes + MeshCount int32 + // Number of materials + 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 } -// NewModel - Returns new Model -func NewModel(mesh Mesh, transform Matrix, material Material) Model { - return Model{mesh, transform, material, [4]byte{}} +// 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 +type BoneInfo struct { + Name [32]int8 + Parent int32 +} + +// Transform type +type Transform struct { + Translation Vector3 + Rotation Vector4 + Scale Vector3 } // Ray type (useful for raycast) @@ -820,59 +923,48 @@ func NewRay(position, direction Vector3) Ray { return Ray{position, direction} } -// newRayFromPointer - Returns new Ray from pointer -func newRayFromPointer(ptr unsafe.Pointer) Ray { - return *(*Ray)(ptr) +// ModelAnimation type +type ModelAnimation struct { + BoneCount int32 + FrameCount int32 + Bones *BoneInfo + FramePoses **Transform + Name [32]uint8 } -// VrDevice type -type VrDevice int32 - -// Head Mounted Display devices -const ( - HmdDefaultDevice VrDevice = iota - HmdOculusRiftDk2 - HmdOculusRiftCv1 - HmdOculusGo - HmdValveHtcVive - HmdSonyPsvr -) - -// VrDeviceInfo - Head-Mounted-Display device parameters -type VrDeviceInfo struct { - // HMD horizontal resolution in pixels - hResolution int - // HMD vertical resolution in pixels - vResolution int - // HMD horizontal size in meters - hScreenSize float32 - // HMD vertical size in meters - vScreenSize float32 - // HMD screen center in meters - vScreenCenter float32 - // HMD distance between eye and display in meters - eyeToScreenDistance float32 - // HMD lens separation distance in meters - lensSeparationDistance float32 - // HMD IPD (distance between pupils) in meters - interpupillaryDistance float32 - // HMD lens distortion constant parameters - lensDistortionValues [4]float32 - // HMD chromatic aberration correction parameters - chromaAbCorrection [4]float32 +// GetBones returns the bones information (skeleton) of a ModelAnimation as go slice +func (m ModelAnimation) GetBones() []BoneInfo { + return unsafe.Slice(m.Bones, m.BoneCount) } -// NewVrDeviceInfo - Returns new VrDeviceInfo -func NewVrDeviceInfo(hResolution, vResolution int, hScreenSize, vScreenSize, vScreenCenter, eyeToScreenDistance, - lensSeparationDistance, interpupillaryDistance float32, lensDistortionValues, chromaAbCorrection [4]float32) VrDeviceInfo { - - return VrDeviceInfo{hResolution, vResolution, hScreenSize, vScreenSize, vScreenCenter, eyeToScreenDistance, - lensSeparationDistance, interpupillaryDistance, lensDistortionValues, chromaAbCorrection} +// 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] } -// newVrDeviceInfoFromPointer - Returns new VrDeviceInfo from pointer -func newVrDeviceInfoFromPointer(ptr unsafe.Pointer) VrDeviceInfo { - return *(*VrDeviceInfo)(ptr) +// 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} } // BlendMode type @@ -880,9 +972,14 @@ type BlendMode int32 // Color blending modes (pre-defined) const ( - BlendAlpha BlendMode = iota - BlendAdditive - BlendMultiplied + 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 ) // Shader type (generic shader) @@ -890,64 +987,65 @@ type Shader struct { // Shader program id ID uint32 // Shader locations array - Locs [MaxShaderLocations]int32 + Locs *int32 } // NewShader - Returns new Shader -func NewShader(id uint32, locs [MaxShaderLocations]int32) Shader { +func NewShader(id uint32, locs *int32) Shader { return Shader{id, locs} } -// newShaderFromPointer - Returns new Shader from pointer -func newShaderFromPointer(ptr unsafe.Pointer) Shader { - return *(*Shader)(ptr) +// 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))) } -// CharInfo - Font character info -type CharInfo struct { +// 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 { // Character value (Unicode) Value int32 - // Character rectangle in sprite font - Rec Rectangle // Character offset X when drawing OffsetX int32 // Character offset Y when drawing OffsetY int32 // Character advance position X AdvanceX int32 + // Character image data + Image Image } -// NewCharInfo - Returns new CharInfo -func NewCharInfo(value int32, rec Rectangle, offsetX, offsetY, advanceX int32) CharInfo { - return CharInfo{value, rec, offsetX, offsetY, advanceX} -} - -// newCharInfoFromPointer - Returns new CharInfo from pointer -func newCharInfoFromPointer(ptr unsafe.Pointer) CharInfo { - return *(*CharInfo)(ptr) +// NewGlyphInfo - Returns new CharInfo +func NewGlyphInfo(value int32, offsetX, offsetY, advanceX int32, image Image) GlyphInfo { + return GlyphInfo{value, offsetX, offsetY, advanceX, image} } // Font type, includes texture and charSet array data type Font struct { - // Font texture - Texture Texture2D // Base size (default chars height) BaseSize int32 // Number of characters CharsCount int32 + // Padding around the chars + CharsPadding int32 + // Characters texture atlas + Texture Texture2D + // Characters rectangles in texture + Recs *Rectangle // Characters info data - Chars *CharInfo + Chars *GlyphInfo } -// NewFont - Returns new Font -func NewFont(texture Texture2D, baseSize, charsCount int32, chars *CharInfo) Font { - return Font{texture, baseSize, charsCount, chars} -} - -// newFontFromPointer - Returns new Font from pointer -func newFontFromPointer(ptr unsafe.Pointer) Font { - return *(*Font)(ptr) -} +// 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 +) // PixelFormat - Texture format type PixelFormat int32 @@ -1027,14 +1125,24 @@ type TextureWrapMode int32 const ( WrapRepeat TextureWrapMode = iota WrapClamp - WrapMirror + WrapMirrorRepeat + 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 @@ -1048,30 +1156,10 @@ 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() - pixels := make([]Color, size.X*size.Y) - - 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() - pixels[x+y*size.Y] = NewColor(uint8(r), uint8(g), uint8(b), uint8(a)) - } - } - - return LoadImageEx(pixels, int32(size.X), int32(size.Y)) -} - // Texture2D type, bpp always RGBA (32bit) // NOTE: Data stored in GPU memory type Texture2D struct { @@ -1092,11 +1180,6 @@ 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 @@ -1112,18 +1195,73 @@ func NewRenderTexture2D(id uint32, texture, depth Texture2D) RenderTexture2D { return RenderTexture2D{id, texture, depth} } -// newRenderTexture2DFromPointer - Returns new RenderTexture2D from pointer -func newRenderTexture2DFromPointer(ptr unsafe.Pointer) RenderTexture2D { - return *(*RenderTexture2D)(ptr) -} +// TraceLogCallbackFun - function that will recive the trace log messages +type TraceLogCallbackFun func(int, string) -// Log message types +// TraceLogLevel parameter of trace log message +type TraceLogLevel int + +// Trace log level +// NOTE: Organized by priority level const ( - LogInfo = 1 << iota - LogWarning - LogError + // Display all logs + LogAll TraceLogLevel = iota + // Trace logging, intended for internal use only + LogTrace + // Debug logging, used for internal debugging, it should be disabled on release builds LogDebug - LogOther + // 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 ) -var logTypeFlags = LogInfo | LogWarning | LogError +// 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 +} diff --git a/raylib/raylib.h b/raylib/raylib.h index d3801b5..f42ab40 100644 --- a/raylib/raylib.h +++ b/raylib/raylib.h @@ -1,46 +1,61 @@ /********************************************************************************************** * -* raylib - A simple and easy-to-use library to learn videogames programming (www.raylib.com) +* raylib v5.6-dev - 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 or ES2 - choose at compile) +* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile) * - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Powerful fonts module with Fonts support (XNA fonts, AngelCode fonts, TTF) +* - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite 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) * - 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, FLAC, XM, MOD) -* - Multiple platforms support: Windows, Linux, FreeBSD, MacOS, UWP, Android, Raspberry Pi, HTML5. +* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, QOA, XM, MOD) * - VR stereo rendering with configurable HMD device parameters -* - NO external dependencies, all required libraries included with raylib -* - Complete bindings to LUA (raylib-lua) and Go (raylib-go) +* - Bindings to multiple programming languages available! * * NOTES: -* One custom font is loaded by default when InitWindow() [core] -* If using OpenGL 3.3 or ES2, one default shader is loaded automatically (internally defined) [rlgl] -* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads +* - 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): -* rglfw (github.com/glfw/glfw) for window/context management and input (only PLATFORM_DESKTOP) [core] -* glad (github.com/Dav1dde/glad) for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] -* mini_al (github.com/dr-soft/mini_al) for audio device/context management [audio] +* [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 * * OPTIONAL DEPENDENCIES (included): -* stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) [textures] -* stb_image_resize (Sean Barret) for image resizing algorythms [textures] -* stb_image_write (Sean Barret) for image writting (PNG) [utils] -* stb_truetype (Sean Barret) for ttf fonts loading [text] -* stb_vorbis (Sean Barret) for OGG audio loading [audio] -* stb_perlin (Sean Barret) for Perlin noise image generation [textures] -* par_shapes (Philip Rideout) for parametric 3d shapes generation [models] -* jar_xm (Joshua Reisenauer) for XM audio module loading [audio] -* jar_mod (Joshua Reisenauer) for MOD audio module loading [audio] -* dr_flac (David Reid) for FLAC audio file loading [audio] -* rgif (Charlie Tangora, Ramon Santamaria) for GIF recording [core] -* tinfl for data decompression (DEFLATE algorithm) [rres] +* [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) +* [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 @@ -48,7 +63,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-2018 Ramon Santamaria (@raysan5) +* 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. @@ -70,12 +85,33 @@ #ifndef RAYLIB_H #define RAYLIB_H -#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll) -#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) +#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" + +// 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 + #if defined(BUILD_LIBTYPE_SHARED) + #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 #else - #define RLAPI // We are building or using raylib as a static library (or Linux shared library) + #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) #endif //---------------------------------------------------------------------------------- @@ -84,279 +120,146 @@ #ifndef PI #define PI 3.14159265358979323846f #endif - -#define DEG2RAD (PI/180.0f) -#define RAD2DEG (180.0f/PI) - -// raylib Config Flags -#define FLAG_SHOW_LOGO 1 // Set to show raylib logo at startup -#define FLAG_FULLSCREEN_MODE 2 // Set to run program in fullscreen -#define FLAG_WINDOW_RESIZABLE 4 // Set to allow resizable window -#define FLAG_WINDOW_DECORATED 8 // Set to show window decoration (frame and buttons) -#define FLAG_WINDOW_TRANSPARENT 16 // Set to allow transparent window -#define FLAG_MSAA_4X_HINT 32 // Set to try enabling MSAA 4X -#define FLAG_VSYNC_HINT 64 // Set to try enabling V-Sync on GPU - -// Keyboard Function Keys -#define KEY_SPACE 32 -#define KEY_ESCAPE 256 -#define KEY_ENTER 257 -#define KEY_TAB 258 -#define KEY_BACKSPACE 259 -#define KEY_INSERT 260 -#define KEY_DELETE 261 -#define KEY_RIGHT 262 -#define KEY_LEFT 263 -#define KEY_DOWN 264 -#define KEY_UP 265 -#define KEY_PAGE_UP 266 -#define KEY_PAGE_DOWN 267 -#define KEY_HOME 268 -#define KEY_END 269 -#define KEY_CAPS_LOCK 280 -#define KEY_SCROLL_LOCK 281 -#define KEY_NUM_LOCK 282 -#define KEY_PRINT_SCREEN 283 -#define KEY_PAUSE 284 -#define KEY_F1 290 -#define KEY_F2 291 -#define KEY_F3 292 -#define KEY_F4 293 -#define KEY_F5 294 -#define KEY_F6 295 -#define KEY_F7 296 -#define KEY_F8 297 -#define KEY_F9 298 -#define KEY_F10 299 -#define KEY_F11 300 -#define KEY_F12 301 -#define KEY_LEFT_SHIFT 340 -#define KEY_LEFT_CONTROL 341 -#define KEY_LEFT_ALT 342 -#define KEY_RIGHT_SHIFT 344 -#define KEY_RIGHT_CONTROL 345 -#define KEY_RIGHT_ALT 346 -#define KEY_GRAVE 96 -#define KEY_SLASH 47 -#define KEY_BACKSLASH 92 - -// Keyboard Alpha Numeric Keys -#define KEY_ZERO 48 -#define KEY_ONE 49 -#define KEY_TWO 50 -#define KEY_THREE 51 -#define KEY_FOUR 52 -#define KEY_FIVE 53 -#define KEY_SIX 54 -#define KEY_SEVEN 55 -#define KEY_EIGHT 56 -#define KEY_NINE 57 -#define KEY_A 65 -#define KEY_B 66 -#define KEY_C 67 -#define KEY_D 68 -#define KEY_E 69 -#define KEY_F 70 -#define KEY_G 71 -#define KEY_H 72 -#define KEY_I 73 -#define KEY_J 74 -#define KEY_K 75 -#define KEY_L 76 -#define KEY_M 77 -#define KEY_N 78 -#define KEY_O 79 -#define KEY_P 80 -#define KEY_Q 81 -#define KEY_R 82 -#define KEY_S 83 -#define KEY_T 84 -#define KEY_U 85 -#define KEY_V 86 -#define KEY_W 87 -#define KEY_X 88 -#define KEY_Y 89 -#define KEY_Z 90 - -// Android Physical Buttons -#define KEY_BACK 4 -#define KEY_MENU 82 -#define KEY_VOLUME_UP 24 -#define KEY_VOLUME_DOWN 25 - -// Mouse Buttons -#define MOUSE_LEFT_BUTTON 0 -#define MOUSE_RIGHT_BUTTON 1 -#define MOUSE_MIDDLE_BUTTON 2 - -// Touch points registered -#define MAX_TOUCH_POINTS 2 - -// Gamepad Number -#define GAMEPAD_PLAYER1 0 -#define GAMEPAD_PLAYER2 1 -#define GAMEPAD_PLAYER3 2 -#define GAMEPAD_PLAYER4 3 - -// Gamepad Buttons/Axis - -// PS3 USB Controller Buttons -#define GAMEPAD_PS3_BUTTON_TRIANGLE 0 -#define GAMEPAD_PS3_BUTTON_CIRCLE 1 -#define GAMEPAD_PS3_BUTTON_CROSS 2 -#define GAMEPAD_PS3_BUTTON_SQUARE 3 -#define GAMEPAD_PS3_BUTTON_L1 6 -#define GAMEPAD_PS3_BUTTON_R1 7 -#define GAMEPAD_PS3_BUTTON_L2 4 -#define GAMEPAD_PS3_BUTTON_R2 5 -#define GAMEPAD_PS3_BUTTON_START 8 -#define GAMEPAD_PS3_BUTTON_SELECT 9 -#define GAMEPAD_PS3_BUTTON_UP 24 -#define GAMEPAD_PS3_BUTTON_RIGHT 25 -#define GAMEPAD_PS3_BUTTON_DOWN 26 -#define GAMEPAD_PS3_BUTTON_LEFT 27 -#define GAMEPAD_PS3_BUTTON_PS 12 - -// PS3 USB Controller Axis -#define GAMEPAD_PS3_AXIS_LEFT_X 0 -#define GAMEPAD_PS3_AXIS_LEFT_Y 1 -#define GAMEPAD_PS3_AXIS_RIGHT_X 2 -#define GAMEPAD_PS3_AXIS_RIGHT_Y 5 -#define GAMEPAD_PS3_AXIS_L2 3 // [1..-1] (pressure-level) -#define GAMEPAD_PS3_AXIS_R2 4 // [1..-1] (pressure-level) - -// Xbox360 USB Controller Buttons -#define GAMEPAD_XBOX_BUTTON_A 0 -#define GAMEPAD_XBOX_BUTTON_B 1 -#define GAMEPAD_XBOX_BUTTON_X 2 -#define GAMEPAD_XBOX_BUTTON_Y 3 -#define GAMEPAD_XBOX_BUTTON_LB 4 -#define GAMEPAD_XBOX_BUTTON_RB 5 -#define GAMEPAD_XBOX_BUTTON_SELECT 6 -#define GAMEPAD_XBOX_BUTTON_START 7 -#define GAMEPAD_XBOX_BUTTON_UP 10 -#define GAMEPAD_XBOX_BUTTON_RIGHT 11 -#define GAMEPAD_XBOX_BUTTON_DOWN 12 -#define GAMEPAD_XBOX_BUTTON_LEFT 13 -#define GAMEPAD_XBOX_BUTTON_HOME 8 - -// Xbox360 USB Controller Axis -// NOTE: For Raspberry Pi, axis must be reconfigured -#if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) - #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [-1..1] (up->down) - #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 // [-1..1] (left->right) - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) - #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) - #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) -#else - #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) - #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) - #define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) - #define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) - #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) #endif -// NOTE: MSC C++ compiler does not support compound literals (C99 feature) -// Plain structures in C++ (without constructors) can be initialized from { } initializers. -#ifdef __cplusplus - #define CLITERAL -#else - #define CLITERAL (Color) +// 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{ 200, 200, 200, 255 } // Light Gray -#define GRAY CLITERAL{ 130, 130, 130, 255 } // Gray -#define DARKGRAY CLITERAL{ 80, 80, 80, 255 } // Dark Gray -#define YELLOW CLITERAL{ 253, 249, 0, 255 } // Yellow -#define GOLD CLITERAL{ 255, 203, 0, 255 } // Gold -#define ORANGE CLITERAL{ 255, 161, 0, 255 } // Orange -#define PINK CLITERAL{ 255, 109, 194, 255 } // Pink -#define RED CLITERAL{ 230, 41, 55, 255 } // Red -#define MAROON CLITERAL{ 190, 33, 55, 255 } // Maroon -#define GREEN CLITERAL{ 0, 228, 48, 255 } // Green -#define LIME CLITERAL{ 0, 158, 47, 255 } // Lime -#define DARKGREEN CLITERAL{ 0, 117, 44, 255 } // Dark Green -#define SKYBLUE CLITERAL{ 102, 191, 255, 255 } // Sky Blue -#define BLUE CLITERAL{ 0, 121, 241, 255 } // Blue -#define DARKBLUE CLITERAL{ 0, 82, 172, 255 } // Dark Blue -#define PURPLE CLITERAL{ 200, 122, 255, 255 } // Purple -#define VIOLET CLITERAL{ 135, 60, 190, 255 } // Violet -#define DARKPURPLE CLITERAL{ 112, 31, 126, 255 } // Dark Purple -#define BEIGE CLITERAL{ 211, 176, 131, 255 } // Beige -#define BROWN CLITERAL{ 127, 106, 79, 255 } // Brown -#define DARKBROWN CLITERAL{ 76, 63, 47, 255 } // Dark Brown +#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{ 255, 255, 255, 255 } // White -#define BLACK CLITERAL{ 0, 0, 0, 255 } // Black -#define BLANK CLITERAL{ 0, 0, 0, 0 } // Blank (Transparent) -#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta -#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo) - -// Shader and material limits -#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct -#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct +#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 //---------------------------------------------------------------------------------- -#ifndef __cplusplus // Boolean type - #ifndef bool - typedef enum { false, true } bool; - #endif +#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 type +// Vector2, 2 components typedef struct Vector2 { - float x; - float y; + float x; // Vector x component + float y; // Vector y component } Vector2; -// Vector3 type +// Vector3, 3 components typedef struct Vector3 { - float x; - float y; - float z; + float x; // Vector x component + float y; // Vector y component + float z; // Vector z component } Vector3; -// Vector4 type +// Vector4, 4 components typedef struct Vector4 { - float x; - float y; - float z; - float w; + float x; // Vector x component + float y; // Vector y component + float z; // Vector z component + float w; // Vector w component } Vector4; -// Matrix type (OpenGL style 4x4 - right handed, column major) +// 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; - float m1, m5, m9, m13; - float m2, m6, m10, m14; - float m3, m7, m11, m15; + 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 type, RGBA (32bit) +// Color, 4 components, R8G8B8A8 (32bit) typedef struct Color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; + 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 type +// Rectangle, 4 components typedef struct Rectangle { - float x; - float y; - float width; - float height; + 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 type, bpp always RGBA (32bit) -// NOTE: Data stored in CPU memory (RAM) +// Image, pixel data stored in CPU memory (RAM) typedef struct Image { void *data; // Image raw data int width; // Image base width @@ -365,54 +268,72 @@ typedef struct Image { int format; // Data format (PixelFormat type) } Image; -// Texture2D type -// NOTE: Data stored in GPU memory -typedef struct Texture2D { +// 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) -} Texture2D; +} Texture; -// RenderTexture2D type, for texture rendering -typedef struct RenderTexture2D { - unsigned int id; // OpenGL Framebuffer Object (FBO) id - Texture2D texture; // Color buffer attachment texture - Texture2D depth; // Depth buffer attachment texture -} RenderTexture2D; +// Texture2D, same as Texture +typedef Texture Texture2D; -// Font character info -typedef struct CharInfo { +// 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) - Rectangle rec; // Character rectangle in sprite font int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X -} CharInfo; + Image image; // Character image data +} GlyphInfo; -// Font type, includes texture and charSet array data +// Font, font texture and GlyphInfo array data typedef struct Font { - Texture2D texture; // Font texture int baseSize; // Base size (default chars height) - int charsCount; // Number of characters - CharInfo *chars; // Characters info data + 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; -#define SpriteFont Font // SpriteFont type fallback, defaults to Font - -// Camera type, defines a camera position/orientation in 3d space +// 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 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 + 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; -#define Camera Camera3D // Camera type fallback, defaults to Camera3D +typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D -// Camera2D type, defines a 2d camera +// 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) @@ -420,279 +341,620 @@ typedef struct Camera2D { float zoom; // Camera zoom (scaling), should be 1.0f by default } Camera2D; -// Bounding box type -typedef struct BoundingBox { - Vector3 min; // Minimum vertex box-corner - Vector3 max; // Maximum vertex box-corner -} BoundingBox; - -// Vertex data definning a mesh -// NOTE: Data stored in CPU memory (and GPU) +// 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 second texture coordinates (useful for lightmaps) (shader-location = 5) + 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) + 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 + + // OpenGL identifiers unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) + unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data) } Mesh; -// Shader type (generic) +// Shader typedef struct Shader { - unsigned int id; // Shader program id - int locs[MAX_SHADER_LOCATIONS]; // Shader locations array + unsigned int id; // Shader program id + int *locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) } Shader; -// Material texture map +// MaterialMap typedef struct MaterialMap { Texture2D texture; // Material map texture Color color; // Material map color float value; // Material map value } MaterialMap; -// Material type (generic) +// Material, includes shader and maps typedef struct Material { Shader shader; // Material shader - MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps - float *params; // Material generic parameters (if required) + MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS) + float params[4]; // Material generic parameters (if required) } Material; -// Model type +// 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 { - Mesh mesh; // Vertex data buffers (RAM and VRAM) Matrix transform; // Local transform matrix - Material material; // Shader and textures data + + 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; -// Ray type (useful for raycast) +// 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 + Vector3 direction; // Ray direction (normalized) } Ray; -// Raycast hit information -typedef struct RayHitInfo { +// RayCollision, ray hit information +typedef struct RayCollision { bool hit; // Did the ray hit something? - float distance; // Distance to nearest hit - Vector3 position; // Position of nearest hit + float distance; // Distance to the nearest hit + Vector3 point; // Point of the nearest hit Vector3 normal; // Surface normal of hit -} RayHitInfo; +} RayCollision; -// Wave type, defines audio wave data +// 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 sampleCount; // Number of samples + 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) + unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) void *data; // Buffer data pointer } Wave; -// Sound source type -typedef struct Sound { - void *audioBuffer; // Pointer to internal data used by the audio system +// Opaque structs declaration +// NOTE: Actual structs are defined internally in raudio module +typedef struct rAudioBuffer rAudioBuffer; +typedef struct rAudioProcessor rAudioProcessor; - unsigned int source; // Audio source id - unsigned int buffer; // Audio buffer id - int format; // Audio format specifier -} Sound; - -// Music type (file streaming from memory) -// NOTE: Anything longer than ~10 seconds should be streamed -typedef struct MusicData *Music; - -// Audio stream type -// NOTE: Useful to create custom audio streams not bound to a specific file +// 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) - - void *audioBuffer; // Pointer to internal data used by the audio system. - - int format; // Audio format specifier - unsigned int source; // Audio source id - unsigned int buffers[2]; // Audio buffers (double buffering) + unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) } AudioStream; -// Head-Mounted-Display device parameters +// 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; // HMD horizontal resolution in pixels - int vResolution; // HMD vertical resolution in pixels - float hScreenSize; // HMD horizontal size in meters - float vScreenSize; // HMD vertical size in meters - float vScreenCenter; // HMD screen center in meters - float eyeToScreenDistance; // HMD distance between eye and display in meters - float lensSeparationDistance; // HMD lens separation distance in meters - float interpupillaryDistance; // HMD IPD (distance between pupils) in meters - float lensDistortionValues[4]; // HMD lens distortion constant parameters - float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters + 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 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 //---------------------------------------------------------------------------------- -// Trace log type -typedef enum { - LOG_INFO = 1, - LOG_WARNING = 2, - LOG_ERROR = 4, - LOG_DEBUG = 8, - LOG_OTHER = 16 -} LogType; - -// Shader location point type +// 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 { - LOC_VERTEX_POSITION = 0, - LOC_VERTEX_TEXCOORD01, - LOC_VERTEX_TEXCOORD02, - LOC_VERTEX_NORMAL, - LOC_VERTEX_TANGENT, - LOC_VERTEX_COLOR, - LOC_MATRIX_MVP, - LOC_MATRIX_MODEL, - LOC_MATRIX_VIEW, - LOC_MATRIX_PROJECTION, - LOC_VECTOR_VIEW, - LOC_COLOR_DIFFUSE, - LOC_COLOR_SPECULAR, - LOC_COLOR_AMBIENT, - LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE - LOC_MAP_METALNESS, // LOC_MAP_SPECULAR - LOC_MAP_NORMAL, - LOC_MAP_ROUGHNESS, - LOC_MAP_OCCLUSION, - LOC_MAP_EMISSION, - LOC_MAP_HEIGHT, - LOC_MAP_CUBEMAP, - LOC_MAP_IRRADIANCE, - LOC_MAP_PREFILTER, - LOC_MAP_BRDF + 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 = 5, // 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: 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 +} GamepadButton; + +// Gamepad axes +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 + 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 } ShaderLocationIndex; -#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO -#define LOC_MAP_SPECULAR LOC_MAP_METALNESS +#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO +#define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS -// Material map type +// Shader uniform data type typedef enum { - MAP_ALBEDO = 0, // MAP_DIFFUSE - MAP_METALNESS = 1, // MAP_SPECULAR - MAP_NORMAL = 2, - MAP_ROUGHNESS = 3, - MAP_OCCLUSION, - MAP_EMISSION, - MAP_HEIGHT, - MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_BRDF -} TexmapIndex; + 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 +} ShaderUniformDataType; -#define MAP_DIFFUSE MAP_ALBEDO -#define MAP_SPECULAR MAP_METALNESS +// 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 { - UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - UNCOMPRESSED_R5G6B5, // 16 bpp - UNCOMPRESSED_R8G8B8, // 24 bpp - UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - COMPRESSED_DXT3_RGBA, // 8 bpp - COMPRESSED_DXT5_RGBA, // 8 bpp - COMPRESSED_ETC1_RGB, // 4 bpp - COMPRESSED_ETC2_RGB, // 4 bpp - COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - COMPRESSED_PVRT_RGB, // 4 bpp - COMPRESSED_PVRT_RGBA, // 4 bpp - COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - 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_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 { - FILTER_POINT = 0, // No filter, just pixel aproximation - FILTER_BILINEAR, // Linear filtering - FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) - FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x - FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x - FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x -} TextureFilterMode; + 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 { - WRAP_REPEAT = 0, - WRAP_CLAMP, - WRAP_MIRROR -} TextureWrapMode; +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 +} 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_ADDITIVE, - BLEND_MULTIPLIED +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; -// Gestures type -// NOTE: It could be used as flags to enable only some gestures +// Gesture +// NOTE: Provided as bit-wise flags to enable only desired 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; + 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, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON + 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; -// Camera projection modes +// Camera projection typedef enum { - CAMERA_PERSPECTIVE = 0, - CAMERA_ORTHOGRAPHIC -} CameraType; + CAMERA_PERSPECTIVE = 0, // Perspective projection + CAMERA_ORTHOGRAPHIC // Orthographic projection +} CameraProjection; -// Head Mounted Display devices +// N-patch layout typedef enum { - HMD_DEFAULT_DEVICE = 0, - HMD_OCULUS_RIFT_DK2, - HMD_OCULUS_RIFT_CV1, - HMD_OCULUS_GO, - HMD_VALVE_HTC_VIVE, - HMD_SONY_PSVR -} VrDeviceType; + 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; -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif +// Callbacks to hook some internal functions +// WARNING: These callbacks are intended for advanced 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 //------------------------------------------------------------------------------------ // Global Variables Definition @@ -703,21 +965,60 @@ extern "C" { // Prevents name mangling of functions // 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 WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed -RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) -RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (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 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 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 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 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 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 @@ -725,255 +1026,505 @@ RLAPI void HideCursor(void); // Hides curso 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); // Initialize 2D mode with custom camera (2D) +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); // Initializes 3D mode with custom camera (3D) +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); // Initializes render texture for drawing +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 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 UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) // Screen-space-related functions -RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position -RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position -RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) +#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 -// Timming-related functions +// Timing-related functions RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI int GetFPS(void); // Returns current FPS -RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn -RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() +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 -// Color-related functions -RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color -RLAPI Vector4 ColorNormalize(Color color); // Returns color normalized as float [0..1] -RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color -RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +// 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 // Misc. functions -RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags) -RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS) -RLAPI void SetTraceLog(unsigned char types); // Enable trace log message types (bit flags based) -RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png) -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 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 advanced 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 bool IsFileExtension(const char *fileName, const char *ext);// Check file extension -RLAPI const char *GetExtension(const char *fileName); // Get pointer to extension for a filename string -RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string -RLAPI const char *GetDirectoryPath(const char *fileName); // Get full path for a given fileName (uses static string) -RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) -RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success -RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window -RLAPI char **GetDroppedFiles(int *count); // Get dropped files names -RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer +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, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success +//------------------------------------------------------------------ -// Persistent storage management -RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position) -RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position) +// 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 int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success +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 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) + +// 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); // 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 int GetKeyPressed(void); // Get latest key pressed +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 void SetExitKey(int key); // Set a custom key to exit program (default is ESC) // Input-related functions: gamepads -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 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); // Return gamepad axis count for a gamepad -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis +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 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); // 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(Vector2 position); // Set mouse position XY -RLAPI void SetMouseScale(float scale); // Set mouse scaling -RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y +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); // 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) +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: gestures) +// Gestures and Touch Handling Functions (Module: rgestures) //------------------------------------------------------------------------------------ -RLAPI void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected +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 int GetTouchPointsCount(void); // Get touch points count -RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds +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 //------------------------------------------------------------------------------------ -// Camera System Functions (Module: camera) +// Camera System Functions (Module: rcamera) //------------------------------------------------------------------------------------ -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 panKey); // Set camera pan key to combine with mouse movement (free camera) -RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) -RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) -RLAPI void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) +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 +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 // 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 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 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 (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 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 DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle -RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-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 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 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 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 DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline -RLAPI void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outline with extended parameters -RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle -RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle 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 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 DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) -RLAPI void DrawPolyEx(Vector2 *points, int numPoints, Color color); // Draw a closed polygon defined by points -RLAPI void DrawPolyExLines(Vector2 *points, int numPoints, Color color); // Draw polygon lines +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 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision +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 //------------------------------------------------------------------------------------ // Texture Loading and Drawing Functions (Module: textures) //------------------------------------------------------------------------------------ -// Image/Texture2D data loading/unloading/saving functions +// 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 LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit) -RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data -RLAPI void ExportImage(const char *fileName, Image image); // Export image as a PNG file -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 RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) +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 void UnloadImage(Image image); // Unload image from CPU memory (RAM) -RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) -RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) -RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array -RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) -RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image -RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data +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 void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) -RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format -RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image -RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color -RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value -RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel -RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) -RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) -RLAPI void ImageMipmaps(Image *image); // Generate 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 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 ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image -RLAPI void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color); // Draw rectangle within an image -RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination) +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 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 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 generation functions -RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color -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 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 +// 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 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 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) -// Texture2D configuration functions +// 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 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 + +// Texture configuration functions RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture -RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode -RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode +RLAPI void SetTextureFilter(Texture2D texture, int filter); // Set texture scaling filter mode +RLAPI void SetTextureWrap(Texture2D texture, int wrap); // Set texture wrapping mode -// Texture2D drawing functions +// 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 sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' 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 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 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 GetDefaultFont(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 charsCount, int *fontChars); // Load Font from file with extended parameters -RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) +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 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 // Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Shows 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 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 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 const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string -RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font +// 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) +// 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() +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(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 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 int TextToInteger(const char *text); // Get integer value from text +RLAPI float TextToFloat(const char *text); // Get float value from text //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) @@ -981,176 +1532,166 @@ RLAPI int GetGlyphIndex(Font font, int character); // 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(const 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 DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured +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)) -RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo -//DrawTorus(), DrawTeapot() could be useful? //------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -// Model loading/unloading functions -RLAPI Model LoadModel(const char *fileName); // Load model from files (mesh and material) -RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh -RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM) - -// Mesh loading/unloading functions -RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file -RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM) -RLAPI void ExportMesh(const char *fileName, Mesh mesh); // Export mesh as an OBJ file - -// Mesh manipulation functions -RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits -RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents -RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals - -// Mesh generation functions -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 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 LoadMaterial(const char *fileName); // Load material from file -RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) -RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) +// 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 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) // Model drawing functions -RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +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 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 center, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec +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 +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 BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits +RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents +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 + +// 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 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 + +// 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 // Collision detection functions -RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres -RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes -RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere -RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere -RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, 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 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) - -//------------------------------------------------------------------------------------ -// Shaders System Functions (Module: rlgl) -// NOTE: This functions are useless when using OpenGL 1.1 -//------------------------------------------------------------------------------------ - -// Shader loading/unloading functions -RLAPI char *LoadText(const char *fileName); // Load chars array from text file -RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderCode(char *vsCode, char *fsCode); // Load shader from code strings and bind default locations -RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) - -RLAPI Shader GetShaderDefault(void); // Get default shader -RLAPI Texture2D GetTextureDefault(void); // Get default texture - -// Shader configuration functions -RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -RLAPI void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float) -RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int) -RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) -RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) -RLAPI Matrix GetMatrixModelview(); // Get internal modelview matrix - -// Texture maps generation (PBR) -// NOTE: Required shaders should be provided -RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture -RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data -RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data -RLAPI Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data - -// Shading begin/end functions -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) -RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) - -// VR control functions -RLAPI VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices -RLAPI void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters -RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -RLAPI void SetVrDistortionShader(Shader shader); // Set VR distortion shader for stereoscopic rendering -RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -RLAPI void ToggleVrMode(void); // Enable/Disable VR experience -RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering -RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +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 LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data +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 Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new 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 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 void StopSound(Sound sound); // Stop playing a 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 WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +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 float *GetWaveData(Wave wave); // Get samples data from wave as a floats array +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 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 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 bool IsMusicPlaying(Music music); // Check if music is playing +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 SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats) +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 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 IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +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 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 @@ -1158,12 +1699,17 @@ 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 -#if defined(PLATFORM_ANDROID) -RLAPI struct android_app *GetAndroidApp(void); -#endif +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 -#ifdef __cplusplus +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) } #endif diff --git a/raylib/raylib_purego.go b/raylib/raylib_purego.go new file mode 100644 index 0000000..70e8b61 --- /dev/null +++ b/raylib/raylib_purego.go @@ -0,0 +1,3984 @@ +//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 new file mode 100644 index 0000000..e0aefc6 --- /dev/null +++ b/raylib/raymath.go @@ -0,0 +1,1847 @@ +package rl + +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) +} + +// Vector2One - Vector with components value 1.0 +func Vector2One() Vector2 { + return NewVector2(1.0, 1.0) +} + +// Vector2Add - Add two vectors (v1 + v2) +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 +} + +// Vector2Distance - Calculate distance between two vectors +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 +func Vector2Angle(v1, v2 Vector2) float32 { + result := math.Atan2(float64(v2.Y), float64(v2.X)) - math.Atan2(float64(v1.Y), float64(v1.X)) + + return float32(result) +} + +// 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))) +} + +// Vector2Scale - Scale vector (multiply by value) +func Vector2Scale(v Vector2, scale float32) Vector2 { + return NewVector2(v.X*scale, v.Y*scale) +} + +// Vector2Multiply - Multiply vector by vector +func Vector2Multiply(v1, v2 Vector2) Vector2 { + return NewVector2(v1.X*v2.X, v1.Y*v2.Y) +} + +// Vector2Negate - Negate vector +func Vector2Negate(v Vector2) Vector2 { + return NewVector2(-v.X, -v.Y) +} + +// Vector2Divide - Divide vector by vector +func Vector2Divide(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 +} + +// Vector2Lerp - Calculate linear interpolation between two vectors +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 +} + +// Vector2Cross - Calculate the cross product of a vector and a value +func Vector2Cross(value float32, vector Vector2) Vector2 { + return NewVector2(-value*vector.Y, value*vector.X) +} + +// Vector2LenSqr - Returns the len square root of a vector +func Vector2LenSqr(vector Vector2) float32 { + return vector.X*vector.X + vector.Y*vector.Y +} + +// Vector3Zero - Vector with components value 0.0 +func Vector3Zero() Vector3 { + return NewVector3(0.0, 0.0, 0.0) +} + +// Vector3One - Vector with components value 1.0 +func Vector3One() Vector3 { + return NewVector3(1.0, 1.0, 1.0) +} + +// Vector3Add - Add two vectors +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) +} + +// 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 { + result := Vector3{} + + result.X = v1.X * v2.X + result.Y = v1.Y * v2.Y + result.Z = v1.Z * v2.Z + + return result +} + +// Vector3CrossProduct - Calculate two vectors cross product +func Vector3CrossProduct(v1, v2 Vector3) Vector3 { + result := Vector3{} + + result.X = v1.Y*v2.Z - v1.Z*v2.Y + result.Y = v1.Z*v2.X - v1.X*v2.Z + result.Z = v1.X*v2.Y - v1.Y*v2.X + + return result +} + +// Vector3Perpendicular - Calculate one vector perpendicular vector +func Vector3Perpendicular(v Vector3) Vector3 { + min := math.Abs(float64(v.X)) + cardinalAxis := NewVector3(1.0, 0.0, 0.0) + + if math.Abs(float64(v.Y)) < min { + min = math.Abs(float64(v.Y)) + cardinalAxis = NewVector3(0.0, 1.0, 0.0) + } + + if math.Abs(float64(v.Z)) < min { + cardinalAxis = NewVector3(0.0, 0.0, 1.0) + } + + result := Vector3CrossProduct(v, cardinalAxis) + + return result +} + +// Vector3Length - Calculate vector length +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 +} + +// Vector3Distance - Calculate distance between two vectors +func Vector3Distance(v1, v2 Vector3) float32 { + dx := v2.X - v1.X + dy := v2.Y - v1.Y + dz := v2.Z - v1.Z + + 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 +} + +// Vector3Negate - Negate provided vector (invert direction) +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 + + var length, ilength float32 + + length = Vector3Length(v) + + if length == 0 { + length = 1.0 + } + + ilength = 1.0 / length + + result.X *= ilength + result.Y *= ilength + result.Z *= ilength + + 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{} + + x := v.X + y := v.Y + z := v.Z + + 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 + result.Z = mat.M2*x + mat.M6*y + mat.M10*z + mat.M14 + + 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{} + + 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) + + return result +} + +// Vector3Reflect - Calculate reflected vector to normal +func Vector3Reflect(vector, normal Vector3) Vector3 { + // I is the original vector + // N is the normal of the incident plane + // R = I - (2*N*( DotProduct[ I,N] )) + + result := Vector3{} + + dotProduct := Vector3DotProduct(vector, normal) + + result.X = vector.X - (2.0*normal.X)*dotProduct + result.Y = vector.Y - (2.0*normal.Y)*dotProduct + result.Z = vector.Z - (2.0*normal.Z)*dotProduct + + return result +} + +// Vector3Min - Return min value for each pair of components +func Vector3Min(vec1, vec2 Vector3) Vector3 { + result := Vector3{} + + result.X = float32(math.Min(float64(vec1.X), float64(vec2.X))) + result.Y = float32(math.Min(float64(vec1.Y), float64(vec2.Y))) + result.Z = float32(math.Min(float64(vec1.Z), float64(vec2.Z))) + + return result +} + +// Vector3Max - Return max value for each pair of components +func Vector3Max(vec1, vec2 Vector3) Vector3 { + result := Vector3{} + + result.X = float32(math.Max(float64(vec1.X), float64(vec2.X))) + result.Y = float32(math.Max(float64(vec1.Y), float64(vec2.Y))) + result.Z = float32(math.Max(float64(vec1.Z), float64(vec2.Z))) + + return result +} + +// Vector3Barycenter - Barycenter coords for p in triangle abc +func Vector3Barycenter(p, a, b, c Vector3) Vector3 { + v0 := Vector3Subtract(b, a) + v1 := Vector3Subtract(c, a) + v2 := Vector3Subtract(p, a) + d00 := Vector3DotProduct(v0, v0) + d01 := Vector3DotProduct(v0, v1) + d11 := Vector3DotProduct(v1, v1) + d20 := Vector3DotProduct(v2, v0) + d21 := Vector3DotProduct(v2, v1) + + denom := d00*d11 - d01*d01 + + result := Vector3{} + + result.Y = (d11*d20 - d01*d21) / denom + result.Z = (d00*d21 - d01*d20) / denom + result.X = 1.0 - (result.Z + result.Y) + + 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 + + a00 := mat.M0 + a01 := mat.M1 + a02 := mat.M2 + a03 := mat.M3 + a10 := mat.M4 + a11 := mat.M5 + a12 := mat.M6 + a13 := mat.M7 + a20 := mat.M8 + a21 := mat.M9 + a22 := mat.M10 + a23 := mat.M11 + a30 := mat.M12 + a31 := mat.M13 + a32 := mat.M14 + a33 := mat.M15 + + 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 +} + +// MatrixTrace - Returns the trace of the matrix (sum of the values along the diagonal) +func MatrixTrace(mat Matrix) float32 { + return mat.M0 + mat.M5 + mat.M10 + mat.M15 +} + +// MatrixTranspose - Transposes provided matrix +func MatrixTranspose(mat Matrix) Matrix { + var result Matrix + + 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 +} + +// MatrixInvert - Invert provided matrix +func MatrixInvert(mat Matrix) Matrix { + var result Matrix + + a00 := mat.M0 + a01 := mat.M1 + a02 := mat.M2 + a03 := mat.M3 + a10 := mat.M4 + a11 := mat.M5 + a12 := mat.M6 + a13 := mat.M7 + a20 := mat.M8 + a21 := mat.M9 + a22 := mat.M10 + a23 := mat.M11 + a30 := mat.M12 + a31 := mat.M13 + a32 := mat.M14 + a33 := mat.M15 + + b00 := a00*a11 - a01*a10 + b01 := a00*a12 - a02*a10 + b02 := a00*a13 - a03*a10 + b03 := a01*a12 - a02*a11 + b04 := a01*a13 - a03*a11 + b05 := a02*a13 - a03*a12 + b06 := a20*a31 - a21*a30 + b07 := a20*a32 - a22*a30 + b08 := a20*a33 - a23*a30 + b09 := a21*a32 - a22*a31 + b10 := a21*a33 - a23*a31 + b11 := a22*a33 - a23*a32 + + // Calculate the invert determinant (inlined to avoid double-caching) + invDet := 1.0 / (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 +} + +// 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 + + det := MatrixDeterminant(mat) + + result.M0 /= det + result.M1 /= det + result.M2 /= det + result.M3 /= det + result.M4 /= det + result.M5 /= det + result.M6 /= det + result.M7 /= det + result.M8 /= det + result.M9 /= det + result.M10 /= det + result.M11 /= det + result.M12 /= det + result.M13 /= det + result.M14 /= det + result.M15 /= det + + return result +} + +// MatrixAdd - Add two matrices +func MatrixAdd(left, right Matrix) Matrix { + result := MatrixIdentity() + + result.M0 = left.M0 + right.M0 + result.M1 = left.M1 + right.M1 + result.M2 = left.M2 + right.M2 + result.M3 = left.M3 + right.M3 + result.M4 = left.M4 + right.M4 + result.M5 = left.M5 + right.M5 + result.M6 = left.M6 + right.M6 + result.M7 = left.M7 + right.M7 + result.M8 = left.M8 + right.M8 + result.M9 = left.M9 + right.M9 + result.M10 = left.M10 + right.M10 + result.M11 = left.M11 + right.M11 + result.M12 = left.M12 + right.M12 + result.M13 = left.M13 + right.M13 + result.M14 = left.M14 + right.M14 + result.M15 = left.M15 + right.M15 + + return result +} + +// MatrixSubtract - Subtract two matrices (left - right) +func MatrixSubtract(left, right Matrix) Matrix { + result := MatrixIdentity() + + result.M0 = left.M0 - right.M0 + result.M1 = left.M1 - right.M1 + result.M2 = left.M2 - right.M2 + result.M3 = left.M3 - right.M3 + result.M4 = left.M4 - right.M4 + result.M5 = left.M5 - right.M5 + result.M6 = left.M6 - right.M6 + result.M7 = left.M7 - right.M7 + result.M8 = left.M8 - right.M8 + result.M9 = left.M9 - right.M9 + result.M10 = left.M10 - right.M10 + result.M11 = left.M11 - right.M11 + result.M12 = left.M12 - right.M12 + result.M13 = left.M13 - right.M13 + result.M14 = left.M14 - right.M14 + result.M15 = left.M15 - right.M15 + + 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( + 1.0, 0.0, 0.0, x, + 0.0, 1.0, 0.0, y, + 0.0, 0.0, 1.0, z, + 0, 0, 0, 1.0) +} + +// MatrixRotate - Returns rotation matrix for an angle around an specified axis (angle in radians) +func MatrixRotate(axis Vector3, angle float32) Matrix { + var result Matrix + + mat := MatrixIdentity() + + x := axis.X + y := axis.Y + z := axis.Z + + length := float32(math.Sqrt(float64(x*x + y*y + z*z))) + + if length != 1.0 && length != 0.0 { + length = 1.0 / length + x *= length + y *= length + z *= length + } + + sinres := float32(math.Sin(float64(angle))) + cosres := float32(math.Cos(float64(angle))) + t := 1.0 - cosres + + // Cache some matrix values (speed optimization) + a00 := mat.M0 + a01 := mat.M1 + a02 := mat.M2 + a03 := mat.M3 + a10 := mat.M4 + a11 := mat.M5 + a12 := mat.M6 + a13 := mat.M7 + a20 := mat.M8 + a21 := mat.M9 + a22 := mat.M10 + a23 := mat.M11 + + // Construct the elements of the rotation matrix + b00 := x*x*t + cosres + b01 := y*x*t + z*sinres + b02 := z*x*t - y*sinres + b10 := x*y*t - z*sinres + b11 := y*y*t + cosres + b12 := z*y*t + x*sinres + b20 := x*z*t + y*sinres + b21 := y*z*t - x*sinres + b22 := z*z*t + cosres + + // Perform rotation-specific matrix multiplication + result.M0 = a00*b00 + a10*b01 + a20*b02 + result.M1 = a01*b00 + a11*b01 + a21*b02 + result.M2 = a02*b00 + a12*b01 + a22*b02 + result.M3 = a03*b00 + a13*b01 + a23*b02 + result.M4 = a00*b10 + a10*b11 + a20*b12 + result.M5 = a01*b10 + a11*b11 + a21*b12 + result.M6 = a02*b10 + a12*b11 + a22*b12 + result.M7 = a03*b10 + a13*b11 + a23*b12 + result.M8 = a00*b20 + a10*b21 + a20*b22 + result.M9 = a01*b20 + a11*b21 + a21*b22 + result.M10 = a02*b20 + a12*b21 + a22*b22 + result.M11 = a03*b20 + a13*b21 + a23*b22 + result.M12 = mat.M12 + result.M13 = mat.M13 + result.M14 = mat.M14 + result.M15 = mat.M15 + + return result +} + +// MatrixRotateX - Returns x-rotation matrix (angle in radians) +func MatrixRotateX(angle float32) Matrix { + result := MatrixIdentity() + + cosres := float32(math.Cos(float64(angle))) + sinres := float32(math.Sin(float64(angle))) + + result.M5 = cosres + result.M6 = -sinres + result.M9 = sinres + result.M10 = cosres + + return result +} + +// MatrixRotateY - Returns y-rotation matrix (angle in radians) +func MatrixRotateY(angle float32) Matrix { + result := MatrixIdentity() + + cosres := float32(math.Cos(float64(angle))) + sinres := float32(math.Sin(float64(angle))) + + result.M0 = cosres + result.M2 = sinres + result.M8 = -sinres + result.M10 = cosres + + return result +} + +// MatrixRotateZ - Returns z-rotation matrix (angle in radians) +func MatrixRotateZ(angle float32) Matrix { + result := MatrixIdentity() + + cosres := float32(math.Cos(float64(angle))) + sinres := float32(math.Sin(float64(angle))) + + result.M0 = cosres + result.M1 = -sinres + result.M4 = sinres + result.M5 = cosres + + 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( + x, 0.0, 0.0, 0.0, + 0.0, y, 0.0, 0.0, + 0.0, 0.0, z, 0.0, + 0.0, 0.0, 0.0, 1.0) + + return result +} + +// MatrixFrustum - Returns perspective projection matrix +func MatrixFrustum(left, right, bottom, top, near, far float32) Matrix { + var result Matrix + + rl := right - left + tb := top - bottom + fn := far - near + + result.M0 = (near * 2.0) / rl + result.M1 = 0.0 + result.M2 = 0.0 + result.M3 = 0.0 + + result.M4 = 0.0 + result.M5 = (near * 2.0) / tb + result.M6 = 0.0 + result.M7 = 0.0 + + result.M8 = right + left/rl + result.M9 = top + bottom/tb + result.M10 = -(far + near) / fn + result.M11 = -1.0 + + result.M12 = 0.0 + result.M13 = 0.0 + result.M14 = -(far * near * 2.0) / fn + result.M15 = 0.0 + + return result +} + +// MatrixPerspective - Returns perspective projection matrix +func MatrixPerspective(fovy, aspect, near, far float32) Matrix { + top := near * float32(math.Tan(float64(fovy*Pi)/360.0)) + right := top * aspect + + return MatrixFrustum(-right, right, -top, top, near, far) +} + +// MatrixOrtho - Returns orthographic projection matrix +func MatrixOrtho(left, right, bottom, top, near, far float32) Matrix { + var result Matrix + + rl := right - left + tb := top - bottom + fn := far - near + + result.M0 = 2.0 / rl + result.M1 = 0.0 + result.M2 = 0.0 + result.M3 = 0.0 + result.M4 = 0.0 + result.M5 = 2.0 / tb + result.M6 = 0.0 + result.M7 = 0.0 + result.M8 = 0.0 + result.M9 = 0.0 + result.M10 = -2.0 / fn + result.M11 = 0.0 + result.M12 = -(left + right) / rl + result.M13 = -(top + bottom) / tb + result.M14 = -(far + near) / fn + result.M15 = 1.0 + + return result +} + +// MatrixLookAt - Returns camera look-at matrix (view matrix) +func MatrixLookAt(eye, target, up Vector3) Matrix { + var result Matrix + + z := Vector3Subtract(eye, target) + z = Vector3Normalize(z) + x := Vector3CrossProduct(up, z) + x = Vector3Normalize(x) + y := Vector3CrossProduct(z, x) + y = Vector3Normalize(y) + + result.M0 = x.X + result.M1 = x.Y + result.M2 = x.Z + result.M3 = -((x.X * eye.X) + (x.Y * eye.Y) + (x.Z * eye.Z)) + result.M4 = y.X + result.M5 = y.Y + result.M6 = y.Z + result.M7 = -((y.X * eye.X) + (y.Y * eye.Y) + (y.Z * eye.Z)) + result.M8 = z.X + result.M9 = z.Y + result.M10 = z.Z + result.M11 = -((z.X * eye.X) + (z.Y * eye.Y) + (z.Z * eye.Z)) + result.M12 = 0.0 + result.M13 = 0.0 + result.M14 = 0.0 + result.M15 = 1.0 + + 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))) +} + +// QuaternionNormalize - Normalize provided quaternion +func QuaternionNormalize(q Quaternion) Quaternion { + result := q + + length := QuaternionLength(q) + + if length != 0.0 { + result.X /= length + result.Y /= length + result.Z /= length + result.W /= length + } + + return result +} + +// QuaternionInvert - Invert provided quaternion +func QuaternionInvert(quat Quaternion) Quaternion { + result := quat + + length := QuaternionLength(quat) + lengthSq := length * length + + if lengthSq != 0.0 { + i := 1.0 / lengthSq + + result.X *= -i + result.Y *= -i + result.Z *= -i + result.W *= i + } + + return result +} + +// QuaternionMultiply - Calculate two quaternion multiplication +func QuaternionMultiply(q1, q2 Quaternion) Quaternion { + var result Quaternion + + qax := q1.X + qay := q1.Y + qaz := q1.Z + qaw := q1.W + qbx := q2.X + qby := q2.Y + qbz := q2.Z + qbw := q2.W + + result.X = qax*qbw + qaw*qbx + qay*qbz - qaz*qby + result.Y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz + result.Z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx + result.W = qaw*qbw - qax*qbx - qay*qby - qaz*qbz + + 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 + + cosHalfTheta := q1.X*q2.X + q1.Y*q2.Y + q1.Z*q2.Z + q1.W*q2.W + + if math.Abs(float64(cosHalfTheta)) >= 1.0 { + result = q1 + } else { + halfTheta := float32(math.Acos(float64(cosHalfTheta))) + sinHalfTheta := float32(math.Sqrt(float64(1.0 - cosHalfTheta*cosHalfTheta))) + + if math.Abs(float64(sinHalfTheta)) < 0.001 { + result.X = q1.X*0.5 + q2.X*0.5 + result.Y = q1.Y*0.5 + q2.Y*0.5 + result.Z = q1.Z*0.5 + q2.Z*0.5 + result.W = q1.W*0.5 + q2.W*0.5 + } else { + ratioA := float32(math.Sin(float64((1-amount)*halfTheta))) / sinHalfTheta + ratioB := float32(math.Sin(float64(amount*halfTheta))) / sinHalfTheta + + result.X = q1.X*ratioA + q2.X*ratioB + result.Y = q1.Y*ratioA + q2.Y*ratioB + result.Z = q1.Z*ratioA + q2.Z*ratioB + result.W = q1.W*ratioA + q2.W*ratioB + } + } + + 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 + + trace := MatrixTrace(matrix) + + if trace > 0.0 { + s := float32(math.Sqrt(float64(trace+1)) * 2.0) + invS := 1.0 / s + + result.W = s * 0.25 + result.X = (matrix.M6 - matrix.M9) * invS + result.Y = (matrix.M8 - matrix.M2) * invS + result.Z = (matrix.M1 - matrix.M4) * invS + } else { + m00 := matrix.M0 + m11 := matrix.M5 + m22 := matrix.M10 + + if m00 > m11 && m00 > m22 { + s := float32(math.Sqrt(float64(1.0+m00-m11-m22)) * 2.0) + invS := 1.0 / s + + result.W = (matrix.M6 - matrix.M9) * invS + result.X = s * 0.25 + result.Y = (matrix.M4 + matrix.M1) * invS + result.Z = (matrix.M8 + matrix.M2) * invS + } else if m11 > m22 { + s := float32(math.Sqrt(float64(1.0+m11-m00-m22)) * 2.0) + invS := 1.0 / s + + result.W = (matrix.M8 - matrix.M2) * invS + result.X = (matrix.M4 + matrix.M1) * invS + result.Y = s * 0.25 + result.Z = (matrix.M9 + matrix.M6) * invS + } else { + s := float32(math.Sqrt(float64(1.0+m22-m00-m11)) * 2.0) + invS := 1.0 / s + + result.W = (matrix.M1 - matrix.M4) * invS + result.X = (matrix.M8 + matrix.M2) * invS + result.Y = (matrix.M9 + matrix.M6) * invS + result.Z = s * 0.25 + } + } + + return result +} + +// QuaternionToMatrix - Returns a matrix for a given quaternion +func QuaternionToMatrix(q Quaternion) Matrix { + var result Matrix + + x := q.X + y := q.Y + z := q.Z + w := q.W + + x2 := x + x + y2 := y + y + z2 := z + z + + xx := x * x2 + xy := x * y2 + xz := x * z2 + + yy := y * y2 + yz := y * z2 + zz := z * z2 + + wx := w * x2 + wy := w * y2 + wz := w * z2 + + result.M0 = 1.0 - (yy + zz) + result.M1 = xy - wz + result.M2 = xz + wy + result.M3 = 0.0 + result.M4 = xy + wz + result.M5 = 1.0 - (xx + zz) + result.M6 = yz - wx + result.M7 = 0.0 + result.M8 = xz - wy + result.M9 = yz + wx + result.M10 = 1.0 - (xx + yy) + result.M11 = 0.0 + result.M12 = 0.0 + result.M13 = 0.0 + result.M14 = 0.0 + result.M15 = 1.0 + + return result +} + +// QuaternionFromAxisAngle - Returns rotation quaternion for an angle and axis +func QuaternionFromAxisAngle(axis Vector3, angle float32) Quaternion { + result := NewQuaternion(0.0, 0.0, 0.0, 1.0) + + if Vector3Length(axis) != 0.0 { + angle *= 0.5 + } + + axis = Vector3Normalize(axis) + + sinres := float32(math.Sin(float64(angle))) + cosres := float32(math.Cos(float64(angle))) + + result.X = axis.X * sinres + result.Y = axis.Y * sinres + result.Z = axis.Z * sinres + result.W = cosres + + result = QuaternionNormalize(result) + + return result +} + +// QuaternionToAxisAngle - Returns the rotation angle and axis for a given quaternion +func QuaternionToAxisAngle(q Quaternion, outAxis *Vector3, outAngle *float32) { + if math.Abs(float64(q.W)) > 1.0 { + q = QuaternionNormalize(q) + } + + resAxis := NewVector3(0.0, 0.0, 0.0) + + resAngle := 2.0 * float32(math.Acos(float64(q.W))) + den := float32(math.Sqrt(float64(1.0 - q.W*q.W))) + + if den > 0.0001 { + resAxis.X = q.X / den + resAxis.Y = q.Y / den + resAxis.Z = q.Z / den + } else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + resAxis.X = 1.0 + } + + *outAxis = resAxis + *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 + + x := q.X + y := q.Y + z := q.Z + w := q.W + + result.X = mat.M0*x + mat.M4*y + mat.M8*z + mat.M12*w + result.Y = mat.M1*x + mat.M5*y + mat.M9*z + mat.M13*w + result.Z = mat.M2*x + mat.M6*y + mat.M10*z + mat.M14*w + result.W = mat.M3*x + mat.M7*y + mat.M11*z + mat.M15*w + + 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) + } else { + // Set to identity if close to zero + *rotation = QuaternionIdentity() + } +} diff --git a/raylib/raymath.h b/raylib/raymath.h index b004652..a531b3a 100644 --- a/raylib/raymath.h +++ b/raylib/raymath.h @@ -1,26 +1,38 @@ /********************************************************************************************** * -* raymath v1.2 - Math functions to work with Vector3, Matrix and Quaternions +* 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++ * * 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_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_STATIC_INLINE +* Define static inline functions code, so #include header suffices for use. +* This may use up lots of memory. * +* #define RAYMATH_DISABLE_CPP_OPERATORS +* Disables C++ operator overloads for raymath types. * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-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. @@ -42,32 +54,28 @@ #ifndef RAYMATH_H #define RAYMATH_H -//#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 +#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE) + #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory" #endif -#ifdef __cplusplus - #define RMEXTERN extern "C" // Functions visible from other files (no name mangling of functions in C++) -#else - #define RMEXTERN // Functions visible from other files -#endif - -#if defined RAYMATH_IMPLEMENTATION && defined RAYMATH_HEADER_ONLY - #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_HEADER_ONLY is contradictory" -#endif - -#ifdef RAYMATH_IMPLEMENTATION - #define RMDEF extern inline // Provide external definition -#elif defined RAYMATH_HEADER_ONLY - #define RMDEF static inline // Functions may be inlined, no external out-of-line definition -#else - #ifdef __TINYC__ - #define RMDEF static inline // plain inline not supported by tinycc (See issue #435) +// 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) + #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) + #define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) #else - #define RMDEF inline // Functions may be inlined or external definition used + #define RMAPI 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 +#else + #if defined(__TINYC__) + #define RMAPI static inline // plain inline not supported by tinycc (See issue #435) + #else + #define RMAPI inline // Functions may be inlined or external definition used #endif #endif @@ -76,7 +84,11 @@ // Defines and Macros //---------------------------------------------------------------------------------- #ifndef PI - #define PI 3.14159265358979323846 + #define PI 3.14159265358979323846f +#endif + +#ifndef EPSILON + #define EPSILON 0.000001f #endif #ifndef DEG2RAD @@ -87,66 +99,133 @@ #define RAD2DEG (180.0f/PI) #endif -// Return float vector for Matrix +// Get float vector for Matrix #ifndef MatrixToFloat #define MatrixToFloat(mat) (MatrixToFloatV(mat).v) #endif -// Return float vector for Vector3 +// Get float vector for Vector3 #ifndef Vector3ToFloat - #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v) + #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v) #endif //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- - -#if defined(RAYMATH_STANDALONE) - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; - - // Vector3 type - typedef struct Vector3 { - float x; - float y; - float z; - } Vector3; - - // 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; +#if !defined(RL_VECTOR2_TYPE) +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; +#define RL_VECTOR2_TYPE #endif -// NOTE: Helper types to be used instead of array return types for *ToFloat functions -typedef struct float3 { float v[3]; } float3; -typedef struct float16 { float v[16]; } float16; +#if !defined(RL_VECTOR3_TYPE) +// Vector3 type +typedef struct Vector3 { + float x; + float y; + float z; +} Vector3; +#define RL_VECTOR3_TYPE +#endif -// Quaternion type -typedef struct Quaternion { +#if !defined(RL_VECTOR4_TYPE) +// Vector4 type +typedef struct Vector4 { float x; float y; float z; float w; -} Quaternion; +} Vector4; +#define RL_VECTOR4_TYPE +#endif -#include // Required for: sinf(), cosf(), tan(), fabs() +#if !defined(RL_QUATERNION_TYPE) +// Quaternion type +typedef Vector4 Quaternion; +#define RL_QUATERNION_TYPE +#endif + +#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 +#endif + +// NOTE: Helper types to be used instead of array return types for *ToFloat functions +typedef struct float3 { + float v[3]; +} float3; + +typedef struct float16 { + float v[16]; +} float16; + +#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf() //---------------------------------------------------------------------------------- // Module Functions Definition - Utils math //---------------------------------------------------------------------------------- // Clamp float value -RMDEF float Clamp(float value, float min, float max) +RMAPI float Clamp(float value, float min, float max) { - const float res = value < min ? min : value; - return res > max ? max : res; + float result = (value < min)? min : value; + + if (result > max) result = max; + + return result; +} + +// Calculate linear interpolation between two floats +RMAPI float Lerp(float start, float end, float amount) +{ + float result = start + amount*(end - start); + + return result; +} + +// Normalize input value within input range +RMAPI float Normalize(float value, float start, float end) +{ + float result = (value - start)/(end - start); + + return result; +} + +// Remap input value within input range to output range +RMAPI 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; } //---------------------------------------------------------------------------------- @@ -154,145 +233,434 @@ RMDEF float Clamp(float value, float min, float max) //---------------------------------------------------------------------------------- // Vector with components value 0.0f -RMDEF Vector2 Vector2Zero(void) -{ +RMAPI Vector2 Vector2Zero(void) +{ Vector2 result = { 0.0f, 0.0f }; + return result; } // Vector with components value 1.0f -RMDEF Vector2 Vector2One(void) -{ +RMAPI Vector2 Vector2One(void) +{ Vector2 result = { 1.0f, 1.0f }; + return result; } // Add two vectors (v1 + v2) -RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2) +RMAPI 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) +{ + Vector2 result = { v.x + add, v.y + add }; + return result; } // Subtract two vectors (v1 - v2) -RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +RMAPI 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) +{ + Vector2 result = { v.x - sub, v.y - sub }; + return result; } // Calculate vector length -RMDEF float Vector2Length(Vector2 v) +RMAPI 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) +{ + float result = (v.x*v.x) + (v.y*v.y); + return result; } // Calculate two vectors dot product -RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2) +RMAPI 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 -RMDEF float Vector2Distance(Vector2 v1, Vector2 v2) +RMAPI 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 angle from two vectors in X-axis -RMDEF float Vector2Angle(Vector2 v1, Vector2 v2) +// Calculate square distance between two vectors +RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) { - float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); - if (result < 0) result += 360.0f; + 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); + return result; } // Scale vector (multiply by value) -RMDEF Vector2 Vector2Scale(Vector2 v, float scale) +RMAPI 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) +{ + Vector2 result = { v1.x*v2.x, v1.y*v2.y }; + return result; } // Negate vector -RMDEF Vector2 Vector2Negate(Vector2 v) +RMAPI Vector2 Vector2Negate(Vector2 v) { Vector2 result = { -v.x, -v.y }; + return result; } -// Divide vector by a float value -RMDEF Vector2 Vector2Divide(Vector2 v, float div) +// Divide vector by vector +RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2) { - Vector2 result = { v.x/div, v.y/div }; + Vector2 result = { v1.x/v2.x, v1.y/v2.y }; + return result; } // Normalize provided vector -RMDEF Vector2 Vector2Normalize(Vector2 v) +RMAPI Vector2 Vector2Normalize(Vector2 v) { - Vector2 result = Vector2Divide(v, Vector2Length(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; + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) +{ + Vector2 result = { 0 }; + + result.x = v1.x + amount*(v2.x - v1.x); + result.y = v1.y + amount*(v2.y - v1.y); + + return result; +} + +// Calculate reflected vector to normal +RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal) +{ + Vector2 result = { 0 }; + + float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product + + result.x = v.x - (2.0f*normal.x)*dotProduct; + result.y = v.y - (2.0f*normal.y)*dotProduct; + + return result; +} + +// Get min value for each pair of components +RMAPI Vector2 Vector2Min(Vector2 v1, Vector2 v2) +{ + 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; + + return result; +} + +// Move Vector towards target +RMAPI 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; + + float dist = sqrtf(value); + + result.x = v.x + dx/dist*maxDistance; + result.y = v.y + dy/dist*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 -RMDEF Vector3 Vector3Zero(void) -{ +RMAPI Vector3 Vector3Zero(void) +{ Vector3 result = { 0.0f, 0.0f, 0.0f }; - return result; + + return result; } // Vector with components value 1.0f -RMDEF Vector3 Vector3One(void) -{ +RMAPI Vector3 Vector3One(void) +{ Vector3 result = { 1.0f, 1.0f, 1.0f }; - return result; + + return result; } // Add two vectors -RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2) +RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2) { Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - return result; + + return result; } -// Substract two vectors -RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) +// Add vector and float value +RMAPI 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) { Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; - return result; + + return result; +} + +// Subtract vector by float value +RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub) +{ + Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; + + return result; } // Multiply vector by scalar -RMDEF Vector3 Vector3Multiply(Vector3 v, float scalar) +RMAPI Vector3 Vector3Scale(Vector3 v, float scalar) { Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar }; + return result; } // Multiply vector by vector -RMDEF Vector3 Vector3MultiplyV(Vector3 v1, Vector3 v2) -{ +RMAPI 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 -RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) +RMAPI 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 -RMDEF Vector3 Vector3Perpendicular(Vector3 v) +RMAPI Vector3 Vector3Perpendicular(Vector3 v) { Vector3 result = { 0 }; @@ -312,62 +680,141 @@ RMDEF Vector3 Vector3Perpendicular(Vector3 v) cardinalAxis = tmp; } - result = Vector3CrossProduct(v, cardinalAxis); + // 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; return result; } // Calculate vector length -RMDEF float Vector3Length(const Vector3 v) +RMAPI 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) +{ + float result = v.x*v.x + v.y*v.y + v.z*v.z; + return result; } // Calculate two vectors dot product -RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2) +RMAPI 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 -RMDEF float Vector3Distance(Vector3 v1, Vector3 v2) +RMAPI 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; - float result = sqrtf(dx*dx + dy*dy + dz*dz); + result = sqrtf(dx*dx + dy*dy + dz*dz); + return result; } -// Scale provided vector -RMDEF Vector3 Vector3Scale(Vector3 v, float scale) +// Calculate square distance between two vectors +RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2) { - Vector3 result = { v.x*scale, v.y*scale, v.z*scale }; + 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); + return result; } // Negate provided vector (invert direction) -RMDEF Vector3 Vector3Negate(Vector3 v) +RMAPI 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) +{ + Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; + return result; } // Normalize provided vector -RMDEF Vector3 Vector3Normalize(Vector3 v) +RMAPI Vector3 Vector3Normalize(Vector3 v) { Vector3 result = v; - - 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; + float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length != 0.0f) + { + float 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); return result; } @@ -375,18 +822,43 @@ RMDEF Vector3 Vector3Normalize(Vector3 v) // Orthonormalize provided vectors // Makes vectors normalized and orthogonal to each other // Gram-Schmidt function implementation -RMDEF void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) +RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) { - *v1 = Vector3Normalize(*v1); - Vector3 vn = Vector3CrossProduct(*v1, *v2); - vn = Vector3Normalize(vn); - *v2 = Vector3CrossProduct(vn, *v1); + 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; } // Transforms a Vector3 by a given Matrix -RMDEF Vector3 Vector3Transform(Vector3 v, Matrix mat) +RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat) { Vector3 result = { 0 }; + float x = v.x; float y = v.y; float z = v.z; @@ -394,12 +866,97 @@ RMDEF Vector3 Vector3Transform(Vector3 v, Matrix mat) 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; result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; - + return result; -}; +} + +// Transform a vector by quaternion rotation +RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) +{ + Vector3 result = { 0 }; + + 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; +} + +// 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 -RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) +RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) { Vector3 result = { 0 }; @@ -410,16 +967,32 @@ RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) return result; } -// Calculate reflected vector to normal -RMDEF Vector3 Vector3Reflect(Vector3 v, Vector3 normal) +// 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) { - // I is the original vector - // N is the normal of the incident plane - // R = I - (2*N*( DotProduct[ I,N] )) - Vector3 result = { 0 }; - float dotProduct = Vector3DotProduct(v, normal); + 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) +{ + Vector3 result = { 0 }; + + // I is the original vector + // N is the normal of the incident plane + // R = I - (2*N*(DotProduct[I, N])) + + float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z); result.x = v.x - (2.0f*normal.x)*dotProduct; result.y = v.y - (2.0f*normal.y)*dotProduct; @@ -428,58 +1001,140 @@ RMDEF Vector3 Vector3Reflect(Vector3 v, Vector3 normal) return result; } -// Return min value for each pair of components -RMDEF Vector3 Vector3Min(Vector3 v1, Vector3 v2) +// Get min value for each pair of components +RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2) { Vector3 result = { 0 }; - + result.x = fminf(v1.x, v2.x); result.y = fminf(v1.y, v2.y); result.z = fminf(v1.z, v2.z); - + return result; } -// Return max value for each pair of components -RMDEF Vector3 Vector3Max(Vector3 v1, Vector3 v2) +// Get max value for each pair of components +RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2) { Vector3 result = { 0 }; - + result.x = fmaxf(v1.x, v2.x); result.y = fmaxf(v1.y, v2.y); result.z = fmaxf(v1.z, v2.z); - + return result; } // 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 -RMDEF Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) +RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { - //Vector v0 = b - a, v1 = c - a, v2 = p - a; - - 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 }; - + + 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) + + float denom = d00*d11 - d01*d01; + result.y = (d11*d20 - d01*d21)/denom; result.z = (d00*d21 - d01*d20)/denom; result.x = 1.0f - (result.z + result.y); - + return result; } -// Returns Vector3 as float array -RMDEF float3 Vector3ToFloatV(Vector3 v) +// 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) { float3 buffer = { 0 }; @@ -490,40 +1145,372 @@ RMDEF 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 -RMDEF float MatrixDeterminant(Matrix mat) +RMAPI float MatrixDeterminant(Matrix mat) { - float result = { 0 }; - + 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)))); return result; } -// Returns the trace of the matrix (sum of the values along the diagonal) -RMDEF float MatrixTrace(Matrix mat) +// Get the trace of the matrix (sum of the values along the diagonal) +RMAPI float MatrixTrace(Matrix mat) { float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15); + return result; } // Transposes provided matrix -RMDEF Matrix MatrixTranspose(Matrix mat) +RMAPI Matrix MatrixTranspose(Matrix mat) { Matrix result = { 0 }; @@ -548,7 +1535,7 @@ RMDEF Matrix MatrixTranspose(Matrix mat) } // Invert provided matrix -RMDEF Matrix MatrixInvert(Matrix mat) +RMAPI Matrix MatrixInvert(Matrix mat) { Matrix result = { 0 }; @@ -594,38 +1581,11 @@ RMDEF Matrix MatrixInvert(Matrix mat) return result; } -// Normalize provided matrix -RMDEF Matrix MatrixNormalize(Matrix mat) +// Get identity matrix +RMAPI Matrix MatrixIdentity(void) { - 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, + 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 }; @@ -633,9 +1593,9 @@ RMDEF Matrix MatrixIdentity(void) } // Add two matrices -RMDEF Matrix MatrixAdd(Matrix left, Matrix right) +RMAPI Matrix MatrixAdd(Matrix left, Matrix right) { - Matrix result = MatrixIdentity(); + Matrix result = { 0 }; result.m0 = left.m0 + right.m0; result.m1 = left.m1 + right.m1; @@ -657,10 +1617,10 @@ RMDEF Matrix MatrixAdd(Matrix left, Matrix right) return result; } -// Substract two matrices (left - right) -RMDEF Matrix MatrixSubstract(Matrix left, Matrix right) +// Subtract two matrices (left - right) +RMAPI Matrix MatrixSubtract(Matrix left, Matrix right) { - Matrix result = MatrixIdentity(); + Matrix result = { 0 }; result.m0 = left.m0 - right.m0; result.m1 = left.m1 - right.m1; @@ -682,124 +1642,9 @@ RMDEF Matrix MatrixSubstract(Matrix left, Matrix right) return result; } -// 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, - 0.0f, 0.0f, 1.0f, z, - 0.0f, 0.0f, 0.0f, 1.0f }; - - return result; -} - -// Create rotation matrix from axis and angle -// NOTE: Angle should be provided in radians -RMDEF Matrix MatrixRotate(Vector3 axis, float angle) -{ - Matrix result = { 0 }; - - float x = axis.x, y = axis.y, z = axis.z; - - float length = sqrtf(x*x + y*y + z*z); - - if ((length != 1.0f) && (length != 0.0f)) - { - length = 1.0f/length; - x *= length; - y *= length; - z *= length; - } - - 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.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.m10 = z*z*t + cosres; - result.m11 = 0.0f; - - result.m12 = 0.0f; - result.m13 = 0.0f; - result.m14 = 0.0f; - result.m15 = 1.0f; - - return result; -} - -// Returns x-rotation matrix (angle in radians) -RMDEF Matrix MatrixRotateX(float angle) -{ - Matrix result = MatrixIdentity(); - - float cosres = cosf(angle); - float sinres = sinf(angle); - - result.m5 = cosres; - result.m6 = -sinres; - result.m9 = sinres; - result.m10 = cosres; - - return result; -} - -// Returns y-rotation matrix (angle in radians) -RMDEF Matrix MatrixRotateY(float angle) -{ - Matrix result = MatrixIdentity(); - - float cosres = cosf(angle); - float sinres = sinf(angle); - - result.m0 = cosres; - result.m2 = sinres; - result.m8 = -sinres; - result.m10 = cosres; - - return result; -} - -// Returns z-rotation matrix (angle in radians) -RMDEF Matrix MatrixRotateZ(float angle) -{ - Matrix result = MatrixIdentity(); - - float cosres = cosf(angle); - float sinres = sinf(angle); - - result.m0 = cosres; - result.m1 = -sinres; - result.m4 = sinres; - result.m5 = cosres; - - return result; -} - -// 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, - 0.0f, 0.0f, z, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - - return result; -} - -// Returns two matrix multiplication +// Get two matrix multiplication // NOTE: When multiplying matrices... the order matters! -RMDEF Matrix MatrixMultiply(Matrix left, Matrix right) +RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) { Matrix result = { 0 }; @@ -823,57 +1668,268 @@ RMDEF Matrix MatrixMultiply(Matrix left, Matrix right) return result; } -// Returns perspective projection matrix -RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far) +// Get translation matrix +RMAPI Matrix MatrixTranslate(float x, float y, float z) +{ + Matrix result = { 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 }; + + return result; +} + +// Create rotation matrix from axis and angle +// NOTE: Angle should be provided in radians +RMAPI Matrix MatrixRotate(Vector3 axis, float angle) { Matrix result = { 0 }; - float rl = (right - left); - float tb = (top - bottom); - float fn = (far - near); + float x = axis.x, y = axis.y, z = axis.z; - result.m0 = (near*2.0f)/rl; + float lengthSquared = x*x + y*y + z*z; + + if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) + { + float ilength = 1.0f/sqrtf(lengthSquared); + x *= ilength; + y *= ilength; + z *= ilength; + } + + 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.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.m10 = z*z*t + cosres; + result.m11 = 0.0f; + + result.m12 = 0.0f; + result.m13 = 0.0f; + result.m14 = 0.0f; + result.m15 = 1.0f; + + return result; +} + +// Get x-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI 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() + + float cosres = cosf(angle); + float sinres = sinf(angle); + + result.m5 = cosres; + 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) +{ + 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 cosres = cosf(angle); + float sinres = sinf(angle); + + result.m0 = cosres; + 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) +{ + 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 cosres = cosf(angle); + float sinres = sinf(angle); + + result.m0 = cosres; + 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) +{ + 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 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); + + result.m0 = cosz*cosy; + result.m1 = (cosz*siny*sinx) - (sinz*cosx); + result.m2 = (cosz*siny*cosx) + (sinz*sinx); + + result.m4 = sinz*cosy; + result.m5 = (sinz*siny*sinx) + (cosz*cosx); + result.m6 = (sinz*siny*cosx) - (cosz*sinx); + + result.m8 = -siny; + result.m9 = cosy*sinx; + result.m10= cosy*cosx; + + return result; +} + +// Get zyx-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateZYX(Vector3 angle) +{ + 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); + + 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.m3 = 0; + result.m7 = 0; + result.m11 = 0; + result.m15 = 1; + + return result; +} + +// Get scaling matrix +RMAPI Matrix MatrixScale(float x, float y, float z) +{ + Matrix result = { 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 }; + + return result; +} + +// Get perspective projection matrix +RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) +{ + Matrix result = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(farPlane - nearPlane); + + result.m0 = ((float)nearPlane*2.0f)/rl; result.m1 = 0.0f; result.m2 = 0.0f; result.m3 = 0.0f; result.m4 = 0.0f; - result.m5 = (near*2.0f)/tb; + result.m5 = ((float)nearPlane*2.0f)/tb; result.m6 = 0.0f; result.m7 = 0.0f; - result.m8 = (right + left)/rl; - result.m9 = (top + bottom)/tb; - result.m10 = -(far + near)/fn; + 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.m12 = 0.0f; result.m13 = 0.0f; - result.m14 = -(far*near*2.0f)/fn; + result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; result.m15 = 0.0f; return result; } -// Returns perspective projection matrix -// NOTE: Angle should be provided in radians -RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far) -{ - double top = near*tan(fovy*0.5); - double right = top*aspect; - Matrix result = MatrixFrustum(-right, right, -top, top, near, far); - - return result; -} - -// Returns orthographic projection matrix -RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) +// Get perspective projection matrix +// NOTE: Fovy angle must be provided in radians +RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane) { Matrix result = { 0 }; - float rl = (right - left); - float tb = (top - bottom); - float fn = (far - near); + double top = nearPlane*tan(fovY*0.5); + double bottom = -top; + 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; + + return result; +} + +// Get orthographic projection matrix +RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane) +{ + Matrix result = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(farPlane - nearPlane); result.m0 = 2.0f/rl; result.m1 = 0.0f; @@ -887,131 +1943,185 @@ RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, d result.m9 = 0.0f; result.m10 = -2.0f/fn; result.m11 = 0.0f; - result.m12 = -(left + right)/rl; - result.m13 = -(top + bottom)/tb; - result.m14 = -(far + near)/fn; + result.m12 = -((float)left + (float)right)/rl; + result.m13 = -((float)top + (float)bottom)/tb; + result.m14 = -((float)farPlane + (float)nearPlane)/fn; result.m15 = 1.0f; return result; } -// Returns camera look-at matrix (view matrix) -RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) +// Get camera look-at matrix (view matrix) +RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) { Matrix result = { 0 }; - Vector3 z = Vector3Subtract(eye, target); - z = Vector3Normalize(z); - Vector3 x = Vector3CrossProduct(up, z); - x = Vector3Normalize(x); - Vector3 y = Vector3CrossProduct(z, x); - y = Vector3Normalize(y); - - result.m0 = x.x; - result.m1 = x.y; - result.m2 = x.z; - result.m3 = 0.0f; - result.m4 = y.x; - result.m5 = y.y; - result.m6 = y.z; - result.m7 = 0.0f; - result.m8 = z.x; - result.m9 = z.y; - result.m10 = z.z; - result.m11 = 0.0f; - result.m12 = eye.x; - result.m13 = eye.y; - result.m14 = eye.z; - result.m15 = 1.0f; + float length = 0.0f; + float ilength = 0.0f; - result = MatrixInvert(result); + // 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.m3 = 0.0f; + result.m4 = vx.y; + result.m5 = vy.y; + result.m6 = vz.y; + result.m7 = 0.0f; + result.m8 = vx.z; + result.m9 = vy.z; + result.m10 = vz.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.m15 = 1.0f; return result; } -// Returns float array of matrix data -RMDEF float16 MatrixToFloatV(Matrix mat) +// Get float array of matrix data +RMAPI float16 MatrixToFloatV(Matrix mat) { - float16 buffer = { 0 }; + float16 result = { 0 }; - 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; + 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 buffer; + return result; } //---------------------------------------------------------------------------------- // Module Functions Definition - Quaternion math //---------------------------------------------------------------------------------- -// Returns identity quaternion -RMDEF Quaternion QuaternionIdentity(void) +// Add two quaternions +RMAPI 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) +{ + 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) +{ + 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) +{ + Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub}; + + return result; +} + +// Get identity quaternion +RMAPI Quaternion QuaternionIdentity(void) { Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; + return result; } // Computes the length of a quaternion -RMDEF float QuaternionLength(Quaternion q) +RMAPI float QuaternionLength(Quaternion q) { - float result = sqrt(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + return result; } // Normalize provided quaternion -RMDEF Quaternion QuaternionNormalize(Quaternion q) +RMAPI Quaternion QuaternionNormalize(Quaternion q) { Quaternion result = { 0 }; - - float length, ilength; - length = QuaternionLength(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; - ilength = 1.0f/length; + 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; } // Invert provided quaternion -RMDEF Quaternion QuaternionInvert(Quaternion q) +RMAPI Quaternion QuaternionInvert(Quaternion q) { Quaternion result = q; - float length = QuaternionLength(q); - float lengthSq = length*length; - - if (lengthSq != 0.0) + + float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; + + if (lengthSq != 0.0f) { - float i = 1.0f/lengthSq; - - result.x *= -i; - result.y *= -i; - result.z *= -i; - result.w *= i; + float invLength = 1.0f/lengthSq; + + result.x *= -invLength; + result.y *= -invLength; + result.z *= -invLength; + result.w *= invLength; } - + return result; } // Calculate two quaternion multiplication -RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) +RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) { Quaternion result = { 0 }; @@ -1026,8 +2136,29 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) return result; } +// Scale quaternion by float value +RMAPI 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; + + return result; +} + +// Divide two quaternions +RMAPI 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 -RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) +RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) { Quaternion result = { 0 }; @@ -1040,29 +2171,55 @@ RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) } // Calculate slerp-optimized interpolation between two quaternions -RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) +RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) { - Quaternion result = QuaternionLerp(q1, q2, amount); - result = QuaternionNormalize(result); - + 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; + return result; } // Calculates spherical linear interpolation between two quaternions -RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) +RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) { Quaternion result = { 0 }; - float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif - if (fabs(cosHalfTheta) >= 1.0f) result = q1; + float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; + + if (cosHalfTheta < 0) + { + q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w; + cosHalfTheta = -cosHalfTheta; + } + + if (fabsf(cosHalfTheta) >= 1.0f) result = q1; else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); else { - float halfTheta = acos(cosHalfTheta); - float sinHalfTheta = sqrt(1.0f - cosHalfTheta*cosHalfTheta); + float halfTheta = acosf(cosHalfTheta); + float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta); - if (fabs(sinHalfTheta) < 0.001f) + if (fabsf(sinHalfTheta) < EPSILON) { result.x = (q1.x*0.5f + q2.x*0.5f); result.y = (q1.y*0.5f + q2.y*0.5f); @@ -1084,167 +2241,223 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) return result; } -// Calculate quaternion based on the rotation from one vector to another -RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) +// 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) { + 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 }; - float cos2Theta = Vector3DotProduct(from, to); - Vector3 cross = Vector3CrossProduct(from, to); - - result.x = cross.x; - result.y = cross.y; - result.z = cross.y; - 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 }; - - float trace = MatrixTrace(mat); - - if (trace > 0.0f) - { - float s = (float)sqrt(trace + 1)*2.0f; - float invS = 1.0f/s; - - result.w = s*0.25f; - result.x = (mat.m6 - mat.m9)*invS; - result.y = (mat.m8 - mat.m2)*invS; - result.z = (mat.m1 - mat.m4)*invS; - } - else - { - float m00 = mat.m0, m11 = mat.m5, m22 = mat.m10; - - if (m00 > m11 && m00 > m22) - { - float s = (float)sqrt(1.0f + m00 - m11 - m22)*2.0f; - float invS = 1.0f/s; - - result.w = (mat.m6 - mat.m9)*invS; - result.x = s*0.25f; - result.y = (mat.m4 + mat.m1)*invS; - result.z = (mat.m8 + mat.m2)*invS; - } - else if (m11 > m22) - { - float s = (float)sqrt(1.0f + m11 - m00 - m22)*2.0f; - float invS = 1.0f/s; - - result.w = (mat.m8 - mat.m2)*invS; - result.x = (mat.m4 + mat.m1)*invS; - result.y = s*0.25f; - result.z = (mat.m9 + mat.m6)*invS; - } - else - { - float s = (float)sqrt(1.0f + m22 - m00 - m11)*2.0f; - float invS = 1.0f/s; - - result.w = (mat.m1 - mat.m4)*invS; - result.x = (mat.m8 + mat.m2)*invS; - result.y = (mat.m9 + mat.m6)*invS; - result.z = s*0.25f; - } - } - - return result; -} - -// Returns a matrix for a given quaternion -RMDEF Matrix QuaternionToMatrix(Quaternion q) -{ - Matrix result = { 0 }; - - float x = q.x, y = q.y, z = q.z, w = q.w; - - float x2 = x + x; - float y2 = y + y; - float z2 = z + z; - - float length = QuaternionLength(q); - float lengthSquared = length*length; - - float xx = x*x2/lengthSquared; - float xy = x*y2/lengthSquared; - float xz = x*z2/lengthSquared; - - float yy = y*y2/lengthSquared; - float yz = y*z2/lengthSquared; - float zz = z*z2/lengthSquared; - - float wx = w*x2/lengthSquared; - float wy = w*y2/lengthSquared; - float wz = w*z2/lengthSquared; - - result.m0 = 1.0f - (yy + zz); - result.m1 = xy - wz; - result.m2 = xz + wy; - result.m3 = 0.0f; - result.m4 = xy + wz; - result.m5 = 1.0f - (xx + zz); - result.m6 = yz - wx; - result.m7 = 0.0f; - result.m8 = xz - wy; - result.m9 = yz + wx; - result.m10 = 1.0f - (xx + yy); - result.m11 = 0.0f; - result.m12 = 0.0f; - result.m13 = 0.0f; - result.m14 = 0.0f; - result.m15 = 1.0f; - - 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 = QuaternionAdd(p0, m0); + result = QuaternionAdd(result, p1); + result = QuaternionAdd(result, m1); result = QuaternionNormalize(result); return result; } -// Returns the rotation angle and axis for a given quaternion -RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) +// Calculate quaternion based on the rotation from one vector to another +RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) { - if (fabs(q.w) > 1.0f) q = QuaternionNormalize(q); + 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; + } Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; - float resAngle = 0.0f; + float resAngle = 2.0f*acosf(q.w); + float den = sqrtf(1.0f - q.w*q.w); - resAngle = 2.0f*(float)acos(q.w); - float den = (float)sqrt(1.0f - q.w*q.w); - - if (den > 0.0001f) + if (den > EPSILON) { resAxis.x = q.x/den; resAxis.y = q.y/den; @@ -1261,53 +2474,54 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle *outAngle = resAngle; } -// Returns he quaternion equivalent to Euler angles -RMDEF Quaternion QuaternionFromEuler(float roll, float pitch, float yaw) +// Get the quaternion equivalent to Euler angles +// NOTE: Rotation order is ZYX +RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) { - Quaternion q = { 0 }; + Quaternion result = { 0 }; - float x0 = cosf(roll*0.5f); - float x1 = sinf(roll*0.5f); - float y0 = cosf(pitch*0.5f); - float y1 = sinf(pitch*0.5f); - float z0 = cosf(yaw*0.5f); - float z1 = sinf(yaw*0.5f); + float x0 = cosf(pitch*0.5f); + float x1 = sinf(pitch*0.5f); + float y0 = cosf(yaw*0.5f); + float y1 = sinf(yaw*0.5f); + float z0 = cosf(roll*0.5f); + float z1 = sinf(roll*0.5f); - 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 q; + 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; } -// 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) +// 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) { Vector3 result = { 0 }; - // 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)*RAD2DEG; + // 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); - // 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)*RAD2DEG; + // 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); + + // 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); - // 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)*RAD2DEG; - return result; } // Transform a quaternion given a transformation matrix -RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat) +RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat) { Quaternion result = { 0 }; @@ -1315,8 +2529,438 @@ RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat) result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w; result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w; result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w; - + return result; } +// Check whether two given quaternions are almost equal +RMAPI int QuaternionEquals(Quaternion p, Quaternion 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)))))) || + (((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; +} + +// 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 new file mode 100644 index 0000000..d0df645 --- /dev/null +++ b/raylib/rcamera.go @@ -0,0 +1,350 @@ +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 new file mode 100644 index 0000000..a598e11 --- /dev/null +++ b/raylib/rcamera.h @@ -0,0 +1,555 @@ +/******************************************************************************************* +* +* 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 new file mode 100644 index 0000000..f8b061a --- /dev/null +++ b/raylib/rcore.c @@ -0,0 +1,4134 @@ +/********************************************************************************************** +* +* 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/rcore.go b/raylib/rcore.go new file mode 100644 index 0000000..213a656 --- /dev/null +++ b/raylib/rcore.go @@ -0,0 +1,1282 @@ +package rl + +/* +#include "raylib.h" +#include +*/ +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 (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 +func WindowShouldClose() bool { + ret := C.WindowShouldClose() + v := bool(ret) + return v +} + +// CloseWindow - Close Window and Terminate Context +func CloseWindow() { + C.CloseWindow() +} + +// IsWindowReady - Check if window has been initialized successfully +func IsWindowReady() bool { + ret := C.IsWindowReady() + v := bool(ret) + return v +} + +// IsWindowFullscreen - Check if window is currently fullscreen +func IsWindowFullscreen() bool { + ret := C.IsWindowFullscreen() + v := bool(ret) + return v +} + +// IsWindowHidden - Check if window is currently hidden +func IsWindowHidden() bool { + ret := C.IsWindowHidden() + v := bool(ret) + return v +} + +// IsWindowMinimized - Check if window is currently minimized +func IsWindowMinimized() bool { + ret := C.IsWindowMinimized() + v := bool(ret) + return v +} + +// IsWindowMaximized - Check if window is currently maximized +func IsWindowMaximized() bool { + ret := C.IsWindowMaximized() + v := bool(ret) + return v +} + +// IsWindowFocused - Check if window is currently focused +func IsWindowFocused() bool { + ret := C.IsWindowFocused() + v := bool(ret) + return v +} + +// IsWindowResized - Check if window has been resized +func IsWindowResized() bool { + ret := C.IsWindowResized() + v := bool(ret) + return v +} + +// IsWindowState - Check if one specific window flag is enabled +func IsWindowState(flag uint32) bool { + cflag := (C.uint)(flag) + ret := C.IsWindowState(cflag) + v := bool(ret) + return v +} + +// SetWindowState - Set window configuration state using flags +func SetWindowState(flags uint32) { + cflags := (C.uint)(flags) + C.SetWindowState(cflags) +} + +// ClearWindowState - Clear window configuration state flags +func ClearWindowState(flags uint32) { + cflags := (C.uint)(flags) + C.ClearWindowState(cflags) +} + +// ToggleFullscreen - Fullscreen toggle (only PLATFORM_DESKTOP) +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() +} + +// MinimizeWindow - Set window state: minimized, if resizable +func MinimizeWindow() { + C.MinimizeWindow() +} + +// RestoreWindow - Set window state: not minimized/maximized +func RestoreWindow() { + C.RestoreWindow() +} + +// SetWindowIcon - Set icon for window (single image, RGBA 32bit, 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) + defer C.free(unsafe.Pointer(ctitle)) + C.SetWindowTitle(ctitle) +} + +// SetWindowPosition - Set window position on screen (only PLATFORM_DESKTOP) +func SetWindowPosition(x, y int) { + cx := (C.int)(x) + cy := (C.int)(y) + C.SetWindowPosition(cx, cy) +} + +// SetWindowMonitor - Set monitor for the current window (fullscreen mode) +func SetWindowMonitor(monitor int) { + cmonitor := (C.int)(monitor) + C.SetWindowMonitor(cmonitor) +} + +// SetWindowMinSize - Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) +func SetWindowMinSize(w, h int) { + cw := (C.int)(w) + ch := (C.int)(h) + 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) + ch := (C.int)(h) + 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() + v := (int)(ret) + return v +} + +// GetScreenHeight - Get current screen height +func GetScreenHeight() int { + ret := C.GetScreenHeight() + v := (int)(ret) + 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() + v := (int)(ret) + return v +} + +// GetCurrentMonitor - Get current monitor where window is placed +func GetCurrentMonitor() int { + ret := C.GetCurrentMonitor() + v := (int)(ret) + return v +} + +// GetMonitorPosition - Get specified monitor position +func GetMonitorPosition(monitor int) Vector2 { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorPosition(cmonitor) + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetMonitorWidth - Get primary monitor width +func GetMonitorWidth(monitor int) int { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorWidth(cmonitor) + v := (int)(ret) + return v +} + +// GetMonitorHeight - Get primary monitor height +func GetMonitorHeight(monitor int) int { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorHeight(cmonitor) + v := (int)(ret) + return v +} + +// GetMonitorPhysicalWidth - Get primary monitor physical width in millimetres +func GetMonitorPhysicalWidth(monitor int) int { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorPhysicalWidth(cmonitor) + v := (int)(ret) + return v +} + +// GetMonitorPhysicalHeight - Get primary monitor physical height in millimetres +func GetMonitorPhysicalHeight(monitor int) int { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorPhysicalHeight(cmonitor) + v := (int)(ret) + return v +} + +// GetMonitorRefreshRate - Get specified monitor refresh rate +func GetMonitorRefreshRate(monitor int) int { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorRefreshRate(cmonitor) + v := (int)(ret) + return v +} + +// GetWindowPosition - Get window position XY on monitor +func GetWindowPosition() Vector2 { + ret := C.GetWindowPosition() + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetWindowScaleDPI - Get window scale DPI factor +func GetWindowScaleDPI() Vector2 { + ret := C.GetWindowScaleDPI() + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetMonitorName - Get the human-readable, UTF-8 encoded name of the primary monitor +func GetMonitorName(monitor int) string { + cmonitor := (C.int)(monitor) + ret := C.GetMonitorName(cmonitor) + v := C.GoString(ret) + return v +} + +// SetClipboardText - Set clipboard text content +func SetClipboardText(data string) { + cdata := C.CString(data) + defer C.free(unsafe.Pointer(cdata)) + C.SetClipboardText(cdata) +} + +// GetClipboardText - Get clipboard text content +func GetClipboardText() string { + ret := C.GetClipboardText() + v := C.GoString(ret) + 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) + C.ClearBackground(*ccolor) +} + +// BeginDrawing - Setup drawing canvas to start drawing +func BeginDrawing() { + C.BeginDrawing() +} + +// EndDrawing - End canvas drawing and Swap Buffers (Double Buffering) +func EndDrawing() { + C.EndDrawing() +} + +// BeginMode2D - Initialize 2D mode with custom camera +func BeginMode2D(camera Camera2D) { + ccamera := camera.cptr() + C.BeginMode2D(*ccamera) +} + +// EndMode2D - Ends 2D mode custom camera usage +func EndMode2D() { + C.EndMode2D() +} + +// BeginMode3D - Initializes 3D mode for drawing (Camera setup) +func BeginMode3D(camera Camera) { + ccamera := camera.cptr() + C.BeginMode3D(*ccamera) +} + +// EndMode3D - Ends 3D mode and returns to default 2D orthographic mode +func EndMode3D() { + C.EndMode3D() +} + +// BeginTextureMode - Initializes render texture for drawing +func BeginTextureMode(target RenderTexture2D) { + ctarget := target.cptr() + C.BeginTextureMode(*ctarget) +} + +// EndTextureMode - Ends drawing to render texture +func EndTextureMode() { + C.EndTextureMode() +} + +// BeginScissorMode - Begins scissor mode (define screen area for following drawing) +func BeginScissorMode(x, y, width, height int32) { + cx := (C.int)(x) + cy := (C.int)(y) + cwidth := (C.int)(width) + cheight := (C.int)(height) + C.BeginScissorMode(cx, cy, cwidth, cheight) +} + +// EndScissorMode - Ends scissor mode +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. +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() + 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) + v := newRayFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetCameraMatrix - Returns camera transform matrix (view matrix) +func GetCameraMatrix(camera Camera) Matrix { + ccamera := camera.cptr() + ret := C.GetCameraMatrix(*ccamera) + v := newMatrixFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetCameraMatrix2D - Returns camera 2d transform matrix +func GetCameraMatrix2D(camera Camera2D) Matrix { + ccamera := camera.cptr() + ret := C.GetCameraMatrix2D(*ccamera) + v := newMatrixFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetWorldToScreen - Returns the screen space position from a 3d world space position +func GetWorldToScreen(position Vector3, camera Camera) Vector2 { + cposition := position.cptr() + ccamera := camera.cptr() + ret := C.GetWorldToScreen(*cposition, *ccamera) + v := newVector2FromPointer(unsafe.Pointer(&ret)) + 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() + ccamera := camera.cptr() + ret := C.GetWorldToScreen2D(*cposition, *ccamera) + v := newVector2FromPointer(unsafe.Pointer(&ret)) + return v +} + +// SetTargetFPS - Set target FPS (maximum) +func SetTargetFPS(fps int32) { + cfps := (C.int)(fps) + C.SetTargetFPS(cfps) +} + +// GetFPS - Returns current FPS +func GetFPS() int32 { + ret := C.GetFPS() + v := (int32)(ret) + return v +} + +// GetFrameTime - Returns time in seconds for one frame +func GetFrameTime() float32 { + ret := C.GetFrameTime() + v := (float32)(ret) + return v +} + +// GetTime - Return time in seconds +func GetTime() float64 { + ret := C.GetTime() + v := (float64)(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) + 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) + ret := C.ColorToInt(*ccolor) + v := (int32)(ret) + return v +} + +// ColorNormalize - Returns color normalized as float [0..1] +func ColorNormalize(col color.RGBA) 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 + + return result +} + +// ColorFromNormalized - Returns Color from normalized values [0..1] +func ColorFromNormalized(normalized Vector4) color.RGBA { + cnormalized := normalized.cptr() + ret := C.ColorFromNormalized(*cnormalized) + v := newColorFromPointer(unsafe.Pointer(&ret)) + return v +} + +// ColorToHSV - Returns HSV values for a Color, hue [0..360], saturation/value [0..1] +func ColorToHSV(col color.RGBA) Vector3 { + ccolor := colorCptr(col) + 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 { + chue := (C.float)(hue) + csaturation := (C.float)(saturation) + cvalue := (C.float)(value) + ret := C.ColorFromHSV(chue, csaturation, cvalue) + v := newColorFromPointer(unsafe.Pointer(&ret)) + 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) +} + +// 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) + 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) + ret := C.GetColor(chexValue) + v := newColorFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetPixelDataSize - Get pixel data size in bytes for certain format +func GetPixelDataSize(width, height, format int32) int32 { + cwidth := (C.int)(width) + cheight := (C.int)(height) + cformat := (C.int)(format) + ret := C.GetPixelDataSize(cwidth, cheight, cformat) + v := (int32)(ret) + return v +} + +// Vector3ToFloat - Converts Vector3 to float32 slice +func Vector3ToFloat(vec Vector3) []float32 { + data := make([]float32, 0) + data[0] = vec.X + data[1] = vec.Y + data[2] = vec.Z + + return data +} + +// GetRandomValue - Returns a random value between min and max (both included) +func GetRandomValue(min, max int32) int32 { + cmin := (C.int)(min) + cmax := (C.int)(max) + ret := C.GetRandomValue(cmin, cmax) + v := (int32)(ret) + 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) { + cflags := (C.uint)(flags) + C.SetConfigFlags(cflags) +} + +// TakeScreenshot - Takes a screenshot of current screen (saved a .png) +func TakeScreenshot(name string) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + 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)) + + 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) + ret := C.IsKeyPressed(ckey) + v := bool(ret) + 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) + ret := C.IsKeyDown(ckey) + v := bool(ret) + return v +} + +// IsKeyReleased - Detect if a key has been released once +func IsKeyReleased(key int32) bool { + ckey := (C.int)(key) + ret := C.IsKeyReleased(ckey) + v := bool(ret) + return v +} + +// IsKeyUp - Detect if a key is NOT being pressed +func IsKeyUp(key int32) bool { + ckey := (C.int)(key) + ret := C.IsKeyUp(ckey) + v := bool(ret) + return v +} + +// GetKeyPressed - Get latest key pressed +func GetKeyPressed() int32 { + ret := C.GetKeyPressed() + v := (int32)(ret) + 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) + C.SetExitKey(ckey) +} + +// IsGamepadAvailable - Detect if a gamepad is available +func IsGamepadAvailable(gamepad int32) bool { + cgamepad := (C.int)(gamepad) + ret := C.IsGamepadAvailable(cgamepad) + v := bool(ret) + return v +} + +// GetGamepadName - Return gamepad internal name id +func GetGamepadName(gamepad int32) string { + cgamepad := (C.int)(gamepad) + ret := C.GetGamepadName(cgamepad) + v := C.GoString(ret) + return v +} + +// IsGamepadButtonPressed - Detect if a gamepad button has been pressed once +func IsGamepadButtonPressed(gamepad, button int32) bool { + cgamepad := (C.int)(gamepad) + cbutton := (C.int)(button) + ret := C.IsGamepadButtonPressed(cgamepad, cbutton) + v := bool(ret) + return v +} + +// IsGamepadButtonDown - Detect if a gamepad button is being pressed +func IsGamepadButtonDown(gamepad, button int32) bool { + cgamepad := (C.int)(gamepad) + cbutton := (C.int)(button) + ret := C.IsGamepadButtonDown(cgamepad, cbutton) + v := bool(ret) + return v +} + +// IsGamepadButtonReleased - Detect if a gamepad button has been released once +func IsGamepadButtonReleased(gamepad, button int32) bool { + cgamepad := (C.int)(gamepad) + cbutton := (C.int)(button) + ret := C.IsGamepadButtonReleased(cgamepad, cbutton) + v := bool(ret) + return v +} + +// IsGamepadButtonUp - Detect if a gamepad button is NOT being pressed +func IsGamepadButtonUp(gamepad, button int32) bool { + cgamepad := (C.int)(gamepad) + cbutton := (C.int)(button) + ret := C.IsGamepadButtonUp(cgamepad, cbutton) + v := bool(ret) + return v +} + +// GetGamepadButtonPressed - Get the last gamepad button pressed +func GetGamepadButtonPressed() int32 { + ret := C.GetGamepadButtonPressed() + v := (int32)(ret) + return v +} + +// GetGamepadAxisCount - Return gamepad axis count for a gamepad +func GetGamepadAxisCount(gamepad int32) int32 { + cgamepad := (C.int)(gamepad) + ret := C.GetGamepadAxisCount(cgamepad) + v := (int32)(ret) + return v +} + +// GetGamepadAxisMovement - Return axis movement value for a gamepad axis +func GetGamepadAxisMovement(gamepad, axis int32) float32 { + cgamepad := (C.int)(gamepad) + caxis := (C.int)(axis) + ret := C.GetGamepadAxisMovement(cgamepad, caxis) + v := (float32)(ret) + return v +} + +// SetGamepadMappings - Set internal gamepad mappings (SDL_GameControllerDB) +func SetGamepadMappings(mappings string) int32 { + cmappings := C.CString(mappings) + defer C.free(unsafe.Pointer(cmappings)) + ret := C.SetGamepadMappings(cmappings) + v := (int32)(ret) + 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 { + cbutton := (C.int)(button) + ret := C.IsMouseButtonPressed(cbutton) + v := bool(ret) + return v +} + +// IsMouseButtonDown - Detect if a mouse button is being pressed +func IsMouseButtonDown(button MouseButton) bool { + cbutton := (C.int)(button) + ret := C.IsMouseButtonDown(cbutton) + v := bool(ret) + return v +} + +// IsMouseButtonReleased - Detect if a mouse button has been released once +func IsMouseButtonReleased(button MouseButton) bool { + cbutton := (C.int)(button) + ret := C.IsMouseButtonReleased(cbutton) + v := bool(ret) + return v +} + +// IsMouseButtonUp - Detect if a mouse button is NOT being pressed +func IsMouseButtonUp(button MouseButton) bool { + cbutton := (C.int)(button) + ret := C.IsMouseButtonUp(cbutton) + v := bool(ret) + return v +} + +// GetMouseX - Returns mouse position X +func GetMouseX() int32 { + ret := C.GetMouseX() + v := (int32)(ret) + return v +} + +// GetMouseY - Returns mouse position Y +func GetMouseY() int32 { + ret := C.GetMouseY() + v := (int32)(ret) + return v +} + +// GetMousePosition - Returns mouse position XY +func GetMousePosition() Vector2 { + ret := C.GetMousePosition() + v := newVector2FromPointer(unsafe.Pointer(&ret)) + 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) + cy := (C.int)(y) + C.SetMousePosition(cx, cy) +} + +// SetMouseOffset - Set mouse offset +func SetMouseOffset(offsetX, offsetY int) { + ox := (C.int)(offsetX) + oy := (C.int)(offsetY) + C.SetMouseOffset(ox, oy) +} + +// SetMouseScale - Set mouse scaling +func SetMouseScale(scaleX, scaleY float32) { + cscaleX := (C.float)(scaleX) + cscaleY := (C.float)(scaleY) + C.SetMouseScale(cscaleX, cscaleY) +} + +// GetMouseWheelMove - Get mouse wheel movement for X or Y, whichever is larger +func GetMouseWheelMove() float32 { + ret := C.GetMouseWheelMove() + v := (float32)(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() + v := (int32)(ret) + return v +} + +// GetTouchY - Returns touch position Y for touch point 0 (relative to screen size) +func GetTouchY() int32 { + ret := C.GetTouchY() + v := (int32)(ret) + return v +} + +// GetTouchPosition - Returns touch position XY for a touch point index (relative to screen size) +func GetTouchPosition(index int32) Vector2 { + cindex := (C.int)(index) + ret := C.GetTouchPosition(cindex) + 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/gestures.go b/raylib/rgestures.go similarity index 86% rename from raylib/gestures.go rename to raylib/rgestures.go index efe34ba..12b181f 100644 --- a/raylib/gestures.go +++ b/raylib/rgestures.go @@ -1,4 +1,4 @@ -package raylib +package rl /* #include "raylib.h" @@ -14,9 +14,9 @@ func SetGesturesEnabled(gestureFlags uint32) { // IsGestureDetected - Check if a gesture have been detected func IsGestureDetected(gesture Gestures) bool { - cgesture := (C.int)(gesture) + cgesture := (C.uint)(gesture) ret := C.IsGestureDetected(cgesture) - v := bool(int(ret) == 1) + v := bool(ret) return v } @@ -27,13 +27,6 @@ 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/rgestures.h new file mode 100644 index 0000000..1bf4e05 --- /dev/null +++ b/raylib/rgestures.h @@ -0,0 +1,555 @@ +/********************************************************************************************** +* +* rgestures - Gestures system, gestures processing based on input events (touch/mouse) +* +* 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. +* +* CONTRIBUTORS: +* Marc Palau: Initial implementation (2014) +* Albert Martos: Complete redesign and testing (2015) +* Ian Eito: Complete redesign and testing (2015) +* Ramon Santamaria: Supervision, review, update and maintenance +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-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. +* +**********************************************************************************************/ + +#ifndef RGESTURES_H +#define RGESTURES_H + +#ifndef PI + #define PI 3.14159265358979323846 +#endif + +//---------------------------------------------------------------------------------- +// 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 +//---------------------------------------------------------------------------------- +// 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; +#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; + +// Gesture event +typedef struct { + int touchAction; + int pointCount; + int pointId[MAX_TOUCH_POINTS]; + Vector2 position[MAX_TOUCH_POINTS]; +} GestureEvent; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// 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 +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 +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) +} +#endif + +#endif // RGESTURES_H + +/*********************************************************************************** +* +* RGESTURES IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RGESTURES_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 + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #endif + #include // Required for: timespec + #include // Required for: clock_gettime() + + #include // Required for: sqrtf(), atan2f() +#endif +#if defined(__APPLE__) // macOS also defines __MACH__ + #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 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 DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Gestures module state context [136 bytes] +typedef struct { + unsigned int current; // Current detected gesture + unsigned int enabledFlags; // Enabled gestures flags + struct { + int firstId; // Touch id for first touch point + int pointCount; // Touch points counter + double eventTime; // Time stamp when an event happened + Vector2 upPosition; // Touch up position + Vector2 downPositionA; // First touch down position + Vector2 downPositionB; // Second touch down position + 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) + } Touch; + struct { + bool resetRequired; // HOLD reset to get first touch point again + double timeDuration; // HOLD duration in seconds + } Hold; + struct { + Vector2 vector; // DRAG vector (between initial and current position) + float angle; // DRAG angle (relative to x-axis) + float distance; // DRAG distance (from initial touch point to final) (normalized [0..1]) + float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame) + } Drag; + struct { + double startTime; // SWIPE start time to calculate drag intensity + } Swipe; + struct { + Vector2 vector; // PINCH vector (between first and second touch points) + float angle; // PINCH angle (relative to x-axis) + float distance; // PINCH displacement distance (normalized [0..1]) + } Pinch; +} GesturesData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GesturesData GESTURES = { + .Touch.firstId = -1, + .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); + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Enable only desired gestures to be detected +void SetGesturesEnabled(unsigned int flags) +{ + GESTURES.enabledFlags = flags; +} + +// Check if a gesture have been detected +bool IsGestureDetected(unsigned int gesture) +{ + if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true; + else return false; +} + +// Process gesture event and translate it into gestures +void ProcessGestureEvent(GestureEvent event) +{ + // Reset required variables + GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures() + + if (GESTURES.Touch.pointCount == 1) // One touch point + { + if (event.touchAction == TOUCH_ACTION_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)) + { + GESTURES.current = GESTURE_DOUBLETAP; + GESTURES.Touch.tapCounter = 0; + } + else // Detect GESTURE_TAP + { + GESTURES.Touch.tapCounter = 1; + GESTURES.current = GESTURE_TAP; + } + + GESTURES.Touch.downPositionA = event.position[0]; + GESTURES.Touch.downDragPosition = event.position[0]; + + GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; + GESTURES.Touch.eventTime = rgGetCurrentTime(); + + GESTURES.Swipe.startTime = rgGetCurrentTime(); + + GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_ACTION_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]; + + // 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)); + + // Detect GESTURE_SWIPE + if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG)) + { + // NOTE: Angle should be inverted in Y + GESTURES.Drag.angle = 360.0f - rgVector2Angle(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 + else GESTURES.current = GESTURE_NONE; + } + else + { + GESTURES.Drag.distance = 0.0f; + GESTURES.Drag.intensity = 0.0f; + GESTURES.Drag.angle = 0.0f; + + GESTURES.current = GESTURE_NONE; + } + + GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; + GESTURES.Touch.pointCount = 0; + } + else if (event.touchAction == TOUCH_ACTION_MOVE) + { + GESTURES.Touch.moveDownPositionA = event.position[0]; + + if (GESTURES.current == GESTURE_HOLD) + { + if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0]; + + GESTURES.Hold.resetRequired = false; + + // Detect GESTURE_DRAG + if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT) + { + GESTURES.Touch.eventTime = rgGetCurrentTime(); + GESTURES.current = GESTURE_DRAG; + } + } + + GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x; + GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y; + } + } + else if (GESTURES.Touch.pointCount == 2) // Two touch points + { + if (event.touchAction == TOUCH_ACTION_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.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(); + } + else if (event.touchAction == TOUCH_ACTION_MOVE) + { + GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); + + GESTURES.Touch.moveDownPositionA = event.position[0]; + GESTURES.Touch.moveDownPositionB = event.position[1]; + + 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 ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN; + else GESTURES.current = GESTURE_PINCH_OUT; + } + else + { + GESTURES.current = GESTURE_HOLD; + GESTURES.Hold.timeDuration = rgGetCurrentTime(); + } + + // NOTE: Angle should be inverted in Y + GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); + } + else if (event.touchAction == TOUCH_ACTION_UP) + { + GESTURES.Pinch.distance = 0.0f; + GESTURES.Pinch.angle = 0.0f; + GESTURES.Pinch.vector = (Vector2){ 0.0f, 0.0f }; + GESTURES.Touch.pointCount = 0; + + 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) +void UpdateGestures(void) +{ + // NOTE: Gestures are processed through system callbacks on touch events + + // Detect GESTURE_HOLD + if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) + { + GESTURES.current = GESTURE_HOLD; + GESTURES.Hold.timeDuration = rgGetCurrentTime(); + } + + // Detect GESTURE_NONE + if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN)) + { + GESTURES.current = GESTURE_NONE; + } +} + +// Get latest detected gesture +int GetGestureDetected(void) +{ + // Get current gesture only if enabled + return (GESTURES.enabledFlags & GESTURES.current); +} + +// Hold time measured in seconds +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; + + return (float)time; +} + +// Get drag vector (between initial touch point to current) +Vector2 GetGestureDragVector(void) +{ + // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE + + return GESTURES.Drag.vector; +} + +// Get drag angle +// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise +float GetGestureDragAngle(void) +{ + // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP + + return GESTURES.Drag.angle; +} + +// Get distance between two pinch points +Vector2 GetGesturePinchVector(void) +{ + // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE + + return GESTURES.Pinch.vector; +} + +// Get angle between two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise +float GetGesturePinchAngle(void) +{ + // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE + + return GESTURES.Pinch.angle; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- +// Get angle from two-points vector with X-axis +static float rgVector2Angle(Vector2 v1, Vector2 v2) +{ + float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); + + if (angle < 0) angle += 360.0f; + + return angle; +} + +// Calculate distance between two Vector2 +static float rgVector2Distance(Vector2 v1, Vector2 v2) +{ + float result; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + + result = (float)sqrt(dx*dx + dy*dy); + + return result; +} + +// Time measure returned are seconds +static double rgGetCurrentTime(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! + QueryPerformanceCounter(¤tTime); + + time = (double)currentTime/clockFrequency; // Time in seconds +#endif + +#if defined(__linux__) + // NOTE: Only for Linux-based systems + struct timespec now; + 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 +#endif + +#if defined(__APPLE__) + //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 + //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time + + clock_serv_t cclock; + mach_timespec_t now; + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + + // NOTE: OS X does not have clock_gettime(), using clock_get_time() + clock_get_time(cclock, &now); + 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 +#endif + + return time; +} + +#endif // RGESTURES_IMPLEMENTATION diff --git a/raylib/rlgl.c b/raylib/rlgl.c deleted file mode 100644 index 93a0b0f..0000000 --- a/raylib/rlgl.c +++ /dev/null @@ -1,4209 +0,0 @@ -/********************************************************************************************** -* -* rlgl - raylib OpenGL abstraction layer -* -* 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...). -* -* 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 auxiliar resources -* rlglDraw() - Process internal buffers and send required draw calls -* 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_ES2 -* Use selected OpenGL backend -* -* #define RLGL_STANDALONE -* Use rlgl as standalone library (no raylib dependency) -* -* #define SUPPORT_VR_SIMULATOR -* Support VR simulation functionality (stereo rendering) -* -* #define SUPPORT_DISTORTION_SHADER -* Include stereo rendering distortion shader (shader_distortion.h) -* -* DEPENDENCIES: -* raymath - 3D math functionality (Vector3, Matrix, Quaternion) -* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2018 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 "config.h" - -#include "rlgl.h" - -#include // Required for: fopen(), fclose(), fread()... [Used only on LoadText()] -#include // Required for: malloc(), free(), rand() -#include // Required for: strcmp(), strlen(), strtok() [Used only in extensions loading] -#include // Required for: atan2() - -#if !defined(RLGL_STANDALONE) - #include "raymath.h" // Required for: Vector3 and Matrix functions -#endif - -#if defined(GRAPHICS_API_OPENGL_11) - #if defined(__APPLE__) - #include // OpenGL 1.1 library for OSX - #include - #else - // APIENTRY for OpenGL function pointer declarations is required - #ifndef APIENTRY - #ifdef _WIN32 - #define APIENTRY __stdcall - #else - #define APIENTRY - #endif - #endif - // WINGDIAPI definition. Some Windows OpenGL headers need it - #if !defined(WINGDIAPI) && defined(_WIN32) - #define WINGDIAPI __declspec(dllimport) - #endif - - #include // OpenGL 1.1 library - #endif -#endif - -#if defined(GRAPHICS_API_OPENGL_21) - #define GRAPHICS_API_OPENGL_33 -#endif - -#if defined(GRAPHICS_API_OPENGL_33) - #if defined(__APPLE__) - #include // OpenGL 3 library for OSX - #include - #else - #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_ES2) - #include // EGL library - #include // OpenGL ES 2.0 library - #include // OpenGL ES 2.0 extensions library -#endif - -#if defined(RLGL_STANDALONE) - #include // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()] -#endif - -#if !defined(GRAPHICS_API_OPENGL_11) && defined(SUPPORT_DISTORTION_SHADER) - #include "shader_distortion.h" // Distortion shader to be embedded -#endif - - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define MATRIX_STACK_SIZE 16 // Matrix stack max size -#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes -#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations) - // NOTE: Every vertex are 3 floats (12 bytes) - -#ifndef GL_SHADING_LANGUAGE_VERSION - #define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#endif - -#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT - #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 -#endif -#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 -#endif -#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 -#endif -#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 -#endif -#ifndef GL_ETC1_RGB8_OES - #define GL_ETC1_RGB8_OES 0x8D64 -#endif -#ifndef GL_COMPRESSED_RGB8_ETC2 - #define GL_COMPRESSED_RGB8_ETC2 0x9274 -#endif -#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC - #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 -#endif -#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG - #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 -#endif -#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG - #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 -#endif -#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR - #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 -#endif -#ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR - #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 -#endif - -#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT - #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF -#endif - -#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT - #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE -#endif - -#if defined(GRAPHICS_API_OPENGL_11) - #define GL_UNSIGNED_SHORT_5_6_5 0x8363 - #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 - #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#endif - -#if defined(GRAPHICS_API_OPENGL_21) - #define GL_LUMINANCE 0x1909 - #define GL_LUMINANCE_ALPHA 0x190A -#endif - -#if defined(GRAPHICS_API_OPENGL_ES2) - #define glClearDepth glClearDepthf - #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER - #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER -#endif - -// Default vertex attribute names on shader to set location points -#define DEFAULT_ATTRIB_POSITION_NAME "vertexPosition" // shader-location = 0 -#define DEFAULT_ATTRIB_TEXCOORD_NAME "vertexTexCoord" // shader-location = 1 -#define DEFAULT_ATTRIB_NORMAL_NAME "vertexNormal" // shader-location = 2 -#define DEFAULT_ATTRIB_COLOR_NAME "vertexColor" // shader-location = 3 -#define DEFAULT_ATTRIB_TANGENT_NAME "vertexTangent" // shader-location = 4 -#define DEFAULT_ATTRIB_TEXCOORD2_NAME "vertexTexCoord2" // shader-location = 5 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// Dynamic vertex buffers (position + texcoords + colors + indices arrays) -typedef struct DynamicBuffer { - 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) - 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) -#elif defined(GRAPHICS_API_OPENGL_ES2) - unsigned short *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad) - // NOTE: 6*2 byte = 12 byte, not alignment problem! -#endif - unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) -} DynamicBuffer; - -// Draw call type -// NOTE: Used to track required draw-calls, organized by texture -typedef struct DrawCall { - int vertexCount; - GLuint vaoId; - GLuint textureId; - GLuint shaderId; - - Matrix projection; - Matrix modelview; - - // TODO: Store additional draw state data - //int blendMode; - //Guint fboId; -} DrawCall; - -#if defined(SUPPORT_VR_SIMULATOR) -// VR Stereo rendering configuration for simulator -typedef struct VrStereoConfig { - RenderTexture2D stereoFbo; // VR stereo rendering framebuffer - Shader distortionShader; // VR stereo rendering distortion shader - Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports - Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices - Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices -} VrStereoConfig; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -static Matrix stack[MATRIX_STACK_SIZE]; -static int stackCounter = 0; - -static Matrix modelview; -static Matrix projection; -static Matrix *currentMatrix; -static int currentMatrixMode; - -static int currentDrawMode; - -static float currentDepth = -1.0f; - -static DynamicBuffer lines; // Default dynamic buffer for lines data -static DynamicBuffer triangles; // Default dynamic buffer for triangles data -static DynamicBuffer quads; // Default dynamic buffer for quads data (used to draw textures) - -// Default buffers draw calls -static DrawCall *draws; -static int drawsCounter; - -// Temp vertex buffer to be used with rlTranslate, rlRotate, rlScale -static Vector3 *tempBuffer; -static int tempBufferCount = 0; -static bool useTempBuffer = false; - -// Shaders -static unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) -static unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) - -static Shader defaultShader; // Basic shader, support vertex color and diffuse texture -static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) - -// Extension supported flag: VAO -static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) - -// Extension supported flag: Compressed textures -static bool texCompETC1Supported = false; // ETC1 texture compression support -static bool texCompETC2Supported = false; // ETC2/EAC texture compression support -static bool texCompPVRTSupported = false; // PVR texture compression support -static bool texCompASTCSupported = false; // ASTC texture compression support - -#if defined(SUPPORT_VR_SIMULATOR) -// VR global variables -static VrStereoConfig vrConfig; // VR stereo configuration for simulator -static bool vrSimulatorReady = false; // VR simulator ready flag -static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag - // NOTE: This flag is useful to render data over stereo image (i.e. FPS) -#endif // defined(SUPPORT_VR_SIMULATOR) - -#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - -// Extension supported flag: Anisotropic filtering -static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support -static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supported (minimum is 2.0f) - -// Extension supported flag: Clamp mirror wrap mode -static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported - -#if defined(GRAPHICS_API_OPENGL_ES2) -// NOTE: VAO functionality is exposed through extensions (OES) -static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays; -static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray; -static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; -//static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted -#endif - -static bool debugMarkerSupported = false; - -// Compressed textures support flags -static bool texCompDXTSupported = false; // DDS texture compression support -static bool texNPOTSupported = false; // NPOT textures full support -static bool texFloatSupported = false; // float textures support (32 bit per channel) - -static int blendMode = 0; // Track current blending mode - -// White texture useful for plain color polys (required by shader) -static unsigned int whiteTexture; - -// Default framebuffer size -static int screenWidth; // Default framebuffer width -static int screenHeight; // Default framebuffer height - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -static unsigned int CompileShader(const char *shaderStr, int type); // Compile custom shader and return shader id -static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program - -static Shader LoadShaderDefault(void); // Load default shader (just vertex positioning and texture coloring) -static void SetShaderDefaultLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) -static void UnloadShaderDefault(void); // Unload default shader - -static void LoadBuffersDefault(void); // Load default internal buffers (lines, triangles, quads) -static void UpdateBuffersDefault(void); // Update default internal buffers (VAOs/VBOs) with vertex data -static void DrawBuffersDefault(void); // Draw default internal buffers vertex data -static void UnloadBuffersDefault(void); // Unload default internal buffers vertex data from CPU and GPU - -static void GenDrawCube(void); // Generate and draw cube -static void GenDrawQuad(void); // Generate and draw quad - -#if defined(SUPPORT_VR_SIMULATOR) -static void SetStereoConfig(VrDeviceInfo info); // Configure stereo rendering (including distortion shader) with HMD device parameters -static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye -#endif - -#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - -// Get OpenGL internal formats and data type from raylib PixelFormat -static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType); - -#if defined(GRAPHICS_API_OPENGL_11) -static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); -static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Matrix operations -//---------------------------------------------------------------------------------- - -#if defined(GRAPHICS_API_OPENGL_11) - -// Fallback to OpenGL 1.1 function calls -//--------------------------------------- -void rlMatrixMode(int mode) -{ - switch (mode) - { - case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break; - case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break; - case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break; - default: break; - } -} - -void rlFrustum(double left, double right, double bottom, double top, double zNear, double zFar) -{ - glFrustum(left, right, bottom, top, zNear, zFar); -} - -void rlOrtho(double left, double right, double bottom, double top, double zNear, double zFar) -{ - glOrtho(left, right, bottom, top, zNear, zFar); -} - -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 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(float *matf) { glMultMatrixf(matf); } - -#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - -// Choose the current matrix to be transformed -void rlMatrixMode(int mode) -{ - if (mode == RL_PROJECTION) currentMatrix = &projection; - else if (mode == RL_MODELVIEW) currentMatrix = &modelview; - //else if (mode == RL_TEXTURE) // Not supported - - currentMatrixMode = mode; -} - -// Push the current matrix to stack -void rlPushMatrix(void) -{ - if (stackCounter == MATRIX_STACK_SIZE - 1) - { - TraceLog(LOG_ERROR, "Stack Buffer Overflow (MAX %i Matrix)", MATRIX_STACK_SIZE); - } - - stack[stackCounter] = *currentMatrix; - rlLoadIdentity(); // TODO: Review matrix stack logic! - stackCounter++; - - if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true; -} - -// Pop lattest inserted matrix from stack -void rlPopMatrix(void) -{ - if (stackCounter > 0) - { - Matrix mat = stack[stackCounter - 1]; - *currentMatrix = mat; - stackCounter--; - } -} - -// Reset current matrix to identity matrix -void rlLoadIdentity(void) -{ - *currentMatrix = MatrixIdentity(); -} - -// Multiply the current matrix by a translation matrix -void rlTranslatef(float x, float y, float z) -{ - Matrix matTranslation = MatrixTranslate(x, y, z); - - // NOTE: We transpose matrix with multiplication order - *currentMatrix = MatrixMultiply(matTranslation, *currentMatrix); -} - -// Multiply the current matrix by a rotation matrix -void rlRotatef(float angleDeg, float x, float y, float z) -{ - Matrix matRotation = MatrixIdentity(); - - Vector3 axis = (Vector3){ x, y, z }; - matRotation = MatrixRotate(Vector3Normalize(axis), angleDeg*DEG2RAD); - - // NOTE: We transpose matrix with multiplication order - *currentMatrix = MatrixMultiply(matRotation, *currentMatrix); -} - -// Multiply the current matrix by a scaling matrix -void rlScalef(float x, float y, float z) -{ - Matrix matScale = MatrixScale(x, y, z); - - // NOTE: We transpose matrix with multiplication order - *currentMatrix = MatrixMultiply(matScale, *currentMatrix); -} - -// Multiply the current matrix by another matrix -void rlMultMatrixf(float *matf) -{ - // Matrix creation from array - Matrix mat = { matf[0], matf[4], matf[8], matf[12], - matf[1], matf[5], matf[9], matf[13], - matf[2], matf[6], matf[10], matf[14], - matf[3], matf[7], matf[11], matf[15] }; - - *currentMatrix = MatrixMultiply(*currentMatrix, mat); -} - -// Multiply the current matrix by a perspective matrix generated by parameters -void rlFrustum(double left, double right, double bottom, double top, double near, double far) -{ - Matrix matPerps = MatrixFrustum(left, right, bottom, top, near, far); - - *currentMatrix = MatrixMultiply(*currentMatrix, matPerps); -} - -// Multiply the current matrix by an orthographic matrix generated by parameters -void rlOrtho(double left, double right, double bottom, double top, double near, double far) -{ - Matrix matOrtho = MatrixOrtho(left, right, bottom, top, near, far); - - *currentMatrix = MatrixMultiply(*currentMatrix, matOrtho); -} - -#endif - -// Set the viewport area (transformation from normalized device coordinates to window coordinates) -// NOTE: Updates global variables: screenWidth, screenHeight -void rlViewport(int x, int y, int width, int height) -{ - glViewport(x, y, width, height); -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Vertex level operations -//---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_11) - -// Fallback to OpenGL 1.1 function calls -//--------------------------------------- -void rlBegin(int mode) -{ - switch (mode) - { - case RL_LINES: glBegin(GL_LINES); break; - case RL_TRIANGLES: glBegin(GL_TRIANGLES); break; - case RL_QUADS: glBegin(GL_QUADS); break; - default: break; - } -} - -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); } -void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); } -void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); } -void rlColor4ub(byte r, byte g, byte b, byte a) { glColor4ub(r, g, b, a); } -void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); } -void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); } - -#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - -// Initialize drawing mode (how to organize vertex) -void rlBegin(int mode) -{ - // Draw mode can only be RL_LINES, RL_TRIANGLES and RL_QUADS - currentDrawMode = mode; -} - -// Finish vertex providing -void rlEnd(void) -{ - if (useTempBuffer) - { - // NOTE: In this case, *currentMatrix is already transposed because transposing has been applied - // independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1) - // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1 - - // Apply transformation matrix to all temp vertices - for (int i = 0; i < tempBufferCount; i++) tempBuffer[i] = Vector3Transform(tempBuffer[i], *currentMatrix); - - // Deactivate tempBuffer usage to allow rlVertex3f do its job - useTempBuffer = false; - - // Copy all transformed vertices to right VAO - for (int i = 0; i < tempBufferCount; i++) rlVertex3f(tempBuffer[i].x, tempBuffer[i].y, tempBuffer[i].z); - - // Reset temp buffer - tempBufferCount = 0; - } - - // Make sure vertexCount is the same for vertices-texcoords-normals-colors - // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls. - switch (currentDrawMode) - { - case RL_LINES: - { - if (lines.vCounter != lines.cCounter) - { - int addColors = lines.vCounter - lines.cCounter; - - for (int i = 0; i < addColors; i++) - { - lines.colors[4*lines.cCounter] = lines.colors[4*lines.cCounter - 4]; - lines.colors[4*lines.cCounter + 1] = lines.colors[4*lines.cCounter - 3]; - lines.colors[4*lines.cCounter + 2] = lines.colors[4*lines.cCounter - 2]; - lines.colors[4*lines.cCounter + 3] = lines.colors[4*lines.cCounter - 1]; - - lines.cCounter++; - } - } - } break; - case RL_TRIANGLES: - { - if (triangles.vCounter != triangles.cCounter) - { - int addColors = triangles.vCounter - triangles.cCounter; - - for (int i = 0; i < addColors; i++) - { - triangles.colors[4*triangles.cCounter] = triangles.colors[4*triangles.cCounter - 4]; - triangles.colors[4*triangles.cCounter + 1] = triangles.colors[4*triangles.cCounter - 3]; - triangles.colors[4*triangles.cCounter + 2] = triangles.colors[4*triangles.cCounter - 2]; - triangles.colors[4*triangles.cCounter + 3] = triangles.colors[4*triangles.cCounter - 1]; - - triangles.cCounter++; - } - } - } break; - case RL_QUADS: - { - // Make sure colors count match vertex count - if (quads.vCounter != quads.cCounter) - { - int addColors = quads.vCounter - quads.cCounter; - - for (int i = 0; i < addColors; i++) - { - quads.colors[4*quads.cCounter] = quads.colors[4*quads.cCounter - 4]; - quads.colors[4*quads.cCounter + 1] = quads.colors[4*quads.cCounter - 3]; - quads.colors[4*quads.cCounter + 2] = quads.colors[4*quads.cCounter - 2]; - quads.colors[4*quads.cCounter + 3] = quads.colors[4*quads.cCounter - 1]; - - quads.cCounter++; - } - } - - // Make sure texcoords count match vertex count - if (quads.vCounter != quads.tcCounter) - { - int addTexCoords = quads.vCounter - quads.tcCounter; - - for (int i = 0; i < addTexCoords; i++) - { - quads.texcoords[2*quads.tcCounter] = 0.0f; - quads.texcoords[2*quads.tcCounter + 1] = 0.0f; - - quads.tcCounter++; - } - } - - // TODO: Make sure normals count match vertex count... if normals support is added in a future... :P - - } break; - default: break; - } - - // 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) - currentDepth += (1.0f/20000.0f); - - // TODO: Verify internal buffers limits - // NOTE: Before launching draw, verify no matrix are left in the stack! - // NOTE: Probably a lines/triangles margin should be left, rlEnd could be called - // after an undetermined number of triangles buffered (check shapes::DrawPoly()) - if ((lines.vCounter/2 >= MAX_LINES_BATCH - 2) || - (triangles.vCounter/3 >= MAX_TRIANGLES_BATCH - 16) || - (quads.vCounter/4 >= MAX_QUADS_BATCH - 2)) rlglDraw(); -} - -// Define one vertex (position) -void rlVertex3f(float x, float y, float z) -{ - if (useTempBuffer) - { - tempBuffer[tempBufferCount].x = x; - tempBuffer[tempBufferCount].y = y; - tempBuffer[tempBufferCount].z = z; - tempBufferCount++; - } - else - { - switch (currentDrawMode) - { - case RL_LINES: - { - // Verify that MAX_LINES_BATCH limit not reached - if (lines.vCounter/2 < MAX_LINES_BATCH) - { - lines.vertices[3*lines.vCounter] = x; - lines.vertices[3*lines.vCounter + 1] = y; - lines.vertices[3*lines.vCounter + 2] = z; - - lines.vCounter++; - } - else TraceLog(LOG_ERROR, "MAX_LINES_BATCH overflow"); - - } break; - case RL_TRIANGLES: - { - // Verify that MAX_TRIANGLES_BATCH limit not reached - if (triangles.vCounter/3 < MAX_TRIANGLES_BATCH) - { - triangles.vertices[3*triangles.vCounter] = x; - triangles.vertices[3*triangles.vCounter + 1] = y; - triangles.vertices[3*triangles.vCounter + 2] = z; - - triangles.vCounter++; - } - else TraceLog(LOG_ERROR, "MAX_TRIANGLES_BATCH overflow"); - - } break; - case RL_QUADS: - { - // Verify that MAX_QUADS_BATCH limit not reached - if (quads.vCounter/4 < MAX_QUADS_BATCH) - { - quads.vertices[3*quads.vCounter] = x; - quads.vertices[3*quads.vCounter + 1] = y; - quads.vertices[3*quads.vCounter + 2] = z; - - quads.vCounter++; - - draws[drawsCounter - 1].vertexCount++; - } - else TraceLog(LOG_ERROR, "MAX_QUADS_BATCH overflow"); - - } break; - default: break; - } - } -} - -// Define one vertex (position) -void rlVertex2f(float x, float y) -{ - rlVertex3f(x, y, currentDepth); -} - -// Define one vertex (position) -void rlVertex2i(int x, int y) -{ - rlVertex3f((float)x, (float)y, currentDepth); -} - -// Define one vertex (texture coordinate) -// NOTE: Texture coordinates are limited to QUADS only -void rlTexCoord2f(float x, float y) -{ - if (currentDrawMode == RL_QUADS) - { - quads.texcoords[2*quads.tcCounter] = x; - quads.texcoords[2*quads.tcCounter + 1] = y; - - quads.tcCounter++; - } -} - -// Define one vertex (normal) -// NOTE: Normals limited to TRIANGLES only ? -void rlNormal3f(float x, float y, float z) -{ - // TODO: Normals usage... -} - -// Define one vertex (color) -void rlColor4ub(byte x, byte y, byte z, byte w) -{ - switch (currentDrawMode) - { - case RL_LINES: - { - lines.colors[4*lines.cCounter] = x; - lines.colors[4*lines.cCounter + 1] = y; - lines.colors[4*lines.cCounter + 2] = z; - lines.colors[4*lines.cCounter + 3] = w; - - lines.cCounter++; - - } break; - case RL_TRIANGLES: - { - triangles.colors[4*triangles.cCounter] = x; - triangles.colors[4*triangles.cCounter + 1] = y; - triangles.colors[4*triangles.cCounter + 2] = z; - triangles.colors[4*triangles.cCounter + 3] = w; - - triangles.cCounter++; - - } break; - case RL_QUADS: - { - quads.colors[4*quads.cCounter] = x; - quads.colors[4*quads.cCounter + 1] = y; - quads.colors[4*quads.cCounter + 2] = z; - quads.colors[4*quads.cCounter + 3] = w; - - quads.cCounter++; - - } break; - default: break; - } -} - -// Define one vertex (color) -void rlColor4f(float r, float g, float b, float a) -{ - rlColor4ub((byte)(r*255), (byte)(g*255), (byte)(b*255), (byte)(a*255)); -} - -// Define one vertex (color) -void rlColor3f(float x, float y, float z) -{ - rlColor4ub((byte)(x*255), (byte)(y*255), (byte)(z*255), 255); -} - -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition - OpenGL equivalent functions (common to 1.1, 3.3+, ES2) -//---------------------------------------------------------------------------------- - -// Enable texture usage -void rlEnableTexture(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_11) - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, id); -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (draws[drawsCounter - 1].textureId != id) - { - if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++; - - if (drawsCounter >= MAX_DRAWS_BY_TEXTURE) - { - rlglDraw(); - drawsCounter = 1; - } - - draws[drawsCounter - 1].textureId = id; - draws[drawsCounter - 1].vertexCount = 0; - } -#endif -} - -// Disable texture usage -void rlDisableTexture(void) -{ -#if defined(GRAPHICS_API_OPENGL_11) - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); -#else - // NOTE: If quads batch limit is reached, - // we force a draw call and next batch starts - if (quads.vCounter/4 >= MAX_QUADS_BATCH) rlglDraw(); -#endif -} - -// Set texture parameters (wrap mode/filter mode) -void rlTextureParameters(unsigned int id, int param, int value) -{ - glBindTexture(GL_TEXTURE_2D, id); - - switch (param) - { - case RL_TEXTURE_WRAP_S: - case RL_TEXTURE_WRAP_T: - { - if ((value == RL_WRAP_CLAMP_MIRROR) && !texClampMirrorSupported) TraceLog(LOG_WARNING, "Clamp mirror wrap mode not supported"); - 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; - case RL_TEXTURE_ANISOTROPIC_FILTER: - { - if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); - else if (maxAnisotropicLevel > 0.0f) - { - TraceLog(LOG_WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); - } - else TraceLog(LOG_WARNING, "Anisotropic filtering not supported"); - } break; - default: break; - } - - glBindTexture(GL_TEXTURE_2D, 0); -} - -// Enable rendering to texture (fbo) -void rlEnableRenderTexture(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindFramebuffer(GL_FRAMEBUFFER, id); - - //glDisable(GL_CULL_FACE); // Allow double side drawing for texture flipping - //glCullFace(GL_FRONT); -#endif -} - -// Disable rendering to texture -void rlDisableRenderTexture(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - //glEnable(GL_CULL_FACE); - //glCullFace(GL_BACK); -#endif -} - -// Enable depth test -void rlEnableDepthTest(void) -{ - glEnable(GL_DEPTH_TEST); -} - -// Disable depth test -void rlDisableDepthTest(void) -{ - glDisable(GL_DEPTH_TEST); -} - -// Enable wire mode -void rlEnableWireMode(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_LINE); -#endif -} - -// Disable wire mode -void rlDisableWireMode(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 -} - -// Unload texture from GPU memory -void rlDeleteTextures(unsigned int id) -{ - if (id > 0) glDeleteTextures(1, &id); -} - -// Unload render texture from GPU memory -void rlDeleteRenderTextures(RenderTexture2D target) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (target.id > 0) glDeleteFramebuffers(1, &target.id); - if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); - if (target.depth.id > 0) glDeleteTextures(1, &target.depth.id); - - TraceLog(LOG_INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id); -#endif -} - -// Unload shader from GPU memory -void rlDeleteShader(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (id != 0) glDeleteProgram(id); -#endif -} - -// Unload vertex data (VAO) from GPU memory -void rlDeleteVertexArrays(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (vaoSupported) - { - if (id != 0) glDeleteVertexArrays(1, &id); - TraceLog(LOG_INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", id); - } -#endif -} - -// Unload vertex data (VBO) from GPU memory -void rlDeleteBuffers(unsigned int id) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (id != 0) - { - glDeleteBuffers(1, &id); - if (!vaoSupported) TraceLog(LOG_INFO, "[VBO ID %i] Unloaded model vertex data from VRAM (GPU)", id); - } -#endif -} - -// Clear color buffer with color -void rlClearColor(byte r, byte g, byte b, byte a) -{ - // Color values clamp to 0.0f(0) and 1.0f(255) - float cr = (float)r/255; - float cg = (float)g/255; - float cb = (float)b/255; - float ca = (float)a/255; - - glClearColor(cr, cg, cb, ca); -} - -// Clear used screen buffers (color and depth) -void rlClearScreenBuffers(void) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D) - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used... -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - rlgl Functions -//---------------------------------------------------------------------------------- - -// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states -void rlglInit(int width, int height) -{ - // Check OpenGL information and capabilities - //------------------------------------------------------------------------------ - - // Print current OpenGL and GLSL version - TraceLog(LOG_INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR)); - TraceLog(LOG_INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER)); - TraceLog(LOG_INFO, "GPU: Version: %s", glGetString(GL_VERSION)); - TraceLog(LOG_INFO, "GPU: GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); - - // NOTE: We can get a bunch of extra information about GPU capabilities (glGet*) - //int maxTexSize; - //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); - //TraceLog(LOG_INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize); - - //GL_MAX_TEXTURE_IMAGE_UNITS - //GL_MAX_VIEWPORT_DIMS - - //int numAuxBuffers; - //glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers); - //TraceLog(LOG_INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers); - - //GLint numComp = 0; - //GLint format[32] = { 0 }; - //glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp); - //glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, format); - //for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]); - - // NOTE: We don't need that much data on screen... right now... - -#if defined(GRAPHICS_API_OPENGL_11) - //TraceLog(LOG_INFO, "OpenGL 1.1 (or driver default) profile initialized"); -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Get supported extensions list - GLint numExt = 0; - -#if defined(GRAPHICS_API_OPENGL_33) - - // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default - vaoSupported = true; - texNPOTSupported = true; - texFloatSupported = true; - - // We get a list of available extensions and we check for some of them (compressed textures) - // NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that) - glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); - -#ifdef _MSC_VER - const char **extList = malloc(sizeof(const char *)*numExt); -#else - const char *extList[numExt]; -#endif - - for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i); - -#elif defined(GRAPHICS_API_OPENGL_ES2) - char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string - - // NOTE: We have to duplicate string because glGetString() returns a const value - // If not duplicated, it fails in some systems (Raspberry Pi) - // Equivalent to function: char *strdup(const char *str) - char *extensionsDup; - size_t len = strlen(extensions) + 1; - void *newstr = malloc(len); - if (newstr == NULL) extensionsDup = NULL; - extensionsDup = (char *)memcpy(newstr, extensions, len); - - // NOTE: String could be splitted using strtok() function (string.h) - // NOTE: strtok() modifies the received string, it can not be const - - char *extList[512]; // Allocate 512 strings pointers (2 KB) - - extList[numExt] = strtok(extensionsDup, " "); - - while (extList[numExt] != NULL) - { - numExt++; - extList[numExt] = strtok(NULL, " "); - } - - free(extensionsDup); // Duplicated string must be deallocated - - numExt -= 1; -#endif - - TraceLog(LOG_INFO, "Number of supported extensions: %i", numExt); - - // Show supported extensions - //for (int i = 0; i < numExt; i++) TraceLog(LOG_INFO, "Supported extension: %s", extList[i]); - - // Check required extensions - for (int i = 0; i < numExt; i++) - { -#if defined(GRAPHICS_API_OPENGL_ES2) - // Check VAO support - // NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature - if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0) - { - vaoSupported = true; - - // The extension is supported by our hardware and driver, try to get related functions pointers - // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... - glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES"); - glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES"); - glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES"); - //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted - } - - // Check NPOT textures support - // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature - if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) texNPOTSupported = true; - - // Check texture float support - if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true; -#endif - - // DDS texture compression support - if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true; - - // ETC1 texture compression support - if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) texCompETC1Supported = true; - - // ETC2/EAC texture compression support - if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) texCompETC2Supported = true; - - // PVR texture compression support - if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) texCompPVRTSupported = true; - - // ASTC texture compression support - if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true; - - // Anisotropic texture filter support - if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) - { - texAnisotropicFilterSupported = true; - glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT - } - - // Clamp mirror wrap mode supported - if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; - - // Debug marker support - if(strcmp(extList[i], (const char *)"GL_EXT_debug_marker") == 0) debugMarkerSupported = true; - } - -#if defined(_MSC_VER) - //free(extList); -#endif - -#if defined(GRAPHICS_API_OPENGL_ES2) - if (vaoSupported) TraceLog(LOG_INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully"); - else TraceLog(LOG_WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); - - if (texNPOTSupported) TraceLog(LOG_INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported"); - else TraceLog(LOG_WARNING, "[EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); -#endif - - if (texCompDXTSupported) TraceLog(LOG_INFO, "[EXTENSION] DXT compressed textures supported"); - if (texCompETC1Supported) TraceLog(LOG_INFO, "[EXTENSION] ETC1 compressed textures supported"); - if (texCompETC2Supported) TraceLog(LOG_INFO, "[EXTENSION] ETC2/EAC compressed textures supported"); - if (texCompPVRTSupported) TraceLog(LOG_INFO, "[EXTENSION] PVRT compressed textures supported"); - if (texCompASTCSupported) TraceLog(LOG_INFO, "[EXTENSION] ASTC compressed textures supported"); - - if (texAnisotropicFilterSupported) TraceLog(LOG_INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); - if (texClampMirrorSupported) TraceLog(LOG_INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); - - if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported"); - - // Initialize buffers, default shaders and default textures - //---------------------------------------------------------- - - // Init default white texture - unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) - - whiteTexture = rlLoadTexture(pixels, 1, 1, UNCOMPRESSED_R8G8B8A8, 1); - - if (whiteTexture != 0) TraceLog(LOG_INFO, "[TEX ID %i] Base white texture loaded successfully", whiteTexture); - else TraceLog(LOG_WARNING, "Base white texture could not be loaded"); - - // Init default Shader (customized for GL 3.3 and ES2) - defaultShader = LoadShaderDefault(); - currentShader = defaultShader; - - // Init default vertex arrays buffers (lines, triangles, quads) - LoadBuffersDefault(); - - // Init temp vertex buffer, used when transformation required (translate, rotate, scale) - tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE); - - for (int i = 0; i < TEMP_VERTEX_BUFFER_SIZE; i++) tempBuffer[i] = Vector3Zero(); - - // Init draw calls tracking system - draws = (DrawCall *)malloc(sizeof(DrawCall)*MAX_DRAWS_BY_TEXTURE); - - for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++) - { - draws[i].textureId = 0; - draws[i].vertexCount = 0; - } - - drawsCounter = 1; - draws[drawsCounter - 1].textureId = whiteTexture; - currentDrawMode = RL_TRIANGLES; // Set default draw mode - - // Init internal matrix stack (emulating OpenGL 1.1) - for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); - - // Init internal projection and modelview matrices - projection = MatrixIdentity(); - modelview = MatrixIdentity(); - currentMatrix = &modelview; -#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - - // Initialize OpenGL default states - //---------------------------------------------------------- - - // Init state: Depth test - glDepthFunc(GL_LEQUAL); // Type of depth testing to apply - glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) - - // Init state: Blending mode - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed) - glEnable(GL_BLEND); // Enable color blending (required to work with transparencies) - - // Init state: Culling - // NOTE: All shapes/models triangles are drawn CCW - glCullFace(GL_BACK); // Cull the back face (default) - glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) - glEnable(GL_CULL_FACE); // Enable backface culling - -#if defined(GRAPHICS_API_OPENGL_11) - // Init state: Color hints (deprecated in OpenGL 3.0+) - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation - glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) -#endif - - // Init state: Color/Depth buffers clear - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) - glClearDepth(1.0f); // Set clear depth value (default) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) - - // Store screen size into global variables - screenWidth = width; - screenHeight = height; - - TraceLog(LOG_INFO, "OpenGL default states initialized successfully"); -} - -// Vertex Buffer Object deinitialization (memory free) -void rlglClose(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - UnloadShaderDefault(); // Unload default shader - UnloadBuffersDefault(); // Unload default buffers (lines, triangles, quads) - glDeleteTextures(1, &whiteTexture); // Unload default texture - - TraceLog(LOG_INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); - - free(draws); -#endif -} - -// Drawing batches: triangles, quads, lines -void rlglDraw(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: In a future version, models could be stored in a stack... - //for (int i = 0; i < modelsCount; i++) rlDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform); - - // NOTE: Default buffers upload and draw - UpdateBuffersDefault(); - DrawBuffersDefault(); // NOTE: Stereo rendering is checked inside -#endif -} - -// Returns current OpenGL version -int rlGetVersion(void) -{ -#if defined(GRAPHICS_API_OPENGL_11) - return OPENGL_11; -#elif defined(GRAPHICS_API_OPENGL_21) - #if defined(__APPLE__) - return OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX - #else - return OPENGL_21; - #endif -#elif defined(GRAPHICS_API_OPENGL_33) - return OPENGL_33; -#elif defined(GRAPHICS_API_OPENGL_ES2) - return OPENGL_ES_20; -#endif -} - -// Set debug marker -void rlSetDebugMarker(const char *text) -{ -#if defined(GRAPHICS_API_OPENGL_33) - if (debugMarkerSupported) glInsertEventMarkerEXT(0, text); -#endif -} - -// Load OpenGL extensions -// NOTE: External loader function could be passed as a pointer -void rlLoadExtensions(void *loader) -{ -#if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_33) - // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions) - #if !defined(__APPLE__) - if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(LOG_WARNING, "GLAD: Cannot load OpenGL extensions"); - else TraceLog(LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); - - #if defined(GRAPHICS_API_OPENGL_21) - if (GLAD_GL_VERSION_2_1) TraceLog(LOG_INFO, "OpenGL 2.1 profile supported"); - #elif defined(GRAPHICS_API_OPENGL_33) - if(GLAD_GL_VERSION_3_3) TraceLog(LOG_INFO, "OpenGL 3.3 Core profile supported"); - else TraceLog(LOG_ERROR, "OpenGL 3.3 Core profile not supported"); - #endif - #endif - - // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans - //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object -#endif -} - -// Get world coordinates from screen coordinates -Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view) -{ - Vector3 result = { 0.0f, 0.0f, 0.0f }; - - // Calculate unproject matrix (multiply view patrix by projection matrix) and invert it - Matrix matViewProj = MatrixMultiply(view, proj); - 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; -} - -// Convert image data to OpenGL texture (returns OpenGL valid Id) -unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount) -{ - glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding - - GLuint id = 0; - - // Check texture format support by OpenGL 1.1 (compressed textures not supported) -#if defined(GRAPHICS_API_OPENGL_11) - if (format >= COMPRESSED_DXT1_RGB) - { - TraceLog(LOG_WARNING, "OpenGL 1.1 does not support GPU compressed texture formats"); - return id; - } -#endif - - if ((!texCompDXTSupported) && ((format == COMPRESSED_DXT1_RGB) || (format == COMPRESSED_DXT1_RGBA) || - (format == COMPRESSED_DXT3_RGBA) || (format == COMPRESSED_DXT5_RGBA))) - { - TraceLog(LOG_WARNING, "DXT compressed texture format not supported"); - return id; - } -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((!texCompETC1Supported) && (format == COMPRESSED_ETC1_RGB)) - { - TraceLog(LOG_WARNING, "ETC1 compressed texture format not supported"); - return id; - } - - if ((!texCompETC2Supported) && ((format == COMPRESSED_ETC2_RGB) || (format == COMPRESSED_ETC2_EAC_RGBA))) - { - TraceLog(LOG_WARNING, "ETC2 compressed texture format not supported"); - return id; - } - - if ((!texCompPVRTSupported) && ((format == COMPRESSED_PVRT_RGB) || (format == COMPRESSED_PVRT_RGBA))) - { - TraceLog(LOG_WARNING, "PVRT compressed texture format not supported"); - return id; - } - - if ((!texCompASTCSupported) && ((format == COMPRESSED_ASTC_4x4_RGBA) || (format == COMPRESSED_ASTC_8x8_RGBA))) - { - TraceLog(LOG_WARNING, "ASTC compressed texture format not supported"); - return id; - } -#endif - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glGenTextures(1, &id); // Generate Pointer to the texture - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - //glActiveTexture(GL_TEXTURE0); // If not defined, using GL_TEXTURE0 by default (shader texture) -#endif - - glBindTexture(GL_TEXTURE_2D, id); - - int mipWidth = width; - int mipHeight = height; - int mipOffset = 0; // Mipmap data offset - - TraceLog(LOG_DEBUG, "Load texture from data memory address: 0x%x", data); - - // Load the different mipmap levels - for (int i = 0; i < mipmapCount; i++) - { - unsigned int mipSize = GetPixelDataSize(mipWidth, mipHeight, format); - - int glInternalFormat, glFormat, glType; - GetGlFormats(format, &glInternalFormat, &glFormat, &glType); - - TraceLog(LOG_DEBUG, "Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); - - if (glInternalFormat != -1) - { - if (format < 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, (unsigned char *)data + mipOffset); - #endif - - #if defined(GRAPHICS_API_OPENGL_33) - if (format == UNCOMPRESSED_GRAYSCALE) - { - GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - else if (format == UNCOMPRESSED_GRAY_ALPHA) - { - GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - #endif - } - - mipWidth /= 2; - mipHeight /= 2; - mipOffset += mipSize; - - // Security check for NPOT textures - if (mipWidth < 1) mipWidth = 1; - if (mipHeight < 1) mipHeight = 1; - } - - // Texture parameters configuration - // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used -#if defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used - if (texNPOTSupported) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis - } - else - { - // NOTE: If using negative texture coordinates (LoadOBJ()), it does not work! - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis - } -#else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis -#endif - - // Magnification and minification filters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR - -#if defined(GRAPHICS_API_OPENGL_33) - if (mipmapCount > 1) - { - // 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); - } -#endif - - // At this point we have the texture loaded in GPU and texture parameters configured - - // NOTE: If mipmaps were not in data, they are not generated automatically - - // Unbind current texture - glBindTexture(GL_TEXTURE_2D, 0); - - if (id > 0) TraceLog(LOG_INFO, "[TEX ID %i] Texture created successfully (%ix%i - %i mipmaps)", id, width, height, mipmapCount); - else TraceLog(LOG_WARNING, "Texture could not be created"); - - return id; -} - -// Update already loaded texture in GPU with new data -void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data) -{ - glBindTexture(GL_TEXTURE_2D, id); - - int glInternalFormat, glFormat, glType; - GetGlFormats(format, &glInternalFormat, &glFormat, &glType); - - if ((glInternalFormat != -1) && (format < COMPRESSED_DXT1_RGB)) - { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, glFormat, glType, (unsigned char *)data); - } - else TraceLog(LOG_WARNING, "Texture format updating not supported"); -} - -// Unload texture from GPU memory -void rlUnloadTexture(unsigned int id) -{ - if (id > 0) glDeleteTextures(1, &id); -} - - -// Load a texture to be used for rendering (fbo with color and depth attachments) -RenderTexture2D rlLoadRenderTexture(int width, int height) -{ - RenderTexture2D target; - - target.id = 0; - - target.texture.id = 0; - target.texture.width = width; - target.texture.height = height; - target.texture.format = UNCOMPRESSED_R8G8B8A8; - target.texture.mipmaps = 1; - - target.depth.id = 0; - target.depth.width = width; - target.depth.height = height; - target.depth.format = 19; //DEPTH_COMPONENT_24BIT - target.depth.mipmaps = 1; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Create the texture that will serve as the color attachment for the framebuffer - glGenTextures(1, &target.texture.id); - glBindTexture(GL_TEXTURE_2D, target.texture.id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - -#if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) - #define USE_DEPTH_RENDERBUFFER -#else - #define USE_DEPTH_TEXTURE -#endif - -#if defined(USE_DEPTH_RENDERBUFFER) - // Create the renderbuffer that will serve as the depth attachment for the framebuffer. - glGenRenderbuffers(1, &target.depth.id); - glBindRenderbuffer(GL_RENDERBUFFER, target.depth.id); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); // GL_DEPTH_COMPONENT24 not supported on Android -#elif defined(USE_DEPTH_TEXTURE) - // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extension required) - // A renderbuffer is simpler than a texture and could offer better performance on embedded devices - glGenTextures(1, &target.depth.id); - glBindTexture(GL_TEXTURE_2D, target.depth.id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glBindTexture(GL_TEXTURE_2D, 0); -#endif - - // Create the framebuffer object - glGenFramebuffers(1, &target.id); - glBindFramebuffer(GL_FRAMEBUFFER, target.id); - - // Attach color texture and depth renderbuffer to FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target.texture.id, 0); -#if defined(USE_DEPTH_RENDERBUFFER) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, target.depth.id); -#elif defined(USE_DEPTH_TEXTURE) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target.depth.id, 0); -#endif - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - TraceLog(LOG_WARNING, "Framebuffer object could not be created..."); - - switch (status) - { - case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(LOG_WARNING, "Framebuffer is unsupported"); break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(LOG_WARNING, "Framebuffer incomplete attachment"); break; -#if defined(GRAPHICS_API_OPENGL_ES2) - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TraceLog(LOG_WARNING, "Framebuffer incomplete dimensions"); break; -#endif - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(LOG_WARNING, "Framebuffer incomplete missing attachment"); break; - default: break; - } - - glDeleteTextures(1, &target.texture.id); - glDeleteTextures(1, &target.depth.id); - glDeleteFramebuffers(1, &target.id); - } - else TraceLog(LOG_INFO, "[FBO ID %i] Framebuffer object created successfully", target.id); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif - - return target; -} - -// Generate mipmap data for selected texture -void rlGenerateMipmaps(Texture2D *texture) -{ - glBindTexture(GL_TEXTURE_2D, texture->id); - - // Check if texture is power-of-two (POT) - bool texIsPOT = false; - - if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) && - ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true; - - if ((texIsPOT) || (texNPOTSupported)) - { -#if defined(GRAPHICS_API_OPENGL_11) - // Compute required mipmaps - void *data = rlReadTexturePixels(*texture); - - // NOTE: data size is reallocated to fit mipmaps data - // NOTE: CPU mipmap generation only supports RGBA 32bit data - int mipmapCount = GenerateMipmaps(data, texture->width, texture->height); - - int size = texture->width*texture->height*4; // RGBA 32bit only - 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 *)data + offset); - - size = mipWidth*mipHeight*4; - offset += size; - - mipWidth /= 2; - mipHeight /= 2; - } - - TraceLog(LOG_WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture->id); - - // NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data - free(data); - - texture->mipmaps = mipmapCount + 1; -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - //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 - TraceLog(LOG_INFO, "[TEX ID %i] Mipmaps generated automatically", texture->id); - - 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 - - #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)); -#endif - } - else TraceLog(LOG_WARNING, "[TEX ID %i] Mipmaps can not be generated", texture->id); - - glBindTexture(GL_TEXTURE_2D, 0); -} - -// Upload vertex data into a VAO (if supported) and VBO -// TODO: Check if mesh has already been loaded in GPU -void rlLoadMesh(Mesh *mesh, bool dynamic) -{ - mesh->vaoId = 0; // Vertex Array Object - mesh->vboId[0] = 0; // Vertex positions VBO - mesh->vboId[1] = 0; // Vertex texcoords VBO - mesh->vboId[2] = 0; // Vertex normals VBO - mesh->vboId[3] = 0; // Vertex colors VBO - mesh->vboId[4] = 0; // Vertex tangents VBO - mesh->vboId[5] = 0; // Vertex texcoords2 VBO - mesh->vboId[6] = 0; // Vertex indices VBO - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - int drawHint = GL_STATIC_DRAW; - if (dynamic) drawHint = GL_DYNAMIC_DRAW; - - if (vaoSupported) - { - // Initialize Quads VAO (Buffer A) - glGenVertexArrays(1, &mesh->vaoId); - glBindVertexArray(mesh->vaoId); - } - - // NOTE: Attributes must be uploaded considering default locations points - - // Enable vertex attributes: position (shader-location = 0) - glGenBuffers(1, &mesh->vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint); - glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(0); - - // Enable vertex attributes: texcoords (shader-location = 1) - glGenBuffers(1, &mesh->vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint); - glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(1); - - // Enable vertex attributes: normals (shader-location = 2) - if (mesh->normals != NULL) - { - glGenBuffers(1, &mesh->vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint); - glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(2); - } - else - { - // Default color vertex attribute set to WHITE - glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f); - glDisableVertexAttribArray(2); - } - - // Default color vertex attribute (shader-location = 3) - if (mesh->colors != NULL) - { - glGenBuffers(1, &mesh->vboId[3]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[3]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint); - glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(3); - } - else - { - // Default color vertex attribute set to WHITE - glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); - glDisableVertexAttribArray(3); - } - - // Default tangent vertex attribute (shader-location = 4) - if (mesh->tangents != NULL) - { - glGenBuffers(1, &mesh->vboId[4]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[4]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh->vertexCount, mesh->tangents, drawHint); - glVertexAttribPointer(4, 4, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(4); - } - else - { - // Default tangents vertex attribute - glVertexAttrib4f(4, 0.0f, 0.0f, 0.0f, 0.0f); - glDisableVertexAttribArray(4); - } - - // Default texcoord2 vertex attribute (shader-location = 5) - if (mesh->texcoords2 != NULL) - { - glGenBuffers(1, &mesh->vboId[5]); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId[5]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint); - glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(5); - } - else - { - // Default texcoord2 vertex attribute - glVertexAttrib2f(5, 0.0f, 0.0f); - glDisableVertexAttribArray(5); - } - - if (mesh->indices != NULL) - { - glGenBuffers(1, &mesh->vboId[6]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->vboId[6]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*mesh->triangleCount*3, mesh->indices, GL_STATIC_DRAW); - } - - if (vaoSupported) - { - if (mesh->vaoId > 0) TraceLog(LOG_INFO, "[VAO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); - else TraceLog(LOG_WARNING, "Mesh could not be uploaded to VRAM (GPU)"); - } - else - { - TraceLog(LOG_INFO, "[VBOs] Mesh uploaded successfully to VRAM (GPU)"); - } -#endif -} - -// Update vertex data on GPU (upload new data to one buffer) -void rlUpdateMesh(Mesh mesh, int buffer, int numVertex) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Activate mesh VAO - if (vaoSupported) glBindVertexArray(mesh.vaoId); - - switch (buffer) - { - case 0: // Update vertices (vertex position) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.vertices, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.vertices); - - } break; - case 1: // Update texcoords (vertex texture coordinates) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords); - - } break; - case 2: // Update normals (vertex normals) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.normals, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.normals); - - } break; - case 3: // Update colors (vertex colors) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.colors, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*numVertex, mesh.colors); - - } break; - case 4: // Update tangents (vertex tangents) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.tangents, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*numVertex, mesh.tangents); - } break; - case 5: // Update texcoords2 (vertex second texture coordinates) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]); - if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords2, GL_DYNAMIC_DRAW); - else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords2); - } break; - default: break; - } - - // Unbind the current VAO - if (vaoSupported) glBindVertexArray(0); - - // Another option would be using buffer mapping... - //mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - // Now we can modify vertices - //glUnmapBuffer(GL_ARRAY_BUFFER); -#endif -} - -// Draw a 3d mesh with material and transform -void rlDrawMesh(Mesh mesh, Material material, Matrix transform) -{ -#if defined(GRAPHICS_API_OPENGL_11) - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, material.maps[MAP_DIFFUSE].texture.id); - - // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model - glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array - glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array - if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array - if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY); // Enable colors array - - glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array - glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array - if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array - if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array - - rlPushMatrix(); - rlMultMatrixf(MatrixToFloat(transform)); - rlColor4ub(material.maps[MAP_DIFFUSE].color.r, material.maps[MAP_DIFFUSE].color.g, material.maps[MAP_DIFFUSE].color.b, material.maps[MAP_DIFFUSE].color.a); - - if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices); - else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); - rlPopMatrix(); - - glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array - glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array - if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array - if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable colors array - - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); -#endif - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Bind shader program - glUseProgram(material.shader.id); - - // Matrices and other values required by shader - //----------------------------------------------------- - // Calculate and send to shader model matrix (used by PBR shader) - if (material.shader.locs[LOC_MATRIX_MODEL] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_MODEL], transform); - - // Upload to shader material.colDiffuse - if (material.shader.locs[LOC_COLOR_DIFFUSE] != -1) - glUniform4f(material.shader.locs[LOC_COLOR_DIFFUSE], (float)material.maps[MAP_DIFFUSE].color.r/255.0f, - (float)material.maps[MAP_DIFFUSE].color.g/255.0f, - (float)material.maps[MAP_DIFFUSE].color.b/255.0f, - (float)material.maps[MAP_DIFFUSE].color.a/255.0f); - - // Upload to shader material.colSpecular (if available) - if (material.shader.locs[LOC_COLOR_SPECULAR] != -1) - glUniform4f(material.shader.locs[LOC_COLOR_SPECULAR], (float)material.maps[MAP_SPECULAR].color.r/255.0f, - (float)material.maps[MAP_SPECULAR].color.g/255.0f, - (float)material.maps[MAP_SPECULAR].color.b/255.0f, - (float)material.maps[MAP_SPECULAR].color.a/255.0f); - - if (material.shader.locs[LOC_MATRIX_VIEW] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_VIEW], modelview); - if (material.shader.locs[LOC_MATRIX_PROJECTION] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_PROJECTION], projection); - - // At this point the modelview matrix just contains the view matrix (camera) - // That's because BeginMode3D() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix() - Matrix matView = modelview; // View matrix (camera) - Matrix matProjection = projection; // Projection matrix (perspective) - - // Calculate model-view matrix combining matModel and matView - Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates - //----------------------------------------------------- - - // Bind active texture maps (if available) - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - if (material.maps[i].texture.id > 0) - { - glActiveTexture(GL_TEXTURE0 + i); - if ((i == MAP_IRRADIANCE) || (i == MAP_PREFILTER) || (i == MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, material.maps[i].texture.id); - else glBindTexture(GL_TEXTURE_2D, material.maps[i].texture.id); - - glUniform1i(material.shader.locs[LOC_MAP_DIFFUSE + i], i); - } - } - - // Bind vertex array objects (or VBOs) - if (vaoSupported) glBindVertexArray(mesh.vaoId); - else - { - // TODO: Simplify VBO binding into a for loop - - // Bind mesh VBO data: vertex position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_POSITION]); - - // Bind mesh VBO data: vertex texcoords (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TEXCOORD01]); - - // Bind mesh VBO data: vertex normals (shader-location = 2, if available) - if (material.shader.locs[LOC_VERTEX_NORMAL] != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_NORMAL]); - } - - // Bind mesh VBO data: vertex colors (shader-location = 3, if available) - if (material.shader.locs[LOC_VERTEX_COLOR] != -1) - { - if (mesh.vboId[3] != 0) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_COLOR]); - } - else - { - // Set default value for unused attribute - // NOTE: Required when using default shader and no VAO support - glVertexAttrib4f(material.shader.locs[LOC_VERTEX_COLOR], 1.0f, 1.0f, 1.0f, 1.0f); - glDisableVertexAttribArray(material.shader.locs[LOC_VERTEX_COLOR]); - } - } - - // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) - if (material.shader.locs[LOC_VERTEX_TANGENT] != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TANGENT], 4, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TANGENT]); - } - - // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available) - if (material.shader.locs[LOC_VERTEX_TEXCOORD02] != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]); - glVertexAttribPointer(material.shader.locs[LOC_VERTEX_TEXCOORD02], 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(material.shader.locs[LOC_VERTEX_TEXCOORD02]); - } - - if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vboId[6]); - } - - int eyesCount = 1; -#if defined(SUPPORT_VR_SIMULATOR) - if (vrStereoRender) eyesCount = 2; -#endif - - for (int eye = 0; eye < eyesCount; eye++) - { - if (eyesCount == 1) modelview = matModelView; - #if defined(SUPPORT_VR_SIMULATOR) - else SetStereoView(eye, matProjection, matModelView); - #endif - - // Calculate model-view-projection matrix (MVP) - Matrix matMVP = MatrixMultiply(modelview, projection); // Transform to screen-space coordinates - - // Send combined model-view-projection matrix to shader - glUniformMatrix4fv(material.shader.locs[LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP)); - - // Draw call! - if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw - else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); - } - - // Unbind all binded texture maps - for (int i = 0; i < MAX_MATERIAL_MAPS; i++) - { - glActiveTexture(GL_TEXTURE0 + i); // Set shader active texture - if ((i == MAP_IRRADIANCE) || (i == MAP_PREFILTER) || (i == MAP_CUBEMAP)) glBindTexture(GL_TEXTURE_CUBE_MAP, 0); - else glBindTexture(GL_TEXTURE_2D, 0); // Unbind current active texture - } - - // Unind vertex array objects (or VBOs) - if (vaoSupported) glBindVertexArray(0); - else - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - // Unbind shader program - glUseProgram(0); - - // Restore projection/modelview matrices - // NOTE: In stereo rendering matrices are being modified to fit every eye - projection = matProjection; - modelview = matView; -#endif -} - -// Unload mesh data from CPU and GPU -void rlUnloadMesh(Mesh *mesh) -{ - if (mesh->vertices != NULL) free(mesh->vertices); - if (mesh->texcoords != NULL) free(mesh->texcoords); - if (mesh->normals != NULL) free(mesh->normals); - if (mesh->colors != NULL) free(mesh->colors); - if (mesh->tangents != NULL) free(mesh->tangents); - if (mesh->texcoords2 != NULL) free(mesh->texcoords2); - if (mesh->indices != NULL) free(mesh->indices); - - rlDeleteBuffers(mesh->vboId[0]); // vertex - rlDeleteBuffers(mesh->vboId[1]); // texcoords - rlDeleteBuffers(mesh->vboId[2]); // normals - rlDeleteBuffers(mesh->vboId[3]); // colors - rlDeleteBuffers(mesh->vboId[4]); // tangents - rlDeleteBuffers(mesh->vboId[5]); // texcoords2 - rlDeleteBuffers(mesh->vboId[6]); // indices - - rlDeleteVertexArrays(mesh->vaoId); -} - -// Read screen pixel data (color buffer) -unsigned char *rlReadScreenPixels(int width, int height) -{ - unsigned char *screenData = (unsigned char *)calloc(width*height*4, sizeof(unsigned char)); - - // NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); - - // Flip image vertically! - unsigned char *imgData = (unsigned char *)malloc(width*height*sizeof(unsigned char)*4); - - for (int y = height - 1; y >= 0; y--) - { - for (int x = 0; x < (width*4); x++) - { - // Flip line - imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; - - // 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; - } - } - - free(screenData); - - return imgData; // NOTE: image data should be freed -} - -// Read texture pixel data -// NOTE: glGetTexImage() is not available on OpenGL ES 2.0 -// Texture2D width and height are required on OpenGL ES 2.0. There is no way to get it from texture id. -void *rlReadTexturePixels(Texture2D texture) -{ - void *pixels = NULL; - -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - glBindTexture(GL_TEXTURE_2D, texture.id); - - // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0) - /* - 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); - // Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE - */ - - // 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); - - int glInternalFormat, glFormat, glType; - GetGlFormats(texture.format, &glInternalFormat, &glFormat, &glType); - unsigned int size = GetPixelDataSize(texture.width, texture.height, texture.format); - - if ((glInternalFormat != -1) && (texture.format < COMPRESSED_DXT1_RGB)) - { - pixels = (unsigned char *)malloc(size); - glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); - } - else TraceLog(LOG_WARNING, "Texture data retrieval not suported for pixel format"); - - glBindTexture(GL_TEXTURE_2D, 0); -#endif - -#if defined(GRAPHICS_API_OPENGL_ES2) - RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height); - - // NOTE: Two possible Options: - // 1 - Bind texture to color fbo attachment and glReadPixels() - // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() - -#define GET_TEXTURE_FBO_OPTION_1 // It works -#if defined(GET_TEXTURE_FBO_OPTION_1) - glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); - glBindTexture(GL_TEXTURE_2D, 0); - - // Attach our texture to FBO -> Texture must be RGBA - // NOTE: Previoust attached texture is automatically detached - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0); - - pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char)); - - // NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture... - glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Re-attach internal FBO color texture before deleting it - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.texture.id, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - -#elif defined(GET_TEXTURE_FBO_OPTION_2) - // Render texture to fbo - glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepthf(1.0f); - //glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); - //glDisable(GL_BLEND); - - glViewport(0, 0, texture.width, texture.height); - rlOrtho(0.0, texture.width, texture.height, 0.0, 0.0, 1.0); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(GetShaderDefault().id); - glBindTexture(GL_TEXTURE_2D, texture.id); - GenDrawQuad(); - glBindTexture(GL_TEXTURE_2D, 0); - glUseProgram(0); - - pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char)); - - glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Bind framebuffer 0, which means render to back buffer - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Reset viewport dimensions to default - glViewport(0, 0, screenWidth, screenHeight); - -#endif // GET_TEXTURE_FBO_OPTION - - // Clean up temporal fbo - rlDeleteRenderTextures(fbo); - -#endif - - return pixels; -} - -/* -// TODO: Record draw calls to be processed in batch -// NOTE: Global state must be kept -void rlRecordDraw(void) -{ - // TODO: Before adding a new draw, check if anything changed from last stored draw -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - draws[drawsCounter].vaoId = currentState.vaoId; // lines.id, trangles.id, quads.id? - draws[drawsCounter].textureId = currentState.textureId; // whiteTexture? - draws[drawsCounter].shaderId = currentState.shaderId; // defaultShader.id - draws[drawsCounter].projection = projection; - draws[drawsCounter].modelview = modelview; - draws[drawsCounter].vertexCount = currentState.vertexCount; - - drawsCounter++; -#endif -} -*/ - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Shaders Functions -// NOTE: Those functions are exposed directly to the user in raylib.h -//---------------------------------------------------------------------------------- - -// Get default internal texture (white texture) -Texture2D GetTextureDefault(void) -{ - Texture2D texture; - - texture.id = whiteTexture; - texture.width = 1; - texture.height = 1; - texture.mipmaps = 1; - texture.format = UNCOMPRESSED_R8G8B8A8; - - return texture; -} - -// Get default shader -Shader GetShaderDefault(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - return defaultShader; -#else - Shader shader = { 0 }; - return shader; -#endif -} - -// Load text data from file -// NOTE: text chars array should be freed manually -char *LoadText(const char *fileName) -{ - FILE *textFile; - char *text = NULL; - - int count = 0; - - if (fileName != NULL) - { - textFile = fopen(fileName,"rt"); - - if (textFile != NULL) - { - fseek(textFile, 0, SEEK_END); - count = ftell(textFile); - rewind(textFile); - - if (count > 0) - { - text = (char *)malloc(sizeof(char)*(count + 1)); - count = fread(text, sizeof(char), count, textFile); - text[count] = '\0'; - } - - fclose(textFile); - } - else TraceLog(LOG_WARNING, "[%s] Text file could not be opened", fileName); - } - - return text; -} - -// 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 = LoadText(vsFileName); - if (fsFileName != NULL) fShaderStr = LoadText(fsFileName); - - shader = LoadShaderCode(vShaderStr, fShaderStr); - - if (vShaderStr != NULL) free(vShaderStr); - if (fShaderStr != NULL) free(fShaderStr); - - return shader; -} - -// Load shader from code strings -// NOTE: If shader string is NULL, using default vertex/fragment shaders -Shader LoadShaderCode(char *vsCode, char *fsCode) -{ - Shader shader = { 0 }; - - // NOTE: All locations must be reseted to -1 (no location) - for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId = defaultVShaderId; - unsigned int fragmentShaderId = defaultFShaderId; - - if (vsCode != NULL) vertexShaderId = CompileShader(vsCode, GL_VERTEX_SHADER); - if (fsCode != NULL) fragmentShaderId = CompileShader(fsCode, GL_FRAGMENT_SHADER); - - if ((vertexShaderId == defaultVShaderId) && (fragmentShaderId == defaultFShaderId)) shader = defaultShader; - else - { - shader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); - - if (vertexShaderId != defaultVShaderId) glDeleteShader(vertexShaderId); - if (fragmentShaderId != defaultFShaderId) glDeleteShader(fragmentShaderId); - - if (shader.id == 0) - { - TraceLog(LOG_WARNING, "Custom shader could not be loaded"); - shader = defaultShader; - } - - // After shader loading, we TRY to set default location names - if (shader.id > 0) SetShaderDefaultLocations(&shader); - } - - // Get available shader uniforms - // NOTE: This information is useful for debug... - int uniformCount = -1; - - glGetProgramiv(shader.id, GL_ACTIVE_UNIFORMS, &uniformCount); - - 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(shader.id, i,sizeof(name) - 1, &namelen, &num, &type, name); - - name[namelen] = 0; - - // Get the location of the named uniform - GLuint location = glGetUniformLocation(shader.id, name); - - TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location); - } -#endif - - return shader; -} - -// Unload shader from GPU memory (VRAM) -void UnloadShader(Shader shader) -{ - if (shader.id > 0) - { - rlDeleteShader(shader.id); - TraceLog(LOG_INFO, "[SHDR ID %i] Unloaded shader program data", shader.id); - } -} - -// Begin custom shader mode -void BeginShaderMode(Shader shader) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (currentShader.id != shader.id) - { - rlglDraw(); - currentShader = shader; - } -#endif -} - -// End custom shader mode (returns to default shader) -void EndShaderMode(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - BeginShaderMode(defaultShader); -#endif -} - -// Get shader uniform location -int GetShaderLocation(Shader shader, const char *uniformName) -{ - int location = -1; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetUniformLocation(shader.id, uniformName); - - if (location == -1) TraceLog(LOG_WARNING, "[SHDR ID %i] Shader uniform [%s] COULD NOT BE FOUND", shader.id, uniformName); - else TraceLog(LOG_INFO, "[SHDR ID %i] Shader uniform [%s] set at location: %i", shader.id, uniformName, location); -#endif - return location; -} - -// Set shader uniform value (float) -void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - if (size == 1) glUniform1fv(uniformLoc, 1, value); // Shader uniform type: float - else if (size == 2) glUniform2fv(uniformLoc, 1, value); // Shader uniform type: vec2 - else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3 - else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4 - else TraceLog(LOG_WARNING, "Shader value float array size not supported"); - - //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set -#endif -} - -// Set shader uniform value (int) -void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - if (size == 1) glUniform1iv(uniformLoc, 1, value); // Shader uniform type: int - else if (size == 2) glUniform2iv(uniformLoc, 1, value); // Shader uniform type: ivec2 - else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3 - else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4 - else TraceLog(LOG_WARNING, "Shader value int array size not supported"); - - //glUseProgram(0); -#endif -} - -// Set shader uniform value (matrix 4x4) -void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); - - //glUseProgram(0); -#endif -} - -// Set a custom projection matrix (replaces internal projection matrix) -void SetMatrixProjection(Matrix proj) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - projection = proj; -#endif -} - -// Set a custom modelview matrix (replaces internal modelview matrix) -void SetMatrixModelview(Matrix view) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - modelview = view; -#endif -} - -// Return internal modelview matrix -Matrix GetMatrixModelview() -{ - Matrix matrix = MatrixIdentity(); -#if defined(GRAPHICS_API_OPENGL_11) - float mat[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, mat); -#else - matrix = modelview; -#endif - return matrix; -} - -// Generate cubemap texture from HDR texture -// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 -Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size) -{ - Texture2D cubemap = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader - // Other locations should be setup externally in shader before calling the function - - // Set up depth face culling and cubemap seamless - glDisable(GL_CULL_FACE); -#if defined(GRAPHICS_API_OPENGL_33) - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Flag not supported on OpenGL ES 2.0 -#endif - - - // Setup framebuffer - unsigned int fbo, rbo; - glGenFramebuffers(1, &fbo); - glGenRenderbuffers(1, &rbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); - - // Set up cubemap to render and attach to framebuffer - // NOTE: faces are stored with 16 bit floating point values - glGenTextures(1, &cubemap.id); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); - for (unsigned int i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); - 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); -#if defined(GRAPHICS_API_OPENGL_33) - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0 -#endif - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Create projection (transposed) and different views for each face - Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0); - //MatrixTranspose(&fboProjection); - Matrix fboViews[6] = { - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) - }; - - // Convert HDR equirectangular environment map to cubemap equivalent - glUseProgram(shader.id); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, skyHDR.id); - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection); - - // Note: don't forget to configure the viewport to the capture dimensions - glViewport(0, 0, size, size); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - for (unsigned int i = 0; i < 6; i++) - { - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap.id, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GenDrawCube(); - } - - // Unbind framebuffer and textures - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Reset viewport dimensions to default - glViewport(0, 0, screenWidth, screenHeight); - //glEnable(GL_CULL_FACE); - - cubemap.width = size; - cubemap.height = size; -#endif - return cubemap; -} - -// Generate irradiance texture using cubemap data -// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 -Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size) -{ - Texture2D irradiance = { 0 }; - -#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader - // Other locations should be setup externally in shader before calling the function - - // Setup framebuffer - unsigned int fbo, rbo; - glGenFramebuffers(1, &fbo); - glGenRenderbuffers(1, &rbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); - - // Create an irradiance cubemap, and re-scale capture FBO to irradiance scale - glGenTextures(1, &irradiance.id); - glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance.id); - for (unsigned int i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); - 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); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Create projection (transposed) and different views for each face - Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0); - //MatrixTranspose(&fboProjection); - Matrix fboViews[6] = { - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) - }; - - // Solve diffuse integral by convolution to create an irradiance cubemap - glUseProgram(shader.id); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection); - - // Note: don't forget to configure the viewport to the capture dimensions - glViewport(0, 0, size, size); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - for (unsigned int i = 0; i < 6; i++) - { - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance.id, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GenDrawCube(); - } - - // Unbind framebuffer and textures - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Reset viewport dimensions to default - glViewport(0, 0, screenWidth, screenHeight); - - irradiance.width = size; - irradiance.height = size; -#endif - return irradiance; -} - -// Generate prefilter texture using cubemap data -// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 -Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size) -{ - Texture2D prefilter = { 0 }; - -#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader - // Other locations should be setup externally in shader before calling the function - // TODO: Locations should be taken out of this function... too shader dependant... - int roughnessLoc = GetShaderLocation(shader, "roughness"); - - // Setup framebuffer - unsigned int fbo, rbo; - glGenFramebuffers(1, &fbo); - glGenRenderbuffers(1, &rbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); - - // Create a prefiltered HDR environment map - glGenTextures(1, &prefilter.id); - glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter.id); - for (unsigned int i = 0; i < 6; i++) - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); - 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); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Generate mipmaps for the prefiltered HDR texture - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - - // Create projection (transposed) and different views for each face - Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0); - //MatrixTranspose(&fboProjection); - Matrix fboViews[6] = { - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), - MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) - }; - - // Prefilter HDR and store data into mipmap levels - glUseProgram(shader.id); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection); - - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - #define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps - - for (unsigned int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++) - { - // Resize framebuffer according to mip-level size. - unsigned int mipWidth = size*powf(0.5f, mip); - unsigned int mipHeight = size*powf(0.5f, mip); - - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); - glViewport(0, 0, mipWidth, mipHeight); - - float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1); - glUniform1f(roughnessLoc, roughness); - - for (unsigned int i = 0; i < 6; ++i) - { - SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GenDrawCube(); - } - } - - // Unbind framebuffer and textures - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Reset viewport dimensions to default - glViewport(0, 0, screenWidth, screenHeight); - - prefilter.width = size; - prefilter.height = size; -#endif - return prefilter; -} - -// Generate BRDF texture using cubemap data -// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 -Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size) -{ - Texture2D brdf = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) - // Generate BRDF convolution texture - glGenTextures(1, &brdf.id); - glBindTexture(GL_TEXTURE_2D, brdf.id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, size, size, 0, GL_RG, GL_FLOAT, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // Render BRDF LUT into a quad using FBO - unsigned int fbo, rbo; - glGenFramebuffers(1, &fbo); - glGenRenderbuffers(1, &rbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdf.id, 0); - - glViewport(0, 0, size, size); - glUseProgram(shader.id); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GenDrawQuad(); - - // Unbind framebuffer and textures - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Reset viewport dimensions to default - glViewport(0, 0, screenWidth, screenHeight); - - brdf.width = size; - brdf.height = size; -#endif - return brdf; -} - -// Begin blending mode (alpha, additive, multiplied) -// NOTE: Only 3 blending modes supported, default blend mode is alpha -void BeginBlendMode(int mode) -{ - if ((blendMode != mode) && (mode < 3)) - { - rlglDraw(); - - switch (mode) - { - case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; - case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE); - case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; - default: break; - } - - blendMode = mode; - } -} - -// End blending mode (reset to default: alpha blending) -void EndBlendMode(void) -{ - BeginBlendMode(BLEND_ALPHA); -} - -#if defined(SUPPORT_VR_SIMULATOR) -// Get VR device information for some standard devices -VrDeviceInfo GetVrDeviceInfo(int vrDeviceType) -{ - VrDeviceInfo hmd = { 0 }; // Current VR device info - - switch (vrDeviceType) - { - case HMD_DEFAULT_DEVICE: - case HMD_OCULUS_RIFT_CV1: - { - // Oculus Rift CV1 parameters - // NOTE: CV1 represents a complete HMD redesign compared to previous versions, - // new Fresnel-hybrid-asymmetric lenses have been added and, consequently, - // previous parameters (DK2) and distortion shader (DK2) doesn't work any more. - // I just defined a set of parameters for simulator that approximate to CV1 stereo rendering - // but result is not the same obtained with Oculus PC SDK. - hmd.hResolution = 2160; // HMD horizontal resolution in pixels - hmd.vResolution = 1200; // HMD vertical resolution in pixels - hmd.hScreenSize = 0.133793f; // HMD horizontal size in meters - hmd.vScreenSize = 0.0669f; // HMD vertical size in meters - hmd.vScreenCenter = 0.04678f; // HMD screen center in meters - hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters - hmd.lensSeparationDistance = 0.07f; // HMD lens separation distance in meters - hmd.interpupillaryDistance = 0.07f; // HMD IPD (distance between pupils) in meters - hmd.lensDistortionValues[0] = 1.0f; // HMD lens distortion constant parameter 0 - hmd.lensDistortionValues[1] = 0.22f; // HMD lens distortion constant parameter 1 - hmd.lensDistortionValues[2] = 0.24f; // HMD lens distortion constant parameter 2 - hmd.lensDistortionValues[3] = 0.0f; // HMD lens distortion constant parameter 3 - hmd.chromaAbCorrection[0] = 0.996f; // HMD chromatic aberration correction parameter 0 - hmd.chromaAbCorrection[1] = -0.004f; // HMD chromatic aberration correction parameter 1 - hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 - hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 - - TraceLog(LOG_INFO, "Initializing VR Simulator (Oculus Rift CV1)"); - } break; - case HMD_OCULUS_RIFT_DK2: - { - // Oculus Rift DK2 parameters - hmd.hResolution = 1280; // HMD horizontal resolution in pixels - hmd.vResolution = 800; // HMD vertical resolution in pixels - hmd.hScreenSize = 0.14976f; // HMD horizontal size in meters - hmd.vScreenSize = 0.09356f; // HMD vertical size in meters - hmd.vScreenCenter = 0.04678f; // HMD screen center in meters - hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters - hmd.lensSeparationDistance = 0.0635f; // HMD lens separation distance in meters - hmd.interpupillaryDistance = 0.064f; // HMD IPD (distance between pupils) in meters - hmd.lensDistortionValues[0] = 1.0f; // HMD lens distortion constant parameter 0 - hmd.lensDistortionValues[1] = 0.22f; // HMD lens distortion constant parameter 1 - hmd.lensDistortionValues[2] = 0.24f; // HMD lens distortion constant parameter 2 - hmd.lensDistortionValues[3] = 0.0f; // HMD lens distortion constant parameter 3 - hmd.chromaAbCorrection[0] = 0.996f; // HMD chromatic aberration correction parameter 0 - hmd.chromaAbCorrection[1] = -0.004f; // HMD chromatic aberration correction parameter 1 - hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 - hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 - - TraceLog(LOG_INFO, "Initializing VR Simulator (Oculus Rift DK2)"); - } break; - case HMD_OCULUS_GO: - { - // TODO: Provide device display and lens parameters - } - case HMD_VALVE_HTC_VIVE: - { - // TODO: Provide device display and lens parameters - } - case HMD_SONY_PSVR: - { - // TODO: Provide device display and lens parameters - } - default: break; - } - - return hmd; -} - -// Init VR simulator for selected device parameters -// NOTE: It modifies the global variable: VrStereoConfig vrConfig -void InitVrSimulator(VrDeviceInfo info) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Initialize framebuffer and textures for stereo rendering - // NOTE: Screen size should match HMD aspect ratio - vrConfig.stereoFbo = rlLoadRenderTexture(screenWidth, screenHeight); - -#if defined(SUPPORT_DISTORTION_SHADER) - // Load distortion shader - unsigned int vertexShaderId = CompileShader(distortionVShaderStr, GL_VERTEX_SHADER); - unsigned int fragmentShaderId = CompileShader(distortionFShaderStr, GL_FRAGMENT_SHADER); - - vrConfig.distortionShader.id = LoadShaderProgram(vertexShaderId, fragmentShaderId); - if (vrConfig.distortionShader.id > 0) SetShaderDefaultLocations(&vrConfig.distortionShader); -#endif - - // Set VR configutarion parameters, including distortion shader - SetStereoConfig(info); - - vrSimulatorReady = true; -#endif - -#if defined(GRAPHICS_API_OPENGL_11) - TraceLog(LOG_WARNING, "VR Simulator not supported on OpenGL 1.1"); -#endif -} - -// Close VR simulator for current device -void CloseVrSimulator(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (vrSimulatorReady) - { - rlDeleteRenderTextures(vrConfig.stereoFbo); // Unload stereo framebuffer and texture - #if defined(SUPPORT_DISTORTION_SHADER) - UnloadShader(vrConfig.distortionShader); // Unload distortion shader - #endif - } -#endif -} - -// Detect if VR simulator is running -bool IsVrSimulatorReady(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - return vrSimulatorReady; -#else - return false; -#endif -} - -// Set VR distortion shader for stereoscopic rendering -// TODO: Review VR system to be more flexible, move distortion shader to user side -void SetVrDistortionShader(Shader shader) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - vrConfig.distortionShader = shader; - - //SetStereoConfig(info); // TODO: Must be reviewed to set new distortion shader uniform values... -#endif -} - -// Enable/Disable VR experience (device or simulator) -void ToggleVrMode(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - vrSimulatorReady = !vrSimulatorReady; - - if (!vrSimulatorReady) - { - vrStereoRender = false; - - // Reset viewport and default projection-modelview matrices - rlViewport(0, 0, screenWidth, screenHeight); - projection = MatrixOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); - modelview = MatrixIdentity(); - } - else vrStereoRender = true; -#endif -} - -// Update VR tracking (position and orientation) and camera -// NOTE: Camera (position, target, up) gets update with head tracking information -void UpdateVrTracking(Camera *camera) -{ - // TODO: Simulate 1st person camera system -} - -// Begin Oculus drawing configuration -void BeginVrDrawing(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (vrSimulatorReady) - { - // Setup framebuffer for stereo rendering - rlEnableRenderTexture(vrConfig.stereoFbo.id); - - // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) - // and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then: - // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB - // - Do NOT enable GL_FRAMEBUFFER_SRGB - //glEnable(GL_FRAMEBUFFER_SRGB); - - //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) - rlClearScreenBuffers(); // Clear current framebuffer(s) - - vrStereoRender = true; - } -#endif -} - -// End Oculus drawing process (and desktop mirror) -void EndVrDrawing(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (vrSimulatorReady) - { - vrStereoRender = false; // Disable stereo render - - rlDisableRenderTexture(); // Unbind current framebuffer - - rlClearScreenBuffers(); // Clear current framebuffer - - // Set viewport to default framebuffer size (screen size) - rlViewport(0, 0, screenWidth, screenHeight); - - // Let rlgl reconfigure internal matrices - rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix - rlLoadIdentity(); // Reset internal projection matrix - rlOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); // Recalculate internal projection matrix - rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix - rlLoadIdentity(); // Reset internal modelview matrix - -#if defined(SUPPORT_DISTORTION_SHADER) - // Draw RenderTexture (stereoFbo) using distortion shader - currentShader = vrConfig.distortionShader; -#else - currentShader = GetShaderDefault(); -#endif - - rlEnableTexture(vrConfig.stereoFbo.texture.id); - - rlPushMatrix(); - rlBegin(RL_QUADS); - rlColor4ub(255, 255, 255, 255); - rlNormal3f(0.0f, 0.0f, 1.0f); - - // Bottom-left corner for texture and quad - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(0.0f, 0.0f); - - // Bottom-right corner for texture and quad - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(0.0f, vrConfig.stereoFbo.texture.height); - - // Top-right corner for texture and quad - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f(vrConfig.stereoFbo.texture.width, vrConfig.stereoFbo.texture.height); - - // Top-left corner for texture and quad - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f(vrConfig.stereoFbo.texture.width, 0.0f); - rlEnd(); - rlPopMatrix(); - - rlDisableTexture(); - - // Update and draw render texture fbo with distortion to backbuffer - UpdateBuffersDefault(); - DrawBuffersDefault(); - - // Restore defaultShader - currentShader = defaultShader; - - // Reset viewport and default projection-modelview matrices - rlViewport(0, 0, screenWidth, screenHeight); - projection = MatrixOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); - modelview = MatrixIdentity(); - - rlDisableDepthTest(); - } -#endif -} -#endif // SUPPORT_VR_SIMULATOR - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -// Compile custom shader and return shader id -static unsigned int CompileShader(const char *shaderStr, int type) -{ - unsigned int shader = glCreateShader(type); - glShaderSource(shader, 1, &shaderStr, NULL); - - GLint success = 0; - glCompileShader(shader); - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - - if (success != GL_TRUE) - { - TraceLog(LOG_WARNING, "[SHDR ID %i] Failed to compile shader...", shader); - int maxLength = 0; - int length; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - -#if defined(_MSC_VER) - char *log = malloc(maxLength); -#else - char log[maxLength]; -#endif - glGetShaderInfoLog(shader, maxLength, &length, log); - - TraceLog(LOG_INFO, "%s", log); - -#if defined(_MSC_VER) - free(log); -#endif - } - else TraceLog(LOG_INFO, "[SHDR ID %i] Shader compiled successfully", shader); - - return shader; -} - -// Load custom shader strings and return program id -static unsigned int LoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - - GLint success = 0; - program = glCreateProgram(); - - glAttachShader(program, vShaderId); - glAttachShader(program, fShaderId); - - // NOTE: Default attribute shader locations must be binded before linking - glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME); - glBindAttribLocation(program, 1, DEFAULT_ATTRIB_TEXCOORD_NAME); - glBindAttribLocation(program, 2, DEFAULT_ATTRIB_NORMAL_NAME); - glBindAttribLocation(program, 3, DEFAULT_ATTRIB_COLOR_NAME); - glBindAttribLocation(program, 4, DEFAULT_ATTRIB_TANGENT_NAME); - glBindAttribLocation(program, 5, DEFAULT_ATTRIB_TEXCOORD2_NAME); - - // NOTE: If some attrib name is no found on the shader, it locations becomes -1 - - 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(LOG_WARNING, "[SHDR ID %i] Failed to link shader program...", program); - - int maxLength = 0; - int length; - - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - -#ifdef _MSC_VER - char *log = malloc(maxLength); -#else - char log[maxLength]; -#endif - glGetProgramInfoLog(program, maxLength, &length, log); - - TraceLog(LOG_INFO, "%s", log); - -#ifdef _MSC_VER - free(log); -#endif - glDeleteProgram(program); - - program = 0; - } - else TraceLog(LOG_INFO, "[SHDR ID %i] Shader program loaded successfully", program); -#endif - return program; -} - - -// Load default shader (just vertex positioning and texture coloring) -// NOTE: This shader program is used for batch buffers (lines, triangles, quads) -static Shader LoadShaderDefault(void) -{ - Shader shader = { 0 }; - - // NOTE: All locations must be reseted to -1 (no location) - for (int i = 0; i < MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; - - // Vertex shader directly defined, no external file required - char defaultVShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) - "#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - "#version 100 \n" -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) - "attribute vec3 vertexPosition; \n" - "attribute vec2 vertexTexCoord; \n" - "attribute vec4 vertexColor; \n" - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) - "#version 330 \n" - "in vec3 vertexPosition; \n" - "in vec2 vertexTexCoord; \n" - "in vec4 vertexColor; \n" - "out vec2 fragTexCoord; \n" - "out vec4 fragColor; \n" -#endif - "uniform mat4 mvp; \n" - "void main() \n" - "{ \n" - " fragTexCoord = vertexTexCoord; \n" - " fragColor = vertexColor; \n" - " gl_Position = mvp*vec4(vertexPosition, 1.0); \n" - "} \n"; - - // Fragment shader directly defined, no external file required - char defaultFShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) - "#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - "#version 100 \n" - "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) - "#version 330 \n" - "in vec2 fragTexCoord; \n" - "in vec4 fragColor; \n" - "out vec4 finalColor; \n" -#endif - "uniform sampler2D texture0; \n" - "uniform vec4 colDiffuse; \n" - "void main() \n" - "{ \n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) - " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 - " gl_FragColor = texelColor*colDiffuse*fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) - " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = texelColor*colDiffuse*fragColor; \n" -#endif - "} \n"; - - // NOTE: Compiled vertex/fragment shaders are kept for re-use - defaultVShaderId = CompileShader(defaultVShaderStr, GL_VERTEX_SHADER); // Compile default vertex shader - defaultFShaderId = CompileShader(defaultFShaderStr, GL_FRAGMENT_SHADER); // Compile default fragment shader - - shader.id = LoadShaderProgram(defaultVShaderId, defaultFShaderId); - - if (shader.id > 0) - { - TraceLog(LOG_INFO, "[SHDR ID %i] Default shader loaded successfully", shader.id); - - // Set default shader locations: attributes locations - shader.locs[LOC_VERTEX_POSITION] = glGetAttribLocation(shader.id, "vertexPosition"); - shader.locs[LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(shader.id, "vertexTexCoord"); - shader.locs[LOC_VERTEX_COLOR] = glGetAttribLocation(shader.id, "vertexColor"); - - // Set default shader locations: uniform locations - shader.locs[LOC_MATRIX_MVP] = glGetUniformLocation(shader.id, "mvp"); - shader.locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader.id, "colDiffuse"); - shader.locs[LOC_MAP_DIFFUSE] = glGetUniformLocation(shader.id, "texture0"); - - // NOTE: We could also use below function but in case DEFAULT_ATTRIB_* points are - // changed for external custom shaders, we just use direct bindings above - //SetShaderDefaultLocations(&shader); - } - else TraceLog(LOG_WARNING, "[SHDR ID %i] Default shader could not be loaded", shader.id); - - return shader; -} - -// Get location handlers to for shader attributes and uniforms -// NOTE: If any location is not found, loc point becomes -1 -static void SetShaderDefaultLocations(Shader *shader) -{ - // NOTE: 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 - - // Get handles to GLSL input attibute locations - shader->locs[LOC_VERTEX_POSITION] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME); - shader->locs[LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME); - shader->locs[LOC_VERTEX_TEXCOORD02] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME); - shader->locs[LOC_VERTEX_NORMAL] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME); - shader->locs[LOC_VERTEX_TANGENT] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME); - shader->locs[LOC_VERTEX_COLOR] = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME); - - // Get handles to GLSL uniform locations (vertex shader) - shader->locs[LOC_MATRIX_MVP] = glGetUniformLocation(shader->id, "mvp"); - shader->locs[LOC_MATRIX_PROJECTION] = glGetUniformLocation(shader->id, "projection"); - shader->locs[LOC_MATRIX_VIEW] = glGetUniformLocation(shader->id, "view"); - - // Get handles to GLSL uniform locations (fragment shader) - shader->locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader->id, "colDiffuse"); - shader->locs[LOC_MAP_DIFFUSE] = glGetUniformLocation(shader->id, "texture0"); - shader->locs[LOC_MAP_SPECULAR] = glGetUniformLocation(shader->id, "texture1"); - shader->locs[LOC_MAP_NORMAL] = glGetUniformLocation(shader->id, "texture2"); -} - -// Unload default shader -static void UnloadShaderDefault(void) -{ - glUseProgram(0); - - glDetachShader(defaultShader.id, defaultVShaderId); - glDetachShader(defaultShader.id, defaultFShaderId); - glDeleteShader(defaultVShaderId); - glDeleteShader(defaultFShaderId); - - glDeleteProgram(defaultShader.id); -} - -// Load default internal buffers (lines, triangles, quads) -static void LoadBuffersDefault(void) -{ - // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads) - //-------------------------------------------------------------------------------------------- - - // Lines - Initialize arrays (vertex position and color data) - lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line - lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line - lines.texcoords = NULL; - lines.indices = NULL; - - for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0f; - for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0; - - lines.vCounter = 0; - lines.cCounter = 0; - lines.tcCounter = 0; - - // Triangles - Initialize arrays (vertex position and color data) - triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle - triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle - triangles.texcoords = NULL; - triangles.indices = NULL; - - for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0f; - for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0; - - triangles.vCounter = 0; - triangles.cCounter = 0; - triangles.tcCounter = 0; - - // Quads - Initialize arrays (vertex position, texcoord, color data and indexes) - quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad - quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad - quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad -#if defined(GRAPHICS_API_OPENGL_33) - quads.indices = (unsigned int *)malloc(sizeof(unsigned int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) -#elif defined(GRAPHICS_API_OPENGL_ES2) - quads.indices = (unsigned short *)malloc(sizeof(unsigned short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) -#endif - - for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f; - for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0f; - for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0; - - int k = 0; - - // Indices can be initialized right now - for (int i = 0; i < (6*MAX_QUADS_BATCH); i+=6) - { - quads.indices[i] = 4*k; - quads.indices[i+1] = 4*k+1; - quads.indices[i+2] = 4*k+2; - quads.indices[i+3] = 4*k; - quads.indices[i+4] = 4*k+2; - quads.indices[i+5] = 4*k+3; - - k++; - } - - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; - - TraceLog(LOG_INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)"); - //-------------------------------------------------------------------------------------------- - - // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads) - // NOTE: Default buffers are linked to use currentShader (defaultShader) - //-------------------------------------------------------------------------------------------- - - // Upload and link lines vertex buffers - if (vaoSupported) - { - // Initialize Lines VAO - glGenVertexArrays(1, &lines.vaoId); - glBindVertexArray(lines.vaoId); - } - - // Lines - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(2, &lines.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(2, &lines.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", lines.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", lines.vboId[0], lines.vboId[1]); - - // Upload and link triangles vertex buffers - if (vaoSupported) - { - // Initialize Triangles VAO - glGenVertexArrays(1, &triangles.vaoId); - glBindVertexArray(triangles.vaoId); - } - - // Triangles - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(1, &triangles.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &triangles.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", triangles.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (triangles)", triangles.vboId[0], triangles.vboId[1]); - - // Upload and link quads vertex buffers - if (vaoSupported) - { - // Initialize Quads VAO - glGenVertexArrays(1, &quads.vaoId); - glBindVertexArray(quads.vaoId); - } - - // Quads - Vertex buffers binding and attributes enable - // Vertex position buffer (shader-location = 0) - glGenBuffers(1, &quads.vboId[0]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - - // Vertex texcoord buffer (shader-location = 1) - glGenBuffers(1, &quads.vboId[1]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_TEXCOORD01]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - - // Vertex color buffer (shader-location = 3) - glGenBuffers(1, &quads.vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - // Fill index buffer - glGenBuffers(1, &quads.vboId[3]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); -#if defined(GRAPHICS_API_OPENGL_33) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); -#elif defined(GRAPHICS_API_OPENGL_ES2) - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); -#endif - - if (vaoSupported) TraceLog(LOG_INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", quads.vaoId); - else TraceLog(LOG_INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quads.vboId[0], quads.vboId[1], quads.vboId[2], quads.vboId[3]); - - // Unbind the current VAO - if (vaoSupported) glBindVertexArray(0); - //-------------------------------------------------------------------------------------------- -} - -// Update default internal buffers (VAOs/VBOs) with vertex array data -// 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 (change flag required) -static void UpdateBuffersDefault(void) -{ - // Update lines vertex buffers - if (lines.vCounter > 0) - { - // Activate Lines VAO - if (vaoSupported) glBindVertexArray(lines.vaoId); - - // Lines - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*lines.vCounter, lines.vertices); // target - offset (in bytes) - size (in bytes) - data pointer - - // Lines - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*lines.cCounter, lines.colors); - } - - // Update triangles vertex buffers - if (triangles.vCounter > 0) - { - // Activate Triangles VAO - if (vaoSupported) glBindVertexArray(triangles.vaoId); - - // Triangles - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*triangles.vCounter, triangles.vertices); - - // Triangles - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*triangles.cCounter, triangles.colors); - } - - // Update quads vertex buffers - if (quads.vCounter > 0) - { - // Activate Quads VAO - if (vaoSupported) glBindVertexArray(quads.vaoId); - - // Quads - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices); - - // Quads - texture coordinates buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords); - - // Quads - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*quads.vCounter, quads.colors); - - // Another option would be using buffer mapping... - //quads.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - // Now we can modify vertices - //glUnmapBuffer(GL_ARRAY_BUFFER); - } - //-------------------------------------------------------------- - - // Unbind the current VAO - if (vaoSupported) glBindVertexArray(0); -} - -// Draw default internal buffers vertex data -// NOTE: We draw in this order: lines, triangles, quads -static void DrawBuffersDefault(void) -{ - Matrix matProjection = projection; - Matrix matModelView = modelview; - - int eyesCount = 1; -#if defined(SUPPORT_VR_SIMULATOR) - if (vrStereoRender) eyesCount = 2; -#endif - - for (int eye = 0; eye < eyesCount; eye++) - { - #if defined(SUPPORT_VR_SIMULATOR) - if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); - #endif - - // Set current shader and upload current MVP matrix - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) - { - glUseProgram(currentShader.id); - - // Create modelview-projection matrix - Matrix matMVP = MatrixMultiply(modelview, projection); - - glUniformMatrix4fv(currentShader.locs[LOC_MATRIX_MVP], 1, false, MatrixToFloat(matMVP)); - glUniform4f(currentShader.locs[LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0); - - // NOTE: Additional map textures not considered for default buffers drawing - } - - // Draw lines buffers - if (lines.vCounter > 0) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(lines.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - } - - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - // Draw triangles buffers - if (triangles.vCounter > 0) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(triangles.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - } - - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - // Draw quads buffers - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; - - if (vaoSupported) - { - glBindVertexArray(quads.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_POSITION]); - - // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_TEXCOORD01]); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - glVertexAttribPointer(currentShader.locs[LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.locs[LOC_VERTEX_COLOR]); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); - } - - //TraceLog(LOG_DEBUG, "Draws required per frame: %i", drawsCounter); - - for (int i = 0; i < drawsCounter; i++) - { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads*6 index by Quad - - //TraceLog(LOG_DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - - // 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 - #if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); - #elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); - #endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(LOG_INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! - - indicesOffset += draws[i].vertexCount/4*6; - } - - if (!vaoSupported) - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures - } - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO - - glUseProgram(0); // Unbind shader program - } - - // Reset draws counter - drawsCounter = 1; - draws[0].textureId = whiteTexture; - draws[0].vertexCount = 0; - - // Reset vertex counters for next frame - lines.vCounter = 0; - lines.cCounter = 0; - triangles.vCounter = 0; - triangles.cCounter = 0; - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; - - // Reset depth for next draw - currentDepth = -1.0f; - - // Restore projection/modelview matrices - projection = matProjection; - modelview = matModelView; -} - -// Unload default internal buffers vertex data from CPU and GPU -static void UnloadBuffersDefault(void) -{ - // Unbind everything - if (vaoSupported) glBindVertexArray(0); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(3); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - // Delete VBOs from GPU (VRAM) - glDeleteBuffers(1, &lines.vboId[0]); - glDeleteBuffers(1, &lines.vboId[1]); - glDeleteBuffers(1, &triangles.vboId[0]); - glDeleteBuffers(1, &triangles.vboId[1]); - glDeleteBuffers(1, &quads.vboId[0]); - glDeleteBuffers(1, &quads.vboId[1]); - glDeleteBuffers(1, &quads.vboId[2]); - glDeleteBuffers(1, &quads.vboId[3]); - - if (vaoSupported) - { - // Delete VAOs from GPU (VRAM) - glDeleteVertexArrays(1, &lines.vaoId); - glDeleteVertexArrays(1, &triangles.vaoId); - glDeleteVertexArrays(1, &quads.vaoId); - } - - // Free vertex arrays memory from CPU (RAM) - free(lines.vertices); - free(lines.colors); - - free(triangles.vertices); - free(triangles.colors); - - free(quads.vertices); - free(quads.texcoords); - free(quads.colors); - free(quads.indices); -} - -// Renders a 1x1 XY quad in NDC -static void GenDrawQuad(void) -{ - unsigned int quadVAO = 0; - unsigned int quadVBO = 0; - - float vertices[] = { - // Positions // Texture Coords - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - }; - - // Set up plane VAO - glGenVertexArrays(1, &quadVAO); - glGenBuffers(1, &quadVBO); - glBindVertexArray(quadVAO); - - // Fill buffer - glBindBuffer(GL_ARRAY_BUFFER, quadVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); - - // Link vertex attributes - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); - - // Draw quad - glBindVertexArray(quadVAO); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArray(0); - - glDeleteBuffers(1, &quadVBO); - glDeleteVertexArrays(1, &quadVAO); -} - -// Renders a 1x1 3D cube in NDC -static void GenDrawCube(void) -{ - unsigned int cubeVAO = 0; - unsigned int cubeVBO = 0; - - float vertices[] = { - -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, - -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, - -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f - }; - - // Set up cube VAO - glGenVertexArrays(1, &cubeVAO); - glGenBuffers(1, &cubeVBO); - - // Fill buffer - glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // Link vertex attributes - glBindVertexArray(cubeVAO); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - // Draw cube - glBindVertexArray(cubeVAO); - glDrawArrays(GL_TRIANGLES, 0, 36); - glBindVertexArray(0); - - glDeleteBuffers(1, &cubeVBO); - glDeleteVertexArrays(1, &cubeVAO); -} - -#if defined(SUPPORT_VR_SIMULATOR) -// Configure stereo rendering (including distortion shader) with HMD device parameters -// NOTE: It modifies the global variable: VrStereoConfig vrConfig -static void SetStereoConfig(VrDeviceInfo hmd) -{ - // Compute aspect ratio - float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution; - - // Compute lens parameters - float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize; - float leftLensCenter[2] = { 0.25f + lensShift, 0.5f }; - float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; - float leftScreenCenter[2] = { 0.25f, 0.5f }; - float rightScreenCenter[2] = { 0.75f, 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 = hmd.lensDistortionValues[0] + - hmd.lensDistortionValues[1]*lensRadiusSq + - hmd.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq + - hmd.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; - - TraceLog(LOG_DEBUG, "VR: Distortion Scale: %f", distortionScale); - - float normScreenWidth = 0.5f; - float normScreenHeight = 1.0f; - float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; - float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; - - TraceLog(LOG_DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); - TraceLog(LOG_DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); - TraceLog(LOG_DEBUG, "VR: Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]); - TraceLog(LOG_DEBUG, "VR: Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]); - -#if defined(SUPPORT_DISTORTION_SHADER) - // Update distortion shader with lens and distortion-scale parameters - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftScreenCenter"), leftScreenCenter, 2); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightScreenCenter"), rightScreenCenter, 2); - - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scale"), scale, 2); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, 4); - SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, 4); -#endif - - // Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance) - // ...but with lens distortion it is increased (see Oculus SDK Documentation) - //float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance); // Really need distortionScale? - float fovy = 2.0f*(float)atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance); - - // Compute camera projection matrices - float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] - Matrix proj = MatrixPerspective(fovy, aspect, 0.01, 1000.0); - vrConfig.eyesProjection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); - vrConfig.eyesProjection[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. - vrConfig.eyesViewOffset[0] = MatrixTranslate(-hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); - vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); - - // Compute eyes Viewports - vrConfig.eyesViewport[0] = (Rectangle){ 0, 0, hmd.hResolution/2, hmd.vResolution }; - vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution }; -} - -// Set internal projection and modelview matrix depending on eyes tracking data -static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) -{ - Matrix eyeProjection = matProjection; - Matrix eyeModelView = matModelView; - - // Setup viewport and projection/modelview matrices using tracking data - rlViewport(eye*screenWidth/2, 0, screenWidth/2, screenHeight); - - // Apply view offset to modelview matrix - eyeModelView = MatrixMultiply(matModelView, vrConfig.eyesViewOffset[eye]); - - // Set current eye projection matrix - eyeProjection = vrConfig.eyesProjection[eye]; - - SetMatrixModelview(eyeModelView); - SetMatrixProjection(eyeProjection); -} -#endif // defined(SUPPORT_VR_SIMULATOR) - -#endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - -// Get OpenGL internal formats and data type from raylib PixelFormat -static void GetGlFormats(int format, int *glInternalFormat, int *glFormat, int *glType) -{ - *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 UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; - #if !defined(GRAPHICS_API_OPENGL_11) - case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float - #endif - #elif defined(GRAPHICS_API_OPENGL_33) - case UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; - case UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; - case UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; - case UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; - case UNCOMPRESSED_R32: if (texFloatSupported) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; - case UNCOMPRESSED_R32G32B32: if (texFloatSupported) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; - case UNCOMPRESSED_R32G32B32A32: if (texFloatSupported) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; - #endif - #if !defined(GRAPHICS_API_OPENGL_11) - case COMPRESSED_DXT1_RGB: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; - case COMPRESSED_DXT1_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; - case COMPRESSED_DXT3_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case COMPRESSED_DXT5_RGBA: if (texCompDXTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case COMPRESSED_ETC1_RGB: if (texCompETC1Supported) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 - case COMPRESSED_ETC2_RGB: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case COMPRESSED_ETC2_EAC_RGBA: if (texCompETC2Supported) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 - case COMPRESSED_PVRT_RGB: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case COMPRESSED_PVRT_RGBA: if (texCompPVRTSupported) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU - case COMPRESSED_ASTC_4x4_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - case COMPRESSED_ASTC_8x8_RGBA: if (texCompASTCSupported) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 - #endif - default: TraceLog(LOG_WARNING, "Texture format not supported"); break; - } -} - -#if defined(GRAPHICS_API_OPENGL_11) -// Mipmaps data is generated after image data -static int GenerateMipmaps(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)) - { - if (width != 1) width /= 2; - if (height != 1) height /= 2; - - TraceLog(LOG_DEBUG, "Next mipmap size: %i x %i", width, height); - - mipmapCount++; - - size += (width*height*4); // Add mipmap size (in bytes) - } - - TraceLog(LOG_DEBUG, "Total mipmaps required: %i", mipmapCount); - TraceLog(LOG_DEBUG, "Total size of data required: %i", size); - - unsigned char *temp = realloc(data, size); - - if (temp != NULL) data = temp; - else TraceLog(LOG_WARNING, "Mipmaps required memory could not be allocated"); - - width = baseWidth; - height = baseHeight; - size = (width*height*4); - - // Generate mipmaps - // NOTE: Every mipmap data is stored after data - Color *image = (Color *)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++; - } - - TraceLog(LOG_DEBUG, "Mipmap base (%ix%i)", width, height); - - for (int mip = 1; mip < mipmapCount; mip++) - { - mipmap = GenNextMipmap(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++; - } - - free(image); - - image = mipmap; - mipmap = NULL; - } - - free(mipmap); // free mipmap data - - return mipmapCount; -} - -// Manual mipmap generation (basic scaling algorithm) -static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) -{ - int x2, y2; - Color prow, pcol; - - int width = srcWidth/2; - int height = srcHeight/2; - - Color *mipmap = (Color *)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; - } - } - - TraceLog(LOG_DEBUG, "Mipmap generated successfully (%ix%i)", width, height); - - return mipmap; -} -#endif - -#if defined(RLGL_STANDALONE) -// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -void TraceLog(int msgType, const char *text, ...) -{ - va_list args; - va_start(args, text); - - switch (msgType) - { - case LOG_INFO: fprintf(stdout, "INFO: "); break; - case LOG_ERROR: fprintf(stdout, "ERROR: "); break; - case LOG_WARNING: fprintf(stdout, "WARNING: "); break; - case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break; - default: break; - } - - vfprintf(stdout, text, args); - fprintf(stdout, "\n"); - - va_end(args); - - if (msgType == LOG_ERROR) exit(1); -} -#endif diff --git a/raylib/rlgl.go b/raylib/rlgl.go new file mode 100644 index 0000000..cc24f30 --- /dev/null +++ b/raylib/rlgl.go @@ -0,0 +1,177 @@ +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 + + 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) +} + +// 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 +} + +// RenderBatch type +type RenderBatch struct { + BufferCount int32 + CurrentBuffer int32 + VertexBuffer *VertexBuffer + Draws *DrawCall + DrawCounter int32 + DurrentDepth float32 +} + +// OpenGL version +const ( + Opengl11 int32 = 1 + Opengl21 int32 = 2 + Opengl33 int32 = 3 + Opengl43 int32 = 4 + OpenglEs20 int32 = 5 +) + +// GlVersion type +type GlVersion = int32 + +// Shader attribute data types +const ( + ShaderAttribFloat int32 = 0 + ShaderAttribVec2 int32 = 1 + ShaderAttribVec3 int32 = 2 + ShaderAttribVec4 int32 = 3 +) + +// ShaderAttributeDataType type +type ShaderAttributeDataType = int32 + +// 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 +) + +// FramebufferAttachType type +type FramebufferAttachType = int32 + +// 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 +) + +// FramebufferAttachTextureType type +type FramebufferAttachTextureType = int32 diff --git a/raylib/rlgl.h b/raylib/rlgl.h index c071aca..c39d096 100644 --- a/raylib/rlgl.h +++ b/raylib/rlgl.h @@ -1,43 +1,94 @@ /********************************************************************************************** * -* rlgl - raylib OpenGL abstraction layer +* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API * -* 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...). +* 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...) * -* 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 auxiliar resources -* rlglDraw() - Process internal buffers and send required draw calls -* rlglClose() - De-initialize internal buffers data and other auxiliar resources +* 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() * * 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 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() tocheck 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 RLGL_STANDALONE -* Use rlgl as standalone library (no raylib dependency) +* #define RLGL_RENDER_TEXTURES_HINT +* Enable framebuffer objects (fbo) support (enabled by default) +* Some GPUs could not support them despite the OpenGL version * -* #define SUPPORT_VR_SIMULATOR -* Support VR simulation functionality (stereo rendering) +* #define RLGL_SHOW_GL_DETAILS_INFO +* Show OpenGL extensions and capabilities detailed logs on init * -* #define SUPPORT_DISTORTION_SHADER -* Include stereo rendering distortion shader (shader_distortion.h) +* #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) * * DEPENDENCIES: -* raymath - 3D math functionality (Vector3, Matrix, Quaternion) -* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) +* - OpenGL libraries (depending on platform and OpenGL version selected) +* - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core) * * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-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. @@ -59,17 +110,52 @@ #ifndef RLGL_H #define RLGL_H -#if defined(RLGL_STANDALONE) - #define RAYMATH_STANDALONE -#else - #include "raylib.h" // Required for: Model, Shader, Texture2D, TraceLog() +#define RLGL_VERSION "5.0" + +// 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) #endif -#include "raymath.h" // Required for: Vector3, Matrix +// 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 // 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_ES2) - #define GRAPHICS_API_OPENGL_11 +#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) + #define GRAPHICS_API_OPENGL_33 #endif // Security check in case multiple GRAPHICS_API_OPENGL_* defined @@ -80,420 +166,5101 @@ #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 #endif +// OpenGL 2.1 uses most of OpenGL 3.3 Core functionality +// WARNING: Specific parts are checked with #if defines #if defined(GRAPHICS_API_OPENGL_21) #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 + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - // NOTE: This is the maximum amount of lines, triangles and quads per frame, be careful! - #define MAX_LINES_BATCH 8192 - #define MAX_TRIANGLES_BATCH 4096 - #define MAX_QUADS_BATCH 8192 -#elif defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: 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 MAX_LINES_BATCH 1024 // Critical for wire shapes (sphere) - #define MAX_TRIANGLES_BATCH 2048 // Critical for some shapes (sphere) - #define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad + +// Default internal render batch elements limits +#ifndef RL_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 + #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 + #endif +#endif +#ifndef RL_DEFAULT_BATCH_BUFFERS + #define RL_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) +#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()) +#endif + +// Internal Matrix stack +#ifndef RL_MAX_MATRIX_STACK_SIZE + #define RL_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 +#endif + +// Projection matrix culling +#ifndef RL_CULL_DISTANCE_NEAR + #define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance +#endif +#ifndef RL_CULL_DISTANCE_FAR + #define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance #endif // Texture parameters (equivalent to OpenGL defines) -#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S -#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T -#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER -#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER -#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier) +#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S +#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T +#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER +#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER -#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST -#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR -#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST -#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR -#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST -#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR +#define RL_TEXTURE_FILTER_NEAREST 0x2600 // GL_NEAREST +#define RL_TEXTURE_FILTER_LINEAR 0x2601 // GL_LINEAR +#define RL_TEXTURE_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST +#define RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR +#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_WRAP_REPEAT 0x2901 // GL_REPEAT -#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE -#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT +#define RL_TEXTURE_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_TEXTURE_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_TEXTURE_WRAP_MIRROR_REPEAT 0x8370 // GL_MIRRORED_REPEAT +#define RL_TEXTURE_WRAP_MIRROR_CLAMP 0x8742 // GL_MIRROR_CLAMP_EXT // Matrix modes (equivalent to OpenGL) -#define RL_MODELVIEW 0x1700 // GL_MODELVIEW -#define RL_PROJECTION 0x1701 // GL_PROJECTION -#define RL_TEXTURE 0x1702 // GL_TEXTURE +#define RL_MODELVIEW 0x1700 // GL_MODELVIEW +#define RL_PROJECTION 0x1701 // GL_PROJECTION +#define RL_TEXTURE 0x1702 // GL_TEXTURE // Primitive assembly draw modes -#define RL_LINES 0x0001 // GL_LINES -#define RL_TRIANGLES 0x0004 // GL_TRIANGLES -#define RL_QUADS 0x0007 // GL_QUADS +#define RL_LINES 0x0001 // GL_LINES +#define RL_TRIANGLES 0x0004 // GL_TRIANGLES +#define RL_QUADS 0x0007 // GL_QUADS + +// GL equivalent data types +#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 //---------------------------------------------------------------------------------- -typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; - -typedef unsigned char byte; - -#if defined(RLGL_STANDALONE) - #ifndef __cplusplus +#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 { false, true } bool; - #endif - - // 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 { - int x; - int y; - int width; - int height; - } Rectangle; - - // Texture2D 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; - - // RenderTexture2D type, for texture rendering - typedef struct RenderTexture2D { - unsigned int id; // Render texture (fbo) id - Texture2D texture; // Color buffer attachment texture - Texture2D depth; // Depth buffer attachment texture - } RenderTexture2D; - - // Vertex data definning a mesh - typedef struct Mesh { - int vertexCount; // number of vertices stored in arrays - int triangleCount; // number of triangles stored (indexed or not) - 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 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 int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) - } Mesh; - - // Shader and material limits - #define MAX_SHADER_LOCATIONS 32 - #define MAX_MATERIAL_MAPS 12 - - // Shader type (generic) - typedef struct Shader { - unsigned int id; // Shader program id - int locs[MAX_SHADER_LOCATIONS]; // Shader locations array - } Shader; - - // Material texture map - typedef struct MaterialMap { - Texture2D texture; // Material map texture - Color color; // Material map color - float value; // Material map value - } MaterialMap; - - // Material type (generic) - typedef struct Material { - Shader shader; // Material shader - MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps - float *params; // Material generic parameters (if required) - } Material; - - // Camera type, defines a camera position/orientation in 3d space - typedef struct Camera { - 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) - } Camera; - - // Head-Mounted-Display device parameters - typedef struct VrDeviceInfo { - int hResolution; // HMD horizontal resolution in pixels - int vResolution; // HMD vertical resolution in pixels - float hScreenSize; // HMD horizontal size in meters - float vScreenSize; // HMD vertical size in meters - float vScreenCenter; // HMD screen center in meters - float eyeToScreenDistance; // HMD distance between eye and display in meters - float lensSeparationDistance; // HMD lens separation distance in meters - float interpupillaryDistance; // HMD IPD (distance between pupils) in meters - float lensDistortionValues[4]; // HMD lens distortion constant parameters - float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters - } VrDeviceInfo; - - // TraceLog message types - typedef enum { - LOG_INFO = 0, - LOG_ERROR, - LOG_WARNING, - LOG_DEBUG, - LOG_OTHER - } TraceLogType; - - // Texture formats (support depends on OpenGL version) - typedef enum { - UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) - UNCOMPRESSED_GRAY_ALPHA, - UNCOMPRESSED_R5G6B5, // 16 bpp - UNCOMPRESSED_R8G8B8, // 24 bpp - UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - COMPRESSED_DXT3_RGBA, // 8 bpp - COMPRESSED_DXT5_RGBA, // 8 bpp - COMPRESSED_ETC1_RGB, // 4 bpp - COMPRESSED_ETC2_RGB, // 4 bpp - COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - COMPRESSED_PVRT_RGB, // 4 bpp - COMPRESSED_PVRT_RGBA, // 4 bpp - COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - 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 { - FILTER_POINT = 0, // No filter, just pixel aproximation - FILTER_BILINEAR, // Linear filtering - FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) - FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x - FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x - FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x - } TextureFilterMode; - - // Texture parameters: wrap mode - typedef enum { - WRAP_REPEAT = 0, - WRAP_CLAMP, - WRAP_MIRROR - } TextureWrapMode; - - // Color blending modes (pre-defined) - typedef enum { - BLEND_ALPHA = 0, - BLEND_ADDITIVE, - BLEND_MULTIPLIED - } BlendMode; - - // Shader location point type - typedef enum { - LOC_VERTEX_POSITION = 0, - LOC_VERTEX_TEXCOORD01, - LOC_VERTEX_TEXCOORD02, - LOC_VERTEX_NORMAL, - LOC_VERTEX_TANGENT, - LOC_VERTEX_COLOR, - LOC_MATRIX_MVP, - LOC_MATRIX_MODEL, - LOC_MATRIX_VIEW, - LOC_MATRIX_PROJECTION, - LOC_VECTOR_VIEW, - LOC_COLOR_DIFFUSE, - LOC_COLOR_SPECULAR, - LOC_COLOR_AMBIENT, - LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE - LOC_MAP_METALNESS, // LOC_MAP_SPECULAR - LOC_MAP_NORMAL, - LOC_MAP_ROUGHNESS, - LOC_MAP_OCCLUSION, - LOC_MAP_EMISSION, - LOC_MAP_HEIGHT, - LOC_MAP_CUBEMAP, - LOC_MAP_IRRADIANCE, - LOC_MAP_PREFILTER, - LOC_MAP_BRDF - } ShaderLocationIndex; - - #define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO - #define LOC_MAP_SPECULAR LOC_MAP_METALNESS - - // Material map type - typedef enum { - MAP_ALBEDO = 0, // MAP_DIFFUSE - MAP_METALNESS = 1, // MAP_SPECULAR - MAP_NORMAL = 2, - MAP_ROUGHNESS = 3, - MAP_OCCLUSION, - MAP_EMISSION, - MAP_HEIGHT, - MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP - MAP_BRDF - } TexmapIndex; - - #define MAP_DIFFUSE MAP_ALBEDO - #define MAP_SPECULAR MAP_METALNESS - - // VR Head Mounted Display devices - typedef enum { - HMD_DEFAULT_DEVICE = 0, - HMD_OCULUS_RIFT_DK2, - HMD_OCULUS_RIFT_CV1, - HMD_OCULUS_GO, - HMD_VALVE_HTC_VIVE, - HMD_SONY_PSVR - } VrDevice; +typedef enum bool { false = 0, true = !false } bool; #endif -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions +#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 +// Dynamic vertex buffers (position + texcoords + colors + indices arrays) +typedef struct rlVertexBuffer { + int elementCount; // Number of elements in the buffer (QUADS) + + 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) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + 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; + +// 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 { + 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 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; + +// rlRenderBatch type +typedef struct rlRenderBatch { + int bufferCount; // 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 + + rlDrawCall *draws; // Draw calls array, depends on textureId + int drawCounter; // 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; + +// 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; + +// 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; + +// 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; + +// Face culling mode +typedef enum { + RL_CULL_FACE_FRONT = 0, + RL_CULL_FACE_BACK +} rlCullMode; + //------------------------------------------------------------------------------------ // Functions Declaration - Matrix operations //------------------------------------------------------------------------------------ -void rlMatrixMode(int mode); // Choose the current matrix to be transformed -void rlPushMatrix(void); // Push the current matrix to stack -void rlPopMatrix(void); // Pop lattest inserted matrix from stack -void rlLoadIdentity(void); // Reset current matrix to identity matrix -void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix -void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix -void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix -void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix -void rlFrustum(double left, double right, double bottom, double top, double near, double far); -void rlOrtho(double left, double right, double bottom, double top, double near, double far); -void rlViewport(int x, int y, int width, int height); // Set the viewport area + +#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 +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 //------------------------------------------------------------------------------------ -void rlBegin(int mode); // Initialize drawing mode (how to organize vertex) -void rlEnd(void); // Finish vertex providing -void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int -void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float -void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float -void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float -void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float -void rlColor4ub(byte r, byte g, byte b, byte a); // Define one vertex (color) - 4 byte -void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float -void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 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 //------------------------------------------------------------------------------------ -// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2) -// NOTE: This functions are used to completely abstract raylib code from OpenGL layer +// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2) +// NOTE: This functions are used to completely abstract raylib code from OpenGL layer, +// some of them are direct wrappers over OpenGL calls, some others are custom //------------------------------------------------------------------------------------ -void rlEnableTexture(unsigned int id); // Enable texture usage -void rlDisableTexture(void); // Disable texture usage -void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) -void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo) -void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer -void rlEnableDepthTest(void); // Enable depth test -void rlDisableDepthTest(void); // Disable depth test -void rlEnableWireMode(void); // Enable wire mode -void rlDisableWireMode(void); // Disable wire mode -void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU -void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU -void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU -void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory -void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory -void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color -void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth) + +// Vertex buffers state +RLAPI bool rlEnableVertexArray(unsigned int vaoId); // Enable vertex array (VAO, if supported) +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 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 +#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 +#endif + +// Textures state +RLAPI void rlActiveTextureSlot(int slot); // Select and active a texture slot +RLAPI void rlEnableTexture(unsigned int id); // Enable texture +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 +RLAPI void rlDisableShader(void); // Disable shader program + +// 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 +RLAPI float rlGetLineWidth(void); // Get the line drawing width +RLAPI void rlEnableSmoothLines(void); // Enable line aliasing +RLAPI void rlDisableSmoothLines(void); // Disable line aliasing +RLAPI void rlEnableStereoRender(void); // Enable stereo rendering +RLAPI void rlDisableStereoRender(void); // Disable stereo rendering +RLAPI bool rlIsStereoRenderEnabled(void); // Check if stereo render is enabled + +RLAPI void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Clear color buffer with color +RLAPI void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth) +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 //------------------------------------------------------------------------------------ -void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) -void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures) -void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads) +// 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 -int rlGetVersion(void); // Returns current OpenGL version -void rlSetDebugMarker(const char *text); // Set debug marker for analysis -void rlLoadExtensions(void *loader); // Load OpenGL extensions -Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates +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 -// Textures data management -unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU -void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data -void rlUnloadTexture(unsigned int id); -void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture -void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data -unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) -RenderTexture2D rlLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) +// 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 -// Vertex data management -void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids -void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer) -void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform -void rlUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU +RLAPI void rlSetTexture(unsigned int id); // Set current texture for render batch and check buffers limits -// NOTE: There is a set of shader related functions that are available to end user, -// to avoid creating function wrappers through core module, they have been directly declared in raylib.h +//------------------------------------------------------------------------------------------------------------------------ -#if defined(RLGL_STANDALONE) -//------------------------------------------------------------------------------------ -// Shaders System Functions (Module: rlgl) -// NOTE: This functions are useless when using OpenGL 1.1 -//------------------------------------------------------------------------------------ -Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -void UnloadShader(Shader shader); // Unload a custom shader from memory +// 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 -Shader GetShaderDefault(void); // Get default shader -Texture2D GetTextureDefault(void); // Get default texture +// 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 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 unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) -// Shader configuration functions -int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float) -void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int) -void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) -void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) -Matrix GetMatrixModelview(); // Get internal modelview matrix +// 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 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 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) -// Texture maps generation (PBR) -// NOTE: Required shaders should be provided -Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture -Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data -Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data -Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data +// 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) -// Shading and blending -void BeginShaderMode(Shader shader); // Begin custom shader drawing -void EndShaderMode(void); // End custom shader drawing (use default shader) -void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) -void EndBlendMode(void); // End blending mode (reset to default: alpha blending) +// 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 -// VR simulator functionality -VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices -void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters -void CloseVrSimulator(void); // Close VR simulator for current device -void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) -void BeginVrDrawing(void); // Begin VR stereo rendering -void EndVrDrawing(void); // End VR stereo rendering +// Buffer management +RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly); // Bind image texture -void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -#endif +// Matrix state management +RLAPI Matrix rlGetMatrixModelview(void); // Get internal modelview matrix +RLAPI Matrix rlGetMatrixProjection(void); // Get internal projection matrix +RLAPI Matrix rlGetMatrixTransform(void); // Get internal accumulated transform matrix +RLAPI Matrix rlGetMatrixProjectionStereo(int eye); // Get internal projection matrix for stereo render (selected eye) +RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye); // Get internal view offset matrix for stereo render (selected eye) +RLAPI void rlSetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +RLAPI void rlSetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +RLAPI void rlSetMatrixProjectionStereo(Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering +RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering -#ifdef __cplusplus +// 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 #endif // RLGL_H + +/*********************************************************************************** +* +* RLGL IMPLEMENTATION +* +************************************************************************************/ + +#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 +#endif + +#if defined(GRAPHICS_API_OPENGL_11) + #if defined(__APPLE__) + #include // OpenGL 1.1 library for OSX + #include // OpenGL extensions library + #else + // APIENTRY for OpenGL function pointer declarations is required + #if !defined(APIENTRY) + #if defined(_WIN32) + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #endif + // WINGDIAPI definition. Some Windows OpenGL headers need it + #if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) + #endif + + #include // OpenGL 1.1 library + #endif +#endif + +#if defined(GRAPHICS_API_OPENGL_33) + #define GLAD_MALLOC RL_MALLOC + #define GLAD_FREE RL_FREE + + #define GLAD_GL_IMPLEMENTATION + #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers +#endif + +#if defined(GRAPHICS_API_OPENGL_ES3) + #include // OpenGL ES 3.0 library + #define GL_GLEXT_PROTOTYPES + #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) + 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 + +#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT + #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif +#ifndef GL_ETC1_RGB8_OES + #define GL_ETC1_RGB8_OES 0x8D64 +#endif +#ifndef GL_COMPRESSED_RGB8_ETC2 + #define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC + #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif +#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#endif +#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#endif +#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR + #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 +#endif +#ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR + #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 +#endif + +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #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 + #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#endif + +#if defined(GRAPHICS_API_OPENGL_21) + #define GL_LUMINANCE 0x1909 + #define GL_LUMINANCE_ALPHA 0x190A +#endif + +#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 +#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 +#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 +#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 +#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 +#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 +#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) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#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 + + 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 + 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 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) + + 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 + + } 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 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) + bool texCompPVRT; // PVR texture compression support (GL_IMG_texture_compression_pvrtc) + 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 + + } ExtSupported; // Extensions supported flags +} rlglData; + +typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions loader signature (same as GLADloadproc) + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +//---------------------------------------------------------------------------------- +// 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) +// NOTE: VAO functionality is exposed through extensions (OES) +static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL; +static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL; +static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL; + +// NOTE: Instancing functionality could also be available through extension +static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL; +static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL; +static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; +#endif + +//---------------------------------------------------------------------------------- +// 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 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +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 +//---------------------------------------------------------------------------------- + +#if defined(GRAPHICS_API_OPENGL_11) +// Fallback to OpenGL 1.1 function calls +//--------------------------------------- +void rlMatrixMode(int mode) +{ + switch (mode) + { + case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break; + case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break; + case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break; + default: break; + } +} + +void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) +{ + glFrustum(left, right, bottom, top, znear, zfar); +} + +void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) +{ + glOrtho(left, right, bottom, top, znear, zfar); +} + +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 rlScalef(float x, float y, float z) { glScalef(x, y, z); } +void rlMultMatrixf(const float *matf) { glMultMatrixf(matf); } +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Choose the current matrix to be transformed +void rlMatrixMode(int mode) +{ + if (mode == RL_PROJECTION) RLGL.State.currentMatrix = &RLGL.State.projection; + else if (mode == RL_MODELVIEW) RLGL.State.currentMatrix = &RLGL.State.modelview; + //else if (mode == RL_TEXTURE) // Not supported + + RLGL.State.currentMatrixMode = 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.currentMatrixMode == RL_MODELVIEW) + { + RLGL.State.transformRequired = true; + RLGL.State.currentMatrix = &RLGL.State.transform; + } + + RLGL.State.stack[RLGL.State.stackCounter] = *RLGL.State.currentMatrix; + RLGL.State.stackCounter++; +} + +// Pop lattest inserted matrix from RLGL.State.stack +void rlPopMatrix(void) +{ + if (RLGL.State.stackCounter > 0) + { + Matrix mat = RLGL.State.stack[RLGL.State.stackCounter - 1]; + *RLGL.State.currentMatrix = mat; + RLGL.State.stackCounter--; + } + + if ((RLGL.State.stackCounter == 0) && (RLGL.State.currentMatrixMode == RL_MODELVIEW)) + { + RLGL.State.currentMatrix = &RLGL.State.modelview; + RLGL.State.transformRequired = false; + } +} + +// Reset current matrix to identity matrix +void rlLoadIdentity(void) +{ + *RLGL.State.currentMatrix = rlMatrixIdentity(); +} + +// 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 + }; + + // NOTE: We transpose matrix with multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(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) +{ + Matrix matRotation = rlMatrixIdentity(); + + // 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; + + // NOTE: We transpose matrix with multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(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 + }; + + // NOTE: We transpose matrix with multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); +} + +// Multiply the current matrix by another matrix +void rlMultMatrixf(const float *matf) +{ + // Matrix creation from array + Matrix mat = { matf[0], matf[4], matf[8], matf[12], + matf[1], matf[5], matf[9], matf[13], + matf[2], matf[6], matf[10], matf[14], + matf[3], matf[7], matf[11], matf[15] }; + + *RLGL.State.currentMatrix = rlMatrixMultiply(mat, *RLGL.State.currentMatrix); +} + +// 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 }; + + 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); +} + +// 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 }; + + 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); +} +#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 +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_11) +// Fallback to OpenGL 1.1 function calls +//--------------------------------------- +void rlBegin(int mode) +{ + switch (mode) + { + case RL_LINES: glBegin(GL_LINES); break; + case RL_TRIANGLES: glBegin(GL_TRIANGLES); break; + case RL_QUADS: glBegin(GL_QUADS); break; + default: break; + } +} + +void rlEnd(void) { 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); } +void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); } +void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); } +void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glColor4ub(r, g, b, a); } +void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); } +void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); } +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Initialize drawing mode (how to organize vertex) +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->drawCounter - 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 (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + { + RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; + RLGL.currentBatch->drawCounter++; + } + } + + if (RLGL.currentBatch->drawCounter >= RL_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; + } +} + +// Finish vertex providing +void rlEnd(void) +{ + // 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); +} + +// 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; + + // Transform provided vector if required + if (RLGL.State.transformRequired) + { + 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; + } + + // 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++; +} + +// Define one vertex (position) +void rlVertex2f(float x, float y) +{ + rlVertex3f(x, y, RLGL.currentBatch->currentDepth); +} + +// Define one vertex (position) +void rlVertex2i(int x, int y) +{ + rlVertex3f((float)x, (float)y, RLGL.currentBatch->currentDepth); +} + +// Define one vertex (texture coordinate) +// NOTE: Texture coordinates are limited to QUADS only +void rlTexCoord2f(float x, float y) +{ + RLGL.State.texcoordx = x; + RLGL.State.texcoordy = y; +} + +// 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; +} + +// 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; +} + +// Define one vertex (color) +void rlColor4f(float r, float g, float b, float a) +{ + rlColor4ub((unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), (unsigned char)(a*255)); +} + +// Define one vertex (color) +void rlColor3f(float x, float y, float z) +{ + rlColor4ub((unsigned char)(x*255), (unsigned char)(y*255), (unsigned char)(z*255), 255); +} + +#endif + +//-------------------------------------------------------------------------------------- +// Module Functions Definition - OpenGL style functions (common to 1.1, 3.3+, ES2) +//-------------------------------------------------------------------------------------- + +// Set current texture to use +void rlSetTexture(unsigned int id) +{ + if (id == 0) + { +#if defined(GRAPHICS_API_OPENGL_11) + 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) + { + rlDrawRenderBatch(RLGL.currentBatch); + } +#endif + } + else + { +#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->drawCounter - 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 (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + { + RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; + + RLGL.currentBatch->drawCounter++; + } + } + + if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); + + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = id; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0; + } +#endif + } +} + +// Select and active a texture slot +void rlActiveTextureSlot(int slot) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glActiveTexture(GL_TEXTURE0 + slot); +#endif +} + +// Enable texture +void rlEnableTexture(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glEnable(GL_TEXTURE_2D); +#endif + glBindTexture(GL_TEXTURE_2D, id); +} + +// Disable texture +void rlDisableTexture(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glDisable(GL_TEXTURE_2D); +#endif + glBindTexture(GL_TEXTURE_2D, 0); +} + +// Enable texture cubemap +void rlEnableTextureCubemap(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_CUBE_MAP, id); +#endif +} + +// Disable texture cubemap +void rlDisableTextureCubemap(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif +} + +// Set texture parameters (wrap mode/filter mode) +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: + case RL_TEXTURE_WRAP_T: + { + if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) + { +#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)"); +#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; + case RL_TEXTURE_FILTER_ANISOTROPIC: + { +#if !defined(GRAPHICS_API_OPENGL_11) + 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); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + } + else TRACELOG(RL_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) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + glUseProgram(id); +#endif +} + +// Disable shader program +void rlDisableShader(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + glUseProgram(0); +#endif +} + +// 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) + 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) + 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); } + +// Disable depth test +void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); } + +// Enable depth write +void rlEnableDepthMask(void) { glDepthMask(GL_TRUE); } + +// Disable depth write +void rlDisableDepthMask(void) { glDepthMask(GL_FALSE); } + +// Enable backface culling +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); } + +// Disable scissor test +void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); } + +// Scissor test +void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); } + +// Enable wire mode +void rlEnableWireMode(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_LINE); +#endif +} + +// Disable wire mode +void rlDisableWireMode(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 +} + +// 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); } + +// Get the line drawing width +float rlGetLineWidth(void) +{ + float width = 0; + glGetFloatv(GL_LINE_WIDTH, &width); + return width; +} + +// Enable line aliasing +void rlEnableSmoothLines(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11) + glEnable(GL_LINE_SMOOTH); +#endif +} + +// Disable line aliasing +void rlDisableSmoothLines(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11) + glDisable(GL_LINE_SMOOTH); +#endif +} + +// Enable stereo rendering +void rlEnableStereoRender(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + RLGL.State.stereoRender = true; +#endif +} + +// Disable stereo rendering +void rlDisableStereoRender(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + RLGL.State.stereoRender = false; +#endif +} + +// Check if stereo render is enabled +bool rlIsStereoRenderEnabled(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + return RLGL.State.stereoRender; +#else + return false; +#endif +} + +// Clear color buffer with color +void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + // Color values clamp to 0.0f(0) and 1.0f(255) + float cr = (float)r/255; + float cg = (float)g/255; + float cb = (float)b/255; + float ca = (float)a/255; + + glClearColor(cr, cg, cb, ca); +} + +// Clear used screen buffers (color and depth) +void rlClearScreenBuffers(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D) + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used... +} + +// Check and log OpenGL error codes +void rlCheckErrors(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int check = 1; + while (check) + { + const GLenum err = glGetError(); + 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; + } + } +#endif +} + +// Set blend mode +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)) + { + 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; + default: break; + } + + RLGL.State.currentBlendMode = mode; + RLGL.State.glCustomBlendModeModified = false; + } +#endif +} + +// Set blending mode factor and equation +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; + } +#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 +//---------------------------------------------------------------------------------- + +// 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); + + 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"); + + // 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; + + // 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.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(); + + // Init internal matrices + RLGL.State.transform = rlMatrixIdentity(); + RLGL.State.projection = rlMatrixIdentity(); + RLGL.State.modelview = rlMatrixIdentity(); + RLGL.State.currentMatrix = &RLGL.State.modelview; +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + + // Initialize OpenGL default states + //---------------------------------------------------------- + // Init state: Depth test + glDepthFunc(GL_LEQUAL); // Type of depth testing to apply + glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) + + // Init state: Blending mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed) + glEnable(GL_BLEND); // Enable color blending (required to work with transparencies) + + // Init state: Culling + // NOTE: All shapes/models triangles are drawn CCW + glCullFace(GL_BACK); // Cull the back face (default) + glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) + glEnable(GL_CULL_FACE); // Enable backface culling + + // Init state: Cubemap seamless +#if defined(GRAPHICS_API_OPENGL_33) + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) +#endif + +#if defined(GRAPHICS_API_OPENGL_11) + // Init state: Color hints (deprecated in OpenGL 3.0+) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation + glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) +#endif + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Store screen size into global variables + RLGL.State.framebufferWidth = width; + RLGL.State.framebufferHeight = height; + + TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); + //---------------------------------------------------------- +#endif + + // Init state: Color/Depth buffers clear + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) + glClearDepth(1.0f); // Set clear depth value (default) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) +} + +// Vertex Buffer Object deinitialization (memory free) +void rlglClose(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlUnloadRenderBatch(RLGL.defaultBatch); + + 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); +#endif +} + +// Load OpenGL extensions +// NOTE: External loader function must be provided +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"); + + // Get number of supported extensions + GLint numExt = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); + TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); + +#if defined(RLGL_SHOW_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)); +#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; + #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 + + // 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 *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)); + strcpy(extensionsDup, extensions); + extList[numExt] = extensionsDup; + + for (int i = 0; i < size; i++) + { + if (extensionsDup[i] == ' ') + { + extensionsDup[i] = '\0'; + numExt++; + extList[numExt] = &extensionsDup[i + 1]; + } + } + + TRACELOG(RL_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]); +#endif + + // Check required extensions + for (int i = 0; i < numExt; i++) + { + // Check VAO support + // NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature + if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0) + { + // The extension is supported by our hardware and driver, try to get related functions pointers + // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... + glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)((rlglLoadProc)loader)("glGenVertexArraysOES"); + glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)((rlglLoadProc)loader)("glBindVertexArrayOES"); + glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)((rlglLoadProc)loader)("glDeleteVertexArraysOES"); + //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)loader("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted + + if ((glGenVertexArrays != NULL) && (glBindVertexArray != NULL) && (glDeleteVertexArrays != NULL)) RLGL.ExtSupported.vao = true; + } + + // Check instanced rendering support + if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays + { + // 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)("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"); + } + 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 + // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature + if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) RLGL.ExtSupported.texNPOT = true; + + // 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_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 + + // Check texture compression support: DXT + if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) RLGL.ExtSupported.texCompDXT = true; + + // Check texture compression support: ETC1 + if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) RLGL.ExtSupported.texCompETC1 = true; + + // Check texture compression support: ETC2/EAC + if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) RLGL.ExtSupported.texCompETC2 = true; + + // Check texture compression support: PVR + if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) RLGL.ExtSupported.texCompPVRT = true; + + // Check texture compression support: ASTC + if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) RLGL.ExtSupported.texCompASTC = true; + + // Check anisotropic texture filter support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) RLGL.ExtSupported.texAnisoFilter = true; + + // Check clamp mirror wrap mode support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) RLGL.ExtSupported.texMirrorClamp = true; + } + + // Free extensions pointers + RL_FREE(extList); + RL_FREE(extensionsDup); // Duplicated string must be deallocated +#endif // GRAPHICS_API_OPENGL_ES2 + + // 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)); + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: Anisotropy levels capability is an extension + #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + #endif + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel); + +#if defined(RLGL_SHOW_GL_DETAILS_INFO) + // Show some OpenGL GPU capabilities + TRACELOG(RL_LOG_INFO, "GL: OpenGL capabilities:"); + GLint capability = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &capability); + TRACELOG(RL_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); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &capability); + TRACELOG(RL_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); + #if !defined(GRAPHICS_API_OPENGL_ES2) + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &capability); + TRACELOG(RL_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); + #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); + +#if defined(GRAPHICS_API_OPENGL_43) + glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability); + TRACELOG(RL_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 + + // 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 + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +} + +// Get current OpenGL version +int rlGetVersion(void) +{ + int glVersion = 0; +#if defined(GRAPHICS_API_OPENGL_11) + glVersion = RL_OPENGL_11; +#endif +#if defined(GRAPHICS_API_OPENGL_21) + glVersion = RL_OPENGL_21; +#elif defined(GRAPHICS_API_OPENGL_43) + glVersion = RL_OPENGL_43; +#elif defined(GRAPHICS_API_OPENGL_33) + glVersion = RL_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; +#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; +#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; +#endif + return height; +} + +// Get default internal texture (white texture) +// NOTE: Default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 +unsigned int rlGetTextureIdDefault(void) +{ + unsigned int id = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + id = RLGL.State.defaultTextureId; +#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; +} + +// Render batch management +//------------------------------------------------------------------------------------------------ +// Load render batch +rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) +{ + rlRenderBatch 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)); + + for (int i = 0; i < numBuffers; i++) + { + batch.vertexBuffer[i].elementCount = 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) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(bufferElements*6*sizeof(unsigned short)); // 6 int by quad (indices) +#endif + + 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; + + // Indices can be initialized right now + for (int j = 0; j < (6*bufferElements); j += 6) + { + batch.vertexBuffer[i].indices[j] = 4*k; + batch.vertexBuffer[i].indices[j + 1] = 4*k + 1; + batch.vertexBuffer[i].indices[j + 2] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 3] = 4*k; + batch.vertexBuffer[i].indices[j + 4] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 5] = 4*k + 3; + + k++; + } + + RLGL.State.vertexCounter = 0; + } + + TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)"); + //-------------------------------------------------------------------------------------------- + + // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs + //-------------------------------------------------------------------------------------------- + for (int i = 0; i < numBuffers; i++) + { + if (RLGL.ExtSupported.vao) + { + // Initialize Quads VAO + glGenVertexArrays(1, &batch.vertexBuffer[i].vaoId); + glBindVertexArray(batch.vertexBuffer[i].vaoId); + } + + // Quads - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) + 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); + + // 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); + + // Vertex color buffer (shader-location = 3) + glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); + 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); + + // Fill index buffer + glGenBuffers(1, &batch.vertexBuffer[i].vboId[4]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[4]); +#if defined(GRAPHICS_API_OPENGL_33) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(int), batch.vertexBuffer[i].indices, GL_STATIC_DRAW); +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(short), batch.vertexBuffer[i].indices, GL_STATIC_DRAW); +#endif + } + + TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)"); + + // Unbind the current VAO + if (RLGL.ExtSupported.vao) glBindVertexArray(0); + //-------------------------------------------------------------------------------------------- + + // Init draw calls tracking system + //-------------------------------------------------------------------------------------------- + batch.draws = (rlDrawCall *)RL_MALLOC(RL_DEFAULT_BATCH_DRAWCALLS*sizeof(rlDrawCall)); + + for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + { + batch.draws[i].mode = RL_QUADS; + batch.draws[i].vertexCount = 0; + batch.draws[i].vertexAlignment = 0; + //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.bufferCount = numBuffers; // Record buffer count + batch.drawCounter = 1; // Reset draws counter + batch.currentDepth = -1.0f; // Reset depth value + //-------------------------------------------------------------------------------------------- +#endif + + return batch; +} + +// Unload default internal buffers vertex data from CPU and GPU +void rlUnloadRenderBatch(rlRenderBatch batch) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Unbind everything + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // Unload all vertex buffers data + for (int i = 0; i < batch.bufferCount; 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); + + // 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); + } + + // Unload arrays + RL_FREE(batch.vertexBuffer); + RL_FREE(batch.draws); +#endif +} + +// Draw render batch +// NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer) +void rlDrawRenderBatch(rlRenderBatch *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) + { + // 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 + + // 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 + + // 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 + + // 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 + + // Another option: map the buffer object into client's memory + // Probably this code could be moved somewhere else... + // batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + // if (batch->vertexBuffer[batch->currentBuffer].vertices) + // { + // Update vertex data + // } + // glUnmapBuffer(GL_ARRAY_BUFFER); + + // Unbind the current VAO + if (RLGL.ExtSupported.vao) glBindVertexArray(0); + } + //------------------------------------------------------------------------------------------------------------ + + // Draw batch vertex buffers (considering VR stereo if required) + //------------------------------------------------------------------------------------------------------------ + Matrix matProjection = RLGL.State.projection; + Matrix matModelView = RLGL.State.modelview; + + int eyeCount = 1; + if (RLGL.State.stereoRender) eyeCount = 2; + + for (int eye = 0; eye < eyeCount; eye++) + { + if (eyeCount == 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])); + // Set current eye projection matrix + rlSetMatrixProjection(RLGL.State.projectionStereo[eye]); + } + + // Draw buffers + if (RLGL.State.vertexCounter > 0) + { + // Set current shader and upload current MVP matrix + glUseProgram(RLGL.State.currentShaderId); + + // 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)))); + } + + 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]); + + // 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]); + + // 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_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[4]); + } + + // 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 + + // 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++) + { + if (RLGL.State.activeTextureId[i] > 0) + { + glActiveTexture(GL_TEXTURE0 + 1 + i); + glBindTexture(GL_TEXTURE_2D, RLGL.State.activeTextureId[i]); + } + } + + // Activate default sampler2D texture0 (one texture is always active for default batch shader) + // 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++) + { + // Bind current draw call texture, activated as GL_TEXTURE0 and bound 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 + // 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) + glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(vertexOffset/4*6*sizeof(GLushort))); + #endif + } + + vertexOffset += (batch->draws[i].vertexCount + batch->draws[i].vertexAlignment); + } + + if (!RLGL.ExtSupported.vao) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } + + if (RLGL.ExtSupported.vao) glBindVertexArray(0); // Unbind VAO + + 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 depth for next draw + batch->currentDepth = -1.0f; + + // Restore projection/modelview matrices + RLGL.State.projection = matProjection; + RLGL.State.modelview = matModelView; + + // Reset RLGL.currentBatch->draws array + for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + { + batch->draws[i].mode = RL_QUADS; + batch->draws[i].vertexCount = 0; + batch->draws[i].textureId = RLGL.State.defaultTextureId; + } + + // Reset active texture units for next batch + for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) RLGL.State.activeTextureId[i] = 0; + + // Reset draws counter to one draw for the batch + batch->drawCounter = 1; + //------------------------------------------------------------------------------------------------------------ + + // Change to next buffer in the list (in case of multi-buffering) + batch->currentBuffer++; + if (batch->currentBuffer >= batch->bufferCount) batch->currentBuffer = 0; +#endif +} + +// Set the active render batch for rlgl +void rlSetRenderBatchActive(rlRenderBatch *batch) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDrawRenderBatch(RLGL.currentBatch); + + if (batch != NULL) RLGL.currentBatch = batch; + else RLGL.currentBatch = &RLGL.defaultBatch; +#endif +} + +// Update and draw internal render batch +void rlDrawRenderBatchActive(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside +#endif +} + +// Check internal buffer overflow for a given number of vertex +// and force a rlRenderBatch 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)) + { + 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 + + return overflow; +} + +// 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 id = 0; + + glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding + + // 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) + { + TRACELOG(RL_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))) + { + TRACELOG(RL_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)) + { + TRACELOG(RL_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))) + { + TRACELOG(RL_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))) + { + TRACELOG(RL_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))) + { + TRACELOG(RL_LOG_WARNING, "GL: ASTC compressed texture format not supported"); + return id; + } +#endif +#endif // GRAPHICS_API_OPENGL_11 + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &id); // Generate texture id + + glBindTexture(GL_TEXTURE_2D, id); + + 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; + + // Load the different mipmap levels + for (int i = 0; i < mipmapCount; i++) + { + unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); + + if (glInternalFormat != 0) + { + if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, dataPtr); +#if !defined(GRAPHICS_API_OPENGL_11) + else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, dataPtr); +#endif + +#if defined(GRAPHICS_API_OPENGL_33) + if (format == RL_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) + { +#if defined(GRAPHICS_API_OPENGL_21) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; +#elif defined(GRAPHICS_API_OPENGL_33) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; +#endif + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } +#endif + } + + mipWidth /= 2; + mipHeight /= 2; + mipOffset += mipSize; // Increment offset position to next mipmap + if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap + + // Security check for NPOT textures + if (mipWidth < 1) mipWidth = 1; + if (mipHeight < 1) mipHeight = 1; + } + + // Texture parameters configuration + // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used +#if defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used + if (RLGL.ExtSupported.texNPOT) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis + } + else + { + // NOTE: If using negative texture coordinates (LoadOBJ()), it does not work! + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis + } +#else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis +#endif + + // Magnification and minification filters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + +#if defined(GRAPHICS_API_OPENGL_33) + if (mipmapCount > 1) + { + // 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 + + // At this point we have the texture loaded in GPU and texture parameters configured + + // NOTE: If mipmaps were not in data, they are not generated automatically + + // 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"); + + 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 +unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) +{ + unsigned int id = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // In case depth textures not supported, we force renderbuffer usage + if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; + + // NOTE: We let the implementation to choose the best bit-depth + // 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; + } +#endif + + if (!useRenderBuffer && RLGL.ExtSupported.texDepth) + { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, 0); + + TRACELOG(RL_LOG_INFO, "TEXTURE: Depth texture loaded successfully"); + } + else + { + // Create the renderbuffer that will serve as the depth attachment for the framebuffer + // NOTE: A renderbuffer is simpler than a texture and could offer better performance on embedded devices + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height); + + 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); + } +#endif + + return id; +} + +// 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 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); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + if (glInternalFormat != 0) + { + // Load cubemap faces/mipmaps + for (int i = 0; i < 6*mipmapCount; i++) + { + int mipmapLevel = i/6; + int face = i%6; + + if (data == NULL) + { + if (format < RL_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); + } + else TRACELOG(RL_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 defined(GRAPHICS_API_OPENGL_33) + if (format == RL_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) + { +#if defined(GRAPHICS_API_OPENGL_21) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; +#elif defined(GRAPHICS_API_OPENGL_33) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; +#endif + 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_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); +#if defined(GRAPHICS_API_OPENGL_33) + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0 +#endif + + 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"); + + return id; +} + +// Update already loaded texture in GPU with new data +// NOTE: We don't know safely if internal texture format is the expected one... +void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data) +{ + glBindTexture(GL_TEXTURE_2D, id); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, data); + } + else TRACELOG(RL_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; + + 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; + #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 + #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; + #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 + #endif + default: TRACELOG(RL_LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break; + } +} + +// Unload texture from GPU memory +void rlUnloadTexture(unsigned int id) +{ + glDeleteTextures(1, &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) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_2D, 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 ((texIsPOT) || (RLGL.ExtSupported.texNPOT)) + { + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: 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)) + + *mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2)); + TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps); + } + else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", 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 *pixels = NULL; + +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + glBindTexture(GL_TEXTURE_2D, id); + + // 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 + // 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); + + if ((glInternalFormat != 0) && (format < RL_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); + + 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 + // 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(); + + 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); + + // 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); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Clean up temporal fbo + rlUnloadFramebuffer(fboId); +#endif + + 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)); + + // 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); + + // 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--) + { + for (int x = 0; x < (width*4); x += 4) + { + unsigned int s = ((height - 1) - y)*width*4 + x; + unsigned int e = y*width*4 + x; + + 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 + } + } + + return imgData; // NOTE: image data should be freed +} + +// Framebuffer management (fbo) +//----------------------------------------------------------------------------------------- +// Load a framebuffer to be used for rendering +// NOTE: No textures attached +unsigned int rlLoadFramebuffer(void) +{ + unsigned int fboId = 0; + +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) + glGenFramebuffers(1, &fboId); // Create the framebuffer object + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer +#endif + + return fboId; +} + +// Attach color buffer texture to an fbo (unloads previous attachment) +// 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) + glBindFramebuffer(GL_FRAMEBUFFER, fboId); + + switch (attachType) + { + case RL_ATTACHMENT_COLOR_CHANNEL0: + case RL_ATTACHMENT_COLOR_CHANNEL1: + case RL_ATTACHMENT_COLOR_CHANNEL2: + case RL_ATTACHMENT_COLOR_CHANNEL3: + case RL_ATTACHMENT_COLOR_CHANNEL4: + case RL_ATTACHMENT_COLOR_CHANNEL5: + case RL_ATTACHMENT_COLOR_CHANNEL6: + case RL_ATTACHMENT_COLOR_CHANNEL7: + { + 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; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + +// Verify render texture is complete +bool rlFramebufferComplete(unsigned int id) +{ + bool result = false; + +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) + glBindFramebuffer(GL_FRAMEBUFFER, id); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + 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; +#if defined(GRAPHICS_API_OPENGL_ES2) + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(RL_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; + default: break; + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + result = (status == GL_FRAMEBUFFER_COMPLETE); +#endif + + return result; +} + +// Unload framebuffer from GPU memory +// 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) + // 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); + + // 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 + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &id); + + TRACELOG(RL_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 id = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glGenBuffers(1, &id); + glBindBuffer(GL_ARRAY_BUFFER, id); + glBufferData(GL_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#endif + + return id; +} + +// Load a new attributes element buffer +unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic) +{ + unsigned int id = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glGenBuffers(1, &id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#endif + + return id; +} + +// Enable vertex buffer (VBO) +void rlEnableVertexBuffer(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, id); +#endif +} + +// Disable vertex buffer (VBO) +void rlDisableVertexBuffer(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, 0); +#endif +} + +// Enable vertex buffer element (VBO element) +void rlEnableVertexBufferElement(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); +#endif +} + +// Disable vertex buffer element (VBO element) +void rlDisableVertexBufferElement(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#endif +} + +// Update vertex 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) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, id); + 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; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) + { + glBindVertexArray(vaoId); + result = true; + } +#endif + return result; +} + +// Disable vertex array object (VAO) +void rlDisableVertexArray(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) glBindVertexArray(0); +#endif +} + +// Enable vertex attribute index +void rlEnableVertexAttribute(unsigned int index) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glEnableVertexAttribArray(index); +#endif +} + +// Disable vertex attribute index +void rlDisableVertexAttribute(unsigned int index) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDisableVertexAttribArray(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) +{ + // 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); +} + +// 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); +#endif +} + +// Draw vertex array elements instanced +void rlDrawVertexArrayElementsInstanced(int offset, int count, const 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); +#endif +} + +#if defined(GRAPHICS_API_OPENGL_11) +// Enable vertex state pointer +void rlEnableStatePointer(int vertexAttribType, void *buffer) +{ + if (buffer != NULL) glEnableClientState(vertexAttribType); + switch (vertexAttribType) + { + case GL_VERTEX_ARRAY: glVertexPointer(3, GL_FLOAT, 0, buffer); break; + case GL_TEXTURE_COORD_ARRAY: glTexCoordPointer(2, GL_FLOAT, 0, buffer); break; + case GL_NORMAL_ARRAY: if (buffer != NULL) glNormalPointer(GL_FLOAT, 0, buffer); break; + case GL_COLOR_ARRAY: if (buffer != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer); break; + //case GL_INDEX_ARRAY: if (buffer != NULL) glIndexPointer(GL_SHORT, 0, buffer); break; // Indexed colors + default: break; + } +} + +// Disable vertex state pointer +void rlDisableStatePointer(int vertexAttribType) +{ + glDisableClientState(vertexAttribType); +} +#endif + +// Load vertex array object (VAO) +unsigned int rlLoadVertexArray(void) +{ + unsigned int vaoId = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) + { + glGenVertexArrays(1, &vaoId); + } +#endif + return vaoId; +} + +// Set vertex attribute +void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, int offset) +{ +#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); +#endif +} + +// Set vertex attribute divisor +void rlSetVertexAttributeDivisor(unsigned int index, int divisor) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glVertexAttribDivisor(index, divisor); +#endif +} + +// Unload vertex array object (VAO) +void rlUnloadVertexArray(unsigned int vaoId) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) + { + glBindVertexArray(0); + glDeleteVertexArrays(1, &vaoId); + TRACELOG(RL_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)"); +#endif +} + +// Shaders management +//----------------------------------------------------------------------------------------------- +// Load shader from code strings +// NOTE: If shader string is NULL, using default vertex/fragment shaders +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; + + // 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)) + { + // 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); + glDeleteShader(vertexShaderId); + } + if (fragmentShaderId != RLGL.State.defaultFShaderId) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if (id > 0) 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; + } + /* + 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 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 + + return id; +} + +// Compile custom shader and return shader id +unsigned int rlCompileShader(const char *shaderCode, int type) +{ + unsigned int shader = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + shader = glCreateShader(type); + glShaderSource(shader, 1, &shaderCode, NULL); + + GLint success = 0; + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + + if (success == GL_FALSE) + { + 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_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 + default: break; + } + + int maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetShaderInfoLog(shader, maxLength, &length, log); + TRACELOG(RL_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_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 + default: break; + } + } +#endif + + return shader; +} + +// Load custom shader strings and return program id +unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) +{ + unsigned int program = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLint success = 0; + program = glCreateProgram(); + + 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: If some attrib name is no found on the shader, it locations becomes -1 + + 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 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] Program shader loaded successfully", program); + } +#endif + return program; +} + +// Unload shader program +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); +#endif +} + +// Get shader location uniform +int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) +{ + int location = -1; +#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); +#endif + return location; +} + +// Get shader location attribute +int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) +{ + int location = -1; +#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); +#endif + return location; +} + +// Set shader value uniform +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() + } +#endif +} + +// Set shader value attribute +void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count) +{ +#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"); + } +#endif +} + +// Set shader value uniform matrix +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); +#endif +} + +// Set shader value uniform sampler +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; + } + } + + // 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++) + { + if (RLGL.State.activeTextureId[i] == 0) + { + glUniform1i(locIndex, 1 + i); // Activate new texture unit + RLGL.State.activeTextureId[i] = textureId; // Save texture id for binding on drawing + break; + } + } +#endif +} + +// Set shader currently active (id and locations) +void rlSetShader(unsigned int id, int *locs) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.State.currentShaderId != id) + { + rlDrawRenderBatch(RLGL.currentBatch); + RLGL.State.currentShaderId = id; + RLGL.State.currentShaderLocs = locs; + } +#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 +Matrix rlGetMatrixModelview(void) +{ + Matrix matrix = rlMatrixIdentity(); +#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]; +#else + matrix = RLGL.State.modelview; +#endif + return matrix; +} + +// Get 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]; + return m; +#else + return RLGL.State.projection; +#endif +} + +// Get internal accumulated transform matrix +Matrix rlGetMatrixTransform(void) +{ + Matrix mat = rlMatrixIdentity(); +#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); + mat = RLGL.State.transform; +#endif + return mat; +} + +// Get internal projection matrix for stereo render (selected eye) +Matrix rlGetMatrixProjectionStereo(int eye) +{ + Matrix mat = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + mat = RLGL.State.projectionStereo[eye]; +#endif + return mat; +} + +// Get internal view offset matrix for stereo render (selected eye) +Matrix rlGetMatrixViewOffsetStereo(int eye) +{ + Matrix mat = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + mat = RLGL.State.viewOffsetStereo[eye]; +#endif + return mat; +} + +// Set a custom modelview matrix (replaces internal modelview matrix) +void rlSetMatrixModelview(Matrix view) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.modelview = view; +#endif +} + +// Set a custom projection matrix (replaces internal projection matrix) +void rlSetMatrixProjection(Matrix projection) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.projection = projection; +#endif +} + +// Set eyes projection matrices for stereo rendering +void rlSetMatrixProjectionStereo(Matrix right, Matrix left) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.projectionStereo[0] = right; + RLGL.State.projectionStereo[1] = left; +#endif +} + +// Set eyes view offsets matrices for stereo rendering +void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.viewOffsetStereo[0] = right; + RLGL.State.viewOffsetStereo[1] = left; +#endif +} + +// Load and draw a quad in NDC +void rlLoadDrawQuad(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int quadVAO = 0; + unsigned int quadVBO = 0; + + float vertices[] = { + // Positions Texcoords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + + // Gen VAO to contain VBO + glGenVertexArrays(1, &quadVAO); + glBindVertexArray(quadVAO); + + // Gen and fill vertex buffer (VBO) + glGenBuffers(1, &quadVBO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + 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 + + // Draw quad + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + + // Delete buffers (VBO and VAO) + glDeleteBuffers(1, &quadVBO); + glDeleteVertexArrays(1, &quadVAO); +#endif +} + +// Load and draw a cube in NDC +void rlLoadDrawCube(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int cubeVAO = 0; + unsigned int cubeVBO = 0; + + float vertices[] = { + // Positions Normals Texcoords + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f + }; + + // Gen VAO to contain VBO + glGenVertexArrays(1, &cubeVAO); + glBindVertexArray(cubeVAO); + + // Gen and fill vertex buffer (VBO) + glGenBuffers(1, &cubeVBO); + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // 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 + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // Draw cube + glBindVertexArray(cubeVAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); + + // Delete VBO and VAO + glDeleteBuffers(1, &cubeVBO); + glDeleteVertexArrays(1, &cubeVAO); +#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 +static void rlLoadShaderDefault(void) +{ + RLGL.State.defaultShaderLocs = (int *)RL_CALLOC(RL_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; + + // Vertex shader directly defined, no external file required + const char *defaultVShaderCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "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) + "#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" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " gl_Position = mvp*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // Fragment shader directly defined, no external file required + const char *defaultFShaderCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "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"; +#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) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \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 + + RLGL.State.defaultShaderId = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); + + if (RLGL.State.defaultShaderId > 0) + { + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", RLGL.State.defaultShaderId); + + // 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); + + // 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); + } + else TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", RLGL.State.defaultShaderId); +} + +// Unload default shader +// NOTE: Unloads: RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs +static void rlUnloadShaderDefault(void) +{ + glUseProgram(0); + + glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultVShaderId); + glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultFShaderId); + glDeleteShader(RLGL.State.defaultVShaderId); + glDeleteShader(RLGL.State.defaultFShaderId); + + glDeleteProgram(RLGL.State.defaultShaderId); + + RL_FREE(RLGL.State.defaultShaderLocs); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId); +} + +#if defined(RLGL_SHOW_GL_DETAILS_INFO) +// Get compressed format official GL identifier name +static const char *rlGetCompressedFormatName(int format) +{ + 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; + // GL_3DFX_texture_compression_FXT1 + case 0x86B0: return "GL_COMPRESSED_RGB_FXT1_3DFX"; break; + case 0x86B1: return "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; + // GL_OES_compressed_ETC1_RGB8_texture + case 0x8D64: return "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; + // 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; + // 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; + // 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; + } +} +#endif // RLGL_SHOW_GL_DETAILS_INFO + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +// Get pixel data size in bytes (image or texture) +// NOTE: Size depends on pixel format +static int rlGetPixelDataSize(int width, int height, int format) +{ + int dataSize = 0; // Size in bytes + int bpp = 0; // Bits per pixel + + 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; + default: break; + } + + double bytesPerPixel = (double)bpp/8.0; + dataSize = (int)(bytesPerPixel*width*height); // 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; + } + + 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 new file mode 100644 index 0000000..bd60809 --- /dev/null +++ b/raylib/rlgl_cgo.go @@ -0,0 +1,1010 @@ +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 new file mode 100644 index 0000000..1439cfa --- /dev/null +++ b/raylib/rlgl_purego.go @@ -0,0 +1,944 @@ +//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 new file mode 100644 index 0000000..84daabc --- /dev/null +++ b/raylib/rmodels.c @@ -0,0 +1,6930 @@ +/********************************************************************************************** +* +* 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/rmodels.go b/raylib/rmodels.go new file mode 100644 index 0000000..fc58860 --- /dev/null +++ b/raylib/rmodels.go @@ -0,0 +1,724 @@ +package rl + +/* +#include "raylib.h" +#include +*/ +import "C" + +import ( + "image/color" + "unsafe" +) + +// newMeshFromPointer - Returns new Mesh from pointer +func newMeshFromPointer(ptr unsafe.Pointer) Mesh { + return *(*Mesh)(ptr) +} + +// 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) { + cstartPos := startPos.cptr() + cendPos := endPos.cptr() + ccolor := colorCptr(col) + 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) { + ccenter := center.cptr() + cradius := (C.float)(radius) + crotationAxis := rotationAxis.cptr() + crotationAngle := (C.float)(rotationAngle) + ccolor := colorCptr(col) + 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) { + cposition := position.cptr() + cwidth := (C.float)(width) + cheight := (C.float)(height) + clength := (C.float)(length) + ccolor := colorCptr(col) + C.DrawCube(*cposition, cwidth, cheight, clength, *ccolor) +} + +// DrawCubeV - Draw cube (Vector version) +func DrawCubeV(position Vector3, size Vector3, col color.RGBA) { + cposition := position.cptr() + csize := size.cptr() + ccolor := colorCptr(col) + C.DrawCubeV(*cposition, *csize, *ccolor) +} + +// DrawCubeWires - Draw cube wires +func DrawCubeWires(position Vector3, width float32, height float32, length float32, col color.RGBA) { + cposition := position.cptr() + cwidth := (C.float)(width) + cheight := (C.float)(height) + clength := (C.float)(length) + ccolor := colorCptr(col) + C.DrawCubeWires(*cposition, cwidth, cheight, clength, *ccolor) +} + +// DrawCubeWiresV - Draw cube wires (Vector version) +func DrawCubeWiresV(position Vector3, size Vector3, col color.RGBA) { + cposition := position.cptr() + csize := size.cptr() + ccolor := colorCptr(col) + C.DrawCubeWiresV(*cposition, *csize, *ccolor) +} + +// DrawSphere - Draw sphere +func DrawSphere(centerPos Vector3, radius float32, col color.RGBA) { + ccenterPos := centerPos.cptr() + cradius := (C.float)(radius) + ccolor := colorCptr(col) + C.DrawSphere(*ccenterPos, cradius, *ccolor) +} + +// DrawSphereEx - Draw sphere with extended parameters +func DrawSphereEx(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { + ccenterPos := centerPos.cptr() + cradius := (C.float)(radius) + crings := (C.int)(rings) + cslices := (C.int)(slices) + ccolor := colorCptr(col) + C.DrawSphereEx(*ccenterPos, cradius, crings, cslices, *ccolor) +} + +// DrawSphereWires - Draw sphere wires +func DrawSphereWires(centerPos Vector3, radius float32, rings int32, slices int32, col color.RGBA) { + ccenterPos := centerPos.cptr() + cradius := (C.float)(radius) + crings := (C.int)(rings) + cslices := (C.int)(slices) + ccolor := colorCptr(col) + 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) { + cposition := position.cptr() + cradiusTop := (C.float)(radiusTop) + cradiusBottom := (C.float)(radiusBottom) + cheight := (C.float)(height) + cslices := (C.int)(slices) + ccolor := colorCptr(col) + 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) { + cposition := position.cptr() + cradiusTop := (C.float)(radiusTop) + cradiusBottom := (C.float)(radiusBottom) + cheight := (C.float)(height) + cslices := (C.int)(slices) + ccolor := colorCptr(col) + 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) { + ccenterPos := centerPos.cptr() + csize := size.cptr() + ccolor := colorCptr(col) + C.DrawPlane(*ccenterPos, *csize, *ccolor) +} + +// DrawRay - Draw a ray line +func DrawRay(ray Ray, col color.RGBA) { + cray := ray.cptr() + ccolor := colorCptr(col) + C.DrawRay(*cray, *ccolor) +} + +// DrawGrid - Draw a grid (centered at (0, 0, 0)) +func DrawGrid(slices int32, spacing float32) { + cslices := (C.int)(slices) + cspacing := (C.float)(spacing) + C.DrawGrid(cslices, cspacing) +} + +// LoadModel - Load model from file +func LoadModel(fileName string) Model { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadModel(cfileName) + v := newModelFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadModelFromMesh - Load model from mesh data +func LoadModelFromMesh(data Mesh) Model { + cdata := data.cptr() + ret := C.LoadModelFromMesh(*cdata) + v := newModelFromPointer(unsafe.Pointer(&ret)) + 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)) +} + +// ExportMesh - Export mesh as an OBJ file +func ExportMesh(mesh Mesh, fileName string) { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + cmesh := mesh.cptr() + 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) + clength := (C.float)(length) + cresX := (C.int)(resX) + cresZ := (C.int)(resZ) + + ret := C.GenMeshPlane(cwidth, clength, cresX, cresZ) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshCube - Generate cuboid mesh +func GenMeshCube(width, height, length float32) Mesh { + cwidth := (C.float)(width) + cheight := (C.float)(height) + clength := (C.float)(length) + + ret := C.GenMeshCube(cwidth, cheight, clength) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshSphere - Generate sphere mesh (standard sphere) +func GenMeshSphere(radius float32, rings, slices int) Mesh { + cradius := (C.float)(radius) + crings := (C.int)(rings) + cslices := (C.int)(slices) + + ret := C.GenMeshSphere(cradius, crings, cslices) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshHemiSphere - Generate half-sphere mesh (no bottom cap) +func GenMeshHemiSphere(radius float32, rings, slices int) Mesh { + cradius := (C.float)(radius) + crings := (C.int)(rings) + cslices := (C.int)(slices) + + ret := C.GenMeshHemiSphere(cradius, crings, cslices) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshCylinder - Generate cylinder mesh +func GenMeshCylinder(radius, height float32, slices int) Mesh { + cradius := (C.float)(radius) + cheight := (C.float)(height) + cslices := (C.int)(slices) + + ret := C.GenMeshCylinder(cradius, cheight, cslices) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + 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) + csize := (C.float)(size) + cradSeg := (C.int)(radSeg) + csides := (C.int)(sides) + + ret := C.GenMeshTorus(cradius, csize, cradSeg, csides) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshKnot - Generate trefoil knot mesh +func GenMeshKnot(radius, size float32, radSeg, sides int) Mesh { + cradius := (C.float)(radius) + csize := (C.float)(size) + cradSeg := (C.int)(radSeg) + csides := (C.int)(sides) + + ret := C.GenMeshKnot(cradius, csize, cradSeg, csides) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshHeightmap - Generate heightmap mesh from image data +func GenMeshHeightmap(heightmap Image, size Vector3) Mesh { + cheightmap := heightmap.cptr() + csize := size.cptr() + + ret := C.GenMeshHeightmap(*cheightmap, *csize) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenMeshCubicmap - Generate cubes-based map mesh from image data +func GenMeshCubicmap(cubicmap Image, size Vector3) Mesh { + ccubicmap := cubicmap.cptr() + csize := size.cptr() + + ret := C.GenMeshCubicmap(*ccubicmap, *csize) + v := newMeshFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadMaterials - Load material data (.MTL) +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)] + return v +} + +// LoadMaterialDefault - Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +func LoadMaterialDefault() Material { + ret := C.LoadMaterialDefault() + v := newMaterialFromPointer(unsafe.Pointer(&ret)) + 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() + C.UnloadMaterial(*cmaterial) +} + +// SetMaterialTexture - Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +func SetMaterialTexture(material *Material, mapType int32, texture Texture2D) { + cmaterial := material.cptr() + cmapType := (C.int)(mapType) + ctexture := texture.cptr() + C.SetMaterialTexture(cmaterial, cmapType, *ctexture) +} + +// SetModelMeshMaterial - Set material for a mesh +func SetModelMeshMaterial(model *Model, meshId int32, materialId int32) { + cmodel := model.cptr() + cmeshId := (C.int)(meshId) + cmaterialId := (C.int)(materialId) + 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) { + cmodel := model.cptr() + canim := anim.cptr() + cframe := (C.int)(frame) + C.UpdateModelAnimation(*cmodel, *canim, cframe) +} + +// UpdateModelAnimationBones - Update model animation mesh bone matrices (GPU skinning) +func UpdateModelAnimationBones(model Model, anim ModelAnimation, frame int32) { + cmodel := model.cptr() + canim := anim.cptr() + cframe := (C.int)(frame) + C.UpdateModelAnimationBones(*cmodel, *canim, cframe) +} + +// 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 { + cmodel := model.cptr() + canim := anim.cptr() + ret := C.IsModelAnimationValid(*cmodel, *canim) + v := bool(ret) + return v +} + +// CheckCollisionSpheres - Detect collision between two spheres +func CheckCollisionSpheres(centerA Vector3, radiusA float32, centerB Vector3, radiusB float32) bool { + ccenterA := centerA.cptr() + cradiusA := (C.float)(radiusA) + ccenterB := centerB.cptr() + cradiusB := (C.float)(radiusB) + ret := C.CheckCollisionSpheres(*ccenterA, cradiusA, *ccenterB, cradiusB) + v := bool(ret) + return v +} + +// CheckCollisionBoxes - Detect collision between two bounding boxes +func CheckCollisionBoxes(box1 BoundingBox, box2 BoundingBox) bool { + cbox1 := box1.cptr() + cbox2 := box2.cptr() + ret := C.CheckCollisionBoxes(*cbox1, *cbox2) + v := bool(ret) + return v +} + +// CheckCollisionBoxSphere - Detect collision between box and sphere +func CheckCollisionBoxSphere(box BoundingBox, centerSphere Vector3, radiusSphere float32) bool { + cbox := box.cptr() + ccenterSphere := centerSphere.cptr() + cradiusSphere := (C.float)(radiusSphere) + ret := C.CheckCollisionBoxSphere(*cbox, *ccenterSphere, cradiusSphere) + v := bool(ret) + return v +} + +// GetRayCollisionSphere - Get collision info between ray and sphere +func GetRayCollisionSphere(ray Ray, center Vector3, radius float32) RayCollision { + cray := ray.cptr() + ccenter := center.cptr() + cradius := (C.float)(radius) + ret := C.GetRayCollisionSphere(*cray, *ccenter, cradius) + v := newRayCollisionFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GetRayCollisionBox - Get collision info between ray and box +func GetRayCollisionBox(ray Ray, box BoundingBox) RayCollision { + 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)) + return v +} diff --git a/raylib/rshapes.c b/raylib/rshapes.c new file mode 100644 index 0000000..be28e6c --- /dev/null +++ b/raylib/rshapes.c @@ -0,0 +1,2442 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..4922b3a --- /dev/null +++ b/raylib/rshapes.go @@ -0,0 +1,647 @@ +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 new file mode 100644 index 0000000..d7818d2 --- /dev/null +++ b/raylib/rtext.c @@ -0,0 +1,2596 @@ +/********************************************************************************************** +* +* 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 new file mode 100644 index 0000000..e32ee20 --- /dev/null +++ b/raylib/rtext.go @@ -0,0 +1,261 @@ +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/rtextures.c b/raylib/rtextures.c new file mode 100644 index 0000000..ac06d6d --- /dev/null +++ b/raylib/rtextures.c @@ -0,0 +1,5569 @@ +/********************************************************************************************** +* +* rtextures - Basic functions to load and draw textures +* +* 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_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_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 +* +* +* 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_RTEXTURES) + +#include "utils.h" // Required for: TRACELOG() +#include "rlgl.h" // OpenGL abstraction layer to multiple versions + +#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()] + +// Support only desired texture formats on stb_image +#if !defined(SUPPORT_FILEFORMAT_BMP) + #define STBI_NO_BMP +#endif +#if !defined(SUPPORT_FILEFORMAT_PNG) + #define STBI_NO_PNG +#endif +#if !defined(SUPPORT_FILEFORMAT_TGA) + #define STBI_NO_TGA +#endif +#if !defined(SUPPORT_FILEFORMAT_JPG) + #define STBI_NO_JPEG // Image format .jpg and .jpeg +#endif +#if !defined(SUPPORT_FILEFORMAT_PSD) + #define STBI_NO_PSD +#endif +#if !defined(SUPPORT_FILEFORMAT_GIF) + #define STBI_NO_GIF +#endif +#if !defined(SUPPORT_FILEFORMAT_PIC) + #define STBI_NO_PIC +#endif +#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 +#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 + + #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) + #define STBIW_MALLOC RL_MALLOC + #define STBIW_FREE RL_FREE + #define STBIW_REALLOC RL_REALLOC + + #define STB_IMAGE_WRITE_IMPLEMENTATION + #include "external/stb_image_write.h" // Required for: stbi_write_*() +#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 +//---------------------------------------------------------------------------------- +#ifndef PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD + #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 +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// It's lonely here... + +//---------------------------------------------------------------------------------- +// 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) + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Load image from file into CPU memory (RAM) +Image LoadImage(const char *fileName) +{ + Image image = { 0 }; + +#if defined(SUPPORT_FILEFORMAT_PNG) || \ + defined(SUPPORT_FILEFORMAT_BMP) || \ + defined(SUPPORT_FILEFORMAT_TGA) || \ + defined(SUPPORT_FILEFORMAT_JPG) || \ + defined(SUPPORT_FILEFORMAT_GIF) || \ + defined(SUPPORT_FILEFORMAT_PIC) || \ + defined(SUPPORT_FILEFORMAT_HDR) || \ + defined(SUPPORT_FILEFORMAT_PNM) || \ + defined(SUPPORT_FILEFORMAT_PSD) + + #define STBI_REQUIRED +#endif + + // Loading file to memory + int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + // Loading image from memory data + if (fileData != NULL) + { + image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize); + + UnloadFileData(fileData); + } + + return image; +} + +// Load an image from RAW file data +Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize) +{ + Image image = { 0 }; + + int dataSize = 0; + unsigned char *fileData = LoadFileData(fileName, &dataSize); + + if (fileData != NULL) + { + unsigned char *dataPtr = fileData; + 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; + + 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); + } + + return image; +} + +// 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 LoadImageAnim(const char *fileName, int *frames) +{ + Image image = { 0 }; + int frameCount = 0; + +#if defined(SUPPORT_FILEFORMAT_GIF) + if (IsFileExtension(fileName, ".gif")) + { + 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); + + image.mipmaps = 1; + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + UnloadFileData(fileData); + RL_FREE(delays); // NOTE: Frames delays are discarded + } + } +#else + if (false) { } +#endif + else + { + image = LoadImage(fileName); + frameCount = 1; + } + + *frames = frameCount; + return image; +} + +// 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; + 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; + } + + if ((false) +#if defined(SUPPORT_FILEFORMAT_PNG) + || (strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0) +#endif +#if defined(SUPPORT_FILEFORMAT_BMP) + || (strcmp(fileType, ".bmp") == 0) || (strcmp(fileType, ".BMP") == 0) +#endif +#if defined(SUPPORT_FILEFORMAT_TGA) + || (strcmp(fileType, ".tga") == 0) || (strcmp(fileType, ".TGA") == 0) +#endif +#if defined(SUPPORT_FILEFORMAT_JPG) + || (strcmp(fileType, ".jpg") == 0) || (strcmp(fileType, ".jpeg") == 0) + || (strcmp(fileType, ".JPG") == 0) || (strcmp(fileType, ".JPEG") == 0) +#endif +#if defined(SUPPORT_FILEFORMAT_GIF) + || (strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0) +#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) +#endif +#if defined(SUPPORT_FILEFORMAT_PSD) + || (strcmp(fileType, ".psd") == 0) || (strcmp(fileType, ".PSD") == 0) +#endif + ) + { +#if defined(STBI_REQUIRED) + // NOTE: Using stb_image to load images (Supports multiple image formats) + + if (fileData != NULL) + { + int comp = 0; + image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0); + + if (image.data != NULL) + { + 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; + } + } +#endif + } +#if defined(SUPPORT_FILEFORMAT_HDR) + else if ((strcmp(fileType, ".hdr") == 0) || (strcmp(fileType, ".HDR") == 0)) + { +#if defined(STBI_REQUIRED) + if (fileData != NULL) + { + int comp = 0; + image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0); + + image.mipmaps = 1; + + if (comp == 1) image.format = PIXELFORMAT_UNCOMPRESSED_R32; + else if (comp == 3) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; + else if (comp == 4) image.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32A32; + else + { + TRACELOG(LOG_WARNING, "IMAGE: HDR file format not supported"); + UnloadImage(image); + } + } +#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); + } +#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); + } +#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); + } +#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); + } +#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); + } +#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"); + + 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) +{ + RL_FREE(image.data); +} + +// Export image data to file +// 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; + +#if defined(SUPPORT_IMAGE_EXPORT) + int channels = 4; + bool allocatedData = false; + unsigned char *imgData = (unsigned char *)image.data; + + 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; + else + { + // NOTE: Getting Color array as RGBA unsigned char values + imgData = (unsigned char *)LoadImageColors(image); + allocatedData = true; + } + +#if defined(SUPPORT_FILEFORMAT_PNG) + if (IsFileExtension(fileName, ".png")) + { + 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); + RL_FREE(fileData); + } +#else + if (false) { } +#endif +#if defined(SUPPORT_FILEFORMAT_BMP) + else if (IsFileExtension(fileName, ".bmp")) result = 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); +#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); + } + } +#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); + } +#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)); + } + + if (allocatedData) RL_FREE(imgData); +#endif // SUPPORT_IMAGE_EXPORT + + if (result != 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; +} + +// Export image as code file (.h) defining an array of bytes +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 + + int dataSize = GetPixelDataSize(image.width, image.height, image.format); + + // 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)); + + 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"); + + // 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, "// 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); + + 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]); + + // NOTE: Text data size 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; +} + +//------------------------------------------------------------------------------------ +// Image generation functions +//------------------------------------------------------------------------------------ +// Generate image: plain color +Image GenImageColor(int width, int height, Color color) +{ + Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color)); + + for (int i = 0; i < width*height; i++) pixels[i] = color; + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +#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) +{ + 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); + + // 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); + + // 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++) + { + 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)); + } + } + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +// Generate image: radial gradient +Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) +{ + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + float radius = (width < height)? (float)width/2.0f : (float)height/2.0f; + + 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++) + { + float dist = hypotf((float)x - centerX, (float)y - centerY); + 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 + + 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: 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) +{ + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if ((x/checksX + y/checksY)%2 == 0) pixels[y*width + x] = col1; + else pixels[y*width + x] = col2; + } + } + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +// 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)); + + for (int i = 0; i < width*height; i++) + { + if (GetRandomValue(0, 99) < (int)(factor*100.0f)) pixels[i] = WHITE; + else pixels[i] = BLACK; + } + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +// Generate image: perlin noise +Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale) +{ + 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); + + // 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; + + // 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 }; + } + } + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + return image; +} + +// Generate image: cellular algorithm. Bigger tileSize means bigger cells +Image GenImageCellular(int width, int height, int tileSize) +{ + Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color)); + + int seedsPerRow = width/tileSize; + int seedsPerCol = height/tileSize; + int seedCount = seedsPerRow*seedsPerCol; + + Vector2 *seeds = (Vector2 *)RL_MALLOC(seedCount*sizeof(Vector2)); + + for (int i = 0; i < seedCount; 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 }; + } + + for (int y = 0; y < height; y++) + { + int tileY = y/tileSize; + + for (int x = 0; x < width; x++) + { + int tileX = x/tileSize; + + float minDistance = 65536.0f; //(float)strtod("Inf", NULL); + + // Check all adjacent tiles + for (int i = -1; i < 2; i++) + { + if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue; + + for (int j = -1; j < 2; j++) + { + if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue; + + Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i]; + + float dist = (float)hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y); + minDistance = (float)fmin(minDistance, dist); + } + } + + // 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; + + pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; + } + } + + RL_FREE(seeds); + + Image image = { + .data = pixels, + .width = width, + .height = height, + .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, + .mipmaps = 1 + }; + + 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 + +//------------------------------------------------------------------------------------ +// Image manipulation functions +//------------------------------------------------------------------------------------ +// Copy an image to a new image +Image ImageCopy(Image image) +{ + Image newImage = { 0 }; + + int width = image.width; + int height = image.height; + int size = 0; + + for (int i = 0; i < image.mipmaps; i++) + { + size += GetPixelDataSize(width, height, image.format); + + width /= 2; + height /= 2; + + // Security check for NPOT textures + if (width < 1) width = 1; + if (height < 1) height = 1; + } + + newImage.data = RL_CALLOC(size, 1); + + if (newImage.data != NULL) + { + // NOTE: Size must be provided in bytes + memcpy(newImage.data, image.data, size); + + newImage.width = image.width; + newImage.height = image.height; + newImage.mipmaps = image.mipmaps; + newImage.format = image.format; + } + + return newImage; +} + +// Create an image from another image piece +Image ImageFromImage(Image image, Rectangle rec) +{ + Image result = { 0 }; + + int bytesPerPixel = GetPixelDataSize(1, 1, image.format); + + result.width = (int)rec.width; + result.height = (int)rec.height; + result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); + result.format = image.format; + result.mipmaps = 1; + + for (int y = 0; y < (int)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); + } + + return result; +} + +// Crop an image to area defined by a rectangle +// NOTE: Security checks are performed in case rectangle goes out of bounds +void ImageCrop(Image *image, Rectangle crop) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + // Security checks to validate crop rectangle + if (crop.x < 0) { crop.width += crop.x; crop.x = 0; } + if (crop.y < 0) { crop.height += crop.y; crop.y = 0; } + if ((crop.x + crop.width) > image->width) crop.width = image->width - crop.x; + if ((crop.y + crop.height) > image->height) crop.height = image->height - crop.y; + if ((crop.x > image->width) || (crop.y > image->height)) + { + TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds"); + 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 + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + + unsigned char *croppedData = (unsigned char *)RL_MALLOC((int)(crop.width*crop.height)*bytesPerPixel); + + // OPTION 1: Move cropped data line-by-line + for (int y = (int)crop.y, offsetSize = 0; y < (int)(crop.y + crop.height); y++) + { + memcpy(croppedData + offsetSize, ((unsigned char *)image->data) + (y*image->width + (int)crop.x)*bytesPerPixel, (int)crop.width*bytesPerPixel); + offsetSize += ((int)crop.width*bytesPerPixel); + } + + /* + // OPTION 2: Move cropped data pixel-by-pixel or byte-by-byte + for (int y = (int)crop.y; y < (int)(crop.y + crop.height); y++) + { + for (int x = (int)crop.x; x < (int)(crop.x + crop.width); x++) + { + //memcpy(croppedData + ((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel); + for (int i = 0; i < bytesPerPixel; i++) croppedData[((y - (int)crop.y)*(int)crop.width + (x - (int)crop.x))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i]; + } + } + */ + + RL_FREE(image->data); + image->data = croppedData; + image->width = (int)crop.width; + image->height = (int)crop.height; + } +} + +// Convert image data to desired format +void ImageFormat(Image *image, int newFormat) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if ((newFormat != 0) && (image->format != newFormat)) + { + if ((image->format < PIXELFORMAT_COMPRESSED_DXT1_RGB) && (newFormat < PIXELFORMAT_COMPRESSED_DXT1_RGB)) + { + Vector4 *pixels = LoadImageDataNormalized(*image); // Supports 8 to 32 bit per channel + + RL_FREE(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... + image->data = NULL; + image->format = newFormat; + + switch (image->format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*sizeof(unsigned char)); + + for (int i = 0; i < image->width*image->height; i++) + { + ((unsigned char *)image->data)[i] = (unsigned char)((pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f)*255.0f); + } + + } break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + 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++) + { + ((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); + } + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); + + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round(pixels[i].x*31.0f)); + g = (unsigned char)(round(pixels[i].y*63.0f)); + b = (unsigned char)(round(pixels[i].z*31.0f)); + + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; + } + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*3*sizeof(unsigned char)); + + for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) + { + ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f); + ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f); + ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f); + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); + + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + unsigned char a = 0; + + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round(pixels[i].x*31.0f)); + g = (unsigned char)(round(pixels[i].y*31.0f)); + b = (unsigned char)(round(pixels[i].z*31.0f)); + a = (pixels[i].w > ((float)PIXELFORMAT_UNCOMPRESSED_R5G5B5A1_ALPHA_THRESHOLD/255.0f))? 1 : 0; + + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; + } + + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); + + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + unsigned char a = 0; + + for (int i = 0; i < image->width*image->height; i++) + { + r = (unsigned char)(round(pixels[i].x*15.0f)); + g = (unsigned char)(round(pixels[i].y*15.0f)); + b = (unsigned char)(round(pixels[i].z*15.0f)); + a = (unsigned char)(round(pixels[i].w*15.0f)); + + ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; + } + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + image->data = (unsigned char *)RL_MALLOC(image->width*image->height*4*sizeof(unsigned char)); + + for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) + { + ((unsigned char *)image->data)[i] = (unsigned char)(pixels[k].x*255.0f); + ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].y*255.0f); + ((unsigned char *)image->data)[i + 2] = (unsigned char)(pixels[k].z*255.0f); + ((unsigned char *)image->data)[i + 3] = (unsigned char)(pixels[k].w*255.0f); + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R32: + { + // WARNING: Image is converted to GRAYSCALE equivalent 32bit + + image->data = (float *)RL_MALLOC(image->width*image->height*sizeof(float)); + + for (int i = 0; i < image->width*image->height; i++) + { + ((float *)image->data)[i] = (float)(pixels[i].x*0.299f + pixels[i].y*0.587f + pixels[i].z*0.114f); + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: + { + image->data = (float *)RL_MALLOC(image->width*image->height*3*sizeof(float)); + + for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) + { + ((float *)image->data)[i] = pixels[k].x; + ((float *)image->data)[i + 1] = pixels[k].y; + ((float *)image->data)[i + 2] = pixels[k].z; + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + { + image->data = (float *)RL_MALLOC(image->width*image->height*4*sizeof(float)); + + for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) + { + ((float *)image->data)[i] = pixels[k].x; + ((float *)image->data)[i + 1] = pixels[k].y; + ((float *)image->data)[i + 2] = pixels[k].z; + ((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 + // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost + if (image->mipmaps > 1) + { + image->mipmaps = 1; + #if defined(SUPPORT_IMAGE_MANIPULATION) + if (image->data != NULL) ImageMipmaps(image); + #endif + } + } + else TRACELOG(LOG_WARNING, "IMAGE: Data format is compressed, can not be converted"); + } +} + +// 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) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + // Calculate next power-of-two values + // NOTE: Just add the required amount of pixels at the right and bottom sides of image... + int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); + int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); + + // Check if POT texture generation is required (if texture is not already POT) + if ((potWidth != image->width) || (potHeight != image->height)) ImageResizeCanvas(image, potWidth, potHeight, 0, 0, fill); +} + +// Crop image depending on alpha value +// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f +void ImageAlphaCrop(Image *image, float threshold) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + Rectangle crop = GetImageAlphaBorder(*image, threshold); + + // Crop if rectangle is valid + if (((int)crop.width != 0) && ((int)crop.height != 0)) ImageCrop(image, crop); +} + +// Clear alpha channel to desired color +// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f +void ImageAlphaClear(Image *image, Color color, float threshold) +{ + // 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 + { + switch (image->format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + unsigned char thresholdValue = (unsigned char)(threshold*255.0f); + for (int i = 1; i < image->width*image->height*2; i += 2) + { + if (((unsigned char *)image->data)[i] <= thresholdValue) + { + ((unsigned char *)image->data)[i - 1] = color.r; + ((unsigned char *)image->data)[i] = color.a; + } + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + unsigned char thresholdValue = ((threshold < 0.5f)? 0 : 1); + + unsigned char r = (unsigned char)(round((float)color.r*31.0f)); + unsigned char g = (unsigned char)(round((float)color.g*31.0f)); + unsigned char b = (unsigned char)(round((float)color.b*31.0f)); + unsigned char a = (color.a < 128)? 0 : 1; + + for (int i = 0; i < image->width*image->height; i++) + { + if ((((unsigned short *)image->data)[i] & 0b0000000000000001) <= thresholdValue) + { + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; + } + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + unsigned char thresholdValue = (unsigned char)(threshold*15.0f); + + unsigned char r = (unsigned char)(round((float)color.r*15.0f)); + unsigned char g = (unsigned char)(round((float)color.g*15.0f)); + unsigned char b = (unsigned char)(round((float)color.b*15.0f)); + unsigned char a = (unsigned char)(round((float)color.a*15.0f)); + + for (int i = 0; i < image->width*image->height; i++) + { + if ((((unsigned short *)image->data)[i] & 0x000f) <= thresholdValue) + { + ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; + } + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + unsigned char thresholdValue = (unsigned char)(threshold*255.0f); + for (int i = 3; i < image->width*image->height*4; i += 4) + { + if (((unsigned char *)image->data)[i] <= thresholdValue) + { + ((unsigned char *)image->data)[i - 3] = color.r; + ((unsigned char *)image->data)[i - 2] = color.g; + ((unsigned char *)image->data)[i - 1] = color.b; + ((unsigned char *)image->data)[i] = color.a; + } + } + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + { + for (int i = 3; i < image->width*image->height*4; i += 4) + { + if (((float *)image->data)[i] <= threshold) + { + ((float *)image->data)[i - 3] = (float)color.r/255.0f; + ((float *)image->data)[i - 2] = (float)color.g/255.0f; + ((float *)image->data)[i - 1] = (float)color.b/255.0f; + ((float *)image->data)[i] = (float)color.a/255.0f; + } + } + } 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; + } + } +} + +// Apply alpha mask to image +// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit) +// NOTE 2: alphaMask should be same size as image +void ImageAlphaMask(Image *image, Image alphaMask) +{ + if ((image->width != alphaMask.width) || (image->height != alphaMask.height)) + { + TRACELOG(LOG_WARNING, "IMAGE: Alpha mask must be same size as image"); + } + else if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) + { + TRACELOG(LOG_WARNING, "IMAGE: Alpha mask can not be applied to compressed data formats"); + } + else + { + // Force mask to be Grayscale + Image mask = ImageCopy(alphaMask); + if (mask.format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE); + + // In case image is only grayscale, we just add alpha channel + if (image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + { + unsigned char *data = (unsigned char *)RL_MALLOC(image->width*image->height*2); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 0; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2) + { + data[k] = ((unsigned char *)image->data)[i]; + data[k + 1] = ((unsigned char *)mask.data)[i]; + } + + RL_FREE(image->data); + image->data = data; + image->format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA; + } + else + { + // Convert image to RGBA + if (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } + } + + UnloadImage(mask); + } +} + +// Premultiply alpha channel +void ImageAlphaPremultiply(Image *image) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + float alpha = 0.0f; + Color *pixels = LoadImageColors(*image); + + for (int i = 0; i < image->width*image->height; i++) + { + if (pixels[i].a == 0) + { + pixels[i].r = 0; + pixels[i].g = 0; + pixels[i].b = 0; + } + else if (pixels[i].a < 255) + { + alpha = (float)pixels[i].a/255.0f; + pixels[i].r = (unsigned char)((float)pixels[i].r*alpha); + pixels[i].g = (unsigned char)((float)pixels[i].g*alpha); + pixels[i].b = (unsigned char)((float)pixels[i].b*alpha); + } + } + + RL_FREE(image->data); + + int format = image->format; + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} + +// Apply box blur to image +void ImageBlurGaussian(Image *image, int blurSize) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + ImageAlphaPremultiply(image); + + 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++) + { + pixelsCopy1[i].x = pixels[i].r; + pixelsCopy1[i].y = pixels[i].g; + pixelsCopy1[i].z = pixels[i].b; + pixelsCopy1[i].w = pixels[i].a; + } + + // 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++) + { + 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; + } + } + + // 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; + } + else + { + startRange = -kernelWidth/2; + endRange = kernelWidth/2 + 1; + } + + for (int x = 0; x < image->height; x++) + { + for (int y = 0; y < image->width; y++) + { + 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); + + 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; + } + } + } + + 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; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + ImageFormat(image, format); +} + +// Generate all mipmap levels for a provided image +// NOTE 1: Supports POT and NPOT images +// NOTE 2: image.data is scaled to include mipmap levels +// NOTE 3: Mipmaps format is the same as base image +void ImageMipmaps(Image *image) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + int mipCount = 1; // Required mipmap levels count (including base level) + int mipWidth = image->width; // Base image width + int mipHeight = image->height; // Base image height + int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); // Image data size (in bytes) + + // Count mipmap levels required + while ((mipWidth != 1) || (mipHeight != 1)) + { + if (mipWidth != 1) mipWidth /= 2; + if (mipHeight != 1) mipHeight /= 2; + + // Security check for NPOT textures + if (mipWidth < 1) mipWidth = 1; + if (mipHeight < 1) mipHeight = 1; + + TRACELOGD("IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize); + + mipCount++; + mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format); // Add mipmap size (in bytes) + } + + if (image->mipmaps < mipCount) + { + void *temp = RL_REALLOC(image->data, mipSize); + + if (temp != NULL) image->data = temp; // Assign new pointer (new size) to store mipmaps data + 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; + + mipWidth = image->width; + mipHeight = image->height; + mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); + Image imCopy = ImageCopy(*image); + + for (int i = 1; i < mipCount; i++) + { + nextmip += mipSize; + + mipWidth /= 2; + mipHeight /= 2; + + // Security check for NPOT textures + if (mipWidth < 1) mipWidth = 1; + 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, +// dithered data is stored in the LSB part of the unsigned short +void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (image->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) + { + TRACELOG(LOG_WARNING, "IMAGE: Compressed data formats can not be dithered"); + return; + } + + if ((rBpp + gBpp + bBpp + aBpp) > 16) + { + TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); + } + else + { + Color *pixels = LoadImageColors(*image); + + RL_FREE(image->data); // free old image data + + if ((image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) + { + TRACELOG(LOG_WARNING, "IMAGE: Format is already 16bpp or lower, dithering could have no effect"); + } + + // Define new image format, check if desired bpp match internal known format + if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G6B5; + else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1; + else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4; + else + { + image->format = 0; + TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); + } + + // NOTE: We will store the dithered data as unsigned short (16bpp) + image->data = (unsigned short *)RL_MALLOC(image->width*image->height*sizeof(unsigned short)); + + Color oldPixel = WHITE; + Color newPixel = WHITE; + + int rError, gError, bError; + unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition + + #define MIN(a,b) (((a)<(b))?(a):(b)) + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + oldPixel = pixels[y*image->width + x]; + + // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) + newPixel.r = oldPixel.r >> (8 - rBpp); // R bits + newPixel.g = oldPixel.g >> (8 - gBpp); // G bits + newPixel.b = oldPixel.b >> (8 - bBpp); // B bits + newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering) + + // NOTE: Error must be computed between new and old pixel but using same number of bits! + // We want to know how much color precision we have lost... + rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); + gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); + bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); + + pixels[y*image->width + x] = newPixel; + + // NOTE: Some cases are out of the array and should be ignored + if (x < (image->width - 1)) + { + pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); + pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); + pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); + } + + if ((x > 0) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); + pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); + } + + if (y < (image->height - 1)) + { + pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); + pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); + } + + if ((x < (image->width - 1)) && (y < (image->height - 1))) + { + pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); + pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); + } + + rPixel = (unsigned short)newPixel.r; + gPixel = (unsigned short)newPixel.g; + bPixel = (unsigned short)newPixel.b; + aPixel = (unsigned short)newPixel.a; + + ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; + } + } + + UnloadImageColors(pixels); + } +} + +// Flip image vertically +void ImageFlipVertical(Image *image) +{ + // 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 + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel); + + for (int i = (image->height - 1), offsetSize = 0; i >= 0; i--) + { + memcpy(flippedData + offsetSize, ((unsigned char *)image->data) + i*image->width*bytesPerPixel, image->width*bytesPerPixel); + offsetSize += image->width*bytesPerPixel; + } + + RL_FREE(image->data); + image->data = flippedData; + } +} + +// Flip image horizontally +void ImageFlipHorizontal(Image *image) +{ + // 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 + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *flippedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + // OPTION 1: Move pixels with memcpy() + //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 + for (int i = 0; i < bytesPerPixel; i++) flippedData[(y*image->width + x)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - 1 - x))*bytesPerPixel + i]; + } + } + + RL_FREE(image->data); + image->data = flippedData; + + /* + // OPTION 3: Faster implementation (specific for 32bit pixels) + // NOTE: It does not require additional allocations + uint32_t *ptr = (uint32_t *)image->data; + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width/2; x++) + { + uint32_t backup = ptr[y*image->width + x]; + ptr[y*image->width + x] = ptr[y*image->width + (image->width - 1 - x)]; + ptr[y*image->width + (image->width - 1 - x)] = backup; + } + } + */ + } +} + +// 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) +{ + // 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 + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + //memcpy(rotatedData + (x*image->height + (image->height - y - 1))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + x)*bytesPerPixel, bytesPerPixel); + for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + (image->height - y - 1))*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + x)*bytesPerPixel + i]; + } + } + + RL_FREE(image->data); + image->data = rotatedData; + int width = image->width; + int height = image-> height; + + image->width = height; + image->height = width; + } +} + +// Rotate image counter-clockwise 90deg +void ImageRotateCCW(Image *image) +{ + // 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 + { + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *rotatedData = (unsigned char *)RL_MALLOC(image->width*image->height*bytesPerPixel); + + for (int y = 0; y < image->height; y++) + { + for (int x = 0; x < image->width; x++) + { + //memcpy(rotatedData + (x*image->height + y))*bytesPerPixel, ((unsigned char *)image->data) + (y*image->width + (image->width - x - 1))*bytesPerPixel, bytesPerPixel); + for (int i = 0; i < bytesPerPixel; i++) rotatedData[(x*image->height + y)*bytesPerPixel + i] = ((unsigned char *)image->data)[(y*image->width + (image->width - x - 1))*bytesPerPixel + i]; + } + } + + RL_FREE(image->data); + image->data = rotatedData; + int width = image->width; + int height = image-> height; + + image->width = height; + image->height = width; + } +} + +// Modify image color: tint +void ImageColorTint(Image *image, Color color) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + 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); + + pixels[i].r = r; + pixels[i].g = g; + pixels[i].b = b; + pixels[i].a = a; + } + + int format = image->format; + RL_FREE(image->data); + + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} + +// Modify image color: invert +void ImageColorInvert(Image *image) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + Color *pixels = LoadImageColors(*image); + + for (int i = 0; i < image->width*image->height; i++) + { + pixels[i].r = 255 - pixels[i].r; + pixels[i].g = 255 - pixels[i].g; + pixels[i].b = 255 - pixels[i].b; + } + + int format = image->format; + RL_FREE(image->data); + + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} + +// Modify image color: grayscale +void ImageColorGrayscale(Image *image) +{ + ImageFormat(image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE); +} + +// Modify image color: contrast +// NOTE: Contrast values between -100 and 100 +void ImageColorContrast(Image *image, float contrast) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (contrast < -100) contrast = -100; + if (contrast > 100) contrast = 100; + + contrast = (100.0f + contrast)/100.0f; + contrast *= contrast; + + Color *pixels = LoadImageColors(*image); + + for (int i = 0; i < image->width*image->height; i++) + { + 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; + + 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 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; + + pixels[i].r = (unsigned char)pR; + pixels[i].g = (unsigned char)pG; + pixels[i].b = (unsigned char)pB; + } + + int format = image->format; + RL_FREE(image->data); + + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} + +// Modify image color: brightness +// NOTE: Brightness values between -255 and 255 +void ImageColorBrightness(Image *image, int brightness) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + if (brightness < -255) brightness = -255; + if (brightness > 255) brightness = 255; + + Color *pixels = LoadImageColors(*image); + + for (int i = 0; i < image->width*image->height; i++) + { + int cR = pixels[i].r + brightness; + int cG = pixels[i].g + brightness; + int cB = pixels[i].b + brightness; + + if (cR < 0) cR = 1; + if (cR > 255) cR = 255; + + if (cG < 0) cG = 1; + if (cG > 255) cG = 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; + } + + int format = image->format; + RL_FREE(image->data); + + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} + +// Modify image color: replace color +void ImageColorReplace(Image *image, Color color, Color replace) +{ + // Security check to avoid program crash + if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return; + + Color *pixels = LoadImageColors(*image); + + for (int i = 0; i < image->width*image->height; i++) + { + if ((pixels[i].r == color.r) && + (pixels[i].g == color.g) && + (pixels[i].b == color.b) && + (pixels[i].a == color.a)) + { + pixels[i].r = replace.r; + pixels[i].g = replace.g; + pixels[i].b = replace.b; + pixels[i].a = replace.a; + } + } + + int format = image->format; + RL_FREE(image->data); + + image->data = pixels; + image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + ImageFormat(image, format); +} +#endif // SUPPORT_IMAGE_MANIPULATION + +// Load color data from image as a Color array (RGBA - 32bit) +// NOTE: Memory allocated should be freed using UnloadImageColors(); +Color *LoadImageColors(Image image) +{ + if ((image.width == 0) || (image.height == 0)) return NULL; + + Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color)); + + if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats"); + else + { + if ((image.format == PIXELFORMAT_UNCOMPRESSED_R32) || + (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) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + pixels[i].r = ((unsigned char *)image.data)[i]; + pixels[i].g = ((unsigned char *)image.data)[i]; + pixels[i].b = ((unsigned char *)image.data)[i]; + pixels[i].a = 255; + + } break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + pixels[i].r = ((unsigned char *)image.data)[k]; + pixels[i].g = ((unsigned char *)image.data)[k]; + pixels[i].b = ((unsigned char *)image.data)[k]; + pixels[i].a = ((unsigned char *)image.data)[k + 1]; + + k += 2; + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); + pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); + pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); + pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); + pixels[i].a = 255; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + unsigned short pixel = ((unsigned short *)image.data)[i]; + + pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); + pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); + pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); + pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + pixels[i].r = ((unsigned char *)image.data)[k]; + pixels[i].g = ((unsigned char *)image.data)[k + 1]; + pixels[i].b = ((unsigned char *)image.data)[k + 2]; + pixels[i].a = ((unsigned char *)image.data)[k + 3]; + + k += 4; + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + pixels[i].r = (unsigned char)((unsigned char *)image.data)[k]; + pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1]; + pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2]; + pixels[i].a = 255; + + k += 3; + } break; + case PIXELFORMAT_UNCOMPRESSED_R32: + { + pixels[i].r = (unsigned char)(((float *)image.data)[k]*255.0f); + pixels[i].g = 0; + pixels[i].b = 0; + pixels[i].a = 255; + + k += 1; + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: + { + 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 = 255; + + k += 3; + } break; + 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); + + k += 4; + } break; + default: break; + } + } + } + + return pixels; +} + +// 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) +{ + #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) + + int palCount = 0; + Color *palette = NULL; + Color *pixels = LoadImageColors(image); + + if (pixels != NULL) + { + palette = (Color *)RL_MALLOC(maxPaletteSize*sizeof(Color)); + + for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK; // Set all colors to BLANK + + for (int i = 0; i < image.width*image.height; i++) + { + if (pixels[i].a > 0) + { + bool colorInPalette = false; + + // Check if the color is already on palette + for (int j = 0; j < maxPaletteSize; j++) + { + if (COLOR_EQUAL(pixels[i], palette[j])) + { + colorInPalette = true; + break; + } + } + + // Store color if not on the palette + if (!colorInPalette) + { + palette[palCount] = pixels[i]; // Add pixels[i] to palette + palCount++; + + // We reached the limit of colors supported by palette + if (palCount >= maxPaletteSize) + { + i = image.width*image.height; // Finish palette get + TRACELOG(LOG_WARNING, "IMAGE: Palette is greater than %i colors", maxPaletteSize); + } + } + } + } + + UnloadImageColors(pixels); + } + + *colorCount = palCount; + + return palette; +} + +// Unload color data loaded with LoadImageColors() +void UnloadImageColors(Color *colors) +{ + RL_FREE(colors); +} + +// Unload colors palette loaded with LoadImagePalette() +void UnloadImagePalette(Color *colors) +{ + RL_FREE(colors); +} + +// Get image alpha border rectangle +// NOTE: Threshold is defined as a percentage: 0.0f -> 1.0f +Rectangle GetImageAlphaBorder(Image image, float threshold) +{ + Rectangle crop = { 0 }; + + Color *pixels = LoadImageColors(image); + + if (pixels != NULL) + { + int xMin = 65536; // Define a big enough number + int xMax = 0; + int yMin = 65536; + int yMax = 0; + + for (int y = 0; y < image.height; y++) + { + for (int x = 0; x < image.width; x++) + { + if (pixels[y*image.width + x].a > (unsigned char)(threshold*255.0f)) + { + if (x < xMin) xMin = x; + if (x > xMax) xMax = x; + if (y < yMin) yMin = y; + if (y > yMax) yMax = y; + } + } + } + + // Check for empty blank image + if ((xMin != 65536) && (xMax != 65536)) + { + crop = (Rectangle){ (float)xMin, (float)yMin, (float)((xMax + 1) - xMin), (float)((yMax + 1) - yMin) }; + } + + UnloadImageColors(pixels); + } + + 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); + } +} + +// Draw pixel within an image +// NOTE: Compressed image formats not supported +void ImageDrawPixel(Image *dst, int x, int y, Color color) +{ + // Security check to avoid program crash + if ((dst->data == NULL) || (x < 0) || (x >= dst->width) || (y < 0) || (y >= dst->height)) return; + + switch (dst->format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + // NOTE: Calculate grayscale equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f); + + ((unsigned char *)dst->data)[y*dst->width + x] = gray; + + } break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + // NOTE: Calculate grayscale equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f); + + ((unsigned char *)dst->data)[(y*dst->width + x)*2] = gray; + ((unsigned char *)dst->data)[(y*dst->width + x)*2 + 1] = color.a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + // NOTE: Calculate R5G6B5 equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + + unsigned char r = (unsigned char)(round(coln.x*31.0f)); + unsigned char g = (unsigned char)(round(coln.y*63.0f)); + unsigned char b = (unsigned char)(round(coln.z*31.0f)); + + ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + // NOTE: Calculate R5G5B5A1 equivalent color + Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f }; + + 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 short *)dst->data)[y*dst->width + x] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + // NOTE: Calculate R5G5B5A1 equivalent color + Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f }; + + unsigned char r = (unsigned char)(round(coln.x*15.0f)); + unsigned char g = (unsigned char)(round(coln.y*15.0f)); + unsigned char b = (unsigned char)(round(coln.z*15.0f)); + unsigned char a = (unsigned char)(round(coln.w*15.0f)); + + ((unsigned short *)dst->data)[y*dst->width + x] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + ((unsigned char *)dst->data)[(y*dst->width + x)*3] = color.r; + ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 1] = color.g; + ((unsigned char *)dst->data)[(y*dst->width + x)*3 + 2] = color.b; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + ((unsigned char *)dst->data)[(y*dst->width + x)*4] = color.r; + ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 1] = color.g; + ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 2] = color.b; + ((unsigned char *)dst->data)[(y*dst->width + x)*4 + 3] = color.a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R32: + { + // 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 }; + + ((float *)dst->data)[y*dst->width + x] = coln.x*0.299f + coln.y*0.587f + coln.z*0.114f; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32: + { + // 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 }; + + ((float *)dst->data)[(y*dst->width + x)*3] = coln.x; + ((float *)dst->data)[(y*dst->width + x)*3 + 1] = coln.y; + ((float *)dst->data)[(y*dst->width + x)*3 + 2] = coln.z; + } break; + case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: + { + // 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 }; + + ((float *)dst->data)[(y*dst->width + x)*4] = coln.x; + ((float *)dst->data)[(y*dst->width + x)*4 + 1] = coln.y; + ((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; + } +} + +// Draw pixel within an image (Vector version) +void ImageDrawPixelV(Image *dst, Vector2 position, Color color) +{ + ImageDrawPixel(dst, (int)position.x, (int)position.y, 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; + + // Determine if the line is more vertical than horizontal + if (abs(shortLen) > abs(longLen)) + { + // Swap the lengths if the line is more vertical + int temp = shortLen; + shortLen = longLen; + longLen = temp; + yLonger = true; + } + + // 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) + { + // 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); + } + } +} + +// 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 + } + } +} + +// Draw circle within an image +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 decesionParameter = 3 - 2*radius; + + while (y >= x) + { + ImageDrawPixel(dst, centerX + x, centerY + y, color); + ImageDrawPixel(dst, centerX - x, centerY + y, color); + ImageDrawPixel(dst, centerX + x, centerY - y, color); + ImageDrawPixel(dst, centerX - x, centerY - y, color); + ImageDrawPixel(dst, centerX + y, centerY + x, color); + ImageDrawPixel(dst, centerX - y, centerY + x, color); + ImageDrawPixel(dst, centerX + y, centerY - x, color); + ImageDrawPixel(dst, centerX - y, centerY - x, color); + x++; + + if (decesionParameter > 0) + { + y--; + decesionParameter = decesionParameter + 4*(x - y) + 10; + } + else decesionParameter = decesionParameter + 4*x + 6; + } +} + +// Draw circle outline within an image (Vector version) +void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color) +{ + ImageDrawCircleLines(dst, (int)center.x, (int)center.y, radius, color); +} + +// Draw rectangle within an image +void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color) +{ + ImageDrawRectangleRec(dst, (Rectangle){ (float)posX, (float)posY, (float)width, (float)height }, color); +} + +// Draw rectangle within an image (Vector version) +void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color) +{ + ImageDrawRectangle(dst, (int)position.x, (int)position.y, (int)size.x, (int)size.y, color); +} + +// Draw rectangle within an image +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 sx = (int)rec.x; + + 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++) + { + 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); + } +} + +// Draw rectangle lines within an image +void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color) +{ + ImageDrawRectangle(dst, (int)rec.x, (int)rec.y, (int)rec.width, thick, color); + ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + thick), thick, (int)(rec.height - thick*2), color); + ImageDrawRectangle(dst, (int)(rec.x + rec.width - thick), (int)(rec.y + thick), thick, (int)(rec.height - thick*2), 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) +{ + // Security check to avoid program crash + if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0) || + (src.data == NULL) || (src.width == 0) || (src.height == 0)) return; + + if (dst->format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "Image drawing not supported for compressed formats"); + else + { + Image srcMod = { 0 }; // Source copy (in case it was required) + Image *srcPtr = &src; // Pointer to source image + bool useSrcMod = false; // Track source copy required + + // Source rectangle out-of-bounds security checks + if (srcRec.x < 0) { srcRec.width += srcRec.x; srcRec.x = 0; } + if (srcRec.y < 0) { srcRec.height += srcRec.y; srcRec.y = 0; } + if ((srcRec.x + srcRec.width) > src.width) srcRec.width = src.width - srcRec.x; + 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 + if (((int)srcRec.width != (int)dstRec.width) || ((int)srcRec.height != (int)dstRec.height)) + { + srcMod = ImageFromImage(src, srcRec); // Create image from another image + ImageResize(&srcMod, (int)dstRec.width, (int)dstRec.height); // Resize to destination rectangle + srcRec = (Rectangle){ 0, 0, (float)srcMod.width, (float)srcMod.height }; + + srcPtr = &srcMod; + useSrcMod = true; + } + + // Destination rectangle out-of-bounds security checks + if (dstRec.x < 0) + { + srcRec.x -= dstRec.x; + srcRec.width += dstRec.x; + dstRec.x = 0; + } + else if ((dstRec.x + srcRec.width) > dst->width) srcRec.width = dst->width - dstRec.x; + + if (dstRec.y < 0) + { + srcRec.y -= dstRec.y; + srcRec.height += dstRec.y; + dstRec.y = 0; + } + else if ((dstRec.y + srcRec.height) > dst->height) srcRec.height = dst->height - dstRec.y; + + if (dst->width < srcRec.width) srcRec.width = (float)dst->width; + if (dst->height < srcRec.height) srcRec.height = (float)dst->height; + + // This blitting method is quite fast! The process followed is: + // for every pixel -> [get_src_format/get_dst_format -> blend -> format_to_dst] + // Some optimization ideas: + // [x] Avoid creating source copy if not required (no resize required) + // [x] Optimize ImageResize() for pixel format (alternative: ImageResizeNN()) + // [x] Optimize ColorAlphaBlend() to avoid processing (alpha = 0) and (alpha = 1) + // [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 + + 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; + + int strideDst = GetPixelDataSize(dst->width, 1, dst->format); + int bytesPerPixelDst = strideDst/(dst->width); + + int strideSrc = GetPixelDataSize(srcPtr->width, 1, srcPtr->format); + int bytesPerPixelSrc = strideSrc/(srcPtr->width); + + unsigned char *pSrcBase = (unsigned char *)srcPtr->data + ((int)srcRec.y*srcPtr->width + (int)srcRec.x)*bytesPerPixelSrc; + unsigned char *pDstBase = (unsigned char *)dst->data + ((int)dstRec.y*dst->width + (int)dstRec.x)*bytesPerPixelDst; + + for (int y = 0; y < (int)srcRec.height; y++) + { + unsigned char *pSrc = pSrcBase; + unsigned char *pDst = pDstBase; + + // Fast path: Avoid moving pixel by pixel if no blend required and same format + if (!blendRequired && (srcPtr->format == dst->format)) memcpy(pDst, pSrc, (int)(srcRec.width)*bytesPerPixelSrc); + else + { + for (int x = 0; x < (int)srcRec.width; x++) + { + colSrc = GetPixelColor(pSrc, srcPtr->format); + colDst = GetPixelColor(pDst, dst->format); + + // Fast path: Avoid blend if source has no alpha to blend + if (blendRequired) blend = ColorAlphaBlend(colDst, colSrc, tint); + else blend = colSrc; + + SetPixelColor(pDst, blend, dst->format); + + pDst += bytesPerPixelDst; + pSrc += bytesPerPixelSrc; + } + } + + pSrcBase += strideSrc; + pDstBase += strideDst; + } + + 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 +} + +// Draw text (custom sprite font) within an image (destination) +void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint) +{ + Image imText = ImageTextEx(font, text, fontSize, spacing, tint); + + Rectangle srcRec = { 0.0f, 0.0f, (float)imText.width, (float)imText.height }; + Rectangle dstRec = { position.x, position.y, (float)imText.width, (float)imText.height }; + + ImageDraw(dst, imText, srcRec, dstRec, WHITE); + + UnloadImage(imText); +} + +//------------------------------------------------------------------------------------ +// Texture loading functions +//------------------------------------------------------------------------------------ +// Load texture from file into GPU memory (VRAM) +Texture2D LoadTexture(const char *fileName) +{ + Texture2D texture = { 0 }; + + Image image = LoadImage(fileName); + + if (image.data != NULL) + { + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + + return texture; +} + +// Load a texture from image data +// NOTE: image is not unloaded, it must be done manually +Texture2D LoadTextureFromImage(Image image) +{ + Texture2D texture = { 0 }; + + if ((image.width != 0) && (image.height != 0)) + { + texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps); + } + else TRACELOG(LOG_WARNING, "IMAGE: Data is not valid to load texture"); + + texture.width = image.width; + texture.height = image.height; + texture.mipmaps = image.mipmaps; + texture.format = image.format; + + return texture; +} + +// Load cubemap from image, multiple image cubemap layouts supported +TextureCubemap LoadTextureCubemap(Image image, int layout) +{ + TextureCubemap cubemap = { 0 }; + + if (layout == CUBEMAP_LAYOUT_AUTO_DETECT) // Try to automatically guess layout type + { + // Check image width/height to determine the type of cubemap provided + if (image.width > image.height) + { + 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.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; + + // 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 + } + /*else if (layout == CUBEMAP_LAYOUT_PANORAMA) + { + // TODO: implement panorama by converting 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; + else if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR) + { + faceRecs[0].x = (float)size; faceRecs[0].y = (float)size; + faceRecs[1].x = (float)size; faceRecs[1].y = (float)size*3; + faceRecs[2].x = (float)size; faceRecs[2].y = 0; + faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2; + faceRecs[4].x = 0; faceRecs[4].y = (float)size; + faceRecs[5].x = (float)size*2; faceRecs[5].y = (float)size; + } + else if (layout == CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE) + { + faceRecs[0].x = (float)size*2; faceRecs[0].y = (float)size; + faceRecs[1].x = 0; faceRecs[1].y = (float)size; + faceRecs[2].x = (float)size; faceRecs[2].y = 0; + faceRecs[3].x = (float)size; faceRecs[3].y = (float)size*2; + faceRecs[4].x = (float)size; faceRecs[4].y = (float)size; + faceRecs[5].x = (float)size*3; faceRecs[5].y = (float)size; + } + + // Convert image data to 6 faces in a vertical column, that's the optimum layout for loading + 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); + } + + // 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); + + if (cubemap.id != 0) + { + cubemap.format = faces.format; + cubemap.mipmaps = faces.mipmaps; + } + else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image"); + + UnloadImage(faces); + } + else TRACELOG(LOG_WARNING, "IMAGE: Failed to detect cubemap image layout"); + + return cubemap; +} + +// Load texture for rendering (framebuffer) +// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer +RenderTexture2D LoadRenderTexture(int width, int height) +{ + RenderTexture2D target = { 0 }; + + target.id = rlLoadFramebuffer(); // Load an empty framebuffer + + if (target.id > 0) + { + rlEnableFramebuffer(target.id); + + // Create color texture (default to RGBA) + target.texture.id = rlLoadTexture(NULL, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + target.texture.width = width; + target.texture.height = height; + target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + target.texture.mipmaps = 1; + + // Create depth renderbuffer/texture + target.depth.id = rlLoadTextureDepth(width, height, true); + target.depth.width = width; + target.depth.height = height; + target.depth.format = 19; //DEPTH_COMPONENT_24BIT? + target.depth.mipmaps = 1; + + // Attach color texture and depth renderbuffer/texture to FBO + rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); + rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0); + + // Check if fbo is complete with attachments (valid) + if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); + + rlDisableFramebuffer(); + } + else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); + + 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) +{ + if (texture.id > 0) + { + rlUnloadTexture(texture.id); + + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded texture data from VRAM (GPU)", texture.id); + } +} + +// 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); + } + + // NOTE: Depth texture/renderbuffer is automatically + // queried and deleted before deleting framebuffer + rlUnloadFramebuffer(target.id); + } +} + +// Update GPU texture with new data +// NOTE: pixels data must match texture.format +void UpdateTexture(Texture2D texture, const void *pixels) +{ + rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels); +} + +// Update GPU texture rectangle with new data +// NOTE: pixels data must match texture.format +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); +} + +//------------------------------------------------------------------------------------ +// Texture configuration functions +//------------------------------------------------------------------------------------ +// Generate GPU mipmaps for a texture +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); +} + +// Set texture scaling filter mode +void SetTextureFilter(Texture2D texture, int filter) +{ + switch (filter) + { + case TEXTURE_FILTER_POINT: + { + if (texture.mipmaps > 1) + { + // RL_TEXTURE_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_NEAREST); + + // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST); + } + else + { + // RL_TEXTURE_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_NEAREST); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_NEAREST); + } + } break; + case TEXTURE_FILTER_BILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) + // Alternative: RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST); + + // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR); + } + else + { + // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR); + } + } break; + case TEXTURE_FILTER_TRILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_TEXTURE_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_MIP_LINEAR); + + // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR); + } + else + { + TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id); + + // RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR); + } + } break; + case TEXTURE_FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 4); break; + case TEXTURE_FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 8); break; + case TEXTURE_FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_FILTER_ANISOTROPIC, 16); break; + default: break; + } +} + +// Set texture wrapping mode +void SetTextureWrap(Texture2D texture, int wrap) +{ + switch (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; + case TEXTURE_WRAP_CLAMP: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_CLAMP); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_CLAMP); + } break; + case TEXTURE_WRAP_MIRROR_REPEAT: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_REPEAT); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_REPEAT); + } break; + case TEXTURE_WRAP_MIRROR_CLAMP: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_MIRROR_CLAMP); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_MIRROR_CLAMP); + } break; + default: break; + } +} + +//------------------------------------------------------------------------------------ +// Texture drawing functions +//------------------------------------------------------------------------------------ +// Draw a texture +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 +void DrawTextureV(Texture2D texture, Vector2 position, Color tint) +{ + DrawTextureEx(texture, position, 0, 1.0f, tint); +} + +// Draw a texture 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 }; + Rectangle dest = { position.x, position.y, (float)texture.width*scale, (float)texture.height*scale }; + Vector2 origin = { 0.0f, 0.0f }; + + DrawTexturePro(texture, source, dest, origin, rotation, tint); +} + +// Draw a part of a texture (defined by a rectangle) +void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint) +{ + Rectangle dest = { position.x, position.y, fabsf(source.width), fabsf(source.height) }; + Vector2 origin = { 0.0f, 0.0f }; + + DrawTexturePro(texture, source, dest, origin, 0.0f, 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) +{ + // Check if texture is valid + if (texture.id > 0) + { + float width = (float)texture.width; + float height = (float)texture.height; + + bool flipX = false; + + 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 }; + Vector2 bottomRight = { 0 }; + + // Only calculate rotation if needed + if (rotation == 0.0f) + { + float x = dest.x - origin.x; + float y = dest.y - origin.y; + topLeft = (Vector2){ x, y }; + topRight = (Vector2){ x + dest.width, y }; + bottomLeft = (Vector2){ x, y + dest.height }; + bottomRight = (Vector2){ x + dest.width, y + dest.height }; + } + else + { + float sinRotation = sinf(rotation*DEG2RAD); + float cosRotation = cosf(rotation*DEG2RAD); + float x = dest.x; + float y = dest.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 + dest.width)*cosRotation - dy*sinRotation; + topRight.y = y + (dx + dest.width)*sinRotation + dy*cosRotation; + + bottomLeft.x = x + dx*cosRotation - (dy + dest.height)*sinRotation; + bottomLeft.y = y + dx*sinRotation + (dy + dest.height)*cosRotation; + + bottomRight.x = x + (dx + dest.width)*cosRotation - (dy + dest.height)*sinRotation; + bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation; + } + + rlSetTexture(texture.id); + rlBegin(RL_QUADS); + + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + // Top-left corner for texture and quad + if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height); + else rlTexCoord2f(source.x/width, source.y/height); + rlVertex2f(topLeft.x, topLeft.y); + + // Bottom-left corner for texture and quad + if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); + else rlTexCoord2f(source.x/width, (source.y + source.height)/height); + rlVertex2f(bottomLeft.x, bottomLeft.y); + + // Bottom-right corner for texture and quad + if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height); + else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); + rlVertex2f(bottomRight.x, bottomRight.y); + + // Top-right corner for texture and quad + if (flipX) rlTexCoord2f(source.x/width, source.y/height); + else rlTexCoord2f((source.x + source.width)/width, source.y/height); + rlVertex2f(topRight.x, topRight.y); + + rlEnd(); + rlSetTexture(0); + + // 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, + // just in case someone wants to do some performance test + /* + rlSetTexture(texture.id); + rlPushMatrix(); + rlTranslatef(dest.x, dest.y, 0.0f); + if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + rlTranslatef(-origin.x, -origin.y, 0.0f); + + rlBegin(RL_QUADS); + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + // Bottom-left corner for texture and quad + if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height); + else rlTexCoord2f(source.x/width, source.y/height); + rlVertex2f(0.0f, 0.0f); + + // Bottom-right corner for texture and quad + if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); + else rlTexCoord2f(source.x/width, (source.y + source.height)/height); + rlVertex2f(0.0f, dest.height); + + // Top-right corner for texture and quad + if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height); + else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); + rlVertex2f(dest.width, dest.height); + + // Top-left corner for texture and quad + if (flipX) rlTexCoord2f(source.x/width, source.y/height); + else rlTexCoord2f((source.x + source.width)/width, source.y/height); + rlVertex2f(dest.width, 0.0f); + rlEnd(); + rlPopMatrix(); + rlSetTexture(0); + */ + } +} + +// Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info +void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint) +{ + if (texture.id > 0) + { + 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; + + if (nPatchInfo.source.width < 0) nPatchInfo.source.x -= nPatchInfo.source.width; + if (nPatchInfo.source.height < 0) nPatchInfo.source.y -= nPatchInfo.source.height; + if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL) patchHeight = nPatchInfo.source.height; + if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL) patchWidth = nPatchInfo.source.width; + + bool drawCenter = true; + bool drawMiddle = true; + float leftBorder = (float)nPatchInfo.left; + float topBorder = (float)nPatchInfo.top; + float rightBorder = (float)nPatchInfo.right; + float bottomBorder = (float)nPatchInfo.bottom; + + // 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 + if (patchHeight <= (topBorder + bottomBorder) && nPatchInfo.layout != NPATCH_THREE_PATCH_HORIZONTAL) + { + drawMiddle = false; + topBorder = (topBorder/(topBorder + bottomBorder))*patchHeight; + bottomBorder = patchHeight - topBorder; + } + + Vector2 vertA, vertB, vertC, vertD; + vertA.x = 0.0f; // outer left + vertA.y = 0.0f; // outer top + vertB.x = leftBorder; // inner left + vertB.y = topBorder; // inner top + vertC.x = patchWidth - rightBorder; // inner right + vertC.y = patchHeight - bottomBorder; // inner bottom + vertD.x = patchWidth; // outer right + vertD.y = patchHeight; // outer bottom + + Vector2 coordA, coordB, coordC, coordD; + coordA.x = nPatchInfo.source.x/width; + coordA.y = nPatchInfo.source.y/height; + coordB.x = (nPatchInfo.source.x + leftBorder)/width; + coordB.y = (nPatchInfo.source.y + topBorder)/height; + coordC.x = (nPatchInfo.source.x + nPatchInfo.source.width - rightBorder)/width; + coordC.y = (nPatchInfo.source.y + nPatchInfo.source.height - bottomBorder)/height; + coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width; + coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height; + + rlSetTexture(texture.id); + + rlPushMatrix(); + rlTranslatef(dest.x, dest.y, 0.0f); + rlRotatef(rotation, 0.0f, 0.0f, 1.0f); + rlTranslatef(-origin.x, -origin.y, 0.0f); + + rlBegin(RL_QUADS); + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + if (nPatchInfo.layout == NPATCH_NINE_PATCH) + { + // ------------------------------------------------------------ + // TOP-LEFT QUAD + rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y); // Top-left corner for texture and quad + if (drawCenter) + { + // TOP-CENTER QUAD + rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y); // Top-left corner for texture and quad + } + // TOP-RIGHT QUAD + rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y); // Top-left corner for texture and quad + if (drawMiddle) + { + // ------------------------------------------------------------ + // MIDDLE-LEFT QUAD + rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y); // Top-left corner for texture and quad + if (drawCenter) + { + // MIDDLE-CENTER QUAD + rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y); // Top-right corner for texture and quad + rlTexCoord2f(coordB.x, coordB.y); rlVertex2f(vertB.x, vertB.y); // Top-left corner for texture and quad + } + + // MIDDLE-RIGHT QUAD + rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y); // Top-right corner for texture and quad + rlTexCoord2f(coordC.x, coordB.y); rlVertex2f(vertC.x, vertB.y); // Top-left corner for texture and quad + } + + // ------------------------------------------------------------ + // BOTTOM-LEFT QUAD + rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y); // Top-left corner for texture and quad + if (drawCenter) + { + // BOTTOM-CENTER QUAD + rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y); // Top-right corner for texture and quad + rlTexCoord2f(coordB.x, coordC.y); rlVertex2f(vertB.x, vertC.y); // Top-left corner for texture and quad + } + + // BOTTOM-RIGHT QUAD + rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y); // Top-right corner for texture and quad + rlTexCoord2f(coordC.x, coordC.y); rlVertex2f(vertC.x, vertC.y); // Top-left corner for texture and quad + } + else if (nPatchInfo.layout == NPATCH_THREE_PATCH_VERTICAL) + { + // TOP QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y); // Top-left corner for texture and quad + if (drawCenter) + { + // MIDDLE QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordB.y); rlVertex2f(vertD.x, vertB.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordB.y); rlVertex2f(vertA.x, vertB.y); // Top-left corner for texture and quad + } + // BOTTOM QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordC.y); rlVertex2f(vertD.x, vertC.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordC.y); rlVertex2f(vertA.x, vertC.y); // Top-left corner for texture and quad + } + else if (nPatchInfo.layout == NPATCH_THREE_PATCH_HORIZONTAL) + { + // LEFT QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordA.x, coordD.y); rlVertex2f(vertA.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordA.x, coordA.y); rlVertex2f(vertA.x, vertA.y); // Top-left corner for texture and quad + if (drawCenter) + { + // CENTER QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordB.x, coordD.y); rlVertex2f(vertB.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordB.x, coordA.y); rlVertex2f(vertB.x, vertA.y); // Top-left corner for texture and quad + } + // RIGHT QUAD + // ----------------------------------------------------------- + // Texture coords Vertices + rlTexCoord2f(coordC.x, coordD.y); rlVertex2f(vertC.x, vertD.y); // Bottom-left corner for texture and quad + rlTexCoord2f(coordD.x, coordD.y); rlVertex2f(vertD.x, vertD.y); // Bottom-right corner for texture and quad + rlTexCoord2f(coordD.x, coordA.y); rlVertex2f(vertD.x, vertA.y); // Top-right corner for texture and quad + rlTexCoord2f(coordC.x, coordA.y); rlVertex2f(vertC.x, vertA.y); // Top-left corner for texture and quad + } + rlEnd(); + rlPopMatrix(); + + rlSetTexture(0); + } +} + +// Check if two colors are equal +bool ColorIsEqual(Color col1, Color col2) +{ + bool result = false; + + if ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) result = true; + + return result; +} + +// Get 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; +} + +// Get 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; +} + +// Get color normalized as float [0..1] +Vector4 ColorNormalize(Color color) +{ + Vector4 result; + + result.x = (float)color.r/255.0f; + result.y = (float)color.g/255.0f; + result.z = (float)color.b/255.0f; + result.w = (float)color.a/255.0f; + + return result; +} + +// Get color from normalized values [0..1] +Color ColorFromNormalized(Vector4 normalized) +{ + Color result; + + result.r = (unsigned char)(normalized.x*255.0f); + result.g = (unsigned char)(normalized.y*255.0f); + result.b = (unsigned char)(normalized.z*255.0f); + result.a = (unsigned char)(normalized.w*255.0f); + + return result; +} + +// Get HSV values for a Color +// NOTE: Hue is returned as degrees [0..360] +Vector3 ColorToHSV(Color color) +{ + Vector3 hsv = { 0 }; + Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + float min, max, delta; + + 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 = NAN; // Undefined + 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; +} + +// Get 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] +// Saturation/Value are provided normalized: [0.0f..1.0f] +Color ColorFromHSV(float hue, float saturation, float value) +{ + Color color = { 0, 0, 0, 255 }; + + // Red channel + float k = fmodf((5.0f + hue/60.0f), 6); + float t = 4.0f - k; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; + color.r = (unsigned char)((value - value*saturation*k)*255.0f); + + // Green channel + k = fmodf((3.0f + hue/60.0f), 6); + t = 4.0f - k; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; + color.g = (unsigned char)((value - value*saturation*k)*255.0f); + + // Blue channel + k = fmodf((1.0f + hue/60.0f), 6); + t = 4.0f - k; + k = (t < k)? t : k; + k = (k < 1)? k : 1; + k = (k > 0)? k : 0; + color.b = (unsigned char)((value - value*saturation*k)*255.0f); + + 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 +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; +} + +// Get 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); + +//#define COLORALPHABLEND_FLOAT +#define COLORALPHABLEND_INTEGERS +#if defined(COLORALPHABLEND_INTEGERS) + if (src.a == 0) out = dst; + else if (src.a == 255) out = src; + else + { + unsigned int alpha = (unsigned int)src.a + 1; // We are shifting by 8 (dividing by 256), so we need to take that excess into account + out.a = (unsigned char)(((unsigned int)alpha*256 + (unsigned int)dst.a*(256 - alpha)) >> 8); + + if (out.a > 0) + { + out.r = (unsigned char)((((unsigned int)src.r*alpha*256 + (unsigned int)dst.r*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8); + out.g = (unsigned char)((((unsigned int)src.g*alpha*256 + (unsigned int)dst.g*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8); + out.b = (unsigned char)((((unsigned int)src.b*alpha*256 + (unsigned int)dst.b*(unsigned int)dst.a*(256 - alpha))/out.a) >> 8); + } + } +#endif +#if defined(COLORALPHABLEND_FLOAT) + if (src.a == 0) out = dst; + else if (src.a == 255) out = src; + else + { + Vector4 fdst = ColorNormalize(dst); + Vector4 fsrc = ColorNormalize(src); + Vector4 ftint = ColorNormalize(tint); + Vector4 fout = { 0 }; + + fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w); + + if (fout.w > 0.0f) + { + fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w; + fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w; + fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w; + } + + out = (Color){ (unsigned char)(fout.x*255.0f), (unsigned char)(fout.y*255.0f), (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) }; + } +#endif + + 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) +{ + 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; +} + +// Get color from a pixel from certain format +Color GetPixelColor(void *srcPtr, int format) +{ + Color color = { 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_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; + + } 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; + + } 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); + + } break; + default: break; + } + + return color; +} + +// Set pixel color formatted into destination pointer +void SetPixelColor(void *dstPtr, Color color, int format) +{ + switch (format) + { + case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: + { + // NOTE: Calculate grayscale equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f); + + ((unsigned char *)dstPtr)[0] = gray; + + } break; + case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + { + // NOTE: Calculate grayscale equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + unsigned char gray = (unsigned char)((coln.x*0.299f + coln.y*0.587f + coln.z*0.114f)*255.0f); + + ((unsigned char *)dstPtr)[0] = gray; + ((unsigned char *)dstPtr)[1] = color.a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G6B5: + { + // NOTE: Calculate R5G6B5 equivalent color + Vector3 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; + + unsigned char r = (unsigned char)(round(coln.x*31.0f)); + unsigned char g = (unsigned char)(round(coln.y*63.0f)); + unsigned char b = (unsigned char)(round(coln.z*31.0f)); + + ((unsigned short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + { + // NOTE: Calculate R5G5B5A1 equivalent color + Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f }; + + 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 short *)dstPtr)[0] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: + { + // NOTE: Calculate R5G5B5A1 equivalent color + Vector4 coln = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f, (float)color.a/255.0f }; + + unsigned char r = (unsigned char)(round(coln.x*15.0f)); + unsigned char g = (unsigned char)(round(coln.y*15.0f)); + unsigned char b = (unsigned char)(round(coln.z*15.0f)); + unsigned char a = (unsigned char)(round(coln.w*15.0f)); + + ((unsigned short *)dstPtr)[0] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8: + { + ((unsigned char *)dstPtr)[0] = color.r; + ((unsigned char *)dstPtr)[1] = color.g; + ((unsigned char *)dstPtr)[2] = color.b; + + } break; + case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: + { + ((unsigned char *)dstPtr)[0] = color.r; + ((unsigned char *)dstPtr)[1] = color.g; + ((unsigned char *)dstPtr)[2] = color.b; + ((unsigned char *)dstPtr)[3] = color.a; + + } break; + default: break; + } +} + +// Get pixel data size in bytes for certain format +// NOTE: Size can be requested for Image or Texture data +int GetPixelDataSize(int width, int height, int format) +{ + int dataSize = 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_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: + 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 + + // 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)) dataSize = 8; + else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + } + + return dataSize; +} + +//---------------------------------------------------------------------------------- +// 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) +{ + float result = 0.0f; + + union { + float fm; + unsigned int ui; + } uni; + + 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 + + result = uni.fm; + + return result; +} + +// Convert float to half-float (stored as unsigned short) +static unsigned short FloatToHalf(float x) +{ + unsigned short result = 0; + + union { + float fm; + unsigned int ui; + } uni; + uni.fm = x; + + 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 + { + 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; + + 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; + } + } + } + + return pixels; +} + +#endif // SUPPORT_MODULE_RTEXTURES diff --git a/raylib/rtextures.go b/raylib/rtextures.go new file mode 100644 index 0000000..6cb16ad --- /dev/null +++ b/raylib/rtextures.go @@ -0,0 +1,923 @@ +package rl + +/* +#include "raylib.h" +#include +*/ +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)) +} + +// 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) + cimg := i.cptr() + ret := C.LoadImageColors(*cimg) + pixels := (*[1 << 24]uint8)(unsafe.Pointer(ret))[0 : i.Width*i.Height*4] + + img.Pix = pixels + + 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) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadImage(cfileName) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadImageRaw - Load image data from RAW file +func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + cwidth := (C.int)(width) + cheight := (C.int)(height) + cformat := (C.int)(format) + cheaderSize := (C.int)(headerSize) + ret := C.LoadImageRaw(cfileName, cwidth, cheight, cformat, cheaderSize) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadImageAnim - Load image sequence from file (frames appended to image.data) +func LoadImageAnim(fileName string, frames *int32) *Image { + cfileName := C.CString(fileName) + defer C.free(unsafe.Pointer(cfileName)) + cframes := (*C.int)(frames) + ret := C.LoadImageAnim(cfileName, cframes) + v := newImageFromPointer(unsafe.Pointer(&ret)) + 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) + defer C.free(unsafe.Pointer(cfileType)) + cfileData := (*C.uchar)(unsafe.Pointer(&fileData[0])) + cdataSize := (C.int)(dataSize) + ret := C.LoadImageFromMemory(cfileType, cfileData, cdataSize) + v := newImageFromPointer(unsafe.Pointer(&ret)) + 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) + defer C.free(unsafe.Pointer(cfileName)) + ret := C.LoadTexture(cfileName) + v := newTexture2DFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadTextureFromImage - Load a texture from image data +func LoadTextureFromImage(image *Image) Texture2D { + cimage := image.cptr() + ret := C.LoadTextureFromImage(*cimage) + v := newTexture2DFromPointer(unsafe.Pointer(&ret)) + return v +} + +// LoadRenderTexture - Load a texture to be used for rendering +func LoadRenderTexture(width, height int32) RenderTexture2D { + cwidth := (C.int)(width) + cheight := (C.int)(height) + ret := C.LoadRenderTexture(cwidth, cheight) + v := newRenderTexture2DFromPointer(unsafe.Pointer(&ret)) + 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 { + cimg := img.cptr() + ret := C.LoadImageColors(*cimg) + return (*[1 << 24]color.RGBA)(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]))) +} + +// UpdateTexture - Update GPU texture with new data +func UpdateTexture(texture Texture2D, pixels []color.RGBA) { + 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) { + ctexture := texture.cptr() + cpixels := unsafe.Pointer(&pixels[0]) + crec := rec.cptr() + C.UpdateTextureRec(*ctexture, *crec, cpixels) +} + +// 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)) + cimage := image.cptr() + + var size C.int + ret := C.ExportImageToMemory(*cimage, cfileType, &size) + v := unsafe.Slice((*byte)(unsafe.Pointer(ret)), size) + return v +} + +// ImageCopy - Create an image duplicate (useful for transformations) +func ImageCopy(image *Image) *Image { + cimage := image.cptr() + ret := C.ImageCopy(*cimage) + v := newImageFromPointer(unsafe.Pointer(&ret)) + 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 { + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cfontSize := (C.int)(fontSize) + ccolor := colorCptr(col) + 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 { + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + ctint := colorCptr(tint) + ret := C.ImageTextEx(*cfont, ctext, cfontSize, cspacing, *ctint) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// ImageFormat - Convert image data to desired format +func ImageFormat(image *Image, newFormat PixelFormat) { + cimage := image.cptr() + cnewFormat := (C.int)(newFormat) + C.ImageFormat(cimage, cnewFormat) +} + +// ImageToPOT - Convert image to POT (power-of-two) +func ImageToPOT(image *Image, fillColor color.RGBA) { + cimage := image.cptr() + cfillColor := colorCptr(fillColor) + C.ImageToPOT(cimage, *cfillColor) +} + +// ImageCrop - Crop an image to a defined rectangle +func ImageCrop(image *Image, crop Rectangle) { + cimage := image.cptr() + ccrop := crop.cptr() + C.ImageCrop(cimage, *ccrop) +} + +// ImageAlphaCrop - Crop image depending on alpha value +func ImageAlphaCrop(image *Image, threshold float32) { + cimage := image.cptr() + cthreshold := (C.float)(threshold) + C.ImageAlphaCrop(cimage, cthreshold) +} + +// ImageAlphaClear - Apply alpha mask to image +func ImageAlphaClear(image *Image, col color.RGBA, threshold float32) { + cimage := image.cptr() + ccolor := colorCptr(col) + cthreshold := (C.float)(threshold) + C.ImageAlphaClear(cimage, *ccolor, cthreshold) +} + +// ImageAlphaMask - Apply alpha mask to image +func ImageAlphaMask(image, alphaMask *Image) { + cimage := image.cptr() + calphaMask := alphaMask.cptr() + C.ImageAlphaMask(cimage, *calphaMask) +} + +// ImageAlphaPremultiply - Premultiply alpha channel +func ImageAlphaPremultiply(image *Image) { + cimage := image.cptr() + 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() + cnewWidth := (C.int)(newWidth) + cnewHeight := (C.int)(newHeight) + C.ImageResize(cimage, cnewWidth, cnewHeight) +} + +// ImageResizeNN - Resize an image (Nearest-Neighbor scaling algorithm) +func ImageResizeNN(image *Image, newWidth, newHeight int32) { + cimage := image.cptr() + cnewWidth := (C.int)(newWidth) + cnewHeight := (C.int)(newHeight) + C.ImageResizeNN(cimage, cnewWidth, cnewHeight) +} + +// ImageResizeCanvas - Resize canvas and fill with color +func ImageResizeCanvas(image *Image, newWidth, newHeight, offsetX, offsetY int32, col color.RGBA) { + cimage := image.cptr() + cnewWidth := (C.int)(newWidth) + cnewHeight := (C.int)(newHeight) + coffsetX := (C.int)(offsetX) + coffsetY := (C.int)(offsetY) + ccolor := colorCptr(col) + C.ImageResizeCanvas(cimage, cnewWidth, cnewHeight, coffsetX, coffsetY, *ccolor) +} + +// ImageMipmaps - Generate all mipmap levels for a provided image +func ImageMipmaps(image *Image) { + cimage := image.cptr() + C.ImageMipmaps(cimage) +} + +// ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +func ImageDither(image *Image, rBpp, gBpp, bBpp, aBpp int32) { + cimage := image.cptr() + crBpp := (C.int)(rBpp) + cgBpp := (C.int)(gBpp) + cbBpp := (C.int)(bBpp) + caBpp := (C.int)(aBpp) + C.ImageDither(cimage, crBpp, cgBpp, cbBpp, caBpp) +} + +// ImageFlipVertical - Flip image vertically +func ImageFlipVertical(image *Image) { + cimage := image.cptr() + C.ImageFlipVertical(cimage) +} + +// ImageFlipHorizontal - Flip image horizontally +func ImageFlipHorizontal(image *Image) { + cimage := image.cptr() + 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() + C.ImageRotateCW(cimage) +} + +// ImageRotateCCW - Rotate image counter-clockwise 90deg +func ImageRotateCCW(image *Image) { + cimage := image.cptr() + C.ImageRotateCCW(cimage) +} + +// ImageColorTint - Modify image color: tint +func ImageColorTint(image *Image, col color.RGBA) { + cimage := image.cptr() + ccolor := colorCptr(col) + C.ImageColorTint(cimage, *ccolor) +} + +// ImageColorInvert - Modify image color: invert +func ImageColorInvert(image *Image) { + cimage := image.cptr() + C.ImageColorInvert(cimage) +} + +// ImageColorGrayscale - Modify image color: grayscale +func ImageColorGrayscale(image *Image) { + cimage := image.cptr() + C.ImageColorGrayscale(cimage) +} + +// ImageColorContrast - Modify image color: contrast (-100 to 100) +func ImageColorContrast(image *Image, contrast float32) { + cimage := image.cptr() + ccontrast := (C.float)(contrast) + C.ImageColorContrast(cimage, ccontrast) +} + +// ImageColorBrightness - Modify image color: brightness (-255 to 255) +func ImageColorBrightness(image *Image, brightness int32) { + cimage := image.cptr() + cbrightness := (C.int)(brightness) + C.ImageColorBrightness(cimage, cbrightness) +} + +// ImageColorReplace - Modify image color: replace color +func ImageColorReplace(image *Image, col, replace color.RGBA) { + cimage := image.cptr() + ccolor := colorCptr(col) + creplace := colorCptr(replace) + 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) { + cdst := dst.cptr() + csrc := src.cptr() + csrcRec := srcRec.cptr() + cdstRec := dstRec.cptr() + ctint := colorCptr(tint) + 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) { + cdst := dst.cptr() + cx := (C.int)(x) + cy := (C.int)(y) + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor := colorCptr(col) + 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) { + cdst := dst.cptr() + crec := rec.cptr() + cthick := (C.int)(thick) + ccolor := colorCptr(col) + 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) { + 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) + 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) { + cdst := dst.cptr() + cposition := position.cptr() + cfont := font.cptr() + ctext := C.CString(text) + defer C.free(unsafe.Pointer(ctext)) + cfontSize := (C.float)(fontSize) + cspacing := (C.float)(spacing) + ccolor := colorCptr(col) + C.ImageDrawTextEx(cdst, *cfont, ctext, *cposition, cfontSize, cspacing, *ccolor) +} + +// GenImageColor - Generate image: plain color +func GenImageColor(width, height int, col color.RGBA) *Image { + cwidth := (C.int)(width) + cheight := (C.int)(height) + ccolor := colorCptr(col) + + 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 { + cwidth := (C.int)(width) + cheight := (C.int)(height) + cdensity := (C.int)(direction) + cstart := colorCptr(start) + cend := colorCptr(end) + + ret := C.GenImageGradientLinear(cwidth, cheight, cdensity, *cstart, *cend) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenImageGradientRadial - Generate image: radial gradient +func GenImageGradientRadial(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.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 { + cwidth := (C.int)(width) + cheight := (C.int)(height) + cchecksX := (C.int)(checksX) + cchecksY := (C.int)(checksY) + ccol1 := colorCptr(col1) + ccol2 := colorCptr(col2) + + ret := C.GenImageChecked(cwidth, cheight, cchecksX, cchecksY, *ccol1, *ccol2) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenImageWhiteNoise - Generate image: white noise +func GenImageWhiteNoise(width, height int, factor float32) *Image { + cwidth := (C.int)(width) + cheight := (C.int)(height) + cfactor := (C.float)(factor) + + ret := C.GenImageWhiteNoise(cwidth, cheight, cfactor) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenImagePerlinNoise - Generate image: perlin noise +func GenImagePerlinNoise(width, height, offsetX, offsetY int, scale float32) *Image { + cwidth := (C.int)(width) + cheight := (C.int)(height) + coffsetX := (C.int)(offsetX) + coffsetY := (C.int)(offsetY) + cscale := (C.float)(scale) + + ret := C.GenImagePerlinNoise(cwidth, cheight, coffsetX, coffsetY, cscale) + v := newImageFromPointer(unsafe.Pointer(&ret)) + return v +} + +// GenImageCellular - Generate image: cellular algorithm. Bigger tileSize means bigger cells +func GenImageCellular(width, height, tileSize int) *Image { + cwidth := (C.int)(width) + cheight := (C.int)(height) + ctileSize := (C.int)(tileSize) + + ret := C.GenImageCellular(cwidth, cheight, ctileSize) + v := newImageFromPointer(unsafe.Pointer(&ret)) + 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() + C.GenTextureMipmaps(ctexture) +} + +// SetTextureFilter - Set texture scaling filter mode +func SetTextureFilter(texture Texture2D, filterMode TextureFilterMode) { + ctexture := texture.cptr() + cfilterMode := (C.int)(filterMode) + C.SetTextureFilter(*ctexture, cfilterMode) +} + +// SetTextureWrap - Set texture wrapping mode +func SetTextureWrap(texture Texture2D, wrapMode TextureWrapMode) { + ctexture := texture.cptr() + cwrapMode := (C.int)(wrapMode) + C.SetTextureWrap(*ctexture, cwrapMode) +} + +// DrawTexture - Draw a Texture2D +func DrawTexture(texture Texture2D, posX int32, posY int32, tint color.RGBA) { + ctexture := texture.cptr() + cposX := (C.int)(posX) + cposY := (C.int)(posY) + ctint := colorCptr(tint) + C.DrawTexture(*ctexture, cposX, cposY, *ctint) +} + +// DrawTextureV - Draw a Texture2D with position defined as Vector2 +func DrawTextureV(texture Texture2D, position Vector2, tint color.RGBA) { + ctexture := texture.cptr() + cposition := position.cptr() + ctint := colorCptr(tint) + C.DrawTextureV(*ctexture, *cposition, *ctint) +} + +// DrawTextureEx - Draw a Texture2D with extended parameters +func DrawTextureEx(texture Texture2D, position Vector2, rotation, scale float32, tint color.RGBA) { + ctexture := texture.cptr() + cposition := position.cptr() + crotation := (C.float)(rotation) + cscale := (C.float)(scale) + ctint := colorCptr(tint) + 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) { + ctexture := texture.cptr() + csourceRec := sourceRec.cptr() + cposition := position.cptr() + ctint := colorCptr(tint) + 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) { + ctexture := texture.cptr() + csourceRec := sourceRec.cptr() + cdestRec := destRec.cptr() + corigin := origin.cptr() + crotation := (C.float)(rotation) + ctint := colorCptr(tint) + 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/shader_distortion.h b/raylib/shader_distortion.h deleted file mode 100644 index 3b37c63..0000000 --- a/raylib/shader_distortion.h +++ /dev/null @@ -1,106 +0,0 @@ - -// Vertex shader definition to embed, no external file required -static const char distortionVShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) -"#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) -"#version 100 \n" -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -"attribute vec3 vertexPosition; \n" -"attribute vec2 vertexTexCoord; \n" -"attribute vec4 vertexColor; \n" -"varying vec2 fragTexCoord; \n" -"varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -"#version 330 \n" -"in vec3 vertexPosition; \n" -"in vec2 vertexTexCoord; \n" -"in vec4 vertexColor; \n" -"out vec2 fragTexCoord; \n" -"out vec4 fragColor; \n" -#endif -"uniform mat4 mvp; \n" -"void main() \n" -"{ \n" -" fragTexCoord = vertexTexCoord; \n" -" fragColor = vertexColor; \n" -" gl_Position = mvp*vec4(vertexPosition, 1.0); \n" -"} \n"; - -// Fragment shader definition to embed, no external file required -static const char distortionFShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) -"#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) -"#version 100 \n" -"precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -"varying vec2 fragTexCoord; \n" -"varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -"#version 330 \n" -"in vec2 fragTexCoord; \n" -"in vec4 fragColor; \n" -"out vec4 finalColor; \n" -#endif -"uniform sampler2D texture0; \n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -"uniform vec2 leftLensCenter; \n" -"uniform vec2 rightLensCenter; \n" -"uniform vec2 leftScreenCenter; \n" -"uniform vec2 rightScreenCenter; \n" -"uniform vec2 scale; \n" -"uniform vec2 scaleIn; \n" -"uniform vec4 hmdWarpParam; \n" -"uniform vec4 chromaAbParam; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -"uniform vec2 leftLensCenter = vec2(0.288, 0.5); \n" -"uniform vec2 rightLensCenter = vec2(0.712, 0.5); \n" -"uniform vec2 leftScreenCenter = vec2(0.25, 0.5); \n" -"uniform vec2 rightScreenCenter = vec2(0.75, 0.5); \n" -"uniform vec2 scale = vec2(0.25, 0.45); \n" -"uniform vec2 scaleIn = vec2(4, 2.2222); \n" -"uniform vec4 hmdWarpParam = vec4(1, 0.22, 0.24, 0); \n" -"uniform vec4 chromaAbParam = vec4(0.996, -0.004, 1.014, 0.0); \n" -#endif -"void main() \n" -"{ \n" -" vec2 lensCenter = fragTexCoord.x < 0.5 ? leftLensCenter : rightLensCenter; \n" -" vec2 screenCenter = fragTexCoord.x < 0.5 ? leftScreenCenter : rightScreenCenter; \n" -" vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n" -" float rSq = theta.x*theta.x + theta.y*theta.y; \n" -" vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n" -" vec2 thetaBlue = theta1*(chromaAbParam.z + chromaAbParam.w*rSq); \n" -" vec2 tcBlue = lensCenter + scale*thetaBlue; \n" -" if (any(bvec2(clamp(tcBlue, screenCenter - vec2(0.25, 0.5), screenCenter + vec2(0.25, 0.5)) - tcBlue))) \n" -" { \n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); \n" -#elif defined(GRAPHICS_API_OPENGL_33) -" finalColor = vec4(0.0, 0.0, 0.0, 1.0); \n" -#endif -" } \n" -" else \n" -" { \n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" float blue = texture2D(texture0, tcBlue).b; \n" -" vec2 tcGreen = lensCenter + scale*theta1; \n" -" float green = texture2D(texture0, tcGreen).g; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -" float blue = texture(texture0, tcBlue).b; \n" -" vec2 tcGreen = lensCenter + scale*theta1; \n" -" float green = texture(texture0, tcGreen).g; \n" -#endif -" vec2 thetaRed = theta1*(chromaAbParam.x + chromaAbParam.y*rSq); \n" -" vec2 tcRed = lensCenter + scale*thetaRed; \n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" float red = texture2D(texture0, tcRed).r; \n" -" gl_FragColor = vec4(red, green, blue, 1.0); \n" -#elif defined(GRAPHICS_API_OPENGL_33) -" float red = texture(texture0, tcRed).r; \n" -" finalColor = vec4(red, green, blue, 1.0); \n" -#endif -" } \n" -"} \n"; diff --git a/raylib/shaders.go b/raylib/shaders.go deleted file mode 100644 index 5ac86f9..0000000 --- a/raylib/shaders.go +++ /dev/null @@ -1,235 +0,0 @@ -package raylib - -/* -#include "raylib.h" -#include -*/ -import "C" -import "unsafe" -import "reflect" - -// cptr returns C pointer -func (v *VrDeviceInfo) cptr() *C.VrDeviceInfo { - return (*C.VrDeviceInfo)(unsafe.Pointer(v)) -} - -// cptr returns C pointer -func (s *Shader) cptr() *C.Shader { - return (*C.Shader)(unsafe.Pointer(s)) -} - -// 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 -} - -// LoadShaderCode - Load shader from code strings and bind default locations -func LoadShaderCode(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.LoadShaderCode(cvsCode, cfsCode) - v := newShaderFromPointer(unsafe.Pointer(&ret)) - - return v -} - -// UnloadShader - Unload a custom shader from memory -func UnloadShader(shader Shader) { - cshader := shader.cptr() - C.UnloadShader(*cshader) -} - -// GetShaderDefault - Get default shader -func GetShaderDefault() Shader { - ret := C.GetShaderDefault() - v := newShaderFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GetTextureDefault - Get default texture -func GetTextureDefault() *Texture2D { - ret := C.GetTextureDefault() - v := newTexture2DFromPointer(unsafe.Pointer(&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 -} - -// SetShaderValue - Set shader uniform value (float) -func SetShaderValue(shader Shader, uniformLoc int32, value []float32, size int32) { - cshader := shader.cptr() - cuniformLoc := (C.int)(uniformLoc) - cvalue := (*C.float)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&value)).Data)) - csize := (C.int)(size) - C.SetShaderValue(*cshader, cuniformLoc, cvalue, csize) -} - -// SetShaderValuei - Set shader uniform value (int) -func SetShaderValuei(shader Shader, uniformLoc int32, value []int32, size int32) { - cshader := shader.cptr() - cuniformLoc := (C.int)(uniformLoc) - cvalue := (*C.int)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&value)).Data)) - csize := (C.int)(size) - C.SetShaderValuei(*cshader, cuniformLoc, cvalue, csize) -} - -// SetShaderValueMatrix - Set shader uniform value (matrix 4x4) -func SetShaderValueMatrix(shader Shader, uniformLoc int32, mat Matrix) { - cshader := shader.cptr() - cuniformLoc := (C.int)(uniformLoc) - cmat := mat.cptr() - C.SetShaderValueMatrix(*cshader, cuniformLoc, *cmat) -} - -// SetMatrixProjection - Set a custom projection matrix (replaces internal projection matrix) -func SetMatrixProjection(proj Matrix) { - cproj := proj.cptr() - C.SetMatrixProjection(*cproj) -} - -// SetMatrixModelview - Set a custom modelview matrix (replaces internal modelview matrix) -func SetMatrixModelview(view Matrix) { - cview := view.cptr() - C.SetMatrixModelview(*cview) -} - -// GenTextureCubemap - Generate cubemap texture from HDR texture -func GenTextureCubemap(shader Shader, skyHDR Texture2D, size int) Texture2D { - cshader := shader.cptr() - cskyHDR := skyHDR.cptr() - csize := (C.int)(size) - - ret := C.GenTextureCubemap(*cshader, *cskyHDR, csize) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenTextureIrradiance - Generate irradiance texture using cubemap data -func GenTextureIrradiance(shader Shader, cubemap Texture2D, size int) Texture2D { - cshader := shader.cptr() - ccubemap := cubemap.cptr() - csize := (C.int)(size) - - ret := C.GenTextureIrradiance(*cshader, *ccubemap, csize) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenTexturePrefilter - Generate prefilter texture using cubemap data -func GenTexturePrefilter(shader Shader, cubemap Texture2D, size int) Texture2D { - cshader := shader.cptr() - ccubemap := cubemap.cptr() - csize := (C.int)(size) - - ret := C.GenTexturePrefilter(*cshader, *ccubemap, csize) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenTextureBRDF - Generate BRDF texture using cubemap data -func GenTextureBRDF(shader Shader, cubemap Texture2D, size int) Texture2D { - cshader := shader.cptr() - ccubemap := cubemap.cptr() - csize := (C.int)(size) - - ret := C.GenTextureBRDF(*cshader, *ccubemap, csize) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// 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() -} - -// GetVrDeviceInfo - Get VR device information for some standard devices -func GetVrDeviceInfo(vrDevice VrDevice) VrDeviceInfo { - cvrDevice := (C.int)(vrDevice) - ret := C.GetVrDeviceInfo(cvrDevice) - v := newVrDeviceInfoFromPointer(unsafe.Pointer(&ret)) - return v -} - -// InitVrSimulator - Init VR simulator for selected device -func InitVrSimulator(vrDeviceInfo VrDeviceInfo) { - cvrDeviceInfo := vrDeviceInfo.cptr() - C.InitVrSimulator(*cvrDeviceInfo) -} - -// CloseVrSimulator - Close VR simulator for current device -func CloseVrSimulator() { - C.CloseVrSimulator() -} - -// IsVrSimulatorReady - Detect if VR simulator is ready -func IsVrSimulatorReady() bool { - ret := C.IsVrSimulatorReady() - v := bool(int(ret) == 1) - return v -} - -// UpdateVrTracking - Update VR tracking (position and orientation) and camera -func UpdateVrTracking(camera *Camera) { - ccamera := camera.cptr() - C.UpdateVrTracking(ccamera) -} - -// ToggleVrMode - Enable/Disable VR experience (device or simulator) -func ToggleVrMode() { - C.ToggleVrMode() -} - -// BeginVrDrawing - Begin VR simulator stereo rendering -func BeginVrDrawing() { - C.BeginVrDrawing() -} - -// EndVrDrawing - End VR simulator stereo rendering -func EndVrDrawing() { - C.EndVrDrawing() -} diff --git a/raylib/shapes.c b/raylib/shapes.c deleted file mode 100644 index ed911b2..0000000 --- a/raylib/shapes.c +++ /dev/null @@ -1,761 +0,0 @@ -/********************************************************************************************** -* -* raylib.shapes - Basic functions to draw 2d Shapes and check collisions -* -* CONFIGURATION: -* -* #define SUPPORT_FONT_TEXTURE -* Draw rectangle shapes using font texture white character instead of default white texture -* Allows drawing rectangles and text with a single draw call, very useful for GUI systems! -* -* #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) 2014-2018 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 "config.h" // Defines module configuration flags -#include "raylib.h" // Declares module functions - -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 - -#include // Required for: abs(), fabs() -#include // Required for: sinf(), cosf(), sqrtf() - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Nop... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Not here... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// 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) -{ - if (startPos.x > endPos.x) - { - Vector2 tempPos = startPos; - startPos = endPos; - endPos = tempPos; - } - - float dx = endPos.x - startPos.x; - float dy = endPos.y - startPos.y; - - float d = sqrtf(dx*dx + dy*dy); - float angle = asinf(dy/d); - - rlEnableTexture(GetTextureDefault().id); - - rlPushMatrix(); - rlTranslatef((float)startPos.x, (float)startPos.y, 0); - rlRotatef(RAD2DEG*angle, 0, 0, 1); - rlTranslatef(0, -thick/2.0f, 0); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 0.0f, 1.0f); - - rlVertex2f(0.0f, 0.0f); - rlVertex2f(0.0f, thick); - rlVertex2f(d, thick); - rlVertex2f(d, 0.0f); - rlEnd(); - rlPopMatrix(); - - rlDisableTexture(); -} - -// Draw line using cubic-bezier curves in-out -void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) -{ - #define LINE_DIVISIONS 24 // Bezier line divisions - - Vector2 previous = startPos; - Vector2 current; - - for (int i = 1; i <= LINE_DIVISIONS; i++) - { - // Cubic easing in-out - // NOTE: Easing is calcutated only for y position value - current.y = EaseCubicInOut(i, startPos.y, endPos.y - startPos.y, LINE_DIVISIONS); - current.x = previous.x + (endPos.x - startPos.x)/LINE_DIVISIONS; - - DrawLineEx(previous, current, thick, color); - - previous = current; - } -} - -// 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 gradient-filled circle -// NOTE: Gradient goes from center (color1) to border (color2) -void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2) -{ - rlBegin(RL_TRIANGLES); - for (int i = 0; i < 360; i += 10) - { - rlColor4ub(color1.r, color1.g, color1.b, color1.a); - rlVertex2i(centerX, centerY); - rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); - rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, 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 (view rlglDraw) -void DrawCircleV(Vector2 center, float radius, Color color) -{ -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - for (int i = 0; i < 360; i += 20) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); - rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); - rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius); - } - rlEnd(); - - rlDisableTexture(); -#else - 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 + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); - rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); - } - rlEnd(); -#endif -} - -// Draw circle outline -void DrawCircleLines(int centerX, int centerY, 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(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 a color-filled rectangle -void DrawRectangle(int posX, int posY, int width, int height, Color color) -{ - Vector2 position = { (float)posX, (float)posY }; - Vector2 size = { (float)width, (float)height }; - - DrawRectangleV(position, size, color); -} - -// Draw a color-filled rectangle (Vector version) -// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) -void DrawRectangleV(Vector2 position, Vector2 size, Color color) -{ -#if defined(SUPPORT_QUADS_DRAW_MODE) - #if defined(SUPPORT_FONT_TEXTURE) - // Draw rectangle using font texture white character - rlEnableTexture(GetDefaultFont().texture.id); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 0.0f, 1.0f); - - // NOTE: Default raylib font character 95 is a white square - rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(position.x, position.y); - - rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(position.x, position.y + size.y); - - rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - (float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(position.x + size.x, position.y + size.y); - - rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - (float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(position.x + size.x, position.y); - rlEnd(); - - rlDisableTexture(); - #else - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 0.0f, 1.0f); - - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(position.x, position.y); - - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(position.x, position.y + size.y); - - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f(position.x + size.x, position.y + size.y); - - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f(position.x + size.x, position.y); - rlEnd(); - - rlDisableTexture(); - #endif // SUPPORT_FONT_TEXTURE -#else - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2i(position.x, position.y); - rlVertex2i(position.x, position.y + size.y); - rlVertex2i(position.x + size.x, position.y + size.y); - - rlVertex2i(position.x, position.y); - rlVertex2i(position.x + size.x, position.y + size.y); - rlVertex2i(position.x + size.x, position.y); - rlEnd(); -#endif // SUPPORT_QUADS_DRAW_MODE -} - -// Draw a color-filled rectangle -void DrawRectangleRec(Rectangle rec, Color color) -{ - DrawRectangle(rec.x, rec.y, rec.width, rec.height, color); -} - -void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) -{ - rlEnableTexture(GetTextureDefault().id); - - rlPushMatrix(); - rlTranslatef(rec.x, rec.y, 0); - rlRotatef(rotation, 0, 0, 1); - rlTranslatef(-origin.x, -origin.y, 0); - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer - - rlVertex2f(0.0f, 0.0f); - rlVertex2f(0.0f, rec.height); - rlVertex2f(rec.width, rec.height); - rlVertex2f(rec.width, 0.0f); - rlEnd(); - rlPopMatrix(); - - rlDisableTexture(); -} - -// 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){ posX, posY, width, 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){ posX, posY, width, 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) -{ -#if defined(SUPPORT_FONT_TEXTURE) - // Draw rectangle using font texture white character - rlEnableTexture(GetDefaultFont().texture.id); - - 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(GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y); - - rlColor4ub(col2.r, col2.g, col2.b, col2.a); - rlTexCoord2f(GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width, - (GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x, rec.y + rec.height); - - rlColor4ub(col3.r, col3.g, col3.b, col3.a); - rlTexCoord2f((GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - (GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y + rec.height); - - rlColor4ub(col4.r, col4.g, col4.b, col4.a); - rlTexCoord2f((GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width, - GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height); - rlVertex2f(rec.x + rec.width, rec.y); - rlEnd(); - - rlDisableTexture(); -#else - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - rlNormal3f(0.0f, 0.0f, 1.0f); - - rlColor4ub(col1.r, col1.g, col1.b, col1.a); - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(rec.x, rec.y); - - rlColor4ub(col2.r, col2.g, col2.b, col2.a); - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(rec.x, rec.y + rec.height); - - rlColor4ub(col3.r, col3.g, col3.b, col3.a); - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f(rec.x + rec.width, rec.y + rec.height); - - rlColor4ub(col4.r, col4.g, col4.b, col4.a); - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f(rec.x + rec.width, rec.y); - rlEnd(); - - rlDisableTexture(); -#endif -} - -// Draw rectangle outline -// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) -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, int 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; - } - - DrawRectangle(rec.x, rec.y, rec.width, lineThick, color); - DrawRectangle(rec.x - lineThick + rec.width, rec.y + lineThick, lineThick, rec.height - lineThick*2, color); - DrawRectangle(rec.x, rec.y + rec.height - lineThick, rec.width, lineThick, color); - DrawRectangle(rec.x, rec.y + lineThick, lineThick, rec.height - lineThick*2, color); -} - -// Draw a triangle -void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) -{ -#if defined(SUPPORT_QUADS_DRAW_MODE) - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - 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); - rlEnd(); - - rlDisableTexture(); -#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 -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 regular polygon of n sides (Vector version) -void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) -{ - if (sides < 3) sides = 3; - - rlPushMatrix(); - rlTranslatef(center.x, center.y, 0.0); - rlRotatef(rotation, 0, 0, 1); - - #if defined(SUPPORT_QUADS_DRAW_MODE) - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - for (int i = 0; i < 360; i += 360/sides) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(0, 0); - rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); - rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); - rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); - } - rlEnd(); - rlDisableTexture(); - #else - rlBegin(RL_TRIANGLES); - for (int i = 0; i < 360; i += 360/sides) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(0, 0); - rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); - rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); - } - rlEnd(); - #endif - rlPopMatrix(); -} - -// Draw a closed polygon defined by points -void DrawPolyEx(Vector2 *points, int pointsCount, Color color) -{ - if (pointsCount >= 3) - { - #if defined(SUPPORT_QUADS_DRAW_MODE) - rlEnableTexture(GetTextureDefault().id); // Default white texture - - rlBegin(RL_QUADS); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 1; i < pointsCount - 1; i++) - { - rlVertex2f(points[0].x, points[0].y); - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i + 1].x, points[i + 1].y); - } - rlEnd(); - rlDisableTexture(); - #else - rlBegin(RL_TRIANGLES); - rlColor4ub(color.r, color.g, color.b, color.a); - - for (int i = 1; i < pointsCount - 1; i++) - { - rlVertex2f(points[0].x, points[0].y); - rlVertex2f(points[i].x, points[i].y); - rlVertex2f(points[i + 1].x, points[i + 1].y); - } - rlEnd(); - #endif - } -} - -// Draw polygon using lines -void DrawPolyExLines(Vector2 *points, int pointsCount, Color color) -{ - if (pointsCount >= 2) - { - 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(); - } -} - -//---------------------------------------------------------------------------------- -// 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; - - int dx = abs((rec1.x + rec1.width/2) - (rec2.x + rec2.width/2)); - int dy = abs((rec1.y + rec1.height/2) - (rec2.y + rec2.height/2)); - - if ((dx <= (rec1.width/2 + rec2.width/2)) && ((dy <= (rec1.height/2 + rec2.height/2)))) 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 = rec.x + rec.width/2; - int recCenterY = rec.y + rec.height/2; - - 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); - - return (cornerDistanceSq <= (radius*radius)); -} - -// Get collision rectangle for two rectangles collision -Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) -{ - Rectangle retRec = { 0, 0, 0, 0 }; - - if (CheckCollisionRecs(rec1, rec2)) - { - int dxx = abs(rec1.x - rec2.x); - int dyy = abs(rec1.y - rec2.y); - - if (rec1.x <= rec2.x) - { - if (rec1.y <= rec2.y) - { - retRec.x = rec2.x; - retRec.y = rec2.y; - retRec.width = rec1.width - dxx; - retRec.height = rec1.height - dyy; - } - else - { - retRec.x = rec2.x; - retRec.y = rec1.y; - retRec.width = rec1.width - dxx; - retRec.height = rec2.height - dyy; - } - } - else - { - if (rec1.y <= rec2.y) - { - retRec.x = rec1.x; - retRec.y = rec2.y; - retRec.width = rec2.width - dxx; - retRec.height = rec1.height - dyy; - } - else - { - retRec.x = rec1.x; - retRec.y = rec1.y; - retRec.width = rec2.width - dxx; - retRec.height = rec2.height - dyy; - } - } - - if (rec1.width > rec2.width) - { - if (retRec.width >= rec2.width) retRec.width = rec2.width; - } - else - { - if (retRec.width >= rec1.width) retRec.width = rec1.width; - } - - if (rec1.height > rec2.height) - { - if (retRec.height >= rec2.height) retRec.height = rec2.height; - } - else - { - if (retRec.height >= rec1.height) retRec.height = rec1.height; - } - } - - return retRec; -} - -//---------------------------------------------------------------------------------- -// 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.5*d) < 1) - return 0.5*c*t*t*t + b; - t -= 2; - return 0.5*c*(t*t*t + 2) + b; -} diff --git a/raylib/shapes.go b/raylib/shapes.go deleted file mode 100644 index e2b4706..0000000 --- a/raylib/shapes.go +++ /dev/null @@ -1,292 +0,0 @@ -package raylib - -/* -#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) -} - -// 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) -} - -// 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, color Color) { - crec := rec.cptr() - corigin := origin.cptr() - crotation := (C.float)(rotation) - ccolor := color.cptr() - 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 int32, color Color) { - crec := rec.cptr() - clineThick := (C.int)(lineThick) - ccolor := color.cptr() - C.DrawRectangleLinesEx(*crec, 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) -} - -// 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) -} - -// DrawPolyEx - Draw a closed polygon defined by points -func DrawPolyEx(points []Vector2, numPoints int32, color Color) { - cpoints := points[0].cptr() - cnumPoints := (C.int)(numPoints) - ccolor := color.cptr() - C.DrawPolyEx(cpoints, cnumPoints, *ccolor) -} - -// DrawPolyExLines - Draw polygon lines -func DrawPolyExLines(points []Vector2, numPoints int32, color Color) { - cpoints := points[0].cptr() - cnumPoints := (C.int)(numPoints) - ccolor := color.cptr() - C.DrawPolyExLines(cpoints, cnumPoints, *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(int(ret) == 1) - 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(int(ret) == 1) - 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(int(ret) == 1) - 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 -} - -// 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(int(ret) == 1) - 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(int(ret) == 1) - 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(int(ret) == 1) - return v -} diff --git a/raylib/text.c b/raylib/text.c deleted file mode 100644 index aa22c30..0000000 --- a/raylib/text.c +++ /dev/null @@ -1,916 +0,0 @@ -/********************************************************************************************** -* -* 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 -* -* DEPENDENCIES: -* stb_truetype - Load TTF file and rasterize characters data -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2018 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 "config.h" - -#include "raylib.h" - -#include // Required for: malloc(), free() -#include // Required for: strlen() -#include // Required for: va_list, va_start(), vfprintf(), va_end() -#include // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() - -#include "utils.h" // Required for: fopen() Android mapping - -#if defined(SUPPORT_FILEFORMAT_TTF) - // Following libs are used on LoadTTF() - #define STBTT_STATIC // Define stb_truetype functions static to this module - #define STB_TRUETYPE_IMPLEMENTATION - #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() -#endif - -// Rectangle packing functions (not used at the moment) -//#define STB_RECT_PACK_IMPLEMENTATION -//#include "stb_rect_pack.h" - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define MAX_FORMATTEXT_LENGTH 256 -#define MAX_SUBTEXT_LENGTH 256 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global variables -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_DEFAULT_FONT) -static Font defaultFont; // Default font provided by raylib -// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core] -#endif - -//---------------------------------------------------------------------------------- -// Other Modules Functions Declaration (required by text) -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static Font LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) -#if defined(SUPPORT_FILEFORMAT_FNT) -static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) -#endif -#if defined(SUPPORT_FILEFORMAT_TTF) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data -#endif - -#if defined(SUPPORT_DEFAULT_FONT) -extern void LoadDefaultFont(void); -extern void UnloadDefaultFont(void); -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_DEFAULT_FONT) - -// Load raylib default font -extern void LoadDefaultFont(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 - // http://www.utf8-chartable.de/unicode-utf8-table.pl - - defaultFont.charsCount = 224; // Number of chars included in our default font - - // 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 - 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 - //---------------------------------------------------------------------- - int imWidth = 128; - int imHeight = 128; - - Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color)); - - for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array - - int counter = 0; // Font data elements counter - - // Fill imgData with defaultFontData (convert from bit to pixel!) - for (int i = 0; i < imWidth*imHeight; i += 32) - { - for (int j = 31; j >= 0; j--) - { - if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE; - } - - counter++; - - if (counter > 512) counter = 0; // Security check... - } - - //FILE *myimage = fopen("default_font.raw", "wb"); - //fwrite(image.pixels, 1, 128*128*4, myimage); - //fclose(myimage); - - Image image = LoadImageEx(imagePixels, imWidth, imHeight); - ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA); - - free(imagePixels); - - defaultFont.texture = LoadTextureFromImage(image); - UnloadImage(image); - - // 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 *)malloc(defaultFont.charsCount*sizeof(CharInfo)); - - 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.chars[i].rec.x = currentPosX; - defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor); - defaultFont.chars[i].rec.width = charsWidth[i]; - defaultFont.chars[i].rec.height = charsHeight; - - testPosX += (defaultFont.chars[i].rec.width + charsDivisor); - - if (testPosX >= defaultFont.texture.width) - { - currentLine++; - currentPosX = 2*charsDivisor + charsWidth[i]; - testPosX = currentPosX; - - defaultFont.chars[i].rec.x = charsDivisor; - defaultFont.chars[i].rec.y = 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; - } - - defaultFont.baseSize = defaultFont.chars[0].rec.height; - - TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); -} - -// Unload raylib default font -extern void UnloadDefaultFont(void) -{ - UnloadTexture(defaultFont.texture); - free(defaultFont.chars); -} -#endif // SUPPORT_DEFAULT_FONT - -// Get the default font, useful to be used with extended parameters -Font GetDefaultFont() -{ -#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 hardcoded values for ttf file loading - #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) - #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs - #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont - - Font spriteFont = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); - else -#endif -#if defined(SUPPORT_FILEFORMAT_FNT) - if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); - else -#endif - { - Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); - UnloadImage(image); - } - - if (spriteFont.texture.id == 0) - { - TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName); - spriteFont = GetDefaultFont(); - } - else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) - - return spriteFont; -} - -// 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 charsCount, int *fontChars) -{ - Font spriteFont = { 0 }; - int totalChars = 95; // Default charset [32..126] - -#if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) - { - if (charsCount != 0) totalChars = charsCount; - - if (fontChars == NULL) - { - fontChars = (int *)malloc(totalChars*sizeof(int)); - for (int i = 0; i < totalChars; i++) fontChars[i] = i + 32; // Default first character: SPACE[32] - } - - spriteFont = LoadTTF(fileName, fontSize, totalChars, fontChars); - } -#endif - - if (spriteFont.texture.id == 0) - { - TraceLog(LOG_WARNING, "[%s] Font could not be generated, using default font", fileName); - spriteFont = GetDefaultFont(); - } - - return spriteFont; -} - -// Unload Font from GPU memory (VRAM) -void UnloadFont(Font font) -{ - // NOTE: Make sure spriteFont is not default font (fallback) - if (font.texture.id != GetDefaultFont().texture.id) - { - UnloadTexture(font.texture); - free(font.chars); - - TraceLog(LOG_DEBUG, "Unloaded sprite font data"); - } -} - -// 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 (GetDefaultFont().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(GetDefaultFont(), 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) -{ - int length = strlen(text); - int textOffsetX = 0; // Offset between characters - int textOffsetY = 0; // Required for line break! - float scaleFactor; - - unsigned char letter; // Current character - int index; // Index position in sprite font - - scaleFactor = fontSize/font.baseSize; - - // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly - // written in C code files (codified by default as UTF-8) - - for (int i = 0; i < length; i++) - { - if ((unsigned char)text[i] == '\n') - { - // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); - textOffsetX = 0; - } - else - { - if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) - letter = (unsigned char)text[i + 1]; - index = GetGlyphIndex(font, (int)letter); - i++; - } - else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) - letter = (unsigned char)text[i + 1]; - index = GetGlyphIndex(font, (int)letter + 64); - i++; - } - else index = GetGlyphIndex(font, (unsigned char)text[i]); - - if ((unsigned char)text[i] != ' ') - { - DrawTexturePro(font.texture, font.chars[index].rec, - (Rectangle){ position.x + textOffsetX + font.chars[index].offsetX*scaleFactor, - position.y + textOffsetY + font.chars[index].offsetY*scaleFactor, - font.chars[index].rec.width*scaleFactor, - font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); - } - - if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.chars[index].rec.width*scaleFactor + spacing); - else textOffsetX += (int)(font.chars[index].advanceX*scaleFactor + spacing); - } - } -} - -// Formatting of text with variables to 'embed' -const char *FormatText(const char *text, ...) -{ - static char buffer[MAX_FORMATTEXT_LENGTH]; - - va_list args; - va_start(args, text); - vsprintf(buffer, text, args); - va_end(args); - - return buffer; -} - -// Get a piece of a text string -const char *SubText(const char *text, int position, int length) -{ - static char buffer[MAX_SUBTEXT_LENGTH]; - int textLength = strlen(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; -} - -// 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 (GetDefaultFont().texture.id != 0) - { - int defaultFontSize = 10; // Default Font chars height in pixel - if (fontSize < defaultFontSize) fontSize = defaultFontSize; - int spacing = fontSize/defaultFontSize; - - vec = MeasureTextEx(GetDefaultFont(), 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 = strlen(text); - int tempLen = 0; // Used to count longer text line num chars - int lenCounter = 0; - - float textWidth = 0; - float tempTextWidth = 0; // Used to count longer text line width - - float textHeight = (float)font.baseSize; - float scaleFactor = fontSize/(float)font.baseSize; - - for (int i = 0; i < len; i++) - { - lenCounter++; - - if (text[i] != '\n') - { - int index = GetGlyphIndex(font, (int)text[i]); - - if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX; - else textWidth += (font.chars[index].rec.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; - 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 character) -{ -#define UNORDERED_CHARSET -#if defined(UNORDERED_CHARSET) - int index = 0; - - for (int i = 0; i < font.charsCount; i++) - { - if (font.chars[i].value == character) - { - index = i; - break; - } - } - - return index; -#else - return (character - 32); -#endif -} - -// Shows current FPS on top-left corner -// NOTE: Uses default font -void DrawFPS(int posX, int posY) -{ - // NOTE: We are rendering fps every second for better viewing on high framerates - - static int fps = 0; - static int counter = 0; - static int refreshRate = 20; - - if (counter < refreshRate) counter++; - else - { - fps = GetFPS(); - refreshRate = fps; - counter = 0; - } - - // NOTE: We have rounding errors every frame, so it oscillates a lot - DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME); -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Load an Image font file (XNA style) -static Font LoadImageFont(Image image, Color key, int firstChar) -{ - #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; - - // Default number of characters supported - #define MAX_FONTCHARS 256 - - // 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_FONTCHARS]; - Rectangle tempCharRecs[MAX_FONTCHARS]; - - Color *pixels = GetImageData(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 = xPosToRead; - tempCharRecs[index].y = lineSpacing + lineToRead*(charHeight + lineSpacing); - tempCharRecs[index].height = charHeight; - - int charWidth = 0; - - while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++; - - tempCharRecs[index].width = charWidth; - - index++; - - xPosToRead += (charWidth + charSpacing); - } - - lineToRead++; - xPosToRead = charSpacing; - } - - TraceLog(LOG_DEBUG, "Font data parsed correctly from image"); - - // NOTE: We need to remove key color borders from image to avoid weird - // artifacts on texture scaling when using FILTER_BILINEAR or 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 = LoadImageEx(pixels, image.width, image.height); - - free(pixels); // Free pixels array memory - - // Create spritefont with all data parsed from image - Font spriteFont = { 0 }; - - spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture - spriteFont.charsCount = index; - - UnloadImage(fontClear); // Unload processed image once converted to texture - - // We got tempCharValues and tempCharsRecs populated with chars data - // Now we move temp data to sized charValues and charRecs arrays - spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); - - for (int i = 0; i < spriteFont.charsCount; i++) - { - spriteFont.chars[i].value = tempCharValues[i]; - spriteFont.chars[i].rec = tempCharRecs[i]; - - // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - spriteFont.chars[i].offsetX = 0; - spriteFont.chars[i].offsetY = 0; - spriteFont.chars[i].advanceX = 0; - } - - spriteFont.baseSize = spriteFont.chars[0].rec.height; - - TraceLog(LOG_INFO, "Image file loaded correctly as Font"); - - return spriteFont; -} - -#if defined(SUPPORT_FILEFORMAT_FNT) -// Load a BMFont file (AngelCode font file) -static Font LoadBMFont(const char *fileName) -{ - #define MAX_BUFFER_SIZE 256 - - Font font = { 0 }; - font.texture.id = 0; - - char buffer[MAX_BUFFER_SIZE]; - char *searchPoint = NULL; - - int fontSize = 0; - int texWidth, texHeight; - char texFileName[129]; - int charsCount = 0; - - int base; // Useless data - - FILE *fntFile; - - fntFile = fopen(fileName, "rt"); - - if (fntFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] FNT file could not be opened", fileName); - return font; - } - - // NOTE: We skip first line, it contains no useful information - fgets(buffer, MAX_BUFFER_SIZE, fntFile); - //searchPoint = strstr(buffer, "size"); - //sscanf(searchPoint, "size=%i", &fontSize); - - fgets(buffer, MAX_BUFFER_SIZE, fntFile); - searchPoint = strstr(buffer, "lineHeight"); - sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight); - - TraceLog(LOG_DEBUG, "[%s] Font size: %i", fileName, fontSize); - TraceLog(LOG_DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight); - - fgets(buffer, MAX_BUFFER_SIZE, fntFile); - searchPoint = strstr(buffer, "file"); - sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName); - - TraceLog(LOG_DEBUG, "[%s] Font texture filename: %s", fileName, texFileName); - - fgets(buffer, MAX_BUFFER_SIZE, fntFile); - searchPoint = strstr(buffer, "count"); - sscanf(searchPoint, "count=%i", &charsCount); - - TraceLog(LOG_DEBUG, "[%s] Font num chars: %i", fileName, charsCount); - - // Compose correct path using route of .fnt file (fileName) and texFileName - char *texPath = NULL; - char *lastSlash = NULL; - - lastSlash = strrchr(fileName, '/'); - - // NOTE: We need some extra space to avoid memory corruption on next allocations! - texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); - - // NOTE: strcat() and strncat() required a '\0' terminated string to work! - *texPath = '\0'; - strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1); - strncat(texPath, texFileName, strlen(texFileName)); - - TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath); - - Image imFont = LoadImage(texPath); - - if (imFont.format == UNCOMPRESSED_GRAYSCALE) - { - Image imCopy = ImageCopy(imFont); - - for (int i = 0; i < imCopy.width*imCopy.height; i++) ((unsigned char *)imCopy.data)[i] = 0xff; // WHITE pixel - - ImageAlphaMask(&imCopy, imFont); - font.texture = LoadTextureFromImage(imCopy); - UnloadImage(imCopy); - } - else font.texture = LoadTextureFromImage(imFont); - - font.baseSize = fontSize; - font.charsCount = charsCount; - font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); - - UnloadImage(imFont); - - free(texPath); - - int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - - for (int i = 0; i < charsCount; i++) - { - fgets(buffer, MAX_BUFFER_SIZE, fntFile); - 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); - - // Save data properly in sprite font - font.chars[i].value = charId; - font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight }; - font.chars[i].offsetX = charOffsetX; - font.chars[i].offsetY = charOffsetY; - font.chars[i].advanceX = charAdvanceX; - } - - fclose(fntFile); - - if (font.texture.id == 0) - { - UnloadFont(font); - font = GetDefaultFont(); - } - else TraceLog(LOG_INFO, "[%s] Font loaded successfully", fileName); - - return font; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_TTF) -// Generate a sprite font from TTF file data (font size required) -// TODO: Review texture packing method and generation (use oversampling) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) -{ - #define MAX_TTF_SIZE 16 // Maximum ttf file size in MB - - // NOTE: Font texture size is predicted (being as much conservative as possible) - // Predictive method consist of supposing same number of chars by line-column (sqrtf) - // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... - - // Calculate next power-of-two value - float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); - int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT - - TraceLog(LOG_INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); - - unsigned char *ttfBuffer = (unsigned char *)malloc(MAX_TTF_SIZE*1024*1024); - unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); - - Font font = { 0 }; - - FILE *ttfFile = fopen(fileName, "rb"); - - if (ttfFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); - return font; - } - - // NOTE: We try reading up to 16 MB of elements of 1 byte - fread(ttfBuffer, 1, MAX_TTF_SIZE*1024*1024, ttfFile); - - // Find font baseline (vertical origin of the font) - // NOTE: This value is required because y-offset depends on it! - stbtt_fontinfo fontInfo; - int ascent, baseline; - float scale; - - stbtt_InitFont(&fontInfo, ttfBuffer, 0); - scale = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); - stbtt_GetFontVMetrics(&fontInfo, &ascent, 0, 0); - baseline = (int)(ascent*scale); - - if (fontChars[0] != 32) TraceLog(LOG_WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); - - // NOTE: Using stb_truetype crappy packing method, no guarantee the font fits the image... - // TODO: Replace this function by a proper packing method and support random chars order, - // we already receive a list (fontChars) with the ordered expected characters - int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData); - - //if (result > 0) TraceLog(LOG_INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); - if (result < 0) TraceLog(LOG_WARNING, "TTF spritefont loading: Not all the characters fit in the font"); - - free(ttfBuffer); - - // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - - for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) - { - dataGrayAlpha[k] = 255; - dataGrayAlpha[k + 1] = dataBitmap[i]; - } - - free(dataBitmap); - - // Sprite font generation from TTF extracted data - Image image; - image.width = textureSize; - image.height = textureSize; - image.mipmaps = 1; - image.format = UNCOMPRESSED_GRAY_ALPHA; - image.data = dataGrayAlpha; - - font.texture = LoadTextureFromImage(image); - - //SavePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2); - - UnloadImage(image); // Unloads dataGrayAlpha - - font.baseSize = fontSize; - font.charsCount = charsCount; - font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo)); - - for (int i = 0; i < font.charsCount; i++) - { - font.chars[i].value = fontChars[i]; - - font.chars[i].rec.x = (int)charData[i].x0; - font.chars[i].rec.y = (int)charData[i].y0; - font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0; - font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; - - font.chars[i].offsetX = charData[i].xoff; - font.chars[i].offsetY = baseline + charData[i].yoff; - font.chars[i].advanceX = (int)charData[i].xadvance; - } - - free(charData); - - return font; -} -#endif diff --git a/raylib/text.go b/raylib/text.go deleted file mode 100644 index 909a2bd..0000000 --- a/raylib/text.go +++ /dev/null @@ -1,104 +0,0 @@ -package raylib - -/* -#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)) -} - -// GetDefaultFont - Get the default Font -func GetDefaultFont() Font { - ret := C.GetDefaultFont() - 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, charsCount int32, fontChars *int32) Font { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - cfontSize := (C.int)(fontSize) - ccharsCount := (C.int)(charsCount) - cfontChars := (*C.int)(unsafe.Pointer(fontChars)) - ret := C.LoadFontEx(cfileName, cfontSize, ccharsCount, cfontChars) - v := newFontFromPointer(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) -} - -// 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 -} - -// 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/textures.c b/raylib/textures.c deleted file mode 100644 index 56d2aa8..0000000 --- a/raylib/textures.c +++ /dev/null @@ -1,2687 +0,0 @@ -/********************************************************************************************** -* -* raylib.textures - Basic functions to load and draw Textures (2d) -* -* CONFIGURATION: -* -* #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_HDR -* #define SUPPORT_FILEFORMAT_DDS -* #define SUPPORT_FILEFORMAT_PKM -* #define SUPPORT_FILEFORMAT_KTX -* #define SUPPORT_FILEFORMAT_PVR -* #define SUPPORT_FILEFORMAT_ASTC -* Selecte 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_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 proedural 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 algorythms -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2018 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 "config.h" - -#include "raylib.h" - -#include // Required for: malloc(), free() -#include // Required for: strcmp(), strrchr(), strncmp() - -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 - // Required for: rlLoadTexture() rlDeleteTextures(), - // rlGenerateMipmaps(), some funcs for DrawTexturePro() - -#include "utils.h" // Required for: fopen() Android mapping - -#define STB_PERLIN_IMPLEMENTATION -#include "external/stb_perlin.h"// Required for: stb_perlin_fbm_noise3 - -// Support only desired texture formats on stb_image -#if !defined(SUPPORT_FILEFORMAT_BMP) - #define STBI_NO_BMP -#endif -#if !defined(SUPPORT_FILEFORMAT_PNG) - #define STBI_NO_PNG -#endif -#if !defined(SUPPORT_FILEFORMAT_TGA) - #define STBI_NO_TGA -#endif -#if !defined(SUPPORT_FILEFORMAT_JPG) - #define STBI_NO_JPEG // Image format .jpg and .jpeg -#endif -#if !defined(SUPPORT_FILEFORMAT_PSD) - #define STBI_NO_PSD -#endif -#if !defined(SUPPORT_FILEFORMAT_GIF) - #define STBI_NO_GIF -#endif -#if !defined(SUPPORT_FILEFORMAT_HDR) - #define STBI_NO_HDR -#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)) - #define STB_IMAGE_IMPLEMENTATION - #include "external/stb_image.h" // Required for: stbi_load_from_file() - // NOTE: Used to read image data (multiple formats support) -#endif - -#if defined(SUPPORT_IMAGE_MANIPULATION) - #define STB_IMAGE_RESIZE_IMPLEMENTATION - #include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() - // NOTE: Used for image scaling on ImageResize() -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// Nop... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// It's lonely here... - -//---------------------------------------------------------------------------------- -// Other Modules Functions Declaration (required by text) -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(SUPPORT_FILEFORMAT_DDS) -static Image LoadDDS(const char *fileName); // Load DDS file -#endif -#if defined(SUPPORT_FILEFORMAT_PKM) -static Image LoadPKM(const char *fileName); // Load PKM file -#endif -#if defined(SUPPORT_FILEFORMAT_KTX) -static Image LoadKTX(const char *fileName); // Load KTX file -#endif -#if defined(SUPPORT_FILEFORMAT_PVR) -static Image LoadPVR(const char *fileName); // Load PVR file -#endif -#if defined(SUPPORT_FILEFORMAT_ASTC) -static Image LoadASTC(const char *fileName); // Load ASTC file -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Load image from file into CPU memory (RAM) -Image LoadImage(const char *fileName) -{ - Image image = { 0 }; - - if ((IsFileExtension(fileName, ".png")) -#if defined(SUPPORT_FILEFORMAT_BMP) - || (IsFileExtension(fileName, ".bmp")) -#endif -#if defined(SUPPORT_FILEFORMAT_TGA) - || (IsFileExtension(fileName, ".tga")) -#endif -#if defined(SUPPORT_FILEFORMAT_JPG) - || (IsFileExtension(fileName, ".jpg")) -#endif -#if defined(SUPPORT_FILEFORMAT_DDS) - || (IsFileExtension(fileName, ".gif")) -#endif -#if defined(SUPPORT_FILEFORMAT_PSD) - || (IsFileExtension(fileName, ".psd")) -#endif - ) - { - int imgWidth = 0; - int imgHeight = 0; - int imgBpp = 0; - - FILE *imFile = fopen(fileName, "rb"); - - if (imFile != NULL) - { - // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) - image.data = stbi_load_from_file(imFile, &imgWidth, &imgHeight, &imgBpp, 0); - - fclose(imFile); - - image.width = imgWidth; - image.height = imgHeight; - image.mipmaps = 1; - - if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE; - else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA; - else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8; - else if (imgBpp == 4) image.format = UNCOMPRESSED_R8G8B8A8; - } - } -#if defined(SUPPORT_FILEFORMAT_HDR) - else if (IsFileExtension(fileName, ".hdr")) - { - int imgBpp = 0; - - FILE *imFile = fopen(fileName, "rb"); - - stbi_set_flip_vertically_on_load(true); - - // Load 32 bit per channel floats data - image.data = stbi_loadf_from_file(imFile, &image.width, &image.height, &imgBpp, 0); - - stbi_set_flip_vertically_on_load(false); - - fclose(imFile); - - image.mipmaps = 1; - - if (imgBpp == 1) image.format = UNCOMPRESSED_R32; - else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32; - else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32; - else - { - TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName); - UnloadImage(image); - } - } -#endif -#if defined(SUPPORT_FILEFORMAT_DDS) - else if (IsFileExtension(fileName, ".dds")) image = LoadDDS(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_PKM) - else if (IsFileExtension(fileName, ".pkm")) image = LoadPKM(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_KTX) - else if (IsFileExtension(fileName, ".ktx")) image = LoadKTX(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_PVR) - else if (IsFileExtension(fileName, ".pvr")) image = LoadPVR(fileName); -#endif -#if defined(SUPPORT_FILEFORMAT_ASTC) - else if (IsFileExtension(fileName, ".astc")) image = LoadASTC(fileName); -#endif - else TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName); - - if (image.data != NULL) TraceLog(LOG_INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height); - else TraceLog(LOG_WARNING, "[%s] Image could not be loaded", fileName); - - return image; -} - -// Load image from Color array data (RGBA - 32bit) -// NOTE: Creates a copy of pixels data array -Image LoadImageEx(Color *pixels, int width, int height) -{ - Image image; - image.data = NULL; - image.width = width; - image.height = height; - image.mipmaps = 1; - image.format = UNCOMPRESSED_R8G8B8A8; - - int k = 0; - - image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); - - for (int i = 0; i < image.width*image.height*4; i += 4) - { - ((unsigned char *)image.data)[i] = pixels[k].r; - ((unsigned char *)image.data)[i + 1] = pixels[k].g; - ((unsigned char *)image.data)[i + 2] = pixels[k].b; - ((unsigned char *)image.data)[i + 3] = pixels[k].a; - k++; - } - - return image; -} - -// Load image from raw data with parameters -// NOTE: This functions makes a copy of provided data -Image LoadImagePro(void *data, int width, int height, int format) -{ - Image srcImage = { 0 }; - - srcImage.data = data; - srcImage.width = width; - srcImage.height = height; - srcImage.mipmaps = 1; - srcImage.format = format; - - Image dstImage = ImageCopy(srcImage); - - return dstImage; -} - -// Load an image from RAW file data -Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize) -{ - Image image = { 0 }; - - FILE *rawFile = fopen(fileName, "rb"); - - if (rawFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] RAW image file could not be opened", fileName); - } - else - { - if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); - - unsigned int size = GetPixelDataSize(width, height, format); - - image.data = malloc(size); // Allocate required memory in bytes - - // NOTE: fread() returns num read elements instead of bytes, - // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element) - int bytes = fread(image.data, 1, size, rawFile); - - // Check if data has been read successfully - if (bytes < size) - { - TraceLog(LOG_WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName); - - if (image.data != NULL) free(image.data); - } - else - { - image.width = width; - image.height = height; - image.mipmaps = 1; - image.format = format; - } - - fclose(rawFile); - } - - return image; -} - -// Load texture from file into GPU memory (VRAM) -Texture2D LoadTexture(const char *fileName) -{ - Texture2D texture = { 0 }; - - Image image = LoadImage(fileName); - - if (image.data != NULL) - { - texture = LoadTextureFromImage(image); - UnloadImage(image); - } - else TraceLog(LOG_WARNING, "Texture could not be created"); - - return texture; -} - -// Load a texture from image data -// NOTE: image is not unloaded, it must be done manually -Texture2D LoadTextureFromImage(Image image) -{ - Texture2D texture = { 0 }; - - texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps); - - texture.width = image.width; - texture.height = image.height; - texture.mipmaps = image.mipmaps; - texture.format = image.format; - - return texture; -} - -// Load texture for rendering (framebuffer) -RenderTexture2D LoadRenderTexture(int width, int height) -{ - RenderTexture2D target = rlLoadRenderTexture(width, height); - - return target; -} - -// Unload image from CPU memory (RAM) -void UnloadImage(Image image) -{ - if (image.data != NULL) free(image.data); - - // NOTE: It becomes anoying every time a texture is loaded - //TraceLog(LOG_INFO, "Unloaded image data"); -} - -// Unload texture from GPU memory (VRAM) -void UnloadTexture(Texture2D texture) -{ - if (texture.id > 0) - { - rlDeleteTextures(texture.id); - - TraceLog(LOG_INFO, "[TEX ID %i] Unloaded texture data from VRAM (GPU)", texture.id); - } -} - -// Unload render texture from GPU memory (VRAM) -void UnloadRenderTexture(RenderTexture2D target) -{ - if (target.id > 0) rlDeleteRenderTextures(target); -} - -// Get pixel data from image in the form of Color struct array -// TODO: Support float pixel data retrieval -Color *GetImageData(Image image) -{ - Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); - - for (int i = 0, k = 0; i < image.width*image.height; i++) - { - switch (image.format) - { - case UNCOMPRESSED_GRAYSCALE: - { - pixels[i].r = ((unsigned char *)image.data)[i]; - pixels[i].g = ((unsigned char *)image.data)[i]; - pixels[i].b = ((unsigned char *)image.data)[i]; - pixels[i].a = 255; - - } break; - case UNCOMPRESSED_GRAY_ALPHA: - { - pixels[i].r = ((unsigned char *)image.data)[k]; - pixels[i].g = ((unsigned char *)image.data)[k]; - pixels[i].b = ((unsigned char *)image.data)[k]; - pixels[i].a = ((unsigned char *)image.data)[k + 1]; - - k += 2; - } break; - case UNCOMPRESSED_R5G5B5A1: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); - pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); - pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); - - } break; - case UNCOMPRESSED_R5G6B5: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - pixels[i].r = (unsigned char)((float)((pixel & 0b1111100000000000) >> 11)*(255/31)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); - pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); - pixels[i].a = 255; - - } break; - case UNCOMPRESSED_R4G4B4A4: - { - unsigned short pixel = ((unsigned short *)image.data)[i]; - - pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); - pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); - pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); - pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); - - } break; - case UNCOMPRESSED_R8G8B8A8: - { - pixels[i].r = ((unsigned char *)image.data)[k]; - pixels[i].g = ((unsigned char *)image.data)[k + 1]; - pixels[i].b = ((unsigned char *)image.data)[k + 2]; - pixels[i].a = ((unsigned char *)image.data)[k + 3]; - - k += 4; - } break; - case UNCOMPRESSED_R8G8B8: - { - pixels[i].r = (unsigned char)((unsigned char *)image.data)[k]; - pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1]; - pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2]; - pixels[i].a = 255; - - k += 3; - } break; - default: TraceLog(LOG_WARNING, "Format not supported for pixel data retrieval"); break; - } - } - - return pixels; -} - -// Get pixel data size in bytes (image or texture) -// NOTE: Size depends on pixel format -int GetPixelDataSize(int width, int height, int format) -{ - int dataSize = 0; // Size in bytes - int bpp = 0; // Bits per pixel - - switch (format) - { - case UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case UNCOMPRESSED_GRAY_ALPHA: - case UNCOMPRESSED_R5G6B5: - case UNCOMPRESSED_R5G5B5A1: - case UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case UNCOMPRESSED_R8G8B8: bpp = 24; break; - case UNCOMPRESSED_R32: bpp = 32; break; - case UNCOMPRESSED_R32G32B32: bpp = 32*3; break; - case UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; - case COMPRESSED_DXT1_RGB: - case COMPRESSED_DXT1_RGBA: - case COMPRESSED_ETC1_RGB: - case COMPRESSED_ETC2_RGB: - case COMPRESSED_PVRT_RGB: - case COMPRESSED_PVRT_RGBA: bpp = 4; break; - case COMPRESSED_DXT3_RGBA: - case COMPRESSED_DXT5_RGBA: - case COMPRESSED_ETC2_EAC_RGBA: - case COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; - default: break; - } - - dataSize = width*height*bpp/8; // Total data size in bytes - - return dataSize; -} - -// 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 < 8) - { - image.data = rlReadTexturePixels(texture); - - if (image.data != NULL) - { - image.width = texture.width; - image.height = texture.height; - image.format = texture.format; - image.mipmaps = 1; - - // NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA - // coming from FBO color buffer, but it seems original - // texture format is retrieved on RPI... weird... - //image.format = UNCOMPRESSED_R8G8B8A8; - - TraceLog(LOG_INFO, "Texture pixel data obtained successfully"); - } - else TraceLog(LOG_WARNING, "Texture pixel data could not be obtained"); - } - else TraceLog(LOG_WARNING, "Compressed texture data could not be obtained"); - - return image; -} - -// Update GPU texture with new data -// NOTE: pixels data must match texture.format -void UpdateTexture(Texture2D texture, const void *pixels) -{ - rlUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels); -} - -// Export image as a PNG file -void ExportImage(const char *fileName, Image image) -{ - // NOTE: Getting Color array as RGBA unsigned char values - unsigned char *imgData = (unsigned char *)GetImageData(image); - SavePNG(fileName, imgData, image.width, image.height, 4); - free(imgData); -} - -// Copy an image to a new image -Image ImageCopy(Image image) -{ - Image newImage = { 0 }; - - int width = image.width; - int height = image.height; - int size = 0; - - for (int i = 0; i < image.mipmaps; i++) - { - size += GetPixelDataSize(width, height, image.format); - - width /= 2; - height /= 2; - - // Security check for NPOT textures - if (width < 1) width = 1; - if (height < 1) height = 1; - } - - newImage.data = malloc(size); - - if (newImage.data != NULL) - { - // NOTE: Size must be provided in bytes - memcpy(newImage.data, image.data, size); - - newImage.width = image.width; - newImage.height = image.height; - newImage.mipmaps = image.mipmaps; - newImage.format = image.format; - } - - return newImage; -} - -// Convert image to POT (power-of-two) -// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) -void ImageToPOT(Image *image, Color fillColor) -{ - Color *pixels = GetImageData(*image); // Get pixels data - - // Calculate next power-of-two values - // NOTE: Just add the required amount of pixels at the right and bottom sides of image... - int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); - int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); - - // Check if POT texture generation is required (if texture is not already POT) - if ((potWidth != image->width) || (potHeight != image->height)) - { - Color *pixelsPOT = NULL; - - // Generate POT array from NPOT data - pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); - - for (int j = 0; j < potHeight; j++) - { - for (int i = 0; i < potWidth; i++) - { - if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; - else pixelsPOT[j*potWidth + i] = fillColor; - } - } - - TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); - - free(pixels); // Free pixels data - free(image->data); // Free old image data - - int format = image->format; // Store image data format to reconvert later - - // TODO: Image width and height changes... do we want to store new values or keep the old ones? - // NOTE: Issues when using image.width and image.height for sprite animations... - *image = LoadImageEx(pixelsPOT, potWidth, potHeight); - - free(pixelsPOT); // Free POT pixels data - - ImageFormat(image, format); // Reconvert image to previous format - } -} - -// Convert image data to desired format -void ImageFormat(Image *image, int newFormat) -{ - if (image->format != newFormat) - { - if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB)) - { - Color *pixels = GetImageData(*image); - - free(image->data); // WARNING! We loose mipmaps data --> Regenerated at the end... - image->data = NULL; - image->format = newFormat; - - int k = 0; - - switch (image->format) - { - case UNCOMPRESSED_GRAYSCALE: - { - image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height; i++) - { - ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[i].r*0.299f + (float)pixels[i].g*0.587f + (float)pixels[i].b*0.114f); - } - - } break; - case UNCOMPRESSED_GRAY_ALPHA: - { - image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); - - for (int i = 0; i < image->width*image->height*2; i += 2, k++) - { - ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); - ((unsigned char *)image->data)[i + 1] = pixels[k].a; - } - - } break; - case UNCOMPRESSED_R5G6B5: - { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r = 0; - unsigned char g = 0; - unsigned char b = 0; - - for (int i = 0; i < image->width*image->height; i++) - { - r = (unsigned char)(round((float)pixels[i].r*31.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*63.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*31.0f/255)); - - ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; - } - - } break; - case UNCOMPRESSED_R8G8B8: - { - image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); - - for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) - { - ((unsigned char *)image->data)[i] = pixels[k].r; - ((unsigned char *)image->data)[i + 1] = pixels[k].g; - ((unsigned char *)image->data)[i + 2] = pixels[k].b; - } - } break; - case UNCOMPRESSED_R5G5B5A1: - { - #define ALPHA_THRESHOLD 50 - - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r = 0; - unsigned char g = 0; - unsigned char b = 0; - unsigned char a = 0; - - for (int i = 0; i < image->width*image->height; i++) - { - r = (unsigned char)(round((float)pixels[i].r*31.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*31.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*31.0f/255)); - a = (pixels[i].a > ALPHA_THRESHOLD) ? 1 : 0; - - ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; - } - - } break; - case UNCOMPRESSED_R4G4B4A4: - { - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - unsigned char r = 0; - unsigned char g = 0; - unsigned char b = 0; - unsigned char a = 0; - - for (int i = 0; i < image->width*image->height; i++) - { - r = (unsigned char)(round((float)pixels[i].r*15.0f/255)); - g = (unsigned char)(round((float)pixels[i].g*15.0f/255)); - b = (unsigned char)(round((float)pixels[i].b*15.0f/255)); - a = (unsigned char)(round((float)pixels[i].a*15.0f/255)); - - ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8 | (unsigned short)b << 4 | (unsigned short)a; - } - - } break; - case UNCOMPRESSED_R8G8B8A8: - { - image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); - - for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) - { - ((unsigned char *)image->data)[i] = pixels[k].r; - ((unsigned char *)image->data)[i + 1] = pixels[k].g; - ((unsigned char *)image->data)[i + 2] = pixels[k].b; - ((unsigned char *)image->data)[i + 3] = pixels[k].a; - } - } break; - case UNCOMPRESSED_R32: - { - image->data = (float *)malloc(image->width*image->height*sizeof(float)); - - for (int i = 0; i < image->width*image->height; i++) - { - ((float *)image->data)[i] = (float)((float)pixels[i].r*0.299f/255.0f + (float)pixels[i].g*0.587f/255.0f + (float)pixels[i].b*0.114f/255.0f); - } - } break; - case UNCOMPRESSED_R32G32B32: - { - image->data = (float *)malloc(image->width*image->height*3*sizeof(float)); - - for (int i = 0, k = 0; i < image->width*image->height*3; i += 3, k++) - { - ((float *)image->data)[i] = (float)pixels[k].r/255.0f; - ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; - ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; - } - } break; - case UNCOMPRESSED_R32G32B32A32: - { - image->data = (float *)malloc(image->width*image->height*4*sizeof(float)); - - for (int i = 0, k = 0; i < image->width*image->height*4; i += 4, k++) - { - ((float *)image->data)[i] = (float)pixels[k].r/255.0f; - ((float *)image->data)[i + 1] = (float)pixels[k].g/255.0f; - ((float *)image->data)[i + 2] = (float)pixels[k].b/255.0f; - ((float *)image->data)[i + 3] = (float)pixels[k].a/255.0f; - } - } break; - default: break; - } - - free(pixels); - pixels = NULL; - // 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) - { - image->mipmaps = 1; - assert(image->data != NULL); - ImageMipmaps(image); - } - } - else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted"); - } -} - -// Apply alpha mask to image -// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit) -// NOTE 2: alphaMask should be same size as image -void ImageAlphaMask(Image *image, Image alphaMask) -{ - if ((image->width != alphaMask.width) || (image->height != alphaMask.height)) - { - TraceLog(LOG_WARNING, "Alpha mask must be same size as image"); - } - else if (image->format >= COMPRESSED_DXT1_RGB) - { - TraceLog(LOG_WARNING, "Alpha mask can not be applied to compressed data formats"); - } - else - { - // Force mask to be Grayscale - Image mask = ImageCopy(alphaMask); - if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); - - // In case image is only grayscale, we just add alpha channel - if (image->format == UNCOMPRESSED_GRAYSCALE) - { - ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA); - - // Apply alpha mask to alpha channel - for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2) - { - ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; - } - } - else - { - // Convert image to RGBA - if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); - - // Apply alpha mask to alpha channel - for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) - { - ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; - } - } - - UnloadImage(mask); - } -} - -// Clear alpha channel to desired color -// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f -void ImageAlphaClear(Image *image, Color color, float threshold) -{ - Color *pixels = GetImageData(*image); - - for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color; - - UnloadImage(*image); - - int prevFormat = image->format; - *image = LoadImageEx(pixels, image->width, image->height); - - ImageFormat(image, prevFormat); -} - -// Crop image depending on alpha value -void ImageAlphaCrop(Image *image, float threshold) -{ - Rectangle crop = { 0 }; - - Color *pixels = GetImageData(*image); - - int minx = 0; - int miny = 0; - - for (int i = 0; i < image->width*image->height; i++) - { - if (pixels[i].a > (unsigned char)(threshold*255.0f)) - { - minx = i%image->width; - miny = -(-((i/image->width) + 1) + 1); - - if (crop.y == 0) crop.y = miny; - - if (crop.x == 0) crop.x = minx; - else if (minx < crop.x) crop.x = minx; - - if (crop.width == 0) crop.width = minx; - else if (crop.width < minx) crop.width = minx; - - if (crop.height == 0) crop.height = miny; - else if (crop.height < miny) crop.height = miny; - } - } - - crop.width -= (crop.x - 1); - crop.height -= (crop.y - 1); - - TraceLog(LOG_INFO, "Crop rectangle: (%i, %i, %i, %i)", crop.x, crop.y, crop.width, crop.height); - - free(pixels); - - // NOTE: Added this weird check to avoid additional 1px crop to - // image data that has already been cropped... - if ((crop.x != 1) && - (crop.y != 1) && - (crop.width != image->width - 1) && - (crop.height != image->height - 1)) ImageCrop(image, crop); -} - -// Premultiply alpha channel -void ImageAlphaPremultiply(Image *image) -{ - float alpha = 0.0f; - Color *pixels = GetImageData(*image); - - for (int i = 0; i < image->width*image->height; i++) - { - alpha = (float)pixels[i].a/255.0f; - pixels[i].r = (unsigned char)((float)pixels[i].r*alpha); - pixels[i].g = (unsigned char)((float)pixels[i].g*alpha); - pixels[i].b = (unsigned char)((float)pixels[i].b*alpha); - } - - UnloadImage(*image); - - int prevFormat = image->format; - *image = LoadImageEx(pixels, image->width, image->height); - - ImageFormat(image, prevFormat); -} - - - -#if defined(SUPPORT_IMAGE_MANIPULATION) -// Crop an image to area defined by a rectangle -// NOTE: Security checks are performed in case rectangle goes out of bounds -void ImageCrop(Image *image, Rectangle crop) -{ - // Security checks to make sure cropping rectangle is inside margins - if ((crop.x + crop.width) > image->width) - { - crop.width = image->width - crop.x; - TraceLog(LOG_WARNING, "Crop rectangle width out of bounds, rescaled crop width: %i", crop.width); - } - - if ((crop.y + crop.height) > image->height) - { - crop.height = image->height - crop.y; - TraceLog(LOG_WARNING, "Crop rectangle height out of bounds, rescaled crop height: %i", crop.height); - } - - if ((crop.x < image->width) && (crop.y < image->height)) - { - // Start the cropping process - Color *pixels = GetImageData(*image); // Get data as Color pixels array - Color *cropPixels = (Color *)malloc((int)crop.width*(int)crop.height*sizeof(Color)); - - for (int j = (int)crop.y; j < (int)(crop.y + crop.height); j++) - { - for (int i = (int)crop.x; i < (int)(crop.x + crop.width); i++) - { - cropPixels[(j - (int)crop.y)*(int)crop.width + (i - (int)crop.x)] = pixels[j*image->width + i]; - } - } - - free(pixels); - - int format = image->format; - - UnloadImage(*image); - - *image = LoadImageEx(cropPixels, (int)crop.width, (int)crop.height); - - free(cropPixels); - - // Reformat 32bit RGBA image to original format - ImageFormat(image, format); - } - else - { - TraceLog(LOG_WARNING, "Image can not be cropped, crop rectangle out of bounds"); - } -} - -// 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) -{ - // Get data as Color pixels array to work with it - Color *pixels = GetImageData(*image); - Color *output = (Color *)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; - - UnloadImage(*image); - - *image = LoadImageEx(output, newWidth, newHeight); - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - - free(output); - free(pixels); -} - -// Resize and image to new size using Nearest-Neighbor scaling algorithm -void ImageResizeNN(Image *image,int newWidth,int newHeight) -{ - Color *pixels = GetImageData(*image); - Color *output = (Color *)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; - - UnloadImage(*image); - - *image = LoadImageEx(output, newWidth, newHeight); - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - - free(output); - free(pixels); -} - -// Generate all mipmap levels for a provided image -// NOTE 1: Supports POT and NPOT images -// NOTE 2: image.data is scaled to include mipmap levels -// NOTE 3: Mipmaps format is the same as base image -void ImageMipmaps(Image *image) -{ - int mipCount = 1; // Required mipmap levels count (including base level) - int mipWidth = image->width; // Base image width - int mipHeight = image->height; // Base image height - int mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); // Image data size (in bytes) - - // Count mipmap levels required - while ((mipWidth != 1) || (mipHeight != 1)) - { - if (mipWidth != 1) mipWidth /= 2; - if (mipHeight != 1) mipHeight /= 2; - - // Security check for NPOT textures - if (mipWidth < 1) mipWidth = 1; - if (mipHeight < 1) mipHeight = 1; - - TraceLog(LOG_DEBUG, "Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize); - - mipCount++; - mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format); // Add mipmap size (in bytes) - } - - TraceLog(LOG_DEBUG, "Mipmaps available: %i - Mipmaps required: %i", image->mipmaps, mipCount); - TraceLog(LOG_DEBUG, "Mipmaps total size required: %i", mipSize); - TraceLog(LOG_DEBUG, "Image data memory start address: 0x%x", image->data); - - if (image->mipmaps < mipCount) - { - void *temp = realloc(image->data, mipSize); - - if (temp != NULL) - { - image->data = temp; // Assign new pointer (new size) to store mipmaps data - TraceLog(LOG_DEBUG, "Image data memory point reallocated: 0x%x", temp); - } - else TraceLog(LOG_WARNING, "Mipmaps required memory could not be allocated"); - - // Pointer to allocated memory point where store next mipmap level data - unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format); - - 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++) - { - TraceLog(LOG_DEBUG, "Gen 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; - - // Security check for NPOT textures - if (mipWidth < 1) mipWidth = 1; - if (mipHeight < 1) mipHeight = 1; - - mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); - } - - UnloadImage(imCopy); - } - 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 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) -{ - if (image->format >= COMPRESSED_DXT1_RGB) - { - TraceLog(LOG_WARNING, "Compressed data formats can not be dithered"); - return; - } - - if ((rBpp+gBpp+bBpp+aBpp) > 16) - { - TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); - } - else - { - Color *pixels = GetImageData(*image); - - free(image->data); // free old image data - - if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) - { - TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); - } - - // Define new image format, check if desired bpp match internal known format - if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; - else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; - else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; - else - { - image->format = 0; - TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); - } - - // NOTE: We will store the dithered data as unsigned short (16bpp) - image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - - Color oldPixel = WHITE; - Color newPixel = WHITE; - - int rError, gError, bError; - unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition - - #define MIN(a,b) (((a)<(b))?(a):(b)) - - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - oldPixel = pixels[y*image->width + x]; - - // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) - newPixel.r = oldPixel.r >> (8 - rBpp); // R bits - newPixel.g = oldPixel.g >> (8 - gBpp); // G bits - newPixel.b = oldPixel.b >> (8 - bBpp); // B bits - newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering) - - // NOTE: Error must be computed between new and old pixel but using same number of bits! - // We want to know how much color precision we have lost... - rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); - gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); - bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); - - pixels[y*image->width + x] = newPixel; - - // NOTE: Some cases are out of the array and should be ignored - if (x < (image->width - 1)) - { - pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); - pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); - pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); - } - - if ((x > 0) && (y < (image->height - 1))) - { - pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); - pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); - pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); - } - - if (y < (image->height - 1)) - { - pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); - pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); - pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); - } - - if ((x < (image->width - 1)) && (y < (image->height - 1))) - { - pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); - pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); - pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); - } - - rPixel = (unsigned short)newPixel.r; - gPixel = (unsigned short)newPixel.g; - bPixel = (unsigned short)newPixel.b; - aPixel = (unsigned short)newPixel.a; - - ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; - } - } - - free(pixels); - } -} - -// Draw an image (source) within an image (destination) -// TODO: Feel this function could be simplified... -void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) -{ - bool cropRequired = false; - - // Security checks to avoid size and rectangle issues (out of bounds) - // Check that srcRec is inside src image - if (srcRec.x < 0) srcRec.x = 0; - if (srcRec.y < 0) srcRec.y = 0; - - if ((srcRec.x + srcRec.width) > src.width) - { - srcRec.width = src.width - srcRec.x; - TraceLog(LOG_WARNING, "Source rectangle width out of bounds, rescaled width: %i", srcRec.width); - } - - if ((srcRec.y + srcRec.height) > src.height) - { - srcRec.height = src.height - srcRec.y; - TraceLog(LOG_WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height); - cropRequired = true; - } - - Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it - ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle - - // Check that dstRec is inside dst image - // TODO: Allow negative position within destination with cropping - if (dstRec.x < 0) dstRec.x = 0; - if (dstRec.y < 0) dstRec.y = 0; - - // Scale source image in case destination rec size is different than source rec size - if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) - { - ImageResize(&srcCopy, dstRec.width, dstRec.height); - } - - if ((dstRec.x + dstRec.width) > dst->width) - { - dstRec.width = dst->width - dstRec.x; - TraceLog(LOG_WARNING, "Destination rectangle width out of bounds, rescaled width: %i", dstRec.width); - cropRequired = true; - } - - if ((dstRec.y + dstRec.height) > dst->height) - { - dstRec.height = dst->height - dstRec.y; - TraceLog(LOG_WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height); - cropRequired = true; - } - - if (cropRequired) - { - // Crop destination rectangle if out of bounds - Rectangle crop = { 0, 0, dstRec.width, dstRec.height }; - ImageCrop(&srcCopy, crop); - } - - // Get image data as Color pixels array to work with it - Color *dstPixels = GetImageData(*dst); - Color *srcPixels = GetImageData(srcCopy); - - UnloadImage(srcCopy); // Source copy not required any more... - - Vector4 fsrc, fdst, fout; // float based versions of pixel data - - // Blit pixels, copy source image into destination - // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping... - for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++) - { - for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++) - { - // Alpha blending (https://en.wikipedia.org/wiki/Alpha_compositing) - - fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]); - fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]); - - fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w); - - if (fout.w <= 0.0f) - { - fout.x = 0.0f; - fout.y = 0.0f; - fout.z = 0.0f; - } - else - { - fout.x = (fsrc.x*fsrc.w + fdst.x*fdst.w*(1 - fsrc.w))/fout.w; - fout.y = (fsrc.y*fsrc.w + fdst.y*fdst.w*(1 - fsrc.w))/fout.w; - fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w; - } - - dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f), - (unsigned char)(fout.y*255.0f), - (unsigned char)(fout.z*255.0f), - (unsigned char)(fout.w*255.0f) }; - - // TODO: Support other blending options - } - } - - UnloadImage(*dst); // NOTE: Only dst->data is unloaded - - *dst = LoadImageEx(dstPixels, (int)dst->width, (int)dst->height); - ImageFormat(dst, dst->format); - - free(srcPixels); - free(dstPixels); -} - -// 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 = (float)fontSize/defaultFontSize; - - Image imText = ImageTextEx(GetDefaultFont(), 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 = strlen(text); - int posX = 0; - int index; // Index position in sprite font - unsigned char character; // Current character - - // TODO: ISSUE: Measured text size does not seem to be correct... issue on ImageDraw() - Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing); - - TraceLog(LOG_DEBUG, "Text Image size: %f, %f", imSize.x, imSize.y); - - // NOTE: glGetTexImage() not available in OpenGL ES - // TODO: This is horrible, retrieving font texture from GPU!!! - // Define ImageFont struct? or include Image spritefont in Font struct? - Image imFont = GetTextureData(font.texture); - - ImageColorTint(&imFont, tint); // Apply color tint to font - - // Create image to store text - Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); - - for (int i = 0; i < length; i++) - { - if ((unsigned char)text[i] == '\n') - { - // TODO: Support line break - } - else - { - if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) - character = (unsigned char)text[i + 1]; - index = GetGlyphIndex(font, (int)character); - i++; - } - else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) - character = (unsigned char)text[i + 1]; - index = GetGlyphIndex(font, (int)character + 64); - i++; - } - else index = GetGlyphIndex(font, (unsigned char)text[i]); - - CharInfo letter = font.chars[index]; - - if ((unsigned char)text[i] != ' ') - { - ImageDraw(&imText, imFont, letter.rec, (Rectangle){ posX + letter.offsetX, - letter.offsetY, letter.rec.width, letter.rec.height }); - } - - if (letter.advanceX == 0) posX += letter.rec.width + spacing; - else posX += letter.advanceX + spacing; - } - } - - UnloadImage(imFont); - - // 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 == GetDefaultFont().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; -} - -// Draw rectangle within an image -void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color) -{ - Image imRec = GenImageColor(rec.width, rec.height, color); - - Rectangle dstRec = { position.x, position.y, imRec.width, imRec.height }; - - ImageDraw(dst, imRec, rec, dstRec); - - UnloadImage(imRec); -} - -// Draw text (default font) within an image (destination) -void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) -{ - // NOTE: For default font, sapcing is set to desired font size / default font size (10) - ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, (float)fontSize/10, color); -} - -// Draw text (custom sprite font) within an image (destination) -void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color) -{ - Image imText = ImageTextEx(font, text, fontSize, spacing, color); - - Rectangle srcRec = { 0, 0, imText.width, imText.height }; - Rectangle dstRec = { position.x, position.y, imText.width, imText.height }; - - ImageDraw(dst, imText, srcRec, dstRec); - - UnloadImage(imText); -} - -// Flip image vertically -void ImageFlipVertical(Image *image) -{ - Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); - - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - dstPixels[y*image->width + x] = srcPixels[(image->height - 1 - y)*image->width + x]; - } - } - - Image processed = LoadImageEx(dstPixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - - free(srcPixels); - free(dstPixels); - - image->data = processed.data; -} - -// Flip image horizontally -void ImageFlipHorizontal(Image *image) -{ - Color *srcPixels = GetImageData(*image); - Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); - - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - dstPixels[y*image->width + x] = srcPixels[y*image->width + (image->width - 1 - x)]; - } - } - - Image processed = LoadImageEx(dstPixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - - free(srcPixels); - free(dstPixels); - - image->data = processed.data; -} - -// Modify image color: tint -void ImageColorTint(Image *image, Color color) -{ - Color *pixels = GetImageData(*image); - - float cR = (float)color.r/255; - float cG = (float)color.g/255; - float cB = (float)color.b/255; - float cA = (float)color.a/255; - - for (int y = 0; y < image->height; y++) - { - for (int x = 0; x < image->width; x++) - { - unsigned char r = 255*((float)pixels[y*image->width + x].r/255*cR); - unsigned char g = 255*((float)pixels[y*image->width + x].g/255*cG); - unsigned char b = 255*((float)pixels[y*image->width + x].b/255*cB); - unsigned char a = 255*((float)pixels[y*image->width + x].a/255*cA); - - 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; - } - } - - Image processed = LoadImageEx(pixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - free(pixels); - - image->data = processed.data; -} - -// Modify image color: invert -void ImageColorInvert(Image *image) -{ - Color *pixels = GetImageData(*image); - - for (int y = 0; y < image->height; y++) - { - 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; - } - } - - Image processed = LoadImageEx(pixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - free(pixels); - - image->data = processed.data; -} - -// Modify image color: grayscale -void ImageColorGrayscale(Image *image) -{ - ImageFormat(image, UNCOMPRESSED_GRAYSCALE); -} - -// Modify image color: contrast -// NOTE: Contrast values between -100 and 100 -void ImageColorContrast(Image *image, float contrast) -{ - if (contrast < -100) contrast = -100; - if (contrast > 100) contrast = 100; - - contrast = (100.0f + contrast)/100.0f; - contrast *= contrast; - - Color *pixels = GetImageData(*image); - - for (int y = 0; y < image->height; y++) - { - 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[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[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[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; - } - } - - Image processed = LoadImageEx(pixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - free(pixels); - - image->data = processed.data; -} - -// Modify image color: brightness -// NOTE: Brightness values between -255 and 255 -void ImageColorBrightness(Image *image, int brightness) -{ - if (brightness < -255) brightness = -255; - if (brightness > 255) brightness = 255; - - Color *pixels = GetImageData(*image); - - for (int y = 0; y < image->height; y++) - { - 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 (cG < 0) cG = 1; - if (cG > 255) cG = 255; - - if (cB < 0) cB = 1; - if (cB > 255) cB = 255; - - 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; - } - } - - Image processed = LoadImageEx(pixels, image->width, image->height); - ImageFormat(&processed, image->format); - UnloadImage(*image); - free(pixels); - - image->data = processed.data; -} -#endif // SUPPORT_IMAGE_MANIPULATION - -#if defined(SUPPORT_IMAGE_GENERATION) -// Generate image: plain color -Image GenImageColor(int width, int height, Color color) -{ - Color *pixels = (Color *)calloc(width*height, sizeof(Color)); - - for (int i = 0; i < width*height; i++) pixels[i] = color; - - Image image = LoadImageEx(pixels, width, height); - - free(pixels); - - return image; -} - -// Generate image: vertical gradient -Image GenImageGradientV(int width, int height, Color top, Color bottom) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - 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)); - } - } - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: horizontal gradient -Image GenImageGradientH(int width, int height, Color left, Color right) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - for (int i = 0; i < width; i++) - { - float factor = (float)i/(float)width; - for (int j = 0; j < height; j++) - { - 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)); - } - } - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: radial gradient -Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - float radius = (width < height) ? (float)width/2.0f : (float)height/2.0f; - - 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++) - { - float dist = hypotf((float)x - centerX, (float)y - centerY); - float factor = (dist - radius*density)/(radius*(1.0f - density)); - - factor = fmax(factor, 0.f); - factor = 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)); - 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 = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: checked -Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - if ((x/checksX + y/checksY)%2 == 0) pixels[y*width + x] = col1; - else pixels[y*width + x] = col2; - } - } - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: white noise -Image GenImageWhiteNoise(int width, int height, float factor) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - for (int i = 0; i < width*height; i++) - { - if (GetRandomValue(0, 99) < (int)(factor*100.0f)) pixels[i] = WHITE; - else pixels[i] = BLACK; - } - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: perlin noise -Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - 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; - - // 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 - - // 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, 0, 0, 0) + 1.0f)/2.0f; - - int intensity = (int)(p*255.0f); - pixels[y*width + x] = (Color){intensity, intensity, intensity, 255}; - } - } - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} - -// Generate image: cellular algorithm. Bigger tileSize means bigger cells -Image GenImageCellular(int width, int height, int tileSize) -{ - Color *pixels = (Color *)malloc(width*height*sizeof(Color)); - - int seedsPerRow = width/tileSize; - int seedsPerCol = height/tileSize; - int seedsCount = seedsPerRow * seedsPerCol; - - Vector2 *seeds = (Vector2 *)malloc(seedsCount*sizeof(Vector2)); - - 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){x, y}; - } - - for (int y = 0; y < height; y++) - { - int tileY = y/tileSize; - - for (int x = 0; x < width; x++) - { - int tileX = x/tileSize; - - float minDistance = strtod("Inf", NULL); - - // Check all adjacent tiles - for (int i = -1; i < 2; i++) - { - if ((tileX + i < 0) || (tileX + i >= seedsPerRow)) continue; - - for (int j = -1; j < 2; j++) - { - if ((tileY + j < 0) || (tileY + j >= seedsPerCol)) continue; - - Vector2 neighborSeed = seeds[(tileY + j)*seedsPerRow + tileX + i]; - - float dist = hypot(x - (int)neighborSeed.x, y - (int)neighborSeed.y); - minDistance = fmin(minDistance, dist); - } - } - - // 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; - - pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; - } - } - - free(seeds); - - Image image = LoadImageEx(pixels, width, height); - free(pixels); - - return image; -} -#endif // SUPPORT_IMAGE_GENERATION - -// Generate GPU mipmaps for a texture -void GenTextureMipmaps(Texture2D *texture) -{ - // NOTE: NPOT textures support check inside function - // On WebGL (OpenGL ES 2.0) NPOT textures support is limited - rlGenerateMipmaps(texture); -} - -// Set texture scaling filter mode -void SetTextureFilter(Texture2D texture, int filterMode) -{ - switch (filterMode) - { - case FILTER_POINT: - { - if (texture.mipmaps > 1) - { - // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST); - - // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); - } - else - { - // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST); - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); - } - } break; - case FILTER_BILINEAR: - { - if (texture.mipmaps > 1) - { - // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) - // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST); - - // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); - } - else - { - // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); - } - } break; - case FILTER_TRILINEAR: - { - if (texture.mipmaps > 1) - { - // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR); - - // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); - } - else - { - TraceLog(LOG_WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id); - - // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); - } - } break; - case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break; - case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break; - case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break; - default: break; - } -} - -// Set texture wrapping mode -void SetTextureWrap(Texture2D texture, int wrapMode) -{ - switch (wrapMode) - { - case WRAP_REPEAT: - { - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT); - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT); - } break; - case WRAP_CLAMP: - { - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP); - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP); - } break; - case WRAP_MIRROR: - { - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR); - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR); - } break; - default: break; - } -} - -// 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 Texture2D with position defined as Vector2 -void DrawTextureV(Texture2D texture, Vector2 position, Color tint) -{ - DrawTextureEx(texture, position, 0, 1.0f, tint); -} - -// Draw a Texture2D with extended parameters -void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) -{ - Rectangle sourceRec = { 0, 0, texture.width, texture.height }; - Rectangle destRec = { position.x, position.y, texture.width*scale, texture.height*scale }; - Vector2 origin = { 0, 0 }; - - DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); -} - -// Draw a part of a texture (defined by a rectangle) -void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) -{ - Rectangle destRec = { position.x, position.y, sourceRec.width, sourceRec.height }; - Vector2 origin = { 0, 0 }; - - DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, 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 sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) -{ - // Check if texture is valid - if (texture.id > 0) - { - if (sourceRec.width < 0) sourceRec.x -= sourceRec.width; - if (sourceRec.height < 0) sourceRec.y -= sourceRec.height; - - rlEnableTexture(texture.id); - - rlPushMatrix(); - rlTranslatef(destRec.x, destRec.y, 0); - rlRotatef(rotation, 0, 0, 1); - rlTranslatef(-origin.x, -origin.y, 0); - - rlBegin(RL_QUADS); - rlColor4ub(tint.r, tint.g, tint.b, tint.a); - rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer - - // Bottom-left corner for texture and quad - rlTexCoord2f(sourceRec.x/texture.width, sourceRec.y/texture.height); - rlVertex2f(0.0f, 0.0f); - - // Bottom-right corner for texture and quad - rlTexCoord2f(sourceRec.x/texture.width, (sourceRec.y + sourceRec.height)/texture.height); - rlVertex2f(0.0f, destRec.height); - - // Top-right corner for texture and quad - rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, (sourceRec.y + sourceRec.height)/texture.height); - rlVertex2f(destRec.width, destRec.height); - - // Top-left corner for texture and quad - rlTexCoord2f((sourceRec.x + sourceRec.width)/texture.width, sourceRec.y/texture.height); - rlVertex2f(destRec.width, 0.0f); - rlEnd(); - rlPopMatrix(); - - rlDisableTexture(); - } -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(SUPPORT_FILEFORMAT_DDS) -// Loading DDS image data (compressed or uncompressed) -static Image LoadDDS(const char *fileName) -{ - // 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 rgbBitCount; - unsigned int rBitMask; - unsigned int gBitMask; - unsigned int bBitMask; - unsigned int aBitMask; - } DDSPixelFormat; - - // 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; - - Image image = { 0 }; - - FILE *ddsFile = fopen(fileName, "rb"); - - if (ddsFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] DDS file could not be opened", fileName); - } - else - { - // Verify the type of file - char filecode[4]; - - fread(filecode, 4, 1, ddsFile); - - if (strncmp(filecode, "DDS ", 4) != 0) - { - TraceLog(LOG_WARNING, "[%s] DDS file does not seem to be a valid image", fileName); - } - else - { - DDSHeader ddsHeader; - - // Get the image header - fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile); - - TraceLog(LOG_DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(DDSHeader)); - TraceLog(LOG_DEBUG, "[%s] DDS file pixel format size: %i", fileName, ddsHeader.ddspf.size); - TraceLog(LOG_DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags); - TraceLog(LOG_DEBUG, "[%s] DDS file format: 0x%x", fileName, ddsHeader.ddspf.fourCC); - TraceLog(LOG_DEBUG, "[%s] DDS file bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount); - - 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 - { - if (ddsHeader.ddspf.flags == 0x40) // no alpha channel - { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); - fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); - - image.format = UNCOMPRESSED_R5G6B5; - } - else if (ddsHeader.ddspf.flags == 0x41) // with alpha channel - { - if (ddsHeader.ddspf.aBitMask == 0x8000) // 1bit alpha - { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); - fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); - - 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 = UNCOMPRESSED_R5G5B5A1; - } - else if (ddsHeader.ddspf.aBitMask == 0xf000) // 4bit alpha - { - image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); - fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); - - 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 = UNCOMPRESSED_R4G4B4A4; - } - } - } - if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed - { - // NOTE: not sure if this case exists... - image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char)); - fread(image.data, image.width*image.height*3, 1, ddsFile); - - image.format = UNCOMPRESSED_R8G8B8; - } - else if (ddsHeader.ddspf.flags == 0x41 && ddsHeader.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed - { - image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); - fread(image.data, image.width*image.height*4, 1, ddsFile); - - 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) - { - blue = ((unsigned char *)image.data)[i]; - ((unsigned char *)image.data)[i] = ((unsigned char *)image.data)[i + 2]; - ((unsigned char *)image.data)[i + 2] = blue; - } - - image.format = UNCOMPRESSED_R8G8B8A8; - } - else if (((ddsHeader.ddspf.flags == 0x04) || (ddsHeader.ddspf.flags == 0x05)) && (ddsHeader.ddspf.fourCC > 0)) // Compressed - { - int size; // DDS image data size - - // Calculate data size, including all mipmaps - if (ddsHeader.mipmapCount > 1) size = ddsHeader.pitchOrLinearSize*2; - else size = ddsHeader.pitchOrLinearSize; - - TraceLog(LOG_DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize); - - image.data = (unsigned char*)malloc(size*sizeof(unsigned char)); - - fread(image.data, size, 1, ddsFile); - - switch (ddsHeader.ddspf.fourCC) - { - case FOURCC_DXT1: - { - if (ddsHeader.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB; - else image.format = COMPRESSED_DXT1_RGBA; - } break; - case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break; - case FOURCC_DXT5: image.format = COMPRESSED_DXT5_RGBA; break; - default: break; - } - } - } - - fclose(ddsFile); // Close file pointer - } - - 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 char *fileName) -{ - // 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 }; - - FILE *pkmFile = fopen(fileName, "rb"); - - if (pkmFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] PKM file could not be opened", fileName); - } - else - { - PKMHeader pkmHeader; - - // Get the image header - fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile); - - if (strncmp(pkmHeader.id, "PKM ", 4) != 0) - { - TraceLog(LOG_WARNING, "[%s] PKM file does not seem to be a valid image", fileName); - } - else - { - // 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); - - TraceLog(LOG_DEBUG, "PKM (ETC) image width: %i", pkmHeader.width); - TraceLog(LOG_DEBUG, "PKM (ETC) image height: %i", pkmHeader.height); - TraceLog(LOG_DEBUG, "PKM (ETC) 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 size = image.width*image.height*bpp/8; // Total data size in bytes - - image.data = (unsigned char*)malloc(size*sizeof(unsigned char)); - - fread(image.data, size, 1, pkmFile); - - if (pkmHeader.format == 0) image.format = COMPRESSED_ETC1_RGB; - else if (pkmHeader.format == 1) image.format = COMPRESSED_ETC2_RGB; - else if (pkmHeader.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA; - } - - fclose(pkmFile); // Close file pointer - } - - return image; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_KTX) -// Load KTX compressed image data (ETC1/ETC2 compression) -static Image LoadKTX(const char *fileName) -{ - // 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) - // https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ - 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 }; - - FILE *ktxFile = fopen(fileName, "rb"); - - if (ktxFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] KTX image file could not be opened", fileName); - } - else - { - KTXHeader ktxHeader; - - // Get the image header - fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile); - - 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, "[%s] KTX file does not seem to be a valid file", fileName); - } - else - { - image.width = ktxHeader.width; - image.height = ktxHeader.height; - image.mipmaps = ktxHeader.mipmapLevels; - - TraceLog(LOG_DEBUG, "KTX (ETC) image width: %i", ktxHeader.width); - TraceLog(LOG_DEBUG, "KTX (ETC) image height: %i", ktxHeader.height); - TraceLog(LOG_DEBUG, "KTX (ETC) image format: 0x%x", ktxHeader.glInternalFormat); - - unsigned char unused; - - if (ktxHeader.keyValueDataSize > 0) - { - for (int i = 0; i < ktxHeader.keyValueDataSize; i++) fread(&unused, sizeof(unsigned char), 1, ktxFile); - } - - int dataSize; - fread(&dataSize, sizeof(unsigned int), 1, ktxFile); - - image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char)); - - fread(image.data, dataSize, 1, ktxFile); - - if (ktxHeader.glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB; - else if (ktxHeader.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB; - else if (ktxHeader.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA; - } - - fclose(ktxFile); // Close file pointer - } - - return image; -} -#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 char *fileName) -{ - // 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 }; - - FILE *pvrFile = fopen(fileName, "rb"); - - if (pvrFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] PVR file could not be opened", fileName); - } - else - { - // Check PVR image version - unsigned char pvrVersion = 0; - fread(&pvrVersion, sizeof(unsigned char), 1, pvrFile); - fseek(pvrFile, 0, SEEK_SET); - - // Load different PVR data formats - if (pvrVersion == 0x50) - { - PVRHeaderV3 pvrHeader; - - // Get PVR image header - fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile); - - if ((pvrHeader.id[0] != 'P') || (pvrHeader.id[1] != 'V') || (pvrHeader.id[2] != 'R') || (pvrHeader.id[3] != 3)) - { - TraceLog(LOG_WARNING, "[%s] PVR file does not seem to be a valid image", fileName); - } - else - { - 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 = UNCOMPRESSED_GRAYSCALE; - else if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8))) - image.format = 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 = UNCOMPRESSED_R5G5B5A1; - else if ((pvrHeader.channelDepth[0] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4)) - image.format = UNCOMPRESSED_R4G4B4A4; - else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8) && (pvrHeader.channelDepth[3] == 8)) - image.format = UNCOMPRESSED_R8G8B8A8; - } - else if (pvrHeader.channels[3] == 0) - { - if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 6) && (pvrHeader.channelDepth[2] == 5)) image.format = UNCOMPRESSED_R5G6B5; - else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8)) image.format = UNCOMPRESSED_R8G8B8; - } - } - else if (pvrHeader.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB; - else if (pvrHeader.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA; - - // Skip meta data header - unsigned char unused = 0; - for (int i = 0; i < pvrHeader.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile); - - // Calculate data size (depends on format) - int bpp = 0; - - switch (image.format) - { - case UNCOMPRESSED_GRAYSCALE: bpp = 8; break; - case UNCOMPRESSED_GRAY_ALPHA: - case UNCOMPRESSED_R5G5B5A1: - case UNCOMPRESSED_R5G6B5: - case UNCOMPRESSED_R4G4B4A4: bpp = 16; break; - case UNCOMPRESSED_R8G8B8A8: bpp = 32; break; - case UNCOMPRESSED_R8G8B8: bpp = 24; break; - case COMPRESSED_PVRT_RGB: - case 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*)malloc(dataSize*sizeof(unsigned char)); - - // Read data from file - fread(image.data, dataSize, 1, pvrFile); - } - } - else if (pvrVersion == 52) TraceLog(LOG_INFO, "PVR v2 not supported, update your files to PVR v3"); - - fclose(pvrFile); // Close file pointer - } - - return image; -} -#endif - -#if defined(SUPPORT_FILEFORMAT_ASTC) -// Load ASTC compressed image data (ASTC compression) -static Image LoadASTC(const char *fileName) -{ - // 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 }; - - FILE *astcFile = fopen(fileName, "rb"); - - if (astcFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] ASTC file could not be opened", fileName); - } - else - { - ASTCHeader astcHeader; - - // Get ASTC image header - fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile); - - if ((astcHeader.id[3] != 0x5c) || (astcHeader.id[2] != 0xa1) || (astcHeader.id[1] != 0xab) || (astcHeader.id[0] != 0x13)) - { - TraceLog(LOG_WARNING, "[%s] ASTC file does not seem to be a valid image", fileName); - } - else - { - // 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]); - - TraceLog(LOG_DEBUG, "ASTC image width: %i", image.width); - TraceLog(LOG_DEBUG, "ASTC image height: %i", image.height); - TraceLog(LOG_DEBUG, "ASTC 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 *)malloc(dataSize*sizeof(unsigned char)); - fread(image.data, dataSize, 1, astcFile); - - if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA; - else if (bpp == 2) image.format = COMPRESSED_ASTC_4x4_RGBA; - } - else TraceLog(LOG_WARNING, "[%s] ASTC block size configuration not supported", fileName); - } - - fclose(astcFile); - } - - return image; -} -#endif diff --git a/raylib/textures.go b/raylib/textures.go deleted file mode 100644 index 3879a75..0000000 --- a/raylib/textures.go +++ /dev/null @@ -1,532 +0,0 @@ -package raylib - -/* -#include "raylib.h" -#include -*/ -import "C" - -import ( - "image" - "unsafe" -) - -// cptr returns C pointer -func (i *Image) cptr() *C.Image { - return (*C.Image)(unsafe.Pointer(i)) -} - -// 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) - cimg := i.cptr() - ret := C.GetImageData(*cimg) - pixels := (*[1 << 24]uint8)(unsafe.Pointer(ret))[0 : i.Width*i.Height*4] - - img.Pix = pixels - - return img -} - -// cptr returns C pointer -func (t *Texture2D) cptr() *C.Texture2D { - return (*C.Texture2D)(unsafe.Pointer(t)) -} - -// cptr returns C pointer -func (r *RenderTexture2D) cptr() *C.RenderTexture2D { - return (*C.RenderTexture2D)(unsafe.Pointer(r)) -} - -// LoadImage - Load an image into CPU memory (RAM) -func LoadImage(fileName string) *Image { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadImage(cfileName) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadImageEx - Load image data from Color array data (RGBA - 32bit) -func LoadImageEx(pixels []Color, width, height int32) *Image { - cpixels := pixels[0].cptr() - cwidth := (C.int)(width) - cheight := (C.int)(height) - ret := C.LoadImageEx(cpixels, cwidth, cheight) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadImagePro - Load image from raw data with parameters -func LoadImagePro(data []byte, width, height int32, format PixelFormat) *Image { - cdata := unsafe.Pointer(&data[0]) - cwidth := (C.int)(width) - cheight := (C.int)(height) - cformat := (C.int)(format) - ret := C.LoadImagePro(cdata, cwidth, cheight, cformat) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadImageRaw - Load image data from RAW file -func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - cwidth := (C.int)(width) - cheight := (C.int)(height) - cformat := (C.int)(format) - cheaderSize := (C.int)(headerSize) - ret := C.LoadImageRaw(cfileName, cwidth, cheight, cformat, cheaderSize) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadTexture - Load an image as texture into GPU memory -func LoadTexture(fileName string) Texture2D { - cfileName := C.CString(fileName) - defer C.free(unsafe.Pointer(cfileName)) - ret := C.LoadTexture(cfileName) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadTextureFromImage - Load a texture from image data -func LoadTextureFromImage(image *Image) Texture2D { - cimage := image.cptr() - ret := C.LoadTextureFromImage(*cimage) - v := newTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// LoadRenderTexture - Load a texture to be used for rendering -func LoadRenderTexture(width, height int32) RenderTexture2D { - cwidth := (C.int)(width) - cheight := (C.int)(height) - ret := C.LoadRenderTexture(cwidth, cheight) - v := newRenderTexture2DFromPointer(unsafe.Pointer(&ret)) - return v -} - -// UnloadImage - Unload image from CPU memory (RAM) -func UnloadImage(image *Image) { - cimage := image.cptr() - C.UnloadImage(*cimage) -} - -// UnloadTexture - Unload texture from GPU memory -func UnloadTexture(texture Texture2D) { - ctexture := texture.cptr() - C.UnloadTexture(*ctexture) -} - -// UnloadRenderTexture - Unload render texture from GPU memory -func UnloadRenderTexture(target RenderTexture2D) { - ctarget := target.cptr() - C.UnloadRenderTexture(*ctarget) -} - -// GetImageData - Get pixel data from image -func GetImageData(img *Image) []Color { - cimg := img.cptr() - ret := C.GetImageData(*cimg) - return (*[1 << 24]Color)(unsafe.Pointer(ret))[0 : img.Width*img.Height] -} - -// GetPixelDataSize - Get pixel data size in bytes (image or texture) -func GetPixelDataSize(width, height, format int32) int32 { - cwidth := (C.int)(width) - cheight := (C.int)(height) - cformat := (C.int)(format) - ret := C.GetPixelDataSize(cwidth, cheight, cformat) - return int32(ret) -} - -// 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) { - ctexture := texture.cptr() - cpixels := unsafe.Pointer(&pixels[0]) - C.UpdateTexture(*ctexture, cpixels) -} - -// ExportImage - Export image as a PNG file -func ExportImage(name string, image Image) { - cname := C.CString(name) - defer C.free(unsafe.Pointer(cname)) - cimage := image.cptr() - - C.ExportImage(cname, *cimage) -} - -// ImageToPOT - Convert image to POT (power-of-two) -func ImageToPOT(image *Image, fillColor Color) { - cimage := image.cptr() - cfillColor := fillColor.cptr() - C.ImageToPOT(cimage, *cfillColor) -} - -// ImageFormat - Convert image data to desired format -func ImageFormat(image *Image, newFormat PixelFormat) { - cimage := image.cptr() - cnewFormat := (C.int)(newFormat) - C.ImageFormat(cimage, cnewFormat) -} - -// ImageAlphaMask - Apply alpha mask to image -func ImageAlphaMask(image, alphaMask *Image) { - cimage := image.cptr() - calphaMask := alphaMask.cptr() - C.ImageAlphaMask(cimage, *calphaMask) -} - -// ImageAlphaClear - Apply alpha mask to image -func ImageAlphaClear(image *Image, color Color, threshold float32) { - cimage := image.cptr() - ccolor := color.cptr() - cthreshold := (C.float)(threshold) - C.ImageAlphaClear(cimage, *ccolor, cthreshold) -} - -// ImageAlphaCrop - Crop image depending on alpha value -func ImageAlphaCrop(image *Image, threshold float32) { - cimage := image.cptr() - cthreshold := (C.float)(threshold) - C.ImageAlphaCrop(cimage, cthreshold) -} - -// ImageAlphaPremultiply - Premultiply alpha channel -func ImageAlphaPremultiply(image *Image) { - cimage := image.cptr() - C.ImageAlphaPremultiply(cimage) -} - -// ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -func ImageDither(image *Image, rBpp, gBpp, bBpp, aBpp int32) { - cimage := image.cptr() - crBpp := (C.int)(rBpp) - cgBpp := (C.int)(gBpp) - cbBpp := (C.int)(bBpp) - caBpp := (C.int)(aBpp) - C.ImageDither(cimage, crBpp, cgBpp, cbBpp, caBpp) -} - -// ImageCopy - Create an image duplicate (useful for transformations) -func ImageCopy(image *Image) *Image { - cimage := image.cptr() - ret := C.ImageCopy(*cimage) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ImageCrop - Crop an image to a defined rectangle -func ImageCrop(image *Image, crop Rectangle) { - cimage := image.cptr() - ccrop := crop.cptr() - C.ImageCrop(cimage, *ccrop) -} - -// ImageResize - Resize an image (bilinear filtering) -func ImageResize(image *Image, newWidth, newHeight int32) { - cimage := image.cptr() - cnewWidth := (C.int)(newWidth) - cnewHeight := (C.int)(newHeight) - C.ImageResize(cimage, cnewWidth, cnewHeight) -} - -// ImageResizeNN - Resize an image (Nearest-Neighbor scaling algorithm) -func ImageResizeNN(image *Image, newWidth, newHeight int32) { - cimage := image.cptr() - cnewWidth := (C.int)(newWidth) - cnewHeight := (C.int)(newHeight) - C.ImageResizeNN(cimage, cnewWidth, cnewHeight) -} - -// ImageMipmaps - Generate all mipmap levels for a provided image -func ImageMipmaps(image *Image) { - cimage := image.cptr() - C.ImageMipmaps(cimage) -} - -// ImageText - Create an image from text (default font) -func ImageText(text string, fontSize int32, color Color) *Image { - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.int)(fontSize) - 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) *Image { - cfont := font.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ctint := tint.cptr() - ret := C.ImageTextEx(*cfont, ctext, cfontSize, cspacing, *ctint) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// ImageDraw - Draw a source image within a destination image -func ImageDraw(dst, src *Image, srcRec, dstRec Rectangle) { - cdst := dst.cptr() - csrc := src.cptr() - csrcRec := srcRec.cptr() - cdstRec := dstRec.cptr() - C.ImageDraw(cdst, *csrc, *csrcRec, *cdstRec) -} - -// ImageDrawRectangle - Draw rectangle within an image -func ImageDrawRectangle(dst *Image, position Vector2, rec Rectangle, color Color) { - cdst := dst.cptr() - cposition := position.cptr() - crec := rec.cptr() - ccolor := color.cptr() - C.ImageDrawRectangle(cdst, *cposition, *crec, *ccolor) -} - -// ImageDrawText - Draw text (default font) within an image (destination) -func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, color Color) { - cdst := dst.cptr() - cposition := position.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.int)(fontSize) - ccolor := color.cptr() - C.ImageDrawText(cdst, *cposition, ctext, 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, color Color) { - cdst := dst.cptr() - cposition := position.cptr() - cfont := font.cptr() - ctext := C.CString(text) - defer C.free(unsafe.Pointer(ctext)) - cfontSize := (C.float)(fontSize) - cspacing := (C.float)(spacing) - ccolor := color.cptr() - C.ImageDrawTextEx(cdst, *cposition, *cfont, ctext, cfontSize, cspacing, *ccolor) -} - -// ImageFlipVertical - Flip image vertically -func ImageFlipVertical(image *Image) { - cimage := image.cptr() - C.ImageFlipVertical(cimage) -} - -// ImageFlipHorizontal - Flip image horizontally -func ImageFlipHorizontal(image *Image) { - cimage := image.cptr() - C.ImageFlipHorizontal(cimage) -} - -// ImageColorTint - Modify image color: tint -func ImageColorTint(image *Image, color Color) { - cimage := image.cptr() - ccolor := color.cptr() - C.ImageColorTint(cimage, *ccolor) -} - -// ImageColorInvert - Modify image color: invert -func ImageColorInvert(image *Image) { - cimage := image.cptr() - C.ImageColorInvert(cimage) -} - -// ImageColorGrayscale - Modify image color: grayscale -func ImageColorGrayscale(image *Image) { - cimage := image.cptr() - C.ImageColorGrayscale(cimage) -} - -// ImageColorContrast - Modify image color: contrast (-100 to 100) -func ImageColorContrast(image *Image, contrast float32) { - cimage := image.cptr() - ccontrast := (C.float)(contrast) - C.ImageColorContrast(cimage, ccontrast) -} - -// ImageColorBrightness - Modify image color: brightness (-255 to 255) -func ImageColorBrightness(image *Image, brightness int32) { - cimage := image.cptr() - cbrightness := (C.int)(brightness) - C.ImageColorBrightness(cimage, cbrightness) -} - -// GenImageColor - Generate image: plain color -func GenImageColor(width, height int, color Color) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - ccolor := color.cptr() - - ret := C.GenImageColor(cwidth, cheight, *ccolor) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenImageGradientV - Generate image: vertical gradient -func GenImageGradientV(width, height int, top, bottom Color) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - ctop := top.cptr() - cbottom := bottom.cptr() - - 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) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - cdensity := (C.float)(density) - cinner := inner.cptr() - couter := outer.cptr() - - ret := C.GenImageGradientRadial(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) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - cchecksX := (C.int)(checksX) - cchecksY := (C.int)(checksY) - ccol1 := col1.cptr() - ccol2 := col2.cptr() - - ret := C.GenImageChecked(cwidth, cheight, cchecksX, cchecksY, *ccol1, *ccol2) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenImageWhiteNoise - Generate image: white noise -func GenImageWhiteNoise(width, height int, factor float32) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - cfactor := (C.float)(factor) - - ret := C.GenImageWhiteNoise(cwidth, cheight, cfactor) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenImagePerlinNoise - Generate image: perlin noise -func GenImagePerlinNoise(width, height, offsetX, offsetY int, scale float32) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - coffsetX := (C.int)(offsetX) - coffsetY := (C.int)(offsetY) - cscale := (C.float)(scale) - - ret := C.GenImagePerlinNoise(cwidth, cheight, coffsetX, coffsetY, cscale) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenImageCellular - Generate image: cellular algorithm. Bigger tileSize means bigger cells -func GenImageCellular(width, height, tileSize int) *Image { - cwidth := (C.int)(width) - cheight := (C.int)(height) - ctileSize := (C.int)(tileSize) - - ret := C.GenImageCellular(cwidth, cheight, ctileSize) - v := newImageFromPointer(unsafe.Pointer(&ret)) - return v -} - -// GenTextureMipmaps - Generate GPU mipmaps for a texture -func GenTextureMipmaps(texture *Texture2D) { - ctexture := texture.cptr() - C.GenTextureMipmaps(ctexture) -} - -// SetTextureFilter - Set texture scaling filter mode -func SetTextureFilter(texture Texture2D, filterMode TextureFilterMode) { - ctexture := texture.cptr() - cfilterMode := (C.int)(filterMode) - C.SetTextureFilter(*ctexture, cfilterMode) -} - -// SetTextureWrap - Set texture wrapping mode -func SetTextureWrap(texture Texture2D, wrapMode TextureWrapMode) { - ctexture := texture.cptr() - cwrapMode := (C.int)(wrapMode) - C.SetTextureWrap(*ctexture, cwrapMode) -} - -// DrawTexture - Draw a Texture2D -func DrawTexture(texture Texture2D, posX int32, posY int32, tint Color) { - ctexture := texture.cptr() - cposX := (C.int)(posX) - cposY := (C.int)(posY) - 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) { - ctexture := texture.cptr() - cposition := position.cptr() - 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) { - ctexture := texture.cptr() - cposition := position.cptr() - crotation := (C.float)(rotation) - cscale := (C.float)(scale) - 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) { - ctexture := texture.cptr() - csourceRec := sourceRec.cptr() - cposition := position.cptr() - 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) { - ctexture := texture.cptr() - csourceRec := sourceRec.cptr() - cdestRec := destRec.cptr() - corigin := origin.cptr() - crotation := (C.float)(rotation) - ctint := tint.cptr() - C.DrawTexturePro(*ctexture, *csourceRec, *cdestRec, *corigin, crotation, *ctint) -} diff --git a/raylib/utils.c b/raylib/utils.c index 9d9d8b5..26e7a1b 100644 --- a/raylib/utils.c +++ b/raylib/utils.c @@ -3,26 +3,14 @@ * raylib.utils - Some common utility functions * * CONFIGURATION: -* -* #define SUPPORT_SAVE_PNG (defined by default) -* Support saving image data as PNG fileformat -* NOTE: Requires stb_image_write library -* -* #define SUPPORT_SAVE_BMP -* Support saving image data as BMP fileformat -* NOTE: Requires stb_image_write library -* -* #define SUPPORT_TRACELOG -* Show TraceLog() output messages -* NOTE: By default LOG_DEBUG traces not shown -* -* DEPENDENCIES: -* stb_image_write - BMP/PNG writting functions +* #define SUPPORT_TRACELOG +* Show TraceLog() output messages +* NOTE: By default LOG_DEBUG traces not shown * * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-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. @@ -41,42 +29,65 @@ * **********************************************************************************************/ -#include "config.h" +#include "raylib.h" // WARNING: Required for: LogType enum + +// 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 "raylib.h" // WARNING: Required for: LogType enum #include "utils.h" #if defined(PLATFORM_ANDROID) - #include - #include - #include + #include // Required for: Android error types + #include // Required for: Android log system: __android_log_vprint() + #include // Required for: Android assets manager: AAsset, AAssetManager_open()... #endif -#include // Required for: malloc(), free() -#include // Required for: fopen(), fclose(), fputc(), fwrite(), printf(), fprintf(), funopen() -#include // Required for: va_list, va_start(), vfprintf(), va_end() -#include // Required for: strlen(), strrchr(), strcmp() +#include // Required for: exit() +#include // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose() +#include // Required for: va_list, va_start(), va_end() +#include // Required for: strcpy(), strcat() -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) - #define STB_IMAGE_WRITE_IMPLEMENTATION - #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef MAX_TRACELOG_MSG_LENGTH + #define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message #endif //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- +static int logTypeLevel = LOG_INFO; // Minimum log type level -// Log types messages supported flags (bit based) -static unsigned char logTypeFlags = LOG_INFO | LOG_WARNING | LOG_ERROR; +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 + +//---------------------------------------------------------------------------------- +// Functions to set internal callbacks +//---------------------------------------------------------------------------------- +void SetTraceLogCallback(TraceLogCallback callback) { traceLog = callback; } // Set custom trace log +void SetLoadFileDataCallback(LoadFileDataCallback callback) { loadFileData = callback; } // Set custom file data loader +void SetSaveFileDataCallback(SaveFileDataCallback callback) { saveFileData = callback; } // Set custom file data saver +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) -AAssetManager *assetManager; +static AAssetManager *assetManager = NULL; // Android assets manager pointer +static const char *internalDataPath = NULL; // Android internal data path #endif //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) +FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), + fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)); + static int android_read(void *cookie, char *buf, int size); static int android_write(void *cookie, const char *buf, int size); static fpos_t android_seek(void *cookie, fpos_t offset, int whence); @@ -87,124 +98,401 @@ static int android_close(void *cookie); // Module Functions Definition - Utilities //---------------------------------------------------------------------------------- -// Enable trace log message types (bit flags based) -void SetTraceLog(unsigned char types) -{ - logTypeFlags = types; -} +// Set the current threshold (minimum) log level +void SetTraceLogLevel(int logType) { logTypeLevel = logType; } // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) -void TraceLog(int msgType, const char *text, ...) +void TraceLog(int logType, const char *text, ...) { #if defined(SUPPORT_TRACELOG) - static char buffer[128]; - - switch(msgType) - { - case LOG_INFO: strcpy(buffer, "INFO: "); break; - case LOG_ERROR: strcpy(buffer, "ERROR: "); break; - case LOG_WARNING: strcpy(buffer, "WARNING: "); break; - case LOG_DEBUG: strcpy(buffer, "DEBUG: "); break; - default: break; - } - - strcat(buffer, text); - strcat(buffer, "\n"); + // Message has level below current threshold, don't emit + if (logType < logTypeLevel) return; va_list args; va_start(args, text); -#if defined(PLATFORM_ANDROID) - switch(msgType) + if (traceLog) { - case LOG_INFO: if (logTypeFlags & LOG_INFO) __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break; - case LOG_WARNING: if (logTypeFlags & LOG_WARNING) __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break; - case LOG_ERROR: if (logTypeFlags & LOG_ERROR) __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break; - case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; + traceLog(logType, text, args); + va_end(args); + return; + } + +#if defined(PLATFORM_ANDROID) + 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; + case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break; + case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break; + case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break; + case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break; default: break; } #else - switch(msgType) + char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 }; + + switch (logType) { - case LOG_INFO: if (logTypeFlags & LOG_INFO) vprintf(buffer, args); break; - case LOG_WARNING: if (logTypeFlags & LOG_WARNING) vprintf(buffer, args); break; - case LOG_ERROR: if (logTypeFlags & LOG_ERROR) vprintf(buffer, args); break; - case LOG_DEBUG: if (logTypeFlags & LOG_DEBUG) vprintf(buffer, args); break; + case LOG_TRACE: strcpy(buffer, "TRACE: "); break; + case LOG_DEBUG: strcpy(buffer, "DEBUG: "); break; + case LOG_INFO: strcpy(buffer, "INFO: "); break; + case LOG_WARNING: strcpy(buffer, "WARNING: "); break; + case LOG_ERROR: strcpy(buffer, "ERROR: "); break; + case LOG_FATAL: strcpy(buffer, "FATAL: "); break; 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, "\n"); + vprintf(buffer, args); + fflush(stdout); #endif va_end(args); - if (msgType == LOG_ERROR) exit(1); // If LOG_ERROR message, exit program - + if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program + #endif // SUPPORT_TRACELOG } -#if defined(SUPPORT_SAVE_BMP) -// Creates a BMP image file from an array of pixel data -void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize) +// Internal memory allocator +// NOTE: Initializes to zero by default +void *MemAlloc(unsigned int size) { -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) - stbi_write_bmp(fileName, width, height, compSize, imgData); - TraceLog(LOG_INFO, "BMP Image saved: %s", fileName); -#endif + void *ptr = RL_CALLOC(size, 1); + return ptr; } + +// Internal memory reallocator +void *MemRealloc(void *ptr, unsigned int size) +{ + void *ret = RL_REALLOC(ptr, size); + return ret; +} + +// Internal memory free +void MemFree(void *ptr) +{ + RL_FREE(ptr); +} + +// Load data from file into a buffer +unsigned char *LoadFileData(const char *fileName, int *dataSize) +{ + unsigned char *data = NULL; + *dataSize = 0; + + if (fileName != NULL) + { + if (loadFileData) + { + data = loadFileData(fileName, dataSize); + return data; + } +#if defined(SUPPORT_STANDARD_FILEIO) + FILE *file = fopen(fileName, "rb"); + + if (file != NULL) + { + // 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) + 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); + + // 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); + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); +#else + TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); +#endif + } + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + + return data; +} + +// Unload file data allocated by LoadFileData() +void UnloadFileData(unsigned char *data) +{ + RL_FREE(data); +} + +// Save data to file from buffer +bool SaveFileData(const char *fileName, void *data, int dataSize) +{ + bool success = false; + + if (fileName != NULL) + { + if (saveFileData) + { + return saveFileData(fileName, data, dataSize); + } +#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); + + 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 TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName); + + int result = fclose(file); + if (result == 0) success = true; + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); +#else + TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); +#endif + } + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + + 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 -#if defined(SUPPORT_SAVE_PNG) -// Creates a PNG image file from an array of pixel data -void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) - stbi_write_png(fileName, width, height, compSize, imgData, width*compSize); - TraceLog(LOG_INFO, "PNG Image saved: %s", fileName); -#endif -} -#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)); -// Keep track of memory allocated -// NOTE: mallocType defines the type of data allocated -/* -void RecordMalloc(int mallocType, int mallocSize, const char *msg) -{ - // TODO: Investigate how to record memory allocation data... - // Maybe creating my own malloc function... + 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) +{ + char *text = NULL; + + if (fileName != NULL) + { + if (loadFileText) + { + text = loadFileText(fileName); + return text; + } +#if defined(SUPPORT_STANDARD_FILEIO) + FILE *file = fopen(fileName, "rt"); + + if (file != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(file, 0, SEEK_END); + unsigned int size = (unsigned int)ftell(file); + fseek(file, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)RL_MALLOC((size + 1)*sizeof(char)); + + 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); + + // 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); + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); +#else + TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); +#endif + } + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + + return text; +} + +// Unload file text data allocated by LoadFileText() +void UnloadFileText(char *text) +{ + RL_FREE(text); +} + +// Save text data to file (write), string must be '\0' terminated +bool SaveFileText(const char *fileName, const char *text) +{ + bool success = false; + + if (fileName != NULL) + { + if (saveFileText) + { + return saveFileText(fileName, text); + } +#if defined(SUPPORT_STANDARD_FILEIO) + FILE *file = fopen(fileName, "wt"); + + if (file != NULL) + { + int count = fprintf(file, "%s", text); + + if (count < 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName); + else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName); + + int result = fclose(file); + if (result == 0) success = true; + } + else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); +#else + TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); +#endif + } + else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); + + return success; } -*/ #if defined(PLATFORM_ANDROID) // Initialize asset manager from android app -void InitAssetManager(AAssetManager *manager) +void InitAssetManager(AAssetManager *manager, const char *dataPath) { assetManager = manager; + internalDataPath = dataPath; } -// Replacement for fopen +// Replacement for fopen() +// Ref: https://developer.android.com/ndk/reference/group/asset FILE *android_fopen(const char *fileName, const char *mode) { - if (mode[0] == 'w') return NULL; + 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 + // 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 + return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode); + #define fopen(name, mode) android_fopen(name, mode) + } + else + { + // NOTE: AAsset provides access to read-only asset + AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN); - AAsset *asset = AAssetManager_open(assetManager, fileName, 0); - - if (!asset) return NULL; - - return funopen(asset, android_read, android_write, android_seek, android_close); + if (asset != NULL) + { + // Get pointer to file in the assets + return funopen(asset, android_read, android_write, android_seek, android_close); + } + else + { + #undef fopen + // Just do a regular open if file is not found in the assets + return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode); + #define fopen(name, mode) android_fopen(name, mode) + } + } } -#endif +#endif // PLATFORM_ANDROID //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) -static int android_read(void *cookie, char *buf, int size) +static int android_read(void *cookie, char *data, int dataSize) { - return AAsset_read((AAsset *)cookie, buf, size); + return AAsset_read((AAsset *)cookie, data, dataSize); } -static int android_write(void *cookie, const char *buf, int size) +static int android_write(void *cookie, const char *data, int dataSize) { - TraceLog(LOG_ERROR, "Can't provide write access to the APK"); + TRACELOG(LOG_WARNING, "ANDROID: Failed to provide write access to APK"); return EACCES; } @@ -219,4 +507,4 @@ static int android_close(void *cookie) AAsset_close((AAsset *)cookie); return 0; } -#endif +#endif // PLATFORM_ANDROID diff --git a/raylib/utils.go b/raylib/utils.go index c1c35f6..a4bc3e6 100644 --- a/raylib/utils.go +++ b/raylib/utils.go @@ -1,48 +1,43 @@ -// +build !android,!windows +//go:build !android +// +build !android -package raylib +package rl /* +#include "stdlib.h" #include "raylib.h" +void TraceLogWrapper(int logLevel, const char *text) +{ + TraceLog(logLevel, text); +} */ import "C" import ( "fmt" "os" + "unsafe" ) -// SetTraceLog - Enable trace log message types (bit flags based) -func SetTraceLog(typeFlags int) { - logTypeFlags = typeFlags - - ctypeFlags := (C.uchar)(typeFlags) - C.SetTraceLog(ctypeFlags) +// SetTraceLogLevel - Set the current threshold (minimum) log level +func SetTraceLogLevel(logLevel TraceLogLevel) { + clogLevel := (C.int)(logLevel) + C.SetTraceLogLevel(clogLevel) } -// 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...) - } - } +// 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) } // HomeDir - Returns user home directory +// NOTE: On Android this returns internal data path and must be called after InitWindow func HomeDir() string { - return os.Getenv("HOME") + if homeDir, err := os.UserHomeDir(); err == nil { + return homeDir + } + return "" } diff --git a/raylib/utils.h b/raylib/utils.h index 1d1c541..23eca8e 100644 --- a/raylib/utils.h +++ b/raylib/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2024 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. @@ -32,23 +32,30 @@ #include // Required for: AAssetManager #endif -#ifndef SUPPORT_SAVE_PNG -#define SUPPORT_SAVE_PNG 1 +#if defined(SUPPORT_TRACELOG) + #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__) + + #if defined(SUPPORT_TRACELOG_DEBUG) + #define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__) + #else + #define TRACELOGD(...) (void)0 + #endif +#else + #define TRACELOG(level, ...) (void)0 + #define TRACELOGD(...) (void)0 #endif //---------------------------------------------------------------------------------- // Some basic Defines //---------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) - #define fopen(name, mode) android_fopen(name, mode) + #define fopen(name, mode) android_fopen(name, mode) #endif //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif +//... //---------------------------------------------------------------------------------- // Global Variables Definition @@ -58,21 +65,16 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -//#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) -#if defined(SUPPORT_SAVE_BMP) -void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize); +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions #endif -#if defined(SUPPORT_SAVE_PNG) -void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize); -#endif -//#endif #if defined(PLATFORM_ANDROID) -void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app -FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() +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! #endif -#ifdef __cplusplus +#if defined(__cplusplus) } #endif diff --git a/raylib/utils_android.c b/raylib/utils_android.c deleted file mode 100644 index 9f290f2..0000000 --- a/raylib/utils_android.c +++ /dev/null @@ -1,24 +0,0 @@ -// +build android - -#include "_cgo_export.h" -#include - -void log_info(const char *msg) { - __android_log_print(ANDROID_LOG_INFO, "raylib", msg); -} - -void log_warn(const char *msg) { - __android_log_print(ANDROID_LOG_WARN, "raylib", msg); -} - -void log_error(const char *msg) { - __android_log_print(ANDROID_LOG_ERROR, "raylib", msg); -} - -void log_debug(const char *msg) { - __android_log_print(ANDROID_LOG_DEBUG, "raylib", msg); -} - -const char* get_internal_storage_path() { - return internal_storage_path; -} diff --git a/raylib/utils_android.go b/raylib/utils_android.go index 08ab482..4189da4 100644 --- a/raylib/utils_android.go +++ b/raylib/utils_android.go @@ -1,17 +1,15 @@ +//go:build android // +build android -package raylib +package rl /* +#include "stdlib.h" #include "raylib.h" -#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(); +void TraceLogWrapper(int logLevel, const char *text) +{ + TraceLog(logLevel, text); +} */ import "C" @@ -20,46 +18,22 @@ import ( "unsafe" ) -// SetTraceLog - Enable trace log message types (bit flags based) -func SetTraceLog(typeFlags int) { - logTypeFlags = typeFlags - - ctypeFlags := (C.uchar)(typeFlags) - C.SetTraceLog(ctypeFlags) +// SetTraceLogLevel - Set the current threshold (minimum) log level +func SetTraceLogLevel(logLevel TraceLogLevel) { + clogLevel := (C.int)(logLevel) + C.SetTraceLogLevel(clogLevel) } -// 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) - } - } +// 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) } // HomeDir - Returns user home directory // NOTE: On Android this returns internal data path and must be called after InitWindow func HomeDir() string { - return C.GoString(C.get_internal_storage_path()) + return getInternalStoragePath() } diff --git a/raylib/utils_log.c b/raylib/utils_log.c new file mode 100644 index 0000000..7d3d95e --- /dev/null +++ b/raylib/utils_log.c @@ -0,0 +1,18 @@ +#include "raylib.h" +#include "utils_log.h" +#include // Required for: vprintf() +#include // Required for: strcpy(), strcat() + +#define MAX_TRACELOG_BUFFER_SIZE 256 // As defined in utils.c from raylib + +void rayLogWrapperCallback(int logType, const char *text, va_list args) { + char buffer[MAX_TRACELOG_BUFFER_SIZE] = { 0 }; + + vsprintf(buffer, text, args); + + internalTraceLogCallbackGo(logType, buffer, strlen(buffer)); +} + +void setLogCallbackWrapper(void) { + SetTraceLogCallback(rayLogWrapperCallback); +} diff --git a/raylib/utils_log.go b/raylib/utils_log.go new file mode 100644 index 0000000..4eec623 --- /dev/null +++ b/raylib/utils_log.go @@ -0,0 +1,23 @@ +package rl + +/* +#include "utils_log.h" +*/ +import "C" + +import "unsafe" + +var internalTraceLogCallbackFun TraceLogCallbackFun = func(int, string) {} + +// SetTraceLogCallback - set a call-back function for trace log +func SetTraceLogCallback(fn TraceLogCallbackFun) { + internalTraceLogCallbackFun = fn + C.setLogCallbackWrapper() +} + +//export internalTraceLogCallbackGo +func internalTraceLogCallbackGo(logType C.int, cstr unsafe.Pointer, length C.int) { + str := string(C.GoBytes(cstr, length)) + lt := int(logType) + internalTraceLogCallbackFun(lt, str) +} diff --git a/raylib/utils_log.h b/raylib/utils_log.h new file mode 100644 index 0000000..8bfc72f --- /dev/null +++ b/raylib/utils_log.h @@ -0,0 +1,10 @@ +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + + +void setLogCallbackWrapper(void); // enable the call-back + +#if defined(__cplusplus) +} +#endif diff --git a/raylib/utils_windows.go b/raylib/utils_windows.go deleted file mode 100644 index a617ad7..0000000 --- a/raylib/utils_windows.go +++ /dev/null @@ -1,52 +0,0 @@ -// +build windows - -package raylib - -/* -#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.uchar)(typeFlags) - C.SetTraceLog(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/raymath/README.md b/raymath/README.md deleted file mode 100644 index f8099cc..0000000 --- a/raymath/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## raymath [![GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raymath?status.svg)](https://godoc.org/github.com/gen2brain/raylib-go/raymath) - -Some useful functions to work with Vector2, Vector3, Matrix and Quaternions. diff --git a/raymath/raymath.go b/raymath/raymath.go deleted file mode 100644 index 757702c..0000000 --- a/raymath/raymath.go +++ /dev/null @@ -1,1041 +0,0 @@ -// Package raymath - Some useful functions to work with Vector2, Vector3, Matrix and Quaternions -package raymath - -import ( - "math" - - "github.com/gen2brain/raylib-go/raylib" -) - -// Vector2Zero - Vector with components value 0.0 -func Vector2Zero() raylib.Vector2 { - return raylib.NewVector2(0.0, 0.0) -} - -// Vector2One - Vector with components value 1.0 -func Vector2One() raylib.Vector2 { - return raylib.NewVector2(1.0, 1.0) -} - -// Vector2Add - Add two vectors (v1 + v2) -func Vector2Add(v1, v2 raylib.Vector2) raylib.Vector2 { - return raylib.NewVector2(v1.X+v2.X, v1.Y+v2.Y) -} - -// Vector2Subtract - Subtract two vectors (v1 - v2) -func Vector2Subtract(v1, v2 raylib.Vector2) raylib.Vector2 { - return raylib.NewVector2(v1.X-v2.X, v1.Y-v2.Y) -} - -// Vector2Length - Calculate vector length -func Vector2Length(v raylib.Vector2) float32 { - return float32(math.Sqrt(float64((v.X * v.X) + (v.Y * v.Y)))) -} - -// Vector2DotProduct - Calculate two vectors dot product -func Vector2DotProduct(v1, v2 raylib.Vector2) float32 { - return (v1.X*v2.X + v1.Y*v2.Y) -} - -// Vector2Distance - Calculate distance between two vectors -func Vector2Distance(v1, v2 raylib.Vector2) float32 { - return float32(math.Sqrt(float64((v1.X-v2.X)*(v1.X-v2.X) + (v1.Y-v2.Y)*(v1.Y-v2.Y)))) -} - -// Vector2Angle - Calculate angle between two vectors in X-axis -func Vector2Angle(v1, v2 raylib.Vector2) float32 { - angle := float32(math.Atan2(float64(v2.Y-v1.Y), float64(v2.X-v1.X)) * (180.0 / float64(raylib.Pi))) - - if angle < 0 { - angle += 360.0 - } - - return angle -} - -// Vector2Scale - Scale vector (multiply by value) -func Vector2Scale(v *raylib.Vector2, scale float32) { - v.X *= scale - v.Y *= scale -} - -// Vector2Negate - Negate vector -func Vector2Negate(v *raylib.Vector2) { - v.X = -v.X - v.Y = -v.Y -} - -// Vector2Divide - Divide vector by a float value -func Vector2Divide(v *raylib.Vector2, div float32) { - v.X = v.X / div - v.Y = v.Y / div -} - -// Vector2Normalize - Normalize provided vector -func Vector2Normalize(v *raylib.Vector2) { - Vector2Divide(v, Vector2Length(*v)) -} - -// Vector2CrossProduct - Calculate two vectors cross product -func Vector2CrossProduct(v1, v2 raylib.Vector2) float32 { - return v1.X*v2.Y - v1.Y*v2.X -} - -// Vector2Cross - Calculate the cross product of a vector and a value -func Vector2Cross(value float32, vector raylib.Vector2) raylib.Vector2 { - return raylib.NewVector2(-value*vector.Y, value*vector.X) -} - -// Vector2LenSqr - Returns the len square root of a vector -func Vector2LenSqr(vector raylib.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) raylib.Mat2 { - c := float32(math.Cos(float64(radians))) - s := float32(math.Sin(float64(radians))) - - return raylib.NewMat2(c, -s, s, c) -} - -// Mat2Set - Set values from radians to a created matrix 2x2 -func Mat2Set(matrix *raylib.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 raylib.Mat2) raylib.Mat2 { - return raylib.NewMat2(matrix.M00, matrix.M10, matrix.M01, matrix.M11) -} - -// Mat2MultiplyVector2 - Multiplies a vector by a matrix 2x2 -func Mat2MultiplyVector2(matrix raylib.Mat2, vector raylib.Vector2) raylib.Vector2 { - return raylib.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() raylib.Vector3 { - return raylib.NewVector3(0.0, 0.0, 0.0) -} - -// Vector3One - Vector with components value 1.0 -func Vector3One() raylib.Vector3 { - return raylib.NewVector3(1.0, 1.0, 1.0) -} - -// Vector3Add - Add two vectors -func Vector3Add(v1, v2 raylib.Vector3) raylib.Vector3 { - return raylib.NewVector3(v1.X+v2.X, v1.Y+v2.Y, v1.Z+v2.Z) -} - -// Vector3Multiply - Multiply vector by scalar -func Vector3Multiply(v raylib.Vector3, scalar float32) raylib.Vector3 { - result := raylib.Vector3{} - - result.X = v.X * scalar - result.Y = v.Y * scalar - result.Z = v.Z * scalar - - return result -} - -// Vector3MultiplyV - Multiply vector by vector -func Vector3MultiplyV(v1, v2 raylib.Vector3) raylib.Vector3 { - result := raylib.Vector3{} - - result.X = v1.X * v2.X - result.Y = v1.Y * v2.Y - result.Z = v1.Z * v2.Z - - return result -} - -// Vector3Subtract - Subtract two vectors -func Vector3Subtract(v1, v2 raylib.Vector3) raylib.Vector3 { - return raylib.NewVector3(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z) -} - -// Vector3CrossProduct - Calculate two vectors cross product -func Vector3CrossProduct(v1, v2 raylib.Vector3) raylib.Vector3 { - result := raylib.Vector3{} - - result.X = v1.Y*v2.Z - v1.Z*v2.Y - result.Y = v1.Z*v2.X - v1.X*v2.Z - result.Z = v1.X*v2.Y - v1.Y*v2.X - - return result -} - -// Vector3Perpendicular - Calculate one vector perpendicular vector -func Vector3Perpendicular(v raylib.Vector3) raylib.Vector3 { - result := raylib.Vector3{} - - min := math.Abs(float64(v.X)) - cardinalAxis := raylib.NewVector3(1.0, 0.0, 0.0) - - if math.Abs(float64(v.Y)) < min { - min = math.Abs(float64(v.Y)) - cardinalAxis = raylib.NewVector3(0.0, 1.0, 0.0) - } - - if math.Abs(float64(v.Z)) < min { - cardinalAxis = raylib.NewVector3(0.0, 0.0, 1.0) - } - - result = Vector3CrossProduct(v, cardinalAxis) - - return result -} - -// Vector3Length - Calculate vector length -func Vector3Length(v raylib.Vector3) float32 { - return float32(math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z))) -} - -// Vector3DotProduct - Calculate two vectors dot product -func Vector3DotProduct(v1, v2 raylib.Vector3) float32 { - return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z -} - -// Vector3Distance - Calculate distance between two vectors -func Vector3Distance(v1, v2 raylib.Vector3) float32 { - dx := v2.X - v1.X - dy := v2.Y - v1.Y - dz := v2.Z - v1.Z - - return float32(math.Sqrt(float64(dx*dx + dy*dy + dz*dz))) -} - -// Vector3Scale - Scale provided vector -func Vector3Scale(v *raylib.Vector3, scale float32) { - v.X *= scale - v.Y *= scale - v.Z *= scale -} - -// Vector3Negate - Negate provided vector (invert direction) -func Vector3Negate(v *raylib.Vector3) { - v.X = -v.X - v.Y = -v.Y - v.Z = -v.Z -} - -// Vector3Normalize - Normalize provided vector -func Vector3Normalize(v *raylib.Vector3) { - var length, ilength float32 - - length = Vector3Length(*v) - - if length == 0 { - length = 1.0 - } - - ilength = 1.0 / length - - v.X *= ilength - v.Y *= ilength - v.Z *= ilength -} - -// Vector3Transform - Transforms a Vector3 by a given Matrix -func Vector3Transform(v *raylib.Vector3, mat raylib.Matrix) { - x := v.X - y := v.Y - z := v.Z - - v.X = mat.M0*x + mat.M4*y + mat.M8*z + mat.M12 - v.Y = mat.M1*x + mat.M5*y + mat.M9*z + mat.M13 - v.Z = mat.M2*x + mat.M6*y + mat.M10*z + mat.M14 -} - -// Vector3Lerp - Calculate linear interpolation between two vectors -func Vector3Lerp(v1, v2 raylib.Vector3, amount float32) raylib.Vector3 { - result := raylib.Vector3{} - - 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) - - return result -} - -// Vector3Reflect - Calculate reflected vector to normal -func Vector3Reflect(vector, normal raylib.Vector3) raylib.Vector3 { - // I is the original vector - // N is the normal of the incident plane - // R = I - (2*N*( DotProduct[ I,N] )) - - result := raylib.Vector3{} - - dotProduct := Vector3DotProduct(vector, normal) - - result.X = vector.X - (2.0*normal.X)*dotProduct - result.Y = vector.Y - (2.0*normal.Y)*dotProduct - result.Z = vector.Z - (2.0*normal.Z)*dotProduct - - return result -} - -// Vector3Min - Return min value for each pair of components -func Vector3Min(vec1, vec2 raylib.Vector3) raylib.Vector3 { - result := raylib.Vector3{} - - result.X = float32(math.Min(float64(vec1.X), float64(vec2.X))) - result.Y = float32(math.Min(float64(vec1.Y), float64(vec2.Y))) - result.Z = float32(math.Min(float64(vec1.Z), float64(vec2.Z))) - - return result -} - -// Vector3Max - Return max value for each pair of components -func Vector3Max(vec1, vec2 raylib.Vector3) raylib.Vector3 { - result := raylib.Vector3{} - - result.X = float32(math.Max(float64(vec1.X), float64(vec2.X))) - result.Y = float32(math.Max(float64(vec1.Y), float64(vec2.Y))) - result.Z = float32(math.Max(float64(vec1.Z), float64(vec2.Z))) - - return result -} - -// Vector3Barycenter - Barycenter coords for p in triangle abc -func Vector3Barycenter(p, a, b, c raylib.Vector3) raylib.Vector3 { - v0 := Vector3Subtract(b, a) - v1 := Vector3Subtract(c, a) - v2 := Vector3Subtract(p, a) - d00 := Vector3DotProduct(v0, v0) - d01 := Vector3DotProduct(v0, v1) - d11 := Vector3DotProduct(v1, v1) - d20 := Vector3DotProduct(v2, v0) - d21 := Vector3DotProduct(v2, v1) - - denom := d00*d11 - d01*d01 - - result := raylib.Vector3{} - - result.Y = (d11*d20 - d01*d21) / denom - result.Z = (d00*d21 - d01*d20) / denom - result.X = 1.0 - (result.Z + result.Y) - - return result -} - -// MatrixDeterminant - Compute matrix determinant -func MatrixDeterminant(mat raylib.Matrix) float32 { - var result float32 - - a00 := mat.M0 - a01 := mat.M1 - a02 := mat.M2 - a03 := mat.M3 - a10 := mat.M4 - a11 := mat.M5 - a12 := mat.M6 - a13 := mat.M7 - a20 := mat.M8 - a21 := mat.M9 - a22 := mat.M10 - a23 := mat.M11 - a30 := mat.M12 - a31 := mat.M13 - a32 := mat.M14 - a33 := mat.M15 - - 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 -} - -// MatrixTrace - Returns the trace of the matrix (sum of the values along the diagonal) -func MatrixTrace(mat raylib.Matrix) float32 { - return mat.M0 + mat.M5 + mat.M10 + mat.M15 -} - -// MatrixTranspose - Transposes provided matrix -func MatrixTranspose(mat *raylib.Matrix) { - var temp raylib.Matrix - - temp.M0 = mat.M0 - temp.M1 = mat.M4 - temp.M2 = mat.M8 - temp.M3 = mat.M12 - temp.M4 = mat.M1 - temp.M5 = mat.M5 - temp.M6 = mat.M9 - temp.M7 = mat.M13 - temp.M8 = mat.M2 - temp.M9 = mat.M6 - temp.M10 = mat.M10 - temp.M11 = mat.M14 - temp.M12 = mat.M3 - temp.M13 = mat.M7 - temp.M14 = mat.M11 - temp.M15 = mat.M15 - - mat = &temp -} - -// MatrixInvert - Invert provided matrix -func MatrixInvert(mat *raylib.Matrix) { - var temp raylib.Matrix - - a00 := mat.M0 - a01 := mat.M1 - a02 := mat.M2 - a03 := mat.M3 - a10 := mat.M4 - a11 := mat.M5 - a12 := mat.M6 - a13 := mat.M7 - a20 := mat.M8 - a21 := mat.M9 - a22 := mat.M10 - a23 := mat.M11 - a30 := mat.M12 - a31 := mat.M13 - a32 := mat.M14 - a33 := mat.M15 - - b00 := a00*a11 - a01*a10 - b01 := a00*a12 - a02*a10 - b02 := a00*a13 - a03*a10 - b03 := a01*a12 - a02*a11 - b04 := a01*a13 - a03*a11 - b05 := a02*a13 - a03*a12 - b06 := a20*a31 - a21*a30 - b07 := a20*a32 - a22*a30 - b08 := a20*a33 - a23*a30 - b09 := a21*a32 - a22*a31 - b10 := a21*a33 - a23*a31 - b11 := a22*a33 - a23*a32 - - // Calculate the invert determinant (inlined to avoid double-caching) - invDet := 1.0 / (b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06) - - temp.M0 = (a11*b11 - a12*b10 + a13*b09) * invDet - temp.M1 = (-a01*b11 + a02*b10 - a03*b09) * invDet - temp.M2 = (a31*b05 - a32*b04 + a33*b03) * invDet - temp.M3 = (-a21*b05 + a22*b04 - a23*b03) * invDet - temp.M4 = (-a10*b11 + a12*b08 - a13*b07) * invDet - temp.M5 = (a00*b11 - a02*b08 + a03*b07) * invDet - temp.M6 = (-a30*b05 + a32*b02 - a33*b01) * invDet - temp.M7 = (a20*b05 - a22*b02 + a23*b01) * invDet - temp.M8 = (a10*b10 - a11*b08 + a13*b06) * invDet - temp.M9 = (-a00*b10 + a01*b08 - a03*b06) * invDet - temp.M10 = (a30*b04 - a31*b02 + a33*b00) * invDet - temp.M11 = (-a20*b04 + a21*b02 - a23*b00) * invDet - temp.M12 = (-a10*b09 + a11*b07 - a12*b06) * invDet - temp.M13 = (a00*b09 - a01*b07 + a02*b06) * invDet - temp.M14 = (-a30*b03 + a31*b01 - a32*b00) * invDet - temp.M15 = (a20*b03 - a21*b01 + a22*b00) * invDet - - mat = &temp -} - -// MatrixNormalize - Normalize provided matrix -func MatrixNormalize(mat *raylib.Matrix) { - det := MatrixDeterminant(*mat) - - mat.M0 /= det - mat.M1 /= det - mat.M2 /= det - mat.M3 /= det - mat.M4 /= det - mat.M5 /= det - mat.M6 /= det - mat.M7 /= det - mat.M8 /= det - mat.M9 /= det - mat.M10 /= det - mat.M11 /= det - mat.M12 /= det - mat.M13 /= det - mat.M14 /= det - mat.M15 /= det -} - -// MatrixIdentity - Returns identity matrix -func MatrixIdentity() raylib.Matrix { - return raylib.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 raylib.Matrix) raylib.Matrix { - result := MatrixIdentity() - - result.M0 = left.M0 + right.M0 - result.M1 = left.M1 + right.M1 - result.M2 = left.M2 + right.M2 - result.M3 = left.M3 + right.M3 - result.M4 = left.M4 + right.M4 - result.M5 = left.M5 + right.M5 - result.M6 = left.M6 + right.M6 - result.M7 = left.M7 + right.M7 - result.M8 = left.M8 + right.M8 - result.M9 = left.M9 + right.M9 - result.M10 = left.M10 + right.M10 - result.M11 = left.M11 + right.M11 - result.M12 = left.M12 + right.M12 - result.M13 = left.M13 + right.M13 - result.M14 = left.M14 + right.M14 - result.M15 = left.M15 + right.M15 - - return result -} - -// MatrixSubtract - Subtract two matrices (left - right) -func MatrixSubtract(left, right raylib.Matrix) raylib.Matrix { - result := MatrixIdentity() - - result.M0 = left.M0 - right.M0 - result.M1 = left.M1 - right.M1 - result.M2 = left.M2 - right.M2 - result.M3 = left.M3 - right.M3 - result.M4 = left.M4 - right.M4 - result.M5 = left.M5 - right.M5 - result.M6 = left.M6 - right.M6 - result.M7 = left.M7 - right.M7 - result.M8 = left.M8 - right.M8 - result.M9 = left.M9 - right.M9 - result.M10 = left.M10 - right.M10 - result.M11 = left.M11 - right.M11 - result.M12 = left.M12 - right.M12 - result.M13 = left.M13 - right.M13 - result.M14 = left.M14 - right.M14 - result.M15 = left.M15 - right.M15 - - return result -} - -// MatrixTranslate - Returns translation matrix -func MatrixTranslate(x, y, z float32) raylib.Matrix { - return raylib.NewMatrix( - 1.0, 0.0, 0.0, x, - 0.0, 1.0, 0.0, y, - 0.0, 0.0, 1.0, z, - 0, 0, 0, 1.0) -} - -// MatrixRotate - Returns rotation matrix for an angle around an specified axis (angle in radians) -func MatrixRotate(axis raylib.Vector3, angle float32) raylib.Matrix { - var result raylib.Matrix - - mat := MatrixIdentity() - - x := axis.X - y := axis.Y - z := axis.Z - - length := float32(math.Sqrt(float64(x*x + y*y + z*z))) - - if length != 1.0 && length != 0.0 { - length = 1.0 / length - x *= length - y *= length - z *= length - } - - sinres := float32(math.Sin(float64(angle))) - cosres := float32(math.Cos(float64(angle))) - t := 1.0 - cosres - - // Cache some matrix values (speed optimization) - a00 := mat.M0 - a01 := mat.M1 - a02 := mat.M2 - a03 := mat.M3 - a10 := mat.M4 - a11 := mat.M5 - a12 := mat.M6 - a13 := mat.M7 - a20 := mat.M8 - a21 := mat.M9 - a22 := mat.M10 - a23 := mat.M11 - - // Construct the elements of the rotation matrix - b00 := x*x*t + cosres - b01 := y*x*t + z*sinres - b02 := z*x*t - y*sinres - b10 := x*y*t - z*sinres - b11 := y*y*t + cosres - b12 := z*y*t + x*sinres - b20 := x*z*t + y*sinres - b21 := y*z*t - x*sinres - b22 := z*z*t + cosres - - // Perform rotation-specific matrix multiplication - result.M0 = a00*b00 + a10*b01 + a20*b02 - result.M1 = a01*b00 + a11*b01 + a21*b02 - result.M2 = a02*b00 + a12*b01 + a22*b02 - result.M3 = a03*b00 + a13*b01 + a23*b02 - result.M4 = a00*b10 + a10*b11 + a20*b12 - result.M5 = a01*b10 + a11*b11 + a21*b12 - result.M6 = a02*b10 + a12*b11 + a22*b12 - result.M7 = a03*b10 + a13*b11 + a23*b12 - result.M8 = a00*b20 + a10*b21 + a20*b22 - result.M9 = a01*b20 + a11*b21 + a21*b22 - result.M10 = a02*b20 + a12*b21 + a22*b22 - result.M11 = a03*b20 + a13*b21 + a23*b22 - result.M12 = mat.M12 - result.M13 = mat.M13 - result.M14 = mat.M14 - result.M15 = mat.M15 - - return result -} - -// MatrixRotateX - Returns x-rotation matrix (angle in radians) -func MatrixRotateX(angle float32) raylib.Matrix { - result := MatrixIdentity() - - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) - - result.M5 = cosres - result.M6 = -sinres - result.M9 = sinres - result.M10 = cosres - - return result -} - -// MatrixRotateY - Returns y-rotation matrix (angle in radians) -func MatrixRotateY(angle float32) raylib.Matrix { - result := MatrixIdentity() - - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) - - result.M0 = cosres - result.M2 = sinres - result.M8 = -sinres - result.M10 = cosres - - return result -} - -// MatrixRotateZ - Returns z-rotation matrix (angle in radians) -func MatrixRotateZ(angle float32) raylib.Matrix { - result := MatrixIdentity() - - cosres := float32(math.Cos(float64(angle))) - sinres := float32(math.Sin(float64(angle))) - - result.M0 = cosres - result.M1 = -sinres - result.M4 = sinres - result.M5 = cosres - - return result -} - -// MatrixScale - Returns scaling matrix -func MatrixScale(x, y, z float32) raylib.Matrix { - result := raylib.NewMatrix( - x, 0.0, 0.0, 0.0, - 0.0, y, 0.0, 0.0, - 0.0, 0.0, z, 0.0, - 0.0, 0.0, 0.0, 1.0) - - return result -} - -// MatrixMultiply - Returns two matrix multiplication -func MatrixMultiply(left, right raylib.Matrix) raylib.Matrix { - var result raylib.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) raylib.Matrix { - var result raylib.Matrix - - rl := right - left - tb := top - bottom - fn := far - near - - result.M0 = (near * 2.0) / rl - result.M1 = 0.0 - result.M2 = 0.0 - result.M3 = 0.0 - - result.M4 = 0.0 - result.M5 = (near * 2.0) / tb - result.M6 = 0.0 - result.M7 = 0.0 - - result.M8 = right + left/rl - result.M9 = top + bottom/tb - result.M10 = -(far + near) / fn - result.M11 = -1.0 - - result.M12 = 0.0 - result.M13 = 0.0 - result.M14 = -(far * near * 2.0) / fn - result.M15 = 0.0 - - return result -} - -// MatrixPerspective - Returns perspective projection matrix -func MatrixPerspective(fovy, aspect, near, far float32) raylib.Matrix { - top := near * float32(math.Tan(float64(fovy*raylib.Pi)/360.0)) - right := top * aspect - - return MatrixFrustum(-right, right, -top, top, near, far) -} - -// MatrixOrtho - Returns orthographic projection matrix -func MatrixOrtho(left, right, bottom, top, near, far float32) raylib.Matrix { - var result raylib.Matrix - - rl := (right - left) - tb := (top - bottom) - fn := (far - near) - - result.M0 = 2.0 / rl - result.M1 = 0.0 - result.M2 = 0.0 - result.M3 = 0.0 - result.M4 = 0.0 - result.M5 = 2.0 / tb - result.M6 = 0.0 - result.M7 = 0.0 - result.M8 = 0.0 - result.M9 = 0.0 - result.M10 = -2.0 / fn - result.M11 = 0.0 - result.M12 = -(left + right) / rl - result.M13 = -(top + bottom) / tb - result.M14 = -(far + near) / fn - result.M15 = 1.0 - - return result -} - -// MatrixLookAt - Returns camera look-at matrix (view matrix) -func MatrixLookAt(eye, target, up raylib.Vector3) raylib.Matrix { - var result raylib.Matrix - - z := Vector3Subtract(eye, target) - Vector3Normalize(&z) - x := Vector3CrossProduct(up, z) - Vector3Normalize(&x) - y := Vector3CrossProduct(z, x) - Vector3Normalize(&y) - - result.M0 = x.X - result.M1 = x.Y - result.M2 = x.Z - result.M3 = -((x.X * eye.X) + (x.Y * eye.Y) + (x.Z * eye.Z)) - result.M4 = y.X - result.M5 = y.Y - result.M6 = y.Z - result.M7 = -((y.X * eye.X) + (y.Y * eye.Y) + (y.Z * eye.Z)) - result.M8 = z.X - result.M9 = z.Y - result.M10 = z.Z - result.M11 = -((z.X * eye.X) + (z.Y * eye.Y) + (z.Z * eye.Z)) - result.M12 = 0.0 - result.M13 = 0.0 - result.M14 = 0.0 - result.M15 = 1.0 - - return result -} - -// QuaternionLength - Compute the length of a quaternion -func QuaternionLength(quat raylib.Quaternion) float32 { - return float32(math.Sqrt(float64(quat.X*quat.X + quat.Y*quat.Y + quat.Z*quat.Z + quat.W*quat.W))) -} - -// QuaternionNormalize - Normalize provided quaternion -func QuaternionNormalize(q *raylib.Quaternion) { - var length, ilength float32 - - length = QuaternionLength(*q) - - if length == 0.0 { - length = 1.0 - } - - ilength = 1.0 / length - - q.X *= ilength - q.Y *= ilength - q.Z *= ilength - q.W *= ilength -} - -// QuaternionInvert - Invert provided quaternion -func QuaternionInvert(quat *raylib.Quaternion) { - length := QuaternionLength(*quat) - lengthSq := length * length - - if lengthSq != 0.0 { - i := 1.0 / lengthSq - - quat.X *= -i - quat.Y *= -i - quat.Z *= -i - quat.W *= i - } -} - -// QuaternionMultiply - Calculate two quaternion multiplication -func QuaternionMultiply(q1, q2 raylib.Quaternion) raylib.Quaternion { - var result raylib.Quaternion - - qax := q1.X - qay := q1.Y - qaz := q1.Z - qaw := q1.W - qbx := q2.X - qby := q2.Y - qbz := q2.Z - qbw := q2.W - - result.X = qax*qbw + qaw*qbx + qay*qbz - qaz*qby - result.Y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz - result.Z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx - result.W = qaw*qbw - qax*qbx - qay*qby - qaz*qbz - - return result -} - -// QuaternionSlerp - Calculates spherical linear interpolation between two quaternions -func QuaternionSlerp(q1, q2 raylib.Quaternion, amount float32) raylib.Quaternion { - var result raylib.Quaternion - - cosHalfTheta := q1.X*q2.X + q1.Y*q2.Y + q1.Z*q2.Z + q1.W*q2.W - - if math.Abs(float64(cosHalfTheta)) >= 1.0 { - result = q1 - } else { - halfTheta := float32(math.Acos(float64(cosHalfTheta))) - sinHalfTheta := float32(math.Sqrt(float64(1.0 - cosHalfTheta*cosHalfTheta))) - - if math.Abs(float64(sinHalfTheta)) < 0.001 { - result.X = (q1.X*0.5 + q2.X*0.5) - result.Y = (q1.Y*0.5 + q2.Y*0.5) - result.Z = (q1.Z*0.5 + q2.Z*0.5) - result.W = (q1.W*0.5 + q2.W*0.5) - } else { - ratioA := float32(math.Sin(float64((1-amount)*halfTheta))) / sinHalfTheta - ratioB := float32(math.Sin(float64(amount*halfTheta))) / sinHalfTheta - - result.X = (q1.X*ratioA + q2.X*ratioB) - result.Y = (q1.Y*ratioA + q2.Y*ratioB) - result.Z = (q1.Z*ratioA + q2.Z*ratioB) - result.W = (q1.W*ratioA + q2.W*ratioB) - } - } - - return result -} - -// QuaternionFromMatrix - Returns a quaternion for a given rotation matrix -func QuaternionFromMatrix(matrix raylib.Matrix) raylib.Quaternion { - var result raylib.Quaternion - - trace := MatrixTrace(matrix) - - if trace > 0.0 { - s := float32(math.Sqrt(float64(trace+1)) * 2.0) - invS := 1.0 / s - - result.W = s * 0.25 - result.X = (matrix.M6 - matrix.M9) * invS - result.Y = (matrix.M8 - matrix.M2) * invS - result.Z = (matrix.M1 - matrix.M4) * invS - } else { - m00 := matrix.M0 - m11 := matrix.M5 - m22 := matrix.M10 - - if m00 > m11 && m00 > m22 { - s := float32(math.Sqrt(float64(1.0+m00-m11-m22)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M6 - matrix.M9) * invS - result.X = s * 0.25 - result.Y = (matrix.M4 + matrix.M1) * invS - result.Z = (matrix.M8 + matrix.M2) * invS - } else if m11 > m22 { - s := float32(math.Sqrt(float64(1.0+m11-m00-m22)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M8 - matrix.M2) * invS - result.X = (matrix.M4 + matrix.M1) * invS - result.Y = s * 0.25 - result.Z = (matrix.M9 + matrix.M6) * invS - } else { - s := float32(math.Sqrt(float64(1.0+m22-m00-m11)) * 2.0) - invS := 1.0 / s - - result.W = (matrix.M1 - matrix.M4) * invS - result.X = (matrix.M8 + matrix.M2) * invS - result.Y = (matrix.M9 + matrix.M6) * invS - result.Z = s * 0.25 - } - } - - return result -} - -// QuaternionToMatrix - Returns a matrix for a given quaternion -func QuaternionToMatrix(q raylib.Quaternion) raylib.Matrix { - var result raylib.Matrix - - x := q.X - y := q.Y - z := q.Z - w := q.W - - x2 := x + x - y2 := y + y - z2 := z + z - - xx := x * x2 - xy := x * y2 - xz := x * z2 - - yy := y * y2 - yz := y * z2 - zz := z * z2 - - wx := w * x2 - wy := w * y2 - wz := w * z2 - - result.M0 = 1.0 - (yy + zz) - result.M1 = xy - wz - result.M2 = xz + wy - result.M3 = 0.0 - result.M4 = xy + wz - result.M5 = 1.0 - (xx + zz) - result.M6 = yz - wx - result.M7 = 0.0 - result.M8 = xz - wy - result.M9 = yz + wx - result.M10 = 1.0 - (xx + yy) - result.M11 = 0.0 - result.M12 = 0.0 - result.M13 = 0.0 - result.M14 = 0.0 - result.M15 = 1.0 - - return result -} - -// QuaternionFromAxisAngle - Returns rotation quaternion for an angle and axis -func QuaternionFromAxisAngle(axis raylib.Vector3, angle float32) raylib.Quaternion { - result := raylib.NewQuaternion(0.0, 0.0, 0.0, 1.0) - - if Vector3Length(axis) != 0.0 { - angle *= 0.5 - } - - Vector3Normalize(&axis) - - sinres := float32(math.Sin(float64(angle))) - cosres := float32(math.Cos(float64(angle))) - - result.X = axis.X * sinres - result.Y = axis.Y * sinres - result.Z = axis.Z * sinres - result.W = cosres - - QuaternionNormalize(&result) - - return result -} - -// QuaternionToAxisAngle - Returns the rotation angle and axis for a given quaternion -func QuaternionToAxisAngle(q raylib.Quaternion, outAxis *raylib.Vector3, outAngle *float32) { - if math.Abs(float64(q.W)) > 1.0 { - QuaternionNormalize(&q) - } - - resAxis := raylib.NewVector3(0.0, 0.0, 0.0) - - resAngle := 2.0 * float32(math.Acos(float64(q.W))) - den := float32(math.Sqrt(float64(1.0 - q.W*q.W))) - - if den > 0.0001 { - resAxis.X = q.X / den - resAxis.Y = q.Y / den - resAxis.Z = q.Z / den - } else { - // This occurs when the angle is zero. - // Not a problem: just set an arbitrary normalized axis. - resAxis.X = 1.0 - } - - *outAxis = resAxis - *outAngle = resAngle -} - -// QuaternionTransform - Transform a quaternion given a transformation matrix -func QuaternionTransform(q *raylib.Quaternion, mat raylib.Matrix) { - x := q.X - y := q.Y - z := q.Z - w := q.W - - q.X = mat.M0*x + mat.M4*y + mat.M8*z + mat.M12*w - q.Y = mat.M1*x + mat.M5*y + mat.M9*z + mat.M13*w - q.Z = mat.M2*x + mat.M6*y + mat.M10*z + mat.M14*w - q.W = mat.M3*x + mat.M7*y + mat.M11*z + mat.M15*w -} - -// 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 -} diff --git a/rres/README.md b/rres/README.md deleted file mode 100644 index 9844231..0000000 --- a/rres/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## 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 deleted file mode 100644 index 6e8b957..0000000 --- a/rres/cmd/rrem/README.md +++ /dev/null @@ -1,27 +0,0 @@ -## 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 deleted file mode 100644 index 5938f27..0000000 --- a/rres/cmd/rrem/main.go +++ /dev/null @@ -1,434 +0,0 @@ -// 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 deleted file mode 100644 index 3b5f258..0000000 --- a/rres/rres.go +++ /dev/null @@ -1,691 +0,0 @@ -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 { - raylib.TraceLog(raylib.LogWarning, err.Error()) - return - } - - // Verify "rRES" identifier - if string(fileHeader.ID[:]) != "rRES" { - raylib.TraceLog(raylib.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 { - raylib.TraceLog(raylib.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 { - raylib.TraceLog(raylib.LogWarning, "[ID %d] %v", infoHeader.ID, err) - } - - // Decrypt data - data.Data, err = Decrypt(key, data.Data, int(infoHeader.CryptoType)) - if err != nil { - raylib.TraceLog(raylib.LogWarning, "[ID %d] %v", infoHeader.ID, err) - } - - if data.Data != nil && len(data.Data) == int(infoHeader.UncompSize) { - raylib.TraceLog(raylib.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 { - raylib.TraceLog(raylib.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 -}